openacs-5.7.0/0000755000175000017500000000000011575226031012775 5ustar frankiefrankieopenacs-5.7.0/bin/0000755000175000017500000000000011724401450013541 5ustar frankiefrankieopenacs-5.7.0/bin/create-tablespace.tcl0000755000175000017500000000525510551254366017634 0ustar frankiefrankie#!/bin/sh # # A simple tcl script to be run from the commandline which will output # SQL statements suitable for pasting in srvmgrl to drop and create # a new tablespace. # # Call it without arguments to see a short usage message. # # # Based on a sql script from S&R (http://www.sussdorff-roy.com), # licensed under GPL2. Complaints to tils-oacs@tils.net please. See # http://pinds.com/acs-tips/oracle-statements for an online version # of this and maybe some helpful comments. # # the next line restarts using tclsh \ exec tclsh "$0" "$@" if { $argc < 1 || $argc > 3 } { puts "Usage: ./create-tablespace.tcl service_name \[database_password\] \[oracle_data_path\] This will output the sql statements needed to create the tablespace. You have to copy and paste the statements into svrmgrl. If you don't specify database_password then the service name will be used as password. If you don't specify oracle_data_path then the default /ora8/m02/oradata/ora8/ will be used. " exit } set service_name [lindex $argv 0] if { $argc < 2 } { # default pwd set database_password "${service_name}" } else { # pwd specified set database_password [lindex $argv 1] } if { $argc < 3 } { # default oracle_data_path set oracle_data_path "/ora8/m02/oradata/ora8/" } else { # oracle_data_path specified. make sure it has a trailing slash. set oracle_data_path [lindex $argv 2] if { [string index $oracle_data_path end] ne "/" } { set oracle_data_path "${oracle_data_path}/" } } puts " \ spool create-${service_name}.log REM * Start the instance (ORACLE_SID must be set). REM * We expect the database to already be started. REM * connect internal drop user ${service_name} cascade; drop tablespace ${service_name} including contents; REM * Create user and tablespace for live site REM * create tablespace ${service_name} datafile '${oracle_data_path}${service_name}01.dbf' size 50m autoextend on next 640k maxsize 2147450880 extent management local uniform size 160K; create user ${service_name} identified by ${database_password} default tablespace ${service_name} temporary tablespace temp quota unlimited on ${service_name}; grant connect, resource, ctxapp, javasyspriv, query rewrite to ${service_name}; grant create table, select any table, create materialized view, connect, resource, ctxapp, javasyspriv, query rewrite to ${service_name}; revoke unlimited tablespace from ${service_name}; alter user ${service_name} quota unlimited on ${service_name}; REM * Allow user to use autotrace connect ${service_name}/${database_password} @/ora8/m01/app/oracle/product/8.1.7/rdbms/admin/utlxplan.sql REM * All done, so close the log file and exit. REM * spool off exit " openacs-5.7.0/bin/data-dictionary-diff.pl0000644000175000017500000001751507253523116020077 0ustar frankiefrankie#!/usr/local/bin/perl # by Jin Choi , 2000-03-20 # Utility script to check differences between two Oracle data dictionaries. # Can be run in one of three modes. # "Connect" is given two connect strings and does the diff then and there. # "Write" is given a connect string and a file, and writes the results # out to the file. You can do this twice on different data dictionaries, # then use "Read" mode to compare the two. # $Id: data-dictionary-diff.pl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ use strict; use DBI; my $usage_string = <{$table_name}; } elsif (!defined($tablename_hash2{$table_name})) { push @deleted_tables, $table_name; delete $table1_info->{$table_name}; } } print "New tables:\n", join("\n", @new_tables), "\n\n"; print "Deleted tables:\n", join("\n", @deleted_tables), "\n\n"; # Figure out which columns in the remaining tables have been added or deleted. my %column_hash1; my %column_hash2; foreach my $table (keys %$table1_info) { foreach my $column (keys %{$table1_info->{$table}}) { $column_hash1{"$table:$column"} = $table1_info->{$table}{$column}; } } foreach my $table (keys %$table2_info) { foreach my $column (keys %{$table2_info->{$table}}) { $column_hash2{"$table:$column"} = $table2_info->{$table}{$column}; } } %union = union_hashes(\%column_hash1, \%column_hash2); my @new_columns; my @deleted_columns; foreach my $key (sort keys %union) { if (!defined($column_hash1{$key})) { push @new_columns, $key; delete $column_hash2{$key}; } elsif (!defined($column_hash2{$key})) { push @deleted_columns, $key; delete $column_hash1{$key}; } } print "New columns:\n", join("\n", @new_columns), "\n\n"; print "Deleted columns:\n", join("\n", @deleted_columns), "\n\n"; # Report columns which are different. column_hashes 1 and 2 should # both contain the same columns now. print "Modified columns:\n"; foreach my $key (sort keys %column_hash1) { if ($column_hash1{$key} ne $column_hash2{$key}) { print "$key\n $column_hash1{$key}\n $column_hash2{$key}\n"; } } exit; # Get information on tables. Returns a multi-dimensional hashref where # the keys are the table name and the column name, and the value is # the type and constraint information. sub get_table_info { my $connstr = shift; my $table_info = {}; print "Fetching data from Oracle data dictionary for $connstr.\n"; my $db = DBI->connect("dbi:Oracle:", $connstr) || die $!; $db->{AutoCommit} = 0; $db->{RaiseError} = 1; $db->{LongReadLen} = 2048; $db->{LongTruncOk} = 1; print "Connected to Oracle.\n"; my $sth = $db->prepare("select lower(table_name), lower(column_name), lower(data_type), data_length, data_precision, data_scale, nullable from user_tab_columns"); $sth->execute; while (my $rowref = $sth->fetchrow_arrayref) { my ($table_name, $column_name, $data_type, $data_length, $data_precision, $data_scale, $nullable) = @$rowref; $table_info->{$table_name}{$column_name} = format_type_info($data_type, $data_length, $data_precision, $data_scale, $nullable); } # Figure out the constraints. $sth = $db->prepare("select uc.constraint_type, uc.search_condition, uc.r_constraint_name, lower(ucc.table_name), lower(ucc.column_name) from user_constraints uc, user_cons_columns ucc where uc.constraint_name = ucc.constraint_name order by constraint_type"); my $sth2 = $db->prepare("select lower(table_name), lower(column_name) from user_cons_columns where constraint_name = ?"); my %cached_reference_columns; $sth->execute; while (my $rowref = $sth->fetchrow_arrayref) { my ($constraint_type, $search_condition, $r_constraint_name, $table_name, $column_name) = @$rowref; if ($constraint_type eq "P") { $table_info->{$table_name}{$column_name} .= " primary key"; } elsif ($constraint_type eq "U") { $table_info->{$table_name}{$column_name} .= " unique"; } elsif ($constraint_type eq "C") { if ($search_condition !~ /IS NOT NULL/) { $table_info->{$table_name}{$column_name} .= " check ($search_condition)"; } } elsif ($constraint_type eq "R") { my $ref_clause; if ($cached_reference_columns{$r_constraint_name}) { $ref_clause = $cached_reference_columns{$r_constraint_name}; } else { $sth2->execute($r_constraint_name); my ($ref_table_name, $ref_column_name) = $sth2->fetchrow_array; $ref_clause = " references $ref_table_name($ref_column_name)"; $cached_reference_columns{$r_constraint_name} = $ref_clause; } $table_info->{$table_name}{$column_name} .= $ref_clause; } } $sth->finish; $sth2->finish; $db->disconnect; return $table_info; } sub format_type_info { my ($type, $length, $precision, $scale, $nullable) = @_; my $formatted_info; $formatted_info = $type; if ($type eq "char" || $type eq "varchar2") { $formatted_info .= "($length)"; } elsif ($type eq "number") { if ($scale > 0) { $formatted_info .= "($precision,$scale)"; } elsif ($precision) { $formatted_info .= "($precision)"; } else { $formatted_info = "integer"; } } if ($nullable eq "N") { $formatted_info .= " not null"; } return $formatted_info; } # Returns a union of the keys of the two argument hashes. # The values are unimportant. sub union_hashes { my %union; my $h1_ref = shift; my $h2_ref = shift; foreach my $key (keys(%$h1_ref), keys(%$h2_ref)) { $union{$key} = 1; } return %union; } # Reports keys in first hash argument which are not in the second. sub report_difference { my $h1_ref = shift; my $h2_ref = shift; foreach my $key (sort keys %$h1_ref) { if (!defined($$h2_ref{$key})) { print "* $key\n"; } } } sub write_table_info_to_file { my ($table_info, $outfile) = @_; open(F, ">$outfile") || die $!; print "Outputting data to file $outfile.\n"; foreach my $table (keys %$table_info) { foreach my $column (keys %{$table_info->{$table}}) { print F "$table:$column:", $table_info->{$table}{$column}, "\n"; } } close F; } sub get_table_info_from_file { my $filename = shift; my $table_info = {}; open(F, "<$filename") || die $!; while () { chop; my ($table, $column, $info) = split /:/; $table_info->{$table}{$column} = $info; } close F; return $table_info; } openacs-5.7.0/bin/encode64.pl0000644000175000017500000000051507253523116015514 0ustar frankiefrankie#!/usr/local/bin/perl # # Encode a file from stdin as base64 # # hqm@ai.mit.edu # # This script does the following: # use MIME::Base64 (); binmode(STDIN); binmode(STDOUT); # Make sure to read in multiples of 6 chars, to # keep the encoded blocks contiguous. while (read(STDIN, $_, 60*1024)) { print MIME::Base64::encode($_); } openacs-5.7.0/bin/restart-aolserver0000644000175000017500000000243007613003350017146 0ustar frankiefrankie#!/usr/bin/perl ## Restarts an AOLserver. ## Takes as its only argument the name of the server to kill. ## bquinn 6/16/2000 with help from {ryanlee, doug}@arsdigita ## This is a perl script because it needs to run setuid root, ## and perl has fewer security gotchas than most shells. ## ## Make sure that $PIDFILE points to the right location. use strict; undef %ENV; $ENV{'PATH'} = '/sbin:/bin'; if (scalar(@ARGV) == 0) { die "Don't run this without any arguments!"; } my $server = shift; $server =~ /^([\w-]*)$/; my $service_name = $1; my $PIDFILE = "/usr/local/aolserver/log/nspid.$service_name"; my $pid; $< = $>; # set realuid to effective uid (root) # Get the PID of the process to kill. open(IN,"$PIDFILE") || die "No such server\n"; while() { chomp($_); $pid=$_; } close(IN) || die "Problem closing PID file\n"; # Remove the PID file. We have to delete the file to make sure that a subsequent call # to this script will kill some other process. We delete the file before the process dies # because if the service is set to respawn then we may delete the new pid file. my $cmd ="rm -f $PIDFILE"; $cmd =~ /^(.*)$/; my $untaint_cmd = $1; `$untaint_cmd`; # Issue the kill $pid =~ /^(.*)$/; my $untaint_pid = $1; print "Killing $untaint_pid\n"; kill 9, $untaint_pid; openacs-5.7.0/bin/paths.sh0000755000175000017500000000060107253523116015222 0ustar frankiefrankie#!/bin/sh # This shell script will recurse through the packages directory, searching # for java/src directory trees. It will append any of these directories to # the java CLASSPATH in the current environment. curdir=`pwd` for dir in `find . -type d | grep "java\/src$"` do CLASSPATH=$CLASSPATH:${curdir}`echo $dir | sed -e s/\.//` done # Just to be sure.... export CLASSPATH openacs-5.7.0/bin/triggers-diff.pl0000644000175000017500000000764707253523116016656 0ustar frankiefrankie#!/usr/local/bin/perl # by Jin Choi , 2000-03-26 # Utility script for comparing definitions triggers in different data # dictionaries. # Can be run in one of three modes. # "Connect" is given two connect strings and does the diff then and there. # "Write" is given a connect string and a file, and writes the results # out to the file. You can do this twice on different data dictionaries, # then use "Read" mode to compare the two. # $Id: triggers-diff.pl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ use strict; use DBI; use Data::Dumper; my $usage_string = <{$key})) { push @new_triggers, $key; delete $trigger2_info->{$key}; } elsif (!defined($trigger2_info->{$key})) { push @deleted_triggers, $key; delete $trigger1_info->{$key}; } } print "New triggers:\n", join("\n", @new_triggers), "\n\n"; print "Deleted triggers:\n", join("\n", @deleted_triggers), "\n\n"; # Report triggers which are different. trigger_infoes 1 and 2 should # both contain the same triggers now. print "Modified triggers:\n"; foreach my $key (sort keys %$trigger1_info) { if ($trigger1_info->{$key} ne $trigger2_info->{$key}) { print "$trigger1_info->{$key}\n--\n$trigger2_info->{$key}\n\n"; } } exit; sub get_trigger_info { my $db = shift; my $trigger_info = {}; my $sth = $db->prepare("select trigger_name, description, trigger_body from user_triggers"); $sth->execute; while (my $rowref = $sth->fetchrow_arrayref) { my ($name, $description, $body) = @$rowref; chop $body; # Get rid of extraneous NULL. $trigger_info->{$name} .= "$description $body"; } $sth->finish; $db->disconnect; return $trigger_info; } sub get_dbhandle { my $connstr = shift; print "Opening database connection for $connstr.\n"; my $db = DBI->connect("dbi:Oracle:", $connstr) || die $!; $db->{AutoCommit} = 0; $db->{RaiseError} = 1; $db->{LongReadLen} = 2048; $db->{LongTruncOk} = 1; return $db; } # Returns a union of the keys of the two argument hashes. # The values are unimportant. sub union_hashes { my %union; my $h1_ref = shift; my $h2_ref = shift; foreach my $key (keys(%$h1_ref), keys(%$h2_ref)) { $union{$key} = 1; } return %union; } sub write_trigger_info_to_file { my ($trigger_info, $outfile) = @_; open(F, ">$outfile") || die $!; print "Outputting data to file $outfile.\n"; print F Dumper($trigger_info); close F; } sub get_trigger_info_from_file { my $filename = shift; return do $filename; } openacs-5.7.0/bin/acs-4-0-publish.sh0000644000175000017500000000124507253523116016615 0ustar frankiefrankie#!/bin/sh # # Usage: acs-4-0-stable.sh [files] # # Write a special tag (acs-4-0-stable) into the CVS repository # for a set of files to indicate that they are ready for integration # into the acs-4-0 source tree. # # This script is exceedingly simple. The operation is # provided as a shell script so that programmers cannot mistakenly # type the wrong tag name. To undo this script run # # cvs tag -D acs-4-0-stable [files] # # # bquinn@arsdigita.com, September 2000 # # $Id: acs-4-0-publish.sh,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ # ----------------------------------------------------------------------------- cvs -q -d ls:/usr/local/cvsroot tag -F acs-4-0-stable $@openacs-5.7.0/bin/create-sql-drop-file.pl0000644000175000017500000000345607253523116020033 0ustar frankiefrankie#!/usr/local/bin/perl -w # @author: Jim Guggemoos created it # @author: Christian Brechbuehler some maintenance # From a -create.sql script, construct the matching -drop.sql script. # # Does not follow @ or @@; rather there should be a -drop for every -create, # like, e.g., in /packags/acs-kernel/sql. if ( @ARGV != 1 ) { die "usage: $0 x-create.sql [ > x-drop.sql ]\n" } open( INFILE, "$ARGV[0]" ) or die "could not open $ARGV[0] for read\n"; $commit = 0; while ( ) { chop( $_ ); $_ =~ s/--.*$//; $_ =~ s/\s+or\s+replace//i; $_ =~ s/replace\s+or\s+//i; $_ =~ s/^\s+$//; if ( $_ =~ /^create\s+([^\s]+\s+[^\s\(;]+)/ ) { $x = $1; $x =~ s/\s+$//; push( @obj_list, "$x" ); } elsif ( $_ =~ /begin\s+create_group_type_fields\(\s*('[^']+'),/i ) { $group = $1; push( @obj_list, "GTF:$group" ); } elsif ( $_ =~ /commit\s*;/i ) { $commit = 1; } elsif ( $_ =~ /alter\s+table\s+([^\s]+)\s+add\s+constraint\s+([^\s]+)/i ) { push( @obj_list, "CONS:$1:$2" ); } elsif ( $_ =~ /(@@?)\s*(\S+)-create(\.sql)?/i ) { push( @obj_list, "$1 $2") } } close( INFILE ); $tailname = $ARGV[0]; if ( $tailname =~ /\/([^\/]+$)/ ) { $tailname = $1; } $t = localtime(time()); print "-- Uninstall file for the data model created by '$tailname'\n"; print "-- (This file created automatically by create-sql-uninst.pl.)\n"; $uname=$ENV{"USER"}; print "--\n-- $uname ($t)\n--\n-- \$Id\$\n--\n\n"; foreach $x (reverse( @obj_list )) { if ( $x =~ /^GTF:(.+)$/ ) { print "BEGIN remove_group_type_fields( $1 );\nEND;\n/\n"; } elsif ( $x =~ /^CONS:([^:]+):(.*)/ ) { print "alter table $1 drop constraint $2;\n"; } elsif ( $x =~ /^@/) { print "$x-drop\n"; } else { print "drop $x;\n"; } } if ( $commit ) { print "\nCOMMIT;\n"; } openacs-5.7.0/bin/plsql-diff.pl0000644000175000017500000001047707253523116016156 0ustar frankiefrankie#!/usr/local/bin/perl # by Jin Choi , 2000-03-21 # Utility script for comparing definitions of functions and procedures # in different data dictionaries. # Can be run in one of three modes. # "Connect" is given two connect strings and does the diff then and there. # "Write" is given a connect string and a file, and writes the results # out to the file. You can do this twice on different data dictionaries, # then use "Read" mode to compare the two. # $Id: plsql-diff.pl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ use strict; use DBI; use Data::Dumper; my $usage_string = <{$type}}) { $object_hash1{"$type:$object"} = $object1_info->{$type}{$object}; } } foreach my $type (keys %$object2_info) { foreach my $object (keys %{$object2_info->{$type}}) { $object_hash2{"$type:$object"} = $object2_info->{$type}{$object}; } } my %union = union_hashes(\%object_hash1, \%object_hash2); my @new_objects; my @deleted_objects; foreach my $key (sort keys %union) { if (!defined($object_hash1{$key})) { push @new_objects, $key; delete $object_hash2{$key}; } elsif (!defined($object_hash2{$key})) { push @deleted_objects, $key; delete $object_hash1{$key}; } } print "New objects:\n", join("\n", @new_objects), "\n\n"; print "Deleted objects:\n", join("\n", @deleted_objects), "\n\n"; # Report objects which are different. object_hashes 1 and 2 should # both contain the same objects now. print "Modified objects:\n"; foreach my $key (sort keys %object_hash1) { if ($object_hash1{$key} ne $object_hash2{$key}) { print "$object_hash1{$key}\n--\n$object_hash2{$key}\n\n"; } } exit; sub get_object_info { my $db = shift; my $object_info = {}; my $sth = $db->prepare("select object_type, s.name, s.text from user_source s, user_objects o where (object_type = 'FUNCTION' or object_type = 'PROCEDURE') and (s.name = o.object_name) order by o.object_name, s.line"); $sth->execute; while (my $rowref = $sth->fetchrow_arrayref) { my ($type, $name, $text) = @$rowref; $object_info->{$type}{$name} .= $text; } $sth->finish; $db->disconnect; return $object_info; } sub get_dbhandle { my $connstr = shift; print "Opening database connection for $connstr.\n"; my $db = DBI->connect("dbi:Oracle:", $connstr) || die $!; $db->{AutoCommit} = 0; $db->{RaiseError} = 1; $db->{LongReadLen} = 2048; $db->{LongTruncOk} = 1; return $db; } # Returns a union of the keys of the two argument hashes. # The values are unimportant. sub union_hashes { my %union; my $h1_ref = shift; my $h2_ref = shift; foreach my $key (keys(%$h1_ref), keys(%$h2_ref)) { $union{$key} = 1; } return %union; } sub write_object_info_to_file { my ($object_info, $outfile) = @_; open(F, ">$outfile") || die $!; print "Outputting data to file $outfile.\n"; print F Dumper($object_info); close F; } sub get_object_info_from_file { my $filename = shift; return do $filename; } openacs-5.7.0/bin/ad-context-server.pl0000644000175000017500000001312607253523116017461 0ustar frankiefrankie#!/usr/local/bin/perl ########################################################## # ArsDigita Context Server # mbryzek@arsdigita.com # 1/20/2000 ########################################################## # Revision History: # # 04/24/2000 mbryzek Revised documentation ########################################################## # MOTIVATION: # Updating Intermedia indexes sucks. Intermedia # Context server is deprecated according to some people # at Intermedia. And aolserver with keepalive can restart # itself making it very difficult to ensure that two alter # index statements are not running at the same time. ### # FUNCTION: # This script is intended to run as a cron job on # each machine that is running Intermedia. We # recommend running it no more frequently than once # an hour. This script generates a list of intermedia # indexes that are awaiting updates, and updates them. # # This scripts connects to the database as the ctxsys user, # generates a list of indexes to updates, and then issues # alter index statements on all of those indexes. All sql # queries run and the total run time are logged in # /tmp/ad-context-server.log # # Note that this script does NOT need to be run as # root, but it doesn't hurt. ### # SETUP # 1. Install the perl DBI and Oracle DBD # # 2. Put the username for your service in @services # # 3. Set variables in USER CONFIGURATION # a. Make sure $username = ctxsys and $password is # the current password for the ctxsys user. # b. Make sure $ps_path points to ps on your box # c. Make sure the environment variables are correct # # 4. Put script in crontab: # # # ad-context-server monitors all Intermedia indexes # # on the system, updating those that need it. # # DO NOT RUN ad-context-server.pl IN PARALLEL # # WITH INTERMEDIA CONTEXT SERVER (ctxsrv) AND DO # # NOT EVER ISSUE AN ALTER INDEX STATEMENT ON AN # # INTERMEDIA INDEX WHILE THIS IS RUNNING. # # Currently runs every hour on the hour # 0 * * * * /usr/local/bin/ad-context-server.pl > /dev/null 2>&1 # ########################################################## # USER CONFIGURATION # You have to list every service's username for which you want to update # the intermedia indexes. The oracle username must be in uppercase my @services = qw(YOURSERVICENAME); # connect to oracle with the context user - we need to access to the # view ctx_pending. You probably don't want to change $username, but # make sure $password is the ctxsys user's password. my $username = 'ctxsys'; my $password = 'ctxsucks'; # We need to run ps -p PID... where is ps? my $ps_path = '/bin/ps'; # ORACLE ENVIRONMENT CONFIGURATION $ENV{ORACLE_HOME} = "/ora8/m01/app/oracle/product/8.1.5"; $ENV{ORACLE_BASE} = "/ora8/m01/app/oracle"; $ENV{LD_LIBRARY_PATH} = "$ENV{ORACLE_HOME}/lib:$ENV{ORACLE_HOME}/ctx/lib:/usr/lib:/lib:/usr/openwin/lib:/usr/ucblib"; $ENV{PATH} = "$ENV{ORACLE_HOME}/bin:$ENV{ORACLE_HOME}/ctx/lib:/usr/ccs/bin:$ENV{PATH}"; $ENV{ORACLE_SID} = 'ora8'; $ENV{ORACLE_TERM} = 'vt100'; $ENV{ORAENV_ASK} = 'NO'; # END USER CONFIGURATION # Make this local so ad_context_server_exit # can see the filename to clean it up local $pid_file = '/tmp/ad-context-server.pid'; # Exit if there are no services to update ad_context_server_exit(0) if @services == 0; # Let's see if there is already an ad-context-server running. # If there is, we want to bail out since InterMedia is not too good # at concurrency (e.g. 2 concurrent updates lead to deadlock which # may corrupt the index, causing a rebuild) if ( -e $pid_file ) { # The file exists... let's see if the process is still running open PID, $pid_file; my $pid = ; close PID; chomp($pid); my $ps = `$ps_path -p $pid`; # Now let's see if the pid is in the output of ps ad_context_server_exit(0) if $ps =~ /$pid/; } # Print the current process id to $pid_file open PID, ">$pid_file" || ad_context_server_exit(0); print PID $$; close PID; # Let's create the sql portion of the query for service names my $service_sql = "'"; $service_sql .= join "','", @services; $service_sql .= "'"; # Connect to oracle use DBI; my $dbh = DBI->connect('dbi:Oracle:', $username, $password) || die "Couldn't connect to oracle\n"; # Grab all index owners and names that need update. Create a temporary # file to source that contains the alter index statements my $sql_query = << "eof"; select distinct pnd_index_owner||'.'||pnd_index_name from ctx_pending where pnd_index_owner in ($service_sql) eof my $tmp_file = '/tmp/ad-context-server.log'; open TMP, ">$tmp_file" || ad_context_server_exit(0); print TMP "-- SQL QUERY USED TO GET INDEXES (AS USER $username):\n$sql_query\n"; my $sth = $dbh->prepare($sql_query) || die $dbh->errstr; $sth->execute; my $cnt = 0; while ($index = $sth->fetchrow) { $cnt++; print TMP "alter index $index rebuild online parameters('sync memory 45M');\n"; } # log the start time my $time = localtime(); print TMP "-- $time: Starting intermedia updates\n"; close TMP; # Disconnect $sth->finish || die($dbh->errstr); $dbh->disconnect || die $dbh->errstr; # do the updates `$ENV{ORACLE_HOME}/bin/sqlplus $username/$password < $tmp_file`; # Write the status to the temp _file - more for logging purposes :) $time = localtime(); open TMP, ">>$tmp_file" || ad_context_server_exit(0); if ( $cnt > 0 ) { print TMP "-- $time: Finished executing the above alter statements\n"; } else { print TMP "-- $time: Nothing to update!\n"; } close TMP; ad_context_server_exit(0); # Cleans up the pid file and exits with status 0 # References $pid_file sub ad_context_server_exit { unlink $pid_file if -e $pid_file; exit(0); } openacs-5.7.0/bin/webspell0000755000175000017500000000125610746077746015334 0ustar frankiefrankie#!/bin/sh # # webspell - Wrapper for Aspell/Ispell that sets the HOME environment variable # to [ns_info home] ... can't seem to do this from AOLserver Tcl. # # Takes five arguments: # # $1) AOLserver home. # $2) Spellcheck binary (Aspell or Ispell). # $3) Language, in lang or locale format. (Aspell only - Ispell gets "".) # $4) Local dictionary file (additional words you don't want to get caught by.) # $5) tmpfile # # Root must be able to execute this file if AOLserver runs as root # (which it does if it runs on a privileged port, e.g., port 80) HOME=$1 export HOME # set default language, in case, no language was given LANG=en_US.UTF-8 export LANG exec $2 $3 -a -p $4 < $5 openacs-5.7.0/bin/svrmgrl-example.sql0000644000175000017500000000240507253523116017416 0ustar frankiefrankie-- -- bin/svrmgrl-example.sql -- -- An example file to create a tablespace with the -- appropriate permissions. -- -- @author Richard Li (richardl@arsdigita.com) -- @creation-date 1 October 2000 -- @cvs-id $Id: svrmgrl-example.sql,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ connect internal; -- substitute a tablespace creation statement appropriate for your -- installation. this exact statement should almost never be used -- exactly as is. create tablespace yourservicename datafile '/ora8/m02/oradata/ora8/yourservicename01.dbf' size 50m autoextend on default storage (pctincrease 1); create user yourservicename identified by yourservicename default tablespace yourservicename temporary tablespace temp quota unlimited on yourservicename; grant connect, resource, ctxapp, javasyspriv, query rewrite to yourservicename; revoke unlimited tablespace from yourservicename; alter user yourservicename quota unlimited on yourservicename; -- these are necessary for utPLSQL. you shouldn't grant these on a -- production system unless absolutely necessary. grant create public synonym to yourservicename; grant drop public synonym to yourservicename; grant execute on dbms_pipe to yourservicename; grant drop any table to yourservicename; grant create any table to yourservicename; openacs-5.7.0/bin/pg_7.2to7.3_upgrade_helper.pl0000755000175000017500000001250210114404475020740 0ustar frankiefrankie#!/usr/bin/perl # Written by Richard Hamilton 02/05/04 # Based on an original script written by Jun Yamog # # usage: ./dump_parser.pl origdump newdump /your/oacs/dir # # This script examines the OpenACS file system and extracts # all function and view names that have length greater # than 32 chars and are therefore likely to have been # truncated by PostgreSQL version 7.2.x and earlier. # # It then parses a PostgreSQL v 7.2.x dumpfile and # substitutes the full function or view names for the # truncated ones, placing the output into a new dump file. # The new dump file can be used to restore on pg 7.3.x and 7.4.x # # requires: perl, grep and find # # These are the create statements on a dump file. I have # checked my own installations and only FUNCTION and VIEW # definitions have been affected. It is possible that in # some installations other object types are affected. # For this reason the script only goes through functions # and views, but may be easily modified to include other # types. # # CREATE CONSTRAINT # CREATE FUNCTION # CREATE INDEX # CREATE RULE # CREATE SEQUENCE # CREATE TABLE # CREATE TRIGGER # CREATE TRUSTED # CREATE UNIQUE # CREATE VIEW # # # look at this thread for further info # # http://openacs.org/forums/message-view?message_id=109337 # # # 2004-08-14 Gilbert Wong: # - modified s/ / / line to include ' (the apostrophe) # which is used in triggers and the gi option to catch multiple # instances of the key and all cases.. # - added command line argument checking # - added $types variable so that adding types can be done easily # - added the "copy" command to the list of commands to check ### do argument checking and sanity checks if ($#ARGV!=2) { # print error message print "\nThis script examines the OpenACS file system and extracts all function and view names that have length greater than 32 chars and are therefore likely to have been truncated by PostgreSQL version 7.2.x and earlier. It then parses a PostgreSQL v 7.2.x dumpfile and substitutes the full function or view names for the truncated ones, placing the output into a new dump file. The new dump file can be used to restore on pg 7.3.x and 7.4.x requires: perl, grep and find USAGE: ------ rhdmppsr2.pl origdump newdump /your/oacs/dir origdump: original PostgreSQL dump file newdump: cleaned up PostgreSQL dump file /your/oacs/dir: path to your OpenACS directory (e.g. /web/openacs-4)\n\n"; exit; } ### added by Gilbert Wong: ### edit these lines to add more types $types = "(function|view|table|sequence|trigger|constraint)"; ### get command line args $input_dump = $ARGV[0]; $output_dump = $ARGV[1]; $oacs_home = $ARGV[2]; ### added by Gilbert Wong: ### check existence of files and directories $errstr = ""; $errcnt = 0; if (!(-e $input_dump)) { $errstr .= "\nERROR: $input_dump does not exist"; $errcnt++; } if (!(-d $oacs_home)) { $errstr .= "\nERROR: $oacs_home does not exist"; $errcnt++; } if ($errcnt > 0) { print "$errstr\n\n"; exit; } # Grab object names from file system, split on newlines, and put in list called @object_names print("\nLooking up definitions in OpenACS *.sql files"); ### edited by Gilbert Wong: $types added below. $types is defined above #@object_names = (split /\n/, `find $oacs_home -name "*.sql" | xargs egrep -riI '(create|create or replace|drop) $types [^ ]* '`); @object_names = (split /\n/, `find $oacs_home -name "*.sql" | xargs egrep -riI '(create|create or replace|drop) $types \w*'`); print(" : DONE\n"); foreach $name (@object_names) { # Grab the name from each line and process it if it is longer than 32 characters ### edited by Gilbert Wong: $types added below. $types is defined above if (($name =~ /(create|create or replace|drop) $types (\w*)/i) && (length($3) > 31)) { # Each set of parentheses specifies a regexp memory. Our name is memory 3 ($3) $real_function_name = $3; print("Found declaration for: $real_function_name\n"); # Store full names in a hash called $full_name with the truncated name as key $full_name{substr($real_function_name, 0, 31)}=$real_function_name; } } print("\nPreparing to processing dump file: $input_dump\n\n"); # Now go through the dump file open(INPUT_DUMP, $input_dump); open(OUTPUT_DUMP, ">$output_dump"); while (my $line = ) { # For all lines beginning with 'CREATE', 'DROP' or '--NAME: "' ### added by Gilbert Wong: copy if ($line =~ /^(create|drop|copy|-- Name: ")/i) { # Loop through the hash of names for each line in the file foreach $key (keys %full_name) { # If it exists, substitute the truncated name in $key for the full name in the hash # The truncated name will be followed by an optional space and either a '"' or a '(' or a ''' (apostrophe for triggers). # Store whichever it is # in the $1 regexp memory and use it at the end of the substitution $original_line = $line; if ($line =~ s/$key( ?("|\(|'))/$full_name{$key}$1/ig) {printf("Original line: %sAmmended Line: %s\n", $original_line, $line);}; } } print OUTPUT_DUMP ($line); } close(INPUT_DUMP); close(OUTPUT_DUMP); print("==========================================================================\nWrote new dump file as $output_dump"); print(" : DONE\n"); print("Process Completed\n"); openacs-5.7.0/etc/0000755000175000017500000000000011724401450013544 5ustar frankiefrankieopenacs-5.7.0/etc/deploy.sh0000755000175000017500000000230510021355453015377 0ustar frankiefrankie#!/bin/bin/tclsh # process command line arguments foreach arg $argv { switch -glob -- $arg { --status {set status_p true} --help* {set help_p true} --switch* {set switch_p true} } } if { [llength $argv] = 0 } { set help_p true } if { $help_p } { puts stdout {Usage: deploy [--switch | --status | --help]} exit } if { $status_p } { set balance_txt [exec /usr/sbin/balance -c show 80] puts stdout $balance_txt exit } # the old bash script: # PROD=primary # ALT=alternate # BASE_DIR=/var/lib/aolserver # SVC_DIR=/var/lib/svscan # OLD=$1 # NEW=$2 # # basic premise: a server named foo is controlled by daemontools as $SVC_DIR/foo, # # and is actually rooted at BASE_DIR/foo # # when it is moved to production, its config.tcl is updated # # and the BASE_DIR/PROD link is changed to point to it # # and BASE_DIR/ALT is changed to point to whatever it replaced # svc -d $SVC_DIR/$OLD # svc -d $SVC_DIR/$NEW # cd $BASE_DIR # rm $PROD # rm $ALT # cd $BASE_DIR/$NEW/etc # cvs up -r $PROD config.tcl # cd $BASE_DIR/$OLD/etc # cvs up -r $ALT config.tcl # cd $BASE_DIR # ln -s $NEW $PROD # ln -s $OLD $ALT # svc -u $SVC_DIR/$NEW # svc -u $SVC_DIR/$OLD # # show status # svstat $SVC_DIR/* openacs-5.7.0/etc/config.tcl0000644000175000017500000006263311466054446015543 0ustar frankiefrankie# Changes in 5.6.0 # ================ # # - ROLLOUT SUPPORT # # ns_sendmail and its rollout support are now DEPRECATED in # OpenACS. Use acs_mail_lite::send instead. # # acs-mail-lite provides rollout support for acs_mail_lite::send and # implements ns_sendmail as a wrapper to it for backward # compatibility. See acs-mail-lite package parameters to set rollout # support. # ns_log notice "nsd.tcl: starting to read config file..." ###################################################################### # # Instance-specific settings # These default settings will only work in limited circumstances # Two servers with default settings cannot run on the same host # ###################################################################### #--------------------------------------------------------------------- # change to 80 and 443 for production use set httpport 8000 set httpsport 8443 # If setting port below 1024 with AOLServer 4, read comments in file: # /var/lib/aolserver/service0/packages/etc/daemontools/run # The hostname and address should be set to actual values. # setting the address to 0.0.0.0 means aolserver listens on all interfaces set hostname localhost set address 127.0.0.1 # Note: If port is privileged (usually < 1024), OpenACS must be # started by root, and, in AOLserver 4, the run script have a # '-b address' flag which matches the address according to settings (above) set server "service0" set servername "New OpenACS Installation - Development" set serverroot "/var/www/${server}" #--------------------------------------------------------------------- # which database do you want? postgres or oracle set database postgres set db_name $server if { $database eq "oracle" } { set db_password "mysitepassword" } else { set db_host localhost set db_port "" set db_user $server } #--------------------------------------------------------------------- # if debug is false, all debugging will be turned off set debug false set homedir /usr/lib/aolserver4 set bindir ${homedir}/bin set max_file_upload_mb 20 set max_file_upload_min 5 ###################################################################### # # End of instance-specific settings # # Nothing below this point need be changed in a default install. # ###################################################################### #--------------------------------------------------------------------- # # AOLserver's directories. Autoconfigurable. # #--------------------------------------------------------------------- # Where are your pages going to live ? set pageroot ${serverroot}/www set directoryfile index.tcl,index.adp,index.html,index.htm #--------------------------------------------------------------------- # Global server parameters #--------------------------------------------------------------------- ns_section ns/parameters ns_param serverlog ${serverroot}/log/error.log ns_param home $homedir # maxkeepalive is ignored in aolserver4.x ns_param maxkeepalive 0 ns_param logroll on ns_param logmaxbackup 10 ns_param maxbackup 5 ns_param debug $debug # ns_param mailhost localhost # setting to Unicode by default # see http://dqd.com/~mayoff/encoding-doc.html ns_param HackContentType 1 ns_param DefaultCharset utf-8 ns_param HttpOpenCharset utf-8 ns_param OutputCharset utf-8 ns_param URLCharset utf-8 #--------------------------------------------------------------------- # Thread library (nsthread) parameters #--------------------------------------------------------------------- ns_section ns/threads ns_param mutexmeter true ;# measure lock contention # The per-thread stack size must be a multiple of 8k for AOLServer to run under MacOS X ns_param stacksize [expr {128 * 8192}] # # MIME types. # ns_section ns/mimetypes # Note: AOLserver already has an exhaustive list of MIME types: # see: /usr/local/src/aolserver-4.{version}/aolserver/nsd/mimetypes.c # but in case something is missing you can add it here. ns_param Default */* ns_param NoExtension */* ns_param .pcd image/x-photo-cd ns_param .prc application/x-pilot ns_param .xls application/vnd.ms-excel ns_param .doc application/vnd.ms-word #--------------------------------------------------------------------- # # Server-level configuration # # There is only one server in AOLserver, but this is helpful when multiple # servers share the same configuration file. This file assumes that only # one server is in use so it is set at the top in the "server" Tcl variable # Other host-specific values are set up above as Tcl variables, too. # #--------------------------------------------------------------------- ns_section ns/servers ns_param $server $servername # # Server parameters # ns_section ns/server/${server} ns_param directoryfile $directoryfile ns_param pageroot $pageroot ns_param maxconnections 100 ;# Max connections to put on queue ns_param maxdropped 0 ns_param maxthreads 10 ns_param minthreads 5 ns_param threadtimeout 120 ;# Idle threads die at this rate ns_param globalstats false ;# Enable built-in statistics ns_param urlstats false ;# Enable URL statistics ns_param maxurlstats 1000 ;# Max number of URL's to do stats on # ns_param directoryadp $pageroot/dirlist.adp ;# Choose one or the other # ns_param directoryproc _ns_dirlist ;# ...but not both! # ns_param directorylisting fancy ;# Can be simple or fancy # # Special HTTP pages # ns_param NotFoundResponse "/global/file-not-found.html" ns_param ServerBusyResponse "/global/busy.html" ns_param ServerInternalErrorResponse "/global/error.html" #--------------------------------------------------------------------- # # ADP (AOLserver Dynamic Page) configuration # #--------------------------------------------------------------------- ns_section ns/server/${server}/adp ns_param map /*.adp ;# Extensions to parse as ADP's # ns_param map "/*.html" ;# Any extension can be mapped ns_param enableexpire false ;# Set "Expires: now" on all ADP's ns_param enabledebug $debug ;# Allow Tclpro debugging with "?debug" ns_param defaultparser fancy ns_section ns/server/${server}/adp/parsers ns_param fancy ".adp" ns_section ns/server/${server}/redirects ns_param 404 "global/file-not-found.html" ns_param 403 "global/forbidden.html" # # Tcl Configuration # ns_section ns/server/${server}/tcl ns_param library ${serverroot}/tcl ns_param autoclose on ns_param debug $debug #--------------------------------------------------------------------- # # WebDAV Support (optional, requires oacs-dav package to be installed # #--------------------------------------------------------------------- ns_section ns/server/${server}/tdav ns_param propdir ${serverroot}/data/dav/properties ns_param lockdir ${serverroot}/data/dav/locks ns_param defaultlocktimeout "300" ns_section ns/server/${server}/tdav/shares ns_param share1 "OpenACS" # ns_param share2 "Share 2 description" ns_section ns/server/${server}/tdav/share/share1 ns_param uri "/dav/*" # all WebDAV options ns_param options "OPTIONS COPY GET PUT MOVE DELETE HEAD MKCOL POST PROPFIND PROPPATCH LOCK UNLOCK" #ns_section ns/server/${server}/tdav/share/share2 # ns_param uri "/share2/path/*" # read-only WebDAV options # ns_param options "OPTIONS COPY GET HEAD MKCOL POST PROPFIND PROPPATCH" #--------------------------------------------------------------------- # # Socket driver module (HTTP) -- nssock # #--------------------------------------------------------------------- ns_section ns/server/${server}/module/nssock ns_param timeout 120 ns_param address $address ns_param hostname $hostname ns_param port $httpport # setting maxinput higher than practical may leave the server vulnerable to resource DoS attacks # see http://www.panoptic.com/wiki/aolserver/166 ns_param maxinput [expr {$max_file_upload_mb * 1024 * 1024}] ;# Maximum File Size for uploads in bytes ns_param maxpost [expr {$max_file_upload_mb * 1024 * 1024}] ;# Maximum File Size for uploads in bytes ns_param recvwait [expr {$max_file_upload_min * 60}] ;# Maximum request time in minutes # maxsock will limit the number of simultanously returned pages, # regardless of what maxthreads is saying ns_param maxsock 100 ;# 100 = default # On Windows you need to set this parameter to define the number of # connections as well (it seems). ns_param backlog 5 ;# if < 1 == 5 # Optional params with defaults: ns_param bufsize 16000 ns_param rcvbuf 0 ns_param sndbuf 0 ns_param socktimeout 30 ;# if < 1 == 30 ns_param sendwait 30 ;# if < 1 == socktimeout ns_param recvwait 30 ;# if < 1 == socktimeout ns_param closewait 2 ;# if < 0 == 2 ns_param keepwait 30 ;# if < 0 == 30 ns_param readtimeoutlogging false ns_param serverrejectlogging false ns_param sockerrorlogging false ns_param sockshuterrorlogging false #--------------------------------------------------------------------- # # Access log -- nslog # #--------------------------------------------------------------------- ns_section ns/server/${server}/module/nslog ns_param debug false ns_param dev false ns_param enablehostnamelookup false ns_param file ${serverroot}/log/${server}.log ns_param logcombined true ns_param extendedheaders COOKIE # ns_param logrefer false # ns_param loguseragent false ns_param logreqtime true ns_param maxbackup 1000 ns_param rollday * ns_param rollfmt %Y-%m-%d-%H:%M ns_param rollhour 0 ns_param rollonsignal true ns_param rolllog true #--------------------------------------------------------------------- # # nsjava - aolserver module that embeds a java virtual machine. Needed to # support webmail. See http://nsjava.sourceforge.net for further # details. This may need to be updated for OpenACS4 webmail # #--------------------------------------------------------------------- ns_section ns/server/${server}/module/nsjava ns_param enablejava off ;# Set to on to enable nsjava. ns_param verbosejvm off ;# Same as command line -debug. ns_param loglevel Notice ns_param destroyjvm off ;# Destroy jvm on shutdown. ns_param disablejitcompiler off ns_param classpath /usr/local/jdk/jdk118_v1/lib/classes.zip:${bindir}/nsjava.jar:${pageroot}/webmail/java/activation.jar:${pageroot}/webmail/java/mail.jar:${pageroot}/webmail/java #--------------------------------------------------------------------- # # CGI interface -- nscgi, if you have legacy stuff. Tcl or ADP files inside # AOLserver are vastly superior to CGIs. I haven't tested these params but they # should be right. # #--------------------------------------------------------------------- #ns_section "ns/server/${server}/module/nscgi" # ns_param map "GET /cgi-bin ${serverroot}/cgi-bin" # ns_param map "POST /cgi-bin ${serverroot}/cgi-bin" # ns_param Interps CGIinterps #ns_section "ns/interps/CGIinterps" # ns_param .pl "/usr/bin/perl" #--------------------------------------------------------------------- # # PAM authentication # #--------------------------------------------------------------------- ns_section ns/server/${server}/module/nspam ns_param PamDomain "pam_domain" #--------------------------------------------------------------------- # # OpenSSL for Aolserver 4 # #--------------------------------------------------------------------- ns_section "ns/server/${server}/module/nsopenssl" # this is used by acs-tcl/tcl/security-procs.tcl to get the https port. ns_param ServerPort $httpsport # setting maxinput higher than practical may leave the server vulnerable to resource DoS attacks # see http://www.panoptic.com/wiki/aolserver/166 # must set maxinput for nsopenssl as well as nssock ns_param maxinput [expr {$max_file_upload_mb * 1024 * 1024}] ;# Maximum File Size for uploads in bytes # We explicitly tell the server which SSL contexts to use as defaults when an # SSL context is not specified for a particular client or server SSL # connection. Driver connections do not use defaults; they must be explicitly # specificied in the driver section. The Tcl API will use the defaults as there # is currently no provision to specify which SSL context to use for a # particular connection via an ns_openssl Tcl command. ns_section "ns/server/${server}/module/nsopenssl/sslcontexts" ns_param users "SSL context used for regular user access" # ns_param admins "SSL context used for administrator access" ns_param client "SSL context used for outgoing script socket connections" ns_section "ns/server/${server}/module/nsopenssl/defaults" ns_param server users ns_param client client ns_section "ns/server/${server}/module/nsopenssl/sslcontext/users" ns_param Role server ns_param ModuleDir ${serverroot}/etc/certs ns_param CertFile users-certfile.pem ns_param KeyFile users-keyfile.pem # CADir/CAFile can be commented out, if CA chain cert is appended to CA issued server cert. ns_param CADir ${serverroot}/etc/certs ns_param CAFile users-ca.crt # for Protocols "ALL" = "SSLv2, SSLv3, TLSv1" ns_param Protocols "SSLv3, TLSv1" ns_param CipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" ns_param PeerVerify false ns_param PeerVerifyDepth 3 ns_param Trace false # following helps to stablize some openssl connections from buggy clients. ns_param SessionCache true ns_param SessionCacheID 1 ns_param SessionCacheSize 512 ns_param SessionCacheTimeout 300 # ns_section "ns/server/${server}/module/nsopenssl/sslcontext/admins" # ns_param Role server # ns_param ModuleDir /path/to/dir # ns_param CertFile server/server.crt # ns_param KeyFile server/server.key # ns_param CADir ca-client/dir # ns_param CAFile ca-client/ca-client.crt # for Protocols "ALL" = "SSLv2, SSLv3, TLSv1" # ns_param Protocols "All" # ns_param CipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" # ns_param PeerVerify false # ns_param PeerVerifyDepth 3 # ns_param Trace false ns_section "ns/server/${server}/module/nsopenssl/sslcontext/client" ns_param Role client ns_param ModuleDir ${serverroot}/etc/certs ns_param CertFile client-certfile.pem ns_param KeyFile client-keyfile.pem # CADir/CAFile can be commented out, if CA chain cert is appended to CA issued server cert. ns_param CADir ${serverroot}/etc/certs ns_param CAFile client-ca.crt # for Protocols "ALL" = "SSLv2, SSLv3, TLSv1" ns_param Protocols "SSLv2, SSLv3, TLSv1" ns_param CipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" ns_param PeerVerify false ns_param PeerVerifyDepth 3 ns_param Trace false # following helps to stablize some openssl connections to buggy servers. ns_param SessionCache true ns_param SessionCacheID 1 ns_param SessionCacheSize 512 ns_param SessionCacheTimeout 300 # SSL drivers. Each driver defines a port to listen on and an explitictly named # SSL context to associate with it. Note that you can now have multiple driver # connections within a single virtual server, which can be tied to different # SSL contexts. ns_section "ns/server/${server}/module/nsopenssl/ssldrivers" ns_param users "Driver for regular user access" # ns_param admins "Driver for administrator access" ns_section "ns/server/${server}/module/nsopenssl/ssldriver/users" ns_param sslcontext users # ns_param port $httpsport_users ns_param port $httpsport ns_param hostname $hostname ns_param address $address # following added per # http://www.mail-archive.com/aolserver@listserv.aol.com/msg07365.html # Maximum File Size for uploads: ns_param maxinput [expr {$max_file_upload_mb * 1024 * 1024}] ;# in bytes # Maximum request time ns_param recvwait [expr {$max_file_upload_min * 60}] ;# in minutes # ns_section "ns/server/${server}/module/nsopenssl/ssldriver/admins" # ns_param sslcontext admins # ns_param port $httpsport_admins # ns_param port $httpsport # ns_param hostname $hostname # ns_param address $address #--------------------------------------------------------------------- # # Database drivers # The database driver is specified here. # Make sure you have the driver compiled and put it in {aolserverdir}/bin # #--------------------------------------------------------------------- ns_section "ns/db/drivers" if { $database eq "oracle" } { ns_param ora8 ${bindir}/ora8.so } else { ns_param postgres ${bindir}/nspostgres.so ;# Load PostgreSQL driver } if { $database eq "oracle" } { ns_section "ns/db/driver/ora8" ns_param maxStringLogLength -1 ns_param LobBufferSize 32768 } # Database Pools: This is how AOLserver ``talks'' to the RDBMS. You need # three for OpenACS: main, log, subquery. Make sure to replace ``yourdb'' # and ``yourpassword'' with the actual values for your db name and the # password for it, if needed. # # AOLserver can have different pools connecting to different databases # and even different different database servers. See # http://openacs.org/doc/tutorial-second-database.html # An example 'other db' configuration is included (and commented out) using other1_db_name # set other1_db_name "yourDBname" ns_section ns/db/pools ns_param pool1 "Pool 1" ns_param pool2 "Pool 2" ns_param pool3 "Pool 3" # ns_param pool4 "Pool4 Other1" # ns_param pool5 "Pool5 Other1" # ns_param pool6 "Pool6 Other1" ns_section ns/db/pool/pool1 ns_param maxidle 0 ns_param maxopen 0 ns_param connections 15 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database eq "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource ${db_host}:${db_port}:${db_name} ns_param user $db_user ns_param password "" } ns_section ns/db/pool/pool2 ns_param maxidle 0 ns_param maxopen 0 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database eq "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource ${db_host}:${db_port}:${db_name} ns_param user $db_user ns_param password "" } ns_section ns/db/pool/pool3 ns_param maxidle 0 ns_param maxopen 0 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database eq "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource ${db_host}:${db_port}:${db_name} ns_param user $db_user ns_param password "" } # ns_section ns/db/pool/pool4 # ns_param maxidle 0 # ns_param maxopen 0 # ns_param connections 5 # ns_param verbose $debug # ns_param extendedtableinfo true # ns_param logsqlerrors $debug # if { $database eq "oracle" } { # ns_param driver ora8 # ns_param datasource {} # ns_param user $db_name # ns_param password $db_password # } else { # ns_param driver postgres # ns_param datasource ${db_host}:${db_port}:${other1_db_name} # ns_param user $db_user # ns_param password "" # } # ns_section ns/db/pool/pool5 # ... # ns_section ns/db/pool/pool6 # ... ns_section ns/server/${server}/db ns_param pools pool1,pool2,pool3 # if a second db is added, add the pools here. for example, replace above line with: # ns_param pools pool1,pool2,pool3,pool4,pool5,pool6 ns_param defaultpool pool1 # following from http://openacs.org/doc/tutorial-second-database.html #ns_section ns/server/${server}/acs/database # ns_param database_names [list main other1] # ns_param pools_main [list pool1 pool2 pool3] # ns_param pools_other1 [list pool4 pool5 pool6] # Start each pool set with pools_* # The code assumes the name in database_names matches the suffix to pools_ in one of the ns_params. #--------------------------------------------------------------------- # which modules should be loaded? Missing modules break the server, so # don't uncomment modules unless they have been installed. ns_section ns/server/${server}/modules ns_param nssock ${bindir}/nssock.so ns_param nslog ${bindir}/nslog.so ns_param nssha1 ${bindir}/nssha1.so # since aolserver version 4.5.1 built-in ns_cache, so we dont # need to load the nscache module. if {[ns_info version] < 4.5 || [ns_info patchlevel] eq "4.5.0"} { ns_param nscache ${bindir}/nscache.so } # openacs versions earlier than 5.x requires nsxml # ns_param nsxml ${bindir}/nsxml.so #--------------------------------------------------------------------- # nsopenssl will fail unless the cert files are present as specified # later in this file, so it's disabled by default # ns_param nsopenssl ${bindir}/nsopenssl.so # authorize-gateway package requires dqd_utils # ns_param dqd_utils dqd_utils[expr {int($tcl_version)}].so # Full Text Search # ns_param nsfts ${bindir}/nsfts.so # PAM authentication # ns_param nspam ${bindir}/nspam.so # LDAP authentication # ns_param nsldap ${bindir}/nsldap.so # These modules aren't used in standard OpenACS installs # ns_param nsperm ${bindir}/nsperm.so # ns_param nscgi ${bindir}/nscgi.so # ns_param nsjava ${bindir}/libnsjava.so # ns_param nsrewrite ${bindir}/nsrewrite.so if { [ns_info version] >= 4 } { # Required for AOLserver 4.x ns_param nsdb ${bindir}/nsdb.so } else { # Required for AOLserver 3.x ns_param libtdom ${bindir}/libtdom.so } # nsthread library which should become standard in 5.3 ns_param libthread [lindex [glob ${homedir}/lib/thread*/libthread*[info sharedlibextension]] 0] if {[ns_info version] >= 4.5} { ns_limits set default -maxupload [ns_config ns/server/${server}/module/nssock maxinput] } ns_log notice "nsd.tcl: using threadsafe tcl: [info exists tcl_platform(threaded)]" ns_log notice "nsd.tcl: finished reading config file." openacs-5.7.0/etc/analog.cfg0000644000175000017500000001113310207353611015465 0ustar frankiefrankie# Configuration file for analog 5.32 # See http://www.analog.cx/ # modified by Joel Aufrecht for OpenACS Reference Platform 09 March 2003 # modified in April 2004 for http://openacs.org/bugtracker/openacs/bug?bug%5fnumber=1359 # # Here are a couple of configuration commands to get you started. Add any more # you like from the Readme. # # Lines starting with # are comments. # # There is a much more extensive configuration file in examples/big.cfg # # If you need a LOGFORMAT command (most people don't -- try it without first!), # it must go here, above the LOGFILE commands. LOGFORMAT (%S %j %j [%d/%M/%Y:%h:%n:%j] "%j%w%r%wHTTP%j" %c %b "%f" "%B" %j\n) # If your /etc/config.tcl file includes the logreqtime parameter, and # it is set to true, you can change the LOGFORMAT # LOGFORMAT (%S %j %j [%d/%M/%Y:%h:%n:%j] "%j%w%r%wHTTP%j" %c %b "%f" "%B" %j\n) LOGFILE /var/lib/aolserver/service0/log/service0.log* OUTFILE /var/lib/aolserver/service0/www/log/traffic.html # do DNS lookups DNSFILE /var/lib/aolserver/service0/log/dnscache DNSLOCKFILE /var/lib/aolserver/service0/log/dnslock DNS WRITE HOSTNAME "[Your Organization]" # exclude these hosts # Put your own network here to omit local calls from the total # HOSTEXCLUDE 10.10.0.* ###################################################################### # # You probably don't need to change anything below this until you are # experienced. IMAGEDIR /log/images/ PNGIMAGES ON ALLCHART OFF DESCRIPTIONS OFF GOTOS OFF # ERRFILE errors.txt # REQINCLUDE pages REQLINKINCLUDE pages REFLINKINCLUDE * REDIRREFLINKINCLUDE * FAILREFLINKINCLUDE * SUBBROW */* SUBTYPE *.gz,*.Z # OSCHARTEXPAND Windows # Add whichever of these types of pages you have on your server, or others. PAGEINCLUDE .adp PAGEINCLUDE .tcl # PAGEINCLUDE *.shtml # PAGEINCLUDE *.asp # PAGEINCLUDE *.jsp # PAGEINCLUDE *.cfm # PAGEINCLUDE *.pl # PAGEINCLUDE *.php # More SEARCHENGINE commands can be found at # http://www.analog.cx/helpers/#conffiles SEARCHENGINE http://*google.*/* q,as_q,as_epq,as_oq SEARCHENGINE http://*altavista.*/* q SEARCHENGINE http://*yahoo.*/* p SEARCHENGINE http://*lycos.*/* query,wfq SEARCHENGINE http://*aol.*/* query SEARCHENGINE http://*excite.*/* search SEARCHENGINE http://*go2net.*/* general SEARCHENGINE http://*metacrawler.*/* general SEARCHENGINE http://*msn.*/* q,MT SEARCHENGINE http://*netscape.*/* search SEARCHENGINE http://*looksmart.*/* key SEARCHENGINE http://*webcrawler.*/* qkw,search,searchText SEARCHENGINE http://*overture.*/* Keywords SEARCHENGINE http://*teoma.*/* q SEARCHENGINE http://*infospace.*/* qkw SEARCHENGINE http://*alltheweb.*/* q SEARCHENGINE http://*dogpile.*/* q SEARCHENGINE http://*ask.*/* ask SEARCHENGINE http://*alltheweb.*/* query SEARCHENGINE http://*northernlight.*/* qr SEARCHENGINE http://*nlsearch.*/* qr SEARCHENGINE http://*dmoz.*/* search SEARCHENGINE http://*/netfind* query SEARCHENGINE http://*/pursuit query ROBOTINCLUDE REGEXPI:robot ROBOTINCLUDE REGEXPI:spider ROBOTINCLUDE REGEXPI:crawler ROBOTINCLUDE Googlebot* ROBOTINCLUDE Infoseek* ROBOTINCLUDE Scooter* ROBOTINCLUDE *Slurp* ROBOTINCLUDE *Validator* ROBOTINCLUDE Ultraseek* TYPEALIAS .html ".html [Hypertext Markup Language]" TYPEALIAS .htm ".htm [Hypertext Markup Language]" TYPEALIAS .shtml ".shtml [Server-parsed HTML]" TYPEALIAS .ps ".ps [PostScript]" TYPEALIAS .gz ".gz [Gzip compressed files]" TYPEALIAS .tar.gz ".tar.gz [Compressed archives]" TYPEALIAS .jpg ".jpg [JPEG graphics]" TYPEALIAS .jpeg ".jpeg [JPEG graphics]" TYPEALIAS .gif ".gif [GIF graphics]" TYPEALIAS .png ".png [PNG graphics]" TYPEALIAS .txt ".txt [Plain text]" TYPEALIAS .cgi ".cgi [CGI scripts]" TYPEALIAS .pl ".pl [Perl scripts]" TYPEALIAS .css ".css [Cascading Style Sheets]" TYPEALIAS .class ".class [Java class files]" TYPEALIAS .pdf ".pdf [Adobe Portable Document Format]" TYPEALIAS .zip ".zip [Zip archives]" TYPEALIAS .hqx ".hqx [Macintosh BinHex files]" TYPEALIAS .exe ".exe [Executables]" TYPEALIAS .wav ".wav [WAV sound files]" TYPEALIAS .avi ".avi [AVI movies]" TYPEALIAS .arc ".arc [Compressed archives]" TYPEALIAS .mid ".mid [MIDI sound files]" TYPEALIAS .mp3 ".mp3 [MP3 sound files]" TYPEALIAS .doc ".doc [Microsoft Word document]" TYPEALIAS .rtf ".rtf [Rich Text Format]" TYPEALIAS .mov ".mov [Quick Time movie]" TYPEALIAS .mpg ".mpg [MPEG movie]" TYPEALIAS .mpeg ".mpeg [MPEG movie]" TYPEALIAS .asp ".asp [Active Server Pages]" TYPEALIAS .jsp ".jsp [Java Server Pages]" TYPEALIAS .cfm ".cfm [Cold Fusion]" TYPEALIAS .php ".php [PHP]" TYPEALIAS .js ".js [JavaScript code]" openacs-5.7.0/etc/keepalive/0000755000175000017500000000000011575226031015515 5ustar frankiefrankieopenacs-5.7.0/etc/keepalive/keepalive.sh0000755000175000017500000000347610520167113020025 0ustar frankiefrankie#!/bin/sh # # This script will attempt to request the db test page of a number of OpenACS # servers. If a server doesn't respond then a configurable restart shell command will # be executed. The restart command may for example send an email alert and/or log to some # log file and then restart the server. The URLs of the servers to monitor and their # restart commands are expected to be in a config file named keepalive-config.tcl # in the same directory as this script # # @author Peter Marklund # the next line restarts using tclsh, the trailing slash is intentional \ exec /usr/bin/tclsh "$0" "$@" set script_dir [file dirname [info script]] source $script_dir/keepalive-config.tcl proc server_responds_p { server_url } { set script_dir [file dirname [info script]] set wget_file $script_dir/dbtest if { [file exists $wget_file] } { file delete -force $wget_file } catch {exec /usr/bin/wget -O $wget_file --tries=5 --timeout=7 ${server_url}/SYSTEM/dbtest} if { [file exists $wget_file] } { set wget_file_id [open $wget_file r] set wget_file_contents [read $wget_file_id] close $wget_file_id if { [regexp {success} $wget_file_contents] } { set responds_p 1 } else { set responds_p 0 } } else { set responds_p 0 } return $responds_p } foreach {server_url restart_command} $servers_to_monitor { puts -nonewline "Checking server at $server_url - " if { [server_responds_p $server_url] } { puts "server responds." } else { puts -nonewline "no response. " puts "Executing command \"$restart_command\" to restart server." if { [catch {eval exec $restart_command} errmsg] } { puts "Error executing restart_command: $errmsg" } } } openacs-5.7.0/etc/keepalive/keepalive-config.tcl0000644000175000017500000000103110551254367021432 0ustar frankiefrankie# Config file for the keepalive.sh script # # @author Peter Marklund # The servers_to_monitor variable should be a flat list with URLs to monitor # on even indices and the commands to execute if the server doesn't respond # on odd indices, like this: # {server_url1 restart_command1 server_url2 restart_command2 ...} set servers_to_monitor {} # How long the keepalive script waits until it attempts another restart set seconds_between_restarts [expr {10*60}] # Who shall we email if the server is/cannot be restarted? set mailto root openacs-5.7.0/etc/keepalive/keepalive-cron.sh0000755000175000017500000000365710520167113020765 0ustar frankiefrankie#!/bin/sh # # This script will attempt to request the db test page of a number of OpenACS # servers. If a server doesn't respond then a configurable restart shell command will # be executed. The restart command may for example send an email alert and/or log to some # log file and then restart the server. The URLs of the servers to monitor and their # restart commands are expected to be in a config file named keepalive-config.tcl # in the same directory as this script # # If you're having problems with this script, you should look at this thread: # http://openacs.org/forums/message-view?message_id=260846 # # @author Peter Marklund # the next line restarts using tclsh, the trailing slash is intentional \ exec /usr/bin/tclsh "$0" "$@" set script_dir [file dirname [info script]] source $script_dir/keepalive-config.tcl proc server_responds_p { server_url } { set script_dir [file dirname [info script]] set wget_file $script_dir/dbtest if { [file exists $wget_file] } { file delete -force $wget_file } catch {exec /usr/bin/wget -O $wget_file --tries=5 --timeout=7 ${server_url}/SYSTEM/dbtest} if { [file exists $wget_file] } { set wget_file_id [open $wget_file r] set wget_file_contents [read $wget_file_id] close $wget_file_id if { [regexp {success} $wget_file_contents] } { set responds_p 1 } else { set responds_p 0 } } else { set responds_p 0 } return $responds_p } foreach {server_url restart_command} $servers_to_monitor { if { ![server_responds_p $server_url] } { if { [catch {eval exec $restart_command} errmsg] } { catch { exec /bin/mail -s "${server_url} did not respond to a monitoring check and could not be restarted" $mailto } } else { catch { exec /bin/mail -s "${server_url} did not respond to a monitoring check so it was restarted" $mailto } } } } openacs-5.7.0/etc/backup.sh0000755000175000017500000002060610607360167015364 0ustar frankiefrankie#!/bin/bash # # $Id: backup.sh,v 1.13 2007/04/12 07:32:07 maltes Exp $ # # full and incremental backup script # created 07 February 2000 # Based on a script by Daniel O'Callaghan # and modified by Gerhard Mourani # modified more by Joel Aufrecht in 2002 # merged with Collaboraid database backups Dec 2003 # 2004-02-10: Joel Aufrecht: added rolling delete and space check # # Change the variables below to fit your computer/backup # COMPUTER=yourserver.net # name of this computer DBHOST=localhost # name of the computer running the database BACKUPUSER=backup # username to own the files BACKUPDIR=/backup/thisserver # where to store the backups BACKUPPART=/dev/hda1 # which partition are we backing up to # (would be nice to figure this out automatically) WEBDIR=/var/lib/aolserver # path to OpenACS service root FULL_SPACE_FREE=5 # must be this many GB free to run full backup # if not, try incremental INCR_SPACE_FREE=1 # must be this many GB free to run incremental # if not, don't back up OTHERHOST=theservice.de # another server, to receive backup # files # leave blank to skip scp exchange WIPE_OLD_AFTER_SCP_FULL=false # if true, then whenever a full backup file is # sucessfully scp'ed to OTHERHOST, wipe out all # similar backups except for the full backup file # rationale is, keep last good full + incrementals # on this box, keep everything on other box OTHERUSER=malte # the user on the recipient server # must have silent authentication, ie, # certificates # script assumes an exact match between database # name and filesystem POSTGRES_DBS="service0" # space-separated list of postgres databases # to be backed up to file system ORACLE8I_DBS="service0" # space-separated list of Oracle8i databases # to be backed up to file system # space-separated list of directories to be backed up KEEP_DAYS=7 # Number of days to keep backups in $BACKUPDIR RSYNC="no" # Use RSYNC for the content-repository. Useful with large amount of content #--------------------------------------------------------------------- # a space-delimited list of directories to back up # A minimal backup DIRECTORIES="/var/lib/aolserver/service0" # # this is a fairly thorough set of data back - must run as root to work, though #DIRECTORIES="/etc /home /root /cvsroot /var/qmail/alias /usr/local/aolserver $WEBDIR" #--------------------------------------------------------------------- # System Program Paths PG_BINDIR=/usr/local/pg80/bin # path to PostGreSQL binaries TIMEDIR=$BACKUPDIR/last-full # where to store time of full backup TAR=/bin/tar # name and location of tar CHOWN=/bin/chown CHMOD=/bin/chmod SCP="/usr/bin/scp -oProtocol=2" ####################################################################### # # Shouldn't need to change anything below this line # ####################################################################### DOW=`date +%a` # Day of the week e.g. Mon DOM=`date +%d` # Date of the Month e.g. 27 DM=`date +%d%b` # Date and Month e.g. 27Sep DATE=`date +"%Y-%m-%d"` # Year, Month, Date, e.g. 20020401 # A full backup is generated: # the first time the script is run, # On the 1st of the month # Every Sunday # The rest of the time the backup includes only files that have changed # since the last full backup # Each backup has a date-specific filename # #--------------------------------------------------------------------- # Parse command line #--------------------------------------------------------------------- case $1 in --full) TYPE="full" ;; --help | -help | -h | --h) echo "Usage: $0 --full to force full backup, or $0 to run automated. All other variables are set in the script." exit;; *) esac if [ ! -s $TIMEDIR/$COMPUTER-full-date ]; then TYPE="full"; fi if [[ $DOM == "01" || $DOW == "Sun" ]]; then TYPE="full"; fi if [ $TYPE == "full" ]; then NEW_FLAG="" else TYPE="incremental" NEW_FLAG="--newer-mtime `cat $TIMEDIR/$COMPUTER-full-date`"; fi #--------------------------------------------------------------------- # Check for free space #--------------------------------------------------------------------- # get free byte count free=`df | grep $BACKUPPART | awk '{print $4}'` # force to incremental if there isn't room for full if [ $free -lt `expr $FULL_SPACE_FREE \* 1024 \* 1024` ]; then TYPE="incremental" echo "Not enough free space for full backup; trying incremental" fi # abort if there isn't room for incremental if [ $free -lt `expr $INCR_SPACE_FREE \* 1024 \* 1024` ]; then echo "Not enough free space for backup; aborting" exit -1 fi mkdir -p $BACKUPDIR mkdir -p $TIMEDIR #--------------------------------------------------------------------- # Dump databases #--------------------------------------------------------------------- #--------------------------------------------------------------------- # PostGreSQL echo -e "\nPostgres" for dbname in $POSTGRES_DBS do dmp_file=$WEBDIR/$dbname/database-backup/$dbname-nightly-backup.dmp echo -n "-> Dumping $dbname to $dmp_file ... " time $PG_BINDIR/pg_dump -f $dmp_file -Fp $dbname -h $DBHOST /bin/ls -lh $dmp_file | awk '{print $5}' gzip -f $dmp_file done #--------------------------------------------------------------------- # Oracle for dbname in $ORACLE8IDBS do dmp_file=$WEBDIR/$dbname/database-backup/$dbname-nightly-backup.dmp echo -n "-> Dumping $dbname to $dmp_file ... " time /usr/sbin/export-oracle $dbname $dmp_file /bin/ls -lh $dmp_file | awk '{print $5}' gzip -f $dmp_file done #--------------------------------------------------------------------- # Make backup files from file system and transfer to remote site # TODO: This could be parallelized #--------------------------------------------------------------------- # we switched from bzip2 back to gzip because bzip2 takes 10 times longer # for a 10% size advantage for directory in $DIRECTORIES do # strip directory of slashes when using it in the backup file name FULLNAME=$BACKUPDIR/$DATE-$COMPUTER-${directory//\//-}-backup-$TYPE.tar.gz # to use bzip2 instead of gzip, change z to j in the tar flags cd $directory if [[ $RSYNC == "yes" ]]; then # Exclude at least on GNU Tar is picky about using the full patch and the order exclude and directoy. tar -zcpsh --file $FULLNAME --exclude "$directory/content-repository-content-files" $NEW_FLAG $directory else tar -zcpsh . --file $FULLNAME $NEW_FLAG fi $CHOWN $BACKUPUSER $FULLNAME $CHMOD 660 $FULLNAME if [ -n "$OTHERHOST" ] then scp_success=1 if [[ $RSYNC == "yes" ]]; then rsync -aq $BACKUPDIR $OTHERUSER@$OTHERHOST:$BACKUPDIR else scp_success=`$SCP -q $FULLNAME $OTHERUSER@$OTHERHOST:$BACKUPDIR` fi # if scp returns success, see if we should wipe if [[ scp_success -eq 0 && $WIPE_OLD_AFTER_SCP_FULL == "true" && $TYPE == "full" ]]; then # wipe out all similar backups except for the just-copied one for file in `ls $BACKUPDIR/*-$COMPUTER-${directory//\//-}-backup-*.tgz` do if [ $file != $FULLNAME] then rm $file fi done fi fi done # If full backup completed successfully, record the date so that # incremental backups are relative to the last successful full # backup if [ $TYPE == "full" ]; then NEWER="" NOW=`date +%Y-%m-%d` echo $NOW> $TIMEDIR/$COMPUTER-full-date; fi # Delete old files /usr/bin/find $BACKUPDIR -atime +$KEEP_DAYS -exec /bin/rm -f {} \; echo "Done." openacs-5.7.0/etc/install/0000755000175000017500000000000011724401450015212 5ustar frankiefrankieopenacs-5.7.0/etc/install/tcl/0000755000175000017500000000000011724401450015774 5ustar frankiefrankieopenacs-5.7.0/etc/install/tcl/config-procs.tcl0000644000175000017500000000305507745745365021124 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs for getting config info. If those tests were to run # from within OpenACS some of these procs could go away. # # @author Peter Marklund namespace eval ::twt::config {} #################### # # Global variables # #################### # TODO: put variables in twt namespace global __serverroot set __serverroot $serverroot global __server_url set __server_url $server_url global __admin_last_name set __admin_last_name $admin_last_name global __admin_email set __admin_email $admin_email global __admin_password set __admin_password $admin_password global __url_history set __url_history [list] global __demo_users_password if { [info exists demo_users_password] } { set __demo_users_password $demo_users_password } else { set __demo_users_password "guest" } global __dotlrn_users_data_file if { [info exists dotlrn_users_data_file] } { set __dotlrn_users_data_file $dotlrn_users_data_file } else { set __dotlrn_users_data_file users-data.csv } global __alert_keyword set __alert_keyword $alert_keyword ad_proc ::twt::config::server_url { } { global __server_url return $__server_url } ad_proc ::twt::config::admin_email { } { global __admin_email return $__admin_email } ad_proc ::twt::config::admin_password { } { global __admin_password return $__admin_password } ad_proc ::twt::config::serverroot { } { global __serverroot return $__serverroot } ad_proc ::twt::config::alert_keyword { } { global __alert_keyword return $__alert_keyword } openacs-5.7.0/etc/install/tcl/new-portal-procs.tcl0000644000175000017500000000322107745745365021742 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs for testing the acs-lang (I18N) package # # @author Peter Marklund namespace eval ::twt::new_portal {} namespace eval ::twt::new_portal::test {} ad_proc ::twt::new_portal::test::customize_layout {} { Test customizing the layout of the MySpace page. } { # Visit the customize layout page ::twt::do_request "/dotlrn/configure" # Revert to default layout to have a clean starting point form find ~n op_revert form submit # Remove an element link follow ~u {configure-2.*op_hide=1} # Move element in different directions link follow ~u {configure-2.*op_swap=1.*direction=up} link follow ~u {configure-2.*op_swap=1.*direction=down} link follow ~u {configure-2.*op_move=1.*direction=right} # Move element to different page form find ~n op_move_to_page form submit # Rename a page form find ~n op_rename_page set test_page_name "__test_page_name" field fill $test_page_name ~n pretty_name form submit # Assert that the test page name is there ::twt::assert "page rename was successful" [regexp "$test_page_name" [response body]] # Add a page form find ~n op_add_page form submit # Revert back to default layout form find ~n op_revert form submit # Assert that the test page name is gone ::twt::assert "test page name gone after revert" [expr ![regexp "$test_page_name" [response body]]] # Assert three pages set page_count [regexp -all {]+?name="op_rename_page"} [response body]] ::twt::assert_equals "customize page has three pages after revert" $page_count "3" } openacs-5.7.0/etc/install/tcl/dotlrn-procs.tcl0000644000175000017500000003100610551254367021140 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs related to creating a basic .LRN class and communities setup. # Membership of the classes is handled by procs in class-procs.tcl. # # @author Peter Marklund namespace eval ::twt::dotlrn {} namespace eval ::twt::dotlrn::test {} ad_proc ::twt::dotlrn::add_term { server_url term_name start_month start_year end_month end_year } { ::twt::do_request "/dotlrn/admin/term-new" form find ~n add_term field find ~n "term_name" field fill "$term_name" # Start date ::twt::multiple_select_value start_date.month $start_month ::twt::multiple_select_value start_date.day "1" field find ~n "start_date.year" field fill $start_year # End date ::twt::multiple_select_value end_date.month $end_month ::twt::multiple_select_value end_date.day "1" field find ~n "end_date.year" field fill $end_year form submit } ad_proc ::twt::dotlrn::setup_terms { server_url } { add_term $server_url "Spring" "1" "2004" "7" "2004" add_term $server_url "Fall" "9" "2004" "1" "2005" add_term $server_url "Spring" "1" "2005" "7" "2005" } ad_proc ::twt::dotlrn::current_term_pretty_name {} { return "Spring 2004" } ad_proc ::twt::dotlrn::current_term_id {} { ::twt::do_request [class_admin_url] form find ~n term_form field find ~n term_id # Term pretty names are not I18N so this will work in different locales field select [current_term_pretty_name] array set term_select_field [field current] set term_id $term_select_field(value) return $term_id } ad_proc ::twt::dotlrn::class_admin_url { {-term_id "-1"} } { return "/dotlrn/admin/term?term_id=$term_id" } ad_proc ::twt::dotlrn::add_department { server_url pretty_name description external_url } { ::twt::do_request "/dotlrn/admin/department-new" form find ~n add_department field find ~n "pretty_name" field fill $pretty_name field find ~n "description" field fill $description field find ~n "external_url" field fill $external_url form submit } ad_proc ::twt::dotlrn::setup_departments { server_url } { add_department $server_url "Mathematics" \ "The Faculty of Mathematics consists of the Department of Applied Mathematics & Theoretical Physics (DAMTP) and the Department of Pure Mathematics & Mathematical Statistics (DPMMS). The Statistical Laboratory is a sub-department of the DPMMS. Also located within the University of Cambridge is the Isaac Newton Institute for Mathematical Sciences." \ "http://www.maths.cam.ac.uk/" add_department $server_url "Computer Science" \ "The Computer Laboratory is the Computer Science department of the University of Cambridge. The University Computing Service has a separate set of web pages." \ "http://www.cl.cam.ac.uk/" add_department $server_url "Architecture" \ "Because of the great diversity of offerings in the College of Environmental Design and in the Department of Architecture in areas such as building environments, practice of design, design methods, structures and construction, history, social and cultural factors in design, and design itself, it is possible to obtain either a very broad and general foundation or to concentrate in one or several areas." \ "http://arch.ced.berkeley.edu/" add_department $server_url "Business Administration" \ "The department offers a range of courses in Business Administration, Finance, and Law" \ "http://mitsloan.mit.edu/" } ad_proc ::twt::dotlrn::add_subject { server_url department_pretty_name pretty_name description } { ::twt::do_request "/dotlrn/admin/class-new" form find ~n add_class field find ~n "form:id" # Department pretty names are not I18N so this will work in different locales field select "$department_pretty_name" field find ~n "pretty_name" field fill $pretty_name field find ~n "description" field fill $description form submit } ad_proc ::twt::dotlrn::setup_subjects { server_url } { # Mathematics Department add_subject $server_url "Mathematics" "Differential Geometry" " An introduction to differential geometry with applications to general relativity. Metrics, Lie bracket, connections, geodesics, tensors, intrinsic and extrinsic curvature are studied on abstractly defined manifolds using coordinate charts. Curves and surfaces in three dimensions are studied as important special cases. Gauss-Bonnet theorem for surfaces and selected introductory topics in special and general relativity are also studied. 18.100 is required, 18.101 is strongly recommended, and 18.901 would be helpful." # Computer Science department add_subject $server_url "Computer Science" "Peer to Peer Computing" "The term peer-to-peer (P2P) refers to a class of systems and applications that employ distributed resources to perform a critical function in a decentralized manner..." add_subject $server_url "Computer Science" "Advanced Topics in Programming Languages" "This course focuses on bioinformatics applications, high-performance computing, and the application of high-performance computing to bioinformatics applications." add_subject $server_url "Computer Science" "Computer and Network Security" "This class serves as an introduction to information systems security and covers security issues at an undergraduate level" # Architecture Department add_subject $server_url "Architecture" "Architecture and Culture" "Selected examples of architecture and interior design are used as case studies to illustrate the presence of ideas in built matter. A range of projects are analysed and discussed in terms of the conceptual qualities that underpin the physical manifestations of architecture and interior design." # Business Administration Department add_subject $server_url "Business Administration" "Economic Analysis for Business Decisions" " Introduces students to principles of microeconomic analysis used in managerial decision making. Topics include demand analysis, cost and production functions, the behavior of competitive and non-competitive markets, sources and uses of market power, and game theory and competitive strategy, with applications to various business and public policy decisions. Antitrust policy and other government regulations are also discussed. 15.010 restricted to first-year Sloan masters students. 15.011 primarily for non-Sloan School students." add_subject $server_url "Business Administration" "Organizational Psychology & Sociology" "Organizations are changing rapidly. To deal with these changes requires new skills and attitudes on the part of managers. The goal of the OPS course is to make you aware of this challenge and equip you to better meet it. In short, the purpose is to acquaint you with some of psychological and sociological phenomena that regularly occur in organizations - the less visible forces that influence employee and managerial behavior. The aim is to increase your understanding of these forces -- in yourself and in others -- so that as they become more visible, they become manageable (more or less) and hence subject to analysis and choice." add_subject $server_url "Business Administration" "Advanced Corporate Finance" "The primary objective of the advanced corporate finance course is to conduct an in-depth analysis of special topics of interest to corporate finance managers. Our attempt will be to obtain a detailed understanding of the motives and reasons that lead to certain corporate decisions specifically in relation to the following issues: Mergers and Acquisitions, Corporate Restructurings, Corporate Bankruptcy, Corporate Governance" } ad_proc ::twt::dotlrn::get_class_add_urls { server_url } { return [::twt::get_url_list "/dotlrn/admin/classes" "class-instance-new"] } ad_proc ::twt::dotlrn::setup_classes { server_url } { setup_classes_for_term $server_url "[::twt::dotlrn::current_term_pretty_name]" setup_classes_for_term $server_url "Spring 2004" } ad_proc ::twt::dotlrn::setup_classes_for_term { server_url term_name } { foreach link [get_class_add_urls $server_url] { ::twt::do_request $link form find ~n "add_class_instance" field find # Term pretty names are not I18N so this will work in different locales field select $term_name field find ~n pretty_name array set name_field [field current] set pretty_name $name_field(value) field fill "$pretty_name $term_name" form submit } } ad_proc ::twt::dotlrn::setup_communities { server_url } { add_community $server_url "Tennis Club" "Community for the university tennis club with tournaments and other events, also helps you find people to play with." "open" add_community $server_url "Business Alumni Class of 1997" "Alumni community for the Business Administration graduates from the class of 1997." "closed" add_community $server_url "Business Administration Program" "Community for all students following the Business Administration Program" "closed" add_community $server_url "Star Trek Fan Club" "Community for die-hard fans of Star Trek" "needs approval" } ad_proc ::twt::dotlrn::add_community { server_url name description policy } { ::twt::do_request "/dotlrn/admin/club-new" form find ~n add_club field find ~n pretty_name field fill $name field find ~n description field fill $description ::twt::multiple_select_value join_policy $policy form submit } ad_proc ::twt::dotlrn::get_user_admin_url { email } { Get the .LRN admin URL for a user. This is awkward. If we could lookup the user_id from email this would be much easier. } { ::twt::do_request "/dotlrn/admin/users-search?name=einstein&form%3Aid=user_search" link follow ~u {user\?user} return [response url] } ad_proc ::twt::dotlrn::add_site_wide_admin { server_url } { global __admin_last_name # Goto users page ::twt::do_request "/dotlrn/admin/users?type=pending" # Goto the community page for the site-wide admin (assuming he's first in the list) link follow ~u {^user\?user} # Follow the add to dotlrn link link follow ~u "user-new-2" # Use defaults (external with full access) form find ~a "user-new-2" form submit } ################### # # Namespace ::twt::dotlrn::test - no demo data setup, pure testing # ################### ad_proc ::twt::dotlrn::test::manage_my_memberships {} { Test that user can manage (join/drop) his own class and community memberships. } { # First request some ids from the OpenACS server set user_id [::twt::oacs::eval "ad_conn user_id"] set class_community_id [::twt::oacs::get_class_to_join $user_id] set club_join_community_id [::twt::oacs::get_club_to_join $user_id "open"] set club_request_community_id [::twt::oacs::get_club_to_join $user_id "needs approval"] # Visit the manage memberships page ::twt::do_request "/dotlrn/manage-memberships" # Join a class set link_pattern "register.*community_id=$class_community_id" link follow ~u $link_pattern # Assert class join link is gone if { [::twt::count_links $link_pattern] > 0 } { ::twt::log_alert "Class with community_id $class_community_id was joined but the join link still appears to be present" } # Join a club set link_pattern "register.*community_id=$club_join_community_id" link follow ~u $link_pattern # Assert join club link is gone if { [::twt::count_links $link_pattern] > 0 } { ::twt::log_alert "Club with community_id $club_join_community_id was joined but the join link still appears to be present" } # Request membership for a club set link_pattern "register.*community_id=$club_request_community_id" link follow ~u $link_pattern # Assert request membership link is gone if { [::twt::count_links $link_pattern] > 0 } { ::twt::log_alert "Requested membership for club with community_id $club_request_community_id but the request link still appears to be present" } # Drop a class set link_pattern deregister set deregister_count_before [::twt::count_links $link_pattern] link follow ~u $link_pattern set deregister_count_after [::twt::count_links $link_pattern] # Assert there is now one less class to deregister from ::twt::assert_equals \ "Should be one less class to dergister from after deregistering" \ $deregister_count_after \ [expr {$deregister_count_before - 1}] } openacs-5.7.0/etc/install/tcl/twt-procs.tcl0000644000175000017500000003070310551254367020457 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Basic utility procs. # # @author Peter Marklund namespace eval ::twt {} ad_proc ::twt::log_section { message } { set script_name [file tail [info script]] puts "" puts "##############################" puts "#" puts "# ${script_name}: $message" puts "#" puts "##############################" puts "" } ad_proc ::twt::log { message } { set script_name [file tail [info script]] puts "${script_name}: $message" } ad_proc ::twt::log_alert { message } { set script_name [file tail [info script]] puts "" puts "${script_name}: [::twt::config::alert_keyword] - $message" puts "" } ad_proc ::twt::assert { explanation expression } { if { !$expression } { ::twt::log_alert "Assertion \"$explanation\" failed" } } ad_proc ::twt::assert_equals { explanation actual_value expected_value } { if { $actual_value ne $expected_value } { ::twt::log_alert "Assertion \"$explanation\" failed: actual_value=\"$actual_value\", expected_value=\"$expected_value\"" } } ad_proc ::twt::do_request { page_url } { Takes a a url and invokes tclwebtest::do_request. Will retry the request a number of times if it fails because of a socket connect problem. } { # Qualify page_url if necessary if { [regexp {^/} $page_url] } { set page_url "[::twt::config::server_url]${page_url}" } set retry_count 0 set retry_max 10 set error_p 0 while { [catch {::tclwebtest::do_request $page_url} errmsg] } { set error_p 1 if { $retry_count < $retry_max } { switch -regexp -- $errmsg { {unreachable} - {refused} { ::twt::log "Failed to connect to server with error \"$errmsg\" - retrying" incr retry_count exec "sleep" "5" set error_p 0 continue } default { ::twt::log "Failed to connect to server with error \"$errmsg\" - giving up" break } } } else { break } } if { $error_p } { # Either some non-socket error, or a socket problem occuring with more than # $retry_max times. Propagate the error while retaining the stack trace global errorInfo error $errmsg $errorInfo } ::twt::acs_lang::check_no_keys } ad_proc ::twt::get_url_list { page_url link_url_pattern } { ::twt::do_request $page_url set urls_list [list] # Loop over and add all links set errno "0" while { $errno == "0" } { set errno [catch { array set link_array [link find -next ~u "$link_url_pattern"]} error] if {$errno eq "0"} { set url $link_array(url) lappend urls_list $url } } return $urls_list } ad_proc ::twt::get_random_items_from_list { list number } { Given a list and the lenght of the list to return, return a list with a random subset of items from the input list. } { # Build a list of indices set index_list [list] for { set i 0 } { $i < [llength $list] } { incr i } { lappend index_list $i } # If the list was empty - return if { [llength $index_list] == 0 } { return {} } # Cannot return more items than are in the list if { $number > [llength $list] } { error "get_random_items_from_list: cannot return $number items from list $list" } # Pick number random indices from the list. Remove each index that we have # already picked. set random_indices [list] for { set index_count 0 } { $index_count < $number } { incr index_count } { set random_index [randomRange [llength $index_list]] lappend random_indices [lindex $index_list $random_index] # Remove the index that we picked set index_list [lreplace $index_list $random_index $random_index] } # Build and return the items at the random indices set return_list [list] foreach index $random_indices { lappend return_list [lindex $list $index] } if { [llength $return_list] == 1 } { return [lindex $return_list 0] } else { return $return_list } } ad_proc ::twt::randomRange {range} { Given an integer N, return an integer between 0 and N. } { return [expr int([expr {rand()}] * $range)] } ad_proc ::twt::write_response_to_file { filename } { Write the HTML body of the last HTTP response to the file with given path. If the directory of the file doesn't exist then create it. } { # Create the directory of the output file if it doesn't exist if { ![file isdirectory [file dirname $filename]] } { exec mkdir -p [file dirname $filename] } set file_id [open "$filename" w+] puts $file_id "[response body]" } ad_proc ::twt::set_crawler_exclude_links { url_list } { A list of URLs that the crawler should not visit (for example URLs that would delete data that shouldn't be deleted). @author Peter Marklund } { global __crawler_exclude_links set __crawler_exclude_links $url_list } ad_proc ::twt::get_crawler_exclude_links {} { Get the list of URLs that the crawler should exclude. @see ::twt::set_crawler_exclude_links @author Peter Marklund } { global __crawler_exclude_links if { [info exists __crawler_exclude_links] } { return $__crawler_exclude_links } else { return {} } } ad_proc ::twt::exclude_crawl_link_p { url } { Return 1 if the given URL matches the patterns in the URL exclude list and 0 otherwise. } { foreach exclude_pattern [get_crawler_exclude_links] { if { [regexp [string trim $exclude_pattern] $url] } { return 1 } } return 0 } ad_proc ::twt::record_excluded_url { url } { Record that a URL was not crawled because it matched a pattern in the exclude list. } { global __crawler_excluded_links lappend __crawler_excluded_links $url } ad_proc ::twt::get_excluded_urls {} { global __crawler_excluded_links if { [info exists __crawler_excluded_links] } { return $__crawler_excluded_links } else { return {} } } ad_proc ::twt::crawl_links { {-max_requests 2000} {-previous_url ""} start_url } { Crawl links recursively under the given url. For example, if start_url is "/simulation" then a link with the URL "/simulation/object-display?object_id=125" would be visited whereas a link with a URL not under "/simulation", such as "/", would not. Never visit links with external URLs (outside the server). @param max_requests The maximum number of links that the proc will crawl @param start_url The url to start crawling from. The first time the proc is invoked the start_url needs to have a trailing slash if it is a directory. @author Peter Marklund } { if { $previous_url ne "" } { # For relative links to work, when we come back from the recursive crawling of a link, we need to make # Tclwebtest understand that we are now relative to a different URL than the one last requested, namely # relative to the URL of the page the link is on. #::twt::log "pm debug setting previous_url $previous_url" #::twt::log "pm debug set ::tclwebtest::url $previous_url" set ::tclwebtest::url $previous_url } # Return if given start URL is external set server_url [::twt::config::server_url] #::twt::log "pm debug about to generate absolute_url start_url=$start_url previous_url=$previous_url" set start_url_absolute [tclwebtest::absolute_link $start_url] #::twt::log "pm debug after generating absolute_url start_url_absolute=$start_url_absolute" if { [string first $server_url $start_url_absolute] == -1 } { #::twt::log "pm debug returning because link $start_url_absolute is external" return } # Also return if this is the logout link if { [regexp {/register/logout} $start_url match] } { #::twt::log "pm debug returning because link $start_url_absolute is logout" return } global __url_history # Return if maximum number of links is exceeded if { [llength $__url_history] > $max_requests } { ::twt::log "[::twt::config::alert_keyword] - maximum number of links exceeded, not following link to $start_url_absolute" return } # Before requesting, check if the URL matches the exclude list if { [::twt::exclude_crawl_link_p $start_url_absolute] } { # Keep a record of URLs not visited because the matched the exclude link ::twt::record_excluded_url $start_url_absolute return } lappend __url_history $start_url_absolute # Request the page #::twt::log "pm debug about to invoke \"do_request $start_url_absolute\" start_url=$start_url previous_url=$previous_url" # Note that we are re-initializing start_url_absolute here since a trailing slash will be added if the URL is a directory # and we need that to resolve relative URLs if { [catch {set foobar [::twt::do_request $start_url_absolute]} errmsg] } { if { "$previous_url" ne "" } { set previous_page_message " (link found on page $previous_url)" } else { set previous_page_message "" } ::twt::log "[::twt::config::alert_keyword] - requesting url $start_url_absolute failed${previous_page_message}. Response status is [response status] and error is $errmsg" return } else { #::twt::log "pm debug after do_request ::tclwebtest::url=$::tclwebtest::url start_url_absolute=$start_url_absolute foobar=$foobar" set start_url_absolute $::tclwebtest::url } # Get all links on the page if { [catch {set all_links [link all]} errmsg] } { #::twt::log "pm debug could not get links for url $start_url_absolute : $errmsg" return } # Loop over and recurse on each appropriate link foreach link_list $all_links { array set link $link_list set url $link(url) set absolute_url [tclwebtest::absolute_link $url] # Don't revisit URL:s we have already tested # Don't follow relative anchors on pages - can't get them to work with TclWebtest set new_url_p [expr {[lsearch -exact $__url_history $absolute_url] == -1}] if { [string range $url 0 0] == "#" } { set anchor_link_p 1 } else { set anchor_link_p 0 } #::twt::log "pm debug under_start_url_p - string first $start_url_absolute $absolute_url" set under_start_url_p [expr {[string first $start_url_absolute $absolute_url] != -1}] set visit_p [expr {$new_url_p && !$anchor_link_p && $under_start_url_p}] if { $visit_p } { crawl_links -previous_url $start_url_absolute $url } #::twt::log "pm debug looping with url $absolute_url visit_p=$visit_p new_url_p=$new_url_p under_start_url_p=$under_start_url_p anchor_link_p=$anchor_link_p" } } ad_proc ::twt::multiple_select_value { name value } { Selects the option with the given value in the current form widget (workaround since I can only get tclwebtest to select based on label). } { field find ~n $name array set current_field [field current] set field_choices $current_field(choices) set index 0 foreach field_choice $field_choices { if {$value eq [lindex $field_choice 0]} { break } incr index } ::tclwebtest::field_select -index $index } ad_proc ::twt::count_links { pattern } { set count 0 foreach link_list [link all] { array set link $link_list if { [regexp $pattern $link(url)] } { incr count } } return $count } # No longer needed as the problem was due to malformed HTML and is # better handled within tclwebtest # ad_proc ::twt::all_urls {} { # Returns all urls on the page last requested. # This proc is a workaround to the problem # with Tclwebtest not always finding all links with the [link all] # command. # @return A list of URLs of the last requested page # @author Peter Marklund # } { # set all_urls [list] # set remaining_body [response body] # while { [regexp -all {^(.*?)]+)(.*)$} $remaining_body match before_match link_url remaining_body] } { # lappend all_urls $link_url # } # return $all_urls # } openacs-5.7.0/etc/install/tcl/news-procs.tcl0000644000175000017500000000453307742124765020625 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs related to the news application. # # @author Peter Marklund namespace eval ::twt::news {} ad_proc ::twt::news::add_item_to_classes { server_url } { set news_item_list [get_items] set class_counter 0 foreach admin_url [::twt::class::get_admin_urls] { # We want the professor of the class to post the news item # TODO #set email [::twt::class::get_professor $admin_url] #user::login $email [::twt::user::get_password $email] # Admin page of the class ::twt::do_request $admin_url # News item add link follow ~u {news/+item-create} set news_item [lindex [::twt::get_random_items_from_list $news_item_list 1] 0] form find ~a preview set publish_title [lindex $news_item 0] set publish_body [lindex $news_item 1] field fill $publish_title ~n publish_title field fill $publish_body ~n publish_body field check ~n permanent_p form submit # confirm form find ~a {item-create-3} form submit incr class_counter } # Re-login the site-wide admin #login_site_wide_admin } ad_proc ::twt::news::get_items {} { set news_item_list [list] lappend news_item_list {{The exam is postponed by one week} {The final exam previously planned for the 20:th of December will be on the 3:d of January instead - the calendar has been updated}} lappend news_item_list {{Recommended Reading for friday workshop} {For the friday workshop reading up on chapter three of the course materials is strongly recommended. See you on friday!}} lappend news_item_list {{Class Assistants Needed} {We need more people to assist with the seminar on tuesday - let me know if you are interested!}} lappend news_item_list {{Changed Schedule} {We have decided to adjust the schedule slightly by moving section 6 and 8 of the of the text book to be treated in december.}} lappend news_item_list {{Deadline for assignment II on thursday} {We need to have the homework assignments handed in for review no later than this thursday}} lappend news_item_list {{Project Group Meeting} {We will hold an extra project group meeting on next wednesday to plan and discuss the various topics that have been suggested.}} return $news_item_list } openacs-5.7.0/etc/install/tcl/oacs-procs.tcl0000644000175000017500000000413207745756142020574 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs used to access the Tcl API on the OpenACS server. # # @author Peter Marklund namespace eval ::twt::oacs {} ad_proc ::twt::oacs::eval { tcl_command } { Execute an OpenACS Tcl API command and return the result. @param tcl_command A list where the first item is the the proc name and the remaining ones are proc arguments } { ::twt::do_request "/eval-command?[::http::formatQuery tcl_command $tcl_command]" return [response body] } ad_proc ::twt::oacs::user_id_from_email { email } { return [::twt::oacs::eval " db_string user_id_from_email { select party_id from parties where email = '$email' } "] } ad_proc ::twt::oacs::get_class_to_join { user_id } { Return community_id of a random class that the user can join. } { set community_ids [::twt::oacs::eval " db_list can_join_community_ids { select community_id from dotlrn_class_instances_full where dotlrn_class_instances_full.join_policy = 'open' and not exists (select 1 from dotlrn_member_rels_full where dotlrn_member_rels_full.user_id = '$user_id' and dotlrn_member_rels_full.community_id = dotlrn_class_instances_full.class_instance_id) } "] return [::twt::get_random_items_from_list $community_ids 1] } ad_proc ::twt::oacs::get_club_to_join { user_id join_policy } { Return community_id of a random club that the user can join. } { return [::twt::oacs::eval " db_list can_join_club_ids { select f.community_id from dotlrn_clubs_full f where f.join_policy = '$join_policy' and f.club_id not in (select dotlrn_member_rels_full.community_id as club_id from dotlrn_member_rels_full where dotlrn_member_rels_full.user_id = '$user_id') } "] return [::twt::get_random_items_from_list $community_ids 1] } openacs-5.7.0/etc/install/tcl/admin-procs.tcl0000644000175000017500000000562610551254367020737 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs related to OpenACS admin (APM, parameters, site map etc.) # A few of these procs are no longer so important now that we have # the install.xml files for mounting packages and setting parameter values. # # @author Peter Marklund namespace eval ::twt::admin {} ad_proc ::twt::admin::install_all_packages { server_url } { ::twt::do_request "$server_url/acs-admin/apm/packages-install?checked_by_default_p=1" #assert text "Package Installation" # If there are no new packages to install, just return if { [regexp -nocase {no new packages to install} [response body] match] } { return } form submit # Sometimes there are failed dependencies for certain packages # In this case we ignore those packages and continue if { [regexp {.*packages-install-2} "$::tclwebtest::url" match]} { form submit } #assert text "Select Data Model Scripts to Run" # Source SQL scripts (took 68s) form submit } ad_proc ::twt::admin::add_main_site_folder { server_url folder_name } { ::twt::do_request "$server_url/admin/site-map" link follow ~c "new sub folder" form find ~a new field find ~n name field fill "$folder_name" form submit } ad_proc ::twt::admin::mount_main_site_package { server_url folder_name instance_name package_key } { ::twt::do_request "$server_url/admin/site-map" # Follow the link to add a new application at the first matching folder name link find ~c $folder_name link follow ~c "new application" # Add the package instance form find ~a "package-new" field find ~n instance_name field fill "$instance_name" # package_key field select "$package_key" form submit } # FIXME: This proc is very vulnerable since the parameter-set form in # the site-map uses parameter_id to identify parameters # We should put a db-exec.tcl file on the server instead to be able to retrieve # the parameter_id of the parameter. ad_proc ::twt::admin::submit_acs_param_internal { old_parameter_value new_parameter_value } { form find ~a "parameter-set-2" field find ~v "$old_parameter_value" field fill "$new_parameter_value" form submit } ad_proc ::twt::admin::set_acs_subsite_param { server_url old_parameter_value parameter_value } { ::twt::do_request "$server_url/admin/site-map" link follow ~u {parameter-set\?package%5fid=[0-9]+&package%5fkey=acs%2dsubsite&instance%5fname=Main%20Site} submit_acs_param_internal $old_parameter_value $parameter_value } ad_proc ::twt::admin::set_acs_kernel_param { server_url param_section old_parameter_value parameter_value } { ::twt::do_request "$server_url/admin/site-map" link follow ~u {parameter-set\?package%5fid=[0-9]+&package%5fkey=acs%2dkernel} if { $param_section ne "acs-kernel" } { link follow ~c "$param_section" } submit_acs_param_internal $old_parameter_value $parameter_value } openacs-5.7.0/etc/install/tcl/user-procs.tcl0000644000175000017500000001123310551254367020614 0ustar frankiefrankie# Procs related to users to support testing of OpenACS and .LRN with # Tclwebtest. # # @author Peter Marklund namespace eval ::twt::user {} ad_proc ::twt::user::get_users { {type ""} } { Return a list of emails for .LRN users of a certain type. If type is not specified, returns all .LRN users. } { set user_emails [list] foreach user_data [get_test_data] { if { $type eq "" || \ [string equal -nocase [lindex $user_data 4] $type] } { lappend user_emails [lindex $user_data 2] } } return $user_emails } ad_proc ::twt::user::get_random_users { type number } { Get emails for a random set of .LRN users of a certain type. } { set email_list [get_users $type] return [::twt::get_random_items_from_list $email_list $number] } ad_proc ::twt::user::get_password { email } { if {$email eq [::twt::config::admin_email]} { return [::twt::config::admin_password] } else { global __demo_users_password return $__demo_users_password } } ad_proc ::twt::user::login { email } { ::twt::user::logout # Request the start page ::twt::do_request "[::twt::config::server_url]/register" # Login the user form find ~n login field find ~n email field fill "$email" field find ~n password field fill [get_password $email] form submit } ad_proc ::twt::user::logout {} { ::twt::do_request "[::twt::config::server_url]/register/logout" } ad_proc ::twt::user::login_site_wide_admin {} { ::twt::user::login [::twt::config::admin_email] } ad_proc ::twt::user::add { server_url first_names last_name email id type full_access guest } { ::twt::do_request "/dotlrn/admin/users" link follow ~u "user-add" form find ~a "/dotlrn/user-add" field find ~n "email" field fill $email field find ~n "first_names" field fill $first_names field find ~n "last_name" field fill $last_name field find ~n "password" field fill [get_password $email] field find ~n "password_confirm" field fill [get_password $email] form submit form find ~n add_user ::twt::multiple_select_value type $type ::twt::multiple_select_value can_browse_p $full_access ::twt::multiple_select_value guest_p $guest form submit } ad_proc ::twt::user::get_test_data {} { # Let's cache the data global __users_data if { [info exists __users_data] } { return $__users_data } global __dotlrn_users_data_file set file_id [open "$__dotlrn_users_data_file" r] set file_contents [read -nonewline $file_id] set file_lines_list [split $file_contents "\n"] set return_list [list] foreach line $file_lines_list { set fields_list [split $line ","] # Allow commenting of lines with hash if { ![regexp {\#.+} "[string trim [lindex $fields_list 0]]" match] } { # Get the first 6 items without leading/trailing space set trimmed_list [list] foreach item [lrange $fields_list 0 6] { lappend trimmed_list [string trim $item] } lappend return_list $trimmed_list } } set __users_data $return_list return $return_list } ad_proc ::twt::user::upload_users { server_url } { set users_data_list [get_test_data] foreach user_data $users_data_list { ::twt::user::add $server_url \ [lindex $user_data 0] \ [lindex $user_data 1] \ [lindex $user_data 2] \ [lindex $user_data 3] \ [lindex $user_data 4] \ [lindex $user_data 5] \ [lindex $user_data 6] } # We want the users to have a known password so people can log in with them set_passwords $server_url # Since Einstein will be posting in all classes # we make him site-wide-admin ::twt::user::make_site_wide_admin albert_einstein@dotlrn.test } ad_proc ::twt::user::set_passwords { server_url } { foreach user_email [get_users] { # User admin page ::twt::do_request "/dotlrn/admin/users" form find ~a "users-search" field fill $user_email ~n name form submit # User workspace link follow ~u {user\?} # change password link follow ~u {password-update\?} form find ~a password-update-2 field fill [get_password $user_email] ~n password_1 field fill [get_password $user_email] ~n password_2 form submit } } ad_proc ::twt::user::make_site_wide_admin { email } { ::twt::do_request [::twt::dotlrn::get_user_admin_url $email] # Do nothing if the user is already site-wide-admin catch {link follow ~u {site-wide-admin-toggle.*value=grant}} }openacs-5.7.0/etc/install/tcl/eval-command.tcl0000644000175000017500000000125607745756142021072 0ustar frankiefrankiead_page_contract { This is a page script to be put on a test server that enables us to execute arbitrary Tcl commands and retrieve the results. This is a temporary solution to allow us to access the OpenACS Tcl API for as long as Tclwebtest is not running inside OpenACS. @author Peter Marklund } { tcl_command } # Commenting out as this forces scripts to keep an admin login but we want to test with # student accounts as well #if { ![acs_user::site_wide_admin_p -user_id [ad_conn user_id]] } { # ad_return_forbidden "Permission Denied" "You don't have permission to access this page" #} set result [eval $tcl_command] ns_return 200 text/plain $result openacs-5.7.0/etc/install/tcl/acs-lang-procs.tcl0000644000175000017500000000276610551254367021336 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # Procs for testing the acs-lang (I18N) package # # @author Peter Marklund namespace eval ::twt::acs_lang {} ad_proc ::twt::acs_lang::load_i18n_messages { {-locales ""} } { Enables all locales, or a given list of locales, and loads all message catalogs for those locales. } { if { $locales eq "" } { set locales [::twt::oacs::eval {db_list all_locales {select locale from ad_locales}}] } # First enable all locales ::twt::oacs::eval " foreach locale {$locales} { lang::system::locale_set_enabled -locale \$locale -enabled_p t } " # Load all catalog files for enabled locales ::twt::oacs::eval lang::catalog::import } ad_proc ::twt::acs_lang::set_locale { locale } { Change locale of logged in user to locale. } { ::twt::log "Changing to locale $locale" ::twt::do_request /acs-lang form find locale ::twt::multiple_select_value site_wide_locale $locale form submit } ad_proc ::twt::acs_lang::check_no_keys { } { Check in the current request body for occurences of #package_key.message_key# which might be message keys that a developer forgot to let go through a lang::util::localize call to be converted into text. } { if { [regexp {#[a-zA-Z0-9_.-]+\.[a-zA-Z0-9_.-]+#} [response body] message_key] } { ::twt::log_alert "Found \"$message_key\" on page [response url] and might be a message key that needs a lang::util::localize call" } } openacs-5.7.0/etc/install/tcl/class-procs.tcl0000644000175000017500000001176410551254367020754 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # .LRN Class procs. # # @author Peter Marklund namespace eval ::twt::class {} namespace eval ::twt::class::test {} ad_proc ::twt::class::get_admin_urls { } { Returns a list with the fully qualified URLs of the admin pages of all .LRN classes. } { set term_id [::twt::dotlrn::current_term_id] set page_url [::twt::dotlrn::class_admin_url -term_id $term_id] set url_pattern {/dotlrn/classes/.*/one-community-admin$} return [::twt::get_url_list $page_url $url_pattern] } ad_proc ::twt::class::get_urls { } { Returns a list with the fully qualified URLs of the home pages of all .LRN classes. } { # The trick we use here is that we know that class urls are the admin # URLs minus "one-community-admin" set url_list [list] set admin_url_list [get_admin_urls] foreach admin_url $admin_url_list { regexp {^(.*)one-community-admin$} $admin_url match class_url lappend url_list $class_url } return $url_list } ad_proc ::twt::class::engineering_p { class_url } { return [regexp {dotlrn/classes/(computer-science|mathematics)} $class_url match] } ad_proc ::twt::class::follow_members_link {} { link follow ~u {members$} } ad_proc ::twt::class::get_professor { class_url } { # TODO: find the professor of the class class::follow_members_link # This is fragile... # TODO regexping on HTML code is too fragile # write special pages that export such data instead return [user::get_random_users professor 1] } ad_proc ::twt::class::setup_memberships { server_url } { foreach admin_url [get_admin_urls] { # Admin page for the class ::twt::do_request "$admin_url" # Member management for the class follow_members_link # Add all students add_members [::twt::user::get_users student] dotlrn_student_rel # Add a random professor add_member [::twt::user::get_random_users professor 1] dotlrn_instructor_rel # Add two staff in random roles (one of Teaching Assistant, Course Admin, or Course Assistant) set admin_users [::twt::user::get_random_users staff 2] set admin_rels [list dotlrn_ta_rel dotlrn_cadmin_rel dotlrn_ca_rel] set admin_counter 0 for { set admin_counter 0 } \ { [expr {$admin_counter < 2 && $admin_counter < [llength $admin_users]}] } \ { incr admin_counter } { set admin_rel [::twt::get_random_items_from_list $admin_rels 1] add_member [lindex $admin_users $admin_counter] $admin_rel } } } ad_proc ::twt::class::add_members { email_list rel_type } { foreach email $email_list { add_member $email $rel_type } } ad_proc ::twt::class::add_member { email rel_type } { if { $email eq "" } { return } # Search for the student to add form find ~a member-add field find ~n search_text field fill $email form submit # Pick the user (there should be only one) link follow ~u member-add-2 # pick relationship type to class (role) form find ~a "member-add-3" ::twt::multiple_select_value rel_type $rel_type form submit } ad_proc ::twt::class::setup_subgroups { server_url } { foreach admin_url [get_admin_urls] { foreach {name description policy} [subcommunity_properties_list] { # Admin page of one class ::twt::do_request $admin_url # Add subcommunity form link follow ~u subcommunity-new form find ~n add_subcomm field fill $name ~n pretty_name field fill $description ~n description ::twt::multiple_select_value join_policy $policy form submit } } } ad_proc ::twt::class::subcommunity_properties_list {} { set property_list [list] foreach letter {A B} { set pretty_name "Project Group $letter" lappend property_list $pretty_name lappend property_list "Workspace for people working in $pretty_name" # Other possible values: open, closed lappend property_list "needs approval" } return $property_list } ad_proc ::twt::class::add_member_applets { server_url } { foreach admin_url [get_admin_urls] { # Only add the members applet to computing classes so that we can # demo adding it to other classes manually if { [regexp -nocase {comput} $admin_url match] } { # Admin page of the class ::twt::do_request $admin_url # Manage Applets link follow ~u {applets$} # Add the Members Info applet link follow ~u {applet-add.*applet_key=dotlrn_members} } } } ################### # # Namespace ::twt::class::test - no demo data setup, pure testing # ################### ad_proc ::twt::class::test::manage_memberships {} { Test removing users and changing their roles in a class using the class_url/members page. @author Peter Marklund } { }openacs-5.7.0/etc/install/tcl/test-procs.tcl0000644000175000017500000000063407755165574020635 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # This is the master file - the only file that needs to be sourced. # It sets up global vars and sources all procs. # # @author Peter Marklund namespace eval ::twt {} # Source all *-procs.tcl files in this directory foreach path [glob [file dirname [info script]]/*-procs.tcl] { if { ![regexp {test-procs\.tcl$} $path] } { source $path } } openacs-5.7.0/etc/install/tcl/forums-procs.tcl0000644000175000017500000001047207742124765021163 0ustar frankiefrankie# Procs to support testing OpenACS with Tclwebtest. # # For testing forums package. # # @author Peter Marklund namespace eval ::twt::forums {} ad_proc ::twt::forums::add_default_forums { server_url } { Adds a general forum to each class. Goes via the class admin pages. } { foreach admin_url [::twt::class::get_admin_urls] { # Admin page of one class ::twt::do_request $admin_url # Add forum form link follow ~u forum-new form find ~n forum field fill "This is a general discussion forum where teachers, assistants, and students can come together to discuss the subject of the class or practical matters surrounding exams, assignments, project work etc." ~n charter form submit } } ad_proc ::twt::forums::add_postings {} { # Loop over all classes foreach class_url [::twt::class::get_urls] { # Class index page ::twt::do_request $class_url # Forum index page link follow ~u {forum-view?[^/]+$} # Post question array set question [get_question] link follow ~u {message-post?[^/]+$} field find ~n subject field fill $question(subject) field find ~n content field fill $question(content) form submit # Assuming here we are redirected to thread page - fragile... set thread_url [response url] # Post answer array set answer [get_answer] ::twt::user::login albert_einstein@dotlrn.test ::twt::do_request $thread_url link follow ~u {message-post?[^/]+$} field find ~n content field fill $answer(content) form submit ::twt::user::login_site_wide_admin } } ad_proc ::twt::forums::get_question {} { return { subject "What is the meaning of life?" content "Let's step back a moment... Why do you want to know the meaning of life? Often people ask this question when they really want the answer to some other question. Let's try and get those people back on track with some \"pre-meaning of life\" advice: * If you're questioning the meaning of life because you've been unhappy and depressed a good bit, click here. * On a related note, if you want to know the meaning of life because you feel useless and worthless, click here. * If you want to see our answer so that you can prove your intellectual prowess by poking holes in it, click here. * If something awful just happened to you or someone you care about and you don't understand why bad things happen to good people, click here. ... From http://www.aristotle.net/~diogenes/meaning1.htm Comments? " } } ad_proc ::twt::forums::get_answer {} { return { content " I was impressed by the earnestness of your struggle to find a purpose for the life of the individual and of mankind as a whole. In my opinion there can be no reasonable answer if the question is put this way. If we speak of the purpose and goal of an action we mean simply the question: which kind of desire should we fulfill by the action or its consequences or which undesired consequences should be prevented? We can, of course, also speak in a clear way of the goal of an action from the standpoint of a community to which the individual belongs. In such cases the goal of the action has also to do at least indirectly with fulfillment of desires of the individuals which constitute a society. If you ask for the purpose or goal of society as a whole or of an individual taken as a whole the question loses its meaning. This is, of course, even more so if you ask the purpose or meaning of nature in general. For in those cases it seems quite arbitrary if not unreasonable to assume somebody whose desires are connected with the happenings. Nevertheless we all feel that it is indeed very reasonable and important to ask ourselves how we should try to conduct our lives. The answer is, in my opinion: satisfaction of the desires and needs of all, as far as this can be achieved, and achievement of harmony and beauty in the human relationships. This presupposes a good deal of conscious thought and of self-education. It is undeniable that the enlightened Greeks and the old Oriental sages had achieved a higher level in this all-important field than what is alive in our schools and universities. " } } openacs-5.7.0/etc/install/updateserver.sh0000755000175000017500000000207410227014330020257 0ustar frankiefrankie#!/bin/bash # # Usage: updateserver.sh # # Update an OpenACS and .LRN source tree without checking out new packages # but still checking out new dirs in current packages and the www root dir. # Does the update as the anonymous user to avoid any password issues. # # by Peter Marklund server_root=$1 packages_root=${server_root}/packages root_dirs="www etc" cvs_args_with_dir="-f -q update -Pd" cvs_args_no_dir="-f -q update -P" oacs_cvs="cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot" # CVS update in root without new dirs echo "$0 - Updating in root dir $server_root" cd $server_root $oacs_cvs $cvs_args_no_dir # Update all packages with new dirs echo "$0 - Updating all packages" cd $packages_root for dir in $(find -maxdepth 1 -type d|grep -v CVS|egrep -v '^\.$') do cd $dir echo "$0 - Updating package $dir" $oacs_cvs $cvs_args_with_dir cd .. done # Update www root dir with new dirs for root_dir in $root_dirs do root_path="${server_root}/${root_dir}" echo "$0 - Updating dir $root_path" cd $root_path $oacs_cvs $cvs_args_with_dir done openacs-5.7.0/etc/install/TODO0000644000175000017500000000032007742210555015706 0ustar frankiefrankie- TclWebTest selects options in selects bases on label rather than value. I would like to be able to select based on value. - Grep for TODO in this dir and in the tcl dir to see TODO comments in the scripts. openacs-5.7.0/etc/install/functions.sh0000755000175000017500000000252010042702653017561 0ustar frankiefrankie# Access config parameters in the TCL file through this function get_config_param () { echo "source $config_file; puts -nonewline [set $1]" | tclsh } create_override_config_file () { server=$1 config_file=$2 override_config_file=/tmp/config-$server-$$.tcl # Only write the source_config_file if this hasn't already been done if [ ! -a $override_config_file ]; then echo "set server $server" > $override_config_file cat $config_file | egrep -v '^[[:space:]]*set[[:space:]]+server[[:space:]]+' >> $override_config_file export config_file=$override_config_file fi } # present an interactive continue prompt. # Quit the script if user chooses no. prompt_continue () { interactive=$1 if [ "$interactive" == "yes" ]; then echo "Continue? (y/n)" read continue if [ "$continue" == "n" ]; then echo "$0: exiting on users request" exit fi fi } # convert y, Y, t, and T to true and other values to false parameter_true () { case "$1" in [yY]*|[tT]*) true ;; *) false ;; esac } # peter_marklund/lars: ps|grep for pid of process using full path of executable grep_for_pid(){ echo `ps auwx | grep $1 | grep -v grep | awk '{print $2}'` } openacs-5.7.0/etc/install/install.tcl0000644000175000017500000003000010227014330017347 0ustar frankiefrankie# This is the configuration file for the install.sh script # for installing OpenACS services # ####################################################################### # # Things you will probably want to inspect and change # ####################################################################### #--------------------------------------------------------------------- # New Service Configuration # Values in this section will be written into the config.tcl of the # the new site if do_checkout=yes or do_checkout=up #--------------------------------------------------------------------- #--------------------------------------------------------------------- # the name of your service (site). # It will be used as the name of directories, the name of database # users and/or tablespaces, etc. set server "service0" #--------------------------------------------------------------------- # Server root directory. This is where all of the files for your server # will live. set serverroot "/var/lib/aolserver/${server}" #--------------------------------------------------------------------- # The host name (DNS) the server will be listening on set server_host yourserver.test #--------------------------------------------------------------------- # The IP address the server will be listening on set server_ip 127.0.0.1 #--------------------------------------------------------------------- # The port number the server will be listening on set server_port 8000 #--------------------------------------------------------------------- # The URL where your server will be accessible. # This is used by the installation scripts to complete the installation. # Don't forget to include the port number above set server_url "http://${server_ip}:${server_port}" #--------------------------------------------------------------------- # OS user and group that AOLserver runs as. We recommend that you # create a new user for your server. # If you do not want to do that, change the user name below set aolserver_user ${server} set aolserver_group "web" #--------------------------------------------------------------------- # End of settings for config.tcl #--------------------------------------------------------------------- #--------------------------------------------------------------------- # OpenACS configuration # These settings will be used when the install script walks the # installation setup web page set admin_email "admin@${server_host}" set admin_username "admin" set admin_first_names "Admin" set admin_last_name "User" set admin_password "1" set system_name "An OpenACS Development Server" set publisher_name "An OpenACS Developer" #--------------------------------------------------------------------- # Should we automatically grab the OpenACS code from CVS? # If this is yes, we will build a new server from CVS and also set up # daemontools directories if appropriate # If not, you must have already unpacked a tar-ball or done a cvs checkout # of acs-core or more (not just the checkout of /install you used to get # this file) in the server root# directory specified above. A third option # is to set this parameter to "up" in which case a full cvs update of the # tree will be done instead of the checkout. The cvs update will fully update # existing packages without checkout out new ones. set do_checkout "yes" #--------------------------------------------------------------------- # Which branch or symbolic tag should we use for the checkout. Use: # "HEAD" to get the latest code, # openacs-5-0-0-final to get version 5.0.0. # oacs-5-0 to get the 5.0 branch. set oacs_branch "HEAD" #--------------------------------------------------------------------- # Which additional packages should be checked out. # A space separated list of OpenACS packages to checkout in addition # to the OpenACS core packages (acs-core). # These packages must be modules as defined in the cvs repository # file :openacs.org:/cvsroot/CVSROOT/modules. set packages_list "" # example: cvs checkout of simulation and all pre-reqs # We don't use dotLRN, which is the obvious example, because it's still # a special case - see elsewhere in this doc. #set packages_list "bcms notifications simulation acs-mail-lite workflow file-storage" #--------------------------------------------------------------------- # Optional install.xml file # An absolute path to an install.xml file which controls the OpenACS # installation set install_xml_file "" # example: install simulation during server setup #set install_xml_file "${serverroot}/packages/simulation/install.xml" #--------------------------------------------------------------------- # Choose which database you will use - Say 'oracle' or 'postgres' set database "postgres" #---------------------------------------------------------------------- # Database configuration - PostgreSQL #---------------------------------------------------------------------- #--------------------------------------------------------------------- # Name of the postgres admin user set pg_db_admin postgres #--------------------------------------------------------------------- # Name of the postgres user for web service access set pg_db_user ${server} #--------------------------------------------------------------------- # Name of the PostgreSQL database. Will be created. set db_name ${server} #--------------------------------------------------------------------- # The host running PostgreSQL set pg_host localhost #--------------------------------------------------------------------- # The port PostgreSQL is running on. Default PostgreSQL port is 5432. set pg_port 5432 #--------------------------------------------------------------------- # The home directory of your PostgreSQL server. Type 'which psql' to find this. set pg_bindir "/usr/local/pgsql/bin" #---------------------------------------------------------------------- # Database configuration - Oracle #---------------------------------------------------------------------- # The name of the Oracle user and tablespace. Will get created. set db_name ${server} # Password for the Oracle user set oracle_password ${db_name} # The system user account and password. We need this to create the tablespace and user above. set system_user "system" set system_user_password "manager" #---------------------------------------------------------------------- # XML Report settings. #---------------------------------------------------------------------- # An XML report file will be generated by the installation scripts. Such # a file may be used by a master install server to report on the install # results of one or more other servers. # A text describing the purpose of the server. Must be XML quoted (for example may not contain any # <, or > signs). set server_description "" ####################################################################### # System settings # # The remaining settings should not change for different servers, but # might be different for different servers # ####################################################################### # Path to AOLserver config.tcl file to use. If you don't specify any file here, we will use the default config file. set aolserver_config_file "" # The path to the server's error log file, so we can look for errors during installation set error_log_file "${serverroot}/log/error.log" # TCLWebTest home directory set tclwebtest_dir "/usr/local/tclwebtest" # AOLserver's home directory set aolserver_home "/usr/local/aolserver" # The directory the xml report of the installation should be copied to with scp. Use # a local absolute path if you want a local copy. Leave empty if you don't want the xml # report copied anywhere. Example values: # /var/log/openacs-install # me@test.mycompany.com:/var/log/openacs-install set report_scp_target "/var/log/openacs-install" #---------------------------------------------------------------------- # Settings for starting and stopping the server #---------------------------------------------------------------------- # The default server control parameters use daemontools set use_daemontools "true" # Do 'which svc' to find where the svc binary is installed set svc_bindir "/usr/local/bin" # This is the directory which daemontools scans for services to supervies. # Normally it's /service, though there has been talk about moving it to /var/lib/svacan. # Do not use trailing slash. set svscanroot "/service/${server}" # This is the directory under your server's root dir which we should link to from the # svscanroot directory. set svscan_sourcedir "$serverroot/etc/daemontools" # alternate server startup commands # enable these commands to run without daemontools set start_server_command "exec /usr/local/aolserver/bin/nsd-postgres -it $serverroot/etc/config.tcl -u $aolserver_user -g $aolserver_group" set stop_server_command "killall nsd" set restart_server_command "${stop_server_command}; ${start_server_command}" # Number of loops and seconds per loop while waiting for the server to start # or restart set startup_seconds 10 set startup_loop_count 30 set restart_loop_count 50 # Number of loops and seconds per loop while waiting for the server to stop set shutdown_seconds 5 set shutdown_loop_count 10 #---------------------------------------------------------------------- # OpenACS configuration options #---------------------------------------------------------------------- # More OpenACS configuration options set system_owner_email "$admin_email" set admin_owner_email "$admin_email" set host_administrator_email "$admin_email" set outgoing_sender_email "$admin_email" set new_registrations_email "$admin_email" #---------------------------------------------------------------------- # Checking out code from CVS #---------------------------------------------------------------------- # To use for example for moving away (saving) certain files under serverroot (see README) set pre_checkout_script "" # To use for example for moving back certain (saved) files under serverroot (see README) set post_checkout_script "" #---------------------------------------------------------------------- # Install log and email alerting #---------------------------------------------------------------------- # The keyword output by the install script to indicate # that an email alert should be sent set alert_keyword "INSTALLATION ALERT" set send_alert_script "send-alert" set install_output_file "${serverroot}/log/install-output.html" # Where all errors in the log file during installation are collected set install_error_file "${serverroot}/log/install-log-errors" #---------------------------------------------------------------------- # Installing .LRN #---------------------------------------------------------------------- # dotLRN configuration # should we install dotlrn? set dotlrn "no" # Should basic demo setup of departments, classes, users, etc. be done? set dotlrn_demo_data "no" set dotlrn_users_data_file "users-data.csv" set demo_users_password "guest" #---------------------------------------------------------------------- # Tcl API testing. Not recommended for production servers. #---------------------------------------------------------------------- set do_tclapi_testing "no" #---------------------------------------------------------------------- # HTTP level testing and demo data setup with tclwebtest #---------------------------------------------------------------------- # A list of full paths for any additional tclwebtest scripts that should # be executed after install set tclwebtest_scripts "" # Should links be crawled to search for broken pages? If so, specify the path # to start from here. To crawl the whole site, set this parameter to "/". To # not do any crawling, leave empty. set crawl_links_start_path "" openacs-5.7.0/etc/install/build-release.sh0000644000175000017500000000353510005232275020267 0ustar frankiefrankie#!/bin/bash # if TAG=1 create the cvs tags otherwise assume they exist. TAG=1 # What release version are we building; version format should be # dashes rather than dots eg. OACS_VERSION=5-0-0b4 OACS_VERSION=5-0-0b4 DOTLRN_VERSION=2-0-0b4 OACS_BRANCH=oacs-5-0 DOTLRN_BRANCH=dotlrn-2-0 DOTLRN_CVSROOT=/dotlrn-cvsroot OACS_CVSROOT=/cvsroot # # Nothing below here should need to change... # BASE=/var/tmp/release-$OACS_VERSION mkdir $BASE if [ ! -d $BASE ]; then echo "Failed creating base dir $BASE" exit 1 fi cd $BASE if [ $TAG -eq 1 ]; then # Checkout and tag the release cvs -d $OACS_CVSROOT checkout -r $OACS_BRANCH openacs-4 cd openacs-4 cvs tag -F openacs-$OACS_VERSION cd ../ # Checkout and tag the dotlrn release mkdir dotlrn-packages cd dotlrn-packages cvs -d $DOTLRN_CVSROOT checkout -r $DOTLRN_BRANCH dotlrn-all for dir in *; do ( cd $dir && cvs tag -F dotlrn-$DOTLRN_VERSION ); done cd ../ # # Should check for .sql .xql .adp .tcl .html .xml executable files and squak if found. # fi # Generate tarballs... # # openacs # mkdir tarball cd tarball cvs -d $OACS_CVSROOT export -r openacs-$OACS_VERSION acs-core mv opeancs-4 openacs-${OACS_VERSION//-/.} tar -czf ../openacs-${OACS_VERSION//-/.}.tar.gz openacs-${OACS_VERSION//-/.} cd .. # dotlrn # mkdir dotlrn-tarball cd dotlrn-tarball cvs -d $OACS_CVSROOT export -r openacs-$OACS_VERSION acs-core cd openacs-4/packages cvs -d $OACS_CVSROOT export -r openacs-$OACS_VERSION dotlrn-prereq cvs -d $DOTLRN_CVSROOT export -r dotlrn-$DOTLRN_VERSION dotlrn-core cd ../.. cp -f openacs-4/packages/dotlrn/install.xml openacs-4 mv openacs-4 dotlrn-${DOTLRN_VERSION//-/.} tar -czf ../dotlrn-${DOTLRN_VERSION//-/.}.tar.gz dotlrn-${DOTLRN_VERSION//-/.} # Clean up after ourselves... cd $BASE && rm -rf dotlrn-tarball tarball openacs-4 dotlrn-packages openacs-5.7.0/etc/install/README0000644000175000017500000000565507751704444016123 0ustar frankiefrankieOpenACS and .LRN automated install and test scripts *** Prerequisites in brief tclwebtest aolserver oracle or postgresql For oracle a tablespace with same name as db user must exist user named service0 root access to server see /packages/acs-core-docs/www/index.html for more documentation about installing OpenACS and its prerequisites *** Quick Guide edit install.tcl su - ./install.sh By default, this will 1) stop any OpenACS service supervised at /var/lib/svscan/service0 2) drop the database service0 if it exists 3) create a CVS HEAD checkout of OpenACS at /var/lib/aolserver/service0 4) create the database service0 5) install OpenACS, including configuring the web-driven pages, to http://localhost:8000 The install.sh script can also be used to perform a full .LRN test data setup, or to only perform a cvs checkout, or only recreate the database. Invoke install.sh --help to see command line switches. *** Prerequisites in full 1) If you already have a server running that is to be recreated - move away and save any local changes (patches) that you have made to the source code. If the do_checkout parameter is set to true the whole source code tree of the server will be moved away to temporary storage and deleted on the next recreation. Any patches that you want to apply on recreation should be executed by a script specified in the config file (see below) as post_checkout_script. This script will be executed after checkout is completed. If you keep AOLserver config file and log files under the server root dir you might want to save them before the checkout with the pre_checkout_script (specify path in config file), otherwise any changes to the AOLServer config file will be lost as the whole server tree is moved away for a new checkout from CVS. 2) A tablespace must exist with the same name as the oracle user of the server. The oracle recreate script uses statements from http://www.pinds.com/acs-tips/oracle-statements. Make sure you are not connected to the database user that the server uses so that that user can be dropped (i.e. log out of any sqlplus or psql sessions you might have). 3) Use the config template install.tcl to create a server specific installation config file. Per default install.sh will use the file install.tcl in the same directory but you can specify any config file on the command line with the switch --config-file. 4) Make sure an AOLServer config file is prepared. You can use /etc/config.tcl as a template. 5) The server you are to create/recreate must be under supervise (i.e. ln -s /web/dotlrn-test /service/dotlrn-test). 6) Make sure you have root access since you must run install.sh as root. 7) Fetch a fresh checkout from CVS of TclWebTest (see http://tclwebtest.sourceforge.net) and specify the directory the tclwebtest executable resides in in your install.tcl file. *** FAQ Q: How do I copy files into the source tree after checkout, but before install? A: You can specify openacs-5.7.0/etc/install/openacs-install.test0000644000175000017500000000225307742125124021217 0ustar frankiefrankie# Source procedures source tcl/test-procs.tcl # Test Execution START # Request the root page ::twt::do_request $server_url # Check that database connection is there and configuration is ok assert ![regexp -nocase "At least one misconfiguration was discovered" "[response text]"] # Fill in administrator info field find ~f ~n email field fill "$admin_email" field find ~f ~n "first_names" field fill "$admin_first_names" field find ~f ~n last_name field fill "$admin_last_name" field find ~n password field fill "$admin_password" field find ~n password_confirmation field fill "$admin_password" # Fill in the system settings field find ~n system_url field fill "$server_url" field find ~n system_name field fill "$system_name" field find ~n publisher_name field fill "$publisher_name" field find ~n system_owner field fill "$system_owner_email" field find ~n admin_owner field fill "$admin_owner_email" field find ~n host_administrator field fill "$admin_owner_email" field find ~n outgoing_sender field fill "$outgoing_sender_email" field find ~n new_registrations field fill "$new_registrations_email" form submit ::twt::write_response_to_file $install_output_file # Test Execution END openacs-5.7.0/etc/install/check-errors-output.sh0000755000175000017500000000034607752203767021522 0ustar frankiefrankie#!/bin/sh file_name=$1 # FIXME: Ignore InterMedia errors for now egrep -i 'error' $file_name | egrep -i -v 'no error' | egrep -i -v 'ODCIINDEXCREATE|Intermedia' | egrep -i -v 'If not, please check your server error log' exit 0 openacs-5.7.0/etc/install/warn-if-installation-errors.sh0000755000175000017500000000102607751735010023133 0ustar frankiefrankie#!/bin/sh # # Relies on environment variables: # config_file # Make script dir current dir for convenience script_path=$(dirname $(which $0)) cd $script_path file_name=$1 source ./functions.sh alert_keyword=`get_config_param alert_keyword` installation_errors=`./check-errors-output.sh $file_name` if echo $installation_errors | grep -q -i '[a-z]' ; then echo "${alert_keyword}: There are potential installation errors. The file $file_name contains the following lines that suggest errors:" echo "$installation_errors" fi openacs-5.7.0/etc/install/config-replace.sh0000755000175000017500000000353607756373070020456 0ustar frankiefrankie#!/bin/sh # # There is some degree of duplication of parameters in the etc/install/install.tcl file # and the etc/config.tcl file. This script will take parameter values in install.tcl # and insert them in the config.tcl file so that the two are in sync. # # # The next line restarts using tclsh. Do not remove this backslash: \ exec tclsh "$0" "$@" set install_file_path [lindex $argv 0] source $install_file_path #---------------------------------------------------------------------- # Replace variables in config.tcl #---------------------------------------------------------------------- # Left side = install.tcl, right side = config.tcl array set __replace_with { server server serverroot serverroot httpport server_port hostname server_host address server_ip servername system_name homedir aolserver_home database database db_name db_name db_password oracle_password db_host pg_host db_port pg_port db_user pg_db_user } set __config_file_path "${serverroot}/etc/config.tcl" set __fd [open $__config_file_path] set __config_text [read $__fd] close $__fd set __output {} foreach __line [split $__config_text \n] { if { [regexp {^(\s*)set\s+([^\s]+)\s+} $__line match __whitespace __varname] } { if { [info exists __replace_with($__varname)] } { append __output $__whitespace [list set $__varname [set $__replace_with($__varname)]] \n continue } } append __output $__line \n } set __new_config_file_path "${__config_file_path}.new" set __fd [open $__new_config_file_path w] puts $__fd $__output close $__fd # Rename file delete "${__config_file_path}.bak" file rename $__config_file_path "${__config_file_path}.bak" file rename $__new_config_file_path $__config_file_path openacs-5.7.0/etc/install/install.sh0000755000175000017500000006057610207353611017235 0ustar frankiefrankie#!/bin/bash # # Read the README file before executing this script. # # This script recreates an OpenACS server from scratch by: # # - dropping and creating the database # - Re-checking out the source code from CVS (optional) # - Doing necessary installation and configuration of OpenACS and # .LRN over HTTP that is normally done manually in a browser. # # @author Peter Marklund (peter@collaboraid.biz) # @author Lars Pind (lars@collaboraid.biz) # @author Joel Aufrecht (joel@aufrecht.org) ###################################################################### # # Initial setup # ###################################################################### #--------------------------------------------------------------------- # Uncomment the following line to exit on any failure # However, we are not using this because we don't have a way # for postgres database user drop/add to work without failure # regardless of whether the user # already exists or not. # #set -e #--------------------------------------------------------------------- #--------------------------------------------------------------------- # Uncomment following line for debug mode #set -x #--------------------------------------------------------------------- #--------------------------------------------------------------------- # Set the script directory to the current dir for convenience export script_path=$(dirname $(which $0)) cd $script_path #--------------------------------------------------------------------- # If you don't say ./, it'll search for functions.sh in your path source ./functions.sh #--------------------------------------------------------------------- # TODO: create user if necessary # we should check for the existence of the specified user # if the user doesn't exist, # if the user was specified in the command line # TODO - Check if the user exists first # echo "$0: Creating the user $aolserver_user" # useradd -m -g $aolserver_group $aolserver_user -d /home/$server # fi # interactive prompt to create user or terminate script # fi # # Meanwhile, however, we're just going to assume that service user # is the same as servername and that the user exists. Documented # in README #--------------------------------------------------------------------- ###################################################################### # # Parse command-line arguments # ###################################################################### #--------------------------------------------------------------------- # Look for two-part command line arguments # Also, we need to look for command-line setting for config file # before we load the config file config_val_next=0 server_next=0 export config_file="$script_path/install.tcl" server_overridden="no" for arg in "$@" do if [ $config_val_next == "1" ]; then export config_file=$arg config_val_next=0 fi if [ $server_next == "1" ]; then # Overrides server setting in config file export server=$arg server_next=0 server_overridden="yes" fi if [ $arg == "--config-file" ]; then config_val_next=1 fi if [ $arg == "--server" ]; then server_next=1 fi done # Create a config file with overridden server name if it was # provided on the command line export orig_config_file=$config_file if parameter_true "$server_overridden"; then echo "$0: Overriding config server setting with $server" create_override_config_file $server $config_file fi usage="$0 [OPTIONS] --server Server name. Overrides config file. --config-file Sets up information about the server and database used (see install.tcl.in). Defaults to install.tcl --no-checkout Do not checkout new source code --oacs-only Do not install .LRN, only OpenACS --no-install Do not install .LRN or OpenACS. Useful if you only want to recreate the db user and then install manually --postgresql Install on PostgreSQL. Overrides database setting in install config file. --interactive Gives you the possibility to exit at certain points during installation " # Check that script is executed as root if [ $(whoami) != "root" ]; then echo "$(date): You must execute this script as root; exiting" exit -1 fi # Check that the config file exists if [ ! -r ${config_file} ]; then echo "$(date): Aborting installation. The config file \"$config_file\" does not exist or is not readable." exit -1 fi # Set overridable configuration parameters from config file do_checkout=`get_config_param do_checkout` dotlrn=`get_config_param dotlrn` database=`get_config_param database` interactive="no" do_install="yes" server=`get_config_param server` while [ -n "$1" ] ; do case "$1" in "--config-file") # We already got this value above so just shift and continue shift ;; "--server") # We already got this value above so just shift and continue shift ;; "--no-checkout") do_checkout="no" ;; "--oacs-only") dotlrn="no" ;; "--postgresql") database="postgres" ;; "--interactive") interactive="yes" ;; "--help"|"-h") echo "${usage}" exit 0 ;; "--no-install") do_install="no" ;; *) echo "$(date): option not recognized: ${i}" echo "${usage}" exit -1 ;; esac shift done #--------------------------------------------------------------------- # # set the rest of the config file parameters # #--------------------------------------------------------------------- # some of them may vary based on command-line overrides, so we # do them after checking the command line serverroot=`get_config_param serverroot` use_daemontools=`get_config_param use_daemontools` svc_bindir=`get_config_param svc_bindir` svscanroot=`get_config_param svscanroot` svscan_sourcedir=`get_config_param svscan_sourcedir` server_url=`get_config_param server_url` error_log_file=`get_config_param error_log_file` install_error_file=`get_config_param install_error_file` tclwebtest_dir=`get_config_param tclwebtest_dir` stop_server_command=`get_config_param stop_server_command` start_server_command=`get_config_param start_server_command` restart_server_command=`get_config_param restart_server_command` startup_seconds=`get_config_param startup_seconds` shutdown_seconds=`get_config_param shutdown_seconds` startup_loop_count=`get_config_param startup_loop_count` restart_loop_count=`get_config_param restart_loop_count` shutdown_loop_count=`get_config_param shutdown_loop_count` dotlrn_demo_data=`get_config_param dotlrn_demo_data` crawl_links_start_path=`get_config_param crawl_links_start_path` aolserver_user=`get_config_param aolserver_user` aolserver_group=`get_config_param aolserver_group` admin_email=`get_config_param admin_email` admin_password=`get_config_param admin_password` aolserver_config_file=`get_config_param aolserver_config_file` install_xml_file=`get_config_param install_xml_file` tclwebtest_scripts=`get_config_param tclwebtest_scripts` do_tclapi_testing=`get_config_param do_tclapi_testing` report_scp_target=`get_config_param report_scp_target` server_description=`get_config_param server_description` # If pre/post checkout scripts have been provided, check that they can # be executed pre_checkout_script=`get_config_param pre_checkout_script` post_checkout_script=`get_config_param post_checkout_script` if [ -n "$pre_checkout_script" ] && [ ! -x $pre_checkout_script ]; then echo "The pre checkout script $pre_checkout_script does not exist or is not executable" exit -1 fi if [ -n "$post_checkout_script" ] && [ ! -x $post_checkout_script ]; then echo "The post checkout script $post_checkout_script does not exist or is not executable" exit -1 fi # Log some important parameters for the installation echo "$(date): Starting installation with config_file $orig_config_file. Using serverroot=$serverroot, server_url=$server_url, do_checkout=$do_checkout, do_install=${do_install}, dotlrn=$dotlrn, and database=$database., use_daemontools=$use_daemontools" if parameter_true $use_daemontools; then echo "$(date): Daemontools settings: svscanroot=$svscanroot svscan_sourcedir=$svscan_sourcedir" fi # Give the user a chance to abort prompt_continue $interactive ###################################################################### # # stop the server # ###################################################################### echo "$(date): Taking down $serverroot" if parameter_true $use_daemontools; then echo "$(date): supervise status is: $($svc_bindir/svstat ${svscanroot})" command="$svc_bindir/svc -d ${svscanroot}" echo "$(date): Issuing command $command" $command echo "$(date): supervise status is: $($svc_bindir/svstat ${svscanroot})" else # non-daemontools stop echo "$(date): Issuing command $stop_server_command" $stop_server_command fi # Wait in a finite loop for the server to come down x=0 while test "$x" -lt $shutdown_loop_count ; do pid=`grep_for_pid "nsd.*${serverroot}/etc/config.tcl"` if [ "$pid" == "" ]; then echo "$(date): Server is down" break fi echo "$(date): Process IDs of running servers: $pid" echo "$(date): Waiting $shutdown_seconds seconds for server to shut down." sleep $shutdown_seconds x=`expr "$x" + 1` done # Verify that the server is down, and abort if not pid=$(grep_for_pid "nsd.*${serverroot}/etc/config.tcl") if ! [ "$pid" == "" ]; then echo "$(date): Cannot stop the server. You must shut down the server first." exit -1 fi ###################################################################### # # Recreate the database user and database # ###################################################################### echo "$(date): Recreating database user and database." if [ $database == "postgres" ]; then # Postgres pg_bindir=`get_config_param pg_bindir` pg_port=`get_config_param pg_port` pg_db_user=`get_config_param pg_db_user` db_name=`get_config_param db_name` su `get_config_param pg_db_admin` -c "export LD_LIBRARY_PATH=${pg_bindir}/../lib; ${pg_bindir}/dropuser -p $pg_port $pg_db_user" # dropdb may be redundant becasue dropping the user should drop the db, # but only if our assumption that db_user owns db_name is true su `get_config_param pg_db_admin` -c "export LD_LIBRARY_PATH=${pg_bindir}/../lib; ${pg_bindir}/dropdb -p $pg_port $db_name" su `get_config_param pg_db_admin` -c "export LD_LIBRARY_PATH=${pg_bindir}/../lib; ${pg_bindir}/createuser -d -a -p $pg_port $pg_db_user" su `get_config_param pg_db_admin` -c "export LD_LIBRARY_PATH=${pg_bindir}/../lib; ${pg_bindir}/createdb -E UNICODE -p $pg_port $db_name" # createlang was part of this command but is not necessary # (and causes an error) for newer installs # ${pg_bindir}/createlang -p $pg_port plpgsql $db_name"; else #Oracle # Need to su to login shell for sqlplus to be in path. Should maybe make ORA_HOME # a config param instead. su - oracle -c "cd ${script_path}/oracle; config_file=$config_file ./recreate-user.sh"; fi ###################################################################### # # Check out new files # # If we are doing checkout, checkout files and modify checked out files, # including /etc/config.tcl and /etc/daemontools/run # ###################################################################### if parameter_true $do_checkout || [ $do_checkout == "up" ] ; then # The pre_checkout script can move away any files or changes # to the source tree that we want to keep (for example an # edited AOLserver config file, see README) if [ -n "$pre_checkout_script" ]; then source $pre_checkout_script fi #----------------------------------------------------------------- # Remove supervise link if it exists if parameter_true $use_daemontools; then # Make sure any existing supervise directory is a symlink if [ -e $svscanroot ]; then if ! [ -L $svscanroot ]; then echo "You have a supervise directory $svscanroot which is not a symlink and we curently don't support that." exit -1 fi rm ${svscanroot} fi if [ -r "$svscan_sourcedir" ]; then $svc_bindir/svc -dx $svscan_sourcedir echo "$(date): supervise status is: $($svc_bindir/svstat ${svscanroot})" fi fi pid=`grep_for_pid "nsd.*$serverroot"` if ! [ "$pid" == "" ]; then echo "The server is still running. You must shut down the server first." echo "Process IDs of running servers: $pid" exit fi if [ $do_checkout == "up" ] ; then echo "$(date): Doing cvs update" chmod +x updateserver.sh ./updateserver.sh $serverroot else echo "$(date): Checking out OpenACS" chmod +x checkout.sh config_file=$config_file dotlrn=$dotlrn ./checkout.sh fi #----------------------------------------------------------------- # The post_checkout script can copy back any files (AOLServer config files, # log files etc.) under the new source tree, and apply any patches # that should be applied (see README). if [ -n "$post_checkout_script" ]; then source $post_checkout_script fi #----------------------------------------------------------------- # If we are using daemontools, set up the supervise directory if needed if parameter_true $use_daemontools && ! [ -e $svscanroot ]; then # Create a daemontools directory # prevent it from autostarting when linked if [ ! -d $svscan_sourcedir ]; then echo "$(date): ABORTING: Failed to create daemontools symlink $svscan_sourcedir" exit -1 fi echo "$(date): Linking $svscan_sourcedir from $svscanroot" touch $svscan_sourcedir/down ln -s $svscan_sourcedir $svscanroot # allow svscan to start echo "$(date): Waiting for 10 seconds for svscan to find the new link." sleep 10 echo "$(date): supervise status is: $($svc_bindir/svstat ${svscanroot})" echo "$(date): daemontools errors: : $(ps -auxw | grep readproctitle)" # Check if svgroup is present, and if so, use it if which svgroup &> /dev/null; then echo "$(date): Giving group $aolserver_group control over the server: svgroup web ${svscanroot}" svgroup $aolserver_group ${svscanroot} fi fi #----------------------------------------------------------------- # Modify the config file if [ -z "$aolserver_config_file" ]; then # No AOLserver config file specified - we are using the standard etc/config.tcl file. # We need to update it with settings in install.tcl since certain parameters # (such as serverroot) are duplicated between the two files. echo "$(date): Editing AOLserver config file with parameter settings in install.tcl" ./config-replace.sh $config_file chmod +x $svscan_sourcedir/run else # Copy specified config file to the right path echo "$(date): Copying custom AOLserver config file $aolserver_config_file" cp $aolserver_config_file $serverroot/etc/config.tcl fi #----------------------------------------------------------------- # Edit the run script echo "$(date): Editing run script at $svscan_sourcedir/run" ./run-create.sh $config_file chmod +x $svscan_sourcedir/run #----------------------------------------------------------------- # Make sure we always have sensible ownership and permissions in the whole source tree echo "$(date): Setting permissions and ownership for files under ${serverroot}" chown -R ${aolserver_user}.${aolserver_group} ${serverroot} chmod -R go+rwX ${serverroot} else echo "$(date): Proceeding without checkout. This assumes that you have a full working site already set up at ${serverroot}, including correctly configured ${serverroot}/etc/config.tcl and ${svscan_sourcedir}" fi # # Done with checkout # ###################################################################### # # Start the server # ###################################################################### echo "$(date): Bringing $serverroot back up" if parameter_true $use_daemontools; then echo "$(date): supervise status is: $($svc_bindir/svstat ${svscanroot})" if [ -f $svscanroot/down ]; then echo "$(date): removing down file" rm $svscanroot/down fi command="$svc_bindir/svc -u $svscanroot" echo "$(date): Issuing command $command" $command echo "$(date): supervise status is: $($svc_bindir/svstat ${svscanroot})" else # non-daemontools command echo "$(date): Issuing command $start_server_command" $start_server_command fi # Wait in a finite loop for the server to become responsive # but first wait just a few seconds, since this startup is usually very quick sleep 4 # prep for the test wget_test=${server_url}/SYSTEM/success if [ -f ${script_path}/success ]; then rm ${script_path}/success fi x=0 while test "$x" -lt $startup_loop_count ; do # check for static file echo "$(date): attempting: wget --tries=1 $wget_test" wget --tries=1 $wget_test if [ -r ${script_path}/success ] && [ $(cat ${script_path}/success) = "success" ]; then echo "$(date): Server is up" break fi echo "$(date): Waiting for $startup_seconds seconds for server to respond." sleep $startup_seconds x=`expr "$x" + 1` done if parameter_true $do_install; then # Save the time we started installation installation_start_time=$(date +%s) if [ $dotlrn == "yes" ]; then # Make sure the dotlrn/install.xml file is at the server root cp $serverroot/packages/dotlrn/install.xml $serverroot elif [ -n "$install_xml_file" ]; then # Copy specified install.xml file cp ${install_xml_file} $serverroot fi #------------------------------------------------------------------- # Install OpenACS echo "$(date): Starting installation of OpenACS." # TODO: this should be a parameter in install.tcl export TCLLIBPATH="$TCLLIBPATH /usr/local/tclwebtest" ${tclwebtest_dir}/tclwebtest -config_file $config_file openacs-install.test #------------------------------------------------------------------- # Restart the server echo "$(date): Restarting $serverroot" if parameter_true $use_daemontools; then echo "$(date): Daemontools should restart the server automatically" else echo "$(date): Issuing command $start_server_command" $start_server_command fi # Peter: it seems nsunix will trigger a restart of the server after we request # the SYSTEM/dbtest page, so give the server some extra time here to potentially restart # again before we proceed sleep 30 # we check for dbtest instead of success here because dbtest is a more thorough test # we would have used dbtest before but it doesn't work on postgresql before openacs # install wget_test=${server_url}/SYSTEM/dbtest if [ -f ${script_path}/dbtest ]; then rm ${script_path}/dbtest fi # Wait in a finite loop for the server to become responsive x=0 while test "$x" -lt $restart_loop_count ; do # check for database responsiveness wget_test=${server_url}/SYSTEM/dbtest echo "$(date): trying to retrieve $wget_test" wget --tries=1 $wget_test if [ -r ${script_path}/dbtest ] && [ $(cat ${script_path}/dbtest) = "success" ]; then echo "$(date): Server is up" break fi echo "$(date): Waiting for $startup_seconds seconds for server to respond." sleep $startup_seconds x=`expr "$x" + 1` done #------------------------------------------------------------------- # Do .LRN demo data setup if parameter_true "$dotlrn_demo_data"; then echo "$(date): Starting basic setup of .LRN." cp tcl/eval-command.tcl $serverroot/www/eval-command.tcl ${tclwebtest_dir}/tclwebtest -config_file $config_file dotlrn-basic-setup.test rm $serverroot/www/eval-command.tcl fi #--------------------------------------------------------------- # Search for broken pages if [ -n "$crawl_links_start_path" ]; then echo "$(date): Starting to crawl links to search for broken pages. Start path is $crawl_links_start_path" ${tclwebtest_dir}/tclwebtest -config_file $config_file crawl-links.test fi #------------------------------------------------------------------- # Run any additional tclwebtest scripts if [ -n "$tclwebtest_scripts" ]; then echo "$(date): Running additional tclwebtest scripts" for tclwebtest_script_path in $tclwebtest_scripts do echo "$(date): Running tclwebtest script $tclwebtest_script_path" ${tclwebtest_dir}/tclwebtest -config_file $config_file $tclwebtest_script_path done fi #------------------------------------------------------------------- # Check errors in the log file # We do this before the Tcl API tests as these tend to generate errors intentionally if [ -r ${error_log_file} ]; then seconds_since_installation_start=$(expr $(date +%s) - $installation_start_time) minutes_since_installation_start=$(expr $seconds_since_installation_start / 60 + 1) ./aolserver-errors.pl -${minutes_since_installation_start}m ${error_log_file} > ${install_error_file} error_line_count=$(wc -l $install_error_file | awk '{print $1}') if expr $error_line_count \> 1 &> /dev/null; then alert_keyword=`get_config_param alert_keyword` echo "$(date): ${alert_keyword} - There are error messages in the log file, they are stored in $install_error_file" fi else echo "$(date): Log file ${error_log_file} not readable - cannot check for errors" fi #------------------------------------------------------------------- # Run the Tcl API tests if parameter_true $do_tclapi_testing; then echo "$(date): Running tclwebtest tests" ${tclwebtest_dir}/tclwebtest -config_file $config_file tcl-api-test.test fi #------------------------------------------------------------------- # Vacuum analyze for PG if [ $database == "postgres" ]; then pg_bindir=`get_config_param pg_bindir` db_name=`get_config_param db_name` echo "$(date): Beginning 'vacuum analyze'." su `get_config_param pg_db_user` -c "export LD_LIBRARY_PATH=${pg_bindir}/../lib; ${pg_bindir}/vacuumdb -p $pg_port -z $db_name" fi #------------------------------------------------------------------- # Warn about errors in the HTML returned from the server ./warn-if-installation-errors.sh `get_config_param install_output_file` ###################################################################### # # Generate an XML report # ###################################################################### xmlreportfile=$script_path/$HOSTNAME-$server-installreport.xml echo "" > $xmlreportfile echo " $server_description" >> $xmlreportfile echo " $(uname -a)" >> $xmlreportfile echo " $database" >> $xmlreportfile if [ $database == "postgres" ]; then # Postgres echo " $(${pg_bindir}/psql --version)" >> $xmlreportfile fi #TODO: Oracle version number echo " $(/usr/local/aolserver/bin/nsd -V)" >> $xmlreportfile echo " $server_url" >> $xmlreportfile echo " $HOSTNAME" >> $xmlreportfile echo " $(get_config_param oacs_branch)" >> $xmlreportfile echo " $(get_config_param system_name)" >> $xmlreportfile echo " $admin_email" >> $xmlreportfile echo " $admin_password" >> $xmlreportfile echo " $installation_start_time" >> $xmlreportfile echo " $(date +%s)" >> $xmlreportfile echo " $(date)" >> $xmlreportfile echo " $script_path" >> $xmlreportfile echo "" >> $xmlreportfile # Report the time at which we were done echo "$(date): Finished (re)installing $serverroot. ###################################################################### New site URL: $server_url admin email : $admin_email admin password: $admin_password ######################################################################" if [ -n "$report_scp_target" ]; then echo "$(date): Copying xml report to $report_scp_target" scp $xmlreportfile $report_scp_target fi fi openacs-5.7.0/etc/install/checkout.sh0000644000175000017500000000524510227014330017353 0ustar frankiefrankie#!/bin/bash # # Read the README file before executing this script. # # Checks out all source code needed for .LRN and OpenACS from CVS and copies # the supervise run script that runs AOLServer to the server root directory. # # This script should be executed as root and requires the following # environment variables to be set: # # config_file - where variables such as the serverroot are kept # dotlrn - (yes or no) Indicates if dotlrn should be checked out # # @author Peter Marklund (peter@collaboraid.biz) set -e #set -x export CVS_RSH=ssh export script_path=$(dirname $(which $0)) cd $script_path # Sometimes script path will be the dot so I need this workaround export script_path=$(pwd) source ./functions.sh # Fetch config parameters # NOTE: fetching parameters further down in the script will not work # if the config_file=./install.tcl since we are cd:ing to a different dir # below serverroot=`get_config_param serverroot` aolserver_user=`get_config_param aolserver_user` aolserver_group=`get_config_param aolserver_group` packages_list=`get_config_param packages_list` oacs_branch=`get_config_param oacs_branch` echo "$0: Starting checkout for server path $serverroot with config_file $config_file and dotlrn=$dotlrn" # Move away the old sources if they exist if [ -d ${serverroot} ]; then # Remove old tmp storage of sources server_name=$(basename ${serverroot}) old_sources_path="/var/tmp/${server_name}" if [ -d ${old_sources_path} ]; then echo "$0: removing old server sources at ${old_sources_path}" rm -rf ${old_sources_path} fi echo "$0: Moving sources at ${serverroot} to ${old_sources_path}" mv ${serverroot} ${old_sources_path} fi # Checkout OpenACS core mkdir -p ${serverroot}-tmp cd ${serverroot}-tmp if [ "$oacs_branch" == "HEAD" ]; then oacs_branch_switch="" else oacs_branch_switch="-r $oacs_branch" fi echo "$0: Checking out acs-core from branch \"$oacs_branch\"" cvs -q -d :pserver:anonymous:@cvs.openacs.org:/cvsroot login cvs -q -z3 -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout $oacs_branch_switch acs-core mv ${serverroot}-tmp/openacs-4 ${serverroot} rmdir ${serverroot}-tmp cd ${serverroot}/packages if [ -n "$packages_list" ]; then # Checkout additional packages (modules) for package in $packages_list do cvs -q -z3 -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout $oacs_branch_switch $package done fi if [ $dotlrn == "yes" ]; then # Checkout needed packages echo "$0: Checking out packages from branch $oacs_branch" cvs -q -z3 -d :pserver:anonymous@cvs.openacs.org:/cvsroot co $oacs_branch_switch dotlrn-all fi echo $(date) > ${serverroot}/www/SYSTEM/checkout-date # Set proper privileges openacs-5.7.0/etc/install/ref-timezones-rules.sql0000644000175000017500000000332607725666616021705 0ustar frankiefrankie-- packages/ref-timezones/sql//common/ref-timezones-rules.sql -- -- This file is generated automatically based on the Unix timezone -- database. It defines each time range during which a particular -- local-to-UTC conversion rule is in effect. The rules specification -- is of the form: -- -- where -- -- tz is the Unix timezone name -- abbrev is an abbreviation for the conversion rule, -- isdist is the Daylight Savings Time flag -- gmt_offset is the difference between local time and UTC in seconds -- utc_[start,end] are the UTC times during which the rule applies -- local_[start,end] are the local times during which this rule applies. -- -- Note that local times are discontinuous because of DST transitions. -- -- Rules in general run until 2038. -- -- @author Jon Griffin (jon@jongriffin.com) -- -- @created 2000-12-04 -- -- $Id: ref-timezones-rules.sql,v 1.1 2003/09/04 16:51:26 joela Exp $ insert into timezone_rules values (1,'GMT',rdbms_date('Dec 14 1901 08:45:52'),rdbms_date('Jan 01 1912 12:16:07'),rdbms_date('Dec 14 1901 08:29:44'),rdbms_date('Dec 31 1911 11:59:59'),-968,'f'); insert into timezone_rules values (1,'GMT',rdbms_date('Jan 01 1912 12:16:08'),rdbms_date('Jan 18 2038 03:14:07'),rdbms_date('Jan 01 1912 12:16:08'),rdbms_date('Jan 18 2038 03:14:07'),0,'f'); insert into timezone_rules values (2,'GMT',rdbms_date('Dec 14 1901 08:45:52'),rdbms_date('Jan 01 1918 12:00:51'),rdbms_date('Dec 14 1901 08:45:00'),rdbms_date('Dec 31 1917 11:59:59'),-52,'f'); insert into timezone_rules values (2,'GMT',rdbms_date('Jan 01 1918 12:00:52'),rdbms_date('Aug 31 1936 11:59:59'),rdbms_date('Jan 01 1918 12:00:52'),rdbms_date('Aug 31 1936 11:59:59'),0,'f'); openacs-5.7.0/etc/install/run-create.sh0000755000175000017500000000163007756701774017644 0ustar frankiefrankie#!/bin/sh # # Edit (recreate) the run script to reflect the parameter values in install.tcl # # The next line restarts using tclsh. Do not remove this backslash: \ exec tclsh "$0" "$@" set install_file_path [lindex $argv 0] source $install_file_path #---------------------------------------------------------------------- # Create daemontools run file #---------------------------------------------------------------------- set __run_file_path "${serverroot}/etc/daemontools/run" set __new_run_file_path "${serverroot}/etc/daemontools/run.new" set __fd [open $__new_run_file_path w] puts $__fd "#!/bin/sh" puts $__fd "" puts $__fd "exec ${aolserver_home}/bin/nsd-${database} -it ${serverroot}/etc/config.tcl -u ${aolserver_user} -g ${aolserver_group}" close $__fd # Rename file delete "${__run_file_path}.bak" file rename $__run_file_path "${__run_file_path}.bak" file rename $__new_run_file_path $__run_file_path openacs-5.7.0/etc/install/tcl-api-test.test0000644000175000017500000000130207756716622020441 0ustar frankiefrankieif { [catch { # Source procedures source tcl/test-procs.tcl # Test Execution START ::twt::log_section "Login the site wide admin" ::twt::user::login_site_wide_admin # Run all tests ::twt::do_request "/test/admin/rerun?package_key=&category=&view_by=package&quiet=0" # Grep for packages with failed tests if { [regexp {FAILED} [response body]] } { ::twt::log "$alert_keyword - There are failed tests at $server_url" } # Test Execution END } result] } { global errorInfo ::twt::log $result ::twt::log "*** Tcl TRACE ***" ::twt::log $errorInfo ::twt::log "The response body is: [response body]" error "Test failed: $result" } openacs-5.7.0/etc/install/users-data.csv0000644000175000017500000000143607725666616020032 0ustar frankiefrankieAlbert,Smidth,albert_smidth@dotlrn.test,,student,1,f John,White,john_white@dotlrn.test,,student,1,f Samuel, Williamson, samuel_williamson@dotlrn.test,,student,1,f Tracy, Hill, tracy_hill@dotlrn.test,,student,1,f Katharina, Cohen, katharina_cohen@dotlrn.test,,student,1,f Mikael, Hansson, mikael_hansson@dotlrn.test,,student,1,f Andreas, Svensson, andreas_svensson@dotlrn.test,,student,1,f Amanda,Edmonds,amanda_edmonds@dotlrn.test,,professor,1,f John,Cameron,john_cameron@dotlrn.test,,professor,1,f Albert,Einstein,albert_einstein@dotlrn.test,,admin,1,f Marie,Curie,marie_curie@dotlrn.test,,admin,1,f Niels,Bohr,niels_bohr@dotlrn.test,,admin,1,f Bertrand,Russel,bertrand_russel@dotlrn.test,,admin,1,f Isaac,Newton,isaac_newton@dotlrn.test,,admin,1,f Adam,Nowak,adam_nowak@dotlrn.test,,external,0,t openacs-5.7.0/etc/install/post-checkout-script.sh0000644000175000017500000000003007725666616021660 0ustar frankiefrankie#!/bin/sh # placeholderopenacs-5.7.0/etc/install/install-and-alert.sh0000755000175000017500000000354307751735010021100 0ustar frankiefrankie#!/bin/sh # # This script runs the install.sh script and sends # an email alert if there are installation errors. The # script is intended to be run by cron. # # Must be executed as root set -x # Make script dir current dir for convenience script_path=$(dirname $(which $0)) cd $script_path source ./functions.sh # Get a proper environment set up if [ -f ~/.bashrc ]; then source ~/.bashrc fi # Look for two-part command line arguments # Also, we need to look for command-line setting for config file # before we load the config file config_val_next=0 server_next=0 export config_file="install.tcl" server_overridden="no" for arg in "$@" do if [ $config_val_next == "1" ]; then export config_file=$arg config_val_next=0 fi if [ $server_next == "1" ]; then # Overrides server setting in config file export server=$arg server_next=0 server_overridden="yes" fi if [ $arg == "--config-file" ]; then config_val_next=1 fi if [ $arg == "--server" ]; then server_next=1 fi done # Create a config file with overridden server name if it was # provided on the command line if parameter_true "$server_overridden"; then echo "$0: Overriding config server setting with $server" create_override_config_file $server $config_file fi alert_keyword=`get_config_param alert_keyword` send_alert_script=`get_config_param send_alert_script` export server=`get_config_param server` output_dir="server-output/${server}" if [ ! -d ${output_dir} ]; then mkdir -p $output_dir fi installation_output_file="${output_dir}/installation-output" ./install.sh $@ &> $installation_output_file # Get lines with alert keywords or lines with failed TclWebtest tests error_lines=$(egrep -i "(FAILED: .+\.test)|($alert_keyword)" $installation_output_file) if [ -n "$error_lines" ]; then $send_alert_script "$error_lines" > /dev/null fi openacs-5.7.0/etc/install/oracle/0000755000175000017500000000000011724401450016457 5ustar frankiefrankieopenacs-5.7.0/etc/install/oracle/recreate-user.sh0000755000175000017500000000143010227014330021554 0ustar frankiefrankie#!/bin/bash # Assumes the environment variable config_file to be set # The drop and create scripts are assumed to be in the same directory as this script script_path=$(dirname $(which $0)) source $script_path/../functions.sh system_user=`get_config_param system_user` system_user_password=`get_config_param system_user_password` oracle_user=`get_config_param db_name` oracle_password=`get_config_param oracle_password` cat ${script_path}/user-drop.sql | perl -pi -e "s/:oracle_user/$oracle_user/g" | \ sqlplus $system_user/$system_user_password cat ${script_path}/user-create.sql | perl -pi -e "s/:oracle_user/$oracle_user/g" | \ perl -pi -e "s/:oracle_password/$oracle_password/g" | \ sqlplus $system_user/$system_user_password openacs-5.7.0/etc/install/oracle/user-drop.sql0000644000175000017500000000003707726114366021136 0ustar frankiefrankiedrop user :oracle_user cascade;openacs-5.7.0/etc/install/oracle/user-create.sql0000644000175000017500000000051007726114366021431 0ustar frankiefrankiecreate user :oracle_user identified by :oracle_password default tablespace :oracle_user temporary tablespace temp quota unlimited on :oracle_user; grant connect, resource, ctxapp, javasyspriv, query rewrite to :oracle_user; revoke unlimited tablespace from :oracle_user; alter user :oracle_user quota unlimited on :oracle_user; openacs-5.7.0/etc/install/aolserver-errors.pl0000755000175000017500000001254207725666616021121 0ustar frankiefrankie#!/usr/bin/perl -i # aolserver-errors.pl # # prints out the errors from an AOLserver error log # # dvr@arsdigita.com, 11/27/99 # # USAGE: # # aolserver-errors -b # # print all errors found in the last of # the error log. # # aolserver-errors -m # # print all errors logged in the last # minutes # # # If called with no options, it will default to # # aolserver-errors -200000b # # ############################################################# # # Modification History: # # 1/1/2000 -- Removed reliance on the POSIX module and got the # parameter working correctly. # # 1/15/2000 -- replaced all calls to 'tail` with seek() calls # to improve portability. This also allows us to compile this script # with perlcc to create a single binary that should work under # a chroot'ed server. # # 2/01/2000 -- fixed a bug that caused trouble the first of every # month. (Now the problem happens only on the first of each year) # # 5/12/2000 -- mbryzek@arsdigita.com # Added exit at end of script to kill the thread $num_args = scalar @ARGV; # the number of bytes to read from the end of the file when # we're trying to find all errors in the last N minutes. $bite_size = 200000; # The default size for the -b parameter $default_num_bytes = 200000; %month_num = ('Jan', '00', 'Feb', '01', 'Mar', '02', 'Apr', '03', 'May', '04', 'Jun', '05', 'Jul', '06', 'Aug', '07', 'Sep', '08', 'Oct', '09', 'Nov', '10', 'Dec', '11'); foreach $arg_num (0 .. ($num_args - 2)) { $arg = $ARGV[$arg_num]; if ($arg =~ /\-([0-9]+)([A-Za-z])/) { ($number, $type) = ($1, lc($2)); if ($type eq 'b') { $num_bytes = $number; } elsif ($type eq 'm') { $num_minutes = $number; } else { die "Bad option: $arg\n"; } } else { die "Bad option: $arg\n"; } } $log_file = $ARGV[-1]; open LOG, "< $log_file"; if ($num_minutes) { $start_time = sprintf "%02d%02d%02d%02d", (localtime(time - (60*$num_minutes)))[4,3,2,1]; seek LOG, -$bite_size, 2; while (1) { while () { if (/^\[([0-9]+)\/([A-Za-z]+)\/([0-9]+):([0-9]+):([0-9]+)/) { my($day, $month_name, $year, $hour, $minute) = ($1, $2, $3, $4, $5); $log_time = $month_num{$month_name} . $day . $hour . $minute; if ($log_time lt $start_time) { # We've gone too far back. Advance until we find # an error that's on or past $start_time $last_position = tell LOG; while () { if (/^\[([0-9]+)\/([A-Za-z]+)\/([0-9]+):([0-9]+):([0-9]+)/) { my($day, $month_name, $year, $hour, $minute) = ($1, $2, $3, $4, $5); $log_time = $month_num{$month_name} . $day . $hour . $minute; if ($start_time le $log_time) { $starting_point = $last_position; last; } } $last_position = tell LOG; } # Either we've found the line we want or have reached # the end of the file. If it's the second case, we # need to set the starting point to the end of the file. $starting_point = $last_position unless $starting_point; } # We only need to get one time stamp last; } } last if defined $starting_point; seek LOG, -$bite_size, 1; $position = tell LOG; if ($position < $bite_size) { # then we need to read the entire file $starting_point = 0; last; } } } if (defined $starting_point) { seek LOG, $starting_point, 0; } else { $num_bytes = $default_num_bytes unless $num_bytes; seek LOG, -$num_bytes, 2; } $in_error = 0; $in_following_notice = 0; while () { if (/^\[(.*?)\]\[(.*?)\][^ ]? (.*)/) { ($time, undef, $message) = ($1, $2, $3); unless ($first_log_time) { ($first_log_time) = ($time =~ /^([^ ]+)/); print "Errors since $first_log_time\n"; } if ($message =~ /^Error/) { print "\n[$time]\n $message\n"; $in_error = 1; $in_following_notice = 0; } elsif ($message =~ /^Notice/) { if ($in_error == 1) { $in_following_notice = 1; } else { $in_following_notice = 0; } $in_error = 0; print " $message\n" if $in_following_notice; } else { $in_error = 0; $in_following_notice = 0; } } else { print " $_" if ($in_error or $in_following_notice); } } close LOG; exit(0); openacs-5.7.0/etc/install/ref-timezones-data.sql0000644000175000017500000000047307725666616021464 0ustar frankiefrankie-- packages/ref-timezones/sql/oracle/ref-timezone-data.sql -- -- Part of the timezone reference data -- -- @cvs-id $Id: ref-timezones-data.sql,v 1.1 2003/09/04 16:51:26 joela Exp $ insert into timezones values (1,'Africa/Abidjan','+000000'); insert into timezones values (2,'Africa/Accra','+000000'); openacs-5.7.0/etc/install/dotlrn-basic-setup.test0000644000175000017500000000451107747750336021657 0ustar frankiefrankieif { [catch { source tcl/test-procs.tcl # Test Execution START ::twt::log_section "Login the site wide admin" ::twt::user::login_site_wide_admin ::twt::log_section "Add the site wide admin to dotLRN" ::twt::dotlrn::add_site_wide_admin $server_url ::twt::log_section "Load I18N Messages and enter German locale" ::twt::acs_lang::load_i18n_messages ::twt::acs_lang::set_locale de_DE ::twt::log_section "Upload users" ::twt::user::upload_users $server_url ::twt::log_section "Set up terms" ::twt::dotlrn::setup_terms $server_url ::twt::log_section "Set up departments" ::twt::dotlrn::setup_departments $server_url ::twt::log_section "Set up subjects" ::twt::dotlrn::setup_subjects $server_url ::twt::log_section "Set up classes" ::twt::dotlrn::setup_classes $server_url ::twt::log_section "Set up communities (i.e. Tennis Club etc.)" ::twt::dotlrn::setup_communities $server_url ::twt::log_section "Add class members, i.e. professors, students and assistants" ::twt::class::setup_memberships $server_url ::twt::log_section "Add class subgroups" ::twt::class::setup_subgroups $server_url ::twt::log_section "Add class member applet" ::twt::class::add_member_applets $server_url ::twt::log_section "Set up class forums - one per class" ::twt::forums::add_default_forums $server_url ::twt::log_section "Add forum postings" ::twt::forums::add_postings ::twt::log_section "Add news items - one per class" ::twt::news::add_item_to_classes $server_url set student_email [::twt::user::get_random_users student 1] ::twt::log_section "Login as student $student_email" ::twt::user::login $student_email ::twt::log_section "Test customize layout page" ::twt::new_portal::test::customize_layout ::twt::log_section "Test the manage memberships page" ::twt::dotlrn::test::manage_my_memberships #::twt::user::login_site_wide_admin # Test Execution END } result] } { global errorInfo # Output error stack trace and HTML response body ::twt::log $result ::twt::log "*** Tcl TRACE ***" ::twt::log $errorInfo ::twt::log "The response body is: [response body]" error "Test failed: $result" } openacs-5.7.0/etc/install/crawl-links.test0000644000175000017500000000157207761153351020360 0ustar frankiefrankieif { [catch { # Source procedures source tcl/test-procs.tcl ::twt::log_section "Login the site wide admin" ::twt::user::login_site_wide_admin set exclude_list {delete remove /acs-admin/install} ::twt::set_crawler_exclude_links $exclude_list ::twt::log_section "crawling links starting from \"$crawl_links_start_path\"" ::twt::crawl_links $crawl_links_start_path if { [llength [::twt::get_excluded_urls]] > 0 } { ::twt::log "Did not visit the following URLs because of exclude list: [join [::twt::get_excluded_urls] "\n"]" } else { ::twt::log "No URLs matched the exclude list ([join $exclude_list ", "])" } } result] } { global errorInfo ::twt::log $result ::twt::log "*** Tcl TRACE ***" ::twt::log $errorInfo ::twt::log "The response body is: [response body]" error "Test failed: $result" } openacs-5.7.0/etc/daemontools/0000755000175000017500000000000011724401450016070 5ustar frankiefrankieopenacs-5.7.0/etc/daemontools/run0000755000175000017500000000100310742626374016631 0ustar frankiefrankie#!/bin/sh # aolserver4 recommends descriptors limit (FD_SETSIZE) to be set to 1024, # which is standard for most OS distributions # For freebsd systems, uncomment following line: # ulimit -n 1024 # give time for Postgres to come up # see http://openacs.org/forums/message-view?message_id=176100 sleep 4 exec /usr/lib/aolserver4/bin/nsd -it /var/www/service0/etc/config.tcl -u service0 -g web # For AOLserver 4 using privileged ports (usually < 1024), add the flag # -b youraddress:yourport to the nsd command openacs-5.7.0/log/0000755000175000017500000000000011724401450013552 5ustar frankiefrankieopenacs-5.7.0/log/log.txt0000644000175000017500000000001407726050750015101 0ustar frankiefrankieplaceholder openacs-5.7.0/tcl/0000755000175000017500000000000011724401446013560 5ustar frankiefrankieopenacs-5.7.0/tcl/zz-postload.tcl0000644000175000017500000000357510211652247016561 0ustar frankiefrankie# $Id: zz-postload.tcl,v 1.5 2005/03/03 18:17:11 jeffd Exp $ # Name: 00-ad-postload.tcl # Author: Jon Salz # Date: 24 Feb 2000 # Description: Sources library files that need to be loaded after the rest. set tcllib [ns_info tcllib] ns_log "Notice" "Sourcing files for postload..." foreach file [glob -nocomplain ${tcllib}/*.tcl.postload] { ns_log Notice "postloading $file" source "$file" } ns_log "Notice" "Done." # This should probably be moved to the end of bootstrap.tcl once all files are # weeded out of the tcl directory. ns_log "Notice" "Executing initialization code blocks..." foreach init_item [nsv_get ad_after_server_initialization .] { array set init $init_item ns_log "Notice" "Executing initialization code block $init(name) in $init(script)" if { [llength $init(args)] == 1 } { set init(args) [lindex $init(args) 0] } if { [catch $init(args) error] } { global errorInfo ns_log "Error" "Error executing initialization code block $init(name) in $init(script): $errorInfo" } } # We need to load query files for the top-level stuff in www and tcl # dirs is the list of directories to walk for xql files. Packages .xql # files are parsed elsewhere in the bootstrap process. set dirs {www tcl} # The __is_xql helper function is used to filter out just the xql files. # # It should return true for directories it should descend as well # If you had a large static tree with no .xql files you could return 0 on # the subdirectory and it would not be searched. proc __is_xql {arg} { return [expr {[file isdir $arg] || [string match -nocase {*.xql} $arg]}] } foreach dir $dirs { set files [ad_find_all_files -check_file_func __is_xql [acs_root_dir]/$dir] ns_log Debug "QD=Postload files to load: $files" foreach file $files { db_qd_load_query_file $file } } nsv_unset ad_after_server_initialization . openacs-5.7.0/tcl/0-acs-init.tcl0000644000175000017500000000306310551254406016131 0ustar frankiefrankie# /tcl/0-acs-init.tcl # # The very first file invoked when OpenACS is started up. Sources # /packages/acs-tcl/bootstrap/bootstrap.tcl. # # jsalz@mit.edu, 12 May 2000 # # $Id: 0-acs-init.tcl,v 1.6 2007/01/10 21:22:14 gustafn Exp $ # Determine the OpenACS root directory, which is the directory right above the # Tcl library directory [ns_info tcllib]. set root_directory [file dirname [string trimright [ns_info tcllib] "/"]] nsv_set acs_properties root_directory $root_directory ns_log "Notice" "Loading OpenACS, rooted at $root_directory" set bootstrap_file "$root_directory/packages/acs-bootstrap-installer/bootstrap.tcl" ns_log "Notice" "Sourcing $bootstrap_file" if { [file isfile $bootstrap_file] } { # Check that the appropriate version of tDom (http://www.tdom.org) is installed # and spit out a comment or try to install it if not. if {{} eq [info commands domNode]} { if {[ns_info version] < 4} { ns_log Error "0-acs-init.tcl: domNode command not found -- libtdom.so not loaded?" } elseif {[ns_info version] >= 4} { if {[catch {set version [package require tdom]} errmsg]} { ns_log Error "0-acs-init.tcl: error loading tdom: $errmsg" } else { foreach {major minor point} [split $version .] { break } if {$major == 0 && ( $minor < 7 || ($minor == 7 && $point < 8))} { ns_log Error "0-acs-init.tcl: please use tdom version 0.7.8 or greater (you have version $version)" } } } } source $bootstrap_file } else { ns_log "Error" "$bootstrap_file does not exist. Aborting the OpenACS load process." } openacs-5.7.0/www/0000755000175000017500000000000011575226031013621 5ustar frankiefrankieopenacs-5.7.0/www/SYSTEM/0000755000175000017500000000000011575226031014645 5ustar frankiefrankieopenacs-5.7.0/www/SYSTEM/flush-memoized-statement.tcl0000644000175000017500000000105107537470343022312 0ustar frankiefrankiead_page_contract { Performs util_memoize_flush_local on the statement parameter. @author Jon Salz [jsalz@mit.edu] @creation-date 29 Feb 2000 @cvs-id $Id: flush-memoized-statement.tcl,v 1.2 2002/09/10 22:23:31 jeffd Exp $ } { statement } if { ![server_cluster_authorized_p [ns_conn peeraddr]] } { ns_returnforbidden return } util_memoize_flush_local [ns_queryget statement] if { [server_cluster_logging_p] } { ns_log "Notice" "Distributed flush of [ns_queryget statement]" } doc_return 200 "text/plain" "Successful." openacs-5.7.0/www/SYSTEM/security-debug.tcl0000644000175000017500000000411610024337404020301 0ustar frankiefrankie# NOTE: # Comment out below two lines to use this page # ns_return 200 text/html "Forbidden" return sec_login_handler set session_id {} catch { set session_id [ad_get_signed_cookie_with_expr "ad_session_id"] } session_id set ad_user_login {} catch { set ad_user_login [ad_get_signed_cookie "ad_user_login"] } ad_user_login set ad_user_login_secure {} catch { set ad_user_login_secure [ad_get_signed_cookie "ad_user_login_secure"] } ad_user_login_secure set ad_secure_token {} catch { set ad_secure_token [ad_get_signed_cookie "ad_secure_token"] } ad_secure_token set auth_expires_in "N/A" catch { set login_list [split [ad_get_signed_cookie "ad_user_login"] ","] set login_expr [lindex $login_list 1] set auth_expires_in [expr [sec_login_timeout] - ([ns_time] - $login_expr)] } set page "

Debug Page For Security Cookies

Cookies

Cookie nameValueExplanation
session_id$session_idsession_id, user_id, login_level expiration
ad_user_login$ad_user_loginuser_id, issue_time, auth_token
ad_user_login_secure$ad_user_login_secure...
ad_secure_token$ad_secure_token...

Cookie HTTP header:

"

foreach elm [split [ns_set iget [ad_conn headers] Cookie] ";"] {
    append page [string trim $elm] ";" \n
}

append page "

ad_conn

user_id: [ad_conn user_id]

untrusted_user_id: [ad_conn untrusted_user_id]

auth_level: [ad_conn auth_level]

account_status: [ad_conn account_status]

Authentication

Authentication expires in: $auth_expires_in

LoginTimeout: [sec_login_timeout]

[ad_decode [ad_conn untrusted_user_id] 0 "" "

auth_token: [sec_get_user_auth_token [ad_conn untrusted_user_id]]

"]

Change auth token

" ns_return 200 text/html $page openacs-5.7.0/www/SYSTEM/change-auth-token.tcl0000644000175000017500000000041110017410325020636 0ustar frankiefrankie# This page changes the current user's auth token, thus causing the user's authentication to become expired # This can be useful for testing/troubleshooting expiring logins. sec_change_user_auth_token [ad_conn untrusted_user_id] ad_returnredirect security-debug openacs-5.7.0/www/SYSTEM/dbtest-other.tcl0000644000175000017500000000117507253523117017764 0ustar frankiefrankiead_page_contract { This is called by server monitoring scripts, such as keepalive (see http://arsdigita.com/free-tools/keepalive.html) if it doesn't return "success" then they are supposed to kill the AOLserver. You can also use this with our Uptime monitoring system, described in Chapter 15 of http://photo.net/wtr/thebook/ This tests total db connectivity. @cvs-id $Id: dbtest-other.tcl,v 1.1.1.1 2001/03/13 22:59:27 ben Exp $ } { } if { ![db_0or1row date_check { select sysdate from dual }] } { doc_return 500 text/plain "failed" } else { ns_return 200 text/plain "success" } openacs-5.7.0/www/SYSTEM/success.tcl0000644000175000017500000000004307756665073017041 0ustar frankiefrankiens_return 200 text/plain "success" openacs-5.7.0/www/SYSTEM/success.txt0000644000175000017500000000001007756663131017061 0ustar frankiefrankiesuccess openacs-5.7.0/www/SYSTEM/dbtest.tcl0000644000175000017500000000143511300621405016627 0ustar frankiefrankiead_page_contract { This is called by server monitoring scripts, such as keepalive (see http://arsdigita.com/free-tools/keepalive.html) if it doesn't return "success" then they are supposed to kill the AOLserver. You can also use this with our Uptime monitoring system, described in Chapter 15 of http://photo.net/wtr/thebook/ This tests total db connectivity of all 3 database pools. @cvs-id $Id: dbtest.tcl,v 1.2 2009/11/17 22:26:13 ryang Exp $ } { } if { [catch { db_foreach check_pool1 "select sysdate from dual" { db_foreach check_pool2 "select sysdate from dual" { db_1row check_pool3 "select sysdate from dual" } } } errmsg] } { doc_return 500 text/plain "failed" } else { ns_return 200 text/plain "success" } openacs-5.7.0/www/blank-master.adp0000644000175000017500000000513511022567615016676 0ustar frankiefrankie@doc.type;noquote@ lang="@doc.lang;noquote@"> lang="@doc.title_lang;noquote@">@doc.title;noquote@ http-equiv="@meta.http_equiv;noquote@" name="@meta.name;noquote@" scheme="@meta.scheme;noquote@" lang="@meta.lang;noquote@" content="@meta.content@"> lang="@link.lang;noquote@" title="@link.title;noquote@" type="@link.type;noquote@" media="@link.media@"> These two variables have to be set before the XinhaCore.js is loaded. To enforce the order, it is put here. @head;noquote@ class="@body.class;noquote@" id="@body.id;noquote@"@event_handlers;noquote@> @header;noquote@ @footer;noquote@ openacs-5.7.0/www/blank-master.tcl0000644000175000017500000002153511456662501016717 0ustar frankiefrankiead_page_contract { This is the top level master template. It allows the basic parts of an XHTML document to be set through convenient data structures without introducing anything site specific. You should NEVER need to modify this file. Most of the time your pages or master templates should not directly set this file in their tag. They should instead use site-master with provides a set of standard OpenACS content. Only pages which need to return raw HTML should use this template directly. When using this template directly you MUST supply the following variables: @property doc(title) The document title, ie. tag. @property doc(title_lang) The language of the document title, if different from the document language. The document output can be customised by supplying the following variables: @property doc(type) The declared xml DOCTYPE. @property doc(charset) The document character set. @property body(id) The id attribute of the body tag. @property body(class) The class of the body tag. ad_conn -set language Must be used to override the document language if necessary. To add a CSS or Javascripts to the <head> section of the document you can call the corresponding template::head::add_* functions within your page. @see template::head::add_css @see template::head::add_javascript More generally, meta, link and script tags can be added to the <head> section of the document by calling their template::head::add_* function within your page. @see template::head::add_meta @see template::head::add_link @see template::head::add_script Javascript event handlers, such as onload, an be added to the <body> tag by calling template::add_body_handler within your page. @see template::add_body_handler Finally, for more advanced functionality see the documentation for template::add_body_script, template::add_header and template::add_footer. @see template::add_body_script @see template::add_header @see template::add_footer @author Kevin Scaldeferri (kevin@arsdigita.com) Lee Denison (lee@xarg.co.uk) @creation-date 14 Sept 2000 $Id: blank-master.tcl,v 1.52 2010/10/17 21:06:09 donb Exp $ } if {[template::util::is_nil doc(type)]} { set doc(type) {<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">} } # # Add standard meta tags # template::head::add_meta \ -name generator \ -lang en \ -content "OpenACS version [ad_acs_version]" # Add standard javascript # template::head::add_javascript -src "/resources/acs-subsite/core.js" # The following (forms, list and xinha) should # be done in acs-templating. # # Add css for the current subsite, defaulting to the old list/form css which was # hard-wired in previous versions of OpenACS. set css [parameter::get -package_id [ad_conn subsite_id] -parameter ThemeCSS -default ""] if { $css ne "" } { # DRB: Need to handle two cases, the lame first attempt and the more complete current # attempt which allows you to specify all of the parameters to template::head::add_css # (sigh, remove this kludge for 5.5.1). We need to handle the old case so upgrades # to 5.5 for mgh and various of my sites work correctly. foreach css $css { if { [llength $css] == 2 && [llength [lindex $css 0]] == 1 } { template::head::add_css -href [lindex $css 0] -media [lindex $css 1] } else { set params [list] foreach param $css { lappend params -[lindex $param 0] [lindex $param 1] } eval [concat template::head::add_css $params] } } } else { template::head::add_css \ -href "/resources/acs-templating/lists.css" \ -media "all" template::head::add_css \ -href "/resources/acs-templating/forms.css" \ -media "all" } # # Temporary (?) fix to get xinha working # if {[info exists ::acs_blank_master(xinha)]} { set ::xinha_dir /resources/acs-templating/xinha-nightly/ set ::xinha_lang [lang::conn::language] # # Xinha localization covers 33 languages, removing # the following restriction should be fine. # #if {$::xinha_lang ne "en" && $::xinha_lang ne "de"} { # set ::xinha_lang en #} # We could add site wide Xinha configurations (.js code) into xinha_params set xinha_params "" # Per call configuration set xinha_plugins $::acs_blank_master(xinha.plugins) set xinha_options $::acs_blank_master(xinha.options) # HTML ids of the textareas used for Xinha set htmlarea_ids '[join $::acs_blank_master__htmlareas "','"]' template::head::add_script -type text/javascript -script " xinha_editors = null; xinha_init = null; xinha_config = null; xinha_plugins = null; xinha_init = xinha_init ? xinha_init : function() { xinha_plugins = xinha_plugins ? xinha_plugins : \[$xinha_plugins\]; // THIS BIT OF JAVASCRIPT LOADS THE PLUGINS, NO TOUCHING if(!Xinha.loadPlugins(xinha_plugins, xinha_init)) return; xinha_editors = xinha_editors ? xinha_editors :\[ $htmlarea_ids \]; xinha_config = xinha_config ? xinha_config() : new Xinha.Config(); $xinha_params $xinha_options xinha_editors = Xinha.makeEditors(xinha_editors, xinha_config, xinha_plugins); Xinha.startEditors(xinha_editors); } //window.onload = xinha_init; " template::add_body_handler -event onload -script "xinha_init();" template::head::add_javascript -src ${::xinha_dir}XinhaCore.js } if { [info exists ::acs_blank_master(tinymce)] } { # we are using TinyMCE template::head::add_javascript -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/tiny_mce_src.js" -order tinymce0 # get the textareas where we apply tinymce set tinymce_elements [list] foreach htmlarea_id [lsort -unique $::acs_blank_master__htmlareas] { lappend tinymce_elements $htmlarea_id } set tinymce_config $::acs_blank_master(tinymce.config) # Figure out the language to use # 1st is the user language, if not available then the system one, # fallback to english which is provided by default set tinymce_relpath "packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce" set lang_list [list [lang::user::language] [lang::system::language]] set tinymce_lang "en" foreach elm $lang_list { if { [file exists [acs_root_dir]/${tinymce_relpath}/langs/${elm}.js] } { set tinymce_lang $elm break } } # TODO : each element should have it's own init template::head::add_javascript -script " tinyMCE.init(\{language: \"$tinymce_lang\", $tinymce_config\}); " -order tinymceZ } if {![info exists doc(title)]} { set doc(title) "[ad_conn instance_name]" ns_log warning "[ad_conn url] has no doc(title) set." } # AG: Markup in <title> tags doesn't render well. set doc(title) [ns_striphtml $doc(title)] if {[template::util::is_nil doc(charset)]} { set doc(charset) [ns_config ns/parameters OutputCharset [ad_conn charset]] } template::head::add_meta \ -content "text/html; charset=$doc(charset)" \ -http_equiv "content-type" # The document language is always set from [ad_conn lang] which by default # returns the language setting for the current user. This is probably # not a bad guess, but the rest of OpenACS must override this setting when # appropriate and set the lang attribxute of tags which differ from the language # of the page. Otherwise we are lying to the browser. set doc(lang) [ad_conn language] # Determine if we should be displaying the translation UI # if {[lang::util::translator_mode_p]} { template::add_footer -src "/packages/acs-lang/lib/messages-to-translate" } # Determine if developer support is installed and enabled # set developer_support_p [expr { [llength [info procs ::ds_show_p]] == 1 && [ds_show_p] }] if {$developer_support_p} { template::head::add_css \ -href "/resources/acs-developer-support/acs-developer-support.css" \ -media "all" template::add_header -src "/packages/acs-developer-support/lib/toolbar" template::add_footer -src "/packages/acs-developer-support/lib/footer" } if {[info exists focus] && $focus ne ""} { # Handle elements where the name contains a dot if { [regexp {^([^.]*)\.(.*)$} $focus match form_name element_name] } { template::add_body_handler \ -event onload \ -script "acs_Focus('${form_name}', '${element_name}');" \ -identifier "focus" } } # Retrieve headers and footers set header [template::get_header_html] set footer [template::get_footer_html] template::head::prepare_multirows set event_handlers [template::get_body_event_handlers] �������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/blank-compat.adp������������������������������������������������������������������0000644�0001750�0001750�00000003370�10721035644�016662� 0����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<master src="/www/blank-master"> <if @meta:rowcount@ not nil><property name="&meta">meta</property></if> <if @link:rowcount@ not nil><property name="&link">link</property></if> <if @script:rowcount@ not nil><property name="&script">script</property></if> <if @doc@ defined><property name="&doc">doc</property></if> <if @body@ defined><property name="&body">body</property></if> <if @head@ not nil><property name="head">@head;noquote@</property></if> <if @acs_blank_master.rte@ not nil and @acs_blank_master__htmlareas@ not nil> <script type="text/javascript"> <!-- initRTE("/resources/acs-templating/rte/images/", "/resources/acs-templating/rte/", "/resources/acs-templating/rte/rte.css"); // --> </script> </if> <if @acs_blank_master.xinha@ not nil and @acs_blank_master__htmlareas@ not nil> <script type="text/javascript"> <!-- xinha_editors = null; xinha_init = null; xinha_config = null; xinha_plugins = null; xinha_init = xinha_init ? xinha_init : function() { xinha_plugins = xinha_plugins ? xinha_plugins : [@xinha_plugins;noquote@]; // THIS BIT OF JAVASCRIPT LOADS THE PLUGINS, NO TOUCHING :) if(!HTMLArea.loadPlugins(xinha_plugins, xinha_init)) return; xinha_editors = xinha_editors ? xinha_editors : [ @htmlarea_ids@ ]; xinha_config = xinha_config ? xinha_config() : new HTMLArea.Config(); @xinha_params;noquote@ @xinha_options;noquote@ xinha_editors = HTMLArea.makeEditors(xinha_editors, xinha_config, xinha_plugins); HTMLArea.startEditors(xinha_editors); } window.onload = xinha_init; // --> </script> </if> <if @acs_blank_master__htmlareas@ not nil><textarea id="holdtext" style="display: none;" rows="1" cols="1"></textarea></if> <slave /> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/blank-compat.tcl������������������������������������������������������������������0000644�0001750�0001750�00000007275�10725063452�016712� 0����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ad_page_contract { Accepts and translates deprecated master template variables. Writes a warning message to the log in each case. @author Lee Denison (lee@xarg.co.uk) @creation-date: 2007-02-18 $Id: blank-compat.tcl,v 1.4 2007/12/03 20:29:30 daveb Exp $ } if { [template::util::is_nil title] } { set title [ad_conn instance_name] } if {![array exists doc]} { array set doc [list] } set translations [list \ doc_type doc(type) \ title doc(title) \ header_stuff head \ on_load body(onload) \ ] foreach {from to} $translations { if {[info exists $from]} { ns_log warning "blank-compat: [ad_conn file] uses deprecated property $from instead of $to." set $to [set $from] } else { set $to {} } } if {[exists_and_not_null body_attributes]} { foreach body_attribute $body_attributes { if {[lsearch { id class onload onunload onclick ondblclick onmousedown onmouseup onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup } [lindex $body_attribute 0] >= 0]} { ns_log warning "blank-compat: [ad_conn file] uses deprecated property body_attribute for [lindex $body_attribute 0] instead of body([lindex $body_attribute 0])." set body([lindex $body_attribute 0]) [lindex $body_attribute 1] } else { ns_log error "blank-compat: [ad_conn file] uses deprecated property body_attribute for [lindex $body_attribute 0] which is no longer supported!" } } } if {![template::multirow exists link]} { template::multirow create link rel type href title lang media } # DRB: this shouldn't really be in blank master, there should be some way for the templating # package to associate a particular css file with pages that use particular form or list # templates. Therefore I'll put the hard-wired values in blank-compat for the moment. multirow append link stylesheet text/css /resources/acs-templating/lists.css "" [ad_conn language] all multirow append link stylesheet text/css /resources/acs-templating/forms.css "" [ad_conn language] all if {![template::multirow exists script]} { template::multirow create script type src charset defer content } # # Add WYSIWYG editor content # global acs_blank_master__htmlareas acs_blank_master if {[info exists acs_blank_master__htmlareas] && [llength $acs_blank_master__htmlareas] > 0} { # # Add RTE scripts if we are using RTE # if {[info exists acs_blank_master(rte)]} { foreach htmlarea_id [lsort -unique $acs_blank_master__htmlareas] { lappend body(onload) "acs_rteInit('${htmlarea_id}')" } template::multirow append script \ "text/javascript" \ "/resources/acs-templating/rte/richtext.js" } # # Add Xinha scripts if we are using Xinha # if {[info exists acs_blank_master(xinha)]} { set xinha_dir /resources/acs-templating/xinha-nightly/ set xinha_plugins $acs_blank_master(xinha.plugins) set xinha_params "" set xinha_options $acs_blank_master(xinha.options) set xinha_lang [lang::conn::language] if {$xinha_lang ne "en" && $xinha_lang ne "de"} { set xinha_lang en } template::multirow append script "text/javascript" {} {} {} " _editor_url = \"$xinha_dir\"; _editor_lang = \"$xinha_lang\";" template::multirow append script \ "text/javascript" \ "${xinha_dir}htmlarea.js" set htmlarea_ids '[join $acs_blank_master__htmlareas "','"]' } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/global/���������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11724401446�015062� 5����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/global/busy.html������������������������������������������������������������������0000644�0001750�0001750�00000000027�07677222474�016747� 0����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������server busy placeholder���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/global/file-not-found.html��������������������������������������������������������0000644�0001750�0001750�00000000017�10005232304�020556� 0����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������File not found.�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/global/error.html�����������������������������������������������������������������0000644�0001750�0001750�00000000021�07677222474�017110� 0����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������error placeholder���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������openacs-5.7.0/www/global/site-failure.html.disabled�������������������������������������������������0000644�0001750�0001750�00000001646�07734414456�022131� 0����������������������������������������������������������������������������������������������������ustar �frankie�������������������������frankie����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <!-- This html page will be displayed instead of the standard OpenACS error message if there is a database failure. Customize at your will, and don't forget to update the contact address below! When you are finished customizing it you need to enable it by renaming it from 'www/global/site-failure.html.disabled' to 'www/global/site-failure.html'. Note that some broken IE browsers might show a 'friendly' error message instead if this file does not exceed 500 bytes. --> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15"> <title>

Site Failure


This site is currently not working due to a technical problem.

Please contact admin@example.com if you think the problem is not known yet.


openacs-5.7.0/www/robots.txt0000644000175000017500000000120310212644250015660 0ustar frankiefrankieUser-agent: * Disallow: /doc/ Disallow: /api-doc/ Disallow: /register Disallow: /register/ Disallow: /comments/ Disallow: /notifications/ Disallow: /test/ Disallow: /workflow/ Disallow: /acs-service-contract/ Disallow: /acs-lang/ Disallow: /acs-admin/ Disallow: /RPC2/ # googlebot knows wildcards so block all register User-agent: googlebot Disallow: /doc/ Disallow: /api-doc/ Disallow: /register Disallow: /register/ Disallow: /*/register Disallow: /*/register/ Disallow: /comments/ Disallow: /notifications/ Disallow: /test/ Disallow: /workflow/ Disallow: /acs-service-contract/ Disallow: /acs-lang/ Disallow: /acs-admin/ Disallow: /RPC2/ openacs-5.7.0/www/site-master.adp0000644000175000017500000000046610725555641016562 0ustar frankiefrankie doc body @head;noquote@ @focus;noquote@ openacs-5.7.0/www/site-master.tcl0000644000175000017500000000254010732460436016566 0ustar frankiefrankiead_page_contract { This is the highest level site specific master template. site-master adds site wide OpenACS functionality to every page. You should NOT need to modify this file unless you are adding functionality for a site wide service. If you want to customise the look and feel of your site you probably want to modify /www/default-master. Note: currently site wide service content is hard coded in this file. At some point we will want to determine this content dynamically which will change the content of this file significantly. @author Lee Denison (lee@xarg.co.uk) $Id: site-master.tcl,v 1.31 2007/12/20 12:33:34 emmar Exp $ } # # Add Site-Wide CSS # template::head::add_css \ -href "/resources/acs-subsite/site-master.css" \ -media "all" # # Fire subsite callbacks to get header content # FIXME: it's not clear why these callbacks are scoped to subsite or if # FIXME callbacks are the right way to add content of this type. Either way # FIXME using the @head@ property or indeed having a callback for every # FIXME possible javascript event handler is probably not the right way to go. # append head [join [callback subsite::get_extra_headers] "\n"] set onload_handlers [callback subsite::header_onload] foreach onload_handler $onload_handlers { template::add_body_handler -event onload -script $onload_handler } openacs-5.7.0/www/login-status.adp0000644000175000017500000000076207742315563016757 0ustar frankiefrankie
#acs-subsite.Not_logged_in#
#acs-subsite.Login_or_register#
@user_name@
@pvt_home_name@ @pvt_home_name@ - #acs-subsite.Logout#
openacs-5.7.0/www/login-status.tcl0000644000175000017500000000054310551254406016760 0ustar frankiefrankieset user_id [ad_conn user_id] if { $user_id != 0 } { set user_name [person::name -person_id $user_id] } set pvt_home_url [ad_pvt_home] if {[ad_conn url] eq $pvt_home_url} { set pvt_home_url {} } set pvt_home_name [ad_pvt_home_name] set login_url "/register/.?[export_vars { { return_url [ad_return_url]} }]" set logout_url "/register/logout" openacs-5.7.0/www/site-compat.adp0000644000175000017500000000071310622143345016533 0ustar frankiefrankie meta link script doc body @head;noquote@ openacs-5.7.0/www/site-compat.tcl0000644000175000017500000000116310622143345016551 0ustar frankiefrankiead_page_contract { Accepts and translates deprecated master template variables. Writes a warning message to the log in each case. @author Lee Denison (lee@xarg.co.uk) @creation-date: 2007-02-18 $Id: site-compat.tcl,v 1.2 2007/05/14 20:30:29 donb Exp $ } if {![array exists doc]} { array set doc [list] } set translations [list \ doc_type doc(type) \ header_stuff head \ on_load body(onload) \ ] foreach {from to} $translations { if {[info exists $from]} { ns_log warning "site-compat: [ad_conn file] uses deprecated property $from instead of $to." set $to [set $from] } } openacs-5.7.0/www/resources/0000755000175000017500000000000011724401446015634 5ustar frankiefrankieopenacs-5.7.0/www/resources/info.txt0000644000175000017500000000012210211142346017312 0ustar frankiefrankieThis directory is public and not checked for permissions. Put here your CSS file.openacs-5.7.0/www/default-master.adp0000644000175000017500000001054011022567615017227 0ustar frankiefrankie doc body @head;noquote@ @focus;noquote@ @skip_link;noquote@
@system_name@ @system_name@
TODO: remove this and add a more systematic / package independent way TODO of getting this content here empty UL gives a validation error for the W3C validator
openacs-5.7.0/www/default-master.tcl0000644000175000017500000001036511022567615017252 0ustar frankiefrankiead_page_contract { This is the highest level site specific master template. Properties allowed doc(title) HTML title head code to be entered into head of document body focus HTML id of form element to focus skip_link href of link to skip to. Should be of format #skip_link @author Lee Denison (lee@xarg.co.uk) $Id: default-master.tcl,v 1.27 2008/06/07 20:29:01 donb Exp $ } # # Set some basic variables # set system_name [ad_system_name] if {[ad_conn url] eq "/"} { set system_url "" } else { set system_url [ad_url] } if {[template::util::is_nil title]} { # TODO: decide how best to set the lang attribute for the title set title [ad_conn instance_name] } # # Create standard top level navigation # if {![info exists navigation_groups]} { set navigation_groups [list] } if {![template::multirow exists navigation]} { template::multirow create navigation \ group \ label \ href \ target \ title \ lang \ accesskey \ class \ id \ tabindex } for {set i 1} {$i <= [template::multirow size navigation]} {incr i} { template::multirow get navigation $i if {[lsearch $navigation_groups $navigation(group)] < 0} { lappend navigation_groups $navigation(group) } } # # Add standard css # template::head::add_css \ -href "/resources/acs-subsite/default-master.css" \ -media "all" # # User information and top level navigation links # set user_id [ad_conn user_id] set untrusted_user_id [ad_conn untrusted_user_id] set sw_admin_p 0 if { $untrusted_user_id == 0 } { # The browser does NOT claim to represent a user that we know about set login_url [ad_get_login_url -return] } else { # The browser claims to represent a user that we know about set user_name [person::name -person_id $untrusted_user_id] set pvt_home_url [ad_pvt_home] set pvt_home_name [_ acs-subsite.Your_Account] set logout_url [ad_get_logout_url] # Site-wide admin link set admin_url {} set sw_admin_p [acs_user::site_wide_admin_p -user_id $untrusted_user_id] if { $sw_admin_p } { set admin_url "/acs-admin/" set devhome_url "/acs-admin/developer" set locale_admin_url "/acs-lang/admin" } else { set subsite_admin_p [permission::permission_p \ -object_id [subsite::get_element -element object_id] \ -privilege admin \ -party_id $untrusted_user_id] if { $subsite_admin_p } { set admin_url "[subsite::get_element -element url]admin/" } } } # # User messages # util_get_user_messages -multirow user_messages # # Set acs-lang urls # set acs_lang_url [apm_package_url_from_key "acs-lang"] set num_of_locales [llength [lang::system::get_locales]] if {$acs_lang_url eq ""} { set lang_admin_p 0 } else { set lang_admin_p [permission::permission_p \ -object_id [site_node::get_element \ -url $acs_lang_url \ -element object_id] \ -privilege admin \ -party_id [ad_conn untrusted_user_id]] } set toggle_translator_mode_url [export_vars \ -base ${acs_lang_url}admin/translator-mode-toggle \ {{return_url [ad_return_url]}}] set package_id [ad_conn package_id] if { $num_of_locales > 1 } { set change_locale_url [export_vars -base $acs_lang_url {package_id}] } # # Change locale link # if {[llength [lang::system::get_locales]] > 1} { set change_locale_url [export_vars -base "/acs-lang/" {package_id}] } # # Who's Online # set num_users_online [lc_numeric [whos_online::num_users]] set whos_online_url "[subsite::get_element -element url]shared/whos-online" # # Context bar # if {[info exists context]} { set context_tmp $context unset context } else { set context_tmp {} } ad_context_bar_multirow -- $context_tmp # Context bar separator set subsite_id [ad_conn subsite_id] set separator [parameter::get -package_id $subsite_id -parameter ContextBarSeparator -default ":"] # # Curriculum specific bar # TODO: remove this and add a more systematic / package independent way # TODO of getting this content here # set curriculum_bar_p [expr { [site_node::get_package_url -package_key curriculum] ne "" }] if {![info exists skip_link]} { set skip_link "#content-wrapper" } openacs-5.7.0/packages/0000755000175000017500000000000011724401446014554 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/0000755000175000017500000000000011724401447017112 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/tcl/0000755000175000017500000000000011575226023017673 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/tcl/apm-callback-procs.tcl0000644000175000017500000001155311456662501024042 0ustar frankiefrankiead_library { Installation procs for ref-language @author Emmanuelle Raffenne (eraffenne@gmail.com) } namespace eval ref_language {} namespace eval ref_language::apm {} ad_proc -private ref_language::apm::after_install { } { Fill ISO-639-2 codes table } { ref_language::apm::add_language_639_2_codes } ad_proc -private ref_language::apm::after_upgrade { {-from_version_name:required} {-to_version_name:required} } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { 5.6.0d1 5.6.0d2 { # If the constraint doesn't exist, we don't care ... catch [db_dml drop_constraint {}] set new_languages [ref_language::apm::lang_list_for_5_6_0d2] foreach {code name} $new_languages { ref_language::set_data -iso1 $code -label $name } } 5.6.0d2 5.6.0d3 { ref_language::apm::add_language_639_2_codes } } } ## Helper procs ad_proc -private ref_language::apm::add_language_639_2_codes { } { Fills language_639_2_codes The ISO-639-2 codes are in a dat file located at ref-language/sql/commjon directory. The file was downloaded from http://www.loc.gov/standards/iso639-2/ISO-639-2_utf-8.txt Separator is "|" and the columns are:
  • ISO 639-2 Bibliographic code (used if terminology one is empty)
  • ISO 639-2 Terminology code (used if exists)
  • ISO 639-1 code (2 digits)
  • Language name in english
  • Language name in french (ignored if present)
} { set filename "[acs_root_dir]/packages/ref-language/sql/common/iso-639-2.dat" set channel [open $filename] set data [read $channel] close $channel set row_list [split $data "\n"] foreach row $row_list { if { $row eq "" } { continue } set col_list [split $row "|"] # Set iso-639-2 code to terminology if exists, otherwise # uses the bibliography one (see RFC 4646) set iso2b [lindex $col_list 0] set iso2 [lindex $col_list 1] set iso1 [lindex $col_list 2] set label [lindex $col_list 3] if { $iso2 eq "" } { set iso2 $iso2b } ref_language::set_data -iso2 $iso2 -iso1 $iso1 -label $label } } ad_proc -private ref_language::apm::lang_list_for_5_6_0d2 { } { return { ae "Avestan" ak "Akan" an "Aragonese" av "Avaric" be "Belarusian" bm "Bambara" bn "Bengali" bs "Bosnian" ca "Catalan; Valencian" ce "Chechen" ch "Chamorro" cr "Cree" cu "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic" cv "Chuvash" dv "Divehi; Dhivehi; Maldivian" dz "Dzongkha" ee "Ewe" el "Greek, Modern (1453-)" es "Spanish; Castilian" ff "Fulah" fj "Fijian" fo "Faroese" fy "Western Frisian" gd "Gaelic; Scottish Gaelic" gv "Manx" he "Hebrew" ho "Hiri Motu" ht "Haitian; Haitian Creole" hz "Herero" ia "Interlingua (International Auxiliary Language Association)" id "Indonesian" ie "Interlingue; Occidental" ig "Igbo" ii "Sichuan Yi; Nuosu" ik "Inupiaq" io "Ido" iu "Inuktitut" jv "Javanese" kg "Kongo" ki "Kikuyu; Gikuyu" kj "Kuanyama; Kwanyama" kl "Kalaallisut; Greenlandic" km "Central Khmer" kr "Kanuri" kv "Komi" kw "Cornish" ky "Kirghiz; Kyrgyz" lb "Luxembourgish; Letzeburgesch" lg "Ganda" li "Limburgan; Limburger; Limburgish" lo "Lao" lu "Luba-Katanga" lv "Latvian" mh "Marshallese" nb "Bokmål, Norwegian; Norwegian Bokmål" nd "Ndebele, North; North Ndebele" ng "Ndonga" nl "Dutch; Flemish" nn "Norwegian Nynorsk; Nynorsk, Norwegian" nr "Ndebele, South; South Ndebele" nv "Navajo; Navaho" ny "Chichewa; Chewa; Nyanja" oc "Occitan (post 1500); Provençal" oj "Ojibwa" om "Oromo" os "Ossetian; Ossetic" pa "Panjabi; Punjabi" pi "Pali" ps "Pushto; Pashto" rm "Romansh" rn "Rundi" ro "Romanian; Moldavian; Moldovan" sc "Sardinian" se "Northern Sami" sg "Sango" si "Sinhala; Sinhalese" ss "Swati" st "Sotho, Southern" tn "Tswana" to "Tonga (Tonga Islands)" ty "Tahitian" ug "Uighur; Uyghur" ve "Venda" vo "Volapük" wa "Walloon" yi "Yiddish" yo "Yoruba" za "Zhuang; Chuang" } } openacs-5.7.0/packages/ref-language/tcl/apm-callback-procs.xql0000644000175000017500000000035611456662501024063 0ustar frankiefrankie alter table language_codes drop constraint language_codes_name_uq openacs-5.7.0/packages/ref-language/tcl/ref-language-procs.tcl0000644000175000017500000000223611373240231024054 0ustar frankiefrankiead_library { Library for managing language codes @author Emmanuelle Raffenne (eraffenne@gmail.com) } namespace eval ref_language {} ad_proc -public ref_language::set_data { -label:required {-iso1 ""} {-iso2 ""} } { Add new ISO-639 language codes (3 chars and 2 chars) where they don't exist, update them otherwise. } { if { $iso1 eq "" && $iso2 eq "" } { error "you need to provide either a 2 chars or a 3 chars language code" } else { if { $iso2 ne "" } { set exists_p [db_string get_lang {} -default 0] if { $exists_p } { db_dml update_lang {} } else { db_dml insert_lang {} } } if { $iso1 ne "" } { ref_language::set_iso1 -code $iso1 -name $label } } } ad_proc -private ref_language::set_iso1 { -code:required -name:required } { Add a new ISO-639-1 language code (2 chars) if it doesn't exist, update it otherwise } { set exists_p [db_string get_lang {} -default 0] if { $exists_p } { db_dml update_lang {} } else { db_dml insert_lang {} } } openacs-5.7.0/packages/ref-language/tcl/ref-language-procs.xql0000644000175000017500000000231411373240231024073 0ustar frankiefrankie select count(*) from language_639_2_codes where iso_639_2 = :iso2 update language_639_2_codes set label = :label, iso_639_1 = :iso1 where iso_639_2 = :iso2 insert into language_639_2_codes (iso_639_2, iso_639_1, label) values (:iso2, :iso1, :label) select count(*) from language_codes where language_id = :code update language_codes set name = :name where language_id = :code insert into language_codes (language_id, name) values (:code, :name) openacs-5.7.0/packages/ref-language/sql/0000755000175000017500000000000011724401447017711 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/sql/common/0000755000175000017500000000000011724401447021201 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/sql/common/iso-639-1.dat0000644000175000017500000000503211373027560023142 0ustar frankiefrankieaa|Afar ab|Abkhazian ae|Avestan af|Afrikaans ak|Akan am|Amharic an|Aragonese ar|Arabic as|Assamese av|Avaric ay|Aymara az|Azerbaijani ba|Bashkir be|Belarusian bg|Bulgarian bh|Bihari bi|Bislama bm|Bambara bn|Bengali bo|Tibetan br|Breton bs|Bosnian ca|Catalan; Valencian ce|Chechen ch|Chamorro co|Corsican cr|Cree cs|Czech cu|Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic cv|Chuvash cy|Welsh da|Danish de|German dv|Divehi; Dhivehi; Maldivian dz|Dzongkha ee|Ewe el|Greek, Modern (1453-) en|English eo|Esperanto es|Spanish; Castilian et|Estonian eu|Basque fa|Persian ff|Fulah fi|Finnish fj|Fijian fo|Faroese fr|French fy|Western Frisian ga|Irish gd|Gaelic; Scottish Gaelic gl|Galician gn|Guarani gu|Gujarati gv|Manx ha|Hausa he|Hebrew hi|Hindi ho|Hiri Motu hr|Croatian ht|Haitian; Haitian Creole hu|Hungarian hy|Armenian hz|Herero ia|Interlingua (International Auxiliary Language Association) id|Indonesian ie|Interlingue; Occidental ig|Igbo ii|Sichuan Yi; Nuosu ik|Inupiaq io|Ido is|Icelandic it|Italian iu|Inuktitut ja|Japanese jv|Javanese ka|Georgian kg|Kongo ki|Kikuyu; Gikuyu kj|Kuanyama; Kwanyama kk|Kazakh kl|Kalaallisut; Greenlandic km|Central Khmer kn|Kannada ko|Korean kr|Kanuri ks|Kashmiri ku|Kurdish kv|Komi kw|Cornish ky|Kirghiz; Kyrgyz la|Latin lb|Luxembourgish; Letzeburgesch lg|Ganda li|Limburgan; Limburger; Limburgish ln|Lingala lo|Lao lt|Lithuanian lu|Luba-Katanga lv|Latvian mg|Malagasy mh|Marshallese mi|Maori mk|Macedonian ml|Malayalam mn|Mongolian mr|Marathi ms|Malay mt|Maltese my|Burmese na|Nauru nb|BokmÃ¥l, Norwegian; Norwegian BokmÃ¥l nd|Ndebele, North; North Ndebele ne|Nepali ng|Ndonga nl|Dutch; Flemish nn|Norwegian Nynorsk; Nynorsk, Norwegian no|Norwegian nr|Ndebele, South; South Ndebele nv|Navajo; Navaho ny|Chichewa; Chewa; Nyanja oc|Occitan (post 1500); Provençal oj|Ojibwa om|Oromo or|Oriya os|Ossetian; Ossetic pa|Panjabi; Punjabi pi|Pali pl|Polish ps|Pushto; Pashto pt|Portuguese qu|Quechua rm|Romansh rn|Rundi ro|Romanian; Moldavian; Moldovan ru|Russian rw|Kinyarwanda sa|Sanskrit sc|Sardinian sd|Sindhi se|Northern Sami sg|Sango si|Sinhala; Sinhalese sk|Slovak sl|Slovenian sm|Samoan sn|Shona so|Somali sq|Albanian sr|Serbian ss|Swati st|Sotho, Southern su|Sundanese sv|Swedish sw|Swahili ta|Tamil te|Telugu tg|Tajik th|Thai ti|Tigrinya tk|Turkmen tl|Tagalog tn|Tswana to|Tonga (Tonga Islands) tr|Turkish ts|Tsonga tt|Tatar tw|Twi ty|Tahitian ug|Uighur; Uyghur uk|Ukrainian ur|Urdu uz|Uzbek ve|Venda vi|Vietnamese vo|Volapük wa|Walloon wo|Wolof xh|Xhosa yi|Yiddish yo|Yoruba za|Zhuang; Chuang zh|Chinese zu|Zulu openacs-5.7.0/packages/ref-language/sql/common/iso-639-2.dat0000644000175000017500000002222711373027560023150 0ustar frankiefrankieaar||aa|Afar abk||ab|Abkhazian ace|||Achinese ach|||Acoli ada|||Adangme ady|||Adyghe; Adygei afa|||Afro-Asiatic languages afh|||Afrihili afr||af|Afrikaans ain|||Ainu aka||ak|Akan akk|||Akkadian alb|sqi|sq|Albanian ale|||Aleut alg|||Algonquian languages alt|||Southern Altai amh||am|Amharic ang|||English, Old (ca.450-1100) anp|||Angika apa|||Apache languages ara||ar|Arabic arc|||Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE) arg||an|Aragonese arm|hye|hy|Armenian arn|||Mapudungun; Mapuche arp|||Arapaho art|||Artificial languages arw|||Arawak asm||as|Assamese ast|||Asturian; Bable; Leonese; Asturleonese ath|||Athapascan languages aus|||Australian languages ava||av|Avaric ave||ae|Avestan awa|||Awadhi aym||ay|Aymara aze||az|Azerbaijani bad|||Banda languages bai|||Bamileke languages bak||ba|Bashkir bal|||Baluchi bam||bm|Bambara ban|||Balinese baq|eus|eu|Basque bas|||Basa bat|||Baltic languages bej|||Beja; Bedawiyet bel||be|Belarusian bem|||Bemba ben||bn|Bengali ber|||Berber languages bho|||Bhojpuri bih||bh|Bihari bik|||Bikol bin|||Bini; Edo bis||bi|Bislama bla|||Siksika bnt|||Bantu (Other) bos||bs|Bosnian bra|||Braj bre||br|Breton btk|||Batak languages bua|||Buriat bug|||Buginese bul||bg|Bulgarian bur|mya|my|Burmese byn|||Blin; Bilin cad|||Caddo cai|||Central American Indian languages car|||Galibi Carib cat||ca|Catalan; Valencian cau|||Caucasian languages ceb|||Cebuano cel|||Celtic languages cha||ch|Chamorro chb|||Chibcha che||ce|Chechen chg|||Chagatai chi|zho|zh|Chinese chk|||Chuukese chm|||Mari chn|||Chinook jargon cho|||Choctaw chp|||Chipewyan; Dene Suline chr|||Cherokee chu||cu|Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic chv||cv|Chuvash chy|||Cheyenne cmc|||Chamic languages cop|||Coptic cor||kw|Cornish cos||co|Corsican cpe|||Creoles and pidgins, English based cpf|||Creoles and pidgins, French-based cpp|||Creoles and pidgins, Portuguese-based cre||cr|Cree crh|||Crimean Tatar; Crimean Turkish crp|||Creoles and pidgins csb|||Kashubian cus|||Cushitic languages cze|ces|cs|Czech dak|||Dakota dan||da|Danish dar|||Dargwa day|||Land Dayak languages del|||Delaware den|||Slave (Athapascan) dgr|||Dogrib din|||Dinka div||dv|Divehi; Dhivehi; Maldivian doi|||Dogri dra|||Dravidian languages dsb|||Lower Sorbian dua|||Duala dum|||Dutch, Middle (ca.1050-1350) dut|nld|nl|Dutch; Flemish dyu|||Dyula dzo||dz|Dzongkha efi|||Efik egy|||Egyptian (Ancient) eka|||Ekajuk elx|||Elamite eng||en|English enm|||English, Middle (1100-1500) epo||eo|Esperanto est||et|Estonian ewe||ee|Ewe ewo|||Ewondo fan|||Fang fao||fo|Faroese fat|||Fanti fij||fj|Fijian fil|||Filipino; Pilipino fin||fi|Finnish fiu|||Finno-Ugrian languages fon|||Fon fre|fra|fr|French frm|||French, Middle (ca.1400-1600) fro|||French, Old (842-ca.1400) frr|||Northern Frisian frs|||Eastern Frisian fry||fy|Western Frisian ful||ff|Fulah fur|||Friulian gaa|||Ga gay|||Gayo gba|||Gbaya gem|||Germanic languages geo|kat|ka|Georgian ger|deu|de|German gez|||Geez gil|||Gilbertese gla||gd|Gaelic; Scottish Gaelic gle||ga|Irish glg||gl|Galician glv||gv|Manx gmh|||German, Middle High (ca.1050-1500) goh|||German, Old High (ca.750-1050) gon|||Gondi gor|||Gorontalo got|||Gothic grb|||Grebo grc|||Greek, Ancient (to 1453) gre|ell|el|Greek, Modern (1453-) grn||gn|Guarani gsw|||Swiss German; Alemannic; Alsatian guj||gu|Gujarati gwi|||Gwich'in hai|||Haida hat||ht|Haitian; Haitian Creole hau||ha|Hausa haw|||Hawaiian heb||he|Hebrew her||hz|Herero hil|||Hiligaynon him|||Himachali hin||hi|Hindi hit|||Hittite hmn|||Hmong hmo||ho|Hiri Motu hrv||hr|Croatian hsb|||Upper Sorbian hun||hu|Hungarian hup|||Hupa iba|||Iban ibo||ig|Igbo ice|isl|is|Icelandic ido||io|Ido iii||ii|Sichuan Yi; Nuosu ijo|||Ijo languages iku||iu|Inuktitut ile||ie|Interlingue; Occidental ilo|||Iloko ina||ia|Interlingua (International Auxiliary Language Association) inc|||Indic languages ind||id|Indonesian ine|||Indo-European languages inh|||Ingush ipk||ik|Inupiaq ira|||Iranian languages iro|||Iroquoian languages ita||it|Italian jav||jv|Javanese jbo|||Lojban jpn||ja|Japanese jpr|||Judeo-Persian jrb|||Judeo-Arabic kaa|||Kara-Kalpak kab|||Kabyle kac|||Kachin; Jingpho kal||kl|Kalaallisut; Greenlandic kam|||Kamba kan||kn|Kannada kar|||Karen languages kas||ks|Kashmiri kau||kr|Kanuri kaw|||Kawi kaz||kk|Kazakh kbd|||Kabardian kha|||Khasi khi|||Khoisan languages khm||km|Central Khmer kho|||Khotanese; Sakan kik||ki|Kikuyu; Gikuyu kin||rw|Kinyarwanda kir||ky|Kirghiz; Kyrgyz kmb|||Kimbundu kok|||Konkani kom||kv|Komi kon||kg|Kongo kor||ko|Korean kos|||Kosraean kpe|||Kpelle krc|||Karachay-Balkar krl|||Karelian kro|||Kru languages kru|||Kurukh kua||kj|Kuanyama; Kwanyama kum|||Kumyk kur||ku|Kurdish kut|||Kutenai lad|||Ladino lah|||Lahnda lam|||Lamba lao||lo|Lao lat||la|Latin lav||lv|Latvian lez|||Lezghian lim||li|Limburgan; Limburger; Limburgish lin||ln|Lingala lit||lt|Lithuanian lol|||Mongo loz|||Lozi ltz||lb|Luxembourgish; Letzeburgesch lua|||Luba-Lulua lub||lu|Luba-Katanga lug||lg|Ganda lui|||Luiseno lun|||Lunda luo|||Luo (Kenya and Tanzania) lus|||Lushai mac|mkd|mk|Macedonian mad|||Madurese mag|||Magahi mah||mh|Marshallese mai|||Maithili mak|||Makasar mal||ml|Malayalam man|||Mandingo mao|mri|mi|Maori map|||Austronesian languages mar||mr|Marathi mas|||Masai may|msa|ms|Malay mdf|||Moksha mdr|||Mandar men|||Mende mga|||Irish, Middle (900-1200) mic|||Mi'kmaq; Micmac min|||Minangkabau mis|||Uncoded languages mkh|||Mon-Khmer languages mlg||mg|Malagasy mlt||mt|Maltese mnc|||Manchu mni|||Manipuri mno|||Manobo languages moh|||Mohawk mon||mn|Mongolian mos|||Mossi mul|||Multiple languages mun|||Munda languages mus|||Creek mwl|||Mirandese mwr|||Marwari myn|||Mayan languages myv|||Erzya nah|||Nahuatl languages nai|||North American Indian languages nap|||Neapolitan nau||na|Nauru nav||nv|Navajo; Navaho nbl||nr|Ndebele, South; South Ndebele nde||nd|Ndebele, North; North Ndebele ndo||ng|Ndonga nds|||Low German; Low Saxon; German, Low; Saxon, Low nep||ne|Nepali new|||Nepal Bhasa; Newari nia|||Nias nic|||Niger-Kordofanian languages niu|||Niuean nno||nn|Norwegian Nynorsk; Nynorsk, Norwegian nob||nb|BokmÃ¥l, Norwegian; Norwegian BokmÃ¥l nog|||Nogai non|||Norse, Old nor||no|Norwegian nqo|||N'Ko nso|||Pedi; Sepedi; Northern Sotho nub|||Nubian languages nwc|||Classical Newari; Old Newari; Classical Nepal Bhasa nya||ny|Chichewa; Chewa; Nyanja nym|||Nyamwezi nyn|||Nyankole nyo|||Nyoro nzi|||Nzima oci||oc|Occitan (post 1500); Provençal oji||oj|Ojibwa ori||or|Oriya orm||om|Oromo osa|||Osage oss||os|Ossetian; Ossetic ota|||Turkish, Ottoman (1500-1928) oto|||Otomian languages paa|||Papuan languages pag|||Pangasinan pal|||Pahlavi pam|||Pampanga; Kapampangan pan||pa|Panjabi; Punjabi pap|||Papiamento pau|||Palauan peo|||Persian, Old (ca.600-400 B.C.) per|fas|fa|Persian phi|||Philippine languages phn|||Phoenician pli||pi|Pali pol||pl|Polish pon|||Pohnpeian por||pt|Portuguese pra|||Prakrit languages pro|||Provençal, Old (to 1500) pus||ps|Pushto; Pashto que||qu|Quechua raj|||Rajasthani rap|||Rapanui rar|||Rarotongan; Cook Islands Maori roa|||Romance languages roh||rm|Romansh rom|||Romany rum|ron|ro|Romanian; Moldavian; Moldovan run||rn|Rundi rup|||Aromanian; Arumanian; Macedo-Romanian rus||ru|Russian sad|||Sandawe sag||sg|Sango sah|||Yakut sai|||South American Indian (Other) sal|||Salishan languages sam|||Samaritan Aramaic san||sa|Sanskrit sas|||Sasak sat|||Santali scn|||Sicilian sco|||Scots sel|||Selkup sem|||Semitic languages sga|||Irish, Old (to 900) sgn|||Sign Languages shn|||Shan sid|||Sidamo sin||si|Sinhala; Sinhalese sio|||Siouan languages sit|||Sino-Tibetan languages sla|||Slavic languages slo|slk|sk|Slovak slv||sl|Slovenian sma|||Southern Sami sme||se|Northern Sami smi|||Sami languages smj|||Lule Sami smn|||Inari Sami smo||sm|Samoan sms|||Skolt Sami sna||sn|Shona snd||sd|Sindhi snk|||Soninke sog|||Sogdian som||so|Somali son|||Songhai languages sot||st|Sotho, Southern spa||es|Spanish; Castilian srd||sc|Sardinian srn|||Sranan Tongo srp||sr|Serbian srr|||Serer ssa|||Nilo-Saharan languages ssw||ss|Swati suk|||Sukuma sun||su|Sundanese sus|||Susu sux|||Sumerian swa||sw|Swahili swe||sv|Swedish syc|||Classical Syriac syr|||Syriac tah||ty|Tahitian tai|||Tai languages tam||ta|Tamil tat||tt|Tatar tel||te|Telugu tem|||Timne ter|||Tereno tet|||Tetum tgk||tg|Tajik tgl||tl|Tagalog tha||th|Thai tib|bod|bo|Tibetan tig|||Tigre tir||ti|Tigrinya tiv|||Tiv tkl|||Tokelau tlh|||Klingon; tlhIngan-Hol tli|||Tlingit tmh|||Tamashek tog|||Tonga (Nyasa) ton||to|Tonga (Tonga Islands) tpi|||Tok Pisin tsi|||Tsimshian tsn||tn|Tswana tso||ts|Tsonga tuk||tk|Turkmen tum|||Tumbuka tup|||Tupi languages tur||tr|Turkish tut|||Altaic languages tvl|||Tuvalu twi||tw|Twi tyv|||Tuvinian udm|||Udmurt uga|||Ugaritic uig||ug|Uighur; Uyghur ukr||uk|Ukrainian umb|||Umbundu und|||Undetermined urd||ur|Urdu uzb||uz|Uzbek vai|||Vai ven||ve|Venda vie||vi|Vietnamese vol||vo|Volapük vot|||Votic wak|||Wakashan languages wal|||Walamo war|||Waray was|||Washo wel|cym|cy|Welsh wen|||Sorbian languages wln||wa|Walloon wol||wo|Wolof xal|||Kalmyk; Oirat xho||xh|Xhosa yao|||Yao yap|||Yapese yid||yi|Yiddish yor||yo|Yoruba ypk|||Yupik languages zap|||Zapotec zbl|||Blissymbols; Blissymbolics; Bliss zen|||Zenaga zha||za|Zhuang; Chuang znd|||Zande languages zul||zu|Zulu zun|||Zuni zxx|||No linguistic content; Not applicable zza|||Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki openacs-5.7.0/packages/ref-language/sql/oracle/0000755000175000017500000000000011724401447021156 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/sql/oracle/ref-language-create.sql0000644000175000017500000000257511456662501025510 0ustar frankiefrankie-- packages/ref-language/sql/oracle/ref-language-create.sql -- -- @author jon@jongriffin.com -- @creation-date 2000-11-21 -- @cvs-id $Id: ref-language-create.sql,v 1.8 2010/10/17 21:06:09 donb Exp $ -- -- ISO 639-1 create table language_codes ( language_id char(2) constraint language_codes_language_id_pk primary key, name varchar(100) constraint language_codes_name_nn not null ); comment on table language_codes is ' This is data from the ISO 639-1 standard on language codes. '; comment on column language_codes.language_id is ' This is the ISO standard language 2 char code '; comment on column language_codes.name is ' This is the English version of the language name. '; -- now register this table with the repository declare v_id integer; begin v_id := acs_reference.new( table_name => upper('language_codes'), source => 'ISO 639-1', source_url => 'http://www.iso.ch', effective_date => sysdate ); commit; end; / -- Languages ISO-639-2 codes create table language_639_2_codes ( iso_639_2 char(3) constraint language_codes_iso_639_2_pk primary key, iso_639_1 char(2), label varchar(200) ); comment on table language_639_2_codes is 'Contains ISO-639-2 language codes and their corresponding ISO-639-1 when it exists.'; openacs-5.7.0/packages/ref-language/sql/oracle/ref-language-drop.sql0000644000175000017500000000202211373240231025162 0ustar frankiefrankie-- Drop the ACS Reference Language data -- -- @author jon@jongriffin.com -- @cvs-id $Id: ref-language-drop.sql,v 1.5 2010/05/14 12:22:49 emmar Exp $ set serveroutput on -- drop all associated tables and packages -- I am not sure this is a good idea since we have no way to register -- if any other packages are using this data. -- This will probably fail if their is a child table using this. -- I can probably make this cleaner also, but ... no time today drop table language_639_2_codes; declare cursor refsrc_cur is select table_name, package_name, repository_id from acs_reference_repositories where upper(table_name) = 'LANGUAGE_CODES'; begin for rec in refsrc_cur loop dbms_output.put_line('Dropping ' || rec.table_name); execute immediate 'drop table ' || rec.table_name; if rec.package_name is not null then execute immediate 'drop package ' || rec.package_name; end if; acs_reference.del(rec.repository_id); end loop; end; / show errors openacs-5.7.0/packages/ref-language/sql/oracle/upgrade/0000755000175000017500000000000011575226023022604 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/sql/oracle/upgrade/upgrade-5.6.0d2-5.6.0d3.sql0000644000175000017500000000067011373240231026535 0ustar frankiefrankie-- The table is filled by after_install and after_upgrade apm callbacks -- using the iso-639-2.dat file create table language_639_2_codes ( iso_639_2 char(3) constraint language_codes_iso_639_2_pk primary key, iso_639_1 char(2), label varchar(200) ); comment on table language_639_2_codes is 'Contains ISO-639-2 language codes and their corresponding ISO-639-1 when it exists.'; openacs-5.7.0/packages/ref-language/sql/oracle/00-languages.ctl0000644000175000017500000000027211373027560024046 0ustar frankiefrankieload data infile '[acs_root_dir]/packages/ref-language/sql/common/iso-639-1.dat' into table language_codes replace fields terminated by "|" optionally enclosed by "'" (language_id,name) openacs-5.7.0/packages/ref-language/sql/postgresql/0000755000175000017500000000000011575226023022113 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/sql/postgresql/ref-language-create.sql0000644000175000017500000000234711456662501026443 0ustar frankiefrankie-- packages/ref-language/sql/postgresql/language.sql -- -- @author jon@jongriffin.com -- @creation-date 2000-11-21 -- @cvs-id $Id: ref-language-create.sql,v 1.5 2010/10/17 21:06:09 donb Exp $ -- -- ISO 639 create table language_codes ( language_id char(2) constraint language_codes_language_id_pk primary key, name varchar(100) constraint language_codes_name_nn not null ); comment on table language_codes is ' This is data from the ISO 639-1 standard on language codes. '; comment on column language_codes.language_id is ' This is the ISO standard language 2 chars code '; comment on column language_codes.name is ' This is the English version of the language name. '; -- now register this table with the repository select acs_reference__new( 'LANGUAGE_CODES', null, 'ISO 639-1', 'http://www.iso.ch', now() ); -- Languages ISO-639-2 codes create table language_639_2_codes ( iso_639_2 char(3) constraint language_codes_iso_639_2_pk primary key, iso_639_1 char(2), label varchar(200) ); comment on table language_639_2_codes is 'Contains ISO-639-2 language codes and their corresponding ISO-639-1 when it exists.'; openacs-5.7.0/packages/ref-language/sql/postgresql/ref-language-drop.sql0000644000175000017500000000160111373240231026122 0ustar frankiefrankie-- Drop the ACS Reference Country data -- -- @author jon@jongriffin.com -- @cvs-id $Id: ref-language-drop.sql,v 1.4 2010/05/14 12:22:49 emmar Exp $ -- drop all associated tables and packages -- I am not sure this is a good idea since we have no way to register -- if any other packages are using this data. -- This will probably fail if their is a child table using this. -- I can probably make this cleaner also, but ... no time today drop table language_639_2_codes; create function inline_0() returns integer as ' declare rec acs_reference_repositories%ROWTYPE; begin for rec in select * from acs_reference_repositories where upper(table_name) = ''LANGUAGE_CODES'' loop execute ''drop table '' || rec.table_name; perform acs_reference__delete(rec.repository_id); end loop; return 0; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); openacs-5.7.0/packages/ref-language/sql/postgresql/upgrade/0000755000175000017500000000000011575226023023542 5ustar frankiefrankieopenacs-5.7.0/packages/ref-language/sql/postgresql/upgrade/upgrade-5.6.0d2-5.6.0d3.sql0000644000175000017500000000066711373240231027501 0ustar frankiefrankie-- The table is filled by after_install and after_upgrade apm callbacks -- using the iso-639-2.dat file create table language_639_2_codes ( iso_639_2 char(3) constraint language_codes_iso_639_2_pk primary key, iso_639_1 char(2), label varchar(200) ); comment on table language_639_2_codes is 'Contains ISO-639-2 language codes and their corresponding ISO-639-1 when it exists.'; openacs-5.7.0/packages/ref-language/sql/postgresql/00-languages.ctl0000644000175000017500000000016311373027560025003 0ustar frankiefrankie\copy language_codes from '[acs_root_dir]/packages/ref-language/sql/common/iso-639-1.dat' delimiter '|' null as '' openacs-5.7.0/packages/ref-language/ref-language.info0000644000175000017500000000250111575167337022335 0ustar frankiefrankie Reference Data - Language Reference Data - Languages t t Jon Griffin ISO 639-1 language reference data for acs-reference. Mayuli Enterprises, LLC This is the ISO 639-1 language reference data (with languages names in English). openacs-5.7.0/packages/acs-service-contract/0000755000175000017500000000000011724401447020574 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/tcl/0000755000175000017500000000000011724401447021356 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/tcl/test/0000755000175000017500000000000011575225534022342 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/tcl/test/acs-service-contract-procs.tcl0000644000175000017500000000556507727635501030227 0ustar frankiefrankiead_library { Register acs-automated-testing test cases for acs-service-contract package on server startup. @author Simon Carstensen @creation-date 2003-09-10 @cvs-id $Id: acs-service-contract-procs.tcl,v 1.1 2003/09/10 14:54:57 peterm Exp $ } aa_register_case acs_sc_impl_new_from_spec { Test the acs_sc::impl::new_from_spec proc. } { aa_run_with_teardown \ -rollback \ -test_code { set spec { name "foo_contract" description "Blah blah blah blah" operations { Authenticate { description { Validate this username/password combination, and return the result. Valid auth_status codes are 'ok', 'no_account', 'bad_password', 'auth_error', 'failed_to_connect'. The last, 'failed_to_connect', is reserved for communications or implementation errors. auth_message is a human-readable explanation of what went wrong, may contain HTML. Only checked if auth_status is not ok. Valid account_status codes are 'ok' and 'closed'. account_message may be supplied regardless of account_status, and may contain HTML. } input { username:string password:string parameters:string,multiple } output { auth_status:string auth_message:string account_status:string account_message:string } } GetParameters { description { Get an arraay-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec set spec { contract_name "foo_contract" owner "acs-service-contract" name "foo" pretty_name "Foo Driver" aliases { Authenticate auth::local::authentication::Authenticate GetParameters auth::local::authentication::GetParameters } } set impl_id [acs_sc::impl::new_from_spec -spec $spec] acs_sc::impl::get -impl_id $impl_id -array impl aa_equals "pretty_name dit not get inserted correctly" $impl(impl_pretty_name) "Foo Driver" } } openacs-5.7.0/packages/acs-service-contract/tcl/msg-type-procs-oracle.xql0000644000175000017500000000225607736271233026253 0ustar frankiefrankie oracle8.1.6 begin :1 := acs_sc_msg_type.new( :name, :specification ); end; begin acs_sc_msg_type.del( msg_type_id => :msg_type_id ); end; begin acs_sc_msg_type.del( msg_type_name => :name ); end; begin :1 := acs_sc_msg_type.new_element( :msg_type_name, :element_name, :element_msg_type_name, :element_msg_type_isset_p, :element_pos ); end; openacs-5.7.0/packages/acs-service-contract/tcl/implementation-procs-postgresql.xql0000644000175000017500000000240707727635221030470 0ustar frankiefrankie postgresql7.2 select acs_sc_impl__new( :contract_name, :name, :pretty_name, :owner ); select acs_sc_impl_alias__new( :contract_name, :impl_name, :operation, :alias, :language ); select acs_sc_binding__new( :contract_name, :impl_name ); select acs_sc_impl__delete( :contract_name, :impl_name ); openacs-5.7.0/packages/acs-service-contract/tcl/acs-service-contract-init-oracle.xql0000644000175000017500000000040007360501701030314 0ustar frankiefrankie oracle8.1.6 select acs_sc_binding.exists_p(:impl_contract_name,:impl_name) from dual openacs-5.7.0/packages/acs-service-contract/tcl/acs-service-contract-init.tcl0000644000175000017500000000103010041311127027016 0ustar frankiefrankie# Loop over actual bindings, finding every impl alias for each contract operation db_foreach impl_operation { select ia.impl_contract_name, ia.impl_operation_name, ia.impl_name, ia.impl_alias, ia.impl_pl from acs_sc_bindings b, acs_sc_impl_aliases ia where ia.impl_id = b.impl_id } { # This creates the AcsSc.Contract.Operation.Impl wrapper proc for this implementation acs_sc_proc $impl_contract_name $impl_operation_name $impl_name $impl_alias $impl_pl } openacs-5.7.0/packages/acs-service-contract/tcl/contract-procs-postgresql.xql0000644000175000017500000000360707617456740027270 0ustar frankiefrankie postgresql7.2 select acs_sc_contract__new( :name, :description ); select acs_sc_contract__get_name(:contract_id); select acs_sc_contract__get_id(:name); select operation_id, operation_inputtype_id, operation_outputtype_id from acs_sc_operations where contract_id = :contract_id select acs_sc_contract__delete(:name); select acs_sc_operation__new( :contract_name, :operation, :description, :is_cachable_p, :nargs, :input_type_name, :output_type_name ); select contract_name, operation_name from acs_sc_operations where operation_id = :operation_id select acs_sc_operation__delete(:contract_name, :operation_name); openacs-5.7.0/packages/acs-service-contract/tcl/acs-service-contract-procs-postgresql.xql0000644000175000017500000000314310016637472031453 0ustar frankiefrankie postgresql7.1 select acs_sc_binding__exists_p(:contract,:impl) select impl_alias, impl_pl from acs_sc_impl_aliases where impl_contract_name = :contract and impl_operation_name = :operation and impl_name = :impl select operation_desc, coalesce(operation_iscachable_p,'f') as operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id from acs_sc_operations where contract_name = :contract and operation_name = :operation select element_name, acs_sc_msg_type__get_name(element_msg_type_id) as element_msg_type_name, element_msg_type_isset_p, element_pos from acs_sc_msg_type_elements where msg_type_id = :operation_inputtype_id order by element_pos asc select element_name, acs_sc_msg_type__get_name(element_msg_type_id) as element_msg_type_name, element_msg_type_isset_p, element_pos from acs_sc_msg_type_elements where msg_type_id = :operation_outputtype_id order by element_pos asc openacs-5.7.0/packages/acs-service-contract/tcl/acs-service-contract-procs-oracle.xql0000644000175000017500000000313510022125465030505 0ustar frankiefrankie oracle8.1.6 select acs_sc_binding.exists_p(:contract,:impl) from dual select impl_alias, impl_pl from acs_sc_impl_aliases where impl_contract_name = :contract and impl_operation_name = :operation and impl_name = :impl select operation_desc, nvl(operation_iscachable_p,'f') as operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id from acs_sc_operations where contract_name = :contract and operation_name = :operation select element_name, acs_sc_msg_type.get_name(element_msg_type_id) as element_msg_type_name, element_msg_type_isset_p, element_pos from acs_sc_msg_type_elements where msg_type_id = :operation_inputtype_id order by element_pos asc select element_name, acs_sc_msg_type.get_name(element_msg_type_id) as element_msg_type_name, element_msg_type_isset_p, element_pos from acs_sc_msg_type_elements where msg_type_id = :operation_outputtype_id order by element_pos asc openacs-5.7.0/packages/acs-service-contract/tcl/msg-type-procs-postgresql.xql0000644000175000017500000000144207626704225027205 0ustar frankiefrankie postgresql7.2 select acs_sc_msg_type__new( :name, :specification); select acs_sc_msg_type__delete(:name); select acs_sc_msg_type__new_element( :msg_type_name, :element_name, :element_msg_type_name, :element_msg_type_isset_p, :element_pos ); openacs-5.7.0/packages/acs-service-contract/tcl/acs-service-contract-init-postgresql.xql0000644000175000017500000000037007766162052031274 0ustar frankiefrankie postgresql7.1 select acs_sc_binding__exists_p(:impl_contract_name,:impl_name) openacs-5.7.0/packages/acs-service-contract/tcl/contract-procs.tcl0000644000175000017500000002132510551254375025031 0ustar frankiefrankiead_library { Support library for acs service contracts. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-01-14 @cvs-id $Id: contract-procs.tcl,v 1.5 2007/01/10 21:22:05 gustafn Exp $ } namespace eval acs_sc::contract {} namespace eval acs_sc::contract::operation {} ##### # # Contract # ##### ad_proc -public acs_sc::contract::new { {-name:required} {-description:required} } { Procedure to call to define and new service contract and the message types, implementations and bindings. Refer to the Service contract Tcl API discussion at http://openacs.org/forums/message-view?message_id=71799 @param name Name of the service contract @param description Comment/description of the service contract @return id of the contract } { return [db_exec_plsql insert_sc_contract {}] } ad_proc -public acs_sc::contract::new_from_spec { {-spec:required} } { Takes a complete service contract specification and creates the new service contract.

The spec looks like this:

    set spec {
        name "Action_SideEffect"
        description "Get the name of the side effect to create action"
        operations {
            GetObjectTypes {
                description "Get the object types for which this implementation is valid."
                output { object_types:string,multiple }
                iscachable_p "t"
            }
            GetPrettyName { 
                description "Get the pretty name of this implementation."
                output { pretty_name:string }
                iscachable_p "t"
            }
            DoSideEffect {
                description "Do the side effect"
                input {
                    case_id:integer
                    object_id:integer
                    action_id:integer
                    entry_id:integer
                }
            }
        } 
    }  
    
    acs_sc::contract::new_from_spec -spec $spec
    
Here's the detailed explanation:

The spec should be an array-list with 3 entries:

  • name: The name of the service contract.
  • description: A human-readable descirption.
  • operations: An array-list of operations in this service contract.
The operations array-list has the operation name as key, and another array-list containing the specification for the operation as the value. That array-list has the following entries:
  • description: Human-readable description of the operation.
  • input: Specification of the input to this operation.
  • output: Specification of the output of this operation.
  • iscachable_p: A 't' or 'f' for whether output from this service contract implementation should automatically be cached using util_memoize.

The format of the 'input' and 'output' specs is a Tcl list of parameter specs, each of which consist of name, colon (:), datatype plus an optional comma (,) and the flag 'multiple'. @param spec The service contract specification as described above. @return The contract_id of the newly created service contract. @see util_memoize @see acs_sc::invoke } { # Default values array set contract { description "" } # Get the spec array set contract $spec db_transaction { set contract_id [new \ -name $contract(name) \ -description $contract(description)] acs_sc::contract::operation::parse_operations_spec \ -name $contract(name) \ -spec $contract(operations) } return $contract_id } ad_proc -public acs_sc::contract::delete { {-contract_id} {-name} {-no_cascade:boolean} } { Delete a service contract definition. Supply either contract_id or name. @param contract_id The ID of the service contract to delete @param name Name of the service contract to delete } { if { ![exists_and_not_null contract_id] && ![exists_and_not_null name] } { error "You must supply either name or contract_id" } db_transaction { # Need both name and ID below if { ![exists_and_not_null name] } { set name [db_string get_name_by_id {}] } elseif { ![exists_and_not_null contract_id] } { set contract_id [db_string get_id_by_name {}] } if { !$no_cascade_p } { set operations [list] set msg_types [list] db_foreach select_operations {} { # Put them on list of mesage types and operations to delete lappend msg_types $operation_inputtype_id lappend msg_types $operation_outputtype_id lappend operations $operation_id } # Delete the operations foreach operation_id $operations { acs_sc::contract::operation::delete -operation_id $operation_id } # Delete msg types foreach msg_type_id $msg_types { if { $msg_type_id ne "" } { acs_sc::msg_type::delete -msg_type_id $msg_type_id } } } # LARS: # It seems like delete by ID doesn't work, because our PG bind thing turns all integers into strings # by wrapping them in single quotes, causing PG to invoke the function for deleting by name db_exec_plsql delete_by_name {} } } ad_proc -public acs_sc::contract::get_operations { {-contract_name:required} } { Get a list of names of operations for the contract. } { return [db_list select_operations { select o.operation_name from acs_sc_operations o, acs_sc_contracts c where c.contract_name = :contract_name and o.contract_id = c.contract_id }] } ##### # # Operations # ##### ad_proc -public acs_sc::contract::operation::new { {-contract_name:required} {-operation:required} {-input:required} {-output:required} {-description:required} {-is_cachable_p ""} } { Call the service contract function to create the operation in the database. } { db_transaction { # Create the input type set input_type_name "${contract_name}.${operation}.InputType" set nargs [acs_sc::msg_type::parse_spec \ -name $input_type_name \ -spec $input] # Create the output type set output_type_name "${contract_name}.${operation}.OutputType" acs_sc::msg_type::parse_spec \ -name $output_type_name \ -spec $output # Create the operation db_exec_plsql insert_operation {} } } ad_proc -public acs_sc::contract::operation::delete { {-operation_id} {-contract_name} {-operation_name} } { Delete a message type. Supply either ID or name. @param msg_type_id The ID of the msg_type to delete. @param name Name of the service contract to delete } { if { ![exists_and_not_null operation_id] && ( ![exists_and_not_null contract_name] || ![exists_and_not_null operation_name] ) } { error "You must supply either contract_name and operation_name, or operation_id" } # LARS: # It seems like delete by ID doesn't work, because our PG bind thing turns all integers into strings # by wrapping them in single quotes, causing PG to invoke the function for deleting by name if { ![exists_and_not_null contract_name] || ![exists_and_not_null operation_name] } { # get contract_name and operation_name db_1row select_names {} } db_exec_plsql delete_by_name {} } ad_proc -public acs_sc::contract::operation::parse_operations_spec { {-name:required} {-spec:required} } { Parse the operations defined in the operations specification @param name Name of the contract @spec spec Specification of all the operations } { foreach { operation subspec } $spec { acs_sc::contract::operation::parse_spec \ -contract_name $name \ -operation $operation \ -spec $subspec } } ad_proc -public acs_sc::contract::operation::parse_spec { {-contract_name:required} {-operation:required} {-spec:required} } { Parse one operation } { # Default values array set attributes { description {} input {} output {} is_cachable_p "f" } # Get the sepc array set attributes $spec # New operation acs_sc::contract::operation::new \ -contract_name $contract_name \ -operation $operation \ -description $attributes(description) \ -input $attributes(input) \ -output $attributes(output) \ -is_cachable_p $attributes(is_cachable_p) } openacs-5.7.0/packages/acs-service-contract/tcl/implementation-procs-oracle.xql0000644000175000017500000000270107736271233027526 0ustar frankiefrankie oracle8.1.6 begin :1 := acs_sc_impl.new( :contract_name, :name, :pretty_name, :owner ); end; begin :1 := acs_sc_impl_alias.new( :contract_name, :impl_name, :operation, :alias, :language ); end; begin acs_sc_binding.new( contract_name => :contract_name, impl_name => :impl_name ); end; begin acs_sc_impl.del( impl_contract_name => :contract_name, impl_name => :impl_name ); end; openacs-5.7.0/packages/acs-service-contract/tcl/implementation-procs.tcl0000644000175000017500000002441310551254375026242 0ustar frankiefrankiead_library { Support library for acs service contracts. Implements the acs_sc::impl namespace. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-01-14 @cvs-id $Id: implementation-procs.tcl,v 1.13 2007/01/10 21:22:05 gustafn Exp $ } namespace eval acs_sc::impl {} namespace eval acs_sc::impl::alias {} namespace eval acs_sc::impl::binding {} ##### # # Implementations # ##### ad_proc -public acs_sc::impl::new { {-contract_name:required} {-name:required} {-pretty_name ""} {-owner:required} } { Add new service contract implementation. @param name The internal name of the implementation. Referred to when invoking the implementation. Alphanumeric characters and underscores only. @param pretty_name The name of the implementation when display to users. Defaults to 'name'. @return the ID of the new implementation } { if { $pretty_name eq "" } { set pretty_name $name } return [db_exec_plsql impl_new {}] } ad_proc -public acs_sc::impl::delete { {-contract_name:required} {-impl_name:required} } { Delete a service contract implementation } { if { ![exists_and_not_null contract_name] || ![exists_and_not_null impl_name] } { error "You must supply contract_name and impl_name" } db_exec_plsql delete_impl {} } ad_proc -public acs_sc::impl::new_from_spec { {-spec:required} } { Add new service contract implementation from an array-list style implementation, and binds it to the specified contract.

The specification takes the following form:

    set spec {
        contract_name "Action_SideEffect"
        owner "bug-tracker"
        name "CaptureResolutionCode"
        pretty_name "Capture Resolution Code"
        aliases {
            GetObjectType bug_tracker::bug::object_type
            GetPrettyName bug_tracker::bug::capture_resolution_code::pretty_name
            DoSideEffect  bug_tracker::bug::capture_resolution_code::do_side_effect
        }
    }
    acs_sc::impl::new_from_spec -spec $spec
    
And here's the explanation:

The spec is an array-list with the following entries:

  • contract_name: The name of the service contract you're implementing.
  • owner: Owner of the implementation, use the package-key.
  • name: Name of your implementation.
  • name: Pretty name of your implementation. You'd typically use this when displaying the service contract implementation through a UI.
  • aliases: Specification of the tcl procedures for each of the service contract's operations.
The aliases section is itself an array-list. The keys are the operation names from the service contract. The values are the names of Tcl procedures in your package, which implement these operations. @param spec The specification for the new service contract implementation. @return the impl_id of the newly registered implementation } { # Spec contains: contract_name, name, pretty_name, owner, aliases array set impl $spec if { ![exists_and_not_null impl(pretty_name)] } { set impl(pretty_name) "" } db_transaction { set impl_id [new \ -contract_name $impl(contract_name) \ -name $impl(name) \ -pretty_name $impl(pretty_name) \ -owner $impl(owner)] acs_sc::impl::alias::parse_aliases_spec \ -contract_name $impl(contract_name) \ -impl_name $impl(name) \ -spec $impl(aliases) acs_sc::impl::binding::new \ -contract_name $impl(contract_name) \ -impl_name $impl(name) } # Initialize the procs so we can start calling them right away acs_sc::impl::binding::init_procs -impl_id $impl_id return $impl_id } ad_proc -public acs_sc::impl::get_id { {-owner:required} {-name:required} -contract } { Retrieves the ID for a service contract. If the contract is specified then the ID is retrieved for the specified contract, otherwise all service contract IDs will be retrieved that match the specified owner and implementation name. @param owner Owner of the service contract. @param name Implementation name. @param contract Implementation contract name. @return Returns the ID for a specified service contract, or all IDs for for service contracts that match the owner and implementation name of a service contract, if the contract is not specified. } { if {[exists_and_not_null contract]} { return [db_string select_impl_id_with_contract {}] } else { return [db_string select_impl_id {}] } } ad_proc -public acs_sc::impl::get { {-impl_id:required} {-array:required} } { Get information about a service contract implementation. @param array Name of an array into which you want the info. Available columns are: impl_name, impl_owner_name, impl_contract_name. @author Lars Pind (lars@collaboraid.biz) } { upvar 1 $array row db_1row select_impl {} -column_array row } ad_proc -public acs_sc::impl::get_options { {-contract_name:required} {-exclude_names ""} {-empty_label "-"} } { Get a list of service contract implementation options for an HTML multiple choice widget. @param contract_name The name of the service contract to return options for. @param exclude_names A list of implementation names to exclude @param empty_label If provided an option with id empty string and the provided label will be added. @return A list of lists with the inner lists having label in first element and id in second. @author Peter Marklund } { set full_list [db_list_of_lists select_impl_options { select case when impl_pretty_name is not null then impl_pretty_name else impl_name end as impl_name, impl_id from acs_sc_impls where impl_contract_name = :contract_name }] set impl_list [list] if { $empty_label ne "" } { lappend impl_list [list $empty_label ""] } if { [llength $exclude_names] > 0 } { # There are exclude names foreach element $full_list { set impl_name [lindex $element 0] if { [lsearch -exact $exclude_names $impl_name] == -1 } { # Name is not in exclude list so add option lappend impl_list $element } } } else { # No exclude names, use all options set impl_list [concat $impl_list $full_list] } return $impl_list } ##### # # Aliases # ##### ad_proc -public acs_sc::impl::alias::new { {-contract_name:required} {-impl_name:required} {-operation:required} {-alias:required} {-language "TCL"} } { Add new service contract implementation alias (the procedure that implements the operation in a contract). @return the ID of the implementation } { set impl_id [db_exec_plsql alias_new {}] } ad_proc -private acs_sc::impl::alias::parse_aliases_spec { {-contract_name:required} {-impl_name:required} {-spec:required} } { Parse multiple aliases. } { foreach { operation subspec } $spec { parse_spec \ -contract_name $contract_name \ -impl_name $impl_name \ -operation $operation \ -spec $subspec } } ad_proc -private acs_sc::impl::alias::parse_spec { {-contract_name:required} {-impl_name:required} {-operation:required} {-spec:required} } { Parse the spec for a single alias. The spec can either be just the name of a Tcl procedure, or it can be an array list containing the two keys 'alias' and 'language'. } { if { [llength $spec] == 1 } { # Single-element spec, which means it's the name of a Tcl procedure new \ -contract_name $contract_name \ -impl_name $impl_name \ -operation $operation \ -alias $spec } else { # It's a full spec, expect 'alias' and 'language' array set alias $spec new \ -contract_name $contract_name \ -impl_name $impl_name \ -operation $operation \ -alias $alias(alias) \ -language $alias(language) } } ##### # # Bindings # ##### ad_proc -public acs_sc::impl::binding::new { {-contract_name:required} {-impl_name:required} } { Bind implementation to the contract. Bombs if not all operations have aliases. } { db_exec_plsql binding_new {} } ad_proc -private acs_sc::impl::binding::init_procs { {-impl_id:required} } { Initialize the procs so we can call the service contract. Note that this proc doesn't really work, because it doesn't initialize the aliases in all interpreters, only in one. } { # LARS: # This is a hack to get around the problem with multiple interpreters: # We ask the APM to reload the acs-service-contract-init file, which will # redefine the service contract wrapper procs set file "/packages/acs-service-contract/tcl/acs-service-contract-init.tcl" apm_mark_files_for_reload -force_reload [list $file] return #---------------------------------------------------------------------- # NOTE: End of actual proc above this line. Stale code below #---------------------------------------------------------------------- # LARS: # This is the left-over stuff, which we could one day resurrect if we # decide to implement an apm_eval feature, which can eval chunks of code # in each interpreter. Then we could just say # apm_eval "acs_sc::impl::binding::init_procs_internal -impl_id $impl_id" # Get the list of aliases db_foreach impl_operation { select impl_contract_name, impl_operation_name, impl_name from acs_sc_impl_aliases where impl_id = :impl_id } -column_array row { lappend rows [array get row] } # Register them # Hm. We need to do this in all interpreters foreach row_list $rows { array set row $row_list acs_sc_proc $row(impl_contract_name) $row(impl_operation_name) $row(impl_name) } } openacs-5.7.0/packages/acs-service-contract/tcl/implementation-procs.xql0000644000175000017500000000153110207353615026253 0ustar frankiefrankie select impl_id from acs_sc_impls where impl_owner_name = :owner and impl_name = :name select impl_id from acs_sc_impls where impl_owner_name = :owner and impl_name = :name and impl_contract_name = :contract select impl_name, impl_pretty_name, impl_owner_name, impl_contract_name from acs_sc_impls where impl_id = :impl_id openacs-5.7.0/packages/acs-service-contract/tcl/msg-type-procs.tcl0000644000175000017500000000645107725065641024771 0ustar frankiefrankiead_library { Support library for acs service contracts. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-01-14 @cvs-id $Id: msg-type-procs.tcl,v 1.3 2003/09/02 10:06:25 lars Exp $ } namespace eval acs_sc::msg_type {} namespace eval acs_sc::msg_type::element {} ad_proc -public acs_sc::msg_type::new { {-name:required} {-specification ""} } { @param specification Msg type specification in the format required by the SQL proc, namely 'foo:integer,bar:[string]' } { db_exec_plsql insert_msg_type {} } ad_proc -public acs_sc::msg_type::delete { {-msg_type_id} {-name} } { Delete a message type. Supply either ID or name. @param msg_type_id The ID of the msg_type to delete. @param name Name of the service contract to delete } { if { ![exists_and_not_null msg_type_id] && ![exists_and_not_null name] } { error "You must supply either name or msg_type_id" } # LARS: # It seems like delete by ID doesn't work, because our PG bind thing turns all integers into strings # by wrapping them in single quotes, causing PG to invoke the function for deleting by name if { ![exists_and_not_null name] } { # get msg_type name db_1row select_name {} } db_exec_plsql delete_by_name {} } ad_proc -public acs_sc::msg_type::parse_spec { {-name:required} {-spec:required} } { #The specification for the message type could be like this! #case_id:integer #foobar:string,multiple @param name Name of new msg_type @param spec Spec in ad_page_contract style format, namely { foo:integer bar:string,multiple } } { db_transaction { # First, create the msg_type acs_sc::msg_type::new -name $name set nargs 0 # Then create the elements foreach element $spec { incr nargs # element:flag,flag set elementv [split $element :] set flagsv [split [lindex $elementv 1] ","] set element_name [string trim [lindex $elementv 0]] if { [llength $flagsv] > 1 } { set idx [lsearch $flagsv "multiple"] if { [llength $flagsv] > 2 || $idx == -1 } { error "Only one modified flag allowed, and that's multiple as in foo:integer,multiple" } # Remove the 'multiple' flag set flagsv [lreplace $flagsv $idx $idx] set element_type "[lindex $flagsv 0]" set isset_p "t" } else { set element_type [lindex $flagsv 0] set isset_p "f" } acs_sc::msg_type::element::new \ -msg_type_name $name \ -element_name $element_name \ -element_msg_type_name $element_type \ -element_msg_type_isset_p $isset_p \ -element_pos $nargs } } return $nargs } ##### # # Msg_type Element # ##### ad_proc -public acs_sc::msg_type::element::new { {-msg_type_name:required} {-element_name:required} {-element_msg_type_name:required} {-element_msg_type_isset_p:required} {-element_pos:required} } { Insert a new msg_type element } { db_exec_plsql insert_msg_type_element {} } openacs-5.7.0/packages/acs-service-contract/tcl/msg-type-procs.xql0000644000175000017500000000041407626704225025002 0ustar frankiefrankie select msg_type_name as name from acs_sc_msg_types where msg_type_id = :msg_type_id openacs-5.7.0/packages/acs-service-contract/tcl/acs-service-contract-procs.tcl0000644000175000017500000001704711463110545027232 0ustar frankiefrankiead_library { Support library for acs service contracts. @author Neophytos Demetriou @creation-date 2001-09-01 @cvs-id $Id: acs-service-contract-procs.tcl,v 1.24 2010/10/30 21:43:01 gustafn Exp $ } namespace eval acs_sc {} ##### # # Invoke # ##### ad_proc -public acs_sc::invoke { {-contract ""} {-operation:required} {-impl ""} {-impl_id ""} {-call_args {}} {-error:boolean} } { A wrapper for the acs_sc_call procedure, with explicitly named parameters so it's easier to figure out how to use it. You must supply either contract and impl, or just impl_id. If you supply impl_id and contract, we throw an error if the impl_id's contract doesn't match the contract you passed in. If you supply both impl_id and impl, we throw an error. @param contract_name The name of the contract you wish to use. @param operation_name The name of the operation in the contract you wish to call. @param impl The name of the implementation you wish to use. @param impl_id The ID of the implementation you wish to use. @param args The arguments you want to pass to the proc. @param error If specified, will throw an error if the operation isn't implemented. @author Lars Pind (lars@collaboraid.biz) @see acs_sc_call } { if { [exists_and_not_null impl_id] } { if { [exists_and_not_null impl] } { error "Cannot supply both impl and impl_id" } acs_sc::impl::get -impl_id $impl_id -array impl_info set impl $impl_info(impl_name) if { $contract ne "" && $contract ne $impl_info(impl_contract_name) } { error "The contract of implementation with id $impl_id does not match contract passed in. Expected contract to be '$contract', but contract of impl_id was '$impl_info(impl_contract_name)'" } set contract $impl_info(impl_contract_name) } if { ![exists_and_not_null impl] || ![exists_and_not_null contract] } { error "You must supply either impl_id, or contract and impl to acs_sc::invoke" } return [acs_sc_call -error=$error_p $contract $operation $call_args $impl] } ##### # # All the rest that used to be there # ##### ad_proc -public acs_sc_binding_exists_p { contract impl } { Returns a boolean depending on whether or not the binding between the contract and implementation exists. @param contract the contract name @param impl the implementation name @return 0 or 1 @author Neophytos Demetriou } { return [db_string binding_exists_p {*SQL*}] } ad_proc -private acs_sc_generate_name { contract impl operation } { generate the internal proc name. @author Neophytos Demetriou } { return "AcsSc.[util_text_to_url -no_resolve -replacement "_" -text $contract].[util_text_to_url -no_resolve -replacement "_" -text $operation].[util_text_to_url -no_resolve -replacement "_" -text $impl]" } ad_proc -private acs_sc_get_alias { contract operation impl } { Returns the implementation alias (the proc defined to handle a given operation for a given implementation). @author Neophytos Demetriou } { # LARS set exists_p [acs_sc_binding_exists_p $contract $impl] #set exists_p [util_memoize "acs_sc_binding_exists_p $contract $impl"] if {![set exists_p]} {return ""} db_0or1row get_alias {*SQL*} return [list $impl_alias $impl_pl] } ad_proc -private acs_sc_proc { contract operation impl {impl_alias {}} {impl_pl {}} } { Builds the proc used by acs_sc_call, generally only called in acs-service-contract-init.tcl at startup. @return 0 on failure, 1 on success. @author Neophytos Demetriou } { set arguments [list] set docblock {} set proc_name [acs_sc_generate_name $contract $impl $operation] acs_sc_log SCDebug "ACS_SC_PROC: proc_name = $proc_name" if { $impl_alias eq "" } { foreach {impl_alias impl_pl} [acs_sc_get_alias $contract $operation $impl] break } if { $impl_alias eq "" } { error "ACS-SC: Cannot find alias for $proc_name" } if {![db_0or1row get_operation_definition {*SQL*}]} { ns_log warning "ACS-SC: operation definition not found for contract $contract operation $operation" return 0 } append docblock "\nacs-service-contract operation. Call via acs_sc_call.\n\n$operation_desc\n\n" db_foreach operation_inputtype_element {*SQL*} { lappend arguments "$element_name" append docblock "\n@param $element_name $element_msg_type_name" if { $element_msg_type_isset_p } { append docblock " \[\]" } } db_foreach operation_outputtype_element {*SQL*} { append docblock "\n@return $element_name - $element_msg_type_name" if { $element_msg_type_isset_p } { append docblock " \[\]" } } append docblock "\n@see $impl_alias\n@see acs_sc_call" set full_statement [acs_sc_get_statement $impl_alias $impl_pl $arguments] if { $operation_iscachable_p } { set full_statement "util_memoize \"$full_statement\"" } #FIX ME: CALL BY NAME USING UPVAR set body "return \[$full_statement\]" set arguments [join $arguments] acs_sc_log SCDebug "ACS-SC: ad_proc $proc_name $arguments\n$docblock\n$body\n" ad_proc -private $proc_name $arguments $docblock $body return 1 } ad_proc -private acs_sc_get_statement { impl_alias impl_pl arguments } { Builds the statement to call from the provided metadata. @param impl_alias tcl or plpgsql proc to call @param impl_pl programmimg language of the proc to call (TCL or PLPGSQL) @param arguments list of argument names @author Neophytos Demetriou } { switch $impl_pl { TCL { set full_statement [list $impl_alias] for {set __i 0} {$__i < [llength $arguments]} {incr __i} { lappend full_statement "\$[lindex $arguments $__i]" } set full_statement [join $full_statement] } PLPGSQL { set args_list [list] for {set __i 0} {$__i < [llength $arguments]} {incr __i} { lappend args_list "\$[lindex $arguments $__i]" } set args_final [join $args_list ,] set full_statement "db_exec_plsql full_statement \"select ${impl_alias}(${args_final})\"" } default { error "ACS-SC: Unknown impl_pl: $impl_pl" } } return $full_statement } ad_proc -private -deprecated acs_sc_call { {-error:boolean} contract operation {arguments ""} {impl ""} } { Additional documentation and commentary at http://openacs.org/forums/message-view?message_id=108614. @param contract the contract name @param operation the method to invoke @param arguments list of arguments to pass to the method @param impl the implementation name. @param error If specified, will throw an error if the operation isn't implemented. @author Neophytos Demetriou @see acs_sc::invoke } { set proc_name [acs_sc_generate_name $contract $impl $operation] if { [llength [info procs $proc_name]] == 1 } { return [ad_apply $proc_name $arguments] } else { if { $error_p } { error "Operation $operation is not implemented in '$impl' implementation of contract '$contract'" } else { ns_log warning "ACS-SC: Function Not Found: $proc_name [info procs $proc_name]" } return } } ## ## Logging ## # Private logging proc proc acs_sc_log {level msg} { # If you want to debug the SC, uncomment the Debug log below if { "SCDebug" ne $level } { ns_log $level "$msg" } else { # ns_log Debug "$msg" } } openacs-5.7.0/packages/acs-service-contract/tcl/contract-procs-oracle.xql0000644000175000017500000000424607736271233026324 0ustar frankiefrankie oracle8.1.6 begin :1 := acs_sc_contract.new( :name, :description ); end; acs_sc_contract.get_name( :contract_id ) from dual select acs_sc_contract.get_id( :name ) from dual select operation_id, operation_inputtype_id, operation_outputtype_id from acs_sc_operations where contract_id = :contract_id begin acs_sc_contract.del( contract_name => :name ); end; begin :1 := acs_sc_operation.new( :contract_name, :operation, :description, :is_cachable_p, :nargs, :input_type_name, :output_type_name ); end; select contract_name, operation_name from acs_sc_operations where operation_id = :operation_id begin acs_sc_operation.del( contract_name => :contract_name, operation_name => :operation_name ); end; openacs-5.7.0/packages/acs-service-contract/sql/0000755000175000017500000000000011724401447021373 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/sql/oracle/0000755000175000017500000000000011724401447022640 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-object-types-create.sql0000644000175000017500000000150410475607372030410 0ustar frankiefrankie-- $Id: acs-sc-object-types-create.sql,v 1.2 2006/08/31 16:31:54 emmar Exp $ begin acs_object_type.create_type( object_type => 'acs_sc_contract', pretty_name => 'ACS SC Contract', pretty_plural => 'ACS SC Contracts', supertype => 'acs_object', table_name => 'acs_sc_contracts', id_column => 'contract_id' ); acs_object_type.create_type( object_type => 'acs_sc_operation', pretty_name => 'ACS SC Operation', pretty_plural => 'ACS SC Operations', supertype => 'acs_object', table_name => 'acs_sc_operations', id_column => 'operation_id' ); acs_object_type.create_type( object_type => 'acs_sc_implementation', pretty_name => 'ACS SC Implementation', pretty_plural => 'ACS SC Implementations', supertype => 'acs_object', table_name => 'acs_sc_impls', id_column => 'impl_id' ); end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-tables-create.sql0000644000175000017500000000535210506242162027242 0ustar frankiefrankie-- $Id: acs-sc-tables-create.sql,v 1.5 2006/09/26 15:17:06 byronl Exp $ create table acs_sc_contracts ( contract_id integer constraint acs_sc_contract_id_fk references acs_objects(object_id) on delete cascade constraint acs_sc_contract_pk primary key, contract_name varchar2(1000) constraint acs_sc_contract_name_nn not null constraint acs_sc_contract_name_un unique, contract_desc varchar2(4000) constraint acs_sc_contract_desc_nn not null ); create table acs_sc_operations ( contract_id integer constraint acs_sc_operation_cid_fk references acs_sc_contracts(contract_id) on delete cascade, operation_id integer constraint acs_sc_operation_opid_fk references acs_objects(object_id) on delete cascade constraint acs_sc_operation_pk primary key, contract_name varchar2(1000), operation_name varchar2(100), operation_desc varchar2(4000) constraint acs_sc_operation_desc_nn not null, operation_iscachable_p char(1) constraint acs_sc_operation_cache_p_ck check (operation_iscachable_p in ('t', 'f')), operation_nargs integer, operation_inputtype_id integer constraint acs_sc_operation_intype_fk references acs_sc_msg_types(msg_type_id), operation_outputtype_id integer constraint acs_sc_operation_outtype_fk references acs_sc_msg_types(msg_type_id) ); create table acs_sc_impls ( impl_id integer constraint acs_sc_impls_impl_id_fk references acs_objects(object_id) on delete cascade constraint acs_sc_impl_pk primary key, impl_name varchar2(100), impl_pretty_name varchar2(200), impl_owner_name varchar2(1000), impl_contract_name varchar2(1000) ); create table acs_sc_impl_aliases ( impl_id integer constraint acs_sc_impl_aliases_impl_id_fk references acs_sc_impls(impl_id) on delete cascade, impl_name varchar2(100), impl_contract_name varchar2(1000), impl_operation_name varchar2(100), impl_alias varchar2(100), impl_pl varchar2(100), constraint acs_sc_impl_aliases_un unique(impl_name,impl_contract_name,impl_operation_name) ); create table acs_sc_bindings ( contract_id integer constraint acs_sc_binding_contract_id_fk references acs_sc_contracts(contract_id) on delete cascade, impl_id integer constraint acs_sc_binding_impl_id_fk references acs_sc_impls(impl_id) on delete cascade ); openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-views-drop.sql0000644000175000017500000000025707352221465026635 0ustar frankiefrankie-- $Id: acs-sc-views-drop.sql,v 1.1 2001/09/19 22:59:01 donb Exp $ drop view orphan_implementation; drop view invalid_uninstalled_binding; drop view valid_uninstalled_binding;openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-object-types-drop.sql0000644000175000017500000000071607352221465030110 0ustar frankiefrankie-- $Id: acs-sc-object-types-drop.sql,v 1.1 2001/09/19 22:59:01 donb Exp $ begin delete from acs_objects where object_type ='acs_sc_implementation'; acs_object_type.drop_type('acs_sc_implementation'); delete from acs_objects where object_type ='acs_sc_operation'; acs_object_type.drop_type('acs_sc_operation'); delete from acs_objects where object_type ='acs_sc_contract'; acs_object_type.drop_type('acs_sc_contract'); end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-packages-drop.sql0000644000175000017500000000027307433225366027260 0ustar frankiefrankie-- $Id: acs-sc-packages-drop.sql,v 1.2 2002/02/15 15:36:22 donb Exp $ drop package acs_sc_contract; drop package acs_sc_operation; drop package acs_sc_impl; drop package acs_sc_binding; openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-msg-types-drop.sql0000644000175000017500000000046707352221465027433 0ustar frankiefrankie-- $Id: acs-sc-msg-types-drop.sql,v 1.1 2001/09/19 22:59:01 donb Exp $ drop package acs_sc_msg_type; drop table acs_sc_msg_type_elements; drop table acs_sc_msg_types; delete from acs_objects where object_type = 'acs_sc_msg_type'; begin acs_object_type.drop_type('acs_sc_msg_type'); end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-packages-create.sql0000644000175000017500000004353110024403025027537 0ustar frankiefrankie-- $Id: acs-sc-packages-create.sql,v 1.15 2004/03/12 18:48:53 jeffd Exp $ create or replace package acs_sc_contract as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, contract_desc in acs_sc_contracts.contract_desc%TYPE ) return acs_sc_contracts.contract_id%TYPE; function get_id ( contract_name in acs_sc_contracts.contract_name%TYPE ) return acs_sc_contracts.contract_id%TYPE; function get_name ( contract_id in acs_sc_contracts.contract_id%TYPE ) return acs_sc_contracts.contract_name%TYPE; procedure del ( contract_name in acs_sc_contracts.contract_name%TYPE default null, contract_id in acs_sc_contracts.contract_id%TYPE default null ); end acs_sc_contract; / show errors create or replace package acs_sc_operation as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, operation_name in acs_sc_operations.operation_name%TYPE, operation_desc in acs_sc_operations.operation_desc%TYPE, operation_iscachable_p in acs_sc_operations.operation_iscachable_p%TYPE, operation_nargs in acs_sc_operations.operation_nargs%TYPE, operation_inputtype in acs_sc_msg_types.msg_type_name%TYPE, operation_outputtype in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_operations.operation_id%TYPE; function get_id ( contract_name acs_sc_contracts.contract_name%TYPE, operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_operations.operation_id%TYPE; procedure del ( operation_id acs_sc_operations.operation_id%TYPE default null, operation_name acs_sc_operations.operation_name%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null ); end acs_sc_operation; / show errors create or replace package acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE; procedure del ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ); /* Next 2 functions are deprecated but left here for backwards compatability */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE; -- fix by Ben from delete_aliases to delete_alias function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE; end acs_sc_impl; / show error create or replace package acs_sc_impl_alias as function new ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE; function del ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE; end acs_sc_impl_alias; / show error create or replace package acs_sc_binding as procedure new ( contract_id acs_sc_operations.contract_id%TYPE default null, impl_id acs_sc_bindings.impl_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ); procedure del ( contract_id acs_sc_contracts.contract_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_id acs_sc_impls.impl_id%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ); function exists_p ( contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return integer; end acs_sc_binding; / show errors create or replace package body acs_sc_contract as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, contract_desc in acs_sc_contracts.contract_desc%TYPE ) return acs_sc_contracts.contract_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; begin v_contract_id := acs_object.new( object_type => 'acs_sc_contract', title => contract_name ); insert into acs_sc_contracts ( contract_id, contract_name, contract_desc ) values ( v_contract_id, contract_name, contract_desc ); return v_contract_id; end new; function get_id ( contract_name in acs_sc_contracts.contract_name%TYPE ) return acs_sc_contracts.contract_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; begin select contract_id into v_contract_id from acs_sc_contracts where contract_name = get_id.contract_name; return v_contract_id; end get_id; function get_name ( contract_id in acs_sc_contracts.contract_id%TYPE ) return acs_sc_contracts.contract_name%TYPE is v_contract_name acs_sc_contracts.contract_name%TYPE; begin select contract_name into v_contract_name from acs_sc_contracts where contract_id = get_name.contract_id; return v_contract_name; end get_name; procedure del ( contract_name in acs_sc_contracts.contract_name%TYPE default null, contract_id in acs_sc_contracts.contract_id%TYPE default null ) is v_contract_id acs_sc_contracts.contract_id%TYPE; begin if contract_name is not NULL then v_contract_id := acs_sc_contract.get_id(contract_name); elsif contract_id is not NULL then v_contract_id := contract_id; else raise_application_error(-20001, 'Service Contracts: no valid args supplied to delete'); end if; delete from acs_sc_contracts where contract_id = v_contract_id; acs_object.del(v_contract_id); end del; end acs_sc_contract; / show errors create or replace package body acs_sc_operation as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, operation_name in acs_sc_operations.operation_name%TYPE, operation_desc in acs_sc_operations.operation_desc%TYPE, operation_iscachable_p in acs_sc_operations.operation_iscachable_p%TYPE, operation_nargs in acs_sc_operations.operation_nargs%TYPE, operation_inputtype in acs_sc_msg_types.msg_type_name%TYPE, operation_outputtype in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_operations.operation_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; v_operation_id acs_sc_operations.operation_id%TYPE; v_operation_inputtype_id acs_sc_operations.operation_inputtype_id%TYPE; v_operation_outputtype_id acs_sc_operations.operation_outputtype_id%TYPE; begin v_contract_id := acs_sc_contract.get_id(contract_name); v_operation_id := acs_object.new ( object_type => 'acs_sc_operation', title => operation_name ); v_operation_inputtype_id := acs_sc_msg_type.get_id(operation_inputtype); v_operation_outputtype_id := acs_sc_msg_type.get_id(operation_outputtype); insert into acs_sc_operations ( contract_id, operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id ) values ( v_contract_id, v_operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, v_operation_inputtype_id, v_operation_outputtype_id ); return v_operation_id; end new; function get_id ( contract_name acs_sc_contracts.contract_name%TYPE, operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_operations.operation_id%TYPE as v_operation_id acs_sc_operations.operation_id%TYPE; begin select operation_id into v_operation_id from acs_sc_operations where contract_name = get_id.contract_name and operation_name = get_id.operation_name; return v_operation_id; end get_id; procedure del ( operation_id acs_sc_operations.operation_id%TYPE default null, operation_name acs_sc_operations.operation_name%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null ) is v_operation_id acs_sc_operations.operation_id%TYPE; begin if (operation_id is NULL and operation_name is not NULL and contract_name is not NULL) then v_operation_id := get_id(contract_name, operation_name); elsif operation_id is not NULL then v_operation_id := operation_id; else raise_application_error(-20001, 'ACS Contracts: Invalid args to operation delete'); end if; delete from acs_sc_operations where operation_id = v_operation_id; end del; end acs_sc_operation; / show errors create or replace package body acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_object.new ( object_type => 'acs_sc_implementation', title => impl_pretty_name ); insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ); return v_impl_id; end new; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE as v_impl_id acs_sc_impls.impl_id%TYPE; begin select impl_id into v_impl_id from acs_sc_impls where impl_name = get_id.impl_name and impl_contract_name = get_id.impl_contract_name; return v_impl_id; end get_id; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE as v_impl_name acs_sc_impls.impl_name%TYPE; begin select impl_name into v_impl_name from acs_sc_impls where impl_id = get_name.impl_id; return v_impl_name; end get_name; procedure del ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) as begin delete from acs_sc_impls where impl_contract_name = acs_sc_impl.del.impl_contract_name and impl_name = acs_sc_impl.del.impl_name; end del; /* next 2 functions are deprecated. */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.new dbms_output.put_line('acs_sc_impl.new_alias DEPRECATED. Use acs_sc_impl_alias.new'); v_impl_id := acs_sc_impl_alias.new( impl_contract_name, impl_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new_alias; function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.delete dbms_output.put_line('acs_sc_impl.delete_alias DEPRECATED. Use acs_sc_impl_alias.delete'); v_impl_id := acs_sc_impl_alias.del( impl_contract_name, impl_name, impl_operation_name ); return v_impl_id; end delete_alias; end acs_sc_impl; / show errors create or replace package body acs_sc_impl_alias as function new ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_sc_impl.get_id(impl_contract_name,impl_name); insert into acs_sc_impl_aliases ( impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ) values ( v_impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new; function del ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_sc_impl.get_id(impl_contract_name,impl_name); delete from acs_sc_impl_aliases where impl_contract_name = acs_sc_impl_alias.del.impl_contract_name and impl_name = acs_sc_impl_alias.del.impl_name and impl_operation_name = acs_sc_impl_alias.del.impl_operation_name; return v_impl_id; end del; end acs_sc_impl_alias; / show errors create or replace package body acs_sc_binding as -- you can pick a pair of args, either ids or names to pass in. procedure new ( contract_id acs_sc_operations.contract_id%TYPE default null, impl_id acs_sc_bindings.impl_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ) is v_contract_name acs_sc_contracts.contract_name%TYPE; v_contract_id acs_sc_contracts.contract_id%TYPE; v_impl_name acs_sc_impls.impl_name%TYPE; v_impl_id acs_sc_impls.impl_id%TYPE; v_count integer; begin if impl_id is not null and contract_id is not null then v_contract_name := acs_sc_contract.get_name(contract_id); v_impl_name := acs_sc_impl.get_name(impl_id); v_contract_id := contract_id; v_impl_id := impl_id; elsif contract_name is not null and impl_name is not null then v_contract_id := acs_sc_contract.get_id(contract_name); v_impl_id := acs_sc_impl.get_id(contract_name,impl_name); v_impl_name := impl_name; v_contract_name := contract_name; else raise_application_error(-20001, 'Service Contracts:Invalid args to binding new'); end if; select count(*) into v_count from acs_sc_operations where contract_id = new.contract_id and operation_name not in (select impl_operation_name from acs_sc_impl_aliases where impl_contract_name = v_contract_name and impl_id = v_impl_id); if v_count > 0 then raise_application_error(-20001, 'Binding of ' || v_contract_name || ' to ' || v_impl_name || ' failed since certain operations are not implemented.'); end if; insert into acs_sc_bindings ( contract_id, impl_id ) values ( v_contract_id, v_impl_id ); end new; procedure del ( contract_id acs_sc_contracts.contract_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_id acs_sc_impls.impl_id%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ) is v_contract_id acs_sc_contracts.contract_id%TYPE; v_impl_id acs_sc_impls.impl_id%TYPE; begin if impl_id is not null and contract_id is not null then v_impl_id := impl_id; v_contract_id := contract_id; elsif impl_name is not null and contract_name is not null then v_impl_id := acs_sc_impl.get_id(contract_name,impl_name); v_contract_id := acs_sc_contract.get_id(contract_name); else raise_application_error(-20001, 'Service contract binding delete invalid args'); end if; delete from acs_sc_bindings where contract_id = v_contract_id and impl_id = v_impl_id; end del; function exists_p ( contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return integer is v_exists_p integer; begin select decode(count(*),0, 0, 1) into v_exists_p from acs_sc_bindings where contract_id = acs_sc_contract.get_id(contract_name) and impl_id = acs_sc_impl.get_id(contract_name,impl_name); return v_exists_p; end exists_p; end acs_sc_binding; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-tables-drop.sql0000644000175000017500000000022007364610402026734 0ustar frankiefrankiedrop table acs_sc_bindings; drop table acs_sc_impl_aliases; drop table acs_sc_impls; drop table acs_sc_operations; drop table acs_sc_contracts; openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-views-create.sql0000644000175000017500000000344407731545006027136 0ustar frankiefrankie-- $Id: acs-sc-views-create.sql,v 1.4 2003/09/16 08:29:58 lars Exp $ create or replace view valid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); create or replace view invalid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); create or replace view orphan_implementations as select i.impl_id, i.impl_name, i.impl_contract_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_impls i where not exists (select 1 from acs_sc_bindings b where b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_contracts c where c.contract_name = i.impl_contract_name); openacs-5.7.0/packages/acs-service-contract/sql/oracle/upgrade/0000755000175000017500000000000011575225533024273 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.7d3-5.0d1.sql0000644000175000017500000006176207741041152027732 0ustar frankiefrankie-- $Id: upgrade-4.7d3-5.0d1.sql,v 1.1 2003/10/08 16:59:22 mohanp Exp $ create or replace package acs_sc_msg_type as function new ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return acs_sc_msg_types.msg_type_id%TYPE; procedure del ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE default null, msg_type_name in acs_sc_msg_types.msg_type_name%TYPE default null ); function get_id ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE; function get_name ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE ) return acs_sc_msg_types.msg_type_name%TYPE; -- ask nd about name function parse_spec ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return integer; function new_element ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_name in acs_sc_msg_type_elements.element_name%TYPE, element_msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_msg_type_isset_p in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE, element_pos in acs_sc_msg_type_elements.element_pos%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE; end acs_sc_msg_type; / show errors create or replace package body acs_sc_msg_type as function new ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id integer; v_spec_parse_level integer; begin v_msg_type_id := acs_object.new( object_type => 'acs_sc_msg_type' ); insert into acs_sc_msg_types ( msg_type_id, msg_type_name ) values ( v_msg_type_id, msg_type_name ); v_spec_parse_level := acs_sc_msg_type.parse_spec( msg_type_name, msg_type_spec); return v_msg_type_id; end new; procedure del ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE default null, msg_type_name in acs_sc_msg_types.msg_type_name%TYPE default null ) is v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin if msg_type_name is not NULL then v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name); elsif msg_type_id is not NULL then v_msg_type_id := msg_type_id; else raise_application_error(-20000, 'no args supplied to sc_msg_type.delete'); end if; delete from acs_sc_msg_types where msg_type_id = v_msg_type_id; end del; function get_id ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin select msg_type_id into v_msg_type_id from acs_sc_msg_types where msg_type_name = get_id.msg_type_name; return v_msg_type_id; end get_id; function get_name ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE ) return acs_sc_msg_types.msg_type_name%TYPE is v_msg_type_name acs_sc_msg_types.msg_type_name%TYPE; begin select msg_type_name into v_msg_type_name from acs_sc_msg_types where msg_type_id = get_name.msg_type_id; return v_msg_type_name; end get_name; -- string processing in pl/sql is so much fun -- i'm sure there is a better way to go about this function parse_spec ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return integer is v_element_pos integer; v_str_s_idx integer; -- spec str pointers v_str_e_idx integer; v_elem_idx integer; -- element str pointer v_str_len integer; v_element varchar(200); v_element_type varchar(200); v_element_name varchar(200); v_element_msg_type_name varchar(200); v_element_msg_type_isset_p char(1); v_junk_msg_type_id integer; begin -- oracle treats empty strings as nulls if msg_type_spec is null then return 0; end if; v_element_pos := 1; v_str_e_idx := 1; while TRUE loop -- string start check if v_element_pos = 1 then v_str_s_idx := 1; else v_str_s_idx := instr(msg_type_spec, ',', v_str_e_idx); if v_str_s_idx > 0 then v_str_s_idx := v_str_s_idx + 1; end if; end if; v_str_e_idx := instr(msg_type_spec, ',', v_str_s_idx+1)-1; -- end of string check if v_str_s_idx > 0 and v_str_e_idx <= 0 then v_str_e_idx := length(msg_type_spec); end if; -- dbms_output.put_line(v_str_s_idx || ' '|| v_str_e_idx || ' ' || v_element_pos); -- dbms_output.new_line(); if v_str_s_idx > 0 then v_element := substr(msg_type_spec, v_str_s_idx, v_str_e_idx+1 - v_str_s_idx); v_elem_idx := instr(v_element, ':'); if v_elem_idx > 0 then v_element_name := trim( substr(v_element, 1, v_elem_idx-1)); v_element_type := trim( substr(v_element, v_elem_idx+1)); if (instr(v_element_type, '[',1,1) = length(v_element_type)-1) and (instr(v_element_type, ']',1,1) = length(v_element_type)) then v_element_msg_type_isset_p := 't'; v_element_msg_type_name := trim(substr( v_element_type, 1, length(v_element_type)-2)); if v_element_msg_type_name = '' then raise_application_error (-20001, 'Wrong Format: Message Type Specification'); end if; else v_element_msg_type_isset_p := 'f'; v_element_msg_type_name := v_element_type; end if; v_junk_msg_type_id := acs_sc_msg_type.new_element ( msg_type_name =>parse_spec.msg_type_name, element_name => v_element_name, element_msg_type_name => v_element_msg_type_name, element_msg_type_isset_p => v_element_msg_type_isset_p, element_pos => v_element_pos ); else raise_application_error(-20001,'Wrong Format: Message Type Specification'); end if; else -- yippee we're done exit; end if; v_element_pos := v_element_pos + 1; end loop; return v_element_pos - 1; end parse_spec; function new_element ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_name in acs_sc_msg_type_elements.element_name%TYPE, element_msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_msg_type_isset_p in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE, element_pos in acs_sc_msg_type_elements.element_pos%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id integer; v_element_msg_type_id integer; begin v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name); if v_msg_type_id is null then raise_application_error (-20001, 'Unknown Message Type: ' || msg_type_name); end if; v_element_msg_type_id := acs_sc_msg_type.get_id(element_msg_type_name); if v_element_msg_type_id is null then raise_application_error (-20001, 'Unknown Message Type: ' || element_msg_type_name); end if; insert into acs_sc_msg_type_elements ( msg_type_id, element_name, element_msg_type_id, element_msg_type_isset_p, element_pos ) values ( v_msg_type_id, element_name, v_element_msg_type_id, element_msg_type_isset_p, element_pos ); return v_msg_type_id; end new_element; end acs_sc_msg_type; / show errors create or replace package acs_sc_contract as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, contract_desc in acs_sc_contracts.contract_desc%TYPE ) return acs_sc_contracts.contract_id%TYPE; function get_id ( contract_name in acs_sc_contracts.contract_name%TYPE ) return acs_sc_contracts.contract_id%TYPE; function get_name ( contract_id in acs_sc_contracts.contract_id%TYPE ) return acs_sc_contracts.contract_name%TYPE; procedure del ( contract_name in acs_sc_contracts.contract_name%TYPE default null, contract_id in acs_sc_contracts.contract_id%TYPE default null ); end acs_sc_contract; / show errors create or replace package acs_sc_operation as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, operation_name in acs_sc_operations.operation_name%TYPE, operation_desc in acs_sc_operations.operation_desc%TYPE, operation_iscachable_p in acs_sc_operations.operation_iscachable_p%TYPE, operation_nargs in acs_sc_operations.operation_nargs%TYPE, operation_inputtype in acs_sc_msg_types.msg_type_name%TYPE, operation_outputtype in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_operations.operation_id%TYPE; function get_id ( contract_name acs_sc_contracts.contract_name%TYPE, operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_operations.operation_id%TYPE; procedure del ( operation_id acs_sc_operations.operation_id%TYPE default null, operation_name acs_sc_operations.operation_name%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null ); end acs_sc_operation; / show errors create or replace package acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE; procedure del ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ); /* Next 2 functions are deprecated but left here for backwards compatability */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE; -- fix by Ben from delete_aliases to delete_alias function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE; end acs_sc_impl; / show error create or replace package acs_sc_impl_alias as function new ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE; function del ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE; end acs_sc_impl_alias; / show error create or replace package acs_sc_binding as procedure new ( contract_id acs_sc_operations.contract_id%TYPE default null, impl_id acs_sc_bindings.impl_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ); procedure del ( contract_id acs_sc_contracts.contract_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_id acs_sc_impls.impl_id%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ); function exists_p ( contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return integer; end acs_sc_binding; / show errors create or replace package body acs_sc_contract as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, contract_desc in acs_sc_contracts.contract_desc%TYPE ) return acs_sc_contracts.contract_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; begin v_contract_id := acs_object.new( object_type=>'acs_sc_contract'); insert into acs_sc_contracts ( contract_id, contract_name, contract_desc ) values ( v_contract_id, contract_name, contract_desc ); return v_contract_id; end new; function get_id ( contract_name in acs_sc_contracts.contract_name%TYPE ) return acs_sc_contracts.contract_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; begin select contract_id into v_contract_id from acs_sc_contracts where contract_name = get_id.contract_name; return v_contract_id; end get_id; function get_name ( contract_id in acs_sc_contracts.contract_id%TYPE ) return acs_sc_contracts.contract_name%TYPE is v_contract_name acs_sc_contracts.contract_name%TYPE; begin select contract_name into v_contract_name from acs_sc_contracts where contract_id = get_name.contract_id; return v_contract_name; end get_name; procedure del ( contract_name in acs_sc_contracts.contract_name%TYPE default null, contract_id in acs_sc_contracts.contract_id%TYPE default null ) is v_contract_id acs_sc_contracts.contract_id%TYPE; begin if contract_name is not NULL then v_contract_id := acs_sc_contract.get_id(contract_name); elsif contract_id is not NULL then v_contract_id := contract_id; else raise_application_error(-20001, 'Service Contracts: no valid args supplied to delete'); end if; delete from acs_sc_contracts where contract_id = v_contract_id; acs_object.del(v_contract_id); end del; end acs_sc_contract; / show errors create or replace package body acs_sc_operation as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, operation_name in acs_sc_operations.operation_name%TYPE, operation_desc in acs_sc_operations.operation_desc%TYPE, operation_iscachable_p in acs_sc_operations.operation_iscachable_p%TYPE, operation_nargs in acs_sc_operations.operation_nargs%TYPE, operation_inputtype in acs_sc_msg_types.msg_type_name%TYPE, operation_outputtype in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_operations.operation_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; v_operation_id acs_sc_operations.operation_id%TYPE; v_operation_inputtype_id acs_sc_operations.operation_inputtype_id%TYPE; v_operation_outputtype_id acs_sc_operations.operation_outputtype_id%TYPE; begin v_contract_id := acs_sc_contract.get_id(contract_name); v_operation_id := acs_object.new (object_type=>'acs_sc_operation'); v_operation_inputtype_id := acs_sc_msg_type.get_id(operation_inputtype); v_operation_outputtype_id := acs_sc_msg_type.get_id(operation_outputtype); insert into acs_sc_operations ( contract_id, operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id ) values ( v_contract_id, v_operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, v_operation_inputtype_id, v_operation_outputtype_id ); return v_operation_id; end new; function get_id ( contract_name acs_sc_contracts.contract_name%TYPE, operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_operations.operation_id%TYPE as v_operation_id acs_sc_operations.operation_id%TYPE; begin select operation_id into v_operation_id from acs_sc_operations where contract_name = get_id.contract_name and operation_name = get_id.operation_name; return v_operation_id; end get_id; procedure del ( operation_id acs_sc_operations.operation_id%TYPE default null, operation_name acs_sc_operations.operation_name%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null ) is v_operation_id acs_sc_operations.operation_id%TYPE; begin if (operation_id is NULL and operation_name is not NULL and contract_name is not NULL) then v_operation_id := get_id(contract_name, operation_name); elsif operation_id is not NULL then v_operation_id := operation_id; else raise_application_error(-20001, 'ACS Contracts: Invalid args to operation delete'); end if; delete from acs_sc_operations where operation_id = v_operation_id; end del; end acs_sc_operation; / show errors create or replace package body acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_object.new (object_type => 'acs_sc_implementation'); insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ); return v_impl_id; end new; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE as v_impl_id acs_sc_impls.impl_id%TYPE; begin select impl_id into v_impl_id from acs_sc_impls where impl_name = get_id.impl_name and impl_contract_name = get_id.impl_contract_name; return v_impl_id; end get_id; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE as v_impl_name acs_sc_impls.impl_name%TYPE; begin select impl_name into v_impl_name from acs_sc_impls where impl_id = get_name.impl_id; return v_impl_name; end get_name; procedure del ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) as begin delete from acs_sc_impls where impl_contract_name = acs_sc_impl.del.impl_contract_name and impl_name = acs_sc_impl.del.impl_name; end del; /* next 2 functions are deprecated. */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.new dbms_output.put_line('acs_sc_impl.new_alias DEPRECATED. Use acs_sc_impl_alias.new'); v_impl_id := acs_sc_impl_alias.new( impl_contract_name, impl_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new_alias; function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.delete dbms_output.put_line('acs_sc_impl.delete_alias DEPRECATED. Use acs_sc_impl_alias.delete'); v_impl_id := acs_sc_impl_alias.del( impl_contract_name, impl_name, impl_operation_name ); return v_impl_id; end delete_alias; end acs_sc_impl; / show errors create or replace package body acs_sc_impl_alias as function new ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_sc_impl.get_id(impl_contract_name,impl_name); insert into acs_sc_impl_aliases ( impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ) values ( v_impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new; function del ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_sc_impl.get_id(impl_contract_name,impl_name); delete from acs_sc_impl_aliases where impl_contract_name = acs_sc_impl_alias.del.impl_contract_name and impl_name = acs_sc_impl_alias.del.impl_name and impl_operation_name = acs_sc_impl_alias.del.impl_operation_name; return v_impl_id; end del; end acs_sc_impl_alias; / show errors create or replace package body acs_sc_binding as -- you can pick a pair of args, either ids or names to pass in. procedure new ( contract_id acs_sc_operations.contract_id%TYPE default null, impl_id acs_sc_bindings.impl_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ) is v_contract_name acs_sc_contracts.contract_name%TYPE; v_contract_id acs_sc_contracts.contract_id%TYPE; v_impl_name acs_sc_impls.impl_name%TYPE; v_impl_id acs_sc_impls.impl_id%TYPE; v_count integer; begin if impl_id is not null and contract_id is not null then v_contract_name := acs_sc_contract.get_name(contract_id); v_impl_name := acs_sc_impl.get_name(impl_id); v_contract_id := contract_id; v_impl_id := impl_id; elsif contract_name is not null and impl_name is not null then v_contract_id := acs_sc_contract.get_id(contract_name); v_impl_id := acs_sc_impl.get_id(contract_name,impl_name); v_impl_name := impl_name; v_contract_name := contract_name; else raise_application_error(-20001, 'Service Contracts:Invalid args to binding new'); end if; select count(*) into v_count from acs_sc_operations where contract_id = new.contract_id and operation_name not in (select impl_operation_name from acs_sc_impl_aliases where impl_contract_name = v_contract_name and impl_id = v_impl_id); if v_count > 0 then raise_application_error(-20001, 'Binding of ' || v_contract_name || ' to ' || v_impl_name || ' failed since certain operations are not implemented.'); end if; insert into acs_sc_bindings ( contract_id, impl_id ) values ( v_contract_id, v_impl_id ); end new; procedure del ( contract_id acs_sc_contracts.contract_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_id acs_sc_impls.impl_id%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ) is v_contract_id acs_sc_contracts.contract_id%TYPE; v_impl_id acs_sc_impls.impl_id%TYPE; begin if impl_id is not null and contract_id is not null then v_impl_id := impl_id; v_contract_id := contract_id; elsif impl_name is not null and contract_name is not null then v_impl_id := acs_sc_impl.get_id(contract_name,impl_name); v_contract_id := acs_sc_contract.get_id(contract_name); else raise_application_error(-20001, 'Service contract binding delete invalid args'); end if; delete from acs_sc_bindings where contract_id = v_contract_id and impl_id = v_impl_id; end del; function exists_p ( contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return integer is v_exists_p integer; begin select decode(count(*),0, 0, 1) into v_exists_p from acs_sc_bindings where contract_id = acs_sc_contract.get_id(contract_name) and impl_id = acs_sc_impl.get_id(contract_name,impl_name); return v_exists_p; end exists_p; end acs_sc_binding; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.5.1-4.6.sql0000644000175000017500000000112307745303530027406 0ustar frankiefrankie-- packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.5.1-4.6.sql -- -- @author Vinod Kurup (vinod@kurup.com) -- @creation_date 2002-10-08 -- -- $Id: upgrade-4.5.1-4.6.sql,v 1.3 2003/10/21 19:22:00 tilmanns Exp $ -- UPGRADE ISSUE #1 -- add timestamp datatype declare v_count integer; v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin select count(*) into v_count from acs_sc_msg_types where msg_type_name = 'timestamp'; if v_count = 0 then v_msg_type_id := acs_sc_msg_type.new('timestamp',''); end if; end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.5-4.5.1.sql0000644000175000017500000002246607572171623027426 0ustar frankiefrankie-- packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.5-4.5.1.sql -- -- @author Vinod Kurup (vinod@kurup.com) -- @creation_date 2002-08-14 -- -- $Id: upgrade-4.5-4.5.1.sql,v 1.3 2002/11/30 17:21:23 jeffd Exp $ -- UPGRADE ISSUE 1 -- PG version has 2 packages acs_sc_impl and acs_sc_impl_alias -- For consistency, we're making it the same in Oracle -- Oracle function acs_sc_impl.new_alias -> acs_sc_impl_alias.new -- acs_sc_impl.delete_alias -> acs_sc_impl_alias.delete -- Old functions deprecated, but still work. create or replace package acs_sc_impl_alias as function new ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE; function delete ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE; end acs_sc_impl_alias; / show error -- now the new package bodies create or replace package body acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_object.new (object_type => 'acs_sc_implementation'); insert into acs_sc_impls ( impl_id, impl_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, impl_name, impl_owner_name, impl_contract_name ); return v_impl_id; end new; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE as v_impl_id acs_sc_impls.impl_id%TYPE; begin select impl_id into v_impl_id from acs_sc_impls where impl_name = get_id.impl_name and impl_contract_name = get_id.impl_contract_name; return v_impl_id; end get_id; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE as v_impl_name acs_sc_impls.impl_name%TYPE; begin select impl_name into v_impl_name from acs_sc_impls where impl_id = get_name.impl_id; return v_impl_name; end get_name; procedure delete ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) as begin delete from acs_sc_impls where impl_contract_name = acs_sc_impl.delete.impl_contract_name and impl_name = acs_sc_impl.delete.impl_name; end delete; /* next 2 functions are deprecated. */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.new dbms_output.put_line('acs_sc_impl.new_alias DEPRECATED. Use acs_sc_impl_alias.new'); v_impl_id := acs_sc_impl_alias.new( impl_contract_name, impl_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new_alias; function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.delete dbms_output.put_line('acs_sc_impl.delete_alias DEPRECATED. Use acs_sc_impl_alias.delete'); v_impl_id := acs_sc_impl_alias.delete( impl_contract_name, impl_name, impl_operation_name ); return v_impl_id; end delete_alias; end acs_sc_impl; / show errors create or replace package body acs_sc_impl_alias as function new ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_sc_impl.get_id(impl_contract_name,impl_name); insert into acs_sc_impl_aliases ( impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ) values ( v_impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new; function delete ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_sc_impl.get_id(impl_contract_name,impl_name); delete from acs_sc_impl_aliases where impl_contract_name = acs_sc_impl_alias.delete.impl_contract_name and impl_name = acs_sc_impl_alias.delete.impl_name and impl_operation_name = acs_sc_impl_alias.delete.impl_operation_name; return v_impl_id; end delete; end acs_sc_impl_alias; / show errors -- UPGRADE ISSUE 2 -- acs_sc_binding.exists_p was broken on Oracle if you -- tested a binding for which the implementation was installed, but the -- contract wasn't. create or replace package body acs_sc_binding as -- you can pick a pair of args, either ids or names to pass in. procedure new ( contract_id acs_sc_operations.contract_id%TYPE default null, impl_id acs_sc_bindings.impl_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ) is v_contract_name acs_sc_contracts.contract_name%TYPE; v_contract_id acs_sc_contracts.contract_id%TYPE; v_impl_name acs_sc_impls.impl_name%TYPE; v_impl_id acs_sc_impls.impl_id%TYPE; v_count integer; begin if impl_id is not null and contract_id is not null then v_contract_name := acs_sc_contract.get_name(contract_id); v_impl_name := acs_sc_impl.get_name(impl_id); v_contract_id := contract_id; v_impl_id := impl_id; elsif contract_name is not null and impl_name is not null then v_contract_id := acs_sc_contract.get_id(contract_name); v_impl_id := acs_sc_impl.get_id(contract_name,impl_name); v_impl_name := impl_name; v_contract_name := contract_name; else raise_application_error(-20001, 'Service Contracts:Invalid args to binding new'); end if; select count(*) into v_count from acs_sc_operations where contract_id = new.contract_id and operation_name not in (select impl_operation_name from acs_sc_impl_aliases where impl_contract_name = v_contract_name and impl_id = v_impl_id); if v_count > 0 then raise_application_error(-20001, 'Binding of ' || v_contract_name || ' to ' || v_impl_name || ' failed.'); end if; insert into acs_sc_bindings ( contract_id, impl_id ) values ( v_contract_id, v_impl_id ); end new; procedure delete( contract_id acs_sc_contracts.contract_id%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null, impl_id acs_sc_impls.impl_id%TYPE default null, impl_name acs_sc_impls.impl_name%TYPE default null ) is v_contract_id acs_sc_contracts.contract_id%TYPE; v_impl_id acs_sc_impls.impl_id%TYPE; begin if impl_id is not null and contract_id is not null then v_impl_id := impl_id; v_contract_id := contract_id; elsif impl_name is not null and contract_name is not null then v_impl_id := acs_sc_impl.get_id(contract_name,impl_name); v_contract_id := acs_sc_contract.get_id(contract_name); else raise_application_error(-20001, 'Service contract binding delete invalid args'); end if; delete from acs_sc_bindings where contract_id = v_contract_id and impl_id = v_impl_id; end delete; function exists_p ( contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return integer is v_exists_p integer; begin select decode(count(*),0, 0, 1) into v_exists_p from acs_sc_bindings where contract_id = acs_sc_contract.get_id(contract_name) and impl_id = acs_sc_impl.get_id(contract_name,impl_name); return v_exists_p; end exists_p; end acs_sc_binding; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.7d2-4.7d3.sql0000644000175000017500000001567407736526144027757 0ustar frankiefrankie-- -- @author Simon Carstensen (simon@collaboraid.biz) -- @creation_date 2003-09-10 -- -- $Id: upgrade-4.7d2-4.7d3.sql,v 1.4 2003/10/01 10:28:52 peterm Exp $ -- add column impl_pretty_name alter table acs_sc_impls add impl_pretty_name varchar2(200); update acs_sc_impls set impl_pretty_name = impl_name; create or replace package acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE; procedure delete ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ); /* Next 2 functions are deprecated but left here for backwards compatability */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE; -- fix by Ben from delete_aliases to delete_alias function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE; end acs_sc_impl; / show error create or replace package body acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; v_impl_pretty_name varchar(4000); begin v_impl_id := acs_object.new (object_type => 'acs_sc_implementation'); if impl_pretty_name is null then v_impl_pretty_name := impl_name; else v_impl_pretty_name := impl_pretty_name; end if; insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, impl_name, v_impl_pretty_name, impl_owner_name, impl_contract_name ); return v_impl_id; end new; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE as v_impl_id acs_sc_impls.impl_id%TYPE; begin select impl_id into v_impl_id from acs_sc_impls where impl_name = get_id.impl_name and impl_contract_name = get_id.impl_contract_name; return v_impl_id; end get_id; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE as v_impl_name acs_sc_impls.impl_name%TYPE; begin select impl_name into v_impl_name from acs_sc_impls where impl_id = get_name.impl_id; return v_impl_name; end get_name; procedure delete ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) as begin delete from acs_sc_impls where impl_contract_name = acs_sc_impl.delete.impl_contract_name and impl_name = acs_sc_impl.delete.impl_name; end delete; /* next 2 functions are deprecated. */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.new dbms_output.put_line('acs_sc_impl.new_alias DEPRECATED. Use acs_sc_impl_alias.new'); v_impl_id := acs_sc_impl_alias.new( impl_contract_name, impl_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new_alias; function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.delete dbms_output.put_line('acs_sc_impl.delete_alias DEPRECATED. Use acs_sc_impl_alias.delete'); v_impl_id := acs_sc_impl_alias.delete( impl_contract_name, impl_name, impl_operation_name ); return v_impl_id; end delete_alias; end acs_sc_impl; / show errors create or replace view valid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); create or replace view invalid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); create or replace view orphan_implementations as select i.impl_id, i.impl_name, i.impl_contract_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_impls i where not exists (select 1 from acs_sc_bindings b where b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_contracts c where c.contract_name = i.impl_contract_name); openacs-5.7.0/packages/acs-service-contract/sql/oracle/upgrade/upgrade-5.1.0d1-5.1.0d2.sql0000644000175000017500000003606210024403026030202 0ustar frankiefrankieupdate acs_objects set title = (select msg_type_name from acs_sc_msg_types where msg_type_id = object_id) where object_type = 'acs_sc_msg_type'; update acs_objects set title = (select contract_name from acs_sc_contracts where contract_id = object_id) where object_type = 'acs_sc_contract'; update acs_objects set title = (select operation_name from acs_sc_operations where operation_id = object_id) where object_type = 'acs_sc_operation'; update acs_objects set title = (select impl_pretty_name from acs_sc_impls where impl_id = object_id) where object_type = 'acs_sc_implementation'; commit; create or replace package body acs_sc_msg_type as function new ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id integer; v_spec_parse_level integer; begin v_msg_type_id := acs_object.new( object_type => 'acs_sc_msg_type', title => msg_type_name ); insert into acs_sc_msg_types ( msg_type_id, msg_type_name ) values ( v_msg_type_id, msg_type_name ); v_spec_parse_level := acs_sc_msg_type.parse_spec( msg_type_name, msg_type_spec); return v_msg_type_id; end new; procedure del ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE default null, msg_type_name in acs_sc_msg_types.msg_type_name%TYPE default null ) is v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin if msg_type_name is not NULL then v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name); elsif msg_type_id is not NULL then v_msg_type_id := msg_type_id; else raise_application_error(-20000, 'no args supplied to sc_msg_type.delete'); end if; delete from acs_sc_msg_types where msg_type_id = v_msg_type_id; end del; function get_id ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin select msg_type_id into v_msg_type_id from acs_sc_msg_types where msg_type_name = get_id.msg_type_name; return v_msg_type_id; end get_id; function get_name ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE ) return acs_sc_msg_types.msg_type_name%TYPE is v_msg_type_name acs_sc_msg_types.msg_type_name%TYPE; begin select msg_type_name into v_msg_type_name from acs_sc_msg_types where msg_type_id = get_name.msg_type_id; return v_msg_type_name; end get_name; -- string processing in pl/sql is so much fun -- i'm sure there is a better way to go about this function parse_spec ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return integer is v_element_pos integer; v_str_s_idx integer; -- spec str pointers v_str_e_idx integer; v_elem_idx integer; -- element str pointer v_str_len integer; v_element varchar(200); v_element_type varchar(200); v_element_name varchar(200); v_element_msg_type_name varchar(200); v_element_msg_type_isset_p char(1); v_junk_msg_type_id integer; begin -- oracle treats empty strings as nulls if msg_type_spec is null then return 0; end if; v_element_pos := 1; v_str_e_idx := 1; while TRUE loop -- string start check if v_element_pos = 1 then v_str_s_idx := 1; else v_str_s_idx := instr(msg_type_spec, ',', v_str_e_idx); if v_str_s_idx > 0 then v_str_s_idx := v_str_s_idx + 1; end if; end if; v_str_e_idx := instr(msg_type_spec, ',', v_str_s_idx+1)-1; -- end of string check if v_str_s_idx > 0 and v_str_e_idx <= 0 then v_str_e_idx := length(msg_type_spec); end if; -- dbms_output.put_line(v_str_s_idx || ' '|| v_str_e_idx || ' ' || v_element_pos); -- dbms_output.new_line(); if v_str_s_idx > 0 then v_element := substr(msg_type_spec, v_str_s_idx, v_str_e_idx+1 - v_str_s_idx); v_elem_idx := instr(v_element, ':'); if v_elem_idx > 0 then v_element_name := trim( substr(v_element, 1, v_elem_idx-1)); v_element_type := trim( substr(v_element, v_elem_idx+1)); if (instr(v_element_type, '[',1,1) = length(v_element_type)-1) and (instr(v_element_type, ']',1,1) = length(v_element_type)) then v_element_msg_type_isset_p := 't'; v_element_msg_type_name := trim(substr( v_element_type, 1, length(v_element_type)-2)); if v_element_msg_type_name = '' then raise_application_error (-20001, 'Wrong Format: Message Type Specification'); end if; else v_element_msg_type_isset_p := 'f'; v_element_msg_type_name := v_element_type; end if; v_junk_msg_type_id := acs_sc_msg_type.new_element ( msg_type_name =>parse_spec.msg_type_name, element_name => v_element_name, element_msg_type_name => v_element_msg_type_name, element_msg_type_isset_p => v_element_msg_type_isset_p, element_pos => v_element_pos ); else raise_application_error(-20001,'Wrong Format: Message Type Specification'); end if; else -- yippee we're done exit; end if; v_element_pos := v_element_pos + 1; end loop; return v_element_pos - 1; end parse_spec; function new_element ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_name in acs_sc_msg_type_elements.element_name%TYPE, element_msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_msg_type_isset_p in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE, element_pos in acs_sc_msg_type_elements.element_pos%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id integer; v_element_msg_type_id integer; begin v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name); if v_msg_type_id is null then raise_application_error (-20001, 'Unknown Message Type: ' || msg_type_name); end if; v_element_msg_type_id := acs_sc_msg_type.get_id(element_msg_type_name); if v_element_msg_type_id is null then raise_application_error (-20001, 'Unknown Message Type: ' || element_msg_type_name); end if; insert into acs_sc_msg_type_elements ( msg_type_id, element_name, element_msg_type_id, element_msg_type_isset_p, element_pos ) values ( v_msg_type_id, element_name, v_element_msg_type_id, element_msg_type_isset_p, element_pos ); return v_msg_type_id; end new_element; end acs_sc_msg_type; / show errors create or replace package body acs_sc_contract as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, contract_desc in acs_sc_contracts.contract_desc%TYPE ) return acs_sc_contracts.contract_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; begin v_contract_id := acs_object.new( object_type => 'acs_sc_contract', title => contract_name ); insert into acs_sc_contracts ( contract_id, contract_name, contract_desc ) values ( v_contract_id, contract_name, contract_desc ); return v_contract_id; end new; function get_id ( contract_name in acs_sc_contracts.contract_name%TYPE ) return acs_sc_contracts.contract_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; begin select contract_id into v_contract_id from acs_sc_contracts where contract_name = get_id.contract_name; return v_contract_id; end get_id; function get_name ( contract_id in acs_sc_contracts.contract_id%TYPE ) return acs_sc_contracts.contract_name%TYPE is v_contract_name acs_sc_contracts.contract_name%TYPE; begin select contract_name into v_contract_name from acs_sc_contracts where contract_id = get_name.contract_id; return v_contract_name; end get_name; procedure del ( contract_name in acs_sc_contracts.contract_name%TYPE default null, contract_id in acs_sc_contracts.contract_id%TYPE default null ) is v_contract_id acs_sc_contracts.contract_id%TYPE; begin if contract_name is not NULL then v_contract_id := acs_sc_contract.get_id(contract_name); elsif contract_id is not NULL then v_contract_id := contract_id; else raise_application_error(-20001, 'Service Contracts: no valid args supplied to delete'); end if; delete from acs_sc_contracts where contract_id = v_contract_id; acs_object.del(v_contract_id); end del; end acs_sc_contract; / show errors create or replace package body acs_sc_operation as function new ( contract_name in acs_sc_contracts.contract_name%TYPE, operation_name in acs_sc_operations.operation_name%TYPE, operation_desc in acs_sc_operations.operation_desc%TYPE, operation_iscachable_p in acs_sc_operations.operation_iscachable_p%TYPE, operation_nargs in acs_sc_operations.operation_nargs%TYPE, operation_inputtype in acs_sc_msg_types.msg_type_name%TYPE, operation_outputtype in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_operations.operation_id%TYPE is v_contract_id acs_sc_contracts.contract_id%TYPE; v_operation_id acs_sc_operations.operation_id%TYPE; v_operation_inputtype_id acs_sc_operations.operation_inputtype_id%TYPE; v_operation_outputtype_id acs_sc_operations.operation_outputtype_id%TYPE; begin v_contract_id := acs_sc_contract.get_id(contract_name); v_operation_id := acs_object.new ( object_type => 'acs_sc_operation', title => operation_name ); v_operation_inputtype_id := acs_sc_msg_type.get_id(operation_inputtype); v_operation_outputtype_id := acs_sc_msg_type.get_id(operation_outputtype); insert into acs_sc_operations ( contract_id, operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id ) values ( v_contract_id, v_operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, v_operation_inputtype_id, v_operation_outputtype_id ); return v_operation_id; end new; function get_id ( contract_name acs_sc_contracts.contract_name%TYPE, operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_operations.operation_id%TYPE as v_operation_id acs_sc_operations.operation_id%TYPE; begin select operation_id into v_operation_id from acs_sc_operations where contract_name = get_id.contract_name and operation_name = get_id.operation_name; return v_operation_id; end get_id; procedure del ( operation_id acs_sc_operations.operation_id%TYPE default null, operation_name acs_sc_operations.operation_name%TYPE default null, contract_name acs_sc_contracts.contract_name%TYPE default null ) is v_operation_id acs_sc_operations.operation_id%TYPE; begin if (operation_id is NULL and operation_name is not NULL and contract_name is not NULL) then v_operation_id := get_id(contract_name, operation_name); elsif operation_id is not NULL then v_operation_id := operation_id; else raise_application_error(-20001, 'ACS Contracts: Invalid args to operation delete'); end if; delete from acs_sc_operations where operation_id = v_operation_id; end del; end acs_sc_operation; / show errors create or replace package body acs_sc_impl as function new ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_pretty_name acs_sc_impls.impl_pretty_name%TYPE default null, impl_owner_name acs_sc_impls.impl_owner_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin v_impl_id := acs_object.new ( object_type => 'acs_sc_implementation', title => impl_pretty_name ); insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ); return v_impl_id; end new; function get_id ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) return acs_sc_impls.impl_id%TYPE as v_impl_id acs_sc_impls.impl_id%TYPE; begin select impl_id into v_impl_id from acs_sc_impls where impl_name = get_id.impl_name and impl_contract_name = get_id.impl_contract_name; return v_impl_id; end get_id; function get_name ( impl_id acs_sc_impls.impl_id%TYPE ) return acs_sc_impls.impl_name%TYPE as v_impl_name acs_sc_impls.impl_name%TYPE; begin select impl_name into v_impl_name from acs_sc_impls where impl_id = get_name.impl_id; return v_impl_name; end get_name; procedure del ( impl_contract_name acs_sc_impls.impl_contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE ) as begin delete from acs_sc_impls where impl_contract_name = acs_sc_impl.del.impl_contract_name and impl_name = acs_sc_impl.del.impl_name; end del; /* next 2 functions are deprecated. */ function new_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE, impl_alias acs_sc_impl_aliases.impl_alias%TYPE, impl_pl acs_sc_impl_aliases.impl_pl%TYPE ) return acs_sc_impl_aliases.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.new dbms_output.put_line('acs_sc_impl.new_alias DEPRECATED. Use acs_sc_impl_alias.new'); v_impl_id := acs_sc_impl_alias.new( impl_contract_name, impl_name, impl_operation_name, impl_alias, impl_pl ); return v_impl_id; end new_alias; function delete_alias ( impl_contract_name acs_sc_contracts.contract_name%TYPE, impl_name acs_sc_impls.impl_name%TYPE, impl_operation_name acs_sc_operations.operation_name%TYPE ) return acs_sc_impls.impl_id%TYPE is v_impl_id acs_sc_impls.impl_id%TYPE; begin -- FUNCTION DEPRECATED. USE acs_sc_impl_alias.delete dbms_output.put_line('acs_sc_impl.delete_alias DEPRECATED. Use acs_sc_impl_alias.delete'); v_impl_id := acs_sc_impl_alias.del( impl_contract_name, impl_name, impl_operation_name ); return v_impl_id; end delete_alias; end acs_sc_impl; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/sc-sample-create.sql0000644000175000017500000000600107352221465026505 0ustar frankiefrankie-- CREATE CONTRACT declare sc_sample_test integer; begin sc_sample_test := acs_sc_contract.new( contract_name => 'ObjectDisplay', contract_desc => 'Object display' ); sc_sample_test := acs_sc_msg_type.new( msg_type_name => 'ObjectDisplay.Name.InputType', msg_type_spec => 'object_id:integer' ); sc_sample_test := acs_sc_msg_type.new( msg_type_name => 'ObjectDisplay.Name.OutputType', msg_type_spec => 'object_name:string' ); sc_sample_test := acs_sc_operation.new( contract_name => 'ObjectDisplay', operation_name => 'name', operation_desc => 'Returns objects name', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputttype => 'ObjectDisplay.Name.InputType', operation_ouputtype => 'ObjectDisplay.Name.OutputType' ); sc_sample_test := acs_sc_msg_type.new('ObjectDisplay.Url.InputType','object_id:integer'); sc_sample_test := acs_sc_msg_type.new('ObjectDisplay.Url.OutputType','object_url:uri'); sc_sample_test := acs_sc_operation.new( 'ObjectDisplay', -- contract_name 'url', -- operation_name 'Returns object''s url', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'ObjectDisplay.Url.InputType', -- operation_inputtype 'ObjectDisplay.Url.OutputType' -- operation_outputtype ); sc_sample_test := acs_sc_msg_type.new ('ObjectDisplay.SampleHello.InputType', 'object_id:integer,object_txt:string'); sc_sample_test := acs_sc_msg_type.new ('ObjectDisplay.SampleHello.OutputType', 'object_sample:string[],xxx_p:boolean'); sc_sample_test := acs_sc_operation.new ( 'ObjectDisplay', -- contract_name 'sample_hello', -- operation_name 'Returns object''s url', -- operation_desc 't', -- operation_iscachable_p 1, -- operation_nargs 'ObjectDisplay.SampleHello.InputType', -- operation_inputtype 'ObjectDisplay.SampleHello.OutputType' -- operation_outputtype ); -- CREATE IMPLEMENTATION sc_sample_test := acs_sc_impl.new( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'bboard' -- impl_owner_name ); sc_sample_test := acs_sc_impl.new_alias( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'name', -- impl_operation_name 'bboard_message__name', -- impl_alias 'PLPGSQL' -- impl_pl ); sc_sample_test := acs_sc_impl.new_alias( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'url', -- impl_operation_name 'bboard_message__url', -- impl_alias 'PLPGSQL' -- impl_pl ); sc_sample_test := acs_sc_impl.new_alias( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'sample_hello', -- impl_operation_name 'bboard_message__sample_hello', -- impl_alias 'TCL' -- impl_pl ); end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-sc-msg-types-create.sql0000644000175000017500000002206210024403025027705 0ustar frankiefrankie-- $Id: acs-sc-msg-types-create.sql,v 1.7 2004/03/12 18:48:53 jeffd Exp $ begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'acs_sc_msg_type', pretty_name => 'ACS SC Message Type', pretty_plural => 'ACS SC Message Types', table_name => 'acs_sc_msg_types', id_column => 'msg_type_id' ); end; / show errors create table acs_sc_msg_types ( msg_type_id integer constraint acs_sc_msg_type_id_fk references acs_objects(object_id) on delete cascade constraint acs_sc_msg_type_pk primary key, msg_type_name varchar2(100) constraint acs_sc_msg_type_name_un unique ); create table acs_sc_msg_type_elements ( msg_type_id integer constraint acs_sc_msg_type_el_mtype_id_fk references acs_sc_msg_types(msg_type_id) on delete cascade, element_name varchar2(100), element_msg_type_id integer constraint acs_sc_msg_type_el_emti_id_fk references acs_sc_msg_types(msg_type_id), element_msg_type_isset_p char(1) constraint acs_msg_type_el_set_p_ck check (element_msg_type_isset_p in ('t', 'f')), element_pos integer ); create or replace package acs_sc_msg_type as function new ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return acs_sc_msg_types.msg_type_id%TYPE; procedure del ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE default null, msg_type_name in acs_sc_msg_types.msg_type_name%TYPE default null ); function get_id ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE; function get_name ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE ) return acs_sc_msg_types.msg_type_name%TYPE; -- ask nd about name function parse_spec ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return integer; function new_element ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_name in acs_sc_msg_type_elements.element_name%TYPE, element_msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_msg_type_isset_p in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE, element_pos in acs_sc_msg_type_elements.element_pos%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE; end acs_sc_msg_type; / show errors create or replace package body acs_sc_msg_type as function new ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id integer; v_spec_parse_level integer; begin v_msg_type_id := acs_object.new( object_type => 'acs_sc_msg_type', title => msg_type_name ); insert into acs_sc_msg_types ( msg_type_id, msg_type_name ) values ( v_msg_type_id, msg_type_name ); v_spec_parse_level := acs_sc_msg_type.parse_spec( msg_type_name, msg_type_spec); return v_msg_type_id; end new; procedure del ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE default null, msg_type_name in acs_sc_msg_types.msg_type_name%TYPE default null ) is v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin if msg_type_name is not NULL then v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name); elsif msg_type_id is not NULL then v_msg_type_id := msg_type_id; else raise_application_error(-20000, 'no args supplied to sc_msg_type.delete'); end if; delete from acs_sc_msg_types where msg_type_id = v_msg_type_id; end del; function get_id ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin select msg_type_id into v_msg_type_id from acs_sc_msg_types where msg_type_name = get_id.msg_type_name; return v_msg_type_id; end get_id; function get_name ( msg_type_id in acs_sc_msg_types.msg_type_id%TYPE ) return acs_sc_msg_types.msg_type_name%TYPE is v_msg_type_name acs_sc_msg_types.msg_type_name%TYPE; begin select msg_type_name into v_msg_type_name from acs_sc_msg_types where msg_type_id = get_name.msg_type_id; return v_msg_type_name; end get_name; -- string processing in pl/sql is so much fun -- i'm sure there is a better way to go about this function parse_spec ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, msg_type_spec in varchar2 ) return integer is v_element_pos integer; v_str_s_idx integer; -- spec str pointers v_str_e_idx integer; v_elem_idx integer; -- element str pointer v_str_len integer; v_element varchar(200); v_element_type varchar(200); v_element_name varchar(200); v_element_msg_type_name varchar(200); v_element_msg_type_isset_p char(1); v_junk_msg_type_id integer; begin -- oracle treats empty strings as nulls if msg_type_spec is null then return 0; end if; v_element_pos := 1; v_str_e_idx := 1; while TRUE loop -- string start check if v_element_pos = 1 then v_str_s_idx := 1; else v_str_s_idx := instr(msg_type_spec, ',', v_str_e_idx); if v_str_s_idx > 0 then v_str_s_idx := v_str_s_idx + 1; end if; end if; v_str_e_idx := instr(msg_type_spec, ',', v_str_s_idx+1)-1; -- end of string check if v_str_s_idx > 0 and v_str_e_idx <= 0 then v_str_e_idx := length(msg_type_spec); end if; -- dbms_output.put_line(v_str_s_idx || ' '|| v_str_e_idx || ' ' || v_element_pos); -- dbms_output.new_line(); if v_str_s_idx > 0 then v_element := substr(msg_type_spec, v_str_s_idx, v_str_e_idx+1 - v_str_s_idx); v_elem_idx := instr(v_element, ':'); if v_elem_idx > 0 then v_element_name := trim( substr(v_element, 1, v_elem_idx-1)); v_element_type := trim( substr(v_element, v_elem_idx+1)); if (instr(v_element_type, '[',1,1) = length(v_element_type)-1) and (instr(v_element_type, ']',1,1) = length(v_element_type)) then v_element_msg_type_isset_p := 't'; v_element_msg_type_name := trim(substr( v_element_type, 1, length(v_element_type)-2)); if v_element_msg_type_name = '' then raise_application_error (-20001, 'Wrong Format: Message Type Specification'); end if; else v_element_msg_type_isset_p := 'f'; v_element_msg_type_name := v_element_type; end if; v_junk_msg_type_id := acs_sc_msg_type.new_element ( msg_type_name =>parse_spec.msg_type_name, element_name => v_element_name, element_msg_type_name => v_element_msg_type_name, element_msg_type_isset_p => v_element_msg_type_isset_p, element_pos => v_element_pos ); else raise_application_error(-20001,'Wrong Format: Message Type Specification'); end if; else -- yippee we're done exit; end if; v_element_pos := v_element_pos + 1; end loop; return v_element_pos - 1; end parse_spec; function new_element ( msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_name in acs_sc_msg_type_elements.element_name%TYPE, element_msg_type_name in acs_sc_msg_types.msg_type_name%TYPE, element_msg_type_isset_p in acs_sc_msg_type_elements.element_msg_type_isset_p%TYPE, element_pos in acs_sc_msg_type_elements.element_pos%TYPE ) return acs_sc_msg_types.msg_type_id%TYPE is v_msg_type_id integer; v_element_msg_type_id integer; begin v_msg_type_id := acs_sc_msg_type.get_id(msg_type_name); if v_msg_type_id is null then raise_application_error (-20001, 'Unknown Message Type: ' || msg_type_name); end if; v_element_msg_type_id := acs_sc_msg_type.get_id(element_msg_type_name); if v_element_msg_type_id is null then raise_application_error (-20001, 'Unknown Message Type: ' || element_msg_type_name); end if; insert into acs_sc_msg_type_elements ( msg_type_id, element_name, element_msg_type_id, element_msg_type_isset_p, element_pos ) values ( v_msg_type_id, element_name, v_element_msg_type_id, element_msg_type_isset_p, element_pos ); return v_msg_type_id; end new_element; end acs_sc_msg_type; / show errors -- -- Primitive Message Types -- declare v_msg_type_id acs_sc_msg_types.msg_type_id%TYPE; begin v_msg_type_id := acs_sc_msg_type.new('integer',''); v_msg_type_id := acs_sc_msg_type.new('string',''); v_msg_type_id := acs_sc_msg_type.new('boolean',''); v_msg_type_id := acs_sc_msg_type.new('timestamp',''); v_msg_type_id := acs_sc_msg_type.new('uri',''); v_msg_type_id := acs_sc_msg_type.new('version',''); v_msg_type_id := acs_sc_msg_type.new('float',''); v_msg_type_id := acs_sc_msg_type.new('bytearray',''); end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-service-contract-drop.sql0000644000175000017500000000032707352221465030346 0ustar frankiefrankie-- $Id: acs-service-contract-drop.sql,v 1.1 2001/09/19 22:59:01 donb Exp $ @@ acs-sc-views-drop.sql @@ acs-sc-packages-drop.sql @@ acs-sc-tables-drop.sql @@ acs-sc-object-types-drop.sql @@ acs-sc-msg-types-drop.sqlopenacs-5.7.0/packages/acs-service-contract/sql/oracle/sc-sample-drop.sql0000644000175000017500000000111507736271232026212 0ustar frankiefrankiebegin acs_sc_impl.del( 'ObjectDisplay', -- impl_contract_name 'bboard_message' -- impl_name ); acs_sc_contract.del(contract_name=>'ObjectDisplay', operation_name=>'name'); acs_sc_msg_type.del ('ObjectDisplay.Name.InputType'); acs_sc_msg_type.del ('ObjectDisplay.Name.OutputType'); acs_sc_msg_type.del ('ObjectDisplay.Url.InputType'); acs_sc_msg_type.del ('ObjectDisplay.Url.OutputType'); acs_sc_msg_type.del ('ObjectDisplay.SampleHello.InputType'); acs_sc_msg_type.del ('ObjectDisplay.SampleHello.OutputType'); end; / show errors openacs-5.7.0/packages/acs-service-contract/sql/oracle/acs-service-contract-create.sql0000644000175000017500000000022507352221465030642 0ustar frankiefrankie@@ acs-sc-msg-types-create.sql @@ acs-sc-object-types-create.sql @@ acs-sc-tables-create.sql @@ acs-sc-packages-create.sql @@ acs-sc-views-create.sqlopenacs-5.7.0/packages/acs-service-contract/sql/postgresql/0000755000175000017500000000000011575225534023603 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-object-types-create.sql0000644000175000017500000000234207357630646031354 0ustar frankiefrankieselect acs_object_type__create_type ( 'acs_sc_contract', -- object_type 'ACS SC Contract', -- pretty_name 'ACS SC Contracts', -- pretty_plural 'acs_object', -- supertype 'acs_sc_contracts', -- table_name 'contract_id', -- id_column null, -- package_name 'f', -- abstract_p null, -- type_extension_table null -- name_method ); select acs_object_type__create_type ( 'acs_sc_operation', -- object_type 'ACS SC Operation', -- pretty_name 'ACS SC Operations', -- pretty_plural 'acs_object', -- supertype 'acs_sc_operations', -- table_name 'operation_id', -- id_column null, -- package_name 'f', -- abstract_p null, -- type_extension_table null -- name_method ); select acs_object_type__create_type ( 'acs_sc_implementation', -- object_type 'ACS SC Implementation', -- pretty_name 'ACS SC Implementations', -- pretty_plural 'acs_object', -- supertype 'acs_sc_impls', -- table_name 'impl_id', -- id_column null, -- package_name 'f', -- abstract_p null, -- type_extension_table null -- name_method ); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-tables-create.sql0000644000175000017500000000511210506042627030176 0ustar frankiefrankiecreate table acs_sc_contracts ( contract_id integer constraint acs_sc_contracts_id_fk references acs_objects(object_id) on delete cascade constraint acs_sc_contracts_pk primary key, contract_name varchar(1000) constraint acs_sc_contracts_name_nn not null constraint acs_sc_contracts_name_un unique, contract_desc text constraint acs_sc_contracts_desc_nn not null ); create table acs_sc_operations ( contract_id integer constraint acs_sc_operations_cid_fk references acs_sc_contracts(contract_id) on delete cascade, operation_id integer constraint acs_sc_operations_opid_fk references acs_objects(object_id) on delete cascade constraint acs_sc_operations_pk primary key, contract_name varchar(1000), operation_name varchar(100), operation_desc text constraint acs_sc_operations_desc_nn not null, operation_iscachable_p boolean, operation_nargs integer, operation_inputtype_id integer constraint acs_sc_operations_intype_fk references acs_sc_msg_types(msg_type_id), operation_outputtype_id integer constraint acs_sc_operations_outtype_fk references acs_sc_msg_types(msg_type_id) ); create table acs_sc_impls ( impl_id integer constraint acs_sc_impls_impl_id_fk references acs_objects(object_id) on delete cascade constraint acs_sc_impls_impl_id_pk primary key, impl_name varchar(100), impl_pretty_name varchar(200), impl_owner_name varchar(1000), impl_contract_name varchar(1000) ); create table acs_sc_impl_aliases ( impl_id integer constraint acs_sc_impl_aliases_impl_id_fk references acs_sc_impls(impl_id) on delete cascade, impl_name varchar(100), impl_contract_name varchar(1000), impl_operation_name varchar(100), impl_alias varchar(100), impl_pl varchar(100), constraint acs_sc_impl_alias_un unique(impl_name,impl_contract_name,impl_operation_name) ); create table acs_sc_bindings ( contract_id integer constraint acs_sc_bindings_contract_id_fk references acs_sc_contracts(contract_id) on delete cascade, impl_id integer constraint acs_sc_bindings_impl_id_fk references acs_sc_impls(impl_id) on delete cascade ); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-views-drop.sql0000644000175000017500000000015707357630646027604 0ustar frankiefrankiedrop view orphan_implementations; drop view invalid_uninstalled_bindings; drop view valid_uninstalled_bindings;openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-object-types-drop.sql0000644000175000017500000000060207344241641031037 0ustar frankiefrankiedelete from acs_objects where object_type = 'acs_sc_implementation'; select acs_object_type__drop_type ('acs_sc_implementation', 'f'); delete from acs_objects where object_type = 'acs_sc_operation'; select acs_object_type__drop_type ('acs_sc_operation', 'f'); delete from acs_objects where object_type = 'acs_sc_contract'; select acs_object_type__drop_type ('acs_sc_contract', 'f'); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-packages-drop.sql0000644000175000017500000000214207661403517030212 0ustar frankiefrankiedrop function acs_sc_binding__exists_p(varchar,varchar); drop function acs_sc_binding__delete(varchar,varchar); drop function acs_sc_binding__delete(integer,integer); drop function acs_sc_binding__new(integer,integer); drop function acs_sc_binding__new(varchar,varchar); drop function acs_sc_impl_alias__delete(varchar,varchar,varchar); drop function acs_sc_impl_alias__new(varchar,varchar,varchar,varchar,varchar); drop function acs_sc_impl__delete(varchar,varchar); drop function acs_sc_impl__get_name(integer); drop function acs_sc_impl__get_id(varchar,varchar); drop function acs_sc_impl__new(varchar,varchar,varchar); drop function acs_sc_operation__delete(varchar,varchar); drop function acs_sc_operation__delete(integer); drop function acs_sc_operation__get_id(varchar,varchar); drop function acs_sc_operation__new(varchar,varchar,text,boolean,integer,varchar,varchar); drop function acs_sc_contract__delete(varchar); drop function acs_sc_contract__delete(integer); drop function acs_sc_contract__get_name(integer); drop function acs_sc_contract__get_id(varchar); drop function acs_sc_contract__new(varchar,text); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-msg-types-drop.sql0000644000175000017500000000110607354441057030363 0ustar frankiefrankiedrop function acs_sc_msg_type__parse_spec(varchar,varchar); drop function acs_sc_msg_type__new_element(varchar,varchar,varchar,boolean,integer); drop table acs_sc_msg_type_elements; drop function acs_sc_msg_type__delete(varchar); drop function acs_sc_msg_type__delete(integer); drop function acs_sc_msg_type__get_name(integer); drop function acs_sc_msg_type__get_id(varchar); drop function acs_sc_msg_type__new(varchar,varchar); drop table acs_sc_msg_types; delete from acs_objects where object_type = 'acs_sc_msg_type'; select acs_object_type__drop_type ('acs_sc_msg_type', 'f'); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-packages-create.sql0000644000175000017500000003523110632312561030504 0ustar frankiefrankie-- register function record select define_function_args('acs_sc_contract__new','contract_name,contract_desc'); -- declare function create or replace function acs_sc_contract__new(varchar,text) returns integer as ' declare p_contract_name alias for $1; p_contract_desc alias for $2; v_contract_id integer; begin v_contract_id := acs_object__new( null, ''acs_sc_contract'', now(), null, null, null, ''t'', p_contract_name, null ); insert into acs_sc_contracts ( contract_id, contract_name, contract_desc ) values ( v_contract_id, p_contract_name, p_contract_desc ); return v_contract_id; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_contract__get_id','contract_name'); -- declare function create or replace function acs_sc_contract__get_id(varchar) returns integer as ' declare p_contract_name alias for $1; v_contract_id integer; begin select contract_id into v_contract_id from acs_sc_contracts where contract_name = p_contract_name; return v_contract_id; end;' language 'plpgsql' stable strict; -- register function record select define_function_args('acs_sc_contract__get_name','contract_id'); -- declare function create or replace function acs_sc_contract__get_name(integer) returns varchar as ' declare p_contract_id alias for $1; v_contract_name varchar; begin select contract_name into v_contract_name from acs_sc_contracts where contract_id = p_contract_id; return v_contract_name; end;' language 'plpgsql' stable strict; create or replace function acs_sc_contract__delete(integer) returns integer as ' declare p_contract_id alias for $1; begin delete from acs_sc_contracts where contract_id = p_contract_id; return 0; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_contract__delete','contract_name'); -- declare function create or replace function acs_sc_contract__delete(varchar) returns integer as ' declare p_contract_name alias for $1; v_contract_id integer; begin v_contract_id := acs_sc_contract__get_id(p_contract_name); perform acs_sc_contract__delete(v_contract_id); return 0; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_operation__new','contract_name,operation_name,operation_desc,operation_iscachable_p;f,operation_nargs,operation_inputtype,operation_outputtype'); -- declare function create or replace function acs_sc_operation__new(varchar,varchar,text,boolean,integer,varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_operation_name alias for $2; p_operation_desc alias for $3; p_operation_iscachable_p alias for $4; p_operation_nargs alias for $5; p_operation_inputtype alias for $6; p_operation_outputtype alias for $7; v_contract_id integer; v_operation_id integer; v_operation_inputtype_id integer; v_operation_outputtype_id integer; begin v_contract_id := acs_sc_contract__get_id(p_contract_name); v_operation_id := acs_object__new( null, ''acs_sc_operation'', now(), null, null, null, ''t'', p_operation_name, null ); v_operation_inputtype_id := acs_sc_msg_type__get_id(p_operation_inputtype); v_operation_outputtype_id := acs_sc_msg_type__get_id(p_operation_outputtype); insert into acs_sc_operations ( contract_id, operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id ) values ( v_contract_id, v_operation_id, p_contract_name, p_operation_name, p_operation_desc, p_operation_iscachable_p, p_operation_nargs, v_operation_inputtype_id, v_operation_outputtype_id ); return v_operation_id; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_operation__get_id','contract_name,operation_name'); -- declare function create or replace function acs_sc_operation__get_id(varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_operation_name alias for $2; v_operation_id integer; begin select operation_id into v_operation_id from acs_sc_operations where contract_name = p_contract_name and operation_name = p_operation_name; return v_operation_id; end;' language 'plpgsql' stable strict; -- register function record select define_function_args('acs_sc_operation__delete','operation_id'); -- declare function create or replace function acs_sc_operation__delete(integer) returns integer as ' declare p_operation_id alias for $1; begin delete from acs_sc_operations where operation_id = p_operation_id; return 0; end;' language 'plpgsql'; -- XXX: should it exception on null? create or replace function acs_sc_operation__delete(varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_operation_name alias for $2; v_operation_id integer; begin v_operation_id := acs_sc_operation__get_id( p_contract_name, p_operation_name ); perform acs_sc_operation__delete(v_operation_id); return v_operation_id; end;' language 'plpgsql' strict; -- register function record select define_function_args('acs_sc_impl__new','impl_contract_name,impl_name,impl_pretty_name,impl_owner_name'); -- declare function create or replace function acs_sc_impl__new(varchar,varchar,varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; p_impl_pretty_name alias for $3; p_impl_owner_name alias for $4; v_impl_id integer; begin v_impl_id := acs_object__new( null, ''acs_sc_implementation'', now(), null, null, null, ''t'', p_impl_pretty_name, null ); insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, p_impl_name, p_impl_pretty_name, p_impl_owner_name, p_impl_contract_name ); return v_impl_id; end;' language 'plpgsql'; -- Only three arguments, defaults pretty name to empty string create or replace function acs_sc_impl__new(varchar,varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; p_impl_owner_name alias for $3; v_impl_id integer; begin -- Using an empty pretty name v_impl_id := acs_sc_impl__new( p_impl_contract_name, p_impl_name, p_impl_name, p_impl_owner_name ); return v_impl_id; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_impl__get_id','impl_contract_name,impl_name'); -- declare function create or replace function acs_sc_impl__get_id(varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; v_impl_id integer; begin select impl_id into v_impl_id from acs_sc_impls where impl_name = p_impl_name and impl_contract_name = p_impl_contract_name; return v_impl_id; end;' language 'plpgsql' stable strict; -- register function record select define_function_args('acs_sc_impl__get_name','impl_id'); -- declare function create or replace function acs_sc_impl__get_name(integer) returns varchar as ' declare p_impl_id alias for $1; v_impl_name varchar; begin select impl_name into v_impl_name from acs_sc_impls where impl_id = p_impl_id; return v_impl_name; end;' language 'plpgsql' stable strict; -- register function record select define_function_args('acs_sc_impl__delete','impl_contract_name,impl_name'); -- declare function create or replace function acs_sc_impl__delete(varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; begin delete from acs_sc_impls where impl_contract_name = p_impl_contract_name and impl_name = p_impl_name; return 0; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_impl_alias__new','impl_contract_name,impl_name,impl_operation_name,impl_alias,impl_pl'); -- declare function create or replace function acs_sc_impl_alias__new(varchar,varchar,varchar,varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; p_impl_operation_name alias for $3; p_impl_alias alias for $4; p_impl_pl alias for $5; v_impl_id integer; begin v_impl_id := acs_sc_impl__get_id(p_impl_contract_name,p_impl_name); insert into acs_sc_impl_aliases ( impl_id, impl_name, impl_contract_name, impl_operation_name, impl_alias, impl_pl ) values ( v_impl_id, p_impl_name, p_impl_contract_name, p_impl_operation_name, p_impl_alias, p_impl_pl ); return v_impl_id; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_impl_alias__delete','impl_contract_name,impl_name,impl_operation_name'); -- declare function create or replace function acs_sc_impl_alias__delete(varchar,varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; p_impl_operation_name alias for $3; v_impl_id integer; begin v_impl_id := acs_sc_impl__get_id(p_impl_contract_name, p_impl_name); delete from acs_sc_impl_aliases where impl_contract_name = p_impl_contract_name and impl_name = p_impl_name and impl_operation_name = p_impl_operation_name; return v_impl_id; end;' language 'plpgsql'; create or replace function acs_sc_binding__new(integer,integer) returns integer as ' declare p_contract_id alias for $1; p_impl_id alias for $2; v_contract_name varchar; v_impl_name varchar; v_count integer; v_missing_op varchar; begin v_contract_name := acs_sc_contract__get_name(p_contract_id); v_impl_name := acs_sc_impl__get_name(p_impl_id); select count(*),min(operation_name) into v_count, v_missing_op from acs_sc_operations where contract_id = p_contract_id and operation_name not in (select impl_operation_name from acs_sc_impl_aliases where impl_contract_name = v_contract_name and impl_id = p_impl_id); if v_count > 0 then raise exception ''Binding of % to % failed since certain operations are not implemented like: %.'', v_contract_name, v_impl_name, v_missing_op; end if; insert into acs_sc_bindings ( contract_id, impl_id ) values ( p_contract_id, p_impl_id ); return 0; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_binding__new','contract_name,impl_name'); -- declare function create or replace function acs_sc_binding__new(varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_impl_name alias for $2; v_contract_id integer; v_impl_id integer; v_count integer; begin v_contract_id := acs_sc_contract__get_id(p_contract_name); v_impl_id := acs_sc_impl__get_id(p_contract_name,p_impl_name); if v_contract_id is null or v_impl_id is null then raise exception ''Binding of % to % failed.'', p_contract_name, p_impl_name; else perform acs_sc_binding__new(v_contract_id,v_impl_id); end if; return 0; end;' language 'plpgsql'; create or replace function acs_sc_binding__delete(integer,integer) returns integer as ' declare p_contract_id alias for $1; p_impl_id alias for $2; begin delete from acs_sc_bindings where contract_id = p_contract_id and impl_id = p_impl_id; return 0; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_binding__delete','contract_name,impl_name'); -- declare function create or replace function acs_sc_binding__delete(varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_impl_name alias for $2; v_contract_id integer; v_impl_id integer; begin v_contract_id := acs_sc_contract__get_id(p_contract_name); v_impl_id := acs_sc_impl__get_id(p_contract_name,p_impl_name); perform acs_sc_binding__delete(v_contract_id,v_impl_id); return 0; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_binding__exists_p','contract_name,impl_name'); -- declare function create or replace function acs_sc_binding__exists_p(varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_impl_name alias for $2; v_contract_id integer; v_impl_id integer; v_exists_p integer; begin v_contract_id := acs_sc_contract__get_id(p_contract_name); v_impl_id := acs_sc_impl__get_id(p_contract_name,p_impl_name); select case when count(*)=0 then 0 else 1 end into v_exists_p from acs_sc_bindings where contract_id = v_contract_id and impl_id = v_impl_id; return v_exists_p; end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-tables-drop.sql0000644000175000017500000000022007357630646027710 0ustar frankiefrankiedrop table acs_sc_bindings; drop table acs_sc_impl_aliases; drop table acs_sc_impls; drop table acs_sc_operations; drop table acs_sc_contracts; openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-views-create.sql0000644000175000017500000000426507732027422030074 0ustar frankiefrankie-- $Id: acs-sc-views-create.sql,v 1.4 2003/09/17 09:53:22 lars Exp $ create view valid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); create view invalid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); create view orphan_implementations as select i.impl_id, i.impl_name, i.impl_owner_name, i.impl_contract_name, i.impl_pretty_name from acs_sc_impls i where not exists (select 1 from acs_sc_bindings b where b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_contracts c where c.contract_name = i.impl_contract_name); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/upgrade/0000755000175000017500000000000011575225534025232 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/sql/postgresql/upgrade/upgrade-4.5.1-4.6.sql0000644000175000017500000000234607572171636030364 0ustar frankiefrankie-- packages/acs-service-contract/sql/oracle/upgrade/upgrade-4.5-4.5.1.sql -- -- @author Vinod Kurup (vinod@kurup.com) -- @creation_date 2002-08-14 -- -- $Id: upgrade-4.5.1-4.6.sql,v 1.2 2002/11/30 17:21:34 jeffd Exp $ -- UPGRADE ISSUE #1 -- add more verbose error message create or replace function acs_sc_binding__new(integer,integer) returns integer as ' declare p_contract_id alias for $1; p_impl_id alias for $2; v_contract_name varchar; v_impl_name varchar; v_count integer; begin v_contract_name := acs_sc_contract__get_name(p_contract_id); v_impl_name := acs_sc_impl__get_name(p_impl_id); select count(*) into v_count from acs_sc_operations where contract_id = p_contract_id and operation_name not in (select impl_operation_name from acs_sc_impl_aliases where impl_contract_name = v_contract_name and impl_id = p_impl_id); if v_count > 0 then raise exception ''Binding of % to % failed since certain operations are not implemented.'', v_contract_name, v_impl_name; end if; insert into acs_sc_bindings ( contract_id, impl_id ) values ( p_contract_id, p_impl_id ); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-service-contract/sql/postgresql/upgrade/upgrade-4.7d2-4.7d3.sql0000644000175000017500000000661207731545007030677 0ustar frankiefrankie-- -- @author Simon Carstensen (simon@collaboraid.biz) -- @creation_date 2003-09-10 -- -- $Id: upgrade-4.7d2-4.7d3.sql,v 1.2 2003/09/16 08:29:59 lars Exp $ -- add column impl_pretty_name alter table acs_sc_impls add column impl_pretty_name varchar(200); update acs_sc_impls set impl_pretty_name = impl_name; create or replace function acs_sc_impl__new(varchar,varchar,varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; p_impl_pretty_name alias for $3; p_impl_owner_name alias for $4; v_impl_id integer; begin v_impl_id := acs_object__new( null, ''acs_sc_implementation'', now(), null, null, null ); insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, p_impl_name, p_impl_pretty_name, p_impl_owner_name, p_impl_contract_name ); return v_impl_id; end;' language 'plpgsql'; drop view valid_uninstalled_bindings; create view valid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); drop view invalid_uninstalled_bindings; create view invalid_uninstalled_bindings as select c.contract_id, c.contract_name, i.impl_id, i.impl_name, i.impl_owner_name, i.impl_pretty_name from acs_sc_contracts c, acs_sc_impls i where c.contract_name = i.impl_contract_name and not exists (select 1 from acs_sc_bindings b where b.contract_id = c.contract_id and b.impl_id = i.impl_id) and exists (select 1 from acs_sc_operations o where o.contract_id = c.contract_id and not exists (select 1 from acs_sc_impl_aliases a where a.impl_contract_name = c.contract_name and a.impl_id = i.impl_id and a.impl_operation_name = o.operation_name)); drop view orphan_implementations; create view orphan_implementations as select i.impl_id, i.impl_name, i.impl_owner_name, i.impl_contract_name, i.impl_pretty_name from acs_sc_impls i where not exists (select 1 from acs_sc_bindings b where b.impl_id = i.impl_id) and not exists (select 1 from acs_sc_contracts c where c.contract_name = i.impl_contract_name); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/upgrade/upgrade-5.3.1-5.4.0d1.sql0000644000175000017500000000646110632312561030730 0ustar frankiefrankie-- / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / -- This upgrade provides for the registering -- of ACS SC db procedures with the PostgreSQL -- 'package' infrastructure (acs_function_args). -- $Id: upgrade-5.3.1-5.4.0d1.sql,v 1.1 2007/06/08 17:44:17 gustafn Exp $ -- // acs-sc-packages-create.sql // -- acs_sc_contract__new(varchar,text) select define_function_args('acs_sc_contract__new','contract_name,contract_desc'); -- acs_sc_contract__get_id(varchar) select define_function_args('acs_sc_contract__get_id','contract_name'); -- acs_sc_contract__get_name(integer) select define_function_args('acs_sc_contract__get_name','contract_id'); -- acs_sc_contract__delete(varchar) select define_function_args('acs_sc_contract__delete','contract_name'); -- acs_sc_operation__new(varchar,varchar,text,boolean,integer,varchar,varchar) select define_function_args('acs_sc_operation__new','contract_name,operation_name,operation_desc,operation_iscachable_p;f,operation_nargs,operation_inputtype,operation_outputtype'); -- acs_sc_operation__get_id(varchar,varchar) select define_function_args('acs_sc_operation__get_id','contract_name,operation_name'); -- acs_sc_operation__delete(integer) select define_function_args('acs_sc_operation__delete','operation_id'); -- acs_sc_impl__new(varchar,varchar,varchar,varchar) select define_function_args('acs_sc_impl__new','impl_contract_name,impl_name,impl_pretty_name,impl_owner_name'); -- acs_sc_impl__get_id(varchar,varchar) select define_function_args('acs_sc_impl__get_id','impl_contract_name,impl_name'); -- acs_sc_impl__get_name(integer) select define_function_args('acs_sc_impl__get_name','impl_id'); -- acs_sc_impl__delete(varchar,varchar) select define_function_args('acs_sc_impl__delete','impl_contract_name,impl_name'); -- acs_sc_impl_alias__new(varchar,varchar,varchar,varchar,varchar) select define_function_args('acs_sc_impl_alias__new','impl_contract_name,impl_name,impl_operation_name,impl_alias,impl_pl'); -- acs_sc_impl_alias__delete(varchar,varchar,varchar) select define_function_args('acs_sc_impl_alias__delete','impl_contract_name,impl_name,impl_operation_name'); -- acs_sc_binding__new(varchar,varchar) select define_function_args('acs_sc_binding__new','contract_name,impl_name'); -- acs_sc_binding__delete(varchar,varchar) select define_function_args('acs_sc_binding__delete','contract_name,impl_name'); -- acs_sc_binding__exists_p(varchar,varchar) select define_function_args('acs_sc_binding__exists_p','contract_name,impl_name'); -- // acs-sc-msg-types-create.sql // -- acs_sc_msg_type__new(varchar,varchar) select define_function_args('acs_sc_msg_type__new','msg_type_name,msg_type_spec'); -- acs_sc_msg_type__get_id(varchar) select define_function_args('acs_sc_msg_type__get_id','msg_type_name'); -- acs_sc_msg_type__get_name(integer) select define_function_args('acs_sc_msg_type__get_name','msg_type_id'); -- acs_sc_msg_type__delete(varchar) select define_function_args('acs_sc_msg_type__delete','msg_type_name'); -- acs_sc_msg_type__new_element(varchar,varchar,varchar,boolean,integer) select define_function_args('acs_sc_msg_type__new_element','msg_type_name,element_name,element_msg_type_name,element_msg_type_isset_p;f,element_pos'); -- acs_sc_msg_type__parse_spec(varchar,varchar) select define_function_args('acs_sc_msg_type__parse_spec','msg_type_name,msg_type_spec');openacs-5.7.0/packages/acs-service-contract/sql/postgresql/upgrade/upgrade-5.1.0d1-5.1.0d2.sql0000644000175000017500000001225610024403026031137 0ustar frankiefrankieupdate acs_objects set title = (select msg_type_name from acs_sc_msg_types where msg_type_id = object_id) where object_type = 'acs_sc_msg_type'; update acs_objects set title = (select contract_name from acs_sc_contracts where contract_id = object_id) where object_type = 'acs_sc_contract'; update acs_objects set title = (select operation_name from acs_sc_operations where operation_id = object_id) where object_type = 'acs_sc_operation'; update acs_objects set title = (select impl_pretty_name from acs_sc_impls where impl_id = object_id) where object_type = 'acs_sc_implementation'; drop function acs_sc_msg_type__new(varchar,varchar); create or replace function acs_sc_msg_type__new(varchar,varchar) returns integer as ' declare p_msg_type_name alias for $1; p_msg_type_spec alias for $2; v_msg_type_id integer; begin v_msg_type_id := acs_object__new( null, ''acs_sc_msg_type'', now(), null, null, null, ''t'', p_msg_type_name, null ); insert into acs_sc_msg_types ( msg_type_id, msg_type_name ) values ( v_msg_type_id, p_msg_type_name ); perform acs_sc_msg_type__parse_spec(p_msg_type_name,p_msg_type_spec); return v_msg_type_id; end;' language 'plpgsql'; drop function acs_sc_contract__new(varchar,text); create or replace function acs_sc_contract__new(varchar,text) returns integer as ' declare p_contract_name alias for $1; p_contract_desc alias for $2; v_contract_id integer; begin v_contract_id := acs_object__new( null, ''acs_sc_contract'', now(), null, null, null, ''t'', p_contract_name, null ); insert into acs_sc_contracts ( contract_id, contract_name, contract_desc ) values ( v_contract_id, p_contract_name, p_contract_desc ); return v_contract_id; end;' language 'plpgsql'; drop function acs_sc_operation__new(varchar,varchar,text,boolean,integer,varchar,varchar); create or replace function acs_sc_operation__new(varchar,varchar,text,boolean,integer,varchar,varchar) returns integer as ' declare p_contract_name alias for $1; p_operation_name alias for $2; p_operation_desc alias for $3; p_operation_iscachable_p alias for $4; p_operation_nargs alias for $5; p_operation_inputtype alias for $6; p_operation_outputtype alias for $7; v_contract_id integer; v_operation_id integer; v_operation_inputtype_id integer; v_operation_outputtype_id integer; begin v_contract_id := acs_sc_contract__get_id(p_contract_name); v_operation_id := acs_object__new( null, ''acs_sc_operation'', now(), null, null, null, ''t'', p_operation_name, null ); v_operation_inputtype_id := acs_sc_msg_type__get_id(p_operation_inputtype); v_operation_outputtype_id := acs_sc_msg_type__get_id(p_operation_outputtype); insert into acs_sc_operations ( contract_id, operation_id, contract_name, operation_name, operation_desc, operation_iscachable_p, operation_nargs, operation_inputtype_id, operation_outputtype_id ) values ( v_contract_id, v_operation_id, p_contract_name, p_operation_name, p_operation_desc, p_operation_iscachable_p, p_operation_nargs, v_operation_inputtype_id, v_operation_outputtype_id ); return v_operation_id; end;' language 'plpgsql'; drop function acs_sc_impl__new(varchar,varchar,varchar,varchar); create or replace function acs_sc_impl__new(varchar,varchar,varchar,varchar) returns integer as ' declare p_impl_contract_name alias for $1; p_impl_name alias for $2; p_impl_pretty_name alias for $3; p_impl_owner_name alias for $4; v_impl_id integer; begin v_impl_id := acs_object__new( null, ''acs_sc_implementation'', now(), null, null, null, ''t'', p_impl_pretty_name, null ); insert into acs_sc_impls ( impl_id, impl_name, impl_pretty_name, impl_owner_name, impl_contract_name ) values ( v_impl_id, p_impl_name, p_impl_pretty_name, p_impl_owner_name, p_impl_contract_name ); return v_impl_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-service-contract/sql/postgresql/sc-sample-create.sql0000644000175000017500000000521307344241641027446 0ustar frankiefrankie-- CREATE CONTRACT select acs_sc_contract__new ( 'ObjectDisplay', -- contract_name 'Object display' -- contract_desc ); select acs_sc_msg_type__new ('ObjectDisplay.Name.InputType','object_id:integer'); select acs_sc_msg_type__new ('ObjectDisplay.Name.OutputType','object_name:string'); select acs_sc_operation__new ( 'ObjectDisplay', -- contract_name 'name', -- operation_name 'Returns object''s name', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'ObjectDisplay.Name.InputType', -- operation_inputtype 'ObjectDisplay.Name.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ('ObjectDisplay.Url.InputType','object_id:integer'); select acs_sc_msg_type__new ('ObjectDisplay.Url.OutputType','object_url:uri'); select acs_sc_operation__new ( 'ObjectDisplay', -- contract_name 'url', -- operation_name 'Returns object''s url', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'ObjectDisplay.Url.InputType', -- operation_inputtype 'ObjectDisplay.Url.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ('ObjectDisplay.SampleHello.InputType','object_id:integer,object_txt:string'); select acs_sc_msg_type__new ('ObjectDisplay.SampleHello.OutputType','object_sample:string[],xxx_p:boolean'); select acs_sc_operation__new ( 'ObjectDisplay', -- contract_name 'sample_hello', -- operation_name 'Returns object''s url', -- operation_desc 't', -- operation_iscachable_p 1, -- operation_nargs 'ObjectDisplay.SampleHello.InputType', -- operation_inputtype 'ObjectDisplay.SampleHello.OutputType' -- operation_outputtype ); -- CREATE IMPLEMENTATION select acs_sc_impl__new( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'bboard' -- impl_owner_name ); select acs_sc_impl_alias__new( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'name', -- impl_operation_name 'bboard_message__name', -- impl_alias 'PLPGSQL' -- impl_pl ); select acs_sc_impl_alias__new( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'url', -- impl_operation_name 'bboard_message__url', -- impl_alias 'PLPGSQL' -- impl_pl ); select acs_sc_impl_alias__new( 'ObjectDisplay', -- impl_contract_name 'bboard_message', -- impl_name 'sample_hello', -- impl_operation_name 'bboard_message__sample_hello', -- impl_alias 'TCL' -- impl_pl ); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-sc-msg-types-create.sql0000644000175000017500000001710010632312561030651 0ustar frankiefrankieselect acs_object_type__create_type ( 'acs_sc_msg_type', -- object_type 'ACS SC Message Type', -- pretty_name 'ACS SC Message Types', -- pretty_plural 'acs_object', -- supertype 'acs_sc_msg_types', -- table_name 'msg_type_id', -- id_column null, -- package_name 'f', -- abstract_p null, -- type_extension_table null -- name_method ); create table acs_sc_msg_types ( msg_type_id integer constraint acs_sc_msg_types_id_fk references acs_objects(object_id) on delete cascade constraint acs_sc_msg_types_pk primary key, msg_type_name varchar(100) constraint acs_sc_msg_types_name_un unique ); create table acs_sc_msg_type_elements ( msg_type_id integer constraint acs_sc_msg_type_el_mtype_id_fk references acs_sc_msg_types(msg_type_id) on delete cascade, element_name varchar(100), element_msg_type_id integer constraint acs_sc_msg_type_el_emti_id_fk references acs_sc_msg_types(msg_type_id), element_msg_type_isset_p boolean, element_pos integer ); -- register function record select define_function_args('acs_sc_msg_type__new','msg_type_name,msg_type_spec'); -- declare function create or replace function acs_sc_msg_type__new(varchar,varchar) returns integer as ' declare p_msg_type_name alias for $1; p_msg_type_spec alias for $2; v_msg_type_id integer; begin v_msg_type_id := acs_object__new( null, ''acs_sc_msg_type'', now(), null, null, null, ''t'', p_msg_type_name, null ); insert into acs_sc_msg_types ( msg_type_id, msg_type_name ) values ( v_msg_type_id, p_msg_type_name ); perform acs_sc_msg_type__parse_spec(p_msg_type_name,p_msg_type_spec); return v_msg_type_id; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_msg_type__get_id','msg_type_name'); -- declare function create or replace function acs_sc_msg_type__get_id(varchar) returns integer as ' declare p_msg_type_name alias for $1; v_msg_type_id integer; begin select msg_type_id into v_msg_type_id from acs_sc_msg_types where msg_type_name = p_msg_type_name; return v_msg_type_id; end;' language 'plpgsql' stable strict; -- register function record select define_function_args('acs_sc_msg_type__get_name','msg_type_id'); -- declare function create or replace function acs_sc_msg_type__get_name(integer) returns varchar as ' declare p_msg_type_id alias for $1; v_msg_type_name varchar; begin select msg_type_name into v_msg_type_name from acs_sc_msg_types where msg_type_id = p_msg_type_id; return v_msg_type_name; end;' language 'plpgsql' stable strict; create or replace function acs_sc_msg_type__delete(integer) returns integer as ' declare p_msg_type_id alias for $1; begin delete from acs_sc_msg_types where msg_type_id = p_msg_type_id; return 0; end;' language 'plpgsql'; -- XXX: this might be a bug that it does not return 0 as the above does. -- anyway now it is strict as being called with null is a noop and returns null -- register function record select define_function_args('acs_sc_msg_type__delete','msg_type_name'); -- declare function create or replace function acs_sc_msg_type__delete(varchar) returns integer as ' declare p_msg_type_name alias for $1; v_msg_type_id integer; begin v_msg_type_id := acs_sc_msg_type__get_id(p_msg_type_name); perform acs_sc_msg_type__delete(v_msg_type_id); return v_msg_type_id; end;' language 'plpgsql' strict; -- register function record select define_function_args('acs_sc_msg_type__new_element','msg_type_name,element_name,element_msg_type_name,element_msg_type_isset_p;f,element_pos'); -- declare function create or replace function acs_sc_msg_type__new_element(varchar,varchar,varchar,boolean,integer) returns integer as ' declare p_msg_type_name alias for $1; p_element_name alias for $2; p_element_msg_type_name alias for $3; p_element_msg_type_isset_p alias for $4; p_element_pos alias for $5; v_msg_type_id integer; v_element_msg_type_id integer; begin v_msg_type_id := acs_sc_msg_type__get_id(p_msg_type_name); if v_msg_type_id is null then raise exception ''Unknown Message Type: %'', p_msg_type_name; end if; v_element_msg_type_id := acs_sc_msg_type__get_id(p_element_msg_type_name); if v_element_msg_type_id is null then raise exception ''Unknown Message Type: %'', p_element_msg_type_name; end if; insert into acs_sc_msg_type_elements ( msg_type_id, element_name, element_msg_type_id, element_msg_type_isset_p, element_pos ) values ( v_msg_type_id, p_element_name, v_element_msg_type_id, p_element_msg_type_isset_p, p_element_pos ); return v_msg_type_id; end;' language 'plpgsql'; -- register function record select define_function_args('acs_sc_msg_type__parse_spec','msg_type_name,msg_type_spec'); -- declare function create or replace function acs_sc_msg_type__parse_spec(varchar,varchar) returns integer as ' declare p_msg_type_name alias for $1; p_msg_type_spec alias for $2; v_element varchar; v_element_type varchar; v_str_pos integer; v_element_name varchar; v_element_msg_type_name varchar; v_element_msg_type_isset_p boolean; v_element_pos integer; begin v_element_pos := 1; v_element := split(p_msg_type_spec, '','', v_element_pos); while v_element is not null loop v_str_pos = instr(v_element, '':'', 1, 1); if v_str_pos > 0 then v_element_name := trim(substr(v_element, 1, v_str_pos-1)); v_element_type := trim(substr(v_element, v_str_pos+1, length(v_element) - v_str_pos)); if (instr(v_element_type, ''['',1,1) = length(v_element_type)-1) and (instr(v_element_type, '']'',1,1) = length(v_element_type)) then v_element_msg_type_isset_p := ''t''; v_element_msg_type_name := trim(substr(v_element_type,1,length(v_element_type)-2)); if v_element_msg_type_name = '''' then raise exception ''Wrong Format: Message Type Specification''; end if; else v_element_msg_type_isset_p := ''f''; v_element_msg_type_name := v_element_type; end if; else raise exception ''Wrong Format: Message Type Specification''; end if; perform acs_sc_msg_type__new_element( p_msg_type_name, -- msg_type_id v_element_name, -- element_name v_element_msg_type_name, -- element_msg_type_id v_element_msg_type_isset_p, -- element_msg_type_isset_p v_element_pos -- element_pos ); v_element_pos := v_element_pos + 1; v_element := split(p_msg_type_spec, '','', v_element_pos); end loop; return v_element_pos-1; end;' language 'plpgsql'; -- -- Primitive Message Types -- select acs_sc_msg_type__new('integer',''); select acs_sc_msg_type__new('string',''); select acs_sc_msg_type__new('boolean',''); select acs_sc_msg_type__new('timestamp',''); select acs_sc_msg_type__new('uri',''); select acs_sc_msg_type__new('version',''); select acs_sc_msg_type__new('float',''); select acs_sc_msg_type__new('bytearray',''); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-service-contract-drop.sql0000644000175000017500000000021307344241641031275 0ustar frankiefrankie\i acs-sc-views-drop.sql \i acs-sc-packages-drop.sql \i acs-sc-tables-drop.sql \i acs-sc-object-types-drop.sql \i acs-sc-msg-types-drop.sqlopenacs-5.7.0/packages/acs-service-contract/sql/postgresql/sc-sample-drop.sql0000644000175000017500000000110207344241641027140 0ustar frankiefrankieselect acs_sc_contract__delete('ObjectDisplay'); select acs_sc_msg_type__delete ('ObjectDisplay.Name.InputType'); select acs_sc_msg_type__delete ('ObjectDisplay.Name.OutputType'); select acs_sc_msg_type__delete ('ObjectDisplay.Url.InputType'); select acs_sc_msg_type__delete ('ObjectDisplay.Url.OutputType'); select acs_sc_msg_type__delete ('ObjectDisplay.SampleHello.InputType'); select acs_sc_msg_type__delete ('ObjectDisplay.SampleHello.OutputType'); select acs_sc_impl__delete( 'ObjectDisplay', -- impl_contract_name 'bboard_message' -- impl_name ); openacs-5.7.0/packages/acs-service-contract/sql/postgresql/acs-service-contract-create.sql0000644000175000017500000000022507344241641031577 0ustar frankiefrankie\i acs-sc-msg-types-create.sql \i acs-sc-object-types-create.sql \i acs-sc-tables-create.sql \i acs-sc-packages-create.sql \i acs-sc-views-create.sqlopenacs-5.7.0/packages/acs-service-contract/www/0000755000175000017500000000000011575225534021425 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/www/doc/0000755000175000017500000000000011724401447022165 5ustar frankiefrankieopenacs-5.7.0/packages/acs-service-contract/www/doc/index.html0000644000175000017500000001340507367317674024205 0ustar frankiefrankie ACS Service Contract Documentation

ACS Service Contract Documentation

Why

To facilitate greater code reuse, application integration, and package extensibility within the OpenACS.

To do this acs-service-contract defines an api for the creation of interfaces and discovery of interface implementations.

Background

Most component systems are based on the use of interfaces. Interfaces allow components to create contracts which define their functional level of reuse and customization. It also provides the infrastructure for runtime discovery of which implemented interfaces are available.

The ACS4 is based on a thin object system, that is primarily relational but the acs_objects system allows a veneer of object orientedness by providing globally unique object ids, object metadata, and bundling of data and methods as an object. While this permits a level of reuse on an object or package basis, it requires hardcoding the unit of reuse.

ACS Service contract allows these objects and packages to also define and register their implementation of interfaces, so the level of reuse is defined at the contract level.

In addition ACS Service contract provides mean to dispatch method calls on an interface implementation. The dispatch means is only available through tcl.

Interface Discovery is available programmatically as well as via documentation through ad_proc.

The Service Contract interface specification was inspired by WDSL, the interface specfication for web services.

Hitchiker's Guide to Service Contract Definitions

  • contract - analagous to interface, contracts serve as logical containers for operations.
  • operation - a method of an interface. defines a method signature, including both input and outputs as well as metadata such as caching.
  • implementation - an implementation is a set of concrete functions that fufills an interface.
  • implementation alias - is the method of an implementation that fufills a given operation of the contract.
  • bindings - association between an interface and an implementation.
  • types - define the kind of input and outputs a operation recieves.

Usage

Design the Contract

First Off design the interface for your contract, keeping in mind that all implementations need to implement it and that extension of the contract after deployment is often not practical. In other words take the time to do a little future proofing and thinking about possible uses that you weren't planning on.

Defining Operations

Next define the logical operations that will make up your contract

Register the Contract

with acs contracts.

Implement the Contract

FAQ

Why Does an implementation reference an interface?

This might seem a little strange since a binding is the official reference between an implementation and an interface. However it is quite possible that an implementation for interface might exist prior to the interface being defined, ie the interface defining package is not installed. By retaining this information the interface defining package can be installed and the implementations already installed on the system can be bound to it.

Api Reference

[for oracle please syntax replace __ with .]

Creating Message Types

  • (sql):: acs_sc_msg_type__new (name, spec):

    defines a type based on spec. Spec should be a string (possibly emtpy) that defines the names and types that compose this type. example ObjectDisplay.Name.InputType as name object_id:integer as spec.

Creating Interfaces

  • (sql):
                     acs_sc_contract__new (contract_name, contract_desc):

creates a new contract to serve as a logical container for operations. contract_desc is a text description of the contract.

  • (sql):
                     acs_sc_operation__new (contract_name, operation_name,
                                           operation_desc, operation_iscachable_p,
                                           operation_inputtype, operation_outputtype
                                          ):

creates a new operation as part of a contract.

Creating Implementations

  • (tcl) acs_sc_proc (contract, operation, impl): registers an implementations. ?? why operation

Discovery

  • (tcl) acs_sc_binding_exists_p (contract, impl): returns boolean whether a binding exists between a given contract name and implmentation.

Dispatching

  • (tcl) acs_sc_call (contract, operation, [arguments, impl]): calls an operation

Examples

Included in the service contract package are examples for oracle and postgresql of a trivial contract.

Also the search contract functions as a non-trivial core contract used by openacs4.

Further Reading

Abstract Factory Pattern - GOF

Component Systems - Clemens Syzperski

WSDL Spec

Credits

Most content was provided by Neophytos Demetriou. Most of the errors were provided by Kapil Thangavelu.

openacs-5.7.0/packages/acs-service-contract/www/doc/index.stx0000644000175000017500000001173607367317674024064 0ustar frankiefrankieACS Service Contract Documentation Why To facilitate greater code reuse, application integration, and package extensibility within the OpenACS. To do this acs-service-contract defines an api for the creation of interfaces and discovery of interface implementations. Background Most component systems are based on the use of interfaces. Interfaces allow components to create contracts which define their functional level of reuse and customization. It also provides the infrastructure for runtime discovery of which implemented interfaces are available. The ACS4 is based on a thin object system, that is primarily relational but the acs_objects system allows a veneer of object orientedness by providing globally unique object ids, object metadata, and bundling of data and methods as an object. While this permits a level of reuse on an object or package basis, it requires hardcoding the unit of reuse. ACS Service contract allows these objects and packages to also define and register their implementation of interfaces, so the level of reuse is defined at the contract level. In addition ACS Service contract provides mean to dispatch method calls on an interface implementation. The dispatch means is only available through tcl. Interface Discovery is available programmatically as well as via documentation through ad_proc. The Service Contract interface specification was inspired by WDSL, the interface specfication for web services. Hitchiker's Guide to Service Contract Definitions - contract - analagous to interface, contracts serve as logical containers for operations. - operation - a method of an interface. defines a method signature, including both input and outputs as well as metadata such as caching. - implementation - an implementation is a set of concrete functions that fufills an interface. - implementation alias - is the method of an implementation that fufills a given operation of the contract. - bindings - association between an interface and an implementation. - types - define the kind of input and outputs a operation recieves. Usage Design the Contract First Off design the interface for your contract, keeping in mind that all implementations need to implement it and that extension of the contract after deployment is often not practical. In other words take the time to do a little future proofing and thinking about possible uses that you weren't planning on. Defining Operations Next define the logical operations that will make up your contract Register the Contract with acs contracts. Implement the Contract FAQ Why Does an implementation reference an interface? This might seem a little strange since a binding is the official reference between an implementation and an interface. However it is quite possible that an implementation for interface might exist prior to the interface being defined, ie the interface defining package is not installed. By retaining this information the interface defining package can be installed and the implementations already installed on the system can be bound to it. Api Reference [for oracle please syntax replace __ with .] Creating Message Types - (sql):: acs_sc_msg_type__new (name, spec): defines a type based on spec. Spec should be a string (possibly emtpy) that defines the names and types that compose this type. example 'ObjectDisplay.Name.InputType' as name 'object_id:integer' as spec. Creating Interfaces - (sql):: acs_sc_contract__new (contract_name, contract_desc): creates a new contract to serve as a logical container for operations. contract_desc is a text description of the contract. - (sql):: acs_sc_operation__new (contract_name, operation_name, operation_desc, operation_iscachable_p, operation_inputtype, operation_outputtype ): creates a new operation as part of a contract. Creating Implementations - (tcl) acs_sc_proc (contract, operation, impl): registers an implementations. ?? why operation Discovery - (tcl) acs_sc_binding_exists_p (contract, impl): returns boolean whether a binding exists between a given contract name and implmentation. Dispatching - (tcl) acs_sc_call (contract, operation, [arguments, impl]): calls an operation Examples Included in the service contract package are examples for oracle and postgresql of a trivial contract. Also the search contract functions as a non-trivial core contract used by openacs4. Further Reading Abstract Factory Pattern - GOF Component Systems - Clemens Syzperski WSDL Spec Credits Most content was provided by Neophytos Demetriou. Most of the errors were provided by Kapil Thangavelu. openacs-5.7.0/packages/acs-service-contract/www/doc/index.xml0000644000175000017500000001560007367317674024040 0ustar frankiefrankie
ACS Service Contract Documentation
ACS Service Contract Documentation
Why To facilitate greater code reuse, application integration, and package extensibility within the OpenACS. To do this acs-service-contract defines an api for the creation of interfaces and discovery of interface implementations.
Background Most component systems are based on the use of interfaces. Interfaces allow components to create contracts which define their functional level of reuse and customization. It also provides the infrastructure for runtime discovery of which implemented interfaces are available. The ACS4 is based on a thin object system, that is primarily relational but the acs_objects system allows a veneer of object orientedness by providing globally unique object ids, object metadata, and bundling of data and methods as an object. While this permits a level of reuse on an object or package basis, it requires hardcoding the unit of reuse. ACS Service contract allows these objects and packages to also define and register their implementation of interfaces, so the level of reuse is defined at the contract level. In addition ACS Service contract provides mean to dispatch method calls on an interface implementation. The dispatch means is only available through tcl. Interface Discovery is available programmatically as well as via documentation through ad_proc. The Service Contract interface specification was inspired by WDSL, the interface specfication for web services.
Hitchiker's Guide to Service Contract Definitions contract - analagous to interface, contracts serve as logical containers for operations. operation - a method of an interface. defines a method signature, including both input and outputs as well as metadata such as caching. implementation - an implementation is a set of concrete functions that fufills an interface. implementation alias - is the method of an implementation that fufills a given operation of the contract. bindings - association between an interface and an implementation. types - define the kind of input and outputs a operation recieves.
Usage
Design the Contract First Off design the interface for your contract, keeping in mind that all implementations need to implement it and that extension of the contract after deployment is often not practical. In other words take the time to do a little future proofing and thinking about possible uses that you weren't planning on.
Defining Operations Next define the logical operations that will make up your contract
Register the Contract with acs contracts.
Implement the Contract
FAQ
Why Does an implementation reference an interface? This might seem a little strange since a binding is the official reference between an implementation and an interface. However it is quite possible that an implementation for interface might exist prior to the interface being defined, ie the interface defining package is not installed. By retaining this information the interface defining package can be installed and the implementations already installed on the system can be bound to it.
Api Reference [for oracle please syntax replace __ with .]
Creating Message Types (sql):: acs_sc_msg_type__new (name, spec): defines a type based on spec. Spec should be a string (possibly emtpy) that defines the names and types that compose this type. example ObjectDisplay.Name.InputTypeas name object_id:integeras spec.
Creating Interfaces (sql):
creates a new contract to serve as a logical container for operations. contract_desc is a text description of the contract. (sql): creates a new operation as part of a contract.
Creating Implementations (tcl) acs_sc_proc (contract, operation, impl): registers an implementations. ?? why operation
Discovery (tcl) acs_sc_binding_exists_p (contract, impl): returns boolean whether a binding exists between a given contract name and implmentation.
Dispatching (tcl) acs_sc_call (contract, operation, [arguments, impl]): calls an operation
Examples Included in the service contract package are examples for oracle and postgresql of a trivial contract. Also the search contract functions as a non-trivial core contract used by openacs4.
Further Reading Abstract Factory Pattern - GOF Component Systems - Clemens Syzperski WSDL Spec
Credits Most content was provided by Neophytos Demetriou. Most of the errors were provided by Kapil Thangavelu.
openacs-5.7.0/packages/acs-service-contract/www/doc/notes.html0000644000175000017500000000201707344241641024204 0ustar frankiefrankieACS Service Contract Overview by Neophytos Demetriou (k2pts@yahoo.com) and Kapil Thangavelu (k_vertigo@yahoo.com) Goals - To increase inter-application code reuse by designating interfaces for interaction. - To increase flexibility by allowing developers to reimplement an interface for their needs. - To provide the framework for constructing web services by housing the metadata needed to construct wsdl. - To be low impediment to developers to create interfaces for their packages. - To reduce fixed dependencies in packages. Definitions Interface - An abstract set of operations supported by one or more endpoints. Operation - An abstract description of an action supported by the service. Binding - A concrete implementation for a particular interface. Function - The implementation of an operation. Actors Registrar - An entity that defines the specification of a contract and registers it with the repository. Provider - Provides an implementation of the contract. Dependant - Something that uses a contract. openacs-5.7.0/packages/acs-service-contract/www/contract-display.adp0000644000175000017500000000116607731545010025370 0ustar frankiefrankie Contract @contract_name;noquote@ {@contract_name;noquote@}
  • @contract.operation_name@ - @contract.operation_desc@
    • @contract.inout@ @contract.param@ @contract.param_type@ []

Valid Installed Bindings

openacs-5.7.0/packages/acs-service-contract/www/contract-display.tcl0000644000175000017500000000340510202011401025357 0ustar frankiefrankiead_page_contract { Display a given service contract } { id:integer,notnull } set contract_name [db_string contract_name {select contract_name from acs_sc_contracts where contract_id = :id}] db_multirow contract contract {select o.contract_name, o.operation_name, o.operation_desc, (case when t.msg_type_id = o.operation_inputtype_id then 'input' else 'output' end) as inout, e.element_name as param, e.element_msg_type_isset_p as set_p, et.msg_type_name as param_type from acs_sc_operations o, acs_sc_msg_types t, acs_sc_msg_type_elements e, acs_sc_msg_types et where contract_id = :id and t.msg_type_id in (o.operation_inputtype_id, operation_outputtype_id) and e.msg_type_id = t.msg_type_id and et.msg_type_id = e.element_msg_type_id order by o.contract_name, o.operation_name, t.msg_type_name, e.element_pos } template::list::create \ -name bindings \ -multirow valid_installed_binding \ -elements { impl_name { label "Implementation Name" } impl_pretty_name { label "Label" } impl_owner_name { label "Owner" } uninstall { label {} link_url_eval {[export_vars -base binding-uninstall { contract_id impl_id }]} link_html { title "Uninstall binding" } display_template {Uninstall} sub_class narrow } display { label {} link_url_eval {[export_vars -base binding-display { {id $contract_id} impl_name }]} link_html { title "View this contracts implementation details" } display_template {view} sub_class narrow } } db_multirow valid_installed_binding valid_installed_binding {} openacs-5.7.0/packages/acs-service-contract/www/binding-uninstall.tcl0000644000175000017500000000032607344241641025547 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou } { contract_id:integer impl_id:integer } db_exec_plsql binding_uninstall "select acs_sc_binding__delete($contract_id,$impl_id)" ad_returnredirect "" openacs-5.7.0/packages/acs-service-contract/www/binding-install-postgresql.xql0000644000175000017500000000045307427245733027440 0ustar frankiefrankie postgresql7.1 select acs_sc_binding__new(cast(:contract_id as integer), cast(:impl_id as integer)) openacs-5.7.0/packages/acs-service-contract/www/binding-uninstall-postgresql.xql0000644000175000017500000000040707426132100027760 0ustar frankiefrankie postgresql7.1 select acs_sc_binding__delete(:contract_id,:impl_id) openacs-5.7.0/packages/acs-service-contract/www/binding-install-oracle.xql0000644000175000017500000000052407431105177026471 0ustar frankiefrankie oracle8.1.6 begin acs_sc_binding.new( contract_id => :contract_id, impl_id => :impl_id); end; openacs-5.7.0/packages/acs-service-contract/www/contract-display-postgresql.xql0000644000175000017500000000106407731545010027626 0ustar frankiefrankie postgresql7.1 select b.contract_id, b.impl_id, acs_sc_impl__get_name(b.impl_id) as impl_name, impl.impl_owner_name, impl.impl_pretty_name from acs_sc_bindings b, acs_sc_impls impl where b.contract_id = :id and impl.impl_id = b.impl_id openacs-5.7.0/packages/acs-service-contract/www/binding-install.tcl0000644000175000017500000000032107344241641025177 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou } { contract_id:integer impl_id:integer } db_exec_plsql binding_install "select acs_sc_binding__new($contract_id,$impl_id)" ad_returnredirect "" openacs-5.7.0/packages/acs-service-contract/www/index-postgresql.xql0000644000175000017500000000141307731545010025453 0ustar frankiefrankie postgresql7.1 select q.* from (select b.contract_id, b.impl_id, acs_sc_contract__get_name(contract_id) as contract_name, acs_sc_impl__get_name(b.impl_id) as impl_name, impl.impl_owner_name, impl.impl_pretty_name from acs_sc_bindings b, acs_sc_impls impl where impl.impl_id = b.impl_id) q order by upper(contract_name), contract_name, upper(impl_name), impl_name openacs-5.7.0/packages/acs-service-contract/www/index.adp0000644000175000017500000000116207731545010023213 0ustar frankiefrankie ACS Service Contract @context;noquote@

Defined Contracts

Installed Bindings

Valid Uninstalled Bindings

Invalid Uninstalled Bindings

Orphan Implementations

openacs-5.7.0/packages/acs-service-contract/www/index.tcl0000644000175000017500000000630310070240705023224 0ustar frankiefrankieset context [list] db_multirow defined_contracts defined_contracts { select contract_id, contract_name, contract_desc from acs_sc_contracts order by upper(contract_name), contract_name } template::list::create \ -name contracts \ -multirow defined_contracts \ -elements { contract_name { label "Name" link_url_eval {[export_vars -base contract-display { { id $contract_id } }]} link_html { title "View contract" } } contract_desc { label "Description" } } db_multirow valid_installed_bindings valid_installed_binding {} template::list::create \ -name valid_installed_bindings \ -multirow valid_installed_bindings \ -elements { contract_name { label "Contract" link_url_eval {[export_vars -base contract-display { { id $contract_id } }]} link_html { title "View contract" } } impl_name { label "Implementation" } impl_pretty_name { label "Label" } impl_owner_name { label "Owner" } uninstall { label {} link_url_eval {[export_vars -base binding-uninstall { contract_id impl_id }]} link_html { title "Uninstall binding" } display_template {Uninstall} sub_class narrow } } db_multirow valid_uninstalled_bindings valid_uninstalled_binding {} template::list::create \ -name valid_uninstalled_bindings \ -multirow valid_uninstalled_bindings \ -elements { contract_name { label "Contract" link_url_eval {[export_vars -base contract-display { { id $contract_id } }]} link_html { title "View contract" } } impl_name { label "Implementation" } impl_pretty_name { label "Label" } impl_owner_name { label "Owner" } install { label {} link_url_eval {[export_vars -base binding-install { contract_id impl_id }]} link_html { title "Install binding" } display_template {Install} sub_class narrow } } db_multirow invalid_uninstalled_bindings invalid_uninstalled_binding {} template::list::create \ -name invalid_uninstalled_bindings \ -multirow invalid_uninstalled_bindings \ -elements { contract_name { label "Contract" link_url_eval {[export_vars -base contract-display { { id $contract_id } }]} link_html { title "View contract" } } impl_name { label "Implementation" } impl_pretty_name { label "Label" } impl_owner_name { label "Owner" } } db_multirow orphan_implementations orphan_implementation {} template::list::create \ -name orphan_implementations \ -multirow orphan_implementations \ -elements { impl_contract_name { label "Contract" } impl_name { label "Implementation" } impl_pretty_name { label "Label" } }openacs-5.7.0/packages/acs-service-contract/www/index.xql0000644000175000017500000000163007732027706023263 0ustar frankiefrankie select contract_id, contract_name, impl_name, impl_owner_name, impl_pretty_name, impl_id from valid_uninstalled_bindings order by upper(contract_name), contract_name, upper(impl_name), impl_name select contract_id, contract_name, impl_name, impl_owner_name, impl_pretty_name, impl_id from invalid_uninstalled_bindings order by upper(contract_name), contract_name, upper(impl_name), impl_name select impl_id, impl_name, impl_pretty_name, impl_contract_name from orphan_implementations order by upper(impl_name), impl_name openacs-5.7.0/packages/acs-service-contract/www/binding-display.adp0000644000175000017500000000115310202011401025134 0ustar frankiefrankie Contract @contract_name;noquote@ {@contract_name;noquote@}

Binding @contract_name@

Contract details

  • @contract.operation_name@ - @contract.operation_desc@
    • @contract.inout@ @contract.param@ @contract.param_type@ []
openacs-5.7.0/packages/acs-service-contract/www/binding-display.tcl0000644000175000017500000000503011004037257025172 0ustar frankiefrankiead_page_contract { Display a given service contract @author Jeff Davis @creation-date 2005-02-05 @cvs-id $Id: binding-display.tcl,v 1.3 2008/04/24 08:02:55 gustafn Exp $ } { id impl_name:trim,notnull } set contract_name [db_string contract_name {select contract_name from acs_sc_contracts where contract_id = :id}] db_multirow contract contract { select o.contract_name, o.operation_name, o.operation_desc, (case when t.msg_type_id = o.operation_inputtype_id then 'input' else 'output' end) as inout, e.element_name as param, e.element_msg_type_isset_p as set_p, et.msg_type_name as param_type from acs_sc_operations o, acs_sc_msg_types t, acs_sc_msg_type_elements e, acs_sc_msg_types et where contract_id = :id and t.msg_type_id in (o.operation_inputtype_id, operation_outputtype_id) and e.msg_type_id = t.msg_type_id and et.msg_type_id = e.element_msg_type_id order by o.contract_name, o.operation_name, t.msg_type_name, e.element_pos } template::list::create \ -name binding \ -multirow binding \ -elements { impl_operation_name { label "Operation" } impl_pl { label "Language" } impl_alias { label "Alias" display_template {@binding.impl_alias;noquote@} } } db_multirow -extend {check} binding binding { select impl_operation_name, impl_alias, impl_pl from acs_sc_impl_aliases where impl_name = :impl_name and impl_contract_name = :contract_name order by lower(impl_operation_name) } { if {$impl_pl eq "TCL"} { regsub {^::} $impl_alias {} impl_alias if {[info proc ::$impl_alias] ne ""} { append impl_alias " {[info args ::$impl_alias]}" } elseif {[llength $impl_alias]>1 && [info command ::xotcl::Object] ne "" && [::xotcl::Object isobject [lindex $impl_alias 0]] && [[lindex $impl_alias 0] info methods [lindex $impl_alias 1]] ne ""} { # - it looks like a method, # - we have XOTcl installed, # - the first word is an object, # - the second word is a method for the object, # ... so provide a link to the XOTcl api browser set href "/xotcl/show-object?object=[lindex $impl_alias 0]&show_methods=2" append impl_alias "" \ "" } else { append impl_alias { - NOT FOUND!} } set impl_alias "$impl_alias" } } openacs-5.7.0/packages/acs-service-contract/www/contract-display-oracle.xql0000644000175000017500000000106107731545010026665 0ustar frankiefrankie oracle8.1.6 select b.contract_id, b.impl_id, acs_sc_impl.get_name(b.impl_id) as impl_name, impl.impl_owner_name, impl.impl_pretty_name from acs_sc_bindings b, acs_sc_impls impl where b.contract_id = :id and impl.impl_id = b.impl_id openacs-5.7.0/packages/acs-service-contract/www/index-oracle.xql0000644000175000017500000000140707731545010024520 0ustar frankiefrankie oracle8.1.6 select q.* from (select b.contract_id, b.impl_id, acs_sc_contract.get_name(contract_id) as contract_name, acs_sc_impl.get_name(b.impl_id) as impl_name, impl.impl_owner_name, impl.impl_pretty_name from acs_sc_bindings b, acs_sc_impls impl where impl.impl_id = b.impl_id) q order by upper(contract_name), contract_name, upper(impl_name), impl_name openacs-5.7.0/packages/acs-service-contract/www/binding-uninstall-oracle.xql0000644000175000017500000000047310367523214027035 0ustar frankiefrankie oracle8.1.6 begin acs_sc_binding.del(contract_id => :contract_id, impl_id => :impl_id); end; openacs-5.7.0/packages/acs-service-contract/acs-service-contract.info0000644000175000017500000000274311575167337025511 0ustar frankiefrankie Service Contracts Service Contract Packages t t OpenACS API and UI for service contracts 2011-06-12 3 OpenACS Service contracts defines an API for the creation of interfaces and discovery of interface implementations. Examples are the contracts used for search which provide a means to get content on a given object and to translate an object_id to a url or the contracts used by dotlrn and new-portals to allow packages to provide portalized panes. GPL version 2 3 openacs-5.7.0/packages/acs-content-repository/0000755000175000017500000000000011724401447021210 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/tcl/0000755000175000017500000000000011724401447021772 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/tcl/filter-procs-postgresql.xql0000644000175000017500000000337510174264424027342 0ustar frankiefrankie postgresql7.1 select 0 as tree_level, '' as name , 'Home' as title UNION select t.tree_level, i.name, content_item.get_title(t.context_id) as title from (select o2.context_id, tree_level(o2.tree_sortkey) as tree_level from (select * from acs_objects where object_id = :item_id) o1, acs_objects o2 where context_id <> content_item__get_root_folder() and o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)) t, cr_items i where i.item_id = t.context_id order by tree_level select 1 select content from cr_revisions where revision_id = :revision_id select content_item__get_live_revision(content_item__get_template(:item_id, :context)) as template_id, content_template__get_path(content_item__get_template(:item_id, :context),:template_root) as template_url from dual select content_template__get_path( content_item__get_template(:item_id, :context),:template_root) as template_url from dual openacs-5.7.0/packages/acs-content-repository/tcl/test/0000755000175000017500000000000011575225426022756 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/tcl/test/content-image-test-procs.tcl0000644000175000017500000001006210551254373030310 0ustar frankiefrankiead_library { Procedures to test content::image tcl API @author Hugh Brock @creation-date 2006-01-17 @cvs-id $Id: content-image-test-procs.tcl,v 1.4 2007/01/10 21:22:03 gustafn Exp $ } aa_register_case content_image { content image test } { aa_run_with_teardown \ -rollback \ -test_code { # create a cr_folder set first_folder_id [db_nextval "acs_object_id_seq"] set returned_first_folder_id [content::folder::new \ -folder_id $first_folder_id \ -name "test_folder_${first_folder_id}"] aa_true "Folder created" [expr {$first_folder_id == $returned_first_folder_id}] content::folder::register_content_type \ -folder_id $first_folder_id \ -content_type "image" \ # create a cr_item set first_item_id [db_nextval "acs_object_id_seq"] set returned_first_item_id [content::item::new \ -name "test_item_one" \ -item_id $first_item_id \ -parent_id $first_folder_id \ -content_type "image" \ -storage_type "file"] aa_true "First item created $first_item_id" [expr {$first_item_id == $returned_first_item_id}] # create an image set image_id [db_nextval "acs_object_id_seq"] set returned_image_id [content::revision::new \ -revision_id $image_id \ -item_id $first_item_id \ -title "Test Title" \ -description "Test Description"] aa_true "Basic Image created revision_id $image_id returned_revision_id $returned_image_id " [expr {$image_id == $returned_image_id}] ::item::get_content -revision_id $returned_image_id -array revision_content aa_true "Revision contains correct content" [expr \ [string equal $revision_content(title) "Test Title"] \ && $image_id == $revision_content(revision_id)] content::item::delete -item_id $first_item_id content::folder::unregister_content_type \ -folder_id $first_folder_id \ -content_type "image" \ content::folder::delete -folder_id $first_folder_id } } aa_register_case -cats {api smoke db} image_new { } { aa_run_with_teardown \ -rollback \ -test_code \ { # create a cr_folder set first_folder_id [db_nextval "acs_object_id_seq"] set returned_first_folder_id [content::folder::new \ -folder_id $first_folder_id \ -name "test_folder_${first_folder_id}"] aa_true "Folder created" [expr {$first_folder_id == $returned_first_folder_id}] content::folder::register_content_type \ -folder_id $first_folder_id \ -content_type "image" \ set tmp_filename "[acs_root_dir]/packages/acs-content-repository/tcl/test/test-image-1.jpg" set image_item_id_orig [db_nextval "acs_object_id_seq"] set image_name [ns_mktemp "XXXXXX"] set image_item_id [image::new \ -item_id $image_item_id_orig \ -parent_id $first_folder_id \ -name $image_name \ -tmp_filename $tmp_filename] aa_true "Image Created" [expr {$image_item_id_orig eq $image_item_id}] aa_true "Image CR Item Exists" \ [expr \ {$image_item_id eq \ [content::item::get_id \ -item_path $image_name \ -root_folder_id $first_folder_id]}] } } openacs-5.7.0/packages/acs-content-repository/tcl/test/test-image-1.jpg0000644000175000017500000003673510502043174025656 0ustar frankiefrankieÿØÿàJFIFÈÈÿí:Photoshop 3.08BIMíÈÈ8BIMó8BIM' 8BIMõH/fflff/ff¡™š2Z5-8BIM8BIMPHUT5DPHUT48BIMÿþ'File written by Adobe Photoshop¨ 4.0ÿîAdobed€ÿÛ„              ÿÀð@"ÿÝÿIJ !1AQ"aq2‘¡B±ÁRbr’#ðÑ‚¢Â3CS²Òcsáñ£³$4ÃÓ´%ƒ“TdtE&!1QAaq‘±"2¡ðÁBRr#3Ñá²ÿÚ ?¨Û±²æÙööƒ+îÀ,ªËyÈ•µþrQ‘+acåI›0Íê@ˆ²+­Ùä2¬\-öj”ŒgØöé2&š…òÔ´.èõ¼ý?µö¨¬=¿·µ3û”Å.á&'ªr%r…€·Blukù«+×>|>`ž3g‚MÒ'’’<XfM¾pJúÙR²Ì³zQÇÁéPf›IfÉy‘:C Ï“‹:ò¨û¸ãÉÝ“iX#%Y¢³–q¯UºHûHµ›zmû@î„ôœYå/0l\-üÊ7Ríxcx[Ÿ¿sSeöæTfÏ ™i}E‹/¨8Yc»åô߬{nÒÿâVÖeI?6‡•§ç":ñ&&Ú½få4±ôcPm¨èS§·ª®éw7e3‚Ô¢›:3ˆábô¶„?ïÕl†ÊqcŠÇVŒ¸'Øz«T¸;6—ð2 þÝN»^ÂEÈÆ_ÛÈŒn”Õ&cpa1E0hŒÇ!ÍÛ«¬7©ÿâuôýŠô=»sÜvè'ꎉqN\YÍ&*©S*ÅÐc³µ½?“çªôžßé¹|ŽBŸÈMm#xãØö¼ úHFz”Æ‚Þ_ÕÕj7;mÛºJ«jzAåÉÝÙåD‹<`°¾cÿ•RÖÛ &gHýU‰ÙŽ®ݳ'”}ÏË¡·ªxiÊR.Ð4à™òcÓþÖŸA{µ(%ï ç->é&s´SÿTºÙ•´*l«Æ®·¨#º°°¿©–b¢êZ vVŽßoZì¨6u…ãY1„®§Ò GQaçª}µg¾A0Ýc\@ÝrAŒÍ0 $hذ¤…ÌÏöcEû~wù)®Ìꢜ#PsÄsÃlçmÝG¨¬Ñ¾b Oþ`Ý_û…¯Ó/üF­¯dãúø»ËœÈsc|y)!]@=%Õ¼ÈÍÕö•k7‘xq'“­ºî–±½‡êýšÓö^2írgÅ2¦T61ùT%Í™…‡õh«NÊsÉ•x›|K‹ŒÒ5B]@$JÉ®rà,öևũ™½ êuqéùJëA¶/ …‚ ×áVê$Ê”ÇssÒmÊž1šçÊEX>f~®dÑÁhgTR}…ÈêøR6õ°H=FÝqÿñ/þÈjP‚AR ž4áR xŠ•·=€\Ó Õõþ¥BwM…T¿ú” ?Ù£Èq‰¤ü5ãoMØ!eU%ˆð ù²9 þ¡'bÀ}$U¾2Ç“êA2O ‚pººÞÜ:”‘L’ øreÀ‹ ÀyI {†[Ê>U·Ø_ž²ßˆŽ—•êõz‘68Eºîà3k­kR<‰‰ýeUàEúG¸uQ~"BéØÛ©Ö‰fsñ3L`…IØXqEÔ²I&B‰ \ükO‚™˜‚å¬ÌÃMùzPŸ…(­ØxÇÖ}l=Áøýu³›^!ü"öSH“:#"ÌÍÕ}^`ë’ I¯@]MÍ•>Ö‚]Âeńߡ¤Ð½¸úh/$ŸÐZ¯ÿ®;DèÓd=¹ˆ‚üGCýZ% ‚Ú]Êg¸@~º¯’ig" Řø^‡nóìÿ”¶MΠCÿIzv„MÔ‡$¸àH†ßTƉZ„ |eÀ€<¤õJOÀUFT³JÅ£‘†¿)·×@äwnË™%–yˆä¡ýbJ²Û7Ø™•r¥Èˆ¶¥P~ÑC'Oô©È ´‡©dbn4>ÚÔž }A~5èi³m2FN5žâ૽Ɔ©ó6‡RHˆè®(ÀtñâöŽÙ“’ž¡\©1­Ä­÷Iø7÷r“Íúç™,p;‘Ÿ!r±ñ&’u!®Òd”n«p{·SW¢÷9^ÚÁê¸o¼ô”¹éõ΋À7ÍX_»GÓÝ&5°h±N`³doÉIæ‘uX/4¡ŽçÒ]ÀÒ•”Qâݵ\vf×&Ñ“¸aË"JÉ,]2G{gŒ__Ùªí¯·dÏŃGfºýØ …6Vù“ÊãÍW}£·¾l˜ä`ï/¡-ÑzT^~›ZíúÁCçè%Œ>‡ÿÐÂïÏ3v¦Ø·þß²–@-©)­ÏmVý›žø;$ûtØé™“)—ÒkX\epÀ†SЫ·ˆY»B€³E¹Ìúc§í¡ãÚ!û³,imr/Ǧ³Ým&“ͯI+n©·ÝŠƒ[^Ý…GŸ ¦<)#(TôÕô úÍCo=P£Ք㷷R, /ôÛýêÖàDßwÂl‚aÉÛàûº©êt˜ôª³žÚ·BôõÖ—hü6ÓïÆã”K€SJ„¯&®íû=t;·Ç–}ùS½C¬¬B ñ ;kvUi$p]œ´„8›ù¨ñqÔÙ¯3ƒóÁ>‹ë[ù}¯p“eÙ–E‹Ã2i&’^¹8úcÔféX¾×éIû2…°Ê8ŠÇröžÚà–Û{u‰jCÜõ3~jF™[[:š¯l‚uÖü€¡¤ŸªúØxVJ’l6jz߀Ԋó§$˜åu#˜bøÐ cÄôû8šh`E‡ è9 µD€:-×sBJæÌ¶ä$`°QIÜ›â/HÍ‘—f$}uNZÄ |m]Ôj k¢òÉÜç̘äfF“Ìl=ISXh_å_ÕZÏ<ڃĤ’/öé½ZXÒåsDuóaÛ]Ó‹²ße<ŠNÚ{®¬6mÈl9‹™µO“ ­êÁ3 csY•?ÕûjÂ÷¤½öÄîÓÈŒE•N ±Nʲ ýÂú”ŸˆçmïÝ‹Ÿ…°çG—›xqÅÒW *–éŽ@¬zWÍ^> N £P«ï±ŸðÖe6{ßàÆ;ÇØX#".‡dY€2G…k÷ýÞ‡hÊÜæPÞŠÿ.r7–4þ“Ÿ3}„ó×Ì»~ñ»mo×·n§þ¬ ûÔ“ñ«Ü®úîMÏý;sÊ\Ìb+$h¬n¬†î[äv§ßÈâk,K¾Ûí­Ûñ#pÈß7œ—L¾—˜ d<}¼©-¿R?ø’ú^øiÙøÈá4ß­$²_úŒ‹õV#´¿ Ù0 ÚgÛ•pá ±Ø‡L]‰Y æoÓZô»v^às ¬³Õèʽ,@ãÓ«+[õZ…eâL5€ü9ìÀÌßé·'Æiì=ßÄ©W°;=xmiñyOåzÒWU½J(û3µâ ǶƤp7÷«³»KhÉ£‚%¼Œ·"üº?’¯k©¦×uÄóžÖÎÈÚ÷÷íÜÓkõ pßbEצÿåJ¿Öèý:Û,{‹åz’…X´òƒq¥`{ˆ˜?1¥Sn¥îÉ•ÈèÑKU¹A†µa²áãô1)üDˆ8~d GÐE } HÒã•´#׋cD¼Í'ûµ­ôOÐj;›Já2ÿѦء“+`Ìa4PeõÍ"‹„I#UêoÑ^¡ÓÕQb oD(ôT pÖ×ð9ÕŸvÇ`YP²A¾”ÏÅ}¶ ³xÆÏÅ(ldÏŽ–  êô±-ÿ}±ßÛsÜž VWѵd’¯n#7?Z8ˆ¬4Òý7øëR`_"5ž0okz¦G-Hw±B¹]=ÂÕsÚQmm»bÅœ˜‘<½ +±³9¢/1é 'Ùf¬k\cŒþ15oCw“x;ac'˼b¨ö2^¼£±1•wý÷š0}Ó°·õkÒ÷ܼú[zÊÄ'îë¸Á´=%•zޱÞ{KúˆU^žD±¿ÑÓUýú“dÍÜØ€ðÆ} x[Ëýòµi^eøÅºˆpp6…6iݲdý˜‡B‹IÕý /nÚ·ä=º÷].¿É2²]Ù™˜³1,ìN¤I4 ÊÄ=>WµÆì/kVUGKe¹Ôëüõbt<ùÞ¹|9𹸟Tˆú®I?ì¥ê°6×Ä|)‡;ÚšâòãʨdWÐqåAen‰!Š4õtml£Ùz–y[Y”y”yyêlg…ΤÜIöÓª2Ý»¬%že‰ÞroMóþZ²ÄÍ‹01K£®¬‡—º³Äi¡§âJaÌ…ÁµØ+{›Jn¨Î»–œ\£N¾¿ât¿…FÌ .u×¾Ÿ“Z“ }ÇÇó×r¿ÕQÞÜ4§â>í-z[súi—¥ {Ûé Ž5*“ÆõãÇ<?-!@\nEµ«< Æ|I£ÈÆ‘£š29B¬¼»¬Q7B/[f è>4N&ç ÌT~@óøÐêó3v¬ÄŸFö7wžåÅ’ Εܱ€2"H΂Uÿ+÷«Yzùÿ±÷&Ûû‹oÈVéYdòø”ôû‰V¯ jèåcÀÊõ†uu':Z¢O,ï wÞ-Í€†+þý_MÜY˜Ì ¿d|²=é”WñïòŇÀžªÖãfmâY332 êk©M)ÿЭòð^ƒ·œ¹³»omÊœÞYr r4à%š¨áË _ýt•a¼î¸vöÚz„&iÚH`“ÒÍ*(P ý£ÓTØ“Å>ïµI uÆðGf±¶t èÖ£Eèüß3Õ~B7¬z•O÷ÞžŒÊÓÞhز×mÛ!Þ±b;Žå+ˆ5ä÷m4Öέó7éÒ•ƒ^B´ß9Ž£î9Sfv÷>@uÈž,\©–QÒáä†6~µû/ÔÞjódÜp ÕSŒ1šN©#b:гX+{:§‘W÷«Ð$Ì|®ÇÞšOï~éšíÔ}DŽ Yz¬yÖRcxíbí9[‹1!НèªUÞÑNµÀÏnÛŽK’ëº3qP¬3¡³ac¦¿0«'Ï‚~óíŒÔ=+‘“UÊl’üïÆšçŸZeq<ÏÓM ׇ>¦6€\­Ks{# 7½µ·×Lc]DÑ< l$^’Üm~ž‘^h¥u6?ÏZB¶Ǩ'ÅÆÈ[LVàÃB>"©8#smÛš(:êl½lÈôº!ꇮ$®fp—Õ4¿ÓGÁ<}¯HçÌ“âM7eÀλVœpD£Àpé ɾ–¤$›rçK{o“q·Qâx× ëo…8ÀòãHú¨í>Å%ÈÒÿÊõÚÞÖö×Xh×ú)™R¼xÒÈŸ0ß’ô¢À[6tõqäˆqe6÷ò V˜pS/ TŠÝ$t2½¸èxiáõ·:³ŒÝìó±‰fÌ–`}£_Ê+éüi}|hgÿ5ÿx_,í'£/F¢¾¡Ûcm¸qpD û šgc[åV«««ªÌÏ ïé:?ßäã_ë«™e‰•ÕÚÂÚ{Mg?߉̷á7ä«,…êWPᬘiz~Ao“è½fcÆëÛqƒü3 ¸ºkóúK¦†·­?èÝÜDn§ ‰ã]•¯ûµ‘šVvŒ·ÙŽ>Ÿ`(­ùëG 2vÇqcŒ8ÿÞ²^¿VN8úˆEJ×sWñ©†Ö»š!"ª±òˆ×ã{4ez!fÅH+nDZÇê š@ ~P‡v$‹šŠÑ`nØ~FTù3<óÈÒÊä³Hæä“ãC´ÌŒ’Mùs¦ñJ¾Ô „ –#¤ê<(<…Rn¢Ôâà\pñ¨¤{Š;t‚"ÂÀó®,>Þ 7©àÙ}úU"5[×`l=´Õm*N uäMˆN›Xsµ¯L鱿ÑS­Ä×[ZÞøP}<ízKij’Öµõו6Ü?—i ¥Æ”¼iuÔkq]o¢`•ÖSÊ”a]ÓôP1 é~Wáã\o*u¹¡ä4®µ…̓¹Ð\ð¿Æ»Sr9S.5G²” èiˆ|r®å™þì}²HÌdaÂö|:AöÔ‹n'ãD²޳0‹]±iã…x»ÒÄ/篩£ŒED Â(P}ÂÕó_dbýó¹v¨ºœ˜Ù‡ˆŒúõ-},h§êf[Ù¤u(¨ˆ¢“pňìtãe&´NLüJnŸÅs`qñI?½SÏ<–a¢ÇZñ>toÄÕd7 ‹ˆG.!ÍLdT•Èofo(úZ•†×» ¡e f^Øêù† Äûý\Š1ŸÿôûøÅ ¼ƒUÐäAÿ؃ä@Hç_U<ŽÒÌÝ'_Z3æîŽÝu!ãè ]He¿Þ'ku /j‰›xx/È$?“áùª}ŒõI <†0úóh5>O‡æ©v“ïQCÖºžŽd›­BãÑ‚ÌÿÔÆvÃt÷åà`šãǦX›óPJªP‚ÌÃÆöb8QÛ+z}Õ“ku2>uf‡paËš+X$® ñDþzËáN†¿oóÒ2ôî_Qöñõ¨=Ë&\)±÷X…ý"c•|Q¸_úU7¬YœßC‘2•_‡*¿í[v㊥™eÂËQsmÍmtûu”Úñçl˜›ÔHñä„i÷ýšÞé:ýQͶÚÜ|[P˸åY0cÈ2¨ôØ@ñ›õuÛ«è馴‡€øFÁ·ã œõÍ÷‹—©…ÇZ'ƅ̋їÊÝQ¸¼mÎÜdz­“}ª|Nˆ²žï¡ ½ô5×q¯Qúk•‡*^«Þ´c£ji­®”†Üt¦ÜëH$†BC[꧃åú¾5æÄT±¡qñ4ÉYÀô·òÒ¦KßÚM"(°ï¿þµœx££j„—³;­©ö|‹{ÈMÈ}ôyYy™ÖX›k\RÜ>½*Æm›xÇ$dmù1‘©ê‰ÿšƒtxÍ¥FŒð³-ôÐ4Ó!ÚÓ¿´R‚-¦µÁ€ AüÇØ$ ‹,ºñ¹éˆæW¾ZõólwvGf6nã‡N^Di”°TºÝˆ[3|‹ö–“püJï]з­»Iއü,Eì ƒÔú^^˜^­Údúc&L|xÌ™3$Ž/#_¥ˆ¬OpwÏimQÈFâ™Ù+`1q‘‰ý°}1ûÕóæFVFc™32%Év7-+³›ûØš„0]W‡…? –ÚãÐÕwvE¼oo8Ø ’ÑÇ K!õR UmöTëYüŒÜ¼·2dÌò±Ô–?›…ÒÞIÆ”"Ñ/—ÂŒÛ÷\íªtŸ VÐõÅn?W…W™÷Òú€)4†z†ÏºÅ»bzª:&QiÛì©¶!}êä¿wOêä¶¿½YžÊk´Ö$ÆÂ´{ ƒýsÚ‘4ö&¨YYh™”<ÿÕÅbO¼¦äA•_÷¡Ý:—?2Ú†¿MYOÓÝ‹”œÔŽ_¦åZ‚Þbo¾gL2MG2†økYn|)ÐÓjUßB¥dèßSÈЮúžYµ$Óß[_«CH°ôñ7öÔ¨ÎMs Ñv¤¤É.?C”¤׎6ìÕÚƒÿDÍÐF¾F׫¡ÛæAæ³pZ¹íBîñZýHâßµý•P©haP,Ê%PG,òþJ»|*g_ò¾…ÄR£; J× #êöýãݧíVyÜž,èàÃH ¹”|êK1 }•a…„%£ru6>ú¶Ý¶xcÆÉmµ=921dÈ ‚Ý>“Gê*#ËêTR;°àwlÕ%á,ý·3c>^<˜‡*!4qÎ¥ Sö€kyhU½¾ao}o{«#¹û¶{§‰&Àv½ÑA»Fá@^±úÏRÿÎJóõ µêñRŸSœuz}çê¦5ýÔàAáM ‘nT‹É§P<5©ñGRƒI2ÿ ¯áNÂþéI<ª¸þ¡C‡—€áR%¸ž4ÑÓc¥HÖÇ™çRÍ£Àëùh-ÑѤ-§Q$òà,?-͸Æ…ÏÅAkXk­"’M¤ò=Ëðã¼"îmš<,·¶÷·F±æFxÈ‹ä)HHñ?BZ°îþîÛûKn99?Å˚뇆 žWþÌkþ$ŸÚ¯Ÿ°²ó¶¼Ø7M®vÆÍÇ7ŽU<ÌŽ8ðÿwÜHÑ_'J'ÙŽè‘b¾uêR[Ua¨ óò[ u ðæ=õëýø—¶âöì›grär¶ˆ¿ô’XäÀºG[æÈ‹û¾Ÿ¶ þe:Û|ûŸ·xZ•á #Ñ÷MÓeÀ›sÜæbÀ½RHßR¨ûNß* ù«Îû/ñBmÿ»rv½Ê5ÆÀÜN̦Ýi$áÊã‹ä'Ÿõdþy×wwnåÞÂ|®¨0!bpð/pƒ‡©%´y›ô¾ÇÊ•CÒêD±1ŽXÙdŠD6ee=JÊ|U…Ø…>Íö>ï“Ë‘õ™¸6¡³s`Ûñ'ÎÌ”CŽ,Ò1ÑUEɬ÷aw”=ç¶)TÞñ\üeÓ«’äF?Ë—í–þZóÏÅnñ]Ï$öÆÙ'V+ßq™–Iù`šB|Ïÿö*›ƒž›Vµû"#>G öGzÅÞ{~^LQœiðçhß›©½'óA)ýµù¿]kC40d/NḐˆ‘¿Ú¾pìÎå~ÐßâÜÊ´˜S)ÇÜa^- 7ëAþdMüEþ’ýªõ¾ñüGÚ¶]¾1²Oá¸fÄ$ÄôÏTq£,Ó~üŸ¨œ}›+öÕg‘‘üLÂí½·pÇiQæÃ¯3î–2<ŽËþŽ~U_™|Õˆ·CΣY&È—?;:s6dÝI+êÒ30ê×ìô¯û´àOJÛJÎe¸Ôí¶ÓÚT­›oµ6ß6òËr %üXÔJÆ»-¿Œ=ƒóÓý4øíâɃiaJ¦Ä‹èE©—Ò“¬ Aµ‘Àxð¤,£†¦œ±M=Œi{ëÔtI©>çÒ.Ì\þŒcûGËL–àƒª®6ŽßÌÜó°ñfêÆ‹1€ŽF,¥Šu ?®½5Û›N >Þç+äa¶D…Ï[KŸgä‰júr»ûnùcÇŒXûrò¥·1– —u§©6նǶáˆV bǺƒíÙ/ÝÑø4d|aÈÙ«|§ÝU}·Š§{ÅÌ¿œÍd~¨‹,ßë©É>„æÏÿÖ©–3þ¥é7‘½‡¤ô·×YÍà½J‹¯S+wHµm%€Á8‰ÆŠ×Œû+#»EÓ—0é¹P†ÃÂÖ¬ný«“ÀèU÷§ªeQ¯¥ªVeð`}ÔÐÊ·f$.n-¥f 톸bR¼,£—Ùé $‘‘Pí²&KÜ3:~=u?o?Nû¶»ï5·íÔÆfn ýC_èZÚßɳ ÿ‘ð”Xà§K´ˆnŒ§º´M)lL¬eYJ'…ͯ¡WÛJÎìü,ˆŽ;ŽŸØ”u®®ðU”Ê¢ä”n•O“‡Ò+¾Û§§¡µëß¶×/ª;d˜Ym¶M&ݸ¯NfßR6±ë^?#ùãòù*€ Æ£•]¯páFìÍ` ÄéTŒ½"ÇQzÞø5ÍÛSõ “ôÞÇNt8k{Çä§–Ä)¦$æÈ}”üE´j<µ!·‰±üôTB×ù |ci%Dþz5úkÆ£:}u(Ðjtåð©fÈr‚£Cìüô&y¼Ëo4bñÊÔw÷ê ~zF›%âGo(ÿ¾¸¨azëéJ…&v(âBÂÔ:j-Îô@Vú錇ו ŠÛQŠÈ„ñöW~Zæâ/KÃU>úd@ü\Œ¼ ‘™<˜™J¥Vx£€Â̽KmTiãÄÔœE‡ê$‡Uœ ¼†”½ £Ê$ñÕ#„ ¡MüM0Žøñ¢C·uUéœóº§òð§ôôƾòSE“Úüý—©æ5奩Qàú±ÿ°Q»U¦Õ>¸•¹ƒøÿÑÔê-Ò¢ìx­ødL+*>QÏÚÇÊ*ßÏ$++bÃúDêÕ²Mäy6º«e+ƒ«nSË@ÚHñ"3ͧ HTþܵ&í°ãÁ÷^Ðí¹²så#sÞí3'VŸÂÅP¸Šÿ¡'ñ]Ë«xwÇcû¦41}‘1 |l ÉÞg„à~`ˆ‘ý>˜[Óþ=aþ43þFùx{OÝ¥Ý'9î,À‹ª¯J¯÷ éá2)dm©&ܤúq(-ÄU|Û®J±%B±ãj¨Œ ™ÄÒv†D“gC›Œ|>„÷%ÿY͸fJ;ǦÀâGD}ò<·?*³²óq`É2d’¤ C˜IoëÔ»®DIݳd\úqG¶šÙ.ͧº³w€ÖLÚ‘n¡ì5OÛYäo°a¿ñ¢³þÔyMýš÷¶ÀÀ•i¼Àôÿ ÿ=GÚùxýÉ“¶–0‰q‘Ë‚ª°f°<¼Â¡ÕÅ¥pe'‰ÿ×#6/QQ¡R ŸÍYâFrY²ÏßÞ·­æ*E› ˜ÄÙí§°ÖKÆ‘±ƒH/&;ôŸW5²;c†>RÊÝ$Þ…ÎéxÄ.Ý"Cæ:¨ÉWÌO…Tø¸Ü# FëtN?Æé[Õß µÕ™ÓÏÈfÔÃýK&z¸ë*À~^àkC‰/§‘£B„îZÌáÈ#ßpÁ6ÆÐ·ôú­õÖŽ¡ÍyV7X§ª6£Á­F_"í.)G’àÕ Y«S8$_‰Š?}€ ß1xeÂY¿n!é7õ}:‹_MkY˜|Œ©Xî\ÁŠÈH*ƒÛÏꥎ[ªF¿Ê| Q1iDt‚)Éj«0oMP€J‹sñàª_[r©Eè’’§R<*E[û-ÎkZ\q©R<|?ï©fˆUé°$Þ€ÌäéÈ žvæ)Š=iÉ‹PᜰãN·åã]o©ÀXÐ b9<Â@xuŸËR¸=*µ ‰§Ú¢E–ÚX )—‹3ÿ`ç{¥)ÿ’És8¤7ïkƆW¾¿ƒ4:-øEýý7¨Ó¦×¶ž5ÑWí]ÿ+u õ…¬k½Qÿ}ú(óR¸7ª“2Ge<‡ÆÉé ®„€jfà= ½*Mù^“c-;b)§ÜWžW•Š1‹9ÇÛ^ ­ÒÕ6å8Ÿv–MÎk:³*ŽEýå¤ìÃÿßqÇŽ3êÉNßÑbî]äX<ì?X©½J~æ¹S/:+møhßq˜p;€á‹1þÕb#Ð0:éã[¯ÃBNž-¸3èâ¿óÒÜø¾Ð¥™ÿÐ7o”C–èA×ÝP÷.:I<¦=têøŠt„Å1bx\T[ƒúðãMÂ×F®lë‰Ü׺|;”3DÞVàoÎF}Ù£}y-sín‚*ß1:²ÞM¬Ä+ó]•·Ÿ]L—뉃ÆêlA†«nÊ®xnÑÙGh•¤Ý±Üñõ#ý“jÔn‡«}ܘý¦ŒwM¿5UGƒ&v$±<™)ÔOµ¯añ5iº½ï8“`V"| u«»VÛÃS*']Ô­£)sÝÓ1 š Œ‡Ú<ÕµŠDËŽ,È~YÔ8ö´¿½XYßÖ™¤ òû†‚­ö=Õ0ƒbdõz¨ÝEÊ?=?E©^“U¡Óq+Z^eöê°a ¿ÅŠcéŸëg•ªn.x;;6,Ãü!Þí¡$tð¡l>•ZX–šnV<ÈÕEô©G…0jI©éð¦PƒV©W…øÚ˜¢çN&ŸÀ›9ÛÙAHáÃZ‘šñ¨ƒŸå¥J‡BEÁ>ãzE¡H`n5÷ H'›:$x¬Ç[šbµø|M8“ÌU($Ž ±q¢A価ɰ[Z†§f›oØÃ›cµ¾Z“¹ÅŸÿñ¡·×Cöy#¸0õÿÇõeþj›¹zr檋õc@ÒjW€ø32¤y½Úk[?ÃWtÁôräcñÇqù«§^<¼k_øfûî.¿ãÿðf¥¹ñ}HÿÑ—uoâ!]:õµ’z˜Œ‡^‡½M¹±e_”¿–®;œõH`N¡íŠÑU*¤µ1µ­/B°-ªl]e·°Ÿ£Zˆ)Ði*\ñÓéÉ.baÓm<¯‡*‚"€>06:^³¶léÛ^Ôu­üÔá§ 9\SVúßè¥×•#BXÏe)П…­ùé#âI<)ì :ý? ªk0ð©Ü¸^™â-í§–µÉãÈûi µîÜÇx7PQ{iLà5Ôò§h4½¹PÖvwßqáîS¢§ËrÈ!Ò×Z²ˆýà.x#€>œgû5’¹'ÆÜi΂œ½Y.µyÕ?\߈Üà†ÜÓì¤kõ…¤?ˆÝqmɬC•OÌg÷k+{ u®èe9z±vSö¯#L½õÝq¡_õ9X7 Ÿ#ª¥‹¿û²#Ô7~Ÿ²áX}ÔÖPõmÃq6'Ž‡Æ‰z°ì§í^FÍ?{¦!fš@¾¯ž>à*x?; `Æ™ZÚt±þ‰]`ÏU®ojhã…¨îz‰íí¿ÐD?‹;™½¶ìpy\ÿj©w_Ä.åÜãh Ë‹ ‚¯:…êS¡ Ç©Ž•“,NƒZBM¼MÏP[tYUÂÖ ¯¶£µôçΜn?57æ"¶.è?õóþ~zçÛÎŽÜGTÐ0ÿ)~¦j£Ër+JüQŹó}D@ÜÁ®nž©}Ñ\T𱪠hñ¨æ×Oe†–4ñ÷"£^þÓkw!é?Ô³ÔÝÎþ—qåJ8®4'ßæ5?mìÙ£+ xÅÈŽ7Ǖԣ¡p}#*°µÇWW©Aw,n›æDr?¨ç§"×&CË—ŸÕ<‡Á™ï”ìüÕ«ü6×Ä>J>˜2?š²MóhoZ¿Ã6¾ûŽy}é?ò2in|_Gè4ÿÒsJRöóiUøä æÛ^ÞYDŽên¾«SȬÞË“ð®Z,û<ú[ìwÈW©I÷UC»„ê.jã1Û*7iI(*†cr¨«Çà+¢¹A×Pl‹ô ì]lo ´ë‹>ø1²Q’E… ˜º° ½G.?oÍï¸"Ë‘'nm –R¾¤öóE ›þlŸáôyT¹»Ž~é“÷ÍÆY&‘®¨ò– -ú„qõÓ_ÈŸf«„ï奌ŸV3úÃòÓézPlëìa@ñiáD}ŸÉBg#ÛD+\ÊjlèÛ~ÔH4Qí§sÓé!Ãòð®^>ê“RDµÈ&ëãRx“î½Eb·õÔª57þm!܇·Ä×1:kà>šo>ªVÇü) [uXñ.tÿž“[ÜÿÛ\ÔXñ®:ܓÅ(*MÆ‚ÕÊ,xëN^âmõÓ9–Þ˜‰¿¿ùk]å^FâÚò¦õ¹÷{)OzK‚xü)æÜGcÂÿ\9‘¯¾€~$ü?ì¦k®ºš[–×è÷Ó[ÄaÒèA±à3ØtcHÍÈbl~ƒF ÂÖ¦“¯à|×ã@™dðúÉ ~”·ÐM(Æn¤kî£6ô2cuZö6&Žû«2‹oem_Š87>vêV.:€­íúºS^Hf¢®ªo¦…“ ’|yŠ *$€®šiPü¬HÓÝ¥ZMŒÂàÜÌøÕ^LR"ÞàÛ¹Pj;rؽ³k»dÎsÕÚ²ÝÍ“ÛöD±Û¤cã‚8ð—Ü*ëÍÿNcEëuÉ•úµÀ,yÕ7táâÁ™›•Œ=('ÀÅËÇCÌ>H‰—Þ–·ô)GCY5×Ô/fÆ’/]¢^“Ÿê}ôkA7vâGޝ«4ô²«;ºeÏ0$.ʧÌlxÕáü³äoØÙ2›½GbEî°ä7Ëó}®5{Ý«m¤±€¢s:ŸÿÓ{• ƼI»{…úcJ\ô‚„Þ¸ù’»~•¾ºtÒcbEêfÆf€-Þ¢BÜ:‡›§ôºk ,$ìÜp°3¸{~fR6CºãaFÝ3nß >ŒJ<ÓÎßåGòüòúqùêŸ7> qyïýëBŸ+¿þ^—{îL½Ó DáS!Ñ‹ôGq鈿¥öŸüFvª÷Hä /OñY‡jÕO‘À$í)"V-#77$žfõ}ܧ˵`ƒtÃ[õÕc^1ïo½Iêãm‡¢ ü*ø>¨‡šñC¥s~ÈÛAJIé5#,¤ ¸–öëˆö؃D£*«:oK#oü½$7¹ºEX¡ÓÝ•³4Ûx£|— zßAÀŠO…J­Ì{8T›Õ„q ð:R±%´'Qn:°nu k^üÏ E¢ak‹yŠuô°üÕÍKr´ó>6 d€¥®-Ãþúeø°ü”—ÒÇ Ò›qÔ[AowN®dÒuX[˜åKn:W 5…þ»P‡:¥µãΞ_ê;©'…´ãN<ÈøPI$Ýo¯J¦úUÜm¯¼Ž4‡·0ÆÂþ?a7Ïæ6Ðs¨äf塵ÂÄ[—:^®vµé…Ø~ZåcÇÆ€ú_Ÿ@MÇÓMºñøR+ éñ¦Kf“ivû»t걯aV+'@¸>ñAìØêv虆²±{{ ·æ£Sb>ŠÖ¹#‡qÍíÔ%rÓ&ㆂ |•Ð/ìãO0'EÕm§Â…h¤´~ZdäN¶¶¶ªlǸ6újó/Uo/ª—%¯t^êL¤]ì6m«þt•Œï,‡¬8nßÃÆA ~Ä“<ßGñ+gÛñHû\, #Ö”].z¯Däì[~fJfd㤙ج‡Ç øÚ¥¾S€U¬z³½ÍN"Ç•%HîCÕå¿—òÕá܄︋ËïŠGÆùªÓ}ÚÒÐb㆔›H ’¬zt$©ìÉÜ0èå.GFWs½-Ë7W:~EUÿԮ΅_?¦?”¶÷Õ?teúxV3y5qŸ*ãÄùvé»sX­ÿ+ïÆBÝV’ÃàMe]Ë{V¥bççæiêì¬H4ÞÛÔRÏ…hsƒæŸ(öš?sf\lOÙAÒ«s úG¶æÝuÀÁý‹} iðAÒ¤½åÙSÐR»¯› þ«ÉGáOê㤗ÖÖoxҀϻbbû M®VŽFƒy—ßΆ:8eà:~Z‘ûêU6Ê“dÂS^µ½=|j{kmxÓÃYN´S'×BNµ×øÔA¹“îþj^®'Ÿ/eõxsà…-ôö!Qu m¯;ÓühãÖõÄ߇ôSM†¾<¦–Ö×ÔRÜ<¼P’or/á\Mõ:F˜—ÒÜùšàÄ‹šˆKÔ@µèòÀyÔlÝc^\>Þ«ÞÜi¬G ‹¡·Pã¥!°órµ½”Ât¤.,GL–Ä'] ‡*|¶D±Àš´¬HÚ¡-ÔuáÈQ›~CáåG•U–&u ¡ÏÊYOhÎÏn±ðD-÷`½" );mò·AÔhk8;¹}xßïXòØê=4á¡j÷/¹ûš|u8K‡·\nG&ú|Óúµ¤œ¼Ð@Àš8GH'†´;àÌï—°r§EÜ}î1dý5“‰&5Öáýå1;§¼VŸ»í²Ü‘r:oýcD­~Œ;y¢ œBa77å`jž}º^‚ȤÛÙVQ÷N÷y'lÅtÿ .“zwÖ\P»<\KÞíV—ˆC'Ø:ÎÖøçB2\­€ê[¢p'úU¡“_C*5¾kýU‘Ùû§mx³¥Í\4Q…w[t1*ªúX›_•B­kv­ªÔ𫬖æ>š^½ò5 ߑә¥Ö× ¥bek1¿O ˆµ›ÚÿG*p,8'](“uÖæiaðáQ3=üiC_¾”’±R5åõÒ\aáQuEùÒõ›s<è %áÃOç¦ßBj>£{r:ŠVqbf€”(ý+ò½ýÔÒÜùšoV‡Ý¯¶˜Cjd¶8±à~5byR3‚ÂÞÓz l’ú®–C#úJ¤që ý L…=Csrª 5¸(ˆ§nµòƒÃáM^ØA21kqà select keyword_id from cr_keywords where keyword_id=:keyword_id openacs-5.7.0/packages/acs-content-repository/tcl/test/test.html0000644000175000017500000000014410437316506024616 0ustar frankiefrankie this is a test

this is a test

openacs-5.7.0/packages/acs-content-repository/tcl/test/content-item-test-procs.tcl0000644000175000017500000003017511407232204030161 0ustar frankiefrankie# ad_library { Tests for content item @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 @cvs-id $Id: content-item-test-procs.tcl,v 1.9 2010/06/19 21:20:04 daveb Exp $ } aa_register_case content_item { content item test } { aa_run_with_teardown \ -rollback \ -test_code { ######################################################### # create a cr_folder ######################################################### set first_folder_id [db_nextval "acs_object_id_seq"] set returned_first_folder_id [content::folder::new \ -folder_id $first_folder_id \ -name "test_folder_${first_folder_id}"] content::folder::register_content_type \ -folder_id $first_folder_id \ -content_type "content_revision" aa_true "Folder created" [expr {$first_folder_id == $returned_first_folder_id}] set is_empty [content::folder::is_empty -folder_id $first_folder_id] aa_true "Folder is empty" [string is true $is_empty] ######################################################### # create another cr_folder ######################################################### set second_folder_id [db_nextval "acs_object_id_seq"] set returned_second_folder_id [content::folder::new \ -folder_id $second_folder_id \ -name "test_folder_${second_folder_id}"] aa_true "Folder 2 created" [expr {$second_folder_id == $returned_second_folder_id}] ######################################################### # create a cr_item ######################################################### set test_name "cr_test_item[ad_generate_random_string]" set first_item_id [db_nextval "acs_object_id_seq"] set returned_first_item_id [content::item::new \ -name "$test_name" \ -item_id $first_item_id \ -parent_id $first_folder_id \ -is_live "t" \ -attributes [list [list title "$test_name"]] ] aa_true "First item created" [expr {$first_item_id == $returned_first_item_id}] aa_true "first item exists" [expr {[content::item::get -item_id $first_item_id] == 1}] aa_true "First item's revision exists" \ [expr \ {![string equal "" \ [db_string get_revision "select latest_revision from cr_items, cr_revisions where latest_revision=revision_id and cr_items.item_id=:first_item_id" -default ""]]}] # check the folder is not empty now. set is_empty [content::folder::is_empty -folder_id $first_folder_id] aa_true "Folder 1 is not empty" [string is false $is_empty] ######################################################### # create a cr_item with evil string ######################################################### set evil_string {-Bad [BAD] \077 \{ $Bad } set evil_test_name "${evil_string}cr_test_item[ad_generate_random_string]" aa_log "evil_test_name is $evil_test_name" set evil_item_id [db_nextval "acs_object_id_seq"] set returned_evil_item_id [content::item::new \ -name "${evil_test_name}" \ -item_id $evil_item_id \ -parent_id $first_folder_id \ -attributes [list [list title "${evil_test_name}"]] ] aa_true "Evil_name item created" [expr {$evil_item_id == $returned_evil_item_id}] aa_true "Evil_name item exists" [expr \ [content::item::get \ -item_id $evil_item_id \ -revision latest \ -array_name evil_name] == 1] aa_true "Evil_name item's revision exists" \ [expr \ {$evil_name(latest_revision) ne ""}] ######################################################### # delete the evil_name item ######################################################### # in oracle content_item.del is not a fucntion and cannot # return true or false so we have to rely on a query to # see if the item exists or not content::item::delete -item_id $evil_item_id array unset evil_name aa_true "evil_name item no longer exists" [expr \ [content::item::get \ -item_id $evil_item_id \ -revision "latest" \ -array_name evil_name] == 0] aa_true "evil_name item revision does not exist" [expr \ ![info exists evil(latest_revision)]] ######################################################### # create a new content type ######################################################### catch {content::type::delete -content_type "test_type"} errmsg set new_type_id [content::type::new \ -content_type "test_type" \ -pretty_name "test_type" \ -pretty_plural "test_type" \ -table_name "test_type" \ -id_column "test_id"] ######################################################### # create an attribute ######################################################### content::type::attribute::new \ -content_type "test_type" \ -attribute_name "attribute_name" \ -datatype "text" \ -pretty_name "Attribute Name" \ -pretty_plural "Attribute Names" \ -column_spec "text" # todo test that new item is NOT allowed to be created # unless registered by catching error when creating new # item ######################################################### # register new type to folder ######################################################### content::folder::register_content_type \ -folder_id $first_folder_id \ -content_type "test_type" # create an item of that type set new_type_item_id [db_nextval "acs_object_id_seq"] set returned_new_type_item_id [content::item::new \ -name "test_item_${new_type_item_id}" \ -item_id $new_type_item_id \ -parent_id $first_folder_id \ -is_live "t" \ -content_type "test_type" \ -attributes [list [list title "Title"] [list attribute_name "attribute_value"]]] ######################################################### # check that the item exists ######################################################### aa_true "New Type item created" [expr {$new_type_item_id == $returned_new_type_item_id}] aa_true "New Type item exists" [expr {[content::item::get \ -item_id $new_type_item_id \ -revision "latest" \ -array_name new_type_item] == 1}] ######################################################### # check that extended attribute exists ######################################################### aa_true "Extended attribute set" [expr [string equal "attribute_value" \ $new_type_item(attribute_name)]] ######################################################### # test update of item and attributes ######################################################### content::item::update \ -item_id $new_type_item_id \ -attributes {{name new_name} {publish_status live}} array unset new_type_item content::item::get \ -item_id $new_type_item_id \ -revision "latest" \ -array_name new_type_item aa_true "Item updated $new_type_item(name) $new_type_item(publish_status)" [expr {($new_type_item(name)) eq "new_name" && ($new_type_item(publish_status) eq "live")} ] ######################################################### # copy it ######################################################### #TODO ######################################################### # move the copy ######################################################### #TODO ######################################################### # delete the item ######################################################### #TODO ######################################################### # rename it ######################################################### set new_name "__rename_new_name" content::item::rename \ -item_id $new_type_item_id \ -name $new_name content::item::get \ -item_id $new_type_item_id \ -array_name renamed_item aa_true "Item renamed" \ [expr {$new_name eq $renamed_item(name)}] ######################################################### # publish it ######################################################### #TODO ######################################################### # unpublish it ######################################################### #TODO ######################################################### # new from tmpfile ######################################################### set tmp_item_name [ns_mktemp "__content_item_test_XXXXXX"] set tmp_item_id [content::item::new \ -name $tmp_item_name \ -title $tmp_item_name \ -parent_id $first_folder_id \ -tmp_filename [acs_root_dir]/packages/acs-content-repository/tcl/test/test.html] aa_true "Tmp_filename added cr_item exists" \ [expr {[content::item::get_id \ -item_path $tmp_item_name \ -root_folder_id $first_folder_id] \ eq $tmp_item_id}] aa_true "Tmp_filename added cr_revision exists" \ [expr {[content::item::get_latest_revision \ -item_id $tmp_item_id] ne ""}] ######################################################### # delete first folder and everything in it to clean up ######################################################### content::folder::delete \ -folder_id $second_folder_id content::folder::delete \ -folder_id $first_folder_id \ -cascade_p "t" } } openacs-5.7.0/packages/acs-content-repository/tcl/test/acs-content-repository-procs.tcl0000644000175000017500000000330710210730322031221 0ustar frankiefrankiead_library { Automated tests. @author Joel Aufrecht @creation-date 2 Nov 2003 @cvs-id $Id: acs-content-repository-procs.tcl,v 1.3 2005/03/01 00:01:22 jeffd Exp $ } aa_register_case -cats {smoke api} acs_content_repository_trivial_smoke_test { Minimal smoke test. } { aa_run_with_teardown \ -rollback \ -test_code { # initialize random values set name [ad_generate_random_string] set name_2 [ad_generate_random_string] # there is no function in the api to directly retrieve a key # so instead we have to create a child of another and then # retrieve the parent's child set new_keyword_id [cr::keyword::new -heading $name] aa_true "created a new cr_keyword" [exists_and_not_null new_keyword_id] set new_keyword_id_2 [cr::keyword::new -heading $name_2 -parent_id $new_keyword_id] aa_true "created a child cr_keyword" [exists_and_not_null new_keyword_id_2] set children [cr::keyword::get_children -parent_id $new_keyword_id ] aa_true "child is returned" [string match "*$new_keyword_id_2*" $children] set delete_result [content::keyword::delete -keyword_id $new_keyword_id_2] set children_after_delete [cr::keyword::get_children -parent_id $new_keyword_id ] aa_true "child is not returned after deletion" ![string match "*$new_keyword_id_2*" $children_after_delete] # teardown doesn't seem to eliminate this: set delete_result [content::keyword::delete -keyword_id $new_keyword_id] # would test that delete works but there's no relevant function in the API } }openacs-5.7.0/packages/acs-content-repository/tcl/content-revision-procs-postgresql.xql0000644000175000017500000000377610474400735031370 0ustar frankiefrankie postgresql 7.3 update cr_revisions set content=:content where revision_id=:revision_id select item_id from cr_revisions where revision_id = :revision_id update cr_revisions set mime_type = :mime_type, lob = [set __lob_id [db_string get_lob_id "select empty_lob()"]] where revision_id = :revision_id update cr_revisions set content_length = lob_length(lob) where revision_id = :revision_id update cr_revisions set content = :filename, mime_type = :mime_type, content_length = :tmp_size where revision_id = :revision_id select storage_area_key, content as filename from cr_items ci, cr_revisions cr where cr.item_id=ci.item_id and cr.revision_id=:revision_id openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-procs-oracle.xql0000644000175000017500000000071707622727355031562 0ustar frankiefrankie oracle8.1.6 select distinct crftd.path, crftd.storage_area_key from cr_files_to_delete crftd where not exists (select 1 from cr_revisions r where r.filename = crftd.path) openacs-5.7.0/packages/acs-content-repository/tcl/keyword-procs-postgresql.xql0000644000175000017500000000262410024403020027512 0ustar frankiefrankie postgresql7.1 select content_keyword__new ( :heading, :description, :parent_id, :keyword_id, current_timestamp, :user_id, :creation_ip, :object_type, :package_id ) select content_keyword__delete (:keyword_id) select content_keyword__set_heading(:keyword_id, :heading) select content_keyword__item_unassign(:item_id, :keyword_id) select content_keyword__item_assign( :item_id, :keyword, null, null, null ) openacs-5.7.0/packages/acs-content-repository/tcl/item-procs-postgresql.xql0000644000175000017500000000116610607655035027012 0ustar frankiefrankie postgresql7.1 , content as text select 't' from cr_revisions r, cr_items i where r.revision_id = :revision_id and i.item_id = r.item_id and ((r.content is not null and i.storage_type in ('text','file')) or (r.lob is not null and i.storage_type = 'lob')) openacs-5.7.0/packages/acs-content-repository/tcl/keyword-procs-oracle.xql0000644000175000017500000000305210024403020026550 0ustar frankiefrankie oracle8.1.6 begin :1 := content_keyword.new ( :heading, :description, :parent_id, :keyword_id, sysdate(), :user_id, :creation_ip, :object_type, :package_id ); end; begin content_keyword.del(:keyword_id); end; begin content_keyword.set_heading(:keyword_id, :heading); end; begin content_keyword.item_unassign(:item_id, :keyword_id); end; begin content_keyword.item_assign( :item_id, :keyword, null, null, null ); end; openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-callback-procs.tcl0000644000175000017500000000415410665515105032013 0ustar frankiefrankie# packages/acs-content-repository/tcl/acs-content-repository-callback-procs.tcl ad_library { Callback procs for acs-content-repository @author Malte Sussdorff (sussdorff@sussdorff.de) @creation-date 2005-06-15 @arch-tag: d9aec4df-102d-4b0d-8d0e-3dc470dbe783 @cvs-id $Id: acs-content-repository-callback-procs.tcl,v 1.5 2007/08/30 10:21:57 maltes Exp $ } ad_proc -public -callback subsite::parameter_changed -impl acs-content-repository { -package_id:required -parameter:required -value:required } { Implementation of subsite::parameter_changed for acs-content-repository. This is needed as we can change the CRFileLocationRoot parameter. As the cr_fs_path is stored in an NSV we would need to update the NSV the moment we change the parameter so we don't need to restart the server. @author Malte Sussdorff (malte.sussdorff@cognovis.de) @creation-date 2005-10-29 @param package_id the package_id of the package the parameter was changed for @param parameter the parameter name @param value the new value } { ns_log Debug "subsite::parameter_changed -impl acs-content-repository called for $parameter" set package_key [apm_package_key_from_id $package_id] if {$package_key eq "acs-content-repository" && $parameter eq "CRFileLocationRoot" && $value ne ""} { nsv_unset CR_LOCATIONS CR_FILES # Take the directory from the FileLocation parameter that # must be specified in acs-content-repository package. set relativepath_p [parameter::get_from_package_key -package_key "acs-content-repository" -parameter FileLocationRelativeP] set file_location "" if {$relativepath_p} { # The file location is relative to acs_root_dir append file_location "[acs_root_dir]/" } append file_location [parameter::get_from_package_key -package_key "acs-content-repository" -parameter "CRFileLocationRoot" -default "content-repository-content-files"] nsv_set CR_LOCATIONS CR_FILES "$file_location" } else { ns_log Debug "subsite::parameter_changed -impl acs-content-repository don't care about $parameter" } } openacs-5.7.0/packages/acs-content-repository/tcl/content-revision-procs-oracle.xql0000644000175000017500000000400411232053743030407 0ustar frankiefrankie oracle 8.1.6 update cr_revisions set content = empty_blob() where revision_id = :revision_id returning content into :1 update $lob_table set $lob_attribute = empty_clob() where $lob_id_column = :revision_id returning $lob_attribute into :1 select item_id from cr_revisions where revision_id = :revision_id update cr_revisions set content_length = lob_length(lob) where revision_id = :revision_id update cr_revisions set filename = :filename, mime_type = :mime_type, content_length = :tmp_size where revision_id = :revision_id select storage_area_key, filename from cr_items ci, cr_revisions cr where cr.item_id=ci.item_id and cr.revision_id=:revision_id openacs-5.7.0/packages/acs-content-repository/tcl/content-permission-procs.tcl0000644000175000017500000001105010067326447027464 0ustar frankiefrankie# ad_library { These should probably just use the regular old permission procedures @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-09 @arch-tag: da21d1e8-0729-4f3b-8bef-3b847a979fec @cvs-id $Id: content-permission-procs.tcl,v 1.3 2004/06/26 17:06:47 jeffd Exp $ } namespace eval ::content::permission {} ad_proc -public content::permission::cm_admin_exists { } { @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ ] content_permission cm_admin_exists] } ad_proc -public content::permission::grant_permission { -object_id:required -holder_id:required -privilege:required -recepient_id:required {-is_recursive ""} {-object_type ""} } { @param object_id @param holder_id @param privilege @param recepient_id @param is_recursive @param object_type } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list holder_id $holder_id ] \ [list privilege $privilege ] \ [list recepient_id $recepient_id ] \ [list is_recursive $is_recursive ] \ [list object_type $object_type ] \ ] content_permission grant_permission] } ad_proc -public content::permission::grant_permission_h { -object_id:required -grantee_id:required -privilege:required } { @param object_id @param grantee_id @param privilege } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list grantee_id $grantee_id ] \ [list privilege $privilege ] \ ] content_permission grant_permission_h] } ad_proc -public content::permission::has_grant_authority { -object_id:required -holder_id:required -privilege:required } { @param object_id @param holder_id @param privilege @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list holder_id $holder_id ] \ [list privilege $privilege ] \ ] content_permission has_grant_authority] } ad_proc -public content::permission::has_revoke_authority { -object_id:required -holder_id:required -privilege:required -revokee_id:required } { @param object_id @param holder_id @param privilege @param revokee_id @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list holder_id $holder_id ] \ [list privilege $privilege ] \ [list revokee_id $revokee_id ] \ ] content_permission has_revoke_authority] } ad_proc -public content::permission::inherit_permissions { -parent_object_id:required -child_object_id:required {-child_creator_id ""} } { @param parent_object_id @param child_object_id @param child_creator_id } { return [package_exec_plsql -var_list [list \ [list parent_object_id $parent_object_id ] \ [list child_object_id $child_object_id ] \ [list child_creator_id $child_creator_id ] \ ] content_permission inherit_permissions] } ad_proc -public content::permission::permission_p { -object_id:required -holder_id:required -privilege:required } { @param object_id @param holder_id @param privilege @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list holder_id $holder_id ] \ [list privilege $privilege ] \ ] content_permission permission_p] } ad_proc -public content::permission::revoke_permission { -object_id:required -holder_id:required -privilege:required -revokee_id:required {-is_recursive ""} {-object_type ""} } { @param object_id @param holder_id @param privilege @param revokee_id @param is_recursive @param object_type } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list holder_id $holder_id ] \ [list privilege $privilege ] \ [list revokee_id $revokee_id ] \ [list is_recursive $is_recursive ] \ [list object_type $object_type ] \ ] content_permission revoke_permission] } ad_proc -public content::permission::revoke_permission_h { -object_id:required -revokee_id:required -privilege:required } { @param object_id @param revokee_id @param privilege } { return [package_exec_plsql -var_list [list \ [list object_id $object_id ] \ [list revokee_id $revokee_id ] \ [list privilege $privilege ] \ ] content_permission revoke_permission_h] } openacs-5.7.0/packages/acs-content-repository/tcl/symlink-procs-postgresql.xql0000644000175000017500000000314410171476702027536 0ustar frankiefrankie postgresql7.1 select content_symlink__new ( :name, :label, :target_id, :parent_id, :symlink_id, current_timestamp, :creation_user, :creation_ip, :package_id ); update acs_objects set last_modified = current_timestamp, modifying_user = :modifying_user, modifying_ip = :modifying_ip, title = :label where object_id = :symlink_id select content_symlink__delete ( :symlink_id ); select content_symlink__is_symlink ( :item_id ); select content_symlink__resolve ( :item_id ); select content_symlink__resolve_content_type ( :item_id ); openacs-5.7.0/packages/acs-content-repository/tcl/search-procs.tcl0000644000175000017500000001046011164404157025067 0ustar frankiefrankiead_proc content_search__datasource { object_id } { Provides data source for search interface. Used to access content items after search. } { db_0or1row revisions_datasource " select r.revision_id as object_id, r.title, case i.storage_type when 'lob' then r.lob::text when 'file' then '[cr_fs_path]' || r.content else r.content end as content, r.mime_type as mime, '' as keywords, i.storage_type from cr_revisions r, cr_items i where revision_id = :object_id and i.item_id = r.item_id " -column_array datasource if { $datasource(storage_type) ne "lob" } { set datasource(storage_type) "text" set datasource(content) [cr_write_content -string -revision_id $object_id ] } return [array get datasource] } ad_proc content_search__url { object_id } { Provides a url for linking to content items which show up in a search result set. } { set package_id [apm_package_id_from_key acs-content-repository] db_1row get_url_stub " select site_node__url(node_id) as root_url, (select content_item__get_path(item_id,content_item__get_root_folder(null)) from cr_revisions where revision_id = :object_id) as url from site_nodes n where n.object_id = :package_id " return "[ad_url]$root_url$url?revision_id=$object_id" } ad_proc image_search__datasource { object_id } { Provides data source for search interface. Used to access content items after search. } { db_0or1row revisions_datasource { select r.revision_id as object_id, r.title as title, r.description as content, r.mime_type as mime, '' as keywords, 'text' as storage_type from cr_revisions r where revision_id = :object_id } -column_array datasource return [array get datasource] } ad_proc image_search__url { object_id } { Provides a url for linking to content items which show up in a search result set. } { set package_id [apm_package_id_from_key acs-content-repository] db_1row get_url_stub " select site_node__url(node_id) as root_url, (select content_item__get_path(item_id,null) from cr_revisions where revision_id = :object_id) as url from site_nodes n where n.object_id = :package_id " return "[ad_url][string trimright $root_url /]$url?revision_id=$object_id" } ad_proc template_search__datasource { object_id } { Provides data source for search interface. Used to access content items after search. } { db_0or1row revisions_datasource " select r.revision_id as object_id, r.title as title, case i.storage_type when 'lob' then r.lob::text when 'file' then '[cr_fs_path]' || r.content when 'text' then r.content else r.content end as content, r.mime_type as mime, '' as keywords, i.storage_type from cr_revisions r, cr_items i where revision_id = :object_id and i.item_id = r.item_id " -column_array datasource return [array get datasource] } ad_proc template_search__url { object_id } { Provides a url for linking to content items which show up in a search result set. } { set package_id [apm_package_id_from_key acs-content-repository] db_1row get_url_stub " select site_node__url(node_id) as root_url, (select content_item__get_path(item_id,null) from cr_revisions where revision_id = :object_id) as url from site_nodes n where n.object_id = :package_id " return "[ad_url][string trimright $root_url /]$url?revision_id=$object_id" } ad_proc content_search__search_ids { q { offset 0 } { limit 100 } } { Returns the object ids for a specified search. } { set package_id [apm_package_id_from_key search] set driver [parameter::get -package_id $package_id -parameter FtsEngineDriver] array set result [acs_sc_call FtsEngineDriver search [list $q $offset $limit] $driver] return $result(ids) } openacs-5.7.0/packages/acs-content-repository/tcl/publish-procs-postgresql.xql0000644000175000017500000000261107351303470027511 0ustar frankiefrankie postgresql7.1 select 1 select content from cr_revisions where revision_id = :revision_id select case when i.storage_type = 'file' then '[cr_fs_path]' || r.content when i.storage_type = 'lob' then lob::text else r.content end as content, i.storage_type from cr_revisions r, cr_items i where r.item_id = i.item_id and r.revision_id = $revision_id select 1 select content from cr_revisions where revision_id = :revision_id openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-init.tcl0000644000175000017500000000342210673662316030101 0ustar frankiefrankietemplate::filter add content::init # a patch to the cr for handling the deleting revision's files # when the revision has been deleted from the database # schedules the sweep # # Walter McGinnis (wtem@olywa.net), 2001-09-23 # based on original photo-album package code by Tom Baginski # Daveb: unless someone has a good reason this should go away for openacs 5.1 # we should promote a tcl api to the cr instead of each package accessing # the pl/sql procs directly. ad_schedule_proc -thread t -schedule_proc ns_schedule_daily [list 22 0] cr_delete_scheduled_files ad_proc -public acs_cr_scheduled_release_exec {} { This was handled by oracle, but since other dbs, such as postgresql don't support job submission, the job scheduling has been moved to aolserver. (OpenACS - DanW) } { db_exec_plsql schedule_releases {begin cr_scheduled_release_exec; end;} } ad_schedule_proc [expr {15 * 60}] acs_cr_scheduled_release_exec nsv_set CR_LOCATIONS . "" if {![nsv_exists CR_LOCATIONS CR_FILES]} { # Take the directory from the FileLocation parameter that # must be specified in acs-content-repository package. set relativepath_p [parameter::get_from_package_key -package_key "acs-content-repository" -parameter FileLocationRelativeP -default "1"] set file_location "" if {$relativepath_p} { # The file location is relative to acs_root_dir append file_location "[acs_root_dir]/" } append file_location [parameter::get_from_package_key -package_key "acs-content-repository" -parameter "CRFileLocationRoot" -default "content-repository-content-files"] nsv_set CR_LOCATIONS CR_FILES "$file_location" } ## ## At boot time, we should scan AOLserver mime types and insert them if they're ## not there already. (ben@openforce) ## cr_scan_mime_types openacs-5.7.0/packages/acs-content-repository/tcl/filter-procs-oracle.xql0000644000175000017500000000276510174264424026406 0ustar frankiefrankie oracle8.1.6 select 0 as tree_level, '' as name , 'Home' as title from dual UNION select t.tree_level, i.name, content_item.get_title(t.context_id) as title from ( select context_id, level as tree_level from acs_objects where context_id <> content_item.get_root_folder connect by prior context_id = object_id start with object_id = :item_id ) t, cr_items i where i.item_id = t.context_id order by tree_level begin content_revision.to_temporary_clob(:revision_id); end; select content from cr_content_text where revision_id = :revision_id select content_item.get_live_revision(content_item.get_template(:item_id, :context)) as template_id, content_template.get_path(content_item.get_template(:item_id, :context), :template_root) as template_url from dual openacs-5.7.0/packages/acs-content-repository/tcl/content-extlink-procs.tcl0000644000175000017500000000567511145370162026761 0ustar frankiefrankie# packages/acs-content-repository/tcl/content-extlink-procs.tcl ad_library { Procedures for content_extlink @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-09 @arch-tag: f8f62c6c-bf3b-46d9-8e1e-fa5e60ba1c05 @cvs-id $Id: content-extlink-procs.tcl,v 1.7 2009/02/13 22:13:06 jeffd Exp $ } namespace eval ::content::extlink {} ad_proc -public content::extlink::copy { -extlink_id:required -target_folder_id:required -creation_user:required {-creation_ip ""} } { @param extlink_id extlink to copy @param target_folder_id folder to copy extlink into @param creation_user @param creation_ip @return 0 } { return [package_exec_plsql -var_list [list \ [list extlink_id $extlink_id ] \ [list target_folder_id $target_folder_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ ] content_extlink copy] } ad_proc -public content::extlink::new { {-extlink_id ""} -url:required -parent_id:required {-name ""} {-label ""} {-description ""} {-package_id ""} } { @param Create a new external link. @return 0 } { return [package_exec_plsql -var_list [list \ [list extlink_id $extlink_id ] \ [list url $url ] \ [list parent_id $parent_id ] \ [list name $name ] \ [list label $label ] \ [list description $description ] \ [list package_id $package_id ] \ ] content_extlink new] } ad_proc -public content::extlink::edit { -extlink_id:required -url:required -label:required -description:required } { Edit an existing external link. The parameters are required because it is assumed that the caller will be pulling the existing values out of the database before editing them. @extlink_id Optional pre-assigned object_id for the link @url The URL of the external resource @label Label for the extlink (defaults to the URL) @description An extended description of the link (defaults to NULL) } { set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml extlink_update_object {} db_dml extlink_update_extlink {} } } ad_proc -public content::extlink::delete { -extlink_id:required } { @param extlink_id item_id of extlink to delete @return 0 } { return [package_exec_plsql -var_list [list \ [list extlink_id $extlink_id ] \ ] content_extlink del] } ad_proc -public content::extlink::is_extlink { -item_id:required } { @param item_id item_id to check @return 1 if extlink, otherwise 0 } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_extlink is_extlink] } ad_proc -public content::extlink::name { -item_id:required } { Returns the name of an extlink @item_id The object id of the item to check. } { return [db_string get {}] } openacs-5.7.0/packages/acs-content-repository/tcl/content-extlink-procs.xql0000644000175000017500000000155411145370162026773 0ustar frankiefrankie update cr_extlinks set url = :url, label = :label, description = :description where extlink_id = :extlink_id update acs_objects set last_modified = current_timestamp, modifying_user = :modifying_user, modifying_ip = :modifying_ip, title = :label where object_id = :extlink_id select label from cr_extlinks where extlink_id = :item_id openacs-5.7.0/packages/acs-content-repository/tcl/publish-procs-oracle.xql0000644000175000017500000000274207351303470026560 0ustar frankiefrankie oracle8.1.6 begin content_revision.to_temporary_clob(:revision_id); end; select content from cr_content_text where revision_id = :revision_id select [ad_decode $storage_type file "'[cr_fs_path]' || filename" content] from cr_revisions where revision_id = $revision_id begin content_revision.to_temporary_clob(:revision_id); end; select content from cr_content_text where revision_id = :revision_id openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-init-oracle.xql0000644000175000017500000000046007277414751031371 0ustar frankiefrankie oracle8.1.6 begin cr_scheduled_release_exec; end; openacs-5.7.0/packages/acs-content-repository/tcl/content-type-procs.tcl0000644000175000017500000002477511506400166026265 0ustar frankiefrankie# ad_library { Procedures for content types @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-09 @arch-tag: 4a8a3652-fd5d-49aa-86fc-fade683f06ce @cvs-id $Id: content-type-procs.tcl,v 1.12 2010/12/28 15:21:26 gustafn Exp $ } namespace eval ::content::type {} namespace eval ::content::type::attribute {} ad_proc -public content::type::new { -content_type:required {-supertype "content_revision"} -pretty_name:required -pretty_plural:required -table_name:required -id_column:required {-name_method ""} } { @param content_type @param supertype @param pretty_name @param pretty_plural @param table_name @param id_column @param name_method @return type_id } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list supertype $supertype ] \ [list pretty_name $pretty_name ] \ [list pretty_plural $pretty_plural ] \ [list table_name $table_name ] \ [list id_column $id_column ] \ [list name_method $name_method ] \ ] content_type create_type] } ad_proc -public content::type::delete { -content_type:required {-drop_children_p ""} {-drop_table_p ""} {-drop_objects_p "f"} } { @param content_type @param drop_children_p @param drop_table_p @param drop_objets_p Drop the objects of this content type along with all entries in cr_items and cr_revisions. Will not be done by default. } { if {$drop_objects_p eq "f"} { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list drop_children_p $drop_children_p ] \ [list drop_table_p $drop_table_p ] \ ] content_type drop_type] } else { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list drop_children_p $drop_children_p ] \ [list drop_table_p $drop_table_p ] \ [list drop_objects_p $drop_objects_p ] \ ] content_type drop_type] } } ad_proc -public content::type::attribute::new { -content_type:required -attribute_name:required -datatype:required -pretty_name:required {-pretty_plural ""} {-sort_order ""} {-default_value ""} {-column_spec ""} } { @param content_type @param attribute_name @param datatype @param pretty_name @param pretty_plural @param sort_order @param default_value @param column_spec Specification for column to pass to the database. Not optional if the column does not already exist in the table. @return attribute_id for created attribute } { if {[db_type] eq "oracle"} { switch -- $column_spec { text { set column_spec clob } boolean { set column_spec "char(1)" } } } else { switch -- $column_spec { clob { set column_spec text } } } return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list attribute_name $attribute_name ] \ [list datatype $datatype ] \ [list pretty_name $pretty_name ] \ [list pretty_plural $pretty_plural ] \ [list sort_order $sort_order ] \ [list default_value $default_value ] \ [list column_spec $column_spec ] \ ] content_type create_attribute] } ad_proc -public content::type::attribute::delete { -content_type:required -attribute_name:required {-drop_column ""} } { @param content_type @param attribute_name @param drop_column } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list attribute_name $attribute_name ] \ [list drop_column $drop_column ] \ ] content_type drop_attribute] } ad_proc -public content::type::get_template { -content_type:required {-use_context "public"} } { @param content_type @param use_context @return template_id } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list use_context $use_context ] \ ] content_type get_template] } ad_proc -public content::type::is_content_type { -object_type:required } { @param object_type @return t or f } { return [package_exec_plsql -var_list [list \ [list object_type $object_type ] \ ] content_type is_content_type] } ad_proc -public content::type::refresh_view { -content_type:required } { @param content_type Creates or replaces the view associated with the supplied content type. By convention, this view is called TYPEx . } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ ] content_type refresh_view] } ad_proc -public content::type::register_child_type { -parent_type:required -child_type:required {-relation_tag ""} {-min_n ""} {-max_n ""} } { @param parent_type @param child_type @param relation_tag @param min_n @param max_n @return 0 } { return [package_exec_plsql -var_list [list \ [list parent_type $parent_type ] \ [list child_type $child_type ] \ [list relation_tag $relation_tag ] \ [list min_n $min_n ] \ [list max_n $max_n ] \ ] content_type register_child_type] } ad_proc -public content::type::register_mime_type { -content_type:required -mime_type:required } { Associate a content_type with a mime_type (both params are strings, e.g. folder , application/pdf ) @param content_type @param mime_type @return 0 } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list mime_type $mime_type ] \ ] content_type register_mime_type] } ad_proc -public content::type::register_relation_type { -content_type:required -target_type:required {-relation_tag ""} {-min_n ""} {-max_n ""} } { @param content_type @param target_type @param relation_tag @param min_n @param max_n @return 0 } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list target_type $target_type ] \ [list relation_tag $relation_tag ] \ [list min_n $min_n ] \ [list max_n $max_n ] \ ] content_type register_relation_type] } ad_proc -public content::type::register_template { -content_type:required -template_id:required {-use_context "public"} {-is_default ""} } { @param content_type @param template_id @param use_context @param is_default } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list template_id $template_id ] \ [list use_context $use_context ] \ [list is_default $is_default ] \ ] content_type register_template] } ad_proc -public content::type::rotate_template { -template_id:required -content_type:required {-use_context "public"} } { Force all items of content_type to use a new template. This will also cause items of this content type with no template assigned to use the new template. Finally, sets new template as default for this type. (IS THIS RIGHT ???? ----------------- ??????? ) @param template_id @param content_type @param use_context } { return [package_exec_plsql -var_list [list \ [list template_id $template_id ] \ [list content_type $v_content_type ] \ [list use_context $use_context ] \ ] content_type rotate_template] } ad_proc -public content::type::set_default_template { -content_type:required -template_id:required {use_context "public"} } { @param content_type @param template_id @param use_context @return 0 } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list template_id $template_id ] \ [list use_context $use_context ] \ ] content_type set_default_template] } ad_proc -public content::type::unregister_child_type { -parent_type:required -child_type:required {-relation_tag ""} } { @param parent_type @param child_type @param relation_tag @see content::type::register_child_type @return 0 } { return [package_exec_plsql -var_list [list \ [list parent_type $parent_type ] \ [list child_type $child_type ] \ [list relation_tag $relation_tag ] \ ] content_type unregister_child_type] } ad_proc -public content::type::unregister_mime_type { -content_type:required -mime_type:required } { @param content_type @param mime_type @see content::type::register_mime_type @return 0 } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list mime_type $mime_type ] \ ] content_type unregister_mime_type] } ad_proc -public content::type::unregister_relation_type { -content_type:required -target_type:required {-relation_tag ""} } { @param content_type @param target_type @param relation_tag @see content::type::register_relation_type @return 0 } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list target_type $target_type ] \ [list relation_tag $relation_tag ] \ ] content_type unregister_relation_type] } ad_proc -public content::type::unregister_template { {-content_type ""} -template_id:required {-use_context ""} } { @param content_type @param template_id @param use_context @see content::type::register_template @return 0 } { return [package_exec_plsql -var_list [list \ [list content_type $content_type ] \ [list template_id $template_id ] \ [list use_context $use_context ] \ ] content_type unregister_template] } ad_proc -public content::type::content_type_p { -content_type:required -mime_type:required } { Checks if the mime_type is of the content_type, e.g if application/pdf is of content_type "image" (which it should not...) Cached @param content_type content type to check against @param mime_type mime type to check for } { return [util_memoize [list content::type::content_type_p_not_cached -mime_type $mime_type -content_type $content_type]] } ad_proc -public content::type::content_type_p_not_cached { -content_type:required -mime_type:required } { Checks if the mime_type is of the content_type, e.g if application/pdf is of content_type "image" (which it should not...) @param content_type content type to check against @param mime_type mime type to check for } { return [db_string content_type_p "" -default 0] } openacs-5.7.0/packages/acs-content-repository/tcl/content-type-procs.xql0000644000175000017500000000121710526534625026302 0ustar frankiefrankie select 1 from cr_content_mime_type_map where mime_type = :mime_type and content_type = :content_type openacs-5.7.0/packages/acs-content-repository/tcl/content-item-procs.tcl0000644000175000017500000006162111403743217026234 0ustar frankiefrankiead_library { Tcl API for cr_items in the content repository @author Dave Bauer (dave@thedesignexperience.org) @author Jun Yamog @creation-date 2004-05-28 @cvs-id $Id: content-item-procs.tcl,v 1.22 2010/06/09 16:51:27 daveb Exp $ } namespace eval ::content::item {} ad_proc -public ::content::item::new { -name:required {-parent_id ""} {-item_id ""} {-locale ""} {-creation_date ""} {-creation_user ""} {-context_id ""} {-package_id ""} {-creation_ip ""} {-item_subtype "content_item"} {-content_type "content_revision"} {-title ""} {-description ""} {-mime_type ""} {-nls_language ""} {-text ""} {-data ""} {-relation_tag ""} {-is_live "f"} {-storage_type "file"} {-attributes ""} {-tmp_filename ""} } { @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 Create a new content item This proc creates versioned content items where content_type iscontent_revision or subtypes of content revision. There are procedures for each other base content item. This procdedure uses package_instantiate object. Under PostgreSQL the object_type new function must be registered with define_function_args. @param name @param item_id - item_id of this content_item. If this is not specified an item_id will be generated automatically @param parent_id - parent object of this content_item @param item_subtype @param content_type - content_revision or subtype of content_revision @param context_id - Context of the item. usually used in conjunction with permissions. @param package_id - Package ID of the object @param creation_user - @param creation_ip - @param creation_date - defaults to current date and time @param storage_type - file, lob, or text (postgresql only) @param locale - @param title - title of content_revision to be created @param description of content_revision to be created @param text - text of content revision to be created @param tmp_filename file containing content to be added to new revision. Caller is responsible to handle cleaning up the tmp file @param nls_language - ??? @param data - ??? @param attributes - A list of lists ofpairs of additional attributes and their values to pass to the constructor. Each pair is a list of two elements: key => value such as [list [list attribute value] [list attribute value]] @return item_id of the new content item @see content::symlink::new content::extlink::new content::folder::new } { if {$creation_user eq ""} { set creation_user [ad_conn user_id] } if {$creation_ip eq ""} { set creation_ip [ad_conn peeraddr] } if {$package_id eq ""} { set package_id [ad_conn package_id] } set var_list [list] lappend var_list \ [list name $name] \ [list parent_id $parent_id ] \ [list item_id $item_id ] \ [list locale $locale ] \ [list creation_date $creation_date ] \ [list creation_user $creation_user ] \ [list context_id $context_id ] \ [list package_id $package_id ] \ [list creation_ip $creation_ip ] \ [list item_subtype $item_subtype ] \ [list content_type $content_type ] \ [list mime_type $mime_type ] \ [list nls_language $nls_language ] \ [list relation_tag $relation_tag ] \ [list is_live $is_live ] \ [list storage_type $storage_type] # we don't pass title, text, or data to content_item__new # because the magic revision creation of the pl/sql proc does # not create a proper subtype of content revision, also it # can't set attributes of an extended type # the content type is not the object type of the cr_item so we pass in # the cr_item subtype here and content_type as part of # var_list db_transaction { # An explict lock was necessary for PostgreSQL between 8.0 and # 8.2; left the following statement here for documentary purposes # # db_dml lock_objects "LOCK TABLE acs_objects IN SHARE ROW EXCLUSIVE MODE" set item_id [package_exec_plsql \ -var_list $var_list \ content_item new] # if we have attributes we pass in everything # and create a revision with all subtype attributes that were # passed in # since we can't rely on content_item__new to create a revision # we have to pass is_live to content::revision::new and # set the live revision there if {[exists_and_not_null title] \ || [exists_and_not_null text] \ || [exists_and_not_null data] \ || [exists_and_not_null tmp_filename] \ || [llength $attributes]} { content::revision::new \ -item_id $item_id \ -title $title \ -description $description \ -content $text \ -mime_type $mime_type \ -content_type $content_type \ -is_live $is_live \ -package_id $package_id \ -creation_user $creation_user \ -creation_ip $creation_ip \ -creation_date $creation_date \ -nls_language $nls_language \ -tmp_filename $tmp_filename \ -attributes $attributes } } return $item_id } ad_proc -public ::content::item::delete { -item_id:required } { @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 Delete a content item from the database. If the content item to delete has children content items referencing its parent via acs_objects.context_id then this proc will fail. @param item_id } { return [package_exec_plsql \ -var_list [list [list item_id $item_id]] \ content_item del] } ad_proc -public ::content::item::rename { -item_id:required -name:required } { @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 Rename a content item. @param item_id @param name } { return [package_exec_plsql \ -var_list [list \ [list item_id $item_id] \ [list name $name] ] \ content_item edit_name] } ad_proc -public ::content::item::move { -item_id:required -target_folder_id:required {-name} } { @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 @param item_id item to move @param new_parent_id new parent item @param name new name, allows move with rename } { set var_list [list \ [list item_id $item_id] \ [list target_folder_id $target_folder_id] ] if {[exists_and_not_null name]} { lappend var_list [list name $name] } return [package_exec_plsql \ -var_list $var_list \ content_item move] } ad_proc -public ::content::item::get { -item_id:required {-revision "live"} {-array_name "content_item"} } { @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 @param item_id @param revision live, latest, or best (live if it exists, otherwise latest) @param array_name name of array to upvar content into @return upvars array_name containing all attributes of the content type except content @return returns 0 if item does not exists or 1 if query was sucessful @error } { upvar $array_name local_array if {[lsearch {live latest} $revision] == -1} { error "content::item::get revision was '${revision}'. It must be 'live' or 'latest'" } set content_type [content_type -item_id $item_id] if {$content_type eq ""} { # content_type query was unsucessful, item does not exist return 0 } if {"content_folder" eq $content_type} { return [db_0or1row get_item_folder "" -column_array local_array] } set table_name [db_string get_table_name "select table_name from acs_object_types where object_type=:content_type"] set table_name "${table_name}x" # get attributes of the content_item use the content_typex view return [db_0or1row get_item "" -column_array local_array] } ad_proc -public ::content::item::update { -item_id:required -attributes:required } { Update standard non-versioned content item attributes (cr_items) Valid attributes: name parent_id latest_revision live_revision locale publish_status @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-04 @param item_id item to update @param attributes A list of pairs of additional attributes and their values to get. Each pair is a list of two elements: key => value @return @error } { # do not allow update of item_id, storage_location, storage_type, # content_type, or tree_sortkey set valid_attributes [list name parent_id latest_revision live_revision locale publish_status] set update_text "" foreach {attribute_list} $attributes { set attribute [lindex $attribute_list 0] set value [lindex $attribute_list 1] if {[lsearch $valid_attributes $attribute] > -1} { # create local variable to use for binding set $attribute $value if {$update_text ne ""} { append update_text "," } append update_text " ${attribute} = :${attribute} " } } if {$update_text ne ""} { # we have valid attributes, update them set query_text "update cr_items set ${update_text} where item_id=:item_id" db_dml item_update $query_text } } ad_proc -public ::content::item::content_type { -item_id:required } { @public get_content_type Retrieves the content type of the item. If the item does not exist, returns an empty string. @param item_id The item_id of the content item @return The content type of the item, or an empty string if no such item exists } { return [package_exec_plsql \ -var_list [list [list item_id $item_id]] \ content_item get_content_type] } ad_proc -public content::item::get_content_type { -item_id:required } { Retrieves the content type of the item. If the item does not exist, returns an empty string. @param item_id The item_id of the content item @return The content type of the item, or an empty string if no such item exists } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_content_type] } ad_proc -public content::item::get_context { -item_id:required } { @param item_id @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_context] } ad_proc -public content::item::get_id { -item_path:required {-root_folder_id ""} {-resolve_index ""} } { Looks up the item_path starting with the root folder and returns item_id for that content item or empty, if none exists @param item_path @param root_folder_id @param resolve_index @return The item_id of the found item, or the empty string on failure } { return [package_exec_plsql -var_list [list \ [list item_path $item_path ] \ [list root_folder_id $root_folder_id ] \ [list resolve_index $resolve_index ] \ ] content_item get_id] } ad_proc -public content::item::get_best_revision { -item_id:required } { Attempts to retrieve the live revision for the item. If no live revision exists, attempts to retrieve the latest revision. If the item has no revisions, returns an empty string. @param item_id The item_id of the content item @return The best revision_id for the item, or an empty string if no revisions exist @see content::revision::item_id @see content::item::get_live_revision @see content::item::get_latest_revision } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_best_revision] } ad_proc -public content::item::get_latest_revision { -item_id:required } { Retrieves the latest revision for the item. If the item has no live revision, returns an empty string. @param item_id The item_id of the content item @return The latest revision_id for the item, or an empty string if no revisions exist @see content::revision::item_id @see content::item::get_best_revision @see content::item::get_live_revision } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_latest_revision] } ad_proc -public content::item::get_live_revision { -item_id:required } { Retrieves the live revision for the item. If the item has no live revision, returns an empty string. @param item_id The item_id of the content item @return The live revision_id for the item, or an empty string if no live revision exists @see content::revision::item_id @see content::item::get_best_revision @see content::item::get_latest_revision } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_live_revision] } ad_proc -public content::item::get_parent_folder { -item_id:required } { @param item_id @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_parent_folder] } ad_proc -public content::item::get_path { -item_id:required {-root_folder_id ""} } { @param item_id @param root_folder_id @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list root_folder_id $root_folder_id ] \ ] content_item get_path] } ad_proc -public content::item::get_publish_date { -item_id:required {-is_live ""} } { @param item_id @param is_live @return DATE } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list is_live $is_live ] \ ] content_item get_publish_date] } ad_proc -public content::item::get_revision_count { -item_id:required } { @param item_id @return NUMBER } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_revision_count] } ad_proc -public content::item::get_root_folder { {-item_id ""} } { @param item_id @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item get_root_folder] } ad_proc -public content::item::get_template { -item_id:required -use_context:required } { Retrieves the template which can be used to render the item. If there is a template registered directly to the item, returns the id of that template. Otherwise, returns the id of the default template registered to the item's content_type. Returns an empty string on failure. @param item_id The item_id @param context The context in which the template will be used (e.g. public) @return The template_id of the template which can be used to render the item, or an empty string on failure } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list use_context $use_context ] \ ] content_item get_template] } ad_proc -public content::item::get_title { -item_id:required {-is_live ""} } { Get the title for the item. If a live revision for the item exists, use the live revision. Otherwise, use the latest revision. @param item_id The item_id of the content item @param is_live @return The title of the item @see content::item::get_best_revision @see content::item::get_title } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list is_live $is_live ] \ ] content_item get_title] } ad_proc -public content::item::get_virtual_path { -item_id:required {-root_folder_id ""} } { Retrieves the relative path to the item. The path is relative to the page root, and has no extension (Example: "/foo/bar/baz"). @param item_id The item_id for the item, for which the path is computed @param root_folder_id Starts path resolution from this folder. Defaults to the root of the sitemap (when null). @return The path to the item, or an empty string on failure } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list root_folder_id $root_folder_id ] \ ] content_item get_virtual_path] } ad_proc -public content::item::is_index_page { -item_id:required -folder_id:required } { @param item_id @param folder_id @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list folder_id $folder_id ] \ ] content_item is_index_page] } ad_proc -public content::item::is_publishable { -item_id:required } { Determine if the item is publishable. The item is publishable only if:
  • All child relations, as well as item relations, are satisfied (according to min_n and max_n)
  • The workflow (if any) for the item is finished
@param item_id The item_id of the content item @see content::item::is_publishable @return 't' if the item is publishable, 'f' otherwise } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item is_publishable] } ad_proc -public content::item::is_published { -item_id:required } { @param item_id @return CHAR } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item is_published] } ad_proc -public content::item::is_subclass { -object_type:required -supertype:required } { @param object_type @param supertype @return CHAR } { return [package_exec_plsql -var_list [list \ [list object_type $object_type ] \ [list supertype $supertype ] \ ] content_item is_subclass] } ad_proc -public content::item::is_valid_child { -item_id:required -content_type:required {-relation_tag ""} } { @param item_id @param content_type @param relation_tag @return CHAR } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list content_type $content_type ] \ [list relation_tag $relation_tag ] \ ] content_item is_valid_child] } ad_proc -public content::item::register_template { -item_id:required -template_id:required -use_context:required } { @param item_id @param template_id @param use_context } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list template_id $template_id ] \ [list use_context $use_context ] \ ] content_item register_template] } ad_proc -public content::item::relate { -item_id:required -object_id:required {-relation_tag ""} {-order_n ""} {-relation_type "cr_item_rel"} } { @param item_id @param object_id @param relation_tag @param order_n @param relation_type @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list object_id $object_id ] \ [list relation_tag $relation_tag ] \ [list order_n $order_n ] \ [list relation_type $relation_type ] \ ] content_item relate] } ad_proc -public content::item::set_live_revision { -revision_id:required {-publish_status "ready"} } { @param revision_id @param publish_status } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ [list publish_status $publish_status ] \ ] content_item set_live_revision] } ad_proc -public content::item::set_release_period { -item_id:required {-start_when ""} {-end_when ""} } { @param item_id @param start_when @param end_when } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list start_when $start_when ] \ [list end_when $end_when ] \ ] content_item set_release_period] } ad_proc -public content::item::unregister_template { -item_id:required {-template_id ""} {-use_context ""} } { @param item_id @param template_id @param use_context } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list template_id $template_id ] \ [list use_context $use_context ] \ ] content_item unregister_template] } ad_proc -public content::item::unrelate { -rel_id:required } { @param rel_id } { return [package_exec_plsql -var_list [list \ [list rel_id $rel_id ] \ ] content_item unrelate] } ad_proc -public content::item::unset_live_revision { -item_id:required } { @param item_id } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_item unset_live_revision] } ad_proc -public content::item::copy { -item_id:required -target_folder_id:required {-creation_user ""} {-creation_ip ""} {-name ""} } { @author Jun Yamog @creation-date 2004-06-27 copy a content item to a new content item @param item_id - item_id of the content to be copied from. source content item @param target_folder_id - destination folder where the new content item is be passed @param creation_user - @param creation_ip - @param name - the name of the new item, useful if you are copying in the same folder. @return item_id of the new copied item } { return [package_exec_plsql \ -var_list [list \ [list item_id $item_id] \ [list target_folder_id $target_folder_id] \ [list creation_user $creation_user] \ [list creation_ip $creation_ip] \ [list name $name]] \ content_item copy] } ad_proc -public content::item::upload_file { {-upload_file:required} {-parent_id:required} {-package_id ""} } { Store the file uploaded under the parent_id if a file was uploaded @author Malte Sussdorff (sussdorff@sussdorff.de) @creation-date 2005-06-21 @param upload_file @param parent_id @return the revision_id of the generated item @error } { set filename [template::util::file::get_property filename $upload_file] if {$filename ne "" } { set tmp_filename [template::util::file::get_property tmp_filename $upload_file] set mime_type [template::util::file::get_property mime_type $upload_file] set tmp_size [file size $tmp_filename] set extension [file extension $filename] if {![exists_and_not_null title]} { # maltes: The following regsub garbles the title and consequently the filename as well. # "info_c+w.zip" will become "info_c+" # This is bad, first of all because a letter is missing entirely. Additionally # the title in itself should be the original filename, after all this is what # the user uploaded, not something stripped of its extension. # So I commented this out until someone can either fix the regsub but more importantly # can explain why the title should not contain the extension. # DRB: removing the explicit "." isn't sufficient because the "." in the # extension also matches any char unless it is escaped. Like Malte, I # see no reason to get rid of the extension in the title anyway ... # regsub -all ".${extension}\$" $filename "" title set title $filename } set existing_filenames [db_list get_parent_existing_filenames {}] set filename [util_text_to_url \ -text ${title} -existing_urls "$existing_filenames" -replacement "_"] set revision_id [cr_import_content \ -storage_type "file" -title $title -package_id $package_id $parent_id $tmp_filename $tmp_size $mime_type $filename] content::item::set_live_revision -revision_id $revision_id return $revision_id } } ad_proc -public content::item::get_id_by_name { {-name:required} {-parent_id:required} } { Returns The item_id of the a content item with the passed in name @param name Name of the content item @param parent_id Parent_id of the content item @return The item_id belonging to the name, empty string if no item_id was found } { return [db_string get_item_id_by_name {} -default ""] } # # # ad_proc -public ::content::item::get_publish_status { -item_id:required } { Get the publish status of the item. The publish status will be one of the following:
  • production - The item is still in production. The workflow (if any) is not finished, and the item has no live revision.
  • ready - The item is ready for publishing
  • live - The item has been published
  • expired - The item has been published in the past, but its publication has expired
@param item_id The item_id of the content item @return The publish status of the item, or the empty string on failure @see proc content::item::is_publishable } { set publish_status [db_string gps_get_publish_status \ "select publish_status from cr_items where item_id = :item_id"] return $publish_status }openacs-5.7.0/packages/acs-content-repository/tcl/content-item-procs.xql0000644000175000017500000000336710440426443026260 0ustar frankiefrankie select cx.*, ci.live_revision, ci.latest_revision, ci.locale, ci.publish_status, ci.content_type, ci.storage_type from ${table_name} cx, cr_items ci where ci.${revision}_revision = cx.revision_id and ci.item_id = :item_id select name from cr_items where parent_id = :parent_id select cf.*, ci.name, ci.item_id, ci.live_revision, ci.latest_revision, ci.locale, ci.publish_status, ci.content_type, ci.storage_type from cr_folders cf, cr_items ci where ci.item_id = cf.folder_id and ci.item_id = :item_id select name from cr_items where parent_id = :parent_id select item_id from cr_items where name = :name and parent_id = :parent_id openacs-5.7.0/packages/acs-content-repository/tcl/content-procs.tcl0000644000175000017500000000525110551254373025300 0ustar frankiefrankiead_library { Functions that the content-repository uses to interact with the file system. @author Dan Wickstrom (dcwickstrom@earthlink.net) @creation-date Sat May 5 13:45 2001 @cvs-id $Id: content-procs.tcl,v 1.11 2007/01/10 21:22:03 gustafn Exp $ } # The location for files ad_proc -public cr_fs_path { { location CR_FILES } } { Root path of content repository files. } { return [nsv_get CR_LOCATIONS $location] } ad_proc -private cr_create_content_file_path {item_id revision_id} { Creates a unique file in the content repository file system based off of the item_id and revision_id of the content item. } { # Split out the version_id by groups of 2. set item_id_length [string length $item_id] set path "/" for {set i 0} {$i < $item_id_length} {incr i} { append path [string range $item_id $i $i] if {($i % 2) == 1} { if {$i < $item_id_length} { # Check that the directory exists if {![file exists [cr_fs_path]$path]} { ns_mkdir [cr_fs_path]$path } append path "/" } } } # Check that the directory exists if {![file exists [cr_fs_path]$path]} { ns_mkdir [cr_fs_path]$path } if {[string index $path end] ne "/" } { append path "/" } return "${path}${revision_id}" } # lifted from new-file-storage (DanW - OpenACS) ad_proc -public cr_create_content_file { -move:boolean item_id revision_id client_filename } { Copies the file passed by client_filename to the content repository file storage area, and it returns the relative file path from the root of the content repository file storage area.. if the -move flag is given the file is renamed instead } { set content_file [cr_create_content_file_path $item_id $revision_id] if { $move_p } { file rename -- $client_filename [cr_fs_path]$content_file } else { file copy -force -- $client_filename [cr_fs_path]$content_file } return $content_file } ad_proc -public cr_create_content_file_from_string {item_id revision_id str} { Copies the string to the content repository file storage area, and it returns the relative file path from the root of the content repository file storage area. } { set content_file [cr_create_content_file_path $item_id $revision_id] set ofp [open [cr_fs_path]$content_file w] puts -nonewline $ofp $str close $ofp return $content_file } ad_proc -public cr_file_size {relative_file_path} { Returns the size of a file stored in the content repository. Takes the relative file path of the content repository file as an arguement. } { return [file size [cr_fs_path]$relative_file_path] } openacs-5.7.0/packages/acs-content-repository/tcl/revision-procs-oracle.xql0000644000175000017500000001172110232132775026745 0ustar frankiefrankie oracle8.1.6 select r.mime_type, i.storage_type, i.storage_area_key, r.revision_id, r.content_length from cr_revisions r, cr_items i where i.item_id = r.item_id and r.revision_id = content_item.get_live_revision(:item_id) select :path || filename from cr_revisions where revision_id = :revision_id select content from cr_revisions where revision_id = $revision_id begin content_type.register_mime_type('content_revision', :mime_type); end; select content_item.is_subclass(:image_type, 'image') from dual select content_item.is_subclass(:other_type, 'content_revision') from dual begin :1 := image.new( name => :object_name, parent_id => :parent_id, item_id => :item_id, revision_id => :revision_id, mime_type => :mime_type, creation_user => :creation_user, creation_ip => :creation_ip, title => :title, content_type => :image_type, storage_type => :storage_type, height => :original_height, width => :original_width, package_id => :package_id ); end; begin :1 := image.new_revision ( item_id => :item_id, revision_id => :revision_id, title => :title, description => :description, mime_type => :mime_type, creation_user => :creation_user, creation_ip => :creation_ip, height => :original_height, width => :original_width, package_id => :package_id ); end; begin :1 := content_item.new( name => :object_name, item_id => :item_id, parent_id => :parent_id, context_id => :parent_id, creation_user => :creation_user, creation_ip => :creation_ip, content_type => :other_type, storage_type => :storage_type, package_id => :package_id ); end; begin :1 := content_revision.new ( title => :title, description => :description, mime_type => :mime_type, item_id => :item_id, revision_id => :revision_id, creation_user => :creation_user, creation_ip => :creation_ip, package_id => :package_id, filename => :object_name ); end; update cr_revisions set mime_type = :mime_type, content = empty_blob() where revision_id = :revision_id returning content into :1 update cr_revisions set content_length = dbms_lob.getlength(content) where revision_id = :revision_id begin content_item.set_live_revision (revision_id => :revision_id); end; update cr_revisions set filename = :filename, mime_type = :mime_type, content_length = :tmp_size where revision_id = :revision_id openacs-5.7.0/packages/acs-content-repository/tcl/content-keyword-procs.tcl0000644000175000017500000001160610174210303026745 0ustar frankiefrankie# ad_library { Procedures for content_keywords @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-09 @arch-tag: dc56be97-e611-4f34-a5b6-264b46a6ad7b @cvs-id $Id: content-keyword-procs.tcl,v 1.4 2005/01/21 14:25:07 jeffd Exp $ } namespace eval ::content::keyword {} ad_proc -public content::keyword::write_to_file { -item_id:required -root_path:required } { @param item_id @param root_path } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list root_path $root_path ] \ ] content_keyword write_to_file] } ad_proc -public content::keyword::delete { -keyword_id:required } { @param keyword_id @return 0 } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ ] content_keyword del] } ad_proc -public content::keyword::get_description { -keyword_id:required } { @param keyword_id @return string with description } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ ] content_keyword get_description] } ad_proc -public content::keyword::get_heading { -keyword_id:required } { @param keyword_id @return string with heading } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ ] content_keyword get_heading] } ad_proc -public content::keyword::get_path { -keyword_id:required } { @param keyword_id @return "/" delimited path in the keyword tree to the supplied keyword } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ ] content_keyword get_path] } ad_proc -public content::keyword::is_assigned { -item_id:required -keyword_id:required {-recurse ""} } { @param item_id @param keyword_id @param recurse @return t or f } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list keyword_id $keyword_id ] \ [list recurse $recurse ] \ ] content_keyword is_assigned] } ad_proc -public content::keyword::is_leaf { -keyword_id:required } { @param keyword_id @return t or f } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ ] content_keyword is_leaf] } ad_proc -public content::keyword::item_assign { -item_id:required -keyword_id:required {-context_id ""} {-creation_user ""} {-creation_ip ""} } { @param item_id @param keyword_id @param context_id @param creation_user @param creation_ip Associate a keyword with a CR item. @return 0 } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list keyword_id $keyword_id ] \ [list context_id $context_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ ] content_keyword item_assign] } ad_proc -public content::keyword::item_unassign { -item_id:required -keyword_id:required } { @param item_id @param keyword_id @return 0 } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list keyword_id $keyword_id ] \ ] content_keyword item_unassign] } ad_proc -public content::keyword::new { -heading:required {-description ""} {-parent_id ""} {-keyword_id ""} -creation_date {-creation_user ""} {-creation_ip ""} -object_type } { @param heading @param description @param parent_id @param keyword_id @param creation_date @param creation_user @param creation_ip @param object_type @return keyword_id of created keyword } { set var_list [list \ [list heading $heading ] \ [list description $description ] \ [list parent_id $parent_id ] \ [list keyword_id $keyword_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ ] if {[exists_and_not_null creation_date]} { lappend var_list [list creation_date $creation_date ] } if {[exists_and_not_null object_type]} { lappend var_list [list object_type $object_type ] } return [package_exec_plsql -var_list $var_list content_keyword new] } ad_proc -public content::keyword::set_description { -keyword_id:required -description:required } { @param keyword_id @param description @return 0 } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ [list description $description ] \ ] content_keyword set_description] } ad_proc -public content::keyword::set_heading { -keyword_id:required -heading:required } { @param keyword_id @param heading @return 0 } { return [package_exec_plsql -var_list [list \ [list keyword_id $keyword_id ] \ [list heading $heading ] \ ] content_permission set_heading] } openacs-5.7.0/packages/acs-content-repository/tcl/content-symlink-procs.tcl0000644000175000017500000000576710440426443026774 0ustar frankiefrankie# ad_library { Procedures for content symlink @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-09 @arch-tag: 31c66882-e912-4db4-84fe-8a2b0890ffb0 @cvs-id $Id: content-symlink-procs.tcl,v 1.5 2006/06/04 00:45:23 donb Exp $ } namespace eval ::content::symlink {} ad_proc -public content::symlink::copy { -symlink_id:required -target_folder_id:required -creation_user:required {-creation_ip ""} } { @param symlink_id @param target_folder_id @param creation_user @param creation_ip } { return [package_exec_plsql -var_list [list \ [list symlink_id $symlink_id ] \ [list target_folder_id $target_folder_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ ] content_symlink copy] } ad_proc -public content::symlink::delete { -symlink_id:required } { @param symlink_id } { return [package_exec_plsql -var_list [list \ [list symlink_id $symlink_id ] \ ] content_symlink delete] } ad_proc -public content::symlink::is_symlink { -item_id:required } { @param item_id @return CHAR } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_symlink is_symlink] } ad_proc -public content::symlink::new { {-name ""} {-label ""} -target_id:required -parent_id:required {-symlink_id ""} -creation_date {-creation_user ""} {-creation_ip ""} } { This procedure allows you to create a new Symlink @param name Name of the new content item. Used instead of "symlink_to_item target_id" @param label @param target_id Item_id of the item to which the link should point @param parent_id item_id (preferably folder_id) of the parent (folder) where the link is associated and shown in. @param symlink_id @param creation_date @param creation_user @param creation_ip @return NUMBER(38) } { set var_list [list \ [list name $name ] \ [list label $label ] \ [list target_id $target_id ] \ [list parent_id $parent_id ] \ [list symlink_id $symlink_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ ] if {[exists_and_not_null creation_date]} { lappend var_list [list creation_date $creation_date ] } return [package_exec_plsql -var_list $var_list content_symlink new] } ad_proc -public content::symlink::resolve { -item_id:required } { Return the item_id of the target item to which the symlink points @param item_id item_id of the symlink @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_symlink resolve] } ad_proc -public content::symlink::resolve_content_type { -item_id:required } { @param item_id @return VARCHAR2(100) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ ] content_symlink resolve_content_type] } openacs-5.7.0/packages/acs-content-repository/tcl/image-procs.tcl0000644000175000017500000002554011451376353024716 0ustar frankiefrankie# packages/acs-content-repository/tcl/image-procs.tcl ad_library { Procedures to handle image subtype Image magick handling procedures inspired and borrowed from photo-album and imagemagick packages @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2006-07-31 @cvs-id $Id: image-procs.tcl,v 1.9 2010/10/01 15:23:23 daveb Exp $ } namespace eval image:: {} ad_proc -public image::new { {-name ""} {-parent_id ""} {-item_id ""} {-locale ""} {-creation_date ""} {-creation_user ""} {-context_id ""} {-package_id ""} {-creation_ip ""} {-item_subtype "content_item"} {-content_type "image"} {-title ""} {-description ""} {-mime_type ""} {-relation_tag ""} {-is_live ""} {-storage_type "file"} {-attributes {}} {-tmp_filename ""} {-width ""} {-height ""} } { Create a new image object from a temporary file @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2006-07-31 @param item_id Item id of the content item for this image. The item_id will be generated from the acs_object_id sequence if not specified. @param parent_id Parent object for this image. Context_id will be set to parent_id @param name Name of image item, must be unique per parent_id @param tmp_filename Filename in the filesystem, readable by AOLserver user to create image from @return Item_id @error } { if {$width eq "" || $height eq ""} { foreach {width height} [image::get_file_dimensions \ -filename $tmp_filename \ -mime_type $mime_type] {} } if {[util_search_list_of_lists $attributes width]<0} { lappend attributes [list width $width] } if {[util_search_list_of_lists $attributes height]<0} { lappend attributes [list height $height] } return [content::item::new \ -name $name \ -parent_id $parent_id \ -item_id $item_id \ -locale $locale \ -creation_date $creation_date \ -creation_user $creation_user \ -context_id $context_id \ -package_id $package_id \ -creation_ip $creation_ip \ -item_subtype $item_subtype \ -content_type $content_type \ -title $title \ -description $description \ -mime_type $mime_type \ -relation_tag $relation_tag \ -is_live $is_live \ -storage_type "file" \ -attributes $attributes \ -tmp_filename $tmp_filename] } ad_proc -public image::get_file_info { -filename } { Get info about an image file, dimensions, mime_type The name of this proc tries to make clear that we aren't getting info for an image type object, but examinging an image file in the filesystem @param filename Full path to file in the filesystem @return List of width height mime_type in array get format @author Dave Bauer @creation-date 2006-08-27 } { if {![catch {set info [image::imagemagick_identify -filename $filename]} errmsg]} { return $info } else { set size [image::ns_size -filename $filename] set mime_type [image::filename_mime_type -filename $filename] return [concat $size $mime_type] } } ad_proc -public image::get_file_info_array { -filename -array_name } { Get info about an image file, dimensions, mime_type into an array in the caller's namespace. @param filename Full path to file in the filesystem @param array_name Array in caller's namespace to populate @return List of width height mime_type in array get format @author Dave Bauer @creation-date 2006-08-27 @see image::get_info } { upvar $array_name local_array set info [image::get_file_info -filename $filename] set local_array(width) [lindex $info 0] set local_array(height) [lindex $info 1] set local_array(mime_type) [lindex $info 2] } ad_proc -public image::get_file_dimensions { -filename {-mime_type ""} } { Get the width and height of an image from a file in the filesystem. This uses for an imagemagick binary, if that is not available, it tries ns_gifsize, ns_jpgsize AOLserver commands. We use imagemagick first since it supports many more image formats. @param filename full path to file in the filesystem @return Returns a list of width and height @creation-date 2006-08-28 @author Dave Bauer (dave@solutiongrove.com) } { if {[catch {set size [image::imagemagick_file_dimensions -filename $filename]} errmsg]} { set size [image::ns_size -filename $filename -mime_type $mime_type] } return $size } ad_proc -public image::imagmagick_identify { -filename } { Get width height and mime type from imagemagick @param filename Full path to an image file in the filesystem @return List of width height mime_type @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-27 } { if { [ catch {set out [exec [parameter::get -parameter ImageMagickPath]/identify -format "%w %h %m %k %q %#" $file]} errMsg]} { return -code error $errMsg } foreach {width height type} [split $out { }] {} switch $type { JPG - JPEG { set mime_type image/jpeg } GIF - GIF87 { set mime_type image/gif } PNG { set mime_type image/png } TIF - TIFF { set mime_type image/tiff } default { set mime_type {} } } return [list $width $height $mime_type] } ad_proc -public image::imagemagick_file_dimensions { -filename } { Get the dimensions of an image from imagemagick @param filename Full path to an image file in the filesystem @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-27 } { set geometry [exec [image::identify_binary] -size geometry $filename] set width "" set height "" regexp {(\d+)x(\d+)} $geometry x width height return [list $width $height] } ad_proc -public image::identify_binary { } { Find imagemagick identify binary @author Dave Bauer (dave@solutiongrove.com) @creation_date 2006-08-27 } { # FIXME create parameter return [parameter::get \ -parameter ImageMagickIdentifyBinary \ -package_id [apm_package_id_from_key acs-content-repository] \ -default "/usr/bin/identify"] } ad_proc -public image::convert_binary { } { Find imagemagick convert binary @author Dave Bauer (dave@solutiongrove.com) @creation_date 2006-08-27 } { #FIXME create parameter return [parameter::get \ -parameter ImageMagickConvertBinary \ -package_id [apm_package_id_from_key acs-content-repository] \ -default "/usr/bin/convert"] } ad_proc -public image::ns_size { -filename {-mime_type ""} } { Use ns_gifsize/ns_jpegsize to try to get the size of an image @param filename Full path to file in the filesystem @return List in array get format with names of width and height @author Dave Bauer (dave@solutiongrove.com) @creation_date 2006-08-27 } { switch -- \ [image::filename_mime_type \ -filename $filename \ -mime_type $mime_type] { *gif { set size [ns_gifsize $filename] } *jpg - *jpeg { set size [ns_jpegsize $filename] } default { set size [list "" ""] } } return $size } ad_proc -public image::filename_mime_type { -filename -mime_type } { Use ns_guesstype if we don't know the mime_type @param filename Filename of image file @param mime_type If known, the mime type of the file @author Dave Bauer (dave@thedesignexperience.org) @creation_date 2006-08-27 } { if {$mime_type eq ""} { set mime_type [ns_guesstype $filename] } return $mime_type } ad_proc -private image::get_convert_to_sizes { } { List of sizes to convert an image to. List of maximum width x height. @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-27 } { #TODO make a parameter in content repository # avatar size to match gravatar.com return [list thumbnail 150x150 view 500x500 avatar 80x80] } ad_proc -public image::resize { -item_id {-revision_id ""} {-size_name "thumbnail"} } { Create a thumbnail of an image in the content repository @param item_id item_id of image @return image item_id of the thumbnail @author Dave Bauer (dave@solutiongrove.com) @cretion-date 2006-08-27 } { if {$revision_id eq ""} { set revision_id [content::item::get_best_revision -item_id $item_id] } set original_filename [content::revision::get_cr_file_path -revision_id $revision_id] set tmp_filename [ns_mktemp "/tmp/XXXXXX"] array set sizes [image::get_convert_to_sizes] if {[catch {exec [image::convert_binary] -resize $sizes($size_name) $original_filename $tmp_filename} errmsg]} { # maybe imagemagick isn't installed? file delete $tmp_filename return "" } if {[set resize_item_id \ [image::get_size_item_id \ -item_id $item_id \ -size_name $size_name]] eq ""} { set resize_item_id \ [image::new \ -item_id $resize_item_id \ -name "${item_id}_${size_name}" \ -parent_id $item_id \ -relation_tag "image-${size_name}" \ -tmp_filename $tmp_filename] } else { content::revision::new \ -item_id $resize_item_id \ -tmp_filename $tmp_filename } file delete $tmp_filename return $resize_item_id } ad_proc -public image::get_size_item_id { -item_id -size_name } { Get the item_id of a resized version of an image @param item_id Original image item_id @size_name Name of the size to get @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-27 @see image::get_convert_to_sizes } { return [content::item::get_id \ -item_path ${item_id}_${size_name} \ -root_folder_id $item_id] } ad_proc -public image::get_resized_item_id { -item_id {-size_name "thumbnail"} } { Get the item id of a related resized image, usually the thumbnail size @param item_id Item_id of the original image @return item_id of the resized image, empty string if it doeesn't exist @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-29 } { return [db_string get_resized_item_id "" -default ""] } ad_proc -private image::resize_existing_images { } { Generate thumbnails for images already in the CR } { foreach {size_name dimensions} [image::get_convert_to_sizes] { foreach item_id [db_list get_items "select item_id from cr_items where \content_type='image' and latest_revision is not null"] { image::resize \ -item_id $item_id \ -size_name $size_name } } } openacs-5.7.0/packages/acs-content-repository/tcl/image-procs.xql0000644000175000017500000000107610475066665024745 0ustar frankiefrankie select child_id from cr_child_rels where parent_id=:item_id and relation_tag = 'image-' || :size_name openacs-5.7.0/packages/acs-content-repository/tcl/doc-procs-oracle.xql0000644000175000017500000000314707276424503025666 0ustar frankiefrankie oracle8.1.6 select doc.get_package_header(:package_name) from dual select doc.get_proc_header(:proc_name, :package_name) from dual select distinct lower(name) as label, lower(name) as value from user_source where type='PACKAGE' and line=1 order by label select distinct lower(text) as line_header from user_source where type='PACKAGE' and lower(name) = lower(:package_name) and ( lower(text) like '%procedure%' or lower(text) like '%function%' ) order by line_header select distinct lower(text) as line_header from user_source where type='PACKAGE' and lower(name) = lower(:package_name) and ( lower(text) like '%procedure%' or lower(text) like '%function%' ) order by line_header openacs-5.7.0/packages/acs-content-repository/tcl/folder-procs-postgresql.xql0000644000175000017500000000040410046433070027307 0ustar frankiefrankie postgresql7.1 select content_folder__delete(:folder_id) openacs-5.7.0/packages/acs-content-repository/tcl/item-procs.tcl0000644000175000017500000004657611377243120024576 0ustar frankiefrankie########################################## # # Procs for accessing content item properties # @namespace item # # The item commands allow easy access to properties of the # content_item object. In the future, a unified API for caching # item properties will be developed here. # @see namespace publish namespace eval item {} ad_proc -public item::get_content { {-revision_id ""} {-array:required} {-item_id ""} } { @public get_revision_content Create a onerow datasource called content in the calling frame which contains all attributes for the revision (including inherited ones).

The datasource will contain a column called "text", representing the main content (blob) of the revision, but only if the revision has a textual mime-type. @param revision_id The revision whose attributes are to be retrieved @option item_id The item_id of the corresponding item. You can provide this as an optimization. If you don't provide revision_id, you must provide item_id, and the item must have a live revision. @return 1 on success (and set the array in the calling frame), 0 on failure @see proc item::get_mime_info @see proc item::get_content_type } { upvar 1 $array content if { $item_id eq "" } { set item_id [::content::revision::item_id -revision_id $revision_id] if { $item_id eq "" } { ns_log notice "item::get_content: no such revision: $revision_id" return 0 } } elseif { $revision_id eq "" } { set revision_id [::content::item::get_live_revision -item_id $item_id] } if { $revision_id eq "" } { error "You must supply revision_id, or the item must have a live revision." } return [item::get_revision_content $revision_id $item_id] } ad_proc -public item::content_is_null { revision_id } { @public content_is_null Determines if the content for the revision is null (not mereley zero-length) @param revision_id The revision id @return 1 if the content is null, 0 otherwise } { set content_test [db_string cin_get_content ""] return [template::util::is_nil content_test] } ad_proc -public item::get_revision_content { revision_id args } { @public get_revision_content Create a onerow datasource called content in the calling frame which contains all attributes for the revision (including inherited ones).

The datasource will contain a column called "text", representing the main content (blob) of the revision, but only if the revision has a textual mime-type. @param revision_id The revision whose attributes are to be retrieved @option item_id {default auto-generated} The item_id of the corresponding item. @return 1 on success (and create a content array in the calling frame), 0 on failure @see proc item::get_mime_info @see proc item::get_content_type } { template::util::get_opts $args if { [template::util::is_nil opts(item_id)] } { # Get the item id set item_id [::content::revision::item_id -revision_id $revision_id] if { [template::util::is_nil item_id] } { ns_log warning "item::get_revision_content: No such revision: $revision_id" return 0 } } else { set item_id $opts(item_id) } # Get the mime type, decide if we want the text get_mime_info $revision_id if { [exists_and_not_null mime_info(mime_type)] && \ [string equal [lindex [split $mime_info(mime_type) "/"] 0] "text"] } { set text_sql [db_map grc_get_all_content_1] } else { set text_sql "" } # Get the content type set content_type [::content::item::get_content_type -item_id $item_id] # Get the table name set table_name [db_string grc_get_table_names ""] upvar content content # Get (all) the content (note this is really dependent on file type) db_0or1row grc_get_all_content "" -column_array content if { ![array exists content] } { ns_log warning "item::get_revision_content: No data found for item $item_id, revision $revision_id" return 0 } return 1 } ad_proc -public item::content_methods_by_type { content_type args } { @public content_methods_by_type Determines all the valid content methods for instantiating a content type. Possible choices are text_entry, file_upload, no_content and xml_import. Currently, this proc merely removes the text_entry method if the item does not have a text mime type registered to it. In the future, a more sophisticated mechanism will be implemented. @param content_type The content type @option get_labels Return not just a list of types, but a list of name-value pairs, as in the -options ATS switch for form widgets @return A Tcl list of all possible content methods } { template::util::get_opts $args set types [db_list cmbt_get_content_mime_types ""] set need_text [expr {[llength $types] > 0}] if { [info exists opts(get_labels)] } { set methods [list \ [list "No Content" no_content] \ [list "File Upload" file_upload]] if { $need_text } { lappend methods [list "Text Entry" text_entry] } lappend methods [list "XML Import" xml_import] } else { set methods [list no_content file_upload] if { $need_text } { lappend methods text_entry } lappend methods xml_import } return $methods } ad_proc -public item::get_mime_info { revision_id {datasource_ref mime_info} } { @public get_mime_info Creates a onerow datasource in the calling frame which holds the mime_type and file_extension of the specified revision. If the revision does not exist, does not create the datasource. @param revision_id The revision id @param datasource_ref {default mime_info} The name of the datasource to be created. The datasource will have two columns, mime_type and file_extension. return 1 (one) if the revision exists, 0 (zero) otherwise. @see proc item::get_extended_url } { set sql [db_map gmi_get_mime_info] return [uplevel "db_0or1row ignore \"$sql\" -column_array $datasource_ref"] } ad_proc -public item::get_extended_url { item_id args } { Retrieves the relative URL of the item with a file extension based on the item's mime_type (Example: "/foo/bar/baz.html"). @param item_id The item id @option template_extension Signifies that the file extension should be retrieved using the mime_type of the template assigned to the item, not from the item itself. The live revision of the template is used. If there is no template which could be used to render the item, or if the template has no live revision, the extension defaults to ".html" @option revision_id {default the live revision} Specifies the revision_id which will be used to retrieve the item's mime_type. This option is ignored if the -template_extension option is specified. @return The relative URL of the item with the appropriate file extension or an empty string on failure @see proc item::get_url @see proc item::get_mime_info @see proc item::get_template_id } { set item_url [get_url $item_id] if { [template::util::is_nil item_url] } { ns_log warning "item::get_extended_url: No item URL found for content item $item_id" return "" } template::util::get_opts $args # Get full path set file_url [ns_normalizepath "/$item_url"] # Determine file extension if { [info exists opts(template_extension)] } { set file_extension "html" # Use template mime type set template_id [get_template_id $item_id] if { ![template::util::is_nil template_id] } { # Get extension from the template mime type set template_revision_id [::content::item::get_best_revision -item_id $template_id] if { ![template::util::is_nil template_revision_id] } { get_mime_info $template_revision_id mime_info if { [info exists mime_info(file_extension)] } { set file_extension $mime_info(file_extension) } } } } else { # Use item mime type if template extension does not exist # Determine live revision, if none specified if { [template::util::is_nil opts(revision_id)] } { set revision_id [::content::item::get_live_revision -item_id $item_id] if { [template::util::is_nil revision_id] } { ns_log warning "item::get_best_revision: No live revision for content item $item_id" return "" } } else { set revision_id $opts(revision_id) } get_mime_info $revision_id mime_info if { [info exists mime_info(file_extension)] } { set file_extension $mime_info(file_extension) } else { set file_extension "html" } } append file_url ".$file_extension" return $file_url } ####################################################### # # the following have no counter parts in content::item::* # but use no direct sql calls. # ####################################################### ad_proc -public item::get_element { {-item_id:required} {-element:required} } { Return the value of a single element (attribute) of a content item. @param item_id The id of the item to get element value for @param element The name (column name) of the element. See item::get for valid element names. } { ::content::item::get -item_id $item_id -array row return $row($element) } ad_proc -public item::publish { {-item_id:required} {-revision_id ""} } { Publish a content item. Updates the live_revision and publish_date attributes, and sets publish_status to live. @param item_id The id of the content item @param revision_id The id of the revision to publish. Defaults to the latest revision. @author Peter Marklund } { if { $revision_id eq "" } { set revision_id [::content::item::get_latest_revision -item_id $item_id] } ::content::item::set_live_revision -revision_id $revision_id -publish_status "live" } ad_proc -public item::unpublish { {-item_id:required} {-publish_status "production"} } { Unpublish a content item. @param item_id The id of the content item @param publish_status The publish_status to put the item in after unpublishing it. @author Peter Marklund } { ::content::item::set_live_revision -item_id $item_id ::content::item::update -item_id $item_id -attributes [list [list publish_status $publish_status]] } ####################################################### # # all the following procs are deprecated and do not have # direct sql calls. # ####################################################### ad_proc -public -deprecated item::get_title { item_id } { @public get_title Get the title for the item. If a live revision for the item exists, use the live revision. Otherwise, use the latest revision. @param item_id The item id @return The title of the item @see item::get_best_revision @see content::item::get_title } { return [::content::item::get_title -item_id $item_id] } ad_proc -public -deprecated item::get_publish_status { item_id } { @public get_publish_status Get the publish status of the item. The publish status will be one of the following:

  • production - The item is still in production. The workflow (if any) is not finished, and the item has no live revision.
  • ready - The item is ready for publishing
  • live - The item has been published
  • expired - The item has been published in the past, but its publication has expired
@param item_id The item id @return The publish status of the item, or the empty string on failure @see proc item::is_publishable } { return [::content::item::get_publish_status -item_id $item_id] } ad_proc -public -deprecated item::is_publishable { item_id } { Determine if the item is publishable. The item is publishable only if:
  • All child relations, as well as item relations, are satisfied (according to min_n and max_n)
  • The workflow (if any) for the item is finished
@param item_id The item id @see content::item::is_publishable @return 1 if the item is publishable, 0 otherwise } { return [string equal [::content::item::is_publishable -item_id $item_id] "t"] } ad_proc -public -deprecated item::get_content_type { item_id } { @public get_content_type Retrieves the content type of tyhe item. If the item does not exist, returns an empty string. @param item_id The item id @return The content type of the item, or an empty string if no such item exists @see content::item::get_content_type } { return [::content::item::get_content_type -item_id $item_id] } ad_proc -public -deprecated item::get_item_from_revision { revision_id } { @public get_item_from_revision Gets the item_id of the item to which the revision belongs. @param revision_id The revision id @return The item_id of the item to which this revision belongs @see content::item::get_live_revision @see content::revision::item_id } { return [::content::revision::item_id -revision_id $revision_id] } ad_proc -public -deprecated item::get_id { url {root_folder ""}} { @public get_id Looks up the URL and gets the item id at that URL, if any. @param url The URL @param root_folder {default The Sitemap} The ID of the root folder to use for resolving the URL @return The item ID of the item at that URL, or the empty string on failure @see proc item::get_url @see content::item::get_id } { # Strip off file extension set last [string last "." $url] if { $last > 0 } { set url [string range $url 0 [expr {$last - 1}]] } if {$root_folder ne ""} { return [::content::item::get_id -item_path $url] } else { return [::content::item::get_id -item_path $url -root_folder_id $root_folder] } } ad_proc -public -deprecated item::get_template_id { item_id {context public} } { @public get_template_id Retrieves the template which can be used to render the item. If there is a template registered directly to the item, returns the id of that template. Otherwise, returns the id of the default template registered to the item's content_type. Returns an empty string on failure. @param item_id The item id @param context {default 'public'} The context in which the template will be used. @return The template_id of the template which can be used to render the item, or an empty string on failure @see proc item::get_template_url @see content::item::get_template } { return [::content::item::get_template -item_id $item_id -use_context $context] } ad_proc -public -deprecated item::get_template_url { item_id {context public} } { @public get_template_url Retrieves the relative URL of the template which can be used to render the item. The URL is relative to the TemplateRoot as it is specified in the ini file. @param item_id The item id @param context {default 'public'} The context in which the template will be used. @return The template_id of the template which can be used to render the item, or an empty string on failure @see proc item::get_template_id @see content::item::get_path } { set template_id [::content::item::get_template -item_id $item_id -use_context $context] if { $template_id eq "" } { return "" } return [::content::item::get_virtual_path -item_id $template_id] } ad_proc -public -deprecated item::get_url { {-root_folder_id "null"} item_id } { @public get_url Retrieves the relative URL stub to the item. The URL is relative to the page root, and has no extension (Example: "/foo/bar/baz"). @param item_id The item id @param root_folder_id Starts path resolution from this folder. Defaults to the root of the sitemap (when null). @return The relative URL to the item, or an empty string on failure @see proc item::get_extended_url @see content::item::get_virtual_path } { if {$root_folder_id eq "null"} { return [::content::item::get_virtual_path -item_id $item_id] } else { return [::content::item::get_virtual_path -item_id $item_id -root_folder_id $root_folder_id] } } ad_proc -public -deprecated item::get_best_revision { item_id } { @public get_best_revision Attempts to retrieve the live revision for the item. If no live revision exists, attempts to retrieve the latest revision. If the item has no revisions, returns an empty string. @param item_id The item id @return The best revision id for the item, or an empty string if no revisions exist @see content::item::get_live_revision @see content::item::get_latest_revision @see content::item::get_best_revision } { return [::content::item::get_best_revision -item_id $item_id] } ad_proc -public -deprecated item::get_latest_revision { item_id } { Retrieves the latest revision for the item. If the item has no live revision, returns an empty string. @param item_id The item id @return The latest revision id for the item, or an empty string if no revisions exist @see content::item::get_live_revision @see content::item::get_latest_revision @see content::item::get_best_revision } { return [::content::item::get_latest_revision -item_id $item_id] } ad_proc -public -deprecated item::get_live_revision { item_id } { @public get_live_revision Retrieves the live revision for the item. If the item has no live revision, returns an empty string. @param item_id The item id @return The live revision id for the item, or an empty string if no live revision exists @see item::get_best_revision @see content::revision::item_id @see content::item::get_live_revision } { return [::content::item::get_live_revision -item_id $item_id] } ad_proc -public -deprecated item::get_type { item_id } { Returns the content type of the specified item, or empty string if the item_id is invalid @see content::item::get_content_type } { return [::content::item::get_content_type -item_id $item_id] } ad_proc -deprecated item::copy { -item_id:required -target_folder_id:required } { Copy the given item. @param item_id The content item to copy @param target_folder_id The folder which will hold the new copy @see content::item::copy } { ::content::item::copy -item_id $item_id \ -target_folder_id $target_folder_id \ -creation_user [ad_conn user_id] \ -creation_ip [ad_conn peeraddr] } ad_proc -public -deprecated item::get { {-item_id:required} {-array:required} } { Get information about a content item. @param item_id The id of the item to get info for @param array The name of the array to populate with values. The keys are: ITEM_ID, PARENT_ID, NAME, LOCALE, LIVE_REVISION, LATEST_REVISION, PUBLISH_STATUS, CONTENT_TYPE, STORAGE_TYPE, STORAGE_AREA_KEY, ARCHIVE_DATE, PACKAGE_ID @author Peter Marklund @see content::item::get } { upvar $array row ::content::item::get -item_id $item_id -array row } ad_proc -public -deprecated item::delete { {-item_id:required} } { Delete a content item from the database. If the content item to delete has children content items referencing its parent via acs_objects.context_id then this proc will fail. @author Peter Marklund @see content::item::delete } { ::content::item::delete -item_id $item_id } openacs-5.7.0/packages/acs-content-repository/tcl/item-procs.xql0000644000175000017500000000224510607416604024605 0ustar frankiefrankie select table_name from acs_object_types where object_type = :content_type select x.*, :item_id as item_id $text_sql, :content_type as content_type from cr_revisions r, ${table_name}x x where r.revision_id = :revision_id and x.revision_id = r.revision_id select mime_type from cr_content_mime_type_map where content_type = :content_type and lower(mime_type) like 'text/%' select m.mime_type, m.file_extension from cr_mime_types m, cr_revisions r where r.mime_type = m.mime_type and r.revision_id = $revision_id openacs-5.7.0/packages/acs-content-repository/tcl/extlink-procs-postgresql.xql0000644000175000017500000000233310024403020027501 0ustar frankiefrankie postgresql7.1 select content_extlink__new ( :name, :url, :label, :description, :parent_id, :extlink_id, current_timestamp, :creation_user, :creation_ip, :package_id ); update acs_objects set last_modified = current_timestamp, modifying_user = :modifying_user, modifying_ip = :modifying_ip, title = :label where object_id = :extlink_id select content_extlink__delete ( :extlink_id ); select content_extlink__is_extlink ( :item_id ); openacs-5.7.0/packages/acs-content-repository/tcl/apm-callback-procs.tcl0000644000175000017500000000405311253303077026130 0ustar frankiefrankie# /packages/acs-content-repository/tcl/apm-callback-procs.tcl ad_library { APM callbacks library @creation-date July 2009 @author Emmanuelle Raffenne (eraffenne@gmail.com) @cvs-id $Id: apm-callback-procs.tcl,v 1.2 2009/09/13 23:54:39 donb Exp $ } namespace eval content {} namespace eval content::apm {} ad_proc -public content::apm::after_upgrade { {-from_version_name:required} {-to_version_name:required} } { APM callback executed on package upgrade. } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { 5.5.1d1 5.5.1d2 { set mimetype_list [list \ {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" "xlsx" "Microsoft Office Excel"} \ {"application/vnd.openxmlformats-officedocument.spreadsheetml.template" "xltx" "Microsoft Office Excel Template"} \ {"application/vnd.openxmlformats-officedocument.presentationml.presentation" "pptx" "Microsoft Office PowerPoint Presentation"} \ {"application/vnd.openxmlformats-officedocument.presentationml.slideshow" "ppsx" "Microsoft Office PowerPoint Slideshow"} \ {"application/vnd.openxmlformats-officedocument.presentationml.template" "potx" "Microsoft Office PowerPoint Template"} \ {"application/vnd.openxmlformats-officedocument.wordprocessingml.document" "docx" "Microsoft Office Word"} \ {"application/vnd.openxmlformats-officedocument.wordprocessingml.template" "dotx" "Microsoft Office Word Template"}] foreach elm $mimetype_list { cr_create_mime_type \ -mime_type [lindex $elm 0] \ -extension [lindex $elm 1] \ -description [lindex $elm 2] } } } } openacs-5.7.0/packages/acs-content-repository/tcl/item-procs-oracle.xql0000644000175000017500000000122110607416604026041 0ustar frankiefrankie oracle8.1.6 , content.blob_to_string(content) as text select 't' from cr_revisions r, cr_items i where r.revision_id = :revision_id and i.item_id = r.item_id and ((r.content is not null and i.storage_type in ('lob','text')) or (r.filename is not null and i.storage_type = 'file')) openacs-5.7.0/packages/acs-content-repository/tcl/symlink-procs-oracle.xql0000644000175000017500000000347710024403020026565 0ustar frankiefrankie oracle8.1.6 begin :1 := content_symlink.new ( name => :name, target_id => :target_id, label => :label, parent_id => :parent_id, symlink_id => :symlink_id, creation_user => :creation_user, creation_ip => :creation_ip, package_id => :package_id ); end; update acs_objects set last_modified = sysdate, modifying_user = :modifying_user, modifying_ip = :modifying_ip, title = :label where object_id = :symlink_id begin content_symlink.del ( symlink_id => :symlink_id ); end; select content_symlink.is_symlink (:item_id) from dual select content_symlink.resolve ( :item_id ) from dual select content_symlink.resolve_content_type ( :item_id ) from dual openacs-5.7.0/packages/acs-content-repository/tcl/extlink-procs.tcl0000644000175000017500000000511711145370162025300 0ustar frankiefrankiead_library { Manage external links in the content repository @author Don Baccus (dhogaza@pacifier.com) @cvs-d $Id: extlink-procs.tcl,v 1.10 2009/02/13 22:13:06 jeffd Exp $ } namespace eval content_extlink {} ad_proc -deprecated content_extlink::new { {-extlink_id ""} -url:required -parent_id:required {-name ""} {-label ""} {-description ""} {-package_id ""} } { Create a new external link. @see content::extlink::new @extlink_id Optional pre-assigned object_id for the link @url The URL of the external resource @parent_id The folder that will contain this extlink @name Name to assign the object (defaults to "link extlink_id") @label Label for the extlink (defaults to the URL) @description An extended description of the link (defaults to NULL) @package_id Package Id of the package that created the link } { set creation_user [ad_conn user_id] set creation_ip [ad_conn peeraddr] if {$package_id eq ""} { set package_id [ad_conn package_id] } return [db_exec_plsql extlink_new {}] } ad_proc -deprecated content_extlink::edit { -extlink_id:required -url:required -label:required -description:required } { Edit an existing external link. The parameters are required because it is assumed that the caller will be pulling the existing values out of the database before editing them. @extlink_id Optional pre-assigned object_id for the link @url The URL of the external resource @label Label for the extlink (defaults to the URL) @description An extended description of the link (defaults to NULL) @see content::extlink::edit } { set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml extlink_update_object {} db_dml extlink_update_extlink {} } } ad_proc -deprecated content_extlink::delete { -extlink_id:required } { Delete an external link. @see content::extlink::delete @extlink_id The object id of the link to delete } { db_exec_plsql extlink_delete {} } ad_proc -deprecated content_extlink::extlink_p { -item_id:required } { Returns true if the given item is an external link. @see content::extlink::is_extlink @extlink_id The object id of the item to check. } { return [db_string extlink_check {}] } ad_proc -deprecated content_extlink::extlink_name { -item_id:required } { Returns the name of an extlink @item_id The object id of the item to check. @see content::extlink::name } { return [db_string extlink_name {}] } openacs-5.7.0/packages/acs-content-repository/tcl/extlink-procs.xql0000644000175000017500000000103507723347122025324 0ustar frankiefrankie update cr_extlinks set url = :url, label = :label, description = :description where extlink_id = :extlink_id select label from cr_extlinks where extlink_id = :item_id openacs-5.7.0/packages/acs-content-repository/tcl/doc-procs.tcl0000644000175000017500000001470510551254373024377 0ustar frankiefrankie################################### # # Process function headers and return comments in JavaDoc format. sort of. # ################################## namespace eval doc { ad_proc -public package_info { package_name info_ref } { Set up a data source with overall package info (overview, see also, etc.) } { upvar $info_ref info set info_source [db_string get_info ""] # Delete leading stars and dashes regsub -all -line -- {^( |--|\*|/\*\*|\*/)*} $info_source "" info_source # Get the comment block regexp {[^@]*} $info_source comment set info(comment) $comment if {[regexp {@see (.*)} $info_source x see]} { foreach s [split $see ","] { # strip braces regsub {\{([^\}]+)\}} $s {\1} s lappend see_links $s } } if { [info exists see_links] } { set info(see) $see_links } } ad_proc -public get_proc_header { proc_name package_name doc_ref code_ref { db "" } } { Retreive the function header for a specific function and parse out the javadoc comment. } { variable start_text; variable end_text; upvar $doc_ref doc upvar $code_ref code set header [db_string get_header ""] # Get JavaDoc block, if any if { [regexp {/\*\*(.*)\*/} $header match] } { # Strip off the leading --, *, /**, */ regsub -all -line -- {^( |--|\*|/\*\*|\*/)*} $match "" doc # Take the doc out of the code regsub -- { *--/\*\*.*\*/(\n*)} $header "" code } else { set doc "" set code $header } } ad_proc -public parse_proc_header { doc_block code_block param_ref tags_ref code_ref {level 2}} { Parse the header block and prepare the datasources: Prepare a multirow datasource for the param tags Prepare a onerow datasource for all the other tags } { upvar $level "${param_ref}:rowcount" param_rowcount upvar $level $tags_ref tags set param_rowcount 0 set tags(code) $code_block # Go through all the tags and stick them in the appropriate datasources set remaining_doc $doc_block while { [regexp {[^@]*@([a-zA-Z0-9_-]+) +([^@]*)(.*?)} $remaining_doc match tag data remaining_doc] } { if { [string equal -nocase $tag "param"] } { if { [regexp {([^ ]+) +(.*)} $data match name value] } { incr param_rowcount upvar $level "${param_ref}:$param_rowcount" row set row(name) $name set row(value) $value set row(rownum) $param_rowcount } } else { set tags($tag) [string trim $data] } } # Get all the stuff that is not a tag (at the top) if { [template::util::is_nil tags(header)] } { set doc_head "" regexp {[^@]*} $doc_block doc_head set tags(header) $doc_head } # Determine whether we have a procedure or a function if { [template::util::is_nil tags(type)] } { if { [regexp -nocase -line {(procedure|function) .*$} $code_block match type] } { set tags(type) [string totitle $type] } else { set tags(type) "Subprogram" } } upvar $level $code_ref code set code $code_block } ad_proc -public get_proc_doc { proc_name package_name param_ref tags_ref code_ref args } { Query the database and prepare the datasources The user should call this procedure } { upvar $tags_ref tags set opts(db) "" template::util::get_opts $args get_proc_header $proc_name $package_name doc_block code_block $opts(db) parse_proc_header $doc_block $code_block $param_ref $tags_ref $code_ref # Get the proc name if { [template::util::is_nil tags(name)] } { set tags(name) "${package_name}.${proc_name}" } # Modify the "see" tag to dislplay links if { [info exists tags(see)] } { if { [template::util::is_nil opts(link_url_stub)] } { # Just remove the links regsub -all {\{([^\}]*)\}} $tags(see) {\1} new_see set tags(see) $new_see } else { if { [template::util::is_nil opts(link_package_name)] } { set opts(link_package_name) package_name } if { [template::util::is_nil opts(link_proc_name)] } { set opts(link_proc_name) proc_name } regsub -all {\&} $opts(link_url_stub) {\\\&} stub set subspec "\\1.\\2" regsub -all {\{([a-zA-Z0-9_]+)\.([a-zA-Z0-9_]+)\}} $tags(see) $subspec new_see set tags(see) $new_see } } } ad_proc -public package_list { {db ""} } { Return a list of all the packages in the data model, in form { {label value} {label value} ... } } { set result [db_list_of_list get_packages ""] return $result } ad_proc -public func_list { package_name {db ""} } { Return a list of all the function creation headers in a package, in form { value value ... } } { set result [db_list_of_lists get_funcs ""] set line_opts [list] foreach line $result { # Only get lines in form "procedure proc_name..." or "function func_name..." if { [regexp {(procedure|function)[^a-zA-Z0-9_]*([a-zA-Z0-9_]+)} $line match type name] && ![regexp {\-\-} $line match]} { lappend line_opts [list "[string totitle $type] [string tolower $name]" \ [string tolower $name]] } } return $line_opts } ad_proc -public func_multirow { package_name result_ref {db ""} } { Return a multirow datatsource for all the functions { value value ... } } { upvar "${result_ref}:rowcount" result_rowcount set result_rowcount 0 # Get each line that contains "procedure" or "function" in it # Pretty risky... The like query should be improved to return # less false matches db_multirow result get_functions "" { # Only insert a row into the datasource if it looks like a procedure # or function definition # Maybe this should ignore comments, too ? [^-]* at the beginning if { [regexp {(procedure|function)[^a-zA-Z0-9_]*([a-zA-Z0-9_]+)} \ $line_header match type name] && ![regexp {\-\-} $line_header match]} { incr result_rowcount upvar "${result_ref}:${result_rowcount}" result_row set result_row(rownum) $result_rowcount set result_row(type) [string totitle $type] set result_row(name) [string tolower $name] } } } } openacs-5.7.0/packages/acs-content-repository/tcl/revision-procs-postgresql.xql0000644000175000017500000001310010041311105027654 0ustar frankiefrankie postgresql7.1 select i.storage_type, i.storage_area_key, r.mime_type, r.revision_id, r.content_length from cr_items i, cr_revisions r where r.revision_id = content_item__get_live_revision(:item_id) and i.item_id = r.item_id select :path || content from cr_revisions where revision_id = :revision_id select lob as content from cr_revisions where revision_id = :revision_id select content_type__register_mime_type('content_revision', :mime_type) select content_item__is_subclass(:image_type, 'image') select content_item__is_subclass(:other_type, 'content_revision') select image__new( /* name => */ :object_name, /* parent_id => */ :parent_id, /* item_id => */ :item_id, /* revision_id => */ :revision_id, /* mime_type => */ :mime_type, /* creation_user => */ :creation_user, /* creation_ip => */ :creation_ip, /* title => */ :title, /* description => */ :description, /* storage_type => */ :storage_type, /* content_type => */ :image_type, /* nls_language => */ null, /* publish_date => */ current_timestamp, /* height => */ :original_height, /* width => */ :original_width, /* package_id => */ :package_id ); select image__new_revision ( /* item_id => */ :item_id, /* revision_id => */ :revision_id, /* title => */ :title, /* description => */ :description, /* publish_date => */ current_timestamp, /* mime_type => */ :mime_type, /* nls_language => */ null, /* creation_user => */ :creation_user, /* creation_ip => */ :creation_ip, /* height => */ :original_height, /* width => */ :original_width, /* package_id => */ :package_id ); select content_item__new ( /* name => */ varchar :object_name, /* parent_id => */ :parent_id, /* item_id => */ :item_id, /* new_locale => */ null, /* creation_date => */ current_timestamp, /* creation_user => */ :creation_user, /* context_id => */ :parent_id, /* creation_ip => */ :creation_ip, /* item_subtype => */ 'content_item', /* content_type => */ :other_type, /* title => */ null, /* description => */ null, /* mime_type => */ null, /* nls_language => */ null, /* text => */ null, /* storage_type => */ :storage_type, /* package_id => */ :package_id ); select content_revision__new ( /* title => */ :title, /* description => */ :description, /* publish_date => */ current_timestamp, /* mime_type => */ :mime_type, /* nls_language => */ null, /* data => */ null, /* item_id => */ :item_id, /* revision_id => */ :revision_id, /* creation_date => */ current_timestamp, /* creation_user => */ :creation_user, /* creation_ip => */ :creation_ip, /* package_id => */ :package_id ); update cr_revisions set mime_type = :mime_type, lob = [set __lob_id [db_string get_lob_id "select empty_lob()"]] where revision_id = :revision_id update cr_revisions set content_length = lob_length(lob) where revision_id = :revision_id select content_item__set_live_revision(:revision_id) update cr_revisions set content = :filename, mime_type = :mime_type, content_length = :tmp_size where revision_id = :revision_id openacs-5.7.0/packages/acs-content-repository/tcl/folder-procs-oracle.xql0000644000175000017500000000044310046433070026354 0ustar frankiefrankie oracle8.1.6 begin content_folder.delete(:folder_id); end; openacs-5.7.0/packages/acs-content-repository/tcl/keyword-procs.tcl0000644000175000017500000000761110551254373025314 0ustar frankiefrankiead_library { Procs for manipulating keywords. @author Lars Pind @author Mark Aufflick @creation-date February 27, 2003 @cvs-id $Id: keyword-procs.tcl,v 1.11 2007/01/10 21:22:03 gustafn Exp $ } namespace eval cr {} namespace eval cr::keyword {} ad_proc -public -deprecated cr::keyword::new { {-heading:required} {-description ""} {-parent_id ""} {-keyword_id ""} {-object_type "content_keyword"} {-package_id ""} } { Create a new keyword @see content::keyword::new } { set user_id [ad_conn user_id] set creation_ip [ad_conn peeraddr] if {$package_id eq ""} { set package_id [ad_conn package_id] } set keyword_id [db_exec_plsql content_keyword_new {}] return $keyword_id } ad_proc -public -deprecated cr::keyword::delete { {-keyword_id:required} } { Delete a keyword. @author Peter Marklund @see content::keyword::delete } { db_exec_plsql delete_keyword {} } ad_proc -public -deprecated cr::keyword::set_heading { {-keyword_id:required} {-heading:required} } { Update a keyword heading @see content::keyword::set_heading } { db_exec_plsql set_heading { } } ad_proc -public cr::keyword::get_keyword_id { {-parent_id:required} {-heading:required} } { Get the keyword with the given heading under the given parent. Returns the empty string if none exists. } { return [db_string select_keyword_id {} -default {}] } ad_proc -public -deprecated cr::keyword::item_unassign { {-keyword_id:required} {-item_id:required} } { Unassign a single keyword from a content item. Returns the supplied item_id for convenience. @see content::keyword::item_unassign } { db_exec_plsql item_unassign {} return $item_id } ad_proc -public cr::keyword::item_unassign_children { {-item_id:required} {-parent_id:required} } { Unassign all the keywords attached to a content item that are children of keyword parent_id. Returns the supplied item_id for convenience. } { db_dml item_unassign_children {} return $item_id } ad_proc -public -deprecated cr::keyword::item_assign { {-item_id:required} {-keyword_id:required} {-singular:boolean} } { Assign one or more keywords to a content_item. @param singular If singular is specified, then any keywords with the same parent_id as this keyword_id will first be unassigned. @param keyword_id A list of keywords to assign. @return the supplied item_id for convenience. @see content::keyword::item_assign } { # First, unassign for the parents of each/all if {$singular_p} { foreach keyword $keyword_id { set parent_id [db_string get_parent_id {}] item_unassign_children -item_id $item_id -parent_id $parent_id } } # Now assign for each/all foreach keyword $keyword_id { db_exec_plsql keyword_assign {} } return $item_id } ad_proc -public cr::keyword::item_get_assigned { {-item_id:required} {-parent_id} } { Returns a list of all keywords assigned to the given cr_item. If parent_id is supplied, only keywords that are children of parent_id are listed. } { if {[info exists parent_id]} { set keyword_list [db_list get_child_keywords {}] } else { set keyword_list [db_list get_keywords {}] } return $keyword_list } ad_proc -public cr::keyword::get_options_flat { {-parent_id ""} } { Returns a flat options list of the keywords with the given parent_id. } { return [db_list_of_lists select_keyword_options {}] } ad_proc -public cr::keyword::get_children { {-parent_id ""} } { Returns the ids of the keywords having the given parent_id. Returns an empty list if there are no children. @author Peter Marklund } { return [db_list select_child_keywords { select keyword_id from cr_keywords where parent_id = :parent_id }] } openacs-5.7.0/packages/acs-content-repository/tcl/keyword-procs.xql0000644000175000017500000000352607733604335025344 0ustar frankiefrankie select keyword_id from cr_keywords where parent_id = :parent_id and heading = :heading delete from cr_item_keyword_map where item_id = :item_id and keyword_id in (select p.keyword_id from cr_keywords p where p.parent_id = :parent_id) select parent_id from cr_keywords where keyword_id = :keyword select keyword_id from cr_item_keyword_map where item_id = :item_id select km.keyword_id from cr_item_keyword_map km, cr_keywords kw where km.item_id = :item_id and kw.parent_id = :parent_id and kw.keyword_id = km.keyword_id select heading, keyword_id from cr_keywords where [ad_decode $parent_id "" "parent_id is null" "parent_id = :parent_id"] order by lower(heading) openacs-5.7.0/packages/acs-content-repository/tcl/filter-procs.tcl0000644000175000017500000002221711126244270025106 0ustar frankiefrankie########### # Register the filter to automatically look up paths to content # items and retrieve the appropriate item id ########### namespace eval content { variable item_id variable item_url variable template_url variable revision_id } ad_proc -public content::get_template_root {} { Find the directory in the file system where templates are stored. There are a variety of ways in which this can be set. The proc looks for that directory in the following places in this order: (1) the TemplateRoot parameter of the package for which the request is made, i.e., [ad_conn package_id] (2) the TemplateRoot parameter of the acs-content-repository If it is not found in any of these places, it defaults to [acs_root_dir]/templates If the value resulting from the search does not start with a '/' it is taken to be relative to [acs_root_dir] @return the template root (full path from /) } { # Look for package-defined root set package_id [ad_conn package_id] set template_root \ [parameter::get -package_id $package_id -parameter TemplateRoot -default ""] if { $template_root eq "" } { # Look for template root defined in the CR set package_id [apm_package_id_from_key "acs-content-repository"] set template_root [parameter::get -package_id $package_id \ -parameter TemplateRoot -default "templates"] } if { [string index $template_root 0] ne "/" } { # Relative path, prepend server_root set template_root "[acs_root_dir]/$template_root" } return [ns_normalizepath $template_root] } ad_proc -public content::has_content {} { return true if the request has content associated with it @return 1 if ::content::item_id is defined } { variable item_id return [info exists item_id] } ad_proc -public content::get_item_id {} { @return current value of ::content::item_id } { variable item_id return $item_id } ad_proc -public content::get_content { { content_type {} } } { sets the content in the array "content" in the callers scope assumes item_id or revision_id is set in the ::content namespace. @param content_type } { variable item_id variable revision_id if { [template::util::is_nil item_id] } { ns_log warning "content::get_content: No active item in content::get_content" return } if { [template::util::is_nil revision_id] } { # Try to get the live revision ns_log notice "content::get_content: trying to get live revision" set revision_id [db_string get_revision ""] if { [template::util::is_nil revision_id] } { ns_log notice "content::get_content: No live revision for item $item_id" return } } # Get the mime type, decide if we want the text set mime_type [db_string get_mime_type ""] if { [template::util::is_nil mime_type] } { ns_log notice "content::get_content: No such revision: $revision_id" return } if { [string equal -length 4 "text" $mime_type] } { set text_sql [db_map content_as_text] } else { set text_sql "" } # Get the content type if { $content_type eq "" } { set content_type [db_string get_content_type ""] } # Get the table name set table_name [db_string get_table_name ""] upvar content content # Get (all) the content (note this is really dependent on file type) if {![db_0or1row get_content "" -column_array content]} { ns_log notice "content::get_content: No data found for item $item_id, revision $revision_id" return 0 } } ad_proc -public content::get_template_url {} { @return current value of ::content::template_url } { variable template_url return $template_url } ad_proc -public content::get_folder_labels { { varname "folders" } } { Set a data source in the calling frame with folder URL and label Useful for generating a context bar } { variable item_id # this repeats the query used to look up the item in the first place # but there does not seem to be a clear way around this # build the folder URL out as we iterate over the query set query [db_map get_url] db_multirow -extend {url} $varname ignore_get_url $query { append url "$name/" } } ad_proc -public content::get_content_value { revision_id } { @return content element corresponding to the provided revision_id } { db_transaction { db_exec_plsql gcv_get_revision_id { begin content_revision.to_temporary_clob(:revision_id); end; } # Query for values from a previous revision set content [db_string gcv_get_previous_content ""] } return $content } ad_proc -public content::init { {-resolve_index "f"} {-revision "live"} urlvar rootvar {content_root ""} {template_root ""} {context "public"} {rev_id ""} {content_type ""} } { Initialize the namespace variables for the ::content procs and figures out which template to use and set up the template for the required content type etc. } { upvar $urlvar url $rootvar root_path variable root_folder_id variable item_id variable revision_id set root_folder_id $content_root # if a .tcl file exists at this url, then don't do any queries if { [file exists [ns_url2file "$url.tcl"]] } { return 0 } # cache this query persistently for 1 hour set item_info(item_id) [::content::item::get_id -item_path $url \ -root_folder_id $content_root \ -resolve_index $resolve_index] set item_info(content_type) [::content::item::get_content_type \ -item_id $item_info(item_id)] # No item found, so do not handle this request if {$item_info(item_id) eq ""} { set item_info(item_id) [::content::item::get_id -item_path $url \ -root_folder_id $content_root \ -resolve_index $resolve_index] set item_info(content_type) [::content::item::get_content_type \ -item_id $item_info(item_id)] if {$item_info(item_id) eq ""} { ns_log notice "content::init: no content found for url $url" return 0 } } variable item_url set item_url $url set item_id $item_info(item_id) if { $content_type eq "" } { set content_type $item_info(content_type) } # TODO accept latest revision as well. DaveB # Make sure that a live revision exists if { $rev_id eq "" } { if {"best" eq $revision} { # lastest_revision unless live_revision is set, then live_revision set revision_id [::content::item::get_best_revision -item_id $item_id] } else { # default live_revision set revision_id [::content::item::get_live_revision -item_id $item_id] } if {$revision_id eq ""} { ns_log notice "content::init: no live revision found for content item $item_id" return 0 } } else { set revision_id $rev_id } variable template_path # Get the template set template_found_p [db_0or1row get_template_url "" -column_array info] if { !$template_found_p || $info(template_url) eq {} } { ns_log notice "content::init: No template found to render content item $item_id in context '$context'" return 0 } set url $info(template_url) set root_path [get_template_root] # Added so that published templates are regenerated if they are missing. # This is useful for default templates. # (OpenACS - DanW, dcwickstrom@earthlink.net) set file ${root_path}/${url}.adp if { ![file exists $file] } { file mkdir [file dirname $file] set text [content::get_content_value $info(template_id)] template::util::write_file $file $text } set file ${root_path}/${url}.tcl if { ![file exists $file] } { file mkdir [file dirname $file] set text "\# Put the current revision's attributes in a onerow datasource named \"content\". \# The detected content type is \"$content_type\". content::get_content $content_type if { !\[string equal \"text/html\" \$content(mime_type)\] && !\[ad_html_text_convertable_p -from \$content(mime_type) -to text/html\] } { \# don't render its content cr_write_content -revision_id \$content(revision_id) ad_script_abort } \# Ordinary text/* mime type. template::util::array_to_vars content set text \[cr_write_content -string -revision_id \$revision_id\] if { !\[string equal \"text/html\" \$content(mime_type)\] } { set text \[ad_html_text_convert -from \$content(mime_type) -to text/html -- \$text\] } set context \[list \$title\] ad_return_template " template::util::write_file $file $text } return 1 } ad_proc -public content::deploy { url_stub } { render the template and write it to the file system with template::util::write_file } { set output_path [ns_info pageroot]$url_stub init url_stub root_path set output [template::adp_parse $file_stub] template::util::write_file $output_path $output } openacs-5.7.0/packages/acs-content-repository/tcl/filter-procs.xql0000644000175000017500000000317707702263321025137 0ustar frankiefrankie select live_revision from cr_items where item_id = :item_id select mime_type from cr_revisions where revision_id = :revision_id select content_type from cr_items where item_id = :item_id select table_name from acs_object_types where object_type = :content_type , content as text select x.*, :content_type as content_type $text_sql from cr_revisions r, ${table_name}x x where r.revision_id = :revision_id and x.revision_id = r.revision_id select live_revision from cr_items where item_id = :item_id select live_revision from cr_items where item_id = :item_id openacs-5.7.0/packages/acs-content-repository/tcl/doc-procs-postgresql.xql0000644000175000017500000000301207277547635026630 0ustar frankiefrankie postgresql7.1 select doc__get_package_header(:package_name) from dual select doc__get_proc_header(:proc_name, :package_name) from dual select distinct substr(proname,1,position('__' in proname)-1) as label, substr(proname,1,position('__' in proname)-1) as value from pg_proc where proname like '%\\\_\\\_%' order by label select 'function ' || proname as line_header from pg_proc where proname like lower(:package_name) || '\\\_\\\_%' order by line_header select 'function ' || substr(proname,length(:package_name)+3) as line_header from pg_proc where proname like lower(:package_name) || '\\\_\\\_%' order by line_header openacs-5.7.0/packages/acs-content-repository/tcl/symlink-procs.tcl0000644000175000017500000000572210551254373025317 0ustar frankiefrankiead_library { Manage external links in the content repository @author Dave Bauer (dave@thedesignexperience.org) @cvs-d $Id: } namespace eval content_symlink {} ad_proc -deprecated content_symlink::new { {-symlink_id ""} -target_id:required -parent_id:required {-name ""} {-label ""} {-package_id ""} } { Create a new internal link. @symlink_id Optional pre-assigned object_id for the link @target_id The item_id of the target of the link @parent_id The folder that will contain this symlink @name Name to assign the object (defaults to the name of the target item) @label Label for the symlink (defaults to the URL) @description An extended description of the link (defaults to NULL) @package_id Package Id of the package that created the link @see content::symlink::new } { set creation_user [ad_conn user_id] set creation_ip [ad_conn peeraddr] if {$package_id eq ""} { set package_id [ad_conn package_id] } return [db_exec_plsql symlink_new {}] } ad_proc content_symlink::edit { -symlink_id:required -target_id:required -label:required } { Edit an existing internal link. The parameters are required because it is assumed that the caller will be pulling the existing values out of the database before editing them. @symlink_id Optional pre-assigned object_id for the link @target_id The target item_id of the link @label Label for the symlink (defaults to the target_id item title) @description An extended description of the link (defaults to NULL) } { set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml symlink_update_object {} db_dml symlink_update_symlink {} } } ad_proc -deprecated content_symlink::delete { -symlink_id:required } { Delete an external link. @symlink_id The object id of the link to delete @see content::symlink::delete } { db_exec_plsql symlink_delete {} } ad_proc -deprecated content_symlink::symlink_p { -item_id:required } { Returns true if the given item is a symlink @symlink_id The object id of the item to check. @see content::symlink::is_symlink } { return [db_string symlink_check {}] } ad_proc content_symlink::symlink_name { -item_id:required } { Returns the name of an symlink @item_id The object id of the item to check. } { return [db_string symlink_name {}] } ad_proc -public -deprecated content_symlink::resolve { -item_id:required } { @param item)id item_id of content_symlink item to resolve @return item_id of symlink target @see content::symlink::resolve } { return [db_exec_plsql resolve_symlink ""] } ad_proc -public -deprecated content_symlink::resolve_content_type { -item_id:required } { @param item_id item_id of symlink @return content_type of target item @see content::symlink::resolve_content_type } { return [db_exec_plsql resolve_content_type ""] } openacs-5.7.0/packages/acs-content-repository/tcl/symlink-procs.xql0000644000175000017500000000105110005537431025321 0ustar frankiefrankie update cr_symlinks set target_id = :target_id, label = :label, description = :description where symlink_id = :symlink_id select label from cr_symlinks where symlink_id = :item_id openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-procs.tcl0000644000175000017500000000454610551254373030267 0ustar frankiefrankie# tcl/acs-content-repository-procs.tcl patch # # a patch to the cr for handling the deleting revision's files # when the revision has been deleted from the database # # Walter McGinnis (wtem@olywa.net), 2001-09-23 # based on original photo-album package code by Tom Baginski # # JCD 2002-12-96 This should be fixed since on oracle anyway, being in a # transaction does not mean that you get read level consistency across # queries. End result is that someone can do an insert into the # delete list and the delete_files query will whack it and the file # will then never be deleted. Oops. ad_proc -private cr_delete_scheduled_files {} { Tries to delete all the files in cr_files_to_delete. Makes sure file isn't being used by another revision prior to deleting it. Should be scheduled daily. This proc is extremely simple, and does not have any concurrancy checks to make sure another version of the proc is running/deleting a file. Will add some concurancy checks to a future revision. Right now go with short and sweet, count on scheduling to prevent conflicts } { db_transaction { # subselect makes sure there isn't a parent revision still lying around db_foreach fetch_paths { *SQL* } { # try to remove file from filesystem set file "[cr_fs_path $storage_area_key]/${path}" ns_log Debug "cr_delete_scheduled_files: deleting $file" ns_unlink -nocomplain "$file" } # now that all scheduled files deleted, clear table db_dml delete_files { *SQL* } } } ## ## Scan AOLserver mime types and insert them into cr_mime_types ## ## ben@openforce ## ad_proc -private cr_scan_mime_types {} { # Get the config file ns_set set mime_types [ns_configsection "ns/mimetypes"] if {$mime_types ne ""} { set n_mime_types [ns_set size $mime_types] for {set i 0} {$i < $n_mime_types} {incr i} { set extension [ns_set key $mime_types $i] set mime_type [ns_set value $mime_types $i] # special case if {$extension eq "NoExtension" || $extension eq "Default"} { continue } ns_log Notice "cr_scan_mime_types: inserting MIME TYPE - $extension maps to $mime_type" # Insert the mime type db_dml insert_mime_type {} } } } openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-procs.xql0000644000175000017500000000147107622727356030316 0ustar frankiefrankie SELECT distinct crftd.path, crftd.storage_area_key FROM cr_files_to_delete crftd WHERE not exists (SELECT 1 FROM cr_revisions r WHERE r.content = crftd.path) delete from cr_files_to_delete insert into cr_mime_types (mime_type, file_extension) select :mime_type, :extension from dual where not exists (select 1 from cr_mime_types where mime_type = :mime_type) openacs-5.7.0/packages/acs-content-repository/tcl/content-template-procs.tcl0000644000175000017500000000462410167266311027112 0ustar frankiefrankie# ad_library { Procudures for content template @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-09 @arch-tag: a2fad1c8-17eb-412c-a62e-9704d346b27b @cvs-id $Id: content-template-procs.tcl,v 1.7 2005/01/06 16:52:25 daveb Exp $ } namespace eval ::content::template {} ad_proc -public content::template::new { -name:required {-text ""} {-parent_id ""} {-is_live ""} {-template_id ""} -creation_date {-creation_user ""} {-creation_ip ""} {-package_id ""} } { @param name @param text @param parent_id @param is_live @param template_id @param creation_date @param creation_user @param creation_ip @return template_id of created template } { set arg_list [list \ [list name $name ] \ [list text $text ] \ [list parent_id $parent_id ] \ [list is_live $is_live ] \ [list template_id $template_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ [list package_id $package_id ] \ ] if {[exists_and_not_null creation_date]} { lappend arg_list [list creation_date $creation_date ] } return [package_exec_plsql -var_list $arg_list content_template new] } ad_proc -public content::template::delete { -template_id:required } { @param template_id @return 0 } { return [package_exec_plsql -var_list [list \ [list template_id $template_id ] \ ] content_template del] } ad_proc -public content::template::get_path { -template_id:required {-root_folder_id ""} } { @param template_id @param root_folder_id @throws -20000: Invalid item ID: %'', get_path__item_id; @return "/" delimited path from root to supplied template_id } { return [package_exec_plsql -var_list [list \ [list template_id $template_id ] \ [list root_folder_id $root_folder_id ] \ ] content_template get_path] } ad_proc -public content::template::get_root_folder { } { @return folder_id of Template Root Folder } { return [package_exec_plsql -var_list [list \ ] content_template get_root_folder] } ad_proc -public content::template::is_template { -template_id:required } { @param template_id @return t or f } { return [package_exec_plsql -var_list [list \ [list template_id $template_id ] \ ] content_template is_template] } openacs-5.7.0/packages/acs-content-repository/tcl/acs-content-repository-init-postgresql.xql0000644000175000017500000000043107277414751032325 0ustar frankiefrankie postgresql7.1 select cr_scheduled_release_exec(); openacs-5.7.0/packages/acs-content-repository/tcl/folder-procs.tcl0000644000175000017500000000112510153251145025065 0ustar frankiefrankiead_library { Procedures in the folder namespace related to content folders. @author Peter Marklund @cvs-id $Id: folder-procs.tcl,v 1.2 2004/12/01 05:11:01 alfredw Exp $ } namespace eval folder {} ad_proc -public -deprecated folder::delete { {-folder_id:required} } { Deprecated. See content::folder::delete instead. Delete a content folder. If the folder to delete has children content items referencing it via acs_objects.context_id then this proc will fail. @author Peter Marklund @see content::folder::delete } { db_exec_plsql delete_folder {} } openacs-5.7.0/packages/acs-content-repository/tcl/revision-procs.tcl0000644000175000017500000003501211533343743025463 0ustar frankiefrankie# upload an item revision from a file ad_proc -public cr_write_content { -string:boolean -item_id -revision_id } { Write out the specified content to the current HTML connection or return it to the caller by using the -string flag. Only one of item_id and revision_id should be passed to this procedure. If item_id is provided the item's live revision will be written, otherwise the specified revision. This routine was was written to centralize the downloading of data from the content repository. Previously, similar code was scattered among various packages, not all of which were written to handle both in-database and in-filesystem storage of content items. Though this routine is written to be fully general in terms of a content item's storage type, typically those stored as text aren't simply dumped to the user in raw form, but rather ran through the templating system in order to surround the content with decorative HTML. @param string specifies whether the content should be returned as a string or (the default) be written to the HTML connection (ola@polyxena.net) @param item_id the item to write @param revision_id revision to write @author Don Baccus (dhogaza@pacifier.com) } { if { [info exists revision_id] && [info exists item_id] } { ad_return -code error "Both revision_id and item_id were specfied" } if { [info exists item_id] } { if { ![db_0or1row get_item_info ""] } { error "There is no content that matches item_id '$item_id'" {} NOT_FOUND } } elseif { [info exists revision_id] } { if { ![db_0or1row get_revision_info ""] } { error "There is no content that matches revision_id '$revision_id'" {} NOT_FOUND } } else { ad_return -code error "Either revision_id or item_id must be specified" } if { $storage_type ne "file" && \ $storage_type ne "text" && \ $storage_type ne "lob" } { ad_return -code error "Storage type '$storage_type' is invalid." } # I set content length to 0 here because otherwise I need to do # db-specific queries for get_revision_info if {$content_length eq ""} { set content_length 0 } switch $storage_type { text { set text [db_string write_text_content ""] if { $string_p } { return $text } ReturnHeaders $mime_type ns_write $text } file { set path [cr_fs_path $storage_area_key] set filename [db_string write_file_content ""] if {$filename eq ""} { ad_return -code error "No content for the revision $revision_id. This seems to be an error which occured during the upload of the file" } else { if { $string_p } { set fd [open $filename "r"] fconfigure $fd \ -translation binary \ -encoding [encoding system] set text [read $fd] close $fd return $text } else { # JCD: for webdavfs there needs to be a content-length 0 header # but ns_returnfile does not send one. Also, we need to # ns_return size 0 files since if fastpath is enabled ns_returnfile # simply closes the connection rather than send anything (including # any headers). This bug is fixed in AOLServer 4.0.6 and later # but work around it for now. set size [file size $filename] if {!$size} { ns_set put [ns_conn outputheaders] "Content-Length" 0 ns_return 200 text/plain {} } else { if {[info command ad_returnfile_background] eq "" || [security::secure_conn_p]} { ns_returnfile 200 $mime_type $filename } else { ad_returnfile_background 200 $mime_type $filename } } } } } lob { if { $string_p } { return [db_blob_get write_lob_content ""] } # need to set content_length header here ns_set put [ns_conn outputheaders] "Content-Length" $content_length ReturnHeaders $mime_type # also need to check for HEAD method and skip sending # actual content if {![string equal -nocase "head" [ns_conn method]]} { db_write_blob write_lob_content "" } else { ns_conn close } } } return } ad_proc -public cr_import_content { {-storage_type "file"} -creation_user -creation_ip -image_only:boolean {-image_type "image"} {-other_type "content_revision"} {-title ""} {-description ""} {-package_id ""} -item_id parent_id tmp_filename tmp_size mime_type object_name } { Import an uploaded file into the content repository. @param storage_type Where to store the content (lob or file), defaults to "file" (later a system-wide parameter) @param creation_user The creating user (defaults to current user) @param creation_ip The creating ip (defaults to peeraddr) @param image_only Only allow images @param image_type The type of content item to create if the file contains an image @param other_type The type of content item to create for a non-image file @param title The title given the new revision @param description The description of the new revision @param package_id Package Id of the package that created the item @param item_id If present, make a new revision of this item, otherwise, make a new item @param parent_id The parent of the content item we create @param tmp_filename The name of the temporary file holding the uploaded content @param tmp_size The size of tmp_file @param mime_type The uploaded file's mime type @param object_name The name to give the result content item and revision This procedure handles all mime_type details, creating a new item of the appropriate type and stuffing the content into either the file system or the database depending on "storage_type". The new revision is set live, and its item_id is returned to the caller. image_type and other_type should be supplied when the client package has extended the image and content_revision types to hold package-specific information. Checking is done to ensure that image_type has been inherited from image, and that other_type has been inherited from content_revision. It up to the caller to do any checking on size limitations, etc. } { if { ![info exists creation_user] } { set creation_user [ad_conn user_id] } if { ![info exists creation_ip] } { set creation_ip [ad_conn peeraddr] } # DRB: Eventually we should allow for text storage ... (CLOB for Oracle) if { $storage_type ne "file" && $storage_type ne "lob" } { return -code error "Imported content must be stored in the file system or as a large object" } if {$mime_type eq "*/*"} { set mime_type "application/octet-stream" } if {$package_id eq ""} { set package_id [ad_conn package_id] } set old_item_p [info exists item_id] if { !$old_item_p } { set item_id [db_nextval acs_object_id_seq] } # use content_type of existing item if {$old_item_p} { set content_type [db_string get_content_type ""] } else { # all we really need to know is if the mime type is mapped to image, we # actually use the passed in image_type or other_type to create the object if {[db_string image_type_p "" -default 0]} { set content_type image } else { set content_type content_revision } } set revision_id [db_nextval acs_object_id_seq] db_transaction { if { [empty_string_p [db_string is_registered "" -default ""]] } { db_dml mime_type_insert "" db_exec_plsql mime_type_register "" } switch $content_type { image { if { [db_string image_subclass ""] eq "f" } { ad_return -code error "Image file must be stored in an image object" } set what_aolserver_told_us "" if {$mime_type eq "image/jpeg"} { catch { set what_aolserver_told_us [ns_jpegsize $tmp_filename] } } elseif {$mime_type eq "image/gif"} { catch { set what_aolserver_told_us [ns_gifsize $tmp_filename] } } elseif {$mime_type eq "image/png"} { # we don't have built in png size detection # but we want to allow upload of png images } else { ad_return -code error "Unknown image type" } # the AOLserver jpegsize command has some bugs where the height comes # through as 1 or 2 if { $what_aolserver_told_us ne "" && \ [lindex $what_aolserver_told_us 0] > 10 && \ [lindex $what_aolserver_told_us 1] > 10 } { set original_width [lindex $what_aolserver_told_us 0] set original_height [lindex $what_aolserver_told_us 1] } else { set original_width "" set original_height "" } if { !$old_item_p } { db_exec_plsql image_new "" } else { db_exec_plsql image_revision_new "" } } default { if { $image_only_p } { ad_return -code error "The file you uploaded was not an image (.gif, .jpg or .jpeg) file" } if { [db_string content_revision_subclass ""] eq "f" } { ad_return -code error "Content must be stored in a content revision object" } if { !$old_item_p } { db_exec_plsql content_item_new "" } db_exec_plsql content_revision_new "" } } # insert the attatchment into the database switch $storage_type { file { set filename [cr_create_content_file $item_id $revision_id $tmp_filename] db_dml set_file_content "" } lob { db_dml set_lob_content "" -blob_files [list $tmp_filename] db_dml set_lob_size "" } } } return $revision_id } ad_proc cr_set_imported_content_live { -image_sql -other_sql mime_type revision_id } { @param image_sql Optional SQL to extend the base image type @param other_sql Optional SQL to extend the base content revision type @mime_type Mime type of the new revision @revision_id The revision we're setting live If provided execute the appropriate SQL in the caller's context, then set the given revision live. The idea is to give the caller a clean way of setting the additional information needed for its private type. This is a hack. Executing this SQL can't be done within cr_import_content because the caller can't see the new revision's key... } { if { [cr_registered_type_for_mime_type $mime_type] eq "image" } { if { [info exists image_sql] } { uplevel 1 [list db_dml dynamic_query $image_sql] } } elseif { [info exists other_sql] } { uplevel 1 [list db_dml dynamic_query $other_sql] } db_exec_plsql set_live "" } ad_proc cr_registered_type_for_mime_type { mime_type } { Return the type registered for this mime type. @mime_type param The mime type } { return [db_string registered_type_for_mime_type "" -default ""] } ad_proc -public cr_filename_to_mime_type { -create:boolean filename } { given a filename, returns the mime type. If the -create flag is given the mime type will be created; this assumes there is some other way such as ns_guesstype to find the filename @param create flag whether to create the mime type the routine picks for filename @param filename the filename to try to guess a mime type for (the file need not exist, the routine does not attempt to access the file in any way) @return mimetype (or */* of unknown) @author Jeff Davis (davis@xarg.net) } { set extension [string tolower [string trimleft [file extension $filename] "."]] if {$extension eq ""} { return "*/*" } if {[db_0or1row lookup_mimetype { select mime_type from cr_extension_mime_type_map where extension = :extension }]} { return $mime_type } else { set mime_type [string tolower [ns_guesstype $filename]] ns_log Debug "guessed mime \"$mime_type\" create_p $create_p" if {(!$create_p) || $mime_type eq "*/*" || $mime_type eq ""} { # we don't have anything meaningful for this mimetype # so just */* it. return "*/*" } # We guessed a type but there was no mapping # create it and map it. We know the extension cr_create_mime_type -extension $extension -mime_type $mime_type -description {} return $mime_type } } ad_proc -public cr_create_mime_type { -mime_type:required {-extension ""} {-description ""} } { Creates a mime type if it does not exist. Also maps extension to mime_type (unless the extension is already mapped to another mime type or extension is empty). @param mime_type the mime_type to create @param extension the default extension for the given mime type @param a plain text description of the mime type (< 200 characters) @author Jeff Davis (davis@xarg.net) } { # make both lower since that is the convention. # should never pass in anything that is not lower cased # already but just be safe. set mime_type [string tolower $mime_type] set extension [string tolower $extension] db_dml maybe_create_mime { insert into cr_mime_types (label, mime_type, file_extension) select :description, :mime_type, :extension from dual where not exists (select 1 from cr_mime_types where mime_type = :mime_type) } if { $extension ne "" } { db_dml maybe_map_extension { insert into cr_extension_mime_type_map (extension, mime_type) select :extension, :mime_type from dual where not exists (select 1 from cr_extension_mime_type_map where extension = :extension) } } } openacs-5.7.0/packages/acs-content-repository/tcl/revision-procs.xql0000644000175000017500000000337310440426443025505 0ustar frankiefrankie select i.storage_type, i.storage_area_key, r.mime_type, i.item_id, r.content_length from cr_items i, cr_revisions r where r.revision_id = :revision_id and i.item_id = r.item_id select content from cr_revisions where revision_id = :revision_id select content_type from cr_items where item_id = :item_id insert into cr_mime_types (mime_type) select :mime_type from dual where not exists (select 1 from cr_mime_types where mime_type = :mime_type) select content_type from cr_content_mime_type_map where mime_type = :mime_type select 1 from cr_content_mime_type_map where mime_type = :mime_type and content_type = 'content_revision' select 1 from cr_content_mime_type_map where mime_type = :mime_type and content_type = 'image' openacs-5.7.0/packages/acs-content-repository/tcl/publish-procs.tcl0000644000175000017500000007273410607655035025310 0ustar frankiefrankie namespace eval publish { variable item_id_stack variable revision_html namespace eval handle {} } ad_proc -public publish::get_page_root {} { Get the page root. All items will be published to the filesystem with their URLs relative to this root. The page root is controlled by the PageRoot parameter in CMS. A relative path is relative to [ns_info pageroot] The default is [ns_info pageroot] @return The page root @see publish::get_template_root @see publish::get_publish_roots } { # LARS TODO: This parameter doesn't exist, it's a remnant from the CMS package set root_path [parameter::get \ -package_id [ad_conn package_id] \ -parameter PageRoot] if { [string index $root_path 0] ne "/" } { # Relative path, prepend server_root set root_path "[ns_info pageroot]/$root_path" } return [ns_normalizepath $root_path] } ad_proc -public publish::get_publish_roots {} { Get a list of all page roots to which files may be published. The publish roots are controlled by the PublishRoots parameter in CMS, which should be a space-separated list of all the roots. Relative paths are relative to publish::get_page_root. The default is [list [publish::get_page_root]] @return A list of all the publish roots @see publish::get_template_root @see publish::get_page_root } { # LARS TODO: This parameter doesn't exist, it's a remnant from the CMS package set root_paths [parameter::get \ -package_id [ad_conn package_id] \ -parameter PublishRoots] if { [llength $root_paths] == 0 } { set root_paths [list [get_page_root]] } # Resolve relative paths set page_root [publish::get_page_root] set absolute_paths [list] foreach path $root_paths { if { [string index $path 0] ne "/" } { lappend absolute_paths [ns_normalizepath "$page_root/$path"] } else { lappend absolute_paths $path } } return $absolute_paths } ad_proc -public publish::mkdirs { path } { Create all the directories neccessary to save the specified file @param path The path to the file that is about to be saved } { set index [string last "/" $path] if { $index != -1 } { file mkdir [string range $path 0 [expr {$index - 1}]] } } ############################################### # Procs to maintain the item_id stack # main_item_id is always the id at the top of the stack ad_proc -private publish::push_id { item_id {revision_id ""}} { @private push_id Push an item id on top of stack. This proc is used to store state between child, relation and content tags. @param item_id The id to be put on stack @param revision_id {default ""} The id of the revision to use. If missing, live revision will most likely be used @see publish::pop_id @see publish::get_main_item_id @see publish::get_main_revision_id } { variable item_id_stack variable revision_html if { [template::util::is_nil item_id] } { error "Null id pushed on stack in publish::push_id" } # Determine old configuration set old_item_id "" set old_revision_id "" if { [info exists ::content::item_id] } { set old_item_id $::content::item_id } if { [info exists ::content::revision_id] } { set old_revision_id $::content::revision_id } # Preserve old data if { ![template::util::is_nil old_item_id] } { set pair [list $old_item_id $old_revision_id] if { ![template::util::is_nil item_id_stack] } { set item_id_stack [concat [list $pair] $item_id_stack] } else { # This is the first id pushed - also clear the cache set item_id_stack [list $pair] array unset revision_html } } else { set item_id_stack [list] } # Set new data set ::content::item_id $item_id set ::content::revision_id $revision_id } ad_proc -private publish::pop_id {} { @private pop_id Pop the item_id and the revision_id off the top of the stack. Clear the temporary item cache if the stack becomes empty. @return The popped item id, or the empty string if the string is already empty @see publish::push_id @see publish::get_main_item_id @see publish::get_main_revision_id } { variable item_id_stack set pair [lindex $item_id_stack 0] if { [template::util::is_nil pair] } { #error "Item id stack is empty in publish::pop_id" } set item_id_stack [lrange $item_id_stack 1 end] # If the stack is now empty, clear the cache if { [template::util::is_nil item_id_stack] } { array unset revision_html } set ::content::item_id [lindex $pair 0] set ::content::revision_id [lindex $pair 1] return $::content::item_id } ad_proc -public publish::proc_exists { namespace_name proc_name } { @public proc_exists Determine if a procedure exists in the given namespace @param namespace_name The fully qualified namespace name, such as "template::util" @param proc_name The proc name, such as "is_nil" @return 1 if the proc exists in the given namespace, 0 otherwise } { return [expr ![string equal \ [namespace eval $namespace_name \ "info procs $proc_name"] {}]] } ########################################################## # # Procs for handling mime types # ad_proc -public publish::handle_binary_file { item_id revision_id_ref url_ref error_ref args } { @public handle_binary_file Helper procedure for writing handlers for binary files. It will write the blob of the item to the filesystem, but only if -embed is specified. Then, it will attempt to merge the image with its template.
This proc accepts exactly the same options a typical handler. @param item_id The id of the item to handle @param revision_id_ref {required} The name of the variable in the calling frame that will recieve the revision_id whose content blob was written to the filesystem. @param url_ref The name of the variable in the calling frame that will recieve the relative URL of the file in the file system which contains the content blob @param error_ref The name of the variable in the calling frame that will recieve an error message. If no error has ocurred, this variable will be set to the empty string "" @option embed Signifies that the content should be embedded directly in the parent item. -embed is required for this proc, since it makes no sense to handle the binary file in any other way. @option revision_id {default The live revision for the item} The revision whose content is to be used @option no_merge If present, do NOT merge with the template, in order to prevent infinite recursion in the <content> tag. In this case, the proc will return the empty string "" @return The HTML resulting from merging the item with its template, or "" if no template exists or the -no_merge flag was specified @see publish::handle::image } { template::util::get_opts $args upvar $error_ref error_msg upvar $url_ref file_url upvar $revision_id_ref revision_id set error_msg "" if { [template::util::is_nil opts(revision_id)] } { set revision_id [::content::item::get_live_revision -item_id $item_id] } else { set revision_id $opts(revision_id) } # If the embed tag is true, return the html. Otherwise, # just write the image to the filesystem if { [info exists opts(embed)] } { set file_url [publish::write_content $revision_id \ -item_id $item_id -root_path [publish::get_publish_roots]] # If write_content aborted, give up if { [template::util::is_nil file_url] } { set error_msg "No URL found for revision $revision_id, item $item_id" return "" } # Try to use the registered template for the image if { ![info exists opts(no_merge)] } { set code "publish::merge_with_template $item_id $args" set html [eval $code] # Return the result of merging - could be "" return $html } return "" } else { set error_msg "No embed specified for handle_binary_file, aborting" return "" } } ad_proc -private publish::html_args { argv } { @private html_args Concatenate a list of name-value pairs as returned by set_to_pairs into a list of "name=value" pairs @param argv The list of name-value pairs @return An HTML string in format "name=value name=value ..." @see publish::set_to_pairs } { set extra_html "" if { ![template::util::is_nil argv] } { foreach { name value } $argv { append extra_html "$name=\"$value\" " } } return $extra_html } ad_proc -public publish::item_include_tag { item_id {extra_args {}} } { @public item_include_tag Create an include tag to include an item, in the form
include src=/foo/bar/baz item_id=item_id param=value param=value ...
@param item_id The item id @param extra_args {} A list of extra parameters to be passed to the include tag, in form {name value name value ...} @return The HTML for the include tag @see content::item::get_virtual_path @see publish::html_args } { # Concatenate all the extra html arguments into a string set extra_html [publish::html_args $extra_args]"" set item_url [::content::item::get_virtual_path -item_id $item_id] return "" } ad_proc -public publish::handle::image { item_id args } { The basic image handler. Writes the image blob to the filesystem, then either merges with the template or provides a default tag. Uses the title for alt text if no alt text is specified externally. } { template::util::get_opts $args # LARS TODO: Added -no_merge, verify how this is supposed to work set html [eval publish::handle_binary_file \ $item_id revision_id url error_msg $args -no_merge] # If an error happened, abort if { ![template::util::is_nil error_msg] } { ns_log Warning "publish::handle::image: WARNING: $error_msg" return "" } # Return the HTML if we have any if { ![template::util::is_nil html] } { return $html } # If the merging failed, output a straight tag db_1row i_get_image_info "" # Concatenate all the extra html arguments into a string if { [info exists opts(html)] } { set extra_html [publish::html_args $opts(html)] set have_alt [expr [lsearch [string tolower $opts(html)] "alt"] >= 0] } else { set extra_html "" set have_alt 0 } set html "" return $html } ad_proc -private publish::merge_with_template { item_id args } { @private merge_with_template Merge the item with its template and return the resulting HTML. This proc is simlar to content::init @param item_id The item id @option revision_id {default The live revision} The revision which is to be used when rendering the item @option html Extra HTML parameters to be passed to the ADP parser, in format {name value name value ...} @return The rendered HTML, or the empty string on failure @see publish::handle_item } { #set ::content::item_id $item_id set ::content::item_url [::content::item::get_virtual_path -item_id $item_id] template::util::get_opts $args # Either auto-get the live revision or use the parameter if { ![template::util::is_nil opts(revision_id)] } { set revision_id $opts(revision_id) } else { set revision_id [::content::item::get_live_revision -item_id $item_id] } # Get the template set ::content::template_url [::content::item::get_template -item_id $item_id -use_context public] if {$::content::template_url eq {}} { ns_log Warning "publish::merge_with_template: no template for item $item_id" return "" } ns_log debug "publish::merge_with_template: template for item $item_id is $::content::template_url" # Get the full path to the template set root_path [content::get_template_root] set file_stub [ns_normalizepath "$root_path/$::content::template_url"] # Set the passed-in variables if { ![template::util::is_nil opts(html)] } { set adp_args $opts(html) } else { set adp_args "" } # Parse the template and return the result publish::push_id $item_id $revision_id ns_log debug "publish::merge_with_template: parsing $file_stub" set html [eval "template::adp_parse \"$file_stub\" \[list $adp_args\]"] publish::pop_id return $html } ad_proc -public publish::handle::text { item_id args } { Return the text body of the item } { template::util::get_opts $args if { [template::util::is_nil opts(revision_id)] } { set revision_id [::content::item::get_live_revision -item_id $item_id] } else { set revision_id $opts(revision_id) } if { [info exists opts(embed)] } { # Render the child item and embed it in the code if { ![info exists opts(no_merge)] } { set code "publish::merge_with_template $item_id $args" set html [eval $code] } else { db_transaction { db_exec_plsql get_revision_id { begin content_revision.to_temporary_clob(:revision_id); end; } # Query for values from a previous revision set html [db_string get_previous_content ""] } } } else { # Just create an include tag # Concatenate all the extra html arguments into a string if { [info exists opts(html)] } { set extra_args $opts(html) } else { set extra_args "" } set html [publish::item_include_tag $item_id $extra_args] } return $html } ad_proc -public publish::get_mime_handler { mime_type } { @public get_mime_handler Return the name of a proc that should be used to render items with the given mime-type. The mime type handlers should all follow the naming convention
proc publish::handle::mime_prefix::mime_suffix
If the specific mime handler could not be found, get_mime_handler looks for a generic procedure with the name
proc publish::handle::mime_prefix
If the generic mime handler does not exist either, get_mime_handler returns "" @param mime_type The full mime type, such as "text/html" or "image/jpg" @return The name of the proc which should be used to handle the mime-type, or an empty string on failure. @see publish::handle_item } { set mime_pair [split $mime_type "/"] set mime_prefix [lindex $mime_pair 0] set mime_suffix [lindex $mime_pair 1] # Look for the specific handler if { [proc_exists "::publish::handle::${mime_prefix}" $mime_suffix] } { return "::publish::handle::${mime_prefix}::$mime_suffix" } # Look for the generic handler if { [proc_exists "::publish::handle" $mime_prefix] } { return "::publish::handle::${mime_prefix}" } # Failure return "" } ad_proc -private publish::get_main_item_id {} { @private get_main_item_id Get the main item id from the top of the stack @return the main item id @see publish::pop_id @see publish::push_id @see publish::get_main_revision_id } { if { ![template::util::is_nil ::content::item_id] } { set ret $::content::item_id } else { error "Item id stack is empty" } return $ret } ad_proc -private publish::get_main_revision_id {} { @private get_main_revision_id Get the main item revision from the top of the stack @return the main item id @see publish::pop_id @see publish::push_id @see publish::get_main_item_id } { if { [template::util::is_nil ::content::revision_id] } { set item_id [get_main_item_id] set ret [::content::item::get_live_revision -item_id $item_id] } else { set ret $::content::revision_id } return $ret } ad_proc -private publish::handle_item { item_id args } { @private handle_item Render an item either by looking it up in the the temporary cache, or by using the appropriate mime handler. Once the item is rendered, it is stored in the temporary cache under a key which combines the item_id, any extra HTML parameters, and a flag which specifies whether the item was merged with its template.
This proc takes the same arguments as the individual mime handlers. @param item_id The id of the item to be rendered @option revision_id {default The live revision} The revision which is to be used when rendering the item @option no_merge Indicates that the item should NOT be merged with its template. This option is used to avoid infinite recursion. @option refresh Re-render the item even if it exists in the cache. Use with caution - circular dependencies may cause infinite recursion if this option is specified @option embed Signifies that the content should be statically embedded directly in the HTML. If this option is not specified, the item may be dynamically referenced, f.ex. using the <include> tag @option html Extra HTML parameters to be passed to the item handler, in format {name value name value ...} @return The rendered HTML for the item, or an empty string on failure @see publish::handle_binary_file @see publish::handle::text @see publish::handle::image } { template::util::get_opts $args variable revision_html # Process options if { [template::util::is_nil opts(revision_id)] } { set revision_id [::content::item::get_live_revision -item_id $item_id] } else { set revision_id $opts(revision_id) } if { [template::util::is_nil revision_id] } { ns_log warning "publish::handle_item: No live revision for $item_id" return "" } if { [template::util::is_nil opts(no_merge)] } { set merge_str "merge" } else { set merge_str "no_merge" } # Create a unique key set revision_key "$merge_str $revision_id" if { ![template::util::is_nil opts(html)] } { lappend revision_key $opts(html) } # Pull the item out of the cache if { ![info exists opts(refresh)] && \ [info exists revision_html($revision_key)] } { ns_log debug "publish::handle_item: Fetching $item_id from cache" return $revision_html($revision_key) } else { # Render the item and cache it ns_log debug "publish::handle_item: Rendering item $item_id" item::get_mime_info $revision_id mime_info set item_handler [get_mime_handler $mime_info(mime_type)] if { [template::util::is_nil item_handler] } { ns_log warning "publish::handle_item: No mime handler for mime type $mime_info(mime_type)" return "" } # Call the appropriate handler function set code [list $item_handler $item_id] set code [concat $code $args] # Pass the revision_id if { ![info exists opts(revision_id)] } { lappend code -revision_id $revision_id } set html [eval $code] ns_log debug "publish::handle_item: Caching html for revision $revision_id" set revision_html($revision_key) $html return $html } } ad_proc -public publish::get_html_body { html } { @public get_html_body Strip the <body> tags from the HTML, leaving just the body itself. Useful for including templates in each other. @param html The html to be processed @return Everything between the <body> and the </body> tags if they exist; the unchanged HTML if they do not } { if { [regexp -nocase {]*>(.*)} $html match body_text] } { return $body_text } else { return $html } } ad_proc -public publish::render_subitem { main_item_id relation_type relation_tag \ index is_embed extra_args {is_merge t} } { @private render_subitem Render a child/related item and return the resulting HTML, stripping off the headers. @param main_item_id The id of the parent item @param relation_type Either child or relation. Determines which tables are searched for subitems. @param relation_tag The relation tag to look for @param index The relative index of the subitem. The subitem with lowest order_n has index 1, the second lowest order_n has index 2, and so on. @param is_embed If "t", the child item may be embedded directly in the HTML. Otherwise, it may be dynamically included. The proc does not process this parameter directly, but passes it to handle_item @param extra_args Any additional HTML arguments to be used when rendering the item, in form {name value name value ...} @param is_merge {default t} If "t", merge_with_template may be used to render the subitem. Otherwise, merge_with_template should not be used, in order to prevent infinite recursion. @return The rendered HTML for the child item @see publish::merge_with_template @see publish::handle_item } { # Get the child item if {$relation_type eq "child"} { set subitems [db_list rs_get_subitems ""] } else { set subitems [db_list cs_get_subitems_related ""] } set sub_item_id [lindex $subitems [expr {$index - 1}]] if { [template::util::is_nil sub_item_id] } { ns_log notice "publish::render_subitem: No such subitem" return "" } # Call the appropriate handler function set code [list handle_item $sub_item_id -html $extra_args] if {$is_embed eq "t"} { lappend code -embed } return [get_html_body [eval $code]] } ####################################################### # # The content tags ad_proc -private publish::set_to_pairs { params {exclusion_list ""} } { @private set_to_pairs Convert an ns_set into a list of name-value pairs, in form {name value name value ...} @param params The ns_set id @param exclusion_list {} A list of keys to be ignored @return A list of name-value pairs representing the data in the ns_set } { set extra_args [list] for { set i 0 } { $i < [ns_set size $params] } { incr i } { set key [ns_set key $params $i] set value [ns_set value $params $i] if { [lsearch $exclusion_list $key] == -1 } { lappend extra_args $key $value } } return $extra_args } ad_proc -private publish::process_tag { relation_type params } { @private process_tag Process a child or relation tag. This is a helper proc for the tags, which acts as a wrapper for render_subitem. @param relation_type Either child or relation @param params The ns_set id for extra HTML parameters @see publish::render_subitem } { set tag [template::get_attribute content $params tag] set index [template::get_attribute content $params index 1] set embed [ns_set find $params embed] if { $embed != -1 } { set embed t } else { set embed f } set parent_item_id [ns_set iget $params parent_item_id] # Concatenate all other keys into the extra arguments list set extra_args [publish::set_to_pairs $params \ {tag index embed parent_item_id}] # Render the item, append it to the page # set item_id [publish::get_main_item_id] set command "publish::render_subitem" append command \ " \[template::util::nvl \"$parent_item_id\" \$::content::item_id\]" append command " $relation_type $tag $index $embed" append command " \{$extra_args\}" template::adp_append_code "append __adp_output \[$command\]" } ad_proc -private publish::foreach_publish_path { url code {root_path ""} } { @private foreach_publish_path Execute some TCL code for each root path in the PublishRoots parameter @param url Relative URL to append to the roots @param code Execute this code @param root_path {default The empty string} Use this root path instead of the paths specified in the INI file @see publish::get_publish_roots } { if { ![template::util::is_nil root_path] } { set paths $root_path } else { # set paths [get_publish_roots] set paths "./" } upvar filename filename upvar current_page_root current_page_root foreach root_path $paths { ns_log debug "publish::foreach_publish_path: root_path: $root_path" set current_page_root $root_path set filename [ns_normalizepath "/$root_path/$url"] uplevel $code } } ad_proc -private publish::write_multiple_blobs { url revision_id {root_path ""} } { @private write_multiple_blobs Write the content of some revision to multiple publishing roots. @param db A valid database handle @param url Relative URL of the file to write @param revision_id Write the blob for this revision @see publish::get_publish_roots @see publish::write_multiple_files } { foreach_publish_path $url { mkdirs $filename db_1row get_storage_type " select storage_type from cr_items where item_id = (select item_id from cr_revisions where revision_id = :revision_id)" db_blob_get_file wmb_get_blob_file " select content from cr_revisions where revision_id = $revision_id " -file $filename ns_chmod $filename 0764 ns_log debug "publish::write_multiple_blobs: Wrote revision $revision_id to $filename" } $root_path } ad_proc -private publish::write_multiple_files { url text {root_path ""}} { @private write_multiple_files Write a relative URL to the multiple publishing roots. @param url Relative URL of the file to write @param text A string of text to be written to the URL @see template::util::write_file @see publish::get_publish_roots @see publish::write_multiple_blobs } { ns_log debug "publish::write_multiple_files: root_path = $root_path" foreach_publish_path $url { mkdirs $filename template::util::write_file $filename $text ns_chmod $filename 0764 ns_log debug "publish::write_multiple_files: Wrote text to $filename" } $root_path } ad_proc -public publish::write_content { revision_id args } { @public write_content Write the content (blob) of a revision into a binary file in the filesystem. The file will be published at the relative URL under each publish root listed under the PublishRoots parameter in the server's INI file (the value returnded by publish::get_page_root is used as the default). The file extension will be based on the revision's mime-type.
For example, an revision whose mime-type is "image/jpeg" for an item at "Sitemap/foo/bar" may be written as /web/your_server_name/www/foo/bar.jpg @param revision_id The id of the revision to write @option item_id {default The item_id of the revision} Specifies the item to which this revision belongs (mereley for optimization purposes) @option text If specified, indicates that the content of the revision is readable text (clob), not a binary file @option root_path {default All paths in the PublishPaths parameter} Write the content to this path only. @return The relative URL of the file that was written, or an empty string on failure @see content::get_content_value @see publish::get_publish_roots } { template::util::get_opts $args if { [template::util::is_nil opts(root_path)] } { set root_path "" } else { set root_path $opts(root_path) } db_transaction { # Get the item id if none specified if { [template::util::is_nil opts(item_id)] } { set item_id [db_string get_one_revision ""] if { [template::util::is_nil item_id] } { ns_log warning "publish::write_content: No such revision $revision_id" return "" } } else { set item_id $opts(item_id) } set file_url [item::get_extended_url $item_id -revision_id $revision_id] # LARS HACK: Delete the file if it already exists # Not sure what we should really do here, since on the one hand, the below db commands # crap out if the file already exists, but on the other hand, we shouldn't accidentally # overwrite files if { [file exists $root_path$file_url] } { file delete $root_path$file_url } # Write blob/text to file ns_log debug " publish::write_content: writing item $item_id to $file_url" if { [info exists opts(text)] } { db_transaction { db_exec_plsql gcv_get_revision_id { begin content_revision.to_temporary_clob(:revision_id); end; } # Query for values from a previous revision set text [db_string gcv_get_previous_content ""] } write_multiple_files $file_url $text $root_path } else { # Determine if the blob is null. If it is, give up (or else the # ns_ora blob_get_file will crash). if { [item::content_is_null $revision_id] } { ns_log warning "publish::write_content: No content supplied for revision $revision_id" return "" } # Write the blob write_multiple_blobs $file_url $revision_id $root_path } } # Return either the full path or the relative URL return $file_url } openacs-5.7.0/packages/acs-content-repository/tcl/publish-procs.xql0000644000175000017500000000320507351303470025310 0ustar frankiefrankie select im.width, im.height, r.title as image_alt from images im, cr_revisions r where im.image_id = :revision_id and r.revision_id = :revision_id select child_id from cr_child_rels r, cr_items i where r.parent_id = :main_item_id and r.relation_tag = :relation_tag and i.item_id = r.child_id order by order_n select related_object_id from cr_item_rels r, cr_items i where r.item_id = :main_item_id and r.relation_tag = :relation_tag and i.item_id = r.related_object_id order by r.order_n select storage_type from cr_items where item_id = (select item_id from cr_revisions where revision_id = :revision_id) select item_id from cr_revisions where revision_id = :revision_id openacs-5.7.0/packages/acs-content-repository/tcl/extlink-procs-oracle.xql0000644000175000017500000000266710024403020026555 0ustar frankiefrankie oracle8.1.6 begin :1 := content_extlink.new ( name => :name, url => :url, label => :label, description => :description, parent_id => :parent_id, extlink_id => :extlink_id, creation_user => :creation_user, creation_ip => :creation_ip, package_id => :package_id ); end; update acs_objects set last_modified = sysdate, modifying_user = :modifying_user, modifying_ip = :modifying_ip, title = :label where object_id = :extlink_id begin content_extlink.del ( extlink_id => :extlink_id ); end; select content_extlink.is_extlink (:item_id) from dual openacs-5.7.0/packages/acs-content-repository/tcl/content-revision-procs.tcl0000644000175000017500000003002211226233607027123 0ustar frankiefrankie# ad_library { Procedures to manipulate content revisions @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-04 @arch-tag: ddc736fb-cb5f-41fe-a854-703df26e8e03 @cvs-id $Id: content-revision-procs.tcl,v 1.25 2009/07/12 01:08:23 donb Exp $ } namespace eval ::content::revision {} ad_proc -public ::content::revision::new { {-revision_id ""} {-item_id:required} {-title ""} {-description ""} {-content ""} {-mime_type ""} {-publish_date ""} {-nls_language ""} {-creation_date ""} {-content_type} {-creation_user} {-creation_ip} {-package_id} {-attributes} {-is_live "f"} {-tmp_filename ""} {-storage_type ""} } { Adds a new revision of a content item. If content_type is not passed in, we determine it from the content item. This is needed to find the attributes for the content type. @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-04 @param revision_id @param item_id @param content_type @param title @param description @param content @param mime_type @param publish_date @param nls_language @param creation_date @param creation_user @param creation_ip @param package_id Package_id content belongs to @param is_live True is revision should be set live @param tmp_filename file containing content to be added to revision. Caller is responsible to handle cleaning up the tmp file @param package_id @param package_id @param is_live @param attributes A list of lists of pairs of additional attributes and their values to pass to the constructor. Each pair is a list of two elements: key => value such as [list [list attribute value] [list attribute value]] @return @error } { if {![info exists creation_user]} { set creation_user [ad_conn user_id] } if {![info exists creation_ip]} { set creation_ip [ad_conn peeraddr] } if {![exists_and_not_null content_type]} { set content_type [::content::item::content_type -item_id $item_id] } if {![exists_and_not_null storage_type]} { set storage_type [db_string get_storage_type ""] } if {![info exists package_id]} { set package_id [ad_conn package_id] } set attribute_names "" set attribute_values "" if { [exists_and_not_null attributes] } { set type_attributes [package_object_attribute_list $content_type] set valid_attributes [list] # add in extended attributes for this type, ingore # content_revision as those are already captured as named # parameters to this procedure foreach type_attribute $type_attributes { if {"cr_revisions" ne [lindex $type_attribute 1] \ && "acs_objects" ne [lindex $type_attribute 1] } { lappend valid_attributes [lindex $type_attribute 2] } } foreach attribute_pair $attributes { foreach {attribute_name attribute_value} $attribute_pair {break} if {[lsearch $valid_attributes $attribute_name] > -1} { # first add the column name to the list append attribute_names ", ${attribute_name}" # create local variable to use for binding set $attribute_name $attribute_value append attribute_values ", :${attribute_name}" } } } set table_name [db_string get_table_name "select table_name from acs_object_types where object_type=:content_type"] set query_text "insert into ${table_name}i (revision_id, object_type, creation_user, creation_date, creation_ip, title, description, item_id, object_package_id, mime_type $attribute_names) values (:revision_id, :content_type, :creation_user, :creation_date, :creation_ip, :title, :description, :item_id, :package_id, :mime_type $attribute_values)" db_transaction { # An explict lock was necessary for PostgreSQL between 8.0 and # 8.2; left the following statement here for documentary purposes # # db_dml lock_objects "LOCK TABLE acs_objects IN SHARE ROW EXCLUSIVE MODE" if {$revision_id eq ""} { set revision_id [db_nextval "acs_object_id_seq"] } # the postgres "insert into view" is rewritten by the rule into a "select" [expr {[db_driverkey ""] eq "postgresql" ? "db_0or1row" : "db_dml"}] \ insert_revision $query_text ::content::revision::update_content \ -item_id $item_id \ -revision_id $revision_id \ -content $content \ -tmp_filename $tmp_filename \ -storage_type $storage_type \ -mime_type $mime_type } if {[string is true $is_live]} { content::item::set_live_revision -revision_id $revision_id } return $revision_id } ad_proc -public ::content::revision::update_content { -item_id -revision_id -content -storage_type -mime_type {-tmp_filename ""} } { Update content column seperately. Oracle does not allow insert into a BLOB. This assumes that if storage type is lob and no file is specified that the content is really text and store it in the text column in PostgreSQL @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-02-09 @param revision_id Content revision to update @param content Content to add to resivsion @param storage_type text, file, or lob @param mime_type mime type of the content @param tmp_filename For file storage type a filename can be specified. It will be added to the contnet repository. Caller is responsible to handle cleaning up the tmp file @return @error } { switch $storage_type { file { if {$tmp_filename eq ""} { set filename [cr_create_content_file_from_string $item_id $revision_id $content] } else { set filename [cr_create_content_file $item_id $revision_id $tmp_filename] } set tmp_size [file size [cr_fs_path]$filename] db_dml set_file_content "" } lob { if {$tmp_filename ne ""} { # handle file set filename [cr_create_content_file $item_id $revision_id $tmp_filename] db_dml set_lob_content "" -blob_files [list $tmp_filename] db_dml set_lob_size "" } else { # handle blob db_dml update_content "" -blobs [list $content] } } default { # HAM : 112505 # I added a default switch because in some cases # storage type is text and revision is not being updated db_dml update_content "" -blobs [list $content] } } } ad_proc -public content::revision::content_copy { -revision_id:required {-revision_id_dest ""} } { @param revision_id @param revision_id_dest } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ [list revision_id_dest $revision_id_dest ] \ ] content_revision content_copy] } ad_proc -public content::revision::copy { -revision_id:required {-copy_id ""} {-target_item_id ""} {-creation_user ""} {-creation_ip ""} } { @param revision_id @param copy_id @param target_item_id @param creation_user @param creation_ip @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ [list copy_id $copy_id ] \ [list target_item_id $target_item_id ] \ [list creation_user $creation_user ] \ [list creation_ip $creation_ip ] \ ] content_revision copy] } ad_proc -public content::revision::delete { -revision_id:required } { @param revision_id } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision del] } ad_proc -public content::revision::export_xml { -revision_id:required } { @param revision_id @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision export_xml] } ad_proc -public content::revision::get_number { -revision_id:required } { @param revision_id @return NUMBER } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision get_number] } ad_proc -public content::revision::import_xml { -item_id:required -revision_id:required -doc_id:required } { @param item_id @param revision_id @param doc_id @return NUMBER(38) } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list revision_id $revision_id ] \ [list doc_id $doc_id ] \ ] content_revision import_xml] } ad_proc -public content::revision::index_attributes { -revision_id:required } { @param revision_id } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision index_attributes] } ad_proc -public content::revision::is_latest { -revision_id:required } { @param revision_id @return t or f } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision is_latest] } ad_proc -public content::revision::is_live { -revision_id:required } { @param revision_id @return t or f } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision is_live] } ad_proc -public content::revision::item_id { -revision_id:required } { Gets the item_id of the item to which the revision belongs. @param revision_id The revision id @return The item_id of the item to which this revision belongs } { return [db_string item_id {} -default ""] } ad_proc -public content::revision::read_xml { -item_id:required -revision_id:required -clob_loc:required } { @param item_id @param revision_id @param clob_loc @return NUMBER } { return [package_exec_plsql -var_list [list \ [list item_id $item_id ] \ [list revision_id $revision_id ] \ [list clob_loc $clob_loc ] \ ] content_revision read_xml] } ad_proc -public content::revision::replace { -revision_id:required -search:required -replace:required } { @param revision_id @param search @param replace } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ [list search $search ] \ [list replace $replace ] \ ] content_revision replace] } ad_proc -public content::revision::revision_name { -revision_id:required } { @param revision_id @return VARCHAR2 } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision revision_name] } ad_proc -public content::revision::to_html { -revision_id:required } { @param revision_id } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision to_html] } ad_proc -public content::revision::to_temporary_clob { -revision_id:required } { @param revision_id } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ ] content_revision to_temporary_clob] } ad_proc -public content::revision::write_xml { -revision_id:required -clob_loc:required } { @param revision_id @param clob_loc @return NUMBER } { return [package_exec_plsql -var_list [list \ [list revision_id $revision_id ] \ [list clob_loc $clob_loc ] \ ] content_revision write_xml] } ad_proc -public content::revision::update_attribute_index { } { } { return [package_exec_plsql content_revision update_attribute_index] } ad_proc -public content::revision::get_cr_file_path { -revision_id } { Get the path to content in the filesystem @param revision_id @return path to filesystem stored revision content @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-27 } { # the file path is stored in filename column on oracle # and content in postgresql, but we alias to filename so it makes # sense db_1row get_storage_key_and_path "" return [cr_fs_path $storage_area_key]${filename} } openacs-5.7.0/packages/acs-content-repository/tcl/content-revision-procs.xql0000644000175000017500000000106710437316506027157 0ustar frankiefrankie select storage_type from cr_items where item_id=:item_id openacs-5.7.0/packages/acs-content-repository/tcl/content-folder-procs.tcl0000644000175000017500000001742410763577646026576 0ustar frankiefrankie# ad_library { Tcl API for content_folders @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 @cvs-id $Id: content-folder-procs.tcl,v 1.14 2008/03/05 20:16:38 donb Exp $ } namespace eval ::content::folder {} ad_proc -public ::content::folder::new { -name:required {-folder_id ""} {-parent_id ""} {-content_type "content_folder"} {-label ""} {-description ""} {-creation_user ""} {-creation_ip ""} -creation_date {-context_id ""} {-package_id ""} } { @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 @param folder_id @param name @param parent_id @param content_type @param label @param description @param creation_user @param creation_ip @param creation_date @param context_id @param package_id @return @error } { set var_list [list] foreach var [list folder_id name label description parent_id context_id package_id] { lappend var_list [list $var [set $var]] } if {[exists_and_not_null creation_date]} { lappend var_list [list creation_date $creation_date] } set folder_id [package_instantiate_object \ -creation_user $creation_user \ -creation_ip $creation_ip \ -var_list $var_list \ $content_type] return $folder_id } ad_proc -public ::content::folder::delete { -folder_id:required {-cascade_p "f"} } { Delete a content folder @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-28 @param folder_id item_id of the content_folder @param cascade_p if true delete all children, if false, return error if folder is non-empty @return @error } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id ] \ [list cascade_p $cascade_p] ] \ content_folder del] } ad_proc -public ::content::folder::register_content_type { -folder_id:required -content_type:required {-include_subtypes "f"} } { Register an allowed content type for folder_id @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-05-29 @param folder_id folder to register type to @param content_type content_revision or subtype of content_revision @param include_subtypes t or f @return @error } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id] \ [list content_type $content_type] \ [list include_subtypes $include_subtypes]] \ content_folder register_content_type] } ad_proc -public ::content::folder::unregister_content_type { -folder_id:required -content_type:required {-include_subtypes "f"} } { Unregister an allowed content type for folder_id @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-04 @param folder_id folder to unregister type from @param content_type content_revision or subtype of content_revision @param include_subtypes t or f @return @error } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id] \ [list content_type $content_type] \ [list include_subtypes $include_subtypes]] \ content_folder unregister_content_type] } ad_proc -public ::content::folder::update { -folder_id:required -attributes:required } { Update standard cr_folder attributes, including the attributes for the folder cr_item @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2004-06-04 @param folder_id folder to update @param attributes A list of pairs of additional attributes and their values to set. Each pair is a list of lists of two elements: key => value Valid attributes are: label, description, name, package_id @return @error } { set valid_attributes [list label description package_id] set update_text "" foreach {attribute_list} $attributes { set attribute [lindex $attribute_list 0] set value [lindex $attribute_list 1] if {[lsearch $valid_attributes $attribute] > -1} { # create local variable to use for binding set $attribute $value if {$update_text ne ""} { append update_text "," } append update_text " ${attribute} = :${attribute} " } } if {$update_text ne ""} { # we have valid attributes, update them set query_text "update cr_folders set ${update_text} where folder_id=:folder_id" db_dml item_update $query_text } # pass the rest of the attributes to content::item::update # we can just send the folder attributes because they don't overlap content::item::update \ -item_id $folder_id \ -attributes $attributes } ad_proc -public content::folder::get_index_page { -folder_id:required } { @param folder_id @return item_id of content item named "index" in folder_id } { return [package_exec_plsql \ -var_list [list [list \ folder_id $folder_id \ ]] \ content_folder get_index_page] } ad_proc -public content::folder::get_label { -folder_id:required } { @param folder_id @return label of cr_folder suitable for display } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id] \ ] \ content_folder get_label] } ad_proc -public content::folder::is_empty { -folder_id:required } { @param folder_id @return t or f } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id ] \ ] \ content_folder is_empty] } ad_proc -public content::folder::is_folder { -item_id:required } { @param item_id @return t or f } { return [package_exec_plsql -var_list [list \ [list item_id $item_id] \ ] content_folder is_folder] } ad_proc -public content::folder::is_registered { -folder_id:required -content_type:required {-include_subtypes ""} } { @param folder_id @param content_type @param include_subtypes @return t or f } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id] \ [list content_type $content_type] \ [list include_subtypes $include_subtypes] \ ] \ content_folder is_registered] } ad_proc -public content::folder::is_root { -folder_id:required } { @param folder_id @return t or f } { return [package_exec_plsql -var_list [list \ [list folder_id $folder_id] \ ] content_folder is_root] } ad_proc -public content::folder::is_sub_folder { -folder_id:required -target_folder_id:required } { @param folder_id @param target_folder_id @return t of f } { return [package_exec_plsql \ -var_list [list \ [list folder_id $folder_id] \ [list target_folder_id $target_folder_id] \ ] \ content_folder is_sub_folder] } ad_proc content::folder::get_folder_from_package { -package_id:required } { @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-01-06 Returns the folder_id of the package instance. Cached } { return [util_memoize [list content::folder::get_folder_from_package_not_cached -package_id $package_id]] } ad_proc content::folder::get_folder_from_package_not_cached { -package_id:required } { @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-01-06 Returns the folder_id of the package instance } { return [db_string get_folder_id "select folder_id from cr_folders where package_id=:package_id"] } openacs-5.7.0/packages/acs-content-repository/sql/0000755000175000017500000000000011724401447022007 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/common/0000755000175000017500000000000011724401447023277 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/common/upgrade/0000755000175000017500000000000011575225406024731 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/common/upgrade/upgrade-5.3.0b1-5.3.0b2.sql0000644000175000017500000000205110602667755030657 0ustar frankiefrankie-- Add a few common mime types insert into cr_mime_types (label,mime_type,file_extension) values ('XPInstall', 'application/x-xpinstall', 'xpi'); insert into cr_mime_types (label,mime_type,file_extension) values ('Video MP4', 'video/mp4', 'mp4'); insert into cr_mime_types (label,mime_type,file_extension) select 'Video MP4', 'video/mp4', 'mp4' from dual where not exists (select 1 from cr_mime_types where mime_type = 'video/mp4'); insert into cr_extension_mime_type_map (extension, mime_type) select 'mp4', 'video/mp4' from dual where not exists (select 1 from cr_extension_mime_type_map where mime_type = 'video/mp4'); insert into cr_mime_types (label,mime_type,file_extension) select 'XPInstall', 'application/x-xpinstall', 'xpi' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-xpinstall'); insert into cr_extension_mime_type_map (extension, mime_type) select 'xpi', 'application/x-xpinstall' from dual where not exists (select 1 from cr_extension_mime_type_map where mime_type = 'application/x-xpinstall');openacs-5.7.0/packages/acs-content-repository/sql/common/mime-type-data.sql0000644000175000017500000016116411253303077026643 0ustar frankiefrankie-- Common mime types (administered from admin pages) -- -- see http://www.isi.edu/in-notes/iana/assignments/media-types/ -- also http://www.utoronto.ca/webdocs/HTMLdocs/Book/Book-3ed/appb/mimetype.html -- -- data assembly Jeff Davis davis@xarg.net -- Here are Mime types + text description + cannonical extension -- -- mapping of extension to mime type done later. insert into cr_mime_types (label,mime_type,file_extension) values ( 'Unkown' , '*/*' , '' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'AutoCAD drawing files' , 'application/acad' , 'dwg' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Andrew data stream' , 'application/andrew-inset' , 'ez' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'ClarisCAD files' , 'application/clariscad' , 'ccad' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Comma separated value' , 'application/csv' , 'csv' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'MATRA Prelude drafting' , 'application/drafting' , 'drw' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'DXF (AutoCAD)' , 'application/dxf' , 'dxf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Filemaker Pro' , 'application/filemaker' , 'fm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Futuresplash' , 'application/futuresplash' , 'spl' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'NCSA HDF data format' , 'application/hdf' , 'hdf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - IGES graphics format' , 'application/iges' , 'iges' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Mac binhex 4.0' , 'application/mac-binhex40' , 'hqx' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Mac Compactpro' , 'application/mac-compactpro' , 'cpt' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Word' , 'application/msword' , 'doc' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Uninterpreted binary' , 'application/octet-stream' , 'bin' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'ODA ODIF' , 'application/oda' , 'oda' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'PDF' , 'application/pdf' , 'pdf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'PostScript' , 'application/postscript' , 'ps' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'RTF - Rich Text Format' , 'application/rtf' , 'rtf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Stereolithography' , 'application/sla' , 'stl'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'VCard' , 'application/vcard' , 'vcf'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'VDA-FS Surface data' , 'application/vda' , 'vda'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'SSOYE Koan Files' , 'application/vnd.koan' , 'skp'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'FrameMaker MIF format' , 'application/vnd.mif' , 'mif' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Access file' , 'application/vnd.ms-access' , 'mdb' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Excel' , 'application/vnd.ms-excel' , 'xls' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft PowerPoint' , 'application/vnd.ms-powerpoint' , 'ppt' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Project' , 'application/vnd.ms-project' , 'mpp' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'WML XML in binary format', 'application/vnd.wap.wmlc' , 'wmlc'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'WMLScript bytecode' , 'application/vnd.wap.wmlscriptc', 'wmlsc'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'CorelXARA' , 'application/vnd.xara' , 'xar'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'WordPerfect' , 'application/wordperfect' , 'wpd'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'WordPerfect 6.0' , 'application/wordperfect6.0' , 'w60'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive ARJ ' , 'application/x-arj-compressed' , 'arj'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-bin' , 'aab' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-map' , 'aam' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-seg' , 'aas' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Channel Definition' , 'application/x-cdf' , 'cdf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'VCD' , 'application/x-cdlink' , 'vcd' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Chess PGN file' , 'application/x-chess-pgn' , 'pgn'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive compres' , 'application/x-compress' , 'z'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive CPIO' , 'application/x-cpio' , 'cpio'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'C-shell script' , 'application/x-csh' , 'csh' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive Debian Package' , 'application/x-debian-package' , 'deb'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Director' , 'application/x-director' , 'dxr' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'TeX DVI file' , 'application/x-dvi' , 'dvi' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive GNU Tar' , 'application/x-gtar' , 'gtar'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive gzip compressed' , 'application/x-gzip' , 'gz' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'CGI Script' , 'application/x-httpd-cgi' , 'cgi'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Adobe Illustrator' , 'application/x-illustrator' , 'ai' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Installshield data' , 'application/x-installshield' , 'wis'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Java Network Launching Protocol', 'application/x-java-jnlp-file', 'jnlp'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Javascript' , 'application/x-javascript' , 'js' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'LaTeX source' , 'application/x-latex' , 'latex' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmd)', 'application/x-ms-wmd' , 'wmd'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmz)', 'application/x-ms-wmz' , 'wmz'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Unidata netCDF' , 'application/x-netcdf' , 'cdf'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Ogg Vorbis' , 'application/x-ogg' , 'ogg' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Adobe PageMaker' , 'application/x-pagemaker' , 'p65' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Photoshop' , 'application/x-photoshop' , 'psd' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Palm Pilot Data' , 'application/x-pilot' , 'prc' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Real' , 'application/x-pn-realmedia' , 'rp'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Quattro Pro' , 'application/x-quattro-pro' , 'wq1'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive RAR' , 'application/x-rar-compressed' , 'rar'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Session Description Protocol', 'application/sdp' , 'sdp' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Shockwave' , 'application/x-shockwave-flash' , 'swf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'SQL' , 'application/x-sql' , 'sql' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive Mac Stuffit compressed' , 'application/x-stuffit' , 'sit' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive SVR4 cpio' , 'application/x-sv4cpio' , 'sv4cpio'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive SVR4 crc' , 'application/x-sv4crc' , 'sv4crc'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive Tar' , 'application/x-tar' , 'tar' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - TeX source' , 'application/x-tex' , 'tex' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Texinfo (emacs)' , 'application/x-texinfo' , 'texinfo' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - troff' , 'application/x-troff' , 'tr' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - troff with MAN macros' , 'application/x-troff-man' , 'man' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - troff with ME macros' , 'application/x-troff-me' , 'me' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - troff with MS macros' , 'application/x-troff-ms' , 'ms' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive POSIX Tar' , 'application/x-ustar' , 'ustar'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'X509 CA Cert' , 'application/x-x509-ca-cert' , 'cacert'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Archive Zip' , 'application/zip' , 'zip' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Basic audio (m-law PCM)' , 'audio/basic' , 'au' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Midi' , 'audio/midi' , 'midi'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio MPEG' , 'audio/x-mpeg' , 'mp3'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio MPEG-2' , 'audio/x-mpeg2' , 'mp2a'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Java Media Framework', 'audio/rmf' , 'rmf'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Voice' , 'audio/voice' , 'voc' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio AIFF' , 'audio/x-aiff' , 'aif' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Mod' , 'audio/x-mod' , 'xm'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio mpeg url (m3u)' , 'audio/x-mpegurl' , 'm3u'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Windows Media Services (wma)', 'audio/x-ms-wma' , 'wma'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Windows Media Services (wmv)', 'audio/x-ms-wmv' , 'wmv'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Realaudio' , 'audio/x-pn-realaudio' , 'ra' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Realaudio Plugin' , 'audio/x-pn-realaudio-plugin' , 'rm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Audio Microsoft WAVE' , 'audio/x-wav' , 'wav' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Chemical Brookhaven PDB' , 'chemical/x-pdb' , 'pdb'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Chemical XMol XYZ' , 'chemical/x-xyz' , 'xyz'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'WHIP Web Drawing file' , 'drawing/x-dwf' , 'dwf'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - BMP' , 'image/bmp' , 'bmp' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Fractal Image Format', 'image/fif' , 'fif'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Gif' , 'image/gif' , 'gif' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Image Exchange Format' , 'image/ief' , 'ief' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Jpeg' , 'image/jpeg' , 'jpg' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - PNG' , 'image/png' , 'png' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - TIFF' , 'image/tiff' , 'tif' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - WAP wireless bitmap' , 'image/vnd.wap.wbmp' , 'wbmp'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - CMU Raster' , 'image/x-cmu-raster' , 'ras' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Flexible Image Transport', 'image/x-fits' , 'fit' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Macromedia Freehand' , 'image/x-freehand' , 'fh' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - SVG' , 'image/xml+svg' , 'svg' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - PhotoCD' , 'image/x-photo-cd' , 'pcd' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Mac pict' , 'image/x-pict' , 'pict' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - PNM' , 'image/x-portable-anymap' , 'pnm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - PBM' , 'image/x-portable-bitmap' , 'pbm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - PGM' , 'image/x-portable-graymap' , 'pgm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - Portable Pixmap' , 'image/x-portable-pixmap' , 'ppm'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - RGB' , 'image/x-rgb' , 'rgb'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - X bitmap' , 'image/x-xbitmap' , 'xbm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - X pixmap' , 'image/x-xpixmap' , 'xpm' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Image - X window dump (xwd)' , 'image/x-xwindowdump' , 'xwd' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'RFC822 Message' , 'message/rfc822' , 'mime'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Computational mesh' , 'model/mesh' , 'mesh'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - SGML Text' , 'text/sgml' , 'sgml'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - CSS' , 'text/css' , 'css' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - HTML' , 'text/html' , 'html' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Plain text' , 'text/plain' , 'txt' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Plain text (flowed)' , 'text/plain; format=flowed' , 'text' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Enriched Text' , 'text/enriched' , 'rtx' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Tab separated values' , 'text/tab-separated-values' , 'tsv' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - WMLScript' , 'text/vnd.wap.wmlscript' , 'wmls'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - WML' , 'text/vnd.wap.wml' , 'wml'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - XML Document' , 'text/xml' , 'xml' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - Structured enhanced text', 'text/x-setext' , 'etx'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Text - XSL' , 'text/xsl' , 'xsl' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video FLI' , 'video/fli' , 'fli'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video MPEG' , 'video/mpeg' , 'mpg' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video MPEG-2' , 'video/mpeg2' , 'mpv2' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Quicktime' , 'video/quicktime' , 'mov' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video VDOlive streaming' , 'video/vdo' , 'vdo'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Vivo' , 'video/vnd.vivo' , 'vivo'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Microsoft ASF' , 'video/x-ms-asf' , 'asf' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Windows Media Services (wm)', 'video/x-ms-wm' , 'wm'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Windows Media Services (wvx)', 'video/x-ms-wvx' , 'wvx'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Windows Media Services (wmx)', 'video/x-mx-wmx' , 'wmx'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video Microsoft AVI' , 'video/x-msvideo' , 'avi' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Video SGI movie player' , 'video/x-sgi-movie' , 'movie' ); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Conference Cooltalk' , 'x-conference/x-cooltalk' , 'ice'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'VRML' , 'x-world/x-vrml' , 'vrml'); insert into cr_mime_types (label,mime_type,file_extension) values ( 'Xuda' , 'xuda/gen-cert' , 'xuda'); insert into cr_mime_types (label,mime_type,file_extension) values ('Enhanced text' , 'text/enhanced' , 'etxt'); insert into cr_mime_types (label,mime_type,file_extension) values ('Fixed-width text' , 'text/fixed-width' , 'ftxt'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Spreadsheet' , 'application/vnd.sun.xml.calc', 'sxc'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Spreadsheet Template', 'application/vnd.sun.xml.calc.template', 'stc'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Draw', 'application/vnd.sun.xml.draw', 'sxd'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Draw Template', 'application/vnd.sun.xml.draw.template', 'std'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Impress', 'application/vnd.sun.xml.impress', 'sxi'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Impress Template', 'application/vnd.sun.xml.impress.template', 'sti'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Math', 'application/vnd.sun.xml.math', 'sxm'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer', 'application/vnd.sun.xml.writer', 'sxw'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer Global', 'application/vnd.sun.xml.writer.global', 'sxg'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer Template', 'application/vnd.sun.xml.writer.template', 'stw'); insert into cr_mime_types (label,mime_type,file_extension) values ('Audio - WAV','audio/wav', 'wav'); insert into cr_mime_types (label,mime_type,file_extension) values ('Audio - MPEG','audio/mpeg', 'mpeg'); insert into cr_mime_types (label,mime_type,file_extension) values ('Audio - MP3','audio/mp3', 'mp3'); insert into cr_mime_types (label,mime_type,file_extension) values ('Image - Progressive JPEG','image/pjpeg', 'pjpeg'); insert into cr_mime_types (label,mime_type,file_extension) values ('SPPS data file','application/x-spss-savefile', 'sav'); insert into cr_mime_types (label,mime_type,file_extension) values ('SPPS data file','application/x-spss-outputfile', 'spo'); insert into cr_mime_types (label,mime_type,file_extension) values ('Video MP4', 'video/mp4', 'mp4'); insert into cr_mime_types (label,mime_type,file_extension) values ('XPInstall', 'application/x-xpinstall', 'xpi'); -- Open Documents MIME types insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.text', 'odt', 'OpenDocument Text'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.text-template', 'ott', 'OpenDocument Text Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.text-web', 'oth', 'HTML Document Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.text-master', 'odm', 'OpenDocument Master Document'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.graphics', 'odg', 'OpenDocument Drawing'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.graphics-template', 'otg', 'OpenDocument Drawing Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.presentation', 'odp', 'OpenDocument Presentation'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.presentation-template', 'otp', 'OpenDocument Presentation Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.spreadsheet', 'ods', 'OpenDocument Spreadsheet'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.spreadsheet-template', 'ots', 'OpenDocument Spreadsheet Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.chart', 'odc', 'OpenDocument Chart'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.formula', 'odf', 'OpenDocument Formula'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.database', 'odb', 'OpenDocument Database'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.oasis.opendocument.image', 'odi', 'OpenDocument Image'); -- Open XML formats for MS-Office insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx', 'Microsoft Office Excel'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'xltx', 'Microsoft Office Excel Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx', 'Microsoft Office PowerPoint Presentation'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.presentationml.slideshow', 'ppsx', 'Microsoft Office PowerPoint Slideshow'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.presentationml.template', 'potx', 'Microsoft Office PowerPoint Template'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx', 'Microsoft Office Word'); insert into cr_mime_types (mime_type, file_extension, label) values ('application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dotx', 'Microsoft Office Word Template'); -- Extension to mime type maps. -- text/plain for prog langs (maybe we should do application/x-LANG but then you can't look -- at the code in the browser. insert into cr_extension_mime_type_map (extension, mime_type) values ( 'c', 'text/plain'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'c++', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cpp', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cxx', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cc', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'h', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'hh', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'h++', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'hxx', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tcl', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sql', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sh', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'csh', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ksh', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'py', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'java', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xql', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'php', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'm4', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pl', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pm', 'text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pod', 'text/plain' ); -- map a few to binary insert into cr_extension_mime_type_map (extension, mime_type) values ( 'o','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'so','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'a','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dll','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'exe','application/octet-stream' ); -- all the rest insert into cr_extension_mime_type_map (extension, mime_type) values ( 'aab','application/x-authorware-bin' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'aam','application/x-authorware-map' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'aas','application/x-authorware-seg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ai','application/x-illustrator'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'aif','audio/x-aiff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'aifc','audio/x-aiff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'aiff','audio/x-aiff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ani','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'arj','application/x-arj-compressed' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'asc','text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'asf','video/x-ms-asf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'asx','video/x-ms-asf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'au','audio/basic' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'avi','video/x-msvideo' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'bin','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'bmp','image/bmp' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'bqy','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cacert','application/x-x509-ca-cert' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ccad','application/clariscad' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cdf','application/x-netcdf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cgi','application/x-httpd-cgi' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'class','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cpio','application/x-cpio' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cpt','application/mac-compactpro' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'css','text/css' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'csv','application/csv'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'cur','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dcr','application/x-director' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'deb','application/x-debian-package' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dhtml','text/html' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dir','application/x-director' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dms','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'doc','application/msword' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dot','application/msword' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'drw','application/drafting' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dump','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dvi','application/x-dvi' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dwf','drawing/x-dwf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dwg','application/acad' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dxf','application/dxf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'dxr','application/x-director' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'eps','application/postscript' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'etx','text/x-setext' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ez','application/andrew-inset' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fh4','image/x-freehand' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fh5','image/x-freehand' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fh7','image/x-freehand' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fhc','image/x-freehand' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fh','image/x-freehand' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fif','image/fif' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fit','image/x-fits'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fli','video/fli' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'fm','application/filemaker'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'gif','image/gif' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'gtar','application/x-gtar' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'gz','application/x-gzip' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'gzip','application/x-gzip' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'hdf','application/hdf'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'hqx','application/mac-binhex40' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'html','text/html' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'htm','text/html' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ice','x-conference/x-cooltalk' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ico','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ief','image/ief' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'iges','application/iges' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'igs','application/iges' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'jnlp','application/x-java-jnlp-file' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'jpeg','image/jpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'jpe','image/jpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'jpg','image/jpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'js','application/x-javascript' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'kar','audio/midi' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'latex','application/x-latex' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'lha','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'lzh','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'm15','audio/x-mod' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'm3u','audio/x-mpegurl' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'm3url','audio/x-mpegurl' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'man','application/x-troff-man' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mdb','application/vnd.ms-access'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'me','application/x-troff-me' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mesh','model/mesh' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mid','audio/midi' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'midi','audio/midi' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mif','application/vnd.mif' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mime','message/rfc822' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'movie','video/x-sgi-movie' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mov','video/quicktime' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mp2','audio/x-mpeg2' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mp2a','audio/x-mpeg2' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mp3','audio/x-mpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mp3a','audio/x-mpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpeg','video/mpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpe','video/mpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpga','audio/x-mpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpg','video/mpeg' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpv2','video/mpeg2' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mp2v','video/mpeg2' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpp','application/vnd.ms-project'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpc','application/vnd.ms-project'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpt','application/vnd.ms-project'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpx','application/vnd.ms-project'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mpw','application/vnd.ms-project'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ms','application/x-troff-ms' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'msh','model/mesh' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'msw','application/msword' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'mtm','audio/x-mod' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'nc','application/x-netcdf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'oda','application/oda' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ogg','application/x-ogg'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'p65','application/x-pagemaker'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pbm','image/x-portable-bitmap' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pcd','image/x-photo-cd'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pdb','chemical/x-pdb' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pdf','application/pdf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pgm','image/x-portable-graymap' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pgn','application/x-chess-pgn' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pict','image/x-pict' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'png','image/png' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pnm','image/x-portable-anymap' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ppm','image/x-portable-pixmap' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ppt','application/vnd.ms-powerpoint' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ppz','application/vnd.ms-powerpoint' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pps','application/vnd.ms-powerpoint' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'pot','application/vnd.ms-powerpoint' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'prc','application/x-pilot'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ps','application/postscript' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'psd','application/x-photoshop'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'qt','video/quicktime' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ra','audio/x-pn-realaudio' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ram','audio/x-pn-realaudio' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rar','application/x-rar-compressed' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ras','image/x-cmu-raster' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rgb','image/x-rgb' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rmf', 'audio/rmf'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rm','audio/x-pn-realaudio-plugin' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rmm','audio/x-pn-realaudio-plugin' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'roff','application/x-troff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rp','application/x-pn-realmedia' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rpm','audio/x-pn-realaudio-plugin' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rr','application/x-troff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rtf','application/rtf' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'rtx','text/enriched' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 's3m','audio/x-mod' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sd2','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sdp','application/sdp' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sea','application/x-stuffit' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sgml','text/sgml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sgm','text/sgml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'shtml','text/html' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'silo','model/mesh' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sit','application/x-stuffit' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'skd','application/vnd.koan' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'skm','application/vnd.koan' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'skp','application/vnd.koan' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'skt','application/vnd.koan' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'snd','audio/basic' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'spl','application/futuresplash' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'stl','application/sla' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'stm','audio/x-mod' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sv4cpio','application/x-sv4cpio' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'sv4crc','application/x-sv4crc' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'svg','image/xml+svg'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'swf','application/x-shockwave-flash' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 't','application/x-troff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tar','application/x-tar' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tex','application/x-tex' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'texi','application/x-texinfo' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'texinfo','application/x-texinfo' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'text','text/plain; format=flowed'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tiff','image/tiff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tif','image/tiff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tr','application/x-troff' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'tsv','text/tab-separated-values' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'txt','text/plain' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ult','audio/x-mod' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'ustar','application/x-ustar' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'uu','application/octet-stream' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vcd','application/x-cdlink' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vcf','application/vcard' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vdo','video/vdo' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vda','application/vda' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vivo','video/vnd.vivo' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'viv','video/vnd.vivo' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'voc','audio/voice'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vrml','x-world/x-vrml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'vrm','x-world/x-vrml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wav','audio/x-wav' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wb1','application/x-quattro-pro' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wb2','application/x-quattro-pro' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wb3','application/x-quattro-pro' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wbmp','image/vnd.wap.wbmp' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'web','application/vnd.xara' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wis','application/x-installshield' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wma','audio/x-ms-wma' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmd','application/x-ms-wmd' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmlc','application/vnd.wap.wmlc' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmlsc','application/vnd.wap.wmlscriptc' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmls','text/vnd.wap.wmlscript' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wml','text/vnd.wap.wml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmv','audio/x-ms-wmv' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wm','video/x-ms-wm' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmx','video/x-mx-wmx' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wmz','application/x-ms-wmz' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wpd','application/wordperfect' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wq1','application/x-quattro-pro' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wrl','x-world/x-vrml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'wvx','video/x-ms-wvx' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xar','application/vnd.xara' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'w60','application/wordperfect6.0'); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xbm','image/x-xbitmap' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xlc','application/vnd.ms-excel' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xls','application/vnd.ms-excel' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xlm','application/vnd.ms-excel' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xlw','application/vnd.ms-excel' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xm','audio/x-mod' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xml','text/xml' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xpm','image/x-xpixmap' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xsl','text/xsl' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xuda','xuda/gen-cert' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xwd','image/x-xwindowdump' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'xyz','chemical/x-xyz' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'z','application/x-compress' ); insert into cr_extension_mime_type_map (extension, mime_type) values ( 'zip','application/zip' ); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxc', 'application/vnd.sun.xml.calc'); insert into cr_extension_mime_type_map (extension, mime_type) values ('stc', 'application/vnd.sun.xml.calc.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxd', 'application/vnd.sun.xml.draw'); insert into cr_extension_mime_type_map (extension, mime_type) values ('std', 'application/vnd.sun.xml.draw.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxi', 'application/vnd.sun.xml.impress'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sti', 'application/vnd.sun.xml.impress.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxm', 'application/vnd.sun.xml.math'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxw', 'application/vnd.sun.xml.writer'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxg', 'application/vnd.sun.xml.writer.global'); insert into cr_extension_mime_type_map (extension, mime_type) values ('stw', 'application/vnd.sun.xml.writer.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sav', 'application/x-spss-savefile'); insert into cr_extension_mime_type_map (extension, mime_type) values ('spo', 'application/x-spss-outputfile'); insert into cr_extension_mime_type_map (extension, mime_type) values ('mp4', 'video/mp4'); insert into cr_extension_mime_type_map (extension, mime_type) values ('xpi', 'application/x-xpinstall'); -- Open Documents MIME types insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.text', 'odt'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.text-template', 'ott'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.text-web', 'oth'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.text-master', 'odm'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.graphics', 'odg'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.graphics-template', 'otg'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.presentation', 'odp'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.presentation-template', 'otp'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.spreadsheet', 'ods'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.spreadsheet-template', 'ots'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.chart', 'odc'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.formula', 'odf'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.database', 'odb'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.oasis.opendocument.image', 'odi'); -- Open XML formats for MS-Office insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.spreadsheetml.template', 'xltx'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pptx'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.presentationml.slideshow', 'ppsx'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.presentationml.template', 'potx'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'docx'); insert into cr_extension_mime_type_map (mime_type, extension) values ('application/vnd.openxmlformats-officedocument.wordprocessingml.template', 'dotx'); -- Here are some less common mime types and extensions not defined here. -- -- tsp | application/dsptype -- pfr | application/font-tdpfr -- imd | application/immedia -- mbd | application/mbedlet -- pps | application/pps -- prt | application/pro_eng -- smi | application/smil -- smil | application/smil -- sol | application/solids -- step | application/step -- stp | application/step -- vmd | application/vocaltec-media-desc -- vmf | application/vocaltec-media-file -- bcpio | application/x-bcpio -- chat | application/x-chat -- ipx | application/x-ipix -- ips | application/x-ipscript -- src | application/x-wais-source -- wsrc | application/x-wais-source -- vox | audio/voxware -- rmf | audio/x-rmf -- svh | image/svh -- ivr | i-world/i-vrml -- hdml | text/x-hdml openacs-5.7.0/packages/acs-content-repository/sql/oracle/0000755000175000017500000000000011724401447023254 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/oracle/content-item.sql0000644000175000017500000013062411023613734026405 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-item.sql,v 1.31 2008/06/11 00:10:04 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html set serveroutput on size 1000000 format wrapped create or replace view content_item_globals as select -100 as c_root_folder_id from dual; create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL or item_id in (-4,-100,-200) then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = -4 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = -4 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= -4 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= -4 then begin -- Figure out the relation_tag to use if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type, v_rel_tag) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, title => content_item.new.name, package_id => content_item.new.package_id, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, security_inherit_p => content_item.new.security_inherit_p ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels -- We checked above before creating the object that it is a valid rel if v_parent_id ^= -4 and content_folder.is_folder(v_parent_id) = 'f' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', title => v_rel_tag || ': ' || v_parent_id || ' - ' || v_item_id, package_id => content_item.new.package_id, context_id => v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, package_id => content_item.new.package_id, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, package_id => content_item.new.package_id, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure del ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.del.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.del.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.del.item_id or related_object_id = content_item.del.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.del.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.del.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.del(v_symlink_val.symlink_id); end loop; delete from cr_release_periods where item_id = content_item.del.item_id; -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.del.item_id; for v_revision_val in c_revision_cur loop content_revision.del(v_revision_val.revision_id); end loop; -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.del.item_id; -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.del(v_rel_val.rel_id); end loop; for v_rel_val in c_child_cur loop acs_rel.del(v_rel_val.rel_id); end loop; for v_rel_val in c_parent_cur loop acs_rel.del(v_rel_val.rel_id); content_item.del(v_rel_val.child_id); end loop; -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.del.item_id; -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.del.item_id; -- 7) delete associated comments journal_entry.delete_for_object( content_item.del.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; acs_object.del(content_item.del.item_id); end del; procedure edit_name ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where cr_items.name = content_item.edit_name.name and parent_id = (select parent_id from cr_items where cr_items.item_id = content_item.edit_name.item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set cr_items.name = content_item.edit_name.name where cr_items.item_id = content_item.edit_name.item_id; update acs_objects set title = content_item.edit_name.name where object_id = content_item.edit_name.item_id; else close exists_cur; if exists_id <> item_id then raise_application_error(-20000, 'An item with the name ' || name || ' already exists in this directory.'); end if; end if; end edit_name; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := -4; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := -4; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id, name); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id, name = nvl (move.name, cr_items.name) where item_id = move.item_id; end if; if name is not null then update acs_objects set title = move.name where object_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip, name); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; select content_type, name , locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- can't copy to the same folder unless name is different if copy2.target_folder_id ^= v_current_folder_id or (v_name != copy2.name and copy2.name is not null) then if copy2.name is not null then v_name := copy2.name; end if; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; elsif v_content_type = 'content_extlink' then select label into v_title from cr_extlinks where extlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; v_package_id := acs_object.package_id(relate.item_id); -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, title => relation_tag || ': ' || relate.item_id || ' - ' || relate.object_id, package_id => v_package_id, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; update acs_objects set title = relate.relation_tag || ': ' || relate.item_id || ' - ' || relate.object_id where object_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.del( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; v_folder_id := get_parent_folder.item_id; while v_parent_folder_p = 'f' and v_folder_id is not null loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end get_parent_folder; end content_item; / show errors -- Trigger to maintain context_id in acs_objects create or replace trigger cr_items_update_tr after update of parent_id on cr_items for each row begin update acs_objects set context_id = :new.parent_id where object_id = :new.item_id; end cr_items_ins_update_tr; / show errors -- Trigger to maintain publication audit trail create or replace trigger cr_items_publish_update_tr before update of live_revision, publish_status on cr_items for each row begin insert into cr_item_publish_audit ( item_id, old_revision, new_revision, old_status, new_status, publish_date ) values ( :new.item_id, :old.live_revision, :new.live_revision, :old.publish_status, :new.publish_status, sysdate ); end cr_items_publish_update_tr; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-revision.sql0000644000175000017500000003627710744701417027323 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-revision.sql,v 1.16 2008/01/20 17:21:19 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_revision as function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; v_package_id acs_objects.package_id%TYPE; v_content_type acs_object_types.object_type%TYPE; begin v_content_type := content_item.get_content_type(item_id); if package_id is null then v_package_id := acs_object.package_id(item_id); else v_package_id := package_id; end if; v_revision_id := acs_object.new( object_id => revision_id, object_type => v_content_type, title => title, package_id => v_package_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, context_id => item_id ); insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, content, item_id, filename ) values ( v_revision_id, title, description, mime_type, publish_date, nls_language, data, item_id, filename ); return v_revision_id; end new; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; blob_loc cr_revisions.content%TYPE; begin blob_loc := empty_blob(); v_revision_id := content_revision.new( title => title, description => description, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => blob_loc, item_id => item_id, revision_id => revision_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, package_id => package_id, filename => filename ); select content into blob_loc from cr_revisions where revision_id = v_revision_id for update; string_to_blob(text, blob_loc); return v_revision_id; end new; procedure copy_attributes ( content_type in acs_object_types.object_type%TYPE, revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE ) is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = copy_attributes.content_type; cols varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; end loop; execute immediate 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) ( select ' || copy_id || cols || ' from ' || v_table_name || ' where ' || v_id_column || ' = ' || revision_id || ')'; end copy_attributes; function copy ( revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE is v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; -- get the content_type and supertypes cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = ( select object_type from acs_objects where object_id = copy.revision_id ) order by level desc; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy.revision_id; else v_target_item_id := target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy_id is null then select acs_object_id_seq.nextval into v_copy_id from dual; else v_copy_id := copy_id; end if; -- create the basic object insert into acs_objects ( object_id, object_type, context_id, security_inherit_p, creation_user, creation_date, creation_ip, last_modified, modifying_user, modifying_ip, title, package_id ) ( select v_copy_id, object_type, v_target_item_id, security_inherit_p, copy.creation_user, sysdate, copy.creation_ip, sysdate, copy.creation_user, copy.creation_ip, title, package_id from acs_objects where object_id = copy.revision_id ); -- create the basic revision (using v_target_item_id) insert into cr_revisions ( revision_id, title, description, publish_date, mime_type, nls_language, content, item_id, content_length ) ( select v_copy_id, title, description, publish_date, mime_type, nls_language, content, v_target_item_id, content_length from cr_revisions where revision_id = copy.revision_id ); -- iterate over the ancestor types and copy attributes for type_rec in type_cur loop copy_attributes(type_rec.object_type, copy.revision_id, v_copy_id); end loop; return v_copy_id; end copy; procedure del ( revision_id in cr_revisions.revision_id%TYPE ) is v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = content_revision.del.revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = content_revision.del.revision_id then declare cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> content_revision.del.revision_id order by o.creation_date desc; begin open c_revision_cur; fetch c_revision_cur into v_latest_revision; if c_revision_cur%NOTFOUND then v_latest_revision := null; end if; close c_revision_cur; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end; end if; -- Clear live revision if v_live_revision = content_revision.del.revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = content_revision.del.revision_id or new_revision = content_revision.del.revision_id; -- Delete the revision acs_object.del(revision_id); end del; function get_number ( revision_id in cr_revisions.revision_id%TYPE ) return number is cursor rev_cur is select revision_id from cr_revisions r, acs_objects o where item_id = (select item_id from cr_revisions where revision_id = get_number.revision_id) and o.object_id = r.revision_id order by o.creation_date; v_number integer; v_revision cr_revisions.revision_id%TYPE; begin open rev_cur; loop fetch rev_cur into v_revision; if v_revision = get_number.revision_id then v_number := rev_cur%ROWCOUNT; exit; end if; end loop; close rev_cur; return v_number; end get_number; function revision_name( revision_id IN cr_revisions.revision_id%TYPE ) return varchar2 is v_text varchar2(500); v_sql varchar2(500); begin v_sql := 'select ''Revision '' || content_revision.get_number(r.revision_id) || '' of '' || (select count(*) from cr_revisions where item_id = r.item_id) || '' for item: '' || content_item.get_title(item_id) from cr_revisions r where r.revision_id = ' || revision_name.revision_id; execute immediate v_sql into v_text; return v_text; end revision_name; procedure index_attributes( revision_id IN cr_revisions.revision_id%TYPE ) is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_revision_attributes ( revision_id, attributes ) values ( revision_id, empty_clob() ) returning attributes into clob_loc; v_revision_id := write_xml(revision_id, clob_loc); end index_attributes; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin select doc into clob_loc from cr_xml_docs where doc_id = import_xml.doc_id; v_revision_id := read_xml(item_id, revision_id, clob_loc); return v_revision_id; end import_xml; function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE is clob_loc clob; v_doc_id cr_xml_docs.doc_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_xml_docs (doc_id, doc) values (cr_xml_doc_seq.nextval, empty_clob()) returning doc_id, doc into v_doc_id, clob_loc; v_revision_id := write_xml(revision_id, clob_loc); return v_doc_id; end export_xml; procedure to_html ( revision_id IN cr_revisions.revision_id%TYPE ) is tmp_clob clob; blob_loc blob; begin ctx_doc.filter('cr_doc_filter_index', revision_id, tmp_clob, false); select content into blob_loc from cr_revisions where revision_id = to_html.revision_id for update; clob_to_blob(tmp_clob, blob_loc); dbms_lob.freetemporary(tmp_clob); end to_html; function is_live ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where live_revision = is_live.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_live; function is_latest ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where latest_revision = is_latest.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_latest; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ) is b blob; c clob; begin insert into cr_content_text ( revision_id, content ) values ( revision_id, empty_clob() ) returning content into c; select content into b from cr_revisions where revision_id = to_temporary_clob.revision_id; blob_to_clob(b, c); end to_temporary_clob; -- revision_id is the revision with the content that is to be copied procedure content_copy ( revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ) is v_item_id cr_items.item_id%TYPE; v_content_length integer; v_revision_id_dest cr_revisions.revision_id%TYPE; v_filename cr_revisions.filename%TYPE; v_content blob; begin select content_length, item_id into v_content_length, v_item_id from cr_revisions where revision_id = content_copy.revision_id; -- get the destination revision if content_copy.revision_id_dest is null then select latest_revision into v_revision_id_dest from cr_items where item_id = v_item_id; else v_revision_id_dest := content_copy.revision_id_dest; end if; -- only copy the content if the source content is not null if v_content_length is not null and v_content_length > 0 then /* The internal LOB types - BLOB, CLOB, and NCLOB - use copy semantics, as opposed to the reference semantics which apply to BFILEs. When a BLOB, CLOB, or NCLOB is copied from one row to another row in the same table or in a different table, the actual LOB value is copied, not just the LOB locator. */ select filename, content_length into v_filename, v_content_length from cr_revisions where revision_id = content_copy.revision_id; -- need to update the file name after the copy, -- if this content item is in CR file storage. The file name is based -- off of the item_id and revision_id and it will be invalid for the -- copied revision. update cr_revisions set content = (select content from cr_revisions where revision_id = content_copy.revision_id), filename = v_filename, content_length = v_content_length where revision_id = v_revision_id_dest; end if; end content_copy; end content_revision; / show errors -- Trigger to maintain latest_revision in cr_items create or replace trigger cr_revision_latest_tr after insert on cr_revisions for each row begin update cr_items set latest_revision = :new.revision_id where item_id = :new.item_id; end cr_revision_latest_tr; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-perms.sql0000644000175000017500000002754307341732250026605 0ustar frankiefrankie-------------------------------------------------------------- -- -- Set up the basic permissions used by the CMS, and invent some -- api in dealing with them -- -------------------------------------------------------------- declare v_perms varchar2(1) := 'f'; begin begin select 't' into v_perms from dual where exists (select 1 from acs_privileges where privilege = 'cm_root'); exception when no_data_found then v_perms := 'f'; end; if v_perms <> 't' then -- Dummy root privilege acs_privilege.create_privilege('cm_root', 'Root', 'Root'); -- He can do everything acs_privilege.create_privilege('cm_admin', 'Administrator', 'Administrators'); acs_privilege.create_privilege('cm_write', 'Write', 'Write'); acs_privilege.create_privilege('cm_new', 'Create New Item', 'Create New Item'); acs_privilege.create_privilege('cm_examine', 'Admin-level Read', 'Admin-level Read'); acs_privilege.create_privilege('cm_read', 'User-level Read', 'User-level Read'); acs_privilege.create_privilege('cm_item_workflow', 'Modify Workflow', 'Modify Workflow'); acs_privilege.create_privilege('cm_perm_admin', 'Modify Any Permissions', 'Modify Any Permissions'); acs_privilege.create_privilege('cm_perm', 'Donate Permissions', 'Donate Permissions'); acs_privilege.add_child('cm_root', 'cm_admin'); -- Do anything to an object acs_privilege.add_child('cm_admin', 'cm_write'); -- Do anything to an object acs_privilege.add_child('cm_write', 'cm_new'); -- Create subitems acs_privilege.add_child('cm_new', 'cm_examine'); -- View in admin mode acs_privilege.add_child('cm_examine', 'cm_read'); -- View in user mode acs_privilege.add_child('cm_write', 'cm_item_workflow'); -- Change item workflow acs_privilege.add_child('cm_admin', 'cm_perm_admin'); -- Modify any permissions acs_privilege.add_child('cm_perm_admin', 'cm_perm'); -- Modify any permissions on an item -- Proper inheritance acs_privilege.add_child('admin', 'cm_root'); end if; end; / show errors create or replace package body content_permission is procedure inherit_permissions ( parent_object_id in acs_objects.object_id%TYPE, child_object_id in acs_objects.object_id%TYPE, child_creator_id in parties.party_id%TYPE default null ) is v_dummy integer; begin -- Determine if the child is a direct descendant of the -- parent select 1 into v_dummy from acs_objects where object_id = child_object_id and context_id = parent_object_id; -- Copy everything one level down insert into acs_permissions ( object_id, grantee_id, privilege ) ( select inherit_permissions.child_object_id as object_id, grantee_id, privilege from acs_permissions where object_id = parent_object_id ); if child_creator_id is not null then -- Grant cm_write and cm_perm to the child creator if content_permission.permission_p ( child_object_id, child_creator_id, 'cm_perm' ) <> 't' then -- Turn off inheritance and grant permission update acs_objects set security_inherit_p = 'f' where object_id = child_object_id; acs_permission.grant_permission ( child_object_id, child_creator_id, 'cm_perm' ); end if; if content_permission.permission_p ( child_object_id, child_creator_id, 'cm_write' ) <> 't' then acs_permission.grant_permission ( child_object_id, child_creator_id, 'cm_write' ); end if; end if; exception when no_data_found then raise_application_error(-20000, 'Child object is not actually a child of the parent object in inherit_permissions'); end inherit_permissions; function has_grant_authority ( object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) return varchar2 is begin -- Can donate permission only if you already have it and you have cm_perm, -- OR you have cm_perm_admin if content_permission.permission_p (object_id, holder_id, 'cm_perm_admin')= 't' or ( content_permission.permission_p (object_id, holder_id, 'cm_perm') = 't' and content_permission.permission_p (object_id, holder_id, privilege) = 't' ) then return 't'; else return 'f'; end if; end has_grant_authority; function has_revoke_authority ( object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, revokee_id in parties.party_id%TYPE ) return varchar2 is cursor c_perm_cur is select 't' from (select object_id from acs_objects connect by prior context_id = object_id start with object_id = has_revoke_authority.object_id) t, (select privilege, child_privilege from acs_privilege_hierarchy connect by prior privilege = child_privilege start with child_privilege = 'cm_perm') h where content_permission.permission_p( t.object_id, has_revoke_authority.holder_id, h.child_privilege ) = 't' and content_permission.permission_p( t.object_id, has_revoke_authority.revokee_id, h.privilege ) = 'f'; v_ret varchar2(1); begin open c_perm_cur; fetch c_perm_cur into v_ret; if c_perm_cur%NOTFOUND then v_ret := 'f'; end if; close c_perm_cur; return v_ret; end has_revoke_authority; procedure grant_permission_h ( object_id in acs_objects.object_id%TYPE, grantee_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) is cursor c_priv_cur is select descendant from acs_privilege_descendant_map where privilege = grant_permission_h.privilege and descendant <> grant_permission_h.privilege; v_privilege acs_privilege_descendant_map.privilege%TYPE; begin -- If the permission is already granted, do nothing if content_permission.permission_p ( object_id, grantee_id, privilege ) = 't' then return; end if; -- Grant the parent, make sure there is no inheritance update acs_objects set security_inherit_p = 'f' where object_id = grant_permission_h.object_id; acs_permission.grant_permission(object_id, grantee_id, privilege); -- Revoke the children - they are no longer relevant open c_priv_cur; loop fetch c_priv_cur into v_privilege; exit when c_priv_cur%NOTFOUND; acs_permission.revoke_permission(object_id, grantee_id, v_privilege); end loop; close c_priv_cur; end grant_permission_h; procedure grant_permission ( object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, recepient_id in parties.party_id%TYPE, is_recursive in varchar2 default 'f', object_type in acs_objects.object_type%TYPE default 'content_item' ) is cursor c_object_cur is select o.object_id from (select object_id, object_type from acs_objects connect by context_id = prior object_id start with object_id = grant_permission.object_id) o where has_grant_authority ( o.object_id, holder_id, grant_permission.privilege ) = 't' and content_item.is_subclass (o.object_type, grant_permission.object_type) = 't'; v_object_id acs_objects.object_id%TYPE; begin open c_object_cur; loop -- Determine if the grant is possible fetch c_object_cur into v_object_id; exit when c_object_cur%NOTFOUND; -- Grant the parent and revoke the children, since we don't need them -- anymore content_permission.grant_permission_h ( v_object_id, recepient_id, privilege ); exit when is_recursive = 'f'; end loop; close c_object_cur; end grant_permission; procedure revoke_permission_h ( object_id in acs_objects.object_id%TYPE, revokee_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) is cursor c_perm_child_cur is select child_privilege from acs_privilege_hierarchy where privilege = revoke_permission_h.privilege; v_privilege acs_privileges.privilege%TYPE; begin -- Grant all child privileges of the parent privilege open c_perm_child_cur; loop fetch c_perm_child_cur into v_privilege; exit when c_perm_child_cur%NOTFOUND; acs_permission.grant_permission ( revoke_permission_h.object_id, revoke_permission_h.revokee_id, v_privilege ); end loop; close c_perm_child_cur; -- Revoke the parent privilege acs_permission.revoke_permission ( revoke_permission_h.object_id, revoke_permission_h.revokee_id, revoke_permission_h.privilege ); end revoke_permission_h; procedure revoke_permission ( object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, revokee_id in parties.party_id%TYPE, is_recursive in varchar2 default 'f', object_type in acs_objects.object_type%TYPE default 'content_item' ) is cursor c_object_cur is select o.object_id from (select object_id, object_type from acs_objects connect by context_id = prior object_id start with object_id = revoke_permission.object_id) o where has_revoke_authority (o.object_id, holder_id, privilege, revokee_id) = 't' and content_item.is_subclass(o.object_type, revoke_permission.object_type) = 't'; v_object_id acs_objects.object_id%TYPE; begin open c_object_cur; loop fetch c_object_cur into v_object_id; exit when c_object_cur%NOTFOUND; content_permission.revoke_permission_h ( v_object_id, revokee_id, privilege ); exit when is_recursive = 'f'; end loop; close c_object_cur; end revoke_permission; function permission_p ( object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) return varchar2 is /* cursor c_perm_cur is select 't' as truth from acs_privilege_descendant_map pdm, acs_permissions p, (select group_id as party_id from group_member_map where member_id = permission_p.holder_id union select permission_p.holder_id as party_id from dual ) gm where p.privilege = pdm.privilege and p.object_id = permission_p.object_id and p.grantee_id = gm.party_id and p.privilege = pdm.privilege and pdm.descendant = permission_p.privilege; v_perm varchar2(1);*/ begin /* open c_perm_cur; fetch c_perm_cur into v_perm; if c_perm_cur%NOTFOUND then v_perm := 'f'; end if; close c_perm_cur; return v_perm; */ return acs_permission.permission_p (object_id, holder_id, privilege); end permission_p; -- Determine if the CMS admin exists function cm_admin_exists return varchar2 is v_exists varchar2(1); begin select 't' into v_exists from dual where exists ( select 1 from acs_permissions where privilege in ('cm_admin', 'cm_root') ); return v_exists; exception when no_data_found then return 'f'; end cm_admin_exists; end content_permission; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-symlink.sql0000644000175000017500000001554210035526153027136 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-symlink.sql,v 1.9 2004/04/09 14:00:11 andrewg Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_symlink as function new ( name in cr_items.name%TYPE default null, label in cr_symlinks.label%TYPE default null, target_id in cr_items.item_id%TYPE, parent_id in cr_items.parent_id%TYPE, symlink_id in cr_symlinks.symlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_symlinks.symlink_id%TYPE is v_symlink_id cr_symlinks.symlink_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_name cr_items.name%TYPE; v_label cr_symlinks.label%TYPE; begin -- SOME CHECKS -- -- 1) check that the target is now a symlink if content_symlink.is_symlink( target_id ) = 't' then raise_application_error(-20000, 'Cannot create a symlink to a symlink ' || target_id); end if; -- 2) check that the parent is a folder if content_folder.is_folder(parent_id) = 'f' then raise_application_error(-20000, 'The parent is not a folder'); end if; -- 3) check that parent folder supports symlinks if content_folder.is_registered(parent_id,'content_symlink') = 'f' then raise_application_error(-20000, 'This folder does not allow symlinks to be created'); end if; -- 4) check that the content folder supports the target item's content type if content_folder.is_registered( parent_id,content_item.get_content_type(target_id)) = 'f' then raise_application_error(-20000, 'This folder does not allow symlinks to items of type ' || content_item.get_content_type(target_id) || ' to be created'); end if; -- PASSED ALL CHECKS -- -- Select default name if the name is null begin if name is null then select 'symlink_to_' || name into v_name from cr_items where item_id = target_id; else v_name := name; end if; exception when no_data_found then v_name := null; end; -- Select default label if the label is null if content_symlink.new.label is null then v_label := 'Symlink to ' || v_name; else v_label := content_symlink.new.label; end if; if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_symlink_id := content_item.new( item_id => content_symlink.new.symlink_id, name => v_name, package_id => v_package_id, content_type => 'content_symlink', creation_date => content_symlink.new.creation_date, creation_user => content_symlink.new.creation_user, creation_ip => content_symlink.new.creation_ip, parent_id => content_symlink.new.parent_id ); insert into cr_symlinks (symlink_id, target_id, label) values (v_symlink_id, content_symlink.new.target_id, v_label); update acs_objects set title = v_label where object_id = v_symlink_id; return v_symlink_id; end new; procedure del ( symlink_id in cr_symlinks.symlink_id%TYPE ) is begin delete from cr_symlinks where symlink_id = content_symlink.del.symlink_id; content_item.del(content_symlink.del.symlink_id); end del; function is_symlink ( item_id in cr_items.item_id%TYPE ) return char is v_symlink_p integer := 0; begin select count(*) into v_symlink_p from cr_symlinks where symlink_id = is_symlink.item_id; if v_symlink_p = 1 then return 't'; else return 'f'; end if; end is_symlink; procedure copy ( symlink_id in cr_symlinks.symlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_target_id cr_items.item_id%TYPE; v_label cr_symlinks.label%TYPE; v_symlink_id cr_symlinks.symlink_id%TYPE; begin if content_folder.is_folder(copy.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy.symlink_id; select i.name, content_symlink.resolve(i.item_id), s.label into v_name, v_target_id, v_label from cr_symlinks s, cr_items i where s.symlink_id = i.item_id and s.symlink_id = copy.symlink_id; -- can't copy to the same folder if copy.target_folder_id ^= v_current_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; if content_folder.is_registered(copy.target_folder_id, 'content_symlink') = 't' then if content_folder.is_registered(copy.target_folder_id, content_item.get_content_type(resolve(copy.symlink_id))) = 't' then v_symlink_id := content_symlink.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, target_id => v_target_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end if; end if; end if; end if; end copy; function resolve ( item_id in cr_items.item_id%TYPE ) return cr_items.item_id%TYPE is v_target_id cr_items.item_id%TYPE; begin select target_id into v_target_id from cr_symlinks where symlink_id = resolve.item_id; return v_target_id; exception when no_data_found then return resolve.item_id; end resolve; function resolve_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_item.get_content_type( target_id ) into v_content_type from cr_symlinks where symlink_id = resolve_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end resolve_content_type; end content_symlink; / show errors -- Convenience view to simply access to symlink targets create or replace view cr_resolved_items as select i.parent_id, i.item_id, i.name, decode(s.target_id, NULL, 'f', 't') is_symlink, nvl(s.target_id, i.item_id) resolved_id, s.label from cr_items i, cr_symlinks s where i.item_id = s.symlink_id (+); openacs-5.7.0/packages/acs-content-repository/sql/oracle/types-create.sql0000644000175000017500000002431211562016154026401 0ustar frankiefrankie-- Object type declarations to support content repository of the -- ArsDigita Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: types-create.sql,v 1.4.2.2 2011/05/09 16:55:08 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- Define content items. Also the supertype for folders, symlinks and extlinks. declare attr_id acs_attributes.attribute_id%TYPE; begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'content_item', pretty_name => 'Content Item', pretty_plural => 'Content Items', table_name => 'cr_items', id_column => 'item_id', name_method => 'content_item.get_title' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_item', attribute_name => 'name', datatype => 'keyword', pretty_name => 'Name', pretty_plural => 'Names' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_item', attribute_name => 'locale', datatype => 'keyword', pretty_name => 'Locale', pretty_plural => 'Locales' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_item', attribute_name => 'live_revision', datatype => 'integer', pretty_name => 'Live Revision', pretty_plural => 'Live Revisions' ); end; / show errors -- Define content folders. A folder is equivalent to a directory in -- the file system. It is used for grouping content items that have -- public URL's. declare attr_id acs_attributes.attribute_id%TYPE; begin acs_object_type.create_type ( supertype => 'content_item', object_type => 'content_folder', pretty_name => 'Content Folder', pretty_plural => 'Content Folders', table_name => 'cr_folders', id_column => 'folder_id', name_method => 'content_folder.get_label' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_folder', attribute_name => 'label', datatype => 'string', pretty_name => 'Label', pretty_plural => 'Labels' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_folder', attribute_name => 'description', datatype => 'string', pretty_name => 'Description', pretty_plural => 'Descriptions' ); end; / show errors -- Define content keywords declare attr_id acs_attributes.attribute_id%TYPE; begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'content_keyword', pretty_name => 'Content Keyword', pretty_plural => 'Content Keywords', table_name => 'cr_keywords', id_column => 'keyword_id', name_method => 'acs_object.default_name' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_keyword', attribute_name => 'heading', datatype => 'string', pretty_name => 'Heading', pretty_plural => 'Headings' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_keyword', attribute_name => 'description', datatype => 'string', pretty_name => 'Description', pretty_plural => 'Descriptions' ); end; / show errors -- Symlinks are represented by a subclass of content_item (content_link) -- Each symlink thus has a row in the acs_objects table. Each symlink -- also has a row in the cr_items table. The name column for the symlink -- is the name that appears in the path to the symlink. declare attr_id integer; begin acs_object_type.create_type ( supertype => 'content_item', object_type => 'content_symlink', pretty_name => 'Content Symlink', pretty_plural => 'Content Symlinks', table_name => 'cr_symlinks', id_column => 'symlink_id', name_method => 'acs_object.default_name' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_symlink', attribute_name => 'target_id', datatype => 'integer', pretty_name => 'Target ID', pretty_plural => 'Target IDs' ); end; / show errors -- Extlinks are links to external content (offsite URL's) declare attr_id integer; begin acs_object_type.create_type ( supertype => 'content_item', object_type => 'content_extlink', pretty_name => 'External Link', pretty_plural => 'External Links', table_name => 'cr_extlinks', id_column => 'extlink_id', name_method => 'acs_object.default_name' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_extlink', attribute_name => 'url', datatype => 'text', pretty_name => 'URL', pretty_plural => 'URLs' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_extlink', attribute_name => 'label', datatype => 'text', pretty_name => 'Label', pretty_plural => 'Labels' ); attr_id := acs_attribute.create_attribute ( object_type => 'content_extlink', attribute_name => 'description', datatype => 'text', pretty_name => 'Description', pretty_plural => 'Descriptions' ); end; / show errors -- Define content templates. begin acs_object_type.create_type ( supertype => 'content_item', object_type => 'content_template', pretty_name => 'Content Template', pretty_plural => 'Content Templates', table_name => 'cr_templates', id_column => 'template_id', name_method => 'acs_object.default_name' ); end; / show errors -- Define content revisions, children of content items declare attr_id acs_attributes.attribute_id%TYPE; begin content_type.create_type ( supertype => 'acs_object', content_type => 'content_revision', pretty_name => 'Basic Item', pretty_plural => 'Basic Items', table_name => 'cr_revisions', id_column => 'revision_id', name_method => 'content_revision.revision_name' ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'title', datatype => 'text', pretty_name => 'Title', pretty_plural => 'Titles', sort_order => 1 ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'description', datatype => 'text', pretty_name => 'Description', pretty_plural => 'Descriptions', sort_order => 2 ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'publish_date', datatype => 'date', pretty_name => 'Publish Date', pretty_plural => 'Publish Dates', sort_order => 3 ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'mime_type', datatype => 'text', pretty_name => 'Mime Type', pretty_plural => 'Mime Types', sort_order => 4 ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'nls_language', datatype => 'text', pretty_name => 'Language', pretty_plural => 'Language' ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'item_id', datatype => 'integer', pretty_name => 'Item id', pretty_plural => 'Item ids' ); attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'content', datatype => 'text', pretty_name => 'content', pretty_plural => 'content' ); end; / show errors -- Declare standard relationships with children and other items declare attr_id acs_attributes.attribute_id%TYPE; begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'cr_item_child_rel', pretty_name => 'Child Item', pretty_plural => 'Child Items', table_name => 'cr_child_rels', id_column => 'rel_id', name_method => 'acs_object.default_name' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'parent_id', datatype => 'integer', pretty_name => 'Parent ID', pretty_plural => 'Parent IDs' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'child_id', datatype => 'integer', pretty_name => 'Child ID', pretty_plural => 'Child IDs' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'relation_tag', datatype => 'text', pretty_name => 'Relationship Tag', pretty_plural => 'Relationship Tags' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'order_n', datatype => 'integer', pretty_name => 'Sort Order', pretty_plural => 'Sort Orders' ); acs_object_type.create_type ( supertype => 'acs_object', object_type => 'cr_item_rel', pretty_name => 'Item Relationship', pretty_plural => 'Item Relationships', table_name => 'cr_item_rels', id_column => 'rel_id', name_method => 'acs_object.default_name' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_rel', attribute_name => 'item_id', datatype => 'integer', pretty_name => 'Item ID', pretty_plural => 'Item IDs' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_rel', attribute_name => 'related_object_id', datatype => 'integer', pretty_name => 'Related Object ID', pretty_plural => 'Related Object IDs' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_rel', attribute_name => 'relation_tag', datatype => 'text', pretty_name => 'Relationship Tag', pretty_plural => 'Relationship Tags' ); attr_id := acs_attribute.create_attribute ( object_type => 'cr_item_rel', attribute_name => 'order_n', datatype => 'integer', pretty_name => 'Sort Order', pretty_plural => 'Sort Orders' ); end; / show errors -- Refresh the attribute views prompt *** Refreshing content type attribute views... begin for type_rec in (select object_type from acs_object_types connect by supertype = prior object_type start with object_type = 'content_revision') loop content_type.refresh_view(type_rec.object_type); end loop; end; / openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-update.sql0000644000175000017500000001445111022567577026744 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System. This file contains DDL patches to the basic data model -- that were incorporated after the code freeze. It makes it easier for -- existing users to update their data models. -- Copyright (C) 1999-2000 ArsDigita Corporation -- Authors: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-update.sql,v 1.2 2008/06/07 20:28:47 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html set serveroutput on begin -- altering the constraint on cr_type_template_map dbms_output.put_line('Altering constraint on cr_type_template_map...'); execute immediate 'alter table cr_type_template_map drop constraint cr_type_template_map_pk'; execute immediate 'alter table cr_type_template_map add constraint cr_type_template_map_pk primary key (content_type, template_id, use_context)'; execute immediate 'analyze table cr_type_template_map compute statistics for all indexes'; end; / show errors begin -- Set the workflow permission as child of admin update acs_privilege_hierarchy set privilege = 'cm_admin' where privilege = 'cm_write' and child_privilege = 'cm_item_workflow'; if not table_exists('cr_content_text') then dbms_output.put_line('Creating CR_CONTENT_TEXT table'); execute immediate 'create global temporary table cr_content_text ( revision_id integer primary key, content CLOB ) on commit delete rows'; end if; if not column_exists('cr_folders', 'has_child_folders') then dbms_output.put_line('Adding HAS_CHILD_FOLDERS column to CR_FOLDERS' || ' and updating the column based on selection criteria.'); execute immediate 'create or replace view cr_resolved_items as select i.parent_id, i.item_id, i.name, decode(s.target_id, NULL, ''f'', ''t'') is_symlink, nvl(s.target_id, i.item_id) resolved_id, s.label from cr_items i, cr_symlinks s where i.item_id = s.symlink_id (+)'; execute immediate 'alter table cr_folders add has_child_folders char(1) default ''f'' constraint cr_folder_child_chk check (has_child_folders in (''t'',''f''))'; execute immediate 'update cr_folders f set has_child_folders = nvl((select ''t'' from dual where exists (select 1 from cr_folders f_child, cr_resolved_items r_child where r_child.parent_id = f.folder_id and f_child.folder_id = r_child.resolved_id)), ''f'')'; end if; if not column_exists('cr_keywords', 'parent_id') then dbms_output.put_line('Adding PARENT_ID column to CR_KEYWORDS' || ' and updating the parent id from the context id'); execute immediate 'alter table cr_keywords add parent_id integer constraint cr_keywords_hier references cr_keywords'; execute immediate 'update cr_keywords set parent_id = ( select context_id from acs_objects where object_id = keyword_id)'; end if; if not table_exists('cr_text') then dbms_output.put_line('Creating CR_TEXT table ' || 'for incoming text submissions...'); execute immediate 'create table cr_text ( text varchar2(4000) )'; -- For some reason a simple insert statement throws an error but this works execute immediate 'insert into cr_text values (NULL)'; end if; if not column_exists('cr_items', 'publish_status') then dbms_output.put_line('Adding PUBLISH_STATUS column to CR_ITEMS ' || 'for tracking deployment status...'); execute immediate 'alter table cr_items add publish_status varchar2(40) constraint cr_items_pub_status_chk check (publish_status in (''production'', ''ready'', ''live'', ''expired''))'; execute immediate 'update cr_items set publish_status = ''live'' where live_revision is not null'; execute immediate 'alter table cr_item_publish_audit add old_status varchar2(40)'; execute immediate 'alter table cr_item_publish_audit add new_status varchar2(40)'; end if; if not column_exists('cr_items', 'latest_revision') then dbms_output.put_line('Adding LATEST_REVISION column to CR_ITEMS ' || 'for tracking revision status...'); execute immediate 'alter table cr_items add latest_revision integer constraint cr_items_latest_fk references cr_revisions'; execute immediate 'update cr_items set latest_revision = content_item.get_latest_revision(item_id)'; end if; if not table_exists('cr_release_periods') then dbms_output.put_line('Creating CR_RELEASE_PERIODS table ' || 'for scheduled publishing...'); execute immediate ' create table cr_release_periods ( item_id integer constraint cr_release_periods_fk references cr_items constraint cr_release_periods_pk primary key, start_when date default sysdate, end_when date default sysdate + (365 * 20) )'; end if; if not table_exists('cr_scheduled_release_log') then dbms_output.put_line('Creating CR_SCHEDULED_RELEASE_LOG table ' || 'for auditing of scheduled publishing...'); execute immediate ' create table cr_scheduled_release_log ( exec_date date default sysdate not null, items_released integer not null, items_expired integer not null, err_num integer, err_msg varchar2(500) )'; end if; if not table_exists('cr_scheduled_release_job') then dbms_output.put_line('Creating CR_SCHEDULED_RELEASE_JOB table ' || 'for tracking database job for scheduled publishing...'); execute immediate ' create table cr_scheduled_release_job ( job_id integer, last_exec date )'; execute immediate ' insert into cr_scheduled_release_job values (NULL, sysdate)'; end if; end; / show errors create or replace trigger cr_text_tr before insert on cr_text for each row begin raise_application_error(-20000, 'Inserts are not allowed into cr_text.' ); end; / show errors @@ content-schedule.sql openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-image.sql0000644000175000017500000002675711022567577026560 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Hiro Iwashima (iwashima@mit.edu) -- $Id: content-image.sql,v 1.15 2008/06/07 20:28:47 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- This is to handle images create table images ( image_id integer constraint images_image_id_fk references cr_revisions constraint images_image_id_pk primary key, width integer, height integer ); declare attr_id integer; begin content_type.create_type ( content_type => 'image', supertype => 'content_revision', pretty_name => 'Image', pretty_plural => 'Images', table_name => 'images', id_column => 'image_id' ); attr_id := content_type.create_attribute ( content_type => 'image', attribute_name => 'width', datatype => 'integer', pretty_name => 'Width', pretty_plural => 'Widths' ); attr_id := content_type.create_attribute ( content_type => 'image', attribute_name => 'height', datatype => 'integer', pretty_name => 'Height', pretty_plural => 'Heights' ); end; / show errors -- register MIME types to this content type begin content_type.register_mime_type( content_type => 'image', mime_type => 'image/jpeg' ); content_type.register_mime_type( content_type => 'image', mime_type => 'image/gif' ); end; / show errors -- content-image.sql patch -- -- adds standard image pl/sql package -- -- Walter McGinnis (wtem@olywa.net), 2001-09-23 -- based on original photo-album package code by Tom Baginski -- create or replace package image as --/** -- Creates a new image -- Binary file stored in file-system --*/ function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE; --/** -- Deletes a single revision of image -- Schedules binary file for deletion. -- File delete sweep checks to see if no other images are using binary prior to deleting --*/ procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ); --/** -- Deletes a image and all revisions -- Schedules binary files for deletion. -- -- Be careful, cannot be undone (easily) --*/ procedure del ( item_id in cr_items.item_id%TYPE ); end image; / show errors; create or replace package body image as function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE is v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_item_id := content_item.new ( name => name, item_id => item_id, parent_id => parent_id, package_id => v_package_id, relation_tag => relation_tag, content_type => content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, locale => locale, context_id => context_id, storage_type => storage_type ); v_revision_id := content_revision.new ( title => title, description => description, item_id => v_item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => sysdate, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_item_id; end new; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new_revision.item_id); else v_package_id := package_id; end if; v_revision_id := content_revision.new ( title => title, description => description, item_id => item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_revision_id; end new_revision; procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ) is v_content cr_files_to_delete.path%TYPE default null; begin content_revision.del ( revision_id => revision_id ); end delete_revision; procedure del ( item_id in cr_items.item_id%TYPE ) is cursor image_revision_cur is select revision_id from cr_revisions where item_id = image.del.item_id order by revision_id asc; -- order by used in cursur so latest revision will be deleted last -- save resetting latest revision multiple times during delete process begin for v_revision_val in image_revision_cur loop image.delete_revision ( revision_id => v_revision_val.revision_id ); end loop; content_item.del ( item_id => item_id ); end del; end image; / show errors; openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-util.sql0000644000175000017500000000475311010464266026427 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-util.sql,v 1.3 2008/05/08 02:43:02 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace function table_exists ( table_name varchar2 ) return boolean is v_count integer; v_exists boolean; begin select decode(count(*),0,0,1) into v_count from user_tables where table_name = upper(table_exists.table_name); if v_count = 1 then v_exists := true; else v_exists := false; end if; return v_exists; end table_exists; / show errors create or replace function column_exists ( table_name varchar2, column_name varchar2 ) return boolean is v_count integer; v_exists boolean; begin select decode(count(*),0,0,1) into v_count from user_tab_columns where table_name = upper(column_exists.table_name) and column_name = upper(column_exists.column_name); if v_count = 1 then v_exists := true; else v_exists := false; end if; return v_exists; end column_exists; / show errors create or replace procedure clob_to_blob( clob_loc clob, blob_loc blob) as language java name 'com.arsdigita.content.Util.clobToBlob( oracle.sql.CLOB, oracle.sql.BLOB )'; / show errors create or replace procedure blob_to_clob( blob_loc blob, clob_loc clob) as language java name 'com.arsdigita.content.Util.blobToClob( oracle.sql.BLOB, oracle.sql.CLOB )'; / show errors create or replace procedure string_to_blob( s varchar2, blob_loc blob) as language java name 'com.arsdigita.content.Util.stringToBlob( java.lang.String, oracle.sql.BLOB )'; / show errors create or replace procedure string_to_blob_size( s varchar2, blob_loc blob, blob_size number) as language java name 'com.arsdigita.content.Util.stringToBlob( java.lang.String, oracle.sql.BLOB, int )'; / show errors create or replace function blob_to_string( blob_loc blob) return varchar2 as language java name 'com.arsdigita.content.Util.blobToString( oracle.sql.BLOB ) return java.lang.String'; / show errors create or replace procedure blob_to_file( s varchar2, blob_loc blob) as language java name 'com.arsdigita.content.Util.blobToFile( java.lang.String, oracle.sql.BLOB )'; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-package.sql0000644000175000017500000000227510744701417027047 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-package.sql,v 1.3 2008/01/20 17:21:19 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package content is procedure string_to_blob( s varchar2, blob_loc blob) as language java name 'com.arsdigita.content.Util.stringToBlob( java.lang.String, oracle.sql.BLOB )'; procedure string_to_blob_size( s varchar2, blob_loc blob, blob_size number) as language java name 'com.arsdigita.content.Util.stringToBlob( java.lang.String, oracle.sql.BLOB, int )'; function blob_to_string( blob_loc blob) return varchar2 as language java name 'com.arsdigita.content.Util.blobToString( oracle.sql.BLOB ) return java.lang.String'; procedure blob_to_file( s varchar2, blob_loc blob) as language java name 'com.arsdigita.content.Util.blobToFile( java.lang.String, oracle.sql.BLOB )'; end content; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-create.sql0000644000175000017500000006642111550452213026713 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-create.sql,v 1.29 2011/04/11 01:08:27 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -------------------------------------------------------------- -- MIME TYPES -------------------------------------------------------------- create table cr_mime_types ( label varchar2(200), mime_type varchar2(200) constraint cr_mime_types_pk primary key, file_extension varchar2(200) ); comment on table cr_mime_types is ' Standard MIME types recognized by the content management system. '; comment on table cr_mime_types is ' file_extension is not used to recognize MIME types, but to associate a file extension to the file after its MIME type is specified. '; -- Currently file_extension is the pk although it seems likely someone -- will want to support multiple mime types with the same extension. -- Would need UI work however create table cr_extension_mime_type_map ( extension varchar(200) constraint cr_mime_type_extension_map_pk primary key, mime_type varchar(200) constraint cr_mime_ext_map_mime_type_ref references cr_mime_types ); create index cr_extension_mime_type_map_idx on cr_extension_mime_type_map(mime_type); comment on table cr_extension_mime_type_map is ' a mapping table for extension to mime_type in db version of ns_guesstype data '; prompt *** Loading mime type data ... @ '../common/mime-type-data.sql' create table cr_content_mime_type_map ( content_type varchar2(100) constraint cr_content_mime_map_ctyp_fk references acs_object_types, mime_type varchar2(200) constraint cr_content_mime_map_typ_fk references cr_mime_types, constraint cr_content_mime_map_pk primary key (content_type, mime_type) ); comment on table cr_content_mime_type_map is ' A mapping table that restricts the MIME types associated with a content type. '; --RI Indexes create index cr_cont_mimetypmap_mimetyp_idx ON cr_content_mime_type_map(mime_type); -------------------------------------------------------------- -- LOCALES -------------------------------------------------------------- create table cr_locales ( locale varchar2(4) constraint cr_locale_abbrev_pk primary key, label varchar2(200) constraint cr_locale_name_nn not null constraint cr_locale_name_un unique, nls_language varchar2(30) constraint cr_locale_nls_lang_nn not null, nls_territory varchar2(30), nls_charset varchar2(30) ); comment on table cr_locales is ' Locale definitions in Oracle consist of a language, and optionally territory and character set. (Languages are associated with default territories and character sets when not defined). The formats for numbers, currency, dates, etc. are determined by the territory. '; insert into cr_locales ( locale, label, nls_language, nls_territory, nls_charset ) values ( 'us', 'American', 'AMERICAN', 'AMERICA', 'WE8ISO8859P1' ); -------------------------------------------------------------- -- CONTENT TYPES -------------------------------------------------------------- create table cr_type_children ( parent_type varchar2(100) constraint cr_type_children_parent_fk references acs_object_types, child_type varchar2(100) constraint cr_type_children_child_fk references acs_object_types, relation_tag varchar2(100), min_n integer, max_n integer, constraint cr_type_children_pk primary key (parent_type, child_type, relation_tag) ); --RI Indexes create index cr_type_children_chld_type_idx ON cr_type_children(child_type); comment on table cr_type_children is ' Constrains the allowable content types which a content type may contain. '; create table cr_type_relations ( content_type varchar2(100) constraint cr_type_relations_parent_fk references acs_object_types, target_type varchar2(100) constraint cr_type_relations_child_fk references acs_object_types, relation_tag varchar2(100), min_n integer, max_n integer, constraint cr_type_relations_pk primary key (content_type, target_type, relation_tag) ); -- RI Indexes create index cr_type_relations_tgt_typ_idx ON cr_type_relations(target_type); comment on table cr_type_relations is ' Constrains the allowable object types to which a content type may relate (see above). '; -------------------------------------------------------------- -- CONTENT ITEMS -------------------------------------------------------------- -- Define the cr_items table create table cr_items ( item_id integer constraint cr_items_item_id_fk references acs_objects on delete cascade constraint cr_items_pk primary key, parent_id integer constraint cr_items_parent_id_nil not null constraint cr_items_parent_id_fk references acs_objects on delete cascade, name varchar2(400) constraint cr_items_name_nn not null, locale varchar2(4) constraint cr_items_locale_fk references cr_locales, live_revision integer, latest_revision integer, publish_status varchar2(40) constraint cr_items_pub_status_ck check (publish_status in ('production', 'ready', 'live', 'expired') ), content_type varchar2(100) constraint cr_items_rev_type_fk references acs_object_types, storage_type varchar2(10) default 'lob' not null constraint cr_items_storage_type_ck check (storage_type in ('lob','file')), storage_area_key varchar2(100) default 'CR_FILES' not null ); create index cr_items_by_locale on cr_items(locale); create index cr_items_by_content_type on cr_items(content_type); create unique index cr_items_by_live_revision on cr_items(live_revision); create unique index cr_items_by_latest_revision on cr_items(latest_revision); create unique index cr_items_unique_name on cr_items(parent_id, name); create unique index cr_items_unique_id on cr_items(parent_id, item_id); create index cr_items_by_parent_id on cr_items(parent_id); create index cr_items_name on cr_items(name); comment on table cr_items is ' Each content item has a row in this table, as well as a row in the acs_objects table. The parent_id is used to place an item in a directory or place it within another container item. '; comment on column cr_items.content_type is ' The content type constrains the type of revision that may be added to this item (an item should have revisions of only one type). If null, then no revisions should be allowed. '; -- content-create.sql patch -- -- adds standard mechanism for deleting revisions from the file-system -- -- Walter McGinnis (wtem@olywa.net), 2001-09-23 -- based on original photo-album package code by Tom Baginski -- create table cr_files_to_delete ( path varchar2(250), storage_area_key varchar2(100) ); comment on table cr_files_to_delete is ' Table to store files to be deleted by a scheduled sweep. Since binaries are stored in filesystem and attributes in database, need a way to delete both atomically. So any process to delete file-system cr_revisions, copies the file path to this table as part of the delete transaction. Sweep run later to remove the files from filesystem once database info is successfully deleted. '; create table cr_child_rels ( rel_id integer constraint cr_child_rels_rel_pk primary key constraint cr_child_rels_rel_fk references acs_objects, parent_id integer constraint cr_child_rels_parent_nn not null, child_id integer constraint cr_child_rels_child_nn not null, relation_tag varchar2(100), order_n integer ); create index cr_child_rels_by_parent on cr_child_rels(parent_id); create unique index cr_child_rels_unq_id on cr_child_rels(parent_id, child_id); CREATE UNIQUE INDEX CR_CHILD_RELS_kids_IDx ON CR_CHILD_RELS(CHILD_ID); comment on table cr_child_rels is ' Provides for richer parent-child relationships than the simple link encapsulated in the primary table. May be subclassed to provide additional attributes. '; create table cr_item_rels ( rel_id integer constraint cr_item_rels_pk primary key constraint cr_item_rels_fk references acs_objects, item_id integer constraint cr_item_rels_item_fk references cr_items, related_object_id integer constraint cr_item_rels_rel_obj_fk references acs_objects, relation_tag varchar2(100), order_n integer ); create unique index cr_item_rel_unq on cr_item_rels ( item_id, related_object_id, relation_tag ); -- RI Indexes create index cr_item_rels_rel_obj_id_idx ON cr_item_rels(related_object_id); comment on table cr_item_rels is ' Describes all relations from one item to any number of other objects. '; comment on column cr_item_rels.relation_tag is ' A token for lightweight classification of item relationships. If additional attributes are required, then a subtype of item_rel may be created. '; comment on column cr_item_rels.order_n is ' Optional column for specifying a sort order. Note that the ordering method is application-dependent (it may be by relation type or across multiple relation types). '; -------------------------------------------------------------- -- CONTENT REVISIONS -------------------------------------------------------------- -- Define the cr_revisions table create table cr_revisions ( revision_id constraint cr_revisions_rev_id_fk references acs_objects (object_id) on delete cascade constraint cr_revisions_pk primary key, item_id constraint cr_revisions_item_id_nn not null constraint cr_revisions_item_id_fk references cr_items on delete cascade, title varchar2(1000), description varchar2(4000), publish_date date, mime_type varchar2(200) default 'text/plain' constraint cr_revisions_mime_type_fk references cr_mime_types, nls_language varchar2(50), filename varchar2(4000), content BLOB, content_length integer ); create index cr_revisions_by_mime_type on cr_revisions(mime_type); create index cr_revisions_title_idx on cr_revisions(title); create index cr_revisions_item_id_idx ON cr_revisions(item_id); create index cr_revisions_publish_date_idx on cr_revisions(publish_date); -- create index cr_revisions_lower_title_idx on cr_revisions(lower(title)); -- create index cr_revisions_title_ltr_idx on cr_revisions(substr(lower(title), 1, 1)); comment on table cr_revisions is ' Each content item may be associated with any number of revisions. The item_id is used to associate revisions with an item. '; comment on column cr_revisions.nls_language is ' NLS_LANGUAGE is required in the same table as the content column for multi-lingual searching in Intermedia. '; alter table cr_items add constraint cr_items_live_fk foreign key (live_revision) references cr_revisions(revision_id); alter table cr_items add constraint cr_items_latest_fk foreign key (latest_revision) references cr_revisions(revision_id); create table cr_revision_attributes ( revision_id integer constraint cr_revision_attributes_pk primary key constraint cr_revision_attributes_fk references cr_revisions, attributes clob ); comment on table cr_revision_attributes is ' Table contains an XML document representing the compiled attributes for a revision. '; create global temporary table cr_content_text ( revision_id integer constraint cr_content_text_revision_id_pk primary key, content CLOB ) on commit delete rows; comment on table cr_content_text is ' A temporary table for holding text extracted from the content blob. Provides a workaround for the fact that blob_to_string(content) has 4000 character limit. '; -------------------------------------------------------------- -- CONTENT PUBLISHING -------------------------------------------------------------- create table cr_item_publish_audit ( item_id integer constraint cr_item_publish_audit_fk references cr_items on delete cascade, old_revision integer constraint cr_item_pub_audit_old_rev_fk references cr_revisions, new_revision integer constraint cr_item_pub_audit_new_rev_fk references cr_revisions, old_status varchar2(40), new_status varchar2(40), publish_date date constraint cr_item_publish_audit_date_nn not null ); create index cr_item_publish_audit_idx on cr_item_publish_audit(item_id); comment on table cr_item_publish_audit is ' An audit table (populated by a trigger on cr_items.live_revision) that is used to keep track of the publication history of an item. '; create table cr_release_periods ( item_id integer constraint cr_release_periods_fk references cr_items constraint cr_release_periods_pk primary key, start_when date default sysdate, end_when date default sysdate + (365 * 20) ); create table cr_scheduled_release_log ( exec_date date default sysdate not null, items_released integer not null, items_expired integer not null, err_num integer, err_msg varchar2(500) ); comment on table cr_scheduled_release_log is ' Maintains a record, including any exceptions that may have aborted processing, for each scheduled update of live content. '; create table cr_scheduled_release_job ( job_id integer, last_exec date ); comment on table cr_scheduled_release_job is ' One-row table to track job ID of scheduled release update. '; insert into cr_scheduled_release_job values (NULL, sysdate); -------------------------------------------------------------- -- CONTENT FOLDERS -------------------------------------------------------------- create table cr_folders ( folder_id integer constraint cr_folders_folder_id_fk references cr_items on delete cascade constraint cr_folders_pk primary key, label varchar2(1000), description varchar2(4000), has_child_folders char(1) default 'f' constraint cr_folder_child_ck check (has_child_folders in ('t','f')), has_child_symlinks char(1) default 'f' constraint cr_folder_symlink_ck check (has_child_symlinks in ('t', 'f')), package_id integer constraint cr_fldr_pkg_id_fk references apm_packages ); comment on table cr_folders is ' Folders are used to support a virtual file system within the content repository. '; --RI Indexes create index cr_folders_package_id_idx ON cr_folders(package_id); create table cr_folder_type_map ( folder_id integer constraint cr_folder_type_map_fldr_fk references cr_folders, content_type varchar2(100) constraint cr_folder_type_map_typ_fk references acs_object_types, constraint cr_folder_type_map_pk primary key (folder_id, content_type) ); comment on table cr_folder_type_map is ' A one-to-many mapping table of content folders to content types. Basically, this table restricts the content types a folder may contain. Future releases will add numeric and tagged constraints similar to thos available for content types. '; -- RI Indexes create index cr_folder_typ_map_cont_typ_idx ON cr_folder_type_map(content_type); -------------------------------------------------------------- -- CONTENT TEMPLATES -------------------------------------------------------------- create table cr_templates ( template_id integer constraint cr_template_id_fk references cr_items on delete cascade constraint cr_templates_pk primary key ); comment on table cr_templates is ' Templates are a special class of text objects that are used for specifying the layout of a content item. They may be mapped to content types for defaults, or may be mapped to individual content items. '; create table cr_template_use_contexts ( use_context varchar2(100) constraint cr_template_use_contexts_pk primary key ); comment on table cr_template_use_contexts is ' A simple table (for now) for constraining template use contexts. '; insert into cr_template_use_contexts values ('admin'); insert into cr_template_use_contexts values ('public'); create table cr_type_template_map ( content_type varchar2(100) constraint cr_type_template_map_typ_fk references acs_object_types constraint cr_type_template_map_typ_nn not null, template_id integer constraint cr_type_template_map_tmpl_fk references cr_templates, use_context varchar2(100) constraint cr_type_template_map_ctx_nn not null constraint cr_type_template_map_ctx_fk references cr_template_use_contexts, is_default char(1) default 'f' constraint cr_type_template_map_def_ck check (is_default in ('t','f')), constraint cr_type_template_map_pk primary key (content_type, template_id, use_context) ); create index cr_ttmap_by_content_type on cr_type_template_map(content_type); create index cr_ttmap_by_template_id on cr_type_template_map(template_id); create index cr_ttmap_by_use_context on cr_type_template_map(use_context); comment on table cr_type_template_map is ' A simple mapping template among content types and templates. Used to determine the default template to use in any particular context, as well as for building any UI that allows publishers to choose from a palette of templates. '; comment on column cr_type_template_map.use_context is ' A token to indicate the context in which a template is appropriate, such as admin or public. Should be constrained when it becomes clearer how this will be used. '; create table cr_item_template_map ( item_id integer constraint cr_item_template_map_item_fk references cr_items constraint cr_item_template_map_item_nn not null, template_id integer constraint cr_item_template_map_tmpl_fk references cr_templates constraint cr_item_template_map_tmpl_nil not null, use_context varchar2(100) constraint cr_item_template_map_ctx_nn not null constraint cr_item_template_map_ctx_fk references cr_template_use_contexts, constraint cr_item_template_map_pk primary key (item_id, template_id, use_context) ); create index cr_itmap_by_item_id on cr_item_template_map(item_id); create index cr_itmap_by_template_id on cr_item_template_map(template_id); create index cr_itmap_by_use_context on cr_item_template_map(use_context); comment on table cr_item_template_map is ' Allows a template to be assigned to a specific item. '; -------------------------------------------------------------- -- CONTENT SYMLINKS -------------------------------------------------------------- create table cr_symlinks ( symlink_id integer constraint cr_symlink_id_fk references cr_items on delete cascade constraint cr_symlinks_pk primary key, target_id integer constraint cr_symlink_target_id_fk references cr_items constraint cr_symlink_target_id_nn not null, label varchar2(1000) ); create index cr_symlinks_by_target_id on cr_symlinks(target_id); comment on table cr_symlinks is ' Symlinks are pointers to items within the content repository. '; -------------------------------------------------------------- -- CONTENT EXTLINKS -------------------------------------------------------------- create table cr_extlinks ( extlink_id integer constraint cr_extlink_id_fk references cr_items on delete cascade constraint cr_extlinks_pk primary key, url varchar2(1000) constraint cr_extlink_url_nn not null, label varchar2(1000) constraint cr_extlink_label_nn not null, description varchar2(4000) ); comment on table cr_extlinks is ' Extlinks are pointers to items anywhere on the web which the publisher wishes to categorize, index and relate to items in the content repository. '; -------------------------------------------------------------- -- CONTENT KEYWORDS -------------------------------------------------------------- create table cr_keywords ( keyword_id integer constraint cr_keywords_pk primary key, parent_id integer constraint cr_keywords_fk references cr_keywords, heading varchar2(600) constraint cr_keywords_name_nn not null, description varchar2(4000), has_children char(1) constraint cr_keywords_child_ck check (has_children in ('t', 'f')) ); -- RI Indexes create index cr_keywords_parent_id_idx ON cr_keywords(parent_id); comment on table cr_keywords is ' Stores a subject taxonomy for classifying content items, analogous to the system used by a library. '; comment on column cr_keywords.heading is ' A subject heading. This will become a message ID in the next release so it should never be referenced directly (only through the API) '; comment on column cr_keywords.description is ' Description of a subject heading. This will be a message ID in the next release so it should never be referenced directly (only through the API) '; create table cr_item_keyword_map ( item_id integer constraint cr_item_keyword_map_item_fk references cr_items constraint cr_item_keyword_map_item_nn not null, keyword_id integer constraint cr_item_keyword_map_kw_fk references cr_keywords constraint cr_item_keyword_map_kw_nn not null, constraint cr_item_keyword_map_pk primary key (item_id, keyword_id) ); -- RI Indexes create index cr_item_keyword_map_kw_id_idx ON cr_item_keyword_map(keyword_id); -------------------------------------------------------------- -- TEXT SUBMISSION -------------------------------------------------------------- create table cr_text ( text varchar2(4000) ); comment on table cr_text is ' A simple placeholder table for generating input views, so that a complete revision may be added with a single INSERT statement. '; insert into cr_text values (NULL); create or replace trigger cr_text_tr before insert on cr_text for each row begin raise_application_error(-20000, 'Inserts are not allowed into cr_text.' ); end; / show errors -------------------------------------------------------------- -- DOCUMENT SUBMISSION WITH CONVERSION TO HTML -------------------------------------------------------------- -- Source PL/SQL Definitions. @@ content-util @@ content-xml prompt *** Creating packaged call specs for Java utility methods... @@ content-package prompt *** Defining and compiling packages... @@ packages-create prompt *** Creating object types... @@ types-create prompt *** Preparing search indices... @@ content-search -- (DanW - OpenACS) Added cleanup trigger to log file items that need -- to be cleaned up from the CR. -- DRB: moved here because the package "content" needs to be defined -- before this trigger is created. create or replace trigger cr_cleanup_cr_files_del_trg before delete on cr_revisions for each row begin insert into cr_files_to_delete ( path, storage_area_key ) select :old.filename, i.storage_area_key from cr_items i where i.item_id = :old.item_id and i.storage_type = 'file'; end cr_cleanup_cr_files_del_trg; / show errors prompt *** Compiling documentation package... @@ doc-package prompt *** Creating image content type... @@ content-image -- map some MIME types to 'content_revision' begin content_type.register_mime_type( content_type => 'content_revision', mime_type => 'text/html'); content_type.register_mime_type( content_type => 'content_revision', mime_type => 'text/plain'); content_type.register_mime_type( content_type => 'content_revision', mime_type => 'application/rtf'); end; / show errors prompt *** Initializing content repository hierarchy... -- Create the default folders declare v_id integer; begin v_id := content_folder.new ( name => 'pages', label => 'Pages', description => 'Site pages go here', parent_id => -4, folder_id => content_item.get_root_folder ); content_folder.register_content_type( folder_id => v_id, content_type => 'content_revision', include_subtypes => 't' ); content_folder.register_content_type( folder_id => v_id, content_type => 'content_folder', include_subtypes => 't' ); content_folder.register_content_type( folder_id => v_id, content_type => 'content_symlink', include_subtypes => 't' ); -- add the root content folder to acs_magic_objects insert into acs_magic_objects (name, object_id) select 'cr_item_root', content_item.get_root_folder from dual; v_id := content_folder.new ( name => 'templates', label => 'Templates', description => 'Templates which render the pages go here', parent_id => -4, folder_id => content_template.get_root_folder ); content_folder.register_content_type( folder_id => v_id, content_type => 'content_folder', include_subtypes => 't' ); content_folder.register_content_type( folder_id => v_id, content_type => 'content_symlink', include_subtypes => 't' ); content_folder.register_content_type( folder_id => v_id, content_type => 'content_template', include_subtypes => 't' ); -- add to acs_magic_objects insert into acs_magic_objects (name, object_id) select 'cr_template_root', content_template.get_root_folder from dual; end; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-schedule.sql0000644000175000017500000000715307277364656027271 0ustar frankiefrankie-- Data model to support release scheduling of items in the content -- repository of the ArsDigita Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-schedule.sql,v 1.2 2001/05/13 01:55:58 danw Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html prompt *** Preparing for scheduled updates to live content... create or replace trigger cr_scheduled_release_tr before insert on cr_scheduled_release_job for each row begin raise_application_error(-20000, 'Inserts are not allowed into cr_scheduled_release_job.' ); end; / show errors -- Update the publishing status for items that are due to be released -- or expired. create or replace procedure cr_scheduled_release_exec is last_exec date; this_exec date := sysdate; cursor start_cur is select p.item_id, live_revision from cr_release_periods p, cr_items i where start_when between last_exec and sysdate and p.item_id = i.item_id; cursor end_cur is select p.item_id, live_revision from cr_release_periods p, cr_items i where end_when between last_exec and sysdate and p.item_id = i.item_id; items_released integer := 0; items_expired integer := 0; err_num integer := sqlcode; err_msg varchar2(500) := substr(sqlerrm, 1, 500); begin begin select last_exec into last_exec from cr_scheduled_release_job; for item_rec in start_cur loop -- update publish status update cr_items set publish_status = 'live' where item_id = item_rec.item_id; items_released := items_released + 1; end loop; for item_rec in end_cur loop -- update publish status update cr_items set publish_status = 'expired' where item_id = item_rec.item_id; items_expired := items_expired + 1; end loop; exception when others then err_num := SQLCODE; err_msg := substr(SQLERRM, 1, 500); end; -- keep a record of the update insert into cr_scheduled_release_log ( items_released, items_expired, err_num, err_msg ) values ( items_released, items_expired, err_num, err_msg ); -- Reset the last time of execution to start of processing update cr_scheduled_release_job set last_exec = this_exec; -- Table was growing without bound (OpenACS DanW) delete from cr_scheduled_release_log where exec_date < sysdate - 4*7; commit; end cr_scheduled_release_exec; / show errors -- initialize the scheduled publication job -- job scheduling moved to aolserver (OpenACS - DanW) -- declare -- v_job_id integer; -- interval integer := 15; -- cursor job_cur is -- select job from user_jobs -- where what = 'cr_scheduled_release_exec;'; -- begin -- open job_cur; -- fetch job_cur into v_job_id; -- if job_cur%NOTFOUND then -- dbms_output.put_line(' -- Submitting job to process scheduled updates to live content...'); -- dbms_job.submit( -- job => v_job_id, -- what => 'cr_scheduled_release_exec;', -- next_date => sysdate, -- interval => 'sysdate + ' || (interval/24/60) -- ); -- update cr_scheduled_release_job set job_id = v_job_id; -- else -- dbms_job.change( -- job => v_job_id, -- what => 'cr_scheduled_release_exec;', -- next_date => sysdate, -- interval => 'sysdate + ' || (interval/24/60) -- ); -- end if; -- end; -- / -- show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-type.sql0000644000175000017500000006655111307261467026446 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Authors: Michael Pih (pihman@arsdigita.com) -- Karl Goldstein (karlg@arsdigita.com) -- $Id: content-type.sql,v 1.11 2009/12/07 20:19:03 daveb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- Create a trigger to make sure that there will never be more than -- one default template for a given content type and use context set serveroutput on create or replace trigger cr_type_template_map_tr before insert on cr_type_template_map for each row begin if :new.is_default = 't' then update cr_type_template_map set is_default = 'f' where content_type = :new.content_type and use_context = :new.use_context and template_id ^= :new.template_id and is_default = 't'; end if; return; end cr_type_template_map_tr; / show errors create or replace package body content_type is procedure create_type ( content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ) is table_exists integer; v_supertype_table acs_object_types.table_name%TYPE; v_count integer; begin if (supertype != 'content_revision') and (content_type != 'content_revision') then select count(*) into v_count from acs_object_type_supertype_map where object_type = create_type.supertype and ancestor_type = 'content_revision'; if v_count = 0 then raise_application_error(-20000, 'Content types can only be created as subclasses of content_revision or a derivation thereof. ' || supertype || ' is not a subclass oc content_revision.'); end if; end if; -- create the attribute table if not already created select decode(count(*),0,0,1) into table_exists from user_tables where table_name = upper(create_type.table_name); if table_exists = 0 and create_type.table_name is not null then select table_name into v_supertype_table from acs_object_types where object_type = create_type.supertype; execute immediate 'create table ' || table_name || ' (' || id_column || ' integer primary key references ' || v_supertype_table || ')'; end if; acs_object_type.create_type ( supertype => create_type.supertype, object_type => create_type.content_type, pretty_name => create_type.pretty_name, pretty_plural => create_type.pretty_plural, table_name => create_type.table_name, id_column => create_type.id_column, name_method => create_type.name_method ); refresh_view(content_type); end create_type; procedure drop_type ( content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f', drop_objects_p in char default 'f' ) is cursor attribute_cur is select attribute_name from acs_attributes where object_type = drop_type.content_type; cursor child_type_cur is select object_type from acs_object_types where supertype = drop_type.content_type; cursor revision_cur is select revision_id from cr_revisions, acs_objects where revision_id = object_id and object_type = drop_type.content_type; cursor item_cur is select item_id from cr_items where content_type = drop_type.content_type; table_exists integer; v_table_name varchar2(50); is_subclassed_p char; begin -- first we'll rid ourselves of any dependent child types, if any , along with their -- own dependent grandchild types select decode(count(*),0,'f','t') into is_subclassed_p from acs_object_types where supertype = drop_type.content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children's packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_children_p = 't' and is_subclassed_p = 't' then for child_rec in child_type_cur loop drop_type( content_type => child_rec.object_type, drop_children_p => 't', drop_table_p => drop_table_p, drop_objects_p => drop_objects_p ); end loop; end if; -- now drop all the attributes related to this type for attr_row in attribute_cur loop drop_attribute( content_type => drop_type.content_type, attribute_name => attr_row.attribute_name ); end loop; -- we'll remove the associated table if it exists select decode(count(*),0,0,1) into table_exists from user_tables u, acs_object_types objet where objet.object_type = drop_type.content_type and u.table_name = upper(objet.table_name); if table_exists = 1 and drop_table_p = 't' then select nvl(table_name,object_type) into v_table_name from acs_object_types where object_type = drop_type.content_type; -- drop the input/output views for the type -- being dropped. -- FIXME: does the trigger get dropped when the -- view is dropped? This did not exist in the 4.2 release, -- and it needs to be tested. execute immediate 'drop view ' || v_table_name || 'x'; execute immediate 'drop view ' || v_table_name || 'i'; execute immediate 'drop table ' || v_table_name; end if; if drop_objects_p = 't' then for revision_row in revision_cur loop content_revision.del( revision_id => revision_row.revision_id ); end loop; for item_row in item_cur loop content_item.del( item_id => item_row.item_id ); end loop; end if; acs_object_type.drop_type( object_type => drop_type.content_type ); end drop_type; function create_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE is v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists integer; begin -- add the appropriate column to the table begin select upper(table_name) into v_table_name from acs_object_types where object_type = create_attribute.content_type; exception when no_data_found then raise_application_error(-20000, 'Content type ''' || content_type || ''' does not exist in content_type.create_attribute'); end; select decode(count(*),0,0,1) into v_column_exists from user_tab_columns where table_name = v_table_name and column_name = upper(attribute_name); if v_column_exists = 0 then execute immediate 'alter table ' || v_table_name || ' add ' || attribute_name || ' ' || column_spec; end if; v_attr_id := acs_attribute.create_attribute ( object_type => create_attribute.content_type, attribute_name => create_attribute.attribute_name, datatype => create_attribute.datatype, pretty_name => create_attribute.pretty_name, pretty_plural => create_attribute.pretty_plural, sort_order => create_attribute.sort_order, default_value => create_attribute.default_value ); refresh_view(content_type); return v_attr_id; end create_attribute; procedure drop_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ) is v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information begin select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute.content_type and a.object_type = drop_attribute.content_type and a.attribute_name = drop_attribute.attribute_name; exception when no_data_found then raise_application_error(-20000, 'Attribute ' || content_type || ':' || attribute_name || ' does not exist in content_type.drop_attribute'); end; -- Drop the attribute acs_attribute.drop_attribute(content_type, attribute_name); -- Drop the column if neccessary if drop_column = 't' then begin execute immediate 'alter table ' || v_table || ' drop column ' || attribute_name; exception when others then raise_application_error(-20000, 'Unable to drop column ' || v_table || '.' || attribute_name || ' in content_type.drop_attribute'); end; end if; refresh_view(content_type); end drop_attribute; procedure register_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ) is v_template_registered integer; begin select count(*) into v_template_registered from cr_type_template_map where content_type = register_template.content_type and use_context = register_template.use_context and template_id = register_template.template_id; -- register the template if v_template_registered = 0 then insert into cr_type_template_map ( template_id, content_type, use_context, is_default ) values ( template_id, content_type, use_context, is_default ); -- update the registration status of the template else -- unset the default template before setting this one as the default if register_template.is_default = 't' then update cr_type_template_map set is_default = 'f' where content_type = register_template.content_type and use_context = register_template.use_context; end if; update cr_type_template_map set is_default = register_template.is_default where template_id = register_template.template_id and content_type = register_template.content_type and use_context = register_template.use_context; end if; end register_template; procedure set_default_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is begin update cr_type_template_map set is_default = 't' where template_id = set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context; -- make sure there is only one default template for -- any given content_type/use_context pair update cr_type_template_map set is_default = 'f' where template_id ^= set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context and is_default = 't'; end set_default_template; function get_template ( content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template.content_type and use_context = get_template.use_context and is_default = 't'; return v_template_id; exception when NO_DATA_FOUND then return null; end get_template; procedure unregister_template ( content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ) is begin if unregister_template.use_context is null and unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id; elsif unregister_template.use_context is null then delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type; elsif unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id and use_context = unregister_template.use_context; else delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type and use_context = unregister_template.use_context; end if; end unregister_template; -- Helper function for refresh_trigger (below) to generate the -- insert statement for a particular content type; function trigger_insert_statement ( content_type in acs_object_types.object_type%TYPE ) return varchar2 is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = trigger_insert_statement.content_type; cols varchar2(2000) := ''; vals varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; vals := vals || ', :new.' || attr_rec.attribute_name; end loop; return 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) values ( new_revision_id' || vals || ')'; end trigger_insert_statement; -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ) is tr_text varchar2(10000) := ''; v_table_name acs_object_types.table_name%TYPE; cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' and table_name is not null connect by prior supertype = object_type start with object_type = refresh_trigger.content_type order by level desc; begin -- get the table name for the content type (determines view name) select nvl(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_trigger.content_type; -- start building trigger code tr_text := ' create or replace trigger ' || v_table_name || 't instead of insert on ' || v_table_name || 'i for each row declare new_revision_id integer; begin if :new.item_id is null then raise_application_error(-20000, ''item_id is required when inserting into ' || v_table_name || 'i ''); end if; if :new.text is not null then new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, text => :new.text, package_id => :new.object_package_id ); else new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, data => :new.data, package_id => :new.object_package_id ); end if;'; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in type_cur loop tr_text := tr_text || ' ' || trigger_insert_statement(type_rec.object_type) || '; '; end loop; -- end building the trigger code tr_text := tr_text || ' end ' || v_table_name || 't;'; -- (Re)create the trigger execute immediate tr_text; end refresh_trigger; -- Create or replace a view joining all attribute tables procedure refresh_view ( content_type in cr_type_template_map.content_type%TYPE ) is -- exclude the BLOB column because it will make it impossible -- to do a select * cursor join_cur is select distinct lower(table_name) as table_name, id_column, level from acs_object_types where object_type <> 'acs_object' and object_type <> 'content_revision' and lower(table_name) <> 'acs_objects' and lower(table_name) <> 'cr_revisions' start with object_type = refresh_view.content_type connect by object_type = prior supertype; cols varchar2(1000); tabs varchar2(1000); joins varchar2(1000) := ''; v_table_name varchar2(40); begin for join_rec in join_cur loop cols := cols || ', ' || join_rec.table_name || '.*'; tabs := tabs || ', ' || join_rec.table_name; joins := joins || ' and acs_objects.object_id = ' || join_rec.table_name || '.' || join_rec.id_column; end loop; select nvl(table_name,object_type) into v_table_name from acs_object_types where object_type = content_type; -- create the input view (includes content columns) execute immediate 'create or replace view ' || v_table_name || 'i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.content as data, cr_text.text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language' || cols || ' from acs_objects, cr_revisions cr, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id ' || joins; -- create the output view (excludes content columns to enable SELECT *) execute immediate 'create or replace view ' || v_table_name || 'x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id' || cols || ' from acs_objects, cr_revisions cr, cr_items i, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id' || joins; refresh_trigger(content_type); exception when others then dbms_output.put_line('Error creating attribute view or trigger for ' || content_type); end refresh_view; procedure register_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin select decode(count(*),0,0,1) into v_exists from cr_type_children where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; if v_exists = 0 then insert into cr_type_children ( parent_type, child_type, relation_tag, min_n, max_n ) values ( parent_type, child_type, relation_tag, min_n, max_n ); else update cr_type_children set min_n = register_child_type.min_n, max_n = register_child_type.max_n where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; end if; end register_child_type; procedure unregister_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ) is begin delete from cr_type_children where parent_type = unregister_child_type.parent_type and child_type = unregister_child_type.child_type and relation_tag = unregister_child_type.relation_tag; end unregister_child_type; procedure register_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin -- check if the relation type exists select decode(count(*),0,0,1) into v_exists from cr_type_relations where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; -- if the relation type does not exist, insert a row into cr_type_relations if v_exists = 0 then insert into cr_type_relations ( content_type, target_type, relation_tag, min_n, max_n ) values ( content_type, target_type, relation_tag, min_n, max_n ); -- otherwise, update the row in cr_type_relations else update cr_type_relations set min_n = register_relation_type.min_n, max_n = register_relation_type.max_n where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; end if; end register_relation_type; procedure unregister_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ) is begin delete from cr_type_relations where content_type = unregister_relation_type.content_type and target_type = unregister_relation_type.target_type and relation_tag = unregister_relation_type.relation_tag; end unregister_relation_type; procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is v_valid_registration integer; begin -- check if this type is already registered select count(*) into v_valid_registration from cr_mime_types where not exists ( select 1 from cr_content_mime_type_map where mime_type = register_mime_type.mime_type and content_type = register_mime_type.content_type ) and mime_type = register_mime_type.mime_type; if v_valid_registration = 1 then insert into cr_content_mime_type_map ( content_type, mime_type ) values ( register_mime_type.content_type, register_mime_type.mime_type ); end if; end register_mime_type; procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is begin delete from cr_content_mime_type_map where content_type = unregister_mime_type.content_type and mime_type = unregister_mime_type.mime_type; end unregister_mime_type; function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char is v_is_content_type char(1) := 'f'; begin if object_type = 'content_revision' then v_is_content_type := 't'; else select decode(count(*),0,'f','t') into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type.object_type and ancestor_type = 'content_revision'; end if; return v_is_content_type; end is_content_type; procedure rotate_template ( template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is v_template_id cr_templates.template_id%TYPE; -- items that have an associated default template but not at the item level cursor c_items_cursor is select item_id from cr_items i, cr_type_template_map m where i.content_type = rotate_template.v_content_type and m.use_context = rotate_template.use_context and i.content_type = m.content_type and not exists ( select 1 from cr_item_template_map where item_id = i.item_id and use_context = rotate_template.use_context ); begin -- get the default template select template_id into v_template_id from cr_type_template_map where content_type = rotate_template.v_content_type and use_context = rotate_template.use_context and is_default = 't'; if v_template_id is not null then -- register an item-template to all items without an item-template for v_items_val in c_items_cursor loop content_item.register_template ( item_id => v_items_val.item_id, template_id => v_template_id, use_context => rotate_template.use_context ); end loop; end if; -- register the new template as the default template of the content type if v_template_id ^= rotate_template.template_id then content_type.register_template( content_type => rotate_template.v_content_type, template_id => rotate_template.template_id, use_context => rotate_template.use_context, is_default => 't' ); end if; end rotate_template; end content_type; / show errors -- Refresh the attribute views prompt *** Refreshing content type attribute views... begin for type_rec in (select object_type from acs_object_types connect by supertype = prior object_type start with object_type = 'content_revision') loop content_type.refresh_view(type_rec.object_type); end loop; end; / openacs-5.7.0/packages/acs-content-repository/sql/oracle/acs-content-repository-create.sql0000644000175000017500000000066007257214420031672 0ustar frankiefrankie-- Registration of ACS Content Repository System. -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: acs-content-repository-create.sql,v 1.1 2001/03/24 22:00:48 danw Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html @@ content-create openacs-5.7.0/packages/acs-content-repository/sql/oracle/datatype-upgrade.sql0000644000175000017500000000150307257214420027233 0ustar frankiefrankie update acs_attributes set datatype = 'keyword' where attribute_name = 'name' and object_type = 'content_item'; update acs_attributes set datatype = 'keyword' where attribute_name = 'locale' and object_type = 'content_item'; update acs_attributes set datatype = 'text' where attribute_name = 'title' and object_type = 'content_revision'; update acs_attributes set datatype = 'text' where attribute_name = 'description' and object_type = 'content_revision'; update acs_attributes set datatype = 'text' where attribute_name = 'mime_type' and object_type = 'content_revision'; update acs_attributes set datatype = 'integer' where attribute_name = 'width' and object_type = 'image'; update acs_attributes set datatype = 'integer' where attribute_name = 'height' and object_type = 'image'; openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-template.sql0000644000175000017500000000704010214643301027247 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-template.sql,v 1.7 2005/03/12 19:45:05 andrewg Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_template as function get_root_folder return cr_folders.folder_id%TYPE is begin return c_root_folder_id; end get_root_folder; function new ( name in cr_items.name%TYPE, text in varchar2 default null, parent_id in cr_items.parent_id%TYPE default null, is_live in char default 't', template_id in cr_templates.template_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- make sure we're allowed to create a template in this folder if content_folder.is_folder(parent_id) = 't' and content_folder.is_registered(parent_id,'content_template') = 'f' then raise_application_error(-20000, 'This folder does not allow templates to be created'); else if package_id is null then v_package_id := acs_object.package_id(v_parent_id); else v_package_id := package_id; end if; v_template_id := content_item.new ( item_id => content_template.new.template_id, name => content_template.new.name, text => content_template.new.text, parent_id => v_parent_id, package_id => v_package_id, content_type => 'content_template', is_live => content_template.new.is_live, creation_date => content_template.new.creation_date, creation_user => content_template.new.creation_user, creation_ip => content_template.new.creation_ip ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end new; -- delete all template relations procedure del ( template_id in cr_templates.template_id%TYPE ) is begin delete from cr_type_template_map where template_id = content_template.del.template_id; delete from cr_item_template_map where template_id = content_template.del.template_id; delete from cr_templates where template_id = content_template.del.template_id; content_item.del(content_template.del.template_id); end del; function is_template ( template_id in cr_templates.template_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_templates where template_id = is_template.template_id; return v_ret; exception when no_data_found then return 'f'; end is_template; function get_path ( template_id in cr_templates.template_id%TYPE, root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id ) return varchar2 is begin return content_item.get_path(template_id, root_folder_id); end get_path; end content_template; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/0000755000175000017500000000000011575225416024707 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0d2-5.2.0d3.sql0000644000175000017500000000114210044221035030611 0ustar frankiefrankie-- @cvs-id $Id: upgrade-5.2.0d2-5.2.0d3.sql,v 1.1 2004/04/29 15:41:17 jeffd Exp $ -- @author davis@xarg.net -- cascade on delete of folder and of content_type alter table cr_folder_type_map drop constraint cr_folder_type_map_fldr_fk; alter table cr_folder_type_map add constraint cr_folder_type_map_fldr_fk foreign key (folder_id) references cr_folders on delete cascade; alter table cr_folder_type_map drop constraint cr_folder_type_map_typ_fk; alter table cr_folder_type_map add constraint cr_folder_type_map_typ_fk foreign key (content_type) references acs_object_types on delete cascade; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.1d1-5.2.1d2.sql0000644000175000017500000023032210440426443030627 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-12-26 -- @arch-tag: c141278e-3359-4f40-8d61-3b8e940c633c -- @cvs-id $Id: upgrade-5.2.1d1-5.2.1d2.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- -- New installs were not setting parent_id to security_context_root (-4) -- but 0 so the CR root folders have the wrong info -- re-run these upgrades. -- Content Repository sets parent_id to security_context_root -- for content modules update acs_objects set context_id = -4 where context_id = 0; update cr_items set parent_id = -4 where parent_id = 0; -- now we need to recreate all the functions that assume 0 -- we use acs_magic_object('security_context_root') instead of 0 -- for future flexibility -- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-5.2.1d1-5.2.1d2.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html set serveroutput on size 1000000 format wrapped create or replace view content_item_globals as select -100 as c_root_folder_id from dual; -- package body content_item create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL or item_id in (-4,-100,-200) then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = -4 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = -4 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= -4 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= -4 then begin -- Figure out the relation_tag to use if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type, v_rel_tag) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, title => content_item.new.name, package_id => content_item.new.package_id, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, security_inherit_p => content_item.new.security_inherit_p ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels -- We checked above before creating the object that it is a valid rel if v_parent_id ^= -4 and content_folder.is_folder(v_parent_id) = 'f' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', title => v_rel_tag || ': ' || v_parent_id || ' - ' || v_item_id, package_id => content_item.new.package_id, context_id => v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, package_id => content_item.new.package_id, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, package_id => content_item.new.package_id, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure del ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.del.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.del.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.del.item_id or related_object_id = content_item.del.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.del.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.del.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; dbms_output.put_line('Deleting symlinks...'); -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.del(v_symlink_val.symlink_id); end loop; dbms_output.put_line('Unscheduling item...'); delete from cr_release_periods where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated revisions...'); -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.del.item_id; for v_revision_val in c_revision_cur loop content_revision.del(v_revision_val.revision_id); end loop; dbms_output.put_line('Deleting associated item templates...'); -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting item relationships...'); -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting child relationships...'); for v_rel_val in c_child_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting parent relationships...'); for v_rel_val in c_parent_cur loop acs_rel.del(v_rel_val.rel_id); content_item.del(v_rel_val.child_id); end loop; dbms_output.put_line('Deleting associated permissions...'); -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.del.item_id; dbms_output.put_line('Deleting keyword associations...'); -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated comments...'); -- 7) delete associated comments journal_entry.delete_for_object( content_item.del.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; dbms_output.put_line('Deleting content item...'); acs_object.del(content_item.del.item_id); end del; procedure edit_name ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where cr_items.name = content_item.edit_name.name and parent_id = (select parent_id from cr_items where cr_items.item_id = content_item.edit_name.item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set cr_items.name = content_item.edit_name.name where cr_items.item_id = content_item.edit_name.item_id; update acs_objects set title = content_item.edit_name.name where object_id = content_item.edit_name.item_id; else close exists_cur; if exists_id <> item_id then raise_application_error(-20000, 'An item with the name ' || name || ' already exists in this directory.'); end if; end if; end edit_name; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := -4; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := -4; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id, name); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id, name = nvl (move.name, cr_items.name) where item_id = move.item_id; end if; if name is not null then update acs_objects set title = move.name where object_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip, name); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; select content_type, name , locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- can't copy to the same folder unless name is different if copy2.target_folder_id ^= v_current_folder_id or (v_name != copy2.name and copy2.name is not null) then if copy2.name is not null then v_name := copy2.name; end if; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; elsif v_content_type = 'content_extlink' then select label into v_title from cr_extlinks where extlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; v_package_id := acs_object.package_id(relate.item_id); -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, title => relation_tag || ': ' || relate.item_id || ' - ' || relate.object_id, package_id => v_package_id, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; update acs_objects set title = relate.relation_tag || ': ' || relate.item_id || ' - ' || relate.object_id where object_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.del( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; v_folder_id := get_parent_folder.item_id; while v_parent_folder_p = 'f' and v_folder_id is not null loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end get_parent_folder; end content_item; / show errors --package body content folder create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = security context root means that this is a mount point if parent_id ^= -4 and content_folder.is_folder(parent_id) = 'f' and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( name => new.name, parent_id => new.parent_id, item_id => new.folder_id, creation_date => new.creation_date, creation_user => new.creation_user, context_id => v_context_id, creation_ip => new.creation_ip, item_subtype => 'content_folder', content_type => 'content_folder', security_inherit_p => new.security_inherit_p, package_id => new.package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, label, description, package_id ); -- set the correct object title update acs_objects set title = new.label where object_id = v_folder_id; -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null then update acs_objects set title = edit_name.label where object_id = edit_name.folder_id; end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy.folder_id; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder or target_folder_id = folder_id then v_valid_folders_p := 0; end if; if v_valid_folders_p = 2 then -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if is_sub_folder(folder_id, target_folder_id) ^= 't' or v_current_folder_id != copy.target_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end if; end if; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := -4; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; if v_parent_id = folder_id then v_sub_folder_p := 't'; end if; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors -- Refresh the attribute triggers begin for type_rec in (select object_type,table_name from acs_object_types connect by supertype = prior object_type start with object_type = 'content_revision') loop if table_exists(type_rec.table_name) then content_type.refresh_view(type_rec.object_type); end if; end loop; -- DRB: The EVIL acs_message_revision names CR_REVISIONS as its table name. This replaces -- the cr_revision trigger on cr_revisionsi which doesn't set item_id. This causes an -- "can't insert NULL item_id" error when inserting on the view. This took me like -- THREE FUCKING DAYS to figure out (well, there were other errors I had to fix with -- upgrades before I could fix this one). content_type.refresh_view('content_revision'); end; / show errors; -- recreate content keyword package for package_id create or replace package content_keyword as function new ( --/** Creates a new keyword (also known as "subject category"). -- @author Karl Goldstein -- @param heading The heading for the new keyword -- @param description The description for the new keyword -- @param parent_id The parent of this keyword, defaults to null. -- @param keyword_id The id of the new keyword. A new id will be allocated if this -- parameter is null -- @param object_type The type for the new keyword, defaults to 'content_keyword'. -- This parameter may be used by subclasses of -- content_keyword to initialize the superclass. -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created keyword -- @see {acs_object.new}, {content_item.new}, {content_keyword.item_assign}, -- {content_keyword.delete} --*/ heading in cr_keywords.heading%TYPE, description in cr_keywords.description%TYPE default null, parent_id in cr_keywords.parent_id%TYPE default null, keyword_id in cr_keywords.keyword_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_object_types.object_type%TYPE default 'content_keyword', package_id in acs_objects.package_id%TYPE default null ) return cr_keywords.keyword_id%TYPE; procedure del ( --/** Deletes the specified keyword, which must be a leaf. Unassigns the -- keyword from all content items. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param keyword_id The id of the keyword to be deleted -- @see {acs_object.delete}, {content_keyword.item_unassign} --*/ keyword_id in cr_keywords.keyword_id%TYPE ); function get_heading ( --/** Retrieves the heading of the content keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The heading for the specified keyword -- @see {content_keyword.set_heading}, {content_keyword.get_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; function get_description ( --/** Retrieves the description of the content keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The description for the specified keyword -- @see {content_keyword.get_heading}, {content_keyword.set_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; procedure set_heading ( --/** Sets a new heading for the keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @param heading The new heading -- @see {content_keyword.get_heading}, {content_keyword.set_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE, heading in cr_keywords.heading%TYPE ); procedure set_description ( --/** Sets a new description for the keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @param description The new description -- @see {content_keyword.set_heading}, {content_keyword.get_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE, description in cr_keywords.description%TYPE ); function is_leaf ( --/** Determines if the keyword has no sub-keywords associated with it -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return 't' if the keyword has no descendants, 'f' otherwise -- @see {content_keyword.new} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; procedure item_assign ( --/** Assigns this keyword to a content item, creating a relationship between them -- @author Karl Goldstein -- @param item_id The item to be assigned to -- @param keyword_id The keyword to be assigned -- @param context_id As in acs_rel.new, deprecated -- @param creation_ip As in acs_rel.new, deprecated -- @param creation_user As in acs_rel.new, deprecated -- @see {acs_rel.new}, {content_keyword.item_unassign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ); procedure item_unassign ( --/** Unassigns this keyword to a content item, removing a relationship between them -- @author Karl Goldstein -- @param item_id The item to be unassigned from -- @param keyword_id The keyword to be unassigned -- @see {acs_rel.delete}, {content_keyword.item_assign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE ); function is_assigned ( --/** Determines if the keyword is assigned to the item -- @author Karl Goldstein -- @param item_id The item id -- @param keyword_id The keyword id to be checked for assignment -- @param recurse Specifies if the keyword search is -- recursive. May be set to one of the following -- values:
    --
  • none: Not recursive. Look for an exact match.
  • --
  • up: Recursive from specific to general. A search for -- "attack dogs" will also match "dogs", "animals", "mammals", etc.
  • --
  • down: Recursive from general to specific. A search for -- "mammals" will also match "dogs", "attack dogs", "cats", "siamese cats", -- etc.
-- @return 't' if the keyword may be matched to an item, 'f' otherwise -- @see {content_keyword.item_assign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, recurse in varchar2 default 'none' ) return varchar2; function get_path ( --/** Retreives a path to the keyword/subject category, with the most general -- category at the root of the path -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The path to the keyword, or null if no such keyword exists -- @see {content_keyword.new} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; end content_keyword; / show errors -- recreate content keyword package body for package_id create or replace package body content_keyword as function get_heading ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_heading varchar2(4000); begin select heading into v_heading from cr_keywords where keyword_id = content_keyword.get_heading.keyword_id; return v_heading; end get_heading; function get_description ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_description varchar2(4000); begin select description into v_description from cr_keywords where keyword_id = content_keyword.get_description.keyword_id; return v_description; end get_description; procedure set_heading ( keyword_id in cr_keywords.keyword_id%TYPE, heading in cr_keywords.heading%TYPE ) is begin update cr_keywords set heading = set_heading.heading where keyword_id = set_heading.keyword_id; update acs_objects set title = set_heading.heading where object_id = set_heading.keyword_id; end set_heading; procedure set_description ( keyword_id in cr_keywords.keyword_id%TYPE, description in cr_keywords.description%TYPE ) is begin update cr_keywords set description = set_description.description where keyword_id = set_description.keyword_id; end set_description; function is_leaf ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_leaf varchar2(1); cursor c_leaf_cur is select 'f' from cr_keywords k where k.parent_id = is_leaf.keyword_id; begin open c_leaf_cur; fetch c_leaf_cur into v_leaf; if c_leaf_cur%NOTFOUND then v_leaf := 't'; end if; close c_leaf_cur; return v_leaf; end is_leaf; function new ( heading in cr_keywords.heading%TYPE, description in cr_keywords.description%TYPE default null, parent_id in cr_keywords.parent_id%TYPE default null, keyword_id in cr_keywords.keyword_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_object_types.object_type%TYPE default 'content_keyword', package_id in acs_objects.package_id%TYPE default null ) return cr_keywords.keyword_id%TYPE is v_id integer; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_id := acs_object.new (object_id => keyword_id, context_id => parent_id, object_type => object_type, title => heading, package_id => v_package_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip); insert into cr_keywords (heading, description, keyword_id, parent_id) values (heading, description, v_id, parent_id); return v_id; end new; procedure del ( keyword_id in cr_keywords.keyword_id%TYPE ) is v_item_id integer; cursor c_rel_cur is select item_id from cr_item_keyword_map where keyword_id = content_keyword.del.keyword_id; begin open c_rel_cur; loop fetch c_rel_cur into v_item_id; exit when c_rel_cur%NOTFOUND; item_unassign(v_item_id, content_keyword.del.keyword_id); end loop; close c_rel_cur; acs_object.del(keyword_id); end del; procedure item_assign ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_dummy integer; begin -- Do nothing if the keyword is assigned already select decode(count(*),0,0,1) into v_dummy from dual where exists (select 1 from cr_item_keyword_map where item_id=item_assign.item_id and keyword_id=item_assign.keyword_id); if v_dummy > 0 then -- previous assignment exists return; end if; insert into cr_item_keyword_map ( item_id, keyword_id ) values ( item_id, keyword_id ); end item_assign; procedure item_unassign ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE ) is begin delete from cr_item_keyword_map where item_id = item_unassign.item_id and keyword_id = item_unassign.keyword_id; end item_unassign; function is_assigned ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, recurse in varchar2 default 'none' ) return varchar2 is v_ret varchar2(1); begin -- Look for an exact match if recurse = 'none' then declare begin select 't' into v_ret from cr_item_keyword_map where item_id = is_assigned.item_id and keyword_id = is_assigned.keyword_id; return 't'; exception when no_data_found then return 'f'; end; end if; -- Look from specific to general if recurse = 'up' then begin select 't' into v_ret from dual where exists (select 1 from (select keyword_id from cr_keywords connect by parent_id = prior keyword_id start with keyword_id = is_assigned.keyword_id ) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned.item_id); return 't'; exception when no_data_found then return 'f'; end; end if; if recurse = 'down' then begin select 't' into v_ret from dual where exists ( select 1 from (select keyword_id from cr_keywords connect by prior parent_id = keyword_id start with keyword_id = is_assigned.keyword_id ) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned.item_id); return 't'; exception when no_data_found then return 'f'; end; end if; -- Tried none, up and down - must be an invalid parameter raise_application_error (-20000, 'The recurse parameter to ' || 'content_keyword.is_assigned should be ''none'', ''up'' or ''down''.'); end is_assigned; function get_path ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_path varchar2(4000) := ''; v_is_found varchar2(1) := 'f'; cursor c_keyword_cur is select heading from ( select heading, level as tree_level from cr_keywords connect by prior parent_id = keyword_id start with keyword_id = get_path.keyword_id ) order by tree_level desc; v_heading cr_keywords.heading%TYPE; begin open c_keyword_cur; loop fetch c_keyword_cur into v_heading; exit when c_keyword_cur%NOTFOUND; v_is_found := 't'; v_path := v_path || '/' || v_heading; end loop; close c_keyword_cur; if v_is_found = 'f' then return null; else return v_path; end if; end get_path; end content_keyword; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.6.1-4.6.2.sql0000644000175000017500000000170310042720530030152 0ustar frankiefrankie-- Adds indexes for RI checking -- -- cr_mime_types.mime_type create index cr_cont_mimetypmap_mimetyp_idx ON cr_content_mime_type_map(mime_type); -- acs_object_types.object_type create index cr_folder_typ_map_cont_typ_idx ON cr_folder_type_map(content_type); -- apm_packages.package_id create index cr_folders_package_id_idx ON cr_folders(package_id); -- cr_keywords.keyword_id create index cr_item_keyword_map_kw_id_idx ON cr_item_keyword_map(keyword_id); -- acs_objects.object_id create index cr_item_rels_rel_obj_id_idx ON cr_item_rels(related_object_id); -- cr_keywords.keyword_id create index cr_keywords_parent_id_idx ON cr_keywords(parent_id); -- cr_items.item_id create index cr_revisions_item_id_idx ON cr_revisions(item_id); -- acs_object_types.object_type create index cr_type_children_chld_type_idx ON cr_type_children(child_type); -- acs_object_types.object_type create index cr_type_relations_tgt_typ_idx ON cr_type_relations(target_type); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.7d1-4.7d6.sql0000644000175000017500000000045707702263321030352 0ustar frankiefrankie-- Upgrade content_template.new() and make it take an optional text parameter. -- If it is provided, a revision of the template will be created automatically. -- You thus avoid calling content_revision.new() in a separate step ... -- (ola@polyxena.net) @@ ../packages-create.sql @@ ../content-item.sql openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.0d2-5.1.0d3.sql0000644000175000017500000003130510024403017030613 0ustar frankiefrankieupdate acs_objects set title = (select label from cr_folders where folder_id = object_id), package_id = (select package_id from apm_packages where package_key = 'acs-content-repository') where object_type = 'content_folder' and object_id < 0; update acs_objects set title = (select label from cr_folders where folder_id = object_id), package_id = (select nvl(package_id, acs_object.package_id(content_item.get_root_folder(folder_id))) from cr_folders where folder_id = object_id) where object_type = 'content_folder' and object_id > 0; update acs_objects set title = (select name from cr_items where item_id = object_id), package_id = acs_object.package_id(content_item.get_root_folder(object_id)) where object_type = 'content_item'; update acs_objects set title = (select title from cr_revisions where revision_id = object_id), package_id = (select acs_object.package_id(item_id) from cr_revisions where revision_id = object_id) where object_type in ('content_revision', 'image'); update acs_objects set title = (select label from cr_symlinks where symlink_id = object_id), package_id = (select acs_object.package_id(target_id) from cr_symlinks where symlink_id = object_id) where object_type = 'content_symlink'; update acs_objects set title = (select label from cr_extlinks where extlink_id = object_id), package_id = (select acs_object.package_id(parent_id) from cr_items where item_id = object_id) where object_type = 'content_extlink'; update acs_objects set title = (select heading from cr_keywords where keyword_id = object_id), package_id = (select package_id from apm_packages where package_key = 'acs-content-repository') where object_type = 'content_keyword'; update acs_objects set title = (select name from cr_items where item_id = object_id), package_id = (select acs_object.package_id(parent_id) from cr_items where item_id = object_id) where object_type = 'content_template'; update acs_objects set title = (select relation_tag || ': ' || item_id || ' - ' || related_object_id from cr_item_rels where rel_id = object_id), package_id = (select acs_object.package_id(item_id) from cr_item_rels where rel_id = object_id) where object_type = 'cr_item_rel'; update acs_objects set title = (select relation_tag || ': ' || parent_id || ' - ' || child_id from cr_child_rels where rel_id = object_id), package_id = (select acs_object.package_id(parent_id) from cr_child_rels where rel_id = object_id) where object_type = 'cr_item_child_rel'; @@ ../packages-create.sql @@ ../content-item.sql @@ ../content-revision.sql @@ ../content-folder.sql @@ ../content-template.sql @@ ../content-symlink.sql @@ ../content-extlink.sql @@ ../content-keyword.sql create or replace package image as --/** -- Creates a new image -- Binary file stored in file-system --*/ function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE ) return cr_items.item_id%TYPE; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE ) return cr_revisions.revision_id%TYPE; --/** -- Deletes a single revision of image -- Schedules binary file for deletion. -- File delete sweep checks to see if no other images are using binary prior to deleting --*/ procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ); --/** -- Deletes a image and all revisions -- Schedules binary files for deletion. -- -- Be careful, cannot be undone (easily) --*/ procedure del ( item_id in cr_items.item_id%TYPE ); end image; / show errors; create or replace package body image as function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE ) return cr_items.item_id%TYPE is v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_item_id := content_item.new ( name => name, item_id => item_id, parent_id => parent_id, package_id => v_package_id, relation_tag => relation_tag, content_type => content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, locale => locale, context_id => context_id, storage_type => storage_type ); v_revision_id := content_revision.new ( title => title, description => description, item_id => v_item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => sysdate, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_item_id; end new; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new_revision.item_id); else v_package_id := package_id; end if; v_revision_id := content_revision.new ( title => title, description => description, item_id => item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_revision_id; end new_revision; procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ) is v_content cr_files_to_delete.path%TYPE default null; begin content_revision.del ( revision_id => revision_id ); end delete_revision; procedure del ( item_id in cr_items.item_id%TYPE ) is cursor image_revision_cur is select revision_id from cr_revisions where item_id = image.del.item_id order by revision_id asc; -- order by used in cursur so latest revision will be deleted last -- save resetting latest revision multiple times during delete process begin for v_revision_val in image_revision_cur loop image.delete_revision ( revision_id => v_revision_val.revision_id ); end loop; content_item.del ( item_id => item_id ); end del; end image; / show errors; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.3.0d3-5.3.0d4.sql0000644000175000017500000000532010540513327030630 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.3.0d3-5.3.0d4.sql -- -- @author Emmanuelle Raffenne (eraffenne@dia.uned.es) -- @creation-date 2006-12-15 -- @arch-tag: a67a9b16-d809-4da4-a47a-62f96f7e8d1e -- @cvs-id $Id: upgrade-5.3.0d3-5.3.0d4.sql,v 1.2 2006/12/15 12:36:39 emmar Exp $ -- create or replace procedure update_mime_types ( v_mime_type in cr_mime_types.mime_type%TYPE, v_file_extension in cr_mime_types.file_extension%TYPE, v_label in cr_mime_types.label%TYPE ) is v_count integer; begin select count(*) into v_count from cr_mime_types where file_extension = v_file_extension; if v_count = 0 then insert into cr_mime_types (mime_type, file_extension, label) values (v_mime_type, v_file_extension, v_label); else update cr_mime_types set mime_type=v_mime_type, label=v_label where file_extension=v_file_extension; end if; select count(*) into v_count from cr_extension_mime_type_map where extension=v_file_extension; if v_count = 0 then insert into cr_extension_mime_type_map (mime_type, extension) values (v_mime_type, v_file_extension); else update cr_extension_mime_type_map set mime_type=v_mime_type where extension=v_file_extension; end if; end update_mime_types; / show errors; begin update_mime_types('application/vnd.oasis.opendocument.text', 'odt', 'OpenDocument Text'); update_mime_types('application/vnd.oasis.opendocument.text-template', 'ott','OpenDocument Text Template'); update_mime_types('application/vnd.oasis.opendocument.text-web', 'oth', 'HTML Document Template'); update_mime_types('application/vnd.oasis.opendocument.text-master', 'odm', 'OpenDocument Master Document'); update_mime_types('application/vnd.oasis.opendocument.graphics', 'odg', 'OpenDocument Drawing'); update_mime_types('application/vnd.oasis.opendocument.graphics-template', 'otg', 'OpenDocument Drawing Template'); update_mime_types('application/vnd.oasis.opendocument.presentation', 'odp', 'OpenDocument Presentation'); update_mime_types('application/vnd.oasis.opendocument.presentation-template', 'otp', 'OpenDocument Presentation Template'); update_mime_types('application/vnd.oasis.opendocument.spreadsheet', 'ods', 'OpenDocument Spreadsheet'); update_mime_types('application/vnd.oasis.opendocument.spreadsheet-template', 'ots', 'OpenDocument Spreadsheet Template'); update_mime_types('application/vnd.oasis.opendocument.chart', 'odc', 'OpenDocument Chart'); update_mime_types('application/vnd.oasis.opendocument.formula', 'odf', 'OpenDocument Formula'); update_mime_types('application/vnd.oasis.opendocument.database', 'odb', 'OpenDocument Database'); update_mime_types('application/vnd.oasis.opendocument.image', 'odi', 'OpenDocument Image'); end; / show errors; drop procedure update_mime_types; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0d15-5.2.0d16.sql0000644000175000017500000000144410240746004030774 0ustar frankiefrankie-- Add a few common mime types insert into cr_mime_types (label,mime_type,file_extension) select 'Audio - WAV','audio/wav', 'wav' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/wav'); insert into cr_mime_types (label,mime_type,file_extension) select 'Audio - MPEG','audio/mpeg', 'mpeg' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/mpeg'); insert into cr_mime_types (label, mime_type, file_extension) select 'Audio - MP3','audio/mp3', 'mp3' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/mp3'); insert into cr_mime_types (label,mime_type,file_extension) select 'Image - Progressive JPEG','image/pjpeg', 'pjpeg' from dual where not exists (select 1 from cr_mime_types where mime_type = 'image/pjpeg'); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0d11-5.2.0d12.sql0000644000175000017500000000011110175030103030743 0ustar frankiefrankiecreate index cr_revisions_publish_date_idx on cr_revisions(publish_date);openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.1-4.1.2.sql0000644000175000017500000000053307263137640030020 0ustar frankiefrankie-- packages/acs-content-repository/sql/upgrade/upgrade-4.1-4.1.2.sql -- -- @author teeters@arsdigita.com -- @creation-date 2000-03-06 -- @cvs-id $Id: upgrade-4.1-4.1.2.sql,v 1.1 2001/04/05 18:55:28 donb Exp $ -- -- upgrade script. -- reload all packages. -- This should be run manually. @../../../acs-content-repository/sql/packages-create.sql openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.2d8-5.1.2d9.sql0000644000175000017500000005275510171476674030675 0ustar frankiefrankie create or replace package content_revision as function new ( --/** Create a new revision for an item. -- @author Karl Goldstein -- @param title The revised title for the item -- @param description A short description of this revision, 4000 characters maximum -- @param publish_date Publication date. -- @param mime_type The revised mime type of the item, defaults to 'text/plain' -- @param nls_language The revised language of the item, for use with Intermedia searching -- @param data The blob which contains the body of the revision -- @param item_id The id of the item being revised -- @param revision_id The id of the new revision. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created revision -- @see {acs_object.new}, {content_item.new} --*/ title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE; function copy ( --/** Creates a new copy of a revision, including all attributes and content -- and content, returning the ID of the new revision -- @author Karl Goldstein, Michael Pih -- @param revision_id The id of the revision to copy -- @param copy_id The id of the new copy (default null) -- @param target_item_id The id of the item which will own the copied revision. If null, the item that holds the original revision will own the copied revision. Defaults to null. -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (default null) -- @return The id of the new revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE; procedure del ( --/** Deletes the revision. -- @author Karl Goldstein -- @param revision_id The id of the revision to delete -- @see {content_revision.new}, {acs_object.delete} --*/ revision_id in cr_revisions.revision_id%TYPE ); function get_number ( --/** Return the revision number of the specified revision, according to -- the chronological -- order in which revisions have been added for this item. -- @author Karl Goldstein -- @param revision_id The id the revision -- @return The number of the revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE ) return number; function revision_name ( --/** Return a pretty string 'revision x of y' --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure index_attributes( --/** Generates an XML document for insertion into cr_revision_attributes, -- which is indexed by Intermedia for searching attributes. -- @author Karl Goldstein -- @param revision_id The id of the revision to index -- @see {content_revision.new} --*/ revision_id IN cr_revisions.revision_id%TYPE ); function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE; function write_xml ( revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.exportRevision( java.lang.Integer, oracle.sql.CLOB ) return int'; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE; function read_xml ( item_id IN number, revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.importRevision( java.lang.Integer, java.lang.Integer, oracle.sql.CLOB ) return int'; procedure to_html ( --/** Converts a revision uploaded as a binary document to html -- @author Karl Goldstein -- @param revision_id The id of the revision to index --*/ revision_id IN cr_revisions.revision_id%TYPE ); procedure replace( revision_id number, search varchar2, replace varchar2) as language java name 'com.arsdigita.content.Regexp.replace( int, java.lang.String, java.lang.String )'; function is_live ( -- /** Determine if the revision is live -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is live, 'f' otherwise -- @see {content_revision.is_latest} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; function is_latest ( -- /** Determine if the revision is the latest revision -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is the latest revision for its item, 'f' otherwise -- @see {content_revision.is_live} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ); procedure content_copy ( -- /** Copies the content of the specified revision to the content -- of another revision -- @author Michael Pih -- @param revision_id The id of the revision with the content to be copied -- @param revision_id The id of the revision to be updated, defaults to the -- latest revision of the item with which the source revision is -- associated. --*/ revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ); end content_revision; / show errors create or replace package body content_revision as function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; v_content_type acs_object_types.object_type%TYPE; begin v_content_type := content_item.get_content_type(item_id); v_revision_id := acs_object.new( object_id => revision_id, object_type => v_content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, context_id => item_id ); insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, content, item_id, filename ) values ( v_revision_id, title, description, mime_type, publish_date, nls_language, data, item_id, filename ); return v_revision_id; end new; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; blob_loc cr_revisions.content%TYPE; begin blob_loc := empty_blob(); v_revision_id := content_revision.new( title => title, description => description, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => blob_loc, item_id => item_id, revision_id => revision_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, filename => filename ); select content into blob_loc from cr_revisions where revision_id = v_revision_id for update; string_to_blob(text, blob_loc); return v_revision_id; end new; procedure copy_attributes ( content_type in acs_object_types.object_type%TYPE, revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE ) is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = copy_attributes.content_type; cols varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; end loop; execute immediate 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) ( select ' || copy_id || cols || ' from ' || v_table_name || ' where ' || v_id_column || ' = ' || revision_id || ')'; end copy_attributes; function copy ( revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE is v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; -- get the content_type and supertypes cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = ( select object_type from acs_objects where object_id = copy.revision_id ) order by level desc; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy.revision_id; else v_target_item_id := target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy_id is null then select acs_object_id_seq.nextval into v_copy_id from dual; else v_copy_id := copy_id; end if; -- create the basic object insert into acs_objects ( object_id, object_type, context_id, security_inherit_p, creation_user, creation_date, creation_ip, last_modified, modifying_user, modifying_ip ) ( select v_copy_id, object_type, v_target_item_id, security_inherit_p, copy.creation_user, sysdate, copy.creation_ip, sysdate, copy.creation_user, copy.creation_ip from acs_objects where object_id = copy.revision_id ); -- create the basic revision (using v_target_item_id) insert into cr_revisions ( revision_id, title, description, publish_date, mime_type, nls_language, content, item_id, content_length ) ( select v_copy_id, title, description, publish_date, mime_type, nls_language, content, v_target_item_id, content_length from cr_revisions where revision_id = copy.revision_id ); -- iterate over the ancestor types and copy attributes for type_rec in type_cur loop copy_attributes(type_rec.object_type, copy.revision_id, v_copy_id); end loop; return v_copy_id; end copy; procedure del ( revision_id in cr_revisions.revision_id%TYPE ) is v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = content_revision.del.revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = content_revision.del.revision_id then declare cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> content_revision.del.revision_id order by o.creation_date desc; begin open c_revision_cur; fetch c_revision_cur into v_latest_revision; if c_revision_cur%NOTFOUND then v_latest_revision := null; end if; close c_revision_cur; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end; end if; -- Clear live revision if v_live_revision = content_revision.del.revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = content_revision.del.revision_id or new_revision = content_revision.del.revision_id; -- Delete the revision acs_object.del(revision_id); end del; function get_number ( revision_id in cr_revisions.revision_id%TYPE ) return number is cursor rev_cur is select revision_id from cr_revisions r, acs_objects o where item_id = (select item_id from cr_revisions where revision_id = get_number.revision_id) and o.object_id = r.revision_id order by o.creation_date; v_number integer; v_revision cr_revisions.revision_id%TYPE; begin open rev_cur; loop fetch rev_cur into v_revision; if v_revision = get_number.revision_id then v_number := rev_cur%ROWCOUNT; exit; end if; end loop; close rev_cur; return v_number; end get_number; function revision_name( revision_id IN cr_revisions.revision_id%TYPE ) return varchar2 is v_text varchar2(500); v_sql varchar2(500); begin v_sql := 'select ''Revision '' || content_revision.get_number(r.revision_id) || '' of '' || (select count(*) from cr_revisions where item_id = r.item_id) || '' for item: '' || content_item.get_title(item_id) from cr_revisions r where r.revision_id = ' || revision_name.revision_id; execute immediate v_sql into v_text; return v_text; end revision_name; procedure index_attributes( revision_id IN cr_revisions.revision_id%TYPE ) is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_revision_attributes ( revision_id, attributes ) values ( revision_id, empty_clob() ) returning attributes into clob_loc; v_revision_id := write_xml(revision_id, clob_loc); end index_attributes; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin select doc into clob_loc from cr_xml_docs where doc_id = import_xml.doc_id; v_revision_id := read_xml(item_id, revision_id, clob_loc); return v_revision_id; end import_xml; function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE is clob_loc clob; v_doc_id cr_xml_docs.doc_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_xml_docs (doc_id, doc) values (cr_xml_doc_seq.nextval, empty_clob()) returning doc_id, doc into v_doc_id, clob_loc; v_revision_id := write_xml(revision_id, clob_loc); return v_doc_id; end export_xml; procedure to_html ( revision_id IN cr_revisions.revision_id%TYPE ) is tmp_clob clob; blob_loc blob; begin ctx_doc.filter('cr_doc_filter_index', revision_id, tmp_clob, false); select content into blob_loc from cr_revisions where revision_id = to_html.revision_id for update; clob_to_blob(tmp_clob, blob_loc); dbms_lob.freetemporary(tmp_clob); end to_html; function is_live ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where live_revision = is_live.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_live; function is_latest ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where latest_revision = is_latest.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_latest; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ) is b blob; c clob; begin insert into cr_content_text ( revision_id, content ) values ( revision_id, empty_clob() ) returning content into c; select content into b from cr_revisions where revision_id = to_temporary_clob.revision_id; blob_to_clob(b, c); end to_temporary_clob; -- revision_id is the revision with the content that is to be copied procedure content_copy ( revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ) is v_item_id cr_items.item_id%TYPE; v_content_length integer; v_revision_id_dest cr_revisions.revision_id%TYPE; v_filename cr_revisions.filename%TYPE; v_content blob; begin select content_length, item_id into v_content_length, v_item_id from cr_revisions where revision_id = content_copy.revision_id; -- get the destination revision if content_copy.revision_id_dest is null then select latest_revision into v_revision_id_dest from cr_items where item_id = v_item_id; else v_revision_id_dest := content_copy.revision_id_dest; end if; -- only copy the content if the source content is not null if v_content_length is not null and v_content_length > 0 then /* The internal LOB types - BLOB, CLOB, and NCLOB - use copy semantics, as opposed to the reference semantics which apply to BFILEs. When a BLOB, CLOB, or NCLOB is copied from one row to another row in the same table or in a different table, the actual LOB value is copied, not just the LOB locator. */ select filename, content_length into v_filename, v_content_length from cr_revisions where revision_id = content_copy.revision_id; -- need to update the file name after the copy, -- if this content item is in CR file storage. The file name is based -- off of the item_id and revision_id and it will be invalid for the -- copied revision. update cr_revisions set content = (select content from cr_revisions where revision_id = content_copy.revision_id), filename = v_filename, content_length = v_content_length where revision_id = v_revision_id_dest; end if; end content_copy; end content_revision; / show errors -- Trigger to maintain latest_revision in cr_items create or replace trigger cr_revision_latest_tr after insert on cr_revisions for each row begin update cr_items set latest_revision = :new.revision_id where item_id = :new.item_id; end cr_revision_latest_tr; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0b5-5.2.0b6.sql0000644000175000017500000027004710440426443030641 0ustar frankiefrankie-- -- -- -- @author Don Baccus (dhogaza@pacifier.com) -- @creation-date 2005-10-28 -- @arch-tag: dab7cf3d-a947-43d4-ba54-66f34c66d9d0 -- @cvs-id $Id: upgrade-5.2.0b5-5.2.0b6.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- create or replace package content_item as --/** --Content items store the overview of the content published on a --website. The actual content is stored in content revisions. It is --implemented this way so that there can be mulitple versions of the --actual content while the main idea remains constant. For example: If --there is a review for the movie "Terminator," there will exist a --content item by the name "terminator" with all the right parameters --(supertype, parent, etc), there will also exist at least one content --revision pointing to this item with the actual review content. --@see {content_revision}, {content_folder} --*/ c_root_folder_id constant integer := -100; function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content item. If the data, title or text -- parameters are specified, also creates a revision for the item. -- @author Karl Goldstein -- @param name The name for the item, must be URL-encoded. -- If an item with this name already exists under the specified -- parent item, an error is thrown -- @param parent_id The parent of this item, defaults to null -- @param item_id The id of the new item. A new id will be allocated if this -- parameter is null -- @param locale The locale for this item, for use with Intermedia search -- @param item_subtype The type of the new item, defaults to 'content_item' -- This parameter is used to support inheritance, so that -- subclasses of content_item can call this function -- to initialize the parent class -- @param content_type The content type for the item, defaults to -- 'content_revision'. Only objects of this type -- may be used as revisions for the item -- @param title The user-readable title for the item, defaults to the item's -- name -- @param description A short description for the item (4000 characters maximum) -- @param mime_type The file type of the item, defaults to 'text/plain' -- @param nls_language The language for the item, used for Intermedia search -- @param text The text content of the new revision, 4000 charcters maximum. -- Cannot be specified simultaneously with the data -- parameter -- @param data The blob content of the new revision. Cannot be specified -- simultaneously with the text parameter -- @param relation_tag If a parent-child relationship is registered -- for these content types, use this tag to -- describe the parent-child relationship. Defaults -- to 'parent content type'-'child content type' -- @param is_live If 't', the new revision will become live -- @param context_id Security context id, as in acs_object.new -- If null, defaults to parent_id, and copies permissions -- from the parent into the current item -- @param storage_type in ('lob','file'). Indicates how content is to be stored. -- 'file' content is stored externally in the file system. -- @param others As in acs_object.new -- @return The id of the newly created item -- @see {acs_object.new} --*/ name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE; function is_published ( --/** Determins whether an item is published or not. -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is published, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE ) return char; function is_publishable ( --/** Determines if an item is publishable. Publishable items must -- meet the following criteria: -- 1) for each child type, the item has n children, min_n < n < max_n -- 2) for each relation type, the item has n relations, min_n < n < max_n -- 3) any 'publishing_wf' workflows are finished -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is publishable in it's present state, -- Otherwise, returns 'f' --*/ item_id in cr_items.item_id%TYPE ) return char; function is_valid_child ( --/** Determines if an item would be a valid child of another item by -- checking if the parent allows children of the would-be child's -- content type and if the parent already has n_max children of -- that content type. -- @author Michael Pih -- @param item_id The item ID of the potential parent -- @param content_type The content type of the potential child item -- @return 't' if the item would be a valid child, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char; procedure del ( --/** Deletes the specified content item, along with any revisions, symlinks, -- workflows, associated templates, associated keywords, -- child and item relationships for the item. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param item_id The id of the item to delete -- @see {acs_object.delete} --*/ item_id in cr_items.item_id%TYPE ); procedure edit_name ( --/** Renames the item. If an item with the specified name already exists -- under this item's parent, an error is thrown -- @author Karl Goldstein -- @param item_id The id of the item to rename -- @param name The new name for the item, must be URL-encoded -- @see {content_item.new} --*/ item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ); function get_id ( --/** Takes in a path, such as "/tv/programs/star_trek/episode_203" -- and returns the id of the item with this path. Note: URLs are abstract (no -- extensions are allowed in content item names and extensions are stripped when -- looking up content items) -- @author Karl Goldstein -- @param item_path The path to be resolved -- @param root_folder_id Starts path resolution from this folder. Defaults to -- the root of the sitemap -- @param resolve_index Boolean flag indicating whether to return the -- id of the index page for folders (if one -- exists). Defaults to 'f'. -- @return The id of the item with the given path, or null if no such item exists -- @see {content_item.get_path} --*/ item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE; function get_path ( --/** Retrieves the full path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Karl Goldstein -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The path to the item -- @see {content_item.get_id}, {content_item.write_to_file} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2; function get_virtual_path ( --/** Retrieves the virtual path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Michael Pih -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The virtual path to the item -- @see {content_item.get_id}, {content_item.write_to_file}, {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2; procedure write_to_file ( --/** Writes the content of the live revision of this item to a file, -- creating all the neccessary directories in the process -- @author Karl Goldstein -- @param item_id The item to be written to a file -- @param root_path The path in the filesystem to which the root of the -- sitemap corresponds -- @see {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_path in varchar2 ); procedure register_template ( --/** Registers a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be registered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.unregister_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ); procedure unregister_template ( --/** Unregisters a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.register_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ); function get_template ( --/** Retrieves the template which should be used to render this item. If no template -- is registered to specifically render the item in the given context, the -- default template for the item's type is returned. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param use_context The context in the item is to be rendered, such -- as 'admin' or 'public' -- @return The id of the registered template, or null if no template could be -- found -- @see {content_type.register_template}, {content_item.register_template}, --*/ item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; function get_live_revision ( --/** Retrieves the id of the live revision for the item -- @param item_id The item for which the live revision is to be retrieved -- @return The id of the live revision for this item, or null if no live revision -- exists -- @see {content_item.set_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; procedure set_live_revision ( --/** Make the specified revision the live revision for the item -- @author Karl Goldstein -- @param revision_id The id of the revision which is to become live -- for its corresponding item -- @see {content_item.get_live_revision} --*/ revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ); procedure unset_live_revision ( --/** Set the live revision to null for the item -- @author Michael Pih -- @param item_id The id of the item for which to unset the live revision -- @see {content_item.set_live_revision} item_id in cr_items.item_id%TYPE ); procedure set_release_period ( --/** Sets the release period for the item. This information may be -- used by applications to update the publishing status of items -- at periodic intervals. -- @author Karl Goldstein -- @param item_id The id the item. -- @param start_when The time and date when the item should be released. -- @param end_when The time and date when the item should be expired. --*/ item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ); function get_revision_count ( --/** Return the total count of revisions for this item -- @author Karl Goldstein -- @param item_id The id the item -- @return The number of revisions for this item -- @see {content_revision.new} --*/ item_id in cr_items.item_id%TYPE ) return number; -- Return the object type of this item function get_content_type ( --/** Retrieve the content type of this item. Only objects of this type may be -- used as revisions for the item. -- @author Karl Goldstein -- @param item_id The item for which the content type is to be retrieved -- @return The content type of the item --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; function get_context ( --/** Retrieve the parent of the given item -- @author Karl Goldstein -- @param item_id The item for which the parent is to be retrieved -- @return The id of the parent for this item --*/ item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE; procedure move ( --/** Move the specified item to a different folder. If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein -- @param item_id The item to be moved -- @param target_folder_id The new folder for the item -- @see {content_item.new}, {content_folder.new}, {content_item.copy} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function copy2 ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @return The item ID of the new copy. -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE; -- get the latest revision for an item function get_latest_revision ( --/** Retrieves the id of the latest revision for the item (as opposed to the live -- revision) -- @author Karl Goldstein -- @param item_id The item for which the latest revision is to be retrieved -- @return The id of the latest revision for this item, or null if no revisions -- exist -- @see {content_item.get_live_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_best_revision ( --/** Retrieves the id of the live revision for the item if one exists, -- otherwise retrieves the id of the latest revision if one exists. -- revision) -- @author Michael Pih -- @param item_id The item for which the revision is to be retrieved -- @return The id of the live or latest revision for this item, -- or null if no revisions exist -- @see {content_item.get_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_title ( --/** Retrieves the title for the item, using either the latest or the live revision. -- If the specified item is in fact a folder, return the folder's label. -- In addition, this function will automatically resolve symlinks. -- @author Karl Goldstein -- @param item_id The item for which the title is to be retrieved -- @param is_live If 't', use the live revision to get the title. Otherwise, -- use the latest revision. The default is 'f' -- @return The title of the item -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, -- {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE; function get_publish_date ( --/** Retrieves the publish date for the item -- @author Karl Goldstein -- @param item_id The item for which the publish date is to be retrieved -- @param is_live If 't', use the live revision for the item. Otherwise, use -- the latest revision. The default is 'f' -- @return The publish date for the item, or null if the item has no revisions -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE; function is_subclass ( --/** Determines if one type is a subclass of another. A class is always a subclass of -- itself. -- @author Karl Goldstein -- @param object_type The child class -- @param supertype The superclass -- @return 't' if the child class is a subclass of the superclass, 'f' otherwise -- @see {acs_object_type.create_type} --*/ object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char; function relate ( --/** Relates two content items -- @author Karl Goldstein -- @param item_id The item id -- @param object_id The item id of the related object -- @param relation_tag A tag to help identify the relation type, -- defaults to 'generic' -- @param order_n The order of this object among other objects -- of the same relation type, defaults to null. -- @param relation_type The object type of the relation, defaults to -- 'cr_item_rel' --*/ item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE; procedure unrelate ( --/** Delete the item relationship between two items -- @author Michael Pih -- @param rel_id The relationship id -- @see {content_item.relate} --*/ rel_id in cr_item_rels.rel_id%TYPE ); function is_index_page ( --/** Determine if the item is an index page for the specified folder. -- The item is an index page for the folder if it exists in the -- folder and its item name is "index". -- @author Karl Goldstein -- @param item_id The item id -- @param folder_id The folder id -- @return 't' if the item is an index page for the specified -- folder, 'f' otherwise -- @see {content_folder.get_index_page} --*/ item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2; function get_parent_folder ( --/** Get the parent folder. -- @author Michael Pih -- @param item_id The item id -- @return the folder_id of the parent folder, null otherwise --*/ item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE; end content_item; / show errors create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL or item_id in (-4,-100,-200) then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = -4 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_package_id acs_objects.package_id%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; if package_id is null and parent_id ^= -4 then v_package_id := acs_object.package_id(content_item.get_root_folder(v_parent_id)); else v_package_id := package_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = -4 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= -4 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= -4 then begin -- Figure out the relation_tag to use if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type, v_rel_tag) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, title => content_item.new.name, package_id => v_package_id, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, security_inherit_p => content_item.new.security_inherit_p ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels -- We checked above before creating the object that it is a valid rel if v_parent_id ^= -4 and content_folder.is_folder(v_parent_id) = 'f' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', title => v_rel_tag || ': ' || v_parent_id || ' - ' || v_item_id, package_id => v_package_id, context_id => v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, package_id => v_package_id, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, package_id => v_package_id, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure del ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.del.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.del.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.del.item_id or related_object_id = content_item.del.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.del.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.del.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; dbms_output.put_line('Deleting symlinks...'); -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.del(v_symlink_val.symlink_id); end loop; dbms_output.put_line('Unscheduling item...'); delete from cr_release_periods where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated revisions...'); -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.del.item_id; for v_revision_val in c_revision_cur loop content_revision.del(v_revision_val.revision_id); end loop; dbms_output.put_line('Deleting associated item templates...'); -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting item relationships...'); -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting child relationships...'); for v_rel_val in c_child_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting parent relationships...'); for v_rel_val in c_parent_cur loop acs_rel.del(v_rel_val.rel_id); content_item.del(v_rel_val.child_id); end loop; dbms_output.put_line('Deleting associated permissions...'); -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.del.item_id; dbms_output.put_line('Deleting keyword associations...'); -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated comments...'); -- 7) delete associated comments journal_entry.delete_for_object( content_item.del.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; dbms_output.put_line('Deleting content item...'); acs_object.del(content_item.del.item_id); end del; procedure edit_name ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where cr_items.name = content_item.edit_name.name and parent_id = (select parent_id from cr_items where cr_items.item_id = content_item.edit_name.item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set cr_items.name = content_item.edit_name.name where cr_items.item_id = content_item.edit_name.item_id; update acs_objects set title = content_item.edit_name.name where object_id = content_item.edit_name.item_id; else close exists_cur; if exists_id <> item_id then raise_application_error(-20000, 'An item with the name ' || name || ' already exists in this directory.'); end if; end if; end edit_name; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := -4; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := -4; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id, name); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id, name = nvl (move.name, cr_items.name) where item_id = move.item_id; end if; if name is not null then update acs_objects set title = move.name where object_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip, name); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; select content_type, name , locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- can't copy to the same folder unless name is different if copy2.target_folder_id ^= v_current_folder_id or (v_name != copy2.name and copy2.name is not null) then if copy2.name is not null then v_name := copy2.name; end if; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; elsif v_content_type = 'content_extlink' then select label into v_title from cr_extlinks where extlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; v_package_id := acs_object.package_id(relate.item_id); -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, title => relation_tag || ': ' || relate.item_id || ' - ' || relate.object_id, package_id => v_package_id, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; update acs_objects set title = relate.relation_tag || ': ' || relate.item_id || ' - ' || relate.object_id where object_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.del( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; v_folder_id := get_parent_folder.item_id; while v_parent_folder_p = 'f' and v_folder_id is not null loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end get_parent_folder; end content_item; / show errors create or replace package content_folder as function new ( --/** Create a new folder -- @author Karl Goldstein -- @param label The label for the folder -- @param description A short description of the folder, 4000 characters maximum -- @param parent_id The parent of the folder -- @param folder_id The id of the new folder. A new id will be allocated by default -- @param context_id The context id. The parent id will be used as the default context -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @param package_id The package id. -- @return The id of the newly created folder -- @see {acs_object.new}, {content_item.new} --*/ name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_folders.folder_id%TYPE; procedure del ( --/** Delete a folder. An error is thrown if the folder is not empty -- @author Karl Goldstein -- @param folder_id The id of the folder to delete -- @see {acs_object.delete}, {content_item.delete} --*/ folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ); procedure edit_name ( --/** Change the name, label and/or description of the folder -- @author Karl Goldstein -- @param folder_id The id of the folder to modify -- @param name The new name for the folder. An error will be thrown if -- an item with this name already exists under this folder's -- parent. If this parameter is null, the old name will be preserved -- @param label The new label for the folder. The old label will be preserved if -- this parameter is null -- @param label The new description for the folder. The old description -- will be preserved if this parameter is null -- @see {content_folder.new} --*/ folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ); procedure move ( --/** Recursively move the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be moved. -- @author Karl Goldstein -- @param folder_id The id of the folder to move -- @param target_folder_id The destination folder -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Recursively copy the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be copied -- @author Karl Goldstein -- @param folder_id The id of the folder to copy -- @param target_folder_id The destination folder -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defaults to null) -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function is_folder ( --/** Determine if the item is a folder -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a folder, 'f' otherwise -- @see {content_folder.new}, {content_folder.is_sub_folder} --*/ item_id in cr_items.item_id%TYPE ) return char; function is_sub_folder ( --/** Determine if the item target_folder_id is a subfolder of -- the item folder_id -- @author Karl Goldstein -- @param folder_id The superfolder id -- @param target_folder_id The subfolder id -- @return 't' if the item target_folder_id is a subfolder of -- the item folder_id, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char; function is_empty ( --/** Determine if the folder is empty -- @author Karl Goldstein -- @param folder_id The folder id -- @return 't' if the folder contains no subfolders or items, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE ) return varchar2; function is_root ( --/** Determine whether the folder is a root (has a parent_id of 0) -- @author Karl Goldstein -- @param folder_id The folder ID -- @return 't' if the folder is a root or 'f' otherwise --*/ folder_id in cr_folders.folder_id%TYPE ) return char; procedure register_content_type ( --/** Register a content type to the folder, if it is not already registered. -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be registered -- @see {content_folder.unregister_content_type}, -- {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); procedure unregister_content_type ( --/** Unregister a content type from the folder, if it has been registered. -- Only items of the registered type(s) may be added to the folder. -- If the folder already contains items of the type to be unregistered, the -- items remain in the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be unregistered -- @param include_subtypes If 't', all subtypes of content_type will be -- unregistered as well -- @see {content_folder.register_content_type}, {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); -- change this to is_type_registered function is_registered ( --/** Determines if a content type is registered to the folder -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be checked -- @param include_subtypes If 't', all subtypes of the content_type -- will be checked, returning 't' if all of them are registered. If 'f', -- only an exact match with content_type will be -- performed. -- @return 't' if the type is registered to this folder, 'f' otherwise -- @see {content_folder.register_content_type}, {content_folder.unregister_content_type}, --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2; function get_label ( --/** Returns the label for the folder. This function is the default name method -- for the folder object. -- @author Karl Goldstein -- @param folder_id The folder id -- @return The folder's label -- @see {acs_object_type.create_type}, the docs for the name_method parameter --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE; function get_index_page ( --/** Returns the item ID of the index page of the folder, null otherwise -- @author Michael Pih -- @param folder_id The folder id -- @return The item ID of the index page --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE; end content_folder; / show errors create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = security context root means that this is a mount point if parent_id ^= -4 and content_folder.is_folder(parent_id) = 'f' and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_package_id := package_id; if parent_id is not null and parent_id ^= -4 and package_id is null then v_package_id := acs_object.package_id(content_item.get_root_folder(parent_id)); end if; v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id, security_inherit_p => security_inherit_p, package_id => v_package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, label, description, v_package_id ); -- set the correct object title update acs_objects set title = new.label where object_id = v_folder_id; -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null then update acs_objects set title = edit_name.label where object_id = edit_name.folder_id; end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy.folder_id; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder or target_folder_id = folder_id then v_valid_folders_p := 0; end if; if v_valid_folders_p = 2 then -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if is_sub_folder(folder_id, target_folder_id) ^= 't' or v_current_folder_id != copy.target_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end if; end if; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := -4; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; if v_parent_id = folder_id then v_sub_folder_p := 't'; end if; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.2-5.2.3d1.sql0000644000175000017500000002336410440426443030412 0ustar frankiefrankie-- update image package to allow null package_id -- hbrock@harpcolumn.com 2006-1-19 create or replace package image as --/** -- Creates a new image -- Binary file stored in file-system --*/ function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE; --/** -- Deletes a single revision of image -- Schedules binary file for deletion. -- File delete sweep checks to see if no other images are using binary prior to deleting --*/ procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ); --/** -- Deletes a image and all revisions -- Schedules binary files for deletion. -- -- Be careful, cannot be undone (easily) --*/ procedure del ( item_id in cr_items.item_id%TYPE ); end image; / show errors; create or replace package body image as function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE is v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_item_id := content_item.new ( name => name, item_id => item_id, parent_id => parent_id, package_id => v_package_id, relation_tag => relation_tag, content_type => content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, locale => locale, context_id => context_id, storage_type => storage_type ); v_revision_id := content_revision.new ( title => title, description => description, item_id => v_item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => sysdate, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_item_id; end new; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new_revision.item_id); else v_package_id := package_id; end if; v_revision_id := content_revision.new ( title => title, description => description, item_id => item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_revision_id; end new_revision; procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ) is v_content cr_files_to_delete.path%TYPE default null; begin content_revision.del ( revision_id => revision_id ); end delete_revision; procedure del ( item_id in cr_items.item_id%TYPE ) is cursor image_revision_cur is select revision_id from cr_revisions where item_id = image.del.item_id order by revision_id asc; -- order by used in cursur so latest revision will be deleted last -- save resetting latest revision multiple times during delete process begin for v_revision_val in image_revision_cur loop image.delete_revision ( revision_id => v_revision_val.revision_id ); end loop; content_item.del ( item_id => item_id ); end del; end image; / show errors; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.5-4.6.sql0000644000175000017500000001126707572171034027675 0ustar frankiefrankie-- Upgrade script -- -- @author vinod@kurup.com -- @created 2002-10-06 -- add mime_types insert into cr_mime_types(label, mime_type, file_extension) select 'Binary', 'application/octet-stream', 'bin' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/octet-stream'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft Word', 'application/msword', 'doc' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/msword'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft Excel', 'application/msexcel', 'xls' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/msexcel'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft PowerPoint', 'application/powerpoint', 'ppt' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/powerpoint'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft Project', 'application/msproject', 'mpp' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/msproject'); insert into cr_mime_types(label, mime_type, file_extension) select 'PostScript', 'application/postscript', 'ps' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/postscript'); insert into cr_mime_types(label, mime_type, file_extension) select 'Adobe Illustrator', 'application/x-illustrator', 'ai' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-illustrator'); insert into cr_mime_types(label, mime_type, file_extension) select 'Adobe PageMaker', 'application/x-pagemaker', 'p65' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-pagemaker'); insert into cr_mime_types(label, mime_type, file_extension) select 'Filemaker Pro', 'application/filemaker', 'fm' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/filemaker'); insert into cr_mime_types(label, mime_type, file_extension) select 'Image Pict', 'image/x-pict', 'pic' from dual where not exists (select 1 from cr_mime_types where mime_type = 'image/x-pict'); insert into cr_mime_types(label, mime_type, file_extension) select 'Photoshop', 'application/x-photoshop', 'psd' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-photoshop'); insert into cr_mime_types(label, mime_type, file_extension) select 'Acrobat', 'application/pdf', 'pdf' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/pdf'); insert into cr_mime_types(label, mime_type, file_extension) select 'Video Quicktime', 'video/quicktime', 'mov' from dual where not exists (select 1 from cr_mime_types where mime_type = 'video/quicktime'); insert into cr_mime_types(label, mime_type, file_extension) select 'Video MPEG', 'video/mpeg', 'mpg' from dual where not exists (select 1 from cr_mime_types where mime_type = 'video/mpeg'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio AIFF', 'audio/aiff', 'aif' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/aiff'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio Basic', 'audio/basic', 'au' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/basic'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio Voice', 'audio/voice', 'voc' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/voice'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio Wave', 'audio/wave', 'wav' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/wave'); insert into cr_mime_types(label, mime_type, file_extension) select 'Archive Zip', 'application/zip', 'zip' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/zip'); insert into cr_mime_types(label, mime_type, file_extension) select 'Archive Tar', 'application/z-tar', 'tar' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/z-tar'); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.6.4-4.6.5.sql0000644000175000017500000013723007661402012030172 0ustar frankiefrankie create or replace package content_extlink as function new ( --/** Create a new extlink, an item pointing to an off-site resource -- @author Karl Goldstein -- @param name The name for the new extlink, defaults to the name of the -- target item -- @param url The URL of the item -- @param label The text label or title of the item -- @param description A brief description of the item -- @param parent_id The parent folder for the extlink. This must actually be a folder -- and not a generic content item. -- @param extlink_id The id of the new extlink. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created extlink -- @see {acs_object.new}, {content_item.new}, {content_extlink.resolve} --*/ name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure delete ( --/** Deletes the extlink -- @author Karl Goldstein -- @param extlink_id The id of the extlink to delete -- @see {content_extlink.new}, {acs_object.delete} --*/ extlink_id in cr_extlinks.extlink_id%TYPE ); function is_extlink ( --/** Determines if the item is a extlink -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a extlink, 'f' otherwise -- @see {content_extlink.new}, {content_extlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return char; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ); end content_extlink; / show errors -- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.6.4-4.6.5.sql,v 1.2 2003/05/17 09:42:34 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_extlink as function new ( name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; v_label cr_extlinks.label%TYPE; v_name cr_items.name%TYPE; begin if label is null then v_label := url; else v_label := label; end if; if name is null then select acs_object_id_seq.nextval into v_extlink_id from dual; v_name := 'link' || v_extlink_id; else v_name := name; end if; v_extlink_id := content_item.new( item_id => content_extlink.new.extlink_id, name => v_name, content_type => 'content_extlink', creation_date => content_extlink.new.creation_date, creation_user => content_extlink.new.creation_user, creation_ip => content_extlink.new.creation_ip, parent_id => content_extlink.new.parent_id ); insert into cr_extlinks (extlink_id, url, label, description) values (v_extlink_id, content_extlink.new.url, v_label, content_extlink.new.description); return v_extlink_id; end new; procedure delete ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin delete from cr_extlinks where extlink_id = content_extlink.delete.extlink_id; content_item.delete(content_extlink.delete.extlink_id); end delete; function is_extlink ( item_id in cr_items.item_id%TYPE ) return char is v_extlink_p integer := 0; begin select count(1) into v_extlink_p from cr_extlinks where extlink_id = is_extlink.item_id; if v_extlink_p = 1 then return 't'; else return 'f'; end if; end is_extlink; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_label cr_extlinks.label%TYPE; v_description cr_extlinks.description%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder.is_folder(copy.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy.extlink_id; -- can't copy to the same folder if copy.target_folder_id ^= v_current_folder_id then select i.name, e.url, e.label, e.description into v_name, v_url, v_label, v_description from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy.extlink_id; if content_folder.is_registered(copy.target_folder_id, 'content_extlink') = 't' then v_extlink_id := content_extlink.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, description => v_description, url => v_url, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end if; end if; end if; end copy; end content_extlink; / show errors set serveroutput on size 1000000 format wrapped create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = 0 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob' ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = 0 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= 0 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= 0 then begin select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id ^= 0 and content_folder.is_folder(v_parent_id) = 'f' and content_item.is_valid_child(v_parent_id, content_item.new.content_type) = 't' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', context_id => v_parent_id ); if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type; exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type; if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure delete ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.delete.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.delete.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.delete.item_id or related_object_id = content_item.delete.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.delete.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.delete.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; dbms_output.put_line('Deleting symlinks...'); -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.delete(v_symlink_val.symlink_id); end loop; dbms_output.put_line('Unscheduling item...'); delete from cr_release_periods where item_id = content_item.delete.item_id; dbms_output.put_line('Deleting associated revisions...'); -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.delete.item_id; for v_revision_val in c_revision_cur loop content_revision.delete(v_revision_val.revision_id); end loop; dbms_output.put_line('Deleting associated item templates...'); -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.delete.item_id; dbms_output.put_line('Deleting item relationships...'); -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.delete(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting child relationships...'); for v_rel_val in c_child_cur loop acs_rel.delete(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting parent relationships...'); for v_rel_val in c_parent_cur loop acs_rel.delete(v_rel_val.rel_id); content_item.delete(v_rel_val.child_id); end loop; dbms_output.put_line('Deleting associated permissions...'); -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.delete.item_id; dbms_output.put_line('Deleting keyword associations...'); -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.delete.item_id; dbms_output.put_line('Deleting associated comments...'); -- 7) delete associated comments journal_entry.delete_for_object( content_item.delete.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; dbms_output.put_line('Deleting content item...'); acs_object.delete(content_item.delete.item_id); end delete; procedure rename ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where name = rename.name and parent_id = (select parent_id from cr_items where item_id = rename.item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set name = rename.name where item_id = rename.item_id; else close exists_cur; if exists_id <> rename.item_id then raise_application_error(-20000, 'An item with the name ' || rename.name || ' already exists in this directory.'); end if; end if; end rename; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := 0; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := 0; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id where item_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; -- can't copy to the same folder if copy2.target_folder_id ^= v_current_folder_id then select content_type, name, locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.delete( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; while v_parent_folder_p = 'f' loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = get_parent_folder.item_id; end loop; return v_folder_id; exception when NO_DATA_FOUND then return null; end get_parent_folder; end content_item; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.7d6-5.0d1.sql0000644000175000017500000053642007741031647030357 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_extlink as function new ( name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; v_label cr_extlinks.label%TYPE; v_name cr_items.name%TYPE; begin if label is null then v_label := url; else v_label := label; end if; if name is null then select acs_object_id_seq.nextval into v_extlink_id from dual; v_name := 'link' || v_extlink_id; else v_name := name; end if; v_extlink_id := content_item.new( item_id => content_extlink.new.extlink_id, name => v_name, content_type => 'content_extlink', creation_date => content_extlink.new.creation_date, creation_user => content_extlink.new.creation_user, creation_ip => content_extlink.new.creation_ip, parent_id => content_extlink.new.parent_id ); insert into cr_extlinks (extlink_id, url, label, description) values (v_extlink_id, content_extlink.new.url, v_label, content_extlink.new.description); return v_extlink_id; end new; procedure del ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin delete from cr_extlinks where extlink_id = content_extlink.del.extlink_id; content_item.del(content_extlink.del.extlink_id); end del; function is_extlink ( item_id in cr_items.item_id%TYPE ) return char is v_extlink_p integer := 0; begin select count(1) into v_extlink_p from cr_extlinks where extlink_id = is_extlink.item_id; if v_extlink_p = 1 then return 't'; else return 'f'; end if; end is_extlink; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_label cr_extlinks.label%TYPE; v_description cr_extlinks.description%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder.is_folder(copy.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy.extlink_id; -- can't copy to the same folder if copy.target_folder_id ^= v_current_folder_id then select i.name, e.url, e.label, e.description into v_name, v_url, v_label, v_description from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy.extlink_id; if content_folder.is_registered(copy.target_folder_id, 'content_extlink') = 't' then v_extlink_id := content_extlink.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, description => v_description, url => v_url, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end if; end if; end if; end copy; end content_extlink; / show errors -- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = 0 means that this is a mount point if parent_id ^= 0 and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id ); insert into cr_folders ( folder_id, label, description ) values ( v_folder_id, label, description ); -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE ) is v_count integer; v_parent_id integer; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure rename ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.rename(folder_id, name); end if; if label is not null and description is not null then update cr_folders set label = label, description = description where folder_id = folder_id; elsif label is not null and description is null then update cr_folders set label = label where folder_id = folder_id; end if; end rename; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy.folder_id; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder or target_folder_id = folder_id or v_current_folder_id = target_folder_id then v_valid_folders_p := 0; end if; if v_valid_folders_p = 2 then if is_sub_folder(folder_id, target_folder_id) ^= 't' then -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end if; end if; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := 0; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; if v_parent_id ^= 0 then v_sub_folder_p := 't'; end if; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors -- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Hiro Iwashima (iwashima@mit.edu) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package image as --/** -- Creates a new image -- Binary file stored in file-system --*/ function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file' ) return cr_items.item_id%TYPE; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null ) return cr_revisions.revision_id%TYPE; --/** -- Deletes a single revision of image -- Schedules binary file for deletion. -- File delete sweep checks to see if no other images are using binary prior to deleting --*/ procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ); --/** -- Deletes a image and all revisions -- Schedules binary files for deletion. -- -- Be careful, cannot be undone (easily) --*/ procedure del ( item_id in cr_items.item_id%TYPE ); end image; / show errors; create or replace package body image as function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file' ) return cr_items.item_id%TYPE is v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_item_id := content_item.new ( name => name, item_id => item_id, parent_id => parent_id, relation_tag => relation_tag, content_type => content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, locale => locale, context_id => context_id, storage_type => storage_type ); v_revision_id := content_revision.new ( title => title, description => description, item_id => v_item_id, revision_id => revision_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => sysdate, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_item_id; end new; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => title, description => description, item_id => item_id, revision_id => revision_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_revision_id; end new_revision; procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ) is v_content cr_files_to_delete.path%TYPE default null; begin content_revision.del ( revision_id => revision_id ); end delete_revision; procedure del ( item_id in cr_items.item_id%TYPE ) is cursor image_revision_cur is select revision_id from cr_revisions where item_id = image.del.item_id order by revision_id asc; -- order by used in cursur so latest revision will be deleted last -- save resetting latest revision multiple times during delete process begin for v_revision_val in image_revision_cur loop image.delete_revision ( revision_id => v_revision_val.revision_id ); end loop; content_item.del ( item_id => item_id ); end del; end image; / show errors; -- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html set serveroutput on size 1000000 format wrapped create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = 0 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob' ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = 0 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= 0 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= 0 then begin -- Figure out the relation_tag to use if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type, v_rel_tag) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels -- We checked above before creating the object that it is a valid rel if v_parent_id ^= 0 and content_folder.is_folder(v_parent_id) = 'f' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', context_id => v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure del ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.del.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.del.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.del.item_id or related_object_id = content_item.del.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.del.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.del.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; dbms_output.put_line('Deleting symlinks...'); -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.del(v_symlink_val.symlink_id); end loop; dbms_output.put_line('Unscheduling item...'); delete from cr_release_periods where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated revisions...'); -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.del.item_id; for v_revision_val in c_revision_cur loop content_revision.del(v_revision_val.revision_id); end loop; dbms_output.put_line('Deleting associated item templates...'); -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting item relationships...'); -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting child relationships...'); for v_rel_val in c_child_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting parent relationships...'); for v_rel_val in c_parent_cur loop acs_rel.del(v_rel_val.rel_id); content_item.del(v_rel_val.child_id); end loop; dbms_output.put_line('Deleting associated permissions...'); -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.del.item_id; dbms_output.put_line('Deleting keyword associations...'); -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated comments...'); -- 7) delete associated comments journal_entry.delete_for_object( content_item.del.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; dbms_output.put_line('Deleting content item...'); acs_object.del(content_item.del.item_id); end del; procedure rename ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where name = name and parent_id = (select parent_id from cr_items where item_id = item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set name = name where item_id = item_id; else close exists_cur; if exists_id <> item_id then raise_application_error(-20000, 'An item with the name ' || name || ' already exists in this directory.'); end if; end if; end rename; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := 0; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := 0; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id where item_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; -- can't copy to the same folder if copy2.target_folder_id ^= v_current_folder_id then select content_type, name, locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.del( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; while v_parent_folder_p = 'f' loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = get_parent_folder.item_id; end loop; return v_folder_id; exception when NO_DATA_FOUND then return null; end get_parent_folder; end content_item; / show errors -- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Stanislav Freidin (sfreidin@arsdigita.com) -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_keyword as function get_heading ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_heading varchar2(4000); begin select heading into v_heading from cr_keywords where keyword_id = content_keyword.get_heading.keyword_id; return v_heading; end get_heading; function get_description ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_description varchar2(4000); begin select description into v_description from cr_keywords where keyword_id = content_keyword.get_description.keyword_id; return v_description; end get_description; procedure set_heading ( keyword_id in cr_keywords.keyword_id%TYPE, heading in cr_keywords.heading%TYPE ) is begin update cr_keywords set heading = set_heading.heading where keyword_id = set_heading.keyword_id; end set_heading; procedure set_description ( keyword_id in cr_keywords.keyword_id%TYPE, description in cr_keywords.description%TYPE ) is begin update cr_keywords set description = set_description.description where keyword_id = set_description.keyword_id; end set_description; function is_leaf ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_leaf varchar2(1); cursor c_leaf_cur is select 'f' from cr_keywords k where k.parent_id = is_leaf.keyword_id; begin open c_leaf_cur; fetch c_leaf_cur into v_leaf; if c_leaf_cur%NOTFOUND then v_leaf := 't'; end if; close c_leaf_cur; return v_leaf; end is_leaf; function new ( heading in cr_keywords.heading%TYPE, description in cr_keywords.description%TYPE default null, parent_id in cr_keywords.parent_id%TYPE default null, keyword_id in cr_keywords.keyword_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_object_types.object_type%TYPE default 'content_keyword' ) return cr_keywords.keyword_id%TYPE is v_id integer; begin v_id := acs_object.new (object_id => keyword_id, context_id => parent_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip); insert into cr_keywords (heading, description, keyword_id, parent_id) values (heading, description, v_id, parent_id); return v_id; end new; procedure del ( keyword_id in cr_keywords.keyword_id%TYPE ) is v_item_id integer; cursor c_rel_cur is select item_id from cr_item_keyword_map where keyword_id = content_keyword.del.keyword_id; begin open c_rel_cur; loop fetch c_rel_cur into v_item_id; exit when c_rel_cur%NOTFOUND; item_unassign(v_item_id, content_keyword.del.keyword_id); end loop; close c_rel_cur; acs_object.del(keyword_id); end del; procedure item_assign ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_dummy integer; begin -- Do nothing if the keyword is assigned already select decode(count(*),0,0,1) into v_dummy from dual where exists (select 1 from cr_item_keyword_map where item_id=item_assign.item_id and keyword_id=item_assign.keyword_id); if v_dummy > 0 then -- previous assignment exists return; end if; insert into cr_item_keyword_map ( item_id, keyword_id ) values ( item_id, keyword_id ); end item_assign; procedure item_unassign ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE ) is begin delete from cr_item_keyword_map where item_id = item_unassign.item_id and keyword_id = item_unassign.keyword_id; end item_unassign; function is_assigned ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, recurse in varchar2 default 'none' ) return varchar2 is v_ret varchar2(1); begin -- Look for an exact match if recurse = 'none' then declare begin select 't' into v_ret from cr_item_keyword_map where item_id = is_assigned.item_id and keyword_id = is_assigned.keyword_id; return 't'; exception when no_data_found then return 'f'; end; end if; -- Look from specific to general if recurse = 'up' then begin select 't' into v_ret from dual where exists (select 1 from (select keyword_id from cr_keywords connect by parent_id = prior keyword_id start with keyword_id = is_assigned.keyword_id ) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned.item_id); return 't'; exception when no_data_found then return 'f'; end; end if; if recurse = 'down' then begin select 't' into v_ret from dual where exists ( select 1 from (select keyword_id from cr_keywords connect by prior parent_id = keyword_id start with keyword_id = is_assigned.keyword_id ) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned.item_id); return 't'; exception when no_data_found then return 'f'; end; end if; -- Tried none, up and down - must be an invalid parameter raise_application_error (-20000, 'The recurse parameter to ' || 'content_keyword.is_assigned should be ''none'', ''up'' or ''down''.'); end is_assigned; function get_path ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_path varchar2(4000) := ''; v_is_found varchar2(1) := 'f'; cursor c_keyword_cur is select heading from ( select heading, level as tree_level from cr_keywords connect by prior parent_id = keyword_id start with keyword_id = get_path.keyword_id ) order by tree_level desc; v_heading cr_keywords.heading%TYPE; begin open c_keyword_cur; loop fetch c_keyword_cur into v_heading; exit when c_keyword_cur%NOTFOUND; v_is_found := 't'; v_path := v_path || '/' || v_heading; end loop; close c_keyword_cur; if v_is_found = 'f' then return null; else return v_path; end if; end get_path; end content_keyword; / show errors -- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_revision as function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; v_content_type acs_object_types.object_type%TYPE; begin v_content_type := content_item.get_content_type(item_id); v_revision_id := acs_object.new( object_id => revision_id, object_type => v_content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, context_id => item_id ); insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, content, item_id, filename ) values ( v_revision_id, title, description, mime_type, publish_date, nls_language, data, item_id, filename ); return v_revision_id; end new; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; blob_loc cr_revisions.content%TYPE; begin blob_loc := empty_blob(); v_revision_id := content_revision.new( title => title, description => description, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => blob_loc, item_id => item_id, revision_id => revision_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); select content into blob_loc from cr_revisions where revision_id = v_revision_id for update; string_to_blob(text, blob_loc); return v_revision_id; end new; procedure copy_attributes ( content_type in acs_object_types.object_type%TYPE, revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE ) is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = copy_attributes.content_type; cols varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; end loop; execute immediate 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) ( select ' || copy_id || cols || ' from ' || v_table_name || ' where ' || v_id_column || ' = ' || revision_id || ')'; end copy_attributes; function copy ( revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE is v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; -- get the content_type and supertypes cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = ( select object_type from acs_objects where object_id = copy.revision_id ) order by level desc; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy.revision_id; else v_target_item_id := target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy_id is null then select acs_object_id_seq.nextval into v_copy_id from dual; else v_copy_id := copy_id; end if; -- create the basic object insert into acs_objects ( object_id, object_type, context_id, security_inherit_p, creation_user, creation_date, creation_ip, last_modified, modifying_user, modifying_ip ) ( select v_copy_id, object_type, context_id, security_inherit_p, copy.creation_user, sysdate, copy.creation_ip, sysdate, copy.creation_user, copy.creation_ip from acs_objects where object_id = copy.revision_id ); -- create the basic revision (using v_target_item_id) insert into cr_revisions ( revision_id, title, description, publish_date, mime_type, nls_language, content, item_id ) ( select v_copy_id, title, description, publish_date, mime_type, nls_language, content, v_target_item_id from cr_revisions where revision_id = copy.revision_id ); -- iterate over the ancestor types and copy attributes for type_rec in type_cur loop copy_attributes(type_rec.object_type, copy.revision_id, v_copy_id); end loop; return v_copy_id; end copy; procedure del ( revision_id in cr_revisions.revision_id%TYPE ) is v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = content_revision.del.revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = content_revision.del.revision_id then declare cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> content_revision.del.revision_id order by o.creation_date desc; begin open c_revision_cur; fetch c_revision_cur into v_latest_revision; if c_revision_cur%NOTFOUND then v_latest_revision := null; end if; close c_revision_cur; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end; end if; -- Clear live revision if v_live_revision = content_revision.del.revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = content_revision.del.revision_id or new_revision = content_revision.del.revision_id; -- Delete the revision acs_object.del(revision_id); end del; function get_number ( revision_id in cr_revisions.revision_id%TYPE ) return number is cursor rev_cur is select revision_id from cr_revisions r, acs_objects o where item_id = (select item_id from cr_revisions where revision_id = get_number.revision_id) and o.object_id = r.revision_id order by o.creation_date; v_number integer; v_revision cr_revisions.revision_id%TYPE; begin open rev_cur; loop fetch rev_cur into v_revision; if v_revision = get_number.revision_id then v_number := rev_cur%ROWCOUNT; exit; end if; end loop; close rev_cur; return v_number; end get_number; function revision_name( revision_id IN cr_revisions.revision_id%TYPE ) return varchar2 is v_text varchar2(500); v_sql varchar2(500); begin v_sql := 'select ''Revision '' || content_revision.get_number(r.revision_id) || '' of '' || (select count(*) from cr_revisions where item_id = r.item_id) || '' for item: '' || content_item.get_title(item_id) from cr_revisions r where r.revision_id = ' || revision_name.revision_id; execute immediate v_sql into v_text; return v_text; end revision_name; procedure index_attributes( revision_id IN cr_revisions.revision_id%TYPE ) is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_revision_attributes ( revision_id, attributes ) values ( revision_id, empty_clob() ) returning attributes into clob_loc; v_revision_id := write_xml(revision_id, clob_loc); end index_attributes; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin select doc into clob_loc from cr_xml_docs where doc_id = import_xml.doc_id; v_revision_id := read_xml(item_id, revision_id, clob_loc); return v_revision_id; end import_xml; function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE is clob_loc clob; v_doc_id cr_xml_docs.doc_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_xml_docs (doc_id, doc) values (cr_xml_doc_seq.nextval, empty_clob()) returning doc_id, doc into v_doc_id, clob_loc; v_revision_id := write_xml(revision_id, clob_loc); return v_doc_id; end export_xml; procedure to_html ( revision_id IN cr_revisions.revision_id%TYPE ) is tmp_clob clob; blob_loc blob; begin ctx_doc.filter('cr_doc_filter_index', revision_id, tmp_clob, false); select content into blob_loc from cr_revisions where revision_id = to_html.revision_id for update; clob_to_blob(tmp_clob, blob_loc); dbms_lob.freetemporary(tmp_clob); end to_html; function is_live ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where live_revision = is_live.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_live; function is_latest ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where latest_revision = is_latest.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_latest; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ) is b blob; c clob; begin insert into cr_content_text ( revision_id, content ) values ( revision_id, empty_clob() ) returning content into c; select content into b from cr_revisions where revision_id = to_temporary_clob.revision_id; blob_to_clob(b, c); end to_temporary_clob; -- revision_id is the revision with the content that is to be copied procedure content_copy ( revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ) is v_item_id cr_items.item_id%TYPE; v_content_length integer; v_revision_id_dest cr_revisions.revision_id%TYPE; v_filename cr_revisions.filename%TYPE; v_content blob; begin select content_length, item_id into v_content_length, v_item_id from cr_revisions where revision_id = content_copy.revision_id; -- get the destination revision if content_copy.revision_id_dest is null then select latest_revision into v_revision_id_dest from cr_items where item_id = v_item_id; else v_revision_id_dest := content_copy.revision_id_dest; end if; -- only copy the content if the source content is not null if v_content_length is not null and v_content_length > 0 then /* The internal LOB types - BLOB, CLOB, and NCLOB - use copy semantics, as opposed to the reference semantics which apply to BFILEs. When a BLOB, CLOB, or NCLOB is copied from one row to another row in the same table or in a different table, the actual LOB value is copied, not just the LOB locator. */ select filename, content_length into v_filename, v_content_length from cr_revisions where revision_id = content_copy.revision_id; -- need to update the file name after the copy, -- if this content item is in CR file storage. The file name is based -- off of the item_id and revision_id and it will be invalid for the -- copied revision. update cr_revisions set content = (select content from cr_revisions where revision_id = content_copy.revision_id), filename = v_filename, content_length = v_content_length where revision_id = v_revision_id_dest; end if; end content_copy; end content_revision; / show errors -- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_symlink as function new ( name in cr_items.name%TYPE default null, label in cr_symlinks.label%TYPE default null, target_id in cr_items.item_id%TYPE, parent_id in cr_items.parent_id%TYPE, symlink_id in cr_symlinks.symlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_symlinks.symlink_id%TYPE is v_symlink_id cr_symlinks.symlink_id%TYPE; v_name cr_items.name%TYPE; v_label cr_symlinks.label%TYPE; begin -- SOME CHECKS -- -- 1) check that the target is now a symlink if content_symlink.is_symlink( target_id ) = 't' then raise_application_error(-20000, 'Cannot create a symlink to a symlink ' || target_id); end if; -- 2) check that the parent is a folder if content_folder.is_folder(parent_id) = 'f' then raise_application_error(-20000, 'The parent is not a folder'); end if; -- 3) check that parent folder supports symlinks if content_folder.is_registered(parent_id,'content_symlink') = 'f' then raise_application_error(-20000, 'This folder does not allow symlinks to be created'); end if; -- 4) check that the content folder supports the target item's content type if content_folder.is_registered( parent_id,content_item.get_content_type(target_id)) = 'f' then raise_application_error(-20000, 'This folder does not allow symlinks to items of type ' || content_item.get_content_type(target_id) || ' to be created'); end if; -- PASSED ALL CHECKS -- -- Select default name if the name is null begin if name is null then select 'symlink_to_' || name into v_name from cr_items where item_id = target_id; else v_name := name; end if; exception when no_data_found then v_name := null; end; -- Select default label if the label is null if content_symlink.new.label is null then v_label := 'Symlink to ' || v_name; else v_label := content_symlink.new.label; end if; v_symlink_id := content_item.new( item_id => content_symlink.new.symlink_id, name => v_name, content_type => 'content_symlink', creation_date => content_symlink.new.creation_date, creation_user => content_symlink.new.creation_user, creation_ip => content_symlink.new.creation_ip, parent_id => content_symlink.new.parent_id ); insert into cr_symlinks (symlink_id, target_id, label) values (v_symlink_id, content_symlink.new.target_id, v_label); return v_symlink_id; end new; procedure del ( symlink_id in cr_symlinks.symlink_id%TYPE ) is begin delete from cr_symlinks where symlink_id = content_symlink.del.symlink_id; content_item.del(content_symlink.del.symlink_id); end del; function is_symlink ( item_id in cr_items.item_id%TYPE ) return char is v_symlink_p integer := 0; begin select count(*) into v_symlink_p from cr_symlinks where symlink_id = is_symlink.item_id; if v_symlink_p = 1 then return 't'; else return 'f'; end if; end is_symlink; procedure copy ( symlink_id in cr_symlinks.symlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_target_id cr_items.item_id%TYPE; v_label cr_symlinks.label%TYPE; v_symlink_id cr_symlinks.symlink_id%TYPE; begin if content_folder.is_folder(copy.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy.symlink_id; -- can't copy to the same folder if copy.target_folder_id ^= v_current_folder_id then select i.name, content_symlink.resolve(i.item_id), s.label into v_name, v_target_id, v_label from cr_symlinks s, cr_items i where s.symlink_id = i.item_id and s.symlink_id = copy.symlink_id; if content_folder.is_registered(copy.target_folder_id, 'content_symlink') = 't' then if content_folder.is_registered(copy.target_folder_id, content_item.get_content_type(resolve(copy.symlink_id))) = 't' then v_symlink_id := content_symlink.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, target_id => v_target_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end if; end if; end if; end if; end copy; function resolve ( item_id in cr_items.item_id%TYPE ) return cr_items.item_id%TYPE is v_target_id cr_items.item_id%TYPE; begin select target_id into v_target_id from cr_symlinks where symlink_id = resolve.item_id; return v_target_id; exception when no_data_found then return resolve.item_id; end resolve; function resolve_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_item.get_content_type( target_id ) into v_content_type from cr_symlinks where symlink_id = resolve_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end resolve_content_type; end content_symlink; / show errors -- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: upgrade-4.7d6-5.0d1.sql,v 1.1 2003/10/08 15:56:23 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_template as function get_root_folder return cr_folders.folder_id%TYPE is begin return c_root_folder_id; end get_root_folder; function new ( name in cr_items.name%TYPE, text in varchar2 default null, parent_id in cr_items.parent_id%TYPE default null, is_live in char default 't', template_id in cr_templates.template_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- make sure we're allowed to create a template in this folder if content_folder.is_folder(parent_id) = 't' and content_folder.is_registered(parent_id,'content_template') = 'f' then raise_application_error(-20000, 'This folder does not allow templates to be created'); else v_template_id := content_item.new ( item_id => content_template.new.template_id, name => content_template.new.name, text => content_template.new.text, parent_id => v_parent_id, content_type => 'content_template', is_live => content_template.new.is_live, creation_date => content_template.new.creation_date, creation_user => content_template.new.creation_user, creation_ip => content_template.new.creation_ip ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end new; -- delete all template relations procedure del ( template_id in cr_templates.template_id%TYPE ) is begin delete from cr_type_template_map where template_id = content_template.del.template_id; delete from cr_item_template_map where template_id = content_template.del.template_id; delete from cr_templates where template_id = content_template.del.template_id; content_item.del(content_template.del.template_id); end del; function is_template ( template_id in cr_templates.template_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_templates where template_id = is_template.template_id; return v_ret; exception when no_data_found then return 'f'; end is_template; function get_path ( template_id in cr_templates.template_id%TYPE, root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id ) return varchar2 is begin return content_item.get_path(template_id, root_folder_id); end get_path; end content_template; / show errors create or replace package content_type AUTHID CURRENT_USER as --/** This package is used to manipulate content types and attributes -- --*/ procedure create_type ( --/** Create a new content type. Automatically create the attribute table -- for the type if the table does not already exist. -- @author Karl Goldstein -- @param content_type The name of the new type -- @param supertype The supertype, defaults to content_revision -- @param pretty_name Pretty name for the type, singular -- @param pretty_plural Pretty name for the type, plural -- @param table_name The name for the attribute table, defaults to -- the name of the supertype -- @param id_column The primary key for the table, defaults to 'XXX' -- @param name_method As in acs_object_type.create_type -- @see {acs_object_type.create_type} --*/ content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ); procedure drop_type ( --/** First drops all attributes related to a specific type, then drops type -- the given type. -- @author Simon Huynh -- @param content_type The content type to be dropped -- @param drop_children_p If 't', then the sub-types -- of the given content type and their associated tables -- are also dropped. --*/ content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f' ); function create_attribute ( --/** Create a new attribute for the specified type. Automatically create -- the column for the attribute if the column does not already exist. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to create -- @param pretty_name Pretty name for the new attribute, singular -- @param pretty_plural Pretty name for the new attribute, plural -- @param default_value The default value for the attribute, defaults to null -- @return The id of the newly created attribute -- @see {acs_object_type.create_attribute}, {content_type.create_type} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE; procedure drop_attribute ( --/** Drop an existing attribute. If you are using CMS, make sure to -- call cm_form_widget.unregister_attribute_widget before calling -- this function. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to drop -- @param drop_column If 't', will also alter the table and remove -- the column where the attribute is stored. The default is 'f' -- (leaves the table untouched). -- @see {acs_object.drop_attribute}, {content_type.create_attribute}, -- {cm_form_widget.unregister_attribute_widget} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ); procedure register_template ( --/** Register a template for the content type. This template may be used -- to render all items of that type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be registered -- @param template_id The ID of the template to register -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @param is_default If 't', this template becomes the default template for -- the type, default is 'f'. -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.set_default_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ); procedure set_default_template ( --/** Make the registered template a default template. The default template -- will be used to render all items of the type for which no individual -- template is registered. -- @author Karl Goldstein -- @param content_type The type for which the template is to be made default -- @param template_id The ID of the template to make default -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ); function get_template ( --/** Retrieve the appropriate template for rendering items of the specified type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be retrieved -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @return The ID of the template to use -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.set_default_template} --*/ content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; procedure unregister_template ( --/** Unregister a template. If the unregistered template was the default template, -- the content_type can no longer be rendered in the use_context, -- @author Karl Goldstein -- @param content_type The type for which the template is to be unregistered -- @param template_id The ID of the template to unregister -- @param use_context The context in which the template is to be unregistered -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.set_default_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ); procedure refresh_view ( --/** Create a view for the type which joins all attributes of the type, -- including the inherited attributes. The view is named -- "X" -- Called by create_attribute and create_type. -- @author Karl Goldstein -- @param content_type The type for which the view is to be created. -- @see {content_type.create_type} --*/ content_type in cr_type_template_map.content_type%TYPE ); procedure register_relation_type ( --/** Register a relationship between a content type and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate any relationship between an item and another -- object. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.unregister_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_relation_type ( --/** Unregister a relationship between a content type and another object -- type. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ); procedure register_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of parent-child -- relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param parent_type The type of the parent item. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ); procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char; procedure rotate_template ( --/** Sets the default template for a content type and registers all the -- previously existing items of that content type to the original -- template -- @author Michael Pih -- @param template_id The template that will become the default -- registered template for the specified content type and use context -- @param v_content_type The content type -- @param use_context The context in which the template will be used --*/ template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ); end content_type; / show errors; create or replace package content_item as --/** --Content items store the overview of the content published on a --website. The actual content is stored in content revisions. It is --implemented this way so that there can be mulitple versions of the --actual content while the main idea remains constant. For example: If --there is a review for the movie "Terminator," there will exist a --content item by the name "terminator" with all the right parameters --(supertype, parent, etc), there will also exist at least one content --revision pointing to this item with the actual review content. --@see {content_revision}, {content_folder} --*/ c_root_folder_id constant integer := -100; function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content item. If the data, title or text -- parameters are specified, also creates a revision for the item. -- @author Karl Goldstein -- @param name The name for the item, must be URL-encoded. -- If an item with this name already exists under the specified -- parent item, an error is thrown -- @param parent_id The parent of this item, defaults to null -- @param item_id The id of the new item. A new id will be allocated if this -- parameter is null -- @param locale The locale for this item, for use with Intermedia search -- @param item_subtype The type of the new item, defaults to 'content_item' -- This parameter is used to support inheritance, so that -- subclasses of content_item can call this function -- to initialize the parent class -- @param content_type The content type for the item, defaults to -- 'content_revision'. Only objects of this type -- may be used as revisions for the item -- @param title The user-readable title for the item, defaults to the item's -- name -- @param description A short description for the item (4000 characters maximum) -- @param mime_type The file type of the item, defaults to 'text/plain' -- @param nls_language The language for the item, used for Intermedia search -- @param text The text content of the new revision, 4000 charcters maximum. -- Cannot be specified simultaneously with the data -- parameter -- @param data The blob content of the new revision. Cannot be specified -- simultaneously with the text parameter -- @param relation_tag If a parent-child relationship is registered -- for these content types, use this tag to -- describe the parent-child relationship. Defaults -- to 'parent content type'-'child content type' -- @param is_live If 't', the new revision will become live -- @param context_id Security context id, as in acs_object.new -- If null, defaults to parent_id, and copies permissions -- from the parent into the current item -- @param storage_type in ('lob','file'). Indicates how content is to be stored. -- 'file' content is stored externally in the file system. -- @param others As in acs_object.new -- @return The id of the newly created item -- @see {acs_object.new} --*/ name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob' ) return cr_items.item_id%TYPE; function is_published ( --/** Determins whether an item is published or not. -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is published, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE ) return char; function is_publishable ( --/** Determines if an item is publishable. Publishable items must -- meet the following criteria: -- 1) for each child type, the item has n children, min_n < n < max_n -- 2) for each relation type, the item has n relations, min_n < n < max_n -- 3) any 'publishing_wf' workflows are finished -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is publishable in it's present state, -- Otherwise, returns 'f' --*/ item_id in cr_items.item_id%TYPE ) return char; function is_valid_child ( --/** Determines if an item would be a valid child of another item by -- checking if the parent allows children of the would-be child's -- content type and if the parent already has n_max children of -- that content type. -- @author Michael Pih -- @param item_id The item ID of the potential parent -- @param content_type The content type of the potential child item -- @return 't' if the item would be a valid child, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char; procedure del ( --/** Deletes the specified content item, along with any revisions, symlinks, -- workflows, associated templates, associated keywords, -- child and item relationships for the item. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param item_id The id of the item to delete -- @see {acs_object.delete} --*/ item_id in cr_items.item_id%TYPE ); procedure rename ( --/** Renames the item. If an item with the specified name already exists -- under this item's parent, an error is thrown -- @author Karl Goldstein -- @param item_id The id of the item to rename -- @param name The new name for the item, must be URL-encoded -- @see {content_item.new} --*/ item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ); function get_id ( --/** Takes in a path, such as "/tv/programs/star_trek/episode_203" -- and returns the id of the item with this path. Note: URLs are abstract (no -- extensions are allowed in content item names and extensions are stripped when -- looking up content items) -- @author Karl Goldstein -- @param item_path The path to be resolved -- @param root_folder_id Starts path resolution from this folder. Defaults to -- the root of the sitemap -- @param resolve_index Boolean flag indicating whether to return the -- id of the index page for folders (if one -- exists). Defaults to 'f'. -- @return The id of the item with the given path, or null if no such item exists -- @see {content_item.get_path} --*/ item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE; function get_path ( --/** Retrieves the full path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Karl Goldstein -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The path to the item -- @see {content_item.get_id}, {content_item.write_to_file} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2; function get_virtual_path ( --/** Retrieves the virtual path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Michael Pih -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The virtual path to the item -- @see {content_item.get_id}, {content_item.write_to_file}, {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2; procedure write_to_file ( --/** Writes the content of the live revision of this item to a file, -- creating all the neccessary directories in the process -- @author Karl Goldstein -- @param item_id The item to be written to a file -- @param root_path The path in the filesystem to which the root of the -- sitemap corresponds -- @see {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_path in varchar2 ); procedure register_template ( --/** Registers a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be registered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.unregister_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ); procedure unregister_template ( --/** Unregisters a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.register_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ); function get_template ( --/** Retrieves the template which should be used to render this item. If no template -- is registered to specifically render the item in the given context, the -- default template for the item's type is returned. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param use_context The context in the item is to be rendered, such -- as 'admin' or 'public' -- @return The id of the registered template, or null if no template could be -- found -- @see {content_type.register_template}, {content_item.register_template}, --*/ item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; function get_live_revision ( --/** Retrieves the id of the live revision for the item -- @param item_id The item for which the live revision is to be retrieved -- @return The id of the live revision for this item, or null if no live revision -- exists -- @see {content_item.set_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; procedure set_live_revision ( --/** Make the specified revision the live revision for the item -- @author Karl Goldstein -- @param revision_id The id of the revision which is to become live -- for its corresponding item -- @see {content_item.get_live_revision} --*/ revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ); procedure unset_live_revision ( --/** Set the live revision to null for the item -- @author Michael Pih -- @param item_id The id of the item for which to unset the live revision -- @see {content_item.set_live_revision} item_id in cr_items.item_id%TYPE ); procedure set_release_period ( --/** Sets the release period for the item. This information may be -- used by applications to update the publishing status of items -- at periodic intervals. -- @author Karl Goldstein -- @param item_id The id the item. -- @param start_when The time and date when the item should be released. -- @param end_when The time and date when the item should be expired. --*/ item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ); function get_revision_count ( --/** Return the total count of revisions for this item -- @author Karl Goldstein -- @param item_id The id the item -- @return The number of revisions for this item -- @see {content_revision.new} --*/ item_id in cr_items.item_id%TYPE ) return number; -- Return the object type of this item function get_content_type ( --/** Retrieve the content type of this item. Only objects of this type may be -- used as revisions for the item. -- @author Karl Goldstein -- @param item_id The item for which the content type is to be retrieved -- @return The content type of the item --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; function get_context ( --/** Retrieve the parent of the given item -- @author Karl Goldstein -- @param item_id The item for which the parent is to be retrieved -- @return The id of the parent for this item --*/ item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE; procedure move ( --/** Move the specified item to a different folder. If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein -- @param item_id The item to be moved -- @param target_folder_id The new folder for the item -- @see {content_item.new}, {content_folder.new}, {content_item.copy} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ); procedure copy ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ); function copy2 ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @return The item ID of the new copy. -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_items.item_id%TYPE; -- get the latest revision for an item function get_latest_revision ( --/** Retrieves the id of the latest revision for the item (as opposed to the live -- revision) -- @author Karl Goldstein -- @param item_id The item for which the latest revision is to be retrieved -- @return The id of the latest revision for this item, or null if no revisions -- exist -- @see {content_item.get_live_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_best_revision ( --/** Retrieves the id of the live revision for the item if one exists, -- otherwise retrieves the id of the latest revision if one exists. -- revision) -- @author Michael Pih -- @param item_id The item for which the revision is to be retrieved -- @return The id of the live or latest revision for this item, -- or null if no revisions exist -- @see {content_item.get_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_title ( --/** Retrieves the title for the item, using either the latest or the live revision. -- If the specified item is in fact a folder, return the folder's label. -- In addition, this function will automatically resolve symlinks. -- @author Karl Goldstein -- @param item_id The item for which the title is to be retrieved -- @param is_live If 't', use the live revision to get the title. Otherwise, -- use the latest revision. The default is 'f' -- @return The title of the item -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, -- {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE; function get_publish_date ( --/** Retrieves the publish date for the item -- @author Karl Goldstein -- @param item_id The item for which the publish date is to be retrieved -- @param is_live If 't', use the live revision for the item. Otherwise, use -- the latest revision. The default is 'f' -- @return The publish date for the item, or null if the item has no revisions -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE; function is_subclass ( --/** Determines if one type is a subclass of another. A class is always a subclass of -- itself. -- @author Karl Goldstein -- @param object_type The child class -- @param supertype The superclass -- @return 't' if the child class is a subclass of the superclass, 'f' otherwise -- @see {acs_object_type.create_type} --*/ object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char; function relate ( --/** Relates two content items -- @author Karl Goldstein -- @param item_id The item id -- @param object_id The item id of the related object -- @param relation_tag A tag to help identify the relation type, -- defaults to 'generic' -- @param order_n The order of this object among other objects -- of the same relation type, defaults to null. -- @param relation_type The object type of the relation, defaults to -- 'cr_item_rel' --*/ item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE; procedure unrelate ( --/** Delete the item relationship between two items -- @author Michael Pih -- @param rel_id The relationship id -- @see {content_item.relate} --*/ rel_id in cr_item_rels.rel_id%TYPE ); function is_index_page ( --/** Determine if the item is an index page for the specified folder. -- The item is an index page for the folder if it exists in the -- folder and its item name is "index". -- @author Karl Goldstein -- @param item_id The item id -- @param folder_id The folder id -- @return 't' if the item is an index page for the specified -- folder, 'f' otherwise -- @see {content_folder.get_index_page} --*/ item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2; function get_parent_folder ( --/** Get the parent folder. -- @author Michael Pih -- @param item_id The item id -- @return the folder_id of the parent folder, null otherwise --*/ item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE; end content_item; / show errors create or replace package content_revision as function new ( --/** Create a new revision for an item. -- @author Karl Goldstein -- @param title The revised title for the item -- @param description A short description of this revision, 4000 characters maximum -- @param publish_date Publication date. -- @param mime_type The revised mime type of the item, defaults to 'text/plain' -- @param nls_language The revised language of the item, for use with Intermedia searching -- @param data The blob which contains the body of the revision -- @param item_id The id of the item being revised -- @param revision_id The id of the new revision. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created revision -- @see {acs_object.new}, {content_item.new} --*/ title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE; function copy ( --/** Creates a new copy of a revision, including all attributes and content -- and content, returning the ID of the new revision -- @author Karl Goldstein, Michael Pih -- @param revision_id The id of the revision to copy -- @param copy_id The id of the new copy (default null) -- @param target_item_id The id of the item which will own the copied revision. If null, the item that holds the original revision will own the copied revision. Defaults to null. -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (default null) -- @return The id of the new revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE; procedure del ( --/** Deletes the revision. -- @author Karl Goldstein -- @param revision_id The id of the revision to delete -- @see {content_revision.new}, {acs_object.delete} --*/ revision_id in cr_revisions.revision_id%TYPE ); function get_number ( --/** Return the revision number of the specified revision, according to -- the chronological -- order in which revisions have been added for this item. -- @author Karl Goldstein -- @param revision_id The id the revision -- @return The number of the revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE ) return number; function revision_name ( --/** Return a pretty string 'revision x of y' --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure index_attributes( --/** Generates an XML document for insertion into cr_revision_attributes, -- which is indexed by Intermedia for searching attributes. -- @author Karl Goldstein -- @param revision_id The id of the revision to index -- @see {content_revision.new} --*/ revision_id IN cr_revisions.revision_id%TYPE ); function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE; function write_xml ( revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.exportRevision( java.lang.Integer, oracle.sql.CLOB ) return int'; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE; function read_xml ( item_id IN number, revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.importRevision( java.lang.Integer, java.lang.Integer, oracle.sql.CLOB ) return int'; procedure to_html ( --/** Converts a revision uploaded as a binary document to html -- @author Karl Goldstein -- @param revision_id The id of the revision to index --*/ revision_id IN cr_revisions.revision_id%TYPE ); procedure replace( revision_id number, search varchar2, replace varchar2) as language java name 'com.arsdigita.content.Regexp.replace( int, java.lang.String, java.lang.String )'; function is_live ( -- /** Determine if the revision is live -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is live, 'f' otherwise -- @see {content_revision.is_latest} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; function is_latest ( -- /** Determine if the revision is the latest revision -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is the latest revision for its item, 'f' otherwise -- @see {content_revision.is_live} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ); procedure content_copy ( -- /** Copies the content of the specified revision to the content -- of another revision -- @author Michael Pih -- @param revision_id The id of the revision with the content to be copied -- @param revision_id The id of the revision to be updated, defaults to the -- latest revision of the item with which the source revision is -- associated. --*/ revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ); end content_revision; / show errors create or replace package content_symlink as function new ( --/** Create a new symlink, linking two items -- @author Karl Goldstein -- @param name The name for the new symlink, defaults to the name of the -- target item -- @param label The label of the symlink, defaults to 'Symlinke to ' -- @param target_id The item which the symlink will point to -- @param parent_id The parent folder for the symlink. This must actually be a folder -- and not a generic content item. -- @param symlink_id The id of the new symlink. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created symlink -- @see {acs_object.new}, {content_item.new}, {content_symlink.resolve} --*/ name in cr_items.name%TYPE default null, label in cr_symlinks.label%TYPE default null, target_id in cr_items.item_id%TYPE, parent_id in cr_items.parent_id%TYPE, symlink_id in cr_symlinks.symlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_symlinks.symlink_id%TYPE; procedure del ( --/** Deletes the symlink -- @author Karl Goldstein -- @param symlink_id The id of the symlink to delete -- @see {content_symlink.new}, {acs_object.delete} --*/ symlink_id in cr_symlinks.symlink_id%TYPE ); procedure copy ( --/** Copies the symlink itself to another folder, without resolving the symlink -- @author Karl Goldstein -- @param symlink_id The id of the symlink to copy -- @param target_folder_id The id of the folder where the symlink is to be copied -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defualt null) -- @see {content_symlink.new}, {content_item.copy} --*/ symlink_id in cr_symlinks.symlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ); function is_symlink ( --/** Determines if the item is a symlink -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a symlink, 'f' otherwise -- @see {content_symlink.new}, {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return char; function resolve ( --/** Resolves the symlink and returns the target item id. -- @author Karl Goldstein -- @param item_id The item id to be resolved -- @return The target item of the symlink, or the original item id if -- the item is not in fact a symlink -- @see {content_symlink.new}, {content_symlink.is_symlink} --*/ item_id in cr_items.item_id%TYPE ) return cr_items.item_id%TYPE; function resolve_content_type ( --/** Gets the content type of the target item. -- @author Michael Pih -- @param item_id The item id to be resolved -- @return The content type of the symlink target, otherwise null. -- the item is not in fact a symlink -- @see {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; end content_symlink; / show errors create or replace package content_extlink as function new ( --/** Create a new extlink, an item pointing to an off-site resource -- @author Karl Goldstein -- @param name The name for the new extlink, defaults to the name of the -- target item -- @param url The URL of the item -- @param label The text label or title of the item -- @param description A brief description of the item -- @param parent_id The parent folder for the extlink. This must actually be a folder -- and not a generic content item. -- @param extlink_id The id of the new extlink. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created extlink -- @see {acs_object.new}, {content_item.new}, {content_extlink.resolve} --*/ name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure del ( --/** Deletes the extlink -- @author Karl Goldstein -- @param extlink_id The id of the extlink to delete -- @see {content_extlink.new}, {acs_object.delete} --*/ extlink_id in cr_extlinks.extlink_id%TYPE ); function is_extlink ( --/** Determines if the item is a extlink -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a extlink, 'f' otherwise -- @see {content_extlink.new}, {content_extlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return char; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ); end content_extlink; / show errors create or replace package content_folder as function new ( --/** Create a new folder -- @author Karl Goldstein -- @param label The label for the folder -- @param description A short description of the folder, 4000 characters maximum -- @param parent_id The parent of the folder -- @param folder_id The id of the new folder. A new id will be allocated by default -- @param context_id The context id. The parent id will be used as the default context -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created folder -- @see {acs_object.new}, {content_item.new} --*/ name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_folders.folder_id%TYPE; procedure del ( --/** Delete a folder. An error is thrown if the folder is not empty -- @author Karl Goldstein -- @param folder_id The id of the folder to delete -- @see {acs_object.delete}, {content_item.delete} --*/ folder_id in cr_folders.folder_id%TYPE ); procedure rename ( --/** Change the name, label and/or description of the folder -- @author Karl Goldstein -- @param folder_id The id of the folder to modify -- @param name The new name for the folder. An error will be thrown if -- an item with this name already exists under this folder's -- parent. If this parameter is null, the old name will be preserved -- @param label The new label for the folder. The old label will be preserved if -- this parameter is null -- @param label The new description for the folder. The old description -- will be preserved if this parameter is null -- @see {content_folder.new} --*/ folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ); procedure move ( --/** Recursively move the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be moved. -- @author Karl Goldstein -- @param folder_id The id of the folder to move -- @param target_folder_id The destination folder -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ); procedure copy ( --/** Recursively copy the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be copied -- @author Karl Goldstein -- @param folder_id The id of the folder to copy -- @param target_folder_id The destination folder -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defaults to null) -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null ); function is_folder ( --/** Determine if the item is a folder -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a folder, 'f' otherwise -- @see {content_folder.new}, {content_folder.is_sub_folder} --*/ item_id in cr_items.item_id%TYPE ) return char; function is_sub_folder ( --/** Determine if the item target_folder_id is a subfolder of -- the item folder_id -- @author Karl Goldstein -- @param folder_id The superfolder id -- @param target_folder_id The subfolder id -- @return 't' if the item target_folder_id is a subfolder of -- the item folder_id, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char; function is_empty ( --/** Determine if the folder is empty -- @author Karl Goldstein -- @param folder_id The folder id -- @return 't' if the folder contains no subfolders or items, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE ) return varchar2; function is_root ( --/** Determine whether the folder is a root (has a parent_id of 0) -- @author Karl Goldstein -- @param folder_id The folder ID -- @return 't' if the folder is a root or 'f' otherwise --*/ folder_id in cr_folders.folder_id%TYPE ) return char; procedure register_content_type ( --/** Register a content type to the folder, if it is not already registered. -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be registered -- @see {content_folder.unregister_content_type}, -- {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); procedure unregister_content_type ( --/** Unregister a content type from the folder, if it has been registered. -- Only items of the registered type(s) may be added to the folder. -- If the folder already contains items of the type to be unregistered, the -- items remain in the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be unregistered -- @param include_subtypes If 't', all subtypes of content_type will be -- unregistered as well -- @see {content_folder.register_content_type}, {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); -- change this to is_type_registered function is_registered ( --/** Determines if a content type is registered to the folder -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be checked -- @param include_subtypes If 't', all subtypes of the content_type -- will be checked, returning 't' if all of them are registered. If 'f', -- only an exact match with content_type will be -- performed. -- @return 't' if the type is registered to this folder, 'f' otherwise -- @see {content_folder.register_content_type}, {content_folder.unregister_content_type}, --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2; function get_label ( --/** Returns the label for the folder. This function is the default name method -- for the folder object. -- @author Karl Goldstein -- @param folder_id The folder id -- @return The folder's label -- @see {acs_object_type.create_type}, the docs for the name_method parameter --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE; function get_index_page ( --/** Returns the item ID of the index page of the folder, null otherwise -- @author Michael Pih -- @param folder_id The folder id -- @return The item ID of the index page --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE; end content_folder; / show errors create or replace package content_template as c_root_folder_id constant integer := -200; function get_root_folder return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content template which can be used to render content items. -- @author Karl Goldstein -- @param name The name for the template, must be a valid UNIX-like filename. -- If a template with this name already exists under the specified -- parent item, an error is thrown -- @param text The body of the .adp template itself, defaults to null -- @param parent_id The parent of this item, defaults to null -- @param is_live The should the revision be set live, defaults to 't'. Requires -- that text is not null or there will be no revision to begin with -- @param template_id The id of the new template. A new id will be allocated if this -- parameter is null -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created template -- @see {acs_object.new}, {content_item.new}, {content_item.register_template}, -- {content_type.register_template} --*/ name in cr_items.name%TYPE, text in varchar2 default null, parent_id in cr_items.parent_id%TYPE default null, is_live in char default 't', template_id in cr_templates.template_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_templates.template_id%TYPE; procedure del ( --/** Deletes the specified template, and unregisters the template from -- all content types and content items. -- Use with caution - this operation cannot be undone. -- @author Karl Goldstein -- @param template_id The id of the template to delete -- @see {acs_object.delete}, {content_item.unregister_template}, -- {content_type.unregister_template}, --*/ template_id in cr_templates.template_id%TYPE ); function is_template ( --/** Determine if an item is a template. -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a template, 'f' otherwise -- @see {content_template.new} --*/ template_id in cr_templates.template_id%TYPE ) return varchar2; function get_path ( --/** Retrieves the full path to the template, as described in content_item.get_path -- @author Karl Goldstein -- @param template_id The id of the template for which the path is to -- be retrieved -- @param root_folder_id Starts path resolution at this folder -- @return The path to the template, starting with the specified root folder -- @see {content_item.get_path} --*/ template_id in cr_templates.template_id%TYPE, root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id ) return varchar2; end content_template; / show errors create or replace package content_keyword as function new ( --/** Creates a new keyword (also known as "subject category"). -- @author Karl Goldstein -- @param heading The heading for the new keyword -- @param description The description for the new keyword -- @param parent_id The parent of this keyword, defaults to null. -- @param keyword_id The id of the new keyword. A new id will be allocated if this -- parameter is null -- @param object_type The type for the new keyword, defaults to 'content_keyword'. -- This parameter may be used by subclasses of -- content_keyword to initialize the superclass. -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created keyword -- @see {acs_object.new}, {content_item.new}, {content_keyword.item_assign}, -- {content_keyword.delete} --*/ heading in cr_keywords.heading%TYPE, description in cr_keywords.description%TYPE default null, parent_id in cr_keywords.parent_id%TYPE default null, keyword_id in cr_keywords.keyword_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_object_types.object_type%TYPE default 'content_keyword' ) return cr_keywords.keyword_id%TYPE; procedure del ( --/** Deletes the specified keyword, which must be a leaf. Unassigns the -- keyword from all content items. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param keyword_id The id of the keyword to be deleted -- @see {acs_object.delete}, {content_keyword.item_unassign} --*/ keyword_id in cr_keywords.keyword_id%TYPE ); function get_heading ( --/** Retrieves the heading of the content keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The heading for the specified keyword -- @see {content_keyword.set_heading}, {content_keyword.get_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; function get_description ( --/** Retrieves the description of the content keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The description for the specified keyword -- @see {content_keyword.get_heading}, {content_keyword.set_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; procedure set_heading ( --/** Sets a new heading for the keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @param heading The new heading -- @see {content_keyword.get_heading}, {content_keyword.set_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE, heading in cr_keywords.heading%TYPE ); procedure set_description ( --/** Sets a new description for the keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @param description The new description -- @see {content_keyword.set_heading}, {content_keyword.get_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE, description in cr_keywords.description%TYPE ); function is_leaf ( --/** Determines if the keyword has no sub-keywords associated with it -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return 't' if the keyword has no descendants, 'f' otherwise -- @see {content_keyword.new} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; procedure item_assign ( --/** Assigns this keyword to a content item, creating a relationship between them -- @author Karl Goldstein -- @param item_id The item to be assigned to -- @param keyword_id The keyword to be assigned -- @param context_id As in acs_rel.new, deprecated -- @param creation_ip As in acs_rel.new, deprecated -- @param creation_user As in acs_rel.new, deprecated -- @see {acs_rel.new}, {content_keyword.item_unassign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ); procedure item_unassign ( --/** Unassigns this keyword to a content item, removing a relationship between them -- @author Karl Goldstein -- @param item_id The item to be unassigned from -- @param keyword_id The keyword to be unassigned -- @see {acs_rel.delete}, {content_keyword.item_assign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE ); function is_assigned ( --/** Determines if the keyword is assigned to the item -- @author Karl Goldstein -- @param item_id The item id -- @param keyword_id The keyword id to be checked for assignment -- @param recurse Specifies if the keyword search is -- recursive. May be set to one of the following -- values:
    --
  • none: Not recursive. Look for an exact match.
  • --
  • up: Recursive from specific to general. A search for -- "attack dogs" will also match "dogs", "animals", "mammals", etc.
  • --
  • down: Recursive from general to specific. A search for -- "mammals" will also match "dogs", "attack dogs", "cats", "siamese cats", -- etc.
-- @return 't' if the keyword may be matched to an item, 'f' otherwise -- @see {content_keyword.item_assign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, recurse in varchar2 default 'none' ) return varchar2; function get_path ( --/** Retreives a path to the keyword/subject category, with the most general -- category at the root of the path -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The path to the keyword, or null if no such keyword exists -- @see {content_keyword.new} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; end content_keyword; / show errors create or replace package content_permission is procedure inherit_permissions ( --/** Make the child object inherit all of the permissions of the parent -- object. Typically, this function is called whenever a new object -- is created under a given parent -- @author Karl Goldstein -- @param parent_object_id The parent object id -- @param child_object_id The child object id -- @see {content_permission.grant}, {acs_permission.grant_permission} --*/ parent_object_id in acs_objects.object_id%TYPE, child_object_id in acs_objects.object_id%TYPE, child_creator_id in parties.party_id%TYPE default null ); function has_grant_authority ( --/** Determine if the user may grant a certain permission to another -- user. The permission may only be granted if the user has -- the permission himself and posesses the cm_perm access, or if the -- user posesses the cm_perm_admin access. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to grant the permissions -- @param privilege The privilege to be granted -- @return 't' if the donation is possible, 'f' otherwise -- @see {content_permission.grant_permission}, {content_permission.is_has_revoke_authority}, -- {acs_permission.grant_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) return varchar2; procedure grant_permission_h ( --/** This is a helper function for content_permission.grant_permission and -- should not be called individually.

-- Grants a permission and revokes all descendants of the permission, since -- they are no longer relevant. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param grantee_id The person who should gain the parent privilege -- @param privilege The parent privilege to be granted -- @see {content_permission.grant_permission} --*/ object_id in acs_objects.object_id%TYPE, grantee_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ); procedure grant_permission ( --/** Grant the specified privilege to another user. If the donation is -- not possible, the procedure does nothing. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to grant the permissions -- @param privilege The privilege to be granted -- @param recepient_id The person who will gain the privilege -- @param is_recursive If 't', applies the donation recursively to -- all child objects of the object (equivalent to UNIX's chmod -r). -- If 'f', only affects the objects itself. -- @see {content_permission.has_grant_authority}, {content_permission.revoke_permission}, -- {acs_permission.grant_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, recepient_id in parties.party_id%TYPE, is_recursive in varchar2 default 'f', object_type in acs_objects.object_type%TYPE default 'content_item' ); function has_revoke_authority ( --/** Determine if the user may take a certain permission away from another -- user. The permission may only be revoked if the user has -- the permission himself and posesses the cm_perm access, while the -- other user does not, or if the user posesses the cm_perm_admin access. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to revoke the permissions -- @param privilege The privilege to be revoked -- @param revokee_id The user from whom the privilege is to be taken away -- @return 't' if it is possible to revoke the privilege, 'f' otherwise -- @see {content_permission.has_grant_authority}, {content_permission.revoke_permission}, -- {acs_permission.revoke_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, revokee_id in parties.party_id%TYPE ) return varchar2; procedure revoke_permission_h ( --/** This is a helper function for content_permission.revoke_permission and -- should not be called individually.

-- Revokes a permission but grants all child permissions to the holder, to -- ensure that the permission is not permanently lost -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param revokee_id The person who should lose the parent permission -- @param privilege The parent privilege to be revoked -- @see {content_permission.revoke_permission} --*/ object_id in acs_objects.object_id%TYPE, revokee_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ); procedure revoke_permission ( --/** Take the specified privilege away from another user. If the operation is -- not possible, the procedure does nothing. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to revoke the permissions -- @param privilege The privilege to be revoked -- @param recepient_id The person who will lose the privilege -- @param is_recursive If 't', applies the operation recursively to -- all child objects of the object (equivalent to UNIX's chmod -r). -- If 'f', only affects the objects itself. -- @see {content_permission.grant_permission}, {content_permission.has_revoke_authority}, -- {acs_permission.revoke_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, revokee_id in parties.party_id%TYPE, is_recursive in varchar2 default 'f', object_type in acs_objects.object_type%TYPE default 'content_item' ); function permission_p ( --/** Determine if the user has the specified permission on the specified -- object. Does NOT check objects recursively: that is, if the user has -- the permission on the parent object, he does not automatically gain -- the permission on all the child objects. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be checked -- @param holder_id The person whose permissions are to be examined -- @param privilege The privilege to be checked -- @return 't' if the user has the specified permission on the object, -- 'f' otherwise -- @see {content_permission.grant_permission}, {content_permission.revoke_permission}, -- {acs_permission.permission_p} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) return varchar2; function cm_admin_exists -- /** Determine if there exists a user who has administrative -- privileges on the entire content repository. -- @author Stanislav Freidin -- @return 't' if an administrator exists, 'f' otherwise -- @see {content_permission.grant_permission} return varchar2; end content_permission; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.0-4.0.1.sql0000644000175000017500000000006307263137640030013 0ustar frankiefrankie-- -- CR upgrade script. -- @@ packages-create.sqlopenacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.1d2-5.1.1d3.sql0000644000175000017500000026252110074522377030643 0ustar frankiefrankie create or replace package content_item as --/** --Content items store the overview of the content published on a --website. The actual content is stored in content revisions. It is --implemented this way so that there can be mulitple versions of the --actual content while the main idea remains constant. For example: If --there is a review for the movie "Terminator," there will exist a --content item by the name "terminator" with all the right parameters --(supertype, parent, etc), there will also exist at least one content --revision pointing to this item with the actual review content. --@see {content_revision}, {content_folder} --*/ c_root_folder_id constant integer := -100; function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content item. If the data, title or text -- parameters are specified, also creates a revision for the item. -- @author Karl Goldstein -- @param name The name for the item, must be URL-encoded. -- If an item with this name already exists under the specified -- parent item, an error is thrown -- @param parent_id The parent of this item, defaults to null -- @param item_id The id of the new item. A new id will be allocated if this -- parameter is null -- @param locale The locale for this item, for use with Intermedia search -- @param item_subtype The type of the new item, defaults to 'content_item' -- This parameter is used to support inheritance, so that -- subclasses of content_item can call this function -- to initialize the parent class -- @param content_type The content type for the item, defaults to -- 'content_revision'. Only objects of this type -- may be used as revisions for the item -- @param title The user-readable title for the item, defaults to the item's -- name -- @param description A short description for the item (4000 characters maximum) -- @param mime_type The file type of the item, defaults to 'text/plain' -- @param nls_language The language for the item, used for Intermedia search -- @param text The text content of the new revision, 4000 charcters maximum. -- Cannot be specified simultaneously with the data -- parameter -- @param data The blob content of the new revision. Cannot be specified -- simultaneously with the text parameter -- @param relation_tag If a parent-child relationship is registered -- for these content types, use this tag to -- describe the parent-child relationship. Defaults -- to 'parent content type'-'child content type' -- @param is_live If 't', the new revision will become live -- @param context_id Security context id, as in acs_object.new -- If null, defaults to parent_id, and copies permissions -- from the parent into the current item -- @param storage_type in ('lob','file'). Indicates how content is to be stored. -- 'file' content is stored externally in the file system. -- @param others As in acs_object.new -- @return The id of the newly created item -- @see {acs_object.new} --*/ name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob' ) return cr_items.item_id%TYPE; function is_published ( --/** Determins whether an item is published or not. -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is published, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE ) return char; function is_publishable ( --/** Determines if an item is publishable. Publishable items must -- meet the following criteria: -- 1) for each child type, the item has n children, min_n < n < max_n -- 2) for each relation type, the item has n relations, min_n < n < max_n -- 3) any 'publishing_wf' workflows are finished -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is publishable in it's present state, -- Otherwise, returns 'f' --*/ item_id in cr_items.item_id%TYPE ) return char; function is_valid_child ( --/** Determines if an item would be a valid child of another item by -- checking if the parent allows children of the would-be child's -- content type and if the parent already has n_max children of -- that content type. -- @author Michael Pih -- @param item_id The item ID of the potential parent -- @param content_type The content type of the potential child item -- @return 't' if the item would be a valid child, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char; procedure del ( --/** Deletes the specified content item, along with any revisions, symlinks, -- workflows, associated templates, associated keywords, -- child and item relationships for the item. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param item_id The id of the item to delete -- @see {acs_object.delete} --*/ item_id in cr_items.item_id%TYPE ); procedure edit_name ( --/** Renames the item. If an item with the specified name already exists -- under this item's parent, an error is thrown -- @author Karl Goldstein -- @param item_id The id of the item to rename -- @param name The new name for the item, must be URL-encoded -- @see {content_item.new} --*/ item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ); function get_id ( --/** Takes in a path, such as "/tv/programs/star_trek/episode_203" -- and returns the id of the item with this path. Note: URLs are abstract (no -- extensions are allowed in content item names and extensions are stripped when -- looking up content items) -- @author Karl Goldstein -- @param item_path The path to be resolved -- @param root_folder_id Starts path resolution from this folder. Defaults to -- the root of the sitemap -- @param resolve_index Boolean flag indicating whether to return the -- id of the index page for folders (if one -- exists). Defaults to 'f'. -- @return The id of the item with the given path, or null if no such item exists -- @see {content_item.get_path} --*/ item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE; function get_path ( --/** Retrieves the full path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Karl Goldstein -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The path to the item -- @see {content_item.get_id}, {content_item.write_to_file} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2; function get_virtual_path ( --/** Retrieves the virtual path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Michael Pih -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The virtual path to the item -- @see {content_item.get_id}, {content_item.write_to_file}, {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2; procedure write_to_file ( --/** Writes the content of the live revision of this item to a file, -- creating all the neccessary directories in the process -- @author Karl Goldstein -- @param item_id The item to be written to a file -- @param root_path The path in the filesystem to which the root of the -- sitemap corresponds -- @see {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_path in varchar2 ); procedure register_template ( --/** Registers a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be registered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.unregister_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ); procedure unregister_template ( --/** Unregisters a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.register_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ); function get_template ( --/** Retrieves the template which should be used to render this item. If no template -- is registered to specifically render the item in the given context, the -- default template for the item's type is returned. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param use_context The context in the item is to be rendered, such -- as 'admin' or 'public' -- @return The id of the registered template, or null if no template could be -- found -- @see {content_type.register_template}, {content_item.register_template}, --*/ item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; function get_live_revision ( --/** Retrieves the id of the live revision for the item -- @param item_id The item for which the live revision is to be retrieved -- @return The id of the live revision for this item, or null if no live revision -- exists -- @see {content_item.set_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; procedure set_live_revision ( --/** Make the specified revision the live revision for the item -- @author Karl Goldstein -- @param revision_id The id of the revision which is to become live -- for its corresponding item -- @see {content_item.get_live_revision} --*/ revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ); procedure unset_live_revision ( --/** Set the live revision to null for the item -- @author Michael Pih -- @param item_id The id of the item for which to unset the live revision -- @see {content_item.set_live_revision} item_id in cr_items.item_id%TYPE ); procedure set_release_period ( --/** Sets the release period for the item. This information may be -- used by applications to update the publishing status of items -- at periodic intervals. -- @author Karl Goldstein -- @param item_id The id the item. -- @param start_when The time and date when the item should be released. -- @param end_when The time and date when the item should be expired. --*/ item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ); function get_revision_count ( --/** Return the total count of revisions for this item -- @author Karl Goldstein -- @param item_id The id the item -- @return The number of revisions for this item -- @see {content_revision.new} --*/ item_id in cr_items.item_id%TYPE ) return number; -- Return the object type of this item function get_content_type ( --/** Retrieve the content type of this item. Only objects of this type may be -- used as revisions for the item. -- @author Karl Goldstein -- @param item_id The item for which the content type is to be retrieved -- @return The content type of the item --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; function get_context ( --/** Retrieve the parent of the given item -- @author Karl Goldstein -- @param item_id The item for which the parent is to be retrieved -- @return The id of the parent for this item --*/ item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE; procedure move ( --/** Move the specified item to a different folder. If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein -- @param item_id The item to be moved -- @param target_folder_id The new folder for the item -- @see {content_item.new}, {content_folder.new}, {content_item.copy} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function copy2 ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @return The item ID of the new copy. -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE; -- get the latest revision for an item function get_latest_revision ( --/** Retrieves the id of the latest revision for the item (as opposed to the live -- revision) -- @author Karl Goldstein -- @param item_id The item for which the latest revision is to be retrieved -- @return The id of the latest revision for this item, or null if no revisions -- exist -- @see {content_item.get_live_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_best_revision ( --/** Retrieves the id of the live revision for the item if one exists, -- otherwise retrieves the id of the latest revision if one exists. -- revision) -- @author Michael Pih -- @param item_id The item for which the revision is to be retrieved -- @return The id of the live or latest revision for this item, -- or null if no revisions exist -- @see {content_item.get_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_title ( --/** Retrieves the title for the item, using either the latest or the live revision. -- If the specified item is in fact a folder, return the folder's label. -- In addition, this function will automatically resolve symlinks. -- @author Karl Goldstein -- @param item_id The item for which the title is to be retrieved -- @param is_live If 't', use the live revision to get the title. Otherwise, -- use the latest revision. The default is 'f' -- @return The title of the item -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, -- {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE; function get_publish_date ( --/** Retrieves the publish date for the item -- @author Karl Goldstein -- @param item_id The item for which the publish date is to be retrieved -- @param is_live If 't', use the live revision for the item. Otherwise, use -- the latest revision. The default is 'f' -- @return The publish date for the item, or null if the item has no revisions -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE; function is_subclass ( --/** Determines if one type is a subclass of another. A class is always a subclass of -- itself. -- @author Karl Goldstein -- @param object_type The child class -- @param supertype The superclass -- @return 't' if the child class is a subclass of the superclass, 'f' otherwise -- @see {acs_object_type.create_type} --*/ object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char; function relate ( --/** Relates two content items -- @author Karl Goldstein -- @param item_id The item id -- @param object_id The item id of the related object -- @param relation_tag A tag to help identify the relation type, -- defaults to 'generic' -- @param order_n The order of this object among other objects -- of the same relation type, defaults to null. -- @param relation_type The object type of the relation, defaults to -- 'cr_item_rel' --*/ item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE; procedure unrelate ( --/** Delete the item relationship between two items -- @author Michael Pih -- @param rel_id The relationship id -- @see {content_item.relate} --*/ rel_id in cr_item_rels.rel_id%TYPE ); function is_index_page ( --/** Determine if the item is an index page for the specified folder. -- The item is an index page for the folder if it exists in the -- folder and its item name is "index". -- @author Karl Goldstein -- @param item_id The item id -- @param folder_id The folder id -- @return 't' if the item is an index page for the specified -- folder, 'f' otherwise -- @see {content_folder.get_index_page} --*/ item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2; function get_parent_folder ( --/** Get the parent folder. -- @author Michael Pih -- @param item_id The item id -- @return the folder_id of the parent folder, null otherwise --*/ item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE; end content_item; / show errors create or replace package content_folder as function new ( --/** Create a new folder -- @author Karl Goldstein -- @param label The label for the folder -- @param description A short description of the folder, 4000 characters maximum -- @param parent_id The parent of the folder -- @param folder_id The id of the new folder. A new id will be allocated by default -- @param context_id The context id. The parent id will be used as the default context -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created folder -- @see {acs_object.new}, {content_item.new} --*/ name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_folders.folder_id%TYPE; procedure del ( --/** Delete a folder. An error is thrown if the folder is not empty -- @author Karl Goldstein -- @param folder_id The id of the folder to delete -- @see {acs_object.delete}, {content_item.delete} --*/ folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ); procedure edit_name ( --/** Change the name, label and/or description of the folder -- @author Karl Goldstein -- @param folder_id The id of the folder to modify -- @param name The new name for the folder. An error will be thrown if -- an item with this name already exists under this folder's -- parent. If this parameter is null, the old name will be preserved -- @param label The new label for the folder. The old label will be preserved if -- this parameter is null -- @param label The new description for the folder. The old description -- will be preserved if this parameter is null -- @see {content_folder.new} --*/ folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ); procedure move ( --/** Recursively move the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be moved. -- @author Karl Goldstein -- @param folder_id The id of the folder to move -- @param target_folder_id The destination folder -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Recursively copy the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be copied -- @author Karl Goldstein -- @param folder_id The id of the folder to copy -- @param target_folder_id The destination folder -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defaults to null) -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function is_folder ( --/** Determine if the item is a folder -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a folder, 'f' otherwise -- @see {content_folder.new}, {content_folder.is_sub_folder} --*/ item_id in cr_items.item_id%TYPE ) return char; function is_sub_folder ( --/** Determine if the item target_folder_id is a subfolder of -- the item folder_id -- @author Karl Goldstein -- @param folder_id The superfolder id -- @param target_folder_id The subfolder id -- @return 't' if the item target_folder_id is a subfolder of -- the item folder_id, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char; function is_empty ( --/** Determine if the folder is empty -- @author Karl Goldstein -- @param folder_id The folder id -- @return 't' if the folder contains no subfolders or items, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE ) return varchar2; function is_root ( --/** Determine whether the folder is a root (has a parent_id of 0) -- @author Karl Goldstein -- @param folder_id The folder ID -- @return 't' if the folder is a root or 'f' otherwise --*/ folder_id in cr_folders.folder_id%TYPE ) return char; procedure register_content_type ( --/** Register a content type to the folder, if it is not already registered. -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be registered -- @see {content_folder.unregister_content_type}, -- {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); procedure unregister_content_type ( --/** Unregister a content type from the folder, if it has been registered. -- Only items of the registered type(s) may be added to the folder. -- If the folder already contains items of the type to be unregistered, the -- items remain in the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be unregistered -- @param include_subtypes If 't', all subtypes of content_type will be -- unregistered as well -- @see {content_folder.register_content_type}, {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); -- change this to is_type_registered function is_registered ( --/** Determines if a content type is registered to the folder -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be checked -- @param include_subtypes If 't', all subtypes of the content_type -- will be checked, returning 't' if all of them are registered. If 'f', -- only an exact match with content_type will be -- performed. -- @return 't' if the type is registered to this folder, 'f' otherwise -- @see {content_folder.register_content_type}, {content_folder.unregister_content_type}, --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2; function get_label ( --/** Returns the label for the folder. This function is the default name method -- for the folder object. -- @author Karl Goldstein -- @param folder_id The folder id -- @return The folder's label -- @see {acs_object_type.create_type}, the docs for the name_method parameter --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE; function get_index_page ( --/** Returns the item ID of the index page of the folder, null otherwise -- @author Michael Pih -- @param folder_id The folder id -- @return The item ID of the index page --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE; end content_folder; / show errors create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = 0 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob' ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = 0 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= 0 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= 0 then begin -- Figure out the relation_tag to use if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type, v_rel_tag) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels -- We checked above before creating the object that it is a valid rel if v_parent_id ^= 0 and content_folder.is_folder(v_parent_id) = 'f' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', context_id => v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure del ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.del.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.del.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.del.item_id or related_object_id = content_item.del.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.del.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.del.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; dbms_output.put_line('Deleting symlinks...'); -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.del(v_symlink_val.symlink_id); end loop; dbms_output.put_line('Unscheduling item...'); delete from cr_release_periods where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated revisions...'); -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.del.item_id; for v_revision_val in c_revision_cur loop content_revision.del(v_revision_val.revision_id); end loop; dbms_output.put_line('Deleting associated item templates...'); -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting item relationships...'); -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting child relationships...'); for v_rel_val in c_child_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting parent relationships...'); for v_rel_val in c_parent_cur loop acs_rel.del(v_rel_val.rel_id); content_item.del(v_rel_val.child_id); end loop; dbms_output.put_line('Deleting associated permissions...'); -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.del.item_id; dbms_output.put_line('Deleting keyword associations...'); -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated comments...'); -- 7) delete associated comments journal_entry.delete_for_object( content_item.del.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; dbms_output.put_line('Deleting content item...'); acs_object.del(content_item.del.item_id); end del; procedure edit_name ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where cr_items.name = content_item.edit_name.name and parent_id = (select parent_id from cr_items where cr_items.item_id = content_item.edit_name.item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set cr_items.name = content_item.edit_name.name where cr_items.item_id = content_item.edit_name.item_id; else close exists_cur; if exists_id <> item_id then raise_application_error(-20000, 'An item with the name ' || name || ' already exists in this directory.'); end if; end if; end edit_name; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := 0; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := 0; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id, name); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id, name = nvl (move.name, cr_items.name) where item_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip, name); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; select content_type, name , locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- can't copy to the same folder unless name is different if copy2.target_folder_id ^= v_current_folder_id or (v_name != copy2.name and copy2.name is not null) then if copy2.name is not null then v_name := copy2.name; end if; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; elsif v_content_type = 'content_extlink' then select label into v_title from cr_extlinks where extlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.del( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; v_folder_id := get_parent_folder.item_id; while v_parent_folder_p = 'f' and v_folder_id is not null loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end get_parent_folder; end content_item; / show errors create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = 0 means that this is a mount point if parent_id ^= 0 and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id ); insert into cr_folders ( folder_id, label, description ) values ( v_folder_id, label, description ); -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy.folder_id; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder or target_folder_id = folder_id then v_valid_folders_p := 0; end if; if v_valid_folders_p = 2 then -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if is_sub_folder(folder_id, target_folder_id) ^= 't' or v_current_folder_id != copy.target_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end if; end if; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := 0; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; if v_parent_id ^= 0 then v_sub_folder_p := 't'; end if; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.0.0-5.1.0d1.sql0000644000175000017500000000520510041311104030354 0ustar frankiefrankie-- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-01-22 -- @cvs-id $Id @@ ../packages-create.sql -- OpenOffice MIME types insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Spreadsheet' , 'application/vnd.sun.xml.calc', 'sxc'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Spreadsheet Template', 'application/vnd.sun.xml.calc.template', 'stc'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Draw', 'application/vnd.sun.xml.draw', 'sxd'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Draw Template', 'application/vnd.sun.xml.draw.template', 'std'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Impress', 'application/vnd.sun.xml.impress', 'sxi'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Impress Template', 'application/vnd.sun.xml.impress.template', 'sti'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Math', 'application/vnd.sun.xml.math', 'sxm'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer', 'application/vnd.sun.xml.writer', 'sxw'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer Global', 'application/vnd.sun.xml.writer.global', 'sxg'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer Template', 'application/vnd.sun.xml.writer.template', 'stw'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxc', 'application/vnd.sun.xml.calc'); insert into cr_extension_mime_type_map (extension, mime_type) values ('stc', 'application/vnd.sun.xml.calc.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxd', 'application/vnd.sun.xml.draw'); insert into cr_extension_mime_type_map (extension, mime_type) values ('std', 'application/vnd.sun.xml.draw.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxi', 'application/vnd.sun.xml.impress'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sti', 'application/vnd.sun.xml.impress.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxm', 'application/vnd.sun.xml.math'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxw', 'application/vnd.sun.xml.writer'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxg', 'application/vnd.sun.xml.writer.global'); insert into cr_extension_mime_type_map (extension, mime_type) values ('stw', 'application/vnd.sun.xml.writer.template'); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.2d5-5.1.2d6.sql0000644000175000017500000004013510171476673030653 0ustar frankiefrankie create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = 0 means that this is a mount point if parent_id ^= 0 and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id ); insert into cr_folders ( folder_id, label, description ) values ( v_folder_id, label, description ); -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy.folder_id; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder or target_folder_id = folder_id then v_valid_folders_p := 0; end if; if v_valid_folders_p = 2 then -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if is_sub_folder(folder_id, target_folder_id) ^= 't' or v_current_folder_id != copy.target_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end if; end if; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := 0; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; if v_parent_id = folder_id then v_sub_folder_p := 't'; end if; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0a1-5.2.0a2.sql0000644000175000017500000017112410440426443030623 0ustar frankiefrankiecreate or replace package content_revision as function new ( --/** Create a new revision for an item. -- @author Karl Goldstein -- @param title The revised title for the item -- @param description A short description of this revision, 4000 characters maximum -- @param publish_date Publication date. -- @param mime_type The revised mime type of the item, defaults to 'text/plain' -- @param nls_language The revised language of the item, for use with Intermedia searching -- @param data The blob which contains the body of the revision -- @param item_id The id of the item being revised -- @param revision_id The id of the new revision. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created revision -- @see {acs_object.new}, {content_item.new} --*/ title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE; function copy ( --/** Creates a new copy of a revision, including all attributes and content -- and content, returning the ID of the new revision -- @author Karl Goldstein, Michael Pih -- @param revision_id The id of the revision to copy -- @param copy_id The id of the new copy (default null) -- @param target_item_id The id of the item which will own the copied revision. If null, the item that holds the original revision will own the copied revision. Defaults to null. -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (default null) -- @return The id of the new revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE; procedure del ( --/** Deletes the revision. -- @author Karl Goldstein -- @param revision_id The id of the revision to delete -- @see {content_revision.new}, {acs_object.delete} --*/ revision_id in cr_revisions.revision_id%TYPE ); function get_number ( --/** Return the revision number of the specified revision, according to -- the chronological -- order in which revisions have been added for this item. -- @author Karl Goldstein -- @param revision_id The id the revision -- @return The number of the revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE ) return number; function revision_name ( --/** Return a pretty string 'revision x of y' --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure index_attributes( --/** Generates an XML document for insertion into cr_revision_attributes, -- which is indexed by Intermedia for searching attributes. -- @author Karl Goldstein -- @param revision_id The id of the revision to index -- @see {content_revision.new} --*/ revision_id IN cr_revisions.revision_id%TYPE ); function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE; function write_xml ( revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.exportRevision( java.lang.Integer, oracle.sql.CLOB ) return int'; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE; function read_xml ( item_id IN number, revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.importRevision( java.lang.Integer, java.lang.Integer, oracle.sql.CLOB ) return int'; procedure to_html ( --/** Converts a revision uploaded as a binary document to html -- @author Karl Goldstein -- @param revision_id The id of the revision to index --*/ revision_id IN cr_revisions.revision_id%TYPE ); procedure replace( revision_id number, search varchar2, replace varchar2) as language java name 'com.arsdigita.content.Regexp.replace( int, java.lang.String, java.lang.String )'; function is_live ( -- /** Determine if the revision is live -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is live, 'f' otherwise -- @see {content_revision.is_latest} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; function is_latest ( -- /** Determine if the revision is the latest revision -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is the latest revision for its item, 'f' otherwise -- @see {content_revision.is_live} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ); procedure content_copy ( -- /** Copies the content of the specified revision to the content -- of another revision -- @author Michael Pih -- @param revision_id The id of the revision with the content to be copied -- @param revision_id The id of the revision to be updated, defaults to the -- latest revision of the item with which the source revision is -- associated. --*/ revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ); end content_revision; / show errors create or replace package body content_revision as function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; v_package_id acs_objects.package_id%TYPE; v_content_type acs_object_types.object_type%TYPE; begin v_content_type := content_item.get_content_type(item_id); if package_id is null then v_package_id := acs_object.package_id(item_id); else v_package_id := package_id; end if; v_revision_id := acs_object.new( object_id => revision_id, object_type => v_content_type, title => title, package_id => v_package_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, context_id => item_id ); insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, content, item_id, filename ) values ( v_revision_id, title, description, mime_type, publish_date, nls_language, data, item_id, filename ); return v_revision_id; end new; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE is v_revision_id integer; blob_loc cr_revisions.content%TYPE; begin blob_loc := empty_blob(); v_revision_id := content_revision.new( title => title, description => description, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => blob_loc, item_id => item_id, revision_id => revision_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, package_id => package_id, filename => filename ); select content into blob_loc from cr_revisions where revision_id = v_revision_id for update; string_to_blob(text, blob_loc); return v_revision_id; end new; procedure copy_attributes ( content_type in acs_object_types.object_type%TYPE, revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE ) is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = copy_attributes.content_type; cols varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; end loop; execute immediate 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) ( select ' || copy_id || cols || ' from ' || v_table_name || ' where ' || v_id_column || ' = ' || revision_id || ')'; end copy_attributes; function copy ( revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE is v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; -- get the content_type and supertypes cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = ( select object_type from acs_objects where object_id = copy.revision_id ) order by level desc; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy.revision_id; else v_target_item_id := target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy_id is null then select acs_object_id_seq.nextval into v_copy_id from dual; else v_copy_id := copy_id; end if; -- create the basic object insert into acs_objects ( object_id, object_type, context_id, security_inherit_p, creation_user, creation_date, creation_ip, last_modified, modifying_user, modifying_ip, title, package_id ) ( select v_copy_id, object_type, v_target_item_id, security_inherit_p, copy.creation_user, sysdate, copy.creation_ip, sysdate, copy.creation_user, copy.creation_ip, title, package_id from acs_objects where object_id = copy.revision_id ); -- create the basic revision (using v_target_item_id) insert into cr_revisions ( revision_id, title, description, publish_date, mime_type, nls_language, content, item_id, content_length ) ( select v_copy_id, title, description, publish_date, mime_type, nls_language, content, v_target_item_id, content_length from cr_revisions where revision_id = copy.revision_id ); -- iterate over the ancestor types and copy attributes for type_rec in type_cur loop copy_attributes(type_rec.object_type, copy.revision_id, v_copy_id); end loop; return v_copy_id; end copy; procedure del ( revision_id in cr_revisions.revision_id%TYPE ) is v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = content_revision.del.revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = content_revision.del.revision_id then declare cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> content_revision.del.revision_id order by o.creation_date desc; begin open c_revision_cur; fetch c_revision_cur into v_latest_revision; if c_revision_cur%NOTFOUND then v_latest_revision := null; end if; close c_revision_cur; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end; end if; -- Clear live revision if v_live_revision = content_revision.del.revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = content_revision.del.revision_id or new_revision = content_revision.del.revision_id; -- Delete the revision acs_object.del(revision_id); end del; function get_number ( revision_id in cr_revisions.revision_id%TYPE ) return number is cursor rev_cur is select revision_id from cr_revisions r, acs_objects o where item_id = (select item_id from cr_revisions where revision_id = get_number.revision_id) and o.object_id = r.revision_id order by o.creation_date; v_number integer; v_revision cr_revisions.revision_id%TYPE; begin open rev_cur; loop fetch rev_cur into v_revision; if v_revision = get_number.revision_id then v_number := rev_cur%ROWCOUNT; exit; end if; end loop; close rev_cur; return v_number; end get_number; function revision_name( revision_id IN cr_revisions.revision_id%TYPE ) return varchar2 is v_text varchar2(500); v_sql varchar2(500); begin v_sql := 'select ''Revision '' || content_revision.get_number(r.revision_id) || '' of '' || (select count(*) from cr_revisions where item_id = r.item_id) || '' for item: '' || content_item.get_title(item_id) from cr_revisions r where r.revision_id = ' || revision_name.revision_id; execute immediate v_sql into v_text; return v_text; end revision_name; procedure index_attributes( revision_id IN cr_revisions.revision_id%TYPE ) is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_revision_attributes ( revision_id, attributes ) values ( revision_id, empty_clob() ) returning attributes into clob_loc; v_revision_id := write_xml(revision_id, clob_loc); end index_attributes; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE is clob_loc clob; v_revision_id cr_revisions.revision_id%TYPE; begin select doc into clob_loc from cr_xml_docs where doc_id = import_xml.doc_id; v_revision_id := read_xml(item_id, revision_id, clob_loc); return v_revision_id; end import_xml; function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE is clob_loc clob; v_doc_id cr_xml_docs.doc_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin insert into cr_xml_docs (doc_id, doc) values (cr_xml_doc_seq.nextval, empty_clob()) returning doc_id, doc into v_doc_id, clob_loc; v_revision_id := write_xml(revision_id, clob_loc); return v_doc_id; end export_xml; procedure to_html ( revision_id IN cr_revisions.revision_id%TYPE ) is tmp_clob clob; blob_loc blob; begin ctx_doc.filter('cr_doc_filter_index', revision_id, tmp_clob, false); select content into blob_loc from cr_revisions where revision_id = to_html.revision_id for update; clob_to_blob(tmp_clob, blob_loc); dbms_lob.freetemporary(tmp_clob); end to_html; function is_live ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where live_revision = is_live.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_live; function is_latest ( revision_id in cr_revisions.revision_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_items where latest_revision = is_latest.revision_id; return v_ret; exception when no_data_found then return 'f'; end is_latest; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ) is b blob; c clob; begin insert into cr_content_text ( revision_id, content ) values ( revision_id, empty_clob() ) returning content into c; select content into b from cr_revisions where revision_id = to_temporary_clob.revision_id; blob_to_clob(b, c); end to_temporary_clob; -- revision_id is the revision with the content that is to be copied procedure content_copy ( revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ) is v_item_id cr_items.item_id%TYPE; v_content_length integer; v_revision_id_dest cr_revisions.revision_id%TYPE; v_filename cr_revisions.filename%TYPE; v_content blob; begin select content_length, item_id into v_content_length, v_item_id from cr_revisions where revision_id = content_copy.revision_id; -- get the destination revision if content_copy.revision_id_dest is null then select latest_revision into v_revision_id_dest from cr_items where item_id = v_item_id; else v_revision_id_dest := content_copy.revision_id_dest; end if; -- only copy the content if the source content is not null if v_content_length is not null and v_content_length > 0 then /* The internal LOB types - BLOB, CLOB, and NCLOB - use copy semantics, as opposed to the reference semantics which apply to BFILEs. When a BLOB, CLOB, or NCLOB is copied from one row to another row in the same table or in a different table, the actual LOB value is copied, not just the LOB locator. */ select filename, content_length into v_filename, v_content_length from cr_revisions where revision_id = content_copy.revision_id; -- need to update the file name after the copy, -- if this content item is in CR file storage. The file name is based -- off of the item_id and revision_id and it will be invalid for the -- copied revision. update cr_revisions set content = (select content from cr_revisions where revision_id = content_copy.revision_id), filename = v_filename, content_length = v_content_length where revision_id = v_revision_id_dest; end if; end content_copy; end content_revision; / show errors create or replace package content_type AUTHID CURRENT_USER as --/** This package is used to manipulate content types and attributes -- --*/ procedure create_type ( --/** Create a new content type. Automatically create the attribute table -- for the type if the table does not already exist. -- @author Karl Goldstein -- @param content_type The name of the new type -- @param supertype The supertype, defaults to content_revision -- @param pretty_name Pretty name for the type, singular -- @param pretty_plural Pretty name for the type, plural -- @param table_name The name for the attribute table, defaults to -- the name of the supertype -- @param id_column The primary key for the table, defaults to 'XXX' -- @param name_method As in acs_object_type.create_type -- @see {acs_object_type.create_type} --*/ content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ); procedure drop_type ( --/** First drops all attributes related to a specific type, then drops type -- the given type. -- @author Simon Huynh -- @param content_type The content type to be dropped -- @param drop_children_p If 't', then the sub-types -- of the given content type and their associated tables -- are also dropped. --*/ content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f' ); function create_attribute ( --/** Create a new attribute for the specified type. Automatically create -- the column for the attribute if the column does not already exist. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to create -- @param pretty_name Pretty name for the new attribute, singular -- @param pretty_plural Pretty name for the new attribute, plural -- @param default_value The default value for the attribute, defaults to null -- @return The id of the newly created attribute -- @see {acs_object_type.create_attribute}, {content_type.create_type} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE; procedure drop_attribute ( --/** Drop an existing attribute. If you are using CMS, make sure to -- call cm_form_widget.unregister_attribute_widget before calling -- this function. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to drop -- @param drop_column If 't', will also alter the table and remove -- the column where the attribute is stored. The default is 'f' -- (leaves the table untouched). -- @see {acs_object.drop_attribute}, {content_type.create_attribute}, -- {cm_form_widget.unregister_attribute_widget} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ); procedure register_template ( --/** Register a template for the content type. This template may be used -- to render all items of that type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be registered -- @param template_id The ID of the template to register -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @param is_default If 't', this template becomes the default template for -- the type, default is 'f'. -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.set_default_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ); procedure set_default_template ( --/** Make the registered template a default template. The default template -- will be used to render all items of the type for which no individual -- template is registered. -- @author Karl Goldstein -- @param content_type The type for which the template is to be made default -- @param template_id The ID of the template to make default -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ); function get_template ( --/** Retrieve the appropriate template for rendering items of the specified type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be retrieved -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @return The ID of the template to use -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.set_default_template} --*/ content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; procedure unregister_template ( --/** Unregister a template. If the unregistered template was the default template, -- the content_type can no longer be rendered in the use_context, -- @author Karl Goldstein -- @param content_type The type for which the template is to be unregistered -- @param template_id The ID of the template to unregister -- @param use_context The context in which the template is to be unregistered -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.set_default_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ); procedure refresh_view ( --/** Create a view for the type which joins all attributes of the type, -- including the inherited attributes. The view is named -- "

X" -- Called by create_attribute and create_type. -- @author Karl Goldstein -- @param content_type The type for which the view is to be created. -- @see {content_type.create_type} --*/ content_type in cr_type_template_map.content_type%TYPE ); procedure register_relation_type ( --/** Register a relationship between a content type and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate any relationship between an item and another -- object. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.unregister_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_relation_type ( --/** Unregister a relationship between a content type and another object -- type. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ); procedure register_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of parent-child -- relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param parent_type The type of the parent item. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ); procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char; procedure rotate_template ( --/** Sets the default template for a content type and registers all the -- previously existing items of that content type to the original -- template -- @author Michael Pih -- @param template_id The template that will become the default -- registered template for the specified content type and use context -- @param v_content_type The content type -- @param use_context The context in which the template will be used --*/ template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ); -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ); end content_type; / show errors; create or replace package body content_type is procedure create_type ( content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ) is table_exists integer; v_supertype_table acs_object_types.table_name%TYPE; v_count integer; begin if (supertype != 'content_revision') and (content_type != 'content_revision') then select count(*) into v_count from acs_object_type_supertype_map where object_type = create_type.supertype and ancestor_type = 'content_revision'; if v_count = 0 then raise_application_error(-20000, 'Content types can only be created as subclasses of content_revision or a derivation thereof. ' || supertype || ' is not a subclass oc content_revision.'); end if; end if; -- create the attribute table if not already created select decode(count(*),0,0,1) into table_exists from user_tables where table_name = upper(create_type.table_name); if table_exists = 0 then select table_name into v_supertype_table from acs_object_types where object_type = create_type.supertype; execute immediate 'create table ' || table_name || ' (' || id_column || ' integer primary key references ' || v_supertype_table || ')'; end if; acs_object_type.create_type ( supertype => create_type.supertype, object_type => create_type.content_type, pretty_name => create_type.pretty_name, pretty_plural => create_type.pretty_plural, table_name => create_type.table_name, id_column => create_type.id_column, name_method => create_type.name_method ); refresh_view(content_type); end create_type; procedure drop_type ( content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f' ) is cursor attribute_cur is select attribute_name from acs_attributes where object_type = drop_type.content_type; cursor child_type_cur is select object_type from acs_object_types where supertype = drop_type.content_type; table_exists integer; v_table_name varchar2(50); is_subclassed_p char; begin -- first we'll rid ourselves of any dependent child types, if any , along with their -- own dependent grandchild types select decode(count(*),0,'f','t') into is_subclassed_p from acs_object_types where supertype = drop_type.content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children's packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_children_p = 't' and is_subclassed_p = 't' then for child_rec in child_type_cur loop drop_type( content_type => child_rec.object_type, drop_children_p => 't' ); end loop; end if; -- now drop all the attributes related to this type for attr_row in attribute_cur loop drop_attribute( content_type => drop_type.content_type, attribute_name => attr_row.attribute_name ); end loop; -- we'll remove the associated table if it exists select decode(count(*),0,0,1) into table_exists from user_tables u, acs_object_types objet where objet.object_type = drop_type.content_type and u.table_name = upper(objet.table_name); if table_exists = 1 and drop_table_p = 't' then select table_name into v_table_name from acs_object_types where object_type = drop_type.content_type; -- drop the input/output views for the type -- being dropped. -- FIXME: does the trigger get dropped when the -- view is dropped? This did not exist in the 4.2 release, -- and it needs to be tested. execute immediate 'drop view ' || v_table_name || 'x'; execute immediate 'drop view ' || v_table_name || 'i'; execute immediate 'drop table ' || v_table_name; end if; acs_object_type.drop_type( object_type => drop_type.content_type ); end drop_type; function create_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE is v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists integer; begin -- add the appropriate column to the table begin select upper(table_name) into v_table_name from acs_object_types where object_type = create_attribute.content_type; exception when no_data_found then raise_application_error(-20000, 'Content type ''' || content_type || ''' does not exist in content_type.create_attribute'); end; select decode(count(*),0,0,1) into v_column_exists from user_tab_columns where table_name = v_table_name and column_name = upper(attribute_name); if v_column_exists = 0 then execute immediate 'alter table ' || v_table_name || ' add ' || attribute_name || ' ' || column_spec; end if; v_attr_id := acs_attribute.create_attribute ( object_type => create_attribute.content_type, attribute_name => create_attribute.attribute_name, datatype => create_attribute.datatype, pretty_name => create_attribute.pretty_name, pretty_plural => create_attribute.pretty_plural, sort_order => create_attribute.sort_order, default_value => create_attribute.default_value ); refresh_view(content_type); return v_attr_id; end create_attribute; procedure drop_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ) is v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information begin select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute.content_type and a.object_type = drop_attribute.content_type and a.attribute_name = drop_attribute.attribute_name; exception when no_data_found then raise_application_error(-20000, 'Attribute ' || content_type || ':' || attribute_name || ' does not exist in content_type.drop_attribute'); end; -- Drop the attribute acs_attribute.drop_attribute(content_type, attribute_name); -- Drop the column if neccessary if drop_column = 't' then begin execute immediate 'alter table ' || v_table || ' drop column ' || attribute_name; exception when others then raise_application_error(-20000, 'Unable to drop column ' || v_table || '.' || attribute_name || ' in content_type.drop_attribute'); end; end if; refresh_view(content_type); end drop_attribute; procedure register_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ) is v_template_registered integer; begin select count(*) into v_template_registered from cr_type_template_map where content_type = register_template.content_type and use_context = register_template.use_context and template_id = register_template.template_id; -- register the template if v_template_registered = 0 then insert into cr_type_template_map ( template_id, content_type, use_context, is_default ) values ( template_id, content_type, use_context, is_default ); -- update the registration status of the template else -- unset the default template before setting this one as the default if register_template.is_default = 't' then update cr_type_template_map set is_default = 'f' where content_type = register_template.content_type and use_context = register_template.use_context; end if; update cr_type_template_map set is_default = register_template.is_default where template_id = register_template.template_id and content_type = register_template.content_type and use_context = register_template.use_context; end if; end register_template; procedure set_default_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is begin update cr_type_template_map set is_default = 't' where template_id = set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context; -- make sure there is only one default template for -- any given content_type/use_context pair update cr_type_template_map set is_default = 'f' where template_id ^= set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context and is_default = 't'; end set_default_template; function get_template ( content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template.content_type and use_context = get_template.use_context and is_default = 't'; return v_template_id; exception when NO_DATA_FOUND then return null; end get_template; procedure unregister_template ( content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ) is begin if unregister_template.use_context is null and unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id; elsif unregister_template.use_context is null then delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type; elsif unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id and use_context = unregister_template.use_context; else delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type and use_context = unregister_template.use_context; end if; end unregister_template; -- Helper function for refresh_trigger (below) to generate the -- insert statement for a particular content type; function trigger_insert_statement ( content_type in acs_object_types.object_type%TYPE ) return varchar2 is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = trigger_insert_statement.content_type; cols varchar2(2000) := ''; vals varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; vals := vals || ', :new.' || attr_rec.attribute_name; end loop; return 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) values ( new_revision_id' || vals || ')'; end trigger_insert_statement; -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ) is tr_text varchar2(10000) := ''; v_table_name acs_object_types.table_name%TYPE; cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = refresh_trigger.content_type order by level desc; begin -- get the table name for the content type (determines view name) select table_name into v_table_name from acs_object_types where object_type = refresh_trigger.content_type; -- start building trigger code tr_text := ' create or replace trigger ' || v_table_name || 't instead of insert on ' || v_table_name || 'i for each row declare new_revision_id integer; begin if :new.item_id is null then raise_application_error(-20000, ''item_id is required when inserting into ' || v_table_name || 'i ''); end if; if :new.text is not null then new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, text => :new.text, package_id => :new.object_package_id ); else new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, data => :new.data, package_id => :new.object_package_id ); end if;'; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in type_cur loop tr_text := tr_text || ' ' || trigger_insert_statement(type_rec.object_type) || '; '; end loop; -- end building the trigger code tr_text := tr_text || ' end ' || v_table_name || 't;'; -- (Re)create the trigger execute immediate tr_text; end refresh_trigger; -- Create or replace a view joining all attribute tables procedure refresh_view ( content_type in cr_type_template_map.content_type%TYPE ) is -- exclude the BLOB column because it will make it impossible -- to do a select * cursor join_cur is select distinct lower(table_name) as table_name, id_column, level from acs_object_types where object_type <> 'acs_object' and object_type <> 'content_revision' and lower(table_name) <> 'acs_objects' and lower(table_name) <> 'cr_revisions' start with object_type = refresh_view.content_type connect by object_type = prior supertype; cols varchar2(1000); tabs varchar2(1000); joins varchar2(1000) := ''; v_table_name varchar2(40); begin for join_rec in join_cur loop cols := cols || ', ' || join_rec.table_name || '.*'; tabs := tabs || ', ' || join_rec.table_name; joins := joins || ' and acs_objects.object_id = ' || join_rec.table_name || '.' || join_rec.id_column; end loop; select table_name into v_table_name from acs_object_types where object_type = content_type; -- create the input view (includes content columns) execute immediate 'create or replace view ' || v_table_name || 'i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.content as data, cr_text.text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language' || cols || ' from acs_objects, cr_revisions cr, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id ' || joins; -- create the output view (excludes content columns to enable SELECT *) execute immediate 'create or replace view ' || v_table_name || 'x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id' || cols || ' from acs_objects, cr_revisions cr, cr_items i, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id' || joins; refresh_trigger(content_type); exception when others then dbms_output.put_line('Error creating attribute view or trigger for ' || content_type); end refresh_view; procedure register_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin select decode(count(*),0,0,1) into v_exists from cr_type_children where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; if v_exists = 0 then insert into cr_type_children ( parent_type, child_type, relation_tag, min_n, max_n ) values ( parent_type, child_type, relation_tag, min_n, max_n ); else update cr_type_children set min_n = register_child_type.min_n, max_n = register_child_type.max_n where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; end if; end register_child_type; procedure unregister_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ) is begin delete from cr_type_children where parent_type = unregister_child_type.parent_type and child_type = unregister_child_type.child_type and relation_tag = unregister_child_type.relation_tag; end unregister_child_type; procedure register_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin -- check if the relation type exists select decode(count(*),0,0,1) into v_exists from cr_type_relations where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; -- if the relation type does not exist, insert a row into cr_type_relations if v_exists = 0 then insert into cr_type_relations ( content_type, target_type, relation_tag, min_n, max_n ) values ( content_type, target_type, relation_tag, min_n, max_n ); -- otherwise, update the row in cr_type_relations else update cr_type_relations set min_n = register_relation_type.min_n, max_n = register_relation_type.max_n where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; end if; end register_relation_type; procedure unregister_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ) is begin delete from cr_type_relations where content_type = unregister_relation_type.content_type and target_type = unregister_relation_type.target_type and relation_tag = unregister_relation_type.relation_tag; end unregister_relation_type; procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is v_valid_registration integer; begin -- check if this type is already registered select count(*) into v_valid_registration from cr_mime_types where not exists ( select 1 from cr_content_mime_type_map where mime_type = register_mime_type.mime_type and content_type = register_mime_type.content_type ) and mime_type = register_mime_type.mime_type; if v_valid_registration = 1 then insert into cr_content_mime_type_map ( content_type, mime_type ) values ( register_mime_type.content_type, register_mime_type.mime_type ); end if; end register_mime_type; procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is begin delete from cr_content_mime_type_map where content_type = unregister_mime_type.content_type and mime_type = unregister_mime_type.mime_type; end unregister_mime_type; function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char is v_is_content_type char(1) := 'f'; begin if object_type = 'content_revision' then v_is_content_type := 't'; else select decode(count(*),0,'f','t') into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type.object_type and ancestor_type = 'content_revision'; end if; return v_is_content_type; end is_content_type; procedure rotate_template ( template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is v_template_id cr_templates.template_id%TYPE; -- items that have an associated default template but not at the item level cursor c_items_cursor is select item_id from cr_items i, cr_type_template_map m where i.content_type = rotate_template.v_content_type and m.use_context = rotate_template.use_context and i.content_type = m.content_type and not exists ( select 1 from cr_item_template_map where item_id = i.item_id and use_context = rotate_template.use_context ); begin -- get the default template select template_id into v_template_id from cr_type_template_map where content_type = rotate_template.v_content_type and use_context = rotate_template.use_context and is_default = 't'; if v_template_id is not null then -- register an item-template to all items without an item-template for v_items_val in c_items_cursor loop content_item.register_template ( item_id => v_items_val.item_id, template_id => v_template_id, use_context => rotate_template.use_context ); end loop; end if; -- register the new template as the default template of the content type if v_template_id ^= rotate_template.template_id then content_type.register_template( content_type => rotate_template.v_content_type, template_id => rotate_template.template_id, use_context => rotate_template.use_context, is_default => 't' ); end if; end rotate_template; end content_type; / show errors -- Refresh the attribute triggers begin for type_rec in (select object_type,table_name from acs_object_types connect by supertype = prior object_type start with object_type = 'content_revision') loop if table_exists(type_rec.table_name) then content_type.refresh_view(type_rec.object_type); end if; end loop; end; / show errors; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0b6-5.2.0b7.sql0000644000175000017500000003607010440426443030637 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0b6-5.2.0b7.sql -- -- @author eraffenne@innova.uned.es -- @creation-date 2006-03-17 -- @cvs-id $Id: upgrade-5.2.0b6-5.2.0b7.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- -- replace package create or replace package content_extlink as function new ( name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure del ( extlink_id in cr_extlinks.extlink_id%TYPE ); function is_extlink ( item_id in cr_items.item_id%TYPE ) return char; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); end content_extlink; / show errors -- replace package body create or replace package body content_extlink as function new ( name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_label cr_extlinks.label%TYPE; v_name cr_items.name%TYPE; begin if label is null then v_label := url; else v_label := label; end if; if name is null then select acs_object_id_seq.nextval into v_extlink_id from dual; v_name := 'link' || v_extlink_id; else v_name := name; end if; if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_extlink_id := content_item.new( item_id => content_extlink.new.extlink_id, name => v_name, package_id => v_package_id, content_type => 'content_extlink', creation_date => content_extlink.new.creation_date, creation_user => content_extlink.new.creation_user, creation_ip => content_extlink.new.creation_ip, parent_id => content_extlink.new.parent_id ); insert into cr_extlinks (extlink_id, url, label, description) values (v_extlink_id, content_extlink.new.url, v_label, content_extlink.new.description); update acs_objects set title = v_label where object_id = v_extlink_id; return v_extlink_id; end new; procedure del ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin delete from cr_extlinks where extlink_id = content_extlink.del.extlink_id; content_item.del(content_extlink.del.extlink_id); end del; function is_extlink ( item_id in cr_items.item_id%TYPE ) return char is v_extlink_p integer := 0; begin select count(1) into v_extlink_p from cr_extlinks where extlink_id = is_extlink.item_id; if v_extlink_p = 1 then return 't'; else return 'f'; end if; end is_extlink; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_label cr_extlinks.label%TYPE; v_description cr_extlinks.description%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder.is_folder(copy.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy.extlink_id; select i.name, e.url, e.label, e.description into v_name, v_url, v_label, v_description from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy.extlink_id; -- can't copy to the same folder if copy.target_folder_id ^= v_current_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; if content_folder.is_registered(copy.target_folder_id, 'content_extlink') = 't' then v_extlink_id := content_extlink.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, description => v_description, url => v_url, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end if; end if; end if; end copy; end content_extlink; / show errors -- Add package_id to image pl/sql package create or replace package image as function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE ) return cr_items.item_id%TYPE; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE ) return cr_revisions.revision_id%TYPE; --/** -- Deletes a single revision of image -- Schedules binary file for deletion. -- File delete sweep checks to see if no other images are using binary prior to deleting --*/ procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ); --/** -- Deletes a image and all revisions -- Schedules binary files for deletion. -- -- Be careful, cannot be undone (easily) --*/ procedure del ( item_id in cr_items.item_id%TYPE ); end image; / show errors; create or replace package body image as function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, content_type in acs_object_types.object_type%TYPE default 'image', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, locale in cr_items.locale%TYPE default null, context_id in acs_objects.context_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE ) return cr_items.item_id%TYPE is v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_item_id := content_item.new ( name => name, item_id => item_id, parent_id => parent_id, package_id => v_package_id, relation_tag => relation_tag, content_type => content_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, locale => locale, context_id => context_id, storage_type => storage_type ); v_revision_id := content_revision.new ( title => title, description => description, item_id => v_item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => sysdate, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_item_id; end new; function new_revision ( item_id in acs_objects.object_id%TYPE default null, revision_id in acs_objects.object_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default null, nls_language in cr_revisions.nls_language%TYPE default null, is_live in char default 'f', publish_date in cr_revisions.publish_date%TYPE default sysdate, data in cr_revisions.content%TYPE default null, filename in cr_revisions.filename%TYPE default null, height in images.height%TYPE default null, width in images.width%TYPE default null, file_size in cr_revisions.content_length%TYPE default null, package_id in acs_objects.package_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new_revision.item_id); else v_package_id := package_id; end if; v_revision_id := content_revision.new ( title => title, description => description, item_id => item_id, revision_id => revision_id, package_id => v_package_id, publish_date => publish_date, mime_type => mime_type, nls_language => nls_language, data => data, filename => filename, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); insert into images (image_id, height, width) values (v_revision_id, height, width); -- update revision with image file info update cr_revisions set content_length = file_size where revision_id = v_revision_id; -- is_live => 't' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if is_live = 't' then content_item.set_live_revision ( revision_id => v_revision_id ); end if; return v_revision_id; end new_revision; procedure delete_revision ( revision_id in cr_revisions.revision_id%TYPE ) is v_content cr_files_to_delete.path%TYPE default null; begin content_revision.del ( revision_id => revision_id ); end delete_revision; procedure del ( item_id in cr_items.item_id%TYPE ) is cursor image_revision_cur is select revision_id from cr_revisions where item_id = image.del.item_id order by revision_id asc; -- order by used in cursur so latest revision will be deleted last -- save resetting latest revision multiple times during delete process begin for v_revision_val in image_revision_cur loop image.delete_revision ( revision_id => v_revision_val.revision_id ); end loop; content_item.del ( item_id => item_id ); end del; end image; / show errors; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.4.0d1-5.4.0d2.sql0000755000175000017500000000015511022567577030646 0ustar frankiefrankie-- Introduces some changes from Quest CREATE UNIQUE INDEX CR_CHILD_RELS_kids_IDx ON CR_CHILD_RELS(CHILD_ID); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.6.0d2-5.6.0d3.sql0000644000175000017500000006422211307261467030651 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2009-10-12 -- @cvs-id $Id: upgrade-5.6.0d2-5.6.0d3.sql,v 1.2 2009/12/07 20:19:03 daveb Exp $ -- create or replace package body content_type is procedure create_type ( content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ) is table_exists integer; v_supertype_table acs_object_types.table_name%TYPE; v_count integer; begin if (supertype != 'content_revision') and (content_type != 'content_revision') then select count(*) into v_count from acs_object_type_supertype_map where object_type = create_type.supertype and ancestor_type = 'content_revision'; if v_count = 0 then raise_application_error(-20000, 'Content types can only be created as subclasses of content_revision or a derivation thereof. ' || supertype || ' is not a subclass oc content_revision.'); end if; end if; -- create the attribute table if not already created select decode(count(*),0,0,1) into table_exists from user_tables where table_name = upper(create_type.table_name); if table_exists = 0 and create_type.table_name is not null then select table_name into v_supertype_table from acs_object_types where object_type = create_type.supertype; execute immediate 'create table ' || table_name || ' (' || id_column || ' integer primary key references ' || v_supertype_table || ')'; end if; acs_object_type.create_type ( supertype => create_type.supertype, object_type => create_type.content_type, pretty_name => create_type.pretty_name, pretty_plural => create_type.pretty_plural, table_name => create_type.table_name, id_column => create_type.id_column, name_method => create_type.name_method ); refresh_view(content_type); end create_type; procedure drop_type ( content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f', drop_objects_p in char default 'f' ) is cursor attribute_cur is select attribute_name from acs_attributes where object_type = drop_type.content_type; cursor child_type_cur is select object_type from acs_object_types where supertype = drop_type.content_type; cursor revision_cur is select revision_id from cr_revisions, acs_objects where revision_id = object_id and object_type = drop_type.content_type; cursor item_cur is select item_id from cr_items where content_type = drop_type.content_type; table_exists integer; v_table_name varchar2(50); is_subclassed_p char; begin -- first we'll rid ourselves of any dependent child types, if any , along with their -- own dependent grandchild types select decode(count(*),0,'f','t') into is_subclassed_p from acs_object_types where supertype = drop_type.content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children's packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_children_p = 't' and is_subclassed_p = 't' then for child_rec in child_type_cur loop drop_type( content_type => child_rec.object_type, drop_children_p => 't', drop_table_p => drop_table_p, drop_objects_p => drop_objects_p ); end loop; end if; -- now drop all the attributes related to this type for attr_row in attribute_cur loop drop_attribute( content_type => drop_type.content_type, attribute_name => attr_row.attribute_name ); end loop; -- we'll remove the associated table if it exists select decode(count(*),0,0,1) into table_exists from user_tables u, acs_object_types objet where objet.object_type = drop_type.content_type and u.table_name = upper(objet.table_name); if table_exists = 1 and drop_table_p = 't' then select nvl(table_name,object_type) into v_table_name from acs_object_types where object_type = drop_type.content_type; -- drop the input/output views for the type -- being dropped. -- FIXME: does the trigger get dropped when the -- view is dropped? This did not exist in the 4.2 release, -- and it needs to be tested. execute immediate 'drop view ' || v_table_name || 'x'; execute immediate 'drop view ' || v_table_name || 'i'; execute immediate 'drop table ' || v_table_name; end if; if drop_objects_p = 't' then for revision_row in revision_cur loop content_revision.del( revision_id => revision_row.revision_id ); end loop; for item_row in item_cur loop content_item.del( item_id => item_row.item_id ); end loop; end if; acs_object_type.drop_type( object_type => drop_type.content_type ); end drop_type; function create_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE is v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists integer; begin -- add the appropriate column to the table begin select upper(table_name) into v_table_name from acs_object_types where object_type = create_attribute.content_type; exception when no_data_found then raise_application_error(-20000, 'Content type ''' || content_type || ''' does not exist in content_type.create_attribute'); end; select decode(count(*),0,0,1) into v_column_exists from user_tab_columns where table_name = v_table_name and column_name = upper(attribute_name); if v_column_exists = 0 then execute immediate 'alter table ' || v_table_name || ' add ' || attribute_name || ' ' || column_spec; end if; v_attr_id := acs_attribute.create_attribute ( object_type => create_attribute.content_type, attribute_name => create_attribute.attribute_name, datatype => create_attribute.datatype, pretty_name => create_attribute.pretty_name, pretty_plural => create_attribute.pretty_plural, sort_order => create_attribute.sort_order, default_value => create_attribute.default_value ); refresh_view(content_type); return v_attr_id; end create_attribute; procedure drop_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ) is v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information begin select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute.content_type and a.object_type = drop_attribute.content_type and a.attribute_name = drop_attribute.attribute_name; exception when no_data_found then raise_application_error(-20000, 'Attribute ' || content_type || ':' || attribute_name || ' does not exist in content_type.drop_attribute'); end; -- Drop the attribute acs_attribute.drop_attribute(content_type, attribute_name); -- Drop the column if neccessary if drop_column = 't' then begin execute immediate 'alter table ' || v_table || ' drop column ' || attribute_name; exception when others then raise_application_error(-20000, 'Unable to drop column ' || v_table || '.' || attribute_name || ' in content_type.drop_attribute'); end; end if; refresh_view(content_type); end drop_attribute; procedure register_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ) is v_template_registered integer; begin select count(*) into v_template_registered from cr_type_template_map where content_type = register_template.content_type and use_context = register_template.use_context and template_id = register_template.template_id; -- register the template if v_template_registered = 0 then insert into cr_type_template_map ( template_id, content_type, use_context, is_default ) values ( template_id, content_type, use_context, is_default ); -- update the registration status of the template else -- unset the default template before setting this one as the default if register_template.is_default = 't' then update cr_type_template_map set is_default = 'f' where content_type = register_template.content_type and use_context = register_template.use_context; end if; update cr_type_template_map set is_default = register_template.is_default where template_id = register_template.template_id and content_type = register_template.content_type and use_context = register_template.use_context; end if; end register_template; procedure set_default_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is begin update cr_type_template_map set is_default = 't' where template_id = set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context; -- make sure there is only one default template for -- any given content_type/use_context pair update cr_type_template_map set is_default = 'f' where template_id ^= set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context and is_default = 't'; end set_default_template; function get_template ( content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template.content_type and use_context = get_template.use_context and is_default = 't'; return v_template_id; exception when NO_DATA_FOUND then return null; end get_template; procedure unregister_template ( content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ) is begin if unregister_template.use_context is null and unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id; elsif unregister_template.use_context is null then delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type; elsif unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id and use_context = unregister_template.use_context; else delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type and use_context = unregister_template.use_context; end if; end unregister_template; -- Helper function for refresh_trigger (below) to generate the -- insert statement for a particular content type; function trigger_insert_statement ( content_type in acs_object_types.object_type%TYPE ) return varchar2 is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = trigger_insert_statement.content_type; cols varchar2(2000) := ''; vals varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; vals := vals || ', :new.' || attr_rec.attribute_name; end loop; return 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) values ( new_revision_id' || vals || ')'; end trigger_insert_statement; -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ) is tr_text varchar2(10000) := ''; v_table_name acs_object_types.table_name%TYPE; cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' and table_name is not null connect by prior supertype = object_type start with object_type = refresh_trigger.content_type order by level desc; begin -- get the table name for the content type (determines view name) select nvl(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_trigger.content_type; -- start building trigger code tr_text := ' create or replace trigger ' || v_table_name || 't instead of insert on ' || v_table_name || 'i for each row declare new_revision_id integer; begin if :new.item_id is null then raise_application_error(-20000, ''item_id is required when inserting into ' || v_table_name || 'i ''); end if; if :new.text is not null then new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, text => :new.text, package_id => :new.object_package_id ); else new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, data => :new.data, package_id => :new.object_package_id ); end if;'; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in type_cur loop tr_text := tr_text || ' ' || trigger_insert_statement(type_rec.object_type) || '; '; end loop; -- end building the trigger code tr_text := tr_text || ' end ' || v_table_name || 't;'; -- (Re)create the trigger execute immediate tr_text; end refresh_trigger; -- Create or replace a view joining all attribute tables procedure refresh_view ( content_type in cr_type_template_map.content_type%TYPE ) is -- exclude the BLOB column because it will make it impossible -- to do a select * cursor join_cur is select distinct lower(table_name) as table_name, id_column, level from acs_object_types where object_type <> 'acs_object' and object_type <> 'content_revision' and lower(table_name) <> 'acs_objects' and lower(table_name) <> 'cr_revisions' start with object_type = refresh_view.content_type connect by object_type = prior supertype; cols varchar2(1000); tabs varchar2(1000); joins varchar2(1000) := ''; v_table_name varchar2(40); begin for join_rec in join_cur loop cols := cols || ', ' || join_rec.table_name || '.*'; tabs := tabs || ', ' || join_rec.table_name; joins := joins || ' and acs_objects.object_id = ' || join_rec.table_name || '.' || join_rec.id_column; end loop; select nvl(table_name,object_type) into v_table_name from acs_object_types where object_type = content_type; -- create the input view (includes content columns) execute immediate 'create or replace view ' || v_table_name || 'i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.content as data, cr_text.text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language' || cols || ' from acs_objects, cr_revisions cr, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id ' || joins; -- create the output view (excludes content columns to enable SELECT *) execute immediate 'create or replace view ' || v_table_name || 'x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id' || cols || ' from acs_objects, cr_revisions cr, cr_items i, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id' || joins; refresh_trigger(content_type); exception when others then dbms_output.put_line('Error creating attribute view or trigger for ' || content_type); end refresh_view; procedure register_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin select decode(count(*),0,0,1) into v_exists from cr_type_children where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; if v_exists = 0 then insert into cr_type_children ( parent_type, child_type, relation_tag, min_n, max_n ) values ( parent_type, child_type, relation_tag, min_n, max_n ); else update cr_type_children set min_n = register_child_type.min_n, max_n = register_child_type.max_n where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; end if; end register_child_type; procedure unregister_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ) is begin delete from cr_type_children where parent_type = unregister_child_type.parent_type and child_type = unregister_child_type.child_type and relation_tag = unregister_child_type.relation_tag; end unregister_child_type; procedure register_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin -- check if the relation type exists select decode(count(*),0,0,1) into v_exists from cr_type_relations where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; -- if the relation type does not exist, insert a row into cr_type_relations if v_exists = 0 then insert into cr_type_relations ( content_type, target_type, relation_tag, min_n, max_n ) values ( content_type, target_type, relation_tag, min_n, max_n ); -- otherwise, update the row in cr_type_relations else update cr_type_relations set min_n = register_relation_type.min_n, max_n = register_relation_type.max_n where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; end if; end register_relation_type; procedure unregister_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ) is begin delete from cr_type_relations where content_type = unregister_relation_type.content_type and target_type = unregister_relation_type.target_type and relation_tag = unregister_relation_type.relation_tag; end unregister_relation_type; procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is v_valid_registration integer; begin -- check if this type is already registered select count(*) into v_valid_registration from cr_mime_types where not exists ( select 1 from cr_content_mime_type_map where mime_type = register_mime_type.mime_type and content_type = register_mime_type.content_type ) and mime_type = register_mime_type.mime_type; if v_valid_registration = 1 then insert into cr_content_mime_type_map ( content_type, mime_type ) values ( register_mime_type.content_type, register_mime_type.mime_type ); end if; end register_mime_type; procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is begin delete from cr_content_mime_type_map where content_type = unregister_mime_type.content_type and mime_type = unregister_mime_type.mime_type; end unregister_mime_type; function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char is v_is_content_type char(1) := 'f'; begin if object_type = 'content_revision' then v_is_content_type := 't'; else select decode(count(*),0,'f','t') into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type.object_type and ancestor_type = 'content_revision'; end if; return v_is_content_type; end is_content_type; procedure rotate_template ( template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is v_template_id cr_templates.template_id%TYPE; -- items that have an associated default template but not at the item level cursor c_items_cursor is select item_id from cr_items i, cr_type_template_map m where i.content_type = rotate_template.v_content_type and m.use_context = rotate_template.use_context and i.content_type = m.content_type and not exists ( select 1 from cr_item_template_map where item_id = i.item_id and use_context = rotate_template.use_context ); begin -- get the default template select template_id into v_template_id from cr_type_template_map where content_type = rotate_template.v_content_type and use_context = rotate_template.use_context and is_default = 't'; if v_template_id is not null then -- register an item-template to all items without an item-template for v_items_val in c_items_cursor loop content_item.register_template ( item_id => v_items_val.item_id, template_id => v_template_id, use_context => rotate_template.use_context ); end loop; end if; -- register the new template as the default template of the content type if v_template_id ^= rotate_template.template_id then content_type.register_template( content_type => rotate_template.v_content_type, template_id => rotate_template.template_id, use_context => rotate_template.use_context, is_default => 't' ); end if; end rotate_template; end content_type; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.6.3-4.6.4.sql0000644000175000017500000000046707631426606030205 0ustar frankiefrankie-- Upgrade script -- -- @author Lars Pind -- @created 2003-01-27 insert into cr_mime_types(label, mime_type, file_extension) values ('Enhanced text', 'text/enhanced', 'etxt'); insert into cr_mime_types(label, mime_type, file_extension) values ('Fixed-width text', 'text/fixed-width', 'ftxt'); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.4.2b1-5.4.2b2.sql0000644000175000017500000000031411022567577030640 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2008-05-13 -- @cvs-id $Id: upgrade-5.4.2b1-5.4.2b2.sql,v 1.2 2008/06/07 20:28:47 donb Exp $ -- drop table cr_doc_filter;openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.5.0d2-5.5.0d3.sql0000644000175000017500000004242011100351226030623 0ustar frankiefrankie-- -- -- -- @author Victor Guerra (vguerra@wu-wien.ac.at) -- @creation-date 2008-10-21 -- @cvs-id $Id: upgrade-5.5.0d2-5.5.0d3.sql,v 1.2 2008/10/24 13:50:14 victorg Exp $ -- create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = security context root means that this is a mount point if parent_id ^= -4 and content_folder.is_folder(parent_id) = 'f' and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id, security_inherit_p => security_inherit_p, package_id => package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, label, description, package_id ); -- set the correct object title update acs_objects set title = new.label where object_id = v_folder_id; -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null then update acs_objects set title = edit_name.label where object_id = edit_name.folder_id; end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.copy - Cannot copy root folder'); end if; select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.copy - Not valid folder(s)'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.copy - Cannot copy a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.copy - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.copy - Destination folder does not allow subfolders'); end if; -- get the source folder info select name, label, description, parent_id into v_name, v_label, v_description, v_current_folder_id from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if v_current_folder_id = copy__target_folder_id and (v_name = copy.name or copy.name is null) then raise EXCEPTION ''-20000: content_folder.copy - Destination folder is parent folder''; end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := -4; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; if v_parent_id = folder_id then v_sub_folder_p := 't'; end if; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.7.0d3-5.7.0d4.sql0000644000175000017500000000156011555114410030637 0ustar frankiefrankiedeclare attr_id acs_attributes.attribute_id%TYPE; exists_p integer; begin select count(*) into exists_p from acs_attributes where object_type = 'content_revision' and attribute_name = 'item_id'; if exists_p = 0 then attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'item_id', datatype => 'integer', pretty_name => 'Item id', pretty_plural => 'Item ids' ); end if; select count(*) into exists_p from acs_attributes where object_type = 'content_revision' and attribute_name = 'content'; if exists_p = 0 then attr_id := content_type.create_attribute ( content_type => 'content_revision', attribute_name => 'content', datatype => 'text', pretty_name => 'content', pretty_plural => 'content' ); end if; end; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.6-4.6.1.sql0000644000175000017500000000037407661402012030022 0ustar frankiefrankie-- -- Adds the */* mime type as "Unknown" (added to content-create.sql by lars -- insert into cr_mime_types(label, mime_type, file_extension) select 'Unkown', '*/*', '' from dual where not exists (select 1 from cr_mime_types where mime_type = '*/*'); openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.5d2-5.1.5d3.sql0000644000175000017500000026420410540362705030646 0ustar frankiefrankiecreate or replace package content_item as --/** --Content items store the overview of the content published on a --website. The actual content is stored in content revisions. It is --implemented this way so that there can be mulitple versions of the --actual content while the main idea remains constant. For example: If --there is a review for the movie "Terminator," there will exist a --content item by the name "terminator" with all the right parameters --(supertype, parent, etc), there will also exist at least one content --revision pointing to this item with the actual review content. --@see {content_revision}, {content_folder} --*/ c_root_folder_id constant integer := -100; function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content item. If the data, title or text -- parameters are specified, also creates a revision for the item. -- @author Karl Goldstein -- @param name The name for the item, must be URL-encoded. -- If an item with this name already exists under the specified -- parent item, an error is thrown -- @param parent_id The parent of this item, defaults to null -- @param item_id The id of the new item. A new id will be allocated if this -- parameter is null -- @param locale The locale for this item, for use with Intermedia search -- @param item_subtype The type of the new item, defaults to 'content_item' -- This parameter is used to support inheritance, so that -- subclasses of content_item can call this function -- to initialize the parent class -- @param content_type The content type for the item, defaults to -- 'content_revision'. Only objects of this type -- may be used as revisions for the item -- @param title The user-readable title for the item, defaults to the item's -- name -- @param description A short description for the item (4000 characters maximum) -- @param mime_type The file type of the item, defaults to 'text/plain' -- @param nls_language The language for the item, used for Intermedia search -- @param text The text content of the new revision, 4000 charcters maximum. -- Cannot be specified simultaneously with the data -- parameter -- @param data The blob content of the new revision. Cannot be specified -- simultaneously with the text parameter -- @param relation_tag If a parent-child relationship is registered -- for these content types, use this tag to -- describe the parent-child relationship. Defaults -- to 'parent content type'-'child content type' -- @param is_live If 't', the new revision will become live -- @param context_id Security context id, as in acs_object.new -- If null, defaults to parent_id, and copies permissions -- from the parent into the current item -- @param storage_type in ('lob','file'). Indicates how content is to be stored. -- 'file' content is stored externally in the file system. -- @param others As in acs_object.new -- @return The id of the newly created item -- @see {acs_object.new} --*/ name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't' ) return cr_items.item_id%TYPE; function is_published ( --/** Determins whether an item is published or not. -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is published, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE ) return char; function is_publishable ( --/** Determines if an item is publishable. Publishable items must -- meet the following criteria: -- 1) for each child type, the item has n children, min_n < n < max_n -- 2) for each relation type, the item has n relations, min_n < n < max_n -- 3) any 'publishing_wf' workflows are finished -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is publishable in it's present state, -- Otherwise, returns 'f' --*/ item_id in cr_items.item_id%TYPE ) return char; function is_valid_child ( --/** Determines if an item would be a valid child of another item by -- checking if the parent allows children of the would-be child's -- content type and if the parent already has n_max children of -- that content type. -- @author Michael Pih -- @param item_id The item ID of the potential parent -- @param content_type The content type of the potential child item -- @return 't' if the item would be a valid child, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char; procedure del ( --/** Deletes the specified content item, along with any revisions, symlinks, -- workflows, associated templates, associated keywords, -- child and item relationships for the item. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param item_id The id of the item to delete -- @see {acs_object.delete} --*/ item_id in cr_items.item_id%TYPE ); procedure edit_name ( --/** Renames the item. If an item with the specified name already exists -- under this item's parent, an error is thrown -- @author Karl Goldstein -- @param item_id The id of the item to rename -- @param name The new name for the item, must be URL-encoded -- @see {content_item.new} --*/ item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ); function get_id ( --/** Takes in a path, such as "/tv/programs/star_trek/episode_203" -- and returns the id of the item with this path. Note: URLs are abstract (no -- extensions are allowed in content item names and extensions are stripped when -- looking up content items) -- @author Karl Goldstein -- @param item_path The path to be resolved -- @param root_folder_id Starts path resolution from this folder. Defaults to -- the root of the sitemap -- @param resolve_index Boolean flag indicating whether to return the -- id of the index page for folders (if one -- exists). Defaults to 'f'. -- @return The id of the item with the given path, or null if no such item exists -- @see {content_item.get_path} --*/ item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE; function get_path ( --/** Retrieves the full path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Karl Goldstein -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The path to the item -- @see {content_item.get_id}, {content_item.write_to_file} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2; function get_virtual_path ( --/** Retrieves the virtual path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Michael Pih -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The virtual path to the item -- @see {content_item.get_id}, {content_item.write_to_file}, {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2; procedure write_to_file ( --/** Writes the content of the live revision of this item to a file, -- creating all the neccessary directories in the process -- @author Karl Goldstein -- @param item_id The item to be written to a file -- @param root_path The path in the filesystem to which the root of the -- sitemap corresponds -- @see {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_path in varchar2 ); procedure register_template ( --/** Registers a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be registered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.unregister_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ); procedure unregister_template ( --/** Unregisters a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.register_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ); function get_template ( --/** Retrieves the template which should be used to render this item. If no template -- is registered to specifically render the item in the given context, the -- default template for the item's type is returned. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param use_context The context in the item is to be rendered, such -- as 'admin' or 'public' -- @return The id of the registered template, or null if no template could be -- found -- @see {content_type.register_template}, {content_item.register_template}, --*/ item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; function get_live_revision ( --/** Retrieves the id of the live revision for the item -- @param item_id The item for which the live revision is to be retrieved -- @return The id of the live revision for this item, or null if no live revision -- exists -- @see {content_item.set_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; procedure set_live_revision ( --/** Make the specified revision the live revision for the item -- @author Karl Goldstein -- @param revision_id The id of the revision which is to become live -- for its corresponding item -- @see {content_item.get_live_revision} --*/ revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ); procedure unset_live_revision ( --/** Set the live revision to null for the item -- @author Michael Pih -- @param item_id The id of the item for which to unset the live revision -- @see {content_item.set_live_revision} item_id in cr_items.item_id%TYPE ); procedure set_release_period ( --/** Sets the release period for the item. This information may be -- used by applications to update the publishing status of items -- at periodic intervals. -- @author Karl Goldstein -- @param item_id The id the item. -- @param start_when The time and date when the item should be released. -- @param end_when The time and date when the item should be expired. --*/ item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ); function get_revision_count ( --/** Return the total count of revisions for this item -- @author Karl Goldstein -- @param item_id The id the item -- @return The number of revisions for this item -- @see {content_revision.new} --*/ item_id in cr_items.item_id%TYPE ) return number; -- Return the object type of this item function get_content_type ( --/** Retrieve the content type of this item. Only objects of this type may be -- used as revisions for the item. -- @author Karl Goldstein -- @param item_id The item for which the content type is to be retrieved -- @return The content type of the item --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; function get_context ( --/** Retrieve the parent of the given item -- @author Karl Goldstein -- @param item_id The item for which the parent is to be retrieved -- @return The id of the parent for this item --*/ item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE; procedure move ( --/** Move the specified item to a different folder. If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein -- @param item_id The item to be moved -- @param target_folder_id The new folder for the item -- @see {content_item.new}, {content_folder.new}, {content_item.copy} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function copy2 ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @return The item ID of the new copy. -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE; -- get the latest revision for an item function get_latest_revision ( --/** Retrieves the id of the latest revision for the item (as opposed to the live -- revision) -- @author Karl Goldstein -- @param item_id The item for which the latest revision is to be retrieved -- @return The id of the latest revision for this item, or null if no revisions -- exist -- @see {content_item.get_live_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_best_revision ( --/** Retrieves the id of the live revision for the item if one exists, -- otherwise retrieves the id of the latest revision if one exists. -- revision) -- @author Michael Pih -- @param item_id The item for which the revision is to be retrieved -- @return The id of the live or latest revision for this item, -- or null if no revisions exist -- @see {content_item.get_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_title ( --/** Retrieves the title for the item, using either the latest or the live revision. -- If the specified item is in fact a folder, return the folder's label. -- In addition, this function will automatically resolve symlinks. -- @author Karl Goldstein -- @param item_id The item for which the title is to be retrieved -- @param is_live If 't', use the live revision to get the title. Otherwise, -- use the latest revision. The default is 'f' -- @return The title of the item -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, -- {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE; function get_publish_date ( --/** Retrieves the publish date for the item -- @author Karl Goldstein -- @param item_id The item for which the publish date is to be retrieved -- @param is_live If 't', use the live revision for the item. Otherwise, use -- the latest revision. The default is 'f' -- @return The publish date for the item, or null if the item has no revisions -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE; function is_subclass ( --/** Determines if one type is a subclass of another. A class is always a subclass of -- itself. -- @author Karl Goldstein -- @param object_type The child class -- @param supertype The superclass -- @return 't' if the child class is a subclass of the superclass, 'f' otherwise -- @see {acs_object_type.create_type} --*/ object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char; function relate ( --/** Relates two content items -- @author Karl Goldstein -- @param item_id The item id -- @param object_id The item id of the related object -- @param relation_tag A tag to help identify the relation type, -- defaults to 'generic' -- @param order_n The order of this object among other objects -- of the same relation type, defaults to null. -- @param relation_type The object type of the relation, defaults to -- 'cr_item_rel' --*/ item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE; procedure unrelate ( --/** Delete the item relationship between two items -- @author Michael Pih -- @param rel_id The relationship id -- @see {content_item.relate} --*/ rel_id in cr_item_rels.rel_id%TYPE ); function is_index_page ( --/** Determine if the item is an index page for the specified folder. -- The item is an index page for the folder if it exists in the -- folder and its item name is "index". -- @author Karl Goldstein -- @param item_id The item id -- @param folder_id The folder id -- @return 't' if the item is an index page for the specified -- folder, 'f' otherwise -- @see {content_folder.get_index_page} --*/ item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2; function get_parent_folder ( --/** Get the parent folder. -- @author Michael Pih -- @param item_id The item id -- @return the folder_id of the parent folder, null otherwise --*/ item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE; end content_item; / show errors create or replace package content_folder as function new ( --/** Create a new folder -- @author Karl Goldstein -- @param label The label for the folder -- @param description A short description of the folder, 4000 characters maximum -- @param parent_id The parent of the folder -- @param folder_id The id of the new folder. A new id will be allocated by default -- @param context_id The context id. The parent id will be used as the default context -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created folder -- @see {acs_object.new}, {content_item.new} --*/ name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in cr_folders.package_id%TYPE default null ) return cr_folders.folder_id%TYPE; procedure del ( --/** Delete a folder. An error is thrown if the folder is not empty -- @author Karl Goldstein -- @param folder_id The id of the folder to delete -- @see {acs_object.delete}, {content_item.delete} --*/ folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ); procedure edit_name ( --/** Change the name, label and/or description of the folder -- @author Karl Goldstein -- @param folder_id The id of the folder to modify -- @param name The new name for the folder. An error will be thrown if -- an item with this name already exists under this folder's -- parent. If this parameter is null, the old name will be preserved -- @param label The new label for the folder. The old label will be preserved if -- this parameter is null -- @param label The new description for the folder. The old description -- will be preserved if this parameter is null -- @see {content_folder.new} --*/ folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ); procedure move ( --/** Recursively move the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be moved. -- @author Karl Goldstein -- @param folder_id The id of the folder to move -- @param target_folder_id The destination folder -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Recursively copy the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be copied -- @author Karl Goldstein -- @param folder_id The id of the folder to copy -- @param target_folder_id The destination folder -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defaults to null) -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function is_folder ( --/** Determine if the item is a folder -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a folder, 'f' otherwise -- @see {content_folder.new}, {content_folder.is_sub_folder} --*/ item_id in cr_items.item_id%TYPE ) return char; function is_sub_folder ( --/** Determine if the item target_folder_id is a subfolder of -- the item folder_id -- @author Karl Goldstein -- @param folder_id The superfolder id -- @param target_folder_id The subfolder id -- @return 't' if the item target_folder_id is a subfolder of -- the item folder_id, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char; function is_empty ( --/** Determine if the folder is empty -- @author Karl Goldstein -- @param folder_id The folder id -- @return 't' if the folder contains no subfolders or items, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE ) return varchar2; function is_root ( --/** Determine whether the folder is a root (has a parent_id of 0) -- @author Karl Goldstein -- @param folder_id The folder ID -- @return 't' if the folder is a root or 'f' otherwise --*/ folder_id in cr_folders.folder_id%TYPE ) return char; procedure register_content_type ( --/** Register a content type to the folder, if it is not already registered. -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be registered -- @see {content_folder.unregister_content_type}, -- {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); procedure unregister_content_type ( --/** Unregister a content type from the folder, if it has been registered. -- Only items of the registered type(s) may be added to the folder. -- If the folder already contains items of the type to be unregistered, the -- items remain in the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be unregistered -- @param include_subtypes If 't', all subtypes of content_type will be -- unregistered as well -- @see {content_folder.register_content_type}, {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); -- change this to is_type_registered function is_registered ( --/** Determines if a content type is registered to the folder -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be checked -- @param include_subtypes If 't', all subtypes of the content_type -- will be checked, returning 't' if all of them are registered. If 'f', -- only an exact match with content_type will be -- performed. -- @return 't' if the type is registered to this folder, 'f' otherwise -- @see {content_folder.register_content_type}, {content_folder.unregister_content_type}, --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2; function get_label ( --/** Returns the label for the folder. This function is the default name method -- for the folder object. -- @author Karl Goldstein -- @param folder_id The folder id -- @return The folder's label -- @see {acs_object_type.create_type}, the docs for the name_method parameter --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE; function get_index_page ( --/** Returns the item ID of the index page of the folder, null otherwise -- @author Michael Pih -- @param folder_id The folder id -- @return The item ID of the index page --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE; end content_folder; / show errors create or replace package body content_item as function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; begin if item_id is NULL then v_folder_id := c_root_folder_id; else select item_id into v_folder_id from cr_items where parent_id = 0 connect by prior parent_id = item_id start with item_id = get_root_folder.item_id; end if; return v_folder_id; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Could not find a root folder for item ID ' || item_id || '. ' || 'Either the item does not exist or its parent value is corrupted.'); end get_root_folder; function new ( name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't' ) return cr_items.item_id%TYPE is v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- if content_item.is_subclass(item_subtype,'content_item') = 'f' then -- raise_application_error(-20000, 'The object_type ' || item_subtype || -- ' does not inherit from content_item.'); -- end if; -- place the item in the context of the pages folder if no -- context specified if storage_type = 'text' then v_storage_type := 'lob'; else v_storage_type := storage_type; end if; if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- Determine context_id if context_id is null then v_context_id := v_parent_id; else v_context_id := context_id; end if; if v_parent_id = 0 or content_folder.is_folder(v_parent_id) = 't' then if v_parent_id ^= 0 and content_folder.is_registered( v_parent_id, content_item.new.content_type, 'f') = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not registered to this folder ' || v_parent_id); end if; elsif v_parent_id ^= 0 then begin -- Figure out the relation_tag to use if content_item.new.relation_tag is null then v_rel_tag := content_item.get_content_type(v_parent_id) || '-' || content_item.new.content_type; else v_rel_tag := content_item.new.relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if is_subclass(v_parent_type, 'content_item') = 't' and is_valid_child(v_parent_id, content_item.new.content_type, v_rel_tag) = 'f' then raise_application_error(-20000, 'This item''s content type ' || content_item.new.content_type || ' is not allowed in this container ' || v_parent_id); end if; exception when NO_DATA_FOUND then raise_application_error(-20000, 'Invalid parent ID ' || v_parent_id || ' specified in content_item.new'); end; end if; -- Create the object v_item_id := acs_object.new( object_id => content_item.new.item_id, object_type => content_item.new.item_subtype, context_id => v_context_id, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, security_inherit_p => content_item.new.security_inherit_p ); -- Turn off security inheritance if there is no security context --if context_id is null then -- update acs_objects set security_inherit_p = 'f' -- where object_id = v_item_id; --end if; insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, content_item.new.name, content_item.new.content_type, v_parent_id, v_storage_type ); -- if the parent is not a folder, insert into cr_child_rels -- We checked above before creating the object that it is a valid rel if v_parent_id ^= 0 and content_folder.is_folder(v_parent_id) = 'f' then v_rel_id := acs_object.new( object_type => 'cr_item_child_rel', context_id => v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if content_item.new.title is null then v_title := content_item.new.name; else v_title := content_item.new.title; end if; -- create the revision if data or title or text is not null -- note that the caller could theoretically specify both text -- and data, in which case the text is ignored. if content_item.new.data is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, data => content_item.new.data, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip, nls_language => content_item.new.nls_language ); elsif content_item.new.title is not null or content_item.new.text is not null then v_revision_id := content_revision.new( item_id => v_item_id, title => v_title, description => content_item.new.description, text => content_item.new.text, mime_type => content_item.new.mime_type, creation_date => content_item.new.creation_date, creation_user => content_item.new.creation_user, creation_ip => content_item.new.creation_ip ); end if; -- make the revision live if is_live is 't' if content_item.new.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; -- Have the new item inherit the permission of the parent item -- if no security context was specified --if parent_id is not null and context_id is null then -- content_permission.inherit_permissions ( -- parent_id, v_item_id, creation_user -- ); --end if; return v_item_id; end new; function is_published ( item_id in cr_items.item_id%TYPE ) return char is v_is_published char(1); begin select 't' into v_is_published from cr_items where live_revision is not null and publish_status = 'live' and item_id = is_published.item_id; return v_is_published; exception when NO_DATA_FOUND then return 'f'; end is_published; function is_publishable ( item_id in cr_items.item_id%TYPE ) return char is v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; -- get the child types registered to this content type cursor c_child_types is select child_type, min_n, max_n from cr_type_children where parent_type = content_item.get_content_type( is_publishable.item_id ); -- get the relation types registered to this content type cursor c_rel_types is select target_type, min_n, max_n from cr_type_relations where content_type = content_item.get_content_type( is_publishable.item_id ); -- get the publishing workflows associated with this content item -- there should only be 1 if CMS exists, otherwise 0 -- cursor c_pub_wf is -- select -- case_id, state -- from -- wf_cases -- where -- workflow_key = 'publishing_wf' -- and -- object_id = is_publishable.item_id; begin -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in c_child_types loop select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable.item_id and content_item.get_content_type( child_id ) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return 'f'; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return 'f'; end if; end loop; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n for v_rel_type in c_rel_types loop select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable.item_id and nvl(content_item.get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return 'f'; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return 'f'; end if; end loop; -- validate publishing workflows -- make sure any 'publishing_wf' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in c_pub_wf loop -- if v_pub_wf.state ^= 'finished' then -- return 'f'; -- end if; -- end loop; return 't'; exception when NO_DATA_FOUND then return 'f'; end is_publishable; function is_valid_child ( item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char is v_is_valid_child char(1); v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := 'f'; -- first check if content_type is a registered child_type begin select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item.get_content_type( is_valid_child.item_id ) and child_type = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); exception when NO_DATA_FOUND then return 'f'; end; -- if the max is null then infinite number is allowed if v_max_children is null then return 't'; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child.item_id and content_item.get_content_type( child_id ) = is_valid_child.content_type and (is_valid_child.relation_tag is null or is_valid_child.relation_tag = relation_tag); if v_n_children < v_max_children then v_is_valid_child := 't'; end if; return v_is_valid_child; exception when NO_DATA_FOUND then return 'f'; end is_valid_child; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ procedure del ( item_id in cr_items.item_id%TYPE ) is -- cursor c_wf_cases_cur is -- select -- case_id -- from -- wf_cases -- where -- object_id = item_id; cursor c_symlink_cur is select symlink_id from cr_symlinks where target_id = content_item.del.item_id; cursor c_revision_cur is select revision_id from cr_revisions where item_id = content_item.del.item_id; cursor c_rel_cur is select rel_id from cr_item_rels where item_id = content_item.del.item_id or related_object_id = content_item.del.item_id; cursor c_child_cur is select rel_id from cr_child_rels where child_id = content_item.del.item_id; cursor c_parent_cur is select rel_id, child_id from cr_child_rels where parent_id = content_item.del.item_id; -- this is strictly for debugging -- cursor c_error_cur is -- select -- object_id, object_type -- from -- acs_objects -- where -- context_id = content_item.delete.item_id; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- dbms_output.put_line('Deleting associated workflows...'); -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in c_wf_cases_cur loop -- workflow_case.delete(v_wf_cases_val.case_id); -- end loop; dbms_output.put_line('Deleting symlinks...'); -- 2) delete all symlinks to this item for v_symlink_val in c_symlink_cur loop content_symlink.del(v_symlink_val.symlink_id); end loop; dbms_output.put_line('Unscheduling item...'); delete from cr_release_periods where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated revisions...'); -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = content_item.del.item_id; for v_revision_val in c_revision_cur loop content_revision.del(v_revision_val.revision_id); end loop; dbms_output.put_line('Deleting associated item templates...'); -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting item relationships...'); -- Delete all relations on this item for v_rel_val in c_rel_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting child relationships...'); for v_rel_val in c_child_cur loop acs_rel.del(v_rel_val.rel_id); end loop; dbms_output.put_line('Deleting parent relationships...'); for v_rel_val in c_parent_cur loop acs_rel.del(v_rel_val.rel_id); content_item.del(v_rel_val.child_id); end loop; dbms_output.put_line('Deleting associated permissions...'); -- 5) delete associated permissions delete from acs_permissions where object_id = content_item.del.item_id; dbms_output.put_line('Deleting keyword associations...'); -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = content_item.del.item_id; dbms_output.put_line('Deleting associated comments...'); -- 7) delete associated comments journal_entry.delete_for_object( content_item.del.item_id ); -- context_id debugging loop --for v_error_val in c_error_cur loop -- dbms_output.put_line('ID=' || v_error_val.object_id || ' TYPE=' -- || v_error_val.object_type); --end loop; dbms_output.put_line('Deleting content item...'); acs_object.del(content_item.del.item_id); end del; procedure edit_name ( item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ) is cursor exists_cur is select item_id from cr_items where cr_items.name = content_item.edit_name.name and parent_id = (select parent_id from cr_items where cr_items.item_id = content_item.edit_name.item_id); exists_id integer; begin open exists_cur; fetch exists_cur into exists_id; if exists_cur%NOTFOUND then close exists_cur; update cr_items set cr_items.name = content_item.edit_name.name where cr_items.item_id = content_item.edit_name.item_id; else close exists_cur; if exists_id <> item_id then raise_application_error(-20000, 'An item with the name ' || name || ' already exists in this directory.'); end if; end if; end edit_name; function get_id ( item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE is v_item_path varchar2(4000); v_root_folder_id cr_items.item_id%TYPE; parent_id integer; child_id integer; start_pos integer := 1; end_pos integer; counter integer := 0; item_name varchar2(200); begin v_root_folder_id := nvl(root_folder_id, c_root_folder_id); -- If the request path is the root, then just return the root folder if item_path = '/' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(item_path), '/'), '/'); parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); loop end_pos := instr(v_item_path, '/', start_pos); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); end if; select item_id into child_id from cr_items where parent_id = get_id.parent_id and name = item_name; exit when end_pos = 0; parent_id := child_id; -- if parent_id is a symlink, resolve it parent_id := content_symlink.resolve(parent_id); start_pos := end_pos + 1; end loop; if get_id.resolve_index = 't' then -- if the item is a folder and has an index page, then return if content_folder.is_folder( child_id ) = 't' and content_folder.get_index_page( child_id ) is not null then child_id := content_folder.get_index_page( child_id ); end if; end if; return child_id; exception when NO_DATA_FOUND then return null; end get_id; function get_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2 is cursor c_abs_cur is select name, parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = get_path.item_id order by tree_level desc; v_count integer; v_name varchar2(400); v_parent_id integer := 0; v_tree_level integer; v_resolved_root_id integer; cursor c_rel_cur is select parent_id, level as tree_level from cr_items where parent_id <> 0 connect by prior parent_id = item_id start with item_id = v_resolved_root_id order by tree_level desc; v_rel_parent_id integer := 0; v_rel_tree_level integer := 0; v_path varchar2(4000) := ''; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path.item_id; if v_count = 0 then raise_application_error(-20000, 'Invalid item ID: ' || item_id); end if; -- begin walking down the path to the item (from the repository root) open c_abs_cur; -- if the root folder is not null then prepare for a relative path if root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink.resolve(root_folder_id); -- begin walking down the path to the root folder. Discard -- elements of the item path as long as they are the same as the root -- folder open c_rel_cur; while v_parent_id = v_rel_parent_id loop fetch c_abs_cur into v_name, v_parent_id, v_tree_level; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; exit when c_abs_cur%NOTFOUND or c_rel_cur%NOTFOUND; end loop; -- walk the remainder of the relative path, add a '..' for each -- additional step loop exit when c_rel_cur%NOTFOUND; v_path := v_path || '../'; fetch c_rel_cur into v_rel_parent_id, v_rel_tree_level; end loop; close c_rel_cur; -- an item relative to itself is '../item' if v_resolved_root_id = item_id then v_path := '../'; end if; else -- this is an absolute path so prepend a '/' v_path := '/'; -- prime the pump to be consistent with relative path execution plan fetch c_abs_cur into v_name, v_parent_id, v_tree_level; end if; -- loop over the remainder of the absolute path loop v_path := v_path || v_name; fetch c_abs_cur into v_name, v_parent_id, v_tree_level; exit when c_abs_cur%NOTFOUND; v_path := v_path || '/'; end loop; close c_abs_cur; return v_path; end get_path; function get_virtual_path ( item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2 is v_path varchar2(4000); v_item_id cr_items.item_id%TYPE; v_is_folder char(1); v_index cr_items.item_id%TYPE; begin -- first resolve the item v_item_id := content_symlink.resolve( get_virtual_path.item_id ); v_is_folder := content_folder.is_folder( v_item_id ); v_index := content_folder.get_index_page( v_item_id ); -- if the folder has an index page if v_is_folder = 't' and v_index is not null then v_path := content_item.get_path( content_symlink.resolve( v_index )); else v_path := content_item.get_path( v_item_id ); end if; return v_path; exception when NO_DATA_FOUND then return null; end get_virtual_path; procedure write_to_file ( item_id in cr_items.item_id%TYPE, root_path in varchar2 )is blob_loc cr_revisions.content%TYPE; v_revision cr_items.live_revision%TYPE; begin v_revision := get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; blob_to_file(root_path || get_path(item_id), blob_loc); exception when no_data_found then raise_application_error(-20000, 'No live revision for content item' || item_id || ' in content_item.write_to_file.'); end write_to_file; procedure register_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) is begin -- register template if it is not already registered insert into cr_item_template_map ( template_id, item_id, use_context ) select register_template.template_id, register_template.item_id, register_template.use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template.item_id and template_id = register_template.template_id and use_context = register_template.use_context ); end register_template; procedure unregister_template ( item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ) is begin if use_context is null and template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id; elsif use_context is null then delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id; elsif template_id is null then delete from cr_item_template_map where item_id = unregister_template.item_id and use_context = unregister_template.use_context; else delete from cr_item_template_map where template_id = unregister_template.template_id and item_id = unregister_template.item_id and use_context = unregister_template.use_context; end if; end unregister_template; function get_template ( item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; cursor item_cur is select template_id from cr_item_template_map where item_id = get_template.item_id and use_context = get_template.use_context; begin -- look for a template assigned specifically to this item open item_cur; fetch item_cur into v_template_id; -- otherwise get the default for the content type if item_cur%NOTFOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template.item_id and i.content_type = m.content_type and m.use_context = get_template.use_context and m.is_default = 't'; end if; close item_cur; return v_template_id; exception when NO_DATA_FOUND then if item_cur%ISOPEN then close item_cur; end if; return null; end get_template; -- Return the object type of this item function get_content_type ( item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE is v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type.item_id; return v_content_type; exception when NO_DATA_FOUND then return null; end get_content_type; function get_live_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_live_revision; procedure set_live_revision ( revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ) is begin update cr_items set live_revision = set_live_revision.revision_id, publish_status = set_live_revision.publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision.revision_id); update cr_revisions set publish_date = sysdate where revision_id = set_live_revision.revision_id; end set_live_revision; procedure unset_live_revision ( item_id in cr_items.item_id%TYPE ) is begin update cr_items set live_revision = NULL where item_id = unset_live_revision.item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = 'production' where publish_status = 'live' and item_id = unset_live_revision.item_id; end unset_live_revision; procedure set_release_period ( item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ) is v_count integer; begin select decode(count(*),0,0,1) into v_count from cr_release_periods where item_id = set_release_period.item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( item_id, start_when, end_when ); else update cr_release_periods set start_when = set_release_period.start_when, end_when = set_release_period.end_when where item_id = set_release_period.item_id; end if; end set_release_period; function get_revision_count ( item_id in cr_items.item_id%TYPE ) return number is v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count.item_id; return v_count; end get_revision_count; function get_context ( item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE is v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context.item_id; return v_context_id; exception when no_data_found then raise_application_error(-20000, 'Content item ' || item_id || ' does not exist in content_item.get_context'); end get_context; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item procedure move ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is begin if content_folder.is_folder(item_id) = 't' then content_folder.move(item_id, target_folder_id, name); elsif content_folder.is_folder(target_folder_id) = 't' then if content_folder.is_registered( move.target_folder_id, get_content_type( move.item_id )) = 't' and content_folder.is_registered( move.target_folder_id, get_content_type( content_symlink.resolve( move.item_id)),'f') = 't' then -- update the parent_id for the item update cr_items set parent_id = move.target_folder_id, name = nvl (move.name, cr_items.name) where item_id = move.item_id; end if; end if; end move; procedure copy ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is copy_id cr_items.item_id%TYPE; begin copy_id := copy2(item_id, target_folder_id, creation_user, creation_ip, name); end copy; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) function copy2 ( item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE is v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered char(1); v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder.is_folder(copy2.item_id) = 't' then content_folder.copy( folder_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_symlink.copy if the item is a symlink elsif content_symlink.is_symlink(copy2.item_id) = 't' then content_symlink.copy( symlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, name => copy2.name ); -- call content_extlink.copy if the item is a extlink elsif content_extlink.is_extlink(copy2.item_id) = 't' then content_extlink.copy( extlink_id => copy2.item_id, target_folder_id => copy2.target_folder_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); -- make sure the target folder is really a folder elsif content_folder.is_folder(copy2.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy2.item_id; select content_type, name , locale, nvl(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2.item_id; -- can't copy to the same folder unless name is different if copy2.target_folder_id ^= v_current_folder_id or (v_name != copy2.name and copy2.name is not null) then if copy2.name is not null then v_name := copy2.name; end if; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder.is_registered( folder_id => copy2.target_folder_id, content_type => v_content_type, include_subtypes => 'f' ); if v_is_registered = 't' then -- create the new content item v_item_id := content_item.new( parent_id => copy2.target_folder_id, name => v_name, locale => v_locale, content_type => v_content_type, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip, storage_type => v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2.item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision.copy ( revision_id => v_old_revision_id, target_item_id => v_item_id, creation_user => copy2.creation_user, creation_ip => copy2.creation_ip ); end if; end if; end if; end if; return v_item_id; end copy2; -- get the latest revision for an item function get_latest_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id integer; cursor c_revision_cur is select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision.item_id order by o.creation_date desc; begin if item_id is null then return null; end if; open c_revision_cur; fetch c_revision_cur into v_revision_id; if c_revision_cur%NOTFOUND then close c_revision_cur; return null; end if; close c_revision_cur; return v_revision_id; exception when NO_DATA_FOUND then if c_revision_cur%ISOPEN then close c_revision_cur; end if; return null; end get_latest_revision; function get_best_revision ( item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin select NVL (live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision.item_id; return v_revision_id; exception when NO_DATA_FOUND then return null; end get_best_revision; function get_title ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE is v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title.item_id; if v_content_type = 'content_folder' then select label into v_title from cr_folders where folder_id = get_title.item_id; elsif v_content_type = 'content_symlink' then select label into v_title from cr_symlinks where symlink_id = get_title.item_id; elsif v_content_type = 'content_extlink' then select label into v_title from cr_extlinks where extlink_id = get_title.item_id; else if is_live ^= 'f' then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title.item_id and r.revision_id = i.latest_revision; end if; end if; return v_title; end get_title; function get_publish_date ( item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE is v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if is_live ^= 'f' then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date.item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; exception when no_data_found then return null; end get_publish_date; function is_subclass ( object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char is v_subclass_p char; cursor c_inherit_cur is select object_type from acs_object_types connect by prior object_type = supertype start with object_type = is_subclass.supertype; begin v_subclass_p := 'f'; for v_inherit_val in c_inherit_cur loop if v_inherit_val.object_type = is_subclass.object_type then v_subclass_p := 't'; end if; end loop; return v_subclass_p; end is_subclass; function relate ( item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE is v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; begin -- check the relationship is valid v_content_type := content_item.get_content_type ( relate.item_id ); v_object_type := content_item.get_content_type ( relate.object_id ); select decode( count(1),0,0,1) into v_is_valid from cr_type_relations where content_item.is_subclass( v_object_type, target_type ) = 't' and content_item.is_subclass( v_content_type, content_type ) = 't'; if v_is_valid = 0 then raise_application_error(-20000, 'There is no registered relation type matching this item relation.'); end if; if relate.item_id ^= relate.object_id then -- check that these two items are not related already --dbms_output.put_line( 'checking if the items are already related...'); begin select rel_id, 1 as v_exists into v_rel_id, v_exists from cr_item_rels where item_id = relate.item_id and related_object_id = relate.object_id and relation_tag = relate.relation_tag; exception when no_data_found then v_exists := 0; end; -- if order_n is null, use rel_id (the order the item was related) if relate.order_n is null then v_order_n := v_rel_id; else v_order_n := relate.order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( 'creating new relationship...'); v_rel_id := acs_object.new( object_type => relation_type, context_id => item_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, item_id, object_id, v_order_n, relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( 'updating existing relationship...'); update cr_item_rels set relation_tag = relate.relation_tag, order_n = v_order_n where rel_id = v_rel_id; end if; end if; return v_rel_id; end relate; procedure unrelate ( rel_id in cr_item_rels.rel_id%TYPE ) is begin -- delete the relation object acs_rel.del( unrelate.rel_id ); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate.rel_id; end unrelate; function is_index_page ( item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2 is begin if content_folder.get_index_page(folder_id) = item_id then return 't'; else return 'f'; end if; end is_index_page; function get_parent_folder ( item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p char(1); begin v_parent_folder_p := 'f'; v_folder_id := get_parent_folder.item_id; while v_parent_folder_p = 'f' and v_folder_id is not null loop select parent_id, content_folder.is_folder( parent_id ) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end get_parent_folder; end content_item; / show errors create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in cr_folders.package_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = 0 means that this is a mount point if parent_id ^= 0 and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id, security_inherit_p => security_inherit_p ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, label, description, package_id ); -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy.folder_id; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder or target_folder_id = folder_id then v_valid_folders_p := 0; end if; if v_valid_folders_p = 2 then -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if is_sub_folder(folder_id, target_folder_id) ^= 't' or v_current_folder_id != copy.target_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end if; end if; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := 0; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; if v_parent_id = folder_id then v_sub_folder_p := 't'; end if; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-05-02 -- @cvs-id $Id: upgrade-5.1.5d2-5.1.5d3.sql,v 1.3 2006/12/15 00:01:09 donb Exp $ -- -- reload packages to get fixed version of content_folder.rename @@ ../packages-create.sql openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.3d1-5.2.3d2.sql0000644000175000017500000001472410440426443030641 0ustar frankiefrankie-- update package content_template to add package_id parameter create or replace package content_template as c_root_folder_id constant integer := -200; function get_root_folder return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content template which can be used to render content items. -- @author Karl Goldstein -- @param name The name for the template, must be a valid UNIX-like filename. -- If a template with this name already exists under the specified -- parent item, an error is thrown -- @param text The body of the .adp template itself, defaults to null -- @param parent_id The parent of this item, defaults to null -- @param is_live The should the revision be set live, defaults to 't'. Requires -- that text is not null or there will be no revision to begin with -- @param template_id The id of the new template. A new id will be allocated if this -- parameter is null -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created template -- @see {acs_object.new}, {content_item.new}, {content_item.register_template}, -- {content_type.register_template} --*/ name in cr_items.name%TYPE, text in varchar2 default null, parent_id in cr_items.parent_id%TYPE default null, is_live in char default 't', template_id in cr_templates.template_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_templates.template_id%TYPE; procedure del ( --/** Deletes the specified template, and unregisters the template from -- all content types and content items. -- Use with caution - this operation cannot be undone. -- @author Karl Goldstein -- @param template_id The id of the template to delete -- @see {acs_object.delete}, {content_item.unregister_template}, -- {content_type.unregister_template}, --*/ template_id in cr_templates.template_id%TYPE ); function is_template ( --/** Determine if an item is a template. -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a template, 'f' otherwise -- @see {content_template.new} --*/ template_id in cr_templates.template_id%TYPE ) return varchar2; function get_path ( --/** Retrieves the full path to the template, as described in content_item.get_path -- @author Karl Goldstein -- @param template_id The id of the template for which the path is to -- be retrieved -- @param root_folder_id Starts path resolution at this folder -- @return The path to the template, starting with the specified root folder -- @see {content_item.get_path} --*/ template_id in cr_templates.template_id%TYPE, root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id ) return varchar2; end content_template; / show errors create or replace package body content_template as function get_root_folder return cr_folders.folder_id%TYPE is begin return c_root_folder_id; end get_root_folder; function new ( name in cr_items.name%TYPE, text in varchar2 default null, parent_id in cr_items.parent_id%TYPE default null, is_live in char default 't', template_id in cr_templates.template_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if parent_id is null then v_parent_id := c_root_folder_id; else v_parent_id := parent_id; end if; -- make sure we're allowed to create a template in this folder if content_folder.is_folder(parent_id) = 't' and content_folder.is_registered(parent_id,'content_template') = 'f' then raise_application_error(-20000, 'This folder does not allow templates to be created'); else if package_id is null then v_package_id := acs_object.package_id(v_parent_id); else v_package_id := package_id; end if; v_template_id := content_item.new ( item_id => content_template.new.template_id, name => content_template.new.name, text => content_template.new.text, parent_id => v_parent_id, package_id => v_package_id, content_type => 'content_template', is_live => content_template.new.is_live, creation_date => content_template.new.creation_date, creation_user => content_template.new.creation_user, creation_ip => content_template.new.creation_ip ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end new; -- delete all template relations procedure del ( template_id in cr_templates.template_id%TYPE ) is begin delete from cr_type_template_map where template_id = content_template.del.template_id; delete from cr_item_template_map where template_id = content_template.del.template_id; delete from cr_templates where template_id = content_template.del.template_id; content_item.del(content_template.del.template_id); end del; function is_template ( template_id in cr_templates.template_id%TYPE ) return varchar2 is v_ret varchar2(1); begin select 't' into v_ret from cr_templates where template_id = is_template.template_id; return v_ret; exception when no_data_found then return 'f'; end is_template; function get_path ( template_id in cr_templates.template_id%TYPE, root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id ) return varchar2 is begin return content_item.get_path(template_id, root_folder_id); end get_path; end content_template; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.2d6-5.1.2d7.sql0000644000175000017500000000041610207353612030636 0ustar frankiefrankie-- -- -- -- @author Rocael Hernandez (roc@viaro.net) -- @creation-date 2004-09-02 -- @arch-tag: d5184853-cbe4-4860-94a8-9a60587b36eb -- @cvs-id $Id: upgrade-5.1.2d6-5.1.2d7.sql,v 1.3 2005/02/24 13:32:58 jeffd Exp $ -- -- create index cr_items_name on cr_items(name);openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.6.2-4.6.3.sql0000644000175000017500000014235210070240677030174 0ustar frankiefrankie-- This upgrade adds more mime types and -- creates the cr_extension_mime_type_map -- -- Jeff Davis davis@xarg.net 2003-02-06 create table cr_extension_mime_type_map ( extension varchar(200) constraint cr_mime_type_extension_map_pk primary key, mime_type varchar(200) constraint cr_mime_ext_map_mime_type_ref references cr_mime_types ); create index cr_extension_mime_type_map_idx on cr_extension_mime_type_map(mime_type); comment on table cr_extension_mime_type_map is ' a mapping table for extension to mime_type in db version of ns_guesstype data '; -- Quicky create some tmp tables. create table tmp_cr_mime_types as select * from cr_mime_types where 0 = 1; create table tmp_cr_extension_mime_type_map as select * from cr_extension_mime_type_map where 0 = 1; -- data from sql/common/mime-type-data.sql insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Unkown' , '*/*' , '' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'AutoCAD drawing files' , 'application/acad' , 'dwg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Andrew data stream' , 'application/andrew-inset' , 'ez' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'ClarisCAD files' , 'application/clariscad' , 'ccad' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Comma separated value' , 'application/csv' , 'csv' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'MATRA Prelude drafting' , 'application/drafting' , 'drw' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'DXF (AutoCAD)' , 'application/dxf' , 'dxf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Filemaker Pro' , 'application/filemaker' , 'fm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Futuresplash' , 'application/futuresplash' , 'spl' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'NCSA HDF data format' , 'application/hdf' , 'hdf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'IGES graphics format' , 'application/iges' , 'iges' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Mac binhex 4.0' , 'application/mac-binhex40' , 'hqx' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Mac Compactpro' , 'application/mac-compactpro' , 'cpt' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Word' , 'application/msword' , 'doc' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Uninterpreted binary' , 'application/octet-stream' , 'bin' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'ODA ODIF' , 'application/oda' , 'oda' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'PDF' , 'application/pdf' , 'pdf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'PostScript' , 'application/postscript' , 'ps' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Rich Text Format' , 'application/rtf' , 'rtf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Stereolithography' , 'application/sla' , 'stl'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VCard' , 'application/vcard' , 'vcf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VDA-FS Surface data' , 'application/vda' , 'vda'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SSOYE Koan Files' , 'application/vnd.koan' , 'skp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'FrameMaker MIF format' , 'application/vnd.mif' , 'mif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Access file' , 'application/vnd.ms-access' , 'mdb' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Excel' , 'application/vnd.ms-excel' , 'xls' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft PowerPoint' , 'application/vnd.ms-powerpoint' , 'ppt' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Project' , 'application/vnd.ms-project' , 'mpp' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WML XML in binary format', 'application/vnd.wap.wmlc' , 'wmlc'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WMLScript bytecode' , 'application/vnd.wap.wmlscriptc', 'wmlsc'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'CorelXARA' , 'application/vnd.xara' , 'xar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WordPerfect' , 'application/wordperfect' , 'wpd'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WordPerfect 6.0' , 'application/wordperfect6.0' , 'w60'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive ARJ ' , 'application/x-arj-compressed' , 'arj'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-bin' , 'aab' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-map' , 'aam' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-seg' , 'aas' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Channel Definition' , 'application/x-cdf' , 'cdf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VCD' , 'application/x-cdlink' , 'vcd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Chess PGN file' , 'application/x-chess-pgn' , 'pgn'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive compres' , 'application/x-compress' , 'z'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive CPIO' , 'application/x-cpio' , 'cpio'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'C-shell script' , 'application/x-csh' , 'csh' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive Debian Package' , 'application/x-debian-package' , 'deb'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Director' , 'application/x-director' , 'dxr' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'TeX DVI file' , 'application/x-dvi' , 'dvi' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'GNU Tar' , 'application/x-gtar' , 'gtar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Compressed - gzip' , 'application/x-gzip' , 'gz' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'CGI Script' , 'application/x-httpd-cgi' , 'cgi'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Adobe Illustrator' , 'application/x-illustrator' , 'ai' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Installshield data' , 'application/x-installshield' , 'wis'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Java Network Launching Protocol', 'application/x-java-jnlp-file', 'jnlp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Javascript' , 'application/x-javascript' , 'js' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'LaTeX source' , 'application/x-latex' , 'latex' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmd)', 'application/x-ms-wmd' , 'wmd'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmz)', 'application/x-ms-wmz' , 'wmz'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Unidata netCDF' , 'application/x-netcdf' , 'cdf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Ogg Vorbis' , 'application/x-ogg' , 'ogg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Adobe PageMaker' , 'application/x-pagemaker' , 'p65' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Photoshop' , 'application/x-photoshop' , 'psd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Palm Pilot Data' , 'application/x-pilot' , 'prc' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Real' , 'application/x-pn-realmedia' , 'rp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Quattro Pro' , 'application/x-quattro-pro' , 'wq1'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive RAR' , 'application/x-rar-compressed' , 'rar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Session Description Protocol', 'application/sdp' , 'sdp' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Shockwave' , 'application/x-shockwave-flash' , 'swf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SQL' , 'application/x-sql' , 'sql' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Mac Stuffit compressed' , 'application/x-stuffit' , 'sit' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive SVR4 cpio' , 'application/x-sv4cpio' , 'sv4cpio'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive SVR4 crc' , 'application/x-sv4crc' , 'sv4crc'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Tar Archive' , 'application/x-tar' , 'tar' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'TeX source' , 'application/x-tex' , 'tex' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Texinfo (emacs)' , 'application/x-texinfo' , 'texinfo' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff' , 'application/x-troff' , 'tr' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff with MAN macros' , 'application/x-troff-man' , 'man' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff with ME macros' , 'application/x-troff-me' , 'me' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff with MS macros' , 'application/x-troff-ms' , 'ms' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive POSIX Tar' , 'application/x-ustar' , 'ustar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X509 CA Cert' , 'application/x-x509-ca-cert' , 'cacert'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive Zip' , 'application/zip' , 'zip' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Basic audio (m-law PCM)' , 'audio/basic' , 'au' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Midi' , 'audio/midi' , 'midi'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio MPEG' , 'audio/x-mpeg' , 'mpga'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio MPEG-2' , 'audio/x-mpeg2' , 'mp2a'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Java Media Framework', 'audio/rmf' , 'rmf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Voice' , 'audio/voice' , 'voc' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio AIFF' , 'audio/x-aiff' , 'aif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Mod' , 'audio/x-mod' , 'xm'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'mpeg url (m3u)' , 'audio/x-mpegurl' , 'm3u'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wma)', 'audio/x-ms-wma' , 'wma'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmv)', 'audio/x-ms-wmv' , 'wmv'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Realaudio' , 'audio/x-pn-realaudio' , 'ra' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Realaudio Plugin' , 'audio/x-pn-realaudio-plugin' , 'rm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft WAVE audio' , 'audio/x-wav' , 'wav' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Brookhaven PDB' , 'chemical/x-pdb' , 'pdb'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'XMol XYZ' , 'chemical/x-xyz' , 'xyz'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WHIP Web Drawing file' , 'drawing/x-dwf' , 'dwf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - BMP' , 'image/bmp' , 'bmp' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Fractal Image Format' , 'image/fif' , 'fif'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Gif' , 'image/gif' , 'gif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image Exchange Format' , 'image/ief' , 'ief' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Jpeg' , 'image/jpeg' , 'jpg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PNG' , 'image/png' , 'png' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - TIFF' , 'image/tiff' , 'tif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WAP wireless bitmap' , 'image/vnd.wap.wbmp' , 'wbmp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - CMU Raster' , 'image/x-cmu-raster' , 'ras' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Flexible Image Transport', 'image/x-fits' , 'fit' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Freehand' , 'image/x-freehand' , 'fh' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SVG' , 'image/xml+svg' , 'svg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PhotoCD' , 'image/x-photo-cd' , 'pcd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Mac pict' , 'image/x-pict' , 'pict' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PNM' , 'image/x-portable-anymap' , 'pnm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PBM' , 'image/x-portable-bitmap' , 'pbm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PGM' , 'image/x-portable-graymap' , 'pgm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Portable Pixmap' , 'image/x-portable-pixmap' , 'ppm'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - RGB' , 'image/x-rgb' , 'rgb'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X bitmap' , 'image/x-xbitmap' , 'xbm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X pixmap' , 'image/x-xpixmap' , 'xpm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X window dump (xwd)' , 'image/x-xwindowdump' , 'xwd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'RFC822 Message' , 'message/rfc822' , 'mime'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Computational mesh' , 'model/mesh' , 'mesh'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SGML Text' , 'text/sgml' , 'sgml'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Cascading style sheet' , 'text/css' , 'css' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'HTML text' , 'text/html' , 'html' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Plain text' , 'text/plain' , 'txt' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Text (flowed)' , 'text/plain; format=flowed' , 'text' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Enriched Text' , 'text/enriched' , 'rtx' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Tab separated values' , 'text/tab-separated-values' , 'tsv' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WMLScript' , 'text/vnd.wap.wmlscript' , 'wmls'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WML' , 'text/vnd.wap.wml' , 'wml'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'XML Document' , 'text/xml' , 'xml' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Structured enhanced text', 'text/x-setext' , 'etx'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'XSL style sheet' , 'text/xsl' , 'xsl' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video FLI' , 'video/fli' , 'fli'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video MPEG' , 'video/mpeg' , 'mpg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video MPEG-2' , 'video/mpeg2' , 'mpv2' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Quicktime' , 'video/quicktime' , 'mov' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video VDOlive streaming' , 'video/vdo' , 'vdo'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Vivo' , 'video/vnd.vivo' , 'vivo'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Microsoft ASF' , 'video/x-ms-asf' , 'asf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wm)', 'video/x-ms-wm' , 'wm'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wvx)', 'video/x-ms-wvx' , 'wvx'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmx)', 'video/x-mx-wmx' , 'wmx'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Microsoft AVI' , 'video/x-msvideo' , 'avi' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video SGI movie player' , 'video/x-sgi-movie' , 'movie' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Conference Cooltalk' , 'x-conference/x-cooltalk' , 'ice'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VRML' , 'x-world/x-vrml' , 'vrml'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Xuda' , 'xuda/gen-cert' , 'xuda'); -- Extension to mime type maps. -- text/plain for prog langs (maybe we should do application/x-LANG but then you can't look -- at the code in the browser. insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'c', 'text/plain'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'c++', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cpp', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cxx', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cc', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'h', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'h++', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hxx', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tcl', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sql', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'csh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ksh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'py', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'java', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xql', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'php', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm4', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pl', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pm', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pod', 'text/plain' ); -- map a few to binary insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'o','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'so','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'a','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dll','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'exe','application/octet-stream' ); -- all the rest insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aab','application/x-authorware-bin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aam','application/x-authorware-map' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aas','application/x-authorware-seg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ai','application/x-illustrator'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aif','audio/x-aiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aifc','audio/x-aiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aiff','audio/x-aiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ani','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'arj','application/x-arj-compressed' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'asc','text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'asf','video/x-ms-asf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'asx','video/x-ms-asf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'au','audio/basic' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'avi','video/x-msvideo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'bin','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'bmp','image/bmp' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'bqy','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cacert','application/x-x509-ca-cert' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ccad','application/clariscad' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cdf','application/x-netcdf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cgi','application/x-httpd-cgi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'class','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cpio','application/x-cpio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cpt','application/mac-compactpro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'css','text/css' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'csv','application/csv'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cur','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dcr','application/x-director' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'deb','application/x-debian-package' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dhtml','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dir','application/x-director' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dms','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'doc','application/msword' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dot','application/msword' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'drw','application/drafting' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dump','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dvi','application/x-dvi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dwf','drawing/x-dwf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dwg','application/acad' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dxf','application/dxf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dxr','application/x-director' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'eps','application/postscript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'etx','text/x-setext' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ez','application/andrew-inset' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh4','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh5','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh7','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fhc','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fif','image/fif' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fit','image/x-fits'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fli','video/fli' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fm','application/filemaker'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gif','image/gif' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gtar','application/x-gtar' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gz','application/x-gzip' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gzip','application/x-gzip' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hdf','application/hdf'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hqx','application/mac-binhex40' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'html','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'htm','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ice','x-conference/x-cooltalk' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ico','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ief','image/ief' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'iges','application/iges' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'igs','application/iges' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jnlp','application/x-java-jnlp-file' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jpeg','image/jpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jpe','image/jpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jpg','image/jpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'js','application/x-javascript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'kar','audio/midi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'latex','application/x-latex' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'lha','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'lzh','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm15','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm3u','audio/x-mpegurl' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm3url','audio/x-mpegurl' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'man','application/x-troff-man' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mdb','application/vnd.ms-access'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'me','application/x-troff-me' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mesh','model/mesh' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mid','audio/midi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'midi','audio/midi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mif','application/vnd.mif' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mime','message/rfc822' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'movie','video/x-sgi-movie' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mov','video/quicktime' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp2','audio/x-mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp2a','audio/x-mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp3','audio/x-mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp3a','audio/x-mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpeg','video/mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpe','video/mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpga','audio/x-mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpg','video/mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpv2','video/mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp2v','video/mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpp','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpc','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpt','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpx','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpw','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ms','application/x-troff-ms' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'msh','model/mesh' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'msw','application/msword' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mtm','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'nc','application/x-netcdf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'oda','application/oda' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ogg','application/x-ogg'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'p65','application/x-pagemaker'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pbm','image/x-portable-bitmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pcd','image/x-photo-cd'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pdb','chemical/x-pdb' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pdf','application/pdf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pgm','image/x-portable-graymap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pgn','application/x-chess-pgn' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pict','image/x-pict' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'png','image/png' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pnm','image/x-portable-anymap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ppm','image/x-portable-pixmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ppt','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ppz','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pps','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pot','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'prc','application/x-pilot'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ps','application/postscript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'psd','application/x-photoshop'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'qt','video/quicktime' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ra','audio/x-pn-realaudio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ram','audio/x-pn-realaudio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rar','application/x-rar-compressed' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ras','image/x-cmu-raster' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rgb','image/x-rgb' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rmf', 'audio/rmf'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rm','audio/x-pn-realaudio-plugin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rmm','audio/x-pn-realaudio-plugin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'roff','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rp','application/x-pn-realmedia' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rpm','audio/x-pn-realaudio-plugin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rr','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rtf','application/rtf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rtx','text/enriched' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 's3m','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sd2','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sdp','application/sdp' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sea','application/x-stuffit' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sgml','text/sgml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sgm','text/sgml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'shtml','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'silo','model/mesh' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sit','application/x-stuffit' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skd','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skm','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skp','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skt','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'snd','audio/basic' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'spl','application/futuresplash' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'stl','application/sla' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'stm','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sv4cpio','application/x-sv4cpio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sv4crc','application/x-sv4crc' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'svg','image/xml+svg'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'swf','application/x-shockwave-flash' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 't','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tar','application/x-tar' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tex','application/x-tex' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'texi','application/x-texinfo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'texinfo','application/x-texinfo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'text','text/plain; format=flowed'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tiff','image/tiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tif','image/tiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tr','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tsv','text/tab-separated-values' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'txt','text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ult','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ustar','application/x-ustar' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'uu','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vcd','application/x-cdlink' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vcf','application/vcard' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vdo','video/vdo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vda','application/vda' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vivo','video/vnd.vivo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'viv','video/vnd.vivo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'voc','audio/voice'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vrml','x-world/x-vrml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vrm','x-world/x-vrml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wav','audio/x-wav' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wb1','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wb2','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wb3','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wbmp','image/vnd.wap.wbmp' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'web','application/vnd.xara' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wis','application/x-installshield' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wma','audio/x-ms-wma' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmd','application/x-ms-wmd' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmlc','application/vnd.wap.wmlc' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmlsc','application/vnd.wap.wmlscriptc' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmls','text/vnd.wap.wmlscript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wml','text/vnd.wap.wml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmv','audio/x-ms-wmv' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wm','video/x-ms-wm' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmx','video/x-mx-wmx' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmz','application/x-ms-wmz' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wpd','application/wordperfect' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wq1','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wrl','x-world/x-vrml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wvx','video/x-ms-wvx' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xar','application/vnd.xara' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'w60','application/wordperfect6.0'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xbm','image/x-xbitmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xlc','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xls','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xlm','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xlw','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xm','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xml','text/xml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xpm','image/x-xpixmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xsl','text/xsl' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xuda','xuda/gen-cert' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xwd','image/x-xwindowdump' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xyz','chemical/x-xyz' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'z','application/x-compress' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'zip','application/zip' ); -- Now update the existing data taking care not to mess anything up. -- Add the mime types that don't already exist. -- don't add extensions yet since we do that later to prevent -- duplicates in the insert into cr_mime_types (label, mime_type, file_extension) select label, mime_type, null from tmp_cr_mime_types n where not exists ( select 1 from cr_mime_types o where o.mime_type = n.mime_type); -- Provide extension for mime types with missing ones and which are -- not in use for another mime type. update cr_mime_types set label = ( select label from tmp_cr_mime_types n where n.mime_type = cr_mime_types.mime_type) where label is null; -- Add extensions, verify extension not already used by another mime type. -- have to do this since we don't want to introduce duplicate -- extensions since there is still code using the cr_mime_types table to -- look up mime_type. update cr_mime_types set file_extension = ( select file_extension from tmp_cr_mime_types m where m.mime_type = cr_mime_types.mime_type and not exists (select * from cr_mime_types c where m.file_extension = c.file_extension)) where file_extension is null; -- Create a mapping entry for existing mime types. -- we make sure we only get one mapping per extension just in case insert into cr_extension_mime_type_map (extension, mime_type) select file_extension, min(mime_type) from cr_mime_types where file_extension is not null group by file_extension; -- insert all the rest that are not being used insert into cr_extension_mime_type_map select extension, mime_type from tmp_cr_extension_mime_type_map n where not exists ( select 1 from cr_extension_mime_type_map o where o.extension = n.extension ); drop table tmp_cr_mime_types; drop table tmp_cr_extension_mime_type_map; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.3.0d2-5.3.0d3.sql0000644000175000017500000011635110511235423030631 0ustar frankiefrankie-- package specification create or replace package content_type AUTHID CURRENT_USER as --/** This package is used to manipulate content types and attributes -- --*/ procedure create_type ( --/** Create a new content type. Automatically create the attribute table -- for the type if the table does not already exist. -- @author Karl Goldstein -- @param content_type The name of the new type -- @param supertype The supertype, defaults to content_revision -- @param pretty_name Pretty name for the type, singular -- @param pretty_plural Pretty name for the type, plural -- @param table_name The name for the attribute table, defaults to -- the name of the supertype -- @param id_column The primary key for the table, defaults to 'XXX' -- @param name_method As in acs_object_type.create_type -- @see {acs_object_type.create_type} --*/ content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ); procedure drop_type ( --/** First drops all attributes related to a specific type, then drops type -- the given type. -- @author Simon Huynh -- @param content_type The content type to be dropped -- @param drop_children_p If 't', then the sub-types -- of the given content type and their associated tables -- are also dropped. --*/ content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f', drop_objects_p in char default 'f' ); function create_attribute ( --/** Create a new attribute for the specified type. Automatically create -- the column for the attribute if the column does not already exist. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to create -- @param pretty_name Pretty name for the new attribute, singular -- @param pretty_plural Pretty name for the new attribute, plural -- @param default_value The default value for the attribute, defaults to null -- @return The id of the newly created attribute -- @see {acs_object_type.create_attribute}, {content_type.create_type} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE; procedure drop_attribute ( --/** Drop an existing attribute. If you are using CMS, make sure to -- call cm_form_widget.unregister_attribute_widget before calling -- this function. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to drop -- @param drop_column If 't', will also alter the table and remove -- the column where the attribute is stored. The default is 'f' -- (leaves the table untouched). -- @see {acs_object.drop_attribute}, {content_type.create_attribute}, -- {cm_form_widget.unregister_attribute_widget} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ); procedure register_template ( --/** Register a template for the content type. This template may be used -- to render all items of that type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be registered -- @param template_id The ID of the template to register -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @param is_default If 't', this template becomes the default template for -- the type, default is 'f'. -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.set_default_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ); procedure set_default_template ( --/** Make the registered template a default template. The default template -- will be used to render all items of the type for which no individual -- template is registered. -- @author Karl Goldstein -- @param content_type The type for which the template is to be made default -- @param template_id The ID of the template to make default -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ); function get_template ( --/** Retrieve the appropriate template for rendering items of the specified type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be retrieved -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @return The ID of the template to use -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.set_default_template} --*/ content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; procedure unregister_template ( --/** Unregister a template. If the unregistered template was the default template, -- the content_type can no longer be rendered in the use_context, -- @author Karl Goldstein -- @param content_type The type for which the template is to be unregistered -- @param template_id The ID of the template to unregister -- @param use_context The context in which the template is to be unregistered -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.set_default_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ); procedure refresh_view ( --/** Create a view for the type which joins all attributes of the type, -- including the inherited attributes. The view is named -- "
X" -- Called by create_attribute and create_type. -- @author Karl Goldstein -- @param content_type The type for which the view is to be created. -- @see {content_type.create_type} --*/ content_type in cr_type_template_map.content_type%TYPE ); procedure register_relation_type ( --/** Register a relationship between a content type and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate any relationship between an item and another -- object. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.unregister_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_relation_type ( --/** Unregister a relationship between a content type and another object -- type. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ); procedure register_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of parent-child -- relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param parent_type The type of the parent item. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ); procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char; procedure rotate_template ( --/** Sets the default template for a content type and registers all the -- previously existing items of that content type to the original -- template -- @author Michael Pih -- @param template_id The template that will become the default -- registered template for the specified content type and use context -- @param v_content_type The content type -- @param use_context The context in which the template will be used --*/ template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ); -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ); end content_type; / show errors; -- package body create or replace package body content_type is procedure create_type ( content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ) is table_exists integer; v_supertype_table acs_object_types.table_name%TYPE; v_count integer; begin if (supertype != 'content_revision') and (content_type != 'content_revision') then select count(*) into v_count from acs_object_type_supertype_map where object_type = create_type.supertype and ancestor_type = 'content_revision'; if v_count = 0 then raise_application_error(-20000, 'Content types can only be created as subclasses of content_revision or a derivation thereof. ' || supertype || ' is not a subclass oc content_revision.'); end if; end if; -- create the attribute table if not already created select decode(count(*),0,0,1) into table_exists from user_tables where table_name = upper(create_type.table_name); if table_exists = 0 then select table_name into v_supertype_table from acs_object_types where object_type = create_type.supertype; execute immediate 'create table ' || table_name || ' (' || id_column || ' integer primary key references ' || v_supertype_table || ')'; end if; acs_object_type.create_type ( supertype => create_type.supertype, object_type => create_type.content_type, pretty_name => create_type.pretty_name, pretty_plural => create_type.pretty_plural, table_name => create_type.table_name, id_column => create_type.id_column, name_method => create_type.name_method ); refresh_view(content_type); end create_type; procedure drop_type ( content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f', drop_objects_p in char default 'f' ) is cursor attribute_cur is select attribute_name from acs_attributes where object_type = drop_type.content_type; cursor child_type_cur is select object_type from acs_object_types where supertype = drop_type.content_type; cursor revision_cur is select revision_id from cr_revisions, acs_objects where revision_id = object_id and object_type = drop_type.content_type; cursor item_cur is select item_id from cr_items where content_type = drop_type.content_type; table_exists integer; v_table_name varchar2(50); is_subclassed_p char; begin -- first we'll rid ourselves of any dependent child types, if any , along with their -- own dependent grandchild types select decode(count(*),0,'f','t') into is_subclassed_p from acs_object_types where supertype = drop_type.content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children's packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_children_p = 't' and is_subclassed_p = 't' then for child_rec in child_type_cur loop drop_type( content_type => child_rec.object_type, drop_children_p => 't', drop_table_p => drop_table_p, drop_objects_p => drop_objects_p ); end loop; end if; -- now drop all the attributes related to this type for attr_row in attribute_cur loop drop_attribute( content_type => drop_type.content_type, attribute_name => attr_row.attribute_name ); end loop; -- we'll remove the associated table if it exists select decode(count(*),0,0,1) into table_exists from user_tables u, acs_object_types objet where objet.object_type = drop_type.content_type and u.table_name = upper(objet.table_name); if table_exists = 1 and drop_table_p = 't' then select table_name into v_table_name from acs_object_types where object_type = drop_type.content_type; -- drop the input/output views for the type -- being dropped. -- FIXME: does the trigger get dropped when the -- view is dropped? This did not exist in the 4.2 release, -- and it needs to be tested. execute immediate 'drop view ' || v_table_name || 'x'; execute immediate 'drop view ' || v_table_name || 'i'; execute immediate 'drop table ' || v_table_name; end if; if drop_objects_p = 't' then for revision_row in revision_cur loop content_revision.del( revision_id => revision_row.revision_id ); end loop; for item_row in item_cur loop content_item.del( item_id => item_row.item_id ); end loop; end if; acs_object_type.drop_type( object_type => drop_type.content_type ); end drop_type; function create_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE is v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists integer; begin -- add the appropriate column to the table begin select upper(table_name) into v_table_name from acs_object_types where object_type = create_attribute.content_type; exception when no_data_found then raise_application_error(-20000, 'Content type ''' || content_type || ''' does not exist in content_type.create_attribute'); end; select decode(count(*),0,0,1) into v_column_exists from user_tab_columns where table_name = v_table_name and column_name = upper(attribute_name); if v_column_exists = 0 then execute immediate 'alter table ' || v_table_name || ' add ' || attribute_name || ' ' || column_spec; end if; v_attr_id := acs_attribute.create_attribute ( object_type => create_attribute.content_type, attribute_name => create_attribute.attribute_name, datatype => create_attribute.datatype, pretty_name => create_attribute.pretty_name, pretty_plural => create_attribute.pretty_plural, sort_order => create_attribute.sort_order, default_value => create_attribute.default_value ); refresh_view(content_type); return v_attr_id; end create_attribute; procedure drop_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ) is v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information begin select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute.content_type and a.object_type = drop_attribute.content_type and a.attribute_name = drop_attribute.attribute_name; exception when no_data_found then raise_application_error(-20000, 'Attribute ' || content_type || ':' || attribute_name || ' does not exist in content_type.drop_attribute'); end; -- Drop the attribute acs_attribute.drop_attribute(content_type, attribute_name); -- Drop the column if neccessary if drop_column = 't' then begin execute immediate 'alter table ' || v_table || ' drop column ' || attribute_name; exception when others then raise_application_error(-20000, 'Unable to drop column ' || v_table || '.' || attribute_name || ' in content_type.drop_attribute'); end; end if; refresh_view(content_type); end drop_attribute; procedure register_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ) is v_template_registered integer; begin select count(*) into v_template_registered from cr_type_template_map where content_type = register_template.content_type and use_context = register_template.use_context and template_id = register_template.template_id; -- register the template if v_template_registered = 0 then insert into cr_type_template_map ( template_id, content_type, use_context, is_default ) values ( template_id, content_type, use_context, is_default ); -- update the registration status of the template else -- unset the default template before setting this one as the default if register_template.is_default = 't' then update cr_type_template_map set is_default = 'f' where content_type = register_template.content_type and use_context = register_template.use_context; end if; update cr_type_template_map set is_default = register_template.is_default where template_id = register_template.template_id and content_type = register_template.content_type and use_context = register_template.use_context; end if; end register_template; procedure set_default_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is begin update cr_type_template_map set is_default = 't' where template_id = set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context; -- make sure there is only one default template for -- any given content_type/use_context pair update cr_type_template_map set is_default = 'f' where template_id ^= set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context and is_default = 't'; end set_default_template; function get_template ( content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template.content_type and use_context = get_template.use_context and is_default = 't'; return v_template_id; exception when NO_DATA_FOUND then return null; end get_template; procedure unregister_template ( content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ) is begin if unregister_template.use_context is null and unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id; elsif unregister_template.use_context is null then delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type; elsif unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id and use_context = unregister_template.use_context; else delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type and use_context = unregister_template.use_context; end if; end unregister_template; -- Helper function for refresh_trigger (below) to generate the -- insert statement for a particular content type; function trigger_insert_statement ( content_type in acs_object_types.object_type%TYPE ) return varchar2 is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = trigger_insert_statement.content_type; cols varchar2(2000) := ''; vals varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; vals := vals || ', :new.' || attr_rec.attribute_name; end loop; return 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) values ( new_revision_id' || vals || ')'; end trigger_insert_statement; -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ) is tr_text varchar2(10000) := ''; v_table_name acs_object_types.table_name%TYPE; cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = refresh_trigger.content_type order by level desc; begin -- get the table name for the content type (determines view name) select table_name into v_table_name from acs_object_types where object_type = refresh_trigger.content_type; -- start building trigger code tr_text := ' create or replace trigger ' || v_table_name || 't instead of insert on ' || v_table_name || 'i for each row declare new_revision_id integer; begin if :new.item_id is null then raise_application_error(-20000, ''item_id is required when inserting into ' || v_table_name || 'i ''); end if; if :new.text is not null then new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, text => :new.text, package_id => :new.object_package_id ); else new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, data => :new.data, package_id => :new.object_package_id ); end if;'; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in type_cur loop tr_text := tr_text || ' ' || trigger_insert_statement(type_rec.object_type) || '; '; end loop; -- end building the trigger code tr_text := tr_text || ' end ' || v_table_name || 't;'; -- (Re)create the trigger execute immediate tr_text; end refresh_trigger; -- Create or replace a view joining all attribute tables procedure refresh_view ( content_type in cr_type_template_map.content_type%TYPE ) is -- exclude the BLOB column because it will make it impossible -- to do a select * cursor join_cur is select distinct lower(table_name) as table_name, id_column, level from acs_object_types where object_type <> 'acs_object' and object_type <> 'content_revision' and lower(table_name) <> 'acs_objects' and lower(table_name) <> 'cr_revisions' start with object_type = refresh_view.content_type connect by object_type = prior supertype; cols varchar2(1000); tabs varchar2(1000); joins varchar2(1000) := ''; v_table_name varchar2(40); begin for join_rec in join_cur loop cols := cols || ', ' || join_rec.table_name || '.*'; tabs := tabs || ', ' || join_rec.table_name; joins := joins || ' and acs_objects.object_id = ' || join_rec.table_name || '.' || join_rec.id_column; end loop; select table_name into v_table_name from acs_object_types where object_type = content_type; -- create the input view (includes content columns) execute immediate 'create or replace view ' || v_table_name || 'i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.content as data, cr_text.text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language' || cols || ' from acs_objects, cr_revisions cr, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id ' || joins; -- create the output view (excludes content columns to enable SELECT *) execute immediate 'create or replace view ' || v_table_name || 'x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id' || cols || ' from acs_objects, cr_revisions cr, cr_items i, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id' || joins; refresh_trigger(content_type); exception when others then dbms_output.put_line('Error creating attribute view or trigger for ' || content_type); end refresh_view; procedure register_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin select decode(count(*),0,0,1) into v_exists from cr_type_children where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; if v_exists = 0 then insert into cr_type_children ( parent_type, child_type, relation_tag, min_n, max_n ) values ( parent_type, child_type, relation_tag, min_n, max_n ); else update cr_type_children set min_n = register_child_type.min_n, max_n = register_child_type.max_n where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; end if; end register_child_type; procedure unregister_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ) is begin delete from cr_type_children where parent_type = unregister_child_type.parent_type and child_type = unregister_child_type.child_type and relation_tag = unregister_child_type.relation_tag; end unregister_child_type; procedure register_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin -- check if the relation type exists select decode(count(*),0,0,1) into v_exists from cr_type_relations where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; -- if the relation type does not exist, insert a row into cr_type_relations if v_exists = 0 then insert into cr_type_relations ( content_type, target_type, relation_tag, min_n, max_n ) values ( content_type, target_type, relation_tag, min_n, max_n ); -- otherwise, update the row in cr_type_relations else update cr_type_relations set min_n = register_relation_type.min_n, max_n = register_relation_type.max_n where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; end if; end register_relation_type; procedure unregister_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ) is begin delete from cr_type_relations where content_type = unregister_relation_type.content_type and target_type = unregister_relation_type.target_type and relation_tag = unregister_relation_type.relation_tag; end unregister_relation_type; procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is v_valid_registration integer; begin -- check if this type is already registered select count(*) into v_valid_registration from cr_mime_types where not exists ( select 1 from cr_content_mime_type_map where mime_type = register_mime_type.mime_type and content_type = register_mime_type.content_type ) and mime_type = register_mime_type.mime_type; if v_valid_registration = 1 then insert into cr_content_mime_type_map ( content_type, mime_type ) values ( register_mime_type.content_type, register_mime_type.mime_type ); end if; end register_mime_type; procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is begin delete from cr_content_mime_type_map where content_type = unregister_mime_type.content_type and mime_type = unregister_mime_type.mime_type; end unregister_mime_type; function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char is v_is_content_type char(1) := 'f'; begin if object_type = 'content_revision' then v_is_content_type := 't'; else select decode(count(*),0,'f','t') into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type.object_type and ancestor_type = 'content_revision'; end if; return v_is_content_type; end is_content_type; procedure rotate_template ( template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is v_template_id cr_templates.template_id%TYPE; -- items that have an associated default template but not at the item level cursor c_items_cursor is select item_id from cr_items i, cr_type_template_map m where i.content_type = rotate_template.v_content_type and m.use_context = rotate_template.use_context and i.content_type = m.content_type and not exists ( select 1 from cr_item_template_map where item_id = i.item_id and use_context = rotate_template.use_context ); begin -- get the default template select template_id into v_template_id from cr_type_template_map where content_type = rotate_template.v_content_type and use_context = rotate_template.use_context and is_default = 't'; if v_template_id is not null then -- register an item-template to all items without an item-template for v_items_val in c_items_cursor loop content_item.register_template ( item_id => v_items_val.item_id, template_id => v_template_id, use_context => rotate_template.use_context ); end loop; end if; -- register the new template as the default template of the content type if v_template_id ^= rotate_template.template_id then content_type.register_template( content_type => rotate_template.v_content_type, template_id => rotate_template.template_id, use_context => rotate_template.use_context, is_default => 't' ); end if; end rotate_template; end content_type; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-4.6.5-4.7d6.sql0000644000175000017500000000045707702263321030267 0ustar frankiefrankie-- Upgrade content_template.new() and make it take an optional text parameter. -- If it is provided, a revision of the template will be created automatically. -- You thus avoid calling content_revision.new() in a separate step ... -- (ola@polyxena.net) @@ ../packages-create.sql @@ ../content-item.sql openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.2.0d16-5.2.0d17.sql0000644000175000017500000006274010440426443031010 0ustar frankiefrankiecreate or replace package body content_type is procedure create_type ( content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ) is table_exists integer; v_supertype_table acs_object_types.table_name%TYPE; v_count integer; begin if (supertype != 'content_revision') and (content_type != 'content_revision') then select count(*) into v_count from acs_object_type_supertype_map where object_type = create_type.supertype and ancestor_type = 'content_revision'; if v_count = 0 then raise_application_error(-20000, 'Content types can only be created as subclasses of content_revision or a derivation thereof. ' || supertype || ' is not a subclass oc content_revision.'); end if; end if; -- create the attribute table if not already created select decode(count(*),0,0,1) into table_exists from user_tables where table_name = upper(create_type.table_name); if table_exists = 0 then select table_name into v_supertype_table from acs_object_types where object_type = create_type.supertype; execute immediate 'create table ' || table_name || ' (' || id_column || ' integer primary key references ' || v_supertype_table || ')'; end if; acs_object_type.create_type ( supertype => create_type.supertype, object_type => create_type.content_type, pretty_name => create_type.pretty_name, pretty_plural => create_type.pretty_plural, table_name => create_type.table_name, id_column => create_type.id_column, name_method => create_type.name_method ); refresh_view(content_type); end create_type; procedure drop_type ( content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f' ) is cursor attribute_cur is select attribute_name from acs_attributes where object_type = drop_type.content_type; cursor child_type_cur is select object_type from acs_object_types where supertype = drop_type.content_type; table_exists integer; v_table_name varchar2(50); is_subclassed_p char; begin -- first we'll rid ourselves of any dependent child types, if any , along with their -- own dependent grandchild types select decode(count(*),0,'f','t') into is_subclassed_p from acs_object_types where supertype = drop_type.content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children's packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_children_p = 't' and is_subclassed_p = 't' then for child_rec in child_type_cur loop drop_type( content_type => child_rec.object_type, drop_children_p => 't' ); end loop; end if; -- now drop all the attributes related to this type for attr_row in attribute_cur loop drop_attribute( content_type => drop_type.content_type, attribute_name => attr_row.attribute_name ); end loop; -- we'll remove the associated table if it exists select decode(count(*),0,0,1) into table_exists from user_tables u, acs_object_types objet where objet.object_type = drop_type.content_type and u.table_name = upper(objet.table_name); if table_exists = 1 and drop_table_p = 't' then select table_name into v_table_name from acs_object_types where object_type = drop_type.content_type; -- drop the input/output views for the type -- being dropped. -- FIXME: does the trigger get dropped when the -- view is dropped? This did not exist in the 4.2 release, -- and it needs to be tested. execute immediate 'drop view ' || v_table_name || 'x'; execute immediate 'drop view ' || v_table_name || 'i'; execute immediate 'drop table ' || v_table_name; end if; acs_object_type.drop_type( object_type => drop_type.content_type ); end drop_type; function create_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE is v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists integer; begin -- add the appropriate column to the table begin select upper(table_name) into v_table_name from acs_object_types where object_type = create_attribute.content_type; exception when no_data_found then raise_application_error(-20000, 'Content type ''' || content_type || ''' does not exist in content_type.create_attribute'); end; select decode(count(*),0,0,1) into v_column_exists from user_tab_columns where table_name = v_table_name and column_name = upper(attribute_name); if v_column_exists = 0 then execute immediate 'alter table ' || v_table_name || ' add ' || attribute_name || ' ' || column_spec; end if; v_attr_id := acs_attribute.create_attribute ( object_type => create_attribute.content_type, attribute_name => create_attribute.attribute_name, datatype => create_attribute.datatype, pretty_name => create_attribute.pretty_name, pretty_plural => create_attribute.pretty_plural, sort_order => create_attribute.sort_order, default_value => create_attribute.default_value ); refresh_view(content_type); return v_attr_id; end create_attribute; procedure drop_attribute ( content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ) is v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information begin select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute.content_type and a.object_type = drop_attribute.content_type and a.attribute_name = drop_attribute.attribute_name; exception when no_data_found then raise_application_error(-20000, 'Attribute ' || content_type || ':' || attribute_name || ' does not exist in content_type.drop_attribute'); end; -- Drop the attribute acs_attribute.drop_attribute(content_type, attribute_name); -- Drop the column if neccessary if drop_column = 't' then begin execute immediate 'alter table ' || v_table || ' drop column ' || attribute_name; exception when others then raise_application_error(-20000, 'Unable to drop column ' || v_table || '.' || attribute_name || ' in content_type.drop_attribute'); end; end if; refresh_view(content_type); end drop_attribute; procedure register_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ) is v_template_registered integer; begin select count(*) into v_template_registered from cr_type_template_map where content_type = register_template.content_type and use_context = register_template.use_context and template_id = register_template.template_id; -- register the template if v_template_registered = 0 then insert into cr_type_template_map ( template_id, content_type, use_context, is_default ) values ( template_id, content_type, use_context, is_default ); -- update the registration status of the template else -- unset the default template before setting this one as the default if register_template.is_default = 't' then update cr_type_template_map set is_default = 'f' where content_type = register_template.content_type and use_context = register_template.use_context; end if; update cr_type_template_map set is_default = register_template.is_default where template_id = register_template.template_id and content_type = register_template.content_type and use_context = register_template.use_context; end if; end register_template; procedure set_default_template ( content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is begin update cr_type_template_map set is_default = 't' where template_id = set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context; -- make sure there is only one default template for -- any given content_type/use_context pair update cr_type_template_map set is_default = 'f' where template_id ^= set_default_template.template_id and content_type = set_default_template.content_type and use_context = set_default_template.use_context and is_default = 't'; end set_default_template; function get_template ( content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE is v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template.content_type and use_context = get_template.use_context and is_default = 't'; return v_template_id; exception when NO_DATA_FOUND then return null; end get_template; procedure unregister_template ( content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ) is begin if unregister_template.use_context is null and unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id; elsif unregister_template.use_context is null then delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type; elsif unregister_template.content_type is null then delete from cr_type_template_map where template_id = unregister_template.template_id and use_context = unregister_template.use_context; else delete from cr_type_template_map where template_id = unregister_template.template_id and content_type = unregister_template.content_type and use_context = unregister_template.use_context; end if; end unregister_template; -- Helper function for refresh_trigger (below) to generate the -- insert statement for a particular content type; function trigger_insert_statement ( content_type in acs_object_types.object_type%TYPE ) return varchar2 is v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cursor attr_cur is select attribute_name from acs_attributes where object_type = trigger_insert_statement.content_type; cols varchar2(2000) := ''; vals varchar2(2000) := ''; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement.content_type; for attr_rec in attr_cur loop cols := cols || ', ' || attr_rec.attribute_name; vals := vals || ', :new.' || attr_rec.attribute_name; end loop; return 'insert into ' || v_table_name || ' ( ' || v_id_column || cols || ' ) values ( new_revision_id' || vals || ')'; end trigger_insert_statement; -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ) is tr_text varchar2(10000) := ''; v_table_name acs_object_types.table_name%TYPE; cursor type_cur is select object_type from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = refresh_trigger.content_type order by level desc; begin -- get the table name for the content type (determines view name) select table_name into v_table_name from acs_object_types where object_type = refresh_trigger.content_type; -- start building trigger code tr_text := ' create or replace trigger ' || v_table_name || 't instead of insert on ' || v_table_name || 'i for each row declare new_revision_id integer; begin if :new.item_id is null then raise_application_error(-20000, ''item_id is required when inserting into ' || v_table_name || 'i ''); end if; if :new.text is not null then new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, text => :new.text, package_id => :new.object_package_id ); else new_revision_id := content_revision.new( revision_id => :new.revision_id, title => :new.title, description => :new.description, mime_type => :new.mime_type, nls_language => :new.nls_language, item_id => content_symlink.resolve(:new.item_id), creation_ip => :new.creation_ip, creation_user => :new.creation_user, data => :new.data, package_id => :new.object_package_id ); end if;'; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in type_cur loop tr_text := tr_text || ' ' || trigger_insert_statement(type_rec.object_type) || '; '; end loop; -- end building the trigger code tr_text := tr_text || ' end ' || v_table_name || 't;'; -- (Re)create the trigger execute immediate tr_text; end refresh_trigger; -- Create or replace a view joining all attribute tables procedure refresh_view ( content_type in cr_type_template_map.content_type%TYPE ) is -- exclude the BLOB column because it will make it impossible -- to do a select * cursor join_cur is select distinct lower(table_name) as table_name, id_column, level from acs_object_types where object_type <> 'acs_object' and object_type <> 'content_revision' and lower(table_name) <> 'acs_objects' and lower(table_name) <> 'cr_revisions' start with object_type = refresh_view.content_type connect by object_type = prior supertype; cols varchar2(1000); tabs varchar2(1000); joins varchar2(1000) := ''; v_table_name varchar2(40); begin for join_rec in join_cur loop cols := cols || ', ' || join_rec.table_name || '.*'; tabs := tabs || ', ' || join_rec.table_name; joins := joins || ' and acs_objects.object_id = ' || join_rec.table_name || '.' || join_rec.id_column; end loop; select table_name into v_table_name from acs_object_types where object_type = content_type; -- create the input view (includes content columns) execute immediate 'create or replace view ' || v_table_name || 'i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.content as data, cr_text.text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language' || cols || ' from acs_objects, cr_revisions cr, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id ' || joins; -- create the output view (excludes content columns to enable SELECT *) execute immediate 'create or replace view ' || v_table_name || 'x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id' || cols || ' from acs_objects, cr_revisions cr, cr_items i, cr_text' || tabs || ' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id' || joins; refresh_trigger(content_type); exception when others then dbms_output.put_line('Error creating attribute view or trigger for ' || content_type); end refresh_view; procedure register_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin select decode(count(*),0,0,1) into v_exists from cr_type_children where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; if v_exists = 0 then insert into cr_type_children ( parent_type, child_type, relation_tag, min_n, max_n ) values ( parent_type, child_type, relation_tag, min_n, max_n ); else update cr_type_children set min_n = register_child_type.min_n, max_n = register_child_type.max_n where parent_type = register_child_type.parent_type and child_type = register_child_type.child_type and relation_tag = register_child_type.relation_tag; end if; end register_child_type; procedure unregister_child_type ( parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ) is begin delete from cr_type_children where parent_type = unregister_child_type.parent_type and child_type = unregister_child_type.child_type and relation_tag = unregister_child_type.relation_tag; end unregister_child_type; procedure register_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ) is v_exists integer; begin -- check if the relation type exists select decode(count(*),0,0,1) into v_exists from cr_type_relations where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; -- if the relation type does not exist, insert a row into cr_type_relations if v_exists = 0 then insert into cr_type_relations ( content_type, target_type, relation_tag, min_n, max_n ) values ( content_type, target_type, relation_tag, min_n, max_n ); -- otherwise, update the row in cr_type_relations else update cr_type_relations set min_n = register_relation_type.min_n, max_n = register_relation_type.max_n where content_type = register_relation_type.content_type and target_type = register_relation_type.target_type and relation_tag = register_relation_type.relation_tag; end if; end register_relation_type; procedure unregister_relation_type ( content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ) is begin delete from cr_type_relations where content_type = unregister_relation_type.content_type and target_type = unregister_relation_type.target_type and relation_tag = unregister_relation_type.relation_tag; end unregister_relation_type; procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is v_valid_registration integer; begin -- check if this type is already registered select count(*) into v_valid_registration from cr_mime_types where not exists ( select 1 from cr_content_mime_type_map where mime_type = register_mime_type.mime_type and content_type = register_mime_type.content_type ) and mime_type = register_mime_type.mime_type; if v_valid_registration = 1 then insert into cr_content_mime_type_map ( content_type, mime_type ) values ( register_mime_type.content_type, register_mime_type.mime_type ); end if; end register_mime_type; procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ) is begin delete from cr_content_mime_type_map where content_type = unregister_mime_type.content_type and mime_type = unregister_mime_type.mime_type; end unregister_mime_type; function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char is v_is_content_type char(1) := 'f'; begin if object_type = 'content_revision' then v_is_content_type := 't'; else select decode(count(*),0,'f','t') into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type.object_type and ancestor_type = 'content_revision'; end if; return v_is_content_type; end is_content_type; procedure rotate_template ( template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) is v_template_id cr_templates.template_id%TYPE; -- items that have an associated default template but not at the item level cursor c_items_cursor is select item_id from cr_items i, cr_type_template_map m where i.content_type = rotate_template.v_content_type and m.use_context = rotate_template.use_context and i.content_type = m.content_type and not exists ( select 1 from cr_item_template_map where item_id = i.item_id and use_context = rotate_template.use_context ); begin -- get the default template select template_id into v_template_id from cr_type_template_map where content_type = rotate_template.v_content_type and use_context = rotate_template.use_context and is_default = 't'; if v_template_id is not null then -- register an item-template to all items without an item-template for v_items_val in c_items_cursor loop content_item.register_template ( item_id => v_items_val.item_id, template_id => v_template_id, use_context => rotate_template.use_context ); end loop; end if; -- register the new template as the default template of the content type if v_template_id ^= rotate_template.template_id then content_type.register_template( content_type => rotate_template.v_content_type, template_id => rotate_template.template_id, use_context => rotate_template.use_context, is_default => 't' ); end if; end rotate_template; end content_type; / show errors -- Refresh the attribute triggers begin for type_rec in (select object_type from acs_object_types connect by supertype = prior object_type start with object_type = 'content_revision') loop content_type.refresh_view(type_rec.object_type); end loop; end; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.1.2d3-5.1.2d4.sql0000644000175000017500000000014310100417374030623 0ustar frankiefrankiecreate or replace view content_item_globals as select -100 as c_root_folder_id from dual; openacs-5.7.0/packages/acs-content-repository/sql/oracle/upgrade/upgrade-5.0.0b3-5.0.0b4.sql0000644000175000017500000000043207766162042030627 0ustar frankiefrankie-- there was an infinite loop in content_item.get_parent_folder if called with -- a child content_item rather than a content item which was directly below a -- folder. @@ ../content-item.sql -- fix error in setting context_id in content_revision__copy @@ ../content-revision.sqlopenacs-5.7.0/packages/acs-content-repository/sql/oracle/content-test.sql0000644000175000017500000003217110057204431026420 0ustar frankiefrankieset serveroutput on size 1000000 format wrapped declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin -- create folders and an item folder_id := content_folder.new('grandpa', 'Grandpa', NULL, -100); folder_b_id := content_folder.new('grandma', 'Grandma', NULL, -100); sub_folder_id := content_folder.new('pa', 'Pa', NULL, folder_id); sub_sub_folder_id := content_folder.new('me', 'Me', NULL, sub_folder_id); item_id := content_item.new('puppy', sub_sub_folder_id); simple_item_id := content_item.new( name => 'bunny', title => 'Bugs Bunny', description => 'Simple (Revisionless) Item Test', text => 'Simple (Revisionless) Item Test Text', parent_id => sub_sub_folder_id ); live_revision_id := content_revision.new( title => 'Live Revision of Puppy', description => 'Live Revision of Puppy Description', publish_date => to_date('1999-08-12','YYYY-MM-DD'), mime_type => 'text/html', text => 'Text for Live Revision of Puppy', item_id => item_id ); late_revision_id := content_revision.new( title => 'Latest Revision of Puppy', description => 'Latest Revision of Puppy Description', publish_date => to_date('2001-09-22','YYYY-MM-DD'), mime_type => 'text/html', text => 'Text for Latest Revision of Puppy', item_id => item_id ); item_template_id := content_template.new( name => 'Item Template' ); type_template_id := content_template.new( name => 'Type Template' ); def_type_template_id := content_template.new( name => 'Dumb Default Type Template' ); dum_template_id := content_template.new( name => 'Default Type Template' ); dbms_output.put_line('-------------------------------------'); dbms_output.put_line('CREATING CONTENT FOLDERS AND ITEMS...'); dbms_output.put_line('...all tests passed'); dbms_output.put_line('Folder grandpa is ' || folder_id); dbms_output.put_line('Folder grandma is ' || folder_b_id); dbms_output.put_line('Sub folder pa is ' || sub_folder_id); dbms_output.put_line('Sub sub folder me is ' || sub_sub_folder_id); dbms_output.put_line('Added item puppy to sub sub folder me at ' || item_id); dbms_output.put_line('Created simple item bunny to sub sub folder me at ' || simple_item_id); --dbms_output.put_line('Added a revision to puppy at ' || live_revision_id); --dbms_output.put_line('Added a revision to puppy at ' || late_revision_id); --dbms_output.put_line('Created Item Template at ' || item_template_id); --dbms_output.put_line('Created Type Template at ' || type_template_id); --dbms_output.put_line('Created Def Type Template at ' || def_type_template_id); --dbms_output.put_line('Created Dum Def Type Template at ' || dum_template_id); dbms_output.put_line('-----------------------------------'); dbms_output.put_line('FOLDERS AND EMPTY FOLDERS AND SUBFOLDERS'); dbms_output.put_line('...all tests passed'); --dbms_output.put_line('Is folder ' || folder_id || ' empty? ' || -- content_folder.is_empty(folder_id)); --dbms_output.put_line('Is folder ' || sub_sub_folder_id || ' empty? ' || -- content_folder.is_empty(sub_sub_folder_id)); --dbms_output.put_line('Is folder ' || sub_folder_id || ' empty? ' || -- content_folder.is_empty(sub_folder_id)); --dbms_output.put_line('Is folder ' || folder_b_id || ' empty? ' || -- content_folder.is_empty(folder_b_id)); --dbms_output.put_line('Is folder ' || folder_id || '? ' || -- content_folder.is_folder(folder_id)); --dbms_output.put_line('Is folder ' || item_id || '? ' || -- content_folder.is_folder(item_id)); --dbms_output.put_line('Is ' || folder_id || ' a subfolder of ' || -- sub_folder_id || '? ' || content_folder.is_sub_folder(sub_folder_id,folder_id)); --dbms_output.put_line('Is ' || sub_folder_id || ' a subfolder of ' || -- folder_id || '? ' || content_folder.is_sub_folder(folder_id,sub_folder_id)); --dbms_output.put_line('Is ' || sub_sub_folder_id || ' a subfolder of ' || -- folder_id || '? ' || content_folder.is_sub_folder(folder_id,sub_sub_folder_id)); --dbms_output.put_line('Is ' || sub_folder_id || ' a subfolder of ' || -- -1 || '? ' || content_folder.is_sub_folder(-1,sub_folder_id)); dbms_output.put_line('-------------------------------------'); dbms_output.put_line('LIVE AND LATEST REVISIONS...'); dbms_output.put_line('...all tests passed'); --dbms_output.put_line('Get live_revision_id for item puppy ' || item_id || -- ' is ' || content_item.get_live_revision(item_id)); content_item.set_live_revision(live_revision_id); --dbms_output.put_line('Set ' || live_revision_id || -- ' as the live revision for item puppy ' || item_id); --dbms_output.put_line('Get live_revision_id for item puppy ' || item_id || -- ' is ' || content_item.get_live_revision(item_id)); --dbms_output.put_line('Get live_revision_id for item kitty ' || -- simple_item_id || ' is ' || -- content_item.get_live_revision(simple_item_id)); --dbms_output.put_line('Get late_revision_id for item puppy ' || item_id || -- ' is ' || content_item.get_latest_revision(item_id)); --dbms_output.put_line('Get late_revision_id for item bunny ' || simple_item_id || -- ' is ' || content_item.get_latest_revision(simple_item_id)); content_item.register_template(item_id,item_template_id,'public'); content_type.register_template('content_revision',type_template_id,'public'); content_type.register_template('content_revision',def_type_template_id,'admin'); content_type.register_template('content_revision',dum_template_id,'admin','t'); content_type.set_default_template('content_revision',def_type_template_id,'admin'); dbms_output.put_line('-------------------------------------'); dbms_output.put_line('REGISTERING TEMPLATES TO ITEMS AND TYPES...'); dbms_output.put_line('...all tests passed'); --dbms_output.put_line('Registered Item Template ' || item_template_id || -- ' to item puppy ' || item_id || ' with public context'); --dbms_output.put_line('Registered Type Template ' || type_template_id || -- ' to content_revision ' || item_id || ' with public context'); --dbms_output.put_line('Registered Default Type Template ' || -- def_type_template_id || ' to content_revision ' || item_id || -- ' with admin context'); --dbms_output.put_line('Get template id for item puppy ' || item_id || -- ' and context public is ' || content_item.get_template(item_id,'public')); --dbms_output.put_line('Get template id for item puppy ' || item_id || -- ' and context admin is ' || content_item.get_template(item_id,'admin')); found_folder_id := content_item.get_id('grandpa/pa/me', -1); dbms_output.put_line('-------------------------------------'); dbms_output.put_line('LOCATING CONTENT FOLDERS AND ITEMS...'); dbms_output.put_line('...all tests passed!'); --dbms_output.put_line('Found me at grandpa/pa/me: ' || found_folder_id); --dbms_output.put_line('Path for ' || found_folder_id || ' is ' || -- content_item.get_path(found_folder_id)); dbms_output.put_line('Path for puppy ' || item_id || ' is ' || content_item.get_path(item_id)); dbms_output.put_line('Path for puppy ' || item_id || ' from folder_id: ' || folder_id || ' is ' || content_item.get_path(item_id,folder_id)); dbms_output.put_line('Path for puppy ' || item_id || ' from sub_folder_id: ' || sub_folder_id || ' is ' || content_item.get_path(item_id,sub_folder_id)); dbms_output.put_line('Path for puppy' || item_id || ' from sub_sub_folder_id: ' || sub_sub_folder_id || ' is ' || content_item.get_path(item_id,sub_sub_folder_id)); dbms_output.put_line('Get id of item with invalid path - shouldn''t return anything'); dbms_output.put_line('Found item at ' || content_item.get_id('grandpa/me', -200)); dbms_output.put_line('Get id of item using subpath'); dbms_output.put_line('Found item at ' || content_item.get_id('pa/me/puppy', folder_id)); dbms_output.put_line('This is the path to a folder from a subfolder'); dbms_output.put_line('Path for ' || sub_folder_id || ' from sub_sub_folder_id: ' || sub_sub_folder_id || ' is ' || content_item.get_path(sub_folder_id,sub_sub_folder_id)); dbms_output.put_line('This is a path to an item from a non-existant item'); dbms_output.put_line('Path for ' || item_id || ' from nonexistant_id: ' || -200 || ' is ' || content_item.get_path(item_id,-200)); dbms_output.put_line('This is a path to an item from a non-related branch'); dbms_output.put_line('Path for ' || item_id || ' from unrelated branch: ' || folder_b_id || ' is ' || content_item.get_path(item_id,folder_b_id)); dbms_output.put_line('-------------------------------------'); dbms_output.put_line('MOVING/RENAMING CONTENT FOLDERS...'); dbms_output.put_line('...all tests passed'); --dbms_output.put_line('Moving me from under pa to under grandpa'); content_item.move(sub_sub_folder_id, folder_id); --dbms_output.put_line('Path for ' || item_id || ' is ' || --content_item.get_path(item_id)); --dbms_output.put_line('Moving grandpa to pa - this should''nt work'); -- content_folder.move(folder_id, sub_folder_id); --dbms_output.put_line('Path for ' || item_id || ' is ' || -- content_item.get_path(item_id)); --dbms_output.put_line('Renaming puppy to kitty...'); content_item.edit_name(item_id, 'kitty'); --dbms_output.put_line('Renaming me to aunty...'); content_folder.edit_name(sub_sub_folder_id, 'aunty'); --dbms_output.put_line('Path for ' || item_id || ' is ' || -- content_item.get_path(item_id)); --dbms_output.put_line('Renaming kitty to pa -- this should work'); --content_item.edit_name(item_id, 'pa'); --dbms_output.put_line('Path for ' || item_id || ' is ' || --content_item.get_path(item_id)); dbms_output.put_line('-------------------------------------'); dbms_output.put_line('SYMLINKS...'); --dbms_output.put_line('...all tests passed'); /* symlink_a_id := content_symlink.new('link_a',sub_sub_folder_id,sub_folder_id); dbms_output.put_line('Create a link in pa to aunty: Symlink is ' || symlink_a_id); dbms_output.put_line('Is ' || symlink_a_id || ' a symlink?: ' || content_symlink.is_symlink(symlink_a_id)); dbms_output.put_line('Is ' || folder_id || ' a symlink?: ' || content_symlink.is_symlink(folder_id)); dbms_output.put_line('Path for symlink ' || symlink_a_id || ' is ' || content_item.get_path(symlink_a_id)); dbms_output.put_line('Resolving symlink ' || symlink_a_id || ' is ' || content_symlink.resolve(symlink_a_id)); dbms_output.put_line('Resolved path for symlink ' || symlink_a_id || ' is ' || content_item.get_path(content_symlink.resolve(symlink_a_id))); dbms_output.put_line('Path to item ' || item_id || ' from symlink ' || symlink_a_id || ' is ' || content_item.get_path(item_id, symlink_a_id)); dbms_output.put_line('Path to item ' || item_id || ' from aunty ' || sub_sub_folder_id || ' is ' || content_item.get_path(item_id, sub_sub_folder_id)); dbms_output.put_line('Path to pa ' || sub_folder_id || ' from symlink ' || symlink_a_id || ' is ' || content_item.get_path(sub_folder_id, symlink_a_id)); dbms_output.put_line('Found item ' || item_id || ' at ' || content_item.get_id('/grandpa/aunty/kitty')); dbms_output.put_line('Found item ' || item_id || ' at ' || content_item.get_id('/grandpa/pa/link_a/kitty')); dbms_output.put_line('Found item ' || item_id || ' starting at aunty ' || sub_sub_folder_id || ' at ' || content_item.get_id('kitty',sub_sub_folder_id)); dbms_output.put_line('Found item ' || item_id || ' starting at symlink ' || symlink_a_id || ' at ' || content_item.get_id('kitty',symlink_a_id)); dbms_output.put_line('Found item ' || item_id || ' starting at pa ' || sub_folder_id || ' at ' || content_item.get_id('link_a/kitty',sub_folder_id)); dbms_output.put_line('--------------------------------'); */ --dbms_output.put_line('Moving item ' || item_id || ' to grandma ' || -- folder_b_id); --content_item.move(item_id,folder_b_id); --dbms_output.put_line('Path for item ' || item_id || ' is ' || -- content_item.get_path(item_id)); --dbms_output.put_line('Moving folder ' || folder_b_id || ' to aunty ' || -- sub_sub_folder_id); ----content_item.move(folder_b_id,sub_sub_folder_id); --dbms_output.put_line('Path for item ' || item_id || ' is ' || -- content_item.get_path(item_id)); --dbms_output.put_line('--------------------------------'); -- symlinks/revisions should be deleted automatically /* content_item.del(simple_item_id); content_template.del(item_template_id); content_item.del(item_id); content_template.del(type_template_id); content_template.del(def_type_template_id); content_template.del(dum_template_id); content_folder.del(sub_sub_folder_id); content_folder.del(sub_folder_id); content_folder.del(folder_id); content_folder.del(folder_b_id); */ end; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-xml.sql0000644000175000017500000000166710506237540026255 0ustar frankiefrankie-- Data model to support XML exchange with thecontent repository of -- the ArsDigita Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-xml.sql,v 1.2 2006/09/26 14:55:28 byronl Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- A sequence for uniquely identifying uploaded XML documents until -- they are inserted into the repository create sequence cr_xml_doc_seq; create global temporary table cr_xml_docs ( doc_id integer constraint cr_xml_docs_doc_id_pk primary key, doc CLOB ) on commit delete rows; comment on table cr_xml_docs is ' A temporary table for holding uploaded XML documents for the duration of a transaction, until they can be inserted into the content repository. '; openacs-5.7.0/packages/acs-content-repository/sql/oracle/packages-create.sql0000644000175000017500000022745010744672247027037 0ustar frankiefrankie -- Ensure that the data model is up-to-date before compiling packages @@ content-util.sql @@ content-update.sql create or replace package content_type AUTHID CURRENT_USER as --/** This package is used to manipulate content types and attributes -- --*/ procedure create_type ( --/** Create a new content type. Automatically create the attribute table -- for the type if the table does not already exist. -- @author Karl Goldstein -- @param content_type The name of the new type -- @param supertype The supertype, defaults to content_revision -- @param pretty_name Pretty name for the type, singular -- @param pretty_plural Pretty name for the type, plural -- @param table_name The name for the attribute table, defaults to -- the name of the supertype -- @param id_column The primary key for the table, defaults to 'XXX' -- @param name_method As in acs_object_type.create_type -- @see {acs_object_type.create_type} --*/ content_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.object_type%TYPE default 'content_revision', pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', name_method in acs_object_types.name_method%TYPE default null ); procedure drop_type ( --/** First drops all attributes related to a specific type, then drops type -- the given type. -- @author Simon Huynh -- @param content_type The content type to be dropped -- @param drop_children_p If 't', then the sub-types -- of the given content type and their associated tables -- are also dropped. --*/ content_type in acs_object_types.object_type%TYPE, drop_children_p in char default 'f', drop_table_p in char default 'f', drop_objects_p in char default 'f' ); function create_attribute ( --/** Create a new attribute for the specified type. Automatically create -- the column for the attribute if the column does not already exist. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to create -- @param pretty_name Pretty name for the new attribute, singular -- @param pretty_plural Pretty name for the new attribute, plural -- @param default_value The default value for the attribute, defaults to null -- @return The id of the newly created attribute -- @see {acs_object_type.create_attribute}, {content_type.create_type} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, sort_order in acs_attributes.sort_order%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, column_spec in varchar2 default 'varchar2(4000)' ) return acs_attributes.attribute_id%TYPE; procedure drop_attribute ( --/** Drop an existing attribute. If you are using CMS, make sure to -- call cm_form_widget.unregister_attribute_widget before calling -- this function. -- @author Karl Goldstein -- @param content_type The name of the type to alter -- @param attribute_name The name of the attribute to drop -- @param drop_column If 't', will also alter the table and remove -- the column where the attribute is stored. The default is 'f' -- (leaves the table untouched). -- @see {acs_object.drop_attribute}, {content_type.create_attribute}, -- {cm_form_widget.unregister_attribute_widget} --*/ content_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, drop_column in varchar2 default 'f' ); procedure register_template ( --/** Register a template for the content type. This template may be used -- to render all items of that type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be registered -- @param template_id The ID of the template to register -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @param is_default If 't', this template becomes the default template for -- the type, default is 'f'. -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.set_default_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE, is_default in cr_type_template_map.is_default%TYPE default 'f' ); procedure set_default_template ( --/** Make the registered template a default template. The default template -- will be used to render all items of the type for which no individual -- template is registered. -- @author Karl Goldstein -- @param content_type The type for which the template is to be made default -- @param template_id The ID of the template to make default -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE ); function get_template ( --/** Retrieve the appropriate template for rendering items of the specified type. -- @author Karl Goldstein -- @param content_type The type for which the template is to be retrieved -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @return The ID of the template to use -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.unregister_template}, -- {content_type.register_template}, {content_type.set_default_template} --*/ content_type in cr_type_template_map.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; procedure unregister_template ( --/** Unregister a template. If the unregistered template was the default template, -- the content_type can no longer be rendered in the use_context, -- @author Karl Goldstein -- @param content_type The type for which the template is to be unregistered -- @param template_id The ID of the template to unregister -- @param use_context The context in which the template is to be unregistered -- @see {content_item.register_template}, {content_item.unregister_template}, -- {content_item.get_template}, {content_type.set_default_template}, -- {content_type.register_template}, {content_type.get_template} --*/ content_type in cr_type_template_map.content_type%TYPE default null, template_id in cr_templates.template_id%TYPE, use_context in cr_type_template_map.use_context%TYPE default null ); procedure refresh_view ( --/** Create a view for the type which joins all attributes of the type, -- including the inherited attributes. The view is named -- "
X" -- Called by create_attribute and create_type. -- @author Karl Goldstein -- @param content_type The type for which the view is to be created. -- @see {content_type.create_type} --*/ content_type in cr_type_template_map.content_type%TYPE ); procedure register_relation_type ( --/** Register a relationship between a content type and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate any relationship between an item and another -- object. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.unregister_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_relation_type ( --/** Unregister a relationship between a content type and another object -- type. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param target_type The type of the item to which the relationship -- is targeted. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type} --*/ content_type in cr_type_relations.content_type%TYPE, target_type in cr_type_relations.target_type%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default null ); procedure register_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param content_type The type of the item from which the relationship -- originated. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @param min_n The minimun number of parent-child -- relationships of this type -- which an item must have to go live. -- @param max_n The minimun number of relationships of this type -- which an item must have to go live. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default 'generic', min_n in integer default 0, max_n in integer default null ); procedure unregister_child_type ( --/** Register a parent-child relationship between a content type -- and another object -- type. This may then be used by the content_item.is_valid_relation -- function to validate the relationship between an item and a potential -- child. -- @author Karl Goldstein -- @param parent_type The type of the parent item. -- @param child_type The type of the child item. -- @param relation_tag A simple token used to identify a set of -- relations. -- @see {content_type.register_relation_type}, {content_type.register_child_type} --*/ parent_type in cr_type_children.parent_type%TYPE, child_type in cr_type_children.child_type%TYPE, relation_tag in cr_type_children.relation_tag%TYPE default null ); procedure register_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); procedure unregister_mime_type ( content_type in cr_content_mime_type_map.content_type%TYPE, mime_type in cr_content_mime_type_map.mime_type%TYPE ); function is_content_type ( object_type in acs_object_types.object_type%TYPE ) return char; procedure rotate_template ( --/** Sets the default template for a content type and registers all the -- previously existing items of that content type to the original -- template -- @author Michael Pih -- @param template_id The template that will become the default -- registered template for the specified content type and use context -- @param v_content_type The content type -- @param use_context The context in which the template will be used --*/ template_id in cr_templates.template_id%TYPE, v_content_type in cr_items.content_type%TYPE, use_context in cr_type_template_map.use_context%TYPE ); -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type procedure refresh_trigger ( content_type in acs_object_types.object_type%TYPE ); end content_type; / show errors; create or replace package content_item as --/** --Content items store the overview of the content published on a --website. The actual content is stored in content revisions. It is --implemented this way so that there can be mulitple versions of the --actual content while the main idea remains constant. For example: If --there is a review for the movie "Terminator," there will exist a --content item by the name "terminator" with all the right parameters --(supertype, parent, etc), there will also exist at least one content --revision pointing to this item with the actual review content. --@see {content_revision}, {content_folder} --*/ c_root_folder_id constant integer := -100; function get_root_folder ( item_id in cr_items.item_id%TYPE default null ) return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content item. If the data, title or text -- parameters are specified, also creates a revision for the item. -- @author Karl Goldstein -- @param name The name for the item, must be URL-encoded. -- If an item with this name already exists under the specified -- parent item, an error is thrown -- @param parent_id The parent of this item, defaults to null -- @param item_id The id of the new item. A new id will be allocated if this -- parameter is null -- @param locale The locale for this item, for use with Intermedia search -- @param item_subtype The type of the new item, defaults to 'content_item' -- This parameter is used to support inheritance, so that -- subclasses of content_item can call this function -- to initialize the parent class -- @param content_type The content type for the item, defaults to -- 'content_revision'. Only objects of this type -- may be used as revisions for the item -- @param title The user-readable title for the item, defaults to the item's -- name -- @param description A short description for the item (4000 characters maximum) -- @param mime_type The file type of the item, defaults to 'text/plain' -- @param nls_language The language for the item, used for Intermedia search -- @param text The text content of the new revision, 4000 charcters maximum. -- Cannot be specified simultaneously with the data -- parameter -- @param data The blob content of the new revision. Cannot be specified -- simultaneously with the text parameter -- @param relation_tag If a parent-child relationship is registered -- for these content types, use this tag to -- describe the parent-child relationship. Defaults -- to 'parent content type'-'child content type' -- @param is_live If 't', the new revision will become live -- @param context_id Security context id, as in acs_object.new -- If null, defaults to parent_id, and copies permissions -- from the parent into the current item -- @param storage_type in ('lob','file'). Indicates how content is to be stored. -- 'file' content is stored externally in the file system. -- @param others As in acs_object.new -- @return The id of the newly created item -- @see {acs_object.new} --*/ name in cr_items.name%TYPE, parent_id in cr_items.parent_id%TYPE default null, item_id in acs_objects.object_id%TYPE default null, locale in cr_items.locale%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, context_id in acs_objects.context_id%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, item_subtype in acs_object_types.object_type%TYPE default 'content_item', content_type in acs_object_types.object_type%TYPE default 'content_revision', title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, data in cr_revisions.content%TYPE default null, relation_tag in cr_child_rels.relation_tag%TYPE default null, is_live in char default 'f', storage_type in cr_items.storage_type%TYPE default 'lob', security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_items.item_id%TYPE; function is_published ( --/** Determins whether an item is published or not. -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is published, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE ) return char; function is_publishable ( --/** Determines if an item is publishable. Publishable items must -- meet the following criteria: -- 1) for each child type, the item has n children, min_n < n < max_n -- 2) for each relation type, the item has n relations, min_n < n < max_n -- 3) any 'publishing_wf' workflows are finished -- @author Michael Pih -- @param item_id The item ID -- @return 't' if the item is publishable in it's present state, -- Otherwise, returns 'f' --*/ item_id in cr_items.item_id%TYPE ) return char; function is_valid_child ( --/** Determines if an item would be a valid child of another item by -- checking if the parent allows children of the would-be child's -- content type and if the parent already has n_max children of -- that content type. -- @author Michael Pih -- @param item_id The item ID of the potential parent -- @param content_type The content type of the potential child item -- @return 't' if the item would be a valid child, 'f' otherwise --*/ item_id in cr_items.item_id%TYPE, content_type in acs_object_types.object_type%TYPE, relation_tag in cr_child_rels.relation_tag%TYPE default null ) return char; procedure del ( --/** Deletes the specified content item, along with any revisions, symlinks, -- workflows, associated templates, associated keywords, -- child and item relationships for the item. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param item_id The id of the item to delete -- @see {acs_object.delete} --*/ item_id in cr_items.item_id%TYPE ); procedure edit_name ( --/** Renames the item. If an item with the specified name already exists -- under this item's parent, an error is thrown -- @author Karl Goldstein -- @param item_id The id of the item to rename -- @param name The new name for the item, must be URL-encoded -- @see {content_item.new} --*/ item_id in cr_items.item_id%TYPE, name in cr_items.name%TYPE ); function get_id ( --/** Takes in a path, such as "/tv/programs/star_trek/episode_203" -- and returns the id of the item with this path. Note: URLs are abstract (no -- extensions are allowed in content item names and extensions are stripped when -- looking up content items) -- @author Karl Goldstein -- @param item_path The path to be resolved -- @param root_folder_id Starts path resolution from this folder. Defaults to -- the root of the sitemap -- @param resolve_index Boolean flag indicating whether to return the -- id of the index page for folders (if one -- exists). Defaults to 'f'. -- @return The id of the item with the given path, or null if no such item exists -- @see {content_item.get_path} --*/ item_path in varchar2, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id, resolve_index in char default 'f' ) return cr_items.item_id%TYPE; function get_path ( --/** Retrieves the full path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Karl Goldstein -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The path to the item -- @see {content_item.get_id}, {content_item.write_to_file} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default null ) return varchar2; function get_virtual_path ( --/** Retrieves the virtual path to an item, in the form of -- "/tv/programs/star_trek/episode_203" -- @author Michael Pih -- @param item_id The item for which the path is to be retrieved -- @param root_folder_id Starts path resolution from this folder. -- Defaults to the root of the sitemap -- @return The virtual path to the item -- @see {content_item.get_id}, {content_item.write_to_file}, {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_folder_id in cr_items.item_id%TYPE default c_root_folder_id ) return varchar2; procedure write_to_file ( --/** Writes the content of the live revision of this item to a file, -- creating all the neccessary directories in the process -- @author Karl Goldstein -- @param item_id The item to be written to a file -- @param root_path The path in the filesystem to which the root of the -- sitemap corresponds -- @see {content_item.get_path} --*/ item_id in cr_items.item_id%TYPE, root_path in varchar2 ); procedure register_template ( --/** Registers a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be registered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.unregister_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ); procedure unregister_template ( --/** Unregisters a template which will be used to render this item. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param template_id The template to be registered -- @param use_context The context in which the template is appropriate, such -- as 'admin' or 'public' -- @see {content_type.register_template}, {content_item.register_template}, -- {content_item.get_template} --*/ item_id in cr_items.item_id%TYPE, template_id in cr_templates.template_id%TYPE default null, use_context in cr_item_template_map.use_context%TYPE default null ); function get_template ( --/** Retrieves the template which should be used to render this item. If no template -- is registered to specifically render the item in the given context, the -- default template for the item's type is returned. -- @author Karl Goldstein -- @param item_id The item for which the template will be unregistered -- @param use_context The context in the item is to be rendered, such -- as 'admin' or 'public' -- @return The id of the registered template, or null if no template could be -- found -- @see {content_type.register_template}, {content_item.register_template}, --*/ item_id in cr_items.item_id%TYPE, use_context in cr_item_template_map.use_context%TYPE ) return cr_templates.template_id%TYPE; function get_live_revision ( --/** Retrieves the id of the live revision for the item -- @param item_id The item for which the live revision is to be retrieved -- @return The id of the live revision for this item, or null if no live revision -- exists -- @see {content_item.set_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; procedure set_live_revision ( --/** Make the specified revision the live revision for the item -- @author Karl Goldstein -- @param revision_id The id of the revision which is to become live -- for its corresponding item -- @see {content_item.get_live_revision} --*/ revision_id in cr_revisions.revision_id%TYPE, publish_status in cr_items.publish_status%TYPE default 'ready' ); procedure unset_live_revision ( --/** Set the live revision to null for the item -- @author Michael Pih -- @param item_id The id of the item for which to unset the live revision -- @see {content_item.set_live_revision} item_id in cr_items.item_id%TYPE ); procedure set_release_period ( --/** Sets the release period for the item. This information may be -- used by applications to update the publishing status of items -- at periodic intervals. -- @author Karl Goldstein -- @param item_id The id the item. -- @param start_when The time and date when the item should be released. -- @param end_when The time and date when the item should be expired. --*/ item_id in cr_items.item_id%TYPE, start_when date default null, end_when date default null ); function get_revision_count ( --/** Return the total count of revisions for this item -- @author Karl Goldstein -- @param item_id The id the item -- @return The number of revisions for this item -- @see {content_revision.new} --*/ item_id in cr_items.item_id%TYPE ) return number; -- Return the object type of this item function get_content_type ( --/** Retrieve the content type of this item. Only objects of this type may be -- used as revisions for the item. -- @author Karl Goldstein -- @param item_id The item for which the content type is to be retrieved -- @return The content type of the item --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; function get_context ( --/** Retrieve the parent of the given item -- @author Karl Goldstein -- @param item_id The item for which the parent is to be retrieved -- @return The id of the parent for this item --*/ item_id in cr_items.item_id%TYPE ) return acs_objects.context_id%TYPE; procedure move ( --/** Move the specified item to a different folder. If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein -- @param item_id The item to be moved -- @param target_folder_id The new folder for the item -- @see {content_item.new}, {content_folder.new}, {content_item.copy} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function copy2 ( --/** Copies the item to a new location, creating an identical item with -- an identical latest revision (if any). If the target folder does -- not exist, or if the folder already contains an item with the same name -- as the given item, an error will be thrown. -- @author Karl Goldstein, Michael Pih -- @param item_id The item to be copied -- @param target_folder_id The folder where the item is to be copied -- @param creation_user The user_id of the creator -- @param creation_ip The IP address of the creator -- @return The item ID of the new copy. -- @see {content_item.new}, {content_folder.new}, {content_item.move} --*/ item_id in cr_items.item_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) return cr_items.item_id%TYPE; -- get the latest revision for an item function get_latest_revision ( --/** Retrieves the id of the latest revision for the item (as opposed to the live -- revision) -- @author Karl Goldstein -- @param item_id The item for which the latest revision is to be retrieved -- @return The id of the latest revision for this item, or null if no revisions -- exist -- @see {content_item.get_live_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_best_revision ( --/** Retrieves the id of the live revision for the item if one exists, -- otherwise retrieves the id of the latest revision if one exists. -- revision) -- @author Michael Pih -- @param item_id The item for which the revision is to be retrieved -- @return The id of the live or latest revision for this item, -- or null if no revisions exist -- @see {content_item.get_live_revision}, {content_item.get_latest_revision} --*/ item_id in cr_items.item_id%TYPE ) return cr_revisions.revision_id%TYPE; function get_title ( --/** Retrieves the title for the item, using either the latest or the live revision. -- If the specified item is in fact a folder, return the folder's label. -- In addition, this function will automatically resolve symlinks. -- @author Karl Goldstein -- @param item_id The item for which the title is to be retrieved -- @param is_live If 't', use the live revision to get the title. Otherwise, -- use the latest revision. The default is 'f' -- @return The title of the item -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, -- {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.title%TYPE; function get_publish_date ( --/** Retrieves the publish date for the item -- @author Karl Goldstein -- @param item_id The item for which the publish date is to be retrieved -- @param is_live If 't', use the live revision for the item. Otherwise, use -- the latest revision. The default is 'f' -- @return The publish date for the item, or null if the item has no revisions -- @see {content_item.get_live_revision}, {content_item.get_latest_revision}, --*/ item_id in cr_items.item_id%TYPE, is_live in char default 'f' ) return cr_revisions.publish_date%TYPE; function is_subclass ( --/** Determines if one type is a subclass of another. A class is always a subclass of -- itself. -- @author Karl Goldstein -- @param object_type The child class -- @param supertype The superclass -- @return 't' if the child class is a subclass of the superclass, 'f' otherwise -- @see {acs_object_type.create_type} --*/ object_type in acs_object_types.object_type%TYPE, supertype in acs_object_types.supertype%TYPE ) return char; function relate ( --/** Relates two content items -- @author Karl Goldstein -- @param item_id The item id -- @param object_id The item id of the related object -- @param relation_tag A tag to help identify the relation type, -- defaults to 'generic' -- @param order_n The order of this object among other objects -- of the same relation type, defaults to null. -- @param relation_type The object type of the relation, defaults to -- 'cr_item_rel' --*/ item_id in cr_items.item_id%TYPE, object_id in acs_objects.object_id%TYPE, relation_tag in cr_type_relations.relation_tag%TYPE default 'generic', order_n in cr_item_rels.order_n%TYPE default null, relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel' ) return cr_item_rels.rel_id%TYPE; procedure unrelate ( --/** Delete the item relationship between two items -- @author Michael Pih -- @param rel_id The relationship id -- @see {content_item.relate} --*/ rel_id in cr_item_rels.rel_id%TYPE ); function is_index_page ( --/** Determine if the item is an index page for the specified folder. -- The item is an index page for the folder if it exists in the -- folder and its item name is "index". -- @author Karl Goldstein -- @param item_id The item id -- @param folder_id The folder id -- @return 't' if the item is an index page for the specified -- folder, 'f' otherwise -- @see {content_folder.get_index_page} --*/ item_id in cr_items.item_id%TYPE, folder_id in cr_folders.folder_id%TYPE ) return varchar2; function get_parent_folder ( --/** Get the parent folder. -- @author Michael Pih -- @param item_id The item id -- @return the folder_id of the parent folder, null otherwise --*/ item_id in cr_items.item_id%TYPE ) return cr_folders.folder_id%TYPE; end content_item; / show errors create or replace package content_revision as function new ( --/** Create a new revision for an item. -- @author Karl Goldstein -- @param title The revised title for the item -- @param description A short description of this revision, 4000 characters maximum -- @param publish_date Publication date. -- @param mime_type The revised mime type of the item, defaults to 'text/plain' -- @param nls_language The revised language of the item, for use with Intermedia searching -- @param data The blob which contains the body of the revision -- @param item_id The id of the item being revised -- @param revision_id The id of the new revision. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created revision -- @see {acs_object.new}, {content_item.new} --*/ title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, data in cr_revisions.content%TYPE, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, filename in cr_revisions.filename%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_revisions.revision_id%TYPE; function new ( title in cr_revisions.title%TYPE, description in cr_revisions.description%TYPE default null, publish_date in cr_revisions.publish_date%TYPE default sysdate, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', nls_language in cr_revisions.nls_language%TYPE default null, text in varchar2 default null, item_id in cr_items.item_id%TYPE, revision_id in cr_revisions.revision_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null, filename in cr_revisions.filename%TYPE default null ) return cr_revisions.revision_id%TYPE; function copy ( --/** Creates a new copy of a revision, including all attributes and content -- and content, returning the ID of the new revision -- @author Karl Goldstein, Michael Pih -- @param revision_id The id of the revision to copy -- @param copy_id The id of the new copy (default null) -- @param target_item_id The id of the item which will own the copied revision. If null, the item that holds the original revision will own the copied revision. Defaults to null. -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (default null) -- @return The id of the new revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE, copy_id in cr_revisions.revision_id%TYPE default null, target_item_id in cr_items.item_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_revisions.revision_id%TYPE; procedure del ( --/** Deletes the revision. -- @author Karl Goldstein -- @param revision_id The id of the revision to delete -- @see {content_revision.new}, {acs_object.delete} --*/ revision_id in cr_revisions.revision_id%TYPE ); function get_number ( --/** Return the revision number of the specified revision, according to -- the chronological -- order in which revisions have been added for this item. -- @author Karl Goldstein -- @param revision_id The id the revision -- @return The number of the revision -- @see {content_revision.new} --*/ revision_id in cr_revisions.revision_id%TYPE ) return number; function revision_name ( --/** Return a pretty string 'revision x of y' --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure index_attributes( --/** Generates an XML document for insertion into cr_revision_attributes, -- which is indexed by Intermedia for searching attributes. -- @author Karl Goldstein -- @param revision_id The id of the revision to index -- @see {content_revision.new} --*/ revision_id IN cr_revisions.revision_id%TYPE ); function export_xml ( revision_id IN cr_revisions.revision_id%TYPE ) return cr_xml_docs.doc_id%TYPE; function write_xml ( revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.exportRevision( java.lang.Integer, oracle.sql.CLOB ) return int'; function import_xml ( item_id IN cr_items.item_id%TYPE, revision_id IN cr_revisions.revision_id%TYPE, doc_id IN number ) return cr_revisions.revision_id%TYPE; function read_xml ( item_id IN number, revision_id IN number, clob_loc IN clob ) return number as language java name 'com.arsdigita.content.XMLExchange.importRevision( java.lang.Integer, java.lang.Integer, oracle.sql.CLOB ) return int'; procedure to_html ( --/** Converts a revision uploaded as a binary document to html -- @author Karl Goldstein -- @param revision_id The id of the revision to index --*/ revision_id IN cr_revisions.revision_id%TYPE ); procedure replace( revision_id number, search varchar2, replace varchar2) as language java name 'com.arsdigita.content.Regexp.replace( int, java.lang.String, java.lang.String )'; function is_live ( -- /** Determine if the revision is live -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is live, 'f' otherwise -- @see {content_revision.is_latest} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; function is_latest ( -- /** Determine if the revision is the latest revision -- @author Karl Goldstein, Stanislav Freidin -- @param revision_id The id of the revision to check -- @return 't' if the revision is the latest revision for its item, 'f' otherwise -- @see {content_revision.is_live} --*/ revision_id in cr_revisions.revision_id%TYPE ) return varchar2; procedure to_temporary_clob ( revision_id in cr_revisions.revision_id%TYPE ); procedure content_copy ( -- /** Copies the content of the specified revision to the content -- of another revision -- @author Michael Pih -- @param revision_id The id of the revision with the content to be copied -- @param revision_id The id of the revision to be updated, defaults to the -- latest revision of the item with which the source revision is -- associated. --*/ revision_id in cr_revisions.revision_id%TYPE, revision_id_dest in cr_revisions.revision_id%TYPE default null ); end content_revision; / show errors create or replace package content_symlink as function new ( --/** Create a new symlink, linking two items -- @author Karl Goldstein -- @param name The name for the new symlink, defaults to the name of the -- target item -- @param label The label of the symlink, defaults to 'Symlinke to ' -- @param target_id The item which the symlink will point to -- @param parent_id The parent folder for the symlink. This must actually be a folder -- and not a generic content item. -- @param symlink_id The id of the new symlink. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created symlink -- @see {acs_object.new}, {content_item.new}, {content_symlink.resolve} --*/ name in cr_items.name%TYPE default null, label in cr_symlinks.label%TYPE default null, target_id in cr_items.item_id%TYPE, parent_id in cr_items.parent_id%TYPE, symlink_id in cr_symlinks.symlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_symlinks.symlink_id%TYPE; procedure del ( --/** Deletes the symlink -- @author Karl Goldstein -- @param symlink_id The id of the symlink to delete -- @see {content_symlink.new}, {acs_object.delete} --*/ symlink_id in cr_symlinks.symlink_id%TYPE ); procedure copy ( --/** Copies the symlink itself to another folder, without resolving the symlink -- @author Karl Goldstein -- @param symlink_id The id of the symlink to copy -- @param target_folder_id The id of the folder where the symlink is to be copied -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defualt null) -- @see {content_symlink.new}, {content_item.copy} --*/ symlink_id in cr_symlinks.symlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function is_symlink ( --/** Determines if the item is a symlink -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a symlink, 'f' otherwise -- @see {content_symlink.new}, {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return char; function resolve ( --/** Resolves the symlink and returns the target item id. -- @author Karl Goldstein -- @param item_id The item id to be resolved -- @return The target item of the symlink, or the original item id if -- the item is not in fact a symlink -- @see {content_symlink.new}, {content_symlink.is_symlink} --*/ item_id in cr_items.item_id%TYPE ) return cr_items.item_id%TYPE; function resolve_content_type ( --/** Gets the content type of the target item. -- @author Michael Pih -- @param item_id The item id to be resolved -- @return The content type of the symlink target, otherwise null. -- the item is not in fact a symlink -- @see {content_symlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return cr_items.content_type%TYPE; end content_symlink; / show errors create or replace package content_extlink as function new ( --/** Create a new extlink, an item pointing to an off-site resource -- @author Karl Goldstein -- @param name The name for the new extlink, defaults to the name of the -- target item -- @param url The URL of the item -- @param label The text label or title of the item -- @param description A brief description of the item -- @param parent_id The parent folder for the extlink. This must actually be a folder -- and not a generic content item. -- @param extlink_id The id of the new extlink. A new id will be allocated by default -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created extlink -- @see {acs_object.new}, {content_item.new}, {content_extlink.resolve} --*/ name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure del ( --/** Deletes the extlink -- @author Karl Goldstein -- @param extlink_id The id of the extlink to delete -- @see {content_extlink.new}, {acs_object.delete} --*/ extlink_id in cr_extlinks.extlink_id%TYPE ); function is_extlink ( --/** Determines if the item is a extlink -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a extlink, 'f' otherwise -- @see {content_extlink.new}, {content_extlink.resolve} --*/ item_id in cr_items.item_id%TYPE ) return char; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); end content_extlink; / show errors create or replace package content_folder as function new ( --/** Create a new folder -- @author Karl Goldstein -- @param label The label for the folder -- @param description A short description of the folder, 4000 characters maximum -- @param parent_id The parent of the folder -- @param folder_id The id of the new folder. A new id will be allocated by default -- @param context_id The context id. The parent id will be used as the default context -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @param package_id The package id. -- @return The id of the newly created folder -- @see {acs_object.new}, {content_item.new} --*/ name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_folders.folder_id%TYPE; procedure del ( --/** Delete a folder. An error is thrown if the folder is not empty -- @author Karl Goldstein -- @param folder_id The id of the folder to delete -- @see {acs_object.delete}, {content_item.delete} --*/ folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ); procedure edit_name ( --/** Change the name, label and/or description of the folder -- @author Karl Goldstein -- @param folder_id The id of the folder to modify -- @param name The new name for the folder. An error will be thrown if -- an item with this name already exists under this folder's -- parent. If this parameter is null, the old name will be preserved -- @param label The new label for the folder. The old label will be preserved if -- this parameter is null -- @param label The new description for the folder. The old description -- will be preserved if this parameter is null -- @see {content_folder.new} --*/ folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ); procedure move ( --/** Recursively move the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be moved. -- @author Karl Goldstein -- @param folder_id The id of the folder to move -- @param target_folder_id The destination folder -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ); procedure copy ( --/** Recursively copy the folder and all items in into a new location. -- An error is thrown if either of the parameters is not a folder. -- The root folder of the sitemap and the root folder of the -- templates cannot be copied -- @author Karl Goldstein -- @param folder_id The id of the folder to copy -- @param target_folder_id The destination folder -- @param creation_user The id of the creation user -- @param creation_ip The IP address of the creation user (defaults to null) -- @see {content_folder.new}, {content_folder.copy} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ); function is_folder ( --/** Determine if the item is a folder -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a folder, 'f' otherwise -- @see {content_folder.new}, {content_folder.is_sub_folder} --*/ item_id in cr_items.item_id%TYPE ) return char; function is_sub_folder ( --/** Determine if the item target_folder_id is a subfolder of -- the item folder_id -- @author Karl Goldstein -- @param folder_id The superfolder id -- @param target_folder_id The subfolder id -- @return 't' if the item target_folder_id is a subfolder of -- the item folder_id, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char; function is_empty ( --/** Determine if the folder is empty -- @author Karl Goldstein -- @param folder_id The folder id -- @return 't' if the folder contains no subfolders or items, 'f' otherwise -- @see {content_folder.is_folder} --*/ folder_id in cr_folders.folder_id%TYPE ) return varchar2; function is_root ( --/** Determine whether the folder is a root (has a parent_id of 0) -- @author Karl Goldstein -- @param folder_id The folder ID -- @return 't' if the folder is a root or 'f' otherwise --*/ folder_id in cr_folders.folder_id%TYPE ) return char; procedure register_content_type ( --/** Register a content type to the folder, if it is not already registered. -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be registered -- @see {content_folder.unregister_content_type}, -- {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); procedure unregister_content_type ( --/** Unregister a content type from the folder, if it has been registered. -- Only items of the registered type(s) may be added to the folder. -- If the folder already contains items of the type to be unregistered, the -- items remain in the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be unregistered -- @param include_subtypes If 't', all subtypes of content_type will be -- unregistered as well -- @see {content_folder.register_content_type}, {content_folder.is_registered} --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ); -- change this to is_type_registered function is_registered ( --/** Determines if a content type is registered to the folder -- Only items of the registered type(s) may be added to the folder. -- @author Karl Goldstein -- @param folder_id The folder id -- @param content_type The content type to be checked -- @param include_subtypes If 't', all subtypes of the content_type -- will be checked, returning 't' if all of them are registered. If 'f', -- only an exact match with content_type will be -- performed. -- @return 't' if the type is registered to this folder, 'f' otherwise -- @see {content_folder.register_content_type}, {content_folder.unregister_content_type}, --*/ folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2; function get_label ( --/** Returns the label for the folder. This function is the default name method -- for the folder object. -- @author Karl Goldstein -- @param folder_id The folder id -- @return The folder's label -- @see {acs_object_type.create_type}, the docs for the name_method parameter --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE; function get_index_page ( --/** Returns the item ID of the index page of the folder, null otherwise -- @author Michael Pih -- @param folder_id The folder id -- @return The item ID of the index page --*/ folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE; end content_folder; / show errors create or replace package content_template as c_root_folder_id constant integer := -200; function get_root_folder return cr_folders.folder_id%TYPE; function new ( --/** Creates a new content template which can be used to render content items. -- @author Karl Goldstein -- @param name The name for the template, must be a valid UNIX-like filename. -- If a template with this name already exists under the specified -- parent item, an error is thrown -- @param text The body of the .adp template itself, defaults to null -- @param parent_id The parent of this item, defaults to null -- @param is_live The should the revision be set live, defaults to 't'. Requires -- that text is not null or there will be no revision to begin with -- @param template_id The id of the new template. A new id will be allocated if this -- parameter is null -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created template -- @see {acs_object.new}, {content_item.new}, {content_item.register_template}, -- {content_type.register_template} --*/ name in cr_items.name%TYPE, text in varchar2 default null, parent_id in cr_items.parent_id%TYPE default null, is_live in char default 't', template_id in cr_templates.template_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_templates.template_id%TYPE; procedure del ( --/** Deletes the specified template, and unregisters the template from -- all content types and content items. -- Use with caution - this operation cannot be undone. -- @author Karl Goldstein -- @param template_id The id of the template to delete -- @see {acs_object.delete}, {content_item.unregister_template}, -- {content_type.unregister_template}, --*/ template_id in cr_templates.template_id%TYPE ); function is_template ( --/** Determine if an item is a template. -- @author Karl Goldstein -- @param item_id The item id -- @return 't' if the item is a template, 'f' otherwise -- @see {content_template.new} --*/ template_id in cr_templates.template_id%TYPE ) return varchar2; function get_path ( --/** Retrieves the full path to the template, as described in content_item.get_path -- @author Karl Goldstein -- @param template_id The id of the template for which the path is to -- be retrieved -- @param root_folder_id Starts path resolution at this folder -- @return The path to the template, starting with the specified root folder -- @see {content_item.get_path} --*/ template_id in cr_templates.template_id%TYPE, root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id ) return varchar2; end content_template; / show errors create or replace package content_keyword as function new ( --/** Creates a new keyword (also known as "subject category"). -- @author Karl Goldstein -- @param heading The heading for the new keyword -- @param description The description for the new keyword -- @param parent_id The parent of this keyword, defaults to null. -- @param keyword_id The id of the new keyword. A new id will be allocated if this -- parameter is null -- @param object_type The type for the new keyword, defaults to 'content_keyword'. -- This parameter may be used by subclasses of -- content_keyword to initialize the superclass. -- @param creation_date As in acs_object.new -- @param creation_ip As in acs_object.new -- @param creation_user As in acs_object.new -- @return The id of the newly created keyword -- @see {acs_object.new}, {content_item.new}, {content_keyword.item_assign}, -- {content_keyword.delete} --*/ heading in cr_keywords.heading%TYPE, description in cr_keywords.description%TYPE default null, parent_id in cr_keywords.parent_id%TYPE default null, keyword_id in cr_keywords.keyword_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_object_types.object_type%TYPE default 'content_keyword', package_id in acs_objects.package_id%TYPE default null ) return cr_keywords.keyword_id%TYPE; procedure del ( --/** Deletes the specified keyword, which must be a leaf. Unassigns the -- keyword from all content items. Use with caution - this -- operation cannot be undone. -- @author Karl Goldstein -- @param keyword_id The id of the keyword to be deleted -- @see {acs_object.delete}, {content_keyword.item_unassign} --*/ keyword_id in cr_keywords.keyword_id%TYPE ); function get_heading ( --/** Retrieves the heading of the content keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The heading for the specified keyword -- @see {content_keyword.set_heading}, {content_keyword.get_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; function get_description ( --/** Retrieves the description of the content keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The description for the specified keyword -- @see {content_keyword.get_heading}, {content_keyword.set_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; procedure set_heading ( --/** Sets a new heading for the keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @param heading The new heading -- @see {content_keyword.get_heading}, {content_keyword.set_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE, heading in cr_keywords.heading%TYPE ); procedure set_description ( --/** Sets a new description for the keyword -- @author Karl Goldstein -- @param keyword_id The keyword id -- @param description The new description -- @see {content_keyword.set_heading}, {content_keyword.get_description} --*/ keyword_id in cr_keywords.keyword_id%TYPE, description in cr_keywords.description%TYPE ); function is_leaf ( --/** Determines if the keyword has no sub-keywords associated with it -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return 't' if the keyword has no descendants, 'f' otherwise -- @see {content_keyword.new} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; procedure item_assign ( --/** Assigns this keyword to a content item, creating a relationship between them -- @author Karl Goldstein -- @param item_id The item to be assigned to -- @param keyword_id The keyword to be assigned -- @param context_id As in acs_rel.new, deprecated -- @param creation_ip As in acs_rel.new, deprecated -- @param creation_user As in acs_rel.new, deprecated -- @see {acs_rel.new}, {content_keyword.item_unassign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ); procedure item_unassign ( --/** Unassigns this keyword to a content item, removing a relationship between them -- @author Karl Goldstein -- @param item_id The item to be unassigned from -- @param keyword_id The keyword to be unassigned -- @see {acs_rel.delete}, {content_keyword.item_assign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE ); function is_assigned ( --/** Determines if the keyword is assigned to the item -- @author Karl Goldstein -- @param item_id The item id -- @param keyword_id The keyword id to be checked for assignment -- @param recurse Specifies if the keyword search is -- recursive. May be set to one of the following -- values:
    --
  • none: Not recursive. Look for an exact match.
  • --
  • up: Recursive from specific to general. A search for -- "attack dogs" will also match "dogs", "animals", "mammals", etc.
  • --
  • down: Recursive from general to specific. A search for -- "mammals" will also match "dogs", "attack dogs", "cats", "siamese cats", -- etc.
-- @return 't' if the keyword may be matched to an item, 'f' otherwise -- @see {content_keyword.item_assign} --*/ item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, recurse in varchar2 default 'none' ) return varchar2; function get_path ( --/** Retreives a path to the keyword/subject category, with the most general -- category at the root of the path -- @author Karl Goldstein -- @param keyword_id The keyword id -- @return The path to the keyword, or null if no such keyword exists -- @see {content_keyword.new} --*/ keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2; end content_keyword; / show errors create or replace package content_permission is procedure inherit_permissions ( --/** Make the child object inherit all of the permissions of the parent -- object. Typically, this function is called whenever a new object -- is created under a given parent -- @author Karl Goldstein -- @param parent_object_id The parent object id -- @param child_object_id The child object id -- @see {content_permission.grant}, {acs_permission.grant_permission} --*/ parent_object_id in acs_objects.object_id%TYPE, child_object_id in acs_objects.object_id%TYPE, child_creator_id in parties.party_id%TYPE default null ); function has_grant_authority ( --/** Determine if the user may grant a certain permission to another -- user. The permission may only be granted if the user has -- the permission himself and posesses the cm_perm access, or if the -- user posesses the cm_perm_admin access. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to grant the permissions -- @param privilege The privilege to be granted -- @return 't' if the donation is possible, 'f' otherwise -- @see {content_permission.grant_permission}, {content_permission.is_has_revoke_authority}, -- {acs_permission.grant_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) return varchar2; procedure grant_permission_h ( --/** This is a helper function for content_permission.grant_permission and -- should not be called individually.

-- Grants a permission and revokes all descendants of the permission, since -- they are no longer relevant. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param grantee_id The person who should gain the parent privilege -- @param privilege The parent privilege to be granted -- @see {content_permission.grant_permission} --*/ object_id in acs_objects.object_id%TYPE, grantee_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ); procedure grant_permission ( --/** Grant the specified privilege to another user. If the donation is -- not possible, the procedure does nothing. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to grant the permissions -- @param privilege The privilege to be granted -- @param recepient_id The person who will gain the privilege -- @param is_recursive If 't', applies the donation recursively to -- all child objects of the object (equivalent to UNIX's chmod -r). -- If 'f', only affects the objects itself. -- @see {content_permission.has_grant_authority}, {content_permission.revoke_permission}, -- {acs_permission.grant_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, recepient_id in parties.party_id%TYPE, is_recursive in varchar2 default 'f', object_type in acs_objects.object_type%TYPE default 'content_item' ); function has_revoke_authority ( --/** Determine if the user may take a certain permission away from another -- user. The permission may only be revoked if the user has -- the permission himself and posesses the cm_perm access, while the -- other user does not, or if the user posesses the cm_perm_admin access. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to revoke the permissions -- @param privilege The privilege to be revoked -- @param revokee_id The user from whom the privilege is to be taken away -- @return 't' if it is possible to revoke the privilege, 'f' otherwise -- @see {content_permission.has_grant_authority}, {content_permission.revoke_permission}, -- {acs_permission.revoke_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, revokee_id in parties.party_id%TYPE ) return varchar2; procedure revoke_permission_h ( --/** This is a helper function for content_permission.revoke_permission and -- should not be called individually.

-- Revokes a permission but grants all child permissions to the holder, to -- ensure that the permission is not permanently lost -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param revokee_id The person who should lose the parent permission -- @param privilege The parent privilege to be revoked -- @see {content_permission.revoke_permission} --*/ object_id in acs_objects.object_id%TYPE, revokee_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ); procedure revoke_permission ( --/** Take the specified privilege away from another user. If the operation is -- not possible, the procedure does nothing. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be changed -- @param holder_id The person who is attempting to revoke the permissions -- @param privilege The privilege to be revoked -- @param recepient_id The person who will lose the privilege -- @param is_recursive If 't', applies the operation recursively to -- all child objects of the object (equivalent to UNIX's chmod -r). -- If 'f', only affects the objects itself. -- @see {content_permission.grant_permission}, {content_permission.has_revoke_authority}, -- {acs_permission.revoke_permission} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE, revokee_id in parties.party_id%TYPE, is_recursive in varchar2 default 'f', object_type in acs_objects.object_type%TYPE default 'content_item' ); function permission_p ( --/** Determine if the user has the specified permission on the specified -- object. Does NOT check objects recursively: that is, if the user has -- the permission on the parent object, he does not automatically gain -- the permission on all the child objects. -- @author Karl Goldstein -- @param object_id The object whose permissions are to be checked -- @param holder_id The person whose permissions are to be examined -- @param privilege The privilege to be checked -- @return 't' if the user has the specified permission on the object, -- 'f' otherwise -- @see {content_permission.grant_permission}, {content_permission.revoke_permission}, -- {acs_permission.permission_p} --*/ object_id in acs_objects.object_id%TYPE, holder_id in parties.party_id%TYPE, privilege in acs_privileges.privilege%TYPE ) return varchar2; function cm_admin_exists -- /** Determine if there exists a user who has administrative -- privileges on the entire content repository. -- @author Stanislav Freidin -- @return 't' if an administrator exists, 'f' otherwise -- @see {content_permission.grant_permission} return varchar2; end content_permission; / show errors @@content-type @@content-item @@content-revision @@content-symlink @@content-extlink @@content-folder @@content-template @@content-keyword openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-image-drop.sql0000644000175000017500000000164407360476634027511 0ustar frankiefrankie-- drop the content-image type from the data model -- Copyright (C) 20000 ArsDigita Corporation -- $Id: content-image-drop.sql,v 1.2 2001/10/09 04:31:24 danw Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- unregister mime types from the image type begin content_type.unregister_mime_type( content_type => 'image', mime_type => 'image/jpeg' ); content_type.unregister_mime_type( content_type => 'image', mime_type => 'image/gif' ); end; / show errors -- remove image mime types delete from cr_mime_types where mime_type like 'image%'; -- this should remove the attributes and table related to the -- the image type begin content_type.drop_type ( content_type => 'image', drop_table_p => 't'); end; / show errors drop package image; openacs-5.7.0/packages/acs-content-repository/sql/oracle/doc-package.sql0000644000175000017500000000541307341732250026135 0ustar frankiefrankie---------------------------------------- -- Return function headers for packages --------------------------------------- create or replace package doc is function get_proc_header ( proc_name in varchar2, package_name in varchar2 ) return varchar2; function get_package_header ( package_name in varchar2 ) return varchar2; end doc; / show errors create or replace package body doc is function get_proc_header ( proc_name in varchar2, package_name in varchar2 ) return varchar2 is v_line integer; v_result varchar2(4000); v_text varchar2(4000); v_started varchar2(1); v_newline varchar2(10) := ' '; cursor v_package_cur is select line, text from user_source where lower(name) = lower(package_name) and type = 'PACKAGE' order by line; begin v_result := ''; v_started := 'f'; open v_package_cur; loop fetch v_package_cur into v_line, v_text; exit when v_package_cur%NOTFOUND; -- Look for the function header if v_started = 'f' then if lower(v_text) like '%function%' || lower(proc_name) || '%' then v_started := 't'; elsif lower(v_text) like '%procedure%' || lower(proc_name) || '%' then v_started := 't'; end if; end if; -- Process the header if v_started = 't' then v_result := v_result || v_text; if v_text like '%;%' then close v_package_cur; return v_result; end if; end if; end loop; close v_package_cur; -- Return unfinished result return v_result; end get_proc_header; function get_package_header ( package_name in varchar2 ) return varchar2 is v_line integer; v_result varchar2(4000); v_text varchar2(4000); v_started varchar2(1); v_newline varchar2(10) := ' '; cursor v_package_cur is select line, text from user_source where lower(name) = lower(package_name) and type = 'PACKAGE' order by line; begin v_result := ''; v_started := 'f'; open v_package_cur; loop fetch v_package_cur into v_line, v_text; exit when v_package_cur%NOTFOUND; -- Look for the function header if v_started = 'f' then if v_text like '--%' then v_started := 't'; end if; end if; -- Process the header if v_started = 't' then if v_text not like '--%' then close v_package_cur; return v_result; end if; v_result := v_result || v_text; end if; end loop; close v_package_cur; -- Return unfinished result return v_result; end get_package_header; end doc; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-folder.sql0000644000175000017500000004302311141725376026725 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-folder.sql,v 1.22 2009/02/03 02:25:02 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_folder as function new ( name in cr_items.name%TYPE, label in cr_folders.label%TYPE, description in cr_folders.description%TYPE default null, parent_id in cr_items.parent_id%TYPE default null, context_id in acs_objects.context_id%TYPE default null, folder_id in cr_folders.folder_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, security_inherit_p in acs_objects.security_inherit_p%TYPE default 't', package_id in acs_objects.package_id%TYPE default null ) return cr_folders.folder_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if content_folder.new.context_id is null then v_context_id := content_folder.new.parent_id; else v_context_id := content_folder.new.context_id; end if; -- parent_id = security context root means that this is a mount point if parent_id ^= -4 and content_folder.is_folder(parent_id) = 'f' and content_folder.is_registered(parent_id,'content_folder') = 'f' then raise_application_error(-20000, 'This folder does not allow subfolders to be created'); else v_folder_id := content_item.new( item_id => folder_id, name => name, item_subtype => 'content_folder', content_type => 'content_folder', context_id => v_context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, parent_id => parent_id, security_inherit_p => security_inherit_p, package_id => package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, label, description, package_id ); -- set the correct object title update acs_objects set title = new.label where object_id = v_folder_id; -- inherit the attributes of the parent folder if content_folder.new.parent_id is not null then insert into cr_folder_type_map ( folder_id, content_type ) select v_folder_id, content_type from cr_folder_type_map where folder_id = content_folder.new.parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = 't' where folder_id = content_folder.new.parent_id; return v_folder_id; end if; end new; procedure del ( folder_id in cr_folders.folder_id%TYPE, cascade_p in char default 'f' ) is v_count integer; v_parent_id cr_items.parent_id%TYPE; v_child_item_id cr_items.item_id%TYPE; cursor c_folder_children_cur is select item_id from cr_items connect by prior item_id=parent_id start with parent_id = del.folder_id; begin -- check if the folder contains any items select count(*) into v_count from cr_items where parent_id = folder_id; if v_count > 0 and content_folder.del.cascade_p='f' then raise_application_error(-20000, 'Folder ID ' || folder_id || ' (' || content_item.get_path(folder_id) || ') cannot be deleted because it is not empty.'); else open c_folder_children_cur; loop fetch c_folder_children_cur into v_child_item_id; exit when c_folder_children_cur%NOTFOUND; if is_folder(v_child_item_id) = 't' then content_folder.del(v_child_item_id,'t'); else content_item.del(v_child_item_id); end if; end loop; close c_folder_children_cur; end if; content_folder.unregister_content_type( folder_id => content_folder.del.folder_id, content_type => 'content_revision', include_subtypes => 't' ); delete from cr_folder_type_map where folder_id = content_folder.del.folder_id; select parent_id into v_parent_id from cr_items where item_id = content_folder.del.folder_id; content_item.del(folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = 'f' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = 'content_folder'); end del; -- renames a folder, making sure the new name is not already in use procedure edit_name ( folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null, label in cr_folders.label%TYPE default null, description in cr_folders.description%TYPE default null ) is v_name_already_exists_p integer := 0; begin if name is not null then content_item.edit_name(folder_id, name); end if; if label is not null then update acs_objects set title = edit_name.label where object_id = edit_name.folder_id; end if; if label is not null and description is not null then update cr_folders set cr_folders.label = content_folder.edit_name.label, cr_folders.description = content_folder.edit_name.description where cr_folders.folder_id = content_folder.edit_name.folder_id; elsif label is not null and description is null then update cr_folders set cr_folders.label = content_folder.edit_name.label where cr_folders.folder_id = content_folder.edit_name.folder_id; end if; end edit_name; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder procedure move ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, name in cr_items.name%TYPE default null ) is v_source_folder_id integer; v_valid_folders_p integer := 0; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move.target_folder_id or folder_id = move.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.move - Not valid folder(s)'); end if; if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.move - Cannot move root folder'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.move - Cannot move a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.move - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.move - Destination folder does not allow subfolders'); end if; select parent_id into v_source_folder_id from cr_items where item_id = move.folder_id; -- update the parent_id for the folder update cr_items set parent_id = move.target_folder_id, name=nvl(move.name, cr_items.name) where item_id = move.folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = 'f' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = 'content_folder'); -- update the destination update cr_folders set has_child_folders = 't' where folder_id = target_folder_id; end move; -- * make sure that subfolders are allowed in this folder -- * creates new folder in the target folder with the same attributes -- as the old one -- * copies all contents of folder to the new one procedure copy ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_valid_folders_p integer := 0; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; -- cursor: items in the folder cursor c_folder_contents_cur is select item_id from cr_items where parent_id = copy.folder_id; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then raise_application_error( -20000, 'content_folder.copy - Cannot copy root folder'); end if; select count(*) into v_valid_folders_p from cr_folders where folder_id = copy.target_folder_id or folder_id = copy.folder_id; if v_valid_folders_p ^= 2 then raise_application_error(-20000, 'content_folder.copy - Not valid folder(s)'); end if; if target_folder_id = folder_id then raise_application_error(-20000, 'content_folder.copy - Cannot copy a folder to itself'); end if; if is_sub_folder(folder_id, target_folder_id) = 't' then raise_application_error(-20000, 'content_folder.copy - Destination folder is subfolder'); end if; if is_registered(target_folder_id,'content_folder') ^= 't' then raise_application_error(-20000, 'content_folder.copy - Destination folder does not allow subfolders'); end if; -- get the source folder info select name, label, description, parent_id into v_name, v_label, v_description, v_current_folder_id from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy.folder_id; if v_current_folder_id = copy.target_folder_id and (v_name = copy.name or copy.name is null) then raise_application_error(-20000, 'content_folder.copy - Destination folder is parent folder'); end if; -- create the new folder v_new_folder_id := content_folder.new( parent_id => copy.target_folder_id, name => nvl(copy.name,v_name), label => v_label, description => v_description, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map ( folder_id, content_type ) select v_new_folder_id, content_type from cr_folder_type_map map where folder_id = copy.folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in c_folder_contents_cur loop content_item.copy( item_id => v_folder_contents_val.item_id, target_folder_id => v_new_folder_id, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end loop; end copy; -- returns 1 if the item_id passed in is a folder function is_folder ( item_id in cr_items.item_id%TYPE ) return char is v_folder_p varchar2(1) := 'f'; begin select 't' into v_folder_p from cr_folders where folder_id = item_id; return v_folder_p; exception when NO_DATA_FOUND then return 'f'; end is_folder; -- target_folder_id is the possible sub folder function is_sub_folder ( folder_id in cr_folders.folder_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE ) return char is cursor c_tree_cur is select parent_id from cr_items connect by prior parent_id = item_id start with item_id = target_folder_id; v_parent_id integer := -4; v_sub_folder_p char := 'f'; begin if folder_id = content_item.get_root_folder or folder_id = content_template.get_root_folder then v_sub_folder_p := 't'; end if; -- Get the parents open c_tree_cur; while v_parent_id <> folder_id loop fetch c_tree_cur into v_parent_id; if v_parent_id = folder_id then v_sub_folder_p := 't'; end if; exit when c_tree_cur%NOTFOUND; end loop; close c_tree_cur; return v_sub_folder_p; end is_sub_folder; function is_empty ( folder_id in cr_folders.folder_id%TYPE ) return varchar2 is v_return varchar2(1); begin select decode( count(*), 0, 't', 'f' ) into v_return from cr_items where parent_id = is_empty.folder_id; return v_return; end is_empty; procedure register_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is v_is_registered varchar2(100); begin if register_content_type.include_subtypes = 'f' then v_is_registered := is_registered( folder_id => register_content_type.folder_id, content_type => register_content_type.content_type, include_subtypes => 'f' ); if v_is_registered = 'f' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type.folder_id, register_content_type.content_type ); end if; else insert into cr_folder_type_map ( folder_id, content_type ) select register_content_type.folder_id, object_type from acs_object_types where object_type ^= 'acs_object' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type.folder_id and content_type = acs_object_types.object_type) connect by prior object_type = supertype start with object_type = register_content_type.content_type; end if; end register_content_type; procedure unregister_content_type ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) is begin if unregister_content_type.include_subtypes = 'f' then delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type = unregister_content_type.content_type; else delete from cr_folder_type_map where folder_id = unregister_content_type.folder_id and content_type in (select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = unregister_content_type.content_type); end if; end unregister_content_type; function is_registered ( folder_id in cr_folders.folder_id%TYPE, content_type in cr_folder_type_map.content_type%TYPE, include_subtypes in varchar2 default 'f' ) return varchar2 is v_is_registered integer; cursor c_subtype_cur is select object_type from acs_object_types where object_type ^= 'acs_object' connect by prior object_type = supertype start with object_type = is_registered.content_type; begin if is_registered.include_subtypes = 'f' then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered.folder_id and content_type = is_registered.content_type; else v_is_registered := 1; for v_subtype_val in c_subtype_cur loop if is_registered(is_registered.folder_id, v_subtype_val.object_type, 'f') = 'f' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return 'f'; else return 't'; end if; end is_registered; function get_label ( folder_id in cr_folders.folder_id%TYPE ) return cr_folders.label%TYPE is v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label.folder_id; return v_label; end get_label; function get_index_page ( folder_id in cr_folders.folder_id%TYPE ) return cr_items.item_id%TYPE is v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink.is_symlink( get_index_page.folder_id ) = 't' then v_folder_id := content_symlink.resolve( get_index_page.folder_id ); else v_folder_id := get_index_page.folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = 'index' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_folder') = 'f' and content_item.is_subclass( content_item.get_content_type( content_symlink.resolve(item_id) ), 'content_template') = 'f'; return v_index_page_id; exception when no_data_found then return null; end get_index_page; function is_root ( folder_id in cr_folders.folder_id%TYPE ) return char is v_is_root char(1); begin select decode(parent_id, 0, 't', 'f') into v_is_root from cr_items where item_id = is_root.folder_id; return v_is_root; end is_root; end content_folder; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-drop.sql0000644000175000017500000001000111550452213026373 0ustar frankiefrankie-- Uninstall content repository tables of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-drop.sql,v 1.4 2011/04/11 01:08:27 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html set serveroutput on -- unregistering types, deleting the default folders declare v_id integer; begin -- root folder for templates v_id := content_template.get_root_folder; content_folder.unregister_content_type( folder_id => v_id, content_type => 'content_template', include_subtypes => 't' ); content_folder.unregister_content_type( folder_id => v_id, content_type => 'content_symlink', include_subtypes => 't' ); content_folder.unregister_content_type( folder_id => v_id, content_type => 'content_folder', include_subtypes => 't' ); content_folder.del(v_id); -- the root folder for content items v_id := content_item.get_root_folder; content_folder.unregister_content_type( folder_id => v_id, content_type => 'content_symlink', include_subtypes => 't' ); content_folder.unregister_content_type( folder_id => v_id, content_type => 'content_folder', include_subtypes => 't' ); content_folder.unregister_content_type ( folder_id => v_id, content_type => 'content_revision', include_subtypes => 't' ); content_folder.del (v_id); end; / show errors begin content_type.unregister_mime_type( content_type => 'content_revision', mime_type => 'text/html'); content_type.unregister_mime_type( content_type => 'content_revision', mime_type => 'text/plain'); end; / show errors -- drop all extended attribute tables --declare -- cursor type_cur is -- select object_type, table_name -- from acs_object_types -- where table_name <> 'cr_revisions' -- connect by prior object_type = supertype -- start with object_type = 'content_revision' -- order by level desc; --begin -- for type_rec in type_cur loop -- dbms_output.put_line('Dropping ' || type_rec.table_name); -- execute immediate 'drop table ' || type_rec.table_name; -- end loop; --end; --/ --show errors -- dropping pl/sql definitions prompt ** dropping content-image @@ content-image-drop -- doc-package-drop -- content-search-drop begin ctx_ddl.drop_section_group('auto'); end; / show errors begin ctx_ddl.drop_preference('CONTENT_FILTER_PREF'); end; / show errors prompt ** dropping object types @@ types-drop -- packages-drop -- content-package-drop prompt ** dropping lots of tables -- content-xml-drop drop table cr_xml_docs; drop sequence cr_xml_doc_seq; -- content-util drop -- document submission with conversion to html drop index cr_doc_filter_index; drop table cr_doc_filter; --text submission drop table cr_text; -- content keywords drop table cr_item_keyword_map ; drop table cr_keywords ; -- content extlinks drop table cr_extlinks ; -- content symlinks drop table cr_symlinks ; -- content templates drop table cr_item_template_map ; drop table cr_type_template_map ; drop table cr_template_use_contexts ; drop table cr_templates ; -- content folders drop table cr_folder_type_map ; drop table cr_folders cascade constraints; prompt ** dropping more tables -- content publishing drop table cr_scheduled_release_job; drop table cr_scheduled_release_log; drop table cr_release_periods; drop table cr_item_publish_audit; -- content revisions drop table cr_files_to_delete; drop table cr_content_text; drop table cr_revision_attributes; drop table cr_revisions cascade constraints; -- content_items drop table cr_item_rels ; drop table cr_child_rels ; drop table cr_items cascade constraints; -- content types drop table cr_type_relations ; drop table cr_type_children ; -- locales drop table cr_locales ; -- mime types drop table cr_content_mime_type_map ; drop table cr_mime_types ; openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-extlink.sql0000644000175000017500000001103610035526153027120 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-extlink.sql,v 1.10 2004/04/09 14:00:11 andrewg Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_extlink as function new ( name in cr_items.name%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in cr_items.parent_id%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_label cr_extlinks.label%TYPE; v_name cr_items.name%TYPE; begin if label is null then v_label := url; else v_label := label; end if; if name is null then select acs_object_id_seq.nextval into v_extlink_id from dual; v_name := 'link' || v_extlink_id; else v_name := name; end if; if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_extlink_id := content_item.new( item_id => content_extlink.new.extlink_id, name => v_name, package_id => v_package_id, content_type => 'content_extlink', creation_date => content_extlink.new.creation_date, creation_user => content_extlink.new.creation_user, creation_ip => content_extlink.new.creation_ip, parent_id => content_extlink.new.parent_id ); insert into cr_extlinks (extlink_id, url, label, description) values (v_extlink_id, content_extlink.new.url, v_label, content_extlink.new.description); update acs_objects set title = v_label where object_id = v_extlink_id; return v_extlink_id; end new; procedure del ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin delete from cr_extlinks where extlink_id = content_extlink.del.extlink_id; content_item.del(content_extlink.del.extlink_id); end del; function is_extlink ( item_id in cr_items.item_id%TYPE ) return char is v_extlink_p integer := 0; begin select count(1) into v_extlink_p from cr_extlinks where extlink_id = is_extlink.item_id; if v_extlink_p = 1 then return 't'; else return 'f'; end if; end is_extlink; procedure copy ( extlink_id in cr_extlinks.extlink_id%TYPE, target_folder_id in cr_folders.folder_id%TYPE, creation_user in acs_objects.creation_user%TYPE, creation_ip in acs_objects.creation_ip%TYPE default null, name in cr_items.name%TYPE default null ) is v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_label cr_extlinks.label%TYPE; v_description cr_extlinks.description%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder.is_folder(copy.target_folder_id) = 't' then select parent_id into v_current_folder_id from cr_items where item_id = copy.extlink_id; select i.name, e.url, e.label, e.description into v_name, v_url, v_label, v_description from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy.extlink_id; -- can't copy to the same folder if copy.target_folder_id ^= v_current_folder_id or (v_name != copy.name and copy.name is not null) then if copy.name is not null then v_name := copy.name; end if; if content_folder.is_registered(copy.target_folder_id, 'content_extlink') = 't' then v_extlink_id := content_extlink.new( parent_id => copy.target_folder_id, name => v_name, label => v_label, description => v_description, url => v_url, creation_user => copy.creation_user, creation_ip => copy.creation_ip ); end if; end if; end if; end copy; end content_extlink; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-search.sql0000644000175000017500000000555007363705753026732 0ustar frankiefrankie------------------------------------------------------------ -- Set up an index with INSO filtering on the content column ------------------------------------------------------------ set serveroutput on declare v_exists integer; begin -- Check whether the preference already exists select decode(count(*),0,0,1) into v_exists from ctx_user_preferences where pre_name = 'CONTENT_FILTER_PREF'; if v_exists = 0 then dbms_output.put_line('Creating content filter preference...'); ctx_ddl.create_preference ( preference_name => 'CONTENT_FILTER_PREF', object_name => 'INSO_FILTER' ); end if; end; / create index cr_rev_content_index on cr_revisions ( content ) indextype is ctxsys.context parameters ('FILTER content_filter_pref' ); -- DRB: Use the "online" version if you have Oracle Enterprise Edition -- alter index cr_rev_content_index rebuild online parameters ('sync'); alter index cr_rev_content_index rebuild parameters ('sync'); ------------------------------------------------------------ -- Set up an XML index for searching attributes ------------------------------------------------------------ -- To find the word company in the title only: -- select revision_id,score(1) -- from cr_revision_attributes -- where contains(attributes, 'company WITHIN title', 1) > 0; -- use a direct datastore rather than setting up a user datastore -- this avoids having to generate an XML document for every -- revision every time the index is rebuilt. It also avoids the -- cumbersome manual process of setting up a user datastore. create or replace package content_search is procedure update_attribute_index; end content_search; / show errors create or replace package body content_search is procedure update_attribute_index is begin for c1 in (select revision_id from cr_revisions r where not exists ( select 1 from cr_revision_attributes a where a.revision_id = r.revision_id)) loop content_revision.index_attributes(c1.revision_id); commit; end loop; end update_attribute_index; end; / show errors declare v_exists integer; begin -- Check whether the section group already exists select decode(count(*),0,0,1) into v_exists from ctx_user_section_groups where sgp_name = 'AUTO'; if v_exists = 0 then dbms_output.put_line('Creating auto section group for attribute index...'); ctx_ddl.create_section_group('auto', 'AUTO_SECTION_GROUP'); end if; end; / create index cr_rev_attribute_index on cr_revision_attributes ( attributes ) indextype is ctxsys.context parameters ('filter ctxsys.null_filter section group auto' ); begin content_search.update_attribute_index; end; / show errors -- DRB: Use the "online" version if you have Oracle Enterprise Edition -- alter index cr_rev_attribute_index rebuild online parameters ('sync'); alter index cr_rev_attribute_index rebuild parameters ('sync'); openacs-5.7.0/packages/acs-content-repository/sql/oracle/content-keyword.sql0000644000175000017500000001721110440426442027127 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Stanislav Freidin (sfreidin@arsdigita.com) -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace package body content_keyword as function get_heading ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_heading varchar2(4000); begin select heading into v_heading from cr_keywords where keyword_id = content_keyword.get_heading.keyword_id; return v_heading; end get_heading; function get_description ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_description varchar2(4000); begin select description into v_description from cr_keywords where keyword_id = content_keyword.get_description.keyword_id; return v_description; end get_description; procedure set_heading ( keyword_id in cr_keywords.keyword_id%TYPE, heading in cr_keywords.heading%TYPE ) is begin update cr_keywords set heading = set_heading.heading where keyword_id = set_heading.keyword_id; update acs_objects set title = set_heading.heading where object_id = set_heading.keyword_id; end set_heading; procedure set_description ( keyword_id in cr_keywords.keyword_id%TYPE, description in cr_keywords.description%TYPE ) is begin update cr_keywords set description = set_description.description where keyword_id = set_description.keyword_id; end set_description; function is_leaf ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_leaf varchar2(1); cursor c_leaf_cur is select 'f' from cr_keywords k where k.parent_id = is_leaf.keyword_id; begin open c_leaf_cur; fetch c_leaf_cur into v_leaf; if c_leaf_cur%NOTFOUND then v_leaf := 't'; end if; close c_leaf_cur; return v_leaf; end is_leaf; function new ( heading in cr_keywords.heading%TYPE, description in cr_keywords.description%TYPE default null, parent_id in cr_keywords.parent_id%TYPE default null, keyword_id in cr_keywords.keyword_id%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_object_types.object_type%TYPE default 'content_keyword', package_id in acs_objects.package_id%TYPE default null ) return cr_keywords.keyword_id%TYPE is v_id integer; v_package_id acs_objects.package_id%TYPE; begin if package_id is null then v_package_id := acs_object.package_id(new.parent_id); else v_package_id := package_id; end if; v_id := acs_object.new (object_id => keyword_id, context_id => parent_id, object_type => object_type, title => heading, package_id => v_package_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip); insert into cr_keywords (heading, description, keyword_id, parent_id) values (heading, description, v_id, parent_id); return v_id; end new; procedure del ( keyword_id in cr_keywords.keyword_id%TYPE ) is v_item_id integer; cursor c_rel_cur is select item_id from cr_item_keyword_map where keyword_id = content_keyword.del.keyword_id; begin open c_rel_cur; loop fetch c_rel_cur into v_item_id; exit when c_rel_cur%NOTFOUND; item_unassign(v_item_id, content_keyword.del.keyword_id); end loop; close c_rel_cur; acs_object.del(keyword_id); end del; procedure item_assign ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) is v_dummy integer; begin -- Do nothing if the keyword is assigned already select decode(count(*),0,0,1) into v_dummy from dual where exists (select 1 from cr_item_keyword_map where item_id=item_assign.item_id and keyword_id=item_assign.keyword_id); if v_dummy > 0 then -- previous assignment exists return; end if; insert into cr_item_keyword_map ( item_id, keyword_id ) values ( item_id, keyword_id ); end item_assign; procedure item_unassign ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE ) is begin delete from cr_item_keyword_map where item_id = item_unassign.item_id and keyword_id = item_unassign.keyword_id; end item_unassign; function is_assigned ( item_id in cr_items.item_id%TYPE, keyword_id in cr_keywords.keyword_id%TYPE, recurse in varchar2 default 'none' ) return varchar2 is v_ret varchar2(1); begin -- Look for an exact match if recurse = 'none' then declare begin select 't' into v_ret from cr_item_keyword_map where item_id = is_assigned.item_id and keyword_id = is_assigned.keyword_id; return 't'; exception when no_data_found then return 'f'; end; end if; -- Look from specific to general if recurse = 'up' then begin select 't' into v_ret from dual where exists (select 1 from (select keyword_id from cr_keywords connect by parent_id = prior keyword_id start with keyword_id = is_assigned.keyword_id ) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned.item_id); return 't'; exception when no_data_found then return 'f'; end; end if; if recurse = 'down' then begin select 't' into v_ret from dual where exists ( select 1 from (select keyword_id from cr_keywords connect by prior parent_id = keyword_id start with keyword_id = is_assigned.keyword_id ) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned.item_id); return 't'; exception when no_data_found then return 'f'; end; end if; -- Tried none, up and down - must be an invalid parameter raise_application_error (-20000, 'The recurse parameter to ' || 'content_keyword.is_assigned should be ''none'', ''up'' or ''down''.'); end is_assigned; function get_path ( keyword_id in cr_keywords.keyword_id%TYPE ) return varchar2 is v_path varchar2(4000) := ''; v_is_found varchar2(1) := 'f'; cursor c_keyword_cur is select heading from ( select heading, level as tree_level from cr_keywords connect by prior parent_id = keyword_id start with keyword_id = get_path.keyword_id ) order by tree_level desc; v_heading cr_keywords.heading%TYPE; begin open c_keyword_cur; loop fetch c_keyword_cur into v_heading; exit when c_keyword_cur%NOTFOUND; v_is_found := 't'; v_path := v_path || '/' || v_heading; end loop; close c_keyword_cur; if v_is_found = 'f' then return null; else return v_path; end if; end get_path; end content_keyword; / show errors -- Ensure that the context_id in acs_objects is always set to the -- parent_id in cr_keywords create or replace trigger cr_keywords_update_tr after update of parent_id on cr_keywords for each row begin update acs_objects set context_id = :new.parent_id where object_id = :new.keyword_id; end cr_keywords_update_tr; / show errors openacs-5.7.0/packages/acs-content-repository/sql/oracle/types-drop.sql0000644000175000017500000000645407572171014026114 0ustar frankiefrankie-- Drop script for clearing content-repositry object type declarations -- Copyright (C) 20000 ArsDigita Corporation -- $Id: types-drop.sql,v 1.2 2002/11/30 17:14:52 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- just working backwards from types declared in types-create.sql -- removing the standard relationship types begin acs_attribute.drop_attribute ( object_type => 'cr_item_rel', attribute_name => 'order_n'); acs_attribute.drop_attribute ( object_type => 'cr_item_rel', attribute_name => 'relation_tag'); acs_attribute.drop_attribute ( object_type => 'cr_item_rl', attribute_name => 'related_object_id'); acs_attribute.drop_attribute ( object_type => 'cr_item_rl', attribute_name => 'item_id'); acs_object_type.drop_type ( object_type => 'cr_item_rel'); -- cr_item_child_rel type acs_attribute.drop_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'order_n'); acs_attribute.drop_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'relation_tag'); acs_attribute.drop_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'child_id'); acs_attribute.drop_attribute ( object_type => 'cr_item_child_rel', attribute_name => 'parent_id'); acs_object_type.drop_type ( object_type => 'cr_item_child_rel'); end; / show errors -- drop content revisions, begin content_type.drop_type('content_revision'); end; / show errors --dropping content templates begin acs_object_type.drop_type( object_type => 'content_template'); end; / show errors -- extlinks begin acs_attribute.drop_attribute ( object_type => 'content_extlink', attribute_name => 'description'); acs_attribute.drop_attribute ( object_type => 'content_extlink', attribute_name => 'label'); acs_attribute.drop_attribute ( object_type => 'content_extlink', attribute_name => 'url'); acs_object_type.drop_type( object_type => 'content_extlink'); end; / show errors -- symlinks begin acs_attribute.drop_attribute ( object_type => 'content_symlink', attribute_name => 'target_id'); acs_object_type.drop_type ( object_type => 'content_symlink'); end; / show errors --content keywords begin acs_attribute.drop_attribute ( object_type => 'content_keyword', attribute_name => 'description'); acs_attribute.drop_attribute ( object_type => 'content_keyword', attribute_name => 'heading'); acs_object_type.drop_type ( object_type => 'content_keyword'); end; / show errors begin acs_attribute.drop_attribute ( object_type => 'content_folder', attribute_name => 'description'); acs_attribute.drop_attribute ( object_type => 'content_folder', attribute_name => 'label'); acs_object_type.drop_type ( object_type => 'content_folder'); end; / show errors begin acs_attribute.drop_attribute ( object_type => 'content_item', attribute_name => 'live_revision'); acs_attribute.drop_attribute ( object_type => 'content_item', attribute_name => 'locale'); acs_attribute.drop_attribute ( object_type => 'content_item', attribute_name => 'name'); acs_object_type.drop_type ( object_type => 'content_item'); end; / show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/0000755000175000017500000000000011575225420024211 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-item.sql0000644000175000017500000026137611023613621027347 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-item.sql,v 1.69 2008/06/11 00:08:49 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create or replace view content_item_globals as select -100 as c_root_folder_id; select define_function_args('content_item__get_root_folder','item_id'); create or replace function content_item__get_root_folder (integer) returns integer as ' declare get_root_folder__item_id alias for $1; -- default null v_folder_id cr_folders.folder_id%TYPE; begin if get_root_folder__item_id is NULL or get_root_folder__item_id in (-4,-100,-200) then select c_root_folder_id from content_item_globals into v_folder_id; else select i2.item_id into v_folder_id from cr_items i1, cr_items i2 where i2.parent_id = -4 and i1.item_id = get_root_folder__item_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey); if NOT FOUND then raise EXCEPTION '' -20000: Could not find a root folder for item ID %. Either the item does not exist or its parent value is corrupted.'', get_root_folder__item_id; end if; end if; return v_folder_id; end;' language 'plpgsql' stable; -- new 19 param version of content_item__new (now its 20 with package_id) select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;null,package_id'); create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__data alias for $16; -- default null new__relation_tag alias for $17; -- default null new__is_live alias for $18; -- default ''f'' new__storage_type alias for $19; -- default null new__package_id alias for $20; -- default null v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__data, new__relation_tag, new__is_live, new__storage_type, null); return v_item_id; end;' language 'plpgsql'; -- create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') new__package_id alias for $17; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', coalesce(new__title,new__name), new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if new__title is null then v_title := new__name; else v_title := new__title; end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__storage_type, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null new__package_id alias for $16; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, ''lob'' ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null or new__relation_tag = '''' then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- create the revision if data or title is not null if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, null, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__data, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,varchar,text,text,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__title alias for $3; -- default null new__description alias for $4; -- default null new__text alias for $5; -- default null new__package_id alias for $6; -- default null begin return content_item__new(new__name, new__parent_id, null, null, now(), null, null, null, ''content_item'', ''content_revision'', new__title, new__description, ''text/plain'', null, new__text, ''text'', new__package_id ); end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,varchar,text,text) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__title alias for $3; -- default null new__description alias for $4; -- default null new__text alias for $5; -- default null begin return content_item__new(new__name, new__parent_id, new__title, new__description, new__text, null); end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__package_id alias for $3; begin return content_item__new(new__name, new__parent_id, null, null, null, new__package_id); end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; begin return content_item__new(new__name, new__parent_id, null, null, null, null); end;' language 'plpgsql'; -- function new -- sets security_inherit_p to FALSE -DaveB create or replace function content_item__new ( integer, varchar, integer, varchar, timestamptz, integer, integer, varchar, boolean, varchar, text, varchar, boolean, varchar,varchar,varchar,integer) returns integer as ' declare new__item_id alias for $1; --default null new__name alias for $2; new__parent_id alias for $3; -- default null new__title alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__is_live alias for $9; -- default ''f'' new__mime_type alias for $10; new__text alias for $11; -- default null new__storage_type alias for $12; -- check in (''text'', ''file'') new__security_inherit_p alias for $13; -- default ''t'' new__storage_area_key alias for $14; -- default ''CR_FILES'' new__item_subtype alias for $15; new__content_type alias for $16; new__package_id alias for $17; -- default null new__description varchar default null; new__relation_tag varchar default null; new__nls_language varchar default null; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, new__security_inherit_p, v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type, storage_area_key ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type, new__storage_area_key ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', new__creation_date, null, null, v_parent_id, ''f'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( integer, varchar, integer, varchar, timestamptz, integer, integer, varchar, boolean, varchar, text, varchar, boolean, varchar,varchar,varchar) returns integer as ' declare new__item_id alias for $1; --default null new__name alias for $2; new__parent_id alias for $3; -- default null new__title alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__is_live alias for $9; -- default ''f'' new__mime_type alias for $10; new__text alias for $11; -- default null new__storage_type alias for $12; -- check in (''text'', ''file'') new__security_inherit_p alias for $13; -- default ''t'' new__storage_area_key alias for $14; -- default ''CR_FILES'' new__item_subtype alias for $15; new__content_type alias for $16; v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__item_id, new__name, new__parent_id, new__title, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__is_live, new__mime_type, new__text, new__storage_type, new__security_inherit_p, new__storage_area_key, new__item_subtype, new__content_type, null); return v_item_id; end;' language 'plpgsql'; select define_function_args('content_item__is_published','item_id'); create or replace function content_item__is_published (integer) returns boolean as ' declare is_published__item_id alias for $1; begin return count(*) > 0 from cr_items where live_revision is not null and publish_status = ''live'' and item_id = is_published__item_id; end;' language 'plpgsql' stable; select define_function_args('content_item__is_publishable','item_id'); create or replace function content_item__is_publishable (integer) returns boolean as ' declare is_publishable__item_id alias for $1; v_child_count integer; v_rel_count integer; v_content_type varchar; v_template_id cr_templates.template_id%TYPE; v_child_type record; v_rel_type record; -- v_pub_wf record; begin -- check valid item_id select content_item__get_content_type(is_publishable__item_id) into v_content_type; if v_content_type is null then raise exception ''content_item__is_publishable item_id % invalid'',is_publishable__item_id; end if; -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in select child_type, min_n, max_n from cr_type_children where parent_type = v_content_type and (min_n is not null or max_n is not null) LOOP select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable__item_id and content_item__get_content_type(child_id) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return ''f''; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return ''f''; end if; end LOOP; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n -- only check if one of min_n max_n not null for v_rel_type in select target_type, min_n, max_n from cr_type_relations where content_type = v_content_type and (max_n is not null or min_n is not null) LOOP select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable__item_id and coalesce(content_item__get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return ''f''; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return ''f''; end if; end loop; -- validate publishing workflows -- make sure any ''publishing_wf'' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in select -- case_id, state -- from -- wf_cases -- where -- workflow_key = ''publishing_wf'' -- and -- object_id = is_publishable__item_id -- -- LOOP -- if v_pub_wf.state != ''finished'' then -- return ''f''; -- end if; -- end loop; -- if NOT FOUND then -- return ''f''; -- end if; return ''t''; end;' language 'plpgsql' stable; select define_function_args('content_item__is_valid_child','item_id,content_type,relation_tag'); create or replace function content_item__is_valid_child (integer,varchar,varchar) returns boolean as ' declare is_valid_child__item_id alias for $1; is_valid_child__content_type alias for $2; is_valid_child__relation_tag alias for $3; v_is_valid_child boolean; v_max_children cr_type_children.max_n%TYPE; v_n_children integer; v_null_exists boolean; begin v_is_valid_child := ''f''; -- first check if content_type is a registered child_type select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item__get_content_type(is_valid_child__item_id) and child_type = is_valid_child__content_type and (is_valid_child__relation_tag is null or is_valid_child__relation_tag = relation_tag); if NOT FOUND then return ''f''; end if; -- if the max is null then infinite number is allowed if v_max_children is null then return ''t''; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child__item_id and content_item__get_content_type(child_id) = is_valid_child__content_type and (is_valid_child__relation_tag is null or is_valid_child__relation_tag = relation_tag); if NOT FOUND then return ''f''; end if; if v_n_children < v_max_children then v_is_valid_child := ''t''; end if; return v_is_valid_child; end;' language 'plpgsql' stable; create or replace function content_item__is_valid_child (integer,varchar) returns boolean as ' declare is_valid_child__item_id alias for $1; is_valid_child__content_type alias for $2; v_is_valid_child boolean; v_max_children cr_type_children.max_n%TYPE; v_n_children integer; begin v_is_valid_child := ''f''; -- first check if content_type is a registered child_type select sum(max_n) into v_max_children from cr_type_children where parent_type = content_item__get_content_type(is_valid_child__item_id) and child_type = is_valid_child__content_type; if NOT FOUND then return ''f''; end if; -- if the max is null then infinite number is allowed if v_max_children is null then return ''t''; end if; -- next check if there are already max_n children of that content type select count(rel_id) into v_n_children from cr_child_rels where parent_id = is_valid_child__item_id and content_item__get_content_type(child_id) = is_valid_child__content_type; if NOT FOUND then return ''f''; end if; if v_n_children < v_max_children then v_is_valid_child := ''t''; end if; return v_is_valid_child; end;' language 'plpgsql' stable; /* delete a content item 1) delete all associated workflows 2) delete all symlinks associated with this object 3) delete any revisions for this item 4) unregister template relations 5) delete all permissions associated with this item 6) delete keyword associations 7) delete all associated comments */ select define_function_args('content_item__del','item_id'); create or replace function content_item__del (integer) returns integer as ' declare delete__item_id alias for $1; -- v_wf_cases_val record; v_symlink_val record; v_revision_val record; v_rel_val record; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- raise NOTICE ''Deleting associated workflows...''; -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in select -- case_id -- from -- wf_cases -- where -- object_id = delete__item_id -- LOOP -- PERFORM workflow_case__delete(v_wf_cases_val.case_id); -- end loop; -- 2) delete all symlinks to this item for v_symlink_val in select symlink_id from cr_symlinks where target_id = delete__item_id LOOP PERFORM content_symlink__delete(v_symlink_val.symlink_id); end loop; delete from cr_release_periods where item_id = delete__item_id; update cr_items set live_revision = null, latest_revision = null where item_id = delete__item_id; -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = delete__item_id; for v_revision_val in select revision_id from cr_revisions where item_id = delete__item_id LOOP PERFORM acs_object__delete(v_revision_val.revision_id); end loop; -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = delete__item_id; -- Delete all relations on this item for v_rel_val in select rel_id from cr_item_rels where item_id = delete__item_id or related_object_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); end loop; for v_rel_val in select rel_id from cr_child_rels where child_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); end loop; for v_rel_val in select rel_id, child_id from cr_child_rels where parent_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); PERFORM content_item__delete(v_rel_val.child_id); end loop; -- 5) delete associated permissions delete from acs_permissions where object_id = delete__item_id; -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = delete__item_id; -- 7) delete associated comments PERFORM journal_entry__delete_for_object(delete__item_id); -- context_id debugging loop --for v_error_val in c_error_cur loop -- || v_error_val.object_type); --end loop; PERFORM acs_object__delete(delete__item_id); return 0; end;' language 'plpgsql'; select define_function_args('content_item__delete','item_id'); create or replace function content_item__delete (integer) returns integer as ' declare delete__item_id alias for $1; begin PERFORM content_item__del (delete__item_id); return 0; end;' language 'plpgsql'; select define_function_args('content_item__edit_name','item_id,name'); create or replace function content_item__edit_name (integer,varchar) returns integer as ' declare edit_name__item_id alias for $1; edit_name__name alias for $2; exists_id integer; begin select item_id into exists_id from cr_items where name = edit_name__name and parent_id = (select parent_id from cr_items where item_id = edit_name__item_id); if NOT FOUND then update cr_items set name = edit_name__name where item_id = edit_name__item_id; update acs_objects set title = edit_name__name where object_id = edit_name__item_id; else if exists_id != edit_name__item_id then raise EXCEPTION ''-20000: An item with the name % already exists in this directory.'', edit_name__name; end if; end if; return 0; end;' language 'plpgsql'; select define_function_args('content_item__get_id','item_path,root_folder_id,resolve_index;f'); create or replace function content_item__get_id (varchar,integer,boolean) returns integer as ' declare get_id__item_path alias for $1; get_id__root_folder_id alias for $2; -- default null get_id__resolve_index alias for $3; -- default ''f'' v_item_path varchar; v_root_folder_id cr_items.item_id%TYPE; get_id__parent_id integer; child_id integer; start_pos integer default 1; end_pos integer; counter integer default 1; item_name varchar; begin if get_id__root_folder_id is null then select c_root_folder_id from content_item_globals into v_root_folder_id; else v_root_folder_id := get_id__root_folder_id; end if; -- If the request path is the root, then just return the root folder if get_id__item_path = ''/'' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(get_id__item_path), ''/''), ''/''); get_id__parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it get_id__parent_id := content_symlink__resolve(get_id__parent_id); LOOP end_pos := instr(v_item_path, ''/'', 1, counter); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); counter := counter + 1; end if; select item_id into child_id from cr_items where parent_id = get_id__parent_id and name = item_name; if NOT FOUND then return null; end if; exit when end_pos = 0; get_id__parent_id := child_id; -- if parent_id is a symlink, resolve it get_id__parent_id := content_symlink__resolve(get_id__parent_id); start_pos := end_pos + 1; end loop; if get_id__resolve_index = ''t'' then -- if the item is a folder and has an index page, then return if content_folder__is_folder(child_id ) = ''t'' and content_folder__get_index_page(child_id) is not null then child_id := content_folder__get_index_page(child_id); end if; end if; return child_id; end;' language 'plpgsql' stable; -- create sequence content_item_gp_session_id; -- create table get_path_cursors ( -- rel_cursor_pos integer, -- abs_cursor_pos integer -- ); -- insert into get_path_cursors values (0,0); -- create table get_path_abs_cursor ( -- sid integer, -- pos integer, -- name text, -- parent_id integer, -- tree_level integer, -- primary key (sid,pos) -- ); -- create table get_path_rel_cursor ( -- sid integer, -- pos integer, -- parent_id integer, -- tree_level integer, -- primary key (sid,pos) -- ); -- create or replace function content_item__create_rel_cursor(integer,integer) -- returns integer as ' -- declare -- v_item_id alias for $1; -- v_sid alias for $2; -- v_rec record; -- v_cur_pos integer default 0; -- begin -- update get_path_cursors set rel_cursor_pos = 0; -- for v_rec in select i2.name, -- i2.parent_id, -- tree_level(i2.tree_sortkey) as tree_level -- from (select * from cr_items where item_id = v_item_id) i1, -- cr_items i2 -- where i2.parent_id <> 0 -- and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) -- order by i2.tree_sortkey -- LOOP -- insert into get_path_rel_cursor -- (sid,pos,parent_id,tree_level) -- values -- (v_sid,v_cur_pos,v_rec.parent_id,v_rec.tree_level); -- v_cur_pos := v_cur_pos + 1; -- end LOOP; -- return null; -- end;' language 'plpgsql'; -- create or replace function content_item__create_abs_cursor(integer,integer) -- returns integer as ' -- declare -- v_item_id alias for $1; -- v_sid alias for $2; -- v_rec record; -- v_cur_pos integer default 0; -- begin -- update get_path_cursors set abs_cursor_pos = 0; -- for v_rec in select i2.name, -- i2.parent_id, -- tree_level(i2.tree_sortkey) as tree_level -- from (select * from cr_items where item_id = v_item_id) i1, -- cr_items i2 -- where i2.parent_id <> 0 -- and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) -- order by i2.tree_sortkey -- LOOP -- insert into get_path_abs_cursor -- (sid,pos,name,parent_id,tree_level) -- values -- (v_sid,v_cur_pos,v_rec.name,v_rec.parent_id,v_rec.tree_level); -- v_cur_pos := v_cur_pos + 1; -- end LOOP; -- return null; -- end;' language 'plpgsql'; -- create or replace function content_item__abs_cursor_next_pos() returns integer as ' -- declare -- v_pos integer; -- begin -- select abs_cursor_pos into v_pos from get_path_cursors; -- update get_path_cursors set abs_cursor_pos = abs_cursor_pos + 1; -- return v_pos; -- end;' language 'plpgsql'; -- create or replace function content_item__rel_cursor_next_pos() returns integer as ' -- declare -- v_pos integer; -- begin -- select rel_cursor_pos into v_pos from get_path_cursors; -- update get_path_cursors set rel_cursor_pos = rel_cursor_pos + 1; -- return v_pos; -- end;' language 'plpgsql'; -- -- if called with null its a noop and returns null so strict. -- create or replace function content_item__cleanup_cursors(integer) returns integer as ' -- declare -- v_sid alias for $1; -- begin -- delete from get_path_abs_cursor where sid = v_sid; -- delete from get_path_rel_cursor where sid = v_sid; -- return null; -- end;' language 'plpgsql' strict; -- old slow version -- create or replace function content_item__get_path (integer,integer) -- returns varchar as ' -- declare -- get_path__item_id alias for $1; -- get_path__root_folder_id alias for $2; -- default null -- v_count integer; -- v_name varchar; -- v_saved_name varchar; -- v_parent_id integer default 0; -- v_tree_level integer; -- v_resolved_root_id integer; -- v_rel_parent_id integer default 0; -- v_rel_tree_level integer default 0; -- v_path text default ''''; -- v_rec record; -- v_item_id integer; -- v_rel_item_id integer; -- v_session_id integer; -- v_rel_found_p boolean; -- v_abs_found_p boolean; -- v_tmp integer; -- begin -- -- check that the item exists -- select count(*) into v_count from cr_items where item_id = get_path__item_id; -- if v_count = 0 then -- raise EXCEPTION ''-20000: Invalid item ID: %'', get_path__item_id; -- end if; -- -- begin walking down the path to the item (from the repository root) -- -- if the root folder is not null then prepare for a relative path -- if get_path__root_folder_id is not null then -- -- if root_folder_id is a symlink, resolve it (child items will point -- -- to the actual folder, not the symlink) -- v_resolved_root_id := content_symlink__resolve(get_path__root_folder_id); -- v_session_id := nextval(''content_item_gp_session_id''); -- PERFORM content_item__create_abs_cursor(get_path__item_id, v_session_id); -- PERFORM content_item__create_rel_cursor(v_resolved_root_id, v_session_id); -- -- begin walking down the path to the root folder. Discard -- -- elements of the item path as long as they are the same as the root -- -- folder -- while v_parent_id = v_rel_parent_id loop -- v_tmp := content_item__abs_cursor_next_pos(); -- select name, parent_id, tree_level -- into v_name, v_parent_id, v_tree_level -- from get_path_abs_cursor -- where sid = v_session_id -- and pos = v_tmp; -- if NOT FOUND then -- v_name := v_saved_name; -- v_abs_found_p := ''f''; -- else -- v_saved_name := v_name; -- v_abs_found_p := ''t''; -- end if; -- v_tmp := content_item__rel_cursor_next_pos(); -- select parent_id, tree_level -- into v_rel_parent_id, v_rel_tree_level -- from get_path_rel_cursor -- where sid = v_session_id -- and pos = v_tmp; -- if NOT FOUND then -- v_rel_found_p := ''f''; -- else -- v_rel_found_p := ''t''; -- end if; -- exit when NOT v_rel_found_p or NOT v_abs_found_p; -- end loop; -- -- walk the remainder of the relative path, add a ''..'' for each -- -- additional step -- LOOP -- exit when NOT v_rel_found_p; -- v_path := v_path || ''../''; -- v_tmp := content_item__rel_cursor_next_pos(); -- select parent_id, tree_level -- into v_rel_parent_id, v_rel_tree_level -- from get_path_rel_cursor -- where sid = v_session_id -- and pos = v_tmp; -- if NOT FOUND then -- v_rel_found_p := ''f''; -- else -- v_rel_found_p := ''t''; -- end if; -- end loop; -- -- an item relative to itself is ''../item'' -- if v_resolved_root_id = get_path__item_id then -- v_path := ''../''; -- end if; -- -- loop over the remainder of the absolute path -- LOOP -- v_path := v_path || v_name; -- v_tmp := content_item__abs_cursor_next_pos(); -- select name, parent_id, tree_level -- into v_name, v_parent_id, v_tree_level -- from get_path_abs_cursor -- where sid = v_session_id -- and pos = v_tmp; -- if NOT FOUND then -- v_abs_found_p := ''f''; -- else -- v_abs_found_p := ''t''; -- end if; -- exit when NOT v_abs_found_p; -- v_path := v_path || ''/''; -- end LOOP; -- PERFORM content_item__cleanup_cursors(v_session_id); -- else -- -- this is an absolute path so prepend a ''/'' -- -- loop over the absolute path -- for v_rec in select i2.name, tree_level(i2.tree_sortkey) as tree_level -- from cr_items i1, cr_items i2 -- where i2.parent_id <> 0 -- and i1.item_id = get_path__item_id -- and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) -- order by tree_level -- LOOP -- v_path := v_path || ''/'' || v_rec.name; -- end loop; -- end if; -- return v_path; -- end;' language 'plpgsql'; select define_function_args('content_item__get_path','item_id,root_folder_id'); create or replace function content_item__get_path (integer,integer) returns varchar as ' declare get_path__item_id alias for $1; get_path__root_folder_id alias for $2; -- default null v_count integer; v_resolved_root_id integer; v_path text default ''''; v_rec record; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path__item_id; if v_count = 0 then raise EXCEPTION ''-20000: Invalid item ID: %'', get_path__item_id; end if; -- begin walking down the path to the item (from the repository root) -- if the root folder is not null then prepare for a relative path if get_path__root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink__resolve(get_path__root_folder_id); -- check to see if the item is under or out side the root_id PERFORM 1 from cr_items i, (select tree_sortkey from cr_items where item_id = v_resolved_root_id) a where tree_ancestor_p(a.tree_sortkey, i.tree_sortkey) and i.item_id = get_path__item_id; if NOT FOUND then -- if not found then we need to go up the folder and append ../ until we have common ancestor for v_rec in select i1.name, i1.parent_id, tree_level(i1.tree_sortkey) as tree_level from cr_items i1, (select tree_ancestor_keys(tree_sortkey) as tree_sortkey from cr_items where item_id = v_resolved_root_id) i2, (select tree_sortkey from cr_items where item_id = get_path__item_id) i3 where i1.parent_id <> 0 and i2.tree_sortkey = i1.tree_sortkey and not tree_ancestor_p(i2.tree_sortkey, i3.tree_sortkey) order by tree_level desc LOOP v_path := v_path || ''../''; end loop; -- lets now assign the new root_id to be the last parent_id on the loop v_resolved_root_id := v_rec.parent_id; end if; -- go downwards the tree and append the name and / for v_rec in select i1.name, i1.item_id, tree_level(i1.tree_sortkey) as tree_level from cr_items i1, (select tree_sortkey from cr_items where item_id = v_resolved_root_id) i2, (select tree_ancestor_keys(tree_sortkey) as tree_sortkey from cr_items where item_id = get_path__item_id) i3 where i1.tree_sortkey = i3.tree_sortkey and i1.tree_sortkey > i2.tree_sortkey order by tree_level LOOP v_path := v_path || v_rec.name; if v_rec.item_id <> get_path__item_id then -- put a / if we are still going down v_path := v_path || ''/''; end if; end loop; else -- this is an absolute path so prepend a ''/'' -- loop over the absolute path for v_rec in select i2.name, tree_level(i2.tree_sortkey) as tree_level from cr_items i1, cr_items i2 where i2.parent_id <> 0 and i1.item_id = get_path__item_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) order by tree_level LOOP v_path := v_path || ''/'' || v_rec.name; end loop; end if; return v_path; end;' language 'plpgsql'; -- I hard code the content_item_globals.c_root_folder_id here select define_function_args('content_item__get_virtual_path','item_id,root_folder_id;-100'); create or replace function content_item__get_virtual_path (integer,integer) returns varchar as ' declare get_virtual_path__item_id alias for $1; get_virtual_path__root_folder_id alias for $2; -- default content_item_globals.c_root_folder_id v_path varchar; v_item_id cr_items.item_id%TYPE; v_is_folder boolean; v_index cr_items.item_id%TYPE; begin -- XXX possible bug: root_folder_id arg is ignored. -- first resolve the item v_item_id := content_symlink__resolve(get_virtual_path__item_id); v_is_folder := content_folder__is_folder(v_item_id); v_index := content_folder__get_index_page(v_item_id); -- if the folder has an index page if v_is_folder = ''t'' and v_index is not null then v_path := content_item__get_path(content_symlink__resolve(v_index),null); else v_path := content_item__get_path(v_item_id,null); end if; return v_path; end;' language 'plpgsql'; create or replace function content_item__write_to_file (integer,varchar) returns integer as ' declare item_id alias for $1; root_path alias for $2; -- blob_loc cr_revisions.content%TYPE; -- v_revision cr_items.live_revision%TYPE; begin -- FIXME: raise NOTICE ''not implemented for postgresql''; /* v_revision := content_item__get_live_revision(item_id); select content into blob_loc from cr_revisions where revision_id = v_revision; if NOT FOUND then raise EXCEPTION ''-20000: No live revision for content item % in content_item.write_to_file.'', item_id; end if; PERFORM blob_to_file(root_path || content_item__get_path(item_id), blob_loc); */ return 0; end;' language 'plpgsql'; select define_function_args('content_item__register_template','item_id,template_id,use_context'); create or replace function content_item__register_template (integer,integer,varchar) returns integer as ' declare register_template__item_id alias for $1; register_template__template_id alias for $2; register_template__use_context alias for $3; begin -- register template if it is not already registered insert into cr_item_template_map select register_template__item_id as item_id, register_template__template_id as template_id, register_template__use_context as use_context from dual where not exists ( select 1 from cr_item_template_map where item_id = register_template__item_id and template_id = register_template__template_id and use_context = register_template__use_context ); return 0; end;' language 'plpgsql'; select define_function_args('content_item__unregister_template','item_id,template_id,use_context'); create or replace function content_item__unregister_template (integer,integer,varchar) returns integer as ' declare unregister_template__item_id alias for $1; unregister_template__template_id alias for $2; -- default null unregister_template__use_context alias for $3; -- default null begin if unregister_template__use_context is null and unregister_template__template_id is null then delete from cr_item_template_map where item_id = unregister_template__item_id; else if unregister_template__use_context is null then delete from cr_item_template_map where template_id = unregister_template__template_id and item_id = unregister_template__item_id; else if unregister_template__template_id is null then delete from cr_item_template_map where item_id = unregister_template__item_id and use_context = unregister_template__use_context; else delete from cr_item_template_map where template_id = unregister_template__template_id and item_id = unregister_template__item_id and use_context = unregister_template__use_context; end if; end if; end if; return 0; end;' language 'plpgsql'; select define_function_args('content_item__get_template','item_id,use_context'); create or replace function content_item__get_template (integer,varchar) returns integer as ' declare get_template__item_id alias for $1; get_template__use_context alias for $2; v_template_id cr_templates.template_id%TYPE; v_content_type cr_items.content_type%TYPE; begin -- look for a template assigned specifically to this item select template_id into v_template_id from cr_item_template_map where item_id = get_template__item_id and use_context = get_template__use_context; -- otherwise get the default for the content type if NOT FOUND then select m.template_id into v_template_id from cr_items i, cr_type_template_map m where i.item_id = get_template__item_id and i.content_type = m.content_type and m.use_context = get_template__use_context and m.is_default = ''t''; if NOT FOUND then return null; end if; end if; return v_template_id; end;' language 'plpgsql' stable strict; select define_function_args('content_item__get_content_type','item_id'); create or replace function content_item__get_content_type (integer) returns varchar as ' declare get_content_type__item_id alias for $1; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type__item_id; return v_content_type; end;' language 'plpgsql' stable strict; select define_function_args('content_item__get_live_revision','item_id'); select define_function_args('content_item__get_live_revision','item_id'); create or replace function content_item__get_live_revision (integer) returns integer as ' declare get_live_revision__item_id alias for $1; v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision__item_id; return v_revision_id; end;' language 'plpgsql' stable strict; select define_function_args('content_item__set_live_revision','revision_id,publish_status;ready'); create or replace function content_item__set_live_revision (integer) returns integer as ' declare set_live_revision__revision_id alias for $1; set_live_revision__publish_status cr_items.publish_status%TYPE default ''ready''; begin update cr_items set live_revision = set_live_revision__revision_id, publish_status = set_live_revision__publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision__revision_id); update cr_revisions set publish_date = now() where revision_id = set_live_revision__revision_id; return 0; end;' language 'plpgsql'; select define_function_args('content_item__set_live_revision','revision_id,publish_status;ready'); create or replace function content_item__set_live_revision (integer,varchar) returns integer as ' declare set_live_revision__revision_id alias for $1; set_live_revision__publish_status alias for $2; -- default ''ready'' begin update cr_items set live_revision = set_live_revision__revision_id, publish_status = set_live_revision__publish_status where item_id = (select item_id from cr_revisions where revision_id = set_live_revision__revision_id); update cr_revisions set publish_date = now() where revision_id = set_live_revision__revision_id; return 0; end;' language 'plpgsql'; select define_function_args('content_item__unset_live_revision','item_id'); create or replace function content_item__unset_live_revision (integer) returns integer as ' declare unset_live_revision__item_id alias for $1; begin update cr_items set live_revision = NULL where item_id = unset_live_revision__item_id; -- if an items publish status is "live", change it to "ready" update cr_items set publish_status = ''production'' where publish_status = ''live'' and item_id = unset_live_revision__item_id; return 0; end;' language 'plpgsql'; select define_function_args('content_item__set_release_period','item_id,start_when,end_when'); create or replace function content_item__set_release_period (integer, timestamptz, timestamptz) returns integer as ' declare set_release_period__item_id alias for $1; set_release_period__start_when alias for $2; -- default null set_release_period__end_when alias for $3; -- default null v_count integer; begin select count(*) into v_count from cr_release_periods where item_id = set_release_period__item_id; if v_count = 0 then insert into cr_release_periods ( item_id, start_when, end_when ) values ( set_release_period__item_id, set_release_period__start_when, set_release_period__end_when ); else update cr_release_periods set start_when = set_release_period__start_when, end_when = set_release_period__end_when where item_id = set_release_period__item_id; end if; return 0; end;' language 'plpgsql'; select define_function_args('content_item__get_revision_count','item_id'); select define_function_args('content_item__get_revision_count','item_id'); create or replace function content_item__get_revision_count (integer) returns integer as ' declare get_revision_count__item_id alias for $1; v_count integer; begin select count(*) into v_count from cr_revisions where item_id = get_revision_count__item_id; return v_count; end;' language 'plpgsql' stable; select define_function_args('content_item__get_context','item_id'); create or replace function content_item__get_context (integer) returns integer as ' declare get_context__item_id alias for $1; v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context__item_id; if NOT FOUND then raise EXCEPTION ''-20000: Content item % does not exist in content_item.get_context'', get_context__item_id; end if; return v_context_id; end;' language 'plpgsql' stable; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item create or replace function content_item__move (integer,integer) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; begin perform content_item__move( move__item_id, move__target_folder_id, NULL ); return null; end;' language 'plpgsql'; select define_function_args('content_item__move','item_id,target_folder_id,name'); create or replace function content_item__move (integer,integer,varchar) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; begin if move__target_folder_id is null then raise exception ''attempt to move item_id % to null folder_id'', move__item_id; end if; if content_folder__is_folder(move__item_id) = ''t'' then PERFORM content_folder__move(move__item_id, move__target_folder_id); elsif content_folder__is_folder(move__target_folder_id) = ''t'' then if content_folder__is_registered(move__target_folder_id, content_item__get_content_type(move__item_id),''f'') = ''t'' and content_folder__is_registered(move__target_folder_id, content_item__get_content_type(content_symlink__resolve(move__item_id)),''f'') = ''t'' then -- update the parent_id for the item update cr_items set parent_id = move__target_folder_id, name = coalesce(move__name, name) where item_id = move__item_id; end if; if move__name is not null then update acs_objects set title = move__name where object_id = move__item_id; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_item__copy (integer,integer,integer,varchar) returns integer as ' declare item_id alias for $1; target_folder_id alias for $2; creation_user alias for $3; creation_ip alias for $4; -- default null copy_id cr_items.item_id%TYPE; begin copy_id := content_item__copy2(item_id, target_folder_id, creation_user, creation_ip); return 0; end;' language 'plpgsql'; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) create or replace function content_item__copy2 (integer,integer,integer,varchar) returns integer as ' declare copy2__item_id alias for $1; copy2__target_folder_id alias for $2; copy2__creation_user alias for $3; copy2__creation_ip alias for $4; -- default null begin perform content_item__copy ( copy2__item_id, copy2__target_folder_id, copy2__creation_user, copy2__creation_ip, null ); return copy2__item_id; end;' language 'plpgsql'; select define_function_args('content_item__copy','item_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_item__copy ( integer, integer, integer, varchar, varchar ) returns integer as ' declare copy__item_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered boolean; v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_old_live_revision_id cr_revisions.revision_id%TYPE; v_new_live_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder__is_folder(copy__item_id) = ''t'' then PERFORM content_folder__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_symlink.copy if the item is a symlink else if content_symlink__is_symlink(copy__item_id) = ''t'' then PERFORM content_symlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_extlink.copy if the item is an url else if content_extlink__is_extlink(copy__item_id) = ''t'' then PERFORM content_extlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- make sure the target folder is really a folder else if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__item_id; select content_type, name, locale, coalesce(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy__item_id; -- copy to a different folder, or allow copy to the same folder -- with a different name if copy__target_folder_id != v_current_folder_id or ( v_name != copy__name and copy__name is not null ) then -- make sure the content type of the item is registered to the folder v_is_registered := content_folder__is_registered( copy__target_folder_id, v_content_type, ''f'' ); if v_is_registered = ''t'' then -- create the new content item v_item_id := content_item__new( coalesce (copy__name, v_name), copy__target_folder_id, null, v_locale, now(), copy__creation_user, null, copy__creation_ip, ''content_item'', v_content_type, null, null, ''text/plain'', null, null, v_storage_type ); select latest_revision, live_revision into v_old_revision_id, v_old_live_revision_id from cr_items where item_id = copy__item_id; end if; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision__copy ( v_old_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); end if; -- copy the live revision (if there is one and it differs from the latest) to the new item if v_old_live_revision_id is not null then if v_old_live_revision_id <> v_old_revision_id then v_new_live_revision_id := content_revision__copy ( v_old_live_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); else v_new_live_revision_id := v_new_revision_id; end if; end if; update cr_items set live_revision = v_new_live_revision_id, latest_revision = v_new_revision_id where item_id = v_item_id; end if; end if; end if; end if; end if; return v_item_id; end;' language 'plpgsql'; select define_function_args('content_item__get_latest_revision','item_id'); create or replace function content_item__get_latest_revision (integer) returns integer as ' declare get_latest_revision__item_id alias for $1; v_revision_id integer; v_rec record; begin for v_rec in select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision__item_id order by o.creation_date desc LOOP v_revision_id := v_rec.revision_id; exit; end LOOP; return v_revision_id; end;' language 'plpgsql' strict stable; select define_function_args('content_item__get_best_revision','item_id'); create or replace function content_item__get_best_revision (integer) returns integer as ' declare get_best_revision__item_id alias for $1; v_revision_id cr_revisions.revision_id%TYPE; begin select coalesce(live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision__item_id; return v_revision_id; end;' language 'plpgsql' stable strict; select define_function_args('content_item__get_title','item_id,is_live;f'); create or replace function content_item__get_title (integer,boolean) returns varchar as ' declare get_title__item_id alias for $1; get_title__is_live alias for $2; -- default ''f'' v_title cr_revisions.title%TYPE; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_title__item_id; if v_content_type = ''content_folder'' then select label into v_title from cr_folders where folder_id = get_title__item_id; else if v_content_type = ''content_symlink'' then select label into v_title from cr_symlinks where symlink_id = get_title__item_id; else if v_content_type = ''content_extlink'' then select label into v_title from cr_extlinks where extlink_id = get_title__item_id; else if get_title__is_live then select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title__item_id and r.revision_id = i.live_revision; else select title into v_title from cr_revisions r, cr_items i where i.item_id = get_title__item_id and r.revision_id = i.latest_revision; end if; end if; end if; end if; return v_title; end;' language 'plpgsql' stable; create or replace function content_item__get_title (integer) returns varchar as ' declare get_title__item_id alias for $1; begin return content_item__get_title(get_title__item_id, ''f''); end;' language 'plpgsql' stable strict; select define_function_args('content_item__get_publish_date','item_id,is_live;f'); create or replace function content_item__get_publish_date (integer,boolean) returns timestamptz as ' declare get_publish_date__item_id alias for $1; get_publish_date__is_live alias for $2; -- default ''f'' v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if get_publish_date__is_live then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date__item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date__item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; end;' language 'plpgsql' stable; select define_function_args('content_item__is_subclass','object_type,supertype'); create or replace function content_item__is_subclass (varchar,varchar) returns boolean as ' declare is_subclass__object_type alias for $1; is_subclass__supertype alias for $2; v_subclass_p boolean; v_inherit_val record; begin select count(*) > 0 into v_subclass_p where exists ( select 1 from acs_object_types o, acs_object_types o2 where o2.object_type = is_subclass__supertype and o.object_type = is_subclass__object_type and o.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)); return v_subclass_p; end;' language 'plpgsql' stable; select define_function_args('content_item__relate','item_id,object_id,relation_tag;generic,order_n,relation_type;cr_item_rel'); create or replace function content_item__relate (integer,integer,varchar,integer,varchar) returns integer as ' declare relate__item_id alias for $1; relate__object_id alias for $2; relate__relation_tag alias for $3; -- default ''generic'' relate__order_n alias for $4; -- default null relate__relation_type alias for $5; -- default ''cr_item_rel'' v_content_type cr_items.content_type%TYPE; v_object_type acs_objects.object_type%TYPE; v_is_valid integer; v_rel_id integer; v_package_id integer; v_exists integer; v_order_n cr_item_rels.order_n%TYPE; begin -- check the relationship is valid v_content_type := content_item__get_content_type (relate__item_id); v_object_type := content_item__get_content_type (relate__object_id); select count(1) into v_is_valid from cr_type_relations where content_item__is_subclass( v_object_type, target_type ) = ''t'' and content_item__is_subclass( v_content_type, content_type ) = ''t''; if v_is_valid = 0 then raise EXCEPTION ''-20000: There is no registered relation type matching this item relation.''; end if; if relate__item_id != relate__object_id then -- check that these two items are not related already --dbms_output.put_line( ''checking if the items are already related...''); select rel_id, 1 into v_rel_id, v_exists from cr_item_rels where item_id = relate__item_id and related_object_id = relate__object_id and relation_tag = relate__relation_tag; if NOT FOUND then v_exists := 0; end if; v_package_id := acs_object__package_id(relate__item_id); -- if order_n is null, use rel_id (the order the item was related) if relate__order_n is null then v_order_n := v_rel_id; else v_order_n := relate__order_n; end if; -- if relationship does not exist, create it if v_exists <> 1 then --dbms_output.put_line( ''creating new relationship...''); v_rel_id := acs_object__new( null, relate__relation_type, now(), null, null, relate__item_id, ''t'', relate__relation_tag || '': '' || relate__item_id || '' - '' || relate__object_id, v_package_id ); insert into cr_item_rels ( rel_id, item_id, related_object_id, order_n, relation_tag ) values ( v_rel_id, relate__item_id, relate__object_id, v_order_n, relate__relation_tag ); -- if relationship already exists, update it else --dbms_output.put_line( ''updating existing relationship...''); update cr_item_rels set relation_tag = relate__relation_tag, order_n = v_order_n where rel_id = v_rel_id; update acs_objects set title = relate__relation_tag || '': '' || relate__item_id || '' - '' || relate__object_id where object_id = v_rel_id; end if; end if; return v_rel_id; end;' language 'plpgsql'; select define_function_args('content_item__unrelate','rel_id'); select define_function_args('content_item__unrelate','rel_id'); create or replace function content_item__unrelate (integer) returns integer as ' declare unrelate__rel_id alias for $1; begin -- delete the relation object PERFORM acs_rel__delete(unrelate__rel_id); -- delete the row from the cr_item_rels table delete from cr_item_rels where rel_id = unrelate__rel_id; return 0; end;' language 'plpgsql'; select define_function_args('content_item__is_index_page','item_id,folder_id'); select define_function_args('content_item__is_index_page','item_id,folder_id'); create or replace function content_item__is_index_page (integer,integer) returns boolean as ' declare is_index_page__item_id alias for $1; is_index_page__folder_id alias for $2; begin if content_folder__get_index_page(is_index_page__folder_id) = is_index_page__item_id then return ''t''; else return ''f''; end if; end;' language 'plpgsql' stable; select define_function_args('content_item__get_parent_folder','item_id'); create or replace function content_item__get_parent_folder (integer) returns integer as ' declare get_parent_folder__item_id alias for $1; v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p boolean default ''f''; begin v_folder_id := get_parent_folder__item_id; while NOT v_parent_folder_p and v_folder_id is not null LOOP select parent_id, content_folder__is_folder(parent_id) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end;' language 'plpgsql' stable strict; -- Trigger to maintain context_id in acs_objects create function cr_items_update_tr () returns opaque as ' begin if new.parent_id <> old.parent_id then update acs_objects set context_id = new.parent_id where object_id = new.item_id; end if; return new; end;' language 'plpgsql'; create trigger cr_items_update_tr after update on cr_items for each row execute procedure cr_items_update_tr (); -- Trigger to maintain publication audit trail create function cr_items_publish_update_tr () returns opaque as ' begin if new.live_revision <> old.live_revision or new.publish_status <> old.publish_status then insert into cr_item_publish_audit ( item_id, old_revision, new_revision, old_status, new_status, publish_date ) values ( new.item_id, old.live_revision, new.live_revision, old.publish_status, new.publish_status, now() ); end if; return new; end;' language 'plpgsql'; create trigger cr_items_publish_update_tr before update on cr_items for each row execute procedure cr_items_publish_update_tr (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-revision.sql0000644000175000017500000006767111144344032030252 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-revision.sql,v 1.46 2009/02/10 18:31:54 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- create or replace package body content_revision -- function new -- DRB: BLOB issues make it impractical to use package_instantiate_object to create -- new revisions that contain binary data so a higher-level Tcl API is required rather -- than the standard package_instantiate_object. So we don't bother calling define_function_args -- here. create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null -- lob id new__data alias for $6; new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null new__package_id alias for $12; -- default null v_revision_id integer; v_package_id acs_objects.package_id%TYPE; v_content_type acs_object_types.object_type%TYPE; begin v_content_type := content_item__get_content_type(new__item_id); if new__package_id is null then v_package_id := acs_object__package_id(new__item_id); else v_package_id := new__package_id; end if; v_revision_id := acs_object__new( new__revision_id, v_content_type, new__creation_date, new__creation_user, new__creation_ip, new__item_id, ''t'', new__title, v_package_id ); -- binary data is stored in cr_revisions using Dons lob hack. -- This routine only inserts the lob id. It would need to be followed by -- ns_pg blob_dml from within a tcl script to actually insert the lob data. -- After the lob data is inserted, the content_length needs to be updated -- as well. -- DanW, 2001-05-10. insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, lob, item_id, content_length ) values ( v_revision_id, new__title, new__description, new__mime_type, new__publish_date, new__nls_language, new__data, new__item_id, 0 ); return v_revision_id; end;' language 'plpgsql'; create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null -- lob id new__data alias for $6; new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, new__nls_language, new__data, new__item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, null ); end;' language 'plpgsql'; create or replace function content_revision__new(varchar,varchar,timestamptz,varchar,text,integer,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__text alias for $5; -- default '' '' new__item_id alias for $6; new__package_id alias for $7; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, null, new__text, new__item_id, null, now(), null, null, null, new__package_id ); end;' language 'plpgsql'; create or replace function content_revision__new(varchar,varchar,timestamptz,varchar,text,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__text alias for $5; -- default '' '' new__item_id alias for $6; begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, null, new__text, new__item_id, null, now(), null, null, null, null ); end;' language 'plpgsql'; create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,text,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null new__text alias for $6; -- default '' '' new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, new__nls_language, new__text, new__item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, null, null ); end;' language 'plpgsql'; create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,text,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null new__text alias for $6; -- default '' '' new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null new__content_length alias for $12; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, new__nls_language, new__text, new__item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, new__content_length, null ); end;' language 'plpgsql'; -- function new create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,text,integer,integer,timestamptz,integer,varchar,integer,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null new__text alias for $6; -- default '' '' new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null new__content_length alias for $12; -- default null new__package_id alias for $13; -- default null v_revision_id integer; v_package_id acs_objects.package_id%TYPE; v_content_type acs_object_types.object_type%TYPE; v_storage_type cr_items.storage_type%TYPE; v_length cr_revisions.content_length%TYPE; begin v_content_type := content_item__get_content_type(new__item_id); if new__package_id is null then v_package_id := acs_object__package_id(new__item_id); else v_package_id := new__package_id; end if; v_revision_id := acs_object__new( new__revision_id, v_content_type, new__creation_date, new__creation_user, new__creation_ip, new__item_id, ''t'', new__title, v_package_id ); select storage_type into v_storage_type from cr_items where item_id = new__item_id; if v_storage_type = ''text'' then v_length := length(new__text); else v_length := coalesce(new__content_length,0); end if; -- text data is stored directly in cr_revisions using text datatype. insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, content, item_id, content_length ) values ( v_revision_id, new__title, new__description, new__mime_type, new__publish_date, new__nls_language, new__text, new__item_id, v_length ); return v_revision_id; end;' language 'plpgsql'; -- procedure copy_attributes select define_function_args('content_revision__copy_attributes','content_type,revision_id,copy_id'); create or replace function content_revision__copy_attributes (varchar,integer,integer) returns integer as ' declare copy_attributes__content_type alias for $1; copy_attributes__revision_id alias for $2; copy_attributes__copy_id alias for $3; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; attr_rec record; begin if copy_attributes__content_type is null or copy_attributes__revision_id is null or copy_attributes__copy_id is null then raise exception ''content_revision__copy_attributes called with null % % %'',copy_attributes__content_type,copy_attributes__revision_id, copy_attributes__copy_id; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = copy_attributes__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; end loop; execute ''insert into '' || v_table_name || ''('' || v_id_column || cols || '')'' || '' select '' || copy_attributes__copy_id || '' as '' || v_id_column || cols || '' from '' || v_table_name || '' where '' || v_id_column || '' = '' || copy_attributes__revision_id; return 0; end;' language 'plpgsql'; -- function copy select define_function_args('content_revision__copy','revision_id,copy_id,target_item_id,creation_user,creation_ip'); create or replace function content_revision__copy (integer,integer,integer,integer,varchar) returns integer as ' declare copy__revision_id alias for $1; copy__copy_id alias for $2; -- default null copy__target_item_id alias for $3; -- default null copy__creation_user alias for $4; -- default null copy__creation_ip alias for $5; -- default null v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; type_rec record; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if copy__target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy__revision_id; else v_target_item_id := copy__target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy__copy_id is null then select nextval(''t_acs_object_id_seq'') into v_copy_id from dual; else v_copy_id := copy__copy_id; end if; -- create the basic object insert into acs_objects ( object_id, object_type, context_id, security_inherit_p, creation_user, creation_date, creation_ip, last_modified, modifying_user, modifying_ip, title, package_id) select v_copy_id as object_id, object_type, v_target_item_id, security_inherit_p, copy__creation_user as creation_user, now() as creation_date, copy__creation_ip as creation_ip, now() as last_modified, copy__creation_user as modifying_user, copy__creation_ip as modifying_ip, title, package_id from acs_objects where object_id = copy__revision_id; -- create the basic revision (using v_target_item_id) insert into cr_revisions select v_copy_id as revision_id, v_target_item_id as item_id, title, description, publish_date, mime_type, nls_language, lob, content, content_length from cr_revisions where revision_id = copy__revision_id; -- iterate over the ancestor types and copy attributes for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2, acs_objects o where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and o.object_id = copy__revision_id and ot1.object_type = o.object_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level desc LOOP PERFORM content_revision__copy_attributes(type_rec.object_type, copy__revision_id, v_copy_id); end loop; return v_copy_id; end;' language 'plpgsql'; -- procedure delete select define_function_args('content_revision__del','revision_id'); create or replace function content_revision__del (integer) returns integer as ' declare delete__revision_id alias for $1; v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; v_rec record; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = delete__revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = delete__revision_id then for v_rec in select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> delete__revision_id order by o.creation_date desc LOOP v_latest_revision := v_rec.revision_id; exit; end LOOP; if NOT FOUND then v_latest_revision := null; end if; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end if; -- Clear live revision if v_live_revision = delete__revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = delete__revision_id or new_revision = delete__revision_id; -- Delete the revision PERFORM acs_object__delete(delete__revision_id); return 0; end;' language 'plpgsql'; select define_function_args('content_revision__delete','revision_id'); create or replace function content_revision__delete (integer) returns integer as ' declare delete__revision_id alias for $1; begin PERFORM content_revision__del(delete__revision_id); return 0; end;' language 'plpgsql'; -- function get_number select define_function_args('content_revision__get_number','revision_id'); create or replace function content_revision__get_number (integer) returns integer as ' declare get_number__revision_id alias for $1; v_revision cr_revisions.revision_id%TYPE; v_row_count integer default 0; rev_cur record; begin for rev_cur in select revision_id from cr_revisions r, acs_objects o where item_id = (select item_id from cr_revisions where revision_id = get_number__revision_id) and o.object_id = r.revision_id order by o.creation_date LOOP v_row_count := v_row_count + 1; if rev_cur.revision_id = get_number__revision_id then return v_row_count; exit; end if; end LOOP; return null; end;' language 'plpgsql' stable strict; select define_function_args('content_revision__revision_name','revision_id'); create or replace function content_revision__revision_name(integer) returns text as ' declare p_revision_id alias for $1; begin return ''Revision '' || content_revision__get_number(revision_id) || '' of '' || (select count(*) from cr_revisions where item_id = r.item_id) || '' for item: '' || content_item__get_title(item_id) from cr_revisions r where r.revision_id = p_revision_id; end;' language 'plpgsql' stable strict; -- procedure to_html select define_function_args('content_revision__to_html','revision_id'); create or replace function content_revision__to_html (integer) returns integer as ' declare to_html__revision_id alias for $1; tmp_clob text; blob_loc integer; begin -- FIXME -- ctx_doc.filter(''cr_doc_filter_index'', revision_id, tmp_clob); select content into blob_loc from cr_revisions where revision_id = to_html__revision_id for update; PERFORM clob_to_blob(tmp_clob, blob_loc); PERFORM dbms_lob__freetemporary(tmp_clob); return 0; end;' language 'plpgsql'; -- function is_live select define_function_args('content_revision__is_live','revision_id'); create or replace function content_revision__is_live (integer) returns boolean as ' declare is_live__revision_id alias for $1; begin return count(*) > 0 from cr_items where live_revision = is_live__revision_id; end;' language 'plpgsql' strict; -- function is_latest select define_function_args('content_revision__is_latest','revision_id'); create or replace function content_revision__is_latest (integer) returns boolean as ' declare is_latest__revision_id alias for $1; begin return count(*) > 0 from cr_items where latest_revision = is_latest__revision_id; end;' language 'plpgsql' stable; -- procedure to_temporary_clob create or replace function content_revision__to_temporary_clob (integer) returns integer as ' declare to_temporary_clob__revision_id alias for $1; -- b blob; -- c text; begin -- FIXME: I cannot find an instance in the 4.2 beta code where this -- is used so I am not worrying about porting it for now. -- DCW - 2001-03-28. raise EXCEPTION ''not implemented content_revision.to_temporary_clob''; /* insert into cr_content_text ( revision_id, content ) values ( revision_id, empty_clob() ) returning content into c; select content into b from cr_revisions where revision_id = to_temporary_clob__revision_id; PERFORM blob_to_clob(b, c); */ return 0; end;' language 'plpgsql'; -- procedure content_copy select define_function_args('content_revision__content_copy','revision_id,revision_id_dest'); create or replace function content_revision__content_copy (integer,integer) returns integer as ' declare content_copy__revision_id alias for $1; content_copy__revision_id_dest alias for $2; -- default null v_item_id cr_items.item_id%TYPE; v_content_length cr_revisions.content_length%TYPE; v_revision_id_dest cr_revisions.revision_id%TYPE; v_content cr_revisions.content%TYPE; v_lob cr_revisions.lob%TYPE; v_new_lob cr_revisions.lob%TYPE; v_storage_type varchar; begin if content_copy__revision_id is null then raise exception ''content_revision__content_copy attempt to copy a null revision_id''; end if; select content_length, item_id into v_content_length, v_item_id from cr_revisions where revision_id = content_copy__revision_id; -- get the destination revision if content_copy__revision_id_dest is null then select latest_revision into v_revision_id_dest from cr_items where item_id = v_item_id; else v_revision_id_dest := content_copy__revision_id_dest; end if; -- only copy the content if the source content is not null if v_content_length is not null and v_content_length > 0 then /* The internal LOB types - BLOB, CLOB, and NCLOB - use copy semantics, as opposed to the reference semantics which apply to BFILEs. When a BLOB, CLOB, or NCLOB is copied from one row to another row in the same table or in a different table, the actual LOB value is copied, not just the LOB locator. */ select r.content, r.content_length, r.lob, i.storage_type into v_content, v_content_length, v_lob, v_storage_type from cr_revisions r, cr_items i where r.item_id = i.item_id and r.revision_id = content_copy__revision_id; if v_storage_type = ''lob'' then v_new_lob := empty_lob(); PERFORM lob_copy(v_lob, v_new_lob); update cr_revisions set content = null, content_length = v_content_length, lob = v_new_lob where revision_id = v_revision_id_dest; -- this call has to be before the above instruction, -- because lob references the v_new_lob -- PERFORM lob_copy(v_lob, v_new_lob); else -- this will work for both file and text types... well sort of. -- this really just creates a reference to the first file which is -- wrong since, the item_id, revision_id uniquely describes the -- location of the file in the content repository file system. -- after copy is called, the content attribute needs to be updated -- with the new relative file path: -- update cr_revisions -- set content = ''[cr_create_content_file $item_id $revision_id [cr_fs_path]$old_rel_path]'' -- where revision_id = :revision_id -- old_rel_path is the content attribute value of the content revision -- that is being copied. update cr_revisions set content = v_content, content_length = v_content_length, lob = null where revision_id = v_revision_id_dest; end if; end if; return 0; end;' language 'plpgsql'; -- procedure content__get_content select define_function_args('content_revision__get_content','revision_id'); create or replace function content_revision__get_content (integer) returns text as ' declare get_content__revision_id alias for $1; v_storage_type varchar; v_lob_id integer; v_data text; begin select i.storage_type, r.lob into v_storage_type, v_lob_id from cr_items i, cr_revisions r where i.item_id = r.item_id and r.revision_id = get_content__revision_id; if v_storage_type = ''lob'' then return v_lob_id::text; else return content from cr_revisions where revision_id = get_content__revision_id; end if; end;' language 'plpgsql' stable strict; -- show errors -- Trigger to maintain latest_revision in cr_items create function cr_revision_latest_tr () returns opaque as ' begin update cr_items set latest_revision = new.revision_id where item_id = new.item_id; return new; end;' language 'plpgsql'; create trigger cr_revision_latest_tr after insert on cr_revisions for each row execute procedure cr_revision_latest_tr (); -- show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-perms.sql0000644000175000017500000003420507626066763027553 0ustar frankiefrankie-------------------------------------------------------------- -- -- Set up the basic permissions used by the CMS, and invent some -- api in dealing with them -- -------------------------------------------------------------- create function inline_0 () returns integer as ' declare found_p boolean; begin select count(*) > 0 into found_p from dual where exists (select 1 from acs_privileges where privilege = ''cm_root''); if NOT found_p then -- Dummy root privilege PERFORM acs_privilege__create_privilege(''cm_root'', ''Root'', ''Root''); -- He can do everything PERFORM acs_privilege__create_privilege(''cm_admin'', ''Administrator'', ''Administrators''); PERFORM acs_privilege__create_privilege(''cm_write'', ''Write'', ''Write''); PERFORM acs_privilege__create_privilege(''cm_new'', ''Create New Item'', ''Create New Item''); PERFORM acs_privilege__create_privilege(''cm_examine'', ''Admin-level Read'', ''Admin-level Read''); PERFORM acs_privilege__create_privilege(''cm_read'', ''User-level Read'', ''User-level Read''); PERFORM acs_privilege__create_privilege(''cm_item_workflow'', ''Modify Workflow'', ''Modify Workflow''); PERFORM acs_privilege__create_privilege(''cm_perm_admin'', ''Modify Any Permissions'', ''Modify Any Permissions''); PERFORM acs_privilege__create_privilege(''cm_perm'', ''Donate Permissions'', ''Donate Permissions''); PERFORM acs_privilege__add_child(''cm_root'', ''cm_admin''); -- Do anything to an object PERFORM acs_privilege__add_child(''cm_admin'', ''cm_write''); -- Do anything to an object PERFORM acs_privilege__add_child(''cm_write'', ''cm_new''); -- Create subitems PERFORM acs_privilege__add_child(''cm_new'', ''cm_examine''); -- View in admin mode PERFORM acs_privilege__add_child(''cm_examine'', ''cm_read''); -- View in user mode PERFORM acs_privilege__add_child(''cm_write'', ''cm_item_workflow''); -- Change item workflow PERFORM acs_privilege__add_child(''cm_admin'', ''cm_perm_admin''); -- Modify any permissions PERFORM acs_privilege__add_child(''cm_perm_admin'', ''cm_perm''); -- Modify any permissions on an item -- Proper inheritance PERFORM acs_privilege__add_child(''admin'', ''cm_root''); end if; return 0; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); -- create or replace package body content_permission -- procedure inherit_permissions create function content_permission__inherit_permissions (integer,integer,integer) returns integer as ' declare inherit_permissions__parent_object_id alias for $1; inherit_permissions__child_object_id alias for $2; inherit_permissions__child_creator_id alias for $3; -- default null v_dummy integer; begin -- Determine if the child is a direct descendant of the -- parent select 1 into v_dummy from acs_objects where object_id = inherit_permissions__child_object_id and context_id = inherit_permissions__parent_object_id; if NOT FOUND then raise EXCEPTION ''-20000: Child object is not actually a child of the parent object in inherit_permissions''; end if; -- Copy everything one level down insert into acs_permissions select inherit_permissions__child_object_id as object_id, grantee_id, privilege from acs_permissions where object_id = inherit_permissions__parent_object_id; if inherit_permissions__child_creator_id is not null then -- Grant cm_write and cm_perm to the child creator if content_permission__permission_p ( inherit_permissions__child_object_id, inherit_permissions__child_creator_id, ''cm_perm'' ) != ''t'' then -- Turn off inheritance and grant permission update acs_objects set security_inherit_p = ''f'' where object_id = inherit_permissions__child_object_id; PERFORM acs_permission__grant_permission ( inherit_permissions__child_object_id, inherit_permissions__child_creator_id, ''cm_perm'' ); end if; if content_permission__permission_p ( inherit_permissions__child_object_id, inherit_permissions__child_creator_id, ''cm_write'' ) != ''t'' then PERFORM acs_permission__grant_permission ( inherit_permissions__child_object_id, inherit_permissions__child_creator_id, ''cm_write'' ); end if; end if; return 0; end;' language 'plpgsql'; -- function has_grant_authority create function content_permission__has_grant_authority (integer,integer,varchar) returns boolean as ' declare object_id alias for $1; holder_id alias for $2; privilege alias for $3; begin -- Can donate permission only if you already have it and you have cm_perm, -- OR you have cm_perm_admin if content_permission__permission_p (object_id, holder_id, ''cm_perm_admin'')= ''t'' or ( content_permission__permission_p (object_id, holder_id, ''cm_perm'') = ''t'' and content_permission__permission_p (object_id, holder_id, privilege) = ''t'' ) then return ''t''; else return ''f''; end if; end;' language 'plpgsql'; -- function has_revoke_authority create function content_permission__has_revoke_authority (integer,integer,varchar,integer) returns boolean as ' declare has_revoke_authority__object_id alias for $1; has_revoke_authority__holder_id alias for $2; has_revoke_authority__privilege alias for $3; has_revoke_authority__revokee_id alias for $4; begin -- DRB: Note that the privilege selection doesn't use the slick tree_ancestor_keys -- trick. There are two reasons for this. The first is that we might have a set of -- tree_sortkeys returned from the acs_privilege_hierarchy_index when child_privilege -- is ''cm_perm''. The second is that this table is relatively small anyway and the -- old style's probably just as efficient as the first as an index scan is only preferred -- by the Postgres optimizer when it will significantly reduce the number of rows scanned. -- DanW: Removed hierarchy index query in favor of using descendant map. return exists (select 1 from (select o2.object_id from (select tree_ancestor_keys(acs_object__get_tree_sortkey(has_revoke_authority__object_id)) as tree_sortkey) parents, acs_objects o2 where o2.tree_sortkey = parents.tree_sortkey) t (select privilege, descendant as child_privilege from acs_privilege_descendant_map where descendant = 'cm_perm') h where content_permission__permission_p( t.object_id, has_revoke_authority__holder_id, h.child_privilege ) and not content_permission__permission_p( t.object_id, has_revoke_authority__revokee_id, h.privilege )); end;' language 'plpgsql'; -- procedure grant_permission_h create function content_permission__grant_permission_h (integer,integer,varchar) returns integer as ' declare grant_permission_h__object_id alias for $1; grant_permission_h__grantee_id alias for $2; grant_permission_h__privilege alias for $3; v_privilege acs_privilege_descendant_map.privilege%TYPE; v_rec record; begin -- If the permission is already granted, do nothing if content_permission__permission_p ( grant_permission_h__object_id, grant_permission_h__grantee_id, grant_permission_h__privilege ) = ''t'' then return null; end if; -- Grant the parent, make sure there is no inheritance update acs_objects set security_inherit_p = ''f'' where object_id = grant_permission_h__object_id; PERFORM acs_permission__grant_permission(grant_permission_h__object_id, grant_permission_h__grantee_id, grant_permission_h__privilege); -- Revoke the children - they are no longer relevant for v_rec in select descendant from acs_privilege_descendant_map where privilege = grant_permission_h__privilege and descendant <> grant_permission_h__privilege; LOOP PERFORM acs_permission__revoke_permission( grant_permission_h__object_id, grant_permission_h__grantee_id, v_rec.descendant ); end LOOP; return 0; end;' language 'plpgsql'; -- procedure grant_permission create function content_permission__grant_permission (integer,integer,varchar,integer,boolean,varchar) returns integer as ' declare grant_permission__object_id alias for $1; grant_permission__holder_id alias for $2; grant_permission__privilege alias for $3; grant_permission__recepient_id alias for $4; grant_permission__is_recursive alias for $5; -- default ''f'' grant_permission__object_type alias for $6; -- default ''content_item'' v_object_id acs_objects.object_id%TYPE; begin -- select -- o.object_id -- from -- (select object_id, object_type from acs_objects -- connect by context_id = prior object_id -- start with object_id = grant_permission__object_id) o -- where -- content_permission__has_grant_authority ( -- o.object_id, holder_id, grant_permission__privilege -- ) = ''t'' -- and -- content_item__is_subclass (o.object_type, grant_permission__object_type) = ''t'' for v_rec in select o.object_id from (select o1.object_id, o1.object_type from acs_objects o1, acs_objects o2 where o2.object_id = grant_permission__object_id and o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)) o where content_permission__has_grant_authority (o.object_id, holder_id, grant_permission__privilege) and content_item__is_subclass (o.object_type, grant_permission__object_type) LOOP -- Grant the parent and revoke the children, since we do not need them -- anymore PERFORM content_permission__grant_permission_h ( v_rec.object_id, grant_permission__recepient_id, grant_permission__privilege ); exit when grant_permission__is_recursive = ''f''; end loop; return 0; end;' language 'plpgsql'; -- procedure revoke_permission_h create function content_permission__revoke_permission_h (integer,integer,varchar) returns integer as ' declare revoke_permission_h__object_id alias for $1; revoke_permission_h__revokee_id alias for $2; revoke_permission_h__privilege alias for $3; v_rec record; begin -- Grant all child privileges of the parent privilege for v_rec in select child_privilege from acs_privilege_hierarchy where privilege = revoke_permission_h__privilege LOOP PERFORM acs_permission__grant_permission ( revoke_permission_h__object_id, revoke_permission_h__revokee_id, v_rec.child_privilege ); end loop; -- Revoke the parent privilege PERFORM acs_permission__revoke_permission ( revoke_permission_h__object_id, revoke_permission_h__revokee_id, revoke_permission_h__privilege ); return 0; end;' language 'plpgsql'; -- procedure revoke_permission create function content_permission__revoke_permission (integer,integer,varchar,integer,boolean,varchar) returns integer as ' declare revoke_permission__object_id alias for $1; revoke_permission__holder_id alias for $2; revoke_permission__privilege alias for $3; revoke_permission__revokee_id alias for $4; revoke_permission__is_recursive alias for $5; -- default ''f'' revoke_permission__object_type alias for $6; -- default ''content_item'' v_rec record; begin -- select object_id, object_type from acs_objects -- connect by context_id = prior object_id -- start with object_id = revoke_permission__object_id for v_rec in select o.object_id from (select o1.object_id, o1.object_type from acs_objects o1, acs_objects o2 where o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey) and o2.object_id = revoke_permission__object_id) o where content_permission__has_revoke_authority (o.object_id, revoke_permission__holder_id, revoke_permission__privilege, revoke_permission__revokee_id) = ''t'' and content_item__is_subclass(o.object_type, revoke_permission__object_type) = ''t'' LOOP PERFORM content_permission__revoke_permission_h ( v_rec.object_id, revoke_permission__revokee_id, revoke_permission__privilege ); exit when revoke_permission__is_recursive = ''f''; end loop; return 0; end;' language 'plpgsql'; -- function permission_p create function content_permission__permission_p (integer,integer,varchar) returns boolean as ' declare object_id alias for $1; holder_id alias for $2; privilege alias for $3; begin return acs_permission__permission_p (object_id, holder_id, privilege); end;' language 'plpgsql'; -- Determine if the CMS admin exists create function cm_admin_exists () returns boolean as ' begin return count(*) > 0 from dual where exists ( select 1 from acs_permissions where privilege in (''cm_admin'', ''cm_root'') ); end;' language 'plpgsql'; -- show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-symlink.sql0000644000175000017500000002467210440426443030101 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-symlink.sql,v 1.20 2006/06/04 00:45:23 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- create or replace package body content_symlink -- function new select define_function_args('content_symlink__new','name,label,target_id,parent_id,symlink_id,creation_date;now,creation_user,creation_ip,package_id'); create or replace function content_symlink__new (varchar,varchar,integer,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__name alias for $1; -- default null new__label alias for $2; -- default null new__target_id alias for $3; new__parent_id alias for $4; new__symlink_id alias for $5; -- default null new__creation_date alias for $6; -- default now() new__creation_user alias for $7; -- default null new__creation_ip alias for $8; -- default null new__package_id alias for $9; -- default null v_symlink_id cr_symlinks.symlink_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_name cr_items.name%TYPE; v_label cr_symlinks.label%TYPE; v_ctype varchar; begin -- SOME CHECKS -- -- 1) check that the target is now a symlink if content_symlink__is_symlink(new__target_id) = ''t'' then raise EXCEPTION ''-20000: Cannot create a symlink to a symlink %'', new__target_id; end if; -- 2) check that the parent is a folder if content_folder__is_folder(new__parent_id) = ''f'' then raise EXCEPTION ''-20000: The parent is not a folder''; end if; -- 3) check that parent folder supports symlinks if content_folder__is_registered(new__parent_id,''content_symlink'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow symlinks to be created''; end if; -- 4) check that the content folder supports the target items content type if content_folder__is_registered(new__parent_id, content_item__get_content_type(new__target_id), ''f'') = ''f'' then v_ctype := content_item__get_content_type(new__target_id); raise EXCEPTION ''-20000: This folder does not allow symlinks to items of type % to be created'', v_ctype; end if; -- PASSED ALL CHECKS -- -- Select default name if the name is null if new__name is null or new__name = '''' then select ''symlink_to_'' || name into v_name from cr_items where item_id = new__target_id; if NOT FOUND then v_name := null; end if; else v_name := new__name; end if; -- Select default label if the label is null if new__label is null then v_label := ''Symlink to '' || v_name; else v_label := new__label; end if; if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_symlink_id := content_item__new( v_name, new__parent_id, new__symlink_id, null, new__creation_date, new__creation_user, null, new__creation_ip, ''content_item'', ''content_symlink'', null, null, ''text/plain'', null, null, ''text'', v_package_id ); insert into cr_symlinks (symlink_id, target_id, label) values (v_symlink_id, new__target_id, v_label); update acs_objects set title = v_label where object_id = v_symlink_id; return v_symlink_id; end;' language 'plpgsql'; create or replace function content_symlink__new (varchar,varchar,integer,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__name alias for $1; -- default null new__label alias for $2; -- default null new__target_id alias for $3; new__parent_id alias for $4; new__symlink_id alias for $5; -- default null new__creation_date alias for $6; -- default now() new__creation_user alias for $7; -- default null new__creation_ip alias for $8; -- default null begin return content_extlink__new(new__name, new__label, new__target_id, new__parent_id, new__symlink_id, new__creation_date, new__creation_user, new__creation_ip, null ); end;' language 'plpgsql'; -- procedure delete select define_function_args('content_symlink__delete','symlink_id'); create or replace function content_symlink__delete (integer) returns integer as ' declare delete__symlink_id alias for $1; begin PERFORM content_symlink__del(delete__symlink_id); return 0; end;' language 'plpgsql'; select define_function_args('content_symlink__del','symlink_id'); create or replace function content_symlink__del (integer) returns integer as ' declare del__symlink_id alias for $1; begin delete from cr_symlinks where symlink_id = del__symlink_id; PERFORM content_item__delete(del__symlink_id); return 0; end;' language 'plpgsql'; -- function is_symlink select define_function_args('content_symlink__is_symlink','item_id'); create or replace function content_symlink__is_symlink (integer) returns boolean as ' declare is_symlink__item_id alias for $1; v_symlink_p boolean; begin select count(*) = 1 into v_symlink_p from cr_symlinks where symlink_id = is_symlink__item_id; return v_symlink_p; end;' language 'plpgsql' stable; -- procedure copy select define_function_args('content_symlink__copy','symlink_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_symlink__copy ( integer, integer, integer, varchar, varchar) returns integer as ' declare copy__symlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_target_id cr_items.item_id%TYPE; v_label cr_symlinks.label%TYPE; v_symlink_id cr_symlinks.symlink_id%TYPE; begin -- XXX: bug if target is not a folder this will silently fail. if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__symlink_id; -- can''t copy to the same folder unless name is different select i.name, content_symlink__resolve(i.item_id), s.label into v_name, v_target_id, v_label from cr_symlinks s, cr_items i where s.symlink_id = i.item_id and s.symlink_id = copy__symlink_id; -- copy to a different folder, or same folder if name -- is different if copy__target_folder_id != v_current_folder_id or ( v_name <> copy_name and copy_name is not null ) then if content_folder__is_registered(copy__target_folder_id, ''content_symlink'',''f'') = ''t'' then if content_folder__is_registered(copy__target_folder_id, content_item__get_content_type(content_symlink__resolve(copy__symlink_id)),''f'') = ''t'' then v_symlink_id := content_symlink__new( coalesce (copy__name,v_name), v_label, v_target_id, copy__target_folder_id, null, now(), copy__creation_user, copy__creation_ip, null ); end if; end if; end if; end if; return v_symlink_id; end;' language 'plpgsql'; create or replace function content_symlink__copy ( integer, integer, integer, varchar) returns integer as ' declare copy__symlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_target_id cr_items.item_id%TYPE; v_label cr_symlinks.label%TYPE; v_symlink_id cr_symlinks.symlink_id%TYPE; begin v_symlink_id := content_symlink__copy ( copy__symlink_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, NULL ); return v_symlink_id; end;' language 'plpgsql'; -- function resolve select define_function_args('content_symlink__resolve','item_id'); create or replace function content_symlink__resolve (integer) returns integer as ' declare resolve__item_id alias for $1; v_target_id cr_items.item_id%TYPE; begin select target_id into v_target_id from cr_symlinks where symlink_id = resolve__item_id; if NOT FOUND then return resolve__item_id; else return v_target_id; end if; end;' language 'plpgsql' stable strict; -- function resolve_content_type select define_function_args('content_symlink__resolve_content_type','item_id'); create or replace function content_symlink__resolve_content_type (integer) returns varchar as ' declare resolve_content_type__item_id alias for $1; v_content_type cr_items.content_type%TYPE; begin select content_item__get_content_type(target_id) into v_content_type from cr_symlinks where symlink_id = resolve_content_type__item_id; return v_content_type; end;' language 'plpgsql' stable strict; -- show errors -- Convenience view to simply access to symlink targets create view cr_resolved_items as select i.parent_id, i.item_id, i.name, case when s.target_id is NULL then 'f' else 't' end as is_symlink, coalesce(s.target_id, i.item_id) as resolved_id, s.label from cr_items i left outer join cr_symlinks s on (i.item_id = s.symlink_id); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/types-create.sql0000644000175000017500000002145511562016155027345 0ustar frankiefrankie-- Object type declarations to support content repository of the -- ArsDigita Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: types-create.sql,v 1.7.2.2 2011/05/09 16:55:09 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- Define content items. Also the supertype for folders, symlinks and extlinks. begin; select acs_object_type__create_type ( 'content_item', 'Content Item', 'Content Items', 'acs_object', 'cr_items', 'item_id', null, 'f', null, 'content_item.get_title' ); select acs_attribute__create_attribute ( 'content_item', 'name', 'keyword', 'Name', 'Names', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'content_item', 'locale', 'keyword', 'Locale', 'Locales', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'content_item', 'live_revision', 'integer', 'Live Revision', 'Live Revisions', null, null, null, 1, 1, null, 'type_specific', 'f' ); end; -- Define content folders. A folder is equivalent to a directory in -- the file system. It is used for grouping content items that have -- public URL's. begin; select acs_object_type__create_type ( 'content_folder', 'Content Folder', 'Content Folders', 'content_item', 'cr_folders', 'folder_id', null, 'f', null, 'content_folder.get_label' ); select acs_attribute__create_attribute ( 'content_folder', 'label', 'string', 'Label', 'Labels', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'content_folder', 'description', 'string', 'Description', 'Descriptions', null, null, null, 1, 1, null, 'type_specific', 'f' ); end; -- Define content keywords begin; select acs_object_type__create_type ( 'content_keyword', 'Content Keyword', 'Content Keywords', 'acs_object', 'cr_keywords', 'keyword_id', null, 'f', null, 'acs_object.default_name' ); select acs_attribute__create_attribute ( 'content_keyword', 'heading', 'string', 'Heading', 'Headings', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'content_keyword', 'description', 'string', 'Description', 'Descriptions', null, null, null, 1, 1, null, 'type_specific', 'f' ); end; -- Symlinks are represented by a subclass of content_item (content_link) -- Each symlink thus has a row in the acs_objects table. Each symlink -- also has a row in the cr_items table. The name column for the symlink -- is the name that appears in the path to the symlink. begin; select acs_object_type__create_type ( 'content_symlink', 'Content Symlink', 'Content Symlinks', 'content_item', 'cr_symlinks', 'symlink_id', null, 'f', null, 'acs_object.default_name' ); select acs_attribute__create_attribute ( 'content_symlink', 'target_id', 'integer', 'Target ID', 'Target IDs', null, null, null, 1, 1, null, 'type_specific', 'f' ); end; -- Extlinks are links to external content (offsite URL's) begin; select acs_object_type__create_type ( 'content_extlink', 'External Link', 'External Links', 'content_item', 'cr_extlinks', 'extlink_id', null, 'f', null, 'acs_object.default_name' ); select acs_attribute__create_attribute ( 'content_extlink', 'url', 'text', 'URL', 'URLs', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'content_extlink', 'label', 'text', 'Label', 'Labels', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'content_extlink', 'description', 'text', 'Description', 'Descriptions', null, null, null, 1, 1, null, 'type_specific', 'f' ); end; -- Define content templates. begin; select acs_object_type__create_type ( 'content_template', 'Content Template', 'Content Templates', 'content_item', 'cr_templates', 'template_id', null, 'f', null, 'acs_object.default_name' ); end; -- Define content revisions, children of content items begin; select content_type__create_type ( 'content_revision', 'acs_object', 'Basic Item', 'Basic Items', 'cr_revisions', 'revision_id', 'content_revision.revision_name' ); select content_type__create_attribute ( 'content_revision', 'title', 'text', 'Title', 'Titles', 1, null, 'text' ); select content_type__create_attribute ( 'content_revision', 'description', 'text', 'Description', 'Descriptions', 2, null, 'text' ); select content_type__create_attribute ( 'content_revision', 'publish_date', 'date', 'Publish Date', 'Publish Dates', 3, null, 'text' ); select content_type__create_attribute ( 'content_revision', 'mime_type', 'text', 'Mime Type', 'Mime Types', 4, null, 'text' ); select content_type__create_attribute ( 'content_revision', 'nls_language', 'text', 'Language', 'Language', null, null, 'text' ); select content_type__create_attribute ( 'content_revision', 'item_id', 'integer', 'Item id', 'Item ids', null, null, 'integer' ); select content_type__create_attribute ( 'content_revision', 'content', 'text', 'Content', 'Content', null, null, 'text' ); end; -- Declare standard relationships with children and other items begin; select acs_object_type__create_type ( 'cr_item_child_rel', 'Child Item', 'Child Items', 'acs_object', 'cr_child_rels', 'rel_id', null, 'f', null, 'acs_object.default_name' ); select acs_attribute__create_attribute ( 'cr_item_child_rel', 'parent_id', 'integer', 'Parent ID', 'Parent IDs', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'cr_item_child_rel', 'child_id', 'integer', 'Child ID', 'Child IDs', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'cr_item_child_rel', 'relation_tag', 'text', 'Relationship Tag', 'Relationship Tags', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'cr_item_child_rel', 'order_n', 'integer', 'Sort Order', 'Sort Orders', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_object_type__create_type ( 'cr_item_rel', 'Item Relationship', 'Item Relationships', 'acs_object', 'cr_item_rels', 'rel_id', null, 'f', null, 'acs_object.default_name' ); select acs_attribute__create_attribute ( 'cr_item_rel', 'item_id', 'integer', 'Item ID', 'Item IDs', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'cr_item_rel', 'related_object_id', 'integer', 'Related Object ID', 'Related Object IDs', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'cr_item_rel', 'relation_tag', 'text', 'Relationship Tag', 'Relationship Tags', null, null, null, 1, 1, null, 'type_specific', 'f' ); select acs_attribute__create_attribute ( 'cr_item_rel', 'order_n', 'integer', 'Sort Order', 'Sort Orders', null, null, null, 1, 1, null, 'type_specific', 'f' ); end; -- Refresh the attribute views -- prompt *** Refreshing content type attribute views... create function inline_0 () returns integer as ' declare type_rec record; begin -- select object_type from acs_object_types -- connect by supertype = prior object_type -- start with object_type = ''content_revision'' for type_rec in select o1.object_type from acs_object_types o1, acs_object_types o2 where o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey) and o2.object_type = ''content_revision'' LOOP PERFORM content_type__refresh_view(type_rec.object_type); end LOOP; return null; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-update.sql0000644000175000017500000001527110440426443027670 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System. This file contains DDL patches to the basic data model -- that were incorporated after the code freeze. It makes it easier for -- existing users to update their data models. -- Copyright (C) 1999-2000 ArsDigita Corporation -- Authors: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-update.sql,v 1.8 2006/06/04 00:45:23 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html --set serveroutput on -- FIXME: drop constraint doesn't work on postgresql create function inline_0 () returns integer as ' begin -- altering the constraint on cr_type_template_map raise NOTICE ''Altering constraint on cr_type_template_map...''; execute ''alter table cr_type_template_map drop constraint cr_type_template_map_pk''; execute ''alter table cr_type_template_map add constraint cr_type_template_map_pk primary key (content_type, template_id, use_context)''; execute ''VACUUM ANALYZE cr_type_template_map''; return 0; end;' language 'plpgsql'; -- select inline_0 (); drop function inline_0 (); create function inline_1 () returns integer as ' begin -- Set the workflow permission as child of admin update acs_privilege_hierarchy set privilege = ''cm_admin'' where privilege = ''cm_write'' and child_privilege = ''cm_item_workflow''; if not table_exists(''cr_doc_filter'') then raise NOTICE ''Creating CR_DOC_FILTER table for converting documents to HTML''; execute ''create table cr_doc_filter ( revision_id integer primary key, content integer )''; -- execute ''create index cr_doc_filter_index -- on cr_doc_filter ( content ) indextype is ctxsys.context -- parameters (''''FILTER content_filter_pref'''' )''; end if; if not table_exists(''cr_content_text'') then raise NOTICE ''Creating CR_CONTENT_TEXT table''; execute ''create table cr_content_text ( revision_id integer primary key, content text )''; end if; if not column_exists(''cr_folders'', ''has_child_folders'') then raise NOTICE ''Adding HAS_CHILD_FOLDERS column to CR_FOLDERS and updating the column based on selection criteria.''; execute ''create view cr_resolved_items as select i.parent_id, i.item_id, i.name, case s.target_id is NULL then \\\'\\\'f\\\'\\\' else \\\'\\\'t\\\'\\\' end as is_symlink, coalesce(s.target_id, i.item_id) resolved_id, s.label from cr_items i left outer join cr_symlinks s on i.item_id = s.symlink_id''; execute ''alter table cr_folders add has_child_folders boolean default \\\'\\\'f\\\'\\\'''; execute ''update cr_folders f set has_child_folders = coalesce((select \\\'\\\'t\\\'\\\' from dual where exists (select 1 from cr_folders f_child, cr_resolved_items r_child where r_child.parent_id = f.folder_id and f_child.folder_id = r_child.resolved_id)), \\\'\\\'f\\\'\\\')''; end if; if not column_exists(''cr_keywords'', ''parent_id'') then raise NOTICE ''Adding PARENT_ID column to CR_KEYWORDS and updating the parent id from the context id''; execute ''alter table cr_keywords add parent_id integer constraint cr_keywords_hier references cr_keywords''; execute ''update cr_keywords set parent_id = ( select context_id from acs_objects where object_id = keyword_id)''; end if; if not table_exists(''cr_text'') then raise NOTICE ''Creating CR_TEXT table for incoming text submissions...''; execute ''create table cr_text ( text text default \\\'\\\' not null )''; -- For some reason a simple insert statement throws an error but this works execute ''insert into cr_text values (NULL)''; end if; if not column_exists(''cr_items'', ''publish_status'') then raise NOTICE ''Adding PUBLISH_STATUS column to CR_ITEMS for tracking deployment status...''; execute ''alter table cr_items add publish_status varchar(40) constraint cr_items_pub_status_chk check (publish_status in (\\\'\\\'production\\\'\\\', \\\'\\\'ready\\\'\\\', \\\'\\\'live\\\'\\\', \\\'\\\'expired\\\'\\\'))''; execute ''update cr_items set publish_status = \\\'\\\'live\\\'\\\' where live_revision is not null''; execute ''alter table cr_item_publish_audit add column old_status varchar(40)''; execute ''alter table cr_item_publish_audit add column new_status varchar(40)''; end if; if not column_exists(''cr_items'', ''latest_revision'') then raise NOTICE ''Adding LATEST_REVISION column to CR_ITEMS for tracking revision status...''; execute ''alter table cr_items add latest_revision integer constraint cr_items_latest_fk references cr_revisions''; execute ''update cr_items set latest_revision = content_item__get_latest_revision(item_id)''; end if; if not table_exists(''cr_release_periods'') then raise NOTICE ''Creating CR_RELEASE_PERIODS table for scheduled publishing...''; execute '' create table cr_release_periods ( item_id integer constraint cr_release_periods_fk references cr_items constraint cr_release_periods_pk primary key, start_when timestamptz default current_timestamp, end_when timestamptz default current_timestamp + interval ''''20 years'''' )''; end if; if not table_exists(''cr_scheduled_release_log'') then raise NOTICE ''Creating CR_SCHEDULED_RELEASE_LOG table for auditing of scheduled publishing...''; execute '' create table cr_scheduled_release_log ( exec_date timestamptz default current_timestamp not null, items_released integer not null, items_expired integer not null, err_num integer, err_msg varchar(500) default \\\'\\\' not null )''; end if; if not table_exists(''cr_scheduled_release_job'') then raise NOTICE ''Creating CR_SCHEDULED_RELEASE_JOB table for tracking database job for scheduled publishing...''; execute '' create table cr_scheduled_release_job ( job_id integer, last_exec timestamptz )''; execute '' insert into cr_scheduled_release_job values (NULL, now())''; end if; return null; end;' language 'plpgsql'; -- select inline_1 (); drop function inline_1 (); -- show errors \i content-schedule.sql openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-image.sql0000644000175000017500000003415110506035457027472 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Hiro Iwashima (iwashima@mit.edu) -- $Id: content-image.sql,v 1.17 2006/09/25 20:25:19 byronl Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- This is to handle images create table images ( image_id integer constraint images_image_id_fk references cr_revisions constraint images_image_id_pk primary key, width integer, height integer ); begin; select content_type__create_type ( 'image', 'content_revision', 'Image', 'Images', 'images', 'image_id', null ); select content_type__create_attribute ( 'image', 'width', 'integer', 'Width', 'Widths', null, null, 'text' ); select content_type__create_attribute ( 'image', 'height', 'integer', 'Height', 'Heights', null, null, 'text' ); end; -- register MIME types to this content type begin; select content_type__register_mime_type( 'image', 'image/jpeg' ); select content_type__register_mime_type( 'image', 'image/gif' ); end; -- content-image.sql patch -- -- adds standard image pl/sql package -- -- Walter McGinnis (wtem@olywa.net), 2001-09-23 -- based on original photo-album package code by Tom Baginski -- /* Creates a new image Binary file stored in file-system */ -- DRB: This code has some serious problem, IMO. It's impossible to derive a new -- type from "image" and make use of it, for starters. Photo-album uses two -- content types to store a photograph - pa_photo and image. pa_photo would, in -- the world of real object-oriented languages, be derived from image and there's -- really no reason not to do so in the OpenACS object type system. The current -- style requires separate content_items and content_revisions for both the -- pa_photo extended type and the image base type. They're only tied together -- by the coincidence of both being the live revision at the same time. Delete -- one or the other and guess what, that association's broken! -- This is not, to put it mildly, clean. Nor is it efficient to fill the RDBMS -- with twice as many objects as you need... -- The Oracle version does allow a non-image type to be specified, as does my -- alternative down below. This needs a little more straightening out. -- DRB: BLOB issues make it impractical to use package_instantiate_object to create -- new revisions that contain binary data so a higher-level Tcl API is required rather -- than the standard package_instantiate_object. So we don't bother calling define_function_args -- here. create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; new__package_id alias for $17; -- default null new__locale varchar default null; new__nls_language varchar default null; new__creation_date timestamptz default current_timestamp; new__context_id integer; v_item_id cr_items.item_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin new__context_id := new__parent_id; if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_item_id := content_item__new ( new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''content_item'', ''image'', null, new__description, new__mime_type, new__nls_language, null, ''file'', -- storage_type v_package_id ); -- update cr_child_rels to have the correct relation_tag update cr_child_rels set relation_tag = new__relation_tag where parent_id = new__parent_id and child_id = new__item_id and relation_tag = content_item__get_content_type(new__parent_id) || ''-'' || ''image''; v_revision_id := content_revision__new ( new__title, new__description, new__publish_date, new__mime_type, new__nls_language, null, v_item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, new__height, new__width); -- update revision with image file info update cr_revisions set content_length = new__file_size, content = new__path where revision_id = v_revision_id; -- is_live => ''t'' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if new__is_live = ''t'' then PERFORM content_item__set_live_revision (v_revision_id); end if; return v_item_id; end; ' language 'plpgsql'; create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; begin return image__new(new__name, new__parent_id, new__item_id, new__revision_id, new__mime_type, new__creation_user, new__creation_ip, new__relation_tag, new__title, new__description, new__is_live, new__publish_date, new__path, new__file_size, new__height, new__width, null ); end; ' language 'plpgsql'; -- DRB's version create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer, integer) returns integer as ' declare p_name alias for $1; p_parent_id alias for $2; -- default null p_item_id alias for $3; -- default null p_revision_id alias for $4; -- default null p_mime_type alias for $5; -- default jpeg p_creation_user alias for $6; -- default null p_creation_ip alias for $7; -- default null p_title alias for $8; -- default null p_description alias for $9; -- default null p_storage_type alias for $10; p_content_type alias for $11; p_nls_language alias for $12; p_publish_date alias for $13; p_height alias for $14; p_width alias for $15; p_package_id alias for $16; -- default null v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if content_item__is_subclass(p_content_type, ''image'') = ''f'' then raise EXCEPTION ''-20000: image__new can only be called for an image type''; end if; if p_package_id is null then v_package_id := acs_object__package_id(p_parent_id); else v_package_id := p_package_id; end if; v_item_id := content_item__new ( p_name, p_parent_id, p_item_id, null, current_timestamp, p_creation_user, p_parent_id, p_creation_ip, ''content_item'', p_content_type, null, null, null, null, null, p_storage_type, v_package_id ); -- We will let the caller fill in the LOB data or file path. v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, v_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_item_id; end; ' language 'plpgsql'; create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer) returns integer as ' declare p_name alias for $1; p_parent_id alias for $2; -- default null p_item_id alias for $3; -- default null p_revision_id alias for $4; -- default null p_mime_type alias for $5; -- default jpeg p_creation_user alias for $6; -- default null p_creation_ip alias for $7; -- default null p_title alias for $8; -- default null p_description alias for $9; -- default null p_storage_type alias for $10; p_content_type alias for $11; p_nls_language alias for $12; p_publish_date alias for $13; p_height alias for $14; p_width alias for $15; begin return image__new(p_name, p_parent_id, p_item_id, p_revision_id, p_mime_type, p_creation_user, p_creation_ip, p_title, p_description, p_storage_type, p_content_type, p_nls_language, p_publish_date, p_height, p_width, null ); end; ' language 'plpgsql'; create or replace function image__new_revision(integer, integer, varchar, varchar, timestamptz, varchar, varchar, integer, varchar, integer, integer, integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; p_package_id alias for $12; v_revision_id integer; v_package_id acs_objects.package_id%TYPE; begin -- We will let the caller fill in the LOB data or file path. if p_package_id is null then v_package_id := acs_object__package_id(p_item_id); else v_package_id := p_package_id; end if; v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, p_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_revision_id; end;' language 'plpgsql'; create or replace function image__new_revision(integer,integer,varchar,varchar,timestamptz,varchar,varchar, integer,varchar,integer,integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; v_revision_id integer; begin return image__new_revision(p_item_id, p_revision_id, p_title, p_description, p_publish_date, p_mime_type, p_nls_language, p_creation_user, p_creation_ip, p_height, p_width, p_revision_id, null ); end;' language 'plpgsql'; create or replace function image__delete (integer) returns integer as ' declare v_item_id alias for $1; begin -- This should take care of deleting revisions, too. PERFORM content_item__delete (v_item_id); return 0; end; ' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-util.sql0000644000175000017500000000431410673474766027402 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-util.sql,v 1.8 2007/09/17 12:58:30 maltes Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create function table_exists (varchar) returns boolean as ' declare table_exists__table_name alias for $1; begin return count(*) > 0 from pg_class where relname = lower(table_exists__table_name); end;' language 'plpgsql' stable strict; create or replace function column_exists (varchar,varchar) returns boolean as ' declare column_exists__table_name alias for $1; column_exists__column_name alias for $2; begin return count(*) > 0 from pg_class c, pg_attribute a where c.relname = lower(column_exists__table_name) and c.oid = a.attrelid and a.attname = lower(column_exists__column_name); end;' language 'plpgsql' stable; create or replace function trigger_exists (varchar,varchar) returns boolean as ' declare trigger_name alias for $1; on_table alias for $2; begin return count(*) > 0 from pg_class c, pg_trigger t where c.relname = lower(on_table) and c.oid = t.tgrelid and t.tgname = lower(trigger_name); end;' language 'plpgsql' stable; create or replace function trigger_func_exists (varchar) returns boolean as ' declare trigger_name alias for $1; begin return count(*) = 1 from pg_proc where proname = lower(trigger_name) and pronargs = 0; end;' language 'plpgsql' stable; create or replace function rule_exists (varchar,varchar) returns boolean as ' declare rule_name alias for $1; table_name alias for $2; begin return count(*) = 1 from pg_rules where tablename::varchar = lower(table_name) and rulename::varchar = lower(rule_name); end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-package.sql0000644000175000017500000000230207257254311027775 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-package.sql,v 1.1 2001/03/25 02:32:41 danw Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html /* create or replace package content is procedure string_to_blob( s varchar2, blob_loc blob) as language java name 'com.arsdigita.content.Util.stringToBlob( java.lang.String, oracle.sql.BLOB )'; procedure string_to_blob_size( s varchar2, blob_loc blob, blob_size number) as language java name 'com.arsdigita.content.Util.stringToBlob( java.lang.String, oracle.sql.BLOB, int )'; function blob_to_string( blob_loc blob) return varchar2 as language java name 'com.arsdigita.content.Util.blobToString( oracle.sql.BLOB ) return java.lang.String'; procedure blob_to_file( s varchar2, blob_loc blob) as language java name 'com.arsdigita.content.Util.blobToFile( java.lang.String, oracle.sql.BLOB )'; end content; / show errors */ openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-create.sql0000644000175000017500000012052311530060570027642 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-create.sql,v 1.57 2011/02/20 00:34:00 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -------------------------------------------------------------- -- MIME TYPES -------------------------------------------------------------- -- Mime data for the following table is in mime-type-data.sql create table cr_mime_types ( label varchar(200), mime_type varchar(200) constraint cr_mime_types_mime_type_pk primary key, file_extension varchar(200) ); comment on table cr_mime_types is ' Standard MIME types recognized by the content management system. '; comment on table cr_mime_types is ' file_extension is not used to recognize MIME types, but to associate a file extension to the file after its MIME type is specified. '; -- Currently file_extension is the pk although it seems likely someone -- will want to support multiple mime types with the same extension. -- Would need UI work however create table cr_extension_mime_type_map ( extension varchar(200) constraint cr_extension_mime_type_map_pk primary key, mime_type varchar(200) constraint cr_mime_ext_map_mime_type_fk references cr_mime_types ); create index cr_extension_mime_type_map_idx on cr_extension_mime_type_map(mime_type); comment on table cr_extension_mime_type_map is ' a mapping table for extension to mime_type in db version of ns_guesstype data '; -- Load the mime type data. \i ../common/mime-type-data.sql create table cr_content_mime_type_map ( content_type varchar(100) constraint cr_content_mime_map_ctyp_fk references acs_object_types, mime_type varchar(200) constraint cr_content_mime_map_typ_fk references cr_mime_types, constraint cr_content_mime_map_pk primary key (content_type, mime_type) ); comment on table cr_content_mime_type_map is ' A mapping table that restricts the MIME types associated with a content type. '; -- RI Index -- fairly static, could probably omit this one. create index cr_cont_mimetypmap_mimetyp_idx ON cr_content_mime_type_map(mime_type); -------------------------------------------------------------- -- LOCALES -------------------------------------------------------------- create table cr_locales ( locale varchar(4) constraint cr_locales_locale_pk primary key, label varchar(200) constraint cr_locales_label_nn not null constraint cr_locales_label_un unique, nls_language varchar(30) constraint cr_locale_nls_language_nn not null, nls_territory varchar(30), nls_charset varchar(30) ); comment on table cr_locales is ' Locale definitions in Oracle consist of a language, and optionally territory and character set. (Languages are associated with default territories and character sets when not defined). The formats for numbers, currency, dates, etc. are determined by the territory. '; insert into cr_locales ( locale, label, nls_language, nls_territory, nls_charset ) values ( 'us', 'American', 'AMERICAN', 'AMERICA', 'WE8ISO8859P1' ); -------------------------------------------------------------- -- CONTENT TYPES -------------------------------------------------------------- create table cr_type_children ( parent_type varchar(100) constraint cr_type_children_parent_type_fk references acs_object_types, child_type varchar(100) constraint cr_type_children_child_type_fk references acs_object_types, relation_tag varchar(100), min_n integer, max_n integer, constraint cr_type_children_pk primary key (parent_type, child_type, relation_tag) ); comment on table cr_type_children is ' Constrains the allowable content types which a content type may contain. '; -- RI Indexes create index cr_type_children_chld_type_idx ON cr_type_children(child_type); create table cr_type_relations ( content_type varchar(100) constraint cr_type_relations_parent_fk references acs_object_types, target_type varchar(100) constraint cr_type_relations_child_fk references acs_object_types, relation_tag varchar(100), min_n integer, max_n integer, constraint cr_type_relations_pk primary key (content_type, target_type, relation_tag) ); comment on table cr_type_relations is ' Constrains the allowable object types to which a content type may relate (see above). '; -- RI Indexes create index cr_type_relations_tgt_typ_idx ON cr_type_relations(target_type); -------------------------------------------------------------- -- CONTENT ITEMS -------------------------------------------------------------- -- Define the cr_items table create table cr_items ( item_id integer constraint cr_items_item_id_fk references acs_objects on delete cascade constraint cr_items_item_id_pk primary key, parent_id integer constraint cr_items_parent_id_nn not null constraint cr_items_parent_id_fk references acs_objects on delete cascade, name varchar(400) constraint cr_items_name_nn not null, locale varchar(4) constraint cr_items_locale_fk references cr_locales, live_revision integer, latest_revision integer, publish_status varchar(40) constraint cr_items_publish_status_ck check (publish_status in ('production', 'ready', 'live', 'expired') ), content_type varchar(100) constraint cr_items_content_type_fk references acs_object_types, storage_type varchar(10) default 'text' not null constraint cr_items_storage_type_ck check (storage_type in ('lob','text','file')), storage_area_key varchar(100) default 'CR_FILES' not null, tree_sortkey varbit not null, max_child_sortkey varbit ); create index cr_items_by_locale on cr_items(locale); create index cr_items_by_content_type on cr_items(content_type); create unique index cr_items_by_live_revision on cr_items(live_revision); create unique index cr_items_by_latest_revision on cr_items(latest_revision); create unique index cr_items_unique_name on cr_items(parent_id, name); create unique index cr_items_unique_id on cr_items(parent_id, item_id); create index cr_items_by_parent_id on cr_items(parent_id); create index cr_items_name on cr_items(name); create unique index cr_items_tree_sortkey_un on cr_items(tree_sortkey); -- content-create.sql patch -- -- adds standard mechanism for deleting revisions from the file-system -- -- Walter McGinnis (wtem@olywa.net), 2001-09-23 -- based on original photo-album package code by Tom Baginski -- create table cr_files_to_delete ( path varchar(250), storage_area_key varchar(100) ); comment on table cr_files_to_delete is ' Table to store files to be deleted by a scheduled sweep. Since binaries are stored in filesystem and attributes in database, need a way to delete both atomically. So any process to delete file-system cr_revisions, copies the file path to this table as part of the delete transaction. Sweep run later to remove the files from filesystem once database info is successfully deleted. '; -- DCW, this can't be defined in the apm_package_versions table defintion, -- because cr_items is created afterwards. alter table apm_package_versions add constraint apm_package_ver_item_id_fk foreign key (item_id) references cr_items(item_id); create function cr_items_get_tree_sortkey(integer) returns varbit as ' declare p_item_id alias for $1; begin return tree_sortkey from cr_items where item_id = p_item_id; end;' language 'plpgsql' stable strict; create function cr_items_tree_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_parent_id integer default null; begin select item_id into v_parent_id from cr_items where item_id = new.parent_id; if new.parent_id = 0 then new.tree_sortkey := int_to_tree_key(new.item_id+1000); elsif v_parent_id is null then new.tree_sortkey := int_to_tree_key(new.parent_id+1000) || int_to_tree_key(new.item_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM cr_items WHERE item_id = new.parent_id FOR UPDATE; UPDATE cr_items SET max_child_sortkey = v_max_child_sortkey WHERE item_id = new.parent_id; new.tree_sortkey := v_parent_sk || v_max_child_sortkey; end if; return new; end;' language 'plpgsql'; create trigger cr_items_tree_insert_tr before insert on cr_items for each row execute procedure cr_items_tree_insert_tr (); create function cr_items_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_parent_id integer default null; v_old_parent_length integer; begin if new.item_id = old.item_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) then return new; end if; select item_id into v_parent_id from cr_items where item_id = new.parent_id; -- the tree sortkey is going to change so get the new one and update it and all its -- children to have the new prefix... v_old_parent_length := length(new.tree_sortkey) + 1; if new.parent_id = 0 then v_parent_sk := int_to_tree_key(new.item_id+1000); elsif v_parent_id is null then v_parent_sk := int_to_tree_key(new.parent_id+1000) || int_to_tree_key(new.item_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM cr_items WHERE item_id = new.parent_id FOR UPDATE; UPDATE cr_items SET max_child_sortkey = v_max_child_sortkey WHERE item_id = new.parent_id; v_parent_sk := v_parent_sk || v_max_child_sortkey; end if; UPDATE cr_items SET tree_sortkey = v_parent_sk || substring(tree_sortkey, v_old_parent_length) WHERE tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); return new; end;' language 'plpgsql'; create trigger cr_items_tree_update_tr after update on cr_items for each row execute procedure cr_items_tree_update_tr (); comment on table cr_items is ' Each content item has a row in this table, as well as a row in the acs_objects table. The parent_id is used to place an item in a directory or place it within another container item. '; comment on column cr_items.content_type is ' The content type constrains the type of revision that may be added to this item (an item should have revisions of only one type). If null, then no revisions should be allowed. '; create table cr_child_rels ( rel_id integer constraint cr_child_rels_rel_id_pk primary key constraint cr_child_rels_rel_id_fk references acs_objects, parent_id integer constraint cr_child_rels_parent_id_nn not null, child_id integer constraint cr_child_rels_child_id_nn not null, relation_tag varchar(100), order_n integer ); create index cr_child_rels_by_parent on cr_child_rels(parent_id); create unique index cr_child_rels_unq_id on cr_child_rels(parent_id, child_id); CREATE UNIQUE INDEX CR_CHILD_RELS_kids_IDx ON CR_CHILD_RELS(CHILD_ID); comment on table cr_child_rels is ' Provides for richer parent-child relationships than the simple link encapsulated in the primary table. May be subclassed to provide additional attributes. '; create table cr_item_rels ( rel_id integer constraint cr_item_rels_rel_id_pk primary key constraint cr_item_rels_rel_id_fk references acs_objects, item_id integer constraint cr_item_rels_item_id_fk references cr_items, related_object_id integer constraint cr_item_rels_rel_obj_fk references acs_objects, relation_tag varchar(100), order_n integer ); create unique index cr_item_rel_unq on cr_item_rels ( item_id, related_object_id, relation_tag ); -- RI Indexes create index cr_item_rels_rel_obj_id_idx ON cr_item_rels(related_object_id); comment on table cr_item_rels is ' Describes all relations from one item to any number of other objects. '; comment on column cr_item_rels.relation_tag is ' A token for lightweight classification of item relationships. If additional attributes are required, then a subtype of item_rel may be created. '; comment on column cr_item_rels.order_n is ' Optional column for specifying a sort order. Note that the ordering method is application-dependent (it may be by relation type or across multiple relation types). '; -------------------------------------------------------------- -- CONTENT REVISIONS -------------------------------------------------------------- -- Define the cr_revisions table create table cr_revisions ( revision_id integer constraint cr_revisions_revision_id_fk references acs_objects (object_id) on delete cascade constraint cr_revisions_revision_id_pk primary key, item_id integer constraint cr_revisions_item_id_nn not null constraint cr_revisions_item_id_fk references cr_items on delete cascade, title varchar(1000), description text, publish_date timestamptz, mime_type varchar(200) default 'text/plain' constraint cr_revisions_mime_type_fk references cr_mime_types, nls_language varchar(50), -- lob_id if storage_type = lob. lob integer constraint cr_revisions_lob_fk references lobs on delete set null, -- content holds the file name if storage type = file -- otherwise it holds the text data if storage_type = text. content text, content_length integer ); -- RI Indexes create index cr_revisions_lob_idx ON cr_revisions(lob); create index cr_revisions_item_id_idx ON cr_revisions(item_id); create trigger cr_revisions_lob_trig before delete or update or insert on cr_revisions for each row execute procedure on_lob_ref(); create index cr_revisions_by_mime_type on cr_revisions(mime_type); create index cr_revisions_title_idx on cr_revisions(title); create index cr_revisions_publish_date_idx on cr_revisions(publish_date); -- create index cr_revisions_lower_title_idx on cr_revisions(lower(title)); -- create index cr_revisions_title_ltr_idx on cr_revisions(substr(lower(title), 1, 1)); comment on table cr_revisions is ' Each content item may be associated with any number of revisions. The item_id is used to associate revisions with an item. '; comment on column cr_revisions.nls_language is ' NLS_LANGUAGE is required in the same table as the content column for multi-lingual searching in Intermedia. '; -- postgresql RI bug causes multiple failures with regards to deletion of -- content_revisions (DanW dcwickstrom@earthlink.net) -- alter table cr_items add constraint cr_items_live_fk -- foreign key (live_revision) references cr_revisions(revision_id); -- alter table cr_items add constraint cr_items_latest_fk -- foreign key (latest_revision) references cr_revisions(revision_id); create function cr_revision_del_ri_trg() returns opaque as ' declare dummy integer; v_latest integer; v_live integer; begin select 1 into dummy from cr_revisions where revision_id = old.live_revision; if FOUND then raise EXCEPTION ''Referential Integrity: live_revision still exists: %'', old.live_revision; end if; select 1 into dummy from cr_revisions where revision_id = old.latest_revision; if FOUND then raise EXCEPTION ''Referential Integrity: latest_revision still exists: %'', old.latest_revision; end if; return old; end;' language 'plpgsql'; create function cr_revision_ins_ri_trg() returns opaque as ' declare dummy integer; v_latest integer; v_live integer; begin select 1 into dummy from cr_revisions where revision_id = new.live_revision; if NOT FOUND and new.live_revision is NOT NULL then raise EXCEPTION ''Referential Integrity: live_revision does not exist: %'', new.live_revision; end if; select 1 into dummy from cr_revisions where revision_id = new.latest_revision; if NOT FOUND and new.latest_revision is NOT NULL then raise EXCEPTION ''Referential Integrity: latest_revision does not exist: %'', new.latest_revision; end if; return new; end;' language 'plpgsql'; create function cr_revision_up_ri_trg() returns opaque as ' declare dummy integer; v_latest integer; v_live integer; begin select 1 into dummy from cr_revisions where revision_id = new.live_revision; if NOT FOUND and new.live_revision <> old.live_revision and new.live_revision is NOT NULL then raise EXCEPTION ''Referential Integrity: live_revision does not exist: %'', new.live_revision; end if; select 1 into dummy from cr_revisions where revision_id = new.latest_revision; if NOT FOUND and new.latest_revision <> old.latest_revision and new.latest_revision is NOT NULL then raise EXCEPTION ''Referential Integrity: latest_revision does not exist: %'', new.latest_revision; end if; return new; end;' language 'plpgsql'; create function cr_revision_del_rev_ri_trg() returns opaque as ' declare dummy integer; begin select 1 into dummy from cr_items where item_id = old.item_id and live_revision = old.revision_id; if FOUND then raise EXCEPTION ''Referential Integrity: attempting to delete live_revision: %'', old.revision_id; end if; select 1 into dummy from cr_items where item_id = old.item_id and latest_revision = old.revision_id; if FOUND then raise EXCEPTION ''Referential Integrity: attempting to delete latest_revision: %'', old.revision_id; end if; return old; end;' language 'plpgsql'; -- reimplementation of RI triggers. (DanW dcwickstrom@earthlink.net) create trigger cr_revision_del_ri_trg after delete on cr_items for each row execute procedure cr_revision_del_ri_trg(); create trigger cr_revision_up_ri_trg after update on cr_items for each row execute procedure cr_revision_up_ri_trg(); create trigger cr_revision_ins_ri_trg after insert on cr_items for each row execute procedure cr_revision_ins_ri_trg(); create trigger cr_revision_del_rev_ri_trg after delete on cr_revisions for each row execute procedure cr_revision_del_rev_ri_trg(); -- (DanW - OpenACS) Added cleanup trigger to log file items that need -- to be cleaned up from the CR. create function cr_cleanup_cr_files_del_trg() returns opaque as ' declare begin insert into cr_files_to_delete select r.content as path, i.storage_area_key from cr_items i, cr_revisions r where i.item_id = r.item_id and r.revision_id = old.revision_id and i.storage_type = ''file''; return old; end;' language 'plpgsql'; create trigger cr_cleanup_cr_files_del_trg before delete on cr_revisions for each row execute procedure cr_cleanup_cr_files_del_trg(); create table cr_revision_attributes ( revision_id integer constraint cr_revision_attributes_pk primary key constraint cr_revision_attributes_fk references cr_revisions, attributes text ); comment on column cr_revision_attributes.attributes is ' An XML document representing the compiled attributes for a revision '; -- create global temporary table cr_content_text ( -- revision_id integer primary key, -- content CLOB -- ) on commit delete rows; create table cr_content_text ( revision_id integer constraint cr_content_text_revision_id_pk primary key, content integer ); comment on table cr_content_text is ' A temporary table for holding text extracted from the content blob. Provides a workaround for the fact that blob_to_string(content) has 4000 character limit. '; -------------------------------------------------------------- -- CONTENT PUBLISHING -------------------------------------------------------------- create table cr_item_publish_audit ( item_id integer, old_revision integer, new_revision integer, old_status varchar(40), new_status varchar(40), publish_date timestamptz constraint cr_item_publish_audit_date_nn not null ); create index cr_item_publish_audit_idx on cr_item_publish_audit(item_id); comment on table cr_item_publish_audit is ' An audit table (populated by a trigger on cr_items.live_revision) that is used to keep track of the publication history of an item. '; create table cr_release_periods ( item_id integer constraint cr_release_periods_item_id_fk references cr_items constraint cr_release_periods_item_id_pk primary key, start_when timestamptz default current_timestamp, end_when timestamptz default current_timestamp + interval '20 years' ); create table cr_scheduled_release_log ( exec_date timestamptz default current_timestamp not null, items_released integer not null, items_expired integer not null, err_num integer, err_msg varchar(500) ); comment on table cr_scheduled_release_log is ' Maintains a record, including any exceptions that may have aborted processing, for each scheduled update of live content. '; create table cr_scheduled_release_job ( job_id integer, last_exec timestamptz ); comment on table cr_scheduled_release_job is ' One-row table to track job ID of scheduled release update. '; insert into cr_scheduled_release_job values (NULL, now()); -------------------------------------------------------------- -- CONTENT FOLDERS -------------------------------------------------------------- create table cr_folders ( folder_id integer constraint cr_folders_folder_id_fk references cr_items on delete cascade constraint cr_folders_folder_id_pk primary key, label varchar(1000), description text, has_child_folders boolean default 'f', has_child_symlinks boolean default 'f', package_id integer constraint cr_folders_pkg_id_fk references apm_packages ); comment on table cr_folders is ' Folders are used to support a virtual file system within the content repository. '; --RI Indexes create index cr_folders_package_id_idx ON cr_folders(package_id); create table cr_folder_type_map ( folder_id integer constraint cr_folder_type_map_fldr_fk references cr_folders on delete cascade, content_type varchar(100) constraint cr_folder_type_map_typ_fk references acs_object_types on delete cascade, constraint cr_folder_type_map_pk primary key (folder_id, content_type) ); comment on table cr_folder_type_map is ' A one-to-many mapping table of content folders to content types. Basically, this table restricts the content types a folder may contain. Future releases will add numeric and tagged constraints similar to thos available for content types. '; -- RI Indexes create index cr_folder_typ_map_cont_typ_idx ON cr_folder_type_map(content_type); -------------------------------------------------------------- -- CONTENT TEMPLATES -------------------------------------------------------------- create table cr_templates ( template_id integer constraint cr_templates_template_id_fk references cr_items on delete cascade constraint cr_templates_template_id_pk primary key ); comment on table cr_templates is ' Templates are a special class of text objects that are used for specifying the layout of a content item. They may be mapped to content types for defaults, or may be mapped to individual content items. '; create table cr_template_use_contexts ( use_context varchar(100) constraint cr_template_use_contexts_pk primary key ); comment on table cr_template_use_contexts is ' A simple table (for now) for constraining template use contexts. '; insert into cr_template_use_contexts values ('admin'); insert into cr_template_use_contexts values ('public'); create table cr_type_template_map ( content_type varchar(100) constraint cr_type_template_map_typ_fk references acs_object_types constraint cr_type_template_map_typ_nn not null, template_id integer constraint cr_type_template_map_tmpl_fk references cr_templates, use_context varchar(100) constraint cr_type_template_map_ctx_nn not null constraint cr_type_template_map_ctx_fk references cr_template_use_contexts, is_default boolean default 'f', constraint cr_type_template_map_pk primary key (content_type, template_id, use_context) ); create index cr_ttmap_by_content_type on cr_type_template_map(content_type); create index cr_ttmap_by_template_id on cr_type_template_map(template_id); create index cr_ttmap_by_use_context on cr_type_template_map(use_context); comment on table cr_type_template_map is ' A simple mapping template among content types and templates. Used to determine the default template to use in any particular context, as well as for building any UI that allows publishers to choose from a palette of templates. '; comment on column cr_type_template_map.use_context is ' A token to indicate the context in which a template is appropriate, such as admin or public. Should be constrained when it becomes clearer how this will be used. '; create table cr_item_template_map ( item_id integer constraint cr_item_template_map_item_fk references cr_items constraint cr_item_template_map_item_nn not null, template_id integer constraint cr_item_template_map_tmpl_fk references cr_templates constraint cr_item_template_map_tmpl_nn not null, use_context varchar(100) constraint cr_item_template_map_ctx_nn not null constraint cr_item_template_map_ctx_fk references cr_template_use_contexts, constraint cr_item_template_map_pk primary key (item_id, template_id, use_context) ); create index cr_itmap_by_item_id on cr_item_template_map(item_id); create index cr_itmap_by_template_id on cr_item_template_map(template_id); create index cr_itmap_by_use_context on cr_item_template_map(use_context); comment on table cr_item_template_map is ' Allows a template to be assigned to a specific item. '; -------------------------------------------------------------- -- CONTENT SYMLINKS -------------------------------------------------------------- create table cr_symlinks ( symlink_id integer constraint cr_symlinks_symlink_id_fk references cr_items on delete cascade constraint cr_symlinks_symlink_id_pk primary key, target_id integer constraint cr_symlinks_target_id_fk references cr_items constraint cr_symlinks_target_id_nn not null, label varchar(1000) ); create index cr_symlinks_by_target_id on cr_symlinks(target_id); comment on table cr_symlinks is ' Symlinks are pointers to items within the content repository. '; -------------------------------------------------------------- -- CONTENT EXTLINKS -------------------------------------------------------------- create table cr_extlinks ( extlink_id integer constraint cr_extlinks_extlink_id_fk references cr_items on delete cascade constraint cr_extlinks_extlink_id_pk primary key, url varchar(1000) constraint cr_extlinks_url_nn not null, label varchar(1000) constraint cr_extlinks_label_nn not null, description text ); comment on table cr_extlinks is ' Extlinks are pointers to items anywhere on the web which the publisher wishes to categorize, index and relate to items in the content repository. '; -------------------------------------------------------------- -- CONTENT KEYWORDS -------------------------------------------------------------- create table cr_keywords ( keyword_id integer constraint cr_keywords_keyword_id_pk primary key, parent_id integer constraint cr_keywords_parent_id_fk references cr_keywords, heading varchar(600) constraint cr_keywords_heading_nn not null, description text, has_children boolean, tree_sortkey varbit ); -- RI Indexes create index cr_keywords_parent_id_idx ON cr_keywords(parent_id); create function cr_keywords_get_tree_sortkey(integer) returns varbit as ' declare p_keyword_id alias for $1; begin return tree_sortkey from cr_keywords where keyword_id = p_keyword_id; end;' language 'plpgsql' stable strict; create function cr_keywords_tree_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; begin if new.parent_id is null then select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_keywords where parent_id is null; else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_keywords where parent_id = new.parent_id; select tree_sortkey into v_parent_sk from cr_keywords where keyword_id = new.parent_id; end if; new.tree_sortkey := tree_next_key(v_parent_sk, v_max_value); return new; end;' language 'plpgsql'; create trigger cr_keywords_tree_insert_tr before insert on cr_keywords for each row execute procedure cr_keywords_tree_insert_tr (); create function cr_keywords_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; p_id integer; v_rec record; clr_keys_p boolean default ''t''; begin if new.keyword_id = old.keyword_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) THEN return new; end if; for v_rec in select keyword_id from cr_keywords where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey) order by tree_sortkey LOOP if clr_keys_p then update cr_keywords set tree_sortkey = null where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); clr_keys_p := ''f''; end if; select parent_id into p_id from cr_keywords where keyword_id = v_rec.keyword_id; if p_id is null then select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_keywords where parent_id is null; else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_keywords where parent_id = p_id; select tree_sortkey into v_parent_sk from cr_keywords where keyword_id = p_id; end if; update cr_keywords set tree_sortkey = tree_next_key(v_parent_sk, v_max_value) where keyword_id = v_rec.keyword_id; end LOOP; return new; end;' language 'plpgsql'; create trigger cr_keywords_tree_update_tr after update on cr_keywords for each row execute procedure cr_keywords_tree_update_tr (); comment on table cr_keywords is ' Stores a subject taxonomy for classifying content items, analogous to the system used by a library. '; comment on column cr_keywords.heading is ' A subject heading. This will become a message ID in the next release so it should never be referenced directly (only through the API) '; comment on column cr_keywords.description is ' Description of a subject heading. This will be a message ID in the next release so it should never be referenced directly (only through the API) '; create table cr_item_keyword_map ( item_id integer constraint cr_item_keyword_map_item_id_fk references cr_items constraint cr_item_keyword_map_item_id_nn not null, keyword_id integer constraint cr_item_keyword_map_kw_fk references cr_keywords constraint cr_item_keyword_map_kw_nn not null, constraint cr_item_keyword_map_pk primary key (item_id, keyword_id) ); -- RI Indexes create index cr_item_keyword_map_kw_id_idx ON cr_item_keyword_map(keyword_id); -------------------------------------------------------------- -- TEXT SUBMISSION -------------------------------------------------------------- create table cr_text ( text_data text ); comment on table cr_text is ' A simple placeholder table for generating input views, so that a complete revision may be added with a single INSERT statement. '; insert into cr_text values (NULL); create function cr_text_tr () returns opaque as ' begin raise EXCEPTION ''-20000: Inserts are not allowed into cr_text.''; return new; end;' language 'plpgsql'; create trigger cr_text_tr before insert on cr_text for each row execute procedure cr_text_tr (); -- show errors -------------------------------------------------------------- -- DOCUMENT SUBMISSION WITH CONVERSION TO HTML -------------------------------------------------------------- -- create global temporary table cr_doc_filter ( -- revision_id integer primary key, -- content BLOB --) on commit delete rows; create table cr_doc_filter ( revision_id integer constraint cr_doc_filter_revision_id_pk primary key, -- content BLOB -- need a blob trigger here content integer ); -- Source PL/SQL Definitions. \i content-util.sql \i content-xml.sql -- prompt *** Creating packaged call specs for Java utility methods... \i content-package.sql -- prompt *** Defining and compiling packages... \i packages-create.sql -- prompt *** Creating object types... \i types-create.sql -- this index requires prefs created in content-search -- create index cr_doc_filter_index on cr_doc_filter ( content ) -- indextype is ctxsys.context -- parameters ('FILTER content_filter_pref' ); comment on table cr_doc_filter is ' A temporary table for holding binary documents that are to be converted into HTML (or plain text) prior to insertion into the repository. '; -- prompt *** Compiling documentation package... \i doc-package.sql -- prompt *** Creating image content type... \i content-image.sql -- by default, map all MIME types to 'content_revision' create function inline_1 () returns integer as ' declare v_id integer; begin PERFORM content_type__register_mime_type(''content_revision'', ''text/html''); PERFORM content_type__register_mime_type(''content_revision'', ''text/plain''); PERFORM content_type__register_mime_type(''content_revision'', ''application/rtf''); v_id := content_folder__new ( ''pages'', ''Pages'', ''Site pages go here'', -4, null, content_item__get_root_folder(null), now(), null, null ); PERFORM content_folder__register_content_type( v_id, ''content_revision'', ''t'' ); PERFORM content_folder__register_content_type( v_id, ''content_folder'', ''t'' ); PERFORM content_folder__register_content_type( v_id, ''content_symlink'', ''t'' ); -- add the root content folder to acs_magic_objects insert into acs_magic_objects (name, object_id) select ''cr_item_root'', content_item__get_root_folder(null); v_id := content_folder__new ( ''templates'', ''Templates'', ''Templates which render the pages go here'', -4, null, content_template__get_root_folder(), now(), null, null ); PERFORM content_folder__register_content_type( v_id, ''content_folder'', ''t'' ); PERFORM content_folder__register_content_type( v_id, ''content_symlink'', ''t'' ); PERFORM content_folder__register_content_type( v_id, ''content_template'', ''t'' ); -- add to acs_magic_objects insert into acs_magic_objects (name, object_id) select ''cr_template_root'', content_template__get_root_folder(); return 0; end;' language 'plpgsql'; select inline_1 (); drop function inline_1 (); create function inline_2 () returns integer as ' declare v_item_id integer; v_revision_id integer; begin select nextval(''t_acs_object_id_seq'') into v_item_id; PERFORM content_template__new( ''default_template'', ''-200'', v_item_id, now(), null, null ); v_revision_id := content_revision__new( ''Template'', NULL, now(), ''text/html'', null, ''@text;noquote@'', v_item_id, NULL, now(), null, null); update cr_revisions set content_length = length(content) where revision_id = v_revision_id; update cr_items set live_revision = v_revision_id where item_id = v_item_id; PERFORM content_type__register_template( ''content_revision'', v_item_id, ''public'', ''t''); PERFORM content_type__register_template( ''image'', v_item_id, ''public'', ''t''); -- testing, this may go away. DanW PERFORM content_type__register_template( ''content_template'', v_item_id, ''public'', ''t''); return 0; end;' language 'plpgsql'; select inline_2 (); drop function inline_2 (); -- this was added for edit-this-page and others -- 05-Nov-2001 Jon Griffin jon@mayuli.com ---drop the previw constraint alter table cr_folders drop constraint cr_folders_pkg_id_fk; ------- alter table cr_folders add constraint cr_folders_package_id_fk foreign key (package_id) references apm_packages (package_id); --constraint cr_fldr_pkg_id_fk -- prompt *** Preparing search indices... \i content-search.sql openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-schedule.sql0000644000175000017500000000620210440426443030174 0ustar frankiefrankie-- Data model to support release scheduling of items in the content -- repository of the ArsDigita Publishing System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-schedule.sql,v 1.9 2006/06/04 00:45:23 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- prompt *** Preparing for scheduled updates to live content... create function cr_scheduled_release_tr () returns opaque as ' begin raise EXCEPTION ''-20000: Inserts are not allowed into cr_scheduled_release_job.''; return new; end;' language 'plpgsql'; create trigger cr_scheduled_release_tr before insert on cr_scheduled_release_job for each row execute procedure cr_scheduled_release_tr (); -- show errors -- Update the publishing status for items that are due to be released -- or expired. create function cr_scheduled_release_exec () returns integer as ' declare exec__last_exec timestamptz; exec__this_exec timestamptz default current_timestamp; exec__items_released integer default 0; exec__items_expired integer default 0; exec__err_num integer; -- sqlcode exec__err_msg varchar; -- substr(sqlerrm, 1, 500); item_rec record; begin select last_exec into exec__last_exec from cr_scheduled_release_job; for item_rec in select p.item_id, live_revision from cr_release_periods p, cr_items i where start_when between exec__last_exec and now() and p.item_id = i.item_id LOOP -- update publish status update cr_items set publish_status = ''live'' where item_id = item_rec.item_id; exec__items_released := exec__items_released + 1; end loop; for item_rec in select p.item_id, live_revision from cr_release_periods p, cr_items i where end_when between exec__last_exec and now() and p.item_id = i.item_id LOOP -- update publish status update cr_items set publish_status = ''expired'' where item_id = item_rec.item_id; exec__items_expired := exec__items_expired + 1; end loop; -- exception -- when others then -- err_num := SQLCODE; -- err_msg := substr(SQLERRM, 1, 500); -- end; -- keep a record of the update insert into cr_scheduled_release_log ( items_released, items_expired, err_num, err_msg ) values ( exec__items_released, exec__items_expired, exec__err_num, exec__err_msg ); -- Table was growing without bound (OpenACS DanW) delete from cr_scheduled_release_log where exec_date < now() - ''4 week''::interval; -- Reset the last time of execution to start of processing update cr_scheduled_release_job set last_exec = exec__this_exec; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-type.sql0000644000175000017500000011650111530060570027361 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Authors: Michael Pih (pihman@arsdigita.com) -- Karl Goldstein (karlg@arsdigita.com) -- $Id: content-type.sql,v 1.55 2011/02/20 00:34:00 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- Create a trigger to make sure that there will never be more than -- one default template for a given content type and use context create function cr_type_template_map_tr () returns opaque as ' begin if new.is_default = ''t'' then update cr_type_template_map set is_default = ''f'' where content_type = new.content_type and use_context = new.use_context and template_id <> new.template_id and is_default = ''t''; end if; return new; end;' language 'plpgsql'; create trigger cr_type_template_map_tr before insert on cr_type_template_map for each row execute procedure cr_type_template_map_tr (); select define_function_args('content_type__create_type','content_type,supertype;content_revision,pretty_name,pretty_plural,table_name,id_column,name_method'); create or replace function content_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare create_type__content_type alias for $1; create_type__supertype alias for $2; -- default ''content_revision'' create_type__pretty_name alias for $3; create_type__pretty_plural alias for $4; create_type__table_name alias for $5; create_type__id_column alias for $6; -- default ''XXX'' create_type__name_method alias for $7; -- default null v_temp_p boolean; v_supertype_table acs_object_types.table_name%TYPE; begin if (create_type__supertype <> ''content_revision'') and (create_type__content_type <> ''content_revision'') then select count(*) > 0 into v_temp_p from acs_object_type_supertype_map where object_type = create_type__supertype and ancestor_type = ''content_revision''; if not v_temp_p then raise EXCEPTION ''-20000: supertype % must be a subtype of content_revision'', create_type__supertype; end if; end if; select count(*) = 0 into v_temp_p from pg_class where relname = lower(create_type__table_name); PERFORM acs_object_type__create_type ( create_type__content_type, create_type__pretty_name, create_type__pretty_plural, create_type__supertype, create_type__table_name, create_type__id_column, null, ''f'', null, create_type__name_method, v_temp_p, ''f'' ); PERFORM content_type__refresh_view(create_type__content_type); return 0; end;' language 'plpgsql'; select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f,drop_objects_p;f'); create or replace function content_type__drop_type (varchar,boolean,boolean,boolean) returns integer as ' declare drop_type__content_type alias for $1; drop_type__drop_children_p alias for $2; -- default ''f'' drop_type__drop_table_p alias for $3; -- default ''f'' drop_type__drop_objects_p alias for $4; -- default ''f'' table_exists_p boolean; v_table_name varchar; is_subclassed_p boolean; child_rec record; attr_row record; revision_row record; item_row record; begin -- first we''ll rid ourselves of any dependent child types, if any , -- along with their own dependent grandchild types select count(*) > 0 into is_subclassed_p from acs_object_types where supertype = drop_type__content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children''s packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_type__drop_children_p and is_subclassed_p then for child_rec in select object_type from acs_object_types where supertype = drop_type__content_type LOOP PERFORM content_type__drop_type(child_rec.object_type, ''t'', drop_type__drop_table_p, drop_type__drop_objects_p); end LOOP; end if; -- now drop all the attributes related to this type for attr_row in select attribute_name from acs_attributes where object_type = drop_type__content_type LOOP PERFORM content_type__drop_attribute(drop_type__content_type, attr_row.attribute_name, ''f'' ); end LOOP; -- we''ll remove the associated table if it exists select table_exists(lower(table_name)) into table_exists_p from acs_object_types where object_type = drop_type__content_type; if table_exists_p and drop_type__drop_table_p then select table_name into v_table_name from acs_object_types where object_type = drop_type__content_type; -- drop the rule and input/output views for the type -- being dropped. -- FIXME: this did not exist in the oracle code and it needs to be -- tested. Thanks to Vinod Kurup for pointing this out. -- The rule dropping might be redundant as the rule might be dropped -- when the view is dropped. -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). execute ''drop table '' || v_table_name || '' cascade''; end if; -- If we are dealing with a revision, delete the revision with revision__delete -- This way the integrity constraint with live revision is dealt with correctly if drop_type__drop_objects_p then for revision_row in select revision_id from cr_revisions, acs_objects where revision_id = object_id and object_type = drop_type__content_type loop PERFORM content_revision__delete(revision_row.revision_id); end loop; for item_row in select item_id from cr_items where content_type = drop_type__content_type loop PERFORM content_item__delete(item_row.item_id); end loop; end if; PERFORM acs_object_type__drop_type(drop_type__content_type, drop_type__drop_objects_p); return 0; end;' language 'plpgsql'; -- don't define function_args twice -- select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f'); create or replace function content_type__drop_type (varchar,boolean,boolean) returns integer as ' declare drop_type__content_type alias for $1; drop_type__drop_children_p alias for $2; -- default ''f'' drop_type__drop_table_p alias for $3; -- default ''f'' table_exists_p boolean; v_table_name varchar; is_subclassed_p boolean; child_rec record; attr_row record; begin -- first we''ll rid ourselves of any dependent child types, if any , -- along with their own dependent grandchild types select count(*) > 0 into is_subclassed_p from acs_object_types where supertype = drop_type__content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children''s packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_type__drop_children_p and is_subclassed_p then for child_rec in select object_type from acs_object_types where supertype = drop_type__content_type LOOP PERFORM content_type__drop_type(child_rec.object_type, ''t'', ''f''); end LOOP; end if; -- now drop all the attributes related to this type for attr_row in select attribute_name from acs_attributes where object_type = drop_type__content_type LOOP PERFORM content_type__drop_attribute(drop_type__content_type, attr_row.attribute_name, ''f'' ); end LOOP; -- we''ll remove the associated table if it exists select table_exists(lower(table_name)) into table_exists_p from acs_object_types where object_type = drop_type__content_type; if table_exists_p and drop_type__drop_table_p then select table_name into v_table_name from acs_object_types where object_type = drop_type__content_type; -- drop the rule and input/output views for the type -- being dropped. -- FIXME: this did not exist in the oracle code and it needs to be -- tested. Thanks to Vinod Kurup for pointing this out. -- The rule dropping might be redundant as the rule might be dropped -- when the view is dropped. -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; execute ''drop view '' || v_table_name || ''x cascade''; execute ''drop view '' || v_table_name || ''i cascade''; execute ''drop table '' || v_table_name; end if; PERFORM acs_object_type__drop_type(drop_type__content_type, ''f''); return 0; end;' language 'plpgsql'; select define_function_args('content_type__create_attribute','content_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); create or replace function content_type__create_attribute (varchar,varchar,varchar,varchar,varchar,integer,varchar,varchar) returns integer as ' declare create_attribute__content_type alias for $1; create_attribute__attribute_name alias for $2; create_attribute__datatype alias for $3; create_attribute__pretty_name alias for $4; create_attribute__pretty_plural alias for $5; -- default null create_attribute__sort_order alias for $6; -- default null create_attribute__default_value alias for $7; -- default null create_attribute__column_spec alias for $8; -- default ''text'' v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists boolean; begin -- add the appropriate column to the table select table_name into v_table_name from acs_object_types where object_type = create_attribute__content_type; if NOT FOUND then raise EXCEPTION ''-20000: Content type % does not exist in content_type.create_attribute'', create_attribute__content_type; end if; select count(*) > 0 into v_column_exists from pg_class c, pg_attribute a where c.relname::varchar = v_table_name and c.oid = a.attrelid and a.attname = lower(create_attribute__attribute_name); v_attr_id := acs_attribute__create_attribute ( create_attribute__content_type, create_attribute__attribute_name, create_attribute__datatype, create_attribute__pretty_name, create_attribute__pretty_plural, null, null, create_attribute__default_value, 1, 1, create_attribute__sort_order, ''type_specific'', ''f'', not v_column_exists, null, null, null, null, null, create_attribute__column_spec ); PERFORM content_type__refresh_view(create_attribute__content_type); return v_attr_id; end;' language 'plpgsql'; select define_function_args('content_type__drop_attribute','content_type,attribute_name,drop_column;f'); create or replace function content_type__drop_attribute (varchar,varchar,boolean) returns integer as ' declare drop_attribute__content_type alias for $1; drop_attribute__attribute_name alias for $2; drop_attribute__drop_column alias for $3; -- default ''f'' v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute__content_type and a.object_type = drop_attribute__content_type and a.attribute_name = drop_attribute__attribute_name; if NOT FOUND then raise EXCEPTION ''-20000: Attribute %:% does not exist in content_type.drop_attribute'', drop_attribute__content_type, drop_attribute__attribute_name; end if; -- Drop the attribute PERFORM acs_attribute__drop_attribute(drop_attribute__content_type, drop_attribute__attribute_name); -- FIXME: postgresql does not support drop column. -- Drop the column if neccessary if drop_attribute__drop_column then execute ''alter table '' || v_table || '' drop column '' || drop_attribute__attribute_name || '' cascade''; end if; PERFORM content_type__refresh_view(drop_attribute__content_type); return 0; end;' language 'plpgsql'; select define_function_args('content_type__register_template','content_type,template_id,use_context,is_default;f'); create or replace function content_type__register_template (varchar,integer,varchar,boolean) returns integer as ' declare register_template__content_type alias for $1; register_template__template_id alias for $2; register_template__use_context alias for $3; register_template__is_default alias for $4; -- default ''f'' v_template_registered boolean; begin select count(*) > 0 into v_template_registered from cr_type_template_map where content_type = register_template__content_type and use_context = register_template__use_context and template_id = register_template__template_id; -- register the template if NOT v_template_registered then insert into cr_type_template_map ( template_id, content_type, use_context, is_default ) values ( register_template__template_id, register_template__content_type, register_template__use_context, register_template__is_default ); -- update the registration status of the template else -- unset the default template before setting this one as the default if register_template__is_default then update cr_type_template_map set is_default = ''f'' where content_type = register_template__content_type and use_context = register_template__use_context; end if; update cr_type_template_map set is_default = register_template__is_default where template_id = register_template__template_id and content_type = register_template__content_type and use_context = register_template__use_context; end if; return 0; end;' language 'plpgsql'; select define_function_args('content_type__set_default_template','content_type,template_id,use_context'); create or replace function content_type__set_default_template (varchar,integer,varchar) returns integer as ' declare set_default_template__content_type alias for $1; set_default_template__template_id alias for $2; set_default_template__use_context alias for $3; begin update cr_type_template_map set is_default = ''t'' where template_id = set_default_template__template_id and content_type = set_default_template__content_type and use_context = set_default_template__use_context; -- make sure there is only one default template for -- any given content_type/use_context pair update cr_type_template_map set is_default = ''f'' where template_id <> set_default_template__template_id and content_type = set_default_template__content_type and use_context = set_default_template__use_context and is_default = ''t''; return 0; end;' language 'plpgsql'; select define_function_args('content_type__get_template','content_type,use_context'); create or replace function content_type__get_template (varchar,varchar) returns integer as ' declare get_template__content_type alias for $1; get_template__use_context alias for $2; v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template__content_type and use_context = get_template__use_context and is_default = ''t''; return v_template_id; end;' language 'plpgsql' stable strict; select define_function_args('content_type__unregister_template','content_type,template_id,use_context'); create or replace function content_type__unregister_template (varchar,integer,varchar) returns integer as ' declare unregister_template__content_type alias for $1; -- default null unregister_template__template_id alias for $2; unregister_template__use_context alias for $3; -- default null begin if unregister_template__use_context is null and unregister_template__content_type is null then delete from cr_type_template_map where template_id = unregister_template__template_id; else if unregister_template__use_context is null then delete from cr_type_template_map where template_id = unregister_template__template_id and content_type = unregister_template__content_type; else if unregister_template__content_type is null then delete from cr_type_template_map where template_id = unregister_template__template_id and use_context = unregister_template__use_context; else delete from cr_type_template_map where template_id = unregister_template__template_id and content_type = unregister_template__content_type and use_context = unregister_template__use_context; end if; end if; end if; return 0; end;' language 'plpgsql'; -- function trigger_insert_statement select define_function_args('content_type__trigger_insert_statement','content_type'); create or replace function content_type__trigger_insert_statement (varchar) returns varchar as ' declare trigger_insert_statement__content_type alias for $1; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; vals varchar default ''''; attr_rec record; begin if trigger_insert_statement__content_type is null then return exception ''content_type__trigger_insert_statement called with null content_type''; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = trigger_insert_statement__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; vals := vals || '', p_new.'' || attr_rec.attribute_name; end LOOP; return ''insert into '' || v_table_name || '' ( '' || v_id_column || cols || '' ) values (v_revision_id'' || vals || '')''; end;' language 'plpgsql' stable; -- FIXME: need to look at this in more detail. This probably can't be made -- to work reliably in postgresql. Currently we are using a rule to insert -- into the input view when a new content revision is added. Pg locks the -- underlying table when the rule is dropped, so the dropping and recreating -- of the new content revisons seems like it would be reliable, but the -- possiblity of a race condition exists for either the initial creation -- of dropping of a type. I'm not sure if the possiblity of a race condition -- acually exists in practice. The thing to do here might be to just create -- a function that dynamically builds the insert strings and does the -- each time an insert is done on the content_type view. Trade-off being -- that the inserts would be slower due to the use of dynamic code in pl/psql. -- More digging required ... -- DCW, 2001-03-30. -- Create or replace a trigger on insert for simplifying addition of -- revisions for any content type select define_function_args('content_type__refresh_trigger','content_type'); create or replace function content_type__refresh_trigger (varchar) returns integer as ' declare refresh_trigger__content_type alias for $1; rule_text text default ''''; function_text text default ''''; v_table_name acs_object_types.table_name%TYPE; type_rec record; begin -- get the table name for the content type (determines view name) raise NOTICE ''refresh trigger for % '', refresh_trigger__content_type; -- Since we allow null table name use object type if table name is null so -- we still can have a view. select coalesce(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_trigger__content_type; --=================== start building rule code ======================= function_text := function_text || ''create or replace function '' || v_table_name || ''_f (p_new ''|| v_table_name || ''i) returns void as '''' declare v_revision_id integer; begin select content_revision__new( p_new.title, p_new.description, now(), p_new.mime_type, p_new.nls_language, case when p_new.text is null then p_new.data else p_new.text end, content_symlink__resolve(p_new.item_id), p_new.revision_id, now(), p_new.creation_user, p_new.creation_ip, p_new.object_package_id ) into v_revision_id; ''; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_trigger__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) and ot1.table_name is not null order by level asc LOOP function_text := function_text || '' '' || content_type__trigger_insert_statement(type_rec.object_type) || ''; ''; end loop; function_text := function_text || '' return; end;'''' language ''''plpgsql''''; ''; -- end building the rule definition code -- create the new function execute function_text; rule_text := ''create rule '' || v_table_name || ''_r as on insert to '' || v_table_name || ''i do instead SELECT '' || v_table_name || ''_f(new); '' ; --================== done building rule code ======================= -- drop the old rule if rule_exists(v_table_name || ''_r'', v_table_name || ''i'') then -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; end if; -- create the new rule for inserts on the content type execute rule_text; return null; end;' language 'plpgsql'; select define_function_args('content_type__refresh_view','content_type'); create or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and lower(ot2.table_name) <> ''acs_objects'' and lower(ot2.table_name) <> ''cr_revisions'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP if join_rec.table_name is not null then cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end if; end loop; -- Since we allow null table name use object type if table name is null so -- we still can have a view. select coalesce(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 57 then raise exception ''Table name cannot be longer than 57 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i'' || '' CASCADE''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x cascade''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; select define_function_args('content_type__register_child_type','parent_type,child_type,relation_tag;generic,min_n;0,max_n'); -- procedure register_child_type select define_function_args('content_type__register_child_type','parent_type,child_type,relation_tag;generic,min_n;0,max_n'); create or replace function content_type__register_child_type (varchar,varchar,varchar,integer,integer) returns integer as ' declare register_child_type__parent_type alias for $1; register_child_type__child_type alias for $2; register_child_type__relation_tag alias for $3; -- default ''generic'' register_child_type__min_n alias for $4; -- default 0 register_child_type__max_n alias for $5; -- default null v_exists integer; begin select count(*) into v_exists from cr_type_children where parent_type = register_child_type__parent_type and child_type = register_child_type__child_type and relation_tag = register_child_type__relation_tag; if v_exists = 0 then insert into cr_type_children ( parent_type, child_type, relation_tag, min_n, max_n ) values ( register_child_type__parent_type, register_child_type__child_type, register_child_type__relation_tag, register_child_type__min_n, register_child_type__max_n ); else update cr_type_children set min_n = register_child_type__min_n, max_n = register_child_type__max_n where parent_type = register_child_type__parent_type and child_type = register_child_type__child_type and relation_tag = register_child_type__relation_tag; end if; return 0; end;' language 'plpgsql'; select define_function_args('content_type__unregister_child_type','content_type,child_type,relation_tag'); create or replace function content_type__unregister_child_type (varchar,varchar,varchar) returns integer as ' declare unregister_child_type__parent_type alias for $1; unregister_child_type__child_type alias for $2; unregister_child_type__relation_tag alias for $3; begin delete from cr_type_children where parent_type = unregister_child_type__parent_type and child_type = unregister_child_type__child_type and relation_tag = unregister_child_type__relation_tag; return 0; end;' language 'plpgsql'; select define_function_args('content_type__register_relation_type','content_type,target_type,relation_tag;generic,min_n;0,max_n'); create or replace function content_type__register_relation_type (varchar,varchar,varchar,integer,integer) returns integer as ' declare register_relation_type__content_type alias for $1; register_relation_type__target_type alias for $2; register_relation_type__relation_tag alias for $3; -- default ''generic'' register_relation_type__min_n alias for $4; -- default 0 register_relation_type__max_n alias for $5; -- default null v_exists integer; begin -- check if the relation type exists select count(*) into v_exists from cr_type_relations where content_type = register_relation_type__content_type and target_type = register_relation_type__target_type and relation_tag = register_relation_type__relation_tag; -- if the relation type does not exist, insert a row into cr_type_relations if v_exists = 0 then insert into cr_type_relations ( content_type, target_type, relation_tag, min_n, max_n ) values ( register_relation_type__content_type, register_relation_type__target_type, register_relation_type__relation_tag, register_relation_type__min_n, register_relation_type__max_n ); -- otherwise, update the row in cr_type_relations else update cr_type_relations set min_n = register_relation_type__min_n, max_n = register_relation_type__max_n where content_type = register_relation_type__content_type and target_type = register_relation_type__target_type and relation_tag = register_relation_type__relation_tag; end if; return 0; end;' language 'plpgsql'; select define_function_args('content_type__unregister_relation_type','content_type,target_type,relation_tag;null'); create or replace function content_type__unregister_relation_type (varchar,varchar,varchar) returns integer as ' declare unregister_relation_type__content_type alias for $1; unregister_relation_type__target_type alias for $2; unregister_relation_type__relation_tag alias for $3; -- default null begin delete from cr_type_relations where content_type = unregister_relation_type__content_type and target_type = unregister_relation_type__target_type and relation_tag = unregister_relation_type__relation_tag; return 0; end;' language 'plpgsql'; select define_function_args('content_type__register_mime_type','content_type,mime_type'); create or replace function content_type__register_mime_type (varchar,varchar) returns integer as ' declare register_mime_type__content_type alias for $1; register_mime_type__mime_type alias for $2; v_valid_registration integer; begin -- check if this type is already registered select count(*) into v_valid_registration from cr_mime_types where not exists ( select 1 from cr_content_mime_type_map where mime_type = register_mime_type__mime_type and content_type = register_mime_type__content_type ) and mime_type = register_mime_type__mime_type; if v_valid_registration = 1 then insert into cr_content_mime_type_map ( content_type, mime_type ) values ( register_mime_type__content_type, register_mime_type__mime_type ); end if; return 0; end;' language 'plpgsql'; select define_function_args('content_type__unregister_mime_type','content_type,mime_type'); create or replace function content_type__unregister_mime_type (varchar,varchar) returns integer as ' declare unregister_mime_type__content_type alias for $1; unregister_mime_type__mime_type alias for $2; begin delete from cr_content_mime_type_map where content_type = unregister_mime_type__content_type and mime_type = unregister_mime_type__mime_type; return 0; end;' language 'plpgsql'; select define_function_args('content_type__is_content_type','object_type'); create or replace function content_type__is_content_type (varchar) returns boolean as ' declare is_content_type__object_type alias for $1; v_is_content_type boolean; begin if is_content_type__object_type = ''content_revision'' then v_is_content_type := ''t''; else select count(*) > 0 into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type__object_type and ancestor_type = ''content_revision''; end if; return v_is_content_type; end;' language 'plpgsql' stable; select define_function_args('content_type__rotate_template','template_id,v_content_type,use_context'); create or replace function content_type__rotate_template (integer,varchar,varchar) returns integer as ' declare rotate_template__template_id alias for $1; rotate_template__v_content_type alias for $2; rotate_template__use_context alias for $3; v_template_id cr_templates.template_id%TYPE; v_items_val record; begin -- get the default template select template_id into v_template_id from cr_type_template_map where content_type = rotate_template__v_content_type and use_context = rotate_template__use_context and is_default = ''t''; if v_template_id is not null then -- register an item-template to all items without an item-template for v_items_val in select item_id from cr_items i, cr_type_template_map m where i.content_type = rotate_template__v_content_type and m.use_context = rotate_template__use_context and i.content_type = m.content_type and not exists ( select 1 from cr_item_template_map where item_id = i.item_id and use_context = rotate_template__use_context ) LOOP PERFORM content_item__register_template ( v_items_val.item_id, v_template_id, rotate_template__use_context ); end loop; end if; -- register the new template as the default template of the content type if v_template_id != rotate_template__template_id then PERFORM content_type__register_template( rotate_template__v_content_type, rotate_template__template_id, rotate_template__use_context, ''t'' ); end if; return 0; end;' language 'plpgsql'; -- show errors -- Refresh the attribute views -- prompt *** Refreshing content type attribute views... create or replace function inline_0 () returns integer as ' declare type_rec record; begin for type_rec in select ot.object_type from acs_object_types ot, acs_object_types ot2 where ot2.object_type = ''content_revision'' and ot.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot.tree_sortkey LOOP PERFORM content_type__refresh_view (type_rec.object_type); end LOOP; return 0; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/acs-content-repository-create.sql0000644000175000017500000000066407257217564032650 0ustar frankiefrankie-- Registration of ACS Content Repository System. -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: acs-content-repository-create.sql,v 1.1 2001/03/24 22:28:04 danw Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html \i content-create.sql openacs-5.7.0/packages/acs-content-repository/sql/postgresql/datatype-upgrade.sql0000644000175000017500000000150307257772267030213 0ustar frankiefrankie update acs_attributes set datatype = 'keyword' where attribute_name = 'name' and object_type = 'content_item'; update acs_attributes set datatype = 'keyword' where attribute_name = 'locale' and object_type = 'content_item'; update acs_attributes set datatype = 'text' where attribute_name = 'title' and object_type = 'content_revision'; update acs_attributes set datatype = 'text' where attribute_name = 'description' and object_type = 'content_revision'; update acs_attributes set datatype = 'text' where attribute_name = 'mime_type' and object_type = 'content_revision'; update acs_attributes set datatype = 'integer' where attribute_name = 'width' and object_type = 'image'; update acs_attributes set datatype = 'integer' where attribute_name = 'height' and object_type = 'image'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-template.sql0000644000175000017500000001673011452447070030225 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-template.sql,v 1.24 2010/10/04 21:59:20 victorg Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html create view content_template_globals as select -200 as c_root_folder_id; create or replace function content_template__get_root_folder() returns integer as ' declare v_folder_id integer; begin select c_root_folder_id from content_template_globals into v_folder_id; return v_folder_id; end;' language 'plpgsql' immutable; -- create or replace package body content_template create or replace function content_template__new(varchar) returns integer as ' declare new__name alias for $1; begin return content_template__new(new__name, null, null, now(), null, null ); end;' language 'plpgsql'; -- function new create or replace function content_template__new (varchar,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__template_id alias for $3; -- default null new__creation_date alias for $4; -- default now() new__creation_user alias for $5; -- default null new__creation_ip alias for $6; -- default null v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if new__parent_id is null then select c_root_folder_id into v_parent_id from content_template_globals; else v_parent_id := new__parent_id; end if; -- make sure we''re allowed to create a template in this folder if content_folder__is_folder(new__parent_id) = ''t'' and content_folder__is_registered(new__parent_id,''content_template'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow templates to be created''; else v_template_id := content_item__new ( new__name, v_parent_id, new__template_id, null, new__creation_date, new__creation_user, null, new__creation_ip, ''content_item'', ''content_template'', null, null, ''text/plain'', null, null, ''text'' ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end;' language 'plpgsql'; create or replace function content_template__new(varchar,text,bool) returns integer as ' declare new__name alias for $1; new__text alias for $2; new__is_live alias for $3; begin return content_template__new(new__name, null, null, now(), null, null, new__text, new__is_live ); end;' language 'plpgsql'; select define_function_args('content_template__new','name,parent_id,template_id,creation_date;now,creation_user,creation_ip,text,is_live;f'); create or replace function content_template__new (varchar,integer,integer,timestamptz,integer,varchar,text,bool) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__template_id alias for $3; -- default null new__creation_date alias for $4; -- default now() new__creation_user alias for $5; -- default null new__creation_ip alias for $6; -- default null new__text alias for $7; -- default null new__is_live alias for $8; -- default ''f'' v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if new__parent_id is null then select c_root_folder_id into v_parent_id from content_template_globals; else v_parent_id := new__parent_id; end if; -- make sure we''re allowed to create a template in this folder if content_folder__is_folder(new__parent_id) = ''t'' and content_folder__is_registered(new__parent_id,''content_template'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow templates to be created''; else v_template_id := content_item__new ( new__template_id, -- new__item_id new__name, -- new__name v_parent_id, -- new__parent_id null, -- new__title new__creation_date, -- new__creation_date new__creation_user, -- new__creation_user null, -- new__context_id new__creation_ip, -- new__creation_ip new__is_live, -- new__is_live ''text/plain'', -- new__mime_type new__text, -- new__text ''text'', -- new__storage_type ''t'', -- new__security_inherit_p ''CR_FILES'', -- new__storage_area_key ''content_item'', -- new__item_subtype ''content_template'' -- new__content_type ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end;' language 'plpgsql'; -- procedure delete select define_function_args('content_template__del','template_id'); create or replace function content_template__del (integer) returns integer as ' declare delete__template_id alias for $1; begin delete from cr_type_template_map where template_id = delete__template_id; delete from cr_item_template_map where template_id = delete__template_id; delete from cr_templates where template_id = delete__template_id; PERFORM content_item__delete(delete__template_id); return 0; end;' language 'plpgsql'; select define_function_args('content_template__delete','template_id'); create or replace function content_template__delete (integer) returns integer as ' declare delete__template_id alias for $1; begin PERFORM content_template__delete(delete__template_id); return 0; end;' language 'plpgsql'; -- function is_template select define_function_args('content_template__is_template','template_id'); create or replace function content_template__is_template (integer) returns boolean as ' declare is_template__template_id alias for $1; begin return count(*) > 0 from cr_templates where template_id = is_template__template_id; end;' language 'plpgsql' stable; -- function get_path select define_function_args('content_template__get_path','template_id,root_folder_id'); create or replace function content_template__get_path (integer,integer) returns varchar as ' declare template_id alias for $1; root_folder_id alias for $2; -- default content_template_globals.c_root_folder_id begin return content_item__get_path(template_id, root_folder_id); end;' language 'plpgsql' stable; -- show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/0000755000175000017500000000000011575225424025644 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d2-5.2.0d3.sql0000644000175000017500000000114210044221035031547 0ustar frankiefrankie-- @cvs-id $Id: upgrade-5.2.0d2-5.2.0d3.sql,v 1.2 2004/04/29 15:41:17 jeffd Exp $ -- @author davis@xarg.net -- cascade on delete of folder and of content_type alter table cr_folder_type_map drop constraint cr_folder_type_map_fldr_fk; alter table cr_folder_type_map add constraint cr_folder_type_map_fldr_fk foreign key (folder_id) references cr_folders on delete cascade; alter table cr_folder_type_map drop constraint cr_folder_type_map_typ_fk; alter table cr_folder_type_map add constraint cr_folder_type_map_typ_fk foreign key (content_type) references acs_object_types on delete cascade; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d6-5.2.0d7.sql0000644000175000017500000000057610100473632031576 0ustar frankiefrankie-- exception was miss spelled drop function cr_dummy_ins_del_tr() cascade; create function cr_dummy_ins_del_tr () returns opaque as ' begin raise exception ''Only updates are allowed on cr_dummy''; return null; end;' language 'plpgsql'; create trigger cr_dummy_ins_del_tr before insert or delete on cr_dummy for each row execute procedure cr_dummy_ins_del_tr (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.0d3-5.4.0d4.sql0000644000175000017500000000017210673020465031573 0ustar frankiefrankieselect define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f,drop_objects_p;f'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.0d7-5.4.0d8.sql0000644000175000017500000001151610700147642031605 0ustar frankiefrankiecreate or replace function content_folder__del (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; -- default ''f'' v_count integer; v_child_row record; v_parent_id integer; v_path varchar; v_folder_sortkey varbit; begin if p_cascade_p = ''f'' then select count(*) into v_count from cr_items where parent_id = delete__folder_id; -- check if the folder contains any items if v_count > 0 then v_path := content_item__get_path(delete__folder_id, null); raise EXCEPTION ''-20000: Folder ID % (%) cannot be deleted because it is not empty.'', delete__folder_id, v_path; end if; else -- delete children select into v_folder_sortkey tree_sortkey from cr_items where item_id=delete__folder_id; for v_child_row in select item_id, tree_sortkey, name from cr_items where tree_sortkey between v_folder_sortkey and tree_right(v_folder_sortkey) and tree_sortkey != v_folder_sortkey order by tree_sortkey desc loop if content_folder__is_folder(v_child_row.item_id) then perform content_folder__delete(v_child_row.item_id); else perform content_item__delete(v_child_row.item_id); end if; end loop; end if; PERFORM content_folder__unregister_content_type( delete__folder_id, ''content_revision'', ''t'' ); delete from cr_folder_type_map where folder_id = delete__folder_id; select parent_id into v_parent_id from cr_items where item_id = delete__folder_id; raise notice ''deleteing folder %'',delete__folder_id; PERFORM content_item__delete(delete__folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = ''f'' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = ''content_folder''); return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; -- default ''f'' begin PERFORM content_folder__del(delete__folder_id,p_cascade_p); return 0; end;' language 'plpgsql'; select define_function_args('content_folder__move','folder_id,target_folder_id,name;null'); create or replace function content_folder__move (integer,integer,varchar) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; -- default null v_source_folder_id integer; v_valid_folders_p integer; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move__target_folder_id or folder_id = move__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.move - Not valid folder(s)''; end if; if move__folder_id = content_item__get_root_folder(null) or move__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.move - Cannot move root folder''; end if; if move__target_folder_id = move__folder_id then raise EXCEPTION ''-20000: content_folder.move - Cannot move a folder to itself''; end if; if content_folder__is_sub_folder(move__folder_id, move__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder is subfolder''; end if; if content_folder__is_registered(move__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder does not allow subfolders''; end if; select parent_id into v_source_folder_id from cr_items where item_id = move__folder_id; -- update the parent_id for the folder update cr_items set parent_id = move__target_folder_id, name = coalesce ( move__name, name ) where item_id = move__folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = ''f'' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = ''content_folder''); -- update the destination update cr_folders set has_child_folders = ''t'' where folder_id = move__target_folder_id; return 0; end;' language 'plpgsql'; select define_function_args('content_type__unregister_relation_type','content_type,target_type,relation_tag;null'); -- make it same as in oracle select define_function_args('content_type__rotate_template','template_id,v_content_type,use_context'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.0d1-5.0d2.sql0000644000175000017500000000264507753332554031304 0ustar frankiefrankie-- @author Lars Pind (lars@collaboraid.biz) -- @creation-date 2003-10-14 -- @cvs-id $Id: upgrade-5.0d1-5.0d2.sql,v 1.2 2003/11/09 03:33:00 daveb Exp $ select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date,creation_user,creation_ip'); create or replace function image__new_revision(integer, integer, varchar, varchar, timestamptz, varchar, varchar, integer, varchar, integer, integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; v_revision_id integer; begin -- We will let the caller fill in the LOB data or file path. v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, p_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_revision_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.1d1-5.2.1d2.sql0000755000175000017500000007610110676223672031605 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-12-26 -- @arch-tag: c141278e-3359-4f40-8d61-3b8e940c633c -- @cvs-id $Id: upgrade-5.2.1d1-5.2.1d2.sql,v 1.3 2007/09/25 15:22:34 donb Exp $ -- -- New installs were not setting parent_id to security_context_root (-4) -- but 0 so the CR root folders have the wrong info -- re-run these upgrades. -- Content Repository sets parent_id to security_context_root -- for content modules update acs_objects set context_id = -4 where context_id = 0; update cr_items set parent_id = -4 where parent_id = 0; -- now we need to recreate all the functions that assume 0 -- we use acs_magic_object('security_context_root') instead of 0 -- for future flexibility create or replace function content_item__get_root_folder (integer) returns integer as ' declare get_root_folder__item_id alias for $1; -- default null v_folder_id cr_folders.folder_id%TYPE; begin if get_root_folder__item_id is NULL or get_root_folder__item_id in (-4,-100,-200) then v_folder_id := content_item_globals.c_root_folder_id; else select i2.item_id into v_folder_id from cr_items i1, cr_items i2 where i2.parent_id = -4 and i1.item_id = get_root_folder__item_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey); if NOT FOUND then raise EXCEPTION '' -20000: Could not find a root folder for item ID %. Either the item does not exist or its parent value is corrupted.'', get_root_folder__item_id; end if; end if; return v_folder_id; end;' language 'plpgsql' stable; -- content_item__new select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob,package_id'); create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; new__package_id alias for $20; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__data, new__relation_tag, new__is_live, new__storage_type, null); return v_item_id; end;' language 'plpgsql'; -- create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') new__package_id alias for $17; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', coalesce(new__title,new__name), new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if new__title is null then v_title := new__name; else v_title := new__title; end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__storage_type, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null new__package_id alias for $16; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, ''lob'' ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null or new__relation_tag = '''' then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- create the revision if data or title is not null if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, null, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__data, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,varchar,text,text,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__title alias for $3; -- default null new__description alias for $4; -- default null new__text alias for $5; -- default null new__package_id alias for $6; -- default null begin return content_item__new(new__name, new__parent_id, null, null, now(), null, null, null, ''content_item'', ''content_revision'', new__title, new__description, ''text/plain'', null, new__text, ''text'', new__package_id ); end;' language 'plpgsql'; -- content_folder__new create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true new__package_id alias for $11; -- default null v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if new__context_id is null then v_context_id := new__parent_id; else v_context_id := new__context_id; end if; -- parent_id = security_context_root means that this is a mount point if new__parent_id != -4 and content_folder__is_folder(new__parent_id) and content_folder__is_registered(new__parent_id,''content_folder'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow subfolders to be created''; return null; else v_folder_id := content_item__new( new__folder_id, new__name, new__parent_id, null, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''f'', ''text/plain'', null, ''text'', new__security_inherit_p, ''CR_FILES'', ''content_folder'', ''content_folder'', new__package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, new__label, new__description, new__package_id ); -- set the correct object title update acs_objects set title = new__label where object_id = v_folder_id; -- inherit the attributes of the parent folder if new__parent_id is not null then insert into cr_folder_type_map select v_folder_id as folder_id, content_type from cr_folder_type_map where folder_id = new__parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = ''t'' where folder_id = new__parent_id; return v_folder_id; end if; return v_folder_id; end;' language 'plpgsql'; create or replace function content_folder__is_sub_folder (integer,integer) returns boolean as ' declare is_sub_folder__folder_id alias for $1; is_sub_folder__target_folder_id alias for $2; v_parent_id integer default 0; v_sub_folder_p boolean default ''f''; v_rec record; begin if is_sub_folder__folder_id = content_item__get_root_folder(null) or is_sub_folder__folder_id = content_template__get_root_folder() then v_sub_folder_p := ''t''; end if; -- select -- parent_id -- from -- cr_items -- connect by -- prior parent_id = item_id -- start with -- item_id = is_sub_folder__target_folder_id for v_rec in select i2.parent_id from cr_items i1, cr_items i2 where i1.item_id = is_sub_folder__target_folder_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) order by i2.tree_sortkey desc LOOP v_parent_id := v_rec.parent_id; exit when v_parent_id = is_sub_folder__folder_id; -- we did not find the folder, reset v_parent_id v_parent_id := -4; end LOOP; if v_parent_id != -4 then v_sub_folder_p := ''t''; end if; return v_sub_folder_p; end;' language 'plpgsql'; create or replace function content_folder__is_root (integer) returns boolean as ' declare is_root__folder_id alias for $1; v_is_root boolean; begin select parent_id = -4 into v_is_root from cr_items where item_id = is_root__folder_id; return v_is_root; end;' language 'plpgsql'; select define_function_args('content_keyword__new','heading,description,parent_id,keyword_id,creation_date;now,creation_user,creation_ip,object_type;content_keyword,package_id'); -- add new versions of content_keyword__new that support package_id create or replace function content_keyword__new (varchar,varchar,integer,integer,timestamptz,integer,varchar,varchar,integer) returns integer as ' declare new__heading alias for $1; new__description alias for $2; -- default null new__parent_id alias for $3; -- default null new__keyword_id alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__object_type alias for $8; -- default ''content_keyword'' new__package_id alias for $9; -- default null v_id integer; v_package_id acs_objects.package_id%TYPE; begin if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_id := acs_object__new (new__keyword_id, new__object_type, new__creation_date, new__creation_user, new__creation_ip, new__parent_id, ''t'', new__heading, v_package_id ); insert into cr_keywords (heading, description, keyword_id, parent_id) values (new__heading, new__description, v_id, new__parent_id); return v_id; end;' language 'plpgsql'; create or replace function content_keyword__new (varchar,varchar,integer,integer,timestamptz,integer,varchar,varchar) returns integer as ' declare new__heading alias for $1; new__description alias for $2; -- default null new__parent_id alias for $3; -- default null new__keyword_id alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__object_type alias for $8; -- default ''content_keyword'' begin return content_keyword__new(new__heading, new__description, new__parent_id, new__keyword_id, new__creation_date, new__creation_user, new__creation_ip, new__object_type, null ); end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.6.1-4.6.2.sql0000644000175000017500000000201307661402103031111 0ustar frankiefrankie-- Adds indexes for RI checking -- create index cr_cont_mimetypmap_mimetyp_idx ON cr_content_mime_type_map(mime_type); -- cr_mime_types.mime_type create index cr_folder_typ_map_cont_typ_idx ON cr_folder_type_map(content_type); -- acs_object_types.object_type create index cr_folders_package_id_idx ON cr_folders(package_id); -- apm_packages.package_id create index cr_item_keyword_map_kw_id_idx ON cr_item_keyword_map(keyword_id); -- cr_keywords.keyword_id create index cr_item_rels_rel_obj_id_idx ON cr_item_rels(related_object_id); -- acs_objects.object_id create index cr_keywords_parent_id_idx ON cr_keywords(parent_id); -- cr_keywords.keyword_id create index cr_revisions_lob_idx ON cr_revisions(lob); -- lobs.lob_id create index cr_revisions_item_id_idx ON cr_revisions(item_id); -- cr_items.item_id create index cr_type_children_chld_type_idx ON cr_type_children(child_type); -- acs_object_types.object_type create index cr_type_relations_tgt_typ_idx ON cr_type_relations(target_type); -- acs_object_types.object_type openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.7d1-4.7d6.sql0000644000175000017500000000610507702263321031304 0ustar frankiefrankie-- Make two new versions of content_template__new() and make the one that is a wrapper -- (the first one) take two new params; new__text and new__is_live. -- With this version, a revision of the template will be created automatically. -- You thus avoid calling content_revision.new() in a separate step ... -- (ola@polyxena.net) create or replace function content_template__new(varchar,text,bool) returns integer as ' declare new__name alias for $1; new__text alias for $2; new__is_live alias for $3; begin return content_template__new(new__name, null, null, now(), null, null, new__text, new__is_live ); end;' language 'plpgsql'; create or replace function content_template__new (varchar,integer,integer,timestamptz,integer,varchar,text,bool) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__template_id alias for $3; -- default null new__creation_date alias for $4; -- default now() new__creation_user alias for $5; -- default null new__creation_ip alias for $6; -- default null new__text alias for $7; -- default null new__is_live alias for $8; -- default ''f'' v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if new__parent_id is null then v_parent_id := content_template_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- make sure we''re allowed to create a template in this folder if content_folder__is_folder(new__parent_id) = ''t'' and content_folder__is_registered(new__parent_id,''content_template'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow templates to be created''; else v_template_id := content_item__new ( new__template_id, -- new__item_id new__name, -- new__name v_parent_id, -- new__parent_id null, -- new__title new__creation_date, -- new__creation_date new__creation_user, -- new__creation_user null, -- new__context_id new__creation_ip, -- new__creation_ip new__is_live, -- new__is_live ''text/plain'', -- new__mime_type new__text, -- new__text ''text'', -- new__storage_type ''t'', -- new__security_inherit_p ''CR_FILES'', -- new__storage_area_key ''content_item'', -- new__item_subtype ''content_template'' -- new__content_type ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.4d1-5.1.4d2.sql0000644000175000017500000002266310171476701031603 0ustar frankiefrankie-- add define function args calls to the database. select define_function_args('content_extlink__new','name,url,label,description,parent_id,extlink_id,creation_date;now,creation_user,creation_ip'); select define_function_args('content_extlink__delete','extlink_id'); select define_function_args('content_extlink__is_extlink','item_id'); select define_function_args('content_extlink__copy','extlink_id,target_folder_id,creation_user,creation_ip,name'); select define_function_args('content_extlink__new','name,url,label,description,parent_id,extlink_id,creation_date;now,creation_user,creation_ip'); select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p;t'); select define_function_args('content_folder__delete','folder_id,cascade_p;f'); select define_function_args('content_folder__edit_name','folder_id,name,label,description'); select define_function_args('content_folder__move','folder_id,target_folder_id'); select define_function_args('content_folder__is_folder','folder_id'); select define_function_args('content_folder__is_sub_folder','folder_id,target_folder_id'); select define_function_args('content_folder__is_empty','folder_id'); select define_function_args('content_folder__register_content_type','folder_id,content_type,include_subtypes;f'); select define_function_args('content_folder__unregister_content_type','folder_id,content_type,include_subtypes;f'); select define_function_args('content_folder__is_registered','folder_id,content_type,include_subtypes;f'); select define_function_args('content_folder__get_label','folder_id'); select define_function_args('content_folder__get_index_page','folder_id'); select define_function_args('content_folder__is_root','folder_id'); select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p;t'); -- than the standard package_instantiate_object. So we don't bother calling define_function_args select define_function_args('content_item__get_root_folder','item_id'); select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob'); select define_function_args('content_item__is_published','item_id'); select define_function_args('content_item__is_publishable','item_id'); select define_function_args('content_item__is_valid_child','item_id,content_type,relation_tag'); select define_function_args('content_item__delete','item_id'); select define_function_args('content_item__edit_name','item_id,name'); select define_function_args('content_item__get_id','item_path,root_folder_id,resolve_index;f'); select define_function_args('content_item__get_path','item_id,root_folder_id'); select define_function_args('content_item__get_virtual_path','item_id,root_folder_id;-100'); select define_function_args('content_item__register_template','item_id,template_id,use_context'); select define_function_args('content_item__unregister_template','item_id,template_id,use_context'); select define_function_args('content_item__get_template','item_id,use_context'); select define_function_args('content_item__get_content_type','item_id'); select define_function_args('content_item__get_live_revision','item_id'); select define_function_args('content_item__set_live_revision','item_id,publish_status;ready'); select define_function_args('content_item__unset_live_revision','item_id'); select define_function_args('content_item__set_release_period','item_id,start_when,end_when'); select define_function_args('content_item__get_revision_count','item_id'); select define_function_args('content_item__get_context','item_id'); select define_function_args('content_item__move','item_id,target_folder_id,name'); select define_function_args('content_item__copy','item_id,target_folder_id,creation_user,creation_ip,name'); select define_function_args('content_item__get_latest_revision','item_id'); select define_function_args('content_item__get_best_revision','item_id'); select define_function_args('content_item__get_title','item_id,is_live;f'); select define_function_args('content_item__get_publish_date','item_id,is_live;f'); select define_function_args('content_item__is_subclass','object_type,supertype'); select define_function_args('content_item__relate','item_id,object_id,relation_tag;generic,order_n,relation_type;cr_item_rel'); select define_function_args('content_item__unrelate','rel_id'); select define_function_args('content_item__is_index_page','item_id,folder_id'); select define_function_args('content_item__get_parent_folder','item_id'); select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob'); select define_function_args('content_keyword__new','heading,description,parent_id,keyword_id,creation_date;now,creation_user,creation_ip,object_type;content_keyword'); -- than the standard package_instantiate_object. So we don't bother calling define_function_args select define_function_args('content_revision__copy_attributes','content_type,revision_id,copy_id'); select define_function_args('content_revision__copy','revision_id,copy_id,target_item_id,creation_user,creation_ip'); select define_function_args('content_revision__delete','revision_id'); select define_function_args('content_revision__get_number','revision_id'); select define_function_args('content_revision__revision_name','revision_id'); select define_function_args('content_revision__is_live','revision_id'); select define_function_args('content_revision__is_latest','revision_id'); select define_function_args('content_revision__content_copy','revision_id,revision_id_dest'); select define_function_args('content_revision__get_content','revision_id'); -- than the standard package_instantiate_object. So we don't bother calling define_function_args select define_function_args('content_symlink__new','name,label,target_id,parent_id,symlink_id,creation_date;now,creation_user,creation_ip'); select define_function_args('content_symlink__delete','symlink_id'); select define_function_args('content_symlink__is_symlink','item_id'); select define_function_args('content_symlink__copy','symlink_id,target_folder_id,creation_user,creation_ip,name'); select define_function_args('content_symlink__resolve','item_id'); select define_function_args('content_symlink__resolve_content_type','item_id'); select define_function_args('content_symlink__new','name,label,target_id,parent_id,symlink_id,creation_date;now,creation_user,creation_ip'); select define_function_args('content_template__new','name,parent_id,template_id,creation_date,creation_user,creation_ip'); select define_function_args('content_type__create_type','content_type,supertype;content_revision,pretty_name,pretty_plural,table_name,id_column;XXX,name_method'); select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f'); select define_function_args('content_type__create_attribute','content_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); select define_function_args('content_type__drop_attribute','content_type,attribute_name,drop_column;f'); select define_function_args('content_type__register_template','content_type,template_id,use_context,is_default;f'); select define_function_args('content_type__set_default_template','content_type,template_id,use_context'); select define_function_args('content_type__get_template','content_type,use_context'); select define_function_args('content_type__unregister_template','content_type,template_id,use_context'); select define_function_args('content_type__trigger_insert_statement','content_type'); select define_function_args('content_type__refresh_trigger','content_type'); select define_function_args('content_type__refresh_view','content_type'); select define_function_args('content_type__register_child_type','content_type,child_type,relation_tag;generic,min_n;0,max_n'); select define_function_args('content_type__unregister_child_type','content_type,child_type,relation_tag'); select define_function_args('content_type__register_relation_type','content_type,target_type,relation_tag;generic,min_n;0,max_n'); select define_function_args('content_type__unregister_relation_type','content_type,target_type,relation_tag;generic'); select define_function_args('content_type__register_mime_type','content_type,mime_type'); select define_function_args('content_type__unregister_mime_type','content_type,mime_type'); select define_function_args('content_type__is_content_type','content_type'); select define_function_args('content_type__rotate_template','template_id,content_type,use_context'); select define_function_args('content_type__create_type','content_type,supertype;content_revision,pretty_name,pretty_plural,table_name,id_column;XXX,name_method'); select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f'); select define_function_args('content_type__create_attribute','content_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); select define_function_args('content_type__drop_attribute','content_type,attribute_name,drop_column;f'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.4d5-5.1.4d6.sql0000644000175000017500000000056610171476702031612 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-01-06 -- @arch-tag: e086c05a-d0b7-498a-ac50-4ca5c36f3070 -- @cvs-id $Id: upgrade-5.1.4d5-5.1.4d6.sql,v 1.2 2005/01/13 13:55:14 jeffd Exp $ -- select define_function_args('content_template__new','name,parent_id,template_id,creation_date;now,creation_user,creation_ip,text,is_live;f'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.2d1-5.4.2d2.sql0000644000175000017500000000023011022567600031562 0ustar frankiefrankiealter table cr_folders add foreign key (folder_id) references cr_items(item_id) on delete cascade; drop trigger cr_folder_ins_up_ri_trg on cr_folders;openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0b1-5.3.0b2.sql0000644000175000017500000000104710622143333031555 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0b1-5.3.0b2.sql -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2007-01-03 -- @cvs-id $Id: upgrade-5.3.0b1-5.3.0b2.sql,v 1.2 2007/05/14 20:30:19 donb Exp $ -- update cr_revisions set content = '@text;noquote@' where revision_id = (select live_revision from cr_items ci, cr_type_template_map cm where cm.content_type = 'content_revision' and cm.use_context = 'public' and cm.is_default = 't' and ci.item_id=cm.template_id); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.0d2-5.1.0d3.sql0000644000175000017500000003373610024403017031563 0ustar frankiefrankieupdate acs_objects set title = (select label from cr_folders where folder_id = object_id), package_id = (select package_id from apm_packages where package_key = 'acs-content-repository') where object_type = 'content_folder' and object_id < 0; update acs_objects set title = (select label from cr_folders where folder_id = object_id), package_id = (select coalesce(package_id, acs_object__package_id(content_item__get_root_folder(folder_id))) from cr_folders where folder_id = object_id) where object_type = 'content_folder' and object_id > 0; update acs_objects set title = (select name from cr_items where item_id = object_id), package_id = acs_object__package_id(content_item__get_root_folder(object_id)) where object_type = 'content_item'; update acs_objects set title = (select title from cr_revisions where revision_id = object_id), package_id = (select acs_object__package_id(item_id) from cr_revisions where revision_id = object_id) where object_type in ('content_revision', 'image'); update acs_objects set title = (select label from cr_symlinks where symlink_id = object_id), package_id = (select acs_object__package_id(target_id) from cr_symlinks where symlink_id = object_id) where object_type = 'content_symlink'; update acs_objects set title = (select label from cr_extlinks where extlink_id = object_id), package_id = (select acs_object__package_id(parent_id) from cr_items where item_id = object_id) where object_type = 'content_extlink'; update acs_objects set title = (select heading from cr_keywords where keyword_id = object_id) where object_type = 'content_keyword'; update acs_objects set title = (select name from cr_items where item_id = object_id), package_id = (select acs_object__package_id(parent_id) from cr_items where item_id = object_id) where object_type = 'content_template'; update acs_objects set title = (select relation_tag || ': ' || item_id || ' - ' || related_object_id from cr_item_rels where rel_id = object_id), package_id = (select acs_object__package_id(item_id) from cr_item_rels where rel_id = object_id) where object_type = 'cr_item_rel'; update acs_objects set title = (select relation_tag || ': ' || parent_id || ' - ' || child_id from cr_child_rels where rel_id = object_id), package_id = (select acs_object__package_id(parent_id) from cr_child_rels where rel_id = object_id) where object_type = 'cr_item_child_rel'; \i ../content-item.sql \i ../content-revision.sql \i ../content-folder.sql \i ../content-template.sql \i ../content-symlink.sql \i ../content-extlink.sql \i ../content-keyword.sql create function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer,integer ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; new__package_id alias for $17; -- default null new__locale varchar default null; new__nls_language varchar default null; new__creation_date timestamptz default current_timestamp; new__context_id integer; v_item_id cr_items.item_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin new__context_id := new__parent_id; if p_package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_item_id := content_item__new ( new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''content_item'', ''image'', null, new__description, new__mime_type, new__nls_language, null, ''file'' -- storage_type, v_package_id ); -- update cr_child_rels to have the correct relation_tag update cr_child_rels set relation_tag = new__relation_tag where parent_id = new__parent_id and child_id = new__item_id and relation_tag = content_item__get_content_type(new__parent_id) || ''-'' || ''image''; v_revision_id := content_revision__new ( new__title, new__description, new__publish_date, new__mime_type, new__nls_language, null, v_item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, new__height, new__width); -- update revision with image file info update cr_revisions set content_length = new__file_size, content = new__path where revision_id = v_revision_id; -- is_live => ''t'' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if new__is_live = ''t'' then PERFORM content_item__set_live_revision (v_revision_id); end if; return v_item_id; end; ' language 'plpgsql'; create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; begin return image__new(new__name, new__parent_id, new__item_id, new__revision_id, new__mime_type, new__creation_user, new__creation_ip, new__relation_tag, new__title, new__description, new__is_live, new__publish_date, new__path, new__file_size, new__height, new__width, null ); end; ' language 'plpgsql'; -- DRB's version create function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer, integer) returns integer as ' declare p_name alias for $1; p_parent_id alias for $2; -- default null p_item_id alias for $3; -- default null p_revision_id alias for $4; -- default null p_mime_type alias for $5; -- default jpeg p_creation_user alias for $6; -- default null p_creation_ip alias for $7; -- default null p_title alias for $8; -- default null p_description alias for $9; -- default null p_storage_type alias for $10; p_content_type alias for $11; p_nls_language alias for $12; p_publish_date alias for $13; p_height alias for $14; p_width alias for $15; p_package_id alias for $16; -- default null v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if content_item__is_subclass(p_content_type, ''image'') = ''f'' then raise EXCEPTION ''-20000: image__new can only be called for an image type''; end if; if p_package_id is null then v_package_id := acs_object__package_id(p_parent_id); else v_package_id := p_package_id; end if; v_item_id := content_item__new ( p_name, p_parent_id, p_item_id, null, current_timestamp, p_creation_user, p_parent_id, p_creation_ip, ''content_item'', p_content_type, null, null, null, null, null, p_storage_type, v_package_id ); -- We will let the caller fill in the LOB data or file path. v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, v_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_item_id; end; ' language 'plpgsql'; create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer) returns integer as ' declare p_name alias for $1; p_parent_id alias for $2; -- default null p_item_id alias for $3; -- default null p_revision_id alias for $4; -- default null p_mime_type alias for $5; -- default jpeg p_creation_user alias for $6; -- default null p_creation_ip alias for $7; -- default null p_title alias for $8; -- default null p_description alias for $9; -- default null p_storage_type alias for $10; p_content_type alias for $11; p_nls_language alias for $12; p_publish_date alias for $13; p_height alias for $14; p_width alias for $15; begin return image__new(p_name, p_parent_id, p_item_id, p_revision_id, p_mime_type, p_creation_user, p_creation_ip, p_title, p_description, p_storage_type, p_content_type, p_nls_language, p_publish_date, p_height, p_width, null ); end; ' language 'plpgsql'; create or replace function image__new_revision(integer, integer, varchar, varchar, timestamptz, varchar, varchar, integer, varchar, integer, integer, integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; p_package_id alias for $12; v_revision_id integer; v_package_id acs_objects.package_id%TYPE; begin -- We will let the caller fill in the LOB data or file path. if p_package_id is null then v_package_id := acs_object__package_id(p_item_id); else v_package_id := p_package_id; end if; v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, p_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip, p_package_id ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_revision_id; end;' language 'plpgsql'; create or replace function image__new_revision(integer,integer,varchar,varchar,timestamptz,varchar,varchar, integer,varchar,integer,integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; v_revision_id integer; begin return image__new_revision(p_item_id, p_revision_id, p_title, p_description, p_publish_date, p_mime_type, p_nls_language, p_creation_user, p_creation_ip, p_height, p_width, p_revision_id, null ); end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0d3-5.3.0d4.sql0000644000175000017500000000430410510510667031570 0ustar frankiefrankie-- -- -- -- @author Victor Guerra (guerra@galileo.edu) -- @creation-date 2006-10-02 -- @arch-tag: c6a0a70c-5506-45e4-ba11-8e145f695c57 -- @cvs-id $Id: upgrade-5.3.0d3-5.3.0d4.sql,v 1.1 2006/10/03 16:37:11 victorg Exp $ -- select define_function_args('content_extlink__copy','extlink_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_extlink__copy ( integer, integer, integer, varchar, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_description cr_extlinks.description%TYPE; v_label cr_extlinks.label%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__extlink_id; -- can''t copy to the same folder select i.name, e.url, e.description, e.label into v_name, v_url, v_description, v_label from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy__extlink_id; -- copy to a different folder, or same folder if name -- is different if copy__target_folder_id != v_current_folder_id or ( v_name <> copy__name and copy__name is not null ) then if content_folder__is_registered(copy__target_folder_id, ''content_extlink'',''f'') = ''t'' then v_extlink_id := content_extlink__new( coalesce (copy__name, v_name), v_url, v_label, v_description, copy__target_folder_id, null, current_timestamp, copy__creation_user, copy__creation_ip, null ); end if; end if; end if; return 0; end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0d7-5.3.0d8.sql0000644000175000017500000000522210540513327031577 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0d7-5.3.0d8.sql -- -- @author Emmanuelle Raffenne (eraffenne@dia.uned.es) -- @creation-date 2006-12-15 -- @arch-tag: a67a9b16-d809-4da4-a47a-62f96f7e8d1e -- @cvs-id $Id: upgrade-5.3.0d7-5.3.0d8.sql,v 1.2 2006/12/15 12:36:39 emmar Exp $ -- create or replace function inline_0(varchar,varchar,varchar) returns integer as 'declare v_mime_type alias for $1; v_file_extension alias for $2; v_label alias for $3; crmt_rec record; cremtm_rec record; begin select into crmt_rec * from cr_mime_types where file_extension = v_file_extension; if not found then insert into cr_mime_types (mime_type, file_extension, label) values (v_mime_type, v_file_extension, v_label); else update cr_mime_types set mime_type=v_mime_type, label=v_label where file_extension=v_file_extension; end if; select into cremtm_rec * from cr_extension_mime_type_map where extension=v_file_extension; if not found then insert into cr_extension_mime_type_map (mime_type, extension) values (v_mime_type, v_file_extension); else update cr_extension_mime_type_map set mime_type=v_mime_type where extension=v_file_extension; end if; return 0; end; ' language 'plpgsql'; select inline_0('application/vnd.oasis.opendocument.text', 'odt', 'OpenDocument Text'); select inline_0('application/vnd.oasis.opendocument.text-template', 'ott','OpenDocument Text Template'); select inline_0('application/vnd.oasis.opendocument.text-web', 'oth', 'HTML Document Template'); select inline_0('application/vnd.oasis.opendocument.text-master', 'odm', 'OpenDocument Master Document'); select inline_0('application/vnd.oasis.opendocument.graphics', 'odg', 'OpenDocument Drawing'); select inline_0('application/vnd.oasis.opendocument.graphics-template', 'otg', 'OpenDocument Drawing Template'); select inline_0('application/vnd.oasis.opendocument.presentation', 'odp', 'OpenDocument Presentation'); select inline_0('application/vnd.oasis.opendocument.presentation-template', 'otp', 'OpenDocument Presentation Template'); select inline_0('application/vnd.oasis.opendocument.spreadsheet', 'ods', 'OpenDocument Spreadsheet'); select inline_0('application/vnd.oasis.opendocument.spreadsheet-template', 'ots', 'OpenDocument Spreadsheet Template'); select inline_0('application/vnd.oasis.opendocument.chart', 'odc', 'OpenDocument Chart'); select inline_0('application/vnd.oasis.opendocument.formula', 'odf', 'OpenDocument Formula'); select inline_0('application/vnd.oasis.opendocument.database', 'odb', 'OpenDocument Database'); select inline_0('application/vnd.oasis.opendocument.image', 'odi', 'OpenDocument Image'); drop function inline_0(varchar,varchar,varchar); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.7.0d1-5.7.0d2.sql0000644000175000017500000001173211452447070031602 0ustar frankiefrankie-- @author Victor Guerra (vguerra@gmail.com) -- @creation-date 2010-09-29 -- -- The following function get's rid of the foreign key constraint between cr_folders(folder_id) and cr_items(item_id), -- at somepoint ( upgrade-5.4.2d1-5.42d2 ) it was added using the statement "alter table add foreign key .. " -- which will add a constraint with name $1, since this is not for sure ( could have also other name assigned), we better look for the right constraint name -- to be deleted using pg_constraint and pg_class table create function inline_0 () returns integer as ' declare constraints RECORD; begin for constraints in select conname from pg_constraint con ,pg_class cla1, pg_class cla2 where con.contype = ''f'' and con.conrelid = cla1.oid and cla1.relname = ''cr_folders'' and con.confrelid = cla2.oid and cla2.relname = ''cr_items'' loop EXECUTE ''alter table cr_folders drop constraint '' || constraints.conname; end loop; return null; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); -- Now we create the foreign key constraint with the right name alter table cr_folders add constraint cr_folders_folder_id_fk foreign key (folder_id) references cr_items(item_id) on delete cascade; create or replace function content_template__new (varchar,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__template_id alias for $3; -- default null new__creation_date alias for $4; -- default now() new__creation_user alias for $5; -- default null new__creation_ip alias for $6; -- default null v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if new__parent_id is null then select c_root_folder_id into v_parent_id from content_template_globals; else v_parent_id := new__parent_id; end if; -- make sure we''re allowed to create a template in this folder if content_folder__is_folder(new__parent_id) = ''t'' and content_folder__is_registered(new__parent_id,''content_template'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow templates to be created''; else v_template_id := content_item__new ( new__name, v_parent_id, new__template_id, null, new__creation_date, new__creation_user, null, new__creation_ip, ''content_item'', ''content_template'', null, null, ''text/plain'', null, null, ''text'' ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end;' language 'plpgsql'; create or replace function content_template__new (varchar,integer,integer,timestamptz,integer,varchar,text,bool) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__template_id alias for $3; -- default null new__creation_date alias for $4; -- default now() new__creation_user alias for $5; -- default null new__creation_ip alias for $6; -- default null new__text alias for $7; -- default null new__is_live alias for $8; -- default ''f'' v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if new__parent_id is null then select c_root_folder_id into v_parent_id from content_template_globals; else v_parent_id := new__parent_id; end if; -- make sure we''re allowed to create a template in this folder if content_folder__is_folder(new__parent_id) = ''t'' and content_folder__is_registered(new__parent_id,''content_template'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow templates to be created''; else v_template_id := content_item__new ( new__template_id, -- new__item_id new__name, -- new__name v_parent_id, -- new__parent_id null, -- new__title new__creation_date, -- new__creation_date new__creation_user, -- new__creation_user null, -- new__context_id new__creation_ip, -- new__creation_ip new__is_live, -- new__is_live ''text/plain'', -- new__mime_type new__text, -- new__text ''text'', -- new__storage_type ''t'', -- new__security_inherit_p ''CR_FILES'', -- new__storage_area_key ''content_item'', -- new__item_subtype ''content_template'' -- new__content_type ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d15-5.2.0d16.sql0000644000175000017500000000144410240746004031732 0ustar frankiefrankie-- Add a few common mime types insert into cr_mime_types (label,mime_type,file_extension) select 'Audio - WAV','audio/wav', 'wav' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/wav'); insert into cr_mime_types (label,mime_type,file_extension) select 'Audio - MPEG','audio/mpeg', 'mpeg' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/mpeg'); insert into cr_mime_types (label, mime_type, file_extension) select 'Audio - MP3','audio/mp3', 'mp3' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/mp3'); insert into cr_mime_types (label,mime_type,file_extension) select 'Image - Progressive JPEG','image/pjpeg', 'pjpeg' from dual where not exists (select 1 from cr_mime_types where mime_type = 'image/pjpeg'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d11-5.2.0d12.sql0000644000175000017500000000011110175030104031702 0ustar frankiefrankiecreate index cr_revisions_publish_date_idx on cr_revisions(publish_date);openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.1d1-5.1.1d2.sql0000644000175000017500000000573010052153345031563 0ustar frankiefrankie-- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-05-05 -- @cvs-id $Id: upgrade-5.1.1d1-5.1.1d2.sql,v 1.2 2004/05/17 15:14:45 jeffd Exp $ -- -- fix typo in trigger function bug#1791 drop trigger cr_items_tree_update_tr on cr_items; drop function cr_items_tree_update_tr(); create function cr_items_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; p_id integer; v_rec record; clr_keys_p boolean default ''t''; begin if new.item_id = old.item_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) then return new; end if; for v_rec in select item_id from cr_items where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey) order by tree_sortkey LOOP if clr_keys_p then update cr_items set tree_sortkey = null where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); clr_keys_p := ''f''; end if; -- Lars: If the parent is not a cr_item, we treat it as if it was null. select parent.item_id into p_id from cr_items parent, cr_items child where child.item_id = v_rec.item_id and parent.item_id = child.parent_id; if p_id is null then -- Lars: Treat all items with a non-cr_item parent as one big pool wrt tree_sortkeys -- The old algorithm had tree_sortkeys start from zero for each different parent select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items child where child.parent_id not in (select item_id from cr_items); else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items where parent_id = p_id; select tree_sortkey into v_parent_sk from cr_items where item_id = p_id; end if; update cr_items set tree_sortkey = tree_next_key(v_parent_sk, v_max_value) where item_id = v_rec.item_id; end LOOP; return new; end;' language 'plpgsql'; create trigger cr_items_tree_update_tr after update on cr_items for each row execute procedure cr_items_tree_update_tr (); -- Fix typo in function and invalid parameter reference. Bug #1793 create or replace function content_item__move (integer,integer) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; begin perform content_item__move( move__item_id, move__target_folder_id, NULL ); return null; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.1.2-4.5.sql0000644000175000017500000000142207527505425030763 0ustar frankiefrankie-- packages/acs-content-repository/sql/upgrade/upgrade-4.1.2-4.5.sql -- -- @author vinod@kurup.com -- @creation-date 2002-05-15 -- @cvs-id $Id: upgrade-4.1.2-4.5.sql,v 1.2 2002/08/17 17:42:45 vinodk Exp $ -- -- fixes bug #1502 http://openacs.org/sdm/one-baf.tcl?baf_id=1502 drop function content_keyword__delete(integer); create function content_keyword__delete (integer) returns integer as ' declare delete__keyword_id alias for $1; v_rec record; begin for v_rec in select item_id from cr_item_keyword_map where keyword_id = delete__keyword_id LOOP PERFORM content_keyword__item_unassign(v_rec.item_id, delete__keyword_id); end LOOP; PERFORM acs_object__delete(delete__keyword_id); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.1-4.1.2.sql0000644000175000017500000000053307265761241030760 0ustar frankiefrankie-- packages/acs-content-repository/sql/upgrade/upgrade-4.1-4.1.2.sql -- -- @author teeters@arsdigita.com -- @creation-date 2000-03-06 -- @cvs-id $Id: upgrade-4.1-4.1.2.sql,v 1.1 2001/04/14 05:39:45 danw Exp $ -- -- upgrade script. -- reload all packages. -- This should be run manually. @../../../acs-content-repository/sql/packages-create.sql openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.2d4-5.1.2d5.sql0000644000175000017500000001200310171476701031570 0ustar frankiefrankie-- There was a typo in this routine ... create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if new__title is null then v_title := new__name; else v_title := new__title; end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.0.0b4-5.0.0b5.sql0000644000175000017500000000422310005232277031555 0ustar frankiefrankie-- this one tried to assign an aliased variable bug 1281. -- create or replace function content_keyword__is_assigned (integer,integer,varchar) returns boolean as ' declare is_assigned__item_id alias for $1; is_assigned__keyword_id alias for $2; is_assigned__recurse alias for $3; -- default ''none'' v_ret boolean; v_is_assigned__recurse varchar; begin if is_assigned__recurse is null then v_is_assigned__recurse := ''none''; else v_is_assigned__recurse := is_assigned__recurse; end if; -- Look for an exact match if v_is_assigned__recurse = ''none'' then return count(*) > 0 from cr_item_keyword_map where item_id = is_assigned__item_id and keyword_id = is_assigned__keyword_id; end if; -- Look from specific to general if v_is_assigned__recurse = ''up'' then return count(*) > 0 where exists (select 1 from (select keyword_id from cr_keywords c, cr_keywords c2 where c2.keyword_id = is_assigned__keyword_id and c.tree_sortkey between c2.tree_sortkey and tree_right(c2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; if v_is_assigned__recurse = ''down'' then return count(*) > 0 where exists (select 1 from (select k2.keyword_id from cr_keywords k1, cr_keywords k2 where k1.keyword_id = is_assigned__keyword_id and k1.tree_sortkey between k2.tree_sortkey and tree_right(k2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; -- Tried none, up and down - must be an invalid parameter raise EXCEPTION ''-20000: The recurse parameter to content_keyword.is_assigned should be \\\'none\\\', \\\'up\\\' or \\\'down\\\'''; return null; end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0b1-5.2.0b2.sql0000644000175000017500000000241410440426443031556 0ustar frankiefrankiecreate or replace function content_item__move (integer,integer,varchar) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; begin if move__target_folder_id is null then raise exception ''attempt to move item_id % to null folder_id'', move__item_id; end if; if content_folder__is_folder(move__item_id) = ''t'' then PERFORM content_folder__move(move__item_id, move__target_folder_id); elsif content_folder__is_folder(move__target_folder_id) = ''t'' then if content_folder__is_registered(move__target_folder_id, content_item__get_content_type(move__item_id),''f'') = ''t'' and content_folder__is_registered(move__target_folder_id, content_item__get_content_type(content_symlink__resolve(move__item_id)),''f'') = ''t'' then -- update the parent_id for the item update cr_items set parent_id = move__target_folder_id, name = coalesce(move__name, name) where item_id = move__item_id; end if; if move__name is not null then update acs_objects set title = move__name where object_id = move__item_id; end if; end if; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0b5-5.2.0b6.sql0000644000175000017500000002121210440426443031563 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-10-25 -- @arch-tag: 14af9d7e-7d34-4db0-aa12-6560f61d2142 -- @cvs-id $Id: upgrade-5.2.0b5-5.2.0b6.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- select define_function_args('content_item__set_live_revision','revision_id,publish_status;ready'); create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; new__package_id alias for $20; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if new__package_id is null and v_parent_id != 0 then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true new__package_id alias for $11; -- default null v_package_id acs_objects.object_id%TYPE; v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if new__context_id is null then v_context_id := new__parent_id; else v_context_id := new__context_id; end if; -- parent_id = 0 means that this is a mount point if new__parent_id != 0 and content_folder__is_folder(new__parent_id) and content_folder__is_registered(new__parent_id,''content_folder'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow subfolders to be created''; return null; else v_package_id := new__package_id; if new__parent_id is not null and new__parent_id not in (-100,-200) and new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(new__parent_id)); end if; v_folder_id := content_item__new( new__folder_id, new__name, new__parent_id, null, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''f'', ''text/plain'', null, ''text'', new__security_inherit_p, ''CR_FILES'', ''content_folder'', ''content_folder'', v_package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, new__label, new__description, v_package_id ); -- set the correct object title update acs_objects set title = new__label where object_id = v_folder_id; -- inherit the attributes of the parent folder if new__parent_id is not null then insert into cr_folder_type_map select v_folder_id as folder_id, content_type from cr_folder_type_map where folder_id = new__parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = ''t'' where folder_id = new__parent_id; return v_folder_id; end if; return v_folder_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d3-5.2.0d4.sql0000644000175000017500000000032610070036026031557 0ustar frankiefrankie-- define additional plpgsql select define_function_args('content_item__delete','item_id'); select define_function_args('content_item__copy','item_id,target_folder_id,creation_user,creation_ip;null,name;null'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d7-5.2.0d8.sql0000644000175000017500000000056110115176520031574 0ustar frankiefrankie-- Whoever added package_id forgot to add it to this call... select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob,package_id'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.0d4-5.4.0d5.sql0000644000175000017500000006060610673446134031612 0ustar frankiefrankie-- changes from content-item.sql create or replace function content_item__get_root_folder (integer) returns integer as ' declare get_root_folder__item_id alias for $1; -- default null v_folder_id cr_folders.folder_id%TYPE; begin if get_root_folder__item_id is NULL or get_root_folder__item_id in (-4,-100,-200) then select c_root_folder_id from content_item_globals into v_folder_id; else select i2.item_id into v_folder_id from cr_items i1, cr_items i2 where i2.parent_id = -4 and i1.item_id = get_root_folder__item_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey); if NOT FOUND then raise EXCEPTION '' -20000: Could not find a root folder for item ID %. Either the item does not exist or its parent value is corrupted.'', get_root_folder__item_id; end if; end if; return v_folder_id; end;' language 'plpgsql' stable; create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; new__package_id alias for $20; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') new__package_id alias for $17; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', coalesce(new__title,new__name), new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if new__title is null then v_title := new__name; else v_title := new__title; end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null new__package_id alias for $16; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, ''lob'' ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null or new__relation_tag = '''' then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- create the revision if data or title is not null if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, null, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( integer, varchar, integer, varchar, timestamptz, integer, integer, varchar, boolean, varchar, text, varchar, boolean, varchar,varchar,varchar,integer) returns integer as ' declare new__item_id alias for $1; --default null new__name alias for $2; new__parent_id alias for $3; -- default null new__title alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__is_live alias for $9; -- default ''f'' new__mime_type alias for $10; new__text alias for $11; -- default null new__storage_type alias for $12; -- check in (''text'', ''file'') new__security_inherit_p alias for $13; -- default ''t'' new__storage_area_key alias for $14; -- default ''CR_FILES'' new__item_subtype alias for $15; new__content_type alias for $16; new__package_id alias for $17; -- default null new__description varchar default null; new__relation_tag varchar default null; new__nls_language varchar default null; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, new__security_inherit_p, v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type, storage_area_key ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type, new__storage_area_key ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', new__creation_date, null, null, v_parent_id, ''f'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__get_id (varchar,integer,boolean) returns integer as ' declare get_id__item_path alias for $1; get_id__root_folder_id alias for $2; -- default null get_id__resolve_index alias for $3; -- default ''f'' v_item_path varchar; v_root_folder_id cr_items.item_id%TYPE; get_id__parent_id integer; child_id integer; start_pos integer default 1; end_pos integer; counter integer default 1; item_name varchar; begin if get_id__root_folder_id is null then select c_root_folder_id from content_item_globals into v_root_folder_id; else v_root_folder_id := get_id__root_folder_id; end if; -- If the request path is the root, then just return the root folder if get_id__item_path = ''/'' then return v_root_folder_id; end if; -- Remove leading, trailing spaces, leading slashes v_item_path := rtrim(ltrim(trim(get_id__item_path), ''/''), ''/''); get_id__parent_id := v_root_folder_id; -- if parent_id is a symlink, resolve it get_id__parent_id := content_symlink__resolve(get_id__parent_id); LOOP end_pos := instr(v_item_path, ''/'', 1, counter); if end_pos = 0 then item_name := substr(v_item_path, start_pos); else item_name := substr(v_item_path, start_pos, end_pos - start_pos); counter := counter + 1; end if; select item_id into child_id from cr_items where parent_id = get_id__parent_id and name = item_name; if NOT FOUND then return null; end if; exit when end_pos = 0; get_id__parent_id := child_id; -- if parent_id is a symlink, resolve it get_id__parent_id := content_symlink__resolve(get_id__parent_id); start_pos := end_pos + 1; end loop; if get_id__resolve_index = ''t'' then -- if the item is a folder and has an index page, then return if content_folder__is_folder(child_id ) = ''t'' and content_folder__get_index_page(child_id) is not null then child_id := content_folder__get_index_page(child_id); end if; end if; return child_id; end;' language 'plpgsql' stable; -- changes from content-template.sql create or replace function content_template__get_root_folder() returns integer as ' declare v_folder_id integer; begin select c_root_folder_id from content_template_globals into v_folder_id; return v_folder_id; end;' language 'plpgsql' immutable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.0d8-5.4.0d9.sql0000644000175000017500000002632110700147642031607 0ustar frankiefrankie--- the update script below was added between d7 and d8 half a day after the change. --- In case, one missed the upgrade, we add it to the current update again. create or replace function content_folder__del (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; -- default ''f'' v_count integer; v_child_row record; v_parent_id integer; v_path varchar; v_folder_sortkey varbit; begin if p_cascade_p = ''f'' then select count(*) into v_count from cr_items where parent_id = delete__folder_id; -- check if the folder contains any items if v_count > 0 then v_path := content_item__get_path(delete__folder_id, null); raise EXCEPTION ''-20000: Folder ID % (%) cannot be deleted because it is not empty.'', delete__folder_id, v_path; end if; else -- delete children select into v_folder_sortkey tree_sortkey from cr_items where item_id=delete__folder_id; for v_child_row in select item_id, tree_sortkey, name from cr_items where tree_sortkey between v_folder_sortkey and tree_right(v_folder_sortkey) and tree_sortkey != v_folder_sortkey order by tree_sortkey desc loop if content_folder__is_folder(v_child_row.item_id) then perform content_folder__delete(v_child_row.item_id); else perform content_item__delete(v_child_row.item_id); end if; end loop; end if; PERFORM content_folder__unregister_content_type( delete__folder_id, ''content_revision'', ''t'' ); delete from cr_folder_type_map where folder_id = delete__folder_id; select parent_id into v_parent_id from cr_items where item_id = delete__folder_id; raise notice ''deleteing folder %'',delete__folder_id; PERFORM content_item__delete(delete__folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = ''f'' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = ''content_folder''); return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; -- default ''f'' begin PERFORM content_folder__del(delete__folder_id,p_cascade_p); return 0; end;' language 'plpgsql'; select define_function_args('content_folder__move','folder_id,target_folder_id,name;null'); create or replace function content_folder__move (integer,integer,varchar) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; -- default null v_source_folder_id integer; v_valid_folders_p integer; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move__target_folder_id or folder_id = move__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.move - Not valid folder(s)''; end if; if move__folder_id = content_item__get_root_folder(null) or move__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.move - Cannot move root folder''; end if; if move__target_folder_id = move__folder_id then raise EXCEPTION ''-20000: content_folder.move - Cannot move a folder to itself''; end if; if content_folder__is_sub_folder(move__folder_id, move__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder is subfolder''; end if; if content_folder__is_registered(move__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder does not allow subfolders''; end if; select parent_id into v_source_folder_id from cr_items where item_id = move__folder_id; -- update the parent_id for the folder update cr_items set parent_id = move__target_folder_id, name = coalesce ( move__name, name ) where item_id = move__folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = ''f'' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = ''content_folder''); -- update the destination update cr_folders set has_child_folders = ''t'' where folder_id = move__target_folder_id; return 0; end;' language 'plpgsql'; select define_function_args('content_type__unregister_relation_type','content_type,target_type,relation_tag;null'); -- make it same as in oracle select define_function_args('content_type__rotate_template','template_id,v_content_type,use_context'); -- new changes: documenting defaults for the arguments -- -- note, that i changed the default value in function_args from "lob" to null, -- since apprarently the default in cr_items is "text" (therefore, "lob" was incorrect). -- However, the default in Oracle is "lob", i changed this here to "null" select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;null,package_id'); create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__data alias for $16; -- default null new__relation_tag alias for $17; -- default null new__is_live alias for $18; -- default ''f'' new__storage_type alias for $19; -- default null new__package_id alias for $20; -- default null v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then select c_root_folder_id from content_item_globals into v_parent_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = -4 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != -4 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != -4 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, new__package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != -4 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, new__package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, new__package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.5-4.6.sql0000644000175000017500000002520410171476701030625 0ustar frankiefrankie-- Upgrade script -- -- @author vinod@kurup.com -- @created 2002-10-06 -- fixes bug #1502 http://openacs.org/sdm/one-baf.tcl?baf_id=1502 -- This bug was actually fixed in 4.5, but it didn't get merged in properly -- so let's recreate the function to be sure that it's right create or replace function content_keyword__delete (integer) returns integer as ' declare delete__keyword_id alias for $1; v_rec record; begin for v_rec in select item_id from cr_item_keyword_map where keyword_id = delete__keyword_id LOOP PERFORM content_keyword__item_unassign(v_rec.item_id, delete__keyword_id); end LOOP; PERFORM acs_object__delete(delete__keyword_id); return 0; end;' language 'plpgsql'; -- add mime_types insert into cr_mime_types(label, mime_type, file_extension) select 'Binary', 'application/octet-stream', 'bin' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/octet-stream'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft Word', 'application/msword', 'doc' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/msword'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft Excel', 'application/msexcel', 'xls' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/msexcel'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft PowerPoint', 'application/powerpoint', 'ppt' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/powerpoint'); insert into cr_mime_types(label, mime_type, file_extension) select 'Microsoft Project', 'application/msproject', 'mpp' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/msproject'); insert into cr_mime_types(label, mime_type, file_extension) select 'PostScript', 'application/postscript', 'ps' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/postscript'); insert into cr_mime_types(label, mime_type, file_extension) select 'Adobe Illustrator', 'application/x-illustrator', 'ai' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-illustrator'); insert into cr_mime_types(label, mime_type, file_extension) select 'Adobe PageMaker', 'application/x-pagemaker', 'p65' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-pagemaker'); insert into cr_mime_types(label, mime_type, file_extension) select 'Filemaker Pro', 'application/filemaker', 'fm' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/filemaker'); insert into cr_mime_types(label, mime_type, file_extension) select 'Image Pict', 'image/x-pict', 'pic' from dual where not exists (select 1 from cr_mime_types where mime_type = 'image/x-pict'); insert into cr_mime_types(label, mime_type, file_extension) select 'Photoshop', 'application/x-photoshop', 'psd' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/x-photoshop'); insert into cr_mime_types(label, mime_type, file_extension) select 'Acrobat', 'application/pdf', 'pdf' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/pdf'); insert into cr_mime_types(label, mime_type, file_extension) select 'Video Quicktime', 'video/quicktime', 'mov' from dual where not exists (select 1 from cr_mime_types where mime_type = 'video/quicktime'); insert into cr_mime_types(label, mime_type, file_extension) select 'Video MPEG', 'video/mpeg', 'mpg' from dual where not exists (select 1 from cr_mime_types where mime_type = 'video/mpeg'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio AIFF', 'audio/aiff', 'aif' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/aiff'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio Basic', 'audio/basic', 'au' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/basic'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio Voice', 'audio/voice', 'voc' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/voice'); insert into cr_mime_types(label, mime_type, file_extension) select 'Audio Wave', 'audio/wave', 'wav' from dual where not exists (select 1 from cr_mime_types where mime_type = 'audio/wave'); insert into cr_mime_types(label, mime_type, file_extension) select 'Archive Zip', 'application/zip', 'zip' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/zip'); insert into cr_mime_types(label, mime_type, file_extension) select 'Archive Tar', 'application/z-tar', 'tar' from dual where not exists (select 1 from cr_mime_types where mime_type = 'application/z-tar'); -- new version of content_image__new create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamp,varchar,integer,integer,integer ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; new__locale varchar default null; new__nls_language varchar default null; new__creation_date timestamp default now(); new__context_id integer; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin new__context_id := new__parent_id; v_item_id := content_item__new ( new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''content_item'', ''image'', null, new__description, new__mime_type, new__nls_language, null, ''file'' -- storage_type ); -- update cr_child_rels to have the correct relation_tag update cr_child_rels set relation_tag = new__relation_tag where parent_id = new__parent_id and child_id = new__item_id and relation_tag = content_item__get_content_type(new__parent_id) || ''-'' || ''image''; v_revision_id := content_revision__new ( new__title, new__description, new__publish_date, new__mime_type, new__nls_language, null, v_item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip ); insert into images (image_id, height, width) values (v_revision_id, new__height, new__width); -- update revision with image file info update cr_revisions set content_length = new__file_size, content = new__path where revision_id = v_revision_id; -- is_live => ''t'' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if new__is_live = ''t'' then PERFORM content_item__set_live_revision (v_revision_id); end if; return v_item_id; end; ' language 'plpgsql'; -- new stuff to index only live revisions from davb -- change triggers to index only live revisions --DaveB 2002-09-26 -- triggers queue search interface to modify search index after content -- changes. drop function content_search__itrg() cascade; create or replace function content_search__itrg () returns opaque as ' begin if (select live_revision from cr_items where item_id=new.item_id) = new.revision_id then perform search_observer__enqueue(new.revision_id,''INSERT''); end if; return new; end;' language 'plpgsql'; drop function content_search__dtrg() cascade; create or replace function content_search__dtrg () returns opaque as ' begin select into v_live_revision live_revision from cr_items where item_id=old.item_id; if old.revision_id=v_live_revision then perform search_observer__enqueue(old.revision_id,''DELETE''); end if; return old; end;' language 'plpgsql'; drop function content_search__utrg() cascade; create or replace function content_search__utrg () returns opaque as ' declare v_live_revision integer; begin select into v_live_revision live_revision from cr_items where item_id=old.revision_id; if old.revision_id=v_live_revision then insert into search_observer_queue ( object_id, event ) values ( old.revision_id, ''UPDATE'' ); end if; return new; end;' language 'plpgsql'; -- we need new triggers on cr_items to index when a live revision -- changes create trigger content_search__itrg after insert on cr_revisions for each row execute procedure content_search__itrg (); create trigger content_search__dtrg after delete on cr_revisions for each row execute procedure content_search__dtrg (); create trigger content_search__utrg after update on cr_revisions for each row execute procedure content_search__utrg (); -- LARS: REMOVED -- content-type.sql create or replace function content_type__trigger_insert_statement (varchar) returns varchar as ' declare trigger_insert_statement__content_type alias for $1; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; vals varchar default ''''; attr_rec record; begin select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = trigger_insert_statement__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; vals := vals || '', new.'' || attr_rec.attribute_name; end LOOP; return ''insert into '' || v_table_name || '' ( '' || v_id_column || cols || '' ) values (cr_dummy.val'' || vals || '')''; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.6.4-4.6.5.sql0000644000175000017500000001254507661402103031132 0ustar frankiefrankiecreate or replace function content_item__copy2 (integer,integer,integer,varchar) returns integer as ' declare copy2__item_id alias for $1; copy2__target_folder_id alias for $2; copy2__creation_user alias for $3; copy2__creation_ip alias for $4; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered boolean; v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder__is_folder(copy2__item_id) = ''t'' then PERFORM content_folder__copy( copy2__item_id, copy2__target_folder_id, copy2__creation_user, copy2__creation_ip ); -- call content_symlink.copy if the item is a symlink else if content_symlink__is_symlink(copy2__item_id) = ''t'' then PERFORM content_symlink__copy( copy2__item_id, copy2__target_folder_id, copy2__creation_user, copy2__creation_ip ); -- call content_extlink.copy if the item is an url else if content_extlink__is_extlink(copy2__item_id) = ''t'' then PERFORM content_extlink__copy( copy2__item_id, copy2__target_folder_id, copy2__creation_user, copy2__creation_ip ); -- make sure the target folder is really a folder else if content_folder__is_folder(copy2__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy2__item_id; -- can''t copy to the same folder if copy2__target_folder_id != v_current_folder_id then select content_type, name, locale, coalesce(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy2__item_id; -- make sure the content type of the item is registered to the folder v_is_registered := content_folder__is_registered( copy2__target_folder_id, v_content_type, ''f'' ); if v_is_registered = ''t'' then -- create the new content item v_item_id := content_item__new( v_name, copy2__target_folder_id, null, v_locale, now(), copy2__creation_user, null, copy2__creation_ip, ''content_item'', v_content_type, null, null, ''text/plain'', null, null, v_storage_type ); -- get the latest revision of the old item select latest_revision into v_old_revision_id from cr_items where item_id = copy2__item_id; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision__copy ( v_old_revision_id, null, v_item_id, copy2__creation_user, copy2__creation_ip ); end if; end if; end if; end if; end if; end if; end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_extlink__copy (integer,integer,integer,varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_description cr_extlinks.description%TYPE; v_label cr_extlinks.label%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__extlink_id; -- can''t copy to the same folder if copy__target_folder_id != v_current_folder_id then select i.name, e.url, e.description, e.label into v_name, v_url, v_description, v_label from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy__extlink_id; if content_folder__is_registered(copy__target_folder_id, ''content_extlink'',''f'') = ''t'' then v_extlink_id := content_extlink__new( v_name, v_url, v_label, v_description, copy__target_folder_id, null, current_timestamp, copy__creation_user, copy__creation_ip ); end if; end if; end if; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d9-5.2.0d10.sql0000644000175000017500000002463210440426443031657 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-01-05 -- @arch-tag: 5be8fd4b-0259-4ded-905a-37cb95b7fa9f -- @cvs-id $Id: upgrade-5.2.0d9-5.2.0d10.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- -- procedure delete select define_function_args('content_folder__del','folder_id,cascade_p;f'); create or replace function content_folder__del (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; v_count integer; v_child_row record; v_parent_id integer; v_path varchar; v_folder_sortkey varbit; begin if p_cascade_p = ''f'' then select count(*) into v_count from cr_items where parent_id = delete__folder_id; -- check if the folder contains any items if v_count > 0 then v_path := content_item__get_path(delete__folder_id, null); raise EXCEPTION ''-20000: Folder ID % (%) cannot be deleted because it is not empty.'', delete__folder_id, v_path; end if; else -- delete children select into v_folder_sortkey tree_sortkey from cr_items where item_id=delete__folder_id; for v_child_row in select item_id, tree_sortkey, name from cr_items where tree_sortkey between v_folder_sortkey and tree_right(v_folder_sortkey) and tree_sortkey != v_folder_sortkey order by tree_sortkey desc loop if content_folder__is_folder(v_child_row.item_id) then perform content_folder__delete(v_child_row.item_id); else perform content_item__delete(v_child_row.item_id); end if; end loop; end if; PERFORM content_folder__unregister_content_type( delete__folder_id, ''content_revision'', ''t'' ); delete from cr_folder_type_map where folder_id = delete__folder_id; select parent_id into v_parent_id from cr_items where item_id = delete__folder_id; raise notice ''deleteing folder %'',delete__folder_id; PERFORM content_item__delete(delete__folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = ''f'' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = ''content_folder''); return 0; end;' language 'plpgsql'; select define_function_args('content_folder__delete','folder_id,cascade_p;f'); create or replace function content_folder__delete (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; begin PERFORM content_folder__del(delete__folder_id,p_cascade_p); return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer) returns integer as ' declare delete__folder_id alias for $1; v_count integer; v_parent_id integer; v_path varchar; begin return content_folder__del( delete__folder_id, ''f'' ); end;' language 'plpgsql'; -- procedure delete select define_function_args('content_revision__del','revision_id'); create or replace function content_revision__delete (integer) returns integer as ' declare delete__revision_id alias for $1; v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; v_rec record; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = delete__revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = delete__revision_id then for v_rec in select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> delete__revision_id order by o.creation_date desc LOOP v_latest_revision := v_rec.revision_id; exit; end LOOP; if NOT FOUND then v_latest_revision := null; end if; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end if; -- Clear live revision if v_live_revision = delete__revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = delete__revision_id or new_revision = delete__revision_id; -- Delete the revision PERFORM acs_object__delete(delete__revision_id); return 0; end;' language 'plpgsql'; select define_function_args('content_revision__delete','revision_id'); create or replace function content_revision__delete (integer) returns integer as ' declare delete__revision_id alias for $1; begin PERFORM content_revision__del(delete__revision_id); return 0; end;' language 'plpgsql'; -- item select define_function_args('content_item__del','item_id'); create or replace function content_item__del (integer) returns integer as ' declare delete__item_id alias for $1; -- v_wf_cases_val record; v_symlink_val record; v_revision_val record; v_rel_val record; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- raise NOTICE ''Deleting associated workflows...''; -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in select -- case_id -- from -- wf_cases -- where -- object_id = delete__item_id -- LOOP -- PERFORM workflow_case__delete(v_wf_cases_val.case_id); -- end loop; raise NOTICE ''Deleting symlinks...''; -- 2) delete all symlinks to this item for v_symlink_val in select symlink_id from cr_symlinks where target_id = delete__item_id LOOP PERFORM content_symlink__delete(v_symlink_val.symlink_id); end loop; raise NOTICE ''Unscheduling item...''; delete from cr_release_periods where item_id = delete__item_id; raise NOTICE ''Unsetting live and latest revisions...''; update cr_items set live_revision = null, latest_revision = null where item_id = delete__item_id; raise NOTICE ''Deleting associated revisions...''; -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = delete__item_id; for v_revision_val in select revision_id from cr_revisions where item_id = delete__item_id LOOP PERFORM acs_object__delete(v_revision_val.revision_id); end loop; raise NOTICE ''Deleting associated item templates...''; -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = delete__item_id; raise NOTICE ''Deleting item relationships...''; -- Delete all relations on this item for v_rel_val in select rel_id from cr_item_rels where item_id = delete__item_id or related_object_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); end loop; raise NOTICE ''Deleting child relationships...''; for v_rel_val in select rel_id from cr_child_rels where child_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); end loop; raise NOTICE ''Deleting parent relationships...''; for v_rel_val in select rel_id, child_id from cr_child_rels where parent_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); PERFORM content_item__delete(v_rel_val.child_id); end loop; raise NOTICE ''Deleting associated permissions...''; -- 5) delete associated permissions delete from acs_permissions where object_id = delete__item_id; raise NOTICE ''Deleting keyword associations...''; -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = delete__item_id; raise NOTICE ''Deleting associated comments...''; -- 7) delete associated comments PERFORM journal_entry__delete_for_object(delete__item_id); -- context_id debugging loop --for v_error_val in c_error_cur loop -- raise NOTICE ''ID='' || v_error_val.object_id || '' TYPE='' -- || v_error_val.object_type); --end loop; raise NOTICE ''Deleting content item...''; PERFORM acs_object__delete(delete__item_id); return 0; end;' language 'plpgsql'; select define_function_args('content_item__delete','item_id'); create or replace function content_item__delete (integer) returns integer as ' declare delete__item_id alias for $1; begin PERFORM content_item__del (delete__item_id); return 0; end;' language 'plpgsql'; -- template select define_function_args('content_template__del','template_id'); create or replace function content_template__del (integer) returns integer as ' declare delete__template_id alias for $1; begin delete from cr_type_template_map where template_id = delete__template_id; delete from cr_item_template_map where template_id = delete__template_id; delete from cr_templates where template_id = delete__template_id; PERFORM content_item__delete(delete__template_id); return 0; end;' language 'plpgsql'; select define_function_args('content_template__delete','template_id'); create or replace function content_template__delete (integer) returns integer as ' declare delete__template_id alias for $1; begin PERFORM content_template__delete(delete__template_id); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.4d2-5.1.4d3.sql0000644000175000017500000001017510231440650031567 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-12-22 -- @arch-tag: f76ec7ce-6834-4bff-b134-ad1953aad38e -- @cvs-id $Id: upgrade-5.1.4d2-5.1.4d3.sql,v 1.3 2005/04/20 11:48:56 eduardop Exp $ -- -- add package_id. for some reason content_folder__new did not support setting -- cr_folders.package_id create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin perform content_folder__new ( new__name, new__label, new__description, new__parent_id, new__context_id, new__folder_id, new__creation_date, new__creation_user, new__creation_ip, new__security_inherit_p, null ); return null; end;' language 'plpgsql'; select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p;t,package_id'); create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true new__package_id alias for $11; -- default null v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if new__context_id is null then v_context_id := new__parent_id; else v_context_id := new__context_id; end if; -- parent_id = 0 means that this is a mount point if new__parent_id != 0 and content_folder__is_registered(new__parent_id,''content_folder'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow subfolders to be created''; return null; else v_folder_id := content_item__new( new__folder_id, new__name, new__parent_id, null, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''f'', ''text/plain'', null, ''text'', new__security_inherit_p, ''CR_FILES'', ''content_folder'', ''content_folder''); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, new__label, new__description, new__package_id ); -- inherit the attributes of the parent folder if new__parent_id is not null then insert into cr_folder_type_map select v_folder_id as folder_id, content_type from cr_folder_type_map where folder_id = new__parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = ''t'' where folder_id = new__parent_id; return v_folder_id; end if; return null; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.4d6-5.1.4d7.sql0000644000175000017500000000051110171476702031602 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-01-06 -- @arch-tag: 15e5da0f-cfe5-48a3-a9df-80150cc47864 -- @cvs-id $Id: upgrade-5.1.4d6-5.1.4d7.sql,v 1.2 2005/01/13 13:55:14 jeffd Exp $ -- select define_function_args('content_item__set_live_revision','revision_id,publish_status;ready');openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d18-5.2.0d19.sql0000644000175000017500000000771610540362710031751 0ustar frankiefrankie-- -- -- -- @author Victor Guerra (guerra@galileo.edu) -- @creation-date 2006-07-13 -- @arch-tag: 5d9217e6-cdc0-4fa3-81c7-2f51eb04780e -- @cvs-id $Id: upgrade-5.2.0d18-5.2.0d19.sql,v 1.2 2006/12/15 00:01:12 donb Exp $ -- -- this script was orignally created by daveb -- upgrade-5.2.0d15-5.2.0a1.sql -- patch#548 bug#1937 select define_function_args('content_revision__copy_attributes','content_type,revision_id,copy_id'); create or replace function content_revision__copy_attributes (varchar,integer,integer) returns integer as ' declare copy_attributes__content_type alias for $1; copy_attributes__revision_id alias for $2; copy_attributes__copy_id alias for $3; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; attr_rec record; begin if copy_attributes__content_type is null or copy_attributes__revision_id is null or copy_attributes__copy_id is null then raise exception ''content_revision__copy_attributes called with null % % %'',copy_attributes__content_type,copy_attributes__revision_id, copy_attributes__copy_id; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = copy_attributes__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; end loop; execute ''insert into '' || v_table_name || ''('' || v_id_column || cols || '')'' || '' select '' || copy_attributes__copy_id || '' as '' || v_id_column || cols || '' from '' || v_table_name || '' where '' || v_id_column || '' = '' || copy_attributes__revision_id; return 0; end;' language 'plpgsql'; -- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-06-05 -- @arch-tag: 16725764-0b5d-4e98-a75d-dc77bf3141de -- @cvs-id $Id: upgrade-5.2.0d18-5.2.0d19.sql,v 1.2 2006/12/15 00:01:12 donb Exp $ -- -- patch#548 bug#1937 select define_function_args('content_revision__copy_attributes','content_type,revision_id,copy_id'); create or replace function content_revision__copy_attributes (varchar,integer,integer) returns integer as ' declare copy_attributes__content_type alias for $1; copy_attributes__revision_id alias for $2; copy_attributes__copy_id alias for $3; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; attr_rec record; begin if copy_attributes__content_type is null or copy_attributes__revision_id is null or copy_attributes__copy_id is null then raise exception ''content_revision__copy_attributes called with null % % %'',copy_attributes__content_type,copy_attributes__revision_id, copy_attributes__copy_id; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = copy_attributes__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; end loop; execute ''insert into '' || v_table_name || ''('' || v_id_column || cols || '')'' || '' select '' || copy_attributes__copy_id || '' as '' || v_id_column || cols || '' from '' || v_table_name || '' where '' || v_id_column || '' = '' || copy_attributes__revision_id; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0b2-5.3.0b3.sql0000644000175000017500000002736510622143333031572 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0b2-5.3.0b3.sql -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2007-01-10 -- @cvs-id $Id: upgrade-5.3.0b2-5.3.0b3.sql,v 1.2 2007/05/14 20:30:19 donb Exp $ -- create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null -- lob id new__data alias for $6; new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null new__package_id alias for $12; -- default null v_revision_id integer; v_package_id acs_objects.package_id%TYPE; v_content_type acs_object_types.object_type%TYPE; begin v_content_type := content_item__get_content_type(new__item_id); if new__package_id is null then v_package_id := acs_object__package_id(new__item_id); else v_package_id := new__package_id; end if; v_revision_id := acs_object__new( new__revision_id, v_content_type, new__creation_date, new__creation_user, new__creation_ip, new__item_id, ''t'', new__title, v_package_id ); -- binary data is stored in cr_revisions using Dons lob hack. -- This routine only inserts the lob id. It would need to be followed by -- ns_pg blob_dml from within a tcl script to actually insert the lob data. -- After the lob data is inserted, the content_length needs to be updated -- as well. -- DanW, 2001-05-10. insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, lob, item_id, content_length ) values ( v_revision_id, new__title, new__description, new__mime_type, new__publish_date, new__nls_language, new__data, new__item_id, 0 ); return v_revision_id; end;' language 'plpgsql'; create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null -- lob id new__data alias for $6; new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, new__nls_language, new__data, new__item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, null ); end;' language 'plpgsql'; create or replace function content_revision__new(varchar,varchar,timestamptz,varchar,text,integer,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__text alias for $5; -- default '' '' new__item_id alias for $6; new__package_id alias for $7; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, null, new__text, new__item_id, null, now(), null, null, null, new__package_id ); end;' language 'plpgsql'; create or replace function content_revision__new(varchar,varchar,timestamptz,varchar,text,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__text alias for $5; -- default '' '' new__item_id alias for $6; begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, null, new__text, new__item_id, null, now(), null, null, null, null ); end;' language 'plpgsql'; create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,text,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null new__text alias for $6; -- default '' '' new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, new__nls_language, new__text, new__item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, null, null ); end;' language 'plpgsql'; create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,text,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null new__text alias for $6; -- default '' '' new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null new__content_length alias for $12; -- default null begin return content_revision__new(new__title, new__description, new__publish_date, new__mime_type, new__nls_language, new__text, new__item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, new__content_length, null ); end;' language 'plpgsql'; -- function new create or replace function content_revision__new (varchar,varchar,timestamptz,varchar,varchar,text,integer,integer,timestamptz,integer,varchar,integer,integer) returns integer as ' declare new__title alias for $1; new__description alias for $2; -- default null new__publish_date alias for $3; -- default now() new__mime_type alias for $4; -- default ''text/plain'' new__nls_language alias for $5; -- default null new__text alias for $6; -- default '' '' new__item_id alias for $7; new__revision_id alias for $8; -- default null new__creation_date alias for $9; -- default now() new__creation_user alias for $10; -- default null new__creation_ip alias for $11; -- default null new__content_length alias for $12; -- default null new__package_id alias for $13; -- default null v_revision_id integer; v_package_id acs_objects.package_id%TYPE; v_content_type acs_object_types.object_type%TYPE; v_storage_type cr_items.storage_type%TYPE; v_length cr_revisions.content_length%TYPE; begin v_content_type := content_item__get_content_type(new__item_id); if new__package_id is null then v_package_id := acs_object__package_id(new__item_id); else v_package_id := new__package_id; end if; v_revision_id := acs_object__new( new__revision_id, v_content_type, new__creation_date, new__creation_user, new__creation_ip, new__item_id, ''t'', new__title, v_package_id ); select storage_type into v_storage_type from cr_items where item_id = new__item_id; if v_storage_type = ''text'' then v_length := length(new__text); else v_length := coalesce(new__content_length,0); end if; -- text data is stored directly in cr_revisions using text datatype. insert into cr_revisions ( revision_id, title, description, mime_type, publish_date, nls_language, content, item_id, content_length ) values ( v_revision_id, new__title, new__description, new__mime_type, new__publish_date, new__nls_language, new__text, new__item_id, v_length ); return v_revision_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.5.0d1-5.5.0d2.sql0000644000175000017500000001011211051355307031561 0ustar frankiefrankiecreate or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and lower(ot2.table_name) <> ''acs_objects'' and lower(ot2.table_name) <> ''cr_revisions'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP if join_rec.table_name is not null then cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end if; end loop; select table_name into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 57 then raise exception ''Table name cannot be longer than 57 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i'' || '' CASCADE''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.7.0d2-5.7.0d3.sql0000644000175000017500000000775111530060570031603 0ustar frankiefrankie select define_function_args('content_type__create_type','content_type,supertype;content_revision,pretty_name,pretty_plural,table_name,id_column,name_method'); create or replace function content_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare create_type__content_type alias for $1; create_type__supertype alias for $2; -- default ''content_revision'' create_type__pretty_name alias for $3; create_type__pretty_plural alias for $4; create_type__table_name alias for $5; create_type__id_column alias for $6; -- default ''XXX'' create_type__name_method alias for $7; -- default null v_temp_p boolean; v_supertype_table acs_object_types.table_name%TYPE; begin if (create_type__supertype <> ''content_revision'') and (create_type__content_type <> ''content_revision'') then select count(*) > 0 into v_temp_p from acs_object_type_supertype_map where object_type = create_type__supertype and ancestor_type = ''content_revision''; if not v_temp_p then raise EXCEPTION ''-20000: supertype % must be a subtype of content_revision'', create_type__supertype; end if; end if; select count(*) = 0 into v_temp_p from pg_class where relname = lower(create_type__table_name); PERFORM acs_object_type__create_type ( create_type__content_type, create_type__pretty_name, create_type__pretty_plural, create_type__supertype, create_type__table_name, create_type__id_column, null, ''f'', null, create_type__name_method, v_temp_p, ''f'' ); PERFORM content_type__refresh_view(create_type__content_type); return 0; end;' language 'plpgsql'; select define_function_args('content_type__create_attribute','content_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); create or replace function content_type__create_attribute (varchar,varchar,varchar,varchar,varchar,integer,varchar,varchar) returns integer as ' declare create_attribute__content_type alias for $1; create_attribute__attribute_name alias for $2; create_attribute__datatype alias for $3; create_attribute__pretty_name alias for $4; create_attribute__pretty_plural alias for $5; -- default null create_attribute__sort_order alias for $6; -- default null create_attribute__default_value alias for $7; -- default null create_attribute__column_spec alias for $8; -- default ''text'' v_attr_id acs_attributes.attribute_id%TYPE; v_table_name acs_object_types.table_name%TYPE; v_column_exists boolean; begin -- add the appropriate column to the table select table_name into v_table_name from acs_object_types where object_type = create_attribute__content_type; if NOT FOUND then raise EXCEPTION ''-20000: Content type % does not exist in content_type.create_attribute'', create_attribute__content_type; end if; select count(*) > 0 into v_column_exists from pg_class c, pg_attribute a where c.relname::varchar = v_table_name and c.oid = a.attrelid and a.attname = lower(create_attribute__attribute_name); v_attr_id := acs_attribute__create_attribute ( create_attribute__content_type, create_attribute__attribute_name, create_attribute__datatype, create_attribute__pretty_name, create_attribute__pretty_plural, null, null, create_attribute__default_value, 1, 1, create_attribute__sort_order, ''type_specific'', ''f'', not v_column_exists, null, null, null, null, null, create_attribute__column_spec ); PERFORM content_type__refresh_view(create_attribute__content_type); return v_attr_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d14-5.2.0d15.sql0000644000175000017500000005017310221252771031735 0ustar frankiefrankie-- JCD: Propigate title rather than name to acs_objects title field. select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob,package_id'); create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; new__package_id alias for $20; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__data, new__relation_tag, new__is_live, new__storage_type, null); return v_item_id; end;' language 'plpgsql'; -- create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') new__package_id alias for $17; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', coalesce(new__title,new__name), v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if new__title is null then v_title := new__name; else v_title := new__title; end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__storage_type, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null new__package_id alias for $16; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, ''lob'' ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null or new__relation_tag = '''' then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- create the revision if data or title is not null if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); elsif new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, null, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.5d1-5.1.5d2.sql0000644000175000017500000000322410207353612031570 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-01-13 -- @arch-tag: aa216b34-3586-400c-a3d3-50ca61ea5855 -- @cvs-id $Id: upgrade-5.1.5d1-5.1.5d2.sql,v 1.2 2005/02/24 13:32:58 jeffd Exp $ -- create or replace function content_folder__is_sub_folder (integer,integer) returns boolean as ' declare is_sub_folder__folder_id alias for $1; is_sub_folder__target_folder_id alias for $2; v_parent_id integer default 0; v_sub_folder_p boolean default ''f''; v_rec record; begin if is_sub_folder__folder_id = content_item__get_root_folder(null) or is_sub_folder__folder_id = content_template__get_root_folder() then v_sub_folder_p := ''t''; end if; -- select -- parent_id -- from -- cr_items -- connect by -- prior parent_id = item_id -- start with -- item_id = is_sub_folder__target_folder_id for v_rec in select i2.parent_id from cr_items i1, cr_items i2 where i1.item_id = is_sub_folder__target_folder_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) order by i2.tree_sortkey desc LOOP v_parent_id := v_rec.parent_id; exit when v_parent_id = is_sub_folder__folder_id; -- we did not find the folder, reset v_parent_id v_parent_id := 0; end LOOP; if v_parent_id != 0 then v_sub_folder_p := ''t''; end if; return v_sub_folder_p; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d10-5.2.0d11.sql0000644000175000017500000000056610167303754031735 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-01-06 -- @arch-tag: a39c54fa-1262-4d8c-8ceb-5f5bed0089ee -- @cvs-id $Id: upgrade-5.2.0d10-5.2.0d11.sql,v 1.1 2005/01/06 18:48:12 daveb Exp $ -- select define_function_args('content_template__new','name,parent_id,template_id,creation_date;now,creation_user,creation_ip,text,is_live;f');openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.1d2-5.1.1d3.sql0000644000175000017500000000372510074522377031600 0ustar frankiefrankiecreate or replace function content_item__edit_name (integer,varchar) returns integer as ' declare edit_name__item_id alias for $1; edit_name__name alias for $2; exists_id integer; begin select item_id into exists_id from cr_items where name = edit_name__name and parent_id = (select parent_id from cr_items where item_id = edit_name__item_id); if NOT FOUND then update cr_items set name = edit_name__name where item_id = edit_name__item_id; else if exists_id != edit_name__item_id then raise EXCEPTION ''-20000: An item with the name % already exists in this directory.'', edit_name__name; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_folder__edit_name (integer,varchar,varchar,varchar) returns integer as ' declare edit_name__folder_id alias for $1; edit_name__name alias for $2; -- default null edit_name__label alias for $3; -- default null edit_name__description alias for $4; -- default null v_name_already_exists_p integer; begin if edit_name__name is not null and edit_name__name != '''' then PERFORM content_item__edit_name(edit_name__folder_id, edit_name__name); end if; if edit_name__label is not null and edit_name__label != '''' and edit_name__description is not null and edit_name__description != '''' then update cr_folders set label = edit_name__label, description = edit_name__description where folder_id = edit_name__folder_id; else if(edit_name__label is not null and edit_name__label != '''') and (edit_name__description is null or edit_name__description = '''') then update cr_folders set label = edit_name__label where folder_id = edit_name__folder_id; end if; end if; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.0.0-5.1.0d1.sql0000644000175000017500000010010210440426443031322 0ustar frankiefrankie-- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-01-22 -- @cvs-id $Id -- add optional name parameter to copy and move functions create or replace function content_item__copy (integer,integer,integer,varchar) returns integer as ' declare item_id alias for $1; target_folder_id alias for $2; creation_user alias for $3; creation_ip alias for $4; -- default null copy_id cr_items.item_id%TYPE; begin copy_id := content_item__copy2(item_id, target_folder_id, creation_user, creation_ip); return 0; end;' language 'plpgsql'; -- copy a content item to a target folder -- 1) make sure we are not copying the item to an invalid location: -- that is, the destination folder exists, is a valid folder, -- and is not the current folder -- 2) make sure the content type of the content item is registered -- with the current folder -- 3) create a new item with no revisions in the target folder -- 4) copy the latest revision from the original item to the new item (if any) create or replace function content_item__copy2 (integer,integer,integer,varchar) returns integer as ' declare copy2__item_id alias for $1; copy2__target_folder_id alias for $2; copy2__creation_user alias for $3; copy2__creation_ip alias for $4; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered boolean; v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin perform content_item__copy ( copy2__item_id, copy2__target_folder_id, copy2__creation_user, copy2__creation_ip, null ); return copy2__item_id; end;' language 'plpgsql'; create or replace function content_item__copy ( integer, integer, integer, varchar, varchar ) returns integer as ' declare copy__item_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered boolean; v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder__is_folder(copy__item_id) = ''t'' then PERFORM content_folder__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_symlink.copy if the item is a symlink else if content_symlink__is_symlink(copy__item_id) = ''t'' then PERFORM content_symlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_extlink.copy if the item is an url else if content_extlink__is_extlink(copy__item_id) = ''t'' then PERFORM content_extlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- make sure the target folder is really a folder else if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__item_id; select content_type, name, locale, coalesce(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy__item_id; -- copy to a different folder, or allow copy to the same folder -- with a different name if copy__target_folder_id != v_current_folder_id or ( v_name != copy__name and copy__name is not null ) then -- make sure the content type of the item is registered to the folder v_is_registered := content_folder__is_registered( copy__target_folder_id, v_content_type, ''f'' ); if v_is_registered = ''t'' then -- create the new content item v_item_id := content_item__new( coalesce (copy__name, v_name), copy__target_folder_id, null, v_locale, now(), copy__creation_user, null, copy__creation_ip, ''content_item'', v_content_type, null, null, ''text/plain'', null, null, v_storage_type ); select latest_revision into v_old_revision_id from cr_items where item_id = copy__item_id; end if; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision__copy ( v_old_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); end if; end if; end if; end if; end if; end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__move (integer,integer) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; begin perform content_item__move( move__item_id, move__target_folder_id, move__name ); return null; end;' language 'plpgsql'; create or replace function content_item__move (integer,integer,varchar) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; begin if move__target_folder_id is null then raise exception ''attempt to move item_id % to null folder_id'', move__item_id; end if; if content_folder__is_folder(move__item_id) = ''t'' then PERFORM content_folder__move(move__item_id, move__target_folder_id,move__name); else if content_folder__is_folder(move__target_folder_id) = ''t'' then if content_folder__is_registered(move__target_folder_id, content_item__get_content_type(move__item_id),''f'') = ''t'' and content_folder__is_registered(move__target_folder_id, content_item__get_content_type(content_symlink__resolve(move__item_id)),''f'') = ''t'' then -- update the parent_id for the item update cr_items set parent_id = move__target_folder_id, name = coalesce(move__name, name) where item_id = move__item_id; end if; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_extlink__copy ( integer, integer, integer, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink__copy ( copy__extlink_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, NULL ); return 0; end;' language 'plpgsql' stable; create or replace function content_extlink__copy ( integer, integer, integer, varchar, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_description cr_extlinks.description%TYPE; v_label cr_extlinks.label%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__extlink_id; -- can''t copy to the same folder select i.name, e.url, e.description, e.label into v_name, v_url, v_description, v_label from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy__extlink_id; -- copy to a different folder, or same folder if name -- is different if copy__target_folder_id != v_current_folder_id or ( v_name <> copy_name and copy_name is not null ) then if content_folder__is_registered(copy__target_folder_id, ''content_extlink'',''f'') = ''t'' then v_extlink_id := content_extlink__new( coalesce (copy__name, v_name), v_url, v_label, v_description, copy__target_folder_id, null, current_timestamp, copy__creation_user, copy__creation_ip ); end if; end if; end if; return 0; end;' language 'plpgsql' stable; create or replace function content_folder__copy (integer,integer,integer,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin v_new_folder_id := content_folder__copy ( copy__folder_id, copy__target_folder_id, copy__creation_user, copy_creation_ip, NULL ); return v_new_folder_id; end;' language 'plpgsql'; create or replace function content_folder__copy (integer,integer,integer,varchar,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy__target_folder_id or folder_id = copy__folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy__folder_id; if copy__folder_id = content_item__get_root_folder(null) or copy__folder_id = content_template__get_root_folder() or copy__target_folder_id = copy__folder_id then v_valid_folders_p := 0; end if; -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy__folder_id; if v_valid_folders_p = 2 then if content_folder__is_sub_folder(copy__folder_id, copy__target_folder_id) != ''t'' or v_current_folder_id != copy__target_folder_id or (v_name != copy__name and copy__name is not null) then -- create the new folder v_new_folder_id := content_folder__new( coalesce (copy__name, v_name), v_label, v_description, copy__target_folder_id, null, null, now(), copy__creation_user, copy__creation_ip ); -- copy attributes of original folder insert into cr_folder_type_map select v_new_folder_id as folder_id, content_type from cr_folder_type_map map where folder_id = copy__folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in select item_id from cr_items where parent_id = copy__folder_id LOOP raise notice ''COPYING item %'',v_folder_contents_val.item_id; PERFORM content_item__copy( v_folder_contents_val.item_id, v_new_folder_id, copy__creation_user, copy__creation_ip ); end loop; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; v_count integer; v_child_row record; v_parent_id integer; v_path varchar; v_folder_sortkey varbit; begin if p_cascade_p = ''f'' then select count(*) into v_count from cr_items where parent_id = delete__folder_id; -- check if the folder contains any items if v_count > 0 then v_path := content_item__get_path(delete__folder_id, null); raise EXCEPTION ''-20000: Folder ID % (%) cannot be deleted because it is not empty.'', delete__folder_id, v_path; end if; else -- delete children select into v_folder_sortkey tree_sortkey from cr_items where item_id=delete__folder_id; for v_child_row in select item_id, tree_sortkey, name from cr_items where tree_sortkey between v_folder_sortkey and tree_right(v_folder_sortkey) and tree_sortkey != v_folder_sortkey order by tree_sortkey desc loop if content_folder__is_folder(v_child_row.item_id) then perform content_folder__delete(v_child_row.item_id); else perform content_item__delete(v_child_row.item_id); end if; end loop; end if; PERFORM content_folder__unregister_content_type( delete__folder_id, ''content_revision'', ''t'' ); delete from cr_folder_type_map where folder_id = delete__folder_id; select parent_id into v_parent_id from cr_items where item_id = delete__folder_id; raise notice ''deleteing folder %'',delete__folder_id; PERFORM content_item__delete(delete__folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = ''f'' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = ''content_folder''); return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer) returns integer as ' declare delete__folder_id alias for $1; v_count integer; v_parent_id integer; v_path varchar; begin return content_folder__delete( delete__folder_id, ''f'' ); end;' language 'plpgsql'; create or replace function content_folder__move (integer,integer) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; begin perform content_folder__move ( move__folder_id, move__target_folder_id, NULL ); return null; end;' language 'plpgsql'; create or replace function content_folder__move (integer,integer,varchar) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; v_source_folder_id integer; v_valid_folders_p integer; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move__target_folder_id or folder_id = move__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.move - Not valid folder(s)''; end if; if move__folder_id = content_item__get_root_folder(null) or move__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.move - Cannot move root folder''; end if; if move__target_folder_id = move__folder_id then raise EXCEPTION ''-20000: content_folder.move - Cannot move a folder to itself''; end if; if content_folder__is_sub_folder(move__folder_id, move__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder is subfolder''; end if; if content_folder__is_registered(move__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder does not allow subfolders''; end if; select parent_id into v_source_folder_id from cr_items where item_id = move__folder_id; -- update the parent_id for the folder update cr_items set parent_id = move__target_folder_id, name = coalesce ( move__name, name ) where item_id = move__folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = ''f'' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = ''content_folder''); -- update the destination update cr_folders set has_child_folders = ''t'' where folder_id = move__target_folder_id; return 0; end;' language 'plpgsql'; select define_function_args('content_extlink__new','name,url,label,description,parent_id,extlink_id,creation_date;now,creation_user,creation_ip'); select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p'); select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob'); select define_function_args('content_keyword__new','heading,description,parent_id,keyword_id,creation_date;now,creation_user,creation_ip,object_type;content_keyword'); select define_function_args('content_symlink__new','name,label,target_id,parent_id,symlink_id,creation_date;now,creation_user,creation_ip'); select define_function_args('content_template__new','name,parent_id,template_id,creation_date,creation_user,creation_ip'); select define_function_args('content_type__create_type','content_type,supertype;content_revision,pretty_name,pretty_plural,table_name,id_colum;XXX,name_method'); select define_function_args('content_type__create_attribute','content_type,attribute_name,datatype,pretty_name,pretty_plural,sort_order,default_value,column_spec;text'); -- DRB: PG version now verifies that the new content_type's supertype is indeed content_revision -- or one of its descendants. create or replace function content_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare create_type__content_type alias for $1; create_type__supertype alias for $2; -- default ''content_revision'' create_type__pretty_name alias for $3; create_type__pretty_plural alias for $4; create_type__table_name alias for $5; create_type__id_column alias for $6; -- default ''XXX'' create_type__name_method alias for $7; -- default null v_temp_p boolean; v_supertype_table acs_object_types.table_name%TYPE; begin if (create_type__supertype <> ''content_revision'') and (create_type__content_type <> ''content_revision'') then select count(*) > 0 into v_temp_p from acs_object_type_supertype_map where object_type = create_type__supertype and ancestor_type = ''content_revision''; if not v_temp_p then raise EXCEPTION ''-20000: supertype % must be a subtype of content_revision'', create_type__supertype; end if; end if; -- create the attribute table if not already created select count(*) > 0 into v_temp_p from pg_class where relname = lower(create_type__table_name); if NOT v_temp_p then select table_name into v_supertype_table from acs_object_types where object_type = create_type__supertype; execute ''create table '' || create_type__table_name || '' ('' || create_type__id_column || '' integer primary key references '' || v_supertype_table || '')''; end if; PERFORM acs_object_type__create_type ( create_type__content_type, create_type__pretty_name, create_type__pretty_plural, create_type__supertype, create_type__table_name, create_type__id_column, null, ''f'', null, create_type__name_method ); PERFORM content_type__refresh_view(create_type__content_type); return 0; end;' language 'plpgsql'; select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f'); select define_function_args('content_type__drop_attribute','content_type,attribute_name,drop_column;f'); -- PG 7.3 now supports drop column ... create or replace function content_type__drop_attribute (varchar,varchar,boolean) returns integer as ' declare drop_attribute__content_type alias for $1; drop_attribute__attribute_name alias for $2; drop_attribute__drop_column alias for $3; -- default ''f'' v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute__content_type and a.object_type = drop_attribute__content_type and a.attribute_name = drop_attribute__attribute_name; if NOT FOUND then raise EXCEPTION ''-20000: Attribute %:% does not exist in content_type.drop_attribute'', drop_attribute__content_type, drop_attribute__attribute_name; end if; -- Drop the attribute PERFORM acs_attribute__drop_attribute(drop_attribute__content_type, drop_attribute__attribute_name); -- FIXME: postgresql does not support drop column. -- Drop the column if neccessary if drop_attribute__drop_column then execute ''alter table '' || v_table || '' drop column '' || drop_attribute__attribute_name || ''cascade''; -- exception when others then -- raise_application_error(-20000, ''Unable to drop column '' || -- v_table || ''.'' || attribute_name || '' in content_type.drop_attribute''); end if; PERFORM content_type__refresh_view(drop_attribute__content_type); return 0; end;' language 'plpgsql'; create or replace function content_type__is_content_type (varchar) returns boolean as ' declare is_content_type__object_type alias for $1; v_is_content_type boolean; begin if is_content_type__object_type = ''content_revision'' then v_is_content_type := ''t''; else select count(*) > 0 into v_is_content_type from acs_object_type_supertype_map where object_type = is_content_type__object_type and ancestor_type = ''content_revision''; end if; return v_is_content_type; end;' language 'plpgsql' stable; /***********************************************************************/ /* Lars: Make trigger handle parent_id's that are not cr_items */ /***********************************************************************/ drop trigger cr_items_tree_insert_tr on cr_items; drop function cr_items_tree_insert_tr(); create function cr_items_tree_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; v_parent_id integer; begin -- Lars: If the parent is not a cr_item, we treat it as if it was null. select item_id into v_parent_id from cr_items where item_id = new.parent_id; if v_parent_id is null then -- Lars: Treat all items with a non-cr_item parent as one big pool wrt tree_sortkeys -- The old algorithm had tree_sortkeys start from zero for each different parent select max(tree_leaf_key_to_int(child.tree_sortkey)) into v_max_value from cr_items child where child.parent_id not in (select item_id from cr_items); else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items where parent_id = new.parent_id; select tree_sortkey into v_parent_sk from cr_items where item_id = new.parent_id; end if; new.tree_sortkey := tree_next_key(v_parent_sk, v_max_value); return new; end;' language 'plpgsql'; create trigger cr_items_tree_insert_tr before insert on cr_items for each row execute procedure cr_items_tree_insert_tr (); drop trigger cr_items_tree_update_tr on cr_items; drop function cr_items_tree_update_tr(); create function cr_items_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; p_id integer; v_rec record; clr_keys_p boolean default ''t''; begin if new.item_id = old.item_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) then return new; end if; for v_rec in select item_id from cr_items where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey) order by tree_sortkey LOOP if clr_keys_p then update cr_items set tree_sortkey = null where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); clr_keys_p := ''f''; end if; -- Lars: If the parent is not a cr_item, we treat it as if it was null. select parent.item_id into p_id from cr_items parent, cr_items child where child.item_id = v_rec.item_id and parent.item_id = child.parent_id; if p_id is null then -- Lars: Treat all items with a non-cr_item parent as one big pool wrt tree_sortkeys -- The old algorithm had tree_sortkeys start from zero for each different parent select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items child where child.parent_id not in (select item_id from cr_items); else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items where parent_id = p_id; select tree_sortkey into v_parent_sk from cr_items where item_id = p_id; end if; update cr_items set tree_sortkey = tree_next_key(v_parent_sk, v_max_value) where item_id = v_rec.item_id; end LOOP; return new; end;' language 'plpgsql'; create trigger cr_items_tree_update_tr after update on cr_items for each row execute procedure cr_items_tree_update_tr (); -- Now update all the existing tree_sortkeys -- This will cause the entire set of values to be shifted, -- i.e. it will no longer start at zero, but at max(tree_sortkey)+1. -- Don't know how to avoid this. update cr_items set parent_id = parent_id; -- OpenOffice MIME types insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Spreadsheet' , 'application/vnd.sun.xml.calc', 'sxc'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Spreadsheet Template', 'application/vnd.sun.xml.calc.template', 'stc'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Draw', 'application/vnd.sun.xml.draw', 'sxd'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Draw Template', 'application/vnd.sun.xml.draw.template', 'std'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Impress', 'application/vnd.sun.xml.impress', 'sxi'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Impress Template', 'application/vnd.sun.xml.impress.template', 'sti'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Math', 'application/vnd.sun.xml.math', 'sxm'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer', 'application/vnd.sun.xml.writer', 'sxw'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer Global', 'application/vnd.sun.xml.writer.global', 'sxg'); insert into cr_mime_types (label,mime_type,file_extension) values ('OpenOffice Writer Template', 'application/vnd.sun.xml.writer.template', 'stw'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxc', 'application/vnd.sun.xml.calc'); insert into cr_extension_mime_type_map (extension, mime_type) values ('stc', 'application/vnd.sun.xml.calc.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxd', 'application/vnd.sun.xml.draw'); insert into cr_extension_mime_type_map (extension, mime_type) values ('std', 'application/vnd.sun.xml.draw.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxi', 'application/vnd.sun.xml.impress'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sti', 'application/vnd.sun.xml.impress.template'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxm', 'application/vnd.sun.xml.math'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxw', 'application/vnd.sun.xml.writer'); insert into cr_extension_mime_type_map (extension, mime_type) values ('sxg', 'application/vnd.sun.xml.writer.global'); insert into cr_extension_mime_type_map (extension, mime_type) values ('stw', 'application/vnd.sun.xml.writer.template'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.2d1-5.1.2d2.sql0000644000175000017500000000354110100417375031563 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-07-18 -- @arch-tag: e3c4c07f-a3cc-480f-a06f-7ffd30e5606f -- @cvs-id $Id: upgrade-5.1.2d1-5.1.2d2.sql,v 1.2 2004/07/24 08:34:05 jeffd Exp $ -- create or replace function content_type__drop_attribute (varchar,varchar,boolean) returns integer as ' declare drop_attribute__content_type alias for $1; drop_attribute__attribute_name alias for $2; drop_attribute__drop_column alias for $3; -- default ''f'' v_attr_id acs_attributes.attribute_id%TYPE; v_table acs_object_types.table_name%TYPE; begin -- Get attribute information select upper(t.table_name), a.attribute_id into v_table, v_attr_id from acs_object_types t, acs_attributes a where t.object_type = drop_attribute__content_type and a.object_type = drop_attribute__content_type and a.attribute_name = drop_attribute__attribute_name; if NOT FOUND then raise EXCEPTION ''-20000: Attribute %:% does not exist in content_type.drop_attribute'', drop_attribute__content_type, drop_attribute__attribute_name; end if; -- Drop the attribute PERFORM acs_attribute__drop_attribute(drop_attribute__content_type, drop_attribute__attribute_name); -- Drop the column if neccessary if drop_attribute__drop_column then execute ''alter table '' || v_table || '' drop column '' || drop_attribute__attribute_name || '' cascade''; -- exception when others then -- raise_application_error(-20000, ''Unable to drop column '' || -- v_table || ''.'' || attribute_name || '' in content_type.drop_attribute''); end if; PERFORM content_type__refresh_view(drop_attribute__content_type); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0a1-5.2.0a2.sql0000644000175000017500000002045310440426443031557 0ustar frankiefrankie-- procedure refresh_trigger select define_function_args('content_type__refresh_trigger','content_type'); create or replace function content_type__refresh_trigger (varchar) returns integer as ' declare refresh_trigger__content_type alias for $1; rule_text text default ''''; v_table_name acs_object_types.table_name%TYPE; type_rec record; begin -- get the table name for the content type (determines view name) select table_name into v_table_name from acs_object_types where object_type = refresh_trigger__content_type; --=================== start building rule code ======================= rule_text := ''create rule '' || v_table_name || ''_r as on insert to '' || v_table_name || ''i do instead ( update cr_dummy set val = ( select content_revision__new( new.title, new.description, now(), new.mime_type, new.nls_language, case when new.text is null then new.data else new.text end, content_symlink__resolve(new.item_id), new.revision_id, now(), new.creation_user, new.creation_ip, new.object_package_id )); ''; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_trigger__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level desc LOOP rule_text := rule_text || '' '' || content_type__trigger_insert_statement(type_rec.object_type) || '';''; end loop; -- end building the rule definition code rule_text := rule_text || '' );''; --================== done building rule code ======================= -- drop the old rule if rule_exists(v_table_name || ''_r'', v_table_name || ''i'') then -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; end if; -- create the new rule for inserts on the content type execute rule_text; return null; end;' language 'plpgsql'; -- procedure refresh_view select define_function_args('content_type__refresh_view','content_type'); create or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin -- select -- table_name, id_column, level -- from -- acs_object_types -- where -- object_type <> ''acs_object'' -- and -- object_type <> ''content_revision'' -- start with -- object_type = refresh_view__content_type -- connect by -- object_type = prior supertype for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and lower(ot2.table_name) <> ''acs_objects'' and lower(ot2.table_name) <> ''cr_revisions'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end loop; select table_name into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 25 then raise exception ''Table name cannot be longer than 25 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; -- recreate all views and triggers create function inline_0 () returns integer as ' declare ct RECORD; begin for ct in select t.object_type,t.table_name from acs_object_type_supertype_map m, acs_object_types t where t.object_type = m.object_type and m.ancestor_type = ''content_revision'' loop if table_exists(ct.table_name) = ''t'' then perform content_type__refresh_view (ct.object_type); end if; end loop; return null; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0b2-5.2.0b3.sql0000644000175000017500000001476510440426443031574 0ustar frankiefrankie------------------------------------------------------------ -- Upgrade to enhance the perfomance of the acs-content-repository when adding / editing an -- cr_item, special fix for postgres to avoid using max() which is quite slow. -- Now update tree_sortkey in the process fix dups and add max_child_sortkey -- -- We need a table for the new tree_sortkey -- -- Get the root nodes specially -- Both cases, when the parent is 0 but is an cr_item, and when the parent is a non cr_item CREATE TABLE tmp_crnewtree as SELECT item_id, int_to_tree_key(item_id+1000) as tree_sortkey FROM cr_items where parent_id = 0 UNION SELECT cr.item_id, int_to_tree_key(cr.parent_id+1000) || int_to_tree_key(cr.item_id+1000) as tree_sortkey FROM cr_items cr where cr.parent_id <> 0 and not exists (select 1 from cr_items cri where cri.item_id = cr.parent_id) ; --now add an index on item_id since we need it for the next function... create unique index tmp_crnewtree_idx on tmp_crnewtree(item_id); create or replace function __tmp_crnewtree() returns integer as ' DECLARE ngen integer; nrows integer; totrows integer; rec record; childkey varbit; last_parent integer; BEGIN totrows := 0; ngen := 0; LOOP ngen := ngen + 1; nrows := 0; last_parent := -9999; -- loop over those which have a parent in crnewtree but are not themselves in crnewtree. FOR rec IN SELECT cr.item_id, cr.parent_id, n.tree_sortkey FROM cr_items cr, tmp_crnewtree n WHERE n.item_id = cr.parent_id and not exists (select 1 from tmp_crnewtree e where e.item_id = cr.item_id) ORDER BY cr.parent_id, cr.tree_sortkey LOOP if last_parent = rec.parent_id THEN childkey := tree_increment_key(childkey); else childkey := tree_increment_key(null); last_parent := rec.parent_id; end if; insert into tmp_crnewtree values (rec.item_id, rec.tree_sortkey || childkey); if (nrows % 5000) = 0 and nrows > 0 then raise notice ''ngen % row %'',ngen,nrows; end if; nrows := nrows + 1; END LOOP; totrows := totrows + nrows; raise notice ''ngen % totrows %'',ngen,nrows; if nrows = 0 then exit; end if; END LOOP; return totrows; end;' language plpgsql; select __tmp_crnewtree(); drop function __tmp_crnewtree(); -- make sure unique constraint can be added ALTER TABLE tmp_crnewtree add constraint tmp_crnewtree_sk_un unique(tree_sortkey); -- compute the new maxchilds. CREATE TABLE tmp_crmaxchild as SELECT parent_id as item_id, max(tree_leaf_key_to_int(t.tree_sortkey)) as max_child_sortkey FROM cr_items cr, tmp_crnewtree t where t.item_id = cr.item_id GROUP BY parent_id; create index tmp_crmaxchild_idx on tmp_crmaxchild(item_id); -- we are going to use a unique constraint on this column now drop index cr_sortkey_idx; -- Drop the related triggers on cr_items -- drop trigger cr_items_tree_update_tr on cr_items; drop function cr_items_tree_update_tr(); drop trigger cr_items_tree_insert_tr on cr_items; drop function cr_items_tree_insert_tr(); -- -- add the max_child_sortkey -- alter table cr_items add max_child_sortkey varbit; -- Update the tree_sortkeys in cr_items... -- UPDATE cr_items SET tree_sortkey = (select tree_sortkey from tmp_crnewtree n where n.item_id = cr_items.item_id), max_child_sortkey = (select int_to_tree_key(max_child_sortkey) from tmp_crmaxchild n where n.item_id = cr_items.item_id); -- Drop the temp tables as we no longer need them... -- drop table tmp_crnewtree; drop table tmp_crmaxchild; -- add back the unique not null constraint on tree_sortkey -- ALTER TABLE cr_items add constraint cr_items_tree_sortkey_un unique(tree_sortkey); ALTER TABLE cr_items ALTER COLUMN tree_sortkey SET NOT NULL; -- Recreate the triggers -- create function cr_items_tree_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_parent_id integer default null; begin select item_id into v_parent_id from cr_items where item_id = new.parent_id; if new.parent_id = 0 then new.tree_sortkey := int_to_tree_key(new.item_id+1000); elsif v_parent_id is null then new.tree_sortkey := int_to_tree_key(new.parent_id+1000) || int_to_tree_key(new.item_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM cr_items WHERE item_id = new.parent_id FOR UPDATE; UPDATE cr_items SET max_child_sortkey = v_max_child_sortkey WHERE item_id = new.parent_id; new.tree_sortkey := v_parent_sk || v_max_child_sortkey; end if; return new; end;' language 'plpgsql'; create trigger cr_items_tree_insert_tr before insert on cr_items for each row execute procedure cr_items_tree_insert_tr (); -- -- create function cr_items_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_child_sortkey varbit; v_parent_id integer default null; v_old_parent_length integer; begin if new.item_id = old.item_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) then return new; end if; select item_id into v_parent_id from cr_items where item_id = new.parent_id; -- the tree sortkey is going to change so get the new one and update it and all its -- children to have the new prefix... v_old_parent_length := length(new.tree_sortkey) + 1; if new.parent_id = 0 then v_parent_sk := int_to_tree_key(new.item_id+1000); elsif v_parent_id is null then v_parent_sk := int_to_tree_key(new.parent_id+1000) || int_to_tree_key(new.item_id+1000); else SELECT tree_sortkey, tree_increment_key(max_child_sortkey) INTO v_parent_sk, v_max_child_sortkey FROM cr_items WHERE item_id = new.parent_id FOR UPDATE; UPDATE cr_items SET max_child_sortkey = v_max_child_sortkey WHERE item_id = new.parent_id; v_parent_sk := v_parent_sk || v_max_child_sortkey; end if; UPDATE cr_items SET tree_sortkey = v_parent_sk || substring(tree_sortkey, v_old_parent_length) WHERE tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); return new; end;' language 'plpgsql'; create trigger cr_items_tree_update_tr after update on cr_items for each row execute procedure cr_items_tree_update_tr (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0b6-5.2.0b7.sql0000644000175000017500000001540110440426443031570 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0b6-5.2.0b7.sql -- -- @author sussdorff aolserver (sussdorff@ipxserver.de) -- @creation-date 2005-11-29 -- @arch-tag: 6c315b82-708f-4c42-8c66-297d27dcb2a0 -- @cvs-id $Id: upgrade-5.2.0b6-5.2.0b7.sql,v 1.2 2006/06/04 00:45:23 donb Exp $ -- create or replace function content_extlink__new (varchar,varchar,varchar,varchar,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__name alias for $1; -- default null new__url alias for $2; new__label alias for $3; -- default null new__description alias for $4; -- default null new__parent_id alias for $5; new__extlink_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__package_id alias for $10; -- default null v_extlink_id cr_extlinks.extlink_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_label cr_extlinks.label%TYPE; v_name cr_items.name%TYPE; begin if new__label is null then v_label := new__url; else v_label := new__label; end if; if new__name is null then select acs_object_id_seq.nextval into v_extlink_id from dual; v_name := ''link'' || v_extlink_id; else v_name := new__name; end if; if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_extlink_id := content_item__new( v_name, new__parent_id, new__extlink_id, null, new__creation_date, new__creation_user, null, new__creation_ip, ''content_item'', ''content_extlink'', null, null, ''text/plain'', null, null, ''text'', v_package_id ); insert into cr_extlinks (extlink_id, url, label, description) values (v_extlink_id, new__url, v_label, new__description); update acs_objects set title = v_label where object_id = v_extlink_id; return v_extlink_id; end;' language 'plpgsql'; create or replace function content_extlink__new (varchar,varchar,varchar,varchar,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__name alias for $1; -- default null new__url alias for $2; new__label alias for $3; -- default null new__description alias for $4; -- default null new__parent_id alias for $5; new__extlink_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null begin return content_extlink__new(new__name, new__url, new__label, new__description, new__parent_id, new__extlink_id, new__creation_date, new__creation_user, new__creation_ip, null ); end;' language 'plpgsql'; select define_function_args('content_extlink__delete','extlink_id'); create or replace function content_extlink__delete (integer) returns integer as ' declare delete__extlink_id alias for $1; begin delete from cr_extlinks where extlink_id = delete__extlink_id; PERFORM content_item__delete(delete__extlink_id); return 0; end;' language 'plpgsql'; select define_function_args('content_extlink__is_extlink','item_id'); create or replace function content_extlink__is_extlink (integer) returns boolean as ' declare is_extlink__item_id alias for $1; v_extlink_p boolean; begin select count(1) = 1 into v_extlink_p from cr_extlinks where extlink_id = is_extlink__item_id; return v_extlink_p; end;' language 'plpgsql'; create or replace function content_extlink__copy ( integer, integer, integer, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink__copy ( copy__extlink_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, NULL ); return 0; end;' language 'plpgsql' stable; select define_function_args('content_extlink__copy','extlink_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_extlink__copy ( integer, integer, integer, varchar, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_description cr_extlinks.description%TYPE; v_label cr_extlinks.label%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__extlink_id; -- can''t copy to the same folder select i.name, e.url, e.description, e.label into v_name, v_url, v_description, v_label from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy__extlink_id; -- copy to a different folder, or same folder if name -- is different if copy__target_folder_id != v_current_folder_id or ( v_name <> copy_name and copy_name is not null ) then if content_folder__is_registered(copy__target_folder_id, ''content_extlink'',''f'') = ''t'' then v_extlink_id := content_extlink__new( coalesce (copy__name, v_name), v_url, v_label, v_description, copy__target_folder_id, null, current_timestamp, copy__creation_user, copy__creation_ip, null ); end if; end if; end if; return 0; end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d4-5.2.0d5.sql0000644000175000017500000001554510301423056031572 0ustar frankiefrankie-- define additional plpgsql select define_function_args('content_item__delete','item_id'); select define_function_args('content_item__copy','item_id,target_folder_id,creation_user,creation_ip,name'); select define_function_args('content_item__get_parent_folder','item_id'); select define_function_args('content_item__unrelate','rel_id'); select define_function_args('content_item__is_index_page','item_id,folder_id'); select define_function_args('content_item__relate','item_id,object_id,relation_tag;generic,order_n,relation_type;cr_item_rel'); select define_function_args('content_item__is_subclass','object_type,supertype'); select define_function_args('content_item__get_publish_date','item_id,is_live;f'); select define_function_args('content_item__get_title','item_id,is_live;f'); select define_function_args('content_item__get_best_revision','item_id'); select define_function_args('content_item__get_latest_revision','item_id'); select define_function_args('content_item__move','item_id,target_folder_id,name'); select define_function_args('content_item__get_context','item_id'); select define_function_args('content_item__get_revision_count','item_id'); select define_function_args('content_item__set_release_period','item_id,start_when,end_when'); select define_function_args('content_item__unset_live_revision','item_id'); select define_function_args('content_item__set_live_revision','revision_id,publish_status;ready'); select define_function_args('content_item__get_live_revision','item_id'); select define_function_args('content_item__get_content_type','item_id'); select define_function_args('content_item__get_template','item_id,use_context'); select define_function_args('content_item__unregister_template','item_id,template_id,use_context'); select define_function_args('content_item__register_template','item_id,template_id,use_context'); select define_function_args('content_item__get_virtual_path','item_id,root_folder_id;-100'); select define_function_args('content_item__get_path','item_id,root_folder_id'); select define_function_args('content_item__get_id','item_path,root_folder_id,resolve_index;f'); select define_function_args('content_item__edit_name','item_id,name'); select define_function_args('content_item__is_valid_child','item_id,content_type,relation_tag'); select define_function_args('content_item__is_publishable','item_id'); select define_function_args('content_item__is_published','item_id'); select define_function_args('content_item__get_root_folder','item_id'); select define_function_args('content_revision__get_content','revision_id'); select define_function_args('content_revision__content_copy','revision_id,revision_id_dest'); select define_function_args('content_revision__is_latest','revision_id'); select define_function_args('content_revision__is_live','revision_id'); select define_function_args('content_revision__to_html','revision_id'); select define_function_args('content_revision__revision_name','revision_id'); select define_function_args('content_revision__get_number','revision_id'); select define_function_args('content_revision__delete','revision_id'); select define_function_args('content_revision__copy','revision_id,copy_id,target_item_id,creation_user,creation_ip'); select define_function_args('content_revision__copy_attributes','content_type,revision_id,copy_id'); select define_function_args('content_type__rotate_template','template_id,content_type,use_context'); select define_function_args('content_type__is_content_type','content_type'); select define_function_args('content_type__unregister_mime_type','content_type,mime_type'); select define_function_args('content_type__register_mime_type','content_type,mime_type'); select define_function_args('content_type__unregister_relation_type','content_type,target_type,relation_tag;generic'); select define_function_args('content_type__register_relation_type','content_type,target_type,relation_tag;generic,min_n;0,max_n'); select define_function_args('content_type__unregister_child_type','content_type,child_type,relation_tag'); select define_function_args('content_type__register_child_type','content_type,child_type,relation_tag;generic,min_n;0,max_n'); select define_function_args('content_type__refresh_view','content_type'); select define_function_args('content_type__refresh_trigger','content_type'); select define_function_args('content_type__trigger_insert_statement','content_type'); select define_function_args('content_type__unregister_template','content_type,template_id,use_context'); select define_function_args('content_type__get_template','content_type,use_context'); select define_function_args('content_type__set_default_template','content_type,template_id,use_context'); select define_function_args('content_type__register_template','content_type,template_id,use_context,is_default;f'); select define_function_args('content_folder__delete','folder_id,cascade_p;f'); select define_function_args('content_folder__register_content_type','folder_id,content_type,include_subtypes;f'); select define_function_args('content_folder__is_root','folder_id'); select define_function_args('content_folder__get_index_page','folder_id'); select define_function_args('content_folder__get_label','folder_id'); select define_function_args('content_folder__is_registered','folder_id,content_type,include_subtypes;f'); select define_function_args('content_folder__unregister_content_type','folder_id,content_type,include_subtypes;f'); select define_function_args('content_folder__is_empty','folder_id'); select define_function_args('content_folder__is_sub_folder','folder_id,target_folder_id'); select define_function_args('content_folder__is_folder','folder_id'); select define_function_args('content_folder__edit_name','folder_id,name,label,description'); select define_function_args('content_folder__move','folder_id,target_folder_id'); select define_function_args('content_template__get_path','template_id,root_folder_id;-100'); select define_function_args('content_template__is_template','template_id'); select define_function_args('content_template__delete','template_id'); select define_function_args('content_symlink__resolve','item_id'); select define_function_args('content_symlink__resolve_content_type','item_id'); select define_function_args('content_symlink__is_symlink','item_id'); select define_function_args('content_symlink__copy','symlink_id,target_folder_id,creation_user,creation_ip,name'); select define_function_args('content_symlink__new','name,label,target_id,parent_id,symlink_id,creation_date;now,creation_user,creation_ip,package_id'); select define_function_args('content_extlink__copy','extlink_id,target_folder_id,creation_user,creation_ip,name'); select define_function_args('content_extlink__is_extlink','item_id'); select define_function_args('content_extlink__delete','extlink_id'); select define_function_args('content_extlink__new','name,url,label,description,parent_id,extlink_id,creation_date;now,creation_user,creation_ip,package_id'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d8-5.2.0d9.sql0000644000175000017500000000060610164546535031611 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-12-29 -- @arch-tag: 9b265639-f2f6-49ad-9ca6-d4688b162a8e -- @cvs-id $Id: upgrade-5.2.0d8-5.2.0d9.sql,v 1.1 2004/12/29 15:29:33 daveb Exp $ -- -- set default for creation_date select define_function_args('content_template__new','name,parent_id,template_id,creation_date;now,creation_user,creation_ip');openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.6.0d2-5.6.0d3.sql0000644000175000017500000002024411264730332031575 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2009-10-12 -- @cvs-id $Id: upgrade-5.6.0d2-5.6.0d3.sql,v 1.1 2009/10/12 22:42:34 daveb Exp $ -- create or replace function content_type__refresh_trigger (varchar) returns integer as ' declare refresh_trigger__content_type alias for $1; rule_text text default ''''; function_text text default ''''; v_table_name acs_object_types.table_name%TYPE; type_rec record; begin -- get the table name for the content type (determines view name) raise NOTICE ''refresh trigger for % '', refresh_trigger__content_type; -- Since we allow null table name use object type if table name is null so -- we still can have a view. select coalesce(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_trigger__content_type; --=================== start building rule code ======================= function_text := function_text || ''create or replace function '' || v_table_name || ''_f (p_new ''|| v_table_name || ''i) returns void as '''' declare v_revision_id integer; begin select content_revision__new( p_new.title, p_new.description, now(), p_new.mime_type, p_new.nls_language, case when p_new.text is null then p_new.data else p_new.text end, content_symlink__resolve(p_new.item_id), p_new.revision_id, now(), p_new.creation_user, p_new.creation_ip, p_new.object_package_id ) into v_revision_id; ''; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_trigger__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) and ot1.table_name is not null order by level asc LOOP function_text := function_text || '' '' || content_type__trigger_insert_statement(type_rec.object_type) || ''; ''; end loop; function_text := function_text || '' return; end;'''' language ''''plpgsql''''; ''; -- end building the rule definition code -- create the new function execute function_text; rule_text := ''create rule '' || v_table_name || ''_r as on insert to '' || v_table_name || ''i do instead SELECT '' || v_table_name || ''_f(new); '' ; --================== done building rule code ======================= -- drop the old rule if rule_exists(v_table_name || ''_r'', v_table_name || ''i'') then -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; end if; -- create the new rule for inserts on the content type execute rule_text; return null; end;' language 'plpgsql'; create or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and lower(ot2.table_name) <> ''acs_objects'' and lower(ot2.table_name) <> ''cr_revisions'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP if join_rec.table_name is not null then cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end if; end loop; -- Since we allow null table name use object type if table name is null so -- we still can have a view. select coalesce(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 57 then raise exception ''Table name cannot be longer than 57 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i'' || '' CASCADE''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.6.3-4.6.4.sql0000644000175000017500000001351407631426637031144 0ustar frankiefrankie-- Upgrade script -- -- Extra mime types for the richtext widget -- Fixed typo in content_keyword__is_assigned -- -- @author Lars Pind -- @created 2003-01-27 insert into cr_mime_types(label, mime_type, file_extension) values ('Enhanced text', 'text/enhanced', 'etxt'); insert into cr_mime_types(label, mime_type, file_extension) values ('Fixed-width text', 'text/fixed-width', 'ftxt'); create or replace function content_keyword__is_assigned (integer,integer,varchar) returns boolean as ' declare is_assigned__item_id alias for $1; is_assigned__keyword_id alias for $2; is_assigned__recurse alias for $3; -- default ''none'' v_ret boolean; begin -- Look for an exact match if is_assigned__recurse = ''none'' then return count(*) > 0 from cr_item_keyword_map where item_id = is_assigned__item_id and keyword_id = is_assigned__keyword_id; end if; -- Look from specific to general if is_assigned__recurse = ''up'' then return count(*) > 0 where exists (select 1 from (select keyword_id from cr_keywords c, cr_keywords c2 where c2.keyword_id = is_assigned__keyword_id and c.tree_sortkey between c2.tree_sortkey and tree_right(c2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; if is_assigned__recurse = ''down'' then return count(*) > 0 where exists (select 1 from (select k2.keyword_id from cr_keywords k1, cr_keywords k2 where k1.keyword_id = is_assigned__keyword_id and k1.tree_sortkey between k2.tree_sortkey and tree_right(k2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; -- Tried none, up and down - must be an invalid parameter raise EXCEPTION ''-20000: The recurse parameter to content_keyword.is_assigned should be \\\'none\\\', \\\'up\\\' or \\\'down\\\'''; return null; end;' language 'plpgsql'; create or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin -- select -- table_name, id_column, level -- from -- acs_object_types -- where -- object_type <> ''acs_object'' -- and -- object_type <> ''content_revision'' -- start with -- object_type = refresh_view__content_type -- connect by -- object_type = prior supertype for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end loop; select table_name into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 25 then raise exception ''Table name cannot be longer than 25 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.*, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.*, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.4d3-5.1.4d4.sql0000644000175000017500000001032510171476702031600 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2004-12-29 -- @arch-tag: 4199ac3e-74bb-47ac-8b3c-71166bc12271 -- @cvs-id $Id: upgrade-5.1.4d3-5.1.4d4.sql,v 1.2 2005/01/13 13:55:14 jeffd Exp $ -- -- return new folder_id on creation create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin return content_folder__new ( new__name, new__label, new__description, new__parent_id, new__context_id, new__folder_id, new__creation_date, new__creation_user, new__creation_ip, new__security_inherit_p, null ); end;' language 'plpgsql'; select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p;t,package_id'); create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true new__package_id alias for $11; -- default null v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if new__context_id is null then v_context_id := new__parent_id; else v_context_id := new__context_id; end if; -- parent_id = 0 means that this is a mount point if new__parent_id != 0 and content_folder__is_registered(new__parent_id,''content_folder'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow subfolders to be created''; return null; else v_folder_id := content_item__new( new__folder_id, new__name, new__parent_id, null, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''f'', ''text/plain'', null, ''text'', new__security_inherit_p, ''CR_FILES'', ''content_folder'', ''content_folder''); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, new__label, new__description, new__package_id ); -- inherit the attributes of the parent folder if new__parent_id is not null then insert into cr_folder_type_map select v_folder_id as folder_id, content_type from cr_folder_type_map where folder_id = new__parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = ''t'' where folder_id = new__parent_id; return v_folder_id; end if; return v_folder_id; end;' language 'plpgsql'; -- properly set default of creation_date select define_function_args('content_template__new','name,parent_id,template_id,creation_date;now,creation_user,creation_ip');openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d17-5.2.0d18.sql0000644000175000017500000000014310301423056031726 0ustar frankiefrankieselect define_function_args('content_item__set_live_revision','revision_id,publish_status;ready'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0d1-5.3.0d2.sql0000644000175000017500000003052710622143333031566 0ustar frankiefrankie-- procedure refresh_trigger select define_function_args('content_type__refresh_trigger','content_type'); create or replace function content_type__refresh_trigger (varchar) returns integer as ' declare refresh_trigger__content_type alias for $1; rule_text text default ''''; function_text text default ''''; v_table_name acs_object_types.table_name%TYPE; type_rec record; begin -- get the table name for the content type (determines view name) raise NOTICE ''refresh trigger for % '', refresh_trigger__content_type; select table_name into v_table_name from acs_object_types where object_type = refresh_trigger__content_type; --=================== start building rule code ======================= function_text := function_text || ''create or replace function '' || v_table_name || ''_f (p_new ''|| v_table_name || ''i) returns void as '''' declare v_revision_id integer; begin select content_revision__new( p_new.title, p_new.description, now(), p_new.mime_type, p_new.nls_language, case when p_new.text is null then p_new.data else p_new.text end, content_symlink__resolve(p_new.item_id), p_new.revision_id, now(), p_new.creation_user, p_new.creation_ip, p_new.object_package_id ) into v_revision_id; ''; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_trigger__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level asc LOOP function_text := function_text || '' '' || content_type__trigger_insert_statement(type_rec.object_type) || ''; ''; end loop; function_text := function_text || '' return; end;'''' language ''''plpgsql''''; ''; -- end building the rule definition code -- create the new function execute function_text; rule_text := ''create rule '' || v_table_name || ''_r as on insert to '' || v_table_name || ''i do instead SELECT '' || v_table_name || ''_f(new); '' ; --================== done building rule code ======================= -- drop the old rule if rule_exists(v_table_name || ''_r'', v_table_name || ''i'') then -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; end if; -- create the new rule for inserts on the content type execute rule_text; return null; end;' language 'plpgsql'; -- function trigger_insert_statement select define_function_args('content_type__trigger_insert_statement','content_type'); create or replace function content_type__trigger_insert_statement (varchar) returns varchar as ' declare trigger_insert_statement__content_type alias for $1; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; vals varchar default ''''; attr_rec record; begin if trigger_insert_statement__content_type is null then return exception ''content_type__trigger_insert_statement called with null content_type''; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = trigger_insert_statement__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; vals := vals || '', p_new.'' || attr_rec.attribute_name; end LOOP; return ''insert into '' || v_table_name || '' ( '' || v_id_column || cols || '' ) values (v_revision_id'' || vals || '')''; end;' language 'plpgsql' stable; select define_function_args('content_type__refresh_view','content_type'); create or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and lower(ot2.table_name) <> ''acs_objects'' and lower(ot2.table_name) <> ''cr_revisions'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP if join_rec.table_name is not null then cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end if; end loop; select table_name into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 25 then raise exception ''Table name cannot be longer than 25 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i'' || '' CASCADE''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; create or replace function inline_0() returns integer as ' declare v_row record; begin for v_row in select distinct o.object_type,o.table_name from acs_object_type_supertype_map m, acs_object_types o where (m.ancestor_type=''content_revision'' and o.object_type=m.object_type) or (o.object_type=''content_revision'') loop if table_exists(v_row.table_name) then perform content_type__refresh_view(v_row.object_type); end if; end loop; return 0; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); -- rebuild content search triggers to honor publish_date drop trigger content_search__itrg on cr_revisions; drop trigger content_search__dtrg on cr_revisions; drop trigger content_search__utrg on cr_revisions; drop trigger content_item_search__utrg on cr_items; drop function content_search__itrg(); drop function content_search__utrg(); drop function content_item_search__utrg(); create function content_search__itrg () returns opaque as ' begin if (select live_revision from cr_items where item_id=new.item_id) = new.revision_id and new.publish_date >= current_timestamp then perform search_observer__enqueue(new.revision_id,''INSERT''); end if; return new; end;' language 'plpgsql'; create or replace function content_search__utrg () returns opaque as ' declare v_live_revision integer; begin select into v_live_revision live_revision from cr_items where item_id=old.item_id; if old.revision_id=v_live_revision and new.publish_date <= current_timestamp then insert into search_observer_queue ( object_id, event ) values ( old.revision_id, ''UPDATE'' ); end if; return new; end;' language 'plpgsql'; -- we need new triggers on cr_items to index when a live revision -- changes -DaveB 2002-09-26 create function content_item_search__utrg () returns opaque as ' begin if new.live_revision is not null and coalesce(old.live_revision,0) <> new.live_revision and (select publish_date from cr_revisions where revision_id=new.live_revision) <= current_timestamp then perform search_observer__enqueue(new.live_revision,''INSERT''); end if; if old.live_revision is not null and old.live_revision <> coalesce(new.live_revision,0) then perform search_observer__enqueue(old.live_revision,''DELETE''); end if; if new.publish_status = ''expired'' then perform search_observer__enqueue(old.live_revision,''DELETE''); end if; return new; end;' language 'plpgsql'; create trigger content_search__itrg after insert on cr_revisions for each row execute procedure content_search__itrg (); create trigger content_search__dtrg after delete on cr_revisions for each row execute procedure content_search__dtrg (); create trigger content_search__utrg after update on cr_revisions for each row execute procedure content_search__utrg (); create trigger content_item_search__utrg before update on cr_items for each row execute procedure content_item_search__utrg (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.5.0d2-5.5.0d3.sql0000644000175000017500000000752311100351226031566 0ustar frankiefrankie-- -- -- -- @author Victor Guerra (vguerra@wu-wien.ac.at) -- @creation-date 2008-10-21 -- @cvs-id $Id: upgrade-5.5.0d2-5.5.0d3.sql,v 1.2 2008/10/24 13:50:14 victorg Exp $ -- create or replace function content_folder__copy (integer,integer,integer,varchar,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin if copy__folder_id = content_item__get_root_folder(null) or copy__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.copy - Not allowed to copy root folder''; end if; select count(*) into v_valid_folders_p from cr_folders where folder_id = copy__target_folder_id or folder_id = copy__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.copy - Invalid folder(s)''; end if; if copy__target_folder_id = copy__folder_id then raise EXCEPTION ''-20000: content_folder.copy - Cannot copy folder to itself''; end if; if content_folder__is_sub_folder(copy__folder_id, copy__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.copy - Destination folder is subfolder''; end if; if content_folder__is_registered(copy__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.copy - Destination folder does not allow subfolders''; end if; -- get the source folder info select name, label, description, parent_id into v_name, v_label, v_description, v_current_folder_id from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy__folder_id; -- would be better to check if the copy__name alredy exists in the destination folder. if v_current_folder_id = copy__target_folder_id and (v_name = copy__name or copy__name is null) then raise EXCEPTION ''-20000: content_folder.copy - Destination folder is parent folder and folder alredy exists''; end if; -- create the new folder v_new_folder_id := content_folder__new( coalesce (copy__name, v_name), v_label, v_description, copy__target_folder_id, copy__target_folder_id, null, now(), copy__creation_user, copy__creation_ip, ''t'', null ); -- copy attributes of original folder insert into cr_folder_type_map select v_new_folder_id as folder_id, content_type from cr_folder_type_map map where folder_id = copy__folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in select item_id from cr_items where parent_id = copy__folder_id LOOP PERFORM content_item__copy( v_folder_contents_val.item_id, v_new_folder_id, copy__creation_user, copy__creation_ip, null ); end loop; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.7.0d3-5.7.0d4.sql0000644000175000017500000000147011555112776031612 0ustar frankiefrankie-- Need to guard against xotcl-core which sneakily modifies core behind -- our backs (rather than having fixed acs-core like nice people would do) begin; select content_type__create_attribute ( 'content_revision', 'item_id', 'integer', 'Item id', 'Item ids', null, null, 'integer' ) where not exists (select 1 from acs_attributes where object_type = 'content_revision' and attribute_name = 'item_id'); select content_type__create_attribute ( 'content_revision', 'content', 'text', 'Content', 'Content', null, null, 'text' ) where not exists (select 1 from acs_attributes where object_type = 'content_revision' and attribute_name = 'content'); end; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.6-4.6.1.sql0000644000175000017500000001461207606334001030761 0ustar frankiefrankie-- Upgrade script -- -- @author Ola Hansson -- @created 2002-12-30 -- fixes bug http://openacs.org/bugtracker/openacs/patch?patch_number=25 create or replace function content_type__drop_type (varchar,boolean,boolean) returns integer as ' declare drop_type__content_type alias for $1; drop_type__drop_children_p alias for $2; -- default ''f'' drop_type__drop_table_p alias for $3; -- default ''f'' table_exists_p boolean; v_table_name varchar; is_subclassed_p boolean; child_rec record; attr_row record; begin -- first we''ll rid ourselves of any dependent child types, if any , -- along with their own dependent grandchild types select count(*) > 0 into is_subclassed_p from acs_object_types where supertype = drop_type__content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children''s packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_type__drop_children_p and is_subclassed_p then for child_rec in select object_type from acs_object_types where supertype = drop_type__content_type LOOP PERFORM content_type__drop_type(child_rec.object_type, ''t'', ''f''); end LOOP; end if; -- now drop all the attributes related to this type for attr_row in select attribute_name from acs_attributes where object_type = drop_type__content_type LOOP PERFORM content_type__drop_attribute(drop_type__content_type, attr_row.attribute_name, ''f'' ); end LOOP; -- we''ll remove the associated table if it exists select table_exists(lower(table_name)) into table_exists_p from acs_object_types where object_type = drop_type__content_type; if table_exists_p and drop_type__drop_table_p then select table_name into v_table_name from acs_object_types where object_type = drop_type__content_type; -- drop the rule and input/output views for the type -- being dropped. -- FIXME: this did not exist in the oracle code and it needs to be -- tested. Thanks to Vinod Kurup for pointing this out. -- The rule dropping might be redundant as the rule might be dropped -- when the view is dropped. -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; execute ''drop view '' || v_table_name || ''x''; execute ''drop view '' || v_table_name || ''i''; execute ''drop table '' || v_table_name; end if; PERFORM acs_object_type__drop_type(drop_type__content_type, ''f''); return 0; end;' language 'plpgsql'; -- procedure refresh_trigger create or replace function content_type__refresh_trigger (varchar) returns integer as ' declare refresh_trigger__content_type alias for $1; rule_text text default ''''; v_table_name acs_object_types.table_name%TYPE; type_rec record; begin -- get the table name for the content type (determines view name) select table_name into v_table_name from acs_object_types where object_type = refresh_trigger__content_type; --=================== start building rule code ======================= rule_text := ''create rule '' || v_table_name || ''_r as on insert to '' || v_table_name || ''i do instead ( update cr_dummy set val = ( select content_revision__new( new.title, new.description, now(), new.mime_type, new.nls_language, case when new.text is null then new.data else new.text end, content_symlink__resolve(new.item_id), new.revision_id, now(), new.creation_user, new.creation_ip )); ''; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_trigger__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level desc LOOP rule_text := rule_text || '' '' || content_type__trigger_insert_statement(type_rec.object_type) || '';''; end loop; -- end building the rule definition code rule_text := rule_text || '' );''; --================== done building rule code ======================= -- drop the old rule if rule_exists(v_table_name || ''_r'', v_table_name || ''i'') then -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; end if; -- create the new rule for inserts on the content type execute rule_text; return null; end;' language 'plpgsql';openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d13-5.2.0d14.sql0000644000175000017500000000363010217276637031743 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-03-20 -- @arch-tag: 8694a7de-393a-4d70-a3ce-36019afdf05c -- @cvs-id $Id: upgrade-5.2.0d13-5.2.0d14.sql,v 1.1 2005/03/20 13:41:51 daveb Exp $ -- -- add define function args calls for content_keyword -- add content_keyword__del to coincide with oracle select define_function_args ('content_keyword__get_heading','keyword_id'); select define_function_args ('content_keyword__get_description','keyword_id'); select define_function_args ('content_keyword__set_heading','keyword_id,heading'); select define_function_args ('content_keyword__set_description','keyword_id,description'); select define_function_args ('content_keyword__is_leaf','keyword_id'); select define_function_args ('content_keyword__del','keyword_id'); select define_function_args ('content_keyword__item_assign','item_id,keyword_id,context_id;null,creation_user;null,creation_ip;null'); select define_function_args ('content_keyword__item_unassign','item_id,keyword_id'); select define_function_args ('content_keyword__is_assigned','item_id,keyword_id,recurse;none'); select define_function_args ('content_keyword__get_path','keyword_id'); create or replace function content_keyword__del (integer) returns integer as ' declare delete__keyword_id alias for $1; v_rec record; begin for v_rec in select item_id from cr_item_keyword_map where keyword_id = delete__keyword_id LOOP PERFORM content_keyword__item_unassign(v_rec.item_id, delete__keyword_id); end LOOP; PERFORM acs_object__delete(delete__keyword_id); return 0; end;' language 'plpgsql'; create or replace function content_keyword__delete (integer) returns integer as ' declare delete__keyword_id alias for $1; v_rec record; begin perform content_keyword__del(delete__keyword_id); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0b9-5.2.0b10.sql0000644000175000017500000007612510440426443031657 0ustar frankiefrankie-- new 19 param version of content_item__new (now its 20 with package_id) select define_function_args('content_item__new','name,parent_id,item_id,locale,creation_date;now,creation_user,context_id,creation_ip,item_subtype;content_item,content_type;content_revision,title,description,mime_type;text/plain,nls_language,text,data,relation_tag,is_live;f,storage_type;lob,package_id'); create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE, acs_objects.package_id%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; new__package_id alias for $20; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_title cr_revisions.title%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if new__package_id is null and v_parent_id != 0 then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type, v_rel_tag) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' then v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); elsif new__text is not null or new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( cr_items.name%TYPE, cr_items.parent_id%TYPE, acs_objects.object_id%TYPE, cr_items.locale%TYPE, acs_objects.creation_date%TYPE, acs_objects.creation_user%TYPE, acs_objects.context_id%TYPE, acs_objects.creation_ip%TYPE, acs_object_types.object_type%TYPE, acs_object_types.object_type%TYPE, cr_revisions.title%TYPE, cr_revisions.description%TYPE, cr_revisions.mime_type%TYPE, cr_revisions.nls_language%TYPE, varchar, cr_revisions.content%TYPE, cr_child_rels.relation_tag%TYPE, boolean, cr_items.storage_type%TYPE ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__item_id alias for $3; new__locale alias for $4; new__creation_date alias for $5; new__creation_user alias for $6; new__context_id alias for $7; new__creation_ip alias for $8; new__item_subtype alias for $9; new__content_type alias for $10; new__title alias for $11; new__description alias for $12; new__mime_type alias for $13; new__nls_language alias for $14; new__text alias for $15; new__data alias for $16; new__relation_tag alias for $17; new__is_live alias for $18; new__storage_type alias for $19; v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__data, new__relation_tag, new__is_live, new__storage_type, null); return v_item_id; end;' language 'plpgsql'; -- create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') new__package_id alias for $17; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', coalesce(new__title,new__name), v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- use the name of the item if no title is supplied if new__title is null then v_title := new__name; else v_title := new__title; end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null new__text alias for $15; -- default null new__storage_type alias for $16; -- check in (''text'',''file'') v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__text, new__storage_type, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null new__package_id alias for $16; -- default null new__relation_tag varchar default null; new__is_live boolean default ''f''; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; if new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, ''t'', v_title, v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type ) values ( v_item_id, new__name, new__content_type, v_parent_id, ''lob'' ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null or new__relation_tag = '''' then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', now(), null, null, v_parent_id, ''t'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; -- create the revision if data or title is not null if new__data is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, new__nls_language, new__data, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); elsif new__title is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, null, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new (varchar,integer,integer,varchar,timestamptz,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__locale alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__item_subtype alias for $9; -- default ''content_item'' new__content_type alias for $10; -- default ''content_revision'' new__title alias for $11; -- default null new__description alias for $12; -- default null new__mime_type alias for $13; -- default ''text/plain'' new__nls_language alias for $14; -- default null -- changed to integer for blob_id new__data alias for $15; -- default null v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__item_subtype, new__content_type, new__title, new__description, new__mime_type, new__nls_language, new__data, null::integer); return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,varchar,text,text,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__title alias for $3; -- default null new__description alias for $4; -- default null new__text alias for $5; -- default null new__package_id alias for $6; -- default null begin return content_item__new(new__name, new__parent_id, null, null, now(), null, null, null, ''content_item'', ''content_revision'', new__title, new__description, ''text/plain'', null, new__text, ''text'', new__package_id ); end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,varchar,text,text) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__title alias for $3; -- default null new__description alias for $4; -- default null new__text alias for $5; -- default null begin return content_item__new(new__name, new__parent_id, new__title, new__description, new__text, null); end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; new__package_id alias for $3; begin return content_item__new(new__name, new__parent_id, null, null, null, new__package_id); end;' language 'plpgsql'; create or replace function content_item__new(varchar,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; begin return content_item__new(new__name, new__parent_id, null, null, null, null); end;' language 'plpgsql'; -- function new -- sets security_inherit_p to FALSE -DaveB create or replace function content_item__new ( integer, varchar, integer, varchar, timestamptz, integer, integer, varchar, boolean, varchar, text, varchar, boolean, varchar,varchar,varchar,integer) returns integer as ' declare new__item_id alias for $1; --default null new__name alias for $2; new__parent_id alias for $3; -- default null new__title alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__is_live alias for $9; -- default ''f'' new__mime_type alias for $10; new__text alias for $11; -- default null new__storage_type alias for $12; -- check in (''text'', ''file'') new__security_inherit_p alias for $13; -- default ''t'' new__storage_area_key alias for $14; -- default ''CR_FILES'' new__item_subtype alias for $15; new__content_type alias for $16; new__package_id alias for $17; -- default null new__description varchar default null; new__relation_tag varchar default null; new__nls_language varchar default null; v_parent_id cr_items.parent_id%TYPE; v_parent_type acs_objects.object_type%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_title cr_revisions.title%TYPE; v_rel_id acs_objects.object_id%TYPE; v_rel_tag cr_child_rels.relation_tag%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin -- place the item in the context of the pages folder if no -- context specified if new__parent_id is null then v_parent_id := content_item_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- Determine context_id if new__context_id is null then v_context_id := v_parent_id; else v_context_id := new__context_id; end if; -- use the name of the item if no title is supplied if new__title is null or new__title = '''' then v_title := new__name; else v_title := new__title; end if; if new__package_id is null then v_package_id := acs_object__package_id(content_item__get_root_folder(v_parent_id)); else v_package_id := new__package_id; end if; if v_parent_id = 0 or content_folder__is_folder(v_parent_id) = ''t'' then if v_parent_id != 0 and content_folder__is_registered( v_parent_id, new__content_type, ''f'') = ''f'' then raise EXCEPTION ''-20000: This items content type % is not registered to this folder %'', new__content_type, v_parent_id; end if; else if v_parent_id != 0 then select object_type into v_parent_type from acs_objects where object_id = v_parent_id; if NOT FOUND then raise EXCEPTION ''-20000: Invalid parent ID % specified in content_item.new'', v_parent_id; end if; if content_item__is_subclass(v_parent_type, ''content_item'') = ''t'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''f'' then raise EXCEPTION ''-20000: This items content type % is not allowed in this container %'', new__content_type, v_parent_id; end if; end if; end if; -- Create the object v_item_id := acs_object__new( new__item_id, new__item_subtype, new__creation_date, new__creation_user, new__creation_ip, v_context_id, new__security_inherit_p, v_title, v_package_id ); insert into cr_items ( item_id, name, content_type, parent_id, storage_type, storage_area_key ) values ( v_item_id, new__name, new__content_type, v_parent_id, new__storage_type, new__storage_area_key ); -- if the parent is not a folder, insert into cr_child_rels if v_parent_id != 0 and content_folder__is_folder(v_parent_id) = ''f'' and content_item__is_valid_child(v_parent_id, new__content_type) = ''t'' then if new__relation_tag is null then v_rel_tag := content_item__get_content_type(v_parent_id) || ''-'' || new__content_type; else v_rel_tag := new__relation_tag; end if; v_rel_id := acs_object__new( null, ''cr_item_child_rel'', new__creation_date, null, null, v_parent_id, ''f'', v_rel_tag || '': '' || v_parent_id || '' - '' || v_item_id, v_package_id ); insert into cr_child_rels ( rel_id, parent_id, child_id, relation_tag, order_n ) values ( v_rel_id, v_parent_id, v_item_id, v_rel_tag, v_item_id ); end if; if new__title is not null or new__text is not null then v_revision_id := content_revision__new( v_title, new__description, now(), new__mime_type, null, new__text, v_item_id, null, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); end if; -- make the revision live if is_live is true if new__is_live = ''t'' then PERFORM content_item__set_live_revision(v_revision_id); end if; return v_item_id; end;' language 'plpgsql'; create or replace function content_item__new ( integer, varchar, integer, varchar, timestamptz, integer, integer, varchar, boolean, varchar, text, varchar, boolean, varchar,varchar,varchar) returns integer as ' declare new__item_id alias for $1; --default null new__name alias for $2; new__parent_id alias for $3; -- default null new__title alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__context_id alias for $7; -- default null new__creation_ip alias for $8; -- default null new__is_live alias for $9; -- default ''f'' new__mime_type alias for $10; new__text alias for $11; -- default null new__storage_type alias for $12; -- check in (''text'', ''file'') new__security_inherit_p alias for $13; -- default ''t'' new__storage_area_key alias for $14; -- default ''CR_FILES'' new__item_subtype alias for $15; new__content_type alias for $16; v_item_id cr_items.item_id%TYPE; begin v_item_id := content_item__new (new__item_id, new__name, new__parent_id, new__title, new__creation_date, new__creation_user, new__context_id, new__creation_ip, new__is_live, new__mime_type, new__text, new__storage_type, new__security_inherit_p, new__storage_area_key, new__item_subtype, new__content_type, null); return v_item_id; end;' language 'plpgsql'; \i ../content-folder.sqlopenacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.2d2-5.1.2d3.sql0000644000175000017500000000435010100417375031564 0ustar frankiefrankiecreate or replace function content_item__get_context (integer) returns integer as ' declare get_context__item_id alias for $1; v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context__item_id; if NOT FOUND then raise EXCEPTION ''-20000: Content item % does not exist in content_item.get_context'', get_context__item_id; end if; return v_context_id; end;' language 'plpgsql' stable; -- 1) make sure we are not moving the item to an invalid location: -- that is, the destination folder exists and is a valid folder -- 2) make sure the content type of the content item is registered -- to the target folder -- 3) update the parent_id for the item create or replace function content_item__move (integer,integer) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; begin perform content_item__move( move__item_id, move__target_folder_id, NULL ); return null; end;' language 'plpgsql'; create or replace function content_item__move (integer,integer,varchar) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; begin if move__target_folder_id is null then raise exception ''attempt to move item_id % to null folder_id'', move__item_id; end if; if content_folder__is_folder(move__item_id) = ''t'' then PERFORM content_folder__move(move__item_id, move__target_folder_id,move__name); elsif content_folder__is_folder(move__target_folder_id) = ''t'' then if content_folder__is_registered(move__target_folder_id, content_item__get_content_type(move__item_id),''f'') = ''t'' and content_folder__is_registered(move__target_folder_id, content_item__get_content_type(content_symlink__resolve(move__item_id)),''f'') = ''t'' then -- update the parent_id for the item update cr_items set parent_id = move__target_folder_id, name = coalesce(move__name, name) where item_id = move__item_id; end if; end if; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.2d6-5.1.2d7.sql0000644000175000017500000001000110207353612031563 0ustar frankiefrankie-- -- -- -- @author Rocael Hernandez (roc@viaro.net) -- @creation-date 2004-09-02 -- @arch-tag: d5184853-cbe4-4860-94a8-9a60587b36eb -- @cvs-id $Id: upgrade-5.1.2d6-5.1.2d7.sql,v 1.3 2005/02/24 13:32:58 jeffd Exp $ -- -- create index cr_items_name on cr_items(name); drop trigger cr_items_tree_insert_tr on cr_items; drop function cr_items_tree_insert_tr (); create function cr_items_tree_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; v_parent_id integer; begin -- Lars: If the parent is not a cr_item, we treat it as if it was null. select item_id into v_parent_id from cr_items where item_id = new.parent_id; if v_parent_id is null then -- Lars: Treat all items with a non-cr_item parent as one big pool wrt tree_sortkeys -- The old algorithm had tree_sortkeys start from zero for each different parent select max(tree_leaf_key_to_int(child.tree_sortkey)) into v_max_value from cr_items child where not exists (select 1 from cr_items where child.parent_id = item_id); else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items where parent_id = new.parent_id; select tree_sortkey into v_parent_sk from cr_items where item_id = new.parent_id; end if; new.tree_sortkey := tree_next_key(v_parent_sk, v_max_value); return new; end;' language 'plpgsql'; create trigger cr_items_tree_insert_tr before insert on cr_items for each row execute procedure cr_items_tree_insert_tr (); drop trigger cr_items_tree_update_tr on cr_items; drop function cr_items_tree_update_tr (); create function cr_items_tree_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; p_id integer; v_rec record; clr_keys_p boolean default ''t''; begin if new.item_id = old.item_id and ((new.parent_id = old.parent_id) or (new.parent_id is null and old.parent_id is null)) then return new; end if; for v_rec in select item_id from cr_items where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey) order by tree_sortkey LOOP if clr_keys_p then update cr_items set tree_sortkey = null where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); clr_keys_p := ''f''; end if; -- Lars: If the parent is not a cr_item, we treat it as if it was null. select parent.item_id into p_id from cr_items parent, cr_items child where child.item_id = v_rec.item_id and parent.item_id = child.parent_id; if p_id is null then -- Lars: Treat all items with a non-cr_item parent as one big pool wrt tree_sortkeys -- The old algorithm had tree_sortkeys start from zero for each different parent select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items child where not exists (select 1 from cr_items where child.parent_id = item_id); else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from cr_items where parent_id = p_id; select tree_sortkey into v_parent_sk from cr_items where item_id = p_id; end if; update cr_items set tree_sortkey = tree_next_key(v_parent_sk, v_max_value) where item_id = v_rec.item_id; end LOOP; return new; end;' language 'plpgsql'; create trigger cr_items_tree_update_tr after update on cr_items for each row execute procedure cr_items_tree_update_tr (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0a2-5.2.0a3.sql0000644000175000017500000003763710440426443031575 0ustar frankiefrankieselect define_function_args('content_item__copy','item_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_item__copy ( integer, integer, integer, varchar, varchar ) returns integer as ' declare copy__item_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered boolean; v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_old_live_revision_id cr_revisions.revision_id%TYPE; v_new_live_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder__is_folder(copy__item_id) = ''t'' then PERFORM content_folder__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_symlink.copy if the item is a symlink else if content_symlink__is_symlink(copy__item_id) = ''t'' then PERFORM content_symlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_extlink.copy if the item is an url else if content_extlink__is_extlink(copy__item_id) = ''t'' then PERFORM content_extlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- make sure the target folder is really a folder else if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__item_id; select content_type, name, locale, coalesce(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy__item_id; -- copy to a different folder, or allow copy to the same folder -- with a different name if copy__target_folder_id != v_current_folder_id or ( v_name != copy__name and copy__name is not null ) then -- make sure the content type of the item is registered to the folder v_is_registered := content_folder__is_registered( copy__target_folder_id, v_content_type, ''f'' ); if v_is_registered = ''t'' then -- create the new content item v_item_id := content_item__new( coalesce (copy__name, v_name), copy__target_folder_id, null, v_locale, now(), copy__creation_user, null, copy__creation_ip, ''content_item'', v_content_type, null, null, ''text/plain'', null, null, v_storage_type ); select latest_revision, live_revision into v_old_revision_id, v_old_live_revision_id from cr_items where item_id = copy__item_id; end if; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision__copy ( v_old_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); end if; -- copy the live revision (if there is one and it differs from the latest) to the new item if v_old_live_revision_id is not null then if v_old_live_revision_id <> v_old_revision_id then v_new_live_revision_id := content_revision__copy ( v_old_live_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); else v_new_live_revision_id := v_new_revision_id; end if; end if; update cr_items set live_revision = v_new_live_revision_id, latest_revision = v_new_revision_id where item_id = v_item_id; end if; end if; end if; end if; end if; return v_item_id; end;' language 'plpgsql'; select define_function_args('content_folder__is_folder','item_id'); -- add image__ procs that support package_id create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer,integer) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; new__package_id alias for $17; -- default null new__locale varchar default null; new__nls_language varchar default null; new__creation_date timestamptz default current_timestamp; new__context_id integer; v_item_id cr_items.item_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin new__context_id := new__parent_id; if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_item_id := content_item__new ( new__name, new__parent_id, new__item_id, new__locale, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''content_item'', ''image'', null, new__description, new__mime_type, new__nls_language, null, ''file'', -- storage_type v_package_id ); -- update cr_child_rels to have the correct relation_tag update cr_child_rels set relation_tag = new__relation_tag where parent_id = new__parent_id and child_id = new__item_id and relation_tag = content_item__get_content_type(new__parent_id) || ''-'' || ''image''; v_revision_id := content_revision__new ( new__title, new__description, new__publish_date, new__mime_type, new__nls_language, null, v_item_id, new__revision_id, new__creation_date, new__creation_user, new__creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, new__height, new__width); -- update revision with image file info update cr_revisions set content_length = new__file_size, content = new__path where revision_id = v_revision_id; -- is_live => ''t'' not used as part of content_item.new -- because content_item.new does not let developer specify revision_id, -- revision_id is determined in advance if new__is_live = ''t'' then PERFORM content_item__set_live_revision (v_revision_id); end if; return v_item_id; end; ' language 'plpgsql'; create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer ) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__item_id alias for $3; -- default null new__revision_id alias for $4; -- default null new__mime_type alias for $5; -- default jpeg new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__relation_tag alias for $8; -- default null new__title alias for $9; -- default null new__description alias for $10; -- default null new__is_live alias for $11; -- default f new__publish_date alias for $12; -- default now() new__path alias for $13; new__file_size alias for $14; new__height alias for $15; new__width alias for $16; begin return image__new(new__name, new__parent_id, new__item_id, new__revision_id, new__mime_type, new__creation_user, new__creation_ip, new__relation_tag, new__title, new__description, new__is_live, new__publish_date, new__path, new__file_size, new__height, new__width, null ); end; ' language 'plpgsql'; -- DRB's version create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer, integer) returns integer as ' declare p_name alias for $1; p_parent_id alias for $2; -- default null p_item_id alias for $3; -- default null p_revision_id alias for $4; -- default null p_mime_type alias for $5; -- default jpeg p_creation_user alias for $6; -- default null p_creation_ip alias for $7; -- default null p_title alias for $8; -- default null p_description alias for $9; -- default null p_storage_type alias for $10; p_content_type alias for $11; p_nls_language alias for $12; p_publish_date alias for $13; p_height alias for $14; p_width alias for $15; p_package_id alias for $16; -- default null v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin if content_item__is_subclass(p_content_type, ''image'') = ''f'' then raise EXCEPTION ''-20000: image__new can only be called for an image type''; end if; if p_package_id is null then v_package_id := acs_object__package_id(p_parent_id); else v_package_id := p_package_id; end if; v_item_id := content_item__new ( p_name, p_parent_id, p_item_id, null, current_timestamp, p_creation_user, p_parent_id, p_creation_ip, ''content_item'', p_content_type, null, null, null, null, null, p_storage_type, v_package_id ); -- We will let the caller fill in the LOB data or file path. v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, v_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_item_id; end; ' language 'plpgsql'; create or replace function image__new (varchar,integer,integer,integer,varchar,integer,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer) returns integer as ' declare p_name alias for $1; p_parent_id alias for $2; -- default null p_item_id alias for $3; -- default null p_revision_id alias for $4; -- default null p_mime_type alias for $5; -- default jpeg p_creation_user alias for $6; -- default null p_creation_ip alias for $7; -- default null p_title alias for $8; -- default null p_description alias for $9; -- default null p_storage_type alias for $10; p_content_type alias for $11; p_nls_language alias for $12; p_publish_date alias for $13; p_height alias for $14; p_width alias for $15; begin return image__new(p_name, p_parent_id, p_item_id, p_revision_id, p_mime_type, p_creation_user, p_creation_ip, p_title, p_description, p_storage_type, p_content_type, p_nls_language, p_publish_date, p_height, p_width, null ); end; ' language 'plpgsql'; create or replace function image__new_revision(integer, integer, varchar, varchar, timestamptz, varchar, varchar, integer, varchar, integer, integer, integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; p_package_id alias for $12; v_revision_id integer; v_package_id acs_objects.package_id%TYPE; begin -- We will let the caller fill in the LOB data or file path. if p_package_id is null then v_package_id := acs_object__package_id(p_item_id); else v_package_id := p_package_id; end if; v_revision_id := content_revision__new ( p_title, p_description, p_publish_date, p_mime_type, p_nls_language, null, p_item_id, p_revision_id, current_timestamp, p_creation_user, p_creation_ip, v_package_id ); insert into images (image_id, height, width) values (v_revision_id, p_height, p_width); return v_revision_id; end;' language 'plpgsql'; create or replace function image__new_revision(integer,integer,varchar,varchar,timestamptz,varchar,varchar, integer,varchar,integer,integer) returns integer as ' declare p_item_id alias for $1; p_revision_id alias for $2; p_title alias for $3; p_description alias for $4; p_publish_date alias for $5; p_mime_type alias for $6; p_nls_language alias for $7; p_creation_user alias for $8; p_creation_ip alias for $9; p_height alias for $10; p_width alias for $11; v_revision_id integer; begin return image__new_revision(p_item_id, p_revision_id, p_title, p_description, p_publish_date, p_mime_type, p_nls_language, p_creation_user, p_creation_ip, p_height, p_width, p_revision_id, null ); end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d1-5.2.0d2.sql0000644000175000017500000000307310032100673031553 0ustar frankiefrankie-- add package_id to defined args for content_folder__new select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p;t,package_id'); -- this one had a rename__label as rename_label so replace it. create or replace function content_folder__rename (integer,varchar,varchar,varchar) returns integer as ' declare rename__folder_id alias for $1; rename__name alias for $2; -- default null rename__label alias for $3; -- default null rename__description alias for $4; -- default null v_name_already_exists_p integer; begin if rename__name is not null and rename__name != '''' then PERFORM content_item__rename(rename__folder_id, rename__name); end if; if rename__label is not null and rename__label != '''' then update acs_objects set title = rename__label where object_id = rename__folder_id; end if; if rename__label is not null and rename__label != '''' and rename__description is not null and rename__description != '''' then update cr_folders set label = rename__label, description = rename__description where folder_id = rename__folder_id; else if(rename__label is not null and rename__label != '''') and (rename__description is null or rename__description = '''') then update cr_folders set label = rename__label where folder_id = rename__folder_id; end if; end if; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d5-5.2.0d6.sql0000644000175000017500000000242710077234000031566 0ustar frankiefrankiecreate or replace function content_item__move (integer,integer,varchar) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; begin if move__target_folder_id is null then raise exception ''attempt to move item_id % to null folder_id'', move__item_id; end if; if content_folder__is_folder(move__item_id) = ''t'' then PERFORM content_folder__move(move__item_id, move__target_folder_id,move__name); elsif content_folder__is_folder(move__target_folder_id) = ''t'' then if content_folder__is_registered(move__target_folder_id, content_item__get_content_type(move__item_id),''f'') = ''t'' and content_folder__is_registered(move__target_folder_id, content_item__get_content_type(content_symlink__resolve(move__item_id)),''f'') = ''t'' then -- update the parent_id for the item update cr_items set parent_id = move__target_folder_id, name = coalesce(move__name, name) where item_id = move__item_id; end if; if move__name is not null then update acs_objects set title = move__name where object_id = move__item_id; end if; end if; return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.0d6-5.4.0d7.sql0000644000175000017500000000060310673475171031610 0ustar frankiefrankie-- -- packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.0d6-5.4.0d7.sql -- -- @author Malte Sussdorff (malte.sussdorff@cognovis.de) -- @creation-date 2007-09-07 -- @cvs-id $Id: upgrade-5.4.0d6-5.4.0d7.sql,v 1.1 2007/09/17 13:00:41 maltes Exp $ -- select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f,drop_objects_p;f');openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.6.0d3-5.6.0d4.sql0000644000175000017500000002670711330074421031603 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2010-01-27 -- @cvs-id $Id: -- create or replace function content_type__drop_type (varchar,boolean,boolean,boolean) returns integer as ' declare drop_type__content_type alias for $1; drop_type__drop_children_p alias for $2; -- default ''f'' drop_type__drop_table_p alias for $3; -- default ''f'' drop_type__drop_objects_p alias for $4; -- default ''f'' table_exists_p boolean; v_table_name varchar; is_subclassed_p boolean; child_rec record; attr_row record; revision_row record; item_row record; begin -- first we''ll rid ourselves of any dependent child types, if any , -- along with their own dependent grandchild types select count(*) > 0 into is_subclassed_p from acs_object_types where supertype = drop_type__content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children''s packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_type__drop_children_p and is_subclassed_p then for child_rec in select object_type from acs_object_types where supertype = drop_type__content_type LOOP PERFORM content_type__drop_type(child_rec.object_type, ''t'', drop_type__drop_table_p, drop_type__drop_objects_p); end LOOP; end if; -- now drop all the attributes related to this type for attr_row in select attribute_name from acs_attributes where object_type = drop_type__content_type LOOP PERFORM content_type__drop_attribute(drop_type__content_type, attr_row.attribute_name, ''f'' ); end LOOP; -- we''ll remove the associated table if it exists select table_exists(lower(table_name)) into table_exists_p from acs_object_types where object_type = drop_type__content_type; if table_exists_p and drop_type__drop_table_p then select table_name into v_table_name from acs_object_types where object_type = drop_type__content_type; -- drop the rule and input/output views for the type -- being dropped. -- FIXME: this did not exist in the oracle code and it needs to be -- tested. Thanks to Vinod Kurup for pointing this out. -- The rule dropping might be redundant as the rule might be dropped -- when the view is dropped. -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). execute ''drop table '' || v_table_name || '' cascade''; end if; -- If we are dealing with a revision, delete the revision with revision__delete -- This way the integrity constraint with live revision is dealt with correctly if drop_type__drop_objects_p then for revision_row in select revision_id from cr_revisions, acs_objects where revision_id = object_id and object_type = drop_type__content_type loop PERFORM content_revision__delete(revision_row.revision_id); end loop; for item_row in select item_id from cr_items where content_type = drop_type__content_type loop PERFORM content_item__delete(item_row.item_id); end loop; end if; PERFORM acs_object_type__drop_type(drop_type__content_type, drop_type__drop_objects_p); return 0; end;' language 'plpgsql'; -- don't define function_args twice -- select define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f'); create or replace function content_type__drop_type (varchar,boolean,boolean) returns integer as ' declare drop_type__content_type alias for $1; drop_type__drop_children_p alias for $2; -- default ''f'' drop_type__drop_table_p alias for $3; -- default ''f'' table_exists_p boolean; v_table_name varchar; is_subclassed_p boolean; child_rec record; attr_row record; begin -- first we''ll rid ourselves of any dependent child types, if any , -- along with their own dependent grandchild types select count(*) > 0 into is_subclassed_p from acs_object_types where supertype = drop_type__content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children''s packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_type__drop_children_p and is_subclassed_p then for child_rec in select object_type from acs_object_types where supertype = drop_type__content_type LOOP PERFORM content_type__drop_type(child_rec.object_type, ''t'', ''f''); end LOOP; end if; -- now drop all the attributes related to this type for attr_row in select attribute_name from acs_attributes where object_type = drop_type__content_type LOOP PERFORM content_type__drop_attribute(drop_type__content_type, attr_row.attribute_name, ''f'' ); end LOOP; -- we''ll remove the associated table if it exists select table_exists(lower(table_name)) into table_exists_p from acs_object_types where object_type = drop_type__content_type; if table_exists_p and drop_type__drop_table_p then select table_name into v_table_name from acs_object_types where object_type = drop_type__content_type; -- drop the rule and input/output views for the type -- being dropped. -- FIXME: this did not exist in the oracle code and it needs to be -- tested. Thanks to Vinod Kurup for pointing this out. -- The rule dropping might be redundant as the rule might be dropped -- when the view is dropped. -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; execute ''drop view '' || v_table_name || ''x cascade''; execute ''drop view '' || v_table_name || ''i cascade''; execute ''drop table '' || v_table_name; end if; PERFORM acs_object_type__drop_type(drop_type__content_type, ''f''); return 0; end;' language 'plpgsql'; create or replace function content_type__refresh_view (varchar) returns integer as ' declare refresh_view__content_type alias for $1; cols varchar default ''''; tabs varchar default ''''; joins varchar default ''''; v_table_name varchar; join_rec record; begin for join_rec in select ot2.table_name, ot2.id_column, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and lower(ot2.table_name) <> ''acs_objects'' and lower(ot2.table_name) <> ''cr_revisions'' and ot1.object_type = refresh_view__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by ot2.tree_sortkey desc LOOP if join_rec.table_name is not null then cols := cols || '', '' || join_rec.table_name || ''.*''; tabs := tabs || '', '' || join_rec.table_name; joins := joins || '' and acs_objects.object_id = '' || join_rec.table_name || ''.'' || join_rec.id_column; end if; end loop; -- Since we allow null table name use object type if table name is null so -- we still can have a view. select coalesce(table_name,object_type) into v_table_name from acs_object_types where object_type = refresh_view__content_type; if length(v_table_name) > 57 then raise exception ''Table name cannot be longer than 57 characters, because that causes conflicting rules when we create the views.''; end if; -- create the input view (includes content columns) if table_exists(v_table_name || ''i'') then execute ''drop view '' || v_table_name || ''i'' || '' CASCADE''; end if; -- FIXME: need to look at content_revision__get_content. Since the CR -- can store data in a lob, a text field or in an external file, getting -- the data attribute for this view will be problematic. execute ''create view '' || v_table_name || ''i as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, content_revision__get_content(cr.revision_id) as data, cr_text.text_data as text, cr.description, cr.publish_date, cr.mime_type, cr.nls_language'' || cols || '' from acs_objects, cr_revisions cr, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id '' || joins; -- create the output view (excludes content columns to enable SELECT *) if table_exists(v_table_name || ''x'') then execute ''drop view '' || v_table_name || ''x cascade''; end if; execute ''create view '' || v_table_name || ''x as select acs_objects.object_id, acs_objects.object_type, acs_objects.title as object_title, acs_objects.package_id as object_package_id, acs_objects.context_id, acs_objects.security_inherit_p, acs_objects.creation_user, acs_objects.creation_date, acs_objects.creation_ip, acs_objects.last_modified, acs_objects.modifying_user, acs_objects.modifying_ip, acs_objects.tree_sortkey, acs_objects.max_child_sortkey, cr.revision_id, cr.title, cr.item_id, cr.description, cr.publish_date, cr.mime_type, cr.nls_language, i.name, i.parent_id'' || cols || '' from acs_objects, cr_revisions cr, cr_items i, cr_text'' || tabs || '' where acs_objects.object_id = cr.revision_id and cr.item_id = i.item_id'' || joins; PERFORM content_type__refresh_trigger(refresh_view__content_type); -- exception -- when others then -- dbms_output.put_line(''Error creating attribute view or trigger for'' -- || content_type); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.0d2-5.0d3.sql0000644000175000017500000001656707766162043031314 0ustar frankiefrankie-- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2003-12-03 -- @cvs-id $Id: create or replace function content_item__get_path (integer,integer) returns varchar as ' declare get_path__item_id alias for $1; get_path__root_folder_id alias for $2; -- default null v_count integer; v_resolved_root_id integer; v_path text default ''''; v_rec record; begin -- check that the item exists select count(*) into v_count from cr_items where item_id = get_path__item_id; if v_count = 0 then raise EXCEPTION ''-20000: Invalid item ID: %'', get_path__item_id; end if; -- begin walking down the path to the item (from the repository root) -- if the root folder is not null then prepare for a relative path if get_path__root_folder_id is not null then -- if root_folder_id is a symlink, resolve it (child items will point -- to the actual folder, not the symlink) v_resolved_root_id := content_symlink__resolve(get_path__root_folder_id); -- check to see if the item is under or out side the root_id PERFORM 1 from cr_items i, (select tree_sortkey from cr_items where item_id = v_resolved_root_id) a where tree_ancestor_p(a.tree_sortkey, i.tree_sortkey) and i.item_id = get_path__item_id; if NOT FOUND then -- if not found then we need to go up the folder and append ../ until we have common ancestor for v_rec in select i1.name, i1.parent_id, tree_level(i1.tree_sortkey) as tree_level from cr_items i1, (select tree_ancestor_keys(tree_sortkey) as tree_sortkey from cr_items where item_id = v_resolved_root_id) i2, (select tree_sortkey from cr_items where item_id = get_path__item_id) i3 where i1.parent_id <> 0 and i2.tree_sortkey = i1.tree_sortkey and not tree_ancestor_p(i2.tree_sortkey, i3.tree_sortkey) order by tree_level desc LOOP v_path := v_path || ''../''; end loop; -- lets now assign the new root_id to be the last parent_id on the loop v_resolved_root_id := v_rec.parent_id; end if; -- go downwards the tree and append the name and / for v_rec in select i1.name, i1.item_id, tree_level(i1.tree_sortkey) as tree_level from cr_items i1, (select tree_sortkey from cr_items where item_id = v_resolved_root_id) i2, (select tree_ancestor_keys(tree_sortkey) as tree_sortkey from cr_items where item_id = get_path__item_id) i3 where i1.tree_sortkey = i3.tree_sortkey and i1.tree_sortkey > i2.tree_sortkey order by tree_level LOOP v_path := v_path || v_rec.name; if v_rec.item_id <> get_path__item_id then -- put a / if we are still going down v_path := v_path || ''/''; end if; end loop; else -- this is an absolute path so prepend a ''/'' -- loop over the absolute path for v_rec in select i2.name, tree_level(i2.tree_sortkey) as tree_level from cr_items i1, cr_items i2 where i2.parent_id <> 0 and i1.item_id = get_path__item_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) order by tree_level LOOP v_path := v_path || ''/'' || v_rec.name; end loop; end if; return v_path; end;' language 'plpgsql'; -- -- fix setting of context_id to new item id create or replace function content_revision__copy (integer,integer,integer,integer,varchar) returns integer as ' declare copy__revision_id alias for $1; copy__copy_id alias for $2; -- default null copy__target_item_id alias for $3; -- default null copy__creation_user alias for $4; -- default null copy__creation_ip alias for $5; -- default null v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; type_rec record; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if copy__target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy__revision_id; else v_target_item_id := copy__target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy__copy_id is null then select acs_object_id_seq.nextval into v_copy_id from dual; else v_copy_id := copy__copy_id; end if; -- create the basic object insert into acs_objects select v_copy_id as object_id, object_type, v_target_item_id, security_inherit_p, copy__creation_user as creation_user, now() as creation_date, copy__creation_ip as creation_ip, now() as last_modified, copy__creation_user as modifying_user, copy__creation_ip as modifying_ip from acs_objects where object_id = copy__revision_id; -- create the basic revision (using v_target_item_id) insert into cr_revisions select v_copy_id as revision_id, v_target_item_id as item_id, title, description, publish_date, mime_type, nls_language, lob, content, content_length from cr_revisions where revision_id = copy__revision_id; -- select -- object_type -- from -- acs_object_types -- where -- object_type <> ''acs_object'' -- and -- object_type <> ''content_revision'' -- connect by -- prior supertype = object_type -- start with ---- object_type = (select object_type -- from acs_objects -- where object_id = copy__revision_id) -- order by -- level desc -- iterate over the ancestor types and copy attributes for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2, acs_objects o where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and o.object_id = copy__revision_id and ot1.object_type = o.object_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level desc LOOP PERFORM content_revision__copy_attributes(type_rec.object_type, copy__revision_id, v_copy_id); end loop; return v_copy_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.6.2-4.6.3.sql0000644000175000017500000014231007661402103031120 0ustar frankiefrankie-- This upgrade adds more mime types and -- creates the cr_extension_mime_type_map -- -- Jeff Davis davis@xarg.net 2003-02-06 create table cr_extension_mime_type_map ( extension varchar(200) constraint cr_mime_type_extension_map_pk primary key, mime_type varchar(200) constraint cr_mime_ext_map_mime_type_ref references cr_mime_types ); create index cr_extension_mime_type_map_idx on cr_extension_mime_type_map(mime_type); comment on table cr_extension_mime_type_map is ' a mapping table for extension to mime_type in db version of ns_guesstype data '; -- Quicky create some tmp tables. create table tmp_cr_mime_types as select * from cr_mime_types where 0 = 1; create table tmp_cr_extension_mime_type_map as select * from cr_extension_mime_type_map where 0 = 1; -- data from sql/common/mime-type-data.sql insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Unkown' , '*/*' , '' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'AutoCAD drawing files' , 'application/acad' , 'dwg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Andrew data stream' , 'application/andrew-inset' , 'ez' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'ClarisCAD files' , 'application/clariscad' , 'ccad' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Comma separated value' , 'application/csv' , 'csv' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'MATRA Prelude drafting' , 'application/drafting' , 'drw' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'DXF (AutoCAD)' , 'application/dxf' , 'dxf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Filemaker Pro' , 'application/filemaker' , 'fm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Futuresplash' , 'application/futuresplash' , 'spl' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'NCSA HDF data format' , 'application/hdf' , 'hdf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'IGES graphics format' , 'application/iges' , 'iges' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Mac binhex 4.0' , 'application/mac-binhex40' , 'hqx' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Mac Compactpro' , 'application/mac-compactpro' , 'cpt' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Word' , 'application/msword' , 'doc' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Uninterpreted binary' , 'application/octet-stream' , 'bin' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'ODA ODIF' , 'application/oda' , 'oda' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'PDF' , 'application/pdf' , 'pdf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'PostScript' , 'application/postscript' , 'ps' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Rich Text Format' , 'application/rtf' , 'rtf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Stereolithography' , 'application/sla' , 'stl'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VCard' , 'application/vcard' , 'vcf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VDA-FS Surface data' , 'application/vda' , 'vda'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SSOYE Koan Files' , 'application/vnd.koan' , 'skp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'FrameMaker MIF format' , 'application/vnd.mif' , 'mif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Access file' , 'application/vnd.ms-access' , 'mdb' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Excel' , 'application/vnd.ms-excel' , 'xls' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft PowerPoint' , 'application/vnd.ms-powerpoint' , 'ppt' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft Project' , 'application/vnd.ms-project' , 'mpp' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WML XML in binary format', 'application/vnd.wap.wmlc' , 'wmlc'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WMLScript bytecode' , 'application/vnd.wap.wmlscriptc', 'wmlsc'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'CorelXARA' , 'application/vnd.xara' , 'xar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WordPerfect' , 'application/wordperfect' , 'wpd'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WordPerfect 6.0' , 'application/wordperfect6.0' , 'w60'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive ARJ ' , 'application/x-arj-compressed' , 'arj'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-bin' , 'aab' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-map' , 'aam' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Authorware' , 'application/x-authorware-seg' , 'aas' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Channel Definition' , 'application/x-cdf' , 'cdf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VCD' , 'application/x-cdlink' , 'vcd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Chess PGN file' , 'application/x-chess-pgn' , 'pgn'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive compres' , 'application/x-compress' , 'z'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive CPIO' , 'application/x-cpio' , 'cpio'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'C-shell script' , 'application/x-csh' , 'csh' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive Debian Package' , 'application/x-debian-package' , 'deb'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Director' , 'application/x-director' , 'dxr' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'TeX DVI file' , 'application/x-dvi' , 'dvi' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'GNU Tar' , 'application/x-gtar' , 'gtar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Compressed - gzip' , 'application/x-gzip' , 'gz' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'CGI Script' , 'application/x-httpd-cgi' , 'cgi'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Adobe Illustrator' , 'application/x-illustrator' , 'ai' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Installshield data' , 'application/x-installshield' , 'wis'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Java Network Launching Protocol', 'application/x-java-jnlp-file', 'jnlp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Javascript' , 'application/x-javascript' , 'js' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'LaTeX source' , 'application/x-latex' , 'latex' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmd)', 'application/x-ms-wmd' , 'wmd'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmz)', 'application/x-ms-wmz' , 'wmz'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Unidata netCDF' , 'application/x-netcdf' , 'cdf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Ogg Vorbis' , 'application/x-ogg' , 'ogg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Adobe PageMaker' , 'application/x-pagemaker' , 'p65' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Photoshop' , 'application/x-photoshop' , 'psd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Palm Pilot Data' , 'application/x-pilot' , 'prc' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Real' , 'application/x-pn-realmedia' , 'rp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Quattro Pro' , 'application/x-quattro-pro' , 'wq1'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive RAR' , 'application/x-rar-compressed' , 'rar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Session Description Protocol', 'application/sdp' , 'sdp' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Shockwave' , 'application/x-shockwave-flash' , 'swf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SQL' , 'application/x-sql' , 'sql' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Mac Stuffit compressed' , 'application/x-stuffit' , 'sit' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive SVR4 cpio' , 'application/x-sv4cpio' , 'sv4cpio'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive SVR4 crc' , 'application/x-sv4crc' , 'sv4crc'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Tar Archive' , 'application/x-tar' , 'tar' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'TeX source' , 'application/x-tex' , 'tex' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Texinfo (emacs)' , 'application/x-texinfo' , 'texinfo' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff' , 'application/x-troff' , 'tr' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff with MAN macros' , 'application/x-troff-man' , 'man' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff with ME macros' , 'application/x-troff-me' , 'me' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'troff with MS macros' , 'application/x-troff-ms' , 'ms' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive POSIX Tar' , 'application/x-ustar' , 'ustar'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X509 CA Cert' , 'application/x-x509-ca-cert' , 'cacert'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Archive Zip' , 'application/zip' , 'zip' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Basic audio (m-law PCM)' , 'audio/basic' , 'au' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Midi' , 'audio/midi' , 'midi'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio MPEG' , 'audio/x-mpeg' , 'mpga'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio MPEG-2' , 'audio/x-mpeg2' , 'mp2a'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Java Media Framework', 'audio/rmf' , 'rmf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Voice' , 'audio/voice' , 'voc' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio AIFF' , 'audio/x-aiff' , 'aif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Audio Mod' , 'audio/x-mod' , 'xm'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'mpeg url (m3u)' , 'audio/x-mpegurl' , 'm3u'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wma)', 'audio/x-ms-wma' , 'wma'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmv)', 'audio/x-ms-wmv' , 'wmv'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Realaudio' , 'audio/x-pn-realaudio' , 'ra' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Realaudio Plugin' , 'audio/x-pn-realaudio-plugin' , 'rm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Microsoft WAVE audio' , 'audio/x-wav' , 'wav' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Brookhaven PDB' , 'chemical/x-pdb' , 'pdb'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'XMol XYZ' , 'chemical/x-xyz' , 'xyz'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WHIP Web Drawing file' , 'drawing/x-dwf' , 'dwf'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - BMP' , 'image/bmp' , 'bmp' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Fractal Image Format' , 'image/fif' , 'fif'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Gif' , 'image/gif' , 'gif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image Exchange Format' , 'image/ief' , 'ief' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Jpeg' , 'image/jpeg' , 'jpg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PNG' , 'image/png' , 'png' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - TIFF' , 'image/tiff' , 'tif' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WAP wireless bitmap' , 'image/vnd.wap.wbmp' , 'wbmp'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - CMU Raster' , 'image/x-cmu-raster' , 'ras' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Flexible Image Transport', 'image/x-fits' , 'fit' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Macromedia Freehand' , 'image/x-freehand' , 'fh' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SVG' , 'image/xml+svg' , 'svg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PhotoCD' , 'image/x-photo-cd' , 'pcd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Mac pict' , 'image/x-pict' , 'pict' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PNM' , 'image/x-portable-anymap' , 'pnm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PBM' , 'image/x-portable-bitmap' , 'pbm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - PGM' , 'image/x-portable-graymap' , 'pgm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - Portable Pixmap' , 'image/x-portable-pixmap' , 'ppm'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Image - RGB' , 'image/x-rgb' , 'rgb'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X bitmap' , 'image/x-xbitmap' , 'xbm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X pixmap' , 'image/x-xpixmap' , 'xpm' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'X window dump (xwd)' , 'image/x-xwindowdump' , 'xwd' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'RFC822 Message' , 'message/rfc822' , 'mime'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Computational mesh' , 'model/mesh' , 'mesh'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'SGML Text' , 'text/sgml' , 'sgml'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Cascading style sheet' , 'text/css' , 'css' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'HTML text' , 'text/html' , 'html' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Plain text' , 'text/plain' , 'txt' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Text (flowed)' , 'text/plain; format=flowed' , 'text' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Enriched Text' , 'text/enriched' , 'rtx' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Tab separated values' , 'text/tab-separated-values' , 'tsv' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WMLScript' , 'text/vnd.wap.wmlscript' , 'wmls'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'WML' , 'text/vnd.wap.wml' , 'wml'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'XML Document' , 'text/xml' , 'xml' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Structured enhanced text', 'text/x-setext' , 'etx'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'XSL style sheet' , 'text/xsl' , 'xsl' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video FLI' , 'video/fli' , 'fli'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video MPEG' , 'video/mpeg' , 'mpg' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video MPEG-2' , 'video/mpeg2' , 'mpv2' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Quicktime' , 'video/quicktime' , 'mov' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video VDOlive streaming' , 'video/vdo' , 'vdo'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Vivo' , 'video/vnd.vivo' , 'vivo'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Microsoft ASF' , 'video/x-ms-asf' , 'asf' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wm)', 'video/x-ms-wm' , 'wm'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wvx)', 'video/x-ms-wvx' , 'wvx'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Windows Media Services (wmx)', 'video/x-mx-wmx' , 'wmx'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video Microsoft AVI' , 'video/x-msvideo' , 'avi' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Video SGI movie player' , 'video/x-sgi-movie' , 'movie' ); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Conference Cooltalk' , 'x-conference/x-cooltalk' , 'ice'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'VRML' , 'x-world/x-vrml' , 'vrml'); insert into tmp_cr_mime_types (label,mime_type,file_extension) values ( 'Xuda' , 'xuda/gen-cert' , 'xuda'); -- Extension to mime type maps. -- text/plain for prog langs (maybe we should do application/x-LANG but then you can't look -- at the code in the browser. insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'c', 'text/plain'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'c++', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cpp', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cxx', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cc', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'h', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'h++', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hxx', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tcl', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sql', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'csh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ksh', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'py', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'java', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xql', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'php', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm4', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pl', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pm', 'text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pod', 'text/plain' ); -- map a few to binary insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'o','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'so','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'a','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dll','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'exe','application/octet-stream' ); -- all the rest insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aab','application/x-authorware-bin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aam','application/x-authorware-map' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aas','application/x-authorware-seg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ai','application/x-illustrator'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aif','audio/x-aiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aifc','audio/x-aiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'aiff','audio/x-aiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ani','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'arj','application/x-arj-compressed' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'asc','text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'asf','video/x-ms-asf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'asx','video/x-ms-asf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'au','audio/basic' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'avi','video/x-msvideo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'bin','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'bmp','image/bmp' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'bqy','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cacert','application/x-x509-ca-cert' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ccad','application/clariscad' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cdf','application/x-netcdf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cgi','application/x-httpd-cgi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'class','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cpio','application/x-cpio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cpt','application/mac-compactpro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'css','text/css' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'csv','application/csv'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'cur','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dcr','application/x-director' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'deb','application/x-debian-package' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dhtml','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dir','application/x-director' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dms','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'doc','application/msword' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dot','application/msword' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'drw','application/drafting' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dump','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dvi','application/x-dvi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dwf','drawing/x-dwf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dwg','application/acad' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dxf','application/dxf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'dxr','application/x-director' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'eps','application/postscript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'etx','text/x-setext' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ez','application/andrew-inset' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh4','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh5','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh7','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fhc','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fh','image/x-freehand' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fif','image/fif' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fit','image/x-fits'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fli','video/fli' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'fm','application/filemaker'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gif','image/gif' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gtar','application/x-gtar' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gz','application/x-gzip' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'gzip','application/x-gzip' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hdf','application/hdf'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'hqx','application/mac-binhex40' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'html','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'htm','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ice','x-conference/x-cooltalk' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ico','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ief','image/ief' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'iges','application/iges' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'igs','application/iges' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jnlp','application/x-java-jnlp-file' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jpeg','image/jpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jpe','image/jpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'jpg','image/jpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'js','application/x-javascript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'kar','audio/midi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'latex','application/x-latex' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'lha','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'lzh','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm15','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm3u','audio/x-mpegurl' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'm3url','audio/x-mpegurl' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'man','application/x-troff-man' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mdb','application/vnd.ms-access'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'me','application/x-troff-me' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mesh','model/mesh' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mid','audio/midi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'midi','audio/midi' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mif','application/vnd.mif' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mime','message/rfc822' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'movie','video/x-sgi-movie' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mov','video/quicktime' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp2','audio/x-mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp2a','audio/x-mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp3','audio/x-mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp3a','audio/x-mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpeg','video/mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpe','video/mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpga','audio/x-mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpg','video/mpeg' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpv2','video/mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mp2v','video/mpeg2' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpp','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpc','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpt','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpx','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mpw','application/vnd.ms-project'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ms','application/x-troff-ms' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'msh','model/mesh' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'msw','application/msword' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'mtm','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'nc','application/x-netcdf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'oda','application/oda' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ogg','application/x-ogg'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'p65','application/x-pagemaker'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pbm','image/x-portable-bitmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pcd','image/x-photo-cd'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pdb','chemical/x-pdb' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pdf','application/pdf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pgm','image/x-portable-graymap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pgn','application/x-chess-pgn' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pict','image/x-pict' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'png','image/png' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pnm','image/x-portable-anymap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ppm','image/x-portable-pixmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ppt','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ppz','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pps','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'pot','application/vnd.ms-powerpoint' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'prc','application/x-pilot'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ps','application/postscript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'psd','application/x-photoshop'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'qt','video/quicktime' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ra','audio/x-pn-realaudio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ram','audio/x-pn-realaudio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rar','application/x-rar-compressed' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ras','image/x-cmu-raster' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rgb','image/x-rgb' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rmf', 'audio/rmf'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rm','audio/x-pn-realaudio-plugin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rmm','audio/x-pn-realaudio-plugin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'roff','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rp','application/x-pn-realmedia' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rpm','audio/x-pn-realaudio-plugin' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rr','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rtf','application/rtf' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'rtx','text/enriched' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 's3m','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sd2','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sdp','application/sdp' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sea','application/x-stuffit' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sgml','text/sgml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sgm','text/sgml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'shtml','text/html' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'silo','model/mesh' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sit','application/x-stuffit' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skd','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skm','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skp','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'skt','application/vnd.koan' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'snd','audio/basic' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'spl','application/futuresplash' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'stl','application/sla' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'stm','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sv4cpio','application/x-sv4cpio' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'sv4crc','application/x-sv4crc' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'svg','image/xml+svg'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'swf','application/x-shockwave-flash' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 't','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tar','application/x-tar' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tex','application/x-tex' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'texi','application/x-texinfo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'texinfo','application/x-texinfo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'text','text/plain; format=flowed'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tiff','image/tiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tif','image/tiff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tr','application/x-troff' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'tsv','text/tab-separated-values' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'txt','text/plain' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ult','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'ustar','application/x-ustar' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'uu','application/octet-stream' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vcd','application/x-cdlink' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vcf','application/vcard' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vdo','video/vdo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vda','application/vda' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vivo','video/vnd.vivo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'viv','video/vnd.vivo' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'voc','audio/voice'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vrml','x-world/x-vrml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'vrm','x-world/x-vrml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wav','audio/x-wav' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wb1','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wb2','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wb3','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wbmp','image/vnd.wap.wbmp' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'web','application/vnd.xara' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wis','application/x-installshield' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wma','audio/x-ms-wma' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmd','application/x-ms-wmd' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmlc','application/vnd.wap.wmlc' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmlsc','application/vnd.wap.wmlscriptc' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmls','text/vnd.wap.wmlscript' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wml','text/vnd.wap.wml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmv','audio/x-ms-wmv' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wm','video/x-ms-wm' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmx','video/x-mx-wmx' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wmz','application/x-ms-wmz' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wpd','application/wordperfect' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wq1','application/x-quattro-pro' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wrl','x-world/x-vrml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'wvx','video/x-ms-wvx' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xar','application/vnd.xara' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'w60','application/wordperfect6.0'); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xbm','image/x-xbitmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xlc','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xls','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xlm','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xlw','application/vnd.ms-excel' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xm','audio/x-mod' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xml','text/xml' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xpm','image/x-xpixmap' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xsl','text/xsl' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xuda','xuda/gen-cert' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xwd','image/x-xwindowdump' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'xyz','chemical/x-xyz' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'z','application/x-compress' ); insert into tmp_cr_extension_mime_type_map (extension, mime_type) values ( 'zip','application/zip' ); -- Now update the existing data taking care not to mess anything up. -- Add the mime types that don't already exist. -- don't add extensions yet since we do that later to prevent -- duplicates in the insert into cr_mime_types select label, mime_type, null from tmp_cr_mime_types n where not exists ( select 1 from cr_mime_types o where o.mime_type = n.mime_type); -- Provide extension for mime types with missing ones and which are -- not in use for another mime type. update cr_mime_types set label = ( select label from tmp_cr_mime_types n where n.mime_type = cr_mime_types.mime_type) where label is null; -- Add extensions, verify extension not already used by another mime type. -- have to do this since we don't want to introduce duplicate -- extensions since there is still code using the cr_mime_types table to -- look up mime_type. update cr_mime_types set file_extension = ( select file_extension from tmp_cr_mime_types m where m.mime_type = cr_mime_types.mime_type and not exists (select * from cr_mime_types c where m.file_extension = c.file_extension)) where file_extension is null; -- Create a mapping entry for existing mime types. -- we make sure we only get one mapping per extension just in case insert into cr_extension_mime_type_map (extension, mime_type) select file_extension, min(mime_type) from cr_mime_types where file_extension is not null group by file_extension; -- insert all the rest that are not being used insert into cr_extension_mime_type_map select extension, mime_type from tmp_cr_extension_mime_type_map n where not exists ( select 1 from cr_extension_mime_type_map o where o.extension = n.extension ); drop table tmp_cr_mime_types; drop table tmp_cr_extension_mime_type_map; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.4.1d1-5.4.1d2.sql0000644000175000017500000000040010765512671031572 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2008-03-11 -- @cvs-id $Id: upgrade-5.4.1d1-5.4.1d2.sql,v 1.1 2008/03/11 14:22:49 daveb Exp $ -- select define_function_args('content_type__is_content_type','object_type'); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.4d4-5.1.4d5.sql0000644000175000017500000002437110207353612031602 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-01-05 -- @arch-tag: 5be8fd4b-0259-4ded-905a-37cb95b7fa9f -- @cvs-id $Id: upgrade-5.1.4d4-5.1.4d5.sql,v 1.3 2005/02/24 13:32:58 jeffd Exp $ -- -- procedure delete select define_function_args('content_folder__del','folder_id,cascade_p;f'); create or replace function content_folder__del (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; v_count integer; v_child_row record; v_parent_id integer; v_path varchar; v_folder_sortkey varbit; begin if p_cascade_p = ''f'' then select count(*) into v_count from cr_items where parent_id = delete__folder_id; -- check if the folder contains any items if v_count > 0 then v_path := content_item__get_path(delete__folder_id, null); raise EXCEPTION ''-20000: Folder ID % (%) cannot be deleted because it is not empty.'', delete__folder_id, v_path; end if; else -- delete children select into v_folder_sortkey tree_sortkey from cr_items where item_id=delete__folder_id; for v_child_row in select item_id, tree_sortkey, name from cr_items where tree_sortkey between v_folder_sortkey and tree_right(v_folder_sortkey) and tree_sortkey != v_folder_sortkey order by tree_sortkey desc loop if content_folder__is_folder(v_child_row.item_id) then perform content_folder__delete(v_child_row.item_id); else perform content_item__delete(v_child_row.item_id); end if; end loop; end if; PERFORM content_folder__unregister_content_type( delete__folder_id, ''content_revision'', ''t'' ); delete from cr_folder_type_map where folder_id = delete__folder_id; select parent_id into v_parent_id from cr_items where item_id = delete__folder_id; raise notice ''deleteing folder %'',delete__folder_id; PERFORM content_item__delete(delete__folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = ''f'' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = ''content_folder''); return 0; end;' language 'plpgsql'; select define_function_args('content_folder__delete','folder_id,cascade_p;f'); create or replace function content_folder__delete (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; begin PERFORM content_folder__del(delete__folder_id,p_cascade_p); return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer) returns integer as ' declare delete__folder_id alias for $1; v_count integer; v_parent_id integer; v_path varchar; begin return content_folder__del( delete__folder_id, ''f'' ); end;' language 'plpgsql'; -- procedure delete select define_function_args('content_revision__del','revision_id'); create or replace function content_revision__delete (integer) returns integer as ' declare delete__revision_id alias for $1; v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; v_rec record; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = delete__revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = delete__revision_id then for v_rec in select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> delete__revision_id order by o.creation_date desc LOOP v_latest_revision := v_rec.revision_id; exit; end LOOP; if NOT FOUND then v_latest_revision := null; end if; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end if; -- Clear live revision if v_live_revision = delete__revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = delete__revision_id or new_revision = delete__revision_id; -- Delete the revision PERFORM acs_object__delete(delete__revision_id); return 0; end;' language 'plpgsql'; select define_function_args('content_revision__delete','revision_id'); create or replace function content_revision__delete (integer) returns integer as ' declare delete__revision_id alias for $1; begin PERFORM content_revision__del(delete__revision_id); return 0; end;' language 'plpgsql'; -- item select define_function_args('content_item__del','item_id'); create or replace function content_item__del (integer) returns integer as ' declare delete__item_id alias for $1; -- v_wf_cases_val record; v_symlink_val record; v_revision_val record; v_rel_val record; begin -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- raise NOTICE ''Deleting associated workflows...''; -- 1) delete all workflow cases associated with this item -- for v_wf_cases_val in select -- case_id -- from -- wf_cases -- where -- object_id = delete__item_id -- LOOP -- PERFORM workflow_case__delete(v_wf_cases_val.case_id); -- end loop; raise NOTICE ''Deleting symlinks...''; -- 2) delete all symlinks to this item for v_symlink_val in select symlink_id from cr_symlinks where target_id = delete__item_id LOOP PERFORM content_symlink__delete(v_symlink_val.symlink_id); end loop; raise NOTICE ''Unscheduling item...''; delete from cr_release_periods where item_id = delete__item_id; raise NOTICE ''Deleting associated revisions...''; -- 3) delete all revisions of this item delete from cr_item_publish_audit where item_id = delete__item_id; for v_revision_val in select revision_id from cr_revisions where item_id = delete__item_id LOOP PERFORM acs_object__delete(v_revision_val.revision_id); end loop; raise NOTICE ''Deleting associated item templates...''; -- 4) unregister all templates to this item delete from cr_item_template_map where item_id = delete__item_id; raise NOTICE ''Deleting item relationships...''; -- Delete all relations on this item for v_rel_val in select rel_id from cr_item_rels where item_id = delete__item_id or related_object_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); end loop; raise NOTICE ''Deleting child relationships...''; for v_rel_val in select rel_id from cr_child_rels where child_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); end loop; raise NOTICE ''Deleting parent relationships...''; for v_rel_val in select rel_id, child_id from cr_child_rels where parent_id = delete__item_id LOOP PERFORM acs_rel__delete(v_rel_val.rel_id); PERFORM content_item__delete(v_rel_val.child_id); end loop; raise NOTICE ''Deleting associated permissions...''; -- 5) delete associated permissions delete from acs_permissions where object_id = delete__item_id; raise NOTICE ''Deleting keyword associations...''; -- 6) delete keyword associations delete from cr_item_keyword_map where item_id = delete__item_id; raise NOTICE ''Deleting associated comments...''; -- 7) delete associated comments PERFORM journal_entry__delete_for_object(delete__item_id); -- context_id debugging loop --for v_error_val in c_error_cur loop -- raise NOTICE ''ID='' || v_error_val.object_id || '' TYPE='' -- || v_error_val.object_type); --end loop; raise NOTICE ''Deleting content item...''; PERFORM acs_object__delete(delete__item_id); return 0; end;' language 'plpgsql'; select define_function_args('content_item__delete','item_id'); create or replace function content_item__delete (integer) returns integer as ' declare delete__item_id alias for $1; begin PERFORM content_item__del (delete__item_id); return 0; end;' language 'plpgsql'; -- template select define_function_args('content_template__del','template_id'); create or replace function content_template__del (integer) returns integer as ' declare delete__template_id alias for $1; begin delete from cr_type_template_map where template_id = delete__template_id; delete from cr_item_template_map where template_id = delete__template_id; delete from cr_templates where template_id = delete__template_id; PERFORM content_item__delete(delete__template_id); return 0; end;' language 'plpgsql'; select define_function_args('content_template__delete','template_id'); create or replace function content_template__delete (integer) returns integer as ' declare delete__template_id alias for $1; begin PERFORM content_template__delete(delete__template_id); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.3.0d2-5.3.0d3.sql0000644000175000017500000000760310505466741031602 0ustar frankiefrankieselect define_function_args('content_type__drop_type','content_type,drop_children_p;f,drop_table_p;f,drop_objects_p;f'); create or replace function content_type__drop_type (varchar,boolean,boolean,boolean) returns integer as ' declare drop_type__content_type alias for $1; drop_type__drop_children_p alias for $2; -- default ''f'' drop_type__drop_table_p alias for $3; -- default ''f'' drop_type__drop_objects_p alias for $4; -- default ''f'' table_exists_p boolean; v_table_name varchar; is_subclassed_p boolean; child_rec record; attr_row record; revision_row record; item_row record; begin -- first we''ll rid ourselves of any dependent child types, if any , -- along with their own dependent grandchild types select count(*) > 0 into is_subclassed_p from acs_object_types where supertype = drop_type__content_type; -- this is weak and will probably break; -- to remove grand child types, the process will probably -- require some sort of querying for drop_type -- methods within the children''s packages to make -- certain there are no additional unanticipated -- restraints preventing a clean drop if drop_type__drop_children_p and is_subclassed_p then for child_rec in select object_type from acs_object_types where supertype = drop_type__content_type LOOP PERFORM content_type__drop_type(child_rec.object_type, ''t'', drop_type__drop_table_p, drop_type__drop_objects_p); end LOOP; end if; -- now drop all the attributes related to this type for attr_row in select attribute_name from acs_attributes where object_type = drop_type__content_type LOOP PERFORM content_type__drop_attribute(drop_type__content_type, attr_row.attribute_name, ''f'' ); end LOOP; -- we''ll remove the associated table if it exists select table_exists(lower(table_name)) into table_exists_p from acs_object_types where object_type = drop_type__content_type; if table_exists_p and drop_type__drop_table_p then select table_name into v_table_name from acs_object_types where object_type = drop_type__content_type; -- drop the rule and input/output views for the type -- being dropped. -- FIXME: this did not exist in the oracle code and it needs to be -- tested. Thanks to Vinod Kurup for pointing this out. -- The rule dropping might be redundant as the rule might be dropped -- when the view is dropped. -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). execute ''drop table '' || v_table_name || '' cascade''; end if; -- If we are dealing with a revision, delete the revision with revision__delete -- This way the integrity constraint with live revision is dealt with correctly if drop_type__drop_objects_p then for revision_row in select revision_id from cr_revisions, acs_objects where revision_id = object_id and object_type = drop_type__content_type loop PERFORM content_revision__delete(revision_row.revision_id); end loop; for item_row in select item_id from cr_items where content_type = drop_type__content_type loop PERFORM content_item__delete(item_row.item_id); end loop; end if; PERFORM acs_object_type__drop_type(drop_type__content_type, drop_type__drop_objects_p); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-4.6.5-4.7d6.sql0000644000175000017500000000610507702263321031221 0ustar frankiefrankie-- Make two new versions of content_template__new() and make the one that is a wrapper -- (the first one) take two new params; new__text and new__is_live. -- With this version, a revision of the template will be created automatically. -- You thus avoid calling content_revision.new() in a separate step ... -- (ola@polyxena.net) create or replace function content_template__new(varchar,text,bool) returns integer as ' declare new__name alias for $1; new__text alias for $2; new__is_live alias for $3; begin return content_template__new(new__name, null, null, now(), null, null, new__text, new__is_live ); end;' language 'plpgsql'; create or replace function content_template__new (varchar,integer,integer,timestamptz,integer,varchar,text,bool) returns integer as ' declare new__name alias for $1; new__parent_id alias for $2; -- default null new__template_id alias for $3; -- default null new__creation_date alias for $4; -- default now() new__creation_user alias for $5; -- default null new__creation_ip alias for $6; -- default null new__text alias for $7; -- default null new__is_live alias for $8; -- default ''f'' v_template_id cr_templates.template_id%TYPE; v_parent_id cr_items.parent_id%TYPE; begin if new__parent_id is null then v_parent_id := content_template_globals.c_root_folder_id; else v_parent_id := new__parent_id; end if; -- make sure we''re allowed to create a template in this folder if content_folder__is_folder(new__parent_id) = ''t'' and content_folder__is_registered(new__parent_id,''content_template'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow templates to be created''; else v_template_id := content_item__new ( new__template_id, -- new__item_id new__name, -- new__name v_parent_id, -- new__parent_id null, -- new__title new__creation_date, -- new__creation_date new__creation_user, -- new__creation_user null, -- new__context_id new__creation_ip, -- new__creation_ip new__is_live, -- new__is_live ''text/plain'', -- new__mime_type new__text, -- new__text ''text'', -- new__storage_type ''t'', -- new__security_inherit_p ''CR_FILES'', -- new__storage_area_key ''content_item'', -- new__item_subtype ''content_template'' -- new__content_type ); insert into cr_templates ( template_id ) values ( v_template_id ); return v_template_id; end if; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d16-5.2.0d17.sql0000644000175000017500000000711710251656025031744 0ustar frankiefrankie-- procedure refresh_trigger select define_function_args('content_type__refresh_trigger','content_type'); create or replace function content_type__refresh_trigger (varchar) returns integer as ' declare refresh_trigger__content_type alias for $1; rule_text text default ''''; v_table_name acs_object_types.table_name%TYPE; type_rec record; begin -- get the table name for the content type (determines view name) select table_name into v_table_name from acs_object_types where object_type = refresh_trigger__content_type; --=================== start building rule code ======================= rule_text := ''create rule '' || v_table_name || ''_r as on insert to '' || v_table_name || ''i do instead ( update cr_dummy set val = ( select content_revision__new( new.title, new.description, now(), new.mime_type, new.nls_language, case when new.text is null then new.data else new.text end, content_symlink__resolve(new.item_id), new.revision_id, now(), new.creation_user, new.creation_ip, new.object_package_id )); ''; -- add an insert statement for each subtype in the hierarchy for this type for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2 where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and ot1.object_type = refresh_trigger__content_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level desc LOOP rule_text := rule_text || '' '' || content_type__trigger_insert_statement(type_rec.object_type) || '';''; end loop; -- end building the rule definition code rule_text := rule_text || '' );''; --================== done building rule code ======================= -- drop the old rule if rule_exists(v_table_name || ''_r'', v_table_name || ''i'') then -- different syntax for dropping a rule in 7.2 and 7.3 so check which -- version is being used (olah). if version() like ''%PostgreSQL 7.2%'' then execute ''drop rule '' || v_table_name || ''_r''; else -- 7.3 syntax execute ''drop rule '' || v_table_name || ''_r '' || ''on '' || v_table_name || ''i''; end if; end if; -- create the new rule for inserts on the content type execute rule_text; return null; end;' language 'plpgsql'; create function inline_0 () returns integer as ' declare ct RECORD; v_dummy integer; begin for ct in select object_type from acs_object_type_supertype_map where ancestor_type = ''content_revision'' loop select content_type__refresh_trigger (ct.object_type) into v_dummy; end loop; return null; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.5.0d3-5.5.0d4.sql0000644000175000017500000000026111165236261031574 0ustar frankiefrankiealter table cr_revisions drop constraint cr_revisions_lob_fk; alter table cr_revisions add constraint cr_revisions_lob_fk foreign key (lob) references lobs on delete set null; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.1.5d3-5.1.5d4.sql0000644000175000017500000000370110210402651031564 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-02-27 -- @arch-tag: 0c2560da-f1ba-4fd7-b02d-608cd4d35f47 -- @cvs-id $Id: upgrade-5.1.5d3-5.1.5d4.sql,v 1.1 2005/02/27 17:38:49 daveb Exp $ -- -- fix bug#2298 create or replace function content_revision__del (integer) returns integer as ' declare delete__revision_id alias for $1; v_item_id cr_items.item_id%TYPE; v_latest_revision cr_revisions.revision_id%TYPE; v_live_revision cr_revisions.revision_id%TYPE; v_rec record; begin -- Get item id and latest/live revisions select item_id into v_item_id from cr_revisions where revision_id = delete__revision_id; select latest_revision, live_revision into v_latest_revision, v_live_revision from cr_items where item_id = v_item_id; -- Recalculate latest revision if v_latest_revision = delete__revision_id then for v_rec in select r.revision_id from cr_revisions r, acs_objects o where o.object_id = r.revision_id and r.item_id = v_item_id and r.revision_id <> delete__revision_id order by o.creation_date desc LOOP v_latest_revision := v_rec.revision_id; exit; end LOOP; if NOT FOUND then v_latest_revision := null; end if; update cr_items set latest_revision = v_latest_revision where item_id = v_item_id; end if; -- Clear live revision if v_live_revision = delete__revision_id then update cr_items set live_revision = null where item_id = v_item_id; end if; -- Clear the audit delete from cr_item_publish_audit where old_revision = delete__revision_id or new_revision = delete__revision_id; -- Delete the revision PERFORM acs_object__delete(delete__revision_id); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0d12-5.2.0d13.sql0000644000175000017500000003505310217316666031742 0ustar frankiefrankie-- -- daveb fixes for content_folder__move. -- select define_function_args('content_folder__move','folder_id,target_folder_id,name;NULL'); create or replace function content_folder__move (integer,integer,varchar) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; v_source_folder_id integer; v_valid_folders_p integer; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move__target_folder_id or folder_id = move__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.move - Not valid folder(s)''; end if; if move__folder_id = content_item__get_root_folder(null) or move__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.move - Cannot move root folder''; end if; if move__target_folder_id = move__folder_id then raise EXCEPTION ''-20000: content_folder.move - Cannot move a folder to itself''; end if; if content_folder__is_sub_folder(move__folder_id, move__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder is subfolder''; end if; if content_folder__is_registered(move__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder does not allow subfolders''; end if; select parent_id into v_source_folder_id from cr_items where item_id = move__folder_id; -- update the parent_id for the folder update cr_items set parent_id = move__target_folder_id, name = coalesce ( move__name, name ) where item_id = move__folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = ''f'' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = ''content_folder''); -- update the destination update cr_folders set has_child_folders = ''t'' where folder_id = move__target_folder_id; return 0; end;' language 'plpgsql'; create or replace function content_folder__move (integer,integer) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; begin perform content_folder__move ( move__folder_id, move__target_folder_id, NULL ); return null; end;' language 'plpgsql'; create or replace function content_folder__copy (integer,integer,integer,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin v_new_folder_id := content_folder__copy ( copy__folder_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, NULL ); return v_new_folder_id; end;' language 'plpgsql'; create or replace function content_folder__copy (integer,integer,integer,varchar,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = copy__target_folder_id or folder_id = copy__folder_id; select parent_id into v_current_folder_id from cr_items where item_id = copy__folder_id; if copy__folder_id = content_item__get_root_folder(null) or copy__folder_id = content_template__get_root_folder() or copy__target_folder_id = copy__folder_id then v_valid_folders_p := 0; end if; -- get the source folder info select name, label, description into v_name, v_label, v_description from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy__folder_id; if v_valid_folders_p = 2 then if content_folder__is_sub_folder(copy__folder_id, copy__target_folder_id) != ''t'' or v_current_folder_id != copy__target_folder_id or (v_name != copy__name and copy__name is not null) then -- create the new folder v_new_folder_id := content_folder__new ( coalesce (copy__name, v_name), v_label, v_description, copy__target_folder_id, copy__target_folder_id, null, now(), copy__creation_user, copy__creation_ip, ''t'', null ); -- copy attributes of original folder insert into cr_folder_type_map select v_new_folder_id as folder_id, content_type from cr_folder_type_map map where folder_id = copy__folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in select item_id from cr_items where parent_id = copy__folder_id LOOP PERFORM content_item__copy( v_folder_contents_val.item_id, v_new_folder_id, copy__creation_user, copy__creation_ip, null ); end loop; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_revision__copy (integer,integer,integer,integer,varchar) returns integer as ' declare copy__revision_id alias for $1; copy__copy_id alias for $2; -- default null copy__target_item_id alias for $3; -- default null copy__creation_user alias for $4; -- default null copy__creation_ip alias for $5; -- default null v_copy_id cr_revisions.revision_id%TYPE; v_target_item_id cr_items.item_id%TYPE; type_rec record; begin -- use the specified item_id or the item_id of the original revision -- if none is specified if copy__target_item_id is null then select item_id into v_target_item_id from cr_revisions where revision_id = copy__revision_id; else v_target_item_id := copy__target_item_id; end if; -- use the copy_id or generate a new copy_id if none is specified -- the copy_id is a revision_id if copy__copy_id is null then select acs_object_id_seq.nextval into v_copy_id from dual; else v_copy_id := copy__copy_id; end if; -- create the basic object insert into acs_objects ( object_id, object_type, context_id, security_inherit_p, creation_user, creation_date, creation_ip, last_modified, modifying_user, modifying_ip, title, package_id) select v_copy_id as object_id, object_type, v_target_item_id, security_inherit_p, copy__creation_user as creation_user, now() as creation_date, copy__creation_ip as creation_ip, now() as last_modified, copy__creation_user as modifying_user, copy__creation_ip as modifying_ip, title, package_id from acs_objects where object_id = copy__revision_id; -- create the basic revision (using v_target_item_id) insert into cr_revisions select v_copy_id as revision_id, v_target_item_id as item_id, title, description, publish_date, mime_type, nls_language, lob, content, content_length from cr_revisions where revision_id = copy__revision_id; -- iterate over the ancestor types and copy attributes for type_rec in select ot2.object_type, tree_level(ot2.tree_sortkey) as level from acs_object_types ot1, acs_object_types ot2, acs_objects o where ot2.object_type <> ''acs_object'' and ot2.object_type <> ''content_revision'' and o.object_id = copy__revision_id and ot1.object_type = o.object_type and ot1.tree_sortkey between ot2.tree_sortkey and tree_right(ot2.tree_sortkey) order by level desc LOOP PERFORM content_revision__copy_attributes(type_rec.object_type, copy__revision_id, v_copy_id); end loop; return v_copy_id; end;' language 'plpgsql'; select define_function_args('content_item__copy','item_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_item__copy ( integer, integer, integer, varchar, varchar ) returns integer as ' declare copy__item_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_current_folder_id cr_folders.folder_id%TYPE; v_num_revisions integer; v_name cr_items.name%TYPE; v_content_type cr_items.content_type%TYPE; v_locale cr_items.locale%TYPE; v_item_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_is_registered boolean; v_old_revision_id cr_revisions.revision_id%TYPE; v_new_revision_id cr_revisions.revision_id%TYPE; v_old_live_revision_id cr_revisions.revision_id%TYPE; v_new_live_revision_id cr_revisions.revision_id%TYPE; v_storage_type cr_items.storage_type%TYPE; begin -- call content_folder.copy if the item is a folder if content_folder__is_folder(copy__item_id) = ''t'' then PERFORM content_folder__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_symlink.copy if the item is a symlink else if content_symlink__is_symlink(copy__item_id) = ''t'' then PERFORM content_symlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- call content_extlink.copy if the item is an url else if content_extlink__is_extlink(copy__item_id) = ''t'' then PERFORM content_extlink__copy( copy__item_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, copy__name ); -- make sure the target folder is really a folder else if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__item_id; select content_type, name, locale, coalesce(live_revision, latest_revision), storage_type into v_content_type, v_name, v_locale, v_revision_id, v_storage_type from cr_items where item_id = copy__item_id; -- copy to a different folder, or allow copy to the same folder -- with a different name if copy__target_folder_id != v_current_folder_id or ( v_name != copy__name and copy__name is not null ) then -- make sure the content type of the item is registered to the folder v_is_registered := content_folder__is_registered( copy__target_folder_id, v_content_type, ''f'' ); if v_is_registered = ''t'' then -- create the new content item v_item_id := content_item__new( coalesce (copy__name, v_name), copy__target_folder_id, null, v_locale, now(), copy__creation_user, null, copy__creation_ip, ''content_item'', v_content_type, null, null, ''text/plain'', null, null, v_storage_type ); select latest_revision, live_revision into v_old_revision_id, v_old_live_revision_id from cr_items where item_id = copy__item_id; end if; -- copy the latest revision (if any) to the new item if v_old_revision_id is not null then v_new_revision_id := content_revision__copy ( v_old_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); end if; -- copy the live revision (if there is one and it differs from the latest) to the new item if v_old_live_revision_id is not null then if v_old_live_revision_id <> v_old_revision_id then v_new_live_revision_id := content_revision__copy ( v_old_live_revision_id, null, v_item_id, copy__creation_user, copy__creation_ip ); else v_new_live_revision_id := v_new_revision_id; end if; end if; update cr_items set live_revision = v_new_live_revision, latest_revision = v_new_revision_id where item_id = v_item_id; end if; end if; end if; end if; end if; return v_item_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.0.0b3-5.0.0b4.sql0000644000175000017500000005245310263064665031575 0ustar frankiefrankiecreate or replace function content_item__get_content_type (integer) returns varchar as ' declare get_content_type__item_id alias for $1; v_content_type cr_items.content_type%TYPE; begin select content_type into v_content_type from cr_items where item_id = get_content_type__item_id; return v_content_type; end;' language 'plpgsql' stable strict; create or replace function content_item__get_best_revision (integer) returns integer as ' declare get_best_revision__item_id alias for $1; v_revision_id cr_revisions.revision_id%TYPE; begin select coalesce(live_revision, latest_revision ) into v_revision_id from cr_items where item_id = get_best_revision__item_id; return v_revision_id; end;' language 'plpgsql' stable strict; create or replace function content_item__get_context (integer) returns integer as ' declare get_context__item_id alias for $1; v_context_id acs_objects.context_id%TYPE; begin select context_id into v_context_id from acs_objects where object_id = get_context__item_id; if NOT FOUND then raise EXCEPTION ''-20000: Content item % does not exist in content_item.get_context'', get_context__item_id; end if; return v_context_id; end;' language 'plpgsql' stable; create or replace function content_item__get_latest_revision (integer) returns integer as ' declare get_latest_revision__item_id alias for $1; v_revision_id integer; v_rec record; begin for v_rec in select r.revision_id from cr_revisions r, acs_objects o where r.revision_id = o.object_id and r.item_id = get_latest_revision__item_id order by o.creation_date desc LOOP v_revision_id := v_rec.revision_id; exit; end LOOP; return v_revision_id; end;' language 'plpgsql' strict stable; create or replace function content_item__get_live_revision (integer) returns integer as ' declare get_live_revision__item_id alias for $1; v_revision_id acs_objects.object_id%TYPE; begin select live_revision into v_revision_id from cr_items where item_id = get_live_revision__item_id; return v_revision_id; end;' language 'plpgsql' stable strict; -- there was an infinite loop in content_item.get_parent_folder if called with -- a child content_item rather than a content item which was directly below a -- folder. create or replace function content_item__get_parent_folder (integer) returns integer as ' declare get_parent_folder__item_id alias for $1; v_folder_id cr_folders.folder_id%TYPE; v_parent_folder_p boolean default ''f''; begin v_folder_id := get_parent_folder__item_id; while NOT v_parent_folder_p and v_folder_id is not null LOOP select parent_id, content_folder__is_folder(parent_id) into v_folder_id, v_parent_folder_p from cr_items where item_id = v_folder_id; end loop; return v_folder_id; end;' language 'plpgsql' stable strict; create or replace function content_item__get_publish_date (integer,boolean) returns timestamptz as ' declare get_publish_date__item_id alias for $1; get_publish_date__is_live alias for $2; -- default ''f'' v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if get_publish_date__is_live then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date__item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date__item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; end;' language 'plpgsql' stable; create or replace function content_item__get_publish_date (integer,boolean) returns timestamptz as ' declare get_publish_date__item_id alias for $1; get_publish_date__is_live alias for $2; -- default ''f'' v_revision_id cr_revisions.revision_id%TYPE; v_publish_date cr_revisions.publish_date%TYPE; begin if get_publish_date__is_live then select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date__item_id and r.revision_id = i.live_revision; else select publish_date into v_publish_date from cr_revisions r, cr_items i where i.item_id = get_publish_date__item_id and r.revision_id = i.latest_revision; end if; return v_publish_date; end;' language 'plpgsql' stable; -- This used to have a pretty gross loop and sort. -- create or replace function content_item__is_subclass (varchar,varchar) returns boolean as ' declare is_subclass__object_type alias for $1; is_subclass__supertype alias for $2; v_subclass_p boolean; v_inherit_val record; begin select count(*) > 0 into v_subclass_p where exists ( select 1 from acs_object_types o, acs_object_types o2 where o2.object_type = is_subclass__supertype and o.object_type = is_subclass__object_type and o.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)); return v_subclass_p; end;' language 'plpgsql' stable; create or replace function content_item__is_publishable (integer) returns boolean as ' declare is_publishable__item_id alias for $1; v_child_count integer; v_rel_count integer; v_template_id cr_templates.template_id%TYPE; v_child_type record; v_rel_type record; v_content_type varchar; -- v_pub_wf record; begin -- check valid item_id select content_item__get_content_type(is_publishable__item_id) into v_content_type; if v_content_type is null then raise exception ''content_item__is_publishable item_id % invalid'',is_publishable__item_id; end if; -- validate children -- make sure the # of children of each type fall between min_n and max_n for v_child_type in select child_type, min_n, max_n from cr_type_children where parent_type = v_content_type and (min_n is not null or max_n is not null) LOOP select count(rel_id) into v_child_count from cr_child_rels where parent_id = is_publishable__item_id and content_item__get_content_type(child_id) = v_child_type.child_type; -- make sure # of children is in range if v_child_type.min_n is not null and v_child_count < v_child_type.min_n then return ''f''; end if; if v_child_type.max_n is not null and v_child_count > v_child_type.max_n then return ''f''; end if; end LOOP; -- validate relations -- make sure the # of ext links of each type fall between min_n and max_n -- only check if one of min_n max_n not null for v_rel_type in select target_type, min_n, max_n from cr_type_relations where content_type = v_content_type and (max_n is not null or min_n is not null) LOOP select count(rel_id) into v_rel_count from cr_item_rels i, acs_objects o where i.related_object_id = o.object_id and i.item_id = is_publishable__item_id and coalesce(content_item__get_content_type(o.object_id),o.object_type) = v_rel_type.target_type; -- make sure # of object relations is in range if v_rel_type.min_n is not null and v_rel_count < v_rel_type.min_n then return ''f''; end if; if v_rel_type.max_n is not null and v_rel_count > v_rel_type.max_n then return ''f''; end if; end loop; -- validate publishing workflows -- make sure any ''publishing_wf'' associated with this item are finished -- KG: logic is wrong here. Only the latest workflow matters, and even -- that is a little problematic because more than one workflow may be -- open on an item. In addition, this should be moved to CMS. -- Removed this as having workflow stuff in the CR is just plain wrong. -- DanW, Aug 25th, 2001. -- for v_pub_wf in select -- case_id, state -- from -- wf_cases -- where -- workflow_key = ''publishing_wf'' -- and -- object_id = is_publishable__item_id -- -- LOOP -- if v_pub_wf.state != ''finished'' then -- return ''f''; -- end if; -- end loop; -- if NOT FOUND then -- return ''f''; -- end if; return ''t''; end;' language 'plpgsql' stable; create or replace function content_item__move (integer,integer) returns integer as ' declare move__item_id alias for $1; move__target_folder_id alias for $2; begin if move__target_folder_id is null then raise exception ''attempt to move item_id % to null folder_id'', move__item_id; end if; if content_folder__is_folder(move__item_id) = ''t'' then PERFORM content_folder__move(move__item_id, move__target_folder_id); else if content_folder__is_folder(move__target_folder_id) = ''t'' then if content_folder__is_registered(move__target_folder_id, content_item__get_content_type(move__item_id),''f'') = ''t'' and content_folder__is_registered(move__target_folder_id, content_item__get_content_type(content_symlink__resolve(move__item_id)),''f'') = ''t'' then -- update the parent_id for the item update cr_items set parent_id = move__target_folder_id where item_id = move__item_id; end if; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_revision__copy_attributes (varchar,integer,integer) returns integer as ' declare copy_attributes__content_type alias for $1; copy_attributes__revision_id alias for $2; copy_attributes__copy_id alias for $3; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; attr_rec record; begin if copy_attributes__content_type is null or copy_attributes__revision_id is null or copy_attributes__copy_id is null then raise exception ''content_revision__copy_attributes called with null % % %'',copy_attributes__content_type,copy_attributes__revision_id, copy_attributes__copy_id; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = copy_attributes__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = copy_attributes__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; end loop; execute ''insert into '' || v_table_name || '' select '' || copy_attributes__copy_id || '' as '' || v_id_column || cols || '' from '' || v_table_name || '' where '' || v_id_column || '' = '' || copy_attributes__revision_id; return 0; end;' language 'plpgsql'; create or replace function content_keyword__is_assigned (integer,integer,varchar) returns boolean as ' declare is_assigned__item_id alias for $1; is_assigned__keyword_id alias for $2; is_assigned__recurse alias for $3; -- default ''none'' v_ret boolean; v_is_assigned__recurse varchar; begin if is_assigned__recurse is null then v_is_assigned__recurse := ''none''; else v_is_assigned__recurse := is_assigned__recurse; end if; -- Look for an exact match if v_is_assigned__recurse = ''none'' then return count(*) > 0 from cr_item_keyword_map where item_id = is_assigned__item_id and keyword_id = is_assigned__keyword_id; end if; -- Look from specific to general if v_is_assigned__recurse = ''up'' then return count(*) > 0 where exists (select 1 from (select keyword_id from cr_keywords c, cr_keywords c2 where c2.keyword_id = is_assigned__keyword_id and c.tree_sortkey between c2.tree_sortkey and tree_right(c2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; if v_is_assigned__recurse = ''down'' then return count(*) > 0 where exists (select 1 from (select k2.keyword_id from cr_keywords k1, cr_keywords k2 where k1.keyword_id = is_assigned__keyword_id and k1.tree_sortkey between k2.tree_sortkey and tree_right(k2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; -- Tried none, up and down - must be an invalid parameter raise EXCEPTION ''-20000: The recurse parameter to content_keyword.is_assigned should be \\\'none\\\', \\\'up\\\' or \\\'down\\\'''; return null; end;' language 'plpgsql' stable; create or replace function content_folder__is_registered (integer,varchar,boolean) returns boolean as ' declare is_registered__folder_id alias for $1; is_registered__content_type alias for $2; is_registered__include_subtypes alias for $3; -- default ''f'' v_is_registered integer; v_subtype_val record; begin if is_registered__include_subtypes = ''f'' or is_registered__include_subtypes is null then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered__folder_id and content_type = is_registered__content_type; else -- select -- object_type -- from -- acs_object_types -- where -- object_type <> ''acs_object'' -- connect by -- prior object_type = supertype -- start with -- object_type = is_registered.content_type v_is_registered := 1; for v_subtype_val in select o.object_type from acs_object_types o, acs_object_types o2 where o.object_type <> ''acs_object'' and o2.object_type = is_registered__content_type and o.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey) order by o.tree_sortkey LOOP if content_folder__is_registered(is_registered__folder_id, v_subtype_val.object_type, ''f'') = ''f'' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return ''f''; else return ''t''; end if; end;' language 'plpgsql' stable; create or replace function content_revision__content_copy (integer,integer) returns integer as ' declare content_copy__revision_id alias for $1; content_copy__revision_id_dest alias for $2; -- default null v_item_id cr_items.item_id%TYPE; v_content_length cr_revisions.content_length%TYPE; v_revision_id_dest cr_revisions.revision_id%TYPE; v_content cr_revisions.content%TYPE; v_lob cr_revisions.lob%TYPE; v_new_lob cr_revisions.lob%TYPE; v_storage_type varchar; begin if content_copy__revision_id is null then raise exception ''content_revision__content_copy attempt to copy a null revision_id''; end if; select content_length, item_id into v_content_length, v_item_id from cr_revisions where revision_id = content_copy__revision_id; -- get the destination revision if content_copy__revision_id_dest is null then select latest_revision into v_revision_id_dest from cr_items where item_id = v_item_id; else v_revision_id_dest := content_copy__revision_id_dest; end if; -- only copy the content if the source content is not null if v_content_length is not null and v_content_length > 0 then /* The internal LOB types - BLOB, CLOB, and NCLOB - use copy semantics, as opposed to the reference semantics which apply to BFILEs. When a BLOB, CLOB, or NCLOB is copied from one row to another row in the same table or in a different table, the actual LOB value is copied, not just the LOB locator. */ select r.content, r.content_length, r.lob, i.storage_type into v_content, v_content_length, v_lob, v_storage_type from cr_revisions r, cr_items i where r.item_id = i.item_id and r.revision_id = content_copy__revision_id; if v_storage_type = ''lob'' then v_new_lob := empty_lob(); update cr_revisions set content = null, content_length = v_content_length, lob = v_new_lob where revision_id = v_revision_id_dest; PERFORM lob_copy(v_lob, v_new_lob); else -- this will work for both file and text types... well sort of. -- this really just creates a reference to the first file which is -- wrong since, the item_id, revision_id uniquely describes the -- location of the file in the content repository file system. -- after copy is called, the content attribute needs to be updated -- with the new relative file path: -- update cr_revisions -- set content = ''[cr_create_content_file $item_id $revision_id [cr_fs_path]$old_rel_path]'' -- where revision_id = :revision_id -- old_rel_path is the content attribute value of the content revision -- that is being copied. update cr_revisions set content = v_content, content_length = v_content_length, lob = null where revision_id = v_revision_id_dest; end if; end if; return 0; end;' language 'plpgsql'; create or replace function content_type__get_template (varchar,varchar) returns integer as ' declare get_template__content_type alias for $1; get_template__use_context alias for $2; v_template_id cr_templates.template_id%TYPE; begin select template_id into v_template_id from cr_type_template_map where content_type = get_template__content_type and use_context = get_template__use_context and is_default = ''t''; return v_template_id; end;' language 'plpgsql' stable strict; create or replace function content_type__trigger_insert_statement (varchar) returns varchar as ' declare trigger_insert_statement__content_type alias for $1; v_table_name acs_object_types.table_name%TYPE; v_id_column acs_object_types.id_column%TYPE; cols varchar default ''''; vals varchar default ''''; attr_rec record; begin if trigger_insert_statement__content_type is null then return exception ''content_type__trigger_insert_statement called with null content_type''; end if; select table_name, id_column into v_table_name, v_id_column from acs_object_types where object_type = trigger_insert_statement__content_type; for attr_rec in select attribute_name from acs_attributes where object_type = trigger_insert_statement__content_type LOOP cols := cols || '', '' || attr_rec.attribute_name; vals := vals || '', new.'' || attr_rec.attribute_name; end LOOP; return ''insert into '' || v_table_name || '' ( '' || v_id_column || cols || '' ) values (cr_dummy.val'' || vals || '')''; end;' language 'plpgsql' stable; create or replace function rule_exists (varchar,varchar) returns boolean as ' declare rule_name alias for $1; table_name alias for $2; begin return count(*) = 1 from pg_rules where tablename::varchar = lower(table_name) and rulename::varchar = lower(rule_name); end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/upgrade/upgrade-5.2.0a3-5.2.0a4.sql0000644000175000017500000000130710440426443031560 0ustar frankiefrankie-- procedure for content symlink delete select define_function_args('content_symlink__delete','symlink_id'); create or replace function content_symlink__delete (integer) returns integer as ' declare delete__symlink_id alias for $1; begin PERFORM content_symlink__del(delete__symlink_id); return 0; end;' language 'plpgsql'; select define_function_args('content_symlink__del','symlink_id'); create or replace function content_symlink__del (integer) returns integer as ' declare del__symlink_id alias for $1; begin delete from cr_symlinks where symlink_id = del__symlink_id; PERFORM content_item__delete(del__symlink_id); return 0; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-test.sql0000644000175000017500000007567310057204432027375 0ustar frankiefrankie-- set serveroutput on drop function content_test__create(); drop function content_test__check1(); drop function content_test__check2(); drop function content_test__check3(); drop function content_test__check4(); drop function content_test__check5(); drop function content_test__put_line(text); drop function cast_char(boolean); drop function content_test__dump(); drop function content_test__get_val(varchar); drop function content_test__save_val(integer,varchar); drop table tst_ids; create table tst_ids ( id integer, name varchar(400) ); create function content_test__save_val(integer,varchar) returns integer as ' declare v_id alias for $1; v_name alias for $2; begin insert into tst_ids (id,name) values (v_id, v_name); return null; end;' language 'plpgsql'; create function content_test__get_val(varchar) returns integer as ' begin return id from tst_ids where name = $1; end;' language 'plpgsql'; create function content_test__dump() returns text as ' declare v_rec record; v_str text default ''\\n''; begin for v_rec in select repeat('' '',(tree_level(tree_sortkey)*2 - 1)) || name as name, item_id, parent_id, tree_level(tree_sortkey) as level, tree_sortkey from cr_items order by tree_sortkey LOOP v_str := v_str || rpad(v_rec.name,40) || rpad(v_rec.item_id,6) || rpad(v_rec.parent_id,6) || rpad(v_rec.level,6) || rpad(v_rec.tree_sortkey,30) || ''\\n''; end LOOP; return v_str; end;' language 'plpgsql'; create function content_test__put_line(text) returns integer as ' begin raise NOTICE ''%'', $1; return null; end;' language 'plpgsql'; create function cast_char(boolean) returns char as ' begin return case when $1 then ''t''::char else ''f''::char end; end;' language 'plpgsql'; create function content_test__create() returns integer as ' declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin -- create folders and an item folder_id := content_folder__new(''grandpa'',''Grandpa'',NULL,-100); folder_b_id := content_folder__new(''grandma'',''Grandma'',NULL,-100); sub_folder_id := content_folder__new(''pa'',''Pa'',NULL,folder_id); sub_sub_folder_id := content_folder__new(''me'',''Me'',NULL,sub_folder_id); item_id := content_item__new(''puppy'',sub_sub_folder_id); simple_item_id := content_item__new( ''bunny'', sub_sub_folder_id, ''Bugs Bunny'', ''Simple (Revisionless) Item Test'', ''Simple (Revisionless) Item Test Text'' ); live_revision_id := content_revision__new( ''Live Revision of Puppy'', ''Live Revision of Puppy Description'', to_date(''1999-08-12'',''YYYY-MM-DD''), ''text/html'', ''Text for Live Revision of Puppy'', item_id ); late_revision_id := content_revision__new( ''Latest Revision of Puppy'', ''Latest Revision of Puppy Description'', to_date(''2001-09-22'',''YYYY-MM-DD''), ''text/html'', ''Text for Latest Revision of Puppy'', item_id ); item_template_id := content_template__new( ''Item Template'' ); type_template_id := content_template__new( ''Type Template'' ); def_type_template_id := content_template__new( ''Dumb Default Type Template'' ); dum_template_id := content_template__new( ''Default Type Template'' ); PERFORM content_test__save_val (folder_id,''folder_id''); PERFORM content_test__save_val (folder_b_id,''folder_b_id''); PERFORM content_test__save_val (sub_folder_id,''sub_folder_id''); PERFORM content_test__save_val (sub_sub_folder_id,''sub_sub_folder_id''); PERFORM content_test__save_val (item_id,''item_id''); PERFORM content_test__save_val (simple_item_id,''simple_item_id''); PERFORM content_test__save_val (live_revision_id,''live_revision_id''); PERFORM content_test__save_val (late_revision_id,''late_revision_id''); PERFORM content_test__save_val (item_template_id,''item_template_id''); PERFORM content_test__save_val (type_template_id,''type_template_id''); PERFORM content_test__save_val (def_type_template_id,''def_type_template_id''); PERFORM content_test__save_val (dum_template_id,''dum_template_id''); PERFORM content_test__put_line(''-------------------------------------''); PERFORM content_test__put_line(''CREATING CONTENT FOLDERS AND ITEMS...''); PERFORM content_test__put_line(''...all tests passed''); PERFORM content_test__put_line(''Folder grandpa is '' || folder_id); PERFORM content_test__put_line(''Folder grandma is '' || folder_b_id); PERFORM content_test__put_line(''Sub folder pa is '' || sub_folder_id); PERFORM content_test__put_line(''Sub sub folder me is '' || sub_sub_folder_id); PERFORM content_test__put_line(''Added item puppy to sub sub folder me at '' || item_id); PERFORM content_test__put_line(''Created simple item bunny to sub sub folder me at '' || simple_item_id); PERFORM content_test__put_line(''Added a revision to puppy at '' || live_revision_id); PERFORM content_test__put_line(''Added a revision to puppy at '' || late_revision_id); PERFORM content_test__put_line(''Created Item Template at '' || item_template_id); PERFORM content_test__put_line(''Created Type Template at '' || type_template_id); PERFORM content_test__put_line(''Created Def Type Template at '' || def_type_template_id); PERFORM content_test__put_line(''Created Dum Def Type Template at '' || dum_template_id); PERFORM content_test__put_line(''-----------------------------------''); PERFORM content_test__put_line(''FOLDERS AND EMPTY FOLDERS AND SUBFOLDERS''); PERFORM content_test__put_line(''...all tests passed''); PERFORM content_test__put_line(''Is folder '' || folder_id || '' empty? '' || cast_char(content_folder__is_empty(folder_id)) ); PERFORM content_test__put_line(''Is folder '' || sub_sub_folder_id || '' empty? '' || cast_char(content_folder__is_empty(sub_sub_folder_id)) ); PERFORM content_test__put_line(''Is folder '' || sub_folder_id || '' empty? '' || cast_char(content_folder__is_empty(sub_folder_id)) ); PERFORM content_test__put_line(''Is folder '' || folder_b_id || '' empty? '' || cast_char(content_folder__is_empty(folder_b_id)) ); PERFORM content_test__put_line(''Is folder '' || folder_id || ''? '' || cast_char(content_folder__is_folder(folder_id)) ); PERFORM content_test__put_line(''Is folder '' || item_id || ''? '' || cast_char(content_folder__is_folder(item_id)) ); PERFORM content_test__put_line(''Is '' || folder_id || '' a subfolder of '' || sub_folder_id || ''? '' || cast_char(content_folder__is_sub_folder(sub_folder_id, folder_id )) ); PERFORM content_test__put_line(''Is '' || sub_folder_id || '' a subfolder of '' || folder_id || ''? '' || cast_char(content_folder__is_sub_folder(folder_id, sub_folder_id )) ); PERFORM content_test__put_line(''Is '' || sub_sub_folder_id || '' a subfolder of '' || folder_id || ''? '' || cast_char(content_folder__is_sub_folder(folder_id, sub_sub_folder_id )) ); PERFORM content_test__put_line(''Is '' || sub_folder_id || '' a subfolder of '' || -1 || ''? '' || cast_char(content_folder__is_sub_folder(-1, sub_folder_id )) ); PERFORM content_test__put_line(''-------------------------------------''); PERFORM content_test__put_line(''LIVE AND LATEST REVISIONS...''); PERFORM content_test__put_line(''...all tests passed''); PERFORM content_test__put_line(''Get live_revision_id for item puppy '' || item_id || '' is '' || coalesce(content_item__get_live_revision(item_id)::varchar,''null'') ); PERFORM content_item__set_live_revision(live_revision_id); PERFORM content_test__put_line(''Set '' || live_revision_id || '' as the live revision for item puppy '' || item_id); PERFORM content_test__put_line(''Get live_revision_id for item puppy '' || item_id || '' is '' || content_item__get_live_revision(item_id) ); PERFORM content_test__put_line(''Get live_revision_id for item kitty '' || simple_item_id || '' is '' || coalesce(content_item__get_live_revision(simple_item_id)::varchar,''null'') ); PERFORM content_test__put_line(''Get late_revision_id for item puppy '' || item_id || '' is '' || content_item__get_latest_revision(item_id) ); PERFORM content_test__put_line(''Get late_revision_id for item bunny '' || simple_item_id || '' is '' || content_item__get_latest_revision(simple_item_id) ); /* PERFORM content_item__register_template(item_id, item_template_id, ''public'' ); */ PERFORM content_type__register_template(''content_revision'', type_template_id, ''public'', ''f'' ); PERFORM content_type__register_template(''content_revision'', def_type_template_id, ''admin'', ''f'' ); PERFORM content_type__register_template(''content_revision'', dum_template_id, ''admin'', ''t'' ); PERFORM content_type__set_default_template(''content_revision'', def_type_template_id, ''admin'' ); PERFORM content_test__put_line(''-------------------------------------''); PERFORM content_test__put_line(''REGISTERING TEMPLATES TO ITEMS AND TYPES...''); PERFORM content_test__put_line(''...all tests passed''); PERFORM content_test__put_line(''Registered Item Template '' || item_template_id || '' to item puppy '' || item_id || '' with public context'' ); PERFORM content_test__put_line(''Registered Type Template '' || type_template_id || '' to content_revision '' || item_id || '' with public context'' ); PERFORM content_test__put_line(''Registered Default Type Template '' || def_type_template_id || '' to content_revision '' || item_id || '' with admin context'' ); PERFORM content_test__put_line(''Get template id for item puppy '' || item_id || '' and context public is '' || coalesce(content_item__get_template(item_id, ''public'' )::varchar,''null'') ); PERFORM content_test__put_line(''Get template id for item puppy '' || item_id || '' and context admin is '' || content_item__get_template(item_id, ''admin'' ) ); found_folder_id := content_item__get_id(''grandpa/pa/me'', -100, ''f''); PERFORM content_test__save_val (found_folder_id,''found_folder_id''); PERFORM content_test__put_line(''-------------------------------------''); PERFORM content_test__put_line(''LOCATING CONTENT FOLDERS AND ITEMS...''); PERFORM content_test__put_line(''...all tests passed!''); PERFORM content_test__put_line(''Found me at grandpa/pa/me: '' || found_folder_id ); PERFORM content_test__put_line(''Path for '' || found_folder_id || '' is '' || content_item__get_path(found_folder_id,null) ); PERFORM content_test__put_line(''Path for puppy '' || item_id || '' is '' || content_item__get_path(item_id,null) ); PERFORM content_test__put_line(''Path for puppy '' || item_id || '' from folder_id: '' || folder_id || '' is '' || content_item__get_path(item_id,folder_id) ); PERFORM content_test__put_line(''Path for puppy '' || item_id || '' from sub_folder_id: '' || sub_folder_id || '' is '' || content_item__get_path(item_id, sub_folder_id ) ); PERFORM content_test__put_line(''Path for puppy '' || item_id || '' from sub_sub_folder_id: '' || sub_sub_folder_id || '' is '' || content_item__get_path(item_id, sub_sub_folder_id ) ); PERFORM content_test__put_line(''Get id of item with invalid path - shouldn''''t return anything''); PERFORM content_test__put_line(''Found item at '' || coalesce(content_item__get_id(''grandpa/me'', -200,''f'')::varchar,''null'') ); PERFORM content_test__put_line(''Get id of item using subpath''); PERFORM content_test__put_line(''Found item at '' || content_item__get_id(''pa/me/puppy'', folder_id, ''f'' ) ); PERFORM content_test__put_line(''This is the path to a folder from a subfolder''); PERFORM content_test__put_line(''Path for '' || sub_folder_id || '' from sub_sub_folder_id: '' || sub_sub_folder_id || '' is '' || content_item__get_path(sub_folder_id, sub_sub_folder_id ) ); PERFORM content_test__put_line(''This is a path to an item from a non-existant item''); PERFORM content_test__put_line(''Path for '' || item_id || '' from nonexistant_id: '' || -300 || '' is '' || content_item__get_path(item_id,-300) ); PERFORM content_test__put_line(''This is a path to an item from a non-related branch''); PERFORM content_test__put_line(''Path for '' || item_id || '' from unrelated branch: '' || folder_b_id || '' is '' || content_item__get_path(item_id,folder_b_id) ); return null; end;' language 'plpgsql'; create function content_test__check1() returns integer as ' declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin folder_id := content_test__get_val(''folder_id''); sub_sub_folder_id := content_test__get_val(''sub_sub_folder_id''); PERFORM content_test__put_line(''-------------------------------------''); PERFORM content_test__put_line(''MOVING/RENAMING CONTENT FOLDERS...''); PERFORM content_test__put_line(''...all tests passed''); PERFORM content_test__put_line(''Moving me from under pa to under grandpa''); PERFORM content_item__move(sub_sub_folder_id, folder_id); return null; end;' language 'plpgsql'; create function content_test__check2() returns integer as ' declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin item_id := content_test__get_val(''item_id''); sub_sub_folder_id := content_test__get_val(''sub_sub_folder_id''); sub_folder_id := content_test__get_val(''sub_folder_id''); PERFORM content_test__put_line(''Path for '' || item_id || '' is '' || content_item__get_path(item_id,null) ); -- PERFORM content_test__put_line(''Moving grandpa to pa - this shouldn\\\'t work''); -- PERFORM content_folder__move(folder_id, sub_folder_id); -- PERFORM content_test__put_line(''Path for '' || item_id || '' is '' || -- content_item__get_path(item_id,null) -- ); PERFORM content_test__put_line(''Renaming puppy to kitty...''); PERFORM content_item__edit_name(item_id, ''kitty''); PERFORM content_test__put_line(''Renaming me to aunty...''); PERFORM content_folder__edit_name(sub_sub_folder_id, ''aunty'',null,null); PERFORM content_test__put_line(''Path for '' || item_id || '' is '' || content_item__get_path(item_id,null) ); PERFORM content_test__put_line(''Renaming kitty to pa -- this should work''); PERFORM content_item__edit_name(item_id, ''pa''); PERFORM content_test__put_line(''Path for '' || item_id || '' is '' || content_item__get_path(item_id,null) ); PERFORM content_test__put_line(''-------------------------------------''); PERFORM content_test__put_line(''SYMLINKS...''); PERFORM content_test__put_line(''...all tests passed''); symlink_a_id := content_symlink__new(''link_a'', null, sub_sub_folder_id, sub_folder_id, null, now(), null, null ); PERFORM content_test__save_val (symlink_a_id,''symlink_a_id''); return null; end;' language 'plpgsql'; create function content_test__check3() returns integer as ' declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin folder_id := content_test__get_val(''folder_id''); folder_b_id := content_test__get_val(''folder_b_id''); sub_folder_id := content_test__get_val(''sub_folder_id''); sub_sub_folder_id := content_test__get_val(''sub_sub_folder_id''); item_id := content_test__get_val(''item_id''); simple_item_id := content_test__get_val(''simple_item_id''); live_revision_id := content_test__get_val(''live_revision_id''); late_revision_id := content_test__get_val(''late_revision_id''); item_template_id := content_test__get_val(''item_template_id''); type_template_id := content_test__get_val(''type_template_id''); def_type_template_id := content_test__get_val(''def_type_template_id''); dum_template_id := content_test__get_val(''dum_template_id''); found_folder_id := content_test__get_val(''found_folder_id''); symlink_a_id := content_test__get_val(''symlink_a_id''); PERFORM content_test__put_line(''Create a link in pa to aunty: Symlink is '' || symlink_a_id); PERFORM content_test__put_line(''Is '' || symlink_a_id || '' a symlink?: '' || cast_char(content_symlink__is_symlink(symlink_a_id)) ); PERFORM content_test__put_line(''Is '' || folder_id || '' a symlink?: '' || cast_char(content_symlink__is_symlink(folder_id)) ); PERFORM content_test__put_line(''Path for symlink '' || symlink_a_id || '' is '' || content_item__get_path(symlink_a_id,null) ); PERFORM content_test__put_line(''Resolving symlink '' || symlink_a_id || '' is '' || content_symlink__resolve(symlink_a_id) ); PERFORM content_test__put_line(''Resolved path for symlink '' || symlink_a_id || '' is '' || content_item__get_path(content_symlink__resolve(symlink_a_id),null) ); PERFORM content_test__put_line(''Path to item '' || item_id || '' from symlink '' || symlink_a_id || '' is '' || content_item__get_path(item_id, symlink_a_id) ); PERFORM content_test__put_line(''Path to item '' || item_id || '' from aunty '' || sub_sub_folder_id || '' is '' || content_item__get_path(item_id, sub_sub_folder_id) ); PERFORM content_test__put_line(''Path to pa '' || sub_folder_id || '' from symlink '' || symlink_a_id || '' is '' || content_item__get_path(sub_folder_id, symlink_a_id ) ); PERFORM content_test__put_line(''Found item '' || item_id || '' at '' || content_item__get_id(''/grandpa/aunty/pa'',null,''f'') ); PERFORM content_test__put_line(''Found item '' || item_id || '' at '' || content_item__get_id(''/grandpa/pa/link_a/pa'',null,''f'') ); PERFORM content_test__put_line(''Found item '' || item_id || '' starting at aunty '' || sub_sub_folder_id || '' at '' || content_item__get_id(''pa'', sub_sub_folder_id, ''f'' ) ); PERFORM content_test__put_line(''Found item '' || item_id || '' starting at symlink '' || symlink_a_id || '' at '' || content_item__get_id(''pa'',symlink_a_id,''f'') ); PERFORM content_test__put_line(''Found item '' || item_id || '' starting at pa '' || sub_folder_id || '' at '' || content_item__get_id(''link_a/bunny'', sub_folder_id, ''f'' ) ); PERFORM content_test__put_line(''--------------------------------''); PERFORM content_test__put_line(''Moving item '' || item_id || '' to grandma '' || folder_b_id ); PERFORM content_item__move(item_id,folder_b_id); return null; end;' language 'plpgsql'; create function content_test__check4() returns integer as ' declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin item_id := content_test__get_val(''item_id''); folder_b_id := content_test__get_val(''folder_b_id''); sub_sub_folder_id := content_test__get_val(''sub_sub_folder_id''); PERFORM content_test__put_line(''Path for item '' || item_id || '' is '' || content_item__get_path(item_id,null) ); PERFORM content_test__put_line(''Moving folder '' || folder_b_id || '' to aunty '' || sub_sub_folder_id ); PERFORM content_item__move(folder_b_id,sub_sub_folder_id); return null; end;' language 'plpgsql'; create function content_test__check5() returns integer as ' declare folder_id cr_folders.folder_id%TYPE; folder_b_id cr_folders.folder_id%TYPE; sub_folder_id cr_folders.folder_id%TYPE; sub_sub_folder_id cr_folders.folder_id%TYPE; item_id cr_items.item_id%TYPE; simple_item_id cr_items.item_id%TYPE; live_revision_id cr_revisions.revision_id%TYPE; late_revision_id cr_revisions.revision_id%TYPE; item_template_id cr_templates.template_id%TYPE; type_template_id cr_templates.template_id%TYPE; def_type_template_id cr_templates.template_id%TYPE; dum_template_id cr_templates.template_id%TYPE; symlink_a_id cr_symlinks.symlink_id%TYPE; symlink_b_id cr_symlinks.symlink_id%TYPE; found_folder_id cr_folders.folder_id%TYPE; begin folder_id := content_test__get_val(''folder_id''); folder_b_id := content_test__get_val(''folder_b_id''); sub_folder_id := content_test__get_val(''sub_folder_id''); sub_sub_folder_id := content_test__get_val(''sub_sub_folder_id''); item_id := content_test__get_val(''item_id''); simple_item_id := content_test__get_val(''simple_item_id''); live_revision_id := content_test__get_val(''live_revision_id''); late_revision_id := content_test__get_val(''late_revision_id''); item_template_id := content_test__get_val(''item_template_id''); type_template_id := content_test__get_val(''type_template_id''); def_type_template_id := content_test__get_val(''def_type_template_id''); dum_template_id := content_test__get_val(''dum_template_id''); found_folder_id := content_test__get_val(''found_folder_id''); PERFORM content_test__put_line(''Path for item '' || item_id || '' is '' || content_item__get_path(item_id,null) ); PERFORM content_test__put_line(''--------------------------------''); -- symlinks/revisions should be deleted automatically PERFORM content_template__delete(item_template_id); PERFORM content_template__delete(type_template_id); PERFORM content_template__delete(def_type_template_id); PERFORM content_template__delete(dum_template_id); PERFORM content_item__delete(simple_item_id); PERFORM content_item__delete(item_id); PERFORM content_folder__delete(folder_b_id); PERFORM content_folder__delete(sub_sub_folder_id); PERFORM content_folder__delete(sub_folder_id); PERFORM content_folder__delete(folder_id); return null; end;' language 'plpgsql'; \t select content_test__create(); select content_test__dump(); select content_test__check1(); select content_test__check2(); select content_test__check3(); select content_test__check4(); select content_test__check5(); \t openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-xml.sql0000644000175000017500000000204010506035457027200 0ustar frankiefrankie-- Data model to support XML exchange with thecontent repository of -- the ArsDigita Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-xml.sql,v 1.4 2006/09/25 20:25:19 byronl Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- A sequence for uniquely identifying uploaded XML documents until -- they are inserted into the repository create sequence cr_xml_doc_seq; -- create global temporary table cr_xml_docs ( -- doc_id integer primary key, -- doc CLOB -- ) on commit delete rows; create table cr_xml_docs ( doc_id integer constraint cr_xml_docs_doc_id_pk primary key, doc text ); comment on table cr_xml_docs is ' A temporary table for holding uploaded XML documents for the duration of a transaction, until they can be inserted into the content repository. '; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/packages-create.sql0000644000175000017500000000045207661402055027754 0ustar frankiefrankie-- Ensure that the data model is up-to-date before compiling packages -- \i content-util.sql \i content-update.sql \i content-type.sql \i content-item.sql \i content-revision.sql \i content-symlink.sql \i content-extlink.sql \i content-folder.sql \i content-template.sql \i content-keyword.sql openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-image-drop.sql0000644000175000017500000000255207661402055030434 0ustar frankiefrankie-- drop the content-image type from the data model -- Copyright (C) 20000 ArsDigita Corporation -- $Id: content-image-drop.sql,v 1.4 2003/05/17 09:43:09 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- unregister mime types from the image type drop function image__delete (integer); drop function image__new (varchar,integer,integer,integer,varchar,integer,varchar,integer,varchar,varchar,boolean,timestamptz,varchar,integer,integer,integer); drop function image__new_revision(integer, integer, varchar, varchar, timestamptz, varchar, varchar, integer, varchar, integer, integer); drop function image__new (varchar,integer,integer,integer,varchar,varchar,varchar,varchar,varchar,varchar,varchar, varchar,timestamptz,integer, integer); begin; select content_type__unregister_mime_type( 'image', 'image/jpeg' ); select content_type__unregister_mime_type( 'image', 'image/gif' ); end; -- remove image mime types delete from cr_mime_types where mime_type like 'image%'; -- this should remove the attributes and table related to the -- the image type begin; select content_type__drop_type ( 'image', 'f', 't'); end; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/doc-package.sql0000644000175000017500000000132207766162043027076 0ustar frankiefrankie---------------------------------------- -- Return function headers for packages --------------------------------------- -- show errors create or replace function doc__get_proc_header (varchar,varchar) returns varchar as ' declare proc_name alias for $1; package_name alias for $2; begin return definition from acs_func_headers where fname = (package_name || ''__'' || proc_name)::name limit 1; end;' language 'plpgsql' stable; create or replace function doc__get_package_header (varchar) returns varchar as ' declare package_name alias for $1; begin return ''''; end;' language 'plpgsql' immutable strict; -- show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-folder.sql0000644000175000017500000010066711100351226027653 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-folder.sql,v 1.50 2008/10/24 13:50:14 victorg Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- create or replace package body content_folder create or replace function content_folder__new(varchar,varchar,varchar,integer,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__package_id alias for $5; -- default null begin return content_folder__new(new__name, new__label, new__description, new__parent_id, null, null, now(), null, null, new__package_id ); end;' language 'plpgsql'; create or replace function content_folder__new(varchar,varchar,varchar,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null begin return content_folder__new(new__name, new__label, new__description, new__parent_id, null, null, now(), null, null, ''t'', null ); end;' language 'plpgsql'; -- function new create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null begin return content_folder__new(new__name, new__label, new__description, new__parent_id, new__context_id, new__folder_id, new__creation_date, new__creation_user, new__creation_ip, ''t'', null::integer ); end;' language 'plpgsql'; -- function new create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__package_id alias for $10; -- default null v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; v_package_id acs_objects.package_id%TYPE; begin return content_folder__new(new__name, new__label, new__description, new__parent_id, new__context_id, new__folder_id, new__creation_date, new__creation_user, new__creation_ip, ''t'', new__package_id ); end;' language 'plpgsql'; create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar,boolean) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true v_package_id acs_objects.package_id%TYPE; v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin return content_folder__new ( new__name, new__label, new__description, new__parent_id, new__context_id, new__folder_id, new__creation_date, new__creation_user, new__creation_ip, new__security_inherit_p, null ); end;' language 'plpgsql'; -- function new -- accepts security_inherit_p DaveB select define_function_args('content_folder__new','name,label,description,parent_id,context_id,folder_id,creation_date;now,creation_user,creation_ip,security_inherit_p;t,package_id'); create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar, boolean,integer) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true new__package_id alias for $11; -- default null v_folder_id cr_folders.folder_id%TYPE; v_context_id acs_objects.context_id%TYPE; begin -- set the context_id if new__context_id is null then v_context_id := new__parent_id; else v_context_id := new__context_id; end if; -- parent_id = security_context_root means that this is a mount point if new__parent_id != -4 and content_folder__is_folder(new__parent_id) and content_folder__is_registered(new__parent_id,''content_folder'',''f'') = ''f'' then raise EXCEPTION ''-20000: This folder does not allow subfolders to be created''; return null; else v_folder_id := content_item__new( new__folder_id, new__name, new__parent_id, null, new__creation_date, new__creation_user, new__context_id, new__creation_ip, ''f'', ''text/plain'', null, ''text'', new__security_inherit_p, ''CR_FILES'', ''content_folder'', ''content_folder'', new__package_id ); insert into cr_folders ( folder_id, label, description, package_id ) values ( v_folder_id, new__label, new__description, new__package_id ); -- set the correct object title update acs_objects set title = new__label where object_id = v_folder_id; -- inherit the attributes of the parent folder if new__parent_id is not null then insert into cr_folder_type_map select v_folder_id as folder_id, content_type from cr_folder_type_map where folder_id = new__parent_id; end if; -- update the child flag on the parent update cr_folders set has_child_folders = ''t'' where folder_id = new__parent_id; return v_folder_id; end if; return v_folder_id; end;' language 'plpgsql'; create or replace function content_folder__new (varchar,varchar,varchar,integer,integer,integer,timestamptz,integer,varchar,boolean) returns integer as ' declare new__name alias for $1; new__label alias for $2; new__description alias for $3; -- default null new__parent_id alias for $4; -- default null new__context_id alias for $5; -- default null new__folder_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__security_inherit_p alias for $10; -- default true begin return content_folder__new(new__name, new__label, new__description, new__parent_id, new__context_id, new__folder_id, new__creation_date, new__creation_user, new__creation_ip, new__security_inherit_p, null::integer ); end;' language 'plpgsql'; -- procedure delete select define_function_args('content_folder__del','folder_id,cascade_p;f'); create or replace function content_folder__del (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; -- default ''f'' v_count integer; v_child_row record; v_parent_id integer; v_path varchar; v_folder_sortkey varbit; begin if p_cascade_p = ''f'' then select count(*) into v_count from cr_items where parent_id = delete__folder_id; -- check if the folder contains any items if v_count > 0 then v_path := content_item__get_path(delete__folder_id, null); raise EXCEPTION ''-20000: Folder ID % (%) cannot be deleted because it is not empty.'', delete__folder_id, v_path; end if; else -- delete children select into v_folder_sortkey tree_sortkey from cr_items where item_id=delete__folder_id; for v_child_row in select item_id, tree_sortkey, name from cr_items where tree_sortkey between v_folder_sortkey and tree_right(v_folder_sortkey) and tree_sortkey != v_folder_sortkey order by tree_sortkey desc loop if content_folder__is_folder(v_child_row.item_id) then perform content_folder__delete(v_child_row.item_id); else perform content_item__delete(v_child_row.item_id); end if; end loop; end if; PERFORM content_folder__unregister_content_type( delete__folder_id, ''content_revision'', ''t'' ); delete from cr_folder_type_map where folder_id = delete__folder_id; select parent_id into v_parent_id from cr_items where item_id = delete__folder_id; raise notice ''deleteing folder %'',delete__folder_id; PERFORM content_item__delete(delete__folder_id); -- check if any folders are left in the parent update cr_folders set has_child_folders = ''f'' where folder_id = v_parent_id and not exists ( select 1 from cr_items where parent_id = v_parent_id and content_type = ''content_folder''); return 0; end;' language 'plpgsql'; select define_function_args('content_folder__delete','folder_id,cascade_p;f'); create or replace function content_folder__delete (integer, boolean) returns integer as ' declare delete__folder_id alias for $1; p_cascade_p alias for $2; -- default ''f'' begin PERFORM content_folder__del(delete__folder_id,p_cascade_p); return 0; end;' language 'plpgsql'; create or replace function content_folder__delete (integer) returns integer as ' declare delete__folder_id alias for $1; v_count integer; v_parent_id integer; v_path varchar; begin return content_folder__del( delete__folder_id, ''f'' ); end;' language 'plpgsql'; -- procedure rename select define_function_args('content_folder__edit_name','folder_id,name,label,description'); create or replace function content_folder__edit_name (integer,varchar,varchar,varchar) returns integer as ' declare edit_name__folder_id alias for $1; edit_name__name alias for $2; -- default null edit_name__label alias for $3; -- default null edit_name__description alias for $4; -- default null v_name_already_exists_p integer; begin if edit_name__name is not null and edit_name__name != '''' then PERFORM content_item__edit_name(edit_name__folder_id, edit_name__name); end if; if edit_name__label is not null and edit_name__label != '''' then update acs_objects set title = edit_name__label where object_id = edit_name__folder_id; end if; if edit_name__label is not null and edit_name__label != '''' and edit_name__description is not null and edit_name__description != '''' then update cr_folders set label = edit_name__label, description = edit_name__description where folder_id = edit_name__folder_id; else if(edit_name__label is not null and edit_name__label != '''') and (edit_name__description is null or edit_name__description = '''') then update cr_folders set label = edit_name__label where folder_id = edit_name__folder_id; end if; end if; return 0; end;' language 'plpgsql'; -- 1) make sure we are not moving the folder to an invalid location: -- a. destination folder exists -- b. folder is not the webroot (folder_id = -1) -- c. destination folder is not the same as the folder -- d. destination folder is not a subfolder -- 2) make sure subfolders are allowed in the target_folder -- 3) update the parent_id for the folder -- procedure move select define_function_args('content_folder__move','folder_id,target_folder_id,name;null'); create or replace function content_folder__move (integer,integer,varchar) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; move__name alias for $3; -- default null v_source_folder_id integer; v_valid_folders_p integer; begin select count(*) into v_valid_folders_p from cr_folders where folder_id = move__target_folder_id or folder_id = move__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.move - Not valid folder(s)''; end if; if move__folder_id = content_item__get_root_folder(null) or move__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.move - Cannot move root folder''; end if; if move__target_folder_id = move__folder_id then raise EXCEPTION ''-20000: content_folder.move - Cannot move a folder to itself''; end if; if content_folder__is_sub_folder(move__folder_id, move__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder is subfolder''; end if; if content_folder__is_registered(move__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.move - Destination folder does not allow subfolders''; end if; select parent_id into v_source_folder_id from cr_items where item_id = move__folder_id; -- update the parent_id for the folder update cr_items set parent_id = move__target_folder_id, name = coalesce ( move__name, name ) where item_id = move__folder_id; -- update the has_child_folders flags -- update the source update cr_folders set has_child_folders = ''f'' where folder_id = v_source_folder_id and not exists ( select 1 from cr_items where parent_id = v_source_folder_id and content_type = ''content_folder''); -- update the destination update cr_folders set has_child_folders = ''t'' where folder_id = move__target_folder_id; return 0; end;' language 'plpgsql'; create or replace function content_folder__move (integer,integer) returns integer as ' declare move__folder_id alias for $1; move__target_folder_id alias for $2; begin perform content_folder__move ( move__folder_id, move__target_folder_id, NULL ); return null; end;' language 'plpgsql'; -- procedure copy create or replace function content_folder__copy (integer,integer,integer,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin v_new_folder_id := content_folder__copy ( copy__folder_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, NULL ); return v_new_folder_id; end;' language 'plpgsql'; create or replace function content_folder__copy (integer,integer,integer,varchar,varchar) returns integer as ' declare copy__folder_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; -- default null v_valid_folders_p integer; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_label cr_folders.label%TYPE; v_description cr_folders.description%TYPE; v_new_folder_id cr_folders.folder_id%TYPE; v_folder_contents_val record; begin if copy__folder_id = content_item__get_root_folder(null) or copy__folder_id = content_template__get_root_folder() then raise EXCEPTION ''-20000: content_folder.copy - Not allowed to copy root folder''; end if; select count(*) into v_valid_folders_p from cr_folders where folder_id = copy__target_folder_id or folder_id = copy__folder_id; if v_valid_folders_p != 2 then raise EXCEPTION ''-20000: content_folder.copy - Invalid folder(s)''; end if; if copy__target_folder_id = copy__folder_id then raise EXCEPTION ''-20000: content_folder.copy - Cannot copy folder to itself''; end if; if content_folder__is_sub_folder(copy__folder_id, copy__target_folder_id) = ''t'' then raise EXCEPTION ''-20000: content_folder.copy - Destination folder is subfolder''; end if; if content_folder__is_registered(copy__target_folder_id,''content_folder'',''f'') != ''t'' then raise EXCEPTION ''-20000: content_folder.copy - Destination folder does not allow subfolders''; end if; -- get the source folder info select name, label, description, parent_id into v_name, v_label, v_description, v_current_folder_id from cr_items i, cr_folders f where f.folder_id = i.item_id and f.folder_id = copy__folder_id; -- would be better to check if the copy__name alredy exists in the destination folder. if v_current_folder_id = copy__target_folder_id and (v_name = copy__name or copy__name is null) then raise EXCEPTION ''-20000: content_folder.copy - Destination folder is parent folder and folder alredy exists''; end if; -- create the new folder v_new_folder_id := content_folder__new( coalesce (copy__name, v_name), v_label, v_description, copy__target_folder_id, copy__target_folder_id, null, now(), copy__creation_user, copy__creation_ip, ''t'', null ); -- copy attributes of original folder insert into cr_folder_type_map select v_new_folder_id as folder_id, content_type from cr_folder_type_map map where folder_id = copy__folder_id and -- do not register content_type if it is already registered not exists ( select 1 from cr_folder_type_map where folder_id = v_new_folder_id and content_type = map.content_type ) ; -- for each item in the folder, copy it for v_folder_contents_val in select item_id from cr_items where parent_id = copy__folder_id LOOP PERFORM content_item__copy( v_folder_contents_val.item_id, v_new_folder_id, copy__creation_user, copy__creation_ip, null ); end loop; return 0; end;' language 'plpgsql'; -- function is_folder select define_function_args('content_folder__is_folder','item_id'); create or replace function content_folder__is_folder (integer) returns boolean as ' declare item_id alias for $1; begin return count(*) > 0 from cr_folders where folder_id = item_id; end;' language 'plpgsql' stable; -- function is_sub_folder select define_function_args('content_folder__is_sub_folder','folder_id,target_folder_id'); create or replace function content_folder__is_sub_folder (integer,integer) returns boolean as ' declare is_sub_folder__folder_id alias for $1; is_sub_folder__target_folder_id alias for $2; v_parent_id integer default 0; v_sub_folder_p boolean default ''f''; v_rec record; begin if is_sub_folder__folder_id = content_item__get_root_folder(null) or is_sub_folder__folder_id = content_template__get_root_folder() then v_sub_folder_p := ''t''; end if; -- select -- parent_id -- from -- cr_items -- connect by -- prior parent_id = item_id -- start with -- item_id = is_sub_folder__target_folder_id for v_rec in select i2.parent_id from cr_items i1, cr_items i2 where i1.item_id = is_sub_folder__target_folder_id and i1.tree_sortkey between i2.tree_sortkey and tree_right(i2.tree_sortkey) order by i2.tree_sortkey desc LOOP v_parent_id := v_rec.parent_id; exit when v_parent_id = is_sub_folder__folder_id; -- we did not find the folder, reset v_parent_id v_parent_id := -4; end LOOP; if v_parent_id != -4 then v_sub_folder_p := ''t''; end if; return v_sub_folder_p; end;' language 'plpgsql'; -- function is_empty select define_function_args('content_folder__is_empty','folder_id'); create or replace function content_folder__is_empty (integer) returns boolean as ' declare is_empty__folder_id alias for $1; v_return boolean; begin select count(*) = 0 into v_return from cr_items where parent_id = is_empty__folder_id; return v_return; end;' language 'plpgsql' stable; -- procedure register_content_type select define_function_args('content_folder__register_content_type','folder_id,content_type,include_subtypes;f'); create or replace function content_folder__register_content_type (integer,varchar,boolean) returns integer as ' declare register_content_type__folder_id alias for $1; register_content_type__content_type alias for $2; register_content_type__include_subtypes alias for $3; -- default ''f'' v_is_registered varchar; begin if register_content_type__include_subtypes = ''f'' then v_is_registered := content_folder__is_registered( register_content_type__folder_id, register_content_type__content_type, ''f'' ); if v_is_registered = ''f'' then insert into cr_folder_type_map ( folder_id, content_type ) values ( register_content_type__folder_id, register_content_type__content_type ); end if; else -- insert into cr_folder_type_map -- select -- register_content_type__folder_id as folder_id, -- object_type as content_type -- from -- acs_object_types -- where -- object_type <> ''acs_object'' -- and -- not exists (select 1 from cr_folder_type_map -- where folder_id = register_content_type__folder_id -- and content_type = acs_object_types.object_type) -- connect by -- prior object_type = supertype -- start with -- object_type = register_content_type__content_type; insert into cr_folder_type_map select register_content_type__folder_id as folder_id, o.object_type as content_type from acs_object_types o, acs_object_types o2 where o.object_type <> ''acs_object'' and not exists (select 1 from cr_folder_type_map where folder_id = register_content_type__folder_id and content_type = o.object_type) and o2.object_type = register_content_type__content_type and o.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey); end if; return 0; end;' language 'plpgsql'; -- procedure unregister_content_type select define_function_args('content_folder__unregister_content_type','folder_id,content_type,include_subtypes;f'); create or replace function content_folder__unregister_content_type (integer,varchar,boolean) returns integer as ' declare unregister_content_type__folder_id alias for $1; unregister_content_type__content_type alias for $2; unregister_content_type__include_subtypes alias for $3; -- default ''f'' begin if unregister_content_type__include_subtypes = ''f'' then delete from cr_folder_type_map where folder_id = unregister_content_type__folder_id and content_type = unregister_content_type__content_type; else -- delete from cr_folder_type_map -- where folder_id = unregister_content_type__folder_id -- and content_type in (select object_type -- from acs_object_types -- where object_type <> ''acs_object'' -- connect by prior object_type = supertype -- start with -- object_type = unregister_content_type__content_type); delete from cr_folder_type_map where folder_id = unregister_content_type__folder_id and content_type in (select o.object_type from acs_object_types o, acs_object_types o2 where o.object_type <> ''acs_object'' and o2.object_type = unregister_content_type__content_type and o.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)); end if; return 0; end;' language 'plpgsql'; -- function is_registered select define_function_args('content_folder__is_registered','folder_id,content_type,include_subtypes;f'); create or replace function content_folder__is_registered (integer,varchar,boolean) returns boolean as ' declare is_registered__folder_id alias for $1; is_registered__content_type alias for $2; is_registered__include_subtypes alias for $3; -- default ''f'' v_is_registered integer; v_subtype_val record; begin if is_registered__include_subtypes = ''f'' or is_registered__include_subtypes is null then select count(1) into v_is_registered from cr_folder_type_map where folder_id = is_registered__folder_id and content_type = is_registered__content_type; else -- select -- object_type -- from -- acs_object_types -- where -- object_type <> ''acs_object'' -- connect by -- prior object_type = supertype -- start with -- object_type = is_registered.content_type v_is_registered := 1; for v_subtype_val in select o.object_type from acs_object_types o, acs_object_types o2 where o.object_type <> ''acs_object'' and o2.object_type = is_registered__content_type and o.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey) order by o.tree_sortkey LOOP if content_folder__is_registered(is_registered__folder_id, v_subtype_val.object_type, ''f'') = ''f'' then v_is_registered := 0; end if; end loop; end if; if v_is_registered = 0 then return ''f''; else return ''t''; end if; end;' language 'plpgsql' stable; -- function get_label select define_function_args('content_folder__get_label','folder_id'); create or replace function content_folder__get_label (integer) returns varchar as ' declare get_label__folder_id alias for $1; v_label cr_folders.label%TYPE; begin select label into v_label from cr_folders where folder_id = get_label__folder_id; return v_label; end;' language 'plpgsql' stable strict; -- function get_index_page select define_function_args('content_folder__get_index_page','folder_id'); create or replace function content_folder__get_index_page (integer) returns integer as ' declare get_index_page__folder_id alias for $1; v_folder_id cr_folders.folder_id%TYPE; v_index_page_id cr_items.item_id%TYPE; begin -- if the folder is a symlink, resolve it if content_symlink__is_symlink(get_index_page__folder_id) = ''t'' then v_folder_id := content_symlink__resolve(get_index_page__folder_id); else v_folder_id := get_index_page__folder_id; end if; select item_id into v_index_page_id from cr_items where parent_id = v_folder_id and name = ''index'' and content_item__is_subclass( content_item__get_content_type(content_symlink__resolve(item_id)), ''content_folder'') = ''f'' and content_item__is_subclass( content_item__get_content_type(content_symlink__resolve(item_id)), ''content_template'') = ''f''; if NOT FOUND then return null; end if; return v_index_page_id; end;' language 'plpgsql' stable strict; -- function is_root select define_function_args('content_folder__is_root','folder_id'); create or replace function content_folder__is_root (integer) returns boolean as ' declare is_root__folder_id alias for $1; v_is_root boolean; begin select parent_id = -4 into v_is_root from cr_items where item_id = is_root__folder_id; return v_is_root; end;' language 'plpgsql'; -- show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-drop.sql0000644000175000017500000001043511550452213027344 0ustar frankiefrankie-- Uninstall content repository tables of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-drop.sql,v 1.5 2011/04/11 01:08:27 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- set serveroutput on -- unregistering types, deleting the default folders create function inline_0 () returns integer as ' declare v_id integer; begin -- root folder for templates v_id := content_template__get_root_folder(); PERFORM content_folder__unregister_content_type( v_id, ''content_template'', ''t'' ); PERFORM content_folder__unregister_content_type( v_id, ''content_symlink'', ''t'' ); PERFORM content_folder__unregister_content_type( v_id, ''content_folder'', ''t'' ); PERFORM content_folder__delete(v_id); -- the root folder for content items v_id := content_item__get_root_folder(null); PERFORM content_folder__unregister_content_type( v_id, ''content_symlink'', ''t'' ); PERFORM content_folder__unregister_content_type( v_id, ''content_folder'', ''t'' ); PERFORM content_folder__unregister_content_type ( v_id, ''content_revision'', ''t'' ); PERFORM content_folder__delete (v_id); return null; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); begin; select content_type__unregister_mime_type('content_revision', 'text/html'); select content_type__unregister_mime_type('content_revision', 'text/plain'); end; -- drop all extended attribute tables --declare -- cursor type_cur is -- select object_type, table_name -- from acs_object_types -- where table_name <> 'cr_revisions' -- connect by prior object_type = supertype -- start with object_type = 'content_revision' -- order by level desc; --begin -- for type_rec in type_cur loop -- dbms_output.put_line('Dropping ' || type_rec.table_name); -- execute immediate 'drop table ' || type_rec.table_name; -- end loop; --end; --/ --show errors -- dropping pl/sql definitions --prompt ** dropping content-image \i content-image-drop.sql -- doc-package-drop -- content-search-drop -- begin -- ctx_ddl.drop_section_group('auto'); --end; select acs_sc_impl__delete( 'FtsContentProvider', -- impl_contract_name 'acs-content-repository' -- impl_name ); drop trigger content_search__utrg on cr_revisions; drop trigger content_search__dtrg on cr_revisions; drop trigger content_search__itrg on cr_revisions; drop function content_search__utrg (); drop function content_search__dtrg (); drop function content_search__itrg (); --begin -- ctx_ddl.drop_preference('CONTENT_FILTER_PREF'); --end; -- prompt ** dropping object types \i types-drop.sql -- packages-drop -- content-package-drop -- prompt ** dropping lots of tables -- content-xml-drop drop table cr_xml_docs; drop sequence cr_xml_doc_seq; -- content-util drop -- document submission with conversion to html drop index cr_doc_filter_index; drop table cr_doc_filter; --text submission drop table cr_text; -- content keywords drop table cr_item_keyword_map ; drop table cr_keywords ; -- content extlinks drop table cr_extlinks ; -- content symlinks drop table cr_symlinks ; -- content templates drop table cr_item_template_map ; drop table cr_type_template_map ; drop table cr_template_use_contexts ; drop table cr_templates ; -- content folders drop table cr_folder_type_map ; drop table cr_folders cascade constraints; -- prompt ** dropping more tables -- content publishing drop table cr_scheduled_release_job; drop table cr_scheduled_release_log; drop table cr_release_periods; drop table cr_item_publish_audit; -- content revisions drop table cr_files_to_delete; drop table cr_content_text; drop table cr_revision_attributes; drop table cr_revisions cascade constraints; -- content_items drop table cr_item_rels ; drop table cr_child_rels ; drop table cr_items cascade constraints; -- content types drop table cr_type_relations ; drop table cr_type_children ; -- locales drop table cr_locales ; -- mime types drop table cr_content_mime_type_map ; drop table cr_mime_types ; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-extlink.sql0000644000175000017500000001604211144344032030054 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Karl Goldstein (karlg@arsdigita.com) -- $Id: content-extlink.sql,v 1.20 2009/02/10 18:31:54 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html select define_function_args('content_extlink__new','name,url,label,description,parent_id,extlink_id,creation_date;now,creation_user,creation_ip,package_id'); create or replace function content_extlink__new (varchar,varchar,varchar,varchar,integer,integer,timestamptz,integer,varchar,integer) returns integer as ' declare new__name alias for $1; -- default null new__url alias for $2; new__label alias for $3; -- default null new__description alias for $4; -- default null new__parent_id alias for $5; new__extlink_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null new__package_id alias for $10; -- default null v_extlink_id cr_extlinks.extlink_id%TYPE; v_package_id acs_objects.package_id%TYPE; v_label cr_extlinks.label%TYPE; v_name cr_items.name%TYPE; begin if new__label is null then v_label := new__url; else v_label := new__label; end if; if new__name is null then select nextval(''t_acs_object_id_seq'') into v_extlink_id from dual; v_name := ''link'' || v_extlink_id; else v_name := new__name; end if; if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_extlink_id := content_item__new( v_name, new__parent_id, new__extlink_id, null, new__creation_date, new__creation_user, null, new__creation_ip, ''content_item'', ''content_extlink'', null, null, ''text/plain'', null, null, ''text'', v_package_id ); insert into cr_extlinks (extlink_id, url, label, description) values (v_extlink_id, new__url, v_label, new__description); update acs_objects set title = v_label where object_id = v_extlink_id; return v_extlink_id; end;' language 'plpgsql'; create or replace function content_extlink__new (varchar,varchar,varchar,varchar,integer,integer,timestamptz,integer,varchar) returns integer as ' declare new__name alias for $1; -- default null new__url alias for $2; new__label alias for $3; -- default null new__description alias for $4; -- default null new__parent_id alias for $5; new__extlink_id alias for $6; -- default null new__creation_date alias for $7; -- default now() new__creation_user alias for $8; -- default null new__creation_ip alias for $9; -- default null begin return content_extlink__new(new__name, new__url, new__label, new__description, new__parent_id, new__extlink_id, new__creation_date, new__creation_user, new__creation_ip, null ); end;' language 'plpgsql'; select define_function_args('content_extlink__delete','extlink_id'); create or replace function content_extlink__delete (integer) returns integer as ' declare delete__extlink_id alias for $1; begin delete from cr_extlinks where extlink_id = delete__extlink_id; PERFORM content_item__delete(delete__extlink_id); return 0; end;' language 'plpgsql'; select define_function_args('content_extlink__is_extlink','item_id'); create or replace function content_extlink__is_extlink (integer) returns boolean as ' declare is_extlink__item_id alias for $1; v_extlink_p boolean; begin select count(1) = 1 into v_extlink_p from cr_extlinks where extlink_id = is_extlink__item_id; return v_extlink_p; end;' language 'plpgsql'; create or replace function content_extlink__copy ( integer, integer, integer, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink__copy ( copy__extlink_id, copy__target_folder_id, copy__creation_user, copy__creation_ip, NULL ); return 0; end;' language 'plpgsql' stable; select define_function_args('content_extlink__copy','extlink_id,target_folder_id,creation_user,creation_ip,name'); create or replace function content_extlink__copy ( integer, integer, integer, varchar, varchar) returns integer as ' declare copy__extlink_id alias for $1; copy__target_folder_id alias for $2; copy__creation_user alias for $3; copy__creation_ip alias for $4; -- default null copy__name alias for $5; v_current_folder_id cr_folders.folder_id%TYPE; v_name cr_items.name%TYPE; v_url cr_extlinks.url%TYPE; v_description cr_extlinks.description%TYPE; v_label cr_extlinks.label%TYPE; v_extlink_id cr_extlinks.extlink_id%TYPE; begin if content_folder__is_folder(copy__target_folder_id) = ''t'' then select parent_id into v_current_folder_id from cr_items where item_id = copy__extlink_id; -- can''t copy to the same folder select i.name, e.url, e.description, e.label into v_name, v_url, v_description, v_label from cr_extlinks e, cr_items i where e.extlink_id = i.item_id and e.extlink_id = copy__extlink_id; -- copy to a different folder, or same folder if name -- is different if copy__target_folder_id != v_current_folder_id or ( v_name <> copy__name and copy__name is not null ) then if content_folder__is_registered(copy__target_folder_id, ''content_extlink'',''f'') = ''t'' then v_extlink_id := content_extlink__new( coalesce (copy__name, v_name), v_url, v_label, v_description, copy__target_folder_id, null, current_timestamp, copy__creation_user, copy__creation_ip, null ); end if; end if; end if; return 0; end;' language 'plpgsql' stable; openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-search.sql0000644000175000017500000001203610477557453027667 0ustar frankiefrankie-- @cvs-id $Id: content-search.sql,v 1.8 2006/09/06 14:46:03 daveb Exp $ ------------------------------------------------------------ -- declare CR as a content provider for search/indexing interface ------------------------------------------------------------ select acs_sc_impl__new( 'FtsContentProvider', -- impl_contract_name 'content_revision', -- impl_name 'acs-content-repository' -- impl_owner_name ); select acs_sc_impl_alias__new( 'FtsContentProvider', -- impl_contract_name 'content_revision', -- impl_name 'datasource', -- impl_operation_name 'content_search__datasource', -- impl_alias 'TCL' -- impl_pl ); select acs_sc_impl_alias__new( 'FtsContentProvider', -- impl_contract_name 'content_revision', -- impl_name 'url', -- impl_operation_name 'content_search__url', -- impl_alias 'TCL' -- impl_pl ); select acs_sc_binding__new('FtsContentProvider','content_revision'); select acs_sc_impl__new( 'FtsContentProvider', -- impl_contract_name 'image', -- impl_name 'acs-content-repository' -- impl_owner_name ); select acs_sc_impl_alias__new( 'FtsContentProvider', -- impl_contract_name 'image', -- impl_name 'datasource', -- impl_operation_name 'image_search__datasource', -- impl_alias 'TCL' -- impl_pl ); select acs_sc_impl_alias__new( 'FtsContentProvider', -- impl_contract_name 'image', -- impl_name 'url', -- impl_operation_name 'image_search__url', -- impl_alias 'TCL' -- impl_pl ); select acs_sc_binding__new('FtsContentProvider','image'); select acs_sc_impl__new( 'FtsContentProvider', -- impl_contract_name 'content_template', -- impl_name 'acs-content-repository' -- impl_owner_name ); select acs_sc_impl_alias__new( 'FtsContentProvider', -- impl_contract_name 'content_template', -- impl_name 'datasource', -- impl_operation_name 'template_search__datasource', -- impl_alias 'TCL' -- impl_pl ); select acs_sc_impl_alias__new( 'FtsContentProvider', -- impl_contract_name 'content_template', -- impl_name 'url', -- impl_operation_name 'template_search__url', -- impl_alias 'TCL' -- impl_pl ); select acs_sc_binding__new('FtsContentProvider','content_template'); -- triggers queue search interface to modify search index after content -- changes. -- DaveB: We only want to index live_revisions 2002-09-26 create function content_search__itrg () returns opaque as ' begin if (select live_revision from cr_items where item_id=new.item_id) = new.revision_id and new.publish_date >= current_timestamp then perform search_observer__enqueue(new.revision_id,''INSERT''); end if; return new; end;' language 'plpgsql'; create function content_search__dtrg () returns opaque as ' begin perform search_observer__enqueue(old.revision_id,''DELETE''); return old; end;' language 'plpgsql'; create or replace function content_search__utrg () returns opaque as ' declare v_live_revision integer; begin select into v_live_revision live_revision from cr_items where item_id=old.item_id; if old.revision_id=v_live_revision and new.publish_date <= current_timestamp then insert into search_observer_queue ( object_id, event ) values ( old.revision_id, ''UPDATE'' ); end if; return new; end;' language 'plpgsql'; -- we need new triggers on cr_items to index when a live revision -- changes -DaveB 2002-09-26 create function content_item_search__utrg () returns opaque as ' begin if new.live_revision is not null and coalesce(old.live_revision,0) <> new.live_revision and (select publish_date from cr_revisions where revision_id=new.live_revision) <= current_timestamp then perform search_observer__enqueue(new.live_revision,''INSERT''); end if; if old.live_revision is not null and old.live_revision <> coalesce(new.live_revision,0) then perform search_observer__enqueue(old.live_revision,''DELETE''); end if; if new.publish_status = ''expired'' then perform search_observer__enqueue(old.live_revision,''DELETE''); end if; return new; end;' language 'plpgsql'; create trigger content_search__itrg after insert on cr_revisions for each row execute procedure content_search__itrg (); create trigger content_search__dtrg after delete on cr_revisions for each row execute procedure content_search__dtrg (); create trigger content_search__utrg after update on cr_revisions for each row execute procedure content_search__utrg (); create trigger content_item_search__utrg before update on cr_items for each row execute procedure content_item_search__utrg (); openacs-5.7.0/packages/acs-content-repository/sql/postgresql/content-keyword.sql0000644000175000017500000003003610217276637030100 0ustar frankiefrankie-- Data model to support content repository of the ArsDigita -- Community System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Stanislav Freidin (sfreidin@arsdigita.com) -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html select define_function_args ('content_keyword__get_heading','keyword_id'); create or replace function content_keyword__get_heading (integer) returns text as ' declare get_heading__keyword_id alias for $1; v_heading text; begin select heading into v_heading from cr_keywords where keyword_id = get_heading__keyword_id; return v_heading; end;' language 'plpgsql' stable strict; -- function get_description select define_function_args ('content_keyword__get_description','keyword_id'); create or replace function content_keyword__get_description (integer) returns text as ' declare get_description__keyword_id alias for $1; v_description text; begin select description into v_description from cr_keywords where keyword_id = get_description__keyword_id; return v_description; end;' language 'plpgsql' stable strict; -- procedure set_heading select define_function_args ('content_keyword__set_heading','keyword_id,heading'); create or replace function content_keyword__set_heading (integer,varchar) returns integer as ' declare set_heading__keyword_id alias for $1; set_heading__heading alias for $2; begin update cr_keywords set heading = set_heading__heading where keyword_id = set_heading__keyword_id; update acs_objects set title = set_heading__heading where object_id = set_heading__keyword_id; return 0; end;' language 'plpgsql'; -- procedure set_description select define_function_args ('content_keyword__set_description','keyword_id,description'); create or replace function content_keyword__set_description (integer,varchar) returns integer as ' declare set_description__keyword_id alias for $1; set_description__description alias for $2; begin update cr_keywords set description = set_description__description where keyword_id = set_description__keyword_id; return 0; end;' language 'plpgsql'; -- function is_leaf select define_function_args ('content_keyword__is_leaf','keyword_id'); create or replace function content_keyword__is_leaf (integer) returns boolean as ' declare is_leaf__keyword_id alias for $1; begin return count(*) = 0 from cr_keywords k where k.parent_id = is_leaf__keyword_id; end;' language 'plpgsql' stable; -- function new select define_function_args('content_keyword__new','heading,description,parent_id,keyword_id,creation_date;now,creation_user,creation_ip,object_type;content_keyword'); create or replace function content_keyword__new (varchar,varchar,integer,integer,timestamptz,integer,varchar,varchar,integer) returns integer as ' declare new__heading alias for $1; new__description alias for $2; -- default null new__parent_id alias for $3; -- default null new__keyword_id alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__object_type alias for $8; -- default ''content_keyword'' new__package_id alias for $9; -- default null v_id integer; v_package_id acs_objects.package_id%TYPE; begin if new__package_id is null then v_package_id := acs_object__package_id(new__parent_id); else v_package_id := new__package_id; end if; v_id := acs_object__new (new__keyword_id, new__object_type, new__creation_date, new__creation_user, new__creation_ip, new__parent_id, ''t'', new__heading, v_package_id ); insert into cr_keywords (heading, description, keyword_id, parent_id) values (new__heading, new__description, v_id, new__parent_id); return v_id; end;' language 'plpgsql'; create or replace function content_keyword__new (varchar,varchar,integer,integer,timestamptz,integer,varchar,varchar) returns integer as ' declare new__heading alias for $1; new__description alias for $2; -- default null new__parent_id alias for $3; -- default null new__keyword_id alias for $4; -- default null new__creation_date alias for $5; -- default now() new__creation_user alias for $6; -- default null new__creation_ip alias for $7; -- default null new__object_type alias for $8; -- default ''content_keyword'' begin return content_keyword__new(new__heading, new__description, new__parent_id, new__keyword_id, new__creation_date, new__creation_user, new__creation_ip, new__object_type, null ); end;' language 'plpgsql'; -- procedure delete select define_function_args ('content_keyword__del','keyword_id'); create or replace function content_keyword__del (integer) returns integer as ' declare delete__keyword_id alias for $1; v_rec record; begin for v_rec in select item_id from cr_item_keyword_map where keyword_id = delete__keyword_id LOOP PERFORM content_keyword__item_unassign(v_rec.item_id, delete__keyword_id); end LOOP; PERFORM acs_object__delete(delete__keyword_id); return 0; end;' language 'plpgsql'; create or replace function content_keyword__delete (integer) returns integer as ' declare delete__keyword_id alias for $1; v_rec record; begin perform content_keyword__del(delete__keyword_id); return 0; end;' language 'plpgsql'; -- procedure item_assign select define_function_args ('content_keyword__item_assign','item_id,keyword_id,context_id;null,creation_user;null,creation_ip;null'); create or replace function content_keyword__item_assign (integer,integer,integer,integer,varchar) returns integer as ' declare item_assign__item_id alias for $1; item_assign__keyword_id alias for $2; item_assign__context_id alias for $3; -- default null item_assign__creation_user alias for $4; -- default null item_assign__creation_ip alias for $5; -- default null exists_p boolean; begin -- Do nothing if the keyword is assigned already select count(*) > 0 into exists_p from dual where exists (select 1 from cr_item_keyword_map where item_id = item_assign__item_id and keyword_id = item_assign__keyword_id); if NOT exists_p then insert into cr_item_keyword_map ( item_id, keyword_id ) values ( item_assign__item_id, item_assign__keyword_id ); end if; return 0; end;' language 'plpgsql'; -- procedure item_unassign select define_function_args ('content_keyword__item_unassign','item_id,keyword_id'); create or replace function content_keyword__item_unassign (integer,integer) returns integer as ' declare item_unassign__item_id alias for $1; item_unassign__keyword_id alias for $2; begin delete from cr_item_keyword_map where item_id = item_unassign__item_id and keyword_id = item_unassign__keyword_id; return 0; end;' language 'plpgsql'; -- function is_assigned select define_function_args ('content_keyword__is_assigned','item_id,keyword_id,recurse;none'); create or replace function content_keyword__is_assigned (integer,integer,varchar) returns boolean as ' declare is_assigned__item_id alias for $1; is_assigned__keyword_id alias for $2; is_assigned__recurse alias for $3; -- default ''none'' v_ret boolean; v_is_assigned__recurse varchar; begin if is_assigned__recurse is null then v_is_assigned__recurse := ''none''; else v_is_assigned__recurse := is_assigned__recurse; end if; -- Look for an exact match if v_is_assigned__recurse = ''none'' then return count(*) > 0 from cr_item_keyword_map where item_id = is_assigned__item_id and keyword_id = is_assigned__keyword_id; end if; -- Look from specific to general if v_is_assigned__recurse = ''up'' then return count(*) > 0 where exists (select 1 from (select keyword_id from cr_keywords c, cr_keywords c2 where c2.keyword_id = is_assigned__keyword_id and c.tree_sortkey between c2.tree_sortkey and tree_right(c2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; if v_is_assigned__recurse = ''down'' then return count(*) > 0 where exists (select 1 from (select k2.keyword_id from cr_keywords k1, cr_keywords k2 where k1.keyword_id = is_assigned__keyword_id and k1.tree_sortkey between k2.tree_sortkey and tree_right(k2.tree_sortkey)) t, cr_item_keyword_map m where t.keyword_id = m.keyword_id and m.item_id = is_assigned__item_id); end if; -- Tried none, up and down - must be an invalid parameter raise EXCEPTION ''-20000: The recurse parameter to content_keyword.is_assigned should be \\\'none\\\', \\\'up\\\' or \\\'down\\\'''; return null; end;' language 'plpgsql' stable; -- function get_path select define_function_args ('content_keyword__get_path','keyword_id'); create or replace function content_keyword__get_path (integer) returns text as ' declare get_path__keyword_id alias for $1; v_path text default ''''; v_is_found boolean default ''f''; v_heading cr_keywords.heading%TYPE; v_rec record; begin -- select -- heading -- from ( -- select -- heading, level as tree_level -- from cr_keywords -- connect by prior parent_id = keyword_id -- start with keyword_id = get_path.keyword_id) k -- order by -- tree_level desc for v_rec in select heading from (select k2.heading, tree_level(k2.tree_sortkey) as tree_level from cr_keywords k1, cr_keywords k2 where k1.keyword_id = get_path__keyword_id and k1.tree_sortkey between k2.tree_sortkey and tree_right(k2.tree_sortkey)) k order by tree_level desc LOOP v_heading := v_rec.heading; v_is_found := ''t''; v_path := v_path || ''/'' || v_heading; end LOOP; if v_is_found = ''f'' then return null; else return v_path; end if; end;' language 'plpgsql' stable strict; -- Ensure that the context_id in acs_objects is always set to the -- parent_id in cr_keywords create function cr_keywords_update_tr () returns opaque as ' begin if old.parent_id <> new.parent_id then update acs_objects set context_id = new.parent_id where object_id = new.keyword_id; end if; return new; end;' language 'plpgsql'; create trigger cr_keywords_update_tr after update on cr_keywords for each row execute procedure cr_keywords_update_tr (); -- show errors openacs-5.7.0/packages/acs-content-repository/sql/postgresql/types-drop.sql0000644000175000017500000000544307572171055027054 0ustar frankiefrankie-- Drop script for clearing content-repositry object type declarations -- Copyright (C) 20000 ArsDigita Corporation -- $Id: types-drop.sql,v 1.2 2002/11/30 17:15:25 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- just working backwards from types declared in types-create.sql -- removing the standard relationship types begin; select acs_attribute__drop_attribute ( 'cr_item_rel', 'order_n'); select acs_attribute__drop_attribute ( 'cr_item_rel', 'relation_tag'); select acs_attribute__drop_attribute ( 'cr_item_rl', 'related_object_id'); select acs_attribute__drop_attribute ( 'cr_item_rl', 'item_id'); select acs_object_type__drop_type ( 'cr_item_rel', 'f'); -- cr_item_child_rel type select acs_attribute__drop_attribute ( 'cr_item_child_rel', 'order_n'); select acs_attribute__drop_attribute ( 'cr_item_child_rel', 'relation_tag'); select acs_attribute__drop_attribute ( 'cr_item_child_rel', 'child_id'); select acs_attribute__drop_attribute ( 'cr_item_child_rel', 'parent_id'); select acs_object_type__drop_type ( 'cr_item_child_rel', 'f'); end; -- drop content revisions, begin; select content_type__drop_type('content_revision',f','f'); end; --dropping content templates begin; select acs_object_type__drop_type( 'content_template','f'); end; -- extlinks begin; select acs_attribute__drop_attribute ( 'content_extlink', 'description'); select acs_attribute__drop_attribute ( 'content_extlink', attribute_name => 'label'); select acs_attribute__drop_attribute ( 'content_extlink', attribute_name => 'url'); select acs_object_type__drop_type( 'content_extlink','f'); end; -- symlinks begin; select acs_attribute__drop_attribute ( 'content_symlink', 'target_id'); select acs_object_type__drop_type ( 'content_symlink'); end; --content keywords begin; select acs_attribute__drop_attribute ( 'content_keyword', attribute_name => 'description'); select acs_attribute__drop_attribute ( 'content_keyword', attribute_name => 'heading'); select acs_object_type__drop_type ( 'content_keyword','f'); end; begin; select acs_attribute__drop_attribute ( 'content_folder', 'description'); select acs_attribute__drop_attribute ( 'content_folder', 'label'); select acs_object_type__drop_type ( 'content_folder','f'); end; begin; select acs_attribute__drop_attribute ( 'content_item', 'live_revision'); select acs_attribute__drop_attribute ( 'content_item', 'locale'); select acs_attribute__drop_attribute ( 'content_item', 'name'); select acs_object_type__drop_type ( 'content_item','f'); end; openacs-5.7.0/packages/acs-content-repository/www/0000755000175000017500000000000011575225426022041 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/www/doc/0000755000175000017500000000000011724401447022601 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/www/doc/api/0000755000175000017500000000000011724401447023352 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/www/doc/api/template.html0000644000175000017500000001770207253523116026062 0ustar frankiefrankie Package: content_template

content_template

Content Repository : content_template


 

Overview

Templates are a special class of text objects that are used for specifying the layout of a content item. They may be mapped to content types, meaning that every item of that type will display using that template unless a specific item overrides the default by mapping to a template itself.

 

Related Objects

See also: content_item, content_folder

 

API

  • Function: content_template.get_path

    Retrieves the full path to the template, as described in content_item.get_path

  • Author:Karl Goldstein
    Returns:The path to the template, starting with the specified root folder
    Parameters:
    template_id:   The id of the template for which the path is to be retrieved
    root_folder_id:   Starts path resolution at this folder
    Declaration:
    
    function get_path (
      template_id    in cr_templates.template_id%TYPE,
      root_folder_id in cr_folders.folder_id%TYPE default c_root_folder_id
    ) return varchar2;
    
    
    See Also:content_item.get_path

     

  • Function: content_template.get_root_folder

    Parameters:
    Not yet documented
    Declaration:
    
    function get_root_folder return cr_folders.folder_id%TYPE;
    
    

     

  • Function: content_template.is_template

    Determine if an item is a template.

    Author:Karl Goldstein
    Returns:'t' if the item is a template, 'f' otherwise
    Parameters:
    item_id:   The item id
    Declaration:
    
    function is_template (
      template_id	in cr_templates.template_id%TYPE
    ) return varchar2;
    
    
    See Also:content_template.new

     

  • Function: content_template.new

    Creates a new content template which can be used to render content items.

    Author:Karl Goldstein
    Returns:The id of the newly created template
    Parameters:
    name:   The name for the template, must be a valid UNIX-like filename. If a template with this name already exists under the specified parent item, an error is thrown
    parent_id:   The parent of this item, defaults to null
    template_id:   The id of the new template. A new id will be allocated if this parameter is null
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      name          in cr_items.name%TYPE,
      parent_id     in acs_objects.context_id%TYPE default null,
      template_id	in cr_templates.template_id%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null
    ) return cr_templates.template_id%TYPE;
    
    
    See Also:acs_object.new, content_item.new, content_item.register_template, content_type.register_template

     

  • Procedure: content_template.delete

    Deletes the specified template, and unregisters the template from all content types and content items. Use with caution - this operation cannot be undone.

    Author:Karl Goldstein
    Parameters:
    template_id:   The id of the template to delete
    Declaration:
    
    procedure delete (
      template_id	in cr_templates.template_id%TYPE
    );
    
    
    See Also:acs_object.delete, content_item.unregister_template, content_type.unregister_template,

     

    Last Modified: $Id: template.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/folder.html0000644000175000017500000005146110057204432025513 0ustar frankiefrankie Package: content_folder

    content_folder

    Content Repository : content_folder


     

    Overview

    Content folders contain related content items and allow content managers to group content as they see fit. Within a content folder, content items must have unique names since this is where they will be served from. For example within the folder "movies" (served from "/movies") all items must have unique names, such as: "terminator," "terminator2" (served from "/movies/terminator, "/movies/terminator2" respectively).

     

    Related Objects

    See also: Content Item

     

    API

  • Function: content_folder.get_index_page

    Returns the item ID of the index page of the folder, null otherwise

    Author:Michael Pih
    Returns:The item ID of the index page
    Parameters:
    folder_id The:   folder id
    Declaration:
    
    function get_index_page (
      folder_id in cr_folders.folder_id%TYPE
    ) return cr_items.item_id%TYPE;
    
    

     

  • Function: content_folder.get_label

    Returns the label for the folder. This function is the default name method for the folder object.

    Author:Karl Goldstein
    Returns:The folder's label
    Parameters:
    folder_id:   The folder id
    Declaration:
    
    function get_label (
      folder_id in cr_folders.folder_id%TYPE
    ) return cr_folders.label%TYPE;
    
    
    See Also:acs_object_type.create_type, the docs for the name_method parameter

     

  • Function: content_folder.is_empty

    Determine if the folder is empty

    Author:Karl Goldstein
    Returns:'t' if the folder contains no subfolders or items, 'f' otherwise
    Parameters:
    folder_id:   The folder id
    Declaration:
    
    function is_empty (
      folder_id  in cr_folders.folder_id%TYPE
    ) return varchar2;
    
    
    See Also:content_folder.is_folder

     

  • Function: content_folder.is_folder

    Determine if the item is a folder

    Author:Karl Goldstein
    Returns:'t' if the item is a folder, 'f' otherwise
    Parameters:
    item_id:   The item id
    Declaration:
    
    function is_folder (
      item_id	  in cr_items.item_id%TYPE
    ) return char;
    
    
    See Also:content_folder.new, content_folder.is_sub_folder

     

  • Function: content_folder.is_registered

    change this to is_type_registered Determines if a content type is registered to the folder Only items of the registered type(s) may be added to the folder.

    Author:Karl Goldstein
    Returns:'t' if the type is registered to this folder, 'f' otherwise
    Parameters:
    folder_id:   The folder id
    content_type:   The content type to be checked
    include_subtypes:   If 't', all subtypes of the content_type will be checked, returning 't' if all of them are registered. If 'f', only an exact match with content_type will be performed.
    Declaration:
    
    function is_registered (
      folder_id		in cr_folders.folder_id%TYPE,
      content_type		in cr_folder_type_map.content_type%TYPE,
      include_subtypes	in varchar2 default 'f'
    ) return varchar2;
    
    
    See Also:content_folder.register_content_type, content_folder.unregister_content_type,

     

  • Function: content_folder.is_sub_folder

    Determine if the item target_folder_id is a subfolder of the item folder_id

    Author:Karl Goldstein
    Returns:'t' if the item target_folder_id is a subfolder of the item folder_id, 'f' otherwise
    Parameters:
    folder_id:   The superfolder id
    target_folder_id:   The subfolder id
    Declaration:
    
    function is_sub_folder (
      folder_id		in cr_folders.folder_id%TYPE,
      target_folder_id	in cr_folders.folder_id%TYPE
    ) return char;
    
    
    See Also:content_folder.is_folder

     

  • Function: content_folder.new

    Create a new folder

    Author:Karl Goldstein
    Returns:The id of the newly created folder
    Parameters:
    label:   The label for the folder
    description:   A short description of the folder, 4000 characters maximum
    parent_id:   The parent of the folder
    folder_id:   The id of the new folder. A new id will be allocated by default
    revision_id:   The id of the new revision. A new id will be allocated by default
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      name          in cr_items.name%TYPE,
      label         in cr_folders.label%TYPE,
      description   in cr_folders.description%TYPE default null,
      parent_id     in acs_objects.context_id%TYPE default null,
      folder_id	in cr_folders.folder_id%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null
    ) return cr_folders.folder_id%TYPE;
    
    
    See Also:acs_object.new, content_item.new

     

  • Procedure: content_folder.copy

    Recursively copy the folder and all items in into a new location. An error is thrown if either of the parameters is not a folder. The root folder of the sitemap and the root folder of the templates cannot be copied

    Author:Karl Goldstein
    Parameters:
    folder_id:   The id of the folder to copy
    target_folder_id:   The destination folder
    Declaration:
    
    procedure copy (
      folder_id		in cr_folders.folder_id%TYPE,
      target_folder_id	in cr_folders.folder_id%TYPE
    );
    
    
    See Also:content_folder.new, content_folder.copy

     

  • Procedure: content_folder.delete

    Delete a folder. An error is thrown if the folder is not empty

    Author:Karl Goldstein
    Parameters:
    folder_id:   The id of the folder to delete
    Declaration:
    
    procedure delete (
      folder_id	in cr_folders.folder_id%TYPE
    );
    
    
    See Also:acs_object.delete, content_item.delete

     

  • Procedure: content_folder.move

    Recursively move the folder and all items in into a new location. An error is thrown if either of the parameters is not a folder. The root folder of the sitemap and the root folder of the templates cannot be moved.

    Author:Karl Goldstein
    Parameters:
    folder_id:   The id of the folder to move
    target_folder_id:   The destination folder
    Declaration:
    
    procedure move (
      folder_id		in cr_folders.folder_id%TYPE,
      target_folder_id	in cr_folders.folder_id%TYPE
    );
    
    
    See Also:content_folder.new, content_folder.copy

     

  • Procedure: content_folder.register_content_type

    Register a content type to the folder, if it is not already registered. Only items of the registered type(s) may be added to the folder.

    Author:Karl Goldstein
    Parameters:
    folder_id:   The folder id
    content_type:   The content type to be registered
    Declaration:
    
    procedure register_content_type (
      folder_id		in cr_folders.folder_id%TYPE,
      content_type		in cr_folder_type_map.content_type%TYPE,
      include_subtypes	in varchar2 default 'f'
    );
    
    
    See Also:content_folder.unregister_content_type, content_folder.is_registered

     

  • Procedure: content_folder.edit_name

    Change the name, label and/or description of the folder

    Author:Karl Goldstein
    Parameters:
    folder_id:   The id of the folder to modify
    name:   The new name for the folder. An error will be thrown if an item with this name already exists under this folder's parent. If this parameter is null, the old name will be preserved
    label:   The new label for the folder. The old label will be preserved if this parameter is null
    label:   The new description for the folder. The old description will be preserved if this parameter is null
    Declaration:
    
    procedure rename (
      folder_id	 in cr_folders.folder_id%TYPE,
      name           in cr_items.name%TYPE default null,
      label  	 in cr_folders.label%TYPE default null,
      description    in cr_folders.description%TYPE default null
    );
    
    
    See Also:content_folder.new

     

  • Procedure: content_folder.unregister_content_type

    Unregister a content type from the folder, if it has been registered. Only items of the registered type(s) may be added to the folder. If the folder already contains items of the type to be unregistered, the items remain in the folder.

    Author:Karl Goldstein
    Parameters:
    folder_id:   The folder id
    content_type:   The content type to be unregistered
    include_subtypes:   If 't', all subtypes of content_type will be unregistered as well
    Declaration:
    
    procedure unregister_content_type (
      folder_id		in cr_folders.folder_id%TYPE,
      content_type		in cr_folder_type_map.content_type%TYPE,
      include_subtypes	in varchar2 default 'f'
    );
    
    
    See Also:content_folder.register_content_type, content_folder.is_registered

     

    Last Modified: $Id: folder.html,v 1.2 2004/06/01 22:54:18 donb Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/type.html0000644000175000017500000006411707253523116025232 0ustar frankiefrankie Package: content_type

    content_type

    Content Repository : content_type


     

    Overview

    This package is used to manipulate content types and attributes Content types represent the different kind of content displayed on a website. All content items should subclass a content type.

     

    Related Objects

    See also: {Content Item }

     

    API

  • Function: content_type.create_attribute

    Create a new attribute for the specified type. Automatically create the column for the attribute if the column does not already exist.

    Author:Karl Goldstein
    Returns:The id of the newly created attribute
    Parameters:
    content_type:   The name of the type to alter
    attribute_name:   The name of the attribute to create
    pretty_name:   Pretty name for the new attribute, singular
    pretty_plural:   Pretty name for the new attribute, plural
    default_value:   The default value for the attribute, defaults to null
    Declaration:
    
    function create_attribute (
      content_type		in acs_attributes.object_type%TYPE,
      attribute_name	in acs_attributes.attribute_name%TYPE,
      datatype		in acs_attributes.datatype%TYPE,
      pretty_name		in acs_attributes.pretty_name%TYPE,
      pretty_plural	in acs_attributes.pretty_plural%TYPE default null,
      default_value	in acs_attributes.default_value%TYPE default null,
      column_spec           in varchar2  default 'varchar2(4000)'
    ) return acs_attributes.attribute_id%TYPE;
    
    
    See Also:acs_object_type.create_attribute, content_type.create_type

     

  • Function: content_type.get_template

    Retrieve the appropriate template for rendering items of the specified type.

    Author:Karl Goldstein
    Returns:The ID of the template to use
    Parameters:
    content_type:   The type for which the template is to be retrieved
    use_context:   The context in which the template is appropriate, such as 'admin' or 'public'
    Declaration:
    
    function get_template (
      content_type  in cr_type_template_map.content_type%TYPE,
      use_context   in cr_type_template_map.use_context%TYPE
    ) return cr_templates.template_id%TYPE;
    
    
    See Also:content_item.register_template, content_item.unregister_template, content_item.get_template, content_type.unregister_template, content_type.register_template, content_type.set_default_template

     

  • Function: content_type.is_content_type

    Parameters:
    Not yet documented
    Declaration:
    
    function is_content_type (
      object_type   in acs_object_types.object_type%TYPE
    ) return char;
    
    

     

  • Procedure: content_type.create_type

    Create a new content type. Automatically create the attribute table for the type if the table does not already exist.

    Author:Karl Goldstein
    Parameters:
    content_type:   The name of the new type
    supertype:   The supertype, defaults to content_revision
    pretty_name:   Pretty name for the type, singular
    pretty_plural:   Pretty name for the type, plural
    table_name:   The name for the attribute table, defaults to the name of the supertype
    id_column:   The primary key for the table, defaults to 'XXX'
    name_method:   As in acs_object_type.create_type
    Declaration:
    
    procedure create_type (
      content_type		in acs_object_types.object_type%TYPE,
      supertype		in acs_object_types.object_type%TYPE
                               default 'content_revision',
      pretty_name		in acs_object_types.pretty_name%TYPE,
      pretty_plural	        in acs_object_types.pretty_plural%TYPE,
      table_name		in acs_object_types.table_name%TYPE default null,
      id_column		in acs_object_types.id_column%TYPE default 'XXX',
      name_method           in acs_object_types.name_method%TYPE default null
    );
    
    
    See Also:acs_object_type.create_type

     

  • Procedure: content_type.drop_attribute

    Drop an existing attribute. If you are using CMS, make sure to call cm_form_widget.unregister_attribute_widget before calling this function.

    Author:Karl Goldstein
    Parameters:
    content_type:   The name of the type to alter
    attribute_name:   The name of the attribute to drop
    drop_column:   If 't', will also alter the table and remove the column where the attribute is stored. The default is 'f' (leaves the table untouched).
    Declaration:
    
    procedure drop_attribute (
      content_type		in acs_attributes.object_type%TYPE,
      attribute_name	in acs_attributes.attribute_name%TYPE,
      drop_column           in varchar2 default 'f'
    );
    
    
    See Also:acs_object.drop_attribute, content_type.create_attribute, cm_form_widget.unregister_attribute_widget

     

  • Procedure: content_type.refresh_view

    Create a view for the type which joins all attributes of the type, including the inherited attributes. The view is named "X" Called by create_attribute and create_type.

    Author:Karl Goldstein
    Parameters:
    content_type:   The type for which the view is to be created.
    Declaration:
    
    procedure refresh_view (
      content_type  in cr_type_template_map.content_type%TYPE
    );
    
    
    See Also:content_type.create_type

     

  • Procedure: content_type.register_child_type

    Register a parent-child relationship between a content type and another object type. This may then be used by the content_item.is_valid_relation function to validate the relationship between an item and a potential child.

    Author:Karl Goldstein
    Parameters:
    content_type:   The type of the item from which the relationship originated.
    child_type:   The type of the child item.
    relation_tag:   A simple token used to identify a set of relations.
    min_n:   The minimun number of parent-child relationships of this type which an item must have to go live.
    max_n:   The minimun number of relationships of this type which an item must have to go live.
    Declaration:
    
    procedure register_child_type (
      parent_type  in cr_type_children.parent_type%TYPE,
      child_type    in cr_type_children.child_type%TYPE,
      relation_tag  in cr_type_children.relation_tag%TYPE default 'generic',
      min_n         in integer default 0,
      max_n         in integer default null
    );
    
    
    See Also:content_type.register_relation_type, content_type.register_child_type

     

  • Procedure: content_type.register_mime_type

    Parameters:
    Not yet documented
    Declaration:
    
    procedure register_mime_type (
      content_type  in cr_content_mime_type_map.content_type%TYPE,
      mime_type	in cr_content_mime_type_map.mime_type%TYPE
    );
    
    

     

  • Procedure: content_type.register_relation_type

    Register a relationship between a content type and another object type. This may then be used by the content_item.is_valid_relation function to validate any relationship between an item and another object.

    Author:Karl Goldstein
    Parameters:
    content_type:   The type of the item from which the relationship originated.
    target_type:   The type of the item to which the relationship is targeted.
    relation_tag:   A simple token used to identify a set of relations.
    min_n:   The minimun number of relationships of this type which an item must have to go live.
    max_n:   The minimun number of relationships of this type which an item must have to go live.
    Declaration:
    
    procedure register_relation_type (
      content_type  in cr_type_relations.content_type%TYPE,
      target_type   in cr_type_relations.target_type%TYPE,
      relation_tag  in cr_type_relations.relation_tag%TYPE default 'generic',
      min_n         in integer default 0,
      max_n         in integer default null
    );
    
    
    See Also:content_type.unregister_relation_type

     

  • Procedure: content_type.register_template

    Register a template for the content type. This template may be used to render all items of that type.

    Author:Karl Goldstein
    Parameters:
    content_type:   The type for which the template is to be registered
    template_id:   The ID of the template to register
    use_context:   The context in which the template is appropriate, such as 'admin' or 'public'
    is_default:   If 't', this template becomes the default template for the type, default is 'f'.
    Declaration:
    
    procedure register_template (
      content_type  in cr_type_template_map.content_type%TYPE,
      template_id   in cr_templates.template_id%TYPE,
      use_context   in cr_type_template_map.use_context%TYPE,
      is_default    in cr_type_template_map.is_default%TYPE default 'f'
    );
    
    
    See Also:content_item.register_template, content_item.unregister_template, content_item.get_template, content_type.unregister_template, content_type.set_default_template, content_type.get_template

     

  • Procedure: content_type.set_default_template

    Make the registered template a default template. The default template will be used to render all items of the type for which no individual template is registered.

    Author:Karl Goldstein
    Parameters:
    content_type:   The type for which the template is to be made default
    template_id:   The ID of the template to make default
    use_context:   The context in which the template is appropriate, such as 'admin' or 'public'
    Declaration:
    
    procedure set_default_template (
      content_type  in cr_type_template_map.content_type%TYPE,
      template_id   in cr_templates.template_id%TYPE,
      use_context   in cr_type_template_map.use_context%TYPE
    );
    
    
    See Also:content_item.register_template, content_item.unregister_template, content_item.get_template, content_type.unregister_template, content_type.register_template, content_type.get_template

     

  • Procedure: content_type.unregister_child_type

    Register a parent-child relationship between a content type and another object type. This may then be used by the content_item.is_valid_relation function to validate the relationship between an item and a potential child.

    Author:Karl Goldstein
    Parameters:
    parent_type:   The type of the parent item.
    child_type:   The type of the child item.
    relation_tag:   A simple token used to identify a set of relations.
    Declaration:
    
    procedure unregister_child_type (
      parent_type  in cr_type_children.parent_type%TYPE,
      child_type   in cr_type_children.child_type%TYPE,
      relation_tag in cr_type_children.relation_tag%TYPE default null
    );
    
    
    See Also:content_type.register_relation_type, content_type.register_child_type

     

  • Procedure: content_type.unregister_mime_type

    Parameters:
    Not yet documented
    Declaration:
    
    procedure unregister_mime_type (
      content_type  in cr_content_mime_type_map.content_type%TYPE,
      mime_type	in cr_content_mime_type_map.mime_type%TYPE
    );
    
    

     

  • Procedure: content_type.unregister_relation_type

    Unregister a relationship between a content type and another object type.

    Author:Karl Goldstein
    Parameters:
    content_type:   The type of the item from which the relationship originated.
    target_type:   The type of the item to which the relationship is targeted.
    relation_tag:   A simple token used to identify a set of relations.
    Declaration:
    
    procedure unregister_relation_type (
      content_type in cr_type_relations.content_type%TYPE,
      target_type  in cr_type_relations.target_type%TYPE,
      relation_tag in cr_type_relations.relation_tag%TYPE default null
    );
    
    
    See Also:content_type.register_relation_type

     

  • Procedure: content_type.unregister_template

    Unregister a template. If the unregistered template was the default template, the content_type can no longer be rendered in the use_context,

    Author:Karl Goldstein
    Parameters:
    content_type:   The type for which the template is to be unregistered
    template_id:   The ID of the template to unregister
    use_context:   The context in which the template is to be unregistered
    Declaration:
    
    procedure unregister_template (
      content_type  in cr_type_template_map.content_type%TYPE default null,
      template_id   in cr_templates.template_id%TYPE,
      use_context   in cr_type_template_map.use_context%TYPE default null
    );
    
    
    See Also:content_item.register_template, content_item.unregister_template, content_item.get_template, content_type.set_default_template, content_type.register_template, content_type.get_template

     

    Last Modified: $Id: type.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/keyword.html0000644000175000017500000004303507253523116025731 0ustar frankiefrankie Package: content_keyword

    content_keyword

    Content Repository : content_keyword


     

    Overview

    Keyword cassify a content_item. For example: If you have some press releases about dogs. You might want assigning the Keyword dog to every single content_item.

     

    Related Objects

    See also: content_item

     

    API

  • Function: content_keyword.get_description

    Retrieves the description of the content keyword

    Author:Karl Goldstein
    Returns:The description for the specified keyword
    Parameters:
    keyword_id:   The keyword id
    Declaration:
    
    function get_description (
      keyword_id  in cr_keywords.keyword_id%TYPE
    ) return varchar2;
    
    
    See Also:content_keyword.get_heading, content_keyword.set_description

     

  • Function: content_keyword.get_heading

    Retrieves the heading of the content keyword

    Author:Karl Goldstein
    Returns:The heading for the specified keyword
    Parameters:
    keyword_id:   The keyword id
    Declaration:
    
    function get_heading (
      keyword_id  in cr_keywords.keyword_id%TYPE
    ) return varchar2;
    
    
    See Also:content_keyword.set_heading, content_keyword.get_description

     

  • Function: content_keyword.get_path

    Retreives a path to the keyword/subject category, with the most general category at the root of the path

    Author:Karl Goldstein
    Returns:The path to the keyword, or null if no such keyword exists
    Parameters:
    keyword_id:   The keyword id
    Declaration:
    
    function get_path (
      keyword_id in cr_keywords.keyword_id%TYPE
    ) return varchar2;
    
    
    See Also:content_keyword.new

     

  • Function: content_keyword.is_assigned

    Determines if the keyword is assigned to the item

    Author:Karl Goldstein
    Returns:'t' if the keyword may be matched to an item, 'f' otherwise
    Parameters:
    item_id:   The item id
    keyword_id:   The keyword id to be checked for assignment
    recurse:   Specifies if the keyword search is recursive. May be set to one of the following values:
    • none: Not recursive. Look for an exact match.
    • up: Recursive from specific to general. A search for "attack dogs" will also match "dogs", "animals", "mammals", etc.
    • down: Recursive from general to specific. A search for "mammals" will also match "dogs", "attack dogs", "cats", "siamese cats", etc.
    Declaration:
    
    function is_assigned (
      item_id      in cr_items.item_id%TYPE,
      keyword_id   in cr_keywords.keyword_id%TYPE,
      recurse      in varchar2 default 'none'
    ) return varchar2;
    
    
    See Also:content_keyword.item_assign

     

  • Function: content_keyword.is_leaf

    Determines if the keyword has no sub-keywords associated with it

    Author:Karl Goldstein
    Returns:'t' if the keyword has no descendants, 'f' otherwise
    Parameters:
    keyword_id:   The keyword id
    Declaration:
    
    function is_leaf (
      keyword_id  in cr_keywords.keyword_id%TYPE
    ) return varchar2;
    
    
    See Also:content_keyword.new

     

  • Function: content_keyword.new

    Creates a new keyword (also known as "subject category").

    Author:Karl Goldstein
    Returns:The id of the newly created keyword
    Parameters:
    heading:   The heading for the new keyword
    description:   The description for the new keyword
    parent_id:   The parent of this keyword, defaults to null.
    keyword_id:   The id of the new keyword. A new id will be allocated if this parameter is null
    object_type:   The type for the new keyword, defaults to 'content_keyword'. This parameter may be used by subclasses of content_keyword to initialize the superclass.
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      heading       in cr_keywords.heading%TYPE,
      description   in cr_keywords.description%TYPE default null,
      parent_id     in cr_keywords.parent_id%TYPE default null,
      keyword_id    in cr_keywords.keyword_id%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null,
      object_type   in acs_object_types.object_type%TYPE default 'content_keyword'
    ) return cr_keywords.keyword_id%TYPE;
    
    
    See Also:acs_object.new, content_item.new, content_keyword.item_assign, content_keyword.delete

     

  • Procedure: content_keyword.delete

    Deletes the specified keyword, which must be a leaf. Unassigns the keyword from all content items. Use with caution - this operation cannot be undone.

    Author:Karl Goldstein
    Parameters:
    keyword_id:   The id of the keyword to be deleted
    Declaration:
    
    procedure delete (
      keyword_id  in cr_keywords.keyword_id%TYPE
    );
    
    
    See Also:acs_object.delete, content_keyword.item_unassign

     

  • Procedure: content_keyword.item_assign

    Assigns this keyword to a content item, creating a relationship between them

    Author:Karl Goldstein
    Parameters:
    item_id:   The item to be assigned to
    keyword_id:   The keyword to be assigned
    context_id:   As in acs_rel.new, deprecated
    creation_ip:   As in acs_rel.new, deprecated
    creation_user:   As in acs_rel.new, deprecated
    Declaration:
    
    procedure item_assign (
      item_id       in cr_items.item_id%TYPE,
      keyword_id    in cr_keywords.keyword_id%TYPE,
      context_id	in acs_objects.context_id%TYPE default null,
      creation_user in acs_objects.creation_user%TYPE default null,
      creation_ip   in acs_objects.creation_ip%TYPE default null
    );
    
    
    See Also:acs_rel.new, content_keyword.item_unassign

     

  • Procedure: content_keyword.item_unassign

    Unassigns this keyword to a content item, removing a relationship between them

    Author:Karl Goldstein
    Parameters:
    item_id:   The item to be unassigned from
    keyword_id:   The keyword to be unassigned
    Declaration:
    
    procedure item_unassign (
      item_id     in cr_items.item_id%TYPE,
      keyword_id  in cr_keywords.keyword_id%TYPE
    );
    
    
    See Also:acs_rel.delete, content_keyword.item_assign

     

  • Procedure: content_keyword.set_description

    Sets a new description for the keyword

    Author:Karl Goldstein
    Parameters:
    keyword_id:   The keyword id
    description:   The new description
    Declaration:
    
    procedure set_description (
      keyword_id  in cr_keywords.keyword_id%TYPE,
      description in cr_keywords.description%TYPE
    );
    
    
    See Also:content_keyword.set_heading, content_keyword.get_description

     

  • Procedure: content_keyword.set_heading

    Sets a new heading for the keyword

    Author:Karl Goldstein
    Parameters:
    keyword_id:   The keyword id
    heading:   The new heading
    Declaration:
    
    procedure set_heading (
      keyword_id  in cr_keywords.keyword_id%TYPE,
      heading     in cr_keywords.heading%TYPE
    );
    
    
    See Also:content_keyword.get_heading, content_keyword.set_description

     

    Last Modified: $Id: keyword.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/permission.html0000644000175000017500000003634207253523116026440 0ustar frankiefrankie Package: content_permission

    content_permission

    Content Repository : content_permission


     

    Overview

    Permissions can be set to allow certain users certain things. - They can be compared with the Unix filesystem permission: read, write ...

     

    Related Objects

    See also: {content_item }

     

    API

  • Function: content_permission.has_grant_authority

    Determine if the user may grant a certain permission to another user. The permission may only be granted if the user has the permission himself and posesses the cm_perm access, or if the user posesses the cm_perm_admin access.

    Author:Karl Goldstein
    Returns:'t' if the donation is possible, 'f' otherwise
    Parameters:
    object_id:   The object whose permissions are to be changed
    holder_id:   The person who is attempting to grant the permissions
    privilege:   The privilege to be granted
    Declaration:
    
      function has_grant_authority (
        object_id         in acs_objects.object_id%TYPE,
        holder_id         in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE
      ) return varchar2;
    
    
    See Also:content_permission.grant_permission, content_permission.is_has_revoke_authority, acs_permission.grant_permission

     

  • Function: content_permission.has_revoke_authority

    Determine if the user may take a certain permission away from another user. The permission may only be revoked if the user has the permission himself and posesses the cm_perm access, while the other user does not, or if the user posesses the cm_perm_admin access.

    Author:Karl Goldstein
    Returns:'t' if it is possible to revoke the privilege, 'f' otherwise
    Parameters:
    object_id:   The object whose permissions are to be changed
    holder_id:   The person who is attempting to revoke the permissions
    privilege:   The privilege to be revoked
    revokee_id:   The user from whom the privilege is to be taken away
    Declaration:
    
      function has_revoke_authority (
        object_id         in acs_objects.object_id%TYPE,
        holder_id         in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE,
        revokee_id        in parties.party_id%TYPE
      ) return varchar2;
    
    
    See Also:content_permission.has_grant_authority, content_permission.revoke_permission, acs_permission.revoke_permission

     

  • Function: content_permission.permission_p

    Determine if the user has the specified permission on the specified object. Does NOT check objects recursively: that is, if the user has the permission on the parent object, he does not automatically gain the permission on all the child objects.

    Author:Karl Goldstein
    Returns:'t' if the user has the specified permission on the object, 'f' otherwise
    Parameters:
    object_id:   The object whose permissions are to be checked
    holder_id:   The person whose permissions are to be examined
    privilege:   The privilege to be checked
    Declaration:
    
      function permission_p (
        object_id         in acs_objects.object_id%TYPE,
        holder_id         in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE
      ) return varchar2;
    
    
    See Also:content_permission.grant_permission, content_permission.revoke_permission, acs_permission.permission_p

     

  • Procedure: content_permission.grant_permission

    This is a helper function for content_permission.grant_permission and should not be called individually.

    Grants a permission and revokes all descendants of the permission, since they are no longer relevant.

    Author:Karl Goldstein
    Parameters:
    object_id:   The object whose permissions are to be changed
    grantee_id:   The person who should gain the parent privilege
    privilege:   The parent privilege to be granted
    Declaration:
    
      procedure grant_permission_h (
        object_id         in acs_objects.object_id%TYPE,
        grantee_id        in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE
      );
    
    
    See Also:content_permission.grant_permission

     

  • Procedure: content_permission.grant_permission_h

    This is a helper function for content_permission.grant_permission and should not be called individually.

    Grants a permission and revokes all descendants of the permission, since they are no longer relevant.

    Author:Karl Goldstein
    Parameters:
    object_id:   The object whose permissions are to be changed
    grantee_id:   The person who should gain the parent privilege
    privilege:   The parent privilege to be granted
    Declaration:
    
      procedure grant_permission_h (
        object_id         in acs_objects.object_id%TYPE,
        grantee_id        in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE
      );
    
    
    See Also:content_permission.grant_permission

     

  • Procedure: content_permission.inherit_permissions

    Make the child object inherit all of the permissions of the parent object. Typically, this function is called whenever a new object is created under a given parent

    Author:Karl Goldstein
    Parameters:
    parent_object_id:   The parent object id
    child_object_id:   The child object id
    Declaration:
    
      procedure inherit_permissions (
        parent_object_id  in acs_objects.object_id%TYPE,
        child_object_id   in acs_objects.object_id%TYPE,
        child_creator_id  in parties.party_id%TYPE default null
      );
    
    
    See Also:content_permission.grant, acs_permission.grant_permission

     

  • Procedure: content_permission.revoke_permission

    This is a helper function for content_permission.revoke_permission and should not be called individually.

    Revokes a permission but grants all child permissions to the holder, to ensure that the permission is not permanently lost

    Author:Karl Goldstein
    Parameters:
    object_id:   The object whose permissions are to be changed
    revokee_id:   The person who should lose the parent permission
    privilege:   The parent privilege to be revoked
    Declaration:
    
      procedure revoke_permission_h (
        object_id         in acs_objects.object_id%TYPE,
        revokee_id        in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE
      );
    
    
    See Also:content_permission.revoke_permission

     

  • Procedure: content_permission.revoke_permission_h

    This is a helper function for content_permission.revoke_permission and should not be called individually.

    Revokes a permission but grants all child permissions to the holder, to ensure that the permission is not permanently lost

    Author:Karl Goldstein
    Parameters:
    object_id:   The object whose permissions are to be changed
    revokee_id:   The person who should lose the parent permission
    privilege:   The parent privilege to be revoked
    Declaration:
    
      procedure revoke_permission_h (
        object_id         in acs_objects.object_id%TYPE,
        revokee_id        in parties.party_id%TYPE,
        privilege         in acs_privileges.privilege%TYPE
      );
    
    
    See Also:content_permission.revoke_permission

     

    Last Modified: $Id: permission.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/item.html0000644000175000017500000012777310057204432025210 0ustar frankiefrankie Package: content_item

    content_item

    Content Repository : content_item


     

    Overview

    Content items store the overview of the content published on a website. The actual content is stored in content revisions. It is implemented this way so that there can be mulitple versions of the actual content while the main idea remains constant. For example: If there is a review for the movie "Terminator," there will exist a content item by the name "terminator" with all the right parameters (supertype, parent, etc), there will also exist at least one content revision pointing to this item with the actual review content.

     

    Related Objects

    See also: content_revision, content_folder

     

    API

  • Function: content_item.get_content_type

    Retrieve the content type of this item. Only objects of this type may be used as revisions for the item.

    Author:Karl Goldstein
    Returns:The content type of the item
    Parameters:
    item_id:   The item for which the content type is to be retrieved
    Declaration:
    
    function get_content_type (
      item_id     in cr_items.item_id%TYPE
    ) return cr_items.content_type%TYPE;
    
    

     

  • Function: content_item.get_context

    Retrieve the parent of the given item

    Author:Karl Goldstein
    Returns:The id of the parent for this item
    Parameters:
    item_id:   The item for which the parent is to be retrieved
    Declaration:
    
    function get_context (
      item_id	in cr_items.item_id%TYPE
    ) return acs_objects.context_id%TYPE;
    
    

     

  • Function: content_item.get_id

    Takes in a path, such as "/tv/programs/star_trek/episode_203" and returns the id of the item with this path. Note: URLs are abstract (no extensions are allowed in content item names and extensions are stripped when looking up content items)

    Author:Karl Goldstein
    Returns:The id of the item with the given path, or null if no such item exists
    Parameters:
    item_path:   The path to be resolved
    root_folder_id:   Starts path resolution from this folder. Defaults to the root of the sitemap
    Declaration:
    
    function get_id (
      item_path   in varchar2,
      root_folder_id in cr_items.item_id%TYPE default c_root_folder_id
    ) return cr_items.item_id%TYPE;
    
    
    See Also:content_item.get_path

     

  • Function: content_item.get_latest_revision

    Retrieves the id of the latest revision for the item (as opposed to the live revision)

    Author:Karl Goldstein
    Returns:The id of the latest revision for this item, or null if no revisions exist
    Parameters:
    item_id:   The item for which the latest revision is to be retrieved
    Declaration:
    
    function get_latest_revision (
      item_id    in cr_items.item_id%TYPE
    ) return cr_revisions.revision_id%TYPE;
    
    
    See Also:content_item.get_live_revision

     

  • Function: content_item.get_live_revision

    Retrieves the id of the live revision for the item

    Note that this function does nothing else besides retrieving the value of the column cr_items.live_revision. It is thus more efficient in many cases to join against cr_items and retrieve the value directly.

    Returns:The id of the live revision for this item, or null if no live revision exists
    Parameters:
    item_id:   The item for which the live revision is to be retrieved
    Declaration:
    
    function get_live_revision (
      item_id   in cr_items.item_id%TYPE
    ) return cr_revisions.revision_id%TYPE;
    
    
    See Also:content_item.set_live_revision, content_item.get_latest_revision

     

  • Function: content_item.get_parent_folder

    Get the parent folder.

    Author:Michael Pih
    Returns:the folder_id of the parent folder, null otherwise
    Parameters:
    item_id:   The item id
    Declaration:
    
    function get_parent_folder (
      item_id	in cr_items.item_id%TYPE
    ) return cr_folders.folder_id%TYPE;
    
    

     

  • Function: content_item.get_path

    Retrieves the full path to an item, in the form of "/tv/programs/star_trek/episode_203"

    Author:Karl Goldstein
    Returns:The path to the item
    Parameters:
    item_id:   The item for which the path is to be retrieved
    root_folder_id:   Starts path resolution from this folder. Defaults to the root of the sitemap
    Declaration:
    
    function get_path (
      item_id        in cr_items.item_id%TYPE,
      root_folder_id in cr_items.item_id%TYPE default c_root_folder_id
    ) return varchar2;
    
    
    See Also:content_item.get_id, content_item.write_to_file

     

  • Function: content_item.get_publish_date

    Retrieves the publish date for the item

    Author:Karl Goldstein
    Returns:The publish date for the item, or null if the item has no revisions
    Parameters:
    item_id:   The item for which the publish date is to be retrieved
    is_live:   If 't', use the live revision for the item. Otherwise, use the latest revision. The default is 'f'
    Declaration:
    
    function get_publish_date (
      item_id    in cr_items.item_id%TYPE,
      is_live    in char default 'f'
    ) return cr_revisions.publish_date%TYPE;
    
    
    See Also:content_item.get_live_revision, content_item.get_latest_revision,

     

  • Function: content_item.get_revision_count

    Return the total count of revisions for this item

    Author:Karl Goldstein
    Returns:The number of revisions for this item
    Parameters:
    item_id:   The id the item
    Declaration:
    
    function get_revision_count (
      item_id   in cr_items.item_id%TYPE
    ) return number;
    
    
    See Also:content_revision.new

     

  • Function: content_item.get_root_folder

    Parameters:
    Not yet documented
    Declaration:
    
    function get_root_folder return cr_folders.folder_id%TYPE;
    
    

     

  • Function: content_item.get_template

    Retrieves the template which should be used to render this item. If no template is registered to specifically render the item in the given context, the default template for the item's type is returned.

    Author:Karl Goldstein
    Returns:The id of the registered template, or null if no template could be found
    Parameters:
    item_id:   The item for which the template will be unregistered
    use_context:   The context in the item is to be rendered, such as 'admin' or 'public'
    Declaration:
    
    function get_template (
      item_id     in cr_items.item_id%TYPE,
      use_context in cr_item_template_map.use_context%TYPE
    ) return cr_templates.template_id%TYPE;
    
    
    See Also:content_type.register_template, content_item.register_template,

     

  • Function: content_item.get_title

    Retrieves the title for the item, using either the latest or the live revision. If the specified item is in fact a folder, return the folder's label. In addition, this function will automatically resolve symlinks.

    Author:Karl Goldstein
    Returns:The title of the item
    Parameters:
    item_id:   The item for which the title is to be retrieved
    is_live:   If 't', use the live revision to get the title. Otherwise, use the latest revision. The default is 'f'
    Declaration:
    
    function get_title (
      item_id    in cr_items.item_id%TYPE,
      is_live    in char default 'f'
    ) return cr_revisions.title%TYPE;
    
    
    See Also:content_item.get_live_revision, content_item.get_latest_revision, content_symlink.resolve

     

  • Function: content_item.get_virtual_path

    Retrieves the virtual path to an item, in the form of "/tv/programs/star_trek/episode_203"

    Author:Michael Pih
    Returns:The virtual path to the item
    Parameters:
    item_id:   The item for which the path is to be retrieved
    root_folder_id:   Starts path resolution from this folder. Defaults to the root of the sitemap
    Declaration:
    
    function get_virtual_path (
      item_id        in cr_items.item_id%TYPE,
      root_folder_id in cr_items.item_id%TYPE default c_root_folder_id
    ) return varchar2;
    
    
    See Also:content_item.get_id, content_item.write_to_file, content_item.get_path

     

  • Function: content_item.is_index_page

    Determine if the item is an index page for the specified folder. The item is an index page for the folder if it exists in the folder and its item name is "index".

    Author:Karl Goldstein
    Returns:'t' if the item is an index page for the specified folder, 'f' otherwise
    Parameters:
    item_id:   The item id
    folder_id:   The folder id
    Declaration:
    
    function is_index_page (
      item_id   in cr_items.item_id%TYPE,
      folder_id in cr_folders.folder_id%TYPE
    ) return varchar2;
    
    
    See Also:content_folder.get_index_page

     

  • Function: content_item.is_publishable

    Determines if an item is publishable. Publishable items must meet the following criteria: 1) for each child type, the item has n children, min_n < n < max_n 2) for each relation type, the item has n relations, min_n < n < max_n 3) any 'publishing_wf' workflows are finished

    Author:Michael Pih
    Returns:'t' if the item is publishable in it's present state, Otherwise, returns 'f'
    Parameters:
    item_id The:   item ID of the potential parent
    Declaration:
    
    function is_publishable (
      item_id		in cr_items.item_id%TYPE
    ) return char;
    
    

     

  • Function: content_item.is_subclass

    Determines if one type is a subclass of another. A class is always a subclass of itself.

    Author:Karl Goldstein
    Returns:'t' if the child class is a subclass of the superclass, 'f' otherwise
    Parameters:
    object_type:   The child class
    supertype:   The superclass
    Declaration:
    
    function is_subclass (
      object_type in acs_object_types.object_type%TYPE,
      supertype	in acs_object_types.supertype%TYPE
    ) return char;
    
    
    See Also:acs_object_type.create_type

     

  • Function: content_item.is_valid_child

    Determines if an item would be a valid child of another item by checking if the parent allows children of the would-be child's content type and if the parent already has n_max children of that content type.

    Author:Michael Pih
    Returns:'t' if the item would be a valid child, 'f' otherwise
    Parameters:
    item_id The:   item ID of the potential parent
    content_type The:   content type of the potential child item
    Declaration:
    
    function is_valid_child (
      item_id	in cr_items.item_id%TYPE,
      content_type  in acs_object_types.object_type%TYPE
    ) return char;
    
    

     

  • Function: content_item.new

    Creates a new content item. If the data, title or text parameters are specified, also creates a revision for the item.

    Author:Karl Goldstein
    Returns:The id of the newly created item
    Parameters:
    name:   The name for the item, must be URL-encoded. If an item with this name already exists under the specified parent item, an error is thrown
    parent_id:   The parent of this item, defaults to null
    item_id:   The id of the new item. A new id will be allocated if this parameter is null
    locale:   The locale for this item, for use with Intermedia search
    item_subtype:   The type of the new item, defaults to 'content_item' This parameter is used to support inheritance, so that subclasses of content_item can call this function to initialize the parent class
    content_type:   The content type for the item, defaults to 'content_revision'. Only objects of this type may be used as revisions for the item
    title:   The user-readable title for the item, defaults to the item's name
    description:   A short description for the item (4000 characters maximum)
    mime_type:   The file type of the item, defaults to 'text/plain'
    nls_language:   The language for the item, used for Intermedia search
    text:   The text content of the new revision, 4000 charcters maximum. Cannot be specified simultaneously with the data parameter
    data:   The blob content of the new revison. Cannot be specified simultaneously with the text parameter
    relation_tag:   If a parent-child relationship is registered for these content types, use this tag to describe the parent-child relationship. Defaults to 'parent content type'-'child content type'
    is_live:   If 't', the new revision will become live
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      name          in cr_items.name%TYPE,
      parent_id     in acs_objects.context_id%TYPE default null,
      item_id	in acs_objects.object_id%TYPE default null,
      locale        in cr_items.locale%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null,
      item_subtype	in acs_object_types.object_type%TYPE
                               default 'content_item',
      content_type  in acs_object_types.object_type%TYPE
                               default 'content_revision',
      title         in cr_revisions.title%TYPE default null,
      description   in cr_revisions.description%TYPE default null,
      mime_type   	in cr_revisions.mime_type%TYPE default 'text/plain',
      nls_language 	in cr_revisions.nls_language%TYPE default null,
      text	        in varchar2 default null,
      data	        in cr_revisions.content%TYPE default null,
      relation_tag  in cr_child_rels.relation_tag%TYPE default null,
      is_live       in char default 'f'
    ) return cr_items.item_id%TYPE;
    
    
    See Also:acs_object.new

     

  • Function: content_item.relate

    Parameters:
    Not yet documented
    Declaration:
    
    function relate (
      item_id       in cr_items.item_id%TYPE,
      object_id     in acs_objects.object_id%TYPE,
      relation_tag in cr_type_relations.relation_tag%TYPE default 'generic',
      order_n       in cr_item_rels.order_n%TYPE default null,
      relation_type in acs_object_types.object_type%TYPE default 'cr_item_rel'
    ) return cr_item_rels.rel_id%TYPE;
    
    

     

  • Procedure: content_item.copy

    Copies the item to a new location, creating an identical item with no revisions or associated workflow. If the target folder does not exist, or if the folder already contains an item with the same name as the given item, an error will be thrown.

    Author:Karl Goldstein
    Parameters:
    item_id:   The item to be copied
    target_folder_id:   The folder where the item is to be copied
    Declaration:
    
    procedure copy (
      item_id		in cr_items.item_id%TYPE,
      target_folder_id	in cr_folders.folder_id%TYPE
    );
    
    
    See Also:content_item.new, content_folder.new, content_item.move

     

  • Procedure: content_item.delete

    Deletes the specified content item, along with any revisions, symlinks, workflows, and template relations for the item. Use with caution - this operation cannot be undone.

    Author:Karl Goldstein
    Parameters:
    item_id:   The id of the item to delete
    Declaration:
    
    procedure delete (
      item_id	in cr_items.item_id%TYPE
    );
    
    
    See Also:acs_object.delete

     

  • Procedure: content_item.move

    Move the specified item to a different folder. If the target folder does not exist, or if the folder already contains an item with the same name as the given item, an error will be thrown.

    Author:Karl Goldstein
    Parameters:
    item_id:   The item to be moved
    target_folder_id:   The new folder for the item
    Declaration:
    
    procedure move (
      item_id		in cr_items.item_id%TYPE,
      target_folder_id	in cr_folders.folder_id%TYPE
    );
    
    
    See Also:content_item.new, content_folder.new, content_item.copy

     

  • Procedure: content_item.register_template

    Registers a template which will be used to render this item.

    Author:Karl Goldstein
    Parameters:
    item_id:   The item for which the template will be registered
    template_id:   The template to be registered
    use_context:   The context in which the template is appropriate, such as 'admin' or 'public'
    Declaration:
    
    procedure register_template (
      item_id      in cr_items.item_id%TYPE,
      template_id  in cr_templates.template_id%TYPE,
      use_context  in cr_item_template_map.use_context%TYPE
    );
    
    
    See Also:content_type.register_template, content_item.unregister_template, content_item.get_template

     

  • Procedure: content_item.edit_name

    Renames the item. If an item with the specified name already exists under this item's parent, an error is thrown

    Author:Karl Goldstein
    Parameters:
    item_id:   The id of the item to rename
    name:   The new name for the item, must be URL-encoded
    Declaration:
    
    procedure rename (
      item_id	 in cr_items.item_id%TYPE,
      name           in cr_items.name%TYPE
    );
    
    
    See Also:content_item.new

     

  • Procedure: content_item.set_live_revision

    Make the specified revision the live revision for the item

    Author:Karl Goldstein
    Parameters:
    revision_id:   The id of the revision which is to become live for its corresponding item
    Declaration:
    
    procedure set_live_revision (
      revision_id   in cr_revisions.revision_id%TYPE,
      publish_status in cr_items.publish_status%TYPE default 'ready'
    );
    
    
    See Also:content_item.get_live_revision

     

  • Procedure: content_item.set_release_period

    Sets the release period for the item. This information may be used by applications to update the publishing status of items at periodic intervals.

    Author:Karl Goldstein
    Parameters:
    item_id:   The id the item.
    start_when:   The time and date when the item should be released.
    end_when:   The time and date when the item should be expired.
    Declaration:
    
    procedure set_release_period (
      item_id    in cr_items.item_id%TYPE,
      start_when date default null,
      end_when   date default null
    );
    
    

     

  • Procedure: content_item.unregister_template

    Unregisters a template which will be used to render this item.

    Author:Karl Goldstein
    Parameters:
    item_id:   The item for which the template will be unregistered
    template_id:   The template to be registered
    use_context:   The context in which the template is appropriate, such as 'admin' or 'public'
    Declaration:
    
    procedure unregister_template (
      item_id      in cr_items.item_id%TYPE,
      template_id  in cr_templates.template_id%TYPE default null,
      use_context  in cr_item_template_map.use_context%TYPE default null
    );
    
    
    See Also:content_type.register_template, content_item.register_template, content_item.get_template

     

  • Procedure: content_item.unset_live_revision

    Parameters:
    Not yet documented
    Declaration:
    
    procedure unset_live_revision (
      --/** Set the live revision to null for the item
      --    @author Michael Pih
      --    @param item_id The id of the item for which to unset the live revision
      --    @see {content_item.set_live_revision}
      item_id      in cr_items.item_id%TYPE
    );
    
    

     

  • Procedure: content_item.write_to_file

    Writes the content of the live revision of this item to a file, creating all the neccessary directories in the process

    Author:Karl Goldstein
    Parameters:
    item_id:   The item to be written to a file
    root_path:   The path in the filesystem to which the root of the sitemap corresponds
    Declaration:
    
    procedure write_to_file (
      item_id     in cr_items.item_id%TYPE,
      root_path   in varchar2
    );
    
    
    See Also:content_item.get_path

     

    Last Modified: $Id: item.html,v 1.3 2004/06/01 22:54:18 donb Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/revision.html0000644000175000017500000003270707253523116026107 0ustar frankiefrankie Package: content_revision

    content_revision

    Content Repository : content_revision


     

    Overview

    Content revisions contain the data for content items. There is a many to one relationship between content revisions and content items. There is at most one "live" revision for every content item though. For example, there may be 5 revisions of the review for the movie "Terminator," yet only one of these may be live on the website at a given time.

     

    Related Objects

    See also: {content_item }

     

    API

  • Function: content_revision.copy

    Creates a new copy of an attribute, including all attributes

    Author:Karl Goldstein
    Parameters:
    revision_id:   The id of the revision to copy
    Declaration:
    
    function copy (
      revision_id	in cr_revisions.revision_id%TYPE,
      copy_id	in cr_revisions.revision_id%TYPE default null
    ) return cr_revisions.revision_id%TYPE;
    
    
    See Also:content_revision.new

     

  • Function: content_revision.export_xml

    Parameters:
    Not yet documented
    Declaration:
    
    function export_xml (
      revision_id IN cr_revisions.revision_id%TYPE
    ) return cr_xml_docs.doc_id%TYPE;
    
    

     

  • Function: content_revision.get_number

    Return the revision number of the specified revision, according to the chronological order in which revisions have been added for this item.

    Author:Karl Goldstein
    Returns:The number of the revision
    Parameters:
    revision_id:   The id the revision
    Declaration:
    
    function get_number (
      revision_id   in cr_revisions.revision_id%TYPE
    ) return number;
    
    
    See Also:content_revision.new

     

  • Function: content_revision.import_xml

    Parameters:
    Not yet documented
    Declaration:
    
    function import_xml (
      item_id IN cr_items.item_id%TYPE,
      revision_id IN cr_revisions.revision_id%TYPE,
      doc_id IN number
    ) return cr_revisions.revision_id%TYPE;
    
    

     

  • Function: content_revision.new

    Create a new revision for an item.

    Author:Karl Goldstein
    Returns:The id of the newly created revision
    Parameters:
    title:   The revised title for the item
    description:   A short description of this revision, 4000 characters maximum
    publish_date:   Publication date.
    mime_type:   The revised mime type of the item, defaults to 'text/plain'
    nls_language:   The revised language of the item, for use with Intermedia searching
    data:   The blob which contains the body of the revision
    item_id:   The id of the item being revised
    revision_id:   The id of the new revision. A new id will be allocated by default
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      title         in cr_revisions.title%TYPE,
      description   in cr_revisions.description%TYPE default null,
      publish_date  in cr_revisions.publish_date%TYPE default sysdate,
      mime_type   	in cr_revisions.mime_type%TYPE default 'text/plain',
      nls_language 	in cr_revisions.nls_language%TYPE default null,
      data	        in cr_revisions.content%TYPE,
      item_id       in cr_items.item_id%TYPE,
      revision_id   in cr_revisions.revision_id%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null
    ) return cr_revisions.revision_id%TYPE;
    
    
    See Also:acs_object.new, content_item.new

     

  • Function: content_revision.read_xml

    Parameters:
    Not yet documented
    Declaration:
    
    function read_xml (
      item_id IN number,
      revision_id IN number,
      clob_loc IN clob
    ) return number as language
      java
    name
      'com.arsdigita.content.XMLExchange.importRevision(
         java.lang.Integer, java.lang.Integer, oracle.sql.CLOB
      ) return int';
    
    

     

  • Function: content_revision.write_xml

    Parameters:
    Not yet documented
    Declaration:
    
    function write_xml (
      revision_id IN number,
      clob_loc IN clob
    ) return number as language
      java
    name
      'com.arsdigita.content.XMLExchange.exportRevision(
         java.lang.Integer, oracle.sql.CLOB
      ) return int';
    
    

     

  • Procedure: content_revision.delete

    Deletes the revision.

    Author:Karl Goldstein
    Parameters:
    revision_id:   The id of the revision to delete
    Declaration:
    
    procedure delete (
      revision_id	in cr_revisions.revision_id%TYPE
    );
    
    
    See Also:content_revision.new, acs_object.delete

     

  • Procedure: content_revision.index_attributes

    Generates an XML document for insertion into cr_revision_attributes, which is indexed by Intermedia for searching attributes.

    Author:Karl Goldstein
    Parameters:
    revision_id:   The id of the revision to index
    Declaration:
    
    procedure index_attributes(
      revision_id IN cr_revisions.revision_id%TYPE
    );
    
    
    See Also:content_revision.new

     

  • Procedure: content_revision.replace

    Parameters:
    Not yet documented
    Declaration:
    
    procedure replace(
      revision_id number, search varchar2, replace varchar2)
    as language
      java
    name
      'com.arsdigita.content.Regexp.replace(
        int, java.lang.String, java.lang.String
       )';
    
    

     

  • Procedure: content_revision.to_html

    Converts a revision uploaded as a binary document to html

    Author:Karl Goldstein
    Parameters:
    revision_id:   The id of the revision to index
    Declaration:
    
    procedure to_html (
      revision_id IN cr_revisions.revision_id%TYPE
    );
    
    

     

    Last Modified: $Id: revision.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/symlink.html0000644000175000017500000002320007253523116025723 0ustar frankiefrankie Package: content_symlink

    content_symlink

    Content Repository : content_symlink


     

    Overview

    Symlinks are pointers to items within the content repository. They are simply used to create links between content items.

     

    Related Objects

    See also: content_item, content_folder

     

    API

  • Function: content_symlink.is_symlink

    Determines if the item is a symlink

    Author:Karl Goldstein
    Returns:'t' if the item is a symlink, 'f' otherwise
    Parameters:
    item_id:   The item id
    Declaration:
    
    function is_symlink (
      item_id	   in cr_items.item_id%TYPE
    ) return char;
    
    
    See Also:content_symlink.new, content_symlink.resolve

     

  • Function: content_symlink.new

    Create a new symlink, linking two items

    Author:Karl Goldstein
    Returns:The id of the newly created symlink
    Parameters:
    name:   The name for the new symlink, defaults to the name of the target item
    label :   The label of the symlink, defaults to 'Symlinke to '
    target_id:   The item which the symlink will point to
    parent_id:   The parent folder for the symlink. This must actually be a folder and not a generic content item.
    symlink_id:   The id of the new symlink. A new id will be allocated by default
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      name          in cr_items.name%TYPE default null,
      label		in cr_symlinks.label%TYPE default null,
      target_id	in cr_items.item_id%TYPE,
      parent_id     in acs_objects.context_id%TYPE,
      symlink_id	in cr_symlinks.symlink_id%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null
    ) return cr_symlinks.symlink_id%TYPE;
    
    
    See Also:acs_object.new, content_item.new, content_symlink.resolve

     

  • Function: content_symlink.resolve

    Resolves the symlink and returns the target item id.

    Author:Karl Goldstein
    Returns:The target item of the symlink, or the original item id if the item is not in fact a symlink
    Parameters:
    item_id:   The item id to be resolved
    Declaration:
    
    function resolve (
      item_id	in cr_items.item_id%TYPE
    ) return cr_items.item_id%TYPE;
    
    
    See Also:content_symlink.new, content_symlink.is_symlink

     

  • Function: content_symlink.resolve_content_type

    Gets the content type of the target item.

    Author:Michael Pih
    Returns:The content type of the symlink target, otherwise null. the item is not in fact a symlink
    Parameters:
    item_id:   The item id to be resolved
    Declaration:
    
    function resolve_content_type (
      item_id	in cr_items.item_id%TYPE
    ) return cr_items.content_type%TYPE;
    
    
    See Also:content_symlink.resolve

     

  • Procedure: content_symlink.copy

    Copies the symlink itself to another folder, without resolving the symlink

    Author:Karl Goldstein
    Parameters:
    symlink_id:   The id of the symlink to copy
    target_folder_id:   The id of the folder where the symlink is to be copied
    Declaration:
    
    procedure copy (
      symlink_id		in cr_symlinks.symlink_id%TYPE,
      target_folder_id	in cr_folders.folder_id%TYPE
    );
    
    
    See Also:content_symlink.new, content_item.copy

     

  • Procedure: content_symlink.delete

    Deletes the symlink

    Author:Karl Goldstein
    Parameters:
    symlink_id:   The id of the symlink to delete
    Declaration:
    
    procedure delete (
      symlink_id	in cr_symlinks.symlink_id%TYPE
    );
    
    
    See Also:content_symlink.new, acs_object.delete

     

    Last Modified: $Id: symlink.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/extlink.html0000644000175000017500000001431707253523116025724 0ustar frankiefrankie Package: content_extlink

    content_extlink

    Content Repository : content_extlink


     

    Overview

    External links are references to content pages on other web sites. They provide the basis for maintaining a hierarchy of "bookmarks" that may be managed in a manner analogous to other content items. In particular, external links may be tagged with keywords and related to the site's own content items.

     

    Related Objects

    See also: {content_item }

     

    API

  • Function: content_extlink.is_extlink

    Determines if the item is a extlink

    Author:Karl Goldstein
    Returns:'t' if the item is a extlink, 'f' otherwise
    Parameters:
    item_id:   The item id
    Declaration:
    
    function is_extlink (
      item_id	   in cr_items.item_id%TYPE
    ) return char;
    
    
    See Also:content_extlink.new, content_extlink.resolve

     

  • Function: content_extlink.new

    Create a new extlink, an item pointing to an off-site resource

    Author:Karl Goldstein
    Returns:The id of the newly created extlink
    Parameters:
    name:   The name for the new extlink, defaults to the name of the target item
    url:   The URL of the item
    label:   The text label or title of the item
    description:   A brief description of the item
    parent_id:   The parent folder for the extlink. This must actually be a folder and not a generic content item.
    extlink_id:   The id of the new extlink. A new id will be allocated by default
    creation_date:   As in acs_object.new
    creation_ip:   As in acs_object.new
    creation_user:   As in acs_object.new
    Declaration:
    
    function new (
      name          in cr_items.name%TYPE default null,
      url   	in cr_extlinks.url%TYPE,
      label   	in cr_extlinks.label%TYPE default null,
      description   in cr_extlinks.description%TYPE default null,
      parent_id     in acs_objects.context_id%TYPE,
      extlink_id	in cr_extlinks.extlink_id%TYPE default null,
      creation_date	in acs_objects.creation_date%TYPE
    			   default sysdate,
      creation_user	in acs_objects.creation_user%TYPE
    			   default null,
      creation_ip	in acs_objects.creation_ip%TYPE default null
    ) return cr_extlinks.extlink_id%TYPE;
    
    
    See Also:acs_object.new, content_item.new, content_extlink.resolve

     

  • Procedure: content_extlink.delete

    Deletes the extlink

    Author:Karl Goldstein
    Parameters:
    extlink_id:   The id of the extlink to delete
    Declaration:
    
    procedure delete (
      extlink_id	in cr_extlinks.extlink_id%TYPE
    );
    
    
    See Also:content_extlink.new, acs_object.delete

     

    Last Modified: $Id: extlink.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/api/content.html0000644000175000017500000000547707253523116025727 0ustar frankiefrankie Package: content

    content

    Content Repository : content


  • Function content.blob_to_string

    Parameters:
    Not yet documented
    Declaration:
    
    function blob_to_string(
      blob_loc blob) return varchar2
    as language
      java
    name
      'com.arsdigita.content.Util.blobToString(
        oracle.sql.BLOB
       ) return java.lang.String';
    
    

  • Procedure content.blob_to_file

    Parameters:
    Not yet documented
    Declaration:
    
    procedure blob_to_file(
    s varchar2, blob_loc blob)
    as language
      java
    name
      'com.arsdigita.content.Util.blobToFile(
      java.lang.String, oracle.sql.BLOB
      )';
    
    

  • Procedure content.string_to_blob

    Parameters:
    Not yet documented
    Declaration:
    
    procedure string_to_blob(
      s varchar2, blob_loc blob)
    as language
      java
    name
      'com.arsdigita.content.Util.stringToBlob(
        java.lang.String, oracle.sql.BLOB
       )';
    
    

  • Procedure content.string_to_blob_size

    Parameters:
    Not yet documented
    Declaration:
    
    procedure string_to_blob_size(
      s varchar2, blob_loc blob, blob_size number)
    as language
      java
    name
      'com.arsdigita.content.Util.stringToBlob(
        java.lang.String, oracle.sql.BLOB, int
       )';
    
    

    Last Modified: $Id: content.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/0000755000175000017500000000000011724401447023676 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/www/doc/guide/template.html0000644000175000017500000001316607253523116026406 0ustar frankiefrankie Content Repository Developer Guide: Applying Templates

    Applying Templates

    Content Repository : Developer Guide

    The content repository allows you to associate templates with both content types and individual content items. A template determines how a content item is rendered when exported to the file system or served directly to a client.

    The content repository does not make any assumptions about the type of templating system used by the application server with which it is being used. Templates are simply made available to the application server as text objects. The server is responsible for merging the template with the actual content.

    Creating templates

    The content repository handle templates as a special class of text object. The interface for handling templates builds on that of simple content items:

    template_id := content_template.new(
        name          => 'image_template',
        parent_id     => :parent_id
    );

    The name represents the tail of the location for that content template. The parent ID must be another content item, or a subclass of content item such as a folder.

    The content_template.new function accepts the standard creation_date, creation_user, and creation_ip auditing parameters.

    Content items and templates are organized in two separate hierarchies within the content repository. For example, you may place all your press releases in the press folder under the item root (having the ID returned by content_item.get_root_folder). You may have 5 different templates used to render press releases. These my be stored in the press folder under the template root (having the ID returned by content_template.get_root_folder).

    Templates are placed under their own root to ensures that bare templates are never accessible via a public URL. This is also done because the relationship with the file system may be different for templates than for content items. For example, templates may be associated with additional code or resource files that developers maintain under separate source control.

    Associating templates with content types

    You use the content_type.register_template procedure to associate a template with a particular content type:

    content_type.register_template(
      content_type => 'content_revision',
      template_id  => :template_id,
      use_context  => 'public',
      is_default   => 't'
    );

    The use_context is a simple keyword that specifies the situation in which the template is appropriate. One general context, public, is loaded when the content repository is installed. Templates in this context are for presenting content to users of the site. Some sites may wish to distinguish this further, for example using intranet, extranet and public contexts.

    The is_default flag specifies that this template will serve as the default template in the case that no template is registered to a content item of this content type and this use context. Any content type/context pair may have any number of templates registered to it, but there can be only one default template per pair.

    To make a template the default template for a content type/context pair:

    content_type.set_default_template(
        content_type => 'content_revision',
        template_id  => :template_id,
        use_context  => 'public'
    );

    Associating templates with content items

    Individual items may also be associated with templates using the content_item.register_template procedure:

    content_item.register_template(
      item_id     => :item_id,
      template_id => :template_id,
      use_context => 'intranet'
    );

    Unlike the case with content types, only one template may be registered with a content item for a particular context.

    The content management system uses this functionality to allow publishers to choose templates for each content they create. For example, a company may have three different templates for presenting press releases. Depending on the subject, geographic region or any other criterion, a different template may be used for each press release.

    Retrieving the template for a content item

    The application server (AOLserver or servlet container) may use the content_item.get_template function to determine the proper template to use for rendering a page in any particular context:

    template_id := content_item.get_template(
        item_id     => :item_id, 
        use_context => 'public'
    );
    
    template_path := content_template.get_path(
        template_id => :template_id
    );

    In the case that no template is registered to given item/context pair, content_item.get_template will return the default template (if it exists) for the related content type/context pair.

    Unregistering templates

    The procedure for disassociating templates with content types is as follows:

    content_type.unregister_template(
        content_type => 'content_revision',
        template_id  => :template_id,
        use_context  => 'intranet'
    );

    The corresponding procedure to disassociate templates with content items is:

    content_item.unregister_template(
        item_id     => :item_id,
        template_id => :template_id,
        use_context => 'admin'
    );

    karlg@arsdigita.com

    Last Modified: $Id: template.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/keywords.html0000644000175000017500000001567310453125136026443 0ustar frankiefrankie Content Repository Developer Guide: Subject Keywords (Categories)

    Subject Keywords (Categories)

    Content Repository : Developer Guide

    Overview

    Subject Keywords are used to implement categorization for the Content Management system. A Subject Keyword is a small label, such as "Oracle Documentation" or "My Favorite Foods", which can be associated with any number of content items. Thus, content items may be grouped by arbitrary categories. For example, assigning the Subject Keyword "My Favorite Foods" to the content items "Potstickers", "Strawberries" and "Ice Cream" would indicate that all the three items belong in the same category - namely, the category of the user's favorite foods. The actual physical location of these items within the repository is irrelevant.

    Subject Keywords may be nested to provide more detailed control over categorization; for example, "My Favorite Foods" may be further subdivided into "Healthy" and "Unhealthy". Subject Keywords which have descendants are referred to as "Subject Categories".

    Data Model

    The content_keyword object type is used to represent Subject Keywords (see content_keyword.sql) The content_keyword type inherits from acs_object:

     acs_object_type.create_type ( supertype => 'acs_object', object_type
       => 'content_keyword', pretty_name => 'Content Keyword',
       pretty_plural => 'Content Keywords', table_name => 'cr_keywords',
       id_column => 'keyword_id', name_method => 'acs_object.default_name'
       ); 
    In addition, the cr_keywords table (see content-create.sql) contains extended attributes of Subject Keywords:
    create table cr_keywords (
      keyword_id             integer
                             constraint cr_keywords_pk
                             primary key,
      heading                varchar2(600)
                             constraint cr_keywords_name_nil
                             not null,
      description            varchar2(4000)
    );
    
    In content-keyword.sql:
    attr_id := acs_attribute.create_attribute (
      object_type    => 'acs_object',
      attribute_name => 'heading',
      datatype       => 'string',
      pretty_name    => 'Heading',
      pretty_plural  => 'Headings'
    ); 
    
    attr_id := acs_attribute.create_attribute (
      object_type    => 'content_keyword',
      attribute_name => 'description',
      datatype       => 'string',
      pretty_name    => 'Description',
      pretty_plural  => 'Descriptions'
    );
    

    Thus, each Subject Keyword has a heading, which is a user-readable heading for the keyword, and a description, which is a somewhat longer description of the keyword.

    The cr_item_keyword_map table (see content-create.sql) is used to relate content items to keywords:

    create table cr_item_keyword_map (
      item_id          integer
                       constraint cr_item_keyword_map_item_fk
                       references cr_items
                       constraint cr_item_keyword_map_item_nil
                       not null,
      keyword_id       integer
                       constraint cr_item_keyword_map_kw_fk
                       references cr_keywords
                       constraint cr_item_keyword_map_kw_nil
                       not null
      constraint cr_item_keyword_map_pk
      primary key (item_id, keyword_id)
    );
    

    API Access

    The API used to access and modify content keywords are outlined below. The function names are links that will take you to a more detailed description of the function and its parameters.

    Function/Procedure Purpose Description
    new Create a new Subject Keyword This is a standard new function, used to create a new Subject Keyword. If the parent id is specified, the new keword becomes a child of the parent keyword (which may now be called a Subject Category)
    delete Delete a Subject Keyword This is a standard delete function, used to delete a Subject Keyword
    get_heading
    set_heading
    get_description
    set_description
    Manipulate properties of the Keyword You must use these functions to manipulate the properties of a keyword. In the future, the data model will be updated to handle internatiolization, but the API will not change.
    item_assign
    item_unassign
    is_assigned
    Assign Keywords to Items These functions should be used to assign Subject Keywords to content items, to unassign keywords from items, and to determine whether a particular keyword is assigned to an item.

    The is_assigned function can be used to determine if a keyword matches a content item, based on the recurse parameter:

    • If recurse is set to 'none', is_assigned will return 't' if and only if there is an exact assignment of the keyword to the item.
    • If recurse is set to 'down', is_assigned will return 't' if there is an exact assignment of the keyword to the item, or if a narrower keyword is assigned to the item. For example, a query whether "Potstickers" is assigned the category "My Favorite Foods" will return 't' even if "Potstickers" is only assigned the category "Healthy".
    • If recurse is set to 'up', is_assigned will return 't' if there is an exact assignment of the keyword to the item, or if a broader Subject Category is assigned to the item. For example, a query whether "Potstickers" is assigned the category "Healthy" will return 't' even if "Potstickers" is assigned the broader category "My Favorite Foods".
    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/storage.html0000644000175000017500000001031407253523116026227 0ustar frankiefrankie

    Storing Data in the Content Repository


    This document provides an introduction to using the content repository for storing data (binary or text files) and associated attributes. It describes how to store user portraits as an example.

    Define an Item Type

    The first step towards using the content repository is to define one or more content types for the data you wish to manage.

    The basic content item includes the following attributes:

    • Title
    • Description
    • Publication or Posting Date
    • Author or Contributor
    • MIME Type
    • Binary or Text Data

    Most types of content require additional attributes. For a photo, we probably also want to store the pixel width and height at the very least:

      create table images (
        image_id       integer
                       constraint images_image_id_fk
                       references cr_revisions
                       constraint images_pk
                       primary key,
        width          integer,
        height         integer
      );

    Content types are nothing more than standard ACS Objects that inherit from content_revision:

    begin
    
     acs_object_type.create_type (
       supertype => 'content_revision',
       object_type => 'image',
       pretty_name => 'Image',
       pretty_plural => 'Images',
       table_name => 'images',
       id_column => 'image_id',
       name_method => 'acs_object.default_name'
     );
    
     acs_attribute.create_attribute (
       object_type => 'image',
       attribute_name => 'width',
       datatype => 'number',
       pretty_name => 'Width',
       pretty_plural => 'Widths'
     );
    
     acs_attribute.create_attribute (
       object_type => 'image',
       attribute_name => 'height',
       datatype => 'number',
       pretty_name => 'Height',
       pretty_plural => 'Heights'
     );
    
    end;
    /
    show errors

    Note that content types always extend content_revision, rather than content_item. This is because we want to store multiple revisions of both the actual data (in this case the image) as well as associated attributes (the width and height of the image may vary among revisions).

    Define a Relationship to a Target Object

    The content repository implements a flexible mechanism for organizing data in a hierarchical fashion in a manner similar to a file system. This would be useful if we ever decided to allow each user to manage an entire personal photo gallery rather than a single portrait.

    In the simple case where each user is allowed a single portrait, we can simply define a relationship between user and image as ACS Objects:

      acs_rel_type.create_role('user');
      acs_rel_type.create_role('portrait');
    
      acs_rel_type.create_type( rel_type => 'user_portrait_rel',
         pretty_name => 'User Portrait',
         pretty_plural => 'User Portraits',
         object_type_one => 'user',
         role_one => 'user',
         min_n_rels_one => 1,
         max_n_rels_one => 1,
         object_type_two => 'content_item',
         min_n_rels_two => 0,
         max_n_rels_two => 1
      );

    Note that the user object is related to a content_item object rather than an image object directly. Each image object represents only a single revision of a portrait. Revisions always exist in the context of an item.

    Store Objects

    Now we have defined both a content type and relationship type, we can start storing portraits. The DML for processing a new portrait upload form would look like this:

      begin transaction
        :item_id := content_item.new(:name, :item_id, sysdate, NULL,                           '[ns_conn peeraddr]'); 
        # maybe have content_revision return the LOB locator so that it can
        # be used directly with blob_dml_file
        :revision_id := content_revision.new(:title, :description, $publish_date,                               :mime_type, NULL, :text, 'content_revision', 
                                   :item_id, :revision_id);
        blob_dml_file update cr_revisions set content = empty_blob() ...
        :rel_id := acs_rel.new(...)

    Retrieve Objects

      ns_ora write_blob ...

    karlg@arsdigita.com

    Last Modified: $Id: storage.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/publish.html0000644000175000017500000001370607543727161026251 0ustar frankiefrankie Content Repository Developer Guide: Publishing Content

    Publishing Content

    Content Repository : Developer Guide

    The content repository does not place any restrictions on the methods employed for delivering content via a public server infrastructure. Applications are free to query the repository and process the data in any way desired.

    Although there are no restrictions on publishing methodology, the repository API is intended to facilitate generic template-based publication, regardless of the specific presentation layer used. The following diagram illustrates the steps typically involved in such a publication process:

    In general, there is an initial resolution step in which the server must identify the appropriate content item and then decide which template to actually parse. Following that is an execution step, during which setup tasks associated with the template are performed. Finally, the merging step combines the data and layout into a rendered page.

    Matching URLs to Content Items

    The primary mechanism for matching URLs to Content Items are virtual URL handlers, .vuh files. An explanation of virtual URL handlers can be found in the tutorial on the Request Processor.

    Here is an example index.vuh file that you can adapt to your own purposes:

    # Get the paths
    
    set the_url [ad_conn path_info]
    set the_root [ns_info pageroot]
    
    # Get the IDs
    set content_root \
      [db_string content_root "select content_item.get_root_folder from dual"]
    set template_root \
      [db_string template_root "select content_template.get_root_folder from dual"]
    
    # Serve the page
    # DRB: Note that content::init modifies the local variable the_root, which is treated
    # as though it's been passed by reference.   This requires that the redirect treat the
    # path as an absolute path within the filesystem.
    if { [content::init the_url the_root $content_root $template_root] } {
      set file "$the_root/$the_url"
      rp_internal_redirect -absolute_path $file
    } else {
      ns_returnnotfound
    }
    

    The content_root and template_root parameters select the content and template root folders. In the example, they are just the default roots that the content repository initializes on installation. If you want to store your content completely independent from that of other packages, you can initialize your own content root and pass that folder's ID on to content::init.

    To publish content through URLs that are underneath /mycontent you need to do the following:

    1. Create a directory mycontent in your server's page root and an index.vuh file in that directory.
    2. Adapt the set content_root ... and set template_root .. statements in the example above so that they are being set to the content and template root folders that you want to publish content from.
    3. Change the set the_url ... statement so that the variable the_url contains the absolute path to the content item you wish to serve from your (or the default) content root.

    If you use the example index.vuh file above unaltered for requests to my_content, a request for http://yourserver/mycontent/news/articles/42 would request the content item /news/articles/42 from the content repository on the default content root folder.

    Matching Content Items to Templates

    Querying Content

    Querying Attributes

    When you create a new content type or add an attribute to an existing content type, a view is created (or recreated) that joins the attribute tables for the entire chain of inheritance for that content type. The view always has the same name as the attribute table for the content table, with an "x" appended to distinguish it from the table itself (for example, if the attribute table for Press Releases is press_releases, then the view will be named press_releasesx. Querying this view is a convenient means of accessing any attribute associated with a content item.

    As a shortcut, the item's template may call content::get_content in its Tcl file in order to automatically retrieve the current item's attributes. The attributes will be placed in a onerow datasource called content . The template may then call template::util::array_to_vars content in order to convert the onerow datasource to local variables.

    In addition to the "x" view, the Content Repository creates an "i" view, which simplifies the creation of new revisions. The "i" view has the same name as the content table, with "i" appended at the end. You may insert into the view as if it was a normal table; the insert trigger on the view takes care of inserting the actual values into the content tables.

    Querying Additional Data

    Templates often display more than simple content attributes. Additional queries may be necessary to obtain data about related objects not described directly in attribute tables. The setup code associated with a template typically performs these queries after the initial query for any needed attributes.

    Merging Data with Templates

    Returning Output

    1. Write to the file system
    2. Service public requests directly

    karlg@arsdigita.com
    Last Modified: $Id: publish.html,v 1.3 2002/09/24 00:14:41 donb Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/organization.gif0000644000175000017500000003100307253523116027066 0ustar frankiefrankieGIF89a¸hæÿÿÿÿÿÌôôôïïïïï¿éééÝÝÝÿÌÌßß²ÿ̙￿ÌÌÌÏϦ￙Ìÿß²²¿¿™ß²†¿ï¶¶¶Ï¦¦Ï¦|¯¯Œ†²ß¿™™¿™s|¦ÏŸŸ™™™¯ŒŒ¯Œis™¿rŸiŒ¯Ÿ_}}}frr_ŸrVffooYVrfLfffLfoYYoYC__LCYo_LL_L9OO?9L_O??O?/??2/?O?22?2&&2?//&/&&/&&/  þ!ùJ,¸hÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãÂIæçèéêëìíîïðñêäõö§Iúûüýþÿ H° ¿$Ü[È“€|#JœHÑ`’ è5ÜÈ1ÒˆCŠ90 ‡ ;ª\‰è#É—0IšDɲ¦M—1sê,83¥ÍŸqîJt_O H -Ê4çѤPë-mJuäÓ¨XÁM­ÊuâÕ¬`·mÕ×Cƾ²;5ôXÛÃÆ…®þÿ¾†km¬ƒ$=ŒæÕù!I‘AüÂí'—®áhvñêÕ§ÁFY .¸hÜC„:4èû £Ç‰~}]賑䃃kE;àxʼnÏ8{~Yø°mf‰ƒ|Ø­ø’ .~ÇN‚DF¿2kÀKZõæ$ªI‘ĆŽ$Ÿ{$‘8ïò¶Ðežôy»ü²Äéò’~{{_³.°;Ðî€4ä Eøõý8cÉÐ]P]dŠÙç~âÑdÞ‚Éä¶[_yÑ7œ ¡9Ÿiôi‡Ž~~­%d‡tÞa: ’ÇàŠÂ$¶—‰\u+Txá|ùÈøO‰û\§AhË™%b:ÂT‹HîââÿbÔÙðAHH`ci8žVHèÀ¡sú\'Âu¢„¤åÕž XjiÕxI¶éË’ú(vÚqAh6%†—D[öâv9ðçu{éÉçš º©(.v 6Ðd«%¡¦NG.j©+:v='ÂP•^*j*™jú'¸)¨lŽêj+¥šêh¨¯Ö J¬²ÂE«­¼n‚k®\íÚë°–ü ,U«¬G ›k²ËFˈ±Î­´ŠÊO@.W—}‘¸ûÈ ™ä6u-¶m&‰]2èðÖÀEÔì@¼H–iùÛ*»½º{ÉX™>¨)l“uöi{¢IàB[óž Bÿ™ÕWlûjüÙ޹ÙtŸpYÆ­ 0‹{¯>+ذ#×+é+$qÄ1ê€s”÷ ùÍñ|¦-Á·CçխŒаB~)ÿ»r­-W2–ªÿØ[Áw½…ô]‘Q]ß ˜O¿üôÀ¯™2ëS„dqWgH*_½`Ö”Œµ‚Yþ¸mÙ¯…/®­ïØýƇÎ\M8Eyë]ß“Œb?A$,®o“ žþ![â§÷#x¿ïóVä‚Oî•Õ–‹Š¹$v¡5š™³&3H¢CVÄ eï†ú“ªóëŸoüF »i²KTyí‡ÝÎ,@tªýÁzÚð¦]wÿZĉÆ6ÙK›=vúèzûéówW(õ—ZI¦|pnµDMOÿ\ö{µø·ÿý,tÄ èÚ°]ïzý5¿Bp`,U×Ɉm$¨"ˆ-•6"SG³ÐNR¸Ý$UqÈIˆN+ƒùÛ_lœ¤?ý@O¸À[ öCJù#âHÀõÒð'6\„]òÇÁîæ\Dð!µ¬ÀNb¢ë>PÅÆ@ÎIQ•ÅÈ6ÄOÜ[®:Lb*t¡õÁ%R&{Œãx¹9r«à²Á?c>Ó’KÎqá?Ö¹C–d„´M‘©:"òÿƒ|Œ#Å?*Q$¼ &3i˜M&Â.ªêA%]CFÓdm.pg†2òqb‘3#Ý2ÈÉrNdeG\Ù’ äGcÌ¢ €²*ÉTæF˜yˆN6«Ô& É)=èA ̦8ÂMCÄêš1ç9Oy,u®Óí,D©²Xʈüñ›„ ç=KHÎ4‚Ò—–¨Q:Ðt’û0§~. %jöÐ9ÐÔ‡”4“QYÙ³¡âÈ'!PHD)Å06A¨Ñ‡Vƒ¦È@5.@›¹V#~­Ô£ ©MD:ˆL4”ý¥…¹Óìƒ+¸ñ€õQ~ƒ§‚hÚüáI¡BÒB”ÿÜGcthª¦:µP@£ª¸ªê‘¨æc¡>e¦æô«* «]>ÂTóun™[X#— .—t•Y¾>ƒzêê­påˆ\3HÖ‰ôùƒ§³¼šØl,V¡‡­`erYÌRPE›…âC=k-Ćö%­ºL{Úz¤Vµ¥ÕlkWòZزJ¶³]æhmÛ@Üæv›»å­‘Xû[pÔV¸1¡lqŸ±Xm9÷¹Ðî;ˆ»\°¾k A ¶ËÝîz÷»à ¯xÇKÞòšw»$ nu·V`ˆ¯|çKßúÚ÷¾øÍ¯~÷ËßùbD#ëUl&`€øÀN°‚Ìà;øÁŽ0ÿ‚à¸fB0€†7Ìá{øÃ ±ˆGLâs¸®pCªâ³¸Å~1Œ×+ã/·Æ6þ-Žs<[K÷Ç@ò;RÌãqø¹ ¢°+„Ìä&;ù ò²ÚëL$ãí¿KN€–·Ìå.{ùË`³˜ÇLæ2“9 P²´ŽkeDI0³œçLç:Û™Ë&ÁòšƒÛfù½w´ Mç$¤×·¶bsŸýœeB;úÑNB Ô›$E/zvˆ&Eœ!ÍéN×YÒ”F’¥/m¯P_bÓžNµªÁ êL¿jԤ扩-êUÛzÕ­þ3¯`ëKºZµ¾µ°9klYúk!"j¸ÿ:.®ên>Åæ¬+ìa[{ÐÅÞ3’³,••JÉÙ)å£YM›ÕÞ2ÖÍd àÁÊì \ÛÓÙŽ–¥ñc %a˜Á¢ Úr®˜òñÈ®ŽÉ­‰¥FÚ¿Eºµœ„#¬ÛÈ@X@f$áÝ÷&ö¤#n»à H‹òñ7‚¥­Jo‘^þ„£1\=Û²Î=‰‰' <Ðò6®qÀ€×2 ÚíD€I Á»+@À !t¾§Üœ‰`HjŠaÿÝž HæN÷bât¢š¶€<—„Ï.t¢›@HBÓaà@ïB€0‚ÿ,8|Öï¼õG<ùñ‡|”©ÜÀ¨ê8¹Qhn#´û{܉óΈˆƒÐÞêºs·8Ôñ¨'@ã,ˆ€ë0„!$€O ’ }Þ‹/ôÈOŸˆ$àøÈO¾ò—Ïüæ;ÿùоô§ÿ|4«9lP:™¶þÛë‘Ò’ç9o”ÒÁH?ÒÓÎIþ‰Ô¯›ö†ýëížt¨ß>÷öŸÒƒ/çÆ;ÂøÔ€8€X€Î—gÑs»~áçoºBôCC%H0&eâo«Ò%$BÄSêÓ?q‡}aFw\&°W}§e@p÷÷n‡u(Àsæÿ€¸ƒ<؃X‡vx‡Ë'‡^Ègpñ#ÌÖ]¨_Øe((† ðwGZ‚Wƒ# x@`op‡Ã×sxx‰˜èƒz(ˆ|Øk¾F|£às“hƒ›X|™xЍ€¥ˆ¼æ‰ˆÅ7вˆg•(w©x‹¸È|«x­èŠq1‚ г˜u»ht˜‹ÈˆŠÅX½è‹oÄ~ž ŒÃxoËHǘŒØˆ‡Õ8Í茂 ÓhÿmÛ(×9Žé¨€‡  `=¨ŽëØŽÔG €åÝè°ÈŠã8ŠýxŽI`éèIî %Ѓ™ €ɵˆ}莜 Žyk©‹ y| y|P9°ÇWP9‘ÇÇ1ìx|ï˜1ÐŽ/‰1°,I* “ñ.©5P2‰.™|i’H“6‰BI”°I 29}¹‘¹P¹ ’¸–‘Á¨‹>`F ò¸?‘Y5‘€Fà%—W™5 YI )*>`%˜ÿi ñ™Ey|I–kÙ–w™—{é&©˜Œ ˜I}]¹miä-©Äé.ý0SèòYF–Á7’yˆB?ÙŽ>à–Yy|Bà–?Ù˜X¹‚Yí(˜ji—Ãy—IŽ)™Îy˜»©|ép›œ}¹͉Ïé˜%IšféxÁ/óR/çÓ1ëÉ…Àèxa†²Y–Aˆ–)™,‰ŽéžÇ—ÆçŸ( ‘ æp˜Ê v©œ–ÉO5àûè”iY—ù  € J9˜ ÊŸª8žÿ·[M ³Á0—a7<ãpÄ´3“1FÓ6I³„ #K##ÿ%s2(ka© s7Ÿ¶F›ÖY’ šøh™ž‰˜Fp¤íhš¡ Ez v™ô¡5à¡})˜é”DÊ¡uù¤Š¥ ¥\Ê• šƒ øS›A3"`3>“3;˜ñ3R"4Dã12ê1KC!Ža!C: 5!Xj=š ?z{€8Ð,€tZÖGÇMo8`©Iרò¤[&¤` n‰•1À–[ ™‘ P„iB™*þÉ”ƒ‰ 5x™–?i¤ JFÀ—C*ª°ª­J¹ »ê˜B@â„»UIüà5“:S8e³^“6ƒÓž«7û07`DÿâRe2ôžÿW‚'u80,„—< u#Àz p(àyoG0îºó ªÈ× €‘{y™ñx™þ™ø¸B`°gªF•,© þ¹¥ P˜ù٠ىŸyž{• ëEy±Û’ù¡ÎjšýÐ:CDù>dÓè€8Ûº8Ýêo?у¨ lèús½ç®ZÆ| 04°ˆqFÀLjžúsk:‡;¨±·˜›Ù˜‡S»‡*K…!Ø9…Š0H:¦1:æ7DÇc³oã,XÕ1;k暃?»i†D›ÀGз·¯éµËᙊ àŸÐ™ÿµÖ¹µ‚Ødñlz½c¿se+<ÄS0Ƴ­æÇžËƒÍ#1ª;ä‘']u«ew;´±w€u<( ˆ Ðq†—êt„븦h€%Ÿ·È”Â˸뻬\ÙóÁ=#â=d#:C>+—:wÃ>˜» Ø>~ñ>¥ =§ûŠs;‡«ûzx«†C€u—†go»ç{@Ð{‘Ú»õi¼öûƒÈË‹|hD_¼X¾­{{ÇwI©óöˆ}·i‰t’¤…{¿¬¦)ë2_)·‰Š cYf·ˆ¶µ^öÀ˜¿Æè•ì¿ÆÈiõ ,À®üÁ$ÌŒ"<ÃÑWÿš\Á"4¾^Øi€íúÂ0\¿4<ÄZ;ÁZSeѦÑæA/9o–=+q@LŽ1lD|ÅNYÅÜȇ)”šP’$SµEåzÁ§6f¶»jiÌe{ŽÖ>ü†”(ÄÊW «•ȬӧÇÇ7”öØ|‡ÛŸØhÃG\Dµ<¤C’DBÁ¿eMaD„L:,ˆc|[毎¦É„r‚6(Ф|ƒZlŽÌ‡”‰zIšÔ'«Ê—  –jÙ|×xŽÊxÊþhrd¤‰¬QZÄEè×_FAETFh4IY5kUÆQ >—q üzR—Õœ WA+ÿfÔÜe À¾Ú,uœÌưÆT÷·RfD›Ó1½e£,Êr<Çy °¸mýÜÊ~ ‘‰÷ì · ® F«1œ|]ÔG-—gj `'ÉFM˜rYª_*Ñé̇=‹”G£ÄÑeÕBoGI{Ò"Ý ÂÈÉzý†z{¯÷n;ÍeþšÆ?,hDp,ÿ|tÜ’[™|1Ÿëì˜_šÕÆÙÇ÷Øà– ËXFúØÇÙÆ·‹ëÙ Ù¼™¤w8Ñ™SшôI¯­G¤¤A|ôÑa×wÍ yÝeœL:=oWνɂ½eåüe: ¸_v¯¬ ÊeV¸ p˜Ë—Õ ­ƒ”¡éà’ái|œ|ÔíÝm|Ƨ”«Ÿèà˜™ÈÚ¸“A±4K2eK2€Kº„6n!­Ì|LŒ¡ÌÄ$Ç®¨{ɱ(fzÍÛ½WÜÂ=fƒ½ÉÎmg‰í{ÔÑlÅÊÇš|>àÎÌŠ—èÝŸ¼*Kz—ºÝ!Ë}|ÆÚMj|Ñ}|ê zܘ¸,‘iÝÿµ·=MThã/DƒÂÌfD‹tû‡ü ïF©üÊB.o'N‹Ó‘ ¸5Í4@~g#@´» á–8ÝÒ ¹N1ÖÍ«í(û¸Îj)â„IâÊæ æd~—BðÙ£}áFÉ é=ã7ŒÃ¹½ ¬e?=è?hã\å‹÷ÀBàè Û’»“ŽŽFZ—¸‘Ým|ð›X]â’þœí€а€9êðXéÚÈç…ÜòtNéà9ÅÂÂw •‰ÅY«Þ×3’±ŽNÄãÖ(lã¬Íʾàãˆë¼Á’dÈOÿÀÄ‹fìܨÁ‚–ìËÎÿì$MŠéüìWìë÷C®.ìB^¼~dF©`ÖÆŠþhK‹ÓÞ.r‹-î!Lîdîü ã›!ÉÔDZ¥:nR»î°‰×dæÆ`vÜvØI+àf6Üc†ë]ž‰|LyÖxh•  Ú0òÕçê-Sµ5õˆ ¨&d"BRToMneÆ´Öð\–èÆMÎ…ÞÀÜ|»ìKô׬èI7Î qr{„.Ó[6ÎG‚óÞe¸^¼FéŽÍWËxø’M‰|%ç[öù|òFœòñSI¤E5C¥Q0×@UO´þ¿bƯÆMä#|'Ý®ðw»4°Ò4€u ˆãÌÿqR¯ÍUÞÆ“Z»í ’ˆx3ý†0À¯ŸøEoòºÆAÔ̇ºž|Ȫ–»Îõ ÀИ¢®| ¿ëgŠ«\‰±ÏÔ3É’´/XŸÅgßÚ±ò0C!Cðq}U]üë¾Z:OmcVï[–q˺û·´,À×I·ÖÿeWgÜѯe¶[ÎÊ„ÝeiœYnõá¾| Ÿñ£úkÀމ %ÀªÍúñ4ù’¬Ú|JÙÿõ/}€@(HP`H˜xèÔ±0`y‰™‰™¤Ùéy9ä0JJ*Sêp:ªúábêà"1*á ;[k‹ª»ËÛëKš4YùI\l|™”ÿ ¼Ì<’ÁŒÂ’‘A£<½Ì’­¼­ÍÍœápÝ}^þLîMþ ®)|¬™ôèØx˜ÏH@H˜Èо{ˆ©Ð7ˆ B‚96dph‘¢„%t$½Lœ6z Åëà T2DˆÑãÄ6\|°¡Á&mÈr°BÄ ”V™”qá—С½‚iôˆÔX2xË`„sª joNY4PÖ`Û¶¬ï°]]FmY5w×<<‹Ú5Ôr˜Æ“t©=…Æ(·Ä†Šƒ.>Ú—Oâß¼x.”Á‚>EŠ-Ì8LnRM w©Bõ!&ª nŽÒ ™h]z=ÚÑÈ“[or[nÄÿS`ð i4*$h@ƒ6¯(<Œ°}m~¯µ†b÷pm<2ä¦Ñ†³ÞM—7¯@#ÃqØ OžK°î_'4¼ï #Іë+ÜhÄ÷úÃe½QG®PYjˆà« È K1õX¾…A_)SÁ„Ëd9  Ð3’'ÎY"šhMˆ°™—zø”Ca„€°* B€ 5–@c5Æ€@ {¥£Œ ÄA 1i_“Ž  ä]ìÀ%4F¥•XÄ¢d ˜`˜bŽ9Ê‚ ºö ‰j®Éf8  €‚†mÎÉT—¹hôsˆž|:¹L h¡ÿ†Ögg€ ‚If£Žeæ™çÑIi¥Ì40œ–Ò™(=x j¨¢ŽjX§Ç裮Ê*0óH:馲ÎJ«š¦*Ej}‚ Â+}¹þê­Å Úšª­Ûh¤°ÞYk³ÎÖ*,1Ÿ>B(¨»öê+°Úí'ÄNf,²â&¨ì²ž>‹nºsvëÉ´‡ä¸m¼òÊn'ß&î¸ú¢V®¹J© pÀuþw|Õ΋p‡Ô[Ï¢¢ì ±‚¯ú{®ÀÌ0Gð)Ì1ÇoâpÄ"ó;1Åÿ^Œ2º#³P¿<ïÊ–Ü‹T(IÜŒsÎ:ïÌsÏ>ÿ tÐBë\²ÉÒ¦Œt³2;¸P 0?½íÒÿ4{4ÀÐBÖZoÍu×^ vØbMvÖ$mt»C¯ÍvÛn¿­3Á-*ä2Ôv“*uƒ0~ÿ xà‚Nxᆎxâ€O`€iSõÕeONyå–_n6Ú§*$ßÝžƒš÷¢,@z馟ŽzꪯÎz뮿nº>ÞÉÞ}+Ž{îºïÎûߌ;>÷= ùyñÜÊí%ƒ`@óÎ?}ôÒOO}õÖ_ýóO;1Œ{øâO~ù¥ËÞÚ´Ï>¢ÈßÙ}üòÏŸÔòÙßþúï¯=÷rµÀC…Ž~, ˆ@Ú¹+€ ¼ÇÁJp‚\`/‰÷)Šÿ‚ì ?¸, b¡ OˆÂŠp„,a _Ãp…,dŸ eˆÃêV4¬añn¸Ã qˆÒòa HÄ$*q‡=4âݸÄ(Jñ„p«¢¯ˆEžiÐSSì¢O9¬anŒd,£3ø}qlŒ ízÇ8ÊqŽûÝyÚˆÇ<ð{æë£ÿÈÓ¡ïŽz,¤!Mf?þ)r‘ŒldÿÒwÈHJr’L¤¤%/‰IN-“œì¤'CøÉPŠr”h"¥)O‰Jޤr•¬üä&[™À,Êr–³€ÿ`IÀWâr†#ë%‚’°€Aî’~º&1}‰L’Ùјò+&3ã÷°dJÓIÿ8[Ÿ™6gbóqÑœ¦7Q±´m&Oœ¼ü¦9±Er‚Rå<§9ÃÉN¥Ä³€Ýtç4á9Ooåó˜öü&>÷Ù0€B³ŸþL§@ yPnÔ›ÿL¨ƒªP^ô`¢=Ði¥”å= ÄšPmBôU•ºÜ$—¢=±²·ÚÕˆ`ª'*²“ëYËšAb^ÁPIƒc£:µýÕm°ÕkÑäõ:~ lýãQ0;Ù'X¬Kl°SJ;µ"¸1ŠËlæÿDï’Öºp¥GaƒÛZ5)·(ŽpÓ¶LDeõ¼_}‚o; ?ývN¬êTg¸Ç%Á<]RÌ›âÑt8ds濊âÕËvu¾¹kpy›&äD9ô6KË“—B'Er}b«Få=…‚€ëŠCê5—ú .ÖZ¬œç9fÞJ¡/û2øöêÑg2Ô–7]E«­K#s¢B½ê!Ö*\ל·šâظ–ÁÎJ±“B=(Bá;Š»VjW¯n3šãøÆ}±Eß;åŒdÜê}ëÿ¾&šÏ¬íÿ‚3àm´‚¼ŽVÀ¯Rð¦g•ϱ©úT²¾õ¾õ{˜EMËÜëÿÞg·'šh?®×?sÑNô˜0[$ê_¤œUË×*XɤW Ÿ™n@‹ºe"_ô¾ˆwâWåý§Æ4A.hþ/¦?h‡a?aýâ"÷k™§Ú 4-Íg4p Œ3ñ/…Nkbr_%}¨gSn ë‡0íWSï§ œ1]/A³P'!µ.0‡k6t8¼`p#ȤUh{X¦~ (/ (O¸ –&ƒ7A ¶`%h‚¥p.!&7ˆ‚ž÷yx},è$.8,É7i¨`i-1‚#_=ƒß—ƒµ‰G‚8È„+'r)i_2„DhF(-HèRJ¨„ö}>˜ÿ„¯xUx QÈ è§h+†À"†úƒ¥`p\… +`Z&2`ZbÅQ¦e+~&8Uz§ xˆc2UnXHSBX‡Úr‡Á•‡B¡¬%ž(&ÿ‡†qF‰#e‰ á5-—è@\h/d|­"‡G‡FÐ7s0¬h‹®Pܦ/ÿWÃ(‰ïTŠuŠ”„°IPPÂ5à4P>RÕXû± rA™øŠ›ø€a"ŒÄXŒ£0Š#3‹&W‹±ŒÐŒ%·˜9ÀõΈIà%`F@ÍX*P,Ž¿8 ªÆc½¤q^Uz¼p‰øƒ³ÿ„í¸0¸˜·ˆó(ýýàB0>P#ìQIP°'鋪$Žz˜Žã"O“"8&ëtI·È1‘9ùx39@à8³> t. Œ¿P œÑ^%ŠíåØ#6x§5Š-UWyÿÇ^˜ ZuZ@ÖœQ“ªqŒ•Œ¶øŽጄPIà ÀP—Q%I¹ŠíÓ” ó’@®F¸€· àãZµ Sºû)™´žkrëö ºIû¹Öª­“‘HŽ„»¹ËHÛ3ÿ¹NY¹ Ñ91°Œ ¹°$ŸÛ´ý   µ"é·TK³ë+Ä‹Æë4N+’Cɵš‹Ë(BK¹½;¡EKBp¾FÉêÙÈ;u‰ ‘F|Û®B€¹ ›-þ(›ý0àž¹¾õß[»âÛf3º‘û¡ªY„À«I¾ªÚ$àûP<¾’€<ÁlÁˆ–ª¡JÁ±×Á—¨0·ñrÂPr³…bòˆ(<ÂÃ'K†AŸï¡-5 ( à“Ìû0ÕÁ÷°Àç‰$ÀÀîA% €ì¡ÃZ‹Ä (ùĆb«Ùº¸‰& ËÅ\lKAŒÁëG¼ÿ9b  ¿V‚$W<ÆŽp$I‚$tAW\/«¸C«©Üv È,ȃLÈ…lȇŒÈ‰¬È‰ L’ Æ1ÄéÑøÀ'ÿÀ6L¿2<8Œ@|*‹,Ê£LÊ¥lÊ mûÈôÉ÷ Žpy±Ñõ9lÇ„Ñ$x¢vÊ¿ ÌÁLÊÕtªÜÊ“¼øp0´ŒÉ’|ã£B(',ªYì»h"ÌÙ¬ÍÛ|]:RÇÌE’4b#8¢#IÒ#?$žL¸1Òs%+¼Ëx¡IL¶|¬³ ÉÍûÌÏ£ìÍΆá'r¼’¹2ÅPÓË-ÖÏ ÍЄüÏÿÐŒ©øl¶úÜÐÍÐP ,×R­$ÊJÑ#ÍÏ}P-»¢âѼbò/ íÇ$-ÓÙlÒ…Òðb7û20mÑ3íÓ§\Ó…ÒÏh7Ãó4<Í…¼K½Ô/ Jý ­3 žD2Ôû4ÔI;zò.ƒB%"PL„2ÅËŒÐ!=,†|‹KýI°… × ýÖ3;Q=ÒYO]7A¢jÜ‚¢*ÐÂíj؂͌5b%y<<:­µxÜ‚j--l×üÖŒ7°!ðÇs}›ÝÙü3°7@K=OÚœíÙIpÕŒ×ð)@ÿ¦]Û p×3ðÂÌ×óÄÑÍ8 ºR•Ü*0%SB­)MkœÖÖœ==ÈIð€`Dp×3@ÛÝ×â½ä}Õ?`Õß}³}/0×è­Þ|IÜÜI`p‹/ðÖž}FðD`®ýËÃO]7Ž‘Ì˜Ëx1$ ·õ|«#ã*Ù“mÝo›Ô3DÚäýÔìmÞ@â`â ð@Ip)7ÐðÔ)n‌×ìß)àß3Ú´ýy}ûÛ Þ°nÑK©I›€±‹Ä#R®cÛ1H>l½Ý÷Ûx3'îå8sòMÿ o}3Qæ7ÈxàûíãåÝãþ3µäÅlÁmÔø ›*ÐIâÎþpÎ×Ã^ìš¾ß0.ß/€·ìF°é€¬ÿØß2׫¾êÞT=éÀ ëê„ÒãŠ$¼Î‚X~À>æåêù© Úí®Ý©-ßD ß6þUÛòþî‚L/~3;ðÔÚ^Þ€×.ÜIþyãÎÕ`ÿ¨èÞ"?]ʪžß$îäÄð ñr!ñïÏ f/Á'oòŒ òf&ò ìëörò//×)¯e+Â-_0ó¨,óSFó—Jò’óAñâÔóŽúóžô9?ôÛTôoó‘ô8¿ôØd3]lõVôô›õ0?õÏF@ öaß5B I ­ÔL}ß®ÍL½Ô&`È—ýÓ]ÏLo´¶uo÷ƒ£ÊÓÍÝFPñÂÝ÷ðv.È0.ñrÏL|¹ïø©ãÈz݇È/Ðí7€Û¼íÚwÚìù©Ê<~Ù¢Ûˆ_Ú;®ÝœÝÚáÍÙ½ýÛ¿ÈŠoL·«ÿ»¹¯ûÐûe¿÷ÙÈ3Ðßü `Õ`Úï½Ý& ìËÞ£ÿÇS ä`!€…ßÍf~üÉFPã7äDÐß? àio>Ì;¿Êž´hlï?D ×¯Ú@þÇDð&°©ÜúÏÿ‡I‚I3 3!DI!3ŠDŠ!;F! ‹Šˆ“¥¦¦I- ®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃıIŧŠI)Íž›)ƒ‚ 7ID)ØÚÜ¥É!?†;ÕÔÕ×3?Ú›!DI7èàÊú©«­Åÿ H° ÁƒµŽK¦Œá¤hŠÿL¼˜JÅF(XT€‘B¸I/$¸Ñ¢£MΘá"( 7êý0©¯&?VsêÜɳ§Ož ‡9Du â"#˜0Q°² M<ý¨H*¦q Rlzô)´¥7L,ú±£«G7(‰e„©fCU8ÊK·®]A… ¥ZÊèóˆ”TpΈXÂI }(*…‘$;<&¬­$…À/a„ü²p>·¨àú»Kº´éÓ¨óÛ ºµë×°cǾ9µíÛ¸sT ŒµìßÀƒ w$Z·ñãÈ“C6¼¹óç6‹+ŸN½z]Þ¿|CßÎý5mëàË'ˆÝ—vE»›JoêA PÃ14ûÿì]úøûøóç*ßë<$Sô9—ˆ2´%\€°}§ß‚ .È/Ú]âÑC38¡"*B–@ã–„¦(€Á%‡`}ý4¨âŠà=¸K„°M…L¨À tð‚ì`B ž¸HŒ¥@%_…úÌ7_M)ühB9 ÚÇâ”Tâæ¢.þѧe9 pÃM†B*ò{)”| ˆ5›”U¶éæu̹¥¥)3(™È—˜„9M)ùd¨Œ’͸¦ç) ¾iè¡@¡£è¢Œ‚6'ŸðM‚çžr–B¦™¿•ÔŒ®Šè§ Þ¦]3;Q1br#ªMj‚ê ò§V¦ $¬ÃuÐL!²yê¯ÀÿÒåŸ2ö@y@±Ï‰©z(Æì³Ðî4,³Ôrçk´Øfûϴ͉Xà·˜Vܵږk.„®-û›·à†Ûž¸­‘{î¼ôÊ2ìð*#R¾û°Yï¿ÿû¿} H0¡þ¬°¹+rɱ*{,”~RtM¤ÊªK߆= ¢±È:'ïÂ$Cëª×‚ކˆøŽÜܘ㎙ ú#†&`I)îMÂT޼bðCÎ4Oƒê  7rÉL‡êß¾Ó´…¯";@™—à¼|9;l©ÕX£‡áUr ÜÒM§mèy(KʧۓÔ9߀i¾|a)¼`pÏp‹é74y*rÂjþæyœ¦0 ß”ÿŠ©îbC~™Æ^]8àd¨³µ„îù”ÚmÎg/gN+8«Ê§&¬xC™¤WÅéÏðªÕˆ+e•óÎÍ¡ýùïúigö “„ìðˆ¥ˆx¡ ›´>—4ÿ›ïÀW/·‹T(ýÁüRoý÷ÔaOâöÜÃë=øè‡}ù쇖búð‡·~ûôŸÿý¦ÍO?ûöãïÿuû `¼:÷¿’F$Xÿ È@¼$ð{_'xFYð‚Ì 7ÈA ‚ ÌÉÀ´à„(L¡ WȺð…0Œ¡ _H †ð†<€&Àúð‡@ ¢‡HÄ"ñˆH<â :‘'`0À¦HÅ*ZñŠXÌ¢·ÈÅ.z±‹¨ÍÇXÀhL£×ÈÆ6ºñpŒ£ç(Ç4‘ŒxÌ£÷ÈÇ>úñ€ ¤ IÈBòˆL¤"ÉÈF:ò‘Œ¤$'ª@;openacs-5.7.0/packages/acs-content-repository/www/doc/guide/article.gif0000644000175000017500000000556607253523116026024 0ustar frankiefrankieGIF89aæÕÿÿÿÿÿÌïï¿ßß²ÏϦ™Ìÿ¿¿™¿ï¯¯Œ†²ß|¦ÏŸŸs™¿f™ÌriŒ¯f_ŸVrooYLf__LCYoOO?9L_??2/?O&2?//&&/ þ!ù#,æÿ@€pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|NW7îø¼~Ïïûÿ€‚ƒ„ T…ˆ‰Š‹Œ‡‘’““–—˜~• žŸ ¡¢£¤¥¦§¨©£y›ª®¯°±²«x­³·¸¹·¬Syº¿ÀÁ¢¼R¾ÂÇÈ»µ½xÉÎÏ©ÄQÆÐÕÖžÒPÔ×ÜÎÙOÛÝâÁßNáãè¸åMçéî°ëLí õö÷øùúûüýþÿþNÅ[2ïÀƒ*<(pY±f¦JœH1 ©J zªÈ±ãĆwl•òH²¤ÅR“hìd²¥Ëz 1»sê¥M’1E’ºÉ³bÎÿ™œ"öªðçCšB‰*ýgtÄ‘K£òkªíéN©XñQguTÖ¯0/:tŠ*X¬[Íuu6kZvkCù`ÀÀ€¶éÞÝ÷V^\zûpAX„ d°AÄb“C˜*6$Кú€Á"@ì]H€°½&˜40XÄd¾•e jŸÓö@;°7À„ð!ðŒ ž„ ¦‹ØÞpÅí°{ü÷¾ „7¿Ö×—à_ƒ™7sp` ߄¡oM˜ƒ€Û…7~LtáÃõ2ˆ¸°¹½¾ (æe(UUYWéƒ@„e¡•·@hÁaç^d"Lp\rˆÍÿ€f"T €Øœ~ HHXs÷€~ÛåÓ]FßmÔèGØdìWk"¨·Yt4cŽ€œ÷èöb†ö$ÇŒ’’+y÷4“è퀔¶á€‡ÚC%•õù߀°hÙl˜™g˜‹L(BØ©V.‚¦^d0Ù‘õx8¡‰Æ ùävnæÃ&w±éä•>læÁ`%|Pbp^.€À`ªÁ‡@qiÆÁª®æç˜"”·Ï¤2VzYRùX~æÉ ~‰¢'b=ì™ä‡žvì£QÖ:嬹Ê)Y´%¸Ï{Êé3‹öp‹çŸvm[׸.ͨÿR,ᕺX²«¥»KÁ{D–ôÖ«+¼æË“½FàëïP!ðÀÿî‹mÛT07üÒÃCD,qK añÅ%e ÀÆ{ä1È!s4²¼%c¬ðÙ^š2N+s… Ë/wtòÌlÕ,rÌjá,—Î6ó —ÏïÊ•÷ÊkôÒŸ °ÒL3í´ÁPGmôÔWmõ;XW¬õÖét­ñ×`#öÇd—ÝÍÙYªíÛi»m ÜDƒ´OBûU·wStsË9÷ýQÞÞíÝ®àýÍ0â )Þ/ã N£áóBÞ¸äëRnyQ˜Ç«ùæ9^è'Yi Ì€ÿL:S'ýùê¥Ó2çÂÃ^ÿ­é³³¼¸í·Ë~­îµónèÚbZ×hÓekœ¸ÿŽúîÒ±g¸¤=¦¬õ  czÌûniàø€ØÙg¡!ŸPi{ÖƒZ°•Øi¤Ã·þôëe¦_“õôöºÏE·a­Ëé–sˆsé  :ƒ’”¢#JYë{ª Ÿx¸„óüjP*Œ{àÓ ëÕ£>è!–~ø£ÁÊ̓ `Ä Ç<(By¢Ÿ83"Tý¯[‘ˆH$C©HÔÇ…º7ŒÓõ,u+Ü޶Ç#Õe0BZ`þŒd&-©I"Ø~‚¿p¹ ]ñ{à®F' ëKÛCÏdºˆ(¦IV“™T ˜ý€ÿ1Œ)cñìqàIO3  î¤?ŠPULÒ¢\¢âÈQZøÈTˆbWÄÜ=/x’ÜÔû>µ#QɰT§âäYµ,WÁŠ3pŒÖòÔ&jáÑ{z¤>|•`-`X,jLaž•¬4ñp—.zä*0€Vº2,bäÃW— ÒQ€-:—mÊ•iÞ„x²Þ=° >mnS~T£Ÿ7_YIçzÞäfljÌ<*sãTgÙyÚžõgÖÄÉN{ò Ÿþ<@õé5~Æ“ c3h:Š6…j3 •h2i·Ì…Nx}(CÛ&7³qhHì(×>ª·Š4l$-œIOêQKž“¥ÿRKéäV SnЦ5›L3‡ÓœBã¦èÔèE/™QáAŸä Pƒ'TwRžu*F¡ÚTX¾3›êK‹Ê»£"5ŸZiPºQ”}Õ«HE«D¥JTª’5¬%kWËêÐü/eÌé‡Zg)=bMD1HÂG´§Ag‚•­[…ªø<ÑüÕLë+‰û#ؤ‚b©mcðGLßG8ürHLh ¤Žg÷ ”G³ß„«JÑ)>3ò= À ô6ˆù, „÷iÎÄ~‰}±E¬X™º Þ¾0E1d”…j˜¡v(I:Ѩž]=¶˜4$¢Rwê9šúc‰…iÿ¢kŸXHG“Šö³¢a°¨E(µ ’ùx—î¸×2®ÒK` Óñk6¢iY©¦?³›Þ•S…÷¼Gÿhš>8P…$Ô! ¬H~ÈQ ¾Ç³Î&תOÅ*15Å)O¥ª“Û%ª9JÀ”¡,.´î;Ì(2_;QÞqÀ°^Ђ‡âܳ…ãE`öÞâõâ†~>s¹?ÞÚ×ûìù.‹k›ãÃ÷DÜwo}õcâ}/zâžuŒoÿûò§{ý Ó\˜Ÿ·p¢0um×~F‡qчr—{çr(wÀ€àr“ËÆ| å|É   t¤ äg  ÿWmÖf …$˜i)(‚&ÈQ+¨ #ø‚%ƒ0Ø‚qCƒãe{€†ƒ¢—b< 1øƒ9Èt;(„@hƒ”c„ÆS™Ð„N ›ð„R8…„…Tx…X¨V˜…\H…uð…`†b8†dX†fx†h˜†j¸†l؆nø†p‡r8‡W;openacs-5.7.0/packages/acs-content-repository/www/doc/guide/access-control.html0000644000175000017500000000013207253523116027477 0ustar frankiefrankie

    Last Modified: $Id: access-control.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/items.html0000644000175000017500000000424107253523116025706 0ustar frankiefrankie Content Repository Developer Guide: Creating Content Items

    Creating Content Items

    Content Repository : Developer Guide

    Use the Content Item API to create the item

    Content items are initialized using the content_item.new function. A name is the only parameter required to create an item:

    item_id := content_item.new( name => 'my_item' );

    The name represents the tail of the URL for that content item. In most cases you will want to create items in a particular context with the repository hierarchy:

    item_id := content_item.new(
       name      => 'my_item', 
       parent_id => :parent_id
    );

    The parent ID must be another content item, or a subclass of content item such as a folder.

    The content_item.new function accepts a number of other optional parameters. The standard creation_date, creation_user and creation_ip should be specified for auditing purposes. You can also create the initial revision and publish text items in a single step:

    item_id := content_item.new(
       name      => 'my_item', 
       parent_id => :parent_id,
       title     => 'My Item',
       text      => 'Once upon a time Goldilocks crossed the street.  
                     Here comes a car...uh oh!  The End',
       is_live   => 't'
    );

    If either the title or text are not null, the function will create the first revision of the item. It will also mark the item as live if the is_live parameter is true. The alternative to this one step method is to create a content item and then add a revision using the Content Revision API.

    Publishing a content item

    If a content item has at least one revision, then it can be published by calling the content_item.set_live_revision procedure, which takes as input a revision_id:

    content_item.set_live_revision( revision_id => :revision_id );

    karlg@arsdigita.com

    Last Modified: $Id: items.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/convert.html0000644000175000017500000000443207253523116026247 0ustar frankiefrankie Content Repository Developer Guide: HTML Conversion

    Converting Binary Documents to HTML

    Content Repository : Developer Guide

    The content repository uses the INSO libraries included with Intermedia to support conversion of binary files such as Microsoft Word documents to HTML. This document describes how to make this conversion be part of the item creation or editing process, such that the content is always stored in the repository as HTML.

    Note: Because temporary tables and LOB storage are used during the conversion process, the entire process described here must be performed within the context of a single transaction.

    Create the Revision

    The first step is to create the revision that will be associated with the converted document, and obtain the corresponding ID. The content column for the revision must be initialized with an empty blob object:

    revision_id := content_revision.new(item_id => :item_id,
                                        revision_id => :revision_id,
                                        data => empty_blob(),
                                        title => 'My Word Document',
                                        ...);
    

    Uploading Binary Files

    The next step in the process is to upload the binary file into the temporary table cr_doc_filter. This may be done using any standard technique for uploading a binary file, such as an image. The temporary table has only two columns; one is a BLOB to store the document itself, and one is the revision ID.

    Converting the Document

    Once the revision has been created and the file has been uploaded, the file may be converted to HTML and written into the empty blob associated with the revision. This is done with the to_html procedure in the content_revision package:

    begin
      content_revision.to_html(:revision_id);
    end;
    /
    

    Once the transaction is committed, the uploaded document is automatically deleted from the cr_doc_filter table.


    karlg@arsdigita.com
    Last Modified: $Id: convert.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/file-system.html0000644000175000017500000001423707253523116027034 0ustar frankiefrankie Content Repository Developer Guide: Organizing Content Items

    Organizing Content Items

    ACS Documentation : Content Repository : Developer Guide

    The content repository organizes content items in a hierarchical structure similar to a file system. You manage content items in the repository using the same basic operations as in a file system:

    • A freshly installed content repository consists of a single "root" folder (analogous to the root directory / in UNIX or an empty partition in Windows or MacOS).
    • You organize items by creating subfolders under the root.
    • You can move or copy items from one folder to another.
    • You can create "links" or "shortcuts" for items to make them accessible from within other directories.
    • Each item has a "file name" and an absolute "path" that is determined by its location on a particular branch of the repository tree. For example, the path to an item named widget in the folder products would be /products/widget.

    The content repository adds an additional twist to a traditional filesystem: any content item, not just a folder, may serve as a container for any number of other content items. For example, imagine a book consisting of a preface, a number of chapters and a bibliography (which in turn may have any number of entries). The book itself is a content item, in that it has attributes (publisher, ISBN number, publication date, synopsis, etc.) associated with it. It also is the logical container for all its components.

    It is important to note that folders are simply a special subtype of content item. The content repository's representation of a parent-child relationship between a folder and the items it contains is no different from the relationship between a book and its chapters. Folders may be thought of simply as generic containers for grouping items that are not necessarily part of a greater whole.

    An Example

    Consider a simple repository structure with the following contents:

    Note the following:

    • The root folder of the content repository has a special ID which is returned by the function content_item.get_root_folder.
    • Regular content items such as index and about may be stored directly under the root folder.
    • The "About Us" page has a photo as a child item. Note that the path to the photo is /about/photo. Internally, the photo's parent_id (in the cr_items table) is set to the item_id of the "About Us" page.
    • The "Press" folder contains two items. Internally, the parent_id of the "Press Index" and "Release One" items are set to the item_id of the "Press" folder.

    Note that the same effective organization could have been achieved by creating the "Press Index" item under the root, and having press releases as its children. Using the folder approach may have the following advantages:

    • Content management systems can take advantage of the folder structure to implement an intuitive user interface analagous to familiar desktop tools (Windows Explorer, MacOS Finder, etc.).
    • You can use the content repository API to constraint the type of content that a folder may contain (except for the index page). For example, it is possible to limit the contents of the "Press" folder to items of type "Press Release." See the Content Folder API for more details.

    Using your own root

    By default, the content repository has one root folder for content items and one for templates. In some situations, that is not enough. For example, a package that can be instantiated several times might wish to store the content for each instance in its own content root. Creating your own content (and template) root also has the advantage that you will not accidentally access another package's content nor will another package access your content. Not that that could do any harm, because you have secured all your content through appropriate permissions.

    We only talk about creating content roots from here on — creating template roots is completely analogous. You create your own content root by calling content_folder.new in PL/SQL:

    declare
      v_my_content_root integer;
    begin
      v_my_content_root := content_folder.new(
         name => 'my_root', 
         label => 'My Root', 
         parent_id => 0
      );
      -- Store v_my_content_root in a safe place
    end;
    / 

    The important point is that you have to pass in 0 for the parent_id. This parent_id is special in that it indicates folders with no parent.

    The content repository does not keep track of who created what root folders. You have to do that yourself. In the above example, you need to store the value v_my_content_root somewhere, for example a table that is specific for your package, otherwise you won't have a reliable way of accessing your new content root.

    With multiple content roots, there can be many items with item_path '/news/article' and you need to tell the content repository which root you are talking about. For example, to retrieve content through content_item.get_id, you pass the id of your content root as the root_folder_id parameter to specify the content root under which the item_path should be resolved.


    karlg@arsdigita.com
    Last Modified: $Id: file-system.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/revisions.html0000644000175000017500000001206307253523116026607 0ustar frankiefrankie Content Repository Developer Guide: Creating Content Revisions

    Creating Content Revisions

    ACS Documentation : Content Repository : Developer Guide

    At a basic level, creating a new revision of a content item involves the following steps:

    1. Insert a row in the acs_objects table to create the object.
    2. Insert a corresponding row in the cr_revisions table with the basic attributes for the revision.
    3. Write the content data into the content BLOB column of the cr_revisions table.
    4. Insert a corresponding row into the attribute table of each ancestor of the content type of the item. This is not applicable if the content type is Basic Item or an immediate subtype thereof.
    5. Insert a corresponding row into the attribute table of the content type of the item. This is not applicable if the content type is Basic Item.

    Use the Content Revision API to create a revision

    Content revisions are initialized using the content_revision.new function. The only parameters required to create the revision are a title, a content item ID, and some text:

    revision_id := content_revision.new( 
        title   => 'A Revision',
        item_id => :item_id,
        text    => 'Once upon a time Goldilocks crossed the street.
                    Here comes a car...uh oh!  The End'
    );

    The item_id parameter is ID of the content item with which the revision is associated.

    The content_item.new function accepts a number of other optional parameters: description, mime_type, and publish_date. The standard creation_date, creation_user, and creation_ip should be specified for auditing purposes. Instead of the text parameter, this function can be called with a data parameter, in which data is a blob:

    revision_id := content_revision.new(
        title         => 'A Revision',
        description   => 'A Description of a revision',
        mime_type     => 'text/html',
        publish_date  => to_date('Jan 22, 2000','Mon DD, YYYY'),
        item_id       => :item_id,
        data          => :blob_of_content,
        creation_date => sysdate,
        creation_user => :user_id,
        creation_ip   => :ip_address
    );

    Insert additional attributes

    Given that there is no way (AFAIK) to pass variable parameters to a PL/SQL function, there is no way to make content_revision.new generic enough to support submission of the attributes for all different content types. This leaves you with three alternatives:

    1. Call content_revision.new followed by manual DML statements to write data into the content BLOB and insert attributes.
    2. Write a PL/SQL package for each of your content types, which encapsulates the above code.
    3. Create revisions by inserting into the attribute view for each content type.

    The last option is made possible by an instead of insert trigger on the attribute view for each content type. (An attribute view joins together the storage tables for the ancestors of each content type, including acs_objects and cr_revisions). Normally it is not possible to insert into a view. Oracle allows you to create an instead of trigger for a view, however, which intercepts the DML statement and allows you to execute an arbitrary block of PL/SQL instead. The code to create or replace the trigger is automatically generated and executed with each call to content_type.create_attribute. The trigger makes it possible to create complete revisions with a single insert statement:

    insert into cr_revisionsx (
      item_id, revision_id, title
    ) values (
      18, 19, 'All About Revisions'
    );

    Because a special trigger is generated for each content type that includes insert statements for all inherited tables, revisions with extended attributes may be created in the same fashion:

    insert into cr_imagesx (
      item_id, revision_id, title, height, width
    ) values (
      18, 19, 'A Nice Drawing', 300, 400
    );

    Inserting content via file or text upload

    Selecting a live revision

    The live revision of a content item can be obtained with the content_item.get_live_revision function:

    live_revision_id := content_item.get_live_revision(
        item_id => :item_id
    );

    The item_id identifies the content item with which the revision is associated.

    Likewise, the most recent revision of a content item can be obtained with the content_item.get_latest_revision function:

    latest_revision_id := content_item.get_latest_revision(
        item_id => :item_id
    );

    karlg@arsdigita.com

    Last Modified: $Id: revisions.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/types.html0000644000175000017500000001211707253523116025732 0ustar frankiefrankie Content Repository Developer Guide: Defining Content Types

    Defining Content Types

    Content Repository : Developer Guide

    The content repository requires you to define each type of content supported by your supplication. Content types are defined as ACS Object Types, and may be created in the same fashion as any other object type. This page provides some specific examples and details related to defining ACS object types in the context of the content repository.

    Determine content attributes

    A content item typically consists of two components:

    1. Text or binary data stored as a single object
    2. Structured attributes stored as distinct values

    Note that a content type does not have to store its primary content in the BLOB column of the cr_revisions table. There is some additional overhead associated with retrieving small passages of text from the BLOB column compared to an attribute column. In most cases the difference is trivial (fewer than about 10 microseconds), but if many items must be queried at the same time the difference may become significant. If the primary content will always be small, it is perfectly acceptable to store the content in an attribute column instead.

    Basic attributes for all content types are stored in the cr_revisions (note that they are stored in the revisions table so that attributes may be updated for each new revision of the actual data). Most types of content require more than the basic attributes. For example, when storing images you will usually want to store the pixel height and width so that images can be selected and sorted by size, as well as displayed efficiently.

    Create an attribute table

    Extended attributes associated with ACS object types may be stored as key-value pairs in a central table (generic storage), or in a custom table whose primary key references the associated ACS object ID (specific storage). To ensure efficient access to attributes, the content repository API requires you to use specific storage. Your table should have the form:

    create table cr_content_type (
        content_type_id       integer
                              constraint cr_content_type_id_fk
                              references cr_revisions
                              constraint cr_content_type_pk
                              primary key,
        attributes...
    );

    Note that your extended attribute table must reference the cr_revisions table, not cr_items. As mentioned above, this allows you to maintain multiple revisions of the attribute data in tandem with revisions of the content object itself.

    Use the Content Type API to create the content type

    To define a content type, you should write an SQL script to create the content type and then add attributes to it:

    declare
     attr_id	acs_attributes.attribute_id%TYPE;
    begin
    
     -- create the content type
     content_type.create_type (
       content_type  => 'cr_press_release',
       pretty_name   => 'Press Release',
       pretty_plural => 'Press Releases',
       table_name    => 'cr_press_releases',
       id_column     => 'release_id'
     );
    
     -- create content type attributes
     attr_id := content_type.create_attribute (
       content_type   => 'cr_press_release',
       attribute_name => 'location',
       datatype       => 'text',
       pretty_name    => 'Location',
       pretty_plural  => 'Location',
       column_spec    => 'varchar2(1000)'
     );
    
     ...
    

    The content_type methods use the core ACS Object Type API to create an object type for each content type, and to add attributes to the object type. In addition, content_type.create_type will create the extended attribute table with an appropriately defined primary key column (referencing its supertype) if the table does not already exist. Likewise, content_type.create_attribute will add a column to the table if the column does not already exist.

    Most importantly, the content_type methods call content_type.refresh_view after each change to the content type definition. Each content type must have an associated attribute view named table_namex, where table_name is the name of the extended attribute table for a particular content type. The view joins the acs_objects, cr_revisions, and all extended attribute tables in the class hierarchy of a particular content type. This view may be used to query attributes when serving content.

    Creating compund items

    In many cases your content items will serve as containers for other items. You can include the set of allowable components as part of a content type definition. See Object Relationships for details.


    templating@arsdigita.com

    Last Modified: $Id: types.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/guide/search.html0000644000175000017500000001213007253523116026026 0ustar frankiefrankie Content Repository Developer Guide: Search

    Search

    Content Repository : Developer Guide

    The content repository provides a consistent sitewide interface for searching content. It uses Intermedia to index the content column of cr_revisions) as well as all the attribute columns for each content type.

    Searching Content

    The content column in cr_revisions may contain data in any text or binary format. To accomodate searches across multiple file types, the content repository uses an Intermedia index with the INSO filtering option. The INSO filter automatically detects the the file type of a binary object, and extracts text from it for indexing. Most common file types are supported, including PDF and Microsoft Word, and Excel and PowerPoint.

    Searching for content requires the same syntax as any text index:

    select
      score(1), revision_id, item_id
    from
      cr_revisions r
    where
      contains(content, 'company', 1) > 0
    

    The above query may be useful for an administrative interface where you wish to search across all revisions, but in most cases you only want to search live revisions:

    select
      score(1), revision_id, item_id, content_item.get_path(item_id) url, title
    from
      cr_revisions
    where
      contains(content, 'company', 1) > 0
    and
      revision_id = content_item.get_live_revision(item_id)
    

    The URL and title may be used to construct a hyperlink directly to the item.

    You may implement any number of variants on this basic query to place additional constraints on the results, such as publication date, content type, subject heading or a particular attribute (see below).

    Some limitations of the current implementation include:

    • Multilingual searches are not enabled by default. You may enable them for one more languages by setting the appropriate Intermedia preferences when creating cr_rev_content_index.
    • Some items are not appropriate to display "stand-alone", but rather need to appear only in the context of a container document (typically their parent in the content repository). This is probably a limitation of content_item.get_path: it should be possible to specify an arbitrary function to return the path for items of a particular content type, with content_item.get_path as the default.

    Searching Attributes

    This task is primarily handled to two Intermedia indices:

    Providing a generic mechanism for searching attributes is complicated by the fact that the attributes for each content type are different. The content repository takes advantage of the XML features in Oracle 8.1.6 to address this:

    1. After creating a new revision and inserting attributes into the storage table for the content type and all its ancestors, you must execute the content_revision.index_attributes procedure. (Note that this cannot be called automatically by content_revision.new, since the attributes in all extended storage tables must be inserted first).

    2. This procedure creates a row in the cr_revision_attributes table, and writes an XML document including all attributes into this row. A Java stored procedure using the Oracle XML Parser for Java v2 is used to actually generate the XML document.

    3. A special Intermedia index configured to parse XML documents is built on the column containing the XML documents for all revisions.

    The Intermedia index allows you to use the WITHIN operator to search on individual attributes if desired.

    select 
      revision_id,score(1) 
    from 
      cr_revisions 
    where 
      contains(attributes, 'company WITHIN title', 1) > 0
    

    Some limitations of the current implementation include:

    1. A USER_DATASTORE associated with each row of the cr_items table, which feeds Intermedia the contents of the content column (a BLOB) for the live revision of an item. This should theoretically be more efficient for searching live content, especially in production environments where content is revised often.
    2. A second USER_DATASTORE associated with each row of the cr_items table, which feeds Intermedia the XML document representing all attributes for the live revision of an item (from cr_revision_attributes).
    3. The default XML document handler for the content repository simply provides a flat file of all attributes. Content types should also be able implement custom handlers, to allow the XML document to reflect one-to-many relationships or special formatting of attributes as well. The handler should specify a java class and method, which a dispatch method can call by reflection.

    karlg@arsdigita.com
    Last Modified: $Id: search.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/workflow.html0000644000175000017500000001651207253523116026443 0ustar frankiefrankie Content Repository Developer Guide: Workflow

    Applying Workflow to Content Items

    Content Repository : Developer Guide

    This document describes the workflow API calls necessary to apply a simple workflow to a content item.

    Workflow Description

    Most publishers wish to follow some variation of the following workflow:

    StateTaskDescription
    CreatedAuthoring The publisher has created the item.
    AuthoredEditing The author has written the item.
    EditedPublishing The editor has approved the item.
    PublishedNone The publisher has approved the item.

    At any point in the workflow, an assigned user should be able to check out an item, such that other users are advised that someone is working on it. When checking an item in, a user should have up to three options:

    1. Check the item in but do not mark the task as finished (allowing someone else to work on the task. The currently enabled task (whether it is authoring, editing or approving) does not change.
    2. Check the item in and move to the next task. For the authoring task, this signifies that the authoring is complete. For subsequent tasks, this signifies approval.
    3. Check the item in and move to a previous task, indicating rejection.

    This simple workflow is defined in sql/workflows/author-edit-publish.sql.

    Workflow Creation

    Production of a content item frequently begins with a concept which is initiated by the publisher and then executed by the staff. In this scenario, the publisher creates the workflow and then assigns each task in the workflow to one or more people. The API calls to initialize a new workflow are as follows:

    declare
      v_case_id integer;
      sample_object_id integer := 9;
      sample_user_id integer := 10;
    begin
    
      v_case_id := workflow_case.new(  workflow_key => 'publishing_wf', 
                                       context_key => NULL, 
                                       object_id => sample_object_id);
    
      workflow_case.add_manual_assignment(v_case_id, 'authoring', sample_user_id);
      workflow_case.add_manual_assignment(v_case_id, 'editing', sample_user_id);
      workflow_case.add_manual_assignment(v_case_id,'approval', sample_user_id);
    
      workflow_case.start_case(case_id => v_case_id, msg => 'Here we go.');
    
    end;
    /
    

    In this case, only one assignment is made per task. You can make as many assignments per task as desired. There is currently no workflow API to set deadlines, so you must write your own DML to insert a row into wf_case_deadlines if you wish to allow the publisher to set deadlines ahead of time.

    The above workflow is created in the Default context. In practice, you may wish to create one or more contexts in which to create your workflows. Contexts may be used to represent different departments within an organization.

    The start_case enables the first task in the workflow, in this case Authoring.

    Check Out Item

    If multiple persons are assigned to the same task, it is useful to allow a single person to "check out" or lock an item while they are working. This is accomplished with the following API calls:

    declare
      v_journal_id integer;
      sample_task_id := 1000;
      sample_user_id := 10;
      sample_ip := '127.0.0.1';
    begin
      
      v_journal_id := workflow_case.begin_task_action(sample_task_id, 'start', 
        sample_ip, sample_user_id, 'Checking it out');
      workflow_case.end_task_action(v_journal_id, 'start', sample_task_id);
    
    end;
    /
    

    A mininum of two calls are required to perform any action related to a task. In this case we are simply notifying the workflow engine that someone has started the task. You may specify NULL for the journal message if the user does not wish to comment on the check out.

    Check In Item

    Unless given a timeout period, a lock on a content item will persist until the holding user checks the item back in. This involves notifying the workflow engine that the user has finished the task:

    declare
      v_journal_id integer;
      sample_task_id integer := 1000;
      sample_user_id integer := 10;
      sample_ip := '127.0.0.1';
    begin
      
      v_journal_id := workflow_case.begin_task_action(sample_task_id, 'finish', 
        sample_ip, sample_user_id, 'Done for now');
      workflow_case.set_attribute_value(v_journal_id, 'next_place', 'start');
      workflow_case.end_task_action(v_journal_id, 'finish', sample_task_id);
    
    end;
    /
    

    Upon finishing a task, you must notify the workflow engine where to go next. In this case, an author wishes to simply check an item back in without actually completing the authoring task. The set_attribute_value procedure must thus be used to set next_place to the starting place of the workflow.

    Finish Task

    The process to finish a task varies slightly depending on whether the user has previously checked out the item out or not. If the user has not already checked it out (has been working on the item without locking it, the code looks like this:

    declare
      v_journal_id integer;
      sample_task_id integer := 1002;
      sample_user_id integer := 10;
      sample_ip := '127.0.0.1';
    begin
      
      -- start the task
      v_journal_id := workflow_case.begin_task_action(sample_task_id, 'start', 
        sample_ip, sample_user_id, NULL);
      workflow_case.end_task_action(v_journal_id, 'start', sample_task_id);
    
      -- finish the task
      v_journal_id := workflow_case.begin_task_action(sample_task_id, 'finish', 
        sample_ip, sample_user_id, 'Authoring complete');
      workflow_case.set_attribute_value(v_journal_id, 'next_place', 'authored');
      workflow_case.end_task_action(v_journal_id, 'finish', sample_task_id);
    
    end;
    /
    

    In this case an author is finishing the Authoring task, upon which the workflow engine will move the workflow to the Authored state (as indicated by the next_place attribute). If the author had previously checked out the item, then only the second step is required.

    Approve or Reject

    Approval steps more commonly do not involve an explicit check-out process. The code is thus virtually identical to that above:

    declare
      v_journal_id integer;
      sample_task_id integer := 1003;
      sample_user_id integer := 10;
      sample_ip := '127.0.0.1';
    begin
      
      v_journal_id := workflow_case.begin_task_action(sample_task_id, 'start', 
        sample_ip, sample_user_id, NULL);
      workflow_case.end_task_action(v_journal_id, 'start', sample_task_id);
    
      v_journal_id := workflow_case.begin_task_action(sample_task_id, 'finish', 
        sample_ip, sample_user_id, 'Authoring complete');
      workflow_case.set_attribute_value(v_journal_id, 'next_place', 'edited');
      workflow_case.end_task_action(v_journal_id, 'finish', sample_task_id);
    
    end;
    /
    

    Note the distinction between approval or rejection is determined solely by the value of the next_place attribute.


    karlg@arsdigita.com
    Last Modified: $Id: workflow.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/object-relationships.html0000644000175000017500000001400107253523116030710 0ustar frankiefrankie Content Repository Developer Guide: Object Relationships

    Object Relationships

    Content Repository : Developer Guide

    Many applications of the content repository require that content items be related to each other as well as to other classes of objects. Examples include:

    • News stories may be linked to other stories on the same topic.
    • An article may be linked to any number of photos or charts that are embedded in the article.
    • A long article is divided into multiple sections, each of which is intended for separate display.
    • Product reviews are linked to specific products.
    • User portraits are linked to specific users.

    The ACS kernel provides a standard, highly flexible data model and API for relating objects to other objects. If you have a highly specific problem and are developing your own user interface on the content repository, you can use the ACS relationships framework directly. The relationship framework in the content repository itself is simply intended as a convenience for handling common relationship situations involving content items.

    Parent-Child Relationships

    In many cases one content item may serve as a natural container for another item. An article divided into sections, or a news story with an associated photo are one example of this. These "parent-child" relationships are handled by the basic hierarchical organization of the content repository. Every item has a parent item, represented internally by the parent_id column in the cr_items table.

    It is often desirable to constrain the number and content type of child items. For example, the specifications for a news story may only allow for a single photo. A structured report may have exactly three sections. Furthermore, it may be necessary to classify or identify child items of the same type. Clearly the sections of a report would have a logical order in which they would need to be presented to the user. The layout for a photo album may have a special position for a "featured" photo.

    The content repository accomodates these situations in the following ways:

    • An API procedure, content_type.register_child_type, may be used to specify the minimum and maximum number of children of a particular content type that an item may have. You may optionally specify a "tag" for identifying child items of the same type. For example, you may want to allow only 1 image with the "featured" tag, and up to 8 other images without this.

    • A Boolean API function, content_item.is_valid_child, which checks all registered child constraints on the content type of an item and returns true if it is currently possible to add an child of a particular type to tan item. Note that this function does not protect against concurrent transactions; it is only foolproof if you lock the cr_child_rels table beforehand.

    • A mapping table, cr_child_rels, which contains two attributes, order_n and relation_tag, that may be used to characterize the parent-child relationship. Parent-child relationships are themselves treated as ACS Objects, so this table may be extended with additional attributes as required by the developer.

    Note that there is no currently no explicit API to "add a child." You specify the parent of an item upon creating it. You can use the API procedure content_item.move to change the parent of an item.

    Item-Object Relationships

    In addition to the relationships to their parents and children in the content repository hierarchy, content items may be linked to any number of other objects in the system. This may include products, users or content items on related subjects.

    The same need to constrain the possibilities for an item-object relationship, as described above for parents and children, also apply to items and objects in general. The content repository provides a data model and API for managing these constraints that parallels what is provided for parent-child relationships:

    • An API procedure, content_type.register_relation_type, may be used to specify the minimum and maximum number of relations with a particular object type that an item may have. There is no limitation on the type of objects that may be related to content items. If you wish to relate content items to other content items, however, the object type should specify a content type (a subtype of content_revision) rather than simply content_item. As for parent-child relationship constraints, ou may optionally specify a "tag" for identifying related objects of the same type.

    • A Boolean API function, content_item.is_valid_relation, which checks all registered constraints on the content type of an item and returns true if it is currently possible to relate an object of a particular type to an item.

    • A mapping table, cr_item_rels, which contains two attributes, order_n and relation_tag, that may be used to characterize the item-object relationship. Item-object relationships are themselves treated as ACS Objects, so this table may be extended with additional attributes as required by the developer.

    Extending Parent-Child and Item-Object Relationships

    The simple relation mechanisms described above may not be sufficient for some applications. However, because both relationships defined by the content repository are themselves objects, you have the option to extend their types as you would for any other ACS object.


    karlg@arsdigita.com
    Last modified: $Id: object-relationships.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/guide/photo.gif0000644000175000017500000000674607253523116025533 0ustar frankiefrankieGIF89a*ÄÿÿÿÿÌÌï¿¿ß²²Ï¦¦Œ³Ù¿™™¯ŒŒpœÌf™ÌŸrrffoYY_LLO???22/&& þ!ù,*ÿ Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›ÏBDbÍn»ßð¸|îF ïSº~Ï×ãÿOkƒ„…†‡ˆ‰Š‹„k€K‚Œ“”•ˆŽ™F’–ž‰˜š¢AœŸ¦Ÿ¡£ª<¥§®”©«²7­¯¶  ³º´ ·¾Š±»Â.µ¿¿ÁÃÉ)ÅÆ·ÈÊÐ$ÌͯÏÑÑÓÔ§Ö×ÊÙÚ¨¹Ýã"ßàÜ仿ç•éê³ìí“ïð«òó‹õö£øù¸ü°õúçj_ÀLþ2xðQB…Ä5öb†ñT„ˆ1#š ;z4S‘Kÿ0%r$™’'+= °2œËx 00`„L XÀ`@! D …K z€žÄ›ýr"b@‚I ™tJa‚Ѿ‚ àÕ$„ ÔF ï*VMÙ¸š0ÂR“ Ìd—B„œ*hú”À€²+Ó†f÷.¤¼ j@°ÉA\ Ϭà…liXy€²u-g]tçŸÔöZÓ@×Ô+k‹ P6^­‡¸NN8wí´@ ‡å-}Ðc ±#DnˆëS}:¿í{‚‚}—zep@@_•NSÖ¾öé¾¢' ÿÒ¦}F€_ñ7}qWHÿh@%ÔDÈNg@€ƒV!˜ }Z4HKb‘Dçᇕ…XH¨b,þãâ‹y(xâ4’dã—¤˜#1æ3ãìÈãB>ÙEó ©$L¶ãä“JDyΔT"a%8Xf¹‰‘GFä%`†yQ’cZ±¥6]¦)ÄšÔ´é&p6#çœ>ÔiÌx²Rf˜|ö©ƒžÇ )h‘f2衼$š£0þyä¢Ò@¨/”V*åΪi}„**ŸN¡Æ¨¨¦º†¥¶êê«°Æ*무Öjë­¸æJ㩪öÚ«º¾éë°¤+¬£8.QÌ6ëì³ÐF+í´ÔVkíÿµØfm5pjK¦)@ì¸ä–ë+·3x[§Aðjî»ðÆÛ°1¨[»@ðªí¾üöëï¿Ö²A/ önƒï§"€ì¯$l©¤<‚‹B Wü‰ÃéB|£Ä'PlñÇ”`¼©Æ'rl‚Ç §œˆÈõ’ì¡É% ¬òÌ„°L°ËÁL‚Ì4Ïló ³t°<÷œòÏÄàÌÑÐ=môÇH·´ML8ýtÅQ³0µ':`õÕ g½ÂÖè0ÍÃ×`;*¶ d[Òµh§mæÚË(’Ù;Ä-÷‘t£Ð¶;xë ÷Þ7ö}Âß°žÃà„{h¸ ˆgXõªc½êÃ*¿ ã•+ôx ‘+ª8ÿœwþÏçÒØÝâè7”nú<¨J* ݄믟{98çFÉL–};å¹Ï}yÆ‹P蓉BU¡…IEÅTÖQ%ù¸OÍî`ÖÖZ¸f’Yƒ¤õÕt_½×Ws=ªDöÚÃ=f{¥~`ƒvXbùMïdh_q°G¼øîx#³fÀÏĤ6£„iPCÖ,ð5p_àgÀ[ÌÏH©Í~€3ß¼…: Ÿ‘ÀÁ6 -³Ïrž¢BÝÜ:ƒˆ úV¢CëP;ÉÚ`]‘Úç;á©amÊsû­§=ï1@|Vx„ÑFTW€ý<ð6ý€¾b!ÿ™¤C=^vÅ"ÂðfjЃ&!CPˆšcY8Ä6æ#‹‰HaÉXg+úÑ€D‰L4H5²ñ|#ÐT'#BÖÀœD"-¦9Lfr›¬X'ûøÉíI2i™³$ qKQrø€ÿO €Œv¥(>Ù¨T’b”” ¤¤Q@GPPA`µ&7ÙæÍ+Y´ž´çW"£–ü¸?_ÑŒP#šÓäÔždÑŒù¾b¢©ŠïžÛ<(òúS`Ô;(ÊúT2 E/82hÒ°î$¢%„«P# ŒÕe5 T À¸âs§uK¥#›ñÐÔ f" @ïŒM}ªI+¯6‰e P6ã׬l’‚œ,QX&…@o)!¸è»ÂFV®&aÞIOû¯¤Ö©µE7ÖÕì²´EuKƒûXþ¼V5M _pOø›¸bU·€õ[O¹Ô[üŒÿ}ih!œ2œ:v8Æõk€V’Üì"b&@,Ìs ú٤ɋ\ƒ%-Ó"ºø&+aè ÊZ\çò§¬äí,}ík˜•ô(ü[ïD£Û±÷Ž«½F¸.0¾¶Ô7d€Í:ˆ¾L ¬À†ñ`¬R¸,¦‹{Ü"ëT«9’0!Ôš>é™qÈìj Æ®Œ·Ï¥±[¢2\Ãüø¯0Þ)µq!"¢ŽˆØ ‘ääI4¨ò‹!Œ qò’{ñò,Á<1·’Ì 1s)Ñ|5[¶®@#Ø7WΟqÂDg~Ø™xöÄw—dw:˜X\&Ÿáòþ³B¶uÿ4M !Ó‘šˆDg¼tGIêÆBOòÐÊï?¼¤N *^i±ZjRÙ¢ö{¿iµZ.IO£’«¢ÎG[ðÛ×Ô¶å|5Éd8ÓxG3˜î Pˆ­’cd·m0çÑ–›.^™Àƒœ’Ú¾4-´!q¼Mp?›Á›.›ª›‚E:§†srsúÝyç––¶¶eh 8ÚQ7È+‰÷oì­šzw6¹í€öËØ=±%ƒ#Õ„XŸzþ çÇ5‡&9kn,~錟Ý SwœÞà~ë0ƒ€xjn‹g]X¨µ q\®â˜<ßÅÜ÷û®ïÑå+'žíùaG¥¯trÑÿË¢ep(tTŒ0éK¿²Óƒ¾P”g}È\ŸyÕã]ö³§;Ok_„EûQò•Œ=îM¯ûÀâZÚÃ÷ðq)üä»’öŸðÝ$R"ÑÄ5ßù†xºô<Û!û¹OôÅg(*eJô˜Ÿ¨L…=×ÛùíÁirå{“ËøÎbUô w}cÁvHr}ÿôÇLÐHeÑöƒrùû£þó8@•FßW€Š`W'P#A¥q$dA®{¤y󇃠ü!B_DÔ[Ì`TC$Ó†‚½t€[>Ì¡D7tq=D=$?”z½·zاHÄa#ÄDèá©Á+4T‚¶wƒ8˜‚:˜÷[ÃaüOe1F²ar6€˜…9X|ÒGéDGuGLñ†Vx„'ˆ‚*¨OHÒ´Hz˜†j¨…lx8¯‡)¢ç5Hè|ËwL{~‹øM˜„[(J‡7‰˜|èS‘¨ˆ“K•¸9—8|™H]›ˆ‰øKŸè{m4ŠëVŠÿ¢xŠÎ”Š¡ˆ{¬8r®H‹°8M²x‡X‹…w‹²ç‹¡Œ¬'Œ°ˆhŒ†HŒ¥§ŒÂŒœçŒß²‹X˜…Ò¸.ÐXy×x/ÙyÛh0ݨMßè}ü¶FsŽè˜ŽêÈ,ƒP K ò¸âW7ó˜*M .÷¸ü¸è’Lý*õ(˲Žyi-ÿh, Ùù‘9‘Y‘y‘¶â.I‰‘Òµ‘Åâ‘ t|"C$Y’ u’(©o*¹’u×’.i|ïø‰±‚zu“!Ç{8Yv0¹“9Ù“>9x:”6YƒA™nCé“EiGIˆI¹“KyšS“…øŒMé”ÿ@y”Q‰†Wù“3Ù•H™•DY•Ó–^ù1S +³S ÔGŽfùy¦°}‹Ð}Tó–pI~<±<…~σJÁ~Q=ð':v‰yZÔç3dA>”˜ß£>r!€…–¯B? … xˆØ~HT(•4©– ´·Ñ0F¤"d„ZYš+xš-HB0HB)$—“9š•Yš3Ôµ‰CÕ!„às°9–G´ð$µé„NÔPTlSt“Èy˜¬uq#Ôcÿ!Ad¤g…EJ)›rT P6!ú£@¤?;openacs-5.7.0/packages/acs-content-repository/www/doc/guide/flow.gif0000644000175000017500000003165407253523116025345 0ustar frankiefrankieGIF89aùæÿÿÿÿÿÌøüÏõúÑÿïïï÷Ôèô׿òÙïï¿ÞîÝæêÄØìßÖêáÞçÈÎæåÇãèÿÌÌÅâéßß²ÂàëÎßϼÝî·ÛðÅÙÕ´ÙòËÕ¼¾×Ø­ÖõÏϦ¦Óø¥Òù¯ÏߥÎÿ»ÍÅ™Ìÿ»Å¯«ÅÍÆè¤Áп¿™³À´ÿ™™¿ï·»š¼Õ¨³¥š´À¯¯Œ†²ß¯Æ›­«¢©’•ª®„ªË|¦Ï–£˜†£µŸŸ—›ƒŠœŸ{»†š¡ÿffs™¿f™Ì‡“‹w“¨r}Ž‘iŒ¯ƒ‰yqˆ–x„~h„›_Ÿz}huzkby‰itqÿ33ersVrkm[Zlyfk]Ri|LfVbe__LUZQH\lÿCYoKUVERYOO?ÿILB9L_BIE5BL??2/?O;=47;718:-6;)4=&2?//&),)!(-&/   þ!ùy,ùÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäŠ@çèéêëìíîïðñòóôõö÷øùúûüîåÿ‘€ˆH° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹ȱ‘ÀŒ CŠI²¤É“%7v\‰è#Ê—0cÊœI“¤J–8¹¬É³§ÏŸ@AÞ̉sgУH“*¥9”èJ££ÌÁƒÇŒ …6ŠdÃe`‘«¹Š°Á¦,10 ªÃÆLD±ÿÅ’5Ë&Ê@.l–êÝ ±©SŽPEpÁ3ÇŠèTæ—jÑyâtvRÉfuEHÖ–]ZÓ—`zcn 4cý9 á‘tšÇ”žGg•¦×(“”Yª˜QôI‡™:†abJâiè«3!š(7 ÷ƒ§‰_bÜñffPFic6@)Fw¸eÞœFfʆVLE_›"ØHœ„*˜:¥Êf—/šØ´V4ë¹#É:«6­uåb(FV‚w~§0Le—m^µ,µœ^ Ç´ãÚ/’Uˆ¥b}î÷ÛW ‹îÄB­[Nÿ`èýJqC6üÖÆ Çjq|!—l2{êŽl Æ'·ì2O)«L Ë/·÷OE`Z³k2‡ƒ1 7¤‚ÎPnAûd®BF„´A_5ôC5©pÇÒ͈Pk:44C*ØSÌ=GósÒµu}QÓj±Ôñ]sÍFŸ¥„\M†1¤õA’IíAx„!Ú&‘]ö3Á ñubŒˆidžÿƒ Ž/ä¸Äy 7ÓyC”íåSŽ^püŠõuäy^‰*“ SM¹ ;žÖ“s>ï ê¾ôÕ"d ÖãªD¹«žqð‘ÿŠé‹á7öâŠ"¤›«µÍQÚscÁÿ¾¾è=d°k¿åw°‘_ú-9šã¤Dûwdx¹øäShûÏRÈö\×¾÷ bóÊìbw3K‰O|W‰–æ ¡ýÏWÅã_hÄPšD ãAV^ò5§0×y U Â;Ì©€ŠÖ÷訂0†`)Á^7Xƽ´¤.±Ab.e…®ôð ®²XŽ£¹Ð5D‰cÁ £È0ø-$‰wXbú0Ã9,_À[`gÊDASb¶æ¼ÏŒ‰7)aìŠ`†(p!hƒ‹‹UÃ…ñ¸mjS2Ãgò87‚Mê$ŠÓá2xhBÆÉ,¾RÍàŽø˜ÎmÑŠ ™ß•êçºô±ÿ2è+ ?×W‘ò”ÍJˆ’Æ=<92”ý« ùîp³"¸‘á#¾²•JÜ¢e–ñ%Gm9dâ¹ F$WC©~Å;I:†’À¹ñƒÉ‚!¢)#Mjòî2°ƒÑ*i¸mâå€à<†/ºù å¤fØ>Ø¡‡™CÞfÃAª“ s€ŽãǼÊœ`&VÆ“D2²Aƒ‚Xï]Ž‚lØÏp^DP„ÌMOêèpbŸ‰Ü|0Ðøö“†ô6&ÕhJÝ·ÒÈn!bè.ó/]]Év ¥i2D¾®Q¥ŠQ&K¨Kf“cÿ)ÍøÃBñ…FA¢€Ü'G„X¯¢ÍÍœæ1×µ5#Î;Éèàð±_…®u¢³œ<)jRVeó!vµá9Y× €Vä­úY7ØŒ9Q›ˆËaZ¯±Ö’ '¤œœIÔŽF0Kï$‘µˆnÜ÷؈„M&,1*{‘"ëµ¥I`!âÚ×B+¶!éXcÛ³¹u¶&µªk-R[Ûâv/Å…íΖKàÃe®t§ûç>×Ñ¥®v·[ë^—Ùå®x§ëÝïê"¼ãMoÍÊk^\ôã½ð¯|çKßúÚ÷¾íͯ~÷Ëßþú÷¿°€¼Š€áÀN°‚œ;øÁ˜0ðÿ‚'¬àCøÂ†„„)™ÍÌfŠ¡9Í…Xs›çüª7ÃY'tÎóÎì|gÈYÏ€þmŸ;1©PÅ*X™Ö\èÚˆ¼3!È4È£é¬@3—ÏwÌ` s¿*ïsYPY BÄR 9bDÉWK¿ ÓpÎhúlƒݠŪAÜ’`À–æˆ@ J°e¼˜“œå°UŽ:N¼¦ÿÖ˜'µÅwª†Õ êê–Á:Íb¡ìƒýðç 'R÷Àª¤ uÚ ûù͸…l q%;÷ƒŒ J”ÎE› ƒ9nµÏum1»(¦2¢Qµ¢¤Ì; JZ vC„5\WA:‘ m”—Q°xÙù!žh³©}ŸyМÈvŒÌd¥+©)~®ÔèÃ6.§{!{=hôPÅ7Ž&øÝT?Y¿±¼¨ªtŽX¸t]Á‘-‚ùhj¤óÎo¬k‚eÙ{L>ÄùœïÝÊ> éK¿ïÓW9õ&±©Y¯g×Sö´Ï}Hl?埉„k³/žo)¶:y†$7ÊiHñ²Ù_/mùùÔÊU-}/„÷RÆØ'C·1Ä‘ÑdüžÐ òŠÇ'6C¶·VK_4#y?A O™³VûQŒ òé:°ès”1:Ù¢3çwze8ÑÓX¦ÃÀt:á8ÆÓ96©s€ÁEˆW¸ƒ9¸S<–3€Ï´&¡79üGñSŽ‚2[ Èx9¸•SQ†'!ä“$¤DvîÓ2d„ásA¢÷WðwpöBx†£Q7¢JäsBAˆ„Ç&O×ÉC­"!bGˆ?IBHP"JÐáƒe„íÓKðd8î“$ØQ1„†©¡†’'´&”ˆn±ƒO¦}EE—DdDÝ£â&LV´9®âHiäiÉD…h—#Uª‰cä(Ý„D®3¤òÃäŠÅcXà×1©˜E‘‹-8‚ìä(´¸m°¨$EŠÀ˜ÂÂB=÷çy™àˆ@š">dMyBéƒFZµ‰kK˜ Xÿ-WÈ4ZY¿ä€t'ÈÈŠyò=!õI÷+;ò†ƒ”$2ÅSz#1쳎?Ç9àÇ=ÄTã7ŸÔŽ¥‹ûH;Ï— ca5ÇHMÖ8Iµ1JHJQÐ(˜‘ADuÓ$=èG†30 ñM¤¦X<·aNªh8ÃgÅEM3Ä‘͘$u”ž$,•×’‰”Œ$9“5iWI AHbÐ",ŠØY ƒ+ä“/EV‡T ’V€n¢PrTQä>‡TdõQ3µQ!~¸FˆÇ-%ô&@Þƒ3…Sª´UŽVäÃA7â>˜¡a¹&éw÷ÿRð’q¿ÖAZ©—Ô¦‚ŒY?²“ @ð2RÅF[˜‚ôS<ñx>êšÁˆLÆ2º#44¨=›g,èXne}<¡;’1³‰W Ñ<Œ“à—"(ŠzÏ×j½ÙX½ (Ô6ª¹d¸çÞSŽ-cK&axs`%Ñ|IžÐY•–0 ˆX$Á5¶åk=aœ¡ž¶“`ゆŸ¯%ŸéBžVÙ%öI.ø©ý -ÿù2Êž×£Ÿ“`žº· ©‰  Ê ÚÑyd ¡z}* z¡jjd`¢":¢$Z¢ô•¡(š¢*º¢,Ú¢.ú¢0£†€c$–`&ÿ£8: 4Z£7š£> ;Ja=ú£DÚ Aš`4V¤Jê G Iº¤PZ`$ö¤QZ¥¨@£Ef¥Zz¥ –¥[ú¥¥@d;¦d¦¦deš¦¤N¦¦nú¦p§r:§tZ &z§xš§zZ¢Eº¡ú§*d~ú§¨A6¨„j¡†Úcˆš¨º¨<Ö¨Žº jc…6?ˆÖ›ŠF£–¦= !Ufa j!6p1©?Q©5¦i„aˆá[Œ±&¡†>Ú¹¦¶-ØôLŒ7™EíÃ&¨šª}ºW³†S¹±¸¶7t‡/½UÁvÇ:HÆö{¢lkÔl¿öld$SQ<£E–­ÿ'cTTÁÊÃjFG8÷‘,ôm['â6äF>ppné"ÉÂnëánƒ±J¢6oÙQoº*,Ý:V@Sƒñ«‡f)xW®hE¤ÿF‹6#Ag#82t'‚p‚Á ©ÁpA²xT³—G“OP’œô"ã3ý;–J°óp«ç°ˆt®ateÒ%—&ÚbpE‚&+‡v°³0‡ˆ% "5§«?(6ñ¶ 0 ¬3K³’õ£=÷)t?‡L'’®>û/¢tlW”GuÚ“J"p®H'¡±¶«(µù ±(Gã^ç+À"vg!?`vŠg r—qL7.owjW”yb¶hËl Tÿ~lë¶KµGãwð"/ˆØ©QŽKbx„‘x,çp[åxE öáE RyWe:ÓqyéBš‚.µŽ»{6ËVSø°»Ö6»Jq»¸ûqp»²×»Ò¥ª0&©ÂkiÄûb¾Ç}Á 6j_ƒÍ‹Ð7æÂ5 qZèñ¼ Q[qSr#4Á«½<ó»àV»Ñ}më‘(AHö„¹:ç8ɾáZñû’Yts8¡»At‚Žâ–€/8œúÛ9Èk’“X ÑV,øš ,’#óyX8%Í©¥%™ÃXBƒ:4x)³i7ØÀA$,ÿ÷Á¼4=Ô1(ÂØœ&Åÿ›—q“wñœ‘¼*ÖƒL„Õr‡`H„èÓ†IhI×±«Nè=P¸RhR@C*À„òšL >ìÓAз)Œùp S@hûüƒA}h†Ú“!¤½"Ja@n”ÆÕ“›Ý3CQØ?D\‡Qì>¨{”¥U¨ò?eáNK¶>` ;7T¾?»©8‰I‹—˜À•Ó‘ ©GAä‰?·DŸ¡‰ö{¨Â±™-! „b£FUh«ËèW¿T” "£bsðÉ© ‘A9‘ÓÌY™>))ìM!¹[?g0 !Ý! N—¼¤ê¦ÌBŽ‘O")“S,u`Xt‰Á‹* Hú«N2y~ ’Œ mNéqâЃ¸Êâ†õ9êÄÑ ŒÂ–È À'™¿F™]IR`)–&Y–ry–s–µ–ùHS–‚BB„–7Vå™'µ|’a›R@ç1Õn™™C§$„‰hw™,[hSÂ+ç™IL\]Bf=R_y-W­*:ÕU´Qp}f½:'u%;UÿgÝ%Ô•Ó î i±é:X3 [È8› (Ö á1\@ôù;1É~5˜è; dÙ+ˆÙëkC…W¡í5 LKÿk¾÷[4ñÐíS½?q!Žg<Ó"A¾ˆ„¼ÝžñÔ\ŽM¡ÇÙ﹞lhÃJ¡[aÐ=MÇÍCùÐíܵ½È)R À"Ö½žÚ&]ÉE.ÞÍÏ9j¼Ç hÇŒbîýÞyß!6ßô=gö bøßl¶ß¶§>à^àùP§žà ¾à ÞàþàÐФ6¤n¥Î`ž¦Ž`žáZzáTêá`Ú¤!.â#>¥'fâoŠ¥cªâ+Þ¥-îâ/Žÿ`^*ã3ަ6>§lšã<Þã>þ äB>äD_±HžäJ¾äLÞäNþäPåR>åT^åV~åXžåZ¾å\Þå^Nå©Uäb^__~æhžæj¾ælÞænþæYæ át^çuÞxžç°ç|Þçðç€þç0è„^†~è0о芎é’î”^é–î éšžé Ðéžž ê¢~¤^ê¤n¨žê¨^¬Þê­>°ë ´^ë´žä1cæp¾ë¼Þë¾þëÀìK.ç açÆžçzÞçÊèNè…Žè†ÎèŒþè.é‘~騾é›îéŸ.ÿêÞnꦮêªîêä.ë±në¶Žëe.ììÞîîþîðìÄžÆnçÈŽçʾìÌ.èÎnÐíÒÞèní׎햮íšÎíîíßî§.î«Nî¯nä¹ï¿ñßñ?ì”@3õ~ç÷žï~¾ïÐïþþï/ðŽNð`ðð  ð Àð£îðñ/ñ@ñoñêîºþñFôHŸôh>ï1òt~ï`ò|Žò)ßïÿžè-Oí0/ó•Nó5¯ð8ê:¿ó<ïó¬ôññJßönÿöp?ô:çNõR¿çT¯òWßò õÏõ”îõ6ö >öîPn~nކÇÀΰð¾0†—@_oOŸQWGEU‡×b  À žÁS`€Â…8|è°Ð+ZA$Ï'B™r`òø‘Љ/e@.9!åË’%„$œ<Ô&<H(ƒKœXNœX¡Ì%3 ùò…ƒÍ—.OäÀ‡%‚%e°H ´³jÍV\»zý 6¬Ø+šµ˜ 6 „yàQ…‡‡$UJtàAfM’c%¦¬!ƒc‹)80 Æqœ)>LQãÅDµÉiðL¸L¢K(!²#M P6—s"à 'ìÔ±“1Mÿ -äàq"A4cZÜË‚gÄ#ð0 häL˜™œqް@,g–(hñ¡Ä³µ1iÏ#„ÈsÐ8“e#õEƒ…a†nÈ¡+Ü™eKZºÀÁC‰r•pÇ<àAF5ెxT±Áxhñ,à€Çð8…xŽm¶ ãZn5ëÂù.8q?0÷½ùâáF9nÔáï:p"±Á~ÓSç=õô)܈SQ­o±6Di0BÇB9G= s…ÀÉJþc è3ùÄS°ðG€.ÿ(Ð F•2ž*@!!~;Aœ@i8OVh«8¤,t  P‚)œ'©žÄCo"ÒŬP…$ÊwHÂ:àD/ÁdØÀì èá`zoÀAŽÊ&!X I=ð‚p°6ËL€xx Þ  Œ¯|ucàÔ…ö1NNp‚üÔqƒçŽx0‚=F ~øcXß È„ÇDˆÄÚ°‚˜( –3^"ð2öÐ%9øÏÌ6B A(¥t˜ x¡4_áÀÏjÙ¾ªAt /Äÿ (¸•Wq™Ì|Ú?t<µ¸-‰3ÿò€xÐ*Ü¡1Ø@ ld‡#CHv’¦0$ ¸@ CºB÷Ö5ØFD°äv7ó}É •AÃô¸7‚¡¸?P@ààa  ÇF0(7Ä èÓ>Ò€ƒÄ¡O™~â ƒEeGÐä„vwÌÍ©BSÍl©K_*¬g–¬ˆ¸p‹M‹aŒdè´͆4ºw™ á‡8Ða7s´c©î€Ç;ìgˆAL T5@A®J† 0d$-™†ˆ©R˜Šu¬dåŠLÏÍ´ØÔ-8%†NwÊÓeøtéªP‰jÔ£¢cnå`j;œúT¨:Tªxªj@°zU­*„“d¹œÿ†\¢Ì²Jv²”EÄYADÓ[¬UmíÀ[•W Ì•{uµëeðšW¤:ÁK}õkS*ØÁÖ°‡ElVËØËÆ‚•í­oûÝR$­¹Øì0ÚúYd„V´sªi½޼>©èpíkáÛ¶°†µímµš[Ǫb*/AE‹Þô:M¸´ nMÛÙäc¹£u®iQkTêžÃº€]@v·{ÚZÕ»Š)DºŠÖUL¥ ,AE~§ÞK8Cì­EfE`\ÄW¾ômniïÝÔê·µ~íï·+`ï&·\íäq œww’jpæ |R H &hì <á y>Ö…3ÿ¼áävاöµ+~É1bð°'ž-mU\àðz¥,~$‘Á2´¡ =\IæÆ\†Q^e Ô†2”á¼C®³EQäݾÈåphëûa'‡8¿Qž2lc à˜ÅŒB0ˆÁ`¥,aÇtPÊ$.dfB…0Ð â°•MàÁw.µ©A‘gHíy³Iþì’è»Ê#64vâ+/¼-nì–Á™iä@ž3N ‘iWû†É6©O íh§Ú"@¨¶µ¯ílk{ÛÜî¶·¿ îp‹{Üäï!@M•tW>¡T²}Üî^íDw ~¶¥£ï!O{jüî·¿ÿ ðÿ€ <༠Å¥tÙËqhå²6wŸ8³0lnC/±‡4_(ßð¾ò‹|ä$7÷!blˆ€Îˆðɽmâ“Cä¸ã4÷xÉo>r0èç<ïù±jô ·âã>/¹Î^ô¤“¼àBoºÓAt¥‡üè;—ºÕ þô¬k]ˆWïº,¨¯‹ý×ÀÊÖÏîÒ¨½ß`_»Û+Ât 1ít_¦Úßþ¨¶ã}ïaÅI, <(èå¥à@¯_÷ÄïE×;ãÝwQ`¡Øt`9(1f2—”/àúQÜýñq<éÅùQø 6E{1„‡b ­ê âC{TŸÿç¦ßýÕSŠ…»¹‚/DñGñìÜ+¿£÷=,zï|¥Ÿ•æ JNv{ã‡ð o Ò8ÁzH„pùä·lôsNõóÿ~Xè¼è@’A_!?ÅNx!¤ û“{™áÙ/¿ò›ï|Ч~=7}&d:¡z–l4æèhÈvé'IW€¦ðA¨Àa(z(p‚Kç%XVè{"8‚"w&è‚Pƒ‚»§‚+rq÷+1~/¨ƒ1Eƒþ6ƒ=ˆu‰@ Ò*;h„¿ƒ§÷ƒ@øo×c³’:3×+7Ö+'cŸw„Y¨IHzKÈ„ýVppÆ`_§chVÿC™`(‘Z‡\÷…yGsrL—|¡fCJ63LB ‚)qHˆPg‡â…‡XRaÍv|£† ˜ …H‰¨ˆÏW‡—px؈­Wœj‚gfX‰qÈ…—ˆšwñp„€ìÑ}—f90¬‡:9QŠ…xŠŒ—Š_v^Å †—‹Ãh»Èw½È„`ÀHŒÍ8tªXz™± sËøhΈ‹7_'ÛxtpÙ(ŽÌ·ÜˆtåH:·à8\Âr Èe©sBX(s`sãøCƸwÈ„T·ŽíÈ€Aœ@Š8 9 cˆ|ôx ÷h _Yøèúˆÿwü؃`·Ð^­0£Tgârœo› …[áe6iS8L’€rÃT’!Ù Ù’Jax„w ©ó’1·C/$‘aA‘og‘4v`ðùs«@ ß×J”w7ᆭ"†s† ex†•wQl’f6#:œgéFqF•a6f–—3 8jtJ'ã eÈ9ž`†’:+Tý÷“Ä‚Ž˜xŽ{Y”F‰”¢ µ¤–‡°z6Vyˆ {¸É–35q Å·C D)¶{o¨ Ý~"q!Ÿ¶ׇA_0R L$”—fµ—ð—­é𝠛±)›³I›O”©•ã'|ˆY ˆÿŽic£è™–©;Å&gÙ@¥AÃI†Æ–´(šG0y~˜š¬”nG›ÛÉÝé´é»Õ ;DjÕ‡×WÓ™:öƭמÈVù‰Å7oš¶ °nñÆ /À`¹£ ò/ÔnŸ’†29Ô׉«ù ê  ž‚É9´è~°ÒJq– ±ÒyŸðŠPA3¡,:Ñw(!ÿªq±Rݧ4”:O¡,ÝÇfi¦R H‹®h ÚÙ¹v*¤C:¤ÖØ‚£pR‰`xò7s§Ð¤œ†xOªrðh '>Š!@¤DÊ¥]:›ÖØwXš—Zºšûø—`ÿ¦Ñ6+Á¦ *¦ÃC¦e*”E‰¦i mkÚ¦nú¦Á§rº¥TW§vÊ ó¸§¦è§~ v*¨ŠîY¨;ا‡êu€ºŠ2·rDc+!Œ†°©˜j“=tRWú¨[©’zuG§¨z2 f‹™y$gj qFC¥b†]9ªtWª¦*uÕ˜`óg{š'ˆ¡" ¢Öi5 6ó'T{’™«g·«¼štÊÈŒ†€µØ}™Fjn(gjV™ D–^æ¨Ï*tÑ*­>÷‹¿zO‘ *¥­’P’>¬'=ÑnTJ®g®çºvWK­ä«#OÑp²ÈB"ÊWÁyÇ‘ùZsûʯ¨7ÿž8¨é°N±ÛuGz±&˜±kuÛ±ø± +}#[Š%k²E'²]1°‰¯¦0®“0³c³7è¨5,) /» ˪;8f€G¨ƒæ·²~Ú²Ù°ë³¥0³s×!ß 7X: ,< >‹›¤´‡ ˜¬`±™3†ô*›´<·´('cTˆ©S’4’½‚’—Ê©”ªv còÚ€ƒÈ‘VH)н“’¡ðˆ*·4y“œÆKz 2Y…÷Ic…+…c;x™s…WЏ¸göc s-”¤‹“+—imÀr˜¶«¹´³Úf˪†' 5¤*sFØib–ÿ Yic †)Æiv´†ÀŸjÖ™÷1ê6«[]æA-4»`YlXûˆÇ» iyi–Ó«2yc—bFfÚ»–_à»ÖÚyÅ—»!é c¦iÖy=T32–23–rvfY¾PrÆ m žP Æ¢êb­‹ŽK[+Ê~x¬tõ™žÈö`6~Éf¬4:T«É'jR;^Õ×iÅ ÁäÁ—×›ºÃ™,±Á¬id6¸˜yi›¢ÁÙz¤rx|4{ òAÉ&’!){ÉçÖ2—€œºó™è™ 6ƨÀ{ÉÀÌ­iæ3—à“Æ—rX€ö÷žlŸ~›Â+,ÿÆ~;Í›T»­Æ†ÅÿI ‰ù;e œ5qÅÈˈÅéÆÅGÇä+ÍÆŸøáŸÇgÅp,‰º“*L ¶”rÆyl¢8‰œ@µÀ)‰Œ´S\ŽU¼qñ:…ë–g|Á™‰l6ö‰Ã„n”©™ÄéŠÛ·Ä¤€™%*?Ʒߺc*¼ÈÆÛŸ°$Ë,™ÇÓYCúÉ9¹<Êd;Î*Æ‘iióö­ÉV¿Šìl÷™Ÿí6ˆÂ)ɲòiÀ£#Ř¼K‹°¨cÊÎM «£,W!Ýêß qg8‹·9øÑ° +÷!f_Ì Ð›* ÎI#f¶ËŠËrô 2 Šâly挋.*gꊕÿ¢­Øi&Ÿ Î]J!Ï[‹Ë£,*— g(µ˜ ἦS£kf¢JãªË hËÍw(#‰ ˜‹Êû·À{o6ýµÔ›G¹Uª·’Œ—ªãµ  ¥Eíw¼l¶1=ÓÝ 7!f){@ëCF«{S ¼L'”§KP¼c1Ô¢€³yšÔ¦ÖmºÖA†§m è Ó^„é%ÖyZÖÂÓÖlúÖ¤Ðךšoqͦs­—v­‰`²ËW׈íoŠ½Ø¹×ØŽÍoÙ¡7Ù”Mv—…™­Ù‹ÈÙZèÙŸVäfÚ§Ú©­Ú«ÍÚ­íÚ¯ Û±=n¤MÛµmÛ·Û¹­ÿÛ»ÍÛ½íÛ¿ Ü— šªÁmÜÇ ÃÝÅÜÍíÜ_¨Ü´ÉÜÏMÝÕ]Ñ ›ÿhÝÛÍÝ#ˆÝ­©ÝÝ-Þãí|ß‘ìHÞé­Þ|gÞ:w”ë ßñ½væýÞòmß÷­tØ]ßøÍßý]rÊžþ-àr)`›Žà ®à Îà îàáÞܲMánážÚ.ß–ý“£­árÊáéá=â$¾À&Žâêâøxâ+>->Ž/ãªÈt9ÓX`Ø~'g€·/a „´?Î CîlÆÊ0fùXãã]p²3ñÉ`Áô›–\+.| ”`ä«ÀJ˜ByKÿrD4þäŠÈ[i°B#QÊ'‘™Ö0!ÚÌXÐ ’l¤™ D•ö:i„X`i'A:ŽrÖ`a~)Ô}YAJPÁrÎèÀƒæin‡¼õJ=-s;èa+ÿÑž2 ¨®Ôó¡Ò ¢ 4Jÿ¡w¹º¯£„†bޏHXð~T)÷ç)¿þ~¼4gžÐ X,›Îé_È[?3ì—’)£Ã)ìA Z £°G*¦"•à<'ðéì 4¯ó‹‹ :2†šÞæ~î¶Ó@©5ϾÝÑNæ+:.ã643Í\J³:3jì« A#ï<3)ºÔÿï·CòN:ï~ëQë„ÿaïHˆïÖÍ[šÃ9žózÔþ z¾Aì:Î-á6°":5ÑçŒ2ôqñ ¯ 0/B¡>ì¢cxo|bqoæ)Dó Œ`3aÞ4ÎÞñ4Xp”J4Ad:¤A¥#ëUnó7õ¤ ñB_î%´õcyáþð@ÿ¢sñ¤¹{ ¢sö1ôŒ°F?,HŸô#Xp ´,nVJâq¿©Ô«´q®t3²4:¼Dö}L1ƒKC±ÏJS¡Ã3¯,s Ý`”Ÿqªb 8Q²ãb÷w_qwRøY¯ìgò†JúþU<‘²­ïúY¹8ú²ÿ~2.Ž·ûΧûÙÈû½¿{¿Á/ü¤‡áɯüËáÇïüÏýÑ/ýÓOýÕߺíý¥Ö¯ý—ˆý°9ÝÛþ×Íßþå¯~ÝÞæ¯þLˆþêˆÞëÿÞýšáÿõ/þ¹ßö¯ÿHß¹ÿÿ‚ƒ„…†‡ˆ‰Š„)`Ž`O‹“”•–—˜™š›œžŸ ¡¢£¤¥¦§¡`>¨­®¯°±²³´µ¶·³)O¸¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚ¡@ÝÞßàáâãäåæçèéêëìíåÛðñòŠ@ö÷øùúûüýþÿ H° A~@æ)\¯ÞÁ‡ÿ#JœHqbB†3JsX±£Ç C껨±¤IdEª\ɲåÈ“0cK鲦͛IÊÜÉSM{eÊ ±w"(‡‚Å"¡‡“æ°·Äž”2ür(UzTb)ü U©³§Ù³¤~Àƒ§U¶'>žÀ'(:MõqÀSõ Ô_ð¼Ok™»F'âÁºc‘eÑJž¬Iíb<´9W–2K2ŸX’t‚ÏCrL pâK™Õ÷æö‹%€ç2_ŽbY<Õp_{–Ä ~TÂ’ÂOÄá+áð‹/¹÷-¾§õKÜ—€>]ªqŸ¡®Å<(Ôt«–gÚ12å÷ðY^ÿ‚ç¾xN ˆGŠcìwñu˜mL·W»ýÆ_÷´A‡fq,AGšÑ%Å x`lÄñEèÕ6è-‘‹%Õ–mIÇØˆŸå·®ÝåÌE2NÇâJÀâ_ì™Qä^|L29ßWÎuzP±hJ¡mÓí–YÆÆà` ãr öÅÁ• úüÖ†l6XSvê3]‡nÝW[‹´xB ZþÉ×tZ‚…!‡-Ù䤓ÍG RÒÇ\ôÅEçxunÊ>Ÿ†‹¦Ë¡¨à^ÐA_¬CЙ筄峧¨ÓMGg§ŸÿöŠÕ‰.ŠÕ\¢*)¥ÌÆ7†mH!åˆâQ%ã^`݇U`Iæóé}¹ai*qPª=bÖF`92ˆ+™z2F‡[øøÊ °xd+ît×#VØ‚$i³Ç4ß}õI©åœ`ú{Ý‘/ì6l†/ÐHêbK,±Ü {}¡`sYØscÞÃ"Vô¹ek}Í–§®Œí6ĈCÙ[¾tDL"¨*×cPAŒ×YTðÑfÍW!RðÂrqLÕ©=¬b¹§„muE”¨mˆÇb2–ÛrRÔ•Ï^C¡­jÅx¨/ÌÀí†ef6 2ÙöLw¢¬÷Þµêa;¶‡ôà2©ieŠ‹ÓâûÿœË8>.y<†?tX?®ùÖÊnùä cSùAä±Ö›3n\Ñ©ðyè°O3zë´×¾lì¸k3»í¼÷Ð빯Ìî¾o¼=À ¯|1Äï¼íÉ//=0îToýõØg¯ýöÑOïý÷à‡/þøä—oþùè§_’*´ïþû`¤ þüôûÂ>üøÇ_ÿþüÓrþí“_ÿH@Tü/[€@È@Qð} l '¸‰>"‚Ì 'aÁHlðƒ 4Ä=†ð~$4¡ 7¨ V¬ð…,Ü gHÃÚð†8Ì¡wÈÃú0„Ü ¢‡HÄ"~ã‡ækÞó–è9$–O‰LÿŒ"NºçÄÐAQŠXl «8¹+fñ‹!Ù" çE0š±"b#ÒÊxÆ6æDàSËV¾Ò­|ˆ¥"» ꨎäŽn|#½gÇ”¡@ÉÇ&r²%ì†^ûë²È@$ƒl–eS ¢¸¦7éÁÎjLÄÒ%;ª£–C©2-àHâÇ6ÂAO„,yÉLNÏ2s:AÅ(t  +»BY€èC£ÀÔæ#‚ ¸@5žªµÁté¡’è$›còÒ ˜ôå¤,#ª8è3¢f2ô¡µ„iOÖb°ò¦Ì¸´D$â&ƒàùÍ„SœN’Μ64Q©“1Ó™ÚÿAñAŸjik¡S›šlôY~ö3 ÿ(|6iÅ…[õB¨HEÏ’Þc/ÏÄgÍFÑú8 µb,zÑdT£”áè‚(¢Š}ˆ.PѦÎêiR‹hJÚÌŒP% Ò¤ìAÚ Ãö ´š ä¦8•ŒNOu/µá(Ìо°’.8 [Ìib‘+XÎè34:¬fH?Ѓ¬ú»¬æŽ!Éêþ¡P¾*ɯ¸lë kX‰`±=QlêF“—Æ:²°“¬e-ùXÌn³ õGg= ͆öŒ£%­IŒÈÚÖºöµáP­lgKÛÚÚö¶¸Í­nwËÛÞúö·À ®p‡ KÜâ÷¸ž ;openacs-5.7.0/packages/acs-content-repository/www/doc/style.css0000644000175000017500000000020407253523116024447 0ustar frankiefrankiebody { background-color: white } pre { background-color: #C0C0C0; padding-left: 12pt; padding-top: 6pt; padding-bottom: 6pt } openacs-5.7.0/packages/acs-content-repository/www/doc/package.adp0000644000175000017500000000160107663154215024665 0ustar frankiefrankie Package: @package_name@

    @package_name@

    Content Repository : @package_name@


     

    Overview

    @info.comment@

     

    Related Objects

    See also: @info.see@

     

    API

     

    Last Modified: $Id: package.adp,v 1.2 2003/05/22 14:02:53 jeffd Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/package.tcl0000644000175000017500000000035407253523116024702 0ustar frankiefrankierequest create -params { package_name -datatype keyword } # declare the datasource for the introductory stuff. doc::package_info $package_name info # declare the datasource for the methods doc::func_multirow $package_name methods openacs-5.7.0/packages/acs-content-repository/www/doc/method.adp0000644000175000017500000000266707253523116024562 0ustar frankiefrankie

    @info.type@ @info.name@

    @info.header@

    Author:@info.author@
    Returns:@info.return@
    Parameters:
    @params.name@:   @params.value@
    Not yet documented
    Declaration:
    
    @code@
    
    See Also:@info.see@

     

    openacs-5.7.0/packages/acs-content-repository/www/doc/method.tcl0000644000175000017500000000020707253523116024564 0ustar frankiefrankie# included template # method and package must be defined by the including template doc::get_proc_doc $method $package params info codeopenacs-5.7.0/packages/acs-content-repository/www/doc/design.html0000644000175000017500000001102407253523116024736 0ustar frankiefrankie Content Repository Design

    Content Repository Design

    ACS Documentation : Content Repository

    I. Essentials

    II. Introduction

    Serving content is a basic function of any web site. Common types of content include:

    • Journal articles and stories
    • Documentation
    • News reports
    • Product reviews
    • Press releases
    • Message board postings
    • Photographs

    Note that the definition of content is not limited to what is produced by the publisher. User-contributed content such as reviews, comments, or message board postings may come to dominate active community sites.

    Regardless of its type or origin, it is often useful for developers, publishers and users to handle all content in a consistent fashion. Developers benefit because they can base all their content-driven applications on a single core API, thereby reducing the need for custom (and often redundant) development. Publishers benefit because they can subject all types of content to the same management and production practices, including access control, workflow, categorization and syndication. Users benefit because they can enjoy a single interface for searching, browsing and managing their own contributions.

    The content repository itself is intended only as a common substrate for developing content-driven applications. It provides the developer with a core set of content-related services:

    • Defining arbitrary content types.
    • Common storage of content items (each item consists of a text or binary data with additional attributes as specified by the content type).
    • Establishing relationships among items of any type.
    • Versioning
    • Consistent interaction with other services included in the ACS core, including permissions, workflow and object relationships.
    • Categorization
    • Searching

    As a substrate layer, the content repository is not intended to ever have its own administrative or user interface. ACS modules and custom applications built on the repository remain responsible for implementing an appropriate interface. (Note that the ACS Content Management System provides a general interface for interacting with the content repository).

    III. Historical Considerations

    The content repository was originally developed in the Spring of 2000 as a standalone data model. It was based on an earlier custom system developed for an ArsDigita client. Many of the principle design features of the original data model were also reflected in the ACS Objects system implemented in the ACS 4.0 core. The content repository was subsequently rewritten as an extension of ACS Objects.

    V. Design Tradeoffs

    The content repository is a direct extension of the core ACS Object Model. As such the same design tradeoffs apply.

    The content repository stores all revisions of all content items in a single table, rather than maintaining separate tables for "live" and other revisions. The single-table approach dramatically simplifies most operations on the repository, including adding revisions, marking a "live" revision, and maintaining a full version history. The drawback of this approach is that accessing live content is less efficient. Given the ID of a content item, it is not possible to directly access the live content associated with that item. Instead, an extra join to the revisions table is required. Depending on the production habits of the publisher, the amount of live content in the repository may be eclipsed by large numbers of infrequently accessed working drafts. The impact of this arrangement is minimized by storing the actual content data in a separate tablespace (preferably on a separate disk) from the actual revisions table, reducing its size and allows the database server to scan and read it more efficiently.

    VI. Further Reading

    The Object Model provides a graphic overview of the the how the content repository is designed. The model links to pages of the API Guide that describe individual objects. The Developer Guide describes how to address common development tasks using the content repository.


    karlg@arsdigita.com
    Last Modified: $Id: design.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/index.html0000644000175000017500000000417010061640733024574 0ustar frankiefrankie ACS Content Repository

    ACS Content Repository

    ACS Documentation

    karlg@arsdigita.com
    Last Revised: $Id: index.html,v 1.2 2004/06/09 16:59:07 jader Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/install.html0000644000175000017500000000761207253523116025143 0ustar frankiefrankie Content Repository: Installation

    Installing the Content Repository

    Content Repository

    The content repository is a part of the core data model of ACS 4.0 and greater, and is loaded automatically as part of the ACS installation process.

    If you wish to install the content repository in a database schema outside the context of ACS, the following instructions apply.

    First install the data model and PL/SQL API:

    1. Obtain the latest distribution of ACS.
    2. Run the SQL script packages/acs-kernel/sql/acs-kernel-create.sql to load the core ACS Objects data model.
    3. Run the SQL script packages/acs-workflow/sql/acs-workflow-create.sql to load the workflow package.
    4. Run the SQL script packages/acs-workflow/sql/acs-content-repository-create.sql to load the content repository itself.

    Java

    In additional to SQL and PL/SQL, the content repository implements a limited set of key methods in Java. The XML import and export methods are dependent on Oracle's XML Parser for Java v2, available from the Oracle Technology Network:

    http://technet.us.oracle.com/tech/xml/parser_java2/index.htm

    To load the XML parser, download and untar the distribution. Load the class package lib/xmlparserv2.jar into Oracle from a shell prompt:

    $ loadjava -user user/password xmlparserv2.jar

    Finally, load the SQLJ files in packages/acs-content-repository/java:

    $ loadjava -user user/password -resolve *.sqlj

    Installation of the data model and API should now be complete.

    Intermedia

    The content repository relies on an Intermedia with the INSO filtering option to search text within a wide variety of file formats, including PDF and Microsoft Word. When the index on the content column of cr_revisions is built, the INSO filter automatically detects the file type of each entry and extracts all available text for indexing.

    If your searches are not returning any results even after rebuilding the index, INSO filtering may be silently failing. You can verifying this by checking for entries in the ctx_user_index_errors view following an alter index statement.

    If you experience errors on a UNIX system, check the following:

  • The operating system user running the Oracle database must have execute permission on the files $ORACLE_HOME/ctx/lib/*.flt.
  • The directory $ORACLE_HOME/ctx/lib must be in the $PATH environment variable of the operating system user running the Oracle database.
  • The directory $ORACLE_HOME/ctx/lib must be in the $LD_LIBRARY_PATH of the operating system user running the Oracle database.
  • The LD_LIBRARY_PATH environment variable must be specified in the entry for PLSExtProc in the $ORACLE_HOME/network/admin/listener.ora. For example:
        (SID_DESC =
          (SID_NAME = PLSExtProc)
          (ORACLE_HOME = /ora8/m01/app/oracle/product/8.1.6)
          (ENVS = LD_LIBRARY_PATH=/ora8/m01/app/oracle/product/8.1.6/lib:/usr/lib:/lib:/usr/openwin/lib:/ora8/m01/app/oracle/product/8.1.6/ctx/lib)
          (PROGRAM = extproc)
        )
    

    If your searches are still failing even after following these instructions, try a simple test case to determine whether the problem has something to do with the content repository data model itself.


    karlg@arsdigita.com
    Last revised: $Id: install.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/object-model.gif0000644000175000017500000002442007253523116025636 0ustar frankiefrankieGIF89aôÕÿÿÿÿÿÌøøøïïïïï¿åååÞÞÞßß²ÖÖÖÌÌÌÏϦÄÄÄ™Ìÿ½½½¿¿™¿ïµµµ¯¯¯¯¯Œ†²ß¨¨¨|¦ÏŸŸ™™™s™¿ŒŒŒriŒ¯‚‚‚fzzz_ŸtttVrooYfffLf__LYYYCYoOO?9L_??2/?O&2?//&&/ þ!ù4,ôÿ@€pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß¼3âãäåæçèéêëìíåðàò3 ö÷øùúûüýþÿÞ›1  <ó&ª'°¡Ã‡Î0@±À€x 3b±£Çþf4XE„SþᲥˈ3.P€°À$J•8õ°|ɳg¿ÿ2\€àdΣwvú\ºt(,0p©Õ9J™ju9c¡ ¨Þ¼J–MÖ€0`ØÊ_×.4@Pµ¬]5gû= !ƒ\Š-I„¹!Å÷qçֽ˸LÞ}\Ì‘‚Dо.@®˜Aâcˆ,€+—îØÆ¨¿<ÖGb Àö*ˆ[kïÁ$*àSû`nÚ$§À»î »‰û&A{BŠ.0Lhˆ¸ôâÔØ¹¬Î'y0¾é÷>ôǶ¸çãN0`AŽ8ûq0t38ON}ëqVW|:»+Û¹5mû` Î`HÚ|ÐM÷œ 7ÃpœÐ Ï-(Ž NÆÿ€sÐIGÝh‰™ö߉W8Ѐýlf˜=ˆ£›8È1` Cìå×sj‰3öÜhOk ŽH(&9…ŠöH¦>.° [Ž®5[âØC%ƒæXÉ¢Y2@¤hGš¨ä™N0ÉÀ“ˆ^‡EÞØ•`âÈ™=0ÌPãÒ)¤˜ ‘Yâuh’å;¡åxÀØ× ˆ7Ó~†É¤ÆMö ÚS)C­Á –‘ƒöW(R3`¡¦=l6¤øTðÞdù1HÛŸàÇ€…ä™÷埌W$@û™yª¡ª25Á¨ -K " Ä'q¤Zgê±iªí¶Üv»ÎA]¤šb[ä‚T,¡ØâUÿîº0tFª&Ëî¼ú‘hmºn¬J/¹Uônâ¸ïÀ?Ù‹$¾f¬p>"‘dºKÊÛÑ}å ËùŒYî¹×"L†¾ 7%M6,qD­ÉÀÂÊ+?Ò—º±ÁÆzŒÈ!÷”PD•âÉi Ùm¹Uyq$ø&ó‡!ðlbPo5ÂD3Ä6sÎ/9•TbÅ;®GBç#i¯ž~‰Þ†2ó*Ž  fqœu¶\+ÜÕWr…ýóØŸƒå vjëšmÚØWh¹Ê°›2v N×}uÇw«ÖQZÏæ-è½ Löd,¯l‹÷Ä8ÃŒ,næ²…¡m©Z’5šÿrKvgnƪ{wÔd{çQaŸ Е}Ï–i{¹ócÎJNgÊ[]&Öº{¡fd“UvtšÝéÑg{¹Ø¢^>†KËyøs+Ü“!û.S èúÅל}j† µl0³ nä$åü&6±Òª­ÞðCωx$r¾ÐUak÷ÛG°f)IQŠE7bÎäêÄœIni–»æö§5u'\“ï@㫵Mj=íy€ôâ“6ÚgzÕ2Þ‘çêÅfV2¨ÎÆØÙãl®‘ó‡=¶Ð!ÓÇ '³ uB¢…8Ä> ]èA Q ÿ‘»ãN+ÎúŸ˜´Ðÿ‘'m´¢æ¨3} F2bPþ´¥©åF?ÒÓà†„B ª}ôÜÀò¨Çp9ÄIÜ‘ku¸OiI|èpÞ"3ˆÅ º1}’d%+¹5AÎM>*ã=ÜçÉMâI‘ àÓŠn¦)쑤Si½R±r Q å(Fª/ä¥0•²M®–¡b–#Ì%s^«<&ÿѪ·ÁêhHTâ¯Â”+qtÆm4lÞ(7ØÈ˜rˆoüf[Â)NTò$ŽÍÒ&´Öèi÷æ8õÙ”„ö3Ÿ Õ ?¡°HFtŸ}¨E/º•‰>¡¢Âä([<ÊBo™C¤Íh@êM”2…¤ÿûc©¶ó'{ Çe©dÞ/¹yÊ šô§@ j9TªG™® z€«âöM^Œ¨Å‚`€\  V·ÊÕ®zõ«` «XÇJV¾…¥Š%]è,³Ä=ÇÁ°iO+ Ôx“ðLëhÑ`ÑfIœ„<ŒÅgO`ö” S5À(€à±¬d'KÙÊZö²˜Ílf¿6´ÆT­ƒ«@_dpGx®c•‡>¿]‰}Ñ ãÉ Éè‰{oË'ŸjX|^aH®ÚX÷¸ÈM®r—ËÜæ:÷¹Ðu.ÏŠâÙì•¢H}Û8žÕ¸ÇM†O®±é U˜!O¹ÊqÁr"¸ÜäGøÌi^ò—× ã3Ýù-j>„›<çº-ˆnj¡:ýéÛŠ9Á•N ¦ ±VÅ*Y·Îÿõ®{ëfõÛ}©î «'v±Õ¬Ú×Îö¶¯³bÏ·O¡N÷ºŸƒÔú¶:€+\âF÷àÿ>]#Ë=¤>犻ð~gKçw¿ýM°ä'OùÊK~Á%ƒäFÿ‘~à$(ÏœÞiŒùô¨O½êQ_äꊼçœÉHJbxqêýêÀ5³æÌûÞûþ÷¼¯sè§áØcqd ~Önif;ÿùÐÿ4ãÇ>Sãw>(C¡®ò=vû«;úà²ÝJ€Y¿nO‰Jg·°îKÜüç·ZØ]7÷ïöuèË‘Þ~lèw|á 4ÂÓÄSJ@WTþÒ"”ató›lÿ A>'wd ˆþs4£WtÄË TÇ‘Ä0AѲMöe{X|üðBß³U=T8´]ƒòAé(ºòsøvLöGrø—Eù°ErMgä!aDc'iCFh"DúÃJE¸r (}”&¦:¬3H–">†Ô#ñöZâK¼5„Zø‚þô˜%šÄe,RK[J‡S'Œ„?õ%DD‡›¯$?±ÄhuâhÒôIù‘'{Ò'ë*õ„P m‚ˆxÉ´!Ë$qƒkÏ´dxèL™ÒkL¸ˆr£÷Ö‚x ÿåô*Ï"+ߦN¦ØNwO6¸‡À",XHÿËw‰-åóèöÆÕ‹ì‡/[˜ ­ÁÌŒÕØx¬ètÖxýÔŒ<ZéÐ9>QSý +'u¿ÈŠ]¸,“'*³2w4Ž{ÆtŽ•ø`ÖðŒ¡<ôWx5Ð4º(#ïvLUSé4€ñóõn¹tþ8inXIÞ8tëØe3[OÂ.à;ß#OÒ.`[иR2°,äI‘ªø†êØsB³Aƒ‘eÏãÓ±T@ÈH„³„çõ'ÏÑ( [9SÓ7ÙâÈ0èh3¹tÉBó¢¢Ïa[B’£Ä•ª!äXp}ö'VyHÿYI‰©€3 ƒ1S$Ó’¶DJkØ>Yò'g37wR—æà‡žò”ÜGGB“hG[)3u9O^B@5B%x >±qŒ wŸÕ–qH•KhÎôs©1|ÉŸØéNþ–m7²à™š©ˆ2™S¹eSæ¥)ŒØ‡] ³ò$â6.AM2’›§¥–1i‘ªbwÎéœÓ§y˜(o¨H˜’hñ8P©Sa†™Ö…ÛHagÔ7˜Æü˜ýç–Ûlñyÿ"Á¸/ÐD #ébuFgq C{¾qâiú‰-üùžÔ|™×Mõ‰ ±™…Ìéžÿê)Ø×3št z,:¡l”~`s¡W›:ì9:¡{qWi)ê z* œ{1ª%úki‰/z½#€Q€q€ÊHŸÕ˜£:ºœl¹™zá€Þ1ž1‰*¢-0Ï™¥Pw¢û©®ñ?H4h@ù„$H ‚d…+“²tREUY—U_W§vz§b5ËØ¥=Ê2˜:48C¹èƒ"™ƒ³±ƒâpm„zCqIIú¦+eiT…vŽåv–z©˜ŠYpg¥|ʤó…»‘b ÒEMF#…²T[_”FW(„JJQZÀwÃW«¶z«ÏUxœj ÿGª÷†(†K„d†œqH±¤†½D¥¡‘êxúÅ_–­Ò:­ F2 Vj3sxQ2%ôÕe‘¸›\R¢Ä‡¤T¤ :¤gz«×®îú®AÖz{Ú©ƒø…(^ñ†ˆ´®s鈵‰¦¨ž·£QEf¹wfÀ—° »°p&|Ø*žÊÄLò(ŸM£t)RSMœBªëÞù¨Ì «dvlâW²& jÑI„B劮"çtD³næj‹ïÔ’¾bŠôä—N ž¯7²Íw²@[²ä—nÙúO«AeŒ ‘Œ® ©"Kv±P´Hj¢<+sP R;µ0WµÄwµe—¡ñw£^‹µ`ËFÿ_bŽß$¶cûµ}ÊGkQiË¥E·¶lë©7 G9 òÑTW9MÓ”\1vG·­µ¸3 7".9C  é;8…Grkj†Ë ˆk.xûIù“8‰C0°“œØ“ ŵz¹©¹wËjar–Xy^‰™æêj‹º¨ ºuBÉÚ—¡©˜óH¹¦«s¶{»eû2¬Ë†Y™â*š¿Û5• Q9¼…€»q%«Ùš š‰¹ ä¼;fÒk Ô _b’Çùmq³½£D»ÏûZú¾A•²ÝX¼ ¡´)¸àÔ¾$š£äù.óJ¯Ó©µ¼Ú¶Ÿ ÷°¬¡úK¿6:{ÿó¿êÀœW»v[¢1y׊ ¶ ÜÁç·3ÙW{³Y¯ZkÁ&<µ^£~-ZÂ,À(üÂ'ì,º« ÂÖà Ú5ZÁÏ[(ã £|Áúð£–E$¤®pM²ø˜ÂHªÃGmõ¤”¥ôˆ€ßž)¿`ì-C Ŷù¥@bj‚!ˆ@¢@%ÈW'Ø*h™ûªOŒXrzUtЧ|ÜÇuª§FŠžÚú“3‚ZC8(=îAŠ:!8بè:¿WpvŒU©™zɘl©›*Á8J,¾:8ì5…«j¦¨Êh^Ä>¦t¼³]¬;z'«~‡«²<˵ª«œ¼¿ÁöÉÿLpb(HK¬<‚H¾l®ËÊvœ™“üxÐJ­ÌÜÌÒªÁ ½¸ÌKÆ­uø­wȯyxåZ—:[ÇN{Çx\c7¯æ|Îî*¯&ƒ÷Ê>ùj—Z¦‹e؈¸¤K»æÍÜè‚’ZºÇ°þüÏ ë°Œ]±£;±ÎäA÷\†Ô¤)kF{•‘¬ÏRE²A{Ñ'+¿pjÀ¯è²±˜N2›’Ù†‹7;O¼ØÄ6,£[àlÝÒÏ7´ëŒÃý0ŒQŒm*G¼1Ñ«H›œx1 Äþ§|™­,z‚IÐá,«,R?&Ñ[uÓ+&E<¡1åÆ0º¬œáŒÌÕÐÉ…¸áŽK-ÿCnLõY]¥ÑìÔGýQõ;Ö@p!Òñ·LS¤TW¹4*þ–4á6-c=ÀE]mdÒ‚!Ð9©EeÝæ‘‘ûƒ¤$™‹Z#‡*.€ÄàìÄ\M ^í ¨d¨^ôóI¡Ëd3`;ɺ ’=!À=­E#‘Ï;ÝÕQ@nA¨a°o½+»ølKîCJÚÕm\|Ì^ÌÓ=Z‰·ÃP&eË#>Ì+‰ª½—{¦1åà¨mhÜ®\ØyÖòá&6h¸Ô»Ü›Ú»YSØM8´ËšÒ@­™d C}'`… k¢½¼¾KÝë}Ý (²‹Òk}&O= ]ŽÒã^ÿ±’mÑÓÍ›À-à-®,¸ÕÇMÛ:-ñ@3MàÞj.áoçR#®$ . îŠâÀp*þÃlMß2¬Â4Nâ6¾Ã3LÀí‰ÜD¬¢9Îâ%>lCMÔÜmÔ;>ÅC½âIÒâQ[Ûêä(ådÛÓ>Gå'bå¯à¾aüå‡2äO^äJ€uzìÇhžæcÈØäU@Éi—Ér>çšÊÂò]ãn^°L«´Üç~.]#|ç:žçøõ¬‘ç̈žèÍ Lèê \¥WÎè<é”dêÌÁŽþèüŒ°ÝéžþfÝæniíÒ¦î|½¤£Nê?{ê®îi0髾¢ÀåuKëÿµNæ¸N ¶~¸»> ½Ž¹¿žëK>ì™ì«€ìÆ.ÊžºËþ ÍN¼ÏÞ Ñ~ Õ>íkpí¥ íØ~3ºÞíŠÀíÀîš îÄNî—`î¡ÀŸ`Þîìê³ÍÙX¾‹gž’œén}äž‚Àóyìîþïèï=ë<®ÂL•П*^ïk­î ÄS® |ìú¾ï¡~žÏñï)Âzà+QñóqðòíðÐ>ï8¢ëWî ŸÁÖÍ$ï ?ž4Ü7‚þñÏñÚ7ÐÎóx…¿(¥å{ ð?ò-<ðòÞ¶Fü;AJLœášýBÏÔ3V·\ìùÞ€ÝWÜR:>ʺÝîÿQ_Ó9­œƒÙæ2ÆÓ ñˆmh<@jü@fo,Wk̪7­Ö*¯lrÚûð¹ ø6ûRj/ ÿ§0¨…Ï >d¨x»C=èÈ?ɾ÷La^nˆD' Öu²ž¥:søÑ ñHª?9ªfD…NxªMØú«ªÊ:ð|ïYt#T”wR“ľ>~¥VoØú¡ËÀº:Ã<¬:R¬h˜HdàÅö ðì²#nCkÅAßÎü6÷íwIÕÜ$×ÌIàjŠÛÜ%ò ýµÏëLa ‘#Ì^Æß¶Þoƒ}ºÏäöš8@À`¤f³ÉpÆ20Å£ˆ6ÿgBÖŒ$„Í6‡T…¤äNÏF#Î¥uûŸ×ïù}ÿÿ¯Jm°pe&Ekædé*«áá#Å¥h 2sÍ Nްo&”´Ôô5U5pµNPs‰hÆ…E¦èChÂvãÖêrLðŠ·ÂLæ£R)ŒªlS“ó-n®u›ûô|Âr\æ‰ád6-…ƒäÈëpœª ûs{´›¿ßÿßϾUßÀm84C/4®‘ñÈÙ0!,eAg‰…91LÈ0ÐU¤¬kž´4Ù`½BD`°pYk.EB,ùp‹A¥y±Î¨´v$¨'‰5J ª”>M ÿVÏi5jð`}Á`N$ÐlBv ÄÒƒ"]–˜a³HË-ˆ&qA‚DC²` ܪÏk^½&Çõõûw]Áƒ £±›ooâ;K›M#N˜ )l%‘9qmÚË…—.9TqhÑzs6}zVÄ£I£>•ªkÏ\S%e}7J×»yÛët7w×Ò½‰ûœ7xr妆C¢â7d!59 2ÐõÂÇ—m^üÏß«•v7>ÏwBT^¾f‹DX¼—Þs0wôþÔk²Z!¼Óô+o¿—ëO h©à©H¦ª ’®RÐ)`p‚B á2í.lÐ8Õ>3×kÈ!ˆpdÿ™b(¿6›‘ÆqH¼7ÑP0Aš8¤/QÐÃb*K‡ínŠ ¬qTJ0Ф9Y\h$>5賯ž :¢ËITl{’L¯t\â¹¾À!"dBD&ì¨H„¤XÀënzLi+“9º°%‘%*°åG&€ËB0ht‚ ?Àj"¸ÈÒ0ŠFCoÄÚýT8°Øk…FeáËGˆìéŠ÷Ä@ÆÇ>9ýT@Î\‚¢rÒ`óÊg§P/rH¦*±Ä…/ÆÁ®ž0½©Z¾Dýr*`ÀŠÅê¢i&ۈ̰D×&ýŒ¶”[·í‘;™°ír½¡'ˆHÖØE0½DÿS•œeŽÜ~ucŠG5>²¥W_U¥“Õ,½•æydŧS÷07IüÐì¨Õ%ЙG;y¨Y†I[ÈšÀ€™Ú·\‰U®mÚ$HU¢ÞR µbcVåVáWÏÕ“Ç]™Š¥¤ô$»ÕN;!+Š( “7…˜V~žÚÖ–ÿú1Þêj’‹›i†HçfšWߟ©Æƒbž • QšC""íˆxï*Ed€…,œ.{VäÎþ;½ÑˆJpHPšb¤„ʃ nˆw®.r7Ÿ@æƒ *a„Š æz:(¿€Ä çíð•Mgˆ[m(™sç;†F¿-"sŽ¥8u[IÿÝôÓe3{ÿôà|±rñÃ|'zª‡CoeÌß§6^xÓz—{•Xg+û0ˆ÷ÔzÀ»?ƾÏ^Jb~û€Ê7ýú;ÿïóí÷Y}Ðæ§ZûãÔ¬@Ò#~¢øßÙ xÀ¬ô¯xÌ^ƒ¶@J~øc OGÁ‰Yðz,œ¡Õ@nBƒR¡ÊjÔB¾†1„a CxÂð0=+\™`€\  hÉXD#‰ITâ™ØDdˆØm¢M‡*ã¡@ paãÉXF3žiTã×È P`RŒÚõdXG;Þ4$Eõ²X« âÿ9PHC‘‰Tä"ÙHG>²‘P„@ 0Eªmñ‡Alâ&9ÙIOrò‰Q´dÊúè/ €.ÐJW¾–±”å,iYK[Þò–€ÀP€9Nm‹]ü"‰YLc³˜n„£EWJhñ• X@¨YMk^›ÙÔæ6¹ÙMozs èå(©öÇ@’éTç:Ù™NIR’œHq¦)ÿXùÔç>ùÙOþ è@zÏJ à—ÀD¥*Y‰K‡>¢u¨.yéËͳ_åá8ÚQ~¤!éHIZR“ž”£ý4 Ío¾¦1•)LÃ9΄Ê£äÒ(BQÿÚSŸþ¨"ÝéM/YÏ{©IUêR‘jÐ9•9•êT•£Ñ ^«Y5©J/JU¯~U4CÕêXÉêÓ¡òƒ`UëZÙJš¶¾®q=IZåZW»ÞõƒxÕë^ùJW¾þ°Tõk` [XÖ°‰U,é»XÇ>–{•ìd¯GYË^¶„˜ÕìfoÔXÎ~´n íhIÏ–µ©õŸjYÛÚ®º¶±U¡li[[=œÖ¶¹%-nuÛ[ÎòÖ·Áµ,p…[ÜÇ׸É5,r•ÛÜ¿2׹ѽ+t¥[]¸R׺ÙU+vµÛÝ©r×»áu&xÅ[Þ’×¼éz?‹G÷¾¾~QoQØûÛÿÜ¿ùÕï~ùÛ_ÿþÀ0~ë;_;X³3ð‚Ü`xOE¨û`Ì*øÁÖð†<ƒTRÂ~mr1ÌaŸ8Ã3ȧ@ U+°¹%FñŒiüß4 ¦-~ñj+ãÿÈ3 @ ΃î˜@Êõ1™Œâ@‘Ef&’Ťø^Ë2äjp–Üd/kxn¼@âhQ*?‹zU´bG·Ìš.Xè€ðå&ÏÊŒC%ό樹83¸'‹Ÿš£+@}A8L 0ÚÎÞ¸çôy¶,tonœãxšÉÁ ˆÁ Z`X`Ô"ذbð‚Hçÿ— ¡´´‹1M]nz h/ií¿`(ȯf ‚û*À¸/àü: *Pê$Zζv´§­ìûÀ 8@´K@€ˆ@(¨6„G k›bzúØ4§3ðÎ#»¹ÁÄž·ù l Ü—Ø1¸¯f; À8Z€¡-(¸¶þ‚$ºØµ«k(ÎÞ8ýó¼wƒgeÆñÓGy³.ìþ Þnù}‹ ûj@8€j~€€W»¤¾/°[ÀèD'<AxÇÛýñw‡<ª#'9j<.Ê^ó¥Á‰î€yÎñøû¾'5µñÛõ°Ï@Õÿ÷u@óØ<£ÞºÃƒÍઃêòKó‹@4uÃèÔ ÖºQ0ƒ|»Õ&@€]„´þð(‚¶ðÊü؉ú þÍtwß;ïÜ;=@‚#!‚hL™Î`6°6p\‘? &¸×°p0ºæ÷Uú²«}n¶Ç}¸ï¨á‰~æ—_ºÛ×-à»?=ôy•zU*!ƒT‰`ƒ9„Š|Â&feön°ÛU |sw<´‹ ìµ§¿Ù…7öûé‚Ç@8:£ÁNw—[ÞîšÎ@/úrhô`Á,°ÂK"#>€Qvä*%r$#BêæB,@Á`æÞÿÇpO8 ÕÆ!:îoÔ:ϯn/`Ô8/Ñï•ù6¯ó’ÏóœŽ p1ä*:– 6|aY4Æ„ä*„¤vÂ` -nGaă€ðÍÁ­:@ ¿ õ Ù` ­Í ñ‹ÙÒðÎÐ]jb˜A ]àÜäB*ðÐA‘ ÜbÂ#< !üÐêÕ±Ážïá°t„ðõè0 am @ÆB>²Q>¦Ž€µ¥b¾/!È´QÏ ¡O]aasÒ€¤["b#$[C raLQEPå2Œ$  ¿pÿ¬#m­öd¡C‚ žÀÓå¶àR0áe„Ñ(Vî¿:`‹ÿNLá8ÌçzpS.䜱¬&˜Ä#v¡~A ŸcjæQ0d12VeªüÀ‘¾ìáÐ.þ Žß2,Ñ„OÂ.òXñóÜÞà± Â!ÂPPä!:# ;‚k," óQ>>Âb CùKßšïÎ15@ÚP"ÕÎ -T"}®,@Ù€&U ø­Ùm'!’ÙR­ùll-²ÖbÑ4‡¨r >ô¨!õ‚q%£%÷ Ø&r¿D­àT`Ô\ÎíZÀâ&ÏøÆAÈ2â²í ÿn-gÀÙlíØ­"¯ŽÊ0Òï8cQ‚Ár°¿ÂrÙˆïòÒæhÐ$œ ØÒ.ÑOßÔ âØ0À *ûÌ/ÿ’0³Dìýükáf ïán.g ÚFMøôÍüØÏØVñ\ó¾ /÷ò#¾@S{F ˆ“4¿‚ÎØð ìú æ’î/„91oø‚o7}°3{3 `Ai¦d++‘ Õ`#JÎ }mÁà'óK-ÿçX³öbŽ0“Ïì =ÃÑâ³îÀ9÷í:Û‘/µsb¸SÚwèÂ%œ' ”ÓÊs®ìáb NMâbà>G­€¿Žÿ ÑZÀ eþ‚î:9´ó‚Î.²Ãžò?4p4á¥d $a:àÁ*+µ26„6+xÔ 4E+7ðõëŒ0ÎTÀ(]ðï+ùSE—N\Jýï6«íýpS/±óEat1"€%„ ©0l x¦…aI,àa#Ö$”ðTá²p4¾’¿  ëo,Ãm0 5 “í<›­?ßL¡DF£ >¢&E<ÄûLÒGŒE¨C ¨Àñ0‘±pzþ4S•¿8sLµtT-Š`àMà¦M€¶@&ÄàXêcR@R 0Ñ‹`{ÿfoÄSIPUÕÎXÕU§¯²Ed 1Bàæ&ÎÂ$ÑôôzUnQ ºÑTU]¡5Z5-ºEä& ¦¨Bdà .# `H@5RÄ€¨Ñ ˜&YS£+÷¢Y,!ý‚öе¿Ôu]½ÁLÑ èÅÙ„e[Mr x[Åà#x \UÒOE#aÿk'®,¥ öa]4bÅdbpf* 3b§XéÑ$¿$,d#€ö#M’QöTU–Æ-íÚQcð(‘Íç¤í&ÛÝT ÀP(k2fSŒfk6P8Ã*U62alC4õÆràfÀëäøbÿ .31]–5`ÔZãÄòÁ l‘8sYÿaeìýÀ°4­!÷"I´5mND…/èX3Î(Ïkyóo÷(p·cpcÅ&W¿žØl®>ÕŽí2³Ù$nëN3lò ûök3·j67}R6QŒiõ Ø04? ¯i-ÏIÇ¡ó ðÌ‘EÌoeWh·v“övOŒmñ«ðÈ‘B«s"'3|÷Ùìó¾$ØæÌbWy——y¥Ç\•öÄ7¿Tôín“óˆ·àmíbÀÔ OØ>ÔüJÐrasÇ—|Ë—l—%?·Øöë4×mmPÖ­Ñ xͱj/WLýw;8€w€½ÿŒDÁðáÜš'Ïp E˜‚ýÓ‚ÿƒ›¥sÅÉ, !-·ÿÒU|SmVtÎ÷y Ø^ j “†û׆Ñf8‹Øˆû¢…QfS5y‡¸0 ˆ„蓦˜Š«x‰dmÊÎu‰W±‰8˜¼ŒIŒÇ˜ŒÕèä²}·X»Ø‰ÍIê­âXŽçØ‘ì-;™U¹¸†ø‰j•$ Ysi—xÍÐòØÙxˆYÊ¥fÊ‘’»ÉÓZU‰ùÕy‘ Ÿ˜Š“;Ù“Ê©&ì6 ×’7 “mتÊJ•Wy«Dy”Kù’÷˜Ÿx§XÙ–Yù¬rãˆwÙˆey–Cë “„ÈŠÿÙ˜™“Y™—™™›Ù™Ÿ¹™}ù—?+˜À‹<   Y›·™›»Ù™Û€Ò¢lœ¦YµªŒ¥ØŠÓY=)Ï*mœÉµN‰‹"ˆ8ÀÊŸóù˜<@ÌÈŒÅ(ž k‹Àš©Þ¡Z¡š¡Ú¡¢ZפìŽZ±¹"€j;Ú£j£‰ÌÈ*Ú¢ ‹§¢iš"Y¥Wú‘=¤Kº°Nú¨>™¦kÚ“ í¥aZ yªž>̧¨ƒZ¨‡š¨‹Ú¨©SÊ•u:´jù–Ÿº¬vŠ©Sk¨ªÚª¯«³Z«·š«» §¬ÃZ¬Çš¬ËڬϭÓZ­×š­ÛÚ­ß-®ãZ®çš®ëÚ®ï¯óZ¯÷š¯ûÚ¯ÿ°[°›° Û°±[±+;openacs-5.7.0/packages/acs-content-repository/www/doc/object-model.html0000644000175000017500000000422307253523116026034 0ustar frankiefrankie Content Repository: Object Model

    Object Model

    Content Repository

    The content repository is an extension of the ACS Object Model. The following diagram illustrates the relationship among the standard object types defined by the content repository (click on a box to view a description and API summary for a particular object type):

    Note that content revisions and content items inherit separately from the root of the object model. Each item may be related to one or more revisions, but they are fundamentally different types of objects.

    Also important to note is the relationship between custom content types and the rest of the object model. You define new content types as subtypes of Content Revision, not of Content Item. This is because new content types are characterized by their attributes, which are stored at the revision level to make changes easy to audit. Custom content types typically do not require additional unaudited attributes or methods beyond those already provided by the Content Item type. It is thereful almost never necessary to create a custom subtype of Content Item itself.


    karlg@arsdigita.com
    Last revised: $Id: object-model.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $openacs-5.7.0/packages/acs-content-repository/www/doc/uninstall.html0000644000175000017500000000306107253523116025500 0ustar frankiefrankie Content Repository: Uninstalling

    Uninstalling the Content Repository

    Content Repository

    The content repository includes an uninstall script, sql/content-drop.sql. This script does two things:

    1. Drops the attribute storage tables for all content types you have defined.
    2. Drops the general tables for the content repository.

    The uninstall script does not do the following:

    1. It does not delete rows from the acs_objects table. Many other tables reference the object_id column in this table, so there is the possibility that the uninstall script will encounter foreign key reference errors.
    2. It does not delete types from the acs_object_types table. As for objects themselves, it is impossible for an automatic script to properly handle disposal of all foreign key references.

    Because of what the uninstall script does not do, it is only appropriate for removing the content repository in preparation for removing the entire ACS Objects data model. If you wish to upgrade an existing installation and cannot afford to lose your data, you must run an upgrade script rather than uninstalling the entire data model.


    karlg@arsdigita.com
    Last revised: $Id: uninstall.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $openacs-5.7.0/packages/acs-content-repository/www/doc/todo.html0000644000175000017500000000347007253523116024440 0ustar frankiefrankie

    To Do List for Content Management System

    
    Documentation
    
    Write ASAP.
    
    Sign In/Out
    
    --Eventually need to use regular acs40 API (maintain existing interface)
    
    Work Items 3
    
    --Display deadlines highlighted depending on whether the deadline has
      passed
    --Add ability to check items in and out in addition to simply finishing
      enabled tasks.
    
    Site Map
    
    --Tree widget is buggy (not updating correctly on delete, not showing blue
                            arrows in proper context, etc.) 1-Stas
    --Improve design of folder listing (sortable by name, date, size, mod_time) Michael
    --Symlink title is confusing (Stas)
    --Ideally bookmark graphics show change to show items that are currently 
      marked.
    
    Items
    
    --UI around each item needs polishing (better display of revisions etc.) 
    --support for display and editing of additional simple attributes 2
    --for now just allow assignment of one template. 1-Karl
    --We currently have no way of setting access controls (also applies to 
       folders). 1
    
    Content Types
    
    --Not much to do here, seems OK.
    --Need UI for creating content types, adding attributes, etc. (3)
    
    Subject Categories
    
    --Need to reintegrate simple category table (depends on message catalog)
      Previous UI was functional, should be reusable.
    -- 1
    
    Message Catalog
    
    --Remove as a module for now.
    
    Users
    
    --Should display the party hierarchy here, with tools for adding/removing
      users.  Parties and usersshould be markable to the clipboard so they can 
      be used in building workflow contexts and access control lists.
    -- 2
    
    Workflows
    
    --index.tcl: Display a list of available workflows, add/remove users from
    the eligible list for each transition, etc.
    --reintegration with notifications!
    
    Clipboard 
    
    --think about improving UI for this. 2
    
    

    Last Modified: $Id: todo.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $

    openacs-5.7.0/packages/acs-content-repository/www/doc/tutorial.html0000644000175000017500000011205010061640733025325 0ustar frankiefrankie ACS Content Repository Tutorial

    How to use the content repository

    by Jade Rubick

    Why use the content repository?

    Let's say you're a developer making a package for OpenACS. You've heard statements like, "every package should use the content repository", or maybe a developer has suggested that you use it. Or maybe you just stumbled across it. Why would you want to spend your time reading this document and wasting a good afternoon when you could get started coding right away?

    The simple answer is that the content repository (CR) gives you many different things for free:

    • support for versioning
    • hierarchical organization of items
    • permissions
    • extending your tables dynamically
    The content repository was created to solve many of the common problems we as developers face.

    State of this document

    This is not a perfect introduction to the content repository. But hopefully it will be a skeleton that can be developed further into an excellent, helpful tutorial for people new to the content repository.

    Introduction

    For the sake of an example, I'm going to use a Tasks application. This application will keep track of all the tasks of an organization, deadlines for those tasks, and who needs to work on them.

    The reason I might be interested in using the content repository (CR) in this case is that I can keep track of all the changes to a particular Task, so that if someone changes the deadline on an item, I can see what the original deadline was. In addition, I as a developer would like to have sub-tasks, and sub-sub-tasks, so I can have a whole hierarchy of things that need to be accomplished. Big tasks can be sub-divided so that several people can each do their particular parts.

    So I decide to create a Tasks table. Each of these Tasks has various information associated with it, such as deadlines, descriptions of what needs to be accomplished, and so on:

              Task
              Title
              Description
              Task Number
            

    Overview

    First of all, let's get some terminology out of the way. Columns of a table are referred to as attributes in content repository-speak.

    The steps to set up your data model are as follows:
    1. What attributes do you want?
    2. Define tables
    3. Describe attributes

    What attributes do you want?

    The first step is to decide on what part of a Task you'd you'd like to have under revision control, and what portion you'd like to have just one version of. In our case, the only thing we wouldn't want under version control is the Task Number. This will be a unique identifier for the task, and we don't want that changing every time someone edits it.

    For our simple example:

              Title - want versions
              Description - want versions
              Task Number - do NOT want versions
            

    Define tables

    You will have two tables: one with versioned attributes, and one without versioned attributes.

    Convention: often, developers will name the first table by what it is (in my case pm_tasks), and the second, versioned table by the same name, but with _revisions at the end. Thus, I'll name my second table pm_tasks_revisions.

    This is actually very easy:

    Versioned portion:

                create table pm_tasks_revisions (
                task_revision_id
                integer 
                constraint pm_tasks_revisions_id_pk
                primary key
                constraint pm_tasks_revisions_id_fk
                references cr_revisions(revision_id)
                on delete cascade,
                title
                varchar(100),
                description
                varchar(4000)
                );
              

    Unversioned portion:

                create table pm_tasks (
                task_id
                integer
                constraint pm_tasks_id_pk
                primary key
                constraint pm_tasks_id_fk
                references cr_items(item_id)
                on delete cascade,
                task_number
                integer
                )
              

    One thing you have to be careful of when creating these tables is that there are no columns that have the same names as any of the columns in the cr_items and cr_revisions tables. For example, you can't call you key on the pm_tasks_revisions table revision_id. Why? There are some views that are automatically generated that combine these tables for you, but they won't be created if the names conflict. I'll describe what these views are later, but they are useful. You were warned.

    Notice that each table uses as its primary key a reference to either the cr_revisions table or the cr_items table. A content item is basically just some content: either text or binary data. The contents revisions table keeps track of which version from the tasks_revisions table is the most current, and which one is live.

    All this is going inside the sql/postgresql/project-manager-create.sql file. Your name will be different of course.

    Describe attributes

    After we've created the two tables, we need to let the content repository know that we have a new type of structured data that we are storing in the content repository. Tasks are a "content type", because they have data associated with them, such as when they are due, and what needs to be done.

    I thus need to to

              --create the content type
              select content_type__create_type (
              'pm_task', -- content_type   
              'content_revision', -- not sure what this is
              'Task', -- pretty_name
              'Tasks', -- pretty_plural
              'pm_tasks_revisions', -- table name
              'task_id', -- id_column
              'content_revision.revision_name'
              );
            

    You then need to add in all the attributes, so that the content repository can do some magic things behind the scenes. The content repository doesn't know about what's inside of the pm_tasks and pm_tasks_revisions tables, so we teach it:

              -- add in attributes
              
              select content_type__create_attribute (
              'pm_task', -- content_type
              'start_date', -- attribute_name
              'date',     -- datatype (string, number, boolean, date, keyword, integer)
              'Start date', -- pretty_name
              'Start dates', -- pretty_plural
              null, -- sort_order
              null, -- default value
              'timestamptz' -- column_spec
              );
              
              select content_type__create_attribute (
              'pm_task', -- content_type
              'end_date', -- attribute_name
              'date',     -- datatype
              'End date', -- pretty_name
              'End dates', -- pretty_plural
              null, -- sort_order
              null, -- default value
              'timestamptz' -- column_spec
              );
              
              select content_type__create_attribute (
              'pm_task', -- content_type
              'percent_complete', -- attribute_name
              'number',           -- datatype
              'Percent complete', -- pretty_name
              'Percents complete', -- pretty_plural
              null, -- sort_order
              null, -- default value
              'numeric' -- column_spec
              );
            

    Side effect: once you've created the content type, the content repository creates a view for you called pm_tasks_revisionsx. Note the x at the end of the name. If you're using Postgres, I believe it will also create a view for you called pm_tasks_revisionsi

    Why are these two views created? the x view is created for selection, and the i view is created for inserts. They join the acs_objects, cr_revisions, and our pm_tasks_revisions tables together. Try viewing them to get an idea of how they might be useful.

    Advanced topic: Creating types and attributes

    It is also possible to dynamically create tables, and extend them with extra columns. You could do this by using create table or alter table add column statements in SQL, but this also adds in some meta-data that will be useful to you. The disadvantage is that you have to call the content repository API. The advantage is that someday you'll be able to do really cool stuff with it, like automatically generate interfaces that take advantage of the new columns and tables you've added. Another nice thing is that all that messy business of defining your attributes through the API is taken care of.

    Types is the content repository are another term for tables, although that doesn't explain it completely. Types are also kept track of within OpenACS, in the acs_object_types table, so the system knows about the tables you create, and can do some intelligent things with them.

    A lot of the intelligent things you can do with this information is still being built. But imagine for example that you are using the project manager package I've written. You work at an ice cream company, and every task that is done also has an associated ice cream flavor with it (yeah, this isn't a good example, but pay attention anyway). If I've written the project manager to take advantage of it, when you add in this extra attribute to the pm_tasks_revisions table, the UI aspects will be automatically taken care of. You'll be able to select a flavor when you edit a task, and it will be shown on the task view page. This is the direction OpenACS development is going, and it will be really really cool!

    First, I'm going to describe how to extend other content repository tables using the CR API. Then, I'll describe how to set up your own tables as well:

    As you recall from earlier in this page, attributes are just another term for columns in a table. The Content Repository has a mechanism for adding and removing columns via the pl/sql API. If you check your /api-doc: /api-doc/plsql-subprogram-one?type=FUNCTION&name=content%5ftype%5f%5fcreate%5fattribute , you'll see that there is a way to extend the columns programmatically.

    Why would you want to do this? For project manager, I decided to do this because I wanted to customize my local version of the projects table, to account for company-specific information. That way, I can have a separate edit page for those types, but not have a separate table to join against.

    . Instead of doing this:
    alter table pm_projects add column 
            target_date  date;
    
    I can do this:
    select content_type__create_attribute(
            'pm_project',
            'target_date',
            'date',
            'Target date',
            'Target dates',
            null,
            null,
            'date'
    );
    
    A very important advantage of this method is that it recreates all the views associated with the pm_projects table, like pm_projectsx. If I did an alter table statement, all the views would not contain the new column.

    Note that I believe you CAN create foreign key constraints, by putting them in the column spec (the last column):

    select content_type__create_attribute(
            'pm_project',
            'company_id',
            'integer',
            'Company',
            'Companies',
            null,
            null,
            'integer constraint pm_project_comp_fk references organizations'
    );
    I have no idea of whether or not that is supposed to be legal, but I believe it works.

    Jun was the one who originally talked about the possibility of storing all the revisioned columns in a generic table.

    How versioning works

    You then need to define a couple of functions, that do all the nasty work of putting everything in the right tables. The general idea behind it is that the revisioned information is never changed, but added to. Here's how it works.

    When you create a new task, you call the pm_task__new_task_item function (which we'll write in a little bit). This function creates both a new content item, and a new content revision. Information is actually stored in four tables, believe it or not: cr_revisions, cr_items, pm_tasks, and pm_tasks_revisions.

    The task number is stored in pm_tasks, the title and description are stored in pm_tasks_revisions, and some additional information like who entered the information is stored in cr_revisions and cr_items.

    Whenever you make a change to this item, you don't change the table yourself, but add a revision, using your pm_task__new_task_revision function (which we'll write in a little bit). This function adds another revision, but not another item or cr_item. After you've added another revision, you'll have two revisions and one item. Two entries in cr_revisions (and pm_tasks_revisions), and one item in cr_items and pm_tasks.

    The cr_revisions table keeps track of which item is the most recent, and which item is "live". For the edit-this-page application, for example, this is used to keep track of which revision to a page is actually being served to users.

    In your code, you'll use your pm_tasks_revisionsx view, which joins the pm_tasks_revisions table with the cr_revisions table (and it might even join in cr_items -- I forget at the moment).

    Defining your pl/sql functions

    You can see the actual functions used in project manager via the CVS browser's entry for project-manager. Note these are a little more expanded than what I've used in the examples above.

    select define_function_args('pm_task__new_task_item', 'task_id, project_id, title, description, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, creation_date, creation_user, creation_ip, package_id');
    
    create function pm_task__new_task_item (
            integer,        -- task_id
            integer,        -- project_id
            varchar,        -- title
            varchar,        -- description
            timestamptz,    -- end_date
            numeric,        -- percent_complete
            numeric,        -- estimated_hours_work
            numeric,        -- estimated_hours_work_min
            numeric,        -- estimated_hours_work_max,
            timestamptz,    -- creation_date
            integer,        -- creation_user
            varchar,        -- creation_ip
            integer         -- package_id
    ) returns integer 
    as '
    declare
            p_task_id                               alias for $1;
            p_project_id                            alias for $2;
            p_title                                 alias for $3;
            p_description                           alias for $4;
            p_end_date                              alias for $5;
            p_percent_complete                      alias for $6;
            p_estimated_hours_work                  alias for $7;
            p_estimated_hours_work_min              alias for $8;
            p_estimated_hours_work_max              alias for $9;
            p_creation_date                         alias for $10;
            p_creation_user                         alias for $11;
            p_creation_ip                           alias for $12;
            p_package_id                            alias for $13;
    
            v_item_id               cr_items.item_id%TYPE;
            v_revision_id           cr_revisions.revision_id%TYPE;
            v_id                    cr_items.item_id%TYPE;
            v_task_number           integer;
    begin
            select acs_object_id_seq.nextval into v_id from dual;
    
            -- We want to put the task under the project item
    
            -- create the task_number
            
            v_item_id := content_item__new (
                    v_id::varchar,          -- name
                    p_project_id,           -- parent_id
                    v_id,                   -- item_id
                    null,                   -- locale
                    now(),                  -- creation_date
                    p_creation_user,        -- creation_user
                    p_package_id,           -- context_id
                    p_creation_ip,          -- creation_ip
                    ''content_item'',       -- item_subtype
                    ''pm_task'',            -- content_type
                    p_title,                -- title
                    p_description,          -- description
                    ''text/plain'',         -- mime_type
                    null,                   -- nls_language
                    null                    -- data
            );
    
            v_revision_id := content_revision__new (
                    p_title,                -- title
                    p_description,          -- description
                    now(),                  -- publish_date
                    ''text/plain'',         -- mime_type
                    NULL,                   -- nls_language
                    NULL,                   -- data
                    v_item_id,              -- item_id
                    NULL,                   -- revision_id
                    now(),                  -- creation_date
                    p_creation_user,        -- creation_user
                    p_creation_ip           -- creation_ip
            );
    
            PERFORM content_item__set_live_revision (v_revision_id);
    
            insert into pm_tasks (
                    task_id, task_number)
            values (
                    v_item_id, v_task_number);
    
            insert into pm_tasks_revisions (
                    task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked)
            values (
                    v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, ''0'');
    
            PERFORM acs_permission__grant_permission(
                    v_revision_id,
                    p_creation_user,
                    ''admin''
            );
    
            return v_revision_id;
    end;' language 'plpgsql';
    
    
    select define_function_args('pm_task__new_task_revision', 'task_id, project_id, title, description, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked, creation_date, creation_user, creation_ip, package_id');
    
    create function pm_task__new_task_revision (
            integer,        -- task_id (the item_id)
            integer,        -- project_id
            varchar,        -- title
            varchar,        -- description
            timestamptz,    -- end_date
            numeric,        -- percent_complete
            numeric,        -- estimated_hours_work
            numeric,        -- estimated_hours_work_min
            numeric,        -- estimated_hours_work_max
            numeric,        -- actual_hours_worked
            timestamptz,    -- creation_date
            integer,        -- creation_user
            varchar,        -- creation_ip
            integer         -- package_id
    ) returns integer 
    as '
    declare
            p_task_id                               alias for $1;
            p_project_id                            alias for $2;
            p_title                                 alias for $3;
            p_description                           alias for $4;
            p_end_date                              alias for $5;
            p_percent_complete                      alias for $6;
            p_estimated_hours_work                  alias for $7;
            p_estimated_hours_work_min              alias for $8;
            p_estimated_hours_work_max              alias for $9;
            p_actual_hours_worked                   alias for $10;
            p_creation_date                         alias for $11;
            p_creation_user                         alias for $12;
            p_creation_ip                           alias for $13;
            p_package_id                            alias for $14;
    
            v_revision_id           cr_revisions.revision_id%TYPE;
            v_id                    cr_items.item_id%TYPE;
    begin
            select acs_object_id_seq.nextval into v_id from dual;
    
            -- We want to put the task under the project item
    
            v_revision_id := content_revision__new (
                    p_title,                -- title
                    p_description,          -- description
                    now(),                  -- publish_date
                    ''text/plain'',         -- mime_type
                    NULL,                   -- nls_language
                    NULL,                   -- data
                    p_task_id,              -- item_id
                    NULL,                   -- revision_id
                    now(),                  -- creation_date
                    p_creation_user,        -- creation_user
                    p_creation_ip           -- creation_ip
            );
    
            PERFORM content_item__set_live_revision (v_revision_id);
    
            insert into pm_tasks_revisions (
                    task_revision_id, end_date, percent_complete, estimated_hours_work, estimated_hours_work_min, estimated_hours_work_max, actual_hours_worked)
            values (
                    v_revision_id, p_end_date, p_percent_complete, p_estimated_hours_work, p_estimated_hours_work_min, p_estimated_hours_work_max, p_actual_hours_worked);
    
            PERFORM acs_permission__grant_permission(
                    v_revision_id,
                    p_creation_user,
                    ''admin''
            );
    
            return v_revision_id;
    end;' language 'plpgsql';
    
    
    -- The delete function deletes a record and all related overhead. 
    
    select define_function_args('pm_task__delete_task_item', 'task_id');
    
    create or replace function pm_task__delete_task_item (integer)
    returns integer as '
    declare
            p_task_id                               alias for $1;
    begin
            delete from pm_tasks_revisions
                    where task_revision_id in (select revision_id from pm_tasks_revisionsx where item_id = p_task_id);
    
            delete from pm_tasks
                    where task_id = p_task_id;
    
            raise NOTICE ''Deleting pm_task...'';
    
            PERFORM content_item__delete(p_task_id);
            return 0;
    end;' language 'plpgsql';
    

    Explanation of the columns in cr_items and cr_revisions

    cr_items:
    item_id - unique id for this item, will be different than the revision_id
    parent_id - used to group items into a hierarchy (see below)
    name - this is used to make a URL by the content repository. It must be unique per content folder. You can use a number, or something like project_231. One way to do this is to set it equal to a title plus the item_id.
    locale - not sure, probably for internationalization support
    live_revision - this is equal to the cr_revision table's revision_id that is the live version
    latest_revision - this is equal to the cr_revision table's revision_id that is the latest version
    publish_status - not sure
    content_type - not sure
    storage_type - not sure, probably text or binary?
    storage_area_key - not sure
    tree_sortkey - a utility column used in hierarchical queries.
    cr_revisions:
    revision_id - a unique id for this revision.
    item_id - a reference to the item_id for this revision
    title - you can use this for your application. For example, My Big Project
    description - you can use this for your application, as a longer description.
    publish_date - the date this was published. Not sure if this is for your use, or internal
    mime_type - the mime type.
    nls_language - I believe this is for internationalization
    lob - the binary content.
    content - the text content.
    content_length - the length of the text or binary content?

    Structuring your data into a hierarchy

    The content repository also has a very useful facility for organizing your data into a hierarchy, very similar to a file-system. Just like a file system, you can have folders to store items inside of, and organize your information. The main difference is that every item can also contain other items. So in our case, we can have tasks that contain other tasks. This is a useful way for us to specify sub-tasks, and sub-sub-tasks. In my case, building project-management software, this also allows my tasks to be stored underneath their given project.

    Using this structure is optional, but useful in many circumstances.

    The facility for this is built into the cr_items data model. This makes sense, because you wouldn't want your hierarchy associated with each revision. Here's how Postgres describes the cr_items table:

                             Table "public.cr_items"
          Column      |          Type          |          Modifiers          
    ------------------+------------------------+-----------------------------
     item_id          | integer                | not null
     parent_id        | integer                | not null
     name             | character varying(400) | not null
     locale           | character varying(4)   | 
     live_revision    | integer                | 
     latest_revision  | integer                | 
     publish_status   | character varying(40)  | 
     content_type     | character varying(100) | 
     storage_type     | character varying(10)  | not null default 'text'
     storage_area_key | character varying(100) | not null default 'CR_FILES'
     tree_sortkey     | bit varying            | 
    
    The parent_id refers to either a content item (cr_items), or a subclass of a content_item (such as cr_folders). I'll explain more later about cr_folders.

    One thing that you might want to do for your application is to give the application its own root directory. Because the content repository is shared among applications, this separates it off from other applications. They can still use the items in your application, but it must be a more deliberate process. If you don't create your own root directory, you may see strange-looking data from other applications in your application, or see your application's data in other applications. There are times when you'll want to do this, but probably not until you're much more familiar with the content repository. Another reason for creating your own root repository is that you application may be mounted several times. If you want to separate the directory structure between instances of your application, you need to create your own root directory:

    -- Creates and returns a unique name for new project folders
    
    select define_function_args('pm_project__new_unique_name', 'package_id');
    
    create function pm_project__new_unique_name (integer)
    returns text as '
    declare
    	p_package_id		alias for $1;
    
    	v_name			cr_items.name%TYPE;
    	v_package_key		apm_packages.package_key%TYPE;
    	v_id			integer;
    begin
    	select package_key into v_package_key from apm_packages
    	    where package_id = p_package_id;
    
    	select acs_object_id_seq.nextval into v_id from dual;
    
    	-- Set the name
    	select v_package_key || ''_'' || 
    	    to_char(current_timestamp, ''YYYYMMDD'') || ''_'' ||
    	    v_id into v_name;
    
    	return v_name;
    end;' language 'plpgsql';
    
    
    select define_function_args('pm_project__new_root_folder', 'package_id');
    
    create function pm_project__new_root_folder (integer)
    returns integer as '
    declare
    	p_package_id		alias for $1;
    
            v_folder_id                cr_folders.folder_id%TYPE;
    	v_folder_name		cr_items.name%TYPE;
    begin
    	-- Set the folder name
    	v_folder_name := pm_project__new_unique_name (p_package_id);
    
    	v_folder_id := content_folder__new (
    	    v_folder_name,			-- name
    	    ''Projects'',			-- label
    	    ''Project Repository'',		-- description
    	    p_package_id				-- parent_id
    	);
    
    	-- Register the standard content types
    	PERFORM content_folder__register_content_type (
    	    v_folder_id,	 -- folder_id
    	    ''pm_project'',      -- content_type
    	    ''f''		 -- include_subtypes
    	);
    
    	-- TODO: Handle Permissions here for this folder.
    
    	return v_folder_id;
    end;' language 'plpgsql';
    
    Note that this example is for projects rather than tasks. This is because for the application I'm writing, projects are what tasks are stored inside of. A project has many component tasks. If you were writing another application, or if I wasn't doing anythign with projects, then this would be creating a folder for just tasks.

    Typically, this definition would go in your sql/postgresql/project-manager-create.sql file. If this file is broken in several parts, this would go in the project-manager-create-functions.sql portion.

    Once you've created your root directory, you will set the parent_id of your items to the id for the new root repository (in our case, it's returned from the pm_project__new_root_folder function)

    In the project-manager application, we'll create a root repository, and make all projects under that root repository. That means they'll all have a parent_id set to the root repository. However, we also want to make projects that are sub-projects of other projects. In that case, we will set the parent_id of the sub-project to the item_id of the parent.

    Understanding folders

    For a little while now, we have been talking about folders, but we haven't delved into what CR folders are. Folders are sub-classes of cr_items, and the only real difference is that they contain no data, except for a label and description.

    If you create folders for your application, then you'll need to make sure you manage them along with your other objects. For example, if you were to add a folder for each of your objects, then you would probably want to make sure you delete the folder when you delete the object.

    However, in many cases you are not creating more than one folder. In fact, the only folder you might have will be the root folder you create for each instance of your application (if you install the project-manager in two parts of your web server, for example, it should have two different root folders). When your application is running, it can determine the root folder by searching the cr_folders table. Here's the definition of that table:

                     Table "public.cr_folders"
           Column       |          Type           |  Modifiers  
    --------------------+-------------------------+-------------
     folder_id          | integer                 | not null
     label              | character varying(1000) | 
     description        | text                    | 
     has_child_folders  | boolean                 | default 'f'
     has_child_symlinks | boolean                 | default 'f'
     package_id         | integer                 | 
    
    Note that there is a package_id column. The nice thing about this column is that you can use it to find the root repository, if you only have one folder per instance of your application. You can get your package_id using this call within your .tcl file:
    set package_id [ad_conn package_id]
    
    Then you can find the root repository by using a query like this:
    select folder_id from cr_folders where package_id = :package_id;
    

    Create scripts

    Drop scripts

    If you have problems with your drop script in OpenACS 4.6.2, then Tammy's drop scripts might be of interest to you.

    Using your data model

    You now have a shiny new data model that handles revisions and all sorts of other things we haven't gotten to yet. Now, in your Tcl pages and your ps/sql code, you can...

    Get latest revision (Tcl) set live_revision_id [db_exec_plsql get_live_revision "select content_item__get_live_revision(:item_id)"]
    Get latest revision (pl/sql) live_revision_id := content_item__get_live_revision(:item_id);

    The item_id identifies the content item with which the revision is associated.

    Likewise, the most recent revision of a content item can be obtained with the content_item__get_latest_revision function

    Reference:

    Reference: Definitions

    Content Type
    A set of attributes that may be associated with a text or binary content object. For example, a press_release content type may include a title, byline, and publication date. These attributes are stored in the cr_revisions table, and a table that you set up to store specialized data. In this case, the title (I think), byline, and publication date would be stored in a specialized table.
    Content Item
    Items are the fundamental building blocks of the content repository. Each item represents a distinct text or binary content object that is publishable to the web, such as an article, report, message or photograph. An item my also include any number of attributes with more structured data, such as title, source, byline and publication date.
    Content Revision
    A revision consists of the complete state of the item as it existed at a certain point in time. This includes the main text or binary object associated with the item, as well as all attributes.
    Content Folder
    A folder is analogous to a folder or directory in a file system. It represents a level in the content item hierarchy. In the previous example, press-releases is a folder under the repository root, and products is folder within that.
    Symbolic Link
    Analogous to a symlink, alias or shortcut in a file system. Allows an item to be accessed from multiple folders.
    Templates
    Templates are merged with content items to render output in HTML or other formats. Templates are assumed to be text files containing static markup with embedded tags or code to incorporate dynamic content in appropriate places.

    Content templates

    The only place content templates are used in OpenACS are in the 5.0 version of file storage. See CR and content_template defined wrong

    Troubleshooting

    One problem I ran into while trying to get my SQL create and drop scripts working was that sometimes I wasn't able to delete a content type because I would get errors like these:
    Referential Integrity: attempting to delete live_revision: 658
    
    The problem seems to be that there were still items in the cr_items table. You can remove them using select content_item__delete(648); in psql. You get the codes by doing a query like this:
    select i.item_id, r.revision_id, r.title, i.content_type from cr_items i, cr_revisions r where i.item_id = r.item_id order by i.item_id, r.revision_id;
    
    Really, however, what you need to do is make sure your __delete and drop scripts first go through and delete all children of those items. I'm not sure if you need to delete the items themselves -- I believe they may be dropped by themselves when the tables are dropped, because of the cascade portion of the SQL data model.

    When I was troubleshooting folders, I found this query useful:

    select f.folder_id,f.label,f.description,i.content_type from cr_folders f, cr_items i where f.folder_id = i.item_id;
    

    Once again, thanks to daveb for help in tracking this down (he rocks!). openacs-5.7.0/packages/acs-content-repository/www/doc/intermedia.html0000644000175000017500000000562107253523116025614 0ustar frankiefrankie Content Repository: Testing Intermedia

    Testing Intermedia

    Content Repository

    Even if you follow the instructions in the installation notes, content searches may inexplicably fail to work. This document describes how to create a simple test case independent of the content repository to verify that Intermedia is indeed functioning properly.

    Create a document table

    Create a simple table to hold some test documents:

    create table cr_test_documents ( 
      doc_id    integer primary key, 
      author    varchar2(30), 
      format    varchar2(30), 
      title     varchar2(256), 
      doc       blob 
    );

    Create an Intermedia preference to specify INSO filtering:

    begin
      ctx_ddl.create_preference
      (
        preference_name => 'CONTENT_FILTER_PREF',
        object_name     => 'INSO_FILTER'
      );

    If this preference has already been created, this step will cause an error that you can ignore.

    Create an Intermedia index on the test table with INSO filtering:

    create index cr_test_documents_idx on cr_test_documents ( doc )
      indextype is ctxsys.context
      parameters ('FILTER content_filter_pref' );

    Load test documents

    You can use SQL*Loader to load some documents into the test table. First create a control file named cr-test-docs.ctl:

    load data
    INFILE 'cr-test-docs.data'
    INTO TABLE cr_test_documents
    APPEND
    FIELDS TERMINATED BY ','
    (doc_id SEQUENCE (MAX,1),
     format,
     title,
     ext_fname FILLER CHAR(80),
     doc LOBFILE(ext_fname) TERMINATED BY EOF)

    Copy any number of documents (Microsoft Word, PDF, text, HTML, etc.) to the file system of your database server. Create a data file with an entry for each document you would like to load. This is simply a comma-separated text file:

    word, Simple Story,sample-docs/simple.doc,
    excel, Simple Spreadsheet,sample-docs/simple.xls

    Load the documents from the command line:

    $ sqlldr userid=cms/cms control=cr-test-docs.ctl log=cr-test-docs.log
    
    SQL*Loader: Release 8.1.6.2.0 - Production on Thu Nov 9 13:36:56 2000
    
    (c) Copyright 1999 Oracle Corporation.  All rights reserved.
    
    Commit point reached - logical record count 2

    Test search

    Once the documents have been loaded, rebuild the index and run some test queries:

    SQL> alter index cr_test_documents_index rebuild online parameters ('sync');
    SQL> select score(1), doc_id from cr_test_documents 
           where contains(doc, 'cars', 1) > 0;
    
      SCORE(1)     DOC_ID
    ---------- ----------
    	 4	    1
    

    karlg@arsdigita.com
    Last revised: $Id: intermedia.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-content-repository/www/doc/requirements.html0000644000175000017500000004415707766162043026234 0ustar frankiefrankie Content Repository Requirements

    Content Repository Requirements

    Karl Goldstein (karlg@arsdigita.com)
    Revision History

    VI.A Requirements: Data Model

    5.0 MIME Types

    The content repository must be able to store objects in any format, both text and binary. MIME types provide a standard set of codes for identifying the file format of each content item. For the purpose of data integrity, the repository must have a canonical list of MIME types that may be assigned to content items.

    10.0 Content Types

    A content type is characterized by a set of attributes that may be associated with a text or binary content object. Attributes are stored separately from their associated content object, and as such may be indexed, searched, sorted and retrieved independently. For example, attributes of a press release may include a title, byline, and publication date.

    The data model must support storage of descriptive information for each content type:

    10.10 Content types must be associated with unique keyword identifiers, such as press_release, so they can be referenced in data tables, queries and procedural code.

    10.20 Content types must be associated with singular and plural descriptive labels, such as Press Release and Press Releases, to simplify user recognition.

    10.20 Content types may specify any number of attributes. Attribute values are simple strings or numbers.

    10.30 Content types may inherit attributes from any other other content type. For example, a regional press release may be a subtype of the press release type. Regional press releases have a region attribute in addition to the characteristics of a regular press release.

    10.40 Part of the definition of a content type may include a description of the parent-child relationships allowed for items of this type. For example, a Press Release may contain one or more items of type Image, but it should not contain any items of type Internal Financial Status Report.

    10.60 A content type definition may include a list of allowed file MIME types for items of this type.

    10.70 A content type definition may include a list of tokens to identify or flag relationships with other items. For example, the content type definition for a chapter of a reference manual may include the tokens next, previous and see_also. Each type of relationship may include a minimum and/or maximum number of relationships of this type that are required for an item to be published.

    20.0 Content Items

    Items are the fundamental building blocks of the content repository. Each item represents a distinct text or binary content object that is publishable to the web, such as an article, report, message or photograph. An item my also include any number of attributes with more structured data, such as title, source, byline and publication date.

    Content items have the following persistent characteristics which the data model must support:

    20.10 Content items must have a simple unique identifier so they can be related to other objects in the system.

    20.20 Each content item consists of a set of attributes and a single text or binary object.

    20.25 All content items are associated with a few basic attributes to facilitate searching and development of browser interfaces to the content repository:

    • A title
    • A brief description or summary
    • An author or contributor
    • A publication or posting date
    • A distinguished URL at which an item may be accessed.
    • A MIME type

    20.30 Each content item must be an instance of a particular content type. The content type defines the attributes associated with the content item, in addition to the basic ones described above.

    20.40 A content item must have a unique, persistent URL (Uniform Resource Locator) by which it is publicly accessible, such as /press-releases/products/widget. To facilitate moving of items within the repository, the item itself should only be associated with the "tail" of the url, such as widget. The absolute URL of the item is determined by its location within the repository (See Content Organization).

    20.50 It must be possible to specify the language of each item.

    20.60 It must be possible to maintain a revision history for both the attributes and the text or binary object associated with a content item.

    20.70. There must be a flexible mechanism for implementing access control on individual items, based on granting of permissions to groups or individual users.

    20.80. A content item may be associated with any number of workflows.

    20.90. Content items may themselves be "containers" or "parents" for other content items. For example, an Article may contain multiple Sections.

    20.95 Each item may be associated with any number of related objects. The type and number of relationships must be constrained by the content type of the item (See 10.70 above).

    30.0 Content Revision

    As mentioned above, each content item may be associated with any number of revisions. The data model for revisions must support the following:

    30.10. A revision consists of the complete state of the item as it existed at a certain point in time. This includes the main text or binary object associated with the item, as well as all attributes.

    30.20. The data model must be extensible so that revisions for all content types (with any number of attributes) may be stored and retrieved efficiently.

    40.0 Organization of the Repository

    40.10. The data model must support the hierarchical organization of content items in a manner similar to a file system.

    40.20. The URL of a content item should reflect its location in the hierarchy. For example, a press release with the URL /press-releases/products/new-widget is located at the third level down from the root of the hierarchy.

    40.20.5 Content Folder.

    A folder is analogous to a folder or directory in a file system. It represents a level in the content item hierarchy. In the previous example, press-releases is a folder under the repository root, and products is folder within that. The description of a folder may include the following information:

    40.20.5.10. A URL-encoded name for building the path to folders and individual items within the folder.

    40.20.5.20. A pointer to a content item that may serve as the "index" for the folder (i.e. the item that is served when the URL of the folder itself is accessed).

    40.20.5.30. A set of constraints on the number and type of content items that may be stored in the folder.

    40.30. It must be possible to create symbolic links or shortcuts to content items, so they may be presented at more than one URL or branch of the hierarchy.

    40.30.5 Content Symbolic Link.

    A symbolic link is analogous to a symlink, alias or shortcut in a file system. The description of a symbolic link must include the following information:

    40.30.5.10. A URL-encoded name for the symbolic link. As for folders and items, this only represents the "tail" of the URL, with the full URL being determined by the folder in which the link is located.

    40.30.5.20. A pointer to a target item which the symbolic link references..

    40.30.5.30. A title or label, which may be different from the title or label of the target item.

    50.0 Content Template.

    The content repository should provide a means of storing and managing the templates that are merged with content items to render output in HTML or other formats. Templates are assumed to be text files containing static markup with embedded tags or code to incorporate dynamic content in appropriate places. The data model requirements for templates are a subset of those for content items.

    Because they typically need to reference a specific attributes, a template is typically specific to a particular content types and its subtypes.

    VI.B Requirements: Stored Procedure API

    100.10 MIME Types

    Since a MIME type is a required attribute of each content item, the repository must be capable of managing a list of recognized MIME types for ensuring appropriate delivery and storage of content.

    100.10.10. Register a MIME type

    100.10.20. Set the description of a MIME type

    100.10.30. Get the description of a MIME type

    100.10.40. Determine whether a MIME type is text or binary

    100.10.50. Get a list of registered MIME types

    100.10.60. Unregister a MIME type

    It is important to note that the role of MIME types in the content repository is simply to describe the general file format of each content item. Neither the data model nor the API support the full range of allowed parameters for the general MIME types such as text/plain.

    100.20 Locales

    The repository must have access to a list of recognized locales for the purpose of publishing content items in multiple languages and character sets.

    All content in the repository is stored in UTF-8 to facilitate searching and uniform handling of content. Locales may be specified as user preferences to configure the user interface in the following ways:

    • language of content (when items are available in multiple languages).
    • language of system messages (form labels, warnings, menu links, etc.).
    • character set (text content converted from UTF-8 to the specified character set).
    • number, date and currency format.
    • choice of layout, including templates, graphics and other resources.

    Functional requirements for locales include:

    100.20.10. Register a locale, including language, territory and character set.

    100.20.20. Get the language of a specified locale.

    100.20.10. Get the character set code of a specified locale using either Oracle or WETF/ISO/ANSI codes.

    100.20.30. Get the number, date and currency format of a specified locale.

    100.20.40. Convert a text content item to a specified locale (character set).

    100.20.50. Get a list of registered locales.

    100.20.60. Unregister a locale.

    100.30 Content Types

    100.30.10. Create a content type, optionally specifying that it inherits the attributes of another content type. Multiple inheritance is not supported.

    100.30.20. Get and set the singular and plural proper names for a content type.

    100.30.30. Create an attribute for a content type.

    100.30.40. Register a content type as a container for another content type, optionally specifying a minimum and maximum count of live items.

    100.30.50. Register a content type as a container for another content type, optionally specifying a minimum and maximum count of live items.

    100.30.60. Register a set of tags or tokens for labeling child items of an item of a particular content type.

    100.30.70. Register a template for use with a content type, optionally specifying a use context ("intranet", "extranet") which the template is appropriate to use.

    100.30.80. Register a particular type of workflow to associate with items of this content type by default.

    100.30.90. Register a MIME type as valid for a content type. For example, the Image content type may only allow GIF and JPEG file formats.

    100.30.95 Register a relationship with another type of object, specifying a token or name for the relationship type as well as a minimum and/or maximum number of relationships of this type that are required for the item to be published.

    100.40 Content Items

    100.40.10. Create a new item, specifying a parent context or the root of the repository by default.

    100.40.15. Rename an item.

    100.40.17. Copy an item to another location in the repository.

    100.40.20. Move an item to another location in the repository.

    100.40.30. Get the full path (ancestry of an item) up to the root.

    100.40.35. Get the parent of an item.

    100.40.40. Determine whether an item may have a child of a particular content type, based on the existing children of the item and the constraints on the content type.

    100.40.45. Label a child item with a tag or token, based on the set of tags registered for the content type of the container item.

    100.40.50. Get the children of an item.

    100.40.55. Get the children of an item by type or tag.

    100.40.60. Establish a generic relationship between any object and a content item, optionally specifying a relationship type.

    100.40.70. Create a revision.

    100.40.80. Mark a particular revision of an item as "live".

    100.40.83. Specify a start and end time when an item should be available.

    100.40.85. Clear the live revision attribute of an item, effectively removing it from public view.

    100.40.90. Get a list of revisions for an item, including modifying user, date modified and comments.

    100.40.95. Revert to an older revision (create a new revision based on an older revision).

    100.50 Content Folders

    The repository should allow for hierarchical arrangement of content items in a manner similar to a file system. The API to meet this general requirement focuses primarily on content folders:

    100.50.10. Create a folder for logical groups of content items and other folders. The folder name becomes part of the distinguished URL of any items it contains. Folders may be created at the "root" or may be nested within other folders.

    100.50.20. Set a label and description for a folder.

    100.50.30. Get the label and description for a folder.

    100.50.40. Get a list of folders contained within a folder.

    100.50.50. Move a folder to another folder.

    100.50.60. Copy a folder to another folder.

    100.50.70. Create a symbolic link to a folder from within another folder. The contents of the folder should be accessible via the symbolic link as well as the regular path.

    100.50.80. Tag all live item revisions within a folder with a common version descriptor (i.e. 'Version 1.0' or 'August 1 release'), for the purpose of versioning an entire branch of the site. Folder objects themselves are not eligible for versioning, since they are solely containers and do not have any content other than the items they contain.

    100.50.90. Delete a folder if it is empty.

    Note that folders are simply a special type of content item, and as such may receive the same object services as items, (namely access control and workflow). In addition to the file-system analogy afforded by folders, any type of content item may serve as a contain for other content items (see below).

    Workflow

    The repository must offer integration with a workflow package for managing the content production process.

    100.60 Categorization

    The repository must support a common hierarchical taxonomy of subject classifications that may be applied to content items.

    100.60.10. Create a new subject category.

    100.60.20. Create a new subject category as the child of another subject category.

    100.60.30. Assign a subject category to a content item.

    100.60.40. Remove a subject category from an item.

    100.60.50. Get the subject categories assigned to a content item.

    Search

    The repository must have a standard means of indexing and searching all content.

    Access Control

    The repository must have a means of restricting access on an item-by-item basis.

    VI.C Requirements: Presentation Layer API

    The presentation layer must have access to a subset of the stored procedure API in order to search and retrieve content directly from the repository if desired.

    Revision History

    AuthorDateDescription
    Karl Goldstein9 August 2000 Initial draft.
    Karl Goldstein 22 August 2000 Added to API section.
    Karl Goldstein 19 September 2000 Added data model requirements, revised API requirements, numbered all items.
    Karl Goldstein 21 September 2000 Add requirements for relationships among content items and other objects.

    karlg@arsdigita.com
    Last Modified: $Id: requirements.html,v 1.2 2003/12/11 21:39:47 jeffd Exp $ openacs-5.7.0/packages/acs-content-repository/www/admin/0000755000175000017500000000000011724401447023124 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/www/admin/index.adp0000644000175000017500000000027211345432732024722 0ustar frankiefrankie Content Repository Administration openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/0000755000175000017500000000000011575225426025222 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/map.adp0000644000175000017500000000023711345432732026462 0ustar frankiefrankie doc @context@ openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/map.tcl0000644000175000017500000000204211345432732026474 0ustar frankiefrankiead_page_contract { @author Emmanuelle Raffenne (eraffenne@gmail.com) @creation-date 22-feb-2010 @cvs-id $Id: map.tcl,v 1.1 2010/03/09 11:49:46 emmar Exp $ } { mime_type:notnull {return_url ""} } set doc(title) "Add an extension" set label [db_string get_mime_type {} -default $mime_type] set context [list [list [export_vars -base "extensions" {mime_type}] "Extensions mapped to $label"] $doc(title)] if { $return_url eq "" } { set return_url [export_vars -base "extensions" {mime_type}] } ad_form -name extension_new -export {return_url} -cancel_url $return_url -form { {mime_type:text(inform) {label "MIME type"} {html {size 25}} } {label:text(inform) {label "Description"} {html {size 50}} } {extension:text(text) {label "Extension"} {html {size 5}} } } -on_request { } -on_submit { cr_create_mime_type \ -extension $extension \ -mime_type $mime_type } -after_submit { ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/map.xql0000644000175000017500000000033111345432732026515 0ustar frankiefrankie select label from cr_mime_types where mime_type = :mime_type openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/new.adp0000644000175000017500000000023711345432732026476 0ustar frankiefrankie doc @context@ openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/new.tcl0000644000175000017500000000164311345432732026516 0ustar frankiefrankiead_page_contract { @author Emmanuelle Raffenne (eraffenne@gmail.com) @creation-date 22-feb-2010 @cvs-id $Id: new.tcl,v 1.1 2010/03/09 11:49:46 emmar Exp $ } { {return_url ""} } set doc(title) "Create a new MIME Type" set context [list [list "./" "MIME types"] $doc(title)] if { $return_url eq "" } { set return_url "./" } ad_form -name mime_type_new -export {return_url} -cancel_url $return_url -form { {mime_type:text(text) {label "MIME type"} {html {size 25}} } {label:text(text) {label "Description"} {html {size 50}} } {extension:text(text),optional {label "Default extension"} {html {size 5}} } } -on_request { } -on_submit { cr_create_mime_type \ -extension $extension \ -mime_type $mime_type \ -description $label } -after_submit { ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/index.adp0000644000175000017500000000023611345432732027013 0ustar frankiefrankie doc @context@ openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/index.tcl0000644000175000017500000000504711345432732027036 0ustar frankiefrankiead_page_contract { @author Emmanuelle Raffenne (eraffenne@gmail.com) @creation-date 22-feb-2010 @cvs-id $Id: index.tcl,v 1.1 2010/03/09 11:49:46 emmar Exp $ } { { extension_p 0 } { orderby "mime_type" } } set return_url [export_vars -base "index" {extension_p orderby}] set actions [list "Create MIME type" [export_vars -base "new" {return_url}] ""] if { $extension_p } { set doc(title) "MIME Type Extension Map" lappend actions "Show MIME types only" [export_vars -base "./" {{extension_p 0}}] "" set elms { extension { label "Mapped extension" orderby "map.extension" } mime_type { label "MIME type" link_url_col extensions_url html {title "Manage mapped extensions for this MIME type"} orderby "mime.mime_type" } label { label "Description" link_url_col extensions_url html {title "Manage mapped extensions for this MIME type"} orderby "mime.label" } action { label "Action" link_url_col action_url } } } else { set doc(title) "MIME Types" lappend actions "Show extension map" [export_vars -base "./" {{extension_p 1}}] "" set elms { mime_type { label "MIME type" link_url_col extensions_url html {title "Manage mapped extensions for this MIME type"} orderby "mime_type" } label { label "Description" link_url_col extensions_url html {title "Manage mapped extensions for this MIME type"} orderby "label" } extension { label "Default extension" orderby "extension" } } } template::list::create \ -name mime_types \ -multirow mime_types \ -actions $actions \ -orderby_name orderby \ -bulk_action_export_vars {extension_p} \ -elements $elms \ -filters { extension_p } if { $extension_p } { db_multirow -extend {extensions_url action action_url} mime_types get_mime_type_map {} { set extensions_url [export_vars -base "extensions" {mime_type}] if { $extension ne "" } { set action "unmap" set action_url [export_vars -base "unmap" {return_url extension mime_type}] } } } else { db_multirow -extend {extensions_url} mime_types get_mime_types {} { set extensions_url [export_vars -base "extensions" {mime_type}] } } set context [list $doc(title)] openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/index.xql0000644000175000017500000000115711345432732027056 0ustar frankiefrankie select mime.mime_type, mime.label, map.extension from cr_mime_types mime left join cr_extension_mime_type_map map on (mime.mime_type = map.mime_type) [template::list::orderby_clause -orderby -name mime_types] select mime_type, label, file_extension as extension from cr_mime_types [template::list::orderby_clause -orderby -name mime_types] openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/extensions.adp0000644000175000017500000000023611345432732030103 0ustar frankiefrankie doc @context@ openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/extensions.tcl0000644000175000017500000000203311345432732030116 0ustar frankiefrankiead_page_contract { @author Emmanuelle Raffenne (eraffenne@gmail.com) @creation-date 22-feb-2010 @cvs-id $Id: extensions.tcl,v 1.1 2010/03/09 11:49:46 emmar Exp $ } { mime_type:notnull } set mime_type_label [db_string get_mime_type {} -default $mime_type] set doc(title) "Extensions Mapped to $mime_type_label" set context [list [list "./" "Mime Types"] $doc(title)] set return_url [export_vars -base "extensions" {mime_type}] set actions [list "Add extension" [export_vars -base "map" {mime_type return_url}] ""] template::list::create \ -name extensions \ -multirow extensions \ -actions $actions \ -elements { mime_type { label "MIME type" } extension { label "Extension" } action { label "Action" link_url_col action_url } } db_multirow -extend {action action_url} extensions get_extensions {} { set action_url [export_vars -base "unmap" {mime_type extension return_url}] set action "Unmap" } openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/extensions.xql0000644000175000017500000000067311345432732030150 0ustar frankiefrankie select label from cr_mime_types where mime_type = :mime_type select mime_type,extension from cr_extension_mime_type_map where mime_type = :mime_type order by extension openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/unmap.tcl0000644000175000017500000000054711345432732027047 0ustar frankiefrankiead_page_contract { @author Emmanuelle Raffenne (eraffenne@gmail.com) @creation-date 22-feb-2010 @cvs-id $Id: unmap.tcl,v 1.1 2010/03/09 11:49:46 emmar Exp $ } { extension:notnull mime_type:notnull {return_url ""} } if { $return_url eq "" } { set return_url "index" } db_dml extension_unmap {} ad_returnredirect $return_url openacs-5.7.0/packages/acs-content-repository/www/admin/mime-types/unmap.xql0000644000175000017500000000037111345432732027064 0ustar frankiefrankie delete from cr_extension_mime_type_map where extension = :extension and mime_type = :mime_type openacs-5.7.0/packages/acs-content-repository/www/image-info.adp0000644000175000017500000000042411043711736024534 0ustar frankiefrankie Properties page for @item_id@ @filename@

    Full Size Image url is @ad_url@/image/@item_id@/@filename@

    Thumbnail url is @ad_url@/image/@item_id@/thumbnail/@filename@
    openacs-5.7.0/packages/acs-content-repository/www/image-info.tcl0000644000175000017500000000010610475066760024557 0ustar frankiefrankiead_page_contract { } { item_id filename } set ad_url [ad_url]openacs-5.7.0/packages/acs-content-repository/www/index-postgresql.xql0000644000175000017500000000062207347132553026077 0ustar frankiefrankie postgresql7.1 select content_item__get_root_folder(null) select content_template__get_root_folder() openacs-5.7.0/packages/acs-content-repository/www/index.vuh0000644000175000017500000000261607702263321023672 0ustar frankiefrankie################## KLUDGE BY STAS ############### # Try and look up the item in the content repository ################################################# ad_page_contract { @author Unknown @creation-date Unknown @cvs-id $Id: index.vuh,v 1.8 2003/07/07 12:25:53 olah Exp $ } { { revision_id "" } } # Get the paths set the_root [ns_info pageroot] set the_url [ad_conn path_info] set content_type "" # Get the IDs set content_root [db_string content_root ""] set template_root [db_string template_root ""] # Serve the page # DRB: Note that content::init modifies the local variable the_root, which is treated # as though it's been passed by reference. This requires that the redirect treat the # path as an absolute path within the filesystem. if { [content::init the_url the_root $content_root $template_root public $revision_id $content_type] } { set file "$the_root/$the_url" rp_internal_redirect -absolute_path $file } else { # ns_returnnotfound set page "[ad_header {Content Item Not Found}]" append page "

    Content Item Not Found

    " append page "The requested item is not available for viewing. " append page "The item is either not available on this server or it is not in a publishable state " append page "Unpublished items can be viewed via the CMS interface if the CMS package is installed.
    " append page "[ad_footer]" doc_return 200 text/html $page } openacs-5.7.0/packages/acs-content-repository/www/index.xql0000644000175000017500000000036307347132553023700 0ustar frankiefrankie select first_names || ' ' || last_name from persons where person_id = :user_id openacs-5.7.0/packages/acs-content-repository/www/index-oracle.xql0000644000175000017500000000063207347132553025142 0ustar frankiefrankie oracle8.1.6 select content_item.get_root_folder from dual select content_template.get_root_folder from dual openacs-5.7.0/packages/acs-content-repository/java/0000755000175000017500000000000011724401447022131 5ustar frankiefrankieopenacs-5.7.0/packages/acs-content-repository/java/Util-oracle.sqlj0000644000175000017500000000537607263134052025215 0ustar frankiefrankiepackage com.arsdigita.content; // $Id: Util-oracle.sqlj,v 1.1 2001/04/05 18:23:38 donb Exp $ import java.sql.*; import java.util.*; import oracle.sql.*; import java.io.*; public class Util { public static void stringToBlob(String s, oracle.sql.BLOB blob, int size) throws SQLException { if (s == null) return; byte[] inBuffer = s.getBytes(); if (size < inBuffer.length) size = inBuffer.length; byte[] buffer = new byte[size]; System.arraycopy(inBuffer, 0, buffer, 0, inBuffer.length); blob.putBytes(1, buffer); } public static void stringToBlob(String s, oracle.sql.BLOB blob) throws SQLException { if (s == null) return; blob.putBytes(1, s.getBytes()); } public static String blobToString(oracle.sql.BLOB blob) throws SQLException { if (blob == null || blob.length() == 0) return ""; byte[] buffer = new byte[(int) blob.length()]; blob.getBytes(1, (int) blob.length(), buffer); String s = new String(buffer); return s; } public static void blobToFile(String path, oracle.sql.BLOB blob) throws SQLException { try { File aFile = new File(path); FileOutputStream aFileOutputStream = new FileOutputStream(aFile); long blobLength = blob.length(); aFile.mkdirs(); int chunkSize = blob.getChunkSize(); byte[] buffer = new byte[chunkSize]; for(long pos = 1; pos < blobLength; pos += chunkSize) { chunkSize = blob.getBytes(pos, chunkSize, buffer); aFileOutputStream.write(buffer, 0, chunkSize); } aFileOutputStream.close(); } catch (IOException e) { System.err.println("Error in writing " + path + ": " + e); } } public static void clobToBlob(oracle.sql.CLOB clob, oracle.sql.BLOB blob) throws SQLException, IOException { if (clob == null) { throw new SQLException("Received null value for clob argument."); } if (blob == null) { throw new SQLException("Received null value for blob argument."); } OutputStream outstream = blob.getBinaryOutputStream(); // Get an input stream for the clob Reader instream = clob.getCharacterStream(); int size = 4096; char[] buffer = new char[size]; int length = -1; while ((length = instream.read(buffer)) != -1) outstream.write((new String(buffer)).getBytes(), 0, length); instream.close(); outstream.close(); } // Write a BLOB to a CLOB, assuming the BLOB contains UTF-8 string public static void blobToClob(oracle.sql.BLOB blob, oracle.sql.CLOB clob) throws SQLException, IOException { String s = blobToString(blob); // Get an output stream for the clob Writer outstream = clob.getCharacterOutputStream(); outstream.write(s); outstream.close(); } } openacs-5.7.0/packages/acs-content-repository/java/XMLExchange-oracle.sqlj0000644000175000017500000001737507263134052026405 0ustar frankiefrankiepackage com.arsdigita.content; import java.lang.reflect.*; import java.sql.*; import java.util.*; import java.io.*; import oracle.sql.*; import oracle.xml.parser.v2.*; import oracle.jdbc.driver.*; import org.w3c.dom.*; import sqlj.runtime.ref.DefaultContext; import oracle.sqlj.runtime.Oracle; import org.xml.sax.SAXException; #sql iterator TypeIter(String object_type, String table_name, String id_column); #sql iterator AttrIter(String attribute_name); public class XMLExchange { public static void main(String[] args) throws Exception { Integer revisionID = new Integer(args[0]); PrintWriter out = new PrintWriter( new BufferedWriter(new OutputStreamWriter(System.out))); exportRevision(revisionID, out); } public static int importRevision(Integer itemID, Integer revisionID, CLOB loc) throws SQLException, IOException, XMLParseException, SAXException { DOMParser parser = new DOMParser(); parser.parse(loc.getCharacterStream()); XMLDocument doc = parser.getDocument(); doc.print(System.out); XMLElement revision = (XMLElement) doc.getDocumentElement(); // Create the revision String title = getChildText(revision, "title"); String description = getChildText(revision, "description"); String publishDate = getChildText(revision, "publish_date"); String mimeType = getChildText(revision, "mime_type"); String text = getChildText(revision, "text"); #sql { begin :OUT revisionID := content_revision.new( title => :title, description => :description, publish_date => to_date(:publishDate), mime_type => :mimeType, text => :text, item_id => content_symlink.resolve(:itemID), revision_id => :revisionID); end; }; // Query for additional tables in which to insert extended attributes TypeIter typeIter; #sql typeIter = { select object_type, table_name, id_column from acs_object_types where object_type ^= 'acs_object' and object_type ^= 'content_revision' connect by prior supertype = object_type start with object_type = ( select object_type from acs_objects where object_id = :revisionID ) order by level desc }; String objectType; String dmlColumns, dmlValues; ArrayList attributes = new ArrayList(); AttrIter attrIter; // Use JDBC for the actual insert rather than SQLJ because we need // to build the DML dynamically Connection conn = DefaultContext.getDefaultContext().getConnection(); while (typeIter.next()) { objectType = typeIter.object_type(); dmlColumns = "insert into " + typeIter.table_name() + "(" + typeIter.id_column(); dmlValues = ") values ( ?"; // query the attributes of the table #sql attrIter = { select attribute_name from acs_attributes where object_type = :objectType order by attribute_name }; while (attrIter.next()) { dmlColumns += ", " + attrIter.attribute_name(); dmlValues += ",?"; attributes.add(attrIter.attribute_name()); } PreparedStatement stmt = conn.prepareStatement(dmlColumns + dmlValues + ")"); stmt.setInt(1, revisionID.intValue()); for (int i = 0; i < attributes.size(); i++) { stmt.setString(i + 2, getChildText(revision, (String) attributes.get(i))); } stmt.execute(); stmt.close(); attributes.clear(); } return revisionID.intValue(); } // Write XML to a CLOB public static int exportRevision(Integer revisionID, CLOB loc) throws SQLException, IOException { PrintWriter out = new PrintWriter(loc.getCharacterOutputStream()); exportRevision(revisionID, out); return revisionID.intValue(); } // Default implementation of a function to write an XML // representation of a content revision to an output stream. public static int exportRevision(Integer revisionID, PrintWriter out) throws SQLException { try { XMLDocument doc = new XMLDocument(); // get the content type String contentType; String tableName; String isContentType; #sql { select object_type, table_name, content_type.is_content_type(object_type) into :contentType, :tableName, :isContentType from acs_object_types where object_type = ( select object_type from acs_objects where object_id = :revisionID ) }; // screeen out non-content-types that are revisioned, such as templates if (isContentType.equals("f")) return -1; XMLElement revision = new XMLElement(contentType); doc.appendChild(revision); // select attributes for the revision AttrIter attrIter; #sql attrIter = { select attribute_name from ( select object_type, level sort_level from acs_object_types where object_type <> 'acs_object' start with object_type = :contentType connect by object_type = prior supertype ) types, acs_attributes attrs where attrs.object_type = types.object_type order by types.sort_level desc, attrs.sort_order }; // build the query to select attributes from the view for the // content type String attrQuery = "select revision_id"; while (attrIter.next()) { attrQuery += ", " + attrIter.attribute_name(); } attrQuery += " from " + tableName + "x where revision_id = ?"; // select a row from the attribute view for the content type Connection conn = DefaultContext.getDefaultContext().getConnection(); PreparedStatement stmt = conn.prepareStatement(attrQuery); stmt.setInt(1, revisionID.intValue()); ResultSet rs = stmt.executeQuery(); ResultSetMetaData md = rs.getMetaData(); if (rs.next()) { for (int i = 1; i <= md.getColumnCount(); i++) { // create an XML element for each attribute String colName = md.getColumnName(i); String colValue = rs.getString(i); if (colValue == null) colValue = ""; appendTextOnlyElement(revision, colName, colValue); } } stmt.close(); doc.print(out); } catch (Exception e) { throw new SQLException("Failed to generate XML document for revision " + revisionID + ": " + e); } return revisionID.intValue(); } private static String getChildText(XMLElement element, String name) { NodeList nodes = element.getChildrenByTagName(name); if (nodes.getLength() == 0) return null; // get the text node under this node Node textNode = nodes.item(0).getFirstChild(); return textNode.getNodeValue(); } private static void setChildText(XMLElement element, String text) { XMLText textNode = new XMLText(text); element.appendChild(textNode); } private static void appendTextOnlyElement(XMLElement parent, String name, String text) { XMLElement element = new XMLElement(name); setChildText(element, text); parent.appendChild(element); } } openacs-5.7.0/packages/acs-content-repository/java/PerlTools.jar0000644000175000017500000010722107253523116024555 0ustar frankiefrankiePK‘›U'META-INF/MANIFEST.MF¥˜I“¢X…÷‘ÿ!÷D7 ¨Pµ@fAEw€A†Ç<ýú6«ª»«é¨,5w¾x|qνç^T,òAUÿqeÁìËÛüÏÙëËëËÖIÁ—7¦(,a”yh úÍA™ ª“ø°LÁE¿}[èN]ƒ2ãzäõí†?½Ä©ª×6 Þ肋–Q¦Õ—7C¤ßTvñöúrûôÇ÷_Þ¤:éV^š)ª)8¤ H» ¢QK¿úúúr;ÿÏI«sR\`úCWr.öºseúë×ßðêNY‹Ñ¸UÕÍ;#—Õåð0¨‡É3?4×—UCG´kk›d£bω (ípÇL”ŒáÔ.Bw°˜C*ÝïAßõ´ê(y-Á7r„ìy:öwsQ± FpÛ2uQâ4ASO»®)DÁ•«ª(ý¶áñC´ìf/Ÿ¶Û•B‚nì­ëjdªÓÓ'÷12U1ßÀMÀ8ˆîùø9•,¤+j÷j У?&s)” —f~»‡¥ ­ê¸qAº5'“pBvXXbËàk]¡mwåDüžLuj/܃ªIê‡éÖƒªb¤½:…P‡ùR,í™È RÐbeÈǨÞjÖPø`!wÑýÝןni–£ùãÉmw‚\{ˆ¦pwàÀÚÖ„5ñeº¸º×¸e^„ñ lËñ‡Çï­òMNP>Œ§ŽnS¨Ì¢•aʹ̪|è€)Þ<+`Öa‘®UzüLjù‡‰óŸ|Ы¹":]zŽñc'·´£â5–âÆ¸+í¢Á"Ž–Õìú=•2ærdÒa¥$W†N‚jb}lM¿G3n‚µ!áÎkeí£{„¤ÉUãs÷´î»­ Ló(yB6\g«TÈ+ono{nGÝ>/§²-ñm¯bFàŬ2† Þž¸¼§ì¾ûú4ašJ$Ï(§QÊo·îu]Säµàɬ:!”ØÈ‚Ý•ž…ð@ÓGZ/¨5úpåIYÞ<5¸5°ƒ7öòj` O„ËDqwh#¯§Q#²ÖIïV]+œÇÛ ˜i§»tüisx¯NZ“ Åf†u å­¨Ds·_Óþt‚ÄóJ%Pgì3]——ºmvñépG~Ã3ê8és 1èÕmŒº–vW¯à樼î1Ò1¬vyb]±º£1£Aº&šâğי‡ñ”ƒ´_,Qt RªÇc›¾$ƒx:Kêy€šÌZ@¶ãl‡æõž2ü¦àg;/ÇG-„íRL¥­í 5I¼g‡«©Ë-]yk´5{¯°¿8ÛÞ67ƒ£,ø$¬6cmŠë#²…‹fÉ-yÓ[Éâte¸8DÁ£ãÅIXA+Ÿ0rr‡Lè”ßAõÛOõ™c ç p¦c„ó€'š™¦×~Pý¸Ÿš=»î„¶‘ õ&…iäÕQ4£–3ðßhÔâë(7ÖšÓAÈܦÁHÊÓé X ³ëª]Õ Mõµ•yoïAn?µ«ž‰^àä™ît0h¼ëÜYåòr„Q˜`]L9ŒÙé5´ Ù$÷¼Ï¬…™#ÜC#L͹91z.Š•sãTD› ⋎~GQ8Ú¶qâs݇"þ=íÞ÷þÇw@ÁdÛóH³`2æŒqˆôÐÊ«iV»Aê§ùâ„  Îðp>,»ŸÁ6{ëa6q”}'5Ôç­Ìð.çêüh¸X=ÍŽg…ÀÕ²'jo/Òɸ2PFÞç´ÃËq[— QË¢õHU:$´ñ~75UZÌ…õÎpV@Î$×ö¤^üªîn— ÏÈìì[×^–æÔ8ã‘è±+? !ÙͰÄ}+S³µY—iü+Åþ%zÆFž©Ð‘ÜŠ™uq+w‘®V3õQÌ›@Õ³µ=ãûBDù­4ß3Zñ_Õþ7¨6>§VÅgɸñúP]ªŽïzDÞ‡ª Ætêß,:ŠZÁ¬®*›ëºÉ¨_ÕþÿÀžûc·[Õ· -ñbožyâ€m|Žq4Äéz{9›ãG+fë,a%B&Ž%þí/PK|Ü&2:PK x›U'com/PK Š›U' com/oroinc/PK Š›U'com/oroinc/text/PK ‰›U'com/oroinc/text/perl/PK{›U'9com/oroinc/text/perl/MalformedPerl5PatternException.class}PÁNB1œòà=|Q¿À b¤ãIÃåEO˜¼ûZ*Ö”–Ôbø-O$ü?ʸ%ʃ{˜ÍÎìÎ$ûõýñ‰ —è8)Ð-!ÐJâE‚¶@Ö?¯Nûãz#iÉÍå4ãæ7‰Ïo3q$ЬüL UÞ½Fr±&»â¹¼[+½Œ†YÎØ+²5CV3qö@öɇ…žMt°×ŠQ·;¦Hö˜úUPúÞX6*¿>x㔌zå΢"õ¬÷-®ö–%ÿF þCªÔùŒ%O]î‰o 6ÈÞ· InÿÊ=^opÏ4ÿôã­MçPKêô8aôoPK€›U'2com/oroinc/text/perl/ParsedSubstitutionEntry.class…Q]KA=ã·¶~dIYšoa›µo½½„Á‚ ø*ã:ÈÊ:»Œ³a?« zèô£¢;&E40çÎ\8÷œ™óöþòŠ$.ÐÊ¢™ÅI äò`È(Ø1`Y(£h¡Ž= Gޱo¡C²}6b¸j÷½pá„*ô¥çh±ÒŽ3±r\k¡d·?çÜ ¸œ9C­|9뺮!f®}éë†Ôm8 ÅÛP.5—ză˜î…ÞÊ‘ö©ËÀ\†Ö?B ÕßZ ¥~èñ`Ä•Ï' YWK1Æ“¥öulzR«ÇKC&Ýa+OÜù™¨Že¼p%Í€oÍìšæw:õrãèÓýÙX‰(àžX©:?]GBÎ*_O¸ŸÌ…§Q¡R´)˜UßVJcS)BF»ŒÕ N‰•6ûI»¹FÚ®¥ÖHÙ5²öù™§ —á0ƒPK®*ŠuXPK‰›U'$com/oroinc/text/perl/Perl5Util.class•X XÕþïîìÎî0ÀÈ„@&–TCÖdIˆ Æ IšhL,ÙÀ@Ö.»ëÕVÛô©¶¶VÛ¤>¥UÛb+K‹±¶±µï§_í˾ßïÖ¾MÏ™]–0@äûæÜ;çþ÷Üÿž{Îî>ûÒã“pbµhôà^'èσÏ{ð¾êÁצŠ<¨ ?³¾¡]`e}CGO| )žŒGb=Mic(Ý”4ú¡¦ÎpºçÐN#5M·, ÜÕákÃMÑp¬¿iûÁ«ž™ê]éd$ÖßbÚÞ- Õ7ìk¨®o› Ú2Ø×g$[ÔÖp%7í mÙ†XiÔØÙåa2ìªo7a•ÜÚá<4°¯ÍÄ.«Ÿ±¿átÚHÆÚÂ=‡ŒÆgb²>°-3×h7ß6ÏDÓ‡´ÍùÌÛï<˜JGÒƒéHÜ–‚íÖ;ÏR{,1˜žÌöYíÉèZZÖÌmŒq…ëêgF’mpiv@òºßFßn£2h• ØÞìšú™þœ-9rûØÎš5Üëf‡Ó9G›v›xòìÍç€Ä²ÙFß>?ÍJÛidïb›—A| _†‰³ƒ†ç¯³›Nmy™S§;xÕ¹M%~ëÏ Ùn»J•ÍÜ}fÅ[QÏjÞƒ“fžO8‡„u5íO56 ¸7Db‘t+Ͷx¯!PÜ¥ÒáXzw8:HïÊÖ¡#Áµ%% ¨š.h]ŽFz—C‰¤‘JÑHh©€/§Ž›`V•MW¥XW;w™83KæuÈŠ¹B+WpÉñ…0óLrDÊíjM¹]t•tÄ{ÂÑÝád$|0j›JÌE® kç3\À»kGGûåÝ›;:È¡»âƒÉãÒH”¼ëà/_Yw7‘H¢Ÿ2uSþ5)ÑâÝÝΆ-F$¶½¯/e¤Éï–rk¬7§*êSis“¦¥îmÍ›#‚–ÎZZ #) vwÇ£ÑìöJ»»ãÉ­Žš¹HE¢»;N¦ŒN³‰‚ÓdƱAÊ`Ò$âѰDe¬,üh‘Γ›ÈË'D4Üc 1ZL ÷önZ/îp"aÄz‰o8™ î‰'S$dжúÅÓN„{"i¸{…“›I·x®Ø£ šk¸cçTûÏF$è )4£}ñä€Ñ[ø ˧ Õ~ÛY;Ø…½…~ØK'‰n­=<RM³eHŽÆ ËæÍ)š93J áœ«=%ñ¹×– u ´åógèÜ <·Us}F <,°È™u¬f[ Úê͈­Ì個ÇÒáG³3£ÆTJ–ôÓÓÖCŠ6 KB+ÔÍG¸Ê/Sófù”»VJóŒNJºp¿‘}É;ÂÕŸŒ&(äÍ–Œ—FRnO^BILv*Ì ‰7µo/ˆŠ©ºÆ´Â=ivþâ-•”T••‚I¾³+$ùwJµs0–Ž öø\u©´ÿh:öp*m Lãxù¡dü:®¶9`Áç”*—¿öX¯1´½|5býir›6°©~ÿž†úóý û/¨ßH ]åo § dÝ*gK yÍ›ˆçëgy¾ÏŽÙÌu‡ƒŠ^®¾æºîT"ʾVR¹à#¢^ó%»í¢t¼ÐZ:žÝ<]v‹éFOÇF7÷Eø ž£þ8 ÓCwK³OwQ³¥«§ÙÒ=ÔléRj¶t5[º®ší f»?/°' ãyÒçÞô.øLòYÒ!‘ðûÇPçŸ@E×VŽb¿q-ô¾°«q¯êQ¬!Ð…òï¦, ᤠ^¡ùçÁŸE9øRm¡ÖÓJüÛÉÊ ”hE‡¿±\ΠÇçË }=Ú9š®@WŒáü'i’UdºÄ4Cwn’dF,„‹œ!ùÃâöB².Ÿ†¢Ë§àÙCúu!/É‹BŠîm¤t%ƒ×CõŠº&°¤«\C ´e`Œ!ð$ÏÈàò[w»Æ±‡ ºœ­ºÛíKºt×ëRû7#ªK‹3xÕÃæö.£G¢'BO#=ô\HOŠž=Côl©‘nlFsÏÃm ÆçãvEo)·‹ó¤ÜDŠWɱZ|Äqæî3·¹ÝU3ŽÝN„<æ¦uÏ86;¡{FÈK*y© Õ´Ò—L6tXÆ7ÿ¬¿°™tÌq­¿q !Ó;³›AGkÍQÔú­í"èŒb½ß9Šf`rkk1·9Ýðg,Õtš|žŠ¿‘­'ƒ«ìГºÍ¢qQ!˘@Ý4ìbÔn7id°s6"OZ¦7Z¦/˜2} 2x5[¯)´.Ø´ƒí:¦u›yÁf‹qŠ×2j9ª]d 8bB—‰U8•]Õ©Pª.¤Ð|± ËõòÓØ«—Ÿ‚*†¼g—™áX¡—=†ÖÐn6…4n6+¹Ù¬Ò+ôкtM«Ã+ZåI„Cjq]á8•꥓ò ,ÑK;ÔqTê¥RóItƒÊ=ßêã³9‚>WÐëè g«æ º†q±^ª¹š}ûÃGÞ’Ã$ Ë:S­ùŽ£¤æÍT(V Q<…:âš‹83©)Ž{Q¬)ô&õÎAÂÙ*%  ¦ôŽ¡>D³¤Ì$™g²ij êuh.éáïÃFHLZÁFÍg®–Á•¬¼+œAi y⥚tÔd^4ŒZsa½ØÌ`Ëž)î·hE޹ÝRPv=ZQ–æ¦lþÇÌÐúé9hÕ«\BOœžCV=ØfÕƒ½š[º1èF»æ¦’À½MÔó™½µÔ[jöAy+¥ gKòä\\#¬=X§váR1Zr®æÕÍKþ½@sg+G‰^LBêÔ.½DW5YóŒ¡1T–­(efE±bµB/1ãQeÅ£l”eÿÕ3*Ož¶òò)ªÔ*µ£XÞå[0††GPeæ M ¬+0†Õ!Å<·¾\öꞀ&é^ç8.u ƒƒŠQï8ö t]Ò¸Pbÿ¬Ô½šU Íê_®Ó·dÿ=ôðpïâ#n¡¹5׉3Ï›¦¶9”Ž8ÏP<ñŽ×éŠ^DõçØ™›Íå¨ÌìÏ.å×½¼AÏÈŒ‚SGÊnlõ%óPåsfpÀûxë4¿¯¹“ª{&¶Ç­ŠSiU…+Î8ö áê\Í€30y— Ó'3GÉšRKS²þáæ¬iÕœ ;9vçåÙÝJì\ÔÞ4“å);v!©Z—ˆ_vŒ|ÔZC+é-Sc²[“g×gÇÈ‚)LÍÔRøøŸÊïþPK¾-ðù% ØPK{›U'4com/oroinc/text/MalformedCachePatternException.class}ÁJ1EofÚ™:hµ7nÝÔŠPÜ ºª fÿLcd‰éo¹*¸ðü(ñeк3KÞ=ïÝ$Ÿ_ïHq†qŽƒ£ úQ²]ì 2H''µÀádþD¯T²«r¼¶«óègÚêp)ЫÜR ìUξ²¡&Ór]\­¥zš]áÜI25yM÷F±q|CæÁùF-+’ê–BPÞnGfñJÎX¸ÖKu­ ΤkJç¶² jÊÿ#ŽþÞ}×Ú µ…¼Ä•ð‰ÿÌZp5êПn¾u ~ð˜ÛãX6=Ý ÷Ë÷»˜á7PKÄvnrïVPK ‹›U'com/oroinc/text/regex/PK€›U'#com/oroinc/text/regex/Pattern.classEOKjA}=HŒÑ,²Í^±àRÁ€à¾¦S -m·tJ™³¹ðJ¬MjSÔûñêz;_ÐÁ†]¼v10èŒÆKƒÑxµ£Ù@±¶É>ÖSƒr–~Øàm–â¯P”-…£Þ½yãø ^QƒÁ*9 [ÊžªÀ ô¿I„sœ´*Þ¤cv¼ðAŸ.ímÊÉGg…±™knìáâšeýLn?æý¿ÞºÚ±“ÂÀ @;E©Qºûú”éµ8^îPK)›>¼ñPK‰›U''com/oroinc/text/regex/MatchResult.classmÁN1†g–]@DE={[ÚðH4!ÁH½[†¥¤¶¤Û5ûl|Ê8»®Ñƒ=Ì—™éÿ7?>ßÞ¡·p݃ÓL:étŽ0I§‹½|•ÂH›‹UðÚæ÷q:¯·—Œ×3·!„áÌÙ"HÖÒ”Ü?TŠAóa´pJšµôZf†x0~’Aíž©(M¸«MY°r¥Wô¨ «“Œrm —ÛmAáF¹á¼ÓV‰@UžrªÄ/ŽBvƒpÄõG•äÞ•„nÃúñßËlOŠït Ù<ìúÁ}'‹"¨O?æôüaÀ¼hy݆CHŽ[ŽZžµ¼‚˜N¸F0øPK)#3{PKŠ›U'5com/oroinc/text/regex/MalformedPatternException.classuOÁJ1œì¶»uÑj+^=׊æ/EO„ÂÞŸi\"i"1•ý-O~€U|Y´žÌƒ!ofÞäåkûñ‰—8*1ª¡Ÿ ØÇÊ|rV œLæÏôFÒ’kä"ãš«Äׯ™x#Лù¥8˜y÷ÉÅšìšûê¶Uú%f†s¯ÈÖ =ZÍÄé=Ù'Vzù@1êàvîËô/ü:(}g,gIåWÒoœ’Q·QÝèVþ›!pü·óŽ…àÊNÆ7þ(cÅݨS€þtƒü½3$yð#ٞƊéù½_ý°‹~PKþ+2¿èKPKŠ›U'(com/oroinc/text/regex/Perl5Matcher.class¥Z |[ÕyÿŽï•®$ËÏä&q,ò¶%Ù Á(i^$ql+`'äÈŠ¥$"ŽäJ28´ ÝjÚ2XK·v›ÍÃŽ1SG ;)+…–•>F·B»±¥¬k÷‚=€jßÿÜ{mÙŽgM~úÎ9ßùÞßw^7yé·OŽ’BÕ"¬Ñ\%›ÍÞǽO3޲Yåvkô¾&¶jb›&ê4±];4±S»4q•&ê5±[×jâ:M4k¢E{4±W×kbŸ‹ ©ÓE%sæäÓ-.ÒéV'¹© àÀmŸø$À§NÜîbðiô~à÷>Ð pÀg>ðy€;þà.ðÞÞ:©€¾ðE'[p“œô%'Ñü1À—AüLü Hþ¸?ð½.Òè^ôû®ÏÉ^öœÂìxÛ zƒè=QäÏ2_…€¿xï aøˆ“…>ŠÞ×ÁûxÃìãÿ&þ½Ó.žÁð HÎböO‚í)Lœƒ”§ÑuÑøˆ~í¦ß—å¡ G¯º…Bï¹…Š¡ ÀNÿâzúO·p¸0Ì›Þq‹ô Y¥(¢u‹bÌ–”²1½¹ ÑÑ›0ŸþÉ- W’…ZŽ¡‡Þt‹ ú¹[,¢×ÜâL\ °˜~èK@²”­Ëè€ß¸ÅràV¬¨¨‡*}úªjVab5z—¡·½Ëa}-†WpÔD€þÑ-ÖÒߺÅ:ú‘[| $ë6€d#z›ègn±Ã+éÇn±…þÞ-®¦·Ü¢–6öw€Þv‹ƒô]·¸~ê7AGˆ¾ï­ôAË+«ÚÇW%’‰X¼mU:Ú•^•Œ‰v­j §ÛŽ^Mu¶§7šËt7‡o ¯jǬ º9Ú´RYµW‚ÔʪƒuhêªÌF"ëA†G¶ÊúúªzÙº±rå»Ãét4—6D“õñŽÎô†™I7@~å´ò¢Éö+,JiŠoV¤ëê¥ýAͲƒ3R7§“Ñðñ™}Ê• ‰+*§Fÿ¼ ñž‡°þ<(éUm.1›‹™M”ÕÊFN`d¯^QFk±Ôv®$,æXªq|3âÑžŽŽh+ŒóÍËèh,Mu„Ûx8G"±ÄªúàØQÆ§Øøy³)­G¢]AìÛñH*‡tÎ8iÎÒ,ÇbW>\ñä ÔU€¹¨©t”k½hÒAgIÌ^„u¢ÉÅŒeV`öv'£‡c¼œ^@¼¨±^Ø}®êœØh<4¶¼ütöKwåH–:bÆoH7?!9Öü4YHÿMïpÿ]~°æ‘Êãÿ¡_ùŃ}¼.dË/ Ùò3D¶ùF‹G‹óÛCŽ?0Z¼^äøC³Íšø“_˜cÕl5“ŽßD²ý­Ñâé"[~ïp»þ+ÇNþ‹ÇÄ;ðxá™_òèJ~yÛ¹½\ Ø2´²Ü;zŠlÊP…ßh½åµþŠÚ>t»m¢[ˆnEè6]=•}U"üqàÁc »…iÜîöŽö’Í3T­ÔìÚ¤ÛYN?­)Ø”€š¡9ÕºZ+Qz· ©åžréjõè©ì/tÛFô(_NœÊ>_nh"~ýã¦üÎ2ø<› rûIÐŒPdzdoðú”šaZáõ©Üø½>7UöMªôyl­5›¡©ÂçQ[k‚°Àÿ ¹a£j‚ÝyŠÇÇ!xjëæ y@³b\’-/(Ió‚œL¬̾aX•‡w¯iÕ“fhõú‡©Ò««Ã´Ìûî?Ceô„ù–(ô­¦«¼¾Ótã0­Ê%+zÙ¢b×0]–¡Å^N¤–û<[ÓK%Ü\Vìê'‡W’Y÷Ó*oÅ0“2¸Tj[ÓÔÖÉ T ËÎè -ÒÕ⹤Ïå9]=ÇJ.1Û¥Vt Ç¢û¯¾ÃcßS¤ƒr5J ƒŽû‘3´h˜®‘¦† ¥Ð‡èšå÷R9fOÓZ Ì~C$˜¡â¼‘ƒÉ,›§aÙl²ì‡õ„Š;÷eïöräW[./¢× —ík9qÜú”€] h^Ÿ¿BWÏÐJ^›,ìºõ®2× t†»W¨'{d6jz(ÃãÀ½Ôïåa%ÿëj™ë,mENäèU0ɾRåd/øØ”fµu˜š±àm#³.F?b²U p’‘W Ë\£­XÈy°£—|cââ"XÞ}4Ç'¸ÃfJÆ È–™vËæ;¼¾Š:ÚCNê×u寴v²Ç¶R·?@NÝ®Fš®êZDÑâŠAÚ"-D YðåÒU À•ŵ¨ÉE†·¤{‘âÅãjԘȾ”QŸg]#Š‘õ.(¶±]w—¹x¯rfè î´âÈÛSÝQwv´šŽ ,å%cܺ³/ûÆd‚SÙŒºuŠÔU9t“ÒÈ•|ß˨N¶¶mÀ‘×§¼d®)RÕ@þÔÀ©ì,ktGí׸ʔï3pš¿ëøWÊ»F5·s¸½ßbùwŽ:Wd ·óÿ4·ó™ßjp[Ïm·_Ô¶Ö€#CûƼ 8ug‰ Zg(ÕÚm­µªî,.:Ù…JÑÝ=S3£ôü€;Cv;%Te”yÒ¯nMt«YY }´ÐÒÉ;´ž¥Ñ€½ÉìoÉ5Ë-Iú Ìp¹'’÷ÈTõOëöûÉÁ\y÷Œ“çuKò“³¶+˜cWÝùì*͵+35Fy¥SM{Ò4­W¼7N.~ rñ愜°Šži‚/¾1SðÏeDÏdIÓ¥Q$. )8&é,ŸÖžª™¤<›Î\)ÓÙBoÎ,…¾™#åØt¶Ðýò©\)ÓÚrý¤¬=Ï~7YÆœœl?÷ê¶aªÆâÓmÖÕèJú±ynÞÈ—0ÜJ®õzøêƒÚ°GÏ´XákÅÜé®ïzÕªï¡yòŒôHE^œÔ!ÅRµŽ~d¨_gEn κåÕSªöQ±GW+"|„TxøPΛ®_kÊåVDâf.þá®xîüKš{S/ÿ ù×eìQô3câK¸Ü“D±±'‰JcO[Œ=I샼UR#!û› } «ìð{|yå4˜$ô¶Ü£lµe_öÝ ½"'^60ûšÜËF9TÏÆŸÊ’W׌ýM“û[Oö§ºÇ"ýœAŠ“ýu†º,|b ß|«…¿Þ—ôWYø+Çð’~µ…_iáIú¾h ÏôÈhU$`Ç\¥Û­ä-£WŒä9_åËF ·ßåÓC‘gEUÀ®ã>½ìÔø±’ßç‹Õíµ²•ª›Ê呼f4 eœwÉX¨gi›‘_¾Õïßü0Ëì0´Ñîãé1?ä¿QÄBþ­æß]ükæƒf3×Âi"Û>n·üâ;F <~yðï->|V˜¿óï þñûF-çß ÌÏuo«aúGåý‘œÛø·ß°ÁöºôíÒ~y7ã[lŸãÛìä¥z>ß?äÔr\¤«¼ƒcþ«J¯cP²øÜß=®Ïq‡:4A@¾‡ äà Ça`u{DtT&P:®¥c‡2=¿É¸Ä )4H䫬Û..œ¨ŒöÎÑNnI³ç~XWqÈÇy·Cð!`Þ'<¹êÎŒt§:He!'ÆÆ^9ÇýÖÙÔVF»ÂPÊ›ç ù&Á&\‘ ¹ø<ÆÚ“*þ_²¿>&÷ÈÃmö|_˜¬Ï#ÏÙÙ h´ŠªÈºfŒ»£¬>‰€Ì@‘^¨õ™²Ì5V<×BôÛÕ©¾{äé8k[lÏáøEø`»Ó#¾Ù3ì;¥Ç.Fã|`}qY1ª¤6 _ź«&àÐyýfM.e„1…ˆaŸúº”S¹@ëŽßkP›0hpBWþ.U¬&Îk§nêè®T›¼:?zWdÔS)—ŽSúÕe’ÒŸQËÍ'üú‚2¨[‚§{Y?èåŸúË òø]/‡ã"‡iw.ÆL°¬s6¾Qâ.ß&Z¸qÓµRÄ.¯nÇÍA·Ù"|࣡¬à4]Ūt7b·&œ¦=üÄw¤ºˆ]ýT;F :¦á=˜y«°©’]wâóƒ´£êÂüîbn^ŽBónRìîã½»!?ð¶õŠ­Ä06ÇMÀ•¡B£rø2çÊr?˜ý7£rÆhUWóúä†#7w_ö eoñLŽÿÄZtN¨š€Ë(ùñ¬¢¸¸Ÿæ(g©jà-VsÇ–…ýòPå¾­Um­Ý¤à٘ϫ¤äÃ|¸åÃwçÛù ¢; 0{§;G(Œs¥‹˜ ûäw–*,¼y|ãæ]Uëég·uÛX(ä 5Äרp•v;Å6#±‹åfÑ]8`>£;ïÏžÊÐ' ÓÅl¼Sw PÛòNjµ~jñÊ-E–Oö~Úª»ðµ`ýE˜Ç‰-.Øb˜ñ-«Mn¯Ü¶TiÆQǼ—<ÊyÐÆÑgCfuíÔûióŠ.Äôºù(•ß~‰ìÞòaªyÜœo¤ï™ó%Ü nq«±.‰›øÖmLo6?q®ñž³5ù”jÅ7z–bÕ Ê&¾xú<|Rµ÷Ûç‘Ýôžî,èM>>r¯hôÊÓ»9¯Éùk|ºÆs*‡>s§²ßǪ¬Opí'¼äñ>¿†]³s»VÙ ‹š˜Œ›h¯ü ¼¡—æùüìÏ…zùä–R”!žYÙS´À°!Ft òVg DWâ~nò•ò6þ}l”_èd €~à!W?É›±Ãâëò†A*…ðõ¦ð yä's(À8bXÏ:ùD*µõÓ † iL&ûÙŠÞ¥ŒÐ ÅØæÃõ¦‰Oe|3†š(dµÊ¯ÿåç÷)»Áð©bˆ+ä}‰¾Œw2ý3ÿTÆsˆ¯¡¿6«g¹¹âÒXÍ÷Dñô¼Hš¥ÒÜñÿM?W3X.õžáƒƒk¿FV¾÷)šÏ<ϰ• s³¦ÿ üÞ¿ÿPKI¹’Å;+PKŠ›U'*com/oroinc/text/regex/PatternMatcher.class’±NÃ0†Ï! HSÐJéYØ2F UJEE¥0¹æ®R»r/(ÏÆÀðP'²„€xðoúïÎwòÇçÛ;À%\0 àŒÁ$™BoSm´T"%l(5Xb“Î9‰—{Ü×e æÉ/¶'B£:7š™ÚÕ”ýmͦ ®“bÃ_yZqU¦K2R•}ÂÆÉcÞÃ6ùß6k}~®ŸA˜kµ'®hÅ«ÚÞo;’–2ZðjÅäë -8ÿÙòUÛ‡YêÚ¼••M0î3+¡qÙV”Hg0úÌÝzƒ‚Û.ÄúBwZ|–Ç€í:ñíË èôÐé‘S¿ÓØñØñØñÈñÈñÈñ‘ý+`+„v÷àô PKIS:ú>PKŠ›U' com/oroinc/text/regex/Util.classÅV[wÛDþ6²,[VskTP!---u»æÖI $©Ü$ÄN‚Ë¥(ÎÆ¨¨’±eN^€—¼ð/ôúúZ^↜ÀÿD˜UäÄm⇶Øçìîì~3óíÌz<ýóÇŸ—@i> J Ê –¬(XUð©‚Ï|¡àK7U$qFE gUhbñ’Š8Î ñ¼8x9Rdöb 1¼"V—Ä*­BŘŠ2bbVhä4Ìâ51¼!†÷Ä𾆼«aÓ>ÁŒ†%¼®¡‚«nˆÕgÈkø —5Xx[Ã&4Tñ¦†u¼Ê ¥ÇL†‹é±bÕ»÷žíVó>ßôó ^ã›ùë–_ýz‰7[Ž?Å0B¸[ÖwVÞ±ÜZ¾ä7l·6Yaˆ¥MaKL$J›f$øçô®-ßç 7ðÈSÿ:ê¸ÔZkú¶ßòm0¹dôËÿÉ(:Hß_'¡°YåuQ š Œjè€9_.,-.gÊ…›3Å"Ã`÷ÎüÂ|¡¿èU-gÅjØÖšÃI3YZ,šå}|iy¶T6ËËjÉk5ªüÛ!ïÉeúA^·§k}½àðÛÜõ‰¶U¯s—( ï/º‹Cj×lwac£É {îØ3\è%ž c=?F†KG`yùò0ÝóÇd†ÓÑ  †DÕs}ËiIR4:7OÔ¸¢¼<úìÚÚUô~£iÛU)wk>™–›uÇ&{j³CXd.ö­&|o߆¨MHR_ƒ">Ã5’úèkàã.™‘üÉ}rA´3´kvíö…» ZQ¿A¨9’†hf4Ë™6Nü’¢¥¿¥'A3ß…Vic`RÞ…\ɶ18©H±{Hgvð<Ãdܳz̈K;Ðû°·1HÏõa"¶%íþ†Œ¡Œïà”„»{øì6Œ+ß?pÿVè~„î.Z³Df<+=Àé‚Úñ+u[*Í?í"UÉ‘±6ú'“‚bNPLH•‰ø„|Ó[±½­8 ¹*F2§Ë†ÒÅõäjÖHŠÏeˆáˆ‚àTp—õXÀ<ÑaÞÖãw!çîFr œ\5’Û=¤x%¤¨S cb.‘‹=À ‡)Ê…€œ¥2NóÉÌø.╬.·1”ÓÁ…•ÉPå )È4‡*Ò‘ï„£¤!x uk<ª@"Ák™ÿPKRÌ PK‹›U')com/oroinc/text/regex/Perl5Compiler.classµ;}|\Åqóî½wïÝÝ“ô$ëÉ>ëddóeŸlÙØòY–- Y–A KÆ’ld Ngé,‘î”Óùƒ/ã‘&!4Ó|Ht’K'‚l¨É…$$4¤IÚ´ùNÓ4@BIókÒ4å:³»ïî,,ùúÇÛÙÙ™Ý_ëéó ÃiXüG…D…‹ … “Šj,NIö-*²:üT‡Ÿéðs~¡Ãë:üF‡ÿÐáM~«Ãïuøþ¤Ã[:du tIÒ%—.ɺ¤è’®KݺtP“nФ5©C“vjR§&uiÒÍšÔ§Iû4i¿&õkÒ-št«®‚c^R±š·{aÜA5,–Ã^¨áÅ]¸î¦â8÷Pq‚Š?£â^*ÞåAyd»jï&îÅŽ÷Pñ^j{Ÿ.‡û }?õ>@mAè¨ö—ÔûAª¤âCTü&¡ñ`ïG©ø“TLQïƒ$à!*>NÅÃTLS‘¦âPñ( ùq|‚ÐOR‘¡âST|šŠ¿¦ÞÏPqšlðY*>GÅãÔûy/¬'ÈOzájøOQ1CÅ¢;ë…•pŽˆÿ†èž¦Žg¨ãYªý­ÿ _¢â›TüÿDÅ i1¼aHKà? É/¹ i)¡•T P­JR iÕ.£¶jª-‡¯Ò øª!]ÏÒ•ð;Cº þÙ®†ó†´’zW[~`H5T[/R-ñ®%)ë¨v ë©Ø@muTl¤"$i†´‰:êá'†´™Š*¶Às†´¾kHðcCj¢¢™Æ¸–Æm!Þmð²!µR±¾fHmðCCÚß7¤ëHÞõDÒGÅ7¨ø¶!í‚1¤›à‹†´^2¤Ò´—Š=Tì¥"LãÀßRþÑÀ— i¾bHCÄ…¯H ¯\ÕÊÊv ÊW®ê¸-r$²v$^ÛJÆâÃ[Xç ”•«ö·h]%rT"¸€eÛუÉ-œhû$PW¶2„í¼¹Kjç’Ú/*‰±¨+Û´V^¨' Ù0W{Ç`btm"™ˆÅצ¢ÇRk“Ñáè±µ»"©T4GáWÍÉ5‡!V/ˆ0§ôœZ¢öus´·Ï¯¦{å¾ýÌT—¯Üß:?y£šc*uì!yû[s&ø VY€"D†+ªS…ËШÊÖÆÃj\SŠAiµ‹jkkWUÇ©êdt01Ý’`ùºkÖo¨ÛÚT¿9r`p(z0·lkÝ޶㎷5¥š¸¹&X}012’8:N’ᄪcñêè±±dt|<–ˆãPèRVkKw[¸½³»­³»½§}O[xgK÷èE­‰¡¨E­‰øx*O퉌FÜÀaZz;zUQÛÍ=mÛÛ¶ |q[2™HŽSIUKàm;6K!>.Á’¶|ol¼:•HTD’ÃÑZÔ MpY{üHd$6T½ÿ–ê$®G´P R-±)Dß‘Œ¢EãƒÑ†ê~ Êì®X׫ÕwJðv Õz(’䋽+ÁèqÉÊær„âŽÄ`ddO$‹‰âŠw¢Ú;Ú;mƒ]ÑOE‡pÅÆ¢©›hu°¹f¶ÍËvE“#[£c±‘h²–†Ba»ÛZ¶‡»:;ú„°’îöÎë:Úâ}ÝÑw¦IV¯l–`™»…ù ª?‹GRä+ÞîÄáä`t"¿'‰ô_`ÉúÞ8âÑAR}i!Ý«"Çád´¶ºz×H42¥y%’8È!\°‡‡—K°ßÁ?‚ª'ÇÉ?£ñ¡êÄA§”‹Ì[Âíì¢øîÚÎê»õŠÚý+WÝ…û¼/ž½¡p1Âa{Ÿ` ‡¯ëèÚÖÒ¬áðõm7‡··_×Þƒ[7¾±­mî±pxg[OK¸õú–ÝÝŒ*çk2ÂáήÎÎÞΟs&¸»}箎6&!ï@Œ§{WwOËî¦KÏî¾–ëZÚ;™€½]»»{He¦À`b<…*ŽÅÇc­$M ÅÆp©F"Ãè÷f8Œk½+oV&~,™NFF1 äêÝ´˜=Æ#G·9w)ÉÄ%’4d$™ŒÜŽÑ/L;™ÔŠ&££(¦¥Z’Ã,yÚê¨óv_عÁôðp4Õ‰[œøE•¶9ÉÆÝoË. ÇÆ[q}ÛããÑø8î×#(©‚ÑÝF¢Çvç¶q×IŠcÌ"J¢³íŽ]!™‰í{É¡VÛ¹hPÜ“Ñøpêi:zx<Ń %¬7…[3u;Ùz¶aµpâàÁñ(›IbŒ éŠG‰ÔF)" Ò±žÛǰ¯kQŒšCö :6ˆ¸[Æý0m¡Ó‰í(R·¥£4C¶%i0Éáhn:­#‘q欹Íauoº>zŒfÉê]ƒ©ÈHŽ8o(Rq ý¬=¿zÞÛÕ–¡¡.šH*‘ìÁXD“Î÷ð– »…1™²É©­V¨õ¶XŠiŽ;M6Áó-™bD]9s³6{¡Ü‘1\zŒªW/ð‘`íÜ”;##"£C"CÈE> sstq‡¿ò¢™†}ž`Âó6tÎSG‚¡"ѧxäÅÁ½¸vòЌͱøPôX×A´K,1<:~ŒšÆ·Ç†ch9_l¼#qmŽ[‹a½h:¸9ÅRÑñ±EEùcÖ±_Jó­íhÊaj»,ß6ç±ëš§è:pIMö:VÌ~¨Òs(™8JgNüEœøK8ñ/rànĽ\C¼ÔëˆÃïrø2Ä ^.ºtRî˜ âý“A¼‚2p±€•¬ß¯ØÅ¿,°‹þ«`Þ~ø£w#þš×ÿoŽzƒŸîyØòïØÒŠ– ·’MÏÀê>5xþÐY¸f§¼5Ë‚•uçàÆ)ð®6ûÏÀðÞÕØ@pB’*ƒçOe¶ú ù<=Â0¯å%z† žÔ9纴^+Ø´*–šÁi(]jÖLƒo©Ù< ª|Z9-èñr-è·³iÔã°À†Êa-ªB¼WDî*‚Èo¼3 ¾`å9¸eŠË“m‰Í9‰)!ñ£gãòY=›öèè¶eßdh9q­Nƒýp¿ •¨î.œ^ë…]hvZìV9¤¬‘å® TYŠv,¤XŠ¥š%ÇO„”»Fî¯Uº˜<`•}ÊÊŠØ:Œô…TW:ûM+'¼)'ü&N×–¾ÜRÜL8)µnˆ¤»²³Xx±þS\ùMe_Ê‹ßßâïEñd½#•Ÿa})üh.Ãl­bømÁo¿=ø%ðÛ‰ß8~øÃï¶ Ü_§œ8ÙûUT»¢ÙSÏÕÌ\­šjO°1Aº^ú¬D&}Á§`Ë PD¿­•½Á>ÊÀ lµ¹®€çW;šˆ¿‘H©Øò"˜ŒA%† :É¡†}LŠ+l{§…ØðU!vŠUv’Ø&§X7š_쬆@o•=ÎvøšçÂÞõ$tãZyÓ ©PäÊÇ,åS±Ô6}®³‰ZBJ*&äì„’%.t,«êz«f_£:úœÄ¤šÜ›áÖ別N¨Ùgß´mÛ / åzѲ¤\;_½Ò•å‰JfŽªsÐFžèš¥4e²¿æƒšE¸o«C!œ†¨â©R,W] ±-7Ä58-ß•|ˆÅ•(¯ mAhe]iLãˆÁJu p"6ûÕpž³ãQB¡$éëÏÀ­dŽúÎ5OÁ.Ò a3îˆ2Kyб”º ¨eÞÆ€¹2 ÷刕‹’›Íi¸9G¬ÎC|yj2PÌé•3p]c Ì‹V ˜«ÒÙ×óÍ{3ÙÄ6˸#ŽOÂŽÀ9›Äwl\Dœw¶8µÒv°zø Z†,t#Úǃ°]ªƒHÐ4Î@k“‹¶J}ƒæ×pFS°ØÆ\3° #þ޽ŒÂ¢ ¥·ìežnéT!#,²ô¡˜a–έrgà4†ÀßG¨973_IÃVlÓq¶ë/MTÄuºcœ¥*ÇOtPŽÉQ Ñ FrÜ›h“m ,T7b)—2€å&“–Znó®ið"À•j£a¼A³͵WìÜ_ã§ ë­@ƒn¶Mì{ l"ü™ò¬·Ynt…¦€Ûï&4K£ W@#³4®@SE`õE, ü.ÇzÂ+ðû Œ …®BEDø4Âkñû)~Íßаáóo¥@ß]Äo¯#¹-DQPÅ bQmg4Y«[´6Q«»U]~kqдy]A×”?8y•`ÆCÊädùU¤ÅuãÊ*_´È<…ô…”\ç£\¨âÇìþUâWåZÔnê­wq—!\'/QR¢ §<šº\§Ÿ}”2••œ… |0§ãhÏ@MŸX+¾€–6tBg †YÓYXÿ (+¦šSU¾¢òa,.ã›RîÆb°3ã¸èl_/àëÜ(`HÀMÖ ¸YÀ\S:§¶!|€Üeˆ×!\ŠÇ”žA¸a˜k áØz@üÂA!þm„Q0.`R@L¤ÇxÒÀð£ˆ_Ï“³Yš¯p"²¶z¢‹‡ׯƒæ²9š¿g»MaósA³,×ìÎ5*h.š£ùƒA³|!wMkŽæÁ Y1‡Ž ¹xŽæAsÉÍË‚¦ŽfMi̸\äY¦SñMqÇÒý::–åy,ÕyLðPL Ìòˆ˜-~­ŠeênéÒX«Xþú¼·Õ‘s¤º¼AϹº]Ý»ïy/ÆçyŒ Ôp tÔ^ÚncgrZ¸L‡[P™ÁÄË\j¹OžmÜ Ú ¯íü³4mj¾o˜êo8ÚÄÑ“§bm‘šŒ»™mÁŤª 8ÎÔ¤->Aò1ÙŽÇ!yJœF ŠÕtê>>‡Ôä…c)Iõå ỸËoŠí¤¶ÌëÈjåÆ8 ¿AÉÈPHÏ£ÍçCžŒêµô—7âQfe†ã(³ãŽ‚ñJðã_©FèÐ' !`‘€ÕâÙ#ÿ˜Ÿ=Êëüìap•€µîϘàg Ãï"ÈÐ%ÔºÈ*Êë[”Ó·¨P_öG"NºÞàqRšáq’Áõn°NÀ†Ü$`½€›tÆIEÄIEÄIEÄIEÄIEÄI…ÇIi«ˆ“ “Òˆˆ“ “Òz'¥•})^Á(È_FŽ‘r˜fKš\›3Ã9hŸ„k,ía¤ð’ vOhÒ¬8h¹q0ë.ÖÜ–fÞóŠ#+þñ7¶Ú1Qg«È¾»XÚCÂÄKز‘âh²4%Í•S8X ¿3«–v²÷bašQ\Ê”Iå!Xå™ñ<çù2ÅÅ‚[AüPÜlwãÕ™2´\¤ÏRJ%8…·YK)ó?RªðÚUƒ×íŽþ:Ì^Í’ãÇèedv›ëÞãù›óxŽß:Tú¢ùïdÔ2¤’êAÓC‡ Ï4<~gh{ªðõôÒzfy…OÜš†jÇõI0²L¦ì\Cá {dÐdÜcWÌ^ Åa ¼åŸÄMožÊþ`á Ã-x­2פYÞ!LÆâCrc.UfÚuRÜòíSÃõn wVžU÷‹¬º_dÕý"«îYu¿ÈªûEVÝ/²ê~‘U÷‹¬º_œŸ§ÂÍâT‘5›ü4p‰ÓÀÕ,Nƒ ‘5{Åið–8 ^§ÁoÅi°Zœà§|GdÍdÞ¥'1ia>©Y ´AnVòžìÏi©3®Ã9Ú©yiÛmÚ±ùåVåhç•+½i®k¢G‚ ©ÌÍe_ãDßߎfÝ©ìkfÃÛô²q^å"ÞkRlÿ¨Y„åM–÷›–÷™:–÷˜•XÞnjXŽ‹Èãð=Õ¯Ó1H/Võ~]®eï$pCÎØ§#8Š*áé†RÖ\(Er“œþ¼eˆ$UNÂK­zL›R 6ôæþÍ*öêµÐ-ˆŽÿ s´ë`Áµ¹8=#Þï`Pçe¸< û2üIxh=idz¬ò¢«ÒÙ_r¬.ÿ<·pýïL»>ìtvÎyn™tÝÍÓÊ?h^jm>ßòå2:5Ÿ¯¨¹|Ecx3Ðhyé'–b˰|ih²Ô1¡J b¶¼,?ûI˜Î>àî´ô gbÈdj$“§{þ’ü¯„r½] ÊIÏ þbË»ðÜ1§ÝK¹ìÑ=oö(äy¹FN®‘—KöòL’}u3Áõ 9fÿÿ=1«È2¦¡67?mþìX›‚µ ˜¤¹nšeš==Kµ7¥Qi LÁãrºgp*ÔLC9‚æiz¶£]Û…y£®‘y·¦Q&ÞE,iXN$*îë%AÓ¤·à,»Ñ(»É@/'òaHP0Öï …<¥y7çYΉ| ç)#e„ˆ¦4UMÂlþËí–MêK¨L/˜õ\ÖÇz,%h®Àtí D‚¦Km%¼Ír? ZŒóÒ&a=†f7fù9û/²_bÊ|¸–Fµê_Ã,­2—Ùºyfk)n;Ë]`  ©.åÁŬ²u$‘¤õ±£Ý~)g.A³+êJ¸’°Jn’»äÝdÌ[á»ê ©d]ŒÝžÕh€ÊIé=ŠxO÷ú½¤´ÏòQ…+í#¥ ³|9¥¥z›<ðÀïk´›åŽ0 –£ü݃ÞÕ¡Aà>bîK ØTÅ~£©¢ý*–ö!V‘;ÄV˦n9œ©eï%·„NqÌ\†.·¨ì2Ì¥F\éìØØÕ9·±ÐmèŽ\f8|¥P¼> §6PFß4+ÅÛžŠ·M¼ýxÃØCodxˆª®Ó–êšÆÛ€¥’ Fðº`i!ÕïÁ éøøVÓÑúÖñ.‚ÔÈ®iäþ4K’-ã¢Ì—àwMg§,…û`×%öê”Êoåk7ð5§›­9¦†lÿÑmµ&hÄä« šËY‡­V¼A™µæ:íX•¢dE÷*¢<£¢ŸIÙ³¯âu®‘v“yea¸‘ÔÜfÏÀ2ì]ŽyIЬ¾ ×R&¡Ö1u{Ú&&`3ï`¾í¦àÖ9èo@ú—`ÂUi§TV«bòÕÙ ˜Dÿ߯îZÐ` ¸;åWa¬, >ËûjÎBÝ Ô”ãl;o–‹dzCVÈÙdú=[¦Ø(Ͱë¥óÏdÇE3(¯9û\¶zKEÈÛZ–{[1Yµ=‹§Ë–gા³PKo³$oÂ~7ý´ƒ mœíÌ&‹ü‹d:ˆf©rÉZ°Ô:¤°‘6™^û¥hnð»]3õ»Qn«_ëwf ×ïÆùdåN©A“t…ÿlÎ\ò¶º)å~KUúBjÈÃZ=u¡ò ­r³ó%äË`–åyz¬òZöf—yJ$«LƒWé y§²/#f¤ÑQí<46eŸ"qÓÙÏ"¨šÎ~òIè¶ÊÙ%,"ºËo‘ܺgïWB‹2ðŠZä¢8 W‘Uyæ–e©|ÛY5àNzðI¸©÷JEörY1Q!Õa&§dÀ°*üÖy¼ûÑ»¾ßmyÐ^<ßÊÍrJyËM+íh¿‰+¨¤Áò»ÑÀM|ÖL·Hl¦¡Vü-S ÎÔÒ û&ö~åwëN&kÑTv囄¥–wè¹½qŠ^ÿqÁ›ÔHI!ô,¬k0ìJ‘*Fß–C¦*•CeWŠÛ¶¥põ¨éÊÒ÷}+dò_òy3_cÌxMc:ûzÆUO+L×ðµ(¤ˆq8È3.‹[ù4Ÿ‡‚­5ËOúBV˜ÎþÊ*ÉÍz ”¯ãŠ˜Vé…2êýF~­ÔeÀ²ø›{­bË¢‡Z“€c|OFz®(v<ÈK‘NÁVÔ¡˜ì1‡0 ²u}¡ò©ÿ=ÁXs~_W§¥íåòŠmy8xN$ë{˜ráq r¤A³Ê·+„Å*Ãh…)€Ô@ÛO¡Úk׳H×  Í@ö•Ì@‡_{Êýnú2…1Íï6±³Ó¯¿@›—®á)ï>?Ç)ò=~ŠÀ"ñ×`Z°OÙÛæ"ý– ­¤^úC“ÔÛQÇA-ç¨sQÓÿ„(^q—ˆ?r4‚gñr£Ða²™¿ÅJð¿ô ø?PK-ë¨Ë:PK‹›U'+com/oroinc/text/regex/PatternCompiler.class‘ÍJ1ÇgÖÕ€Øúo B=hzëqQ(¬(zñ4MÇ%%›”˜Ê>›À‡gµ~@‹5sÈÌ/óŸ™$¯oÏ/°gp  «`WÁ>ÂE¯œÒiG¾Òí¯ú§¥ µ1Xotâ&éÈ7úŽRâèû—+Tƒõ²£Þ}±>ëX²þQ,/„:Eð‰|‘›K¼}Õž%+¡[CnDÑÒØ±€Ã…¾õÌ:Žçí5D4 óhøZ‚^Ýù†ÜCˆ5O%¾û œü9ëW/e>]„½Ÿç»OÙ¤ !“ÏiWžË9ä cµ‘ìøA6—ÈÖQ¿‰XGü vÞPK­å‚GøûPK‹›U'/com/oroinc/text/regex/PatternMatcherInput.class•U[sÛT^ùKŠ/isií--Ø2Ô@Ë5¡m"0$¤0ÔE9qÔq¥Œt áïð܇v73e¦¯Ìð£:Ý•Žd9¥$ãouv¿oÏîž#ûŸgOžBÞ†^¾ÈÃ7yøV†ÌÊ ÁÁ¼Œáù>-\ ¸HP%¨,¼Bð*Ák¤¸DÚ˯ÓòŠ 7 Nð.ÁunÂG*Ü"¸M°B°J Ã§*|F°«°NOÛpU….i»¤ý4 ÒõF[‚óõÆÆ=ãW£50ì~kkï3ùÒi÷6w-»¿äk:>v%ÈÔ;:™vÍ,š$…Q2Wo'dzèþl”üó þ@‘­ïèdóhOnÙ²-~7Õ}&Á´îØ7lÞ1C\ËkÇ&;âz%°ù™¤ŠŠŽi :†k{†Ì…;ç̵7 n2·m ù5bÆmgèšlÝ`úCíí±¾eoxŒc²ž9t]fóÐ!÷˜½.*½û”s5®(¾µ1«Ôs\ Æ`uxpÀ\¬;òè‡FPYä Zîb;ÎoÌ Å95+i˜Îý–ã:–m¶8;æ-—õÙq+¡[,Û¯:LÙg|¢æ9Dú2>ë“=«èŠõ3…K‘é>nžA%ôÆDåÓ—tÂtŒ½ ˜Ýç‡x9ü!beGŽäÂ}\&‹Þ©ÊÞÙª½Éª½¨ê’'ê bxE ÞpÏ5(Ü¡SYq]ãw”q'(*ø.§ €|3þð5õ­.캰ørûö¶°·„]vÕ·5̈_ˆïãê2dð`N;Œ–B jÍÚâc˜yäëˆÿŽàÏ#›êQ´fºù*'“®¿LÒscþ{‚?+’(éÓÈ…ü”9$HheíOÿ3µÿ@pºQ/ëÈÉ¢ýDkŽ ¤I#(”5,ôü¦µÚ·—ƒË)Jµ¸ûAF›ÍŒ@~åü·~cCéFýêH¢?¤íJÁžZ³‹ûÿÏ]“›ÙçДü~'ŠŠ¹¦)_u÷F8’Ÿàš`]‚ò0á_¾;fÖªû'Ñßô7NI/V‰·»ªh)Oh¾Fn YDK'SANéo¿·âCz©_&¨AÍRÎ0܆†WÅ—0\ ÿ€lúA&ìêËè2ÄóL…áÍ݆7Ã…0üþᬂfÓªxRáàï&Ç£³û1Š×D¼LñØÁ‡Ì_àMÁ¼ŠÓ¦B.Ä'ºß±awþS¢œ–|ÿB‰*vQã’ï^(Q„L‰Kv ½')ÿ¢)ÔµB—€B\O'4BÅ>¾÷Øç.¾¿~ÿø‰'æ¤{ÓZoŒŒ¤ùȰ¨ñ°ÍµPf [Q)ˆ§m(#÷5R5K/âIÒ:âíÇI\Ç9c,&X\IâKÜHb“˜C9‰;˜I¢Âºy_a:‰^-²á;^™¬[ÂçITñi÷pE1‰&.(ˆæO•¥œ—rQš/ž* we6iùòk\d<’ŸºgÝ· ¶[(;këþœï kuŒM™½M2üàÛ¬°j“ƒïh¥³ª›–Ó(Ì,ßU¬¼‡J:§ßv¦#m§!¹Õü"—¡åï¹Ð8!Ð*vÙvl‚<ŠnM(è+ºNË·Þj®Ó>QzPk¾MZ ôïNRÁþ)·j5ç-϶–›‚ü*Ó®sÆ Ë·ï Ý­×[Â×­VKxL¤ß·Ý¦Å«ÑÄí¦°ZB÷Äšëùº¿b·táy®§û®¾¼Þh]q=×vª£Uw5AÕÝ^ó|ÐIÙÔQÎ…’œs×½ª˜´›”±BuFîÒÕ ™æõÒäÕÊÔóZer²4k–§‹³¥[¥é; Lsy½^^Ù©zbU8¾‚¤iÖífóšÔS“LÓæCxµêúÂÕŒ¬IAo¸Ÿ³L œÚL=HPAÊlÿ–åWWJ¬"˜«ïh\ÏnØŽÕ9Y3‰ Æì„Í&u×L×z—®ÏlÉÓÞì}ªE6¾43§ Çò<ëaÕ]{¨àu±4´à‹~Á ñ °»©tnW½v«²¶&¼"ÝÍngªg:£AӾǬóAãÑ=0¯)äˆW,Ϫú¬íß=Ò]ª¹‡-_P2jЙ<ƒ^÷ÜU]Þ‘pÓ ùëž#júY½JÔ­QJßw§Ü‚ô1@oM€^ á6n@Á$í"„~Säš^ðG¯ˆD3Äyi?'+!.„HÄE‰ â¤÷Šd‰v%zé5ÅEc½ÆHF®F´4‹ŒaÑÅ6ŽÐ°AÃȽÐhjã°iãÐIÍ”ã!eš#„=ÆÈ@?vÐ÷Æårè2DÕò©ûçˆ-Œì ™ëò ýräÇTý¿·#üІžŸŸJx:—]ßÂqã)gÏM¤²Ã »Á{[P‡+?)J6·ùê߀ø–¢–qòy1#Û) øŸ„öB…P#ÞCÛ¡ù\¢ 2+ijfœ°‡Ìé ¨O3T¥l¤J-eÍ`¶61ü}Ï¡-¤";Øÿ×0i,½Ð.1ï@F“ûg¾ ¦Õ_¨Ï™Váwåcá)Žd—èbŒá´J8¸…A4‘Ñ^2Ô˜$–Ž= O“¡éØcºjâÌlá(ó ¦cLV /¨aøæ«§²‡-J22Ýxn'»’MuÙSœËúŸJû ƒ_ЯRß4»¸4 ¿…“÷X–§Êj¸Ž~†Ùà8~ÅÍ-šÐÐÂÆN…ã¹®úr?ã˜,+ÇUu¼7_ý½…}²—|=¥¡8,3}ùB&e_J?¸=-º­nïÊ_Á2Îï1 éíptoɱœúPK <£QëªPK‹›U'(com/oroinc/text/regex/Substitution.classuPKNÃ@ µC¥BKpV° s€ìZ )D¤ì©¦f¢‰å$†àPˆ Bõ²Ÿßóïíýåöàfc˜Žááù¼ØÒ)K®Q¥ãšEÜl8ä…öÊoœV½¨À ÷ê†D?Üs­ä×´»Tw$ÂÁ}Šw÷þbåÂhé׌0[z× 9©ÈÆ”OV½æVLBŽ ¯ÉV Õ–0)} š¯ŒMÔ“2Ö‰{>lŠpJmËný³‚pöÿ6¿IÇß§ÞÖ[Ö’! d0ŽÒèô×Á~ò|PK Ô=tàjPK‹›U'-com/oroinc/text/regex/Perl5Substitution.class¥VmsU~¶ÙdCº-} °¶¤i"/š–j ¢é‹mm-¨a›lÓÅínÜl°€ â?pìÞ¾ô+ÌH 2Ãèñ³ÿÁ„õœdÓ¦4EgÜÌœ{î¹Ï}ιçÜìÙßÿþé<8€ïü8ë=žUz$Ø  W%|!áK _I¸&áz>DhD4™…ðâ ‹‹CÛH¼Îâ0Oß`íƒò¶c,޳x“Å[ÌçÕ¾Fˆègq"€˜ùí$¼Ã¸A'œ`ÒS¼cˆq§yጌñ‹ 3,ÎÉÐq^ÆELÊøYT øP† M†…)y ³gñ‹iŸá#EŒÉ¸„÷e|ޤŒEŒÊ¸ÌÚŒÈøšµoØÛ övƒ½ÝdÛ·Hɸ…w@€'Ô›ÐêM]T/©1C5s± ÇÖÍ\_yqJ€ê=ŸÐJl,ÎÍivƒ½çxH2_†ìèìE-ãôm²¯9ê¬g¯áNrÇC©Œµ³lK731G[tb¶–Ócê“™× EÃé«K mæþ‚õàSÏѸä/ Ù¿5¼èèFlŠx­Mþª@ò·£Ž½œ‰Í ®×ÿ’!"øþÿ$7GµÅ®1Õq4Û,oÞšÛE•óõë¦î PÍVVД°Ì‚£šÎ”jiZÌhyG'«nÚöäÈäÐøØhjpr(=˜J h©µŒŒŽ h«w)Úê•¢9eeTcJµuuÖÐÈÇŽ1Í6ŽNg ŽîÙñAÞF‘LXE;£Ö ËŸ¦]BQ1Ósº©I“Δ· ÕѲe{[ÚP κ™˜Øh6ØÈe Wí‚Æ>) t¡Æ7¯ªÙì¡-h¦CéRóyÍÌQE©SÀž­¥€ž-jòü©„ê#+ùÜݦU$Þœmójy¤Hº™ÕGç(kúZ]%½pJÏé„o_/Ub^µÕ %G@뺕ӕcÛîuÛHqaV³O[ö‚ê¬Ýº Ï—êYÿÞW±5·B643çÌÓy š“rõí¤o<­XЯЋ´mõ2ͱ*üôŽõRKI³Piž¦YýdjæÜÚèõÏ Ž_þ$¯sO qµê „ü„^Ù1j?~ÛŸBžñ¯`{Üû¬5Ç}¬µX•Â%ôÆEÏ€§ßsb·;—pX»<ÆÞ%„ë%(ÓŠT¾۸ªxY£M»ÉSÂk˘§-Q…Èý3Š–VÐB«"‘5OÚç¢}Œöô3_˾»u‹ñÙ}ì&‹xáHË¡;訨e×~±MŠTõÓ#tþÞªJîzêºÛ[ãnA7â¦õˆ»–àS¼„”FúàUJÙøÑÈõ×Jò°‡Ò̉®%j8”Ð%¦¨<Ô“]ø-"dŠ+á±³„Ѐç˜H‰áYP,áå¸Oñý‚Àš"`çô2Î*¾ŸáK۫ǼAïmô½Ñ'xEÀ}tEƒÞ'ØÝ€¸_ñÿŠÎˆâ/¡‹¶µFZöq:"Ao /Mß… Ø}oõ‡‡åˆþvpcê Pë†?Ü&xVÐºŽ˜qí„h Q G6ι€n)ÉMáHW =Uк,U–>÷ÒÆÂ‘ìw=B°«áv•O²‡´æpä1v<ÂÎe V ‘EG•ˆ>a\¢ ú‚’h<Ãyý ­áH”®×|ÝÉ›•ûÐ*Õëayzr8LÓv⡃“Yu0_þ[åþPK_¤.Õ1@ PK‹›U'.com/oroinc/text/regex/StringSubstitution.classu“ÁnÓ@†ÿMÓ81nÒ¦m %´Rà8m …[**ˆŽhãn]WÆŽì5Ê“ôЧh%šJx 1›8EÁ޳»3ßü³»žýýçç/,`¯ÊØÐÐÖ°«a_ƒ­á¹Ž"j: X®YQ¦®£„Uå[Ó±ˆu5kØÂ¦2MϰcÀÄc-<4H÷¸oàM0,˜­c†5³Õ9çß¹íóÀµ»2ò÷pì1ìšÙX›œžŠˆ’Öóp’¹ÈúÓœŽ~³Ã(ôÇ–b(íH¸bhàÒ9û,âÄ—‡ÇYÍ9YŸ¸”" ÆÉóµSj¼±Òk/ðä†âQx"–ŽÂ –<=î'´Öß 1yÝV=ﮪÐá~Gïû‚H½&‘#Þ{>ilL¸nÒ¥'%¶¯Dû'ýŽ\yF¥Õ⎠­ñÁ@'Tr2éÎDÍü³eK1ìÌAg š+ä¬gùßA?öÏ…#g\“B üÿJÛ÷ÓsÕâÿ•Ë2œ°Ôƒjlj6¡꣞%["?53ÙmZ­AM ͪ³[”¯Ç š)Ð @‰èÖ-AíªSæàŽÙL™ªÕ¾! ¥T¦=”[¡Q[´~@¿JÃ/sÂ#Ó°…Gix‹jh4Ö)»r‰âu[ÉŒpïË´Ò²<ý PK®›üG÷ñPK‹›U'-com/oroinc/text/regex/CharStringPointer.classT]OA=K¿×RÚR@lƒe ¥š˜¦ ƒ<ԥʒ²K¶ Áߢ/úâ šˆ$šðüQâÙÙm‰Ä7é;sιwîÝ»ýõûÇ9˜D)\\Dð(‚¹GðDEÝ*ºPBOŒ¼$ߦ¸IómoÃàæ&7Cqh£€Á8¦¹™Á˜‚@~¼,lEA&?¾¼§éŦn6ŠëŽm˜ynûFA0_áü>Z®¢r˜¸¡üV™¯aZÅA„; — Ópž)P(LyW·]ñKË0fOñ §lÕ™‚î²e¶Ýt6ôæ!ß/®,TW—ªë¯Ö*+/¨‹Ç5vàÄ¢€TAbÙªéÍ Ý6ôí&£CuÝ:´klÉh’¼k‹r†«ºmëïªÖYÍfûÌtø¦Áœef6œ]¹YÝÙi1Bb|#ó§|5uÇ8bœl˜~˜hÕh=wÍ:•\µd„DõÀj9 ídîAÅìÈÞêLèXnOÜ­YûE˦ÞÔŠ;vŠ6k°ãâ_mSÐÛ~Õkâ4Ù>]ÝÞc5çÒ‘—%ê%D’æ&ÐÌ]ÇŒ@Á(íºhð‡¦ˆlŠ~4Y„Ü&/KQôhgk…SÄ´Ü)â_á>ÃÈIb/Ѻhh…À"a IÈÌ 9íâ¥,ÙØù'$²ï¡r?;{’VN|Õ TJÕÀ¿E_ É ñ4Ù·Osž.'u¹NÝú¤.M+oFXð=|ÒÇSñ¸ü€úãÉÝ{†µlG{îQ·]<'{äry¥Pà$èEšö ˜“œÐ6E§‚ïj>Ò{RÜåØl;J¦ã>n9Áï¸æá?Ë„Ì2âf©Ë,Õ®9ráêȪ‡ÏúøŒ|c\ï·?Ií»íÿŒPZ)‰{½Îzúûÿ£WÛú‡¸!õ#‹Ê2?Úƒ"Bdëgˆ~\óè—ì!úåÕ¤=v@°;¸yñÜúPKHõç»ß²PK‹›U'"com/oroinc/text/regex/OpCode.class}•[SÛFÇWX²|…ånlhS. NRzIš´5B€[¢Ø&8i«(F!¦ŽM„¡¤Ïý}i2ÃL_xéä¡3N^;ÓoÓ/ÐôÖ2l§™Úãßîïœ={±%ëÏ¿{ÍBì û.Äð"(„>Bˆ 4B˜ "„hè ^Ô‹â„!Iè' 8a0D&ŒF c„qBŠ0AH2„,a’p0E¸H¸D˜ÖÙ¡ÎŽbì2{?ÊÞeW‹„áj‚}®%Ø3–O0Ÿp@è°e……f綦Îs÷¦ÏŒõÔÙÂ\AaáYr£×A$r«Þl´Ï»t Pöާ°¤ÑntÜVgËmÂcæqÝÛï4Å8Ô÷Ûu·¹åú ÷QÓC0nïSéâž{äb|¹}è×½ÕFÅ} íÃÉ­j Ë8y«&ܪ٫ Óœå¼q—âËv‘âËvÕZÁIœåͼe¬SÈ(ÚeStª›ÅåDg›B+…µB…ÊMªBC³Ds;oTh¬æ¬-wC…ÕR¾BjNI„ЊѺS*X%[,jÛDïl#V°FıìÊzÁZÁòFÞÀ¦ŽU-{uµlbL²«vÁª˜›´†½aZÔn«eÚà¦)N]_Ú`+e³{ü`Z*ùMZ³\5 Ó\¡nÕ*šå²ØÝ½õBÑ,Qp×ëäýÝkçÝëA×òŽ;ø¹z]ûñã~Ø÷|·Óöñ RHhk'°á{GçbNã ÐÊû¾ûœòƒ{mÇxâún½ãùô%´÷‹^k·óÄnág8SºLèÑ©<ß÷h?íîBÝ ËÖÛOsm¿ÝhÕsl+ç{»Þq®{Qa5º¬rM·µ›³íyõã¸!.ãž™c)f±LaŸÒmŽ6ÅÖ$%Á]ÉU¸-¹¯H†?’\‡¯H?”< 7%ÁïJž€%O ’÷ÃW%€oHÎá5Éá;’Á¿‘|nH>ß’|¾.ùüžäãðºä)¼ïK>/Iž†oKž;’gá_K> ¿#ùxUò)ø—’_„oJ~ þXòi¸'ù |WòwàøÇ¤ÿgúû­´Ï‚ö»}6>ÿê_×E¾e¡w“ž¸¢úèa2ŸQ.ÒCù'ìÃÿæµó|ãmùðyþ)[ ò\¬‰ÇVZ{ØË¶ÙAvÕâó3H/dèS–^0M=Í.¼~ùæ¯P¯ ù¿ÓµÞ–Ýée÷ÎŽº,6=ÿÓúNÅogìö—xòÓ3ÙÓLölæ}v=¨½̼˜æîKMóïOØLšçEÿþ Oó«¢ã„ÅÓÜù èSµ;£Ç^0Ï ZšG›ÿ•½÷‹HFØÇ½´²…û/åŸù=Vã1Í®ñ8!­BVµ_±䵚ªVk>a|t½Z‹àÃÃ#‚Qc<Æ<&yìçýàñù 8ćÀa> Žðp”‚c| çã`ЧÀ >¦yÌð ˜åYp’O‚°7>%¼(8ͧ«¯Ø<à!Ѝ´–ÓÊ:m1Âãt1§. æxTèT¡‚( QÁ0Œ‰‚qQ‡Ÿ@Ùl÷;VØâêÿüPKP¾^Ä` PK‹›U'+com/oroinc/text/regex/Perl5Repetition.class‘ËJ1†ÿô6ØZ[µÞ×âtV®7ÅB¡¢(táfHÓPRÒ¤dR™×r%¸ð|(ñ$ ® $çðŸk¾¾?>QÅŽ$8l¢‚Ú:¨3TOÏÆ e”¿e¨õíT2´ûÖäž?æzEvó®réyØád$ì"µÎ*#R/ Ÿ:9“Eú(¾z’KéUP_3lŒ¬àzÌâ-)¼÷Gs9篜J<Û•r 4Õc/ÔC¦yîCtP1t¢ýGÍf ^D(²’€{;e¨g†: Ìj1ŒƒˆP¹•-¹“f ­uA• NqÇÿš„¡úL57³ôa2—Â`´I`îšg·ävÉ­’=t"÷K{§d·ä&Z1·“ècÑS?Gõ-ÊhŸôVÐþPK÷ÿì›*ÔPK‹›U',com/oroinc/text/regex/Perl5MatchResult.class•RÛNÛ@=›»¹…„^bhUd(Ľ½@y(¢‰ŠªH‘*RÇ,©‘±‘³©ò/¼ÑW¨Ô‚ÔV|@?ªê¬q(Q¥ZòïÌ9gÇ»óë÷÷s$1‹¥nfñ(‹ÇY<Í♊U¤1¤P}XB^ˆ„‚JP”ÕQ 74L $a\ÃLk˜‘0‹I eÜ×0CÃsÜÒðc `HšSë sjcÏþd[ží×­-º~}1*VRæºä)ô"É2±FÍõÞõ¢y=+™%×wÅ2¬;œ¡%ðÂöEÅöš´VW[?.e5ïå>°8¶W±C×®yœ˜Å·<ôæßØÂùøŽ7šž(KÙmÍÐá¯]¼Ûä7\­ñºë¯…Aó`sw·ÁÃ`•û;W2™ê¾ô’ôèã•Ô´‹éÈ¡¯v9;áûV®ïX‚·„ò:oY—zb˜ìÍù»yºjˆA!ìlZ—ýQgQ¤_êžËfm;âJê⨈îq¿.èG”F³Öˆ“9\Ô1D“”¢HBN äCCÅ™8Ò(*ôNà±ïÒ×iG¦Ï™.ýT¿!w”/‘ˆÉ‘‹ÉŠ4xÄø õýÇ1c¡ÃÈÇŒ 1rçí:Mn\ߦFÓ7Kák2–Ê/)(¥òrl¼Ò1cÂÔ‹©#ŒÅÔgôË¢nœbàD7hùé÷yv†ì ;‰7² ÇYñYÜkoTººù+äŸÖí.Ÿü·ØèŠvÄs±Øl‹Ç¯‰H¬Ò²OÿÐu˜ëí üÛÁ¸ä°ˆÛkHÄ×<…Ö>)ÂÌ?PKÝ£c.d®PKŠ›U'"com/oroinc/text/PatternCache.class…ÍJÃ@Çg“ØH±Úúuòڃ݃Þz …ˆB¡÷éfŒ[¶»e»•è£yð|(qBÔXp;ÌŸùýçããóíB¸„óú1 b8Žá”A8M\ Ó%>#W¨s>sVê|2J…YqcÔ‚;*·”SÁÐ9²zÂàz5ý‹“ƒ^bôÆ¡vsT[Ÿwo Ak'½Êà05Õ­Ä…"/ j>AñDã²­'ffkÝJUâ˜eu ƒ}kÒ½0·Ç¹Cõh슲ʪFšÞ .ÚÀÏÎ øîõ׿†Ýœ\3Yÿûb÷‹% çﱑ¯0 ‚òu"¿?tÀ“>‹| +%n)'¿jX¥Ä-å ö|Â਌^ëù?€ƒ/PKUÿgPKŠ›U'%com/oroinc/text/PatternCacheLRU.class•‘MKÃ@†g“ØÔئ­Í¡~¼ÄTÍÉSE RèA =®qÑ•4[Ö­ôoy Xðø£ÄYIÑ–^º‡w˜áÙwfv¿¾?>Á„cس¡eCÛ†v,9°å€¥Å€’Ê%¨ƒ«¥¢¥ªe›€éX~O‡ŽßëÇb )x‡ŠMU(Ù›†7T)&ÓHŒÆ0—ôRℤ¢¿Æ7_|ÐAgÔ'üQŽçÆ‚XâÒ™Þ³}g¹çÜœoß?|BY<èŒ#Ç ÷TÜWQV1¢bTŘŠqÓ*©x¬¡G4ÄpTƒŽ£MPÐ+cÍÐp\#î„4œ”â©f4á´äÎhØ‹d3âHIHZê2×§ã2ÎÊ㢎Û(èÂMÃ8¯ã.鸋A%ôëx Ň8§c†ŽI©›’ºÉ=ÁÀ4†h2UbèL¦ÊÏø 7lîT ß³œj>0N3’eÓ]4\ϵÓXö-Û(rsAäwª}±êž¨ŠUcœû¾ðœ¢»X³láåeŒÓÉñÇæž Óϧv«΄C\)äùäî’S/‰â÷…z5ªn-ÏÏSå ûÃà”üBˆ¾ôïì{®ZŽå_gPŠnE0ì-ºÎ’ÏšÛË$·Þ.L•'g‹…ñB±49à ­š¢æ[d8pG8³̭Ë1ôËBh˜rŒ%g…ÛV¥W¬Ö<±´DN¹^ê銡û“fh)»&·§¹gñ9[P)Ú„»ì™b˜<é^³¦Ä14Íšõh„à•Ê-…ãÿêùÎk5áTâ&¯qÓò_0œh¬1äª ý¨nϻޢ¨€:x»e =¿Ç3Â;³uwÀÃí%éÿê5½¬ÐN3¨õR˪ÂÿÕ?Fh¤¼Z·Œm½ )lgomüTºÂ7CÇ/Ãä‚ç>—ƒ¥—¹d½$÷ÝŸh…T´Ähh[ö ä– äql9â#DU¢—1@Üâ‘NúìKo %YC[ºo íï‚ra@ï,FôFú=Ú2›8Áhö+º³_Ï) ei’¯°'¡¼%H{¦gÝQä”/íQ-|•þJP‹Lq¡ž¢ƒRDˆªéLt»¡SÛÕ”¨YÍ Mgz<úéœò±™ÐgÚ£hͬc{„Ž„²ŽÑuÞÀ¾ÏÙ·.B{\z±• $¯åÐïµÄÐ&Wt½…]DQMÞt= ot›\òᘮ- C1˵PKökÒ›>¸PK Œ›U'com/oroinc/util/PKŠ›U'com/oroinc/util/Cache.classmÏN1Æ¿YV0‹üÑÄWP8`Àã&{º,)-YºF}4>€El9x@z˜oæëo2“ù9|}£ƒnzö0&t&Ó'ÂÝd¹á7V–ÝZ=¯6¢Ããô¿E¸?ži­EÉúUÒ!/}-„AéÝ>° Û6ÖÅü]Ë.˜è†K¯ÙVÜ^Y‰FñâÛFËÂØ„r]Ï­lÅÂ¥æk>·Úo•o¼qZµÁXuùµ„?~|ºaÜho>%#2¤—ç„+\Ä„0B~Ôëxª¤ƒ¤‘ìǘ¡û PK“PHùÜEPKŠ›U'com/oroinc/util/CacheLRU.classS[Oa=»-]º,wª`‹XÄ m‘›ä‘ÆÄS—íX\vIÙx÷_˜hô…WH($F‰O<øOüê̶`¢DéÃÌ™éÌ93_§ß~|:DIL+¸§à¾‚1*$DTȈ„ ãð<£f6-l.„éÛh˜ZclZ9¼È¦ÃK*‚ˆ³igsYC7®h¸‰”†~F·p]ÛۜÄ CŒ†‘Ö0ÂhW5Üáð&Ñ©a ®î9 Á®iv‰®™cÃHÛ†³”Î,®Óêþ;%aà”Â3¶vž­•¦ [ŽåJ¨3Ìe1óäyŠëhÚ17'8í:ëžáxs†] Xß4ÅšgQV‚4-¡á4ýH)Yð,;=e¬/{Æ¢-(_3㚆=gä-NƒúÔ-äM1aÙÄ-/_ÇŒ鮦ݼk9f‰aR8"o™þ€ãŽ—ß"¦P6»,Œ ˜Í®ºâ™;‘wÏÿ›%°–>ð Ëf`2ËɉMZ2ûZlI¨Ê:…Uf¶x¦PÖ—ÁFyi#—·Åª`æ?Ç;~8 ±M.!þßÅèT–i¨dOOyK*\+ð’yÁÛ£ž\ère¾YB2ß©ïér}?àû ª¤Ó&ÛCÑ$BtüÀ=@H×÷ ~V‹ÿ†j`dM†cdÔ˜¼É¼‘%‡~~ߘ´£LÚHbyE¯k:@E©@æ¿Q¹à%iÉ?&%ú™+šaþhj”£ÖX&öÕ¾bkf•zkU~œñ˹—‘ê“dôhJI*Žq$ÊRIf©8UÕõì£áQï"½_˜Õ“{¨>@%¹úiÇo½†»è*·~¡Æ ò»Ç­³É#´%©u0Øì-¢¾%ØSDÞ,qa­ÿnÑÏøÚËrºÊŸ›Ú€µè/È_Q»6Öáv®íÛCÍ>šæ¹°Š Ky¥uO_ž§;Éì£qþøéóŸ]ÿPK•äîCê1PKŠ›U'"com/oroinc/util/GenericCache.class…SKOQþ.:e:Ŷ‹(¢P RŸø(š`-JR£ H‚.šËp‡ÒN‰°ög¸rã†&<‰Ä• Œ?A8wf í¤ç>ÎwÎ÷3g~ýùv€nàq@FÇmwtÜÕñ@ÇC D‘2 !m@GºÀÊd”él#ÇyåèR悉+È*sÉĆMÊ;`b9 š¸‡^E\dˆä†¦ºsC•e¾Æ OÚ…²ÓX5îI×)úˆYß¾eÐrSê0 Ð6w ¯æ—…å‡þ¾bllJ)£ãÒ‘Þ¢(¹ ‚!QrºÇo–Û :'Ÿ•''ÞTfª¥‰×¥©™9£üÁ«Je!õ\8¢&­·–Ĩ¢``TYº™¬ÎSžàõ%ÏÛ‚îÛ+®ÅíY^“ꂲÓn£f‰Ii“„kï*–»Rpk®t¬ ø4iÙñjë”$ZµÔ‘!^¥>ª[©RE«>‹Ú¬%|a¡l‹áx 1‹¯rKzë¤î,K)È×ó/v†¾ÿŠ£·¸(ˆË {B•õɆm3düžH·0MQÜ–ÜäÙþ1t4齸÷bêÔêrChDEóÚBO+Mf7ú1†«4Ú-´BÍ#Ô†Ó_i4Éêô§™%DížRl ­cù=Äò‘˜ù}èsÙ=;Hä³ß¡í þ©ü6âÙ}hÊÕ6ý‘f?þþªÒ’Ž›¸L›>Œ¡7ÌÛOYÕGÖEq‰á]œ{9òñ‘жѾŶ|A)õy„Z•è˜ ØEò1N…ˆTˆh%„¹ºo¸Ó¡;ª”ûï£'ô÷„]Iªpó­‘M-@2äý¾]?PKRdž:y$PKŒ›U''com/oroinc/util/GenericCacheEntry.classePÍN1œ²Èʺ¬7Š¢‰ÞD÷4^$\I)kKÖBÀ·ò@L<ø>”ñëzÓ&ßÌ7ýù¦™¯ïO¸ÀIˆ£­Çéí*ª";1Ä1°£‰4Æ!R† }>b(·ûž*×Ê(wCºk§’¡ÖµæÅqãF\/HG½•s§h—aÿN™+ÑåâQöŒË×—3¾ä ¬ÏÐø>Óܼñ#com/oroinc/text/regex/Pattern.classPK‰›U')#3{'#com/oroinc/text/regex/MatchResult.classPKŠ›U'þ+2¿èK5zcom/oroinc/text/regex/MalformedPatternException.classPKŠ›U'I¹’Å;+(Åcom/oroinc/text/regex/Perl5Matcher.classPKŠ›U'IS:ú>*à/com/oroinc/text/regex/PatternMatcher.classPKŠ›U'RÌ P1com/oroinc/text/regex/Util.classPK‹›U'-ë¨Ë:)¤5com/oroinc/text/regex/Perl5Compiler.classPK‹›U'­å‚Gøû+£Pcom/oroinc/text/regex/PatternCompiler.classPK‹›U'ÆHåHÝ2 /ôQcom/oroinc/text/regex/PatternMatcherInput.classPK‹›U'Ĉp¨{(.Vcom/oroinc/text/regex/Perl5Pattern.classPK‹›U' <£Qëª,Xcom/oroinc/text/regex/Perl5StreamInput.classPK‹›U' Ô=tàj(â]com/oroinc/text/regex/Substitution.classPK‹›U'_¤.Õ1@ -_com/oroinc/text/regex/Perl5Substitution.classPK‹›U'®›üG÷ñ.¤dcom/oroinc/text/regex/StringSubstitution.classPK‹›U'Hõç»ß²-÷fcom/oroinc/text/regex/CharStringPointer.classPK‹›U'P¾^Ä` "1jcom/oroinc/text/regex/OpCode.classPK‹›U'÷ÿì›*Ô+Eocom/oroinc/text/regex/Perl5Repetition.classPK‹›U'Ý£c.d®,Èpcom/oroinc/text/regex/Perl5MatchResult.classPKŠ›U'Uÿg"†scom/oroinc/text/PatternCache.classPKŠ›U'ÿ·`°T‚%ìtcom/oroinc/text/PatternCacheLRU.classPKŠ›U'ökÒ›>¸)“vcom/oroinc/text/GenericPatternCache.classPK Œ›U'(zcom/oroinc/util/PKŠ›U'“PHùÜEVzcom/oroinc/util/Cache.classPKŠ›U'•äîCê1{{com/oroinc/util/CacheLRU.classPKŠ›U'Rdž:y$"±~com/oroinc/util/GenericCache.classPKŒ›U'R5mí Š'zcom/oroinc/util/GenericCacheEntry.classPK$$Œ ï‚openacs-5.7.0/packages/acs-content-repository/java/Regexp-oracle.sqlj0000644000175000017500000000245507263134052025525 0ustar frankiefrankiepackage com.arsdigita.content; import java.lang.reflect.*; import java.sql.*; import java.util.*; import java.io.*; import oracle.sql.*; import oracle.jdbc.driver.*; import sqlj.runtime.ref.DefaultContext; import oracle.sqlj.runtime.Oracle; import com.oroinc.text.perl.*; public class Regexp { /** Search for a pattern and replace it with another pattern The patterns may be any valid Perl5 regular expressions **/ public static boolean replace(int revisionID, String search, String replace) throws SQLException, IOException, MalformedPerl5PatternException { Perl5Util util = new Perl5Util(); String content; #sql { select blob_to_string(content) into :content from cr_revisions where revision_id = :revisionID }; boolean hasMatch = util.match("/" + search + "/", content); if (hasMatch) { String pattern = "s/" + search + "/" + replace + "/"; content = util.substitute(pattern, content); Integer copyID; BLOB blob; #sql { begin :OUT copyID := content_revision.copy(:revisionID); end; }; #sql { select content into :blob from cr_revisions where revision_id = :copyID }; if (blob != null) blob.putBytes(1, content.getBytes()); } return hasMatch; } } openacs-5.7.0/packages/acs-content-repository/acs-content-repository.info0000644000175000017500000000634411575167337026542 0ustar frankiefrankie Content Repository Content Repository Services t t OpenACS The canonical repository for OpenACS content. 2011-06-12 3 OpenACS Provides the API for creating and managing user generated content including full support for versioning, rendering content to the filesystem, folders and composite content items, and other CMS backing functionality. Utilized by Bug Tracker, File Storage, and other packages. GPL 3 openacs-5.7.0/packages/acs-automated-testing/0000755000175000017500000000000011724401447020757 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/tcl/0000755000175000017500000000000011724401450021533 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/tcl/test/0000755000175000017500000000000011575225403022520 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/tcl/test/acs-automated-testing-procs.tcl0000644000175000017500000000160710521175740030554 0ustar frankiefrankiead_library { Automated tests. @author Peter Marklund @creation-date 20 April 2004 @cvs-id $Id: acs-automated-testing-procs.tcl,v 1.3 2006/10/29 19:07:12 donb Exp $ } aa_register_case -cats {web smoke} -libraries tclwebtest tclwebtest_example { A simple test case demonstrating the use of tclwebtest (HTTP level testing). @author Peter Marklund } { set user_id [db_nextval acs_object_id_seq] aa_run_with_teardown \ -test_code { # Create test user array set user_info [twt::user::create -user_id $user_id] # Login user twt::user::login $user_info(email) $user_info(password) # Visit homepage twt::do_request "/" # Logout user twt::user::logout } -teardown_code { # TODO: delete test user twt::user::delete -user_id $user_id } } openacs-5.7.0/packages/acs-automated-testing/tcl/test/selenium-procs.tcl0000644000175000017500000000065611254456115026200 0ustar frankiefrankiead_library { Test cases for Selenium Remote Control integration } aa_register_case \ -cats {web selenium smoke} \ -init_classes {{selenium acs-automated-testing}} selenium_server_configured { Is the selenium server configured and working? } { aa_false "Start Selenium RC Session" [catch {Se start} errmsg] aa_log $errmsg aa_false "Open [ad_url]" [catch {Se open [ad_url]} errmsg] aa_log $errmsg }openacs-5.7.0/packages/acs-automated-testing/tcl/http.tcl0000644000175000017500000010074511254456115023233 0ustar frankiefrankie# OpenACS is using this for Selenium Remote Control # NOTE: This is sourced by selenium Remote Control adapter so it is # not named http-procs.tcl! daveb dave@solutiongrove.com 2009-09-17 # http.tcl -- # # Client-side HTTP for GET, POST, and HEAD commands. # These routines can be used in untrusted code that uses # the Safesock security policy. These procedures use a # callback interface to avoid using vwait, which is not # defined in the safe base. # # See the file "license.terms" for information on usage and # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: http.tcl,v 1.1 2009/09/17 15:57:01 daveb Exp $ # Rough version history: # 1.0 Old http_get interface # 2.0 http:: namespace and http::geturl # 2.1 Added callbacks to handle arriving data, and timeouts # 2.2 Added ability to fetch into a channel # 2.3 Added SSL support, and ability to post from a channel # This version also cleans up error cases and eliminates the # "ioerror" status in favor of raising an error # 2.4 Added -binary option to http::geturl and charset element # to the state array. # 2.5 Added HTTP/1.1 support for persistent connections. New options # -protocol, -keepalive, -socketvar. (Pat Thoyts) # 2.6 Added support for HTTP/1.1 extensions. New option -method used # for WebDav. (Vince Darley) # 2.6.1 Synchronized with Tcl http 2.4.4 (encoding enhancements) # 2.6.2 Removed to -socketvar option and now handle socket usage internally # 2.6.3 Added support for chunked encoding. package require Tcl 8.2 # keep this in sync with pkgIndex.tcl package provide http 2.6.3 if {0 && [info command _proc] == {}} { rename proc _proc _proc proc {name arglist body} { _proc $name $arglist [concat "proc_begin;" $body ";proc_end"] } _proc proc_begin {} { puts "[string repeat > [info level]][lindex [info level -1] 0]" } _proc proc_end {} { puts "[string repeat < [info level]][lindex [info level -1] 0]" } } namespace eval http { variable http if {![info exists http]} { array set http { -accept */* -proxyhost {} -proxyport {} -proxyfilter http::ProxyRequired } # Use a Mozilla compatible useragent header to avoid problems with # some web sites. set http(-useragent) \ "Mozilla/5.0 ([string totitle $::tcl_platform(platform)];\ $::tcl_platform(os)) http/[package provide http]\ Tcl/[package provide Tcl]" } proc init {} { variable formMap variable alphanumeric a-zA-Z0-9 for {set i 0} {$i <= 256} {incr i} { set c [format %c $i] if {![string match \[$alphanumeric\] $c]} { set formMap($c) %[format %.2x $i] } } # These are handled specially array set formMap { " " + \n %0d%0a } # Create a map for HTTP/1.1 open sockets variable socketmap if {[info exists socketmap]} { foreach {url sock} [array get socketmap] { catch {close $sock} } array unset a } array set socketmap {} } init variable urlTypes array set urlTypes { http {80 ::socket} } variable encodings [string tolower [encoding names]] # This can be changed, but iso8859-1 is the RFC standard. variable defaultCharset "iso8859-1" namespace export geturl config reset wait formatQuery register unregister # Useful, but not exported: data size status code } # http::register -- # # See documentation for details. # # Arguments: # proto URL protocol prefix, e.g. https # port Default port for protocol # command Command to use to create socket # Results: # list of port and command that was registered. proc http::register {proto port command} { variable urlTypes set urlTypes($proto) [list $port $command] } # http::unregister -- # # Unregisters URL protocol handler # # Arguments: # proto URL protocol prefix, e.g. https # Results: # list of port and command that was unregistered. proc http::unregister {proto} { variable urlTypes if {![info exists urlTypes($proto)]} { return -code error "unsupported url type \"$proto\"" } set old $urlTypes($proto) unset urlTypes($proto) return $old } # http::config -- # # See documentation for details. # # Arguments: # args Options parsed by the procedure. # Results: # TODO proc http::config {args} { variable http set options [lsort [array names http -*]] set usage [join $options ", "] if {[llength $args] == 0} { set result {} foreach name $options { lappend result $name $http($name) } return $result } set options [string map {- ""} $options] set pat ^-([join $options |])$ if {[llength $args] == 1} { set flag [lindex $args 0] if {[regexp -- $pat $flag]} { return $http($flag) } else { return -code error "Unknown option $flag, must be: $usage" } } else { foreach {flag value} $args { if {[regexp -- $pat $flag]} { set http($flag) $value } else { return -code error "Unknown option $flag, must be: $usage" } } } } # http::Finish -- # # Clean up the socket and eval close time callbacks # # Arguments: # token Connection token. # errormsg (optional) If set, forces status to error. # skipCB (optional) If set, don't call the -command callback. This # is useful when geturl wants to throw an exception instead # of calling the callback. That way, the same error isn't # reported to two places. # # Side Effects: # Closes the socket proc http::Finish { token {errormsg ""} {skipCB 0}} { variable $token upvar 0 $token state global errorInfo errorCode if {[string length $errormsg] != 0} { set state(error) [list $errormsg $errorInfo $errorCode] set state(status) error } if {[info exists state(connection)] && $state(connection) == "close"} { CloseSocket $state(sock) $token } catch {after cancel $state(after)} if {[info exists state(-command)] && !$skipCB} { if {[catch {eval $state(-command) {$token}} err]} { if {[string length $errormsg] == 0} { set state(error) [list $err $errorInfo $errorCode] set state(status) error } } if {[info exists state(-command)]} { # Command callback may already have unset our state unset state(-command) } } } proc ::http::CloseSocket {s {token {}}} { #puts "CloseSocket $s" catch {fileevent $s readable {}} if {$token != {}} { variable $token upvar 0 $token state if {[info exists state(socketinfo)]} { if {[info exists socketmap($state(socketinfo))]} { unset socketmap($state(socketinfo)) } } } else { set map [array get socketmap] set ndx [lsearch -exact $map $s] if {$ndx != -1} { incr ndx -1 unset socketmap([lindex $map $ndx]) } } catch {close $s} } # ------------------------------------------------------------------------- proc ::http::OpenConnection {host port {socketcmd socket} {async ""}} { variable socketmap if {![info exists socketmap($host:$port)]} { set sock [eval $socketcmd $async $host $port] set id [string map {sock conn} $sock] variable $id upvar 0 $id conn set conn(sock) $sock set id [namespace which -variable $id] set socketmap($host:$port) $id } else { set id $socketmap($host:$port) } return $id } proc ::http::CloseConnection {connection} { variable $connection upvar 0 $connection conn catch {close $conn(sock)} unset $connection return } # ------------------------------------------------------------------------- # http::reset -- # # See documentation for details. # # Arguments: # token Connection token. # why Status info. # # Side Effects: # See Finish proc http::reset { token {why reset} } { variable $token upvar 0 $token state set state(status) $why catch {fileevent $state(sock) readable {}} catch {fileevent $state(sock) writable {}} Finish $token if {[info exists state(error)]} { set errorlist $state(error) unset state eval ::error $errorlist } } # http::geturl -- # # Establishes a connection to a remote url via http. # # Arguments: # url The http URL to goget. # args Option value pairs. Valid options include: # -blocksize, -validate, -headers, -timeout # Results: # Returns a token for this connection. # This token is the name of an array that the caller should # unset to garbage collect the state. proc http::geturl { url args } { variable http variable urlTypes variable defaultCharset # Initialize the state variable, an array. We'll return the # name of this array as the token for the transaction. if {![info exists http(uid)]} { set http(uid) 0 } set token [namespace current]::[incr http(uid)] variable $token upvar 0 $token state reset $token # Process command options. array set state { -binary false -blocksize 8192 -queryblocksize 8192 -validate 0 -headers {} -timeout 0 -type application/x-www-form-urlencoded -queryprogress {} -protocol 1.1 -keepalive 1 binary 0 state header meta {} coding {} currentsize 0 totalsize 0 querylength 0 queryoffset 0 type text/html body {} status "" http "" connection close } set state(charset) $defaultCharset set options {-binary -blocksize -channel -command -handler -headers \ -progress -query -queryblocksize -querychannel -queryprogress\ -validate -timeout -type -protocol -keepalive -method} set usage [join $options ", "] set options [string map {- ""} $options] set pat ^-([join $options |])$ foreach {flag value} $args { if {[regexp $pat $flag]} { # Validate numbers if {[info exists state($flag)] && \ [string is integer -strict $state($flag)] && \ ![string is integer -strict $value]} { unset $token return -code error "Bad value for $flag ($value), must be integer" } set state($flag) $value } else { unset $token return -code error "Unknown option $flag, can be: $usage" } } # Make sure -query and -querychannel aren't both specified set isQueryChannel [info exists state(-querychannel)] set isQuery [info exists state(-query)] if {$isQuery && $isQueryChannel} { unset $token return -code error "Can't combine -query and -querychannel options!" } # Validate URL, determine the server host and port, and check proxy case # Recognize user:pass@host URLs also, although we do not do anything # with that info yet. set exp {^(([^:]*)://)?([^@]+@)?([^/:]+)(:([0-9]+))?(/.*)?$} if {![regexp -nocase $exp $url x prefix proto user host y port srvurl]} { unset $token return -code error "Unsupported URL: $url" } if {[string length $proto] == 0} { set proto http set url ${proto}://$url } if {![info exists urlTypes($proto)]} { unset $token return -code error "Unsupported URL type \"$proto\"" } set defport [lindex $urlTypes($proto) 0] set defcmd [lindex $urlTypes($proto) 1] if {[string length $port] == 0} { set port $defport } if {[string length $srvurl] == 0} { set srvurl / } if {[string length $proto] == 0} { set url http://$url } set state(url) $url if {![catch {$http(-proxyfilter) $host} proxy]} { set phost [lindex $proxy 0] set pport [lindex $proxy 1] } # If a timeout is specified we set up the after event # and arrange for an asynchronous socket connection. if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) \ [list http::reset $token timeout]] set async -async } else { set async "" } # If we are using the proxy, we must pass in the full URL that # includes the server name. if {[info exists phost] && [string length $phost]} { set srvurl $url set state(socketinfo) $phost:$pport } else { set state(socketinfo) $host:$port } # See if we are supposed to use a previously opened channel. set s {} if {$state(-keepalive)} { variable socketmap if {[info exists socketmap($state(socketinfo))]} { #puts -nonewline "try to reuse $state(socketinfo): " if {[catch {fconfigure $socketmap($state(socketinfo))}]} { #puts "socket was closed" unset socketmap($state(socketinfo)) } else { #puts "reusing" set s $socketmap($state(socketinfo)) catch {fileevent $s writable {}} catch {fileevent $s readable {}} } } set state(connection) {} } if {$s == {}} { set conStat [catch { eval $defcmd $async [split $state(socketinfo) :] } s] if {$conStat} { # something went wrong while trying to establish the # connection Clean up after events and such, but DON'T # call the command callback (if available) because we're # going to throw an exception from here instead. Finish $token "" 1 cleanup $token return -code error $s } } set state(sock) $s set socketmap($state(socketinfo)) $s # Wait for the connection to complete if {$state(-timeout) > 0} { fileevent $s writable [list http::Connect $token] http::wait $token if {[string equal $state(status) "error"]} { # something went wrong while trying to establish the connection # Clean up after events and such, but DON'T call the command # callback (if available) because we're going to throw an # exception from here instead. set err [lindex $state(error) 0] cleanup $token return -code error $err } elseif {![string equal $state(status) "connect"]} { # Likely to be connection timeout return $token } set state(status) "" } # Send data in cr-lf format, but accept any line terminators fconfigure $s -translation {auto crlf} -buffersize $state(-blocksize) # The following is disallowed in safe interpreters, but the socket # is already in non-blocking mode in that case. catch {fconfigure $s -blocking off} set how GET if {$isQuery} { set state(querylength) [string length $state(-query)] if {$state(querylength) > 0} { set how POST set contDone 0 } else { # there's no query data unset state(-query) set isQuery 0 } } elseif {$state(-validate)} { set how HEAD } elseif {$isQueryChannel} { set how POST # The query channel must be blocking for the async Write to # work properly. fconfigure $state(-querychannel) -blocking 1 -translation binary set contDone 0 } if {[info exists state(-method)]} { set how $state(-method) } if {[catch { puts $s "$how $srvurl HTTP/$state(-protocol)" puts $s "Accept: $http(-accept)" if {$port == $defport} { # Don't add port in this case, to handle broken servers. # [Bug #504508] puts $s "Host: $host" } else { puts $s "Host: $host:$port" } puts $s "User-Agent: $http(-useragent)" if { $state(-protocol) == 1.0 && $state(-keepalive)} { puts $s "Connection: keep-alive" } if { $state(-protocol) > 1.0 && ! $state(-keepalive) } { puts $s "Connection: close" ;# RFC2616 sec 8.1.2.1 } if {[info exists phost] && [string length $phost] \ && $state(-keepalive)} { puts $s "Proxy-Connection: Keep-Alive" } foreach {key value} $state(-headers) { set value [string map [list \n "" \r ""] $value] set key [string trim $key] if {[string equal $key "Content-Length"]} { set contDone 1 set state(querylength) $value } if {[string length $key]} { puts $s "$key: $value" } } if {$isQueryChannel && $state(querylength) == 0} { # Try to determine size of data in channel # If we cannot seek, the surrounding catch will trap us set start [tell $state(-querychannel)] seek $state(-querychannel) 0 end set state(querylength) \ [expr {[tell $state(-querychannel)] - $start}] seek $state(-querychannel) $start } # Flush the request header and set up the fileevent that will # either push the POST data or read the response. # # fileevent note: # # It is possible to have both the read and write fileevents active # at this point. The only scenario it seems to affect is a server # that closes the connection without reading the POST data. # (e.g., early versions TclHttpd in various error cases). # Depending on the platform, the client may or may not be able to # get the response from the server because of the error it will # get trying to write the post data. Having both fileevents active # changes the timing and the behavior, but no two platforms # (among Solaris, Linux, and NT) behave the same, and none # behave all that well in any case. Servers should always read thier # POST data if they expect the client to read their response. if {$isQuery || $isQueryChannel} { puts $s "Content-Type: $state(-type)" if {!$contDone} { puts $s "Content-Length: $state(querylength)" } puts $s "" fconfigure $s -translation {auto binary} fileevent $s writable [list http::Write $token] } else { puts $s "" flush $s fileevent $s readable [list http::Event $s $token] } if {! [info exists state(-command)]} { # geturl does EVERYTHING asynchronously, so if the user # calls it synchronously, we just do a wait here. wait $token if {[string equal $state(status) "error"]} { # Something went wrong, so throw the exception, and the # enclosing catch will do cleanup. return -code error [lindex $state(error) 0] } } } err]} { # The socket probably was never connected, # or the connection dropped later. # Clean up after events and such, but DON'T call the command callback # (if available) because we're going to throw an exception from here # instead. # if state(status) is error, it means someone's already called Finish # to do the above-described clean up. if {[string equal $state(status) "error"]} { Finish $token $err 1 } cleanup $token return -code error $err } return $token } # Data access functions: # Data - the URL data # Status - the transaction status: ok, reset, eof, timeout # Code - the HTTP transaction code, e.g., 200 # Size - the size of the URL data proc http::data {token} { variable $token upvar 0 $token state return $state(body) } proc http::status {token} { variable $token upvar 0 $token state return $state(status) } proc http::code {token} { variable $token upvar 0 $token state return $state(http) } proc http::ncode {token} { variable $token upvar 0 $token state if {[regexp {[0-9]{3}} $state(http) numeric_code]} { return $numeric_code } else { return $state(http) } } proc http::size {token} { variable $token upvar 0 $token state return $state(currentsize) } proc http::error {token} { variable $token upvar 0 $token state if {[info exists state(error)]} { return $state(error) } return "" } # http::cleanup # # Garbage collect the state associated with a transaction # # Arguments # token The token returned from http::geturl # # Side Effects # unsets the state array proc http::cleanup {token} { variable $token upvar 0 $token state if {[info exists state]} { unset state } } # http::Connect # # This callback is made when an asyncronous connection completes. # # Arguments # token The token returned from http::geturl # # Side Effects # Sets the status of the connection, which unblocks # the waiting geturl call proc http::Connect {token} { variable $token upvar 0 $token state global errorInfo errorCode if {[eof $state(sock)] || [string length [fconfigure $state(sock) -error]]} { Finish $token "connect failed [fconfigure $state(sock) -error]" 1 } else { set state(status) connect fileevent $state(sock) writable {} } return } # http::Write # # Write POST query data to the socket # # Arguments # token The token for the connection # # Side Effects # Write the socket and handle callbacks. proc http::Write {token} { variable $token upvar 0 $token state set s $state(sock) # Output a block. Tcl will buffer this if the socket blocks set done 0 if {[catch { # Catch I/O errors on dead sockets if {[info exists state(-query)]} { # Chop up large query strings so queryprogress callback # can give smooth feedback puts -nonewline $s \ [string range $state(-query) $state(queryoffset) \ [expr {$state(queryoffset) + $state(-queryblocksize) - 1}]] incr state(queryoffset) $state(-queryblocksize) if {$state(queryoffset) >= $state(querylength)} { set state(queryoffset) $state(querylength) puts $s "" set done 1 } } else { # Copy blocks from the query channel set outStr [read $state(-querychannel) $state(-queryblocksize)] puts -nonewline $s $outStr incr state(queryoffset) [string length $outStr] if {[eof $state(-querychannel)]} { set done 1 } } } err]} { # Do not call Finish here, but instead let the read half of # the socket process whatever server reply there is to get. set state(posterror) $err set done 1 } if {$done} { catch {flush $s} fileevent $s writable {} fileevent $s readable [list http::Event $s $token] } # Callback to the client after we've completely handled everything if {[string length $state(-queryprogress)]} { eval $state(-queryprogress) [list $token $state(querylength)\ $state(queryoffset)] } } # http::Event # # Handle input on the socket # # Arguments # s The socket receiving input. # token The token returned from http::geturl # # Side Effects # Read the socket and handle callbacks. proc http::Event {s token} { variable $token upvar 0 $token state if {![info exists state]} { puts "Event $s $token with no token" if {! [eof $s]} { puts "oops: \"[read $s]\"" } CloseSocket $s return } if {[eof $s]} { if {[info exists $token]} { #puts "got eof on $s" set state(connection) close Eof $token } else { # open connection closed on a token that has been cleaned up. puts "close $s without token" CloseSocket $s } return } if {[string equal $state(state) "header"]} { if {[catch {gets $s line} n]} { Finish $token $n } elseif {$n == 0} { # We now have read all headers. if {$state(http) == ""} {puts ">$line<"; return} #puts "[string repeat - 60]\n$token: [array get state]\n[string repeat - 60]" # We ignore HTTP/1.1 100 Continue returns. RFC2616 sec 8.2.3 if {[lindex $state(http) 1] == 100} { return } variable encodings set state(state) body # We have to use binary translation to count bytes properly. fconfigure $s -translation binary if {$state(-binary) || ![string match -nocase text* $state(type)] || [string match *gzip* $state(coding)] || [string match *compress* $state(coding)]} { # Turn off conversions for non-text data set state(binary) 1 if {[info exists state(-channel)]} { fconfigure $state(-channel) -translation binary } } if {[info exists state(-channel)] && \ ![info exists state(-handler)]} { # Initiate a sequence of background fcopies fileevent $s readable {} CopyStart $s $token } } elseif {$n > 0} { # Process header lines if {[regexp -nocase {^([^:]+):(.+)$} $line x key value]} { switch [string tolower $key] { content-type { set state(type) [string trim [string tolower $value]] # grab the optional charset information regexp -nocase {charset\s*=\s*(\S+)} $state(type) \ x state(charset) } content-length { set state(totalsize) [string trim $value] } content-encoding { set state(coding) [string trim $value] } transfer-encoding { set state(transfer) \ [string trim [string tolower $value]] } proxy-connection - connection { set state(connection) \ [string trim [string tolower $value]] } } lappend state(meta) $key [string trim $value] } elseif {[string match HTTP* $line]} { set state(http) $line } } } else { # Now reading body if {[catch { if {[info exists state(-handler)]} { set n [eval $state(-handler) {$s $token}] } elseif {[info exists state(transfer_final)]} { set line [getTextLine $s] set n [string length $line] if {$n > 0} { #puts "final: $n" append state(transfer_final) $line } else { #puts "final chunk part" Eof $token } } elseif {[info exists state(transfer)] && $state(transfer) == "chunked"} { set size 0 set chunk [getTextLine $s] set n [string length $chunk] if {[string trim $chunk] != ""} { scan $chunk %x size if {$size != 0} { set bl [fconfigure $s -blocking] fconfigure $s -blocking 1 set chunk [read $s $size] fconfigure $s -blocking $bl set n [string length $chunk] if {$n >= 0} { append state(body) $chunk } #puts " size $size got [string length $chunk]" getTextLine $s } else { set state(transfer_final) {} } } } else { set block [read $s $state(-blocksize)] set n [string length $block] if {$n >= 0} { append state(body) $block } } if {[info exists state]} { if {$n >= 0} { incr state(currentsize) $n } # If Content-Length - check for end of data. if {$state(totalsize) > 0 \ && $state(currentsize) >= $state(totalsize)} { Eof $token } } } err]} { Finish $token $err } else { if {[info exists state(-progress)]} { eval $state(-progress) \ {$token $state(totalsize) $state(currentsize)} } } } } # http::getTextLine -- # # Get one line with the stream in blocking crlf mode # # Arguments # s The socket receiving input. # # Results: # The line of text, without trailing newline proc http::getTextLine {s} { set tr [fconfigure $s -translation] set bl [fconfigure $s -blocking] fconfigure $s -translation crlf -blocking 1 set r [gets $s] fconfigure $s -translation $tr -blocking $bl return $r } # http::CopyStart # # Error handling wrapper around fcopy # # Arguments # s The socket to copy from # token The token returned from http::geturl # # Side Effects # This closes the connection upon error proc http::CopyStart {s token} { variable $token upvar 0 $token state if {[catch { fcopy $s $state(-channel) -size $state(-blocksize) -command \ [list http::CopyDone $token] } err]} { Finish $token $err } } # http::CopyDone # # fcopy completion callback # # Arguments # token The token returned from http::geturl # count The amount transfered # # Side Effects # Invokes callbacks proc http::CopyDone {token count {error {}}} { variable $token upvar 0 $token state set s $state(sock) incr state(currentsize) $count if {[info exists state(-progress)]} { eval $state(-progress) {$token $state(totalsize) $state(currentsize)} } # At this point the token may have been reset if {[string length $error]} { Finish $token $error } elseif {[catch {eof $s} iseof] || $iseof} { Eof $token } else { CopyStart $s $token } } # http::Eof # # Handle eof on the socket # # Arguments # token The token returned from http::geturl # # Side Effects # Clean up the socket proc http::Eof {token {force 0}} { variable $token upvar 0 $token state if {[string equal $state(state) "header"]} { # Premature eof set state(status) eof } else { set state(status) ok } if { ! $state(binary) } { # If we are getting text, set the incoming channel's # encoding correctly. iso8859-1 is the RFC default, but # this could be any IANA charset. However, we only know # how to convert what we have encodings for. set enc [CharsetToEncoding $state(charset)] if {$enc != "binary"} { set state(body) [encoding convertfrom $enc $state(body)] } # Translate text line endings. set state(body) [string map {\r\n \n \r \n} $state(body)] } Finish $token } # http::wait -- # # See documentation for details. # # Arguments: # token Connection token. # # Results: # The status after the wait. proc http::wait {token} { variable $token upvar 0 $token state if {![info exists state(status)] || [string length $state(status)] == 0} { # We must wait on the original variable name, not the upvar alias vwait $token\(status) } return $state(status) } # http::formatQuery -- # # See documentation for details. # Call http::formatQuery with an even number of arguments, where # the first is a name, the second is a value, the third is another # name, and so on. # # Arguments: # args A list of name-value pairs. # # Results: # TODO proc http::formatQuery {args} { set result "" set sep "" foreach i $args { append result $sep [mapReply $i] if {[string equal $sep "="]} { set sep & } else { set sep = } } return $result } # http::mapReply -- # # Do x-www-urlencoded character mapping # # Arguments: # string The string the needs to be encoded # # Results: # The encoded string proc http::mapReply {string} { variable formMap variable alphanumeric # The spec says: "non-alphanumeric characters are replaced by '%HH'" # 1 leave alphanumerics characters alone # 2 Convert every other character to an array lookup # 3 Escape constructs that are "special" to the tcl parser # 4 "subst" the result, doing all the array substitutions regsub -all \[^$alphanumeric\] $string {$formMap(&)} string regsub -all {[][{})\\]\)} $string {\\&} string return [subst -nocommand $string] } # http::ProxyRequired -- # Default proxy filter. # # Arguments: # host The destination host # # Results: # The current proxy settings proc http::ProxyRequired {host} { variable http if {[info exists http(-proxyhost)] && [string length $http(-proxyhost)]} { if {![info exists http(-proxyport)] || \ ![string length $http(-proxyport)]} { set http(-proxyport) 8080 } return [list $http(-proxyhost) $http(-proxyport)] } } # http::CharsetToEncoding -- # # Tries to map a given IANA charset to a tcl encoding. # If no encoding can be found, returns binary. # proc http::CharsetToEncoding {charset} { variable encodings variable defaultCharset set charset [string tolower $charset] if {[regexp {iso-?8859-([0-9]+)} $charset - num]} { set encoding "iso8859-$num" } elseif {[regexp {iso-?2022-(jp|kr)} $charset - ext]} { set encoding "iso2022-$ext" } elseif {[regexp {shift[-_]?js} $charset -]} { set encoding "shiftjis" } elseif {[regexp {(windows|cp)-?([0-9]+)} $charset - - num]} { set encoding "cp$num" } elseif {[string equal $charset "us-ascii"]} { set encoding "ascii" } elseif {[regexp {(iso-?)?lat(in)?-?([0-9]+)} $charset - - - num]} { switch $num { 5 {set encoding "iso8859-9"} 1 - 2 - 3 {set encoding "iso8859-$num"} } } else { # other charset, like euc-xx, utf-8,... may directly maps to encoding set encoding $charset } set idx [lsearch -exact $encodings $encoding] if {$idx >= 0} { return $encoding } else { return "binary" } } openacs-5.7.0/packages/acs-automated-testing/tcl/aa-test-procs-postgresql.xql0000644000175000017500000000263310440426441027151 0ustar frankiefrankie postgresql7.1 delete from aa_test_results where testcase_id = :testcase_id delete from aa_test_final_results where testcase_id = :testcase_id insert into aa_test_results (testcase_id, package_key, test_id, timestamp, result, notes) values (:aa_testcase_id, :aa_package_key, :aa_testcase_test_id, current_timestamp, :test_result, :test_notes) insert into aa_test_final_results (testcase_id, package_key, timestamp, passes, fails) values (:aa_testcase_id, :aa_package_key, current_timestamp, :test_passes, :test_fails) select site_node__url(node_id) as url from site_nodes where object_id in (select package_id from apm_packages where package_key = :package_key) limit 1 openacs-5.7.0/packages/acs-automated-testing/tcl/aa-test-procs-oracle.xql0000644000175000017500000000215707622154340026220 0ustar frankiefrankie oracle8.1.6 delete from aa_test_results where testcase_id = :testcase_id delete from aa_test_final_results where testcase_id = :testcase_id insert into aa_test_results (testcase_id, package_key, test_id, timestamp, result, notes) values (:aa_testcase_id, :aa_package_key, :aa_testcase_test_id, sysdate, :test_result, :test_notes) insert into aa_test_final_results (testcase_id, package_key, timestamp, passes, fails) values (:aa_testcase_id, :aa_package_key, sysdate, :test_passes, :test_fails) openacs-5.7.0/packages/acs-automated-testing/tcl/aa-test-init.tcl0000644000175000017500000000043407717171276024560 0ustar frankiefrankiead_library { Server startup initialization code for the acs-automated-testing package @author Peter Marklund @creation-date 4:th of April 2003 @cvs-id $Id: aa-test-init.tcl,v 1.2 2003/08/15 14:48:30 peterm Exp $ } # LARS: Moved to aa-test-procs.tcl file. See comment there. openacs-5.7.0/packages/acs-automated-testing/tcl/example-procs.tcl0000644000175000017500000000207010005232276025014 0ustar frankiefrankie############################################################################## # # Copyright 2001, OpenACS, Peter Harper. # # This file is part of acs-automated-testing # ############################################################################## ad_library { Example procedures with which to demonstrate the acs-automated-testing automated testing platform. @author Peter Harper (peter.harper@open-msg.com) @creation-date 24 July 2001 @cvs-id $Id: example-procs.tcl,v 1.3 2004/01/26 15:39:42 jeffd Exp $ } ad_proc -public aa_example_write_audit_entry { name value } { @author Peter Harper @creation-date 24 July 2001 } { ns_log debug "aa_example_write_audit_entry: Auditing: $name, $value" return 1 } ad_proc -public aa_example_write_audit_entries { entries } { @author Peter Harper @creation-date 24 July 2001 } { foreach entry $entries { set name [lindex $entry 0] set value [lindex $entry 1] set result [aa_example_write_audit_entry $name $value] if {$result == 0} { return 0 } } return 1; } openacs-5.7.0/packages/acs-automated-testing/tcl/selenium-procs.tcl0000644000175000017500000001065211254456115025216 0ustar frankiefrankie# selenium.tcl # # This code implements a driver to control Selenium, an open source # test tool for web applications, see http://selenium.openqa.org/ # # This code is modeled after the Python and Ruby drivers. It differs # by not implementing each supported command separately, but instead # using a default dispatch to pass commands to the Selenium server with # very little modification. This is why the commands are not called # get_title, wait_for_page_to_load, etc. but with the same "camelCase" # names used by Selenium itself, i.e. getTitle, waitForPageToLoad, etc. # # All commands known to return a list are singled out and their return # string is converted before returning the result. Since everything is # a string in Tcl, no special handling is needed for numbers and booleans # (boolean results will be the same as in Selenium, i.e. "true"/"false"). # # Note: This code requires a new HTTP/1.1 aware version of geturl - the current # http 2.4 package in Tcl doesn't know how to keep a 1.1 connection alive # and will slow down because *each* Selenium request will time out. # # Example use: # # package require selenium # # Se init localhost 4444 *firefox http://www.google.com/webhp # Se start # # Se open http://www.google.com/webhp # Se type q "hello world" # Se clickAndWait btnG # Se assertTitle "hello world - Google Search" # # Se stop # # by Jean-Claude Wippler, 2007-02-24 source [file dirname [info script]]/http.tcl package require http package provide selenium 0.1 proc Se {cmd args} { global selenium switch -- $cmd { init { set selenium(host) [lindex $args 0] set selenium(port) [lindex $args 1] set selenium(browserStartCommand) [lindex $args 2] set selenium(browserURL) [lindex $args 3] set selenium(sessionId) "" } start { set selenium(sessionId) [Se getNewBrowserSession \ $selenium(browserStartCommand) \ $selenium(browserURL)] } stop { Se testComplete set selenium(sessionId) "" } default { set query [list http::formatQuery cmd $cmd] set i 0 foreach arg $args { lappend query [incr i] $arg } if {$selenium(sessionId) ne ""} { lappend query sessionId $selenium(sessionId) } set url "http://$selenium(host):$selenium(port)" append url /selenium-server/driver/? [eval $query] #puts "url $url" set token [http::geturl $url] #puts " status [http::status $token] code [http::code $token]" set data [http::data $token] #puts " result: $data" http::cleanup $token if {[string range $data 0 1] ne "OK"} { error $data } switch -- $cmd { getSelectedLabels - getSelectedValues - getSelectedIndexes - getSelectedIds - getSelectOptions - getAllButtons - getAllLinks - getAllFields - getAttributeFromAllWindows - getAllWindowIds - getAllWindowNames - getAllWindowTitles { set token "" set tokens {} set escape 0 foreach letter [split $data ""] { if {$escape} { append token $letter set escape 0 } else { switch -- $letter { \\ { set escape 1 } , { lappend tokens $token; set token "" } default { append token $letter } } } } lappend tokens $token return [lrange $tokens 1 end] ;# drop the "OK" element } default { return [string range $data 3 end] ;# drop the "OK," prefix } } } } } openacs-5.7.0/packages/acs-automated-testing/tcl/tclwebtest-procs.tcl0000644000175000017500000001555610622143332025555 0ustar frankiefrankiead_library { Helper procs for test cases using tclwebtest (HTTP level tests). @author Peter Marklund @creation-date 31 March 2004 @cvs-id $Id: tclwebtest-procs.tcl,v 1.7 2007/05/14 20:30:18 donb Exp $ } namespace eval twt {} namespace eval twt::user {} ######################### # # twt namespace # ######################### ad_proc twt::do_request { page_url } { Takes a a url and invokes tclwebtest::do_request. Will retry the request a number of times if it fails because of a socket connect problem. } { aa_log "twt::do_request $page_url" # Qualify page_url if necessary if { [regexp {^/} $page_url] } { set page_url "[twt::server_url]${page_url}" } set retry_count 0 set retry_max 10 set error_p 0 while { [catch {::tclwebtest::do_request $page_url} errmsg] } { set error_p 1 if { $retry_count < $retry_max } { switch -regexp -- $errmsg { {unreachable} - {refused} { ::twt::log "Failed to connect to server with error \"$errmsg\" - retrying" incr retry_count exec "sleep" "5" set error_p 0 continue } default { ::twt::log "Failed to connect to server with error \"$errmsg\" - giving up" break } } } else { break } } if { $error_p } { # Either some non-socket error, or a socket problem occuring with more than # $retry_max times. Propagate the error while retaining the stack trace aa_log "twt::do_request failed with error=\"$errmsg\" response_url=\"[tclwebtest::response url]\". See error log for the HTML response body" ns_log Error "twt::do_request failed with error=\"$errmsg\" response_url=\"[tclwebtest::response url]\" response_body=\"[tclwebtest::response body]\"" global errorInfo error $errmsg $errorInfo } } ad_proc twt::log { message } { TWT proc for writing a Notice message to the web server log. } { ns_log Notice "twt::log - $message" } ad_proc twt::server_url {} { Get the URL of the server (like ad_url) using the IP number of the server. Is more bulletproof than using the domain name. @author Peter Marklund } { set ip_address [ns_config ns/server/[ns_info server]/module/nssock Address] # If the IP is not configured in the config.tcl we will use the ip of localhost if {$ip_address eq ""} { set ip_address 127.0.0.1 } regexp {(:[0-9]*)?$} [util_current_location] match port if { [exists_and_not_null port] } { return "http://${ip_address}${port}" } else { return "http://$ip_address" } } ######################### # # twt::user namespace # ######################### ad_proc twt::user::create { {-user_id {}} {-admin:boolean} } { Create a test user with random email and password for testing @param admin Provide this switch to make the user site-wide admin @return The user_info array list returned by auth::create_user. Contains the additional keys email and password. @author Peter Marklund } { set username "__test_user_[ad_generate_random_string]" set email "${username}@test.test" set password [ad_generate_random_string] array set user_info [auth::create_user \ -user_id $user_id \ -username $username \ -email $email \ -first_names [ad_generate_random_string] \ -last_name [ad_generate_random_string] \ -password $password \ -secret_question [ad_generate_random_string] \ -secret_answer [ad_generate_random_string]] if { $user_info(creation_status) ne "ok" } { # Could not create user error "Could not create test user with username=$username user_info=[array get user_info]" } set user_info(password) $password set user_info(email) $email aa_log "Created user with email=\"$email\" and password=\"$password\"" if { $admin_p } { aa_log "Making user site-wide admin" permission::grant -object_id [acs_magic_object "security_context_root"] -party_id $user_info(user_id) -privilege "admin" } return [array get user_info] } ad_proc twt::user::delete { {-user_id:required} } { Remove a test user. } { acs_user::delete \ -user_id $user_id \ -permanent } ad_proc twt::user::login { email password {username ""}} { tclwebtest for logging the user in. @param email Email of user to log in. @param password Password of user to log in. } { if {$username eq ""} { set username $email } aa_log "twt::login email $email password $password username $username" tclwebtest::cookies clear # Request the start page ::twt::do_request "[twt::server_url]/register" # Login the user tclwebtest::form find ~n login set local_authority_id [auth::authority::local] set local_authority_pretty_name [auth::authority::get_element -authority_id $local_authority_id -element pretty_name] if {![catch {tclwebtest::field find ~n authority_id} errmsg]} { tclwebtest::field select $local_authority_pretty_name aa_log "twt::login selecting authority_id $local_authority_id" } if {[catch {tclwebtest::field find ~n email} errmsg]} { tclwebtest::field find ~n username tclwebtest::field fill $username aa_log "twt::login using username instead of email" } else { aa_log "twt::login using email instead of username" tclwebtest::field fill "$email" } tclwebtest::field find ~n password tclwebtest::field fill $password tclwebtest::form submit # Verify that user is actually logged in and throw error otherwise set home_uri "/pvt/home" twt::do_request $home_uri set response_url [tclwebtest::response url] if { ![string match "*${home_uri}*" $response_url] } { if { [empty_string_p [cc_lookup_email_user $email]] } { error "Failed to login user with email=\"$email\" and password=\"$password\". No user with such email in database." } else { ns_log Error "Failed to log in user with email=\"$email\" and password=\"$password\" eventhough email exists (password may be incorrect). response_body=[tclwebtest::response body]" error "Failed to log in user with email=\"$email\" and password=\"$password\" eventhough email exists (password may be incorrect). User should be able to request $home_uri without redirection, however response url=$response_url" } } } ad_proc twt::user::logout {} { tclwebtest for logging the user out. } { twt::do_request "[twt::server_url]/register/logout" } openacs-5.7.0/packages/acs-automated-testing/tcl/aa-test-procs.tcl0000644000175000017500000012127111254456115024733 0ustar frankiefrankie ############################################################################## # # Copyright 2001, OpenACS, Peter Harper. # # This file is part of acs-automated-testing # ############################################################################## ad_library { Procs to support the acs-automated-testing package. NOTE: There's a hack in packages/acs-bootstrap-installer/bootstrap.tcl to load this file on server startup before other packages' -procs files. @author Peter Harper (peter.harper@open-msg.com) @creation-date 21 June 2001 @cvs-id $Id: aa-test-procs.tcl,v 1.38 2009/09/17 15:57:01 daveb Exp $ } # LARS: We do this here, because if we do it in the -init file, then we cannot register # test cases in -procs files of packages. if { ![nsv_exists aa_test cases] } { nsv_set aa_test cases {} nsv_set aa_test components {} nsv_set aa_test init_classes {} nsv_set aa_test categories { config db api web smoke stress security_risk populator production_safe } nsv_set aa_test exclusion_categories { stress security_risk } if {[parameter::get_from_package_key -package_key "acs-automated-testing" -parameter "SeleniumRcServer"] ne ""} { nsv_lappend aa_test categories "selenium" } else { nsv_lappend aa_test exclusion_categories "selenium" } } ad_proc -public aa_stub { proc_name new_body } { Stubs a function. Provide the procedure name and the new body code.

    Either call this function from within a testcase for a testcase specific stub, or outside a testcase for a file-wide stub. @author Peter Harper @creation-date 24 July 2001 } { global aa_stub_sequence global aa_stub_names global aa_testcase_id if {[info exists aa_testcase_id]} { # # Runtime testcase stub. # If a stub for this procedure hasn't already been defined, take a copy # of the original procedure and add it to the aa_stub_names list. # if {[lsearch -exact $aa_stub_names $proc_name] == -1} { lappend aa_stub_names $proc_name proc ${proc_name}_unstubbed [info args $proc_name] [info body $proc_name] } set aa_stub_sequence($proc_name) 1 set args [list] set counter 0 foreach arg [info args $proc_name] { if { [info default $proc_name $arg default_value] } { lappend args [list $arg $default_value] } else { lappend args $arg } } proc $proc_name $args " global aa_stub_sequence global aa_testcase_id set sequence_id \$aa_stub_sequence\($proc_name\) incr aa_stub_sequence\($proc_name\) $new_body " return } else { # # File wide stub. # if {![nsv_exists aa_file_wide_stubs [info script]]} { nsv_set aa_file_wide_stubs "[info script]" {} } nsv_lappend aa_file_wide_stubs "[info script]" [list $proc_name $new_body] } } ad_proc -public aa_unstub { proc_name } { @author Peter Harper @creation-date 24 July 2001 } { set args [list] set counter 0 foreach arg [info args $proc_name] { if { [info default $proc_name $arg default_value] } { lappend args [list $arg $default_value] } else { lappend args $arg } } proc $proc_name $args [info body ${proc_name}_unstubbed] return } ad_proc -public aa_register_init_class { init_class_id init_class_desc constructor destructor } { Registers a initialisation class to be used by one or more testcases. An initialisation class can be assigned to a testcase via the aa_register_case proc.

    An initialisation constructor is called once before running a set of testcases, and the descructor called once upon completion of running a set of testcases.

    The idea behind this is that it could be used to perform data intensive operations that shared amoungst a set if testcases. For example, mounting an instance of a package. This could be performed by each testcase individually, but this would be highly inefficient if there are any significant number of them.

    Better to let the acs-automated-testing infrastructure call the init_class code to set the package up, run all the tests, then call the descructor to unmount the package. @author Peter Harper @creation-date 04 November 2001 @param init_class_id Unique string to identify the init class @param init_class_desc Longer description of the init class @param constructor Tcl code block to run to setup the init class @param destructor Tcl code block to tear down the init class } { # # Work out the package key # set package_root [file join [acs_root_dir] packages] set package_rel [string replace [info script] \ 0 [string length $package_root]] if {![info exists package_key]} { set package_key [lindex [file split $package_rel] 0] } # # First, search the current list of init_classes. If an old version already # exists, replace it with the new version. # set lpos 0 set found_pos -1 foreach init_class [nsv_get aa_test init_classes] { if {[lindex $init_class 0] == $init_class_id && [lindex $init_class 1] == $package_key} { nsv_set aa_test init_classes [lreplace [nsv_get aa_test init_classes] \ $lpos $lpos \ [list $init_class_id $package_key \ $init_class_desc \ [info script] \ $constructor $destructor]] set found_pos $lpos break } incr lpos } # # If we haven't already replaced an existing entry, append the new # entry to the list. # if {$found_pos == -1} { nsv_lappend aa_test init_classes [list $init_class_id $package_key \ $init_class_desc \ [info script] \ $constructor $destructor] } # # Define the functions. Note the destructor upvars into the # aa_runseries function to gain visibility of all the variables # the constructor has exported. # ad_proc -private _${package_key}__i_$init_class_id {} " aa_log \"Running \\\"$init_class_id\\\" initialisation class constructor\" $constructor " ad_proc -private _${package_key}__d_$init_class_id {} " upvar _aa_exports _aa_exports foreach v \$_aa_exports(\[list $package_key $init_class_id\]) { upvar \$v \$v } $destructor " } ad_proc -public aa_register_component { component_id component_desc body } { Registers a re-usable code component. Provide a component identifier, description and component body code.

    This is useful for re-using code that sets up / clears down, data common to many testcases. @author Peter Harper @creation-date 28 October 2001 } { # # Work out the package key # set package_root [file join [acs_root_dir] packages] set package_rel [string replace [info script] \ 0 [string length $package_root]] set package_key [lindex [file split $package_rel] 0] # # First, search the current list of components. If an old version already # exists, replace it with the new version. # set lpos 0 set found_pos -1 foreach component [nsv_get aa_test components] { if {[lindex $component 0] == $component_id && [lindex $component 1] == $package_key} { nsv_set aa_test components [lreplace [nsv_get aa_test components] \ $lpos $lpos \ [list $component_id $package_key \ $component_desc \ [info script] \ $body]] set found_pos $lpos break } incr lpos } # # If we haven't already replaced an existing entry, append the new # entry to the list. # if {$found_pos == -1} { nsv_lappend aa_test components [list $component_id $package_key \ $component_desc \ [info script] \ $body] } # set munged_body [subst {uplevel 1 {$body}}] ad_proc -private _${package_key}__c_$component_id {} $body } ad_proc -public aa_call_component { component_id } { Executes the chunk of code associated with the component_id.

    Call this function from within a testcase body only. @author Peter Harper @creation-date 28 October 2001 } { global aa_package_key set body "" # # Search for the component body # foreach component [nsv_get aa_test components] { if {$component_id == [lindex $component 0] && $aa_package_key == [lindex $component 1]} { set body [lindex $component 4] } } # # If the component exists, execute the body code in the testcases stack # level. # if {$body ne ""} { aa_log "Running component $component_id" uplevel 1 "_${aa_package_key}__c_$component_id" return } else { error "Unknown component $component_id, package $aa_package_key" } } ad_proc -public aa_register_case { {-libraries {}} {-cats {}} {-error_level "error"} {-bugs {}} {-procs {}} {-init_classes {}} {-on_error {}} testcase_id testcase_desc args } { Registers a testcase with the acs-automated-testing system. Whenever possible, cases that fail to register are replaced with 'metatest' log cases, so that the register-time errors are visible at test time. See the tutorial for examples. @param libraries A list of keywords of additional code modules to load. The entire test case will fail if any package is missing. Currently includes tclwebtest. @param cats Properties of the test case. Must be zero or more of the following:

    • db: Tests the database directly
    • api: tests the TCL API
    • web: tests HTTP interface
    • smoke: Minimal test to assure functionality and catch basic errors.
    • stress: Puts heavy load on server or creates large numbers of records. Intended to simulate maximal production load.
    • security_risk: May introduce a security risk.
    • populator: Creates sample data for future use.
    • production_safe: Can be used on a live production site, ie for sanity checking or keepalive purposes. Implies: no risk of adding or deleting data; no risk of crashing; minimal cpu/db/net load.
    @param error_level Force all test failures to this error level. One of
    • notice: Informative. Does not indicate an error.
    • warning: May indicate an problem. Example: a non-critical bug repro case that hasn't been fixed.
    • error: normal error
    • metatest: Indicates a problem with the test framework, execution, or reporting. Suggests that current test results may be invalid. Use this for test cases that test the tests. Also used, automatically, for errors sourcing test cases.
    @param bugs A list of integers correspending to openacs.org bug numbers which relate to this test case. @param procs A list of OpenACS procs which are tested by this case. @param on_error Deprecated. @param init_classes Deprecated. @author Peter Harper @creation-date 24 July 2001 } { # error reporting kludge: if there is any text in this variable # we'll not register this test case but indicate in the test case # body that there was an error. set case_error "" set allowed_error_levels { notice warning metatest error } if { [lsearch $allowed_error_levels $error_level] == -1 } { set error_level metatest append case_error "error_level must be one of following: $allowed_error_levels.\n\n" } set allowed_categories [nsv_get aa_test categories] foreach cat $cats { if { [lsearch $allowed_categories $cat] == -1 } { set error_level metatest append case_error "cats must contain only the following: $allowed_categories. You had a '$cat' in there.\n\n" } } # # Work out the package_key. # set package_root [file join [acs_root_dir] packages] set package_rel [string replace [info script] \ 0 [string length $package_root]] set package_key [lindex [file split $package_rel] 0] # run library specific code foreach library $libraries { if { $library eq "tclwebtest" } { # kludge: until tclwebtest installs itself in the proper # place following the tcl way, we use this absolute path # hack. set tclwebtest_absolute_path "/usr/local/tclwebtest/lib" if { ![info exists ::auto_path] || [lsearch $::auto_path $tclwebtest_absolute_path] == -1 } { lappend ::auto_path $tclwebtest_absolute_path } if { [catch { package require tclwebtest package require http } err] } { set error_level metatest append case_error "tclwebtest is not available. Not registering this test case.\n\nError message: $err\n\n" } } } # # Print warnings for any unknown init_classes. We actually mask out # any unknown init_classes here, so we don't get any script errors later. # set filtered_inits {} foreach init_class $init_classes { if {[llength $init_class] == 2} { set init_class [lindex $init_class 0] } if {[string trim $init_class] ne ""} { set found 0 foreach init_class_info [nsv_get aa_test init_classes] { if {$init_class == [lindex $init_class_info 0]} { set found 1 } } if {!$found} { ns_log warning " aa_register_case: Unknown init class $init_class" } else { lappend filtered_inits $init_class } } } set init_classes $filtered_inits set test_case_list [list $testcase_id $testcase_desc \ [info script] $package_key \ $cats $init_classes $on_error $args $error_level $bugs $procs] # # First, search the current list of test cases. If an old version already # exists, replace it with the new version. # set lpos 0 set found_pos -1 foreach case [nsv_get aa_test cases] { if {[lindex $case 0] == $testcase_id && [lindex $case 3] == $package_key} { nsv_set aa_test cases [lreplace [nsv_get aa_test cases] $lpos $lpos \ $test_case_list] set found_pos $lpos break } incr lpos } # # If we haven't already replaced an existing entry, append the new # entry to the list. # if {$found_pos == -1} { nsv_lappend aa_test cases $test_case_list } if { $case_error ne "" } { # we don't source this file but insert a little warning text # into the procs body. There seems to be no better way to # indicate that this test should be skipped. ad_proc -private _${package_key}__$testcase_id {} " # make sure errorlevel gets through. this is not 100% cleaned up. global error_level set error_level $error_level aa_log_result $error_level \{${case_error}\}" return } if {[llength $init_classes] == 0} { set init_class_code "" } else { set init_class_code " global aa_init_class_logs upvar 2 _aa_exports _aa_exports foreach init_class \[list $init_classes\] { if {[llength $init_class] == 2} { set init_package_key [lindex $init_class 1] set init_class [lindex $init_class 0] } else { set init_package_key $package_key } foreach v \$_aa_exports(\[list \$init_package_key \$init_class\]) { upvar 2 \$v \$v } foreach logpair \$aa_init_class_logs(\[list \$init_package_key \$init_class\]) { aa_log_result \[lindex \$logpair 0\] \[lindex \$logpair 1\] } } " } set body " $init_class_code set _aa_export {} set body_count 0 foreach testcase_body \[list $args\] { aa_log \"Running testcase body \$body_count\" set catch_val \[catch \"eval \[list \$testcase_body\]\" msg\] if {\$catch_val != 0 && \$catch_val != 2} { global errorInfo aa_log_result \"fail\" \"$testcase_id (body \$body_count): Error during execution: \${msg}, stack trace: \n\$errorInfo\" } incr body_count } " ad_proc -private _${package_key}__$testcase_id {} $body ns_log Debug "aa_register_case: Registered test case $testcase_id in package $package_key" } ad_proc -public aa_export_vars { args } { Called from a initialisation class constructor or a component to explicitly export the specified variables to the current testcase. You need to call aa_export_vars before you create the variables. Example:
        aa_export_vars {package_id item_id}
        set package_id 23
        set item_id 109
        
    } { uplevel " foreach v $args { upvar \$v \$v uplevel 1 \"lappend _aa_export \$v\" } " } ad_proc -public aa_runseries { {-stress 0} {-security_risk 0} -quiet:boolean {-testcase_id ""} by_package_key by_category } { Runs a series of testcases. Runs all cases if both package_key and category are blank, otherwise it uses the package and/or category to select which testcases to run. @author Peter Harper @creation-date 24 July 2001 } { global aa_run_quietly_p global aa_init_class_logs global aa_in_init_class set aa_run_quietly_p $quiet_p # # Work out the list of initialisation classes. # set testcase_ids {} if {$testcase_id ne ""} { lappend testcase_ids $testcase_id foreach testcase [nsv_get aa_test cases] { if {$testcase_id == [lindex $testcase 0]} { set package_key [lindex $testcase 3] set init_classes [lindex $testcase 5] foreach init_class $init_classes { set classes([list $package_key $init_class]) 1 } } } } else { foreach testcase [nsv_get aa_test cases] { set testcase_id [lindex $testcase 0] set package_key [lindex $testcase 3] set categories [lindex $testcase 4] set init_classes [lindex $testcase 5] # try to disqualify the test case # if category is specified, if { [exists_and_not_null by_package_key] && $by_package_key != $package_key } { continue } # is it the wrong category? if { [exists_and_not_null by_category] && [lsearch $categories $by_category] < 0 } { continue } # if we don't want stress, then the test must not be stress if { ! $stress && [lsearch $categories "stress"] >= 0 } { continue } # if we don't want security risks, then the test must not be stress if { ! $security_risk && [lsearch $categories "security_risk"] >= 0 } { continue } # we made it through the filters, so add the test case lappend testcase_ids $testcase_id foreach init_class $init_classes { set classes([list $package_key $init_class]) 1 } } } # # Run each initialisation script. Keep a list of the exported variables # by each initialisation script so each testcase (and destructor) can # correctly upvar to gain visibility of them. # if {[info exists classes]} { foreach initpair [array names classes] { set package_key [lindex $initpair 0] set init_class [lindex $initpair 1] set _aa_export {} set aa_init_class_logs([list $package_key $init_class]) {} set aa_in_init_class [list $package_key $init_class] _${package_key}__i_$init_class set _aa_exports([list $package_key $init_class]) $_aa_export } } set aa_in_init_class "" # # Run each testcase # foreach testcase_id $testcase_ids { aa_run_testcase $testcase_id } # # Run each initialisation destructor script. # if {[info exists classes]} { foreach initpair [array names classes] { set package_key [lindex $initpair 0] set init_class [lindex $initpair 1] set aa_in_init_class [list $package_key $init_class] _${package_key}__d_$init_class } } set aa_in_init_class "" # Generate the XML report file aa_test::write_test_file } ad_proc -public aa_run_testcase { testcase_id } { @author Peter Harper @creation-date 24 July 2001 } { global aa_stub_names global aa_testcase_id global aa_testcase_test_id global aa_testcase_fails global aa_testcase_passes global aa_package_key global aa_init_class_logs global aa_error_level upvar exports exports set aa_stub_names {} set aa_testcase_id $testcase_id set aa_testcase_test_id 0 set aa_testcase_fails 0 set aa_testcase_passes 0 # # Lookup the testcase definition. # set testcase_bodys {} foreach testcase [nsv_get aa_test cases] { if {$testcase_id == [lindex $testcase 0]} { set testcase_file [lindex $testcase 2] set package_key [lindex $testcase 3] set aa_package_key $package_key set testcase_cats [lindex $testcase 4] set testcase_inits [lindex $testcase 5] set testcase_on_error [lindex $testcase 6] set testcase_bodys [lindex $testcase 7] set aa_error_level [lindex $testcase 8] } } if {[llength $testcase_bodys] == 0} { return } # # Create any file-wide stubs. # if {[nsv_exists aa_file_wide_stubs "$testcase_file"]} { foreach stub_def [nsv_get aa_file_wide_stubs "$testcase_file"] { aa_stub [lindex $stub_def 0] [lindex $stub_def 1] } } # # Run the test # set sql "delete from aa_test_results where testcase_id = :testcase_id" db_dml delete_testcase_results $sql set sql "delete from aa_test_final_results where testcase_id = :testcase_id" db_dml delete_testcase_final_results $sql ns_log debug "aa_run_testcase: Running testcase $testcase_id" set catch_val [catch _${package_key}__$testcase_id msg] if {$catch_val} { aa_log_result "fail" "$testcase_id: Error calling testcase function _${package_key}__$testcase_id: $msg" } # # Unstub any stubbed functions # foreach stub_name $aa_stub_names { aa_unstub $stub_name } set aa_stub_names {} aa_log_final $aa_testcase_passes $aa_testcase_fails unset aa_testcase_id } ad_proc -public aa_equals { affirm_name affirm_actual affirm_value } { Tests that the affirm_actual is equal to affirm_value.

    Call this function within a testcase, stub or component. @return True if the affirmation passed, false otherwise. @author Peter Harper @creation-date 24 July 2001 } { global aa_testcase_id global aa_package_key if {$affirm_actual eq $affirm_value} { aa_log_result "pass" "$affirm_name Affirm PASSED, actual = \"$affirm_actual\"" return 1 } else { aa_log_result "fail" "$affirm_name Affirm FAILED, actual = \"$affirm_actual\", expected = \"$affirm_value\"" return 0 } } ad_proc -public aa_true { affirm_name affirm_expr } { Tests that affirm_expr is true.

    Call this function within a testcase, stub or component. @return True if the affirmation passed, false otherwise. @author Peter Harper @creation-date 24 July 2001 } { global aa_testcase_id global aa_package_key set result [uplevel 1 [list expr $affirm_expr]] if { $result } { aa_log_result "pass" "$affirm_name Affirm PASSED, \"$affirm_expr\" true" return 1 } else { aa_log_result "fail" "$affirm_name Affirm FAILED, \"$affirm_expr\" false" return 0 } } ad_proc -public aa_false { affirm_name affirm_expr } { Tests that affirm_expr is false.
    Call this function within a testcase, stub or component. @return True if the affirmation passed, false otherwise. @author Peter Harper @creation-date 24 July 2001 } { global aa_testcase_id global aa_package_key set result [uplevel 1 [list expr $affirm_expr]] if {!$result} { aa_log_result "pass" "$affirm_name Affirm PASSED, \"$affirm_expr\" false" return 1 } else { aa_log_result "fail" "$affirm_name Affirm FAILED, \"$affirm_expr\" true" return 0 } } ad_proc -public aa_log { log_notes } { Writes a log message to the testcase log.

    Call this function within a testcase, stub or component. @author Peter Harper @creation-date 24 July 2001 } { global aa_testcase_id global aa_package_key global aa_run_quietly_p if {$aa_run_quietly_p} { return } aa_log_result "log" $log_notes } ad_proc -public aa_error { error_notes } { Writes an error message to the testcase log.

    Call this function within a testcase, stub or component. @author Peter Harper @creation-date 04 November 2001 } { aa_log_result "fail" $error_notes } ad_proc -public aa_log_result { test_result test_notes } { @author Peter Harper @creation-date 24 July 2001 } { if { [aa_in_rollback_block_p] } { aa_add_rollback_test [list aa_log_result $test_result $test_notes] return } global aa_testcase_id global aa_testcase_test_id global aa_testcase_fails global aa_testcase_passes global aa_package_key global aa_in_init_class global aa_init_class_logs global aa_error_level # # If logging is happened whilst in a initialisation class, store the log # entry, but don't write it to the database. Individual testcase will make # their own copies of these log entries. # if {$aa_in_init_class ne ""} { lappend aa_init_class_logs($aa_in_init_class) \ [list $test_result $test_notes] return } incr aa_testcase_test_id if {$test_result eq "pass"} { ns_log Debug "aa_log_result: PASSED: $aa_testcase_id, $test_notes" incr aa_testcase_passes } elseif {$test_result eq "fail"} { switch $aa_error_level { notice { ns_log notice "aa_log_result: NOTICE: $aa_testcase_id, $test_notes" set test_result "note" } warning { ns_log warning "aa_log_result: WARNING: $aa_testcase_id, $test_notes" set test_result "warn" } error { incr aa_testcase_fails ns_log Bug "aa_log_result: FAILED: $aa_testcase_id, $test_notes" } default { # metatest incr aa_testcase_fails ns_log Bug "aa_log_result: FAILED: Automated test did not function as expected: $aa_testcase_id, $test_notes" } } } else { ns_log Debug "aa_log_result: LOG: $aa_testcase_id, $test_notes" set test_result "log" } # Notes in database can only hold so many characters if { [string length $test_notes] > 2000 } { set test_notes "[string range $test_notes 0 1996]..." } db_dml test_result_insert {} } ad_proc -public aa_log_final { test_passes test_fails } { @author Peter Harper @creation-date 24 July 2001 } { global aa_testcase_id global aa_testcase_fails global aa_testcase_passes global aa_package_key if {$test_fails == 0} { } else { ns_log Bug "aa_log_final: FAILED: $aa_testcase_id, $test_fails tests failed" } db_dml testcase_result_insert { insert into aa_test_final_results (testcase_id, package_key, timestamp, passes, fails) values (:aa_testcase_id, :aa_package_key, sysdate, :test_passes, :test_fails) } } ad_proc -public aa_run_with_teardown { {-test_code:required} {-teardown_code ""} -rollback:boolean } { Execute code in test_code and guarantee that code in teardown_code will be executed even if error is thrown. Will catch errors in teardown_code as well and provide stack traces for both code blocks. @param test_code Tcl code that sets up the test case and executes tests @param teardown_code Tcl code that tears down database data etc. that needs to execute after testing even if error is thrown. @param rollback If specified, any db transactions in test_code will be rolled back. @author Peter Marklund } { if { $rollback_p } { set test_code " set errmsg {} db_transaction { aa_start_rollback_block $test_code aa_end_rollback_block error \"rollback tests\" } on_error { aa_end_rollback_block } aa_execute_rollback_tests if { !\[empty_string_p \$errmsg\] && !\[string equal \$errmsg \"rollback tests\"\] } { global errorInfo error \"\$errmsg \n\n \$errorInfo\" } " } # Testing set setup_error_p [catch {uplevel $test_code} setup_error] global errorInfo set setup_error_stack $errorInfo # Teardown set teardown_error_p 0 if { $teardown_code ne "" } { set teardown_error_p [catch {uplevel $teardown_code} teardown_error] global errorInfo set teardown_error_stack $errorInfo } # Provide complete error message and stack trace set error_text "" if { $setup_error_p } { append error_text "Setup failed with error $setup_error\n\n$setup_error_stack" } if { $teardown_error_p } { append error_text "\n\nTeardown failed with error $teardown_error\n\n$teardown_error_stack" } if { $error_text ne "" } { error $error_text } } ad_proc -private aa_start_rollback_block {} { Start a block of code that is to be rolled back in the db @author Peter Marklund } { global aa_in_rollback_block_p set aa_in_rollback_block_p 1 } ad_proc -private aa_end_rollback_block {} { End a block of code that is to be rolled back in the db @author Peter Marklund } { global aa_in_rollback_block_p set aa_in_rollback_block_p 0 } ad_proc -private aa_in_rollback_block_p {} { Return 1 if we are in a block of code that is to be rolled back in the db and 0 otherwise. @author Peter Marklund } { global aa_in_rollback_block_p if { [info exists aa_in_rollback_block_p] } { return $aa_in_rollback_block_p } else { return 0 } } ad_proc -private aa_add_rollback_test {args} { Add a test statement that is to be executed after a rollback block. If it were to be executed during the rollback block it would be rolled back and this is what we want to avoid. @author Peter Marklund } { global aa_rollback_test_statements lappend aa_rollback_test_statements $args } ad_proc -private aa_execute_rollback_tests {} { Execute all test statements from a rollback block. @author Peter Marklund } { global aa_rollback_test_statements if { [info exists aa_rollback_test_statements] } { foreach test_statement $aa_rollback_test_statements { eval [join $test_statement " "] } } if { [info exists aa_rollback_test_statements] } { unset aa_rollback_test_statements } } namespace eval aa_test {} ad_proc -public aa_test::xml_report_dir {} { Retrieves the XMLReportDir parameter. @return Returns the value for the XMLReportDir parameter. } { return [parameter::get -parameter XMLReportDir] } ad_proc -private aa_test::test_file_path { {-install_file_path:required} } { set filename [file tail $install_file_path] regexp {^(.+)-(.+)-(.+)\.xml$} $filename match hostname server set test_path [file dirname $install_file_path]/${hostname}-${server}-testreport.xml return $test_path } ad_proc -public aa_test::parse_install_file { {-path:required} {-array:required} } { Processes the xml report outputted from install.sh for display. } { upvar 1 $array service set tree [xml_parse -persist [template::util::read_file $path]] set root_node [xml_doc_get_first_node $tree] foreach entry { name os dbtype dbversion webserver openacs_cvs_flag adminemail adminpassword install_begin_epoch install_end_epoch install_end_timestamp num_errors install_duration install_duration_pretty script_path description } { set service($entry) "n/a" } set service(path) $path set service(filename) [file tail $path] set service(parse_errors) {} set service(name) [xml_node_get_attribute $root_node "name"] if { $service(name) eq "" } { append service(parse_error) "No service name attribute;" } foreach child [xml_node_get_children $root_node] { set info_type [xml_node_get_attribute $child "type"] if { $info_type eq "" } { append service(parse_error) "No type on info tag;" continue } set info_type [string map {- _} $info_type] set info_value [xml_node_get_content $child] set service($info_type) $info_value } if { [string is integer -strict $service(install_begin_epoch)] && [string is integer -strict $service(install_end_epoch)] } { set service(install_duration) [expr {$service(install_end_epoch) - $service(install_begin_epoch)}] set service(install_duration_pretty) [util::interval_pretty -seconds $service(install_duration)] } # TODO: Not working set service(admin_login_url) "$service(url)register/?[export_vars { { email $service(adminemail) } { password $service(adminpassword) } }]" set service(auto_test_url) "$service(url)test/admin" set service(rebuild_cmd) "sh [file join $service(script_path) recreate.sh]" } ad_proc -private aa_test::get_test_doc {} { Returns an XML doc with statistics for the most recent test results on the server. @author Peter Marklund } { # Open XML document set xml_doc " \n" set testcase_count [llength [nsv_get aa_test cases]] append xml_doc " $testcase_count\n" db_foreach result_counts { select result, count(*) as result_count from aa_test_results group by result } { set result_counts($result) $result_count } foreach result [array names result_counts] { append xml_doc " $result_counts($result)\n" } db_foreach failure_counts { select testcase_id, count(*) as failure_count from aa_test_results where result = 'fail' group by testcase_id } { set failure_counts($testcase_id) $failure_count } foreach testcase_id [array names failure_counts] { append xml_doc " $failure_counts($testcase_id)\n" } # Close XML document append xml_doc "\n" return $xml_doc } ad_proc -private aa_test::write_test_file {} { Writes an XML file with statistics for the most recent test results on the server. @author Peter Marklund } { set xml_doc "" set report_dir [aa_test::xml_report_dir] if { [file isdirectory $report_dir] } { set hostname [exec hostname] set server [ns_info server] set file_path "$report_dir/${hostname}-${server}-testreport.xml" set xml_doc [get_test_doc] if { [catch {template::util::write_file $file_path $xml_doc} errmsg] } { ns_log Error "Failed to write xml test report to path $file_path - $errmsg" } } return $xml_doc } ad_proc -public aa_test::parse_test_file { {-path:required} {-array:required} } { Processes the xml report with test result data for display. } { upvar 1 $array test set tree [xml_parse -persist [template::util::read_file $path]] set root_node [xml_doc_get_first_node $tree] # Get the total test case cound set testcase_count_node [xml_node_get_children_by_name $root_node testcase_count] set test(testcase_count) [xml_node_get_content $testcase_count_node] # Get the result counts by result type foreach result_count_node [xml_node_get_children_by_name $root_node result_count] { set result [xml_node_get_attribute $result_count_node result] set count [xml_node_get_content $result_count_node] set result_count($result) $count } set test(result_count) [array get result_count] # Get counts for failing test cases foreach testcase_failure_node [xml_node_get_children_by_name $root_node testcase_failure] { set testcase_id [xml_node_get_attribute $testcase_failure_node testcase_id] set count [xml_node_get_content $testcase_failure_node] set testcase_failure($testcase_id) $count } set test(testcase_failure) [array get testcase_failure] } ad_proc -public aa_get_first_url { {-package_key:required} } { Procedure for geting the url of a mounted package with the package_key. It uses the first instance that it founds. This is usefull for tclwebtest tests. } { if {![db_0or1row first_url { *SQL* }]} { site_node::instantiate_and_mount -package_key $package_key db_1row first_url {*SQL*} } return $url } ad_proc -public aa_display_result { {-response:required} {-explanation:required} } { Displays either a pass or fail result with specified explanation depending on the given response. @param response A boolean value where true (or 1, etc) corresponds to a pass result, otherwise the result is a fail. @param explanation An explanation accompanying the response. } { if {$response} { aa_log_result "pass" $explanation } else { aa_log_result "fail" $explanation } } ad_proc -public aa_selenium_init {} { Setup a global Selenium RC server connection @return true is everything is ok, false if there was any error } { # check if the global selenium connection already exists global _acs_automated_testing_selenium_init if {[info exists _acs_automated_testing_selenium_init]} { # if we already initialized Selenium RC this will be true if # we already failed to initialize Selenium RC this will be # false. We don't want to try to initialize Selenium RC more # than once per request thread in any case so just return the # previous status. This is a global and is reset on every # request. return $_acs_automated_testing_selenium_init } set server_url [parameter::get_from_package_key \ -package_key acs-automated-testing \ -parameter "SeleniumRcServer" \ -default ""] if {$server_url eq ""} { # no server configured so don't try to initialize return 0 } set server_port [parameter::get_from_package_key \ -package_key acs-automated-testing \ -parameter "SeleniumRcPort" \ -default "4444"] set browsers [parameter::get_from_package_key \ -package_key acs-automated-testing \ -parameter "SeleniumRcBrowsers" \ -default "*firefox"] set success_p [expr {![catch {Se init $server_url $server_port ${browsers} [ad_url]} errmsg]}] if {!$success_p} { ns_log error [ad_log_stack_trace] } set _acs_automated_testing_selenium_init $success_p return $success_p } aa_register_init_class \ "selenium" \ "Init Class for Selenium Remote Control" \ {aa_selenium_init} \ {catch {Se stop} errmsg} openacs-5.7.0/packages/acs-automated-testing/tcl/filter-procs.tcl0000644000175000017500000000112510551254371024654 0ustar frankiefrankiead_page_contract_filter aa_test_view_by { name value } { Checks whether a view_by value has a value of "testcase", "package" or "category" } { if {$value ne "testcase" && $value ne "package"} { ad_complain "Invalid view_by name" return 0 } return 1 } ad_page_contract_filter aa_test_category { name value } { Checks whether a category value has is valid. } { set found 0 foreach category [nsv_get aa_test categories] { if {$value == $category} { return 1 } } ad_complain "$value is not a valid acs-automated-testing testcase category" return 0 } openacs-5.7.0/packages/acs-automated-testing/sql/0000755000175000017500000000000011724401450021550 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/sql/oracle/0000755000175000017500000000000011724401450023015 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/sql/oracle/acs-automated-testing-drop.sql0000644000175000017500000000210507373536610030714 0ustar frankiefrankie---------------------------------------------------------------------------- -- -- aa-test-drop.sql -- Script to drop Testing tables. -- -- Copyright 2001, OpenMSG Ltd, Peter Harper. -- -- This file is part of aa-test. -- -- aa-test is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- aa-test is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with aa-test; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- ---------------------------------------------------------------------------- drop table aa_test_results; drop table aa_test_final_results; openacs-5.7.0/packages/acs-automated-testing/sql/oracle/acs-automated-testing-create.sql0000644000175000017500000000267407373536610031226 0ustar frankiefrankie---------------------------------------------------------------------------- -- -- aa-test-create.sql -- Script to create Testing tables. -- -- Copyright 2001, OpenMSG Ltd, Peter Harper. -- -- This file is part of aa-test. -- -- aa-test is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- aa-test is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with aa-test; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- ---------------------------------------------------------------------------- create table aa_test_results ( testcase_id varchar2(512), package_key varchar2(100), test_id integer, timestamp date, result varchar2(4), notes varchar2(2000) ); create table aa_test_final_results ( testcase_id varchar2(512), package_key varchar2(100), timestamp date, passes integer, fails integer ); openacs-5.7.0/packages/acs-automated-testing/sql/postgresql/0000755000175000017500000000000011575225402023760 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/sql/postgresql/acs-automated-testing-drop.sql0000644000175000017500000000210507373536610031652 0ustar frankiefrankie---------------------------------------------------------------------------- -- -- aa-test-drop.sql -- Script to drop Testing tables. -- -- Copyright 2001, OpenMSG Ltd, Peter Harper. -- -- This file is part of aa-test. -- -- aa-test is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- aa-test is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with aa-test; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- ---------------------------------------------------------------------------- drop table aa_test_results; drop table aa_test_final_results; openacs-5.7.0/packages/acs-automated-testing/sql/postgresql/acs-automated-testing-create.sql0000644000175000017500000000270407661401453032152 0ustar frankiefrankie---------------------------------------------------------------------------- -- -- aa-test-create.sql -- Script to create Testing tables. -- -- Copyright 2001, OpenMSG Ltd, Peter Harper. -- -- This file is part of aa-test. -- -- aa-test is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- aa-test is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with aa-test; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- ---------------------------------------------------------------------------- create table aa_test_results ( testcase_id varchar(512), package_key varchar(100), test_id integer, timestamp timestamptz, result varchar(4), notes varchar(2000) ); create table aa_test_final_results ( testcase_id varchar(512), package_key varchar(100), timestamp timestamptz, passes integer, fails integer ); openacs-5.7.0/packages/acs-automated-testing/www/0000755000175000017500000000000011575225403021603 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/www/doc/0000755000175000017500000000000011724401447022350 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/www/doc/xml/0000755000175000017500000000000011575225403023150 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/www/doc/xml/Makefile0000644000175000017500000000107710002520173024577 0ustar frankiefrankie# A very simple Makefile to generate the HTML docs # @author Vinod Kurup (vinod@kurup.com) # @author Modified by Roberto Mello (rmello@fslc.usu.edu) # @author Joel Aufrecht # # @creation-date 2002-08-10 # @modified-date 2002-09-21 # @modified-date 2003-10-08 # # Simplified version of acs-core-docs makefile, intended for generating # documentation from standard location /www/doc/xml in # OpenACS packages # # Paths XSLTPROC=/usr/bin/xsltproc HTMLDOC=/usr/bin/htmldoc all: cd .. ; $(XSLTPROC) --nonet --xinclude ../../../acs-core-docs/www/xml/openacs.xsl xml/index.xmlopenacs-5.7.0/packages/acs-automated-testing/www/doc/xml/install.xml0000644000175000017500000000107610002236263025332 0ustar frankiefrankie Installation by Joel Aufrecht Automated Testing is part of acs-core, and therefore should already be installed in any OpenACS system. Individual automated tests are stored within each package in package/tcl/test. openacs-5.7.0/packages/acs-automated-testing/www/doc/xml/selenium.xml0000644000175000017500000001452411254460730025517 0ustar frankiefrankie Using Selenium Remote Control by Dave Bauer To use Selenium Remote Control to run browser-based tested from acs-automated-testing first install Selenium Remote Control. Download Selenium RC. This requires a working Java configuration. See Selenium RC Documentation and specifically Selenium RC Installation. You can record tests to Tcl code that will run in acs-automated-testing by adding the a Tcl-RC mode in Selenium-IDE. Open up Firefox, click on Tools, select Selenium IDE, select Options, then Options again. Click on the formats tab. Click add. Name the format "Tcl-Rc". Paste the following code in the large box. /* * Format for Selenium Remote Control Python client. */ load('remoteControl.js'); this.name = "tcl-rc"; function testMethodName(testName) { return "test_" + underscore(testName); } notOperator = function() { return "! "; } tclString = function(value) { value = value.replace(/\\/g, '\\\\'); value = value.replace(/\"/g, '\\"'); value = value.replace(/\r/g, '\\r'); value = value.replace(/\n/g, '\\n'); value = value.replace(/\{/g, '\\{'); value = value.replace(/\}/g, '\\}'); value = value.replace(/\[/g, '\\['); value = value.replace(/\]/g, '\\]'); value = value.replace(/\$/g, '\\$'); var unicode = false; for (var i = 0; i < value.length; i++) { if (value.charCodeAt(i) >= 128) { unicode = true; } } return (unicode ? 'u' : '') + '"' + value + '"'; } function assertTrue(expression) { return "aa_true " + tclString(expression.toString()) + " [expr {![catch {" + expression.toString() + "} errmsg]}]"; } function assertFalse(expression) { return "aa_false " + tclString(expression.toString()) + " [expr {![catch {" + expression.toString() + "} errmsg]}]"; } function verify(statement) { return statement; } function verifyTrue(expression) { return verify(assertTrue(expression)); } function verifyFalse(expression) { return verify(assertFalse(expression)); } function joinExpression(expression) { return "join " + expression.toString(); } function assignToVariable(type, variable, expression) { return "set " + underscore(variable) + " [" + expression.toString() + "]"; } function waitFor(expression) { return "for {set i 0} {i < " + expression.toString() + "} {incr i} {\n" + "if {" + expression.toString() + "} {break}\n" + "after 1000\n" + "}\n" + "if {$i == 60} {error \"time out\"}"; } function assertOrVerifyFailure(line, isAssert) { return "" + line + "} errmsg]} {error \"expected failure\"}"; } Equals.prototype.toString = function() { return this.e1.toString() + " eq " + this.e2.toString(); } Equals.prototype.assert = function() { return 'aa_equal ' + string(this.e2.toString() + this.e1.toString()) + ' ' + this.e1.toString() + ' [' + this.e2.toString() +']'; } Equals.prototype.verify = function() { return verify(this.assert()); } NotEquals.prototype.toString = function() { return this.e1.toString() + " ne " + this.e2.toString(); } NotEquals.prototype.assert = function() { return "aa_true " + tclString(this.e1.toString() + " ne " + this.e2.toString()) + " [expr {" + this.e1.toString() + " ne " + this.e2.toString() + "}]"; } NotEquals.prototype.verify = function() { return verify(this.assert()); } RegexpMatch.prototype.toString = function() { var str = this.pattern; if (str.match(/\"/) || str.match(/\n/)) { str = str.replace(/\\/g, "\\\\"); str = str.replace(/\"/g, '\\"'); str = str.replace(/\n/g, '\\n'); return '"' + str + '"'; } else { str = 'r"' + str + '"'; } return "re.search(" + str + ", " + this.expression + ")"; } function pause(milliseconds) { return "after " + milliseconds; } function echo(message) { return "aa_log " + xlateArgument(message); } function statement(expression) { return expression.toString(); } function array(value) { var str = '[lst '; for (var i = 0; i < value.length; i++) { str += string(value[i]); if (i < value.length - 1) str += " "; } str += ']'; return str; } function nonBreakingSpace() { return "u\"\\u00a0\""; } CallSelenium.prototype.toString = function() { var result = ''; if (this.negative) { result += '! '; } if (options.receiver) { result += options.receiver + ' '; } result += this.message + ' '; for (var i = 0; i < this.args.length; i++) { result += this.args[i]; if (i < this.args.length - 1) { result += ' '; } } return result; } function formatComment(comment) { return comment.comment.replace(/.+/mg, function(str) { return "# " + str; }); } this.options = { header:'', footer:'' }; this.configForm = '<description>Variable for Selenium instance</description>' + '<description>Header</description>' + '<textbox id="options_header" multiline="true" flex="1" rows="4"/>' + '<description>Footer</description>' + '<textbox id="options_footer" multiline="true" flex="1" rows="4"/>'; You may also refer to the Selenese Commands Documentation which may give some hints to writing tests. openacs-5.7.0/packages/acs-automated-testing/www/doc/xml/using.xml0000644000175000017500000000674510017402533025022 0ustar frankiefrankie Usage by Joel Aufrecht Here's the entire chain of code used to set up auto-rebuilding servers on test.openacs.org The master server shows the status of all other servers. For test.openacs.org, it listens on port 80. The acs-automated-testing parameter IsInstallReportServer is set to 1 The acs-automated-testing parameter XMLReportDir is set to /var/log/openacs-install. This is arbitrary - it just needs to be somewhere all the servers can write to. For each server that will be monitored: Suppose the first test server is service1. Set up a dedicated user and automated install script. To run automated testing automatically each time the server is rebuilt, add this to /home/service1/install/install.tcl: set do_tclapi_testing "yes" Get the results of the automated tests dumped where the master server can see them - in this example, the same directory as above, /var/log/openacs-install, by adding this to install.tcl (requires 5.1): set install_xml_file "/var/lib/aolserver/service0/packages/acs-core-docs/www/files/install-autotest.xml" This will copy in the file install-autotest.xml: example missing which will, during install, configure that parameter in acs-automated-testing on the monitored server. To enable the 'rebuild server' link, edit the file /usr/local/bin/rebuild-server.sh: #!/bin/sh # script to trigger a server rebuild # hard-coding the valid server names here for some minimal security case $1 in service1) ;; service2) ;; "") echo "Usage: $0 servername" exit;; *) echo "$1 is not a permitted servername" exit;; esac sudo /home/$1/install/install.sh 2>&1 and allow the master user to execute this file as root (this is a limitation of the automatic install script, which must be root). In /etc/sudoers, include a line: master ALL = NOPASSWD: /usr/local/bin/rebuild-server.sh openacs-5.7.0/packages/acs-automated-testing/www/doc/xml/requirements.xml0000644000175000017500000002074710014172040026410 0ustar frankiefrankie Requirements by Joel Aufrecht Introduction Automated Testing provides a framework for executing tests of all varieties and for storing and viewing the results. Functional Requirements Req # Status in 5.0 Priority for 5.1 (A=required, B=optional) Description 1 Done Done Execute TCL tests. Execute a sequence of TCL code is executed and determine the correctness of the results. 1.1 partial Done Execute HTTP tests. Execute tests that can interact with a the webserver via the external, HTTP interface, including retrieving pages, following links, and submitting forms. (This is partially done in the sense that we can make http calls from tcl api, but there is no framework for doing anything complicated.) 1.1.1 Done Execute tclwebtest scripts. A test can contain tclwebtest commands. If tclwebtest is not installed, those commands fail gracefully. 1.1.1.1 partial A tclwebtest is easy to install. Tclwebtest installation is fully documented and can be installed with less than five steps. (Install is documented in 5.0, but there's a can't-find-config error; also, some new work in tclwebtest HEAD needs to packaged in a new tarball release.) 2 Done Done Tests have categories. Individual tests can be marked as belonging to zero, one, or many of these categories. The UI provides for running only tests in selected categories, and for viewing only results of tests in selected categories. 2.1 A Each test can be associated with a single OpenACS.org bug (ie, store bug id as in integer, or store full url so that this can point to other bugs) 3 B Tests can be ordered lists of other tests. minimal: verify that a test proc can call other test procs. Better: A test can be created within the GUI by selecting other tests. This test is stored in the database and can be exported. (This is related to a bigger issue of storing test scripts in some format other than tcl procs.) 4 C Test scripts can be imported and exported. It should be possible to import a test into the database from a file, and to export it to a file. These files should be sharable by different OpenACS installations. It should be possible to import/export directly between running OpenACS sites. (We should look at what did and didn't work in acs-lang catalog files and work from there.) 5 B Macro Recording. End users can create and run tests from the web interface without writing code. 1) UI to turn on macro mode. 2) basic recording: when you fill out a form while macro mode is on, the submit is caught and displayed as tclwebtest code, and then executed. 3) UI for creating aa_true tests automatically, based on the content of the page. (For example, a form that says "the returned page must contain [ type regexp here] that spits out aa_true "test X" [string regexp blah blah] 6 A Notification subscriptions are available for "email me whenever this test fails" and "notify me whenever a test in this category fails" 7 A The results of an automated test are optionally written to an xml file. Because the current test package uses in-memory variables instead of database objects to track its tests, it is incompatible with the standard category package. It uses an internal, single-dimension category field. Should this eventually get extended, a more complete list of categories to implement could be: Testing Mode Regression Smoke Stress Default-Only (for tests, such as front page UI tests, that will break once the default site is modified and can be ignored on non-default sites) production-safe security_risk Layer Web Page TCL Page Contract TCL API SQL Severity (derives from ns_log values) Notice (use this for informational items that do not imply a problem) Warning (use this for submitted tests w/o fixes; hygiene tests such as deprecated function sweeps) Error (default severity) Test Validity Bug (use this for problems that suggest the test itself in invalid or broken) Test Data Self-contained Requires no test data, leaves no test data. Populate Generates and leaves test data, for other tests or for end users. Package Version 5.0.0 etc References Forum Posting: tclwebtest with openacs-4/etc/install tests -- help getting started Forum Posting: Berlin bug bash proposal Revision History Document Revision # Action Taken, Notes When? By Whom? 1 Creation 17 Jan 2004 Joel Aufrecht 2 Updated with notes from chat meeting 21 Jan 2004 Joel Aufrecht openacs-5.7.0/packages/acs-automated-testing/www/doc/xml/index.xml0000644000175000017500000000162411254456116025005 0ustar frankiefrankie

    Automated Testing Section Missing Section Missing Section Missing Section Missing
    openacs-5.7.0/packages/acs-automated-testing/www/doc/index.html0000644000175000017500000000351710017402533024342 0ustar frankiefrankieAutomated Testing

    Automated Testing


    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-automated-testing/www/doc/install.html0000644000175000017500000000441410017402533024676 0ustar frankiefrankieInstallation

    Installation

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Automated Testing is part of acs-core, and therefore should already be installed in any OpenACS system. Individual automated tests are stored within each package in package/tcl/test.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-automated-testing/www/doc/usage.html0000644000175000017500000001215210017402533024332 0ustar frankiefrankieUsage

    Usage

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Here's the entire chain of code used to set up auto-rebuilding servers on test.openacs.org

    • The master server shows the status of all other servers. For test.openacs.org, it listens on port 80.

      1. The acs-automated-testing parameter IsInstallReportServer is set to 1

      2. The acs-automated-testing parameter XMLReportDir is set to /var/log/openacs-install. This is arbitrary - it just needs to be somewhere all the servers can write to.

    • For each server that will be monitored:

      1. Suppose the first test server is service1. Set up a dedicated user and automated install script.

      2. To run automated testing automatically each time the server is rebuilt, add this to /home/service1/install/install.tcl:

               set do_tclapi_testing "yes"
      3. Get the results of the automated tests dumped where the master server can see them - in this example, the same directory as above, /var/log/openacs-install, by adding this to install.tcl (requires 5.1):

                  set install_xml_file          "/var/lib/aolserver/service0/packages/acs-core-docs/www/files/install-autotest.xml"

        This will copy in the file install-autotest.xml:

        <?xml version="1.0"?>
        
        <!-- This is an install.xml which can be used to configure servers for reporting their automated test results.  Requires acs-automated-testing 5.1.0b2 or better -->
        
        <application name="acs-automated-testing" pretty-name="Automated Testing" home="http://openacs.org/">
        
          <actions>
        
            <set-parameter package="acs-automated-testing" name="XMLReportDir" value="/var/log/openacs-install"/>
          </actions>
        
        </application>
        

        which will, during install, configure that parameter in acs-automated-testing on the monitored server.

    • To enable the 'rebuild server' link, edit the file /usr/local/bin/rebuild-server.sh:

      #!/bin/sh
      # script to trigger a server rebuild
      
      # hard-coding the valid server names here for some minimal security
      case $1 in
          service1) ;;
          service2) ;;
          *)
              echo "Usage: $0 servername"
              exit;;
      esac
      
      sudo /home/$1/install/install.sh 2>&1

      and allow the master user to execute this file as root (this is a limitation of the automatic install script, which must be root). In /etc/sudoers, include a line:

      master ALL = NOPASSWD: /usr/local/bin/rebuild-server.sh
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-automated-testing/www/doc/requirements.html0000644000175000017500000002075010017402533025754 0ustar frankiefrankieRequirements

    Requirements

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    Automated Testing provides a framework for executing tests of all varieties and for storing and viewing the results.

    Functional Requirements

    Req #Status in 5.0Priority for 5.1 (A=required, B=optional)Description
    1DoneDoneExecute TCL tests. Execute a sequence of TCL code is executed and determine the correctness of the results.
    1.1partialDoneExecute HTTP tests. Execute tests that can interact with a the webserver via the external, HTTP interface, including retrieving pages, following links, and submitting forms. (This is partially done in the sense that we can make http calls from tcl api, but there is no framework for doing anything complicated.)
    1.1.1 DoneExecute tclwebtest scripts. A test can contain tclwebtest commands. If tclwebtest is not installed, those commands fail gracefully.
    1.1.1.1partialAtclwebtest is easy to install. Tclwebtest installation is fully documented and can be installed with less than five steps. (Install is documented in 5.0, but there's a can't-find-config error; also, some new work in tclwebtest HEAD needs to packaged in a new tarball release.)
    2DoneDoneTests have categories. Individual tests can be marked as belonging to zero, one, or many of these categories. The UI provides for running only tests in selected categories, and for viewing only results of tests in selected categories.
    2.1 AEach test can be associated with a single OpenACS.org bug (ie, store bug id as in integer, or store full url so that this can point to other bugs)
    3 BTests can be ordered lists of other tests. minimal: verify that a test proc can call other test procs. Better: A test can be created within the GUI by selecting other tests. This test is stored in the database and can be exported. (This is related to a bigger issue of storing test scripts in some format other than tcl procs.)
    4 CTest scripts can be imported and exported. It should be possible to import a test into the database from a file, and to export it to a file. These files should be sharable by different OpenACS installations. It should be possible to import/export directly between running OpenACS sites. (We should look at what did and didn't work in acs-lang catalog files and work from there.)
    5 BMacro Recording. End users can create and run tests from the web interface without writing code.

    1) UI to turn on macro mode.

    2) basic recording: when you fill out a form while macro mode is on, the submit is caught and displayed as tclwebtest code, and then executed.

    3) UI for creating aa_true tests automatically, based on the content of the page. (For example, a form that says "the returned page must contain [ type regexp here] that spits out aa_true "test X" [string regexp blah blah]

    6 ANotification subscriptions are available for "email me whenever this test fails" and "notify me whenever a test in this category fails"
    7 AThe results of an automated test are optionally written to an xml file.

    Because the current test package uses in-memory variables instead of database objects to track its tests, it is incompatible with the standard category package. It uses an internal, single-dimension category field. Should this eventually get extended, a more complete list of categories to implement could be:

    Testing Mode
      Regression
      Smoke
      Stress
      Default-Only (for tests, such as front page UI tests, that will break 
                    once the default site is modified and can be ignored on 
                    non-default sites)
      production-safe
      security_risk
    Layer
      Web Page
      TCL Page Contract
      TCL API
      SQL  
    Severity (derives from ns_log values)
      Notice (use this for informational items that do not imply a problem)
      Warning (use this for submitted tests w/o fixes; hygiene tests such as deprecated function sweeps)
      Error (default severity)
      Test Validity Bug (use this for problems that suggest the test itself in invalid or broken)
    Test Data
      Self-contained  Requires no test data, leaves no test data.
      Populate  Generates and leaves test data, for other tests or for end users.
    Package Version
      5.0.0
      etc
    

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    1Creation17 Jan 2004Joel Aufrecht
    2Updated with notes from chat meeting21 Jan 2004Joel Aufrecht
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-automated-testing/www/admin/0000755000175000017500000000000011724401447022673 5ustar frankiefrankieopenacs-5.7.0/packages/acs-automated-testing/www/admin/clear.tcl0000644000175000017500000000101707537470214024471 0ustar frankiefrankiead_page_contract { @cvs-id $Id: clear.tcl,v 1.2 2002/09/10 22:22:04 jeffd Exp $ } { {package_key ""} {category:aa_test_category ""} {view_by:aa_test_view_by "package"} {testcase_id:nohtml ""} {quiet "0"} } -properties { } set sql "delete from aa_test_results" db_dml delete_testcase_tests_sql $sql set sql "delete from aa_test_final_results" db_dml delete_testcase_tests_sql $sql ad_returnredirect "index" ad_returnredirect "index?by_package_key=$package_key&by_category=$category&view_by=$view_by&quiet=$quiet" openacs-5.7.0/packages/acs-automated-testing/www/admin/record-test.adp0000644000175000017500000000022210665301606025607 0ustar frankiefrankie @title@ @focus@ openacs-5.7.0/packages/acs-automated-testing/www/admin/record-test.tcl0000755000175000017500000001373511043666757025661 0ustar frankiefrankie# packages/acs-automated-testing/www/admin/record-test.tcl ad_page_contract { Creates test cases and add them to a library @author Enrique Catalan (enrique.catalan@quest.ie) @creation-date 2007-08-21 @cvs-id $Id: record-test.tcl,v 1.2 2008/07/29 19:22:23 emmar Exp $ } { package_key {return_url ""} } -properties { } -validate { } -errors { } # Todo # This is a first attempt of integrating the TwtR # with oacs. I think it is a good point to start # but in the ToDo list would be really usefull to # have: # - Parsing the Test code to replace fixed values with # Random ones (i.e. names, descriptions, intervals, # etc.). We might need to change TwtR src. # - Modify the js code of TwtR to be able to print # the code in this form to avoid users copy&paste it # - Find a way to get fixed date values and replace # them with dynamic date values # - Might be useful to keep record in the db to this # kind if testing procs, for statistics just # or more control set title "Record a new test" set focus "new_test.test_name" acs_user::get -array user_info set creation_user $user_info(email) ad_form -name new_test -method post -export {package_key return_url} \ -form { test_id:key { test_name:text {label "Test Name"} {html {size 50}} } { test_description:text {label "Short Description"} {html {size 70}} } { search_str:text,optional {label "Search String"} {html {size 50}} {help_text "Sometimes, you might need this string to check if the test is successfull or no (i.e. testing Warning messages)
    If you want to check more than one string, use a comma to separate the different strings"} } { login_type:integer(select) {label "Login Type"} {options {{admin -1} {newuser -2} {searched_user 0}}} } { login_id:party_search(party_search),optional {label "Type a keyword to find a user"} } { test_code:text(textarea),nospell {html {cols 90 rows 50}} {label "Test Code"} {help_text "The test code itself, usually generated by the TwtR pluging for firefox (http://www.km.co.at/km/twtr)"} } } \ -validate { { test_name { $test_name ne "" } {The name can not contain special characteres, whitespaces or be null} } { login_type { 1 } {You forgot to search the user} } } \ -new_request { set test_name "" set test_description "" set test_code "" set search_str "" } \ -new_data { # Open the automated tests tcl file # of this package key and add the # test code to the script, then # do an eval to load the test proc. # Get the test directory set pkg_test_path "[acs_package_root_dir $package_key]/tcl/test/" # Create or Open the test cases file and add the # code set file_name "$package_key-recorded-test-procs.tcl" set full_path "${pkg_test_path}${file_name}" # Get the namespace set package_namespace "${package_key}::twt" if {$login_id eq ""} { if {$login_type == -2} { # set login_code "twt::user:::create" set login_code " array set user_info \[twt::user:::create\] twt::user::login \$user_info(email) \$user_info(password) " } elseif {$login_type == -1} { # set login_code "twt::user:::create -admin" set login_code " array set user_info \[twt::user::create -admin\] twt::user::login \$user_info(email) \$user_info(password) " } } else { set login_code "ad_user_login -forever $login_id" } if { ![file exists $full_path] } { # file does not exist yet set file [open $full_path w+] puts $file " ad_library { This library was generated automatically for Automated tests for ${package_key} @author Automatically generated (Ref ${creation_user} ) @creation-date [clock format [clock seconds] -format {%Y-%m-%d %H:%M}] } namespace eval ${package_namespace} {} " } else { # file exists, let us do the job =) set file [open $full_path a] } # To be able to use this cases in other server # we need to replace the URL generated by TwtR # with the URL provided by ad_url, we could do # a string map or use the regexp or regsub like #regsub {::tclwebtest::do_request # \{http://([^:/]+)(:([0-9]*))?} $line [ad_url] new_line2 puts $file " #------------------------------------------ # Code for case ${test_name} #------------------------------------------ aa_register_case \ -cats {web smoke} \ -libraries {tclwebtest} \ ${test_name}_case {} {} { aa_log \"Running test case ${test_name} \" aa_log \"${test_description} \" set response 0 aa_log \" Loging in the user\" $login_code #------------------ TwtR code ----------------- ${test_code} #-------------- End ofTwtR code --------------- aa_log \"Test code executed\" set response_url \[tclwebtest::response url\] aa_log \"Response URL is \$response_url\" # Look for the text \$search_str if not empty if { \[string ne $search_str \"\"\] } { set string_list \[split \$search_str \",\"\] foreach item \$string_list { if { \[catch {tclwebtest::assert text \$item} errmsg\] } { aa_error \"Text \$item was not found!: \$errmsg\" incr errors } else { aa_log \"Good news! :), Text \$item was found!\" } } } # if no errors, test has passed if { !\$errors } { set response 1 } aa_log \"Finishing ${package_namespace}::${test_name}\" twt::user::logout aa_display_result \ -response \$response \ -explanation \"for test: ${test_name} \" } #------------------------------------------ # End of code for case ${test_name} #------------------------------------------ " close $file } -after_submit { set version_id [apm_version_id_from_package_key $package_key] apm_mark_version_for_reload $version_id files ad_returnredirect $return_url } ad_return_templateopenacs-5.7.0/packages/acs-automated-testing/www/admin/testcase.adp0000644000175000017500000000614610724051612025175 0ustar frankiefrankie @title;noquote@ (@package_key@) @context;noquote@
    Description:
    @testcase_desc@
    Defined in file:
    @testcase_file@
    Categories:
    @testcase_cats@
    Bugs:
    This test case covers OpenACS bug number(s): @bug_blurb;noquote@
    Procs:
    This test case covers OpenACS proc(s): @proc_blurb;noquote@
    Initialisation Classes:
    @testcase_inits@
    Testcase failure error response:
    @testcase_on_error;noquote@
    Body @bodys.body_number@ source
    @bodys.body@
    [ show testcase source ] [ hide testcase source ]

    Results [ quiet | verbose quiet | verbose ]

    Result Count
    @tests_quiet.result@ @tests_quiet.count@
    Time Result Notes
    No results
    @tests.timestamp@ FAILED @tests.result@
    @tests.notes@
    openacs-5.7.0/packages/acs-automated-testing/www/admin/testcase.tcl0000644000175000017500000000712410724051612025210 0ustar frankiefrankiead_page_contract { @cvs-id $Id: testcase.tcl,v 1.9 2007/11/30 18:16:42 daveb Exp $ } { testcase_id:nohtml package_key:nohtml {showsource 0} {quiet 1} } -properties { title:onevalue context_bar:onevalue tests:multirow showsource:onevalue testcase_desc:onevalue testcase_file:onevalue testcase_on_error:onevalue bodys:multirow quiet:onevalue fails:onevalue } set title "Test case $testcase_id" set context [list $title] if {$quiet} { set filter { and result = 'fail'} } else { set filter {} } db_multirow tests_quiet summary { select result, count(*) as count from aa_test_results where testcase_id = :testcase_id and package_key = :package_key group by result } db_multirow tests acs-automated-testing.testcase_query {} if {![db_0or1row acs-automated-testing.get_testcase_fails_count { select fails from aa_test_final_results where testcase_id = :testcase_id }]} { set fails -1 } set testcase_bodys {} foreach testcase [nsv_get aa_test cases] { if {$testcase_id == [lindex $testcase 0] && $package_key == [lindex $testcase 3]} { set testcase_desc [lindex $testcase 1] set testcase_file [lindex $testcase 2] set package_key [lindex $testcase 3] set testcase_cats [join [lindex $testcase 4] ", "] set testcase_inits [join [lindex $testcase 5] ", "] set testcase_on_error [lindex $testcase 6] set testcase_bodys [lindex $testcase 7] set testcase_error_level [lindex $testcase 8] set testcase_bugs [lindex $testcase 9] set testcase_procs [lindex $testcase 10] } } set bug_list [list] foreach bug $testcase_bugs { lappend bug_list "$bug" } set bug_blurb [join $bug_list ", "] set proc_list [list] foreach proc $testcase_procs { lappend proc_list "$proc" } set proc_blurb [join $proc_list ", "] template::multirow create bodys body_number body if {[llength $testcase_bodys] == 0} { set testcase_desc "" set testcase_file "" } else { set body_count 0 # # Work out the URL for this directory (stripping off the file element). # set url "[ad_conn url]" regexp {(.*)/[^/]*} $url {\\1} url append url "/component?package_key=${package_key}" foreach body $testcase_bodys { # # This regsub changes any "aa_call_component " so that the # element is a link. # regsub -all {aa_call_component\s+(["]?)([^\s]*)(["]?)} $body \ "aa_call_component \\1\\2\\3" body template::multirow append bodys $body_count $body incr body_count } } set resource_file_url "init-file-resource?[export_vars -url { {return_url {[ad_return_url]} } {absolute_file_path $testcase_file}}]" set return_url [export_vars -base . { { view_by testcase } quiet { by_package_key $package_key } }] set quiet_url "[export_vars -base testcase -entire_form -exclude {quiet}]&quiet=1" set verbose_url "[export_vars -base testcase -entire_form -exclude {quiet}]&quiet=0" template::head::add_style \ -style " .description h2 { 1.5em; } .fail { font-weight: bold; color: red; } .ok { font-weight: bold; color: green; } dt { font-weight: bold } th { background: #c0c0c0; } " ad_return_template openacs-5.7.0/packages/acs-automated-testing/www/admin/testcase-postgresql.xql0000644000175000017500000000115510207450353027432 0ustar frankiefrankie postgresql7.1 select to_char(timestamp,'YYYY-MM-DD HH24:MI:SS') as timestamp, result, notes from aa_test_results where testcase_id = :testcase_id and package_key = :package_key $filter order by test_id select fails from aa_test_final_results where testcase_id = :testcase_id openacs-5.7.0/packages/acs-automated-testing/www/admin/testcase-oracle.xql0000644000175000017500000000115310207450353026472 0ustar frankiefrankie oracle8.1.6 select to_char(timestamp,'YYYY-MM-DD HH24:MI:SS') as timestamp, result, notes from aa_test_results where testcase_id = :testcase_id and package_key = :package_key $filter order by test_id select fails from aa_test_final_results where testcase_id = :testcase_id openacs-5.7.0/packages/acs-automated-testing/www/admin/component.adp0000644000175000017500000000074507727563307025405 0ustar frankiefrankie @title;noquote@ @context;noquote@

    @title@

    Description:
    @component_desc@
    Defined in file:
    @component_file@
    Component body
          @component_body@
        
    openacs-5.7.0/packages/acs-automated-testing/www/admin/component.tcl0000644000175000017500000000125607727563307025421 0ustar frankiefrankiead_page_contract { @cvs-id $Id: component.tcl,v 1.3 2003/09/10 08:54:31 lars Exp $ } { component_id:nohtml package_key:nohtml } -properties { title:onevalue context_bar:onevalue component_desc:onevalue component_file:onevalue component_body:onevalue } set title "Component $component_id ($package_key)" set context [list $title] set component_bodys {} foreach component [nsv_get aa_test components] { if {$component_id == [lindex $component 0] && $package_key == [lindex $component 1]} { set component_desc [lindex $component 2] set component_file [lindex $component 3] set component_body [lindex $component 4] } } ad_return_template openacs-5.7.0/packages/acs-automated-testing/www/admin/index-postgresql.xql0000644000175000017500000000050307373536610026735 0ustar frankiefrankie postgresql7.1 select testcase_id, package_key, timestamp, passes, fails from aa_test_final_results openacs-5.7.0/packages/acs-automated-testing/www/admin/index.adp0000644000175000017500000001763311043711736024501 0ustar frankiefrankie @title;noquote@
    Category Mode View by
    [ all all | @main_categories.name@ @main_categories.name@ ]
    [i] View and run only tests in this category. Tests can have more than one category. (more info)

    Include Stress tests

    Include tests that may compromise security

    [ quiet | verbose quiet | verbose ]
    [i] Quiet mode shows only test failures.
    [ package | testcase package | testcase ]
    » Rerun displayed test cases
    » Clear test result data
    » Record a test
  • Package key Testcases run Passes Fails Result
    @packageinfo.key@ No Data -- fail @packageinfo.total@ @packageinfo.passes@ @packageinfo.fails@ FAILED OK
    Package key Testcase id Categories Description Result Timestamp Passes Fails
    @tests.package_key@
    @tests.package_key@ @tests.id@ @tests.categories@ @tests.description@ No Data -- fail FAILED OK @tests.timestamp@ @tests.passes@ @tests.fails@
    » Rerun displayed test cases
    » Clear test result data
    » Record a test

    Documentation openacs-5.7.0/packages/acs-automated-testing/www/admin/index.tcl0000644000175000017500000001313210665301606024505 0ustar frankiefrankiead_page_contract { @cvs-id $Id: index.tcl,v 1.8 2007/08/29 14:32:38 maltes Exp $ } { {quiet 0} {by_package_key ""} {by_category:aa_test_category ""} {view_by:aa_test_view_by "package"} {stress 0} {security_risk 0} {populator 0} } -properties { context_bar:onevalue title:onevalue server_name:onevalue tests:multirow packages:multirow categories:multirow by_package_key:onevalue by_category:onevalue view_by:onevalue quiet:onevalue } set title "System test cases" if {$by_package_key ne ""} { append title " for package $by_package_key" } if {$by_category ne ""} { append title ", category $by_category" } else { append title ", all categories" } foreach testcase [nsv_get aa_test cases] { set testcase_id [lindex $testcase 0] set testcase_desc [lindex $testcase 1] set package_key [lindex $testcase 3] set categories [lindex $testcase 4] set results("$testcase_id,$package_key") \ [list $testcase_desc $package_key $categories] set packages($package_key) [list 0 0 0] } db_foreach acs-automated-testing.results_queryx { select testcase_id, package_key, to_char(timestamp,'YYYY-MM-DD_HH24:MI:SS') as timestamp, passes, fails from aa_test_final_results } { if {[info exists results("$testcase_id,$package_key")]} { # Append results to individual testcase lappend results("$testcase_id,$package_key") $timestamp $passes $fails # # If viewing by package, update the by-package results, taking into # account whether a specific category has been specified. # if {$view_by eq "package"} { set package_total [lindex $packages($package_key) 0] set package_pass [lindex $packages($package_key) 1] set package_fail [lindex $packages($package_key) 2] if {$by_category ne ""} { # Category specific, only add results if this testcase is of the # specified category. set categories [lindex $results("$testcase_id,$package_key") 2] if {[lsearch $categories $by_category] != -1} { incr package_total incr package_pass $passes incr package_fail $fails set packages($package_key) [list $package_total \ $package_pass $package_fail] } } else { # No category specified, add results. incr package_total incr package_pass $passes incr package_fail $fails set packages($package_key) [list $package_total \ $package_pass $package_fail] } } } } if {$view_by eq "package"} { # # Prepare the template data for a view_by "package" # template::multirow create packageinfo key total passes fails foreach package_key [lsort [array names packages]] { set total [lindex $packages($package_key) 0] set passes [lindex $packages($package_key) 1] set fails [lindex $packages($package_key) 2] template::multirow append packageinfo $package_key $total $passes $fails } } else { # # Prepare the template data for a view_by "testcase" # template::multirow create tests id description package_key categories \ timestamp passes fails marker set old_package_key "" foreach testcase [nsv_get aa_test cases] { set testcase_id [lindex $testcase 0] set package_key [lindex $testcase 3] set testcase_desc [lindex $results("$testcase_id,$package_key") 0] regexp {^(.+?\.)\s} $testcase_desc "" testcase_desc set categories [lindex $results("$testcase_id,$package_key") 2] set categories_str [join $categories ", "] set testcase_timestamp [lindex $results("$testcase_id,$package_key") 3] set testcase_passes [lindex $results("$testcase_id,$package_key") 4] set testcase_fails [lindex $results("$testcase_id,$package_key") 5] # # Only add the testcase to the template multirow if either # - The package key is blank or it matches the specified. # - The category is blank or it matches the specified. # if {($by_package_key eq "" || ($by_package_key eq $package_key)) && \ ($by_category eq "" || ([lsearch $categories $by_category] != -1))} { # Swap the highlight flag between packages. if {$old_package_key ne $package_key} { set marker 1 set old_package_key $package_key } else { set marker 0 } template::multirow append tests $testcase_id $testcase_desc \ $package_key \ $categories_str \ $testcase_timestamp \ $testcase_passes $testcase_fails \ $marker } } } # # Create the category multirow # template::multirow create main_categories name template::multirow create exclusion_categories name foreach category [nsv_get aa_test categories] { # joel@aufrecht.org: putting in special cases for exclusionary categories if { [lsearch [nsv_get aa_test exclusion_categories] $category ] < 0 } { template::multirow append main_categories $category } else { template::multirow append exclusion_categories $category } } # # Set return url # set record_url [export_vars -base "record-test" -url {{return_url [ad_return_url]} package_key}] ad_return_template openacs-5.7.0/packages/acs-automated-testing/www/admin/rerun.tcl0000644000175000017500000000163010551254372024532 0ustar frankiefrankiead_page_contract { @cvs-id $Id: rerun.tcl,v 1.4 2007/01/10 21:22:02 gustafn Exp $ } { {package_key ""} {category:aa_test_category ""} {view_by:aa_test_view_by "package"} {testcase_id:nohtml ""} {quiet "0"} {stress "0"} {security_risk "0"} } -properties { } if {$testcase_id eq ""} { if {$quiet} { aa_runseries -stress $stress -security_risk $security_risk -quiet $package_key $category } else { aa_runseries -stress $stress -security_risk $security_risk $package_key $category } ad_returnredirect "index?by_package_key=$package_key&by_category=$category&view_by=$view_by&quiet=$quiet&stress=$stress&security_risk=$security_risk" } else { if {$quiet} { aa_runseries -quiet -testcase_id $testcase_id "" "" } else { aa_runseries -testcase_id $testcase_id "" "" } ad_returnredirect "testcase?testcase_id=$testcase_id&package_key=$package_key&quiet=$quiet" } openacs-5.7.0/packages/acs-automated-testing/www/admin/proc-coverage.adp0000644000175000017500000000017510013661255026113 0ustar frankiefrankie

    The following procs are not listed as being tested by any test cases.

    @uncovered_procs;noquote@

    openacs-5.7.0/packages/acs-automated-testing/www/admin/proc-coverage.tcl0000644000175000017500000000166510551254372026143 0ustar frankiefrankiead_page_contract { Displays procs not covered by test cases in the given package @author Peter Marklund } { package_key } set all_proc_names [list] foreach file_path [nsv_array names api_proc_doc_scripts] { if { [regexp "^packages/$package_key" $file_path] } { foreach proc_name [nsv_get api_proc_doc_scripts $file_path] { lappend all_proc_names $proc_name } } } set tested_proc_names [list] foreach testcase [nsv_get aa_test cases] { set testcase_package_key [lindex $testcase 3] if {$testcase_package_key eq $package_key} { set tested_procs [lindex $testcase 10] if { [llength $tested_procs] > 0 } { set tested_proc_names [concat $tested_proc_names $tested_procs] } } } set uncovered_procs [list] foreach proc_name $all_proc_names { if { [lsearch -exact $tested_proc_names $proc_name] == -1 } { lappend uncovered_procs $proc_name } } set uncovered_procs [join $uncovered_procs "
    "]openacs-5.7.0/packages/acs-automated-testing/www/admin/index-oracle.xql0000644000175000017500000000055207626720377026011 0ustar frankiefrankie oracle8.1.6 select testcase_id, package_key, to_char(timestamp,'MM/DD/YYYY HH:MI:SS') timestamp, passes, fails from aa_test_final_results openacs-5.7.0/packages/acs-automated-testing/www/admin/init-file-resource.tcl0000644000175000017500000000057307642605250027113 0ustar frankiefrankiead_page_contract { Re-source a test init file with test case definitions to avoid server restart. @author Peter Marklund @cvs-id $Id: init-file-resource.tcl,v 1.1 2003/04/02 16:07:04 peterm Exp $ } { absolute_file_path return_url } ns_log Notice "Sourcing test definition file $absolute_file_path" apm_source $absolute_file_path ad_returnredirect $return_url openacs-5.7.0/packages/acs-automated-testing/www/server.adp0000644000175000017500000000320010017373162023566 0ustar frankiefrankie @page_title@ @context@
    • Service:
      • Name: @service.name@
      • Description: @service.description@
      • URL: @service.url@
    • Login as:
    • Installation:
      • Installation completed at: @service.install_end_timestamp@
      • Duration: @service.install_duration_pretty@
    • Sources
      • OS: @service.os@
      • DB: @service.dbtype@ @service.dbversion@
      • Webserver: : @service.webserver@
      • Openacs flag: @service.openacs_cvs_flag@
    • Test failures none
      Test case Failure count
      @testcase_failures.testcase_id@ @testcase_failures.count@

      Unknown. Missing test report file at path @test_path@

    • Rebuild this server now
    • Rebuild log
    openacs-5.7.0/packages/acs-automated-testing/www/server.tcl0000644000175000017500000000203410017373162023610 0ustar frankiefrankiead_page_contract { Control page for an individual server. } { path:notnull } aa_test::parse_install_file -path $path -array service set admin_p [permission::permission_p -object_id [ad_conn package_id] -privilege admin] set test_path [aa_test::test_file_path -install_file_path $path] set has_test_report_p [file exists $test_path] multirow create testcase_failures testcase_id count if { $has_test_report_p } { aa_test::parse_test_file -path $test_path -array test array set testcase_failure $test(testcase_failure) foreach testcase_id [array names testcase_failure] { multirow append testcase_failures $testcase_id $testcase_failure($testcase_id) } } set page_title "Control Page for Server $service(name)" set context [list $page_title] set admin_login_url [export_vars -base "$service(url)/register/auto-login" {{email {$service(adminemail)}} {password {$service(adminpassword)}}}] set rebuild_url [export_vars -base rebuild-server { { server $service(name) } }] set rebuild_log_url "/rebuild-$service(name).log" openacs-5.7.0/packages/acs-automated-testing/www/index.adp0000644000175000017500000000331610017373162023377 0ustar frankiefrankie @page_title@ @context@
    Server Login Description Last built Errors Details
    This server Automated Test Admin
    Could not parse XML file at @servers.path@: @servers.parse_errors@ @servers.name@ Admin @servers.description;noquote@ @servers.install_date@ @servers.error_total_count@ @servers.error_total_count@ @servers.error_total_count@ More info

    Error reporting is not available for versions of OpenACS prior to 5.1d2.

    Documentation The XMLReportDir parameter is empty so a server listing cannot be generated. openacs-5.7.0/packages/acs-automated-testing/www/index.tcl0000644000175000017500000000312010551254372023412 0ustar frankiefrankiead_page_contract { Typically redirects to the admin index page which displays information about test cases on this server. However, if this is an install/test reporting server (see parameter IsInstallReportServer) then show the list of installed servers here. } if { ![parameter::get -boolean -parameter IsInstallReportServer] } { ad_returnredirect admin ad_script_abort } set page_title "Test Servers Control Page" set context [list] multirow create servers path admin_login_url local_url remote_url name description install_date error_total_count parse_errors set xml_report_dir [aa_test::xml_report_dir] if { $xml_report_dir ne "" } { foreach path [glob $xml_report_dir/*-installreport.xml] { aa_test::parse_install_file -path $path -array service set test_path [aa_test::test_file_path -install_file_path $path] if { [file exists $test_path] } { aa_test::parse_test_file -path $test_path -array test array set testcase_failure $test(testcase_failure) set service(num_errors) [llength [array names testcase_failure]] } set admin_login_url [export_vars -base "$service(url)/register/auto-login" {{email {$service(adminemail)}} {password {$service(adminpassword)}}}] multirow append servers \ $service(path) \ $admin_login_url \ [export_vars -base server { path }] \ $service(url) \ $service(name) \ $service(description) \ $service(install_end_timestamp) \ $service(num_errors) \ $service(parse_errors) } } openacs-5.7.0/packages/acs-automated-testing/www/rebuild-server.tcl0000644000175000017500000000030610017373162025234 0ustar frankiefrankiead_page_contract { Rebuild server } { server:notnull } exec sudo /usr/local/bin/rebuild-server.sh $server >& /web/master/www/rebuild-$server.log & ad_returnredirect /rebuild-$server.log openacs-5.7.0/packages/acs-automated-testing/acs-automated-testing.info0000644000175000017500000000544511575167337026061 0ustar frankiefrankie Automated Testing Automated Testing t t OpenACS

    The interface to the automated testing facilities within OpenACS. 2011-06-12 3 OpenACS 3 GPL version 2 Provides a UI for viewing and running automated tests provided by each package within the OpenACS system. Also provides a UI for managing automatic-rebuild servers as in a test farm. openacs-5.7.0/packages/acs-translations/0000755000175000017500000000000011724401447020042 5ustar frankiefrankieopenacs-5.7.0/packages/acs-translations/acs-translations.info0000644000175000017500000000177111575167337024225 0ustar frankiefrankie ACS Translation Storage ACS Translation Storage t t Malte Sussdorff Package for storing dynamic translations 2011-06-12 Package for storing dynamic translations 3 openacs-5.7.0/packages/acs-reference/0000755000175000017500000000000011724401447017257 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/tcl/0000755000175000017500000000000011724401447020041 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/tcl/acs-reference-procs.tcl0000644000175000017500000000056707343070573024407 0ustar frankiefrankiead_library { Utility procs for working with data in acs-reference @author Jon Griffin @creation-date 2001-08-28 @cvs-id $Id: acs-reference-procs.tcl,v 1.1 2001/08/29 04:37:15 jong Exp $ } ad_proc -private acs_reference_get_db_structure { {-table_name:required} } { Query the DB to get the data structure. Utility function. } { } openacs-5.7.0/packages/acs-reference/sql/0000755000175000017500000000000011724401447020056 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/sql/oracle/0000755000175000017500000000000011724401447021323 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/sql/oracle/acs-reference-create.sql0000644000175000017500000001667410506242016026015 0ustar frankiefrankie-- -- packages/acs-reference/sql/acs-reference-create.sql -- -- @author jon@arsdigita.com -- @creation-date 2000-11-21 -- @cvs-id $Id: acs-reference-create.sql,v 1.8 2006/09/26 15:15:26 byronl Exp $ -- setup the basic admin privileges begin acs_privilege.create_privilege('acs_reference_create'); acs_privilege.create_privilege('acs_reference_write'); acs_privilege.create_privilege('acs_reference_read'); acs_privilege.create_privilege('acs_reference_delete'); acs_privilege.add_child('create','acs_reference_create'); acs_privilege.add_child('write', 'acs_reference_write'); acs_privilege.add_child('read', 'acs_reference_read'); acs_privilege.add_child('delete','acs_reference_delete'); end; / show errors -- Create the basic object type used to represent a reference database begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'acs_reference_repository', pretty_name => 'ACS Reference Repository', pretty_plural => 'ACS Reference Repositories', table_name => 'acs_reference_repositories', id_column => 'repository_id', name_method => 'acs_object.default_name' ); end; / show errors -- A table to store metadata for each reference database create table acs_reference_repositories ( repository_id integer constraint arr_repository_id_fk references acs_objects (object_id) constraint arr_repository_id_pk primary key, -- what is the table name we are monitoring table_name varchar2(100) constraint arr_table_name_nn not null constraint arr_table_name_un unique, -- is this external or internal data internal_data_p char(1) constraint arr_internal_data_p_ck check (internal_data_p in ('t','f')), -- Does this source include pl/sql package? package_name varchar2(100) constraint arr_package_name_un unique, -- last updated last_update date, -- where is this data from source varchar2(1000), source_url varchar2(255), -- should default to today effective_date date default sysdate, expiry_date date, -- a text field to hold the maintainer maintainer_id integer constraint arr_maintainer_id_fk references persons(person_id), -- this could be ancillary docs, pdf's etc notes blob ); -- API create or replace package acs_reference as function new ( repository_id in acs_reference_repositories.repository_id%TYPE default null, table_name in acs_reference_repositories.table_name%TYPE, internal_data_p in acs_reference_repositories.internal_data_p%TYPE default 'f', package_name in acs_reference_repositories.package_name%TYPE default null, last_update in acs_reference_repositories.last_update%TYPE default sysdate, source in acs_reference_repositories.source%TYPE default null, source_url in acs_reference_repositories.source_url%TYPE default null, effective_date in acs_reference_repositories.effective_date%TYPE default sysdate, expiry_date in acs_reference_repositories.expiry_date%TYPE default null, notes in acs_reference_repositories.notes%TYPE default empty_blob(), creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_reference_repository', first_names in persons.first_names%TYPE default null, last_name in persons.last_name%TYPE default null ) return acs_objects.object_id%TYPE; procedure del ( repository_id in acs_reference_repositories.repository_id%TYPE ); function is_expired_p ( repository_id integer ) return char; end acs_reference; / show errors create or replace package body acs_reference as function new ( repository_id in acs_reference_repositories.repository_id%TYPE default null, table_name in acs_reference_repositories.table_name%TYPE, internal_data_p in acs_reference_repositories.internal_data_p%TYPE default 'f', package_name in acs_reference_repositories.package_name%TYPE default null, last_update in acs_reference_repositories.last_update%TYPE default sysdate, source in acs_reference_repositories.source%TYPE default null, source_url in acs_reference_repositories.source_url%TYPE default null, effective_date in acs_reference_repositories.effective_date%TYPE default sysdate, expiry_date in acs_reference_repositories.expiry_date%TYPE default null, notes in acs_reference_repositories.notes%TYPE default empty_blob(), creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_reference_repository', first_names in persons.first_names%TYPE default null, last_name in persons.last_name%TYPE default null ) return acs_objects.object_id%TYPE is v_repository_id acs_reference_repositories.repository_id%TYPE; v_maintainer_id persons.person_id%TYPE; begin v_repository_id := acs_object.new ( object_id => repository_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, object_type => object_type, title => source ); if first_names is not null and last_name is not null then v_maintainer_id := person.new ( first_names => first_names, last_name => last_name, email => null ); else v_maintainer_id := null; end if; insert into acs_reference_repositories (repository_id, table_name, internal_data_p, last_update, package_name, source, source_url, effective_date, expiry_date, maintainer_id, notes) values (v_repository_id, table_name, internal_data_p, last_update, package_name, source, source_url, effective_date, expiry_date, v_maintainer_id, notes); return v_repository_id; end new; procedure del ( repository_id in acs_reference_repositories.repository_id%TYPE ) is v_maintainer_id integer; begin select maintainer_id into v_maintainer_id from acs_reference_repositories where repository_id = acs_reference.del.repository_id; delete from acs_reference_repositories where repository_id = acs_reference.del.repository_id; acs_object.del(repository_id); person.del(v_maintainer_id); end del; function is_expired_p ( repository_id integer ) return char is v_expiry_date date; begin select expiry_date into v_expiry_date from acs_reference_repositories where repository_id = is_expired_p.repository_id; if nvl(v_expiry_date,sysdate+1) < sysdate then return 't'; else return 'f'; end if; end; end acs_reference; / show errors openacs-5.7.0/packages/acs-reference/sql/oracle/acs-reference-drop.sql0000644000175000017500000000274607736271232025526 0ustar frankiefrankie-- Drop the ACS Reference packages -- -- @author jon@jongriffin.com -- @cvs-id $Id: acs-reference-drop.sql,v 1.3 2003/09/30 12:10:02 mohanp Exp $ set serveroutput on -- drop all associated tables and packages -- ordered by repository_id for dependencies. declare cursor refsrc_cur is select table_name, package_name, repository_id from acs_reference_repositories order by repository_id desc; begin for rec in refsrc_cur loop dbms_output.put_line('Dropping ' || rec.table_name); execute immediate 'drop table ' || rec.table_name; if rec.package_name is not null then execute immediate 'drop package ' || rec.package_name; end if; acs_reference.del(rec.repository_id); end loop; end; / show errors -- drop privileges begin acs_privilege.remove_child('create','acs_reference_create'); acs_privilege.remove_child('write', 'acs_reference_write'); acs_privilege.remove_child('read', 'acs_reference_read'); acs_privilege.remove_child('delete','acs_reference_delete'); acs_privilege.drop_privilege('acs_reference_create'); acs_privilege.drop_privilege('acs_reference_write'); acs_privilege.drop_privilege('acs_reference_read'); acs_privilege.drop_privilege('acs_reference_delete'); end; / show errors -- drop the object begin acs_object_type.drop_type('acs_reference_repository','t'); end; / show errors drop package acs_reference; drop table acs_reference_repositories; openacs-5.7.0/packages/acs-reference/sql/oracle/upgrade/0000755000175000017500000000000011575225532022755 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/sql/oracle/upgrade/upgrade-5.0.2-5.0.2d1.sql0000644000175000017500000000740010024403025026432 0ustar frankiefrankieupdate acs_objects set title = (select source from acs_reference_repositories where repository_id = object_id) where object_type = 'acs_reference_repository'; create or replace package body acs_reference as function new ( repository_id in acs_reference_repositories.repository_id%TYPE default null, table_name in acs_reference_repositories.table_name%TYPE, internal_data_p in acs_reference_repositories.internal_data_p%TYPE default 'f', package_name in acs_reference_repositories.package_name%TYPE default null, last_update in acs_reference_repositories.last_update%TYPE default sysdate, source in acs_reference_repositories.source%TYPE default null, source_url in acs_reference_repositories.source_url%TYPE default null, effective_date in acs_reference_repositories.effective_date%TYPE default sysdate, expiry_date in acs_reference_repositories.expiry_date%TYPE default null, notes in acs_reference_repositories.notes%TYPE default empty_blob(), creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_reference_repository', first_names in persons.first_names%TYPE default null, last_name in persons.last_name%TYPE default null ) return acs_objects.object_id%TYPE is v_repository_id acs_reference_repositories.repository_id%TYPE; v_maintainer_id persons.person_id%TYPE; begin v_repository_id := acs_object.new ( object_id => repository_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, object_type => object_type, title => source ); if first_names is not null and last_name is not null then v_maintainer_id := person.new ( first_names => first_names, last_name => last_name, email => null ); else v_maintainer_id := null; end if; insert into acs_reference_repositories (repository_id, table_name, internal_data_p, last_update, package_name, source, source_url, effective_date, expiry_date, maintainer_id, notes) values (v_repository_id, table_name, internal_data_p, last_update, package_name, source, source_url, effective_date, expiry_date, v_maintainer_id, notes); return v_repository_id; end new; procedure del ( repository_id in acs_reference_repositories.repository_id%TYPE ) is v_maintainer_id integer; begin select maintainer_id into v_maintainer_id from acs_reference_repositories where repository_id = acs_reference.del.repository_id; delete from acs_reference_repositories where repository_id = acs_reference.del.repository_id; acs_object.del(repository_id); person.del(v_maintainer_id); end del; function is_expired_p ( repository_id integer ) return char is v_expiry_date date; begin select expiry_date into v_expiry_date from acs_reference_repositories where repository_id = is_expired_p.repository_id; if nvl(v_expiry_date,sysdate+1) < sysdate then return 't'; else return 'f'; end if; end; end acs_reference; / show errors openacs-5.7.0/packages/acs-reference/sql/oracle/upgrade/upgrade-0.2d-0.3d.sql0000644000175000017500000001244107741036057026234 0ustar frankiefrankie-- -- packages/acs-reference/sql/acs-reference-create.sql -- -- @author jon@arsdigita.com -- @creation-date 2000-11-21 -- @cvs-id $Id: upgrade-0.2d-0.3d.sql,v 1.1 2003/10/08 16:32:47 mohanp Exp $ create or replace package acs_reference as function new ( repository_id in acs_reference_repositories.repository_id%TYPE default null, table_name in acs_reference_repositories.table_name%TYPE, internal_data_p in acs_reference_repositories.internal_data_p%TYPE default 'f', package_name in acs_reference_repositories.package_name%TYPE default null, last_update in acs_reference_repositories.last_update%TYPE default sysdate, source in acs_reference_repositories.source%TYPE default null, source_url in acs_reference_repositories.source_url%TYPE default null, effective_date in acs_reference_repositories.effective_date%TYPE default sysdate, expiry_date in acs_reference_repositories.expiry_date%TYPE default null, notes in acs_reference_repositories.notes%TYPE default empty_blob(), creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_reference_repository', first_names in persons.first_names%TYPE default null, last_name in persons.last_name%TYPE default null ) return acs_objects.object_id%TYPE; procedure del ( repository_id in acs_reference_repositories.repository_id%TYPE ); function is_expired_p ( repository_id integer ) return char; end acs_reference; / show errors create or replace package body acs_reference as function new ( repository_id in acs_reference_repositories.repository_id%TYPE default null, table_name in acs_reference_repositories.table_name%TYPE, internal_data_p in acs_reference_repositories.internal_data_p%TYPE default 'f', package_name in acs_reference_repositories.package_name%TYPE default null, last_update in acs_reference_repositories.last_update%TYPE default sysdate, source in acs_reference_repositories.source%TYPE default null, source_url in acs_reference_repositories.source_url%TYPE default null, effective_date in acs_reference_repositories.effective_date%TYPE default sysdate, expiry_date in acs_reference_repositories.expiry_date%TYPE default null, notes in acs_reference_repositories.notes%TYPE default empty_blob(), creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_reference_repository', first_names in persons.first_names%TYPE default null, last_name in persons.last_name%TYPE default null ) return acs_objects.object_id%TYPE is v_repository_id acs_reference_repositories.repository_id%TYPE; v_maintainer_id persons.person_id%TYPE; begin v_repository_id := acs_object.new ( object_id => repository_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, object_type => object_type ); if first_names is not null and last_name is not null then v_maintainer_id := person.new ( first_names => first_names, last_name => last_name, email => null ); else v_maintainer_id := null; end if; insert into acs_reference_repositories (repository_id, table_name, internal_data_p, last_update, package_name, source, source_url, effective_date, expiry_date, maintainer_id, notes) values (v_repository_id, table_name, internal_data_p, last_update, package_name, source, source_url, effective_date, expiry_date, v_maintainer_id, notes); return v_repository_id; end new; procedure del ( repository_id in acs_reference_repositories.repository_id%TYPE ) is v_maintainer_id integer; begin select maintainer_id into v_maintainer_id from acs_reference_repositories where repository_id = acs_reference.del.repository_id; delete from acs_reference_repositories where repository_id = acs_reference.del.repository_id; acs_object.del(repository_id); person.del(v_maintainer_id); end del; function is_expired_p ( repository_id integer ) return char is v_expiry_date date; begin select expiry_date into v_expiry_date from acs_reference_repositories where repository_id = is_expired_p.repository_id; if nvl(v_expiry_date,sysdate+1) < sysdate then return 't'; else return 'f'; end if; end; end acs_reference; / show errors openacs-5.7.0/packages/acs-reference/sql/postgresql/0000755000175000017500000000000011575225532022264 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/sql/postgresql/acs-reference-create.sql0000644000175000017500000001621510546425647026763 0ustar frankiefrankie-- packages/acs-reference/sql/postgresql/acs-reference-create.sql -- -- @author jon@jongriffin.com -- @creation-date 2001-07-16 -- -- @cvs-id $Id: acs-reference-create.sql,v 1.13 2007/01/02 09:53:43 gustafn Exp $ -- setup the basic admin privileges select acs_privilege__create_privilege('acs_reference_create'); select acs_privilege__create_privilege('acs_reference_write'); select acs_privilege__create_privilege('acs_reference_read'); select acs_privilege__create_privilege('acs_reference_delete'); select acs_privilege__add_child('create','acs_reference_create'); select acs_privilege__add_child('write', 'acs_reference_write'); select acs_privilege__add_child('read', 'acs_reference_read'); select acs_privilege__add_child('delete','acs_reference_delete'); -- Create the basic object type used to represent a reference database select acs_object_type__create_type ( 'acs_reference_repository', 'ACS Reference Repository', 'ACS Reference Repositories', 'acs_object', 'acs_reference_repositories', 'repository_id', null, 'f', null, 'acs_object__default_name' ); -- A table to store metadata for each reference database -- add functions to do exports and imports to selected tables. create table acs_reference_repositories ( repository_id integer constraint arr_repository_id_fk references acs_objects (object_id) constraint arr_repository_id_pk primary key, -- what is the table name we are monitoring table_name varchar(100) constraint arr_table_name_nn not null constraint arr_table_name_un unique, -- is this external or internal data internal_data_p boolean, -- Does this source include pl/sql package? package_name varchar(100) constraint arr_package_name_un unique, -- last updated last_update timestamptz, -- where is this data from source varchar(1000), source_url varchar(255), -- should default to today effective_date timestamptz, -- default sysdate expiry_date timestamptz, -- a text field to hold the maintainer maintainer_id integer constraint arr_maintainer_id_fk references persons(person_id), -- this could be ancillary docs, pdf's etc -- needs to be fixed for PG -- DRB: needs to use Content Repository for both PG and Oracle, no??? lob integer ); -- API -- default for Oracle create function acs_reference__new (integer,varchar,boolean,varchar,timestamptz, varchar,varchar,timestamptz,timestamptz,integer,integer,varchar,varchar, varchar,varchar,integer) returns integer as ' declare p_repository_id alias for $1; -- default null p_table_name alias for $2; -- p_internal_data_p alias for $3; -- default "f" p_package_name alias for $4; -- default null p_last_update alias for $5; -- default sysdate p_source alias for $6; -- default null p_source_url alias for $7; -- default null p_effective_date alias for $8; -- default sysdate p_expiry_date alias for $9; -- default null p_maintainer_id alias for $10; -- default null p_notes alias for $11; -- default null (not Oracle empty_blob()) -- I really see no need for these as parameters -- creation_date alias for $12; -- default sysdate p_first_names alias for $12; -- default null p_last_name alias for $13; -- default null p_creation_ip alias for $14; -- default null p_object_type alias for $15; -- default "acs_reference_repository" p_creation_user alias for $16; -- default null v_repository_id acs_reference_repositories.repository_id%TYPE; v_object_type acs_objects.object_type%TYPE; v_maintainer_id persons.person_id%TYPE; begin if p_object_type is null then v_object_type := ''acs_reference_repository''; else v_object_type := p_object_type; end if; v_repository_id := acs_object__new ( p_repository_id, v_object_type, now(), p_creation_user, p_creation_ip, null, ''t'', p_source, null ); -- This logic is not correct as the maintainer could already exist -- The way around this is a little clunky as you can search persons -- then pick an existing person or add a new one, to many screens! -- I really doubt the need for person anyway. -- -- It probably needs to just be a UI function and pass -- in the value for maintainer. -- -- IN OTHER WORDS -- Guaranteed to probably break in the future if you depend on -- first_names and last_name to still exist as a param -- This needs to be updated in the Oracle version also -- NEEDS TO BE FIXED - jag if p_first_names is not null and p_last_name is not null and p_maintainer_id is null then v_maintainer_id := person__new (null, ''person'', now(), null, null, null, null, p_first_names, p_last_name, null); else if p_maintainer_id is not null then v_maintainer_id := p_maintainer_id; else v_maintainer_id := null; end if; end if; insert into acs_reference_repositories (repository_id,table_name,internal_data_p, last_update,package_name,source, source_url,effective_date,expiry_date, maintainer_id,lob) values (v_repository_id, p_table_name, p_internal_data_p, p_last_update, p_package_name, p_source, p_source_url, p_effective_date, p_expiry_date, v_maintainer_id, p_notes); return v_repository_id; end; ' language 'plpgsql'; -- made initially for PG create function acs_reference__new (varchar,timestamptz, varchar,varchar,timestamptz) returns integer as ' declare p_table_name alias for $1; -- p_last_update alias for $2; -- default sysdate p_source alias for $3; -- default null p_source_url alias for $4; -- default null p_effective_date alias for $5; -- default sysdate v_repository_id acs_reference_repositories.repository_id%TYPE; begin return acs_reference__new(null, p_table_name, ''f'', null, null, p_source, p_source_url, p_effective_date, null, null, null, null, null, null, ''acs_reference_repository'', null); end; ' language 'plpgsql'; create function acs_reference__delete (integer) returns integer as ' declare p_repository_id alias for $1; v_maintainer_id acs_objects.object_id%TYPE; begin select maintainer_id into v_maintainer_id from acs_reference_repositories where repository_id = p_repository_id; delete from acs_reference_repositories where repository_id = p_repository_id; perform acs_object__delete(p_repository_id); return 0; end; ' language 'plpgsql'; create function acs_reference__is_expired_p (integer) returns char as ' declare repository_id alias for $1; v_expiry_date acs_reference_repositories.expiry_date%TYPE; begin select expiry_date into v_expiry_date from acs_reference_repositories where repository_id = is_expired_p.repository_id; if coalesce(v_expiry_date,now()+1) < now() then return ''t''; else return ''f''; end if; end; ' language 'plpgsql'; openacs-5.7.0/packages/acs-reference/sql/postgresql/acs-reference-drop.sql0000644000175000017500000000332307661403424026451 0ustar frankiefrankie-- packages/acs-reference/sql/postgresql/acs-reference-data.sql -- -- Drop the ACS Reference packages -- -- @author jon@jongriffin.com -- @dropd 2001-07-16 -- -- @cvs-id $Id: acs-reference-drop.sql,v 1.3 2003/05/17 09:55:32 jeffd Exp $ -- -- drop all associated tables and functions -- DRB: in PG we could do this dynamically as JonG has done in Oracle. The -- proc name can easily be picked up from pg_proc since we use unique package -- keys as prefaces. The params can be picked up as well but I don't know -- how off the top of my head. It would be a nice to write a general function -- to do this in both Oracle and PG - "drop_package_functions(package_key)". select acs_privilege__remove_child('create','acs_reference_create'); select acs_privilege__remove_child('write', 'acs_reference_write'); select acs_privilege__remove_child('read', 'acs_reference_read'); select acs_privilege__remove_child('delete','acs_reference_delete'); select acs_privilege__drop_privilege('acs_reference_create'); select acs_privilege__drop_privilege('acs_reference_write'); select acs_privilege__drop_privilege('acs_reference_read'); select acs_privilege__drop_privilege('acs_reference_delete'); select acs_object__delete(repository_id) from acs_reference_repositories; select acs_object_type__drop_type ('acs_reference_repository', 't'); drop function acs_reference__new (varchar,timestamptz, varchar,varchar,timestamptz); drop function acs_reference__new (integer,varchar,boolean,varchar,timestamptz, varchar,varchar,timestamptz,timestamptz,integer,integer,varchar,varchar, integer,varchar,integer); drop function acs_reference__delete (integer); drop function acs_reference__is_expired_p (integer); drop table acs_reference_repositories; openacs-5.7.0/packages/acs-reference/www/0000755000175000017500000000000011575225532020106 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/www/doc/0000755000175000017500000000000011724401447020650 5ustar frankiefrankieopenacs-5.7.0/packages/acs-reference/www/doc/design.html0000644000175000017500000000636310465451664023026 0ustar frankiefrankie acs-reference Design Documentation

    acs-reference Design Documentation

    I. Introduction

    Reference data services are often overlooked in the rush to get coding. Much of the code is redundant or of similarly patterned implementations. This package intends to address some common features and needs.

    II. Historical Considerations

    Before the existence of acs-reference, the ACS required that you preload some tables in a script to get some basic reference functionality. There were many problems with this:

    • No easy way to find out what reference data even existed.
    • No way to find out how old the data was.
    • No way to find out where that data came from.
    • Very US/English slant on the data.

    III. Design Tradeoffs

    Primary Goals

    • This system was designed with maintainability and reusability as its primary goals. By wrapping a layer around all of the reference tables we have increased the maintainability immensely.
    • Another goal was to bring together many different types of data and present them in a logical fashion. It was amazing how little of this data is available on the internet in a database friendly form.

    Performance

    When updating the reference tables their is overhead due to the fact that the table is registered with the repository. This should rarely occur anyway as the tables are only added once. By not having the actual data itself in the acs-object system, subsequent additions and deletions to the reference tables themselves are unaffected by this overhead.

    IV. API

    See api-browser

    V. Data Model Discussion

    The UNSPSC reference data has a data model for handling data revisions. An application can determine any new/revised category based on existing, obsolete data.

    VI. User Interface

    Their is no end user interface. There needs to be some kind of admin UI to report status and possibly manage updates per requirements.

    VII. Configuration/Parameters

    None

    VIII. Future Improvements/Areas of Likely Change

    A server based update mechanism will be supported. This will allow for tables to be updated (and preferably diffed) instead of being reloaded with a package upgrade. An interface to produce xml/csv from the reference data would be a nice service to the community (allowing legacy applications a way to import this data).

    IX. Authors

    Jon Griffin

    X. Pre-CVS Revision History

    $Log: design.html,v $
    Revision 1.4  2006/08/06 20:40:20  torbenb
    upgrading html, closing li p tags, adding quotes to tag attributes
    
    Revision 1.3  2006/08/06 18:54:02  torbenb
    added documentation commentary, applied bs filter, renumbered sections
    
    Revision 1.2  2006/08/06 18:30:57  torbenb
    removing c-Ms, wrapping text with p tags, added link to api-browser in api section
    
    Revision 1.1  2001/04/22 00:53:12  jong
    initial openacs import
    
    Revision 1.2  2000/12/13 04:39:00  jong
    Added Revision History and corrected typo in reference link
    
    openacs-5.7.0/packages/acs-reference/www/doc/index.html0000644000175000017500000000103410465451664022652 0ustar frankiefrankie ACS Reference Documentation

    ACS Reference Documentation


    Engineering Docs

    Current docs are always at:
    jongriffin.com


    jon@jongriffin.com
    openacs-5.7.0/packages/acs-reference/www/doc/requirements.html0000644000175000017500000001456010465451664024276 0ustar frankiefrankie ACS Reference Requirements

    ACS Reference Requirements

    by Jon Griffin


    I. Introduction

    This document describes the requirements for the ACS Reference service package. This package has the following primary functions:

    • It allows applications to refer to and employ a common set of reference data.
    • It gives administrators the ability to run standard reports on this data.
    • It offers a convenient repository for and the ability to run reports on data of this sort.
    • It allows us to monitor the usage of reference data.

    II. Vision Statement

    What is reference data? Simply put, it is data that doesn't change very often and also in many cases comes from an external source and not from within the system itself. Many times it is created from a standards body, i.e. ISO or ANSI, and may be required for a client's particular industrial needs.

    Some examples of reference data are:

    • Geographic data: zip codes, country codes and states/provinces
    • Standards bodies data: ISO 4217 currency codes, ISO 3166 Country Codes, ITU Vehicle Signs
    • Quasi-Standards: S&P Long-term Issuer Credit Ratings
    • Internal: Status Codes, Employee Position Codes

    Historically, reference data has been looked upon by developers as something less important than more immediate coding needs, and so most data models simply defer the issue by treating reference data as something simple to implement. Elsewhere. The reality is that for most organizations reference data is extremely important and also extremely difficult to manage.

    This module will not only package all of a site's reference data in one place, it will also help manage that data.

    III. System Overview

    The ACS Reference package consists of:

    • A standard framework for monjitoring and modifying reference data.
    • A method of determining whether or not that data is expired.
    • The ability to include not only the data but also functions to work with that data.

    IV. Use-cases and User-Scenarios

    Papi Programmer is developing a module that will use country codes as part of his table structure. Instead of creating his own table he can use the ACS Reference package and the country codes therein. If the country codes change - which does in fact happen from time to time - the ACS Reference package will maintain that information for him.

    V. Related Links

    VI.A Requirements: Data Model

    10.10 The package should use a table that is the master table for all reference tables.
    10.20 The package should employ a field to show whether this data is internally derived or not.
    10.30 The package should employ a field to signify whether there is a PL/SQL package involved with this table.
    10.40 The package should offer an indicatation of when this data was last updated.
    10.50 The package should offer an indication of what the original source of this data was.
    10.60 The package should offer an indication of what the original source URL was, if any.
    10.70 The package should offer a representation of effective datetime
    10.80 The package should offer a representation of discontinued datetime
    10.90 The package should keep an indication of who the data maintainer is, by user_id.

    VI.B Requirements: API

    20.10 The package should offer a function to determine if a particular table has expired.

    The requirements below are not met by the current implementation:

    30.10 There needs to be a way to query the data source and update automatically. If that isn't possible, as it won't be in many cases, the application should be able to query a master server and see if there is new data for a particular table or tables. For example: refdata.arsdigita.com could hold the reference tables and when newer table versions become available, simply upload only these versions or perhaps even only the differences between the tables. In any case, there should be an admin page that shows current status and revisions of various data, where to find info about additional sources (if applicable), and provide a UI to upload or import new data.

    VII. Implementation Notes

    The package needs to handle changes to reference data in a graceful fashion. For example, if a country splits into two or more countries, what should happen?

    • The reference package should note this change.
    • The appropriate table is updated. In this case countries et al.
    • An update to the repository database field effective_date is added.
    • A diff type of entry into the reference repository history. This is not in the current data model
    • Then any sub-programs using this data will note the change of effective date and be able to handle the change as needed (i.e. simply read the new table).
    • Historical data will be available using this diff for those applications that need to use the old data

    Note also that it is possible to have overlapping effective dates. This will not be implemented in the first version, but should be recognized and accomodated throughout the development process for the service package.

    VIII. Pre-CVS Revision History

    $Log: requirements.html,v $
    Revision 1.3  2006/08/06 20:40:20  torbenb
    upgrading html, closing li p tags, adding quotes to tag attributes
    
    Revision 1.2  2006/08/06 18:41:43  torbenb
    removed c-Ms, added p tags, added a comment to unimplemented requirements / feature request
    
    Revision 1.1  2001/04/22 00:53:12  jong
    initial openacs import
    
    Revision 1.7  2000/12/15 04:09:25  jfinkler
    fixed numbering scheme
    
    Revision 1.6  2000/12/13 04:33:47  jong
    Updated doc for alpha release
    
    Revision 1.5  2000/12/12 06:29:21  jfinkler
    spelling error, my fault
    
    Revision 1.4  2000/12/12 06:28:05  jfinkler
    fixed a few formatting errors
    
    Revision 1.3  2000/12/12 06:26:20  jfinkler
    reorganized content, edited for clarity
    
    Revision 1.2  2000/12/08 02:41:31  ron
    initial version
    
    openacs-5.7.0/packages/acs-reference/www/view-one-reference.adp0000644000175000017500000000177007663154545024276 0ustar frankiefrankie @context_bar;noquote@ @title;noquote@
    Table Name @table_info.table_name@
    Package Name @table_info.package_name@
    Internal Data? @table_info.internal_data_p@
    Source @table_info.source@
    Source URL @table_info.source_url@
    Last Update @table_info.last_update@
    Effective Date @table_info.effective_date@
    Expiry Date @table_info.expiry_date@
    Maintainer @table_info.maintainer_id@
    openacs-5.7.0/packages/acs-reference/www/view-one-reference.tcl0000644000175000017500000000120310210730322024252 0ustar frankiefrankiead_page_contract { This page views one table of reference data @param repository_id @author Jon Griffin (jon@jongriffin.com) @creation-date 17 Sept 2001 @cvs-id $Id: view-one-reference.tcl,v 1.3 2005/03/01 00:01:22 jeffd Exp $ } { repository_id:integer,notnull } -properties { context_bar:onevalue package_id:onevalue user_id:onevalue table_info:onerow } set package_id [ad_conn package_id] set title "View one Table" set context_bar [list [list "reference-list" "Reference List" ] "$title"] set user_id [ad_conn user_id] db_1row get_table { *SQL* } -column_array table_info ad_return_template openacs-5.7.0/packages/acs-reference/www/view-one-reference.xql0000644000175000017500000000070010010551570024301 0ustar frankiefrankie select repository_id, table_name, internal_data_p, package_name, last_update, source, source_url, effective_date, expiry_date, (select user_id from cc_users u where user_id = maintainer_id) as maintainer_id from acs_reference_repositories r where repository_id= :repository_id openacs-5.7.0/packages/acs-reference/www/index.adp0000644000175000017500000000055510010551406021671 0ustar frankiefrankie @context_bar;noquote@ @title;noquote@

    @title@;noquote


    Reports

    Coming soon!

    Admin

    None Yet
    openacs-5.7.0/packages/acs-reference/www/index.tcl0000644000175000017500000000076210210730322021705 0ustar frankiefrankiead_page_contract { Main Index page for reference data. @author Jon Griffin (jon@jongriffin.com) @creation-date 2001-08-26 @cvs-id $Id: index.tcl,v 1.3 2005/03/01 00:01:22 jeffd Exp $ } { } -properties { context_bar:onevalue package_id:onevalue user_id:onevalue title:onevalue } set title "Reference Data" set package_id [ad_conn package_id] set context_bar [list $title] set user_id [ad_conn user_id] set admin_p [ad_permission_p $package_id admin] ad_return_template openacs-5.7.0/packages/acs-reference/www/reference-data-list-oracle.xql0000644000175000017500000000066307342613564025725 0ustar frankiefrankie oracle8.1.6 select repository_id, table_name, internal_data_p, package_name, to_char(last_update,'MM-DD-YYYY') updated, source, source_url, effective_date, expiry_date from acs_reference_repositories a order by table_name openacs-5.7.0/packages/acs-reference/www/reference-data-list-postgresql.xql0000644000175000017500000000067007344243113026650 0ustar frankiefrankie postgresql7.1 select repository_id, table_name, internal_data_p, package_name, to_char(last_update,'MM-DD-YYYY') as updated, source, source_url, effective_date, expiry_date from acs_reference_repositories a order by table_name openacs-5.7.0/packages/acs-reference/www/table-detail.adp0000644000175000017500000000016510010551644023112 0ustar frankiefrankie @context_bar;noquote@ @title;noquote@ openacs-5.7.0/packages/acs-reference/www/table-detail.tcl0000644000175000017500000000102110210730322023112 0ustar frankiefrankiead_page_contract { This page views the table structure @param table_name @author Jon Griffin (jon@jongriffin.com) @creation-date 17 Sept 2001 @cvs-id $Id: table-detail.tcl,v 1.3 2005/03/01 00:01:22 jeffd Exp $ } { table_name:notnull } -properties { context_bar:onevalue package_id:onevalue user_id:onevalue table_info:onerow } set package_id [ad_conn package_id] set title "View one Table Structure" set context_bar [list "$title"] set user_id [ad_conn user_id] ad_return_templateopenacs-5.7.0/packages/acs-reference/www/reference-data-list.adp0000644000175000017500000000061610010551460024376 0ustar frankiefrankie @context_bar;noquote@ @title;noquote@ You have no reference data in the database right now.

    openacs-5.7.0/packages/acs-reference/www/reference-data-list.tcl0000644000175000017500000000100010210730322024376 0ustar frankiefrankiead_page_contract { This page lists all the formats @author Jon Griffin (jon@jongriffin.com) @creation-date 2000-10-04 @cvs-id $Id: reference-data-list.tcl,v 1.2 2005/03/01 00:01:22 jeffd Exp $ } { } -properties { context_bar:onevalue package_id:onevalue user_id:onevalue data:multirow } set package_id [ad_conn package_id] set title "List Reference Data" set context_bar [list "$title"] set user_id [ad_conn user_id] db_multirow data data_select { } ad_return_templateopenacs-5.7.0/packages/acs-reference/acs-reference.info0000644000175000017500000000254611575167337022660 0ustar frankiefrankie ACS Reference Data ACS Reference Datas t t Jon Griffin Tools and API for managing refrence data. 2011-06-12 3 Mayuli Enterprises, LLC GPL 3 Reference Data provides an API to support: <ul> <li> A common set of reference data. <li> Running standard reports on this data. <li> Monitoring the usage of reference data. </ul> openacs-5.7.0/packages/acs-subsite/0000755000175000017500000000000011724401447016777 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/lib/0000755000175000017500000000000011724401447017545 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/lib/subsites.adp0000644000175000017500000000005607774373717022117 0ustar frankiefrankie openacs-5.7.0/packages/acs-subsite/lib/subsites.tcl0000644000175000017500000000361711042365440022114 0ustar frankiefrankie# @param admin_p - generate admin action links. set pretty_name [_ acs-subsite.subsite] set pretty_plural [_ acs-subsite.subsites] set admin_p [permission::permission_p -object_id [ad_conn subsite_id] -privilege admin -party_id [ad_conn untrusted_user_id]] set actions {} if {[info exists admin_p] && $admin_p } { lappend actions [_ acs-subsite.Create_new_subsite] "[subsite::get_element -element url]admin/subsite-add" {} } list::create \ -name subsites \ -multirow subsites \ -actions $actions \ -no_data "[_ acs-subsite.No_pretty_plural [list pretty_plural $pretty_plural]]" \ -elements { instance_name { label "[_ acs-subsite.Name]" link_url_col url } num_members { label "\# [_ acs-subsite.Members]" html { align right } } member_state { label "Member state" display_template { Approved Awaiting approval Rejected @subsites.member_state@ Join Request membership } } } set subsite_node_id [subsite::get_element -element node_id] set subsite_url [subsite::get_element -element url] set untrusted_user_id [ad_conn untrusted_user_id] db_multirow -extend { url join_url request_url } subsites select_subsites {*SQL*} { set join_url [export_vars -base "${subsite_url}register/user-join" { group_id { return_url [ad_return_url] } }] set url $subsite_url$name } openacs-5.7.0/packages/acs-subsite/lib/subsites.xql0000644000175000017500000000265110214672157022141 0ustar frankiefrankie select p.package_id, p.instance_name, n.node_id, n.name, :subsite_url || n.name as url, (select count(*) from group_approved_member_map m where m.rel_type = 'membership_rel' and m.group_id = ag.group_id) as num_members, (select min(r2.member_state) from group_member_map m2, membership_rels r2 where m2.group_id = ag.group_id and m2.member_id = :untrusted_user_id and r2.rel_id = m2.rel_id) as member_state, g.group_id, g.join_policy from site_nodes n, apm_packages p, application_groups ag, groups g where n.parent_id = :subsite_node_id and p.package_id = n.object_id and p.package_key in ('[join [subsite::package_keys] {','}]') and ag.package_id = p.package_id and g.group_id = ag.group_id and (exists (select 1 from all_object_party_privilege_map perm where perm.object_id = p.package_id and perm.privilege = 'read' and perm.party_id = :untrusted_user_id) or g.join_policy != 'closed') order by lower(instance_name) openacs-5.7.0/packages/acs-subsite/lib/message.adp0000644000175000017500000000021210221122716021640 0ustar frankiefrankie @title;noquote@ @context;noquote@ @message;noquote@ openacs-5.7.0/packages/acs-subsite/lib/message.tcl0000644000175000017500000000051410221122716021663 0ustar frankiefrankiead_page_contract { This include expects "message" to be set as html and if no title is present uses "Message". Used to inform of actions in registration etc. @cvs-id $Id: message.tcl,v 1.1 2005/03/25 23:59:10 jeffd Exp $ } if {![exists_and_not_null title]} { set page_title Message } set context [list $title] openacs-5.7.0/packages/acs-subsite/lib/user-subsites.adp0000644000175000017500000000047210217666627023064 0ustar frankiefrankie

    #acs-subsite.You_are_in_the_follow#

    openacs-5.7.0/packages/acs-subsite/lib/user-subsites.tcl0000644000175000017500000000077310217666627023106 0ustar frankiefrankiedb_multirow -extend {url admin_p} groups groups { select distinct ap.package_id, groups.group_id, lower(groups.group_name), groups.group_name from groups, group_member_map gm, application_groups ap where groups.group_id = gm.group_id and gm.member_id=:user_id and ap.group_id = groups.group_id order by lower(groups.group_name) } { set admin_p [permission::permission_p -party_id $user_id -object_id $group_id -privilege "admin"] set url [apm_package_url_from_id $package_id] } openacs-5.7.0/packages/acs-subsite/lib/email-confirm.adp0000644000175000017500000000117510626736346022772 0ustar frankiefrankie #acs-subsite.lt_Your_email_is_confirm# #acs-subsite.lt_Your_email_has_been_c#

    @export_vars;noquote@

    #acs-subsite.lt_Your_email_has_been_c_1#

    #acs-subsite.Email_not_Requested#

    #acs-subsite.lt_We_were_not_awaiting_#

    #acs-subsite.lt_Please_try_to_a_hrefi#

    openacs-5.7.0/packages/acs-subsite/lib/email-confirm.tcl0000644000175000017500000000106210626736346023003 0ustar frankiefrankieif {![db_0or1row userp {select 1 from users where user_id = :user_id}] || $token ne [auth::get_user_secret_token -user_id $user_id] } { set title "Bad token" set message "The link given to authenticate your email was invalid." ad_return_template /packages/acs-subsite/lib/message } else { auth::set_email_verified -user_id $user_id acs_user::get -user_id $user_id -array user_info set export_vars [export_vars -form { { username $user_info(username) } }] set site_link [ad_site_home_link] set system_name [ad_system_name] } openacs-5.7.0/packages/acs-subsite/lib/login.adp0000644000175000017500000000064310721035753021345 0ustar frankiefrankie@focus;noquote@ openacs-5.7.0/packages/acs-subsite/lib/login.tcl0000644000175000017500000002277011525000555021363 0ustar frankiefrankie# Present a login box # # Expects: # subsite_id - optional, defaults to nearest subsite # return_url - optional, defaults to Your Account # Optional: # authority_id # username # email # # Redirect to HTTPS if so configured if { [security::RestrictLoginToSSLP] } { security::require_secure_conn } set self_registration [parameter::get_from_package_key \ -package_key acs-authentication \ -parameter AllowSelfRegister \ -default 1] if { ![exists_and_not_null package_id] } { set subsite_id [subsite::get_element -element object_id] } set email_forgotten_password_p [parameter::get \ -parameter EmailForgottenPasswordP \ -package_id $subsite_id \ -default 1] if { ![info exists username] } { set username {} } if { ![info exists email] } { set email {} } if { $email eq "" && $username eq "" && [ad_conn untrusted_user_id] != 0 } { acs_user::get -user_id [ad_conn untrusted_user_id] -array untrusted_user if { [auth::UseEmailForLoginP] } { set email $untrusted_user(email) } else { set authority_id $untrusted_user(authority_id) set username $untrusted_user(username) } } # Persistent login # The logic is: # 1. Allowed if allowed both site-wide (on acs-kernel) and on the subsite # 2. Default setting is in acs-kernel set allow_persistent_login_p [parameter::get -parameter AllowPersistentLoginP -package_id [ad_acs_kernel_id] -default 1] if { $allow_persistent_login_p } { set allow_persistent_login_p [parameter::get -package_id $subsite_id -parameter AllowPersistentLoginP -default 1] } if { $allow_persistent_login_p } { set default_persistent_login_p [parameter::get -parameter DefaultPersistentLoginP -package_id [ad_acs_kernel_id] -default 1] } else { set default_persistent_login_p 0 } set subsite_url [subsite::get_element -element url] set system_name [ad_system_name] if { [exists_and_not_null return_url] } { if { [util::external_url_p $return_url] } { ad_returnredirect -message "only urls without a host name are permitted" "." ad_script_abort } } else { set return_url [ad_pvt_home] } set authority_options [auth::authority::get_authority_options] if { ![exists_and_not_null authority_id] } { set authority_id [lindex [lindex $authority_options 0] 1] } set forgotten_pwd_url [auth::password::get_forgotten_url -authority_id $authority_id -username $username -email $email] set register_url [export_vars -base "[subsite::get_url]register/user-new" { return_url }] if { $authority_id eq [auth::get_register_authority] || [auth::UseEmailForLoginP] } { set register_url [export_vars -no_empty -base $register_url { username email }] } set login_button [list [list [_ acs-subsite.Log_In] ok]] ad_form -name login -html { style "margin: 0px;" } -show_required_p 0 -edit_buttons $login_button -action "[subsite::get_url]register/" -form { {return_url:text(hidden)} {time:text(hidden)} {token_id:text(hidden)} {hash:text(hidden)} } set username_widget text if { [parameter::get -parameter UsePasswordWidgetForUsername -package_id [ad_acs_kernel_id]] } { set username_widget password } set focus {} if { [auth::UseEmailForLoginP] } { ad_form -extend -name login -form [list [list email:text($username_widget),nospell [list label [_ acs-subsite.Email]] [list html [list style "width: 150px"]]]] set user_id_widget_name email if { $email ne "" } { set focus "password" } else { set focus "email" } } else { if { [llength $authority_options] > 1 } { ad_form -extend -name login -form { {authority_id:integer(select) {label "[_ acs-subsite.Authority]"} {options $authority_options} } } } ad_form -extend -name login -form [list [list username:text($username_widget),nospell [list label [_ acs-subsite.Username]] [list html [list style "width: 150px"]]]] set user_id_widget_name username if { $username ne "" } { set focus "password" } else { set focus "username" } } set focus "login.$focus" ad_form -extend -name login -form { {password:text(password) {label "[_ acs-subsite.Password]"} {html {style "width: 150px"}} } } set options_list [list [list [_ acs-subsite.Remember_my_login] "t"]] if { $allow_persistent_login_p } { ad_form -extend -name login -form { {persistent_p:text(checkbox),optional {label ""} {options $options_list} } } } ad_form -extend -name login -on_request { # Populate fields from local vars set persistent_p [ad_decode $default_persistent_login_p 1 "t" ""] # One common problem with login is that people can hit the back button # after a user logs out and relogin by using the cached password in # the browser. We generate a unique hashed timestamp so that users # cannot use the back button. set time [ns_time] set token_id [sec_get_random_cached_token_id] set token [sec_get_token $token_id] set hash [ns_sha1 "$time$token_id$token"] } -on_submit { # Check timestamp set token [sec_get_token $token_id] set computed_hash [ns_sha1 "$time$token_id$token"] set expiration_time [parameter::get -parameter LoginPageExpirationTime -package_id [ad_acs_kernel_id] -default 600] if { $expiration_time < 30 } { # If expiration_time is less than 30 seconds, it's practically impossible to login # and you will have completely hosed login on your entire site set expiration_time 30 } if { $hash ne $computed_hash || \ $time < [ns_time] - $expiration_time } { ad_returnredirect -message [_ acs-subsite.Login_has_expired] -- [export_vars -base [ad_conn url] { return_url }] ad_script_abort } if { ![exists_and_not_null authority_id] } { # Will be defaulted to local authority set authority_id {} } if { ![exists_and_not_null persistent_p] } { set persistent_p "f" } if {![element exists login email]} { set email [ns_queryget email ""] } set first_names [ns_queryget first_names ""] set last_name [ns_queryget last_name ""] array set auth_info [auth::authenticate \ -return_url $return_url \ -authority_id $authority_id \ -email [string trim $email] \ -first_names $first_names \ -last_name $last_name \ -username [string trim $username] \ -password $password \ -persistent=[expr {$allow_persistent_login_p && [template::util::is_true $persistent_p]}]] # Handle authentication problems switch $auth_info(auth_status) { ok { # Continue below } bad_password { form set_error login password $auth_info(auth_message) break } default { form set_error login $user_id_widget_name $auth_info(auth_message) break } } if { [exists_and_not_null auth_info(account_url)] } { ad_returnredirect $auth_info(account_url) ad_script_abort } # Handle account status switch $auth_info(account_status) { ok { # Continue below } default { # if element_messages exists we try to get the element info if {[info exists auth_info(element_messages)] && [auth::authority::get_element \ -authority_id $authority_id \ -element allow_user_entered_info_p]} { foreach message [lsort $auth_info(element_messages)] { ns_log notice "LOGIN $message" switch -glob -- $message { *email* { if {[element exists login email]} { set operation set_properties } else { set operation create } element $operation login email -widget $username_widget -datatype text -label [_ acs-subsite.Email] if {[element error_p login email]} { template::form::set_error login email [_ acs-subsite.Email_not_provided_by_authority] } } *first* { element create login first_names -widget text -datatype text -label [_ acs-subsite.First_names] template::form::set_error login email [_ acs-subsite.First_names_not_provided_by_authority] } *last* { element create login last_name -widget text -datatype text -label [_ acs-subsite.Last_name] template::form::set_error login last_name [_ acs-subsite.Last_name_not_provided_by_authority] } } } set auth_info(account_message) "" ad_return_template } else { # Display the message on a separate page ad_returnredirect \ -message $auth_info(account_message) \ -html \ [export_vars \ -base "[subsite::get_element \ -element url]register/account-closed"] ad_script_abort } } } } -after_submit { # We're logged in # Handle account_message if { [exists_and_not_null auth_info(account_message)] } { ad_returnredirect [export_vars -base "[subsite::get_element -element url]register/account-message" { { message $auth_info(account_message) } return_url }] ad_script_abort } else { if {![info exists auth_info(element_messages)]} { # No message ad_returnredirect $return_url ad_script_abort } } } openacs-5.7.0/packages/acs-subsite/lib/home.adp0000644000175000017500000000734011321344157021164 0ustar frankiefrankie

    #acs-subsite.My_Account#

    #acs-subsite.Account_closed_workspace_msg#

    #acs-subsite.Your_Portrait#

    #acs-subsite.lt_Show_everyone_else_at# #acs-subsite.upload_a_portrait#

    #acs-subsite.Your_Portrait#

    #acs-subsite.lt_On_portrait_publish_d#.

    Portrait

    #acs-subsite.Edit#

    @portrait_description@

    #acs-subsite.Groups#

    @fragments:item;noquote@
    openacs-5.7.0/packages/acs-subsite/lib/home.tcl0000644000175000017500000000512211321344157021176 0ustar frankiefrankie# /pvt/home.tcl ad_page_contract { user's workspace page @cvs-id $Id: home.tcl,v 1.3 2010/01/07 11:41:35 emmar Exp $ } -properties { system_name:onevalue context:onevalue full_name:onevalue email:onevalue url:onevalue screen_name:onevalue bio:onevalue portrait_state:onevalue portrait_publish_date:onevalue portrait_title:onevalue portrait_description:onevalue export_user_id:onevalue ad_url:onevalue member_link:onevalue pvt_home_url:onevalue } set user_id [auth::require_login -account_status closed] acs_user::get -array user -include_bio -user_id $user_id set account_status [ad_conn account_status] set login_url [ad_get_login_url] set subsite_url [ad_conn vhost_subsite_url] set page_title [ad_pvt_home_name] set pvt_home_url [ad_pvt_home] set context [list $page_title] set fragments [callback -catch user::workspace -user_id $user_id] set ad_url [ad_url] set community_member_url [acs_community_member_url -user_id $user_id] set notifications_url [lindex [site_node::get_children -node_id [subsite::get_element -element node_id] -package_key "notifications"] 0] set system_name [ad_system_name] set portrait_upload_url [export_vars -base "../user/portrait/upload" { { return_url [ad_return_url] } }] if {[parameter::get -parameter SolicitPortraitP -default 0]} { # we have portraits for some users if {![db_0or1row get_portrait_info " select cr.publish_date, nvl(cr.title,'your portrait') as portrait_title, nvl(cr.description,'no description') as portrait_description from cr_revisions cr, cr_items ci, acs_rels a where cr.revision_id = ci.live_revision and ci.item_id = a.object_id_two and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel' "]} { set portrait_state "upload" } else { if { $portrait_title eq "" } { set portrait_title "[_ acs-subsite.no_portrait_title_message]" } set portrait_state "show" set portrait_publish_date [lc_time_fmt $publish_date "%q"] } } else { set portrait_state "none" } set whos_online_url "[subsite::get_element -element url]shared/whos-online" set make_visible_url "[subsite::get_element -element url]shared/make-visible" set make_invisible_url "[subsite::get_element -element url]shared/make-invisible" set invisible_p [whos_online::user_invisible_p [ad_conn untrusted_user_id]] set subsite_id [ad_conn subsite_id] set user_info_template [parameter::get -parameter "UserInfoTemplate" -package_id $subsite_id] if {$user_info_template eq ""} { set user_info_template "/packages/acs-subsite/lib/user-info" } openacs-5.7.0/packages/acs-subsite/lib/home.xql0000644000175000017500000000214010665274105021222 0ustar frankiefrankie select first_names, last_name, email, url, screen_name from cc_users where user_id=:user_id select attr_value from acs_attribute_values where object_id = :user_id and attribute_id = (select attribute_id from acs_attributes where object_type = 'person' and attribute_name = 'bio') select cr.publish_date, cr.title as portrait_title, cr.description as portrait_description from cr_revisions cr, cr_items ci, acs_rels a where cr.revision_id = ci.live_revision and ci.item_id = a.object_id_two and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel' select email from cc_users where user_iad=:user_id openacs-5.7.0/packages/acs-subsite/lib/applications.adp0000644000175000017500000000006207774373717022741 0ustar frankiefrankie openacs-5.7.0/packages/acs-subsite/lib/applications.tcl0000644000175000017500000000255711042365440022743 0ustar frankiefrankieset admin_p [permission::permission_p -object_id [ad_conn subsite_id] -privilege admin -party_id [ad_conn untrusted_user_id]] set actions [list] if { $admin_p } { lappend actions [_ acs-subsite.Add_new_app] [export_vars -base "[subsite::get_element -element url]admin/applications/application-add" { { return_url [ad_return_url] } }] {} } list::create \ -name applications \ -multirow applications \ -no_data "[_ acs-subsite.No_applications]" \ -actions $actions \ -elements { instance_name { label "[_ acs-subsite.Name]" link_url_eval {$name/} } } set subsite_node_id [subsite::get_element -element node_id] set user_id [ad_conn user_id] db_multirow applications select_applications { select p.package_id, p.instance_name, n.node_id, n.name from site_nodes n, apm_packages p, apm_package_types t where n.parent_id = :subsite_node_id and p.package_id = n.object_id and t.package_key = p.package_key and t.package_type = 'apm_application' and exists (select 1 from all_object_party_privilege_map perm where perm.object_id = p.package_id and perm.privilege = 'read' and perm.party_id = :user_id) order by upper(instance_name) } openacs-5.7.0/packages/acs-subsite/lib/services.adp0000644000175000017500000000005607766162053022067 0ustar frankiefrankie openacs-5.7.0/packages/acs-subsite/lib/services.tcl0000644000175000017500000000240611042365440022071 0ustar frankiefrankieset admin_p [permission::permission_p -object_id [ad_conn subsite_id] -privilege admin -party_id [ad_conn untrusted_user_id]] list::create \ -name services \ -multirow services \ -no_data "[_ acs-subsite.No_services]" \ -elements { instance_name { label "[_ acs-subsite.Name]" link_url_eval {$name/} } } set services [list] foreach url [site_node::get_children -package_type apm_service -node_id [subsite::get_element -element node_id]] { array unset node array set node [site_node::get_from_url -url $url -exact] if { $node(package_key) ne "acs-subsite" && [permission::permission_p -object_id $node(object_id) -privilege read] } { lappend services [list \ $node(instance_name) \ $node(node_id) \ $node(name) \ $node(object_id)] } } # Sort them by instance_name set services [lsort -index 0 $services] multirow create services instance_name node_id name package_id read_p foreach elm $services { multirow append services \ [lindex $elm 0] \ [lindex $elm 1] \ [lindex $elm 2] \ [lindex $elm 3] \ [lindex $elm 4] } openacs-5.7.0/packages/acs-subsite/lib/user-info.adp0000644000175000017500000000040611320616746022144 0ustar frankiefrankie@focus;noquote@

    #acs-subsite.Notice#

    #acs-subsite.Elements_not_editable#

    openacs-5.7.0/packages/acs-subsite/lib/user-info.tcl0000644000175000017500000001566511320616746022177 0ustar frankiefrankie# # Expects: # user_id:optional # return_url:optional # edit_p:optional # message:optional # show_groups_p:optional auth::require_login -account_status closed if { ![exists_and_not_null user_id] } { set user_id [ad_conn untrusted_user_id] } elseif { $user_id != [auth::get_user_id -account_status closed] } { permission::require_permission -object_id $user_id -privilege admin } if { ![exists_and_not_null return_url] } { set return_url [ad_conn url] } if { ![exists_and_not_null show_groups_p] } { set show_groups_p 0 } set action_url "[subsite::get_element -element url]user/basic-info-update" acs_user::get -user_id $user_id -array user -include_bio set authority_name [auth::authority::get_element -authority_id $user(authority_id) -element pretty_name] set form_elms { authority_id username first_names last_name email screen_name url bio } foreach elm $form_elms { set elm_mode($elm) {} } set read_only_elements [auth::sync::get_sync_elements -authority_id $user(authority_id)] set read_only_notice_p [expr {[llength $read_only_elements] > 0}] if { ![acs_user::site_wide_admin_p] } { lappend read_only_elements authority_id username } foreach elm $read_only_elements { set elm_mode($elm) {display} } set edit_mode_p [expr ![empty_string_p [form::get_action user_info]]] set form_mode display if { [exists_and_equal edit_p 1] } { set form_mode edit } ad_form -name user_info -cancel_url $return_url -action $action_url -mode $form_mode -form { {user_id:integer(hidden),optional} {return_url:text(hidden),optional} {message:text(hidden),optional} } # Fill the form elements list set elms_list [list] if { [llength [auth::authority::get_authority_options]] > 1 } { lappend elms_list { authority_id:text(select) {mode $elm_mode(authority_id)} {label "[_ acs-subsite.Authority]"} {options {[auth::authority::get_authority_options]}} } } else { lappend read_only_elements authority_id } if { $user(authority_id) != [auth::authority::local] || ![auth::UseEmailForLoginP] || \ ([acs_user::site_wide_admin_p] && [llength [auth::authority::get_authority_options]] > 1) } { lappend elms_list { username:text(text) {label "[_ acs-subsite.Username]"} {mode $elm_mode(username)} } } else { lappend read_only_elements username } # TODO: Use get_registration_form_elements, or auto-generate the form somehow? Deferred. lappend elms_list { first_names:text {label "[_ acs-subsite.First_names]"} {html {size 50}} {mode $elm_mode(first_names)} } { last_name:text {label "[_ acs-subsite.Last_name]"} {html {size 50}} {mode $elm_mode(last_name)} } { email:text {label "[_ acs-subsite.Email]"} {html {size 50}} {mode $elm_mode(email)} } if { [acs_user::ScreenName] ne "none" } { lappend elms_list [list screen_name:text[ad_decode [acs_user::ScreenName] "solicit" ",optional" ""] \ {label "[_ acs-subsite.Screen_name]"} \ {html {size 50}} \ {mode $elm_mode(screen_name)} \ ] } lappend elms_list { url:text,optional {label "[_ acs-subsite.Home_page]"} {html {size 50}} {mode $elm_mode(url)} } { bio:text(textarea),optional {label "[_ acs-subsite.Biography]"} {html {rows 8 cols 60}} {mode $elm_mode(bio)} {display_value {[ad_text_to_html -- $user(bio)]}} } set locale_options [list] db_foreach get_locales {} { if { [lang::message::message_exists_p $locale acs-lang.this-language] } { set label "[lang::message::lookup $locale acs-lang.this-language]" } lappend locale_options [list ${label} $locale] } if { [llength $locale_options] > 1 } { lappend elms_list { site_wide_locale:text(select_locales),optional {label "[_ acs-lang.Your_Preferred_Locale]"} {options $locale_options} } } lappend elms_list [list \ timezone:text(select),optional \ {label "[_ acs-lang.Your_timezone]"} \ [list options [db_list_of_lists get_timezones {}]]] # Setting focus on the first editable element of the form set first_element {} foreach elm $form_elms { if { $elm_mode($elm) eq "" && ( [lsearch $read_only_elements $elm] eq -1) } { set first_element $elm break } } set focus "user_info.$first_element" # ad_form -extend -name user_info -form $elms_list -on_request { foreach var { authority_id first_names last_name email username screen_name url bio } { set $var $user($var) } set site_wide_locale [ad_conn locale] set timezone [lang::user::timezone] if { $timezone eq "" } { set timezone [lang::system::timezone] } } -on_submit { # Makes the email an image or text according to the level of privacy catch {email_image::edit_email_image -user_id $user_id -new_email $email} errmsg set user_info(authority_id) $user(authority_id) set user_info(username) $user(username) foreach elm $form_elms { if { $elm_mode($elm) eq "" && [info exists $elm] } { set user_info($elm) [string trim [set $elm]] } } array set result [auth::update_local_account \ -authority_id $user(authority_id) \ -username $user(username) \ -array user_info] # Handle authentication problems switch $result(update_status) { ok { # Updating locale/tz data if { [info exists site_wide_locale] } { lang::user::set_locale $site_wide_locale } lang::user::set_timezone $timezone } default { # Adding the error to the first element, but only if there are no element messages if { [llength $result(element_messages)] == 0 } { form set_error user_info $first_element $result(update_message) } # Element messages foreach { elm_name elm_error } $result(element_messages) { form set_error user_info $elm_name $elm_error } break } } } -after_submit { if {[ad_conn account_status] eq "closed"} { auth::verify_account_status } ad_returnredirect $return_url ad_script_abort } # LARS HACK: Make the URL and email elements real links if { ![form is_valid user_info] } { element set_properties user_info email -display_value "[element get_value user_info email]" if {![string match -nocase "http://*" [element get_value user_info url]]} { element set_properties user_info url -display_value \ "[element get_value user_info url]" } else { element set_properties user_info url -display_value \ "[element get_value user_info url]" } } openacs-5.7.0/packages/acs-subsite/lib/user-info.xql0000644000175000017500000000061111320616746022202 0ustar frankiefrankie select tz || ' ' || gmt_offset as full_tz, tz from timezones order by tz select label, locale from enabled_locales order by label openacs-5.7.0/packages/acs-subsite/lib/user-new.adp0000644000175000017500000000005307735033350021777 0ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/lib/user-new.tcl0000644000175000017500000001520611525000555022014 0ustar frankiefrankie# Expects parameters: # # self_register_p - Is the form for users who self register (1) or # for administrators who create other users (0)? # next_url - Any url to redirect to after the form has been submitted. The # variables user_id, password, and account_messages will be added to the URL. Optional. # email - Prepopulate the register form with given email. Optional. # return_url - URL to redirect to after creation, will not get any query vars added # rel_group_id - The name of a group which you want to relate this user to after creating the user. # Will add an element to the form where the user can pick a relation among the permissible # rel-types for the group. # Check if user can self register auth::self_registration # Set default parameter values array set parameter_defaults { self_register_p 1 next_url {} return_url {} } foreach parameter [array names parameter_defaults] { if { ![exists_and_not_null $parameter] } { set $parameter $parameter_defaults($parameter) } } # Redirect to HTTPS if so configured if { [security::RestrictLoginToSSLP] } { security::require_secure_conn } # Log user out if currently logged in, if specified in the includeable chunk's parameters, # e.g. not when creating accounts for other users if { $self_register_p } { ad_user_logout } # Redirect to the registration assessment if there is one, if not, continue with the regular # registration form. set implName [parameter::get -parameter "RegistrationImplName" -package_id [subsite::main_site_id]] set callback_url [callback -catch -impl "$implName" user::registration] if { $callback_url ne "" } { ad_returnredirect [export_vars -base $callback_url { return_url }] ad_script_abort } # Pre-generate user_id for double-click protection set user_id [db_nextval acs_object_id_seq] ad_form -name register -export {next_url user_id return_url} -form [auth::get_registration_form_elements] -validate { {email {[string equal "" [party::get_by_email -email $email]]} "[_ acs-subsite.Email_already_exists]" } } if { [exists_and_not_null rel_group_id] } { ad_form -extend -name register -form { {rel_group_id:integer(hidden),optional} } if { [permission::permission_p -object_id $rel_group_id -privilege "admin"] } { ad_form -extend -name register -form { {rel_type:text(select) {label "Role"} {options {[group::get_rel_types_options -group_id $rel_group_id]}} } } } else { ad_form -extend -name register -form { {rel_type:text(hidden) {value "membership_rel"} } } } } ad_form -extend -name register -on_request { # Populate elements from local variables } -on_submit { db_transaction { array set creation_info [auth::create_user \ -user_id $user_id \ -verify_password_confirm \ -username $username \ -email $email \ -first_names $first_names \ -last_name $last_name \ -screen_name $screen_name \ -password $password \ -password_confirm $password_confirm \ -url $url \ -secret_question $secret_question \ -secret_answer $secret_answer] if { $creation_info(creation_status) eq "ok" && [exists_and_not_null rel_group_id] } { group::add_member \ -group_id $rel_group_id \ -user_id $user_id \ -rel_type $rel_type } } # Handle registration problems switch $creation_info(creation_status) { ok { # Continue below } default { # Adding the error to the first element, but only if there are no element messages if { [llength $creation_info(element_messages)] == 0 } { array set reg_elms [auth::get_registration_elements] set first_elm [lindex [concat $reg_elms(required) $reg_elms(optional)] 0] form set_error register $first_elm $creation_info(creation_message) } # Element messages foreach { elm_name elm_error } $creation_info(element_messages) { form set_error register $elm_name $elm_error } break } } switch $creation_info(account_status) { ok { # Continue below } default { # Display the message on a separate page ad_returnredirect \ -message $creation_info(account_message) \ -html \ [export_vars \ -base "[subsite::get_element \ -element url]register/account-closed"] ad_script_abort } } } -after_submit { if { $next_url ne "" } { # Add user_id and account_message to the URL ad_returnredirect [export_vars -base $next_url {user_id password {account_message $creation_info(account_message)}}] ad_script_abort } # User is registered and logged in if { ![exists_and_not_null return_url] } { # Redirect to subsite home page. set return_url [subsite::get_element -element url] } # If the user is self registering, then try to set the preferred # locale (assuming the user has set it as a anonymous visitor # before registering). if { $self_register_p } { # We need to explicitly get the cookie and not use # lang::user::locale, as we are now a registered user, # but one without a valid locale setting. set locale [ad_get_cookie "ad_locale"] if { $locale ne "" } { lang::user::set_locale $locale ad_set_cookie -replace t -max_age 0 "ad_locale" "" } } # Handle account_message if { $creation_info(account_message) ne "" && $self_register_p } { # Only do this if user is self-registering # as opposed to creating an account for someone else ad_returnredirect [export_vars -base "[subsite::get_element -element url]register/account-message" { { message $creation_info(account_message) } return_url }] ad_script_abort } else { # No messages ad_returnredirect $return_url ad_script_abort } } openacs-5.7.0/packages/acs-subsite/tcl/0000755000175000017500000000000011724401447017561 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/tcl/attribute-procs-postgresql.xql0000644000175000017500000000632307403013337025637 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_attributes a, acs_object_types t where t.dynamic_p = 't' and a.object_type = t.object_type and a.attribute_id = :value) then 1 else 0 end select case when exists (select 1 from acs_attributes a where (a.attribute_name = :attribute or a.column_name = :attribute) and a.object_type = :object_type) then 1 else 0 end select coalesce(a.column_name, a.attribute_name) as name, a.pretty_name, a.attribute_id, a.datatype, v.enum_value, v.pretty_name as value_pretty_name from acs_object_type_attributes a left outer join acs_enum_values v using (attribute_id), (select t.object_type, tree_level(t.tree_sortkey) - tree_level(t2.tree_sortkey) as type_level from acs_object_types t, acs_object_types t2 where t2.object_type = :start_with and t.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey)) t where a.object_type = :object_type and t.object_type = a.ancestor_type $storage_clause order by type_level, a.sort_order select * from ($package_object_view) dummy where object_id = :object_id select acs_attribute__drop_attribute(:object_type, :attribute_name) select acs_attribute__create_attribute ( '$object_type', '$attribute_name', '$datatype', '$pretty_name', '$pretty_plural', NULL, NULL, '$default_value', '$min_n_values', '$max_n_values', NULL, 'type_specific', 'f' ); alter table $table_name drop column $attribute_name alter table $table_name add $attribute_name $sql_type select acs_attribute__drop_attribute(:object_type, :attribute_name) alter table $table_name rename column $column_name to __DELETED__$column_name openacs-5.7.0/packages/acs-subsite/tcl/test/0000755000175000017500000000000011575225545020547 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/tcl/test/acs-subsite-procs.tcl0000644000175000017500000000630310745145620024614 0ustar frankiefrankiead_library { Automated tests. @author Joel Aufrecht @creation-date 2 Nov 2003 @cvs-id $Id: acs-subsite-procs.tcl,v 1.6 2008/01/21 16:42:56 donb Exp $ } aa_register_case acs_subsite_expose_bug_775 { Exposes Bug 775. @author Don Baccus } { aa_run_with_teardown \ -rollback \ -test_code { set group_id [group::new -group_name group_775] set rel_id [rel_segments_new $group_id membership_rel segment_775] relation_add membership_rel $group_id 0 permission::grant -object_id $group_id -party_id 0 -privilege read if { [catch {group::delete $group_id} errmsg] } { aa_error "Delete of group \"group_775\" failed." } else { aa_true "Delete of group \"group_775\" succeeded." 1 } } } aa_register_case acs_subsite_expose_bug_1144 { Exposes Bug 1144. @author Peter Marklund } { aa_run_with_teardown \ -rollback \ -test_code { array set main_node [site_node::get_from_url -url "/"] set main_group_id [application_group::group_id_from_package_id \ -package_id $main_node(package_id)] set email "__test@test.test" array set creation_info [auth::create_user \ -username "__test" \ -email $email \ -first_names "__Test first" \ -last_name "__Test last" \ -password 1 \ -password_confirm 1] group::add_member \ -group_id $main_group_id \ -user_id $creation_info(user_id) \ -rel_type admin_rel set cc_users_count [db_string count_cc_users { select count(*) from cc_users where email = :email }] aa_equals "New user occurs only once in cc_users" $cc_users_count 1 set registered_users_count [db_string count_registered_users { select count(*) from registered_users where email = :email }] aa_equals "New user occurs only once in registered_users" $registered_users_count 1 acs_user::delete -user_id $creation_info(user_id) } } aa_register_case -cats smoke acs_subsite_trivial_smoke_test { Minimal smoke test. } { aa_run_with_teardown \ -rollback \ -test_code { # initialize random values set name [ad_generate_random_string] set main_subsite_id [subsite::main_site_id] aa_true "Main subsite exists" [exists_and_not_null main_subsite_id] } } aa_register_case -cats smoke acs_subsite_unregistered_visitor { Test that unregistered visitor is not in any groups } { aa_equals "Unregistered vistior is not in any groups except The Public" \ [db_string count_rels " select count(*) from group_member_map g, acs_magic_objects a where g.member_id = 0 and g.group_id <> a.object_id and a.name = 'the_pubic'" -default 0] 0 } openacs-5.7.0/packages/acs-subsite/tcl/subsite-procs-oracle.xql0000644000175000017500000000440111332133300024334 0ustar frankiefrankie oracle8.1.6 BEGIN :1 := rel_constraint.new( constraint_name => :constraint_name, rel_segment => :segment_id, rel_side => 'two', required_rel_segment => rel_segment.get(:supersite_group_id, 'membership_rel'), creation_user => :user_id, creation_ip => :creation_ip ); END; select t.pretty_name as package_name, acs_object.name(s.object_id) as object_name from site_nodes s, apm_package_types t where s.node_id = :node_id and t.package_key = :package_key select case when exists (select 1 from acs_object_types where supertype = :object_type) then 1 else 0 end from dual select object_type from acs_object_types start with object_type = :object_type connect by object_type = prior supertype select pretty_name, package_key from apm_package_types where not (apm_package.singleton_p(package_key) = 1 and apm_package.num_instances(package_key) >= 1) and implements_subsite_p = 'f' and package_type = 'apm_application' order by upper(pretty_name) and rownum < 2 order by decode(host, :search_vhost, 1, 0) desc and rownum < 2 openacs-5.7.0/packages/acs-subsite/tcl/group-type-procs-oracle.xql0000644000175000017500000000315507332611400025005 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_objects o where acs_permission.permission_p(o.object_id, :user_id, 'delete') = 'f' and o.object_type = :group_type) then 0 else 1 end from dual begin acs_object_type.drop_type('$group_type'); end; BEGIN acs_object_type.create_type ( supertype => :supertype, object_type => :group_type, pretty_name => :pretty_name, pretty_plural => :pretty_plural, table_name => :table_name, id_column => :id_column, package_name => :package_name ); END; update acs_object_types set dynamic_p='t' where object_type = :group_type insert into group_type_rels (group_rel_type_id, rel_type, group_type) select acs_object_id_seq.nextval, r.rel_type, :group_type from group_type_rels r where r.group_type = :supertype openacs-5.7.0/packages/acs-subsite/tcl/subsite-procs-postgresql.xql0000644000175000017500000000441311332133300025275 0ustar frankiefrankie postgresql7.1 select rel_constraint__new( null, 'rel_constraint', :constraint_name, :segment_id, 'two', rel_segment__get(:supersite_group_id, 'membership_rel'), null, :user_id, :creation_ip ); select t.pretty_name as package_name, acs_object__name(s.object_id) as object_name from site_nodes s, apm_package_types t where s.node_id = :node_id and t.package_key = :package_key select case when exists (select 1 from acs_object_types where supertype = :object_type) then 1 else 0 end select t2.object_type from acs_object_types t1, acs_object_types t2 where t1.object_type = :object_type and t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) order by t2.tree_sortkey desc select pretty_name, package_key from apm_package_types where not (apm_package__singleton_p(package_key) = 1 and apm_package__num_instances(package_key) >= 1) and not implements_subsite_p and package_type = 'apm_application' order by upper(pretty_name) order by case when host = :search_vhost then 1 else 0 end desc limit 1 limit 1 openacs-5.7.0/packages/acs-subsite/tcl/rel-types-procs.tcl0000644000175000017500000002173411452447070023344 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/rel-types-procs.tcl ad_library { Procs about relationships @author mbryzek@arsdigita.com @creation-date Tue Dec 12 15:40:39 2000 @cvs-id $Id: rel-types-procs.tcl,v 1.10 2010/10/04 21:59:20 victorg Exp $ } ad_page_contract_filter rel_type_dynamic_p {name value} { Checks whether the value (assumed to be a string referring to a relationship type) is a dynamic object type. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/30/2000 } { if {[db_string rel_type_dynamic_p { select case when exists (select 1 from acs_object_types t where t.dynamic_p = 't' and t.object_type = :value) then 1 else 0 end from dual}]} { return 1 } ad_complain "Specific rel type either does not exist or is not dynamic and thus cannot be modified" return 0 } namespace eval rel_types { ad_proc -public additional_rel_types_p { {-group_id "" } {-group_type "" } } { Returns 1 if there is a relationship type not being used by the specified group_id or group_type. Useful for deciding when to offer the user a link to create a add a new permissible relationship type @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { if {$group_id ne ""} { return [additional_rel_types_group_p $group_id] } elseif {$group_type ne ""} { return [additional_rel_types_group_type_p $group_type] } else { error "rel_types::rel_types_p error: One of group_id or group_type must be specified" } } ad_proc -private additional_rel_types_group_p { group_id } { returns 1 if there is a rel type that is not defined as a segment for this group @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/30/2000 } { return [db_string "group_rel_type_exists" " select case when exists (select 1 from acs_object_types t where t.object_type not in (select g.rel_type from group_rels g where g.group_id = :group_id) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel','composition_rel')) then 1 else 0 end from dual"] } ad_proc -private additional_rel_types_group_type_p { group_type } { returns 1 if there is a rel type that is not defined as allowable for the specified group_type. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/30/2000 } { return [db_string "group_rel_type_exists" " select case when exists (select 1 from acs_object_types t where t.object_type not in (select g.rel_type from group_type_rels g where g.group_type = :group_type) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel','composition_rel')) then 1 else 0 end from dual"] } ad_proc -public new { {-supertype "relationship" } {-role_one "" } {-role_two "" } {-table_name ""} {-create_table_p "t"} rel_type pretty_name pretty_plural object_type_one min_n_rels_one max_n_rels_one object_type_two min_n_rels_two max_n_rels_two } { Creates a new relationship type named rel_type @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/30/2000 } { # use 29 chars to leave 1 character in the name for later dynamic # views set rel_type [plsql_utility::generate_oracle_name \ -max_length 29 $rel_type] if {[plsql_utility::object_type_exists_p $rel_type]} { error "Specified relationship type, $rel_type, already exists (or another object of the same type exists)\n" } if {![db_0or1row parent_rel_type { select table_name as references_table, id_column as references_column from acs_object_types where object_type=:supertype}]} { error "The specified supertype \"$supertype\" does not exist" } # use 29 chars to leave 1 character in the name for later dynamic # views if {$table_name eq ""} { set table_name [plsql_utility::generate_oracle_name \ -max_length 29 "${rel_type}_ext"] } set package_name $rel_type # We use rel_id for the primary key... since this is a relationship set pk_constraint_name [plsql_utility::generate_constraint_name $table_name rel_id "pk"] set fk_constraint_name [plsql_utility::generate_constraint_name $table_name rel_id "fk"] set plsql [list] # Create the actual acs object type lappend plsql_drop [list db_exec_plsql drop_type {FOO}] lappend plsql [list db_exec_plsql create_type {FOO}] # Mark the type as dynamic lappend plsql [list db_dml update_type {FOO}] # Force internationalisation of Roles # Internationalising of Attributes. This is done by storing the # attribute with it's acs-lang key set message_key "rel_type_${rel_type}" # Register the language keys lang::message::register en_US acs-translations $message_key $pretty_name lang::message::register en_US acs-translations "${message_key}_plural" $pretty_plural # Replace the pretty_name and pretty_plural with the message key, so # it is inserted correctly in the database set pretty_name "#acs-translations.${message_key}#" set pretty_plural "#acs-translations.${message_key}_plural#" foreach pair $plsql { eval [lindex $pair 0] [lindex $pair 1] [lindex $pair 2] } # The following create table statement commits the transaction. If it # fails, we roll back what we've done if {$create_table_p eq "t"} { if {[catch {db_exec_plsql create_table " create table $table_name ( rel_id constraint $fk_constraint_name references $references_table ($references_column) constraint $pk_constraint_name primary key )"} errmsg]} { # Roll back our work so for for {set i [expr {[llength $plsql_drop] - 1}]} {$i >= 0} {incr i -1} { set drop_pair [lindex $plsql_drop $i] if {[catch {eval [lindex $drop_pair 0] [lindex $drop_pair 1] [lindex $drop_pair 2]} err_msg_2]} { append errmsg "\nAdditional error while trying to roll back: $err_msg_2" return -code error $errmsg } } return -code error $errmsg } } # Finally, create the PL/SQL package. package_recreate_hierarchy $rel_type return $rel_type } ad_proc -public add_permissible { group_type rel_type } { Add a permissible relationship for a given group type } { if {[catch { set group_rel_type_id [db_nextval acs_object_id_seq] db_dml insert_rel_type {} } errmsg]} { } } ad_proc -public remove_permissible { group_type rel_type } { Add a permissible relationship for a given group type } { if {[catch { db_dml delete_rel_type {} } errmsg]} { } } ad_proc -public create_role { {-pretty_name:required} {-pretty_plural:required} {-role} } { Create a new Relationship Role @author Malte Sussdorff (sussdorff@sussdorff.de) @creation-date 2005-06-04 @param pretty_name @param pretty_plural @param role @return 1 if successful } { if {![exists_and_not_null role]} { set role [util_text_to_url \ -text $pretty_name \ -replacement "_" \ -existing_urls [db_list get_roles {}]] } set return_code 1 db_transaction { # Force internationalisation of Roles # Internationalising of Attributes. This is done by storing the # attribute with it's acs-lang key set message_key "role_${role}" # Register the language keys lang::message::register en_US acs-translations $message_key $pretty_name lang::message::register en_US acs-translations "${message_key}_plural" $pretty_plural # Replace the pretty_name and pretty_plural with the message key, so # it is inserted correctly in the database set pretty_name "#acs-translations.${message_key}#" set pretty_plural "#acs-translations.${message_key}_plural#" db_exec_plsql create_role {} } on_error { set return_code 0 } return $return_code } ad_proc -public delete_role { {-role} } { Drop a Relationship Role. @author Nick Carroll (nick.c@rroll.net) @creation-date 2005-11-18 @param role The role to delete. @return Returns 1 if successful, otherwise 0. } { set return_code 1 db_transaction { # Create the message key (refer to rel_types::create_role). # Required to unregister translations. set message_key "role_${role}" # Unegister the language keys lang::message::unregister acs-translations $message_key lang::message::unregister acs-translations "${message_key}_plural" db_exec_plsql drop_role {} } on_error { set return_code 0 } return $return_code } } openacs-5.7.0/packages/acs-subsite/tcl/rel-types-procs.xql0000644000175000017500000000173711452447070023367 0ustar frankiefrankie select table_name as references_table, id_column as references_column from acs_object_types where object_type=:supertype update acs_object_types set dynamic_p='t' where object_type = :rel_type insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (:group_rel_type_id, :group_type, :rel_type) delete from group_type_rels where group_type= :group_type and rel_type= :rel_type select role from acs_rel_roles openacs-5.7.0/packages/acs-subsite/tcl/rel-segments-procs-postgresql.xql0000644000175000017500000000133607661403715026251 0ustar frankiefrankie postgresql7.1 select rel_segment__new( null, 'rel_segment', now(), :creation_user, :creation_ip, null, null, :segment_name, :group_id, :rel_type, :context_id ) select rel_constraint__delete(:constraint_id) select rel_segment__delete(:segment_id) openacs-5.7.0/packages/acs-subsite/tcl/group-procs-postgresql.xql0000644000175000017500000000307010531357073024770 0ustar frankiefrankie postgresql7.1 DECLARE row record; BEGIN -- the acs_group package takes care of segments referred -- to by rel_constraints.rel_segment. We delete the ones -- references by rel_constraints.required_rel_segment here. for row in select cons.constraint_id from rel_constraints cons, rel_segments segs where segs.segment_id = cons.required_rel_segment and segs.group_id = :group_id loop perform rel_segment__delete(row.constraint_id); end loop; -- delete the actual group perform ${package_name}__delete(:group_id); return 1; END; select acs_group__member_p(:user_id,:group_id, :cascade) select role.pretty_name, gr.rel_type from group_rels gr, acs_rel_types rt, acs_rel_roles role where gr.group_id = :group_id and rt.rel_type = gr.rel_type and role.role = rt.role_two and rt.object_type_two = :object_type order by (case when gr.rel_type = 'membership_rel' then 0 else 1 end)||role.pretty_name openacs-5.7.0/packages/acs-subsite/tcl/application-group-procs.tcl0000644000175000017500000002563311256507453025063 0ustar frankiefrankie# /packages/subsite/tcl/application-group-procs.tcl ad_library { Procs to manage application groups @author oumi@arsdigita.com @creation-date 2001-02-01 @cvs-id $Id: application-group-procs.tcl,v 1.15 2009/09/23 21:12:11 donb Exp $ } namespace eval application_group {} ad_proc -public application_group::contains_party_p { { -package_id "" } { -party_id "" } -include_self:boolean } { Determines whether the party in question (identified by party_id) is a contained by the application group identified by package_id. If package_id is not specified, and we have a connection, then the proc will grab the package_id of the current package (i.e., [ad_conn package_id]). } { if {$package_id eq "" && [ad_conn isconnected]} { set package_id [ad_conn package_id] } if {$package_id eq ""} { error "application_group::contains_party_p - package_id not specified" } # Check if the party is a member of the application group, OR # the party *is* the application group. This proc considers the # applcation group to contain itself. if {$include_self_p} { set found_p [db_string app_group_contains_party_p { select case when exists ( select 1 from application_group_element_map where package_id = :package_id and element_id = :party_id union all select 1 from application_groups where package_id = :package_id and group_id = :party_id ) then 1 else 0 end from dual }] } else { set found_p [db_string app_group_contains_party_p { select case when exists ( select 1 from application_group_element_map where package_id = :package_id and element_id = :party_id ) then 1 else 0 end from dual }] } return $found_p } ad_proc -public application_group::contains_relation_p { { -package_id "" } { -rel_id "" } } { Determines whether the relation in question (identified by rel_id) is a contained by the application group identified by package_id. If package_id is not specified, and we have a connection, then the proc will grab the package_id of the current package (i.e., [ad_conn package_id]). } { if {$package_id eq "" && [ad_conn isconnected]} { set package_id [ad_conn package_id] } if {$package_id eq ""} { error "application_group::contains_party_p - package_id not specified" } # Check if the rel belongs to the application group, OR # the party *is* the application group. This proc considers the # application group to contain itself. set found_p [db_string app_group_contains_rel_p { select case when exists ( select 1 from application_group_element_map where package_id = :package_id and rel_id = :rel_id ) then 1 else 0 end from dual }] return $found_p } ad_proc -public application_group::contains_segment_p { { -package_id "" } { -segment_id "" } } { Determines whether the segment in question (identified by segment_id) "belongs" to the application group identified by package_id. If package_id is not specified, and we have a connection, then the proc will grab the package_id of the current package (i.e., [ad_conn package_id]). } { if {$package_id eq "" && [ad_conn isconnected]} { set package_id [ad_conn package_id] } if {$package_id eq ""} { error "application_group::contains_segment_p - package_id not specified" } # Check if the party is a member of the application group, OR # the party *is* the application group. This proc considers the # applcation group to contain itself. set found_p [db_string app_group_contains_segment_p { select case when exists ( select 1 from application_group_segments where package_id = :package_id and segment_id = :segment_id ) then 1 else 0 end from dual }] return $found_p } ad_proc -public application_group::group_id_from_package_id { -no_complain:boolean { -package_id "" } } { Get the application_group of a package. By default, if no application group exists, we throw an error. The -no_complain flag will prevent the error from being thrown, in which case you'll just get an empty string if the application group doesn't exist. } { if {$no_complain_p} { set no_complain_p t } else { set no_complain_p f } if { [ad_conn isconnected] } { if {$package_id eq ""} { set package_id [ad_conn package_id] } } if {$package_id eq ""} { error "application_group::group_id_from_package_id - no package_id specified." } set group_id [db_exec_plsql application_group_from_package_id_query { begin :1 := application_group.group_id_from_package_id ( package_id => :package_id, no_complain_p => :no_complain_p ); end; }] return $group_id } ad_proc -public application_group::package_id_from_group_id { -group_id:required } { Returns the package_id of a given application group. } { return [db_string -cache_key application_group_pid_from_gid_${group_id} get {}] } ad_proc -public application_group::new { { -group_id "" } { -group_type "application_group"} { -package_id "" } { -group_name "" } { -creation_user "" } { -creation_ip "" } { -email "" } { -url "" } } { Creates an application group (i.e., group of "users/parties of this application") Returns the group_id of the new application group. } { if { [ad_conn isconnected] } { # Since we have a connection, default user_id / peeraddr # if they're not specified if { $creation_user eq "" } { set creation_user [ad_conn user_id] } if { $creation_ip eq "" } { set creation_ip [ad_conn peeraddr] } if { $package_id eq "" } { set package_id [ad_conn package_id] } } if {$package_id eq ""} { error "application_group::new - package_id not specified" } if {$group_name eq ""} { set group_name [db_string group_name_query { select substr(instance_name, 1, 90) from apm_packages where package_id = :package_id }] append group_name " Parties" } db_transaction { # creating the new group set group_id [db_exec_plsql add_group {}] } return $group_id } ad_proc -public application_group::delete { -group_id:required } { Delete the given application group and all relational segments and constraints dependent on it (handled by the PL/[pg]SQL API } { # LARS HACK: # Delete permissions on: # - the application group # - any relational segment of this group # - any relation with this gorup # We really ought to have cascading deletes on acs_permissions.grantee_id (and object_id) db_dml delete_perms {} db_exec_plsql delete {} db_flush_cache -cache_key_pattern application_group_* } ad_proc -public application_group::closest_ancestor_application_group_site_node { {-url ""} {-node_id ""} {-include_self:boolean} } { Starting with the node at with given id, or at given url, climb up the site map and return the node of the first non null application group @param url The url of the node to start from. You must provide either url or node_id. An empty url is taken to mean the main site. @param node_id The id of the node to start from. Takes precedence over any provided url. @param include_self If true, include the current package in the search @return The node of the first non-null application group in array get format. @author Peter Marklund, Dave Bauer } { # Make sure we have a url to work with if { [empty_string_p $url] } { if { [empty_string_p $node_id] } { set url "/" } else { set url [site_node::get_url -node_id $node_id] } } set group_id "" while {$group_id eq "" && $url ne ""} { if { $include_self_p } { array set node_array [site_node::get -url $url] set group_id [application_group::group_id_from_package_id \ -package_id $node_array(package_id) \ -no_complain] } set include_self_p 1 # move up a level set url [string trimright $url /] set url [string range $url 0 [string last / $url]] } if {$group_id eq ""} { array unset -no_complain node_array } set node_array(application_group_id) $group_id return [array get node_array] } ad_proc -public application_group::closest_ancestor_element { {-node_id ""} {-url ""} {-element:required} {-include_self:boolean} } { Return one element of the site node for the closest ancestor package that has an application group. @param url url of the node to start searching from. @param node_id node_id of the node to start searching from (only one of node_id and url can be specified). @param include_self If true, include the current package in the search @return element The desired element of the appropriate site node. } { array set site_node \ [application_group::closest_ancestor_application_group_site_node \ -include_self=$include_self_p \ -url $url \ -node_id $node_id] return $site_node($element) } ad_proc -public application_group::closest_ancestor_application_group_id { {-url ""} {-node_id ""} {-include_self:boolean} } { Application group id of the closest ancestor package that has an application group @param url url of the node to start searching from. @param node_id node_id of the node to start searching from (only one of node_id and url can be specified). @param include_self If true, include the current package in the search @return group_id of the closest ancestor package that has an application group, if any. } { return [application_group::closest_ancestor_element \ -include_self=$include_self_p \ -url $url \ -node_id $node_id \ -element application_group_id] } ad_proc -public application_group::child_application_groups { -node_id:required {-package_key ""} } { } { set group_list [list] set child_packages [site_node::get_children -package_key $package_key -node_id $node_id -element package_id] foreach package_id $child_packages { if {[set group_id [application_group::group_id_from_package_id -package_id ${package_id} -no_complain]] ne ""} { lappend group_list $group_id } } return $group_list } openacs-5.7.0/packages/acs-subsite/tcl/application-group-procs.xql0000644000175000017500000000157111153321272025065 0ustar frankiefrankie select package_id from application_groups where group_id = :group_id select substr(instance_name, 1, 90) from apm_packages where package_id = :package_id delete from acs_permissions where grantee_id = :group_id or grantee_id in (select segment_id from rel_segments where group_id = :group_id) or grantee_id in (select rel_id from acs_rels where object_id_one = :group_id or object_id_two = :group_id) openacs-5.7.0/packages/acs-subsite/tcl/relation-procs-postgresql.xql0000644000175000017500000000371207403013337025450 0ustar frankiefrankie postgresql7.1 select rel_constraint__violation(:rel_id) begin perform ${package_name}__delete(:rel_id); return null; end; select case when exists (select 1 from rc_violations_by_removing_rel r where r.rel_id = :rel_id) then 1 else 0 end select case when exists (select 1 from rc_valid_rel_types r where r.group_id = :group_id and r.rel_type = :rel_type) then 1 else 0 end select pretty_name, object_type, level, indent, case when valid_types.rel_type = null then 0 else 1 end as valid_p from (select t2.pretty_name, t2.object_type, tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey) as level, repeat(' ', (tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4) as indent, t2.tree_sortkey as sortkey from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type = :start_with) types left join (select rel_type from rc_valid_rel_types where group_id= :group_id) valid_types on (types.object_type = valid_types.rel_type) order by sortkey openacs-5.7.0/packages/acs-subsite/tcl/package-procs-postgresql.xql0000644000175000017500000002025011253303101025207 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_object_types t where t.dynamic_p = 't' and t.object_type = :object_type) then 1 else 0 end select upper(coalesce(attr.table_name,t.table_name)) as attr_table_name, upper(coalesce(attr.column_name, attr.attribute_name)) as attr_column_name, attr.ancestor_type, attr.min_n_values, attr.default_value from acs_object_type_attributes attr, (select t2.object_type, t2.table_name, (tree_level(t1.tree_sortkey) - tree_level(t2.tree_sortkey)) + 1 as type_level from acs_object_types t1, acs_object_types t2 where t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t1.object_type = :object_type) t where attr.ancestor_type = t.object_type and attr.object_type = :object_type order by t.type_level select t2.object_type from acs_object_types t1, acs_object_types t2 where t2.dynamic_p = 't' and t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type = :object_type select case when exists (select 1 from user_objects where status = 'INVALID' and object_name = upper(:package_name) and object_type = upper(:type)) then 0 else 1 end select t2.object_type as ancestor_type from acs_object_types t1, acs_object_types t2 where t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t1.object_type = :object_type select t2.object_type as sub_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type = :object_type select acs_object__name(:user_id) as author, current_timestamp as creation_date select acs_object__name(:user_id) as author, current_timestamp as creation_date select a.attribute_id, coalesce(a.table_name, t.table_name) as table_name, coalesce(a.column_name, a.attribute_name) as attribute_name, a.pretty_name, a.datatype, case when a.min_n_values = 0 then 'f' else 't' end as required_p, a.default_value, t.table_name as object_type_table_name, t.id_column as object_type_id_column from acs_object_type_attributes a, (select t.object_type, t.table_name, t.id_column, tree_level(t.tree_sortkey) as type_level from acs_object_types t, acs_object_types t2 where t.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t2.object_type = :start_with) t where a.object_type = :object_type and t.object_type = a.ancestor_type $storage_clause order by type_level, attribute_id select cols.table_name, cols.column_name from user_tab_columns cols, (select upper(t2.table_name) as table_name from acs_object_types t1, acs_object_types t2 where t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t1.object_type = :object_type) t where cols.column_name in (select args.arg_name from acs_function_args args where args.function = upper(:package_name) || '__' || upper(:object_name)) and cols.table_name = t.table_name select args.arg_name from acs_function_args args where args.function = upper(:package_name) || '__' || upper(:object_name) select 1 select 1 select ${package_name}__new([plpgsql_utility::generate_attribute_parameter_call \ -prepend ":" \ ${package_name}__new \ $pieces]) select args.arg_name from acs_function_args args where args.function =upper(:supertype_package_name) || '__NEW' begin perform drop_package('${package_name}'); perform define_function_args('${package_name}__new','[plpgsql_utility::define_function_args $attribute_list]'); create function ${package_name}__new([plpgsql_utility::generate_function_signature $attribute_list]) returns [plpgsql_utility::table_column_type ${table_name} ${id_column}] as ' declare [plpgsql_utility::generate_attribute_parameters $attribute_list]; v_$id_column ${table_name}.${id_column}%TYPE; begin v_$id_column := ${supertype_package_name}__new ( [plpgsql_utility::generate_attribute_parameter_call_from_attributes \ -prepend "p_" \ "${supertype_package_name}__new" \ $supertype_attr_list] ); insert into ${table_name} ($id_column[plsql_utility::generate_attribute_dml -ignore [list $id_column] $table_name $attribute_list]) values (v_$id_column[plsql_utility::generate_attribute_dml -prepend "p_" -ignore [list $id_column] $table_name $attribute_list]); return v_$id_column; end;' language 'plpgsql'; create function ${package_name}__delete ([plpgsql_utility::table_column_type ${table_name} ${id_column}]) returns integer as ' declare p_${id_column} alias for [plpgsql_utility::dollar]1; begin perform ${supertype_package_name}__delete( p_${id_column} ); return 1; end;' language 'plpgsql'; return null; end; select 1; now() now() select 1 from dual select ${__package_name}__${__object_name}([plpgsql_utility::generate_attribute_parameter_call \ -prepend ":" \ ${__package_name}__${__object_name} \ $pieces]) openacs-5.7.0/packages/acs-subsite/tcl/subsite-navigation-procs.tcl0000644000175000017500000002325511062067631025231 0ustar frankiefrankie# /packages/subsite/tcl/subsite-procs.tcl ad_library { Procs to manage the default template's navigation multirow. @author Don Baccus (dhogaza@pacifier.com) @creation-date 2008-04-26 @cvs-id $Id: subsite-navigation-procs.tcl,v 1.3 2008/09/11 01:08:41 donb Exp $ } namespace eval subsite_navigation { } ad_proc -public subsite_navigation::define_pageflow { {-subsite_id ""} {-show_applications_p 1} {-no_tab_application_list ""} {-initial_pageflow ""} {-navigation_multirow navigation} {-group main} {-subgroup sub} } { Defines the page flow of the subsite. This sets up a navigation multirow as defined by the default master installed by openacs, which renders it as one or more rows of tabs. The standard CSS defines classes for two rows of tabs, if you want more, you must define your own CSS classes. If the navigation multirow doesn't exist, we create it. @param subsite_id The package id of the subsite we're interested in (defaults to current) @param show_applications_p If true, autogenerate tabs for applications (not declared boolean because the tabbed master takes this from a package parameter) @param no_tab_application_list A list of application package keys to ignore when autogenerating tabs for applications @param initial_pageflow Add these subsections before computing the rest of the page flow @param navigation_multirow The name of the multirow used to build the nav bars @param group Group name for the primary section @param subgroup Group name for the subsection (opened under a selected tab) } { if { $subsite_id eq "" } { set subsite_id [ad_conn subsite_id] } set pageflow [subsite_navigation::get_pageflow_struct \ -subsite_id $subsite_id \ -initial_pageflow $initial_pageflow \ -show_applications_p $show_applications_p \ -no_tab_application_list $no_tab_application_list] set base_url [subsite::get_element -subsite_id $subsite_id -element url] if { ![template::multirow exists $navigation_multirow] } { template::multirow create $navigation_multirow group label href target \ title lang accesskey class id tabindex } foreach { section_name section_spec } $pageflow { array set section_a { label {} url {} title {} subsections {} folder {} selected_patterns {} accesskey {} } array set section_a $section_spec set section_a(name) $section_name set selected_p [add_section_row \ -subsite_id $subsite_id \ -array section_a \ -base_url $base_url \ -group $group \ -multirow $navigation_multirow] if { $selected_p } { foreach { subsection_name subsection_spec } $section_a(subsections) { array set subsection_a { label {} title {} folder {} url {} selected_patterns {} accesskey {} } array set subsection_a $subsection_spec set subsection_a(name) $subsection_name set subsection_a(folder) [file join $section_a(folder) $subsection_a(folder)] add_section_row \ -subsite_id $subsite_id \ -array subsection_a \ -base_url $base_url \ -group $subgroup \ -multirow $navigation_multirow } } } } ad_proc -public subsite_navigation::add_section_row { {-subsite_id ""} {-array:required} {-base_url:required} {-multirow:required} {-group:required} {-section {}} } { Helper proc for adding rows of sections to the page flow of the subsite. @see subsite_navigation::define_pageflow } { upvar $array info # the folder index page is called . if { $info(url) eq "" || $info(url) eq "index" || \ [string match "*/" $info(url)] || [string match "*/index" $info(url)] } { set info(url) "[string range $info(url) 0 [string last / $info(url)]]." } if { [ad_conn node_id] == [site_node::closest_ancestor_package -include_self \ -node_id [site_node::get_node_id_from_object_id -object_id $subsite_id] \ -package_key [subsite::package_keys] \ -url [ad_conn url]] } { set current_url [ad_conn extra_url] } else { # Need to prepend the path from the subsite to this package set current_url [string range [ad_conn url] [string length $base_url] end] } set info(url) [file join $info(folder) $info(url)] regsub {\.$} $info(url) "" info(url) # Default to not selected set selected_p 0 set info(tabindex) [template::multirow size $multirow] if { $info(accesskey) eq "" } { set info(accesskey) $info(tabindex) } if { $current_url eq $info(url) || $info(name) eq $section } { set selected_p 1 } else { foreach pattern $info(selected_patterns) { set full_pattern [file join $info(folder) $pattern] if { [string match $full_pattern $current_url] } { set selected_p 1 break } } } # DRB: Expr thinks "-" is a subtraction operator thus this caveman if... if { $selected_p } { set navigation_id ${group}-navigation-active } else { set navigation_id "" } template::multirow append $multirow $group $info(label) [file join $base_url $info(url)] \ "" $info(title) "" $info(accesskey) "" $navigation_id [template::multirow size $multirow] return $selected_p } ad_proc -public subsite_navigation::get_section_info { {-array "section_info"} {-navigation_multirow "navigation"} } { Takes the navigation_multirow and sets the passed array name with the elements label and url of the selected section. } { upvar $array row # Find the label of the selected section array set row { label {} url {} } template::multirow foreach $navigation_multirow { if { [template::util::is_true $selected_p] } { set row(label) $label set row(url) $url break } } } ad_proc -public subsite_navigation::get_pageflow_struct { {-subsite_id ""} {-initial_pageflow ""} {-show_applications_p 1} {-no_tab_application_list ""} } { Defines the page flow structure. @param subsite_id The package id of the subsite we're interested in (defaults to current) @param initial_pageflow Add these subsections before computing the rest of the page flow @param show_applications_p If true, autogenerate tabs for applications (not declared boolean because the tabbed master takes this from a package parameter) @param no_tab_application_list A list of application package keys to ignore when autogenerating tabs for applications } { set pageflow $initial_pageflow set subsite_node_id [site_node::get_node_id_from_object_id -object_id $subsite_id] set subsite_url [site_node::get_element -node_id $subsite_node_id -element url] set user_id [ad_conn user_id] set admin_p [permission::permission_p \ -object_id [site_node::closest_ancestor_package -include_self \ -node_id $subsite_node_id \ -package_key [subsite::package_keys] \ -url [ad_conn url]] \ -privilege admin \ -party_id [ad_conn untrusted_user_id]] set show_member_list_to [parameter::get -parameter "ShowMembersListTo" -package_id $subsite_id -default 2] if { $admin_p || ($user_id != 0 && $show_member_list_to == 1) || \ $show_member_list_to == 0 } { set pageflow [concat $pageflow [parameter::get -package_id [ad_conn subsite_id] \ -parameter MembersViewNavbarTabsList -default ""]] } set index_redirect_url [parameter::get -parameter "IndexRedirectUrl" -package_id $subsite_id] set index_internal_redirect_url [parameter::get -parameter "IndexInternalRedirectUrl" -package_id $subsite_id] regsub {(.*)/packages} $index_internal_redirect_url "" index_internal_redirect_url regexp {(/[-[:alnum:]]+/)(.*)$} $index_internal_redirect_url dummy index_internal_redirect_url set child_urls [lsort -ascii [site_node::get_children -node_id $subsite_node_id -package_type apm_application]] if { $show_applications_p } { foreach child_url $child_urls { array set child_node [site_node::get_from_url -exact -url $child_url] if { $child_url ne $index_redirect_url && $child_url ne $index_internal_redirect_url && [lsearch -exact $no_tab_application_list $child_node(package_key)] == -1 } { lappend pageflow $child_node(name) [list \ label $child_node(instance_name) \ folder $child_node(name) \ url {} \ selected_patterns *] } } } if { $admin_p } { set pageflow [concat $pageflow [parameter::get -package_id [ad_conn subsite_id] \ -parameter AdminNavbarTabsList -default ""]] } return $pageflow } openacs-5.7.0/packages/acs-subsite/tcl/attribute-procs.tcl0000644000175000017500000004547710674222123023430 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/attribute-procs.tcl ad_library { Procs to help with attributes for object types @author mbryzek@arsdigita.com @creation-date Thu Dec 7 10:30:57 2000 @cvs-id $Id: attribute-procs.tcl,v 1.10 2007/09/19 13:29:55 gustafn Exp $ } ad_page_contract_filter attribute_dynamic_p { name value } { Checks whether the value (assumed to be an integer) is an attribute of a dynamic type. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/30/2000 } { if { [db_string attribute_for_dynamic_object_p { select case when exists (select 1 from acs_attributes a, acs_object_types t where t.dynamic_p = 't' and a.object_type = t.object_type and a.attribute_id = :value) then 1 else 0 end from dual }] } { return 1 } ad_complain "Attribute does not belong to a dynamic object and cannot be modified" return 0 } namespace eval attribute { ad_proc -public exists_p { { -convert_p "t" } object_type orig_attribute } { Returns 1 if the object type already has an attribute of the given name. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param convert_p If t, we convert the attribute using plsql_utility::generate_oracle_name @param orig_attribute The attribute in which we are interested. Note that if convert_p is set to t, we will internally look for the converted attribute name @return 1 if the object type already has an attribute of the specified name. 0 otherwise } { if { $convert_p eq "t" } { set attribute [plsql_utility::generate_oracle_name $orig_attribute] } else { set attribute $orig_attribute } set attr_exists_p [db_string attr_exists_p { select 1 from acs_attributes a where (a.attribute_name = :attribute or a.column_name = :attribute) and a.object_type = :object_type } -default 0] if { $attr_exists_p || $convert_p eq "f" } { # If the attribute exists, o return $attr_exists_p } return [exists_p -convert_p f $object_type $orig_attribute] } ad_proc -public add { { -default "" } { -min_n_values "" } { -max_n_values "" } object_type datatype pretty_name pretty_plural } { wrapper for the acs_attribute.create_attribute call. Note that this procedure assumes type-specific storage. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @return The attribute_id of the newly created attribute } { set default_value $default # We always use type-specific storage. Grab the tablename from the # object_type if { ![db_0or1row select_table { select t.table_name from acs_object_types t where t.object_type = :object_type }] } { error "Specified object type \"$object_type\" does not exist" } # In OpenACS, where we care that SQL must be separate from code, we don't # use these annoying formatting procs on our SQL. We write out the queries in full. (ben) # Attribute name returned from this function will be oracle # friendly and is thus used as the column name set attribute_name [plsql_utility::generate_oracle_name $pretty_name] # set attr_list [list] # lappend attr_list [list "object_type" '$object_type'] # lappend attr_list [list "attribute_name" '$attribute_name'] # lappend attr_list [list "min_n_values" '$min_n_values'] # lappend attr_list [list "max_n_values" '$max_n_values'] # lappend attr_list [list "default_value" '$default'] # lappend attr_list [list "datatype" '$datatype'] # lappend attr_list [list "pretty_name" '$pretty_name'] # lappend attr_list [list "pretty_plural" '$pretty_plural'] # A note (by ben, OpenACS) # the queries are empty because they are pulled out later in db_exec_plsql set plsql [list] lappend plsql_drop [list "drop_attribute" "FOO" db_exec_plsql] lappend plsql [list "create_attribute" "FOO" db_exec_plsql] set sql_type [datatype_to_sql_type -default $default_value $table_name $attribute_name $datatype] lappend plsql_drop [list "drop_attr_column" "FOO" db_dml] lappend plsql [list "add_column" "FOO" db_dml] for { set i 0 } { $i < [llength $plsql] } { incr i } { set pair [lindex $plsql $i] if { [catch {eval [lindex $pair 2] [lindex $pair 0] [lindex $pair 1]} err_msg] } { # Rollback what we've done so far. The loop contitionals are: # start at the end of the plsql_drop list (Drop things in reverse order of creation) # execute drop statements until we reach position $i+1 # This position represents the operation on which we failed, and thus # is not executed for { set inner [expr {[llength $plsql_drop] - 1}] } { $inner > [expr {$i + 1}] } { set inner [expr {$inner - 1}] } { set drop_pair [lindex $plsql_drop $inner] if { [catch {eval [lindex $drop_pair 2] [lindex $drop_pair 0] [lindex $drop_pair 1]} err_msg_2] } { append err_msg "\nAdditional error while trying to roll back: $err_msg_2" return -code error $err_msg } } return -code error $err_msg } } return [db_string select_attribute_id { select a.attribute_id from acs_attributes a where a.object_type = :object_type and a.attribute_name = :attribute_name }] } ad_proc -private datatype_to_sql_type { { -default "" } table column datatype } { Returns the appropriate sql type for a table definitation based on the table, column, datatype, and default value. Note that for default values, this proc automatically generates appropriate constraint names as well. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param default If specified, we add a default clause to the sql statement } { set type "" set constraint "" switch $datatype { "string" { set type "varchar(1000)" } "boolean" { set type "char(1)" set constraint "[plsql_utility::generate_constraint_name $table $column "ck"] check ($column in ('t','f'))" } "number" { set type "number" } "money" { set type "number (12,2)" } "date" { set type "date" } "text" { set type "varchar(4000)" } "integer" { set type "integer" } "enumeration" { set type "varchar(100)" } "keyword" { set type "varchar(1000)" } default {error "Unsupported datatype. Datatype $datatype is not implemented at this time"} } set sql "$type" if { $default ne "" } { # This is also pretty nasty - we have to make sure we # treat db literals appropriately - null is much different # than 'null' - mbryzek set vars [list null sysdate] if { [lsearch -exact $vars [string tolower $default]] == -1 } { set default "'$default'" } append sql " default $default" } if { $constraint ne "" } { append sql " constraint $constraint" } return $sql } ad_proc -public delete { attribute_id } { Delete the specified attribute id and all its values. This is irreversible. Returns 1 if the attribute was actually deleted. 0 otherwise. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { # 1. Drop the column # 2. Drop the attribute # 3. Return if { ![db_0or1row select_attr_info { select a.object_type, a.attribute_name, decode(a.storage,'type_specific',t.table_name,a.table_name) as table_name, nvl(a.column_name, a.attribute_name) as column_name from acs_attributes a, acs_object_types t where a.attribute_id = :attribute_id and t.object_type = a.object_type }] } { # Attribute doesn't exist return 0 } if { $table_name eq "" || $column_name eq "" } { # We have to have both a non-empty table name and column name error "We do not have enough information to automatically remove this attribute. Namely, we are missing either the table name or the column name" } set plsql [list] lappend plsql [list "drop_attribute" "FOO" "db_exec_plsql"] if { [db_column_exists $table_name $column_name] } { lappend plsql [list "drop_attr_column" "FOO" "db_dml"] } foreach pair $plsql { eval [lindex $pair 2] [lindex $pair 0] [lindex $pair 1] } return 1 } ad_proc -public value_add {attribute_id enum_value sort_order} { adds the specified enumeration value to the attribute. @author Ben Adida (ben@openforce.net) @creation-date 08/2001 @param attribute_id The attribute to which we are adding @param enum_value The value which we are adding to the enum } { # Just insert it if we can db_dml insert_enum_value { insert into acs_enum_values (attribute_id, sort_order, enum_value, pretty_name) select :attribute_id, :sort_order, :enum_value, :enum_value from dual where not exists (select 1 from acs_enum_values v2 where v2.pretty_name = :enum_value and v2.attribute_id = :attribute_id) } } ad_proc -public value_delete { attribute_id enum_value } { deletes the specified enumeration value from the attribute. The net effect is that this attribute will have one fewer options for acceptable values. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param attribute_id The attribute from which we are deleting @param enum_value The value of we are deleting } { # This function should remove all occurrences of the # attribute, but we don't do that now. if { ![db_0or1row select_last_sort_order { select v.sort_order as old_sort_order from acs_enum_values v where v.attribute_id = :attribute_id and v.enum_value = :enum_value }] } { # nothing to delete return } db_dml delete_enum_value { delete from acs_enum_values v where v.attribute_id = :attribute_id and v.enum_value = :enum_value } if { [db_resultrows] > 0 } { # update the sort order db_dml update_sort_order { update acs_enum_values v set v.sort_order = v.sort_order - 1 where v.attribute_id = :attribute_id and v.sort_order > :old_sort_order } } return } ad_proc -public translate_datatype { datatype } { translates the datatype into one that can be validated. Default datatype is text (when no validator is found) @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { if { [datatype_validator_exists_p $datatype] } { return $datatype } switch -- $datatype { boolean { set datatype "text" } keyword { set datatype "text" } money { set datatype "integer" } number { set datatype "integer" } string { set datatype "text" } } if { [datatype_validator_exists_p $datatype] } { return $datatype } # No validator exists... return text as default return "text" } ad_proc -public datatype_validator_exists_p { datatype } { Returns 1 if we have a validator for this datatype. 0 otherwise. We currently do not support the "date" datatype and hardcoded support for enumeration. This is hardcoded in this procedure. Also, this procedure assumes that validators are procedures named ::template::data::validate::$datatype @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { if {$datatype eq "date"} { return 0 } if {$datatype eq "enumeration"} { return 1 } if { [empty_string_p [info procs "::template::data::validate::$datatype"]] } { return 0 } return 1 } ad_proc -public array_for_type { { -start_with "acs_object" } { -include_storage_types {type_specific} } array_name enum_array_name object_type } { Fills in 2 arrays used for displaying attributes @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 1/8/2001 @param array_name The name of the array to hold the basic attribute information. The attributes defined are: * array_name(pretty_name:$name) The pretty_name of the attribute * array_name(id:$name) The attribute_id of the attribute * array_name(datatype:$name) The datatype of the attribute @param enum_array_name The name of the array to hold the pretty name of the values of an enumeration. This is only used when the datatype of the attribute_name is enumeration. This array is a mapping from "$attribute_name:enum_value" to value_pretty_name. @param object_type The object for which we are looking up attributes @return A list of all the names of attributes we looked up. This list can be used to iterated through the arrays:
            set attr_list [attribute::array_for_type attr_props enum_values "group"]
    	foreach key $attr_list {
    	    set attribute_id $attr_props(id:$attribute_name)
    	    ...
            }    
        
    } { upvar $array_name attr_props upvar $enum_array_name enum_values set attr_list [list] set storage_clause "" if {$include_storage_types ne ""} { set storage_clause " and a.storage in ('[join $include_storage_types "', '"]')" } db_foreach select_attributes " select nvl(a.column_name, a.attribute_name) as name, a.pretty_name, a.attribute_id, a.datatype, v.enum_value, v.pretty_name as value_pretty_name from acs_object_type_attributes a, acs_enum_values v, (select t.object_type, level as type_level from acs_object_types t start with t.object_type = :start_with connect by prior t.object_type = t.supertype) t where a.object_type = :object_type and a.attribute_id = v.attribute_id(+) and t.object_type = a.ancestor_type $storage_clause order by type_level, a.sort_order " { # Enumeration values show up more than once... if { [lsearch -exact $attr_list $name] == -1 } { lappend attr_list $name set attr_props(pretty_name:$name) $pretty_name set attr_props(datatype:$name) $datatype set attr_props(id:$name) $attribute_id } if {$datatype eq "enumeration"} { set enum_values($name:$enum_value) $value_pretty_name } } return $attr_list } ad_proc -public multirow { { -start_with "acs_object" } { -include_storage_types {type_specific} } { -datasource_name "attributes" } { -object_type "" } { -return_url "" } object_id } { Sets up a multirow datasource containing the attribute values of object_id. We only support specific storage attributes. We include all attributes of the object's type, or any of its supertypes, up to $start_with. } { upvar $datasource_name attributes if {$object_type eq ""} { set object_type [db_string object_type_query { select object_type from acs_objects where object_id = :object_id }] } if {$return_url eq ""} { set return_url "[ad_conn url]?[ad_conn query]" } # Build up the list of attributes for the type specific lookup set attr_list [attribute::array_for_type \ -start_with $start_with \ -include_storage_types $include_storage_types \ attr_props enum_values $object_type] # Build up a multirow datasource to present these attributes to the user template::multirow create $datasource_name pretty_name value export_vars set package_object_view [package_object_view \ -start_with "acs_object" \ $object_type] if { [array size attr_props] > 0 } { db_foreach attribute_select " select * from ($package_object_view) where object_id = :object_id " { foreach key $attr_list { set col_value [set $key] set attribute_id $attr_props(id:$key) if { $attr_props(datatype:$key) eq "enumeration" && [info exists enum_values($key:$col_value)] } { # Replace the value stored in the column with the # pretty name for that attribute set col_value $enum_values($key:$col_value) } template::multirow append $datasource_name $attr_props(pretty_name:$key) $col_value "id_column=$object_id&[ad_export_vars {attribute_id return_url}]" } } } } ad_proc -public add_form_elements { { -form_id "" } { -start_with "acs_object" } { -object_type "acs_object" } { -variable_prefix "" } } { Adds form elements to the specified form_id. Each form element corresponds to an attribute belonging to the given object_type. @param form_id ID of a form to add form elements to. @param start_with Object type to start with. Defaults to acs_object. @param object_type Object type to extract attributes for. Defaults to acs_object. @param variable_prefix Variable prefix. } { if {$form_id eq ""} { error "attribute::add_form_elements - form_id not specified" } if {$object_type eq ""} { error "attribute::add_form_elements - object type not specified" } if {$variable_prefix ne ""} { append variable_prefix "." } # pull out all the attributes up the hierarchy from this object_type # to the $start_with object type set attr_list_of_lists [package_object_attribute_list -start_with $start_with $object_type] foreach row $attr_list_of_lists { set attribute_id [lindex $row 0] set attribute_name [lindex $row 2] set pretty_name [lindex $row 3] # Might translate the datatype into one for which we have a # validator (e.g. a string datatype would change into text). set datatype [translate_datatype [lindex $row 4]] set required_p [lindex $row 5] set default [lindex $row 6] if {$datatype eq "enumeration"} { # For enumerations, we generate a select box of all the possible values set option_list [db_list_of_lists select_enum_values { select enum.pretty_name, enum.enum_value from acs_enum_values enum where enum.attribute_id = :attribute_id order by enum.sort_order }] if {$required_p eq "f"} { # This is not a required option list... offer a default lappend option_list [list " (no value) " ""] } template::element create $form_id "$variable_prefix$attribute_name" \ -datatype "text" [ad_decode $required_p "f" "-optional" ""] \ -widget select \ -options $option_list \ -label "$pretty_name" \ -value $default } else { template::element create $form_id "$variable_prefix$attribute_name" \ -datatype $datatype [ad_decode $required_p "f" "-optional" ""] \ -widget text \ -label $pretty_name \ -value $default } } } } openacs-5.7.0/packages/acs-subsite/tcl/attribute-procs.xql0000644000175000017500000000566407340116360023445 0ustar frankiefrankie select t.table_name from acs_object_types t where t.object_type = :object_type select a.attribute_id from acs_attributes a where a.object_type = :object_type and a.attribute_name = :attribute_name select a.object_type, a.attribute_name, case when a.storage = 'type_specific' then t.table_name else a.table_name end as table_name, coalesce(a.column_name, a.attribute_name) as column_name from acs_attributes a, acs_object_types t where a.attribute_id = :attribute_id and t.object_type = a.object_type select v.sort_order as old_sort_order from acs_enum_values v where v.attribute_id = :attribute_id and v.enum_value = :enum_value delete from acs_enum_values v where v.attribute_id = :attribute_id and v.enum_value = :enum_value update acs_enum_values v set v.sort_order = v.sort_order - 1 where v.attribute_id = :attribute_id and v.sort_order > :old_sort_order select object_type from acs_objects where object_id = :object_id select * from ($package_object_view) where object_id = :object_id select enum.pretty_name, enum.enum_value from acs_enum_values enum where enum.attribute_id = :attribute_id order by enum.sort_order insert into acs_enum_values (attribute_id, sort_order, enum_value, pretty_name) select :attribute_id, :sort_order, :enum_value, :enum_value from dual where not exists (select 1 from acs_enum_values v2 where v2.pretty_name = :enum_value and v2.attribute_id = :attribute_id) openacs-5.7.0/packages/acs-subsite/tcl/party-procs.tcl0000644000175000017500000001657511456662501022570 0ustar frankiefrankie# /packages/subsite/tcl/party-procs.tcl ad_library { Procs to manage groups @author oumi@arsdigita.com @creation-date 2001-02-06 @cvs-id $Id: party-procs.tcl,v 1.8 2010/10/17 21:06:09 donb Exp $ } namespace eval party { ad_proc -public permission_p { { -user_id "" } { -privilege "read" } party_id } { Wrapper for ad_permission to allow us to bypass having to specify the read privilege @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 } { return [ad_permission_p -user_id $user_id $party_id $privilege] } ad_proc new { { -form_id "" } { -variable_prefix "" } { -creation_user "" } { -creation_ip "" } { -party_id "" } { -context_id "" } { -email "" } party_type } { Creates a party of this type by calling the .new function for the package associated with the given party_type. This function will fail if there is no package.

    There are now several ways to create a party of a given type. You can use this TCL API with or without a form from the form system, or you can directly use the PL/SQL API for the party type.

    Examples:

    
    	# OPTION 1: Create the party using the TCL Procedure. Useful if the
    	# only attribute you need to specify is the party name
    	
    	db_transaction {
    	    set party_id [party::new -email "joe@foo.com" $party_type]
    	}
    	
    	
    	# OPTION 2: Create the party using the TCL API with a templating
    	# form. Useful when there are multiple attributes to specify for the
    	# party
    	
    	template::form create add_party
    	template::element create add_party email -value "joe@foo.com"
    	
    	db_transaction {
    	    set party_id [party::new -form_id add_party $party_type ]
    	}
    	
    	# OPTION 3: Create the party using the PL/SQL package automatically
    	# created for it
    	
    	# creating the new party
    	set party_id [db_exec_plsql add_party "
    	  begin
    	    :1 := ${party_type}.new (email => 'joe@foo.com');
    	  end;
    	"]
    	
    	
    @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2001-02-08 @return party_id of the newly created party @param form_id The form id from templating form system (see example above) @param email The email of this party. Note that if email is specified explicitly, this value will be used even if there is a email attribute in the form specified by form_id. @param party_type The type of party we are creating } { # We select out the name of the primary key. Note that the # primary key is equivalent to party_id as this is a subtype of # acs_party if { ![db_0or1row package_select { select t.package_name, lower(t.id_column) as id_column from acs_object_types t where t.object_type = :party_type }] } { error "Object type \"$party_type\" does not exist" } set var_list [list \ [list context_id $context_id] \ [list $id_column $party_id] \ [list "email" $email]] return [package_instantiate_object \ -creation_user $creation_user \ -creation_ip $creation_ip \ -package_name $package_name \ -start_with "party" \ -var_list $var_list \ -form_id $form_id \ -variable_prefix $variable_prefix \ $party_type] } ad_proc types_valid_for_rel_type_multirow { {-datasource_name object_types} {-start_with party} {-rel_type "membership_rel"} } { creates multirow datasource containing party types starting with the $start_with party type. The datasource has columns that are identical to the relation_types_allowed_to_group_multirow, which is why the columns are broadly named "object_*" instead of "party_*". A common template can be used for generating select widgets etc. for both this datasource and the relation_types_allowed_to_groups_multirow datasource. All subtypes of $start_with are returned, but the "valid_p" column in the datasource indicates whether the type is a valid one for $group_id. Includes fields that are useful for presentation in a hierarchical select widget:
    • object_type
    • object_type_enc - encoded object type
    • indent - an html indentation string
    • pretty_name - pretty name of object type
    • valid_p - 1 or 0 depending on whether the type is valid
    @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2000-02-07 @param datasource_name @param start_with @param rel_type - if unspecified, then membership_rel is used } { template::multirow create $datasource_name \ object_type object_type_enc indent pretty_name valid_p # Special case "party" because we don't want to display "party" itself # as an option, and we don't want to display "rel_segment" as an # option. if {$start_with eq "party"} { set start_with_clause [db_map start_with_clause_party] } else { set start_with_clause [db_map start_with_clause] } db_foreach select_sub_rel_types " select types.pretty_name, types.object_type, types.tree_level, types.indent, decode(valid_types.object_type, null, 0, 1) as valid_p from (select t.pretty_name, t.object_type, level as tree_level, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent, rownum as tree_rownum from acs_object_types t connect by prior t.object_type = t.supertype start with $start_with_clause ) types, (select object_type from rel_types_valid_obj_two_types where rel_type = :rel_type ) valid_types where types.object_type = valid_types.object_type(+) order by tree_rownum " { template::multirow append $datasource_name $object_type [ad_urlencode $object_type] $indent $pretty_name $valid_p } } ad_proc -public email { {-party_id:required} } { this returns the parties email. Cached } { return [util_memoize [list ::party::email_not_cached -party_id $party_id]] } ad_proc -private email_not_cached { {-party_id:required} } { this returns the contact's name } { set email [db_string get_party_email { select email from parties where party_id = :party_id } -default {}] return $email } ad_proc -public name { {-party_id ""} {-email ""} } { Gets the party name of the provided party_id @author Miguel Marin (miguelmarin@viaro.net) @author Viaro Networks www.viaro.net @author Malte Sussdorff (malte.sussdorff@cognovis.de) @param party_id The party_id to get the name from. @param email The email of the party @return The party name } { if {$party_id eq "" && $email eq ""} { error "You need to provide either party_id or email" } elseif {"" ne $party_id && "" ne $email } { error "Only provide provide party_id OR email, not both" } if {$party_id eq ""} { set party_id [party::get_by_email -email $email] } if {[person::person_p -party_id $party_id]} { set name [person::name -person_id $party_id] } else { if { [apm_package_installed_p "organizations"] } { set name [db_string get_org_name {} -default ""] } if { $name eq "" } { set name [db_string get_group_name {} -default ""] } if { $name eq "" } { set name [db_string get_party_name {} -default ""] } } return $name } ad_proc -public party_p { -object_id:required } { @author Malte Sussdorff @creation-date 2007-01-26 @param object_id object_id which is checked if it is a party @return true if object_id is a party } { return [db_string party_p {} -default 0] } } openacs-5.7.0/packages/acs-subsite/tcl/party-procs.xql0000644000175000017500000000163210557364026022600 0ustar frankiefrankie select t.package_name, lower(t.id_column) as id_column from acs_object_types t where t.object_type = :party_type select name from organizations where organization_id = :party_id select group_name from groups where group_id = :party_id select party_name from party_names where party_id = :party_id select 1 from parties where party_id = :object_id openacs-5.7.0/packages/acs-subsite/tcl/relation-procs-oracle.xql0000644000175000017500000000716010525170722024514 0ustar frankiefrankie oracle8.1.6 select rel_constraint.violation(:rel_id) from dual select s.segment_id, r.object_id_two as party_id, t.package_name from rel_segments s, acs_rels r, acs_object_types t where r.object_id_one = s.group_id(+) and r.rel_type = s.rel_type(+) and r.rel_type = t.object_type and r.rel_id = :rel_id begin ${package_name}.del(:rel_id); end; select s.segment_id, r.object_id_two as party_id, t.package_name from rel_segments s, acs_rels r, acs_object_types t where r.object_id_one = s.group_id(+) and r.rel_type = s.rel_type(+) and r.rel_type = t.object_type and r.rel_id = :rel_id select case when exists (select 1 from rc_violations_by_removing_rel r where r.rel_id = :rel_id) then 1 else 0 end from dual select case when exists (select 1 from rc_valid_rel_types r where r.group_id = :group_id and r.rel_type = :rel_type) then 1 else 0 end from dual select pretty_name, object_type, indent, case when valid_types.rel_type = null then 0 else 1 end as valid_p from (select t.pretty_name, t.object_type, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent, rownum as tree_rownum from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type = :start_with ) types, (select rel_type from rc_valid_rel_types where group_id = :group_id ) valid_types where types.object_type = valid_types.rel_type(+) order by tree_rownum select distinct s.segment_id, s.group_id, s.rel_type, g.group_name, g.join_policy, t.pretty_name as rel_type_pretty_name, nvl(dl.dependency_level, 0) from rc_all_constraints c, (select rel_segment, required_rel_segment from rc_segment_required_seg_map where rel_side = 'two' UNION ALL select segment_id, segment_id from rel_segments) map, rel_segments s, rc_segment_dependency_levels dl, groups g, acs_object_types t where c.group_id = :group_id and c.rel_type = :rel_type and c.required_rel_segment = map.rel_segment and map.required_rel_segment = s.segment_id and s.segment_id = dl.segment_id(+) and g.group_id = s.group_id and t.object_type = s.rel_type order by nvl(dl.dependency_level, 0) openacs-5.7.0/packages/acs-subsite/tcl/group-procs.tcl0000644000175000017500000005523511305160275022553 0ustar frankiefrankie# /packages/acs-subsite/tcl/group-procs.tcl ad_library { Procs to manage groups @author mbryzek@arsdigita.com @creation-date Thu Dec 7 18:13:56 2000 @cvs-id $Id: group-procs.tcl,v 1.37 2009/12/01 09:24:13 emmar Exp $ } namespace eval group {} ad_proc -public group::new { { -form_id "" } { -variable_prefix "" } { -creation_user "" } { -creation_ip "" } { -group_id "" } { -context_id "" } { -group_name "" } { -pretty_name ""} {group_type "group"} } { Creates a group of this type by calling the .new function for the package associated with the given group_type. This function will fail if there is no package.

    There are now several ways to create a group of a given type. You can use this TCL API with or without a form from the form system, or you can directly use the PL/SQL API for the group type.

    Examples:

    
        # OPTION 1: Create the group using the TCL Procedure. Useful if the
        # only attribute you need to specify is the group name
        
        db_transaction {
            set group_id [group::new -group_name "Author" $group_type]
        }
        
        
        # OPTION 2: Create the group using the TCL API with a templating
        # form. Useful when there are multiple attributes to specify for the
        # group
        
        template::form create add_group
        template::element create add_group group_name -value "Publisher"
        
        db_transaction {
            set group_id [group::new -form_id add_group $group_type ]
        }
        
        # OPTION 3: Create the group using the PL/SQL package automatically
        # created for it
        
        # creating the new group
        set group_id [db_exec_plsql add_group "
          begin
            :1 := ${group_type}.new (group_name => 'Editor');
          end;
        "]
        
        
    @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 @return group_id of the newly created group @param form_id The form id from templating form system (see example above) @param group_name The name of this group. Note that if group_name is specified explicitly, this name will be used even if there is a group_name attribute in the form specified by form_id. @param group_type The type of group we are creating. Defaults to group which is what you want in most cases. @param group_name The name of this group. This is a required variable, though it may be specified either explicitly or through form_id } { # We select out the name of the primary key. Note that the # primary key is equivalent to group_id as this is a subtype of # acs_group if { ![db_0or1row package_select { select t.package_name, lower(t.id_column) as id_column from acs_object_types t where t.object_type = :group_type }] } { error "Object type \"$group_type\" does not exist" } set var_list [list] lappend var_list [list context_id $context_id] lappend var_list [list $id_column $group_id] if { $group_name ne "" } { lappend var_list [list group_name $group_name] if {$pretty_name eq ""} { set pretty_name $group_name } } set group_id [package_instantiate_object \ -creation_user $creation_user \ -creation_ip $creation_ip \ -package_name $package_name \ -start_with "group" \ -var_list $var_list \ -form_id $form_id \ -variable_prefix $variable_prefix \ $group_type] # We can't change the group_name to an I18N version as this would # break compatability with group::member_p -group_name and the # like. So instead we change the title of the object of the group # (through the pretty name). We just have to change the display of # groups to the title at the appropriate places. if { [info procs "::lang::util::convert_to_i18n"] ne "" } { set pretty_name [lang::util::convert_to_i18n -message_key "group_title_${group_id}" -text "$pretty_name"] } # Update the title to the pretty name if {$pretty_name ne ""} { db_dml title_update "update acs_objects set title=:pretty_name where object_id = :group_id" } return $group_id } ad_proc group::delete { group_id } { Deletes the group specified by group_id, including all relational segments specified for the group and any relational constraint that depends on this group in any way. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 @return object_type of the deleted group, if it was actually deleted. Returns the empty string if the object didn't exist to begin with @param group_id The group to delete } { if { ![db_0or1row package_select { select t.package_name, t.object_type from acs_object_types t where t.object_type = (select o.object_type from acs_objects o where o.object_id = :group_id) }] } { # No package means the object doesn't exist. We're done :) return } # Maybe the relational constraint deletion should be moved to # the acs_group package... db_exec_plsql delete_group " BEGIN -- the acs_group package takes care of segments referred -- to by rel_constraints.rel_segment. We delete the ones -- references by rel_constraints.required_rel_segment here. for row in (select cons.constraint_id from rel_constraints cons, rel_segments segs where segs.segment_id = cons.required_rel_segment and segs.group_id = :group_id) loop rel_segment.del(row.constraint_id); end loop; -- delete the actual group ${package_name}.del(:group_id); END; " util_memoize_flush "group::get_title_not_cached -group_id $group_id" return $object_type } ad_proc -public group::get { {-group_id:required} {-array:required} } { Get basic info about a group: group_name, join_policy. @param array The name of an array in the caller's namespace where the info gets delivered. @see group::get_element } { upvar 1 $array row db_1row group_info { select group_name, title, join_policy, description from groups g, acs_objects o where group_id = :group_id and object_id = :group_id } -column_array row } ad_proc -public group::get_element { {-group_id:required} {-element:required} } { Get an element from the basic info about a group: group_name, join_policy. @see group::get } { group::get -group_id $group_id -array row return $row($element) } ad_proc -public group::get_id { {-group_name:required} {-subsite_id ""} {-application_group_id ""} } { Retrieve the group_id to a given group-name. If you have more than one group with this name, it will return the first one it finds. Keep that in mind when using this procedure. @author Christian Langmann (C_Langmann@gmx.de) @author Malte Sussdorff (openacs@sussdorff.de) @creation-date 2005-06-09 @param group_name the name of the group to look for @param subsite_id the ID of the subsite to search for the group name @param application_group_id the ID of the application group to search for the group name @return the first group_id of the groups found for that group_name. @error } { return [util_memoize [list group::get_id_not_cached -group_name $group_name -subsite_id $subsite_id -application_group_id ""]] } ad_proc -private group::get_id_not_cached { {-group_name:required} {-subsite_id ""} {-application_group_id ""} } { Retrieve the group_id to a given group-name. @author Christian Langmann (C_Langmann@gmx.de) @author Malte Sussdorff (openacs@sussdorff.de) @creation-date 2005-06-09 @param group_name the name of the group to look for @return the id of the group @error } { if {[exists_and_not_null subsite_id]} { set application_group_id [application_group::group_id_from_package_id -package_id [ad_conn subsite_id]] } if {[exists_and_not_null application_group_id]} { set group_ids [db_list get_group_id_with_application {}] } else { set group_ids [db_list get_group_id {}] } return [lindex $group_ids 0] } ad_proc -public group::get_members { {-group_id:required} {-type "party"} } { Get party_ids of all members from cache. @param type Type of members - party, person, user @see group::get_members_not_cached @see group::flush_members_cache @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-07-26 } { return [util_memoize [list group::get_members_not_cached -group_id $group_id -type $type]] } ad_proc -private group::get_members_not_cached { {-group_id:required} {-type:required} } { Get party_ids of all members. @param type Type of members - party, person, user @see group::get_members @see group::flush_members_cache @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-07-26 } { switch $type { party { set member_list [db_list group_members_party {}] } default { set member_list [db_list group_members {}] } } return $member_list } ad_proc -private group::flush_members_cache { {-group_id:required} } { Flush group members cache. @see group::get_members @see group::get_members_not_cached @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-07-26 } { util_memoize_flush "group::get_members_not_cached -group_id $group_id -type party" util_memoize_flush "group::get_members_not_cached -group_id $group_id -type user" util_memoize_flush "group::get_members_not_cached -group_id $group_id -type person" util_memoize_flush_regexp "group::member_p_not_cached -group_id $group_id (.*)" } ad_proc -public group::permission_p { { -user_id "" } { -privilege "read" } group_id } { THIS PROC SHOULD GO AWAY! All calls to group::permission_p can be replaced with party::permission_p Wrapper for ad_permission to allow us to bypass having to specify the read privilege @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 } { return [party::permission_p -user_id $user_id -privilege $privilege $group_id] } ad_proc -public group::join_policy { {-group_id:required} } { Returns a group's join policy ('open', 'closed', or 'needs approval') @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 10/2000 } { return [db_string select_join_policy { select join_policy from groups where group_id = :group_id }] } ad_proc -public group::description { {-group_id:required} } { Returns a group's description @creation-date 09/2008 } { return [db_string select_description { select description from groups where group_id = :group_id }] } ad_proc -public group::update { {-group_id:required} {-array:required} } { Updates a group. @param group_id The ID of the group to update. @param array Name of array containing the columns to update. Valid columns are group_name, join_policy. Valid join_policy values are 'open', 'closed', 'needs approval'. } { upvar $array row # Construct clauses for the update statement set columns { group_name join_policy description } set set_clauses [list] foreach name [array names row] { if { [lsearch -exact $columns $name] == -1 } { error "Attribute '$name' isn't valid for groups." } lappend set_clauses "$name = :$name" set $name $row($name) } if { [llength $set_clauses] == 0 } { # No rows to update return } db_dml update_group " update groups set [join $set_clauses ", "] where group_id = :group_id " if {[info exists group_name]} { set pretty_name [lang::util::convert_to_i18n -message_key "group_title.${group_id}" -text "$group_name"] db_dml update_object_title { update acs_objects set title = :pretty_name where object_id = :group_id } util_memoize_flush "group::get_title_not_cached -group_id $group_id" } } ad_proc -public group::possible_member_states {} { Returns the list of possible member states: approved, needs approval, banned, rejected, deleted. } { return [list approved "needs approval" banned rejected deleted] } ad_proc -public group::get_member_state_pretty { {-member_state:required} } { Returns the pretty-name of a member state. } { array set message_key_array { approved #acs-kernel.member_state_approved# "needs approval" #acs-kernel.member_state_needs_approval# banned #acs-kernel.member_state_banned# rejected #acs-kernel.member_state_rejected# deleted #acs-kernel.member_state_deleted# } return [lang::util::localize $message_key_array($member_state)] } ad_proc -public group::get_join_policy_options {} { Returns a list of valid join policies in a format suitable for a form builder drop-down. } { return [list \ [list [_ acs-kernel.common_open] "open"] \ [list [_ acs-kernel.common_needs_approval] "needs approval"] \ [list [_ acs-kernel.common_closed] "closed"]] } ad_proc -public group::default_member_state { { -join_policy "" } { -create_p "" } -no_complain:boolean } { If user has 'create' privilege on group_id OR the group's join policy is 'open', then default_member_state will return "approved". If the group's join policy is 'needs approval' then default_member_state will return 'needs approval'. If the group's join policy is closed then an error will be thrown, unless the no_complain flag is set, in which case empty string is returned. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 10/2000 @param join_policy - the group's join policy (one of 'open', 'closed', or 'needs approval') @param create_p - 1 if the user has 'create' privilege on the group, 0 otherwise. } { if {$create_p || $join_policy eq "open"} { return "approved" } if {$join_policy eq "needs approval"} { return "needs approval" } if {$no_complain_p} { error "group::default_member_state - user is not a group admin and join policy is $join_policy." } return "" } ad_proc -public group::member_p { { -user_id "" } { -group_name "" } { -group_id "" } { -subsite_id "" } -cascade:boolean } { Return 1 if the user is a member of the group specified. You can specify a group name or group id.

    If there is more than one group with this name, it will use the first one.

    If cascade is true, check to see if the user is a member of the group by virtue of any other component group. (e.g. if group B is a component of group A then if a user is a member of group B then he is automatically a member of A also.) If cascade is false, then the user must have specifically been granted membership on the group in question.

    @param subsite_id Only useful when using group_name. Marks the subsite in which to search for the group_id that belongs to the group_name @see group::flush_members_cache } { if { $user_id eq "" } { set user_id [ad_conn user_id] } if { $group_name eq "" && $group_id eq "" } { return 0 } if { $group_name ne "" } { set group_id [group::get_id -group_name $group_name -subsite_id $subsite_id] if { $group_id eq "" } { return 0 } } return [util_memoize [list group::member_p_not_cached -group_id $group_id -user_id $user_id -cascade_p $cascade_p]] } ad_proc -public group::member_p_not_cached { { -user_id "" } { -group_id "" } {-cascade_p ""} } { Return 1 if the user is a member of the group specified. You can specify a group id.

    If there is more than one group with this name, it will use the first one.

    If cascade is true, check to see if the user is a member of the group by virtue of any other component group. (e.g. if group B is a component of group A then if a user is a member of group B then he is automatically a member of A also.) If cascade is false, then the user must have specifically been granted membership on the group in question.

    @param subsite_id Only useful when using group_name. Marks the subsite in which to search for the group_id that belongs to the group_name @see group::flush_members_cache } { set cascade [db_boolean $cascade_p] set result [db_string user_is_member {} -default "f"] return [template::util::is_true $result] } ad_proc -public group::party_member_p { -party_id { -group_name "" } { -group_id "" } { -subsite_id "" } } { Return 1 if the party is an approved member of the group specified. You can specify a group name or group id.

    Note: The group name is not unique by definition, and if you call this function with a duplicate group name it will bomb!!! Using the group name as a parameter is thus strongly discouraged unless you are really, really sure the name is unique.

    The party must have specifically been granted membership on the group in question.

    } { if { $group_name eq "" && $group_id eq "" } { return 0 } if { $group_name ne "" } { set group_id [group::get_id -group_name $group_name -subsite_id $subsite_id] if { $group_id eq "" } { return 0 } } set result [lindex [db_list party_is_member {}] 0] return [template::util::is_true $result] } ad_proc -public group::get_rel_segment { {-group_id:required} {-type:required} } { Get a segment for a particular relation type for a given group. } { return [db_string select_segment_id {}] } ad_proc -public group::get_rel_types_options { {-group_id:required} {-object_type "person"} } { Get the valid relationship-types for this group in a format suitable for a select widget in the form builder. The label used is the name of the role for object two. @param group_id The ID of the group for which to get options. @param object_type The object type which must occupy side two of the relationship. Typically 'person' or 'group'. @return a list of lists with label (role two pretty name) and ID (rel_type) } { # LARS: # The query has a hack to make sure 'membership_rel' appears before all other rel types set rel_types [list] db_foreach select_rel_types {} { # Localize the name lappend rel_types [list [lang::util::localize $pretty_name] $rel_type] } return $rel_types } ad_proc -public group::admin_p { {-group_id:required} {-user_id:required} } { @return 1 if user_id is in teh admin_rel for group_id } { set admin_rel_id [relation::get_id \ -object_id_one $group_id \ -object_id_two $user_id \ -rel_type "admin_rel"] # The party is an admin if the call above returned something non-empty return [expr {$admin_rel_id ne ""}] } ad_proc -public group::add_member { {-no_perm_check:boolean} {-group_id:required} {-user_id:required} {-rel_type ""} {-member_state ""} } { Adds a user to a group, checking that the rel_type is permissible given the user's privileges, Can default both the rel_type and the member_state to their relevant values. } { set admin_p [permission::permission_p -object_id $group_id -privilege "admin"] # Only admins can add non-membership_rel members if { $rel_type eq "" || \ (!$no_perm_check_p && $rel_type ne "" && $rel_type ne "membership_rel" && \ ![permission::permission_p -object_id $group_id -privilege "admin"]) } { set rel_type "membership_rel" } group::get -group_id $group_id -array group if { !$no_perm_check_p } { set create_p [group::permission_p -privilege create $group_id] if { $group(join_policy) eq "closed" && !$create_p } { error "You do not have permission to add members to the group '$group(group_name)'" } } else { set create_p 1 } if { $member_state eq "" } { set member_state [group::default_member_state \ -join_policy $group(join_policy) \ -create_p $create_p] } if { $rel_type ne "membership_rel" } { # add them with a membership_rel first relation_add -member_state $member_state "membership_rel" $group_id $user_id } relation_add -member_state $member_state $rel_type $group_id $user_id flush_members_cache -group_id $group_id } ad_proc -public group::remove_member { {-group_id:required} {-user_id:required} } { Removes a user from a group. No permission checking. } { # Find all acs_rels between this group and this user, which are membership_rels or descendants thereof (admin_rels, for example) set rel_id_list [db_list select_rel_ids { select r.rel_id from acs_rels r, membership_rels mr where r.rel_id = mr.rel_id and r.object_id_one = :group_id and r.object_id_two = :user_id }] db_transaction { foreach rel_id $rel_id_list { relation_remove $rel_id } } flush_members_cache -group_id $group_id } ad_proc -public group::title { {-group_name ""} {-group_id ""} } { Get the title of a group, cached Use either the group_id or the group_name @param group_id The group_id of the group @param group_name The name of the group. Note this is not the I18N title we want to retrieve with this procedure } { if {$group_name ne ""} { set group_id [group::get_id -group_name $group_name] } if {$group_id ne ""} { return [util_memoize [list group::title_not_cached -group_id $group_id]] } else { return "" } } ad_proc -private group::title_not_cached { {-group_id ""} } { Get the title of a group, not cached @param group_id The group_id of the group } { return [group::get_element -group_id $group_id -element "title"] } ad_proc -private group::group_p { {-group_id ""} } { Get the title of a group, not cached @param group_id The group_id of the group } { return [util_memoize [list group::group_p_not_cached -group_id $group_id]] } ad_proc -private group::group_p_not_cached { {-group_id ""} } { Get the title of a group, not cached @param group_id The group_id of the group } { return [db_string group "select 1 from groups where group_id = :group_id" -default 0] } openacs-5.7.0/packages/acs-subsite/tcl/group-procs.xql0000644000175000017500000000551710501566637022604 0ustar frankiefrankie select t.package_name, lower(t.id_column) as id_column from acs_object_types t where t.object_type = :group_type select t.package_name, lower(t.id_column) as id_column from acs_object_types t where t.object_type = :group_type select group_id from groups where group_name = :group_name SELECT g.group_id FROM acs_rels rels INNER JOIN composition_rels comp ON rels.rel_id = comp.rel_id INNER JOIN groups g ON rels.object_id_two = g.group_id WHERE rels.object_id_one = :application_group_id AND g.group_name = :group_name select distinct member_id from group_member_map where group_id = :group_id select distinct m.member_id from group_member_map m, acs_objects o where m.group_id = :group_id and m.member_id = o.object_id and o.object_type = :type select join_policy from groups where group_id = :group_id select group_id from groups where group_name = :group_name select segment_id from rel_segments where group_id = :group_id and rel_type = :type select 1 from group_approved_member_map where member_id = :party_id and group_id = :group_id openacs-5.7.0/packages/acs-subsite/tcl/email-image-procs-postgresql.xql0000644000175000017500000000252210440426466026006 0ustar frankiefrankie postgresql7.1 update cr_revisions set content_length = lob_length(lob) where revision_id = :revision_id update cr_revisions set mime_type = :mime_type, lob = [set __lob_id [db_string get_lob_id "select empty_lob()"]] where revision_id = :revision_id update cr_revisions set content_length = lob_length(lob) where revision_id = :revision_id update cr_revisions set mime_type = :mime_type, lob = [set __lob_id [db_string get_lob_id "select empty_lob()"]] where revision_id = :revision_id select acs_rel__new ( null, 'email_image_rel', :user_id, :item_id, null, null, null ) openacs-5.7.0/packages/acs-subsite/tcl/attribute-procs-oracle.xql0000644000175000017500000000677707335322027024721 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_attributes a, acs_object_types t where t.dynamic_p = 't' and a.object_type = t.object_type and a.attribute_id = :value) then 1 else 0 end from dual select case when exists (select 1 from acs_attributes a where (a.attribute_name = :attribute or a.column_name = :attribute) and a.object_type = :object_type) then 1 else 0 end from dual select a.object_type, a.attribute_name, case when a.storage = 'type_specific' then t.table_name else a.table_name end as table_name, nvl(a.column_name, a.attribute_name) as column_name from acs_attributes a, acs_object_types t where a.attribute_id = :attribute_id and t.object_type = a.object_type select nvl(a.column_name, a.attribute_name) as name, a.pretty_name, a.attribute_id, a.datatype, v.enum_value, v.pretty_name as value_pretty_name from acs_object_type_attributes a, acs_enum_values v, (select t.object_type, level as type_level from acs_object_types t start with t.object_type = :start_with connect by prior t.object_type = t.supertype) t where a.object_type = :object_type and a.attribute_id = v.attribute_id(+) and t.object_type = a.ancestor_type $storage_clause order by type_level, a.sort_order begin acs_attribute.drop_attribute(:object_type, :attribute_name); end; declare attr_id acs_attributes.attribute_id%TYPE; begin attr_id := acs_attribute.create_attribute ( object_type => '$object_type', attribute_name => '$attribute_name', min_n_values => '$min_n_values', max_n_values => '$max_n_values', default_value => '$default_value', datatype => '$datatype', pretty_name => '$pretty_name', pretty_plural => '$pretty_plural' ); end; alter table $table_name drop column $attribute_name alter table $table_name add $attribute_name $sql_type begin acs_attribute.drop_attribute(:object_type, :attribute_name); end; alter table $table_name drop column $column_name openacs-5.7.0/packages/acs-subsite/tcl/email-image-procs.tcl0000644000175000017500000002737611022567611023574 0ustar frankiefrankiead_library { Tcl API for email_image store and manipulation @author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) } namespace eval email_image {} ad_proc -public email_image::update_private_p { -user_id:required -level:required } { Changes the priv_email field from the users table @user_id @level Change to this level } { db_transaction { db_dml update_users { } } } ad_proc -public email_image::get_priv_email { -user_id:required } { Returns the priv_email field of the user from the users table. @user_id } { set priv_level [db_string get_private_email { }] if {$priv_level eq "5"} { set priv_level [parameter::get_from_package_key -package_key "acs-subsite" \ -parameter "PrivateEmailLevelP" -default 4] } return $priv_level } ad_proc -public email_image::get_user_email { -user_id:required {-return_url ""} {-bgcolor "" } {-transparent "" } } { Returns the email in differnet diferent ways (text level 4, image or text and image level 3, link level 2, ...) according to the priv_email field in the users table. To create an image the ImageMagick software is required, if ImageMagick is not present then the @ symbol in the email will be shown as an image. When creating an image you can choose the background color (In this format \#xxxxxx). Also you can make the background color transparent (1 or 0). @user_id @return_url The url to return when the email is shown as a link @bgcolor The Background color of the image. Default to \#ffffff @transparent If the bgcolor is transparent. Default to 1 } { set email [email_image::get_email -user_id $user_id] set user_level [email_image::get_priv_email -user_id $user_id] if { $user_level == 5 } { # We get the privacy level from PrivateEmailLevelP parameter set priv_level [parameter::get_from_package_key -package_key "acs-subsite" \ -parameter "PrivateEmailLevelP" -default 4] } else { # We use the privacy level that the user select set priv_level $user_level } set send_email_url [ad_quotehtml "/shared/send-email?sendto=$user_id&return_url=$return_url"] switch $priv_level { "4" { return "$email" } "3" { set email_image_id [email_image::get_related_item_id -user_id $user_id] if { $email_image_id != "-1" } { # The user has an email image stored in the content repository set revision_id [content::item::get_latest_revision -item_id $email_image_id] set img_src [ad_quotehtml "/shared/email-image-bits.tcl?user_id=$user_id&revision_id=$revision_id"] set email_image "\"#acs-subsite.Email#\"" } else { # Create a new email_image if { [catch { set email_image [email_image::new_item -user_id $user_id -return_url $return_url -bgcolor $bgcolor -transparent $transparent] } errmsg ] } { ns_log Error "email_image::get_user_email failed \n $errmsg" # ImageMagick not present, we protect the email by adding # an image replacing the "@" symbol set email_user [lindex [split $email '@'] 0] set email_domain [lindex [split $email '@'] 1] set email_image "${email_user}\"@\"${email_domain}" } } return $email_image } "2" { return "\#acs-subsite.Send_email_to_this_user\#" } "1" { #Do not show e-mail return "\#acs-subsite.email_not_available\#" } } } ad_proc -public email_image::get_email { -user_id:required } { Returns the email of the user @user_id } { return [db_string get_email { }] } ad_proc -public email_image::new_item { -user_id:required {-return_url ""} {-bgcolor ""} {-transparent ""} } { Creates the email_image of the user with his/her email on it and store it in the content repository under the Email_Images folder. @user_id @bgcolor The background color of the image in the format \#xxxxxx, default to \#ffffff @transparent If you want the background color transparent set it to 1. Default to 1 } { # First we create a type and a folder in the content repository # with label Email_Images where only items of type email_image # will be stored. set font_size 14 set font_type helvetica set folder_id [email_image::get_folder_id] set email [email_image::get_email -user_id $user_id] set image_name "email${user_id}.gif" set email_length [string length $email] set dest_path "/tmp/$image_name" set width [expr [expr {$email_length * [expr {$font_size / 2}]}] + 2] set height $font_size set ypos [expr {[expr {$height / 2}] + 3 }] set size "${width}x$height" if {$bgcolor eq ""} { set bgcolor "\#ffffff" } set bg "xc:$bgcolor" # Creating an image of the rigth length where the email will be if {[catch {exec convert -size $size $bg $dest_path} errmsg]} { return "" } # Creating the image with the email of the user on it if {[catch {exec convert -font $font_type -fill blue -pointsize $font_size -draw "text 0,$ypos $email" \ $dest_path $dest_path} errmsg]} { return "" } if { $transparent eq "" || $transparent eq "1" } { # Making the bg color transparent if {[catch {exec convert $dest_path -transparent $bgcolor $dest_path} errmsg]} { return "" } } # Time to store the image in the content repository db_transaction { set mime_type [cr_filename_to_mime_type -create $dest_path] set creation_ip [ad_conn peeraddr] set item_id [content::item::new -name $image_name -parent_id $folder_id -content_type "email_image" \ -storage_type "lob" -creation_ip $creation_ip] set revision_id [content::revision::new -item_id $item_id -title $image_name -mime_type $mime_type \ -description "User email image" -creation_ip $creation_ip ] email_image::add_relation -user_id $user_id -item_id $item_id db_dml update_cr_items { } db_dml lob_content { } -blob_files [list ${dest_path}] db_dml lob_size { } } # Delete the temporary file created by ImageMagick catch { file delete $dest_path } errMsg set img_src [ad_quotehtml "/shared/email-image-bits.tcl?user_id=$user_id&revision_id=$revision_id"] set send_email_url [ad_quotehtml "/shared/send-email?sendto=$user_id&return_url=$return_url"] set email_image "\"#acs-subsite.Email#\"" return "$email_image" } ad_proc -public email_image::edit_email_image { -user_id:required -new_email:required {-bgcolor ""} {-transparent ""} } { Creates a new email_image of the user with his/her new edited email on it and store it in the content repository under the Email_Images folder. If the user has an image already stored it makes a new revision of the image, if not, it creates a new item with the new image. @user_id @bgcolor The background color of the image in the format \#xxxxxx, default to \#ffffff @transparent If you want the background color transparent set it to 1. Default to 1 } { if { $new_email == [email_image::get_email -user_id $user_id] } { # Email didn't change return } set font_size 14 set font_type helvetica set folder_id [email_image::get_folder_id] set image_name "email${user_id}.gif" set email_length [string length $new_email] set dest_path "/tmp/$image_name" set width [expr [expr {$email_length * [expr {$font_size / 2}]}] + 2] set height $font_size set ypos [expr {[expr {$height / 2}] + 3 }] set size "${width}x$height" if {$bgcolor eq ""} { set bgcolor "\#ffffff" } set bg "xc:$bgcolor" # Creating an image of the rigth length where the email will be if { [catch { exec convert -size $size $bg $dest_path } ] } { # ImageMagick not present return } # Creating the image with the email of the user on it exec convert -font $font_type -fill blue -pointsize $font_size -draw "text 0,$ypos $new_email" \ $dest_path $dest_path if { $transparent eq "" || $transparent eq "1" } { # Making the bg color transparent exec convert $dest_path -transparent $bgcolor $dest_path } set email_image_id [email_image::get_related_item_id -user_id $user_id] set mime_type [cr_filename_to_mime_type -create $dest_path] set creation_ip [ad_conn peeraddr] if { $email_image_id != "-1" } { db_transaction { set item_id $email_image_id set revision_id [content::revision::new -item_id $item_id -title $image_name \ -mime_type $mime_type \ -description "User email image" -creation_ip $creation_ip ] db_dml update_cr_items { } db_dml lob_content { } -blob_files [list ${dest_path}] db_dml lob_size { } } } else { db_transaction { set item_id [content::item::new -name $image_name -parent_id $folder_id -content_type "email_image" \ -storage_type "lob" -creation_ip $creation_ip] set revision_id [content::revision::new -item_id $item_id -title $image_name -mime_type $mime_type \ -description "User email image" -creation_ip $creation_ip ] email_image::add_relation -user_id $user_id -item_id $item_id db_dml update_cr_items { } db_dml lob_content { } -blob_files [list ${dest_path}] db_dml lob_size { } } } # Delete the temporary file created by ImageMagick catch { file delete $dest_path } errMsg } ad_proc -public email_image::get_folder_id { } { Returns the folder_id of the folder with the name "Email_Images" } { return [db_string check_folder_name { } ] } ad_proc -public email_image::add_relation { -user_id:required -item_id:required } { Add a new relation between user_id and item_id @user_id @item_id the item_id of the image in the content repository } { db_exec_plsql add_relation { } } ad_proc -public email_image::get_related_item_id { -user_id:required } { Returns the item_id of the email_image stored in the content repository for user_id. @user_id } { return [db_string get_rel_item { } -default -1 ] } ad_proc -public email_image::create_type_folder_rel { } { Creates a new folder in the content repository with the name and label Email_Images. Also create a new type and register this type to the created folder. Makes a new relation type to asociate the item_id (email_image in the content repository) with the user_id. } { set type_id [content::type::new -content_type "email_image" -pretty_name "Email_Image" \ -pretty_plural "Email_Images" -table_name "users_email_image" -id_column "email_image_id"] set folder_id [content::folder::new -name "Email_Images" -label "Email_Images"] content::folder::register_content_type -folder_id $folder_id -content_type "email_image" rel_types::new email_image_rel "Email Image" "Email Images" user 0 1 content_item 0 1 } openacs-5.7.0/packages/acs-subsite/tcl/email-image-procs.xql0000644000175000017500000000263710725457777023633 0ustar frankiefrankie select email from parties where party_id = :user_id select priv_email from users where user_id = :user_id select folder_id from cr_folders where label = 'Email_Images' select object_id_two from acs_rels where rel_type = 'email_image_rel' and object_id_one = :user_id update users set priv_email = :level where user_id = :user_id update cr_items set live_revision = :revision_id where item_id = :item_id update cr_items set live_revision = :revision_id where item_id = :item_id openacs-5.7.0/packages/acs-subsite/tcl/subsite-callback-procs.tcl0000644000175000017500000000643411355745653024642 0ustar frankiefrankie# /packages/acs-subsite/tcl/group-callback-procs.tcl ad_library { Procs to support a simple callback mechanism that allows other applications to register callbacks triggered when objects, like groups, in the subsite application are created. @author mbryzek@arsdigita.com @creation-date Wed Feb 21 17:10:24 2001 @cvs-id $Id: subsite-callback-procs.tcl,v 1.6 2010/04/03 23:13:47 donb Exp $ } ad_proc -public subsite_callback { { -object_type "" } event_type object_id } { Executes any registered callbacks for this object.

    Example:

        # Execute any callbacks registered for this object type or one of
        # it's parent object types
        subsite_callback -object_type $object_type $object_id
        
    @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param object_type The object's type. We look this up in the db if not specified } { if { $object_type eq "" } { db_1row select_object_type { select object_type from acs_objects where object_id = :object_id } } # Check to see if we have any callbacks registered for this object # type or one of it's parent object types. Put the callbacks into # a list as each callback may itself require a database # handle. Note that we need the distinct in case two callbacks are # registered for an object and it's parent object type. set callback_list [db_list_of_lists select_callbacks { select distinct callback, callback_type from subsite_callbacks where object_type in (select t.object_type from acs_object_types t connect by prior t.supertype = t.object_type start with t.object_type = :object_type) and event_type = :event_type }] set node_id [ad_conn node_id] set package_id [ad_conn package_id] foreach row $callback_list { set callback [lindex $row 0] set type [lindex $row 1] switch -- $type { tcl { # Execute the tcl procedure $callback -object_id $object_id -node_id $node_id -package_id $package_id } default { error "Callbacks of type $type not supported" } } } } ad_proc -public -callback subsite::parameter_changed { -package_id:required -parameter:required -value:required } { Callback for changing the value of an instance parameter. @param package_id The package_id of the package the parameter was changed for. @param parameter The parameter value. @param value The new value. @see package::set_value } - ad_proc -public -callback subsite::global_parameter_changed { -package_key:required -parameter:required -value:required } { Callback for changing the value of a global parameter. @param package_key The package_key of the package the parameter was changed for. @param parameter The parameter value. @param value The new value. @see package::set_value } - ad_proc -public -callback subsite::url { -package_id:required -object_id:required {-type ""} } { Callback for creating a URL for an object_id. THis is usually called in /o.vuh, but you could think of scenarios where using this hook makes sense as well. The type let's you define what kind of URL you are looking for (e.g. admin/edit/display) } - openacs-5.7.0/packages/acs-subsite/tcl/subsite-callback-procs.xql0000644000175000017500000000037507300260124024636 0ustar frankiefrankie select object_type from acs_objects where object_id = :object_id openacs-5.7.0/packages/acs-subsite/tcl/email-image-procs-oracle.xql0000644000175000017500000000252410440426466025052 0ustar frankiefrankie oracle8.1.6 update cr_revisions set content_length = dbms_lob.getlength(content) where revision_id = :revision_id update cr_revisions set content = empty_blob() where revision_id = :revision_id returning content into :1 update cr_revisions set content_length = dbms_lob.getlength(content) where revision_id = :revision_id update cr_revisions set content = empty_blob() where revision_id = :revision_id returning content into :1 begin :1 := acs_rel.new ( rel_type => 'email_image_rel', object_id_one => :user_id, object_id_two => :item_id); end; openacs-5.7.0/packages/acs-subsite/tcl/group-type-procs-postgresql.xql0000644000175000017500000000403207514612460025747 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_objects o where acs_permission__permission_p(o.object_id, :user_id, 'delete') = 'f' and o.object_type = :group_type) then 0 else 1 end select acs_object_type__drop_type('$group_type', 'f'); select acs_object_type__create_type ( :group_type, :pretty_name, :pretty_plural, :supertype, :table_name, :id_column, :package_name, 'f', null, null ) begin update acs_object_types set dynamic_p='t' where object_type = :group_type; return null; end; begin insert into group_type_rels (group_rel_type_id, rel_type, group_type) select nextval('t_acs_object_id_seq'), r.rel_type, :group_type from group_type_rels r where r.group_type = :supertype; return null; end; begin create table $table_name ( $id_column integer constraint $constraint(pk) primary key constraint $constraint(fk) references $references_table ($references_column) ); return null; end; openacs-5.7.0/packages/acs-subsite/tcl/rel-segments-procs.tcl0000644000175000017500000000435210551254376024026 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/rel-segments-procs.tcl ad_library { Helpers for relational segments @author mbryzek@arsdigita.com @creation-date Tue Dec 12 16:37:45 2000 @cvs-id $Id: rel-segments-procs.tcl,v 1.4 2007/01/10 21:22:06 gustafn Exp $ } ad_proc -public rel_segments_new { { -context_id "" } { -creation_user "" } { -creation_ip "" } group_id rel_type segment_name } { Creates a new relational segment @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @return The segment_id of the new segment } { if { [ad_conn isconnected] } { if { $creation_user eq "" } { set creation_user [ad_conn user_id] } if { $creation_ip eq "" } { set creation_ip [ad_conn peeraddr] } } return [db_exec_plsql create_rel_segment { declare begin :1 := rel_segment.new(segment_name => :segment_name, group_id => :group_id, context_id => :context_id, rel_type => :rel_type, creation_user => :creation_user, creation_ip => :creation_ip ); end; }] } ad_proc -public rel_segments_delete { segment_id } { Deletes the specified relational segment including all relational constraints that depend on it. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 1/12/2001 } { # First delete dependant constraints. db_foreach select_dependant_constraints { select c.constraint_id from rel_constraints c where c.required_rel_segment = :segment_id } { db_exec_plsql constraint_delete { begin rel_constraint.del(:constraint_id); end; } } db_exec_plsql rel_segment_delete { begin rel_segment.del(:segment_id); end; } } ad_proc -public rel_segments_permission_p { { -user_id "" } { -privilege "read" } segment_id } { Wrapper for ad_permission to allow us to bypass having to specify the read privilege @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { return [ad_permission_p -user_id $user_id $segment_id $privilege] } openacs-5.7.0/packages/acs-subsite/tcl/rel-segments-procs.xql0000644000175000017500000000043007275342305024040 0ustar frankiefrankie select c.constraint_id from rel_constraints c where c.required_rel_segment = :segment_id openacs-5.7.0/packages/acs-subsite/tcl/rel-types-procs-postgresql.xql0000644000175000017500000000424610337327601025564 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_object_types t where t.dynamic_p = 't' and t.object_type = :value) then 1 else 0 end select case when exists (select 1 from acs_object_types t1, acs_object_types t2, group_type_rels g where g.group_type = :group_type and t2.object_type <> g.rel_type and t1.object_type in ('membership_rel','composition_rel') and t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey)) then 1 else 0 end select acs_rel_type__drop_type(:rel_type, 'f') select acs_rel_type__create_type ( :rel_type, :pretty_name, :pretty_plural, :supertype, :table_name, 'rel_id', :package_name, :object_type_one, :role_one, :min_n_rels_one, :max_n_rels_one, :object_type_two, :role_two, :min_n_rels_two, :max_n_rels_two ); create table $table_name ( rel_id integer constraint $fk_constraint_name references $references_table ($references_column) constraint $pk_constraint_name primary key ); select acs_rel_type__create_role(:role, :pretty_name, :pretty_plural) select acs_rel_type__drop_role(:role) openacs-5.7.0/packages/acs-subsite/tcl/subsite-callback-procs-oracle.xql0000644000175000017500000000105707300260124026077 0ustar frankiefrankie oracle8.1.6 select distinct callback, callback_type from subsite_callbacks where object_type in (select t.object_type from acs_object_types t connect by prior t.supertype = t.object_type start with t.object_type = :object_type) and event_type = :event_type openacs-5.7.0/packages/acs-subsite/tcl/relation-procs.tcl0000644000175000017500000002577510551254376023252 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/relation-procs.tcl ad_library { Helpers for dealing with relations @author mbryzek@arsdigita.com @creation-date Sun Dec 10 16:46:11 2000 @cvs-id $Id: relation-procs.tcl,v 1.15 2007/01/10 21:22:06 gustafn Exp $ } namespace eval relation {} ad_proc -public relation_permission_p { { -user_id "" } { -privilege "read" } rel_id } { Wrapper for ad_permission_p that lets us default to read permission @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { return [ad_permission_p -user_id $user_id $rel_id $privilege] } ad_proc -public relation_add { { -form_id "" } { -extra_vars "" } { -variable_prefix "" } { -creation_user "" } { -creation_ip "" } { -member_state "" } rel_type object_id_one object_id_two } { Creates a new relation of the specified type between the two objects. Throws an error if the new relation violates a relational constraint. @author Michael Bryzek (mbryzek@arsdigita.com) @author Ben Adida (ben@openforce.net) @creation-date 1/5/2001 @param form_id The form id from templating form system @param extra_vars An ns_set of extra variables @param variable_prefix Only form elements that begin with the specified prefix will be processed. @param creation_user The user who is creating the relation @param creation_ip @param member_state Only used for membership_relations. See column membership_rels.member_state for more info. @return The rel_id of the new relation } { # First check if the relation already exists, and if so, just return that set existing_rel_id [db_string rel_exists { select rel_id from acs_rels where rel_type = :rel_type and object_id_one = :object_id_one and object_id_two = :object_id_two } -default {}] if { $existing_rel_id ne "" } { return $existing_rel_id } set var_list [list \ [list object_id_one $object_id_one] \ [list object_id_two $object_id_two]] # Note that we don't explicitly check whether rel_type is a type of # membership relation before adding the member_state variable. The # package_instantiate_object proc will ignore the member_state variable # if the rel_type's plsql package doesn't support it. if {$member_state ne ""} { lappend var_list [list member_state $member_state] } # We initialize rel_id, so it's set if there's a problem set rel_id {} # We use db_transaction inside this proc to roll back the insert # in case of a violation db_transaction { set rel_id [package_instantiate_object \ -creation_user $creation_user \ -creation_ip $creation_ip \ -start_with "relationship" \ -form_id $form_id \ -extra_vars $extra_vars \ -variable_prefix $variable_prefix \ -var_list $var_list \ $rel_type] # Check to see if constraints are violated because of this new # relation # JCD: this is enforced by trigger so no longer check explicitly # see membership_rels_in_tr # # set violated_err_msg [db_string select_rel_violation { # select rel_constraint.violation(:rel_id) from dual # } -default ""] # # if { $violated_err_msg ne "" } { # error $violated_err_msg # } } on_error { return -code error $errmsg } return $rel_id } ad_proc -public relation_remove { {rel_id ""} } { Removes the specified relation. Throws an error if we violate a relational constraint by removing this relation. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 1/5/2001 @return 1 if we delete anything. 0 otherwise (e.g. when the relation was already deleted) } { # Pull out the segment_id and the party_id (object_id_two) from # acs_rels. Note the outer joins since the segment may not exist. if { ![db_0or1row select_rel_info {}] } { # Relation doesn't exist return 0 } # Check if we would violate some constraint by removing this relation. # This query basically says: Does there exist a segment, to which # this party is an element (with any relationship type), that # depends on this party being in this segment? That's tough to # parse. Another way to say the same things is: Is there some constraint # that requires this segment? If so, is the user a member of the segment # on which that constraint is defined? If so, we cannot remove this # relation. Note that this segment is defined by joining against # acs_rels to find the group and rel_type for this relation. if { $segment_id ne "" } { if { [relation_segment_has_dependant -segment_id $segment_id -party_id $party_id] } { error "Relational constraints violated by removing this relation" } } db_exec_plsql relation_delete "begin ${package_name}.del(:rel_id); end;" return 1 } ad_proc -public relation_segment_has_dependant { { -rel_id "" } { -segment_id "" } { -party_id "" } } { Returns 1 if the specified segment/party combination has a dependant (meaning a constraint would be violated if we removed this relation). 0 otherwise. Either rel_id or segment_id and party_id must be specified. rel_id takes precedence. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { if { $rel_id ne "" } { if { ![db_0or1row select_rel_info {}] } { # There is either no relation or no segment... thus no dependants return 0 } } if { $segment_id eq "" || $party_id eq "" } { error "Both of segment_id and party_id must be specified in call to relation_segment_has_dependant" } return [db_string others_depend_p {}] } ad_proc -public relation_type_is_valid_to_group_p { { -group_id "" } rel_type } { Returns 1 if group $group_id allows elements through a relation of type $rel_type, or 0 otherwise. If there are no relational constraints that prevent $group_id from being on side one of a relation of type $rel_type, then 1 is returned. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2000-02-07 @param group_id - if unspecified, then we use [application_group::group_id_from_package_id] @param rel_type } { if {$group_id eq ""} { set group_id [application_group::group_id_from_package_id] } return [db_string rel_type_valid_p {}] } ad_proc relation_types_valid_to_group_multirow { {-datasource_name object_types} {-start_with acs_rel} {-group_id ""} } { creates multirow datasource containing relationship types starting with the $start_with relationship type. The datasource has columns that are identical to the party::types_allowed_in_group_multirow, which is why the columns are broadly named "object_*" instead of "rel_*". A common template can be used for generating select widgets etc. for both this datasource and the party::types_allowed_in_groups_multirow datasource. All subtypes of $start_with are returned, but the "valid_p" column in the datasource indicates whether the type is a valid one for $group_id. If -group_id is not specified or is specified null, then the current application_group will be used (determined from [application_group::group_id_from_package_id]). Includes fields that are useful for presentation in a hierarchical select widget:
    • object_type
    • object_type_enc - encoded object type
    • indent - an html indentation string
    • pretty_name - pretty name of object type
    @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2000-02-07 @param datasource_name @param start_with @param group_id - if unspecified, then [applcation_group::group_id_from_package_id] is used. } { if {$group_id eq ""} { set group_id [application_group::group_id_from_package_id] } template::multirow create $datasource_name \ object_type object_type_enc indent pretty_name valid_p db_foreach select_sub_rel_types {} { template::multirow append $datasource_name $object_type [ad_urlencode $object_type] $indent $pretty_name $valid_p } } ad_proc -public relation_required_segments_multirow { { -datasource_name "" } { -group_id "" } { -rel_type "membership_rel" } { -rel_side "two" } } { Sets up a multirow datasource. Also returns a list containing the most essential information. } { if {$group_id eq ""} { set group_id [application_group::group_id_from_package_id] } template::multirow create $datasource_name \ segment_id group_id rel_type rel_type_enc \ rel_type_pretty_name group_name join_policy set group_rel_type_list [list] db_foreach select_required_rel_segments {} { template::multirow append $datasource_name $segment_id $group_id $rel_type [ad_urlencode $rel_type] $rel_type_pretty_name $group_name $join_policy lappend group_rel_type_list [list $group_id $rel_type] } return $group_rel_type_list } ad_proc -public relation::get_id { {-object_id_one:required} {-object_id_two:required} {-rel_type "membership_rel"} } { Find the rel_id of the relation matching the given object_id_one, object_id_two, and rel_type. @return rel_id of the found acs_rel, or the empty string if none existed. } { return [db_string select_rel_id {} -default {}] } ad_proc -public relation::get_object_one { {-object_id_two:required} {-rel_type "membership_rel"} {-multiple:boolean} } { Return the object_id of object one if a relation of rel_type exists between the supplied object_id_two and it. @param multiple_p If set to "t" return a list instead of only one object_id } { if {$multiple_p} { return [db_list select_object_one {}] } else { return [db_string select_object_one {} -default {}] } } ad_proc -public relation::get_object_two { {-object_id_one:required} {-rel_type "membership_rel"} {-multiple:boolean} } { Return the object_id of object two if a relation of rel_type exists between the supplied object_id_one and it. @param multiple_p If set to "t" return a list instead of only one object_id } { if {$multiple_p} { return [db_list select_object_two {}] } else { return [db_string select_object_two {} -default {}] } } ad_proc -public relation::get_objects { {-object_id_one ""} {-object_id_two ""} {-rel_type "membership_rel"} } { Return the list of object_ids if a relation of rel_type exists between the supplied object_id and it. } { if {$object_id_one eq ""} { if {$object_id_two eq ""} { ad_return_error "[_ acs-subsite.Missing_argument]" "[_ acs-subsite.lt_You_have_to_provide_a]" } else { return [relation::get_object_one -object_id_two $object_id_two -rel_type $rel_type -multiple] } } else { return [relation::get_object_two -object_id_one $object_id_one -rel_type $rel_type -multiple] } } openacs-5.7.0/packages/acs-subsite/tcl/relation-procs.xql0000644000175000017500000000502310212150575023242 0ustar frankiefrankie select s.segment_id, r.object_id_two as party_id, t.package_name from acs_rels r left outer join rel_segments s on (r.object_id_one = s.group_id and r.rel_type = s.rel_type), acs_object_types t where r.rel_type = t.object_type and r.rel_id = :rel_id select s.segment_id, r.object_id_two as party_id from rel_segments s, acs_rels r where r.object_id_one = s.group_id and r.rel_type = s.rel_type and r.rel_id = :rel_id select distinct s.segment_id, s.group_id, s.rel_type, g.group_name, g.join_policy, t.pretty_name as rel_type_pretty_name, coalesce(dl.dependency_level, 0) from rc_all_constraints c, (select rel_segment, required_rel_segment from rc_segment_required_seg_map where rel_side = 'two' UNION ALL select segment_id, segment_id from rel_segments) map, rel_segments s left outer join rc_segment_dependency_levels dl using (segment_id), groups g, acs_object_types t where c.group_id = :group_id and c.rel_type = :rel_type and c.required_rel_segment = map.rel_segment and map.required_rel_segment = s.segment_id and g.group_id = s.group_id and t.object_type = s.rel_type order by coalesce(dl.dependency_level, 0) select rel_id from acs_rels where rel_type = :rel_type and object_id_one = :object_id_one and object_id_two = :object_id_two select object_id_one from acs_rels where rel_type = :rel_type and object_id_two = :object_id_two select object_id_two from acs_rels where rel_type = :rel_type and object_id_one = :object_id_one openacs-5.7.0/packages/acs-subsite/tcl/group-type-procs.tcl0000644000175000017500000001445710551254376023543 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/group-type-procs.tcl ad_library { Procs for creating group types @author mbryzek@arsdigita.com @creation-date Tue Nov 7 22:52:39 2000 @cvs-id $Id: group-type-procs.tcl,v 1.5 2007/01/10 21:22:06 gustafn Exp $ } namespace eval group_type { ad_proc -public drop_all_groups_p { { -user_id "" } group_type } { Returns 1 if the user has permission to delete all groups of the specified type. 0 otherwise. user_id defaults to ad_conn user_id if we have a connection. If there is no connection, and no user id, throws an error. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { if { $user_id eq "" } { if { ![ad_conn isconnected] } { error "group_type::drop_all_groups_p: User ID not specified and we have no connection from which to obtain current user ID.\n" } set user_id [ad_conn user_id] } return [db_string group_exists_p { select case when exists (select 1 from acs_objects o where acs_permission.permission_p(o.object_id, :user_id, 'delete') = 'f' and o.object_type = :group_type) then 0 else 1 end from dual }] } ad_proc -public new { { -group_type "" } { -execute_p "t" } { -supertype "group" } pretty_name pretty_plural } { Creates a new group type

    Example:

    	# create a new group of type user_discount_class
    	set group_type [group_type::new -group_type $group_type \
    		-supertype group \
    		"User Discount Class" "User Discount Classes"]
    	
    @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param group_type The type of group_type to create. If empty, we generate a unique group_type based on "group_id" where id is the next value from acs_object_id_seq. @param execute_p If t, we execute the pl/sql. If f, we return a string that represents the pl/sql we are about to execute. @return the group_type of the object created } { if { $group_type eq "" } { # generate a unique group type name. Note that we expect # the while loop to finish immediately while { $group_type eq "" || [plsql_utility::object_type_exists_p $group_type] } { set group_type "GROUP_[db_nextval "acs_object_id_seq"]" } } else { # use 29 chars to leave 1 character in the name for later dynamic views set group_type [plsql_utility::generate_oracle_name -max_length 29 $group_type] if { [plsql_utility::object_type_exists_p $group_type] } { error "Specified group type, $group_type, already exists" } } set table_name [string toupper "${group_type}_ext"] # Since all group types are extensions of groups, maintain a # unique group_id primary key set id_column [db_string select_group_id_column { select upper(id_column) from acs_object_types where object_type='group' }] set package_name [string tolower $group_type] # pull out information about the supertype db_1row supertype_table_column { select t.table_name as references_table, t.id_column as references_column from acs_object_types t where t.object_type = :supertype } # What happens if a constraint with the same name already # exists? We need to add robustness to the auto-generation of constraint # names at a later date. Probability of name collision is # small though so we leave it for a future version set constraint(fk) [plsql_utility::generate_constraint_name $table_name $id_column "fk"] set constraint(pk) [plsql_utility::generate_constraint_name $table_name $id_column "pk"] # Store the plsql in a list so that we can choose, at the end, # to either execute it or return it as a debug message set plsql [list] set plsql_drop [list] if { [db_table_exists $table_name] } { # What to do? Options: # a) throw an error # b) select a new table name (Though this is probably an # error in the package creation script...) # Choose (a) error "The type extension table, $table_name, for the object type, $group_type, already exists. You must either drop the existing table or enter a different group type" } # Create the table if it doesn't exist. lappend plsql_drop [list drop_type [db_map drop_type]] lappend plsql [list "create_type" [db_map create_type]] # Mark the type as dynamic lappend plsql [list update_type [db_map update_type]] # Now, copy the allowable relation types from the super type lappend plsql_drop [list remove_rel_types "delete from group_type_rels where group_type = :group_type"] lappend plsql [list copy_rel_types [db_map copy_rel_types]] if { $execute_p eq "f" } { set text "-- Create script" foreach pair $plsql { append text "[plsql_utility::parse_sql [lindex $pair 1]]\n\n" } # Now add the drop script append text "-- Drop script\n"; for { set i [expr {[llength $plsql_drop] - 1}] } { $i >= 0 } { set i [expr {$i - 1}] } { # Don't need the sql keys when we display debugging information append text "-- [lindex [lindex $plsql_drop $i] 1]\n\n" } return $text } foreach pair $plsql { db_exec_plsql [lindex $pair 0] [lindex $pair 1] } # The following create table statement commits the # transaction. If it fails, we roll back what we've done if { [catch {db_exec_plsql create_table " create table $table_name ( $id_column integer constraint $constraint(pk) primary key constraint $constraint(fk) references $references_table ($references_column) )"} errmsg] } { # Roll back our work so for for { set i [expr {[llength $plsql_drop] - 1}] } { $i >= 0 } { incr i -1 } { set pair [lindex $plsql_drop $i] if { [catch {db_exec_plsql [lindex $drop_pair 0] [lindex $drop_pair 1]} err_msg_2] } { append errmsg "\nAdditional error while trying to roll back: $err_msg_2" return -code error $errmsg } } return -code error $errmsg } # We need to add something to the group_types table, too! (Ben - OpenACS) db_dml insert_group_type {} # Finally, create the PL/SQL package. package_recreate_hierarchy $group_type return $group_type } } openacs-5.7.0/packages/acs-subsite/tcl/group-type-procs.xql0000644000175000017500000000127307340303237023546 0ustar frankiefrankie select upper(id_column) from acs_object_types where object_type='group' select t.table_name as references_table, t.id_column as references_column from acs_object_types t where t.object_type = :supertype insert into group_types (group_type) values (:group_type) openacs-5.7.0/packages/acs-subsite/tcl/approval-expiration-init.tcl0000644000175000017500000000114007732625445025240 0ustar frankiefrankiead_library { Sweep for expired user approvals. @cvs-id $Id: approval-expiration-init.tcl,v 1.3 2003/09/19 16:13:25 lars Exp $ @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-05-28 } set ApprovalExpirationDays [parameter::get -parameter ApprovalExpirationDays -package_id [ad_acs_kernel_id] -default 0] # Only schedule proc if we've set approvals to expire if { $ApprovalExpirationDays > 0 } { # Schedule proc to run once nightly ad_schedule_proc -thread t -schedule_proc ns_schedule_daily [list 0 0] subsite::sweep_expired_approvals -days $ApprovalExpirationDays } openacs-5.7.0/packages/acs-subsite/tcl/approval-expiration-procs.tcl0000644000175000017500000000151507723347123025423 0ustar frankiefrankiead_library { Sweep for expired user approvals. @cvs-id $Id: approval-expiration-procs.tcl,v 1.2 2003/08/28 09:41:39 lars Exp $ @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-05-28 } namespace eval subsite {} ##### # # subsite namespace # ##### ad_proc -private subsite::sweep_expired_approvals { {-days:required} } { Sweep for expired approvals and bump them to the 'needs approval' state. } { # We don't have a transaction, because it shouldn't cause any harm if we only get halfway through # Find the expired users set expired_user_ids [db_list select_expired_user_ids {}] foreach user_id $expired_user_ids { # Bump the state acs_user::change_state -user_id $user_id -state "needs approval" # We could've sent an email to the user, but we don't } } openacs-5.7.0/packages/acs-subsite/tcl/apm-callback-procs.tcl0000644000175000017500000001143211201401551023703 0ustar frankiefrankiead_library { Installation procs for email-image management @author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) } namespace eval subsite {} ad_proc -private subsite::package_install {} {} { set type_id [content::type::new -content_type "email_image" -pretty_name "Email_Image" \ -pretty_plural "Email_Images" -table_name "users_email_image" -id_column "email_image_id"] set folder_id [content::folder::new -name "Email_Images" -label "Email_Images"] content::folder::register_content_type -folder_id $folder_id -content_type "email_image" } ad_proc -private subsite::after_upgrade { {-from_version_name:required} {-to_version_name:required} } { After upgrade callback for acs-subsite. } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { 5.2.0d1 5.2.0d2 { set type_id [content::type::new -content_type "email_image" -pretty_name "Email_Image" \ -pretty_plural "Email_Images" -table_name "users_email_image" -id_column "email_image_id"] set folder_id [content::folder::new -name "Email_Images" -label "Email_Images"] content::folder::register_content_type -folder_id $folder_id -content_type "email_image" } 5.2.0a1 5.2.0a2 { set value [parameter::get -parameter "AsmForRegisterId" -package_id [subsite::main_site_id]] if {$value eq ""} { apm_parameter_register "AsmForRegisterId" "Assessment used on the registration process." "acs-subsite" "0" "number" "user-login" } apm_parameter_register "RegImplName" "Name of the implementation used in the registration process" "acs-subsite" "asm_url" "string" "user-login" } 5.2.0a1 5.2.0a2 { set value [parameter::get -parameter "RegistrationId" -package_id [subsite::main_site_id]] if {$value eq ""} { apm_parameter_register "RegistrationId" "Assessment used on the registration process." "acs-subsite" "0" "number" "user-login" } set value [parameter::get -parameter "RegistrationId" -package_id [subsite::main_site_id]] if {$value eq ""} { apm_parameter_register "RegistrationImplName" "Name of the implementation used in the registration process" "acs-subsite" "asm_url" "string" "user-login" } } 5.2.0a2 5.2.0a3 { db_transaction { db_foreach select_group_name {select group_id, group_name from groups} { if { ![empty_string_p [info procs "::lang::util::convert_to_i18n"]] } { set pretty_name [lang::util::convert_to_i18n -message_key "group_title_${group_id}" -text "$group_name"] } else { set pretty_name "$group_name" } db_dml title_update "update acs_objects set title=:pretty_name where object_id = :group_id" } } } 5.2.0a1 5.2.0a2 { set value [parameter::get -parameter "RegistrationId" -package_id [subsite::main_site_id]] if {$value eq ""} { apm_parameter_register "RegistrationId" "Assessment used on the registration process." "acs-subsite" "0" "number" "user-login" } set value [parameter::get -parameter "RegistrationId" -package_id [subsite::main_site_id]] if {$value eq ""} { apm_parameter_register "RegistrationImplName" "Name of the implementation used in the registration process" "acs-subsite" "asm_url" "string" "user-login" } } 5.2.0a2 5.2.0a3 { db_transaction { db_foreach select_group_name {select group_id, group_name from groups} { if { ![empty_string_p [info procs "::lang::util::convert_to_i18n"]] } { set pretty_name [lang::util::convert_to_i18n -message_key "group_title_${group_id}" -text "$group_name"] } else { set pretty_name "$group_name" } db_dml title_update "update acs_objects set title=:pretty_name where object_id = :group_id" } } } 5.5.0d7 5.5.0d8 { db_transaction { set package_keys ([join '[subsite::package_keys]' ,]) foreach subsite_id [db_list get_subsite_ids {}] { set new_css [list] set css [parameter::get \ -package_id $subsite_id \ -parameter ThemeCSS \ -default ""] if { $css ne "" } { foreach css $css { lappend new_css [list [list href [lindex $css 0]] \ [list media [lindex $css 1]]] } parameter::set_value \ -package_id $subsite_id \ -parameter ThemeCSS \ -value $new_css } } } } } } openacs-5.7.0/packages/acs-subsite/tcl/apm-callback-procs.xql0000644000175000017500000000040011201401551023716 0ustar frankiefrankie select package_id from apm_packages where package_key in $package_keys openacs-5.7.0/packages/acs-subsite/tcl/callback-procs.tcl0000644000175000017500000000235410640054134023142 0ustar frankiefrankiead_library { Callback definitions @author Jeff Davis @creation-date 2005-03-11 @cvs-id $Id: callback-procs.tcl,v 1.7 2007/06/26 00:05:48 donb Exp $ } ad_proc -public -callback user::workspace { -user_id } { used to generate html fragments for display on the /pvt/home page. The html fragment should have an h2 header for sectioning. @param user_id - the user to display @see callback::user::workspace::impl::acs-subsite } - ad_proc -public -callback user::workspace -impl acs-subsite { -user_id } { Generate a table showing the application group membership } { return [template::adp_include /packages/acs-subsite/lib/user-subsites [list user_id $user_id]] } ad_proc -public -callback user::registration { -package_id } { used to verify if there is another registration process. The implementation must return the url of the registration page. } - ad_proc -callback subsite::get_extra_headers { } { returns any further header stuff that needs to be added } - ad_proc -callback subsite::header_onload { } { returns any javascript function that needs to be loaded the callback implementation should simply do: return {your_function(params);} } - openacs-5.7.0/packages/acs-subsite/tcl/plsql-utility-procs-postgresql.xql0000644000175000017500000000066107275342305026476 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_object_types where object_type=:object_type) then 1 else 0 end openacs-5.7.0/packages/acs-subsite/tcl/rel-types-procs-oracle.xql0000644000175000017500000000314310250320302024602 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_object_types t where t.dynamic_p = 't' and t.object_type = :value) then 1 else 0 end from dual begin acs_rel_type.drop_type(:rel_type); end; begin acs_rel_type.create_type ( rel_type => :rel_type, supertype => :supertype, pretty_name => :pretty_name, pretty_plural => :pretty_plural, table_name => :table_name, id_column => 'rel_id', package_name => :package_name, object_type_one => :object_type_one, role_one => :role_one, min_n_rels_one => :min_n_rels_one, max_n_rels_one => :max_n_rels_one, object_type_two => :object_type_two, role_two => :role_two, min_n_rels_two => :min_n_rels_two, max_n_rels_two => :max_n_rels_two ); end; begin acs_rel_type.create_role(:role, :pretty_name, :pretty_plural); end; openacs-5.7.0/packages/acs-subsite/tcl/plpgsql-utility-procs-postgresql.xql0000644000175000017500000000115607611532706027025 0ustar frankiefrankie postgresql7.1 select arg_name, arg_default from acs_function_args where function = upper(:function_name) order by arg_seq select data_type from user_tab_columns where table_name = upper(:table) and column_name = upper(:column) openacs-5.7.0/packages/acs-subsite/tcl/plsql-utility-procs-oracle.xql0000644000175000017500000000067007275342305025540 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_object_types where object_type=:object_type) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/tcl/subsite-procs.tcl0000644000175000017500000007760111157574253023110 0ustar frankiefrankie# /packages/subsite/tcl/subsite-procs.tcl ad_library { Procs to manage application groups @author oumi@arsdigita.com @creation-date 2001-02-01 @cvs-id $Id: subsite-procs.tcl,v 1.43 2009/03/17 01:11:07 donb Exp $ } namespace eval subsite { namespace eval util {} namespace eval default {} } ad_proc -public subsite::after_mount { {-package_id:required} {-node_id:required} } { This is the TCL proc that is called automatically by the APM whenever a new instance of the subsites application is mounted. @author Don Baccus (dhogaza@pacifier.com) @creation-date 2003-03-05 } { subsite::default::create_app_group -package_id $package_id } ad_proc -public subsite::before_uninstantiate { {-package_id:required} } { Delete the application group associated with this subsite. } { subsite::default::delete_app_group -package_id $package_id } ad_proc -public subsite::before_upgrade { {-from_version_name:required} {-to_version_name:required} } { Handles upgrade } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { 5.0d3 5.0d4 { array set main_site [site_node::get -url /] set main_site_id $main_site(package_id) # Move parameter values from subsite to kernel parameter::set_value \ -package_id [ad_acs_kernel_id] \ -parameter ApprovalExpirationDays \ -value [parameter::get \ -package_id $main_site_id \ -parameter ApprovalExpirationDays \ -default 0] parameter::set_value \ -package_id [ad_acs_kernel_id] \ -parameter PasswordExpirationDays \ -value [parameter::get \ -package_id $main_site_id \ -parameter PasswordExpirationDays \ -default 0] apm_parameter_unregister \ -package_key acs-subsite \ -parameter ApprovalExpirationDays \ {} apm_parameter_unregister \ -package_key acs-subsite \ -parameter PasswordExpirationDays \ {} } } } ad_proc -public subsite::pivot_root { -node_id } { Pivot the package associated with node_id onto the root. Mounting the current root package under node_id. } { array set node [site_node::get -node_id $node_id] array set root [site_node::get -url "/"] db_transaction { site_node::unmount -node_id $node(node_id) site_node::unmount -node_id $root(node_id) site_node::mount -node_id $root(node_id) -object_id $node(package_id) site_node::mount -node_id $node(node_id) -object_id $root(package_id) #TODO: swap the application groups for the subsites so that #TODO: registered users is always the application group of the root #TODO: subsite. } } ad_proc -public subsite::default::create_app_group { -package_id {-name {}} } { Create the default application group for a subsite.
    • Create application group
    • Create segment "Subsite Users"
    • Create relational constraint to make subsite registration require supersite registration.
    } { if { [empty_string_p [application_group::group_id_from_package_id -no_complain -package_id $package_id]] } { array set node [site_node::get_from_object_id -object_id $package_id] set node_id $node(node_id) if { $name eq "" } { set subsite_name [db_string subsite_name_query {}] } else { set subsite_name $name } set truncated_subsite_name [string range $subsite_name 0 89] db_transaction { # Create subsite application group set group_name "$truncated_subsite_name" set subsite_group_id [application_group::new \ -package_id $package_id \ -group_name $group_name] # Create segment of registered users set segment_name "$truncated_subsite_name Members" set segment_id [rel_segments_new $subsite_group_id membership_rel $segment_name] # Create a constraint that says "to be a member of this subsite you must be a member # of the parent subsite. set subsite_id [site_node::closest_ancestor_package \ -node_id $node_id \ -package_key [subsite::package_keys]] db_1row parent_subsite_query {} set constraint_name "Members of [string range $subsite_name 0 30] must be members of [string range $supersite_name 0 30]" set user_id [ad_conn user_id] set creation_ip [ad_conn peeraddr] db_exec_plsql add_constraint {} # Create segment of registered users for administrators set segment_name "$truncated_subsite_name Administrators" set admin_segment_id [rel_segments_new $subsite_group_id admin_rel $segment_name] # Grant admin privileges to the admin segment permission::grant \ -party_id $admin_segment_id \ -object_id $package_id \ -privilege admin # Grant read/write/create privileges to the member segment foreach privilege { read create write } { permission::grant \ -party_id $segment_id \ -object_id $package_id \ -privilege $privilege } } } } ad_proc -public subsite::default::delete_app_group { -package_id } { Delete the default application group for a subsite. } { application_group::delete -group_id [application_group::group_id_from_package_id -package_id $package_id] } ad_proc -private subsite::instance_name_exists_p { node_id instance_name } { Returns 1 if the instance_name exists at this node. 0 otherwise. Note that the search is case-sensitive. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2001-03-01 } { return [db_string select_name_exists_p { select count(*) from site_nodes where parent_id = :node_id and name = :instance_name }] } ad_proc -public subsite::auto_mount_application { { -instance_name "" } { -pretty_name "" } { -node_id "" } package_key } { Mounts a new instance of the application specified by package_key beneath node_id. This proc makes sure that the instance_name (the name of the new node) is unique before invoking site_node::instantiate_and_mount. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2001-02-28 @param instance_name The name to use for the url in the site-map. Defaults to the package_key plus a possible digit to serve as a unique identifier (e.g. news-2) @param pretty_name The english name to use for the site-map and for things like context bars. Defaults to the name of the object mounted at this node + the package pretty name (e.g. Intranet News) @param node_id Defaults to [ad_conn node_id] @see site_node::instantiate_and_mount @return The package id of the newly mounted package } { if { $node_id eq "" } { set node_id [ad_conn node_id] } set ctr 2 if { $instance_name eq "" } { # Default the instance name to the package key. Add a number, # if necessary, until we find a unique name set instance_name $package_key while { [subsite::instance_name_exists_p $node_id $instance_name] } { set instance_name "$package_key-$ctr" incr ctr } } if { $pretty_name eq "" } { # Get the name of the object mounted at this node db_1row select_package_object_names { select t.pretty_name as package_name, acs_object.name(s.object_id) as object_name from site_nodes s, apm_package_types t where s.node_id = :node_id and t.package_key = :package_key } set pretty_name "$object_name $package_name" if { $ctr > 2 } { # This was a duplicate pkg name... append the ctr used in the instance name append pretty_name " [expr {$ctr - 1}]" } } return [site_node::instantiate_and_mount -parent_node_id $node_id \ -node_name $instance_name \ -package_name $pretty_name \ -package_key $package_key] } ad_proc -public subsite::package_keys { } { Get the list of packages which can be subsites. This is built during the bootstrap process. If you install a new subsite-implementing package and don't accept the installers invitation to reboot openacs, tough luck. @return the packages keys of all installed packages acting as subsites. } { return [nsv_get apm_subsite_packages_list package_keys] } ad_proc -public subsite::get { {-subsite_id {}} {-array:required} } { Get information about a subsite. @param subsite_id The id of the subsite for which info is requested. If no id is provided, then the id of the closest ancestor subsite will be used. @param array The name of an array in which information will be returned. @author Frank Nikolajsen (frank@warpspace.com) @creation-date 2003-03-08 } { upvar $array subsite_info if { $subsite_id eq "" } { set subsite_id [ad_conn subsite_id] } if { ![ad_conn isconnected] } { set package_id "" } else { set package_id [ad_conn package_id] } array unset subsite_info array set subsite_info [site_node::get_from_object_id -object_id $subsite_id] } ad_proc -public subsite::get_element { {-subsite_id {}} {-element:required} {-notrailing:boolean} } { Return a single element from the information about a subsite. @param subsite_id The node id of the subsite for which info is requested. If no id is provided, then the id of the closest ancestor subsite will be used. @param element The element you want, one of: directory_p object_type package_key package_id name pattern_p instance_name node_id parent_id url object_id @notrailing If true and the element requested is an url, then strip any trailing slash ('/'). This means the empty string is returned for the root. @return The element you asked for @author Frank Nikolajsen (frank@warpspace.com) @creation-date 2003-03-08 } { if { $subsite_id eq "" } { set subsite_id [ad_conn subsite_id] } subsite::get -subsite_id $subsite_id -array subsite_info set result $subsite_info($element) if { $notrailing_p && [string match $element "url"]} { set result [string trimright $result "/"] } return $result } ad_proc -public subsite::upload_allowed {} { Verifies SolicitPortraitP parameter to ensure upload portrait security. @author Hector Amado (hr_amado@galileo.edu) @creation-date 2004-06-16 } { set package_id [ad_conn subsite_id] if { ![parameter::get -package_id $package_id -parameter SolicitPortraitP -default 1] } { if { ![acs_user::site_wide_admin_p] } { ns_log notice "user is tried to see user/portrait/upload without permission" ad_return_forbidden \ "Permission Denied" \ "
    You don't have permission to see this page.
    " } } } ad_proc -public subsite::util::sub_type_exists_p { object_type } { @param object_type @return 1 if object_type has sub types, or 0 otherwise @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2000-02-07 } { return [db_string sub_type_exists_p { select case when exists (select 1 from acs_object_types where supertype = :object_type) then 1 else 0 end from dual }] } ad_proc -public subsite::util::object_type_path_list { object_type {ancestor_type acs_object} } { @return the object type heirarchy for the given object type from ancestor_type to object_type } { set path_list [list] set type_list [db_list select_object_type_path { select object_type from acs_object_types start with object_type = :object_type connect by object_type = prior supertype }] foreach type $type_list { lappend path_list $type if {$type eq $ancestor_type} { break } } return $path_list } ad_proc -public subsite::util::object_type_pretty_name { object_type } { returns pretty name of object. We need this so often that I thought I'd stick it in a proc so it can possibly be cached later. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2000-02-07 @param object_type } { return [db_string select_pretty_name { select pretty_name from acs_object_types where object_type = :object_type }] } ad_proc -public subsite::util::return_url_stack { return_url_list } { Given a list of return_urls, we recursively encode them into one return_url that can be redirected to or passed into a page. As long as each page in the list does the typical redirect to return_url, then the page flow will go through each of the pages in $return_url_list } { if {[llength $return_url_list] == 0} { error "subsite::util::return_url_stack - \$return_url_list is empty" } set first_url [lindex $return_url_list 0] set rest [lrange $return_url_list 1 end] # Base Case if {[llength $rest] == 0} { return $first_url } # More than 1 url was in the list, so recurse if {[string first ? $first_url] == -1} { append first_url ? } append first_url "&return_url=[ad_urlencode [return_url_stack $rest]]" return $first_url } ad_proc -public subsite::define_pageflow { {-sections_multirow "sections"} {-subsections_multirow "subsections"} {-section ""} {-url ""} } { Defines the page flow of the subsite TODO: add an image TODO: add link_p/selected_p for subsections } { set pageflow [get_pageflow_struct -url $url] if {$url eq ""} { set base_url [subsite::get_element -element url] } else { set base_url $url } template::multirow create $sections_multirow name label title url selected_p link_p template::multirow create $subsections_multirow name label title url selected_p link_p foreach { section_name section_spec } $pageflow { array set section_a { label {} url {} title {} subsections {} folder {} selected_patterns {} } array set section_a $section_spec set section_a(name) $section_name set selected_p [add_section_row \ -array section_a \ -base_url $base_url \ -multirow $sections_multirow] if { $selected_p } { foreach { subsection_name subsection_spec } $section_a(subsections) { array set subsection_a { label {} title {} folder {} url {} selected_patterns {} } array set subsection_a $subsection_spec set subsection_a(name) $subsection_name set subsection_a(folder) [file join $section_a(folder) $subsection_a(folder)] add_section_row \ -array subsection_a \ -base_url $base_url \ -multirow $subsections_multirow } } } } ad_proc -public subsite::add_section_row { {-array:required} {-base_url:required} {-multirow:required} {-section {}} } { Helper proc for adding rows of sections to the page flow of the subsite. @see subsite::define_pageflow } { upvar $array info # the folder index page is called . if { $info(url) eq "" || $info(url) eq "index" || \ [string match "*/" $info(url)] || [string match "*/index" $info(url)] } { set info(url) "[string range $info(url) 0 [string last / $info(url)]]." } if { [ad_conn node_id] == [site_node::closest_ancestor_package -include_self \ -package_key [subsite::package_keys] \ -url [ad_conn url]] } { set current_url [ad_conn extra_url] } else { # Need to prepend the path from the subsite to this package set current_url [string range [ad_conn url] [string length $base_url] end] } if { $current_url eq "" || $current_url eq "index" || \ [string match "*/" $current_url] || [string match "*/index" $current_url] } { set current_url "[string range $current_url 0 [string last / $current_url]]." } set info(url) [file join $info(folder) $info(url)] regsub {/\.$} $info(url) / info(url) # Default to not selected set selected_p 0 if { $current_url eq $info(url) || $info(name) eq $section } { set selected_p 1 } else { foreach pattern $info(selected_patterns) { set full_pattern [file join $info(folder) $pattern] if { [string match $full_pattern $current_url] } { set selected_p 1 break } } } set link_p [expr {$current_url ne $info(url) }] template::multirow append $multirow \ $info(name) \ $info(label) \ $info(title) \ [file join $base_url $info(url)] \ $selected_p \ $link_p return $selected_p } ad_proc -public subsite::get_section_info { {-array "section_info"} {-sections_multirow "sections"} } { Takes the sections_multirow and sets the passed array name with the elements label and url of the selected section. } { upvar $array row # Find the label of the selected section array set row { label {} url {} } template::multirow foreach $sections_multirow { if { [template::util::is_true $selected_p] } { set row(label) $label set row(url) $url break } } } ad_proc -public subsite::get_pageflow_struct { {-url ""} } { Defines the page flow structure. } { # This is where the page flow structure is defined set subsections [list] lappend subsections home { label "Home" url "" } set pageflow [list] if {$url eq ""} { set subsite_url [subsite::get_element -element url] } else { set subsite_url $url } set subsite_id [ad_conn subsite_id] array set subsite_sitenode [site_node::get -url $subsite_url] set subsite_node_id $subsite_sitenode(node_id) set index_redirect_url [parameter::get -parameter "IndexRedirectUrl" -package_id $subsite_id] set child_urls [lsort -ascii [site_node::get_children -node_id $subsite_node_id -package_type apm_application]] if { $index_redirect_url eq "" } { lappend pageflow home { label "Home" folder "" url "" selected_patterns { "" "subsites" } } } else { # See if the redirect-url to a package inside this subsite for { set i 0 } { $i < [llength $child_urls] } { incr i } { array set child_node [site_node::get_from_url -exact -url [lindex $child_urls $i]] if { $index_redirect_url eq $child_node(url) || [string equal ${index_redirect_url}/ $child_node(url)]} { lappend pageflow $child_node(name) [list \ label "Home" \ folder $child_node(name) \ url {} \ selected_patterns *] set child_urls [lreplace $child_urls $i $i] break } } } set user_id [ad_conn user_id] set admin_p [permission::permission_p \ -object_id [site_node::closest_ancestor_package -include_self \ -package_key [subsite::package_keys] \ -url [ad_conn url]] \ -privilege admin \ -party_id [ad_conn untrusted_user_id]] set show_member_list_to [parameter::get -parameter "ShowMembersListTo" -package_id $subsite_id -default 2] if { $admin_p || ($user_id != 0 && $show_member_list_to == 1) || \ $show_member_list_to == 0 } { lappend pageflow members { label "Members" folder "members" selected_patterns {*} } } foreach child_url $child_urls { array set child_node [site_node::get_from_url -exact -url $child_url] lappend pageflow $child_node(name) [list \ label $child_node(instance_name) \ folder $child_node(name) \ url {} \ selected_patterns *] } if { $admin_p } { lappend pageflow admin { label "Administration" url "admin/configure" selected_patterns { admin/* shared/parameters } subsections { configuration { label "Configuration" url "admin/configure" } applications { label "Applications" folder "admin/applications" url "" selected_patterns { * } } subsite_add { label "New Subsite" url "admin/subsite-add" } permissions { label "Permissions" url "admin/permissions" selected_patterns { permissions* } } parameters { label "Parameters" url "shared/parameters" } advanced { label "Advanced" url "admin/." selected_patterns { site-map/* groups/* group-types/* rel-segments/* rel-types/* host-node-map/* object-types/* } } } } } return $pageflow } ad_proc -public subsite::main_site_id {} { Get the package_id of the Main Site. The Main Site is the subsite that is always mounted at '/' and that has a number of site-wide parameter settings. @author Peter Marklund } { array set main_node [site_node::get_from_url -url "/"] return $main_node(object_id) } ad_proc -public subsite::get_theme_options {} { Gets options for subsite themes for use with a form builder select widget. } { db_foreach get_subsite_themes {} { lappend master_theme_options [list [lang::util::localize $name] $key] } return $master_theme_options } ad_proc -public subsite::set_theme { -subsite_id {-theme:required} } { Set the theme for the given subsite. This will change the subsite's ThemeKey, DefaultMaster, and ThemeCSS parameters. } { if { ![info exists subsite_id] } { set subsite_id [ad_conn subsite_id] } db_1row get_theme_paths {} parameter::set_value -parameter ThemeKey -package_id $subsite_id \ -value $theme parameter::set_value -parameter DefaultMaster -package_id $subsite_id \ -value $template parameter::set_value -parameter ThemeCSS -package_id $subsite_id \ -value $css parameter::set_value -parameter DefaultFormStyle -package_id $subsite_id \ -value $form_template parameter::set_value -parameter DefaultListStyle -package_id $subsite_id \ -value $list_template parameter::set_value -parameter DefaultListFilterStyle -package_id $subsite_id \ -value $list_filter_template } ad_proc -public subsite::new_subsite_theme { -key:required -name:required -template:required {-css ""} {-form_template ""} {-list_template ""} {-list_filter_template ""} } { Add a new subsite theme, making it available to the theme configuration code. } { db_dml insert_subsite_theme {} } ad_proc -public subsite::delete_subsite_theme { -key:required } { Delete a subsite theme, making it unavailable to the theme configuration code. } { db_dml delete_subsite_theme {} } ad_proc -public subsite::get_application_options {} { Gets options list for applications to install } { set subsite_package_keys [join '[subsite::package_keys]' ","] return [db_list_of_lists package_types {}] } ad_proc -private subsite::assert_user_may_add_member {} { Used on pages that add users to the application group of the current subsite to assert that the currently logged in user may add users. @author Peter Marklund } { auth::require_login set group_id [application_group::group_id_from_package_id] set admin_p [permission::permission_p -object_id $group_id -privilege "admin"] if { !$admin_p } { # If not admin, user must be member of group, and members must be allowed to invite other members if { ![parameter::get -parameter "MembersCanInviteMembersP" -default 0] || \ ![group::member_p -group_id $group_id] } { ad_return_forbidden "Cannot invite members" "I'm sorry, but you're not allowed to invite members to this group" ad_script_abort } } } ad_proc -public subsite::get_url { {-node_id ""} {-absolute_p 0} {-force_host ""} {-strict_p 0} {-protocol ""} {-port ""} } { Returns the url stub for the specified subsite. If -absolute is supplied then this function will generate absolute urls. If the site is currently being accessed via a host node mapping or -force_host_node_map is also supplied then URLs will ommit the corresponding subsite url stub. The host name will be used for any appropriate subsite when absolute urls are generated. @param node_id the subsite's node_id (defaults to nearest subsite node). @param absolute_p whether to include the host in the returned url. @param force_host_node_map_p whether to produce host node mapped urls regardless of the current connection state } { if {[ad_conn isconnected]} { if {$node_id eq ""} { set node_id [ad_conn subsite_node_id] } array set subsite_node [site_node::get -node_id $node_id] set main_host [ns_config \ "ns/server/[ns_info server]/module/nssock" \ Hostname] util_driver_info -array request set headers [ns_conn headers] set host_addr [split [ns_set iget $headers host] :] set request(vhost) [lindex $host_addr 0] if {[lindex $host_addr 1] ne "" } { set request(port) [lindex $host_addr 1] } set request_vhost_p [expr {$main_host ne $request(vhost) }] } else { if {$node_id eq ""} { error "You must supply node_id when not connected." } else { array set subsite_node [site_node::get -node_id $node_id] } set request_vhost_p 0 } set default_port(http) 80 set default_port(https) 443 set force_host_p [expr {$force_host ne "" }] set force_protocol_p [expr {$protocol ne "" }] if {!$force_protocol_p} { set protocol http } set force_port_p [expr {$port ne "" }] if {!$force_port_p} { set port 80 } set result "" if {$request_vhost_p || $force_host_p} { set root_p [string equal $subsite_node(parent_id) ""] set search_vhost $force_host set mapped_vhost "" set where_clause [db_map strict_search] # Figure out which hostname to use if {!$force_host_p} { set search_vhost $request(vhost) } elseif {$force_host eq "any"} { if {$request_vhost_p} { set search_vhost $request(vhost) set where_clause [db_map orderby] } else { set where_clause [db_map simple_search] } } # TODO: This should be cached set site_node $subsite_node(node_id) set mapped_vhost [db_string get_vhost {} -default ""] if {$root_p && $mapped_vhost eq ""} { if {$strict_p} { error "$search_vhost is not mapped to this subsite or any of its parents." } if {$search_vhost eq "any"} { set mapped_vhost $main_host } else { set mapped_vhost $search_vhost } } if {$mapped_vhost eq ""} { set result "[subsite::get_url \ -node_id $subsite_node(parent_id) \ -absolute_p $absolute_p \ -strict_p $strict_p \ -force_host $force_host]$subsite_node(name)/" } else { if {[ad_conn isconnected] && [string equal $mapped_vhost $request(vhost)]} { if {!$force_protocol_p} { set protocol $request(proto) } if {!$force_port_p} { set port $request(port) } } if {$absolute_p} { set result "${protocol}://${mapped_vhost}" if {$port ne $default_port($protocol) } { append result ":$port" } append result "/" } else { set result "/" } } } else { if {$absolute_p} { set result "${protocol}://${main_host}" if {$port ne $default_port($protocol) } { append result ":$port" } append result "/" } append result "$subsite_node(url)" } return $result } ad_proc -private subsite::util::packages_no_mem { -node_id } { return a list of package_id's for children of the passed node_id @author Jeff Davis davis@xarg.net @creation-date 2004-05-07 @see subsite::util::packages } { # need to strip nodes which have no mounted package... set packages [list] foreach package [site_node::get_children -all -node_id $node_id -element package_id] { if {$package ne ""} { lappend packages $package } } return $packages } ad_proc -public subsite::util::packages { -node_id } { Return a list of package_id's for the subsite containing node_id This is a memoized function which caches for 20 minutes. @author Jeff Davis davis@xarg.net @creation-date 2004-05-07 @see subsite::util::packages_no_mem } { set subsite_node_id [site_node::closest_ancestor_package \ -package_key [subsite::package_keys] \ -node_id $node_id \ -include_self \ -element node_id] return [util_memoize [list subsite::util::packages_no_mem -node_id $subsite_node_id] 1200] } ad_proc -public subsite::util::get_package_options { } { Get a list of pretty name, package key pairs for all packages which identify themselves as implementing subsite semantics. @return a list of pretty name, package key pairs suitable for use in a template select widget. } { return [db_list_of_lists get {}] } openacs-5.7.0/packages/acs-subsite/tcl/subsite-procs.xql0000644000175000017500000000561511157574253023126 0ustar frankiefrankie select 1 from dual where exists (select 1 from application_groups where package_id = :package_id) select instance_name from apm_packages where package_id = :package_id select m.group_id as supersite_group_id, p.instance_name as supersite_name from application_groups m, apm_packages p, site_nodes s1, site_nodes s2 where s1.node_id = :node_id and s2.node_id = s1.parent_id and p.package_id = s2.object_id and m.package_id = :subsite_id select count(*) from site_nodes where parent_id = :node_id and name = :instance_name select pretty_name from acs_object_types where object_type = :object_type select host from host_node_map where node_id = :node_id $where_clause and host = :search_vhost select name, key from subsite_themes insert into subsite_themes (key, name, template, css, form_template, list_template, list_filter_template) values (:key, :name, :template, :css, :form_template, :list_template, :list_filter_template) delete from subsite_themes where key = :key select * from subsite_themes where key = :theme select pretty_name, package_key from apm_package_types where implements_subsite_p = 't' order by pretty_name openacs-5.7.0/packages/acs-subsite/tcl/acs-subsite-init.tcl0000644000175000017500000000171207537470223023456 0ustar frankiefrankiead_library { Initializes mappings of package directories to URLs. @cvs-id $Id: acs-subsite-init.tcl,v 1.2 2002/09/10 22:22:11 jeffd Exp $ @author Richard Li @creation-date 12 August 2000 } # /www # rp_register_directory_map pvt acs-core-ui pvt # rp_register_directory_map user acs-core-ui user # rp_register_directory_map register acs-core-ui register # rp_register_directory_map shared acs-core-ui shared # rp_register_directory_map permissions acs-core-ui permissions # /admin/www # rp_register_directory_map categories acs-core-ui categories # rp_register_directory_map content-tagging acs-core-ui content-tagging # rp_register_directory_map orgs acs-core-ui orgs # rp_register_directory_map users acs-core-ui users # rp_register_directory_map subsites acs-core-ui subsites # rp_register_directory_map object-types acs-core-ui object-types # security filters # ad_register_filter -sitewide preauth * "/doc/*" ad_restrict_to_administrator openacs-5.7.0/packages/acs-subsite/tcl/group-procs-oracle.xql0000644000175000017500000000275310531357073024041 0ustar frankiefrankie oracle8.1.6 BEGIN -- the acs_group package takes care of segments referred -- to by rel_constraints.rel_segment. We delete the ones -- references by rel_constraints.required_rel_segment here. for row in (select cons.constraint_id from rel_constraints cons, rel_segments segs where segs.segment_id = cons.required_rel_segment and segs.group_id = :group_id) loop rel_segment.del(row.constraint_id); end loop; -- delete the actual group ${package_name}.del(:group_id); END; select acs_group.member_p(:user_id,:group_id, :cascade) from dual select role.pretty_name, gr.rel_type from group_rels gr, acs_rel_types rt, acs_rel_roles role where gr.group_id = :group_id and rt.rel_type = gr.rel_type and role.role = rt.role_two and rt.object_type_two = :object_type order by decode(gr.rel_type, 'membership_rel', 0, 1)||role.pretty_name openacs-5.7.0/packages/acs-subsite/tcl/plsql-utility-procs.tcl0000644000175000017500000002035110551254376024252 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/plsql-utility-procs.tcl ad_library { Procs to help generate pl/sql dynamically @author mbryzek@arsdigita.com @creation-date Thu Dec 7 10:31:56 2000 @cvs-id $Id: plsql-utility-procs.tcl,v 1.2 2007/01/10 21:22:06 gustafn Exp $ } namespace eval plsql_utility { ad_proc -public generate_constraint_name { { -max_length 30 } table column stem } { Generates a constraint name adhering to the arsdigita standard for naming constraints. Note that this function does not yet ensure that the returned constraint name is not already in use, though the probability for a collision is pretty low. The ideal name is table_column_stem. We trim first table, then column to make it fit. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set max_length_without_stem [expr $max_length - [expr {[string length $stem] + 1}]] set text "${table}_$column" if { [string length $text] > $max_length_without_stem } { set text "" # Pull out the initials of the table name foreach piece [split $table "_"] { append text [lindex [split $piece ""] 0] } append text "_$column" } return [string toupper "[string range $text 0 [expr {$max_length_without_stem - 1}]]_$stem"] } ad_proc -public object_type_exists_p { object_type } { Returns 1 if the specified object_type exists. 0 otherwise. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { return [db_string object_type_exists_p { select case when exists (select 1 from acs_object_types where object_type=:object_type) then 1 else 0 end from dual }] } ad_proc -public format_pieces { { -indent 6 } { -num_spaces 3 } { -delim "" } { -line_term "," } pieces } { Proc to format a list of elements. This is used to generate nice error/debugging messages when we are executing things like pl/sql. Pieces is a list of lists where each element is a key value pair.

    Example:

    plsql_utility::format_pieces -indent 3 -delim " => " \
    	[list [list object_type group] [list group_id -2] [list group_name "Reg users"]]
    
    returns:
    object_type    => group,
       group_id       => -2,
       group_name     => Reg users
    
    @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 @param pieces a list of lists where each element is a key/value pair } { # Find max length of first column set max_length -1 foreach pair $pieces { if { [string length [lindex $pair 0]] > $max_length } { set max_length [string length [lindex $pair 0]] } } if { $max_length == -1 } { # no elements... return return "" } set indent_text "" for { set i 0 } { $i < $indent } { incr i } { append indent_text " " } # Generate text set text "" set col_width [expr {$max_length + $num_spaces}] foreach pair $pieces { set left [lindex $pair 0] set right [lindex $pair 1] while { [string length $left] < $col_width } { append left " " } if { $text ne "" } { append text "$line_term\n$indent_text" } append text "${left}${delim}${right}" } return $text } ad_proc -public generate_oracle_name { { -max_length 30 } { -include_object_id "f" } stem } { Returns an object name of max_length characters, in lower case, beginning with stem but without any unsafe characters. Only allowed characters are numbers, letter, underscore, dash and space, though the returned word will start with a letter. Throws an error if no safe name could be generated. To almost guarantee uniqueness, you can use the next object_id from acs_object_id_seq as the tail of the name we return. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { if { $include_object_id eq "t" } { set id [db_nextval "acs_object_id_seq"] set suffix "_$id" } else { set suffix "" } # Leave only letters, numbers, underscores, dashes, and spaces regsub -all {[^ _\-a-z0-9]} [string tolower $stem] "" stem # Make sure it starts with a letter regsub {^[^a-z]} $stem "" stem # change spaces to underscores regsub -all {\s+} $stem "_" stem #Trim to fit in $max_length character limit set max_length_without_suffix [expr {$max_length - [string length $suffix]}] if { [string length $stem] >= $max_length_without_suffix } { set stem [string range $stem 0 [expr {$max_length_without_suffix - 1}]] } if { $stem eq "" } { error "generate_oracle_name failed to generate a safe oracle name from the stem \"$stem\"\n" } return "$stem$suffix" } ad_proc -public parse_sql { sql_query } { Replaces bind variables with their Double Apos'd values to aid in debugging. Throws error if any bind variable is undefined in the calling environment.

    Limits: Only handles letter, numbers, and _ or - in bind variable names

    Example:

    set group_id -2
    set sql "select acs_group.name(:group_id) from dual"
    ns_write [plsql_utility::parse_sql $sql]
    
    would write the following to the browser:
    select acs_group.name('-2') from dual
    
    @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { while { 1 } { if { ![regexp -- {:([a-zA-Z0-9_-]+)} $sql_query match var] } { break } # Use $var as the target to get nice error messages upvar 1 $var $var if { ![info exists $var] } { error "Cannot find value for bind variable \"$var\"\n\n" } regsub -- "\:$var" $sql_query '[DoubleApos [set $var]]' sql_query } return $sql_query } ad_proc -public generate_attribute_parameters { { -indent "9" } attr_list } { Generates the arg list to a pl/sql function or procedure @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set pieces [list] foreach triple $attr_list { set table [string toupper [string trim [lindex $triple 0]]] set attr [string toupper [string trim [lindex $triple 1]]] if { [empty_string_p [lindex $triple 2]] } { set default_string "" } else { set default_string " DEFAULT [lindex $triple 2]" } lappend pieces [list "$attr" "IN ${table}.${attr}%TYPE${default_string}"] } return [format_pieces -indent $indent $pieces] } ad_proc -public generate_attribute_parameter_call_from_attributes { { -prepend "" } { -indent "9" } attr_list } { Wrapper for generate_attribute_parameter_call that formats default attribute list to the right format. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set the_list [list] foreach row $attr_list { lappend the_list [list [lindex $row 1] [lindex $row 3]] } return [generate_attribute_parameter_call -prepend $prepend -indent $indent $the_list] } ad_proc -public generate_attribute_parameter_call { { -prepend "" } { -indent "9" } pairs } { Generates the arg list for a call to a pl/sql function or procedure @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set pieces [list] foreach row $pairs { set attr [string trim [lindex $row 0]] set attr_value [string trim [lindex $row 1]] if { $attr_value eq "" } { set attr_value $attr } lappend pieces [list "$attr" "$prepend$attr_value"] } return [format_pieces -delim " => " -indent $indent $pieces] } ad_proc -public generate_attribute_dml { { -start_with_comma "t" } { -prepend "" } { -ignore "" } table_name attr_list } { Generates the string for a sql insert... e.g. ",col1, col2" @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set ignore [string toupper $ignore] set this_columns [list] set table_name [string toupper [string trim $table_name]] foreach triple $attr_list { set table [string toupper [string trim [lindex $triple 0]]] set column [string toupper [string trim [lindex $triple 1]]] if { [lsearch -exact $ignore [string toupper $column]] != -1 } { # Ignore this column continue } if {$table eq $table_name} { lappend this_columns "$prepend$column" } } if { [llength $this_columns] == 0 } { return "" } set return_value [join $this_columns ", "] if { $start_with_comma eq "t" } { return ", $return_value" } return $return_value } } openacs-5.7.0/packages/acs-subsite/tcl/party-procs-oracle.xql0000644000175000017500000000256707344173262024053 0ustar frankiefrankie oracle8.1.6 (object_type = 'group' or object_type = 'person') object_type = :start_with select types.pretty_name, types.object_type, types.tree_level, types.indent, case when valid_types.object_type = null then 0 else 1 end as valid_p from (select t.pretty_name, t.object_type, level as tree_level, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent, rownum as tree_rownum from acs_object_types t connect by prior t.object_type = t.supertype start with $start_with_clause ) types, (select object_type from rel_types_valid_obj_two_types where rel_type = :rel_type ) valid_types where types.object_type = valid_types.object_type(+) order by tree_rownum openacs-5.7.0/packages/acs-subsite/tcl/plpgsql-utility-procs.tcl0000644000175000017500000000773710551254376024616 0ustar frankiefrankiead_library { Procs to help generate pl/pgsql dynamically @author swoodcock@scholastic.co.uk @creation-date Sun Jul 22 13:51:26 BST 2001 @cvs-id $Id: plpgsql-utility-procs.tcl,v 1.4 2007/01/10 21:22:06 gustafn Exp $ } namespace eval plpgsql_utility { ad_proc -public generate_attribute_parameter_call_from_attributes { { -prepend "" } function_name attr_list } { Wrapper for generate_attribute_parameter_call that formats default attribute list to the right format. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set the_list [list] foreach row $attr_list { lappend the_list [list [lindex $row 1] [lindex $row 3]] } return [generate_attribute_parameter_call -prepend $prepend $function_name $the_list] } ad_proc -private get_function_args {function_name} { uncached version returns list of lists args called from generate_attribute_parameter_call } { return [db_list_of_lists get_function_args {}] } ad_proc -public generate_attribute_parameter_call { { -prepend "" } function_name pairs } { Generates the arg list for a call to a pl/pgsql function @author Steve Woodcock (swoodcock@scholastic.co.uk) @creation-date 07/2001 } { # Get the list of real args to the function set real_args [util_memoize [list plpgsql_utility::get_function_args $function_name]] foreach row $pairs { set attr [string trim [lindex $row 0]] set user_supplied([string toupper $attr]) $attr } # For each real arg, append default or supplied arg value set pieces [list] foreach row $real_args { set arg_name [lindex $row 0] set arg_default [lindex $row 1] if { [info exists user_supplied($arg_name)] } { lappend pieces "${prepend}$user_supplied($arg_name)" } else { if { $arg_default eq "" } { lappend pieces "NULL" } else { lappend pieces "'[db_quote $arg_default]'" } } } return [join $pieces ","] } ad_proc -public table_column_type { table column } { Returns the datatype for column in table @author Steve Woodcock (swoodcock@scholastic.co.uk) @creation-date 07/2001 } { return [db_string fetch_type {}] } ad_proc -public generate_attribute_parameters { { -indent "4" } attr_list } { Generates the arg list to a pl/sql function or procedure @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 11/2000 } { set pieces [list] set arg_num 0 foreach triple $attr_list { incr arg_num set attr [string toupper [string trim [lindex $triple 1]]] lappend pieces [list "p_${attr}" "alias for \$${arg_num}"] } return [plsql_utility::format_pieces -indent $indent -line_term ";" $pieces] } ad_proc -public generate_function_signature { attr_list } { Generates the signature for a pl/sql function or procedure @author Steve Woodcock (swoodcock@scholastic.co.uk) @creation-date 07/2001 } { set pieces [list] foreach triple $attr_list { set table [string toupper [string trim [lindex $triple 0]]] set attr [string toupper [string trim [lindex $triple 1]]] set datatype [table_column_type $table $attr] lappend pieces $datatype } return [join $pieces ","] } ad_proc -public dollar { } { Return a literal dollar for use in .xql files. } { return "$" } ad_proc -public define_function_args { attr_list } { Returns the attribute list as a string suitable for a call to define_function_args. @author Steve Woodcock (swoodcock@scholastic.co.uk) @creation-date 07/2001 } { set pieces [list] foreach triple $attr_list { set attr [string trim [lindex $triple 1]] set dft [string trim [lindex $triple 2]] if { $dft eq "" || $dft eq "NULL" } { set default "" } else { if { [string index $dft 0] eq "'" } { set dft [string range $dft 1 [expr {[string length $dft] - 2}]] } set default ";${dft}" } lappend pieces "${attr}${default}" } return [join $pieces ","] } } openacs-5.7.0/packages/acs-subsite/tcl/rel-segments-procs-oracle.xql0000644000175000017500000000176707736271233025324 0ustar frankiefrankie oracle8.1.6 declare begin :1 := rel_segment.new(segment_name => :segment_name, group_id => :group_id, context_id => :context_id, rel_type => :rel_type, creation_user => :creation_user, creation_ip => :creation_ip ); end; begin rel_constraint.del(:constraint_id); end; begin rel_segment.del(:segment_id); end; openacs-5.7.0/packages/acs-subsite/tcl/approval-expiration-procs-oracle.xql0000644000175000017500000000101507723347123026703 0ustar frankiefrankie oracle8.1.6 select u.user_id from cc_users u, acs_objects relo where relo.object_id = u.rel_id and last_visit < sysdate - :days and relo.last_modified < sysdate - :days and u.member_state = 'approved' openacs-5.7.0/packages/acs-subsite/tcl/application-group-procs-oracle.xql0000644000175000017500000000567011141414435026335 0ustar frankiefrankie oracle8.1.6 select case when exists ( select 1 from application_group_element_map where package_id = :package_id and element_id = :party_id union all select 1 from application_groups where package_id = :package_id and group_id = :party_id ) then 1 else 0 end from dual select case when exists ( select 1 from application_group_element_map where package_id = :package_id and element_id = :party_id union all select 1 from application_groups where package_id = :package_id and group_id = :party_id ) then 1 else 0 end from dual select case when exists ( select 1 from application_group_element_map where package_id = :package_id and rel_id = :rel_id ) then 1 else 0 end from dual select case when exists ( select 1 from application_group_segments where package_id = :package_id and segment_id = :segment_id ) then 1 else 0 end from dual begin :1 := application_group.group_id_from_package_id ( package_id => :package_id, no_complain_p => :no_complain_p ); end; begin :1 := application_group.new ( group_id => :group_id, object_type => :group_type, group_name => :group_name, package_id => :package_id, context_id => :package_id, creation_user => :creation_user, creation_ip => :creation_ip, email => :email, url => :url, join_policy => null ); end; begin application_group.del ( group_id => :group_id ); end; openacs-5.7.0/packages/acs-subsite/tcl/application-group-procs-postgresql.xql0000644000175000017500000000521311141414435027264 0ustar frankiefrankie postgresql7.1 select case when exists ( select 1 from application_group_element_map where package_id = :package_id and element_id = :party_id union all select 1 from application_groups where package_id = :package_id and group_id = :party_id ) then 1 else 0 end select case when exists ( select 1 from application_group_element_map where package_id = :package_id and element_id = :party_id union all select 1 from application_groups where package_id = :package_id and group_id = :party_id ) then 1 else 0 end select case when exists ( select 1 from application_group_element_map where package_id = :package_id and rel_id = :rel_id ) then 1 else 0 end select case when exists ( select 1 from application_group_segments where package_id = :package_id and segment_id = :segment_id ) then 1 else 0 end select application_group__group_id_from_package_id ( :package_id, :no_complain_p ) select application_group__new ( :group_id, :group_type, now(), :creation_user, :creation_ip, :email, :url, :group_name, :package_id, null, :package_id ) select application_group__delete ( :group_id ) openacs-5.7.0/packages/acs-subsite/tcl/subsite-callback-procs-postgresql.xql0000644000175000017500000000117407403013337027043 0ustar frankiefrankie postgresql7.1 select distinct callback, callback_type from subsite_callbacks where object_type in (select t2.object_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey <= t1.tree_sortkey and t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t1.object_type = :object_type) and event_type = :event_type openacs-5.7.0/packages/acs-subsite/tcl/package-procs.tcl0000644000175000017500000007647411456662501023030 0ustar frankiefrankie# /packages/mbryzek-subsite/tcl/package-procs.tcl ad_library { Procs to help build PL/SQL packages @author mbryzek@arsdigita.com @creation-date Wed Dec 27 16:02:44 2000 @cvs-id $Id: package-procs.tcl,v 1.25 2010/10/17 21:06:09 donb Exp $ } ad_proc -public package_type_dynamic_p { object_type } { Returns 1 if the object type is dynamic. 0 otherwise @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/30/2000 } { return [db_string object_type_dynamic_p { select case when exists (select 1 from acs_object_types t where t.dynamic_p = 't' and t.object_type = :object_type) then 1 else 0 end from dual }] } ad_proc -private package_create_attribute_list { { -supertype "" } { -object_name "" } { -limit_to "" } { -table "" } { -column "" } { -column_value "" } object_type } { Generates the list of attributes for this object type. Each element in the list is (table_name, column_name, default_value, column_value) where default_value and column_value are optional. Note that if either of table_name, id_column is unspecified, we retrieve the values for both from the acs_object_types table @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param supertype The supertype of the object we are creating. If specified, along with object_name, we lookup the parameters to supertype.object_name and include any missing parameters in our argument list. @param object_name The name of the function / procedure we are creating. See supertype for explanation. @param limit_to If empty, this argument is ignored. Otherwise, it is a list of all the columns to be included in the attribute list. Any attribute whose column_name is not in this list is then ignored. @param table The table_name for this object_type (from the acs_object_types tables) @param column The id_column for this object_type (from the acs_object_types tables) @param column_value The value for this column in the present calling function. Useful when you are calling supertype function and need to refer to the supertype argument by a different name locally. @param object_type The object type for which we are generating attributes } { if { $table eq "" || $column eq "" } { # pull out the table and column names based on the object type db_1row select_type_info { select t.table_name as table, t.id_column as column from acs_object_types t where t.object_type = :object_type } } # set toupper for case-insensitive searching set limit_to [string toupper $limit_to] # For the actual package spec and body, we build up a list of # the arguments and use a helper proc to generate the actual # pl/sql code. Note that the helper procs also return nicely # formatted pl/sql code set attr_list [list] # Start with the primary key for this object type. Continuing with # convention that id_column can be null (will default to new # object_id) lappend attr_list [list $table "$column" NULL $column_value] # the all_attributes array is used to ensure we do not have # duplicate column names set all_attributes([string toupper $column]) 1 if { $column_value ne "" } { # column value is the same physical column as $column - just # named differently in the attribute list. We still don't want # duplicates set all_attributes([string toupper $column_value]) 1 } # Now, loop through and gather all the attributes for this object # type and all its supertypes in order starting with this object # type up the type hierarchy db_foreach select_all_attributes { select upper(nvl(attr.table_name,t.table_name)) as attr_table_name, upper(nvl(attr.column_name, attr.attribute_name)) as attr_column_name, attr.ancestor_type, attr.min_n_values, attr.default_value from acs_object_type_attributes attr, (select t.object_type, t.table_name, level as type_level from acs_object_types t start with t.object_type = :object_type connect by prior t.supertype = t.object_type) t where attr.ancestor_type = t.object_type and attr.object_type = :object_type order by t.type_level } { # First make sure the attribute is okay if { $limit_to ne "" } { # We have a limited list of arguments to use. Make sure # this attribute is one of them if { [lsearch -exact $limit_to $attr_column_name] == -1 } { # This column is not in the list of allowed # columns... ignore continue } } set default [package_attribute_default \ -min_n_values $min_n_values \ -attr_default $default_value \ $object_type $attr_table_name $attr_column_name] lappend attr_list [list $attr_table_name $attr_column_name $default] set all_attributes($attr_column_name) 1 } if { $supertype ne "" && $object_name ne "" } { foreach row [util_memoize "package_table_columns_for_type \"$supertype\""] { set table_name [lindex $row 0] set column_name [lindex $row 1] # Note that limit_to doesn't apply here as we always need # to include these arguments else the call will fail if { [info exists all_attributes($column_name)] } { continue } set all_attributes($column_name) 1 set default [package_attribute_default $object_type $table_name $column_name] lappend attr_list [list $table_name $column_name $default] } } return $attr_list } ad_proc -private package_attribute_default { { -min_n_values "0" } { -attr_default "" } object_type table column } { Returns a sql value to be used as the default in a pl/sql function or procedure parameter list. This is a special case, hardcoded function that specifies defaults for standard acs_object attributes. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/28/2000 @param object_type The object type that owns the attribute we are using. Used only to set a default for acs_object.object_type stored (either table_name from the attribute or for the object_type) @param table The table in which the value of this attribute is stored (either table_name from the attribute or for the object_type) @param column The column in which the value of this attribute is stored (either column_name or attribute_name from the attributes table) @param min_n_values Used to determine if an argument is required (e.g. required = min_n_values != 0) @param attr_default The default values for this attribute as specified in the attributes table. } { # We handle defaults grossly here, but I don't currently have # a better idea how to do this if { $attr_default ne "" } { return "'[DoubleApos $attr_default]'" } # Special cases for acs_object and acs_rels # attributes. Default case sets default to null unless the # attribute is required (min_n_values > 0) if {$table eq "ACS_OBJECTS"} { switch -- $column { "OBJECT_TYPE" { return "'[DoubleApos $object_type]'" } "CREATION_DATE" { return [db_map creation_date] } "CREATION_IP" { return "NULL" } "CREATION_USER" { return "NULL" } "LAST_MODIFIED" { return [db_map last_modified] } "MODIFYING_IP" { return "NULL" } } } elseif {$table eq "ACS_RELS"} { switch -- $column { "REL_TYPE" { return "'[DoubleApos $object_type]'" } } } # return to null unless this attribute is required # (min_n_values > 0) return [ad_decode $min_n_values 0 "NULL" ""] } ad_proc -public package_recreate_hierarchy { object_type } { Recreates all the packages for the hierarchy starting with the specified object type down to a leaf. Resets the package_object_view cache. Note: Only updates packages for dynamic objects (those with dynamic_p set to t) @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/28/2000 @param object_type The object type for which to recreate packages, including all children types. } { set object_type_list [db_list select_object_types { select t.object_type from acs_object_types t where t.dynamic_p = 't' start with t.object_type = :object_type connect by prior t.object_type = t.supertype }] # Something changed... flush the data dictionary cache for the # type hierarchy starting with this object's type. Note that we # flush the cache in advance to reuse it when generating future packages # for object_types in the same level of the hierarchy. Note also that # maintaining this cache only gives us a few hits in the cache in # the degenerate case (one subtype), but the query we're caching # is dreadfully slow because of data dictionary tables. So # ensuring we only run the query once significantly improves # performance. -mbryzek foreach object_type $object_type_list { if { [util_memoize_cached_p "package_table_columns_for_type \"$object_type\""] } { util_memoize_flush "package_table_columns_for_type \"$object_type\"" } } foreach type $object_type_list { package_create $type } } ad_proc -private package_create { { -debug_p "f" } object_type } { Creates a packages with a new function and delete procedure for the specified object type. This function uses metadata exclusively to create the package. Resets the package_object_view cache Throws an error if the specified object type does not exist or is not dynamic @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/27/2000 @param object_type The object type for which to create a package @param debug_p If "t" then we return a text block containing the sql to create the package. Setting debug_p to t will not create the package. } { if { ![package_type_dynamic_p $object_type] } { error "The specified object, $object_type, either does not exist or is not dynamic. Therefore, a package cannot be created for it" } # build up a list of the pl/sql to execute as it will make it # easier to return a string for debugging purposes. set package_name [db_string select_package_name { select t.package_name from acs_object_types t where t.object_type = :object_type }] lappend plsql [list "package" "create_package" [package_generate_spec $object_type]] lappend plsql [list "package body" "create_package_body" [package_generate_body $object_type]] if { $debug_p eq "t" } { foreach pair $plsql { # append text "[plsql_utility::parse_sql [lindex $pair 1]]\n\n" append text [lindex $pair 2] } return $text } foreach pair $plsql { set type [lindex $pair 0] set stmt_name [lindex $pair 1] set code [lindex $pair 2] db_exec_plsql $stmt_name $code # Let's check to make sure the package is valid if { ![db_string package_valid_p { select case when exists (select 1 from user_objects where status = 'INVALID' and object_name = upper(:package_name) and object_type = upper(:type)) then 0 else 1 end from dual }] } { error "$object_type \"$package_name\" is not valid after compiling:\n\n$code\n\n" } } # Now reset the object type view in case we've cached some attribute queries package_object_view_reset $object_type # Return the object type - what else to return? return $object_type } ad_proc -private package_generate_spec { object_type } { Generates pl/sql to create a package specification. Does not execute the pl/sql - simply returns it. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 @param object_type The object for which to create a package spec } { # First pull out some basic information about this object type db_1row select_type_info { select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type } return [db_map spec] } ad_proc -private package_generate_body { object_type } { Generates plsql to create the package body @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 @param object_type The name of the object type for which we are creating the package } { # Pull out information about this object type db_1row select_type_info { select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type } # Pull out information about the supertype db_1row select_type_info { select t.table_name as supertype_table_name, t.id_column as supertype_id_column, lower(t.package_name) as supertype_package_name from acs_object_types t where t.object_type = :supertype } set attribute_list [package_create_attribute_list \ -supertype $supertype \ -object_name "NEW" \ -table $table_name \ -column $id_column \ $object_type] # Prune down the list of attributes in supertype_attr_list to # those specific to the function call in the supertype's package set supertype_params [db_list select_supertype_function_params { select args.argument_name from user_arguments args where args.package_name =upper(:supertype_package_name) and args.object_name='NEW' }] set supertype_attr_list [package_create_attribute_list \ -supertype $supertype \ -object_name "NEW" \ -limit_to $supertype_params \ -table $supertype_table_name \ -column $supertype_id_column \ -column_value $id_column \ $supertype] return [db_map body] } ad_proc -public package_object_view_reset { object_type } { Resets the cached views for all chains (e.g. all variations of start_with in package_object_view) for the specified object type. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 } { # First flush the cache for all pairs of object_type, ancestor_type (start_with) db_foreach select_ancestor_types { select t.object_type as ancestor_type from acs_object_types t start with t.object_type = :object_type connect by prior t.supertype = t.object_type } { if { [util_memoize_cached_p "package_object_view_helper -start_with $ancestor_type $object_type"] } { util_memoize_flush "package_object_view_helper -start_with $ancestor_type $object_type" } } # flush the cache for all pairs of sub_type, object_type(start_with) db_foreach select_sub_types { select t.object_type as sub_type from acs_object_types t start with t.object_type = :object_type connect by prior t.object_type = t.supertype } { if { [util_memoize_cached_p "package_object_view_helper -start_with $object_type $sub_type"] } { util_memoize_flush "package_object_view_helper -start_with $object_type $sub_type" } } } ad_proc -public package_object_view { { -refresh_p "f" } { -start_with "acs_object" } object_type } { Returns a select statement to be used as an inner view for selecting out all the attributes for the object_type. util_memoizes the result @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 @param refresh_p If t, force a reload of the cache @param start_with The highest parent object type for which to include attributes @param object_type The object for which to create a package spec } { if {$refresh_p eq "t"} { package_object_view_reset $object_type } return [util_memoize "package_object_view_helper -start_with $start_with $object_type"] } ad_proc -private package_object_view_helper { { -start_with "acs_object" } object_type } { Returns a select statement to be used as an inner view for selecting out all the attributes for the object_type. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 10/2000 @param start_with The highest parent object type for which to include attributes @param object_type The object for which to create a package spec } { # Let's add the primary key for our lowest object type. We do this # separately in case there are no other attributes for this object type # Note that we also alias this primary key to object_id so # that the calling code can generically use it. db_1row select_type_info { select t.table_name, t.id_column from acs_object_types t where t.object_type = :object_type } set columns [list "${table_name}.${id_column}"] if { [string tolower $id_column] ne "object_id" } { # Add in an alias for object_id lappend columns "${table_name}.${id_column} as object_id" } set tables [list "${table_name}"] set primary_keys [list "${table_name}.${id_column}"] foreach row [package_object_attribute_list -start_with $start_with $object_type] { set table [lindex $row 1] set column [lindex $row 2] set object_column [lindex $row 8] if {[string tolower $column] eq "object_id"} { # We already have object_id... skip this column continue } # Do the column check first to include only the tables we need if { [lsearch -exact $columns "$table.$column"] != -1 } { # We already have a column with the same name. Keep the # first one as it's lower in the type hierarchy. continue } # first time we're seeing this column lappend columns "${table}.${column}" if { [lsearch -exact $tables $table] == -1 } { # First time we're seeing this table lappend tables $table lappend primary_keys "${table}.${object_column}" } } set pk_formatted [list] for { set i 0 } { $i < [expr {[llength $primary_keys] - 1}] } { incr i } { lappend pk_formatted "[lindex $primary_keys $i] = [lindex $primary_keys [expr {$i +1}]]" } return "SELECT [string tolower [join $columns ",\n "]] FROM [string tolower [join $tables ", "]] [ad_decode [llength $pk_formatted] "0" "" " WHERE [join [string tolower $pk_formatted] "\n AND "]"]" } ad_proc -private package_insert_default_comment { } { Returns a string to be used verbatim as the default comment we insert into meta-generated packages and package bodies. If we have a connection, we grab the user's name from ad_conn user_id. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/29/2000 } { if { [ad_conn isconnected] } { set user_id [ad_conn user_id] db_1row select_comments { select acs_object.name(:user_id) as author, sysdate as creation_date from dual } } else { db_1row select_comments { select 'Unknown' as author, sysdate as creation_date from dual } } return " --/** THIS IS AN AUTO GENERATED PACKAGE. $author was the -- user who created it -- -- @creation-date $creation_date --*/ " } ad_proc package_object_attribute_list { { -start_with "acs_object" } { -include_storage_types {type_specific} } object_type } { Returns a list of lists all the attributes (column name or attribute_name) to be used for this object type. Each list elements contains: (attribute_id, table_name, attribute_name, pretty_name, datatype, required_p, default_value) @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/29/2000 @param start_with The highest parent object type for which to include attributes @param object_type The object type for which to include attributes } { set storage_clause "" if {$include_storage_types ne ""} { set storage_clause " and a.storage in ('[join $include_storage_types "', '"]')" } return [db_list_of_lists attributes_select " select a.attribute_id, nvl(a.table_name, t.table_name) as table_name, nvl(a.column_name, a.attribute_name) as attribute_name, a.pretty_name, a.datatype, decode(a.min_n_values,0,'f','t') as required_p, a.default_value, t.table_name as object_type_table_name, t.id_column as object_type_id_column from acs_object_type_attributes a, (select t.object_type, t.table_name, t.id_column, level as type_level from acs_object_types t start with t.object_type=:start_with connect by prior t.object_type = t.supertype) t where a.object_type = :object_type and t.object_type = a.object_type $storage_clause order by type_level"] } ad_proc -private package_plsql_args { { -object_name "NEW" } package_name } { Generates a list of parameters expected to a plsql function defined within a given package.

    @author Ben Adida (ben@openforce.net) @creation-date 11/2001 @param package_name The package which owns the function @param object_name The function name which we're looking up } { # Get just the args return [db_list select_package_func_param_list {}] } ad_proc -private package_function_p { -object_name:required package_name } { Returns true if the package's object is a function. } { return [db_0or1row function_p ""] } ad_proc -private package_table_columns_for_type { object_type } { Generates the list of tables and columns that are parameters of the object named NEW for PL/SQL package associated with this object type.

    Note we limit the argument list to only object_type to make it possible to use util_memoize_flush to clear any cached values for this procedure. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 12/2000 @param object_type The object type for which we are generating the list @return a list of lists where each list element is a pair of table name, column name } { set object_name "NEW" db_1row select_type_info { select t.package_name from acs_object_types t where t.object_type = :object_type } # We need to hit the data dictionary to find the table and column names # for all the arguments to the object_types function/procedure # named "object_name." Note that we join against # acs_object_types to select out the tables and columns for the # object_type up the type tree starting from this object_type. # # NOTE: This query is tuned already, yet still slow (~1 # second on my box right now). Be careful modifying # it... It's slow because of the underlying data dictionary query # against user_arguments return [db_list_of_lists select_object_type_param_list { select cols.table_name, cols.column_name from user_tab_columns cols, (select upper(t.table_name) as table_name from acs_object_types t start with t.object_type = :object_type connect by prior t.supertype = t.object_type) t where cols.column_name in (select args.argument_name from user_arguments args where args.position > 0 and args.object_name = upper(:object_name) and args.package_name = upper(:package_name)) and cols.table_name = t.table_name }] } ad_proc -public package_instantiate_object { { -creation_user "" } { -creation_ip "" } { -package_name "" } { -var_list "" } { -extra_vars "" } { -start_with "" } { -form_id "" } { -variable_prefix "" } object_type } { Creates a new object of the specified type by calling the associated PL/SQL package new function. @author Michael Bryzek (mbryzek@arsdigita.com) @author Ben Adida (ben@openforce.net) @creation-date 02/01/2001 @param creation_user The current user. Defaults to [ad_conn user_id] if not specified and there is a connection @param creation_ip The current user's ip address. Defaults to [ad_conn peeraddr] if not specified and there is a connection @param package_name The PL/SQL package associated with this object type. Defaults to acs_object_types.package_name @param var_list A list of pairs of additional attributes and their values to pass to the constructor. Each pair is a list of two elements: key => value @param extra_vars an ns_set of extra vars @param start_with The object type to start with when gathering attributes for this object type. Defaults to the object type. @param form_id The form id from templating form system if we're using the forms API to specify attributes @param object_type The object type of the object we are instantiating @return The object id of the newly created object

    Example:

    
        template::form create add_group
        template::element create add_group group_name -value "Publisher"
    
        set var_list [list \
    	    [list context_id $context_id]  \
    	    [list group_id $group_id]]
    
        return [package_instantiate_object \
    	    -start_with "group" \
    	    -var_list $var_list \
    	    -form_id "add_group" \
    	    "group"]
    
        
    } { if {$variable_prefix ne ""} { append variable_prefix "." } # Select out the package name if it wasn't passed in if { $package_name eq "" } { if { ![db_0or1row package_select { select t.package_name from acs_object_types t where t.object_type = :object_type }] } { error "Object type \"$object_type\" does not exist" } } if { [ad_conn isconnected] } { if { $creation_user eq "" } { set creation_user [ad_conn user_id] } if { $creation_ip eq "" } { set creation_ip [ad_conn peeraddr] } } if {$creation_user == 0} { set creation_user "" } lappend var_list [list creation_user $creation_user] lappend var_list [list creation_ip $creation_ip] lappend var_list [list object_type $object_type] # The first thing we need to do is select out the list of all # the parameters that can be passed to this object type's new function. # This will prevent us from passing in any parameters that are # not defined foreach arg [util_memoize "package_plsql_args \"$package_name\""] { set real_params([string toupper $arg]) 1 } # Use pieces to generate the parameter list to the new # function. Pieces is just a list of lists where each list contains only # one item - the name of the parameter. We keep track of # parameters we've already added in the array param_array (all keys are # in upper case) set pieces [list] foreach pair $var_list { set __key [lindex $pair 0] set __value [lindex $pair 1] if { ![info exists real_params([string toupper $__key])] } { # The parameter is not accepted as a parameter to the # pl/sql function. Ignore it. continue; } lappend pieces [list $__key] set param_array([string toupper $__key]) 1 # Set the value for binding set $__key $__value } # Go through the extra_vars (ben - OpenACS) if {$extra_vars ne "" } { for {set i 0} {$i < [ns_set size $extra_vars]} {incr i} { set __key [ns_set key $extra_vars $i] set __value [ns_set value $extra_vars $i] if { ![info exists real_params([string toupper $__key])] } { # The parameter is not accepted as a parameter to the # pl/sql function. Ignore it. continue; } lappend pieces [list $__key] set param_array([string toupper $__key]) 1 # Set the value for binding set $__key $__value } } if { $form_id ne ""} { #DRB: This needs to be cached! set __id_column [db_string get_id_column {}] if { [info exists real_params([string toupper $__id_column])] && ![info exists param_array([string toupper $__id_column])] } { set param_array([string toupper $__id_column]) 1 set $__id_column [template::element::get_value $form_id "$variable_prefix$__id_column"] lappend pieces [list $__id_column] } if {$start_with eq ""} { set start_with $object_type } # Append the values from the template form for each attribute foreach row [package_object_attribute_list -start_with $start_with $object_type] { set __attribute [lindex $row 2] if { [info exists real_params([string toupper $__attribute])] && ![info exists param_array([string toupper $__attribute])] } { set param_array([string toupper $__attribute]) 1 set $__attribute [template::element::get_value $form_id "$variable_prefix$__attribute"] lappend pieces [list $__attribute] } } } set object_id [db_exec_plsql create_object {}] if { [ad_conn isconnected] } { subsite_callback -object_type $object_type "insert" $object_id } # BUG FIX (ben - OpenACS) return $object_id } ad_proc -public package_exec_plsql { { -var_list "" } package_name object_name } { Calls a pl/[pg]sql proc/func defined within the object type's package. Use of this Tcl APi proc avoids the need for the developer to write separate SQL for each RDBMS we support. @author Don Baccus (dhogaza@pacifier.com) @creation-date 12/31/2003 @param package_name The PL/[pg]SQL package @param object_name The PL/[pg]SQL function within the package @param var_list A list of pairs of additional attributes and their values to pass to the constructor. Each pair is a list of two elements: key => value @return empty string for procs, function return value for funcs

    Example:

    
        set var_list [list \
    	    [list group_id $group_id]]
    
        package_exec_plsql -var_list $var_list group delete
    
        
    } { # Ugly hack for the case where a proc has params named "package_name" or "object_name". set __package_name $package_name set __object_name $object_name foreach arg [util_memoize [list package_plsql_args -object_name $__object_name $__package_name]] { set real_params([string toupper $arg]) 1 } # Use pieces to generate the parameter list to the new # function. Pieces is just a list of lists where each list contains only # one item - the name of the parameter. We keep track of # parameters we've already added in the array param_array (all keys are # in upper case) set pieces [list] foreach pair $var_list { set __key [lindex $pair 0] set __value [lindex $pair 1] if { ![info exists real_params([string toupper $__key])] } { # The parameter is not accepted as a parameter to the # pl/sql function. Ignore it. ns_log Warning "package_exec_plsql: skipping $__key not found in params for $__package_name $__object_name" continue; } lappend pieces [list $__key] set param_array([string toupper $__key]) 1 # Set the value for binding set $__key $__value } if { [util_memoize [list package_function_p -object_name $__object_name $__package_name]] } { return [db_exec_plsql exec_func_plsql {}] } else { db_exec_plsql exec_proc_plsql {} } } openacs-5.7.0/packages/acs-subsite/tcl/package-procs.xql0000644000175000017500000000527510012472163023027 0ustar frankiefrankie select t.table_name as table, t.id_column as column from acs_object_types t where t.object_type = :object_type select t.package_name from acs_object_types t where t.object_type = :object_type select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type select t.table_name, t.id_column, lower(t.package_name) as package_name, t.supertype from acs_object_types t where t.object_type = :object_type select t.package_name from acs_object_types t where t.object_type = :object_type select id_column from acs_object_types where object_type = :object_type select t.table_name, t.id_column from acs_object_types t where t.object_type = :object_type openacs-5.7.0/packages/acs-subsite/tcl/approval-expiration-procs-postgresql.xql0000644000175000017500000000105207723347123027642 0ustar frankiefrankie postgresql7.1 select u.user_id from cc_users u, acs_objects relo where relo.object_id = u.rel_id and age(u.last_visit) > interval '$days days' and age(relo.last_modified) > interval '$days days' and u.member_state = 'approved' openacs-5.7.0/packages/acs-subsite/tcl/package-procs-oracle.xql0000644000175000017500000002041611253303101024255 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_object_types t where t.dynamic_p = 't' and t.object_type = :object_type) then 1 else 0 end from dual select upper(nvl(attr.table_name,t.table_name)) as attr_table_name, upper(nvl(attr.column_name, attr.attribute_name)) as attr_column_name, attr.ancestor_type, attr.min_n_values, attr.default_value from acs_object_type_attributes attr, (select t.object_type, t.table_name, level as type_level from acs_object_types t start with t.object_type = :object_type connect by prior t.supertype = t.object_type) t where attr.ancestor_type = t.object_type and attr.object_type = :object_type order by t.type_level select t.object_type from acs_object_types t where t.dynamic_p = 't' start with t.object_type = :object_type connect by prior t.object_type = t.supertype select case when exists (select 1 from user_objects where status = 'INVALID' and object_name = upper(:package_name) and object_type = upper(:type)) then 0 else 1 end from dual select t.object_type as ancestor_type from acs_object_types t start with t.object_type = :object_type connect by prior t.supertype = t.object_type select t.object_type as sub_type from acs_object_types t start with t.object_type = :object_type connect by prior t.object_type = t.supertype select acs_object.name(:user_id) as author, sysdate as creation_date from dual select acs_object.name(:user_id) as author, sysdate as creation_date from dual select a.attribute_id, nvl(a.table_name, t.table_name) as table_name, nvl(a.column_name, a.attribute_name) as attribute_name, a.pretty_name, a.datatype, case when a.min_n_values = 0 then 'f' else 't' end as required_p, a.default_value, t.table_name as object_type_table_name, t.id_column as object_type_id_column from acs_object_type_attributes a, (select t.object_type, t.table_name, t.id_column, level as type_level from acs_object_types t start with t.object_type=:start_with connect by prior t.object_type = t.supertype) t where a.object_type = :object_type and t.object_type = a.ancestor_type $storage_clause order by type_level select args.argument_name from user_arguments args where args.position > 0 and args.object_name = upper(:object_name) and args.package_name = upper(:package_name) select 1 from dual where exists (select 1 from user_arguments where rtrim(package_name) = upper(:package_name) and rtrim(object_name) = upper(:object_name) and position = 0) select cols.table_name, cols.column_name from user_tab_columns cols, (select upper(t.table_name) as table_name from acs_object_types t start with t.object_type = :object_type connect by prior t.supertype = t.object_type) t where cols.column_name in (select args.argument_name from user_arguments args where args.position > 0 and args.object_name = upper(:object_name) and args.package_name = upper(:package_name)) and cols.table_name = t.table_name BEGIN :1 := ${package_name}.new([plsql_utility::generate_attribute_parameter_call \ -prepend ":" \ -indent [expr [string length $package_name] + 29] \ $pieces] ); END; create or replace package body ${package_name} as [package_insert_default_comment] function new ( [plsql_utility::generate_attribute_parameters $attribute_list] ) return ${table_name}.${id_column}%TYPE is v_$id_column ${table_name}.${id_column}%TYPE; begin v_$id_column := ${supertype_package_name}.new ( [plsql_utility::generate_attribute_parameter_call_from_attributes \ -prepend "new." \ -indent 21 \ $supertype_attr_list] ); insert into ${table_name} ($id_column[plsql_utility::generate_attribute_dml -ignore [list $id_column] $table_name $attribute_list]) values (v_$id_column[plsql_utility::generate_attribute_dml -prepend "new." -ignore [list $id_column] $table_name $attribute_list]); return v_$id_column; end new; procedure del ( $id_column in ${table_name}.${id_column}%TYPE ) is begin ${supertype_package_name}.del( $package_name.del.$id_column ); end del; end ${package_name}; create or replace package $package_name as [package_insert_default_comment] function new ( [plsql_utility::generate_attribute_parameters [package_create_attribute_list \ -supertype $supertype \ -object_name "NEW" \ -table $table_name \ -column $id_column \ $object_type]] ) return ${table_name}.${id_column}%TYPE; procedure del ( $id_column in ${table_name}.${id_column}%TYPE ); END ${package_name}; sysdate sysdate BEGIN :1 := ${__package_name}.${__object_name}([plsql_utility::generate_attribute_parameter_call \ -prepend ":" \ -indent [expr [string length $__package_name] + 29] \ $pieces] ); END; BEGIN ${__package_name}.${__object_name}([plsql_utility::generate_attribute_parameter_call \ -prepend ":" \ -indent [expr [string length $__package_name] + 29] \ $pieces] ); END; openacs-5.7.0/packages/acs-subsite/tcl/party-procs-postgresql.xql0000644000175000017500000000273507403013337024776 0ustar frankiefrankie postgresql7.1 (t1.object_type = 'group' or t1.object_type = 'person') t1.object_type = :start_with select types.pretty_name, types.object_type, types.tree_level, types.indent, case when valid_types.object_type = null then 0 else 1 end as valid_p from (select t2.pretty_name, t2.object_type, tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey) as tree_level, repeat(' ', (tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4) as indent, t2.tree_sortkey from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and $start_with_clause ) types left outer join (select object_type from rel_types_valid_obj_two_types where rel_type = :rel_type ) valid_types using (object_type) order by types.tree_sortkey openacs-5.7.0/packages/acs-subsite/sql/0000755000175000017500000000000011724401447017576 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/sql/oracle/0000755000175000017500000000000011724401447021043 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/sql/oracle/portraits-drop.sql0000644000175000017500000000050007263134052024546 0ustar frankiefrankie-- -- packages/acs-subsite/sql/portraits-drop.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: portraits-drop.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- drop table user_portraits; drop package user_portrait_rel; begin acs_rel_type.drop_type('user_portrait_rel'); end; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/subsite-callbacks-create.sql0000644000175000017500000001424007736271233026427 0ustar frankiefrankie-- /packages/acs-subsite/sql/subsite-group-callbacks-create.sql -- Defines a simple callback system to allow other applications to -- register callbacks when groups of a given type are created. -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- $Id: subsite-callbacks-create.sql,v 1.2 2003/09/30 12:10:03 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- What about instead of? -- insead_of viewing the group, go to the portal -- instead of inserting the group with package_instantiate_object, go here create table subsite_callbacks ( callback_id integer constraint sgc_callback_id_pk primary key, event_type varchar(100) not null constraint sgc_event_type_ck check(event_type in ('insert','update','delete')), object_type varchar(100) not null constraint sgc_object_type_fk references acs_object_types on delete cascade, callback varchar(300) not null, callback_type varchar(100) not null constraint sgc_callback_type_ck check(callback_type in ('tcl')), sort_order integer default(1) not null constraint sgc_sort_order_ck check(sort_order >= 1), -- allow only one callback of a given type for given constraint subsite_callbacks_un unique (object_type, event_type, callback_type, callback) ); comment on table subsite_callbacks is ' Applications can register callbacks that are triggered whenever a group of a specified type is created. The callback must expect the following arguments: * object_id: The object that just got created * node_id: The node_id where the object got created * package_id: The package_id from where the object got created These are passed in the following way: * tcl procedure: Using named parameters (e.g. -object_id $object_id) All callbacks must accept all of these parameters. '; comment on column subsite_callbacks.event_type is ' The type of event we are monitoring. The keywords here are used by the applications to determine which callbacks to trigger. '; comment on column subsite_callbacks.object_type is ' The object type to monitor. Whenever an object of this type is created, the subsite package will check for a registered callbacks. '; comment on column subsite_callbacks.callback_type is ' The type of the callback. This determines how the callback is executed. Currenlty only a tcl type is supported but other types may be added in the future. '; comment on column subsite_callbacks.callback is ' The actual callback. This can be the name of a plsql function or procedure, a url stub relative to the node at which package id is mounted, or the name of a tcl function. '; comment on column subsite_callbacks.sort_order is ' The order in which the callbacks should fire. This is important when you need to ensure that one event fires before another (e.g. you must mount a portals application before the bboard application) '; create or replace package subsite_callback as function new ( --/** Registers a new callback. If the same callback exists as -- defined in the unique constraint on the table, does -- nothing but returns the existing callback_id. -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE; procedure del ( --/** Deletes the specified callback -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE ); end subsite_callback; / show errors; create or replace package body subsite_callback as function new ( callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE IS v_callback_id subsite_callbacks.callback_id%TYPE; v_sort_order subsite_callbacks.sort_order%TYPE; BEGIN if new.callback_id is null then select acs_object_id_seq.nextval into v_callback_id from dual; else v_callback_id := new.callback_id; end if; if new.sort_order is null then -- Make this the next event for this object_type/event_type combination select nvl(max(sort_order),0) + 1 into v_sort_order from subsite_callbacks where object_type = new.object_type and event_type = new.event_type; else v_sort_order := new.sort_order; end if; begin insert into subsite_callbacks (callback_id, event_type, object_type, callback, callback_type, sort_order) values (v_callback_id, new.event_type, new.object_type, new.callback, new.callback_type, v_sort_order); exception when dup_val_on_index then select callback_id into v_callback_id from subsite_callbacks where event_type = new.event_type and object_type = new.object_type and callback_type = new.callback_type and callback = new.callback; end; return v_callback_id; END new; procedure del ( callback_id IN subsite_callbacks.callback_id%TYPE ) is begin delete from subsite_callbacks where callback_id=subsite_callback.del.callback_id; end del; end subsite_callback; / show errors; openacs-5.7.0/packages/acs-subsite/sql/oracle/email-image.sql0000644000175000017500000000147610506242434023737 0ustar frankiefrankie-- Email-Image Data Model -- author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) -- creation-date 2005-01-22 create table email_images ( user_id constraint email_images_user_id_fk references users constraint email_images_user_id_pk primary key ); begin acs_rel_type.create_role('email_image', 'Email Image', 'Email Images'); acs_rel_type.create_type ( rel_type => 'email_image_rel', pretty_name => 'Email Image', pretty_plural => 'Email Images', object_type_one => 'user', role_one => 'user', table_name => 'email_images', id_column => 'user_id', package_name => 'email_image_rel', min_n_rels_one => 1, max_n_rels_one => 1, object_type_two => 'content_item', min_n_rels_two => 0, max_n_rels_two => 1 ); commit; end; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/tests/0000755000175000017500000000000011724401447022205 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/sql/oracle/tests/acs-subsite-test-harness.sql0000644000175000017500000000107607263134052027570 0ustar frankiefrankie-- /packages/acs-subsite/sql/tests/acs-subsite-test-harness.sql -- Test harness to run all the tests in this directory. New tests -- should be added to this file -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- $Id: acs-subsite-test-harness.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html @@ subsite-callbacks-test openacs-5.7.0/packages/acs-subsite/sql/oracle/tests/subsite-callbacks-test.sql0000644000175000017500000000446707736271233027317 0ustar frankiefrankie-- /packages/acs-subsite/sql/tests/subsite-group-callbacks-test.sql -- Test the basic API to the subsite_callback package. You will -- get an application error if there is an error -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- $Id: subsite-callbacks-test.sql,v 1.2 2003/09/30 12:10:03 mohanp Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html declare v_count integer; v_callback_id integer; v_node_id integer; begin select min(node_id) into v_node_id from site_nodes; for i in 0..2 loop v_callback_id := subsite_callback.new(event_type=>'insert', object_type=>'group', callback=>'subsite_callback_test_foo', callback_type=>'tcl' ); end loop; select count(*) into v_count from subsite_callbacks where object_type = 'group' and event_type = 'insert' and callback_type = 'tcl' and callback = 'subsite_callback_test_foo'; if v_count = 0 then raise_application_error(-20000,'Insert failed'); elsif v_count > 1 then raise_application_error(-20000,'Duplicate insert succeeded where it should have done nothing.'); end if; subsite_callback.del(v_callback_id); v_callback_id := subsite_callback.new(object_type=>'group', event_type=>'insert', callback=>'subsite_callback_test_foo2', callback_type=>'tcl'); select count(*) into v_count from subsite_callbacks where object_type = 'group' and callback = 'subsite_callback_test_foo2' and callback_type = 'tcl'; if v_count = 0 then raise_application_error(-20000,'Insert failed'); end if; subsite_callback.del(v_callback_id); select count(*) into v_count from subsite_callbacks where callback in ('subsite_callback_test_foo','subsite_callback_test_foo2'); if v_count > 0 then raise_application_error(-20000,'Delete failed'); end if; end; / show errors; openacs-5.7.0/packages/acs-subsite/sql/oracle/site-node-selection-drop.sql0000644000175000017500000000031010171476724026377 0ustar frankiefrankie-- -- packages/acs-kernel/sql/site-node-selection.sql -- -- @author vivian@viaro.net -- @creation-date 2004-11-23 -- @cvs-id site-node-selection.sql -- drop table site_nodes_selection; --show errorsopenacs-5.7.0/packages/acs-subsite/sql/oracle/host-node-map-create.sql0000644000175000017500000000064607611532604025506 0ustar frankiefrankie-- @author Mark Dettinger (mdettinger@arsdigita.com) -- $Id: host-node-map-create.sql,v 1.3 2003/01/16 13:37:08 jeffd Exp $ -- This has not been tested against Oracle. create table host_node_map ( host varchar(200) constraint host_node_map_host_pk primary key constraint host_node_map_host_nn not null, node_id integer constraint host_node_map_node_id_fk references site_nodes ); openacs-5.7.0/packages/acs-subsite/sql/oracle/user-sc-create.sql0000644000175000017500000000735207423415153024415 0ustar frankiefrankie -- -- A service contract for allowing packages to be notified of changes in user information -- -- The operations defined here are -- UserData.UserNew -- UserData.UserApprove -- UserData.UserDeapprove -- UserData.UserDelete -- UserData.UserModify -- -- ben@openforce -- Jan 22, 2002 declare foo integer; begin foo := acs_sc_contract.new( contract_name => 'UserData', contract_desc => 'User Data Updates' ); -- The UserNew operation foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserNew.InputType', msg_type_spec => 'user_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserNew.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'UserData', operation_name => 'UserNew', operation_desc => 'Notify that a new user has been created', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'UserData.UserNew.InputType', operation_outputtype => 'UserData.UserNew.OutputType' ); -- The UserApprove operation foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserApprove.InputType', msg_type_spec => 'user_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserApprove.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'UserData', operation_name => 'UserApprove', operation_desc => 'Notify that a user has been approved', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'UserData.UserApprove.InputType', operation_outputtype => 'UserData.UserApprove.OutputType' ); -- The UserDeapprove operation foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserDeapprove.InputType', msg_type_spec => 'user_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserDeapprove.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'UserData', operation_name => 'UserDeapprove', operation_desc => 'Notify that a user has been deapproved', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'UserData.UserDeapprove.InputType', operation_outputtype => 'UserData.UserDeapprove.OutputType' ); -- The UserModify operation foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserModify.InputType', msg_type_spec => 'user_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserModify.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'UserData', operation_name => 'UserModify', operation_desc => 'Notify that a user has been modified', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'UserData.UserModify.InputType', operation_outputtype => 'UserData.UserModify.OutputType' ); -- The UserDelete operation foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserDelete.InputType', msg_type_spec => 'user_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'UserData.UserDelete.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new ( contract_name => 'UserData', operation_name => 'UserDelete', operation_desc => 'Notify that a user has been deleted', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'UserData.UserDelete.InputType', operation_outputtype => 'UserData.UserDelete.OutputType' ); end; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/site-node-selection.sql0000644000175000017500000000110010440426465025427 0ustar frankiefrankie-- -- packages/acs-kernel/sql/site-node-selection.sql -- -- @author vivian@viaro.net -- @creation-date 2004-11-23 -- @cvs-id site-node-selection.sql -- create table site_nodes_selection ( node_id integer constraint site_nodes_sel_id_fk references acs_objects (object_id) on delete cascade constraint site_node_sel_id_pk primary key, view_p char(1) constraint site_nodes_sel_view_p_ck check (view_p in ('t','f')) ); --show errorsopenacs-5.7.0/packages/acs-subsite/sql/oracle/themes-drop.sql0000644000175000017500000000003311010456337024003 0ustar frankiefrankiedrop table subsite_themes; openacs-5.7.0/packages/acs-subsite/sql/oracle/acs-subsite-drop.sql0000644000175000017500000000073010174512211024736 0ustar frankiefrankie-- Uninstall file for the data model created by 'acs-core-ui-create.sql' -- (This file created automatically by create-sql-uninst.pl.) -- -- @author Bryan Quinn -- @creation-date (Sat Aug 26 17:56:07 2000) -- @cvs-id $Id: acs-subsite-drop.sql,v 1.4 2005/01/22 17:59:37 miguelm Exp $ @@ subsite-group-callbacks-drop @@ application-groups-drop @@ user-profiles-drop @@ attributes-drop @@ portraits-drop @@ email-image-drop @@ host-node-map-drop @@ site-node-selection-dropopenacs-5.7.0/packages/acs-subsite/sql/oracle/themes-create.sql0000644000175000017500000000251011452447070024310 0ustar frankiefrankie-- For now, at least, there's no reason for this table to include objects. When a subsite_theme -- is installed, it can add to the table. When it is uninstalled, it can delete from the -- table. Theme switching is only accessible from the admin UI for subsites, therefore -- we don't need permissions on subsite_themes ... -- the css column contains a list of CSS file/media pairs. -- css and the form/list templates can be null because evil old OpenACS provides defaults -- for these. create table subsite_themes ( key varchar(100) constraint subsite_themes_key_pk primary key, name varchar(100) constraint subsite_themes_name_nn not null, template varchar(200) constraint subsite_themes_template_nn not null, css varchar(2000), form_template varchar(200), list_template varchar(200), list_filter_template varchar(200) ); -- Insert the old themes that were hard-wired into earlier versions of acs-subsite. insert into subsite_themes (key, name, template) values ('obsolete_plain', 'Obsolete Plain', '/www/default-master'); insert into subsite_themes (key, name, template) values ('obsolete_tabbed', 'Obsolete Tabbed', '/packages/acs-subsite/www/group-master'); openacs-5.7.0/packages/acs-subsite/sql/oracle/application-groups-drop.sql0000644000175000017500000000106007263134052026341 0ustar frankiefrankie-- -- packages/acs-subsite/sql/application-groups-drop.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: application-groups-drop.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- delete from group_type_rels where rel_type = 'application_group'; drop table application_groups; drop package application_group; begin acs_object_type.drop_type('application_group'); end; / show errors drop view application_group_element_map; drop view application_users; drop view registered_users_for_package_id; drop view cc_users_for_package_id;openacs-5.7.0/packages/acs-subsite/sql/oracle/user-profiles-drop.sql0000644000175000017500000000047607263134052025332 0ustar frankiefrankie-- -- packages/acs-subsite/sql/user-profiles-drop.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: user-profiles-drop.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- drop table user_profiles; drop package user_profile; begin acs_rel_type.drop_type('user_profile'); end; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/user-profiles-create.sql0000644000175000017500000001033310005232302025603 0ustar frankiefrankie-- -- packages/acs-subsite/sql/user-profiles-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: user-profiles-create.sql,v 1.3 2004/01/26 15:39:46 jeffd Exp $ -- ------------------------------- -- APPLICATION USER PROFILES -- ------------------------------- begin -- the 'user' role should already exist from the portraits stuff. -- acs_rel_type.create_role('user', -- 'Registered User', 'Registered Users'); acs_rel_type.create_role('application', 'Application Group', 'Application Group'); acs_rel_type.create_type( rel_type => 'user_profile', pretty_name => 'User Profile', pretty_plural => 'User Profiles', supertype => 'membership_rel', table_name => 'user_profiles', id_column => 'profile_id', package_name => 'user_profile', abstract_p => 'f', object_type_one => 'application_group', role_one => 'application', min_n_rels_one => 0, max_n_rels_one => null, object_type_two => 'user', role_two => 'user', min_n_rels_two => 0, max_n_rels_two => null ); end; / show errors create table user_profiles ( profile_id constraint user_profiles_profile_id_fk references membership_rels (rel_id) constraint user_profiles_profile_id_pk primary key ); create or replace package user_profile as function new ( profile_id in user_profiles.profile_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'user_profile', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, member_state in membership_rels.member_state%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return user_profiles.profile_id%TYPE; procedure del ( profile_id in user_profiles.profile_id%TYPE ); end user_profile; / show errors create or replace package body user_profile as function new ( profile_id in user_profiles.profile_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'user_profile', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, member_state in membership_rels.member_state%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return user_profiles.profile_id%TYPE is v_profile_id integer; begin v_profile_id := membership_rel.new ( rel_id => profile_id, rel_type => rel_type, object_id_one => object_id_one, object_id_two => object_id_two, member_state => member_state, creation_user => creation_user, creation_ip => creation_ip ); insert into user_profiles (profile_id) values (v_profile_id); return v_profile_id; end new; procedure del ( profile_id in user_profiles.profile_id%TYPE ) is begin membership_rel.del(profile_id); end del; end user_profile; / show errors insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'user_profile'); -- This view is extremely fast, but for some reason its not so blaxing fast -- when used in the registered_users_of_package_id view below. create or replace view application_users as select ag.package_id, gem.element_id as user_id from user_profiles up, group_element_map gem, application_groups ag where ag.group_id = gem.group_id and gem.rel_id = up.profile_id; -- create the generalized versions of the registered_users and cc_users views: create or replace view registered_users_of_package_id as select u.*, au.package_id from application_users au, registered_users u where au.user_id = u.user_id; create or replace view cc_users_of_package_id as select u.*, au.package_id from application_users au, cc_users u where au.user_id = u.user_id; openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/0000755000175000017500000000000011724401447022472 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-4.6b-4.6.1b.sql0000644000175000017500000000031307556063516026125 0ustar frankiefrankie-- @author Eric Lorenzo (eric@openforce.net) -- This has not been tested. alter table host_node_map drop primary key; alter table host_node_map add ( constraint host_node_map_pk primary key ( host ) );openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-5.7.0d1-5.7.0d2.sql0000644000175000017500000000055011452447070026427 0ustar frankiefrankie-- Getting right constraint names on subsite_themes this dont matter for PG since -- -- -- @author Victor Guerra (vguerra@gmail.com) -- @creation-date 2010-09-29 -- alter table subsite_themes rename constraint subsite_theme_name_nn to subsite_themes_nn; alter table subsite_themes rename constraint subsite_theme_template_nn to subsite_themes_template_nn; openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-5.2.0b5-5.2.0b6.sql0000644000175000017500000000067610440426466026434 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-11-29 -- @arch-tag: 6595c279-ae92-4dd8-955f-1184e1fccbd7 -- @cvs-id $Id: upgrade-5.2.0b5-5.2.0b6.sql,v 1.2 2006/06/04 00:45:42 donb Exp $ -- alter table site_nodes_selection drop constraint site_nodes_sel_id_fk; alter table site_nodes_selection add constraint site_nodes_sel_id_fk foreign key (node_id) references acs_objects(object_id) on delete cascade; openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-5.0d4-5.0d5.sql0000644000175000017500000002103410005232302026102 0ustar frankiefrankie-- -- packages/acs-subsite/sql/application_groups-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: upgrade-5.0d4-5.0d5.sql,v 1.2 2004/01/26 15:39:46 jeffd Exp $ -- create or replace package application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE; procedure del ( group_id in application_groups.group_id%TYPE ); function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char; end application_group; / show errors create or replace package body application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE is v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group.new ( group_id => group_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, email => email, url => url, group_name => group_name, context_id => context_id ); insert into application_groups (group_id, package_id) values (v_group_id, package_id); return v_group_id; end new; procedure del ( group_id in application_groups.group_id%TYPE ) is begin acs_group.del(group_id); end del; function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char is v_group_id application_groups.group_id%TYPE; begin select group_id into v_group_id from application_groups where package_id = group_id_from_package_id.package_id; return v_group_id; exception when no_data_found then if no_complain_p != 't' then raise_application_error(-20000, 'No group_id found for package ' || package_id || ' (' || acs_object.name(package_id) || ').' ); end if; return null; end group_id_from_package_id; end application_group; / show errors create or replace package subsite_callback as function new ( --/** Registers a new callback. If the same callback exists as -- defined in the unique constraint on the table, does -- nothing but returns the existing callback_id. -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE; procedure del ( --/** Deletes the specified callback -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE ); end subsite_callback; / show errors; create or replace package body subsite_callback as function new ( callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE IS v_callback_id subsite_callbacks.callback_id%TYPE; v_sort_order subsite_callbacks.sort_order%TYPE; BEGIN if new.callback_id is null then select acs_object_id_seq.nextval into v_callback_id from dual; else v_callback_id := new.callback_id; end if; if new.sort_order is null then -- Make this the next event for this object_type/event_type combination select nvl(max(sort_order),0) + 1 into v_sort_order from subsite_callbacks where object_type = new.object_type and event_type = new.event_type; else v_sort_order := new.sort_order; end if; begin insert into subsite_callbacks (callback_id, event_type, object_type, callback, callback_type, sort_order) values (v_callback_id, new.event_type, new.object_type, new.callback, new.callback_type, v_sort_order); exception when dup_val_on_index then select callback_id into v_callback_id from subsite_callbacks where event_type = new.event_type and object_type = new.object_type and callback_type = new.callback_type and callback = new.callback; end; return v_callback_id; END new; procedure del ( callback_id IN subsite_callbacks.callback_id%TYPE ) is begin delete from subsite_callbacks where callback_id=subsite_callback.del.callback_id; end del; end subsite_callback; / show errors; -- -- packages/acs-subsite/sql/user-profiles-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: upgrade-5.0d4-5.0d5.sql,v 1.2 2004/01/26 15:39:46 jeffd Exp $ -- create or replace package user_profile as function new ( profile_id in user_profiles.profile_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'user_profile', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, member_state in membership_rels.member_state%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return user_profiles.profile_id%TYPE; procedure del ( profile_id in user_profiles.profile_id%TYPE ); end user_profile; / show errors create or replace package body user_profile as function new ( profile_id in user_profiles.profile_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'user_profile', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, member_state in membership_rels.member_state%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return user_profiles.profile_id%TYPE is v_profile_id integer; begin v_profile_id := membership_rel.new ( rel_id => profile_id, rel_type => rel_type, object_id_one => object_id_one, object_id_two => object_id_two, member_state => member_state, creation_user => creation_user, creation_ip => creation_ip ); insert into user_profiles (profile_id) values (v_profile_id); return v_profile_id; end new; procedure del ( profile_id in user_profiles.profile_id%TYPE ) is begin membership_rel.del(profile_id); end del; end user_profile; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-4.6.4.1-4.6.4.2.sql0000644000175000017500000000122307723347123026261 0ustar frankiefrankie-- -- @author Lars Pind (lars@collaboraid.biz) -- @creation-date 2003-07-03 -- -- Add 'admin_rel' as a permissible relationship type for application groups -- -- Add 'admin_rel' as a permissible relationship type for application groups insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'admin_rel'); -- Then add it to all existing application groups insert into group_rels (group_rel_id, group_id, rel_type) select acs_object_id_seq.nextval, group_id, 'admin_rel' from groups g, acs_objects o where o.object_id = g.group_id and o.object_type = 'application_group'; openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-5.5.0d1-5.5.0d2.sql0000644000175000017500000000250411010456340026412 0ustar frankiefrankie-- For now, at least, there's no reason for this table to include objects. When a subsite_theme -- is installed, it can add to the table. When it is uninstalled, it can delete from the -- table. Theme switching is only accessible from the admin UI for subsites, therefore -- we don't need permissions on subsite_themes ... -- the css column contains a list of CSS file/media pairs. -- css and the form/list templates can be null because evil old OpenACS provides defaults -- for these. create table subsite_themes ( key varchar(100) constraint subsite_theme_key_pk primary key, name varchar(100) constraint subsite_theme_name_nn not null, template varchar(200) constraint subsite_theme_template_nn not null, css varchar(200), form_template varchar(200), list_template varchar(200), list_filter_template varchar(200) ); -- Insert the old themes that were hard-wired into earlier versions of acs-subsite. insert into subsite_themes (key, name, template) values ('obsolete_plain', 'Obsolete Plain', '/www/default-master'); insert into subsite_themes (key, name, template) values ('obsolete_tabbed', 'Obsolete Tabbed', '/packages/acs-subsite/www/group-master'); openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-5.5.0d5-5.5.0d6.sql0000644000175000017500000000670111140463710026430 0ustar frankiefrankiecreate or replace package application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, join_policy in groups.join_policy%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE; procedure del ( group_id in application_groups.group_id%TYPE ); function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char; end application_group; / show errors create or replace package body application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, join_policy in groups.join_policy%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE is v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group.new ( group_id => group_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, email => email, url => url, group_name => group_name, context_id => context_id, join_policy => join_policy ); insert into application_groups (group_id, package_id) values (v_group_id, package_id); return v_group_id; end new; procedure del ( group_id in application_groups.group_id%TYPE ) is begin acs_group.del(group_id); end del; function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char is v_group_id application_groups.group_id%TYPE; begin select group_id into v_group_id from application_groups where package_id = group_id_from_package_id.package_id; return v_group_id; exception when no_data_found then if no_complain_p != 't' then raise_application_error(-20000, 'No group_id found for package ' || package_id || ' (' || acs_object.name(package_id) || ').' ); end if; return null; end group_id_from_package_id; end application_group; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-5.1.2-5.1.3.sql0000644000175000017500000000102610440426466025746 0ustar frankiefrankie-- -- packages/acs-kernel/sql/site-node-selection.sql -- -- @author vivian@viaro.net -- @creation-date 2004-11-23 -- @cvs-id site-node-selection.sql -- create table site_nodes_selection ( node_id integer constraint site_nodes_sel_id_fk references acs_objects (object_id) constraint site_node_sel_id_pk primary key, view_p char(1) constraint site_nodes_sel_view_p_ck check (view_p in ('t','f')) ); --show errorsopenacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-4.1.1-4.2.sql0000644000175000017500000004061207263134052025603 0ustar frankiefrankie -- before release, we'll have to copy and paste from the referenced sql -- files into this one. For now, we just reference some sql files. ------------------------------------------------------------------------------ -- packages/acs-subsite/sql/application_groups-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: upgrade-4.1.1-4.2.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- ------------------------ -- APPLICATION GROUPS -- ------------------------ begin acs_object_type.create_type ( supertype => 'group', object_type => 'application_group', pretty_name => 'Application Group', pretty_plural => 'Application Groups', table_name => 'application_groups', id_column => 'group_id', package_name => 'application_group', type_extension_table => 'group_types', name_method => 'acs_group.name' ); end; / show errors create table application_groups ( group_id constraint app_groups_group_id_fk references groups (group_id) constraint app_groups_group_id_pk primary key, package_id constraint app_groups_package_id_fk references apm_packages, constraint app_groups_package_id_un unique (package_id) ); create or replace package application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE; procedure delete ( group_id in application_groups.group_id%TYPE ); function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char; end application_group; / show errors create or replace package body application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE is v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group.new ( group_id => group_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, email => email, url => url, group_name => group_name, context_id => context_id ); insert into application_groups (group_id, package_id) values (v_group_id, package_id); return v_group_id; end new; procedure delete ( group_id in application_groups.group_id%TYPE ) is begin acs_group.delete(group_id); end delete; function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char is v_group_id application_groups.group_id%TYPE; begin select group_id into v_group_id from application_groups where package_id = group_id_from_package_id.package_id; return v_group_id; exception when no_data_found then if no_complain_p != 't' then raise_application_error(-20000, 'No group_id found for package ' || package_id || ' (' || acs_object.name(package_id) || ').' ); end if; return null; end group_id_from_package_id; end application_group; / show errors insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'composition_rel'); insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'membership_rel'); ----------- -- Views -- ----------- create or replace view application_group_element_map as select g.package_id, g.group_id, m.element_id, m.container_id, m.rel_id, m.rel_type, m.ancestor_rel_type from application_groups g, group_element_map m where g.group_id = m.group_id; create or replace view app_group_distinct_element_map as select distinct package_id, group_id, element_id from application_group_element_map; create or replace view app_group_distinct_rel_map as select distinct package_id, group_id, rel_id, rel_type, ancestor_rel_type from application_group_element_map; create or replace view application_group_segments as select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, group_element_map m, rel_segments s where g.group_id = m.group_id and m.element_id = s.group_id UNION ALL select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, rel_segments s where g.group_id = s.group_id; ------------------------------------------------------------------------------ -- packages/acs-subsite/sql/user-profiles-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: upgrade-4.1.1-4.2.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- --------------------------- -- UPGRADE EXISTING DATA -- --------------------------- -- ACS's current system: -- -- - Magic object -2 is the 'Registered Users' party. -- -- - developers use the views registered_users and cc_registered_users. -- These views join the users table with the members of group -2. -- -- ACS Subsite 4.1.2 now adds a concept of users (or any party, for that -- matter) "belonging" to a subsite. The upgrade to 4.1.2 needs to -- add all registered users to the main site. -- -- In future versions of ACS, the registration stuff should get RIPPED OUT -- of the kernel (Rafi agrees). Right now, we take the path of least change. -- -- The new and improved system: -- -- - a group type called 'application_group' is created. Application groups -- have a package_id. The application group serves as a container for -- all parties that belong to the package_id application instance. -- (see application-groups-create.sql) -- -- - An application group called 'Main Site Parties' is created. Its -- package_id points to the main site. -- -- Assume that application-groups-create has already been run. set serveroutput on; declare v_package_id integer; v_group_name varchar(100); v_group_id integer; v_rel_id integer; v_segment_id integer; v_segment_name varchar(100); begin dbms_output.put_line('selecting main site instance name and package_id'); select package_id, substr(instance_name, 1, 90) || ' Parties', substr(instance_name, 1, 60) || ' Registered Users' into v_package_id, v_group_name, v_segment_name from apm_packages, site_nodes where site_nodes.object_id = apm_packages.package_id and site_nodes.parent_id is null; dbms_output.put_line('creating main site application_group'); v_group_id := application_group.new( group_name => v_group_name, package_id => v_package_id ); dbms_output.put_line('adding system users to main site'); for r in (select user_id, mr.member_state from users, membership_rels mr, acs_rels r where user_id = r.object_id_two and object_id_one = -2 and r.rel_id = mr.rel_id ) loop v_rel_id := membership_rel.new ( object_id_one => v_group_id, object_id_two => r.user_id, member_state => r.member_state ); end loop; -- add all the groups in the system to the Main Site Parties group -- (except for 'Registered Users' and 'Main Site Parties' itself) for r in (select group_id from groups where not exists(select 1 from group_component_map where group_id = groups.group_id) and group_id not in (-2, v_group_id)) loop v_rel_id := composition_rel.new ( object_id_one => v_group_id, object_id_two => r.group_id ); end loop; -- add the 'Main Site Registered Members' segment: v_segment_id := rel_segment.new( segment_name=> v_segment_name, group_id => v_group_id, rel_type => 'membership_rel' ); end; / show errors -------------------------------------------------------------- -- acs-subsite-create.sql -- oumi@arsdigita.com -- 2/20/2001 -- -- CHANGES -- -- Added party_names view. -------------------------------------------------------------- -- This view lets us avoid using acs_object.name to get party_names. -- create or replace view party_names as select p.party_id, decode(groups.group_id, null, decode(persons.person_id, null, p.email, persons.first_names || ' ' || persons.last_name), groups.group_name) as party_name from parties p, groups, persons where p.party_id = groups.group_id(+) and p.party_id = persons.person_id(+); -------------------------------------------------------------- -- subsite-callbacks-create.sql -- mbryzek@arsdigita.com -- 2/20/2001 -------------------------------------------------------------- -- /packages/acs-subsite/sql/subsite-group-callbacks-create.sql -- Defines a simple callback system to allow other applications to -- register callbacks when groups of a given type are created. -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- $Id: upgrade-4.1.1-4.2.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- What about instead of? -- insead_of viewing the group, go to the portal -- instead of inserting the group with package_instantiate_object, go here create table subsite_callbacks ( callback_id integer constraint sgc_callback_id_pk primary key, event_type varchar(100) not null constraint sgc_event_type_ck check(event_type in ('insert','update','delete')), object_type varchar(100) not null constraint sgc_object_type_fk references acs_object_types on delete cascade, callback varchar(300) not null, callback_type varchar(100) not null constraint sgc_callback_type_ck check(callback_type in ('tcl')), sort_order integer default(1) not null constraint sgc_sort_order_ck check(sort_order >= 1), -- allow only one callback of a given type for given constraint subsite_callbacks_un unique (object_type, event_type, callback_type, callback) ); comment on table subsite_callbacks is ' Applications can register callbacks that are triggered whenever a group of a specified type is created. The callback must expect the following arguments: * object_id: The object that just got created * node_id: The node_id where the object got created * package_id: The package_id from where the object got created These are passed in the following way: * tcl procedure: Using named parameters (e.g. -object_id $object_id) All callbacks must accept all of these parameters. '; comment on column subsite_callbacks.event_type is ' The type of event we are monitoring. The keywords here are used by the applications to determine which callbacks to trigger. '; comment on column subsite_callbacks.object_type is ' The object type to monitor. Whenever an object of this type is created, the subsite package will check for a registered callbacks. '; comment on column subsite_callbacks.callback_type is ' The type of the callback. This determines how the callback is executed. Currenlty only a tcl type is supported but other types may be added in the future. '; comment on column subsite_callbacks.callback is ' The actual callback. This can be the name of a plsql function or procedure, a url stub relative to the node at which package id is mounted, or the name of a tcl function. '; comment on column subsite_callbacks.sort_order is ' The order in which the callbacks should fire. This is important when you need to ensure that one event fires before another (e.g. you must mount a portals application before the bboard application) '; create or replace package subsite_callback as function new ( --/** Registers a new callback. If the same callback exists as -- defined in the unique constraint on the table, does -- nothing but returns the existing callback_id. -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE; procedure delete ( --/** Deletes the specified callback -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE ); end subsite_callback; / show errors; create or replace package body subsite_callback as function new ( callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE IS v_callback_id subsite_callbacks.callback_id%TYPE; v_sort_order subsite_callbacks.sort_order%TYPE; BEGIN if new.callback_id is null then select acs_object_id_seq.nextval into v_callback_id from dual; else v_callback_id := new.callback_id; end if; if new.sort_order is null then -- Make this the next event for this object_type/event_type combination select nvl(max(sort_order),0) + 1 into v_sort_order from subsite_callbacks where object_type = new.object_type and event_type = new.event_type; else v_sort_order := new.sort_order; end if; begin insert into subsite_callbacks (callback_id, event_type, object_type, callback, callback_type, sort_order) values (v_callback_id, new.event_type, new.object_type, new.callback, new.callback_type, v_sort_order); exception when dup_val_on_index then select callback_id into v_callback_id from subsite_callbacks where event_type = new.event_type and object_type = new.object_type and callback_type = new.callback_type and callback = new.callback; end; return v_callback_id; END new; procedure delete ( callback_id IN subsite_callbacks.callback_id%TYPE ) is begin delete from subsite_callbacks where callback_id=subsite_callback.delete.callback_id; end delete; end subsite_callback; / show errors; openacs-5.7.0/packages/acs-subsite/sql/oracle/upgrade/upgrade-4.5-4.5.1.sql0000644000175000017500000000035607661403636025624 0ustar frankiefrankie-- file: packages/acs-subsite/sql/oracle/upgrade/upgrade-4.5-4.5.1.sql -- -- @author jon@jongriffin.com -- @creation-date 2003-02-03 -- @cvs-id $Id: upgrade-4.5-4.5.1.sql,v 1.2 2003/05/17 09:57:50 jeffd Exp $ -- @@ ../user-sc-create.sql openacs-5.7.0/packages/acs-subsite/sql/oracle/email-image-drop.sql0000644000175000017500000000040410174512017024665 0ustar frankiefrankie-- -- packages/acs-subsite/sql/portraits-drop.sql -- -- author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) -- creation-date 2005-01-22 -- drop table email_images; begin acs_rel_type.drop_type('email_image_rel'); end; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/application-groups-create.sql0000644000175000017500000001401311140463710026635 0ustar frankiefrankie-- -- packages/acs-subsite/sql/application_groups-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: application-groups-create.sql,v 1.6 2009/01/30 02:36:56 donb Exp $ -- ------------------------ -- APPLICATION GROUPS -- ------------------------ begin acs_object_type.create_type ( supertype => 'group', object_type => 'application_group', pretty_name => 'Application Group', pretty_plural => 'Application Groups', table_name => 'application_groups', id_column => 'group_id', package_name => 'application_group', type_extension_table => 'group_types', name_method => 'acs_group.name' ); end; / show errors create table application_groups ( group_id constraint application_groups_group_id_fk references groups (group_id) constraint application_groups_group_id_pk primary key, package_id constraint ag_package_id_fk references apm_packages, constraint ag_package_id_un unique (package_id) ); create or replace package application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, join_policy in groups.join_policy%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE; procedure del ( group_id in application_groups.group_id%TYPE ); function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char; end application_group; / show errors create or replace package body application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, join_policy in groups.join_policy%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE is v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group.new ( group_id => group_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, email => email, url => url, group_name => group_name, context_id => context_id, join_policy => join_policy ); insert into application_groups (group_id, package_id) values (v_group_id, package_id); return v_group_id; end new; procedure del ( group_id in application_groups.group_id%TYPE ) is begin acs_group.del(group_id); end del; function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char is v_group_id application_groups.group_id%TYPE; begin select group_id into v_group_id from application_groups where package_id = group_id_from_package_id.package_id; return v_group_id; exception when no_data_found then if no_complain_p != 't' then raise_application_error(-20000, 'No group_id found for package ' || package_id || ' (' || acs_object.name(package_id) || ').' ); end if; return null; end group_id_from_package_id; end application_group; / show errors insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'composition_rel'); insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'membership_rel'); insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'admin_rel'); ----------- -- Views -- ----------- create or replace view application_group_element_map as select g.package_id, g.group_id, m.element_id, m.container_id, m.rel_id, m.rel_type, m.ancestor_rel_type from application_groups g, group_element_map m where g.group_id = m.group_id; create or replace view app_group_distinct_element_map as select distinct package_id, group_id, element_id from application_group_element_map; create or replace view app_group_distinct_rel_map as select distinct package_id, group_id, rel_id, rel_type, ancestor_rel_type from application_group_element_map; create or replace view application_group_segments as select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, group_element_map m, rel_segments s where g.group_id = m.group_id and m.element_id = s.group_id UNION ALL select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, rel_segments s where g.group_id = s.group_id; openacs-5.7.0/packages/acs-subsite/sql/oracle/subsite-callbacks-drop.sql0000644000175000017500000000105307263134052026116 0ustar frankiefrankie-- /packages/acs-subsite/sql/subsite-group-callbacks-drop.sql -- Drops the subsite group callbacks data model -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-21 -- $Id: subsite-callbacks-drop.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html drop package subsite_callback; drop table subsite_callbacks; openacs-5.7.0/packages/acs-subsite/sql/oracle/portraits.sql0000644000175000017500000000164710506242434023617 0ustar frankiefrankie-- Portrait Data Model -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Hiro Iwashima (iwashima@mit.edu) -- $Id: portraits.sql,v 1.2 2006/09/26 15:19:56 byronl Exp $ create table user_portraits ( user_id constraint user_portraits_user_id_fk references users constraint user_portraits_user_id_pk primary key ); begin acs_rel_type.create_role('user', 'User', 'Users'); acs_rel_type.create_role('portrait', 'Portrait', 'Portraits'); acs_rel_type.create_type ( rel_type => 'user_portrait_rel', pretty_name => 'User Portrait', pretty_plural => 'User Portraits', object_type_one => 'user', role_one => 'user', table_name => 'user_portraits', id_column => 'user_id', package_name => 'user_portrait_rel', min_n_rels_one => 1, max_n_rels_one => 1, object_type_two => 'content_item', min_n_rels_two => 0, max_n_rels_two => 1 ); commit; end; / show errors openacs-5.7.0/packages/acs-subsite/sql/oracle/acs-subsite-create.sql0000644000175000017500000000207511307331202025237 0ustar frankiefrankie-- Create the necessary data model and ACS relationships for the ACS Core UI. -- -- @author Hiro Iwashima (iwashima@mit.edu) -- -- @creation-date 28 August 2000 -- -- @cvs-id $Id: acs-subsite-create.sql,v 1.8 2009/12/08 01:57:22 donb Exp $ -- -- create table email_image_rel_ext ( -- rel_id integer constraint email_image_rel_ext_fk references acs_rels(rel_id) -- constraint email_image_rel_ext primary key -- ); @@ portraits @@ email-image @@ application-groups-create @@ subsite-callbacks-create @@ host-node-map-create @@ user-sc-create @@ site-node-selection @@ themes-create -- This view lets us avoid using acs_object.name to get party_names. -- create or replace view party_names as select p.party_id, decode(groups.group_id, null, decode(persons.person_id, null, p.email, persons.first_names || ' ' || persons.last_name), groups.group_name) as party_name from parties p, groups, persons where p.party_id = groups.group_id(+) and p.party_id = persons.person_id(+); openacs-5.7.0/packages/acs-subsite/sql/oracle/host-node-map-drop.sql0000644000175000017500000000011007361105405025166 0ustar frankiefrankie-- @author Alex Sokoloff (sokoloff@panix.com) drop table host_node_map;openacs-5.7.0/packages/acs-subsite/sql/postgresql/0000755000175000017500000000000011575225542022005 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/sql/postgresql/portraits-drop.sql0000644000175000017500000000054607266741036025527 0ustar frankiefrankie-- -- packages/acs-subsite/sql/portraits-drop.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: portraits-drop.sql,v 1.2 2001/04/17 04:10:06 danw Exp $ -- select acs_rel_type__drop_type('user_portrait_rel', 'f'); select acs_rel_type__drop_role('portrait'); select acs_rel_type__drop_role('user'); drop table user_portraits; openacs-5.7.0/packages/acs-subsite/sql/postgresql/subsite-callbacks-create.sql0000644000175000017500000002055211144344032027352 0ustar frankiefrankie-- /packages/acs-subsite/sql/subsite-group-callbacks-create.sql -- Defines a simple callback system to allow other applications to -- register callbacks when groups of a given type are created. -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- $Id: subsite-callbacks-create.sql,v 1.3 2009/02/10 18:31:54 jeffd Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- What about instead of? -- insead_of viewing the group, go to the portal -- instead of inserting the group with package_instantiate_object, go here create table subsite_callbacks ( callback_id integer constraint sgc_callback_id_pk primary key, event_type varchar(100) not null constraint sgc_event_type_ck check(event_type in ('insert','update','delete')), object_type varchar(100) not null constraint sgc_object_type_fk references acs_object_types on delete cascade, callback varchar(300) not null, callback_type varchar(100) not null constraint sgc_callback_type_ck check(callback_type in ('tcl')), sort_order integer default(1) not null constraint sgc_sort_order_ck check(sort_order >= 1), -- allow only one callback of a given type for given constraint subsite_callbacks_un unique (object_type, event_type, callback_type, callback) ); comment on table subsite_callbacks is ' Applications can register callbacks that are triggered whenever a group of a specified type is created. The callback must expect the following arguments: * object_id: The object that just got created * node_id: The node_id where the object got created * package_id: The package_id from where the object got created These are passed in the following way: * tcl procedure: Using named parameters (e.g. -object_id $object_id) All callbacks must accept all of these parameters. '; comment on column subsite_callbacks.event_type is ' The type of event we are monitoring. The keywords here are used by the applications to determine which callbacks to trigger. '; comment on column subsite_callbacks.object_type is ' The object type to monitor. Whenever an object of this type is created, the subsite package will check for a registered callbacks. '; comment on column subsite_callbacks.callback_type is ' The type of the callback. This determines how the callback is executed. Currenlty only a tcl type is supported but other types may be added in the future. '; comment on column subsite_callbacks.callback is ' The actual callback. This can be the name of a plsql function or procedure, a url stub relative to the node at which package id is mounted, or the name of a tcl function. '; comment on column subsite_callbacks.sort_order is ' The order in which the callbacks should fire. This is important when you need to ensure that one event fires before another (e.g. you must mount a portals application before the bboard application) '; -- create or replace package subsite_callback as -- function new ( -- --/** Registers a new callback. If the same callback exists as -- -- defined in the unique constraint on the table, does -- -- nothing but returns the existing callback_id. -- -- -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- -- @creation-date 2001-02-20 -- -- -- --*/ -- callback_id IN subsite_callbacks.callback_id%TYPE default null, -- event_type IN subsite_callbacks.event_type%TYPE, -- object_type IN subsite_callbacks.object_type%TYPE, -- callback IN subsite_callbacks.callback%TYPE, -- callback_type IN subsite_callbacks.callback_type%TYPE, -- sort_order IN subsite_callbacks.sort_order%TYPE default null -- ) return subsite_callbacks.callback_id%TYPE; -- procedure delete ( -- --/** Deletes the specified callback -- -- -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- -- @creation-date 2001-02-20 -- -- -- --*/ -- callback_id IN subsite_callbacks.callback_id%TYPE -- ); -- end subsite_callback; -- / -- show errors; -- create or replace package body subsite_callback as -- function new ( -- callback_id IN subsite_callbacks.callback_id%TYPE default null, -- event_type IN subsite_callbacks.event_type%TYPE, -- object_type IN subsite_callbacks.object_type%TYPE, -- callback IN subsite_callbacks.callback%TYPE, -- callback_type IN subsite_callbacks.callback_type%TYPE, -- sort_order IN subsite_callbacks.sort_order%TYPE default null -- ) return subsite_callbacks.callback_id%TYPE -- IS -- v_callback_id subsite_callbacks.callback_id%TYPE; -- v_sort_order subsite_callbacks.sort_order%TYPE; -- BEGIN -- if new.callback_id is null then -- select acs_object_id_seq.nextval into v_callback_id from dual; -- else -- v_callback_id := new.callback_id; -- end if; -- if new.sort_order is null then -- -- Make this the next event for this object_type/event_type combination -- select nvl(max(sort_order),0) + 1 into v_sort_order -- from subsite_callbacks -- where object_type = new.object_type -- and event_type = new.event_type; -- else -- v_sort_order := new.sort_order; -- end if; -- begin -- insert into subsite_callbacks -- (callback_id, event_type, object_type, callback, callback_type, sort_order) -- values -- (v_callback_id, new.event_type, new.object_type, new.callback, new.callback_type, v_sort_order); -- exception when dup_val_on_index then -- select callback_id into v_callback_id -- from subsite_callbacks -- where event_type = new.event_type -- and object_type = new.object_type -- and callback_type = new.callback_type -- and callback = new.callback; -- end; -- return v_callback_id; -- END new; create function subsite_callback__new(integer,varchar,varchar,varchar,varchar,integer) returns integer as ' declare new__callback_id alias for $1; -- default null, new__event_type alias for $2; new__object_type alias for $3; new__callback alias for $4; new__callback_type alias for $5; new__sort_order alias for $6; -- default null v_callback_id subsite_callbacks.callback_id%TYPE; v_sort_order subsite_callbacks.sort_order%TYPE; begin if new__callback_id is null then select nextval(''t_acs_object_id_seq'') into v_callback_id; else v_callback_id := new__callback_id; end if; if new__sort_order is null then -- Make this the next event for this object_type/event_type combination select coalesce(max(sort_order),0) + 1 into v_sort_order from subsite_callbacks where object_type = new__object_type and event_type = new__event_type; else v_sort_order := new__sort_order; end if; -- begin insert into subsite_callbacks (callback_id, event_type, object_type, callback, callback_type, sort_order) values (v_callback_id, new__event_type, new__object_type, new__callback, new__callback_type, v_sort_order); -- TODO: Can we do this properly? -- If not, could move select before insert -- exception when dup_val_on_index then -- select callback_id into v_callback_id -- from subsite_callbacks -- where event_type = new__event_type -- and object_type = new__object_type -- and callback_type = new__callback_type -- and callback = new__callback; -- end; return v_callback_id; end;' language 'plpgsql'; -- procedure delete ( -- callback_id IN subsite_callbacks.callback_id%TYPE -- ) -- is -- begin -- delete from subsite_callbacks where callback_id=subsite_callback.delete.callback_id; -- end delete; create function subsite_callback__delete(integer) returns integer as ' declare delete__callback_id alias for $1; begin delete from subsite_callbacks where callback_id = delete__callback_id; return 0; end;' language 'plpgsql'; -- end subsite_callback; -- / -- show errors; openacs-5.7.0/packages/acs-subsite/sql/postgresql/email-image.sql0000644000175000017500000000150710506043462024670 0ustar frankiefrankie-- Email Image Data Model -- author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) -- creation-date 2005-01-22 create table email_images ( user_id integer constraint email_images_user_id_fk references users constraint email_images_user_id_pk primary key ); create function inline_0 () returns integer as ' begin PERFORM acs_rel_type__create_role(''email_image'', ''Email Image'', ''Email Images''); PERFORM acs_rel_type__create_type ( ''email_image_rel'', ''Email Image'', ''Email Images'', ''relationship'', ''email_images'', ''user_id'', ''email_image_rel'', ''user'', ''user'', 1, 1, ''content_item'', null, 0, 1 ); return 0; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); openacs-5.7.0/packages/acs-subsite/sql/postgresql/site-node-selection-drop.sql0000644000175000017500000000031010171476724027335 0ustar frankiefrankie-- -- packages/acs-kernel/sql/site-node-selection.sql -- -- @author vivian@viaro.net -- @creation-date 2004-11-23 -- @cvs-id site-node-selection.sql -- drop table site_nodes_selection; --show errorsopenacs-5.7.0/packages/acs-subsite/sql/postgresql/host-node-map-create.sql0000644000175000017500000000057207611532652026445 0ustar frankiefrankie-- @author Mark Dettinger (mdettinger@arsdigita.com) -- $Id: host-node-map-create.sql,v 1.3 2003/01/16 13:37:46 jeffd Exp $ create table host_node_map ( host varchar(200) constraint host_node_map_host_pk primary key constraint host_node_map_host_nn not null, node_id integer constraint host_node_map_node_id_fk references site_nodes ); openacs-5.7.0/packages/acs-subsite/sql/postgresql/user-sc-create.sql0000644000175000017500000000566107512340404025347 0ustar frankiefrankie -- -- A service contract for allowing packages to be notified of changes in user information -- -- The operations defined here are -- UserData.UserNew -- UserData.UserApprove -- UserData.UserDeapprove -- UserData.UserDelete -- UserData.UserModify -- -- ben@openforce -- ported by dan chak (chak@openforce.net) -- Jan 22, 2002 create function inline_0() returns integer as ' declare foo integer; begin foo := acs_sc_contract__new( ''UserData'', ''User Data Updates'' ); -- The UserNew operation foo := acs_sc_msg_type__new( ''UserData.UserNew.InputType'', ''user_id:integer'' ); foo := acs_sc_msg_type__new( ''UserData.UserNew.OutputType'', '''' ); foo := acs_sc_operation__new( ''UserData'', ''UserNew'', ''Notify that a new user has been created'', ''f'', 1, ''UserData.UserNew.InputType'', ''UserData.UserNew.OutputType'' ); -- The UserApprove operation foo := acs_sc_msg_type__new( ''UserData.UserApprove.InputType'', ''user_id:integer'' ); foo := acs_sc_msg_type__new( ''UserData.UserApprove.OutputType'', '''' ); foo := acs_sc_operation__new( ''UserData'', ''UserApprove'', ''Notify that a user has been approved'', ''f'', 1, ''UserData.UserApprove.InputType'', ''UserData.UserApprove.OutputType'' ); -- The UserDeapprove operation foo := acs_sc_msg_type__new( ''UserData.UserDeapprove.InputType'', ''user_id:integer'' ); foo := acs_sc_msg_type__new( ''UserData.UserDeapprove.OutputType'', '''' ); foo := acs_sc_operation__new( ''UserData'', ''UserDeapprove'', ''Notify that a user has been deapproved'', ''f'', 1, ''UserData.UserDeapprove.InputType'', ''UserData.UserDeapprove.OutputType'' ); -- The UserModify operation foo := acs_sc_msg_type__new( ''UserData.UserModify.InputType'', ''user_id:integer'' ); foo := acs_sc_msg_type__new( ''UserData.UserModify.OutputType'', '''' ); foo := acs_sc_operation__new( ''UserData'', ''UserModify'', ''Notify that a user has been modified'', ''f'', 1, ''UserData.UserModify.InputType'', ''UserData.UserModify.OutputType'' ); -- The UserDelete operation foo := acs_sc_msg_type__new( ''UserData.UserDelete.InputType'', ''user_id:integer'' ); foo := acs_sc_msg_type__new( ''UserData.UserDelete.OutputType'', '''' ); foo := acs_sc_operation__new ( ''UserData'', ''UserDelete'', ''Notify that a user has been deleted'', ''f'', 1, ''UserData.UserDelete.InputType'', ''UserData.UserDelete.OutputType'' ); return 0; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); openacs-5.7.0/packages/acs-subsite/sql/postgresql/site-node-selection.sql0000644000175000017500000000074110440426466026400 0ustar frankiefrankie-- -- packages/acs-kernel/sql/site-node-selection.sql -- -- @author vivian@viaro.net -- @creation-date 2004-11-23 -- @cvs-id site-node-selection.sql -- create table site_nodes_selection ( node_id integer constraint site_nodes_sel_id_fk references acs_objects (object_id) on delete cascade constraint site_node_sel_id_pk primary key, view_p boolean ); --show errorsopenacs-5.7.0/packages/acs-subsite/sql/postgresql/themes-drop.sql0000644000175000017500000000003311010456340024733 0ustar frankiefrankiedrop table subsite_themes; openacs-5.7.0/packages/acs-subsite/sql/postgresql/acs-subsite-drop.sql0000644000175000017500000000101210174512610025671 0ustar frankiefrankie-- Uninstall file for the data model created by 'acs-core-ui-create.sql' -- (This file created automatically by create-sql-uninst.pl.) -- -- @author Bryan Quinn -- @creation-date (Sat Aug 26 17:56:07 2000) -- @cvs-id $Id: acs-subsite-drop.sql,v 1.5 2005/01/22 18:03:52 miguelm Exp $ \i subsite-callbacks-drop.sql \i user-profiles-drop.sql \i application-groups-drop.sql \i portraits-drop.sql \i email-image-drop.sql \i attributes-drop.sql \i host-node-map-drop.sql \i site-node-selection-dro.sql drop view party_names; openacs-5.7.0/packages/acs-subsite/sql/postgresql/themes-create.sql0000644000175000017500000000241411452447070025251 0ustar frankiefrankie-- For now, at least, there's no reason for this table to include objects. When a subsite_theme -- is installed, it can add to the table. When it is uninstalled, it can delete from the -- table. Theme switching is only accessible from the admin UI for subsites, therefore -- we don't need permissions on subsite_themes ... -- the css column contains a list of CSS file/media pairs. -- css and the form/list templates can be null because evil old OpenACS provides defaults -- for these. create table subsite_themes ( key text constraint subsite_themes_key_pk primary key, name text constraint subsite_themes_name_nn not null, template text constraint subsite_themes_template_nn not null, css text, form_template text, list_template text, list_filter_template text ); -- Insert the old themes that were hard-wired into earlier versions of acs-subsite. insert into subsite_themes (key, name, template) values ('obsolete_plain', 'Obsolete Plain', '/www/default-master'); insert into subsite_themes (key, name, template) values ('obsolete_tabbed', 'Obsolete Tabbed', '/packages/acs-subsite/www/group-master'); openacs-5.7.0/packages/acs-subsite/sql/postgresql/application-groups-drop.sql0000644000175000017500000000107007266741036027311 0ustar frankiefrankie-- -- packages/acs-subsite/sql/application-groups-drop.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: application-groups-drop.sql,v 1.2 2001/04/17 04:10:06 danw Exp $ -- delete from group_type_rels where rel_type = 'application_group'; drop view application_group_segments; drop view app_group_distinct_rel_map; drop view app_group_distinct_element_map; drop view application_group_element_map; select drop_package('application_group'); select acs_object_type__drop_type('application_group', 'f'); drop table application_groups; openacs-5.7.0/packages/acs-subsite/sql/postgresql/user-profiles-drop.sql0000644000175000017500000000072507266741036026276 0ustar frankiefrankie-- -- packages/acs-subsite/sql/user-profiles-drop.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: user-profiles-drop.sql,v 1.2 2001/04/17 04:10:06 danw Exp $ -- drop view cc_users_of_package_id; drop view registered_users_of_package_id; drop view application_users; select acs_rel_type__drop_type('user_profile', 'f'); select acs_rel_type__drop_role('application'); select drop_package('user_profile'); drop table user_profiles; openacs-5.7.0/packages/acs-subsite/sql/postgresql/user-profiles-create.sql0000644000175000017500000001461711144344032026563 0ustar frankiefrankie-- -- packages/acs-subsite/sql/user-profiles-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: user-profiles-create.sql,v 1.6 2009/02/10 18:31:54 jeffd Exp $ -- ------------------------------- -- APPLICATION USER PROFILES -- ------------------------------- -- begin -- -- the 'user' role should already exist from the portraits stuff. -- -- acs_rel_type.create_role('user', -- -- 'Registered User', 'Registered Users'); -- acs_rel_type.create_role('application', -- 'Application Group', 'Application Group'); -- acs_rel_type.create_type( -- rel_type => 'user_profile', -- pretty_name => 'User Profile', -- pretty_plural => 'User Profiles', -- supertype => 'membership_rel', -- table_name => 'user_profiles', -- id_column => 'profile_id', -- package_name => 'user_profile', -- abstract_p => 'f', -- object_type_one => 'application_group', -- role_one => 'application', -- min_n_rels_one => 0, -- max_n_rels_one => null, -- object_type_two => 'user', -- role_two => 'user', -- min_n_rels_two => 0, -- max_n_rels_two => null -- ); -- end; -- / -- show errors create function inline_0 () returns integer as ' begin -- the ''user'' role should already exist from the portraits stuff. -- acs_rel_type.create_role(''user'', -- ''Registered User'', ''Registered Users''); PERFORM acs_rel_type__create_role(''application'', ''Application Group'', ''Application Group''); PERFORM acs_rel_type__create_type ( ''user_profile'', ''#acs-subsite.User_Profile#'', ''#acs-subsite.User_Profiles#'', ''membership_rel'', ''user_profiles'', ''profile_id'', ''user_profile'', ''application_group'', ''application'', 0, null, ''user'', ''user'', 0, null ); return 0; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); create table user_profiles ( profile_id integer constraint user_profiles_profile_id_fk references membership_rels (rel_id) constraint user_profiles_profile_id_pk primary key ); -- create or replace package user_profile -- as -- function new ( -- profile_id in user_profiles.profile_id%TYPE default null, -- rel_type in acs_rels.rel_type%TYPE default 'user_profile', -- object_id_one in acs_rels.object_id_one%TYPE, -- object_id_two in acs_rels.object_id_two%TYPE, -- member_state in membership_rels.member_state%TYPE default null, -- creation_user in acs_objects.creation_user%TYPE default null, -- creation_ip in acs_objects.creation_ip%TYPE default null -- ) return user_profiles.profile_id%TYPE; -- procedure delete ( -- profile_id in user_profiles.profile_id%TYPE -- ); -- end user_profile; -- / -- show errors -- create or replace package body user_profile -- as -- function new ( -- profile_id in user_profiles.profile_id%TYPE default null, -- rel_type in acs_rels.rel_type%TYPE default 'user_profile', -- object_id_one in acs_rels.object_id_one%TYPE, -- object_id_two in acs_rels.object_id_two%TYPE, -- member_state in membership_rels.member_state%TYPE default null, -- creation_user in acs_objects.creation_user%TYPE default null, -- creation_ip in acs_objects.creation_ip%TYPE default null -- ) return user_profiles.profile_id%TYPE -- is -- v_profile_id integer; -- begin -- v_profile_id := membership_rel.new ( -- rel_id => profile_id, -- rel_type => rel_type, -- object_id_one => object_id_one, -- object_id_two => object_id_two, -- member_state => member_state, -- creation_user => creation_user, -- creation_ip => creation_ip -- ); -- insert into user_profiles (profile_id) values (v_profile_id); -- return v_profile_id; -- end new; select define_function_args('user_profile__new','profile_id,rel_type;user_profile,object_id_one,object_id_two,member_state,creation_user,creation_ip'); create function user_profile__new(integer,varchar,integer,integer,varchar,integer,varchar) returns integer as ' declare new__profile_id alias for $1; -- default null, new__rel_type alias for $2; -- default ''user_profile'', new__object_id_one alias for $3; new__object_id_two alias for $4; new__member_state alias for $5; -- default null, new__creation_user alias for $6; -- default null, new__creation_ip alias for $7; -- default null v_profile_id integer; begin v_profile_id := membership_rel__new ( new__profile_id, new__rel_type, new__object_id_one, new__object_id_two, new__member_state, new__creation_user, new__creation_ip ); insert into user_profiles (profile_id) values (v_profile_id); return v_profile_id; end;' language 'plpgsql'; -- procedure delete ( -- profile_id in user_profiles.profile_id%TYPE -- ) -- is -- begin -- membership_rel.delete(profile_id); -- end delete; create function user_profile__delete(integer) returns integer as ' declare profile_id alias for $1; begin PERFORM membership_rel__delete(profile_id); return 0; end;' language 'plpgsql'; -- end user_profile; -- / -- show errors insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (nextval('t_acs_object_id_seq', 'application_group', 'user_profile'); -- This view is extremely fast, but for some reason its not so blaxing fast -- when used in the registered_users_of_package_id view below. create view application_users as select ag.package_id, gem.element_id as user_id from user_profiles up, group_element_map gem, application_groups ag where ag.group_id = gem.group_id and gem.rel_id = up.profile_id; -- create the generalized versions of the registered_users and cc_users views: create view registered_users_of_package_id as select u.*, au.package_id from application_users au, registered_users u where au.user_id = u.user_id; create view cc_users_of_package_id as select u.*, au.package_id from application_users au, cc_users u where au.user_id = u.user_id; openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/0000755000175000017500000000000011724401447023430 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-4.6b-4.6.1b.sql0000644000175000017500000000145707742350676027100 0ustar frankiefrankie-- packages/acs-subsite/sql/postgresql/upgrade/upgrade-4.5.1-4.5.2.sql -- -- @author Eric Lorenzo (eric@openforce.net) -- @creation-date 2002-10-24 -- @cvs-id $Id: upgrade-4.6b-4.6.1b.sql,v 1.2 2003/10/12 22:12:14 tilmanns Exp $ -- Moving primary key constraint on host_node_map from node_id column -- to host column. Fortunately, nothing references the table, so a -- simple drop-rebuild is feasable alter table host_node_map rename to host_node_map_old; create table host_node_map ( host varchar(200) constraint host_node_map_new_pk primary key, node_id integer not null constraint host_node_map_new_fk references acs_objects (object_id) ); insert into host_node_map ( host, node_id ) select host, node_id from host_node_map_old; drop table host_node_map_old; openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-5.2.0b5-5.2.0b6.sql0000644000175000017500000000067510440426466027371 0ustar frankiefrankie-- -- -- -- @author Dave Bauer (dave@thedesignexperience.org) -- @creation-date 2005-11-29 -- @arch-tag: 2e1f8368-2c55-49fb-9b34-9cd6564288e1 -- @cvs-id $Id: upgrade-5.2.0b5-5.2.0b6.sql,v 1.2 2006/06/04 00:45:42 donb Exp $ -- alter table site_nodes_selection drop constraint site_nodes_sel_id_fk; alter table site_nodes_selection add constraint site_nodes_sel_id_fk foreign key (node_id) references acs_objects(object_id) on delete cascade; openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-4.6.4.1-4.6.4.2.sql0000644000175000017500000000123207733621120027210 0ustar frankiefrankie-- -- @author Lars Pind (lars@collaboraid.biz) -- @creation-date 2003-07-03 -- -- Add 'admin_rel' as a permissible relationship type for application groups -- -- Add 'admin_rel' as a permissible relationship type for application groups insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'admin_rel'); -- Then add it to all existing application groups insert into group_rels (group_rel_id, group_id, rel_type) select nextval('t_acs_object_id_seq'), group_id, 'admin_rel' from groups g, acs_objects o where o.object_id = g.group_id and o.object_type = 'application_group'; openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-5.5.0d1-5.5.0d2.sql0000644000175000017500000000241311452447070027361 0ustar frankiefrankie-- For now, at least, there's no reason for this table to include objects. When a subsite_theme -- is installed, it can add to the table. When it is uninstalled, it can delete from the -- table. Theme switching is only accessible from the admin UI for subsites, therefore -- we don't need permissions on subsite_themes ... -- the css column contains a list of CSS file/media pairs. -- css and the form/list templates can be null because evil old OpenACS provides defaults -- for these. create table subsite_themes ( key text constraint subsite_theme_key_pk primary key, name text constraint subsite_themes_name_nn not null, template text constraint subsite_themes_template_nn not null, css text, form_template text, list_template text, list_filter_template text ); -- Insert the old themes that were hard-wired into earlier versions of acs-subsite. insert into subsite_themes (key, name, template) values ('obsolete_plain', 'Obsolete Plain', '/www/default-master'); insert into subsite_themes (key, name, template) values ('obsolete_tabbed', 'Obsolete Tabbed', '/packages/acs-subsite/www/group-master'); openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-5.5.0d5-5.5.0d6.sql0000644000175000017500000000262411142361766027400 0ustar frankiefrankieselect define_function_args('application_group__new','group_id,object_type;application_group,creation_date;now(),creation_user,creation_ip,email,url,group_name,package_id,join_policy,context_id'); create or replace function application_group__new(integer,varchar,timestamptz,integer,varchar,varchar,varchar,varchar,integer,varchar,integer) returns integer as ' declare new__group_id alias for $1; new__object_type alias for $2; -- default ''application_group'', new__creation_date alias for $3; -- default sysdate, new__creation_user alias for $4; -- default null, new__creation_ip alias for $5; -- default null, new__email alias for $6; -- default null, new__url alias for $7; -- default null, new__group_name alias for $8; new__package_id alias for $9; new__join_policy alias for $10; new__context_id alias for $11; -- default null v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group__new ( new__group_id, new__object_type, new__creation_date, new__creation_user, new__creation_ip, new__email, new__url, new__group_name, new__join_policy, new__context_id ); insert into application_groups (group_id, package_id) values (v_group_id, new__package_id); return v_group_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-5.1.2-5.1.3.sql0000644000175000017500000000066710171476724026721 0ustar frankiefrankie-- -- packages/acs-kernel/sql/site-node-selection.sql -- -- @author vivian@viaro.net -- @creation-date 2004-11-23 -- @cvs-id site-node-selection.sql -- create table site_nodes_selection ( node_id integer constraint site_nodes_sel_id_fk references acs_objects (object_id) constraint site_node_sel_id_pk primary key, view_p boolean ); --show errorsopenacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-4.1.1-4.2.sql0000644000175000017500000004066010506043462026542 0ustar frankiefrankie -- before release, we'll have to copy and paste from the referenced sql -- files into this one. For now, we just reference some sql files. ------------------------------------------------------------------------------ -- packages/acs-subsite/sql/application_groups-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: upgrade-4.1.1-4.2.sql,v 1.2 2006/09/25 21:16:34 byronl Exp $ -- ------------------------ -- APPLICATION GROUPS -- ------------------------ begin acs_object_type.create_type ( supertype => 'group', object_type => 'application_group', pretty_name => 'Application Group', pretty_plural => 'Application Groups', table_name => 'application_groups', id_column => 'group_id', package_name => 'application_group', type_extension_table => 'group_types', name_method => 'acs_group.name' ); end; / show errors create table application_groups ( group_id constraint application_groups_group_id_fk references groups (group_id) constraint application_groups_group_id_pk primary key, package_id constraint application_groups_package_id_fk references apm_packages, constraint application_groups_package_id_un unique (package_id) ); create or replace package application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE; procedure delete ( group_id in application_groups.group_id%TYPE ); function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char; end application_group; / show errors create or replace package body application_group is function new ( group_id in application_groups.group_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'application_group', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, email in parties.email%TYPE default null, url in parties.url%TYPE default null, group_name in groups.group_name%TYPE, package_id in application_groups.package_id%TYPE, context_id in acs_objects.context_id%TYPE default null ) return application_groups.group_id%TYPE is v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group.new ( group_id => group_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, email => email, url => url, group_name => group_name, context_id => context_id ); insert into application_groups (group_id, package_id) values (v_group_id, package_id); return v_group_id; end new; procedure delete ( group_id in application_groups.group_id%TYPE ) is begin acs_group.delete(group_id); end delete; function group_id_from_package_id ( package_id in application_groups.group_id%TYPE, no_complain_p in char default 'f' ) return char is v_group_id application_groups.group_id%TYPE; begin select group_id into v_group_id from application_groups where package_id = group_id_from_package_id.package_id; return v_group_id; exception when no_data_found then if no_complain_p != 't' then raise_application_error(-20000, 'No group_id found for package ' || package_id || ' (' || acs_object.name(package_id) || ').' ); end if; return null; end group_id_from_package_id; end application_group; / show errors insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'composition_rel'); insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (acs_object_id_seq.nextval, 'application_group', 'membership_rel'); ----------- -- Views -- ----------- create or replace view application_group_element_map as select g.package_id, g.group_id, m.element_id, m.container_id, m.rel_id, m.rel_type, m.ancestor_rel_type from application_groups g, group_element_map m where g.group_id = m.group_id; create or replace view app_group_distinct_element_map as select distinct package_id, group_id, element_id from application_group_element_map; create or replace view app_group_distinct_rel_map as select distinct package_id, group_id, rel_id, rel_type, ancestor_rel_type from application_group_element_map; create or replace view application_group_segments as select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, group_element_map m, rel_segments s where g.group_id = m.group_id and m.element_id = s.group_id UNION ALL select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, rel_segments s where g.group_id = s.group_id; ------------------------------------------------------------------------------ -- packages/acs-subsite/sql/user-profiles-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: upgrade-4.1.1-4.2.sql,v 1.2 2006/09/25 21:16:34 byronl Exp $ -- --------------------------- -- UPGRADE EXISTING DATA -- --------------------------- -- ACS's current system: -- -- - Magic object -2 is the 'Registered Users' party. -- -- - developers use the views registered_users and cc_registered_users. -- These views join the users table with the members of group -2. -- -- ACS Subsite 4.1.2 now adds a concept of users (or any party, for that -- matter) "belonging" to a subsite. The upgrade to 4.1.2 needs to -- add all registered users to the main site. -- -- In future versions of ACS, the registration stuff should get RIPPED OUT -- of the kernel (Rafi agrees). Right now, we take the path of least change. -- -- The new and improved system: -- -- - a group type called 'application_group' is created. Application groups -- have a package_id. The application group serves as a container for -- all parties that belong to the package_id application instance. -- (see application-groups-create.sql) -- -- - An application group called 'Main Site Parties' is created. Its -- package_id points to the main site. -- -- Assume that application-groups-create has already been run. set serveroutput on; declare v_package_id integer; v_group_name varchar(100); v_group_id integer; v_rel_id integer; v_segment_id integer; v_segment_name varchar(100); begin dbms_output.put_line('selecting main site instance name and package_id'); select package_id, substr(instance_name, 1, 90) || ' Parties', substr(instance_name, 1, 60) || ' Registered Users' into v_package_id, v_group_name, v_segment_name from apm_packages, site_nodes where site_nodes.object_id = apm_packages.package_id and site_nodes.parent_id is null; dbms_output.put_line('creating main site application_group'); v_group_id := application_group.new( group_name => v_group_name, package_id => v_package_id ); dbms_output.put_line('adding system users to main site'); for r in (select user_id, mr.member_state from users, membership_rels mr, acs_rels r where user_id = r.object_id_two and object_id_one = -2 and r.rel_id = mr.rel_id ) loop v_rel_id := membership_rel.new ( object_id_one => v_group_id, object_id_two => r.user_id, member_state => r.member_state ); end loop; -- add all the groups in the system to the Main Site Parties group -- (except for 'Registered Users' and 'Main Site Parties' itself) for r in (select group_id from groups where not exists(select 1 from group_component_map where group_id = groups.group_id) and group_id not in (-2, v_group_id)) loop v_rel_id := composition_rel.new ( object_id_one => v_group_id, object_id_two => r.group_id ); end loop; -- add the 'Main Site Registered Members' segment: v_segment_id := rel_segment.new( segment_name=> v_segment_name, group_id => v_group_id, rel_type => 'membership_rel' ); end; / show errors -------------------------------------------------------------- -- acs-subsite-create.sql -- oumi@arsdigita.com -- 2/20/2001 -- -- CHANGES -- -- Added party_names view. -------------------------------------------------------------- -- This view lets us avoid using acs_object.name to get party_names. -- create or replace view party_names as select p.party_id, decode(groups.group_id, null, decode(persons.person_id, null, p.email, persons.first_names || ' ' || persons.last_name), groups.group_name) as party_name from parties p, groups, persons where p.party_id = groups.group_id(+) and p.party_id = persons.person_id(+); -------------------------------------------------------------- -- subsite-callbacks-create.sql -- mbryzek@arsdigita.com -- 2/20/2001 -------------------------------------------------------------- -- /packages/acs-subsite/sql/subsite-group-callbacks-create.sql -- Defines a simple callback system to allow other applications to -- register callbacks when groups of a given type are created. -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- $Id: upgrade-4.1.1-4.2.sql,v 1.2 2006/09/25 21:16:34 byronl Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- What about instead of? -- insead_of viewing the group, go to the portal -- instead of inserting the group with package_instantiate_object, go here create table subsite_callbacks ( callback_id integer constraint sgc_callback_id_pk primary key, event_type varchar(100) not null constraint sgc_event_type_ck check(event_type in ('insert','update','delete')), object_type varchar(100) not null constraint sgc_object_type_fk references acs_object_types on delete cascade, callback varchar(300) not null, callback_type varchar(100) not null constraint sgc_callback_type_ck check(callback_type in ('tcl')), sort_order integer default(1) not null constraint sgc_sort_order_ck check(sort_order >= 1), -- allow only one callback of a given type for given constraint subsite_callbacks_un unique (object_type, event_type, callback_type, callback) ); comment on table subsite_callbacks is ' Applications can register callbacks that are triggered whenever a group of a specified type is created. The callback must expect the following arguments: * object_id: The object that just got created * node_id: The node_id where the object got created * package_id: The package_id from where the object got created These are passed in the following way: * tcl procedure: Using named parameters (e.g. -object_id $object_id) All callbacks must accept all of these parameters. '; comment on column subsite_callbacks.event_type is ' The type of event we are monitoring. The keywords here are used by the applications to determine which callbacks to trigger. '; comment on column subsite_callbacks.object_type is ' The object type to monitor. Whenever an object of this type is created, the subsite package will check for a registered callbacks. '; comment on column subsite_callbacks.callback_type is ' The type of the callback. This determines how the callback is executed. Currenlty only a tcl type is supported but other types may be added in the future. '; comment on column subsite_callbacks.callback is ' The actual callback. This can be the name of a plsql function or procedure, a url stub relative to the node at which package id is mounted, or the name of a tcl function. '; comment on column subsite_callbacks.sort_order is ' The order in which the callbacks should fire. This is important when you need to ensure that one event fires before another (e.g. you must mount a portals application before the bboard application) '; create or replace package subsite_callback as function new ( --/** Registers a new callback. If the same callback exists as -- defined in the unique constraint on the table, does -- nothing but returns the existing callback_id. -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE; procedure delete ( --/** Deletes the specified callback -- -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-20 -- --*/ callback_id IN subsite_callbacks.callback_id%TYPE ); end subsite_callback; / show errors; create or replace package body subsite_callback as function new ( callback_id IN subsite_callbacks.callback_id%TYPE default null, event_type IN subsite_callbacks.event_type%TYPE, object_type IN subsite_callbacks.object_type%TYPE, callback IN subsite_callbacks.callback%TYPE, callback_type IN subsite_callbacks.callback_type%TYPE, sort_order IN subsite_callbacks.sort_order%TYPE default null ) return subsite_callbacks.callback_id%TYPE IS v_callback_id subsite_callbacks.callback_id%TYPE; v_sort_order subsite_callbacks.sort_order%TYPE; BEGIN if new.callback_id is null then select acs_object_id_seq.nextval into v_callback_id from dual; else v_callback_id := new.callback_id; end if; if new.sort_order is null then -- Make this the next event for this object_type/event_type combination select nvl(max(sort_order),0) + 1 into v_sort_order from subsite_callbacks where object_type = new.object_type and event_type = new.event_type; else v_sort_order := new.sort_order; end if; begin insert into subsite_callbacks (callback_id, event_type, object_type, callback, callback_type, sort_order) values (v_callback_id, new.event_type, new.object_type, new.callback, new.callback_type, v_sort_order); exception when dup_val_on_index then select callback_id into v_callback_id from subsite_callbacks where event_type = new.event_type and object_type = new.object_type and callback_type = new.callback_type and callback = new.callback; end; return v_callback_id; END new; procedure delete ( callback_id IN subsite_callbacks.callback_id%TYPE ) is begin delete from subsite_callbacks where callback_id=subsite_callback.delete.callback_id; end delete; end subsite_callback; / show errors; openacs-5.7.0/packages/acs-subsite/sql/postgresql/upgrade/upgrade-4.5-4.5.1.sql0000644000175000017500000000035007522620743026550 0ustar frankiefrankie-- packages/acs-subsite/sql/postgresql/upgrade/upgrade-4.2-4.5.sql -- -- @author jon@jongriffi.com -- @creation-date 2002-08-02 -- @cvs-id $Id: upgrade-4.5-4.5.1.sql,v 1.1 2002/08/03 00:20:51 jong Exp $ -- \i ../user-sc-create.sql openacs-5.7.0/packages/acs-subsite/sql/postgresql/email-image-drop.sql0000644000175000017500000000044610174512430025630 0ustar frankiefrankie-- -- packages/acs-subsite/sql/email-image-drop.sql -- -- author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) -- creation-date 2005-01-22 -- select acs_rel_type__drop_type('email_image_rel', 'f'); select acs_rel_type__drop_role('email_image'); drop table email_images; openacs-5.7.0/packages/acs-subsite/sql/postgresql/application-groups-create.sql0000644000175000017500000001160011144344032027571 0ustar frankiefrankie-- -- packages/acs-subsite/sql/application_groups-create.sql -- -- @author oumi@arsdigita.com -- @creation-date 2000-02-02 -- @cvs-id $Id: application-groups-create.sql,v 1.12 2009/02/10 18:31:54 jeffd Exp $ -- ------------------------ -- APPLICATION GROUPS -- ------------------------ select acs_object_type__create_type ( 'application_group', 'Application Group', 'Application Groups', 'group', 'application_groups', 'group_id', 'application_group', 'f', 'group_types', 'acs_group__name' ); create table application_groups ( group_id integer constraint application_groups_group_id_fk references groups (group_id) constraint application_groups_group_id_pk primary key, package_id integer constraint application_groups_package_id_fk references apm_packages, constraint application_groups_package_id_un unique (package_id) ); select define_function_args('application_group__new','group_id,object_type;application_group,creation_date;now(),creation_user,creation_ip,email,url,group_name,package_id,join_policy,context_id'); create function application_group__new(integer,varchar,timestamptz,integer,varchar,varchar,varchar,varchar,integer,varchar,integer) returns integer as ' declare new__group_id alias for $1; new__object_type alias for $2; -- default ''application_group'', new__creation_date alias for $3; -- default sysdate, new__creation_user alias for $4; -- default null, new__creation_ip alias for $5; -- default null, new__email alias for $6; -- default null, new__url alias for $7; -- default null, new__group_name alias for $8; new__package_id alias for $9; new__join_policy alias for $10; new__context_id alias for $11; -- default null v_group_id application_groups.group_id%TYPE; begin v_group_id := acs_group__new ( new__group_id, new__object_type, new__creation_date, new__creation_user, new__creation_ip, new__email, new__url, new__group_name, new__join_policy, new__context_id ); insert into application_groups (group_id, package_id) values (v_group_id, new__package_id); return v_group_id; end;' language 'plpgsql'; create function application_group__delete(integer) returns integer as ' declare group_id alias for $1; begin PERFORM acs_group__delete(group_id); return 0; end;' language 'plpgsql'; create function application_group__group_id_from_package_id(integer,boolean) returns integer as ' declare group_id_from_package_id__package_id alias for $1; group_id_from_package_id__no_complain_p alias for $2; -- default ''f'' v_group_id application_groups.group_id%TYPE; v_object_name varchar; begin select group_id into v_group_id from application_groups where package_id = group_id_from_package_id__package_id; -- TODO: does this shortcut the exception in Oracle? -- return v_group_id; if not found then if group_id_from_package_id__no_complain_p != ''t'' then v_object_name := acs_object__name(group_id_from_package_id__package_id); raise EXCEPTION ''-20000: No group_id found for package % (%)'', group_id_from_package_id__package_id, v_object_name; end if; return null; else return v_group_id; end if; end;' language 'plpgsql' stable; insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (nextval('t_acs_object_id_seq'), 'application_group', 'composition_rel'); insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (nextval('t_acs_object_id_seq'), 'application_group', 'membership_rel'); insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (nextval('t_acs_object_id_seq'), 'application_group', 'admin_rel'); ----------- -- Views -- ----------- create view application_group_element_map as select g.package_id, g.group_id, m.element_id, m.container_id, m.rel_id, m.rel_type, m.ancestor_rel_type from application_groups g, group_element_map m where g.group_id = m.group_id; create view app_group_distinct_element_map as select distinct package_id, group_id, element_id from application_group_element_map; create view app_group_distinct_rel_map as select distinct package_id, group_id, rel_id, rel_type, ancestor_rel_type from application_group_element_map; create view application_group_segments as select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, group_element_map m, rel_segments s where g.group_id = m.group_id and m.element_id = s.group_id UNION ALL select g.package_id, s.segment_id, s.group_id, s.rel_type, s.segment_name from application_groups g, rel_segments s where g.group_id = s.group_id; openacs-5.7.0/packages/acs-subsite/sql/postgresql/subsite-callbacks-drop.sql0000644000175000017500000000106507266741036027070 0ustar frankiefrankie-- /packages/acs-subsite/sql/subsite-group-callbacks-drop.sql -- Drops the subsite group callbacks data model -- Copyright (C) 2001 ArsDigita Corporation -- @author Michael Bryzek (mbryzek@arsdigita.com) -- @creation-date 2001-02-21 -- $Id: subsite-callbacks-drop.sql,v 1.2 2001/04/17 04:10:06 danw Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html select drop_package('subsite_callback'); drop table subsite_callbacks; openacs-5.7.0/packages/acs-subsite/sql/postgresql/portraits.sql0000644000175000017500000000316610506043462024553 0ustar frankiefrankie-- Portrait Data Model -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Hiro Iwashima (iwashima@mit.edu) -- $Id: portraits.sql,v 1.4 2006/09/25 21:16:34 byronl Exp $ create table user_portraits ( user_id integer constraint user_portraits_user_id_fk references users constraint user_portraits_user_id_pk primary key ); -- begin -- acs_rel_type.create_role('user', 'User', 'Users'); -- acs_rel_type.create_role('portrait', 'Portrait', 'Portraits'); -- acs_rel_type.create_type ( -- rel_type => 'user_portrait_rel', -- pretty_name => 'User Portrait', -- pretty_plural => 'User Portraits', -- object_type_one => 'user', -- role_one => 'user', -- table_name => 'user_portraits', -- id_column => 'user_id', -- package_name => 'user_portrait_rel', -- min_n_rels_one => 1, -- max_n_rels_one => 1, -- object_type_two => 'content_item', -- min_n_rels_two => 0, -- max_n_rels_two => 1 -- ); -- commit; -- end; -- / -- show errors create function inline_0 () returns integer as ' begin PERFORM acs_rel_type__create_role(''user'', ''User'', ''Users''); PERFORM acs_rel_type__create_role(''portrait'', ''Portrait'', ''Portraits''); PERFORM acs_rel_type__create_type ( ''user_portrait_rel'', ''#acs-subsite.User_Portrait#'', ''#acs-subsite.User_Portraits#'', ''relationship'', ''user_portraits'', ''user_id'', ''user_portrait_rel'', ''user'', ''user'', 1, 1, ''content_item'', null, 0, 1 ); return 0; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); openacs-5.7.0/packages/acs-subsite/sql/postgresql/acs-subsite-create.sql0000644000175000017500000000307711307331202026200 0ustar frankiefrankie-- Create the necessary data model and ACS relationships for the ACS Core UI. -- -- @author Hiro Iwashima (iwashima@mit.edu) -- -- @creation-date 28 August 2000 -- -- @cvs-id $Id: acs-subsite-create.sql,v 1.9 2009/12/08 01:57:22 donb Exp $ -- \i portraits.sql \i email-image.sql \i application-groups-create.sql \i subsite-callbacks-create.sql \i host-node-map-create.sql \i user-sc-create.sql \i site-node-selection.sql \i themes-create.sql -- DRB: user profiles are fundamentally broken, which is probably why they -- weren't created in the original ACS 4.2 Oracle sources. -- \i user-profiles-create.sql -- This view lets us avoid using acs_object.name to get party_names. -- -- create or replace view party_names -- as -- select p.party_id, -- decode(groups.group_id, -- null, decode(persons.person_id, -- null, p.email, -- persons.first_names || ' ' || persons.last_name), -- groups.group_name) as party_name -- from parties p, -- groups, -- persons -- where p.party_id = groups.group_id(+) -- and p.party_id = persons.person_id(+); create view party_names as select p.party_id, (case when groups.group_id is null then (case when persons.person_id is null then p.email else persons.first_names || ' ' || persons.last_name end) else groups.group_name end) as party_name from ((parties p left outer join groups on p.party_id = groups.group_id) left outer join persons on p.party_id = persons.person_id); openacs-5.7.0/packages/acs-subsite/sql/postgresql/host-node-map-drop.sql0000644000175000017500000000011007361106754026134 0ustar frankiefrankie-- @author Alex Sokoloff (sokoloff@panix.com) drop table host_node_map;openacs-5.7.0/packages/acs-subsite/www/0000755000175000017500000000000011575225553017631 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/doc/0000755000175000017500000000000011724401447020370 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/doc/group-admin-pages-requirements.html0000644000175000017500000002214207335322027027316 0ustar frankiefrankie Group Admin Pages - Requirements

    Group Admin Pages - Requirements

    ACS subsite docs : Group Admin Pages - Requirements

    I. Introduction

    The subsites package offers a powerful way to create discrete collections of subcommunities on top of a single ACS installation. The package must be permissions-aware for all groups, relational segments and constraints, and relations.

    The subsites package must also allow administrators to dynamically extend existing group and relationship types and to define attributes for new types.

    II. Vision Statement

    From /doc/subsites-requirements.html:
    The other piece of the subsite system is a subsite package that provides subsite admins a "control panel" for administering their subsite. This is the same package used to provide all the community core functionality available at the "main" site which is in fact simply another subsite.
    This control panel needs to treat individual groups as belonging to a single instance of a subsite. However, groups themselves are not enough. We must allow a subsite to specify its own types of groups, instances of those types (or of a type from a parent subsite), and types of relationships between those groups.

    III. Historical Motivations

    In the ACS 3.x architecture, many modules, e.g. portals, intranet, and bboard, created their own group types to manage different aspects of the module. While it is true that the ACS Permissioning package will replace the need for group types used exclusively for controlling permissions, some modules require the logical grouping of other parties. For these modules, we must restrict administrative control of their groups to administrators of the subsite. Without this ability, a user with administrative privilege of one subsite can administer all other groups in the system.

    IV. Use case and User Scenarios

    The Intranet Application

    The Intranet application may model employees in many ways. Without loss of generality, we assume each employee is a "person" with an "employment relation" to a company. Figure 1 shows an outline of what the ACS Site Map may look like with several companies. Note that each company represents one instance of the intranet application.



    Figure 1: Structure of Multiple Intranets

    The employment relation is a subtype of the ACS Membership Relation with additional attributes specific to employees (e.g. salary, start date, etc.). Administrators of each instance of the intranet application must be able to create the subtype and to specify the attributes of the subtype dynamically. For example, the ArsDigita administrator may track salary, biography, and education while IBM administrators may choose to track salary and family member information.

    Note: The current version of ACS, 4.0.1, does not treat object types as objects. This is a problem for subsites wishing to support dynamic sub-typing as name collisions are common because object types do not have context. The ability to create unique types of relationships for a given instance of the intranet application requires the object type to be unique to the instance. In other words, the context of the object type is set to the subsite. We use the context here so that we can automatically maintain permissions from subsite to object type.

    VI.A Requirements: Data Model

    10.10 Default relationship types for group types

    Each group type should specify a set of permissible relationship types to use for groups of that type.

    10.20 Default relationship types for groups

    The administrator must be able to specify the permissible relationship types to use for each group. The defaults are inherited from the list of permissible relationship types for the group's type.

    VI.B Requirements: API

    20.10 Define a new group type

    Users should be able to create a new type of group.

    30.10 Specify attributes

    Users should be able to dynamically add attributes to group types. These attributes should be stored efficiently.

    35.10 Remove attributes

    Users should be able to dynamically remove attributes from a group type. Removing the attribute removes all values specified for that attribute.

    40.10 Relationship Constraints

    The API must support the following types of constraints on relationships:

    40.10.10 Permissible relationships

    Each group type should maintain a list of all relationship types that can be used to add elements to groups of this group type.

    40.10.20 Constraints on relationships

    Relationships listed as allowable for a given group type should link to more information about the relationship type, including any constraints that must be satisfied before relations of the specified type are created.

    40.10.30 Constrain membership to a given group

    The system provides a well-defined API call that adds a given relationship type to the list of allowable relationship types to apply to a given group or group type. Any subtype of an allowable relationship type will also be allowed.

    VI.C Requirements: User Interface

    100.10 Create a group type with attributes

    When creating a new group type, the UI should support ACS datatypes with appropriate UI.

    130.10 Group type summary page
    130.10.10 Display allowable relationship types

    The group type summary page should display all the relationship types used to add relations to groups of this type and allow the user to add permissible relationship types or to remove existing ones.

    130.10.20 Display groups

    Display all groups of this type, based on permissions. UI should scale well with a large number of groups.

    110.10 Create an instance of a particular group type

    When creating a new group of the specified type, the UI must request values for each of the attributes of that type, including attributes of all supertypes (up the type tree until the object of type 'group').

    130.10.20 Display type attributes

    Display all attributes for this group type, including supertypes.

    130.10.20 Delete group type

    Allow administrators to delete the group type. This action removes all groups of this type.

    150.10 Group instance summary page
    150.10.10 Display relations

    Each group should display all the parties related to it and through what relationship type. Offer links to remove each relation or to add a new relation of a given type. The UI for relations should scale well.

    150.10.20 Display attributes

    Display all attributes of the group with links to edit each.

    150.10.20 Delete group

    Allow administrators to delete the group including all relations to the group.

    150.20 Integration with relational Segments and Constraints

    The group summary page should offer links to define relational segments for the group, based on a particular relationship type. The UI must also integrate with the relational constraints data model to support defining constraints on intra-party relations.

    Revision History

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Creation 11/16/2000 Michael Bryzek
    0.2 Major Revisions 11/24/2000 Michael Bryzek
    1.0 Final Revisions 1/11/2001 Michael Bryzek

    Michael Bryzek

    $Id: group-admin-pages-requirements.html,v 1.2 2001/08/11 21:31:03 ben Exp $ openacs-5.7.0/packages/acs-subsite/www/doc/images.html0000644000175000017500000001104711043711736022525 0ustar frankiefrankie ACS Subsite Documentation

    Images available from subsite package

    Link is of the form <img src="/resources/filename\" />
    Add16.gif
    Add24.gif
    Copy16.gif
    Copy24.gif
    Delete16.gif
    Delete24.gif
    Edit16.gif
    Edit24.gif
    New16.gif
    New24.gif
    Open16.gif
    Open24.gif
    Preferences16.gif
    Preferences24.gif
    Properties16.gif
    Properties24.gif
    Zoom16.gif
    Zoom24.gif
    ZoomIn16.gif
    ZoomIn24.gif
    ZoomOut16.gif
    ZoomOut24.gif
    action-link-marker.png
    add.gif
    arrow-down.gif
    arrow-up.gif
    bold-button.gif
    checkbox.gif
    checkboxchecked.gif
    core.js
    diamond.gif
    go.gif
    http.png
    info.gif
    italic-button.gif
    left.gif
    new.gif
    profile-16.png
    radio.gif
    radiochecked.gif
    right.gif
    spacer.gif
    stock_copy-16.png
    stock_copy.png
    stock_first-16.png
    stock_first.png
    stock_last-16.png
    stock_last.png
    stock_left-16.png
    stock_left.png
    stock_right-16.png
    stock_right.png
    underline-button.gif
    url-button.gif
    xml.gif
    up.gif
    down.gif
    openacs-5.7.0/packages/acs-subsite/www/doc/index.html0000644000175000017500000000261310171476745022377 0ustar frankiefrankie ACS Subsite Documentation

    ACS Subsite Documentation

    ACS subsite docs

    Document overview

    Overall requirements Overview of the requirements that motivated the design of subsites.
    Design Overview of the API provided by ACS subsites including the package manger, site nodes, and request processor hooks.
    Group admin pages requirements Overview of the requirements for web-based group administration tools
    Group admin pages design Overview of the API and design of the web-based group administration
    Subsite images Shows all (hopefully) images available from the subsite package


    Michael Bryzek

    $Id: index.html,v 1.2 2005/01/13 13:55:49 jeffd Exp $ openacs-5.7.0/packages/acs-subsite/www/doc/group-admin-pages-acceptance-test.html0000644000175000017500000002745407736271233027660 0ustar frankiefrankie Group Admin Pages - Acceptance test

    Group Admin Pages - Acceptance test

    ACS subsite docs : Group Admin Pages - Acceptance test

    DEVELOPER DEFINED GROUP TYPES TEST

    The first thing we have to test is developer defined group types working in conjunction with the user defined ones.

    Create the following object type in SQL*Plus.

    begin
     acs_object_type.create_type (
       supertype => 'group',
       object_type => 'developer_defined_test_type',
       pretty_name => 'Developer defined test type',
       pretty_plural => 'Developer defined test types',
       table_name => 'developer_defined_test_types',
       id_column => 'test_group_id',
       package_name => 'developer_defined_test_type',
       name_method => 'acs_group.name'
     );
    end;
    /
    show errors;   
    
    
    create table developer_defined_test_types (
           test_group_id   integer primary key references groups(group_id)
    );
    
    
    create or replace package developer_defined_test_type
    as
    
      function new (
             TEST_GROUP_ID   IN DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE DEFAULT NULL,
             GROUP_NAME      IN GROUPS.GROUP_NAME%TYPE,
             OBJECT_TYPE     IN ACS_OBJECTS.OBJECT_TYPE%TYPE DEFAULT 'developer_defined_test_type'
      ) return DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE;
    
      procedure delete (
        TEST_GROUP_ID      in DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE
      );
    
    end developer_defined_test_type;
    /
    show errors
    
    create or replace package body developer_defined_test_type
    as
    
      function new (
             TEST_GROUP_ID   IN DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE DEFAULT NULL,
             GROUP_NAME      IN GROUPS.GROUP_NAME%TYPE,
             OBJECT_TYPE     IN ACS_OBJECTS.OBJECT_TYPE%TYPE DEFAULT 'developer_defined_test_type'
      ) return DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE
      is
        v_TEST_GROUP_ID DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE;
      begin
    
        v_TEST_GROUP_ID := acs_group.new (
                         group_id         => new.TEST_GROUP_ID,
                         GROUP_NAME       => new.GROUP_NAME,
                         OBJECT_TYPE      => new.OBJECT_TYPE
                       );
    
        insert into DEVELOPER_DEFINED_TEST_TYPES
        (TEST_GROUP_ID)
        values
        (v_TEST_GROUP_ID);
    
        return v_TEST_GROUP_ID;
    
      end new;
    
      procedure delete (
        TEST_GROUP_ID      in DEVELOPER_DEFINED_TEST_TYPES.TEST_GROUP_ID%TYPE
      )
      is
      begin
    
        acs_group.del( developer_defined_test_type.delete.TEST_GROUP_ID );
    
      end delete;
    
    end developer_defined_test_type;
    /
    show errors
    
    
    1. Go to /admin/group-types and select "Developer defined test types"
    2. Add a permissible rel type of Membership Relation
    3. Add a group named "Test group"

    GROUP TYPE PAGES BASIC FUNCTIONALITY

    (Start at /admin)

    1. Click on group types
    2. Click on Groups
    3. Click on "Group name" under "Attributes of this type of group"
    4. Ensure that you see the properties of the attribute and that you are offered no administrative links
    5. Make sure you cannot add attributes or do anything under administration
    6. Make sure you see Composition and Membership Relation as the default relationship types
    7. Add a new group called "Foobar" - Make sure Foobar appears after adding the group
    8. Click on Foobar
    9. Click on nuke this group then click no. Ensure group is not deleted
    10. Click on nuke this group then click yes. Group should no longer show up
    11. Recreate the group Foobar
    12. Click on foobar, then change the name to "ArsDigita"
    13. Change ArsDigita's join policy to closed

    DYNAMICALLY EXTENDING GROUPS

    (Start at /admin/group-types/)
    1. Click on "Define a new group type" and create a new group type called "Project" with type "project". Ensure that all the fields you see are required (try submitting without entering in anything).
    2. Define another group type, child of group, named "Test"
    3. Define another group type, 'subproject', child of project. Ensure that the index page correctly displays the hierarchy.
    4. Define a new group type with group type = group. See error message saying type already exists.
    5. Go back to the index page (/admin/group-types).
    6. Click on the Test group type. Make sure that:
      • there are no groups
      • Group name attribute is inherited from groups
      • you have a link to add an attribute
      • you see Composition and Membership Relation as the default relationship types
      • You have a link to change the default join policy
      • You have a link to delete the group type
    7. Click on "Add a permissible relationship type." Ensure that you are not given a select bar but are offered a link to "create a new relationship type"
    8. Create a group of type test.
    9. Delete the test group type (first verify that the cancel button works)
    10. Go to the "project" group type
    11. Add a required attribute called "Project type" of datatype enumeration. Values are "Client" "Toolkit"
    12. Add an optional attribute "Monthly fee" of type integer and default of "10000"
    13. Add a third attribute called test.
    14. Make sure you can see all the attributes. Delete the test attribute
    15. Go to "/admin/object-types/one?object_type=project" and ensure that start_date and monthly fees are listed as attributes. Also make sure:
      • test attribute is not visible
      • monthly_fee has a default specified (NULL) in the pl/sql parameter list
      • start_date has no default specified
    16. Go to "/admin/object-types/one?object_type=subproject" and ensure the new attributes of project are in the pl/sql package
    17. Now go back to the group type admin page for the "Projects" group type. Remove the composition relation. Make sure you get a link back to add a relationship type. Add back the composition relation.
    18. Add a group of type project named GuideStar.org

    RELATIONSHIP TYPE PAGES BASIC FUNCTIONALITY

    1. Create a new relationship type, Employment relation, that is a subtype of Membership relation, between group and person. Group has role of employer, person role of employee.
    2. Select the employment relation and add an attribute age (integer, not required)
    3. Delete the employment relationship type.
    4. Re-add the employment relationship type (we're testing to make sure the age attribute is correctly removed and flushed from the cache)
    5. Click on membership relation, then click on create subtype
    6. Click on membership relation -> Create subtype type: project_lead_relation name: Project Lead between projects (the composite) and persons (the project leader new role)
    7. Create a new, dummy rel type, subtype of Project Lead Relation. Make sure the only things in object type one are project and subproject
    8. Select the dummy relationship type and then delete it.
    9. Select the Employment relation and add a required attribute "salary" (type integer)

    SEGMENTS, CONSTRAINTS AND RELATIONS

    1. Go back to the admin page (/admin)
    2. Click on the Groups -> GuideStar.org. Add ArsDigita as a component
    3. Remove the composition rel type from this group
    4. Readd the composition rel type. Make sure arsdigita doesn't show up
    5. remove the composition rel type
    6. Add a permissible rel type: project_lead_relation
    7. Click yes to create a rel segment named "GuideStar Project Leads"
    8. Go back to /admin/groups
    9. Click on "relationship to site"
    10. Remove yourself from the group.
    11. Add yourself again as a member (using the membership relation). You will have to select an existing party from the system.
    12. Make sure you see the segment "Main Site Members" for parties with a membership relation to the main site.
    13. Go to the ArsDigita group.
    14. Add guidestar.org as a component
    15. Remove the membership relation type from this group
    16. Add the employment relation type
    17. Create a segment named "ArsDigita employees"
    18. Add a constraint named "ArsDigita employees must be Main Site Members" for employees and the segment "Main Site Members"
    19. Go back to the guidestar.org group
    20. Add yourself as a project lead.
    21. Click on the project lead segment "GuideStar Project Leads"
    22. Click delete this segment. Say no.
    23. Click delete this segment. Say Yes.
    24. Recreate the "GuideStar Project Leads" segment
    25. Add a constraint named "Project leads must be employees" that says all "project leaders must be employees of ArsDigita"
    26. Make sure you see yourself as a violation. Remove the violating relation and finish adding the constraint
    27. Try to add a project leader to guidestar. You should see that there "There is no other Person that can be added as Project Leader to GuideStar.Org"
    28. Add yourself as an arsdigita employee
    29. Make yourself the project lead on guidestar.org
    30. Go back to /admin/groups and select "relationship typ site." Remove your membership relation. You should get prompted to remove relation to arsdigita, then to guidestar. Remove all of these relations.
    31. Make yourself a project lead of guidestar again.

    Testing with more Users

    Now we're going to test that the user interface remains consistent if there are a few more users.
    1. Go to /acs-admin/users and add 4 users
    2. Go to /admin/groups and click on "relationship to site." You should see all of the people you just entered listed as members of the subsite.
    3. Try to remove your Membership relation. You should see only one constraint violation.
    4. Remove one of the other people from the registered users group. You should be allowed to do it immediately.
    5. Add back the person you removed.
    6. Remove yourself from the registered users group. Make yourself a project lead on guidestar again.
    7. Make another user a project lead on guidestar.

    CLEANING UP

    1. Go to /admin/group-types
    2. Select the project group type
    3. Delete this group type. Should get prompted to delete sub projects group type.
    4. Delete the sub projects group type.
    5. Should get prompt to delete the project lead rel type
    6. Delete the project lead rel type. Continue until you delete the project group type.
    7. Delete the ArsDigita group.
    8. Go to /admin/rel-types/
    9. Click on "View all roles"
    10. Click on "Project Leader" - delete this role
    11. Click on "Employer" then on Employment Relation
    12. Delete the employment relation type.
    13. Delete the employee, employer, and project_leader roles
    14. Delete any groups you created for the developer defined type
    15. Drop the developer defined type (in SQL*Plus):
      exec acs_object_type.drop_type('developer_defined_test_type'); 
      drop table developer_defined_test_types;
      drop package developer_defined_test_type;
      

    Michael Bryzek

    $Id: group-admin-pages-acceptance-test.html,v 1.3 2003/09/30 12:10:03 mohanp Exp $ openacs-5.7.0/packages/acs-subsite/www/doc/group-admin-pages-design.html0000644000175000017500000001626507335322027026055 0ustar frankiefrankie Group Admin Pages - Design

    Group Admin Pages - Design

    ACS subsite docs : Group Admin Pages - Design

    I. Essentials

    II. Introduction

    The group administration packages provides a "control panel" to allow the administrator of a subsite to control the groups in use on that subsite. Administrators manage the types of groups in use on a subsite. For each of these group types, the administrator can create new groups, specify applicable relationship types, create relations between these groups, and modify attributes of the types and groups.

    III. Historical Considerations

    Versions 4.0.x of the ACS lacked a useful group administration package for subsites. For example:
    • Groups were given no context
    • Groups could not be deleted
    • Group types could not be created
    • Relationships were limited to membership and composition, not including subtypes of these two.
    This package addresses most of the short-coming of the previous subsites group administration package making group administration subsite aware and better integrated with the ACS Object Model.

    IV. Design Tradeoffs

    Whenever possible, the design of this package tries to minimize disturbance to the core ACS 4.0 data model. Instead, we focus on adding a more powerful user interface and PL/SQL API to the existing group admin pages while extending the data model only when necessary.

    V. API

    Permissible relationship types

    We defined the following two tables to store the relationship type used to store the permissible relationship types for group types and individual groups. Whenever a group is created using the acs_group.new function, the relationship types for the new group are automatically copied from those allowed for its group type.

    create table group_type_rels (
           group_rel_type_id      integer constraint gtr_group_rel_type_id_pk primary key,
           rel_type		      not null 
                                  constraint gtr_rel_type_fk
                                  references acs_rel_types (rel_type)
                                  on delete cascade,
           group_type	      not null 
                                  constraint gtr_group_type_fk
                                  references acs_object_types (object_type)
                                  on delete cascade,
           constraint gtr_group_rel_types_un unique (group_type, rel_type)
    );
    
    
    create table group_rels (
           group_rel_id           integer constraint group_rels_group_rel_id_pk primary key,
           rel_type		      not null 
                                  constraint group_rels_rel_type_fk
                                  references acs_rel_types (rel_type)
                                  on delete cascade,
           group_id	              not null 
                                  constraint group_rels_group_id_fk
                                  references groups (group_id)
                                  on delete cascade,
           constraint group_rels_group_rel_type_un unique (group_id, rel_type)
    );
    
    

    Dynamic subtypes of object types

    To allow administrators to create dynamic object types (e.g. subtypes of the object types group, membership_rel, and composition_rel), we provide a TCL library of procedure that generate PL/SQL packages. For each dynamically created object type, we:
    • We create the ACS object type
    • We create a table to store the attributes for the new type
    • We create a PL/SQL package with a new function and delete procedure
    Whenever an attribute is added or deleted, a type added or removed, we regenerate some of the PL/SQL packages, based on the type hierarchy affected by the change.

    Attributes themselves are stored using type-specific storage. For each new attribute, we create a column in the table dynamically created for the new object type.

    To support the clean separation between programmer defined PL/SQL packages and automatically generated packages, we add the dynamic_p column to the acs_object_types table.

    acs_object_types.dynamic_p       char(1) default 'f' 
                                     constraint acs_obj_types_dynamic_p_ck
                                     check (dynamic_p in ('t', 'f'))
    

    Note that the dynamic_p is still experimental and may be removed in a future version of ACS

    VII. Data Model Discussion

    ...

    VIII. User Interface

    The user interface comprises entirely of administrative pages located in the /admin/ directory of the subsite package.

    IX. Configuration/Parameters

    The revised group administration pages require no new package parameters.

    X. Future Improvements/Areas of Likely Change

    There are many areas for improvement to the user interface, including tighter integration with the relational segments and constraints packages. One major improvement would allow individual subsites to define their own group types and relationship types, separate from any other subsite. However, since ACS object types are not themselves objects, it is difficult to properly scope object types.

    We also may add a few additional package parameters including:

    • "Create Group Types" (Boolean). Determines whether new group types can be created dynamically.

    • "Create Relationship Types" (Boolean). Determines whether new relationship types can be created dynamically.

    XI. Authors

    This document is primarily the result of discussions between Oumi Mehrotra and Michael Bryzek. Bryan Quinn and Rafi Schloming provided key insights early in the development process.

    XII. Revision History

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Creation 11/30/2000 Michael Bryzek
    1.0 Major Revision 1/11/2001 Michael Bryzek


    Michael Bryzek

    group-admin-pages-design.html,v 1.1.4.1 2001/01/12 22:43:33 mbryzek Exp openacs-5.7.0/packages/acs-subsite/www/doc/intranet-company-structure.gif0000644000175000017500000001700207253523116026405 0ustar frankiefrankieGIF89a\W÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿl"ÿ‚Dÿ™fÿ°ˆÿƪÿÝÌ3"J1`@wOŽ^¤n»}ÒŒè›ÿªÿµ"ÿÁDÿÌfÿ׈ÿãªÿîÌ33GG\\pp……™™­­ÂÂÖÖëëÿÿÿÿ)ÿÿRÿÿzÿÿ£ÿÿÌ"31J@`Ow^Žn¤}»ŒÒ›èªÿµÿ"ÁÿDÌÿf×ÿˆãÿªîÿÌ3M"f+€3™<³DÌMæUÿhÿ|ÿ:ÿW£ÿu¶ÿ’Êÿ¯ÝÿÌ3PmЍÅâÿÿ3ÿ3MÿMfÿf€ÿ€™ÿ™³ÿ³ÌÿÌ3Mf"€+™3³<ÌDæMÿUÿh:ÿ|Wÿuÿ£’ÿ¶¯ÿÊÌÿÝ3"J1`@wOŽ^¤n»}ÒŒè›ÿª"ÿµDÿÁfÿ̈ÿתÿãÌÿî33MMff€€™™³³ÌÌææÿÿÿÿ:ÿÿWÿÿuÿÿ’ÿÿ¯ÿÿÌÿÿ3(P7mEŠT¨bÅqâ€ÿŒÿ3™ÿM¦ÿf³ÿ€¿ÿ™Ìÿ³ÙÿÌæÿ3Uw™»Ýÿÿ--ÿDDÿ[[ÿqqÿˆˆÿŸŸÿµµÿÌÌÿ3&M3f@€M™Y³fÌsæ€ÿŽÿ:ÿ«WÿºuÿÈ’ÿׯÿæÌÿ33MMff€€™™³³ÌÌææÿÿÿÿÿ:ÿÿWÿÿuÿÿ’ÿÿ¯ÿÿÌÿ3M&f3€@™M³YÌfæsÿ€ÿŽÿ:ÿW«ÿuºÿ’Èÿ¯×ÿÌæ!ù,\WþH° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³fÃ8sêÜɳ§ÏŸ@ƒ J´¨Ñœ6“*]Ê´©Ó§JJµªU«P³jÝʵ«W…WÊK–è׳hÓª]K²¬Û·p«²K·®Ý»qóêÝ»ó®ß¿€'åK¸pYÁˆ+^ìѰãÇSKžL¹rTȘ3ÿ´Ì¹³g»šC‹ð¹´éÓYG«†Œºµë×/WË. »¶íÛgëÖ‹»·ïßw  ¼¸qãÓ=μymåб:ŸNÝsôëR«kßλw³ÜÃþ‹Çû½üæñèÓ£5Ïž§ú÷ðS·ŸO:¾ýû5# ôyYgÿ¾ûùàyÙ$ R‡á§à‚,é'€{ øRâ4PP¡…Ö— ƒ †(RHa‡^à€&(!„Š(㌑˜b‡þQ „,ªXŸî×âŽ& 9¤GѨä’Ùˆc‰ü!Ù“i‡^¹â“:^6!xL†)æ†Eõ¨#PZÂhd‰f²Ùæ–7b)'”eŽi§Iâø&šC¸f†-Ziâ”G¢¨gšuÞ©è’yö—!†þù`:èy–BIf¢‹v*¢Q ͉ ¨tÊ©¢•™ zæ¥nÎùh£XžÆº ¨\îy*¥0þhê¡»²ªk–½[ª†²‹­Dþøß¦gÞše¥¢¾J&ª†J ¦±ØªW'¡FÚç ¼>롪¤ž§°¿˜íºãÑ7»ð†çn{ñ6þ 4xaB… 6tøbD‰)V,cF9vôødH‘#I–4™ÑbJ•+Y¶tùfL™3iÖ´ ódN;yöìyhP¡C‰5ziÒ>™6uú”¤R©S©Vµz«U¨[¹vå™lX±cÉ–­êmZµͶuûn\¹K×Öµûtn^½{ùöÅypàœ~ 6|¸¯`Å‹A"vür䩌)W sfÍ›WZö,˜shÑ£I6m—tjÕ« Ÿv–ulٳ;¶Í•vnÝ»“Þöí”wpáÃcþ6þ“xråËw>˜ytéÑŸW:{vÞÖ¹7Öþüêšîã9†7~3yõÑ·wx½ú÷óéëœ"Óúûù×¾oò/èúÀ³þɦ“ \Á£üˆ¨ëœBšd«7ï*ÜÃÎ.¼Ê£EQ¢ÇÂÄU<è¾¶PZF׋ë²mT±;j¼‘ÇÅzN }’Hª~#HÈ"•\²¨×.ÒˆÉ(¥ Ê2„PœË,¼K¡Ž´üþ ,hð „ 2lèð!Ĉ'R¬h1ÆŒ7rìèña‹"G’,iò$Ê”*W²léò%̘2z¬Y“bÈ™:wòìéó'РB‡h£ÉœE—2mêô)Ô¨R§¾TJõ*Ö¬Z·ríêÕ Õ¯bÇ’-kö,ÚaÓ²mëö-ܸ#×Ê­k÷.Þ¼Zéêíë÷/àÀ(ù .lø0â¿„3nìøq×Å'S®l™§äËš7s&J73CÐUƒ~žÛù4j¸¥EŠvÙšåê‹©gÓ.R£€Œ¹wçFÚÛ÷ïà@_¯¼­û8oÝ¿•^û9tª·Õ&ÏÉœ÷îëÄ‹“Æ>½·@íþÔÅG/oÞé÷ìá âÖÞ^èö”é¿[}¿~#öóú÷ûœŸœú}ãŸ|Ý‘w]€ ȃ ÂäŸu"EžzÝ çÝëGazzøaRNÈÞt*ç\Oža‡#šèŠ Ê8£`*Òx#Ž9†¦#=®xA ‰™Ey$’™$“6ùø¤J6B‰˜”SZ©!| U©h[åå•O‚iÚŽ›uyÖ˜aò˜¦l¸…7!Œq§œpx7'œÖÉÉžl²¦& Fy&¢€„*蟆VÈ¡¢~Väh 2B*¢sª…œ‚oÒiW¥.§¨¦1þ4i¤’ ¢Fxh~­&êiQ†Œ†u*N¥Úš­AX¨žbøj¡‹¾é+¬Þzì‚Jç°ò™+Sλá¯tnš%²ÙB›íWÛr[›·ßn®¸¨‘[îUç¢k溌©Ë@þ$XÐàA„ .dØÐáCˆXÑâEŒ5näØÑãEŠEŽ$YÒäI”)E†TÙÒåK˜1?²”YÓæMœ9mÒÔÙÓçO  y%ZÔèQ•C‘.eÚ£R§Q¥N= •êU¬U³nåÚ5©W°awŠ%[֬гiÕn´ºÖíÛ¥máÎ}+—î]¼2íæåëuo_À;þ\¸)aÉ£]ÜX*bÇ‘ \ÙòeÌ™5oæÜÙógÌ’·‚&]ÚôiÓ¢UOÐÚõkرeϦ]Ûömܯ!¯ö ÷oàÁ…ÿÞÍ[±ïáÉ•/¿]Ü8NäÌ¥OWîü¹àèÔµo·mýº^îáÅþÃöþoöñé©—7ï½zøÕÛ_ß>pöóSÖ¿ß¿»~ãøóoÀØòÐ$ TT+ÁlÐÁ•"´P7 EƒðBû&Ìp0/ôðð6 Q½IÌÈÄÇKQE®Xl1¼a¬HÆ·«ÑÆ«pÌq=sòñGév ò1"ý3òH††LR>&sòÉá–Œ2¡)© ÎÊ+«Ò2>.»,(Ë/s SÌ È,³94_RsÍÚÎl³78]œ³¥7ë”MÎ;…Ô“Æ>÷û“;>ÝiP =)OD[+TјmôÑ+%E”RHÝkÈLG²tPL;tÓ"E­TæB5ATS]Õ£OÿTõUO[]nVcÕWZaµÊ^Wü59^—þH€À <ˆ0¡Â… :t€Ä‰+Z¼ˆ1£Æ;R ð0¤È‘$Kš<‰aD,[º|édÊ™4kÚ¼‰3§Â•0{úü¹Q¦Î¡D‹=Ȩҥ=…} 5ªÔ¡I™Z½ªÑéÔ­\» ¨Š5¬X­^Ëš=k¬ØµLÉ¢} ·¤Z¶t}º‹7¯^ƒsëúmyw¯`½}ÿ:8±â·…1|i¢À“% °x±æ®NŽ à±åʇdÞŒ:5ÍÎE·<Ø“´ÒÓªkSeû9²kׇiÛþ <þ_—Ú?-»ròîÐÛËŽ)>~Jì‹+wnÞþû¿ÔåûL~ëM´_zϨsøµvKýýáW¸é]q¡-XÚƒnh}É)ˆÜ‡¢z$·Gr(^€¯Qxž…öy÷‹6îå!z æw¢‚&Žècƒå9xc‘¹ÈRyÇɸ#F>‰VŽXÑË-ã‰"¦ˆ”,"é‘’3ÆHãŠ^ž¹Z’;©ã”%ºi¢{Mªˆæ†`v$ç˜Cff~’„Ý{{vÇ£÷‘‰a…3öçwr$§TòÙh¥:=*–ˆlõi)€4~šU§¢¦ ªc m:*x˜–ŠYª®ÊÅþª©¼­Å髌Ŋk­¶Zº*®@éºkY½újW°ÆîDl©À»Õ°É¾´,³^:û,£ÒnFmµð]{í°rÛœÅr»˜·MÎ ¸Ó‘+­·­x•¸M±«˜»UÂk•¼ëÒk¬½øÂk¡y–Œá¿KEËïmK­yoÀÑ\àU'¡¿3xñ…‡byo«ÆÃ_8ðÆêuÜÖǶZL²À—LpÆ2Ϧr^,úÙ¿klpË×ìêÍ ëÜòÎ"§ 4\BKVtÌ<Ϭ/´IÊrÓV?­ÝÑ?OeÈï^ü2Ö‹jM3×¼zÍ`Øo§ñ¹›}VÕkû¼›ŒÏü+Ü•Ê`íYFQ»4±Þ€¢¯ßo î§¹ñšz8â͆ü÷kŒ{ìø™ÙjKgåS]Žy¨šOÛyoŸKÅyè>ºf¥›^ê© Çº_®¿>Øê±K4;íÙ~{îºÛ|;]¾ÿ.að´ þ 4xaB… 6tè0‰)V´xcF9v¤àaH‘#I–4y%ˆY¶tùÒ#È”3iÖ´ygN…+aöôùs£LC‰5z'P¥K{ =újT©C“2µzU£Ó©[¹vPkX±Z½–5{Ö(X±k™’EûnIµléúto^½çÖõÛòî^Ázûþ5tpbÅo vl1ðbÉ]?¶ òdÍ›iV¾ì83gÑT?—†<uj“žMû ­öI֭龎}{ôlÚkmãöÍP÷î°½\øUâÆ™ Dž¼msé›T·~{víÛ¹w÷þ|öþéãw†7}úóäÙ·Yýër÷óoÇOþ­Øã[×ÿ7þ®ÀSÚÎ9þ \01íÁ%T Âþî›CÆT0Ã#¬°BEäŠCÿF<ñ?L|Å¡ Ñ>e$O¨ ¿rnÆo’ÉÆuü1@ˆ€’$Ûä#I³ˆ;2I—lJÁäc2J§¬K´˜¤2K ·ìÌ©¸ä2LÇ,M¢È¼1Í×\³Í8qœ N9§«³N;ÃÌ“M=½´‰O?£ ´OA $”PC]”ÑF}ÒH%”ÒJÛ3rE·T¢L‘*ÔÒ‘xôO«D}pS‚L õ¨Tòñ™U©\Ýi ÐV]”GK=nÎYAeU2WS5Ñ©a7…pE„e“XU™=–XM(×/”¯jU¬ñÖi•íó>‹µ6ArÁUÜjÍÕõYsaõV%TãcWJyÃýÞ½`-ö]rÅMÛšöUµßck]7Ä|eÖ_|áÒ¶ánî Y¾æd÷_uWÝÐâB Æøb‰Ó„Ø`‘eë5âþ p Á‚"L¨p!Æ(1¢@Š&B¬x±"FŠ->tr£Å’5’ä˜òd€‘!_ÂŒ)s&Íš =jìxÒ&O„8Sêì)t(Ñ¢FΉbKŽMQ6íøq'Q¥T[~|ÊRçÓ¨H¿‚ û5+T”be’eiö,Û¶nßÂUè2®Í¹tïâÍ«w/ß¾~ÿÒÄj°O¬„#N¬x1ãÆŽCŽ,y2åÊ–/cάy3çΞ?ƒ-z4éÒ"?\-j‘HU›Ö+6AÚIaÎNý:6o´1mûþ-ü(ðÞo‹×ÞýyFâÆŸ»NÞzâOÃ;¥jµŽÚúr‰µ‡Úþ5#õì] s‡.Ûûôð[宽ÖèäÁÿ{ÉóQë« Sô©5ÞR+‘´Ô RRn^%˜ÓuBÈ IÌ øÚv º‚ÔHžˆËmX NÞ¢„+fØ¢U*Õ‡&¢7"nÞÁèá‰e%X#‹-Òõ⎚´RuúAˆ nÉåøáŠG>h# É¢ŽO–õ¢’â8dŒYòx YbNy\—V:i$˜LnÙP•N2¨&Œc6X¦qo‚øå„aR(%—Lž¸c‘{z‰¢páÙaš„¢yá€æ$hsŒÂé硼Eb~éY]~⶘›Öשxû¹w)[™ ê)H¦¾þG'€ ±J¤«l©Ÿ¬ªjZq¼®ºd¯šýJX±Ã";­‰l²ÆÚ÷W³ÏR[­µ×b›­¶ÛrÛ­·ß‚®¸ãÖ”ÛAsÁ‡—¹¡»¹A¶Æî¹îƵ.Žg¾›á«óÊÛ×¾ýÞ›¯ºl<éz#L¯ÀÐý ž®>Î7«r§R ±Î.ì& ¤–+’g5ÌñÃN9…qÆŒ™ë¨£•*lTÊ"®lh'óô2‘#ÊlòiëÉáÊ3ÓŒÙ~¢~\èža mq…}¶ôm×5Ó@W5fÔO­³Ó€Áj£Ï^ƒ,#{8g½µP]7švÓC¡ÍrÎfoÖuPKÿ¬µÆ<~I7Øpi¯†÷Ü_£‰´Ø7‡gô |[²§¦uøX/bã #ÞŒ¤2NòÑ_yáš;^¹è£“^ºé§£žºê«³Þºë¯Ã;³×ÚMsí£Ý.{¹Ùæžoï¢ý®»å¼¿<ðÂÙ­ñÞ.|‹þ 8`Aƒ&T¸aC‡F”8‘bE‹!^Ô¸‘cG 3~9’$Æ’'Q¦T¹R`H–/a"t“fMŽ3mæ$‰SgOŸ?ò:ô¢P¢G_EºT&S§OK*…:µ%U«¥^EšUkW¨\½n ;–!X²=ÍžUK3íZ´n×¶…Sî\»XïN­›Wç^¾)ýþ r°ÓÀ…UF,RñâÁ„¹ãdÊ-_Ž«ùhfÎ=žZôUÒ¥)žFmPõj®#·†ÝPöêÚ³ÞÆS÷?ö^uøÒÇ‘'W¾œysçÏ¡GŽRzuë×­ÿľ;wÄÝÁ‡Oþ^¼åóçѧW¿ž}{÷ïßO?~}û÷ñO_~~ÿÿñÛ. ,Ð<­êÏÀ<AƌпPP ãûà ѣð+A„ÏÃÊB,ñ@íL,qDÀR”pE¦,lQŹb”1B k´‘Á£ÒqA·òqF¸r’@¼q±"“‘¼ ›ÜH‹˜Œò>$­,pJ³¼òÉ*»ÌoËÔÂË2Å\M'ÉsM6ÝróÍQœÓ¾1±²“=<ëÔ3M"ý„³¯@3ÔP¿<ÔK@]ïÌFé,LÎ2ùôiRE+}RõÝT?5ÍtPOÛµ,RµÕ%…ÔT›.‚=ôU…b}³ÓMg­¨V+spUNiüõVWAÅ´Í_eÕaC-VÖD‘4Naû$µ×ш-nW?¯eZUWí6¢m›w%rí4w t»dÖXCߎ][ƒ ·ZOÕ=µÙc£MuZ{Á]ÖYBó¯_ãú-…ËVÛƒYýWà€­8Pþ p Á‚"L¨`€ BŒ(q"ÅŠ/^ °p#ÇŽ6Ä(r$É’?¢ì²$Ë–-O¦Œ)s&C—6oF„Is'Ïž q JQ§Ï¢(W MÊ’¨QH•BÅÈ´)Õ˜O£b0µ*×®¯. ¬I¡[½r%›1§Ö¶Y+žE[3¨Ú·ãÊÍû5ìØ¡vµê l´®T¶E⼓ðЕb2ŽšXnä‡á*Î, òÝÎ9¿Ô,:%èÏC"E­µcº£›–†ì¸!m‡¬cœŒ÷iÛ}óFü:pìÔÀm¯Æª{¸èàn O.]5ÐåÌò®­½-õçP­§MZþyë¬à¯“v9¶oëßÎ?£?÷&ØînË߯.ŸfðíÚg÷%sïuÖÞzæíÞKBöw%ß{õ!× ƒN¡Uôq×áxb6ªµwØy*”ƒäYhŠše˜ƒÝ•ç܉ÚX¡z碈1vÈ"JÝøâA*6hàú9ˆë=Å5âTä~9æ÷áqþh€²˜S“<õwà–´…iå˜ü]Ö&„kbç¦]jö¦œbÂ9“mÒ™çQwòéçO€rùÚž„öiä¡& J¡Œ6jТw&Êæ£DFúç¥6Ušé ›*çé| V #©LŠç©&¥ÚÕ¤›vþj誥v9«z­nôê[±âº×R2z†Øw¸fgf•ô™Ze€~Ù‡j¯GòÅØ¢¼«Þl½å†i«ýË)§ÉrØ¢_="û,Bʼn‹í°æ…ÛoÓ¹7Ý}IyÛRÕz›dÜ™`³R›oþÖ›!»’.¨c¼Z®F⽓éíŽä‘Hã¼S’D­f6B)ï—qÀô¥¦å‡ÿŠ ñ¨ëK±J²ªòb{x`‰Ûg,ÀÛÛ²SÚ\ÜÈÊêÈ¢ÅßÊìk´`†ünÇB'-··ØtËøU¦qf®øó…] Wëwùyˆñ­Q#Yõ…Í–¦uªÜfé³Õ/c˜5¾ází]teþ§,+tóßÃI§­ðÚ8µ¦ùRç¯Ï û¦wȹ-؈ýÊØ1ädïì·xŽÇMoº¹)÷]Û½9h•{ªë£¬ëåú’ëznkâ*Ë^¨âåNéݽ »ª¶ßqïÚî¾8ñå¾½|ñ[;3áч˜¼SÔ#Ý<ö;iíéï*WßîÇ‹g=ïÛ‡Æ3ú”m™Ú»žVúúošÏùªÿRÉàKv•ð) Ìl޳י–5ºÿ‰m}ÌÓ„ö<µ,ÐUüšyà“@–ËjñúÙÜ(?Ê9pN¬ŸJè’¹9 åw¿Êà™æõ¥†ùOµ[!Ó€#:Ù¨Mp=Š`sÖÂBø¥Õ„¹2á¸%Õpv¶QaYX³›í+J2ìޥحÔEX€A›û¸°#ŒäZ¢‡×³& drÓ"µWÅ0Þ0rˆ[RjÚ—­+B1üØøºx8—ý1‹W„L͈7ÚprN[ã ·èFõhÑŠžÑc·xX,pƒ`Ô¤$)³ÈD ŽŠÄÚÇhÉ&=)’lT#-øHHâ‘‘YÔ¡cìxG@Õòƒ>LW'±ØA%žRQâQ%×HKWŠŠkƒÝ&V5["æ~NÓå.[YÌbsŠFþˆ 4xaÁ6tø"Ä…'R 0±â„‹72äø0£Æ„#I–4yRaD•+C®tùR%F”3i¶„ygΗhöôù³¤Íˆ![vÔh‘ãE ‰JújÔ“Bu2­z5&H©[¡RÍ©kX2¹þô*íUžeÙr=K1mX¢méÖ%ùV'ظ_3®µû7å^ÁXý‰wpb¦†›D¬¶S×eSÇÖ<[@mÛ«q£Þ-˜uoáºW .¼fñÈÇ}+OÌùVâÎEF>úNëO±g_Œ»»÷ÕêÛé†ÿ |sñÏÓû4Ÿ½á÷Ôã·O¾þ¶ýÖóñ××/?åü³+Àâüï.üòCp³½;Ð>wƒ°- m£Aƒ,Ä Ã ÚP@TP®Þ@T­Cs#‘7;ñ<‚ѳ¥c‘0ÝÃQ2£ñBãñ+‰\PÈ Žd)I7zÊ(¥œ’Ê*­¼r£&Ä’Ë.½äÒÄ/ÅSL-#Í4³4“Í6Ý|Î8圓Î:í¼Ï<õÜ“Ï>ýüÐ@”ÐB =ÑD]”Q’;openacs-5.7.0/packages/acs-subsite/www/pvt/0000755000175000017500000000000011724401447020434 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/pvt/set-on-vacation-until.adp0000644000175000017500000000045007743732044025267 0ustar frankiefrankie #acs-subsite.Vacation_Info_Updated# #acs-subsite.Information_Updated#

    #acs-subsite.Vacation_information_updated#

    #acs-subsite.lt_You_wont_get_any_email#

    #acs-subsite.Please_return_to_home#

    openacs-5.7.0/packages/acs-subsite/www/pvt/set-on-vacation-until.tcl0000644000175000017500000000214007572171755025311 0ustar frankiefrankie# set-on-vacation-until.tcl ad_page_contract { Set someone as being on vacation till a give date. NOTE: on_vacation_util is expected as a date parameter, but ad_page_contract doesn't know how to handle that. @author @creation-date @cvs-id $Id: set-on-vacation-until.tcl,v 1.3 2002/11/30 17:22:53 jeffd Exp $ } { } -properties { site_link:onevalue home_link:onevalue pretty_date:onevalue } # if [catch { ns_dbformvalue [ns_getform] on_vacation_until date on_vacation_until } errmsg] { ad_return_error "Invalid date" "AOLserver didn't like the date that you entered." return } set user_id [ad_get_user_id] db_transaction { # We update the users table to maintain compatibility with acs installations prior to user_vacations set bind_vars [ad_tcl_vars_to_ns_set user_id on_vacation_until] db_dml pvt_set_vacation_update "update users set no_alerts_until = :on_vacation_until where user_id = :user_id" -bind $bind_vars } set home_link [ad_pvt_home_link] set site_link [ad_site_home_link] set pretty_date [lc_time_fmt $on_vacation_until "%q"] ad_return_templateopenacs-5.7.0/packages/acs-subsite/www/pvt/set-on-vacation-until.xql0000644000175000017500000000035107273603702025323 0ustar frankiefrankie update users set no_alerts_until = :on_vacation_until where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe-2-postgresql.xql0000644000175000017500000000072407611533173026053 0ustar frankiefrankie postgresql7.1 select rel_id from group_member_map where group_id = acs__magic_object_id('registered_users') and member_id = :user_id begin return membership_rel__deleted(:rel_id); end; openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe-2-oracle.xql0000644000175000017500000000072207736271233025117 0ustar frankiefrankie oracle8.1.6 select rel_id from group_member_map where group_id = acs.magic_object_id('registered_users') and member_id = :user_id begin membership_rel.del( rel_id => :rel_id ); end; openacs-5.7.0/packages/acs-subsite/www/pvt/toggle-dont-spam-me-p.tcl0000644000175000017500000000037607542067255025173 0ustar frankiefrankie# $Id: toggle-dont-spam-me-p.tcl,v 1.2 2002/09/18 12:16:45 jeffd Exp $ set user_id [ad_get_user_id] db_dml unused "update user_preferences set dont_spam_me_p = util.logical_negation(dont_spam_me_p) where user_id = :user_id" ad_returnredirect "home" openacs-5.7.0/packages/acs-subsite/www/pvt/set-on-vacation-to-null.adp0000644000175000017500000000035507743732044025532 0ustar frankiefrankie #acs-subsite.Vacation_Info_Updated# #acs-subsite.Information_Updated#

    #acs-subsite.Youre_marked_as_back#

    #acs-subsite.Please_return_to_home#

    openacs-5.7.0/packages/acs-subsite/www/pvt/set-on-vacation-to-null.tcl0000644000175000017500000000126410551254401025533 0ustar frankiefrankie# /www/pvt/set-on-vacation-to-null.tcl ad_page_contract { Set on vacation to null. @author Multipe @cvs-id $Id: set-on-vacation-to-null.tcl,v 1.2 2007/01/10 21:22:09 gustafn Exp $ } -properties { site_link:onevalue home_link:onevalue } set user_id [ad_get_user_id] set no_alerts_until [db_string no_alerts_until { select no_alerts_until from users where user_id = :user_id } -default ""] if { $no_alerts_until ne "" } { set clear [db_null] db_dml pvt_unset_no_alerts_until { update users set no_alerts_until = :clear where user_id = :user_id } } set site_link [ad_site_home_link] set home_link [ad_pvt_home_link] ad_return_template openacs-5.7.0/packages/acs-subsite/www/pvt/set-on-vacation-to-null.xql0000644000175000017500000000063207273603702025564 0ustar frankiefrankie select no_alerts_until from users where user_id = :user_id update users set no_alerts_until = :clear where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe-oracle.xql0000644000175000017500000000050207273603702024750 0ustar frankiefrankie oracle8.1.6 select no_alerts_until, acs_user.receives_alerts_p(:user_id) as on_vacation_p from users where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/home.adp0000644000175000017500000000044210665274105022054 0ustar frankiefrankie @page_title@ @context;noquote@ user_info.first_names @user_id@ openacs-5.7.0/packages/acs-subsite/www/pvt/home.tcl0000644000175000017500000000076110665274105022076 0ustar frankiefrankiead_page_contract { Page for users to register themselves on the site. @cvs-id $Id: home.tcl,v 1.26 2007/08/29 13:44:37 maltes Exp $ } { } set user_id [auth::require_login -account_status closed] set page_title [ad_pvt_home_name] set context [list $page_title] set subsite_id [ad_conn subsite_id] set user_home_template [parameter::get -parameter "UserHomeTemplate" -package_id $subsite_id] if {$user_home_template eq ""} { set user_home_template "/packages/acs-subsite/lib/home" }openacs-5.7.0/packages/acs-subsite/www/pvt/index.tcl0000644000175000017500000000033307542067255022256 0ustar frankiefrankiead_page_contract { Makes /pvt/ redirect to /pvt/home @author michael@arsdigita.com @creation-date 30 May 2000 @cvs-id $Id: index.tcl,v 1.2 2002/09/18 12:16:45 jeffd Exp $ } {} ad_returnredirect "home" openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe.adp0000644000175000017500000000073411164423520023444 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ #acs-subsite.Close_account_explanation# openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe.tcl0000644000175000017500000000056211164423520023461 0ustar frankiefrankiead_page_contract { @cvs-id $Id: unsubscribe.tcl,v 1.6 2009/03/31 14:23:12 emmar Exp $ } set user_id [auth::get_user_id -account_status closed] set system_name [ad_system_name] set page_title [_ acs-subsite.Close_your_account] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] set pvt_home [ad_pvt_home] set pvt_home_name [ad_pvt_home_name] openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe.xql0000644000175000017500000000031607273603702023510 0ustar frankiefrankie select dont_spam_me_p from user_preferences where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/alerts-oracle.xql0000644000175000017500000000160507300260125023710 0ustar frankiefrankie oracle8.1.6 select bea.valid_p, bea.frequency, bea.keywords, bt.topic, bea.rowid from bboard_email_alerts bea, bboard_topics bt where bea.user_id = :user_id and bea.topic_id = bt.topic_id order by bea.frequency select cea.valid_p, ad.domain, cea.alert_id, cea.expires, cea.frequency, cea.alert_type, cea.category, cea.keywords from classified_email_alerts cea, ad_domains ad where user_id = :user_id and ad.domain_id = cea.domain_id and sysdate <= expires order by expires desc openacs-5.7.0/packages/acs-subsite/www/pvt/toggle-dont-spam-me-p-postgresql.xql0000644000175000017500000000046707273603702027411 0ustar frankiefrankie postgresql7.1 update user_preferences set dont_spam_me_p = util__logical_negation(dont_spam_me_p) where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/alerts.adp0000644000175000017500000000346107743732044022426 0ustar frankiefrankie @title;noquote@ @context;noquote@

    #acs-subsite.Your_discussion_alerts#

    #acs-subsite.Status# #acs-subsite.Action# #acs-subsite.Topic# #acs-subsite.Frequency# #acs-subsite.Keyword#
    #acs-subsite.Enabled# #acs-subsite.Disable# #acs-subsite.Disabled# #acs-subsite.Re_enable# @topic@ @frequency@ @keyword@

    #acs-subsite.Your_system_alerts#

    #acs-subsite.Status# #acs-subsite.Action# #acs-subsite.Domain# #acs-subsite.Expires# #acs-subsite.Frequency# #acs-subsite.Alert_Type# #acs-subsite.type_specific_info#
    @status@ @action@ @domain@ @expires@ @frequency@ @alert_type@ @alert_value@
    #acs-subsite.You_have_no_email_alerts# openacs-5.7.0/packages/acs-subsite/www/pvt/alerts.tcl0000644000175000017500000000714010551254401022425 0ustar frankiefrankiead_page_contract { @cvs-id $Id: alerts.tcl,v 1.5 2007/01/10 21:22:09 gustafn Exp $ } { } -properties { title:onevalue context:onevalue discussion_forum_alert_p:onevalue bboard_keyword_p:onevalue bboard_rows:multirow classified_email_alert_p:onevalue classified_rows:multirow gc_system_name:onevalue } set user_id [ad_conn user_id] db_1row name_get "select first_names, last_name, email, url from persons, parties where persons.person_id = parties.party_id and party_id =:user_id" -bind [ad_tcl_vars_to_ns_set user_id] if { $first_names ne "" || $last_name ne "" } { set full_name "$first_names $last_name" } else { set full_name "name unknown" } set title "$full_name's alerts in [ad_system_name]" set context [list "Alerts"] set discussion_forum_alert_p 0 set classified_email_alert_p 0 if { [db_table_exists "bboard_email_alerts"] } { set discussion_forum_alert_p 1 set rownum 0 if { [bboard_pls_blade_installed_p] == 1 } { set bboard_keyword_p 1 } else { set bboard_keyword_p 0 } db_foreach alerts_list " select bea.valid_p, bea.frequency, bea.keywords, bt.topic, bea.rowid from bboard_email_alerts bea, bboard_topics bt where bea.user_id = :user_id and bea.topic_id = bt.topic_id order by bea.frequency" { incr rownum if { $valid_p eq "f" } { # alert has been disabled for some reason set bboard_rows:$rownum(status) "disable" set bboard_rows:$rownum(action_url) "/bboard/alert-reenable?rowid=[ns_urlencode $rowid]" } else { # alert is enabled set bboard_rows:$rownum(status) "enable" set bboard_rows:$rownum(action_url) "/bboard/alert-disable?rowid=[ns_urlencode $rowid]" } set bboard_rows:$rownum(topic) $topic set bboard_rows:$rownum(frequency) $frequency set bboard_rows:$rownum(keywords) $keywords } if_no_rows { set discussion_forum_alert_p 0 } } if { [db_table_exists "classified_email_alerts"] } { set classified_email_alert_p 1 set gc_system_name [gc_system_name] set rownum 0 db_foreach alerts_list_2 " select cea.valid_p, ad.domain, cea.alert_id, cea.expires, cea.frequency, cea.alert_type, cea.category, cea.keywords from classified_email_alerts cea, ad_domains ad where user_id = :user_id and ad.domain_id = cea.domain_id and sysdate <= expires order by expires desc" { incr rownum if { $valid_p eq "f" } { # alert has been disabled for some reason set classified_rows:$rownum(status) "Off" set classified_rows:$rownum(action) "Re-enable" } else { # alert is enabled set classified_rows:$rownum(status) "On" set classified_rows:$rownum(action) "Disable" } if { $alert_type eq "all" } { set classified_rows:$rownum(alert_value) "--" } elseif { $alert_type eq "keywords" } { set classified_rows:$rownum(alert_value) $keywords } elseif { $alert_type eq "category" } { set classified_rows:$rownum(alert_value) $category } else { # I don't know what to do here... set classified_rows:$rownum(alert_value) "--" } set classified_rows:$rownum(domain) $domain set classified_rows:$rownum(rowid) $row_id set classified_rows:$rownum(expires) $expires set classified_rows:$rownum(frequency) [gc_PrettyFrequency $frequency] set classified_rows:$rownum(alert_type) $alert_type } if_no_rows { set classified_email_alert_p 0 } } db_release_unused_handles ad_return_templateopenacs-5.7.0/packages/acs-subsite/www/pvt/alerts.xql0000644000175000017500000000041507300260125022443 0ustar frankiefrankie select first_names, last_name, email, url from persons, parties where persons.person_id = parties.party_id and party_id =:user_id openacs-5.7.0/packages/acs-subsite/www/pvt/hide-email.tcl0000644000175000017500000000027610171476746023154 0ustar frankiefrankie# /pvt/hide-email.tcl ad_page_contract { changes show_email field in user's table } { hide:notnull user_id:notnull } db_dml update_show_email { } ad_returnredirect "/pvt/home"openacs-5.7.0/packages/acs-subsite/www/pvt/hide-email.xql0000644000175000017500000000031610171476746023171 0ustar frankiefrankie update users set show_email = $hide where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe-postgresql.xql0000644000175000017500000000050507273603702025711 0ustar frankiefrankie postgresql7.1 select no_alerts_until, acs_user__receives_alerts_p(:user_id) as on_vacation_p from users where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/alerts-postgresql.xql0000644000175000017500000000163007537350325024662 0ustar frankiefrankie postgresql7.1 select bea.valid_p, bea.frequency, bea.keywords, bt.topic, bea.oid as rowid from bboard_email_alerts bea, bboard_topics bt where bea.user_id = :user_id and bea.topic_id = bt.topic_id order by bea.frequency select cea.valid_p, ad.domain, cea.alert_id, cea.expires, cea.frequency, cea.alert_type, cea.category, cea.keywords from classified_email_alerts cea, ad_domains ad where user_id = :user_id and ad.domain_id = cea.domain_id and current_timestamp <= expires order by expires desc openacs-5.7.0/packages/acs-subsite/www/pvt/toggle-dont-spam-me-p-oracle.xql0000644000175000017500000000046407273603702026450 0ustar frankiefrankie oracle8.1.6 update user_preferences set dont_spam_me_p = util.logical_negation(dont_spam_me_p) where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe-2.adp0000644000175000017500000000045207743732044023614 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    #acs-subsite.Account_at_system_closed#

    #acs-subsite.You_can_always_re_open# #acs-subsite.logging_back_in# #acs-subsite.later#

    openacs-5.7.0/packages/acs-subsite/www/pvt/unsubscribe-2.tcl0000644000175000017500000000066407732615034023634 0ustar frankiefrankiead_page_contract { Unsubscribes from the site @cvs-id $Id: unsubscribe-2.tcl,v 1.2 2003/09/19 15:00:44 lars Exp $ } {} -properties { system_name:onevalue } auth::require_login set page_title "Account Closed" set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] acs_user::delete -user_id [ad_conn user_id] set system_name [ad_system_name] set login_url [ad_get_login_url] auth::verify_account_status openacs-5.7.0/packages/acs-subsite/www/user/0000755000175000017500000000000011575225553020607 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/user/password-update.adp0000644000175000017500000000045707733530502024417 0ustar frankiefrankie #acs-subsite.Update_Password# @context;noquote@ @focus;noquote@
    @message@
    openacs-5.7.0/packages/acs-subsite/www/user/password-update.tcl0000644000175000017500000001260311164430563024430 0ustar frankiefrankiead_page_contract { Let's the user change his/her password. Asks for old password, new password, and confirmation. @cvs-id $Id: password-update.tcl,v 1.22 2009/03/31 15:06:27 emmar Exp $ } { {user_id {[ad_conn untrusted_user_id]}} {return_url ""} {old_password ""} {message ""} } # This is a bit confusing, but old_password is what we get passed in here, # whereas password_old is the form element. # Redirect to HTTPS if so configured if { [security::RestrictLoginToSSLP] } { security::require_secure_conn } if { $old_password ne "" } { # If old_password is set, this is a user who has had his password recovered, # so they won't be authenticated yet. } else { set level [ad_decode [security::RestrictLoginToSSLP] 1 "secure" "ok"] # If the user is changing passwords for another user, they need to be account ok set account_status [ad_decode $user_id [ad_conn untrusted_user_id] "closed" "ok"] auth::require_login \ -level $level \ -account_status $account_status } if { ![auth::password::can_change_p -user_id $user_id] } { ad_return_error "Not supported" "Changing password is not supported." } set admin_p [permission::permission_p -object_id $user_id -privilege admin] if { !$admin_p } { permission::require_permission -party_id $user_id -object_id $user_id -privilege write } set page_title [_ acs-subsite.Update_Password] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] set system_name [ad_system_name] set site_link [ad_site_home_link] acs_user::get -user_id $user_id -array user ad_form -name update -edit_buttons [list [list [_ acs-kernel.common_update] "ok"]] -form { {user_id:integer(hidden)} {return_url:text(hidden),optional} {old_password:text(hidden),optional} {message:text(hidden),optional} } if { [exists_and_not_null old_password] } { set focus "update.password_1" } else { ad_form -extend -name update -form { {password_old:text(password) {label {[_ acs-subsite.Current_Password]}} } } set focus "update.password_old" } ad_form -extend -name update -form { {password_1:text(password) {label {[_ acs-subsite.New_Password]}} {html {size 20}} } {password_2:text(password) {label {[_ acs-subsite.Confirm]}} {html {size 20}} } } -on_request { } -validate { {password_1 { [string equal $password_1 $password_2] } { Passwords don't match } } } -on_submit { if { [exists_and_not_null old_password] } { set password_old $old_password } array set result [auth::password::change \ -user_id $user_id \ -old_password $password_old \ -new_password $password_1] switch $result(password_status) { ok { # Continue } old_password_bad { if { ![exists_and_not_null old_password] } { form set_error update password_old $result(password_message) } else { # This hack causes the form to reload as if submitted, but with the old password showing ad_returnredirect [export_vars -base [ad_conn url] -entire_form -exclude { old_password } -override { { password_old $old_password } }] ad_script_abort } break } default { form set_error update password_1 $result(password_message) break } } # If old_password was supplied, handle authentication and log the user in if { [exists_and_not_null old_password] } { # We use full-scale auth::authenticate here, in order to be sure we also get account-status checked # Hm. What if there's a problem with timing, so the password update doesn't take effect immediately? array set auth_info [auth::authenticate \ -return_url $return_url \ -authority_id $user(authority_id) \ -username $user(username) \ -password $password_1] # Handle authentication problems switch $auth_info(auth_status) { ok { # Continue below } default { # we shouldn't get bad password here ... form set_error update password_1 $auth_info(auth_message) break } } if { [exists_and_not_null auth_info(account_url)] } { ad_returnredirect $auth_info(account_url) ad_script_abort } # Handle account status switch $auth_info(account_status) { ok { # Continue below } default { # Display the message on a separate page ad_returnredirect [export_vars -base "[subsite::get_element -element url]register/account-closed" { { message $auth_info(account_message) } }] ad_script_abort } } } # If the account was closed, it might be open now if {[ad_conn account_status] eq "closed"} { auth::verify_account_status } } -after_submit { if { $return_url eq "" } { set return_url [ad_pvt_home] } set message [_ acs-subsite.confirmation_password_changed] ad_returnredirect -message $message -- $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/user/email-privacy-level.adp0000644000175000017500000000022711164425772025144 0ustar frankiefrankie doc @context;noquote@ openacs-5.7.0/packages/acs-subsite/www/user/email-privacy-level.tcl0000644000175000017500000000175511164425772025171 0ustar frankiefrankiead_page_contract { Allows users to change their priv_email field in the users table @author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) } { {user_id ""} {return_url ""} } if { $return_url eq "" } { set return_url [ad_pvt_home] } set doc(title) [_ acs-subsite.Change_my_email_P] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $doc(title)] if {$user_id eq ""} { set user_id [auth::require_login -account_status closed] } ad_form -name private-email -export return_url -form { {level:integer(select) {label "\#acs-subsite.Change_my_email_P\#:"} {options {{"[_ acs-subsite.email_as_text]" 4} {"[_ acs-subsite.email_as_image]" 3} \ {"[_ acs-subsite.email_as_a_form]" 2} {"[_ acs-subsite.email_dont_show]" 1}}} } } -on_request { set level [email_image::get_priv_email -user_id $user_id] } -on_submit { email_image::update_private_p -user_id $user_id -level $level } -after_submit { ad_returnredirect $return_url }openacs-5.7.0/packages/acs-subsite/www/user/portrait/0000755000175000017500000000000011575225553022453 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/user/portrait/upload-postgresql.xql0000644000175000017500000000055010723070027026652 0ustar frankiefrankie postgresql7.1 select acs_rel__new ( null, 'user_portrait_rel', :user_id, :item_id, null, null, null ) openacs-5.7.0/packages/acs-subsite/www/user/portrait/upload-oracle.xql0000644000175000017500000000060310723070027025713 0ustar frankiefrankie oracle8.1.6 begin :1 := acs_rel.new ( rel_type => 'user_portrait_rel', object_id_one => :user_id, object_id_two => :item_id); end; openacs-5.7.0/packages/acs-subsite/www/user/portrait/erase.adp0000644000175000017500000000043511164425461024234 0ustar frankiefrankie doc @context;noquote@

    #acs-subsite.lt_Sure_erase_your_por#

    #acs-subsite.lt_Sure_erase_user_por#

    openacs-5.7.0/packages/acs-subsite/www/user/portrait/erase.tcl0000644000175000017500000000365111164425461024255 0ustar frankiefrankiead_page_contract { Erases a portrait @cvs-id $Id: erase.tcl,v 1.7 2009/03/31 14:39:45 emmar Exp $ } { {return_url "" } {user_id ""} } -properties { context:onevalue export_vars:onevalue admin_p:onevalue } set current_user_id [ad_conn user_id] if {$user_id eq "" || $user_id eq $current_user_id} { set user_id $current_user_id set admin_p 0 } else { set admin_p 1 } ad_require_permission $user_id "write" set doc(title) [_ acs-subsite.Erase] if {$admin_p} { set context [list \ [list [ad_pvt_home] [ad_pvt_home_name]] \ [list "./?[export_vars user_id]" [_ acs-subsite.User_Portrait]] \ $doc(title)] } else { set context [list \ [list [ad_pvt_home] [ad_pvt_home_name]] \ [list "./" [_ acs-subsite.Your_Portrait]] \ $doc(title)] } if { $return_url eq "" } { set return_url [ad_pvt_home] } ad_form -name "portrait_erase" -export {user_id return_url} -form {} -on_submit { set item_id [db_string get_item_id {} -default ""] if {$item_id eq ""} { ad_returnredirect $return_url ad_script_abort } set resized_item_id [image::get_resized_item_id -item_id $item_id] # Delete the resized version if {$resized_item_id ne ""} { content::item::delete -item_id $resized_item_id } # Delete all previous images db_foreach get_images {} { package_exec_plsql -var_list [list [list delete__object_id $object_id]] acs_object delete } db_foreach old_item_id {} { content::item::delete -item_id $object_id } # Delete the relationship db_dml delete_rel {} # Delete the item content::item::delete -item_id $item_id # Flush the portrait cache util_memoize_flush [list acs_user::get_portrait_id_not_cached -user_id $user_id] ad_returnredirect $return_url } ad_return_template openacs-5.7.0/packages/acs-subsite/www/user/portrait/erase.xql0000644000175000017500000000235710723075643024304 0ustar frankiefrankie select object_id_two from acs_rels where object_id_one = :user_id and rel_type = 'user_portrait_rel' select object_id from acs_objects where object_type in ('cr_item_child_rel','image') and context_id = :item_id and object_id not in (select live_revision from cr_items where item_id = :item_id) select object_id from acs_objects where object_type = 'content_item' and context_id = :item_id delete from acs_rels where object_id_two = :item_id and object_id_one = :user_id and rel_type = 'user_portrait_rel' openacs-5.7.0/packages/acs-subsite/www/user/portrait/index.adp0000644000175000017500000000256411164425461024251 0ustar frankiefrankie doc @context;noquote@

    #acs-subsite.lt_This_is_the_image_that#:

    @doc.title@
    • #acs-subsite.lt_Uploaded_pretty_date#
    • #acs-subsite.Caption#:

      @description@

    #acs-subsite.Options#:

    #acs-subsite.lt_We_cant_find_you#

    #acs-subsite.lt_The_picture_of_you_in# #acs-subsite.upload# #acs-subsite.another_picture#

    #acs-subsite.lt_This_user_doesnt_have# #acs-subsite.go_upload_the_users_por#. #acs-subsite.You_dont_have_a_portrait# #acs-subsite.go_upload_your_portrait#.

    openacs-5.7.0/packages/acs-subsite/www/user/portrait/index.tcl0000644000175000017500000000565011164425461024266 0ustar frankiefrankiead_page_contract { displays a user's portrait to the user him/herself offers options to replace it @author philg@mit.edu @creation-date September 26, 1999 @cvs-id $Id: index.tcl,v 1.10 2009/03/31 14:39:45 emmar Exp $ } { {return_url "" } {user_id ""} } -properties { first_names:onevalue last_name:onevalue system_name:onevalue export_vars:onevalue widthheight:onevalue pretty_date:onevalue description:onevalue export_edit_vars:onevalue subsite_url:onevalue return_url:onevalue admin_p:onevalue user_id:onevalue return_code:onevalue } set current_user_id [ad_conn user_id] set subsite_url [subsite::get_element -element url] set return_url "[subsite::get_element -element url]user/portrait/" set return_code "no_error" # Other possibilities: # no_user : Unknown user_id, not in DB. # no_portrait : No portrait uploaded yet for this user. # no_portrait_info : Unable to retrieve information on portrait. if {$user_id eq ""} { set user_id $current_user_id } if { $current_user_id == $user_id } { set admin_p 1 ad_require_permission $user_id "write" } else { set admin_p 0 } set export_vars [export_url_vars user_id] set export_edit_vars [export_url_vars user_id return_url] if {![db_0or1row user_info "select first_names, last_name from persons where person_id=:user_id"]} { set return_code "no_user" set context [list "Account Unavailable"] ad_return_template return } if {![db_0or1row get_item_id "select live_revision as revision_id, item_id from acs_rels a, cr_items c where a.object_id_two = c.item_id and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel'"] || $revision_id eq ""} { # The user doesn't have a portrait yet set portrait_p 0 } else { set portrait_p 1 } if { $admin_p } { set doc(title) [_ acs-subsite.Your_Portrait] } else { set doc(title) [_ acs-subsite.lt_Portrait_of_first_last] } set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $doc(title)] if {! $portrait_p } { set return_code "no_portrait" ad_return_template return } # we have revision_id now if {[catch {db_1row get_picture_info " select i.width, i.height, cr.title, cr.description, cr.publish_date from images i, cr_revisions cr where i.image_id = cr.revision_id and image_id = :revision_id "} errmsg]} { # There was an error obtaining the picture information set context [list "Invalid Picture"] set return_code "no_portrait_info" ad_return_template return } if {$publish_date eq ""} { ad_return_complaint 1 "
  • You shouldn't have gotten here; we don't have a portrait on file for you." return } if { $width ne "" && $height ne "" } { set widthheight "width=$width height=$height" } else { set widthheight "" } db_release_unused_handles set system_name [ad_system_name] set pretty_date [lc_time_fmt $publish_date "%q"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/user/portrait/upload.adp0000644000175000017500000000036711164425461024425 0ustar frankiefrankie doc @context;noquote@

    #acs-subsite.lt_How_would_you_like_the#

    #acs-subsite.lt_Upload_your_favorite#

    openacs-5.7.0/packages/acs-subsite/www/user/portrait/upload.tcl0000644000175000017500000001416711164431737024451 0ustar frankiefrankiead_page_contract { Uploading user portraits @cvs-id $Id: upload.tcl,v 1.15 2009/03/31 15:16:47 emmar Exp $ } { {user_id ""} {return_url ""} } -properties { first_names:onevalue last_name:onevalue context:onevalue export_vars:onevalue } set current_user_id [ad_conn user_id] set portrait_p [db_0or1row "checkportrait" {}] if { $portrait_p } { set doc(title) [_ acs-subsite.upload_a_replacement_por] set description [db_string "getstory" {}] } else { set doc(title) [_ acs-subsite.Upload_Portrait] set description "" set revision_id "" } if {$user_id eq ""} { subsite::upload_allowed set user_id $current_user_id set admin_p 0 } else { set admin_p 1 } ad_require_permission $user_id "write" if {![db_0or1row get_name {}]} { ad_return_error "Account Unavailable" "We can't find you (user #$user_id) in the users table. Probably your account was deleted for some reason." return } if { $return_url eq "" } { set return_url [ad_pvt_home] } if {$admin_p} { set context [list \ [list "./?[export_vars user_id]" [_ acs-subsite.User_Portrait]] \ $doc(title)] } else { set context [list \ [list [ad_pvt_home] [ad_pvt_home_name]] \ [list "./?[export_vars return_url]" [_ acs-subsite.Your_Portrait]] \ $doc(title)] } set help_text [_ acs-subsite.lt_Use_the_Browse_button] ad_form -name "portrait_upload" -html {enctype "multipart/form-data"} -export {user_id return_url} -form { {upload_file:text(file) {label "#acs-subsite.Filename#"} {help_text $help_text} } } if { $portrait_p } { ad_form -extend -name "portrait_upload" -form { {portrait_comment:text(textarea),optional {label "#acs-subsite.Caption#"} {value $description} {html {rows 6 cols 50}} } } } else { ad_form -extend -name "portrait_upload" -form { {portrait_comment:text(textarea),optional {label "#acs-subsite.Caption#"} {html {rows 6 cols 50}} } } } set mime_types [parameter::get -parameter AcceptablePortraitMIMETypes -default ""] set max_bytes [parameter::get -parameter MaxPortraitBytes -default ""] ad_form -extend -name "portrait_upload" -validate { # check to see if this is one of the favored MIME types, # e.g., image/gif or image/jpeg # DRB: the code actually depends on our having either gif or jpeg and this was true # before I switched this routine to use cr_import_content (i.e. don't believe the # generality implicit in the following if statement) {upload_file { $mime_types eq "" || [lsearch $mime_types [ns_guesstype $upload_file]] > -1 } {Your image wasn't one of the acceptable MIME types: $mime_types} } {upload_file { $max_bytes eq "" || [file size [ns_queryget upload_file.tmpfile]] <= $max_bytes } {Your file is too large. The publisher of [ad_system_name] has chosen to limit portraits to [util_commify_number $max_bytes] bytes. You can use PhotoShop or the GIMP (free) to shrink your image} } } -on_submit { # this stuff only makes sense to do if we know the file exists set tmp_filename [ns_queryget upload_file.tmpfile] set file_extension [string tolower [file extension $upload_file]] # remove the first . from the file extension regsub "\." $file_extension "" file_extension set guessed_file_type [ns_guesstype $upload_file] set n_bytes [file size $tmp_filename] # Sizes we want for the portrait set sizename_list {avatar thumbnail} array set resized_portrait [list] # strip off the C:\directories... crud and just get the file name if {![regexp {([^/\\]+)$} $upload_file match client_filename]} { # couldn't find a match set client_filename $upload_file } # Wrap the whole creation along with the relationship in a big transaction # Just to make sure it really worked. db_transaction { set item_id [content::item::get_id_by_name -name "portrait-of-user-$user_id" -parent_id $user_id] if { $item_id eq ""} { # The user doesn't have a portrait relation yet set item_id [content::item::new -name "portrait-of-user-$user_id" -parent_id $user_id -content_type image] } else { foreach sizename $sizename_list { set resized_portrait($sizename) [image::get_resized_item_id \ -item_id $item_id \ -size_name $sizename] } } # Load the file into the revision set revision_id [cr_import_content \ -item_id $item_id \ -image_only \ -storage_type file \ -creation_user [ad_conn user_id] \ -creation_ip [ad_conn peeraddr] \ -description $portrait_comment \ $user_id \ $tmp_filename \ $n_bytes \ $guessed_file_type \ "portrait-of-user-$user_id"] content::item::set_live_revision -revision_id $revision_id foreach name [array names resized_portrait] { if { $resized_portrait($name) ne "" } { # Delete the item content::item::delete -item_id $resized_portrait($name) # Resize the item image::resize -item_id $item_id -size_name $name } } # Only create the new relationship if there does not exist one already set user_portrait_rel_id [relation::get_id -object_id_one $user_id -object_id_two $item_id -rel_type "user_portrait_rel"] if {$user_portrait_rel_id eq ""} { db_exec_plsql create_rel {} } } # Flush the portrait cache util_memoize_flush [list acs_user::get_portrait_id_not_cached -user_id $user_id] ad_returnredirect $return_url } ad_return_template openacs-5.7.0/packages/acs-subsite/www/user/portrait/upload.xql0000644000175000017500000000214510721062130024445 0ustar frankiefrankie SELECT live_revision as revision_id, item_id FROM acs_rels a, cr_items c WHERE a.object_id_two = c.item_id AND a.rel_type = 'user_portrait_rel' AND a.object_id_one = :current_user_id AND c.live_revision is not NULL select description from cr_revisions where revision_id = :revision_id select first_names, last_name from persons where person_id=:user_id openacs-5.7.0/packages/acs-subsite/www/user/portrait/comment-edit.adp0000644000175000017500000000022511164425461025517 0ustar frankiefrankie doc @context;noquote@ openacs-5.7.0/packages/acs-subsite/www/user/portrait/comment-edit.tcl0000644000175000017500000000316311164425461025541 0ustar frankiefrankiead_page_contract { screen to edit the comment associated with a user's portrait @author mbryzek@arsdigita.com @creation-date 22 Jun 2000 @cvs-id $Id: comment-edit.tcl,v 1.8 2009/03/31 14:39:45 emmar Exp $ } { {return_url "" } {user_id ""} } -properties { context:onevalue export_vars:onevalue description:onevalue first_names:onevalue last_name:onevalue } set current_user_id [ad_conn user_id] if {$user_id eq ""} { set user_id $current_user_id } ad_require_permission $user_id "write" if {![db_0or1row user_info {}]} { ad_return_error "Account Unavailable" "We can't find you (user #$user_id) in the users table. Probably your account was deleted for some reason." return } if {![db_0or1row portrait_info {}]} { ad_return_complaint 1 "
  • You shouldn't have gotten here; we don't have a portrait on file for you." return } set doc(title) [_ acs-subsite.Edit_caption] set context [list \ [list [ad_pvt_home] [ad_pvt_home_name]] \ [list "./" [_ acs-subsite.Your_Portrait]] \ $doc(title)] if { $return_url eq "" } { set return_url [ad_pvt_home] } ad_form -name comment_edit -export {user_id return_url} -form { {description:text(textarea),optional {label "#acs-subsite.Caption#"} {value $description} {html {rows "6" cols "50"}} } } -on_submit { if { [string length $description] > 4000 } { ad_return_complaint 1 "Your portrait comment can only be 4000 characters long." return } db_dml comment_update {} ad_returnredirect $return_url } ad_return_template openacs-5.7.0/packages/acs-subsite/www/user/portrait/comment-edit.xql0000644000175000017500000000244010723055642025560 0ustar frankiefrankie select first_names, last_name from persons where person_id = :user_id select description from cr_revisions where revision_id = (select live_revision from cr_items c, acs_rels a where c.item_id = a.object_id_two and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel') update cr_revisions set description=:description where revision_id = (select live_revision from acs_rels a, cr_items c where a.object_id_two = c.item_id and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel') openacs-5.7.0/packages/acs-subsite/www/user/password-reset.adp0000644000175000017500000000037110515672641024255 0ustar frankiefrankie #acs-subsite.Reset_Password# @context;noquote@
    @message@
    openacs-5.7.0/packages/acs-subsite/www/user/password-reset.tcl0000644000175000017500000000514010551254403024262 0ustar frankiefrankiead_page_contract { Let's the user reset his/her password. @cvs-id $Id: password-reset.tcl,v 1.2 2007/01/10 21:22:11 gustafn Exp $ } { {user_id {[ad_conn untrusted_user_id]}} {return_url ""} {password_hash ""} {message ""} } # Redirect to HTTPS if so configured if { [security::RestrictLoginToSSLP] } { security::require_secure_conn } if { ![auth::password::can_change_p -user_id $user_id] } { ad_return_error "Not supported" "Changing password is not supported." } set admin_p [permission::permission_p -object_id $user_id -privilege admin] if { !$admin_p } { permission::require_permission -party_id $user_id -object_id $user_id -privilege write } set page_title [_ acs-subsite.Reset_Password] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] set system_name [ad_system_name] set site_link [ad_site_home_link] acs_user::get -user_id $user_id -array user ad_form -name reset -edit_buttons [list [list [_ acs-kernel.common_update] "ok"]] -form { {user_id:integer(hidden)} {return_url:text(hidden),optional} {password_hash:text(hidden),optional} {message:text(hidden),optional} } ad_form -extend -name reset -form { {password_1:text(password) {label {[_ acs-subsite.New_Password]}} {html {size 20}} } {password_2:text(password) {label {[_ acs-subsite.Confirm]}} {html {size 20}} } } -on_request { } -validate { {password_1 { [string equal $password_1 $password_2] } { Passwords don't match } } } -on_submit { set password_hash_local [db_string get_password_hash {SELECT password FROM users WHERE user_id = :user_id}] if {$password_hash_local eq $password_hash} { array set result [auth::password::change \ -user_id $user_id \ -old_password "" \ -new_password $password_1] switch $result(password_status) { ok { # Continue } default { form set_error reset password_1 $result(password_message) break } } } else { form set_error reset password_1 "Invalid hash" break } } -after_submit { if { $return_url eq "" } { set return_url [ad_pvt_home] set pvt_home_name [ad_pvt_home_name] set continue_label [_ acs-subsite.Continue_to_your_account] } else { set continue_label [_ acs-subsite.Continue] } set message [_ acs-subsite.confirmation_password_changed] set continue_url $return_url ad_return_template /packages/acs-subsite/www/register/display-message } openacs-5.7.0/packages/acs-subsite/www/user/basic-info-update.adp0000644000175000017500000000060311164424127024556 0ustar frankiefrankie @page_title@ @context;noquote@

    #acs-subsite.Your_Account#

    @message@
    openacs-5.7.0/packages/acs-subsite/www/user/basic-info-update.tcl0000644000175000017500000000147711164424127024606 0ustar frankiefrankiead_page_contract { Displays form for currently logged in user to update his/her personal information @author Unknown @creation-date Unknown @cvs-id $Id: basic-info-update.tcl,v 1.14 2009/03/31 14:27:35 emmar Exp $ } { {return_url ""} {user_id ""} {edit_p 0} {message ""} } set page_title [_ acs-subsite.Your_Account] if { $user_id eq "" || ($user_id == [ad_conn untrusted_user_id]) } { set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] } else { set context [list $page_title] } set focus {} set subsite_id [ad_conn subsite_id] set user_info_template [parameter::get -parameter "UserInfoTemplate" -package_id $subsite_id] ns_log Debug "user:: $user_info_template" if {$user_info_template eq ""} { set user_info_template "/packages/acs-subsite/lib/user-info" } openacs-5.7.0/packages/acs-subsite/www/admin/0000755000175000017500000000000011724401447020713 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/subsite-convert-type.adp0000644000175000017500000000032611113231241025476 0ustar frankiefrankie @page_title@ @context@ subsite.instance_name openacs-5.7.0/packages/acs-subsite/www/admin/subsite-convert-type.tcl0000644000175000017500000000172111157574253025541 0ustar frankiefrankiead_page_contract { Convert the current subsite to one of its descendent subsite types. @author Steffen Tiedemann Christensen (steffen@christensen.name) @creation-date 2003-09-26 } auth::require_login set page_title "Convert Subsite To Descendent Type" set context [list $page_title] set subsite_package_options [apm::get_package_descendent_options [ad_conn package_key]] if { [llength $subsite_package_options] == 0 } { return . ad_script_abort } ad_form -name subsite -cancel_url . -form { {package_key:text(select) {label "Subsite Package"} {help_text "Choose the new subsite package type"} {options $subsite_package_options} } } -on_submit { if { $package_key ne [ad_conn package_key] } { apm::convert_type \ -package_id [ad_conn package_id] \ -old_package_key [ad_conn package_key] \ -new_package_key $package_key } ad_returnredirect . ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/confirm-delete-form.adp0000644000175000017500000000043207663154636025252 0ustar frankiefrankie
    @export_vars;noquote@
     
    openacs-5.7.0/packages/acs-subsite/www/admin/permissions-user-add.adp0000644000175000017500000000026707723347124025470 0ustar frankiefrankie @page_title@ @context@ openacs-5.7.0/packages/acs-subsite/www/admin/permissions-user-add.tcl0000644000175000017500000000051707723347124025504 0ustar frankiefrankiead_page_contract { Redirect page for adding users to the permissions list. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-13 @cvs-id $Id: permissions-user-add.tcl,v 1.2 2003/08/28 09:41:40 lars Exp $ } set page_title "Add User" set context [list [list "permissions" "Permissions"] $page_title] openacs-5.7.0/packages/acs-subsite/www/admin/users/0000755000175000017500000000000011575225551022060 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/users/new-postgresql.xql0000644000175000017500000000167107537350324025605 0ustar frankiefrankie postgresql7.1 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select t1.object_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t2.object_type = :add_with_rel_type ) select case when exists (select 1 from users where user_id = :user_id) then 1 else 0 end select oid as rowid from users where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/admin/users/new-oracle.xql0000644000175000017500000000163007300260125024625 0ustar frankiefrankie oracle8.1.6 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :add_with_rel_type connect by object_type = prior supertype ) select case when exists (select 1 from users where user_id = :user_id) then 1 else 0 end from dual select rowid from users where user_id = :user_id openacs-5.7.0/packages/acs-subsite/www/admin/users/new.adp0000644000175000017500000000023107663155307023337 0ustar frankiefrankie @context;noquote@ Add a user openacs-5.7.0/packages/acs-subsite/www/admin/users/new.tcl0000644000175000017500000002270711323322415023351 0ustar frankiefrankie# /packages/subsite/www/admin/users/new.tcl ad_page_contract { Adds a new party @author oumi@arsdigita.com @creation-date 2000-02-07 @cvs-id $Id: new.tcl,v 1.12 2010/01/13 10:48:45 emmar Exp $ } { { user_type:notnull "user" } { user_type_exact_p t } { user_id:naturalnum "" } { return_url "" } {add_to_group_id ""} {add_with_rel_type "user_profile"} {group_rel_type_list ""} } -properties { context:onevalue user_type_pretty_name:onevalue attributes:multirow } set context [list [list "" "Parties"] "Add a user"] set export_var_list [list \ user_id user_type add_to_group_id add_with_rel_type \ return_url user_type_exact_p group_rel_type_list] db_1row group_info { select group_name as add_to_group_name, join_policy as add_to_group_join_policy from groups where group_id = :add_to_group_id } # We assume the group is on side 1... db_1row rel_type_info { select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :add_with_rel_type connect by object_type = prior supertype ) } set create_p [group::permission_p -privilege create $add_to_group_id] # Membership relations have a member_state attribute that gets set # based on the group's join policy. if {$ancestor_rel_type eq "membership_rel"} { if {$add_to_group_join_policy eq "closed" && !$create_p} { ad_complain "You do not have permission to add elements to $add_to_group_name" return } set rel_member_state [group::default_member_state -join_policy $add_to_group_join_policy -create_p $create_p] } else { set rel_member_state "" } # Select out the user name and the user's object type. Note we can # use 1row because the validate filter above will catch missing parties db_1row select_type_info { select t.pretty_name as user_type_pretty_name, t.table_name from acs_object_types t where t.object_type = :user_type } ## ISSUE / TO DO: (see also admin/groups/new.tcl) ## ## Should there be a check here for required segments, as there is ## in parties/new.tcl? (see parties/new.tcl, search for ## "relation_required_segments_multirow). ## ## Tentative Answer: we don't need to repeat that semi-heinous check on this ## page, because (a) the user should have gotten to this page through ## parties/new.tcl, so the required segments check should have already ## happened before the user reaches this page. And (b) even if the user ## somehow bypassed parties/new.tcl, they can't cause any relational ## constraint violations in the database because the constraints are enforced ## by triggers in the DB. if { $user_type_exact_p eq "f" && \ [subsite::util::sub_type_exists_p $user_type] } { # Sub user-types exist... select one set user_type_exact_p "t" set export_url_vars [ad_export_vars -exclude user_type $export_var_list ] party::types_valid_for_rel_type_multirow -datasource_name object_types -start_with $user_type -rel_type $add_with_rel_type set object_type_pretty_name $user_type_pretty_name set this_url [ad_conn url] set object_type_variable user_type ad_return_template ../parties/add-select-type return } template::form create add_user if { [template::form is_request add_user] } { foreach var $export_var_list { template::element create add_user $var \ -value [set $var] \ -datatype text \ -widget hidden } # Set the object id for the new user template::element set_properties add_user user_id \ -value [db_nextval "acs_object_id_seq"] } foreach var [list email first_names last_name] { template::element create add_user $var \ -datatype text -widget text -html {size 30} } template::element create add_user url \ -datatype text -widget text -html {size 30} -optional template::element create add_user password \ -datatype text -widget inform -html {size 30} \ -value "-- automatically generated --" # Get whether they requre some sort of approval if {[parameter::get -parameter RegistrationRequiresApprovalP -default 0]} { set member_state "" } else { set member_state "approved" } # attribute::add_form_elements -form_id add_user -variable_prefix user -start_with user -object_type $user_type attribute::add_form_elements -form_id add_user -variable_prefix rel -start_with relationship -object_type $add_with_rel_type if { [template::form is_valid add_user] } { set password [ad_generate_random_string] if {$add_to_group_id eq ""} { set add_to_group_id [application_group::group_id_from_package_id] } if {[parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0]} { set email_verified_p "f" } else { set email_verified_p "t" } set double_click_p [db_string user_exists { select case when exists (select 1 from users where user_id = :user_id) then 1 else 0 end from dual }] if {!$double_click_p} { db_transaction { # LARS: Hack - we should use acs-subsite/lib/user-new instead array set result [auth::create_user \ -user_id $user_id \ -email [template::element::get_value add_user email] \ -first_names [template::element::get_value add_user first_names] \ -last_name [template::element::get_value add_user last_name] \ -password $password \ -password_confirm $password \ -url [template::element::get_value add_user url] \ -email_verified_p $email_verified_p] # LARS: Hack, we should check the result set user_id $result(user_id) # Hack for adding users to the main subsite, whose application group is the registered users group. if { $add_to_group_id != [acs_lookup_magic_object "registered_users"] || $add_with_rel_type ne "membership_rel" } { relation_add -member_state $rel_member_state $add_with_rel_type $add_to_group_id $user_id } } on_error { ad_return_error "User Creation Failed" "We were unable to create the user record in the database." } } # there may be more segments to put this new party in before the # user's original request is complete. So build a return_url stack foreach group_rel_type $group_rel_type_list { set next_group_id [lindex $group_rel_type 0] set next_rel_type [lindex $group_rel_type 1] lappend return_url_list \ "../relations/add?group_id=$next_group_id&rel_type=[ad_urlencode $next_rel_type]&party_id=$user_id&allow_out_of_scope_p=t" } # Add the original return_url as the last one in the list lappend return_url_list $return_url set return_url_stacked [subsite::util::return_url_stack $return_url_list] if {$return_url_stacked eq ""} { set return_url_stacked "../parties/one?party_id=$user_id" } ad_returnredirect $return_url_stacked if {!$double_click_p} { set notification_address [parameter::get -parameter NewRegistrationEmailAddress -default [ad_system_owner]] if {[parameter::get -parameter NotifyAdminOfNewRegistrationsP -default 0]} { set creation_user [ad_conn user_id] set creation_name [db_string creation_name_query { select p.first_names || ' ' || p.last_name || ' (' || pa.email || ')' from persons p, parties pa where p.person_id = pa.party_id and p.person_id = :creation_user }] # we're supposed to notify the administrator when someone new registers acs_mail_lite::send -send_immediately \ -to_addr $notification_address \ -from_addr [template::element::get_value add_user email] \ -subject "New registration at [ad_url]" \ -body "[template::element::get_value add_user first_names] [template::element::get_value add_user last_name] ([template::element::get_value add_user email]) was added as a registered as a user of [ad_url] The user was added by $creation_name from [ad_conn url]." } if { $email_verified_p eq "f" } { set row_id [db_string user_new_2_rowid_for_email "select rowid from users where user_id = :user_id"] # the user has to come back and activate their account ns_sendmail [template::element::get_value add_user email] \ $notification_address \ "Welcome to [ad_system_name]" \ "To confirm your registration, please go to [parameter::get -package_id [ad_acs_kernel_id] -parameter SystemURL]/register/email-confirm?[export_url_vars row_id] After confirming your email, here's how you can log in at [ad_url]: Username: [template::element::get_value add_user email] Password: $password " } else { with_catch errmsg { # ns_log Notice "sending mail from $notification_address to [template::element::get_value add_user email]" ns_sendmail [template::element::get_value add_user email] \ $notification_address \ "Thank you for visiting [ad_system_name]" \ "Here's how you can log in at [ad_url]: Username: [template::element::get_value add_user email] Password: $password " } { ns_returnerror "500" "$errmsg" ns_log Warning "Error sending registration confirmation to $email in acs-subsite/www/admin/users/new Error: $errmsg" } } } ad_script_abort } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/users/new.xql0000644000175000017500000000153107300260125023362 0ustar frankiefrankie select group_name as add_to_group_name, join_policy as add_to_group_join_policy from groups where group_id = :add_to_group_id select t.pretty_name as user_type_pretty_name, t.table_name from acs_object_types t where t.object_type = :user_type select p.first_names || ' ' || p.last_name || ' (' || pa.email || ')' from persons p, parties pa where p.person_id = pa.party_id and p.person_id = :creation_user openacs-5.7.0/packages/acs-subsite/www/admin/attributes/0000755000175000017500000000000011724401447023101 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add-2.tcl0000644000175000017500000000402010551254376025436 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attribute-add.tcl ad_page_contract { Adds attributes @author mbryzek@arsdigita.com @creation-date Tue Nov 7 12:14:42 2000 @cvs-id $Id: enum-add-2.tcl,v 1.2 2007/01/10 21:22:06 gustafn Exp $ } { attribute_id:integer,notnull attribute_enum_values:array,trim,optional { operation:trim "Finish adding values" } { return_url "" } } set max_sort_order [db_string select_max_sort_order { select nvl(max(v.sort_order),0) from acs_enum_values v where v.attribute_id = :attribute_id }] db_transaction { foreach ideal_sort_order [array names attribute_enum_values] { set sort_order [expr {$ideal_sort_order + $max_sort_order}] set pretty_name $attribute_enum_values($ideal_sort_order) # delete if the value is empty. Update otherwise if { $pretty_name eq "" } { db_dml delete_enum_value { delete from acs_enum_values where attribute_id = :attribute_id and sort_order = :sort_order } } else { db_dml update_enum_value { update acs_enum_values v set v.pretty_name = :pretty_name where v.attribute_id = :attribute_id and v.sort_order = :sort_order } if { [db_resultrows] == 0 } { # No update - insert the row. Set the enum_value to # the pretty_name db_dml insert_enum_value { insert into acs_enum_values v (attribute_id, sort_order, enum_value, pretty_name) select :attribute_id, :sort_order, :pretty_name, :pretty_name from dual where not exists (select 1 from acs_enum_values v2 where v2.pretty_name = :pretty_name and v2.attribute_id = :attribute_id) } } } } } db_release_unused_handles if {$operation eq "Add more values"} { # redirect to add more values set return_url enum-add?[ad_export_vars {attribute_id return_url}] } elseif { $return_url eq "" } { set return_url one?[ad_export_vars attribute_id] } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add-2.xql0000644000175000017500000000132107337765016025467 0ustar frankiefrankie select coalesce(max(v.sort_order),0) from acs_enum_values v where v.attribute_id = :attribute_id delete from acs_enum_values where attribute_id = :attribute_id and sort_order = :sort_order update acs_enum_values set pretty_name = :pretty_name where attribute_id = :attribute_id and sort_order = :sort_order openacs-5.7.0/packages/acs-subsite/www/admin/attributes/edit-one.adp0000644000175000017500000000035407663154673025312 0ustar frankiefrankie @context;noquote@ Edit @attribute_pretty_name;noquote@ @focus;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/attributes/edit-one.tcl0000644000175000017500000000551310551254376025321 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/edit-one.tcl ad_page_contract { Edits one attribute @author mbryzek@arsdigita.com @creation-date Thu Nov 9 20:06:49 2000 @cvs-id $Id: edit-one.tcl,v 1.4 2007/01/10 21:22:06 gustafn Exp $ } { attribute_id:naturalnum id_column:trim,integer { attribute_value "" } { return_url "" } } -properties { context:onevalue focus:onevalue attribute_pretty_name:onevalue } ad_require_permission $id_column "write" set context [list "Edit attribute"] db_1row attribute_properties { select a.pretty_name as attribute_pretty_name, a.datatype, a.attribute_id, nvl(a.column_name,a.attribute_name) as attribute_column, t.id_column as type_column, t.table_name as type_table, t.object_type, a.min_n_values from acs_attributes a, acs_object_types t where a.attribute_id = :attribute_id and a.object_type = t.object_type } db_1row select_value " select my_view.$attribute_column as current_value from ([package_object_view $object_type]) my_view where my_view.object_id = :id_column " template::form create edit_attribute template::element create edit_attribute attribute_id -value $attribute_id \ -label "Attribute ID" -datatype text -widget hidden template::element create edit_attribute object_type -value $object_type \ -label "Object type" -datatype text -widget hidden # add the space to avoid looking like a switch template::element create edit_attribute id_column -value " $id_column" \ -datatype text -widget hidden template::element create edit_attribute return_url -value $return_url \ -optional -datatype text -widget hidden if {$datatype eq "enumeration"} { set focus "" set option_list [db_list_of_lists select_enum_values { select enum.pretty_name, enum.enum_value from acs_enum_values enum where enum.attribute_id = :attribute_id order by enum.sort_order }] if { $min_n_values == 0 } { # This is not a required option list... offer a default lappend option_list [list " (no value) " ""] } template::element create edit_attribute attribute_value \ -value $current_value \ -datatype "text" \ -widget select \ -optional \ -options $option_list \ -label "$attribute_pretty_name" } else { set focus "edit_attribute.attribute_value" template::element create edit_attribute attribute_value \ -value $current_value \ -datatype "text" \ -optional \ -label "$attribute_pretty_name" } if { [template::form is_valid edit_attribute] } { set attribute_value [ns_set get [ns_getform] "attribute_value"] db_dml attribute_update \ "update $type_table set $attribute_column = :attribute_value where $type_column = :id_column" ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/attributes/edit-one.xql0000644000175000017500000000236607300260124025330 0ustar frankiefrankie select a.pretty_name as attribute_pretty_name, a.datatype, a.attribute_id, coalesce(a.column_name,a.attribute_name) as attribute_column, t.id_column as type_column, t.table_name as type_table, t.object_type, a.min_n_values from acs_attributes a, acs_object_types t where a.attribute_id = :attribute_id and a.object_type = t.object_type select my_view.$attribute_column as current_value from ([package_object_view $object_type]) my_view where my_view.object_id = :id_column select enum.pretty_name, enum.enum_value from acs_enum_values enum where enum.attribute_id = :attribute_id order by enum.sort_order update $type_table set $attribute_column = :attribute_value where $type_column = :id_column openacs-5.7.0/packages/acs-subsite/www/admin/attributes/value-delete-2.tcl0000644000175000017500000000117510551254376026330 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/value-delete-2.tcl ad_page_contract { Deletes a value @author mbryzek@arsdigita.com @creation-date Sun Dec 10 14:48:44 2000 @cvs-id $Id: value-delete-2.tcl,v 1.2 2007/01/10 21:22:06 gustafn Exp $ } { attribute_id:naturalnum,notnull enum_value:trim,notnull { operation:trim "No, I want to cancel my request" } { return_url "one?[ad_export_vars attribute_id]" } } if {$operation eq "Yes, I really want to delete this attribute value"} { db_transaction { attribute::value_delete $attribute_id $enum_value } } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/attributes/add-2.tcl0000644000175000017500000000341110551254376024477 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attribute-add.tcl ad_page_contract { Adds attributes @author mbryzek@arsdigita.com @creation-date Tue Nov 7 12:14:42 2000 @cvs-id $Id: add-2.tcl,v 1.3 2007/01/10 21:22:06 gustafn Exp $ } { object_type:notnull,trim pretty_name:notnull,trim pretty_plural:notnull,trim default_value:trim datatype:notnull,trim required_p:notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue pretty_name:onevalue datatypes:multirow } -validate { dynamic_type -requires {object_type:notnull} { if { ![package_type_dynamic_p $object_type] } { ad_complain "The specified object type, $object_type, is not dynamic and therefore cannot be modified." } } } # Let's see if the attribute already exists if { [attribute::exists_p $object_type $pretty_name] } { ad_return_complaint 1 "
  • The specified attribute, $pretty_name, already exists" return } # Right now, we do not support multiple values for attributes set max_n_values 1 if {$required_p eq "t"} { set min_n_values 1 } else { set min_n_values 0 } # Add the attributes to the specified object_type db_transaction { set attribute_id [attribute::add -min_n_values $min_n_values -max_n_values $max_n_values -default $default_value $object_type $datatype $pretty_name $pretty_plural] # Recreate all the packages to use the new attribute package_recreate_hierarchy $object_type } # If we're an enumeration, redirect to start adding possible values. if {$datatype eq "enumeration"} { ad_returnredirect enum-add?[ad_export_vars {attribute_id return_url}] } elseif { $return_url eq "" } { ad_returnredirect add?[ad_export_vars {object_type}] } else { ad_returnredirect $return_url } openacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add.adp0000644000175000017500000000153607663154673025303 0ustar frankiefrankie @context;noquote@ Specify values for @attribute_pretty_name;noquote@ Note: Every value must have a unique name. Duplicate names will be ignored.

    Current values

    • none
    • @current_values.enum_value@
    @export_vars;noquote@
    Value @value_form.sort_order@:

    openacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add.tcl0000644000175000017500000000266010551254376025307 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attribute-add.tcl ad_page_contract { Adds attributes @author mbryzek@arsdigita.com @creation-date Tue Nov 7 12:14:42 2000 @cvs-id $Id: enum-add.tcl,v 1.3 2007/01/10 21:22:06 gustafn Exp $ } { attribute_id:integer,notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue attribute_pretty_name:onevalue attribute_src:multirow max_values:onevalue } set number_values [db_string number_values { select count(*) from acs_enum_values v where v.attribute_id = :attribute_id }] # Set up datasource of existing attribute values db_multirow current_values select_current_values { select v.enum_value from acs_enum_values v where v.attribute_id = :attribute_id order by v.sort_order } set max_values 5 # Set up a datasource to enter multiple attributes template::multirow create value_form sort_order field_name for { set i 1 } { $i <= $max_values } { incr i } { template::multirow append value_form [expr {$i + $number_values}] "attribute_enum_values.[expr {$i + $number_values}]" } db_1row select_attr_name { select a.pretty_name as attribute_pretty_name from acs_attributes a where a.attribute_id = :attribute_id } set context [list [list one?[export_url_vars attribute_id] "One attribute"] "Add values"] set export_vars [ad_export_vars -form {attribute_id return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add.xql0000644000175000017500000000126307300260124025311 0ustar frankiefrankie select count(*) from acs_enum_values v where v.attribute_id = :attribute_id select v.enum_value from acs_enum_values v where v.attribute_id = :attribute_id order by v.sort_order select a.pretty_name as attribute_pretty_name from acs_attributes a where a.attribute_id = :attribute_id openacs-5.7.0/packages/acs-subsite/www/admin/attributes/delete-2.tcl0000644000175000017500000000175610551254376025223 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/delete-2.tcl ad_page_contract { Deletes the attribute and all values @author mbryzek@arsdigita.com @creation-date Sun Nov 12 18:03:50 2000 @cvs-id $Id: delete-2.tcl,v 1.2 2007/01/10 21:22:06 gustafn Exp $ } { attribute_id:notnull,naturalnum,attribute_dynamic_p { return_url "" } { operation "" } } if {$operation eq "Yes, I really want to delete this attribute"} { db_transaction { set object_type [db_string select_object_type { select attr.object_type from acs_attributes attr where attr.attribute_id = :attribute_id } -default ""] # If object type is empty, that means the attribute doesn't exist if { $object_type ne "" && [attribute::delete $attribute_id] } { # Recreate all the packages to use the new attribute package_recreate_hierarchy $object_type } } } elseif { $return_url eq "" } { set return_url one?[ad_export_vars attribute_id] } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/attributes/delete-2.xql0000644000175000017500000000040407300260124025214 0ustar frankiefrankie select attr.object_type from acs_attributes attr where attr.attribute_id = :attribute_id openacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add-2-postgresql.xql0000644000175000017500000000117307337765016027675 0ustar frankiefrankie postgresql7.1 insert into acs_enum_values (attribute_id, sort_order, enum_value, pretty_name) select :attribute_id, :sort_order, :pretty_name, :pretty_name where not exists (select 1 from acs_enum_values v2 where v2.pretty_name = :pretty_name and v2.attribute_id = :attribute_id) openacs-5.7.0/packages/acs-subsite/www/admin/attributes/enum-add-2-oracle.xql0000644000175000017500000000153307300260124026713 0ustar frankiefrankie oracle8.1.6 select nvl(max(v.sort_order),0) from acs_enum_values v where v.attribute_id = :attribute_id insert into acs_enum_values v (attribute_id, sort_order, enum_value, pretty_name) select :attribute_id, :sort_order, :pretty_name, :pretty_name from dual where not exists (select 1 from acs_enum_values v2 where v2.pretty_name = :pretty_name and v2.attribute_id = :attribute_id) openacs-5.7.0/packages/acs-subsite/www/admin/attributes/index.tcl0000644000175000017500000000046507253523116024721 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/index.tcl ad_page_contract { Redirects up one level... useless page right now @author mbryzek@arsdigita.com @creation-date Thu Dec 7 16:33:54 2000 @cvs-id $Id: index.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ } { } ad_returnredirect ../ openacs-5.7.0/packages/acs-subsite/www/admin/attributes/add.adp0000644000175000017500000000216607663154673024341 0ustar frankiefrankie @context;noquote@ Add attribute to @object_pretty_name;noquote@ main_form.pretty_name
    @export_vars;noquote@
    Attribute pretty name:
    Attribute pretty plural:
    Default value:
    Required?:
    Datatype:

    openacs-5.7.0/packages/acs-subsite/www/admin/attributes/add.tcl0000644000175000017500000000263707536221405024345 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attribute/add.tcl ad_page_contract { Form to adds attributes @author mbryzek@arsdigita.com @creation-date Tue Nov 7 12:14:42 2000 @cvs-id $Id: add.tcl,v 1.2 2002/09/06 21:49:57 jeffd Exp $ } { object_type:notnull,trim { return_url "" } } -properties { context:onevalue export_vars:onevalue object_pretty_name:onevalue datatypes:multirow } -validate { dynamic_type -requires {object_type:notnull} { if { ![package_type_dynamic_p $object_type] } { ad_complain "The specified object type, $object_type, is not dynamic and therefore cannot be modified." } } } set context [list "Add attribute"] set export_vars [ad_export_vars -form {object_type return_url}] set object_pretty_name [db_string object_pretty_name { select t.pretty_name from acs_object_types t where t.object_type = :object_type }] # Create a datasource of all the datatypes for which we have validators set ctr 0 template::multirow create datatypes datatype db_foreach select_datatypes { select d.datatype from acs_datatypes d order by lower(d.datatype) } { if { [attribute::datatype_validator_exists_p $datatype] } { incr ctr template::multirow append datatypes $datatype } } if { $ctr == 0 } { ad_return_error "No datatypes" "There are no datatypes with validators available for use" ad_script_abort } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/attributes/add.xql0000644000175000017500000000065707300260124024355 0ustar frankiefrankie select t.pretty_name from acs_object_types t where t.object_type = :object_type select d.datatype from acs_datatypes d order by lower(d.datatype) openacs-5.7.0/packages/acs-subsite/www/admin/attributes/edit-one-oracle.xql0000644000175000017500000000113207300260124026561 0ustar frankiefrankie oracle8.1.6 select a.pretty_name as attribute_pretty_name, a.datatype, a.attribute_id, nvl(a.column_name,a.attribute_name) as attribute_column, t.id_column as type_column, t.table_name as type_table, t.object_type, a.min_n_values from acs_attributes a, acs_object_types t where a.attribute_id = :attribute_id and a.object_type = t.object_type openacs-5.7.0/packages/acs-subsite/www/admin/attributes/one.adp0000644000175000017500000000170407663154673024367 0ustar frankiefrankie @context;noquote@ @attribute.pretty_name;noquote@ Properties:
    • @attr_props.key@: @attr_props.value@

    Possible values:

    Administration:

    • Delete this attribute
    • This attribute can only be administered by programmers as it does not belong to a dynamically created object.
    openacs-5.7.0/packages/acs-subsite/www/admin/attributes/one.tcl0000644000175000017500000000322410551254376024373 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/one.tcl ad_page_contract { Shows information about one attribute @author mbryzek@arsdigita.com @creation-date Sun Nov 12 17:59:39 2000 @cvs-id $Id: one.tcl,v 1.3 2007/01/10 21:22:06 gustafn Exp $ } { attribute_id:naturalnum,notnull { return_url "" } } -properties { context:onevalue attribute:onerow url_vars:onevalue dynamic_p:onevalue enum_values:multirow } set context [list "One attribute"] set url_vars [ad_export_vars {attribute_id return_url}] # Note we really do want all the columns here for this generic display # Stuff it into a column array to avoid writing all these damn column # names again db_1row select_attribute_info { select a.attribute_id, a.object_type, a.table_name, a.attribute_name, a.pretty_name, a.pretty_plural, a.sort_order, a.datatype, a.default_value, a.min_n_values, a.max_n_values, a.storage, a.static_p, a.column_name, t.dynamic_p from acs_attributes a, acs_object_types t where a.object_type = t.object_type and a.attribute_id = :attribute_id } -column_array attribute # Set up a multirow datasource to process this data template::multirow create attr_props key value foreach n [lsort [array names attribute]] { template::multirow append attr_props $n $attribute($n) } if {$attribute(datatype) eq "enumeration"} { # set up the enum values datasource db_multirow enum_values enum_values { select v.enum_value, v.pretty_name from acs_enum_values v where v.attribute_id = :attribute_id order by v.sort_order } } set dynamic_p $attribute(dynamic_p) ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/attributes/one.xql0000644000175000017500000000141007300260124024372 0ustar frankiefrankie select a.attribute_id, a.object_type, a.table_name, a.attribute_name, a.pretty_name, a.pretty_plural, a.sort_order, a.datatype, a.default_value, a.min_n_values, a.max_n_values, a.storage, a.static_p, a.column_name, t.dynamic_p from acs_attributes a, acs_object_types t where a.object_type = t.object_type and a.attribute_id = :attribute_id select v.enum_value, v.pretty_name from acs_enum_values v where v.attribute_id = :attribute_id order by v.sort_order openacs-5.7.0/packages/acs-subsite/www/admin/attributes/delete.adp0000644000175000017500000000103307663154673025043 0ustar frankiefrankie @context;noquote@ Delete @attribute_pretty_name;noquote@ Are you sure you want to permanently remove this attribute? Doing so will also remove any values previously specified for this attribute for any object of type "@object_type@."

    openacs-5.7.0/packages/acs-subsite/www/admin/attributes/delete.tcl0000644000175000017500000000151207536221405025046 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/delete.tcl ad_page_contract { Deletes attribute @author mbryzek@arsdigita.com @creation-date Sun Nov 12 18:03:50 2000 @cvs-id $Id: delete.tcl,v 1.2 2002/09/06 21:49:57 jeffd Exp $ } { attribute_id:notnull,naturalnum,attribute_dynamic_p { return_url "" } } -properties { context:onevalue attribute_id:onevalue object_type:onevalue attribute_pretty_name:onevalue export_form_vars:onevalue } set context [list [list one?[ad_export_vars attribute_id] "One attribute"] "Delete attribute"] db_1row select_object_type { select a.object_type, a.pretty_name as attribute_pretty_name from acs_attributes a where a.attribute_id = :attribute_id } set export_form_vars [ad_export_vars -form {attribute_id return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/attributes/delete.xql0000644000175000017500000000044007300260124025055 0ustar frankiefrankie select a.object_type, a.pretty_name as attribute_pretty_name from acs_attributes a where a.attribute_id = :attribute_id openacs-5.7.0/packages/acs-subsite/www/admin/attributes/value-delete.adp0000644000175000017500000000065607663154673026167 0ustar frankiefrankie @context;noquote@ Delete value @pretty_name;noquote@ Are you sure you want to permanently remove this attribute value?

    openacs-5.7.0/packages/acs-subsite/www/admin/attributes/value-delete.tcl0000644000175000017500000000163207542067250026166 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/attributes/value-delete.tcl ad_page_contract { Deletes a value @author mbryzek@arsdigita.com @creation-date Sun Dec 10 14:45:29 2000 @cvs-id $Id: value-delete.tcl,v 1.3 2002/09/18 12:16:40 jeffd Exp $ } { attribute_id:naturalnum,notnull enum_value:trim,notnull { return_url "one?[ad_export_vars attribute_id]" } } -properties { context:onevalue export_vars:onevalue pretty_name:onevalue } if { ![db_0or1row select_pretty_name { select v.pretty_name from acs_enum_values v where v.attribute_id = :attribute_id and v.enum_value = :enum_value }] } { # Already deleted ad_returnredirect $return_url ad_script_abort } set context [list [list one?[ad_export_vars attribute_id] "One attribute"] "Delete value"] set export_vars [ad_export_vars -form {attribute_id enum_value return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/attributes/value-delete.xql0000644000175000017500000000043507300260124026173 0ustar frankiefrankie select v.pretty_name from acs_enum_values v where v.attribute_id = :attribute_id and v.enum_value = :enum_value openacs-5.7.0/packages/acs-subsite/www/admin/manage-email-privacy.adp0000644000175000017500000000026510173502613025366 0ustar frankiefrankie #acs-subsite.manage_users_email# @context;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/manage-email-privacy.tcl0000644000175000017500000000206210173502613025401 0ustar frankiefrankiead_page_contract { Administer the PrivateEmailLevelP parameter @author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) } { } -properties { context:onevalue } set page_title "\"#acs-subsite.manage_users_email\#\"" set context [list [list "." "Users"] "\"#acs-subsite.manage_users_email\#\""] set user_id [auth::require_login -account_status closed] ad_form -name private-email -form { {level:integer(select) {label "\#acs-subsite.Change_my_email_P\#:"} {options {{"[_ acs-subsite.email_as_text_admin]" 4} {"[_ acs-subsite.email_as_image_admin]" 3} \ {"[_ acs-subsite.email_as_a_form_admin]" 2} {"[_ acs-subsite.email_dont_show_admin]" 1}}} } } -on_request { set level [parameter::get_from_package_key -package_key "acs-subsite" \ -parameter "PrivateEmailLevelP" -default 4] } -on_submit { set package_id [apm_package_id_from_key acs-subsite] parameter::set_value -package_id $package_id -parameter "PrivateEmailLevelP" -value $level } -after_submit { ad_returnredirect "/acs-admin/users/" }openacs-5.7.0/packages/acs-subsite/www/admin/group-types/0000755000175000017500000000000011724401447023211 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-rel-types-exist.adp0000644000175000017500000000077007663154723030232 0ustar frankiefrankie @context;noquote@ Relationship types exist that depend on this group type You must remove all of the following relationship types before you can remove the @group_type_pretty_name@ group type.

    The following relationship types currently depend on this group type:

    • @rel_types.pretty_name@ (delete)
    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-remove-2.tcl0000644000175000017500000000171110551254376027114 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/group-types/rel-type-remove-2.tcl ad_page_contract { Removes the specified relation from the list of allowable ones @author mbryzek@arsdigita.com @creation-date Sun Dec 10 16:45:32 2000 @cvs-id $Id: rel-type-remove-2.tcl,v 1.2 2007/01/10 21:22:06 gustafn Exp $ } { group_rel_type_id:naturalnum,notnull { return_url "" } { operation:trim "No, I want to cancel my request" } } if { $return_url eq "" } { # Pull out the group_type now as we may delete the row later db_1row select_group_type { select g.group_type from group_type_rels g where g.group_rel_type_id = :group_rel_type_id } set return_url one?[ad_export_vars {group_type}] } if {$operation eq "Yes, I really want to remove this relationship type"} { db_transaction { db_dml remove_relation { delete from group_type_rels where group_rel_type_id = :group_rel_type_id } } } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-remove-2.xql0000644000175000017500000000065507300260124027126 0ustar frankiefrankie select g.group_type from group_type_rels g where g.group_rel_type_id = :group_rel_type_id delete from group_type_rels where group_rel_type_id = :group_rel_type_id openacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy.adp0000644000175000017500000000121207663154723027363 0ustar frankiefrankie @context;noquote@ @group_type_pretty_name;noquote@
    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy.tcl0000644000175000017500000000270410551254376027403 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/one.tcl ad_page_contract { Change default join policy for a group type. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2001-02-23 @cvs-id $Id: change-join-policy.tcl,v 1.4 2007/01/10 21:22:06 gustafn Exp $ } { group_type:notnull {return_url ""} } -properties { context:onevalue group_type:onevalue QQgroup_type:onevalue group_type_pretty_name:onevalue admin_p:onevalue QQreturn_url:onevalue default_join_policy:onevalue possible_join_policies:onevalue } set context [list \ [list "[ad_conn package_url]admin/group-types/" "Group types"] \ [list "one?[ad_export_vars group_type]" "One type"] \ "Edit default join policy"] if { ![db_0or1row select_pretty_name { select t.pretty_name as group_type_pretty_name, t.dynamic_p, nvl(gt.default_join_policy, 'open') as default_join_policy from acs_object_types t, group_types gt where t.object_type = :group_type and t.object_type = gt.group_type(+) }] } { ad_return_error "Group type doesn't exist" "Group type \"$group_type\" doesn't exist" return } if {$dynamic_p ne "t" } { ad_return_error "Cannot administer group type" "Group type \"$group_type\" can only be administered by programmers" } set possible_join_policies [list open "needs approval" closed] set QQreturn_url [ad_quotehtml $return_url] set QQgroup_type [ad_quotehtml $group_type] ad_return_templateopenacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy.xql0000644000175000017500000000064407341276557027436 0ustar frankiefrankie select t.pretty_name as group_type_pretty_name, t.dynamic_p, coalesce(gt.default_join_policy, 'open') as default_join_policy from acs_object_types t left outer join group_types gt on (t.object_type = gt.group_type) where t.object_type = :group_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-list.adp0000644000175000017500000000030207253523116026162 0ustar frankiefrankie
  • (none)
  • @groups.group_name@
  • openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-list.tcl0000644000175000017500000000156207253523116026211 0ustar frankiefrankie# /packages/acs-subsite/www/admin/group-types/groups-list.tcl # sets up datasource for groups-list.adp if { ![exists_and_not_null group_type] } { error "Group type must be specified" } set user_id [ad_conn user_id] set package_id [ad_conn package_id] db_multirow groups select_groups { select DISTINCT g.group_id, g.group_name from (select group_id, group_name from groups g, acs_objects o where g.group_id = o.object_id and o.object_type = :group_type) g, (select object_id from all_object_party_privilege_map where party_id = :user_id and privilege = 'read') perm, application_group_element_map m where perm.object_id = g.group_id and m.package_id = :package_id and m.element_id = g.group_id order by lower(g.group_name) } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-list.xql0000644000175000017500000000130707300260124026216 0ustar frankiefrankie select DISTINCT g.group_id, g.group_name from (select group_id, group_name from groups g, acs_objects o where g.group_id = o.object_id and o.object_type = :group_type) g, (select object_id from all_object_party_privilege_map where party_id = :user_id and privilege = 'read') perm, application_group_element_map m where perm.object_id = g.group_id and m.package_id = :package_id and m.element_id = g.group_id order by lower(g.group_name) openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-subtypes-exist.adp0000644000175000017500000000063307663154723030162 0ustar frankiefrankie @context;noquote@ Subtypes exist! You must remove all subtypes of the group type "@group_type_pretty_name@" before you can remove the group type.

    The following subtypes currently exist:

    • @subtypes.pretty_name@ (delete)
    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/new-postgresql.xql0000644000175000017500000000140507403013337026725 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end select repeat(' ', (tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4) || t2.pretty_name, t2.object_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type = 'group' openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add-2-postgresql.xql0000644000175000017500000000067107300260124030560 0ustar frankiefrankie postgresql7.1 select count(*) from acs_rel_types t where (t.object_type_one = :group_type or acs_object_type__is_subtype_p(t.object_type_one, :group_type) = 't') and t.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-2.tcl0000644000175000017500000000664110551254376025331 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/group-types/delete-2.tcl ad_page_contract { Deletes a group type @author mbryzek@arsdigita.com @creation-date Wed Nov 8 18:29:11 2000 @cvs-id $Id: delete-2.tcl,v 1.5 2007/01/10 21:22:06 gustafn Exp $ } { group_type { return_url "" } { operation "" } } -properties { context:onevalue } -validate { user_can_delete_group -requires {group_type:notnull} { if { ![group_type::drop_all_groups_p $group_type] } { ad_complain "Groups exist that you do not have permission to delete. All groups must be deleted before you can remove a group type. Please contact the site administrator." } } } if { $operation ne "Yes, I really want to delete this group type" } { if { $return_url eq "" } { ad_returnredirect "one?[ad_export_vars {group_type}]" } else { ad_returnredirect $return_url } ad_script_abort } set plsql [list] if { ![db_0or1row select_type_info { select t.table_name, t.package_name from acs_object_types t where t.object_type=:group_type }] } { set table_name "" set package_name $group_type } if { [db_string package_exists { select case when exists (select 1 from user_objects o where o.object_type='PACKAGE' and o.object_name = upper(:package_name)) then 1 else 0 end from dual }] } { lappend plsql [list "package_drop" [db_map package_drop]] } else { set package_name "" } # Remove the specified rel_types lappend plsql [list "delete_rel_types" [db_map delete_rel_types]] # Remove the group_type lappend plsql [list "delete_group_type" [db_map delete_group_type]] if { [db_string type_exists { select case when exists (select 1 from acs_object_types t where t.object_type = :group_type) then 1 else 0 end from dual }] } { lappend plsql [list "drop_type" [db_map drop_type]] } # Make sure we drop the table last if { $table_name ne "" && [db_table_exists $table_name] } { lappend plsql [list "drop_table" [db_map drop_table]] } # How do we handle the situation where we delete the groups we can, # but there are groups that we do not have permission to delete? For # now, we check in advance if there is a group that must be deleted # that this user can't delete, and if there is, we return an error # message (in the validate block of page contract). If another group # is added while we're deleting, then it's possible that we'll fail # when actually dropping the type, but that seems reasonable to me. # - mbryzek (famous last words...) set user_id [ad_conn user_id] db_transaction { # First delete the groups if { $package_name ne "" } { foreach group_id [db_list select_group_ids { select o.object_id from acs_objects o, acs_object_party_privilege_map perm where perm.object_id = o.object_id and perm.party_id = :user_id and perm.privilege = 'delete' and o.object_type = :group_type }] { group::delete $group_id } } foreach pair $plsql { db_exec_plsql [lindex $pair 0] [lindex $pair 1] } } on_error { ad_return_error "Error deleting group type" "We got the following error trying to delete this group type:
    $errmsg
    " return } # Reset the attribute view for objects of this type package_object_view_reset $group_type ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-2.xql0000644000175000017500000000115207401227553025340 0ustar frankiefrankie select t.table_name, t.package_name from acs_object_types t where t.object_type=:group_type select distinct o.object_id from acs_objects o, all_object_party_privilege_map perm where perm.object_id = o.object_id and perm.party_id = :user_id and perm.privilege = 'delete' and o.object_type = :group_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-list-postgresql.xql0000644000175000017500000000147107326606510030434 0ustar frankiefrankie postgresql7.1 select g.group_id, g.group_name from ( select distinct g.group_id, g.group_name from (select group_id, group_name from groups g, acs_objects o where g.group_id = o.object_id and o.object_type = :group_type) g, (select object_id from all_object_party_privilege_map where party_id = :user_id and privilege = 'read') perm, application_group_element_map m where perm.object_id = g.group_id and m.package_id = :package_id and m.element_id = g.group_id order by g.group_id, g.group_name) g order by lower(g.group_name) openacs-5.7.0/packages/acs-subsite/www/admin/group-types/one-postgresql.xql0000644000175000017500000000274607443753715026745 0ustar frankiefrankie postgresql7.1 select my_view.group_name, my_view.group_id from (select DISTINCT g.group_name, g.group_id from acs_objects o, groups g, application_group_element_map app_group, all_object_party_privilege_map perm where perm.object_id = g.group_id and perm.party_id = :user_id and perm.privilege = 'read' and g.group_id = o.object_id and o.object_type = :group_type and app_group.package_id = :package_id and app_group.element_id = g.group_id order by g.group_name, g.group_id) my_view limit 26 select a.attribute_id, a.pretty_name, a.ancestor_type, t.pretty_name as ancestor_pretty_name from acs_object_type_attributes a, (select t2.object_type, t2.pretty_name, tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey) + 1 as type_level from acs_object_types t1, acs_object_types t2 where t1.object_type = 'group' and t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey)) t where a.object_type = :group_type and t.object_type = a.ancestor_type order by type_level openacs-5.7.0/packages/acs-subsite/www/admin/group-types/new-oracle.xql0000644000175000017500000000115507300260124025763 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end from dual select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy-oracle.xql0000644000175000017500000000073607300260124030655 0ustar frankiefrankie oracle8.1.6 select t.pretty_name as group_type_pretty_name, t.dynamic_p, nvl(gt.default_join_policy, 'open') as default_join_policy from acs_object_types t, group_types gt where t.object_type = :group_type and t.object_type = gt.group_type(+) openacs-5.7.0/packages/acs-subsite/www/admin/group-types/new.adp0000644000175000017500000000036011552027564024472 0ustar frankiefrankie @context;noquote@ @doc.title@ group_type.object_type

    @doc.title@

    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/new.tcl0000644000175000017500000000661411552027564024520 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/add.tcl ad_page_contract { Form to add a group type @author rhs@mit.edu @creation-date 2000-12-04 @cvs-id $Id: new.tcl,v 1.5 2011/04/15 11:43:48 emmar Exp $ } { { object_type:trim "" } { pretty_name:trim "" } { pretty_plural:trim "" } { supertype:trim "" } { approval_policy:trim "" } } -properties { context:onevalue } set doc(title) [_ acs-subsite.Add_group_type] set context [list [list "[ad_conn package_url]admin/group-types/" [_ acs-subsite.Group_Types]] [_ acs-subsite.Add_type]] template::form create group_type template::element create group_type object_type \ -datatype "text" \ -label "[_ acs-subsite.Group_type]" \ -html { size 30 maxlength 30 } set supertype_options [db_list_of_lists "select_group_supertypes" { select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name, t.object_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type = 'group'}] foreach opt $supertype_options { lappend supertype_options_i18n [lang::util::localize $opt] } template::element create group_type supertype \ -datatype "text" \ -widget select \ -options $supertype_options_i18n \ -label "[_ acs-subsite.Supertype]" template::element create group_type pretty_name \ -datatype "text" \ -label "[_ acs-subsite.Pretty_name]" \ -html { size 50 maxlength 100 } template::element create group_type pretty_plural \ -datatype "text" \ -label "[_ acs-subsite.Pretty_plural]" \ -html { size 50 maxlength 100 } set approval_policy_options { { {Open: Users can create groups of this type} open } { {Wait: Users can suggest groups} wait } { {Closed: Only administrators can create groups} closed } } if { [template::form is_valid group_type] } { set exception_count 0 # Verify that the object type (in safe oracle format) is unique set safe_object_type [plsql_utility::generate_oracle_name -max_length 29 $object_type] if { [plsql_utility::object_type_exists_p $safe_object_type] } { incr exception_count append exception_text "
  • The specified object type, $object_type, already exists. [ad_decode $safe_object_type $object_type "" "Note that we converted the object type to \"$safe_object_type\" to ensure that the name would be safe for the database."] Please back up and choose another.
  • " } else { # let's make sure the names are unique if { [db_string pretty_name_unique { select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end from dual }] } { incr exception_count append exception_text "
  • The specified pretty name, $pretty_name, already exists. Please enter another
  • " } if { [db_string pretty_name_unique { select case when exists (select 1 from acs_object_types t where t.pretty_plural = :pretty_plural) then 1 else 0 end from dual }] } { incr exception_count append exception_text "
  • The specified pretty plural, $pretty_plural, already exists. Please enter another
  • " } } if { $exception_count > 0 } { ad_return_complaint $exception_count $exception_text ad_script_abort } db_transaction { group_type::new -group_type $object_type -supertype $supertype $pretty_name $pretty_plural } ad_returnredirect "" return } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add-2.tcl0000644000175000017500000000323011452447070026341 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/group-types/rel-type-add-2.tcl ad_page_contract { Adds the relationship type to the list of allowable ones for this group type= @author mbryzek@arsdigita.com @creation-date Sun Dec 10 16:57:10 2000 @cvs-id $Id: rel-type-add-2.tcl,v 1.3 2010/10/04 21:59:20 victorg Exp $ } { group_type:trim,notnull rel_type:trim,notnull { return_url "" } } -validate { rel_type_acceptable_p -requires {group_type:notnull rel_type:notnull} { # This test makes sure this group_type can accept the # specified rel type. This means the group type is itself a # type (or subtype) of rel_type.object_type_one if { ![db_string types_match_p { select count(*) from acs_rel_types t where (t.object_type_one = :group_type or acs_object_type.is_subtype_p(t.object_type_one, :group_type) = 't') and t.rel_type = :rel_type }] } { ad_complain "Groups of type \"$group_type\" cannot use relationships of type \"$rel_type.\"" } } } if { [catch { set group_rel_type_id [db_nextval acs_object_id_seq] db_dml insert_rel_type { insert into group_type_rels (group_rel_type_id, group_type, rel_type) values (:group_rel_type_id, :group_type, :rel_type) } } err_msg] } { # Does this pair already exists? if { ![db_string exists_p {select count(*) from group_type_rels where group_type = :group_type and rel_type = :rel_type}] } { ad_return_error "Error inserting to database" $err_msg return } } db_release_unused_handles if { $return_url eq "" } { set return_url "one?[ad_export_vars {group_type}]" } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add-2.xql0000644000175000017500000000035007300260124026351 0ustar frankiefrankie select count(*) from group_type_rels where group_type = :group_type and rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-remove.adp0000644000175000017500000000076407663154723026753 0ustar frankiefrankie @context;noquote@ Remove @rel_pretty_name;noquote@ Are you sure you want to remove @rel_pretty_name@ from the list of allowable relations for groups of type @group_type_pretty_name@?

    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-remove.tcl0000644000175000017500000000225607536221406026757 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/group-types/rel-type-remove.tcl ad_page_contract { Confirmation to remove an allowable relation type @author mbryzek@arsdigita.com @creation-date Sun Dec 10 16:40:11 2000 @cvs-id $Id: rel-type-remove.tcl,v 1.3 2002/09/06 21:49:58 jeffd Exp $ } { group_rel_type_id:naturalnum,notnull { return_url "" } } -properties { context:onevalue rel_pretty_name:onevalue group_type_pretty_name:onevalue export_vars:onevalue } if { ![db_0or1row select_info { select g.rel_type, g.group_type, t.pretty_name as rel_pretty_name, t2.pretty_name as group_type_pretty_name from acs_object_types t, acs_object_types t2, group_type_rels g where g.group_rel_type_id = :group_rel_type_id and t.object_type = g.rel_type and t2.object_type = g.group_type }] } { ad_return_error "Relation already removed." "Please back up and reload" return } set export_vars [ad_export_vars -form {group_rel_type_id return_url}] set context [list [list "[ad_conn package_url]admin/group-types/" "Group types"] [list one?[ad_export_vars {group_type}] "One type"] "Remove relation type"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-remove.xql0000644000175000017500000000072507300260124026765 0ustar frankiefrankie select g.rel_type, g.group_type, t.pretty_name as rel_pretty_name, t2.pretty_name as group_type_pretty_name from acs_object_types t, acs_object_types t2, group_type_rels g where g.group_rel_type_id = :group_rel_type_id and t.object_type = g.rel_type and t2.object_type = g.group_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/index-postgresql.xql0000644000175000017500000000231707403013337027246 0ustar frankiefrankie postgresql7.1 select t.object_type as group_type, t.pretty_plural, coalesce(num.number_groups,0) as number_groups, repeat(' ', t.type_level * 4) as indent from (select t2.object_type, t2.pretty_plural, t2.tree_sortkey, tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey) as type_level from acs_object_types t1, acs_object_types t2 where t1.object_type = 'group' and t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey)) t left outer join (select o.object_type, count(*) as number_groups from groups g, acs_objects o, application_group_element_map app_group where acs_permission__permission_p(g.group_id, :user_id, 'read') and o.object_id = g.group_id and app_group.package_id = :package_id and app_group.element_id = g.group_id group by o.object_type) num using (object_type) order by t.tree_sortkey openacs-5.7.0/packages/acs-subsite/www/admin/group-types/index.adp0000644000175000017500000000115611552027564025014 0ustar frankiefrankie @doc.title@ @context;noquote@

    @doc.title@

    #acs-subsite.Currently_the_system_is#:

    • #acs-subsite.none#
    • @group_types.indent;noquote@@group_types.pretty_plural@ (#acs-subsite.number_of_groups_defined#: @group_types.number_groups@)

    #acs-subsite.Define_a_new_group_type#

    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/index.tcl0000644000175000017500000000353711552027564025037 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/one.tcl ad_page_contract { Display all types of groups for this subsite @author mbryzek@arsdigita.com @creation-date 2000-11-06 @cvs-id $Id: index.tcl,v 1.4 2011/04/15 11:43:48 emmar Exp $ } { } -properties { context:onevalue group_types:multirow } set doc(title) [_ acs-subsite.Group_type_administration] set context [list [_ acs-subsite.Group_Types]] # we may want to move the inner count to get the number of groups of # each type to its own pl/sql function. That way, we execute the # function once for each group type, a number much smaller than the # number of objects in the system. set user_id [ad_conn user_id] set package_id [ad_conn package_id] db_multirow group_types select_group_types { select t.object_type as group_type, t.pretty_plural, nvl(num.number_groups,0) as number_groups, t.indent from (select t.object_type, t.pretty_plural, rownum as inner_rownum, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type = 'group' order by lower(t.pretty_plural)) t, (select o.object_type, count(*) number_groups from groups g, acs_objects o, acs_object_party_privilege_map perm, application_group_element_map app_group where perm.object_id = g.group_id and perm.party_id = :user_id and perm.privilege = 'read' and o.object_id = g.group_id and app_group.package_id = :package_id and app_group.element_id = g.group_id group by o.object_type) num where t.object_type = num.object_type(+) order by t.inner_rownum } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy-2-oracle.xql0000644000175000017500000000070207300260124031005 0ustar frankiefrankie oracle8.1.6 select t.dynamic_p, case when gt.group_type = null then 0 else 1 end as group_type_exists_p from acs_object_types t, group_types gt where t.object_type = :group_type and t.object_type = gt.group_type(+) openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-2-oracle.xql0000644000175000017500000000257207340303237026606 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from user_objects o where o.object_type='PACKAGE' and o.object_name = upper(:package_name)) then 1 else 0 end from dual select case when exists (select 1 from acs_object_types t where t.object_type = :group_type) then 1 else 0 end from dual drop package [DoubleApos $group_type] delete from group_type_rels where group_type = :group_type begin acs_object_type.drop_type(:group_type); end; drop table $table_name begin delete from group_types where group_type=:group_type; end; openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add-postgresql.xql0000644000175000017500000000211207403013337030417 0ustar frankiefrankie postgresql7.1 select repeat(' ', (t.type_level - 1) * 4) as indent, t.pretty_name, t.rel_type from (select t2.pretty_name, t2.object_type as rel_type, tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey) + 1 as type_level from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t2.object_type not in (select g.rel_type from group_type_rels g where g.group_type = :group_type) and t1.object_type in ('membership_rel', 'composition_rel')) t, acs_rel_types rel_type where t.rel_type = rel_type.rel_type and (rel_type.object_type_one = :group_type or acs_object_type__is_subtype_p(rel_type.object_type_one, :group_type) = 't') openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add-oracle.xql0000644000175000017500000000177007300260124027464 0ustar frankiefrankie oracle8.1.6 select replace(lpad(' ', (t.type_level - 1) * 4), ' ', ' ') as indent, t.pretty_name, t.rel_type from (select t.pretty_name, t.object_type as rel_type, level as type_level from acs_object_types t where t.object_type not in (select g.rel_type from group_type_rels g where g.group_type = :group_type) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel', 'composition_rel')) t, acs_rel_types rel_type where t.rel_type = rel_type.rel_type and (rel_type.object_type_one = :group_type or acs_object_type.is_subtype_p(rel_type.object_type_one, :group_type) = 't') openacs-5.7.0/packages/acs-subsite/www/admin/group-types/one.adp0000644000175000017500000000476011552027564024472 0ustar frankiefrankie @context;noquote@ @doc.title@

    @doc.title@

    #acs-subsite.Groups_of_this_type#

    #acs-subsite.Attributes_of_this_type_of_group#

    #acs-subsite.Default_allowed_relationship_types#

    #acs-subsite.You_can_specify_the_default_types_of#

    #acs-subsite.Administration#

    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/one.tcl0000644000175000017500000000714111552027564024504 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/one.tcl ad_page_contract { Shows summary information about one group type @author mbryzek@arsdigita.com @creation-date Wed Nov 8 18:02:15 2000 @cvs-id $Id: one.tcl,v 1.5 2011/04/15 11:43:48 emmar Exp $ } { group_type:notnull } -properties { context:onevalue group_type:onevalue group_type_enc:onevalue group_type_pretty_name:onevalue groups:multirow attributes:multirow allowed_relations:multirow return_url:onevalue dynamic_p:onevalue more_relation_types_p:onevalue } set user_id [ad_conn user_id] set return_url_enc [ad_urlencode [ad_conn url]?[ad_conn query]] set group_type_enc [ad_urlencode $group_type] set package_id [ad_conn package_id] if { ![db_0or1row select_pretty_name { select t.pretty_name as group_type_pretty_name, t.dynamic_p, nvl(gt.default_join_policy, 'open') as default_join_policy from acs_object_types t, group_types gt where t.object_type = :group_type and t.object_type = gt.group_type(+) }] } { ad_return_error "Group type doesn't exist" "Group type \"$group_type\" doesn't exist" return } set doc(title) [_ acs-subsite.Details_for__group_type_pretty_name] set context [list [list "[ad_conn package_url]admin/group-types/" [_ acs-subsite.Group_Types]] $group_type_pretty_name] # Pull out the first 25 groups of this type. If there are more, we'll # offer a link to display them all. Alphabetize the first 25 groups db_multirow groups groups_select { select my_view.group_name, my_view.group_id, rownum as num from (select /*+ ORDERED */ DISTINCT g.group_name, g.group_id from acs_objects o, groups g, application_group_element_map app_group, all_object_party_privilege_map perm where perm.object_id = g.group_id and perm.party_id = :user_id and perm.privilege = 'read' and g.group_id = o.object_id and o.object_type = :group_type and app_group.package_id = :package_id and app_group.element_id = g.group_id order by lower(g.group_name)) my_view where rownum <= 26 } # Select out all the attributes for groups of this type db_multirow -extend {one_attribute_url} attributes attributes_select { select a.attribute_id, a.pretty_name, a.ancestor_type, t.pretty_name as ancestor_pretty_name from acs_object_type_attributes a, (select t.object_type, t.pretty_name, level as type_level from acs_object_types t start with t.object_type='group' connect by prior t.object_type = t.supertype) t where a.object_type = :group_type and t.object_type = a.ancestor_type order by type_level } { set one_attribute_url [export_vars -url -base "../attributes/one" {attribute_id {return_url $return_url_enc}}] } # Select out all the allowed relationship types db_multirow allowed_relations relations_select { select t.pretty_name, g.rel_type, g.group_rel_type_id from acs_object_types t, group_type_rels g where t.object_type = g.rel_type and g.group_type = :group_type order by lower(t.pretty_name) } # See if we need to offer a link to add a rel type set more_relation_types_p [rel_types::additional_rel_types_p -group_type $group_type] set add_group_url [export_vars -url -base "../parties/new" {{party_type $group_type} {add_with_rel_type composition_rel} {return_url $return_url_enc}}] set add_attribute_url [export_vars -url -base "../attributes/add" {{object_type $group_type} {return_url $return_url_enc}}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/one.xql0000644000175000017500000000137207300260124024511 0ustar frankiefrankie select t.pretty_name as group_type_pretty_name, t.dynamic_p, coalesce(gt.default_join_policy, 'open') as default_join_policy from acs_object_types t left outer join group_types gt on (t.object_type = gt.group_type) where t.object_type = :group_type select t.pretty_name, g.rel_type, g.group_rel_type_id from acs_object_types t, group_type_rels g where t.object_type = g.rel_type and g.group_type = :group_type order by lower(t.pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/group-types/index-oracle.xql0000644000175000017500000000242507300260124026302 0ustar frankiefrankie oracle8.1.6 select t.object_type as group_type, t.pretty_plural, nvl(num.number_groups,0) as number_groups, t.indent from (select t.object_type, t.pretty_plural, rownum as inner_rownum, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type = 'group' order by lower(t.pretty_plural)) t, (select o.object_type, count(*) number_groups from groups g, acs_objects o, acs_object_party_privilege_map perm, application_group_element_map app_group where perm.object_id = g.group_id and perm.party_id = :user_id and perm.privilege = 'read' and o.object_id = g.group_id and app_group.package_id = :package_id and app_group.element_id = g.group_id group by o.object_type) num where t.object_type = num.object_type(+) order by t.inner_rownum openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete.adp0000644000175000017500000000132407663154723025152 0ustar frankiefrankie @context;noquote@ Delete @group_type_pretty_name;noquote@
    • Remove the "@group_type_pretty_name@" group type
    • Remove all the groups of this type (of which there are currently @groups_of_this_type@), including any relational segments and constraints defined on those groups
    • Remove all the relations for groups of this type (of which there are currently @relations_to_this_type@)

    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete.tcl0000644000175000017500000000726507536221406025172 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/group-types/delete.tcl ad_page_contract { Confirms deletion of a group type @author mbryzek@arsdigita.com @creation-date Wed Nov 8 18:22:04 2000 @cvs-id $Id: delete.tcl,v 1.3 2002/09/06 21:49:58 jeffd Exp $ } { group_type:notnull { return_url "" } } -properties { subtypes:multirow context:onevalue export_url_vars:onevalue export_form_vars:onevalue group_type:onevalue group_type_pretty_name:onevalue groups_of_this_type:onevalue relations_to_this_type:onevalue } -validate { user_can_delete_type -requires {group_type:notnull} { if { ![group_type::drop_all_groups_p $group_type] } { ad_complain "Groups exist that you do not have permission to delete. All groups must be deleted before you can remove a group type. Please contact the site administrator." } } } set context [list \ [list "[ad_conn package_url]admin/group-types/" "Group types"] \ [list one?[export_url_vars group_type] "One group type"] \ "Delete group type"] if { ![db_0or1row select_pretty_name { select t.pretty_name as group_type_pretty_name from acs_object_types t where t.object_type = :group_type }] } { ad_return_error "Group type doesn't exist" "Group type \"$group_type\" doesn't exist" return } set subtypes_exist_p [db_string number_subtypes { select case when exists (select 1 from acs_object_types t where t.supertype = :group_type) then 1 else 0 end from dual }] if { $subtypes_exist_p } { set return_url "[ad_conn url]?[ad_conn query]" # Just grab direct children... template::multirow create subtypes pretty_name export_vars db_foreach select_subtypes { select t.object_type as group_type, t.pretty_name from acs_object_types t where t.supertype = :group_type } { template::multirow append subtypes $pretty_name [ad_export_vars {group_type return_url}] } ad_return_template "delete-subtypes-exist" return } # Now let's check if any relationship types depend on this group type set rel_types_depend_p [db_string rel_type_exists_p { select case when exists (select 1 from acs_rel_types t where t.object_type_one = :group_type or t.object_type_two = :group_type) then 1 else 0 end from dual }] if { $rel_types_depend_p } { set return_url "[ad_conn url]?[ad_conn query]" # Grab the rel types that depend on this one template::multirow create rel_types pretty_name export_vars db_foreach select_rel_types { select rel.rel_type, t.pretty_name from acs_rel_types rel, acs_object_types t where (rel.object_type_one = :group_type or rel.object_type_two = :group_type) and rel.rel_type = t.object_type } { template::multirow append rel_types $pretty_name [ad_export_vars {rel_type return_url}] } ad_return_template "delete-rel-types-exist" return } set export_form_vars [ad_export_vars -form {group_type return_url}] set groups_of_this_type [util_commify_number [db_string groups_of_this_type { select count(o.object_id) from acs_objects o where o.object_type = :group_type }]] set relations_to_this_type [util_commify_number [db_string relations_to_this_type { select count(r.rel_id) from acs_rels r where r.rel_type in (select t.rel_type from acs_rel_types t where t.object_type_one = :group_type or t.object_type_two = :group_type) }]] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete.xql0000644000175000017500000000262007300260124025167 0ustar frankiefrankie select t.pretty_name as group_type_pretty_name from acs_object_types t where t.object_type = :group_type select t.object_type as group_type, t.pretty_name from acs_object_types t where t.supertype = :group_type select rel.rel_type, t.pretty_name from acs_rel_types rel, acs_object_types t where (rel.object_type_one = :group_type or rel.object_type_two = :group_type) and rel.rel_type = t.object_type select count(o.object_id) from acs_objects o where o.object_type = :group_type select count(r.rel_id) from acs_rels r where r.rel_type in (select t.rel_type from acs_rel_types t where t.object_type_one = :group_type or t.object_type_two = :group_type) openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add.adp0000644000175000017500000000201011552027564026162 0ustar frankiefrankie @context;noquote@ @doc.title@

    #acs-subsite.Add_relationship_for_group__group_type#

    There are no other relationship types that you can add. You can create a new relationship type if you like.

    @export_vars;noquote@

    #acs-subsite.create_a_new_relationship_type#

    openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add.tcl0000644000175000017500000000414711552027564026215 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/group-types/rel-type-add.tcl ad_page_contract { Shows list of available rel types to add for this group type @author mbryzek@arsdigita.com @creation-date Sun Dec 10 16:50:58 2000 @cvs-id $Id: rel-type-add.tcl,v 1.4 2011/04/15 11:43:48 emmar Exp $ } { group_type:trim,notnull { return_url "" } } -properties { context:onevalue return_url_enc:onevalue export_vars:onevalue primary_rels:multirow } set return_url_enc [ad_urlencode "[ad_conn url]?[ad_conn query]"] set doc(title) [_ acs-subsite.Add_a_permissible_relationship_type] set context [list [list "[ad_conn package_url]admin/group-types/" [_ acs-subsite.Group_Types]] [list one?[ad_export_vars {group_type}] $group_type] $doc(title)] # Select out all the relationship types that are not currently # specified for this group type. Note that we use acs_object_types so # that we can probably indent subtypes. We use acs_rel_types to ensure # that the passed in group type is acceptable for object_type_one of # the relationship type. Acceptable means equal to or a child of the # rel type. If you can find a more efficient way to do this query, # please let us know! -mbryzek db_multirow primary_rels select_primary_relations { select replace(lpad(' ', (t.type_level - 1) * 4), ' ', ' ') as indent, t.pretty_name, t.rel_type from (select t.pretty_name, t.object_type as rel_type, level as type_level from acs_object_types t where t.object_type not in (select g.rel_type from group_type_rels g where g.group_type = :group_type) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel', 'composition_rel')) t, acs_rel_types rel_type where t.rel_type = rel_type.rel_type and (rel_type.object_type_one = :group_type or acs_object_type.is_subtype_p(rel_type.object_type_one, :group_type) = 't') } set export_vars [ad_export_vars -form {group_type return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-display.adp0000644000175000017500000000047107663154723026674 0ustar frankiefrankie @context;noquote@ All groups of type @group_type_pretty_name;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-display.tcl0000644000175000017500000000163007536221406026700 0ustar frankiefrankie# /packages/acs-subsite/www/admin/group-types/groups-display.tcl ad_page_contract { Shows elements for a group @author mbryzek@arsdigita.com @creation-date Mon Jan 8 16:31:12 2001 @cvs-id $Id: groups-display.tcl,v 1.3 2002/09/06 21:49:58 jeffd Exp $ } { group_type:notnull } -properties { context:onevalue group_type_pretty_name:onevalue group_type:onevalue group_type_enc:onevalue } set user_id [ad_conn user_id] set context [list [list "[ad_conn package_url]admin/group-types/" "Group types"] [list one?[ad_export_vars group_type] "One type"] "Groups"] set group_type_enc [ad_urlencode $group_type] if { ![db_0or1row select_type_info { select t.pretty_name as group_type_pretty_name from acs_object_types t where t.object_type = :group_type }] } { ad_return_error "Error" "Group type, $group_type, does not exist" ad_script_abort } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/group-types/groups-display.xql0000644000175000017500000000041507300260124026707 0ustar frankiefrankie select t.pretty_name as group_type_pretty_name from acs_object_types t where t.object_type = :group_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/rel-type-add-2-oracle.xql0000644000175000017500000000066607300260124027626 0ustar frankiefrankie oracle8.1.6 select count(*) from acs_rel_types t where (t.object_type_one = :group_type or acs_object_type.is_subtype_p(t.object_type_one, :group_type) = 't') and t.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-oracle.xql0000644000175000017500000000144107300260124026432 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_object_types t where t.supertype = :group_type) then 1 else 0 end from dual select case when exists (select 1 from acs_rel_types t where t.object_type_one = :group_type or t.object_type_two = :group_type) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-postgresql.xql0000644000175000017500000000142107300260124027366 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_object_types t where t.supertype = :group_type) then 1 else 0 end select case when exists (select 1 from acs_rel_types t where t.object_type_one = :group_type or t.object_type_two = :group_type) then 1 else 0 end openacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy-2.tcl0000644000175000017500000000244510551254376027544 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/one.tcl ad_page_contract { Change default join policy for a group type. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2001-02-23 @cvs-id $Id: change-join-policy-2.tcl,v 1.2 2007/01/10 21:22:06 gustafn Exp $ } { group_type:notnull default_join_policy:notnull {return_url ""} } if { ![db_0or1row select_pretty_name { select t.dynamic_p, decode(gt.group_type, null, 0, 1) as group_type_exists_p from acs_object_types t, group_types gt where t.object_type = :group_type and t.object_type = gt.group_type(+) }] } { ad_return_error "Group type doesn't exist" "Group type \"$group_type\" doesn't exist" return } if {$dynamic_p ne "t" } { ad_return_error "Cannot administer group type" "Group type \"$group_type\" can only be administered by programmers" } if {!$group_type_exists_p} { db_dml set_default_join_policy { insert into group_types (group_type, default_join_policy) values (:group_type, :default_join_policy) } } else { db_dml update_join_policy { update group_types set default_join_policy = :default_join_policy where group_type = :group_type } } if {$return_url eq ""} { set return_url one?[ad_export_vars group_type] } ad_returnredirect $return_urlopenacs-5.7.0/packages/acs-subsite/www/admin/group-types/change-join-policy-2.xql0000644000175000017500000000145707341276557027600 0ustar frankiefrankie select t.dynamic_p, case when gt.group_type = null then 0 else 1 end as group_type_exists_p from acs_object_types t left outer join group_types gt on (t.object_type = gt.group_type) where t.object_type = :group_type insert into group_types (group_type, default_join_policy) values (:group_type, :default_join_policy) update group_types set default_join_policy = :default_join_policy where group_type = :group_type openacs-5.7.0/packages/acs-subsite/www/admin/group-types/one-oracle.xql0000644000175000017500000000341107443753715025775 0ustar frankiefrankie oracle8.1.6 select t.pretty_name as group_type_pretty_name, t.dynamic_p, nvl(gt.default_join_policy, 'open') as default_join_policy from acs_object_types t, group_types gt where t.object_type = :group_type and t.object_type = gt.group_type(+) select my_view.group_name, my_view.group_id from (select /*+ ORDERED */ DISTINCT g.group_name, g.group_id from acs_objects o, groups g, application_group_element_map app_group, all_object_party_privilege_map perm where perm.object_id = g.group_id and perm.party_id = :user_id and perm.privilege = 'read' and g.group_id = o.object_id and o.object_type = :group_type and app_group.package_id = :package_id and app_group.element_id = g.group_id order by lower(g.group_name)) my_view where rownum <= 26 select a.attribute_id, a.pretty_name, a.ancestor_type, t.pretty_name as ancestor_pretty_name from acs_object_type_attributes a, (select t.object_type, t.pretty_name, level as type_level from acs_object_types t start with t.object_type='group' connect by prior t.object_type = t.supertype) t where a.object_type = :group_type and t.object_type = a.ancestor_type order by type_level openacs-5.7.0/packages/acs-subsite/www/admin/group-types/delete-2-postgresql.xql0000644000175000017500000000256007340303237027541 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from pg_proc where proname like :package_name || '%') then 1 else 0 end select case when exists (select 1 from acs_object_types t where t.object_type = :group_type) then 1 else 0 end select drop_package('[DoubleApos $group_type]') begin delete from group_type_rels where group_type = :group_type; return 1; end; select acs_object_type__drop_type(:group_type, 'f') begin drop table $table_name; return 1; end; begin delete from group_types where group_type=:group_type; return 1; end; openacs-5.7.0/packages/acs-subsite/www/admin/site-map/0000755000175000017500000000000011724401447022432 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/site-map/unmounted.adp0000644000175000017500000000227210214660366025141 0ustar frankiefrankie @page_title@ @context@ The following application packages are not mounted anywhere. You can delete an unmounted package by clicking the "delete" option.
    • @packages_normal.name@ [delete]
    • There are no unmounted packages
    The following services are singleton packages and are usually not meant to be mounted anywhere. Be careful not to delete a service that is in use as this can potentially break the system.
    • @packages_singleton.name@ [delete]
    • There are no unmounted singleton packages
    openacs-5.7.0/packages/acs-subsite/www/admin/site-map/unmounted.tcl0000644000175000017500000000122110214660345025145 0ustar frankiefrankiead_page_contract { Display all readable unmounted packages @author bquinn@arsdigita.com @creation-date 2000-09-12 @cvs-id $Id: unmounted.tcl,v 1.6 2005/03/12 21:36:37 michaels Exp $ } set page_title "Unmounted Packages" set context [list [list "." "Site Map"] $page_title] set user_id [ad_conn user_id] db_multirow -extend {instance_delete_url} packages_normal packages_normal_select {} { set instance_delete_url [export_vars -base instance-delete package_id] } db_multirow -extend {instance_delete_url} packages_singleton packages_singleton_select {} { set instance_delete_url [export_vars -base instance-delete package_id] } openacs-5.7.0/packages/acs-subsite/www/admin/site-map/mount.adp0000644000175000017500000000214707663155231024272 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    Please select one of the following packages to mount on @site_node_url@.

    These package instances are not mounted anywhere else:

    These instances are already mounted elsewhere. Selecting one of them will create an additional location for the same application:

    These packages are centralized services and are probably not meant to be mounted anywhere:

    openacs-5.7.0/packages/acs-subsite/www/admin/site-map/mount.tcl0000644000175000017500000000163307661404152024304 0ustar frankiefrankie# packages/acs-core-ui/www/admin/site-nodes/mount.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-09-12 @cvs-id $Id: mount.tcl,v 1.3 2003/05/17 10:01:14 jeffd Exp $ } { node_id:integer,notnull {expand:integer,multiple {}} root_id:integer,optional } set user_id [ad_conn user_id] set page_title "Mount A Package Instance" set context [list [list . "Site Map"] $page_title] set site_node_url [site_node::get_url -node_id $node_id] db_multirow -extend { url } unmounted packages_unmounted_select {} { set url "mount-2?[export_vars { expand:multiple root_id node_id package_id }]" } db_multirow -extend { url } mounted packages_mounted_select {} { set url "mount-2?[export_vars { expand:multiple root_id node_id package_id}]" } db_multirow -extend { url } singleton packages_singleton_select {} { set url "mount-2?[export_vars { expand:multiple root_id node_id package_id}]" } openacs-5.7.0/packages/acs-subsite/www/admin/site-map/package-new.tcl0000644000175000017500000000524610551254400025317 0ustar frankiefrankie# packages/acs-core-ui/www/admin/site-nodes/package-new.tcl ad_page_contract { Create a new package and mount it in the site map. If new_node_p is false then the package will be mounted at node_id. If new_node_p is true then a new node with name node_name will be created under root_id and the package will be mounted there. @author rhs@mit.edu @creation-date 2000-09-13 @cvs-id $Id: package-new.tcl,v 1.12 2007/01/10 21:22:08 gustafn Exp $ } { {new_package_id:integer ""} node_id:integer,notnull {new_node_p f} {node_name:trim ""} {instance_name ""} package_key:notnull {expand:integer,multiple ""} root_id:integer,optional } if {$package_key eq "/new"} { ad_returnredirect "/acs-admin/apm/packages-install" ad_script_abort } if { $instance_name eq "" } { set instance_name [db_string instance_default_name "select pretty_name from apm_package_types where package_key = :package_key"] } db_transaction { # Set the context_id to the object_id of the parent node # If the parent node didn't have anything mounted, use the current package_id as context_id set context_id [ad_conn package_id] array set node [site_node::get -node_id $node_id] if { $node(object_id) ne "" } { set context_id $node(object_id) } if { $new_node_p } { # Create a new node under node_id and mount the package there set package_id [site_node::instantiate_and_mount -package_id $new_package_id \ -package_key $package_key \ -parent_node_id $node_id \ -package_name $instance_name \ -context_id $context_id \ -node_name $node_name] } else { # Mount the new package at node_id set package_id [site_node::instantiate_and_mount -package_id $new_package_id \ -package_key $package_key \ -node_id $node_id \ -package_name $instance_name \ -context_id $context_id ] } } on_error { if {![db_string package_new_doubleclick_ck {} -default 0]} { ad_return_complaint 1 "Error Creating Package: The following error was generated when attempting to create the package
    		[ad_quotehtml $errmsg]
    	
    " } } ad_returnredirect ".?[export_url_vars expand:multiple root_id]" openacs-5.7.0/packages/acs-subsite/www/admin/site-map/package-new.xql0000644000175000017500000000044507504674661025360 0ustar frankiefrankie select case when count(*) = 0 then 0 else 1 end from apm_packages where package_id = :new_package_id openacs-5.7.0/packages/acs-subsite/www/admin/site-map/mount-oracle.xql0000644000175000017500000000720310501274250025557 0ustar frankiefrankie oracle8.1.6 select p.package_id, p.instance_name as name, pt.pretty_name as package_pretty_name from apm_packages p, apm_package_types pt, apm_package_versions v where pt.package_key = p.package_key and v.package_key = pt.package_key and (v.installed_p = 't' or v.enabled_p = 't' or not exists ( select 1 from apm_package_versions v2 where v2.package_key = v.package_key and (v2.installed_p = 't' or v2.enabled_p = 't') and apm_package_version.sortable_version_name(v2.version_name) > apm_package_version.sortable_version_name(v.version_name))) and ( acs_permission.permission_p(package_id, :user_id, 'read') = 't' or acs_permission.permission_p(package_id, acs.magic_object_id('the_public'), 'read') = 't' ) and (apm_package.singleton_p(p.package_key) = 0 or v.auto_mount is not null) and not exists (select 1 from site_nodes where object_id = p.package_id) order by name select p.package_id, acs_object.name(p.package_id) as name, pt.pretty_name as package_pretty_name from apm_packages p, apm_package_types pt where pt.package_key = p.package_key and ( acs_permission.permission_p(package_id, :user_id, 'read') = 't' or acs_permission.permission_p(package_id, acs.magic_object_id('the_public'), 'read') = 't' ) and exists (select 1 from site_nodes where object_id = p.package_id) order by name select p.package_id, acs_object.name(p.package_id) as name, pt.pretty_name as package_pretty_name from apm_packages p, apm_package_types pt, apm_package_versions v where pt.package_key = p.package_key and v.package_key = pt.package_key and (v.installed_p = 't' or v.enabled_p = 't' or not exists ( select 1 from apm_package_versions v2 where v2.package_key = v.package_key and (v2.installed_p = 't' or v2.enabled_p = 't') and apm_package_version.sortable_version_name(v2.version_name) > apm_package_version.sortable_version_name(v.version_name))) and ( acs_permission.permission_p(package_id, :user_id, 'read') = 't' or acs_permission.permission_p(package_id, acs.magic_object_id('the_public'), 'read') = 't' ) and (apm_package.singleton_p(p.package_key) = 1 and v.auto_mount is null) and not exists (select 1 from site_nodes where object_id = p.package_id) order by name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/unmount.tcl0000644000175000017500000000061607537470223024653 0ustar frankiefrankie# packages/acs-core-ui/www/admin/site-nodes/unmount.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-09-12 @cvs-id $Id: unmount.tcl,v 1.3 2002/09/10 22:22:11 jeffd Exp $ } { node_id:integer,notnull {expand:integer,multiple ""} root_id:integer,optional } site_node::unmount -node_id $node_id ad_returnredirect ".?[export_url_vars expand:multiple root_id]" openacs-5.7.0/packages/acs-subsite/www/admin/site-map/instance-delete.tcl0000644000175000017500000000364210551254400026177 0ustar frankiefrankiead_page_contract { Delete a package instance. If the package is mounted it will be unmounted before deletion and an attempt will be made to delete the node. @author Bryan Quinn (bquinn@arsdigita.com) @creation-date Mon Oct 23 14:58:57 2000 @cvs-id $Id: instance-delete.tcl,v 1.9 2007/01/10 21:22:08 gustafn Exp $ } { package_id:naturalnum {root_id ""} } db_transaction { # DRB: There used to be a "catch" around the "set" but I removed it because # 1. blank is returned if no node_id exists for the object # 2. the following "if" would throw an error if the "catch" caught anything ... set node_id [site_node::get_node_id_from_object_id -object_id $package_id] # DRB: This is a small trick. If you mount subsite "foo", visit its sitemap page # and delete it, you got an error when the code attempted to return. So this code # will go to the deleted node's parent page which should either be the site map page # you were at when you clicked "delete" or its parent (the case mentioned above). set parent \ [site_node::closest_ancestor_package \ -node_id $node_id \ -package_key acs-subsite \ -element url] # node_id was null so we're not deleting a mounted subsite instance if {$parent eq "" } { set parent [ad_conn subsite_url] } if { $node_id ne "" } { # The package is mounted site_node::unmount -node_id $node_id site_node::delete -node_id $node_id } # Delete the package apm_package_instance_delete $package_id } on_error { if {[db_string instance_delete_doubleclick_ck { select decode(count(*), 0, 0, 1) from apm_packages where package_id = :package_id } -default 0]} { ad_return_error "Error Deleting Instance" "The following error was returned:
    [ad_quotehtml $errmsg]
    " } } ad_returnredirect ${parent}admin/site-map openacs-5.7.0/packages/acs-subsite/www/admin/site-map/instance-delete.xql0000644000175000017500000000105407504674661026237 0ustar frankiefrankie select case when count(*) = 0 then 0 else 1 end from apm_packages p, site_nodes s where package_id = :package_id and p.package_id = s.object_id select case when count(*) = 0 then 0 else 1 end from apm_packages where package_id = :package_id openacs-5.7.0/packages/acs-subsite/www/admin/site-map/site-map-postgresql.xql0000644000175000017500000000730610171476745027116 0ustar frankiefrankie postgresql7.1 select s2.node_id, s2.name, s2.directory_p, tree_level(s2.tree_sortkey) as level, acs_object__name(s2.object_id) as obj_name, acs_permission__permission_p(s2.object_id, :user_id, 'admin') as admin_p from (select tree_ancestor_keys(site_node_get_tree_sortkey(:root_id)) as tree_sortkey) parents, site_nodes s2 where s2.tree_sortkey = parents.tree_sortkey order by level select package_id, package_key, pretty_name as package_pretty_name, apm_package_type__num_parameters(package_key) as parameter_count, node_id, url, parent_url, name, root_p, mylevel, object_id, directory_p, parent_id, n_children, p.instance_name as object_name, acs_permission__permission_p(object_id, :user_id, 'admin') as object_admin_p, (select view_p from site_nodes_selection where node_id=site_map.node_id) as view_p from apm_packages p join apm_package_types using (package_key) right outer join (select n.node_id, site_node__url(n.node_id) as url, site_node__url(n.parent_id) as parent_url, n.name, case when exists (select 1 from site_nodes where parent_id = n.node_id) then 1 else 0 end as n_children, case when n.node_id = (select site_node__node_id('/', null)) then 1 else 0 end as root_p, (tree_level(n.tree_sortkey) - (select tree_level(n2.tree_sortkey) from site_nodes n2 where n2.node_id = (select coalesce(:root_id, site_node__node_id('/', null))))) as mylevel, n.object_id, n.directory_p, n.parent_id from site_nodes n, site_nodes n2 where (n.object_id is null or exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = n.object_id and ppm.party_id = :user_id and ppm.privilege = 'read')) and n2.node_id = (select coalesce(:root_id, site_node__node_id('/', null))) and n.tree_sortkey between n2.tree_sortkey and tree_right(n2.tree_sortkey) and (n.parent_id is null or n.parent_id in ([join $expand ", "]))) site_map on site_map.object_id = p.package_id order by url select package_id, ap.package_key, ap.instance_name, apm_package_type__num_parameters(ap.package_key) as parameter_count from apm_packages ap, apm_package_types where ap.package_key = apm_package_types.package_key and package_type = 'apm_service' and not exists (select 1 from site_nodes sn where sn.object_id = package_id) and exists (select 1 from acs_object_party_privilege_map ppm where ppm.object_id = package_id and ppm.party_id = :user_id and ppm.privilege = 'admin') order by instance_name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/parameter-set-oracle.xql0000644000175000017500000000217107504674661027210 0ustar frankiefrankie oracle8.1.6 select package_key, acs_object.name(package_id) instance_name from apm_packages where package_id = :package_id select p.parameter_id, p.parameter_name, p.package_key, nvl(p.description, 'No Description') description, v.attr_value, nvl(p.section_name, 'No Section Name') section_name from apm_parameters p, (select v.parameter_id, v.attr_value from apm_parameter_values v where v.package_id = :package_id) v where p.parameter_id = v.parameter_id(+) and p.package_key = (select package_key from apm_packages where package_id = :package_id) $additional_sql openacs-5.7.0/packages/acs-subsite/www/admin/site-map/application-new-oracle.xql0000644000175000017500000000065407723347125027530 0ustar frankiefrankie oracle8.1.6 select pretty_name, package_key from apm_package_types where not (apm_package.singleton_p(package_key) = 1 and apm_package.num_instances(package_key) >= 1) order by upper(pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/site-map/unmounted-postgresql.xql0000644000175000017500000000252507504674661027416 0ustar frankiefrankie postgresql7.1 select package_id, acs_object__name(package_id) as name from apm_packages where (acs_permission__permission_p(package_id, :user_id, 'read') = 't' or acs_permission__permission_p(package_id, acs__magic_object_id('the_public'), 'read') = 't') and apm_package__singleton_p(package_key) = 0 and not exists (select 1 from site_nodes where object_id = package_id) order by name select package_id, acs_object__name(package_id) as name from apm_packages where (acs_permission__permission_p(package_id, :user_id, 'read') = 't' or acs_permission__permission_p(package_id, acs__magic_object_id('the_public'), 'read') = 't') and apm_package__singleton_p(package_key) = 1 and not exists (select 1 from site_nodes where object_id = package_id) order by name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/application-new-postgresql.xql0000644000175000017500000000066007723347125030463 0ustar frankiefrankie postgresql7.1 select pretty_name, package_key from apm_package_types where not (apm_package__singleton_p(package_key) = 1 and apm_package__num_instances(package_key) >= 1) order by upper(pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/site-map/allow-for-view.tcl0000644000175000017500000000275110551254400026005 0ustar frankiefrankiead_page_contract { Ask for confirmation for view on public site_map @author Viaro Networks (vivian@viaro.net) @cvs-id $id: } { checkbox:integer,multiple,optional return_url } set user_id [auth::require_login] if { ![info exist checkbox] } { set checkbox "" } # Get the main site node_id from object_id set main_node [site_node::get_node_id_from_object_id -object_id [subsite::main_site_id]] set check_list [list] # Here we make shure that when a child node is checked all his parents # in the tree are also checked as well foreach check_node $checkbox { if {$main_node eq $check_node} { # The main site node is always checked lappend check_list $check_node } elseif {[site_node::get_parent_id -node_id $check_node] eq $main_node} { # This node doesn't have a parent node, only the main site node lappend check_list $check_node } else { # The node has an inmediate parent, we put it on the list and all his parents until the # node_id equals the main_site node_id and is already in the list lappend check_list $check_node while { [site_node::get_parent_id -node_id $check_node] != $main_node && \ [lsearch -exact $check_list [site_node::get_parent_id -node_id $check_node]] == -1 } { set check_node [site_node::get_parent_id -node_id $check_node] lappend check_list $check_node } } } db_transaction { db_dml delete_nodes { *SQL* } foreach checkbox $check_list { db_dml insert_nodes { *SQL* } } } ad_returnredirect $return_urlopenacs-5.7.0/packages/acs-subsite/www/admin/site-map/allow-for-view.xql0000644000175000017500000000053710171476745026047 0ustar frankiefrankie delete from site_nodes_selection insert into site_nodes_selection (node_id,view_p) values (:checkbox,'t') openacs-5.7.0/packages/acs-subsite/www/admin/site-map/new.tcl0000644000175000017500000000345710210730323023723 0ustar frankiefrankiead_page_contract { @author Rafael Schloming (rhs@mit.edu) @creation-date 2000-09-09 @cvs-id $Id: new.tcl,v 1.5 2005/03/01 00:01:23 jeffd Exp $ } { parent_id:integer,notnull name:notnull node_type:notnull {expand:integer,multiple {}} {root_id:integer {}} } -validate { name_root_ck -requires name:notnull { if {[string match "*/*" $name]} { ad_complain } } name_duplicate_ck -requires name_root_ck { if {[db_string site_node_duplicate_name_root_ck {} -default 0]} { ad_complain } } node_type_ck -requires node_type:notnull { switch $node_type { folder { set directory_p t set pattern_p t } file { set directory_p f set pattern_p f } default { ad_complain } } } } -errors { name_root_ck {Folder or file names cannot contain '/'} name_duplicate_ck {The URL mapping you are creating is already in use. Please delete the other one or change your URL.} node_type_ck {The node type you specified is invalid} } set user_id [ad_conn user_id] set ip_address [ad_conn peeraddr] db_transaction { set node_id [site_node::new \ -name $name \ -parent_id $parent_id \ -directory_p $directory_p \ -pattern_p $pattern_p \ ] } on_error { ad_return_complaint \ "Error Creating Site Node" \ "The following error was generated when attempting to create the site node:
                    [ad_quotehtml $errmsg]
            
    " } if {[lsearch $expand $parent_id] == -1} { lappend expand $parent_id } ad_returnredirect ".?[export_url_vars expand:multiple root_id]" openacs-5.7.0/packages/acs-subsite/www/admin/site-map/new.xql0000644000175000017500000000047707505162027023761 0ustar frankiefrankie select case when count(*) = 0 then 0 else 1 end from site_nodes where name = :name and parent_id = :parent_id openacs-5.7.0/packages/acs-subsite/www/admin/site-map/unmounted-oracle.xql0000644000175000017500000000251107504674661026453 0ustar frankiefrankie oracle8.1.6 select package_id, acs_object.name(package_id) as name from apm_packages where (acs_permission.permission_p(package_id, :user_id, 'read') = 't' or acs_permission.permission_p(package_id, acs.magic_object_id('the_public'), 'read') = 't') and apm_package.singleton_p(package_key) = 0 and not exists (select 1 from site_nodes where object_id = package_id) order by name select package_id, acs_object.name(package_id) as name from apm_packages where (acs_permission.permission_p(package_id, :user_id, 'read') = 't' or acs_permission.permission_p(package_id, acs.magic_object_id('the_public'), 'read') = 't') and apm_package.singleton_p(package_key) = 1 and not exists (select 1 from site_nodes where object_id = package_id) order by name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/site-map.adp0000644000175000017500000000100110721035754024627 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ @javascript;noquote@ @head;noquote@ »Return  »#acs-subsite.UserSiteMap#

    openacs-5.7.0/packages/acs-subsite/www/admin/site-map/site-map.tcl0000644000175000017500000002271711043711736024665 0ustar frankiefrankiead_page_contract { @author rhs@mit.edu @author bquinn@arsidigta.com @creation-date 2000-09-09 @cvs-id $Id: site-map.tcl,v 1.6 2008/07/29 22:04:14 emmar Exp $ } { {expand:integer,multiple ""} {new_parent:integer ""} {new_type ""} {root_id:integer ""} {new_application:integer ""} {rename_application:integer {}} } if {$root_id eq ""} { set root_id [ad_conn node_id] } # We do a check for the admin privilege because a user could have # admin privilege on a site_node that has other site_nodes beneath it # that the user does not have admin privilege on. If we don't do this # check, the user could end up making changes on site_nodes that he # does not have the admin privilege for. array set node [site_node::get -node_id $root_id] set parent_id $node(parent_id) set object_id $node(object_id) if {$object_id ne ""} { ad_require_permission $object_id admin } if {$new_parent ne ""} { set javascript "onLoad=\"javascript:document.new_parent.name.focus();document.new_parent.name.select()\"" } elseif {$new_application ne ""} { set javascript "onLoad=\"javascript:document.new_application.instance_name.focus();document.new_application.instance_name.select()\"" } elseif {$rename_application ne ""} { set javascript "onLoad=\"javascript:document.rename_application.instance_name.focus();document.rename_application.instance_name.select()\"" } else { set javascript "" } set javascript "onload=\"javascript:document.check_checkbox()\"" set parent_link ".?[export_url_vars expand:multiple root_id=$parent_id]" set page_title "Build Your Site Map " set context [list [list "." "Site Map"] $page_title] set user_id [ad_conn user_id] db_foreach path_select {} { if {$node_id != $root_id && $admin_p eq "t"} { append head "" } if {$name eq ""} { append head "$obj_name:" } else { append head $name } if {$node_id != $root_id && $admin_p eq "t"} { append head "" } if {$directory_p eq "t"} { append head "/" } } if_no_rows { append head " " } if {[llength $expand] == 0} { lappend expand $root_id if { $parent_id ne "" } { lappend expand $parent_id } } set return_url [ad_return_url] template::list::create \ -name nodes \ -multirow nodes \ -key node_id \ -has_checkboxes \ -bulk_actions { "Allow for view (Publish)" "allow-for-view" } \ -bulk_action_method post \ -bulk_action_export_vars { return_url } \ -elements { checkbox { display_template { } } name { label "URL" html "align left" display_template { @nodes.tree_indent;noquote@ @nodes.name;noquote@ @nodes.name;noquote@ #acs-kernel.common_Open# #acs-kernel.common_Close#
    @nodes.tree_indent;noquote@ @nodes.action_form_part;noquote@
    } } instance { label "Instance" html "align left" display_template {
    @nodes.action_form_part;noquote@
    @nodes.action_form_part;noquote@
    @nodes.instance;noquote@ } } type { label "Package Type" html "align left" display_template { @nodes.type;noquote@ } } } multirow create nodes node_id expand_mode expand_url tree_indent name name_url instance instance_url type action_type action_form_part add_folder_url new_app_url unmount_url mount_url rename_url delete_url parameters_url permissions_url extra_form_part view_p set open_nodes [list] db_foreach nodes_select {} { set add_folder_url "" set new_app_url "" set unmount_url "" set mount_url "" set rename_url "" set delete_url "" set parameters_url "" set permissions_url "" if { [lsearch -exact $open_nodes $parent_id] == -1 && $parent_id ne "" && $mylevel > 2 } { continue } if {$directory_p eq "t"} { set add_folder_url "?[export_url_vars expand:multiple root_id node_id new_parent=$node_id new_type=folder]" if {$object_id eq ""} { set mount_url "mount?[export_url_vars expand:multiple root_id node_id]" set new_app_url "?[export_url_vars expand:multiple root_id new_application=$node_id]" } else { # This makes sure you can't unmount the thing that is serving the page you're looking at. if {[ad_conn node_id] != $node_id} { set unmount_url "unmount?[export_url_vars expand:multiple root_id node_id]" } # Add a link to control permissioning if {$object_admin_p} { set permissions_url "../../permissions/one?[export_url_vars object_id]" set rename_url "?[export_url_vars expand:multiple root_id rename_application=$node_id]" set delete_url "instance-delete?package_id=$object_id&root_id=$root_id" } # Is the object a package? if {$package_id ne ""} { if {$object_admin_p && ($parameter_count > 0)} { set parameters_url "[export_vars -base "/shared/parameters" { package_id {return_url {[ad_return_url]} } }]" } } } } if {[ad_conn node_id] != $node_id && $n_children == 0 && $object_id eq ""} { set delete_url "delete?[export_url_vars expand:multiple root_id node_id]" } # use the indent variable to hold current indent level we'll use it later to indent stuff at the end by the amount of the last node set indent "" if { $mylevel != 1 } { if { $mylevel == 2 } { append indent "  " } else { for {set i 1} {$i <4*$mylevel} {incr i} { append indent " " } } } set expand_mode 0 if {!$root_p && $n_children > 0} { set expand_mode 1 set urlvars [list] foreach n $expand { if {$n == $node_id} { set expand_mode 2 lappend open_nodes "$node_id" } else { lappend urlvars "expand=$n" } } if { $expand_mode == 1} { lappend urlvars "expand=$node_id" } lappend urlvars "root_id=$root_id" set expand_url "[join $urlvars "&"]" } else { set expand_url "" } set name_url [export_url_vars expand:multiple root_id=$node_id] set action_type 0 set action_form_part "" if {$object_id eq ""} { if {$new_application == $node_id} { set action_type "new_app" set action_form_part "[export_form_vars expand:multiple root_id node_id new_package_id] [apm_application_new_checkbox]" #Generate a package_id for double click protection set new_package_id [db_nextval acs_object_id_seq] } else { set action_form_part "(none)" } } elseif {$rename_application == $node_id} { set action_type "rename_app" set action_form_part "[export_form_vars expand:multiple root_id node_id rename_package_id]" } else {} if {$node_id == $new_parent} { set parent_id $new_parent set node_type $new_type set action_type "new_folder" set action_form_part "[export_form_vars expand:multiple parent_id node_type root_id]" } multirow append nodes $node_id $expand_mode $expand_url $indent $name $name_url $object_name $url $package_pretty_name $action_type $action_form_part $add_folder_url $new_app_url $unmount_url $mount_url $rename_url $delete_url $parameters_url $permissions_url "" $view_p } #set new_app_form_part_1 "

    [export_form_vars expand:multiple]

    " #set new_app_form_part_2 "

    [apm_application_new_checkbox]

    " #set new_app_form_part_3 "

    " # multirow append nodes "" "" "" "" $new_app_form_part_1 "" "" "" $new_app_form_part_2 "" "" "" "" "" "" "" "" "" "" $new_app_form_part_3 set services "" db_foreach services_select {} { if {$parameter_count > 0} { append services "
  • $instance_name" } } if_no_rows { append services "
  • (none)\n" } openacs-5.7.0/packages/acs-subsite/www/admin/site-map/index-postgresql.xql0000644000175000017500000000717710671204456026505 0ustar frankiefrankie postgresql7.1 select s2.node_id, s2.name, s2.directory_p, tree_level(s2.tree_sortkey) as level, acs_object__name(s2.object_id) as obj_name, acs_permission__permission_p(s2.object_id, :user_id, 'admin') as admin_p from (select tree_ancestor_keys(site_node_get_tree_sortkey(:root_id)) as tree_sortkey) parents, site_nodes s2 where s2.tree_sortkey = parents.tree_sortkey order by level select package_id, package_key, pretty_name as package_pretty_name, apm_package_type__num_parameters(package_key) as parameter_count, node_id, url, parent_url, name, root_p, mylevel, object_id, directory_p, parent_id, n_children, p.instance_name as object_name, acs_permission__permission_p(object_id, :user_id, 'admin') as object_admin_p from apm_packages p join apm_package_types using (package_key) right outer join (select n.node_id, site_node__url(n.node_id) as url, site_node__url(n.parent_id) as parent_url, n.name, case when exists (select 1 from site_nodes where parent_id = n.node_id) then 1 else 0 end as n_children, case when n.node_id = (select site_node__node_id('/', null)) then 1 else 0 end as root_p, (tree_level(n.tree_sortkey) - (select tree_level(n2.tree_sortkey) from site_nodes n2 where n2.node_id = (select coalesce(:root_id, site_node__node_id('/', null))))) as mylevel, n.object_id, n.directory_p, n.parent_id from site_nodes n, site_nodes n2 where (n.object_id is null or exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = n.object_id and ppm.party_id = :user_id and ppm.privilege = 'read')) and n2.node_id = (select coalesce(:root_id, site_node__node_id('/', null))) and n.tree_sortkey between n2.tree_sortkey and tree_right(n2.tree_sortkey) and (n.parent_id is null or n.parent_id in ([join $expand ", "]))) site_map on site_map.object_id = p.package_id $where_limit order by url select package_id, ap.package_key, ap.instance_name, apm_package_type__num_parameters(ap.package_key) as parameter_count from apm_packages ap, apm_package_types where ap.package_key = apm_package_types.package_key and package_type = 'apm_service' and not exists (select 1 from site_nodes sn where sn.object_id = package_id) and exists (select 1 from acs_object_party_privilege_map ppm where ppm.object_id = package_id and ppm.party_id = :user_id and ppm.privilege = 'admin') order by instance_name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/index.adp0000644000175000017500000000162111553071716024231 0ustar frankiefrankie @doc.title@ @context;noquote@ @javascript;noquote@

    @doc.title@

    #acs-subsite.Services#

      @services;noquote@

    #acs-subsite.Site_Map_Instructions#

    • #acs-subsite.To_add_an_application_to_this_site#
    • #acs-subsite.To_configure_an_application_select_set_parameters#
    • #acs-subsite.To_copy_an_application_instance_to_another#
    • #acs-subsite.To_move_an_application_copy_it_as_above#
    • #acs-subsite.To_remove_an_application_and_all_of_its_data#
    openacs-5.7.0/packages/acs-subsite/www/admin/site-map/index.tcl0000644000175000017500000002377711553071716024267 0ustar frankiefrankiead_page_contract { @author rhs@mit.edu @author bquinn@arsidigta.com @creation-date 2000-09-09 @cvs-id $Id: index.tcl,v 1.27 2011/04/18 17:24:30 emmar Exp $ } { {expand:integer,multiple ""} {new_parent:integer ""} {new_type ""} {root_id:integer ""} {new_application:integer ""} {rename_application:integer {}} } if {$root_id eq ""} { set root_id [ad_conn node_id] } # We do a check for the admin privilege because a user could have # admin privilege on a site_node that has other site_nodes beneath it # that the user does not have admin privilege on. If we don't do this # check, the user could end up making changes on site_nodes that he # does not have the admin privilege for. array set node [site_node::get -node_id $root_id] set parent_id $node(parent_id) set object_id $node(object_id) if {$object_id ne ""} { ad_require_permission $object_id admin } if {$new_parent ne ""} { set javascript "onLoad=\"javascript:document.new_parent.name.focus();document.new_parent.name.select()\"" } elseif {$new_application ne ""} { set javascript "onLoad=\"javascript:document.new_application.instance_name.focus();document.new_application.instance_name.select()\"" } elseif {$rename_application ne ""} { set javascript "onLoad=\"javascript:document.rename_application.instance_name.focus();document.rename_application.instance_name.select()\"" } else { set javascript "" } set parent_link ".?[export_url_vars expand:multiple root_id=$parent_id]" set doc(title) [_ acs-subsite.Site_Map] set context [list $doc(title)] set user_id [ad_conn user_id] set subsite_number [db_string count_subsites "select count(*) from apm_packages where package_key = 'acs-subsite'"] if {$subsite_number > 100} { set too_many_subsites_p 1 set where_limit "where apm_packages.package_key <> 'acs-subsite'" } else { set too_many_subsites_p 0 set where_limit "" } db_foreach path_select {} { if {$node_id != $root_id && $admin_p eq "t"} { append head [subst {}] } if {$name eq ""} { append head "$obj_name:" } else { append head $name } if {$node_id != $root_id && $admin_p eq "t"} { append head "" } if {$directory_p eq "t"} { append head "/" } } if_no_rows { append head " " } if {[llength $expand] == 0} { lappend expand $root_id if { $parent_id ne "" } { lappend expand $parent_id } } template::list::create \ -name nodes \ -multirow nodes \ -key node_id \ -elements { name { label "URL" html "align left" display_template { @nodes.tree_indent;noquote@ (+) (-) @nodes.name;noquote@ @nodes.name;noquote@
    @nodes.tree_indent;noquote@ @nodes.action_form_part;noquote@
    @nodes.name;noquote@ } } instance { label "Instance" html "align left" display_template {
    @nodes.action_form_part;noquote@
    @nodes.action_form_part;noquote@
    @nodes.instance;noquote@ } } type { label "Package Type" html "align left" display_template { @nodes.type;noquote@ } } actions { label "Action" html "align left" display_template { [_ acs-subsite.add_folder] [_ acs-subsite.new_application] [_ acs-subsite.unmount] [_ acs-subsite.mount] [_ acs-subsite.rename] [_ acs-subsite.delete] [_ acs-subsite.parameters] [_ acs-subsite.permissions] @nodes.extra_form_part;noquote@ } } } multirow create nodes node_id expand_mode expand_url tree_indent name name_url instance instance_url type action_type action_form_part add_folder_url new_app_url unmount_url mount_url rename_url delete_url parameters_url permissions_url extra_form_part set open_nodes [list] db_foreach nodes_select {} { set add_folder_url "" set new_app_url "" set unmount_url "" set mount_url "" set rename_url "" set delete_url "" set parameters_url "" set permissions_url "" if { [lsearch -exact $open_nodes $parent_id] == -1 && $parent_id ne "" && $mylevel > 2 } { continue } if {$directory_p eq "t"} { set add_folder_url "?[export_url_vars expand:multiple root_id node_id new_parent=$node_id new_type=folder]" if {$object_id eq ""} { set mount_url "mount?[export_url_vars expand:multiple root_id node_id]" set new_app_url "?[export_url_vars expand:multiple root_id new_application=$node_id]" } else { # This makes sure you can't unmount the thing that is serving the page you're looking at. if {[ad_conn node_id] != $node_id} { set unmount_url "unmount?[export_url_vars expand:multiple root_id node_id]" } # Add a link to control permissioning if {$object_admin_p} { set permissions_url "../../permissions/one?[export_url_vars object_id]" set rename_url "?[export_url_vars expand:multiple root_id rename_application=$node_id]" set delete_url "instance-delete?package_id=$object_id&root_id=$root_id" } # Is the object a package? if {$package_id ne ""} { if {$object_admin_p && ($parameter_count > 0)} { set parameters_url "[export_vars -base "/shared/parameters" { package_id {return_url {[ad_return_url]} } }]" } } } } if {[ad_conn node_id] != $node_id && $n_children == 0 && $object_id eq ""} { set delete_url "delete?[export_url_vars expand:multiple root_id node_id]" } # use the indent variable to hold current indent level we'll use it later to indent stuff at the end by the amount of the last node set indent "" for {set i 0} {$i < 3*$mylevel} {incr i} { append indent " " } set expand_mode 0 if {!$root_p && $n_children > 0} { set expand_mode 1 set urlvars [list] foreach n $expand { if {$n == $node_id} { set expand_mode 2 lappend open_nodes "$node_id" } else { lappend urlvars "expand=$n" } } if { $expand_mode == 1} { lappend urlvars "expand=$node_id" } lappend urlvars "root_id=$root_id" set expand_url "[join $urlvars "&"]" } else { set expand_url "" } set name_url [export_url_vars expand:multiple root_id=$node_id] set action_type 0 set action_form_part "" if {$object_id eq ""} { if {$new_application == $node_id} { set action_type "new_app" set action_form_part "[export_form_vars expand:multiple root_id node_id new_package_id] [apm_application_new_checkbox]" #Generate a package_id for double click protection set new_package_id [db_nextval acs_object_id_seq] } else { set action_form_part "(none)" } } elseif {$rename_application == $node_id} { set action_type "rename_app" set action_form_part "[export_form_vars expand:multiple root_id node_id rename_package_id]" } else {} if {$node_id == $new_parent} { set parent_id $new_parent set node_type $new_type set action_type "new_folder" set action_form_part "[export_form_vars expand:multiple parent_id node_type root_id]" } multirow append nodes $node_id $expand_mode $expand_url $indent $name $name_url $object_name $url $package_pretty_name $action_type $action_form_part $add_folder_url $new_app_url $unmount_url $mount_url $rename_url $delete_url $parameters_url $permissions_url "" } set new_app_form_part_1 [subst {
    [export_form_vars expand:multiple]}] set new_app_form_part_2 "[apm_application_new_checkbox]" set new_app_form_part_3 "
    " multirow append nodes -99999 "" "" "" $new_app_form_part_1 "" "" "" $new_app_form_part_2 "" "" "" "" "" "" "" "" "" "" $new_app_form_part_3 set services "" db_foreach services_select {} { if {$parameter_count > 0} { append services "
  • $instance_name" } } if_no_rows { append services "
  • (none)\n" } openacs-5.7.0/packages/acs-subsite/www/admin/site-map/parameter-set-2.tcl0000644000175000017500000000147411130540436026045 0ustar frankiefrankiead_page_contract { Set parameters on a package instance. @author Bryan Quinn (bquinn@arsdigita.com) @creation-date 12 September 2000 @cvs-id $Id: parameter-set-2.tcl,v 1.5 2009/01/06 02:25:34 gustafn Exp $ } { package_key:notnull package_id:naturalnum,notnull instance_name:notnull {return_url "."} params:array } ad_require_permission $package_id admin if { [catch { db_foreach apm_parameters_set {} { if {[info exists params($parameter_id)]} { parameter::set_value -value $params($parameter_id) -package_id $package_id -parameter $parameter_name } } } errmsg] } { ad_return_error "Database Error" "The parameters could not be set. The database error was:

    [ad_quotehtml $errmsg]
    ." } else { ad_returnredirect $return_url } openacs-5.7.0/packages/acs-subsite/www/admin/site-map/parameter-set-2.xql0000644000175000017500000000044407504674661026105 0ustar frankiefrankie select parameter_id, parameter_name from apm_parameters where package_key = :package_key openacs-5.7.0/packages/acs-subsite/www/admin/site-map/mount-2.tcl0000644000175000017500000000073107504674661024453 0ustar frankiefrankie# packages/acs-core-ui/www/admin/site-nodes/mount-2.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-09-12 @cvs-id $Id: mount-2.tcl,v 1.2 2002/06/21 19:08:33 yon Exp $ } { node_id:integer,notnull package_id:integer,notnull {expand:integer,multiple {}} root_id:integer,optional } ad_require_permission $package_id read site_node::mount -node_id $node_id -object_id $package_id ad_returnredirect ".?[export_url_vars expand:multiple root_id]" openacs-5.7.0/packages/acs-subsite/www/admin/site-map/parameter-set.tcl0000644000175000017500000000625510551254400025707 0ustar frankiefrankiead_page_contract { Set parameters on a package instance. @author Bryan Quinn (bquinn@arsdigita.com) @creation-date 12 September 2000 @cvs-id $Id: parameter-set.tcl,v 1.9 2007/01/10 21:22:08 gustafn Exp $ } { package_id:naturalnum,notnull {orderby ""} {return_url "."} } ad_require_permission $package_id admin db_1row package_info {} set table_def [list \ [list parameter_name "Parameter Name"] \ [list description "Description"]] set table_sql "select p.parameter_id, p.parameter_name, p.package_key, nvl(p.description, 'No Description') description, nvl(v.attr_value, 'No Value') attr_value, nvl(p.section_name, 'No Section Name') section_name from apm_parameters p, (select parameter_id, attr_value from apm_parameter_values v where v.package_id = :package_id) v where p.parameter_id = v.parameter_id(+) and p.package_key = (select package_key from apm_packages where package_id = :package_id)" set dimensional_list [apm_parameter_section_slider $package_key] set additional_sql "" if {[exists_and_not_null dimensional_list] } { lappend table_def [list section_name "Section:"] append additional_sql [ad_dimensional_sql $dimensional_list] ns_log Notice [ad_dimensional_sql $dimensional_list] } # DRB: This should be rewritten to optionally allow for the definition of possible parameter values, # with a drop-down select widget used rather than a text input widget. # TIL: only show the from-file-parameter-warning when there are # actually parameters from a file in this listing. set display_warning_p 0 lappend table_def [list attr_value "Value" no_sort \ { [if { ![empty_string_p [ad_parameter_from_file $parameter_name [uplevel set package_key]]] } { uplevel set display_warning_p 1 } ; ad_parameter_from_file $parameter_name [uplevel set package_key]] }] append additional_sql [ad_order_by_from_sort_spec $orderby $table_def] set body "[ad_header "Parameters for $instance_name"]

    Parameters for $instance_name

    [ad_context_bar [list "index" "Site Map"] "$instance_name Parameters"]
    " if { $dimensional_list ne "" } { append body "[ad_dimensional $dimensional_list]

    " } append table_sql $additional_sql ns_log Notice "table_sql = $table_sql" set table [ad_table -Torderby $orderby \ -bind [ad_tcl_vars_to_ns_set package_id] \ -Tmissing_text "No parameters registered in this section." \ -Textra_rows " " parameter_table $table_sql $table_def] if { $display_warning_p } { append body " Note text in red below the parameter entry fields indicates the value of this parameter is being overridden by an entry in the OpenACS parameter file. The use of the parameter file is discouraged but some sites need it to provide instance-specific values for parameters independent of the apm_parameter tables.


    " } ns_return 200 text/html "$body
    [export_form_vars package_key package_id instance_name return_url] $table
    [ad_footer] " openacs-5.7.0/packages/acs-subsite/www/admin/site-map/site-map-oracle.xql0000644000175000017500000000702110204416413026131 0ustar frankiefrankie oracle8.1.6 select node_id, name, directory_p, level, acs_object.name(object_id) as obj_name, acs_permission.permission_p(object_id, :user_id, 'admin') as admin_p from site_nodes start with node_id = :root_id connect by node_id = prior parent_id order by level desc select package_id, package_key, (select pretty_name from apm_package_types where package_key = p.package_key) as package_pretty_name, apm_package_type.num_parameters(package_key) parameter_count, node_id, url, parent_url, name, root_p, mylevel - 1 as mylevel, object_id, object_name, directory_p, parent_id, n_children, decode(acs_permission.permission_p(object_id, :user_id, 'admin'), 't', 1, 0) object_admin_p, (select view_p from site_nodes_selection where node_id=site_map.node_id) as view_p from apm_packages p, (select node_id, site_node.url(node_id) as url, site_node.url(parent_id) as parent_url, name, (select count(*) from site_nodes where parent_id = n.node_id) as n_children, decode(node_id, site_node.node_id('/'), 1, 0) as root_p, level as mylevel, object_id, acs_object.name(object_id) as object_name, directory_p, parent_id from site_nodes n where (object_id is null or exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = n.object_id and ppm.party_id = :user_id and ppm.privilege = 'read')) start with node_id = nvl(:root_id, site_node.node_id('/')) connect by prior node_id = parent_id and parent_id in ([join $expand ", "])) site_map where site_map.object_id = p.package_id (+) order by url select package_id, ap.package_key, ap.instance_name, apm_package_type.num_parameters(ap.package_key) as parameter_count from apm_packages ap, apm_package_types where ap.package_key = apm_package_types.package_key and package_type = 'apm_service' and not exists (select 1 from site_nodes sn where sn.object_id = package_id) and exists (select 1 from acs_object_party_privilege_map ppm where ppm.object_id = package_id and ppm.party_id = :user_id and ppm.privilege = 'admin') order by instance_name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/index-oracle.xql0000644000175000017500000000665207766162054025554 0ustar frankiefrankie oracle8.1.6 select node_id, name, directory_p, level, acs_object.name(object_id) as obj_name, acs_permission.permission_p(object_id, :user_id, 'admin') as admin_p from site_nodes start with node_id = :root_id connect by node_id = prior parent_id order by level desc select package_id, package_key, (select pretty_name from apm_package_types where package_key = p.package_key) as package_pretty_name, apm_package_type.num_parameters(package_key) parameter_count, node_id, url, parent_url, name, root_p, mylevel - 1 as mylevel, object_id, object_name, directory_p, parent_id, n_children, decode(acs_permission.permission_p(object_id, :user_id, 'admin'), 't', 1, 0) object_admin_p from apm_packages p, (select node_id, site_node.url(node_id) as url, site_node.url(parent_id) as parent_url, name, (select count(*) from site_nodes where parent_id = n.node_id) as n_children, decode(node_id, site_node.node_id('/'), 1, 0) as root_p, level as mylevel, object_id, acs_object.name(object_id) as object_name, directory_p, parent_id from site_nodes n where (object_id is null or exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = n.object_id and ppm.party_id = :user_id and ppm.privilege = 'read')) start with node_id = nvl(:root_id, site_node.node_id('/')) connect by prior node_id = parent_id and parent_id in ([join $expand ", "])) site_map where site_map.object_id = p.package_id (+) order by url select package_id, ap.package_key, ap.instance_name, apm_package_type.num_parameters(ap.package_key) as parameter_count from apm_packages ap, apm_package_types where ap.package_key = apm_package_types.package_key and package_type = 'apm_service' and not exists (select 1 from site_nodes sn where sn.object_id = package_id) and exists (select 1 from acs_object_party_privilege_map ppm where ppm.object_id = package_id and ppm.party_id = :user_id and ppm.privilege = 'admin') order by instance_name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/mount-postgresql.xql0000644000175000017500000000736410501274250026525 0ustar frankiefrankie postgresql7.1 select p.package_id, p.instance_name as name, pt.pretty_name as package_pretty_name from apm_packages p, apm_package_types pt, apm_package_versions v where pt.package_key = p.package_key and v.package_key = pt.package_key and (v.installed_p = 't' or v.enabled_p = 't' or not exists ( select 1 from apm_package_versions v2 where v2.package_key = v.package_key and (v2.installed_p = 't' or v2.enabled_p = 't') and apm_package_version__sortable_version_name(v2.version_name) > apm_package_version__sortable_version_name(v.version_name))) and ( acs_permission__permission_p(p.package_id, :user_id, 'read') = 't' or acs_permission__permission_p(p.package_id, acs__magic_object_id('the_public'), 'read') = 't' ) and (apm_package__singleton_p(p.package_key) = 0 or coalesce(v.auto_mount,'') != '') and not exists (select 1 from site_nodes where object_id = p.package_id) order by name select p.package_id, acs_object__name(p.package_id) as name, pt.pretty_name as package_pretty_name from apm_packages p, apm_package_types pt where pt.package_key = p.package_key and ( acs_permission__permission_p(p.package_id, :user_id, 'read') = 't' or acs_permission__permission_p(p.package_id, acs__magic_object_id('the_public'), 'read') = 't' ) and exists (select 1 from site_nodes where object_id = p.package_id) order by name select p.package_id, acs_object__name(p.package_id) as name, pt.pretty_name as package_pretty_name from apm_packages p, apm_package_types pt, apm_package_versions v where pt.package_key = p.package_key and v.package_key = pt.package_key and (v.installed_p = 't' or v.enabled_p = 't' or not exists ( select 1 from apm_package_versions v2 where v2.package_key = v.package_key and (v2.installed_p = 't' or v2.enabled_p = 't') and apm_package_version__sortable_version_name(v2.version_name) > apm_package_version__sortable_version_name(v.version_name))) and ( acs_permission__permission_p(p.package_id, :user_id, 'read') = 't' or acs_permission__permission_p(p.package_id, acs__magic_object_id('the_public'), 'read') = 't' ) and (apm_package__singleton_p(p.package_key) = 1 and coalesce(v.auto_mount,'') = '') and apm_package__singleton_p(p.package_key) = 1 and not exists (select 1 from site_nodes where object_id = p.package_id) order by name openacs-5.7.0/packages/acs-subsite/www/admin/site-map/delete.tcl0000644000175000017500000000073607537470223024413 0ustar frankiefrankie# packages/acs-core-ui/www/admin/site-nodes/delete.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-09-09 @cvs-id $Id: delete.tcl,v 1.4 2002/09/10 22:22:11 jeffd Exp $ } { expand:integer,multiple node_id:integer,notnull {root_id:integer ""} } if {$root_id == $node_id} { set root_id [site_node::get_parent_id -node_id $node_id] } site_node::delete -node_id $node_id ad_returnredirect ".?[export_url_vars expand:multiple root_id]" openacs-5.7.0/packages/acs-subsite/www/admin/site-map/auto-mount.tcl0000644000175000017500000000103710551254400025237 0ustar frankiefrankie# /packages/acs-subsite/www/admin/site-map/auto-mount.tcl ad_page_contract { Automatically mounts a package beneath the specified node @author mbryzek@arsdigita.com @creation-date Fri Feb 9 20:27:26 2001 @cvs-id $Id: auto-mount.tcl,v 1.4 2007/01/10 21:22:08 gustafn Exp $ } { package_key:notnull node_id:integer,notnull {return_url ""} } subsite::auto_mount_application -node_id $node_id $package_key if {$return_url eq ""} { set return_url [site_node::get_url -node_id] } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/site-map/rename.tcl0000644000175000017500000000270607727570425024425 0ustar frankiefrankie# packages/acs-subsite/www/admin/site-map/rename.tcl # Copyright (C) 2002 Red Hat # This file is part of ACS. # # ACS is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # ACS is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with ACS; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ad_page_contract { packages/acs-subsite/www/admin/site-map/rename.tcl @author bdolicki@redhat.com @creation-date 2000-06-20 @cvs-id $Id: rename.tcl,v 1.2 2003/09/10 09:38:29 lars Exp $ } { node_id:integer,notnull instance_name:notnull {expand:integer,multiple {}} root_id:integer,optional } # (bran 2000-06-20) Here I am assuming that only packages can be hung # on site_nodes. Until we have a general framework for mutators # I can hardly do anything better. set package_id [site_node::get_object_id -node_id $node_id] apm_package_rename \ -package_id $package_id \ -instance_name $instance_name ad_returnredirect [export_vars -base "." { expand:multiple root_id }] openacs-5.7.0/packages/acs-subsite/www/admin/site-map/application-new.adp0000644000175000017500000000032610052153354026205 0ustar frankiefrankie @page_title@ @context@ application.package_key openacs-5.7.0/packages/acs-subsite/www/admin/site-map/application-new.tcl0000644000175000017500000000500010551254400026213 0ustar frankiefrankiead_page_contract { Create and mount a new application. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-05-28 @cvs-id $Id: application-new.tcl,v 1.5 2007/01/10 21:22:08 gustafn Exp $ } set page_title "New Application" set context [list [list "." "Site Map"] $page_title] set packages [db_list_of_lists package_types {}] ad_form -name application -cancel_url . -form { {package_key:text(select) {label "Application"} {options $packages} {help_text "The type of application you want to add."} } {instance_name:text,optional {label "Application name"} {help_text "The human-readable name of your application. If you leave this out, we'll use the name of the application (e.g. 'Forums')."} {html {size 50}} } {folder:text,optional {label "URL folder name"} {help_text "This should be a short string, all lowercase, with hyphens instead of spaces, whicn will be used in the URL of the new application. If you leave this blank, we will generate one for you from name of the application."} {html {size 30}} {validate { empty_or_not_exists {expr \[empty_string_p \$value\] || \[catch { site_node::get_from_url -url "[ad_conn package_url]\$value/" -exact }\]} {This folder name is already used.} }} } } -on_submit { # Get the node ID of this subsite set node_id [ad_conn node_id] if { $instance_name eq "" } { # Find the package pretty name from the list of packages foreach elm $packages { if {[lindex $elm 1] eq $package_key} { set instance_name [lindex $elm 0] break } } if { $instance_name eq "" } { error "Couldn't find package_key '$package_key' in list of system applications" } } # Autogenerate folder name if { $folder eq "" } { set existing_urls [site_node::get_children -node_id $node_id -element name] set folder [util_text_to_url \ -existing_urls $existing_urls \ -text $instance_name] } if { [catch { site_node::instantiate_and_mount \ -parent_node_id $node_id \ -node_name $folder \ -package_name $instance_name \ -package_key $package_key } errsmg] } { ad_return_error "Problem Creating Application" "We had a problem creating the application." } ad_returnredirect . ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/site-map/parameter-set-postgresql.xql0000644000175000017500000000223207504674661030144 0ustar frankiefrankie postgresql7.1 select package_key, acs_object__name(package_id) as instance_name from apm_packages where package_id = :package_id select p.parameter_id, p.parameter_name, p.package_key, coalesce(p.description, 'No Description') as description, v.attr_value, coalesce(p.section_name, 'No Section Name') as section_name from apm_parameters p left outer join (select v.parameter_id, v.attr_value from apm_parameter_values v where v.package_id = :package_id) v on p.parameter_id = v.parameter_id where p.package_key = (select package_key from apm_packages where package_id = :package_id) $additional_sql openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/0000755000175000017500000000000011724401447023320 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/edit.adp0000644000175000017500000000033307723347124024737 0ustar frankiefrankie @context@ Edit Segment Name segment.segment_name openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/edit.tcl0000644000175000017500000000274010024403027024740 0ustar frankiefrankiead_page_contract { Form to edit the name of a relational segment @author lars@collaboraid.biz @creation-date 2003-06-11 @cvs-id $Id: edit.tcl,v 1.5 2004/03/12 18:48:55 jeffd Exp $ } { segment_id:integer,notnull } -validate { segment_exists_p -requires {segment_id:notnull} { if { ![rel_segments_permission_p $segment_id] } { ad_complain "The segment either does not exist or you do not have permission to view it" } } segment_in_scope_p -requires {segment_id:notnull segment_exists_p} { if { ![application_group::contains_segment_p -segment_id $segment_id]} { ad_complain "The segment either does not exist or does not belong to this subsite." } } } set view_url [export_vars -base one { segment_id }] set context [list [list "./" "Relational segments"] [list $view_url "One segment"] "Edit"] ad_form -name segment -cancel_url $view_url -form { {segment_id:integer(hidden),key} {segment_name:text {label "Name"} {html {size 50}} } } -select_query { select s.segment_id, s.segment_name from rel_segments s where s.segment_id = :segment_id } -edit_data { db_dml update_segment_name { update rel_segments set segment_name = :segment_name where segment_id = :segment_id } db_dml update_object_title { update acs_objects set title = :segment_name where object_id = :segment_id } } -after_submit { ad_returnredirect $view_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements-display-postgresql.xql0000644000175000017500000000114407766162053031536 0ustar frankiefrankie postgresql7.1 select acs_object__name(map.party_id) as name, map.rel_id, case when map.container_id = :group_id then 1 else 0 end as direct_p, acs_object__name(map.container_id) as container_name from rel_segment_party_map map where acs_permission__permission_p(map.party_id, :user_id, 'read') = 't' and map.segment_id = :segment_id order by name openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints-redirect.tcl0000644000175000017500000000127710551254377030206 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/constraints-redirect.tcl ad_page_contract { Optionally redirects user to enter constraints @author mbryzek@arsdigita.com @creation-date Thu Jan 4 11:20:37 2001 @cvs-id $Id: constraints-redirect.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { segment_id:naturalnum,notnull { operation "" } { return_url "" } } set operation [string trim [string tolower $operation]] if {$operation eq "yes"} { ad_returnredirect "constraints/new?rel_segment=$segment_id&[ad_export_vars return_url]" } else { if { $return_url eq "" } { set return_url "one?[ad_export_vars segment_id]" } ad_returnredirect $return_url } openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements-display.adp0000644000175000017500000000104610210424047027254 0ustar frankiefrankie

    @segment_name@

    • (none)
    • @elements.name@ (direct relationship) (through @elements.container_name@) (remove)
    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements-display.tcl0000644000175000017500000000113410210424047027270 0ustar frankiefrankie# included from elements. ad_require_permission $segment_id "read" set write_p [ad_permission_p $segment_id "write"] set package_url [ad_conn package_url] set user_id [ad_conn user_id] db_multirow elements elements_select { select acs_object.name(map.party_id) as name, map.rel_id, decode(map.container_id, :group_id, 1, 0) as direct_p, acs_object.name(map.container_id) as container_name from rel_segment_party_map map where acs_permission.permission_p(map.party_id, :user_id, 'read') = 't' and map.segment_id = :segment_id order by lower(name) } openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-postgresql.xql0000644000175000017500000000155107403013337027036 0ustar frankiefrankie postgresql7.1 select t2.pretty_name, t2.object_type as rel_type, repeat(' ', (tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4) as indent from acs_object_types t1, acs_object_types t2, rel_segments s where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type in ('membership_rel', 'composition_rel') and t2.object_type <> s.rel_type and s.group_id = :group_id order by lower(t2.pretty_name) desc select acs_group__name(:group_id) as group_name openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/0000755000175000017500000000000011724401447025667 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/new-postgresql.xql0000644000175000017500000000234307346724754031427 0ustar frankiefrankie postgresql7.1 select s.segment_name, acs_rel_type__role_pretty_name(t.role_one) as role_one_name, acs_rel_type__role_pretty_name(t.role_two) as role_two_name from rel_segments s, acs_rel_types t where s.rel_type = t.rel_type and s.segment_id = :rel_segment select rel_constraint__new( null, 'rel_constraint', :constraint_name, :rel_segment, :rel_side, :required_rel_segment, null, :creation_user, :creation_ip ); select viol.rel_id, acs_object__name(viol.party_id) as name from rel_constraints_violated_one viol where viol.constraint_id = :constraint_id UNION ALL select viol.rel_id, acs_object__name(viol.party_id) as name from rel_constraints_violated_two viol where viol.constraint_id = :constraint_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete-2.tcl0000644000175000017500000000316510551254377030006 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/constraints/delete-2.tcl ad_page_contract { Deletes the specified constraint @author mbryzek@arsdigita.com @creation-date Fri Dec 15 11:27:27 2000 @cvs-id $Id: delete-2.tcl,v 1.4 2007/01/10 21:22:07 gustafn Exp $ } { constraint_id:naturalnum,notnull { operation "" } { return_url "" } } ad_require_permission $constraint_id delete set package_id [ad_conn package_id] if {$operation eq "Yes, I really want to delete this constraint"} { if { $return_url eq "" } { # Redirect to the rel-segment page by default. if { [db_0or1row select_segment_id { select c.rel_segment as segment_id from rel_constraints c where c.constraint_id = :constraint_id }] } { set return_url "../one?[ad_export_vars {segment_id}]" } } if { ![db_0or1row select_constraint_props { select 1 from rel_constraints c, application_group_segments s, application_group_segments s2 where c.rel_segment = s.segment_id and c.constraint_id = :constraint_id and s.package_id = :package_id and s2.segment_id = c.required_rel_segment and s2.package_id = :package_id }] } { # The constraint is already deleted or not in scope ad_returnredirect $return_url ad_script_abort } db_exec_plsql delete_constraint { begin rel_constraint.del(constraint_id => :constraint_id); end; } db_release_unused_handles } elseif { $return_url eq "" } { # if we're not deleting, redirect to the constraint page set return_url one?[ad_export_vars constraint_id] } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete-2.xql0000644000175000017500000000127507300260124030011 0ustar frankiefrankie select c.rel_segment as segment_id from rel_constraints c where c.constraint_id = :constraint_id select 1 from rel_constraints c, application_group_segments s, application_group_segments s2 where c.rel_segment = s.segment_id and c.constraint_id = :constraint_id and s.package_id = :package_id and s2.segment_id = c.required_rel_segment and s2.package_id = :package_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/one-postgresql.xql0000644000175000017500000000314607741522517031411 0ustar frankiefrankie postgresql7.1 select c.constraint_id, c.constraint_name, c.rel_side, s.segment_id, s.segment_name, s.rel_type, acs_group__name(s.group_id) as group_name, s2.segment_id as req_segment_id, s2.segment_name as req_segment_name, s2.rel_type as req_rel_type, acs_group__name(s2.group_id) as req_group_name from application_group_segments s, application_group_segments s2, rel_constraints c where s.segment_id = c.rel_segment and s2.segment_id = c.required_rel_segment and c.constraint_id = :constraint_id and s.package_id = :package_id select role1.role as role_one, coalesce(role1.pretty_name,'Object on side one') as role_one_pretty_name, coalesce(role1.pretty_plural,'Objects on side one') as role_one_pretty_plural, role2.role as role_two, coalesce(role2.pretty_name,'Object on side two') as role_two_pretty_name, coalesce(role2.pretty_plural,'Objects on side two') as role_two_pretty_plural, acs_object_type__pretty_name(rel.rel_type) as rel_type_pretty_name from acs_rel_types rel left outer join acs_rel_roles role1 on (rel.role_one = role1.role) left outer join acs_rel_roles role2 on (rel.role_two = role2.role) where rel.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/new-oracle.xql0000644000175000017500000000273007300260124030441 0ustar frankiefrankie oracle8.1.6 select s.segment_name, acs_rel_type.role_pretty_name(t.role_one) as role_one_name, acs_rel_type.role_pretty_name(t.role_two) as role_two_name from rel_segments s, acs_rel_types t where s.rel_type = t.rel_type and s.segment_id = :rel_segment BEGIN :1 := rel_constraint.new(constraint_name => :constraint_name, rel_segment => :rel_segment, rel_side => :rel_side, required_rel_segment => :required_rel_segment, creation_user => :creation_user, creation_ip => :creation_ip ); END; select viol.rel_id, acs_object.name(viol.party_id) as name from rel_constraints_violated_one viol where viol.constraint_id = :constraint_id UNION ALL select viol.rel_id, acs_object.name(viol.party_id) as name from rel_constraints_violated_two viol where viol.constraint_id = :constraint_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/new.adp0000644000175000017500000000037607663155030027155 0ustar frankiefrankie @context;noquote@ Add constraint to @segment_name;noquote@ constraint_new.constraint_name openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/new.tcl0000644000175000017500000001137110551254377027174 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/constraints/new.tcl ad_page_contract { Form to add a constraint @author mbryzek@arsdigita.com @creation-date Mon Dec 11 11:45:21 2000 @cvs-id $Id: new.tcl,v 1.4 2007/01/10 21:22:07 gustafn Exp $ } { rel_segment:notnull,integer constraint_name:optional rel_side:optional required_rel_segment:optional { return_url "" } } -properties { context:onevalue segment_name:onevalue return_url_enc:onevalue violations:onerow } -validate { rel_segment_in_scope_p -requires {rel_segment:notnull} { if { ![application_group::contains_segment_p -segment_id $rel_segment]} { ad_complain "The relational segment either does not exist or does not belong to this subsite." } } segment_in_scope_p -requires {required_rel_segment:notnull} { if { ![application_group::contains_segment_p -segment_id $required_rel_segment]} { ad_complain "The required relational segment either does not exist or does not belong to this subsite." } } } set return_url_enc [ad_urlencode "[ad_conn url]?[ad_export_vars {rel_segment constraint_name rel_side required_rel_segment return_url}]"] set context [list [list "../" "Relational segments"] [list "../one?segment_id=$rel_segment" "One Segment"] "Add constraint"] set package_id [ad_conn package_id] db_1row select_rel_properties { select s.segment_name, acs_rel_type.role_pretty_name(t.role_one) as role_one_name, acs_rel_type.role_pretty_name(t.role_two) as role_two_name from rel_segments s, acs_rel_types t where s.rel_type = t.rel_type and s.segment_id = :rel_segment } template::form create constraint_new template::element create constraint_new rel_segment \ -value $rel_segment \ -datatype text \ -widget hidden template::element create constraint_new return_url \ -optional \ -value $return_url \ -datatype text \ -widget hidden template::element create constraint_new constraint_name \ -label "Constraint name" \ -datatype text \ -widget text \ -html {maxlength 100} set option_list [list \ [list "-- Select --" ""] \ [list "$role_one_name (Side 1)" one] \ [list "$role_two_name (Side 2)" two]] template::element create constraint_new rel_side \ -datatype "text" \ -widget select \ -options $option_list \ -label "Add constraint for which side?" set segment_list [db_list_of_lists select_segments { select s.segment_name, s.segment_id from application_group_segments s where s.segment_id <> :rel_segment and s.package_id = :package_id order by lower(s.segment_name) }] if { [llength $segment_list] == 0 } { ad_return_complaint 1 "
  • There are currently no other segments. You must have at least two segments before you can create a constraint" return } template::element create constraint_new required_rel_segment \ -datatype "text" \ -widget select \ -options $segment_list \ -label "Select segment" if { [template::form is_valid constraint_new] } { # To what should we set context_id? set creation_user [ad_conn user_id] set creation_ip [ad_conn peeraddr] set ctr 0 db_transaction { set constraint_id [db_exec_plsql add_constraint { BEGIN :1 := rel_constraint.new(constraint_name => :constraint_name, rel_segment => :rel_segment, rel_side => :rel_side, required_rel_segment => :required_rel_segment, creation_user => :creation_user, creation_ip => :creation_ip ); END; }] # check for violations template::multirow create violations rel_id name db_foreach select_violated_rels { select viol.rel_id, acs_object.name(viol.party_id) as name from rel_constraints_violated_one viol where viol.constraint_id = :constraint_id UNION ALL select viol.rel_id, acs_object.name(viol.party_id) as name from rel_constraints_violated_two viol where viol.constraint_id = :constraint_id } { template::multirow append violations $rel_id $name incr ctr } if { $ctr > 0 } { # there are violations... abort the transaction then show # the user the erroneous relations db_abort_transaction } } on_error { if { $ctr == 0 } { # Return the error message ad_return_error "Error creating the constraint" "We got the following error while trying to create the constraint:
    $errmsg
    " return } } if { $ctr > 0 } { # show the user the erroneous relations, then abort ad_return_template violations return } if { $return_url eq "" } { set return_url "../one?segment_id=$rel_segment" } ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/new.xql0000644000175000017500000000052707511410703027204 0ustar frankiefrankie select s.segment_name, s.segment_id from application_group_segments s where s.segment_id <> :rel_segment and s.package_id = :package_id order by lower(s.segment_name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/index.adp0000644000175000017500000000107507663155030027470 0ustar frankiefrankie @context;noquote@ Relational Constraint Administration Currently, the system is able to handle the following relational constraints: Note: Relational constraints are created from the relational segment administration pages openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/index.tcl0000644000175000017500000000213607536221412027502 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/constraints/index.tcl ad_page_contract { Shows all constraints on which the user has read permission @author mbryzek@arsdigita.com @creation-date Fri Dec 15 11:30:52 2000 @cvs-id $Id: index.tcl,v 1.2 2002/09/06 21:50:02 jeffd Exp $ } set context [list [list ../ "Relational segments"] "Constraints"] set user_id [ad_conn user_id] set package_id [ad_conn package_id] # Select out basic information about all the constraints on which the # user has read permission db_multirow constraints select_rel_constraints { select c.constraint_id, c.constraint_name from rel_constraints c, acs_object_party_privilege_map perm, application_group_segments s1, application_group_segments s2 where perm.object_id = c.constraint_id and perm.party_id = :user_id and perm.privilege = 'read' and s1.segment_id = c.rel_segment and s1.package_id = :package_id and s2.segment_id = c.required_rel_segment and s2.package_id = :package_id order by lower(c.constraint_name) } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/index.xql0000644000175000017500000000136407401257304027526 0ustar frankiefrankie select c.constraint_id, c.constraint_name from rel_constraints c application_group_segments s1, application_group_segments s2 where s1.segment_id = c.rel_segment and s1.package_id = :package_id and s2.segment_id = c.required_rel_segment and s2.package_id = :package_id and exists (select 1 from all_object_party_privilege_map perm where perm.object_id = c.constraint_id and perm.party_id = :user_id and perm.privilege = 'read') order by lower(c.constraint_name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete-2-oracle.xql0000644000175000017500000000043207736271233031266 0ustar frankiefrankie oracle8.1.6 begin rel_constraint.del(constraint_id => :constraint_id); end; openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/one.adp0000644000175000017500000000132107663155030027134 0ustar frankiefrankie @context;noquote@ @props.constraint_name;noquote@ All elements in side @props.rel_side@ of the segment @props.segment_name@ must be in the segment @props.req_segment_name@

    In other words, before creating a @rel.rel_type_pretty_name@ to the group @props.group_name@, the @rel.role_pretty_name@ must be a @req_rel.role_pretty_name@ of the group @props.req_group_name@.

    Administration

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/one.tcl0000644000175000017500000001047607741522517027172 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/constraints/one.tcl ad_page_contract { Shows information about one constraint @author mbryzek@arsdigita.com @creation-date Thu Dec 14 18:06:02 2000 @cvs-id $Id: one.tcl,v 1.3 2003/10/10 12:25:51 lars Exp $ } { constraint_id:naturalnum,notnull } -properties { context:onevalue admin_p:onevalue props:onerow rel:onerow req_rel:onerow } ad_require_permission $constraint_id read set admin_p [ad_permission_p $constraint_id admin] set package_id [ad_conn package_id] # Pull out the information about the constraint, required segments, # associated relationship type, and associated roles. # We are driving this query off of rel_constraints: # # rel_side: Identifies the object that must be in # required_rel_segment # # rel_segment: Identifies the segment for which we've created this # constraint # # required_rel_segment: Identifies the segment to which the object # (itself identified by rel_side) must belong before belonging to # rel_segment if { ![db_0or1row select_constraint_properties {} -column_array props] } { ad_return_error "Error" "Constraint #$constraint_id could not be found or is out of the scope of this subsite." return } set segment_id $props(segment_id) set context [list [list "../" "Relational segments"] [list "../one?segment_id=$props(segment_id)" "One Segment"] "One constraint"] # Now we pull out information about the relationship types for each # segment. The outer join is there in case the role in acs_rel_types # is null. Finally, note that we choose to do these queries separately # because they would be too hard to read in one query. set rel_type $props(rel_type) db_1row select_rel_type_info { select role1.role as role_one, nvl(role1.pretty_name,'Object on side one') as role_one_pretty_name, nvl(role1.pretty_plural,'Objects on side one') as role_one_pretty_plural, role2.role as role_two, nvl(role2.pretty_name,'Object on side two') as role_two_pretty_name, nvl(role2.pretty_plural,'Objects on side two') as role_two_pretty_plural, acs_object_type.pretty_name(rel.rel_type) as rel_type_pretty_name from acs_rel_types rel, acs_rel_roles role1, acs_rel_roles role2 where rel.rel_type = :rel_type and rel.role_one = role1.role(+) and rel.role_two = role2.role(+) } -column_array rel set rel_type $props(req_rel_type) db_1row select_rel_type_info { select role1.role as role_one, nvl(role1.pretty_name,'Object on side one') as role_one_pretty_name, nvl(role1.pretty_plural,'Objects on side one') as role_one_pretty_plural, role2.role as role_two, nvl(role2.pretty_name,'Object on side two') as role_two_pretty_name, nvl(role2.pretty_plural,'Objects on side two') as role_two_pretty_plural, acs_object_type.pretty_name(rel.rel_type) as rel_type_pretty_name from acs_rel_types rel, acs_rel_roles role1, acs_rel_roles role2 where rel.rel_type = :rel_type and rel.role_one = role1.role(+) and rel.role_two = role2.role(+) } -column_array req_rel # Choose the appropriate role based on the side of the relation used # in this constraint. set rel_side $props(rel_side) set rel(role) $rel(role_${rel_side}) set rel(role_pretty_name) [lang::util::localize $rel(role_${rel_side}_pretty_name)] set rel(role_pretty_plural) [lang::util::localize $rel(role_${rel_side}_pretty_plural)] set req_rel(role) $req_rel(role_${rel_side}) set req_rel(role_pretty_name) [lang::util::localize $req_rel(role_${rel_side}_pretty_name)] set req_rel(role_pretty_plural) [lang::util::localize $req_rel(role_${rel_side}_pretty_plural)] # Now query for any violations. Note that we use union all since we # know that the two views contain independent elements. # Removed this query 1/18/2001 - constraints enforced in the data # model. There are never any violations. # db_multirow violations select_violated_rels { # select viol.rel_id, acs_object.name(viol.party_id) as name # from rel_constraints_violated_one viol # where viol.constraint_id = :constraint_id # UNION ALL # select viol.rel_id, acs_object.name(viol.party_id) as name # from rel_constraints_violated_two viol # where viol.constraint_id = :constraint_id # } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete.adp0000644000175000017500000000067707663155030027632 0ustar frankiefrankie @context;noquote@ Delete @constraint_name;noquote@ Are you sure you want to delete the constraint @constraint_name@ on segment @segment_name@?

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete.tcl0000644000175000017500000000224107542067252027641 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/constraints/delete.tcl ad_page_contract { Confirms deletions of a constraint @author mbryzek@arsdigita.com @creation-date Fri Dec 15 11:22:34 2000 @cvs-id $Id: delete.tcl,v 1.3 2002/09/18 12:16:42 jeffd Exp $ } { constraint_id:naturalnum,notnull { return_url "" } } -properties { context:onevalue constraint_name:onevalue segment_name:onevalue export_vars:onevalue } set context [list [list one?[ad_export_vars constraint_id] "One constraint"] "Delete constraint"] set package_id [ad_conn package_id] if { ![db_0or1row select_constraint_props { select c.constraint_name, s.segment_name from rel_constraints c, application_group_segments s, application_group_segments s2 where c.rel_segment = s.segment_id and c.constraint_id = :constraint_id and s.package_id = :package_id and s2.segment_id = c.required_rel_segment and s2.package_id = :package_id }] } { # The constraint is already deleted.... return ad_returnredirect $return_url ad_script_abort } set export_vars [ad_export_vars -form {constraint_id return_url}] openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete.xql0000644000175000017500000000100107300260124027635 0ustar frankiefrankie select c.constraint_name, s.segment_name from rel_constraints c, application_group_segments s, application_group_segments s2 where c.rel_segment = s.segment_id and c.constraint_id = :constraint_id and s.package_id = :package_id and s2.segment_id = c.required_rel_segment and s2.package_id = :package_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/violations.adp0000644000175000017500000000067107663155030030551 0ustar frankiefrankie @context;noquote@ Violations exists The following relations are in violation of the constraint you are adding. You must remove these relations before you can add the constraint: openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/one-oracle.xql0000644000175000017500000000307107741522517030450 0ustar frankiefrankie oracle8.1.6 select c.constraint_id, c.constraint_name, c.rel_side, s.segment_id, s.segment_name, s.rel_type, acs_group.name(s.group_id) as group_name, s2.segment_id as req_segment_id, s2.segment_name as req_segment_name, s2.rel_type as req_rel_type, acs_group.name(s2.group_id) as req_group_name from application_group_segments s, application_group_segments s2, rel_constraints c where s.segment_id = c.rel_segment and s2.segment_id = c.required_rel_segment and c.constraint_id = :constraint_id and s.package_id = :package_id select role1.role as role_one, nvl(role1.pretty_name,'Object on side one') as role_one_pretty_name, nvl(role1.pretty_plural,'Objects on side one') as role_one_pretty_plural, role2.role as role_two, nvl(role2.pretty_name,'Object on side two') as role_two_pretty_name, nvl(role2.pretty_plural,'Objects on side two') as role_two_pretty_plural, acs_object_type.pretty_name(rel.rel_type) as rel_type_pretty_name from acs_rel_types rel, acs_rel_roles role1, acs_rel_roles role2 where rel.rel_type = :rel_type and rel.role_one = role1.role(+) and rel.role_two = role2.role(+) openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/constraints/delete-2-postgresql.xql0000644000175000017500000000043607346724754032240 0ustar frankiefrankie postgresql7.1 begin perform rel_constraint__delete(:constraint_id); return null; end; openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/delete-2.tcl0000644000175000017500000000226210551254377025434 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/delete-2.tcl ad_page_contract { Deletes the relational segment @author mbryzek@arsdigita.com @creation-date Tue Dec 12 11:23:12 2000 @cvs-id $Id: delete-2.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { segment_id:integer,notnull { operation "" } { return_url "" } } -validate { segment_exists_p -requires {segment_id:notnull} { if { ![rel_segments_permission_p -privilege delete $segment_id] } { ad_complain "The segment either does not exist or you do not have permission to delete it" } } } if {$operation eq "Yes, I really want to delete this segment"} { if { $return_url eq "" } { # Go back to the group for this segment set group_id [db_string select_group_id { select s.group_id from rel_segments s where s.segment_id = :segment_id } -default ""] if { $group_id ne "" } { set return_url "../groups/one?[ad_export_vars group_id]" } } # Delete all the constraints that require this segment db_transaction { rel_segments_delete $segment_id } } if { $return_url eq "" } { set return_url "one?[ad_export_vars {segment_id}]" } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/delete-2.xql0000644000175000017500000000034107300260124025433 0ustar frankiefrankie select s.group_id from rel_segments s where s.segment_id = :segment_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements-display-oracle.xql0000644000175000017500000000113107766162053030574 0ustar frankiefrankie oracle8.1.6 select acs_object.name(map.party_id) as name, map.rel_id, decode(map.container_id, :group_id, 1, 0) as direct_p, acs_object.name(map.container_id) as container_name from rel_segment_party_map map where acs_permission.permission_p(map.party_id, :user_id, 'read') = 't' and map.segment_id = :segment_id order by lower(name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/one-postgresql.xql0000644000175000017500000000113307661404104027024 0ustar frankiefrankie postgresql7.1 select s.segment_id, s.segment_name, s.group_id, acs_object__name(s.group_id) as group_name, s.rel_type, acs_object_type__pretty_name(r.rel_type) as rel_type_pretty_name, acs_rel_type__role_pretty_plural(r.role_two) as role_pretty_plural from rel_segments s, acs_rel_types r where s.segment_id = :segment_id and s.rel_type = r.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-oracle.xql0000644000175000017500000000143007300260124026066 0ustar frankiefrankie oracle8.1.6 select t.pretty_name, t.object_type as rel_type, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent from acs_object_types t where t.object_type not in (select s.rel_type from rel_segments s where s.group_id = :group_id) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel', 'composition_rel') order by lower(t.pretty_name) desc select acs_group.name(:group_id) as group_name from dual openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements-postgresql.xql0000644000175000017500000000070207300260124030050 0ustar frankiefrankie postgresql7.1 select s.segment_name, s.group_id, acs_rel_type__role_pretty_plural(r.role_two) as role_pretty_plural from rel_segments s, acs_rel_types r where s.segment_id = :segment_id and s.rel_type = r.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new.adp0000644000175000017500000000171407663154776024623 0ustar frankiefrankie @context;noquote@ Create relational segment segment_new.segment_name There are no relationship types for which to create segments You are creating a segment for @group_name@ @group_name@

    @export_vars;noquote@ Segment Name:

    Relationship type for which to create the segment:

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new.tcl0000644000175000017500000000337010551254377024625 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/new.tcl ad_page_contract { Form to create a new relational segment @author mbryzek@arsdigita.com @creation-date Mon Dec 11 13:51:21 2000 @cvs-id $Id: new.tcl,v 1.3 2007/01/10 21:22:07 gustafn Exp $ } { group_id:integer,notnull { rel_type:trim "" } { return_url "" } } -properties { context:onevalue export_vars:onevalue group_id:onevalue primary_rels:multirow group_name:onevalue subsite_group_id:onevalue } -validate { group_in_scope_p -requires {group_id:notnull} { if { ![application_group::contains_party_p -party_id $group_id -include_self]} { ad_complain "The group either does not exist or does not belong to this subsite." } } } set subsite_group_id [application_group::group_id_from_package_id] # If the user has specified a rel_type, redirect to new-2 if { $rel_type ne "" } { ad_returnredirect new-2?[ad_export_vars {group_id rel_type return_url}] ad_script_abort } ad_require_permission $group_id "read" set context [list [list "" "Relational segments"] "Add segment"] set export_vars [ad_export_vars -form {group_id return_url}] # Select out all relationship types db_multirow rel_types select_relation_types { select t.pretty_name, t.object_type as rel_type, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent from acs_object_types t where t.object_type not in (select s.rel_type from rel_segments s where s.group_id = :group_id) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel', 'composition_rel') order by lower(t.pretty_name) desc } db_1row select_basic_info { select acs_group.name(:group_id) as group_name from dual } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-3-postgresql.xql0000644000175000017500000000055407300260124027172 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from rel_segments s where s.segment_id <> :segment_id) then 1 else 0 end openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/index-postgresql.xql0000644000175000017500000000130107401227553027352 0ustar frankiefrankie postgresql7.1 select s.segment_id, s.segment_name, s.group_id, acs_object__name(s.group_id) as group_name, s.rel_type, t.pretty_name as rel_type_pretty_name from acs_object_types t, rel_segments s, application_group_segments ags where acs_permission__permission_p(s.segment_id, :user_id, 'read') and t.object_type = s.rel_type and s.segment_id = ags.segment_id and ags.package_id = :package_id order by lower(s.segment_name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/index.adp0000644000175000017500000000130511553071716025116 0ustar frankiefrankie @context;noquote@ @doc.title@

    @doc.title@

    #acs-subsite.Currently_the_system_is_able_to_handle_the_following_relational_segments#

    #acs-subsite.Note_Relational_segments_are_created_from_the_groups_administration_pages#

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/index.tcl0000644000175000017500000000237611553071716025145 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/index.tcl ad_page_contract { Shows all relational segments that the user has read permission on @author mbryzek@arsdigita.com @creation-date Mon Dec 11 12:13:02 2000 @cvs-id $Id: index.tcl,v 1.3 2011/04/18 17:24:30 emmar Exp $ } { } -properties { context:onevalue seg:multirow } set context [list [_ acs-subsite.Relational_Segments]] set doc(title) [_ acs-subsite.Relational_Segment_administration] set user_id [ad_conn user_id] set package_id [ad_conn package_id] # Select out basic information about all the segments on which the # user has read permission db_multirow seg select_rel_segments { select s.segment_id, s.segment_name, s.group_id, acs_object.name(s.group_id) as group_name, s.rel_type, t.pretty_name as rel_type_pretty_name from acs_object_types t, rel_segments s, acs_object_party_privilege_map perm, application_group_segments ags where perm.object_id = s.segment_id and perm.party_id = :user_id and perm.privilege = 'read' and t.object_type = s.rel_type and s.segment_id = ags.segment_id and ags.package_id = :package_id order by lower(s.segment_name) } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements-oracle.xql0000644000175000017500000000067507335322027027134 0ustar frankiefrankie oracle8.1.6 select s.segment_name, s.group_id, acs_rel_type.role_pretty_plural(r.role_two) as role_pretty_plural from rel_segments s, acs_rel_types r where s.segment_id = :segment_id and s.rel_type = r.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements.adp0000644000175000017500000000044207663154776025643 0ustar frankiefrankie @context;noquote@ @segment_name;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/elements.tcl0000644000175000017500000000253107573650145025651 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/elements.tcl ad_page_contract { Shows elements for one relational segment @author mbryzek@arsdigita.com @creation-date Tue Dec 12 17:52:03 2000 @cvs-id $Id: elements.tcl,v 1.5 2002/12/05 13:11:01 peterm Exp $ } { segment_id:integer,notnull } -properties { context:onevalue segment_id:onevalue segment_name:onevalue role_pretty_plural:onevalue elements:multirow } -validate { segment_exists_p -requires {segment_id:notnull} { if { ![rel_segments_permission_p $segment_id] } { ad_complain "The segment either does not exist or you do not have permission to view it" } } } db_1row select_segment_info { select s.segment_name, s.group_id, acs_rel_type.role_pretty_plural(r.role_two) as role_pretty_plural from rel_segments s, acs_rel_types r where s.segment_id = :segment_id and s.rel_type = r.rel_type } # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_pretty_plural [lang::util::localize $role_pretty_plural] set context [list [list "[ad_conn package_url]admin/rel-segments/" "Relational segments"] [list one?[ad_export_vars {segment_id}] "One segment"] "Elements"] # Expects segment_id, segment_name, group_id, role to be passed in ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-2-oracle.xql0000644000175000017500000000063407300260124026232 0ustar frankiefrankie oracle8.1.6 select acs_group.name(:group_id) as group_name, nvl(acs_rel_type.role_pretty_plural(t.role_two),'Elements') as role_pretty_plural from acs_rel_types t where t.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/one.adp0000644000175000017500000000235107723347124024575 0ustar frankiefrankie @context;noquote@ Segment "@props.segment_name;noquote@"

    Properties of this segment

    Constraints on this segment

    Administration

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/one.tcl0000644000175000017500000000415607741522517024621 0ustar frankiefrankie# /packages/subsite/www/admin/rel-segments/one.tcl ad_page_contract { Displays information about one relational segment @author mbryzek@arsdigita.com @creation-date Mon Dec 11 14:38:26 2000 @cvs-id $Id: one.tcl,v 1.5 2003/10/10 12:25:51 lars Exp $ } { segment_id:naturalnum,notnull } -properties { context:onevalue props:onerow number_elements:onevalue admin_p:onevalue } -validate { segment_exists_p -requires {segment_id:notnull} { if { ![rel_segments_permission_p $segment_id] } { ad_complain "The segment either does not exist or you do not have permission to view it" } } segment_in_scope_p -requires {segment_id:notnull segment_exists_p} { if { ![application_group::contains_segment_p -segment_id $segment_id]} { ad_complain "The segment either does not exist or does not belong to this subsite." } } } set context [list [list "./" "Relational segments"] "One segment"] if { ![db_0or1row select_segment_properties {} -column_array props] } { ad_return_error "Segment does not exist" "Segment $segment_id does not exist" return } set props(role_pretty_plural) [lang::util::localize $props(role_pretty_plural)] set name_edit_url [export_vars -base edit { segment_id }] # Pull out the number of elements that the current user can see. We do # this separately to avoid the join above. This query may need to # removed or changed to handle the permissions check more efficiently set group_id $props(group_id) set rel_type $props(rel_type) set user_id [ad_conn user_id] db_multirow constraints constraints_select { select c.constraint_id, c.constraint_name, c.rel_side from rel_constraints c where c.rel_segment = :segment_id } db_1row select_segment_info { select count(*) as number_elements from rel_segment_party_map map, acs_object_party_privilege_map perm where perm.object_id = map.party_id and perm.party_id = :user_id and perm.privilege = 'read' and map.segment_id = :segment_id } set number_elements [util_commify_number $number_elements] set admin_p [ad_permission_p $segment_id "admin"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/one.xql0000644000175000017500000000141007661404104024621 0ustar frankiefrankie select c.constraint_id, c.constraint_name, c.rel_side from rel_constraints c where c.rel_segment = :segment_id select count(*) as number_elements from rel_segment_party_map map where map.segment_id = :segment_id and exists (select 1 from acs_object_party_privilege_map perm where perm.object_id = map.party_id and perm.party_id = :user_id and perm.privilege = 'read') openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/index-oracle.xql0000644000175000017500000000142607300260124026411 0ustar frankiefrankie oracle8.1.6 select s.segment_id, s.segment_name, s.group_id, acs_object.name(s.group_id) as group_name, s.rel_type, t.pretty_name as rel_type_pretty_name from acs_object_types t, rel_segments s, acs_object_party_privilege_map perm, application_group_segments ags where perm.object_id = s.segment_id and perm.party_id = :user_id and perm.privilege = 'read' and t.object_type = s.rel_type and s.segment_id = ags.segment_id and ags.package_id = :package_id order by lower(s.segment_name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/delete.adp0000644000175000017500000000100407663154776025264 0ustar frankiefrankie @context;noquote@ Remove segment Are you sure you want to remove the relational segment @segment_name@? Removing this segment will also remove all relational constraints that required elements to be in this segment.

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/delete.tcl0000644000175000017500000000176407536221411025273 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/delete.tcl ad_page_contract { Confirms delete of relational segment @author mbryzek@arsdigita.com @creation-date Tue Dec 12 11:23:12 2000 @cvs-id $Id: delete.tcl,v 1.3 2002/09/06 21:50:01 jeffd Exp $ } { segment_id:integer,notnull { return_url "" } } -properties { export_vars:onevalue segment_name:onevalue } -validate { segment_exists_p -requires {segment_id:notnull} { if { ![rel_segments_permission_p -privilege delete $segment_id] } { ad_complain "The segment either does not exist or you do not have permission to delete it" } } } db_1row select_segment_info { select s.segment_name from rel_segments s where s.segment_id = :segment_id } set export_vars [export_form_vars segment_id] set context [list \ [list "[ad_conn package_url]admin/rel-segments/" "Relational segments"] \ [list one?[ad_export_vars segment_id] "One segment"] \ "Remove segment"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/delete.xql0000644000175000017500000000036307300260124025300 0ustar frankiefrankie select s.segment_name from rel_segments s where s.segment_id = :segment_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-2-postgresql.xql0000644000175000017500000000064507300260124027172 0ustar frankiefrankie postgresql7.1 select acs_group__name(:group_id) as group_name, coalesce(acs_rel_type__role_pretty_plural(t.role_two),'Elements') as role_pretty_plural from acs_rel_types t where t.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-3-oracle.xql0000644000175000017500000000056307300260124026234 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from rel_segments s where s.segment_id <> :segment_id) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/one-oracle.xql0000644000175000017500000000112607300260124026060 0ustar frankiefrankie oracle8.1.6 select s.segment_id, s.segment_name, s.group_id, acs_object.name(s.group_id) as group_name, s.rel_type, acs_object_type.pretty_name(r.rel_type) as rel_type_pretty_name, acs_rel_type.role_pretty_plural(r.role_two) as role_pretty_plural from rel_segments s, acs_rel_types r where s.segment_id = :segment_id and s.rel_type = r.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-2.adp0000644000175000017500000000121407663154776024755 0ustar frankiefrankie @context;noquote@ Create relational segment segment_new.segment_name You are creating a segment to represent all @role_pretty_plural@ of @group_name@ @group_name@

    @export_vars;noquote@ Segment Name:

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-2.tcl0000644000175000017500000000332007573650145024762 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/new-2.tcl ad_page_contract { Form to create a new relational segment (Use this only if you know the relationship type in advance. @author mbryzek@arsdigita.com @creation-date Mon Dec 11 13:51:21 2000 @cvs-id $Id: new-2.tcl,v 1.4 2002/12/05 13:11:01 peterm Exp $ } { group_id:integer,notnull rel_type:notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue group_id:onevalue role_pretty_plural:onevalue group_name:onevalue } -validate { group_in_scope_p -requires {group_id:notnull} { if { ![application_group::contains_party_p -party_id $group_id -include_self]} { ad_complain "The group either does not exist or does not belong to this subsite." } } relation_in_scope_p -requires {rel_id:notnull permission_p} { if { ![application_group::contains_relation_p -rel_id $rel_id]} { ad_complain "The relation either does not exist or does not belong to this subsite." } } } set subsite_group_id [application_group::group_id_from_package_id] ad_require_permission $group_id "read" set context [list [list "[ad_conn package_url]admin/rel-segments/" "Relational segments"] "Add segment"] set export_vars [ad_export_vars -form {group_id rel_type return_url}] db_1row select_basic_info { select acs_group.name(:group_id) as group_name, nvl(acs_rel_type.role_pretty_plural(t.role_two),'Elements') as role_pretty_plural from acs_rel_types t where t.rel_type = :rel_type } # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_pretty_plural [lang::util::localize $role_pretty_plural] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-3.adp0000644000175000017500000000102707663154776024760 0ustar frankiefrankie @context;noquote@ Add Constraint on @segment_name;noquote@ Now that you have created a relational segment, you can create relational constraints on this segment. Relational constraints allow you to apply rules on inter-party relationships.

    Would you like to create a constraint now?

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-3.tcl0000644000175000017500000000424410551254377024766 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-segments/new-3.tcl ad_page_contract { Creates a relational segment. Finished by asking the user to create constraints @author mbryzek@arsdigita.com @creation-date Wed Dec 13 20:00:25 2000 @cvs-id $Id: new-3.tcl,v 1.4 2007/01/10 21:22:07 gustafn Exp $ } { group_id:integer,notnull segment_name:notnull rel_type:notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue segment_name:onevalue } -validate { group_in_scope_p -requires {group_id:notnull} { if { ![application_group::contains_party_p -party_id $group_id -include_self]} { ad_complain "The group either does not exist or does not belong to this subsite." } } relation_in_scope_p -requires {rel_id:notnull permission_p} { if { ![application_group::contains_relation_p -rel_id $rel_id]} { ad_complain "The relation either does not exist or does not belong to this subsite." } } } # Make sure we are creating a segment on a group we can actually see ad_require_permission $group_id "read" db_transaction { set segment_id [rel_segments_new -context_id $group_id $group_id $rel_type $segment_name] } on_error { # Let's see if this segment already exists set segment_id [db_string select_segment_id { select s.segment_id from rel_segments s where s.group_id = :group_id and s.rel_type = :rel_type } -default ""] if { $segment_id eq "" } { ad_return_error "Error creating segment" $errmsg ad_script_abort } } # Now let's offer to walk the user through the process of creating # constraints it there are any other segments if { ![db_string segments_exists_p { select case when exists (select 1 from rel_segments s where s.segment_id <> :segment_id) then 1 else 0 end from dual }] } { # No more segments... can't create constraints ad_returnredirect $return_url return } set context [list [list "[ad_conn package_url]admin/rel-segments/" "Relational segments"] [list one?[ad_export_vars segment_id] "One segment"] "Create constraints"] set export_vars [ad_export_vars -form {segment_id return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-segments/new-3.xql0000644000175000017500000000040407300260124024763 0ustar frankiefrankie select s.segment_id from rel_segments s where s.group_id = :group_id and s.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/permissions.adp0000644000175000017500000000035307723347124023762 0ustar frankiefrankie @page_title@ @context@ openacs-5.7.0/packages/acs-subsite/www/admin/permissions.tcl0000644000175000017500000000052007723347124023774 0ustar frankiefrankiead_page_contract { Permissions for the subsite itself. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-13 @cvs-id $Id: permissions.tcl,v 1.2 2003/08/28 09:41:40 lars Exp $ } set page_title "[ad_conn instance_name] Permissions" set context [list "Permissions"] set subsite_id [ad_conn subsite_id] openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/0000755000175000017500000000000011724401447023366 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/index-postgresql.xql0000644000175000017500000000066510214710210027413 0ustar frankiefrankie postgresql7.1 select site_node__node_id('/', null) select host, node_id, site_node__url(node_id) as url from host_node_map openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/index.adp0000644000175000017500000000055211553376447025200 0ustar frankiefrankie @page_title@ @context@

    @page_title@

    #acs-subsite.Registered_hostname_URL_pairs#

    #acs-subsite.Add_another_hostname_URL_pair#

    openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/index.tcl0000644000175000017500000000420511553376447025215 0ustar frankiefrankiead_page_contract { @author Mark Dettinger (mdettinger@arsdigita.com) @author Michael Steigman (michael@steigman.net) @creation-date 2000-10-24 @cvs-id $Id: index.tcl,v 1.9 2011/04/19 21:22:47 emmar Exp $ } { } set page_title [_ acs-subsite.Host_Node_Map] set context [list $page_title] template::list::create \ -name host_node_pairs \ -multirow host_node_pairs \ -key node_id \ -elements { host { label "[_ acs-subsite.Hostname]" } node_id { label "[_ acs-subsite.Root_Node]" } url { label "[_ acs-subsite.Root_URL]" } delete_url { display_template "delete" } } template::multirow create host_node_pairs host node_id url delete_url template::multirow append host_node_pairs \ [ns_config ns/server/[ns_info server]/module/nssock Hostname] \ [db_string root_id "select site_node.node_id('/') from dual"] \ "/" \ "" db_multirow -extend {delete_url} -append host_node_pairs select_host_node_pairs {} { set delete_url [export_vars -base delete {host node_id}] } set node_list [list] foreach node_id [site_node::get_children -all -element node_id -node_id [site_node::get_node_id -url "/"]] { lappend node_list [list [site_node::get_element -node_id $node_id -element url] $node_id] } set sorted_node_list [lsort $node_list] ad_form -name add_host_node_mapping -form { {host:text(text) {label "[_ acs-subsite.Hostname]"} {html {size 40}} {value "mydomain.com"} {help_text "[_ acs-subsite.Hostname_must_be_unique]"} } {root:text(radio) {label "[_ acs-subsite.Root_Node]"} {options $sorted_node_list} {help_text "[_ acs-subsite.Site_node_you_would_like_to_map_hostname_to]"} } {submit:text(submit) {label "[_ acs-subsite.Add_Pair]"} } } -validate { {host {![db_string check_host "select 1 from host_node_map where host = :host" -default 0]} "Host must be unique" } } -on_submit { util_memoize_flush_regexp "rp_lookup_node_from_host" db_dml host_node_insert {} } -after_submit { ad_returnredirect index } openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/index.xql0000644000175000017500000000052410214710210025204 0ustar frankiefrankie insert into host_node_map (host, node_id) values (:host, :root) select node_id from site_nodes openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/index-oracle.xql0000644000175000017500000000066410214710210026454 0ustar frankiefrankie oracle8.1.6 select site_node.node_id('/') from dual select host, node_id, site_node.url(node_id) as url from host_node_map openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/delete.tcl0000644000175000017500000000063307661404066025343 0ustar frankiefrankiead_page_contract { @author Mark Dettinger (mdettinger@arsdigita.com) @creation-date 2000-10-24 @cvs-id $Id: delete.tcl,v 1.3 2003/05/17 10:00:22 jeffd Exp $ } { host node_id:integer } # Flush the cache util_memoize_flush_regexp "rp_lookup_node_from_host" db_dml host_node_delete { delete from host_node_map where host = :host and node_id = :node_id } ad_returnredirect index openacs-5.7.0/packages/acs-subsite/www/admin/host-node-map/delete.xql0000644000175000017500000000032507361110061025345 0ustar frankiefrankie delete from host_node_map where host = :host and node_id = :node_id openacs-5.7.0/packages/acs-subsite/www/admin/configure.adp0000644000175000017500000000031307727570425023372 0ustar frankiefrankie @page_title@ @context@ name.instance_name openacs-5.7.0/packages/acs-subsite/www/admin/configure.tcl0000644000175000017500000000413011552012374023372 0ustar frankiefrankiead_page_contract { Configuration home page. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-13 @cvs-id $Id: configure.tcl,v 1.12 2011/04/15 09:50:52 emmar Exp $ } set page_title "[_ acs-subsite.Subsite_Configuration]" set context [list "[_ acs-subsite.Configuration]"] set group_id [application_group::group_id_from_package_id] ad_form -name name -cancel_url [ad_conn url] -mode display -form { {instance_name:text {label "[_ acs-subsite.Subsite_name]"} {html {size 50}} } {theme:text(select) {label "[_ acs-subsite.Theme]"} {help_text "Choose the layout and navigation theme you want for your subsite."} {options [subsite::get_theme_options]} } {visibility:text(select) {label "[_ acs-subsite.Visible_to]"} {options { { "[_ acs-subsite.Members_only]" "members" } { "[_ acs-subsite.Anyone]" "any" } }} } {join_policy:text(select) {label "[_ acs-subsite.Join_policy]"} {options [group::get_join_policy_options]} } {description:text(textarea),optional {label "[_ acs-subsite.Description]"} {html { rows 6 cols 80 }} } } -on_request { set instance_name [ad_conn instance_name] set theme [parameter::get -parameter ThemeKey -package_id [ad_conn package_id]] if { [permission::inherit_p -object_id [ad_conn package_id]] } { set visibility "any" } else { set visibility "members" } set join_policy [group::join_policy -group_id $group_id] set description [group::description -group_id $group_id] } -on_submit { apm_package_rename -instance_name $instance_name subsite::set_theme -theme $theme set group(join_policy) $join_policy set group(description) $description group::update -group_id $group_id -array group switch $visibility { any { permission::set_inherit -object_id [ad_conn package_id] } members { permission::set_not_inherit -object_id [ad_conn package_id] } } } -after_submit { ad_returnredirect [ad_conn url] ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/groups/0000755000175000017500000000000011724401447022232 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-list-postgresql.xql0000644000175000017500000000105507403013337031406 0ustar frankiefrankie postgresql7.1 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select t2.object_type from acs_object_types t1, acs_object_types t2 where t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t1.object_type = :rel_type ) openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-remove-2.tcl0000644000175000017500000000337610551254377026147 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/rel-type-remove-2.tcl ad_page_contract { Removes the specified relation from the list of allowable ones @author mbryzek@arsdigita.com @creation-date Tue Jan 2 12:28:33 2001 @cvs-id $Id: rel-type-remove-2.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { group_rel_id:naturalnum,notnull { return_url "" } { operation:trim "No, I want to cancel my request" } } # Pull out info we need if { ![db_0or1row select_group_id { select g.group_id, g.rel_type from group_rels g, acs_object_types t where g.rel_type = t.object_type and g.group_rel_id = :group_rel_id }] } { # Already removed... just redirect ad_returnredirect $return_url ad_script_abort } if {$operation eq "Yes, I really want to delete this relationship type"} { set rel_id_list [db_list select_rel_ids { select r.rel_id from acs_rels r where r.rel_type = :rel_type and r.object_id_one = :group_id }] db_transaction { # Remove each relation foreach rel_id $rel_id_list { relation_remove $rel_id } # Remove the relational segment for this group/rel type if it exists if { [db_0or1row select_segments { select segment_id from rel_segments where group_id = :group_id and rel_type = :rel_type }] } { rel_segments_delete $segment_id } # now remove this relationship type from the list of allowable # ones for this group db_dml remove_relationship_type { delete from group_rels where group_rel_id = :group_rel_id } } on_error { ad_return_error "Error removing this relationship type" $errmsg ad_script_abort } } if { $return_url eq "" } { set return_url one?[ad_export_vars {group_id}] } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-remove-2.xql0000644000175000017500000000162307300260124026143 0ustar frankiefrankie select g.group_id, g.rel_type from group_rels g, acs_object_types t where g.rel_type = t.object_type and g.group_rel_id = :group_rel_id select r.rel_id from acs_rels r where r.rel_type = :rel_type and r.object_id_one = :group_id select segment_id from rel_segments where group_id = :group_id and rel_type = :rel_type delete from group_rels where group_rel_id = :group_rel_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-group-type-oracle.xql0000644000175000017500000000123607300260124030550 0ustar frankiefrankie oracle8.1.6 select /*+ ORDERED */ t.object_type, t.pretty_name, count(g.group_id) as number_groups from groups g, acs_objects o, acs_object_types t, application_group_element_map app_group where o.object_id = g.group_id and o.object_type = t.object_type and app_group.package_id = :package_id and app_group.element_id = g.group_id group by t.object_type, t.pretty_name order by lower(t.pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-group-type.adp0000644000175000017500000000110511553071716027254 0ustar frankiefrankie
    • #acs-subsite.none#
    openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-group-type.tcl0000644000175000017500000000461507253523116027301 0ustar frankiefrankie# /packages/subsite/www/admin/groups/elements-by-rel-type.tcl # # Datasource for elements-by-rel-type.adp # (meant to be included by other templates) # # Shows the user a summary of components (NOT members!) of the given # group, provided that the the user has permission to see the component. # The components are summarized by their relationship to the given group. # # NOTE: # There is no scope check done here to ensure that the component "belongs" to # the subsite. The pages that use this template already check that the # given group_id is in scope; therefore, all of its components must be in # scope. And even if a developer screws up and uses this template without # checking that the give group_id belongs to the current subsite, the user # would only be able to see components that they have permission to see. # Thus we take the lazy (and efficient) approach of not checking the # scope of the components returned by this datasource. # # Params: group_id # # @author oumi@arsdigita.com # @creation-date 2001-2-6 # @cvs-id $Id: elements-by-group-type.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ # Select out group types that have at least one group. Count up the # number of groups to decide later if we display them all set user_id [ad_conn user_id] set package_id [ad_conn package_id] template::multirow create group_types group_type group_type_enc type_pretty_name number_groups # ISSUE: this doesn't check permissions when generating the number_groups. # So a user might be told that there are 156 groups of type X, then when they # click to zoom in, they see only 10 groups listed (because they only have # permission on 10 groups). I think the group-types/groups-display page # should tell you total number of groups, and tell you "these are the ones # you have read privilege on", so you don't get confused. db_foreach select_group_types { select /*+ ORDERED */ t.object_type, t.pretty_name, count(g.group_id) as number_groups from groups g, acs_objects o, acs_object_types t, application_group_element_map app_group where o.object_id = g.group_id and o.object_type = t.object_type and app_group.package_id = :package_id and app_group.element_id = g.group_id group by t.object_type, t.pretty_name order by lower(t.pretty_name) } { template::multirow append group_types $object_type [ad_urlencode $object_type] $pretty_name $number_groups } openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-group-type.xql0000644000175000017500000000111107300260124027275 0ustar frankiefrankie select t.object_type, t.pretty_name, count(g.group_id) as number_groups from groups g, acs_objects o, acs_object_types t, application_group_element_map app_group where o.object_id = g.group_id and o.object_type = t.object_type and app_group.package_id = :package_id and app_group.element_id = g.group_id group by t.object_type, t.pretty_name order by lower(t.pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/groups/change-join-policy.adp0000644000175000017500000000114007663154741026404 0ustar frankiefrankie @context;noquote@ @group_name;noquote@
    openacs-5.7.0/packages/acs-subsite/www/admin/groups/change-join-policy.tcl0000644000175000017500000000250007536221407026414 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/one.tcl ad_page_contract { View one group. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2001-02-23 @cvs-id $Id: change-join-policy.tcl,v 1.3 2002/09/06 21:49:59 jeffd Exp $ } { group_id:integer,notnull {return_url ""} } -properties { context:onevalue group_id:onevalue group_name:onevalue admin_p:onevalue QQreturn_url:onevalue join_policy:onevalue possible_join_policies:onevalue } -validate { groups_exists_p -requires {group_id:notnull} { if { ![group::permission_p -privilege admin $group_id] } { ad_complain "The group either does not exist or you do not have permission to administer it" } } group_in_scope_p -requires {group_id:notnull} { if { ![application_group::contains_party_p -party_id $group_id]} { ad_complain "The group either does not exist or does not belong to this subsite." } } } set context [list \ [list "[ad_conn package_url]admin/groups/" "Groups"] \ [list "one?group_id=$group_id" "One Group" ] \ "Edit Join Policy"] db_1row group_info { select g.group_name, g.join_policy from groups g where g.group_id = :group_id } set possible_join_policies [list open "needs approval" closed] set QQreturn_url [ad_quotehtml $return_url] ad_return_templateopenacs-5.7.0/packages/acs-subsite/www/admin/groups/change-join-policy.xql0000644000175000017500000000035407300260124026427 0ustar frankiefrankie select g.group_name, g.join_policy from groups g where g.group_id = :group_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-rel-type-postgresql.xql0000644000175000017500000000251207300260124031132 0ustar frankiefrankie postgresql7.1 select g.rel_type, g.group_rel_id, acs_object_type__pretty_name(g.rel_type) as rel_type_pretty_name, s.segment_id, s.segment_name, acs_rel_type__role_pretty_plural(rel_types.role_two) as role_pretty_plural, acs_rel_type__role_pretty_name(rel_types.role_two) as role_pretty_name, rels.num_rels, case when valid_types.group_id = null then 0 else 1 end as rel_type_valid_p from group_rels g left outer join rel_segments s using (group_id, rel_type) left outer join rc_valid_rel_types valid_types using (group_id, rel_type) left outer join (select rel_type, count(*) as num_rels from group_component_map where group_id = :group_id and group_id = container_id group by rel_type UNION ALL select rel_type, count(*) as num_rels from group_approved_member_map where group_id = :group_id and group_id = container_id group by rel_type) rels using (rel_type), acs_rel_types rel_types where g.rel_type = rel_types.rel_type and g.group_id = :group_id order by lower(g.rel_type) openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-postgresql.xql0000644000175000017500000000111707300260124030426 0ustar frankiefrankie postgresql7.1 select acs_group__name(:group_id) as group_name, acs_object_type__pretty_name(:rel_type) as rel_type_pretty_name, acs_rel_type__role_pretty_plural(rel_types.role_two) as role_pretty_plural, acs_rel_type__role_pretty_name(rel_types.role_two) as role_pretty_name from acs_rel_types rel_types where rel_types.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display.adp0000644000175000017500000000107207766162053026207 0ustar frankiefrankie @context;noquote@ @role_pretty_plural;noquote@ of @group_name;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display.tcl0000644000175000017500000000400607573650134026223 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/elements-display.tcl ad_page_contract { Displays all elements in a group with a specified rel_type @author mbryzek@arsdigita.com @creation-date Mon Jan 8 14:01:48 2001 @cvs-id $Id: elements-display.tcl,v 1.4 2002/12/05 13:10:52 peterm Exp $ } { group_id:integer,notnull rel_type:notnull {member_state ""} } -properties { context:onevalue create_p:onevalue group_id:onevalue group_name:onevalue role_pretty_plural:onevalue create_p:onevalue rel_type_enc:onevalue return_url_enc:onevalue member_state:onevalue possible_member_states:multirow ancestor_rel_type:onevalue } -validate { groups_exists_p -requires {group_id:notnull} { if { ![group::permission_p $group_id] } { ad_complain "The group either does not exist or you do not have permission to view it" } } } set user_id [ad_conn user_id] set create_p [ad_permission_p -user_id $user_id $group_id "create"] set return_url_enc [ad_urlencode "[ad_conn url]?[ad_conn query]"] set rel_type_enc [ad_urlencode $rel_type] # Select out the group name and the group's object type. Note we can # use 1row because the validate filter above will catch missing groups db_1row group_and_rel_info { select acs_group.name(:group_id) as group_name, acs_object_type.pretty_name(:rel_type) as rel_type_pretty_name, acs_rel_type.role_pretty_plural(rel_types.role_two) as role_pretty_plural, acs_rel_type.role_pretty_name(rel_types.role_two) as role_pretty_name from acs_rel_types rel_types where rel_types.rel_type = :rel_type } # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_pretty_name [lang::util::localize $role_pretty_name] set role_pretty_plural [lang::util::localize $role_pretty_plural] set context [list [list "[ad_conn package_url]admin/groups/" "Groups"] [list one?[ad_export_vars group_id] "One Group"] "All $role_pretty_plural"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/new-postgresql.xql0000644000175000017500000000106607403013337025751 0ustar frankiefrankie postgresql7.1 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select t2.object_type from acs_object_types t1, acs_object_types t2 where t1.object_type = :add_with_rel_type and t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) ) openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-group-type-postgresql.xql0000644000175000017500000000121207300260124031500 0ustar frankiefrankie postgresql7.1 select t.object_type, t.pretty_name, count(g.group_id) as number_groups from groups g, acs_objects o, acs_object_types t, application_group_element_map app_group where o.object_id = g.group_id and o.object_type = t.object_type and app_group.package_id = :package_id and app_group.element_id = g.group_id group by t.object_type, t.pretty_name order by lower(t.pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-remove-oracle.xql0000644000175000017500000000070507300260124027247 0ustar frankiefrankie oracle8.1.6 select g.rel_type, g.group_id, acs_object.name(g.group_id) as group_name, t.pretty_name as rel_pretty_name from acs_object_types t, group_rels g where g.group_rel_id = :group_rel_id and t.object_type = g.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add-2-postgresql.xql0000644000175000017500000000217307300260124027600 0ustar frankiefrankie postgresql7.1 select count(*) from acs_rel_types t where (t.object_type_one = :group_type or acs_object_type__is_subtype_p(t.object_type_one, :group_type) = 't') and t.rel_type = :rel_type select case when exists (select 1 from group_rels where group_id = :group_id and rel_type = :rel_type) then 1 else 0 end select case when exists (select 1 from rel_segments s where s.group_id = :group_id and s.rel_type = :rel_type) then 1 else 0 end openacs-5.7.0/packages/acs-subsite/www/admin/groups/delete-2.tcl0000644000175000017500000000163010551254377024344 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/delete-2.tcl ad_page_contract { Deletes a group @author mbryzek@arsdigita.com @creation-date Fri Dec 8 14:41:36 2000 @cvs-id $Id: delete-2.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { group_id:integer,notnull { operation "" } { return_url "" } } -validate { groups_exists_p -requires {group_id:notnull} { if { ![group::permission_p $group_id] } { ad_complain "The group either does not exist or you do not have permission to view it" } } } if {$operation eq "Yes, I really want to delete this group"} { db_transaction { set group_type [group::delete $group_id] } if { $return_url eq "" && $group_type ne "" } { set return_url "../group-types/one?[ad_export_vars group_type]" } } else { if { $return_url eq "" } { set return_url "one?[ad_export_vars group_id]" } } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-rel-type.adp0000644000175000017500000000356211553071716026713 0ustar frankiefrankie openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-rel-type.tcl0000644000175000017500000000617711553071716026736 0ustar frankiefrankie# /packages/subsite/www/admin/groups/elements-by-rel-type.tcl # # Datasource for elements-by-rel-type.adp # (meant to be included by other templates) # # Shows the user a summary of elements (components or members) of the given # group, provided that the the user has permission to see the element. # The elements are summarized by their relationship to the given group. # # NOTE: # There is no scope check done here to ensure that the element "belongs" to # the subsite. The pages that use this template already check that the # given group_id is in scope; therefore, all of its elements must be in # scope. And even if a developer screws up and uses this template without # checking that the give group_id belongs to the current subsite, the user # would only be able to see elements that they have permission to see. # Thus we take the lazy (and efficient) approach of not checking the # scope of the elements returned by this datasource. # # Params: group_id # # @author oumi@arsdigita.com # @creation-date 2001-2-6 # @cvs-id $Id: elements-by-rel-type.tcl,v 1.3 2011/04/18 17:24:30 emmar Exp $ set user_id [ad_conn user_id] set admin_p [ad_permission_p $group_id "admin"] set create_p [ad_permission_p $group_id "create"] set return_url "[ad_conn url]?[ad_conn query]" set return_url_enc [ad_urlencode $return_url] db_multirow -extend {elements_display_url relations_add_url} rels relations_query { select g.rel_type, g.group_rel_id, acs_object_type.pretty_name(g.rel_type) as rel_type_pretty_name, s.segment_id, s.segment_name, acs_rel_type.role_pretty_plural(rel_types.role_two) as role_pretty_plural, acs_rel_type.role_pretty_name(rel_types.role_two) as role_pretty_name, rels.num_rels, decode(valid_types.group_id, null, 0, 1) as rel_type_valid_p from group_rels g, rel_segments s, acs_rel_types rel_types, (select rel_type, count(*) as num_rels from group_component_map where group_id = :group_id and group_id = container_id group by rel_type UNION ALL select rel_type, count(*) as num_rels from group_approved_member_map where group_id = :group_id and group_id = container_id group by rel_type) rels, rc_valid_rel_types valid_types where g.group_id = s.group_id(+) and g.rel_type = s.rel_type(+) and g.rel_type = rels.rel_type(+) and g.rel_type = rel_types.rel_type and g.group_id = :group_id and g.group_id = valid_types.group_id(+) and g.rel_type = valid_types.rel_type(+) order by lower(g.rel_type) } { # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_pretty_name [lang::util::localize $role_pretty_name] set role_pretty_plural [lang::util::localize $role_pretty_plural] set elements_display_url [export_vars -url -base "elements-display" {group_id rel_type}] set relations_add_url [export_vars -url -base "../relations/add" {group_id rel_type {return_url $return_url_enc}}] } openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-oracle.xql0000644000175000017500000000111107300260124027462 0ustar frankiefrankie oracle8.1.6 select acs_group.name(:group_id) as group_name, acs_object_type.pretty_name(:rel_type) as rel_type_pretty_name, acs_rel_type.role_pretty_plural(rel_types.role_two) as role_pretty_plural, acs_rel_type.role_pretty_name(rel_types.role_two) as role_pretty_name from acs_rel_types rel_types where rel_types.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-list-oracle.xql0000644000175000017500000000216507300260124030445 0ustar frankiefrankie oracle8.1.6 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :rel_type connect by object_type = prior supertype ) select r.rel_id, party_names.party_name as element_name from (select /*+ ORDERED */ DISTINCT rels.rel_id, object_id_two from $extra_tables acs_rels rels, all_object_party_privilege_map perm where perm.object_id = rels.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and rels.rel_type = :rel_type and rels.object_id_one = :group_id $extra_where_clauses) r, party_names where r.object_id_two = party_names.party_id order by lower(element_name) openacs-5.7.0/packages/acs-subsite/www/admin/groups/new-oracle.xql0000644000175000017500000000102307300260124024776 0ustar frankiefrankie oracle8.1.6 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :add_with_rel_type connect by object_type = prior supertype ) openacs-5.7.0/packages/acs-subsite/www/admin/groups/new.adp0000644000175000017500000000040707733375151023521 0ustar frankiefrankie @context;noquote@ Add a group of type @group_type_pretty_name;noquote@ add_group.group.group_name openacs-5.7.0/packages/acs-subsite/www/admin/groups/new.tcl0000644000175000017500000001226410551254377023541 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/new.tcl ad_page_contract { Adds a new group @author mbryzek@arsdigita.com @creation-date Wed Nov 8 19:29:22 2000 @cvs-id $Id: new.tcl,v 1.6 2007/01/10 21:22:07 gustafn Exp $ } { group_type:notnull { group_type_exact_p t } { group_name "" } { group_id:naturalnum "" } {add_to_group_id ""} {add_with_rel_type "composition_rel"} { return_url "" } {group_rel_type_list ""} } -properties { context:onevalue group_type_pretty_name:onevalue attributes:multirow } -validate { double_click -requires {group_id:notnull} { if { [db_string group_exists_p { select count(*) from groups where group_id = :group_id }] } { ad_complain "The specified group already exists... Maybe you double-clicked?" } } } set context [list [list "[ad_conn package_url]admin/groups/" "Groups"] "Add a group"] if {$add_to_group_id eq ""} { set add_to_group_id [application_group::group_id_from_package_id] } db_1row group_info { select group_name as add_to_group_name, join_policy as add_to_group_join_policy from groups where group_id = :add_to_group_id } # We assume the group is on side 1... db_1row rel_type_info { select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :add_with_rel_type connect by object_type = prior supertype ) } set create_p [group::permission_p -privilege create $add_to_group_id] # Membership relations have a member_state attribute that gets set # based on the group's join policy. if {$ancestor_rel_type eq "membership_rel"} { if {$add_to_group_join_policy eq "closed" && !$create_p} { ad_complain "You do not have permission to add elements to $add_to_group_name" return } set member_state [group::default_member_state -join_policy $add_to_group_join_policy -create_p $create_p] } else { set member_state "" } db_1row select_type_info { select t.pretty_name as group_type_pretty_name, t.table_name from acs_object_types t where t.object_type = :group_type } set export_var_list [list group_id group_type \ add_to_group_id add_with_rel_type return_url] ## ISSUE / TO DO: (see also admin/users/new.tcl) ## ## Should there be a check here for required segments, as there is ## in parties/new.tcl? (see parties/new.tcl, search for ## "relation_required_segments_multirow). ## ## Tentative Answer: we don't need to repeat that semi-heinous check on this ## page, because (a) the user should have gotten to this page through ## parties/new.tcl, so the required segments check should have already ## happened before the user reaches this page. And (b) even if the user ## somehow bypassed parties/new.tcl, they can't cause any relational ## constraint violations in the database because the constraints are enforced ## by triggers in the DB. if { $group_type_exact_p eq "f" && \ [subsite::util::sub_type_exists_p $group_type] } { # Sub rel-types exist... select one set group_type_exact_p "t" set export_url_vars [ad_export_vars -exclude group_type $export_var_list ] party::types_valid_for_rel_type_multirow -datasource_name object_types -start_with $group_type -rel_type $add_with_rel_type set object_type_pretty_name $group_type_pretty_name set this_url [ad_conn url] set object_type_variable group_type ad_return_template ../parties/add-select-type return } template::form create add_group attribute::add_form_elements -form_id add_group -variable_prefix group -start_with group -object_type $group_type attribute::add_form_elements -form_id add_group -variable_prefix rel -start_with relationship -object_type $add_with_rel_type if { [template::form is_request add_group] } { foreach var $export_var_list { template::element create add_group $var \ -value [set $var] \ -datatype text \ -widget hidden } # Set the object id for the new group template::element set_properties add_group group_id \ -value [db_nextval "acs_object_id_seq"] } if { [template::form is_valid add_group] } { db_transaction { group::new -form_id add_group -variable_prefix group -group_id $group_id -context_id [ad_conn package_id] $group_type relation_add -member_state $member_state $add_with_rel_type $add_to_group_id $group_id } # there may be more segments to put this new group in before the # user's original request is complete. So build a return_url stack set package_url [ad_conn package_url] foreach group_rel_type $group_rel_type_list { set next_group_id [lindex $group_rel_type 0] set next_rel_type [lindex $group_rel_type 1] lappend return_url_list \ "${package_url}admin/relations/add?group_id=$next_group_id&rel_type=[ad_urlencode $next_rel_type]&party_id=$group_id&allow_out_of_scope_p=t" } # Add the original return_url as the last one in the list lappend return_url_list $return_url set return_url_stacked [subsite::util::return_url_stack $return_url_list] ad_returnredirect $return_url_stacked ad_script_abort } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/new.xql0000644000175000017500000000127707300260124023546 0ustar frankiefrankie select count(*) from groups where group_id = :group_id select group_name as add_to_group_name, join_policy as add_to_group_join_policy from groups where group_id = :add_to_group_id select t.pretty_name as group_type_pretty_name, t.table_name from acs_object_types t where t.object_type = :group_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add-2.tcl0000644000175000017500000000454211452447070025371 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/rel-type-add-2.tcl ad_page_contract { Adds a relationship type to the list of permissible ones for this group @author mbryzek@arsdigita.com @creation-date Tue Jan 2 12:10:17 2001 @cvs-id $Id: rel-type-add-2.tcl,v 1.4 2010/10/04 21:59:20 victorg Exp $ } { group_id:integer,notnull rel_type:notnull { return_url "" } } -validate { rel_type_acceptable_p -requires {group_id:notnull rel_type:notnull} { # This test makes sure this group can accept the specified rel # type. This means the group is itself a type (or subtype) of # rel_type.object_type_one db_1row select_group_type { select o.object_type as group_type from acs_objects o where o.object_id = :group_id } if { ![db_string types_match_p { select count(*) from acs_rel_types t where (t.object_type_one = :group_type or acs_object_type.is_subtype_p(t.object_type_one, :group_type) = 't') and t.rel_type = :rel_type }] } { ad_complain "Groups of type \"$group_type\" cannot use relationships of type \"$rel_type.\"" } } } if { [catch { set group_rel_id [db_nextval acs_object_id_seq] db_dml insert_rel_type { insert into group_rels (group_rel_id, group_id, rel_type) values (:group_rel_id, :group_id, :rel_type) } } err_msg] } { # Does this pair already exists? if { ![db_string exists_p { select case when exists (select 1 from group_rels where group_id = :group_id and rel_type = :rel_type) then 1 else 0 end from dual }] } { ad_return_error "Error inserting to database" $err_msg return } } # Now let's see if there is no relational segment. If not, offer to create one if { [db_string segment_exists_p { select case when exists (select 1 from rel_segments s where s.group_id = :group_id and s.rel_type = :rel_type) then 1 else 0 end from dual }] } { if { $return_url eq "" } { set return_url one?[ad_export_vars group_id] } ad_returnredirect $return_url } else { ad_returnredirect constraints-create?[ad_export_vars {group_id rel_type return_url}] } openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add-2.xql0000644000175000017500000000037507300260124025401 0ustar frankiefrankie select o.object_type as group_type from acs_objects o where o.object_id = :group_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-remove.adp0000644000175000017500000000141607663154741025767 0ustar frankiefrankie @context;noquote@ Remove @rel_pretty_name;noquote@ Are you sure you want to remove @rel_pretty_name@ from the list of allowable relations for the group @group_name@? Doing so will permanently:
    • Remove all the elements related to this group through this relationship type
    • Remove all relational segments for this relationship type
    • Remove any constraints that relied on a relational segment defined by this group and relationship type

    openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-remove.tcl0000644000175000017500000000220707536221407025775 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/rel-type-remove.tcl ad_page_contract { Confirmation page to remove a given relationship type from the list of allowable ones. @author mbryzek@arsdigita.com @creation-date Tue Jan 2 12:23:02 2001 @cvs-id $Id: rel-type-remove.tcl,v 1.3 2002/09/06 21:49:59 jeffd Exp $ } { group_rel_id:integer,notnull { return_url "" } } -properties { context:onevalue rel_pretty_name:onevalue group_name:onevalue export_vars:onevalue } if { ![db_0or1row select_info { select g.rel_type, g.group_id, acs_object.name(g.group_id) as group_name, t.pretty_name as rel_pretty_name from acs_object_types t, group_rels g where g.group_rel_id = :group_rel_id and t.object_type = g.rel_type }] } { ad_return_error "Relation already removed." "Please back up and reload" return } ad_require_permission $group_id admin set export_vars [ad_export_vars -form {group_rel_id return_url}] set context [list [list "[ad_conn package_url]admin/groups/" "Groups"] [list one?[ad_export_vars {group_id}] "One group"] "Remove relation type"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/index.adp0000644000175000017500000000134611553071716024035 0ustar frankiefrankie @doc.title@ @context;noquote@

    @doc.title@

    @intro_text@

    #acs-subsite.by_group_type# | #acs-subsite.relationship_to_site# #acs-subsite.by_group_type# | #acs-subsite.relationship_to_site#

    #acs-subsite.To_add_a_group_first_select_a_group_type_above_or_go_to_the#

    openacs-5.7.0/packages/acs-subsite/www/admin/groups/index.tcl0000644000175000017500000000212011553071716024042 0ustar frankiefrankie# /packages/subsite/www/admin/groups/index.tcl ad_page_contract { Shows the user all groups on which s/he has permission @author mbryzek@arsdigita.com @creation-date Thu Dec 7 18:09:49 2000 @cvs-id $Id: index.tcl,v 1.4 2011/04/18 17:24:30 emmar Exp $ } { {view_by "group_type"} } -validate { view_by_valid_p { set valid_view_by_list [list group_type rel_type] if { [lsearch $valid_view_by_list $view_by] == -1} { ad_complain "view_by is invalid." } } } -properties { context:onevalue groups:multirow subsite_group_id:onevalue view_by:onevalue } set context [list [_ acs-subsite.Groups]] set doc(title) [_ acs-subsite.Group_administration] set this_url [ad_conn url] set package_id [ad_conn package_id] db_1row subsite_info { select ag.group_id as subsite_group_id, ap.instance_name from application_groups ag, apm_packages ap where ag.package_id = ap.package_id and ag.package_id = :package_id } set intro_text [lang::util::localize [_ acs-subsite.Currently_the_instance_name_has_the_following_groups]] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/index.xql0000644000175000017500000000051407300260124024055 0ustar frankiefrankie select ag.group_id as subsite_group_id, ap.instance_name from application_groups ag, apm_packages ap where ag.package_id = ap.package_id and ag.package_id = :package_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/constraints-create-2.tcl0000644000175000017500000000171010551254377026711 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/constraints-create-2.tcl ad_page_contract { Optionally directs the user to create a relational segment (based on the value of operation) @author mbryzek@arsdigita.com @creation-date Thu Jan 4 11:02:15 2001 @cvs-id $Id: constraints-create-2.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { group_id:notnull,integer rel_type:notnull { operation "" } { return_url "" } } set operation [string trim [string tolower $operation]] if {$operation eq "yes"} { if { $return_url eq "" } { # Setup return_url to send up back to the group admin page # when we're all done set return_url "[ad_conn package_url]/admin/groups/one?[ad_export_vars group_id]" } ad_returnredirect "../rel-segments/new?[ad_export_vars {group_id rel_type return_url}]" } else { if { $return_url eq "" } { set return_url "one?[ad_export_vars group_id]" } ad_returnredirect $return_url } openacs-5.7.0/packages/acs-subsite/www/admin/groups/constraints-create-oracle.xql0000644000175000017500000000057007300260124030023 0ustar frankiefrankie oracle8.1.6 select acs_group.name(:group_id) as group_name, t.pretty_name as rel_type_pretty_name from acs_object_types t where t.object_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add-postgresql.xql0000644000175000017500000000175107723347124027461 0ustar frankiefrankie postgresql7.1 select repeat(' ', (t.type_level - 1) * 4) as indent, t.pretty_name, t.rel_type from (select t2.pretty_name, t2.object_type as rel_type, tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey) + 1 as type_level from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t2.object_type not in (select g.rel_type from group_rels g where g.group_id = :group_id) and t1.object_type in ('membership_rel', 'composition_rel')) t, acs_rel_types rel_type where t.rel_type = rel_type.rel_type and (rel_type.object_type_one = :group_type or acs_object_type__is_subtype_p(rel_type.object_type_one, :group_type) = 't') openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add-oracle.xql0000644000175000017500000000175707300260124026512 0ustar frankiefrankie oracle8.1.6 select replace(lpad(' ', (t.type_level - 1) * 4), ' ', ' ') as indent, t.pretty_name, t.rel_type from (select t.pretty_name, t.object_type as rel_type, level as type_level from acs_object_types t where t.object_type not in (select g.rel_type from group_rels g where g.group_id = :group_id) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel', 'composition_rel')) t, acs_rel_types rel_type where t.rel_type = rel_type.rel_type and (rel_type.object_type_one = :group_type or acs_object_type.is_subtype_p(rel_type.object_type_one, :group_type) = 't') openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-list.adp0000644000175000017500000000143407253523116027152 0ustar frankiefrankie  |  @possible_member_states.label@ @possible_member_states.label@
    • (none)
    1. @rels.element_name@ (remove)
    openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-list.tcl0000644000175000017500000000505610551254377027201 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/elements-display.tcl if { ![exists_and_not_null group_id] } { error "Group must be specified" } if { ![exists_and_not_null rel_type] } { error "Rel type must be specified" } if { ![exists_and_not_null return_url_enc] } { # Default return url to the current page set return_url_enc [ad_urlencode "[ad_conn url]?[ad_conn query]"] } if {![info exists member_state]} { set member_state "approved" } set user_id [ad_conn user_id] # We need to know both: # - does user have admin on group? # - does user have delete on group? set admin_p [ad_permission_p -user_id $user_id $group_id "admin"] if {$admin_p} { # We can skip the permissions check for "delete" because user had admin. set delete_p 1 } else { # user doesn't have admin -- now find out if they have delete. set delete_p [ad_permission_p -user_id $user_id $group_id "delete"] } # Pull out all the relations of the specified type db_1row rel_type_info { select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :rel_type connect by object_type = prior supertype ) } set extra_tables "" set extra_where_clauses "" if {$ancestor_rel_type eq "membership_rel"} { if {$member_state ne ""} { set extra_tables "membership_rels mr," set extra_where_clauses " and mr.rel_id = rels.rel_id and mr.member_state = :member_state" } } db_multirow rels relations_query " select r.rel_id, party_names.party_name as element_name from (select /*+ ORDERED */ DISTINCT rels.rel_id, object_id_two from $extra_tables acs_rels rels, all_object_party_privilege_map perm where perm.object_id = rels.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and rels.rel_type = :rel_type and rels.object_id_one = :group_id $extra_where_clauses) r, party_names where r.object_id_two = party_names.party_id order by lower(element_name) " # Build the member state dimensional slider set base_url [ad_conn package_url]admin/groups/elements-display?[ad_export_vars {group_id rel_type}] template::multirow create possible_member_states \ val label url template::multirow append possible_member_states \ "" "all" $base_url foreach state [group::possible_member_states] { template::multirow append possible_member_states \ $state $state $base_url&member_state=[ad_urlencode $state] } openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-display-list.xql0000644000175000017500000000117507335322027027213 0ustar frankiefrankie select r.rel_id, party_names.party_name as element_name from (select DISTINCT rels.rel_id, object_id_two from $extra_tables acs_rels rels, all_object_party_privilege_map perm where perm.object_id = rels.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and rels.rel_type = :rel_type and rels.object_id_one = :group_id $extra_where_clauses) r, party_names where r.object_id_two = party_names.party_id order by element_name openacs-5.7.0/packages/acs-subsite/www/admin/groups/one.adp0000644000175000017500000000221710252570715023503 0ustar frankiefrankie @context;noquote@ @group_name;noquote@

    Attributes

    • There are no attributes for groups of this type
    • @attributes.pretty_name@: (no value) @attributes.value@ (edit)
    • Join Policy: @join_policy@ (edit)

    • Category trees: @category_trees@ (edit)

    Permissible relationship types

    Extreme Actions

    openacs-5.7.0/packages/acs-subsite/www/admin/groups/one.tcl0000644000175000017500000000443610551254377023533 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/one.tcl ad_page_contract { View one group. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2000-12-05 @cvs-id $Id: one.tcl,v 1.6 2007/01/10 21:22:07 gustafn Exp $ } { group_id:integer,notnull } -properties { context:onevalue group_id:onevalue group_name:onevalue write_p:onevalue admin_p:onevalue return_url_enc:onevalue attributes:multirow more_relationship_types_p:onevalue join_policy:onevalue } -validate { groups_exists_p -requires {group_id:notnull} { if { ![group::permission_p $group_id] } { ad_complain "The group either does not exist or you do not have permission to view it" } } group_in_scope_p -requires {group_id:notnull} { if { ![application_group::contains_party_p -include_self -party_id $group_id]} { ad_complain "The group either does not exist or does not belong to this subsite." } } } set user_id [ad_conn user_id] set write_p [ad_permission_p $group_id "write"] set admin_p [ad_permission_p $group_id "admin"] set return_url "[ad_conn url]?[ad_conn query]" set return_url_enc [ad_urlencode $return_url] # Select out the group name and the group's object type. Note we can # use 1row because the validate filter above will catch missing groups db_1row group_info { select g.group_name, g.join_policy, o.object_type as group_type from groups g, acs_objects o, acs_object_types t where g.group_id = o.object_id and o.object_type = t.object_type and g.group_id = :group_id } set context [list [list "[ad_conn package_url]admin/groups/" "Groups"] "One Group"] attribute::multirow \ -start_with group \ -datasource_name attributes \ -object_type $group_type \ $group_id if {[apm_package_installed_p categories]} { set category_url [site_node::get_package_url -package_key categories] set mapped_trees [category_tree::get_mapped_trees $group_id] foreach mapped_tree $mapped_trees { util_unlist $mapped_tree tree_id tree_name subtree_id if {$subtree_id ne ""} { set tree_name "${tree_name}::[category::get_name $subtree_id]" } lappend category_trees $tree_name } if {$mapped_trees eq ""} { set category_trees "None" } set category_trees [join $category_trees ,] } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/one.xql0000644000175000017500000000060407300260124023527 0ustar frankiefrankie select g.group_name, g.join_policy, o.object_type as group_type from groups g, acs_objects o, acs_object_types t where g.group_id = o.object_id and o.object_type = t.object_type and g.group_id = :group_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/delete.adp0000644000175000017500000000142207663154741024172 0ustar frankiefrankie @context;noquote@ Delete @group_name;noquote@ Are you sure you want to permanently, and irreversibly, remove this group? Removing this group will:
    • Remove all elements of this group (of which there are currently @number.elements@)
    • Remove all segments defined for this group (of which there are currently @number.segments@)
    • Remove any relational constraints that require this group in any way (of which there are currently @number.constraints@)

    openacs-5.7.0/packages/acs-subsite/www/admin/groups/delete.tcl0000644000175000017500000000250207536221407024201 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/delete.tcl ad_page_contract { Deletes a group @author mbryzek@arsdigita.com @creation-date Fri Dec 8 14:32:28 2000 @cvs-id $Id: delete.tcl,v 1.2 2002/09/06 21:49:59 jeffd Exp $ } { group_id:integer,notnull } -properties { context:onevalue group_name:onevalue number:onerow group_id:onevalue } -validate { groups_exists_p -requires {group_id:notnull} { if { ![group::permission_p -privilege delete $group_id] } { ad_complain "The group either does not exist or you do not have permission to delete it" } } } set context [list [list "" "Groups"] [list one?[ad_export_vars {group_id}] "One Group"] "Nuke group"] set group_name [db_string object_name {select acs_object.name(:group_id) from dual}] set export_form_vars [ad_export_vars -form {group_id}] db_1row select_counts { select (select count(*) from group_element_map where group_id = :group_id) as elements, (select count(*) from rel_segments where group_id = :group_id) as segments, (select count(*) from rel_constraints cons, rel_segments segs where segs.segment_id in (cons.rel_segment,cons.required_rel_segment) and segs.group_id = :group_id) as constraints from dual } -column_array number ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add.adp0000644000175000017500000000146207741502176025217 0ustar frankiefrankie @context;noquote@ Add relation type There are no other relationship types that you can add. You can create a new relationship type if you like.
    @export_vars;noquote@ Select relation type:
    openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add.tcl0000644000175000017500000000373007536221407025232 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/rel-type-add.tcl ad_page_contract { Displays relationship types to add as an allowable one @author mbryzek@arsdigita.com @creation-date Tue Jan 2 12:08:12 2001 @cvs-id $Id: rel-type-add.tcl,v 1.3 2002/09/06 21:49:59 jeffd Exp $ } { group_id:integer,notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue return_url_enc:onevalue primary_rels:multirow } set context [list [list "[ad_conn package_url]admin/groups/" "Groups"] [list "one?[ad_export_vars group_id]" "One Group"] "Add relation type"] set return_url_enc [ad_urlencode "[ad_conn url]?[ad_conn query]"] # Select out all the relationship types that are not currently # specified for this group. Note that we use acs_object_types so that # we can probably indent subtypes. We use acs_rel_types to limit our # selection to acceptable relationship types. # We need this group's type db_1row select_group_type { select o.object_type as group_type from acs_objects o where o.object_id = :group_id } db_multirow primary_rels select_primary_relations { select replace(lpad(' ', (t.type_level - 1) * 4), ' ', ' ') as indent, t.pretty_name, t.rel_type from (select t.pretty_name, t.object_type as rel_type, level as type_level from acs_object_types t where t.object_type not in (select g.rel_type from group_rels g where g.group_id = :group_id) connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel', 'composition_rel')) t, acs_rel_types rel_type where t.rel_type = rel_type.rel_type and (rel_type.object_type_one = :group_type or acs_object_type.is_subtype_p(rel_type.object_type_one, :group_type) = 't') } set export_vars [ad_export_vars -form {group_id return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add.xql0000644000175000017500000000037107300260124025236 0ustar frankiefrankie select o.object_type as group_type from acs_objects o where o.object_id = :group_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-add-2-oracle.xql0000644000175000017500000000221207300260124026634 0ustar frankiefrankie oracle8.1.6 select count(*) from acs_rel_types t where (t.object_type_one = :group_type or acs_object_type.is_subtype_p(t.object_type_one, :group_type) = 't') and t.rel_type = :rel_type select case when exists (select 1 from group_rels where group_id = :group_id and rel_type = :rel_type) then 1 else 0 end from dual select case when exists (select 1 from rel_segments s where s.group_id = :group_id and s.rel_type = :rel_type) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/www/admin/groups/delete-oracle.xql0000644000175000017500000000141007300260124025447 0ustar frankiefrankie oracle8.1.6 select acs_object.name(:group_id) from dual select (select count(*) from group_element_map where group_id = :group_id) as elements, (select count(*) from rel_segments where group_id = :group_id) as segments, (select count(*) from rel_constraints cons, rel_segments segs where segs.segment_id in (cons.rel_segment,cons.required_rel_segment) and segs.group_id = :group_id) as constraints from dual openacs-5.7.0/packages/acs-subsite/www/admin/groups/delete-postgresql.xql0000644000175000017500000000137107300260124026413 0ustar frankiefrankie postgresql7.1 select acs_object__name(:group_id) select (select count(*) from group_element_map where group_id = :group_id) as elements, (select count(*) from rel_segments where group_id = :group_id) as segments, (select count(*) from rel_constraints cons, rel_segments segs where segs.segment_id in (cons.rel_segment,cons.required_rel_segment) and segs.group_id = :group_id) as constraints openacs-5.7.0/packages/acs-subsite/www/admin/groups/change-join-policy-2.tcl0000644000175000017500000000176210551254377026567 0ustar frankiefrankie# /packages/acs-subsite/www/admin/groups/one.tcl ad_page_contract { Change join policy of a group. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2001-02-23 @cvs-id $Id: change-join-policy-2.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { group_id:integer,notnull join_policy:notnull {return_url ""} } -validate { groups_exists_p -requires {group_id:notnull} { if { ![group::permission_p -privilege admin $group_id] } { ad_complain "The group either does not exist or you do not have permission to administer it" } } group_in_scope_p -requires {group_id:notnull} { if { ![application_group::contains_party_p -party_id $group_id]} { ad_complain "The group either does not exist or does not belong to this subsite." } } } db_dml update_join_policy { update groups set join_policy = :join_policy where group_id = :group_id } if {$return_url eq ""} { set return_url one?group_id=@group_id@ } ad_returnredirect $return_urlopenacs-5.7.0/packages/acs-subsite/www/admin/groups/change-join-policy-2.xql0000644000175000017500000000035307300260124026565 0ustar frankiefrankie update groups set join_policy = :join_policy where group_id = :group_id openacs-5.7.0/packages/acs-subsite/www/admin/groups/elements-by-rel-type-oracle.xql0000644000175000017500000000300207300260124030167 0ustar frankiefrankie oracle8.1.6 select g.rel_type, g.group_rel_id, acs_object_type.pretty_name(g.rel_type) as rel_type_pretty_name, s.segment_id, s.segment_name, acs_rel_type.role_pretty_plural(rel_types.role_two) as role_pretty_plural, acs_rel_type.role_pretty_name(rel_types.role_two) as role_pretty_name, rels.num_rels, case when valid_types.group_id = null then 0 else 1 end as rel_type_valid_p from group_rels g, rel_segments s, acs_rel_types rel_types, (select rel_type, count(*) as num_rels from group_component_map where group_id = :group_id and group_id = container_id group by rel_type UNION ALL select rel_type, count(*) as num_rels from group_approved_member_map where group_id = :group_id and group_id = container_id group by rel_type) rels, rc_valid_rel_types valid_types where g.group_id = s.group_id(+) and g.rel_type = s.rel_type(+) and g.rel_type = rels.rel_type(+) and g.rel_type = rel_types.rel_type and g.group_id = :group_id and g.group_id = valid_types.group_id(+) and g.rel_type = valid_types.rel_type(+) order by lower(g.rel_type) openacs-5.7.0/packages/acs-subsite/www/admin/groups/rel-type-remove-postgresql.xql0000644000175000017500000000071007300260124030201 0ustar frankiefrankie postgresql7.1 select g.rel_type, g.group_id, acs_object__name(g.group_id) as group_name, t.pretty_name as rel_pretty_name from acs_object_types t, group_rels g where g.group_rel_id = :group_rel_id and t.object_type = g.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/constraints-create-postgresql.xql0000644000175000017500000000057307300260124030764 0ustar frankiefrankie postgresql7.1 select acs_group__name(:group_id) as group_name, t.pretty_name as rel_type_pretty_name from acs_object_types t where t.object_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/groups/constraints-create.adp0000644000175000017500000000144407663154741026544 0ustar frankiefrankie @context;noquote@ Constraints on relationship type Relational segments allows you to treat all parties that have a @rel_type_pretty_name@ to @group_name@ as a party itself. This is useful for assigning permissions and for further constraining which parties can use the @rel_type_pretty_name@.

    Once you create a relational segment, you will be able to create relational constraints on that segment. Relational constraints allow you to apply rules on inter-party relationships

    Would you like to create a relational segment and/or constraints now?

    openacs-5.7.0/packages/acs-subsite/www/admin/groups/constraints-create.tcl0000644000175000017500000000171307536221407026552 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/groups/constraints-create.tcl ad_page_contract { Describes constraints and offers the option to create a relational segment for this rel_type @author mbryzek@arsdigita.com @creation-date Thu Jan 4 10:54:36 2001 @cvs-id $Id: constraints-create.tcl,v 1.3 2002/09/06 21:49:59 jeffd Exp $ } { group_id:notnull,integer rel_type:notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue rel_type_pretty_name:onevalue group_name:onevalue } set context [list [list "[ad_conn package_url]admin/groups/" "Groups"] [list one?[ad_export_vars group_id] "One Group"] "Add constraint"] set export_vars [ad_export_vars -form {group_id rel_type return_url}] db_1row select_props { select acs_group.name(:group_id) as group_name, t.pretty_name as rel_type_pretty_name from acs_object_types t where t.object_type = :rel_type } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/relations/0000755000175000017500000000000011724401447022713 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/relations/remove-dependants-exist.adp0000644000175000017500000000105307663155153030161 0ustar frankiefrankie @context;noquote@ Dependent relations exist You must remove the following dependent relations before you can remove the @rel.rel_type_pretty_name@ between @rel.object_id_one_name@ and @rel.object_id_two_name@.

    • @dependants.rel_type_pretty_name@ between @dependants.object_id_one_name@ and @dependants.object_id_two_name@ (remove)
    openacs-5.7.0/packages/acs-subsite/www/admin/relations/change-member-state.tcl0000644000175000017500000000201410551254400027214 0ustar frankiefrankie# /packages/acs-subsite/www/admin/relations/one.tcl ad_page_contract { Shows information about one relation @author mbryzek@arsdigita.com @creation-date Wed Dec 13 20:11:27 2000 @cvs-id $Id: change-member-state.tcl,v 1.2 2007/01/10 21:22:08 gustafn Exp $ } { rel_id:integer,notnull member_state:notnull {return_url ""} } -validate { permission_p -requires {rel_id:notnull} { if { ![relation_permission_p -privilege admin $rel_id] } { ad_complain "The relation either does not exist or you do not have permission to administer it" } } relation_in_scope_p -requires {rel_id:notnull permission_p} { if { ![application_group::contains_relation_p -rel_id $rel_id]} { ad_complain "The relation either does not exist or does not belong to this subsite." } } } db_dml update_member_state { update membership_rels set member_state = :member_state where rel_id = :rel_id } if {$return_url eq ""} { set return_url "one?rel_id=$rel_id" } ad_returnredirect $return_urlopenacs-5.7.0/packages/acs-subsite/www/admin/relations/change-member-state.xql0000644000175000017500000000036307300260125027242 0ustar frankiefrankie update membership_rels set member_state = :member_state where rel_id = :rel_id openacs-5.7.0/packages/acs-subsite/www/admin/relations/remove-postgresql.xql0000644000175000017500000000164307300260125027132 0ustar frankiefrankie postgresql7.1 select acs_object_type__pretty_name(r.rel_type) as rel_type_pretty_name, acs_object__name(r.object_id_one) as object_id_one_name, acs_object__name(r.object_id_two) as object_id_two_name, r.object_id_two from acs_rels r where r.rel_id = :rel_id select r.viol_rel_id as rel_id, acs_object_type__pretty_name(r.viol_rel_type) as rel_type_pretty_name, acs_object__name(r.viol_object_id_one) as object_id_one_name, acs_object__name(r.viol_object_id_two) as object_id_two_name from rc_violations_by_removing_rel r where r.rel_id = :rel_id openacs-5.7.0/packages/acs-subsite/www/admin/relations/remove-oracle.xql0000644000175000017500000000163307300260125026173 0ustar frankiefrankie oracle8.1.6 select acs_object_type.pretty_name(r.rel_type) as rel_type_pretty_name, acs_object.name(r.object_id_one) as object_id_one_name, acs_object.name(r.object_id_two) as object_id_two_name, r.object_id_two from acs_rels r where r.rel_id = :rel_id select r.viol_rel_id as rel_id, acs_object_type.pretty_name(r.viol_rel_type) as rel_type_pretty_name, acs_object.name(r.viol_object_id_one) as object_id_one_name, acs_object.name(r.viol_object_id_two) as object_id_two_name from rc_violations_by_removing_rel r where r.rel_id = :rel_id openacs-5.7.0/packages/acs-subsite/www/admin/relations/remove.adp0000644000175000017500000000071307663155153024706 0ustar frankiefrankie @context;noquote@ Remove relation Are you sure you want to remove the @rel.rel_type_pretty_name@ between @rel.object_id_one_name@ and @rel.object_id_two_name@?

    openacs-5.7.0/packages/acs-subsite/www/admin/relations/remove.tcl0000644000175000017500000000446207536221414024722 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/relations/remove.tcl ad_page_contract { Confirmation page for relation removal. @author mbryzek@arsdigita.com @creation-date 2000-12-16 @cvs-id $Id: remove.tcl,v 1.2 2002/09/06 21:50:04 jeffd Exp $ } { rel_id:integer,notnull { return_url "" } } -properties { context:onevalue export_vars:onevalue rel:onerow dependants:multirow } -validate { permission_p -requires {rel_id:notnull} { if { ![relation_permission_p -privilege delete $rel_id] } { ad_complain "The relation either does not exist or you do not have permission to remove it" } } relation_in_scope_p -requires {rel_id:notnull permission_p} { if { ![application_group::contains_relation_p -rel_id $rel_id]} { ad_complain "The relation either does not exist or does not belong to this subsite." } } } set context [list "Remove relation"] if { ![db_0or1row select_rel_info { select acs_object_type.pretty_name(r.rel_type) as rel_type_pretty_name, acs_object.name(r.object_id_one) as object_id_one_name, acs_object.name(r.object_id_two) as object_id_two_name, r.object_id_two from acs_rels r where r.rel_id = :rel_id} -column_array rel] } { ad_return_error "Error" "Relation $rel_id does not exist" ad_script_abort } # Now let's see if removing this relation would violate some # constraint. if { [relation_segment_has_dependant -rel_id $rel_id] } { set return_url "[ad_conn url]?[ad_conn query]" # We can't remove this relation - display the violations template::multirow create dependants rel_id rel_type_pretty_name object_id_one_name object_id_two_name export_vars db_foreach select_dependants { select r.viol_rel_id as rel_id, acs_object_type.pretty_name(r.viol_rel_type) as rel_type_pretty_name, acs_object.name(r.viol_object_id_one) as object_id_one_name, acs_object.name(r.viol_object_id_two) as object_id_two_name from rc_violations_by_removing_rel r where r.rel_id = :rel_id } { template::multirow append dependants $rel_id $rel_type_pretty_name $object_id_one_name $object_id_two_name [ad_export_vars {rel_id return_url}] } ad_return_template remove-dependants-exist return } set export_vars [export_form_vars rel_id return_url] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/relations/one-postgresql.xql0000644000175000017500000000144307300260125026414 0ustar frankiefrankie postgresql7.1 select r.rel_type, acs_object_type__pretty_name(t.rel_type) as rel_type_pretty_name, acs_rel_type__role_pretty_name(t.role_one) as role_one_pretty_name, acs_rel_type__role_pretty_name(t.role_two) as role_two_pretty_name, t.object_type_two as object_type_two, acs_object__name(r.object_id_one) as object_id_one_name, r.object_id_one, acs_object__name(r.object_id_two) as object_id_two_name, r.object_id_two from acs_rels r, acs_rel_types t where r.rel_id = :rel_id and r.rel_type = t.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/relations/remove-2.tcl0000644000175000017500000000205010551254400025040 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/relations/remove-2.tcl ad_page_contract { Removes relations @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2000-12-16 @cvs-id $Id: remove-2.tcl,v 1.2 2007/01/10 21:22:08 gustafn Exp $ } { rel_id:integer,notnull { operation "" } { return_url "" } } -validate { permission_p -requires {rel_id:notnull} { if { ![relation_permission_p -privilege delete $rel_id] } { ad_complain "The relation either does not exist or you do not have permission to remove it" } } } if {$operation eq "Yes, I really want to remove this relation"} { db_transaction { relation_remove $rel_id } on_error { ad_return_error "Error creating the relation" "We got the following error while trying to remove the relation:
    $errmsg
    " ad_script_abort } } else { if { $return_url eq "" } { # redirect to the relation by default, if we haven't deleted it set return_url "one?[ad_export_vars rel_id]" } } db_release_unused_handles ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/relations/index.tcl0000644000175000017500000000045507253523116024532 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/relations/index.tcl ad_page_contract { Redirects to relationship type @author mbryzek@arsdigita.com @creation-date Thu Dec 14 12:12:51 2000 @cvs-id $Id: index.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ } { } ad_returnredirect ../rel-types/ openacs-5.7.0/packages/acs-subsite/www/admin/relations/add.adp0000644000175000017500000000222107663155153024135 0ustar frankiefrankie @context;noquote@ Add @role_pretty_name;noquote@ to @group_name;noquote@
    You can select an existing @object_type_two_name@ from this subsite below.
    If the @object_type_two_name@ that you want to add as @role_pretty_name@ to @group_name@ is not listed below, then you can either
    You can select an existing @object_type_two_name@ from the system below.
    If there are too many options, then you can select an existing @object_type_two_name@ from this subsite.
    You can also add a new @object_type_two_name@ to the system.
    Add @party_name@ as @role_pretty_name@ of @group_name@ . . .

    openacs-5.7.0/packages/acs-subsite/www/admin/relations/add.tcl0000644000175000017500000002024410551254400024141 0ustar frankiefrankie# /packages/acs-subsite/www/admin/relations/add.tcl ad_page_contract { Add a member to a group. If there are subtypes of the specified rel_type, we ask the user to select a precise rel_type before continuing @author mbryzek@mit.edu @creation-date 2000-12-11 @cvs-id $Id: add.tcl,v 1.10 2007/01/10 21:22:08 gustafn Exp $ } { group_id:integer,notnull rel_type:notnull {party_id:integer ""} { exact_p "f" } { return_url "" } { allow_out_of_scope_p "f" } } -properties { context:onevalue role_pretty_name:onevalue group_name:onevalue export_form_vars:onevalue rel_types:multirow rel_type_pretty_name:onevalue add_party_url:onevalue } -validate { party_in_scope_p -requires {party_id:notnull} { if { $allow_out_of_scope_p eq "f" && \ ![application_group::contains_party_p -party_id $party_id]} { ad_complain "The party either does not exist or does not belong to this subsite." } } rel_type_valid_p -requires {group_id:notnull rel_type:notnull exact_p:notnull} { if {$exact_p eq "t" && \ ![relation_type_is_valid_to_group_p -group_id $group_id $rel_type]} { ad_complain "Relations of this type to this group would violate a relational constraint." } } } # ISSUES / TO DO: still need to check that party_id is not already in the # group through this relation. Actually, we should handle this with # double-click protection (which we're not doing yet). We also need # to check permissions on the party. set context [list "Add relation"] set export_var_list [list group_id rel_type exact_p return_url allow_out_of_scope_p] if {$party_id ne ""} { lappend export_var_list party_id } set create_p [group::permission_p -privilege create $group_id] db_1row group_info { select group_name, join_policy from groups where group_id = :group_id } # We assume the group is on side 1... db_1row rel_type_info { select t.object_type_two, t.role_two as role, acs_rel_type.role_pretty_name(t.role_two) as role_pretty_name, acs_object_type.pretty_name(t.object_type_two) as object_type_two_name, ancestor_rel_types.object_type as ancestor_rel_type from acs_rel_types t, acs_object_types obj_types, acs_object_types ancestor_rel_types where t.rel_type = :rel_type and t.rel_type = obj_types.object_type and ancestor_rel_types.supertype = 'relationship' and ancestor_rel_types.object_type in ( select object_type from acs_object_types start with object_type = :rel_type connect by object_type = prior supertype ) } # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_pretty_name [lang::util::localize $role_pretty_name] if {$ancestor_rel_type eq "membership_rel"} { if {$join_policy eq "closed" && !$create_p} { ad_complain "You do not have permission to add elements to $group_name" return } set member_state [group::default_member_state -join_policy $join_policy -create_p $create_p] } else { set member_state "" } if { $exact_p eq "f" && \ [subsite::util::sub_type_exists_p $rel_type] } { # Sub rel-types exist... select one set exact_p "t" set export_url_vars [ad_export_vars -exclude rel_type $export_var_list ] relation_types_valid_to_group_multirow \ -datasource_name object_types \ -start_with $rel_type \ -group_id $group_id set object_type_pretty_name [subsite::util::object_type_pretty_name $rel_type] set this_url [ad_conn url] set object_type_variable rel_type ad_return_template ../parties/add-select-type return } template::form create add_relation foreach var $export_var_list { template::element create add_relation $var \ -value [set $var] \ -datatype text \ -widget hidden } # Build a url used to create a new party of type object_type_two set party_type $object_type_two set party_type_exact_p f set add_to_group_id $group_id set add_with_rel_type $rel_type set add_party_url "[ad_conn package_url]admin/parties/new?[ad_export_vars {add_to_group_id add_with_rel_type party_type party_type_exact_p return_url}]" # Build a url used to select an existing party from the system (as opposed # to limiting the selection to parties on the current subsite). set add_out_of_scope_url "[ad_conn url]?[ad_export_vars -exclude allow_out_of_scope_p $export_var_list]&allow_out_of_scope_p=t" # Build a url used to select an existing party from the current subsite set add_in_scope_url "[ad_conn url]?[ad_export_vars -exclude allow_out_of_scope_p $export_var_list]&allow_out_of_scope_p=f" # We select out all parties that are to not already belong to the # specified group with the specified rel_type. Note that we take # special care to not allow the user to select the group itself... we # don't want circular references. It remains to be seen if this query # will be faster if we assume we are only adding parties, and thus # drive off the smaller parties table. We still somehow need to get # the object type though... set user_id [ad_conn user_id] set package_id [ad_conn package_id] attribute::add_form_elements -form_id add_relation -start_with relationship -object_type $rel_type element::create add_relation rel_id -widget hidden -value [db_nextval "acs_object_id_seq"] if { [template::form is_valid add_relation] } { db_transaction { set rel_id [relation_add -form_id add_relation -member_state $member_state $rel_type $group_id $party_id] } on_error { ad_return_error "Error creating the relation" "We got the following error message while trying to create this relation:
    $errmsg
    " ad_script_abort } if { $return_url eq "" } { set return_url one?[ad_export_vars rel_id] } ad_returnredirect $return_url ad_script_abort } if {$party_id ne ""} { # ISSUES / TO DO: add a check to make sure the party is not # already in the group. We only want to do this on is_request, # in which case we know its not a double-click issue. set party_name [acs_object_name $party_id] # Note: party_id is not null, which means that it got added already # to $export_var_list, which means that there is already a hidden # form element containing the party_id variable. # Inform user which party will be on side two of the new relation. template::element create add_relation party_inform \ -widget "inform" -value "$party_name" -label "$role_pretty_name" } else { if {$object_type_two eq "party"} { # We special case 'party' because we don't want to include # parties whose direct object_type is: # 'rel_segment' - users will get confused by segments here. # 'party' - this is an abstract type and should have no objects, # but the system creates party -1 which users # shouldn't see. set start_with "ot.object_type = 'group' or ot.object_type = 'person'" } else { set start_with "ot.object_type = :object_type_two" } # The $allow_out_of_scope_p flag controls whether or not we limit # the list of parties to those that belong to the current subsite # (allow_out_of_scope_p = 'f'). Even when allow_out_of_scope_p = 't', # permissions checks and relational constraints may limit # the list of parties that can be added to $group_id with a relation # of type $rel_type. if {$allow_out_of_scope_p eq "f"} { set scope_query [db_map select_parties_scope_query] set scope_clause " and p.party_id = app_elements.element_id" } else { set scope_query "" set scope_clause "" } # SENSITIVE PERFORMANCE - this comment tag is here to make it # easy for us to find all the queries that we know may be unscalable. # This query has been tuned as well as possible given development # time constraints, but more tuning may be necessary. set party_option_list [db_list_of_lists select_parties {}] if { [llength $party_option_list] == 0 } { ad_return_template add-no-valid-parties ad_return } template::element create add_relation party_id \ -datatype "text" \ -widget select \ -options $party_option_list \ -label "Select $role_pretty_name" } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/relations/add.xql0000644000175000017500000000034107300260125024156 0ustar frankiefrankie select group_name, join_policy from groups where group_id = :group_id openacs-5.7.0/packages/acs-subsite/www/admin/relations/add-no-valid-parties.adp0000644000175000017500000000077607663155153027326 0ustar frankiefrankie @context;noquote@ Add @role_pretty_name;noquote@ to @group_name;noquote@
    There is no other @object_type_two_name@ on this subsite that can be added as @role_pretty_name@ to @group_name@.

    You can either:

    openacs-5.7.0/packages/acs-subsite/www/admin/relations/one.adp0000644000175000017500000000541207663155153024173 0ustar frankiefrankie @context;noquote@ One relation

    Attributes

    • There are no attributes for relations of this type
    • @attributes.pretty_name@: (no value) @attributes.value@ (edit)

    Properties

    Administration

    About @rel.object_id_two_name@

    • There are no attributes for parties of this type
    • @object_two_attributes.pretty_name@: (no value) @object_two_attributes.value@ (edit)
    • more about @rel.object_id_two_name@
    openacs-5.7.0/packages/acs-subsite/www/admin/relations/one.tcl0000644000175000017500000000651107741545112024205 0ustar frankiefrankie# /packages/acs-subsite/www/admin/relations/one.tcl ad_page_contract { Shows information about one relation @author mbryzek@arsdigita.com @creation-date Wed Dec 13 20:11:27 2000 @cvs-id $Id: one.tcl,v 1.3 2003/10/10 15:03:38 lars Exp $ } { rel_id:integer,notnull } -properties { context:onevalue rel_id:onevalue rel:onerow delete_p:onevalue admin_p:onevalue attributes:multirow write_p:onevalue delete_p:onevalue subsite_group_id:onevalue object_two_attributes:multirow member_state:onevalue QQreturn_url:onevalue possible_member_states:onelist } -validate { permission_p -requires {rel_id:notnull} { if { ![relation_permission_p $rel_id] } { ad_complain "The relation either does not exist or you do not have permission to view it" } } relation_in_scope_p -requires {rel_id:notnull permission_p} { if { ![application_group::contains_relation_p -rel_id $rel_id]} { ad_complain "The relation either does not exist or does not belong to this subsite." } } } set admin_p [ad_permission_p $rel_id "admin"] set delete_p [ad_permission_p $rel_id "delete"] set write_p [ad_permission_p $rel_id "write"] set context [list "One relation"] set subsite_group_id [application_group::group_id_from_package_id] if { ![db_0or1row select_rel_info { select r.rel_type, acs_object_type.pretty_name(t.rel_type) as rel_type_pretty_name, acs_rel_type.role_pretty_name(t.role_one) as role_one_pretty_name, acs_rel_type.role_pretty_name(t.role_two) as role_two_pretty_name, t.object_type_two as object_type_two, acs_object.name(r.object_id_one) as object_id_one_name, r.object_id_one, acs_object.name(r.object_id_two) as object_id_two_name, r.object_id_two from acs_rels r, acs_rel_types t where r.rel_id = :rel_id and r.rel_type = t.rel_type} -column_array rel] } { ad_return_error "Error" "Relation #rel_id does not exist" ad_script_abort } set rel(rel_type_enc) [ad_urlencode $rel(rel_type)] set rel(role_one_pretty_name) [lang::util::localize $rel(role_one_pretty_name)] set rel(role_two_pretty_name) [lang::util::localize $rel(role_two_pretty_name)] # Build up the list of attributes for the type specific lookup set rel_type $rel(rel_type) set attr_list [attribute::array_for_type -start_with "relationship" attr_props enum_values $rel_type] attribute::multirow \ -start_with relationship \ -datasource_name attributes \ -object_type $rel_type \ $rel_id # Membership relations have a member_state. Composition relations don't. # This query will return null if the relation is not a membership relation. set member_state "" db_0or1row select_member_state { select member_state from membership_rels where rel_id = :rel_id } # Data used to build the "toggle member state" widget. set return_url [ad_conn url]?[ad_conn query] set QQreturn_url [ad_quotehtml $return_url] set possible_member_states [group::possible_member_states] set object_two_read_p [ad_permission_p $rel(object_id_two) "read"] if {$object_two_read_p} { set object_two_write_p [ad_permission_p $rel(object_id_two) "write"] attribute::multirow \ -start_with party \ -datasource_name object_two_attributes \ -object_type $rel(object_type_two) \ $rel(object_id_two) } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/relations/one.xql0000644000175000017500000000034007300260125024206 0ustar frankiefrankie select member_state from membership_rels where rel_id = :rel_id openacs-5.7.0/packages/acs-subsite/www/admin/relations/add-postgresql.xql0000644000175000017500000000516510041311133026360 0ustar frankiefrankie postgresql7.1 select t.object_type_two, t.role_two as role, acs_rel_type__role_pretty_name(t.role_two) as role_pretty_name, acs_object_type__pretty_name(t.object_type_two) as object_type_two_name, ancestor_rel_types.object_type as ancestor_rel_type from acs_rel_types t, acs_object_types obj_types, acs_object_types ancestor_rel_types where t.rel_type = :rel_type and t.rel_type = obj_types.object_type and ancestor_rel_types.supertype = 'relationship' and ancestor_rel_types.object_type in ( select t2.object_type from acs_object_types t1, acs_object_types t2 where t1.object_type= :rel_type and t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) ) cross join (select element_id from application_group_element_map where package_id = :package_id) app_elements select DISTINCT case when groups.group_id is null then case when persons.person_id is null then 'INVALID' else persons.first_names || ' ' || persons.last_name end else groups.group_name end as party_name, p.party_id from (select o.object_id as party_id from acs_objects o, (select ot2.object_type from acs_object_types ot, acs_object_types ot2 where ot2.tree_sortkey between ot.tree_sortkey and tree_right(ot.tree_sortkey) and $start_with) t where o.object_type = t.object_type) p left join (select element_id from group_element_map where group_id = :group_id and rel_type = :rel_type UNION ALL select :group_id::integer ) m on (p.party_id = m.element_id) cross join (select party_id from rc_parties_in_required_segs where group_id = :group_id and rel_type = :rel_type) pirs $scope_query left join groups on (p.party_id = groups.group_id) left join persons on (p.party_id = persons.person_id) where m.element_id is null and p.party_id = pirs.party_id $scope_clause openacs-5.7.0/packages/acs-subsite/www/admin/relations/one-oracle.xql0000644000175000017500000000143407300260125025456 0ustar frankiefrankie oracle8.1.6 select r.rel_type, acs_object_type.pretty_name(t.rel_type) as rel_type_pretty_name, acs_rel_type.role_pretty_name(t.role_one) as role_one_pretty_name, acs_rel_type.role_pretty_name(t.role_two) as role_two_pretty_name, t.object_type_two as object_type_two, acs_object.name(r.object_id_one) as object_id_one_name, r.object_id_one, acs_object.name(r.object_id_two) as object_id_two_name, r.object_id_two from acs_rels r, acs_rel_types t where r.rel_id = :rel_id and r.rel_type = t.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/relations/add-oracle.xql0000644000175000017500000000505410041311133025417 0ustar frankiefrankie oracle8.1.6 select t.object_type_two, t.role_two as role, acs_rel_type.role_pretty_name(t.role_two) as role_pretty_name, acs_object_type.pretty_name(t.object_type_two) as object_type_two_name, ancestor_rel_types.object_type as ancestor_rel_type from acs_rel_types t, acs_object_types obj_types, acs_object_types ancestor_rel_types where t.rel_type = :rel_type and t.rel_type = obj_types.object_type and ancestor_rel_types.supertype = 'relationship' and ancestor_rel_types.object_type in ( select object_type from acs_object_types start with object_type = :rel_type connect by object_type = prior supertype ) , (select element_id from application_group_element_map where package_id = :package_id) app_elements select DISTINCT decode(groups.group_id, null, case when persons.person_id = null then 'INVALID' else persons.first_names || ' ' || persons.last_name end, groups.group_name) as party_name, p.party_id from (select o.object_id as party_id from acs_objects o, (select object_type from acs_object_types ot start with $start_with connect by prior ot.object_type = ot.supertype) t where o.object_type = t.object_type) p, (select element_id from group_element_map where group_id = :group_id and rel_type = :rel_type UNION ALL select to_number(:group_id) from dual) m, (select party_id from rc_parties_in_required_segs where group_id = :group_id and rel_type = :rel_type) pirs $scope_query, groups, persons where p.party_id = m.element_id(+) and m.element_id is null and p.party_id = pirs.party_id $scope_clause and p.party_id = groups.group_id(+) and p.party_id = persons.person_id(+) openacs-5.7.0/packages/acs-subsite/www/admin/index-postgresql.xql0000644000175000017500000000061707273343353024762 0ustar frankiefrankie postgresql7.1 select site_node__url(node_id) as acs_admin_url, instance_name from site_nodes s, apm_packages p where s.object_id = p.package_id and p.package_key = 'acs-admin' limit 1 openacs-5.7.0/packages/acs-subsite/www/admin/index.adp0000644000175000017500000000250411552012374022505 0ustar frankiefrankie @title;noquote@

    @title;noquote@

    #acs-subsite.Advanced_Features#

    #acs-subsite.Core_Services#

    openacs-5.7.0/packages/acs-subsite/www/admin/index.tcl0000644000175000017500000000173711552012374022532 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/index.tcl ad_page_contract { @author Bryan Quinn (bquinn@arsdigita.com) @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date August 15, 2000 @cvs-id $Id: index.tcl,v 1.19 2011/04/15 09:50:52 emmar Exp $ } { } -properties { context:onevalue subsite_name:onevalue acs_admin_url:onevalue instance_name:onevalue acs_automated_testing_url:onevalue acs_lang_admin_url:onevalue } array set this_node [site_node::get -url [ad_conn url]] set title "$this_node(instance_name) [_ acs-subsite.Administration]" set acs_admin_url [apm_package_url_from_key "acs-admin"] array set acs_admin_node [site_node::get -url $acs_admin_url] set acs_admin_name $acs_admin_node(instance_name) set sw_admin_p [permission::permission_p -party_id [ad_conn user_id] -object_id $acs_admin_node(object_id) -privilege admin] set convert_subsite_p [expr { [llength [apm::get_package_descendent_options [ad_conn package_key]]] > 0 }] openacs-5.7.0/packages/acs-subsite/www/admin/index.xql0000644000175000017500000000035507273343353022560 0ustar frankiefrankie select p.instance_name from apm_packages p where p.package_id = :package_id openacs-5.7.0/packages/acs-subsite/www/admin/subsite-add.adp0000644000175000017500000000032607736777053023627 0ustar frankiefrankie @page_title@ @context@ subsite.instance_name openacs-5.7.0/packages/acs-subsite/www/admin/subsite-add.tcl0000644000175000017500000000677711552012374023640 0ustar frankiefrankiead_page_contract { Create and mount a new Subsite @author Steffen Tiedemann Christensen (steffen@christensen.name) @creation-date 2003-09-26 } { node_id:integer,optional } auth::require_login set page_title "[_ acs-subsite.New_subsite]" set subsite_pretty_name "[_ acs-subsite.Subsite_name]" set context [list $page_title] ad_form -name subsite -cancel_url . -form { {node_id:key}} set subsite_package_options [subsite::util::get_package_options] if { [llength $subsite_package_options] == 1 } { ad_form -extend -name subsite -form { {package_key:text(hidden) {value "[lindex [lindex $subsite_package_options 0] 1]"} } } } else { ad_form -extend -name subsite -form { {package_key:text(select) {label "[_ acs-subsite.Subsite_Package]"} {help_text "Choose the subsite package you'd like to mount"} {options $subsite_package_options} } } } ad_form -extend -name subsite -form { {instance_name:text {label $subsite_pretty_name} {help_text "[_ acs-subsite.The_name_of_the_new_subsite_you_re_setting_up]"} {html {size 30}} } {folder:url_element(text),optional {label "[_ acs-subsite.URL_folder_name]"} {help_text "[_ acs-subsite.This_should_be_a_short_string]"} {html {size 30}} } {theme:text(select) {label "[_ acs-subsite.Theme]"} {help_text "[_ acs-subsite.Choose_the_layout_and_navigation]"} {options [subsite::get_theme_options]} } {visibility:text(select) {label "[_ acs-subsite.Visible_to]"} {options { { "[_ acs-subsite.Members_only]" "members" } { "[_ acs-subsite.Anyone]" "any" } }} } {join_policy:text(select) {label "[_ acs-subsite.Join_policy]"} {options [group::get_join_policy_options]} } } -on_submit { set folder [site_node::verify_folder_name \ -parent_node_id [ad_conn node_id] \ -current_node_id $node_id \ -folder $folder \ -instance_name $instance_name] if { $folder eq "" } { form set_error subsite folder "This folder name is already used" break } } -new_data { db_transaction { # Create and mount new subsite set new_package_id [site_node::instantiate_and_mount \ -parent_node_id [ad_conn node_id] \ -node_name $folder \ -package_name $instance_name \ -package_key $package_key] # Set template subsite::set_theme -subsite_id $new_package_id -theme $theme # Set join policy set group(join_policy) $join_policy set member_group_id [application_group::group_id_from_package_id -package_id $new_package_id] group::update -group_id $member_group_id -array group # Add current user as admin group::add_member \ -no_perm_check \ -member_state "approved" \ -rel_type "admin_rel" \ -group_id $member_group_id \ -user_id [ad_conn user_id] # Set inheritance (called 'visibility' in form) if { $visibility ne "any" } { permission::set_not_inherit -object_id $new_package_id } } on_error { ad_return_error "Problem Creating Application" "We had a problem creating the subsite." } } -after_submit { ad_returnredirect ../$folder ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/index-oracle.xql0000644000175000017500000000062607273343353024024 0ustar frankiefrankie oracle8.1.6 select site_node.url(node_id) acs_admin_url, instance_name from site_nodes s, apm_packages p where s.object_id = p.package_id and p.package_key = 'acs-admin' and rownum = 1 openacs-5.7.0/packages/acs-subsite/www/admin/parties/0000755000175000017500000000000011724401447022362 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/parties/new-postgresql.xql0000644000175000017500000000075707403013337026107 0ustar frankiefrankie postgresql7.1 select t2.object_type as ancestor_rel_type from acs_object_types t1, acs_object_types t2 where t1.object_type = :add_with_rel_type and t1.tree_sortkey between t2.tree_sortkey and tree_right(t2.tree_sortkey) and t2.supertype = 'relationship' openacs-5.7.0/packages/acs-subsite/www/admin/parties/one-postgresql.xql0000644000175000017500000000054307300260124026062 0ustar frankiefrankie postgresql7.1 select acs_object__name(:party_id) as party_name, object_type as party_type from acs_objects where object_id = :party_id openacs-5.7.0/packages/acs-subsite/www/admin/parties/add-select-type.adp0000644000175000017500000000105207724366066026046 0ustar frankiefrankie @context;noquote@ Select specific @object_type_pretty_name;noquote@ type
    What type of @object_type_pretty_name@ do you want to create?

    @object_types.indent;noquote@ @object_types.pretty_name@ @object_types.pretty_name@

    openacs-5.7.0/packages/acs-subsite/www/admin/parties/new-oracle.xql0000644000175000017500000000102307300260124025126 0ustar frankiefrankie oracle8.1.6 select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :add_with_rel_type connect by object_type = prior supertype ) openacs-5.7.0/packages/acs-subsite/www/admin/parties/new.adp0000644000175000017500000000030407663154757023656 0ustar frankiefrankie @context;noquote@ Add a party of type @party_type_pretty_name;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/parties/new.tcl0000644000175000017500000001615410551254377023673 0ustar frankiefrankie# /packages/subsite/www/admin/parties/new.tcl ad_page_contract { Adds a new party @author oumi@arsdigita.com @creation-date 2000-02-07 @cvs-id $Id: new.tcl,v 1.6 2007/01/10 21:22:07 gustafn Exp $ } { party_type:notnull { party_type_exact_p t } { party_id:naturalnum "" } { party.email ""} { return_url "" } {add_to_group_id ""} {add_with_rel_type "membership_rel"} {group_rel_type_list ""} } -properties { context:onevalue party_type_pretty_name:onevalue attributes:multirow } set context [list [list "" "Parties"] "Add a party"] if {$add_to_group_id eq ""} { set add_to_group_id [application_group::group_id_from_package_id] } set export_var_list [list \ party_id party_type add_to_group_id add_with_rel_type \ return_url party_type_exact_p group_rel_type_list] db_1row group_info { select group_name as add_to_group_name, join_policy as add_to_group_join_policy from groups where group_id = :add_to_group_id } # We assume the group is on side 1... db_1row rel_type_info { select object_type as ancestor_rel_type from acs_object_types where supertype = 'relationship' and object_type in ( select object_type from acs_object_types start with object_type = :add_with_rel_type connect by object_type = prior supertype ) } set create_p [group::permission_p -privilege create $add_to_group_id] # Membership relations have a member_state attribute that gets set # based on the group's join policy. if {$ancestor_rel_type eq "membership_rel"} { if {$add_to_group_join_policy eq "closed" && !$create_p} { ad_complain "You do not have permission to add elements to $add_to_group_name" return } set member_state [group::default_member_state -join_policy $add_to_group_join_policy -create_p $create_p] } else { set member_state "" } # Select out the party name and the party's object type. Note we can # use 1row because the validate filter above will catch missing parties db_1row select_type_info { select t.pretty_name as party_type_pretty_name, t.table_name from acs_object_types t where t.object_type = :party_type } # Check if the new party needs to first be added in other segments before # being added to $add_to_group_id using $add_with_rel_type. if {$group_rel_type_list eq ""} { set required_group_rel_type_list [relation_required_segments_multirow \ -datasource_name required_segments \ -group_id $add_to_group_id \ -rel_type $add_with_rel_type] if {[llength $required_group_rel_type_list] > 0} { # There are required segments that the soon-to-exist party must be in # before it can be added to $add_to_group_id with rel type # $add_with_rel_type. We'll return a notice to the user, and give # them a link to begin the process of adding the party in the right # segments. # set up variables for template set rel_type_pretty_name [subsite::util::object_type_pretty_name $add_with_rel_type] set group_name [acs_object_name $add_to_group_id] set object_type_pretty_name $party_type_pretty_name # We're going to have to pass the required_group_rel_type_list to the # next page. The easiest way I see to do this is jsut encode the list # in a variable, since the list is just a string anyways. # We don't care about the first group/rel_type combo, because we'll pass # that information explicitly in other variables. set group_rel_type_list [lrange $required_group_rel_type_list 1 end] # We also want to make sure that the user is finally returned to a page # where they can put the new party in the original group they were # attempting, and with the original relationship type they wanted. # We can't use return_url because we don't yet know the party_id. So # we'll just add to group_rel_type_list lappend group_rel_type_list [list $add_to_group_id $add_with_rel_type] lappend export_var_list group_rel_type_list set export_url_vars [ad_export_vars -exclude {add_to_group_id add_with_rel_type} $export_var_list] ad_return_template new-list-required-segments return } } ### This page redirects to different pages for groups or rel_segments. ### We have to check whether the party_type is a type of group or rel_segment. # Get a list of types in the type hierarchy that are in the path between # 'party' and $party_type set object_type_path_list [subsite::util::object_type_path_list $party_type party] set redirects_for_type [list \ group "groups/new?group_id=$party_id&group_type_exact_p=$party_type_exact_p&group_type=$party_type&[ad_export_vars -exclude {party_id party_type_exact_p party_type} $export_var_list]" \ rel_segment "rel-segments/new?segment_id=$party_id&group_id=$add_to_group_id" \ user "users/new?user_id=$party_id&[ad_export_vars -exclude {party_id party_type_exact_p party_type} $export_var_list]"] foreach {type url} $redirects_for_type { if {[lsearch $object_type_path_list $type] != -1} { ad_returnredirect [ad_conn package_url]admin/$url } } if { $party_type_exact_p eq "f" && \ [subsite::util::sub_type_exists_p $party_type] } { # Sub party-types exist... select one set party_type_exact_p "t" set export_url_vars [ad_export_vars -exclude party_type $export_var_list ] party::types_valid_for_rel_type_multirow -datasource_name object_types -start_with $party_type -rel_type $add_with_rel_type set object_type_pretty_name $party_type_pretty_name set this_url [ad_conn url] set object_type_variable party_type ad_return_template add-select-type return } template::form create add_party if { [template::form is_request add_party] } { foreach var $export_var_list { template::element create add_party $var \ -value [set $var] \ -datatype text \ -widget hidden } # Set the object id for the new party template::element set_properties add_party party_id \ -value [db_nextval "acs_object_id_seq"] } attribute::add_form_elements -form_id add_party -variable_prefix party -start_with party -object_type $party_type attribute::add_form_elements -form_id add_party -variable_prefix rel -start_with relationship -object_type $add_with_rel_type if { [template::form is_valid add_party] } { db_transaction { party::new -email ${party.email} -form_id add_party -variable_prefix party -party_id $party_id -context_id [ad_conn package_id] $party_type relation_add -member_state $member_state $add_with_rel_type $add_to_group_id $party_id } # there may be more segments to put this new party in before the # user's original request is complete. So build a return_url stack foreach group_rel_type $group_rel_type_list { set next_group_id [lindex $group_rel_type 0] set next_rel_type [lindex $group_rel_type 1] lappend return_url_list \ "../relations/add?group_id=$next_group_id&rel_type=[ad_urlencode $next_rel_type]&party_id=$party_id&allow_out_of_scope_p=t" } # Add the original return_url as the last one in the list lappend return_url_list $return_url set return_url_stacked [subsite::util::return_url_stack $return_url_list] ad_returnredirect $return_url_stacked ad_script_abort } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/parties/new.xql0000644000175000017500000000103507300260124023666 0ustar frankiefrankie select group_name as add_to_group_name, join_policy as add_to_group_join_policy from groups where group_id = :add_to_group_id select t.pretty_name as party_type_pretty_name, t.table_name from acs_object_types t where t.object_type = :party_type openacs-5.7.0/packages/acs-subsite/www/admin/parties/one.adp0000644000175000017500000000131607663154757023652 0ustar frankiefrankie @context;noquote@ @party_name;noquote@

    Attributes

    • There are no attributes for parties of this type
    • @attributes.pretty_name@: (no value) @attributes.value@ (edit)

    Extreme Actions

    openacs-5.7.0/packages/acs-subsite/www/admin/parties/one.tcl0000644000175000017500000000407107542111674023654 0ustar frankiefrankie # /packages/subsite/www/admin/parties/one.tcl ad_page_contract { View one party. @author Oumi Mehrotra (oumi@arsdigita.com) @creation-date 2001-02-06 @cvs-id $Id: one.tcl,v 1.4 2002/09/18 14:54:52 jeffd Exp $ } { party_id:integer,notnull } -properties { context:onevalue party_id:onevalue party_name:onevalue admin_p:onevalue write_p:onevalue attributes:multirow } -validate { parties_exists_p -requires {party_id:notnull} { if { ![party::permission_p $party_id] } { ad_complain "The party either does not exist or you do not have permission to view it" } } party_in_scope_p -requires {party_id:notnull parties_exists_p} { if { ![application_group::contains_party_p -party_id $party_id]} { ad_complain "The party either does not exist or does not belong to this subsite." } } } # Select out the party name and the party's object type. Note we can # use 1row because the validate filter above will catch missing parties db_1row party_info { select acs_object.name(:party_id) as party_name, object_type as party_type from acs_objects where object_id = :party_id } ### This page redirects to different pages for groups or rel_segments. ### We have to check whether the party_type is a type of group or rel_segment. # Get a list of types in the type hierarchy that are in the path between # 'party' and $party_type set object_type_path_list [subsite::util::object_type_path_list $party_type party] set redirects_for_type [list \ group "groups/one?group_id=$party_id" \ rel_segment "rel-segments/one?segment_id=$party_id"] foreach {type url} $redirects_for_type { if {[lsearch $object_type_path_list $type] != -1} { ad_returnredirect [ad_conn package_url]admin/$url ad_script_abort } } set user_id [ad_conn user_id] set write_p [ad_permission_p $party_id "write"] set admin_p [ad_permission_p $party_id "admin"] set context [list [list "" "Parties"] "One Party"] attribute::multirow \ -start_with party \ -datasource_name attributes \ -object_type $party_type \ $party_id openacs-5.7.0/packages/acs-subsite/www/admin/parties/new-list-required-segments.adp0000644000175000017500000000144507663154757030277 0ustar frankiefrankie @context;noquote@ Create a new user
    In order to create a new @object_type_pretty_name@ with @rel_type_pretty_name@ to @group_name@, the @object_type_pretty_name@ must be added to other groups with other relationships.

    You can begin the process of adding a new @object_type_pretty_name@ and giving it the following relationships to the necessary groups:

    • @required_segments.rel_type_pretty_name@ to @required_segments.group_name@
    openacs-5.7.0/packages/acs-subsite/www/admin/parties/one-oracle.xql0000644000175000017500000000054007300260124025121 0ustar frankiefrankie oracle8.1.6 select acs_object.name(:party_id) as party_name, object_type as party_type from acs_objects where object_id = :party_id openacs-5.7.0/packages/acs-subsite/www/admin/site-nodes/0000755000175000017500000000000011724401447022765 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/site-nodes/index.vuh0000644000175000017500000000024107253523116024615 0ustar frankiefrankieset url [ad_conn package_url]admin/site-map/[ad_conn path_info] if {![empty_string_p [ad_conn query]]} { append url [ad_conn query] } ad_returnredirect $url openacs-5.7.0/packages/acs-subsite/www/admin/applications/0000755000175000017500000000000011724401447023401 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/applications/application-add.adp0000644000175000017500000000050311552016774027122 0ustar frankiefrankie @page_title@ @context@ @focus;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/applications/application-add.tcl0000644000175000017500000000713011552016774027143 0ustar frankiefrankiead_page_contract { Create and mount a new application. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-05-28 @cvs-id $Id: application-add.tcl,v 1.11 2011/04/15 10:29:16 emmar Exp $ } { node_id:integer,optional {return_url "."} } set page_title "[_ acs-subsite.New_Application]" set context [list [list "." "Applications"] $page_title] set packages [subsite::get_application_options] if { [ad_form_new_p -key node_id] } { set focus application.package_key } else { set focus application.instance_name } set multiple_add_url [export_vars -base multiple-add { return_url }] ad_form -name application -cancel_url . -form { {return_url:text(hidden),optional} {node_id:key} {package_key:text(select) {label "[_ acs-subsite.Application]"} {options $packages} {help_text "The type of application you want to add. If the application is not in the list, you may need to install it on the server."} {mode {[ad_decode [ad_form_new_p -key node_id] 1 "" "display"]}} } {instance_name:text,optional {label "[_ acs-subsite.Application_name]"} {help_text "The human-readable name of your application. If blank, the name of the application is used (e.g. 'Forums')."} {html {size 50}} } {folder:text,optional {label "[_ acs-subsite.URL_folder_name]"} {help_text "The partial URL of the new application. This should be a short string, all lowercase, with hyphens instead of spaces. If blank, the package name is used (e.g. 'forum')."} {html {size 30}} } } -new_request { # Sets return_url } -edit_request { array set node [site_node::get -node_id $node_id] set package_key $node(package_key) set instance_name $node(instance_name) set folder $node(name) } -on_submit { if { $instance_name eq "" } { # Find the package pretty name from the list of packages foreach elm $packages { if {[lindex $elm 1] eq $package_key} { set instance_name [lindex $elm 0] break } } if { $instance_name eq "" } { error "Couldn't find package_key '$package_key' in list of system applications" } } if { [ad_form_new_p -key node_id] } { set current_node_id {} } else { set current_node_id $node_id } set folder [site_node::verify_folder_name \ -parent_node_id [ad_conn node_id] \ -current_node_id $current_node_id \ -folder $folder \ -instance_name $instance_name] if { $folder eq "" } { form set_error application folder "This folder name is already used" break } } -new_data { if { [catch { site_node::instantiate_and_mount \ -parent_node_id [ad_conn node_id] \ -node_name $folder \ -package_name $instance_name \ -package_key $package_key } errmsg] } { global errorInfo ns_log Error "Error creating application: $errmsg\n$errorInfo" ad_return_error "Problem Creating Application" "We had a problem creating the application." } } -edit_data { # this is where we would rename ... array set node [site_node::get -node_id $node_id] set package_id $node(object_id) db_transaction { apm_package_rename -package_id $node(package_id) -instance_name $instance_name site_node::rename -node_id $node_id -name $folder } } -after_submit { ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/applications/permissions-user-add.adp0000644000175000017500000000026707736016477030166 0ustar frankiefrankie @page_title@ @context@ openacs-5.7.0/packages/acs-subsite/www/admin/applications/permissions-user-add.tcl0000644000175000017500000000065207736016477030202 0ustar frankiefrankiead_page_contract { Redirect page for adding users to the permissions list. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-13 @cvs-id $Id: permissions-user-add.tcl,v 1.1 2003/09/29 11:53:35 lars Exp $ } { object_id:integer } set page_title "Add User" set context [list [list "." "Applications"] [list "permissions" "[apm_instance_name_from_id $object_id] Permissions"] $page_title] openacs-5.7.0/packages/acs-subsite/www/admin/applications/application-delete.adp0000644000175000017500000000056507776227275027661 0ustar frankiefrankie @page_title@ @context@

    Are you sure you want to delete this applicationthese @num@ applications?

    Delete      Cancel, do not delete

    openacs-5.7.0/packages/acs-subsite/www/admin/applications/application-delete.tcl0000644000175000017500000000270607771664571027675 0ustar frankiefrankiead_page_contract { Delete an application. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-05-28 @cvs-id $Id: application-delete.tcl,v 1.4 2003/12/22 22:00:25 lars Exp $ } { node_id:integer,multiple {confirm_p 0} } if { !$confirm_p } { set num [llength $node_id] if { $num == 0 } { ad_returnredirect . return } set page_title "Delete [ad_decode $num 1 "Application" "Applications"]" set context [list [list "." "Applications"] $page_title] set yes_url [export_vars -base [ad_conn url] { node_id:multiple { confirm_p 1 } }] set no_url "." return } # First unmount and delete the site-nodes, then delete the package, in separate transactions, # so even if the package deletion fails, it'll be gone from this subsite. set package_id [list] db_transaction { foreach id $node_id { lappend package_id [site_node::get_object_id -node_id $id] # Unmount the application site_node::unmount -node_id $id # Delete the node site_node::delete -node_id $id } } db_transaction { foreach id $package_id { # Delete the instance apm_package_instance_delete $id } } on_error { set error_p 1 global errorInfo ns_log Error "Error deleting package with package_id $id: $errmsg\n$errorInfo" # Hm. Not sure what to do. For now, let's rethrow the error. error $errmsg $errorInfo } ad_returnredirect . openacs-5.7.0/packages/acs-subsite/www/admin/applications/permissions.adp0000644000175000017500000000035307736016477026460 0ustar frankiefrankie @page_title@ @context@ openacs-5.7.0/packages/acs-subsite/www/admin/applications/permissions.tcl0000644000175000017500000000055707736016477026504 0ustar frankiefrankiead_page_contract { Permissions for the subsite itself. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-13 @cvs-id $Id: permissions.tcl,v 1.1 2003/09/29 11:53:35 lars Exp $ } { package_id:integer } set page_title "[apm_instance_name_from_id $package_id] Permissions" set context [list [list "." "Applications"] $page_title] openacs-5.7.0/packages/acs-subsite/www/admin/applications/index-postgresql.xql0000644000175000017500000000157310204420554027435 0ustar frankiefrankie postgresql7.1 select n.node_id, n.name, p.package_id, p.instance_name, tree_level(n.tree_sortkey) - tree_level(np.tree_sortkey) as treelevel, pt.pretty_name as package_pretty_name, (select count(*) from apm_parameters par where par.package_key = pt.package_key) as num_parameters from site_nodes n, site_nodes np, apm_packages p, apm_package_types pt where np.node_id = :subsite_node_id and n.tree_sortkey between np.tree_sortkey and tree_right(np.tree_sortkey) and p.package_id = n.object_id and pt.package_key = p.package_key order by n.tree_sortkey openacs-5.7.0/packages/acs-subsite/www/admin/applications/index.adp0000644000175000017500000000023610721035753025176 0ustar frankiefrankie @page_title@ @context@ openacs-5.7.0/packages/acs-subsite/www/admin/applications/index.tcl0000644000175000017500000000512211552016774025220 0ustar frankiefrankiead_page_contract { Applications @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-02 @cvs-id $Id: index.tcl,v 1.10 2011/04/15 10:29:16 emmar Exp $ } set page_title "[_ acs-subsite.Applications]" set context [list $page_title] # Get the subsite node ID set subsite_url [site_node_closest_ancestor_package_url] array set subsite_sitenode [site_node::get -url $subsite_url] set subsite_node_id $subsite_sitenode(node_id) db_multirow -extend { parameter_url } applications select_applications {} { set instance_name "[string repeat .. $treelevel]$instance_name" if { $num_parameters > 0 } { set parameter_url [export_vars -base ../../shared/parameters { package_id { return_url [ad_return_url] } }] } } list::create \ -name applications \ -multirow applications \ -key node_id \ -actions { "#acs-subsite.Add_application#" application-add "#acs-subsite.Add_new_app#" } \ -bulk_actions { "#acs-subsite.Delete#" application-delete "#acs-subsite.Delete_selected_app#" } \ -elements { edit { sub_class narrow display_template { #acs-subsite.Edit_application_name_and_path# } link_url_eval {[export_vars -base application-add { node_id }]} link_html { title "#acs-subsite.Edit_application_name_and_path#" } } instance_name { label "[_ acs-subsite.Name]" link_url_eval {../../$name/} } name { label "[_ acs-subsite.URL]" } package_pretty_name { label "[_ acs-subsite.Application]" } permissions { label "[_ acs-subsite.Permissions]" link_url_eval {[export_vars -base permissions { package_id }]} display_template { #acs-subsite.Permissions# } sub_class narrow } parameters { label "[_ acs-subsite.Parameters]" link_url_col parameter_url display_template {[_ acs-subsite.Parameters]} sub_class narrow } delete { sub_class narrow display_template { #acs-subsite.Delete_this_application# } link_url_eval {[export_vars -base application-delete { node_id }]} link_html { title "#acs-subsite.Delete_this_application#" } } } openacs-5.7.0/packages/acs-subsite/www/admin/applications/multiple-add.adp0000644000175000017500000000033211552016774026452 0ustar frankiefrankie @doc.title@ @context@ application.package_key openacs-5.7.0/packages/acs-subsite/www/admin/applications/multiple-add.tcl0000644000175000017500000000305011552016774026470 0ustar frankiefrankiead_page_contract { Create and mount a new application. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-05-28 @cvs-id $Id: multiple-add.tcl,v 1.2 2011/04/15 10:29:16 emmar Exp $ } { {return_url "."} } set doc(title) "[_ acs-subsite.Add_multiple_applications]" set context [list [list "." [_ acs-subsite.Applications]] $doc(title)] set packages [subsite::get_application_options] ad_form -name application -cancel_url . -export { return_url } -form { {package_key:text(checkbox),multiple {label "[_ acs-subsite.Select_Applications]"} {options $packages} {help_text "[_ acs-subsite.Select_Applications__helptext]"} } } -on_submit { # Find the package pretty name from the list of packages array set package_pretty_name [list] foreach elm $packages { set package_pretty_name([lindex $elm 1]) [lindex $elm 0] } if { [catch { foreach one_package_key $package_key { set folder [site_node::verify_folder_name \ -parent_node_id [ad_conn node_id] \ -instance_name $package_pretty_name($one_package_key)] site_node::instantiate_and_mount \ -parent_node_id [ad_conn node_id] \ -node_name $folder \ -package_name $package_pretty_name($one_package_key) \ -package_key $one_package_key } } errmsg] } { global errorInfo ns_log Error "Error creating application: $errmsg\n$errorInfo" ad_return_error "Problem Creating Application" "We had a problem creating the application." } } -after_submit { ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/applications/index-oracle.xql0000644000175000017500000000133710204420554026475 0ustar frankiefrankie oracle8.1.6 select n.node_id, n.name, p.package_id, p.instance_name, pt.pretty_name as package_pretty_name, 0 as treelevel, (select count(*) from apm_parameters par where par.package_key = pt.package_key) as num_parameters from site_nodes n, apm_packages p, apm_package_types pt where n.parent_id = :subsite_node_id and p.package_id = n.object_id and pt.package_key = p.package_key order by lower(p.instance_name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/0000755000175000017500000000000011724401447022637 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/0000755000175000017500000000000011575225550023766 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/edit.adp0000644000175000017500000000032407663155117025404 0ustar frankiefrankie @context;noquote@ Edit @role;noquote@ role_form.role openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/edit.tcl0000644000175000017500000000266410551254377025431 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/roles/edit.tcl ad_page_contract { Form to edit a role @author mbryzek@arsdigita.com @creation-date Wed Dec 13 10:20:29 2000 @cvs-id $Id: edit.tcl,v 1.4 2007/01/10 21:22:07 gustafn Exp $ } { role:notnull { return_url "" } } -properties { context:onevalue } db_1row select_role_props { select r.pretty_name, r.pretty_plural from acs_rel_roles r where r.role = :role } set context [list [list "../" "Relationship types"] [list "one?[ad_export_vars role]" "One role"] "Edit"] template::form create role_form template::element create role_form return_url \ -optional \ -value $return_url \ -datatype text \ -widget hidden template::element create role_form role \ -value $role \ -datatype text \ -widget hidden template::element create role_form pretty_name \ -label "Pretty name" \ -value $pretty_name \ -datatype text \ -html {maxlength 100} template::element create role_form pretty_plural \ -label "Pretty plural" \ -value $pretty_plural \ -datatype text \ -html {maxlength 100} if { [template::form is_valid role_form] } { db_dml update_role { update acs_rel_roles r set r.pretty_name = :pretty_name, r.pretty_plural = :pretty_plural where r.role = :role } -bind [ns_getform] if { $return_url eq "" } { set return_url "one?[ad_export_vars role]" } ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/edit.xql0000644000175000017500000000072207523572210025436 0ustar frankiefrankie select r.pretty_name, r.pretty_plural from acs_rel_roles r where r.role = :role update acs_rel_roles set pretty_name = :pretty_name, pretty_plural = :pretty_plural where role = :role openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/new-postgresql.xql0000644000175000017500000000042407337765017027516 0ustar frankiefrankie postgresql7.1 select acs_rel_type__create_role(:role, :pretty_name, :pretty_plural) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/delete-2.tcl0000644000175000017500000000176410551254377026105 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/roles/delete-2.tcl ad_page_contract { Deletes a role if there are no relationship types that use it @author mbryzek@arsdigita.com @creation-date Mon Dec 11 11:30:53 2000 @cvs-id $Id: delete-2.tcl,v 1.2 2007/01/10 21:22:07 gustafn Exp $ } { role:notnull { operation "" } { return_url "" } } if {$operation eq "Yes, I really want to delete this role"} { db_transaction { if { [catch {db_exec_plsql drop_role {begin acs_rel_type.drop_role(:role);end;}} errmsg] } { if { [db_string role_used_p { select case when exists (select 1 from acs_rel_types where role_one = :role or role_two = :role) then 1 else 0 end from dual }] } { ad_return_complaint 1 "
  • The role \"$role\" is still in use. You must remove all relationship types that use this role before you can remove this role." return } else { ad_return_error "Error deleting role" $errmsg return } } } } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/new-oracle.xql0000644000175000017500000000050707300260125026536 0ustar frankiefrankie oracle8.1.6 begin acs_rel_type.create_role(role => :role, pretty_name => :pretty_name, pretty_plural => :pretty_plural); end; openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/new.adp0000644000175000017500000000031407663155117025247 0ustar frankiefrankie @context;noquote@ Create role role_form.role openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/new.tcl0000644000175000017500000000264310270055362025261 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/role-new.tcl ad_page_contract { Form to create a new role @author mbryzek@arsdigita.com @creation-date Mon Dec 11 10:52:35 2000 @cvs-id $Id: new.tcl,v 1.5 2005/07/22 02:33:22 skaufman Exp $ } { { role:trim "" } { pretty_name "" } { pretty_plural "" } { return_url "" } } -properties { context:onevalue } set context [list [list "../" "Relationship types"] [list "[ad_conn package_url]admin/rel-types/roles/" "Roles"] "Create role"] template::form create role_form template::element create role_form return_url \ -optional \ -value $return_url \ -datatype text \ -widget hidden template::element create role_form role \ -label "Role" \ -datatype text \ -html {maxlength 100} template::element create role_form pretty_name \ -label "Pretty name" \ -datatype text \ -html {maxlength 100} template::element create role_form pretty_plural \ -label "Pretty plural" \ -datatype text \ -html {maxlength 100} if { [template::form is_valid role_form] } { if { [db_string role_exists_p { select count(r.role) from acs_rel_roles r where r.role = :role }] } { ad_return_complaint 1 "
  • The role you entered \"$role\" already exists." return } db_transaction { rel_types::create_role -pretty_name $pretty_name -pretty_plural $pretty_plural -role $role } ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/new.xql0000644000175000017500000000032607300260125025272 0ustar frankiefrankie select count(r.role) from acs_rel_roles r where r.role = :role openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/index.adp0000644000175000017500000000056507663155117025575 0ustar frankiefrankie @context;noquote@ Roles openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/index.tcl0000644000175000017500000000212507573650157025611 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/roles.tcl ad_page_contract { Shows all roles with links to add/delete @author mbryzek@arsdigita.com @creation-date Mon Dec 11 11:08:34 2000 @cvs-id $Id: index.tcl,v 1.3 2002/12/05 13:11:11 peterm Exp $ } { } -properties { context:onevalue } set context [list [list "../" "Relationship types"] "Roles"] db_multirow roles select_roles { select r.role, r.pretty_name, nvl(num1.number_rels,0) + nvl(num2.number_rels,0) as number_rel_types from (select t.role_one as role, count(*) as number_rels from acs_rel_types t group by t.role_one) num1, (select t.role_two as role, count(*) as number_rels from acs_rel_types t group by t.role_two) num2, acs_rel_roles r where r.role = num1.role(+) and r.role = num2.role(+) order by lower(r.role) } { # The role pretty names can be message catalog keys that need # to be localized before they are displayed set pretty_name [lang::util::localize $pretty_name] } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/index.xql0000644000175000017500000000116307340116361025616 0ustar frankiefrankie select r.role, r.pretty_name, coalesce(num1.number_rels,0) + coalesce(num2.number_rels,0) as number_rel_types from acs_rel_roles r left join (select t.role_one as role, count(*) as number_rels from acs_rel_types t group by t.role_one) num1 on r.role=num1.role left join (select t.role_two as role, count(*) as number_rels from acs_rel_types t group by t.role_two) num2 on r.role=num2.role order by lower(r.role) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/delete-2-oracle.xql0000644000175000017500000000070207340116361027351 0ustar frankiefrankie oracle8.1.6 begin acs_rel_type.drop_role(:role);end; select case when exists (select 1 from acs_rel_types where role_one = :role or role_two = :role) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/one.adp0000644000175000017500000000147107663155117025244 0ustar frankiefrankie @context;noquote@ @role_props.pretty_name;noquote@

    Properties:

    • Role: @role@
    • Pretty name: @role_props.pretty_name@
    • Pretty plural: @role_props.pretty_plural@
    • Edit properties

    Relationship types that use this role:

    Administration

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/one.tcl0000644000175000017500000000270507573650157025267 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/roles/one.tcl ad_page_contract { Shows one role @author mbryzek@arsdigita.com @creation-date Mon Dec 11 11:08:34 2000 @cvs-id $Id: one.tcl,v 1.4 2002/12/05 13:11:11 peterm Exp $ } { role:notnull } -properties { context:onevalue role:onevalue role_enc:onevalue role_props:onerow rels_side_one:multirow rels_side_two:multirow } set role_enc [ad_urlencode $role] set context [list [list "../" "Relationship types"] [list "[ad_conn package_url]admin/rel-types/roles/" "Roles"] "One role"] if { ![db_0or1row select_role_props { select r.pretty_name, r.pretty_plural from acs_rel_roles r where r.role = :role } -column_array role_props] } { ad_return_error "Role doesn't exist" "The role \"$role\" could not be found." ad_script_abort } # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_props(pretty_name) [lang::util::localize $role_props(pretty_name)] set role_props(pretty_plural) [lang::util::localize $role_props(pretty_plural)] db_multirow rels select_rel_types_one { select r.rel_type as role, t.pretty_name, r.rel_type, decode(r.role_one,:role,'Side one', 'Side two') as side from acs_object_types t, acs_rel_types r where t.object_type = r.rel_type and (r.role_one = :role or r.role_two = :role) order by side, t.pretty_name } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/one.xql0000644000175000017500000000123407300260125025261 0ustar frankiefrankie select r.pretty_name, r.pretty_plural from acs_rel_roles r where r.role = :role select r.rel_type as role, t.pretty_name, r.rel_type, case when r.role_one = :role then 'Side one' else 'Side two' end as side from acs_object_types t, acs_rel_types r where t.object_type = r.rel_type and (r.role_one = :role or r.role_two = :role) order by side, t.pretty_name openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/index-oracle.xql0000644000175000017500000000130107300260125027045 0ustar frankiefrankie oracle8.1.6 select r.role, r.pretty_name, nvl(num1.number_rels,0) + nvl(num2.number_rels,0) as number_rel_types from (select t.role_one as role, count(*) as number_rels from acs_rel_types t group by t.role_one) num1, (select t.role_two as role, count(*) as number_rels from acs_rel_types t group by t.role_two) num2, acs_rel_roles r where r.role = num1.role(+) and r.role = num2.role(+) order by lower(r.role) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/delete.adp0000644000175000017500000000060407663155117025722 0ustar frankiefrankie @context;noquote@ Delete @pretty_name;noquote@ Are you sure you want to delete this role?

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/delete.tcl0000644000175000017500000000137207536221413025733 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/roles/delete.tcl ad_page_contract { Deletes a role if there are no relationship types that use it @author mbryzek@arsdigita.com @creation-date Mon Dec 11 11:30:53 2000 @cvs-id $Id: delete.tcl,v 1.2 2002/09/06 21:50:03 jeffd Exp $ } { role:notnull { return_url "" } } -properties { context:onevalue pretty_name:onevalue export_vars:onevalue } set context [list [list "../" "Relationship types"] [list "" "Roles"] [list one?[ad_export_vars role] "One role"] "Delete role"] set export_vars [ad_export_vars -form {role return_url}] set pretty_name [db_string select_role_pretty_name { select r.pretty_name from acs_rel_roles r where r.role = :role }] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/delete.xql0000644000175000017500000000033707300260125025745 0ustar frankiefrankie select r.pretty_name from acs_rel_roles r where r.role = :role openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/roles/delete-2-postgresql.xql0000644000175000017500000000067107340116361030314 0ustar frankiefrankie postgresql7.1 select acs_rel_type__drop_role(:role) select case when exists (select 1 from acs_rel_types where role_one = :role or role_two = :role) then 1 else 0 end openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-subtypes-exist.adp0000644000175000017500000000064007663155071027603 0ustar frankiefrankie @context;noquote@ Subtypes exist! You must remove all subtypes of the relationship type "@rel_type_pretty_name@" before you can remove the group type.

    The following subtypes currently exist:

    • @subtypes.pretty_name@ (delete)
    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-postgresql.xql0000644000175000017500000000106107403013337026351 0ustar frankiefrankie postgresql7.1 select repeat(' ', (tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4) || t2.pretty_name as name, t2.object_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type in ('membership_rel', 'composition_rel') openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/add-2.tcl0000644000175000017500000000106107253523116024230 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-type/add-2.tcl ad_page_contract { Adds relation type @author mbryzek@arsdigita.com @creation-date Sun Nov 12 18:05:09 2000 @cvs-id $Id: add-2.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ } { constraint_id:integer,notnull rel_type:notnull object_type:notnull { return_url "" } } db_dml update_rel_type_mapping { insert into group_type_allowed_rels (constraint_id, group_type, rel_type) values (:constraint_id, :object_type, :rel_type) } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/add-2.xql0000644000175000017500000000044707300260125024250 0ustar frankiefrankie insert into group_type_allowed_rels (constraint_id, group_type, rel_type) values (:constraint_id, :object_type, :rel_type) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-2.tcl0000644000175000017500000000463710551254377024763 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/delete-2.tcl ad_page_contract { Deletes the relationship type @author mbryzek@arsdigita.com @creation-date Mon Dec 11 12:00:12 2000 @cvs-id $Id: delete-2.tcl,v 1.3 2007/01/10 21:22:07 gustafn Exp $ } { rel_type:notnull,rel_type_dynamic_p { operation "" } { return_url "" } } if { $operation ne "Yes, I really want to delete this relationship type" } { # set the return_url to something useful if we are not deleting if { $return_url eq "" } { set return_url "one?[ad_export_vars rel_type]" } } else { db_1row select_type_info { select t.table_name from acs_object_types t where t.object_type = :rel_type } set user_id [ad_conn user_id] set rel_id_list [db_list select_rel_ids { select r.rel_id from acs_rels r, acs_object_party_privilege_map perm where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'delete' and r.rel_type = :rel_type }] set segment_id [db_string select_segment_id { select s.segment_id from rel_segments s, acs_object_party_privilege_map perm where perm.object_id = s.segment_id and perm.party_id = :user_id and perm.privilege = 'delete' and s.rel_type = :rel_type } -default ""] # delete all relations, all segments, and drop the relationship # type. This will fail if a relation / segment for this type is created # after we select out the list of rels/segments to delete but before we # finish dropping the type. db_transaction { foreach rel_id $rel_id_list { relation_remove $rel_id } if { $segment_id ne "" } { rel_segments_delete $segment_id } db_exec_plsql drop_relationship_type { BEGIN acs_rel_type.drop_type( rel_type => :rel_type, cascade_p => 't' ); END; } } on_error { ad_return_error "Error deleting relationship type" "We got the following error trying to delete this relationship type:
    $errmsg
    " ad_script_abort } # If we successfully dropped the relationship type, drop the table. # Note that we do this outside the transaction as it commits all # transactions anyway if { [db_table_exists $table_name] } { db_exec_plsql drop_type_table "drop table $table_name" } } # Reset the attribute view for objects of this type package_object_view_reset $rel_type ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-2.xql0000644000175000017500000000154507300260125024762 0ustar frankiefrankie select t.table_name from acs_object_types t where t.object_type = :rel_type select r.rel_id from acs_rels r, acs_object_party_privilege_map perm where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'delete' and r.rel_type = :rel_type select s.segment_id from rel_segments s, acs_object_party_privilege_map perm where perm.object_id = s.segment_id and perm.party_id = :user_id and perm.privilege = 'delete' and s.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/one-postgresql.xql0000644000175000017500000000270007401227553026347 0ustar frankiefrankie postgresql7.1 select t1.pretty_name as object_type_one_pretty_name, r.object_type_one, acs_rel_type__role_pretty_name(r.role_one) as role_one_pretty_name, r.role_one, r.min_n_rels_one, r.max_n_rels_one, t2.pretty_name as object_type_two_pretty_name, r.object_type_two, acs_rel_type__role_pretty_name(r.role_two) as role_two_pretty_name, r.role_two, r.min_n_rels_two, r.max_n_rels_two from acs_rel_types r, acs_object_types t1, acs_object_types t2 where r.rel_type = :rel_type and r.object_type_one = t1.object_type and r.object_type_two = t2.object_type select v_inner.* from (select r.rel_id, acs_object__name(r.object_id_one) || ' and ' || acs_object__name(r.object_id_two) as name from acs_rels r, app_group_distinct_rel_map m where acs_permission__permission_p(r.rel_id, :user_id, 'read') and r.rel_type = :rel_type and m.rel_id = r.rel_id and m.package_id = :package_id order by lower(acs_object__name(r.object_id_one)), lower(acs_object__name(r.object_id_two))) v_inner limit 26 openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-oracle.xql0000644000175000017500000000073207300260125025412 0ustar frankiefrankie oracle8.1.6 select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name as name, t.object_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel','composition_rel') openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new.adp0000644000175000017500000000112711553376447024132 0ustar frankiefrankie @context;noquote@ #acs-subsite.Create_relation_type#

    #acs-subsite.Create_relation_type#

    #acs-subsite.First_select_the_supertype#

    @export_vars;noquote@
    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new.tcl0000644000175000017500000000153711553376447024155 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-type/new.tcl ad_page_contract { Form to select a supertype for a new relationship type @author mbryzek@arsdigita.com @creation-date Sun Nov 12 18:27:08 2000 @cvs-id $Id: new.tcl,v 1.4 2011/04/19 21:22:47 emmar Exp $ } { { return_url "" } } -properties { context:onevalue } db_multirow supertypes select_supertypes { select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name as name, t.object_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel','composition_rel') } set context [list [list "[ad_conn package_url]admin/rel-types/" [_ acs-subsite.Relationship_Types]] [_ acs-subsite.Create_relation_type]] set export_vars [ad_export_vars -form {return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/index-postgresql.xql0000644000175000017500000000222607403013337026673 0ustar frankiefrankie postgresql7.1 select t.object_type as rel_type, t.pretty_name, t.indent, coalesce(num.number_relationships,0) as number_relationships from (select t2.pretty_name, t2.object_type, t2.tree_sortkey as inner_sortkey, repeat(' ', (tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4) as indent from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type in ('membership_rel', 'composition_rel')) t left join (select r.rel_type, count(*) as number_relationships from acs_objects o, acs_rel_types r, app_group_distinct_rel_map m where r.rel_type = o.object_type and o.object_id = m.rel_id and m.package_id = :package_id group by r.rel_type) num on (t.object_type = num.rel_type) order by t.inner_sortkey openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/index.adp0000644000175000017500000000145611553376447024455 0ustar frankiefrankie @context;noquote@ #acs-subsite.Relationship_types_administration#

    #acs-subsite.Relationship_types_administration#

    #acs-subsite.Currently_the_system_is_able_to_handle_the_following_types_of_relationships#

    • #acs-subsite.none#
    • @rel_types.indent;noquote@@rel_types.pretty_name@ (#acs-subsite.number_of_relationships_defined#: @rel_types.number_relationships@)
    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/index.tcl0000644000175000017500000000310211553376447024461 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/index.tcl ad_page_contract { Shows list of all defined relationship types, excluding the parent type "relationship" @author mbryzek@arsdigita.com @creation-date Sun Dec 10 17:10:56 2000 @cvs-id $Id: index.tcl,v 1.3 2011/04/19 21:22:47 emmar Exp $ } { } -properties { context:onevalue rel_types:multirow } set context [list [_ acs-subsite.Relationship_Types]] set package_id [ad_conn package_id] # Select out all relationship types, excluding the parent type names 'relationship' # Count up the number of relations that exists for each type. db_multirow rel_types select_relation_types { select t.object_type as rel_type, t.pretty_name, t.indent, nvl(num.number_relationships,0) as number_relationships from (select t.pretty_name, t.object_type, rownum as inner_rownum, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel','composition_rel') order by lower(t.pretty_name)) t, (select r.rel_type, count(*) as number_relationships from acs_objects o, acs_rel_types r, app_group_distinct_rel_map m where r.rel_type = o.object_type and o.object_id = m.rel_id and m.package_id = :package_id group by r.rel_type) num where t.object_type = num.rel_type(+) order by t.inner_rownum } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/rels-list.adp0000644000175000017500000000056607663155071025260 0ustar frankiefrankie @context;noquote@ All relations of type "@rel_type_pretty_name;noquote@"
    • (none)
    1. @rels.name@
    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/rels-list.tcl0000644000175000017500000000251207536221413025260 0ustar frankiefrankie# /packages/acs-subsite/www/admin/rel-types/rels-list.tcl ad_page_contract { Displays all relations for the specified rel_type @author mbryzek@arsdigita.com @creation-date Fri Jan 12 20:52:33 2001 @cvs-id $Id: rels-list.tcl,v 1.2 2002/09/06 21:50:03 jeffd Exp $ } { rel_type:notnull } -properties { context:onevalue rel_type_pretty_name:onevalue rels:multirow } set user_id [ad_conn user_id] set package_id [ad_conn package_id] set context [list [list "" "Relationship types"] [list one?[ad_export_vars rel_type] "One type"] "Relations"] if { ![db_0or1row select_pretty_name { select t.pretty_name as rel_type_pretty_name from acs_object_types t where t.object_type = :rel_type }] } { ad_return_error "Relationship type doesn't exist" "Relationship type \"$rel_type\" doesn't exist" return } db_multirow rels rels_select { select r.rel_id, acs_object.name(r.object_id_one) || ' and ' || acs_object.name(r.object_id_two) as name from acs_rels r, acs_object_party_privilege_map perm, app_group_distinct_rel_map m where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and r.rel_type = :rel_type and m.rel_id = r.rel_id and m.package_id = :package_id order by lower(name) } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/rels-list.xql0000644000175000017500000000041307300260125025270 0ustar frankiefrankie select t.pretty_name as rel_type_pretty_name from acs_object_types t where t.object_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/add.adp0000644000175000017500000000105407663155071024063 0ustar frankiefrankie @context;noquote@ Add group type
    @export_form_vars@ Select relation type:
    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/add.tcl0000644000175000017500000000200307536221413024065 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-type/add.tcl ad_page_contract { Add a permissible relation type to a group type @author mbryzek@arsdigita.com @creation-date Sun Nov 12 17:50:04 2000 @cvs-id $Id: add.tcl,v 1.3 2002/09/06 21:50:03 jeffd Exp $ } { object_type:notnull { return_url "" } } -properties { context:onevalue export_form_vars:onevalue export_url_vars:onevalue primary_rels:multirow } set context [list "Add relation type"] set constraint_id [db_nextval "acs_object_id_seq"] set export_form_vars [export_form_vars constraint_id object_type return_url] set export_url_vars [export_url_vars constraint_id object_type return_url] db_multirow primary_rels select_primary_relations { select o.object_type as rel_type, o.pretty_name from acs_object_types o where o.object_type in ('composition_rel','membership_rel') and o.object_type not in (select g.rel_type from group_type_allowed_rels g where g.group_type = :object_type) } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/add.xql0000644000175000017500000000064507300260125024111 0ustar frankiefrankie select o.object_type as rel_type, o.pretty_name from acs_object_types o where o.object_type in ('composition_rel','membership_rel') and o.object_type not in (select g.rel_type from group_type_allowed_rels g where g.group_type = :object_type) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/mapping-remove.tcl0000644000175000017500000000224007536221413026266 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/mapping-remove.tcl ad_page_contract { Confirmation to remove an allowable relation type @author mbryzek@arsdigita.com @creation-date Sun Dec 10 16:40:11 2000 @cvs-id $Id: mapping-remove.tcl,v 1.2 2002/09/06 21:50:03 jeffd Exp $ } { { group_rel_type_id:naturalnum "" } { group_rel_id:naturalnum "" } { return_url "" } } -properties { context:onevalue rel_pretty_name:onevalue group_pretty_name:onevalue export_vars:onevalue } if { ![db_0or1row select_info { select g.rel_type, g.group_type, t.pretty_name as rel_pretty_name, t2.pretty_name as group_type_pretty_name from acs_object_types t, acs_object_types t2, group_type_rels g where g.group_rel_type_id = :group_rel_type_id and t.object_type = g.rel_type and t2.object_type = g.group_type }] } { ad_return_error "Relation already removed." "Please back up and reload" return } set export_vars [ad_export_vars -form {group_rel_type_id return_url}] set context [list [list "" "Group types"] [list one?[ad_export_vars {group_type}] "One type"] "Remove relation type"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/mapping-remove.xql0000644000175000017500000000072507300260125026306 0ustar frankiefrankie select g.rel_type, g.group_type, t.pretty_name as rel_pretty_name, t2.pretty_name as group_type_pretty_name from acs_object_types t, acs_object_types t2, group_type_rels g where g.group_rel_type_id = :group_rel_type_id and t.object_type = g.rel_type and t2.object_type = g.group_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-2-oracle.xql0000644000175000017500000000073407300260125026224 0ustar frankiefrankie oracle8.1.6 BEGIN acs_rel_type.drop_type( rel_type => :rel_type, cascade_p => 't' ); END; drop table $table_name openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-2-oracle.xql0000644000175000017500000000250507346706214025567 0ustar frankiefrankie oracle8.1.6 select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name, t.object_type as rel_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type=:max_object_type_one select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name, t.object_type as rel_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type=:max_object_type_two select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end from dual select case when exists (select 1 from acs_object_types t where t.pretty_plural = :pretty_plural) then 1 else 0 end from dual openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/one.adp0000644000175000017500000000517507663155071024124 0ustar frankiefrankie @context;noquote@ Relationship Type "@rel_type_pretty_name;noquote@"

    Relations of this type

    Attributes of this type of relationship

    Properties of this type of relationship

    Administration

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/one.tcl0000644000175000017500000000532507536221413024130 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/one.tcl ad_page_contract { Shows information about one relationship type @author mbryzek@arsdigita.com @creation-date Sun Dec 10 17:24:21 2000 @cvs-id $Id: one.tcl,v 1.3 2002/09/06 21:50:03 jeffd Exp $ } { rel_type:notnull } -properties { context:onevalue rel_type:onevalue rel_type_enc:onevalue rel_type_pretty_name:onevalue dynamic_p:onevalue rels:multirow attributes:multirow properties:onerow return_url_enc:onevalue } set return_url [ad_conn url]?[ad_conn query] set return_url_enc [ad_urlencode $return_url] set rel_type_enc [ad_urlencode $rel_type] set package_id [ad_conn package_id] set context [list [list "./" "Relationship types"] "One type"] if { ![db_0or1row select_pretty_name { select t.pretty_name as rel_type_pretty_name, t.table_name, t.id_column, t.dynamic_p from acs_object_types t where t.object_type = :rel_type }] } { ad_return_error "Relationship type doesn't exist" "Relationship type \"$rel_type\" doesn't exist" return } db_1row select_rel_type_properties { select t1.pretty_name as object_type_one_pretty_name, r.object_type_one, acs_rel_type.role_pretty_name(r.role_one) as role_one_pretty_name, r.role_one, r.min_n_rels_one, r.max_n_rels_one, t2.pretty_name as object_type_two_pretty_name, r.object_type_two, acs_rel_type.role_pretty_name(r.role_two) as role_two_pretty_name, r.role_two, r.min_n_rels_two, r.max_n_rels_two from acs_rel_types r, acs_object_types t1, acs_object_types t2 where r.rel_type = :rel_type and r.object_type_one = t1.object_type and r.object_type_two = t2.object_type } -column_array properties set user_id [ad_conn user_id] # We display up to 25 relations, and then offer a link for the rest. # Pull out all the relations of this type db_multirow rels rels_select { select inner.* from (select r.rel_id, acs_object.name(r.object_id_one) || ' and ' || acs_object.name(r.object_id_two) as name from acs_rels r, acs_object_party_privilege_map perm, app_group_distinct_rel_map m where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and r.rel_type = :rel_type and m.rel_id = r.rel_id and m.package_id = :package_id order by lower(acs_object.name(r.object_id_one)), lower(acs_object.name(r.object_id_two))) inner where rownum <= 26 } db_multirow attributes attributes_select { select a.attribute_id, a.pretty_name from acs_attributes a where a.object_type = :rel_type } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/one.xql0000644000175000017500000000100507300260125024131 0ustar frankiefrankie select t.pretty_name as rel_type_pretty_name, t.table_name, t.id_column, t.dynamic_p from acs_object_types t where t.object_type = :rel_type select a.attribute_id, a.pretty_name from acs_attributes a where a.object_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/index-oracle.xql0000644000175000017500000000214707300260125025732 0ustar frankiefrankie oracle8.1.6 select t.object_type as rel_type, t.pretty_name, t.indent, nvl(num.number_relationships,0) as number_relationships from (select t.pretty_name, t.object_type, rownum as inner_rownum, replace(lpad(' ', (level - 1) * 4), ' ', ' ') as indent from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type in ('membership_rel','composition_rel') order by lower(t.pretty_name)) t, (select r.rel_type, count(*) as number_relationships from acs_objects o, acs_rel_types r, app_group_distinct_rel_map m where r.rel_type = o.object_type and o.object_id = m.rel_id and m.package_id = :package_id group by r.rel_type) num where t.object_type = num.rel_type(+) order by t.inner_rownum openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete.adp0000644000175000017500000000133707663155071024601 0ustar frankiefrankie @context;noquote@ Delete @rel_type_pretty_name;noquote@ Are you sure you want to delete this relationship type? Doing so will:
    • Remove all relational segments that use this relationship type (number of segments defined: @counts.segments@)
    • Remove all the relations of this type (number of relations defined: @counts.rels@)
    • Remove this relationship type

    openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete.tcl0000644000175000017500000000351407536221413024607 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/delete.tcl ad_page_contract { Confirms deletion of a relationship type @author mbryzek@arsdigita.com @creation-date Mon Dec 11 11:57:29 2000 @cvs-id $Id: delete.tcl,v 1.2 2002/09/06 21:50:03 jeffd Exp $ } { rel_type:notnull,rel_type_dynamic_p { return_url "" } } -properties { context:onevalue rel_type_pretty_name:onevalue rel_type:onevalue counts:onerow } set context [list [list "" "Relationship types"] [list one?[ad_export_vars rel_type] "One type"] "Delete type"] set rel_type_pretty_name [db_string select_pretty_name { select t.pretty_name from acs_object_types t where t.object_type = :rel_type }] set subtypes_exist_p [db_string number_subtypes { select case when exists (select 1 from acs_object_types t where t.supertype = :rel_type) then 1 else 0 end from dual }] if { $subtypes_exist_p } { set return_url "[ad_conn url]?[ad_conn query]" # Just grab direct children... template::multirow create subtypes rel_type pretty_name export_vars db_foreach select_subtypes { select t.object_type as rel_type, t.pretty_name from acs_object_types t where t.supertype = :rel_type } { template::multirow append subtypes $rel_type $pretty_name [ad_export_vars {rel_type return_url}] } ad_return_template "delete-subtypes-exist" return } # Now let's count up the number of things we're going to delete db_1row select_counts { select (select count(*) from rel_segments where rel_type = :rel_type) as segments, (select count(*) from acs_rels where rel_type = :rel_type) as rels from dual } -column_array counts set export_vars [ad_export_vars -form {rel_type return_url}] ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete.xql0000644000175000017500000000072707300260125024624 0ustar frankiefrankie select t.pretty_name from acs_object_types t where t.object_type = :rel_type select t.object_type as rel_type, t.pretty_name from acs_object_types t where t.supertype = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-2-postgresql.xql0000644000175000017500000000274507403013337026522 0ustar frankiefrankie postgresql7.1 select repeat(' ', ((tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4)) || t2.pretty_name, t2.object_type as rel_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type = :max_object_type_one select repeat(' ', ((tree_level(t2.tree_sortkey) - tree_level(t1.tree_sortkey)) * 4)) || t2.pretty_name, t2.object_type as rel_type from acs_object_types t1, acs_object_types t2 where t2.tree_sortkey between t1.tree_sortkey and tree_right(t1.tree_sortkey) and t1.object_type = :max_object_type_two select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end select case when exists (select 1 from acs_object_types t where t.pretty_plural = :pretty_plural) then 1 else 0 end openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/rels-list-oracle.xql0000644000175000017500000000121507300260125026534 0ustar frankiefrankie oracle8.1.6 select r.rel_id, acs_object.name(r.object_id_one) || ' and ' || acs_object.name(r.object_id_two) as name from acs_rels r, acs_object_party_privilege_map perm, app_group_distinct_rel_map m where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and r.rel_type = :rel_type and m.rel_id = r.rel_id and m.package_id = :package_id order by lower(name) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-oracle.xql0000644000175000017500000000127207300260125026063 0ustar frankiefrankie oracle8.1.6 select case when exists (select 1 from acs_object_types t where t.supertype = :rel_type) then 1 else 0 end from dual select (select count(*) from rel_segments where rel_type = :rel_type) as segments, (select count(*) from acs_rels where rel_type = :rel_type) as rels from dual openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-postgresql.xql0000644000175000017500000000125207300260125027017 0ustar frankiefrankie postgresql7.1 select case when exists (select 1 from acs_object_types t where t.supertype = :rel_type) then 1 else 0 end select (select count(*) from rel_segments where rel_type = :rel_type) as segments, (select count(*) from acs_rels where rel_type = :rel_type) as rels openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/mapping-remove-2.tcl0000644000175000017500000000163510551254377026442 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-types/mapping-remove.tcl ad_page_contract { Removes a mapping for a permissible rel_type between either a group or a group_type @author mbryzek@arsdigita.com @creation-date Tue Dec 12 10:45:07 2000 @cvs-id $Id: mapping-remove-2.tcl,v 1.4 2007/01/10 21:22:07 gustafn Exp $ } { { group_rel_id:integer "" } { group_type_rel_id "" } { return_url "" } } -properties { context:onevalue } if { $group_rel_id eq "" || $group_type_rel_id eq "" } { error "Either group_rel_id or group_rel_type_id must be specified" } if { $group_rel_id ne "" } { db_dml delete_group_rel_mapping { delete from group_rels where group_rel_id = :group_rel_id } } elseif { $group_rel_id ne "" } { db_dml delete_group_type_rel_mapping { delete from group_type_rels where group_type_rel_id = :group_type_rel_id } } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/mapping-remove-2.xql0000644000175000017500000000064407300260125026445 0ustar frankiefrankie delete from group_rels where group_rel_id = :group_rel_id delete from group_type_rels where group_type_rel_id = :group_type_rel_id openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/rels-list-postgresql.xql0000644000175000017500000000133607743520760027515 0ustar frankiefrankie postgresql7.1 select r.rel_id, acs_object__name(r.object_id_one) || ' and ' || acs_object__name(r.object_id_two) as name from acs_rels r, acs_object_party_privilege_map perm, app_group_distinct_rel_map m where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and r.rel_type = :rel_type and m.rel_id = r.rel_id and m.package_id = :package_id order by lower(acs_object__name(r.object_id_one) || ' and ' || acs_object__name(r.object_id_two)) openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/one-oracle.xql0000644000175000017500000000306707300260125025406 0ustar frankiefrankie oracle8.1.6 select t1.pretty_name as object_type_one_pretty_name, r.object_type_one, acs_rel_type.role_pretty_name(r.role_one) as role_one_pretty_name, r.role_one, r.min_n_rels_one, r.max_n_rels_one, t2.pretty_name as object_type_two_pretty_name, r.object_type_two, acs_rel_type.role_pretty_name(r.role_two) as role_two_pretty_name, r.role_two, r.min_n_rels_two, r.max_n_rels_two from acs_rel_types r, acs_object_types t1, acs_object_types t2 where r.rel_type = :rel_type and r.object_type_one = t1.object_type and r.object_type_two = t2.object_type select inner.* from (select r.rel_id, acs_object.name(r.object_id_one) || ' and ' || acs_object.name(r.object_id_two) as name from acs_rels r, acs_object_party_privilege_map perm, app_group_distinct_rel_map m where perm.object_id = r.rel_id and perm.party_id = :user_id and perm.privilege = 'read' and r.rel_type = :rel_type and m.rel_id = r.rel_id and m.package_id = :package_id order by lower(acs_object.name(r.object_id_one)), lower(acs_object.name(r.object_id_two))) inner where rownum <= 26 openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/delete-2-postgresql.xql0000644000175000017500000000155207401227553027173 0ustar frankiefrankie postgresql7.1 select acs_rel_type__drop_type(:rel_type,'t') drop table $table_name select r.rel_id from acs_rels r where acs_permission__permission_p(r.rel_id, :user_id, 'delete') and r.rel_type = :rel_type select s.segment_id from rel_segments s where acs_permission__permission_p(s.segment_id, :user_id, 'delete') and s.rel_type = :rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-2.adp0000644000175000017500000000040207663155071024257 0ustar frankiefrankie @context;noquote@ Create relation type (child of @supertype_pretty_name;noquote@) rel_type.rel_type openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-2.tcl0000644000175000017500000001477510270075342024305 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/rel-type/new.tcl ad_page_contract { Form to create a new relationship type @author mbryzek@arsdigita.com @creation-date Sun Nov 12 18:27:08 2000 @cvs-id $Id: new-2.tcl,v 1.6 2005/07/22 04:49:38 skaufman Exp $ } { supertype:trim,notnull rel_type:optional pretty_name:optional pretty_plural:optional object_type_one:optional role_one:optional min_n_rels_one:optional max_n_rels_one:optional object_type_two:optional role_two:optional min_n_rels_two:optional max_n_rels_two:optional { return_url "" } } -properties { context:onevalue supertype_pretty_name:onevalue } set context [list [list "[ad_conn package_url]admin/rel-types/" "Relationship types"] "Add relation type"] template::form create rel_type template::element create rel_type return_url \ -optional \ -value $return_url \ -datatype text \ -widget hidden template::element create rel_type supertype \ -value $supertype \ -datatype text \ -widget hidden template::element create rel_type rel_type \ -label "Relation type" \ -datatype text \ -html {maxlength 100} template::element create rel_type pretty_name \ -label "Pretty name" \ -datatype text \ -html {maxlength 100} template::element create rel_type pretty_plural \ -label "Pretty plural" \ -datatype text \ -html {maxlength 100} # Select out the objects from which to generate pick lists for the # relationship type db_1row select_object_types { select r.object_type_one as max_object_type_one, r.object_type_two as max_object_type_two, t.pretty_name as supertype_pretty_name, r.role_one as supertype_role_one, r.role_two as supertype_role_two, r.min_n_rels_one as supertype_min_n_rels_one, r.max_n_rels_one as supertype_max_n_rels_one, r.min_n_rels_two as supertype_min_n_rels_two, r.max_n_rels_two as supertype_max_n_rels_two from acs_object_types t, acs_rel_types r where r.rel_type = :supertype and r.rel_type = t.object_type } set object_types_one_list [db_list_of_lists select_object_types_one { select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name, t.object_type as rel_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type=:max_object_type_one }] foreach obj $object_types_one_list { lappend object_types_one_list_i18n [lang::util::localize $obj] } set object_types_two_list [db_list_of_lists select_object_types_two { select replace(lpad(' ', (level - 1) * 4), ' ', ' ') || t.pretty_name, t.object_type as rel_type from acs_object_types t connect by prior t.object_type = t.supertype start with t.object_type=:max_object_type_two }] foreach obj $object_types_two_list { lappend object_types_two_list_i18n [lang::util::localize $obj] } set roles_list [db_list_of_lists select_roles { select r.pretty_name, r.role from acs_rel_roles r order by lower(r.role) }] foreach role $roles_list { lappend roles_list_i18n [lang::util::localize $role] } template::element create rel_type object_type_one \ -label "Object type one" \ -datatype text \ -widget select \ -options $object_types_one_list_i18n # Set return_url here to set it up correctly for use with roles set role_return_url_enc [ad_urlencode "[ad_conn url]?[ad_conn query]"] template::element create rel_type role_one \ -label "Role one
    (create new role)" \ -datatype text \ -widget select \ -options $roles_list_i18n template::element create rel_type min_n_rels_one \ -value $supertype_min_n_rels_one \ -label "Min n rels one" \ -datatype integer template::element create rel_type max_n_rels_one \ -optional \ -value $supertype_max_n_rels_one \ -label "Max n rels one" \ -datatype integer template::element create rel_type object_type_two \ -label "Object type two" \ -datatype text \ -widget select \ -options $object_types_two_list_i18n template::element create rel_type role_two \ -label "Role two
    (create new role)" \ -datatype text \ -widget select \ -options $roles_list_i18n template::element create rel_type min_n_rels_two \ -value $supertype_min_n_rels_two \ -label "Min n rels two" \ -datatype integer template::element create rel_type max_n_rels_two \ -optional \ -value $supertype_max_n_rels_two \ -label "Max n rels two" \ -datatype integer if { [template::form is_request rel_type] } { template::element set_properties rel_type role_one -value $supertype_role_one template::element set_properties rel_type role_two -value $supertype_role_two } if { [template::form is_valid rel_type] } { set exception_count 0 set safe_rel_type [plsql_utility::generate_oracle_name -max_length 29 $rel_type] if { [plsql_utility::object_type_exists_p $safe_rel_type] } { incr exception_count append exception_text "
  • The specified type for this relationship, $rel_type, already exists. [ad_decode $safe_rel_type $rel_type "" "Note that we converted the object type to \"$safe_rel_type\" to ensure that the name would be safe for the database."] Please back up and choose another.
  • " } else { # let's make sure the names are unique if { [db_string pretty_name_unique { select case when exists (select 1 from acs_object_types t where t.pretty_name = :pretty_name) then 1 else 0 end from dual }] } { incr exception_count append exception_text "
  • The specified pretty name, $pretty_name, already exists. Please enter another
  • " } if { [db_string pretty_plural_unique { select case when exists (select 1 from acs_object_types t where t.pretty_plural = :pretty_plural) then 1 else 0 end from dual }] } { incr exception_count append exception_text "
  • The specified pretty plural, $pretty_plural, already exists. Please enter another
  • " } } if { $exception_count > 0 } { ad_return_complaint $exception_count $exception_text ad_script_abort } rel_types::new \ -supertype $supertype \ -role_one $role_one \ -role_two $role_two \ $rel_type \ $pretty_name \ $pretty_plural \ $object_type_one \ $min_n_rels_one \ $max_n_rels_one \ $object_type_two \ $min_n_rels_two \ $max_n_rels_two ad_returnredirect $return_url ad_script_abort } ad_return_template openacs-5.7.0/packages/acs-subsite/www/admin/rel-types/new-2.xql0000644000175000017500000000163307300260125024307 0ustar frankiefrankie select r.object_type_one as max_object_type_one, r.object_type_two as max_object_type_two, t.pretty_name as supertype_pretty_name, r.role_one as supertype_role_one, r.role_two as supertype_role_two, r.min_n_rels_one as supertype_min_n_rels_one, r.max_n_rels_one as supertype_max_n_rels_one, r.min_n_rels_two as supertype_min_n_rels_two, r.max_n_rels_two as supertype_max_n_rels_two from acs_object_types t, acs_rel_types r where r.rel_type = :supertype and r.rel_type = t.object_type select r.pretty_name, r.role from acs_rel_roles r order by lower(r.role) openacs-5.7.0/packages/acs-subsite/www/admin/object-types/0000755000175000017500000000000011724401447023323 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/admin/object-types/alphabetical-index.adp0000644000175000017500000000056711553071716027541 0ustar frankiefrankie @doc.title@ @context@

    @doc.title@

    View Hierarchical Index

    openacs-5.7.0/packages/acs-subsite/www/admin/object-types/alphabetical-index.tcl0000644000175000017500000000064511553071716027554 0ustar frankiefrankiead_page_contract { Index of all object types (alphabetical, not hierarchichal) @author Yonatan Feldman (yon@arsdigita.com) @creation-date August 15, 2000 @cvs-id $Id: alphabetical-index.tcl,v 1.6 2011/04/18 17:24:30 emmar Exp $ } {} set doc(title) "Object Type Alphabetical Index" set context [list "Object Type Alphabetical Index"] db_multirow alpha_object_types object_type_in_alphabetical_order {} openacs-5.7.0/packages/acs-subsite/www/admin/object-types/alphabetical-index.xql0000644000175000017500000000042207300260124027553 0ustar frankiefrankie select object_type, pretty_name from acs_object_types order by lower(pretty_name) openacs-5.7.0/packages/acs-subsite/www/admin/object-types/one-postgresql.xql0000644000175000017500000000050707344207710027035 0ustar frankiefrankie postgresql7.1 select definition || '\n' as text from acs_func_defs where fname ilike :package_name || '__%' order by fname openacs-5.7.0/packages/acs-subsite/www/admin/object-types/index.adp0000644000175000017500000000041411553071716025121 0ustar frankiefrankie @doc.title@ @context@

    @doc.title@

    #acs-subsite.View_Alphabetical_Index#

    @object_type_hierarchy;noquote@

    openacs-5.7.0/packages/acs-subsite/www/admin/object-types/index.tcl0000644000175000017500000000060011553071716025134 0ustar frankiefrankiead_page_contract { Home page for OpenACS Object Type administration @author Yonatan Feldman (yon@arsdigita.com) @creation-date August 13, 2000 @cvs-id $Id: index.tcl,v 1.6 2011/04/18 17:24:30 emmar Exp $ } {} set doc(title) "Object Type Hierarchical Index" set context [list "Object Type Hierarchical Index"] set object_type_hierarchy [acs_object_type_hierarchy] openacs-5.7.0/packages/acs-subsite/www/admin/object-types/one.adp0000644000175000017500000000042110440426471024565 0ustar frankiefrankie @page_title@ @context@

    @page;noquote@ openacs-5.7.0/packages/acs-subsite/www/admin/object-types/one.tcl0000644000175000017500000000775310440426471024622 0ustar frankiefrankie# /packages/mbryzek-subsite/www/admin/index.tcl ad_page_contract { View an OpenACS Object Type @author Yonantan Feldman (yon@arsdigita.com) @creation-date August 13, 2000 @cvs-id $Id: one.tcl,v 1.7 2006/06/04 00:45:45 donb Exp $ } { object_type:notnull } if { ![db_0or1row object_type {}] } { ad_return_complaint 1 "The specified object type, $object_type, does not exist" ad_script_abort } set page_title "Details for type $pretty_name" set context [list [list index "Object Type Index"] "Details for type $pretty_name"] set page "[acs_object_type_hierarchy -object_type $object_type]" append page "

    Information:

    • Pretty Name: [lang::util::localize $pretty_name]
    • Pretty Plural: [lang::util::localize $pretty_plural]
    • Abstract: [ad_decode $abstract_p "f" "False" "True"]
    • Dynamic: [ad_decode $dynamic_p "f" "False" "True"]
    • [ad_decode $table_name "" "" "
    • Table Name: $table_name
    • "] [ad_decode $id_column "" "" "
    • Primary Key: $id_column
    • "] [ad_decode $name_method "" "" "
    • Name Method: $name_method
    • "] [ad_decode $type_extension_table "" "" "
    • Helper Table: $type_extension_table
    • "] [ad_decode $package_name "" "" "
    • Package Name: $package_name
    • "]
    " set i 0 set body " " db_foreach attribute { select attribute_name, pretty_name, pretty_plural, datatype, default_value, min_n_values, max_n_values, storage, table_name as attr_table_name, column_name from acs_attributes where object_type = :object_type } { incr i append body " " } append body "
    Attribute Name Pretty Name Pretty Plural Datatype Default Value Minimum Number of Values Maximum Number of Values Storage Table Name Column Name
    $attribute_name $pretty_name $pretty_plural $datatype $default_value $min_n_values $max_n_values $storage [string tolower $attr_table_name] [string tolower $column_name]
    " if { $i > 0 } { append page "

    Attributes:

      $body
    " } if { [exists_and_not_null table_name] } { set body [db_string table_comment "select comments from user_tab_comments where table_name = '[string toupper $table_name]'" -default ""] append body " " set i 0 db_foreach attribute_comment " select utc.column_name, utc.data_type, ucc.comments from user_tab_columns utc, user_col_comments ucc where utc.table_name = '[string toupper $table_name]' and utc.table_name = ucc.table_name(+) and utc.column_name = ucc.column_name(+) " { incr i append body " " } append body "
    Type Name Comment
    [string tolower $column_name] [string tolower $data_type] $comments
    " if { $i > 0 } { append page "

    Table Attributes:

      $body
    " } } set i 0 set body "" db_foreach package_index { select replace (replace (text, ' ', ' '), chr(9), '    ') as text from user_source where lower(name) = :package_name and type = 'PACKAGE BODY' order by line } { incr i append body "$text" } if { $i > 0 } { append page "

    Methods:

         
      $body
         
        
    " } append page " " openacs-5.7.0/packages/acs-subsite/www/admin/object-types/one.xql0000644000175000017500000000333007344207710024631 0ustar frankiefrankie select supertype, abstract_p, pretty_name, pretty_plural, table_name, id_column, name_method, type_extension_table, package_name, dynamic_p from acs_object_types where object_type = :object_type select attribute_name, pretty_name, pretty_plural, datatype, default_value, min_n_values, max_n_values, storage, table_name as attr_table_name, column_name from acs_attributes where object_type = :object_type select comments from user_tab_comments where table_name = '[string toupper $table_name]' select utc.column_name, utc.data_type, ucc.comments from user_tab_columns utc left join user_col_comments ucc on (utc.table_name= ucc.table_name and utc.column_name = ucc.column_name) where utc.table_name = '[string toupper $table_name]' select replace (replace (text, ' ', ' '), chr(9), '    ') as text from user_source where lower(name) = :package_name and type = 'PACKAGE BODY' order by line openacs-5.7.0/packages/acs-subsite/www/admin/object-types/one-oracle.xql0000644000175000017500000000100607344207710026072 0ustar frankiefrankie oracle8.1.6 select utc.column_name, utc.data_type, ucc.comments from user_tab_columns utc, user_col_comments ucc where utc.table_name = '[string toupper $table_name]' and utc.table_name = ucc.table_name(+) and utc.column_name = ucc.column_name(+) openacs-5.7.0/packages/acs-subsite/www/o.vuh0000644000175000017500000000503311460320062020574 0ustar frankiefrankiead_page_contract { This page accepts an object_id and uses the FtsContentProvider url method for the content type of that item to redirect to the page to display the object. @author Jeff Davis davis@xarg.net @creation-date 2003-12-29 @cvs-id $Id: o.vuh,v 1.6 2010/10/22 14:31:14 raulm Exp $ } {} if {![regexp {^/([0-9]+)(-(.+))?$} [ad_conn path_info] match object_id dummy anchor]} { ad_return_warning "Invalid object id" [subst { The identifier given for this object is invalid. Please check your url or contact the webmaster if you think it should work. }] return } if {![empty_string_p $anchor]} { set anchor "#$anchor" } if {![ db_0or1row object_data { select o.object_type, o.title, o.package_id from acs_objects o where o.object_id = :object_id }]} { ns_returnnotfound return } # Users are handled as a special case since we want to preserve the subsite # we are loading from... if {[string eq $object_type user]} { ad_returnredirect [acs_community_member_url -user_id $object_id] ad_script_abort } if {[string eq $object_type content_item]} { db_0or1row object_data { select o.object_type, o.object_id, o.package_id from acs_objects o, cr_items i where i.item_id = :object_id and o.object_id = coalesce(i.live_revision, i.latest_revision, i.item_id) } if {[string eq $object_type content_item]} { # punt, assume file storage extlink for now # JCDXXX TODO: figure out what to do... ad_returnredirect [apm_package_url_from_id $package_id]simple?object_id=$object_id&todo=fixthis } } if {![info exists object_type]} { ad_return_warning "Invalid object ID" [subst { The object ID $object_id doesn't exist.

    We are sorry for this inconvenience. }] return } # Try to retrieve the page url using a callback that makes use of upvar set page_url [lindex [callback -catch -impl $object_type subsite::url -object_id $object_id -package_id $package_id -type "display"] 0] # If this did not work, try again with the Service contract if {[empty_string_p $page_url]} { set page_url [acs_sc::invoke -contract FtsContentProvider -operation url -impl $object_type -call_args [list $object_id]] } if {![empty_string_p $page_url]} { ad_returnredirect $page_url$anchor } else { ad_return_warning "Invalid object ID" [subst {

    The object ID $object_id is a $object_type but getting it's real url failed.

    We are sorry for this inconvenience.

    }] } openacs-5.7.0/packages/acs-subsite/www/group-join.tcl0000644000175000017500000000202210210730323022377 0ustar frankiefrankiead_page_contract { Join/request membership for this group @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-08-07 @cvs-id $Id: group-join.tcl,v 1.2 2005/03/01 00:01:23 jeffd Exp $ } { {return_url "."} } auth::require_login set user_id [ad_conn user_id] set group_id [application_group::group_id_from_package_id] set join_policy [group::join_policy -group_id $group_id] set member_p [group::member_p -group_id $group_id -user_id $user_id] # Check that they're not already a member if { !$member_p } { # Create the relation set rel_type "membership_rel" set member_state [group::default_member_state -join_policy $join_policy -create_p 0] db_transaction { set rel_id [relation_add -member_state $member_state $rel_type $group_id $user_id] } on_error { ad_return_error "Error creating the relation" "We got the following error message while trying to create this relation:
    $errmsg
    " ad_script_abort } } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/group-leave.tcl0000644000175000017500000000172510006472613022555 0ustar frankiefrankiead_page_contract { Leave the group @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-08-07 @cvs-id $Id: group-leave.tcl,v 1.2 2004/01/30 15:17:31 lars Exp $ } { {group_id:integer {[application_group::group_id_from_package_id]}} return_url:optional } set user_id [auth::require_login] group::get -group_id $group_id -array group_info set member_p [group::member_p -group_id $group_id -user_id $user_id] if { $member_p } { set rel_id [relation::get_id \ -object_id_one $group_id \ -object_id_two $user_id] db_transaction { relation_remove $rel_id } on_error { ad_return_error "Error creating the relation" "We got the following error while trying to remove the relation:
    $errmsg
    " ad_script_abort } } if { ![exists_and_not_null return_url] } { set return_url "../" } ad_returnredirect -message "You have left the group \"$group_info(group_name)\"." $return_url openacs-5.7.0/packages/acs-subsite/www/site-map/0000755000175000017500000000000011724401447021342 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/site-map/index-postgresql.xql0000644000175000017500000000741410171476747025420 0ustar frankiefrankie postgresql7.1 select s2.node_id, s2.name, s2.directory_p, tree_level(s2.tree_sortkey) as level, acs_object__name(s2.object_id) as obj_name, acs_permission__permission_p(s2.object_id, :user_id, 'admin') as admin_p from (select tree_ancestor_keys(site_node_get_tree_sortkey(:root_id)) as tree_sortkey) parents, site_nodes s2 where s2.tree_sortkey = parents.tree_sortkey order by level select package_id, package_key, pretty_name as package_pretty_name, apm_package_type__num_parameters(package_key) as parameter_count, node_id, url, parent_url, name, root_p, mylevel, object_id, directory_p, parent_id, n_children, p.instance_name as object_name, acs_permission__permission_p(object_id, :user_id, 'admin') as object_admin_p, (select view_p from site_nodes_selection where node_id=site_map.node_id) as view_p from apm_packages p join apm_package_types using (package_key) right outer join (select n.node_id, site_node__url(n.node_id) as url, site_node__url(n.parent_id) as parent_url, n.name, case when exists (select 1 from site_nodes where parent_id = n.node_id) then 1 else 0 end as n_children, case when n.node_id = (select site_node__node_id('/', null)) then 1 else 0 end as root_p, (tree_level(n.tree_sortkey) - (select tree_level(n2.tree_sortkey) from site_nodes n2 where n2.node_id = (select coalesce(:root_id, site_node__node_id('/', null))))) as mylevel, n.object_id, n.directory_p, n.parent_id from site_nodes n, site_nodes n2,site_nodes_selection sn where (n.object_id is null or exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = n.object_id and ppm.party_id = :user_id and ppm.privilege = 'read')) and sn.node_id = n.node_id and n2.node_id = (select coalesce(:root_id, site_node__node_id('/', null))) and n.tree_sortkey between n2.tree_sortkey and tree_right(n2.tree_sortkey) and (n.parent_id is null or n.parent_id in ([join $expand ", "]))) site_map on site_map.object_id = p.package_id order by url select package_id, ap.package_key, ap.instance_name, apm_package_type__num_parameters(ap.package_key) as parameter_count from apm_packages ap, apm_package_types where ap.package_key = apm_package_types.package_key and package_type = 'apm_service' and not exists (select 1 from site_nodes sn where sn.object_id = package_id) and exists (select 1 from acs_object_party_privilege_map ppm where ppm.object_id = package_id and ppm.party_id = :user_id and ppm.privilege = 'admin') order by instance_name openacs-5.7.0/packages/acs-subsite/www/site-map/index.adp0000644000175000017500000000072510721035754023143 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ @javascript;noquote@

    Edit Site Map

    openacs-5.7.0/packages/acs-subsite/www/site-map/index.tcl0000644000175000017500000002101011043711736023146 0ustar frankiefrankiead_page_contract { @author rhs@mit.edu @author bquinn@arsidigta.com @creation-date 2000-09-09 @cvs-id $Id: index.tcl,v 1.7 2008/07/29 22:04:14 emmar Exp $ } { {expand:integer,multiple ""} {new_parent:integer ""} {new_type ""} {root_id:integer ""} {new_application:integer ""} {rename_application:integer {}} } if {$root_id eq ""} { set root_id [ad_conn node_id] } # Check if the user has site-wide-admin privileges set site_wide_admin_p [acs_user::site_wide_admin_p] array set node [site_node::get -node_id $root_id] set parent_id $node(parent_id) set object_id $node(object_id) if {$new_parent ne ""} { set javascript "onLoad=\"javascript:document.new_parent.name.focus();document.new_parent.name.select()\"" } elseif {$new_application ne ""} { set javascript "onLoad=\"javascript:document.new_application.instance_name.focus();document.new_application.instance_name.select()\"" } elseif {$rename_application ne ""} { set javascript "onLoad=\"javascript:document.rename_application.instance_name.focus();document.rename_application.instance_name.select()\"" } else { set javascript "" } set javascript "onload=\"javascript:document.check_checkbox()\"" set parent_link ".?[export_url_vars expand:multiple root_id=$parent_id]" set page_title "[ad_system_name] Site Map" set context [list $page_title] set user_id [ad_conn user_id] db_foreach path_select {} { if {$node_id != $root_id && $admin_p eq "t"} { append head "" } if {$name eq ""} { append head "$obj_name:" } else { append head $name } if {$node_id != $root_id && $admin_p eq "t"} { append head "" } if {$directory_p eq "t"} { append head "/" } } if_no_rows { append head " " } if {[llength $expand] == 0} { lappend expand $root_id if { $parent_id ne "" } { lappend expand $parent_id } } set return_url [ad_return_url] template::list::create \ -name nodes \ -multirow nodes \ -key node_id \ -elements { name_instance { label "#acs-subsite.Name#" html "align left" display_template { @nodes.tree_indent;noquote@ @nodes.name;noquote@ @nodes.instance;noquote@    
    @nodes.tree_indent;noquote@ @nodes.action_form_part;noquote@
    } } instance_url { label "#acs-subsite.URL#" html "align left" display_template {
    (@nodes.action_form_part;noquote@)
    (@nodes.action_form_part;noquote@)
    (@nodes.instance_url;noquote@) } } } multirow create nodes node_id expand_mode expand_url tree_indent name name_url instance instance_url type action_type action_form_part add_folder_url new_app_url unmount_url mount_url rename_url delete_url parameters_url permissions_url extra_form_part view_p set open_nodes [list] db_foreach nodes_select {} { set add_folder_url "" set new_app_url "" set unmount_url "" set mount_url "" set rename_url "" set delete_url "" set parameters_url "" set permissions_url "" if { [lsearch -exact $open_nodes $parent_id] == -1 && $parent_id ne "" && $mylevel > 2 } { continue } if {$directory_p eq "t"} { set add_folder_url "?[export_url_vars expand:multiple root_id node_id new_parent=$node_id new_type=folder]" if {$object_id eq ""} { set mount_url "mount?[export_url_vars expand:multiple root_id node_id]" set new_app_url "?[export_url_vars expand:multiple root_id new_application=$node_id]" } else { # This makes sure you can't unmount the thing that is serving the page you're looking at. if {[ad_conn node_id] != $node_id} { set unmount_url "unmount?[export_url_vars expand:multiple root_id node_id]" } # Add a link to control permissioning if {$object_admin_p} { set permissions_url "../../permissions/one?[export_url_vars object_id]" set rename_url "?[export_url_vars expand:multiple root_id rename_application=$node_id]" set delete_url "instance-delete?package_id=$object_id&root_id=$root_id" } # Is the object a package? if {$package_id ne ""} { if {$object_admin_p && ($parameter_count > 0)} { set parameters_url "[export_vars -base "/shared/parameters" { package_id {return_url {[ad_return_url]} } }]" } } } } if {[ad_conn node_id] != $node_id && $n_children == 0 && $object_id eq ""} { set delete_url "delete?[export_url_vars expand:multiple root_id node_id]" } # use the indent variable to hold current indent level we'll use it later to indent stuff at the end by the amount of the last node set indent "" if { $mylevel != 1 } { if { $mylevel == 2 } { append indent "  " } else { for {set i 1} {$i <4*$mylevel} {incr i} { append indent " " } } } #for {set i 0} {$i < 3*$mylevel} {incr i} { #append indent " " #} set expand_mode 0 if {!$root_p && $n_children > 0} { set expand_mode 1 set urlvars [list] foreach n $expand { if {$n == $node_id} { set expand_mode 2 lappend open_nodes "$node_id" } else { lappend urlvars "expand=$n" } } if { $expand_mode == 1} { lappend urlvars "expand=$node_id" } lappend urlvars "root_id=$root_id" set expand_url "[join $urlvars "&"]" } else { set expand_url "" } set name_url [export_url_vars expand:multiple root_id=$node_id] set action_type 0 set action_form_part "" if {$object_id eq ""} { if {$new_application == $node_id} { set action_type "new_app" set action_form_part "[export_form_vars expand:multiple root_id node_id new_package_id] [apm_application_new_checkbox]" #Generate a package_id for double click protection set new_package_id [db_nextval acs_object_id_seq] } else { set action_form_part "(none)" } } elseif {$rename_application == $node_id} { set action_type "rename_app" set action_form_part "[export_form_vars expand:multiple root_id node_id rename_package_id]" } else {} if {$node_id == $new_parent} { set parent_id $new_parent set node_type $new_type set action_type "new_folder" set action_form_part "[export_form_vars expand:multiple parent_id node_type root_id]" } multirow append nodes $node_id $expand_mode $expand_url $indent $name $name_url $object_name $url $package_pretty_name $action_type $action_form_part $add_folder_url $new_app_url $unmount_url $mount_url $rename_url $delete_url $parameters_url $permissions_url "" $view_p } #set new_app_form_part_1 "

    [export_form_vars expand:multiple]

    " #set new_app_form_part_2 "

    [apm_application_new_checkbox]

    " #set new_app_form_part_3 "

    " # multirow append nodes "" "" "" "" $new_app_form_part_1 "" "" "" $new_app_form_part_2 "" "" "" "" "" "" "" "" "" "" $new_app_form_part_3 set services "" db_foreach services_select {} { if {$parameter_count > 0} { append services "
  • $instance_name" } } if_no_rows { append services "
  • (none)\n" } openacs-5.7.0/packages/acs-subsite/www/site-map/index-oracle.xql0000644000175000017500000000726210204416413024440 0ustar frankiefrankie oracle8.1.6 select node_id, name, directory_p, level, acs_object.name(object_id) as obj_name, acs_permission.permission_p(object_id, :user_id, 'admin') as admin_p from site_nodes start with node_id = :root_id connect by node_id = prior parent_id order by level desc select package_id, package_key, (select pretty_name from apm_package_types where package_key = p.package_key) as package_pretty_name, apm_package_type.num_parameters(package_key) parameter_count, node_id, url, parent_url, name, root_p, mylevel - 1 as mylevel, object_id, object_name, directory_p, parent_id, n_children, decode(acs_permission.permission_p(object_id, :user_id, 'admin'), 't', 1, 0) object_admin_p, (select view_p from site_nodes_selection where node_id=site_map.node_id) as view_p from apm_packages p, (select node_id, site_node.url(node_id) as url, site_node.url(parent_id) as parent_url, name, (select count(*) from site_nodes where parent_id = n.node_id) as n_children, decode(node_id, site_node.node_id('/'), 1, 0) as root_p, level as mylevel, object_id, acs_object.name(object_id) as object_name, directory_p, parent_id from site_nodes n where (object_id is null or exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = n.object_id and ppm.party_id = :user_id and ppm.privilege = 'read')) and exists ( select 1 from site_nodes_selection sn where sn.node_id = n.node_id) start with node_id = nvl(:root_id, site_node.node_id('/')) connect by prior node_id = parent_id and parent_id in ([join $expand ", "])) site_map where site_map.object_id = p.package_id (+) order by url select package_id, ap.package_key, ap.instance_name, apm_package_type.num_parameters(ap.package_key) as parameter_count from apm_packages ap, apm_package_types where ap.package_key = apm_package_types.package_key and package_type = 'apm_service' and not exists (select 1 from site_nodes sn where sn.object_id = package_id) and exists (select 1 from acs_object_party_privilege_map ppm where ppm.object_id = package_id and ppm.party_id = :user_id and ppm.privilege = 'admin') order by instance_name openacs-5.7.0/packages/acs-subsite/www/permissions/0000755000175000017500000000000011724401447022176 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add-2-postgresql.xql0000644000175000017500000000043707723347125027743 0ustar frankiefrankie postgresql7.1 select acs_permission__grant_permission(:object_id, :one_user_id, 'read') openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add-include.adp0000644000175000017500000000021707743732043026757 0ustar frankiefrankie

    » #acs-subsite.lGo_back_without_adding#

    openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add-include.tcl0000644000175000017500000000303711403531375026771 0ustar frankiefrankiead_page_contract { } { object_id:integer,notnull return_url page:integer,optional } # check they have read permission on this file ad_require_permission $object_id admin # TODO: # parties, select privilges, css, clean up #set templating datasources set user_id [ad_conn user_id] set perm_url "[site_node_closest_ancestor_package_url]permissions/" list::create \ -name users \ -multirow users \ -key user_id \ -page_size 20 \ -page_query_name users_who_dont_have_any_permissions_paginator \ -no_data "[_ acs-subsite.lt_There_are_no_users_wh]" \ -bulk_action_export_vars { return_url object_id } \ -bulk_actions [list \ "[_ acs-subsite.Add_users]" "${perm_url}perm-user-add-2" "[_ acs-subsite.lt_Add_checked_users_to_]" \ ] \ -elements { name { label "[_ acs-subsite.Name]" } email { label "[_ acs-subsite.Email]" link_url_eval {mailto:$email} } add { label "[_ acs-subsite.Add]" link_url_col add_url link_html { title "[_ acs-subsite.Add_this_user]" } display_template "[_ acs-subsite.Add]" } } -filters { object_id {} return_url {} } db_multirow -extend { add_url } users users_who_dont_have_any_permissions {} { set add_url [export_vars -base "${perm_url}perm-user-add-2" { return_url object_id user_id }] } set img_path "[ad_conn package_url]images" set form_export_vars [export_vars -form {object_id return_url }] openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add-include.xql0000644000175000017500000000135211403531375027011 0ustar frankiefrankie select u.user_id, u.first_names || ' ' || u.last_name as name, u.email from cc_users u where [template::list::page_where_clause -name users] order by upper(first_names), upper(last_name) select u.user_id, u.first_names || ' ' || u.last_name from cc_users u where u.user_id not in (select grantee_id from acs_permissions_all where object_id = :object_id) order by upper(first_names), upper(last_name) openacs-5.7.0/packages/acs-subsite/www/permissions/revoke-2.tcl0000644000175000017500000000126610551254401024332 0ustar frankiefrankie# packages/acs-core-ui/www/acs_object/permissions/revoke-2.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-08-20 @cvs-id $Id: revoke-2.tcl,v 1.5 2007/01/10 21:22:09 gustafn Exp $ } { object_id:integer,notnull revoke_list:multiple { operation "" } {application_url ""} } permission::require_permission -object_id $object_id -privilege admin if {$operation eq "Yes"} { db_transaction { foreach item $revoke_list { set party_id [lindex $item 0] set privilege [lindex $item 1] permission::revoke -party_id $party_id -object_id $object_id -privilege $privilege } } } ad_returnredirect "one?[export_vars {object_id application_url}]" openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add-2-oracle.xql0000644000175000017500000000064607723347125027007 0ustar frankiefrankie oracle8.1.6 begin acs_permission.grant_permission( object_id => :object_id, grantee_id => :one_user_id, privilege => 'read' ); end; openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add-2.tcl0000644000175000017500000000053007723347125025512 0ustar frankiefrankiead_page_contract {} { object_id user_id:multiple,integer return_url } ad_require_permission $object_id admin db_transaction { foreach one_user_id $user_id { db_exec_plsql add_user {} } } on_error { ad_return_complaint 1 "We had a problem adding the users you selected. Sorry." } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/permissions/perm-include.adp0000644000175000017500000000032310737230763025252 0ustar frankiefrankie
    @perm_form_export_vars;noquote@

    openacs-5.7.0/packages/acs-subsite/www/permissions/perm-include.tcl0000644000175000017500000001002011526443520025255 0ustar frankiefrankie# expects: # object_id # return_url # privs:optional, defaults to 'read', 'write', 'admin' # user_add_url: URL to the page for adding users set user_id [ad_conn user_id] set admin_p [ad_permission_p $object_id admin] if { ![exists_and_not_null return_url] } { set return_url [ad_return_url] } if { ![exists_and_not_null privs] } { set privs { read create write delete admin } } db_1row object_info {} set elements [list] lappend elements grantee_name { label "[_ acs-subsite.Name]" link_url_col name_url display_template { @permissions.grantee_name@ @permissions.grantee_name@ } } foreach priv $privs { lappend select_clauses "sum(ptab.${priv}_p) as ${priv}_p" lappend select_clauses "(case when sum(ptab.${priv}_p) > 0 then 'checked' else '' end) as ${priv}_checked" lappend from_all_clauses "(case when privilege='${priv}' then 2 else 0 end) as ${priv}_p" lappend from_direct_clauses "(case when privilege='${priv}' then -1 else 0 end) as ${priv}_p" lappend from_dummy_clauses "0 as ${priv}_p" lappend elements ${priv}_p \ [list \ html { align center } \ label [string totitle [string map {_ { }} [_ acs-subsite.$priv]]] \ display_template " \"X\" " \ ] } # Remove all lappend elements remove_all { html { align center } label "[_ acs-subsite.Remove_All]" display_template {} } set perm_url "[ad_conn subsite_url]permissions/" if { ![exists_and_not_null user_add_url] } { set user_add_url "${perm_url}perm-user-add" } set user_add_url [export_vars -base $user_add_url { object_id expanded {return_url "[ad_return_url]"}}] set actions [list \ [_ acs-subsite.Grant_Permission] "${perm_url}grant?[export_vars {return_url application_url object_id}]" [_ acs-subsite.Grant_Permission] \ [_ acs-subsite.Search_For_Exist_User] $user_add_url [_ acs-subsite.Search_For_Exist_User]] if { $context_id ne "" } { set inherit_p [permission::inherit_p -object_id $object_id] if { $inherit_p } { lappend actions "[_ acs-subsite.lt_Do_not_inherit_from_p]" [export_vars -base "${perm_url}toggle-inherit" {object_id {return_url [ad_return_url]}}] "[_ acs-subsite.lt_Stop_inheriting_permi]" } else { lappend actions "[_ acs-subsite.lt_Inherit_from_parent_o]" [export_vars -base "${perm_url}toggle-inherit" {object_id {return_url [ad_return_url]}}] "[_ acs-subsite.lt_Inherit_permissions_f]" } } # TODO: Inherit/don't inherit template::list::create \ -name permissions \ -multirow permissions \ -actions $actions \ -elements $elements set perm_form_export_vars [export_vars -form {object_id privs return_url}] set perm_modify_url "${perm_url}perm-modify" set application_group_id [application_group::group_id_from_package_id -package_id [ad_conn subsite_id]] # PERMISSION: yes = 2, no = 0 # DIRECT: yes = 1, no = -1 # 3 = permission + direct # 2 = permission, no direct # 1 = no permission, but direct (can't happen) # 0 = no permission # 2 = has permission, not direct => inherited # 1 = has permission, it's direct => direct # -1 = no permission # NOTE: # We do not include site-wide admins in the list db_multirow -extend { name_url } permissions permissions {} { if { $object_type eq "user" && $grantee_id != 0 } { set name_url [acs_community_member_url -user_id $grantee_id] } } openacs-5.7.0/packages/acs-subsite/www/permissions/perm-include-oracle.xql0000644000175000017500000000477510207353615026566 0ustar frankiefrankie oracle8.1.6 select acs_object.name(object_id) as object_name, acs_object.name(context_id) as parent_object_name, context_id from acs_objects where object_id = :object_id select ptab.grantee_id, acs_object.name(ptab.grantee_id) as grantee_name, o.object_type, [join $select_clauses ", "], sum([join $privs "_p + "]_p) as any_perm_p_ from (select grantee_id, [join $from_all_clauses ", "] from acs_permissions_all where object_id = :object_id union all select grantee_id, [join $from_direct_clauses ", "] from acs_permissions where object_id = :object_id union all select -1 as grantee_id, [join $from_dummy_clauses ", "] from dual union all select -2 as grantee_id, [join $from_dummy_clauses ", "] from dual union all select component_id as grantee_id, [join $from_dummy_clauses ", "] from group_component_map where group_id = :application_group_id union all select segment_id as grantee_id, [join $from_dummy_clauses ", "] from rel_segments rel_seg where rel_seg.group_id = :application_group_id union all select segment_id as grantee_id, [join $from_dummy_clauses ", "] from rel_segments rel_seg, group_component_map gcm where gcm.group_id = :application_group_id and rel_seg.group_id = gcm.group_id ) ptab, acs_objects o where o.object_id = ptab.grantee_id and not exists (select 1 from acs_object_party_privilege_map p where p.object_id = (select object_id from acs_magic_objects where name = 'security_context_root') and p.party_id = ptab.grantee_id and p.privilege = 'admin') group by ptab.grantee_id, acs_object.name(ptab.grantee_id), o.object_type order by object_type desc, grantee_name openacs-5.7.0/packages/acs-subsite/www/permissions/toggle-inherit.tcl0000644000175000017500000000202110440426471025614 0ustar frankiefrankie# packages/acs-subsite/www/permissions/toggle-inherit.tcl ad_page_contract { Toggles the security_inherit_p flag. @author rhs@mit.edu @creation-date 2000-09-30 @cvs-id $Id: toggle-inherit.tcl,v 1.5 2006/06/04 00:45:45 donb Exp $ } { object_id:integer,notnull {application_url ""} {return_url {[export_vars -base "one" {application_url object_id}]}} } ad_require_permission $object_id admin permission::toggle_inherit -object_id $object_id # this prevents administrators from deselecting inheritance and then # discovering that they no longer have admin rights set group_id [application_group::group_id_from_package_id -package_id [ad_conn subsite_id]] set rel_id [group::get_rel_segment -group_id $group_id -type admin_rel] permission::grant -object_id $object_id -party_id $rel_id -privilege admin if { ![permission::permission_p -object_id $object_id -privilege admin] } { permission::grant \ -object_id $object_id -party_id [ad_conn user_id] -privilege admin } ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/permissions/one-postgresql.xql0000644000175000017500000000400510207333047025700 0ustar frankiefrankie postgresql7.1 select acs_object__name(:object_id) select grantee_id, grantee_name, privilege from (select grantee_id, acs_object__name(grantee_id) as grantee_name, privilege, 1 as counter from acs_permissions_all where object_id = :object_id union all select grantee_id, acs_object__name(grantee_id) as grantee_name, privilege, -1 as counter from acs_permissions where object_id = :object_id ) dummy group by grantee_id, grantee_name, privilege having sum(counter) > 0 select grantee_id, acs_object__name(grantee_id) as grantee_name, privilege from acs_permissions where object_id = :object_id SELECT acs_object__name(context_id) as context_name, context_id, security_inherit_p FROM acs_objects WHERE object_id = :object_id select object_id as c_object_id,acs_object__name(object_id) as c_name, object_type as c_type from acs_objects o where context_id = :object_id and exists (select 1 from acs_permissions_all where object_id = o.object_id and grantee_id = :user_id and privilege = 'admin') select count(*) as num_children from acs_objects o where context_id = :object_id and acs_permission__permission_p(o.object_id, :user_id, 'admin') = 't' openacs-5.7.0/packages/acs-subsite/www/permissions/index-postgresql.xql0000644000175000017500000000126707611533124026240 0ustar frankiefrankie postgresql7.1 select o.object_id, acs_object__name(o.object_id) as name, context_id, object_type, (case when o.object_id = :root then 0 else 1 end) as child from acs_objects o where exists ( SELECT 1 FROM acs_permissions_all map WHERE map.object_id = o.object_id and map.grantee_id = :user_id and map.privilege = 'admin') and (o.object_id = :root or o.context_id = :root) order by child, object_type, name openacs-5.7.0/packages/acs-subsite/www/permissions/index.adp0000644000175000017500000000233507743732043024003 0ustar frankiefrankie #acs-subsite.Permissions# @context;noquote@ #acs-subsite.You_have_admin_rights_on# #acs-subsite.You_do_not_have_admin_on#
    #acs-subsite.Select_an_Object_by_Id#

    #acs-subsite.You_can_also_browse_from# #acs-subsite.default_context# #acs-subsite.or_the# #acs-subsite.Security_context_root##acs-subsite._or# #acs-subsite.this_subsite#.

    openacs-5.7.0/packages/acs-subsite/www/permissions/index.tcl0000644000175000017500000000152210210730324023775 0ustar frankiefrankie# packages/acs-core-ui/www/permissions/index.tcl ad_page_contract { Display all objects that the user has admin on. Templated and changed to browse heirarchy by davis@xarg.net since all objects can be a *lot* of objects. @author rhs@mit.edu @creation-date 2000-08-29 @cvs-id $Id: index.tcl,v 1.3 2005/03/01 00:01:24 jeffd Exp $ } { root:trim,integer,optional } set user_id [auth::require_login] set context "Permissions" if {![exists_and_not_null root]} { set root [ad_conn package_id] } db_multirow objects adminable_objects { *SQL* } set security_context_root [acs_magic_object security_context_root] set default_context [acs_magic_object default_context] set admin_p [permission::permission_p -object_id $security_context_root -party_id $user_id -privilege admin] set subsite [ad_conn package_id] openacs-5.7.0/packages/acs-subsite/www/permissions/grant.adp0000644000175000017500000000150507744026013023777 0ustar frankiefrankie @title@ @context@
    #acs-subsite.Grant#:     #acs-subsite.on_name_to#  
     

    #acs-subsite.Notes#
    #acs-subsite.lt_Privileges_higher_implied#
    #acs-subsite.When_leaving_checkbox_empty# openacs-5.7.0/packages/acs-subsite/www/permissions/grant.tcl0000644000175000017500000001171010551254401024006 0ustar frankiefrankie# packages/acs-core-ui/www/acs_object/permissions/grant.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-08-20 @cvs-id $Id: grant.tcl,v 1.14 2007/01/10 21:22:09 gustafn Exp $ } { object_id:integer,notnull privileges:multiple,optional {application_url ""} {return_url ""} } ad_require_permission $object_id admin # The object name is used in various localized messages below set name [acs_object_name $object_id] set title [_ acs-subsite.lt_Grant_Permission_on_n] set context [list [list one?[export_url_vars object_id] "[_ acs-subsite.Permissions_for_name]"] [_ acs-subsite.Grant]] # Compute a hierarchical tree representation of the contents of # acs_privileges. Note that nodes can appear more than one time in the # tree. set existing_privs [db_list select_privileges_list { }] # The maximum level that has been reached within the hierarchy. set maxlevel 1 # Initialize the $hierarchy datastructure which is a list of # lists. The inner lists consist of two elements: 1. level, # 2. privilege set hierarchy [list] foreach privilege $existing_privs { lappend hierarchy [list 0 $privilege] } # Loop through each row in acs_privilege_hierarchy and shuffle the # $hierarchy list accordingly. db_foreach select_privileges_hierarchy { } { if { [set start_pos [lsearch -regexp $hierarchy "\\m$child_privilege\\M"]] == -1 } { # child_privilege of this relation not in privileges - skip. continue } if { [lsearch -regexp $hierarchy "\\m$privilege\\M"] == -1 } { # privilege of this relation not in privileges - skip. continue } # the level of the first privilege element that we move set start_pos_level [lindex [lindex $hierarchy $start_pos] 0] # find the end position up to where the block extends that we have # to move set end_pos $start_pos for { set i [expr {$start_pos + 1}] } { $i <= [llength $hierarchy] } { incr i } { set level [lindex [lindex $hierarchy $i] 0] if { $level <= $start_pos_level } { break } incr end_pos } # define the block set block_to_move [lrange $hierarchy $start_pos $end_pos] # Only cut out the block if it is on the toplevel, which means it # hasn't been moved yet. Otherwise the block will appear in two # places intentionally. if { [lindex [lindex $hierarchy $start_pos] 0] == 0 } { set hierarchy [lreplace $hierarchy $start_pos $end_pos] } if { [set target_pos [lsearch -regexp $hierarchy "\\m$privilege\\M"]] == -1 } { # target not found, something is broken with the # hierarchy. continue } set target_level [lindex [lindex $hierarchy $target_pos] 0] # remember the starting level in the block set offset [lindex [lindex $block_to_move 0] 0] # insert the block to the new position, looping through the block foreach element $block_to_move { incr target_pos set level_to_move [expr {[lindex $element 0] + $target_level + 1 - $offset}] set privilege_to_move [lindex $element 1] set hierarchy [linsert $hierarchy $target_pos [list $level_to_move $privilege_to_move]] if { $maxlevel < $level_to_move } { set maxlevel $level_to_move } } } incr maxlevel # The $hierarchy datastructure is ready, fill a select widget options list with it. foreach element $hierarchy { set privilege [lindex $element 1] set level [lindex $element 0] lappend select_list [list "[string repeat "   " $level] $privilege" $privilege] } ad_form -name grant -export {return_url} -form { {object_id:text(hidden) {value $object_id} } } element create grant application_url \ -widget hidden \ -value $application_url \ -optional element create grant party_id \ -widget party_search \ -datatype party_search \ -optional if { ![info exists privileges] } { set privileges [list] } # limit the size of the select widget to a number that should fit on a # 1024x768 screen if { [llength $select_list] > 23 } { set size 23 } else { set size [llength $select_list] } element create grant privilege \ -widget multiselect \ -datatype text \ -optional \ -html [list size $size] \ -options $select_list \ -value $privileges if { [form is_valid grant] } { # A valid submission - grant accordingly. form get_values grant set privileges [element get_values grant privilege] # grant all selected privs foreach privilege $privileges { # Lars: For some reason, selecting no privileges returns in a list # containing one element, which is the empty string if { $privilege ne "" } { permission::grant -party_id $party_id -object_id $object_id -privilege $privilege } } if {[exists_and_not_null return_url]} { ad_returnredirect "$return_url" } else { ad_returnredirect "one?[export_vars [list object_id application_url]]" } ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/permissions/grant.xql0000644000175000017500000000071407740570011024036 0ustar frankiefrankie select privilege, child_privilege from acs_privilege_hierarchy order by privilege desc, child_privilege desc select privilege from acs_privileges order by privilege openacs-5.7.0/packages/acs-subsite/www/permissions/perm-modify-postgresql.xql0000644000175000017500000000073107723347125027364 0ustar frankiefrankie postgresql7.1 select acs_permission__revoke_permission(:object_id, :party_id, :privilege) select acs_permission__grant_permission(:object_id, :party_id, :privilege) openacs-5.7.0/packages/acs-subsite/www/permissions/perm-modify-oracle.xql0000644000175000017500000000135107723347125026425 0ustar frankiefrankie oracle8.1.6 begin acs_permission.revoke_permission( object_id => :object_id, grantee_id => :party_id, privilege => :privilege ); end; begin acs_permission.grant_permission( object_id => :object_id, grantee_id => :party_id, privilege => :privilege ); end; openacs-5.7.0/packages/acs-subsite/www/permissions/revoke.tcl0000644000175000017500000000230707661404234024201 0ustar frankiefrankie# packages/acs-core-ui/www/acs_object/permissions/revoke.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-08-20 @cvs-id $Id: revoke.tcl,v 1.4 2003/05/17 10:02:04 jeffd Exp $ } { object_id:integer,notnull {revoke_list:multiple,optional {}} {application_url ""} } ad_require_permission $object_id admin if {[llength $revoke_list] == 0} { ad_returnredirect "./?[export_url_vars object_id]" ad_script_abort } doc_body_append "[ad_header "Revoke Confirm"]

    Revoke Confirm


    Are you sure you want to remove the following entries from the access control list of [db_string name {select acs_object.name(:object_id) from dual}]?
      " foreach item $revoke_list { set party_id [lindex $item 0] set privilege [lindex $item 1] doc_body_append "
    • [db_string party_name {select acs_object.name(:party_id) from dual}]
    • \n" } doc_body_append "
    [export_vars -form {object_id application_url}] " foreach item $revoke_list { doc_body_append "\n" } doc_body_append "
    [ad_footer] " openacs-5.7.0/packages/acs-subsite/www/permissions/one.adp0000644000175000017500000000423711043666757023466 0ustar frankiefrankie #acs-subsite.Permissions_for_name# @context;noquote@

    #acs-subsite.lt_Inherited_Permissions#

    • @inherited.grantee_name@, @inherited.privilege@

    #acs-subsite.none#

    #acs-subsite.Direct_Permissions#

    @export_form_vars;noquote@ @acl.grantee_name@, @acl.privilege@ #acs-subsite.perm_cannot_be_removed#

    #acs-subsite.none#

    @controls;noquote@

    #acs-subsite.Children#

    [#acs-subsite.Hide#]

    #acs-subsite.none#

    #acs-subsite.lt_num_children_Children# [#acs-subsite.Show#] #acs-subsite.none#

    [#acs-subsite.return_to_application#]

    [#acs-subsite.up_to_context_name#]

    openacs-5.7.0/packages/acs-subsite/www/permissions/one.tcl0000644000175000017500000000361610551254401023462 0ustar frankiefrankie# packages-core-ui/www/acs_object/permissions/index.tcl ad_page_contract { Display permissions and children for the given object_id Templated + cross site scripting holes patched by davis@xarg.net @author rhs@mit.edu @creation-date 2000-08-20 @cvs-id $Id: one.tcl,v 1.13 2007/01/10 21:22:09 gustafn Exp $ } { object_id:integer,notnull {children_p "f"} {application_url ""} } set user_id [auth::require_login] ad_require_permission $object_id admin # RBM: Check if this is the Main Site and prevent the user from being # able to remove Read permission on "The Public" and locking # him/herself out. if {$object_id eq [subsite::main_site_id]} { set mainsite_p 1 } else { set mainsite_p 0 } set name [db_string name {}] set context [list [list "./" [_ acs-subsite.Permissions]] [ad_quotehtml [_ acs-subsite.Permissions_for_name]]] db_multirow inherited inherited_permissions { *SQL* } { } db_multirow acl acl { *SQL* } { } set controls [list] lappend controls "[_ acs-subsite.Grant_Permission]" db_1row context { *SQL* } if { $security_inherit_p eq "t" && $context_id ne "" } { lappend controls "Don't Inherit Permissions from [ad_quotehtml $context_name]" } else { lappend controls "Inherit Permissions from [ad_quotehtml $context_name]" } set controls "\[ [join $controls " | "] \]" set export_form_vars [export_vars -form {object_id application_url}] set show_children_url "one?[export_vars {object_id application_url {children_p t}}]" set hide_children_url "one?[export_vars {object_id application_url {children_p f}}]" if {$children_p eq "t"} { db_multirow children children { *SQL* } { } } else { db_1row children_count { *SQL* } } openacs-5.7.0/packages/acs-subsite/www/permissions/one.xql0000644000175000017500000000035407404243111023477 0ustar frankiefrankie select security_inherit_p from acs_objects where object_id = :object_id openacs-5.7.0/packages/acs-subsite/www/permissions/index-oracle.xql0000644000175000017500000000122307611533124025272 0ustar frankiefrankie oracle8.1.6 select o.object_id, acs_object.name(o.object_id) as name, context_id, object_type, (case when o.object_id = :root then 0 else 1 end) as child from acs_objects o where exists ( SELECT 1 FROM all_object_party_privilege_map map WHERE map.object_id = o.object_id and map.party_id = :user_id and map.privilege = 'admin') and (o.object_id = :root or o.context_id = :root) order by child, object_type, name openacs-5.7.0/packages/acs-subsite/www/permissions/revoke-postgresql.xql0000644000175000017500000000056007273360410026417 0ustar frankiefrankie postgresql7.1 select acs_object__name(:object_id) select acs_object__name(:party_id) openacs-5.7.0/packages/acs-subsite/www/permissions/revoke-oracle.xql0000644000175000017500000000057607273360410025470 0ustar frankiefrankie oracle8.1.6 select acs_object.name(:object_id) from dual select acs_object.name(:party_id) from dual openacs-5.7.0/packages/acs-subsite/www/permissions/perm-modify.tcl0000644000175000017500000000433510551254401025130 0ustar frankiefrankiead_page_contract {} { object_id:integer {perm:multiple {[list]}} {privs:optional} return_url } ad_require_permission $object_id admin # entried in 'perm' have the form "${party_id}_${privilege}" foreach elm $perm { set elmv [split $elm ","] set party_id [lindex $elmv 0] set priv [lindex $elmv 1] if { $priv ne "remove" } { set perm_array($elm) add } } foreach elm $perm { set elmv [split $elm ","] set party_id [lindex $elmv 0] set priv [lindex $elmv 1] if {$priv eq "remove"} { foreach priv $privs { if { [info exists perm_array(${party_id},${priv})] } { unset perm_array(${party_id},${priv}) } } } } # Don't want them to remove themselves as admins if { ![info exists perm_array([ad_conn user_id],admin)] } { set perm_array([ad_conn user_id],admin) add } set page "
      " db_transaction { db_foreach permissions_in_db {} { if { ![info exists perm_array(${grantee_id},${privilege})] } { # If they're not in the modified list, remove them set perm_array(${grantee_id},${privilege}) remove } else { # If they are in the modified list, make a note that they're also in the databse set perm_array(${grantee_id},${privilege}) nothing } } # run through the perm_array, and depending on the value # remove: Remove the privilege # nothing: Do nothing # add: Add the privilege foreach elm [array names perm_array] { set elmv [split $elm ","] set party_id [lindex $elmv 0] set privilege [lindex $elmv 1] switch -- $perm_array($elm) { remove { db_exec_plsql remove {} append page "
    • select acs_permission__revoke_permission($object_id, $party_id, $privilege)" } add { db_exec_plsql add {} append page "
    • select acs_permission__grant_permission($object_id, $party_id, $privilege)" } } } } on_error { global errorInfo ad_return_complaint 1 "Ooops, looks like we screwed up. Sorry. $errmsg

      $errorInfo" } append page "

    " ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/permissions/perm-modify.xql0000644000175000017500000000045607723347125025167 0ustar frankiefrankie select grantee_id, privilege from acs_permissions where object_id = :object_id and privilege in ('[join $privs "', '"]') openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add.adp0000644000175000017500000000022011403531375025321 0ustar frankiefrankie @title@ @context;noquote@ openacs-5.7.0/packages/acs-subsite/www/permissions/perm-user-add.tcl0000644000175000017500000000032410440426471025344 0ustar frankiefrankiead_page_contract { Simple page for adding users to permissions list. } { return_url } set context [list [list $return_url "Permissions"] "[_ acs-subsite.Add_User]"] set title "[_ acs-subsite.Add_User]" openacs-5.7.0/packages/acs-subsite/www/permissions/perm-include-postgresql.xql0000644000175000017500000000452610207353615027516 0ustar frankiefrankie postgresql7.1 select acs_object__name(object_id) as object_name, acs_object__name(context_id) as parent_object_name, context_id from acs_objects where object_id = :object_id select ptab.grantee_id, acs_object__name(ptab.grantee_id) as grantee_name, o.object_type, [join $select_clauses ", "], sum([join $privs "_p + "]_p) as any_perm_p_ from (select grantee_id, [join $from_all_clauses ", "] from acs_permissions_all where object_id = :object_id union all select grantee_id, [join $from_direct_clauses ", "] from acs_permissions where object_id = :object_id union all select -1 as grantee_id, [join $from_dummy_clauses ", "] union all select -2 as grantee_id, [join $from_dummy_clauses ", "] union all select component_id as grantee_id, [join $from_dummy_clauses ", "] from group_component_map where group_id = :application_group_id union all select segment_id as grantee_id, [join $from_dummy_clauses ", "] from rel_segments rel_seg where rel_seg.group_id = :application_group_id union all select segment_id as grantee_id, [join $from_dummy_clauses ", "] from rel_segments rel_seg, group_component_map gcm where gcm.group_id = :application_group_id and rel_seg.group_id = gcm.group_id ) ptab, acs_objects o where o.object_id = ptab.grantee_id and not exists (select 1 from acs_object_party_privilege_map p where p.object_id = acs__magic_object_id('security_context_root') and p.party_id = ptab.grantee_id and p.privilege = 'admin') group by ptab.grantee_id, grantee_name, object_type order by object_type desc, grantee_name openacs-5.7.0/packages/acs-subsite/www/permissions/one-oracle.xql0000644000175000017500000000401710207333047024745 0ustar frankiefrankie oracle8.1.6 select acs_object.name(:object_id) from dual select grantee_id, grantee_name, privilege from (select grantee_id, acs_object.name(grantee_id) as grantee_name, privilege, 1 as counter from acs_permissions_all where object_id = :object_id union all select grantee_id, acs_object.name(grantee_id) as grantee_name, privilege, -1 as counter from acs_permissions where object_id = :object_id ) group by grantee_id, grantee_name, privilege having sum(counter) > 0 select grantee_id, acs_object.name(grantee_id) as grantee_name, privilege from acs_permissions where object_id = :object_id SELECT acs_object.name(context_id) as context_name, context_id, security_inherit_p FROM acs_objects WHERE object_id = :object_id select object_id as c_object_id,acs_object.name(object_id) as c_name, object_type as c_type from acs_objects o where context_id = :object_id and exists (select 1 from all_object_party_privilege_map where object_id = o.object_id and party_id = :user_id and privilege = 'admin') select count(*) as num_children from acs_objects o where context_id = :object_id and acs_permission.permission_p(o.object_id, :user_id, 'admin') = 't' openacs-5.7.0/packages/acs-subsite/www/file.vuh0000644000175000017500000000333511460320062021260 0ustar frankiefrankie# packages/acs-subsite/www/image.vuh # # Subsite handler for images # # @author Dave Bauer (dave@thedesignexperience.org) # @creation-date 2006-08-01 # @cvs-id $Id: file.vuh,v 1.9 2010/10/22 14:31:14 raulm Exp $ if {![regexp {^/([0-9]+)(/(private)/([0-9]+))?(/(.*))?$} [ad_conn path_info] match object_id private_slash private private_parent_id anchor]} { ad_return_warning "Invalid object id" [subst { The identifier given for this object is invalid. Please check your url or contact the webmaster if you think it should work. }] return } # check permissions! if { $private eq "private" } { # find if the item has a parent link to the object # that is, if the image is used in a content item and you can read the # content item, you can read the image regardless of the permissions set object_to_check $object_id if { [application_data_link::link_exists \ -from_object_id $private_parent_id \ -to_object_id $object_id] } { # if the link does not exist it might be # because its a new object # that means you uploaded the image so you can see it in the editor while you are working on it set object_to_check $private_parent_id } if { ![permission::permission_p \ -object_id $object_to_check \ -privilege "read" \ -party_id [ad_conn user_id]] } { # if you don't have permission to see it, it doesn't exist ns_returnnotfound ad_script_abort } } else { permission::require_permission \ -privilege "read" \ -object_id $object_id \ -party_id [ad_conn user_id] } # find a cr_item and serve it cr_write_content -item_id $object_id openacs-5.7.0/packages/acs-subsite/www/members/0000755000175000017500000000000011724401447021255 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/members/user-batch-add-2.adp0000644000175000017500000000016511043666757024702 0ustar frankiefrankie Add a batch of users @success_text;noquote@
    @exception_text;noquote@ openacs-5.7.0/packages/acs-subsite/www/members/user-batch-add-2.tcl0000644000175000017500000000635111226233616024706 0ustar frankiefrankiead_page_contract { Interface for specifying a list of users to sign up as a batch @cvs-id $Id: user-batch-add-2.tcl,v 1.5 2009/07/12 01:08:30 donb Exp $ } -query { userlist from subject message:allhtml } -properties { title:onevalue success_text:onevalue exception_text:onevalue } subsite::assert_user_may_add_member # parse the notify_ids arguments # ... set exception_text "" set success_text "" set title "Adding new users in bulk" set group_id [application_group::group_id_from_package_id] # parse the userlist input a row at a time # most errors stop the processing of the line but keep going on the # bigger block while {[regexp {(.[^\n]+)} $userlist match_fodder row] } { # remove each row as it's handled set remove_count [string length $row] set userlist [string range $userlist [expr {$remove_count + 1}] end] set row [split $row ,] set email [string trim [lindex $row 0]] set first_names [string trim [lindex $row 1]] set last_name [string trim [lindex $row 2]] if {![info exists email] || ![util_email_valid_p $email]} { append exception_text "
  • Couldn't find a valid email address in ($row).
  • \n" continue } else { set user_exists_p [db_0or1row user_id "select party_id from parties where email = lower(:email)"] if {$user_exists_p > 0} { # Add user to subsite as a member group::add_member \ -group_id $group_id \ -user_id $party_id append exception_text "
  • $email was already in the database.
  • \n" continue } } if {![info exists first_names] || $first_names eq ""} { append exception_text "
  • No first name in ($row)
  • \n" continue } if {![info exists last_name] || $last_name eq ""} { append exception_text "
  • No last name in ($row)
  • \n" continue } # We've checked everything. set password [ad_generate_random_string] array set auth_status_array [auth::create_user -email $email -first_names $first_names -last_name $last_name -password $password] set user_id $auth_status_array(user_id) append success_text "Created user $user_id for ($row)" # Add user to subsite as a member group::add_member \ -group_id $group_id \ -user_id $user_id # if anything goes wrong here, stop the whole process if { !$user_id } { ad_return_error "Insert Failed" "We were unable to create a user record for ($row)." ad_script_abort } # send email set key_list [list first_names last_name email password] set value_list [list $first_names $last_name $email $password] set sub_message $message foreach key $key_list value $value_list { regsub -all "<$key>" $sub_message $value sub_message } if {[catch {acs_mail_lite::send -send_immediately -to_addr $email -from_addr $from -subject $subject -body $sub_message} errmsg]} { ad_return_error "Mail Failed" "

    The system was unable to send email. Please notify the user personally. This problem is probably caused by a misconfiguration of your email system. Here is the error:

    [ad_quotehtml $errmsg]
    " return } } ad_return_template openacs-5.7.0/packages/acs-subsite/www/members/member-remove.tcl0000644000175000017500000000075210005232302024506 0ustar frankiefrankiead_page_contract { Remove member(s). @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-02 @cvs-id $Id: member-remove.tcl,v 1.3 2004/01/26 15:39:46 jeffd Exp $ } { user_id:integer,multiple } set group_id [application_group::group_id_from_package_id] permission::require_permission -object_id $group_id -privilege "admin" foreach id $user_id { group::remove_member \ -group_id $group_id \ -user_id $user_id } ad_returnredirect . openacs-5.7.0/packages/acs-subsite/www/members/make-admin.tcl0000644000175000017500000000126707763747751024015 0ustar frankiefrankiead_page_contract { Make administrators. } { {user_id:multiple ""} } set group_id [application_group::group_id_from_package_id] permission::require_permission -object_id $group_id -privilege "admin" db_transaction { foreach one_user_id $user_id { # membership state stuff should only check the membership_rel at this # point - remember this is going to be made consistent in 5.1 relation_add -member_state "" admin_rel $group_id $one_user_id } } on_error { ad_return_error "Error creating the relation" "We got the following error message while trying to create this relation:
    $errmsg
    " ad_script_abort } ad_returnredirect . ad_script_abort openacs-5.7.0/packages/acs-subsite/www/members/index.adp0000644000175000017500000000101710723077077023057 0ustar frankiefrankie @context@ @page_title@

    @title@

    #acs-subsite.Mem_list_not_allowed#
    openacs-5.7.0/packages/acs-subsite/www/members/index.tcl0000644000175000017500000001643510551254400023071 0ustar frankiefrankiead_page_contract { List and manage subsite members. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-02 @cvs-id $Id: index.tcl,v 1.18 2007/01/10 21:22:08 gustafn Exp $ } { {member_state "approved"} {orderby "name,asc"} page:optional } -validate { member_state_valid -requires { member_state } { if { [lsearch [group::possible_member_states] $member_state] == -1 } { ad_complain "Invalid member_state" } } } set page_title [_ acs-subsite.Members] set context [list $page_title] set group_id [application_group::group_id_from_package_id] # Is this the main site? In that case, we don't offer to remove users completely, # only to ban/delete them. set main_site_p [string equal [site_node::get_url -node_id [ad_conn node_id]] "/"] set user_id [ad_conn user_id] set show_member_list_to [parameter::get -parameter "ShowMembersListTo" -default 2] # 0 = anyone # 1 = members # 2 = admins if { $show_member_list_to != 0 || [permission::permission_p -party_id [ad_conn untrusted_user_id] -object_id $group_id -privilege "admin"] } { # Refresh login auth::require_login } # We need to know both: # - does user have admin on group? # - does user have delete on group? set admin_p [permission::permission_p -party_id $user_id -object_id $group_id -privilege "admin"] set show_member_list_p [expr { $show_member_list_to == 0 || $admin_p || ($show_member_list_to == 1 && [group::member_p -group_id $group_id]) }] if { !$show_member_list_p } { set title [_ acs-subsite.Cannot_see_memb_list] } if { $admin_p } { # We can skip the permissions check for "delete" because user had admin. set delete_p 1 } else { # user doesn't have admin -- now find out if they have delete. set delete_p [ad_permission_p -user_id $user_id $group_id "delete"] } set actions {} set bulk_actions {} if { $admin_p || [parameter::get -parameter "MembersCanInviteMembersP" -default 0] } { set actions [_ acs-subsite.Invite] lappend actions { member-invite } } if { $admin_p } { } set member_state_options [list] db_foreach select_member_states {} { lappend member_state_options \ [list \ [group::get_member_state_pretty -member_state $state] \ $state \ [lc_numeric $num_members]] } db_1row pretty_roles {} template::list::create \ -name "members" \ -multirow "members" \ -row_pretty_plural "members" \ -page_size 50 \ -page_flush_p t \ -page_query_name members_pagination \ -actions $actions \ -bulk_actions $bulk_actions \ -elements { name { label "[_ acs-subsite.Name]" link_url_eval {[acs_community_member_url -user_id $user_id]} } email { label "[_ acs-subsite.Email]" display_template { @members.user_email;noquote@ } } rel_role { label "[_ acs-subsite.Role]" display_template { @members.rel_role_pretty@ } } member_state_pretty { label "[_ acs-subsite.Member_State]" } member_state_change { label {Action} display_template { #acs-subsite.Approve# #acs-subsite.Reject# #acs-subsite.Ban# #acs-subsite.Delete# #acs-subsite.Remove# #acs-subsite.Make_administrator# #acs-subsite.Make_member# } } } -filters { member_state { label "[_ acs-subsite.Member_State]" values $member_state_options where_clause { mr.member_state = :member_state } has_default_p 1 } } -orderby { name { label "[_ acs-subsite.Name]" orderby "lower(u.first_names || ' ' || u.last_name)" } email { label "[_ acs-subsite.Email]" orderby "u.email" } } # Pull out all the relations of the specified type set show_partial_email_p [expr {$user_id == 0}] db_multirow -extend { email_url member_state_pretty remove_url approve_url reject_url ban_url delete_url make_admin_url make_member_url rel_role_pretty user_email } -unclobber members members_select {} { if { $member_admin_p > 0 } { set rel_role_pretty [lang::util::localize $admin_role_pretty] } else { if { $other_role_pretty ne "" } { set rel_role_pretty [lang::util::localize $other_role_pretty] } else { set rel_role_pretty [lang::util::localize $member_role_pretty] } } set member_state_pretty [group::get_member_state_pretty -member_state $member_state] set user_email [email_image::get_user_email -user_id $user_id] if { $admin_p } { switch $member_state { approved { if { $member_admin_p == 0 } { set make_admin_url [export_vars -base make-admin { user_id }] } else { set make_member_url [export_vars -base make-member { user_id }] } if { $main_site_p } { set ban_url [export_vars -base member-state-change { rel_id {member_state banned} }] set delete_url [export_vars -base member-state-change { rel_id {member_state deleted} }] } else { set remove_url [export_vars -base member-remove { user_id }] } } "needs approval" { set approve_url [export_vars -base member-state-change { rel_id { member_state approved } }] if { $main_site_p } { set reject_url [export_vars -base member-state-change { rel_id {member_state rejected} }] } else { set remove_url [export_vars -base member-remove { user_id }] } } "rejected" - "deleted" - "banned" { set approve_url [export_vars -base member-state-change { rel_id { member_state approved } }] if { !$main_site_p } { set remove_url [export_vars -base member-remove { user_id }] } } } } if { [ad_conn user_id] == 0 } { set email [string replace $email \ [expr {[string first "@" $email]+3}] end "..."] } else { set email_url "mailto:$email" } } openacs-5.7.0/packages/acs-subsite/www/members/index.xql0000644000175000017500000000500310270037303023077 0ustar frankiefrankie select r.rel_id, u.first_names || ' ' || u.last_name as name from acs_rels r, membership_rels mr, cc_users u where r.object_id_one = :group_id and r.rel_type = 'membership_rel' and mr.rel_id = r.rel_id and u.user_id = r.object_id_two [template::list::filter_where_clauses -and -name "members"] [template::list::orderby_clause -orderby -name "members"] select admin_role.pretty_name as admin_role_pretty, member_role.pretty_name as member_role_pretty from acs_rel_roles admin_role, acs_rel_roles member_role where admin_role.role = 'admin' and member_role.role = 'member' select r.rel_id, u.user_id, u.first_names || ' ' || u.last_name as name, u.email, mr.member_state, (select count(*) from rel_segment_party_map where rel_type = 'admin_rel' and group_id = :group_id and party_id = u.user_id) as member_admin_p, (select distinct r.pretty_name from acs_rel_roles r, rel_segment_party_map m, acs_rel_types t where m.group_id = :group_id and t.rel_type = m.rel_type and m.rel_type <> 'admin_rel' and m.rel_type <> 'membership_rel' and r.role = t.role_two and m.party_id = u.user_id) as other_role_pretty from acs_rels r, membership_rels mr, cc_users u where r.object_id_one = :group_id and mr.rel_id = r.rel_id and r.rel_id = mr.rel_id and u.user_id = r.object_id_two [template::list::filter_where_clauses -and -name "members"] [template::list::page_where_clause -and -name "members" -key "r.rel_id"] [template::list::orderby_clause -orderby -name "members"] select mr.member_state as state, count(mr.rel_id) as num_members from membership_rels mr, acs_rels r where r.rel_id = mr.rel_id and r.object_id_one = :group_id and r.rel_type = 'membership_rel' group by mr.member_state openacs-5.7.0/packages/acs-subsite/www/members/member-invite.adp0000644000175000017500000000120111547324510024476 0ustar frankiefrankie @context;noquote@ @page_title;noquote@ user_search.user_id

    #acs-subsite.Invite_a_user#

    #acs-subsite.Search_For_Exist_User#

    #acs-subsite.lt_If_you_happen_to_know#

    #acs-subsite.Or_add_a_new_user#

    #acs-subsite.lt_If_you_dont_think_the#

    You may use the user bulk upload page to add many users.

    openacs-5.7.0/packages/acs-subsite/www/members/member-invite.tcl0000644000175000017500000000464711547324510024535 0ustar frankiefrankiead_page_contract { Invite new member. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-02 @cvs-id $Id: member-invite.tcl,v 1.10 2011/04/07 12:08:40 emmar Exp $ } subsite::assert_user_may_add_member set group_id [application_group::group_id_from_package_id] set admin_p [permission::permission_p -object_id $group_id -privilege "admin"] set page_title "Invite Member to [ad_conn instance_name]" set context [list [list "." "Members"] "Invite"] group::get \ -group_id $group_id \ -array group_info # if we are at main site, only show the form for creating a new user set subsite_p [expr { [subsite::main_site_id] ne [ad_conn package_id] }] ad_form -name user_search -cancel_url . -form { {user_id:search {result_datatype integer} {label {Search for user}} {help_text {Type part of the name or email of the user you would like to add}} {search_query {[db_map user_search]}} } } # Only admins can add non-membership_rel members if { $admin_p } { ad_form -extend -name user_search -form { {rel_type:text(select) {label "Role"} {options {[group::get_rel_types_options -group_id $group_id]}} } } } ad_form -extend -name user_search -on_submit { set create_p [group::permission_p -privilege create $group_id] if { $group_info(join_policy) eq "closed" && !$create_p} { ad_return_forbidden "Cannot invite members" "I'm sorry, but you're not allowed to invite members to this group" ad_script_abort } # Only admins can add non-membership_rel members if { !$admin_p } { set rel_type "membership_rel" } if { ![group::member_p -user_id $user_id -group_id $group_id] } { with_catch errmsg { group::add_member \ -group_id $group_id \ -user_id $user_id \ -rel_type $rel_type } { form set_error user_search user_id "Error adding user to community: $errmsg" global errorInfo ns_log Error "Error adding user $user_id to community group $group_id: $errmsg\n$errorInfo" break } } } -after_submit { ad_returnredirect . ad_script_abort } ad_form -action user-new -name user_create -cancel_url . -form { {email:text {label "Email"} {help_text "Type the email of the person you would like to add"} {html {size 50}} } } openacs-5.7.0/packages/acs-subsite/www/members/member-invite-postgresql.xql0000644000175000017500000000136210005232302026730 0ustar frankiefrankie postgresql7.1 select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id from cc_users u where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like upper('%'||:value||'%') and not exists (select 1 from acs_rels where object_id_one = $group_id and object_id_two = u.user_id and rel_type = 'membership_rel') order by name openacs-5.7.0/packages/acs-subsite/www/members/make-member.tcl0000644000175000017500000000113407763471763024162 0ustar frankiefrankiead_page_contract { Make ordinary members. } { {user_id:multiple ""} } set group_id [application_group::group_id_from_package_id] permission::require_permission -object_id $group_id -privilege "admin" # TODO: # Check if you're making yourself an non-admin? db_transaction { foreach one_user_id $user_id { db_1row get_rel_id {} relation_remove $rel_id } } on_error { ad_return_error "Error creating the relation" "We got the following error message while trying to create this relation:
    $errmsg
    " ad_script_abort } ad_returnredirect . ad_script_abort openacs-5.7.0/packages/acs-subsite/www/members/make-member.xql0000644000175000017500000000046307763471763024210 0ustar frankiefrankie select distinct rel_id from rel_segment_party_map where rel_type = 'admin_rel' and group_id = :group_id and party_id = :user_id openacs-5.7.0/packages/acs-subsite/www/members/user-new.adp0000644000175000017500000000047611547321140023511 0ustar frankiefrankie @context;noquote@ @page_title;noquote@ register.first_names openacs-5.7.0/packages/acs-subsite/www/members/user-new.tcl0000644000175000017500000000634511547321140023530 0ustar frankiefrankiead_page_contract { Add a new user to the system, if the email doesn't already exist. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-02 @cvs-id $Id: user-new.tcl,v 1.10 2011/04/07 11:39:12 emmar Exp $ } { email:trim } subsite::assert_user_may_add_member set group_id [application_group::group_id_from_package_id] set mainsite_group_id [application_group::group_id_from_package_id \ -no_complain \ -package_id [subsite::main_site_id]] set rel_group_id "" if { $mainsite_group_id ne $group_id } { set rel_group_id $group_id } set page_title "Inivite Member to [ad_conn instance_name]" set context [list [list "." "Members"] "Invite"] # Check if email is already known on the system set party_id [db_string select_party { select party_id from parties where lower(email) = lower(:email) } -default {}] if { $party_id ne "" } { # Yes, is it a user? set user_id [db_string select_user { select user_id from users where user_id = :party_id } -default {}] if { $user_id eq "" } { # This is a party, but it's not a user acs_object_type::get -object_type [acs_object_type $party_id] -array object_type # TODO: Move this to the form, by moving the form to an include template ad_return_complaint 1 "
  • This email belongs to a $object_type(pretty_name) on the system. We cannot create a new user with this email." ad_script_abort } else { # Already a user, but not a member of this subsite, and may not be a member of the main site (registered users) # We need to know if we're on the main site below set main_site_p [string equal [site_node::get_url -node_id [ad_conn node_id]] "/"] # Check to see if the user is a member of the main site (registered user) set registered_user_id [db_string select_user { select user_id from cc_users where user_id = :party_id } -default {}] if { $registered_user_id eq "" } { # User exists, but is not member of main site. Requires SW-admin to remedy. if { [acs_user::site_wide_admin_p] } { set main_site_id [site_node::get_element -url / -element object_id] group::add_member \ -group_id [application_group::group_id_from_package_id -package_id $main_site_id] \ -user_id $party_id } else { # TODO: Move this to the form, by moving the form to an include template ad_return_complaint 1 "
  • User has an acccount on the system, but has been removed from the main site. Only a site-wide administrator can re-add the user." ad_script_abort } } # The user is now a registered user (member of main site) if { $main_site_p } { # Already a member. } else { group::add_member \ -group_id $group_id \ -user_id $party_id } } ad_returnredirect . ad_script_abort } set subsite_id [ad_conn subsite_id] set user_new_template [parameter::get -parameter "UserNewTemplate" -package_id $subsite_id] if {$user_new_template eq ""} { set user_new_template "/packages/acs-subsite/lib/user-new" } openacs-5.7.0/packages/acs-subsite/www/members/member-invite-oracle.xql0000644000175000017500000000125610005232302025774 0ustar frankiefrankie oracle8.1.6 select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id from cc_users u where upper(nvl(u.first_names || ' ', '') || nvl(u.last_name || ' ', '') || u.email || ' ' || nvl(u.screen_name, '')) like upper('%'||:value||'%') and not exists (select 1 from acs_rels where object_id_one = $group_id and object_id_two = u.user_id and rel_type = 'membership_rel') order by name openacs-5.7.0/packages/acs-subsite/www/members/user-batch-add.adp0000644000175000017500000000203511043711736024525 0ustar frankiefrankie Add a batch of users @context;noquote@

    Add these users to @system_name@, one user per line. The format of the lines should be:

    user@example.net, Jane, Austin
    user2@example.net, Emily, Dickinson

    Each user will get this email:
    From:
    Subject:

    Message:

    openacs-5.7.0/packages/acs-subsite/www/members/user-batch-add.tcl0000644000175000017500000000157511130540436024545 0ustar frankiefrankiead_page_contract { Interface for specifying a list of users to sign up as a batch @cvs-id $Id: user-batch-add.tcl,v 1.4 2009/01/06 02:25:34 gustafn Exp $ } -properties { context:onevalue system_name:onevalue system_url:onevalue administration_name:onevalue admin_email:onevalue } subsite::assert_user_may_add_member set admin_user_id [ad_conn user_id] set admin_email [db_string unused "select email from parties where party_id = :admin_user_id"] set administration_name [db_string admin_name "select first_names || ' ' || last_name from persons where person_id = :admin_user_id"] set context [list [list "./" "Users"] "Notify added user"] set system_name [ad_system_name] set export_vars [export_form_vars email first_names last_name user_id] set system_url [parameter::get -package_id [ad_acs_kernel_id] -parameter SystemURL -default ""]. ad_return_template openacs-5.7.0/packages/acs-subsite/www/members/member-state-change.tcl0000644000175000017500000000044507741557667025620 0ustar frankiefrankiead_page_contract { Change member state } { {rel_id:multiple ""} {member_state:notnull} } ad_require_permission $rel_id "admin" membership_rel::change_state \ -rel_id $rel_id \ -state $member_state ad_returnredirect [export_vars -base . { member_state }] ad_script_abort openacs-5.7.0/packages/acs-subsite/www/image.vuh0000644000175000017500000000454111460320062021423 0ustar frankiefrankie# packages/acs-subsite/www/image.vuh # # Subsite handler for images # # @author Dave Bauer (dave@thedesignexperience.org) # @creation-date 2006-08-01 # @cvs-id $Id: image.vuh,v 1.8 2010/10/22 14:31:14 raulm Exp $ set url [ad_conn path_info] if {![regexp {^/([0-9]+)(/(|thumbnail|avatar|info))?(/(private)/([0-9]+))?(/(.*))?$} $url match object_id extra_arg_slash extra_arg private_slash private private_parent_id filename_slash filename anchor]} { ad_return_warning "Invalid object id" [subst { The identifier given for this object (${object_id}) is invalid. Please check your url or contact the webmaster if you think it should work. }] return } # check permissions! if { $private eq "private" } { # find if the image has a parent link to the object # that is, if the image is used in a content item and you can read the # content item, you can read the image regardless of the permissions set object_to_check $object_id if { [application_data_link::link_exists \ -from_object_id $private_parent_id \ -to_object_id $object_id] } { # if the link does not exist it might be # because its a new object # that means you uploaded the image so you can see it in # the editor while you are working on it set object_to_check $private_parent_id } if {![permission::permission_p \ -privilege "read" \ -object_id $object_to_check \ -party_id [ad_conn user_id]]} { ns_returnnotfound ad_script_abort } } else { permission::require_permission \ -privilege "read" \ -object_id $object_id \ -party_id [ad_conn user_id] } # find a cr_item and serve it if { $extra_arg eq "thumbnail" || $extra_arg eq "avatar" } { #find the thumbnail object_id set new_object_id [image::get_resized_item_id -item_id $object_id -size_name $extra_arg] if {$new_object_id eq ""} { # We need to resize the image it seems set new_object_id [image::resize -item_id $object_id -size_name $extra_arg] } set object_id $new_object_id } if {$extra_arg eq "info"} { rp_form_put item_id $object_id rp_form_put filename $filename rp_internal_redirect "/packages/acs-content-repository/www/image-info" ad_script_abort } else { cr_write_content -item_id $object_id } openacs-5.7.0/packages/acs-subsite/www/index.adp0000644000175000017500000000420211017341324021406 0ustar frankiefrankie @context;noquote@ @subsite_name;noquote@

    #acs-subsite.Applications#

    #acs-subsite.Subsites#

    openacs-5.7.0/packages/acs-subsite/www/index.tcl0000644000175000017500000000417610551254376021452 0ustar frankiefrankie# packages/mbryzek-subsite/www/index.tcl ad_page_contract { @author rhs@mit.edu @author mbryzek@mit.edu @creation-date 2000-09-18 @cvs-id $Id: index.tcl,v 1.21 2007/01/10 21:22:06 gustafn Exp $ } { } -properties { context:onevalue subsite_name:onevalue subsite_url:onevalue nodes:multirow admin_p:onevalue user_id:onevalue show_members_page_link_p:onevalue } set main_site_p [string equal [ad_conn package_url] "/"] # We may have to redirect to some application page set redirect_url [parameter::get -parameter IndexRedirectUrl -default {}] if { $redirect_url eq "" && $main_site_p } { set redirect_url [parameter::get_from_package_key -package_key acs-kernel -parameter IndexRedirectUrl] } if { $redirect_url ne "" } { ad_returnredirect $redirect_url ad_script_abort } # Handle IndexInternalRedirectUrl set redirect_url [parameter::get -parameter IndexInternalRedirectUrl -default {}] if { $redirect_url eq "" && $main_site_p } { set redirect_url [parameter::get_from_package_key -package_key acs-kernel -parameter IndexInternalRedirectUrl] } if { $redirect_url ne "" } { rp_internal_redirect $redirect_url ad_script_abort } set context [list] set package_id [ad_conn package_id] set admin_p [permission::permission_p -object_id $package_id -party_id [ad_conn untrusted_user_id] -privilege admin] set user_id [ad_conn user_id] set untrusted_user_id [ad_conn untrusted_user_id] set subsite_name [ad_conn instance_name] set subsite_url [subsite::get_element -element url] set show_members_list_to [parameter::get -parameter "ShowMembersListTo" -default 2] set show_members_page_link_p \ [expr {$admin_p || ($user_id != 0 && $show_members_list_to ==1) || \ $show_members_list_to == 0 }] # User's group membership set group_id [application_group::group_id_from_package_id] set group_join_policy [group::join_policy -group_id $group_id] set group_member_p [group::member_p -group_id $group_id -user_id $user_id] set group_admin_p [group::admin_p -group_id $group_id -user_id $user_id] set can_join_p [expr {!$group_admin_p && $group_member_p == 0 && $user_id != 0 && $group_join_policy ne "closed" }] openacs-5.7.0/packages/acs-subsite/www/shared/0000755000175000017500000000000011724401447021071 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/shared/make-visible.tcl0000644000175000017500000000043611164426640024150 0ustar frankiefrankiead_page_contract { Make user visible. } { {return_url ""} } auth::require_login whos_online::unset_invisible [ad_conn user_id] if { $return_url eq "" } { set return_url [ad_pvt_home] } ad_returnredirect -message [_ acs-subsite.Online_status_set_visible] -- $return_url openacs-5.7.0/packages/acs-subsite/www/shared/community-member-postgresql.xql0000644000175000017500000000075610171476746027332 0ustar frankiefrankie postgresql7.1 select at.pretty_name, at.pretty_plural, a.creation_date, acs_object__name(a.object_id) as object_name from acs_objects a, acs_object_types at where a.object_type = at.object_type and a.creation_user = :user_id order by at.pretty_name, creation_date desc openacs-5.7.0/packages/acs-subsite/www/shared/send-email.adp0000644000175000017500000000035310171756004023573 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    #acs-subsite.mail_a_message_to# @first_names@ @last_name@

    openacs-5.7.0/packages/acs-subsite/www/shared/send-email.tcl0000644000175000017500000000273411226233616023617 0ustar frankiefrankiead_page_contract { Sends an email to the user with user_id = sendto @author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) } { sendto:notnull {return_url ""} } -properties { context:onevalue } set user_id [auth::require_login -account_status closed] set page_title "\#acs-subsite.Send_email_to_this_user\#" set context [list [list [ad_pvt_home] [ad_pvt_home_name]] "Send Email"] if {$return_url eq ""} { set return_url [ad_pvt_home] } db_1row user_to_info { *SQL* } set from [email_image::get_email -user_id $user_id] ad_form -name send-email -export {sendto return_url} -form { {from:text(text),optional {label "From:"} {html {{disabled ""} {size 40}}} {value $from} } {subject:text(text) {label "Subject:"} {html {size 70}} } {body:text(textarea),nospell {label "Body:"} {html {rows 10 cols 55}} {value ""} } } -on_submit { set to [email_image::get_email -user_id $sendto] if {[catch {acs_mail_lite::send -send_immediately -to_addr $to -from_addr $from -subject $subject -body $body} errmsg]} { ad_return_error "Mail Failed" "

    The system was unable to send email. Please notify the user personally. This problem is probably caused by a misconfiguration of your email system. Here is the error:

    [ad_quotehtml $errmsg]
    " } } -after_submit { ad_returnredirect $return_url } openacs-5.7.0/packages/acs-subsite/www/shared/send-email.xql0000644000175000017500000000031110171756004023625 0ustar frankiefrankie select first_names, last_name from cc_users where user_id = :sendto openacs-5.7.0/packages/acs-subsite/www/shared/iso-codes-no-exist.adp0000644000175000017500000000042507743742277025230 0ustar frankiefrankie #acs-subsite.ISO_Codes_Not_Loaded# #acs-subsite.No_ISO_Codes#

    #acs-subsite.ISO_Codes_not_loaded#


    #acs-subsite.The_ISO_codes_were_not#

    #acs-subsite.lt_If_you_need_this_func# openacs-5.7.0/packages/acs-subsite/www/shared/session-update.tcl0000644000175000017500000000225210551254402024533 0ustar frankiefrankie# acs-subsite/www/shared/session-update.tcl ad_page_contract { @author Don Baccus (dhogaza@pacifier.com) @creation-date 2-Feb-2002 @param session_property The array which describes the new session property. The required elements are package, key, value, and referrer. The referrer element should be set [ad_conn url]. @param return_url The page to return to Update the given session parameter with the given value and redirect to the caller. Note that a session property should never be used alone to drive any action in the system. Always use permissions or an equivalent check! In order to reduce the potential for harm that might follow from forgetting this principle the session_property array passed to this page is signed and verified. } { session_property:array,verify return_url } -validate { referrer_error { if { $session_property(referrer) ne [get_referrer] } { ad_complain "Expected referrer does not match actual referrer" } } } ad_set_client_property $session_property(package) $session_property(key) $session_property(value) ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/www/shared/make-invisible.tcl0000644000175000017500000000044011164426640024472 0ustar frankiefrankiead_page_contract { Make user invisible. } { {return_url ""} } auth::require_login whos_online::set_invisible [ad_conn user_id] if { $return_url eq "" } { set return_url [ad_pvt_home] } ad_returnredirect -message [_ acs-subsite.Online_status_set_invisible] -- $return_url openacs-5.7.0/packages/acs-subsite/www/shared/email-image-bits.tcl0000644000175000017500000000036010171755520024701 0ustar frankiefrankiead_page_contract { spits out correctly MIME-typed bits for a user's email-image @author Miguel Marin (miguelmarin@viaro.net) Viaro Networks (www.viaro.net) } { revision_id:integer } cr_write_content -revision_id $revision_id openacs-5.7.0/packages/acs-subsite/www/shared/whos-online.adp0000644000175000017500000000030511253303101024000 0ustar frankiefrankie doc @context;noquote@

    #acs-subsite.Whos_Online_link_label#

    openacs-5.7.0/packages/acs-subsite/www/shared/whos-online.tcl0000644000175000017500000000253011253303101024020 0ustar frankiefrankiead_page_contract { Displays who's currently online @author Peter Marklund @cvs-id $Id: whos-online.tcl,v 1.11 2009/09/13 23:54:41 donb Exp $ } -properties { title:onevalue context:onevalue } set doc(title) [_ acs-subsite.Whos_Online_title] set context [list $doc(title)] set whos_online_interval [whos_online::interval] template::list::create \ -name online_users \ -multirow online_users \ -no_data [_ acs-subsite.Nobody_is_online] \ -elements { name { label "[_ acs-subsite.User_name]" link_url_col url } online_time_pretty { label "[_ acs-subsite.Online_time]" html { align right } } } set users [list] foreach user_id [whos_online::user_ids] { acs_user::get -user_id $user_id -array user set first_request_minutes [expr {[whos_online::seconds_since_first_request $user_id] / 60}] lappend users [list \ "$user(first_names) $user(last_name)" \ [acs_community_member_url -user_id $user_id] \ "$first_request_minutes minutes"] } set users [lsort -index 0 $users] multirow create online_users name url online_time_pretty foreach elm $users { multirow append online_users \ [lindex $elm 0] \ [lindex $elm 1] \ [lindex $elm 2] } openacs-5.7.0/packages/acs-subsite/www/shared/images/0000755000175000017500000000000011724401447022336 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/shared/images/underline-button.gif0000644000175000017500000000015707634164405026333 0ustar frankiefrankieGIF89a‘ÿÿÿôòïfff!ù,@Œ©Ë£œÑK…Åès ‚7fÛ$’á)¥© f㋲‘[Ö1:ç­}£é ·(ùnÀ"äPJ§T‘ãŠÍ" ;openacs-5.7.0/packages/acs-subsite/www/shared/images/radio.gif0000644000175000017500000000010607634164405024125 0ustar frankiefrankieGIF89a €¡¦¬ÿÿÿ!ù, Œ y ­VkÑðÇ¿yc :;qã¿|å¹ø¬Ñ¿:·æ3ù/$AR6ë`|‰ãŸÌ"S"ã¹ôdJ‚GÿÑiˆ! ¤=Ù„XN¬\ó‘lÈ’+×±hÓ¦5[0 ;openacs-5.7.0/packages/acs-subsite/www/shared/images/go.gif0000644000175000017500000000023107634164405023433 0ustar frankiefrankieGIF89a³Ì3ÿÿÿñÉ»ßaÜrOé§‘ä’wÖ\3à…føäÝõÖÌüñîÉA!ù,FЉª­CÈËíìK  pAÁh´Ñ$&R Á. 8/V )³ÞÌ0bJ†à°B8&††kJ…¼– x'…4;openacs-5.7.0/packages/acs-subsite/www/shared/images/new.gif0000644000175000017500000000035507634164405023626 0ustar frankiefrankieGIF89a" ³ÿÿÿÛlHÌ3襎õÕÊä’vñÉ»øâÛà†gÔS(Ï@Ö\3üñîÓN"úíè!ù," šν8çPš\B(Ždi† €”L.Á)‹IL@!À<¶Ðê …£à Òó†3ðv!ÁÈñ ¢4(2€DoÐ(¨3 8”¦ÂÂÂÓ3 €hwd!f;=  ]=ŽŠN™Œj Ž+  &x> M¬!¦°´"  µ° ¡;openacs-5.7.0/packages/acs-subsite/www/shared/images/add.gif0000644000175000017500000000006507634164405023563 0ustar frankiefrankieGIF89a€Ì!ù, L€fËc:ÓµP;openacs-5.7.0/packages/acs-subsite/www/shared/images/checkbox.gif0000644000175000017500000000010207634164405024611 0ustar frankiefrankieGIF89a €¡¦¬ÿÿÿ!ù, „Ëæ"ŒmÒeo¦[‚ËtŽX}à“¤F;openacs-5.7.0/packages/acs-subsite/www/shared/images/diamond.gif0000644000175000017500000000013307634164405024442 0ustar frankiefrankieGIF89a ¢ÌõÌÌÏÖ33ÝUUÓ""!ù,  hª´®Œ.Ú»ôæðmB`„c¹ –ê îæ’;openacs-5.7.0/packages/acs-subsite/www/shared/images/radiochecked.gif0000644000175000017500000000012207634164405025432 0ustar frankiefrankieGIF89a ‘¡¦¬ÿÿÿ!ù, #”y+­V~k…ɉ(-T|Á„AE}øà6°,%XH˜aã‡iE“¶9¤ 4º|Hàcƒ|!KNJ1€ ^Ât¡ÀÁÇÂ'×>ƒ‚ 80à´ìÒÅ3ðf0DÁƒ b?=Ć ÔÀ#xdéÅ}ëðqáË è÷WI¿A€AYp¡ ~¬G[A-pÀ 1DpʼnüÈl"„C -øGM$$PFeXF&¶у-šÈ^Œ4Æ!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/shared/images/Delete16.gif0000644000175000017500000000032007661404350024372 0ustar frankiefrankieGIF89a¢ÿÿÿÿÌÌÌ™™™fff333ÀÀÀ!ù,BhºÜn$>«•Œ„„d×5fÀö…À¹ˆB0ëÀ2m7ø\‹7@Ì·C u@ž0÷s½ROñUŠ8­¬vÂU$!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/shared/images/Delete24.gif0000644000175000017500000000037107661404351024400 0ustar frankiefrankieGIF89a¢ÿÿÿÿÌÌÌ™™™fff333ÀÀÀ!ù,khºÜþ0ÊUêŒ%èrù`(F  ªC ‰p&š²åüB ‚€ÐÒíz= è¢!ÁaQRz*¥Í£ïÊ4>ªÛh—Ê /§N3Öë'Åhíûœý–çk²í&ˆc"l„…†…‰Š !þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/shared/images/spacer.gif0000644000175000017500000000005307661404351024302 0ustar frankiefrankieGIF89a€ÿÀÀÀ!ù,D;openacs-5.7.0/packages/acs-subsite/www/shared/images/bold-button.gif0000644000175000017500000000015707634164405025266 0ustar frankiefrankieGIF89a‘ÿÿÿôòïfff!ù,@Œ©Ë£œÑK…Åè“ ¢x}F¨Ù&:™ ÇläÖø å¤ Š‰^¿Ï3*ƒÒ±ÙC$§Ô©ãŠÍ" ;openacs-5.7.0/packages/acs-subsite/www/shared/community-member-oracle.xql0000644000175000017500000000075210171476746026370 0ustar frankiefrankie oracle8.1.6 select at.pretty_name, at.pretty_plural, a.creation_date, acs_object.name(a.object_id) as object_name from acs_objects a, acs_object_types at where a.object_type = at.object_type and a.creation_user = :user_id order by at.pretty_name, creation_date desc openacs-5.7.0/packages/acs-subsite/www/shared/index.tcl0000644000175000017500000000030007717247025022704 0ustar frankiefrankie# $Id: index.tcl,v 1.3 2003/08/15 21:18:13 frankn Exp $ # user try to play with the URL and get the directory structure instead of a file ad_returnredirect [subsite::get_element -element url] openacs-5.7.0/packages/acs-subsite/www/shared/portrait-thumbnail-bits.tcl0000644000175000017500000000203210551254402026350 0ustar frankiefrankiead_page_contract { spits out correctly MIME-typed bits for a user's portrait (thumbnail version) @author philg@mit.edu @creation-date 26 Sept 1999 @cvs-id $Id: portrait-thumbnail-bits.tcl,v 1.3 2007/01/10 21:22:10 gustafn Exp $ } { user_id:integer } # NB: this really doesn't work! You can now pass a &size= parameter # into portrait-bits.tcl. sizes as per image::get_convert_to_sizes set column portrait_thumbnail set file_type [db_string -default "" unused "select portrait_file_type from users where user_id = $user_id and portrait_thumbnail is not null"] if { $file_type eq "" } { # Try to get a regular portrait set file_type [db_string -default "" unused "select portrait_file_type from users where user_id = $user_id"] if {$file_type eq ""} { ad_return_error "Couldn't find thumbnail or portrait" "Couldn't find a thumbnail or a portrait for User $user_id" return } set column portrait } ReturnHeaders $file_type ns_ora write_blob $db "select $column from users where user_id = $user_id" openacs-5.7.0/packages/acs-subsite/www/shared/portrait-bits.tcl0000644000175000017500000000126311164427775024414 0ustar frankiefrankiead_page_contract { spits out correctly MIME-typed bits for a user's portrait @author philg@mit.edu @creation-date 26 Sept 1999 @cvs-id $Id: portrait-bits.tcl,v 1.9 2009/03/31 15:00:13 emmar Exp $ } { user_id:integer {item_id ""} {size ""} } # If the item_id is provided then we are fine if {$item_id eq ""} { if { ![db_0or1row get_item_id ""] } { # ad_return_error "Couldn't find portrait" "Couldn't find a portrait for User $user_id" ad_return_string_as_file -string "" -mime_type "image/jpeg" -filename "" return } } if { $size eq "" } { cr_write_content -item_id $item_id } else { ad_returnredirect "/image/${item_id}/${size}" } openacs-5.7.0/packages/acs-subsite/www/shared/portrait-bits.xql0000644000175000017500000000051207370061503024415 0ustar frankiefrankie select c.item_id from acs_rels a, cr_items c where a.object_id_two = c.item_id and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel' openacs-5.7.0/packages/acs-subsite/www/shared/portrait-bits-postgresql.xql0000644000175000017500000000054707277142634026641 0ustar frankiefrankie postgresql7.1 select r.lob, i.storage_type from cr_revisions r, cr_items i where r.item_id = i.item_id and r.revision_id = :revision_id openacs-5.7.0/packages/acs-subsite/www/shared/db-error.adp0000644000175000017500000000051507743742277023313 0ustar frankiefrankie #acs-subsite.Database_Error# #acs-subsite.Database_Error#

    #acs-subsite.lt_We_had_a_problem_proc# @custom_message@

    #acs-subsite.lt_Heres_what_the_databa#

    @errmsg@

    openacs-5.7.0/packages/acs-subsite/www/shared/confirm.adp0000644000175000017500000000066110517147227023221 0ustar frankiefrankie @title;noquote@ #acs-subsite.Confirm# @message@

    @export_vars_yes;noquote@
    @export_vars_no;noquote@
    openacs-5.7.0/packages/acs-subsite/www/shared/confirm.tcl0000644000175000017500000000162207253523116023233 0ustar frankiefrankiead_page_contract { General confirmation script @author lars@pinds.com @creation-date 5 Jun 2000 @cvs-id $Id: confirm.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ } { { header "Confirm" } message yes_url no_url { yes_label "Yes, Proceed" } { no_label "No, Cancel" } } -properties { export_vars_yes:onevalue export_vars_no:onevalue title:onevalue message:onevalue yes_path:onevalue yes_label:onevalue no_path:onevalue no_label:onevalue } set title $header set yes_list [split $yes_url "?"] set yes_path [lindex $yes_list 0] set yes_args_set [ns_parsequery [lindex $yes_list 1]] set no_list [split $no_url "?"] set no_path [lindex $no_list 0] set no_args_set [ns_parsequery [lindex $no_list 1]] set export_vars_yes [export_ns_set_vars form {} $yes_args_set] set export_vars_no [export_ns_set_vars form {} $no_args_set] ad_return_template openacs-5.7.0/packages/acs-subsite/www/shared/portrait.adp0000644000175000017500000000053411164427577023437 0ustar frankiefrankie doc @context;noquote@

    #acs-subsite.lt_Portrait_of_first_last#

    @description@

    openacs-5.7.0/packages/acs-subsite/www/shared/portrait.tcl0000644000175000017500000000303311164427577023452 0ustar frankiefrankiead_page_contract { displays a user's portrait to other users @creation-date 26 Sept 1999 @cvs-id $Id: portrait.tcl,v 1.8 2009/03/31 14:58:07 emmar Exp $ } { user_id:integer } -properties { context:onevalue first_names:onevalue last_name:onevalue description:onevalue export_vars:onevalue widthheight_param:onevalue publish_date:onevalue subsite_url:onevalue } set subsite_url [subsite::get_element -element url] if {![db_0or1row user_info "select first_names, last_name from persons where person_id=:user_id"]} { ad_return_error "Account Unavailable" "We can't find user #$user_id in the users table." return } if {![db_0or1row get_item_id "select i.width, i.height, cr.title, cr.description, cr.publish_date from acs_rels a, cr_items c, cr_revisions cr, images i where a.object_id_two = c.item_id and c.live_revision = cr.revision_id and cr.revision_id = i.image_id and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel'"]} { ad_return_complaint 1 "
  • You shouldn't have gotten here; we don't have a portrait on file for this person." return } if { $width ne "" && $height ne "" } { set widthheight_param "width=$width height=$height" } else { set widthheight_param "" } set doc(title) [_ acs-subsite.lt_Portrait_of_first_last] set context [list [list [acs_community_member_url -user_id $user_id] "$first_names $last_name"] [_ acs-subsite.Portrait]] set export_vars [export_url_vars user_id] set pretty_date [lc_time_fmt $publish_date "%q"] ad_return_template openacs-5.7.0/packages/acs-subsite/www/shared/community-member.adp0000644000175000017500000000344710723077077025066 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ @user_id;noquote@
    Portrait of @first_names@ @last_name@

    #acs-subsite.A_member_of_the_system# @pretty_creation_date@.

    #acs-subsite.This_user_has_left_the#
    #acs-subsite.lt_This_user_is_deleted#

    #acs-subsite.Name#: @first_names@ @last_name@

    @email_image;noquote@

    #acs-subsite.Home_page#:@url@

    #acs-subsite.Biography#:

    @bio;noquote@
    #acs-subsite.If_you_were_to# #acs-subsite.log_in##acs-subsite.lt__youd_be_able_to_get#

    #acs-subsite.lt_For_Site-Wide_Adminis#

    openacs-5.7.0/packages/acs-subsite/www/shared/community-member.tcl0000644000175000017500000000674611211475654025105 0ustar frankiefrankiead_page_contract { shows User A what User B has contributed to the community @param user_id defaults to currently logged in user if there is one @cvs-id $Id: community-member.tcl,v 1.18 2009/06/03 13:33:32 donb Exp $ } { {user_id:integer ""} } -properties { context:onevalue member_state:onevalue first_names:onevalue last_name:onevalue email:onevalue inline_portrait_state:onevalue portrait_export_vars:onevalue width:onevalue height:onevalue system_name:onevalue pretty_creation_date:onevalue show_email_p:onevalue url:onevalue bio:onevalue verified_user_id:onevalue subsite_url:onevalue } set subsite_url [subsite::get_element -element url] #See if this page has been overrided by a parameter in kernel set community_member_url [parameter::get -package_id [ad_acs_kernel_id] -parameter CommunityMemberURL -default "/shared/community-member"] if { $community_member_url ne "/shared/community-member" } { ad_returnredirect "$community_member_url?user_id=$user_id" ad_script_abort } set site_wide_admin_p [acs_user::site_wide_admin_p] set admin_user_url [acs_community_member_admin_url -user_id $user_id] set verified_user_id [ad_conn user_id] set untrusted_user_id [ad_conn untrusted_user_id] if { $user_id eq "" } { if { $verified_user_id == 0 } { # Don't know what to do! ad_return_error "Missing user_id" "We need a user_id to display the community page" return } set user_id $verified_user_id } set bind_vars [ad_tcl_vars_to_ns_set user_id] if { ![db_0or1row user_information "select first_names, last_name, email, priv_email, url, creation_date, member_state from cc_users where user_id = :user_id" -bind $bind_vars]} { ad_return_error "No user found" "There is no community member with the user_id of $user_id" ns_log Notice "Could not find user_id $user_id in community-member.tcl from [ad_conn peeraddr]" return } # Here the email_image is created according to the priv_email # field in the users table set email_image "

    \#acs-subsite.E_mail\#: [email_image::get_user_email -user_id $user_id]

    " if { $url ne "" && ![string match -nocase "http://*" $url] } { set url "http://$url" } set bio [ad_text_to_html -- [person::get_bio -person_id $user_id]] # Do we show the portrait? set inline_portrait_state "none" set portrait_export_vars [export_url_vars user_id] if {[db_0or1row portrait_info " select i.width, i.height, cr.title, cr.description, cr.publish_date from acs_rels a, cr_items c, cr_revisions cr, images i where a.object_id_two = c.item_id and c.live_revision = cr.revision_id and cr.revision_id = i.image_id and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel'"]} { # We have a portrait. Let's see if we can show it inline if { $width ne "" && $width < 300 } { # let's show it inline set inline_portrait_state "inline" } else { set inline_portrait_state "link" } } if { $priv_email <= [ad_privacy_threshold] } { set show_email_p 1 } else { set show_email_p 0 # guy doesn't want his email address shown, but we can still put out # the home page } set page_title "$first_names $last_name" set context [list "Community Member"] set system_name [ad_system_name] set pretty_creation_date [lc_time_fmt $creation_date "%q"] set login_export_vars "return_url=[ns_urlencode [acs_community_member_url -user_id $user_id]]" set login_url [export_vars -base "/register/." { { return_url [ad_return_url]} }] ad_return_template openacs-5.7.0/packages/acs-subsite/www/shared/parameters.adp0000644000175000017500000000105307743742277023740 0ustar frankiefrankie @page_title@ @context@ @focus;noquote@ (*) #acs-subsite.lt_Note_text_in_red_below#

    #acs-subsite.No_package_parameters#

    » #acs-subsite.Go_back#

    openacs-5.7.0/packages/acs-subsite/www/shared/parameters.tcl0000644000175000017500000001076311356123603023743 0ustar frankiefrankiead_page_contract { Parameters page. @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-06-13 @cvs-id $Id: parameters.tcl,v 1.20 2010/04/04 14:51:47 donb Exp $ } { {package_id:naturalnum "[ad_conn package_id]"} package_key:optional {scope "instance"} {return_url:optional "[ad_conn url]?[ad_conn query]"} {section ""} } if { $scope eq "global" } { permission::require_permission \ -object_id [acs_lookup_magic_object security_context_root] \ -privilege admin db_1row select_pretty_name {} set package_url /acs-admin set page_title "$instance_name Global Parameters" set context [list [list $package_url "Site-Wide Administration"] $page_title] } else { permission::require_permission -object_id $package_id -privilege admin db_1row select_instance_name {} set package_url [site_node::get_url_from_object_id -object_id $package_id] set page_title "$instance_name Instance Parameters" if { $package_url eq [subsite::get_element -element url] } { set context [list [list "${package_url}admin/" "Administration"] $page_title] } elseif { $package_url ne "" } { set context [list [list $package_url $instance_name] [list "${package_url}admin/" "Administration"] $page_title] } else { set context [list $page_title] } } ad_form -name parameters -export {section} -cancel_url $return_url -form { {return_url:text(hidden)} {scope:text(hidden)} {package_id:integer(hidden),optional} {package_key:text(hidden),optional} } set display_warning_p 0 set counter 0 set focus_elm {} if {$section ne ""} { set section_where_clause [db_map section_where_clause] } else { set section_where_clause "" } array set sections {} db_foreach select_params {} { if { $section_name eq "" } { set section_name "main" set section_pretty "Main" } else { set section_name [string map {- {_} " " {_}} $section_name] set section_pretty [string map {_ { }} $section_name] set section_pretty "[string toupper [string index $section_pretty 0]][string range $section_pretty 1 end]" } if { ![info exists sections($section_name)] } { set sec [list "-section" $section_name {legendtext "$section_pretty"}] ad_form -extend -name parameters -form [list $sec] set sections($section_name) "$section_pretty" } if { $counter == 0 } { set focus_elm $parameter_name } switch $datatype { text { set widget textarea set html [list cols 100 rows 15] } default { set widget text set html [list size 50] } } set elm [list ${parameter_name}:text($widget),optional,nospell \ {label {$parameter_name}} \ {help_text {$description}} \ [list html $html]] set file_val [ad_parameter_from_file $parameter_name $package_key] if { $file_val ne "" } { set display_warning_p 1 lappend elm [list after_html "
    $file_val (*)"] } ad_form -extend -name parameters -form [list $elm] set param($parameter_name) $attr_value incr counter } set focus "parameters.$focus_elm" if { $counter > 0 } { # Close last section ad_form -extend -name parameters -form [list "-section"] ad_form -extend -name parameters -on_request { foreach name [array names param] { set $name $param($name) } } -on_submit { db_foreach select_params_set {} { if { [info exists $c__parameter_name] } { if { $scope eq "instance" } { parameter::set_value \ -package_id $package_id \ -parameter $c__parameter_name \ -value [set $c__parameter_name] callback subsite::parameter_changed -package_id $package_id -parameter $c__parameter_name -value [set $c__parameter_name] } else { parameter::set_global_value \ -package_key $package_key \ -parameter $c__parameter_name \ -value [set $c__parameter_name] callback subsite::global_parameter_changed -package_key $package_key -parameter $c__parameter_name -value [set $c__parameter_name] } } } } -after_submit { ad_returnredirect $return_url ad_script_abort } } openacs-5.7.0/packages/acs-subsite/www/shared/parameters.xql0000644000175000017500000000326011356123603023757 0ustar frankiefrankie select pretty_name as instance_name from apm_package_types where package_key = :package_key select instance_name, package_key from apm_packages where package_id = :package_id and section_name=:section select p.parameter_name, coalesce(p.description, 'No Description') as description, v.attr_value, coalesce(p.section_name, '') as section_name, p.datatype from apm_parameters p left outer join (select v.parameter_id, v.attr_value from apm_parameter_values v where (v.package_id = :package_id or v.package_id is null)) v on p.parameter_id = v.parameter_id where p.package_key = :package_key and p.scope = :scope $section_where_clause order by section_name, parameter_name select p.parameter_name as c__parameter_name from apm_parameters p left outer join (select v.parameter_id, v.attr_value from apm_parameter_values v where (v.package_id = :package_id or v.package_id is null)) v on p.parameter_id = v.parameter_id where p.package_key = :package_key and p.scope = :scope $section_where_clause openacs-5.7.0/packages/acs-subsite/www/shared/iso-codes.adp0000644000175000017500000000067507743742277023473 0ustar frankiefrankie #acs-subsite.lt_Complete_List_of_ISO_# #acs-subsite.ISO_Code_List#

    #acs-subsite.lt_Complete_List_of_ISO_#

    #acs-subsite.lt_Please_locate_your_co#
    #acs-subsite.Country_Name##acs-subsite.ISO_Code#
    @ccodes.country_name@@ccodes.iso@
    openacs-5.7.0/packages/acs-subsite/www/shared/iso-codes.tcl0000644000175000017500000000067607544501421023471 0ustar frankiefrankiead_page_contract { displays the iso-codes @cvs-id $Id: iso-codes.tcl,v 1.2 2002/09/26 03:46:25 jong Exp $ } -properties { ccodes:multirow } if {![db_table_exists countries] } { # acs-reference countries not loaded set header [ad_header "ISO Codes"] ad_return_template iso-codes-no-exist return } db_multirow ccodes country_codes "select iso, default_name from countries order by default_name" ad_return_templateopenacs-5.7.0/packages/acs-subsite/www/shared/portrait-bits-oracle.xql0000644000175000017500000000045007277415123025670 0ustar frankiefrankie oracle8.1.6 select r.content from cr_revisions r where r.revision_id = $revision_id openacs-5.7.0/packages/acs-subsite/www/shared/report-error.adp0000644000175000017500000000035407743742277024242 0ustar frankiefrankie #acs-subsite.Application_Error# #acs-subsite.Error# #acs-subsite.lt_We_had_a_problem_proc# @custom_message@ openacs-5.7.0/packages/acs-subsite/www/shared/1pixel.footer0000644000175000017500000000002307443753715023521 0ustar frankiefrankieÿÿÿ,D;openacs-5.7.0/packages/acs-subsite/www/shared/1pixel.header0000644000175000017500000000001507443753715023454 0ustar frankiefrankieGIF87a€openacs-5.7.0/packages/acs-subsite/www/shared/1pixel.tcl0000644000175000017500000000247210210133524022767 0ustar frankiefrankie# 1pixel.tcl,v 1.1.2.2 2000/02/03 10:00:24 ron Exp ad_page_contract { Generates a 1-pixel GIF image with a certain color. @author Jon Salz @creation-date 28 Nov 1999 @cvs-id $Id: 1pixel.tcl,v 1.4 2005/02/26 17:52:20 jeffd Exp $ } { r:integer g:integer b:integer } ReturnHeaders "image/gif" if { [catch { set file [open "[acs_package_root_dir "acs-subsite"]/www/shared/1pixel.header"] ns_writefp $file close $file # Can't figure out how to write binary data using AOLserver 3 (it # insist on UTF8-encoding it). So we write to a file, then dump # the file's contents. set file_name [ns_tmpnam] ns_log "Notice" "logging to $file_name" set file [open $file_name w+] fconfigure $file -encoding binary -translation binary puts -nonewline $file "[format "%c%c%c" $r $g $b]" seek $file 0 ns_writefp $file close $file ns_unlink $file_name set file [open "[acs_package_root_dir "acs-subsite"]/www/shared/1pixel.footer"] ns_writefp $file close $file } errMsg] } { # Ignore simple i/o errors, which probably just mean that the user surfed on # to some other page before we finished serving if { ![string equal $errMsg {i/o failed}] } { global errorInfo ns_log Error "$errMsg\n$errorInfo" } } openacs-5.7.0/packages/acs-subsite/www/resources/0000755000175000017500000000000011724401447021635 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/resources/underline-button.gif0000644000175000017500000000015707725607455025642 0ustar frankiefrankieGIF89a‘ÿÿÿôòïfff!ù,@Œ©Ë£œÑK…Åès ‚7fÛ$’á)¥© f㋲‘[Ö1:ç­}£é ·(ùnÀ"äPJ§T‘ãŠÍ" ;openacs-5.7.0/packages/acs-subsite/www/resources/core.js0000644000175000017500000014160511544377536023145 0ustar frankiefrankie/* Emulate getElementById on document.all only browsers. Requires that IDs are unique to the page and do not coincide with NAME attributes on other elements:- Source: http://www.litotes.demon.co.uk/js_info/faq_notes/alt_dynwrite.html#getEl */ if((!document.getElementById) && document.all){ document.getElementById = function(id){return document.all[id];}; } function acs_Focus(form_name, element_name) { if (document.forms == null) return; if (document.forms[form_name] == null) return; if (document.forms[form_name].elements[element_name] == null) return; if (document.forms[form_name].elements[element_name].type == 'hidden') return; document.forms[form_name].elements[element_name].focus(); } function acs_FormRefresh(form_name) { if (document.forms == null) return; if (document.forms[form_name] == null) return; if (document.forms[form_name].elements["__refreshing_p"] == null) return; document.forms[form_name].elements["__refreshing_p"].value = 1; document.forms[form_name].submit(); } /* Copy-Paste functionality */ function acs_CopyText(text) { if (document.all) { holdtext.innerText = text; Copied = holdtext.createTextRange(); Copied.execCommand("Copy"); } else if (window.netscape) { netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard); if (!clip) return; var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable); if (!trans) return; trans.addDataFlavor('text/unicode'); var str = new Object(); var len = new Object(); var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); var copytext = text; str.data = copytext; trans.setTransferData("text/unicode", str, copytext. length*2); var clipid = Components.interfaces.nsIClipboard; if (!clipid) return false; clip.setData(trans, null, clipid. kGlobalClipboard); } } /* Richtext Widget Support */ function acs_RichText_FormatStr (v) { if (!document.selection) return; var str = document.selection.createRange().text; if (!str) return; document.selection.createRange().text = '<' + v + '>' + str + ''; } function acs_RichText_InsertLink () { if (!document.selection) return; var str = document.selection.createRange().text; if (!str) return; var my_link = prompt('Enter URL:', 'http://'); if (my_link != null) document.selection.createRange().text = '' + str + ''; } function acs_RichText_WriteButtons () { if (document.selection) { document.write(''); document.write(''); document.write(''); document.write(''); document.write(''); document.write(''); document.write('
    bolditaliclink
    '); } } function acs_RichText_Or_File_InputMethodChanged(form_name, richtext_name, radio_elm) { if (radio_elm == null) return; if (document.forms == null) return; if (document.forms[form_name] == null) return; if ( radio_elm.value == 'file' ) { document.forms[form_name].elements[richtext_name+".text"].disabled = true; document.forms[form_name].elements[richtext_name+".mime_type"].disabled = true; document.forms[form_name].elements[richtext_name+".file"].disabled = false; } else { document.forms[form_name].elements[richtext_name+".text"].disabled = false; document.forms[form_name].elements[richtext_name+".mime_type"].disabled = false; document.forms[form_name].elements[richtext_name+".file"].disabled = true; } } /* RTE functions */ function acs_rteSubmitForm() { updateRTEs(); return true; } function acs_rteInit(form_name) { // sets onsubmit to function for the given form name if (document.forms == null) return; if (document.forms[form_name] == null) return; document.forms[form_name].onsubmit = acs_rteSubmitForm; } /* HTMLArea (part of Richtext Widget) Support */ function acs_initHtmlArea(editor_var, elementid) { editor_var.generate(); return false; } /* List Builder Support */ function acs_ListFindInput() { if (document.getElementsByTagName) { return document.getElementsByTagName('input'); } else if (document.all) { return document.all.tags('input'); } return false; } function acs_ListCheckAll(listName, checkP) { var Obj, Type, Name, Id; var Controls = acs_ListFindInput(); if (!Controls) { return; } // Regexp to find name of controls var re = new RegExp('^' + listName + '..+'); checkP = checkP ? true : false; for (var i = 0; i < Controls.length; i++) { Obj = Controls[i]; Type = Obj.type ? Obj.type : false; Name = Obj.name ? Obj.name : false; Id = Obj.id ? Obj.id : false; if (!Type || !Name || !Id) { continue; } if (Type == "checkbox" && re.exec(Id)) { Obj.checked = checkP; } } } function acs_ListBulkActionClick(formName, url) { if (document.forms == null) return; if (document.forms[formName] == null) return; var form = document.forms[formName]; form.action = url; form.submit(); } function acs_KeypressGoto(theUrl, event) { var key; if (event) { if (event.which == 13) { location.href = theUrl; } } } /* Copyright Mihai Bazon, 2002, 2003 | http://students.infoiasi.ro/~mishoo * --------------------------------------------------------------------------- * * The DHTML Calendar, version 0.9.3 "It's still alive & keeps rocking" * * Details and latest version at: * http://students.infoiasi.ro/~mishoo/site/calendar.epl * * Feel free to use this script under the terms of the GNU Lesser General * Public License, as long as you do not remove or alter this notice. */ /** The Calendar object constructor. */ Calendar = function (mondayFirst, dateStr, onSelected, onClose, dateFormat) { // member variables this.activeDiv = null; this.currentDateEl = null; this.checkDisabled = null; this.timeout = null; this.onSelected = onSelected || null; this.onClose = onClose || null; this.dragging = false; this.hidden = false; this.minYear = 1970; this.maxYear = 2050; this.dateFormat = dateFormat; this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"]; this.isPopup = true; this.weekNumbers = true; this.mondayFirst = mondayFirst; this.dateStr = dateStr; this.ar_days = null; // HTML elements this.table = null; this.element = null; this.tbody = null; this.firstdayname = null; // Combo boxes this.monthsCombo = null; this.yearsCombo = null; this.hilitedMonth = null; this.activeMonth = null; this.hilitedYear = null; this.activeYear = null; // Information this.dateClicked = false; // one-time initializations if (!Calendar._DN3) { // table of short day names var ar = new Array(); for (var i = 8; i > 0;) { ar[--i] = Calendar._DN[i].substr(0, 3); } Calendar._DN3 = ar; // table of short month names ar = new Array(); for (var i = 12; i > 0;) { ar[--i] = Calendar._MN[i].substr(0, 3); } Calendar._MN3 = ar; } }; // ** constants /// "static", needed for event handlers. Calendar._C = null; /// detect a special case of "web browser" Calendar.is_ie = ( /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) ); // short day names array (initialized at first constructor call) Calendar._DN3 = null; // short month names array (initialized at first constructor call) Calendar._MN3 = null; // BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate // library, at some point. Calendar.getAbsolutePos = function(el) { var r = { x: el.offsetLeft, y: el.offsetTop }; if (el.offsetParent) { var tmp = Calendar.getAbsolutePos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; Calendar.isRelated = function (el, evt) { var related = evt.relatedTarget; if (!related) { var type = evt.type; if (type == "mouseover") { related = evt.fromElement; } else if (type == "mouseout") { related = evt.toElement; } } while (related) { if (related == el) { return true; } related = related.parentNode; } return false; }; Calendar.removeClass = function(el, className) { if (!(el && el.className)) { return; } var cls = el.className.split(" "); var ar = new Array(); for (var i = cls.length; i > 0;) { if (cls[--i] != className) { ar[ar.length] = cls[i]; } } el.className = ar.join(" "); }; Calendar.addClass = function(el, className) { Calendar.removeClass(el, className); el.className += " " + className; }; Calendar.getElement = function(ev) { if (Calendar.is_ie) { return window.event.srcElement; } else { return ev.currentTarget; } }; Calendar.getTargetElement = function(ev) { if (Calendar.is_ie) { return window.event.srcElement; } else { return ev.target; } }; Calendar.stopEvent = function(ev) { if (Calendar.is_ie) { window.event.cancelBubble = true; window.event.returnValue = false; } else { ev.preventDefault(); ev.stopPropagation(); } return false; }; Calendar.addEvent = function(el, evname, func) { if (el.attachEvent) { // IE el.attachEvent("on" + evname, func); } else if (el.addEventListener) { // Gecko / W3C el.addEventListener(evname, func, true); } else { // Opera (or old browsers) el["on" + evname] = func; } }; Calendar.removeEvent = function(el, evname, func) { if (el.detachEvent) { // IE el.detachEvent("on" + evname, func); } else if (el.removeEventListener) { // Gecko / W3C el.removeEventListener(evname, func, true); } else { // Opera (or old browsers) el["on" + evname] = null; } }; Calendar.createElement = function(type, parent) { var el = null; if (document.createElementNS) { // use the XHTML namespace; IE won't normally get here unless // _they_ "fix" the DOM2 implementation. el = document.createElementNS("http://www.w3.org/1999/xhtml", type); } else { el = document.createElement(type); } if (typeof parent != "undefined") { parent.appendChild(el); } return el; }; // END: UTILITY FUNCTIONS // BEGIN: CALENDAR STATIC FUNCTIONS /** Internal -- adds a set of events to make some element behave like a button. */ Calendar._add_evs = function(el) { with (Calendar) { addEvent(el, "mouseover", dayMouseOver); addEvent(el, "mousedown", dayMouseDown); addEvent(el, "mouseout", dayMouseOut); if (is_ie) { addEvent(el, "dblclick", dayMouseDblClick); el.setAttribute("unselectable", true); } } }; Calendar.findMonth = function(el) { if (typeof el.month != "undefined") { return el; } else if (typeof el.parentNode.month != "undefined") { return el.parentNode; } return null; }; Calendar.findYear = function(el) { if (typeof el.year != "undefined") { return el; } else if (typeof el.parentNode.year != "undefined") { return el.parentNode; } return null; }; Calendar.showMonthsCombo = function () { var cal = Calendar._C; if (!cal) { return false; } var cal = cal; var cd = cal.activeDiv; var mc = cal.monthsCombo; if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } if (cal.activeMonth) { Calendar.removeClass(cal.activeMonth, "active"); } var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()]; Calendar.addClass(mon, "active"); cal.activeMonth = mon; mc.style.left = cd.offsetLeft + "px"; mc.style.top = (cd.offsetTop + cd.offsetHeight) + "px"; mc.style.display = "block"; }; Calendar.showYearsCombo = function (fwd) { var cal = Calendar._C; if (!cal) { return false; } var cal = cal; var cd = cal.activeDiv; var yc = cal.yearsCombo; if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } if (cal.activeYear) { Calendar.removeClass(cal.activeYear, "active"); } cal.activeYear = null; var Y = cal.date.getFullYear() + (fwd ? 1 : -1); var yr = yc.firstChild; var show = false; for (var i = 12; i > 0; --i) { if (Y >= cal.minYear && Y <= cal.maxYear) { yr.firstChild.data = Y; yr.year = Y; yr.style.display = "block"; show = true; } else { yr.style.display = "none"; } yr = yr.nextSibling; Y += fwd ? 2 : -2; } if (show) { yc.style.left = cd.offsetLeft + "px"; yc.style.top = (cd.offsetTop + cd.offsetHeight) + "px"; yc.style.display = "block"; } }; // event handlers Calendar.tableMouseUp = function(ev) { var cal = Calendar._C; if (!cal) { return false; } if (cal.timeout) { clearTimeout(cal.timeout); } var el = cal.activeDiv; if (!el) { return false; } var target = Calendar.getTargetElement(ev); Calendar.removeClass(el, "active"); if (target == el || target.parentNode == el) { Calendar.cellClick(el); } var mon = Calendar.findMonth(target); var date = null; if (mon) { date = new Date(cal.date); if (mon.month != date.getMonth()) { date.setMonth(mon.month); cal.setDate(date); cal.dateClicked = false; cal.callHandler(); } } else { var year = Calendar.findYear(target); if (year) { date = new Date(cal.date); if (year.year != date.getFullYear()) { date.setFullYear(year.year); cal.setDate(date); cal.dateClicked = false; cal.callHandler(); } } } with (Calendar) { removeEvent(document, "mouseup", tableMouseUp); removeEvent(document, "mouseover", tableMouseOver); removeEvent(document, "mousemove", tableMouseOver); cal._hideCombos(); _C = null; return stopEvent(ev); } }; Calendar.tableMouseOver = function (ev) { var cal = Calendar._C; if (!cal) { return; } var el = cal.activeDiv; var target = Calendar.getTargetElement(ev); if (target == el || target.parentNode == el) { Calendar.addClass(el, "hilite active"); Calendar.addClass(el.parentNode, "rowhilite"); } else { Calendar.removeClass(el, "active"); Calendar.removeClass(el, "hilite"); Calendar.removeClass(el.parentNode, "rowhilite"); } var mon = Calendar.findMonth(target); if (mon) { if (mon.month != cal.date.getMonth()) { if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } Calendar.addClass(mon, "hilite"); cal.hilitedMonth = mon; } else if (cal.hilitedMonth) { Calendar.removeClass(cal.hilitedMonth, "hilite"); } } else { var year = Calendar.findYear(target); if (year) { if (year.year != cal.date.getFullYear()) { if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } Calendar.addClass(year, "hilite"); cal.hilitedYear = year; } else if (cal.hilitedYear) { Calendar.removeClass(cal.hilitedYear, "hilite"); } } } return Calendar.stopEvent(ev); }; Calendar.tableMouseDown = function (ev) { if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) { return Calendar.stopEvent(ev); } }; Calendar.calDragIt = function (ev) { var cal = Calendar._C; if (!(cal && cal.dragging)) { return false; } var posX; var posY; if (Calendar.is_ie) { posY = window.event.clientY + document.body.scrollTop; posX = window.event.clientX + document.body.scrollLeft; } else { posX = ev.pageX; posY = ev.pageY; } cal.hideShowCovered(); var st = cal.element.style; st.left = (posX - cal.xOffs) + "px"; st.top = (posY - cal.yOffs) + "px"; return Calendar.stopEvent(ev); }; Calendar.calDragEnd = function (ev) { var cal = Calendar._C; if (!cal) { return false; } cal.dragging = false; with (Calendar) { removeEvent(document, "mousemove", calDragIt); removeEvent(document, "mouseover", stopEvent); removeEvent(document, "mouseup", calDragEnd); tableMouseUp(ev); } cal.hideShowCovered(); }; Calendar.dayMouseDown = function(ev) { var el = Calendar.getElement(ev); if (el.disabled) { return false; } var cal = el.calendar; cal.activeDiv = el; Calendar._C = cal; if (el.navtype != 300) with (Calendar) { addClass(el, "hilite active"); addEvent(document, "mouseover", tableMouseOver); addEvent(document, "mousemove", tableMouseOver); addEvent(document, "mouseup", tableMouseUp); } else if (cal.isPopup) { cal._dragStart(ev); } if (el.navtype == -1 || el.navtype == 1) { cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250); } else if (el.navtype == -2 || el.navtype == 2) { cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250); } else { cal.timeout = null; } return Calendar.stopEvent(ev); }; Calendar.dayMouseDblClick = function(ev) { Calendar.cellClick(Calendar.getElement(ev)); if (Calendar.is_ie) { document.selection.empty(); } }; Calendar.dayMouseOver = function(ev) { var el = Calendar.getElement(ev); if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) { return false; } if (el.ttip) { if (el.ttip.substr(0, 1) == "_") { var date = null; with (el.calendar.date) { date = new Date(getFullYear(), getMonth(), el.caldate); } el.ttip = date.print(el.calendar.ttDateFormat) + el.ttip.substr(1); } el.calendar.tooltips.firstChild.data = el.ttip; } if (el.navtype != 300) { Calendar.addClass(el, "hilite"); if (el.caldate) { Calendar.addClass(el.parentNode, "rowhilite"); } } return Calendar.stopEvent(ev); }; Calendar.dayMouseOut = function(ev) { with (Calendar) { var el = getElement(ev); if (isRelated(el, ev) || _C || el.disabled) { return false; } removeClass(el, "hilite"); if (el.caldate) { removeClass(el.parentNode, "rowhilite"); } el.calendar.tooltips.firstChild.data = _TT["SEL_DATE"]; return stopEvent(ev); } }; /** * A generic "click" handler :) handles all types of buttons defined in this * calendar. */ Calendar.cellClick = function(el) { var cal = el.calendar; var closing = false; var newdate = false; var date = null; if (typeof el.navtype == "undefined") { Calendar.removeClass(cal.currentDateEl, "selected"); Calendar.addClass(el, "selected"); closing = (cal.currentDateEl == el); if (!closing) { cal.currentDateEl = el; } cal.date.setDate(el.caldate); date = cal.date; newdate = true; // a date was clicked cal.dateClicked = true; } else { if (el.navtype == 200) { Calendar.removeClass(el, "hilite"); cal.callCloseHandler(); return; } date = (el.navtype == 0) ? new Date() : new Date(cal.date); // unless "today" was clicked, we assume no date was clicked so // the selected handler will know not to close the calenar when // in single-click mode. cal.dateClicked = (el.navtype == 0); var year = date.getFullYear(); var mon = date.getMonth(); function setMonth(m) { var day = date.getDate(); var max = date.getMonthDays(m); if (day > max) { date.setDate(max); } date.setMonth(m); }; switch (el.navtype) { case -2: if (year > cal.minYear) { date.setFullYear(year - 1); } break; case -1: if (mon > 0) { setMonth(mon - 1); } else if (year-- > cal.minYear) { date.setFullYear(year); setMonth(11); } break; case 1: if (mon < 11) { setMonth(mon + 1); } else if (year < cal.maxYear) { date.setFullYear(year + 1); setMonth(0); } break; case 2: if (year < cal.maxYear) { date.setFullYear(year + 1); } break; case 100: cal.setMondayFirst(!cal.mondayFirst); return; case 0: // TODAY will bring us here if ((typeof cal.checkDisabled == "function") && cal.checkDisabled(date)) { // remember, "date" was previously set to new // Date() if TODAY was clicked; thus, it // contains today date. return false; } break; } if (!date.equalsTo(cal.date)) { cal.setDate(date); newdate = true; } } if (newdate) { cal.callHandler(); } if (closing) { Calendar.removeClass(el, "hilite"); cal.callCloseHandler(); } }; // END: CALENDAR STATIC FUNCTIONS // BEGIN: CALENDAR OBJECT FUNCTIONS /** * This function creates the calendar inside the given parent. If _par is * null than it creates a popup calendar inside the BODY element. If _par is * an element, be it BODY, then it creates a non-popup calendar (still * hidden). Some properties need to be set before calling this function. */ Calendar.prototype.create = function (_par) { var parent = null; if (! _par) { // default parent is the document body, in which case we create // a popup calendar. parent = document.getElementsByTagName("body")[0]; this.isPopup = true; } else { parent = _par; this.isPopup = false; } this.date = this.dateStr ? new Date(this.dateStr) : new Date(); var table = Calendar.createElement("table"); this.table = table; table.cellSpacing = 0; table.cellPadding = 0; table.calendar = this; Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown); var div = Calendar.createElement("div"); this.element = div; div.className = "calendar"; if (this.isPopup) { div.style.position = "absolute"; div.style.display = "none"; } div.appendChild(table); var thead = Calendar.createElement("thead", table); var cell = null; var row = null; var cal = this; var hh = function (text, cs, navtype) { cell = Calendar.createElement("td", row); cell.colSpan = cs; cell.className = "button"; Calendar._add_evs(cell); cell.calendar = cal; cell.navtype = navtype; if (text.substr(0, 1) != "&") { cell.appendChild(document.createTextNode(text)); } else { // FIXME: dirty hack for entities cell.innerHTML = text; } return cell; }; row = Calendar.createElement("tr", thead); var title_length = 6; (this.isPopup) && --title_length; (this.weekNumbers) && ++title_length; hh("-", 1, 100).ttip = Calendar._TT["TOGGLE"]; this.title = hh("", title_length, 300); this.title.className = "title"; if (this.isPopup) { this.title.ttip = Calendar._TT["DRAG_TO_MOVE"]; this.title.style.cursor = "move"; hh("×", 1, 200).ttip = Calendar._TT["CLOSE"]; } row = Calendar.createElement("tr", thead); row.className = "headrow"; this._nav_py = hh("«", 1, -2); this._nav_py.ttip = Calendar._TT["PREV_YEAR"]; this._nav_pm = hh("‹", 1, -1); this._nav_pm.ttip = Calendar._TT["PREV_MONTH"]; this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0); this._nav_now.ttip = Calendar._TT["GO_TODAY"]; this._nav_nm = hh("›", 1, 1); this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"]; this._nav_ny = hh("»", 1, 2); this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"]; // day names row = Calendar.createElement("tr", thead); row.className = "daynames"; if (this.weekNumbers) { cell = Calendar.createElement("td", row); cell.className = "name wn"; cell.appendChild(document.createTextNode(Calendar._TT["WK"])); } for (var i = 7; i > 0; --i) { cell = Calendar.createElement("td", row); cell.appendChild(document.createTextNode("")); if (!i) { cell.navtype = 100; cell.calendar = this; Calendar._add_evs(cell); } } this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild; this._displayWeekdays(); var tbody = Calendar.createElement("tbody", table); this.tbody = tbody; for (i = 6; i > 0; --i) { row = Calendar.createElement("tr", tbody); if (this.weekNumbers) { cell = Calendar.createElement("td", row); cell.appendChild(document.createTextNode("")); } for (var j = 7; j > 0; --j) { cell = Calendar.createElement("td", row); cell.appendChild(document.createTextNode("")); cell.calendar = this; Calendar._add_evs(cell); } } var tfoot = Calendar.createElement("tfoot", table); row = Calendar.createElement("tr", tfoot); row.className = "footrow"; cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300); cell.className = "ttip"; if (this.isPopup) { cell.ttip = Calendar._TT["DRAG_TO_MOVE"]; cell.style.cursor = "move"; } this.tooltips = cell; div = Calendar.createElement("div", this.element); this.monthsCombo = div; div.className = "combo"; for (i = 0; i < Calendar._MN.length; ++i) { var mn = Calendar.createElement("div"); mn.className = "label"; mn.month = i; mn.appendChild(document.createTextNode(Calendar._MN3[i])); div.appendChild(mn); } div = Calendar.createElement("div", this.element); this.yearsCombo = div; div.className = "combo"; for (i = 12; i > 0; --i) { var yr = Calendar.createElement("div"); yr.className = "label"; yr.appendChild(document.createTextNode("")); div.appendChild(yr); } this._init(this.mondayFirst, this.date); parent.appendChild(this.element); }; /** keyboard navigation, only for popup calendars */ Calendar._keyEvent = function(ev) { if (!window.calendar) { return false; } (Calendar.is_ie) && (ev = window.event); var cal = window.calendar; var act = (Calendar.is_ie || ev.type == "keypress"); if (ev.ctrlKey) { switch (ev.keyCode) { case 37: // KEY left act && Calendar.cellClick(cal._nav_pm); break; case 38: // KEY up act && Calendar.cellClick(cal._nav_py); break; case 39: // KEY right act && Calendar.cellClick(cal._nav_nm); break; case 40: // KEY down act && Calendar.cellClick(cal._nav_ny); break; default: return false; } } else switch (ev.keyCode) { case 32: // KEY space (now) Calendar.cellClick(cal._nav_now); break; case 27: // KEY esc act && cal.hide(); break; case 37: // KEY left case 38: // KEY up case 39: // KEY right case 40: // KEY down if (act) { var date = cal.date.getDate() - 1; var el = cal.currentDateEl; var ne = null; var prev = (ev.keyCode == 37) || (ev.keyCode == 38); switch (ev.keyCode) { case 37: // KEY left (--date >= 0) && (ne = cal.ar_days[date]); break; case 38: // KEY up date -= 7; (date >= 0) && (ne = cal.ar_days[date]); break; case 39: // KEY right (++date < cal.ar_days.length) && (ne = cal.ar_days[date]); break; case 40: // KEY down date += 7; (date < cal.ar_days.length) && (ne = cal.ar_days[date]); break; } if (!ne) { if (prev) { Calendar.cellClick(cal._nav_pm); } else { Calendar.cellClick(cal._nav_nm); } date = (prev) ? cal.date.getMonthDays() : 1; el = cal.currentDateEl; ne = cal.ar_days[date - 1]; } Calendar.removeClass(el, "selected"); Calendar.addClass(ne, "selected"); cal.date.setDate(ne.caldate); cal.callHandler(); cal.currentDateEl = ne; } break; case 13: // KEY enter if (act) { cal.callHandler(); cal.hide(); } break; default: return false; } return Calendar.stopEvent(ev); }; /** * (RE)Initializes the calendar to the given date and style (if mondayFirst is * true it makes Monday the first day of week, otherwise the weeks start on * Sunday. */ Calendar.prototype._init = function (mondayFirst, date) { var today = new Date(); var year = date.getFullYear(); if (year < this.minYear) { year = this.minYear; date.setFullYear(year); } else if (year > this.maxYear) { year = this.maxYear; date.setFullYear(year); } this.mondayFirst = mondayFirst; this.date = new Date(date); var month = date.getMonth(); var mday = date.getDate(); var no_days = date.getMonthDays(); date.setDate(1); var wday = date.getDay(); var MON = mondayFirst ? 1 : 0; var SAT = mondayFirst ? 5 : 6; var SUN = mondayFirst ? 6 : 0; if (mondayFirst) { wday = (wday > 0) ? (wday - 1) : 6; } var iday = 1; var row = this.tbody.firstChild; var MN = Calendar._MN3[month]; var hasToday = ((today.getFullYear() == year) && (today.getMonth() == month)); var todayDate = today.getDate(); var week_number = date.getWeekNumber(); var ar_days = new Array(); for (var i = 0; i < 6; ++i) { if (iday > no_days) { row.className = "emptyrow"; row = row.nextSibling; continue; } var cell = row.firstChild; if (this.weekNumbers) { cell.className = "day wn"; cell.firstChild.data = week_number; cell = cell.nextSibling; } ++week_number; row.className = "daysrow"; for (var j = 0; j < 7; ++j) { cell.className = "day"; if ((!i && j < wday) || iday > no_days) { // cell.className = "emptycell"; cell.innerHTML = " "; cell.disabled = true; cell = cell.nextSibling; continue; } cell.disabled = false; cell.firstChild.data = iday; if (typeof this.checkDisabled == "function") { date.setDate(iday); if (this.checkDisabled(date)) { cell.className += " disabled"; cell.disabled = true; } } if (!cell.disabled) { ar_days[ar_days.length] = cell; cell.caldate = iday; cell.ttip = "_"; if (iday == mday) { cell.className += " selected"; this.currentDateEl = cell; } if (hasToday && (iday == todayDate)) { cell.className += " today"; cell.ttip += Calendar._TT["PART_TODAY"]; } if (wday == SAT || wday == SUN) { cell.className += " weekend"; } } ++iday; ((++wday) ^ 7) || (wday = 0); cell = cell.nextSibling; } row = row.nextSibling; } this.ar_days = ar_days; this.title.firstChild.data = Calendar._MN[month] + ", " + year; this._hideCombos(); // PROFILE // this.tooltips.firstChild.data = "Generated in " + ((new Date()) - today) + " ms"; }; /** * Calls _init function above for going to a certain date (but only if the * date is different than the currently selected one). */ Calendar.prototype.setDate = function (date) { if (!date.equalsTo(this.date)) { this._init(this.mondayFirst, date); } }; /** * Refreshes the calendar. Useful if the "disabledHandler" function is * dynamic, meaning that the list of disabled date can change at runtime. * Just * call this function if you think that the list of disabled dates * should * change. */ Calendar.prototype.refresh = function () { this._init(this.mondayFirst, this.date); }; /** Modifies the "mondayFirst" parameter (EU/US style). */ Calendar.prototype.setMondayFirst = function (mondayFirst) { this._init(mondayFirst, this.date); this._displayWeekdays(); }; /** * Allows customization of what dates are enabled. The "unaryFunction" * parameter must be a function object that receives the date (as a JS Date * object) and returns a boolean value. If the returned value is true then * the passed date will be marked as disabled. */ Calendar.prototype.setDisabledHandler = function (unaryFunction) { this.checkDisabled = unaryFunction; }; /** Customization of allowed year range for the calendar. */ Calendar.prototype.setRange = function (a, z) { this.minYear = a; this.maxYear = z; }; /** Calls the first user handler (selectedHandler). */ Calendar.prototype.callHandler = function () { if (this.onSelected) { this.onSelected(this, this.date.print(this.dateFormat)); } }; /** Calls the second user handler (closeHandler). */ Calendar.prototype.callCloseHandler = function () { if (this.onClose) { this.onClose(this); } this.hideShowCovered(); }; /** Removes the calendar object from the DOM tree and destroys it. */ Calendar.prototype.destroy = function () { var el = this.element.parentNode; el.removeChild(this.element); Calendar._C = null; }; /** * Moves the calendar element to a different section in the DOM tree (changes * its parent). */ Calendar.prototype.reparent = function (new_parent) { var el = this.element; el.parentNode.removeChild(el); new_parent.appendChild(el); }; // This gets called when the user presses a mouse button anywhere in the // document, if the calendar is shown. If the click was outside the open // calendar this function closes it. Calendar._checkCalendar = function(ev) { if (!window.calendar) { return false; } var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev); for (; el != null && el != calendar.element; el = el.parentNode); if (el == null) { // calls closeHandler which should hide the calendar. window.calendar.callCloseHandler(); return Calendar.stopEvent(ev); } }; /** Shows the calendar. */ Calendar.prototype.show = function () { var rows = this.table.getElementsByTagName("tr"); for (var i = rows.length; i > 0;) { var row = rows[--i]; Calendar.removeClass(row, "rowhilite"); var cells = row.getElementsByTagName("td"); for (var j = cells.length; j > 0;) { var cell = cells[--j]; Calendar.removeClass(cell, "hilite"); Calendar.removeClass(cell, "active"); } } this.element.style.display = "block"; this.hidden = false; if (this.isPopup) { window.calendar = this; Calendar.addEvent(document, "keydown", Calendar._keyEvent); Calendar.addEvent(document, "keypress", Calendar._keyEvent); Calendar.addEvent(document, "mousedown", Calendar._checkCalendar); } this.hideShowCovered(); }; /** * Hides the calendar. Also removes any "hilite" from the class of any TD * element. */ Calendar.prototype.hide = function () { if (this.isPopup) { Calendar.removeEvent(document, "keydown", Calendar._keyEvent); Calendar.removeEvent(document, "keypress", Calendar._keyEvent); Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar); } this.element.style.display = "none"; this.hidden = true; this.hideShowCovered(); }; /** * Shows the calendar at a given absolute position (beware that, depending on * the calendar element style -- position property -- this might be relative * to the parent's containing rectangle). */ Calendar.prototype.showAt = function (x, y) { var s = this.element.style; s.left = x + "px"; s.top = y + "px"; this.show(); }; /** Shows the calendar near a given element. */ Calendar.prototype.showAtElement = function (el, opts) { var p = Calendar.getAbsolutePos(el); if (!opts || typeof opts != "string") { this.showAt(p.x, p.y + el.offsetHeight); return true; } this.show(); var w = this.element.offsetWidth; var h = this.element.offsetHeight; this.hide(); var valign = opts.substr(0, 1); var halign = "l"; if (opts.length > 1) { halign = opts.substr(1, 1); } // vertical alignment switch (valign) { case "T": p.y -= h; break; case "B": p.y += el.offsetHeight; break; case "C": p.y += (el.offsetHeight - h) / 2; break; case "t": p.y += el.offsetHeight - h; break; case "b": break; // already there } // horizontal alignment switch (halign) { case "L": p.x -= w; break; case "R": p.x += el.offsetWidth; break; case "C": p.x += (el.offsetWidth - w) / 2; break; case "r": p.x += el.offsetWidth - w; break; case "l": break; // already there } this.showAt(p.x, p.y); }; /** Customizes the date format. */ Calendar.prototype.setDateFormat = function (str) { this.dateFormat = str; }; /** Customizes the tooltip date format. */ Calendar.prototype.setTtDateFormat = function (str) { this.ttDateFormat = str; }; /** * Tries to identify the date represented in a string. If successful it also * calls this.setDate which moves the calendar to the given date. */ Calendar.prototype.parseDate = function (str, fmt) { var y = 0; var m = -1; var d = 0; var a = str.split(/\W+/); if (!fmt) { fmt = this.dateFormat; } else { this.dateFormat = fmt; } var b = fmt.split(/\W+/); var i = 0, j = 0; for (i = 0; i < a.length; ++i) { if (b[i] == "D" || b[i] == "DD") { continue; } if (b[i] == "d" || b[i] == "dd") { d = parseInt(a[i], 10); } if (b[i] == "m" || b[i] == "mm") { m = parseInt(a[i], 10) - 1; } if ((b[i] == "y") || (b[i] == "yy") || (b[i] == "yyyy")) { y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); } if (b[i] == "M" || b[i] == "MM") { for (j = 0; j < 12; ++j) { if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } } } } if (y != 0 && m != -1 && d != 0) { this.setDate(new Date(y, m, d)); return; } y = 0; m = -1; d = 0; for (i = 0; i < a.length; ++i) { if (a[i].search(/[a-zA-Z]+/) != -1) { var t = -1; for (j = 0; j < 12; ++j) { if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } } if (t != -1) { if (m != -1) { d = m+1; } m = t; } } else if (parseInt(a[i], 10) <= 12 && m == -1) { m = a[i]-1; } else if (parseInt(a[i], 10) > 31 && y == 0) { y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); } else if (d == 0) { d = a[i]; } } if (y == 0) { var today = new Date(); y = today.getFullYear(); } if (m != -1 && d != 0) { this.setDate(new Date(y, m, d)); } }; Calendar.prototype.hideShowCovered = function () { function getStyleProp(obj, style){ var value = obj.style[style]; if (!value) { if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C value = document.defaultView. getComputedStyle(obj, "").getPropertyValue(style); } else if (obj.currentStyle) { // IE value = obj.currentStyle[style]; } else { value = obj.style[style]; } } return value; }; var tags = new Array("applet", "iframe", "select"); var el = this.element; var p = Calendar.getAbsolutePos(el); var EX1 = p.x; var EX2 = el.offsetWidth + EX1; var EY1 = p.y; var EY2 = el.offsetHeight + EY1; for (var k = tags.length; k > 0; ) { var ar = document.getElementsByTagName(tags[--k]); var cc = null; for (var i = ar.length; i > 0;) { cc = ar[--i]; p = Calendar.getAbsolutePos(cc); var CX1 = p.x; var CX2 = cc.offsetWidth + CX1; var CY1 = p.y; var CY2 = cc.offsetHeight + CY1; if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) { if (!cc.__msh_save_visibility) { cc.__msh_save_visibility = getStyleProp(cc, "visibility"); } cc.style.visibility = cc.__msh_save_visibility; } else { if (!cc.__msh_save_visibility) { cc.__msh_save_visibility = getStyleProp(cc, "visibility"); } cc.style.visibility = "hidden"; } } } }; /** Internal function; it displays the bar with the names of the weekday. */ Calendar.prototype._displayWeekdays = function () { var MON = this.mondayFirst ? 0 : 1; var SUN = this.mondayFirst ? 6 : 0; var SAT = this.mondayFirst ? 5 : 6; var cell = this.firstdayname; for (var i = 0; i < 7; ++i) { cell.className = "day name"; if (!i) { cell.ttip = this.mondayFirst ? Calendar._TT["SUN_FIRST"] : Calendar._TT["MON_FIRST"]; cell.navtype = 100; cell.calendar = this; Calendar._add_evs(cell); } if (i == SUN || i == SAT) { Calendar.addClass(cell, "weekend"); } cell.firstChild.data = Calendar._DN3[i + 1 - MON]; cell = cell.nextSibling; } }; /** Internal function. Hides all combo boxes that might be displayed. */ Calendar.prototype._hideCombos = function () { this.monthsCombo.style.display = "none"; this.yearsCombo.style.display = "none"; }; /** Internal function. Starts dragging the element. */ Calendar.prototype._dragStart = function (ev) { if (this.dragging) { return; } this.dragging = true; var posX; var posY; if (Calendar.is_ie) { posY = window.event.clientY + document.body.scrollTop; posX = window.event.clientX + document.body.scrollLeft; } else { posY = ev.clientY + window.scrollY; posX = ev.clientX + window.scrollX; } var st = this.element.style; this.xOffs = posX - parseInt(st.left); this.yOffs = posY - parseInt(st.top); with (Calendar) { addEvent(document, "mousemove", calDragIt); addEvent(document, "mouseover", stopEvent); addEvent(document, "mouseup", calDragEnd); } }; // BEGIN: DATE OBJECT PATCHES /** Adds the number of days array to the Date object. */ Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31); /** Constants used for time computations */ Date.SECOND = 1000 /* milliseconds */; Date.MINUTE = 60 * Date.SECOND; Date.HOUR = 60 * Date.MINUTE; Date.DAY = 24 * Date.HOUR; Date.WEEK = 7 * Date.DAY; /** Returns the number of days in the current month */ Date.prototype.getMonthDays = function(month) { var year = this.getFullYear(); if (typeof month == "undefined") { month = this.getMonth(); } if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { return 29; } else { return Date._MD[month]; } }; /** Returns the number of the week. The algorithm was "stolen" from PPK's * website, hope it's correct :) http://www.xs4all.nl/~ppk/js/week.html */ Date.prototype.getWeekNumber = function() { var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); var then = new Date(this.getFullYear(), 0, 1, 0, 0, 0); var time = now - then; var day = then.getDay(); (day > 3) && (day -= 4) || (day += 3); return Math.round(((time / Date.DAY) + day) / 7); }; /** Checks dates equality (ignores time) */ Date.prototype.equalsTo = function(date) { return ((this.getFullYear() == date.getFullYear()) && (this.getMonth() == date.getMonth()) && (this.getDate() == date.getDate())); }; /** Prints the date in a string according to the given format. */ Date.prototype.print = function (frm) { var str = new String(frm); var m = this.getMonth(); var d = this.getDate(); var y = this.getFullYear(); var wn = this.getWeekNumber(); var w = this.getDay(); var s = new Array(); s["d"] = d; s["dd"] = (d < 10) ? ("0" + d) : d; s["m"] = 1+m; s["mm"] = (m < 9) ? ("0" + (1+m)) : (1+m); s["y"] = y; s["yy"] = new String(y).substr(2, 2); s["yyyy"] = y; s["w"] = wn; s["ww"] = (wn < 10) ? ("0" + wn) : wn; with (Calendar) { s["D"] = _DN3[w]; s["DD"] = _DN[w]; s["M"] = _MN3[m]; s["MM"] = _MN[m]; } var re = /(.*)(\W|^)(d|dd|m|mm|y|yy|yyyy|MM|M|DD|D|w|ww)(\W|$)(.*)/; while (re.exec(str) != null) { str = RegExp.$1 + RegExp.$2 + s[RegExp.$3] + RegExp.$4 + RegExp.$5; } return str; }; // END: DATE OBJECT PATCHES // global object that remembers the calendar window.calendar = null; // ** I18N Calendar._DN = new Array ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"); Calendar._MN = new Array ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"); // tooltips Calendar._TT = {}; Calendar._TT["TOGGLE"] = "Toggle first day of week"; Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)"; Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)"; Calendar._TT["GO_TODAY"] = "Go Today"; Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)"; Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)"; Calendar._TT["SEL_DATE"] = "Select date"; Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; Calendar._TT["PART_TODAY"] = " (today)"; Calendar._TT["MON_FIRST"] = "Display Monday first"; Calendar._TT["SUN_FIRST"] = "Display Sunday first"; Calendar._TT["CLOSE"] = "Close"; Calendar._TT["TODAY"] = "Today"; // date formats Calendar._TT["TT_DATE_FORMAT"] = "D, M d"; Calendar._TT["WK"] = "wk"; var calendar = null; // remember the calendar object so that we reuse // it and avoid creating another // This function gets called when an end-user clicks on some date function selected(cal, date) { cal.sel.value = date; // just update the value of the input field } // And this gets called when the end-user clicks on the _selected_ date, // or clicks the "Close" (X) button. It just hides the calendar without // destroying it. function closeHandler(cal) { cal.hide(); // hide the calendar // don't check mousedown on document anymore (used to be able to hide the // calendar when someone clicks outside it, see the showCalendar function). Calendar.removeEvent(document, "mousedown", checkCalendar); } // This gets called when the user presses a mouse button anywhere in the // document, if the calendar is shown. If the click was outside the open // calendar this function closes it. function checkCalendar(ev) { var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev); for (; el != null; el = el.parentNode) // FIXME: allow end-user to click some link without closing the // calendar. Good to see real-time stylesheet change :) if (el == calendar.element || el.tagName == "A") break; if (el == null) { // calls closeHandler which should hide the calendar. calendar.callCloseHandler(); Calendar.stopEvent(ev); } } // This function shows the calendar under the element having the given id. // It takes care of catching "mousedown" signals on document and hiding the // calendar if the click was outside. // The format specifies how the date is going to be returned. You can combine // the letters y, m, d, D or M in any way you want with any separator that // you want (e.g. "," or "-" or ".") // The letter D will return the name of the day (e.g Fri, Mon, etc.) and // M will return the name of the month (e.g Oct, Spt, Jan, etc.) function showCalendar(id,dateformat) { var el = document.getElementById(id); if (calendar != null) { // we already have one created, so just update it. calendar.hide(); // hide the existing calendar calendar.parseDate(el.value, dateformat); // set it to a new date } else { // first-time call, create the calendar if ( dateformat == null ) { var dateformat = 'y-mm-dd'; } var cal = new Calendar(true, null, selected, closeHandler, dateformat); calendar = cal; // remember the calendar in the global cal.setRange(1900, 2070); // min/max year allowed calendar.create(); // create a popup calendar } calendar.sel = el; // inform it about the input field in use calendar.showAtElement(el); // show the calendar next to the input field // catch mousedown on the document Calendar.addEvent(document, "mousedown", checkCalendar); return false; } // same function as above except you can set a defaultdate which // the calendar will go to immediately when when you click on it function showCalendarWithDefault(id,defaultdate,dateformat) { var el = document.getElementById(id); if (calendar != null) { // we already have one created, so just update it. calendar.hide(); // hide the existing calendar calendar.parseDate(el.value, dateformat); // set it to a new date } else { // first-time call, create the calendar if ( dateformat == null ) { var dateformat = 'y-mm-dd'; } var cal = new Calendar(true, defaultdate, selected, closeHandler, dateformat); calendar = cal; // remember the calendar in the global cal.setRange(1900, 2070); // min/max year allowed calendar.create(); // create a popup calendar } calendar.sel = el; // inform it about the input field in use calendar.showAtElement(el); // show the calendar next to the input field // catch mousedown on the document Calendar.addEvent(document, "mousedown", checkCalendar); return false; } // same function as above but instead of a text box we use the date widget function showCalendarWithDateWidget(id,fmt) { var idM = document.getElementById(id+'.month'); var idD = document.getElementById(id+'.day'); var idY = document.getElementById(id+'.year'); var calval = idY.value+'-'+idM.value+'-'+idD.value; if (calendar != null) { // we already have one created, so just update it. calendar.hide(); // hide the existing calendar calendar.parseDate(calval,fmt); // set it to a new date } else { // first-time call, create the calendar var cal = new Calendar(true, null, selectwidget, closeHandler); calendar = cal; // remember the calendar in the global cal.setRange(1900, 2050); // min/max year allowed calendar.create(); // create a popup calendar calendar.parseDate(calval,fmt); // set it to a new date } calendar.selM = idM; // inform it about the input field in use calendar.selD = idD; // inform it about the input field in use calendar.selY = idY; // inform it about the input field in use calendar.showAtElement(idM); // show the calendar next to the input field // catch mousedown on the document Calendar.addEvent(document, "mousedown", checkCalendar); return false; } // This function gets called when an end-user clicks on some date function selectwidget(cal, date) { var y = 0; var m = -1; var d = 0; var a = date.split(/\W+/); var fmt = cal.dateFormat; var b = fmt.split(/\W+/); var i = 0, j = 0; for (i = 0; i < a.length; ++i) { if (b[i] == "D" || b[i] == "DD") { continue; } if (b[i] == "d" || b[i] == "dd") { d = parseInt(a[i], 10); } if (b[i] == "m" || b[i] == "mm") { m = parseInt(a[i], 10) - 1; } if ((b[i] == "y") || (b[i] == "yy") || (b[i] == "yyyy")) { y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); } if (b[i] == "M" || b[i] == "MM") { for (j = 0; j < 12; ++j) { if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } } } } if (y != 0 && m != -1 && d != 0) { m = m + 1; cal.selM.value = m; cal.selY.value = y; cal.selD.value = d; return; } } // ******************** openacs-5.7.0/packages/acs-subsite/www/resources/xml.gif0000644000175000017500000000065510171476746023143 0ustar frankiefrankieGIF89a$ÕÕXñÔÀá]ÿöðÿrà§‚÷éàå^ôdíɱðcúôïßžrÿ«s÷àÐÐr3罡ÿãÑŸAÿæÕå„Cÿ…4ÿÚÁÎUÍg#ÿíá糑諂Ôaðläw.Ýn$ðÁ¡ø×Áÿ|$æ{3ó¡ú–Sð®‚!ù²‚ÿѲÿDÿ´‚}3ÿšWÂP?ÿȤÿÿÿÿf!ù,$ÊÀ lH,È£§%k:ŸÐ¨4ÊbN¯XªµÙˆ 2U,BXÅb•&ìŽY¦Uh(– db‹9AÎ1.bRqO" 11 .fŠ+g‚1„†[N%g.2ft$–ƒ…ZQb1Mf g¨˜ªP‡NŒ±1#t.·™«O)g¢Ã.·++*O»2]Ÿ(®²N·€1& NÞ2ÕM..2ôçNõ2 õþù2ÞeHE‹ƒ*\Èpበ;openacs-5.7.0/packages/acs-subsite/www/resources/radio.gif0000644000175000017500000000010607725607455023434 0ustar frankiefrankieGIF89a €¡¦¬ÿÿÿ!ù, Œ y ­V s×N·­M—©nõ·Aù÷ñ¦–bnG¤QíIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/italic-button.gif0000644000175000017500000000014507725607455025117 0ustar frankiefrankieGIF89a‘ÿÿÿôòïfff!ù,6Œ©Ë£œÑK…Åèà ö]¸e"™ª,HŽWÄ(ì¾æ,Ïí)¡}‘ñˆL:–Ì&¢;openacs-5.7.0/packages/acs-subsite/www/resources/down.gif0000644000175000017500000000147710171476746023315 0ustar frankiefrankieGIF89a ÷ÿÿÿ, $H°`*L8p¡Ã‚Œh°¡ÂŠ%bl¸±ãÀ€;openacs-5.7.0/packages/acs-subsite/www/resources/ZoomOut16.gif0000644000175000017500000000046007731544722024116 0ustar frankiefrankieGIF89aÄÿÿÿÿ00a==n}}•„„œ‘‘©žž·˜˜°žž¶¥¥½¸¸ÐÌÌåÅÅÝÌÌ丸ÃááæÔÔÙðð󋌢n= µŠq ÀÀÀ!ù,Wà%ŽdYZ€e–i=–°ŠV$Æ4k-…Ã0X ©¤BÀ;= ‹„AÁØõ&„â°k–ƒi55»à€¥‚*Þ—5P(•y]tÏïùpfƒ%!;!!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/ZoomOut24.gif0000644000175000017500000000073507731544722024122 0ustar frankiefrankieGIF89aÕÿÿÿÿïïòììóë¾¥ààæßßåÞÞøÞÞ÷ÝÝêÚÚçÙÙæÙÌÀ××ñ××ðÓ®•ÐÐéÐÏéÉÉãÉÉâÉÉÕÂÂÛÂÂÎÂÁÛÁÁÛÀÀÌÀ³¦¿‘w»»Ô»ºÔ»Ÿ…º»Ô³™€®®Ç«ƒj§§Á§§À  ¹ Ÿ¹™™²”tZ’“«’’¬’’«‹‹¤„„€fMffff333fÀÀÀ!ù2,@§@™pH,‹±B!ÆlÆH àH=Æ>­NŒ«ÂfE™ÀªDØ$bz@EM7¾^€©ÕY&Á,c(lgh1d„&% "su0––y1 [}U1!/ž¥¦ˆILž1_‹“Ÿ³ƒln¶V‚Œn¾G0»oRzh–Ñ–.®žyÖ21 -§B1'ÝÞ1¤ÞDÍêEA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/right.gif0000644000175000017500000000021007725607455023447 0ustar frankiefrankieGIF89a ³Ì3þüûÛoKí¶¤ñÉ»ä’wÔS(ÑD!ù, 5ÉI)¸8_¤¯Éœ6fE|'0¬®-0ÎxQB/¤Á¦35‚ÁÁÔ霚›Š;openacs-5.7.0/packages/acs-subsite/www/resources/http.png0000644000175000017500000000106410052153356023317 0ustar frankiefrankie‰PNG  IHDR Vu\çgAMAÙܲÚ%tEXtComment$0152: 1*Short:1 $935C: ???? ŒeÌ×tEXtSoftwareGraphicConverter5]Hî•IDATxœbàà‘×åâ×qa ðúkÛví•׉jàÒ°c``bÅ«‘‰MFHʪÎ2pñ+ßÌ /û*èùq È02±ó`ÓÃÄ2\üJ¹N1³TϹý·mñ•_ñuÛ^YúUÏàä“VÂj‹Èi¹÷”O¿òmÞÁÿ+>ùo;ç&¯Œ¿Èë…äÏ=?uÛƒ_Svÿú“3õþ7QE« ÄxDÔŒngFò+·¹OÅôâ9Oþwnþñ¯{û ýþ_XÙÒKšŽåËÍB&ìbdbáG¶€ƒ_ Ã8xâíø¾?+V~ÿÛ°þÛϾݟþ•/~ô×>aÃFqt?ˆ±° DÈ™%l h¸ð#uæ÷©³þýO˜üã¿Yè† ,’ؼÂÁÈÌéd±ðfâ¤÷¿ƒ;¿þñ®{ÿÇÀoåeFf Õ̬|BR:©mý k¹ó?´åÑŸŠ;ÿuÝÞjÀ´[ÆPL5l°’÷!U·ÝÂjîûÜöð‰[MºZ¤ÿÿæŽê3°mIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/Properties16.gif0000644000175000017500000000065107731544722024640 0ustar frankiefrankieGIF89aÕÿÿÿÿÀÀÀÚ×üÛØüÊÈìÎÌðÍËïÌÊîÛÙýÙ×ûÊÈïÇÅêËÉîÖÔù×Õú»ºáÅÄìÇÆíÁÀ濾侽ãÄÃéÃÂçÏÎôÔÓøÒÑöÚÙýÏÏÿ®®Ö²²Ù±±Ø¿¿çÁÁèÃÃêÐÐöŸ Ê¡¢Ì©ªÔµ¶à´µÞ²³Ü¯°×¸¹á—™Ã¢¤Í¨ªÓòòòÃÃö¶¶ !ù,s@pH,G€LÉ”Å`FÙ+01ã•å"¥œkôe*¡: åKhT!F]”®>¢Ê¨@¯ 2BCREJCW ˆtBR ›œ‰  ™¥MŠ­CT³™kHFDA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Properties24.gif0000644000175000017500000000224407731544722024637 0ustar frankiefrankieGIF89a÷ÿÿÿÿÀÀÀÎËðÌÉî×ÔùÚ×üÉÇëÇÅéÎÌðÍËïÌÊîÔÒöÛÙýÚØüØÖú¼ºáÂÀ濽ãÅÃéÏÍóÎÌòÍËñÈÆëÇÅêÆÄéÍËðÌÊïËÉîÊÈíÕÓøÓÑöÙ×üØÖû×Õú¶µÜ¼»âº¹à¹¸ßÄÃëÂÁèÁÀç½¼ãÅÄëÀ¿å¿¾äÊÉðÉÈïÈÇíÇÆìÄÃéÁÀåÎÍóÅÄéÑÐöÎÍòÌËðÉÈìÈÇëÕÔùÒÑöÐÏôÍÌðÊÉíÖÕùÚÙýØ×û×ÖúÚÙü×ÖùžžÈ¨¨ÒÃÃò¯¯Ù²²Ü­­Õ¸¸á··à³³Û²²Ú²²Ù±±Ø¯¯Ö¶¶Ý´´Û³³Ú¿¿ç¾¾æ¼¼ä¸¸ß··ÝÀÀ翿澾弼ãÃÃêÂÂé½½ã¼¼áÆÆìÅÅëÂÂèÂÂçÈÈîÃÃèÊÊïÐÐõÏÏôÓÓ÷š›ÅŸ Ê¤¥ÏŸ É¥¦Ðª«Õ¦§Ð±²Ü­®Ø­®Öª«Ó©ªÒ´µÞ°±Ø¯°×º»ã¹ºâ™›Ä¤¦Ð ¢Ë¨ªÔ¯±Û©«Ôµ·ßòòò³³³ !ù,ÿH° Áƒ"<€¡Ã†  PÅ‹’x¨Ð?ŒÔy“‡b¡C)¶'IBK! @QaG9nÍib§K™4RDç)W¨¬ !³cÂŽJðôÙÃeÄ&4MHñ=[´À°¦ÆŽ ,,ä% Š,/X¨ÁPdANR|Æ„‹6t ÑÐÀGˆš;ž(£Ì‡B4P A^ƒÅT@æˆ 6™p±ÁŽ4&xàà`@ÐX(q¹ Å @Iàà3i²¤0]°£ˆ w äà1ãÌ+RP €9€dB.¨ism'?.ÀÐ# 'Ó¥k¬® € ¾@ÁžâúÓ†>Lÿ Æÿõ}'Aý xÐF!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/left.gif0000644000175000017500000000021007725607455023264 0ustar frankiefrankieGIF89a ³ Ì3þüûÛoKí¶¤ñÉ»ÔS(ä’wÑDÒJ!ù , 50ÉI'¸8ß”‹Þ˜ A`”g0,œáÞ#} ©!ü3Ý.§1ƒ`ÆøÁ šÅŠT;openacs-5.7.0/packages/acs-subsite/www/resources/stock_right-16.png0000644000175000017500000000060407735433503025114 0ustar frankiefrankie‰PNG  IHDRóÿagAMA± üabKGDÿÿÿ ½§“ pHYs  d_‘tIMEÒ%@ØÙIDATxÚc` øO’‰RCˆ2 |aNC˜ÐlÁ†LÕ­ f¤c5„Ù€ƒ×ö2üùû›‰‘™™™.ñáË'†~0»¸Ÿa~õB†oÀõ± ›ööýkfV†¿ÿCLüÿŸáÃ?V&† ¦:6 ü=ü ‰]ÿa–£„Á_?þþÿ Çÿÿ30323üýÿ›™‹…‹AUE‡!{BÜ;(.8vìÃû/ïðèËGwö,½÷>Š?ÿübøúé†&n>.¬š±Å5V]ðß%Zç?¡D…3Q¢Ùe´É 8AïæN8Û7ÑÁ9Ä–6Y¾tnÖìµåIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/email.gif0000644000175000017500000000176610622143341023415 0ustar frankiefrankieGIF89a÷“ùüÿúüÿùûýõùü`}ªíóøPŒÈêóþ÷úüÀÛü–µãçñþùûÿàêùãìùáíýäïþÔæýN‰ÄóöûQ‹ÇÞè÷mµÖçýõùÿ ¿éÐáøŠ®âñ÷ûìôø…ªâJ„Äæîù=p¾ÞìýQŒÈ¼ÐìûüÿÛêýÚéýÙäñ\ŒÉÖäùÍàøÛëþÒãù ·ÜW‰ÇeÌíôþQˆÀìñ÷|Óp–йÏì·×üLˆÄØèýÆßüßìþöùü²ÌñÄÛøÞëþåíù[ˆ¶Óåýó÷ûPÈÞéù÷ùü¤Ãì½Õôîóø×èýc̰ãaËžÁðY‹ÈC}ÂP}ҨÜLr¯Ýç÷V„¶˜¶ãðõûîõþñõüMˆÄêïø‹©×³ËêT‡ÆöúÿßëþH‚ëÆíP‰Äãëó‰ªÜFvÂfŽÌ÷úÿ^ÊÜêý³Ö[†ÉÎÚër™Ñ½Óô–´ã?y¿S‡ÃûýÿÜèùòöû³ÊëÜëþÐáùñ÷þ°Ê땼ð±ÍñÉÞ÷ôøûÿÿÿ!ù“,Ó' H° ÁƒÿÀDäK˜>=Æ ‘CB„!„œh #€ sâ0áM$‰!b³ÃÌi ƒÇ$ )ÈÒæ‚|¼xÃÀV¢(hÀâ@TÀˆYRÀ ^"ØÉã€Af4$HPµŒ€ ŒPƒ¦Â‡-!J8)€EOŠ J\¬àÒÂÄ ‘I±¡Æ>žÐ™dÑM~ÄÁCáLk`\‘4`- T…€ …È`¨3ƒ‰ îIC¡íÛ¸o;openacs-5.7.0/packages/acs-subsite/www/resources/stock_left.png0000644000175000017500000000110707735433503024504 0ustar frankiefrankie‰PNG  IHDRàw=øgAMA± üabKGDÿÿÿ ½§“ pHYs  d_‘tIMEÑ žÈlyÄIDATxÚå•Í.,AÇU]Z¸— ØXÈ]Ù˜¥x âØñ båiÄÆMìIn2ÄM,ÄÂg 1LÄ`ÆL×Ç]¨fÌíLw±PI%ݧªÎ¯Î©:ÿ‚ïÚDÖ‰òŽÐ ¨v`ýwŸ‡ˆv`7þnÄÿ½@G»°;GyLÕĶЯMêo *«óóëÒ±}¯Åš Di·áÅùeéH RJDàŒAŠ„£Z«²}ö‡åÙ€_À P¬Js~xuHWÐ…Ž"Àb#‹¶ú5R™ˆëýÛØô¸ku"—ËÙÝãmNŠ'„„Ôuc"Œ3h4J*”T„2|†(…íÖ‰5’]\Zà÷îús þÃ;„¸ø‰u†R¡” €î¹™ùÊÔô£c#™‹¤R.gº¦ÐÀàæjžÓƒÂ‡5%)Ex†7WóE¦y‰ä¶Xæ®tŸè( Uf€ê@9 ²µ–OÛ´ÍRh‰Þþžx|xòÑ6;Œ‹,M*š!cO¾˜.€ó†^ðöZs$irÑ y¨ÆŸ–Z”EìÞDâmu¿Ã¤îÞõ2ù¹!ðÓKõ½××–§¯a¾ÀúËßäOoÿº‹³)üø®IEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/arrow-up.gif0000644000175000017500000000010407727641461024105 0ustar frankiefrankieGIF89a€ÿÿÿ!ù,Œ©Ë€„NNfóÊ\M[5 5B¥x™)ÅB;openacs-5.7.0/packages/acs-subsite/www/resources/url-button.gif0000644000175000017500000000017207725607455024454 0ustar frankiefrankieGIF89a‘ÿÿÿôòïfff!ù,KŒ©ËÝ£œ Š©¸¹ƒ}xhD‚ð¡çi¢´i°óËÍìY»ö—Û©V2\è5Lý–Á¤iÊ)¡:"L”¹b+°•÷ ö:Æä2£;openacs-5.7.0/packages/acs-subsite/www/resources/checkboxchecked.gif0000644000175000017500000000012207725607455025431 0ustar frankiefrankieGIF89a ‘¡¦¬ÿÿÿ!ù, #Œ(Ë-æ"Œ¬é€}aíª]~“†6XªŽžäRœÌ$öQ;openacs-5.7.0/packages/acs-subsite/www/resources/stock_first.png0000644000175000017500000000072707742601071024703 0ustar frankiefrankie‰PNG  IHDRàw=øbKGDùC»ŒIDATxÚí•»JA†¿]‡%XØl,,­R‰ä!_Èʰ|QAð‚`¥`²*¨AÁ !ã&ÙMÌæ²—±ˆ Q²î®h¥¦˜s¾Î?øË17A~aÅel@³Ù”úU6 0QêàÄl™<ÖîÔ™ÛLdÕjÌžÅJ»nGNqŠ?U‹är´ìö oA¡D¼+/rqŽ‹H¨ìí i #ɱ $>VÃdë|ƒÅ…¥È;èÏå/é¸<)ßñ±šùJ¡ Ïáåºìç¹ЧR)ã¡tÇéŽm7ºÏÁ“..BU ©ZW­ø£n°ûú.'7ǽ©±¼ºÌzv¶ÓÒa‰"•® ŠDAÅ—åB9`[¯˜ÏýÉôLÚ˜›Ÿejz2ò©±kµÈÇ´ $×uo ß~OÂLîA æéï¤Zªa•ëC4MľC!G›úÞä v)_ŒØOE'>ê £P …l¯|Ëð_ÿ~ýGû¡ñkrÂpÓªuIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/go.gif0000644000175000017500000000023107725607455022742 0ustar frankiefrankieGIF89a³Ì3ÿÿÿñÉ»ßaÜrOé§‘ä’wÖ\3à…føäÝõÖÌüñîÉA!ù,FЉª­CÈËíìK  pAÁh´Ñ$&R Á. 8/V )³ÞÌ0bJ†à°B8&††kJ…¼– x'…4;openacs-5.7.0/packages/acs-subsite/www/resources/new.gif0000644000175000017500000000035507725607455023135 0ustar frankiefrankieGIF89a" ³ÿÿÿÛlHÌ3襎õÕÊä’vñÉ»øâÛà†gÔS(Ï@Ö\3üñîÓN"úíè!ù," šν8çPš\B(Ždi† €”L.Á)‹IL@!À<¶Ðê …£à Òó†3ðv!ÁÈñ ¢4(2€DoÐ(¨3 8”¦ÂÂÂÓ3 €hwd!f;=  ]=ŽŠN™Œj Ž+  &x> M¬!¦°´"  µ° ¡;openacs-5.7.0/packages/acs-subsite/www/resources/stock_copy.png0000644000175000017500000000176207751737027024541 0ustar frankiefrankie‰PNG  IHDRàw=øgAMA± üabKGDêèãÕVÛ pHYs  ÒÝ~ütIMEÑ &.1¤ oIDATxÚ–]h[eÇç4MÚØ$Ë.‚J¥¨XSç0tµ7zqŠ´W½ê¤P&# ºz1ê†à ©Ô@ÊléÔvHd¬ ?CÝÖ•¥4Go4Ø(ÄÕ4ͱ9¯Ë IOŽ6>ðÂá}>ÿÏ×{$£,ð7àš€øô êùùya†(‹bddDØÉ}À@–ö—#Ÿ_·x=uê4—/Ï155ÅÖÖ¤Ów¹ti¢F.½t§€œ£Ž~Yý¶†‘¿—`qq!¡Pˆo¾þŠé¸Ê ¡£¹ë‰IóÓvyúý\åûÂ[q®^ûž\.ÇÀÀ^¯]×y®G!6ù9÷¶þâxð’zqÇTs²­ÿAç/~Äw?ÞfîJ‚ÙÙÙûZN'ËËËH’Dkk+>ÿC¼óþ4íím\SÁ0ª³!Ù:8óÚ»D^cpHbbb‚ÍÍMòù¼EÎáp0ýɧtvvÒÓâÕ“Ôòí›I¢··w_m§( ¥RÉ“í”nßI033ƒ¦ihšF&“AQ|>š¦¡( š¦‘L&Ëuûã?‚‘‘ϯ‹C~h”$IcgŽš³ð$à³EðhçÄÃa†††ˆF£¨ªZ‰8™L¢ªjEÇëqÛæD*‡‰ çùc #ðôˆ‹gŸ©Aà^N~sÐNœdéNšþþ~2™ Ùl·Û×ëeuu•ÑÑQ‚Á ÝÝÝÄb1 …‘HÃ0êÖà³D"±ï(S©”èèè¨Ë;ä÷ˆó§XjмßvèêêB×uËýÊÊ --NëœA³××ï/9—ËÅðð0Éd’……"‘ªªVÒ²¶¶ÆãuÔj’e®'Æ™™|ÓRÜß„Fö¹,K|³Þ7Éü|kŽ7Æ—ž~u @_8f{{›x•J54ÿò›ç,ðÐ.•'ytÏf}Ðî)JÀ‡ÀÀnÙ`5 @r@ÎT ”ÿU{IÞc¸ÚÀ.PŠe‡{ù¥²ý‘Ì4ƒYgU²IEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/Copy16.gif0000644000175000017500000000044007776747150023423 0ustar frankiefrankieGIF89aÄÿÿÿÿççÿçæÿæçÿææÿåæÿååþßßùÝÝöÛÛôÕÕïÓÓíÌÌÿÌÌæ³³Ì³²Ì²³Ì²²Ì±±Ë°°É¬­ÆªªÄ¨¨Â¥¥¾¢¢»Ÿ ¹™™²ÀÀÀ!ù,@J 'Žd9n€ƒ*T n%ªmtmŠ€ºHÖ ¤ší&B]PPv×xËY­ÄìéJ½!QÖî6 cÑM²Óå S¼#Ú$|k‰!!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Copy24.gif0000644000175000017500000000125207776747150023424 0ustar frankiefrankieGIF89aæÿÿÿÿççÿçæÿæçÿææÿååÿååþääýããýââüááûààùßßùÞÞøÝÝöÜÜõÚÚôÙÚóÙÙòØØñ××ðÔÔíÓÓìÒÒëÑÑêÐÐéÍÍçÍÍæÌÌÿÌÌæ³³Ì³²Ì²³Ì²²Ì²²Ë±±Ë°°Ê°¯É¯°É®¯È®®È®®Ç­­Æ¬¬Å««ÄªªÄ©©Â§§Á¦¦À¥¦¿¤¥¾¤¤¾£¤½££½¢¢¼  ºŸŸ¹žž¸·››´šš³™™³™™²ÀÀÀ!ù@,@´€@‚ƒ„…††?1 ‰:??‡‚?˜™'):‰ˆŠ£“•–…‰ŸŽ‹œž˜«ƒ™·¸ˆ¸™µ¬¦¼½«‰³§1’ª¥®1%Ÿž)¤µ‰žÖ8ؾáâã—æç´ã¯:/ÍêÈ‹‰çæé–‰Ò‰Á”Ĩé3µ(5{¿¶íËW™®„ Š™hø"ØÃBôZmÕM¸{> ƒßGKôRž#.!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/site-master.css0000644000175000017500000002555611014133232024603 0ustar frankiefrankie/* Styles originally defined in default-master.css */ #login-box { border: black 1px solid; padding: 4px; } TABLE.table-display { font-family: tahoma, verdana, helvetica; font-size: 85%; } TR.table-header { background-color: #cccccc; } TR.even { background-color: #f0f0f0; } TR.odd { background-color: #e0e0e0; } /* Replace deprecated center tags in forms. Eventually all forms should use form builder and this tag should not be used */ DIV.submit-button { text-align: center; } /********************************************************************** /* Site-Wide/Master Templates /**********************************************************************/ #skiptocontent { display: none; } .block-marker {display: none;} /* User Messages */ #alert-message { background-color: #ccff99; padding: 4px; padding-top: 6px; padding-bottom: 6px; font-size: 85%; } #alert-message .alert { margin-left: 0; padding-left: 2px; border: none; } /* Boxed User Message */ .boxed-user-message { background-color: #ccff99; padding-left: 12px; padding-right: 12px; padding-top: 8px; padding-bottom: 8px; font-size: 85%; border: 1px solid #dd9988; } .boxed-user-message h3 { color: #990000; margin-top: 0px; } .boxed-user-message .body { color: #990000; } /* Subsite Name */ #subsite-name { font-weight: bold; font-size: 120%; font-family: verdana; padding-left: 8px; } a.subsite-name { color: black; text-decoration: none; } a.subsite-name:hover { color: black; text-decoration: none; } /* Site Footer */ #footer { clear: both; border-top: 1px solid #ccc; font-family: tahoma, verdana, helvetica, sans-serif; font-size: 85%; margin-top: 24px; padding-top: 3px; padding-bottom: 3px; padding-left: 8px; padding-right: 8px; text-align: center; } #footer ul { display: inline; margin-left: 0; padding-left: 0; border: none; } #footer ul li { margin-left: 0; padding-left: 10px; border: none; list-style: none; display: inline; } #footer .action-list { float: left; } /********************************************************************** /* General navigation /**********************************************************************/ /* First level tabs */ #navbar-div { border-bottom: 1px solid #666; } #navbar-container { height: 35px; position: relative; } #navbar { position: absolute; height: 21px; margin: 0px; padding: 0px 0px 0px 0px; left: 10px; bottom: -2px; margin-top: 10px; font-family: Arial, sans-serif; font-size: 80%; font-weight: bold; } html>body #navbar { bottom: 0px } #navbar .tab { height: 16px; float: left; background-color: #eeeeee; border: 1px solid #666; padding: 2px 5px 2px 5px; margin: 0px 2px 0px 2px; } #navbar a { text-decoration: none; color: black; } #navbar a:hover { text-decoration: underline; } #navbar #navbar-here { border-bottom-color: white; background-color: white; } #navbar #navbar-here a { color: black; } #navbar-body { border-bottom: 1px solid #016799; background-color: white; clear: both; padding-top: 4px; padding-left: 12px; padding-right: 12px; padding-bottom: 12px; } /* Second level tabs */ #subnavbar-div { border-bottom: 1px solid #666; } #subnavbar-container { height: 35px; width: 742px; position: relative; } #subnavbar { position: absolute; width: 720px; height: 21px; margin: 0px; padding: 0px 0px 0px 0px; right: 0px; bottom: -2px; margin-top: 10px; font-family: Arial, sans-serif; font-size: 80%; font-weight: bold; } html>body #subnavbar { bottom: 0px } #subnavbar .tab { height: 16px; float: left; background-color: #eeeeee; border: 1px solid #666; padding: 2px 5px 2px 5px; margin: 0px 2px 0px 2px; } #subnavbar a { text-decoration: none; color: black; } #subnavbar a:hover { text-decoration: underline; } #subnavbar #subnavbar-here { border-bottom-color: white; background-color: white; } #subnavbar #subnavbar-here a { color: black; } #subnavbar-body { border-bottom: 1px solid #016799; border-left: 1px solid #016799; border-right: 1px solid #016799; background-color: white; clear: both; padding-top: 6px; padding-bottom: 6px; padding-left: 6px; padding-right: 6px; } /* END NAVIGATION */ /********************************************************************** /* Widgets /**********************************************************************/ /* STANDARD TAGS -----------------------------------------------------------*/ /* standard html (body, h1, p, form...) */ body { margin:5px 5px 0px 5px; padding:0; font:small/1.5em Tahoma, "Lucida Grande", sans-serif; voice-family: "\"}\""; voice-family:inherit; } h1 { font-size: 1.2em; font-weight: bold; color: #666666; margin-bottom: 12px; } h2 { font-size: 1.1em; font-weight:bold; color: #555555; margin-bottom: 12px; } h3 { font-size: 1.05em; font-weight:bold; color: #444444; margin-bottom: 12px; } h3 { font-size: 1.00em; font-weight:bold; color: #444444; margin-bottom: 12px; } a:link { color: #235c96; text-decoration:underline; } a:visited { color: #235c96; } a:hover { color: #235c96; background: #CCCCCC; } /* BUTTON ---- */ a.button { font: .85em arial; border: solid 1px black; background-color: #E1E1E1; text-align: center; padding: 1px; padding-left: 8px; padding-right: 8px; color: black; text-decoration: none; white-space: nowrap; } a.button:link { text-decoration: none; border: solid 1px black; } a.button:hover { text-decoration: none; background-color: #CCCCCC; border: solid 1px black; } a.button:active { text-decoration: none; border: solid 1px black; } /* END BUTTON ---- */ .center {text-align: center;} .small {font-size: x-small;} /* ARE THESE NEEDED ??? -----------------------------------------------------------*/ /* Various forms of links */ .action-list { padding: 0; } .action-list ul { margin: 0; padding: 0; display: inline; border: none; } .action-list ul li { margin: 0; padding: 0; border: none; list-style: none; display: inline; } div.subsite-context-bar { font-size: 85%; margin-bottom: 4px; position: relative; } a.admin-button { font: 85% arial; border: solid 1px black; background-color: #aaa; text-align: center; padding: 1px; padding-left: 8px; padding-right: 8px; color: #fff; text-decoration: none; white-space: nowrap; } a.admin-button:link { text-decoration: none; border: solid 1px black; color: #111; } a.admin-button:visited { text-decoration: none; border: solid 1px black; } a.admin-button:hover { text-decoration: none; background-color: #ccc; border: solid 1px black; } a.admin-button:active { text-decoration: none; border: solid 1px black; } a.admin:link, a.admin:visited { color: #f00; font-family: verdana; font-size: 11px; font-weight: normal; } a.admin:hover { color: #fff; background: #f00; } .highlight { background-color: #ffc; } ul.action-links li { list-style: circle url(/resources/acs-subsite/action-link-marker.png); margin: 8px; margin-left: -16px; } /* END ARE THESE NEEDED -----------------------------------------------------------*/ /* END STANDARD TAGS ---------------------------------------------------------------*/ /* HEADER TAGS ---------------------------------------------------------------------*/ #header { font-size: 0.92em; background-color: #EFEFEF; color: #444444; padding-top: 4px; padding-bottom: 4px; } #system-name { font-size: 1.4em; font-weight: bold; float: left; padding-left: 0.2em; } #system-name a { color: #333333; text-decoration: none; } #header-navigation { float: right; padding-right: 0.4em; } /* CONTEXT BAR ---- */ #breadcrumbs { clear: right; padding-left: 0.4em; } /* END CONTEXT BAR ---- */ /* END HEADER TAGS -----------------------------------------------------------*/ /* LISTS -----------------------------------------------------------*/ ul.compact, .action-list ul{ margin: 0px; padding: 0px; } ul.compact li, .action-list ul li { list-style:none; display: inline; } /* END OF LISTS */ /* Portlets */ .portlet-sidebar { width: 30%; } .portlet { margin: 4px 4px 4px 4px; } .portlet .portlet-title { background: #dddddd; padding: 2px 8px 2px 8px; margin: 0; } .portlet .portlet-body { border: 1px dotted #999; border-top: 0px; padding: 6px 8px 6px 8px; } /* Generally Available Tabs */ #tabs-div { border-bottom: 1px solid #666; } #tabs-container { height: 15px; position: relative; } #tabs { position: absolute; height: 21px; margin: 0px; padding: 0px 0px 0px 0px; left: 10px; bottom: -2px; margin-top: 10px; font-family: Arial, sans-serif; font-size: 80%; font-weight: bold; } html>body #tabs { bottom: 0px } #tabs .tab { height: 16px; float: left; background-color: #cccccc; border: 1px solid #666; padding: 2px 5px 2px 5px; margin: 0px 2px 0px 2px; } #tabs .disabled { color: #999999; } #tabs a { text-decoration: none; color: black; } #tabs a:hover { text-decoration: underline; } #tabs #tabs-here { border-bottom-color: #f6f6f6; background-color: #f6f6f6; } #tabs #tabs-here a { color: black; } #tabs-body { border-bottom: 1px solid #016799; background-color: #f6f6f6; clear: both; padding-top: 4px; padding-bottom: 4px; padding-left: 4px; padding-right: 4px; } /********************************************************************** /* acs-developer-support Toolbar /**********************************************************************/ /* LARS: This ought to go in the developer-support package, somehow */ #developer-toolbar { background-color: #616093; color: white; font-family: tahoma, verdana; font-size: 80%; padding-left: 8px; padding-right: 8px; padding-top: 2px; padding-bottom: 2px; } #developer-toolbar td a { border: solid 1px #616093; text-align: center; color: white; text-decoration: none; } #developer-toolbar td a:hover { text-decoration: none; background-color: #999999; border: solid 1px #cccccc; } #developer-toolbar #search { font: 80% tahoma; color: white; } #developer-toolbar #search input { font: 100% tahoma; } #developer-toolbar td a.on { background-color: #888888; border: solid 1px #cccccc; } #developer-toolbar td a:hover.on { background-color: #666666; border: solid 1px #999999; } /* Developer-support footer */ .developer-support-footer { float: left; padding: 6px; border: solid 1px gray; background-color: #e1e1e1; margin-top: 4px; } /********************************************************************** /* DEPRECATED CLASSES /**********************************************************************/ /* Deprecated, not sure what it's replaced with just yet */ a.action { margin: 8px; margin-left: 24px; display: list-item; list-style: circle url(/resources/acs-subsite/right.gif); } openacs-5.7.0/packages/acs-subsite/www/resources/arrow-down.gif0000644000175000017500000000010507727641461024431 0ustar frankiefrankieGIF89a€ÿÿÿ!ù,Œ©ËàŒ€GRco^Ͼ$…(NM¨”yµm;openacs-5.7.0/packages/acs-subsite/www/resources/add.gif0000644000175000017500000000006507725607455023072 0ustar frankiefrankieGIF89a€Ì!ù, L€fËc:ÓµP;openacs-5.7.0/packages/acs-subsite/www/resources/Preferences16.gif0000644000175000017500000000031707731544722024744 0ustar frankiefrankieGIF89a¢ÿÿÿÿÌÌÌff™fffÀÀÀ!ù,AXºÜ:Ǹ„ú „U$¹XY¸•f"7ÀÑÆWnSQt–\ŒE,Á©x\±–FØÎ1ëMºËo»H!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/stock_right.png0000644000175000017500000000110507735433503024665 0ustar frankiefrankie‰PNG  IHDRàw=øgAMA± üabKGDÿÿÿ ½§“ pHYs  d_‘tIMEÑ 7»Ð¹éÂIDATxÚ啽KA‡Ÿ™¹Kp¯IÌ_àGsU °•ÔéÓÄÊB»©´ Ëtb!±ò/0 mÅ,4•…àáǹžºÞììXdÍ1³îI$E^xÙfö÷¼_3/ü&º9,»·ÀK Ü-¨häÖù+ú« عï3mH_ˆÌ‰VzœÁ_'ê@x‘‘:g€ép  „âÝÐS߯ A„hÖö~ ¥ÔÎ.Ï‘B‘¤ [?YøºÈÅiòˆ– 0°²¾ ªŒ±ú>-kÉÈ~CEm5Æhöv˜›ðB¼=HZ ÆŒ5¤Yб+,J(¤«Q@TŠè¯11ÿ9X®’°µ¹Il/å Yf`ôSÕ¥Ý:ðÚe¢ƒ€f_6 Ïïñá/V—vÞ=À5Ö["aÅSÄß7ÎÓv¼ܦ-®âk¯`¥…Äcàh:@xŠò"þ8ñJ5ò‰Ÿø¦È—A¯kTÅ3eÛÈOB÷ ·î‡FG† Ù8*,ž÷¶‹@ùÚ7oØÕ:W<ØäϲφÜ÷ü1ñn·“"×#í2Èç £äÜ<œõº“ŸÝî°ÅS¿cãIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/checkbox.gif0000644000175000017500000000010207725607455024120 0ustar frankiefrankieGIF89a €¡¦¬ÿÿÿ!ù, „Ëæ"ŒmÒeo¦[‚ËtŽX}à“¤F;openacs-5.7.0/packages/acs-subsite/www/resources/Preferences24.gif0000644000175000017500000000036007731544722024741 0ustar frankiefrankieGIF89a¢ÿÿÿÿÌÌÌff™fffÀÀÀ!ù,bXºÜþ0¶A+%D²ºÇ€¶pX`œ¨ÄÙ¦*[°`ßÂ`­Yã6ÝÌŠLHZQ4 Y(K‘gÚQY5OË•C=F%œ$ÑØGsܤ“? N¬$¿‘g¬óù•t=W !þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/email_add.gif0000644000175000017500000000201310622143341024207 0ustar frankiefrankieGIF89a÷ŸùüÿúüÿùûýPŒÈíóøõùüäïþ7kºd`}ªàêù–µãÀÛü²Ò•çñþAs%ùûÿáíýãìù”°„SŒ(êóþ¼gÜèùPŒÉ—¶ãñõüÆßü¤Ãì^Š·©ÅêQ…Å«ab‹JfŽÌ°ãLr¯cÌPÈC}ÂÂÚø³ÖÞéùûüÿ£¾­œ¿íÛëþ¢¼§˜¶ãH‚Ãó÷ûBygÜêýäìõêïø‡¨Ü½ÓôÒãù§Åì ¿é²ÌñÐáùP}ÅÝç÷Œ¼e·×ü>mµ‘®?y¿^ˆI‹ºb´Ô•?q"8l±Ó|Ó±Ö’¼ÐìE€Ãòöû–´ã‡¹`öúÿÞëþÐáø±Íñ½ÕôÜëþîóø=p¾óöûÖçýQŒÈÞè÷÷úÿ\ˆº‰ªÜaË×èýûýÿFvÂüýÿW-ÚéýÔæý¹ÏìJ„ÄL{1—²ˆîõþ·–ðõû•¼ð¢¿é ·Üõùÿr™Ñz&-ÊóAÒ£/ äÒ #€ WŒ)£ÅF‡%O \hs†ÆŸHQ€©—;ª,PѦƒ ^$4‚Si€—x,P0§‚&”FX B`#bÐ$#B;7Z0`PÕ‡B= é€ñ£KPl `‚L i¨l±²#Šðqƒ!K&™ö8šââÊ G6 23ƒ–oÉT @%L<±$:DN8‰¡Ñ?žb78€ð#A”K‹OŠÖŽc«x}@‚¢ JSâ£Ó0™™.±s¶­Ón·FØö-Þ[¦/Î3W÷Cëåñán$ð=èóÙýŠMN™Iʼn^'ªWeÅ*I‚ bÕ«ˆ‘umyùæù/k[dì¿‹ÓË£(_¯­²¼±Ä¿ÆC…‚"ãÿüIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/diamond.gif0000644000175000017500000000013307725607455023751 0ustar frankiefrankieGIF89a ¢ÌõÌÌÏÖ33ÝUUÓ""!ù,  hª´®Œ.Ú»ôæðmB`„c¹ –ê îæ’;openacs-5.7.0/packages/acs-subsite/www/resources/stock_first-16.png0000644000175000017500000000053407742601071025123 0ustar frankiefrankie‰PNG  IHDR/\bKGDÿÿÿ ½§“IDATxÚÕ“1KÃ@Ź\õ+8ˆ“SA7WÇ‚_Àâä§7q×"\£`Ĉ¥1K±¥\J›KΡP"±×@]|pÛÝ{ïÿÞÿàaJgžkµßÚ6¢u"€tœ® bUk,isÄŠQ¿ìì786"ÄŠÁx€l4¸y¸Æq]Lž#„`:›ÒIï9?½°:2A¬è}öhºMt–1+4ºÐ‹B’å£hRͨÛ}À÷}óøÞ!&xxÌõœ<ÏÐh¤H±Ð•RRléjF¯Ña:û»æ¨uÈÎÞ¶5ÜÉðkmØÎí¥2´X’%Q¿rÉód­Ö~Ý]©ê_’•k¶nöÉÙñÆ›]÷¯þ¾ü«wˆ`ž·IEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/New16.gif0000644000175000017500000000065207731544722023236 0ustar frankiefrankieGIF89aÕÿÿÿÿÀÀÀÚ×üÛØüÊÈìÎÌðÍËïÌÊîÛÙýÙ×ûËÉîÖÔù×Õú»ºáÅÄìÇÆíÁÀ濾侽ãÄÃéÃÂçÏÎôÔÓøÒÑöÚÙýÏÏÿ®®Ö²²Ù±±Ø¿¿çÁÁèÃÃêÐÐöŸ Ê¡¢Ì©ªÔµ¶à´µÞ²³Ü¯°×¸¹á—™Ã¢¤Í¨ªÓòòòÃÃö¶¶ !ù,t@pH,GLÉ„½\FX+0/ãUÅšk´E™6eKX•P‡E]”¦: I¨@¯ HRCl  0”-•CR ™— jRK™MB—Ÿ¡CT²”´˜HBbA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/radiochecked.gif0000644000175000017500000000012207725607455024741 0ustar frankiefrankieGIF89a ‘¡¦¬ÿÿÿ!ù, #”y+­V : ·”GT$*0fðÀÀàÆ‡Z‡:•K‡;0PA>C”¬PÈÂeƒ‡ 2ä¤.a8hh0€!Â\ÈA G‚8Ààlg¡N 2Ü3 £Æ$Á6¢$ñÆŽ Z^&59ÑUt¦£iiZ¸x0EP¦¤•~Úyäè(LŸ†0aÒ)àÔ&¸’Ý-©4¯¡¾!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/profile-16.png0000644000175000017500000000064210052153356024225 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“WIDATxÚÍ“=KÃP†Ÿ„Ø@E*%T:¸w³þÑI,‰Å!.NÒÁ®¢ø,ÙܪT\º¨ ~@ƒRDtl‡~@—’@h›8%m©‚vÑ—{Ͻ—sŸóò^ø¡îˆC×uÝ‘^ÉKlÛæéò˜û«vfçWYX^ÇqDQ¤Óé Iþuµ ¢·Ñn·y-±²±ÍËówâñ8©T APUÇq(¤þd1©˜Œ LG0- Ã0üó\.7Ô†O Ë2‡ç<ì¦1º16Ó{äóyt]÷×:x".mí“L$89=£Vo0›áè`ç[µ a%Ú#˜ …¸¾¹eL”ŒÇÙl]×i6›‹Å/‹¹£D½Zv×#¨hšFÿœÉdüþËlõ4¨WË^å'²ÌÁñ ÂJtÈÊæo¬,ŠâÚßÿÄOÎÆ½ù:IEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/feed.gif0000644000175000017500000000207210622143341023220 0ustar frankiefrankieGIF89a÷ÿ‹ÿ‰ÿ¯Yÿúõÿ®XÿôêÿúôÿEÿ½tÿ¾yÿ¢Pÿ™Gÿuÿ÷òÿGÿÆÿªUÿʃÿÅ~ÿêÖÿ¯ZÿšdÿÀyÿ¸pÿgÿšpÿ“`ÿ©TÿÃ~ÿÀ„ÿ‚<ÿ½„ÿ­Wÿ¬Vÿwÿ»mÿ±Nÿ¬pÿªpÿ«nÿήÿµsÿ’Cÿ‚ÿÀÿÆœÿmÿ»„ÿ¹†ÿ¯Iÿ±dÿ¥pÿ¬Uÿôèÿ°pÿóçÿºwÿÇ€ÿ¹jÿ”EÿúöÿºtÿÝÃÿФÿ}Fÿ®Yÿ¶|ÿ¯XÿÇ—ÿ¶wÿªWÿ«UÿUÿ¸’ÿŠXÿÊ„ÿçÙÿõïÿšPÿÍ™ÿÈÿ_ÿà¿ÿ®hÿ¨SÿMÿÑ®ÿ¡Tÿ{8ÿ̆ÿÉ€ÿ‹?ÿ¸ÿ¶mÿq4ÿ§RÿʆÿÈ‚ÿôïÿÕ¯ÿCÿÀ…ÿ]ÿ¡Oÿ Nÿ¬Xÿ¥kÿ­Vÿȃÿ¹mÿ­pÿ©mÿ©pÿœIÿƒÿ gÿÌ—ÿÂ}ÿóèÿ›Iÿ®^ÿqÿ¹vÿÁ}ÿ¤jÿ{ÿŒUÿ´sÿÒ®ÿðáÿ†Uÿ¿zÿ}ÿÕ¼ÿß¿ÿÌ™ÿ¤Oÿ›bÿŒ@ÿq3ÿz7ÿÅÿˆþòïÿ˃ÿ³cÿiÿ²gÿ¼„ÿgÿKÿåÊÿ¯pÿ°ZÿÈ„ÿùóÿ¦Aÿ„<ÿáÁÿQÿ fÿÿÛÁÿSÿAÿÁ~ÿŠ?ÿ±‹ÿYÿóïÿ¦RÿcÿÅÿéÒÿ«‚ÿÔ¯ÿ·vÿ¡hÿ²cÿ…ÿ‡ÿÿÿ!ù,ÿ›\˜EV€ƒ åFÌN,ÔáÀêA˜`eDÂÄ,EPXyñeCˆ4C2 ‘ƒÐ, \jÉ40F(@`ÑGΞ)€|ÉJN 1˜Å‘**4Ê’ùdƒ‚88\Ð’@ÉÀ„²x’ÙáÎŽ•f5ú ³Ö€A ÕÚäD‘(´érhè€gnÔjÑéªlŒ€ IJ-;W„Ôj€EÍ(ZšÖ\š@OZ0¶4¨å'VZVÈl…†H-Q Õr…Á­%mÔzµ D-&Œ’Ô:UL(-:&ÁZ Â¨D^€(¤áœJ%ÐóÓ>s0Tа(Cª"ä‘´Ê ’O–:áQ@;openacs-5.7.0/packages/acs-subsite/www/resources/up.gif0000644000175000017500000000147710171476746022772 0ustar frankiefrankieGIF89a ÷ÿÿÿ, $H° ÁÀPá@†Bœxp¢Å‚3>̨ѡÁ€;openacs-5.7.0/packages/acs-subsite/www/resources/attach.png0000755000175000017500000000060711057324626023617 0ustar frankiefrankie‰PNG  IHDRµú7êgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDAT(ÏcøÏ€bZ*=çå”SÝ6M†X,VœýrÒõ®G [ûþçÕa(X$=óþÄë‚þ3äX$CS0_dƽþÍ­ëkýA¼íˆç( æ‰Oýг¥e~uP!wæÁø–°­>È æÈOyÛ½¡iVEjPÚÑØŽà)Þ7ÝDá f«NzÒ5¿azy\gÊ­˜® …ž\%ᾘ©8ñAÇŒºî2ïÎ䛑õ‹<^¹ÊÃÃa†zÿûÖ嵌Åk²®'<‹hð_àñÆ…) zÜ[UK€8ña1>3Ýo»¡„d“^ÅËQ'XÕ{±ÛMg1´ .çÎÛš²%F5ÈÚó²ë=',q‘ÌépÞã©kž£‘E¢DRú%úHOIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/email_delete.gif0000644000175000017500000000201210622143341024720 0ustar frankiefrankieGIF89a÷¥ùûýùüÿúüÿíóøPŒÈõùüáíýãìùêóþ–µãàêù¼CÁYäïþ`}ªÀÛüݦ†ùûÿçñþ±ÍñòöûÞè÷œ¿íÖçýPŒÉ¼Ðìÿ\ˆºPȧÅìÂ\#ñ÷þQ…ŤÃì^ÊÀYûýÿÑv=•¼ð–´ãFvÂ=p¾QŒÈY‹È~muC}ÂÐáùÊf(Ëm/J„ÄüýÿØéýÜêýH‚Ãᫌ‰ªÜÌ£”Á^)îóø[†Éñ÷ûñõü¹Ïìðõûã°•Á\$Þìýêïø°ãþÖ¸îõþøûýp–Ð>mµÔ¡…LˆÄÆßüE€ÃåíùÂÚøôøû×èýÿ’Mßìþ½Õôÿ†!Þëþöúÿ»Bßëþ¢¿é ¿é*] ²EË9ÀQ‚!E ¦d±ÒèN¢’Š ÁbD?xL‚R @;RU „ÇA.oZ4©cIM¤bƒÂ‚°=2¥4¢¶]ΈÁ¡v) 0(;openacs-5.7.0/packages/acs-subsite/www/resources/action-link-marker.png0000644000175000017500000000026510006221375026025 0ustar frankiefrankie‰PNG  IHDR ÷$ž„gAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<PLTE10cÿÿÿâM«¾5IDATxÚb`  (HœÉÀ@ @H €’6€b@`²1¾‡wIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/stock_copy-16.png0000644000175000017500000000100407751737027024752 0ustar frankiefrankie‰PNG  IHDRóÿagAMA± üa pHYs  ÒÝ~ütIMEÑ 4͈ГIDATxÚ­“¿KqÆ?²d €¸R!JÄ1]n G p[ Y$KI‘€ÃtJàì-’¡KòBëààDNŽ"¸Hˆ±U/ Æàüñ:hÔ\ªQè ïô>Ïûýð¼|F×!àÆ€£Äq@žw¡PF£!étZÜ3 îq-(_tê´Îöi7˜™ž¢s~Êò’‰ãüEUƒ,ehžì±ú} ì&òÏ¢27;#ù|^Ú­3©V«²öû—$“I™üôQù¢Ï Š{€ˆ ë:½^ïqèõz1M“h4Š¢Ü[=/…aY•J…H$B  ›ÍÒív±m{@÷*ÁkÕ'P’/2˜¦‰ã8ø|>ŠÅâÀyë‹ÏuC¤R) à ‹Q*•…B„ÃáGS.—ò¬¡ þAŸBÓ42™ š¦‘H$Lý^Ì|}?ÁöÆ GÇM‚~*›»Ø?ÖŸlÛÆ0 t] pß=8áàò²3LP«ÕPUõE‚o󟹽¾åêæŠú‘ógk§>þÏøŽŽßÀg¹—L³IEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/Edit16.gif0000644000175000017500000000067107725607455023401 0ustar frankiefrankieGIF89aÕÿÿÿÿ±AT¾NaÀÀÀÚ×üÊÈìÎÌðÍËïÌÊîÛÙýÙ×ûÇÅêËÉîÖÔù×Õú»ºáÅÄìÇÆíÁÀ濾侽ãÄÃéÃÂçÏÎôÔÓøÒÑöÏÏÿ®®Ö²²Ù±±Ø¿¿çÁÁèÃÃêÐÐöŸ Ê¡¢Ì©ªÔµ¶à´µÞ²³Ü¯°×¸¹á—™Ã¢¤Í¨ªÓÅÆFÒÓS¹MÙ¯­æ¼ºòòòÃÃö¶¶‹‹‹((( !ù,ƒ@‚pH, :¤RW£åp·€P7 T«€@ ÃÍŽUk„l\YNJ –H'Ιƒ ¼`–)‚`r/O_S3*!"8.kCY ŒŽl„ €wƒ`Ÿ/¡ET —DY °VªK€96UFVV8kWFD±ÅÈÅA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/ZoomIn16.gif0000644000175000017500000000046007731544722023715 0ustar frankiefrankieGIF89aÄÿÿÿÿ00a==n„„œŠŠ¢˜˜°žž¶««Ä¿¿×ÅÅÝÙÙòÅÅÐááæÔÔÙããæ˜™¯a0—~ ÀÀÀ!ù,W %ŽdY`–iã0À°Š@óL$kýEâ XM©¤aÀ;1 ÀÁ°Øõ ‰‰±k–‚i55£à@‚*Þ”udRM"’y]tÏïùpfƒ%!;!!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/info.gif0000644000175000017500000000016107725607455023272 0ustar frankiefrankieGIF89a ³ffffÿÿÿ!ù, AC BNlqÞž'UÖ…œI¡¤ ÝùÆëX–_;openacs-5.7.0/packages/acs-subsite/www/resources/Edit24.gif0000644000175000017500000000233407725607455023376 0ustar frankiefrankieGIF89a÷ÿÿÿÿ±AT¾NaÀÀÀÎËðÌÉî×ÔùÚ×üÉÇëÎÌðÍËïÌÊîÔÒöÛÙýÚØüØÖú¼ºáÂÀ濽ãÅÃéÏÍóÎÌòÈÆëÇÅêÆÄéÍËðÌÊïËÉîÊÈíÕÓøÓÑöÙ×ü×Õú¶µÜ¼»âº¹à¹¸ßÄÃëÂÁè½¼ãÅÄëÀ¿å¿¾äÊÉðÉÈïÈÇíÄÃéÁÀåÎÍóÅÄéÑÐöÌËðÉÈìÈÇëÕÔùÒÑöÐÏôÍÌðÊÉíÖÕùÚÙýØ×û×ÖúÚÙü×ÖùžžÈ¨¨ÒÃÃò¯¯Ù²²Ü­­Õ¸¸á··à²²Ú²²Ù±±Ø¯¯Ö´´Û³³Ú¾¾æ¸¸ß··ÝÀÀ翿澾弼ãÃÃêÂÂé½½ã¼¼áÆÆìÅÅëÂÂèÃÃèÐÐõÏÏôÓÓ÷š›ÅŸ Ê¤¥ÏŸ É¥¦Ðª«Õ¦§Ð±²Ü­®Ø­®Öª«Ó©ªÒ´µÞ°±Ø¯°×º»ã¹ºâ™›Ä¤¦Ð ¢Ë¨ªÔ¯±Û©«Ôµ·ß+Z+8g8ÅÆFÒÓSƒƒ5ÃóÐÐÀ¬€@¹M«€~¸‹Ù¯­æ¼ºòòò³³³((( !ù,ÿ H° A‚‹$\¨°aAE‰ À!‹/*<4P¡B„$ \tˆÎ;BÔqSñТ‰ *”ˆ#Šbð”)b&Ï‘EDT$hÐÌ <3æš$kª<*”€¢=FÕX±Nš!Hš@q’bÐEŠéÙ£gëÈCFÚÈCEÄ(MħO[‘\°‰ófŠÀȸÁ Q >~k…ɉ(-T|Á„AE}øà6°,%XH˜aã‡iE“¶9¤ 4º|Hàcƒ|!KNJ1€ ^Ât¡ÀÁÇÂ'×>ƒ‚ 80à´ìÒÅ3ðf0DÁƒ b?=Ć ÔÀ#xdéÅ}ëðqáË è÷WI¿A€AYp¡ ~¬G[A-pÀ 1DpʼnüÈl"„C -øGM$$PFeXF&¶у-šÈ^Œ4Æ!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/ZoomIn24.gif0000644000175000017500000000074407731544722023721 0ustar frankiefrankieGIF89aÕÿÿÿÿïïòììóë¾¥ààæßßåÞÞøÞÞ÷ÝÝêÚÚçÙÙæÙÌÀ××ñ××ðÓ®•ÐÐéÐÏéÉÉãÉÉâÉÉÕÂÂÛÂÂÎÂÁÛÀÀÌÀ³¦¿‘w»»Ô»ºÔ»Ÿ…º»Ô³™€®®Ç«ƒj§§Á§§À  ¹ Ÿ¹™™²”tZ’“«’’¬’’«‹‹¤„„€fMffff333fÀÀÀ!ù1,@®À˜pH,‹°BÆlÂFŒàH=Â<,Œ «‚FE™¼ªÄ×$Rz@C‡M7º\€©ÕY&Á+0'lgh0d…0$ !su/——y0 [}U0 .Ÿ¦§‰ILŸ0_+0Œ” *0…m#¸Vc„0À‘ÂG/„lO‘Rzh—n‘“/-¯ŸyÝ10 ,ž¨B0&äå0¥åDÓñEA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Delete16.gif0000644000175000017500000000032007725607455023705 0ustar frankiefrankieGIF89a¢ÿÿÿÿÌÌÌ™™™fff333ÀÀÀ!ù,BhºÜn$>«•Œ„„d×5fÀö…À¹ˆB0ëÀ2m7ø\‹7@Ì·C u@ž0÷s½ROñUŠ8­¬vÂU$!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Delete24.gif0000644000175000017500000000037107725607455023712 0ustar frankiefrankieGIF89a¢ÿÿÿÿÌÌÌ™™™fff333ÀÀÀ!ù,khºÜþ0ÊUêŒ%èrù`(F  ªC ‰p&š²åüB ‚€ÐÒíz= è¢!ÁaQRz*¥Í£ïÊ4>ªÛh—Ê /§N3Öë'Åhíûœý–çk²í&ˆc"l„…†…‰Š !þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/default-master.css0000644000175000017500000000744010617100627025265 0ustar frankiefrankie/* Calendar widget css */ /* The main calendar widget. DIV containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #556; font-size: 11px; color: #000; cursor: default; background: #eef; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #fff; color: #000; padding: 2px; } .calendar thead .headrow { /* Row containing navigation buttons */ background: #778; color: #fff; } .calendar thead .daynames { /* Row containing the day names */ background: #bdf; } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #556; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #a66; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background: #aaf; color: #000; border: 1px solid #04f; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background: #77c; padding: 2px 0px 0px 2px; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; color: #456; text-align: right; padding: 2px 4px 2px 2px; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #bdf; } .calendar tbody .rowhilite td { background: #def; } .calendar tbody .rowhilite td.wn { background: #eef; } .calendar tbody td.hilite { /* Hovered cells */ background: #def; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ background: #cde; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #fff; color: #000; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #a66; } .calendar tbody td.today { /* Cell showing selected date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #556; color: #fff; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #fff; color: #445; border-top: 1px solid #556; padding: 1px; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #aaf; border: 1px solid #04f; color: #000; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #77c; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #655; background: #def; color: #000; font-size: smaller; } .combo .label { width: 100%; text-align: center; } .combo .hilite { background: #acf; } .combo .active { border-top: 1px solid #46a; border-bottom: 1px solid #46a; background: #eef; font-weight: bold; } openacs-5.7.0/packages/acs-subsite/www/resources/spacer.gif0000644000175000017500000000005307725607455023614 0ustar frankiefrankieGIF89a€ÿÀÀÀ!ù,D;openacs-5.7.0/packages/acs-subsite/www/resources/Zoom16.gif0000644000175000017500000000045707731544722023434 0ustar frankiefrankieGIF89aÄÿÿÿÿ00a==n‘‘©žž·˜˜°¥¥½¸¸ÐÌÌåÅÅÝÌÌäááæÔÔÙðð󋌢n= µŠqòòò ÀÀÀ!ù,Y %ŽdYNÀ$æ˜6L3 l;5¢<ƒdã:Ä‚Ð3A…á@3Ý:Â!Q,I&ŲP-)5Õ¢$ð5‚*¯|”I(“yÝ.ÂÏù.+€#5„$!!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Add16.gif0000644000175000017500000000035607731544722023176 0ustar frankiefrankieGIF89a³ÿÿÿÿææÿååÿååþÌÌÿÌÌ崴̳³Ì¨§Á¦¦À‹‹¤‹Š£€€™ÀÀÀ!ù,@HÐÉI+m ¤`xÀf0†Ò`xˆÓ¼ïÏ–$*÷ª×µ`H´ñjHq˜R‘p‰õ5›N)òL®®YÐÀ “”c!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Zoom24.gif0000644000175000017500000000074507731544722023433 0ustar frankiefrankieGIF89aÕÿÿÿÿ¥¤½ÅÄÝ00a==nŠŠ¢‘‘©žž¶««Ä¥¥½²²Ê±±É¸¸Ð¿¿×¾¾ÖÌÌåÅÅÝÓÓëÓÓêÒÒÞÌÌ×ÅÅÐááæÔÔÙððóããæ˜™¯a0n= †nV÷«Î¶±—~ª‘y™{bÈ¥¯‰r—~ß´òòònnn ÀÀÀ!ù+,¯À•pH,ÈdR`ª”Ç&æ±P˜Ð!À‚Éh.ŒC£BÈ®T‘‹ÆÐoTÕ]367bP€vn JtyŒx qJ[aŒ„ ‡‰‚ ‘Jyƒ —qˆJƒ…  ™Y±¡)Mf(»Á( OfÃÃg "ÈfE*"!ÑÒC*!#$ØÙg$%'àD*'&æDÊìDrñôPA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/stock_last.png0000644000175000017500000000072407742601071024514 0ustar frankiefrankie‰PNG  IHDRàw=øbKGDÿÿÿ ½§“‰IDATxÚå•=KA†Ÿ»ó0…þÅ&¢MµÄÚÞF+ Aí,¬ìD-íÄÂÿ ,¬DEPâG@ƒ›pÆèÝq··6~Řd–exöaþCtþ6@i@Ô·Ó0 D9Ž£Ž/*¦aÿt@Ô‚Ø®Í]ñ¶â] Ð×=ÀÂÖl]ÈOaVñ°ÌO×sIô1¿1Ý0¤åý⺞ôð¥¸ø2Àõ O‚Œ¸£Íjg°6`sqK<æÝ. ¯ Èî9Ëœ#•ÿY9¥ 1 Ëh%ñab«1–¦VPòQÏ÷J"•$¤’(Ca¦a •DZ"ôtÇ™YŸ,³KÊ öÎ.N9¸ÚÇ´,-oC £q’Û)°w¼ÃIú°F |‡¢°µ»#—¹!¹âÍ&ñòXÂÎåk´iH³ây­"§3×<_~LŠvDš/,Ï­UMŸ#ÚiXü+À¨3‹š×%û¡)qm€ŽøÓ³Èþæ>øõöÏã¡HË éØOIEND®B`‚openacs-5.7.0/packages/acs-subsite/www/resources/Add24.gif0000644000175000017500000000072607731544722023176 0ustar frankiefrankieGIF89aÕÿÿÿÿççÿçæÿæçÿææÿääþääýäãýããýÜÜöÜÜõÜÛõÛÜõÛÛõÔÔíÓÔíÓÓíÓÓìÎÎÿÌÌæ½½½³³Ì³²Ì²³Ì²²Ì­­Ç­­Æ¬¬Æ¤¤¾¤¤½œœµœ›µ™™²ÀÀÀ!ù",@ @‘pH,!€ÇÁIdh $ …ɨ6a:<¢©œxÌÌ$`| žÛm&‘¼†(â¼^¸VŠzymCIgKMOTk„I‰RqSd‘Qsu”R—_a„¡“¡¥F~£©}¤vfhM‹š­°NRT³§L¶‘b¬DI½œ¹ÁÄr Æ…È‘¡IÄÑXÍnœË_ŸzÀ"ªá£ÖߦWA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Open16.gif0000644000175000017500000000034407731544722023404 0ustar frankiefrankieGIF89a³ÿÿÿÿÿæÌôÝÆóÜÅ̽®Ì´šÌ³š¬™†«˜†«˜…™Š{f33ÀÀÀ!ù ,@>°ÉI«d kÍ ¶Ô"Šcžè®¶‡à¦q‚I³À ˜Ú¨R)ª!Ür;_ &Û „¥äÅR"!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/Open24.gif0000644000175000017500000000071607731544722023406 0ustar frankiefrankieGIF89aÕÿÿÿÿÿçÍÿæÍÿæÌþåËýäËüãÊûâÊúáÉøàÈöÞÇóÛÅðÚÃïØÂí×ÁëÕÀèÔ¿äмâλà͹Þ˸ÚÈ¶×Æ´ÕijÓ²ÑÁ±ÐÀ°Ì½®Ì´šÌ³šÌ³™Ì²™Ë²™Ê±˜È°—Ç®–Å­•딾¨‘¼¦º¤¸¢Ž¸¢·¢¶¡Œ²Š¯›‰®š‡¬™†ª—…¢‘€ žŽ~}™Š{f33ÀÀÀ!ù9,@˜ÀœpH,9œr©8Ÿ ˆ£QVN6 j¼,´ ­‰,›¥Ðtºº‘Õp¨yN?ÞîøÛQ¦UP[Z+anC8b3'#1ˆ†D8 Z™ _}‰•u ¡¢£¤¡yySTq[ƒc©BL²³}•|‰2&Ž#ˆ¯–b€™/bUŸI+ " .`žÌI³ÙK°¥ÝHA!þOCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;openacs-5.7.0/packages/acs-subsite/www/resources/email_open.gif0000644000175000017500000000203510622143341024424 0ustar frankiefrankieGIF89a÷£–Öÿ€¤ØùûýxžÒPŒÈÐáøvœÑõùüíóøîóùN‰Äñõúò÷þæðüïóùÀÛüp—ÍÉÞ÷`}ª[ˆ¶÷úüíòù¹ÏìÙåõz ×ðõû…ªá—µã«ÄéP‰ÄóöûQŒÈôøûðôùQ‹ÇäìõÓåý‘¯àìôøÄÕîP}Å£À꡼ä³Ëí=p¾FvÂC}ÂÒãùÁÓímµñõüvœÔÄÛø±Å㘷äp–ÐÙäñØèýÍÛñ„§ÙæíøÐáùßëþøûþÞëþæîùÝêþÜëþj•Ój“Ì÷ùüó÷ûòöûo—ÍçðüQÂÖçýžµÜïôùn–ÍÛêýãëóÆßü¦Âé|ÓR³÷QˆÀwЩÅêÎÚëÔßïßìþJ„Äéï÷fŽÌµËì×èýÍàøÜåòÍÜó±Íñó÷þó÷üµËíLˆÄóøÿæìö³Êë–¶åùûþìòøèîö³Ëêîóø¼Ðìt›Ð{¡×•¼ð²Ìñ£¿çp—ÎàèóMˆÄxÑÚæöøûý| ÑøúýûüÿõùþPŒÉ[†Éùüÿìñ÷ëñúE€Ã?y¿ñ÷ûÔæýÿÿÿÿÿÿ!ù£,úG 8ÅGŠ &„Á;B&Ta„Á¦KVN”裰S=|5h€‰Ð¤AFq4`€$Šq©Œš£6ø 3@”ÏŸ>!0¸¡Œ¥$DX àQf<0™°æ‹’¤T )Ž(1[ž|p"`Q „ a(ŒŒL¨#€D£!Ê,X  6Ð$àN( ‹(€!ƒ‚QèAEPP˜CxÃ# ‚-(½°P`LfÌ‚,)”‰ÅD:äT¹RDK–3PðB#b¢@yqàÀŒ.(p‚3A’Ÿ\x"2çO$ :´©!! ;openacs-5.7.0/packages/acs-subsite/www/resources/bold-button.gif0000644000175000017500000000015707725607455024575 0ustar frankiefrankieGIF89a‘ÿÿÿôòïfff!ù,@Œ©Ë£œÑK…Åè“ ¢x}F¨Ù&:™ ÇläÖø å¤ Š‰^¿Ï3*ƒÒ±ÙC$§Ô©ãŠÍ" ;openacs-5.7.0/packages/acs-subsite/www/group-master.adp0000644000175000017500000001273210725062137022742 0ustar frankiefrankie doc body @head;noquote@ @focus;noquote@ @skip_link;noquote@
    @system_name@ @system_name@
    Begin main content
    @user_messages.message;noquote@
    TODO: remove this and add a more systematic / package independent way TODO of getting this content here
    openacs-5.7.0/packages/acs-subsite/www/group-master.tcl0000644000175000017500000001034310771246353022761 0ustar frankiefrankie# Expects properties: # doc(title) # focus # head # section # subnavbar_link # # Allowed properties # skip_link, href of link to skip to. Should be of format #skip_link # defaults to #content-wrapper # DRB: This is a TEMPORARY kludge to get 5.3.2 out. This should really set the navigation # tab info then "master" to the site default-master, not site-master. However, Lee's first # implementation of the new master scheme only provides for a single-level tab system for # tab navigation, rather than the two-level tab system implemented by the group master template. # This should be generalized and ideally, someday, tied in with portal navigation. # But for now - kludge city. set system_name [ad_system_name] if {[ad_conn url] eq "/"} { set system_url "" } else { set system_url [ad_url] } if {[template::util::is_nil title]} { # TODO: decide how best to set the lang attribute for the title set title [ad_conn instance_name] } if {![template::multirow exists link]} { template::multirow create link rel type href title lang media } set untrusted_user_id [ad_conn untrusted_user_id] set sw_admin_p 0 if { $untrusted_user_id == 0 } { # The browser does NOT claim to represent a user that we know about set login_url [ad_get_login_url -return] } else { # The browser claims to represent a user that we know about set user_name [person::name -person_id $untrusted_user_id] set pvt_home_url [ad_pvt_home] set pvt_home_name [_ acs-subsite.Your_Account] set logout_url [ad_get_logout_url] # Site-wide admin link set admin_url {} set sw_admin_p [acs_user::site_wide_admin_p -user_id $untrusted_user_id] if { $sw_admin_p } { set admin_url "/acs-admin/" set devhome_url "/acs-admin/developer" set locale_admin_url "/acs-lang/admin" } else { set subsite_admin_p [permission::permission_p \ -object_id [subsite::get_element -element object_id] \ -privilege admin \ -party_id $untrusted_user_id] if { $subsite_admin_p } { set admin_url "[subsite::get_element -element url]admin/" } } } # # User messages # util_get_user_messages -multirow user_messages # # Set acs-lang urls # set acs_lang_url [apm_package_url_from_key "acs-lang"] set num_of_locales [llength [lang::system::get_locales]] if {$acs_lang_url eq ""} { set lang_admin_p 0 } else { set lang_admin_p [permission::permission_p \ -object_id [site_node::get_element \ -url $acs_lang_url \ -element object_id] \ -privilege admin \ -party_id [ad_conn untrusted_user_id]] } set toggle_translator_mode_url [export_vars \ -base ${acs_lang_url}admin/translator-mode-toggle \ {{return_url [ad_return_url]}}] set package_id [ad_conn package_id] if { $num_of_locales > 1 } { set change_locale_url [export_vars -base $acs_lang_url {package_id}] } # # Change locale link # if {[llength [lang::system::get_locales]] > 1} { set change_locale_url [export_vars -base "/acs-lang/" {package_id}] } # # Who's Online # set num_users_online [lc_numeric [whos_online::num_users]] set whos_online_url "[subsite::get_element -element url]shared/whos-online" if { ![info exists section] } { set section {} } if { ![info exists subnavbar_link] } { set subnavbar_link {} } # This will set 'sections' and 'subsections' multirows subsite::define_pageflow -section $section subsite::get_section_info -array section_info # # Context bar # if {[info exists context]} { set context_tmp $context unset context } else { set context_tmp {} } ad_context_bar_multirow -- $context_tmp # # Curriculum specific bar # TODO: remove this and add a more systematic / package independent way # TODO of getting this content here # set curriculum_bar_p [expr { [site_node::get_package_url -package_key curriculum] ne "" }] # Find the subsite we belong to set subsite_url [site_node_closest_ancestor_package_url] array set subsite_sitenode [site_node::get -url $subsite_url] set subsite_node_id $subsite_sitenode(node_id) set subsite_name $subsite_sitenode(instance_name) if {[ad_conn url] eq $subsite_url} { set subsite_url {} } if {![info exists skip_link]} { set skip_link "#content-wrapper" }openacs-5.7.0/packages/acs-subsite/www/register/0000755000175000017500000000000011724401447021447 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/www/register/auto-login.tcl0000644000175000017500000000123210551254401024220 0ustar frankiefrankiead_page_contract { Log in a user without the timestamp protection of the /register/index page. Useful when you need to log in a user from a different server. @author Peter Marklund } { email password {return_url "/"} } array set auth_info [auth::authenticate \ -return_url $return_url \ -email [string trim $email] \ -password $password] if {$auth_info(auth_status) eq "ok"} { ad_returnredirect $return_url ad_script_abort } else { # Login problem - redirect to login form ad_returnredirect [export_vars -base /register { email return_url }] } openacs-5.7.0/packages/acs-subsite/www/register/explain-persistent-cookies.adp0000644000175000017500000000057707717247024027444 0ustar frankiefrankie #acs-subsite.lt_Saving_email_address_# #acs-subsite.at# @home_link;noquote@ #acs-subsite.lt_Saving_email_address_#

    #acs-subsite.lt_Our_server_can_tell_y#

    #acs-subsite.lt_It_would_be_a_very_ba#

    #acs-subsite.lt_Note_that_you_can_era#

    openacs-5.7.0/packages/acs-subsite/www/register/explain-persistent-cookies.tcl0000644000175000017500000000056207253523116027446 0ustar frankiefrankiead_page_contract { Prepare some datasources for the explain-persistent-cookies .adp @author Bryan Quinn (bquinn@arsdigita.com) @creation-date Mon Oct 16 09:27:34 2000 @cvs-id $Id: explain-persistent-cookies.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ } { } -properties { home_link:onevalue } set home_link [ad_site_home_link] ad_return_template openacs-5.7.0/packages/acs-subsite/www/register/email-confirm.adp0000644000175000017500000000031410626736346024666 0ustar frankiefrankie {#acs-subsite.Email_Confirmation#} openacs-5.7.0/packages/acs-subsite/www/register/email-confirm.tcl0000644000175000017500000000073410626736346024712 0ustar frankiefrankiead_page_contract { Page for users to register themselves on the site. @cvs-id $Id: email-confirm.tcl,v 1.11 2007/05/29 05:40:54 maltes Exp $ } { token:notnull,trim user_id:integer {return_url ""} } set subsite_id [ad_conn subsite_id] set email_confirm_template [parameter::get -parameter "EmailConfirmTemplate" -package_id $subsite_id] if {$email_confirm_template eq ""} { set email_confirm_template "/packages/acs-subsite/lib/email-confirm" } openacs-5.7.0/packages/acs-subsite/www/register/account-message.adp0000644000175000017500000000041407743742277025231 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    @message;noquote@

    » #acs-subsite.lt_Continue_working_with# openacs-5.7.0/packages/acs-subsite/www/register/account-message.tcl0000644000175000017500000000044507727652475025255 0ustar frankiefrankiead_page_contract { Inform the user of an account status message. @cvs-id $Id: account-message.tcl,v 1.1 2003/09/10 16:45:49 lars Exp $ } { {message:allhtml ""} {return_url ""} } set page_title "Logged in" set context [list $page_title] set system_name [ad_system_name] openacs-5.7.0/packages/acs-subsite/www/register/recover-password.adp0000644000175000017500000000067707743742277025473 0ustar frankiefrankie @page_title@ @context@ @focus;noquote@

    #acs-subsite.Enter_your_username_to#

    @recover_info.password_message@

    #acs-subsite.To_log_in_visit_the# #acs-subsite.login_page#.

    openacs-5.7.0/packages/acs-subsite/www/register/recover-password.tcl0000644000175000017500000000562611301606175025465 0ustar frankiefrankiead_page_contract { Recover forgotten password. @author Simon Carstensen @creation-date 2003-08-29 @cvs-id $Id: recover-password.tcl,v 1.12 2009/11/20 21:39:09 michaels Exp $ } { {authority_id:integer ""} {username ""} {email ""} } set page_title [_ acs-subsite.Reset_Password] set context [list $page_title] # display error if the subsite doesn't allow recovery of passwords set subsite_id [subsite::get_element -element object_id] set email_forgotten_password_p [parameter::get \ -parameter EmailForgottenPasswordP \ -package_id $subsite_id \ -default 1] if {[string is false $email_forgotten_password_p]} { ad_return_forbidden Forbidden "Emailing passwords is not allowed" ad_script_abort } # Display form to collect username and authority set authority_options [auth::authority::get_authority_options] if { ![exists_and_not_null authority_id] } { set authority_id [lindex [lindex $authority_options 0] 1] } ad_form -name recover -edit_buttons [list [list [_ acs-kernel.common_continue] ok]] -form { {dummy:text(hidden),optional} } set username_widget text if { [parameter::get -parameter UsePasswordWidgetForUsername -package_id [ad_acs_kernel_id]] } { set username_widget password } set focus {} if { [auth::UseEmailForLoginP] } { ad_form -extend -name recover -form [list [list email:text($username_widget) [list label "Email"]]] set user_id_widget_name email set focus "email" } else { if { [llength $authority_options] > 1 } { ad_form -extend -name recover -form { {authority_id:integer(select) {label {[_ acs-kernel.authentication_authority]}} {options $authority_options} } } } ad_form -extend -name recover -form [list [list username:text($username_widget) [list label "Username"]]] -validate { {username { ![empty_string_p [acs_user::get_by_username -authority_id $authority_id -username $username]] } { Could not find username at authority } } } set user_id_widget_name username set focus "username" } set focus "recover.$focus" set submission_p 0 ad_form -extend -name recover -on_request {} # We handle form submission here, because otherwise we can't handle both the case where we use the form # and the case where we don't in one go if { [form is_valid recover] || (![form is_submission recover] && ([exists_and_not_null username] || [exists_and_not_null email])) } { array set recover_info [auth::password::recover_password \ -authority_id $authority_id \ -username $username \ -email $email] set login_url [ad_get_login_url -authority_id $authority_id -username $username] } set system_owner [ad_system_owner] openacs-5.7.0/packages/acs-subsite/www/register/user-join.adp0000644000175000017500000000025107663155371024057 0ustar frankiefrankie #acs-subsite.Join_group_name# @context;noquote@ openacs-5.7.0/packages/acs-subsite/www/register/user-join.tcl0000644000175000017500000001470010551254401024061 0ustar frankiefrankie# /packages/acs-subsite/www/admin/relations/add.tcl ad_page_contract { Add the user to the subsite application group. @author oumi@arsdigita.com @author Randy O'Meara @creation-date 2000-2-28 @cvs-id $Id: user-join.tcl,v 1.12 2007/01/10 21:22:09 gustafn Exp $ } { {group_id:integer {[application_group::group_id_from_package_id]}} {rel_type:notnull "membership_rel"} {return_url {}} } -properties { context:onevalue role_pretty_name:onevalue group_name:onevalue export_form_vars:onevalue } -validate { rel_type_valid_p { if { ![relation_type_is_valid_to_group_p -group_id $group_id $rel_type] } { ad_complain "[_ acs-subsite.lt_Cannot_join_this_grou]" } } } set user_id [auth::require_login] group::get -group_id $group_id -array group_info # Need these as local vars for some of the message keys below set group_name $group_info(group_name) set join_policy $group_info(join_policy) if { [exists_and_not_null return_url] } { set ret_link "Return to previous page." } else { set ret_link "" } if {$join_policy eq "closed"} { ad_return_error [_ acs-subsite.Closed_group] "[_ acs-subsite.This_group_is_closed]

    $ret_link" ad_script_abort } set context [list "[_ acs-subsite.Join_group_name]"] #---------------------------------------------------------------------- # Build up a form asking for relevant attributes #---------------------------------------------------------------------- template::form create join relation_required_segments_multirow \ -datasource_name required_segments \ -group_id $group_id \ -rel_type $rel_type set num_required_segments [multirow size required_segments] if { [form is_request join] } { for { set rownum 1 } { $rownum <= $num_required_segments } { incr rownum } { set required_seg [multirow get required_segments $rownum] if { ![group::member_p -group_id $required_segments(group_id)] } { if {$required_segments(join_policy) eq "closed"} { ad_return_error [_ acs-subsite.Closed_group] "[_ acs-subsite.This_group_is_closed]

    $ret_link" ad_script_abort } # we need to add a rel_id element for the relation to # create because add_form_elements only adds elements for # attributes and id_column is not an attribute element create join seg_$required_segments(segment_id).rel_id \ -widget hidden \ -optional # add any additional attributes we want to capture when a # user joins attribute::add_form_elements \ -form_id join \ -variable_prefix seg_$required_segments(segment_id) \ -start_with relationship \ -object_type $required_segments(rel_type) } } } # don't show the form if all elements are hidden set not_hidden 0 attribute::add_form_elements \ -form_id join \ -start_with relationship \ -object_type $rel_type if { [form size join] > 0 } { foreach var { group_id rel_type return_url } { template::element create join $var \ -value [set $var] \ -datatype text \ -widget hidden } foreach elm [form get_elements join] { if {[element get_property join $elm widget] ne "hidden"} { incr not_hidden } } } # Empty form means nothing to ask for, don't have to submit first if { $not_hidden == 0 || [template::form is_valid join] } { db_transaction { #---------------------------------------------------------------------- # Join all required segments #---------------------------------------------------------------------- for { set rownum 1 } { $rownum <= $num_required_segments } { incr rownum } { set required_seg [template::multirow get required_segments $rownum] if { ![group::member_p -group_id $required_segments(group_id)] } { switch $required_segments(join_policy) { "needs approval" { set member_state "needs approval" } "open" { set member_state "approved" set return_url [ad_conn package_url] } default { # Should have been caught above ad_return_error [_ acs-subsite.Closed_group] "[_ acs-subsite.This_group_is_closed]

    $ret_link" ad_script_abort } } set rel_id [relation_add \ -form_id join \ -variable_prefix seg_$required_segments(segment_id) \ -member_state $member_state \ $required_segments(rel_type) \ $required_segments(group_id) \ $user_id] } } #---------------------------------------------------------------------- # Join the actual group #---------------------------------------------------------------------- if { [permission::permission_p -object_id $group_id -privilege "admin"] } { set member_state "approved" if {$rel_type eq "membership_rel"} { # If they already have admin, bump them to an admin_rel set rel_type "admin_rel" } } else { if {$join_policy eq "needs approval"} { set member_state "needs approval" } else { set member_state "approved" } } group::add_member \ -group_id $group_id \ -user_id $user_id \ -rel_type $rel_type \ -member_state $member_state } on_error { global errorInfo ns_log Error "user-join: Error when adding user to group: $errmsg\n$errorInfo" ad_return_error "Error Joining" "We experienced an error adding you to the group." ad_script_abort } switch $member_state { "approved" { set message "You have joined the group \"$group_name\"." } "needs approval" { set message "Your request to join group \"$group_name\" has been submitted." } } ad_returnredirect -message $message $return_url ad_script_abort } openacs-5.7.0/packages/acs-subsite/www/register/restore-bounce.adp0000644000175000017500000000036310606357624025100 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    #acs-mail-lite.Bounce_disabled#

    » #acs-subsite.Continue#

    openacs-5.7.0/packages/acs-subsite/www/register/restore-bounce.tcl0000644000175000017500000000105310606357624025113 0ustar frankiefrankiead_page_contract { The page restores a user from the deleted state. @cvs-id $Id: restore-bounce.tcl,v 1.1 2007/04/09 06:39:16 maltes Exp $ } { {return_url {[ad_pvt_home]}} } set page_title [_ acs-mail-lite.Restore_bounce] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] # We do require authentication, though their account will be closed set user_id [auth::require_login] db_dml unbounce_user "update users set email_bouncing_p = 'f' where user_id = :user_id" # Used in a message key set system_name [ad_system_name] openacs-5.7.0/packages/acs-subsite/www/register/index.adp0000644000175000017500000000047410724051613023244 0ustar frankiefrankie #acs-subsite.Log_In# {#acs-subsite.Log_In#} openacs-5.7.0/packages/acs-subsite/www/register/index.tcl0000644000175000017500000000065010724051613023256 0ustar frankiefrankiead_page_contract { Prompt the user for email and password. @cvs-id $Id: index.tcl,v 1.13 2007/11/30 18:16:43 daveb Exp $ } { {authority_id ""} {username ""} {email ""} {return_url ""} } set subsite_id [ad_conn subsite_id] set login_template [parameter::get -parameter "LoginTemplate" -package_id $subsite_id] if {$login_template eq ""} { set login_template "/packages/acs-subsite/lib/login" } openacs-5.7.0/packages/acs-subsite/www/register/account-closed.adp0000644000175000017500000000017511525000555025035 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ openacs-5.7.0/packages/acs-subsite/www/register/account-closed.tcl0000644000175000017500000000040311525000555025045 0ustar frankiefrankiead_page_contract { Inform the user that his/her account is closed @cvs-id $Id: account-closed.tcl,v 1.9 2011/02/10 15:17:01 daveb Exp $ } { } set page_title [_ acs-subsite.Account_closed_title] set context [list [_ "acs-kernel.common_Register"]] openacs-5.7.0/packages/acs-subsite/www/register/display-message.adp0000644000175000017500000000036107731312375025230 0ustar frankiefrankie @page_title@ @context;noquote@

    @message;noquote@

    » @continue_label@ openacs-5.7.0/packages/acs-subsite/www/register/user-new.adp0000644000175000017500000000041710617276240023705 0ustar frankiefrankie #acs-subsite.Register# {#acs-subsite.Register#} register.email openacs-5.7.0/packages/acs-subsite/www/register/user-new.tcl0000644000175000017500000000115110617276240023717 0ustar frankiefrankiead_page_contract { Page for users to register themselves on the site. @cvs-id $Id: user-new.tcl,v 1.22 2007/05/06 06:58:40 maltes Exp $ } { {email ""} {return_url [ad_pvt_home]} } set registration_url [parameter::get -parameter RegistrationRedirectUrl] if {$registration_url ne ""} { ad_returnredirect [export_vars -base "$registration_url" -url {return_url email}] } set subsite_id [ad_conn subsite_id] set user_new_template [parameter::get -parameter "UserNewTemplate" -package_id $subsite_id] if {$user_new_template eq ""} { set user_new_template "/packages/acs-subsite/lib/user-new" } openacs-5.7.0/packages/acs-subsite/www/register/user-new.xql0000644000175000017500000000051107467631421023745 0ustar frankiefrankie select parties.party_id as user_id, persons.first_names, persons.last_name from parties, persons where parties.party_id = persons.person_id and parties.email = lower(:email) openacs-5.7.0/packages/acs-subsite/www/register/restore-user.adp0000644000175000017500000000037207743742277024615 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    #acs-subsite.Account_reopened_message#

    » #acs-subsite.Continue#

    openacs-5.7.0/packages/acs-subsite/www/register/restore-user.tcl0000644000175000017500000000205007734332774024623 0ustar frankiefrankiead_page_contract { The page restores a user from the deleted state. @cvs-id $Id: restore-user.tcl,v 1.5 2003/09/24 15:19:24 lars Exp $ } { {return_url {[ad_pvt_home]}} } set page_title [_ acs-subsite.Account_reopened_title] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] # We do require authentication, though their account will be closed set user_id [auth::require_login -account_status closed] set member_state [acs_user::get_element -user_id $user_id -element member_state] switch $member_state { deleted { # They presumably deleted themselves # Note that the only transition allowed if from deleted # to authorized. No other states may be restored acs_user::approve -user_id $user_id } approved { # May be a double-click } default { ad_return_error "[_ acs-subsite.lt_Problem_with_authenti]" "[_ acs-subsite.lt_There_was_a_problem_w]" } } auth::verify_account_status # Used in a message key set system_name [ad_system_name] openacs-5.7.0/packages/acs-subsite/www/register/logout.tcl0000644000175000017500000000075510551254401023464 0ustar frankiefrankie# /www/register/logout.tcl ad_page_contract { Logs a user out @cvs-id $Id: logout.tcl,v 1.4 2007/01/10 21:22:09 gustafn Exp $ } { {return_url ""} } if { $return_url eq "" } { if { [permission::permission_p -object_id [subsite::get_element -element package_id] -party_id 0 -privilege read] } { set return_url [subsite::get_element -element url] } else { set return_url / } } ad_user_logout db_release_unused_handles ad_returnredirect $return_url openacs-5.7.0/packages/acs-subsite/acs-subsite.info0000644000175000017500000003573411575167337022125 0ustar frankiefrankie Subsite Subsite Services t f t OpenACS Subsite 2011-06-12 OpenACS Provides for creating subsites within the OpenACS Community System. Aware of parties, groups, users, portraits. Can be themed via a per subsite master template. GPL 3 openacs-5.7.0/packages/acs-subsite/catalog/0000755000175000017500000000000011724401447020411 5ustar frankiefrankieopenacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.pa_IN.utf-8.xml0000644000175000017500000000066510727201372025310 0ustar frankiefrankie ਗà©à¨ªà¨¤-ਕੋਡ, ਈ-ਮੇਲ, ਪੋਰਟਰੇਟ ਲਾਗਆਉਟ %system_name% ਤੋਂ ਲਾਗ ਆਉਟ %user_name% ਜੀ ਆਇਆਂ ਨੂੰ openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.eu_ES.ISO-8859-1.xml0000644000175000017500000005233110727201372025557 0ustar frankiefrankie , edo Informazio basikoa eguneratu %system_name% komunitatean erregistro data: Zuri buruz Zure kontua %system_name%(e)n itxita izan da Ez, eraman nazazu %pvt_home_name%(e)ra Bai, nere kontua itxi <p>Zure kontua itxita dago.</p><p>Hala nahi baduzu, zure kontua <a href="%restore_url%">berrireki</a> dezakegu.</p> <p><font color="red"> <b> Zure kontua itxita dago. </b> </font> <a href="%login_url%">Sar zaitez</a> berriro ikusteko zer egin dezakezun. </p> Zure kontua %system_name%(e)n berrireki da. Ongi etorri berriro. Kontua berrirekita Ekintza Aplikazio berria gehitu Kontrol-panela %subsite_name% kudeatu Erabiltzaile honetarako kudeaketa-aukerak Abisu mota beste argazki bat. Erantzuna Aplikazioaren errorea Aplikazioak Onartu ondokoan: Autoritatea Pasahitz okerra Debekatu Informazio Basikoa Biografia Ezin da autoritate lokaletik pasahitza lortzea. Ezin da partaideen zerrenda ikusi Hizkuntza aldatu Nere pasahitza aldatu Pasahitza, e-posta, argazkia aldatu Begira ezazu zure sarrera-erretilua "umeak" <p>Mesedez, konfirma ezazu zure kontua itxi nahi duzula %system_name%-en.</p><p>Zure kontuaren ixteak, email abisurik bidaliko ez dizugula eta zure izena %system_name%(e)ko partaideen zerrendetan agertuko ez dela esan nahi du. Zuk sisteman egindako ekarpenak, aldiz, mantendu egingo dira komunitatearen historiaren parte bezela.</p><p>Kontuan izan zure kontua nahi duzunean berrireki ahal izango duzula, sisteman berriro sartuz.</p> Zure kontua itxi Itxitako taldea Iruzkina egin Komunitateak komunitateak komunitatea Konfirmatu Pasahitz berriaren hautaketa zuzena Jarraitu Jarraitu %pvt_home_name%(e)n Herrialdearen Izena %pretty_name% berria eratu Azpi-gune berria eratu Egungo Pasahitza <p>Zure online egoera ez da momentu honetan beste erabiltzaileengatik ikusgarria</p> <p>Zure online egoera momentu honeta beste erabiltzaileengatik ikusgarria da</p> Galdera pertsonalizatu Datu-base errorea "testuinguru" lehenetsia Ezabatu GarKud Garatzailearen kudeaketa Zuzeneko baimenak Desaktibatu Desaktibatuta Domeinua e-posta iruzkina aldatu Elementu batzuk ezin dira aldatu, %authority_name%(e)k kudeatzen bait ditu. e-posta Hauxe da zure sartze-informazio berria: %account_id_label%: %account_id% %password_label%: %password% Mesedez, bisita ezazu hurrengo esteka pasahitza orain aldatzeko: %reset_password_url% Eskerrik asko %system_name%(e)n erregistratzeagatik. Hona hemen zure sartze-informazioa %system_url%(e)n: %account_id_label%: %account_id% %password_label%: %password% Mesedez, bisita ezazu hurrengo esteka pasahitza orain aldatzeko: %reset_password_url% E-posta konfirmazioa e-posta ez da eskatu Ahaztu duzun pasahitza %system_name%(e)n Ongi etorri %system_name%(e)ra Aktibatuta Sar ezazu zure erabiltzaile-izena pasahitza berreskuratzeko Argazkia Ezabatu ezabatu argazkia Errorea Errorea e-posta bidaltzerakoan Iraungitzea Fitxategi-izena Izena Pasahitza ahaztu al duzu? Maiztasuna Atzera jo erabiltzailearen argazkia igo zure argazkia igo Eman Baimena eman Izkutatu Hasiera Nahi bazenu Informazioa eguneratuta Gonbidatu ISO Kodea ISO Kodeen Zerrenda ISO Kodeak ez daude kargatuak ISO kodeak ez dira kargatu Komunitatean sartu %group_name%(e)n parte hartu Azpi-gunean parte hartu Komunitate honetan sartu Azpi-gune honetan sartu Hitz gakoa Abizena beranduago. Komunitatea utzi Azpi-gunea utzi Komunitate hau utzi Azpi-gune hau utzi Atzera bota erabiltzailerik gehitu gabe Sartu sartu %system_name%(e)n sartu berriro sartu Sartze orria iraungitu egin da. Mesedez, sar zaitez berriro. Sartu edo erregistratu sartze-orria Irten %system_name%(e)tik irten , informazio gehiago lortuko duzu komunitatearen partaideari buruz Ezin duzu talde honetan parte hartu. ISO kodeen zerrenda osoa %system_name%(e)n lan egiten jarraitu %first_names% %last_name%(e)n argazkiaren iruzkina aldatu %first_names% %last_name% (%email%) erregistratu da %system_url%(e)ko erabiltzaile gisa Kudeatazaile orokorretarako %name%(e)n baimena eman Hau da datu-baseak esandakoa: Nola gustatuko litzaizuke munduak %first_names% %last_name% ikus dezan? Uste baduzu pertsonak oraindik konturk ez duela: Uste baduzu gonbidatu nahi duzun pertsonak jadanik sistema honetan kontu bat duela: Funtzionalitate hau behar baduzu, mesedez kargatu ezazu acs-reference eta ref-countries. Oinordetutako baimenak Aukera hau ez da egokia liburutegi edo eskola bateko ordenagailu partekatua erabiltzen ari bazara. Makina hori ondoren erabiliko zuen edozein erabiltzailek erabili ahal izango luke zerbitzu hori zure nortasunarekin. Erregistro berria %system_url%(e)n. Ohar zaitez gordetako e-posta eta pasahitza ezabatu ditzakezula zure lan ingurunearen "irten" aukeran sakatuz. %num_children% "ume" izkutatuta %portrait_publish_date%(e)n, <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> igo zenuen Gure zerbitzariak zure arakatzaileari e-posta eta pasahitza bezalako informazioa gorde-arazi diezaioke. Hau komenigarria da, zu bazara zure ordenagailua erabiltzen duen pertsona bakarra, ez duzulako informazio hori behin eta berriro sartzen ardurako beharko. Pasahitzaren konfirmazioa URL pertsonala: Mesedez, aukera ezazu zure herrialdearen kodea behean zerrendatutakoen artean. Jarraiean, sakatu ezazu zure arakatzailearen "atzera" botoia aurreko formulariora bueltatzeko Mesedez, irakur itzazu e-posta honetako aginduak. Mesedez, saia zaitez berriro <a href="index">sartzen</a> %first_names% %last_name%(e)n argazkia Hierarkian gorago dauden pribilegioak, beherago daudenak barne dute, hau da, kudeaketarako baimena ematen duzunean, irakurtzeko eta idazteko baimenak automatikoki ematen dira. Autentifikazioarekin arazoak Zerbitzu honetarako erregistrazio informazioa bidali berri da %email%(e)ra. Zerbitzu honetarako erregistrazio informazioa bidali da %email%(e)ra. Zure erregistrazio eskakizuna %system_name%(e)ko kudeatzaileari bidali zaio. Oraindik onarpenaren zai dago. E-posta helbidea eta pasahitza gordetzen Erakutziezu %system_name%(e)ko partaideei nolakoa zaren: Sentitzen dugu, baina badirudi %system_name%(e)n debekatua izan zarela Ziur al zaude argazki pertsonal hau ezabatu nahi duzulaz? Ziur al zaude zure argazkia ezabatu nahi duzulaz? Sistema honetan dagoen zure argazkia ez da zuzena. Mesedez, Arazoren bat egon da zure kontua autentifikatzerakoan Hau da %system_name%(e)ko beste erabiltzaileei erakusten diegun argazkia Erabiltzaile honek ez du oraindik argazkirik. Nahi baduzu Erabiltzaile hau komunitatetik ezabatua eta debekatua izan da. Zure erregistrazioa konfirmatzeko, mesedez zoaz %confirmation_url%(e)ra Igo ezazu zure fitxategi gogokoena, JPEG edo GIF eskaneatua, zure ordenagailu pertsonalatik (kontutan izan ezin duzula Interneten dagoen argazki bat igo; argazki hau zure disko gogorrean egon behar da). Igota: %pretty_date% Igota: %publish_date% Erabil ezazu "Browse..." botoia zure fitxategia topatzeko, eta gero, "Open" aukeratu. Erabiltzaile honek biografia sartu du edo argazkia igo du Ezin izan zaitugu topatu (user %user_id%) erabiltzaileen taulan. Seguraski zure kontua ezabatua izan da. Arazoren bat izan dugu zure sarrera prozesatzen. Ez genuen zure e-posta espero. Erroreren bat egon omen da. Ongi etorri %system_name%(e)ra Zer ikusten duten besteek zure izena klikatzean Ezin duzu &lt; izan zure izenean, horrek HTML etiketaren itxura duelako eta beste erabiltzaileak konfundiaraziko lukeelako. Ezin duzu &lt; izan zure abizenean, horrek HTML etiketaren itxura duelako eta beste erabiltzaileak konfundiaraziko lukeelako. Ez duzu posta elektronikorik jasoko %pretty_date% arte. Zure e-posta konfirmatuta izan da. Orain %system_name%(e)n sar zaitezke. Zure e-posta konfirmatuta izan da. Orain %system_name%(e)ko kudeatzailearen onarpenaren zai zaude Zure e-posta konfirmatuta dago Zure sarrera inraungitu da. Mesedez, sar ezazu berriro zure pasahitza. Zure URL-ak ez du formato zuzena. URL zuzen batek hurrengo itxura dauka: "%valid_url_example%". Kudeatzailea egin Partaidea egin Zure burua ikustezina egin Zure burua ikusgarria egin Zure abisuak kudeatu Sentitzen dugu baina ezin duzu partaideen zerrenda ikusi. Partaide Egoera Partaideak Izena Pasahitz berria Aplikaziorik ez ISO koderik ez Pakete honek ez du parametrorik. zure argazkia %pretty_plural%(e)rik ez Zerbitzurik ez hutsik Sartu gabe Oharrak: Oharra: %name%(e)n ondokora: (aukerakoa) Aukerak Edo erabiltzaile berria eratu edo Pasahitza Zure sartze-informazioa %system_name%(e)n: %account_id_label%: %account_id% Zure pasahitza kontu honetarako duela gutxi aldatuta izan da. Ez duzu ezer egin beharrik, mezu hau bakarrik notifikazio bat da zure kontuaren segurtasuna babesteko. --------------- Nahi duzunean alda dezakezu zure pasahitza ondoko moduan: 1. %system_name%(e)n sartu 2. "%pvt_home_name%" estekan klikatu 3. "%password_update_link_text%" aukeratu Pasahitza aldatuta Baimenak baimenak %name%(e)rako baimenak %home_link%(e)ra bueltatu. Argazkia Perfila Galdera Berraktibatu Pasahitza berreskuratu Sartzea "freskatu" Erregistratu <p> Eskerrik asko erregistratzeagatik %system_name%(e)n. Kudeatzaile bati jakinarazi zaio zure eskaera</p>. <p> Onartzen zaituenean, e-posta mezu bat jasoko duzu eta %system_name% erabiltzen hasi ahal izango duzu</p> Ezetsi Nere sartzea gogoratu ordenagailu honetan Ezabatu Komunitate honetan parte-hartzea eskatu. Azpi-gune honetan parte-hartzea eskatu. Parte-hartzea eskatu aplikaziora bueltatu Aukeratuak desaukeratu Rola Iruzkina gorde ezizena Sistemako erabiltzailea bilatu Objetu bat aukeratu id-aren bidez Erabiltzaile honi posta bidali Erakutsi Kudeaketa orokorra Sentitzen dugu, ezin zaitugu lagundu ahaztutako pasahitzarekin Egoera Argazkiaren istorioa Argazkiaren istorioa Azpi-komunitateak azpi-komunitateak azpi-komunitatea azpi-gunea Azpi-guneak azpi-guneak Eskerrik asko. ISO kodeak ez daude kargatuak zerbitzari honetan Talde hau itxita dago. Partaideek bakarrik ahal dute lortu sarrera gonbidapenaren bitartez azpi-gune hau Erabiltzaile honek komunitatea utzi du Sartzeko, bisita ezazu Atala motaren araberako informazioa GORA igo %context_name%(e)ra Eguneratu Pasahitza eguneratu igo igo argazkia argazki ordezkaria igo Argazkia Igo Erabiltzaile izena Opor informazioa Eguneratuta Zure opor informazioa %site_link%(e)n eguneratuta izan da Ongi etorri, %user_name% Kontrol-laukia aukeratzen ez duzunean, pribilegio hori kendu egiten zaio partaide horri, baldin eta aurretik eman bazaio. Momentuan online dauden erabiltzaileak Nor dago online Bai, ziur nago Ondoko taldeetan partaide zara: Nahi duzunean ber-ireki dezakezu honela: Ez duzu kudeaketa baimenik %root% objetuan edo bere "umeetako" bateren batean Ez duzu oraindik argazkirik. Ahal duzu Ondoko objetutan kudeaketa baimena duzu: Momentu honetan ez duzu e-posta abisuak erregistratuta. Zure kontua Foroetan dituzun abisuak Zure Argazkia Zure abisuak %gc_system_name%(e)n Oporretatik bueltan bezela agertzen zara %site_link%(e)n. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.th_TH.utf-8.xml0000644000175000017500000000072510727201372025325 0ustar frankiefrankie เปลี่ยนรหัสเข้า อีเมล์ รูปภาพ ออà¸à¸ˆà¸²à¸à¸£à¸°à¸šà¸š ออà¸à¸ˆà¸²à¸ %system_name% ยินดีต้อนรับ, %user_name% openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.da_DK.ISO-8859-1.xml0000644000175000017500000005207210727201372025523 0ustar frankiefrankie , eller Opdater Oplysninger Medlem af %system_name% siden Biografi Din konto i %system_name% er blevet lukket. Nej, jeg vil tilbage til %pvt_home_name% Ja, luk venligst min konto <p>Din konto er i øjeblikket lukket.</p> <p>Hvis du vil, kan vi <a href="%restore_url%">genåbne kontoen</a>.</p> <p> <font color="red"><b>Din konto er i øjeblikket lukket.</b></font> <a href="%login_url%">Log ind</a> igen for at se hvad du kan gøre ved det.</p> Din konto på %system_name% er blevet genåbnet. Velkommen tilbage. Konto Genåbnet Handling Tilføj ny applikation Admin Administrer %subsite_name% Administrative muligheder for denne bruger Alarmtype et billede til. Svar: Fejl i Applikation Applikationer Godkend Autoritet Forkert Adgangskode Bandlys Stamoplysninger Biografi Overførsel af adgangskode fra den lokale autoritet er ikke understøttet. Kan ikke se medlemslisten Skift sprog Ændre min adgangskode Skift kodeord, e-mail-adresse, portræt Tjek din indbakke Børn <p> Bekræft venligst at du gerne vil lukke din konto på %system_name%. </p> <p> Lukning af din konto indebærer at vi ikke længere vil sende dig beskeder med e-mail. Du vil heller ikke optræde på medlemslisten på %system_name%. Dine bidrag til gruppen vil dog blive bevaret, da de er en del af gruppens historik. </p> <p>Bemærk at du når som helst kan genåbne din konto ved simpelthen at logge ind igen. Luk din konto Lukket gruppe Kommentar Grupper grupper gruppe Bekræft: Du har valgt et nyt kodeord. Fortsæt Fortsæt til %pvt_home_name% Land Opret nyt %pretty_name% Opret nyt undersite Nuværende adgangskode: <p> Din status er ikke synlig for andre brugere. </p> <p> Din status er synlig for andre brugere. </p> Tilpas spørgsmål Databasefejl standardkontekst Slet DevAdmin Udvikleradministration Direkte Rettigheder Deaktivér Inaktiv Domæne E-mail rediger kommentar Visse felter kan ikke redigeres fordi de styres af %authority_name%. E-mail Her er din nye logininformation: %account_id_label%: %account_id% %password_label%: %password% Klik venligst på følgende link for at ændre din adgangskode nu: %reset_password_url% Tak fordi du registrerede dig på %system_name%. Her er hvordan du logger ind på %system_url%: %account_id_label%: %account_id% %password_label%: %password% E-mailbeskræftelse E-mail blev ikke anmodet Din glemte adgangskode til %system_name% Velkommen til %system_name% Aktiv Indtast dit brugernavn for at generhverve din adgangskode. Slet Portræt slet portræt Fejl Fejl ved afsendelse af mail Udløber Filnavn Fornavn(e) Glemt din adgangskode? Frekvens Gå tilbage upload brugerens portræt indsend dit portræt Tildel Tildel Rettighed Skjul Hjemmeside Hvis du skulle Oplysninger Opdateret Invitér ISO-kode Liste over ISO-koder ISO-koder ikke indlæst ISO-koder ikke indlæst Tilmeld gruppe Meld ind i %group_name% Tilmeld dig dette undersite Tilmeld denne gruppe Tilmeld dette undersite Stikord Efternavn senere. Forlad gruppen Forlad undersite Forlad denne gruppe Forlad dette undersite Gå tilbage uden at tilføje brugere Log ind log ind Log ind på %system_name% logge ind igen Siden er udløbet. Prøv venligst at logge ind igen. Log ind eller tilmeld loginside Log ud Log ud fra %system_name% kan du få flere oplysninger om brugeren. Kan ikke tilmeldes denne gruppe. Fuldstændig liste over ISO-koder Fortsæt på %system_name% Rediger kommentar til portrættet af %first_names% %last_name% %first_names% %last_name% (%email%) registeret som bruger af %system_url% For administratorer for hele sitet Tildel rettighed til %name% Her er hvad databasen meldte tilbage: Hvordan vil du have at folk skal se %first_names% %last_name%? Hvis du ikke mener at personen allerede har en konto: Hvis du ved eller tror at personen du vil invitere, allerede har en konto på dette site: Hvis du har brug for denne funktionalitet, skal du installere acs-reference og ref-countries. Nedarvede Rettigheder Det ville være en meget dårlig idé at vælge denne mulighed hvis du bruger en delt computer på et bibliotek eller en skole. Alle senere brugere af denne computer vil kunne udgive sig for at være dig. Ny tilmelding på %system_url% Den røde tekst under parameterens indtastningsfelt angiver den parameterværdi som bliver tilsidesat af en linje i OpenACS's parameterfil. Brugen af parameterfilen frarådes, men visse sites behøver den for at oprette instansspecifikke værdier for parametrene uafhængigt af apm_parameter tabellerne. Bemærk at du kan slette den gemte e-mail-adresse og adgangskode ved at vælge "log ud" fra din arbejdsplads. %num_children% børn er skjult Den %portrait_publish_date% indsendte du <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Vores server kan fortælle din browser at den skal gemme visse oplysninger, såsom din e-mail-adresse og din adgangskode. Dette er smart, fordi du &mdash; hvis du er den eneste der bruger din computer &mdash; ikke bliver nødt til at fortælle os din e-mail-adresse og din kode hver gang du besøger siden. Bekræft Adgangskode URL til personlig hjemmeside: Find dit lands kode blandt dem på listen. Brug derefter din browsers "Tilbage"-knap for at returnere til formularen. Læs og følg venligst instruktionerne i denne e-mail. Prøv venligst at <a href="index">logge ind</a> igen Portræt af %first_names% %last_name% Rettigheder højere i hierarkiet medfører alle lavere rettigheder. Når du fx. tildeler administrationsrettigheder, medfører det automatisk læsning, skrivning, osv. Problem med godkendelse Tilmeldingsoplysninger til denne tjeneste er netop blevet sendt til %email%. Tilmeldelsesoplysninger til denne service er blevet sendt til %email%. Din tilmeldingsforespørgsel er sendt til administratoren på %system_name%. Den venter stadig på at blive godkendt. Gemmer e-mail-adresse og adgangskode Vis alle andre på %system_name% hvor godt du ser ud: Beklager, men det lader til at du er bandlyst fra %system_name%. Er du sikker på at du vil slette denne brugers portræt? Er du sikker på at du vil slette dit portræt? Billedet af dig i systemet er ugyldigt. Venligst Der opstod problemer ved godkendelse af din konto Dette er billedet vi viser til andre brugere på %system_name% Brugeren har ikke noget portræt endnu. Du kan Brugeren er slettet og bandlyst fra gruppen. Fortsæt venligt til %confirmation_url% for at bekræfte din tilmelding Indsend din ønskede fil, en scannet JPEG eller GIF, fra din computer (bemærk at du ikke kan henvise til et billde der ligger et andet sted på internettet; dette billede skal være på din computers harddisk). Indsendt: %pretty_date% Indsendt: %publish_date% Brug "Gennemse..."-knappen til at finde din fil, klik derefter på "Åbn". Denne bruger har indtastet en biografi eller uploaded et portræt Vi kan ikke finde dig (bruger %user_id%) i brugertabellen. Din konto er højst sandsynligt blevet slettet. Vi har et problem med din indtastning. Vi afventede ikke din e-mail. Der må være sket en fejl. Velkommen til %system_name% Hvad andre ser når de klikker på dit navn Du kan ikke have et &lt; i dit fornavn da dette vil se ud som HTML og derfor forvirre andre brugere. Du kan ikke have et &lt; i dit efternavn da dette vil se ud som HTML og derfor forvirre andre brugere. Du modtager ikke nogen e-mails før %pretty_date%. Din e-mail-adresse er blevet bekræftet. Du kan nu logge ind på %system_name%. Din e-mail-adresse er blevet bekræftet. Der ventes nu på godkendelse fra administratoren af %system_name%. Din e-mail-adresse er blevet bekræftet. Din adgang er udløbet. Indtast venligst dit kodeord igen for at fortsætte. Din URL har ikke det korrekte format. En gyldig URL vil se ud i retningen af \"%valid_url_example%\". Gør til administrator Gør til medlem Gør dig usynlig Gør dig synlig Rediger dine alarmer Beklager, men du må ikke se medlemslisten. Medlemsstatus Medlemmer Navn Ny Adgangskode Ingen applikationer Ingen ISO-koder Denne pakke har ikke nogen parametre. dit portræt Ingen %pretty_plural% Ingen tjenester ingen Ikke logget ind Noter: Meddelelse: på %name% til: (valgfri) Indstillinger Eller opret en ny bruger eller Adgangskode Dine informationer til log ind på %system_name%: %account_id_label%: %account_id% Din adgangskode til den konto er ændret for nyligt. Det er ikke nødvendigt for dig at gøre noget; du har kun fået denne besked for at beskytte din kontos sikkerhed. --------------- Du kan altid ændre din adgangskode ved at gøre følgende: 1. Log ind på %system_name% 2. Klik på linket til "%pvt_home_name%" 3. Vælg "%password_update_link_text%" Adgangskode ændret Rettigheder rettigheder Rettigheder for %name% Vend venligst tilbage til %home_link%. Portræt Profil Spørgsmål Genaktivér Gendan Adgangskode Forny login Tilmeld <p> Tak for tilmeldingen til %system_name%. En administrator har fået besked om din anmodning. </p> <p>Så snart du er blevet godkendt, vil du modtage en e-mail, og du kan fortsætte med at bruge %system_name%. Afvis Gem mit kodeord på denne computer Fjern Fjern alle Anmod om medlemskab af denne gruppe Anmod om medlemsskab af dette undersite Anmod om medlemskab vend tilbage til applikation Fjern markerede Rolle Gem kommentar Skærmnavn Søg efter en eksisterende bruger Sikkerhedskontekstens rod Vælg et objekt efter ID: Send e-mail til denne bruger Vis Administration for hele sitet Beklager, vi kan ikke hjælpe dig med den glemte adgangskode. Status Historien Bag Billedet Historien Bag Billedet Undergrupper undergrupper undergruppe undersite Undersites undersites Mange tak. ISO-koderne er ikke indlæst på denne server. Denne gruppe er lukket. Du kan kun få adgang ved at blive inviteret. dette undersite Brugeren har forladt gruppen. For at logge ind, besøg Emne typespecifikke oplysninger OP op til %context_name% Opdatér Opdater Adgangskode indlæs indsend et portræt indsend et erstatningsbillede Indsend Portræt Brugernavn Brugers Site Map Ferieoplysninger Opdateret Dine ferieoplysninger på %site_link% er blevet opdateret. Velkommen %user_name% Når du lader fluebenet være tomt, betyder det at rettigheden vil blive tilbagekaldt fra parten i tilfælde af at rettigheden før er blevet tildelt den pågældende part. Brugere der er online Hvem er Online Ja, jeg er sikker Du er i følgende grupper: Du kan også gennemse fra Du kan altid genåbne den ved at Du har ikke administrationsrettigheder på objektet %root% eller nogen af dets børn Du har endnu ikke et portræt. Du kan Du har administrationsrettigheder på følgende objekter: Du har ikke nogen e-mail-alarmer lige nu. Din Konto Dine alarmer på diskussionsfora Dit Portræt Dine alarmer på %gc_system_name% Du er markeret som tilbage fra ferie på %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.no_NO.ISO-8859-1.xml0000644000175000017500000005252110727201372025570 0ustar frankiefrankie , eller Oppdater grunnleggende informasjon En medlem av %system_name% gruppe siden Om deg Kontoen din ved %system_name% har blitt stengt. Nei, ta meg tilbake til %pvt_home_name% Ja, avslutt min konto <p>Kontoen din er stengt.</p> <p>Dersom du ønsker det, kan vi <a href="%restore_url%">åpne kontoen din igjen</a>.</p> <p> <font color="red"> <b> Kontoen din er stengt. </b> </font> <a href="%login_url%">Logg inn</a> igjen for å se hva du kan gjøre med det. </p&;gt; Din konto ved %system_name% har blitt gjenåpnet. Velkommen tilbake. Konto gjenåpnet Oppgave Legg til nytt program Admin Administrer %subsite_name% Administrative valg for denne brukeren Varsel type et annet bilde Svar: Programfeil Programmer Godkjenn Autoritet Feil passord Steng ute Generell informasjon Biografi Å hente passord fra lokal autoritet er ikke støttet. Kan ikke se medlemslisten Bytt språk Endre passordet mitt Endre passord, e-post, portrett Sjekk inn-post Barn <p> Vennligst bekreft at du ønsker å stenge kontoen din ved %system_name%. </p> <p> Å stenge kontoen betyr at vi ikke lenger vil sende e-postmeldinger til deg, og du vil ikke vises på listen over medlemmer ved %system_name%. Dine bidrag til gruppen vil likevel bli tatt vare på, siden de er en del av gruppens historie. </p> <p> Legg merke til at du kan gjenåpne kontoen din når som helst ved å logge deg inn igjen. </p> Steng din konto Stengt gruppe Kommentar Grupper grupper gruppe Bekreft: Nytt passord er registrert Fortsett Fortsett til %pvt_home_name% Navn på land Lag ny %pretty_name% Lag nu undergruppe Nåværende passord <p> Din status på nettet er nå ikke synlig for andre brukere. </p> <p> Din status på nettet er nå synlig for andre brukere </p> Tilpass spørsmål Databasefeil standard sammenheng Slett DevAdmin Utviklers administrasjon Direkte adgang Gjør uvirksom Uvirksom Område E-post rediger kommentar Noen elementer kan ikke redigeres, da de er under kontroll av %authority_name%. E-post Her er din nye innloggingsinformasjon: %account_id_label%: %account_id% %password_label%: %password% Vennligst følg følgende lenke for å forandre passord nå: %reset_password_url% Takk for at du har registrert deg ved %system_name%. Slik kan du logge inn på %system_url%: %account_id_label%: %account_id% %password_label%: %password% Vennligst følg følgende lenke for å forandre ditt passord nå: %reset_password_url% E-post bekreftelse E-post ikke bestilt Passordet du har glemt på %system_name% Velkommen til %system_name% Tilgjengelig Skriv inn ditt brukernavn for å starte gjenfinning av passord. Slett portrett slett portrett Feil Feil oppstod under sending av e-post Utløper Filnavn Fornavn Har du glemt passordet? Frekvens Gå tilbake gå og last opp brukerens portrett gå og last opp ditt portrett Gi Gi tillatelse Gjem Hjemmeside Dersom du skulle Informasjon oppdatert Inviter ISO-kode ISO kodeliste ISO-koder ikke lastet opp ISO-koder ikke lastet opp Delta i gruppe Bli medlem i %group_name% Delta i undergruppe Delta i denne gruppen Delta i denne undergruppen Nøkkel Etternavn seinere. Forlat gruppen Forlat undergruppen Forlat denne gruppen Forlat denne undergruppen Gå tilbake uten å legge inn nye brukere Logg inn logg inn Logg inn ved %system_name% logge inn igjen Innloggingssiden har blitt foreldet. Vennligst logg inn på nytt. Logg inn eller registrer deg innloggingsside Logg ut Logg ut fra %system_name% , du ville være i stand til å få mer informasjon om din kollega i gruppen. Kan ikke bli medlem av denne gruppen. Fullstendig liste over ISO-koder Fortsett å arbeide ved %system_name% Rediger kommentar for portrettet av %first_names% %last_name% %first_names% %last_name% (%email%) registrert som bruker av %system_url% For Site-Wide Administrators Gi rettigheter for %name% Dette ble rapportert fra databasen: Hvordan vil du at verden skal se %first_names% %last_name%? Dersom du ikke tror personen allerede har en konto: Dersom du vet eller tror at personen du ønsker å invitere allerede har konto på dette systemet: Dersom du trenger denne funksjonaliteten, vennligst last opp acs-reference og ref-countries. Arvede rettigheter Det ville være svært lite klokt å velge dette dersom du bruker en felles datamaskin i et biblotek eller fellesareal. Alle brukere som kommer etter deg vil kunne opptre som deg på tjenesten vår. Ny registrering på %system_url% Legg merke til at tekst i rødt under feltet for innlegging av parameter betyr at verdien til denne parameteren er overstyrt av et innleg i Open ACS parameterfil. Bruk av parameterfilen er ikke anbefalt, men noen steder må man bruke dem for å gi spesifkke verdier til parametre uavhengig av apm_parametertabeller. Legg merke til at du kan slette e-postadressen og passordet du har lagret ved å velge "logg ut" fra arbeidsområdet ditt. %num_children% Barn gjemt Den %portrait_publish_date%, lastet du opp <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Tjenesten vår kan be webleseren din å huske visse ting, som bruker-id og passord. Dette er praktisk for deg fordi, dersom du er den eneste personen som bruker denne maskinen, så trenger du ikke fortelle dem til oss hele tiden. Bekreft passord: URL for personlig webside: Du kan finne landkoden i listen under, så bruker du "tilbake"-knappen på nettleseren din for å komme tilbake til det forrige skjemaet. Vennligst les og følg instruksjonene i denne e-posten. Vennligst prøv å <a href="index">logge inn</a> igjen Portrett av %first_names% %last_name% Rettigheter høyere i hierarkiet tar med seg rettighetene under - for eksempel dersom du gir noen rettighet som admin, vil lese- og skriverettigheter automatisk være gitt også. Problemer med autentisering Registreringsinformasjon for denne tjenesten har nettopp blitt sendt til %email% Registreringsinformasjon for denne tjenesten har blitt sendt til %email% Din registreringsforespørsel har blitt sendt til administrator for %system_name%. Den venter fortsatt på godkjennelse. Lagrer e-postadresse og passord Vis alle andre på %system_name% hvordan du ser ut: Beklager, men det ser ut som om du har blitt utestengt fra %system_name%. Er du sikker på at du vil slette portrettet av denne brukeren? Er du sikker på at du vil slette ditt portrett? Bildet av deg i systemet er ikke gyldig. Vennligst Det var et problem med autentiseringen av din konto Dete er bildet som vi viser til andre brukere ved %system_name% Denne brukeren har ikke noe portrett. Du kan Denne brukeren er slettet og utestengt fra gruppen. Gå til %confirmation_url% for å godkjenne din registrering. Last opp din favorittfil, et innskannet JPEG eller GIF, fra din egen datamaskin (legg merke til at du ikke kan vise til et bilde et annet sted på internettet; dette bildet må ligge på harddisken på din egen maskin). Lastet opp: %pretty_date% Lastet opp: %publish_date% Bruk "Søk..."-knappen til å finne filen din, så klikker du "Åpne". Denne brukerene har lagt inn en beskrivelse eller lastet opp et bilde Vi kan ikke finne deg (bruker %user_id%) i brukertabellen, Sannsynligvis har kontoen din blitt slettet av en eller annen grunn. Vi fikk et problem da vi skulle prosessere ditt innlegg. Vi forventet ikke noen e-post. Det må være en misforståelse et sted. Velkommen til %system_name% Det som andre ser når de klikker på ditt navn. Du kan ikke ha &lt; i fornavnet ditt fordi det vil ligne på en HTML-kode og forvirre andre brukere. Du kan ikke ha &lt; i etternavnet ditt fordi det vil ligne på en HTML-kode og forvirre andre brukere. Du kommer ikke til å få noen e-post før etter %pretty_date%. E-posten din er bekreftet. Du kan nå logge inn på %system_name%. E-posten din har blitt mottatt. Du venter nå på endelig godkjenning fra administrator for %system_name%. E-posten din er mottatt. Innloggingen din har gått ut på tid. Vennligst skriv passordet ditt på nytt for å fortsette arbeidet. Din URL har ikke korrekt form. En gyldig URL er noe som ligner på dette: "%valid_url_example%". Lag administrator Lag medlem Gjør deg selv usynlig Gjør deg selv synlig Administrer dine meldinger Beklager - du har ikke tilgang til å se medlemslisten, Medlemsstatus Medlemmer Navn: Nytt passord: Ingen søknader Ingen ISO-koder Denne pakken har ingen parametre. Ditt bilde Ingen %pretty_plural% Ingen tjenester ingen Ikke innlogget Notater: Merk: på %name% til: (valgfri) Valg Eller legg til en ny bruker eller Passord: Innloggingen din ved %system_name%: %account_id_label%: %account_id% Passordet ditt for denne kontoen har nylig blitt endret. Du trenger ikke gjøre noe, dette er bare en melding for å beskytte sikkerheten av kontoen din. --------------- Du kan alltid endre passordet ditt ved å gjøre følgende: 1. Logg inn ved %system_name% 2. Klikk på "%pvt_home_name%" lenke 3. Velg "%password_update_link_text%" Passord endret Rettigheter rettigheter Rettigheter for %name% Vennligst gå tilbake til %home_link% Portrett Profil Spørsmål: Gjør tilgjengelig igjen Finn igjen passord Oppfrisk innlogging Registrer <p> Takk for din registrering ved %system_name%. En administrator har blitt varslet. </p><p>Når du har blitt godkjent vil du få en e-post, og du kan komme tilbake og begynne å bruke %system_name%. </p> Forkast Husk min innlogging på denne datamaskinen Fjern Fjern alle Be om medlemsskap for denne gruppen Be om medlemsskap for denne undergruppen Be om medlemsskap gå tilbake til søking Utfør på avmerkede Rolle Lagre kommentar Skjermnavn Søk etter eksisterende bruker Security context root Velg et Objekt etter Id: Send e-post til denne brukeren Vis Administrasjon for hele systemet Beklager, vi kan ikke hjelpe deg med passordet du har glemt. Status Historien bak bildet Historien bak bildet Undergrupper underbrupper undergruppe undergruppe Undergrupper undergrupper Takk. ISO-kodene har ikke blitt lastet inn på denne tjeneren. Gruppen er stengt. Nye medlemmer kan bare gis tilgang ved invitasjon. denne undergruppen Brukeren har forlatt gruppen. For å logge inn, gå til Emne typespesifikk informasjon OPP opp til %context_name% Oppdater Oppdater passord last opp Last opp et bilde last opp et annet bilde Last opp blide Brukernavn Brukerens sidekart Ferieinformasjon lastet opp Informasjon om ferien din ved %site_link% er lastet opp. Velkommen, %user_name% Når du lar en sjekkboks stå tom her, vil den rettigheten bli fratatt dem du velger dersom de har hatt denne rettigheten tidligere. Brukere som er online nå Hvem er Online Ja, jeg er sikker Du er med i følgende grupper Du kan også lese fra Du kan alltid åpne på nytt ved å Du har ikke administrasjonsrettigheter for objektet %root% eller noen av dets barn Du har ikke noe portrett. Du kan Du har administrasjonsrett til følgende objekter: Du har for øyeblikket ingen e-postvarsler registrert. Din konto Dine e-postvarsler fra diskusjonsfora Ditt bilde Dine %gc_system_name% varsler Du er merket som tilbake fra ferie ved %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.zh_CN.utf-8.xml0000644000175000017500000004506710727201372025330 0ustar frankiefrankie ,å¦åˆ™ æ›´æ–°åŸºæœ¬ä¿¡æ¯ %system_name%社团æˆå‘˜ è‡ªæˆ‘ä»‹ç» æ‚¨åœ¨%system_name%çš„å¸æˆ·å·²å…³é—­ã€‚ 返回%pvt_home_name% è¯·å…³é—­å¸æˆ·ã€‚ <p>æ‚¨çš„å¸æˆ·å·²å…³é—­ã€‚</p> <p>我们å¯ä»¥ä¸ºæ‚¨<a href="%restore_url%">釿–°æ‰“å¼€</a>。</p> <p> <font color="red"> <b> æ‚¨çš„å¸æˆ·å·²å…³é—­ã€‚å¯ä»¥é‡æ–°</b> </font> <a href="%="%login_url%%">登录</a> 查看有关情况。 </p&;gt; 您在%system_name%çš„å¸æˆ·é‡æ–°æ‰“开,欢迎回æ¥ã€‚ 叿ˆ·é‡æ–°æ‰“å¼€ æ“作 新申请 æŽ§åˆ¶é¢æ¿ 管ç†%subsite_name% 用户管ç†é€‰é¡¹ æç¤ºç±»åž‹ å¦ä¸€å¹…图片。 解答 申请错误 申请 批准 在 æƒé™ 密ç é”™è¯¯ ç¦æ­¢ åŸºæœ¬ä¿¡æ¯ è‡ªä¼  䏿”¯æŒé€šè¿‡æœ¬åœ°æƒé™é‡æ–°æ‰¾å›žå¯†ç ã€‚ ä¸èƒ½æµè§ˆæˆå‘˜åˆ—表 改å˜è¯­è¨€ ä¿®æ”¹å¯†ç  æ”¹å˜å¯†ç ã€emailã€è‚–åƒ æ£€æŸ¥æ”¶ä»¶ç®± å­ <p> 请确认您è¦å…³é—­åœ¨%system_name%çš„å¸æˆ·ã€‚ </p> <p> 关闭叿ˆ·æ„å‘³ç€æˆ‘们将ä¸å†ç»™ä½ å‘邮件通知,也ä¸ä¼šå†ä¸ºæ‚¨æ˜¾ç¤º%system_name%的会员列表。但是,您的资料作为团体历å²è®°å½•的一部分将被ä¿ç•™ä¸‹æ¥ã€‚</p> <p> 注æ„:您å¯ä»¥éšæ—¶ç™»é™†ï¼Œé‡æ–°æ‰“å¼€æ‚¨çš„å¸æˆ·ã€‚</p> 关闭叿ˆ· 关闭组 评论 社团 社团 社团 确认 å·²æˆåŠŸé€‰æ‹©æ–°å¯†ç  ç»§ç»­ 到%pvt_home_name% 国家åç§° 新建%pretty_name% 新建å­ç½‘页 当å‰å¯†ç  当å‰çš„在线状æ€ä¸ºä¸å¯è§ã€‚ 当å‰çš„在线状æ€ä¸ºå¯è§ã€‚ 用户化问题 æ•°æ®åº“错误 默认上下文 删除 å¼€å‘ç®¡ç† å¼€å‘äººå‘˜ç®¡ç† ç›´æŽ¥å…许 使ä¸èƒ½ 已使ä¸èƒ½ 主è¦çš„ E-mail 编辑批注 被%authority_name%管ç†çš„特定对象是ä¸å¯ç¼–辑的。 Email 这是您新的登陆信æ¯ï¼š%account_id_label%: %account_id% %password_label%: %password%请点击下é¢çš„链接更改密ç ã€‚ 感谢您注册%system_name%. 这里是如何登陆%system_url%: %account_id_label%: %account_id% %password_label%: %password% 请点击下é¢çš„链接更改密ç ã€‚ Email确认 ä¸èƒ½ç”³è¯·Email 您在%system_name%å¿˜è®°çš„å¯†ç  æ¬¢è¿Žæ¥åˆ°%system_name% 能 输入用户å开始æ¢å¤å¯†ç ã€‚ æ“¦é™¤è‚–åƒ æ“¦é™¤è‚–åƒ é”™è¯¯ 邮件å‘é€é”™è¯¯ 过期 文件å åå­— 忘记密ç ï¼Ÿ 频率 å‘åŽ ä¸Šä¼ ç”¨æˆ·è‚–åƒ ä¸Šä¼ æ‚¨çš„è‚–åƒ æ‰¹å‡† 准许 éšè— 主页 å‡å¦‚你是 ä¿¡æ¯æ›´æ–° 邀请 ISOç¼–ç  ISOç¼–ç åˆ—表 没有装载ISOç¼–ç  æ²¡æœ‰è£…è½½ISOç¼–ç  åŠ å…¥ç¤¾å›¢ 加入%group_name% 加入å­ç½‘ç«™ 加入社团 加入å­ç½‘ç«™ å…³é”®è¯ å§“ ç¨åŽã€‚ 离开社团 离开å­ç½‘页 离开社团 离开å­ç½‘页 ä¸å¢žåŠ ä»»ä½•ç”¨æˆ·ï¼ŒåŽé€€ 登录 登录 登录到%system_name% 釿–°ç™»å½• ç™»å½•ç½‘é¡µè¿‡æœŸã€‚è¯·é‡æ–°ç™»å½•。 登录或注册 登录网页 退出 从%system_name%退出 ,你å¯ä»¥ä»Žä½ çš„åŒç¤¾å›¢æˆå‘˜é‚£é‡Œå¾—到更多的信æ¯ã€‚ ä¸èƒ½åŠ å…¥è¯¥ç»„ 所有的ISOç¼–ç åˆ—表 继续在%system_name%工作 编辑%first_names% %last_name%è‚–åƒçš„评论 %first_names% %last_name%(%email%)已在%system_url%注册 网站管ç†å‘˜ 批准%name% 这是数æ®åº“中的内容 您认为%first_names% %last_name%如何? å¦‚æžœä½ è®¤ä¸ºæ­¤äººè¿˜æ²¡æœ‰ä¸€ä¸ªå¸æˆ·ï¼š å¦‚æžœä½ çŸ¥é“æˆ–ç›¸ä¿¡ä½ æ‰€é‚€è¯·çš„äººå·²æœ‰äº†æ­¤ç³»ç»Ÿçš„å¸æˆ·ï¼š å¦‚æžœéœ€è¦æ­¤åŠŸèƒ½ï¼Œè¯·å®‰è£…acs-reference and ref-countries。 ç»§æ‰¿çš„è®¸å¯ å¦‚æžœæ‚¨ä½¿ç”¨çš„æ˜¯å…¬å…±è®¡ç®—æœºï¼Œå»ºè®®ä¸é€‰ç”¨è¯¥é¡¹ã€‚å¦åˆ™ï¼Œä½¿ç”¨è¯¥è®¡ç®—机的其他人有å¯èƒ½ä¼šä»¥æ‚¨çš„å义使用系统。 新注册到%system_url% 注æ„ï¼šå‚æ•°åŸŸä¸‹é¢æ–‡æœ¬ä¸ºçº¢è‰²æ ‡è®°æ—¶è¡¨ç¤ºæ­¤å‚数的值被OpenACS傿•°æ–‡ä»¶æ‹’ç»ã€‚一般ä¸å»ºè®®ä½¿ç”¨å‚数文件,但是æŸäº›ç½‘站需è¦å®ƒæä¾›ç‰¹å®šå€¼ã€‚ 注æ„:在你的工作空间中选择"退出"ï¼Œå–æ¶ˆä½ å­˜å‚¨çš„email地å€å’Œå¯†ç ã€‚ %num_children%å­éšè— %portrait_publish_date%日,您上传了<a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> æœåС噍å¯ä»¥è®°å¿†email地å€å’Œå¯†ç ã€‚如果您是个人使用该计算机,就ä¸ç”¨æ¯æ¬¡éƒ½è¾“å…¥email地å€å’Œå¯†ç ã€‚ ç¡®è®¤å¯†ç  ä¸ªäººä¸»é¡µURL: 请在下é¢åˆ—表中找到您的国家代ç ï¼Œå•击Back钮返回å‰ä¸€è¡¨æ ¼ã€‚ 请阅读email中的说明。 è¯·é‡æ–°<a href="index">登录</a>。 %first_names% %last_name%è‚–åƒ é«˜æƒé™çš„用户能自动赋予下级它所具有的æƒåˆ©ã€‚å¦‚ï¼Œå½“æŽˆäºˆäº†ç®¡ç†æƒåŽï¼Œå°±èƒ½è¯»ã€å†™ç­‰ç­‰ã€‚ 叿ˆ·è®¤å®šé—®é¢˜ 注册信æ¯è¢«å‘é€åˆ°%email%。 注册信æ¯å·²å‘é€åˆ°%email%。 您的注册信æ¯å·²æäº¤åˆ°%system_name%管ç†å‘˜ã€‚请等待批准。 ä¿å­˜email地å€å’Œå¯†ç  在%system_name%上展示风采: 对ä¸èµ·ï¼Œæ‚¨ä¼¼ä¹Žå·²è¢«%system_name%ç¦æ­¢ã€‚ 真的è¦åˆ é™¤æ­¤ç”¨æˆ·è‚–åƒå—? 真的è¦åˆ é™¤ä½ çš„è‚–åƒå—? 您在系统中的图片格å¼ä¸å¯¹ï¼Œè¯· æ‚¨çš„å¸æˆ·æœ‰é—®é¢˜ã€‚ 这是给%system_name%其他用户看的图片 该用户还没有肖åƒï¼Œæ‚¨å¯ä»¥ æ­¤ç”¨æˆ·å·²è¢«è¯¥ç¤¾å›¢åˆ é™¤å¹¶ç¦æ­¢ã€‚ 请到%confirmation_url%确认注册。 从本地机上传适当格å¼çš„æ–‡ä»¶ï¼Œå¦‚JPEGã€GIF。注æ„:图片必须在本地机上。 上传:%pretty_date% 已上传:%publish_date% 使用“æµè§ˆâ€æŒ‰é’®æ‰¾åˆ°æ–‡ä»¶ï¼Œå•击“打开â€ã€‚ 用户已ç»å†™è¿‡è‡ªä¼ æˆ–上载过照片 在用户列表中找ä¸åˆ°æ‚¨(%user_id%)ï¼Œæ‚¨çš„å¸æˆ·å¯èƒ½å·²è¢«åˆ é™¤ã€‚ å¤„ç†æ‚¨çš„登录时出现问题。 我们一直在等待您的email。肯定有其它错误。 欢迎æ¥åˆ°%system_name% 当别人点击你å字时能看到的内容 å字中ä¸èƒ½å«æœ‰&lt;,å¦åˆ™å°±è±¡ä¸€ä¸ªHTML标记,容易引起其他用户误解。 å§“å中ä¸èƒ½æœ‰&lt;,å¦åˆ™å°±è±¡ä¸€ä¸ªHTML标记,容易引起其他用户误解。 %pretty_date%åŽæ‚¨å°±æœ‰ä¸€ä¸ªemail。 您的email已确认。现在å¯ä»¥ç™»å½•%system_name%。 您的email已确认。请等候%system_name%管ç†å‘˜çš„æ‰¹å‡†ã€‚ 您的email已确认 æ‚¨çš„ç™»å½•è¿‡æœŸã€‚è¯·é‡æ–°è¾“入密ç å¯ç»§ç»­å·¥ä½œã€‚ URLæ ¼å¼é”™è¯¯ã€‚一个有效的URLæ ·å¼å¦‚下:"%valid_url_example%"。 æˆä¸ºç®¡ç†å‘˜ æˆä¸ºä¼šå‘˜ 使自己ä¸å¯è§ 使自己å¯è§ 管ç†é€šçŸ¥ 对ä¸èµ·ï¼Œæ‚¨ä¸èƒ½æµè§ˆæˆå‘˜åˆ—表。 æˆå‘˜çŠ¶æ€ æˆå‘˜ å æ–°å¯†ç  没有申请 没有ISOç¼–ç  æ­¤è½¯ä»¶åŒ…æ²¡æœ‰ä»»ä½•å‚æ•° æˆ‘çš„è‚–åƒ æ²¡æœ‰%pretty_plural 没有æœåŠ¡ 没有 没有登录 注æ„: 注æ„: %name%: (å¯é€‰çš„) 选项 或增加新用户 或这 å¯†ç  æ‚¨åœ¨çš„%system_name%登陆信æ¯ï¼š%account_id_label%: %account_id%ï¼Œæ‚¨å¸æˆ·çš„密ç å·²æ›´æ”¹ã€‚这仅仅是一个通知。您总å¯ä»¥é€šè¿‡ä»¥ä¸‹æ­¥éª¤æ›´æ”¹æ‚¨çš„密ç ï¼š1.登陆%system_name% 2.å•击"%pvt_home_name%" 3.选择"%password_update_link_text%" 密ç å·²æ›´æ”¹ è®¸å¯ è®¸å¯ å…许%name% 请返回%home_link%。 è‚–åƒ è‡ªæˆ‘ä»‹ç» é—®é¢˜ 釿–°ä½¿èƒ½ æ¢å¤å¯†ç  更新登录 注册 <p> 感谢您注册%system_name%. 管ç†å‘˜å·²ç»çœ‹åˆ°æ‚¨çš„申请. </p> <p> 当您收到申请被批准的email,就å¯ä»¥ä½¿ç”¨%system_name%。 </p> æ‹’ç» åœ¨æ­¤è®¡ç®—æœºä¸Šè®°ä½æˆ‘的登录 删除 全部删除 申请为此社团的æˆå‘˜ 申请加入å­ç½‘ç«™ 申请为æˆå‘˜ 返回申请 撤消选中的 角色 ä¿å­˜æ‰¹æ³¨ å§“å æœç´¢å·²å­˜åœ¨ç”¨æˆ· 安全上下文根 按ID选择对象: 给该用户å‘é€email 显示 ç½‘ç«™ç®¡ç† å¯¹ä¸èµ·ï¼Œå¯¹äºŽæ‚¨å¿˜è®°çš„å¯†ç æ— èƒ½ä¸ºåŠ›ã€‚ 身份 照片背åŽçš„æ•…事 照片背åŽçš„æ•…事 å­ç¤¾å›¢ å­ç¤¾å›¢ å­ç¤¾å›¢ å­ç½‘ç«™ å­ç½‘ç«™ å­ç½‘ç«™ è°¢è°¢ï¼ æ­¤æœåŠ¡å™¨æ²¡æœ‰å®‰è£…ISOç¼–ç ã€‚ 该组是关闭的。新的æˆå‘˜æ”¶åˆ°é‚€è¯·åŽæ‰èƒ½åŠ å…¥ã€‚ å­ç½‘ç«™ 此用户已离开该社团。 è¦ç™»å½•,访问 è¯é¢˜ æŒ‡å®šç±»åž‹ä¿¡æ¯ å‘上 上传到%context_name% æ›´æ–° ä¿®æ”¹å¯†ç  ä¸Šä¼  ä¸Šä¼ è‚–åƒ ä¸Šä¼ æ›¿æ¢è‚–åƒ ä¸Šä¼ è‚–åƒ ç”¨æˆ·å 用户导航图 休å‡ä¿¡æ¯å·²æ›´æ–° 你在%site_link%的休å‡ä¿¡æ¯å·²æ›´æ–°ã€‚ 欢迎您,%user_name% 如果ä¸é€‰æ‹©è¯¥é¡¹ï¼Œæ‚¨çš„æƒé™å°†ä»Žç¤¾å›¢ä¸­æ’¤æ¶ˆã€‚ 当å‰åœ¨çº¿ç”¨æˆ· 在线用户 是 你现在所在组: 你也å¯ä»¥æµè§ˆ ä½ å¯ä»¥é‡æ–°æ‰“开它,使用 您没有对%root%åŠå…¶å­å¯¹è±¡çš„ç®¡ç†æƒ 你还没有肖åƒã€‚å¯ä»¥ 你有对以下å„é¡¹çš„ç®¡ç†æƒï¼š 你没有注册emailæç¤ºã€‚ æˆ‘çš„å¸æˆ· ä½ çš„è®ºå›æç¤º æˆ‘çš„è‚–åƒ ä½ çš„%gc_system_name%æç¤º %site_link%已被标记为休å‡ç»“æŸã€‚ openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.es_CO.ISO-8859-1.xml0000644000175000017500000005322410727201372025551 0ustar frankiefrankie , o Actualizar Información Básica Miembro de %system_name% desde Mi información Su cuenta en %system_name% ha sido cancelada. No, volver a %pvt_home_name% Sí, cancelar mi cuenta <p>Su cuenta se encuentra cerrada por el momento.</p><p>Si usted lo desea, podemos <a href="%restore_url%">re-abrir su cuenta</a>.</p> <p><font color="red"><b>Su cuenta está actualmente cancelada.</b></font><a href="%login_url%">Conectese</a> de nuevo para ver que puede hacer al respecto.</p> Su cuenta en %system_name% ha sido reactivada. Bienvenido de nuevo. Cuenta reactivada Acción Agregar una nueva aplicación Panel de Control Administrar %subsite_name% Opciones de administración para este usuario Tipo de aviso otra imagen. Respuesta: Error de la aplicación Aplicaciones Aprobar en Autoridad Contraseña errónea Prohibir Información básica Biografía No se soporta la obtención de contraseñas de una autoridad local. No puede ver la lista de miembros Seleccionar idioma Cambiar mi contraseña Cambiar contraseña, email, foto Revisar correo entrante Hijos <p>Por favor, confirme que realmente desea cancelar su cuenta en %system_name%.</p> <p>Cancelar una cuenta significa que no seguirá recibiendo notificaciones, ni formará parte de los miembros de %system_name%. No obstante, sus contribuciones a la comunidad se conservarán como parte del histórico de la comunidad.</p> <p>Tenga en cuenta que puede reabrir su cuenta en cualquier momento, para ello simplemente vuelva a conectarse.</p> Cancelar cuenta Grupo Cerrado Comentario Comunidades comunidades comunidad Confirmar: Usted a seleccionado una nueva contraseña con éxito Continuar Continuar a %pvt_home_name% País Crear nuevo %pretty_name% Crear un nuevo subsitio Contraseña Actual: <p>Su nombre NO aparece en la lista de usuarios conectados.</p> <p>Su nombre aparece en la lista de usuarios conectados.</p> Personalizar pregunta Error de base de datos contexto por defecto Borrar DevAdmin Administración de desarrolladores Permisos directos Desactivar Desactivado Dominio Correo Electrónico editar comentario Algunos elementos no pueden ser editados ya que están siendo administrados por %authority_name%. Correo Electrónico Datos de su cuenta: %account_id_label%: %account_id% %password_label%: %password% Para cambiar su contraseña, visite %reset_password_url% Gracias por registrarse en %system_name%. Para conectarse, visite %system_url%: %account_id_label%: %account_id% %password_label%: %password% Para cambiar su contraseña, visite %reset_password_url% Confirmación de Correo Electrónico Correo electrónico no solicitado Recordatorio de su contraseña en %system_name% Bienvenido a %system_name% Activado Introduzca su nombre de usuario para poder recuperar su contraseña. Borrar foto borrar foto Error Error al enviar el correo Caduca Nombre de archivo Nombres ¿Ha olvidado su contraseña? Frecuencia Regresar subir la foto del usuario sube tu retrato Otorgar Autorizar Oculto Página web Si fueras a Información Actualizada Invitar Código ISO Lista de Códigos ISO Los Códigos ISO no han sido cargados Códigos ISO no cargados Únete a la comunidad Unirse a %group_name% Únete al subsitio Únete a esta comunidad Únete a este subsitio Palabra clave Apellido después. Salir de la comunidad Salir del subsitio Salir de esta comunidad Salir de este subsitio Regresar sin agregar ningun usuario Entrar entrar Registrate en %system_name% registrarse de nuevo La pagina de registro ha expirado. Por favor registrarse de nuevo. Entrar o registrarse. página de registro Salir Salir de %system_name% ,serás capaz de adquirir mas información en el miembro de tu comunidad No puede unirse a este grupo. Lista completa de los códigos ISO Sigue trabajando en %system_name% Editar commentario de la foto de %first_names% %last_name% %first_names% %last_name% (%email%) se registró como usuario de %system_url% Para los Administradores del sitio Otorgar permiso en %name% Esto es lo que la base de datos reporto: Cómo quisieras que el mundo te viera %first_names% %last_name%? Si crees que la persona ya tiene una cuenta: Si sabes o crees que la persona que quieres invitar ya tiene una cuenta en el sistema: Si necesitas esta funcionalidad, por favor carga acs-reference y ref-countries. Permisos heredados Puede ser una mala idea escoger esta opción si está usando una computadora compartida de una biblioteca o colegio. Cualquier usuario que utilice esta computadora en adelante podría hacerse pasar por usted en nuestra plataforma. Nuevo registro en %system_url% Note que el texto en rojo mostrado debajo de la entrada del campo de parámetro indica que el valor del mismo está siendo sobreescrito por una entrada en el archivo de parámetro de OpenACS. Desalentamos el uso del mismo pero algunos sitios lo necesitan para proveer valores específicos de instancia para los parámetros independientes de la tabla apm_parameter. Tenga en cuenta que puede eliminar su dirección de correo y contraseña de la memoria de su computadora, haciendo click en la opción "Salir" de su portal. %num_children% Hijos ocultos El %portrait_publish_date%, subiste <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%"">%portrait_title%</a> Nuestro servidor le puede decir a su navegador que recuerde algunas cosas como su dirección electrónica y su contraseña. Esto es conveniente porque si usted es la única persona que usa su computadora, no tiene que repetirnos su correo ni su contraseña. Confirmación de la contraseña: URL de su página personal: Por favor localiza el código de tu país entre los listados debajo, luego usa el boton "regresar" en tu navegador para regresar al formulario anterior. Por favor, siga las instrucciones dadas en ese correo. Por favor, intente <a href="index">ingresar</a> de nuevo Foto de %first_names% %last_name% Privilegios altos en la jerarquía implican todos los privilegios debajo, ejemplo: cuando otorgas admin, luego leer, escribir , etc. estan implicados automáticamente. Problema con la autenticación La información de registro para este servicio acaba de ser enviada a %email% La información de registro para este servicio ha sido enviada a %email%. Su solicitud de registro ha sido enviada al administrador de %system_name% y está en espera de aprobación. Guardando dirección de correo y contraseña Hagase conocer a los usuarios de %system_name% Lo sentimos, pero ha sido expulsado de &system_name% Seguro que quieres borrar la foto de este usuario? Estas seguro de borrar tu foto? Tu foto en el systema es inválida. Por favor Ha ocurrido un problema durante la autenticación de su cuenta Esta es la imagen que mostraremos a los otros usuarios en %system_name% Este usuario no tiene foto todavía. Puedes Este usuario fue borrado y su acceso a la comunidad fue prohibido. Para confirmar su registro, por favor, acuda a %confirmation_url% Sube tu foto favorita, un archivo escaneado en formato JPEG o GIF, de tu computadora(nota que no puedes hacer referencia a una imagen en algún lado de internet; tiene que estar en tu disco duro). Subido: %pretty_date% Subido: %publish_date% Utiliza el botón de "Examinar..." para localizar tu archivo, luego selecciona el botón de "Abrir". No te pudimos encontrar (usuario %user_id%) en la tabla de usuarios. Probablemente tu cuenta fue borrada por alguna razón. Tuvimos un problema procesando tu entrada. No estabamos esperando su correo. Debe tratarse de un error. Bienvenido a %system_name% Lo que verán los demás al hacer click sobre su nombre No puede introducir un signo &lt; en su nombre ya que corresponde a una etiqueta HTML y podría crear confusión. No puede introducir un signo &lt; en sus apellidos ya que corresponde a una etiqueta HTML y podría crear confusión. No podrás recibir ningún correo hasta después de pretty_date%. Su correo ha sido confirmado. Ahora, puede ingresar a %system_name%. Su correo ha sido confirmado. Ahora, debe esperar la aprobación del administrador de %system_name%. Su correo ha sido confirmado Tu sesión ha expirado. Por favor ingresa tu contraseña para poder seguir trabajando. El URL introducido no es válido. Un ejemplo de URL válida es \"%valid_url_example%\"." Volver administrador Volver miembro Volverse invisible Volverse visible Administrar notificaciones Lo sentimos, pero no estas autorizado para ver la lista de miembros. Estado del miembro Miembros Nombre y apellidos: Nueva contraseña: No hay aplicaciones No hay códigos ISO Este paquete no tiene parámetros. su foto No tiene %pretty_plural% No hay servicios ninguno No registrado Notas: Aviso: en %name% a (opcional) Opciones O agregar un nuevo/a usuario/a o el Contraseña: Su información de ingreso en %system_name%: %account_id_label%: %account_id% Su contraseña para esta cuenta ha sido modificiada recientemente. Usted no necesita hacer nada, ésta es simplemente una notificación para proteger la seguridad de su cuenta. --------------- Usted puede cambiar su contraseña realizando los siguientes pasos: 1. Ingrese a %system_name% 2. Haga click en el link "%pvt_home_name%" 3. Escoja "%password_update_link_text%" Contraseña modificada Permisos permisos Permisos para %name% Por favor regresa a %home_link%. Foto Pregunta: Reactivar Recuperar Contraseña Actualizar login Registro <p> Gracias por registrarse a %system_name%. Un administrador ha sido notificado por su solicitud. </p> <p> Una vez este aprovado, se le enviara un mail para que pueda empezar a utilizar %system_name%. </p> Rechazar Recordar mi contraseña en esta computadora Eliminar Quite Todos Solicitar membresía de esta comunidad Solicitar membresía de este subsitio Solicitar membresía regresar a la aplicación Revocar Rol Guardar comentario Alias Buscar un usuario existente Contexto de seguridad de root Seleccionar un objeto por Id Enviar email a este usuario Mostrar Administración Site-wide Lo sentimos, no podemos ayudarlo con su contraseña olvidada. Estado Historia Detrás Foto Historia Detrás Foto Subcomunidades subcomunidades subcomunidad subsitio Subsitios subsitios Gracias. Los códigos ISO no fueron cargados en este servidor. Este grupo esta cerrado. Nuevos miembros solo pueden tener acceso por invitación. este subsitio Este usuario ha dejado la comunidad. Para logearse, visite el Tópico Introduzca información especifica UP volver a %context_name% Actualizar Actualizar contraseña subir subir una foto cargar un retrato de reemplazo Cargar Retrato Nombre de usuario Mapa del Sitio para Usuarios Información de Vacaciones Actualizada La información de sus vacaciones en %site_link% ha sido actualizada. Bienvenido/a, %user_name% Cuando aquí usted deja un checkbox vacío ese privilegio será revocado por el grupo que escogió en caso de que haya sido concedido a ese grupo con anterioridad. Usuarios conectados en este momento ¿Quién está conectado? Sí, estoy seguro Usted esta en los siguientes grupos: También puede navegar desde el Usted siembre puede reabrirlo con No tiene derechos de administración en el objeto %root% o cualquier de sus hijos Usted aun no tiene una foto. Usted puede Tiene derechos de administración en los siguientes objetos: Actualmente no tiene avisos de correo activados. Su Cuenta Tus avisos en los foros Su foto Su %gc_system_name% alerta Usted ha sido marcado como de vuelta de vacaciones en openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.es_ES.ISO-8859-1.xml0000644000175000017500000011771611553376447025604 0ustar frankiefrankie , o Actualizar Información Básica Miembro de %system_name% desde Mi información Su cuenta en %system_name% ha sido cancelada. No, volver a %pvt_home_name% Sí, cancelar mi cuenta <p>Su cuenta se encuentra cerrada por el momento.</p><p>Si usted lo desea, podemos <a href="%restore_url%">reactivar su cuenta</a>.</p> Cuenta cerrada <p>Su cuenta está actualmente <strong>cancelada</strong>. <a href="%login_url%">Conectese</a> de nuevo para ver que puede hacer al respecto.</p> Esta cuenta no está disponible en este momento. Su cuenta en %system_name% ha sido reactivada. Bienvenido de nuevo. Cuenta reactivada Acción Añadir Añadir un grupo de este tipo Añadir un tipo de relación Añadir un atributo Añadir otra pareja hostname/URL Añadir aplicación Añadir Aplicaciones Añadir carpeta Crear un tipo de grupo Añadir múltiples aplicaciones Añadir una nueva aplicación Mapear Añadir el tipo de relacion admisible Añadir un tipo de relación para %group_type% Añadir este usuario Crear tipo Añadir Usuario Añadir usuarios Información Adicional Panel de control Admin Administrar %subsite_name% Administración Opciones de administración para este usuario Avanzado Características Avanzadas Tipo de aviso Alias otra imagen. Respuesta: Cualquiera Aplicación Error de la aplicación Nombre de la aplicación Aplicaciones Aprobar en Los atributos sólo pueden ser añadidos por los programadores ya que este tipo de objeto no es creado de forma dinámica Atributos de este tipo de grupo Error interno durante la autenticación Autoridad Contraseña errónea Prohibir Información básica Biografías Biografía Tipo Mime de Biografía Tipos Mime de Biografía Construir el Mapa del sitio por tipo de grupo No se soporta la obtención de contraseñas de una autoridad local. No puede ver la lista de miembros Leyenda Seleccionar idioma Cambiar el nivel de privacidad de mi email Cambiar mi contraseña Cambiar contraseña, correo, foto Ha requerido cambiar su contraseña en el sistema (o alguién lo ha requerido en su nombre). Para completar el cambio, visite: Si no es Vd. la persona que ha realizado esta solicitud, no necesita realizar ninguna acción. Solicitud de cambio de contraseña para Revisar correo entrante Hijos Elija un Cuestionario personalizado de registro: Elija el cuestionario que será mostrado a los nuevos usuarios.<br> Puede ser usado para realizar acciones automáticas (como añadir usuarios a grupos específicos, notificar a usuarios específicos sobre nuevos registros, etc.). Elige el diseño y el tema que desea para su subsitio. <p>Por favor, confirme que realmente desea cancelar su cuenta en %system_name%.</p> <p>Cancelar una cuenta significa que no seguirá recibiendo notificaciones, ni formará parte de los miembros de %system_name%. No obstante, sus contribuciones a la comunidad se conservarán como parte del histórico de la comunidad.</p> <p>Tenga en cuenta que puede reabrir su cuenta en cualquier momento, para ello simplemente vuelva a conectarse.</p> Cancelar cuenta Grupo Cerrado Comentario Comunidades comunidades comunidad Configuración Configurar Confirmar: Usted ha seleccionado una nueva contraseña con éxito Continuar Continuar a %pvt_home_name% Servicios del Core País Crear Crear un nuevo tipo de relación Crear un cuestionario de registro nuevo Crear una nueva aplicación Crear nuevo %pretty_name% Crear un nuevo subsitio Crear un tipo de relación Contraseña Actual: Su nombre NO aparece en la lista de usuarios conectados. Actualmente %instance_name% tiene los siguientes grupos Actualmente, el sistema es capaz de manejar los siguientes tipos de grupos Actualmente el sistema es capaz de manejar los siguientes segmentos de relación Actualmente el sistema es capaz de manejar los siguientes tipos de relaciones Su nombre aparece en la lista de usuarios conectados. Personalizar pregunta Error de base de datos Fecha de nacimiento Tipos de relaciones permitidas por defecto contexto por defecto Política de alta Definir un nuevo tipo de grupo Define un nuevo tipo de relación Borrar Borrar Borrar aplicaciones seleccionadas Borrar esta aplicación Borrar este tipo de grupo Descripción Detalles de %group_type_pretty_name% Administración de desarrolladores Administración de desarrolladores Permisos directos Desactivar Desactivado Dominio Email Editar editar Editar nombre de la aplicación y la ruta Editar el Cuestionario Seleccionado Editar Leyenda editar comentario Opciones Algunos elementos no pueden ser editados ya que están siendo administrados por %authority_name%. Correo electrónico Email ya existe Permitir contactarme mediante una forma Permitir contacto mediante una forma Mostrar mi correo electrónico como una imagen Mostrar el correo electrónico como una imagen Mostrar mi correo electrónico como texto Mostrar el correo electrónico como texto Datos de su cuenta: %account_id_label%: %account_id% %password_label%: %password% Para cambiar su contraseña, visite %reset_password_url% Gracias por registrarse en %system_name%. Para conectarse, visite %system_url%: %account_id_label%: %account_id% %password_label%: %password% Para cambiar su contraseña, visite %reset_password_url% Confirmación de correo No mostrar mi correo electrónico No mostrar el correo electrónico No disponible No consta ninguna dirección de correo electrónico en su cuenta. Por favor, introduzca su dirección de correo electrónico. Correo electrónico no solicitado Email requerido Recordatorio de su contraseña en %system_name% Validación de email en %system_name% Activado Introduzca su nombre de usuario para poder recuperar su contraseña. Eliminar Borrar foto borrar foto Error Error al enviar el correo Ha habido un error al enviar el correo para la verificación por correo Ha habido un error al intentar registrar una cuenta para usted. Ha habido un error al intentar actualizar la información de la cuenta Caduca Mujer Archivo Nombre La autoridad de autenticación no nos ha proporcionado su nombre. Por favor, introduzca su nombre. Primero, seleccione el supertipo para el nuevo tipo de relación ¿Ha olvidado su contraseña? Frecuencia Género Regresar subir la foto del usuario subir su foto Otorgar Autorizar Administración de grupos Tipo de grupo Administración de tipos de grupos Tipos de Grupo Grupos Grupos de este tipo Ya tenemos un grupo con este correo electrónico Ya tenemos un usuario con este correo electrónico. Ya tenemos un usuario con este nombre de usuario. &lt;p&gt;&lt;h3&gt;Información de ayuda&lt;/h3&gt; Oculto Página web Mapa Host-Node Hostname El hostname debe ser único Icono de sobre si fuera a Información Actualizada Instalar Idiomas Invitar Invitar un usuario Código ISO Lista de Códigos ISO Los Códigos ISO no han sido cargados Códigos ISO no cargados Unirse a la comunidad Unirse a %group_name% Únete a la política Unirse al subsitio Unirse a esta comunidad Unirse a este subsitio Palabra clave Apellidos La entidad de autenticación no nos ha proporcionado su apellido. Por favor, introduzca su apellido. después. Salir de la comunidad Salir del subsitio Salir de esta comunidad Salir de este subsitio Regresar sin añadir ningún usuario Entrar entrar Entrar a %system_name% Entrando de nuevo La pagina de registro ha caducado. Por favor regístrese de nuevo. Entrar o registrarse. página de registro Salir Salir de %system_name% ,sería capaz de adquirir mas información sobre este miembro de la comunidad Añadir los usuarios seleccionados a usuarios que tienen permiso en su objeto. No puede unirse a este grupo. Lista completa de los códigos ISO Continue trabajando con %system_name% borrar&lt;/a&gt; &lt;/if&gt; &lt;if @nodes.parameters_url@ ne &quot;&quot;&gt; &lt;a href=&quot;@nodes.parameters_url@&quot;&gt;&lt;#_ parameters No heredar de %parent_object_name% Editar commentario de la foto de %first_names% %last_name% %first_names% %last_name% (%email%) se registró como usuario de %system_url% Para los Administradores del sitio Otorgar permiso en %name% Aquí esta lo que la base de datos ha devuelto: ¿Como quiere que el mundo le vea %first_names% %last_name%? Si cree que la persona no tiene aún una cuenta: Si sabe o cree que la persona que quiere invitar ya tiene una cuenta en el sistema: Si necesita esta funcionalidad, por favor carge acs-reference y ref-countries. heredar de %parent_object_name% Heredar permisos del %parent_object_name% Permisos heredados Puede ser una mala idea escoger esta opción si está usando un ordenador compartido (de una biblioteca o colegio por ejemplo). Cualquier usuario que utilice este ordenador podría hacerse pasar por usted en nuestra plataforma. Nuevo registro en %system_url% La nota en rojo debajo de los campos de entrada de cada parámetro indica que el valor del mismo está sobreescrito por una entrada en el archivo de parámetros de OpenACS. Se aconseja el uso de dicho archivo, pero algunos sitios lo necesitan para asignar valores específicos a los parámetros, independientes de las tablas apm_parameter. Tenga en cuenta que puede eliminar su dirección de correo y contraseña de la memoria de su ordenador, pulsando la opción "Salir" de su portal. %num_children% Hijos ocultos El día %portrait_publish_date%, ha subido <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%"">%portrait_title%</a> Nuestro servidor le puede decir a su navegador que recuerde algunas cosas como su correo y su contraseña. Esto es conveniente si usted es la única persona que usa su ordenador, así no tiene que repetirnos ni su correo ni su contraseña. Introduzca de nuevo la contraseña: URL de su página personal: Por favor localice el código de su país en la lista, después utilice "regresar" de su navegador para regresar al formulario anterior. Por favor, siga las instrucciones dadas en ese correo. Por favor, intente <a href="index">entrar</a> de nuevo Foto de %first_names% %last_name% Los privilegios de la parte de arriba en la jerarquía implican todos los privilegios de abajo, ejemplo: cuando otorga privilegios de administración, estan implicados automáticamentelos privilegios de escritura, lectura, etc. Problema con la autentificación Su cuenta no ha sido confirmada aún. Un email para su validación ha sido enviado a %email%. Para validar su cuenta, por favor, compruebe sus correos y siga el enlace proporcionado en el email de %system_name%. Un email para su validación ha sido enviado a %email%. Para validar su cuenta, por favor, compruebe sus correos y siga el enlace proporcionado en el email de %system_name%. Su solicitud de registro ha sido enviada al administrador de %system_name% y está en espera de aprobación. Guardando dirección de correo y contraseña Demuestre a los usuarios de %system_name% lo fotogénico que es: Lo sentimos, pero ha sido expulsado de %system_name% Dejar de Heredar permisos del %parent_object_name% ¿Seguro que quiere borrar la foto de este usuario? ¿Esta seguro de borrar su foto? Por favor. Su foto en el sistema es erronea. No hay usuarios que no tengan acceso a este objeto. Ha ocurrido un problema durante la autentificación de su cuenta Esta es la foto que verán los demás usuarios en %system_name% Este usuario no tiene una foto todavía. Puede añadirla si lo desea. Este usuario fue borrado y su acceso a la comunidad prohibido. Hola, Este mensaje es para comprobar que la dirección de correo electrónico con la que se ha registrado en %system_name% es correcta. Para validar su dirección, pulse en el enlace a continuación: %confirmation_url% Si no se ha registrado en %system_name%, por favor, ignore este mensaje. Gracias, El equipo de %system_name% Suba su foto favorita, un archivo escaneado en formato JPEG o GIF de su ordenador(No puede subir una imagen desde ningún sitio de internet; tiene que estar en su disco duro). Subido: %pretty_date% Subido: %pretty_date% Utilice el botón "Examinar..." para localizar su archivo, después pulse botón "Abrir". Este usuario ha subido una biografia o una foto No se le ha podido encontrar (usuario %user_id%) en la tabla de usuarios. Probablemente su cuenta ha sido borrada. Ha ocurrido un problema procesando su solicitud. No se esperaba su correo. Debe tratarse de un error. Email de validación para %system_name% Lo que verán los demás al pulsar sobre su nombre No puede introducir un signo &lt; en su nombre ya que corresponde a una etiqueta HTML y podría crear confusión. No puede introducir un signo &lt; en sus apellidos ya que corresponde a una etiqueta HTML y podría crear confusión. Debe proveer object_id_one o object_id_two No podrá recibir ningún correo hasta después de %pretty_date%. Bienvenido. Su correo electrónico ha sido validado con éxito y está registrado en %system_name%. Para empezar, pulse el botón a continuación. Su correo ha sido confirmado. Ahora, debe esperar la aprobación del administrador de %system_name%. Su correo ha sido confirmado Su sesión ha caducado. Por favor introduzca su contraseña para seguir trabajando. La URL introducida no es válida. Un ejemplo de URL válida es "%valid_url_example%". Enviar un mensaje a: Convertir en administrador Crear un miembro Volverse invisible Volverse visible Hombre Administrar Foto Administrar aplicaciones no montadas Administrar la privacidad del correo electrónico de los usuarios Administrar notificaciones No esta autorizado para ver la lista de miembros. Usuario Estado del miembro Miembros Sólo miembros Faltan argumentos montar Mi Cuenta Nombre y apellidos: Nueva Aplicación nueva aplicación Nueva contraseña: Nuevo subsite Nuevo subsitio No hay aplicaciones No hay tareas disponibles No hay códigos ISO Este paquete no tiene parámetros. su foto No tiene %pretty_plural% No hay servicios No se encontró ningún usuario con este nombre de usuario No hay nadie conectado. ninguno No registrado Esta no es una dirección de correo válida Nota: Los segmentos relacional son creados desde la <a href='../group/'>Página de administración de grupos</a> Notas: Aviso: número de grupos definidos número de relaciones definidas Tipos de Objetos en %name% a Conectado Su nombre ya NO aparecerá en la lista de usuarios conectados Ahora su nombre aparecerá en la lista de usuarios conectados Tiempo online (opcional) Opciones O añadir un nuevo/a usuario/a o desde Parámetros parámetros Contraseña Su información en %system_name%: %account_id_label%: %account_id% Su contraseña para esta cuenta ha sido modificiada. No necesita hacer nada, se le envía este correo para proteger la seguridad de su cuenta. --------------- Puede cambiar su contraseña siguiendo los siguientes pasos: 1. Entre en %system_name% 2. Haga click en el enlace "%pvt_home_name%" 3. Escoja "%password_update_link_text%" Contraseña modificada su contraseña debe ser cambiada regularmente. Por favor cambie su contraseña ahora. Las contraseñas no coinciden Este permiso no se puede borrar Permisos permisos Permisos para %name% Lugar de nacimiento Lugar de residencia Por favor vuelva a %home_link%. -- Por favor selecciona -- Foto Powered by <a href="http://openacs.org" title="The OpenACS Project Homepage">OpenACS</a> Nombre Nombre en plural Privacidad Hubo un problema autenticando la cuenta. Probablemente la base de datos contiene usuarios sin member_state Perfil Pregunta: Reactivar Lectura Recuperar Contraseña Actualizar entrada Cuestionario de registro de usuarios personalizado Registro Pareja hostname/URL Registrada Registro en %system_name% <p> Gracias por registrarse en %system_name%. Se ha notificado a un administrador sobre su solicitud. </p> <p> Una vez este aprobado, se le enviará un correo para que pueda entrar en %system_name%. </p> Su correo electrónico es su nombre de usuario en %system_name%. Le enviaremos un mensaje de validación para confirmar que dicho correo es suyo. Rechazar Administración de los Segmentos Relaciones Segmentos relacionales relación con el sitio Tipos de Relación Administración de Tipos de Relación Recordar mi contraseña en este equipo Eliminar eliminar Eliminar todos Renombrar Solicitar pertenecer a esta comunidad Solicitar pertenecer a este subsitio Solicitud de cambio de contraseña: se le ha enviado un correo para cambiar su contraseña. Siga las instrucciones de dicho correo. Solicitar la entrada Reiniciar contraseña volver a la aplicación Revocar Rol Nodo Raíz URL Raíz Guardar comentario Alias Este apodo ya está cogido Screen name ya utilizado Buscar un usuario existente Contexto de seguridad de root Ver a tamaño completo Seleccionar un objeto por Id Selecciona las aplicaciones Si una aplicación no aparece en la lista, necesitará <a href=\"/acs-admin/install/\">instalarla</a> en el servidor Selecciona el tipo de relación Enviar email a este usuario Envienme una copia: Servicios Poner la tarea para el registro Mostrar Mapa del Sitio Instrucciones para el Mapa del sitio El nodo al que desea mapear el hostname Administración del Sitio Principal Administración general No se le puede ayudar con el olvido de su contraseña. Estado Historia de la foto: Historia de la foto Subcomunidades subcomunidades subcomunidad subsitio Configuración del Subsitio Inico %subsite_name% Nombre del subsitio Paquete del subsitio Subsitios subsitios Se ha autentificado correctamente, pero no tiene una cuenta todavía en %system_name%. Supertipo Gracias. Los códigos ISO no han sido cargados en este servidor. El nombre del nuevo subsitio que está configurando Theme theme Este grupo es cerrado. Solo puede ser miembro por invitación. Este tipo de grupo sólo puede ser administrado por programadores Debe ser una cadena corta, todo en minúsculas, con guiones en lugar de espacios, se utilizará en la dirección de la nueva aplicación. Si deja en blanco, vamos a generar una en nombre de la aplicación. este subsitio Este usuario ha dejado la comunidad. Para añadir un grupo primero selecciona un tipo de grupos de la página <a href="../group-types/">administración de tipos de grupo</a> Para <strong>añadir una nueva aplicación</strong> en este sitio, cree un <em>nuevo subdirectorio</em> bajo el directorio seleccionado. Entonces elija <em>nueva aplicación</em> para seleccionar e instalar el paquete a instanciar. La aplicación estará disponible en la URL mostrada. Para <strong>configurar</strong> una aplicación, seleccione <em>parámetros</em> para ver y editar las opciones específicas de la aplicación. <em>Permisos</em> permite otorgar privilegios a los usuarios y grupos sobre aplicaciones específicas u otros datos de la aplicación. Para más información sobre parámetros y permisos, ver la documentación específica del paquete. Para <strong>copiar</strong> una aplicación a otra URL, crear una nueva carpeta y entonces seleccionar <em>montar</em>. Seleccionar la aplicación que será copiada desde la lista de paquetes disponibles. Por favor, compruebe la bandeja de Entrada. En los próximos minutos debe recibir un correo de %system_owner% con una nueva contraseña generada aleatoriamente y las instrucciones de cómo proceder. Una vez recibidas, vuelva a la Para <strong>mover</strong> una aplicación, copiela a la nueva ubicación como indicado arriba, entonces selecione <em>desmontar</em> en la antigua localización. Seleccionando <em>borrar</em> en la carpeta vacía la eliminará del nodo. Para <strong>eliminar</strong> una aplicación y todos sus datos, seleccione <em>Desmontar</em> en todos los nodos donde se montaron, entonces <em>borrelos</em> desde las <em>Aplicaciones no montadas</em>, con el link debajo del mapa del sitio. Tópico Introduzca información especifica Correo desconocido desmontar ARRIBA volver a %context_name% Actualizar Actualizar contraseña subir subir una foto Subir nueva foto Subir una foto URL Nombre de carpeta Nombre de usuario Fotografía del usuario Fotografías de usuario Perfil de usuario Perfiles de usuario Nombre de usuario No se encontró ningún usuario con nombre de usuario '%username%' en la autoridad %this_authority% Nombre de usuario requerido Mapa del sitio del usuario Información de Vacaciones Actualizada La información de sus vacaciones en %site_link% ha sido actualizada. Ver todos los miembros que están conectados Ver todos los roles Ver Índice Alfabético Visible para Bienvenido/a, %user_name% Si deja de selecionar un privilegio, eleminará dicho privilegio al grupo que que excogió si este grupo tenía anteriormete el privilegio. Usuarios conectados en este momento Quién está conectado Escritura Sí, estoy seguro Pertenece a los siguientes grupos: También puede navegar desde el Usted siembre puede reabrirlo con Puede especificar los tipos por defecto de las relaciones que pueden ser utilizados para los grupos de este tipo. Tenga en cuenta que después cada grupo puede cambiar sus tipos de relación permitido. No tiene derechos de administración en el objeto %root% ni sobre sus hijos Usted no tiene una foto. Puede añadirla si lo desea. Tiene derechos de administración en los siguientes objetos: No tiene avisos de correo activados. Su Cuenta Sus avisos en los foros Su foto Su %gc_system_name% alerta Usted vuelve de vacaciones en %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.it_IT.ISO-8859-1.xml0000644000175000017500000005417710727201372025601 0ustar frankiefrankie , oppure Aggiorna Informazione di Base Iscritto alla comunita' %system_name% sin dal Riguardo a te La tua account su %system_name% è stata chiusa. No, riportami alla %pvt_home_name% Si, eliminate la mia utenza <p>La tua account è attualmente chiusa.</p> <p>Se lo desideri, possiamo <a href="%restore_url%">riaprirla</a>.</p> <p> <font color="red"> <b> La tua utenza e' attualmente disattivata. </b> </font> Fai <a href="%login_url%">login</a> nuovamente per vedere quali possibilita' ti vengono offerte. </p&;gt; La tua utenza per %system_name% e' stata riattivata. Bentornato. La tua utenza e' stata riattivata Azione Aggiungi una nuova application Pannello di Controllo Amministra %subsite_name% Opzioni amministrative per questo utente Tipo di notifica un altra fotografia. Risposta: Errore dell'applicazione Applicazioni Approva su Autorità Password Inadatta Bandisci Informazioni Fondamentali Biografia Non e' permesso recuperare la password dall'autorita' locale Non puoi vedere la lista dei partecipanti Cambia Lingua Cambia la Password Cambia password, email, ritratto Controlla la tua posta Figli <p> Devi confermare che hai intenzione di chiudere la tua utenza su %system_name%. </p> <p> La chiusura dell'utenza significa che non ti invieremo più notifiche via Mail, né che apparirai nella lista degli utenti di %system_name%. Ad ogni modo i tuoi contributi alla comunità saranno mantenuti, in quanto parte della storia della comunità. </p> <p> Tieni conto che potrai riaprire la tua utenza in ogni momento, semplicemente effettuando il login. </p> Chiudi la tua utenza Gruppo ad iscrizione riservata Commento Le comunità le comunità comunità Conferma Password: Nuova password confermata. Procedi Procedi a %pvt_home_name% Nazione Crea %pretty_name% Crea nuovo subsite Attuale Password: <p> Lo stato della tua connessione non è visibile agli altri utenti. </p> <p> Lo stato della tua connessione è visibile agli altri utenti. </p> Personalizza la domanda Errore del Database contesto di default Elimina Amministratore Amministrazione per lo Sviluppatore Permessi diretti Disabilita Disabilitato Dominio E-mail modifica il commento Certi elementi non sono modificabili, in quanto gestiti da %authority_name%. Email Queste sono i nuovi dati per il login: %account_id_label%: %account_id% %password_label%: %password% Clicca sul link seguente per modificare la tua password: %reset_password_url% Grazie per esserti registrato su %system_name%. Ecco come devi fare per loggarti su %system_url%: %account_id_label%: %account_id% %password_label%: %password% Clicca sul link seguente per modificare la tua password: %reset_password_url% Conferma Email Email non richiesta La password che avevi dimenticato su %system_name% Benvenuto su %system_name% Abilitato Inserisci il tuo username per iniziare la procedura recupero password. Elimina il ritratto elimina il ritratto Errore Errore nell'invio dell'email Scade Nome file Nome/i di battesimo Hai dimenticato la tua password? Frequenza Indietro invia il ritratto dell'utente invia il tuo ritratto Garantisci Garantisci il permesso Nascondi Pagina home Se tu dovessi Informazione Modificata Invita Codice ISO Lista dei codici ISO Codici ISO Non Caricati Codici ISO non caricati Partecipa alla comunità Partecipa al gruppo %group_name% Partecipa al subsite Partecipa a questa comunità Partecipa a questo subsite Parola chiave (keyword) Cognome più tardi. Abbandona la comunità Abbandona il subsite Abbandona questa comunità Abbandona questo subsite Indietro senza aggiungere alcun utente Entra entra Entra su %system_name% stiamo rieseguendo il logon La pagina di log in è scaduta. Devi rieffettuare il login Fai login oppure registrati pagina di login Esci Esci da %system_name% , potrai avere più informazioni sull'appartente alla comunità. Non è possibile partecipare a questo gruppo. Lista Completa dei Codici ISO Continua il lavoro su %system_name% Modifica i commento al ritratto di %first_names% %last_name% %first_names% %last_name% (%email%) registrato come utente di %system_url% Per Amministratori di livello Sito Garantisci il permesso su %name% Questi è quanto risulta dal database: Come vorresti che %first_names% %last_name% fosse visibile ad occhi esterni ? Se pensi che non abbia gia' un account: Se pensi o sai che la persona che vorresti invitare abbia già un account su questo sistema: Se hai bisogno di questa funzionalità, devi caricare acs-reference e ref-countries Eredita i pemessi Se stai usando un computer pubblico, per esempio presso una libreria o una scuola, questa è una <b>pessima</b>scelta. Chiunque subentrasse alla tua postazione potrebbe utilizzare la tua identità su questo sito. Nuova registrazione su %system_url% Attenzione: la presenza ti testo in rosso sotto i campi dei parametri indica che il valore di qeusto parametro è sovrascritto da un parametro nel file dei parametri di OpenAcs. L'uso del file dei parametri è sconsigliato, anche se alcuni siti potrebbero necessitarne per avere valori specifici per istanza per parametri indipendetemente dalle tabelle apm_parameter* Nota che puoi cancellare il tuo indirizzo mail e la password registrate, scegliendo &quot;log out&quot; dal menu. %num_children% Figli Nascosti Il %portrait_publish_date%, hai caricato <a href="/user/portrait/">%portrait_title%</a> Il nostro server può dire al tuo browser di ricordare alcune cose, come il tuo indirizzo email e la password. Questo è utile per te, perchè se sei la sola persona ad usare questo computer, non dovrai fornirci i tuoi dati ogni volta. Conferma Password: Indirzzo della Home Page personale: Devi scegliere il codice del tuo paese tra quelli elencati di seguito e poi usare il pulsante "indietro" sul tuo browser per tornare alla form precedente Per favore leggi e segui le istruzioni riportate in questo messaggio. Prova a <a href="index">fare la login</a> un'altra volta Ritratto di %first_names% %last_name% I privilegi gerarchicamente più importanti implicano i privilegi dei livelli inferiori, ad esempio concedere permesso Admin implica automaticamente read, write etc. Ci sono problemi con l'autenticazione Le informazioni per la registrazione a questo sito sono appena state inviate all'indirizzo %email%. Le informazioni per la registrazione a questo sito sono appena state inviate all'indirizzo %email%. La tua richiesdta di registrazione è stata inoltrata all'amministratore di %system_name% ed è in attesa di approvazione. Sto salvando l'indirizzo email e la password Mostra a tutti gli utenti di %system_name% quanto sei bello: Spiacente, ma sembra che tu sia stato bandito da %system_name%. Sei sicuro di voler cancellare il ritratto di questo utente ? Sei sicuro di voler cancellare il tuo ritratto ? La tua fotografia nel sistema non è valida. Devi C'era una problema con l'autenticazione della tua utenza Questa è l'immagine che viene mostrata agli altri utenti su %system_name% L'utente non ha un ritratto. Puoi Questo utente è stato eliminato e bandito dalla comunità. Per confermare la tua registrazione, vai alla pagina %confirmation_url% Carica il tuo file preferito dal tuo computer, sia una JPEG od una GIF (tieni conto che non puoi inserire un link, ma che il file deve essere sul tuo disco locale) Caricato: %pretty_date% Caricato: %publish_date% Usa il pulsante "Browse..." per trovare il file, e poi clicca su "Open". Questo utente ha inserito una biografia o caricato un ritratto Non ti troviamo (utente %user_id) nella lista degli utenti. Probabilmente per qualche ragione questa utenza è stata eliminata. C'è stato un problema nel processare i tuoi dati. Non stavamo aspettando il tuo email. Ci deve essere qualche errore. Benvenuto su %system_name% Ecco cosa vedono gli altri utenti quando cliccano sul tuo nome Non puoi avere un &lt; nel tuo nome, perchè sembrerà un tag HTML, confondendo gli altri utenti. Non puoi avere un &lt; nel tuo nome, perchè sembrerà un tag HTML, confondendo gli altri utenti. Non riceverai altre emails fino a dopo il %pretty_date%. Il tuo indirizzo email è stato confermato. Ora puoi fare la login su %system_name%. Il tuo indirizzo email è stato confermato. Ora sei in attesa di approvazione da parte dell'amministratore di %system_name%. Il tuo indirizzo email è confermato La tua login è scaduta. Devi reinserire la tua password per continuare a lavorare. L'indirizzo che hai immesso non ha una forma corretta. Un indirizzo valido dovrebbe essere qualcosa del tipo \"%valid_url_example%\"." Rendi amministratore Rendi membro Renditi invisibile Renditi visibile Gestisci le tue notifiche Spiacenti, non ti è permesso vedere la lista dei membri. Stato del membro Membri Nome: Nuova Password: Non ci sono applicazioni. Non ci sono codici ISO. Questo package non ha parametri. il tuo ritratto Non ci sono %pretty_plural% Non ci sono servizi. nessuno Non sei loggato Note: Avvertenza: su %name% a: (opzionale) Opzioni Oppure aggiungi un nuovo utente o il Password: Dati per la login su %system_name%: %account_id_label%: %account_id% La tua password relativa a questo account è stata appena cambiata. Non è necessario che tu faccia nulla, questo messaggio è semplicemente una conferma, per aumentare la sicurezza del tuo account. --------------- Puoi cambiare la tua password in ogni momento nella maniera seguente: 1. Fai login su %system_name% 2. Clicca sul link "%pvt_home_name%" 3. Scegli "%password_update_link_text%" Password cambiata Permessi permessi Permessi per %name% Devi tornare a %home_link% Ritratto Profilo Domanda: Ri-abilita Recupera la password Riattiva la login Registrati <p> Grazie per esserti registrato su %system_name%. Un amministratore verrà avvertito della tua richiesta. </p> <p> Quando la tua richiesta verrà approvata, riceverai una mail e potrai iniziare ad usare %system_name%. </p> Rifiuta Ricorda Rimuovi Rimuovere tutto Richieste di partecipazione di questa comunità Richieste di partecipazione di questo subsite Richiedi di partecipare ritorna alla applicazione Rimuovi gli elementi selezionati Ruolo Salva il commento Nome schermo Ricerca un utente esistente Radice contesto di sicurezza Seleziona un Oggetto per ID: Invia mail a questo utente Mostra Amministrazione a livello di sito Spiecanti, non ti possiamo aiutare riguardo alla password che hai perso/dimenticato. Stato Storia riguardo alla foto Storia della foto Sottocomunità sottocomunità sottocomunità subsite Subsites subsites Grazie. I codici ISO non sono stati caricati su questo server. Questo gruppo è a partecipazione ristretta. Per potere accedere devi essere invitato. quest subsite Questo utente ha abbandonato la comunità. Controlla la tua mail. Nei prossimi minuti dovresti ricevere un messaggio da %system_owner% con le istruzioni relative a Soggetto Info SU su %context_name% Aggiorna Aggiorna password carica carica un tuo ritratto carica un nuovo ritratto Carica un ritratto Nome utente Mappa di Sito di utente Informazione ferie aggiornata. Informazione ferie su %site_link% aggiornata. Benvenuto, %user_name% Lasciando una checkbox vuota qui, allora quel privilegio viene tolto all'entità a cui era stato invece precedentemente concesso. Utenti online in questo momento Chi è connesso Si, sono sicuro Appartieni ai seguenti gruppi Puoi anche scorrere dal Potrai sempre riaprirlo tramite Non hai i diritti di amministrare l'oggetto %root% od alcuno dei suoi oggetti figlio Non hai ancora un ritratto. Puoi Hai diritti di amministrare i seguenti oggetti: Al momento non hai notifiche via email attive. La tua Utenza Le tue notifiche riguardanti i forum di discussione Il Tuo Ritratto Le tue notifiche su %gc_system_name% Sei segnalato come di ritorno a %site_link% openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ch_zh.utf-8.xml0000644000175000017500000004423011056027177025416 0ustar frankiefrankie ,å¦åˆ™ %system_name%团体的会员 关于我…… 您在%system_name%çš„å¸æˆ·å·²å…³é—­ã€‚ ä¸ï¼Œè¿”回%pvt_home_name% æ˜¯ï¼Œè¯·å…³é—­å¸æˆ·ã€‚ <p>æ‚¨çš„å¸æˆ·å·²å…³é—­ã€‚</p> <p>我们å¯ä»¥ä¸ºæ‚¨<a href="%restore_url%">釿–°æ‰“å¼€</a>。</p> <p> <font color="red"> <b> æ‚¨çš„å¸æˆ·å·²å…³é—­ã€‚å¯ä»¥é‡æ–°</b> </font> <a href="%="%login_url%%">登陆</a> 查看有关情况。 </p&;gt; 您在%system_name%çš„å¸æˆ·é‡æ–°æ‰“开,欢迎回æ¥ã€‚ 叿ˆ·é‡æ–°æ‰“å¼€ 动作 加入新申请 ç®¡ç† ç®¡ç†%subsite_name% 用户管ç†é€‰é¡¹ æç¤ºç±»åž‹ å¦ä¸€å¹…图片。 解答 申请错误 申请 批准 在 æƒé™ 密ç é”™è¯¯ ç¦æ­¢ åŸºæœ¬ä¿¡æ¯ è‡ªä¼  䏿”¯æŒé€šè¿‡æœ¬åœ°æƒé™é‡æ–°æ‰¾å›žå¯†ç ã€‚ ä¸èƒ½æµè§ˆä¼šå‘˜åˆ—表 改å˜è¯­è¨€ 改å˜å¯†ç  改å˜å¯†ç ã€emailã€è‚–åƒ æ£€æŸ¥æ”¶ä»¶ç®± å­ <p> 请确认您è¦å…³é—­åœ¨%system_name%çš„å¸æˆ·ã€‚ </p> <p> 关闭叿ˆ·æ„å‘³ç€æˆ‘们将ä¸å†ç»™ä½ å‘邮件通知,也ä¸ä¼šå†ä¸ºæ‚¨æ˜¾ç¤º%system_name%的会员列表。但是,您的资料作为团体历å²è®°å½•的一部分将被ä¿ç•™ä¸‹æ¥ã€‚</p> <p> 注æ„:您å¯ä»¥éšæ—¶ç™»é™†ï¼Œé‡æ–°æ‰“å¼€æ‚¨çš„å¸æˆ·ã€‚</p> 关闭叿ˆ· 关闭组 评论 团体 团体 团体 确认 ç»§ç»­ 国家å 创建新%pretty_name% 新建å­ç½‘页 当å‰å¯†ç  当å‰çš„在线状æ€ä¸ºä¸å¯è§ã€‚ 当å‰çš„在线状æ€ä¸ºå¯è§ã€‚ 用户化问题 æ•°æ®åº“错误 缺çœä¸Šä¸‹æ–‡ 删除 å¼€å‘ç®¡ç† å¼€å‘äººå‘˜ç®¡ç† ç›´æŽ¥å…许 使ä¸èƒ½ 使ä¸èƒ½çš„ 管区 E-mail 编辑评论 被%authority_name%管ç†çš„特定对象ä¸å¯ç¼–辑。 Email 这是您新的登陆信æ¯ï¼š%account_id_label%: %account_id% %password_label%: %password%请点击下é¢çš„链接更改密ç ã€‚ 感谢您注册%system_name%. 这里是如何登陆%system_url%: %account_id_label%: %account_id% %password_label%: %password% 请点击下é¢çš„链接更改密ç ã€‚ Email确认 ä¸èƒ½ç”³è¯·Email 您在%system_name%å¿˜è®°çš„å¯†ç  æ¬¢è¿Žæ¥åˆ°%system_name% 使能的 输入用户å开始æ¢å¤å¯†ç ã€‚ æ“¦é™¤è‚–åƒ æ“¦é™¤è‚–åƒ é”™è¯¯ å‘é€é‚®ä»¶é”™è¯¯ 过期 文件å å 忘记密了ç ï¼Ÿ 频率 å‘åŽ ä¸Šä¼ ç”¨æˆ·è‚–åƒ ä¸Šä¼ ä½ çš„è‚–åƒ å‡†äºˆ 准许 éšè— 主页 å‡å¦‚你是 ä¿¡æ¯æ›´æ–° 邀请 ISOç¼–ç  ISOç¼–ç åˆ—表 ISOç¼–ç æ²¡æœ‰è£…è½½ ISOç¼–ç æ²¡æœ‰è£…è½½ 加入团体 加入%group_name% å‚加å­ç½‘ç«™ 加入这个团体 å‚加此å­ç½‘ç«™ 关键字 å§“ ç¨åŽã€‚ 离开团体 离开å­ç½‘页 离开团体 离开这个å­ç½‘页 ä¸å¢žåŠ ä»»ä½•ç”¨æˆ·åŽé€€ 登录 登陆 登陆到%system_name% 釿–°ç™»é™† ç™»é™†ç½‘é¡µè¿‡æœŸã€‚è¯·é‡æ–°ç™»é™†ã€‚ 登陆或注册 登陆网页 退出 从%system_name%退出 ,你å¯ä»¥ä»Žä½ çš„åŒå›¢ä½“会员那里得到更多的信æ¯ã€‚ ä¸èƒ½åŠ å…¥è¯¥ç»„ 所有的ISOç¼–ç åˆ—表 继续在%system_name%工作 编辑%first_names% %last_name%è‚–åƒçš„评论 %first_names% %last_name% (%email%)已在%system_url%注册 为网站管ç†å‘˜ 准许%name% 这是数æ®åº“中的内容 您认为%first_names% %last_name%如何? å¦‚æžœä½ è®¤ä¸ºæ­¤äººè¿˜æ²¡æœ‰ä¸€ä¸ªå¸æˆ·ï¼š å¦‚æžœä½ æ­£å¥½çŸ¥é“æˆ–ç›¸ä¿¡ä½ æ‰€é‚€è¯·çš„äººå·²æœ‰äº†æ­¤ç³»ç»Ÿçš„å¸æˆ·ï¼š å¦‚æžœéœ€è¦æ­¤åŠŸèƒ½ï¼Œè¯·å®‰è£…acs-reference and ref-countries。 ç»§æ‰¿çš„è®¸å¯ å¦‚æžœæ‚¨ä½¿ç”¨çš„æ˜¯å…¬å…±è®¡ç®—æœºï¼Œå»ºè®®ä¸é€‰ç”¨è¯¥é¡¹ã€‚å¦åˆ™ï¼Œä½¿ç”¨è¯¥è®¡ç®—机的其他人有å¯èƒ½ä¼šä»¥æ‚¨çš„å义使用系统。 新注册到%system_url% 注æ„ï¼šå‚æ•°åŸŸä¸‹é¢æ–‡æœ¬ä¸ºçº¢è‰²æ ‡è®°æ—¶è¡¨ç¤ºæ­¤å‚数的值被OpenACS傿•°æ–‡ä»¶æ‹’ç»ã€‚一般ä¸å»ºè®®ä½¿ç”¨å‚数文件,但是æŸäº›ç½‘站需è¦å®ƒæä¾›ç‰¹å®šå€¼ã€‚ 注æ„:在你的工作空间中选择"退出"ï¼Œå–æ¶ˆä½ å­˜å‚¨çš„email地å€å’Œå¯†ç ã€‚ %num_children%å­éšè— %portrait_publish_date%日,您上传了<a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> æœåС噍å¯ä»¥è®°å¿†email地å€å’Œå¯†ç ã€‚如果您是个人使用该计算机,就ä¸ç”¨æ¯æ¬¡éƒ½è¾“å…¥email地å€å’Œå¯†ç ã€‚ 密ç ç¡®è®¤ 个人主页URL: 请在下é¢åˆ—表中找到您的国家代ç ï¼Œå•击Back钮返回å‰ä¸€è¡¨æ ¼ã€‚ 请阅读email中的说明。 è¯·é‡æ–°<a href="index">登陆</a>。 %first_names% %last_name%çš„è‚–åƒ é«˜æƒé™çš„用户能自动赋予下级它所具有的æƒåˆ©ã€‚å¦‚ï¼Œå½“æŽˆäºˆäº†ç®¡ç†æƒåŽï¼Œå°±èƒ½è¯»ã€å†™ç­‰ç­‰ã€‚ è®¤å®šå¸æˆ·é—®é¢˜ 注册信æ¯è¢«å‘é€åˆ°%email%。 注册信æ¯å·²å‘é€åˆ°%email%。 您的注册信æ¯å·²æäº¤åˆ°%system_name%管ç†å‘˜ã€‚请等待批准。 ä¿å­˜email地å€å’Œå¯†ç  在%system_name%上展示风采: 对ä¸èµ·ï¼Œæ‚¨ä¼¼ä¹Žå·²è¢«%system_name%ç¦æ­¢ã€‚ 真的è¦åˆ é™¤æ­¤ç”¨æˆ·è‚–åƒå—? 真的è¦åˆ é™¤ä½ çš„è‚–åƒå—? 您在系统中的图片格å¼éžæ³•,请 è®¤å®šå¸æˆ·æœ‰é—®é¢˜ã€‚ 这是给%system_name%系统中其他用户看的图片 该用户还没有肖åƒï¼Œæ‚¨å¯ä»¥ æ­¤ç”¨æˆ·å·²è¢«è¯¥å›¢ä½“åˆ é™¤å¹¶ç¦æ­¢ã€‚ 请到%confirmation_url%确认注册。 从本地机上传适当格å¼çš„æ–‡ä»¶ï¼Œå¦‚JPEGã€GIF。注æ„:图片必须在本地机上。 上传:%pretty_date% 上传:%publish_date% 使用“æµè§ˆâ€æŒ‰é’®æ‰¾åˆ°æ–‡ä»¶ï¼Œå•击“打开â€ã€‚ 在用户列表中找ä¸åˆ°æ‚¨(%user_id%)ï¼Œæ‚¨çš„å¸æˆ·å¯èƒ½å·²è¢«åˆ é™¤ã€‚ å¤„ç†æ‚¨çš„登陆时出现问题。 我们一直在等待您的email。肯定有其它错误。 欢迎æ¥åˆ°%system_name% 当别人点击你å字时能看到的内容 您的å字中没有&lt;,å¦åˆ™å°±è±¡ä¸€ä¸ªHTML标记,容易引起其他用户误解。 您的姓中没有&lt;,å¦åˆ™å°±è±¡ä¸€ä¸ªHTML标记,容易引起其他用户误解。 %pretty_date%åŽæ‚¨å°±æœ‰ä¸€ä¸ªemail。 您的email已确认。现在å¯ä»¥ç™»é™†%system_name%。 您的email已确认。请等候%system_name%管ç†å‘˜çš„æ‰¹å‡†ã€‚ 您的email已确认 æ‚¨çš„ç™»é™†è¿‡æœŸã€‚è¯·é‡æ–°è¾“入密ç å¯ç»§ç»­å·¥ä½œã€‚ URLæ ¼å¼é”™è¯¯ã€‚一个有效的URLæ ·å¼å¦‚下:"%valid_url_example%"。 使æˆä¸ºç®¡ç†å‘˜ 使æˆä¸ºä¼šå‘˜ 使自己ä¸å¯è§ 使自己å¯è§ 管ç†é€šçŸ¥ 对ä¸èµ·ï¼Œæ‚¨ä¸èƒ½æµè§ˆä¼šå‘˜åˆ—表。 ä¼šå‘˜çŠ¶æ€ ä¼šå‘˜ åç§° æ–°å¯†ç  æ²¡æœ‰ç”³è¯· 没有ISOç¼–ç  æ­¤åŒ…æ²¡æœ‰ä»»ä½•å‚æ•° æˆ‘çš„è‚–åƒ æ²¡æœ‰%pretty_plural 没有æœåŠ¡ 没有 没有登陆的 注æ„: 注æ„: %name%: (å¯é€‰çš„) 选项 或增加新用户 或这 å¯†ç  æ‚¨åœ¨çš„%system_name%登陆信æ¯ï¼š%account_id_label%: %account_id%ï¼Œæ‚¨å¸æˆ·çš„密ç å·²æ›´æ”¹ã€‚这仅仅是一个通知。您总å¯ä»¥é€šè¿‡ä»¥ä¸‹æ­¥éª¤æ›´æ”¹æ‚¨çš„密ç ï¼š1.登陆%system_name% 2.å•击"%pvt_home_name%" 3.选择"%password_update_link_text%" 密ç å·²æ›´æ”¹ è®¸å¯ è®¸å¯ è®¸å¯%name% 请返回%home_link%。 è‚–åƒ é—®é¢˜ 釿–°ä½¿èƒ½ æ¢å¤å¯†ç  更新登陆 注册 <p> 感谢您注册%system_name%. 管ç†å‘˜å·²ç»çœ‹åˆ°æ‚¨çš„申请. </p> <p> 当您收到申请被批准的email,就å¯ä»¥ä½¿ç”¨%system_name%。 </p> æ‹’ç» åœ¨æ­¤è®¡ç®—æœºä¸Šè®°ä½æˆ‘的登录 移除 申请为此团体的会员 申请å‚加此å­ç½‘ç«™ 申请为会员 返回申请 撤消选中的 角色 ä¿å­˜è¯„论 å§“å æœç´¢å·²å­˜åœ¨ç”¨æˆ· 安全上下文根 按ID选择对象: 给该用户å‘é€email 显示 ç½‘ç«™ç®¡ç† å¯¹ä¸èµ·ï¼Œå¯¹äºŽæ‚¨å¿˜è®°çš„å¯†ç æ— èƒ½ä¸ºåŠ›ã€‚ 身份 照片背åŽçš„æ•…事 照片背åŽçš„æ•…事 å­å›¢ä½“ å­å›¢ä½“ å­å›¢ä½“ å­ç½‘ç«™ å­ç½‘ç«™ å­ç½‘ç«™ è°¢è°¢ï¼ æ­¤æœåŠ¡å™¨æ²¡æœ‰å®‰è£…ISOç¼–ç ã€‚ 该组诗关闭的。新的æˆå‘˜æ”¶åˆ°é‚€è¯·åŽæ‰èƒ½åŠ å…¥ã€‚ å­ç½‘ç«™ 此用户已离开该团体。 è¦ç™»é™†ï¼Œè®¿é—® è¯é¢˜ æŒ‡å®šç±»åž‹ä¿¡æ¯ å‘上 上传到%context_name% æ›´æ–° 改å˜å¯†ç  上传 ä¸Šä¼ è‚–åƒ ä¸Šä¼ æ›¿æ¢è‚–åƒ ä¸Šä¼ è‚–åƒ ç”¨æˆ·å 休å‡ä¿¡æ¯å·²æ›´æ–° 你在%site_link%的休å‡ä¿¡æ¯å·²æ›´æ–°ã€‚ 欢迎您,%user_name% 如果ä¸é€‰æ‹©è¯¥é¡¹ï¼Œæ‚¨çš„æƒé™å°†ä»Žå›¢ä½“中撤消。 当å‰åœ¨çº¿ç”¨æˆ· 在线用户 是,我肯定 你也å¯ä»¥æµè§ˆ ä½ å¯ä»¥é‡æ–°æ‰“开它,使用 您没有对%root%åŠå…¶å­å¯¹è±¡çš„ç®¡ç†æƒ 你还没有肖åƒã€‚å¯ä»¥ 你有对以下å„é¡¹çš„ç®¡ç†æƒï¼š 你没有注册emailæç¤ºã€‚ æˆ‘çš„å¸æˆ· ä½ çš„è®ºå›æç¤º æˆ‘çš„è‚–åƒ ä½ çš„%gc_system_name%æç¤º %site_link%已被标记为休å‡ç»“æŸã€‚ openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.el_GR.utf-8.xml0000644000175000017500000012221110720404625025301 0ustar frankiefrankie ή ΕνημέÏωση βασικών πληÏοφοÏιών Μέλος της %system_name% κοινότητας από ΠληÏοφοÏίες Ο λογαÏιασμός σας στο %system_name% έχει κλείσει. Όχι, θέλω να επιστÏέψω στο %pvt_home_name% Îαι, παÏακαλώ κλείστε το λογαÏιασμό μου <p>Ο λογαÏιασμός σας είναι κλειστός.</p> <p>Εαν επιθυμείτε, μποÏοÏμε να τον <a href="%restore_url%">ανοίξουμε και πάλι/a>.</p> ΛογαÏισμός κλειστός <p> <font color="red"> <b> Ο λογαÏιασμός σας είναι κλειστός. </b> </font> <a href="%login_url%">Συνδεθείτε /a> πάλι για να δείτε τι μποÏείτε να κάνετε γι' αυτό. </p&;gt; Ο λογαÏισμός αυτός δεν είναι διαθέσιμος για την ÏŽÏα. Ο λογαÏιασμός σας στο %system_name% έχει ανοίξει πάλι. Καλως ήÏθατε. ΛογαÏιασμός πάλι ανοιχτός ΕνέÏγεια ΠÏοσθήκη Ï€Ïοσθήκη φακέλου ΠÏοσθήκη νέας εφαÏμογής ΠÏοσθήκη Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… χÏήστη ΠÏοσθήκη χÏήστη ΠÏοσθήκη χÏηστών Πίνακας Ελέγχου ΔιαχειÏιστής ΔιαχείÏιση %subsite_name% Επιλογές διαχείÏησης για αυτό τον χÏήστη ΤÏπος υπενθÏμισης μια άλλη φωτογÏαφία Απάντηση: Σφάλμα εφαÏμογής ΕφαÏμογές ΈγκÏιση στο ΕσωτεÏικό σφάλμα κατά την ταυτοποίηση ΤÏπος σÏνδεσης Λάθος Συνθηματικό ΑπαγόÏευση Βασικές ΠληÏοφοÏίες ΒιογÏαφίες ΒιογÏαφία ΤÏπος βιογÏαφίας ΤÏποι βιογÏαφίας Ανάκτηση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î±Ï€ÏŒ τοπική δυνατότητα δεν υποστηÏίζεται Δεν είναι δυνατό να δείτε τη λίστα μελών Αλλαγή γλώσσας Αλλαγή επιπέδου δημοσιοποίησης του email σας Αλλαγή ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î‘Î»Î»Î±Î³Î® κωδικοÏ, email, φωτογÏαφίας Έχετε (εσείς ή κάποιος άλλος) ζητήσει να αλλάξετε τον κωδικό σας. Για να ολοκληÏώσετε την αλλαγή, επισκευθείτε τον ακόλουθο σÏνδεσμο: Εαν δεν ζητήσατε εσείς την αλλαγή, τότε δεν χÏειάζεται να Ï€Ïοβείτε σε καμία ενέÏγεια. Αίτημα αλλαγής ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î³Î¹Î± Ελέγξτε τα εισεÏχόμενα Παιδιά Επιλέξτε ένα εÏωτηματολόγιο εγγÏαφής: Διαλέξτε το εÏωτηματολόγιο που θα εμφανίζεται στους νέους χÏήστες.<br> ΜποÏεί να χÏησιμοποιηθεί για να εκτελέσετε αυτόματα διάφοÏες ενέÏγειες (Ï€.χ. Ï€Ïοσθήκη ζÏηστών σε συγκεκεÏιμένες ομάδες, ειδοποιήσεις συγκεκεÏιμένων Ï€Ïοσώπων για τις νέες εγγÏαφές, κλπ.). <p> ΠαÏακαλώ επιβεβαιώστε πως θέλετε να κλείσετε τον λογαÏιασμό σας στο %system_name%. </p> <p> Κλείνοντας το λογαÏιασμό σας πως θα πάψουμε να σας στέλνουμε ειδοποιήσεις μέσω email και πως δεν θα συμπεÏιλαμβάνεστε ως μέλος στις λίστες του %system_name%. Το Ï€Ïοϊόν της συμμετοχής σας στην κοινότητα παÏαμένει παÏόλα αυτά διαθέσιμο καθώς αποτελεί ιστοÏικό αγαθό της κοινότητας. </p> <p> ΜποÏείτε να ανοίξετε το λογαÏιασμό σας οποιαδήποτε στιγμή απλά συνδεόμενος ξανά</p> Κλείσιμο του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚ Κλειστή ομάδα Σχόλιο Κοινότητες κοινότητες κοινότητα Επιβεβαίωση Επιλέξατε νέο κωδικό με επιτυχία. Συνέχεια Συνέχεια στο %pvt_home_name% Όνομα χώÏας ΔημιουÏγία ΔημιουÏγία νέου εÏωτηματολογίου ΔημιουÏγία νέου %pretty_name% ΔημιουÏγία νέου υπο ιστοχώÏου ΤÏέχον κωδικός <p> Η κατάσταση συνδεσής σας δεν είναι οÏατή για τους άλλους χÏήστες. </p> <p> Οι άλλοι χÏήστες βλέπουν πότε είστε συνδεμένος. </p> ΕπεξεÏγασία ΕÏώτησης Σφάλμα βάσης δεδομένων Ï€Ïοεπιλεγμένο πλαίσιο ΔιαγÏαφή διαγÏαφή DevAdmin ΔιαχείÏηση ανάπτυξης Άμεσες άδειες ΑπενεÏγοποιημένο ΑπενεÏγοποιημένο Domain email ΕπεξεÏγασία ΕπεξεÏγασία επιλεγμένου εÏωτηματολογίου επεξεÏγασία σχολίου ΕπεξεÏγασία επιλογών Κάποια στοιχεία δεν είναι δυνατόν να αλλαχθοÏν γιατί διαχειÏίζονται από %authority_name%. Email Îα επιτÏέπεται η επικοινωνία άλλων μαζί μου μέσω web φόÏμας Îα επιτÏέπεται η επικοινωνία με φόÏμα ΠÏοβολή του email μου ως φωτογÏαφία ΠÏοβολή email ως φωτογÏαφία ΠÏοβολή του email ως κείμενο ΠÏοβολή email ως κείμενο ΟÏίστε οι νέες πληÏοφοÏίες σÏνδεσης στο λογαÏισμό σας:%account_id_label%: %account_id% %password_label%: %password% ΠαÏακαλοÏμε επισκευθείτε τον ακόλουθο σÏνδεσμο για να αλλάξετε τον κωδικό σας: %reset_password_url% ΕυχαÏιστοÏμε για την εγγÏαφή σας στο %system_name%. Εδώ θα βÏείτε πως θα συνδεθείτε στο %system_url%: %account_id_label%: %account_id% %password_label%: %password% ΠαÏακαλοÏμε επισκευθείτε τον ακόλουθο σÏνδεσμο για να αλλάξετε τον κωδικό σας: %reset_password_url% Επιβεβαίωση email Îα μην εμφανίζονται τα email μου Îα μην εμφανίζονται τα email μου Μη διαθέσιμο Δεν έχει καταγÏαφεί μια διεÏθυνση email στο λογαÏιασμό σας. ΠαÏακαλοÏμε εισάγετε το email σας. Το email δεν απαιτείται Απαιτείται email Ο κωδικός που ξεχάσατε για το %system_name% %system_name% email ελέγχου ΕνεÏγοποιημένο Εισάγετε το όνομα χÏήστη για να ξεκινήσει η ανάκτηση του κωδικοÏ. ΔιαγÏαφή φωτογÏαφίας διαγÏαφή φωτογÏαφίας Σφάλμα Σφάλμα αποστολής email ΠÏοέκυψε κάποιο σφάλμα κατά την αποστολή του email ελέγχου ΠÏοέκυψε ένα σφάλμα κατά την εγγÏαφή του λογαÏÎ¹ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚. ΠÏοέκυψε κάποιο σφάλμα κατά την ενημέÏωση του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚ Λήξη ΑÏχείο Όνομα Το Όνομα δεν ήταν διαθέσιμο από τη δυνατότητα σÏνδεσης. ΠαÏακαλοÏμε εισάγετε το όνομα σας. Ξεχάσατε τον κωδικό σας; Συχνότητα ΕπιστÏοφή μετάβαση στο ανέβασμα της φωτογÏαφίας του χÏήστη μετάβαση στο ανέβασμα της φωτογÏαφίας σας ΠαÏαχώÏηση Άδεια παÏαχώÏησης ΥπάÏχει ήδη μια ομάδα με αυτό το email ΥπάÏχει ήδη ένας χÏήστης με αυτό το email. ΥπάÏχει ήδη ένας χÏήστης με αυτό το όνομα χÏήστη. <p><h3>ΠληÏοφοÏίες Βοήθειας</h3> ΑπόκÏυψη ΑÏχική Σελίδα Μήνυμα για ειδοποιήσεις Εαν επÏόκειτο να Οι πληÏοφοÏίες ενημεÏώθηκαν Εγκατάσταση υποστήÏιξης γλωσσών ΠÏόσκληση Κωδικός ISO Λίστα κωδικών ISO Οι κωδικοί ISO δεν έχουν φοÏτωθεί Οι κωδικοί ISO δεν έχουν φοÏτωθεί Είσοδος σε κοινότητα Είσοδος σε %group_name% Είσοδος σε ιστοχώÏο Είσοδος σε αυτή τη κοινότητα Είσοδος σε αυτό τον ιστοχώÏο Λέξη κλειδί Επώνυμο Το επώνυμο δεν είναι διαθέσιμο από τη δυνατότητα σÏνδεσης. ΠαÏακαλοÏμε εισάγετε το επώνυμο σας. αÏγότεÏα. Έξοδος από κοινότητα Έξοδος από ιστοχώÏο έξοδος από αυτή τη κοινότητα Έξοδος από αυτό τον ιστοχώÏο ΕπιστÏοφή χωÏίς Ï€Ïοσθήκη χÏηστών ΣÏνδεση σÏνδεση ΣÏνδεση στο %system_name% επανασÏνδεση Ο χÏόνος της σελίδας σÏνδεσης έχει λήξει. ΠαÏακαλοÏμε συνδεθείτε ξανά. Συνδεθείτε ή εγγÏαφείτε σελίδα σÏνδεσης ΑποσÏνδεση ΑποσÏνδεση από %system_name% , θα μποÏείτε να βÏείτε πεÏισσότεÏες πληÏοφοÏίες για κάποιο άλλο μέλος της κοινότητας. ΠÏοσθήκη επιλεγμένων χÏηστών ως χÏήστες που έχουν άδειες για το αντικείμενο σας. Δεν είναι δυνατή η εισαγωγή σε αυτή την ομάδα ΠλήÏης λίστα κωδικών ISO Συνεχίστε δουλεÏοντας στο %system_name% Καμία κληÏονόμηση από %parent_object_name% ΕπεξεÏγασία σχολίου για τη φωτογÏαφία του χÏήστη %first_names% %last_name% Ο %first_names% %last_name% (%email%) έχει καταχωÏηθεί ως χÏήστης του %system_url% Για διαχειÏιστές του ΙστοχώÏου ΠαÏοχή άδειας για τον %name% ΟÏίστε τα αποτελέσματα της βάσης δεδομένων: Πως θέλετε να βλέπει ο υπόλοιπος κόσμος τον %first_names% %last_name%; Εαν δεν νομίζετε ότι το Ï€Ïόσωπο διαθέτει ήδη ένα λογαÏιασμό: Εαν τυγχάνει να γνωÏίζετε ή να πιστεÏετε ότι το Ï€Ïόσωπο που θέλετε να Ï€Ïοσκαλέσετε έχει ήδη ένα λογαÏιασμό στο σÏστημα: Εαν χÏειάζεστε αυτή τη λειτουÏγία παÏακαλοÏμε να φοÏτώσετε τα acs-reference και ref-countries. ΚληÏονομια από %parent_object_name% ΚληÏονόμηση αδειών από %parent_object_name% Άδειες που κληÏονομοÏνται Θα ήταν Ï€Î¿Î»Ï ÎºÎ±ÎºÎ® ιδέαν να επιλέξετε αυτή τη δυνατότητα εαν χÏησιμοποιείτε ένα υπολογιστή κοινής χÏήσης για παÏάδειγμα σε μια βιβλιοθήκη ή ένα σχολείο. Οποιοσδήποτε χÏήστης που θα χÏησιμοποιήσει αυτό το σταθμό εÏγασίας μετά από εσάς, θα μποÏοÏσε να κάνει χÏήση της υπηÏεσίας με τα δικά σας στοιχεία. Îέα εγγÏαφή στο %system_url% Το κόκκινο κείμενο σημείωσης κάτω από το πεδίο εισαγωγής παÏαμέτÏων σημαίνει ότι η τιμή της παÏαμέτÏου είναι εκτός οÏίων βάσει του αÏχείου παÏαμέτÏων του OpenACS. Η χÏήση του αÏχείου παÏαμέτÏων δεν Ï€Ïοβλέπεται αλλά κάποιοι ιστοχώÏοι το χÏειάζονται για να παÏέχουν άμεσες τιμές σε συγκεκÏιμένες παÏαμέτÏους ανεξάÏτητα από τους πίνακες apm_parameter. Σημειώστε οτι μποÏείτε να διαγÏάψετε την αποθηκευμένη διεÏθυνση email και το κωδικό σας επιλέγοντας "ΑποσÏνδεση" από το σÏστημα. %num_children% απόγονοι σε απόκÏυψη Στις %portrait_publish_date%, ανεβάσατε <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Ο εξυπηÏετητής της υπηÏεσίας μποÏεί να υπενθιμίσει στον πλοηγό σας διάφοÏα θέματα, όπως για παÏάδειγμα τη διεÏθυνση email σας και τον κωδικό. Ευτό αποτελεί μια μεγάλη ευκολία γιατί εαν είστε ο μόνος χÏήστης που χÏησιμοποιεί το συγκεκεÏιμένο σταθμό εÏγασίας δεν υπάÏχει ανάγκη να εισάγετε συνεχώς τα σχετικά στοιχεία. Εισάγετε και πάλι το κωδικό URL ΠÏοσωπικής αÏχικής σελίδας: ΠαÏακαλοÏμε εντοπίστε από την ακόλουθη λίστα το κωδικό της χώÏας σας και στη συνέχεια χÏησιμοποιήστε το πλήκτÏο "πίσω" στο λογισμικό πλοήγησης για να επιστÏέψετε στη Ï€ÏοηγοÏμενη φόÏμα. ΠαÏακαλοÏμε διαβάστε και ακολουθήστε τις οδηγίες που αναγÏάφονται στο email. ΠαÏακαλοÏμε Ï€Ïοσπαθήστε να <a href="index"> συνδεθείτε </a> και πάλι ΦωτογÏαφία του %first_names% %last_name% ΠÏονόμια υψηλότεÏα στην ιεÏαÏχία ενεÏγοποιοÏν όλα τα χαμηλοτεÏου επιπέδου Ï€Ïονόμια, για παÏάδειγμα όταν παÏέχονται Ï€Ïονόμια διαχειÏιστή τότε η δυνατότητες ανάγνωσης, εγγÏαφής κτλ είναι αυτόματα ενεÏγές. ΠÏόβλημα με την ταυτοποίηση Η αίτηση εγγÏαφής σας έχει αποσταλλεί στον διαχειÏιστή του %system_name%. Αναμένεται έγκÏιση. Αποθήκευση διεÏθυνσης email και ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î”ÎµÎ¯Î¾Ï„Îµ στους χÏήστες του %system_name% πως μοιάζετε: Συγνώμη αλλά από ότι φαίνεται σας έχει απαγοÏευθεί η είσοδος στο %system_name%. ΤεÏματισμός κληÏονομιάς αδειών από το %parent_object_name% Είστε σίγουÏος ότι επιθυμείτε τη διαγÏαφή της φωτοφγÏαφίας Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… χÏήστη; Είστε σίγουÏος ότι επιθυμείτε τη διαγÏαφή της φωτογÏαφίας σας; Η φωτογÏαφία σας στο σÏστημα είναι μη αποδεκτή. ΠαÏακαλοÏμε Δεν υπάÏχουν χÏήστες που δεν έχουν ήδη Ï€Ïόσβαση σε αυτό το αντικείμενο ΠÏοέκυψε ένα Ï€Ïόβλημα με την ταυτοποίηση του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚ Αυτή είναι η εικόνα που δείχνουμε στους υπόλοιπους χÏήστες του %system_name% Αυτός ο χÏήστης δεν έχει ακόμα φωτογÏαφία. ΜποÏείτε Αυτός ο χÏήστης έχει διαγÏαφεί και αποκλειστεί από την κοινότητα. Ανεβάστε το αγαπημένο σας αÏχείο, ένα JPEG ή GIF έγγÏαφο από το σκληÏÏŒ δίσκο του υπολογιστή σας. Ανεβασμένο: %pretty_date% Ανεβασμένο: %publish_date% ΧÏησιμοποιήστε το πλήκτÏο "Αναζήτηση..." για να εντοπίσετε το αÏχείο και στη συνέχεια "Άνοιγμα". Αυτός ο χÏήστης έχει εισάγει ένα βιογÏαφικό ή ανέβασε μια φωτογÏαφία Δεν είναι δυνατόν να σας εντοπίσουμε (user %user_id%) στη λίστα χÏηστών. Είναι πιθανόν ο λογαÏιασμός σας να έχει διαγÏαφεί. ΠÏοέκυψε ένα Ï€Ïόβλημα κατά την επεξεÏγασία των δεδομένων που εισάγατε. Δεν αναμένουμε email από εσάς. Θα Ï€Ïέπει να Ï€Ïοέκυψε κάποιο σφάλμα. email ενεÏγοποίησης από το %system_name% Τι βλέπουν οι υπόλοιποι όταν κάνουν κλικ στο όνομα σας Δεν είναι δυνατόν να έχετε ένα &lt; στο όνομα σας γιατί θα φάινεται σαν ένα HTML tag και θα μπεÏδεÏει τους υπόλοιπους χÏήστες. Δεν είναι δυνατόν να έχετε ένα &lt; στο όνομα σας γιατί θα φάινεται σαν ένα HTML tag και θα μπεÏδεÏει τους υπόλοιπους χÏήστες. Θα Ï€Ïέπει να παÏέχετε τουλάχιστον ένα object_id_on ή object_id_two Δεν θα παÏαλάβετε κανένα email Ï€Ïιν την %pretty_date% Καλώς ήÏθατε! Έχετε ενεÏγοποιήσει με επιτυχία τη διεÏθυνση του email σας Το email σας έχει επιβεβαιωθεί. ΠεÏιμένετε τώÏα την εξουσιοδότηση από το διαχειÏιστή του %system_name% Το email σας έχει επιβεβαιωθεί Ο χÏόνος σÏνδεσης σας έχει λήξει. ΠαÏακαλοÏμε εισάγετε και παλί το κωδικό σας για να συνεχίσετε την εÏγασία σας. Το URL δεν έχει αποδεκτή διάταξη. Ένα έγκυÏο URL θα ήταν του Ï„Ïπου "%valid_url_example%". Αποστολή μυνληματος σε: ΔημιουÏγία διαχειÏιστή ΔημιουÏγία μέλους Γίνεται "αόÏατος" Îα φαίνεστε ΔιαχειÏιστείτε τη μυστικότητα των emails των χÏηστών ΔιαχείÏιση ειδοποιήσεων Συγνώμη αλλά δεν έχετε τη δυνατότητα Ï€Ïοβολής της λίστας μελών. Μέλος Κατάσταση μέλους Μέλη Ελλείπων επιχείÏημα εγκατάσταση Στοιχεία του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚ Όνομα νέα εφαÏμογή Îέος κωδικός Καμία εφαÏμογή Δεν υπάÏχει διαθέσιμη εκτίμηση Δεν υπάÏχουν κώδικες ISO ΑΣυτό το πακέτο δεν πεÏιέχει παÏαμέτÏους. Η φωτογÏαφία σας Καθόλου %pretty_plural% Καθόλου υπηÏεσίες δεν βÏέθηκε κανείς χÏήστης με αυτό το όνομα καμιά Δεν έχετε συνδεθεί Αυτή δεν είναι μια αποδεκτή διεÏθυνση email Σημειώσεις: Σχόλιο: στο %name% το: Σε σÏνδεση ΧÏόνος σε σÏνδεση (Ï€ÏοεÏαιτικά) Επιλογές Ή Ï€Ïοσθέστε και ένα χÏήστη ή την ΠαÏάμετÏοι παÏάμετÏοι Κωδικός ΟιπληÏοφοÏίες σÏνδεσης σας στο %system_name%:%account_id_label%: %account_id%: %account_id_label%: %account_id%. Ο κωδικός σÏνδεσης για το λογαÏιασμό αυτό έχει Ï€Ïόσφατα αλλαγθεί. Δεν χÏειάζεται να κάνετε κάτι Î±Ï†Î¿Ï Î±Ï…Ï„ÏŒ το μÏνημα αποτελεί μέÏος της διαδικασίας ασφάλειας. ΜποÏείτε πάντα να αλλάξετε το κωδικό της ο οποίας βÏίσκετε με την ακόλουθη διαδικασία: 1. ΣÏνδεση στο σÏστημα, 2. πατήστε στο σÏνδεσμο "%pvt_home_name%" και 3. Επιλέξτε το "%password_update_link_text%" Ο κωδικός αλλάγθηκε. Οι κωδικοί σας θα Ï€Ïέπει να αλλάζονται συχνά. ΠαÏακαλοÏμε αλλάξτε το κωδικό σας άμεσα. Οι κωδικοί δεν είναι οι ίδιοι. Η άδεια δεν είναι μεταβιβάσιμη. Άδειες άδειες Άδειες για %name% ΠαÏακαλοÏμε επιστÏέψτε στο %home_link%. ΦωτογÏαφία Με την δÏναμη του <a href="http://openacs.org" title="Σελίδες του OpenACS">OpenACS</a> Τι βλέπουν οι υπόλοιποι ΠαÏουσιάστηκε κάποιο σφάλμα κατά την ταυτοποίηση του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚. Το πιο πιθανό είναι η βάση δεδομένω πεÏιέχει χÏήστες χωÏίς member_state. ΠÏοφίλ ΕÏώτηση ΕπανενεÏγοποίηση Ανάγνωση Ανάκτηση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î‘Î½Î±Î½Î­Ï‰ÏƒÎ· σÏνδεσης ΕÏωτηματολόγιο εγγÏαφής χÏήστη ΕγγÏαφή <p> ΕυχαÏιστοÏμε για την εγγÏαφή σας στο %system_name%. ένας από τους διαχειÏιστές ασχολείται με το αίτημα σας. </p> <p> Όταν αυτό εγκÏιθεί, θα σας αποσταλλεί ένα email και θα μποÏείτε να χÏησιμοποιήσετε το %system_name%. </p> ΑπόÏÏιψη Îα συνδέομαι αυτόματα από αυτό τον υπολογιστή ΔιαγÏαφή διαγÏαφή όλων μετονομασία Αίτηση συμμετοχής σε αυτή τη κοινότητα Αίτηση συμμετοχής σε αυτό τον ιστοχώÏο Αίτηση αλλαγής ÎºÏ‰Î´Î¹ÎºÎ¿Ï ÏƒÏνδεσης: Μια ειδοποίηση για αλλαγή ÎºÏ‰Î´Î¹ÎºÎ¿Ï ÏƒÏνδεσης σας έχει ήδη αποσταλλέι. ακολουθήστε τις οδηγίες του email για να αλλάξετε το κωδικό συνδεσής σας. Αίτηση συμμετοχής ΕπαναφοÏά ÎºÏ‰Î´Î¹ÎºÎ¿Ï ÎµÏ€Î¹ÏƒÏ„Ïοφή στην εφαÏμογή Ανάκληση επιλεγμένη Ρόλος Αποθήκευση σχολίου Ψευδώνυμο Το όνομα σελίδας χÏησιμοποιείται ήδη. Αναζήτηση για έναν υπάÏχοντα χÏήστη ΔιαδÏομή πλαισίου ασφάλειας Επιλογή αντικειμένου βάσει ταυτότητας: Αποστολή email σε ασυτό το χÏήστη Στείλτε μου ένα αντίγÏαφο: ΟÏίστε την εκτίμιση για εγγÏαφή ΠÏοβολή ΔιαχείÏιση όλου του ιστοχώÏου ΔιαχείÏιση όλου του ιστοχώÏου Συγνώμη, δεν είναι δυνατόν να σας βοηθήσουμε εαν ξεχάσατε τον κωδικό. Κατάσταση Η ιστοÏία πίσω από τη φωτογÏαφία Η ιστοÏία πίσω από τη φωτογÏαφία Υποκοινότητες υποκοινότητες υποκοινότητα υποϊστοχώÏος ΥποϊστοχώÏοι υποϊστοχώÏοι Η ταυτοποίηση έγινε με επιτυχία, αλλά δεν έχετε ακόμα λογαÏιασμό στο %system_name%. ΕυχαÏιστοÏμε. Οι κωδικοί ISO δεν έχουν φοÏτωθεί σε αυτό τον εξυπηÏετητή. Η ομάδα είναι κλειστή. Îέα μέλη μποÏοÏν να έχουν Ï€Ïόσβαση μόνο με Ï€Ïόσκληση. αυτός ο υποϊστοχώÏος Ο χÏήστης έφυγε από την κοινότητα. ΠαÏακαλοÏμε ελέγξτε τα εισεÏχόμενα σας. Μέσα στα επόμενα λεπτά θα λάβετε ένα email από τον %system_owner% με ένα νέο τυχαίο κωδικό σÏνδεσης και οδηγείες για το πως θα ολοκληÏώσετε τη διαδικασία. Μετά τη λήψη του πηγαίνετε στο Θέμα πληÏοφοÏίες Ï„Ïπου Άγνωστο email μη συνδεδεμένο Επάνω μέχÏι το %context_name% ΕνημέÏωση ΕνημέÏωση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης ανέβασμα Ανέβασμα φωτογÏαφίας ανέβασμα νέας φωτογÏαφίας Ανέβασμα φωτογÏαφίας Όνομα χÏήστη ΦωτογÏαφία χÏήστη ΦωτογÏαφίες χÏηστών ΠÏοφίλ χÏήστη ΠÏοφίλ χÏηστών Όνομα χÏήστη Κανένας χÏήστης με δυνατότητα %this_authority% και με όνομα '%username%' δεν βÏέθηκε Απαιτείται όνομα χÏήστη ΧάÏτης ιστοχώÏου χÏήστη ΠληÏοφοÏίες διακοπών ενημεÏωμένες ΟιπληÏοφοÏίες διακοπών σας στο %site_link% έχουν ενημεÏωθεί. ΚαλωσήÏθες, %user_name% Όταν αφήνετε ένα πλαίσιο ελέγχου αδειανό τότε το Ï€Ïονόμιο αυτό αφαιÏείται από την ομάδα που επιλέξατε σε πεÏίπτωση που έχει παÏαχωÏηθεί στο παÏελθόν. Μέλη σε σÏνδεση Σε σÏνδεση ΕγγÏαφή Îαι, είμαι σίγουÏος Συμμετέχετε στις ακόλουθες ομάδες: ΜποÏείτε επίσης να πλοηγηθείτε από ΜποÏείτε πάντοτε να το ανοίξετε και πάλι μέσω Δεν έχετε διακαιώματα διαχείÏισης στο αντικείμενο %root% ή σε κάποιο από τους απογόνους του. Δεν έχετα φωτογÏαφία ακόμα. ΜποÏείτε Έχετε δικαιώματα διαχείÏισης για τα ακόλουθα αντικείμενα: Δεν υπάÏχουν email υπενθÏμισης καταγεγÏαμμένα. Ο λογαÏιασμός σας Οι υπενθυμίσεις των ομάδων συζήτησης που συμμετέχετε Η φωτογÏαφία σας Οι υπενθυμίσεις σας για το %gc_system_name% Έχει οÏιστεί η επιστÏοφή σας από διακοπές στο %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.en_AU.ISO-8859-1.xml0000644000175000017500000005221311056027177025552 0ustar frankiefrankie , or Update Basic Information A member of the %system_name% community since About You Your account at %system_name% has been closed. No, take me back to %pvt_home_name% Yes, please close my account <p>Your account is currently closed.</p> <p>If you wish, we can <a href="%restore_url%">reopen your account</a>.</p> <p> <font color="red"> <b> Your account is currently closed. </b> </font> <a href="%login_url%">Log in</a> again to see what you can do about it. </p&;gt; Your account at %system_name% has been reopened. Welcome back. Account Reopened Action Add new application Control Panel Administer %subsite_name% Administrative options for this user Alert Type another picture. Answer Application Error Applications Approve at Authority Bad Password Ban Basic Information Biography Retrieving password from local authority is not supported. Cannot see the members list Change language Change my Password Change password, email, portrait Check Your Inbox Children <p> Please confirm that you would like to close your account at %system_name%. </p> <p> Closing your account means that we will no longer send you email notifications, nor will you show up in lists of members at %system_name%. Your contributions to the community, however, will be preserved, as they're part of the community's history. </p> <p> Note that you may reopen your account at any time, siply by logging in again. </p> Close your account Closed Group Comment Communities communities community Confirm You have successfully chosen a new password. Continue Continue to %pvt_home_name% Country Name Create new %pretty_name% Create new subsite Current Password <p> Your online status is currently not visible to other users. </p> <p> Your online status is currently visible to other users. </p> Customize Question Database Error default context Delete DevAdmin Developer's Administration Direct Permissions Disable Disabled Domain E-mail edit comment Certain elements are not editable, because they are managed by %authority_name%. Email Here is your new login information: %account_id_label%: %account_id% %password_label%: %password% Please visit the following link to change your password now: %reset_password_url% Thank you for registering at %system_name%. Here's how you can log in at %system_url%: %account_id_label%: %account_id% %password_label%: %password% Please visit the following link to change your password now: %reset_password_url% Email Confirmation Email not Requested Your forgotten password on %system_name% Welcome to %system_name% Enabled Enter your username to begin password recovery. Erase Portrait erase portrait Error Error sending mail Expires Filename First names Forgot your password? Frequency Go back go upload the user's portrait go upload your portrait Grant Grant Permission Hide Home page If you were to Information Updated Invite ISO Code ISO Code List ISO Codes Not Loaded ISO Codes not loaded Join community Join %group_name% Join subsite Join this community Join this subsite Keyword Last name later. Leave community Leave subsite Leave this community Leave this subsite Go back without adding any users Login login Log in to %system_name% logging back in The login page has expired. Please log in again. Login or register login page Logout Logout from %system_name% , you'd be able to get more information on your fellow community member. Cannot join this group. Complete List of ISO Codes Continue working with %system_name% Edit comment for the portrait of %first_names% %last_name% %first_names% %last_name% (%email%) registered as a user of %system_url% For Site-Wide Administrators Grant Permission on %name% Here's what the database reported: How would you like the world to see %first_names% %last_name%? If you don't think the person has an account already: If you happen to know or believe that the person you would like to invite already has an account on this system: If you need this functionality, please load acs-reference and ref-countries. Inherited Permissions It would be a very bad idea to choose this option if you're using a shared computer in a library or school. Any subsequent user of this machine would be able to masquerade as you on our service. New registration at %system_url% Note text in red below the parameter entry fields indicates the value of this parameter is being overridden by an entry in the OpenACS parameter file. The use of the parameter file is discouraged but some sites need it to provide instance-specific values for parameters independent of the apm_parameter tables. Note that you can erase your saved email address and password by choosing the "log out" option from your workspace. %num_children% Children Hidden On %portrait_publish_date%, you uploaded <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Our server can tell your browser to remember certain things, such as your email address and password. This is convenient for you because, if you're the only person who uses your computer, you won't have to keep telling us your email address and password. Password Confirmation Personal Home Page URL: Please locate your country's code among those listed below then use the "back" button on your browser to return to the previous form. Please read and follow the instructions in this email. Please try to <a href="index">log in</a> again Portrait of %first_names% %last_name% Privileges higher in the hierarchy imply all the privileges below, e.g. when you grant admin, then read, write etc. are implied automatically. Problem with authentication Registration information for this service has just been sent to %email%. Registration information for this service has been sent to %email%. Your registration request has been submitted to the %system_name% administrator. It is still waiting approval. Saving email address and password Show everyone else at %system_name% how great looking you are: Sorry but it seems that you've been banned from %system_name%. Are you sure that you want to erase this user's portrait? Are you sure that you want to erase your portrait? The picture of you in the system is invalid. Please There was a problem with authenticating your account This is the image that we show to other users at %system_name% This user doesn't have a portrait yet. You can This user is deleted and banned from the community. To confirm your registration, please go to %confirmation_url% Upload your favorite file, a scanned JPEG or GIF, from your desktop computer system (note that you can't refer to an image elsewhere on the Internet; this image must be on your computer's hard drive). Uploaded: %pretty_date% Uploaded: %publish_date% Use the "Browse..." button to locate your file, then click "Open". This user has a entered a biography or uploaded a portrait We can't find you (user %user_id%) in the users table. Probably your account was deleted for some reason. We had a problem processing your entry. We were not awaiting your email. There must be some mistake. Welcome to %system_name% What other people see when they click your name You can't have a &lt; in your first name because it will look like an HTML tag and confuse other users. You can't have a &lt; in your last name because it will look like an HTML tag and confuse other users. You won't get any email until after %pretty_date%. Your email has been confirmed. You may now log into %system_name%. Your email has been confirmed. You are now awaiting approval from the %system_name% administrator. Your email is confirmed Your login has expired. Please retype your password to continue working. Your URL doesn't have the correct form. A valid URL would be something like "%valid_url_example%". Make administrator Make member Make yourself invisible Make yourself visible Manage your notifications Sorry, but you are not allowed to view the members list. Member State Members Name New Password No applications No ISO Codes This package does not have any parameters. your portrait No %pretty_plural% No services none Not logged in Notes: Notice: on %name% to: (optional) Options Or add a new user or the Password Your login information on %system_name%: %account_id_label%: %account_id% Your password for this account has recently been changed. You don't need to do anything, this message is simply a notification to protect the security of your account. --------------- You can always change your password by doing the following: 1. Log in to %system_name% 2. Click on the "%pvt_home_name%" link 3. Choose "%password_update_link_text%" Password changed Permissions permissions Permissions for %name% Please return to %home_link%. Portrait Profile Question Re-enable Recover Password Refresh login Register <p> Thank you for registering for %system_name%. An administrator has been notified of your request. </p> <p> Once you're approved, you'll get an email message and you can return to start using %system_name%. </p> Reject Remember my login on this computer Remove Request membership of this community Request membership of this subsite Request membership return to application Revoke Checked Role Save comment Screen name Search For An Existing User Security context root Select an Object by Id: Send email to this user Show Site-wide administration Sorry, we can't help you with your forgotten password. Status Story Behind Photo Story Behind Photo Subcommunities subcommunities subcommunity subsite Subsites subsites Thank you. The ISO codes were not loaded on this server. This group is closed. New members can only get access by invitation. this subsite This user has left the community. Please check your inbox. Within the next few minutes, you should find a message from %system_owner% with instructions on Topic type-specific info UP up to %context_name% Update Update Password upload upload a portrait upload a replacement portrait Upload Portrait Username Vacation Information Updated Your vacation information at %site_link% has been updated. Welcome, %user_name% When you leave a checkbox empty here then that privilege will be revoked from the party you choose in case it has been granted to that party before. Users currently online Who's Online Yes, I'm sure You are in the following groups: You can also browse from the You can always re-open it by You do not have admin rights on object %root% or any of it's children You don't have a portrait yet. You can You have admin rights on the following objects: You currently have no email alerts registered. Your Account Your discussion forum alerts Your Portrait Your %gc_system_name% alerts You're marked as back from vacation at %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ms_MY.utf-8.xml0000644000175000017500000005475110727201372025353 0ustar frankiefrankie , atau Kemaskini Informasi Asas Ahli kepada komuniti %system_name% sejak Tentang Anda Akaun anda di %system_name% telah ditutup. Tidak, bawa saya kembali ke %pvt_home_name% Ya, sila tutup akaun saya <p>Akaun anda ketika ini ditutup.</p><p>Jika anda mahu, kami boleh <a href="%restore_url%">buka semula akaun anda</a>.</p> <p><font color="red"><b>Akaun anda ketika ini ditutup.</b></font><a href="%login_url%">Log masuk</a> semula untuk melihat apa yang anda boleh lakukan.</p> Akaun anda di %system_name% telah dibuka semula. Selamat datang kembali! Akaun Dibuka Semula Tindakan Tambah aplikasi baru Urus Tadbir %subsite_name% Pilihan pengurusan untuk ahli ini Jenis amaran gambar lain. Jawapan Ralat Aplikasi Aplikasi-aplikasi Sahkan di Pengendali Salah Kata Laluan Halang Informasi Asas Biografi Tidak dibenarkan mendapatkan semula kata laluan dari pengendali ini. Gagal mendapatkan senarai ahli Tukar bahasa Ubah Kata Laluan Saya Tukar kata laluan, e-mel, gambar Semak Inbox Anda Anak <p>Sila sahkan jika anda mahu menutup akaun di %system_name%. </p><p>Menutup akaun anda bermakna kami tidak boleh memberi e-mel, dan anda tidak akan muncul lagi sebagai ahli di %system_name%. Walau bagaimanapun pemberian anda kepada komuniti dikekalkan sebagai simpanan kepada aset komuniti.</p><p>Anda masih boleh buka kembali akaun anda bila-bila masa hanya dengan login kembali,</p> Tutup akaun anda Kumpulan Tertutup Komen Komuniti-komuniti komuniti-komuniti komuniti Pastikan Anda telah berjaya memilih kata laluan baru. Teruskan Terus ke %pvt_home_name% Nama Negara Cipta %pretty_name% Bina sublaman baru Kata Laluan Kini <p>Status online anda ketika ini tidak kelihatan kepada ahli lain.</p> <p>Status online anda ketika ini boleh diketahui ahli lain.</p> Ubahsuai Soalan Ralat Pangkalan Data konteks asal Padam PengurusanPembangunan Pentadbiran Pembangun Kebenaran Terus Lumpuh Dilumpuhkan Domain E-mail edit komen Elemen-elemen tertentu tidak boleh diedit kerana ia diuruskan oleh %authority_name%. Emel Ini adalah informasi log masuk baru anda: %account_id_label%: %account_id% %password_label%: %password% Sila layari rangkaian berikut untuk mengubah kata laluan anda sekarang: %reset_password_url% Terima kasih kerana berdaftar di %system_name%. Beginilah caranya anda boleh log masuk ke %system_url%: %account_id_label%: %account_id% %password_label%: %password% Sila lawati pautan berikut untuk mengubah kata laluan anda sekarang: %reset_password_url% Pengesahan Email E-mail tidak dikehendaki Anda terlupa kata laluan anda di %system_name% Selamat Datang ke %system_name% Dipulihkan Masukkan nama pengguna anda untuk memulakan pengembalian kata laluan. Padamkan Potret padamkan potret Ralat Ralat menghantar mel Luput Nama Fail Nama Terlupa kata laluan anda? Frekuensi Pergi balik muat naikkan potret pengguna muat naikkan potret anda Diberi Hak Beri Kebenaran Sorok Halaman utama Sekiranya anda Maklumat Telah Dikemaskini Jemput Kod ISO Senarai Kod ISO Kod-kod ISO Tidak Dimuatkan Kod-kod ISO tidak dimuatkan Sertai komuniti Sertai %group_name% Sertai sublaman Sertai komuniti ini Sertai sublaman ini Kata Kunci Nama Bapa kemudian. Tinggalkan komuniti Tinggalkan sublaman Tinggalkan komuniti ini Tinggalkan sublaman ini Pergi balik tanpa menambahkan mana-mana pengguna Log Masuk log masuk Log masuk ke %system_name% log masuk semula Halaman log masuk telah tamat tempoh. Sila log masuk semula. Log masuk atau daftar halaman log masuk Log keluar Log keluar dari %system_name% , anda akan boleh mendapat lebih informasi daripada ahli komuniti yang lain. Tidak boleh memasuki kumpulan ini. Senarai Penuh Kod-kod ISO Bersambung kerja dengan %system_name% Edit komen pada potret untuk %first_names% %last_name% %first_names% %last_name% (%email%) telah berdaftar sebagai pengguna untuk %system_url% Untuk Pentadbir-pentadbir Tapak-Lebar Beri Kebenaran ke atas %name% Inilah apa yang dilaporkan pangkalan data: Bagaimanakah anda ingin pengguna lain melihat %first_names% %last_name%? Sekiranya anda tidak fikir bahawa seseorang itu sudah pun mempunyai akaun: Sekiranya anda tahu atau mempercayai bahawa seseorang yang anda ingin menjemput sudah pun mempunyai akaun di dalam sistem ini: Sekiranya anda perlu fungsi ini, sila muatkan acs-reference dan ref-countries. Kebenaran-kebenaran yang Diwarisi Ia adalah suatu cadangan yang buruk untuk memilih pilihan ini sekiranya anda menggunakan komputer berkongsi di perpustakaan atau sekolah. Mana-mana pengguna seterusnya yang menggunakan komputer ini akan dapat menyamar sebagai anda dalam servis kami. Pendaftaran baru di %system_url% Perhatikan teks berwarna merah di bawah medan pemasukan parameter yang menunjukkan bahawa nilai parameter ini akan digantikan dengan pemasukan dari dalam parameter OpenACS fail parameter. Penggunaan fail parameter ini tidak digalakkan tetapi terdapat beberapa laman yang memerlukannya untuk memberi nilai-nilai seketika tertentu untuk parameter-parameter yang tak bersandar kepada jadual-jadual apm_parameter. Perhatikan bahawa anda boleh padamkan alamat-alamat e-mel dan kata laluan tersimpan dengan memilih opsyen "log keluar" dari ruang kerja anda. %num_children% Anak-anak Tersorok Pada %portrait_publish_date%, anda telah memuat naikkan <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Pelayan kami boleh memberitahu pelayar anda supaya mengingati beberapa benda yang tertentu, seperti alamat-alamat e-mel dan kata laluan anda. Ini adalah untuk menyenangkan anda kerana, sekiranya anda adalah satu-satunya pengguna komputer anda, anda tidak perlu berulang kali memberitahu kami alamat e-mel dan kata laluan anda. Pengenal Pastian Kata Laluan Halaman Peribadi Utama URL: Sila pilih kod lokasi negara anda daripada senarai di bawah kemudian gunakan butang "back" pada pelayar anda untuk kembali kepada borang yang sebelumnya. Sila baca dan ikuti arahan-arahan di dalam e-mel ini. Sila cuba <a href="index">log masuk</a> sekali lagi Potret untuk %first_names% %last_name% Hak-hak istimewa yang berada di sebelah atas di dalam hierarki mengimplikasikan bahawa semua kelebihan di bawah, contohnya semasa anda memberi hak petadbiran, kemudian membaca, menulis dll. adalah diberi hak juga secara automatik. Masalah dengan pengesahan Informasi pendaftaran untuk servis ini telah baru sahaja dihantar ke %email%. Informasi pendaftaran untuk servis ini telah dihantar ke %email%. Permintaan pendaftaran anda telah dihantar ke pentadbir %system_name%. Ia masih menunggu kelulusan. Menyimpan alamat-alamat e-mel dan kata laluan Tunjukkan kepada pengguna lain di %system_name% bagaimana tampannya/jelitanya anda: Maaf tetapi didapati bahawa anda telah dilarang dari memasuki %system_name%. Adakah anda pasti bahawa anda ingin memadamkan potret pengguna ini? Adakah anda pasti bahawa anda ingin memadamkan potret anda? Gambar anda di dalam sistem ini tidak sah. Sila Terdapat masalah dalam pengesahan akaun anda Ini adalah imej yang kami paparkan kepada pengguna-pengguna lain di %system_name% Pengguna ini tidak mempunyai potret lagi. Anda boleh Pengguna ini telah dihapus dan dilarang daripada masuk ke dalam komuniti. Untuk memastikan pendaftaran anda, sila pergi ke %confirmation_url% Muat naikkan fail kegemaran anda, imbasan JPEG atau GIF, dari sistem komputer meja anda (perhatikan bahawa anda tidak boleh merujuk kepada imej yang berada di Internet; imej ini harus berada di dalam cakera liat komputer anda). Dimuat Naikkan: %pretty_date% Dimuat Naikkan: %publish_date% Gunakan butang "Browse..." untuk mendapatkan lokasi fail anda, kemudian klik "Open". Pengguna ini telah memasukkan biografi atau memuat naikan gambar Kami tidak dapat menjumpai anda (user %user_id%) di dalam jadual pengguna-pengguna. Kemungkinan akaun anda telah dihapuskan atas sebab-sebab tertentu. Kami telah mengalami masalah memproseskan kemasukan anda. Kami tidak menunggu kedatangan e-mel anda. Mungkin terdapat kesilapan. Selamat Datang ke %system_name% Apa pengguna lain melihat apabila nama anda diklik Anda tidak boleh mempunyai &lt; dalam nama anda kerana ia akan dianggap seperti suatu tag HTML dan akan mengelirukan pengguna-pengguna lain. Anda tidak boleh mempunyai &lt; dalam nama bapa anda kerana ia akan dianggap seperti suatu tag HTML dan akan mengelirukan pengguna-pengguna lain. Anda tidak akan menerima sebarang e-mel sehingga selepas %pretty_date%. E-mel anda telah dipastikan. Anda boleh log ke dalam %system_name% sekarang. E-mel anda telah dipastikan. Anda kini menunggu kelulusan daripada pentadbir %system_name% sekarang. E-mel anda telah dipastikan Log masuk anda telah tamat tempoh. Sila taip semula kata laluan anda untuk bersambung kerja. URL anda tidak mempunyai borang yang betul. URL yang sah adalah seperti "%valid_url_example%". Buatkan pentadbir Buatkan ahli Buatkan diri anda tidak kelihatan Buatkan diri anda kelihatan Uruskan notifikasi-notifikasi anda Maaf, tetapi anda tidak dibenarkan memapar senarai ahli-ahli. Keadaan Ahli Ahli-ahli Nama: Kata Laluan Baru: Tiada aplikasi-aplikasi Tiada Kod-kod ISO Pakej ini tidak mempunyai apa-apa parameter. potret anda Tiada %pretty_plural% Tiada servis tiada Tidak dilog masuk Nota-nota: Notis: ke %name% untuk: (beropsyen) Opsyen-opsyen Atau tambah pengguna baru atau Kata Laluan: Informasi log masuk anda di %system_name%: %account_id_label%: %account_id% Kata laluan anda untuk akaun ini telah kini diubah. Anda tidak perlu berbuat apa-apa, mesej ini hanya suatu notifikasi untuk melindungi sekuriti akaun anda. --------------- Anda sentiasa boleh menukar kata laluan anda dengan melakukan berikut: 1. Log masuk ke %system_name% 2. Klik pada laman "%pvt_home_name%" 3. Pilih "%password_update_link_text%" Kata laluan diubah Kebenaran-kebenaran kebenaran-kebenaran Kebenaran-kebenaran untuk %name% Sila kembali ke %home_link%. Potret Potfolio Soalan: Pulih Semula Baik Pulihkn Kata Laluan Segar semula log masuk Berdaftar <p> Terima kasih kerana berdaftar dengan %system_name%. Pentadbir kami telah pun diberi notis akan permohonan anda. </p> <p> Setibanya permohonan anda diluluskan, anda boleh menerima mesej e-mel dan kembali ke permulaan dengan menggunakan %system_name%. </p> Ditolak Ingatkan login saya di komputer ini Singkir Memohon keahlian untuk komuniti ini Memohon keahlian untuk sublaman ini Memohon keahlian kembali ke aplikasi Pilihan Ditarik Balik Disemak Watak Simpan komen Nama skrin Cari Pengguna yang Sedia Ada Akar Sekuriti Konteks Pilih suatu Objek mengikut turutan Id: Hantar e-eml kepada pengguna ini Paparkan Pentadbiran Tapak-lebar Maaf, kami tidak dapat menolong dengan terlupanya kata laluan anda. Status Cerita Disebalik Gambar Cerita disebalik gambar Subkomuniti-subkomuniti subkomuniti-subkomuniti Subkomuniti sublaman Sublaman-sublaman sublaman-sublaman Terima kasih. Kod-kod ISO tidak dimuatkan pada pelayan ini. Kumpulan ini ditutup. Ahli-ahli baru hanya boleh mendapat akses dengan cara jemputan. sublaman ini Pengguna ini telah meniggalkan komuniti ini. Untuk log masuk, layari Topik info jenis-tertentu ATAS sampai ke %context_name% Kemaskini Kemaskini Kata Laluan muat naik muat naik potret muat naik potret pengganti Muat Naik Potret Nama Pengguna Informasi Percutian Dikemaskinikan Informasi percutian anda di %site_link% telah dikemaskinikan. Selamat Datang, %user_name% Apabila anda meninggalkan suatu kotak semak kosong di sini, hak istimewa tersebut akan diambil balik daripada pihak yang dipilih sekiranya hak tersebut telah pun diberi sebelum ini. Pengguna-pengguna yang kini berada dalam talian Siapa di Dalam Talian Ya, saya pasti Anda dalam kumpulan-kumpulan berikut: Anda boleh juga melayari dari Anda boleh sentiasa membukanya semula dengan Anda tidak mempunyai hak pengurusan ke atas objek %root% atau mana-mana daripada anak-anaknya Anda tidak mempunyai gambar lagi. Anda boleh Anda mempunyai hak pengurusan untuk objek-objek berikut: Buat masa ini anda tidak mempunyai amaran e-mel yang diregister. Akaun Anda Forum perbincangan anda memberi awasan Gambar Anda %gc_system_name% anda memberi amaran Anda ditanda sudah kembali dari percutian di %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.cs_CZ.utf-8.xml0000644000175000017500000000071311056027177025322 0ustar frankiefrankie ZmÄ›nit jazyk ZmÄ›nit heslo, e-mail, portrét Odhlásit Odhlásit z %system_name% Vítejte, %user_name% Váš úÄet openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.sv_SE.ISO-8859-1.xml0000644000175000017500000005163310727201372025602 0ustar frankiefrankie , eller En medlem av %system_name% sedan Om dig Ditt konto hos %system_name% har stängts. Nej, ta mig tillbaka till %pvt_home_name% Ja, stäng mitt konto <p>Ditt konto är för närvarande stängt.</p> <p>Om du vill kan vi <a href="%restore_url%">öppna ditt konto igen</a>.</p> <p> <font color="red"> <b> Ditt konto är för närvarande stängt. </b> </font> <a href="%login_url%">Logga in</a> igen för att se vad du kan göra åt detta. </p> Ditt konto hos %system_name% har öppnats igen. Välkommen tillbaka. Kontot öppnat igen Åtgärd Lägg till ny applikation Administration Administrera %subsite_name% Apministrativa alternativ för denna användare Typ av meddelande en annan bild. Svar Applikationsfel Applikationer Godkänn Auktoritet Fel lösenord Bannlys Grundläggande information Biografi Återupprättande av lösenord från lokal auktoritet stöds inte. Får inte se medlemslistan Ändra språk Ändra mitt lösenord Ändra lösenord, e-post, porträtt Kolla din inbox Barn <p> Var god konfirmera att du vill stänga ditt konto hos %system_name%. </p> <p> I och med att du stänger kontot kommer vi inte längre skicka dig e-postnotifieringar, och du kommer heller inte visas i listan över medlemmar av %system_name%. Dina bidrag till gruppen kommer däremot bevaras, eftersom de ingår i vår gemensamma historia. </p> <p> Lägg märke till att du när som helst kan öppna ditt konto igen, helt enkelt genom att logga in igen. </p> Stäng ditt konto Stängd grupp Kommentar Grupper grupper grupp Bekräfta Fortsätt Land Skapa ny %pretty_name% Skapa ny subsajt Nuvarande lösenord: <p> Din närvaro online visas inte för andra användare. </p> <p> Din nävaro online visas för andra användare. </p> Skräddarsy fråga Databasfel standardkontextet Radera DevAdmin Utvecklares administration Direkta behörigheter Avaktivera Avaktiverat Domän E-post redigera kommentar Vissa element är ej redigerbara, därför att de är hanterade av %authority_name%. E-post Här är din nya inloggningsinformation: %account_id_label%: %account_id% %password_label%: %password% Var god besök följande länk för att ändra ditt lösenord nu: %reset_password_url% Tack för att du registrerat dig hos %system_name%. Så här loggar du in till %system_url%: %account_id_label%: %account_id% %password_label%: %password% Var god besök följande länk för att ändra ditt lösenord nu: %reset_password_url% E-postbekräftelse E-post ej begärd Ditt bortglömda lösenord till %system_name% Välkommen till %system_name% Aktiverat Skriv in ditt användarnamn för att inleda återställandet av ditt lösenord. Radera porträttet radera porträttet Fel Fel vid utskick av e-post Löper ut Filnamn Förnamn Glömt ditt lösenord? Frekvens Gå tillbaka ladda upp användarens porträtt ladda upp ditt porträtt Tilldela Tilldela behörighet Göm Hemsida Ifall du Informationen är uppdaterad Bjud in ISO-kod ISO-kodlista ISO-koderna är inte laddade ISO-kodern är inte laddade Gå med i gruppen Gå med i %group_name% Gå med i subsajten Gå med i denna grupp Gå med i denna subsajt Nyckelord Efternamn senare. Lämna gruppen Lämna subsajten Lämna denna grupp Lämna denna subsajt Gå tillbaka utan att lägga till några användare Logga in logga in Logga in till %system_name% logga in igen Inloggningssidan har tajmat ur. Var god logga in igen. Inloggning eller registrering inloggningssidan Logga ut Logga ut från %system_name% , så skulle du få reda på mer information om de andra medlemmarna i gruppen. Kan inte gå med i denna grupp. Fullständig lista över ISO-koder Fortsätt arbeta med %system_name% Redigera kommentaren till porträttet av %first_names% %last_name% %first_names% %last_name% (%email%) är registrerade som användare av %system_url% För globala administratörer Tilldela behörighet på %name% Det här är vad databasen rapporterade: Hur vill du att världen ska betrakta %first_names% %last_name%? Ifall du inte tror att personen redan har ett konto: Ifall du råkar veta eller tror att personen du vill bjuda in redan har ett konto hos detta system: Om du behöver denna funktionalitet, var god ladda acs-reference och ref-countries. Ärvda behörigheter Det vore en mycket dålig idé att välja denna funktion om du använder en delad dator i ett bibliotek eller i en skola. Alla efterkommande användare av den datorn kan då låtsas vara dig på denna tjänst. Ny registrering på %system_url% Röd text under parameterns textfält indikerar att denna parameters värde är åsidosatt av ett värde i OpenACS' parameterfil. Användandet av parameterfilen är avrått, men vissa sajter behöver den för att erbjuda instansspecifika parametervärden oberoende av tabellerna i apm_parameter. Notera att du kan ta bort din sparade e-postadress och lösenord genom att välja "logga ut" från ditt rum. %num_children% barn gömda %portrait_publish_date% laddade du upp <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Vår server kan få din webbläsare att minnas vissa saker, t.ex. dín e-postadress och ditt lösenord, så att du slipper upprepa dem. Detta är bekvämt för dig om du är den enda personen som använder din dator. Lösenordsbekräftelse: URL till personlig hemsida: Var god lokalisera ditt lands kod bland dem som är listade nedan, och använd sedan din webbläsares "Tillbaka"-knapp för att återvända till det föregående formuläret. Var god läs och följ instruktionerna i detta e-postmeddelande. Var god prova att <a href="index"> logga in </a> igen Porträtt av %first_names% %last_name% Privilegier högre upp i hierarkin inkluderar alla privilegier därunder, så om du t.ex. beviljar admin blir även read, write etc. automatiskt beviljat. Problem med veriferingen Registreringsinformation för denna tjänst har just blivit sänt till %email%. Registreringsinformation för denna tjänst har blivit sänt till %email%. Din registreringsförfrågan har skickats till administratören för %system_name%. Den avvaktar fortfarande godkännande. Sparar e-postadress och lösenord Visa alla andra på %system_name% hur snygg du är: Beklagar, men det verkar som om du är bannlyst från %system_name%. Är du säker på att du vill radera denna användares porträtt? Är du säker på att du vill radera ditt porträtt? Bilden på dig i systemet är ogiltig. Var god Ett problem inträffade i samband med verifieringen av ditt konto Det här är bilden som vi visar andra användare av %system_name% Den här användaren har inget porträtt ännu. Du kan Den här användaren är raderad och bannlyst från gruppen. För att konfirmera din registrering, var god gå till %confirmation_url% Ladda upp din favoritfil, en scannad JPEG eller GIF, från din arbetsstation (observera att du inte kan referera till en bild någon annanstans på Internet; denna bild måste finnas på din dators hårddisk). Uppladdad: %pretty_date% Uppladdad: %publish_date% Använd "Bläddra"-knappen för att lokalisera din fil, och klicka sedan på "Öppna". Vi kan inte hitta dig (användare %user_id%) i användartabellen. Troligtvis har ditt konto raderats av någon anledning. Vi hade problem med att bearbeta din data. Vi väntade inte din e-post. Det måste vara något misstag. Välkommen till %system_name% Vad andra ser när de klickar på ditt namn Du kan inte ha ett &lt; i ditt förnamn, eftersom det skulle likna HTML, och förvirra andra användare. Du kan inte ha ett &lt; i ditt efternamn, eftersom det skulle likna HTML, och förvirra andra användare. Du kommer inte att få någon e-post förrän efter %pretty_date%. Din e-postadress har bekräftats. Du kan nu logga in på %system_name%. Din e-postadress har bekräftats. Du avvaktar nu godkännande från administratören på %system_name%. Din e-postadress är bekräftad Din inloggning har tajmat ut. Var god skriv in ditt lösenord igen för att fortsätta arbeta. Din URL har inte ett korrekt format. En godkänd URL skall vara något liknande "%valid_url_example%". Gör till administratör Gör till medlem Gör dig själv osynlig Gör dig själv synlig Hantera dina notifieringar Tyvärr, du är inte tillåten att se medlemslistan. Medlemsstatus Medlemmar Namn: Nytt lösenord: Inga applikationer Inga ISO-koder Det här paketet har inga parametrar. ditt porträtt Inga %pretty_plural% Inga tjänster inga Ej inloggad Anteckningar: Notis: på %name% till: (valfri) Alternativ Eller lägg till en ny användare eller Lösenord: Din inloggningsinformation hos %system_name%: %account_id_label%: %account_id% Ditt lösenord till detta konto har nyligen ändrats. Du behöver inte göra något; detta meddelande är helt enkelt en säkerhetsupplysning. --------------- Du kan alltid ändra ditt lösenord genom att göra det följande: 1. Logga in till %system_name% 2. Klicka på länken "%pvt_home_name%" 3. Välja "%password_update_link_text%" Lösenord ändrat Behörigheter behörigheter Behörigheter för %name% Var god återvänd till %home_link%. Porträtt Fråga: Återaktivera Återställ lösenord Förnya inloggningen Registrera <p> Tack för att du har registrerat dig hos %system_name%. En administratör har notifierats om din anhållan om medlemskap. </p> <p> När du har godkänts får du ett e-postmeddelande och kan återvända för att börja använda %system_name%. </p> Avslå Kom ihåg min inloggning på den här datorn Ta bort Anhåll om medlemskap i denna grupp Anhåll om medlemskap i denna subsajt Anhåll om medlemskap återvänd till applikationen Återkalla markerade Roll Spara kommentaren Alias Sök efter en befintlig användare Säkerhetskontextens rot Välj ett objekt genom ID: Skicka e-post till denna användare Visa Site-wide administration Tyvärr, vi kan inte hjälpa dig med ditt bortglömda lösenord. Status Historien bakom fotot Historien bakom fotot Subgrupper subgrupper subgrupp subsajt Subsajter subsajter Tack så mycket. ISO-koderna laddades inte på denna server. Gruppen är sluten. Nya medlemmar kan endast ges tillträde via inbjudan. denna subsajt Denna användare har lämnat gruppen. För att logga in, besök Ämne typspecifik info UP upp till %context_name% Uppdatera Uppdatera lösenord ladda upp ladda upp ett porträtt ladda upp ett ersättningsporträtt Ladda upp ett porträtt Användarnamn Semesterinformation uppdaterad Din semesterinformation på %site_link% har uppdaterats. Välkommen, %user_name% När du lämnar en checkbox tom här blir det privilegiet tillbakadraget från den party du väljer ifall privilegiet har beviljats denna party förut. Användare som för närvarande är online Vem är online? Ja, jag är säker Du kan också bläddra från Du kan alltid öppna det igen genom att Du har inte admin-rättigheter på objekt %root% eller något av dess barn Du har inget porträtt ännu. Du kan Du har admin-rättigheter på följande objekt: Du har inga e-postnotifieringar registrerade för närvarande. Ditt konto Dina notiferingar från diskussionsforumet Ditt porträtt: Din notifieringar från %gc_system_name% Du är markerad som tillbaka från semestern på %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.fr_FR.ISO-8859-1.xml0000644000175000017500000005233410727201372025560 0ustar frankiefrankie ,ou Un membre de la communauté %system_name% depuis A propos de vous Votre compte a %system_name% a été fermé. Non, ramenez-moi à %pvt_home_name% Oui, veuillez fermer mon compte <p>Votre compte est actuellement fermé.</p> <p>Si vous le souhaitez, nous pouvons <a href="%restore_url%">réouvrir votre compte</a>.</p> <p> <font color="red"> <b> Votre compte est actuellement fermé. </b> </font> <a href="%login_url%">S'identifier</a> de nouveau pour voir ce que vous pouvez en faire. </p&;gt; Votre compte à %system_name% a été réouvert. Bon retour parmi nous. Compte Ouvert de Nouveau Action Ajouter une nouvelle application Panneau de Configuration Administrer %subsite_name% Options administratives pour cet utilisateur Type d'Alerte une autre image Réponse: Erreur de l'Application Applications Veuillez confirmer à Autorité Mot de passe erroné Interdiction Information Biographie Nous n'autorisons la récupération des mots de passe par une autorité locale. Vous ne pouvez pas voir la liste des memebres Changer de langue Changer mon mot de passe Changer votre mot de passe, adresse email, photo Voir boite aux lettres Objets subordonnés <p> Veuillez confirmer la cloture de votre compte sur %system_name%. </p> <p> Fermer votre compte signifie que nous ne vous enverrons plus de motifications par email, et que vous ne serez plus listés comme membre de %system_name%. Vos contributions a la communauté, par contre,seront préservées en tant que faisant partie de l'histoire de la communauté. </p> <p> Veuillez noter que vous pouvez à tout moment ouvrir de nouveau votre compte, simplement en vous identifiant à nouveau.</p> Fermer votre compte Groupe Fermé Commentaire Communautés communauté communauté Confirmer: Votre mot de passe a été changé avec succés. Continue Continuer vers %pvt_home_name% Nom du Pays Créer une nouvelle %pretty_name% Créer un nouveau sous-site Mot de passe actuel: <p> Vous êtes pour l'instant invisible aux yeux des autres utilisateurs. </p> <p> Vous êtes pour l'instant visible aux yeux des autres utilisateurs. </p> Question personnalisée Erreur de la Base de Données contexte par défaut Supprimer DevAdmin Administration des Développeurs Autorisation directe Désactiver Désactivé Domaine E-mail Modifier le commentaire Certains elements ne sont pas modifiables, parce qu'ils sont gérés par %authority_name%. Adresse email Voici vos nouveaux identifiants : %account_id_label%: %account_id% %password_label%: %password% Veuillez suivre le lien suivant pour modifier votre mot de passe immédiatement : %reset_password_url% Merci pour enregistrer à % system_name %. Est ici comment vous pouvez abonner à %system_url%: %account_id_label%: %account_id% %password_label%: %password% Visitez s'il vous plaît le lien suivant pour changer votre mot de passe maintenant : %reset_password_url % Confirmation email Courrier non solicité Voici votre mot de passe oublié sur %system_name% Bienvenue à %system_name% Activé Veuillez entrer votre nom d'utilisateur pour commencer la procédure de récupération de votre mot de passe. Effacer votre Photo effacer votre photo Erreur Erreur durant l'envoi de courrier Expire Nom de Fichier Prénoms mot de passe oublié ? Fréquence Retour aller télécharger la photo de l'utilisateur aller télécharger votre photo Autoriser Autorisation Cacher Page début Si vous êtiez à Informations Mises à Jour Inviter Code ISO List des Codes ISO Les codes ISO ne sont pas chargés Codes ISO non chargés Joindre une communauté Se joindre à %group_name% Joindre un sous-site Joindre cette communauté Joindre ce sous-site Mot-clé Nom Plus tard. Quitter la communauté Quitter le sous-site Quitter cette communauté Quitter cet sous-site Retour sans ajout d'utilisateurs Connecter s'identifier S'identifer sur %system_name% s'identifier de nouveau La page d'identification a expiré. S'il vous plaît abonner encore. S'identifier ou S'enregister Page d'identification Quitter Quitter %system_name% Impossible de se joindre à ce groupe. Liste Complète des Codes ISO Continuer à travailler avec % system_name % Editer le commentaire pour le portrait de % first_names % % last_name % %first_names% %last_name% (%email%) s'est inscrit comme utilisateur de %system_url%. Pour Administrateurs de Systèmes Autoriser %name% Voici ce que la base de données a rapporté : Comment aimerez vous que les otres vous verrait %first_names% %last_name%? Si vous ne pensez pas que la personne a un compte déjà : si vous savez ou croyez que la personne que vous aimeriez inviter déjà a un compte sur ce système : Si vous avez besoin de ce caractère fonctionnel, s'il vous plaît courant alternatif-addresse de chargement et les ref-pays. Autorisations héritées Ce serait une très mauvaise idée de choisir cette option si vous êtes plusieurs à utiliser le même ordinateur. Les prochains utilisateurs de cet ordinateur pourraient utiliser votre identité sur notre site. Nouvelle inscription à %system_url% Noter le texte dans rouge au dessous des champs d'entrée de paramètre, indique que la valeur de ce paramètre est annulée par une entrée dans le dossier de paramètre de OpenACS. L'usage du dossier de paramètre est découragé mais quelques sites ont besoin de lui fournir des valeurs exemple-spécifiques pour paramètres indépendant du apm_parameter tables. L'option "déconnecter" de votre espace de travail, permet d'effacer toute trace de votre adresse email et mot de passe. %num_children% fils cachés Vous avez envoyé <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> le %portrait_publish_date% Notre serveur peut envoyer certaines données à votre navigateur, comme vos adresse email et mot de passe. C'est un avantage car, si vous êtes la seule personne à utiliser cet ordinateur, vous n'aurez pas à les introduire à chaque fois. Confirmation de mot de passe: URL de votre page web personnelle: S'il vous plaît localiser le code de votre pays parmi ces énuméré au dessous, alors utilisez le bouton « arrière » sur votre navigateur pour se retourner à la forme précédente. SVP, lisez et suivez les instructions de ce courrier. SVP, essayez de vous <a href="index">connecter</a> à nouveau Le portrait de % first_names % % last_name % Les privilèges plus hauts dans l'hiérarchie impliquent tous les privilèges au dessous, par ex. quand vous accordez l'administration, lire, écrivez, etc. sont automatiquement impliqué. Problème avec l'identification L'information concernant ce service a été envoyée à %email%. L'information concernant ce service a été envoyée à %email%. Votre solicitude d'inscription a été envoyé à l'administrateur de %system_name% et est toujours en attente d'aprobation. Adresse email et mot de passe sauvegardés Montrez vous même a %system_name% Désolés mais vous avez été expulsé de %system_name%. Etes-vous sûr que vous voulez effacer le portrait de cet utilisateur ? Etes-vous sûr que vous voulez effacer votre portrait? L'image de vous dans le système est nulle. S'il vous plaît Impossible d'identifier votre compte Ceci est l'image que nous montrons aux autres utilisateurs à % system_name % Cet utilisateur n'a pas un portrait pourtant. Vous pouvez Cet utilisateur est effacé et est interdit de la communauté Pour confirmer votre inscription, allez à %confirmation_url% Télécharger votre dossier préféré, un JPEG ou GIF scrutés, de votre système d'ordinateur de bureau (notez que vous ne pouvez pas vous référer à une image ailleurs sur l'Internet ; cette image doit être sur l'unité dure de votre ordinateur). Téléchargé : % pretty_date % Téléchargé : %publish_date% Utiliser le bouton "Naviguer... » pour localiser votre dossier, alors cliqueter « Ouvrir ». Cet utilisateur a entré une biographie ou a téléchargé un portrait Nous ne pouvons pas vous trouver (l'utilisateur % user_id %) dans les utilisateurs ajourne. Probablement votre compte est été effacé pour quelque raison. Nous avions un problème traitant votre entrée. Nous n'attendions pas de courrier de votre part. Il doit s'agir d'une erreur. Bienvenu à %system_name% Tout ce que les autres peuvent savoir de vous Votre prénom ne peut pas contenir le signe &lt; car il pourrait être pris pour une étiquette HTML. Votre nom ne peut pas contenir le signe &lt; car il pourrait être pris pour une étiquette HTML. Votre adresse email a été vérifiée. Vous pouvez maintenant vous connecter à %system_name%. Votre adresse email a été vérifiée. Vous devez attendre maintenant l'aprobation de l'administrateur de %system_name%. Votre adresse email a été vérifiée. URL incorrecte. Exemple d'URL valide: \"%valid_url_example%\". Donner droits à l'administration Registrer Dissimuler le statut en ligne Motrer votre statut en ligne Gérer vos notifications Désolé, mais vous n'êtes pas permis de regarder la liste de membres. Etat de membre Membres Nom: Nouveau mot de passe: Aucune applications Aucune ISO Code Ce packet n'a pas des paramètres. votre photo Aucun %pretty_plural% Aucuns services aucun Notes: Notification: sur %name% à: (facultativ) Options Ou ajouter un nouvel utilisateur ou le Mot de passe: Votre information de login sur % system_name % : %account_id_label % : % account_id % Votre mot de passe pour ce compte a été récemment changé. Vous n'avez pas besoin de faire rien, ce message est simplement une notification pour protéger la sécurité de votre compte. --------------. - Vous pouvez toujours changer votre mot de passe en faisant le suivant: 1. Abonner à % system_name % 2. Cliquer sur le "%pvt_home_name % » relie 3. Choisir "%password_update_link_text % » Mot de passe changé Privilèges permissions Privilèges pour %name% S'il vous plaît se retourner à % home_link %. Portrait Profil Question: Récupérer mot de passe Rafraîchir le login S'inscrire <p> Merci pour enregistrer pour % system_name %. Un administrateur a été notifié de votre demande. </p> <p> Une fois vous êtes approuvé, vous obtiendrez un message d'e-mail et vous pouvez retourner et commencer l'utilisation % system_name %. </p> Rejet Mémoriser Enlever Enlever tout Demander l'adhésion de cette communauté Demander l'adhésion de ce subsite Demander l'adhésion se retourner à l'application Effacer sélection Rôle Sauvegarder le commentaire Pseudo Chercher Un Utilisateur Existant Racine de contexte de sécurité Choisir un Objet par Id : Envoyer l'e-mail à cet utilisateur Montrer Administration site-large Désolé, nous ne pouvons pas vous aider avec votre mot de passe oublié. Statut Le commentaire à la Photo Sous-communautés sous-communautés sous-communauté subsite Subsite subsites Merci. Les codes d'ISO n'ont pas été chargés sur ce serveur. Ce groupe est fermé. Les nouveaux membres peuvent obtenir seulement l'accès par invitation. ce subsite Cet utilisateur est parti de la communauté. S'il vous plaît vérifier votre messagerie. Dans les prochains minutes, vous devez trouver un message de % system_owner % avec les instructions sur Subjet information de caractère spécifique EN HAUT vers %context_name% Changer Changer le mot de passe télécharger envoyer une photo télécharger un autre portrait Télécharger le Portrait Nom d'utilisateur Carte de Site de l'utilisateur L'Information de vacances Mis à jour Votre information de vacances à % site_link % a été mis à jour. Bienvenue, %user_name% Les utilisateurs actuellement en ligne Qui est en ligne Oui, je suis sûr Votre Comte Votre information des forums de discussions Votre photo Votre information de %gc_system_name% openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.gl_ES.ISO-8859-1.xml0000644000175000017500000006625510727201372025562 0ustar frankiefrankie , ou Actualizar información básica Membro de %system_name% desde Sobre ti A súa conta en %system_name% foi cancelada Non, voltar a %pvt_home_name% Si, cancelar a miña conta por favor <p>A túa conta encóntrase actualmente fechada.</p> <p>Se desexas, podemos <a href="%restore_url%">reabrir a túa conta</a>.</p> Conta pechada <p><font color="red"><b>A súa conta está actualmente cancelada.</b></font><a href="%login_url%">Conéctese</a> de novo para ver que pode facer respecto diso.</p> Esta conta non está dispoñible neste momento. A súa conta en %system_name% foi reactivada. Benvido de novo Conta reactivada Acción Engadir engadir carpeta Engadir unha nova aplicación Engadir este usuario Engadir usuario Engadir usuarios Panel de Control Admin Administrar %subsite_name% Opcións de administración para este usuario Tipo de aviso outra imaxe Resposta: Erro da aplicación Aplicacións Aprobar en Erro interno durante a autenticación Autoridade Seña incorrecta Prohibir Información básica Biografías Biografía Tipo Mime de Biografía Tipos Mime de Biografía Non está soportado recuperar a seña desde autoridade local. Non pode ver a lista de membros Seleccionar idioma Cambiar o nivel de privacidade do meu email Mudar a minha senha Cambiar, contrasinal, correo, foto Verificar a tua caixa de correo Fillos Elixa un cuestionario personalizado de rexistro: Elixa o cuestionario que será mostrado aos novos usuarios.<br> Pode ser usado para realizar accións automáticas (como engadir usuarios a grupos específicos, notificar a usuarios específicos sobre novos rexistros, etc.) <p>Por favor, confirme que realmente desexa cancelar a súa conta en %system_name%.</p> <p>Cancelar unha conta significa que non seguirá recibindo notificacións, nin formará parte dos membros de %system_name%. No entanto, as súas contribucións á comunidade conservaranse como parte do histórico da comudidade.</p> <p>Teña en conta que pode reabrir a súa conta en calquera momento, para iso simplemente volva a conectarse.</p> Cancelar conta Grupo pechado Comentario Comunidades comunidades comunidad Confirmar Vostede selecionou unha nova contrasinal con éxito Continuar Continuar a %pvt_home_name% País Crear Crear un cuestionario de rexistro novo Crear novo %pretty_name% Crear un novo subsitio Seña actual <p>O seu nome NON aparece na lista de usuarios conectados.</p> <p>O seu nome aparece na lista de usuarios conectados.</p> Personalizar pregunta Erro de base de datos contexto por defecto Borrar borrar Administración de desarrolladores Administración de desarrolladores Permisións directas Desactivar Desactivado Dominio Correo electrónico Editar Editar o Cuestionario Seleccionado editar comentario Opcións Algúns elementos non poden ser editados xa que están sendo administrados por %authority_name% Correo Permitir contactarme mediante unha forma Permitir contacto mediante unha forma Mostrar o meu correo electrónico como unha imaxe Mostrar o correo electrónico como unha imaxe Mostrar o meu correo electrónico como texto Mostrar o correo electrónico como texto Datos da súa conta: %account_id_label%: %account_id% %password_label%: %password% Para cambiar a súa contrasinal, visite %reset_password_url% Gracias por rexistrarse en %system_name%. Para conectarse, visite %system_url%: %account_id_label%: %account_id% %password_label%: %password% Para cambiar a súa contrasinal, visite %reset_password_url% Confirmación de correo Non mostrar o meu correo electrónico Non mostrar o correo electrónico Non dispoñible Correo non solicitado Email requerido Recordatorio da súa contrasinal en %system_name% Benvido a %system_name% Activado Introduza o seu nome de usuario para poder recuperar a súa contrasinal Borrar foto borrar foto Erro Erro enviando correo Houbo un erro ao enviar o correo para a verificación por correo Houbo un erro ao intentar rexistrar unha conta para vostede. Houbo un erro ao intentar actualizar a información da conta Caduca Arquivo Primeiros nomes Esqueceu a súa contrasinal? Frecuencia Regresar Subir a foto do usuario subir a súa foto Conceder Conceder permisión Xa temos un grupo con este correo electrónico. Xa temos un usuario con este nome de usuario Xa temos un usuario con este nome de usuario <p><h3>Información de axuda</h3> Oculto Páxina web Se fose a Información actualizada Instalar Idiomas Invitar Código ISO Lista de Códigos ISO Códigos ISO non cargados Os Códigos ISO non foron cargados Unirse á comunidade Adire a %group_name% Unirse ao subsitio Unirse a esta comunidade Unirse a este subsitio Palabra clave Último nome despois Sair da comunidade Sair do subsitio Sair desta comunidade Sair deste subsitio Regresar sin engadir ningún usuario Log in entrar Entrar a %system_name% Entrando de novo A páxina de rexistro caducou. Por favor, rexístrase de novo. Entrar ou rexistrarse páxina de rexistro Sair Sair de %system_name% , sería capaz de adquirir máis información sobre este membro da comunidad. Engadir os usuarios seleccionados a usuarios que teñen permiso no seu obxecto Non se pode aderir a este grupo. Lista completa dos códigos ISO Continue traballando con %system_name% borrar</a> </if> <if @nodes.parameters_url@ ne ""> <a href="@nodes.parameters_url@"><#_ parameters Non herdar de %parent_object_name% Editar comentario da foto de %first_names% %last_name% %first_names% %last_name% (%email%) rexistrado como un usuario do %system_url% Para los Administradores do sitio Conceder permisión en %name% Aquí está o que a base de datos devolveu ¿Cómo queres que o mundo o vexa %first_names% %last_name%? Si cree que a persoa non ten aínda unha conta: Si sabe ou cree que a persoa que quere invitar xa ten unha conta no sistema: Se necesita esta funcionalidade, por favor carge acs-reference e ref-countries. Herdar de %parent_object_name% Herdar permisos do %parent_object_name% Permisións herdadas Sería unha má idea escoller esta opción se estás a utilizar un computador partillado nunha biblioteca ou escola. O próximo usuario desta máquina será capaz de utilizar o noso servizo facendose pasar por ti. Novo rexistro en %system_url% A nota en vermello debaixo dos campos de entrada de cada parámetro indica que o valor do mesmo está sobreescrito por unha entrada no arquivo de parámetros de OpenACS. Aconséllase o uso de devandito arquivo, pero algúns sitios necesítano para asinar valores específicos aos parámetros, independentes das táboas apm_parameter. Repara en que podes eliminar o teu enderezo de correo e seña gardados ao escoller a opción "log out" no teu espazo de traballo. %num_children% Fillos ocultados En %portrait_publish_date%, carregaches <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> O noso servidor podes dicir ao teu navegador para recordar certas cousas, tais como o teu enderezo de correo e seña. Isto é conveniente para ti porque, se fores a única persoa que utiliza o teu computador, non terás de estar sempre a dicirnos o teu enderezo e seña. Confirmación da seña URL da páxina persoal: Por favor localice o código do seu país na lista, despois utilice "regresar" do seu navegador para regresar ao formulario anterior. Por favor, le e sigue as instruccións presentes nesta mensaxe Por favor, tenta facer o <a href="index">log in</a> novamente Foto de %first_names% %last_name% Os privilexios da parte de arriba na xerarquía implican todos os privilexios de abaixo, exemplo: cando outorga privilexios de administración, están implicados automáticamente os privilexios de escritura, lectura, etc. Problema coa autenticación Información de rexistro para este servizo acaba de ser enviada para %email%. Información de rexistro para este servizo acaba de ser enviada para %email%. O teu pedido de rexistro foi enviado para o administrador de %system_name%. Estás ainda á espera de aprovación. Gardando enderezo de correo e seña Mostrar a toda a xente en %system_name% o ben parecida/o que és: Desculpa mais parece que fuches banido de %system_name%. Deixar de herdar permisos do %parent_object_name% ¿Seguro que quere borrar a foto de este usuario? ¿Está seguro de borrar a súa foto? Por favor, a súa foto no sistema é errónea. Non hai usuarios que non teñan acceso a este obxeto Houbo un problema coa autenticación da túa conta Esta é a foto que verán os demais usuarios en %system_name% Este usuario non ten unha foto aínda. Pode engadi-la se o desexa. Este usuario foi borrado e o seu acceso á comunidade prohibido. Para confirmar o rexistro, por favor vai a %confirmation_url% Suba a súa foto favorita, un arquivo escaneado en formato JPEG ou GIF do seu ordenador (Non pode subir unha imaxe desde ningún sitio de internet; ten que estar no seu disco duro). Subido: %pretty_date% Subido: %publish_date% Utilice o botón "Examinar..." para localiza-lo seu arquivo, despois pulse botón "abrir" Este usuario subiu unha biografía ou unha foto Non se poido atopar (usuario %user_id%) na tabla de usuarios. Probablemente a súa conta foi borrada Ocurriu un problema procesando a súa solicitude Non estábamos á espera da tua mensaxe, Debe haber algún engano. Ben vindo a %system_name% O que verán os demais ao pulsar sobre o seu nome Non podes ter un &lt; no teu primeiro nome porque irá parecerse con unha etiqueta HTML e confundir outros usuarios. Non podes ter un &lt; no teu último nome porque irá parecerse con unha etiqueta HTML e confundir outros usuarios. Debe proveer object_id_one ou object_id_two Non poderá recibir ningún correo ata despois de %pretty_date%. O teu correo electrónico foi confirmado. Podes agora entrar en %system_name%. O teu correo electrónico foi confirmado. Estás agora esperando a aprobación por parte do administrador de %system_name%. O teu correo electrónico está confirmado A súa versión caducou. Por favor introduza o seu contrasinal para seguir traballando O teu URL non ten o formato correcto. Un URL válido ten de ser algo como "%valid_url_example%". Enviar unha mensaxe a Convertir en administrador Crear un membro Voltarse invisible Voltarse visible Manage users E-mail privacy Administrar notificacións Non está autorizado para ver a lista de membros Usuario Estado do membro Membros Falta argumentos montar A miña conta Nome: nova aplicación Nova seña Non hai aplicacións Non hai tareas dispoñibles Non hai códigos ISO Este paquete non ten parámetros o teu retrato Non ten %pretty_plural% Non hai servizos Non se atopou ningún usuario con este nome de usuario ningún Non rexistrado Esta no é unha dirección de correo válida Notas: Aviso: en %name% a: Conectado (optional) Opcións Ou engadir un novo/a usuario/a ou dende Parámetros parámetros Seña A túa información do login en %system_name%: %account_id_label%: %account_id% A túa seña para esta conta foi alterada recentemente. Non precisas de facer nada, esta mensaxe é unha simple notificación para protexer a seguranza da túa conta. ---------------Podes sempre alterar a túa seña facendo o seguinte: 1. Facer o login para %system_name% 2. Clicar na ligazón "%pvt_home_name%" 3. Escoller "%password_update_link_text%" Seña alterada o seu contrasinal debe ser cambiado regularmente. Por favor, cambie o seu contrasinal agora. Os contrasinais non coinciden Este permiso non se pode borrar Permisións permisos Permisións para %name% Por favor volva a %home_link%. Foto Privacidade Houbo un problema autenticando a conta. Probablemente a base de datos contén usuarios sen member_state Perfil Pregunta: Reactivar Lectura Recuperar seña Actualizar entrada Cuestionario de rexistro de usuarios personalizado Rexistrar <p>Gracias por rexistrarse en %system_name%. Notificouse a un administrador sobre a súa solicitude.</p><p>Unha vez esté aprobado, enviaraselle un correo para que poda entrar en %system_name%.</p> Rexeitar Recordar o meu contrasinal neste equipo Eliminar Eliminar todos Renombrar Solicitar pertencer a esta comunidade Solicitar pertencer a este subsitio Solicitar a entrada Voltar á aplicación Revocación verificada Rol Guardar comentario Nome de ecran Este alcume xa está collido Atopar un usuario existente Contexto de seguridade de root Seleccionar un obsexto por Id Enviar email a este usuario Envíame unha copia Poñer a tarea para o rexistro Mostrar Administración do Sitio Principal Administración xeral Desculpa, non podemos axudar coa tua seña esquecida. Estado Historia da foto Historia da foto Subcomunidades subcomunidades subcomunidade subsitio Subsitios subsitios Autentificouse correctamente, pero non ten unha conta aínda en %system_name% Obrigado. Os códigos ISO non forn cargados neste servidor Este grupo é pechao. Só pode ser membro por invitación. Este subsitio Este usuario deixou a comunidade Para entrar, visita a Tópico Introduza información específica Correo desconocido desmontar ARRIBA até %context_name% Actualizar Actualizar seña Subir carregar un retrato Subir nova foto Subir unha foto Fotografía do usuario Fotografías de usuario Perfil de usuario Perfiles de usuario Nome de usuario Non se atopou ningún usuario con nome de usuario '%username%' na autoridade %this_authority% Nome de usuario requerido Mapa do sitio do usuario Información de Vacaciones Actualizada A información das súas vacacións en %site_link% foi actualizada. Benvido/a, %user_name% Se deixa de selecionar un privilexio, eliminará dito privilexio ó grupo que excolleu se este grupo tiña anteriormente o privilexio Usuarios conectados neste momento Quién está conectado Escritura Si, estou seguro Pertence aos seguintes grupos Tamén pode navegar dende o Vostede sempre pode reabri-lo con Non ten dereitos de administración no obxecto %root% nin sobre os seus fillos Vostede non ten unha foto. Pode engadi-la se o desexa. Non ten dereitos de administración nos seguintes obxetos: Non ten avisos de correo activados A súa conta Os seus avisos nos foros O teu retrato A súa %gc_system_name% alerta Vostede volve de vacacións en %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.sh_HR.utf-8.xml0000644000175000017500000000613210727201372025320 0ustar frankiefrankie O tebi Odgovor: kod Pogresna lozinka Osnovna informacija Promeni moju lozinku Promijeni lozinku, adresu e-poÅ¡te, portret Provjeri dolazecu postu Podstavke Potvrdi: Trenutna lozinka: Prilagodi pitanje Izaberi prava E-poÅ¡ta Potvrda email adrese Email adresa nije neophodna Greska pri slanju poste Zaboravili ste lozinku? Dozvoli Garantuj prava Postani clan %group_name% Prikljuci me Clanstvo u ovoj grupi Vam nije dozvoljeno %first_names% %last_name% (%email%) registrovan kao korisnik %system_url% Garantuj prava za %name% Nasledena prava Izbor ove opcije je jako losa ideja ako koristite racunar u biblioteci ili skoli. Bilo koji drugi korisnik ove masine posle vas bi mogao da se lazno predstavi kao vi i koristi nase usluge. %num_children% podstavki sakriveno Potvrda lozinke: Nije dozvoljeno imati &lt; u vasem imenu jer bi to izgledalo kao HTML tag i zbunilo druge korisnike. Nije dozvoljeno imati &lt; u vasem prezimenu jer bi to izgledalo kao HTML tag i zbunilo druge korisnike. Vas email je potvrden Vas URL nije korektno napisan. Korektan URL je na primer slican ovom \"%valid_url_example%\"." Ime: Nova lozinka: prazno Lozinka Dopustenja Dopustenja za %name% Pitanje: Registruj Zapamti me ovdje Ukini oznacena prava Pokazi Hvala vam! Obnovi Obnovi lozinku Dodajte vas portret Vas portret openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.en_GB.ISO-8859-1.xml0000644000175000017500000000060510727201372025526 0ustar frankiefrankie Upload your favourite file, a scanned JPEG or GIF, from your desktop computer system (note that you can't refer to an image elsewhere on the Internet; this image must be on your computer's hard drive). openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.de_DE.ISO-8859-1.xml0000644000175000017500000007121310720127056025516 0ustar frankiefrankie oder Die Allgemeinen Informationen aktualisieren Registriert bei %system_name% seit Benutzerinformation Ihr Benutzerkonto bei %system_name% wurde deaktiviert. Nein, zurück zu %pvt_home_name% Ja, Benutzerkonto deaktivieren <p>Ihr Benutzerkonto ist derzeit deaktiviert.</p> <p>Sie können es <a href="%restore_url%">wieder aktivieren lassen</a>.</p> Account geschlossen <p> <font color="red"> <b> Ihr Benutzerkonto ist derzeit geschlossen. </b> </font> <a href="%login_url%">Melden Sie sich wieder an</a>, um weitere Informationen zu erhalten. </p> Dieses Benutzerkonto ist derzeit nicht verfügbar. Ihr Benutzerkonto wurde wieder aktiviert. Willkommen bei %system_name%. Benutzerkonto wieder aktiviert Aktion Hinzufügen Ordner hinzufügen Neue Anwendung hinzufügen Diesen User hinzufügen User hinzufügen User hinzufügen Verwalten Admin %subsite_name% verwalten Verwaltungsoptionen für diesen Benutzer Art der Benachrichtigung ein neues Bild Antwort: Anwendungsfehler Anwendungen Freischalten unter Interner Fehler bei Authentifizierung Authentifizierungsstelle Falsches Passwort Deaktivieren Allgemeine Informationen: Biographien Lebenslauf Mime Typ für die Biographie Mime Typ für die Biographie Passwort zurücksetzen durch lokale Authentifizierungsstelle nicht unterstützt Liste der Teilnehmer verborgen Sprache einstellen Änderung meines e-Mail Privacy Levels Passwort ändern Passwort, E-Mail-Adresse oder Bild ändern Überpüfen Sie Ihr Postfach Untergeordnete Objekte Wählen Sie einen der Registrationsfragebögen: Wählen sie die Umfrage aus, welche neuen Benutzern angezeigt wird.<br> Dies kann verwendet werden um automatisierte Aktionen (wie zb. Benutzer in bestimmte Gruppen hinzu zu fügen, bestimmte Personen über neue Anmeldungen zu informieren) auszuführen <p> Bitte bestätigen Sie, dass Sie Ihr Benutzerkonto bei %system_name% deaktivieren wollen. </p> <p> Wenn Ihr Benutzerkonto deaktiviert ist, erhalten Sie keine Benachrichtigungen mehr von dotLRN, und Ihr Name erscheint nicht mehr auf Teilnehmerlisten von Kursen oder Communities. Ihre inhaltlichen Beiträge werden jedoch nicht gelöscht, da sie Teil der gemeinschaftlichen Aktivitäten in dotLRN sind. </p> <p> Hinweis: Sie können Ihr Benutzerkonto jederzeit wieder aktivieren, indem Sie sich einfach wieder anmelden. </p> Benutzerkonto deaktivieren Geschlossene Gruppe Kommentar Communities Communities Community Bestätigen: Die Änderung Ihres Passworts war erfolgreich. Fortsetzen Weiter nach %pvt_home_name% Land Erstellen Erstellen Sie einen neuen Registrationsfragebogen Neue %pretty_name% erstellen Neue Subsite erstellen Aktuelles Passwort: <p> Ihr Onlinestatus ist für andere Benutzer verborgen. </p> <p> Ihr Onlinestatus ist für andere Benutzer sichtbar. </p> Frage ändern Datenbankfehler Standardkontext Löschen löschen Administration (Entwickler) Administration auf Entwicklerebene Explizite Berechtigungen Deaktivieren Deaktiviert Domäne E-Mail-Adresse Editieren Verändern des markierten Fragebogens Kommentar bearbeiten Optionen editieren Einige Elemente können nicht bearbeitet werden, da sie von %authority_name% verwaltet werden. E-Mail-Adresse Zulassen, mich über ein Formular anzusprechen Den Kontakt mittels eines Formulars erlauben Meine e-Mail als Bild anzeigen e-Mail als Bild anzeigen Meine e-Mail als Text anzeigen e-Mail als Text anzeigen Hier sind Ihre neuen Anmeldedaten: %account_id_label%: %account_id% %password_label%: %password%. Bitte ändern Sie Ihr Passwort unter folgendem Link: %reset_password_url% Vielen Dank für Ihre Registrierung bei %system_name%. Mit folgenden Daten können Sie sich bei %system_url% anmelden: %account_id_label%: %account_id% %password_label%: %password% Bitte ändern Sie Ihr Passwort unter folgendem Link: %reset_password_url% E-Mail-Adresse bestätigen: Meine e-Mail nicht anzeigen e-Mail nicht anzeigen Nicht verfügbar E-Mail nicht angefordert Email-Adresse muss angegeben werden Ihr vergessenes Passwort für %system_name% Willkommen bei %system_name%. Aktiviert Um Ihr Passwort zurücksetzen zu lassen, geben Sie bitte zunächst Ihre Benutzeridentifikation ein. Bild löschen Bild löschen Fehler Fehler beim Senden der E-Mail Die Email-Nachricht zur Überprüfung der Adresse konte nicht gesendet werden Es trat ein Fehler auf während wir versucht haben, einen Account für Sie anzulegen. Während des Updates des Accounts trat ein Fehler auf Ablaufdatum Dateiname Vorname(n) Passwort vergessen? Häufigkeit Zurück Bild des Benutzers hochladen ein Bild hochladen. Erteilen Berechtigungen erteilen Eine Gruppe mit dieser Email-Adresse existiert bereits. Ein Benutzer mit dieser Email-Adresse existiert bereits. Eine Gruppe mit diesem Benutzernamen existiert bereits. <p><h3>Hilfe Info</h3> Verbergen Homepage Wenn Sie sich anmelden Die Information wurde aktualisiert. Sprachen installieren Einladen ISO-Code Liste der ISO-Codes ISO-Codes nicht geladen ISO-Codes nicht geladen Community hinzufügen %group_name% hinzufügen Subsite beitreten Diese Community hinzufügen Dieser Subsite beitreten Schlüsselwort Nachname &nbsp; Community entfernen Die Subsite verlassen Diese Community entfernen Diese Subsite verlassen Keine Benutzer hinzufügen und zurück Anmelden Anmelden Bei %system_name% anmelden sich erneut anmelden. Die Anmeldeseite ist abgelaufen. Bitte melden Sie sich erneut an. Anmelden oder registrieren Anmeldeseite Abmelden Von %system_name% abmelden , werden Ihnen mehr Informationen über andere Teilnehmer Ihrer Gruppe angezeigt. Markierte User zu den Usern hinzufügen, die Zugriffsrechte auf das Objekt haben. Diese Gruppe kann nicht hinzugefügt werden. Vollständige Liste der ISO-Codes Weiterarbeiten mit %system_name% lösche</a> </if> <if @nodes.parameters_url@ ne ""> <a href="@nodes.parameters_url@"><#_ parameters Nicht vererben von %parent_object_name% Kommentar zum Bild von %first_names% %last_name% bearbeiten %first_names% %last_name% (%email%) ist als Benutzer von %system_url% registriert. Für Systemadministratoren Berechtigungen erteilen für %name% Folgende Daten wurden in der Datenbank gefunden: Hier können Sie ein Bild von sich hochladen, das für andere Benutzer von dotLRN sichtbar ist. Wenn die Person noch kein Benutzerkonto hat: Wenn die Person, die Sie einladen wollen, bereits ein Benutzerkonto auf diesem System hat: Wenn Sie diese Funktionalität nutzen wollen, laden Sie bitte acs-reference und ref-countries. Übernehmen von %parent_object_name% Zugriffsberechtigungen von %parent_object_name% übernehmen Vererbte Berechtigungen Diese Option sollte nicht gewählt werden, wenn der Computer von mehreren Personen genutzt wird, etwa in einer Bibliothek oder einem universitären Rechenzentrum. Nachfolgende Benutzer können sonst unter Ihrer Identität auf den Dienst zugreifen. Neue Registrierung bei %system_url% Note text in red below the parameter entry fields indicates the value of this parameter is being overridden by an entry in the OpenACS parameter file. The use of the parameter file is discouraged but some sites need it to provide instance-specific values for parameters independent of the apm_parameter tables. Hinweis: Sie können Ihre Benutzeridentifikation und Ihr Passwort aus dem Browser löschen, indem Sie auf der dotLRN-Startseite die Option 'Abmelden' wählen. %num_children% untergeordnete Objekte ausgeblendet Am %portrait_publish_date% haben Sie <a href="%subsite_url%user/portrait/">%portrait_title%</a> hochgeladen Bestimmte Daten wie Benutzeridentifikation oder Passwort können vom Browser gespeichert werden. Dadurch brauchen diese Daten bei Computern, die von nur einer Person genutzt werden, nicht bei jeder Sitzung neu eingegeben zu werden. Passwort bestätigen Adresse der persönlichen Homepage: Bitte wählen Sie aus der folgenden Liste Ihren Ländercode aus. Gehen Sie dann mit Hilfe Ihres Browsers zum Formular zurück. Bitte führen Sie die in der E-Mail genannten Schritte aus. Bitte versuchen Sie noch einmal, sich <a href="index">anzumelden</a>. Bild von %first_names% %last_name% Höhere Rechte schließen niedrigere Rechte mit ein. Wenn Sie etwa Verwaltungsrechte erteilen, werden automatisch auch Lese- und Schreibrechte gewährt. Es ist ein Authentifizierungsproblem aufgetreten. Die Registrierungsinformationen für diesen Dienst wurden an %email% gesendet. Die Registrierungsinformationen für diesen Dienst wurden an %email% gesendet. Ihr Registrierungsantrag wurde an den Administrator von %system_name% übermittelt. Sie wurden noch nicht freigeschaltet. E-Mail-Adresse und Passwort werden gespeichert. Zeigen Sie, wer Sie sind bei %system_name% Sie haben keinen Zugang zu %system_name%. Wahrscheinlich wurde Ihr Benutzerkonto deaktiviert. Aufhören, die Berechtigungen von %parent_object_name% zu vererben Wollen Sie das Bild dieses Benutzers wirklich löschen? Wollen Sie Ihr Bild wirklich löschen? Ihr Bild kann nicht in dotLRN angezeigt werden. Bitte Es existieren keine User, die nicht schon einen Zugriff auf dieses Objekt haben Es ist ein Problem bei der Authentifizierung Ihres Benutzerkontos aufgetreten. Folgendes Bild wird anderen Benutzern von %system_name% angezeigt Dieser Benutzer hat noch kein Bild hochgeladen. Sie können Das Benutzerkonto dieses Benutzers wurde gelöscht. Zur Bestätigung Ihrer Registrierung klicken Sie bitte auf %confirmation_url%. Die Datei muss im JPEG oder GIF-Format vorliegen und sich auf Ihrem PC befinden. Eine Verlinkung mit einem Bild im Internet ist nicht möglich. Hochgeladen am: %pretty_date% Hochgeladen am: Klicken Sie auf 'Durchsuchen...', wählen Sie die gewünschte Datei aus und klicken Sie auf 'Öffnen'. Dieser Benutzer hat seinen Lebenslauf oder sein Bild bereitgestellt. Ihre Benutzeridentifikation (%user_id%) konnte nicht in der Benutzerdatenbank gefunden werden. Wahrscheinlich wurde Ihr Benutzerkonto gelöscht. Bei der Verarbeitung Ihrer Eingabe ist ein Fehler aufgetreten. Es wurde keine E-Mail von Ihnen erwartet. Es ist ein Fehler aufgetreten. Willkommen bei %system_name%. Für andere Benutzer sichtbare persönliche Informationen Der Vorname darf keine spitzen Klammern enthalten, da diese gewöhnlich für HTML-Steuerzeichen verwendet werden und andere Benutzer verwirren könnten. Der Nachname darf keine spitzen Klammern enthalten, da diese gewöhnlich für HTML-Steuerzeichen verwendet werden und andere Benutzer verwirren könnten. Sie müssen zumindest eine object_id_on oder eine object_id_two angeben Sie erhalten erst wieder ab %pretty_date% E-Mails. Ihre E-Mail-Adresse wurde bestätigt. Sie können sich nun bei %system_name% anmelden. Ihre E-Mail-Adresse wurde bestätigt. Sie warten nun auf Freischaltung durch den Administrator von %system_name%. Ihre E-Mail-Adresse wurde bestätigt. Ihre Anmeldung ist abgelaufen. Bitte geben Sie erneut Ihr Passwort ein. Die von Ihnen eingegebene URL hat nicht die richtige Form. Eine gültige URL könnte etwa lauten: "%valid_url_example%" Eine Nachricht senden an: Administrationsrechte erteilen Anmelden Onlinestatus verbergen Onlinestatus anzeigen Verwalten des e-Mail Datenschutzes des Users Benachrichtigungsoptionen verwalten Sie sind nicht berechtigt, die Liste der Teilnehmer zu sehen. Teilnehmer Teilnehmerstatus Teilnehmer Fehlendes Argument mount Mein Account Name: neue Applikation Neues Passwort: Keine Anwendungen vorhanden Kein Assessment verfügbar Keine ISO-Codes geladen This package does not have any parameters. Ihr Bild Keine %pretty_plural% vorhanden Keine Dienste verfügbar Benutzername konnte nicht gefunden werden Keine Nicht angemeldet Keine gültige Email-Adresse Hinweise: Hinweis: für %name% an: Online (optional) Optionen oder einen neuen Benutzer hinzufügen oder das Parameter parameter Passwort Das Passwort Ihres Benutzerkontos (%account_id_label%: %account_id%) bei %system_name% wurde kürzlich geändert. Es sind keine weiteren Schritte nötig, diese Mitteilung dient lediglich Ihrer Sicherheit. --------------- Sie können Ihr Passwort jederzeit mit folgenden Schritten ändern: 1. Melden Sie sich bei %system_name% an. 2. Klicken Sie auf den Link '%pvt_home_name%'. 3. Wählen Sie die Option '%password_update_link_text%'. Passwort geändert Ihr Passwort muss rgelmässig geändert werden. Bitte Ändern Sie jetzt ihr Passwort. Passwörter stimmen nicht Überein Die Erlabnis kann nicht wieder zurückgenommen werden. Berechtigungen Berechtigungen Zugriffsberechtigungen für %name% Bitte gehen Sie zurück zu %home_link%. Bild Privatsphäre Es gab einen Fehler beim authentifizieren des Accounts. Sehr wahrscheinlich enthält die Datenbank User mit keinem member_state. Profil Frage: Aktivieren Lesen Passwort zurücksetzen Anmeldung aktualisieren Angepasster Fragebogen für die Benutzerregistrierung Registrieren <p>Vielen Dank für Ihre Registrierung bei %system_name%. Der Antrag wurde an einen Administrator übermittelt.</p> <p>Sobald Sie freigeschaltet sind, erhalten Sie eine E-Mail mit den erforderlichen Anmeldedaten und können %system_name% nutzen.</p> Ablehnen Anmeldedaten auf diesem Computer speichern Entfernen Alle Entfernen Umbenennen Zugang zu dieser Gruppe beantragen Mitgliedschaft für diese Subsite beantragen Zugang beantragen Zurück zur Anwendung Ausgewählte Berechtigungen aufheben Rolle Kommentar speichern Aliasname Dieser Aliasname ist bereits vergeben. Wählen Sie bitte einen anderen Namen. Nach vorhandenem Benutzer suchen Wurzelverzeichnis des Sicherheitskontexts Wählen Sie mit Hilfe der ID ein Objekt aus: E-Mail an diesen Benutzer senden Schicke eine Kopie an mich: #assessment.assessment# für die Registrierung auswählen Anzeigen System Administration Systemadministration Das Passwort kann nicht zurückgesetzt werden. Status Kommentar zum Bild Kommentar zum Bild Subcommunities Subcommunities Subcommunity Subsite Subsites Subsites Sie haben sich erfolgreich angemeldet, aber Sie haben noch kein Benutzerkonto bei %system_name%. Vielen Dank. Die ISO-Codes sind auf diesem Server nicht geladen. Dies ist eine geschlossene Gruppe. Neue Teilnehmer können nur durch Einladung Zugang erhalten. diese Subsite Dieser Benutzer ist nicht mehr bei dotLRN registriert. Um sich anzumelden, gehen Sie auf die Thema Typspezifische Informationen: Email-Adresse unbekannt abhängen Eine Ebene nach oben Eine Ebene höher zu "%context_name%" Aktualisieren Passwort aktualisieren Hochladen Ein Bild hochladen Ein anderes Bild hochladen Bild hochladen Portrait des Users Portraits der User Profil des Users Prodile der User Benutzeridentifikation Benutzer mit Namen '%username%' konnte in %this_authority% nicht gefunden werden Benutzername muss angegeben werden Site Map des Users Die Informationen zu Ihrer Abwesenheit wurden aktualisiert. Die Informationen zu Ihrer Abwesenheit unter %site_link% wurden aktualisiert. Willkommen, %user_name%! Bereits erteilte Berechtigungen, die Sie hier nicht auswählen, werden aufgehoben. Benutzer, die derzeit online sind Wer ist online? Schreiben Ja, löschen Sie gehören folgenden Gruppen an: Weitere Möglichkeiten für die Navigation sind der Sie können es jederzeit wieder aktivieren, indem Sie Sie haben keine Verwaltungsrechte für das Objekt %root% oder ihm untergeordnete Objekte. Sie haben noch kein Bild hochgeladen. Sie können Sie haben Verwaltungsrechte für folgende Objekte: Sie haben derzeit keine Benachrichtigungsfunktion aktiviert. Benutzerkonto Ihre Benachrichtigungen für Diskussionsforen Ihr Bild: Ihre Benachrichtigungen für %gc_system_name% Sie sind unter %site_link% als wieder anwesend gekennzeichnet. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ru_RU.utf-8.xml0000644000175000017500000001125610727201372025354 0ustar frankiefrankie О Ð’Ð°Ñ Ð’Ð°ÑˆÐ° ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ в %system_name% была закрыта. Да, пожалуйÑта удалите мою учётную запиÑÑŒ <p>Ваша ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ закрыта.</p> <p>Ð’Ñ‹ можете <a href="%restore_url%">открыть её Ñнова</a>.</p>. Панель ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐžÑ‚Ð²ÐµÑ‚ Ошибка Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐŸÑ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ðеверный Пароль ОÑновные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð˜Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ Ñзык интерфейÑа Изменить пароль Изменить пароль, Ð°Ð´Ñ€ÐµÑ Ñлектронной почты, фото Дети Закрыть вашу учётную запиÑÑŒ Подтверждение паролÑ: Текущий пароль: Индивидуальные права ÐÐ´Ñ€ÐµÑ Ñлектронной почты Подтверждение адреÑа Ñлектронной почты Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð¸Ð¼Ñ (отчеÑтво) Забыли пароль? ПредоÑтавить права доÑтупа ДомашнÑÑ Ñтраница Ð¤Ð°Ð¼Ð¸Ð»Ð¸Ñ Ð’Ñ…Ð¾Ð´ в ÑиÑтему Завершить ÑÐµÐ°Ð½Ñ Ð—Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚ÑŒ ÑÐµÐ°Ð½Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ %system_name% Как бы вы хотели, чтобы мир знал как выглÑдит %first_names% %last_name%? УнаÑледованные права %num_children% детей ÑпрÑтано Подтверждение Ð¿Ð°Ñ€Ð¾Ð»Ñ URL: домашней Ñтраницы Показать вÑем в %system_name% как хорошо вы выглÑдите: Загрузите ваше любимое изображение, JPEG или GIF, Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÐµÐ³Ð¾ компьютера(не указывайте ÑÑылку на файл в Интернет; картинка должна находитÑÑ Ð½Ð° вашем жёÑтком диÑке). Ðажав на кнопку "Browse...", выберите файл, затем нажмите "Open" ("Открыть"). Ðовый пароль: отÑутÑтвуют (необÑзательно) Пароль Ð’Ð¾Ð¿Ñ€Ð¾Ñ Ð—Ð°Ñ€ÐµÐ³Ð¸ÑтрироватьÑÑ Ð—Ð°Ð¿Ð¾Ð¼Ð½Ð¸Ñ‚ÑŒ моё Ð¸Ð¼Ñ Ð¸ пароль на Ñтом компьютере Ð˜Ð¼Ñ Ð½Ð° Ñкране показать Пару Ñлов под фотографией Благодарим Ð²Ð°Ñ Ð²ÐµÑ€Ð½ÑƒÑ‚ÑŒÑÑ Ðº %context_name% Изменить Обновить пароль загрузить фото Загрузить фото Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð”Ð¾Ð±Ñ€Ð¾ пожаловать, %user_name% Ð’Ñ‹ в Ñледующих группах Ваше фото openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.nl_NL.ISO-8859-1.xml0000644000175000017500000006774110727201372025574 0ustar frankiefrankie , of Basisinformatie bijwerken Lid van %system_name% sinds Iets over mijzelf Deze rekening op %system_name% is gesloten. Nee, naar %pvt_home_name% teruggaan Ja, mijn rekening sluiten. <p>Deze rekening is gesloten.</p> <p>Volg deze <a href="%restore_url%">koppeling om de rekening te heropenen</a>.</p> Rekening gesloten <P><FONT color='red'><B>Deze rekening is momenteel gesloten.</B></FONT> Bij het<A href='%login_url%'>opnieuw aanmelden</a> zal worden aangegeven hoe verder te handelen.<P> Deze rekening is op dit moment niet bereikbaar. Uw rekening op %system_name% is heropend. Welkom terug! Rekening heropend Actie Toevoegen folder toevoegen Nieuwe toepassing toevoegen Voeg deze gebruiker toe Gebruiker toevoegen Gebruikers toevoegen Beheren Beheerder %subsite_name% beheren Administratieve opties voor deze gebruiker Kennisgevingstype een andere foto. Antwoord: Fout in toepassing Toepassingen Goedkeuren op Interne foutgedurende authenticatie Identiteitscontroleur Verkeerd wachtwoord Uitsluiten Basisinformatie Biografiën Biografie Biografie-MIME-type Biografie-MIME-typen Het achterhalen van een wachtwoord via de locale identiteitscontroleur (de database) wordt niet ondersteund. Ledenlijst verborgen Taal instellen Verander mijn e-mailprivacyniveau Mijn wachtwoord veranderen Wachtwoord, e-mail, portretfoto veranderen Het wachtwoord is naar het bij ons bekende e-mailadres gestuurd onderliggende elementen Kies een aangepaste registratievraag Kies de vraag die aan nieuwe gebruikeers getoond wordt.<BR>Het kan gebruikt worden om geautomatiseerde akties (bijvoorbeeld gebruikers toevoegen aan bepaalde groepen, bepaalde mensen op de hoogte brengen van nieuwe registraties, enzovoorts.). <P>Bevestig dat de rekening op %system_name% moet worden gesloten.<P>Het sluiten van uw rekening betekent dat we niet langer kennisgevingen kunnen sturen en we de rekening ook niet meer in de ledenlijst op %system_name% kunnen tonen. Alle bijdragen aan de gemeenschap, zullen daarentegen bewaard blijven; deze maken immers deel uit van de geschiedenis van deze gemeenschap.<P>Merk op dat u uw rekening op ieder moment gewoon weer kunt heropenen. Mijn rekening sluiten Besloten groep Opmerking Gemeenschappen Gemeenschappen gemeenschap Bevestigen Het kiezen van een nieuw wachtwoord is succesvol afgerond. Doorgaan Naar %pvt_home_name% doorgaan Landnaam Aanmaken Maak een nieuwe vragenlijst aan die aan nieuwe gebruikers wordt voorgelegd. Nieuwe %pretty_name% aanmaken Nieuwe subsite aanmaken Huidig wachtwoord: <P><h2>Mijn onlinestatus:</h2></p><p> Andere gebruikers kunnen momenteel <i>niet</i> zien dat ik online ben.</p> <P><h2>Mijn onlinestatus:</h2></p><p> <ul><li>Andere gebruikers kunnen momenteel zien dat ik online ben. </li></ul></p> Vraag aanpassen Databasefout standaardcontext Verwijderen wissen Administratie (ontwikkelaar) Administratie voor ontwikkelaars Directe rechten Uitschakelen Uitgeschakeld Domein E-mail Wijzigen Wijzig gekozen vragenlijst opmerking bewerken Opties wijzigen Bepaalde elementen kunnen niet worden bewerkt, omdat ze onder het beheer van %authority_name% vallen. E-mail Sta toe contact met me op te nemen doormiddel van een formulier Sta contact opnemen toe met formulier Toon mijn e-mailadres als afbeelding Toon e-mailadres als afbeelding Toon mijn e-mailadres als tekst Toon e-mailadres als tekst Hierbij de benodigde informatie om opnieuw te kunnen aanmelden: %account_id_label%: %account_id% %password_label%: %password% Bezoek de volgende koppeling en verander het wachtwoord direct: %reset_password_url% Bedankt voor de inschrijving op %system_name%. Met de volgende gegevens is er toegang tot %system_url%: %account_id_label%: %account_id% %password_label%: %password% Bezoek de volgende koppeling en verander het wachtwoord direct: %reset_password_url% E-mailbevestiging Toon mijn e-mailadres niet Toon e-mailadres niet Niet beschikbaar E-mail niet aangevraagd E-mail vereist Het vergeten wachtwoord van %system_name% Welkom bij %system_name% Ingeschakeld Typ de eigen gebruikersnaam in zodat het bijbehorende wachtwoord kan worden achterhaald. Portretfoto wissen portretfoto wissen Fout Fout bij het verzenden van de e-mail Er is een fout opgetreden tijdens het versturen van de e-mail voor de e-mailcontrole. Er is een fout opgetreden tijdens het aanmaken van een rekening voor jou. Er is een fout opgetreden tijdens het bijwerken van dde rekeninginformatie. Vervalt Bestandsnaam Voornaam Wachtwoord vergeten? Frequentie Ga terug een portretfoto van deze gebruiker aanbieden een portretfoto van mij aanbieden Toekennen Rechten toekennen We hebben al een groep met dit e-mailadres. We hebben al een gebruiken met dit e-mailadres. We hebben al een gebruiker met deze gebruikersnaam. <p><h3>Helpinformatie</h3> Verbergen Mijn website Als je zou Informatie bijgewerkt Installeer talen Uitnodigen ISO-code Lijst met ISO-codes ISO-codes zijn niet geïnstalleerd ISO-codes zijn niet geïnstalleerd Bij gemeenschap inschrijven Bij %group_name% inschrijven Bij subsite inschrijven Bij deze gemeenschap inschrijven Bij deze subsite inschrijven Sleutelwoord Achternaam &nbsp; Gemeenschap verlaten Subsite verlaten Deze gemeenschap verlaten Deze subsite verlaten Terug, geen gebruikers toevoegen Aanmelden aanmelden Aanmelden bij %system_name% opnieuw aanmelden Deze aanmeldsessie is verlopen. Graag opnieuw aanmelden. Aanmelden of inschrijven aanmeldpagina Afmelden Bij %system_name% afmelden , dan kan meer informatie over andere gebruikers worden verkregen. Voeg aangeduidde gebruikers toe aan gebruikers die rechten hebben op je object. Bij deze groep is inschrijven niet mogelijk Complete lijst met ISO-codes Op %system_name% doorwerken Niet erven van %parent_object_name% Bijschrift bewerken van de portretfoto van %first_names% %last_name% %first_names% %last_name% (%email%) heeft zich ingeschreven als gebruiker op %system_url% Voor hoofdbeheerders Rechten voor %name% toekennen Dit is het bericht van de database: Hoe dient de wereld %first_names% %last_name% te zien? Indien deze persoon hier zeker geen rekening heeft: Indien deze persoon hier wel of mogelijk wel een rekening heeft: Indien deze functie nodig is, dienen eerst acs-reference en ref-countries te worden geactiveerd. Erven van %parent_object_name% Erf rechten van de %parent_object_name% Geërfde rechten Het is een zeer slecht idee om deze optie te gebruiken indien deze computer wordt gedeeld met anderen; zoals in een bibliotheek of school. Elke volgende gebruiker van deze computer kan zich dan immers toegang tot uw registratiegegevens verschaffen. Nieuwe inschrijving op %system_url% Rode tekst onder de invoervelden van parameters geeft aan dat de waarde van deze parameter overschreven wordt door een waarde in het OpenACS parameterbestand. Het gebruik van het parameterbestand wordt afgeraden maar sommige sites hebben dit nodig voor het instellen van instance-specifieke parameterwaarden, die onafhankelijk zijn van waarden in de apm_parameter tabellen. Het opgeslagen e-mailadres en het wachtwoord kunnen worden gewist door op "afmelden" te klikken. %num_children% verborgen onderliggende elementen <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> is op %portrait_publish_date% in de database opgenomen. Onze server kan browsers opdragen om dingen te onthouden, zoals een e-mailadres en wachtwoord. Dit heeft als voordeel dat een e-mailadres en wachtwoord niet steeds hoeven te worden ingetypt. Dit is echter alleen veilig als men de computer niet met anderen deelt. Wachtwoordbevestiging Persoonlijke website URL: Kies de eigen landcode uit de onderstaande lijst en gebruik vervolgens de knop "Terug" van de browser om naar het vorige formulier terug te gaan. Lees en volg de instructies in deze e-mail alstublieft. Probeer nogmaals om <a href="index">aan te melden</a> Portretfoto van %first_names% %last_name% Hogere privileges omvatten alle onderliggende privileges. Bijvoorbeeld, het toekennen van "admin"-rechten houdt ook het toekennen van "read"- en "write"-rechten in. Identiteitscontrole is mislukt De inschrijfgegevens voor deze service zijn verzonden aan %email%. De inschrijfgegevens voor deze service zijn verzonden aan %email%. Het inschrijvingsverzoek is verzonden aan de beheerder van %system_name%. We wachten nu op toestemming. e-mailadres en wachtwoord worden opgeslagen Laat aan iedereen op %system_name% zien hoe goed je eruit ziet: De toegang werd geweigerd. Waarschijnlijk is deze rekening uitgesloten van %system_name% en gedeactiveerd. Stop met rechten erven van de %parent_object_name% De portretfoto van deze gebruiker echt verwijderen? De eigen portretfoto echt verwijderen? Deze foto kan niet worden getoond. Er zijn geen gebruikers die nog geen toegang op dit object hebben. De identiteitscontrole bij deze rekening geeft problemen Dit is de foto die we aan andere gebruikers op %system_name% tonen Deze gebruiker heeft nog geen portretfoto. Er kan Deze gebruiker is uitgesloten en verwijderd uit deze gemeenschap. Ga naar %confirmation_url% om de inschrijving te bevestigen. Biedt een favoriet bestand van de eigen computer aan. Het mag een ingescand JPEG- of GIF-bestand zijn. Er kan helaas geen verwijzing worden gemaakt naar een bestand ergens op het internet. Opgeslagen: %pretty_date% Opgeslagen: %publish_date% De knop \"Bladeren\" gebruiken om een bestand te vinden en dan op \"Openen\" klikken Deze gebruiker heeft een biografie of portret opgeslagen We kunnen rekening %user_id% niet in de gebruikerstabel vinden. Kan het zijn dat deze rekening is verwijderd? Er was een probleem bij het verwerken van de invoer. Wij hadden deze e-mail niet verwacht. Er moet een vergissing in het spel zijn. Welkom bij %system_name% Wat andere gebruikers zien als ze op mijn naam klikken &lt; mag niet in een voornaam worden gebruikt. Het lijkt op een HTML tag en kan andere gebruikers in verwarring brengen. &lt; mag niet in een achternaam worden gebruikt. Het lijkt op een HTML tag en kan andere gebruikers in verwarring brengen. Je moet op zin minst een object_id_on of object_id_two opgeven. E-mailtoezending blijft gestaakt tot na %pretty_date% De e-mail is bevestigd. Aanmelden op %system_name% is nu mogelijk. De e-mail is bevestigd. We zijn nu in afwachting van toestemming door de beheerder van %system_name%. De e-mail is bevestigd. Deze aanmeldsessie is verlopen. Graag opnieuw aanmelden. Deze URL heeft niet de juiste opmaak. Een geldige URL ziet er als volgt uit \"%valid_url_example%\"." E-mail een bericht naar: Beheerder maken Lid maken Maak mij onzichtbaar Maak mij zichtbaar Beheer e-mailprivacy van gebruikers Mijn kennisgevingen instellen Sorry, de ledenlijst mag niet worden getoond. Lid Lidstatus Leden Ontbrekende parameter aankoppelen Mijn rekening Naam: nieuwe applicatie Nieuw wachtwoord: Geen toepassingen beschikbaar Geen evaluatie beschikbaar Geen ISO-codes beschikbaar Deze module heeft geen parameters Mijn portretfoto Geen %pretty_plural% beschikbaar Geen diensten beschikbaar Geen gebruiken gevonden met deze gebruikersnaam geen Niet aangemeld Dit is geen geldig e-mailadres Toelichting: Melding: op %name% aan: Online (facultatief) Opties Of een nieuwe gebruiker toevoegen of de Parameters parameters Wachtwoord: Het wachtwoord op %system_name%: %account_id_label%: %account_id% is gewijzigd. Er is geen actie nodig als het wachtwoord door de ontvanger van deze email ZELF is gewijzigd. Dit bericht is slechts bedoeld om te informeren en daarmee de veiligheid van de gegevens in het systeem te verhogen. --------------- Het wachtwoord kan altijd worden gewijzigd door het volgende te doen: 1. Aanmelden op %system_name% 2. Klik op "%pvt_home_name%" 3. Kies "%password_update_link_text%" Wachtwoord is veranderd Uw wachtwoord moet regelmatig veranderd worden. Verander alstublieft nu uw wachtwoord. Wachtwoorden komen niet overeen. Dit privilege kan niet verwijderd worden. Rechten rechten Rechten van %name% Keer terug naar %home_link%. Portretfoto Privacy Er is een probleem opgetreden tijdens de authenticatie van deze rekening. Vermoedelijk bevat de database gebruikers zonder "member_state". Profiel Vraag: Opnieuw inschakelen Lezen Wachtwoord achterhalen Aanmeldsessie verversen Aangepaste gebruikersregistratievragenlijst Inschrijven <p> Bedankt voor de inschrijving bij %system_name%. De beheerder is op de hoogte gebracht. Zodra toestemming is gegeven, zal dit via een e-mail worden gemeld. Daarna kan %system_name% verder worden gebruikt. Weigeren Aanmeldsessie op deze computer bewaren Verwijderen Allen verwijderen Hernoem Toegang tot deze gemeenschap verzoeken Toegang tot deze subsite verzoeken Toegang vragen Terugkeren naar de toepassing Gemarkeerde intrekken Rol Opmerking opslaan Schermnaam Deze schermnaam is al in gebruik. Zoek een gebruiker Hoofdveiligheidscontext Kies een object via Id: Stuur e-mail naar deze gebruiker Stuur me een kopietje: Tonen Sitebreed beheer Hoofdadministratie Sorry, wij kunnen niet verder helpen met het vergeten wachtwoord. Status Verhaal achter de foto Verhaal achter de foto Subgroepen subgroepen subgroep subsite Subsites subsites Uw authenticatie is gelukt, maar u heeft nog geen rekening op %system_name%. Bedankt. De ISO-codes zijn niet geïnstalleerd op deze server. Dit is een besloten groep. Alleen nieuwe leden met een uitnodiging worden toegelaten. deze subsite Deze gebruiker heeft de gemeenschap verlaten. Met dit wachtwoord kan men zich aanmelden op de Onderwerp soortspecifieke info Onbekend e-mailadres afkoppelen Één niveau hoger tot aan %context_name% Bijwerken Wachtwoord bijwerken aanbieden Portretfoto aanbieden een nieuwe portretfoto aanbieden Portretfoto aanbieden Gebruikersportret Gebruikersportretten. Gebruikersprofiel Gebruikersprofielen Gebruikersnaam Geen gebruiker met gebruikersnaam '%username%' gevonden voor de authoriteit %this_authority% Gebruikersnaam vereist Paginaoverzicht van gebruiker De informatie omtrent afwezigheid is bijgewerkt De informatie omtrent afwezigheid op %site_link% is bijgewerkt. Welkom, %user_name% Een leeg aankruisvakje betekent, dat de rechten van de gebruiker worden ingetrokken, voorzover deze rechten eerder waren toegewezen. Gebruikers die nu online zijn Wie is er online? Schrijven Ja, zeker Mijn aansluitingen bij gebruikersgroepen: Bladeren kan ook uit de Heropenen kan altijd door Er zijn geen rechten om het object %root% of onderliggende elementen te beheren. Mijn portretfoto is nog niet beschikbaar. Er zijn rechten aanwezig om de volgende objecten te beheren: Er staan geen kennisgevingen ingesteld. Mijn rekening Mijn forum-kennisgevingen Mijn portretfoto: Mijn %gc_system_name%-kennisgevingen %site_link% toont dat u weer aanwezig bent openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ast_ES.ISO-8859-1.xml0000644000175000017500000001103510727201372025731 0ustar frankiefrankie Sobre ti <p>La to cuenta actualmente ta zarrada.</p> <p>Si quies, podemos <a href="%restore_url%">volver a abrila</a>.</p> Rempuesta en Clave equivocada Información Básica Nun se puede recuperar clave dende autoridá local Cambiar la mio Clave Mira'l Buzón de Correo Neños Confirmar Clave Actual Personalizar la Pregunta Permisos Directos Corréu Lletrónicu Confirmación de Corréu Corréu non solicitáu Error al mandar corréu Nome Dar Dar Permisu Axuntase a "%group_name%" Apellíu Entrada Nun te puedes axuntar a esti grupu "%first_names% %last_name% (%email%)" rexistráu como usuariu de(d') "%system_url%" Dar Permisu en "%name%" Permisos heredaos Nun ye una bona idega escoyer esta opción si tas usando una computadora compartida nuna biblioteca o escuela. El prósimu usuariu d'esta máquina podría usar el nuestru serviciu faciendose pasarpor ti. Rexistru nuevu en "%system_url%" Repara en que puedes eliminar les tos señes lletróniques y clave guardaos nel to ordenador escoyendo "Salir" nel to espaciu web de trabayu. "%num_children%" Fíos ocultos El %portrait_publish_date%, xubisti <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">"%portrait_title%"</a> El nuestru servidor puede dicí-y al to restolador que recuerde delles coses, ye'l casu de les tos señes lletróniques y la to clave. Esto ta bien porque si yes la única persona que fae usu del to computador, nun tienes que repetinos les tos señes nin la to clave. Confirma la to Clave URL del to Web: Por favor llee y sigui les instrucciones del corréu. Por favor intenta <a href="index">conectar</a> otra vuelta Problemes cola autentificación La información del rexistru pa esti serviciu ta acabante de mandase a "%email%". La información del rexistru pa esti serviciu mandóse a "%email%". La to pitición de rexistru mandóse al alministrador de(d') "%system_name%". Inda tas pendiende d'aprovación. Guardando Señes lletróniques y Clave Enseñar a tol mundiu "%system_name%" lo prestosu que yes: Sentímoslo pero fuisti espulsáu de(d') "%system_name%". Hebo un problema cola autentificación de la to cuenta Pa confirmar el to rexistru, por favor vete a "%confirmation_url%" Nun tamos a la espera del to corréu. Debe haber un error. Bienllegáu/da a "%system_name%" El Corréu foi confirmáu. Puedes entrar agora en "%system_name%". openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.hu_HU.utf-8.xml0000644000175000017500000001510010727201372025320 0ustar frankiefrankie Infó rólad Nem, inkább visszamegyek az %pvt_home_name% (?) Igen, felfüggesztem az accountomat <p>Az accountod felfüggesztetted.</p> <p>Ha szeretnéd, <a href="%restore_url%">újraéleszthetjük</a>.</p> <p> <font color="red"> <b> Az accountod legutóbb felfüggesztetted. </b> </font> <a href="%login_url%">Lépj be</a> mégegyszer, és megtudod, mit tehetsz ezzel kapcsolatban.</p&;gt; A(z) %system_name% accountod újranyitottuk. Üdvözlünk, hogy visszatértél! Az account újra lett élesztve Beállítások Válasz Rossz jelszó AlapvetÅ‘ adatok Helyszín és nyelv megváltoztatása Jelszó megváltoztatása BeérkezÅ‘ levelek Utódok <p> Kérlek erÅ‘sítsd meg, hogz fel szeretnéd függeszteni a(z) %system_name% accountodat. </p> <p> Az accountod felfüggesztése azt jelenti, hogy nem fogunk email értesítéseket küldeni, sem pedig a %system_name%felhasználók listáján nem fogsz megjelenni. A hozzászólásaid és hasonlók mindazonáltal megmaradnak, mivel részei a közösség történelmének. </p> <p> Figyelmedbe ajánljuk, hogy bármikor újraélesztheted az accountod, csak egyszerűen be kell lépned. </p> Account felfüggesztése Mégegyszer Jelenlegi jelszó <p>A többi felhasználó nem látja, hogy be vagy lépve.</p> <p>A többi felhasználó látja, hogy be vagy lépve.</p> A kérdés testreszabása Közvetlen jogosultságok Email Email-ellenÅ‘rzés Email nem szükséges Az elfeledett %system_name% jelszavad Üdvözlünk a(z) %system_name% oldalán Hiba az email elküldésekor Keresztnevek Engedélyez Jogosultság megadása Csatlakozás a %group_name% csoporthoz Vezetéknév Bejelentkezés Kilépés Nem csatlakozhatsz ehhez a csoporthoz. %first_names% %last_name% (%email%) regisztrálva lett mint %system_url% felhasználó Jogosultság megadása a(z) %name% felhasználó részére Öröklött jogosulságok Ha sokak által használt számítógépet használsz (például iskolában vagy könyvtárban), akkor rendkívül rossz ötlet ezt a lehetÅ‘séget választani, hiszen bárki, aki utánad használja a számítógépet a te nevedben léphetne fel. Új regisztráció itt: %system_url% A "kijelentkezés" opcióval kitörölheted az elmentett email-címed és jelszavat. %num_children% utód elrejtve A szerverünk ráveheti a böngészÅ‘d, hogy emlékezzen bizonyos dolgokra, mint például az email-címed és a jelszavad. Ez igen hasznos és kényelmes lehetÅ‘ség, ha egyedül te használod ezt a számítógépet, hiszen nem kell minden alkalommal beírnod az email-címed és jelszavad. Jelszó megerÅ‘sítése Személyes weboldal címe: Légy szíves kövesd az emailben megadott instrukciókat. Próbálj meg újra <a href="index">bejelentkezni</a> Probléma az azonosítással A regisztrációs információt elküldtük a következÅ‘ címre: %email% Email-cím és jelszó mentése Mutasd meg az egész %system_name% közösségnek, milyen jól nézel ki: Sajnáljuk, de úgy tűnik ki lettél tiltva a(z) %system_name%-ról/rÅ‘l. Üdvözlünk itt: %system_name% Amit mások látnak, ha a nevedre klikkelnek Az email-címed ellenÅ‘rizve lett Tedd magad láthatatlanná Tedd magad láthatóvá Értesítések kezelése Új jelszó nincsenek A jelszó megváltoztatása sikerült Jogosultságok %name% jogosultságai Megjelöltek jogok visszavonása Megmutat vissza ehhez: %context_name% Jelszó megváltoztatása portré feltöltése Üdvözöljük, %user_name% Az éppen bejelentkezett felhasználók Kik vannak bejelentkezve A portréd openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.es_GT.ISO-8859-1.xml0000644000175000017500000005322610727201372025564 0ustar frankiefrankie , o Actualizar Información Básica Miembro de %system_name% desde Mi información Su cuenta en %system_name% ha sido cancelada. No, volver a %pvt_home_name% Sí, cancelar mi cuenta <p>Su cuenta se encuentra cerrada por el momento.</p><p>Si usted lo desea, podemos <a href="%restore_url%">re-abrir su cuenta</a>.</p> <p><font color="red"><b>Su cuenta está actualmente cancelada.</b></font><a href="%login_url%">Conectese</a> de nuevo para ver que puede hacer al respecto.</p> Su cuenta en %system_name% ha sido reactivada. Bienvenido de nuevo. Cuenta reactivada Acción Agregar una nueva aplicación Panel de Control Administrar %subsite_name% Opciones de administración para este usuario Tipo de aviso otra imagen. Respuesta: Error de la aplicación Aplicaciones Aprobar en Autoridad Contraseña errónea Prohibir Información básica Biografía No se soporta la obtención de contraseñas de una autoridad local. No puede ver la lista de miembros Seleccionar idioma Cambiar mi contraseña Cambiar contraseña, email, foto Revisar correo entrante Hijos <p>Por favor, confirme que realmente desea cancelar su cuenta en %system_name%.</p> <p>Cancelar una cuenta significa que no seguirá recibiendo notificaciones, ni formará parte de los miembros de %system_name%. No obstante, sus contribuciones a la comunidad se conservarán como parte del histórico de la comunidad.</p> <p>Tenga en cuenta que puede reabrir su cuenta en cualquier momento, para ello simplemente vuelva a conectarse.</p> Cancelar cuenta Grupo Cerrado Comentario Comunidades comunidades comunidad Confirmar: Usted ha seleccionado una nueva contraseña con éxito Continuar Continuar a %pvt_home_name% País Crear nuevo %pretty_name% Crear un nuevo subsitio Contraseña Actual: <p>Su nombre NO aparece en la lista de usuarios conectados.</p> <p>Su nombre aparece en la lista de usuarios conectados.</p> Personalizar pregunta Error de base de datos contexto por defecto Borrar DevAdmin Administración de desarrolladores Permisos directos Desactivar Desactivado Dominio Correo Electrónico editar comentario Algunos elementos no pueden ser editados ya que están siendo administrados por %authority_name%. Correo Electrónico Datos de su cuenta: %account_id_label%: %account_id% %password_label%: %password% Para cambiar su contraseña, visite %reset_password_url% Gracias por registrarse en %system_name%. Para conectarse, visite %system_url%: %account_id_label%: %account_id% %password_label%: %password% Para cambiar su contraseña, visite %reset_password_url% Confirmación de Correo Electrónico Correo electrónico no solicitado Recordatorio de su contraseña en %system_name% Bienvenido a %system_name% Activado Introduzca su nombre de usuario para poder recuperar su contraseña. Borrar foto borrar foto Error Error al enviar el correo Caduca Nombre de archivo Nombres ¿Ha olvidado su contraseña? Frecuencia Regresar subir la foto del usuario sube tu retrato Otorgar Autorizar Oculto Página web Si fueras a Información Actualizada Invitar Código ISO Lista de Códigos ISO Los Códigos ISO no han sido cargados Códigos ISO no cargados Únete a la comunidad Unirse a %group_name% Únete al subsitio Únete a esta comunidad Únete a este subsitio Palabra clave Apellido después. Salir de la comunidad Salir del subsitio Salir de esta comunidad Salir de este subsitio Regresar sin agregar ningun usuario Entrar entrar Registrate en %system_name% registrarse de nuevo La pagina de registro ha expirado. Por favor registrarse de nuevo. Entrar o registrarse. página de registro Salir Salir de %system_name% ,serás capaz de adquirir mas información en el miembro de tu comunidad No puede unirse a este grupo. Lista completa de los códigos ISO Sigue trabajando en %system_name% Editar commentario de la foto de %first_names% %last_name% %first_names% %last_name% (%email%) se registró como usuario de %system_url% Para los Administradores del sitio Otorgar permiso en %name% Esto es lo que la base de datos reporto: Cómo quisieras que el mundo te viera %first_names% %last_name%? Si crees que la persona ya tiene una cuenta: Si sabes o crees que la persona que quieres invitar ya tiene una cuenta en el sistema: Si necesitas esta funcionalidad, por favor carga acs-reference y ref-countries. Permisos heredados Puede ser una mala idea escoger esta opción si está usando una computadora compartida de una biblioteca o colegio. Cualquier usuario que utilice esta computadora en adelante podría hacerse pasar por usted en nuestra plataforma. Nuevo registro en %system_url% Note que el texto en rojo mostrado debajo de la entrada del campo de parámetro indica que el valor del mismo está siendo sobreescrito por una entrada en el archivo de parámetro de OpenACS. Desalentamos el uso del mismo pero algunos sitios lo necesitan para proveer valores específicos de instancia para los parámetros independientes de la tabla apm_parameter. Tenga en cuenta que puede eliminar su dirección de correo y contraseña de la memoria de su computadora, haciendo click en la opción "Salir" de su portal. %num_children% Hijos ocultos El %portrait_publish_date%, subiste <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%"">%portrait_title%</a> Nuestro servidor le puede decir a su navegador que recuerde algunas cosas como su dirección electrónica y su contraseña. Esto es conveniente porque si usted es la única persona que usa su computadora, no tiene que repetirnos su correo ni su contraseña. Confirmación de la contraseña: URL de su página personal: Por favor localiza el código de tu país entre los listados debajo, luego usa el boton "regresar" en tu navegador para regresar al formulario anterior. Por favor, siga las instrucciones dadas en ese correo. Por favor, intente <a href="index">ingresar</a> de nuevo Foto de %first_names% %last_name% Privilegios altos en la jerarquía implican todos los privilegios debajo, ejemplo: cuando otorgas admin, luego leer, escribir , etc. estan implicados automáticamente. Problema con la autenticación La información de registro para este servicio acaba de ser enviada a %email% La información de registro para este servicio ha sido enviada a %email%. Su solicitud de registro ha sido enviada al administrador de %system_name% y está en espera de aprobación. Guardando dirección de correo y contraseña Hagase conocer a los usuarios de %system_name% Lo sentimos, pero ha sido expulsado de &system_name% Seguro que quieres borrar la foto de este usuario? Estas seguro de borrar tu foto? Tu foto en el systema es inválida. Por favor Ha ocurrido un problema durante la autenticación de su cuenta Esta es la imagen que mostraremos a los otros usuarios en %system_name% Este usuario no tiene foto todavía. Puedes Este usuario fue borrado y su acceso a la comunidad fue prohibido. Para confirmar su registro, por favor, acuda a %confirmation_url% Sube tu foto favorita, un archivo escaneado en formato JPEG o GIF, de tu computadora(nota que no puedes hacer referencia a una imagen en algún lado de internet; tiene que estar en tu disco duro). Subido: %pretty_date% Subido: %publish_date% Utiliza el botón de "Examinar..." para localizar tu archivo, luego selecciona el botón de "Abrir". No te pudimos encontrar (usuario %user_id%) en la tabla de usuarios. Probablemente tu cuenta fue borrada por alguna razón. Tuvimos un problema procesando tu entrada. No estabamos esperando su correo. Debe tratarse de un error. Bienvenido a %system_name% Lo que verán los demás al hacer click sobre su nombre No puede introducir un signo &lt; en su nombre ya que corresponde a una etiqueta HTML y podría crear confusión. No puede introducir un signo &lt; en sus apellidos ya que corresponde a una etiqueta HTML y podría crear confusión. No podrás recibir ningún correo hasta después de pretty_date%. Su correo ha sido confirmado. Ahora, puede ingresar a %system_name%. Su correo ha sido confirmado. Ahora, debe esperar la aprobación del administrador de %system_name%. Su correo ha sido confirmado Tu sesión ha expirado. Por favor ingresa tu contraseña para poder seguir trabajando. El URL introducido no es válido. Un ejemplo de URL válida es \"%valid_url_example%\"." Volver administrador Volver miembro Volverse invisible Volverse visible Administrar notificaciones Lo sentimos, pero no estas autorizado para ver la lista de miembros. Estado del miembro Miembros Nombre y apellidos: Nueva contraseña: No hay aplicaciones No hay códigos ISO Este paquete no tiene parámetros. su foto No tiene %pretty_plural% No hay servicios ninguno No registrado Notas: Aviso: en %name% a (opcional) Opciones O agregar un nuevo/a usuario/a o el Contraseña: Su información de ingreso en %system_name%: %account_id_label%: %account_id% Su contraseña para esta cuenta ha sido modificiada recientemente. Usted no necesita hacer nada, ésta es simplemente una notificación para proteger la seguridad de su cuenta. --------------- Usted puede cambiar su contraseña realizando los siguientes pasos: 1. Ingrese a %system_name% 2. Haga click en el link "%pvt_home_name%" 3. Escoja "%password_update_link_text%" Contraseña modificada Permisos permisos Permisos para %name% Por favor regresa a %home_link%. Foto Pregunta: Reactivar Recuperar Contraseña Actualizar login Registro <p> Gracias por registrarse a %system_name%. Un administrador ha sido notificado por su solicitud. </p> <p> Una vez este aprovado, se le enviara un mail para que pueda empezar a utilizar %system_name%. </p> Rechazar Recordar mi contraseña en esta computadora Eliminar Eliminar todos Solicitar membresía de esta comunidad Solicitar membresía de este subsitio Solicitar membresía regresar a la aplicación Revocar Rol Guardar comentario Alias Buscar un usuario existente Contexto de seguridad de root Seleccionar un objeto por Id Enviar email a este usuario Mostrar Administración del sitio Lo sentimos, no podemos ayudarlo con su contraseña olvidada. Estado Historia Detrás Foto Historia Detrás Foto Subcomunidades subcomunidades subcomunidad subsitio Subsitios subsitios Gracias. Los códigos ISO no fueron cargados en este servidor. Este grupo esta cerrado. Nuevos miembros solo pueden tener acceso por invitación. este subsitio Este usuario ha dejado la comunidad. Para logearse, visite el Tópico Introduzca información especifica UP volver a %context_name% Actualizar Actualizar contraseña subir subir una foto cargar un retrato de reemplazo Cargar Retrato Nombre de usuario Mapa del sitio del usuario Información de Vacaciones Actualizada La información de sus vacaciones en %site_link% ha sido actualizada. Bienvenido/a, %user_name% Cuando aquí usted deja un checkbox vacío ese privilegio será revocado por el grupo que escogió en caso de que haya sido concedido a ese grupo con anterioridad. Usuarios conectados en este momento ¿Quién está conectado? Sí, estoy seguro Usted esta en los siguientes grupos: También puede navegar desde el Usted siembre puede reabrirlo con No tiene derechos de administración en el objeto %root% o cualquier de sus hijos Usted aun no tiene una foto. Usted puede Tiene derechos de administración en los siguientes objetos: Actualmente no tiene avisos de correo activados. Su Cuenta Tus avisos en los foros Su foto Su %gc_system_name% alerta Usted ha sido marcado como de vuelta de vacaciones en openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.tr_TR.utf-8.xml0000644000175000017500000000447110727201372025353 0ustar frankiefrankie Sizin Hakkınızda Yonetici kontrol paneli Cevap: Kötü Åžifre Temel Bilgi Dil degistir Sifre Degistir Sifre, e-posta, resim degistir Gelen kutusunu kontrol edin Çocuklar Hesabinizi kapatin Teyit: Güncel Åžifre: <p> Su an diger kullanicilar sizin sistemde oldugunuzu goruyor. <p> Soruyu ÖzelleÅŸtir Direkt İzinler E-posta Eposta Teyidi Eposta istenmiyor posta yollama hatası Adiniz Verme İzin Verme Ana sayfa Soyadiniz Sistemden cik %system_name% 'den cik Sistemdeki %system_name% haric herkese nasil gorundugumu goster: Diger kullanicilar isminize tiklayinca ne gorecekler Kendizini gorunmez yapin Ozelliklerinizi yonetin İsim: Yeni Åžifre: Gorunen isminiz Güncelle resim yükle Hosgeldiniz, %user_name% Su an bagli olanlar Sistemde kimler var Su an asagidaki gruplardasiniz: Resminiz openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.fi_FI.utf-8.xml0000644000175000017500000001335510727201372025276 0ustar frankiefrankie Tietoja sinusta Vastaus: kohteessa Väärä salasana Perustietoja Vaihda salasanaa Tarkista tulleet postit Jälkeläiset Uusi salasana uudelleen: Nykyinen salasana: Muokkaa kysymystä Suorat käyttöoikeudet Vahvistus sähköpostilla Sähköpostia ei pyydetty Virhe lähetettäessä sähköpostiviestiä Myönnä Myönnä oikeus Liity %group_name% -ryhmään Kirjaudu sisään Et pysty liittymään tähän ryhmään %first_names% %last_name% (%email%) rekisteröity %system_url%:n käyttäjäksi Myönnä oikeus käyttäjälle %name% Perityt käyttöoikeudet On todella HUONO IDEA valita tämä vaihtoehto, mikäli käyttämäsi kone on yhteiskäytössä esim. kirjastossa tai koulussa. Seuraava käyttäjä pystyy tällöin kirjautumaan palveluumme sinun tunnuksellasi. Uusi rekisteröityminen %system_url% -järjestelmään Huomaa, että voit nollata tallentamasi sähköpostiosoitteen ja salasanan valitsemalla "kirjaudu ulos" järjestelmän omalta kotisivultasi. %num_children% piilotettu(a) lapsi/lasta %portrait_publish_date% tallensit tänne kuvan nimeltä <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Palvelimemme voi pyytää selaintasi muistamaan tiettyjä asioita, kuten sähköpostiosoitteesi ja salasanasi. Tämä on kätevää, koska jos olet koneesi ainoa käyttäjä, sinun ei tarvitse jatkuvasti syöttää näitä tietoja uudelleen. Salasnan varmistus: Oman kotisivun osoite: Lue ja seuraa viestissä olevia ohjeita. <a href="index">Kirjaudu</a> ystävällisesti uudelleen Ongelma käyttäjän autentikoinnissa Palvelun rekisteröitymisohjeet lähetettiin osoitteeseen %email%. Palvelun rekisteröitymisohjeet lähetettiin osoitteeseen %email%. Rekisteröitymispyyntösi on toimitettu järjestelmän %system_name% ylläpitäjälle. Se odottaa edelleen hyväksyntää. Tallennan sähköpostiosoitetta ja salasanaa Näytä muille %system_name%:n jäsenille, kuinka hyvältä näytät: Valitettavasti näyttää siltä, että sinut on asetettu pannaan järjestelmässä %system_name%. Käyttäjätunnuksesi autentikoinnissa oli ongelmia Vahvistaaksesi rekisteröitymisen siirry osoitteseen %confirmation_url% Emme odottaneet sähköpostiviestiä sinulta. Se on luultavasti tullut meille erehdyksessä. Tervetuloa %system_name%-järjestelmään Etunimessäsi ei voi olla &lt;-merkkiä, koska se näyttää HTML-tagilta ja sekoittaa muita käyttäjiä. Sukunimessäsi ei voi olla &lt;-merkkiä, koska se saa nimesi näyttämään HTML-tagilta ja sekoittaa muita käyttäjiä. Sähköpostisi on vahvistettu. Voit nyt kirjautua %system_name%-järjestelmään. Sähköpostisi on vahvistettu. Joudut vielä odottamaan järjestelmän %system_name% ylläpitäjän hyväksyntää. Sähköpostisi on vahvistettu Antamasi osoitteen muoto ei kelpaa. Pätevä URL voisi olla jotain tämän kaltaista: \"%valid_url_example%\"." Nimi: Uusi salasana: kuvasi ei yhtään Salasana: Käyttöoikeudet Kohteen %name% käyttöoikeudet Kysymys: Rekisteröidy Poista valitut Näytä Kiitos. takaisin sivulle %context_name% Päivitä Päivitä salasana lisää kuva itsestäsi Kuvasi: openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ar_EG.utf-8.xml0000644000175000017500000000273510727201372025277 0ustar frankiefrankie عنك :الجواب عÙنْدَ كلمة٠السر سيئة٠المعلومات الأساسية غيّرْ كلمةَ سري Ø¥ÙØ­ØµÙ’ صندوقَ إستلامكَ الأولاد :أَكّدْ :كلمة٠السر الحالية ÙØµÙ‘لْ سؤالاً الأذون المباشرة تأكيد٠بريد إلكتروني البريد الإلكتروني لَيسَ مطلوب :اسم :كلمة٠السر الجديدة٠لا أحد :كلمة السّرّ :السؤال٠عَرْض .شكرًا تّحديث تجديد٠كلمة السر أرسلْ صورةً صورتك openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.nn_NO.ISO-8859-1.xml0000644000175000017500000005221510727201372025567 0ustar frankiefrankie , eller Oppdater grunninformasjon Eit medlem av %subsite_name%-gruppa sidan Om deg Kontoen din ved %system_name% har blitt stengt. Nei, ta meg tilbake til %pvt_home_name% Ja, avslutt kontoen min <p>Kontoen din er stengt.</p> <p>Dersom du ønskjer det, kan vi <a href="%restore_url%">åpne kontoen din att</a>.</p> <p> <font color="red"> <b> Kontoen din er stengt. </b> </font> <a href="%login_url%">Logg inn</a> igjen for å sjå kva du kan gjere med det. </p&;gt; Kontoen din ved %system_name% har blitt opna igjen. Velkomen attende. Konto opna igjen Oppgåve Legg til nytt program Admin Administrer %subsite_name% Administrative val for denne brukaren Varseltype eit anna bilete Svar Programfeil Program Godkjenn Autoritet Feil passord Stengt ute Generell informasjon Biografi Det er ikkje støtte for å hente passord frå lokal autoritet. Kan ikkje sjå medlemslista Endre språk Endre passordet Endre passord, e-post, portrett Sjekk inn-post Born <p> Verifiser at du ønskjer å stenge kontoen din ved %system_name%. </p> <p> Å stenge kontoen ber med seg at vi ikkje lenger vil sende e-postmeldingar til deg, og du vil ikkje vere synleg på lista over medlemer ved %system_name%. Bidraga dine i gruppa vil likevel bli tekne vare på, sidan dei er ein del av gruppa si historie. </p> <p> Legg merke til at du når som helst kan opne opp att kontoen ganske enkelt ved å logge deg inn igjen. Steng kontoen din Stengt gruppe Kommentar Grupper grupper gruppe Verifiser Ditt nye passord er no registrert. Hald fram Hald fram å %pvt_home_name% Navn på land Lag ny %pretty_name% Lag ny undergruppe Nåværande passord <p> Din status på nettet er nå ikkje synleg for andre brukarar. </p> <p> Din status på nettet er nå synleg for andre brukarar. </p> Tilpass spørsmål Databasefeil standard samanheng Slett DevAdmin Administrasjon for utviklarar Direkte tilgang Gjer uverksam Uverksam Område E-post rediger kommentar Nokre element kan ikkje redigerast av di dei ikkje er under kontroll av %authority_name%. E-post Her er ny innloggingsinformasjon for deg: %account_id_label%: %account_id% %password_label%: %password% Gå til følgjande lenkje for å endre passord no: %reset_password_url% Takk for at du har registrert deg ved %system_name%. Slik kan du logge inn på %system_url%: %account_id_label%: %account_id% %password_label%: %password% Gå til følgjande lenkje for å endre passord no: %reset_password_url% Kvittering via e-post E-post ikkje bestilt Passordet ditt på %system_name% som du har gløymt Velkomen til %system_name% Tilgjengeleg Skriv inn brukannavnet ditt for å starte attfinning av passord. Slett bilete slett bilette Feil Feil ved sending av e-post Forelda Filnavn Fornavn Har du gløymt passordet? Frekvens Gå attende gå og last opp bilete av brukaren gå og last opp biletet ditt Gje Tillat Gøym Heimeside Dersom du skulle Informasjon oppdatert Invitert ISO kode ISO kodeliste ISO-kodar ikkje lasta ISO-kodar er ikkje opplasta Delta i gruppe Bli medlem i %group_name% Delta i undergruppe Bli medlem i denne gruppa Bli medlem i denne undergruppa Nøkkel Etternavn seinare. Gå ut av gruppa Gå ut av undergruppa Gå ut av denne undergruppa Gå ut av denne undergruppa Gå attende uten å leggje inn nye brukarar Logg inn logg inn Logg inn ved %system_name% logge inn att Innloggingssida har blitt forelda, så du må diverre logge inn på nytt. Logg inn ellerregistrer deg innloggingsside Logg ut Logg ut frå %system_name% , du ville vere i stand til å få meir informasjon om kollegaen din i gruppa. Kan ikkje verte medlem av denne gruppa. Full liste over ISO-kodar Hald fram å arbeide med %system_name% Rediger kommentar til biletet av %first_names% %last_name% %first_names% %last_name% (%email%) registrert som brukar av %system_url% For Site-Wide Administrators Gje rettar til %name% Dette vart rapportert frå databasen: Korleis vil du at verda skal sjå %first_names% %last_name%? Dersom du ikkje trur personen alt har konto: Dersom du veit eller trur at personen du ønskjer å invitere alt har konto på dette systemet: Dersom du treng denne funksjonaliteten kan du laste opp acs-reference og ref-countries. Arva rettar Det ville vere lite klokt å velgje dette dersom du brukar ei felles datamaskin i eit bibliotek eller eit anna fellesareal. Ein brukar som kjem etter deg vil kunne opptre som deg i tenesta vår. Ny registrering på %system_url% Legg merke til at tekst i raudt under feltet for innlegging av parameter tyder at verdien til denne parameteren er overstyrt av eit innlegg i Open ACS parameterfil. Bruk av parameterfila er ikkje anbefalt, men nokon stader må ein bruke dei for å gje spesifikke verdiar til prarmetrar uavhenging av apm_parametertabellar Legg merke til at du kan slette o-postadressa og passordet du har lagra ved å velgje "logg ut" frå arbeidsområdet ditt. %num_children% born gøymt Den %portrait_publish_date%, lasta du opp <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Tenesta vår kan be weblesaren din hugse visse ting, som brukar-id og passord. Dette er praktisk for deg dersom du er den einaste personen som brukar maskina, for då treng du ikkje fortelje dei til oss heile tida. Verifiser passord URL for personleg web-side: Du kan finne landkoden i lista under, så brukar du "tilbake"-knappen på nettlesaren din for å kome attende til skjemaet du var på. Les og føl instruksjonane i denne e-posten. Prøv å <a href="index">logge inn</a> på nytt Bilete av %first_names% %last_name% Rettar høgre i hierarkiet tek med seg rettar under - til dømes om du gjev nokon rettar som admin, vil lese- og skriverettane automatisk vere gjevne også. Problemer med autentisering Registreringsinformasjon for denne tenesta er no sendt til %email%. Registreringsinformasjon for denne tenesta er sendt til %email%. Registreringsønskjet ditt er sendt til administrator for %system_name%. Du ventar framleis på godkjenning. Lagrar e-postadresse og passord Vis alle andre på %system_name% korleis du ser ut: Eg er lei for det, men det ser ut som om du har blitt stengt ute frå systemet. Er du sikker på at du vil slette biletet av denne brukaren? Er du sikker på at du vil slette biletet ditt? Biletet av deg i systemet er ikkje gyldig. Ver snill å Det var eit problem med autentiseringa av kontoen din Dette er bilet som vi viser til andre brukarar av %system_name% Denne brukaren har ikkje noko bilete enno. Du kan Denne brukaren er sletta og utestengt frå gruppa. Gå til %confirmation_url% for å godkjenne registreringa di Last opp favorittfila di - eit bilete i JPEG eller GIF, frå di eiga datamaskin (legg merke til at du ikkje kan vise til eit bilete på ein annan stad på internettet; dette biletet må liggje på harddisken på di eiga maskin). Lasta opp: %pretty_date% Lasta opp: %publish_date% Bruk "Søk..."-knappen for å finne fila di, så klikkar du "Opne". Brukaren har lagt inn omtale eller lasta opp eit bilete Vi kan ikkje finne deg (brukar %user_id%) i brukarlista. Truleg har kontoen din blitt sletta av ein eller annan grunn. Vi fekk eit problem då vi skulle prosessere innlegget ditt. Vi ventar ikkje på e-post frå deg. Det må vere ei misforståing ein stad. Velkomen til %system_name% Det som andre ser når dei klikkar på navnet ditt. Du kan ikkje ha &lt; i fornavnet ditt fordi det vil likne på ein HTML-kode og forvirre andre brukarar. Du kan ikkje ha &lt; i etternavnet ditt fordi det vil likne på ein HTML-kode og forvirre andre brukarar. Du vil ikkje få nokon e-post før %pretty_date%. E-posten din er verifisert. Du kan no logge inn på %system_name%. E-posten din er motteken. Du ventar no på endeleg godkjenning frå administrator av %system_name%. E-posten din er motteken Innlogginga di har gått ut på tid. Skriv inn passordet ditt på nytt for å halde fram med arbeidet. URL-en din har ikkje korrekt form. Ein gyldig URL er noko som liknar på dette: "%valid_url_example%". Lag administrator Lag medlem Gjer deg sjølv usynleg Gjer deg sjølv synleg Administrer dine meldingar Diverre har du ikkje tilgang til å sjå medlemslista. Medlemsstatus Medlemer Navn Nytt passord Ingen søknadar Ingen ISO-kodar Denne pakka har ingen parametrar. biletet ditt Ingen %pretty_plural% Ingen tenester ingen Ikkje innlogga Notatar: Merk: på %name% til: (valfri) Val Eller legg inn ein ny brukar eler Passord Innlogginga di ved %system_name%: %account_id_label%: %account_id% Passordet ditt for denne kontoen er nyss endra. Du treng ikkje gjere noko, dette er berre ei melding for å ta vare på sikringa av kontoen din. --------------- Du kan alltid endre passordet ditt ved å gjere følgjande: 1. Logg inn ved %system_name% 2. Klikk på "%pvt_home_name%" lenkje 3. Vel "%password_update_link_text%" Passord endra Rettar rettar Rettar for %name% Gå attende til %home_link%. Bilete Profil Spørsmål Gjer tilgjengeleg igjen Finn att passord Oppfrisk innlogginga Registrer <p> Takk for di registrering ved %system_name%. Ein administrator er varsla. </p><p>Når du er itt godkjent vil du få ein e-post, og då kan du ta til å bruke %system_name%. </p> Forkast Hugs innlogginga på denne datamaskina Ta vekk Fjern alt Be om medlemskap i denne gruppa Be om medlemskap i denne undergruppa Be om medlemskap gå attende til søking Utfør på avmerka Rolle Lagre kommentar Skjermnavn Leit etter eksisterande brukar Security context root Vel eit objekt etter Id: Send e-post til denne brukaren Vis Administrasjon for heile systemet Diverre kan vi ikkje hjelpe deg med passordet du har gløymt. Status Historia bak biletet Historia bak biletet Undergrupper undergrupper undergruppe undergruppe Undergrupper undergrupper Takk. ISO-kodane er ikke lasta inn på denne tenaren. Denne gruppa er stengt. Nye medlemer kan berre få tilgang ved invitasjon. denne undergruppa Brukaren har gått ut av gruppa. For å logge inn, gå til Emne type-spesifikk informasjon OPP opp til %context_name% Oppdater Oppdater passord last opp last opp eit bilete last opp eit anna bilete Last opp bilete Brukarnavn Sidekart for brukaren Ferieinformasjon oppdatert Ferieinformasjonen din ved %site_link% er lasta opp. Velkomen, %user_name% Når du let ein sjekkboks stå tom her, vil denne retten bli teken bort frå dei du no vel dersom dei har hatt denne retten tidlegare. Brukarar som er online no Kven er online Ja, eg er sikker Du er i følgjande grupper: Du kan også lese frå Du kan alltid opne på nytt ved å Du har ikkje administrasjonsrettar for objektet %root% eller nokon av borna Du har ikkje noko bilete enno. Du kan Du har administrasjonsrettar til følgjande objekter: Nett no har du ingen e-postvarsel registrert. Din konto Dine e-postvarsel for diskusjonsfora Biletet ditt Dine %gc_system_name% varsel Du er merka som attende frå ferie ved %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ca_ES.ISO-8859-1.xml0000644000175000017500000006452210727201372025536 0ustar frankiefrankie , o Actualitza informació bàsica Membre de la comunitat %system_name% des de La meva informació El vostre compte en %system_name% s'ha tancat. No, torna'm a %pvt_home_name% Sí, tanca el meu compte, per favor <p>El vostre compte està tancat actualment.</p><p>Si voleu, podem <a href="%restore_url%">tornar a obrir-lo</a>.</p> Compte tancat <p> <font color="red"> <b> El vostre compte està tancat actualment </b></font> <a href="%login_url%">Torneu a entrar-hi</a> per a veure què hi podeu fer. </p&;gt; Aquest compte no està disponible en aquest moment. El vostre compte en %system_name% s'ha tornat a obrir. Benvingut/da. El compte s'ha tornat a obrir Acció Afegeix una aplicació nova Panell de control Administra %subsite_name% Opcions d'administració per a aquest usuari Tipus d'alerta una altra imatge. Resposta Error d'aplicació Aplicacions Aprova en Error intern durant l'autenticació Autoritat Contrasenya errònia Prohibició Informació bàsica Biografia Biografia tipus mime No es permet la recuperació de contrasenyes d'una autoritat local. No es veu la llista de membres Canvia l'idioma Canvia el nivell de privacitat del meu correu electrònic Canvia la contrasenya Canvia contrasenya, correu electrònic, fotografia Revisa la safata d'entrada Fills Trieu un qüestionari de registre de client : Trieu el qüestionari que es mostrarà als usuaris nous..<br>Es pot emprar per dur a terme accions automatitzades (p.ex. afegir usuaris a grups específics, notificar nous registres a persones en concret, etc.). <p>Per favor, confirmeu que voleu tancar el vostre compte en %system_name%. </p> <p> En tancar el compte ja no us enviarem notificacions per correu electrònic, ni apareixereu en les llistes de membres de %system_name%. Tot i això, es conservaran les vostres contribucions a la comunitat, ja que són part de l'historial d'aquesta. </p> <p> Podeu tornar a obrir el compte en qualsevol moment, simplement entrant-hi de nou.</p> Tanca el compte Grup tancat Comentari Comunitats comunitats comunitat Confirma Heu triat una contrasenya nova satisfactòriament. Continua Continua a %pvt_home_name% Nom del país Crea un nou qüestionari de registre de clients Crea un nou %pretty_name% Crea un subsite nou Contrasenya actual <p> El vostre estat de connexió actualment no és visible per a altres usuaris. </p> <p> El vostre estat de connexió actualment és visible per a altres usuaris. </p> Personalitza la pregunta Error de la base de dades Context per defecte Suprimeix DevAdmin Administració del desenvolupador Permisos directes Desactiva Desactivat Domini Correu electrònic Edita qüestionari seleccionat edita comentari Alguns elements no es poden editar, perquè els gestiona %authority_name%. Correu electrònic Permet contacte per mitjà d'un formulari Permet contacte per mitjà d'un formulari Mostra el meu correu electrònic com una imatge Mostra el meu correu electrònic com una imatge Mostra el meu correu electrònic com a text Mostra correu electrònic com a text Aquestes són les vostres dades noves d'entrada: %account_id_label%: %account_id% %password_label%: %password% Per favor, visiteu l'enllaç següent per a canviar la vostra contrasenya ara: %reset_password_url% Gràcies per registrar-vos en %system_name%. Aquí teniu com entrar en %system_url%: %account_id_label%: %account_id% %password_label%: %password% Per favor, visiteu l'enllaç següent per a canviar la vostra contrasenya ara: %reset_password_url% Confirmació de correu No mostrar el meu correu electrònic No mostrar el correu electrònic No disponible No s'ha sol·licitat el correu S'ha sol·licitat el correu Si heu oblidat la vostra contrasenya, la trobareu en %system_name% Benvingut/da a %system_name% Activat Escriviu el nom d'usuari per a començar el procés de recuperació de la contrasenya. Suprimeix la fotografia suprimeix la fotografia Error Error en enviar el correu S'ha produït un error en enviar el correu per a verificar-lo S'ha produït un error en intentar registrar el vostre compte. S'ha produït un error en intentar actualitzar la informació del compte Caduca Nom de l'arxiu Nom Heu oblidat la contrasenya? Freqüència Torna enrere carrega la fotografia de l'usuari carregar la vostra fotografia Atorga Autoritza Ja hi ha un grup amb aquest correu Ja hi ha un usuari amb aquest correu. Ja hi ha un usuari amb aquest nom d'usuari. <p><h3>Informació d'ajuda</h3> Oculta Pàgina principal Si anàreu a Informació actualitzada Convida Codi ISO Llista de codi ISO No s'han carregat els codis ISO No s'han carregat els codis ISO Dóna d'alta en la comunitat Ingressa en %group_name% Ingressa en el subsite Ingressa en aquesta comunitat Ingressa en aquest subsite Paraula clau Cognoms després. Ix de la comunitat Ix del subsite Ix d'aquesta comunitat Ix d'aquest subsite Torna enrere sense afegir cap usuari Entra entra Entra en %system_name% tornant a entrar-hi La pàgina d'entrada ha caducat. Per favor, torneu a registrar-vos. Entrar o registrar-se pàgina d'entrada Ix Ix de %system_name% , podríeu aconseguir més informació sobre un company membre de la comunitat. No us podeu afegir a aquest grup. Llista completa dels codis ISO Continua treballant amb %system_name% Edita un comentari per a la fotografia de %first_names% %last_name% %first_names% %last_name% (%email%) està registrat com a usuari de %system_url% Per als administradors del lloc Autoritza en %name% Aquí teniu l'informe que ha proporcionat la base de dades: Com voleu que el món veja %first_names% %last_name%? Si creieu que la persona encara no té un compte: Si sabeu o penseu que la persona que voleu convidar ja té un compte en aquest sistema: Si necessiteu aquesta funcionalitat, per favor, carregueu acs-reference i ref-countries. Permisos heretats No hauríeu de triar aquesta opció si esteu usant un ordinador compartit d'una biblioteca o centre docent. Qualsevol usuari que empre aquest ordinador d'ara endavant us podria suplantar en la nostra plataforma. Nou registre en %system_url% Observeu que el text en roig davall dels camps d'entrada de cada paràmetre indica que el valor d'aquest paràmetre és anul·lat per una entrada en l'arxiu de paràmetre OpenACS. Tot i que s'aconsella no usar l'arxiu del paràmetre, alguns llocs el necessiten per a proporcionar valors específics als paràmetres independents de les taules apm_parameter. Observeu que podeu eliminar l'adreça de correu i la contrasenya de la memòria de l'ordinador pitjant l'opció "Ix" del vostre portal. %num_children% fills ocults El %portrait_publish_date% vàreu carregar <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> El nostre servidor pot fer que el vostre navegador recorde algunes coses com ara la vostra adreça electrònica i contrasenya. Això us convé perquè, si sou l'únic usuari del vostre ordinador, no ens haureu de repetir cada vegada l'adreça ni la contrasenya. Confirmació de la contrasenya URL de la vostra pàgina personal: Per favor, localitzeu el codi del vostre país entre els que hi ha més avall. Després pitgeu el botó "Torna" del navegador per a tornar al formulari anterior. Per favor, llegiu i seguiu les instruccions d'aquest missatge. Per favor, intenteu <a href="index">tornar a entrar</a> Fotografia de %first_names% %last_name% Els privilegis més elevats en la jerarquia impliquen tots els privilegis inferiors; per exemple, quan es concedeix admin, s'hi afegeixen automàticament la lectura, l'escriptura, etc. Problemes amb l'autenticació La informació de registre per a aquest servei s'acaba d'enviar a %email%. La informació de registre per a aquest servei s'ha enviat a %email%. La vostra sol·licitud de registre s'ha enviat a l'administrador de %system_name% i està en espera d'aprovació. Desant l'adreça de correu i la contrasenya Mostra com ets a tots els usuaris de %system_name%: Ho sentim, però us han expulsat de &system_name% Esteu segur que voleu eliminar la fotografia d'aquest usuari? Esteu segur que voleu eliminar la vostra fotografia? La vostra fotografia no és vàlida en el sistema. S'ha produït un problema durant l'autenticació del vostre compte Aquesta és la imatge que mostrem als altres usuaris en %system_name% Aquest usuari encara no té fotografia. Podeu Aquest usuari ha estat eliminat i expulsat de la comunitat. Per confirmar el vostre registre, aneu a %confirmation_url% Carregueu el vostre arxiu preferit, un JPEG o GIF, des de l'escriptori del sistema de l'ordinador (tingueu en compte que no us podeu referir a una imatge d'Internet; la imatge ha d'estar en la unitat de disc dur de l'ordinador). Carregat: %pretty_date% Carregat: %publish_date% Empreu el botó "Navega... " per a localitzar l'arxiu, i després feu clic en "Obre". Aquest usuari ha introduït una biografia o ha carregat una foto. No us podem trobar (usuari %user_id%) en la taula d'usuaris. Probablement el vostre compte s'ha anul·lat per alguna raó. Hem tingut un problema en processar la vostra entrada. No esperàvem el vostre missatge. Deu tractar-se d'un error. Benvingut/da a %system_name% Què veuen les altres persones quan fan clic en el vostre nom No podeu introduir un signe &lt; en el vostre nom, ja que correspon a una etiqueta HTML i podria crear confusió. No podeu introduir un signe &lt; en els vostres cognoms, ja que correspon a una etiqueta HTML i podria crear confusió. Heu de proporcionar almenys un object_id_on or object_id_two No rebreu cap correu electrònic fins després de %pretty_date%. El vostre correu s'ha confirmat. Ara podeu entrar a %system_name%. El vostre correu s'ha confirmat. Ara heu d'esperar l'aprovació de l'administrador de %system_name%. El vostre correu s'ha confirmat El vostre compte ha caducat. Per favor, torneu a escriure la contrasenya per a continuar treballant. La URL introduïda no té la forma correcta. Un exemple d'URL correcta és "%valid_url_example%". Envia un missatge a: Crea un administrador Crea un membre Ocultar-vos Mostrar-vos Administra la privacitat del correu electrònic dels usuaris Administra les notificacions Ho sentim, però no se us permet veure els membres de la llista. Membre Estat del membre Membres Manca argument Nom Contrasenya nova No hi ha aplicacions No hi ha cap tasca disponible No hi ha codis ISO Aquest paquet no té cap paràmetre. la vostra foto Cap %pretty_plural% Cap servei No s'ha trobat cap usuari amb aquest nom d'usuari res No hi heu entrat Aquesta no és una adreça electrònica vàlida Notes: Avís: en %name% a: En línia (opcional) Opcions O afegir-hi un usuari nou o el Contrasenya La vostra informació d'entrada en %system_name%: %account_id_label%: %account_id% La vostra contrasenya per a aquest compte s'ha modificat recentment. No hi heu de fer res, açò és simplement una notificació per a protegir la seguretat del vostre compte. --------------- En qualsevol moment podeu canviar la vostra contrasenya seguint aquests passos: 1. Entreu a %system_name% 2. Feu clic en l'enllaç "%pvt_home_name%" 3. Trieu "%password_update_link_text%" La contrasenya s'ha canviat La vostra contrasenya s'ha de canviar regularment. Per favor, canvieu-la ara. Les contrasenyes no coincideixen Aquest permís no es pot eliminar. Permisos permisos Permisos per a %name% Per favor, torneu a %home_link%. Foto S'ha produït un problema en autenticar el compte. Probablement la base de dades conté usuaris sense member_state. Perfil Pregunta Rehabilita Recupera la contrasenya Refresca l'entrada Personalitza el qüestionari de registre d'usuari Registra <p> Gràcies per registrar-vos en %system_name%. La vostra sol·licitud s'ha notificat a un administrador. </ p> <p> Una vegada que se us accepte, rebreu un missatge de correu electrònic i podreu tornar per a començar a usar %system_name%. </ p> Refusa Recordar la meua contrasenya en aquest ordinador Suprimeix Suprimeix-ho tot Sol·licita l'entrada com a membre en aquesta comunitat Sol·licitar l'entrada com a membre en aquest subsite Sol·licita l'entrada torna a la sol·licitud Revoca els comprovats Perfil Desa el comentari Àlies Aquest àlies ja està en ús. Cerca un usuari existent Context de seguretat Selecciona un objecte per Id: Envia un missatge a aquest usuari Envia'm una còpia: Estableix la tasca per a registre Mostra Administració del lloc Ho sentim, però no us podem ajudar amb la contrasenya que heu oblidat. Estat Text que acompanya la fotografia Text que acompanya la fotografia Subcomunitats subcomunitats subcomunitat subsite Subsites subsites Us heu autenticat correctament, però encara no teniu cap compte en %system_name%. Gràcies. Els codis ISO no estan carregats en aquest servidor. Aquest grup està tancat. Els nous membres no hi poden accedir sense invitació. aquest subsite Aquest usuari ha deixat la comunitat. Reviseu la vostra safata d'entrada. En els propers minuts haurieu de trobar-hi un missatge de %system_owner% amb instruccions sobre Tema Informació específica Correu desconegut AMUNT torna a %context_name% Actualitza Actualitza la contrasenya carrega Carrega una foto carrega una foto nova Carrega una foto Foto de l'usuari Fotos de l'usuari Perfil de l'usuari Perfils de l'usuari Nom d'usuari No s'ha trobat cap usuari amb el nom '%username%' per a l'autoritat %this_authority% El nom d'usuari és necessari Mapa del lloc de l'usuari Informació sobre les vacances actualitzada La informació sobre les vostres vacances en %site_link% s'ha actualitzat. Benvingut/da, %user_name% Quan deixeu buida una casella de verificació, el privilegi es revocarà del grup que heu triat en cas que se li hagen concedit anteriorment. Usuaris connectats actualment Qui hi ha connectat Sí, n'estic segur/a Pertanyeu als grups següents: També podeu navegar des del Sempre ho podeu tornar a obrir amb No teniu drets d'administració de l'objecte %root% ni sobre els seus fills Encara no teniu una foto. Podeu Teniu drets d'administració en els objectes següents: Actualment no teniu avisos de correu activats. El vostre compte Avisos del fòrum de debat La vostra fotografia Els vostres %gc_system_name% avisos Teniu marcada la tornada de les vacances en %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ja_JP.utf-8.xml0000644000175000017500000000407610727201372025305 0ustar frankiefrankie ã‚ãªãŸã«ã¤ã„㦠回答: at パスワードエラー 基本情報 パスワードã®å¤‰æ›´ å—ä¿¡ç®±ã®ç¢ºèª å­ä¾› 確èª: ç¾åœ¨ã®ãƒ‘スワード: 質å•ã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º ç›´æŽ¥æ¨©é™ ãƒ¡ãƒ¼ãƒ«ã®ç¢ºèª ãƒ¡ãƒ¼ãƒ«ã¯æœªç™»éŒ²ã§ã™ メールé€ä¿¡ã‚¨ãƒ©ãƒ¼ 付与 権é™ã®ä»˜ä¸Ž %group_name% ã«å‚加 ログイン ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å‚加ã§ãã¾ã›ã‚“。 %first_names% %last_name% (%email%) 㯠%system_url% ã®ãƒ¦ãƒ¼ã‚¶ã¨ã—ã¦ç™»éŒ²ã•れã¾ã—㟠%name% ã¸ã®æ¨©é™ã®ä»˜ä¸Ž 権é™ã®ç¶™æ‰¿ 図書館や学校ãªã©ã§å…±æœ‰ã®ã‚³ãƒ³ãƒ”ュータを使用ã—ã¦ã„ã‚‹å ´åˆã¯ã€ã“ã®ã‚ªãƒ—ションã«ã¯ãƒã‚§ãƒƒã‚¯ã—ãªã„ã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚ã“ã®ã‚³ãƒ³ãƒ”ュータã®ã“れ以é™ã®ãƒ¦ãƒ¼ã‚¶ã¯èª°ã§ã‚‚ã€ã“ã®ã‚µã‚¤ãƒˆã§ã‚ãªãŸã«ãªã‚Šã™ã¾ã™ã“ã¨ãŒã§ãã¦ã—ã¾ã„ã¾ã™ã€‚ %system_url% ã¸ã®æ–°è¦ç™»éŒ² ä¿å­˜ã—ãŸãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã¨ãƒ‘スワードã¯ã€ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã®"ログアウト"ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’é¸æŠžã™ã‚‹ã“ã¨ã§å‰Šé™¤ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ar_LB.utf-8.xml0000644000175000017500000006235110727201372025301 0ustar frankiefrankie أو حدث المعلومات الاساسية العضو ÙÙŠ مجموعة %system_name% منذ عَنك حسابك ÙÙŠ %system_name%قد تم إغلاقه %pvt_home_name%لا ارجعني الى نعم الرجاء إغلاق حسابي <p>حسابك مغلق حالياً.</p> <p>إذا ترغب، نحن يمكننا <a href="%restore_url%"> إعادة ÙØªØ­ حسابك</a>.</p> <p> <font color="red"> <b> حسابك مغلق حاليا </b> </font> <a href="%login_url%"> أدخل </a> مرة اخرى لتحدد ماذا باستطاعتك عمله </p&;gt; حسابك ÙÙŠ %system_name% قد تم إعادة ÙØªØ­Ù‡ قد تم إعادة ÙØªØ­ الحساب ØªØµØ±Ù Ø¥Ø¶Ø§ÙØ© طلب جديد لوحة التحكم مدبر %subsite_name% خيارات إدارية لهذا المستخدم من النوع المنتبه صورة أخرى الجواب: خطأ ÙÙŠ التطبيق التطبيقات مواÙÙ‚ عÙنْدَ صلاحية كلمة٠السر سيئة٠منع المعلومات الأساسية سيرة استعادة كلمة سرّ من السّلطة المحلّيّة غير Ù…ØªÙˆÙØ±Ø©. لاتستطيع أن ترى لائحة الأعضاء تغير اللغة غيّرْ كلمةَ سري تغير كلمة السر,البريد,الصورة Ø¥ÙØ­ØµÙ’ صندوقَ إستلامكَ Ø§Ù„ØªÙØ±Ø¹Ø§Øª <p> الرجاء أكد رغبتك ÙÙŠ تسكير حسابك لدا %system_name%. </p> <p> تسكير الحساب يعني أنه لن يكون ÙÙŠ مقدورك إرسال ملاحظات بريدية ولن تظهر ÙÙŠ لاءحة الاعضاء لدا %system_name%. Ùˆ لكنه سيتم Ø§Ù„Ø§Ø­ØªÙØ§Ø¸ بمساهماتك كجزء من تاريخ مساهمات المجموعة. </p> <p> لاحظ أنه بإمكانك إعادة ÙØªØ­ حسابك عند دخولك مرة أخرى </p> أغلق حسابك مجموعة مغلقة تعليق مجتمعات مجتمعات مجتمع أَكّدْ: لقد قمت بنجاح إختيار كلمة سر جديدة تابع تابع إلى %pvt_home_name% إسم الدولة أنشئ جديد%pretty_name% أنشئ موقع جديد كلمة٠السر الحالية: <p> وضعك الحالي أنه لن تشاهد من قبل الاخرين. </p> <p> وضعك الحالي أنه ستشاهد من قبل الاخرين. </p> ÙØµÙ‘لْ سؤالاً خطأ ÙÙŠ قواعد البيانات محتويات الأصلية إحذ٠إدارة المطورين إدارة المطورين الأذون المباشرة ÙØµÙ„ Ù…ÙØµÙˆÙ„ مجال البريد الالكتوني تعديل التعلبقات بعض العناصر لا يمن تغيرهالانها من إختصاص %authority_name%. البريد الإلكتروني هذه المعلومات الجديدة لدخولك %account_id_label%: %account_id% %password_label%: %password% لتغير كلمة السر الرجاء زيارة الموقع التالي ألان %reset_password_url% شكرا لك لتسجيلك لدى %system_name%. هذة هي المعلومات عن كيÙية دخولك الى %system_url%: %account_id_label%: %account_id% %password_label%: %password% لتغير كلمة السر الرجاء زيارة الموقع التالي ألان %reset_password_url% تأكيد٠بريد إلكتروني البريد الإلكتروني غير مطلوب كلمة السر التي نسيتها لدى %system_name% مرحبا بك ÙÙŠ %system_name% Ù…ÙØ¹Ù„ أدخل اسم المستخدم الخاص بك لكي تبدأبعملية إسترجاع كلمة السر حذ٠البورتريه حذ٠البورتريه خطأ حصلَ خطأً ÙÙŠ إرسال البريد إلكتروني إنتهاء الصلاحية اسم المل٠الإسم الاول هل نسيت كلمة السر التردد الرجوع إذهب لتحميل بورتريه المستخدم إذهب لتحميل بورتريه الخاص بك واÙÙ‚ واÙÙ‚ على الإذْن Ø¥Ø®ÙØ§Ø¡ Ø§Ù„ØµÙØ­Ø©Ø§Ù„رئيسية إذا كنت تحديث المعلومات إدعو ISO رمز ISO لائحة رموز رموز ISO غير محملة رموز ISO غير محملة إنظم الى مجتمع إنضَمَّ إلى %group_name% إنظم الى موقع إنظم الى هذا المجتمع إنظم الى هذا الموقع كلمة رئيسية الشهرة Ùيما بعد ترك المجتمع ترك الموقع ترك هذا المجتمع ترك هذا الموقع الرجوع من غير Ø¥Ø¶Ø§ÙØ© مستخدمين دخول دخول أدخل الى %system_name% الرجوع الى الدخول ØµÙØ­Ø© الدخول قد انتهى وقتهاالرجاء الدخول من جديد للدخول أو للتسجيل ØµÙØ­Ø© الدخول خروج خروج من %system_name% ستتمكن من الحصول على معلومات أكثر من أعضاء المجتمع الذي تنتمي إليه لا ÙŠÙمكن الإنضمام إلى هذه المجموعة. المجموعة الكاملة لرموز ISO الاستمرار بالعمل ب%system_name% لتعديل الملاحظات لبورتريه %first_names% %last_name% (%first_names% %last_name%(%email% مسجّل كمستخدم ÙÙŠ %system_url% الادارة العامة للموقع إمنح الإذن على %name% هذا تقرير قاعدة البيانات كي٠تحب أن يراك العالم %first_names% %last_name%? إذا كنت لا تعتقد أن هذا الشخص له حساب حالي إذا كنت تعتقد أو تعلم أن المستخدم الذي تريددعوته له حساب على هذا النظام إذا أردت هذهالوظائ٠الرجاء تحميلacs-reference ref-countriesÙˆ Ø§Ù„Ø±ÙØ®ØµÙ المَوْرÙوثة٠هي ستكون Ùكرة سيئّة جدا لإختيار هذا الخيار إذا أنت تستعمل كمبيوتر مشترك ÙÙŠ مكتبة أو مدرسة. أيّ مستعمل لاحق لهذا الكمبيوتر سيكون قادر على التنكّر بشخصك Ùˆ الدخول على خدمتنا التسجيل٠الجديد٠ÙÙŠ %system_url% ملاحظة الكتابة التي لونها أحمر Ùˆ الموجودة أسÙÙ„ المدخلات قد تم تعدبلهامن قبل مدخلة ÙÙŠOpenACSمل٠المدخلات لاحظ أنّك يمكن أن تمسح عنوان بريد إلكترونيّ Ùˆ كلمة السّرّ المحÙوظان باختيار خيار"خروج" من مساحة عملك. Ø£Ø·ÙØ§Ù„ مخÙية %num_children% ÙÙŠ %portrait_publish_date%ØŒ لقد أرسلت، <a href="/user/portrait/">%portrait_title%</a> خادمنا يستطيع إخبار متصÙّحك لتذكير بعض الأشياء، مثل عنوان بريدك الإلكتروني وكلمة سرك. هذا ملائم لك لأن، إذا أنت الشخص الوحيد الذي يستعمل حاسوبك، أنت لا يجب أن تستمرّ بإخبارنا عنوان بريدك الإلكتروني وكلمة سرك. تأكيد٠كلمة٠سر: موقع Ø§Ù„ØµÙØ­Ø© الرئيسية٠الشخصيةÙ: الرجاء إختبار Ø´ÙØ±Ø© دولتك من الائحة التي ÙÙŠ الاسÙÙ„ ثم استخدم كبسة الرجوع التي على Ø§Ù„Ù…ØªØµÙØ­ للعودة إلى Ø§Ù„ØµÙØ­Ø© السابقة من ÙØ¶Ù„Ùƒ اقرأ Ùˆ اتّبع التّوجيهات ÙÙŠ هذا البريد الإلكترونيّ. من ÙØ¶Ù„Ùƒ حاول <a href="index">الدخول</a> مجدداً البورتريه Ù„%first_names% %last_name% الصلاحيات الموجودة ÙÙŠ أعلى الهرم تلغي التي أسÙلها المشكلة بالتّوثيق معلومات٠تسجيل٠لهذه الخدمة٠قَدْ Ø£ÙØ±Ø³Ù„تْ إلى %email%. معلومات٠تسجيل٠لهذه الخدمة٠قَدْ Ø£ÙØ±Ø³Ù„تْ إلى %email%. طلب تسجيلك قد Ø¹ÙØ±Ùضَ إلى مدير %system_name%. مازال ينتظر المواÙقة تذكّر هذا العنوان Ùˆ كلمة السر؟ أظهر لكلّ الآخرين ÙÙŠ %system_name% كم أنت وسيم آس٠لكنّه يبدو أنّك قد Ø­ÙØ¸Ùرْتَ من %system_name%. هل أنت متأكد من إلغاء بورتريه هذا المستخدم هل أنت متأكد من إلغاء بورتريه الشخصي لك صورتك ÙÙŠ هذا النظام غير مقبولة الرجاء كان هناك مشكلةَ بالتّصديق على حسابك هذة الصورة هي التي ستعرض على مستخدمي%system_name% هذا المتخدم لا يوجد له بورتريه بعد , بإمكانك هذا المستخدم قد تم منعه ومسحه من هذا المجتمع لتَأكيد تسجيلÙÙƒÙŽØŒ رجاءً إذهبْ %confirmation_url% لتحميل ملÙÙƒ Ø§Ù„Ù…ÙØ¶Ù„ أوالصورة الممسوحة من سطح المكتب الخاص بك الرجاء الانتباه أن هذه الصورة يجب ان تكون موجودة على ذاكرة جهازك الصلبة تم تحميل %pretty_date% تم تحميل %publish_date% إستخدم كبسة البحث للصول إلى المل٠ومن ثم إضغط علىكبسة Ø§Ù„ÙØªØ­ المستخدم ادخل سيرته الذاتية او حمل معلوماته الشخصية لا نستطيع Ø¥ يجادك %user_id% على لائحة المستخدمين ربما قد تم الغاءك لسبب ما توجد مشكلة أثناء معالجة مدخلاتك نحن لم نكن ننتظر بريدك الإلكتروني. يجب أن يكون هناك بعض الخطأ. أهلاً ÙÙŠ %system_name% الذي سيشاهده الاخرين عند الضغط على اسمك أنت لا يمكن أن تختار &lt; ÙÙŠ اسمك الأول لأنه سيبدو مثل بطاقة إتش تي إم إل Ùˆ سيوشوش على مستخدمين آخرين. أنت لا يمكن أن تختار &lt; ÙÙŠ شهرتك لأنه سيبدو مثل بطاقة إتش تي إم إل ويشوّش مستخدمين آخرين. لن تتمكن من الحصول على بريد الكتروني لغاية بريدكَ الإلكتروني Ø£Ùكّد.أنت ÙŠÙمكنك أنّ ØªÙØ³Ø¬Ù‘ل٠الآن ÙÙŠ %system_name%. بريدكَ الإلكتروني Ø£Ùكّد.أنت الآن ÙÙŠ الإنتطار المواÙقة من مدير %system_name%. بريدك الإلكتروني أكّدْ لقد انتهت صلاحية دخولك, الرجاء إدخال كلمة السر للمتابعة موقعك ليس لديه الشكل الصحيح. الموقع الصحيح سيكون شيء مثل \"%valid_url_example%\"." إنشئ مدير إنشئ عضو إجعل Ù†ÙØ³Ùƒ غير مشاهد للاخرين إجعل Ù†ÙØ³Ùƒ مشاهد للاخرين تحكم بتعليقاتك عذرا لن تستطيع مشاهدة لائحة الأعضاء حالة العضو أعضاء إسم: كلمة السر الجديدة: لا يوجد تطبيقات لا بوجد رمز ISO هذه الحزمة لا يوجد لها عناصر صورتكَ لا يوجد %pretty_plural% لا يوجد خدمات لا أحد غير داخل ملاحظات ملاحظة ÙÙŠ %name% إلى إختياري إختيارات أو أض٠مستخدم جديد أو ال كلمة السّرّ: معلومات دخولك الى %system_name%: %account_id_label%: %account_id% كلمة سرك لهذا الحساب تغيرت حديثًا. غير متوجب عليك أن ØªÙØ¹Ù„ شيئاً، هذه الرسالة بشكل بسيط تبليغاً لي حماية أمن حسابك. --------------- أنت دائماً يمكنك تغيير كلمة سرك Ø¨ÙØ¹Ù„ الخطوات التالية: 1- إدخلْ الى %system_name% 2- إنقرْ على "%pvt_home_name%" 3- إخترْ "%password_update_link_text%" كلمة السر تغيرت الصلاحيات الصلاحيات الصلاحيات Ù„ %name% الرجاء الرجوع إلى %home_link%. بورتريه المل٠الشخصي السؤالÙ: إعادة ØªÙØ¹ÙŠÙ„ إسترجع كلمة السر تحديث الدخول سجلْ <p> شكرالك لتسجيلك لدى %system_name%. سيتم إبلاغ المدير بطلبك . </p> <p> عندما تم الواÙقة سيتم بعث رسالة إلكترونيةلك بأنه بإمكانك إستخدام %system_name%. </p> Ø£Ø±ÙØ¶ Ø¥Ø­ÙØ¸ إسم دخولي علىهذا الحاسوب أزل Remove All أطلب عضوية هذا المجتمع أطلب عضوية هذا الموقع أطلب عضوية العودة للتطبيق الإلغاء المختارين دور Ø¥Ø­ÙØ¸ التعليقات إسم الشاشة إبحث عن مستخدم موجود حماية محتويات الاصل إختيار شئ من خلال Id أرسل رسالة الكترونية إلى هذا المستخدم عَرْض ألاداره العامه لموقع Ù„Ù„Ø£Ø³ÙØŒ لنّ نستطيع مساعدتك ÙÙŠ كلمة سرك المنسية. الحالة القصة خل٠الصورة القصة خل٠الصورة المجتمعات Ø§Ù„ÙØ±Ø¹ÙŠØ© المجتمعات Ø§Ù„ÙØ±Ø¹ÙŠØ© المجتمع Ø§Ù„ÙØ±Ø¹ÙŠ Ø§Ù„Ù…ÙˆÙ‚Ø¹ Ø§Ù„ÙØ±Ø¹ÙŠ Ø§Ù„Ù…ÙˆØ§ قع Ø§Ù„ÙØ±Ø¹ÙŠØ© الموا قع Ø§Ù„ÙØ±Ø¹ÙŠØ© .شكرًا رمز ISO لم يتم تحميلها على هذا الخادم هذه المجموعة مغلقة الاعضاء الجدد يستطيعوا الانظمام Ùقط من خلال الدعوة هذا الموقع Ø§Ù„ÙØ±Ø¹ÙŠ Ù‡Ø°Ø§ المستخدم ترك المجتمع للدخول إذهب إلى الموضوع معلومات عن نوعية محددة Ùوق إلى حدّ %context_name% تّحديث تجديد٠كلمة السر تحميل أرسلْ بورتريه تحميل أو تغير بورتريه تحميل بورتريه إسم المستخدم User's Site Map معلومات الاجازة قد تم تحديثها المعلومات الخاصة بإجازتك قد تم تحديثها أهلا %user_name% عندما تترك صندوق الاجابة ÙØ§Ø±ØºØ§ سيتم إلغاء هذا الحق الممنوح من المجموعة المختارة الستخدمين المجودين على الخط حاليا من موجود على الخط حاليا نعم أنا متاكد أنت ÙÙŠ هذه المجموعات تستطيع أيضا Ø§Ù„ØªØµÙØ­ من تستطيع دائما إعادة ÙØªØ­Ù‡Ø§ بواسطة لا تحمل صلاحيات المدير لهذا %root% أو أي من ØªÙØ±Ø¹Ø§ØªÙ‡ لأ تملك بورتريه بعد لكنك تستطيع ذلك تحمل صلاحيات المدير لهذه الاشياء حاليا ليس لديك نظام إنذار وجود رسائل الكترونية حسابك إنذارات ØµÙØ­Ø© الحوار الخاصة بك بورتريه الخاص بك انذاراتك على %gc_system_name% لقد تم وضع علامة بانه قد رجعت من الاجازة openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.pt_PT.ISO-8859-1.xml0000644000175000017500000001515110727201372025604 0ustar frankiefrankie Sobre Si <p>A sua conta encontra-se actualmente fechada.</p> <p>Se desejar, podemos <a href="%restore_url%">reabrir a sua conta</a>.</p> Resposta: em Senha Incorrecta Informação Básica Recuperação de senha da autoridade local não é suportado. Mudar a minha Senha Verifique a Sua Caixa de Entrada Filhos Confirmar: Senha Actual: Personalizar Pergunta Permissões Directas Email Confirmação do Email Email não Solicitado Erro ao enviar correio Primeiros nomes Conceder Conceder Permissão Adira a %group_name% último nome Log In Não pode aderir a este grupo. %first_names% %last_name% (%email%) registado como um utilizador do %system_url% Conceder Permissão em %name% Permissões Herdadas Será uma má ideia escolher esta opção se está a utilizar um computador partilhado numa biblioteca ou escola. O próximo utilizador desta máquina será capaz de utilizar o nosso serviço fazendo-se passar por si. Novo registo em %system_url% Note que pode apagar o seu endereço de email e senha guardados ao escolher a opção "log out" no seu espaço de trabalho. %num_children% Filhos Ocultados Em %portrait_publish_date%, fez o carregamento de <a href="/user/portrait/">%portrait_title%</a> O nosso servidor pode dizer ao seu navegador para recordar certas coisas, tais como o seu endereço de email e senha. Isto é conveniente para si porque, se for a única pessoa que utiliza o seu computador, não terá de estar sempre a dizer-nos o seu endereço de email e senha. Confirmação da Senha: URL da Página Pessoal: Por favor leia e siga as instruções presentes neste email. Por favor tente fazer o <a href="index">log in</a> novamente Problema com a autenticação Informação de registo para este serviço acabou de ser enviada para %email%. Informação de registo para este serviço foi enviada para %email%. O seu pedido de registo foi submetido para o administrador de %system_name%. Está ainda á espera de aprovação. Guardando endereço de email e senha Mostre a toda a gente em %system_name% o seu grande visual: Desculpe mas parece que foi banido de %system_name%. Houve um problema com a autenticação da sua conta Para confirmar o seu registo, por favor vá a %confirmation_url% Não estávamos á espera do seu email. Deve haver algum engano. Bem vindo a %system_name% Não pode ter um &lt; no seu primeiro nome porque irá parecer-se com uma etiqueta HTML e confundir outros utilizadores. Não pode ter um &lt; no seu último nome porque irá parecer-se com uma etiqueta HTML e confundir outros utilizadores. O seu email foi confirmado. Pode agora entrar em %system_name%. O seu email foi confirmado. Você está agora esperando a aprovação por parte do administrador de %system_name%. O seu email está confirmado O seu URL não tem o formato correcto. Um URL válido tem de ser algo como \"%valid_url_example%\"." Nome: Nova Senha: o seu retrato nenhum Senha: A sua informação do login em %system_name%: %account_id_label%: %account_id% A sua senha para esta conta foi alterada recentemente. Não precisa de fazer nada, esta mensagem é uma simples notificação para proteger a segurança da sua conta. ---------------Pode sempre alterar a sua senha fazendo o seguinte: 1. Fazer o login para %system_name% 2. Clicar na ligação "%pvt_home_name%" 3. Escolher "%password_update_link_text%" Senha alterada Permissões Permissões para %name% Pergunta: Recuperar Senha Registar Revogação Verificada Nome no ecrã Mostre Desculpe, não podemos ajudá-lo com a sua senha esquecida. Obrigado. até %context_name% Actualizar Actualizar Senha carregar um retrato Nome de utilizador O seu Retrato openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.nl_ZA.ISO-8859-1.xml0000644000175000017500000006704511056027177025577 0ustar frankiefrankie , of Basisinligtinge bywerk Lid van %system_name% sinds Iets oor myself Hierdie rekening op %system_name% is gesluit. Nee, na %pvt_home_name% teruggaan Ja, my hef my registrasie op <p>Hierdie rekening is gesluit.</p> <p>Volg hierdie <a href="%restore_url%">skakel om die registrasie te heropen</a>.</p> Rekening is gesluit <P><FONT color=´red´><B>Hierdie rekening is momenteel gesluit.</B></FONT> By <A href=´%login_url%´>´n volgende aanmelding</a> sal aangegeef word hoe verder gehandel moet word.<P> Hierdie rekening is op dit moment nie beskikbaar nie. Die registrasie op %system_name% is heropen. Welkom terug! Rekening heropen Aksie Voeg toe voeg folder toe Voeg nuwe toepassing toe Voeg hierdie gebruiker toe Voeg gebruiker toe Voeg gebruikers to Beheer Beheer %subsite_name% beheer Administratiewe opsies vir hierdie gebruiker Kennisgewingstipe 'n andere foto. Antwoord: Fout in toepassing Toepassinge Goedkeur op Interne fout tydens outentikasie Identiteitscontroleur Verkeerde wagwoord Uitsluiten Basisinligtinge Biografië Biografie Mime-tipe van biografie Mime-tipes van biografie Agterhaling van 'n wagwoord via die lokale identiteitskontroleur (die databank) word nie ondersteun nie. Verberg ledelys Stel taal in Verander my e-posprivaatheidsvlak Verander my wagwoord verander wagwoord, e-pos, portretfoto Die wagwoord is naar die by ons bekende e-posadres gestuur onderliggende elemente Kies 'n aangepaste registrasievraag: Kies die vraag wat aan nuwe gebruikers getoon word.<BR>Dit kan gebruik word om geoutomatiseerde aksies (byvoorbeeld gebruikers toevoeg aan bepaalde groep, bepaalde mense op die hoogte bring van nuwe registrasies, en gaan so verder.). <P>Bevestig dat die registrasie op %system_name% gesluit moet word.<P>Sluiting van die registrasie beteken dat ons nie langer kennisgewinge kan stuur nie en ons die registrasie ook nie meer in die ledenlys op %system_name% kan toon nie. Alle bydrae aan die gemeenskap, sal inteendeel bewaard blyf; hierdie maak immers deel uit van die geskiedenis van hierdie gemeenskap.<P>Let op: Die rekening kan op ´n willekeurig moment weer geopen word. Sluit my rekening Beslote groep Opmerking Gemeenskappe Gemeenskappe gemeenskap Bevestig Jou ingeef van 'n nuwe wagwoord is suksesvol afgerond. Deurgaan Na %pvt_home_name% deurgaan Landnaam Maak aan Maak 'n nuwe aangepaste registrasievraag aan: nuwe %pretty_name% aanmaken nuwe subsite aanmaak Huidig wagwoord: <P><h2>My onlinestatus:</h2></p><p> Andere gebruikers kan momenteel <i>nie</i> sien dat ek aanlyn is nie.</p> <P><h2>My aanlynstatus:</h2></p><p> <ul><li>Andere gebruikers kan momenteel sien dat ek aanlyn is. </li></ul></p> Vraag aanpas Databankfout standaardkontekst Verwyder verwyder Administrasie (ontwikkelaar) Administrasie vir ontwikkelaars Directe regte Uitskakel Uitgeskakel Domein E-pos Wysig Wysig gekose vragelys bewerk opmerking Wysig opsies Bepaalde elemente kan nie bewerk word nie, omdat hulle onder die beheer van %authority_name% vallen. E-pos Staan toe kontak met my te lê via 'n formulier Staan kontak toe met 'n formulier Toon my e-posadres as 'n beeld Toon e-pos as 'n beeld Toon my e-posadres as teks Toon e-pos as teks Hierby die benodigde inligtinge om jou opnuut aan te meld: %account_id_label%: %account_id% %password_label%: %password% Besoek die volgende skakel en verander die wagwoord direk: %reset_password_url% Bedank vir die inskrywing op %system_name%. Met die volgende inligtinge kan u toegang verkryg tot %system_url%: %account_id_label%: %account_id% %password_label%: %password% Besoek assublief die volgende skakel en verander die wagwoord: %reset_password_url% E-posbevestiging Toon my e-posadres nie Toon e-pos nie Nie beskikbaar nie E-pos nie aangevraag nie E-pos vereis Die vergete wagwoord van %system_name% Welkom by %system_name% Ingeskakel Typ die eigen gebruikersnaam in sodat het bybehorende wagwoord kan agterhaal word. Portretfoto wis portretfoto wis Fout Fout by versending van die e-pos Daar is 'n fout opgetree tydens het versturing van die e-pos vir die e-postoetsing. Daar is 'n fout opgetree tydens die aanmaak van 'n rekening vir jou. Daar is 'n fout opgetree tydens die bywerking van die rekeninginligtinge. Verval Leêrnaam Voornaam wagwoord vergeet? Frekwensie Ga terug 'n portretfoto van hierdie gebruiker aanbied 'n portretfoto van my aanbied Toekennen Regte toeken Ons het al 'n groep met hierdie e-posadres. Ons het al 'n gebruiker met hierdie e-posadres. Ons het al 'n gebruiker met hierdie gebruikersnaam. <p><h3>Helpinligtinge</h3> Verbergen My webwerf As jy sou Inligtinge bygewerk Installeer taalareas Uitnodige ISO-kode Lyst met ISO-codes ISO-kodes is nie geïnstalleer nie ISO-kodes is nie geïnstalleer nie By gemeenskap inskryf By %group_name% inskryf By subsite inskryf By hierdie gemeenskap inskryf By hierdie subsite inskryf Sleutelwoord Agternaam &nbsp; Gemeenskap verlaat Deelwerf verlaat Hierdie gemeenskap verlaat Hierdie subsite verlaat Terug, geen gebruikers toevoeg nie Aanmeld aanmeld Aanmeld by %system_name% opnieuw aanmelden Hierdie aanmeldsessie het verloop. Graag opnieuw aanmelding. Aanmeld of inskryf aanmeldbladsy Meld af By %system_name% afmeld , dan kan meer inligting oor andere gebruikers verkryg word. Voeg aangeduidde gebruikers toe aan gebruikers wat regte het op jou voorwerp. By hierdie groep is inskryf nie moontlik nie Komplete lys met ISO-kodes Op %system_name% doorwerke Nie erf nie van %parent_object_name% Byskrif bewerk van die portretfoto van %first_names% %last_name% %first_names% %last_name% (%email%) het sig ingeskryf as gebruiker op %system_url% Vir hoofbeheerders Regte voor %name% toeken Dit is die berig van die databank: Hoe dien die wereld %first_names% %last_name% te zien? Indien hierdie persoon hier zeker geen rekening het: Indien hierdie persoon hier wel of moontlyk wel 'n rekening het: Indien hierdie funksie nodig is, dien eerst acs-reference en ref-countries geaktiveer te word. Erf van %parent_object_name% Erf regte van die %parent_object_name% Geërfde regte Dit is 'n baie slegte idee om hierdie opsie te gebruik indien hierdie rekenaar wordt gedeel met andere; soos in 'n biblioteek of skool. Elke volgende gebruiker van hierdie rekenaar kan hom dan immers toegang tot uw registrasiegegewens verskaf. Nuwe inskrywing op %system_url% Rooi teks onder die invoervelde van parameters geef aan dat die waarde van hierdie parameter oorskryf word deur 'n waarde in die parameterlêer van OpenACS. Die gebruik van die parameterlêer wordt afgeraai maar sommige werve het dit nodig vir die instelling van instansiespesifieke parameterwaardes, wat onafhanklik is van waardes in die apm_parameter-tabelle. Het opgeslagen e-posadres en het wagwoord kan worden gewist door op "afmelden" te klikken. %num_children% verborgen onderliggende elementen <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> is op %portrait_publish_date% in die database opgenomen. Ons bediener kan blaaiers opdraag om dinge te onthou, soos 'n e-posadres en wagwoord. Dit het as voordeel dat 'n e-posadres en wagwoord niet steeds opnuut ingevoer hoef te word. Dit is egter alleen veilig as mens die rekenaar nie met andere deel nie. wagwoordbevestiging URL van persoonlike webwerf: Kies die eie landkode uit die onderstaande lys en gebruik vervolgens die knop "Terug" van die blaaier om naar die vorige formulier terug te gaan. Lees en volg die instruksies in hierdie e-pos assublief. Probeer nogmaals om <a href="index">aan te meld</a> Portretfoto van %first_names% %last_name% Hoëre privileges omvat alle onderliggende privileges. Byvoorbeeld, toekennening van adminregten impliseer ook die toekennen van read- en write-regte. Identiteitskontrole is misluk Die inskryfgegewens vir hierdie diens is verstuur aan %email%. Die inskryfgegevens vir hierdie diens is verstuur aan %email%. Het inskryvingsverzoek is verzonden aan die beheerder van %system_name%. We wagten nu op toestemming. e-posadres en wagwoord worden opgeslagen Laat aan iedereen op %system_name% sien hoe goed jy daaruit sien: Die toegang is geweiger. Waarskynlik is hierdie rekening uitgesluit van %system_name% en gedeaktiveer. Stop met erving van regte van die %parent_object_name% Die portretfoto van hierdie gebruiker egt verwyder? Jou eie portretfoto eg verwyder? Hierdie foto kan nie word getoon nie. Daar is geen gebruikers nie wat nog geen toegang op dit voorwerp het nie. Die identiteitskontrole by dit registrasienummer geeft problemen Dit is die foto die we aan andere gebruikers op %system_name% tonen Hierdie gebruiker het nog geen portretfoto. Er kan Hierdie gebruiker is uitgesloten en verwyderd uit hierdie gemeenskap. Ga naar %confirmation_url% om die inskryving te bevestigen. Bied 'n favoriete leêr van u eie rekenaar aan. Dit mag 'n afgetaste JPEG- of GIF-leêr wees. Daar kan helaas geen verwysing gemaak word na 'n leêr ergens op die internet. Opgeslaan: %pretty_date% Opgeslaan: %publish_date% Gebruik die knop "Blaaier" om 'n leêr te vind en kliek dan op "Open". Hierdie gebruiker het 'n biografie of portret opgeslaan Ons kan registrasienummer %user_id% nie in die gebruikerstabel vind nie. Kan dit wees dat dit registratienummer verwyder is? Daar was &acute;n probleem by het verwerken van die invoer. ons het hierdie e-pos niet verwag nie. Daar moet &acute;n vergissing in die spel wees. Welkom by %system_name% Wat andere gebruikers sien as hulle op my naam kliek &lt; mag niet in &acute;n voornaam worden gebruikt. Het lykt op &acute;n HTML tag en kan andere gebruikers in verwarring brengen. &lt; mag niet in &acute;n agternaam worden gebruikt. Het lykt op &acute;n HTML tag en kan andere gebruikers in verwarring brengen. Jy moet op sy minst 'n object_id_on of object_id_two opgeef. E-postoesending blyf gestaak tot na %pretty_date% Die e-mail is bevestig. Aanmelden op %system_name% is nu moontlik. Die e-mail is bevestig. Ons is nu in afwagting van toestemming door die beheerder van %system_name%. Die e-pos is bevestig. Hierdie aanmeldsessie is verlopen. Graag opnieuw aanmeld. Hierdie URL het niet die juiste opmaak. &acute;n Geldige URL sien daar as volgt uit "%valid_url_example%". Stuur 'n berig aan: Beheerder maak Lid maak Maak my onsigbaar Maak my sigbaar Beheer e-posprivaatheid van gebruikers Stel my kennisgewinge in Sorry, die ledelys mag nie getoon word nie. Lid Lidstatus Lede Ontbrekende parameter koppel aan My rekening Naam: nuwe toepassing Nuwe wagwoord: Geen toepassingen beskikbaar nie Geen evaluasie beskikbaar nie Geen ISO-codes beskikbaar nie Hierdie module het geen parameters nie My portretfoto Geen %pretty_plural% beskikbaar Geen dienste beskikbaar nie Geen gebruiker gevind nie met hierdie gebruikersnaam geen Nie aangemeld nie Dit is geen geldig e-posadres nie Toeligting: Melding: op %name% aan: Aanlyn (facultatief) Opsies Of &acute;n nieuwe gebruiker toevoeg of die Parameters parameters wagwoord: Die wagwoord op %system_name%: %account_id_label%: %account_id% is gewysig. Daar is geen aksie nodig nie as die wagwoord deur die ontvanger van hierdie e-pos SELF gewysig is. Hierdie berig is slegs bedoel om in te lig en daarmee die veiligheid van die inligtinge in die stelsel te verhoog. --------------- Die wagwoord kan altyd gewysig word deur die volgende te doen: 1. Meld aan op %system_name% 2. Kliek op "%pvt_home_name%" 3. Kies "%password_update_link_text%" wagwoord is veranderd U wagwoord moet reëlmatig verander word. Verander assublief nu u wagwoord. Wagwoorde kom nie ooreen nie Dit privilege kan nie verwyder word nie. Regte regte Regte van %name% Keer terug naar %home_link%. Portretfoto Privaatheid Daar was 'n probleem tydens outentikasie van die rekening. Hoogwaarskynlik bevat die databank gebruikers sonder member_state. Profiel Vraag: Opnieuw inskakel Lees wagwoord agterhaal Aanmeldsessie ververs Aangepaste registrasievraagstelling Inskryf <p> Bedankt voor die inskryving by %system_name%. Die beheerder is op die hoogte gebragt. Zodra toestemming is gegeven, zal dit via &acute;n e-mail worden gemeld. Daarna kan %system_name% verder worden gebruikt. Weigeren Aanmeldsessie op hierdie rekenaar bewaar Verwyder Verwyder alles hernoem Toegang tot hierdie gemeenskap versoek Toegang tot hierdie subsite versoek Toegang vraag Terugkeer naar die toepassing Trek gemarkeerde in Rol Opmerking opslaan Skermnaam Hierdie skermnaam is al geneem. Soek 'n gebruiker Hoofveiligheidscontekst Kies 'n voorwerp via Id: Stuur e-pos naar hierdie gebruiker Stuur my 'n kopie: Stel die beoordeling van die registrasie in Toon Werfbrede beheerder Hoofdadministratie Sorry, ons kan nie verder help nie met die vergete wagwoord. Status Verhaal agter die foto Verhaal agter die foto Subgroepe subgroepe subgroep subsite Subsites subsites U is met sukses geoutentiseer, maar u het nog geen rekening op %system_name%. Bedank. Die ISO-kodes is nie geïnstalleer nie op hierdie bediener. Dit is 'n beslote groep. Alleen nuwe lede met 'n uitnodiging word toegelaat. Hierdie deelwerf Hierdie gebruiker het die gemeenskap verlaat. Met dit wagwoord kan mens sig aanmeld op die Onderwerp soortspecifieke info Onbekend e-posadres koppel af Een vlak hoër tot aan %context_name% Opdateer wagwoord bywerk aanbied Bied portretfoto aan Bied &acute;n nuwe portretfoto aan Bied portretfoto Gebruikerportret Gebruikerportrette Gebruikersprofiel Gebruikersprofiele Gebruikersnaam Geen gebruiker %username% gevind vir outoriteit %this_authority% Gebruikersnaam vereis Werfkaart van gebruiker Die inligting omtrent afwesigheid is bygewerk Die inligtinge omtrent afwesigheid op %site_link% is bygewerk. Welkom, %user_name% &acute;n Leeg aankruisvakjie beteken, dat die regte van die gebruiker word ingetrek, voorsover hierdie regte eerder toegewys is. Gebruikers wat nu aanlyn is Wie is aan-lyn? Skryf Ja, sekerlik My aansluitinge by gebruikersgroepe: Blader kan ook uit die Heropen kan altyd deur Daar is geen regte nie om die voorwerp %root% of onderliggende elemente te beheer. My portretfoto is nog niet beskikbaar. Daar is regte aanwesig om die volgende voorwerpe te beheer: Er staan geen kennisgewingen ingestel. My registrasie My forum-kennisgewinge My portretfoto: My %gc_system_name%-kennisgevingen %site_link% toon dat u weer aanwesig is openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ko_KR.utf-8.xml0000644000175000017500000005627610727201372025340 0ustar frankiefrankie , ë˜ëŠ” ì´í›„ %system_name% ì»¤ë®¤ë„ˆí‹°ì˜ íšŒì› ë‹¹ì‹ ì— ê´€í•´ %system_name%ì— ìžˆëŠ” ë‹¹ì‹ ì˜ ê³„ì •ì„ ì¢…ê²°í•©ë‹ˆë‹¤. 아니오, %pvt_home_name%으로 나를 다시 보내주세요. 예, ë‚´ ê³„ì •ì„ ì¢…ê²°í•´ì£¼ì„¸ìš”. <p>ë‹¹ì‹ ì˜ ê³„ì •ì€ í˜„ìž¬ 종결ë˜ì–´ 있습니다. ì›í•˜ì‹œë©´ <a href="%restore_url%">다시 개설하여 드리겠습니다.</a>.</p> <p> <font color="red"> <b> ë‹¹ì‹ ì˜ ê³„ì •ì€ í˜„ìž¬ 종결ë˜ì–´ 있습니다.</b> </font> <a href="%login_url%">로그ì¸ì„</a> 다시 해서 ê³„ì •ì„ ì–´ë–»ê²Œ í• ì§€ ìƒê°í•´ 보세요.</p&;gt; %system_name%ì— ìžˆëŠ” ë‹¹ì‹ ì˜ ê³„ì •ì´ ìž¬ê°œì„¤ë˜ì—ˆìŠµë‹ˆë‹¤. 환ì˜í•©ë‹ˆë‹¤. ê³„ì •ì´ ìž¬ê°œì„¤ë˜ì—ˆìŠµë‹ˆë‹¤. í–‰ë™ ìƒˆë¡œìš´ 애플리케ì´ì…˜ì„ 추가하시오 관리 %subsite_name% ê´€ë¦¬ìž ì´ ì‚¬ìš©ìžë¥¼ 위한 관리 ì„ íƒì‚¬í•­ 경고 종류 다른 그림 ì‘답 애플리케ì´ì…˜ ì—러 애플리케ì´ì…˜ ìŠ¹ì¸ ì—서 권한 ìž˜ëª»ëœ ë¹„ë°€ë²ˆí˜¸ 금지 기본 ì •ë³´ 전기 비밀번호를 지역 관리ìžë¡œë¶€í„° 확ì¸í•  수 없습니다. íšŒì› ëª…ë¶€ë¥¼ ë³¼ 수 없습니다 언어를 변경하시오 비밀번호 변경하시오 비밀번호, ì´ë©”ì¼, ì‚¬ì§„ì„ ë³€ê²½í•˜ì‹œì˜¤ ë°›ì€íŽ¸ì§€í•¨ ì ê²€í•˜ì‹œì˜¤ ì•„ì´ë“¤ <p> %system_name%ì— ìžˆëŠ” ë‹¹ì‹ ì˜ ê³„ì •ì„ ì •ë§ ì¢…ê²°í•  것ì¸ì§€ 확ì¸í•˜ì—¬ 주시기 ë°”ëžë‹ˆë‹¤. </p> <p> ê³„ì •ì„ ì¢…ê²°í•œë‹¤ëŠ” ê²ƒì€ ì´ë©”ì¼ì„ 다시 ë³´ë‚´ì§€ 못하며 %system_name%ì— ìžˆëŠ” 회ì›ë“¤ ëª…ë¶€ì— ë‹¹ì‹ ì˜ ì´ë¦„ì´ ì—†ì–´ì§€ëŠ” ê²ƒì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 하지만 ì»¤ë®¤ë„ˆí‹°ì— ëŒ€í•œ ë‹¹ì‹ ì´ ê¸°ì—¬í•œ ê²ƒì€ ì»¤ë®¤ë„ˆí‹° ì—­ì‚¬ì˜ ì¼ë¶€ì´ê¸° ë•Œë¬¸ì— ìœ ì§€ë  ê²ƒìž…ë‹ˆë‹¤. </p> <p> 그러나 ë‹¹ì‹ ì´ ë‹¨ì§€ ë¡œê·¸ì¸ í•¨ìœ¼ë¡œ ë‹¹ì‹ ì˜ ê³„ì •ì„ ìž¬ê°œì„¤í•  수 있다는 ê²ƒì„ ê¸°ì–µí•´ë‘시기 ë°”ëžë‹ˆë‹¤. </p> ë‹¹ì‹ ì˜ ê³„ì •ì„ ì¢…ê²°í•˜ì‹œì˜¤ 탈퇴한 그룹 ì£¼ì„ ì»¤ë®¤ë„ˆí‹°ë“¤ 커뮤너티들 커뮤너티 í™•ì¸ ê³„ì† êµ­ê°€ ì´ë¦„ 새 %pretty_name% ìƒì„± 새로운 ë¶€ì†ì‚¬ì´íŠ¸ë¥¼ ìƒì„±í•˜ì‹œì˜¤ 현재 비밀번호 ë‹¹ì‹ ì˜ ì˜¨ë¼ì¸ ìƒíƒœê°€ 다른 사용ìžì—게는 ë³´ì´ì§€ 않습니다. ë‹¹ì‹ ì˜ ì˜¨ë¼ì¸ ìƒíƒœê°€ 다른 사람ì—게 보입니다. ì§ˆë¬¸ì„ ê°œë³„í™”í•˜ë‹¤ ë°ì´í„°ë² ì´ìФ 오류 기본ì ì¸ ìƒí™© ì‚­ì œ 개발관리 개발ìžì˜ 관리 ì§ì ‘ 사용권한 사용 못하게 하다 사용 못하게 ë˜ë‹¤ ì˜ì—­ ì´ë©”ì¼ ì£¼ì„ì„ ìˆ˜ì •í•˜ë‹¤ ì–´ë–¤ 요소는 %authority_name%ê°€ 관리하기 ë•Œë¬¸ì— ìˆ˜ì •í•  수 없습니다 ì „ìžìš°íޏ ë¡œê·¸ì¸ í•˜ëŠ”ë° í•„ìš”í•œ 정보입니다: %account_id_label%: %account_id% %password_label%: %password% ë‹¤ìŒ ë§í¬ë¥¼ 지금 방문하여 비밀번호를 변경하시기 ë°”ëžë‹ˆë‹¤: %reset_password_url% %system_name%ì— ë“±ë¡í•œ ê²ƒì„ ê°ì‚¬ë“œë¦½ë‹ˆë‹¤. %system_url%ì— ë¡œê·¸ì¸í•˜ëŠ”ë° í•„ìš”í•œ 정보입니다: %account_id_label%: %account_id% %password_label%: %password% 다ìŒì˜ ë§í¬ë¥¼ 방문하여 ë‹¹ì‹ ì˜ ë¹„ë°€ë²ˆí˜¸ë¥¼ 지금 변경하시기 ë°”ëžë‹ˆë‹¤: %reset_password_url% ì „ìžìš°íޏ í™•ì¸ ì „ìžìš°íŽ¸ì´ ìš”ì²­ë˜ì§€ ì•ŠìŒ ìžŠì–´ë²„ë¦° %system_name%ì˜ ë¹„ë°€ë²ˆí˜¸ %system_name%ì— ì˜¤ì‹ ê±¸ 환ì˜í•©ë‹ˆë‹¤ ì‚¬ìš©ì´ ê°€ëŠ¥í•œ 비밀번호를 복구하기 위해 사용ìžì´ë¦„ì„ ìž…ë ¥í•˜ì‹œì˜¤. 사진 ì‚­ì œ 사진 ì‚­ì œ 오류 ë©”ì¼ ì „ì†¡ 오류 종료ë˜ë‹¤ 파ì¼ì´ë¦„ ì´ë¦„ 비밀번호를 잊으셨습니까? ë°œìƒ ë¹ˆë„ ë˜ëŒì•„ 가다 사용ìžì˜ ì‚¬ì§„ì„ ì—…ë¡œë“œí•˜ì‹œì˜¤ ë‹¹ì‹ ì˜ ì‚¬ì§„ì„ ì—…ë¡œë“œí•˜ì‹œì˜¤ ìŠ¹ì¸ ìŠ¹ì¸í—ˆê°€ ê°ì¶”다 홈페ì´ì§€ ë‹¹ì‹ ì´ í•œë‹¤ê³  하면 ì •ë³´ê°€ ìˆ˜ì •ë¨ ì´ˆì²­í•˜ë‹¤ ISO 코드 ISO 코드 명세표 ISO 코드가 로드ë˜ì§€ ì•ŠìŒ ISO 코드가 로드ë˜ì§€ ì•ŠìŒ ì»¤ë®¤ë„ˆí‹°ì— ê°€ìž…í•˜ë‹¤ %group_name% ë“±ë¡ ë¶€ì† ì‚¬ì´íŠ¸ì— ê°€ìž…í•˜ë‹¤ ì´ ì»¤ë®¤ë„ˆí‹°ì— ê°€ìž…í•˜ë‹¤ ì´ ë¶€ì† ì‚¬ì´íŠ¸ì— ê°€ìž…í•˜ë‹¤ 중심어 성 í›„ì— ì»¤ë®¤ë„ˆí‹°ì—서 탈퇴하다 ë¶€ì† ì‚¬ì´íŠ¸ë¥¼ 탈퇴하다 ì´ ì»¤ë®¤ë„ˆí‹°ë¥¼ 탈퇴하다 ì´ ë¶€ì† ì‚¬ì´íЏì—서 탈퇴하다 사용ìžë¥¼ 추가하지 ë§ê³  ëŒì•„가시오 ë¡œê·¸ì¸ ë¡œê·¸ì¸ %system_name%ì— ë¡œê·¸ì¸ ë‹¤ì‹œ ë¡œê·¸ì¸ í•˜ê¸° ë¡œê·¸ì¸ íŽ˜ì´ì§€ì˜ ì‹œê°„ì´ ì´ˆê³¼ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 로그ì¸í•˜ê¸° ë°”ëžë‹ˆë‹¤. ë¡œê·¸ì¸ ë˜ëŠ” ë“±ë¡ ë¡œê·¸ì¸ íŽ˜ì´ì§€ 로그아웃 %system_name%ì—서 로그아웃 , ë‹¹ì‹ ì˜ ë™ë£Œ 커뮤너티 회ì›ë“¤ì˜ 정보를 ë” ë§Žì´ ì–»ì„ ìˆ˜ 있습니다. ì´ ê·¸ë£¹ì— ê°€ìž…í•  수 ì—†ìŒ ì „ì²´ ISO 코드 ëª©ë¡ %system_name%ì—서 ê³„ì† ìž‘ì—…í•¨ %first_names% %last_name%ì˜ ì‚¬ì§„ì— ëŒ€í•œ 주ì„ì„ ìˆ˜ì •í•˜ì‹œì˜¤ %first_names% %last_name% (%email%)ë‹˜ì€ %system_url%ì˜ ì‚¬ìš©ìžë¡œ 등ë¡ë˜ì—ˆìŠµë‹ˆë‹¤. ì „ì²´ 사ì´íЏ 관리ìžë¥¼ 위한 %name%ì— í—ˆê°€ ìŠ¹ì¸ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë³´ê³ ì„œìž…ë‹ˆë‹¤: %first_names% %last_name%ì„ ë‹¤ë¥¸ 사람들ì—게 어떻게 알리시겠습니까? ê·¸ ì‚¬ëžŒì´ ê³„ì •ì„ ì´ë¯¸ 가지고 있다고 ìƒê°í•˜ì§€ 않는다면 ë‹¹ì‹ ì´ ì´ˆì²­í•˜ë ¤ëŠ” ì‚¬ëžŒì´ ì´ ì‹œìŠ¤í…œì— ì´ë¯¸ ê³„ì •ì„ ê°€ì§€ê³  있는 것으로 알거나 믿는다면 ì´ ê¸°ëŠ¥ì„ í•„ìš”ë¡œ 한다면 acs-reference와 ref-countries를 로드하세요. ìƒì†ë°›ì€ 사용권한 ë„서관ì´ë‚˜ í•™êµì—서 ê³µë™ìœ¼ë¡œ 사용하는 컴퓨터를 ì´ìš©í•œë‹¤ë©´ ì´ ì˜µì…˜ì„ ì„ íƒí•˜ëŠ” ê²ƒì€ ì¢‹ì§€ì•ŠìŠµë‹ˆë‹¤. ì´ ì»´í“¨í„°ì˜ ë‹¤ìŒ ì‚¬ìš©ìžê°€ 우리 ì„œë¹„ìŠ¤ì— ë‹¹ì‹ ì¸ ê²ƒì²˜ëŸ¼ 가장할 수 있습니다. %system_url%ì— ìƒˆë¡­ê²Œ ë“±ë¡ ë§¤ê°œë³€ìˆ˜ ìž…ë ¥ 필드 ë°‘ì— ìžˆëŠ” 빨간 색으로 ëœ í…스트는 ë§¤ê°œë³€ìˆ˜ì˜ ë‚´ìš©ì´ OpenACS 매개변수 파ì¼ì— 있는 항목으로 대치ë˜ëŠ” ê²ƒì„ ì˜ë¯¸í•œë‹¤. ì´ ë§¤ê°œë³€ìˆ˜ 파ì¼ì€ 사용하지 않는 ê²ƒì´ ì¢‹ìœ¼ë‚˜ ì¼ë¶€ 사ì´íŠ¸ëŠ” apm_parameter í…Œì´ë¸”ê³¼ 무관하게 ì¸ìŠ¤í„´ìŠ¤ì— ê³ ìœ í•œ ë§¤ê°œë³€ìˆ˜ì˜ ê°’ì„ ì œê³µí•˜ì—¬ì•¼ 하기 ë•Œë¬¸ì— ì´ê²ƒì„ 필요로 한다. 작업ì˜ì—­ì—서 "로그 아웃"ì˜µì…˜ì„ ì„ íƒí•¨ìœ¼ë¡œì¨ 저장ë˜ì—ˆë˜ ì „ìžìš°íŽ¸ì£¼ì†Œì™€ 비밀번호를 삭제할 수 있습니다. %num_children% 숨겨진 ì•„ì´ë“¤ %portrait_publish_date%ì— ì—…ë¡œë“œí–ˆìŠµë‹ˆë‹¤<a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> ë‹¹ì‹ ì˜ íŽ¸ì˜ë¥¼ 위해, 서버가 브ë¼ìš°ì €ì—게 ì „ìžìš°íŽ¸ì£¼ì†Œë‚˜ 비밀번호와 ê°™ì€ ì‚¬í•­ì„ ê¸°ì–µí•˜ê²Œ í•  수 있습니다. ë§Œì¼ ë‹¹ì‹ ì˜ ì»´í“¨í„°ë¥¼ 당신 혼ìžì„œë§Œ 사용하는 것ì´ë¼ë©´,ì „ìžìš°íޏ 주소나 비밀번호를 매번 입력할 필요가 없습니다. 비밀번호 확ì¸: ê°œì¸ í™ˆíŽ˜ì´ì§€ URL: ë‹¹ì‹ ì˜ êµ­ê°€ 코드를 아래 ë‚˜ì—´ëœ ê²ƒ 중ì—서 ì°¾ì€ í›„ì— ë¶€ë¼ìš°ì €ì˜ "뒤로" ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ ì „ì˜ í¼ìœ¼ë¡œ ëŒì•„가시오. ì „ìžìš°íŽ¸ì— ìžˆëŠ” ì„¤ëª…ì„ ì½ê³  ë”°ë¼í•˜ì‹œì˜¤. 다시 <a href="index">로그ì¸</a> 하시오. %first_names% %last_name%ì˜ ì‚¬ì§„ 계층구조 ìƒì—서 ë†’ì€ ê¶Œí•œì€ ê·¸ ì•„ëž˜ì— ìžˆëŠ” 모든 권한ì´, 예를 들면 관리가 부여ë˜ë©´ ì½ê¸°, 쓰기를 í•  수 있ìŒ, ìžë™ìœ¼ë¡œ 허용ë¨ì„ ì˜ë¯¸í•œë‹¤. ì¸ì¦ 실패 ì´ ì„œë¹„ìŠ¤ë¥¼ 위한 ë“±ë¡ ì •ë³´ëŠ” %email%로 보내야 합니다. ì´ ì„œë¹„ìŠ¤ë¥¼ 위한 ë“±ë¡ ì •ë³´ëŠ” %email%로 보내야 합니다. ë‹¹ì‹ ì˜ ë“±ë¡ìš”ì²­ì€ %system_name% 관리ìžì—게 제출ë˜ì—ˆìŠµë‹ˆë‹¤. 현재 승ì¸ëŒ€ê¸°ì¤‘입니다. ì „ìžìš°íŽ¸ì£¼ì†Œì™€ 비밀번호 저장중 %system_name%ì˜ ë‹¤ë¥¸ 사용ìžë“¤ì—게 ë‹¹ì‹ ì˜ ë©‹ì§„ ëª¨ìŠµì„ ë³´ì—¬ì£¼ì„¸ìš”: %system_name%으로부터 거절당했습니다. ì´ ì‚¬ìš©ìžì˜ ì‚¬ì§„ì„ ì •ë§ ì§€ìš°ë ¤ê³  합니까? ë‹¹ì‹ ì˜ ì‚¬ì§„ì„ ì •ë§ ì§€ìš°ë ¤ê³  합니까? ì‹œìŠ¤í…œì— ìžˆëŠ” ë‹¹ì‹ ì˜ ì‚¬ì§„ì€ ìž˜ 못 ë˜ì—ˆìŠµë‹ˆë‹¤. 계정ì¸ì¦ì— 문제가 있습니다. ì´ ê²ƒì´ %system_name%ì— ìžˆëŠ” 다른 사용ìžì—게 보여주는 ì´ë¯¸ì§€ìž…니다. ì´ ì‚¬ìš©ìžëŠ” ì•„ì§ ì‚¬ì§„ì´ ì—†ìŠµë‹ˆë‹¤. ë‹¹ì‹ ì´ í•  수 있습니다 ì´ ì‚¬ìš©ìžëŠ” 커뮤너티ì—서 ì‚­ì œë˜ê³  가입할 수 없습니다. 등ë¡ì„ 확ì¸í•˜ê¸° 위해 %confirmation_url%(으)로 가시오. ë°ìŠ¤í¬ í†± 컴퓨터ì—서 ë‹¹ì‹ ì´ ì œì¼ ì¢‹ì•„í•˜ëŠ” 파ì¼ì¸ 스캔한 JPEG나 GIF 파ì¼ì„ 업로드 하시오 (ì¸í„°ë„·ì— 있는 ì´ë¯¸ì§€ë¥¼ 참조할 수 없고 반드시 ì´ë¯¸ì§€ëŠ” 당신 ì»´í“¨í„°ì˜ í•˜ë“œ 드ë¼ì´ë¸Œì— 있어야 합니다). 업로드: %pretty_date% 업로드: %publish_date% "ë¶€ë¼ìš°ì¦ˆ" ë²„íŠ¼ì„ ì‚¬ìš©í•˜ì—¬ ë‹¹ì‹ ì˜ íŒŒì¼ì„ 찾아 "열기"를 í´ë¦­í•˜ì„¸ìš”. 당신(ì‚¬ìš©ìž %user_id%)ì„ ì‚¬ìš©ìž ëª©ë¡ì—서 ì°¾ì„ ìˆ˜ 없습니다. ì–´ë–¤ ì´ìœ ë¡œ ì¸í•´ ë‹¹ì‹ ì˜ ê³„ì •ì´ ì‚­ì œëœ ê²ƒê°™ìŠµë‹ˆë‹¤. ë‹¹ì‹ ì˜ ìžë£Œ ìž…ë ¥ì„ ì²˜ë¦¬í•˜ëŠ”ë° ë¬¸ì œê°€ ìƒê²¼ìŠµë‹ˆë‹¤. ë‹¹ì‹ ì˜ ì „ìžìš°íŽ¸ì„ ê¸°ë‹¤ë¦¬ê³  있지 않습니다. ì•½ê°„ì˜ ì‹¤ìˆ˜ê°€ 있습니다. %system_name% ì— ë°©ë¬¸í•˜ì‹  ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤. 다른 사용ìžê°€ ë‹¹ì‹ ì˜ ì´ë¦„ì„ í´ë¦­í• ë•Œ ë³¼ 수 있는 것 ë‹¹ì‹ ì˜ ì´ë¦„ì— &lt;를 가질 수 없습니다. ì´ê²ƒì€ HTML 태그같아 보여서 다른 사용ìžì™€ 혼ë™ì´ ë©ë‹ˆë‹¤. ë‹¹ì‹ ì˜ ì„±ì— &lt;를 가질 수 없습니다. ì´ê²ƒì€ HTML 태그같아 보여서 다른 사용ìžì™€ 혼ë™ì´ ë©ë‹ˆë‹¤. %pretty_date% ì´í›„까지는 ì–´ë–¤ ì´ë©”ì¼ë„ 받지 못할 것입니다. ë‹¹ì‹ ì˜ ì´ë©”ì¼ì´ 확ì¸ë˜ì—ˆìŠµë‹ˆë‹¤. ì´ì œ %system_name%ì— ë¡œê·¸ì¸í•  수 있습니다. ë‹¹ì‹ ì˜ ì „ìžìš°íŽ¸ì´ í™•ì¸ë˜ì—ˆìŠµë‹ˆë‹¤. %system_name% 관리ìžë¡œë¶€í„° ì¸ì¦ëŒ€ê¸°ì¤‘ì— ìžˆìŠµë‹ˆë‹¤. ë‹¹ì‹ ì˜ ì „ìžìš°íŽ¸ì€ í™•ì¸ë˜ì—ˆìŠµë‹ˆë‹¤. ë‹¹ì‹ ì˜ ë¡œê·¸ì¸ì˜ 유효 ê¸°ê°„ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤. ê³„ì† ì§„í–‰í•˜ì‹œë ¤ë©´ 패스워드를 다시 입력하세요. ë‹¹ì‹ ì˜ URLì´ ìž˜ëª»ëœ í˜•ì‹ì„ 가지고 있습니다. 유효한 URLì€ \"%valid_url_example%\"." ê³¼ 같아야 합니다. 관리ìžë¥¼ 만드세요 íšŒì› ìƒì„± 비공개 공개 통보 관리 미안하지만 íšŒì› ëª…ë¶€ë¥¼ ë³¼ 수 없습니다. íšŒì› ìƒíƒœ 회ì›ë“¤ ì´ë¦„: 새로운 비밀번호: ì‹ ì²­ ì—†ìŒ ISO 코드가 ì—†ìŒ ì´ íŒ¨í‚¤ì§€ëŠ” 매개 변수가 없습니다. ë‹¹ì‹ ì˜ ì‚¬ì§„ %pretty_plural%ì´ ì—†ìŒ ì„œë¹„ìŠ¤ ì—†ìŒ ì¡°ê¸ˆë„ ì•Šë‹¤. ë¡œê·¸ì¸ í•˜ì§€ ì•ŠìŒ ì£¼: 통보: %name%ì— ê´€í•˜ì—¬ (ì„ íƒì‚¬í•­) ì„ íƒì‚¬í•­ ë˜ëŠ” 새 ì‚¬ìš©ìž ì¶”ê°€ ë˜ëŠ” 비밀번호 %system_name%ì˜ ë‹¹ì‹ ì˜ ë¡œê·¸ì¸ ì •ë³´: %account_id_label%: %account_id% ì´ ê³„ì •ì˜ ë‹¹ì‹  비밀번호는 ìµœê·¼ì— ë³€ê²½ë˜ì—ˆìŠµë‹ˆë‹¤. 특별한 ì¼ì„ í•  필요는 없으며 ì´ ë©”ì‹œì§€ëŠ” 단지 당신 ê³„ì •ì˜ ë³´ì•ˆì„ ìœ„í•œ 통보입니다. --------------- ë‹¹ì‹ ì€ ë‹¤ìŒê³¼ ê°™ì€ ë°©ë²•ìœ¼ë¡œ 언제든지 ë‹¹ì‹ ì˜ ë¹„ë°€ë²ˆí˜¸ë¥¼ 변경할 수 있습니다: 1. %system_name%ì— ë¡œê·¸ì¸ 2. "%pvt_home_name%" ë§í¬ë¥¼ í´ë¦­ 3. "%password_update_link_text%" ì„ íƒ ë¹„ë°€ë²ˆí˜¸ 변경 사용권한 권한 %name%ì— ëŒ€í•œ 사용권한 %home_link%로 ëŒì•„가세요. 사진 질문: 재가능 비밀번호 복구 새로운 ë¡œê·¸ì¸ ë ˆì§€ìŠ¤í„° <p>%system_name%ì— ë“±ë¡í•¨ì„ ê°ì‚¬ë“œë¦½ë‹ˆë‹¤. 관리ìžê°€ ë‹¹ì‹ ì˜ ìš”ì²­ì„ ì•Œë ¤ì™”ìŠµë‹ˆë‹¤.</p> %<p>승ì¸ì´ 통과ë˜ë©´ ì´ë©”ì¼ ë©”ì‹œì§€ë¥¼ 받게 ë  ê²ƒì´ë©° system_name%ì˜ ì‚¬ìš©ì„ ì‹œìž‘í•  수 있습니다. ê±°ì ˆ ì´ ì»´í“¨í„°ì˜ ë¡œê·¸ì¸ ì €ìž¥í•˜ê¸° ì‚­ì œ ì´ ì»¤ë®¤ë„ˆí‹°ì˜ íšŒì›ê¶Œ 요청 ì´ ë¶€ì† ì‚¬ì´íŠ¸ì˜ íšŒì›ê¶Œ 요청 회ì›ê¶Œ 요청 ì§€ì›ìœ¼ë¡œ 복귀 취소 í‘œì‹œë¨ ì—­í•  ì£¼ì„ ì €ìž¥ 스í¬ë¦° ì´ë¦„ 기존 íšŒì› ê²€ìƒ‰ 보안 컨í…스트 루트 ê°ì²´ë¥¼ ì•„ì´ë””로 ì„ íƒ ì´ ì‚¬ìš©ìžì—게 ì´ë©”ì¼ ë³´ë‚´ê¸° 보여주기 사ì´íЏ ì „ì²´ 관리 미안하지만 잊어버린 ë¹„ë°€ë²ˆí˜¸ì— ê´€í•´ ë„ì›€ì„ ë“œë¦´ 수 없습니다. ìƒíƒœ ì‚¬ì§„ì— ê´€í•œ ë°°ê²½ì´ì•¼ê¸° 사진 ë’· 얘기 ë¶€ì† ì»¤ë®¤ë„ˆí‹°ë“¤ ë¶€ì† ì»¤ë®¤ë„ˆí‹° ë¶€ì† ì»¤ë®¤ë„ˆí‹° ë¶€ì† ì‚¬ì´íЏ ë¶€ì†ì‚¬ì´íŠ¸ë“¤ ë¶€ì†ì‚¬ì´íŠ¸ë“¤ ê°ì‚¬í•©ë‹ˆë‹¤. ì´ ì„œë²„ì— ISO 코드가 로드ë˜ì§€ 않았습니다. ì´ ê·¸ë£¹ì€ ë§ˆê°ë˜ì—ˆìŠµë‹ˆë‹¤. 새 회ì›ì€ ì´ˆì²­ì— ì˜í•´ 참여할 수 있습니다. ì´ ë¶€ì†ì‚¬ì´íЏ ì´ ì‚¬ìš©ìžëŠ” 커뮤너티를 탈퇴하였습니다. 로그ì¸í•˜ë ¤ë©´ ë°©ë¬¸ì„ í† í”½ íƒ€ìž…ì— ê´€í•œ ì •ë³´ 위로 %context_name%ì— ì—… 수정 비밀번호 ì—…ë°ì´íЏ 업로드 사진 업로드 êµì²´í•  ì‚¬ì§„ì„ ì—…ë¡œë“œ ì‚¬ì§„ì„ ì—…ë¡œë“œ ì‚¬ìš©ìž ì´ë¦„ ìˆ˜ì •ëœ íœ´ê°€ ì •ë³´ %site_link%ì—서 ë‹¹ì‹ ì˜ íœ´ê°€ ì •ë³´ê°€ 수정ë˜ì—ˆìŠµë‹ˆë‹¤. %user_name%ì„ í™˜ì˜í•©ë‹ˆë‹¤ ì´ ì²´í¬ë°•스를 비어 ë‘ë©´ ë‹¹ì‹ ì´ ëˆ„êµ°ê°€ì—게 부여한 ì´ íŠ¹ê¶Œì€ ì´ì œ 무효가 ë  ê²ƒìž…ë‹ˆë‹¤. 현재 온ë¼ì¸ ì¤‘ì¸ ì‚¬ìš©ìžë“¤ 온ë¼ì¸ ì¤‘ì¸ ì‚¬ëžŒë“¤ 예, 확실합니다 다ìŒì—서 ë¶€ë¼ìš°ì¦ˆí•  수 있습니다 ë‹¤ìŒ ë°©ë²•ìœ¼ë¡œ í•­ìƒ ë‹¤ì‹œ 개설할 수 있습니다 ê°ì²´ %root%와 ê·¸ê²ƒì˜ ìžë…€ ê°ì²´ë“¤ì„ 관리하는 ìžê²©ì´ 없습니다. ì•„ì§ ë‹¹ì‹ ì˜ ì‚¬ì§„ì´ ì—†ìŠµë‹ˆë‹¤. 다ìŒê³¼ ê°™ì´ í•  수 있습니다 ë‹¤ìŒ ê°ì²´ë“¤ì— 대한 관리 ìžê²©ì„ 가지고 있습니다: ë‹¹ì‹ ì€ ì´ë©”ì¼ ê²½ë³´ë¥¼ 현재 등ë¡í•˜ì§€ 않았습니다. ë‹¹ì‹ ì˜ ê³„ì • ë‹¹ì‹ ì˜ í† ë¡  í¬ëŸ¼ì˜ 경보 사진 ë‹¹ì‹ ì˜ %gc_system_name%ì´ ê²½ê³ í•œë‹¤ %site_link%ì— ë‹¹ì‹ ì€ íœ´ê°€ì—서 ëŒì•„ 온것으로 표시ë˜ì–´ 있습니다. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.hi_IN.utf-8.xml0000644000175000017500000011073110727201372025304 0ustar frankiefrankie , या मोलिक जानकारी को अघतन करे से %system_name% समà¥à¤¦à¤¾à¤¯ का सदसà¥à¤¯ आपके बारे मे %system_name% आपका अकाउनà¥à¤Ÿ बनà¥à¤¦ कर दिया है। नही मà¥à¤à¥‡ वापस %pvt_home_name% मे ले चले। हा कà¥à¤°à¤ªà¥à¤¯à¤¾ मेरा अकाउनà¥à¤Ÿ बनà¥à¤¦ कर दे। अभी आपका अकाउनà¥à¤Ÿ बनà¥à¤¦ है। यदि आप चाहे तो हम <a href=%restore_url%> आपका अकाउनà¥à¤Ÿ दà¥à¤¬à¤¾à¤°à¤¾ खोल देगे । <p> <font color="red"> अभी आपका अकाउनà¥à¤Ÿ बनà¥à¤¦ है। </b> </font> <a href="%login_url%"> लाऊग इन </a> आप इस समà¥à¤¬à¤¨à¥à¤§ मे कà¥à¤¯à¤¾ कर सकते है जानने के लिये दà¥à¤¬à¤¾à¤°à¤¾ लाऊग इन करे। %system_name% पर आपका अकाउनà¥à¤Ÿ दà¥à¤¬à¤¾à¤°à¤¾ खोल दिया है। आपका पà¥à¤¨: सवागत है। अकाउनà¥à¤Ÿ दà¥à¤¬à¤¾à¤°à¤¾ खोल दिया गया है। कà¥à¤°à¤¿à¤¯à¤¾ नया उपयोग याग करना कौनतà¥à¤°à¥‹à¤² सूची %subsite_name% को पà¥à¤°à¤¶à¤¸à¤¿à¤¤ करे। इस पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ के लिये पà¥à¤°à¤¶à¤¾à¤¸à¤¨à¤¿à¤• विकà¥à¤²à¤ªà¥¤ सतरà¥à¤• पà¥à¤°à¤•ार दà¥à¤¸à¤°à¤¾ चितà¥à¤° उतà¥à¤¤à¤° उपयोग गलती उपयोग अनà¥à¤®à¥‹à¤¦à¤¨ करे पर अधिकार संकेत-शबà¥à¤¦ अमानय है पà¥à¤°à¤¤à¤¿à¤·à¥‡à¤¦ करे मूल सूचना जीवनचरित: सà¥à¤¥à¤¾à¤¨à¥€à¤¯ पà¥à¤°à¤§à¤¾à¤•ारी से पासवरà¥à¤¡ पà¥à¤¨: पà¥à¤°à¤¾à¤ªà¥à¤¤ नही हो सकेगा सदसà¥à¤¯à¥‹ की सूची नही देख पाà¤à¤—े भाषा बदलो संकेत-शबà¥à¤¦ परिवरà¥à¤¤à¤¨ पासवरà¥à¤¡, ईमेल, पोटà¥à¤°à¥‡à¤Ÿ बदलो डाक जाà¤à¤šà¤¿à¤¯à¥‡ शिशॠकà¥à¤°à¥à¤ªà¥à¤¯à¤¾ पà¥à¤·à¤¿à¤Ÿ करे कि आप %system_name% पर अपना अकाउनà¥à¤Ÿ बनà¥à¤¦ करना चाहते है। आपका अकाउनà¥à¤Ÿ बनà¥à¤¦ किये जाने का मतलब यह है कि न तो हम आगे से आपको ईमेल की सूचना भेज सकेगे और न ही %system_name% पर सदà¥à¤¸à¥à¤¯à¥‹ की सूची मे आपका नाम होगा । तथापि समà¥à¤¦à¤¾à¤¯ के लिये आपका योगदान सरकà¥à¤·à¤¿à¤¤ रखा जायेगा वे समà¥à¤¦à¤¾à¤¯ के इतिहास का हिसà¥à¤¸à¤¾ होगी । यह नोट करे कि आप अपना अकाउनà¥à¤Ÿ पà¥à¤¨: लौगिन इन दà¥à¤µà¤¾à¤°à¤¾ किसी भी समय दà¥à¤¬à¤¾à¤°à¤¾ खोल सकेगे अपना अकाउनà¥à¤Ÿ बनà¥à¤¦ करे बनà¥à¤¦ समà¥à¤¹ टिपà¥à¤ªà¥à¤£à¥€ समà¥à¤¦à¤¾à¤¯à¥‹ समà¥à¤¦à¤¾à¤¯à¥‹ समà¥à¤¦à¤¾à¤¯ पà¥à¤·à¥à¤Ÿà¤¿à¤•रण: आप नया पासवरà¥à¤¡ चयन करने मे सफ़ल रहे जारी रखे %pvt_home_name% पर जारी रखे देश का नाम नया %pretty_name% सà¥à¤°à¤œà¤¿à¤¤ करे नया सबसाईट बनाये वरà¥à¤¤à¤®à¤¾à¤¨ संकेत-शबà¥à¤¦: <p> अभी आपकी आन लाईन सà¥à¤¥à¤¿à¤¤à¤¿ अनà¥à¤¯ पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ नही देख सकेगे </p> <p> आपकी आन लाईन सà¥à¤¥à¤¿à¤¤à¤¿ को अनà¥à¤¯ पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ देख सकेगे </p> पà¥à¤°à¤¶à¥à¤¨ परिवरà¥à¤¤à¤¿à¤¤ करे देटाबेस तà¥à¤°à¥à¤Ÿà¥€ तà¥à¤°à¥à¤Ÿà¤¿ पà¥à¤°à¥à¤£ सनà¥à¤¦à¤°à¥à¤­ मिटाना डेव à¤à¤¡à¥à¤®à¤¿à¤¨ डेवलà¥à¤ªà¤° का à¤à¤¡à¤®à¤¿à¤¨à¤¿à¤¸à¥à¤Ÿà¥à¤°à¥‡à¤¶à¤¨ मूल अनà¥à¤®à¤¤à¤¿à¤¯à¤¾à¤‚ विकलानà¥à¤— अशकà¥à¤¤ डोमेन ई-मेल टिपà¥à¤ªà¤£à¥€ मे सनà¥à¤¶à¥‹à¤§à¤¨ करे कà¥à¤› तथà¥à¤¯à¥‹ मे सनà¥à¤¶à¥‹à¤§à¤¨ नही किया जा सकता है कà¥à¤¯à¥‹à¤•ि उनका पà¥à¤°à¤¬à¤¨à¥à¤§à¤¨ %authority_name% दà¥à¤µà¤¾à¤°à¤¾ किया जाता है ईमेल आपकी नये लोगिन समà¥à¤¬à¤¨à¥à¤§à¥€ जानकारी इस पà¥à¤°à¤•ार है: %account_id_label%: %account_id% %password_label%: %password% कà¥à¤°à¤ªà¥à¤¯à¤¾ अब अपना पासवरà¥à¤¡ बदलने के लिये निमà¥à¤¨à¤²à¤¿à¤–ित लिनà¥à¤• मे जाये: %reset_password_url% %system_name% मे रजिसà¥à¤Ÿà¥à¤°à¥‡à¤¶à¤¨ के लिये आपका धनà¥à¤¯à¤µà¤¾à¤¦! देखे कि किस पà¥à¤°à¤•ार आप %system_url%: %account_id_label%: %account_id% %password_label%: %password% मे लौगिन कर सकते है: कà¥à¤°à¤ªà¥à¤¯à¤¾ अब अपना पासवरà¥à¤¡ बदलने के लिये निमà¥à¤¨à¤²à¤¿à¤–ित लिनà¥à¤• मे जाये: %reset_password_url% ई-मेल का पà¥à¤·à¥à¤Ÿà¥€à¤•रण ई-मेल पà¥à¤°à¤¾à¤°à¥à¤¥à¤¿à¤¤ नही किया गया %system_name% मे आपका पासवरà¥à¤¡ जिसे आप भूल गये है %system_name% मे आपका सà¥à¤µà¤¾à¤—त है à¤à¤¨à¥‡à¤¬à¥à¤²à¥à¤¡ पासवरà¥à¤¡ रिकवरी शà¥à¤°à¥ करने के लिये अपना यà¥à¤¸à¤° नाम à¤à¤¨à¤Ÿà¤° करे पोटà¥à¤°à¥‡à¤Ÿ को हटा दे पोटà¥à¤°à¥‡à¤Ÿ को हटा दे विभà¥à¤°à¤® ई-मेल भेजने मे विभà¥à¤°à¤® मिट जायेगा फ़ाईल नाम पहला नाम कà¥à¤¯à¤¾ अपना पासà¥à¤µà¤°à¥à¤¡ भूल गये है? आवरति पीछे चले यà¥à¤œà¤° के पोटà¥à¤°à¥‡à¤Ÿ को अपलोड करो अपना पोटà¥à¤°à¥‡à¤Ÿ अपलोड करो अनà¥à¤®à¤¤à¤¿ दें अनà¥à¤®à¤¤à¤¿ दें छिपाये मà¥à¤– पà¥à¤°à¤·à¥à¤  यदि आप सà¥à¤šà¤¨à¤¾ अघतन की गई आमनà¥à¤¤à¥à¤°à¤¿à¤¤ करे आई à¤à¤¸ ओ कोड आई à¤à¤¸ ओ कोड लिसà¥à¤Ÿ आई à¤à¤¸ ओ कोडà¥à¤¸ लोड नही किया गया आई à¤à¤¸ ओ कोड लोड नही किया गया समà¥à¤¦à¤¾à¤¯ मे शामिल हो %group_name% मे समà¥à¤®à¤¿à¤²à¤¿à¤¤ हों इस सबसाइट मे शामिल हो इस समà¥à¤¦à¤¾à¤¯ मे शामिल हो इस सबसाईट मे शामिल हो मà¥à¤–à¥à¤¯ शबà¥à¤¦ बाद का नाम बाद का समà¥à¤¦à¤¾à¤¯ को छोड दे सबसाईट को छोड दे इस समà¥à¤¦à¤¾à¤¯ को छोड दो इस सबसाइट को छोड दे किसी भी पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ को शामिल किये बिना पीछे चले लौगईन लौगईन %system_name% लौगईन लौगईन लोगिन पà¥à¤°à¤·à¥à¤  मिट गया है। कà¥à¤°à¤ªà¥à¤¯à¤¾ दà¥à¤¬à¤¾à¤°à¤¾ लोगिन करे। लोगिन या रजिसà¥à¤Ÿà¤° लोगिन पà¥à¤°à¤·à¥à¤  लौगआउट %system_name% लौगआउट आप अपने साथी समà¥à¤¦à¤¾à¤¯ सदसà¥à¤¯à¥‹ के बारे मे और अधिक जानकारी पà¥à¤°à¤¾à¤ªà¥à¤¤ कर सकेगे इस समà¥à¤¹ मे समà¥à¤®à¤¿à¤²à¤¿à¤¤ नही हो सकते है आई à¤à¤¸ ओ कोडà¥à¤¸ की पूरी लिसà¥à¤Ÿ %system_name% पर कारà¥à¤¯ करना जारी रखे %first_names% %last_name% के लिये टिपà¥à¤ªà¤£à¥€ मे सनà¥à¤¶à¥‹à¤§à¤¨ करे। %first_names% %last_name% (%email%), %system_url% के पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ के रूप मे पंजीकृत हà¥à¤ साइट वाइड पà¥à¤°à¤¶à¤¾à¤¸à¤¨ के लिये %name% पर अनà¥à¤®à¤¤à¤¿ पà¥à¤°à¤¦à¤¾à¤¨ करे यह रहा कि डाटाबेस ने कà¥à¤¯à¤¾ रिपोरà¥à¤Ÿ दी: आप दà¥à¤¨à¤¿à¤¯à¤¾ को केसे देखना चाहेगे %first_names% %last_name%? यदि आप यह नही समà¤à¤¤à¥‡ कि वयकà¥à¤¤à¤¿ का पहले से ही अकाउनà¥à¤Ÿ है: यदि आप यह जान पाये या विशवास कर पाये कि जिस वयकà¥à¤¤à¤¿ को आप आमनà¥à¤¤à¥à¤°à¤¿à¤¤ कर रहे है उसके पास पहले से ही इस सिसटम मे अकाउनà¥à¤Ÿ है यदि आपको इस कारà¥à¤¯à¤¾à¤¤à¥à¤®à¥à¤•à¥à¤¤à¤¾ की आवà¥à¤¶à¥à¤¯à¤•ता है तो कà¥à¤°à¤ªà¥à¤¯à¤¾ à¤à¤¸à¥€à¤à¤¸ सनà¥à¤¦à¤°à¥à¤­ और सनà¥à¤¦à¤°à¥à¤­ लोड करे इनहेरिटेड अनà¥à¤®à¤¤à¤¿ यदि आप लाइबà¥à¤°à¥‡à¤°à¥€ या सà¥à¤•ूल मे शेयर किये गये कमà¥à¤ªà¥à¤Ÿà¤° का उपयोग कर रहे है तो इस विकलप का चयन करना सही नही होगा %system_url% पर नया पनà¥à¤œà¥€à¤•रण नीचे लाल रनà¥à¤— मे दिये गये पाठ को नोट करे। पेरामीटर à¤à¤¨à¥à¤Ÿà¥à¤°à¥€ कà¥à¤·à¥‡à¤¤à¥à¤° इस पेरामीटर के मान को दरà¥à¤¶à¤¾à¤¤à¤¾ है। जो ओपन à¤à¤¸à¥€à¤¾ फ़ाइल मे पà¥à¤°à¤µà¤¿à¤¶à¤Ÿ दà¥à¤µà¤¾à¤°à¤¾à¤… ओवररिडन है। पेरामीटर फ़ाइल के उपयोग को हतोतà¥à¤¸à¤¾à¤¹à¤¿à¤¤ किया जाता है। परनà¥à¤¤à¥ à¤à¤ªà¥€à¤à¤® पेरामीटर टेबल से पà¥à¤°à¤¥à¤• पेरामीटरो के लिये घटना विशिषà¥à¤Ÿ का मान उपà¥à¤²à¤¬à¤§ कराने के लिये कà¥à¤› साइटो को इसकी आवà¥à¤¶à¤•ता हो सकती है। आप अपने वरà¥à¤•सà¥à¤ªà¥‡à¤¸ से लाग आउट विकलà¥à¤ª का उपयोग करके सेव किये गये ईमेल पते और पासवरà¥à¤¡ को मिटा सकते है। %num_children% छà¥à¤ªà¤¾ हà¥à¤† बचà¥à¤šà¤¾ %portrait_publish_date%, को आपने &lt;a href=&quot;%subsite_url%user/portrait/?return_url=%pvt_home_url%&quot;&gt;%portrait_title%&lt;/a&gt; अपलोड किया है हमारा सरवर आपके बà¥à¤°à¤¾à¤‰à¤œà¤° को कà¥à¤› बाते याद रखने के लिये कह सकता है जेसे आपका ईमेल पता और पासवरà¥à¤¡à¥¤ यह आपके लिये सà¥à¤µà¤¿à¤§à¤¾à¤œà¤¨à¤• है कà¥à¤¯à¥‹à¤•ि यदि केवल आप ही अपने कमà¥à¤ªà¥à¤Ÿà¤° का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करते है तो आपको अपने ईमेल पता और पासवरà¥à¤¡ बताने की आवशकयता नही होगी। पासवरà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ वयकतिगत मà¥à¤–à¥à¤¯ पà¥à¤°à¤·à¥à¤  यà¥à¤†à¤°à¤à¤²: नीचे दिये गये कोडो मे से अपने देश का कोड का पता लगाà¤à¥¤ ततà¥à¤ªà¤¶à¤šà¤¾à¤¤ पिछà¥à¤²à¥€ सिथà¥à¤¤à¤¿ मे वापसी के लिये अपने बà¥à¤°à¤¾à¤‰à¤œà¤° पर बेक बटन का उपयोग करे कà¥à¤°à¤ªà¤¯à¤¾ इस ईमेल मे दिये गये अनà¥à¤¦à¥‡à¤¶à¥‹ को पडे और उनका अनà¥à¤ªà¤¾à¤²à¤¨ करे। कà¥à¤°à¤ªà¤¯à¤¾ &lt;a href=&quot;index&quot;&gt; के लागिन का पà¥à¤¨ पà¥à¤°à¤¯à¤¾à¤¸ करे &lt;/a&gt; %first_names% %last_name% का पोटà¥à¤°à¥‡à¤Ÿ शà¥à¤°à¥‡à¤£à¥€ मे उचà¥à¤šà¥à¤¤à¤° पà¥à¤°à¤¿à¤µà¤¿à¤²à¥‡à¤œ नीचे दिये गये सभी पà¥à¤°à¤¿à¤µà¤¿à¤²à¥‡à¤œà¥‹ पर लागू होते है अरà¥à¤¥à¤¾à¤¤ जब आप à¤à¤¡à¥à¤®à¤¿à¤¨ की अनà¥à¤®à¤¤à¤¿ देते है तब पडे, लिखे आदि सà¥à¤µà¤¤: लागू होते है। पà¥à¤°à¤®à¤¾à¤£à¥€à¤•रन के साथ समसà¥à¤¯à¤¾ इस सेवा के लिये रजिसà¥à¤Ÿà¥à¤°à¥‡à¤¶à¤¨ समबनà¥à¤§à¥€ जानकारी %email% को अभी-अभी भेज दी गयी है। इस सेवा के लिये पनà¥à¤œà¤¿à¤•रण सूचना %email% को भेज दी गयी है आपका रजिसà¥à¤Ÿà¥à¤°à¥‡à¤¶à¤¨ के लिये अनà¥à¤°à¥‹à¤§ %system_name% पà¥à¤°à¤¶à¤¾à¤¸à¤• को भेज दिया गया है। अभी इसे सà¥à¤µà¥€à¤•à¥à¤°à¤¤ किया जाना है। ईमेल तथा पासवरà¥à¤¡ को सेव करना है। %system_name% पर अनà¥à¤¯ सभी को दरà¥à¤¶à¤¾à¤¯à¥‡, आप कितने महान लग रहे है: कà¥à¤·à¤®à¤¾ चाहते है किनà¥à¤¤à¥ à¤à¤¸à¤¾ लगता है कि %system_name% से आपको पà¥à¤°à¤¤à¤¿à¤·à¥‡à¤§ किया गया है। कà¥à¤¯à¤¾ आप आशवसà¥à¤¤ है कि आप इस पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ के पोटà¥à¤°à¥‡à¤Ÿ को हटाना चाहते है कà¥à¤¯à¤¾ आप आशवसà¥à¤¤ है कि आप अपना पोटà¥à¤°à¥‡à¤Ÿ हटाना चाहते है सिसà¥à¤Ÿà¤® मे आपका चितà¥à¤° अमानà¥à¤¯ है। कà¥à¤°à¥à¤ªà¥à¤¯à¤¾ आपके अकाउनà¥à¤Ÿ के पà¥à¤°à¤®à¤¾à¤£à¥€à¤•रन मे समसया थी यह वह चितà¥à¤° है जिसे हम अनà¥à¤¯ पà¥à¤°à¤¯à¥‹à¤•ताओ को %system_name% दरà¥à¤¶à¤¾à¤¯à¥‡à¤—े इस पà¥à¤°à¤¯à¥‹à¤•ता का अब तक कोई पोटà¥à¤°à¥‡à¤Ÿ नही है। आप कर सकते है इस पà¥à¤°à¤¯à¥‹à¤•ता को हटा दिया गया है और समà¥à¤¦à¤¾à¤¯ से पà¥à¤°à¤¤à¤¿à¤·à¥‡à¤§ किया गया है। अपने रजिसà¥à¤Ÿà¥à¤°à¥‡à¤¶à¤¨ की पà¥à¤·à¥à¤Ÿà¤¿ के लिये कà¥à¤°à¤ªà¥à¤¯à¤¾ %confirmation_url% पर जाठअपनी मनपसनà¥à¤¦ फ़ाइल अपलोड करे। à¤à¤• सà¥à¤•ेन किया गया जेपीईजी या जीआईà¤à¥ž फ़ाइल को अपने डेसà¥à¤•टाप कमà¥à¤ªà¤¯à¥à¤Ÿà¤° से अपलोड करे। कà¥à¤°à¥à¤ªà¥à¤¯à¤¾ नोट करे कि आप इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ पर कही भी चितà¥à¤° को रेफ़र नही कर सकते, यह चितà¥à¤° आपके कमà¥à¤ªà¤¯à¥à¤Ÿà¤° के हारà¥à¤¡à¤¡à¥à¤°à¤¾à¤‡à¤µ पर होनी चाहिà¤à¥¤ अपलोड किया गया: %pretty_date% अपलोड किया गया: %publish_date% अपनी फ़ाइल का पता लगाने के लिये बà¥à¤°à¤¾à¤‰à¤œ बटन का उपयोग करे और उसके बाद ओपन पर कà¥à¤²à¤¿à¤• करे। इस पà¥à¤°à¤¯à¥‹à¤•ता ने à¤à¤• बायोगà¥à¤°à¤¾à¥žà¥€ समिमिलित की है या à¤à¤• पोटà¥à¤°à¥‡à¤Ÿ अपलोड किया है। हमने आपको पà¥à¤°à¤¯à¥‹à¤•ता टेबल (पà¥à¤°à¤¯à¥‹à¤•ता %user_id%) पर नही पाया । समà¥à¤­à¤µà¤¤ आपका अकाउनà¥à¤Ÿ किसी कारणवश हटा दिया गया है । हमे आपकी इनà¥à¤Ÿà¥à¤°à¥€ के सनà¥à¤¸à¤¾à¤§à¤¨ मे कठिनाई आई है हमे आपके ईमेल की पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ नही थी। इसमे कही कोई गलती अवशय हà¥à¤ˆ है। %system_name% पर आपका सà¥à¤µà¤¾à¤—त है आपके नाम पर कà¥à¤²à¤¿à¤• करने पर अनà¥à¤¯ लोग कà¥à¤¯à¤¾ देख सकेगे। आप अपने पहले नाम मे &amp;lt; नही लगा सकते कà¥à¤¯à¥‹à¤•ि यह à¤à¤š टी à¤à¤® à¤à¤² टेग जैसा दिखेगा और अनà¥à¤¯ पà¥à¤°à¤¯à¥‹à¤•ताओ को भà¥à¤°à¤®à¤¿à¤¤ करेगा। आप अपने आखिरी नाम मे &lt; नही लगा सकते कà¥à¤¯à¥‹à¤•ि यह à¤à¤š टी à¤à¤® à¤à¤² जेसा दिखाई देगा और अनà¥à¤¯ पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾à¤“ को भà¥à¤°à¤®à¤¿à¤¤ करेगा। आप %pretty_date% के बाद कोई ईमेल पà¥à¤°à¤¾à¤ªà¥à¤¤ नही कर सकेगे आपके ई-मेल की पà¥à¤·à¥à¤Ÿà¤¿ की जाती है। अब आप %system_name% मे लोग आन कर सकते है। आपके ई-मेल की पà¥à¤·à¥à¤Ÿà¤¿ की जाती है। अब आपको %system_name% पà¥à¤°à¤¶à¤¾à¤¸à¤• से सवीकà¥à¤°à¤¤à¤¿ मिलनी है। आपके ई-मेल की पà¥à¤·à¥à¤Ÿà¤¿ हो चà¥à¤•ी है। आपका लोगिन कालातीत हो चà¥à¤•ा है। कà¥à¤°à¤ªà¥à¤¯à¤¾ कारà¥à¤¯ जारी रखने के लिये अपना पासवरà¥à¤¡ दà¥à¤¬à¤¾à¤°à¤¾ टाइप करे। आपका यूआरà¤à¤² सही रà¥à¤ª मे नही है। मानà¥à¤¯ यूआरà¤à¤² &quot;%valid_url_example%&quot; की तरह होगा। पà¥à¤°à¤¶à¤¾à¤¸à¤• बनाठसदसà¥à¤¯ बनाठसà¥à¤µà¤¯ को अदà¥à¤°à¤¶à¤¯ बनाये सà¥à¤µà¤¯ को दिखाठअपनी सूचना को वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ करे कà¥à¤·à¤®à¤¾ करे आपको सदसà¥à¤¯à¥‹ की सूची देखने की अनà¥à¤®à¤¤à¤¿ नही है। सदसà¥à¤¯ का राजà¥à¤¯ सदसà¥à¤¯à¥‹ नाम नया पासवरà¥à¤¡ कोइ आवेदन नही कोई आईà¤à¤¸à¤“ कोड नही इस पेकेज मे कोई पेरामीटर नही है। आपका पोरà¥à¤Ÿà¥à¤°à¥ˆà¤Ÿ %pretty_plural% नही कोई सेवा नही कोई नही लोग इन नही किया नोटस: सूचना: को %name% पर: (वेकलà¥à¤ªà¤¿à¤•) विकलà¥à¤ª या à¤à¤• नया पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ को शामिल करे या पासवरà¥à¤¡ %system_name%: %account_id_label%: %account_id% पर आपकी लोगिन समà¥à¤¬à¤¨à¥à¤§à¥€ जानकारी है। इस अकाउणà¥à¤Ÿ के लिये आपका पासवरà¥à¤¡ हाल ही मे बदला गया है। आपकओ कà¥à¤› करने की आवशà¥à¤¯à¤•à¥à¤¤à¤¾ नही है। यह सनà¥à¤¦à¥‡à¤¶ आपके अकाउणà¥à¤Ÿ की सà¥à¤°à¤•à¥à¤·à¤¾ के लिये सामानà¥à¤¯ सूचना मातà¥à¤° है। आप हमेशा निमà¥à¤¨ पà¥à¤°à¤•ार से अपना पासवरà¥à¤¡ बदल सकते है: 1. %system_name% मे लोग इन करे 2. &quot;%pvt_home_name%&quot; लिनà¥à¤• पर कà¥à¤²à¤¿à¤• करे 3. &quot;%password_update_link_text%&quot; का चयन करे पासवरà¥à¤¡ बदल दिया गया है। अनà¥à¤®à¤¤à¤¿à¤¯à¤¾ अनà¥à¤®à¤¤à¤¿à¤¯à¤¾ %name% के लिये अनà¥à¤®à¤¤à¤¿ कà¥à¤°à¤ªà¥à¤¯à¤¾ %home_link% पर वापिस चले पोटà¥à¤°à¥‡à¤Ÿ रà¥à¤ªà¤°à¥‡à¤–ा पà¥à¤°à¤¶à¤¨ दà¥à¤¬à¤¾à¤°à¤¾ योगà¥à¤¯ बनाठपासवरà¥à¤¡ दà¥à¤¬à¤¾à¤°à¤¾ पà¥à¤°à¤¾à¤ªà¥à¤¤ करे लोगिन ताजा करे हिसाब बही &lt;p&gt; %system_name% पर रजिसà¥à¤Ÿà¤° करने के लिये धनà¥à¤¯à¤µà¤¾à¤¦à¥¤ à¤à¤• पà¥à¤°à¤¶à¤¾à¤¸à¤• को आपके अनà¥à¤°à¥‹à¤§ पर सूचित किया गया है। &lt;/p&gt; &lt;p&gt; à¤à¤• बार आपके लिये सà¥à¤µà¥€à¤•à¥à¤°à¤¤à¤¿ मिलने पर आपको à¤à¤• ईमेल पà¥à¤°à¤¾à¤ªà¥à¤¤ होगा और आप %system_name% का उपयोग करते हà¥à¤ शà¥à¤°à¥à¤µà¤¾à¤¤ मे वापस हो सकते है &lt;/p&gt; असà¥à¤µà¥€à¤•ार इस कमà¥à¤ªà¥‚टर पर मेरा लोगिन याद रखो हटाओ सभी कà¥à¤› हटाओ इस समà¥à¤¦à¤¾à¤¯ की सदसà¥à¤¯à¤¤à¤¾ के लिये अनà¥à¤°à¥‹à¤§ करे इस सबसाईट की सदसà¥à¤¯à¤¤à¤¾ के लिये अनà¥à¤°à¥‹à¤§ करे सदसà¥à¤¯à¤¤à¤¾ के लिये अनà¥à¤°à¥‹à¤§ आवेदन पर वापिस आये रदà¥à¤¦ किये गये को चेक किया है कारà¥à¤¯ टिपà¥à¤ªà¥à¤£à¥€ को सेव करे परà¥à¤¦à¥‡ का नाम विधमान पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ को खोजे सà¥à¤°à¤•à¥à¤·à¤¾ सनà¥à¤¦à¤°à¥à¤­ मूल आईडी दà¥à¤µà¤¾à¤°à¤¾ किसी वसà¥à¤¤à¥‚ को चà¥à¤¨à¥‡: इस पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ को ईमेल भेजे दरà¥à¤¶à¤¾à¤ सà¥à¤¥à¤¾à¤¨-विसà¥à¤¤à¤°à¥à¤£ पà¥à¤°à¤¶à¤¾à¤¸à¤¨ कà¥à¤·à¤®à¤¾ कीजिठआप अपना पासवरà¥à¤¡ भूल गये है इसमे हम आपकी मदद नही करे सकेगे सà¥à¤¥à¤¿à¤¤à¤¿ फ़ोटो के पीछे की कहानी फ़ोटो के पीछे की कहानी उप-समà¥à¤¦à¤¾à¤¯ उप-समà¥à¤¦à¤¾à¤¯ उप-समà¥à¤¦à¤¾à¤¯ सबसाईट सबसाईटे सबसाईटे आपका धनà¥à¤¯à¤¾à¤µà¤¾à¤¦ इस सरà¥à¤µà¤° पर आईà¤à¤¸à¤“ कोड भरे नही गये है। यह समूह बनà¥à¤¦ है। नये सदसà¥à¤¯ केवल आमनà¥à¤¤à¥à¤°à¤£ दà¥à¤µà¤¾à¤°à¤¾ इस तक पहà¥à¤š सकेगे। यह सबसाईट इस पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ ने समà¥à¤¦à¤¾à¤¯ को छोड दिया है। कà¥à¤°à¤ªà¥à¤¯à¤¾ अपने इन-बोकà¥à¤¸ की जानà¥à¤š करे। कà¥à¤› ही मिनà¥à¤Ÿà¥‹ मे आपको %system_owner% से इस विषय पर निरà¥à¤¦à¥‡à¤¶à¥‹ के साथ à¤à¤• सनà¥à¤¦à¥‡à¤¶ भेजा जायेगा विषय विशिषà¥à¤Ÿ जानकारी टाईप करे उपर %context_name% तक अघतन पासवरà¥à¤¡ को अघतन करे अघतन करे पोरà¥à¤Ÿà¥à¤°à¥‡à¤Ÿ अपलोड करे बदले जाने वाले पोरà¥à¤Ÿà¥à¤°à¥‡à¤Ÿ को अपलोड करे पोरà¥à¤Ÿà¥à¤°à¥‡à¤Ÿ को अपलोड करे पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ का नाम पà¥à¤°à¤¯à¥‹à¤•à¥à¤¤à¤¾ के सà¥à¤¥à¤¾à¤¨ का नकशा छà¥à¤Ÿà¤¿à¤¯à¥‹ से समà¥à¤¬à¤¨à¥à¤§à¤¿à¤¤ जानकारी को अघतन किया गया है। %site_link% पर आपकी छà¥à¤Ÿà¤¿à¤¯à¥‹ के समà¥à¤¬à¤¨à¥à¤§à¤¿à¤¤ जानकारी को अघतन किया गया है। %user_name% सà¥à¤µà¤¾à¤—त है। जब आप यह चेक बोकà¥à¤¸ को खाली छोड देते है तब आपके दà¥à¤µà¤¾à¤°à¤¾ चयन किये गये पारà¥à¤Ÿà¥€ दà¥à¤µà¤¾à¤°à¤¾ पà¥à¤°à¤¿à¤µà¤¿à¤²à¥‡à¤œ को रिवोक किया जायेगा, यदि उस पारà¥à¤Ÿà¥€ को इसकी पहले ही अनà¥à¤®à¤¤à¤¿ दी गयी है। पà¥à¤°à¤¯à¥‹à¤•ता अभी ओन लाईन है। ओन लाइन कोन है? जी हा! मे आशà¥à¤µà¤¸à¥à¤¤ हू। आप निमà¥à¤¨à¤²à¤¿à¤–ित समूह मे है: आप ...... से भी बà¥à¤°à¤¾à¤‰à¤œ कर सकते है। आप ..... दà¥à¤µà¤¾à¤°à¤¾ हमेशा पà¥à¤¨:ओपन कर सकते है। उदà¥à¤¦à¥‡à¤¶à¤¯ %root% या इसके किसी बचà¥à¤šà¥‹ पर आपको पà¥à¤°à¤¶à¤¾à¤¸à¤¨ का अधिकार नही है। अभी तक आपका पोरà¥à¤Ÿà¥à¤°à¥‡à¤Ÿ नही है। आप पा सकते है। निमà¥à¤¨à¤²à¤¿à¤–ित उदà¥à¤¦à¥‡à¤¶à¤¯à¥‹ पर आपका पà¥à¤°à¤¶à¤¾à¤¸à¤¨à¤¿à¤• अधिकार है: फ़िलहाल आपका कोई ईमेल à¤à¤²à¤°à¥à¤Ÿ रजिसà¥à¤Ÿà¤° नही किया गया है। आपका अकाउणà¥à¤Ÿ आपका चरà¥à¤šà¤¾ फ़ोरम अलरà¥à¤Ÿ आपका चितà¥à¤° %gc_system_name% अपनी चेतावनियां आपको %site_link% पर छà¥à¤Ÿà¤¿à¤¯à¥‹ से वापिस आने पर चिनà¥à¤¹à¤¿à¤¤ किया गया है। openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.ro_RO.utf-8.xml0000644000175000017500000005717310727201372025350 0ustar frankiefrankie , sau ActualizaÅ£i InformaÅ£iile de Bază Membru al comunităţii %system_name% din Despre Tine Contul tau pe %system_name% a fost închis Nu, du-mă înapoi la %pvt_home_name% Da, te rog închide-mi contul <p>Contul dumneavoastră este deocamdată închis.</p><p>Daca doriÅ£i, putem <a href="%restore_url%"> să vă redeschidem contul</a>.</p> <p> <font color="red"> <b> Contul dumneavoastră este deocamdată închis.</b></font><a href="%login_url%">IntraÅ£i</a> din nou ÅŸi vedeÅ£i dacă puteÅ£i rezolva ceva. </p&;gt; Contul dumneavoastră pe %system_name% a fost redeschis. Bine aÅ£i revenit. Cont Redeschis AcÅ£iune Adaugă o nouă aplicaÅ£ie Admin Administrează %subsite_name% OpÅ£iuni administrative pentru acest utilizator Tipul Alertei încă o imagine Răspuns Eroare de program AplicaÅ£ii Abrobă la Autoritate Parolă GreÅŸită Interzice InformaÅ£ii pe scurt Biografie Recuperarea parolei de la autoritatea locala nu este posibilă Lista membrilor nu poate fi afiÅŸată Schimbă limbajul Schimbă-Å£i Parola Schimbă-Å£i Parola, email-ul, portretul Verifică casuÅ£a poÅŸtală electronică Copii <p> Vă rugăm să confirmaÅ£i ca doriÅ£i sa vă inchideÅ£i contul pe %system_name%.</p><p> Dacă închideÅ£i acest cont nu vă vom putea trimite notificări prin email ÅŸi nici nu veÅ£i mai apare în lista membrilor pe %system_name%. Pe de altă parte, contribuÅ£iile dumneavoastră vor fi păstrate, ele făcând parte din istoria comunităţii.</p><p>ReÅ£ineÅ£i că puteÅ£i să vă redeschideÅ£i contul oricând - aceasta se face prin simpla reintrare în sistem folosind detaliile de autentificare ale acestui cont. ÃŽnchide contul Grup Inchis Comentează Comunităţi comunităţi comunitate Confirmă You have successfully chosen a new password. Continuă Continue to %pvt_home_name% Numele Ţării Creează un nou %pretty_name% Creează un subsite nou Parola curentă <p>Starea dumneavoastră online nu este momentan vizibilă celorlalÅ£i utilizatori</p> <p> Starea dumneavoastră online este momentan vizibilă celorlalÅ£i utilizatori</p> Personalizează ÃŽntrebarea Eroare in Baza de date contextul obisnuit Åžterge DevAdmin Administrare pentru Programator Permisiuni Directe Scoate din uz Scos din uz Domeniu Email modifică comentariul Anumite elemente nu sunt modificabil, deoarece ele sunt administrate de către %authority_name%. Email Acestea sunt noile dumneavoastră detalii de autentificare: %account_id_label%: %account_id% %password_label%: %password% Vă rugăm vizitaÅ£i urmatorul link pentru a schimba parola: %reset_password_url% Vă mulÅ£umim pentru înregistrarea pe %system_name%. Acestea sunt detaliile dumneavoastră de autentificare pe %system_url%: %account_id_label%: %account_id% %password_label%: %password% Vă rugăm vizitaÅ£i urmatorul link pentru a schimba parola: %reset_password_url% Confirmare prin Email Email nu a fost Solicitat V-aÅ£i uitat parola pentru %system_name% Bine aÅ£i venit pe %system_name% Activat IntroduceÅ£i numele dumneavoastră de utilizator pentru a începe procesul de recuperare a parolei. Åžterge Portretul ÅŸterge portretul Eroare Eroare de trimitere a email-ului Expiră Numele FiÅŸierului Prenume AÅ£i uitat parola ? Frecvenţă ÃŽnapoi ÃŽncarcă portretul utilizatorului încarcă portretul utilizatorului Oferă Oferă Permisiune Ascunde Pagina principală Dacă aÅ£i InformaÅ£ie Actualizată Invită Cod ISO Lista de Coduri ISO Codurile ISO Nu au fost încărcate Codurile ISO nu au fost încărcate ÃŽnscrie-te în comunitate ÃŽnscrie-te în %group_name% ÃŽnscrie-te în subsite ÃŽnscrie-te în această comunitate ÃŽnscrie-te în acest subsite Cuvănt cheie Nume de familie mai târziu. PărăseÅŸte comunitatea IeÅŸi din subsite PărăseÅŸte această comunitate IeÅŸi din acest subsite ÃŽnapoi fără a mai adăuga utilizatori Intră intră Intră în %system_name% Reautentificare în sistem Pagina de autentificare a expirat. Vă rugăm sa vă reautentificaÅ£i Autentificare sau înregistrare pagina de autentificare IeÅŸire IeÅŸi afară din %system_name% , aÅ£i putea să aveÅ£i ÅŸi alte informaÅ£ii despre colegul dumneavoastră din comunitate Nu poÅ£i să te înscrii în acest grup Listă completă a codurilor ISO Continuă să lucrezi cu %system_name% Modifică comentariul pentru portretul lui %first_names% %last_name% %first_names% %last_name% (%email%) înregistrat ca utilizator al %system_url% Pentru Administratorii întregului Sistem Oferă Permisiuni pe %name% Baza de date a raportat următoarele: Cum doriÅ£i să vadă lumea %first_names% %last_name%? Dacă nu credeÅ£i ca persoana are deja un cont: Dacă ÅŸtiÅ£i cumva sau credeÅ£i ca persoana pe care doriÅ£i să o inivitaÅ£i are deja un cont în acest sistem: Dacă aveÅ£i nevoie de această funcÅ£ionalitate, vă rugăm încărcaÅ£i acs-reference and ref-countries. Permisiuni MoÅŸtenite E o idee foarte proastă să alegeÅ£i această opÅ£iune dacă folosiÅ£i un computer comun într-o bibliotecă sau o ÅŸcoală. Oricare alt utilizator care vine după dumneavoastră ar putea să se folosească de contul dumneavoastră pe serviciul nostru. ÃŽnregistrare nouă pe %system_url% De observat că textul în roÅŸu sub căsuÅ£ele pentru parametri, indică că valoarea acestui parametru este înlocuită de către o valoare în fiÅŸierul parametrului OpenACS. Utilizarea acestui fiÅŸier este descurajată dar anumite site-uri au nevoie de asta pentru a putea oferi valori specifice momentane pentru parametri independent de tabelele apm_parameter. De observat ca puteÅ£i ÅŸterge adresa de email ÅŸi parola salvată de dumneavoastră alegând opÅ£iunea "log out" din spaÅ£iul dumneavoastră de lucru. %num_children% Copii AscunÅŸi Pe data de %portrait_publish_date%, aÅ£i încărcat <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Serverul nostru poate indica browser-ului să-ÅŸi amintească anumite detalii cum ar fi adresa de email ÅŸi parola. Asta e de folos pentru dumneavoastră pentru că dacă sunteÅ£i singura persoană care utilizează acest calculator, nu va mai trebui să tot introduceÅ£i adresa de email ÅŸi parola pentru a folosi sistemul nostru. Confirmare Parolă URL pentru pagina principală personală Vă rugăm să localizaÅ£i codul ţării dumneavoastră prin cele listate mai jos ÅŸi apoi să utilizaÅ£i butonul "back"/"înapoi" în browser-ul dumneavoastră pentru a vă întoarce la formularul precedent Vă rugăm să citiÅ£i ÅŸi să urmaÅ£i instrucÅ£iunile din acest email Vă rugăm încercaÅ£i să <a href="index">vă logaÅ£i</a> din nou Portretul lui %first_names% %last_name% Privilegii superioare în ierarhie includ toate privilegiile de desubt, de exemplu atunci când se acordă privilegiul de administrare, atunci permisiunea de citit, scris etc sunt incluse automat Problemă cu autentificarea InformaÅ£iile legate de înregistrare au fost deja trimise la %email%. InformaÅ£iile referitoare la înregistrare pentru acest serviciu au fost deja trimise la %email%. Cererea dumneavoastră de înregistrare a fost trimisă la administratorul pentru %system_name%. AÅŸteaptă încă să fie abrobată Se salvează adresa de email ÅŸi parola ArătaÅ£i tuturor pe %system_name% cât de bine arătaÅ£i: Ne cerem scuze dar se pare că vi s-a interzis accesul pe %system_name%. SunteÅ£i sigur că vreÅ£i să ÅŸtergeÅ£i portretul acestui utilizator ? SunteÅ£i sigur că vreÅ£i să vă ÅŸtergeÅ£i portretul ? Această a dumneavoastră în sistem nu este valabilă. Vă rugam A apărut o problemă în autentificarea contului dumneavoastră Aceasta este imaginea pe care noi o arătăm celorlalÅ£i utilizatori din %system_name% Acest utilizator nu are încă un portret. PuteÅ£i Acest utilizator este ÅŸters ÅŸi i s-a interzis accesul din această comunitate Pentru a confirma înregistrarea vă rugăm să mergeÅ£i la %confirmation_url% ÃŽncărcaÅ£i fiÅŸierul dumneavoastră favorit, un fiÅŸier tip GIF sau JPEG scanat, din calculatorul dumneavoastră (de reÅ£inut că nu puteÅ£i face referinţă la o imagine aflată undeva pe internet; această imagine trebuie să se afle stocată în memoria de lungă durată (hard-drive-ul) calculatorului dumneavoastră). ÃŽncarcat: %pretty_date% ÃŽncarcat: %publish_date% UtilizaÅ£i butonul "Browse..." pentru a localiza fiÅŸierul, apoi apăsaÅ£i "Open". Acest utilizator a introdus o biografie sau a încărcat un portret Nu vă putem găsi(utilizatorul %user_id%) în tabelul utilizatorilor. Probabil contul dumneavoastră a fost ÅŸters dintr-un motiv sau altul. Am întâmpinat o problem în prelucrarea informaÅ£iei introduse de dumneavoastră Nu ne aÅŸteptam să primim email-ul dumneavoastră. Trebuie să fie vreo greÅŸeală Bine aÅ£i venit pe %system_name% Ce văd alÅ£i oameni când dau click pe numele dumneavoastră Nu puteÅ£i aveal un &lt; în prenume pentru că apare ca un cod HTML ÅŸi poate apare confuz pentru ceilalÅ£i utilizatori Nu puteÅ£i aveal un &lt; în numele de familie pentru că apare ca un cod HTML ÅŸi poate apare confuz pentru ceilalÅ£i utilizatori Nu veÅ£i primi nici un email până după %pretty_date%. Email-ul dumneavoastră a fost confirmat. Acum puteÅ£i să vă autentificaÅ£i în sistemul %system_name%. Email-ul dumneavoastră a fost confirmat. Acum trebuie să aÅŸteptaÅ£i aprobarea din partea administratorului sitemului %system_name%. Email-ul dumneavoastră este confirmat. Autentificarea dumneavoastră a expirat. Vă rugăm să reintroduceÅ£i parola pentru a continua. URL-ul dumneavoastră nu respectă forma corectă. Un URL valabil este ceva de genul acesta "%valid_url_example%". Creează un nou administrator Creează un nou membru Fă-te invizibil Fă-te vizibil Administrează-Å£i notificările Scuze, dar nu vi se permite să vedeÅ£i lista membrilor Stat Membru Membri Nume Parolă nouă Nu există aplicaÅ£ii Nu există Coduri ISO Această aplicaÅ£ie nu are nici un parametru portretul tău Nu există %pretty_plural% Nu există servicii nimic Neautentificat Note: Notificare: pe %name% la: (opÅ£ional) OpÅ£iuni Sau adaugă un nou utilizator sau Parola InformaÅ£ia de autentificare pe %system_name%: %account_id_label%: %account_id% Parola dumneavoastră pentru acest cont a fost schimbată recent. Nu este necesară vreo acÅ£iune din parte dumneavoastră, acest mesaj este o simplă notificare pentru a proteja securitatea contului dumneavoastră.--------------- PuteÅ£i schimba parola oricând în modul următor: 1. AutentificaÅ£i-vă în %system_name% 2. ApăsaÅ£i pe linkul "%pvt_home_name%" 3. AlegeÅ£i "%password_update_link_text%" Parola a fost schimbată Permisiuni permisiuni Permisiuni pentru %name% Vă rugăm reveniÅ£i la %home_link%. Portret Profil ÃŽntrebare Re-activează RecuperaÅ£i Parola Reactualizează acest login ÃŽnregistraÅ£i-vă <p> Vă mulÅ£umim pentru înregistrarea pentru for %system_name%. Unul dintre administratori a fost anunÅ£at de cererea dumneavoastră. </p> <p> De îndată ce veÅ£i fi aprobat, veÅ£i primi un mesaj prin email ÅŸi vă veÅ£i putea întoarce să folosiÅ£i sistemul %system_name%. </p> Respinge AminteÅŸte-Å£i de autentificare mea pe acest calculator Elimină ÅžtergeÅ£i-le pe Toate Cere să fii membru în această comunitate Inscrie-te ca membru in acest subsite Cere calitate de membru întoarce-te la formularul de cerere Anularea este Selectată Rol Salvează comentariul Pseudonim Caută un Utilizator deja Existent rădăcina contextului de securizare Selectează un obiect după Id-ul său: Trimite un email acestui utilizator Arată Administrarea întregului sistem Ne cerem scuze dar nu vă putem ajuta în ceea ce priveÅŸte parola uitată SituaÅ£ie curentă Subtextul Fotografiei Povestea Fotografiei Subcomunităţi subcomunităţi subcomunitate subsite Subsite-uri subsite-uri MulÅ£umim Codurile ISO nu au fost încărcate pe acest server Acest grup este inchis. Noi membri au acces numai cu invitatie acest subsite Acest utilizator a părăsit comunitatea Pentru autentificare, vizitaÅ£i Topic informaÅ£ie tip-specifică SUS până la %context_name% Actualizează Actualizează parola încarcă încarcă un portret încarcă un portret înlocuitor ÃŽncarcă Portret Nume de utilizator Harta Site-ului pentru Utilizator InformaÅ£ie de Vacanţă Actualizată InformaÅ£ia dumneavoastră de vacanţă pe %site_link% a fost actualizată Bine aÅ£i venit, %user_name% Daca lăsaÅ£i aceasta casuţă nebifată atunci acest privilegiu va fi retras de la partea respectivă în cazul în care i-a fost acordat respectivul privilegiul inainte. Utilizatori conectaÅ£i acum Cine e Conectat Da, sunt sigur AparÅ£ii următoarelor grupe: PuteÅ£i răsfoi de asemenea ÅŸi de pe PuteÅ£i oricând să-l redeschideÅ£i prin Nu aveÅ£i drepturi administrative asupra acestui obiect %root% sau asupra oricăreia dintre ramurile sale Nu aveÅ£i un portret încă. PuteÅ£i AveÅ£i drepturi administrative asupra următoarelor obiecte: ÃŽn prezent nu aveÅ£i setat nici un sistem de reamintire automată prin email. Contul Dumneavoastră Semne de aducere aminte pentru forumurile dumneavoastră Portretul Dumneavoastră Mesaje automate transmise dumneavoastră de pe %gc_system_name ApăreÅ£i ca venit din vacanţă pe %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.pl_PL.utf-8.xml0000644000175000017500000006100710727201372025325 0ustar frankiefrankie , lub Zaktualizuj Podstawowe Informacje CzÅ‚onek %system_name% od O Tobie Twoje konto w %system_name% zostaÅ‚o zamkniÄ™te. Nie, wróć do %pvt_home_name% Tak, proszÄ™ zamknąć moje konto <p>Twoje konto jest aktualnie zamkniÄ™te.</p> <p>JeÅ›li chcesz możemy <a href="%restore_url%"> je otworzyć ponownie</a>.</p> Konto ZamkniÄ™te p> <font color="red"> <b> Twoje konto jest obecnie zamkniÄ™te. </b> </font> <a href="%login_url%">Zaloguj siÄ™</a> ponownie i zobacz co w tej sprawie możesz zrobić. </p&;gt; To konto jest w tej chwili niedostÄ™pne. Twoje konto w %system_name% zostaÅ‚o otwarte. Witamy ponownie. Konto otwarte ponownie. Operacja Dodaj dodaj folder Dodaj nowÄ… aplikacjÄ™ Dodaj tego użytkownika Dodaj Użytkownika Dodaj użytkowników Admin Admin ZarzÄ…dzaj %subsite_name% Opcje administracyjne dla tego użytkownika Typ zawiadomienia inna ilustracja Odpowiedź: Błąd aplikacji Aplikacje Zatwierdź w WystÄ…Å‚piÅ‚ błąd w trakcie autentykacji Błędne HassÅ‚o Zablokuj Podstawowe Informacje Biografia System nie umożliwia odzyskiwania haseÅ‚. Lista czÅ‚onków jest niedostÄ™pna ZmieÅ„ jÄ™zyk ZmieÅ„ mój poziom prywatnoÅ›ci. ZmieÅ„ Moje HasÅ‚o ZmieÅ„ hasÅ‚o, email, portret Spradź SwojÄ… SkrzynkÄ™ Dzieci Wybierz kwestionariusz rejestracji: Wybierz kwestionariusz, który bÄ™dzie pokazywany nowym użytkownikom.<br> Kwestionariusz ten może być użyty do wykonywania pewnych operacji automatycznie (np.: dodawanie użytkowników do okreÅ›lonych grup, zawiadamianie odpowiednich ludzi o nowych rejestracjach, etc.). <p>ProszÄ™ potwierdź, że chcesz zamknąć swoje konto w %system_name%.</p><p>ZamkniÄ™cie konta oznacza, że nie bÄ™dziemy już wysyÅ‚ać zawiadomieÅ„ mailem ani nie bÄ™dzie dla Ciebie dostÄ™pna lista czÅ‚onków w %system_name%. Twoje zapisy zostanÄ… zachowane, ponieważ sÄ… częściÄ… historii tej wspólnoty.</p><p>W każdej chwili możesz otworzyć swoje konto ponownie po prostu przez zalogowanie siÄ™.</p> Zamknij swoje konto ZamkniÄ™ta grupa Skomentuj Wspólnoty wspólnoty wspólnota Potwierdź: Zmiana hasÅ‚a przebiegÅ‚a pomyÅ›lnie. Kontynuuj Przejdź do %pvt_home_name% Nazwa kraju Utwórz Utwórz nowy kwestionariusz rejestracji Utwórz nowy(-Ä…) %pretty_name% Utwórz nowÄ… sekcjÄ™ Aktualne HasÅ‚o: <p> Twój status online jest w tej chwili niewidoczny dla innych </p> <p> Twój status online jest w tej chwili widoczny dla innych użytkowników.</p> ZmieÅ„ Pytanie Błąd bazy danych kontekst domyÅ›lny UsuÅ„ usuÅ„ DevAdmin Administracja Programisty BezpoÅ›rednie Prawa Wyłącz Wyłączony Domena Email Edytuj Edytuj Wybrany Kwestionariusz edytuj komentarz Opcje Edycji Pewne elementy sÄ… zarzÄ…dzane przez %authority_name%, dlatego też nie można ich edytować. Email Zezwól na kontakt ze mnÄ… za pomocÄ… formularza Zezwól na kontakt za pomocÄ… formularza Pokaż mój Email jako grafikÄ™ Pokaż email jako grafikÄ™ Pokaż mój Email jako tekst Pokaż Email jako tekst Dane Twojego konta: %account_id_label%: %account_id% %password_label%: %password% ProszÄ™ teraz kliknąć ten link, aby zmienić swoje hasÅ‚o: %reset_password_url% DziÄ™kujemy za rejestracjÄ™ w %system_name%. Możesz teraz logować siÄ™ w %system_url% nastÄ™pujÄ…co: %account_id_label%: %account_id% %password_label%: %password% Zmienić hasÅ‚o możesz za pomocÄ… tego linku: %reset_password_url% Potwierdzenie Email Nie pokazuj mojego Email Nie pokazuj Email NiedostÄ™pny Email nie Żądany Email wymagany Twoje zapomniane hasÅ‚o w %system_name% Witaj w %system_name% Włączony Wprowadź swój login, by rozpocząć odzyskiwanie hasÅ‚a. UsuÅ„ Portret usuÅ„ portret Błąd Błąd wysyÅ‚ania poczty WystÄ…piÅ‚ błąd podczas weryfikacji adresu email WystÄ…piÅ‚ błąd podczas rejestracji Twojego konta. WystÄ…piÅ‚ błąd podczas aktualizacji konta Traci ważność Plik Imiona Zapomniane hasÅ‚o? CzÄ™stotliwość Wróć wgraj portret użytkownika wgraj swój portret Przyznaj Przyznaj Prawa DostÄ™pu Istnieje już grupa o takim email Istnieje już użytkownik o takim email. Istnieje już użytkownik o takim loginie. <p><h3>Informacje</h3> Ukryj Strona domowa Zaktualizowano Informacje ZaproÅ› Kod ISO Lista Kodów ISO Kody ISO nie zaÅ‚adowane Lista Kodów ISO nie zaÅ‚adowana Dołącz do spoÅ‚ecznoÅ›ci Dołącz do %group_name% Zapisz siÄ™ do serwisu Zapisz siÄ™ do tej spoÅ‚ecznoÅ›ci Zapisz siÄ™ do tego serwisu SÅ‚owo kluczowe Nazwisko później. Opuść spoÅ‚eczność Opuść serwis Opuść tÄ™ spoÅ‚eczność Opuść ten serwis Wróć, nie dodajÄ…c użytkownika Zaloguj siÄ™ Zaloguj siÄ™ Zaloguj siÄ™ do %system_name% ponowne logowanie w Strona logowania utraciÅ‚a ważność. ProszÄ™ zalogować siÄ™ ponownie. Zaloguj siÄ™ lub zarejestruj strona logowania Wyloguj siÄ™ Wyloguj siÄ™ z %system_name% , pokazano by wiÄ™cej informacji na temat tej osoby. Dodaj zaznaczonych użytkowników do tych, którzy posiadajÄ… prawa do Twojego obiektu. Nie możesz dołączyć do tej grupy Kompletna lista kodów ISO Pracuj dalej z %system_name% Nie dziedzicz po %parent_object_name% Edytuj komentarz do portretu użytkownika %first_names% %last_name% %first_names% %last_name% (%email%) zarejestrowany jako użytkownik %system_url% Dla Administratorów serwera Przyznaj Prawa do %name% Odpowiedź bazy danych: Jak Å›wiat ma widzieć użytkownika %first_names% %last_name%? JeÅ›li wÄ…tpisz w to, że ta osoba ma już konto: JeÅ›li osoba, którÄ… chcesz zaprosić ma już (lub myÅ›lisz, że może mieć) konto w tym systemie: JeÅ›li potrzebujesz tej funkcjonalnoÅ›ci, zaÅ‚aduj acs-reference i ref-conutries. Dziedzicz po %parent_object_name% Dziedzicz prawa po %parent_object_name% Dziedziczone Prawa Jest to zupeÅ‚nie zÅ‚y pomysÅ‚, jeÅ›li używasz publicznego komputera - jak w bibliotece lub szkole. Ktokolwiek, kto użyje tej maszyny po Tobie, bedzie mógÅ‚ siÄ™ pod Ciebie podszyć w tym systemie. Nowa rejestracja w %system_url% Tekst czerwonÄ… czcionkÄ… poniżej pola parametru wskazuje, że wartość tego parametru jest nadpisana przez wpis w pliku konfiguracyjnym OpenACS. Używanie pliku z parametrami jest nie jest zalecane, ale niektóre instalacje wymagajÄ… specyficznych wartoÅ›ci dla każdej instancji niezależnie od tabeli parametrów apm_parameter. Możesz wymazać swoje zapisane email i hasÅ‚o wybierajÄ…c "wyloguj siÄ™" na Twoim Pulpicie. %num_children% Ukrytych Dzieci %portrait_publish_date% wgrano <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Twoja przeglÄ…darka może zapamiÄ™tać Twój email i hasÅ‚o. Jest to wygodne, bo nie musisz ciÄ…gle ich wpisywać - ale bezpieczne TYLKO wtedy gdy JEDYNIE TY używasz komputera z którego odwiedzasz nasz system. Potwierdzenie HasÅ‚a URL Strony Domowej Wskaż kod swojego kraju na tej liÅ›cie i kliknij przycisk "powrót" w swojej przeglÄ…darce by przejść do poprzedniego formularza. ProszÄ™ wypeÅ‚nić instrukcje podane w niniejszym mailu. ProszÄ™ <a href="index">zalogować siÄ™</a> ponownie Portret użytkownika: %first_names% %last_name% Przywilej wyższy w hierarchii zakÅ‚ada przywileje niższe. To znaczy jeÅ›li przyznasz prawa "admin", prawa "czytaj", "pisz", etc. sÄ… przyznawane automatycznie. Problem potwierdzenia tożsamoÅ›ci Informacja o rejestracji w tym serwisie zostaÅ‚a wysÅ‚ana do %email%. Informacja o rejestracji w tym serwisie zostaÅ‚a wysÅ‚ana do %email%. Twój wniosek o rejestracjÄ™ zostaÅ‚ wysaÅ‚any administratorowi %system_name%, ale jeszcze nie zostaÅ‚ zatwierdzony. Zapisywanie adresu i hasÅ‚a Pokaż wszystkim w %system_name% jak wyglÄ…dasz: Przykro to napisać, ale wyglÄ…da na to że wyrzucono CiÄ™ z %system_name%. Wstrzymaj dziedziczenie praw po %parent_object_name% Czy na pewno chcesz usunąć portret tego użytkownika? Czy na pewno chcesz usunąć swój portret? Twój portret w systemie jest nieprawidÅ‚owy. ProszÄ™ Nie ma już użytkowników, którzy by nie mieli praw do tego obiektu. WystÄ…piÅ‚ problem z weryfikacjÄ… Twojego konta To jest portret, który prezentujemy innym w %system_name% Ten użytkownik nie ma jeszcze portretu. Możesz Ten użytkownik jest usuniÄ™ty i zablokowany. ProszÄ™ przejść do %confirmation_url%, by potwierdzić swojÄ… rejestracjÄ™. Wgraj swój ulubiony plik, skan JPEG lub GIF, z Twojego kmputera ( plik musi być lokalnie na tym komputerze; nie możesz podać adresu pliku skÄ…dÅ› w Internecie ). Wgrano: %pretty_date% Wgrano: %publish_date% Użyj przycisku "przeglÄ…daj..." by wskazać plik, nastÄ™pnie kliknij "Otwórz". Ten użytkownik wpisaÅ‚ biografiÄ™ lub wgraÅ‚ portret Nie można odnaleźć CiÄ™ (użytkownik %user_id%) w tabeli. Prawdopodobnie Twoje konto zostaÅ‚o z jakigoÅ› powodu usuniÄ™te. MieliÅ›my problem z przetwarzaniem Twoich danych. Nie oczekiwaliÅ›my na email od Ciebie. GdzieÅ› musi być usterka. Witaj w %system_name%. Co inni widzÄ…, gdy kliknÄ… Twój link Twoje imiÄ™ nie może zawierać &lt; bo bÄ™dzie to wyglÄ…daÅ‚o jak HTML i może mylić innych. Twoje nazwisko nie może zawierać &lt; bo bÄ™dzie to wyglÄ…daÅ‚o jak HTML i może mylić innych. Musisz podać co najmniej jednÄ… wartość z object_id_one lub object_id_two Do %pretty_date% nie otrzymasz żadnej poczty. Twój email zostaÅ‚ potwierdzony. Możesz teraz logować siÄ™ do %system_name%. Twój email zostaÅ‚ potwierdzony. Oczekujesz teraz na zatwierdzenie administratora %system_name%. Twój email jest potwierdzony Twój login jest nieaktualny. ProszÄ™ ponownie wpisać hasÅ‚o. Twój URL ma błędnÄ… formÄ™. PrzykÅ‚ad prawidÅ‚owego URL to \"%valid_url_example%\"." WyÅ›lij email do: Utwórz administratora Utwórz czÅ‚onka Ukryj swój status online Pokaż swój status online ZarzÄ…dzaj prywatnoÅ›ciÄ… Email użytkowników ZarzÄ…dzaj zawiadomieniami Przykro nam, ale nie możesz zobaczyć listy czÅ‚onków. CzÅ‚onek Status czÅ‚onka CzÅ‚onkowie BrakujÄ…cy argument zamontuj Moje Konto Nazwa nowa aplikacja Nowe HasÅ‚o: Brak aplikacji Brak sprawdzianów. Brak kodów ISO Ten pakiet nie posiada żadnych parametrów. Twój portret Brak %pretty_plural% Brak usÅ‚ug Nie ma użytkownika o takim loginie żaden Nie zalogowany To nie jest ważny adres email Notatki: Uwaga: Opcje Lub dodaj nowego użytkownika lub Parametry parametry HasÅ‚o: HasÅ‚o zostaÅ‚o zmienione Twoje hasÅ‚o musi być zmieniane regularnie. Prosimy o zmianÄ™ hasÅ‚a teraz. HasÅ‚a nie pasujÄ… To prawo nie może być usuniÄ™te. Prawa prawa Prawa dla %name% ProszÄ™ powrócić do %home_link%. Portret Prywatność Profil Pytanie: Włącz ponownie Czytaj Odzyskaj HasÅ‚o OdÅ›wież login Kwestionariusz Rejestracyjny Użytkownika Rejestruj Odrzuć PamiÄ™taj mój login na tym komputerze UsuÅ„ UsuÅ„ Wszystkie zmieÅ„ nazwÄ™ PoproÅ› o czÅ‚onkowstwo w tej spoÅ‚ecznoÅ›ci Złóż proÅ›bÄ™ o czÅ‚onkowstwo powróć do aplikacji OdwoÅ‚aj Zaznaczone Rola Zapisz komentarz Pseudonim Pseudonim już zostaÅ‚ przez kogoÅ› wybrany. Szukaj IstniejÄ…cego Użytkownika Wybierz Obiekt wg. Id: WyÅ›lij email do tego użytkownika PrzeÅ›li mi kopiÄ™: Pokaż Przepraszamy, nie możemy pomóc Ci w przypadku zapomnianego hasÅ‚a. Status Historia o Fotografii Historia o Fotografii DziÄ™kujemy. Kody ISO jeszcze nie zostaÅ‚y zaÅ‚adowane do tego serwera. Ta grua jest zamkniÄ™ta. Nowi czÅ‚onkowie mogÄ… siÄ™ zapisać tylko przez zaproszenie. Użytkownik opuÅ›ciÅ‚ spoÅ‚eczność. Sprawdź swojÄ… skrzynkÄ™ pocztowÄ…. W ciÄ…gu kilku minut powinien znaleźć siÄ™ tam email od %system_owner% z instrukcjami do Temat Nieznany email odmontuj do %context_name% OdÅ›wież OdÅ›wież HasÅ‚o wgraj wgraj portret wgraj portret na zamianÄ™ Wgraj Portret Portret Użytkownika Portrety Użytkownika Profil Użytkownika Profile Użytkownika Login Login wymagany Mapa Serwisu Użytkownika Informacje o Urlopach Zaktualizowane Twoje informacje o urlopach w %site_link% zostaÅ‚y zaktualizowane Witaj, %user_name% Użytkownicy online Kto jest Online Napisz Tak, na pewno JesteÅ› w nastÄ™pujÄ…cych grupach: Możesz także przeglÄ…dać z Zawsze możesz otworzyć to przez Nie masz praw administracyjnych do obiektu %root% ani do jego dzieci Nie masz jeszcze portretu. Możesz Masz prawo do administracji nastÄ™pujÄ…cymi obiektami: Nie masz obecnie zarejestrowanych żadnych alertów email. Twoje Konto Twoje alerty z formu dyskusyjnego Twój Portret Twoje alerty z %gc_system_name% Zazanaczono Twój powrót z wakacji na %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.en_US.ISO-8859-1.xml0000644000175000017500000011602511553376447025607 0ustar frankiefrankie , or Update Basic Information A member of the %system_name% community since About you Your account at %system_name% has been closed. No, take me back to %pvt_home_name% Description please - does this refer to 'Close account' on the 'Your(/My) Account' page? Where ist the user taken if he doesn't confirm? On the 'MySpace' page? (pvt=private?) --Anja Wicht Yes, please close my account <p>Your account is currently closed.</p> <p>If you wish, we can <a href="%restore_url%">reopen your account</a>.</p> Account Closed <p> Your account is currently <strong>closed</strong>. <a href="%login_url%">Log in</a> again to see what you can do about it. </p> This account is not available at this time. Your account at %system_name% has been reopened. Welcome back. Account Reopened Action Add Add a group of this type Add a permissible relationship type Add an attribute Add another hostname/URL pair Add application Add Applications add folder Add group type Add multiple applications Add new application Add Pair Add permissible relationship type Add a relationship type for %group_type% Add this user Add type Add User Add users Additional Information Control Panel Admin Administer %subsite_name% Administration Administrative options for this user Advanced Advanced Features Alert Type Alias another picture. Answer Anyone Application Application Error Application name Applications Approve at Attributes can only be added by programmers since this object type is not dynamically created Attributes of this type of group Internal error during authentication Login type Bad Password Ban Basic Information Biographies Biography Biography Mime Type Biography Mime Types Build Site Map by group type Retrieving password from local authority is not supported. Cannot see the members list Caption Change language Change your email privacy level Change your password Change password, email, portrait You have (or someone impersonating you has) requested to change your system password. To complete the change, visit the following link: If you are not the person who made this request, you don't need to take any action. Change Password Request for Check Your Inbox Children Choose a custom registration questionnaire : Pick the questionnaire that will be displayed to new users.<br> It can be used to perform automated actions (e.g. add users to specific groups, notify specific people about new registrations, etc.). Choose the layout and navigation theme you want for your subsite. <p> Please confirm that you would like to close your account at %system_name%. </p> <p> Closing your account means that we will no longer send you email notifications, nor will you show up in lists of members at %system_name%. Your contributions to the community, however, will be preserved, as they're part of the community's history. </p> <p> Note that you may reopen your account at any time, simply by logging in again. </p> Close your account Closed Group Comment Communities communities community Configuration Configure Confirm You have successfully chosen a new password. Continue Continue to %pvt_home_name% Core Services Country Name Create Create a new relationship type Create a new custom registration questionnaire Create new application Create new %pretty_name% Create new subsite Create relation type Current Password Your online status is currently not visible to other users. Currently the %instance_name% has the following groups Currently, the system is able to handle the following types of groups Currently the system is able to handle the following relational segments Currently the system is able to handle the following types of relationships Your online status is currently visible to other users. Customize Question Database Error Date of birth Default allowed relationship types default context Default join policy Define a new group type Define a new relationship type Delete delete Delete selected applications Delete this application Delete this group type Description Details for %group_type_pretty_name% DevAdmin Can we please have a description about the purpose of this key? Developer's Administration Direct Permissions Disable Disabled Domain E-mail Edit edit Edit application name and path Edit Selected Questionnaire Edit Caption edit comment Edit Options Certain elements are not editable, because they are managed by %authority_name%. Email #acs-subsite.Email# already exists Allow others to contact me through a web form Allow contact with a form Show my E-mail as an image Show email as an image Show my E-mail as text Show E-mail as text Here is your new login information: %account_id_label%: %account_id% %password_label%: %password% Please visit the following link to change your password now: %reset_password_url% Thank you for registering at %system_name%. Here's how you can log in at %system_url%: %account_id_label%: %account_id% %password_label%: %password% Please visit the following link to change your password now: %reset_password_url% Email Confirmation Don't show my E-mail Don't show E-mail Not available An email address is not on record for your account. Please enter your email address. Email not Requested Email required Your forgotten password on %system_name% %system_name% Validation E-mail Enabled Enter your username to begin password recovery. Erase Erase Portrait erase portrait Error Error sending mail We got an error sending out the email for email verification We experienced an error while trying to register an account for you. We experienced an error while trying to update the account information Expires Female Filename First name First name is not provided by the login authority. Please enter your first name. First, select the supertype for the new relationship type Forgot your password? Frequency Gender Go back go upload the user's portrait go upload your portrait Grant Grant Permission Group administration Group type Group type administration Group Types Groups Groups of this type We already have a group with this email We already have a user with this email. We already have a user with this username. <p><h3>Help Information</h3> Hide Home page Host-Node Map Hostname Hostname must be unique Icon of envelope If you were to Information Updated Install Locales Invite Invite a user ISO Code ISO Code List ISO Codes Not Loaded ISO Codes not loaded Join community Join %group_name% Join policy Join subsite Join this community Join this subsite Keyword Last name Last name was not provided by the login authority. Please enter your last name. later. Leave community Leave subsite Leave this community Leave this subsite Go back without adding any users Log In log in Log in to %system_name% logging back in The login page has expired. Please log in again. Login or register login page Logout Logout from %system_name% , you'd be able to get more information on your fellow community member. Add checked users to users who have permissions on your object. Cannot join this group. Complete List of ISO Codes Continue working with %system_name% delete</a> </if> <if @nodes.parameters_url@ ne ""> <a href="@nodes.parameters_url@"><#_ parameters Something went horribly wrong here! Do not inherit from %parent_object_name% Edit comment for the portrait of %first_names% %last_name% %first_names% %last_name% (%email%) registered as a user of %system_url% For Site-Wide Administrators Grant Permission on %name% Here's what the database reported: How would you like the world to see %first_names% %last_name%? If you don't think the person has an account already: If you happen to know or believe that the person you would like to invite already has an account on this system: If you need this functionality, please load acs-reference and ref-countries. Inherit from %parent_object_name% Inherit permissions from the %parent_object_name% Inherited Permissions It would be a very bad idea to choose this option if you're using a shared computer in a library or school. Any subsequent user of this machine would be able to masquerade as you on our service. New registration at %system_url% Note text in red below the parameter entry fields indicates the value of this parameter is being overridden by an entry in the OpenACS parameter file. The use of the parameter file is discouraged but some sites need it to provide instance-specific values for parameters independent of the apm_parameter tables. Note that you can erase your saved email address and password by choosing the "log out" option from your workspace. %num_children% Children Hidden On %portrait_publish_date%, you uploaded <a href="%subsite_url%user/portrait/?return_url=%pvt_home_url%">%portrait_title%</a> Our server can tell your browser to remember certain things, such as your email address and password. This is convenient for you because, if you're the only person who uses your computer, you won't have to keep telling us your email address and password. Re-type password Personal Home Page URL: Please locate your country's code among those listed below then use the "back" button on your browser to return to the previous form. Please read and follow the instructions in this email. Please try to <a href="index">log in</a> again Portrait of %first_names% %last_name% Privileges higher in the hierarchy imply all the privileges below, e.g. when you grant admin, then read, write etc. are implied automatically. Problem with authentication Your account has not been confirmed yet. A validation email has been sent to %email%. To validate your account, please check your emails and follow the link provided in %system_name% email. A validation email has been sent to %email%. To validate your account, please check your emails and follow the link provided in %system_name% email. Your registration request has been submitted to the %system_name% administrator. It is still waiting approval. Saving email address and password Show everyone else at %system_name% how great looking you are: Sorry but it seems that you've been banned from %system_name%. Stop inheriting permissions from the %parent_object_name% Are you sure that you want to erase this user's portrait? Are you sure that you want to erase your portrait? The picture of you in the system is invalid. Please There are no users who don't already have access to this object There was a problem with authenticating your account This is the image that we show to other users at %system_name% This user doesn't have a portrait yet. You can This user is deleted and banned from the community. Hello, This message is to verify that the email address you registered with %system_name% is correct. To validate your address, click on the following link: %confirmation_url% If you have not registered with %system_name%, please ignore this message. Thanks, The %system_name% Team. Upload your favorite file, a scanned JPEG or GIF, from your desktop computer system (note that you can't refer to an image elsewhere on the Internet; this image must be on your computer's hard drive). Uploaded: %pretty_date% Uploaded: %publish_date% Use the "Browse..." button to locate your file, then click "Open". This user has a entered a biography or uploaded a portrait We can't find you (user %user_id%) in the users table. Probably your account was deleted for some reason. We had a problem processing your entry. We were not awaiting your email. There must be some mistake. %system_name% Validation Email What other people see when they click your name You can't have a &lt; in your first name because it will look like an HTML tag and confuse other users. You can't have a &lt; in your last name because it will look like an HTML tag and confuse other users. You have to provide at least an object_id_on or object_id_two You won't get any email until after %pretty_date%. Welcome. You have successfully validated your email address and you are now registered to %system_name%. To get started, click below to login. Your email has been confirmed. You are now awaiting approval from the %system_name% administrator. Your email is confirmed Your login has expired. Please retype your password to continue working. Your URL doesn't have the correct form. A valid URL would be something like "%valid_url_example%". Mail a message to: Make administrator Make member Make yourself invisible Make yourself visible Male Manage Portrait Manage unmounted applications Manage users E-mail privacy Manage your notifications Sorry, but you are not allowed to view the members list. Member Member State Members Members only Missing argument mount Your Account Name New Application new application New Password New Subsite New subsite No applications No assessment available No ISO Codes This package does not have any parameters. your portrait No %pretty_plural% No services No user found with this username Nobody is online none Used to indicate that a list of permissions or objects is empty. Not logged in This is not a valid email address Note: Relational segments are created from the <a href='../groups/'>groups administration pages</a> Notes: Notice: number of groups defined number of relationships defined Object Types on %name% to: Online Your status has been set to invisible Your status has been set to visible Online time (optional) Options Or add a new user or the Parameters parameters Password Your login information on %system_name%: %account_id_label%: %account_id% Your password for this account has recently been changed. You don't need to do anything, this message is simply a notification to protect the security of your account. --------------- You can always change your password by doing the following: 1. Log in to %system_name% 2. Click on the "%pvt_home_name%" link 3. Choose "%password_update_link_text%" Password changed Your password must be changed regularly. Please change your password now. Passwords don't match This permission cannot be removed. Permissions permissions Permissions for %name% Place of birth Place of residence Please return to %home_link%. -- Please select -- Portrait Powered by <a href="http://openacs.org" title="The OpenACS Project Homepage">OpenACS</a> Pretty name Pretty plural Privacy There was a problem authenticating the account. Most likely, the database contains users with no member_state. Profile Question Re-enable Read Recover Password Refresh login Custom User Registration Questionnaire Register Registered hostname/URL pairs %system_name% Registration <p> Thank you for registering for %system_name%. An administrator has been notified of your request. </p> <p> Once you're approved, you'll get an email message and you can return to start using %system_name%. </p> Your email address is your %system_name% login. We will send you a validation message to confirm that you own this address. Reject Relational Segment administration Relational Segments relationship to site Relationship Types Relationship types administration Remember my login on this computer Remove remove Remove All rename Request membership of this community Request membership of this subsite Request to Change Password: A token for changing your password has been emailed to you. Follow the instructions in that email to change your password Request membership Reset Password return to application Revoke Checked Role Root Node Root URL Save comment Screen name This screen name is already taken. Screen name already taken Search For An Existing User Security context root See full size Select an Object by Id: Select Applications If the application is not in the list, you may need to <a href=\"/acs-admin/install/\">install</a> it on the server Select relation type Send email to this user Send me a copy: Services Set the assessment for registration Show Site Map Site Map Instructions Site node you would like to map hostname to Site Wide Administration Site-wide administration Sorry, we can't help you with your forgotten password. Status Story Behind Photo Story Behind Photo Subcommunities subcommunities subcommunity subsite Subsite Configuration %subsite_name% Home Subsite name Subsite Package Subsites subsites You have successfully authenticated, but you do not have an account on %system_name% yet. Supertype Thank you. The ISO codes were not loaded on this server. The name of the new subsite you're setting up Theme theme This group is closed. New members can only get access by invitation. This group type can only be administered by programmers This should be a short string, all lowercase, with hyphens instead of spaces, whicn will be used in the URL of the new application. If you leave this blank, we will generate one for you from name of the application. this subsite This user has left the community. To add a group first select a group type above or go to the <a href="../group-types/">group type administration</a> page To <strong>add an application</strong> to this site, use <em>new sub folder</em> to create a new site node beneath under the selected folder. Then choose <em>new application</em> to select an installed application package for instantiation. The application will then be available at the displayed URL. To <strong>configure</strong> an application select <em>set parameters</em> to view and edit application specific options. <em>set permissions</em> allows one to grant privileges to users and groups to specific application instances or other application data. For more info on parameters and permissions, see the package specific documentation. To <strong>copy</strong> an application instance to another URL, create a new folder as above, then select <em>mount</em>. Select the application to be copied from the list of available packages. Please check your inbox. Within the next few minutes, you should find an e-mail from %system_owner% with a new randomly generated password and instructions on how to proceed. Once received, go to To <strong>move</strong> an application, copy it as above to the new location, then select <em>unmount</em> at the old location. Selecting <em>delete</em> on the empty folder will remove it from the site node. To <strong>remove</strong> an application and all of its data, select <em>unmount</em> from all the site nodes it is mounted from, then <em>delete</em> it from the <em>Unmounted Applications</em> link below the site map. Topic type-specific info Unknown email unmount UP Can we please have a description of this key?? up to %context_name% Update Update Password upload upload a portrait Upload a replacement portrait Upload Portrait URL URL folder name User name User Portrait User Portraits User Profile User Profiles Username No user with username '%username%' found for authority %this_authority% Username required User's Site Map Vacation Information Updated Your vacation information at %site_link% has been updated. View all online members. View all roles View Alphabetical Index Visible to Welcome, %user_name% When you leave a checkbox empty here then that privilege will be revoked from the party you choose in case it has been granted to that party before. Users currently online Who's Online Write Yes, I'm sure You are in the following groups: You can also browse from the You can always re-open it by You can specify the default types of relationships that can be used for groups of this type. Note that each group can later change its allowed relationship types. You do not have admin rights on object %root% or any of it's children You don't have a portrait yet. You can You have admin rights on the following objects: You currently have no email alerts registered. Your Account Your discussion forum alerts Your Portrait Your %gc_system_name% alerts You're marked as back from vacation at %site_link%. openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.pt_BR.ISO-8859-1.xml0000644000175000017500000006645010727201372025574 0ustar frankiefrankie , ou Atualizar Informações Básicas Um membro da comunidade %system_name% desde Sobre você Sua conta em %system_name% está fechada. Não, leve-me de volta para %pvt_home_name% Sim, por favor feche minha conta <p>A sua conta encontra-se atualmente fechada.</p> <p>Se desejar, podemos <a href="%restore_url%">reabrir a sua conta</a>.</p> Conta Fechada <p> <font color="red"> <b> Sua conta está atualmente fechada. </b> </font> <a href="%login_url%">Faça o Log in</a> novamente para ver o que pode fazer sobre isto. </p&;gt; Esta conta não está disponível atualmente. Sua conta em %system_name foi reaberta. Bem-vindo novamente. Conta Reaberta Ação Adicionar adicionar pasta Adicionar nova aplicação Adicionar este usuário Adicionar Usuário Adicionar usuários Administrar Admin Administrar %subsite_name% Opções administrativas para este usuário Tipo de alerta outra imagem. Resposta Erro da aplicação Aplicações Aprovar em Erro interno do servidor durante autenticação Autoridade Senha Incorreta Banir Informações Básicas Biografias Biografia Mime Type para Biografia Mime Types para Biografia Recuperação de senha da autoridade local não é suportado. Não pode ver a lista dos membros Mudar idioma Mudar meu nível de privacidade de email Mudar minha Senha Mudar senha, endereço eletrônico, retrato Verifique sua Caixa de Entrada Filhos Escolher um questionário de registro customizado Use o questionário que será mostrado aos novos usuários.<br> Eles será usado para realizar ações automáticas (por exemplo, adicionar usuários em grupos específicos, notificar usuários específicos sobre novos registros etc.). Por favor, confirme se você deseja mesmo cancelar sua inscrição no sistema %system_name%.</p><p>O encerramento de sua inscrição significa que você não receberá mais notificações por correio eletrônico, nem aparecerá na lista dos membros deste sistema. Suas contribuições, contudo, serã opreservadas, pois são parte da história da nossa comunidade.</p><p>Não se esqueça: você pode se cadastrar novamente quando quiser.</p> Feche sua conta Grupo Fechado Comentário Comunidades comunidades comunidade Confirmar: A senha foi alterada com sucesso. Continuar Prossiga para %pvt_home_name% Nome do País Criar Criar um novo questionário de registro customizado Criar novo %pretty_name% Criar novo subsite Senha Atual <p> Seu estado online está atualmente invisível aos outros usuários </p> <p> Seu estado online está atualmente visível aos outros usuários </p> Personalizar Pergunta Erro no Banco de Dados contexto padrão Deletar excluir DevAdmin Administração para Desenvolvedores Permissões Diretas Desabilitar Desabilitado Domínio Endereço eletrônico Editar Editar Questionário Selecionado editar comentário Editar Opções Alguns elementos não podem ser editados, pois são gerenciados por %authority_name%. Email Permitir contactar-me via formulário Permitir contactar-me via formulário Mostrar meu E-mail como imagem Mostrar E-mail como imagem Mostrar meu E-mail como texto Mostrar E-mail como texto Estas são suas novas informações para login: %account_id_label%: %account_id% %password_label%: %password% Por favor, visite o link a seguir para alterar sua senha: %reset_password_url% Obrigado pelo cadastro no sistema %system_name%. Você pode acessar o %system_url% da seguinte forma: %account_id_label%: %account_id% %password_label%: %password% Por favor, visite o link a seguir para alterar sua senha: %reset_password_url% Confirmação de E-mail Não mostrar meu E-mail Não mostrar E-mail Indisponível E-mail não Solicitado Email é requerido Sua senha esquecida em %system_name% Bem-vindo ao %system_name% Habilitado Informe seu e-mail cadastrado no sistema para obter uma nova senha. A nova senha será encaminhada para o e-mail informado. Apagar Retrato apagar retrato Erro Erro ao enviar e-mail Ocorreu um erro ao enviar email para verificação de amil Ocorreu um erro ao tentar registrar uma conta para você. Ocorreu um erro ao tentar atualizar a informação de conta Expira Nome do arquivo Primeiros nomes Esqueceu sua senha? Frequência Voltar enviar retrato do usuário enviar seu retrato Permitir Dar Permissão Um grupo já existe com este email Um usuário já existe com este email Um usuário já existe com este username <p><h3>Ajuda</h3> Ocultar Página Pessoal Se você fosse Informação Atualizada Instalar Localização Convidar Código ISO Lista de Códigos ISO Códigos ISO Não Carregados Códigos ISO não carregados Aderir à comunidade Juntar-se a %group_name% Aderir ao subsite Aderir a esta comunidade Aderir a este subsite Palavra Chave Último nome mais tarde. Deixar comunidade Deixar o subsite Deixar esta comunidade Deixar este subsite Voltar sem incluir usuários Log In log in Efetuar login no sistema %system_name% logar-se novamente A página de login expirou. Por favor, efetue novamente o login. Efetue o login ou cadastre-se página de login Sair Efetuar logout do sistema %system_name% , você poderia ter maiores informações sobre os outros membros da comunidade. Adicionar usuários selecionados que têm permissão sobre o objeto. Não é possível juntar-se a este grupo. Lista Completa de Códigos ISO Continuar trabalhando com o sistema %system_name% deletar</a> </if> <if @nodes.parameters_url@ ne ""> <a href="@nodes.parameters_url@"><#_ parameters Não herdar permissões de %parent_object_name% Editar comentário para o retrato de: %first_names% %last_name% %first_names% %last_name% (%email%) registrado como um usuário de %system_url% Para Administradores do Site Conceder Permissão para %name% Veja o que a base de dados relatou: Como você quer que os usuários do site vejam você Se você acha que essa pessoa ainda não está cadastrada: Se você acha (ou sabe) que a pessoa que você quer convidar já está cadastrada: Se você precisa ativar essa função, carregue o acs-reference e o ref-countries. Herdar permissões de %parent_object_name% Herdar permissões de %parent_object_name% Permissões Herdadas Seria uma má idéia escolher este opção se você está usando um computador compartilhado numa biblioteca ou escola. O próximo usuário desta máquina poderia usar seu login em nosso serviço. Novo registro em %system_url% Obs.: um texto em vermelho sob os campos de entrada de parâmetros indica que o valor desse parâmetro está sendo substituído por uma entrada no arquivo de parâmetros do OpenACS. Não indicamos o uso do arquivo de parâmetros, mas alguns sites precisam de valores específicos para cada parâmetro, independente das tabelas apm_parameter . Note que você pode apagar seu endereço de email e sua senha salva ao escolher a opção de "logout" do seu espaço de trabalho. %num_children% Filhos Ocultos Em %portrait_publish_date%, você fez o upload de <a href="/user/portrait/">%portrait_title%</a> Nosso servidor pode dizer ao seu navegador para lembrar de certas informações, tal como seu endereço de email e senha. Isto é conveniente para você porque, se você é a única pessoa quem usa seu computador, você não teré que dizer-nos seu endereço de email e senha novamente. Confirmação de Senha: URL da Página Pessoal: Por favor, localize o código do seu país na lista abaixo. Em seguida, use o botão "voltar" em seu navegador para retornar ao formulário anterior. Por favor leia e siga as instruções neste email. Por favor tente <a href="index">fazer login</a> novamente Retrado de %first_names% %last_name% Um alto privilégio implica automaticamente em todas as permissões inferiores. Ex.: autorizando o poder de "Administrar", é automaticamente permitido "Ler", "Gravar", etc. Problema com autenticação Informações de registro deste serviço acabaram de ser enviados para %email%. Informações de registro deste serviço foram enviados para %email%. Sua solicitação de registro foi submetida para o administrador de %system_name%. Ela está esperando para ser aprovada. Salvando endereço de email e senha Mostre a todos em %system_name% como você tem um grande visual: Desculpe mas parece que você foi banido de %system_name%. Cancelar permissões herdadas de %parent_object_name% Você tem creteza que deseja apagar o retrato deste usuário? Você tem certeza que deseja apagar seu retrato? Seu retrato no sistema não é válido. Por favor Todos os usuários já têm acesso a este objeto Ocorreu um problema com a autenticação de sua conta Esta é a imagem que será mostrada aos usuários do %system_name% O usuário não possui um retrato ainda. Voce pode Este usuário foi apagado e banido da comunidade. Para confirmar seu registro, por favor clique em %confirmation_url% Envie seu arquivo favorito, uma imagem scaneada JPEG ou GIF de seu computador (note que você só pode referenciar uma imagem que esteja no disco rígido de seu computador). Enviado: %pretty_date% Enviado: %publish_date% Use o botão "Navegar" para localizar o arquivo, entõa click em "Abrir" Este usuário incluiu uma biografia ou um retrato Não conseguimos encontrar você (usuário user %user_id%) em nossa tabela de membros. Pode ser que sua conta tenha sido apagada. Nós tivemnos um problema processando os dados. Nós não estávamos esperando por seu email. Deve haver algum erro. Bem-vindo a %system_name% O que outras pessoas enxergam quando clicam em seu nome Você não pode ter um &lt; no seu nome porque isto parece com um comando HTML (tag) e confunde outros usuários. Você não pode ter um &lt; no seu sobrenome porque isto parece com um comando HTML (tag) e confunde outros usuários. Você deve prover pelo menos um object_id_on ou object_id_two Você não receberá e-mails do sistema até o dia %pretty_date%. Seu email foi confirmado. Você pode agora fazer login em %system_name%. Seu email foi confirmado. Você agora está esperando por aprovação pelo administrador de %system_name%. Seu email está confirmado Seu login expirou. Digite novamente sua senha para continuar. Seu endereço (URL) não está no formato correto. Um endereço (URL) válido seria algo como \"%valid_url_example%\"." Enviar mensagem para: Tornar admimistrador Tornar membro Tornar-se invisível Tornar-se visível Gerenciar privacidade de e-mail de usuários Gerenciar suas notificações Desculpe, mas você não pode ver a lista de membros Membro Estado do Membro Membros Argumento inexistente montar Minha Conta Nome: nova aplicação Nova Senha: Não há propostas Nenhum questionário disponível Não há códigos ISO Este pacote não tem nenhum parâmetro. seu retrato Não há %pretty_plural% Não há serviços. Nenhum usuário encontrado com este username nenhum Não logado Este não é um endereço válido de e-mail Observações: Aviso: em %name% para: Online (opcional) Opções Ou adicione um novo usuário ou o Parâmetros parâmetros Senha: A sua informação do login em %system_name%: %account_id_label%: %account_id% A sua senha para esta conta foi alterada recentemente. Não precisa de fazer nada, esta mensagem é uma simples notificação para proteger a segurança da sua conta. ---------------Pode sempre alterar a sua senha fazendo o seguinte: 1. Fazer o login para %system_name% 2. Clicar na ligação "%pvt_home_name%" 3. Escolher "%password_update_link_text%" Senha alterada Você deve modificar regularmente a sua senha. Por favor, modifique sua senha agora. Senhas não combinam Esta permissão não pode ser removida Permissões Permissões Permissões para %name% Por favor, retrone à página %home_link%. Retrato Privacidade Ocorreu um problema na autenticação desta conta. Provavelmente, o banco de dados contém usuários sem definição de estado de membro. Perfil Pergunta: Reabilitar Ler Recuperar Senha Recarregar login Questionário Customizado para Registro de Usuário Registrar <p>Obrigado por se cadastrar no sistema %system_name%. O sistema notificou sua solicitação a um administrador. <p> <p>Uma vez aprovado, você receberá um e-mail e poderá então começar utilizar o sistema %system_name%. </p> Rejeitar Lembrar meu login neste computador Remover Remove All renomear Solicitar adesão a esta comunidade Solicite inscrição neste subsite Solicitar adesão retornar para a aplicação Cancelamento Verificado Regra Salvar comentário Nome de Tela Este apelido já está em uso por outro usuário Procurar por um Usuário Existente Contexto de segurança raiz Selecionar um Objeto pelo Id: Enviar email para este usuário Envie-me uma cópia: Definir o questionário para registro Mostrar Administração Global do Site Administração geral do site Desculpe, não podemos ajudá-lo com a sua senha esquecida. Status História por tráz da foto História por Tráz da Foto Subcomunidades subcomunidades subcomunidade subsite Subsites subsites Sua autenticação ocorreu com sucesso mas você ainda não possui ainda uma conta validada em %system_name%. Obrigado. Os códigos ISO não foram carregados neste servidor. Este grupo é fechado. Novos membros só podem ter acesso se forem convidados. este subsite Este usuário deixou a comunidade. Para acessar o site, visite Tópico informação específica Email desconhecido desmontar Acima ir para %context_name% Atualizar Atualizar Senha enviar atualizar retrato envie outro retrato Enviar Retrato Retrato do Usuário Retratos do Usuário Perfil do Usuário Perfis do Usuário Nome de usuário Nenhum usuário com username '%username%' foi encontrado na autoridade %this_authority% Username é requerido User's Site Map Informação de Férias Atualizada Sua informação de férias foi atualizada em %site_link% Bem-vindo, %user_name% Deixando de marcar uma permissão, o usuário ou grupo selecionado terá a mesma revogada caso ela tenha sido concedida anteriormente. Usuários online Quem está online Escrever Sim, tenho certeza Você está nos seguintes grupos: Você tambêm pode navegar pelo Você sempre poderá reabrir Você não tem provilégios administrativos sobre o objeto %root% ou seus descendentes Você ainda não tem um retrato. Você pode Você tem direitos de administrador nos seguintes objetos: Atualmente você não tem alertas de email. Sua Conta Seus alertas nos fóruns de discussão Seu Retrato Seus alertas em %gc_system_name% Sua volta das férias está marcada para %site_link% openacs-5.7.0/packages/acs-subsite/catalog/acs-subsite.zh_TW.utf-8.xml0000644000175000017500000000340210727201372025345 0ustar frankiefrankie 關於你 你在%system_name%的帳號已被關閉 <p>你的帳號已被關閉.</p> <p>我們å¯ä»¥ç‚ºä½ <a href="%restore_url%">釿–°é–‹å•Ÿ.</p> 解答: 在 密碼錯誤 基本資料 變更我的密碼 變更密碼, ä¿¡ç®±, 照片 檢視你的信箱 å…’ç«¥ 確èª: ç›®å‰çš„密碼: 客制的å•題 ç›´æŽ¥è¨±å¯ é›»å­éƒµä»¶ç¢ºèª 未給予電å­éƒµä»¶ 郵件傳é€éŒ¯èª¤ 授與 æŽˆèˆ‡æ¬Šé™ åŠ å…¥ %group_name% 登入 登出 從 %system_name% 登出 無法加入此群組 %first_names% %last_name% (%email%) 註冊為 %system_url% 的使用者 授權給 %name% ç¹¼æ‰¿çš„æ¬Šé™ æ­¡è¿Žå…‰è‡¨, %user_name% openacs-5.7.0/packages/openacs-default-theme/0000755000175000017500000000000011724401447020727 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/lib/0000755000175000017500000000000011724401447021475 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/lib/tabbed-master.adp0000644000175000017500000000073311321721412024666 0ustar frankiefrankie doc body @head;noquote@ @focus;noquote@ @context;noquote@ navigation openacs-5.7.0/packages/openacs-default-theme/lib/tabbed-master.tcl0000644000175000017500000000113711054654465024723 0ustar frankiefrankie# Set the tabs then use the plain master to render the page. subsite_navigation::define_pageflow -navigation_multirow navigation -group main -subgroup sub \ -show_applications_p [parameter::get -package_id [ad_conn subsite_id] \ -parameter ShowApplications -default 1] \ -no_tab_application_list [parameter::get -package_id [ad_conn subsite_id] \ -parameter NoTabApplicationList -default ""] \ -initial_pageflow [parameter::get -package_id [ad_conn subsite_id] \ -parameter UserNavbarTabsList -default ""] openacs-5.7.0/packages/openacs-default-theme/lib/plain-master.adp0000644000175000017500000001074611020573076024564 0ustar frankiefrankie doc body @head;noquote@ @focus;noquote@ @skip_link;noquote@
    @system_name@ @system_name@
    Begin main content
    @user_messages.message;noquote@
    TODO: remove this and add a more systematic / package independent way TODO of getting this content here empty UL gives a validation error for the W3C validator
    openacs-5.7.0/packages/openacs-default-theme/lib/plain-master.tcl0000644000175000017500000001060211150606321024563 0ustar frankiefrankiead_page_contract { This is the highest level site specific master template. Properties allowed doc(title) HTML title head code to be entered into head of document body focus HTML id of form element to focus skip_link href of link to skip to. Should be of format #skip_link main_content_p if true wrap in the main content divs (if false, provide your own page structure, for instance two or three columns of content per page) @author Lee Denison (lee@xarg.co.uk) @author Don Baccus (dhogaza@pacifier.com) $Id: plain-master.tcl,v 1.4 2009/02/23 20:53:37 jeffd Exp $ } if { ![info exists main_content_p] } { set main_content_p 1 } # # Set some basic variables # set system_name [ad_system_name] set subsite_name [lang::util::localize [subsite::get_element -element instance_name]] if {[ad_conn url] eq "/"} { set system_url "" } else { set system_url [ad_url] } if {[template::util::is_nil title]} { # TODO: decide how best to set the lang attribute for the title set title [ad_conn instance_name] } # # Organize standard top level navigation, if any, for output by groups (rows of # horizontal tabs by default) # if { [template::multirow exists navigation] } { if { ![info exists navigation_groups] } { set navigation_groups [list] } for {set i 1} {$i <= [template::multirow size navigation]} {incr i} { template::multirow get navigation $i if { [lsearch -exact $navigation_groups $navigation(group)] < 0} { lappend navigation_groups $navigation(group) } } } # # User information and top level navigation links # set user_id [ad_conn user_id] set untrusted_user_id [ad_conn untrusted_user_id] set sw_admin_p 0 if { $untrusted_user_id == 0 } { # The browser does NOT claim to represent a user that we know about set login_url [ad_get_login_url -return] } else { # The browser claims to represent a user that we know about set user_name [person::name -person_id $untrusted_user_id] set pvt_home_url [ad_pvt_home] set pvt_home_name [_ acs-subsite.Your_Account] set logout_url [ad_get_logout_url] # Site-wide admin link set admin_url {} set sw_admin_p [acs_user::site_wide_admin_p -user_id $untrusted_user_id] if { $sw_admin_p } { set admin_url "/acs-admin/" set devhome_url "/acs-admin/developer" set locale_admin_url "/acs-lang/admin" } else { set subsite_admin_p [permission::permission_p \ -object_id [subsite::get_element -element object_id] \ -privilege admin \ -party_id $untrusted_user_id] if { $subsite_admin_p } { set admin_url "[subsite::get_element -element url]admin/" } } } # # User messages # util_get_user_messages -multirow user_messages # # Set acs-lang urls # set acs_lang_url [apm_package_url_from_key "acs-lang"] set num_of_locales [llength [lang::system::get_locales]] if {$acs_lang_url eq ""} { set lang_admin_p 0 } else { set lang_admin_p [permission::permission_p \ -object_id [site_node::get_element \ -url $acs_lang_url \ -element object_id] \ -privilege admin \ -party_id [ad_conn untrusted_user_id]] } set toggle_translator_mode_url [export_vars \ -base ${acs_lang_url}admin/translator-mode-toggle \ {{return_url [ad_return_url]}}] set package_id [ad_conn package_id] if { $num_of_locales > 1 } { set change_locale_url [export_vars -base $acs_lang_url {package_id}] } # # Change locale link # if {[llength [lang::system::get_locales]] > 1} { set change_locale_url [export_vars -base "/acs-lang/" {package_id}] } # # Who's Online # set num_users_online [lc_numeric [whos_online::num_users]] set whos_online_url "[subsite::get_element -element url]shared/whos-online" # # Context bar # if {[info exists context]} { set context_tmp $context unset context } else { set context_tmp {} } ad_context_bar_multirow -- $context_tmp # Context bar separator set subsite_id [ad_conn subsite_id] set separator [parameter::get -package_id $subsite_id -parameter ContextBarSeparator -default ":"] # # Curriculum specific bar # TODO: remove this and add a more systematic / package independent way # TODO of getting this content here # set curriculum_bar_p [expr { [site_node::get_package_url -package_key curriculum] ne "" }] if {![info exists skip_link]} { set skip_link "#content-wrapper" } openacs-5.7.0/packages/openacs-default-theme/tcl/0000755000175000017500000000000011724401447021511 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/tcl/apm-callback-procs.tcl0000644000175000017500000000565211201401551025642 0ustar frankiefrankienamespace eval openacs_default_theme {} namespace eval openacs_default_theme::install {} ad_proc openacs_default_theme::install::after_install {} { Package after installation callback proc. Add our themes, and set the acs-subsite's default master template parameter's default value to our "plain" theme. } { # Insert this package's themes db_transaction { subsite::new_subsite_theme \ -key default_plain \ -name #openacs-default-theme.plain# \ -template /packages/openacs-default-theme/lib/plain-master \ -css {{{href /resources/openacs-default-theme/styles/default-master.css} {media all}} {{href /resources/acs-templating/forms.css} {media all}} {{href /resources/acs-templating/lists.css} {media all}}} \ -form_template /packages/acs-templating/resources/forms/standard \ -list_template /packages/acs-templating/resources/lists/table \ -list_filter_template /packages/acs-templating/resources/lists/filters subsite::new_subsite_theme \ -key default_tabbed \ -name #openacs-default-theme.tabbed# \ -template /packages/openacs-default-theme/lib/tabbed-master \ -css {{{href /resources/openacs-default-theme/styles/default-master.css} {media all}} {{href /resources/acs-templating/forms.css} {media all}} {{href /resources/acs-templating/lists.css} {media all}}} \ -form_template /packages/acs-templating/resources/forms/standard \ -list_template /packages/acs-templating/resources/lists/table \ -list_filter_template /packages/acs-templating/resources/lists/filters } # Set the default value of the master template parameter, so all subsites will # default to this when mounted. At this point in the ACS installation process, the # main subsite has yet to be mounted, so it will get the "plain" theme value # when the installer gets around to doing so. # Don't do this if you're creating your own theme package! Override the default by # creating a custom install.xml file to be run during the install process if you want # it to be installed by default for your sites. # We don't set up the form or list templates or CSS because the default is to use # those values set for acs-templating during install. parameter::set_default -package_key acs-subsite -parameter DefaultMaster \ -value /packages/openacs-default-theme/lib/plain-master parameter::set_default -package_key acs-subsite -parameter ThemeCSS \ -value {{{href /resources/openacs-default-theme/styles/default-master.css} {media all}} {{href /resources/acs-templating/forms.css} {media all}} {{href /resources/acs-templating/lists.css} {media all}}} parameter::set_default -package_key acs-subsite -parameter ThemeKey -value default_plain } openacs-5.7.0/packages/openacs-default-theme/www/0000755000175000017500000000000011575226023021552 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/www/resources/0000755000175000017500000000000011575226023023564 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/www/resources/images/0000755000175000017500000000000011724401447025032 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/www/resources/images/right.gif0000644000175000017500000000356111010454213026626 0ustar frankiefrankieGIF89aë–Õ:úúúûûûôôôêëêèéèëìëçèçøøøö÷öñññÞßßïðïøùøìììèèèòòò÷ø÷ùùùîîîõõõóóóêêêïïïííí £¡ÚÛÚ¢¥£¡¥£¡¤¢åæåâãâðñðÛÜÛÈËÉ¡¤¡ëëëáâáéêéàààßàßÝÞÝæçæäåäåææéééíîíßßßàáàÚÝÜ¢¤¢ÜÜÜÞßÞ´¶µ¡¥¢ðð𧪨¤§¥çççÿÿÿ!ù:,ë–ÿ@…pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz±+]`L.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Ïïûÿy&0€„…†‡ˆ‰Š‹ŒŽi!”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°ª64±µ¶·¸¹º»¼½¾¿Àš-7ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáÛ8 æçèéêëìíîïðñòóôõö÷øùúûüýþÿ ä7@Ã*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠÙq„(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏÿŸ@ƒ JÔg ’*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶ìW&¨]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°aÀ4X̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¡ l@ͺµë×°cËžM»¶íÛ‘Sl À»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ¥wØð »÷ïàËO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóÏßž ¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f8¡ 5,àÿᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨#p`Á@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–Uö(Á—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çžu’ÀÁ€*è „j衈&ªè¢Œ6êè£F*餔Vj饘fªé¦œZú„*ꨤ–jꩨ¦ªêª¬¶êê«°Æ*무Öjë­¸æªë®¼özë "4 ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvë-¶.Ä0À¸ä–kî¹è¦«ÿîºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿ù΀AlðÁ'¬ð 7ìðÃG,ñÄWlñÅg¬ñÆwìñÇ kŒ”lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@½³ 8`ôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-6×``ÀÙh§­öÚl·íöÛpÇ-÷Üt×m÷Ýxç­÷Þ|÷í÷߀.øà}ƒ€Aˆ'®øâŒ7îøãG.ùä”Wnùå˜g®ùæœwîùç ‡.úè¤{^v騧®úꬷîúë°Ç.û쎟Nÿûí¸ç®ûî¼÷îûï‰ÛüðÄoüñÈ'ºðÊ7ïüóÐG/}éÌOoýõØg¯=ñÕoïý÷à‡/~æÝoþùè§/}ùê·ïþûðËÎ~üô×oÿý–Ïÿþü÷¿þþ  ˜=ð€L ÷§À:ð¼3 'HÁ vN‚Ì 7È8 rðƒ „ CH p„&L¡ é‡Âºð…æk! gHCìɰ†8Ì¡òn¨ÃúÐw<ü¡‡(?ñˆH¢“ÈÄ&щPŒ"ë‚(Å*ZqqT¼¢¥˜Å-z‘‰]ü¢‡Æ1šQ‡e<£g˜Æ5ºQ…m|£CÇ9ÚÿQƒu¼£'˜Ç=úQ}ü£ ÈA’…<¤"ë—ÈE:Ò}|¤$ÏÉIZ|•¼¤& ¸ÄMz’€™ü¤(ÊQšòx¥<¥*—ÊUºrw­|¥,iËYÚòuµ¼¥.U—Ë]úrt½ü¥0M×Éa³yÁ<¦2+—Ìe:rÍ|¦4±XÌiZwѼ¦4³©Mgr³›Êü&8)Îq ³œæô%:Ó©Ëu²Ó–î|§,ã)OWÒ³žª¼'>M©Ï}вŸþô$@ªÉÔ’=¨$ªPG2´¡Š|(D )щ ²¢õ#F3ªÇrÔŽý¨C*R7’´¤j<)JÍ¨Ò•Š±¥Ž.õ"LcªÅ™ÒÔŠ6½)«©Syæ´§Nü)PÁÈÓ¡šS¨F="R“JÆ¢2U›K}ª£*U4:µªÛ¼*V½©Õ­†³«^%'XÃzα’Uf=k;ÓªVx²µ­ó|+\í)׹泮vå'^óúϽòU ~ýkA+X„¶° =,bªØÅF´±Ž¥(d#{Q ;openacs-5.7.0/packages/openacs-default-theme/www/resources/images/left.gif0000644000175000017500000000076611010454213026447 0ustar frankiefrankieGIF89a –Õ2ûûûôôôúúúùùùìììïïïòòòêëêñññøøøíííçèçóóóêêêîîîèéèö÷öëìëøùøÞßß÷ø÷ïðïèèèõõõÒÕÔÓÖÕÑÔÓÑÔÒÒÔÓíîíéêéÓÕÔ÷÷÷ðñðìíìãåäÒÕÓóôóðððÖÙ×öööúûúßâáÔÖÕõöõÔ×ÕÚÝÛéééÐÓÒçççÿÿÿ!ù2, –ÿ@ÙhB,NT€r p1™§”`J´UêjÀír3 ‰x,Á èt"¢¸ß” B¯C>¬‹~Áþ€%€ ‰Š $!•–&›œ ¡ ¦§" ¬­ ²³°·¸0¼½¼0 Âà 0/ÈÉÆÍÎÆ ÒÓ Æ1ר1ÖÙ×ÛÜÞÙàØâÝ/ÜåçÚæçäêéíðëßòáôãöèìøîúïûñþö8O`A‚õ &DxOaC†ùJ\8ñaň3ZÔˆq£ÇŽ ù]É‘äG“!BDÉRåH—%až”™òŸM‡5q¶¼¹’æN>ƒò|94fÑ™GsöLús©Î ;openacs-5.7.0/packages/openacs-default-theme/www/resources/images/left_on.gif0000644000175000017500000000065211010454213027135 0ustar frankiefrankieGIF89a –ÕKh ÒÕÔøøøÓÖÕùùùïïïÒÔÓìììùøøÑÔÒÑÔÓäãäîïïãäããããÓÕÔìíìïîïôôôñññîîïõöõÔÖÕùøùÒÕÓûûûóôóòòòêëêúûúÖÙ×ðñððððöööéêéääãíîíÔ×Õ÷÷÷­ÀäîïîéééÐÓÒÿÿÿ!ù, –ÇÀ`H,FODZ9E)Sˆ0 ÊB\Dw X™Ï«}˜ØæA¾zTè ^ƒßà'tt „t $‰t Žp*t*"–)™›“šœl*ž¡£h¢ ¦¥g§Ÿ­¤¨«ªf¬¯®©°³²+´·¶±¸»º¼¿¾¹ÀÃÆÅÁÇÂÍÌÏÊÈËÑÎÔеؽÙÄÛÉÝÓßÒâÕáäÚçÜèÞêàìã×îæéóëôíöïÖúåðøòõïÌÇo_¼~ÿ \;openacs-5.7.0/packages/openacs-default-theme/www/resources/images/bg.gif0000644000175000017500000000006311010454213026073 0ustar frankiefrankieGIF89a‘ÿÿÿ £¡ÿÿÿ!ù,”™;openacs-5.7.0/packages/openacs-default-theme/www/resources/images/right_on.gif0000644000175000017500000000367611010454213027331 0ustar frankiefrankieGIF89aë–ÕKh ïïïøøø £¡ÚÛÚïîïùøøîïïïïîøùøããããääääãäããøøùããääääãäãäãäùøùøùùîïîùùøîîïïîîùùùîî£¡¥£¡¤¢âãâåæå§ª¨¡¥¢æçæàáàäåäíîíçèçêëêèéèéééëë뢤¢ßßߤ§¥­Àä´¶µÞßÞáâáðððëì롤¡ÛÜÛÝÞÝéêéßàßÜÜÜÿÿÿ!ù,ë–ÿ@€pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz³®¯xL.›Ïè´zÍn»ßð¸|N¯ÛïÐEd!yH   ƒ  „  • ’ {}}„ ~—ƒˆ š ©™¯¬ ° «z‹Ã”ž‘Ç¡¾—Š‹¾¬‰ˆ» ‹®Ã¯—ÜÅšÖ²‚z®´ ƒŽ• ™{¾“»¤ ”‡¹ ºûñ Ü\É¢j FŠœå‚ATCR¢øP*”éà!VÒ^ÁJ WCF‚¾JWèP©Qlú“I¦S‘ Ùã•É©@©\݃u©ÑÿZ5-ú£ÎHh¥z…M¨vÿf£È  Š 5ò³'–¦cû¥2×S –r%ÒçJ$§Úà¡jT” Z,+UAÆ‹4(pðà#Ѐp€0$¾Pà1‚¨ 9q S>š°ãŸ-W@°Ú3åÊNc–¬8ÀëÊŽSkˆ¬Ù6j„` ]áÂcÒ»?°|0hÄ—CÇÎ8qá͈¾| ðå✠T8pÁ8†çÓ ‹‡ÌØ4yã—†|aµ†ÇÛ?­aµtÇ–˜`…AFf¨…FØe˜i¶ŸxŸMiŸ vžg„ñ&Øc F§ÿ\ÍÙ6\l€ÍvA½e¶Xe˜UPÙyÃevÀ}”-vœe¼†Znç¶°Ûsã‘sŸ™¦¤ŽIçmIjðÜg”-‹ j&j„˜`¸¥öaeEö†Xrˆuy”‚8@P  À8Àgœuê©§zZ0Ay 0(¢tÀgL €¢p& (˜RÀç¦p j@‡6J(’Rªç“NЍ¢Œ’'¨Xª‰f°'¤~:Àh±Z +è9¨(Ú§¥ˆzÊg°Á&:Ô)€Ði²’N­€J¥”‚*(­ÔÚŠè° ÿè¡Ñ~šn©–Jkºòªh³à:i´sÊ ç¤zr««­PKk©ÜÖ)+°ŸîÉmœ˜¦:êÁD+»­´{ì´KZpoš¨¥šN‹¬´x jëëI2ÀpΙÀœ8Š§È©Jj)µ–Êl¨¬tÎ\¬gÐèÌ´Úm° _**̱² 0Ÿï›gœˆ‚«±ÒÚ² n¾O:C :¤­öÚl·íöÛpÇ-÷Üt×m÷Ýxç­÷Þ|÷í÷߀.øà„þ÷ ®øâŒ7îøãG.ùä”Wþ¶ ‰[®ùæœwîùç ‡.ºÚ7d>ú騧®úꬷ.x ¦».ûì´×nÿû톣;î¼÷îûïÀ£nÁoüñÈ'ÿ·Ä+ïüóÐGÿûÍKoýõØgÏ9õÚwïý÷àÿMBá—oþùç{Ðúì·ïþóê¿/ÿüôÛÃúõç¯ÿþŸ€?ÿ  ‡ ð€L ÞX°:ðT Á Z0€6 à7ÈÁ÷å@ƒ ¡¿GŽð„(„^ L˜Âºx%|¡ gˆ»Òð†8\ sÈÃzn‡> ¢#Ä!ñˆ„+"—ÈD½)±‰PŒ"Üž(Å*V‘ŠVÌ"±¨Å.‘‹^ #Á(Æ2ÎŒfLc ѨÆ6†nŒ£á(Ç::ÿŽvÌãñ¨Ç>î~ äü)ÈB²†Ldø©ÈFj‘ŽŒ¤ô )ÉJ*’–Ìdñ0©ÉNöŽ“ž eí@)ÊR¶Ž”¦L%êP©ÊV‚Ž•®Œåæ`)ËZNŽ–¶Ì¥ãp©Ë^Ž—¾ fà€)Ìbò˜ÆLæÝ©ÌfʙΌfÛ )Íjꀚ֌&6³ÙÌmr3™Þüf1Ã)Î`’³œ½<':s©ÎuÖ²îŒ%<ãÙÊyÒ3•ö¼g)ó©ÏPò³Ÿü'@3)ÐV² $BÚÈ…24‘}h!#*Ñ@R´¢}¼(Fó¨ÑÖ±£#HCÚÆ‘’4&=iSªÒ0²´¥Û]|)L³(Ó™^‘…6µfMs Åòt‹8ý©3}*Ô#µ¨_ *RyÔ¥ú°©N£R£êK¨Rõ†V½ê§ªU[fµ«.ü*X×ÈÕ±ºR¬f!ZÓúƲ²Õ”k}ëã*×9ºµ®ž¤+^!¨×½Þñ®~µd_‹ÀÁv€=¬# «X2¶±L,d ùØÉÖ¯²–¤d3ëGÌrÖ}žýì!7+Z;†¶´æ;-jIÚÕºQµ®õlcûÈÖÒÖŒ³½íõr«ÛIÚ¶·^ä-pŸ'Üá^ò·Æµbq“{¼;openacs-5.7.0/packages/openacs-default-theme/www/resources/styles/0000755000175000017500000000000011575226023025107 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/www/resources/styles/default-master.css0000644000175000017500000003176511463372347030561 0ustar frankiefrankie/* Main navigation */ #main-navigation { float:left; width:100%; background: url("/resources/openacs-default-theme/images/bg.gif") repeat-x bottom; clear: both; display: block; } #main-navigation ul { margin:0; padding:10px 10px 0; list-style:none; } #main-navigation li { float:left; background:url("/resources/openacs-default-theme/images/left.gif") no-repeat left top; margin:0; padding:0 0 0 9px; } #main-navigation a { float:left; display:block; background:url("/resources/openacs-default-theme/images/right.gif") no-repeat right top; padding:5px 15px 4px 6px; text-decoration:none; font-weight:bold; font-size: .95em; color:#666666; } #main-navigation #main-navigation-active { background-image:url("/resources/openacs-default-theme/images/left_on.gif"); } #main-navigation #main-navigation-active a { background-image:url("/resources/openacs-default-theme/images/right_on.gif"); color:#000; padding-bottom:5px; } #main-navigation a:hover { color: #000; text-decoration: underline; } /* End of main navigation */ /* Subnavigation */ #sub-navigation { float: left; width:100%; background: url("/resources/openacs-default-theme/images/bg.gif") repeat-x bottom; clear: both; padding-top: 5px; /* remove this padding to make the subnavigation links to appear completly enclosed */ padding-bottom: 5px /* remove this padding to make the subnavigation links to appear completly enclosed */ } #sub-navigation ul { margin: 0; padding:0px 10px 10px 10px; list-style:none; line-height: .7em; } #sub-navigation li { float:left; border-right: 1px solid #a0a3a1; padding: 0px 20px 0px 20px ; } #sub-navigation a { float:left; display:block; color:#666666; padding:4px 0px 6px 0px; text-decoration: none; font-weight:bold; font-size: .95em; } #sub-navigation li a:hover { color: #000; text-decoration: underline; } #sub-navigation li#sub-navigation-active a { color: #000; } /* End of subnavigation */ /* Calendar widget css */ /* The main calendar widget. div containing a table. */ div.calendar { position: relative; } .calendar, .calendar table { border: 1px solid #556; font-size: 11px; color: #000; cursor: default; background: #eef; font-family: tahoma,verdana,sans-serif; } /* Header part -- contains navigation buttons and day names. */ .calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ } .calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #fff; color: #000; padding: 2px; } .calendar thead .headrow { /* Row containing navigation buttons */ background: #778; color: #fff; } .calendar thead .daynames { /* Row containing the day names */ background: #bdf; } .calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #556; padding: 2px; text-align: center; color: #000; } .calendar thead .weekend { /* How a weekend day name shows in header */ color: #a66; } .calendar thead .hilite { /* How do the buttons in header appear when hover */ background: #aaf; color: #000; border: 1px solid #04f; padding: 1px; } .calendar thead .active { /* Active (pressed) buttons in header */ background: #77c; padding: 2px 0px 0px 2px; } /* The body part -- contains all the days in month. */ .calendar tbody .day { /* Cells containing month days dates */ width: 2em; color: #456; text-align: right; padding: 2px 4px 2px 2px; } .calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #bdf; } .calendar tbody .rowhilite td { background: #def; } .calendar tbody .rowhilite td.wn { background: #eef; } .calendar tbody td.hilite { /* Hovered cells */ background: #def; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } .calendar tbody td.active { /* Active (pressed) cells */ background: #cde; padding: 2px 2px 0px 2px; } .calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; background: #fff; color: #000; } .calendar tbody td.weekend { /* Cells showing weekend days */ color: #a66; } .calendar tbody td.today { /* Cell showing selected date */ font-weight: bold; color: #00f; } .calendar tbody .disabled { color: #999; } .calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } .calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ .calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #556; color: #fff; } .calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #fff; color: #445; border-top: 1px solid #556; padding: 1px; } .calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #aaf; border: 1px solid #04f; color: #000; padding: 1px; } .calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #77c; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ .combo { position: absolute; display: none; top: 0px; left: 0px; width: 4em; cursor: default; border: 1px solid #655; background: #def; color: #000; font-size: smaller; } .combo .label { width: 100%; text-align: center; } .combo .hilite { background: #acf; } .combo .active { border-top: 1px solid #46a; border-bottom: 1px solid #46a; background: #eef; font-weight: bold; } #login-box { border: black 1px solid; padding: 4px; } table.table-display { font-family: tahoma, verdana, helvetica; font-size: 85%; } tr.table-header { background-color: #cccccc; } tr.even { background-color: #ffffff; } tr.odd { background-color: #f0eff0; } /* Replace deprecated center tags in forms. Eventually all forms should use form builder and this tag should not be used */ div.submit-button { text-align: center; } #skiptocontent { display: none; } .block-marker {display: none;} /* User Messages */ #alert-message { background-color: #ccff99; padding: 4px; padding-top: 6px; padding-bottom: 6px; font-size: 85%; } #alert-message .alert { margin-left: 0; padding-left: 2px; border: none; } /* Boxed User Message */ .boxed-user-message { background-color: #ccff99; padding-left: 12px; padding-right: 12px; padding-top: 8px; padding-bottom: 8px; font-size: 85%; border: 1px solid #dd9988; } .boxed-user-message h3 { color: #990000; margin-top: 0px; } .boxed-user-message .body { color: #990000; } /* Subsite Name */ #subsite-name { font-weight: bold; font-size: 120%; font-family: verdana; padding-left: 8px; } a.subsite-name { color: black; text-decoration: none; } a.subsite-name:hover { color: black; text-decoration: none; } /* Site Footer */ #footer { clear: both; border-top: 1px solid #ccc; font-family: tahoma, verdana, helvetica, sans-serif; font-size: 85%; margin-top: 24px; padding-top: 3px; padding-bottom: 3px; padding-left: 8px; padding-right: 8px; text-align: center; } #footer ul { display: inline; margin-left: 0; padding-left: 0; border: none; } #footer ul li { margin-left: 0; padding-left: 10px; border: none; list-style: none; display: inline; } #footer .action-list { float: left; } #wrapper { } #content-wrapper { clear: both; border-top: 1px solid #fff; padding-bottom: 75px; } /********************************************************************** /* Widgets /**********************************************************************/ /* STANDARD TAGS -----------------------------------------------------------*/ /* standard html (body, h1, p, form...) */ body { margin:5px 5px 0px 5px; padding:0; font:small/1.5em Tahoma, "Lucida Grande", sans-serif; voice-family: "\"}\""; voice-family:inherit; } h1 { font-size: 1.2em; font-weight: bold; color: #666666; margin-bottom: 12px; } h2 { font-size: 1.1em; font-weight:bold; color: #555555; margin-bottom: 12px; } h3 { font-size: 1.05em; font-weight:bold; color: #444444; margin-bottom: 12px; } h3 { font-size: 1.00em; font-weight:bold; color: #444444; margin-bottom: 12px; } a:link { color: #235c96; text-decoration:underline; } a:visited { color: #235c96; } a:hover { color: #235c96; background: #CCCCCC; } /* BUTTON ---- */ a.button { font: .85em arial; border: solid 1px black; background-color: #E1E1E1; text-align: center; padding: 1px; padding-left: 8px; padding-right: 8px; color: black; text-decoration: none; white-space: nowrap; } a.button:link { text-decoration: none; border: solid 1px black; } a.button:hover { text-decoration: none; background-color: #CCCCCC; border: solid 1px black; } a.button:active { text-decoration: none; border: solid 1px black; } a.button .disabled { color: #A0A0A0; background-color: #E0E0E0; cursor: not-allowed; } a.button .disabled:hover { text-decoration: none; } /* END BUTTON ---- */ .center {text-align: center;} .small {font-size: x-small;} .bold {font-weight: bold;} /* ARE THESE NEEDED ??? -----------------------------------------------------------*/ /* Various forms of links */ .action-list { padding: 0; } .action-list ul { margin: 0; padding: 0; display: inline; border: none; } .action-list ul li { margin: 0; padding: 0; border: none; list-style: none; display: inline; } div.subsite-context-bar { font-size: 85%; margin-bottom: 4px; position: relative; } a.admin-button { font: 85% arial; border: solid 1px black; background-color: #aaa; text-align: center; padding: 1px; padding-left: 8px; padding-right: 8px; color: #fff; text-decoration: none; white-space: nowrap; } a.admin-button:link { text-decoration: none; border: solid 1px black; color: #111; } a.admin-button:visited { text-decoration: none; border: solid 1px black; } a.admin-button:hover { text-decoration: none; background-color: #ccc; border: solid 1px black; } a.admin-button:active { text-decoration: none; border: solid 1px black; } a.admin:link, a.admin:visited { color: #f00; font-family: verdana; font-size: 11px; font-weight: normal; } a.admin:hover { color: #fff; background: #f00; } .highlight { background-color: #ffc; } ul.action-links li { list-style: circle url(/resources/acs-subsite/action-link-marker.png); margin: 8px; margin-left: -16px; } /* END ARE THESE NEEDED -----------------------------------------------------------*/ /* END STANDARD TAGS ---------------------------------------------------------------*/ /* HEADER TAGS ---------------------------------------------------------------------*/ #header { font-size: 0.92em; background-color: #EFEFEF; color: #444444; padding-top: 4px; padding-bottom: 4px; } #system-name { font-size: 1.4em; font-weight: bold; float: left; padding-left: 0.2em; } #system-name a { color: #333333; text-decoration: none; } #header-navigation { float: right; padding-right: 0.4em; } /* CONTEXT BAR ---- */ #breadcrumbs { clear: right; padding-left: 0.4em; } /* END CONTEXT BAR ---- */ /* END HEADER TAGS -----------------------------------------------------------*/ /* LISTS -----------------------------------------------------------*/ ul.compact, .action-list ul{ margin: 0px; padding: 0px; } ul.compact li, .action-list ul li { list-style:none; display: inline; } /* END OF LISTS */ /* PORTLETS */ .portlet-sidebar { width: 30%; } .portlet-wrapper { margin: 4px 4px 4px 4px; } .portlet-header { padding: 2px 8px 2px 8px; border-top: 1px solid #fff; background: #ddd; height: 21px; } .portlet-title { float: left; /* comment out if portlet-controls display:none */ display: inline; } .portlet-title h1 { margin: 0px; font-size: 1em; font-weight:bold; color:#000; } .portlet-controls { display: block; /* future development */ padding-top: 2px; text-align: right; } .portlet-controls img { border: 0px; } .portlet-controls a:link { color: #fff; } .portlet-controls a:hover { color: #000; } .portlet { border: 1px dotted #999; border-top: 0px; padding: 6px 8px 6px 8px; clear:left; overflow: auto; } /* END OF PORTLETS */ .portal-page { border: 1px solid #888; padding: 6px 8px 6px 8px; clear:left; } /********************************************************************** /* DEPRECATED CLASSES /**********************************************************************/ /* Deprecated, not sure what it's replaced with just yet */ a.action { margin: 8px; margin-left: 24px; display: list-item; list-style: circle url(/resources/acs-subsite/right.gif); } openacs-5.7.0/packages/openacs-default-theme/catalog/0000755000175000017500000000000011724401447022341 5ustar frankiefrankieopenacs-5.7.0/packages/openacs-default-theme/catalog/openacs-default-theme.en_US.ISO-8859-1.xml0000644000175000017500000000036711010454213031440 0ustar frankiefrankie OpenACS Default Plain OpenACS Default Tabbed openacs-5.7.0/packages/openacs-default-theme/catalog/openacs-default-theme.es_ES.ISO-8859-1.xml0000644000175000017500000000036311332116050031422 0ustar frankiefrankie OpenACS sencillo OpenACS con pestañas openacs-5.7.0/packages/openacs-default-theme/openacs-default-theme.info0000644000175000017500000000272711575167337026001 0ustar frankiefrankie OpenACS Default Theme OpenACS Default Themes t t Don Baccus Provides the default "plain" and "tabbed" themes for OpenACS Subsites. 2011-06-12 Provides the default "plain" and "tabbed" themes for OpenACS Subsites. This has been moved out to a separate package, with availability recorded in the database, to make it easier for developer's to create their own themes and distribute and/or install them in package form. 0 openacs-5.7.0/packages/acs-core-docs/0000755000175000017500000000000011724401447017177 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/tcl/0000755000175000017500000000000011724401447017761 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/tcl/acs-core-docs-procs.tcl0000644000175000017500000000301007572171136024232 0ustar frankiefrankiead_library { core documentation procs. @author Jeff Davis (davis@xarg.net) @creation-date 2002-09-10 @cvs-id $Id: acs-core-docs-procs.tcl,v 1.4 2002/11/30 17:16:14 jeffd Exp $ } ad_proc -private core_docs_uninstalled_packages_internal {} { Returns a list (in array set format) of package.key package-name (used for display on the index.adp page). @author Jeff Davis (davis@xarg.net) } { set uninstalled [list] # Determine which spec files are not installed foreach spec_file [apm_scan_packages "[acs_root_dir]/packages"] { if { ! [catch {array set version [apm_read_package_info_file $spec_file]} errMsg] } { if { ! [apm_package_registered_p $version(package.key)] } { if {[empty_string_p $version(package-name)]} { set version(package-name) $version(package.key) } lappend uninstalled [list $version(package.key) $version(package-name)] } } } # sort the list and return in array set form set out [list] foreach pkg [lsort -dictionary -index 1 $uninstalled] { set out [concat $out $pkg] } return $out } ad_proc -public core_docs_uninstalled_packages {} { Returns a list (in array set format) of package.key package-name (used for display on the index.adp page). Cached version of core_docs_uninstalled_packages_internal @author Jeff Davis davis@xarg.net } { return [util_memoize core_docs_uninstalled_packages_internal] } openacs-5.7.0/packages/acs-core-docs/www/0000755000175000017500000000000011575225461020027 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/sql/0000755000175000017500000000000011724401447020622 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/sql/display-sql.adp0000644000175000017500000000017507766162044023565 0ustar frankiefrankie SQL Display @context;noquote@ @text;noquote@ openacs-5.7.0/packages/acs-core-docs/www/sql/display-sql.tcl0000644000175000017500000000473510551254373023602 0ustar frankiefrankiead_page_contract { Enables user to see a .sql file without encountering the AOLserver's db module magic (offering to load the SQL into a database) or without returning the SQL as content-type application/x-sql. Patched by philg at Jeff Davis's request on 12/5/99 to close the security hole whereby a client adds extra form vars. Patched on 07/06/2000 by deison to restrict access to only .sql files and only files in /doc or /pageroot. 2000 August 8 Updated for ACS4 packages - richardl@arsdigita.com. @param url The full relative path of the file to display the source for. @param package_key The key of the package the file is part of. @author philg@mit.edu @creation-date 12/19/98 @cvs-id $Id: display-sql.tcl,v 1.5 2007/01/10 21:22:03 gustafn Exp $ } { url:notnull {package_key ""} {db ""} } # This is normally a password-protected page, but to be safe let's # check the incoming URL for ".." to make sure that someone isn't # doing # https://photo.net/doc/sql/display-sql.tcl?url=/../../../../etc/passwd # for example if { [string match "*..*" $url] || [string match "*..*" $package_key] } { ad_return_error "Can't back up beyond the pageroot" "You can't use display-sql.tcl to look at files underneath the pageroot." ad_script_abort } if {[exists_and_not_null package_key]} { set safe_p [regexp {/?(.*)} $url package_url] } if {$db eq ""} { # if we were not passed a DB string get a list of matching files. set text {
      } set files [glob -nocomplain "[acs_package_root_dir $package_key]/sql/*/$url" "[acs_package_root_dir $package_key]/sql/$url"] foreach f $files { regexp {([^/]*)/([^/]*)$} $f match db url append text "
    • $db
    • " } if {$files eq ""} { append text "
    • No sql file found." } append text {
    } set context [list [list ../$package_key $package_key] "SQL Display"] } else { # we have a db. if {$db eq "sql"} { set files [glob -nocomplain "[acs_package_root_dir $package_key]/sql/$url"] } else { set files [glob -nocomplain "[acs_package_root_dir $package_key]/sql/$db/$url"] } if { $safe_p && [llength $files] > 0 } { ns_returnfile 200 text/plain $files } else { ad_return_error "Invalid file location" "Can only display files in package or doc directory." } ad_script_abort } openacs-5.7.0/packages/acs-core-docs/www/xml/0000755000175000017500000000000011575225500020621 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/variables.ent0000644000175000017500000000036111456662500023304 0ustar frankiefrankie openacs-5.7.0/packages/acs-core-docs/www/xml/Makefile0000644000175000017500000000632510622143334022263 0ustar frankiefrankie# A very simple Makefile to generate the HTML docs # @author Vinod Kurup (vinod@kurup.com) # @author Modified by Roberto Mello (rmello@fslc.usu.edu) to have PDF generation # plus refactored it a bit to have rules and dependencies. # @author davis@xarg.net Added automatic creation of an XSL link so we don't edit openacs.xsl, # added a lint target which runs xmllint, changed pdf generation to use FOP. Made it # work on the mac. # OSX note: xmllint from fink does not work, use /usr/bin/xmllint # xmllint from fink seems to work fine on osx 10.4.x # # @creation-date 2002-08-10 # @modified-date 2003-12-06 # # This simply copys all the 'files' and 'images' # to the appropriate directory in www so that they are accessible # # It then moves into the www directory and runs the XSLT generation # and runs htmldoc to generate PDFs. # # I'm a Makefile newbie, so feel free to comment/slash/change. # Paths XSLTPROC=xsltproc HTMLDOC=htmldoc all: html XSL: if [ ! -d XSL -a ! -L XSL ]; then \ echo -e "\n\nNo XSL directory here. I am looking for one...\n"; \ for d in \ /sw/share/xml/docbook-xsl \ /usr/share/sgml/docbook/xsl-stylesheets-* \ /usr/share/sgml/docbook/xsl-stylesheets \ /usr/share/sgml/docbook/stylesheet/xsl/nwalsh; \ do \ if [ -d $$d ]; then \ echo "Found $$d"; \ EXISTS=$$d; \ fi; \ done; \ if [ "$$EXISTS" = "" ]; then \ echo -e "\ \nNo xsl stylesheets found in /usr/share/sgml/docbook/\n\ You need to install them on your system or if they exist already,\n\ symlink them here so that XSL/html/chunk.xsl exists\n\ see http://sourceforge.net/projects/docbook/ for the docbook-xsl stylesheets\n"; \ exit 1; \ else \ echo "I think $$EXISTS is the best one\n\n"; \ ln -s $$EXISTS XSL; \ fi; \ fi; prelim: images cp images/*.{pdf,png,gif,jpg} ../images/ # all non-regenerated html is kept in a sub-dir so that we can delete html # in the main directory before regenerating # this helps avoid meaningless cvs conflicts in second-hand files rm ../*html target: non-xml # the dash u part of cp -u is redundant in the context of make/Makefile cp non-xml/*.html .. cp openacs.css .. html: prelim XSL # adding --nonet --novalid is much faster but generates a bunch of bogus error messages cd .. ; $(XSLTPROC) --xinclude xml/openacs.xsl xml/index.xml # I got this to work with FOP 0.20.5 and docbook-xsl 1.62, and Jimi 1.0 # see README.fop for some notes. pdf: XSL cd ..; fop -d -fo fop.fo -pdf full.pdf fopdf: XSL cd ..; $(XSLTPROC) --xinclude --output fop.fo xml/fo.xsl xml/index.xml cd ..; fop -d -fo fop.fo -pdf full.pdf # Validate with xmllint. --postvalid is needed so validation takes place after xincludes. # In emacs do M-x compile then make lint; then C-x ` to walk through the resulting errors. # /usr/bin/xmllint --xinclude --noout --postvalid index.xml 2>&1 | grep -v 'No declaration for attribute base of element' # /sw/bin/xmllint --xinclude --noout --postvalid index.xml 2>&1 | grep -v 'No declaration for attribute base of element' # I skip adding the grep at the end because it returns an ambiguous error when there are no messages at end of compiling.. due to no errors. lint: XSL /sw/bin/xmllint --xinclude --noout --postvalid index.xml 2>&1 openacs-5.7.0/packages/acs-core-docs/www/xml/files/0000755000175000017500000000000011724401447021725 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/files/acceptance-sql.txt0000644000175000017500000000553407766162045025371 0ustar frankiefrankie-- acceptance-sql.txt by philg@mit.edu and Jin S Choi -- (Philip Greenspun and Jin Choi) -- SQL commands to test an Oracle installation -- for adequate privileges and capacity -- run as the same user as the Web user -- creating a table create table foo ( foo_key integer primary key, random varchar(1000) ); -- creating an index create index foo_on_random on foo ( random ); -- inserting some rows insert into foo values (1, '1'); insert into foo values (2, '2'); insert into foo values (3, '3'); insert into foo values (4, '4'); insert into foo values (5, '5'); insert into foo values (6, '6'); insert into foo values (7, '7'); insert into foo values (8, '8'); insert into foo values (9, '9'); insert into foo values (10, '10'); insert into foo values (11, null); insert into foo values (12, null); insert into foo values (13, null); insert into foo values (14, null); insert into foo values (15, null); insert into foo values (16, null); insert into foo values (17, null); insert into foo values (18, null); insert into foo values (19, null); insert into foo values (20, null); -- create another table to work with create table bar as select foo_key + 1 as bar_key, random from foo; -- joins select b.random from foo f, bar b where f.foo_key = b.bar_key and f.random like '3%'; -- update update foo set foo_key = foo_key + 100 where random is null; -- should return 10 select count(*) from foo where foo_key > 100; -- create a sequence create sequence foo_sequence start with 200; -- test whether truncate works truncate table bar; drop table bar; -- test 1) whether has privileges to create a procedure -- and 2) whether rollback segments are adequately sized -- create a pl/sql procedure create or replace procedure thrash_database(v_number_of_rows IN integer) AS i integer; BEGIN FOR i IN 1..v_number_of_rows LOOP insert into foo (foo_key, random) values (foo_sequence.nextval, 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij'); END LOOP; END thrash_database; / show errors -- we think any Oracle installation ought to be able to handle -- 100,000 rows of 500 bytes each execute thrash_database(100000); select count(*) from foo; commit; delete from foo; commit; drop table foo; drop sequence foo_sequence; drop procedure thrash_database; -- make sure that NLS_DATE_FORMAT is correct by -- seeing that the following command returns -- YYYY-MM-DD (e.g., 1999-05-22) select sysdate from dual; openacs-5.7.0/packages/acs-core-docs/www/xml/releasing-openacs.xml0000644000175000017500000004751310456621135024755 0ustar frankiefrankie %myvars; ]> Releasing OpenACS
    OpenACS Core and .LRN Update Translations Rebuild the Changelog Rebuild the Changelog. I use a tool called cvs2cl. Run this command from the package root to automatically generate a Changelog file in the same dir. We generate two changelogs, one for the minor branch and one for the most recent release. The example below is for OpenACS 5.0.2: cd /var/lib/aolserver/$OPENACS_SERVICE_NAME cvs2cl -F oacs-5-0 --delta openacs-5-0-0-final:oacs-5-0 -f ChangeLog cvs2cl -F oacs-5-0 --delta openacs-5-0-1-final:oacs-5-0 -f ChangeLog-recent Update Version Numbers The version numbers in the documentation and in the packages must be updated. This should only happen after a release candidate is approved. .LRN: this must be repeated for .LRN modules (dotlrn-core in the dotlrn cvs tree) and for any modified modules in the .LRN prerequisites (dotlrn-prereq in openacs cvs tree). My current working model is that I bulk-update .LRN and OpenACS core but that I don't touch dotlrn-prereq modules - I just use the most recent release and it's up to individual package developers to tag and release those packages when they change. This model is already broken because following it means that dotlrn-prereqs don't get new translations. Update /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/xml/variables.ent with the new version number. Add new section in /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/xml/for-everyone/release-notes.xml Regenerate all HTML docs cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/xml make Update /var/lib/aolserver/$OPENACS_SERVICE_NAME/readme.txt with the new version number Update version number and release date in all of the core packages. Use /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/update-info.sh with the new version number and the release date as arguments. Run it from /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages: cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages ./acs-core-docs/www/files/update-info 5.2.1 2006-01-16 Install a new site using the modified code and verify that the automated tests pass. Commit changes to CVS Tag the files in CVS The steps to this point should have ensured that the head of the current branch contains the full set of code to release. Now we need to tag it as the code to be released. Check out OpenACS Core. The files must be checked out through a cvs account with write access and should be a checkout from the release branch. In this example, we are assuming this is being done as a local user on openacs.org (which make the checkout and tagging operations much faster). cd /var/tmp cvs -d /cvsroot checkout -r oacs-5-0 acs-core If doing .LRN, repeat with the dotlrn cvs tree. cd /var/tmp mkdir dotlrn-packages cd dotlrn-packages cvs -d /dotlrn-cvsroot checkout -r dotlrn-2-0 dotlrn-all Tag the tree. If it's a final release of core, move or create the appropriate openacs-major-minor-compat tag. (Ie, if releasing 5.0.3 final, move the openacs-5-0-compat flag.) cd /var/tmp/openacs-4 cvs tag -F openacs-5-0-0a1 cvs tag -F openacs-5-0-compat Branching When we feature-freeze on HEAD as part of the release process, we are blocking new development. To avoid this, we branch the code at this point, so that new work can continue on HEAD while the branch is stabilized for release. However, branching means that bug fixes have to be synchronized between HEAD and the branch, and bug fixes tend to be more frequent right at this time. Therefore, our actual branch point is as late as possible - essentially, we do not branch until and unless new feature work is actively blocked by the feature freeze. Branching is almost the same as tagging, except for the flag and slightly different tag nomenclature. To see the list of old branches, cvs status -v somefile. cvs tag -b oacs-5-0 If doing .LRN: Since the .LRN packages aren't all in one module, we iterate through all of the modules. Log in first (cvs login) so that you don't have to log in for each module. cd /var/tmp/dotlrn-packages for dir in *; do ( cd $dir && cvs tag dotlrn-2-0-2-final ); done for dir in *; do ( cd $dir && cvs tag -F openacs-5-0-compat ); done Note that for the compat tag we use the -F flag which will force the tag to the new version (just in case someone has created the tag already on another version). Excercise care when doing this since you don't want to inadvertently move a prior release tag. Also if the tagging goes horribly wrong for some reason you can delete the tag via "cvs tag -d <symbolic_tag>". Apply the final tag across the tree. First, check out the entire OpenACS tree, getting the most recent stable version of each package. This is most simply done on openacs.org: cd /var/tmp cvs -d /cvsroot checkout -r openacs-5-1-compat openacs-4 cd openacs-4 cvs tag openacs-5-1-2-final Make the tarball(s) openacs-core Go to a new working space and export the tagged files. mkdir /var/tmp/tarball cd /var/tmp/tarball cvs -d /cvsroot export -r openacs-5-0-0a1 acs-core Generate the tarball. cd /var/tmp/tarball mv openacs-4 openacs-5.0.0a1 tar cz -f openacs-5.0.0a1.tar.gz openacs-5.0.0a1 dotlrn Go to a new working space and export the tagged files. (was getting errors here trying to use -d, so gave up and just moved things from openacs-4 to openacs at the end) mkdir /var/tmp/dotlrn-tarball cd /var/tmp/dotlrn-tarball cvs -d /cvsroot export -r openacs-5-0-0a1 acs-core cd /var/tmp/dotlrn-tarball/openacs-4/packages cvs -d /cvsroot export -r openacs-5-0-0a1 dotlrn-prereq cvs -d /dotlrn-cvsroot export -r dotlrn-2-0-0a1 dotlrn-core Copy the dotlrn install.xml file, which controls which packages are installed on setup, to the root location: cp /var/tmp/dotlrn-tarball/openacs-4/packages/dotlrn/install.xml \ /var/tmp/dotlrn-tarball/openacs-4 Generate the tarball cd /var/tmp/dotlrn-tarball mv openacs-4 dotlrn-2.0.0a1 tar cz -f dotlrn-2.0.0a1.tar.gz dotlrn-2.0.0a1 Test the new tarball(s) Download the tarballs just created and install them and make sure everything looks okay and that automated tests pass. Update Web site Update the different places on OpenACS.org where we track status. Release Status for the current version - something like http://openacs.org/projects/openacs/5.0/milestones Home page of openacs.org Post a new news item Clean Up Clean up after yourself. cd /var/tmp rm -rf tarball dotlrn-tarball dotlrn-packages openacs-5.0.0a1 rm -rf /var/tmp/openacs-4 Here is a shell script that automates packaging the tarball (it's a bit out of date with the new steps - I've been doing everything manually or with little throwaway scripts as detailed above until the process is stabilized). release script missing ($Id: releasing-openacs.xml,v 1.21 2006/07/17 05:38:37 torbenb Exp $)
    How to Update the OpenACS.org repository Setup a local OpenACS server running 5.0 or better. Edit packages/acs-admin/www/apm/build-repository.tcl and adjust the Configuration Settings. Request /acs-admin/apm/build-repository on your new server. The page will find all branches in the cvs repository labeled oacs-x-y, and build a repository channel for each of those branches where x>=5 (so not for 4.6 and earlier). It will also build a channel for HEAD, which will be named after what you set in 'head_channel' above. For each channel, it'll do an anonymous checkout of packges and contrib/packages, then build .apm files for each package in the checkout. The files will be stored on the server's hard drive in the directory specified by the 'repository_dir' variable in the page script, by default "[acs_root_dir]/www/repository/". If you're on openacs.org, everything should now be fine. Otherwise, you need to move the entire directory tree to openacs.org:/web/openacs/www/repository, replacing what was already there. This is automated on OpenACS.org by having a dedicated site just for building the repository, invoked with this shell script. Since the page circumvents security checks for ease of use, the entire site is limited to local requests. The script is called daily with a cron job. #!/bin/sh #set -x STATUS=`wget --output-document - http://127.0.0.1:8002/build-repository.tcl | grep DONE | wc -l` if [ $STATUS -eq "1" ] then rm -rf /web/openacs.org/www/repository.old mv /web/openacs.org/www/repository /web/openacs.org/www/repository.old cp -r /web/repository/www/repository /web/openacs.org/www/repository fi
    How to package and release an OpenACS Package In this example, we are packaging and releasing myfirstpackage as version 1.0.0, which is compatible with OpenACS 5.0.x. Update the version number, release date, and package maturity of your package in the APM. Make sure all changes are committed. Tag the updated work.: cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage cvs tag myfirstpackages-1-0-0-final cvs tag -F openacs-5-0-compat Done. The package will be added to the repository automatically. If the correct version does not show up within 24 hours, ask for help on the OpenACS.org development forum.
    How to Update the translations Identify any new locales that have been created. For each new locale, check the parameters, especially that the locale is in the format [two-letter code for language, lower-case]_[TWO-LETTER CODE FOR COUNTRY, UPPER-CASE], and create a sql command. A example sql command for creating a locale is: insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fa_IR', 'Farsi (IR)', 'fa', 'IR', 'FARSI', 'IRAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); Put this command into the following four files. For the upgrade files, the correct file name will depend on the exact version. /packages/acs-lang/sql/postgresql/ad-locales.sql /packages/acs-lang/sql/postgresql/upgrade/upgrade-current-version.sql /packages/acs-lang/sql/oracle/ad-locales.sql /packages/acs-lang/sql/oracle/upgrade/upgrade-current-version.sql Make a backup of the production database. Restore it as a new database. For example, if upgrading from OpenACS 5.1.1, and the site name/database name is translate-511, create translate-512b1. Check out the latest code on the release branch (e.g., oacs-5-1) as a new site, using the new site name (e.g., /var/lib/aolserver/translate-512b1. Copy over any local settings - usually, /etc/config.tcl and /etc/daemontools/run and modify appropriately. Also, copy over several translation-server-only files: ...TBD Shut down the production site and put up a notice (no procedure on how to do this yet.) Start the new site, and upgrade it. Go to ACS Lang admin page and click "Import All Messages" Resolve conflicts, if any, on the provided page. Back on the admin page, click the export link. If there are conflicts, the messages will be exported anyway and any errors will be shown in the web interface. Commit the message catalogs to cvs. From the packages dir, run the acs-lang/bin/check-catalog.sh script. (This checks for keys no longer in use and some other things. Until it is rolled into the UI, do it manually and check the results and take whatever steps you can intuit you should do.) CVS commit the catalog files. Done If everything went well, reconfigure the new site to take over the role of the old site (/etc/config.tcl and /etc/daemontools/run). Otherwise, bring the old site back up while investigating problems, and then repeat.
    openacs-5.7.0/packages/acs-core-docs/www/xml/README.fo0000644000175000017500000000344710005232300022073 0ustar frankiefrankieI was able to generate PDFs using: * xsltproc --version Using libxml 20511, libxslt 10033 and libexslt 722 xsltproc was compiled against libxml 20511, libxslt 10033 and libexslt 722 libxslt 10033 was compiled against libxml 20511 libexslt 722 was compiled against libxml 20511 * FOP version 0.20.5 * Jimi 1.0 from Sun * docbook/xsl-stylesheets-1.62.0/ All this except Jimi was installed unchanged via emerge on gentoo. It works on OS X 10.3 as well but you have to change the fink build file to add jimi when building FOP (and it's only on 10.3 unstable I think). I did have to change the fop executable script to increase the JVM memory. On the last line of /usr/bin/fop (or whereever yours ends up) add -Xms64m -Xmx256m; smaller might work too... 104c104 < $JAVACMD -classpath "$LOCALCLASSPATH" $FOP_OPTS org.apache.fop.apps.Fop "$@" --- > $JAVACMD -Xms64m -Xmx256m -classpath "$LOCALCLASSPATH" $FOP_OPTS org.apache.fop.apps.Fop "$@" FOP generates a number of non-intuitive errors for docbook problems... * If you
    ...
    it can end up in an infinite loop trying to place the table. * If you have a listitem w/o a (or some other block level element) it will have a null pointer exception. * If you try to generate a list-of-tables or figures it barfs. (see in fo.xsl for how to turn this off). * Versions 1.62.4 and 1.64.0 of docbook-xsl generate .fo code that sends FOP into an infinite loop. I may investigate but probably not. All in all it's pretty unforgiving of validation errors and it's output is not great (and it's table handling is iffy). It does make a pdf with a TOC and page numbers though. I would be interested in seeing the output produced by PassiveTeX and XEP. Jeff Davis davis@xarg.netopenacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/0000755000175000017500000000000011724401447023364 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/aolserver4.xml0000644000175000017500000003442410456621135026202 0ustar frankiefrankie %myvars; ]> Install AOLserver 4 by Malte Sussdorff Check suitability of previously installed TCL Start tcl (type tclsh or find it using which tclsh). [root root]% info exists tcl_platform(threaded) 1 [root root]% info patchlevel 8.4.7 [root root]% tclsh info exists tcl_platform(threaded) info patchlevel If the first command returns anything other than 1, then tcl is not threaded. If tcl is threaded and the version is 8.4 or higher, then installing tcl from source is optional. Retrieve TCL 8.4 (or higher) Download and install TCL 8.4 from source Note for Debian users: you can apt-get install tcl8.4-dev if you have the right version (stable users will need to add tcl8.4 to their sources.list file as described on the Install Postgres page). You'll have to use /usr/lib/tcl8.4/ instead of /usr/local/lib when you try to find the tcl libraries, however. If you have not installed TCL already, download the latest TCL version from Sourceforge Debian: apt-get install tcl8.4 tcl8.4-dev and proceed to the next step. In that step, replace --with-tcl=/usr/local/lib/ with --with-tcl=/usr/lib/tcl8.4. Remember that you have to be root if you want to follow these instructions. On Mac OS X type sudo su - to become root. Alternatively use curl -L -O instead of wget (especially on Mac OS X). [root root]# cd /usr/local/src [root src]# wget http://heanet.dl.sourceforge.net/sourceforge/tcl/tcl8.4.9-src.tar.gz [root src]# tar xfz tcl8.4.9-src.tar.gz [root src]# cd tcl8.4.9/unix [root unix]# ./configure --enable-threads [root unix]# make install [root root]# cd /usr/local/src wget http://heanet.dl.sourceforge.net/sourceforge/tcl/tcl8.4.9-src.tar.gz tar xfz tcl8.4.9-src.tar.gz cd tcl8.4.9/unix ./configure --enable-threads make install Retrieve AOLserver Download the aolserver from CVS. [root root]# cd /usr/local/src [root src]# mkdir aolserver40r10 [root src]# cd aolserver40r10 [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver login [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r aolserver_v40_r10 aolserver [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nscache [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nspostgres [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nssha1 [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r v2_7 nsoracle [root aolserver]# wget http://www.tdom.org/tDOM-0.7.8.tar.gz [root aolserver]# tar xvfz tDOM-0.7.8.tar.gz [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/tcllib co -r tcllib-1-8 tcllib [root root]# cd /usr/local/src mkdir aolserver40r10 cd aolserver40r10 cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r aolserver_v40_r10 aolserver cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nscache cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nspostgres cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nssha1 cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r v2_7 nsoracle wget http://www.tdom.org/files/tDOM-0.8.0.tar.gz tar xvfz tDOM-0.8.0.tar.gz cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/tcllib co -r tcllib-1-8 tcllib Configure, compile and install AOLserver Many people need to run more than one version of AOLserver in parallel. This section accomodates future upgrades by installing AOLserver 4 in /usr/local/aolserver40r9. [root aolserver]# cd /usr/local/src/aolserver40r10/aolserver [root aolserver]# ./configure --prefix=/usr/local/aolserver40r10 --with-tcl=/usr/local/lib/ [root aolserver]# make install cd /usr/local/src/aolserver40r10/aolserver ./configure --prefix=/usr/local/aolserver40r10 --with-tcl=/usr/local/lib/ make install If you are using gcc 4 or later, see http://openacs.org/forums/message-view?message_id=309814 If this is the only version of AOLserver in use, or is the default version, create a symlink. If not, then be sure to use /usr/local/aolserver40r10 instead of /usr/local/aolserver in the steps below and check both scripts and makefiles to ensure they use the correct path. [root aolserver]# ln -s /usr/local/aolserver40r10 /usr/local/aolserver Configure, compile and install the modules Install nscache [root aolserver]# cd /usr/local/src/aolserver40r10/nscache [root nscache]# make install AOLSERVER=/usr/local/aolserver Install nsoracle (if you want to use Oracle) [root nscache]# cd ../nsoracle [root nsoracle]# make install AOLSERVER=/usr/local/aolserver OpenACS looks for the Oracle driver at /usr/local/aolserver/bin/ora8.so, but some versions of nsoracle may create nsoracle.so instead. In that case, you can symlink (ln -s nsoracle.so ora8.so) to fix it. Install nspostgres (if you want to use Postgres) [root nscache]# cd ../nspostgres [root nspostgres]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib:/usr/local/aolserver/lib [root nspostgres]# make install POSTGRES=LSB ACS=1 INST=/usr/local/aolserver AOLSERVER=/usr/local/aolserver If you get errors like: nspostgres.c: In function `Ns_PgTableList': nspostgres.c:679: warning: passing arg 3 of `Tcl_DStringAppend' as signed due to prototype then PostGreSQL is probably not in the standard location. The location of PostGreSQL is very dependent on which method was used to install it. To correct the problem, replace LSB with the path to the path to your PostGreSQL installation. Often this is /usr/local/pgsql. You can use the ldd command to verify that all libraries are linked in: ldd /usr/local/src/aolserver40r10/nspostgres/nspostgres.so If you run into problems with libpq.a do the following (and repeat the step above) [root nspostgres]# ranlib /usr/local/pgsql/lib/libpq.a If you run into problems with the linker, edit the Makefile. Add -lnsdb to the MODLIBS var. MODLIBS = -L$(PGLIB) -lpq -lnsdb Install nssha1 [root nspostgres]# cd ../nssha1 Now install nssha1: [root nssha1]# make install AOLSERVER=/usr/local/aolserver If the make fails you will have to edit nssha1.c. Comment out the following 2 lines (lines 139-140): // typedef unsigned int u_int32_t; // typedef unsigned char u_int8_t; Install tDOM [root nssha1]# cd ../tDOM-0.8.0/unix Edit the CONFIG file. Uncomment the instructions meant for AOLserver 4, but edit it to look like this: ../configure --enable-threads --disable-tdomalloc --prefix=/usr/local/aolserver --with-tcl=/usr/local/lib Note that the location of the Tcl library may vary on differnt platforms (e.g. for Debian 3.0: --with-tcl=/usr/lib/tcl8.4) Now you can compile and configure tDOM [root unix]# sh CONFIG [root unix]# make install Install TCLLIB [root nssha1]# cd ../tcllib Configure and compile TCLLIB [root unix]# ./configure -prefix=/usr/local/aolserver40r10 [root unix]# make install Add a database-specific wrapper script. This script sets database environment variables before starting AOLserver; this allows the AOLserver instance to communicate with the database. There is one script for Oracle and one for PostgreSQL. They do not conflict. If you plan to use both databases, install both. Note that this section requires you to have OpenACS files available, which you can get through CVS, through a tarball, or by other means. You can come back to this section after you acquire the OpenACS code, but don't forget to come back. (Note to maintainers: this should be moved to the next page and integrated into the text there) Oracle [root aolserver]# cd /usr/local/aolserver/bin [root bin]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle [root bin]# chmod 750 nsd-oracle [root bin]# cd /usr/local/aolserver/bin cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle chmod 750 nsd-oracle PostgreSQL [root aolserver]# cd /usr/local/aolserver/bin [root bin]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres [root bin]# chmod 755 nsd-postgres [root bin]# cd /usr/local/aolserver/bin cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres chmod 755 nsd-postgres You may need to edit these scripts if you are not using /usr/local/aolserver as the directory of Aolserver4. Change startup script (optional). If you want to run AOLserver on a port below 1024 (normally, for a webserver you will use 80), you will have to change the /var/lib/aolserver/service0/etc/daemontools/run script according to the documentation found there (namely: Add the -b yourip:yourport switch) Test AOLserver. ($Id: aolserver4.xml,v 1.30 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/oracle.xml0000644000175000017500000020476710456621135025372 0ustar frankiefrankie %myvars; ]> Install Oracle 8.1.7 By Vinod Kurup If you are installing PostGreSQL instead of Oracle, skip this section. OpenACS &version; will install with Oracle 9i but has not been extensively tested so may still have bugs or tuning issues. See Andrew Piskorski's Oracle 9i notes for guidance. This installation guide attempts to present all of the information necessary to complete an OpenACS installation. We try hard to make all of the steps possible in one pass, rather than having a step which amounts to "go away and develop a profound understanding of software X and then come back and, in 99% of all cases, type these two lines." The exception to our rule is Oracle production systems. This page describes a set of steps to get a working Oracle development server, but it is unsuitable for production systems. If you will be using OpenACS on Oracle in a production environment, you will experience many problems unless you develop a basic understanding of Oracle which is outside the scope of this document. T This document assumes that you'll be installing Oracle on the same box as AOLserver. For more details on a remote Oracle installation, see Daryl Biberdorf's document. Useful links to find help on how to set up Oracle under Linux are: Dizwell - Howard Roger's company - on Oracle on Linux Werner Puschitz - Oracle on Red Hat Linux SuSE/Oracle Support matrix Acquire Oracle Production Oracle systems should run on certified platforms. Follow the metalink note 223718.1to find certified platforms. If you don't have metalink access, take a look at the Oracle on Linux FAQ: Which Linux Distributions Are Directly Supported By Oracle?. In summary, free and inexpensive Linux distributions are not certified. If you don't have an account at OTN get one: you can download the Oracle software from the Oracle Downloads page. It is also get the CDs shipped to you for a nominal fee from the Oracle Store. Each Oracle release comes with extensive and usually quite well-written documentation. Your first step should be to thoroughly read the release notes for your operating system and your Oracle version. Find the docs here: Oracle 8i Release Documentation Oracle 9i Release Documentation Oracle 10g Release Documentation It is generally useful to run a particular Oracle version with its latest patchset. At the time of writing these were 8.1.7.4 and 9.2.0.5, both of which are considered to be very stable. To be able to download a patchset, you need a (to-pay-for) account on Metalink. You may find the appropriate patchset by following Andrew's suggestion. Things to Keep in Mind Oracle is very well-documented software, the online documentation comes with printable PDFs and full-text search. Altogether there is more than 20.000 pages of documentation, so do not expect to understand Oracle within in a few hours. The best starting pointing into Oracle is the Concepts book. Here's the 8i version and the 9.2 version. To give you an idea of how configurable Oracle is and how much thought you may need to put into buying the proper hardware and creating a sane setup, you should thoroughly read Cary Millsap's Configuring Oracle Server for VLDB and the Optimal Flexible Architecture standard. Throughout these instructions, we will refer to a number of configurable settings and advise certain defaults. With the exception of passwords, we advise you to follow these defaults unless you know what you are doing. Subsequent documents will expect that you used the defaults, so a change made here will necessitate further changes later. For a guide to the defaults, please see . In order for OpenACS to work properly you need to set the environment appropriately. export ORACLE_BASE=/ora8/m01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/8.1.7 export PATH=$PATH:$ORACLE_HOME/bin export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib export ORACLE_SID=ora8 export ORACLE_TERM=vt100 export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data umask 022 open_cursors = 500 nls_date_format = "YYYY-MM-DD" For additional resources/documentation, please see this thread and Andrew Piskorski's mini-guide. Pre-Installation Tasks Though Oracle 8.1.7 has an automated installer, we still need to perform several manual, administrative tasks before we can launch it. You must perform all of these steps as the root user. We recommend entering the X window system as a normal user and then doing a su -. This command gives you full root access. Login as a non-root user and start X by typing startx [joeuser ~]$ startx Open a terminal window type and login as root [joeuser ~]$ su - Password: *********** [root ~]# Create and setup the oracle group and oracle account We need to create a user oracle, which is used to install the product, as well as starting and stopping the database. [root ~]# groupadd dba [root ~]# groupadd oinstall [root ~]# groupadd oracle [root ~]# useradd -g dba -G oinstall,oracle -m oracle [root ~]# passwd oracle You will be prompted for the New Password and Confirmation of that password. Setup the installation location for Oracle. While Oracle can reside in a variety of places in the file system, OpenACS has adopted /ora8 as the base directory. Note: the Oracle install needs about 1 GB free on /ora8 to install successfully. [root ~]# mkdir /ora8 root:/ora8# cd /ora8 root:/ora8# mkdir -p m01 m02 m03/oradata/ora8 root:/ora8# chown -R oracle.dba /ora8 root:/ora8# exit Set up the oracle user's environment Log in as the user oracle by typing the following: [joeuser ~]$ su - oracle Password: ******** Use a text editor to edit the .bash_profile file in the oracle account home directory. [oracle ~]$ emacs .bash_profile You may get this error trying to start emacs: Xlib: connection to ":0.0" refused by server Xlib: Client is not authorized to connect to Server emacs: Cannot connect to X server :0. Check the DISPLAY environment variable or use `-d'. Also use the `xhost' program to verify that it is set to permit connections from your machine. If so, open a new terminal window and do the following: [joeuser ~]$ xhost +localhost Now, back in the oracle terminal: [oracle ~]$ export DISPLAY=localhost:0.0 [oracle ~]$ emacs .bash_profile Try this procedure anytime you get an Xlib connection refused error. Add the following lines (substituting your Oracle version number as needed) to .bash_profile: export ORACLE_BASE=/ora8/m01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/8.1.7 export PATH=$PATH:$ORACLE_HOME/bin export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib export ORACLE_SID=ora8 export ORACLE_TERM=vt100 export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data umask 022 Save the file by typing CTRL-X CTRL-S and then exit by typing CTRL-X CTRL-C. Alternatively, use the menus. Make sure that you do not add any lines like the following # NLS_LANG=american # export NLS_LANG These lines will change the Oracle date settings and will break OpenACS since OpenACS depends on the ANSI date format, YYYY-MM-DD dates. Log out as oracle [oracle ~]$ exit Log back in as oracle and double check that your environment variables are as intended. The env command lists all of the variables that are set in your environment, and grep shows you just the lines you want (those with ORA in it). [joeuser ~]$ su - oracle [oracle ~]$ env | grep ORA If it worked, you should see: ORACLE_SID=ora8 ORACLE_BASE=/ora8/m01/app/oracle ORACLE_TERM=vt100 ORACLE_HOME=/ora8/m01/app/oracle/product/8.1.7 ORA_NLS33=/ora8/m01/app/oracle/product/8.1.7/ocommon/nls/admin/data If not, try adding the files to ~/.bashrc instead of .bash_profile. Then logout and log back in again. Also, be certain you are doing su - oracle and not just su oracle. The - means that .bashrc and .bash_profile will be evaluated. Make sure that /bin, /usr/bin, and /usr/local/bin are in your path by typing: [oracle ~]$ echo $PATH /bin:/usr/bin:/usr/local/bin:/usr/bin/X11:/usr/X11R6/bin:/home/oracle/bin:/ora8/m01/app/oracle/product/8.1.7/bin If they are not, then add them to the .bash_profile by changing the PATH statement above to PATH=$PATH:/usr/local/bin:$ORACLE_HOME/bin Installing Oracle 8.1.7 Server Log in as oracle and start X if not already running. Start a new terminal: [joeuser ~]$ xhost +localhost [joeuser ~]$ su - oracle Password: ********** [oracle ~]$ export DISPLAY=localhost:0.0 Find the runInstaller script If you are installing Oracle from a CD-ROM, it is located in the install/linux path from the cd-rom mount point [oracle ~]$ su - root [root ~]# mount -t iso9660 /dev/cdrom /mnt/cdrom [root ~]# exit [oracle ~]$ cd /mnt/cdrom If you are installing from the tarball, the install script is located in the Oracle8iR2 directory that was created when you expanded the archive. [oracle ~]$ cd /where/oracle/Disk1 Check to make sure the file is there. oracle:/where/oracle/Disk1$ ls doc index.htm install runInstaller stage starterdb If you don't see runInstaller, you are in the wrong directory. Run the installer oracle:/where/oracle/Disk1$ ./runInstaller A window will open that welcomes you to the 'Oracle Universal Installer' (OUI). Click on "Next" Some people have had trouble with this step on RedHat 7.3 and 8.0. If so, try the following steps before calling ./runInstaller: Execute the following command: /usr/i386-glibc21-linux/bin/i386-glibc21-linux-env.sh Type export LD_ASSUME_KERNEL=2.2.5 The "File Locations" screen in the OUI: "Source" path should have been prefilled with "(wherever you mounted the CDROM)/stage/products.jar" "destination" path says "/ora8/m01/app/oracle/product/8.1.7" If the destination is not correct it is because your environment variables are not set properly. Make sure you logged on as oracle using su - oracle. If so, edit the ~/.bash_profile as you did in Click "Next" (a pop up window will display Loading Product information). The "Unix Group Name" screen in the OUI: The Unix Group name needs to be set to 'oinstall' ( we made this Unix group earlier ). Click "Next" A popup window appears instantly, requesting you to run a script as root: Debian users need to link /bin/awk to /usr/bin/awk before running the script below [joueser ~]$ su - [root ~]# ln -s /usr/bin/awk /bin/awk Open a new terminal window, then type: [joeuser ~]$ su - [root ~]# cd /ora8/m01/app/oracle/product/8.1.7 [root ~]# ./orainstRoot.sh ; You should see: Creating Oracle Inventory pointer file (/etc/oraInst.loc) Changing groupname of /ora8/m01/app/oracle/oraInventory to oinstall. [root ~]# mkdir -p /usr/local/java [root ~]# exit [joeuser ~]$ exit Click "Retry" The "Available Products" screen in the OUI: Select "Oracle 8i Enterprise Edition 8.1.7.1.0" Click "Next" The "Installation Types" screen Select the "Custom" installation type. Click "Next" The "Available Product Components" screen In addition to the defaults, make sure that "Oracle SQLJ 8.1.7.0," "Oracle Protocol Support 8.1.7.0.0," and "Linux Documentation 8.1.7.0.0" are also checked. Click "Next" A progress bar will appear for about 1 minute. The "Component Locations" screen in the OUI Click on the "Java Runtime Environment 1.1.8" It should have the path "/ora8/m01/app/oracle/jre/1.1.8" Click "Next" A progress bar will appear for about 1 minute. The "Privileged Operation System Groups" screen in the OUI Enter "dba" for "Database Administrator (OSDBA) Group" Enter "dba" for the "Database Operator (OSOPER) Group" Click "Next" A progress bar will appear for about 1 minute. The "Authentication Methods" screen Click "Next" The next screen is "Choose JDK home directory" Keep the default path: /usr/local/java Click "Next" The "Create a Database" screen in the OUI Select "No" as we will do this later, after some important configuration changes. Click "Next" The next screen is "Oracle Product Support" TCP should be checked with "Status" listed as Required Click "Next" The "Summary" screen in the OUI Check the "Space Requirements" section to verify you have enough disk space for the install. Check that "(144 products)" is in the "New Installations" section title. Click "Install" A progress bar will appear for about 20 - 30 minutes. Now is a good time to take a break. A "Setup Privileges" window will popup towards the end of the installation asking you to run a script as root Run the script. Switch to the oracle user first to set the environment appropriately and then do su to get root privileges, while keeping the oracle user's enviroment. [joeuser ~]$ su - oracle Password: ********* [oracle ~]$ su Password: ********* [root ~]# /ora8/m01/app/oracle/product/8.1.7/root.sh ; You should see the following. Creating Oracle Inventory pointer file (/etc/oraInst.loc) Changing groupname of /ora8/m01/app/oracle/oraInventory to oinstall. # /ora8/m01/app/oracle/product/8.1.7/root.sh Running Oracle8 root.sh script... The following environment variables are set as: ORACLE_OWNER= oracle ORACLE_HOME= /ora8/m01/app/oracle/product/8.1.7 ORACLE_SID= ora8 Enter the full pathname of the local bin directory: [/usr/local/bin]: Press ENTER here to accept default of /usr/local/bin Creating /etc/oratab file... Entry will be added to the /etc/oratab file by Database Configuration Assistants when a database is created Finished running generic part of root.sh script. Now product-specific root actions will be performed. IMPORTANT NOTE: Please delete any log and trace files previously created by the Oracle Enterprise Manager Intelligent Agent. These files may be found in the directories you use for storing other Net8 log and trace files. If such files exist, the OEM IA may not restart. Do not follow the instructions on deleting trace and log files, it is not necessary. [root ~]# exit [joeuser ~]$ exit Go back to the pop-up window and click "OK" The "Configuration Tools" screen in the OUI This window displays the config tools that will automatically be launched. The "Welcome" screen in the "net 8 Configuration Assistant" Make sure the "Perform Typical installation" is not selected. Click "Next" The "Directory Service Access" screen in the "Net 8 Configuration Assistant" Select "No" Click "Next" The "Listener Configuration, Listener Name" screen in the "Net 8 Configuration Assistant" Accept the default listener name of "LISTENER" Click "Next" The "Listener Configuration, Select Protocols" screen in the "Net 8 Configuration Assistant" The only choice in "Select protocols:" should be "TCP/IP" Click "Next" The "Listener Configuration TCP/IP Protocol" screen in the "Net 8 Configuration Assistant" Default Port should be 1521 and selected. Click "Next" The "Listener Configuration, More Listeners" screen in the "Net 8 Configuration Assistant" Select "No" Click "Next" The "Listener Configuration Done" screen in the "Net 8 Configuration Assistant" Click "Next" The "Naming Methods Configuration" screen in the "Net 8 Configuration Assistant" Select "No" Click "Next" The "Done" screen in the "Net 8 Configuration Assistant" Click "Finish" The "End of Installation" screen in the OUI Click "Exit" Click "Yes" on the confirmation pop up window. The Oracle Universal Installer window should have disappeared! Congratulations, you have just installed Oracle 8.1.7 Server! However, you still need to create a database which can take about an hour of non-interactive time, so don't quit yet. Creating the First Database This step will take you through the steps of creating a customized database. Be warned that this process takes about an hour on a Pentium II with 128 MB of RAM. RedHat 7.3 and 8.0 users: Before running dbassist, do the following. Download the glibc patch from Oracle Technet into /var/tmp. cd $ORACLE_HOME tar xzf /var/tmp/glibc2.1.3-stubs.tgz ./setup_stubs Make sure you are running X. Open up a terminal and su to oracle and then run the dbassist program. [joeuser ~]$ xhost +localhost [joeuser ~]$ su - oracle Password: ********* [oracle ~]$ export DISPLAY=localhost:0.0 [oracle ~]$ dbassist The "Welcome" screen in the Oracle Database Configuration Agent (ODCA) Select "Create a database" Click "Next" The "Select database type" screen in the ODCA Select "Custom" Click "Next" The "Primary Database Type" window in ODCA Select "Multipurpose" Click "Next" The "concurrent users" screen of the ODCA Select "60" concurrent users. Click "Next" Select "Dedicated Server Mode", click "Next" Accept all of the options, and click Next Oracle Visual Information Retrieval may be grayed out. If so, you can ignore it; just make sure that everything else is checked. For "Global Database Name", enter "ora8"; for "SID", also enter "ora8" (it should do this automatically). Click "Change Character Set and select UTF8. Click "Next". Accept the defaults for the next screen (control file location). Click "Next" Go to the "temporary" and "rollback" tabs, and change the Size (upper-right text box) to 150MB. Click "Next" Increase the redo log sizes to 10000K each. Click "Next" Use the default checkpoint interval & timeout. Click "Next" Increase "Processes" to 100; "Block Size" to 4096 (better for small Linux boxes; use 8192 for a big Solaris machine). Accept the defaults for the Trace File Directory. Click "Next" Finally, select "Save information to a shell script" and click "Finish" (We're going to examine the contents of this file before creating our database.) Click the "Save" button. Oracle will automatically save it to the correct directory and with the correct file name. This will likely be /ora8/m01/app/oracle/product/8.1.7/assistants/dbca/jlib/sqlora8.sh It will alert you that the script has been saved successfully. Now we need to customize the database configuration a bit. While still logged on as oracle, edit the database initialization script (run when the db loads). The scripts are kept in $ORACLE_HOME/dbs and the name of the script is usually initSID.ora where SID is the SID of your database. Assuming your $ORACLE_HOME matches our default of /ora8/m01/app/oracle/product/8.1.7, the following will open the file for editing. [oracle ~]$ emacs /ora8/m01/app/oracle/product/8.1.7/dbs/initora8.ora Add the following line to the end: nls_date_format = "YYYY-MM-DD" Now find the open_cursors line in the file. If you're using emacs scroll up to the top of the buffer and do CTRL-S and type open_cursors to find the line. The default is 100. Change it to 500. open_cursors = 500 Save the file. In emacs, do CTRL-X CTRL-S to save followed by CTRL-X CTRL-C to exit or use the menu. At this point, you are ready to initiate database creation. We recommend shutting down X to free up some RAM unless you have 256 MB of RAM or more. You can do this quickly by doing a CRTL-ALT-BACKSPACE, but make sure you have saved any files you were editing. You should now be returned to a text shell prompt. If you get sent to a graphical login screen instead, switch to a virtual console by doing CRTL-ALT-F1. Then login as oracle. Change to the directory where the database creation script is and run it: [oracle ~]$ cd /ora8/m01/app/oracle/product/8.1.7/assistants/dbca/jlib oracle:/ora8/m01/app/oracle/product/8.1.7/assistants/dbca/jlib$ ./sqlora8.sh In some instances, Oracle will save the file to /ora8/m01/app/oracle/product/8.1.7/assistants/dbca Try running the script there if your first attempt does not succeed. Your database will now be built. It will take > 1 hour - no fooling. You will see lots of errors scroll by (like: "ORA-01432: public synonym to be dropped does not exist") Fear not, this is normal. Eventually, you'll be returned to your shell prompt. In the meantime, relax, you've earned it. Acceptance Test For this step, open up a terminal and su to oracle as usual. You should be running X and Netscape (or other web browser) for this phase. You need to download the "Oracle Acceptance Test" file. It's available here and at http://philip.greenspun.com/wtr/oracle/acceptance-sql.txt. Save the file to /var/tmp In the oracle shell, copy the file. [oracle ~]$ cp /var/tmp/acceptance-sql.txt /var/tmp/acceptance.sql Once you've got the acceptance test file all set, stay in your term and type the following: [oracle ~]$ sqlplus system/manager SQL*Plus should startup. If you get an ORA-01034: Oracle not Available error, it is because your Oracle instance is not running. You can manually start it as the oracle user. [oracle ~]$ svrmgrl SVRMGR> connect internal SVRMGR> startup Now that you're into SQL*Plus, change the default passwords for system, sys, and ctxsys to "alexisahunk" (or to something you'll remember): SQL> alter user system identified by alexisahunk; SQL> alter user sys identified by alexisahunk; SQL> alter user ctxsys identified by alexisahunk; Verify that your date settings are correct. SQL> select sysdate from dual; If you don't see a date that fits the format YYYY-MM-DD, please read . At this point we are going to hammer your database with an intense acceptance test. This usually takes around 30 minutes. SQL> @ /var/tmp/acceptance.sql ; A bunch of lines will scroll by. You'll know if the test worked if ; you see this at the end: SYSDATE ---------- 2000-06-10 SQL> Many people encounter an error regarding maximum key length: ERROR at line 1: ORA-01450: maximum key length (758) exceeded This error occurs if your database block size is wrong and is usually suffered by people trying to load OpenACS into a pre-existing database. Unfortunately, the only solution is to create a new database with a block size of at least 4096. For instructions on how to do this, see above. You can set the parameter using the dbassist program or by setting the DB_BLOCK_SIZE parameter in your database's creation script. If there were no errors, then consider yourself fortunate. Your Oracle installation is working. Automating Startup & Shutdown You will want to automate the database startup and shutdown process. It's probably best to have Oracle spring to life when you boot up your machine. Oracle includes a script called dbstart that can be used to automatically start the database. Unfortunately, the script shipped in the Linux distribution does not work out of the box. The fix is simple. Follow these directions to apply it. First, save dbstart to /var/tmp. Then, as oracle, do the following: [oracle ~]$ cp /var/tmp/dbstart.txt /ora8/m01/app/oracle/product/8.1.7/bin/dbstart [oracle ~]$ chmod 755 /ora8/m01/app/oracle/product/8.1.7/bin/dbstart While you're logged in as oracle, you should configure the oratab file to load your database at start. Edit the file /etc/oratab: You will see this line. ora8:/ora8/m01/app/oracle/product/8.1.7:N By the way, if you changed the service name or have multiple databases, the format of this file is: service_name:$ORACLE_HOME:Y || N (for autoload) Change the last letter from "N" to "Y". This tells Oracle that you want the database to start when the machine boots. It should look like this. ora8:/ora8/m01/app/oracle/product/8.1.7:Y Save the file & quit the terminal. You need a script to automate startup and shutdown. Save oracle8i.txt in /var/tmp. Then login as root and install the script. (Debian users: substitute /etc/init.d for /etc/rc.d/init.d throughout this section) [oracle ~]$ su - [root ~]# cp /var/tmp/oracle8i.txt /etc/rc.d/init.d/oracle8i [root ~]# chown root.root /etc/rc.d/init.d/oracle8i [root ~]# chmod 755 /etc/rc.d/init.d/oracle8i Test the script by typing the following commands and checking the output. (Debian Users: as root, do mkdir /var/lock/subsys first) [root ~]# /etc/rc.d/init.d/oracle8i stop Oracle 8i auto start/stop Shutting Oracle8i: Oracle Server Manager Release 3.1.7.0.0 - Production Copyright (c) 1997, 1999, Oracle Corporation. All Rights Reserved. Oracle8i Enterprise Edition Release 8.1.7.0.1 - Production With the Partitioning option JServer Release 8.1.7.0.1 - Production SVRMGR> Connected. SVRMGR> Database closed. Database dismounted. ORACLE instance shut down. SVRMGR> Server Manager complete. Database "ora8" shut down. [root ~]# /etc/rc.d/init.d/oracle8i start Oracle 8i auto start/stop Starting Oracle8i: SQL*Plus: Release 8.1.7.0.0 - Production on Wed Mar 6 17:56:02 2002 (c) Copyright 2000 Oracle Corporation. All rights reserved. SQL> Connected to an idle instance. SQL> ORACLE instance started. Total System Global Area 84713632 bytes Fixed Size 73888 bytes Variable Size 76079104 bytes Database Buffers 8388608 bytes Redo Buffers 172032 bytes Database mounted. Database opened. SQL> Disconnected Database "ora8" warm started. Database "ora8" warm started. If it worked, then run these commands to make the startup and shutdown automatic. Red Hat users: [root ~]# cd /etc/rc.d/init.d/ [root ~]# chkconfig --add oracle8i [root ~]# chkconfig --list oracle8i ; You should see: oracle8i 0:off 1:off 2:off 3:on 4:on 5:on 6:off Debian users: [root ~]# update-rc.d oracle8i defaults Adding system startup for /etc/init.d/oracle8i ... /etc/rc0.d/K20oracle8i -> ../init.d/oracle8i /etc/rc1.d/K20oracle8i -> ../init.d/oracle8i /etc/rc6.d/K20oracle8i -> ../init.d/oracle8i /etc/rc2.d/S20oracle8i -> ../init.d/oracle8i /etc/rc3.d/S20oracle8i -> ../init.d/oracle8i /etc/rc4.d/S20oracle8i -> ../init.d/oracle8i /etc/rc5.d/S20oracle8i -> ../init.d/oracle8i SuSE users: [root ~]# cd /etc/rc.d/init.d root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/oracle8i K20oracle8i root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/oracle8i S20oracle8i root:/etc/rc.d/init.d# cp K20oracle8i rc0.d root:/etc/rc.d/init.d# cp S20oracle8i rc0.d root:/etc/rc.d/init.d# cp K20oracle8i rc1.d root:/etc/rc.d/init.d# cp S20oracle8i rc1.d root:/etc/rc.d/init.d# cp K20oracle8i rc6.d root:/etc/rc.d/init.d# cp S20oracle8i rc6.d root:/etc/rc.d/init.d# cp K20oracle8i rc2.d root:/etc/rc.d/init.d# cp S20oracle8i rc2.d root:/etc/rc.d/init.d# cp K20oracle8i rc3.d root:/etc/rc.d/init.d# cp S20oracle8i rc3.d root:/etc/rc.d/init.d# cp K20oracle8i rc4.d root:/etc/rc.d/init.d# cp S20oracle8i rc4.d root:/etc/rc.d/init.d# cp K20oracle8i rc5.d root:/etc/rc.d/init.d# cp S20oracle8i rc5.d root:/etc/rc.d/init.d# rm K20oracle8i root:/etc/rc.d/init.d# rm S20oracle8i root:/etc/rc.d/init.d# cd [root ~]# SuSEconfig Started the SuSE-Configuration Tool. Running in full featured mode. Reading /etc/rc.config and updating the system... Executing /sbin/conf.d/SuSEconfig.gdm... Executing /sbin/conf.d/SuSEconfig.gnprint... Executing /sbin/conf.d/SuSEconfig.groff... Executing /sbin/conf.d/SuSEconfig.java... Executing /sbin/conf.d/SuSEconfig.kdm... Executing /sbin/conf.d/SuSEconfig.pcmcia... Executing /sbin/conf.d/SuSEconfig.perl... Executing /sbin/conf.d/SuSEconfig.postfix... Executing /sbin/conf.d/SuSEconfig.sendmail... Executing /sbin/conf.d/SuSEconfig.susehilf... Executing /sbin/conf.d/SuSEconfig.susehilf.add... Executing /sbin/conf.d/SuSEconfig.susewm... Executing /sbin/conf.d/SuSEconfig.tetex... Executing /sbin/conf.d/SuSEconfig.ypclient... Processing index files of all manpages... Finished. You also need some scripts to automate startup and shutdown of the Oracle8i listener. The listener is a name server that allows your Oracle programs to talk to local and remote databases using a standard naming convention. It is required for Intermedia Text and full site search. Download these three scripts into /var/tmp startlsnr.txt stoplsnr.txt listener8i.txt Now issue the following commands (still as root). [root ~]# su - oracle [oracle ~]$ cp /var/tmp/startlsnr.txt /ora8/m01/app/oracle/product/8.1.7/bin/startlsnr [oracle ~]$ cp /var/tmp/stoplsnr.txt /ora8/m01/app/oracle/product/8.1.7/bin/stoplsnr [oracle ~]$ chmod 755 /ora8/m01/app/oracle/product/8.1.7/bin/startlsnr [oracle ~]$ chmod 755 /ora8/m01/app/oracle/product/8.1.7/bin/stoplsnr [oracle ~]$ exit [root ~]# cp /var/tmp/listener8i.txt /etc/rc.d/init.d/listener8i [root ~]# cd /etc/rc.d/init.d root:/etc/rc.d/init.d# chmod 755 listener8i Test the listener automation by running the following commands and checking the output. root:/etc/rc.d/init.d# ./listener8i stop Oracle 8i listener start/stop Shutting down Listener for 8i: LSNRCTL for Linux: Version 8.1.7.0.0 - Production on 06-MAR-2002 18:28:49 (c) Copyright 1998, Oracle Corporation. All rights reserved. Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost.localdomain)(PORT=1521))) The command completed successfully root:/etc/rc.d/init.d# ./listener8i start Oracle 8i listener start/stop Starting the Listener for 8i: LSNRCTL for Linux: Version 8.1.7.0.0 - Production on 06-MAR-2002 18:28:52 (c) Copyright 1998, Oracle Corporation. All rights reserved. Starting /ora8/m01/app/oracle/product/8.1.7/bin/tnslsnr: please wait... TNSLSNR for Linux: Version 8.1.7.0.0 - Production System parameter file is /ora8/m01/app/oracle/product/8.1.7/network/admin/listener.ora Log messages written to /ora8/m01/app/oracle/product/8.1.7/network/log/listener.log Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost.localdomain)(PORT=1521))) Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC))) Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost.localdomain)(PORT=1521))) STATUS of the LISTENER ------------------------ Alias LISTENER Version TNSLSNR for Linux: Version 8.1.7.0.0 - Production Start Date 06-MAR-2002 18:28:53 Uptime 0 days 0 hr. 0 min. 0 sec Trace Level off Security OFF SNMP OFF Listener Parameter File /ora8/m01/app/oracle/product/8.1.7/network/admin/listener.ora Listener Log File /ora8/m01/app/oracle/product/8.1.7/network/log/listener.log Services Summary... PLSExtProc has 1 service handler(s) ora8 has 1 service handler(s) The command completed successfully This test will verify that the listener is operating normally. Login into the database using the listener naming convention. sqlplus username/password/@SID [root ~]# su - oracle [oracle ~]$ sqlplus system/alexisahunk@ora8 SQL> select sysdate from dual; SYSDATE ---------- 2002-02-22 SQL> exit [oracle ~]$ exit [root ~]# RedHat users: Now run chkconfig on the listener8i script. [root ~]# cd /etc/rc.d/init.d/ root:/etc/rc.d/init.d# chkconfig --add listener8i root:/etc/rc.d/init.d# chkconfig --list listener8i listener8i 0:off 1:off 2:off 3:on 4:on 5:on 6:off Debian users: Now run update-rc.d on the listener8i script. [root ~]# update-rc.d listener8i defaults 21 19 Adding system startup for /etc/init.d/listener8i ... /etc/rc0.d/K19listener8i -> ../init.d/listener8i /etc/rc1.d/K19listener8i -> ../init.d/listener8i /etc/rc6.d/K19listener8i -> ../init.d/listener8i /etc/rc2.d/S21listener8i -> ../init.d/listener8i /etc/rc3.d/S21listener8i -> ../init.d/listener8i /etc/rc4.d/S21listener8i -> ../init.d/listener8i /etc/rc5.d/S21listener8i -> ../init.d/listener8i Test the automation As a final test, reboot your computer and make sure Oracle comes up. You can do this by typing [root ~]# /sbin/shutdown -r -t 0 now Log back in and ensure that Oracle started automatically. [joeuser ~]$ su - oracle [oracle ~]$ sqlplus system/alexisahunk@ora8 SQL> exit Congratulations, your installation of Oracle 8.1.7 is complete. Troubleshooting Oracle Dates Oracle has an internal representation for storing the data based on the number of seconds elapsed since some date. However, for the purposes of inputing dates into Oracle and getting them back out, Oracle needs to be told to use a specific date format. By default, it uses an Oracle-specific format which isn't copacetic. You want Oracle to use the ANSI-compliant date format which is of form 'YYYY-MM-DD'. To fix this, you should include the following line in $ORACLE_HOME/dbs/initSID.ora or for the default case, $ORACLE_HOME/dbs/initora8.ora nls_date_format = "YYYY-MM-DD" You test whether this solved the problem by firing up sqlplus and typing: SQL> select sysdate from dual; You should see back a date like 2000-06-02. If some of the date is chopped off, i.e. like 2000-06-0, everything is still fine. The problem here is that sqlplus is simply truncating the output. You can fix this by typing: SQL> column sysdate format a15 SQL> select sysdate from dual; If the date does not conform to this format, double-check that you included the necessary line in the init scripts. If it still isn't working, make sure that you have restarted the database since adding the line: [joeuser ~]$ svrmgrl SVRMGR> connect internal Connected. SVRMGR> shutdown Database closed. Database dismounted. ORACLE instance shut down. SVRMGR> startup ORACLE instance started. If you're sure that you have restarted the database since adding the line, check your initialization scripts. Make sure that the following line is not included: export nls_lang = american Setting this environment variable will override the date setting. Either delete this line and login again or add the following entry to your login scripts after the nls_lang line: export nls_date_format = 'YYYY-MM-DD' Log back in again. If adding the nls_date_format line doesn't help, you can ask for advice in our OpenACS forums. Useful Procedures Dropping a tablespace Run sqlplus as the dba: [oracle ~]$ sqlplus system/changeme To drop a user and all of the tables and data owned by that user: SQL> drop user oracle_user_name cascade; To drop the tablespace: This will delete everything in the tablespace overriding any referential integrity constraints. Run this command only if you want to clean out your database entirely. SQL> drop tablespace table_space_name including contents cascade constraints; For more information on Oracle, please consult the documentation. Oracle Next Steps Defaults We used the following defaults while installing Oracle. Variable Value Reason ORACLE_HOME /ora8/m01/app/oracle/product/8.1.7 This is the default Oracle installation directory. ORACLE_SERVICE ora8 The service name is a domain-qualified identifier for your Oracle server. ORACLE_SID ora8 This is an identifier for your Oracle server. ORACLE_OWNER oracle The user who owns all of the oracle files. ORACLE_GROUP dba The special oracle group. Users in the dba group are authorized to do a connect internal within svrmgrl to gain full system access to the Oracle system. ($Id: oracle.xml,v 1.21 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/database-maintenance.xml0000644000175000017500000001441310456621135030134 0ustar frankiefrankie %myvars; ]> Database Management By Joel Aufrecht Running a PostgreSQL database on another server To run a database on a different machine than the webserver requires changes to the database configuration file and access control file, and to the OpenACS service's configuration file. Edit the database configuration file, which in a Reference install is located at /usr/local/pgsql/data/postgresql.conf and change #tcpip_socket = false to tcpip_socket = true Change the access control file for the database to permit specific remote clients to access. Access can be controlled ... (add notes from forum post) Change the OpenACS service's configuration file to point to the remote database. Edit /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl and change to Deleting a tablespace Skip down for instructions on . Deleting an Oracle tablespace Should it become necessary to rebuild a tablespace from scratch, you can use the drop user command in SVRMGRL with the cascade option. This command will drop the user and every database object the user owns. SVRMGR> drop user $OPENACS_SERVICE_NAME cascade; If this does not work because svrmgrl "cannot drop a user that is currently connected", make sure to kill the AOLserver using this user. If it still does not work, do: SVRMGR> select username, sid, serial# from v$session where lower(username)='$OPENACS_SERVICE_NAME'; and then SVRMGR> alter system kill session 'sid, serial#'; where sid and serial# are replaced with the corresponding values for the open session. Use with caution! If you feel the need to delete everything related to the service, you can also issue the following: SVRMGR> drop tablespace $OPENACS_SERVICE_NAME including contents cascade constraints; Deleting a PostgreSQL tablespace Dropping a PostgreSQL tablespace is easy. You have to stop any AOLserver instances that are using the database that you wish to drop. If you're using daemontools, this is simple, just use the 'down' flag (-d). If you're using inittab, you have to comment out your server in /etc/inittab, reread the inittab with /sbin/init q, and then restart-aolserver $OPENACS_SERVICE_NAME. Then, to drop the db, just do: [$OPENACS_SERVICE_NAME ~]$ dropdb $OPENACS_SERVICE_NAME DROP DATABASE Vacuum Postgres nightly The "vacuum" command must be run periodically to reclaim space in versions of PostgreSQL before 7.4. The "vacuum analyze" form additionally collects statistics on the disbursion of columns in the database, which the optimizer uses when it calculates just how to execute queries. The availability of this data can make a tremendous difference in the execution speed of queries. This command can also be run from cron, but it probably makes more sense to run this command as part of your nightly backup procedure - if "vacuum" is going to screw up the database, you'd prefer it to happen immediately after (not before!) you've made a backup! The "vacuum" command is very reliable, but conservatism is the key to good system management. So, if you're using the export procedure described above, you don't need to do this extra step. Edit your crontab: [joeuser ~]$ crontab -e We'll set vacuum up to run nightly at 1 AM. Add the following line: 0 1 * * * /usr/local/pgsql/bin/vacuumdb $OPENACS_SERVICE_NAME ($Id: database-maintenance.xml,v 1.8 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/software.xml0000644000175000017500000006710511253303101025732 0ustar frankiefrankie %myvars; ]> Prerequisite Software by Joel Aufrecht OpenACS requires, at a minimum, an operating system, database, and webserver to work. Many additional programs, such as a build environment, Mail Transport Agent, and source control system, are also needed for a fully effective installation. Version Compatibility Matrix OpenACS Version 3.2.5 4.5 4.6 4.6.1 4.6.2 4.6.3 5.0 5.1 5.2 5.3 5.4 5.5 AOLserver 3 Yes No 3.3+ad13 Maybe Yes No 3.3oacs1 Maybe Yes No 3.4.4 No 3.4.4oacs1 Maybe Yes No 3.5.5 Maybe Yes No 4.0 Maybe Yes 4.5 No Yes Tcl 8.4 Yes 8.5.4 - Maybe PostgreSQL 7.0 Yes No 7.2 Maybe Yes No 7.3.2 - 7.3.x No Yes No 7.4 No Yes No 8.0 No Maybe Yes 8.1 No Yes 8.2 No CVS version only Yes 8.3 No Yes Oracle 8.1.6 Maybe Yes Maybe 8.1.7 Maybe Yes Maybe 9i No Yes 10g No Yes 11g No Maybe
    The OpenACS installation instructions assume the operating system and build environment are installed. The instructions explain installation of TCL, Tcllib, tDOM, tclwebtest, a Web Server, a Database, a Process Controller, and Source Control software. The following external links are for reference only. <ulink url="http://openacs.org/projects/openacs/download/">OpenACS &version;</ulink> The OpenACS tarball comprises the core packages and many useful additional packages. This includes a full set of documentation. The tarball works with both PostgreSQL and Oracle. Some scripts require bash shell. Operating System OpenACS is designed for a Unix-like system. It is developed primarily in Linux. It can be run on Mac OS X, and in Windows within VMWare. GNU/Linux The installation assumes a linux kernel of 2.2.22 or newer, or 2.4.14 or newer. FreeBSD FreeBSD guide. The OpenACS Reference Platform uses shell scripts written for bash, which is the standard Linux shell. If you are using a different shell, you will need to substitute your shell's conventions for setting environment variables when appropriate, and install bash to work with the scripts. Substitute fetch when the instructions suggest you use wget to download software. Mac OS X Windows/VMWare The only way to run OpenACS on Windows is through the VMWare emulator. (Please let me know if you have OpenACS running directly in Windows.) Build Environment The Reference Platform installation compiles most programs from source code. <ulink url="http://www.gnu.org/software/libc/libc.html">glibc</ulink> 2.2 or newer, REQUIRED You need recent versions of these libraries for Oracle to work properly. For Unicode support, you need glibc 2.2 or newer. This should be included in your operating system distribution. <ulink url="http://www.gnu.org/software/make/">GNU Make</ulink> 3.76.1 or newer, REQUIRED PostgreSQL and AOLserver require gmake to compile. Note that on most linux distributions, GNU Make is simply named make and there is no gmake, whereas on BSD distributions, make and gmake are different --use gmake. <ulink url="http://www.tcl.tk/">TCL</ulink> 8.4.x <ulink url="http://www.tcl.tk/">TCL</ulink> 8.4.x, REQUIRED OpenACS is written in TCL, an interpreted language. A threaded version of the TCL interpreter must be installed for OpenACS to work. The TCL interpreter that is included in most standard distributions may not be thread safe. <ulink url="http://www.tcl.tk/">TCL</ulink> 8.4.x development headers and libraries, OPTIONAL The site-wide-search service, OpenFTS, requires these to compile. (Debian users: apt-get install tcl8.4-dev). You need this to install OpenFTS. <ulink url="http://tcllib.sourceforge.net/">Tcllib</ulink>, REQUIRED OpenACS &version; uses those Tcl extensions to send e-mail out, among others. <ulink url="http://www.tdom.org/">tDOM</ulink>, REQUIRED OpenACS &version; stores queries in XML files, so we use an AOLserver module called tDOM to parse these files. (This replaces libxml2, which was used prior to 4.6.4.) <ulink url="http://sourceforge.net/project/showfiles.php?group_id=31075">tclwebtest</ulink>, OPTIONAL tclwebtest is a tool for testing web interfaces via tcl scripts. Web Server The web server handles incoming HTTP requests, provides a runtime environment for OpenACS's tcl code, connects to the database, sends out HTTP responses, and logs requests and errors. OpenACS uses AOLserver; some people have had success running Apache with mod_nsd. <ulink url="http://aolserver.com/">AOLserver</ulink> 4.x, REQUIRED Provides the base HTTP server Mat Kovach is graciously maintaining an AOLserver distribution that includes all the patches and modules needed to run OpenACS &version;. These instructions will describe how to install using his source distribution. He also has binaries for SuSE 7.3 and OpenBSD 2.8 (and perhaps more to come), currently located at uptime.openacs.org. It's also possible to download all the pieces and patches yourself: AOLserver is available at aolserver.com The OpenACS PostgreSQL driver (nspostgres.so) is available from SourceForge. If you do decide to use nspostgres.so, you have to remember to change the AOLserver config file to point to nspostgres.so instead of postgres.so. This guide uses Mat Kovach's distro (i.e. postgres.so) The patch that makes exec work on BSD is available at sourceforge.net The patch for aolserver 3.x that makes ns_uuencode work for binary files is available at sourceforge.net The patch that makes AOLserver 3.x respect the -g flag is available at sourceforge.net nsopenssl, OPTIONAL Provides SSL capabilities for AOLserver. It requires OpenSSL. You need this if you want users to make secure (https) connections to your webserver. aolserver3.x requires nsopenssl 2.1a. aolserver4.x requires nsopenssl3; see aolserver.com for latest release. (home page) <ulink url="http://braindamage.alal.com/software/nspam.html">ns_pam</ulink> 0.1 or newer, OPTIONAL Provides PAM capabilities for AOLserver. You need this if you want OpenACS users to authenticate through a PAM module (such as RADIUS). <ulink url="ftp://ftp.freeradius.org/pub/radius/pam_radius-1.3.16.tar">pam_radius 1.3.16</ulink>, OPTIONAL Provides RADIUS capabilities for PAM. You need this if you want to use RADIUS authentication via PAM in OpenACS. <ulink url="http://sourceforge.net/project/showfiles.php?group_id=3152">ns_ldap 0.r8</ulink>, OPTIONAL Provides LDAP capabilities for AOLserver. You need this if you want to use LDAP authentication in OpenACS. <ulink url="http://unc.dl.sourceforge.net/sourceforge/openfts/Search-OpenFTS-tcl-0.3.2.tar.gz">OpenFTS TCL 0.3.2</ulink>, OPTIONAL Adds full-text-search to PostgreSQL and includes a driver for AOLserver. You need this if you want users to be able to search for any text on your site. For postgres 7.4.x and higher, full text search is also available via tsearch2. <ulink url="http://www.analog.cx/">Analog</ulink> 5.32 or newer, OPTIONAL This program examines web server request logs, looks up DNS values, and produces a report. You need this if you want to see how much traffic your site is getting. <ulink url="http://sourceforge.net/projects/balance/">Balance</ulink> 3.11 or newer, OPTIONAL "Balance is a simple but powerful generic tcp proxy with round robin load balancing and failover mechanisms." You need this or something equivalent if you are running a high-availability production site and do not have an external load balancing system. Database The data on your site (for example, user names and passwords, calender entries, and notes) is stored in the database. OpenACS separates the database with an abstraction layer, which means that several different databases all function identically. While you can run the core OpenACS on any supported database, not all contributed packages support all databases. Oracle 8.1.7 (Either this or PostgreSQL is REQUIRED) You can register and download Oracle from Oracle TechNet. You need this if you want to use an Oracle database. <ulink url="http://sourceforge.net/projects/pgsql/">PostgreSQL</ulink> 7.4.x (Either this or Oracle is REQUIRED) You need this if you want to use a PostgreSQL database. Process Controller This is software that initiates other software, and restarts that software if it fails. On Linux, we recommend using Daemontools to control AOLserver and qmail. <ulink url="http://cr.yp.to/daemontools/daemontools-0.76.tar.gz">Daemontools 0.76</ulink>, OPTIONAL You need this if you want AOLserver and qmail to run "supervised," meaning that they are monitored and automatically restarted if they fail. An alternative would be to run the services from inittab. Mail Transport Agent A Mail Transport Agent is a program that handles all incoming and outgoing mail. The Reference Platform uses Qmail; any MTA that provides a sendmail wrapper (that is, that can be invoked by calling the sendmail program with the same variables that sendmail expects) can be used. <ulink url="http://www.qmail.org/netqmail/">Netqmail 1.04</ulink>, OPTIONAL You need this (or a different Mail Transport Agent) if you want your webserver to send and receive email. <ulink url="http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz">ucspi-tcp 0.88</ulink>, OPTIONAL This program listens for incoming TCP connections and hands them to a program. We use it instead of inetd, which is insecure. You need this if you are running qmail. <ulink url="http://www.docbook.org/">DocBook</ulink>, OPTIONAL (docbook-xml v4.4, docbook-xsl v1.56, libxslt 1.0.21, xsltproc 1.0.21). You need this to write or edit documentation. Source Control A Source Control system keeps track of all of the old versions of your files. It lets you recover old files, compare versions of file, and identify specific versions of files. You can use any source control system; the Reference Platform and the OpenACS.org repository (where you can get patched and development code in between releases) use cvs. <ulink url="https://www.cvshome.org/">cvs</ulink> 1.11.18, OPTIONAL cvs is included in most unix distributions. You need this if you want to track old versions of your files, do controlled deployment of code from development to production, or get or contribute development code from openacs.org. ($Id: software.xml,v 1.25 2009/09/13 23:54:41 donb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/win2kinstall.xml0000644000175000017500000005632310456621136026540 0ustar frankiefrankie %myvars; ]> OpenACS Installation Guide for Windows2000 by Matthew Burke and Curtis Galloway NOTE: These instructions were valid for ACS v4, but have not been tested with OpenACS and the ArsDigita binary distributions are no longer available. Currently (10/2003), the best option to get OpenACS &version; running on Windows is to use VMware and John Sequeira's Oasis VM distribution Source: http://openacs.org/projects/openacs/download Bug reports: http://openacs.org/bugtracker/openacs Philosophy: http://photo.net/wtr/thebook/community (the community chapter of Philip and Alex's Guide to Web Publishing) Technical background: http://photo.net/wtr/thebook/ Overview With the recent release of a win32 version of AOLserver, it is now possible to run the OpenACS on Windows2000 and Windows98. This document explains the steps necessary to get the OpenACS installed and running on your machine. Note: We do not recommend running a production server on Windows98. But the platform is more than sufficient for working the problem sets and for getting a feel for the OpenACS. You'll need to use the ArsDigita binary distribution of AOLserver for the Win32 platform, which contains patches for several problems we have come across in the default AOLserver binary distribution. See the ArsDigita AOLserver 3 distribution page for details. You can download the binary distribution from the ArsDigita download page under "ArsDigita AOLserver 3 Binary Distribution for Win32." Please read the release notes in the distribution for configuration notes specific to the version you are downloading. Prerequisites Windows 2000 or Windows 98 WinZip or any tool that can extract gzipped/tarred archives. zsh (free; included in the binary distribution). If this link is broken try http://www.zsh.org. Oracle 8 relational database management system AOLserver (free) Oracle driver for AOLserver (free) It is helpful if you have Oracle interMedia Text for full-text searches. We're also trying to make our system work with the PLS System, available free from http://www.pls.com. Although the zsh shell is the only command-line tool required to install the OpenACS, if you are a UNIX person used to typing ls instead of dir you'll get along much better with the Cygwin toolkit from RedHat (available at http://sourceware.cygnus.com/cygwin). This is a development library and set of tools that gives you a very UNIX-like environment under Windows. In particular, it includes bash, gzip and tar, which you can use to perform the OpenACS installation instead of WinZip and zsh. Your Oracle installation When you install Oracle, a good rule of thumb is "every default setting is wrong." We will not discuss Oracle configuration here except to mention that the OpenACS requires Oracle's NLS_DATE_FORMAT parameter be set to 'YYYY-MM-DD'. Fixing this depends on whether Oracle Administration Assistant for Windows NT (yes, that's Windows NT) will run on your machine or not (in some cases, it will complain about Microsoft Managment Console not being installed). If it runs on your machine, proceed as follows: Run Oracle Administration Assistant for Windows NT Navigate using the Explorer-style control in the left panel and select the Oracle Home for the database you wish to use. Bring up its properties dialog and add a parameter NLS_DATE_FORMAT with value 'YYYY-MM-DD' (without the quotes) Verify the date format by logging into the database using SQL Plus and run the following query: select sysdate from dual; Otherwise you will need to perform a little registry surgery as follows: Run regedit and navigate down the registry keys to HKEY_LOCAL_MACHINE\Software\ORACLE. Choose the appropriate subtree; this will be HOME0 if you only have on einstallation of Oracle.
    If you are an Oracle achiever and have more than one Oracle installation on your machine, you will see HOME0, HOME1, HOME2, etc. Choose the subtree that corresponds to the Oracle installtion you wish to use with the OpenACS.
    If the NLS_DATE_FORMAT key is already present, double-click on its value and change it to 'YYYY-MM-DD' (without the quotes). If the key does not exist, choose Edit->New->String Value from the menu and type NLS_DATE_FORMAT for the name of the new value to create it. Then double-click on the empty value to change it. Verify the date format by logging into the database using SQL Plus and run the following query: select sysdate from dual;
    For more information on Oracle configuration look at http://photo.net/wtr/oracle-tips or search the OpenACS forums. One other note: the "nuke a user" admin page and Intermedia won't run unless you set open_cursors = 500 for your database.
    The ArsDigita binary installation Extract the ArsDigita AOLserver distribution onto the C: drive into the default aol30 directory. You can install it on any drive, but it will make your life easier if you keep the AOLserver binary and your OpenACS instance on the same drive. For the rest of these instructions, we'll assume that you used drive C:. Untar the OpenACS We recommend rooting webserver content in c:\web. Since most servers these days are expected to run multiple services from multiple IP addresses, each server gets a subdirectory from c:\web. For example, http://scorecard.org would be rooted at c:\web\scorecard on one of our machines and if http://jobdirect.com were on the same box then it would be at c:\web\jobdirect. For the sake of argument, we're going to assume that your service is called "yourdomain", is going to be at http://yourdomain.com and is rooted at c:\web\yourdomain in the Windows 2000 file system. Note that you'll find our definitions files starting out with "yourdomain.com". download the OpenACS (see above) into c:\temp\acs.tar.gz use WinZip (or equivalent) to extract the files to c:\web\yourdomain You'll now find that c:\web\yourdomain\www contains the document root and c:\web\yourdomain\tcl contains Tcl scripts that are loaded when the AOLserver starts up. Feeding Oracle the Data Model The entire server will behave in an unhappy manner if it connects to Oracle and finds that, for example, the users table does not exist. Thus you need to connect to Oracle as whatever user the AOLserver will connect as, and feed Oracle the table definitions. load the states, country_codes and counties tables using the load-geo-tables shell script in the c:\web\yourdomain\www\install directory. You will need to open a console window and run zsh load-geo-tables foo/foopassword You most likely will see a slew of "Commit point reached . . . " messages. This does not indicate a problem. cd to c:\web\yourdomain\www\doc\sql and feed Oracle the .sql files that you find there. There is a meta-loader file, load-data-model.sql, that includes the other files in the proper order. To use it, open a console window and run sqlplus foo/foopassword < load-data-model.sql If you have interMedia installed, while still in c:\web\yourdomain\www\doc\sql, run zsh load-site-wide-search foo foopassword ctxsys-password Note that there's no slash between foo and foopassword here. The third argument, ctxsys-password, is the password for interMedia Text's special ctxsys user. Configuring AOLserver You will need two configuration files. The first is a Tcl file with configuration information for AOLserver. This should be called yourdomain and should be located in c:\aolserve3_0. The second is an .ini file that configures the OpenACS and is discussed below. Note that pathnames in yourdomain must use forward slashes rather than the Windows back slashes. This is also true for the .ini file. The following items must be defined in yourdomain: three database pools: main, subquery, and log. They must be named as such. The default pool will be "main". the auxconfig directory which contains the .ini file: c:\web\yourdomain\parameters the pageroot: c:\web\yourdomain\www the directory containing the TclLibrary: c:\web\yourdomain\tcl You can use our template file as a starting point (you'll need to save this file with a rather than .txt extension). Configuring OpenACS itself If you want a system that works, go to c:\web\yourdomain\parameters and copy ad.ini to yourdomain.ini (or any other name different from ad.ini). You don't actually have to delete ad.ini. Each section of yourdomain.ini has a hardcoded "yourservername" in the name (e.g. [ns/server/yourservername/acs]). This means that the OpenACS will ignore your configuration settings unless your AOLserver name happens to be "yourservername". Therefore you must go through yourdomain.ini and change "yourservername" to whatever you're calling this particular AOLserver (look at the server name in the nsd file for a reference). Unless you want pages that advertise a community called "Yourdomain Network" owned by "webmaster@yourdomain.com", you'll probably want to edit the text of yourdomain.ini to change system-wide parameters. If you want to see how some of these are used, a good place to look is c:\web\yourdomain\tcl\ad-defs. The Tcl function, ad_parameter, is used to grab parameter values from the .ini file. Starting the Service Now you're ready to start things up. Before installing as a Windows service, you might want to test the setup for configuration errors. Open up a console window and go to c:\aol30. Then run bin\nsd -ft yourdomain.tcl This will print all the AOLserver messages to the console so you can see them. Try to connect to your new server with a web browser. If you see the message "Error in serving group pages", you probably forgot to copy the ad.ini file in c:\web\yourdomain\parameters If everything seems ok, you can kill the server with Control-c and then issue the following command to install as a Windows service: bin\nsd -I -s yourdomain -t yourdomain.tcl You can now configure error recovery and other Windows aspects of the service from the Services control panel. If you make further changes to yourdomain or yourdomain.ini you should stop and start the service from the Services control panel. Configuring Permissions Now, you need to protect the proper administration directories of the OpenACS. You decide the policy although we recommend requiring the admin directories be accessible only via an SSL connection. Here are the directories to consider protecting: /doc (or at least /doc/sql/ since some AOLserver configurations will allow a user to execute SQL files) /admin any private admin dirs for a module you might have written that are not underneath the /admin directory Adding Yourself as a User and Making Yourself a Sysadmin OpenACS will define two users: system and anonymous. It will also define a user group of system administrators. You'll want to add yourself as a user (at /register/ ) and then add yourself as as member of the site-wide administration group. Start by logging out as yourself and logging in as the system user (email of "system"). Change the system user's password. Visit the https://yourservername.com/admin/ug/ directory and add your personal user as a site-wide administrator. Now you're bootstrapped! If you do not know what the system user's password is connect to Oracle using SQL Plus and run the following query: select password from users where last_name = 'system'; Closing Down Access The OpenACS ships with a user named "anonymous" (email "anonymous") to serve as a content owner. If you're operating a restricted-access site, make sure to change the anonymous user's password. In recent versions of the OpenACS you cannot log into "anonymous" because the account does not have a valid user state. Log in as a sysadmin and change the anonymous user's password from https://yourservername/admin/users. You should read the documentation for user registration and access control and decide what the appropriate user state is for anonymous on your site. Where to Find What A few pointers: the /register directory contains the login and registration scripts. You can easily redirect someone to /register/index to have them login or register. the /pvt directory is for user-specific pages. They can only be accessed by people who have logged in. Making sure that it works Run the acceptance tests in /doc/acceptance-test Running Multiple Instances of the OpenACS You can run multiple instances of the OpenACS on a physical machine but they must each be set up as a separate Windows service. Each instance of the OpenACS must have its own: Oracle tablespace and a user account with the appropriate permissions on that tablespace. Each of these tablespaces must have the OpenACS data model loaded. file with the appropriate settings including server name, auxconfig, ipaddress, and port. Copy of the acs files in an appropriate directory under c:\web. Suppose you wish to run two services: lintcollectors.com and iguanasdirect.com. You would need the following: an Oracle tablespace, lintcollectors with a user lintcollectors and password secretlint an Oracle tablespace, iguanasdirect with a user iguanasdirect and password secretiguanas For each of these tablespaces/users you would load the OpenACS data model as described above. Then in c:\aolserver3_0 create files for each service, i.e. lintcollectors and iguanasdirect. These files would point to their respective pageroots, c:\web\lintcollectors\www and c:\web\iguanasdirect\www; their respective auxconfigdirs, c:\web\lintcollectors\parameters and c:\web\iguanasdirect\parameters; etc. In the respective auxconfigdirs would be the files lintcollectors.ini and iguanasdirect.ini. Now open a console window and go to c:\aol30. You'll start up the two services as follows: bin\nsd -I -s lintcollectors -t lintcollectors.tcl bin\nsd -I -s iguanasdirect -t iguanasdirect.tcl In the services control panel you should see two services: AOLserver-lintcollectors and AOLserver-iguanasdirect. ($Id: win2kinstall.xml,v 1.10 2006/07/17 05:38:38 torbenb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/aolserver.xml0000644000175000017500000004172610456621135026121 0ustar frankiefrankie %myvars; ]> Install AOLserver 3.3oacs1 by Vinod Kurup We recommend the use of AOLserver 4.0.1 or later. These instructions are retained as a resource. Debian users: we do not recommend installing Debian packages for Aolserver or Postgres. Several people have reported problems while trying to install using apt-get instead of from source. If you have the time to debug these and submit what you did, that's great, but if not, you should stick to installing from source. Unpack the Aolserver tarball Download the aolserver tarball and unpack it. [root root]# cd /usr/local/src [root src]# wget --passive http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz --15:38:08-- http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz => `aolserver3.3oacs1.tar.gz' Resolving uptime.openacs.org... done. Connecting to uptime.openacs.org[207.166.200.199]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 3,858,074 [application/x-compressed] 100%[====================================>] 3,858,074 66.56K/s ETA 00:00 15:39:05 (66.56 KB/s) - `aolserver3.3oacs1.tar.gz' saved [3858074/3858074] [root src]# tar xzf aolserver3.3oacs1.tar.gz [root src]# cd /usr/local/src wget --passive http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz tar xzf aolserver3.3oacs1.tar.gz This section also relies on some OpenACS files, which you can get with . Compile AOLserver Compile and install AOLserver. First, prepare the installation directory and the source code. The message about BUILD-MODULES can be ignored. root@yourserver root]# mkdir -p /usr/local/aolserver [root root]# cd /usr/local/src/aolserver [root aolserver]# ./conf-clean cat: BUILD-MODULES: No such file or directory Done. [root aolserver]#mkdir -p /usr/local/aolserver cd /usr/local/src/aolserver ./conf-clean If you are using Oracle, edit conf-db and change postgresql to oracle, or to the word both if you want both drivers installed. In order to get nsoracle to compile, you may need to su - oracle, and then su (without the -) root to set the environment variables properly. conf-inst should contain the location where AOLserver is to be installed. Overwrite the tarball's default value with our default value, /usr/local/aolserver: [root aolserver]# echo "/usr/local/aolserver" > conf-inst [root aolserver]# conf-make should contain the name of the GNU Make command on your system. It defaults to gmake. Debian users: ln -s /usr/bin/make /usr/bin/gmake. Set an environment variable that the nspostgres driver Makefile needs to compile correctly and run conf, which compiles AOLserver, the default modules, and the database driver, and installs them. Debian users, see warning above, but if you do use apt-get for AOLserver 3.3+ad13 and postgresql from apt-get may need to make these symlinks: ln -s /usr/include/postgresql/ /usr/include/pgsql and ln -s /usr/lib/postgresql /usr/local/pgsql) [root aolserver]# export POSTGRES=/usr/local/pgsql; ./conf Building in /usr/local/aolserver with the following modules: aolserver nscache nsrewrite nssha1 nsxml pgdriver ================================================================== Starting Build Sat Mar 8 10:28:26 PST 2003 Running gmake in aolserver/; output in log/aolserver.log (several minute delay here) Running gmake in nscache/; output in log/nscache.log Running gmake in nsrewrite/; output in log/nsrewrite.log Running gmake in nssha1/; output in log/nssha1.log Running gmake in nsxml/; output in log/nsxml.log Running gmake in nspostgres/; output in log/nspostgres.log Creating ... ================================================================== Done Building Sat Mar 8 10:31:35 PST 2003 [root aolserver]# This takes about 5 minutes. It builds aolserver, several modules, and the database driver. (Upgraders, note that the postgres database driver has changed from postgres.so to nspostgres.so). All of the results are logged to files in /usr/local/src/aolserver/log. If you run into problems running AOLserver, check these files for build errors. Add a database-specific wrapper script. This script sets database environment variables before starting AOLserver; this allows the AOLserver instance can communicate with the database. There is one script each for Oracle and PostgreSQL. They don't conflict, so if you plan to use both databases, install both. Oracle [root aolserver]# cd /usr/local/aolserver/bin [root bin]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle [root bin]# chmod 750 nsd-oracle [root bin]# cd /usr/local/aolserver/bin cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle chmod 750 nsd-oracle PostgreSQL [root aolserver]# cd /usr/local/aolserver/bin [root bin]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres [root bin]# chmod 755 nsd-postgres [root bin]# cd /usr/local/aolserver/bin cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres chmod 755 nsd-postgres Install tDOM Download the tDOM tarball, unpack it, adjust the configuration file to match our patched distribution of aolserver, and compile it. [root root]# cd /usr/local/src [root src]# wget --passive http://www.tdom.org/tDOM-0.7.8.tar.gz --16:40:58-- http://www.tdom.org/tDOM-0.7.8.tar.gz => `tDOM-0.7.8.tar.gz' Resolving www.tdom.org... done. Connecting to www.tdom.org[212.14.81.4]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 826,613 [application/x-compressed] 100%[====================================>] 826,613 138.06K/s ETA 00:00 16:41:04 (138.06 KB/s) - `tDOM-0.7.8.tar.gz' saved [826613/826613] [root src]# tar xzf tDOM-0.7.8.tar.gz [root src]# cd tDOM-0.7.8/unix [root unix]# cd /usr/local/src wget --passive http://www.tdom.org/tDOM-0.7.8.tar.gz tar xzf tDOM-0.7.8.tar.gz cd tDOM-0.7.8/unix Edit the file CONFIG and change this section: # ---------------------------------------------------- # aolsrc="/usr/src/aolserver-3.4" # ../configure --enable-threads --disable-tdomalloc \ # --with-aolserver=$aolsrc \ # --with-tcl=$aolsrc/tcl8.3.4/unix to # ---------------------------------------------------- aolsrc="/usr/local/src/aolserver/aolserver" ../configure --enable-threads --disable-tdomalloc \ --with-aolserver=$aolsrc \ --with-tcl=$aolsrc/tcl8.3.2/unix And configure and compile: [root unix]# sh CONFIG creating cache ./config.cache checking for memmove... yes (many lines omitted) creating Makefile creating tdomConfig.sh [root unix]# make gcc -pipe -DHAVE_UNISTD_H=1 -DHAVE_LIMITS_H=1 -DTCL_THREADS=1 -DHAVE_GETCWD=1 -DHAVE_OPENDIR=1 -DHAVE_STRSTR=1 -DHAVE_STRTOL=1 (many lines omitted) -Wl,-rpath,/usr/local/lib -o tcldomsh;\ fi [root unix]# cp libtdom0.7.8.so /usr/local/aolserver/bin/ [root unix]# cd /usr/local/aolserver/bin/ [root bin]# ln -s libtdom0.7.8.so libtdom.so [root bin]# sh CONFIG make cp libtdom0.7.8.so /usr/local/aolserver/bin/ cd /usr/local/aolserver/bin ln -s libtdom0.7.8.so libtdom.so Install nsopenssl (OPTIONAL) Install Full Text Search with OpenFTS (OPTIONAL) Install nspam (OPTIONAL) Test AOLserver In order to test AOLserver, we'll run it using the sample-config.tcl file provided in the AOLserver distribution, under the nobody user and web group. The sample-config.tcl configuration writes to the default log locations, so we need to give it permission to do so or it will fail. Grant the web group permission to write to /usr/local/aolserver/log and /usr/local/aolserver/servers. [root root]# cd /usr/local/aolserver [root aolserver]# chown -R root.web log servers [root aolserver]# chmod -R g+w log servers [root aolserver]# ls -l total 32 drwxr-sr-x 2 root root 4096 Mar 8 12:57 bin drwxr-xr-x 3 root root 4096 Mar 8 10:34 include drwxr-sr-x 3 root root 4096 Mar 8 10:34 lib drwxrwsr-x 2 root web 4096 Mar 8 10:31 log drwxr-sr-x 3 root root 4096 Mar 8 10:31 modules -rw-r--r-- 1 root root 7320 Mar 31 2001 sample-config.tcl drwxrwsr-x 3 root web 4096 Mar 8 10:31 servers [root aolserver]# cd /usr/local/aolserver chown -R root.web log servers chmod -R g+w log servers ls -l Note: AOLserver4.x does not include a default start page, so we create one for this test. Type echo "Welcome to AOLserver" > /usr/local/aolserver40r8/servers/server1/pages/index.html Now, we'll run a quick test to ensure AOLserver is running correctly. We'll use the sample config file provided with AOLserver. This file will attempt to guess your IP address and hostname. It will then start up the server at port 8000 of that IP address. [root aolserver]# ./bin/nsd -t sample-config.tcl -u nobody -g web [root aolserver]# [08/Mar/2003:15:07:18][31175.8192][-main-] Notice: config.tcl: starting to read config file... [08/Mar/2003:15:07:18][31175.8192][-main-] Warning: config.tcl: nsssl not loaded -- key/cert files do not exist. [08/Mar/2003:15:07:18][31175.8192][-main-] Warning: config.tcl: nscp not loaded -- user/password is not set. [08/Mar/2003:15:07:18][31175.8192][-main-] Notice: config.tcl: finished reading config file. The first warning, about nsssl, can be ignored. We won't be using nsssl; we'll be using nsopenssl instead, and we haven't fully configured it yet. The nscp warning refers to the fact that, without a user and password in the config file, the administrative panel of AOLserver won't load. We don't plan to use it and can ignore that error as well. Any other warning or error is unexpected and probably a problem. Test to see if AOLserver is working by starting Mozilla or Lynx on the same computer and surfing over to your web page. If you browse from another computer and the sample config file didn't guess your hostname or ip correctly, you'll get a false negative test. [root aolserver]# lynx localhost:8000 You should see a "Welcome to AOLserver" page. If this doesn't work, try going to http://127.0.0.1:8000/. If this still doesn't work, check out the section below. Note that you will not be able to browse to the web page from another machine, because AOLserver is only listening to the local address. Shutdown the test server: [root aolserver]# killall nsd [root aolserver]# The killall command will kill all processes with the name nsd, but clearly this is not a good tool to use for managing your services in general. We cover this topic in the section. Troubleshooting. If you can't view the welcome page, it's likely there's a problem with your server configuration. Start by viewing your AOLserver log, which is in /usr/local/aolserver/log/server.log. You should also try to find lines of the form: [01/Jun/2000:12:11:20][5914.4051][-nssock-] Notice: nssock: listening on http://localhost.localdomain:8000 (127.0.0.1:8000) [01/Jun/2000:12:11:20][5914.4051][-nssock-] Notice: accepting connections If you can find these lines, try entering the URL the server is listening on. If you cannot find these lines, there must be an error somewhere in the file. Search for lines beginning with the word Error instead of Notice. The sample-config.tcl file grabs your address and hostname from your OS settings. set hostname [ns_info hostname] set address [ns_info address] If you get an error that nssock can't get the requested address, you can set these manually. If you type 0.0.0.0, AOLserver will try to listen on all available addresses. Note: ns_info address doesn't appear to be supported in current versions of AOLserver. set hostname [ns_info hostname] #set address [ns_info address] set address 0.0.0.0 Install Analog web file analyzer. (OPTIONAL) ($Id: aolserver.xml,v 1.22 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/quick.xml0000644000175000017500000000613310456621136025225 0ustar frankiefrankie %myvars; ]> Quick Install by Joel Aufrecht Purpose of this document This page describes a minimal installation of OpenACS with PostgreSQL (not Oracle). It will produce a working OpenACS installation in under an hour. It excludes source control, full text search, ssl, managed services (daemontools), DocBook, and qmail. For Red Hat 9 Install PostgreSQL 7.3.2 from RPM. Select Menu > System Settings > Add/Remove Applications and select Database Server. Postgres section missing After completing installation and restarting the server, go to for configuration and customization instructions. You can upgrade a Quick Install with source control, full text search, backup/recovery, and other production features by walking through the Installation documentation and doing the steps marked OPTIONAL. ($Id: quick.xml,v 1.5 2006/07/17 05:38:38 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/upgrade.xml0000644000175000017500000012460211501005400025520 0ustar frankiefrankie %myvars; ]> Upgrading by Joel Aufrecht Overview Starting with Version 4.5, all OpenACS core packages support automatic upgrade. That means that, if you have OpenACS 4.5 or better, you should always be able to upgrade all of your core packages automatically. If you haven't changed anything, no manual intervention should be required. If you are running OpenACS prior to 4.5, upgrading will require manual effort. If all of these conditions are true: Your OpenACS Core is 5.0.0 or later You do not keep your OpenACS site in a local CVS repository You do not have any custom code then you can upgrade automatically using the automated installer in the OpenACS Package Manager (APM), and you can probably skip the rest of this chapter. To upgrade directly from the OpenACS repository using the APM: Browse to the Installer. Click install or upgrade under "Install from OpenACS Repository" and select the packages to install or upgrade. The APM will download the requested packages from OpenACS.org, install the files on your hard drive, run any appropriate database upgrade scripts, and prompt you to restart the server. After restarting the server again, the upgrade is complete.
    Upgrading with the APM
    It's always a good idea to precede an upgrade attempt with a snapshot backup. Assumptions in this section name of OpenACS user $OPENACS_SERVICE_NAME OpenACS server name $OPENACS_SERVICE_NAME Root of OpenACS file tree /var/lib/aolserver/$OPENACS_SERVICE_NAME Database backup directory /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup
    Upgrading 4.5 or higher to 4.6.3 upgrade OpenACS 4.5 to 4.6.x Linux/Unix The required platform for OpenACS 4.6 is the same as 4.5, with the exception of OpenFTS. OpenACS 4.6 and later require OpenFTS 0.3.2 for full text search on PostGreSQL. If you have OpenFTS 0.2, you'll need to upgrade. If upgrading from 4.4, you need to manually run acs-kernel/sql/postgres/upgrade-4.4-4.5.sql. See Bug #632 A computer with OpenACS 4.5. OpenACS 4.6 tarball or CVS checkout/export. Required for Full Text Search on PostgreSQL: OpenFTS 0.3.2 Make a Backup Back up the database and file system (see ). OPTIONAL: Upgrade OpenFTS Stop the server [root root]# svc -d /service/$OPENACS_SERVICE_NAME Upgrade the file system Start the server [root root]# svc -u /service/$OPENACS_SERVICE_NAME Use APM to upgrade the database Browse to the package manager, http://yourserver/acs-admin/apm. Click Install packages. Select the packages you want to install. This should be everything that says upgrade, plus any new packages you want. It's safest to upgrade the kernel by itself, and then come back and upgrade the rest of the desired packages in a second pass. On the next screen, click Install Packages When prompted, restart the server: [root root]# restart-aolserver $OPENACS_SERVICE_NAME Wait a minute, then browse to the package manager, http://yourserver/acs-admin/apm. Check that the kernel upgrade worked by clicking All and making sure that acs-kernel version is &version;. Rollback If anything goes wrong, roll back to the backup snapshot. Upgrading OpenACS 4.6.3 to 5.0 Oracle This forum posting documents how to upgrade an Oracle installation from OpenACS 4.6.3 to 5 . PostGreSQL You must use PostGreSQL 7.3.x or newer to upgrade OpenACS beyond 4.6.3. See Upgrade PostGreSQL to 7.3; Back up the database and file system. Upgrade the file system for packages/acs-kernel Upgrade the kernel manually. (There is a script to do most of the rest: /contrib/misc/upgrade_4.6_to_5.0.sh on HEAD). You'll still have to do a lot of stuff manually, but automated trial and error is much more fun.) [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/ $OPENACS_SERVICE_NAME/packages/acs-kernel/sql/postgresql/upgrade Manually execute each of the upgrade scripts in sequence, either from within psql or from the command line with commands such as psql -f upgrade-4.6.3-4.6.4.sql $OPENACS_SERVICE_NAME. Run the scripts in this order (order is tentative, not verified): psql -f upgrade-4.6.3-4.6.4.sql $OPENACS_SERVICE_NAME psql -f upgrade-4.6.4-4.6.5.sql $OPENACS_SERVICE_NAME psql -f upgrade-4.6.5-4.6.6.sql $OPENACS_SERVICE_NAME psql -f upgrade-4.7d-4.7.2d.sql $OPENACS_SERVICE_NAME psql -f upgrade-4.7.2d-5.0d.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0d-5.0d2.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0d2-5.0d3.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0d6-5.0d7.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0d7-5.0d9.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0d11-5.0d12.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0.0a4-5.0.0a5.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0.0b1-5.0.0b2.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0.0b2-5.0.0b3.sql $OPENACS_SERVICE_NAME psql -f upgrade-5.0.0b3-5.0.0b4.sql $OPENACS_SERVICE_NAME Upgrade ACS Service Contracts manually: [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/ $OPENACS_SERVICE_NAME/packages/acs-service-contracts/sql/postgresql/upgrade psql -f upgrade-4.7d2-4.7d3.sql $OPENACS_SERVICE_NAME Load acs-authentication data model. psql -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/openacs-5/packages/acs-authentication/sql/postgresql/acs-authentication-create.sql $OPENACS_SERVICE_NAME Load acs-lang data model. psql -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-lang/sql/postgresql/acs-lang-create.sql $OPENACS_SERVICE_NAME (This step may overlap with the two previous steps, but I think it's harmless?) Create a file which will be executed on startup which takes care of a few issues with authentication and internationalization: create $OPENACS_SERVICE_NAME/tcl/zzz-postload.tcl containing: if {![apm_package_installed_p acs-lang]} { apm_package_install -enable -mount_path acs-lang [acs_root_dir]/packages/acs-lang/acs-lang.info lang::catalog::import -locales [list "en_US"] } if {![apm_package_installed_p acs-authentication]} { apm_package_install -enable [acs_root_dir]/packages/acs-authentication/acs-authentication.info apm_parameter_register "UsePasswordWidgetForUsername" \ "Should we hide what the user types in the username field, the way we do with the password field? Set this to 1 if you are using sensitive information such as social security number for username." \ acs-kernel 0 number \ security 1 1 parameter::set_value -package_id [ad_acs_kernel_id] -parameter UsePasswordWidgetForUsername -value 0 } If you can login, visit /acs-admin/apm and upgrade acs-kernel and acs-service-contract and uncheck the data model scripts. Restart. If everything is still working, make another backup of the database. Upgrade other packages via the APM See also these forum posts: Forum OpenACS Development: 4.6.3 upgrade to 5-HEAD: final results, OpenACS 5.0 Upgrade Experiences. There are a few things you might want to do once you've upgraded. First, the acs-kernel parameters need to be set to allow HREF and IMG tags, if you want users who can edit HTML to be able to insert HREF and IMG tags. Also, you might need to set the default language for your site. See the above link on OpenACS 5.0 Upgrade Experiences for details. Upgrading an OpenACS 5.0.0 or greater installation Upgrading a stock site If you have no custom code, and your site is not in a CVS repository, upgrade with these steps: Go to /acs-admin/install/ and click "Upgrade Your System" in "Install from OpenACS Repository" Select all of the packages you want to upgrade and proceed After upgrade is complete, restart the server as indicated. If you are using locales other than en_US, go to acs-lang/admin and "Import all Messages" to load the new translated messages. Your local translations, if any, will take precedence over imported translations. Upgrading a Custom or CVS site If you have custom code, and your site is in a CVS repository, upgrade with these steps: Upgrade the file system for all packages in use Go to /acs-admin/install/ and click "Upgrade Your System" in "Install from local file system" Select all of the packages you want to upgrade and proceed After upgrade is complete, restart the server as indicated. If you are using locales other than en_US, go to acs-lang/admin and "Import all Messages" to load the new translated messages. Your local translations, if any, will take precedence over imported translations. Upgrading the OpenACS files Chosing a Method to Upgrade your Files OpenACS is distributed in many different ways: as a collection of files as one big tarball via CVS via automatic download from within the APM (package manager) Upgrades work by first changing the file system (via any of the previous methods), and then using the APM to scan the file system, find upgrade scripts, and execute them. Starting with OpenACS 5.0, the last method was added, which automatically changes the file system for you. If you are using the last method, you can skip this page. This page describes whether or not you need to be upgrading using this page or not: Methods of upgrading OpenACS files Upgrading files for a site which is not in a CVS repository Unpack the tarball into a new directory and copy its contents on top of your working directory. Or just 'install software', select remote repository, and upgrade your files from there. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver [$OPENACS_SERVICE_NAME web]$ tar xzf /var/tmp/openacs-5-1.tar.gz [$OPENACS_SERVICE_NAME web]$ cp -r openacs-5-1/* openacs-4 [$OPENACS_SERVICE_NAME openacs-upgrade]$ exit [root root]# su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver tar xzf /var/tmp/openacs-5-1.tgz cp -r openacs-5-1/* openacs-4 exit Upgrading files for a site in a private CVS repository Many OpenACS site developers operate their own CVS repository to keep track of local customizations. In this section, we describe how to upgrade your local CVS repository with the latest OpenACS version, without overriding your own local customizations. This diagram explains the basic idea. However, the labels are incorrect. Step 1(a) has been removed, and Step 1(b) should be labelled Step 1.
    Upgrading a local CVS repository
    Step 0: Set up a working CVS checkout To get your OpenACS code into your local CVS repository, you will set up a working CVS checkout of OpenACS. When you want to update your site, you'll update the working CVS checkout, import those changes into your local CVS checkout, create a temporary CVS checkout to merge your local changes, fix any conflicts, commit your changes, and then update your site. It sounds complicated, but it's not too bad, and it is the best way to work around CVS's limitations. This part describes how to set up your working CVS checkout. Once it is set up, you'll be able to update any packages using the existing working CVS checkout. We use one dedicated directory for each branch of OpenACS - if you are using OpenACS 5.1,x, you will need a 5.1 checkout. That will be good for 5.1, 5.11, 5.12, and so on. But when you want to upgrade to OpenACS 5.2, you'll need to check out another branch. The openacs-5-1-compat tag identifies the latest released version of OpenACS 5.1 (ie, 5.1.3 or 5.1.4) and the latest compatible version of each package. Each minor release of OpenACS since 5.0 has this tagging structure. For example, OpenACS 5.1.x has openacs-5-1-compat. You will want to separately check out all the packages you are using. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver [$OPENACS_SERVICE_NAME aolserver]$ cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r openacs-5-1-compat acs-core [$OPENACS_SERVICE_NAME aolserver]$ cd openacs-4/packages [$OPENACS_SERVICE_NAME aolserver]$ cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r openacs-5-1-compat packagename packagename2... [$OPENACS_SERVICE_NAME aolserver]$ cd ../.. [$OPENACS_SERVICE_NAME aolserver]$ mv openacs-4 openacs-5-1 Make sure your working CVS checkout doesn't have the entire CVS tree from OpenACS. A good way to check this is if it has a contrib directory. If it does, you probably checked out the entire tree. You might want to start over, remove your working CVS checkout, and try again. Step 1: Import new OpenACS code Update CVS Update your local CVS working checkout (unless you just set it up). [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/openacs-5-1 [$OPENACS_SERVICE_NAME aolserver]$ cvs up -Pd ChangeLog *.txt bin etc tcl www packages/* Update a single package via cvs working checkout You can add or upgrade a single package at a time, if you already have a cvs working directory. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/packages/openacs-5-1 [$OPENACS_SERVICE_NAME openacs-5-1]$ cvs up -Pd packagename In the next section, the import must be tailored to just this package. Step 2: Merge New OpenACS code Now that you have a local copy of the new OpenACS code, you need to import it into your local CVS repository and resolve any conflicts that occur. Import the new files into your cvs repository; where they match existing files, they will become the new version of the file. [$OPENACS_SERVICE_NAME openacs-5-1]$ cd /var/lib/aolserver/openacs-5-1 [$OPENACS_SERVICE_NAME openacs-5-1]$ cvs -d /var/lib/cvs import -m "upgrade to OpenACS 5.1" $OPENACS_SERVICE_NAME OpenACS openacs-5-1 If adding or upgrading a single package, run the cvs import from within the base directory of that package, and adjust the cvs command accordingly. In this example, we are adding the myfirstpackage package. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/openacs-5-0/package/myfirstpackage [$OPENACS_SERVICE_NAME myfirstpackage]$ cvs -d /var/lib/cvs/ import -m "importing package" $OPENACS_SERVICE_NAME/packages/myfirstpackage OpenACS openacs-5-1 Create a new directory as temporary working space to reconcile conflicts between the new files and your current work. The example uses the cvs keyword yesterday, making the assumption that you haven't checked in new code to your local tree in the last day. This section should be improved to use tags instead of the keyword yesterday! [$OPENACS_SERVICE_NAME openacs-5.1]$ cd /var/lib/aolserver [$OPENACS_SERVICE_NAME tmp]$ rm -rf $OPENACS_SERVICE_NAME-upgrade [$OPENACS_SERVICE_NAME tmp]$ mkdir $OPENACS_SERVICE_NAME-upgrade [$OPENACS_SERVICE_NAME tmp]$ cvs checkout -d $OPENACS_SERVICE_NAME-upgrade -jOpenACS:yesterday -jOpenACS -kk $OPENACS_SERVICE_NAME > cvs.txt 2>&1 (CVS feedback here) The file /var/tmp/openacs-upgrade/cvs.txt contains the results of the upgrade. If you changed files that are part of the OpenACS tarball and those changes conflict, you'll have to manually reconcile them. Use the emacs command M-x sort-lines (you may have to click Ctrl-space at the beginning of the file, and go to the end, and then try M-x sort-lines) and then, for each line that starts with a C, open that file and manually resolve the conflict by deleting the excess lines. When you're finished, or if there aren't any conflicts, save and exit. Once you've fixed any conflicts, commit the new code to your local tree. [$OPENACS_SERVICE_NAME tmp]$ cd $OPENACS_SERVICE_NAME-upgrade [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME-upgrade]$ cvs commit -m "Upgraded to 5.1" Step 3: Upgrade your local staging site Update your working tree with the new files. The CVS flags ensure that new directories are created and pruned directories destroyed. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME-upgrade]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs up -Pd (CVS feedback) [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit [root root]#
    Upgrading files for a site using the OpenACS CVS repository (cvs.openacs.org) [$OPENACS_SERVICE_NAME ~]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs up -Pd (CVS feedback) [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    Upgrading a Production Site Safely If you are upgrading a production OpenACS site which is on a private CVS tree, this process lets you do the upgrade without risking extended downtime or an unusable site: Declare a freeze on new cvs updates - ie, you cannot run cvs update on the production site Make a manual backup of the production site in addition to the automated backups Import the new code (for example, OpenACS 5.0.4, openacs-5-0-compat versions of ETP, blogger, and other applications) into a "vendor branch" of the $OPENACS_SERVICE_NAME CVS tree, as described in "Upgrading a local CVS repository", step 1, above. As soon as we do this, any cvs update command on production might bring new code onto the production site, which would be bad. Do step 2 above (merging conflicts in a $OPENACS_SERVICE_NAME-upgrade working tree). Manually resolve any conflicts in the working upgrade tree Use the upgrade script and a recent backup of the production database, to ake a new upgraded database called $OPENACS_SERVICE_NAME-upgrade. Now we have a new website called $OPENACS_SERVICE_NAME-upgrade. Test the $OPENACS_SERVICE_NAME-upgrade site If $OPENACS_SERVICE_NAME-upgrade is fully functional, do the real upgrade. Take down the $OPENACS_SERVICE_NAME site and put up a "down for maintenance" page. Repeat the upgrade with the most recent database Test the that the new site is functional. If so, change the upgraded site to respond to yourserver.net requests. If not, bring the original production site back up and return to the merge.
    Upgrading Platform components Upgrading OpenFTS from 0.2 to 0.3.2 OpenACS Full Text Search requires several pieces: the OpenFTS code, some database functions, and the OpenFTS Engine. This section describes how to upgrade OpenFTS from 0.2 to 0.3.2 and upgrade the search engine on an OpenACS site at the same time. Uninstall the old OpenFTS Engine from the $OPENACS_SERVICE_NAME database. Browse to http://yourserver/openfts. Click Administration. Click Drop OpenFTS Engine Build and install the new OpenFTS driver and supporting tcl procedures. (This section of shell code is not fully documented; please exercise care.) cd /usr/local/src/ tar xzf /var/tmp/Search-OpenFTS-tcl-0.3.2.tar.gz chown -R root.root Search-OpenFTS-tcl-0.3.2/ cd Search-OpenFTS-tcl-0.3.2/ ./configure --with-aolserver-src=/usr/local/src/aolserver/aolserver --with-tcl=/usr/lib/ cd aolserver/ make Back up the old fts driver as a precaution and install the newly compiled one mv /usr/local/aolserver/bin/nsfts.so /usr/local/aolserver/bin/nsfts-0.2.so cp nsfts.so /usr/local/aolserver/bin Build and install the OpenFTS code for PostGresSQL cd /usr/local/src/Search-OpenFTS-tcl-0.3.2/ cp -r pgsql_contrib_openfts /usr/local/src/postgresql-7.2.3/contrib /usr/local/src/postgresql-7.2.3/contrib/pgsql_contrib_openfts make su - postgres cd tsearch/ make make install exit In order for the OpenACS 4.6 OpenFTS Engine to use the OpenFTS 0.3.2 driver, we need some commands added to the database. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME dev]$ psql $OPENACS_SERVICE_NAME -f /usr/local/pgsql/share/contrib/openfts.sql CREATE CREATE [$OPENACS_SERVICE_NAME dev]$ psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.2.3/contrib/tsearch/tsearch.sql BEGIN CREATE (~30 more lines) [$OPENACS_SERVICE_NAME dev]$ exit [root root]# su - $OPENACS_SERVICE_NAME psql $OPENACS_SERVICE_NAME -f /usr/local/pgsql/share/contrib/openfts.sql psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.2.3/contrib/tsearch/tsearch.sql exit OPTIONAL: Install the new OpenFTS Engine. If you want to upgrade the OpenFTS Engine, do these steps. (You must have already upgraded the OpenFTS driver to 0.3.2.) Browse to http://yourserver/admin/site-map On the openfts line, click on set parameters. Change the value of openfts_tcl_src_path from /usr/local/src/Search-OpenFTS-tcl-0.2/ to /usr/local/src/Search-OpenFTS-tcl-0.3.2/ Click Set Parameters [root root]# restart-aolserver $OPENACS_SERVICE_NAME Browse to http://yourserver/openfts Click Administration. Click Initialize OpenFTS Engine Upgrading from PostGreSQL 7.2 to 7.3 An OpenACS database created in PostGreSQL 7.2 will not work correctly in PostGreSQL 7.3. This is because 7.2 truncates function names to 31 characters, but 7.3 does not. This does not cause problems in 7.2, because truncation occurs both at function creation and at function calling, so they still match. But if you use a database created in 7.2 in 7.3, the function names in the database remain truncated but the function calls are not, and so they don't match. Also some functions use casting commands that no longer work in 7.3 and these functions must be recreated. To upgrade an OpenACS site from PostGreSQL 7.2 to 7.3, first upgrade the kernel to 4.6.3. Then, dump the database, run the upgrade script /var/lib/aolserver/$OPENACS_SERVICE_NAME/bin/pg_7.2to7.3_upgrade_helper.pl on the dump file, and reply the dump. See Forum OpenACS Q&A: PG 7.2->7.3 upgrade gotcha?. Example: Back up the database as per . Run the upgrade script on the backup file. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]# cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/bin [$OPENACS_SERVICE_NAME bin]$ ./pg_7.2to7.3_upgrade_helper.pl \ ../database-backup/nightly.dmp \ ../database-backup/upgrade-7.3.dmp \ /var/lib/aolserver/$OPENACS_SERVICE_NAME ================================================================== looking for function acs_object__check_object_ancest in oacs grep result: /var/lib/aolserver/aufrecht-dev/packages/acs-kernel/sql/postgresql/acs-objects-create.sql:create function acs_object__check_object_ancestors (integer,integer,integer) replacing acs_object__check_object_ancest with acs_object__check_object_ancestors (many lines omitted) [$OPENACS_SERVICE_NAME bin]$ Use perl to replace timestamp with timestamptz in the dump file. See example perl code in step two in /contrib/misc/upgrade_4.6_to_5.0.sh Create a new user for PostgreSQL 7.3.x, as per the Postgres installation guide. Keep in mind that your installation location is different, and your startup script (/etc/init.d/postgres73 should be named differently. You might even need to edit that file to make the paths correct). You'll also need to add export PGPORT=5434 to the .bashrc and/or .bash_profile for the postgres73 user. Install PostgreSQL 7.3.x. Note that you PostgreSQL must listen on a different port in order to work correctly, so you'll need to edit the configuration file (/usr/local/pgsql73/data/postgresql.conf) and change the port (to 5433, say). create a second postgres user to differentiate between the two postgres installs. When you do ./configure, you'll need to include --prefix=$HOME to ensure that it is installed in the postgres73 user's home directory. Change the path in $OPENACS_SERVICE_NAME's .bashrc or .bash_profile (or both) files to reflect the new postgres73 user directory. Also add in the PGPORT. Restore the database from dump as per the recovery instructions.
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/macinstall.xml0000644000175000017500000000321310456621135026233 0ustar frankiefrankie %myvars; ]> OpenACS Installation Guide for Mac OS X Prerequisites Install readline: Download readline from http://ftp.gnu.org/pub/gnu/readline/readline-4.3.tar.gz into /usr/local/src Extract readline in /usr/local/src, configure, compile, and install: su - root cd /usr/local/src tar xvfz readline-4.3.tar.gz readline-4.3 ./configure make make install Proceed with the Unix-like system instructions. OS X is incompatible with Oracle 8, and Oracle 9i on OSX is not yet verified for OpenACS. So continue with . Additional special steps for OS X are documented inline with the standard Unix-like instructions. Additional resources for installing on OS X. OpenACS on Mac OS X Quickstart An older forum thread ($Id: macinstall.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/openacs.xml0000644000175000017500000011534110456621135025542 0ustar frankiefrankie %myvars; ]> Install OpenACS &version; by Vinod Kurup Set up a user account for each site. AOLserver needs to be started as the root user if you want to use port 80. Once it starts, though, it will drop the root privileges and run as another user, which you must specify on the command line. It's important that this user has as few privileges as possible. Why? Because if an intruder somehow breaks in through AOLserver, you don't want her to have any ability to do damage to the rest of your server. At the same time, AOLserver needs to have write access to some files on your system in order for OpenACS to function properly. So, we'll run AOLserver with a different user account for each different service. A service name should be a single word, letters and numbers only. If the name of your site is one word, that would be a good choice. For example "$OPENACS_SERVICE_NAME" might be the service name for the $OPENACS_SERVICE_NAME.net community. We'll leave the password blank, which prevents login by password, for increased security. The only way to log in will be with ssh certificates. The only people who should log in are developers for that specific instance. Add this user, and put it in the $OPENACS_SERVICE_NAME group so that it can use database and server commands associated with that group. (If you don't know how to do this, type man usermod. You can type groups to find out which groups a user is a part of) [root root]# useradd $OPENACS_SERVICE_NAME You also need to set up a group called web. [root root]# groupadd web Then change the user to be a part of this group: [root root]# usermod -g web $OPENACS_SERVICE_NAME FreeBSD creates the user this way: [root root]# mkdir -p /home/$OPENACS_SERVICE_NAME [root root]# pw useradd -n $OPENACS_SERVICE_NAME -g web -d /home/$OPENACS_SERVICE_NAME -s /bin/bash [root root]# mkdir -p /home/$OPENACS_SERVICE_NAME pw useradd -n $OPENACS_SERVICE_NAME -g web -d /home/$OPENACS_SERVICE_NAME -s /bin/bash Set up the file system for one or more OpenACS Sites For Linux Standard Base compliance and ease of backup, all of the files in each OpenACS site are stored in a subdirectory of /var/lib/aolserver, one subdirectory per site. The first time you install an OpenACS site on a server, you must create the parent directory and set its permissions: [root root]# mkdir /var/lib/aolserver [root root]# chgrp web /var/lib/aolserver [root root]# chmod 770 /var/lib/aolserver [root root]# mkdir /var/lib/aolserver chgrp web /var/lib/aolserver chmod 770 /var/lib/aolserver Installation Option 1: Use automated script A bash script is available to automate all of the steps for the rest of this section. It requires tclwebtest. The automated script can greatly accelerate the install process, but is very sensitive to the install environment. We recommend that you run the automated install and, if it does not work the first time, consider switching to a manual installation. Get the install script from CVS. It is located within the main cvs tree, at /etc/install. Use anonymous CVS checkout to get that directory in the home directory of the service's dedicated user. We put it there so that it is not overwritten when we do the main CVS checkout to the target location. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot co -d install openacs-4/etc/install cvs server: Updating install U install/README U install/TODO ... many lines omitted ... U install/tcl/twt-procs.tcl U install/tcl/user-procs.tcl [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd install [$OPENACS_SERVICE_NAME install]$ emacs install.tcl Edit the installation configuration file, /home/$OPENACS_SERVICE_NAME/install/install.tcl and update the site-specific values, such as the new service's IP address and name, which will be written into the new service's config.tcl file. If your system is different from the one described in the previous sections, check the file paths as well. Set do_checkout=yes to create a new OpenACS site directly from a CVS checkout, or =no if you have a fully configured site and just want to rebuild it (drop and recreate the database and repeat the installation). If you have followed a stock installation, the default configuration will work without changes and will install an OpenACS site at 127.0.0.1:8000. Run the install script install.sh as root: [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit [root root]# sh /home/$OPENACS_SERVICE_NAME/install/install.sh /home/$OPENACS_SERVICE_NAME/install/install.sh: Starting installation with config_file /home/$OPENACS_SERVICE_NAME/install/install.tcl. Using serverroot=/var/lib/aolserver/ $OPENACS_SERVICE_NAME, server_url=http://0.0.0.0:8000, do_checkout=yes, do_install=yes, dotlrn=no, and database=postgres., use_daemontools=true ... many lines omitted ... Tue Jan 27 11:50:59 CET 2004: Finished (re)installing /var/lib/aolserver/$OPENACS_SERVICE_NAME. ###################################################################### New site URL: http://127.0.0.1:8000 admin email : admin@yourserver.net admin password: xxxx ###################################################################### [root root]# You can proceed to . Installation Option 2: Install from tarball You should already have downloaded the OpenACS tarball to the /var/tmp directory. If not, download the OpenACS tarball and save it in /var/tmp and proceed: Unpack the OpenACS tarball and rename it to $OPENACS_SERVICE_NAME. Secure the directory so that only the owner can access it. Check the permissions by listing the directory. FreeBSD note: Change the period in chown -R $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME to a colon: chown -R $OPENACS_SERVICE_NAME:$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver [$OPENACS_SERVICE_NAME aolserver]$ tar xzf /var/tmp/&tarballpath;.tgz [$OPENACS_SERVICE_NAME aolserver]$ mv &tarballpath; $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ chmod -R 775 $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ chown -R $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ ls -al total 3 drwxrwx--- 3 root web 1024 Mar 29 16:41 . drwxr-xr-x 25 root root 1024 Mar 29 16:24 .. drwx------ 7 $OPENACS_SERVICE_NAME web 1024 Jan 6 14:36 $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ exit logout [root root]# su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver tar xzf /var/tmp/&tarballpath;.tgz mv &tarballpath; $OPENACS_SERVICE_NAME chmod -R 755 $OPENACS_SERVICE_NAME chown -R $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME exit Add the Service to CVS (OPTIONAL) Prepare the database Prepare Oracle for OpenACS If you won't be using Oracle, skip to You should be sure that your user account (e.g. $OPENACS_SERVICE_NAME) is in the dba group. Verify membership by typing groups when you login: [$OPENACS_SERVICE_NAME ~]$ groups dba web If you do not see these groups, take the following action: [$OPENACS_SERVICE_NAME ~]$ su - Password: ************ [root ~]# adduser $OPENACS_SERVICE_NAME dba If you get an error about an undefined group, then add that group manually: [root ~]# groupadd dba [root ~]# groupadd web Make sure to logout as root when you are finished with this step and log back in as your regular user. Connect to Oracle using svrmgrl and login: [$OPENACS_SERVICE_NAME ~]$ svrmgrl SVRMGR> connect internal Connected. Determine where the system tablespaces are stored: SVRMGR> select file_name from dba_data_files; Example results: /ora8/m01/app/oracle/oradata/ora8/system01.dbf /ora8/m01/app/oracle/oradata/ora8/tools01.dbf /ora8/m01/app/oracle/oradata/ora8/rbs01.dbf /ora8/m01/app/oracle/oradata/ora8/temp01.dbf /ora8/m01/app/oracle/oradata/ora8/users01.dbf /ora8/m01/app/oracle/oradata/ora8/indx01.dbf /ora8/m01/app/oracle/oradata/ora8/drsys01.dbf Using the above output, you should determine where to store your tablespace. As a general rule, you'll want to store your tablespace on a mount point under the /ora8 directory that is separate from the Oracle system data files. By default, the Oracle system is on m01, so we will use m02. This enables your Oracle system and database files to be on separate disks for optimized performance. For more information on such a configuration, see Chapter 12 of Philip's book. For this example, we'll use /ora8/m02/oradata/ora8/. Create the directory for the datafile; to do this, exit from svrmgrl and login as root for this step: SVRMGR> exit [$OPENACS_SERVICE_NAME ~]$ su - Password: ************ [root ~]# mkdir -p /ora8/m02/oradata/ora8/ [root ~]# chown $OPENACS_SERVICE_NAME:web /ora8/m02/oradata/ora8 [root ~]# chmod 775 /ora8/m02/oradata/ora8 [root ~]# exit [$OPENACS_SERVICE_NAME ~]$ Create a tablespace for the service. It is important that the tablespace can autoextend. This allows the tablespace's storage capacity to grow as the size of the data grows. We set the pctincrease to be a very low value so that our extents won't grow geometrically. We do not set it to 0 at the tablespace level because this would affect Oracle's ability to automatically coalesce free space in the tablespace. [$OPENACS_SERVICE_NAME ~]$ svrmgrl SVRMGR> connect internal; SVRMGR> create tablespace $OPENACS_SERVICE_NAME datafile '/ora8/m02/oradata/ora8/$OPENACS_SERVICE_NAME01.dbf' size 50M autoextend on next 10M maxsize 300M extent management local uniform size 32K; Create a database user for this service. Give the user access to the tablespace and rights to connect. We'll use $OPENACS_SERVICE_NAMEpassword as our password. Write down what you specify as service_name (i.e. $OPENACS_SERVICE_NAME) and database_password (i.e. $OPENACS_SERVICE_NAMEpassword). You will need this information for configuring exports and AOLserver. SVRMGR> create user $OPENACS_SERVICE_NAME identified by $OPENACS_SERVICE_NAMEpassword default tablespace $OPENACS_SERVICE_NAME temporary tablespace temp quota unlimited on $OPENACS_SERVICE_NAME; SVRMGR> grant connect, resource, ctxapp, javasyspriv, query rewrite to $OPENACS_SERVICE_NAME; SVRMGR> revoke unlimited tablespace from $OPENACS_SERVICE_NAME; SVRMGR> alter user $OPENACS_SERVICE_NAME quota unlimited on $OPENACS_SERVICE_NAME; SVRMGR> exit; Your table space is now ready. In case you are trying to delete a previous OpenACS installation, consult these commands in below. Make sure that you can login to Oracle using your service_name account: [$OPENACS_SERVICE_NAME ~]$ sqlplus $OPENACS_SERVICE_NAME/$OPENACS_SERVICE_NAMEpassword SQL> select sysdate from dual; SYSDATE ---------- 2001-12-20 SQL> exit; You should see today's date in a format 'YYYY-MM-DD.' If you can't login, try redoing step 1 again. If the date is in the wrong format, make sure you followed the steps outlined in Prepare PostgreSQL for an OpenACS Service PostgreSQL: Create a user in the database matching the service name. With default PostgreSQL authentication, a system user connecting locally automatically authenticates as the postgres user of the same name, if one exists. We currently use postgres "super-users" for everything, which means that anyone with access to any of the openacs system accounts on a machine has full access to all postgresql databases on that machine. [root root]# su - postgres [postgres pgsql]$ createuser -a -d $OPENACS_SERVICE_NAME CREATE USER [postgres pgsql]$ exit logout [root root]# Create a database with the same name as our service name, $OPENACS_SERVICE_NAME. The full pathname for createdb needs to be used, since the pgsql directory has not been added to the $OPENACS_SERVICE_NAME bash profile. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/createdb -E UNICODE $OPENACS_SERVICE_NAME CREATE DATABASE [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ su - $OPENACS_SERVICE_NAME /usr/local/pgsql/bin/createdb -E UNICODE $OPENACS_SERVICE_NAME Automate daily database Vacuuming. This is a process which cleans out discarded data from the database. A quick way to automate vacuuming is to edit the cron file for the database user. Recommended: VACUUM ANALYZE every hour and VACUUM FULL ANALYZE every day. Postgres Vacuuming [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ export EDITOR=emacs;crontab -e Add these lines to the file. The vacuum command cleans up temporary structures within a PostGreSQL database, and can improve performance. We vacuum gently every hour and completely every day. The numbers and stars at the beginning are cron columns that specify when the program should be run - in this case, whenever the minute is 0 and the hour is 1, i.e., 1:00 am every day, and every (*) day of month, month, and day of week. Type man 5 crontab for more information. 0 1-23 * * * /usr/local/pgsql/bin/vacuumdb --analyze $OPENACS_SERVICE_NAME 0 0 * * * /usr/local/pgsql/bin/vacuumdb --full --analyze $OPENACS_SERVICE_NAME Depending on your distribution, you may receive email when the crontab items are executed. If you don't want to receive email for those crontab items, you can add > /dev/null 2>&1 to the end of each crontab line Add Full Text Search Support (OPTIONAL) At this point the database should be ready for installing OpenACS. Configure an AOLserver Service for OpenACS The AOLserver architecture lets you run an arbitrary number of virtual servers. A virtual server is an HTTP service running on a specific port, e.g. port 80. In order for OpenACS to work, you need to configure a virtual server. The Reference Platform uses a configuration file included in the OpenACS tarball, /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl. Open it in an editor to adjust the parameters. AOLserver configuration [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc [$OPENACS_SERVICE_NAME etc]$ emacs config.tcl You can continue without changing any values in the file. However, if you don't change address to match the computer's ip address, you won't be able to browse to your server from other machines. httpport - If you want your server on a different port, enter it here. The Reference Platform port is 8000, which is suitable for development use. Port 80 is the standard http port - it's the port used by your browser when you enter http://yourserver.test. So you should use port 80 for your production site. httpsport - This is the port for https requests. The Reference Platform https port is 8443. If http port is set to 80, httpsport should be 443 to match the standard. address - The IP address of the server. If you are hosting multiple IPs on one computer, this is the address specific to the web site. Each virtual server will ignore any requests directed at other addresses. server - This is the keyword that, by convention, identifies the service. It is also used as part of the path for the service root, as the name of the user for running the service, as the name of the database, and in various dependent places. The Reference Platform uses $OPENACS_SERVICE_NAME. db_name - In almost all cases, this can be kept as a reference to $server. If for some reason, the tablespace you are using is different than your servername, then you can set it here. You should have a good reason for doing this. servername - This is just a *pretty* name for your server. user_account - The account that will both own OpenACS files and connect to the database (for Postgresql). debug - Set to true for a very verbose error log, including many lines for every page view, success or failure. AOLserver is very configurable. These settings should get you started, but for more options, read the AOLserver docs. Enable OpenFTS Full Text Search (OPTIONAL) Install nsopenssl for SSL support. (OPTIONAL) Verify AOLserver startup Kill any current running AOLserver processes and start a new one. The recommended way to start an AOLserver process is by running the included script, /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/run. If you are not using the default file paths and names, you will need to edit run. If you want to use port 80, there are complications. AOLserver must be root to use system ports such as 80, but refuses to run as root for security reasons. So, we call the run script as root and specify a non-root user ID and Group ID which AOLserver will switch to after claiming the port. To do so, find the UID and GID of the $OPENACS_SERVICE_NAME user via grep $OPENACS_SERVICE_NAME /etc/passwd and then put those numbers into the command line via -u 501 -g 502. In AOLserver 4, you must also send a -b flag. Do this by editing the run file as indicated in the comments. If you are root then killall will affect all OpenACS services on the machine, so if there's more than one you'll have to do ps -auxw | grep nsd and selectively kill by job number. [$OPENACS_SERVICE_NAME etc]$ killall nsd nsd: no process killed [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/aolserver/bin/nsd-postgres -t /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ [08/Mar/2003:18:13:29][32131.8192][-main-] Notice: nsd.tcl: starting to read config file... [08/Mar/2003:18:13:29][32131.8192][-main-] Notice: nsd.tcl: finished reading config file. Attempt to connect to the service from a web browser. You should specify a URL like: http://yourserver.test:8000 You should see a page that looks like this. If you imported your files into cvs, now that you know it worked you can erase the temp directory with rm -rf /var/lib/aolserver/$OPENACS_SERVICE_NAME.orig. If you don't see the login page, view your error log (/var/lib/aolserver/$OPENACS_SERVICE_NAME/log/$OPENACS_SERVICE_NAME-error.log) to make sure the service is starting without any problems. The most common errors here are trying to start a port 80 server while not root, failing to connect because of a firewall, and aolserver failing to start due to permissions errors or missing files. If you need to make changes, don't forget to kill any running servers with killall nsd. Automate AOLserver keepalive (OPTIONAL) Configure a Service with the OpenACS Installer Now that you've got AOLserver up and running, let's install OpenACS &version;. You should see a page from the webserver titled OpenACS Installation: Welcome. You will be warned if your version of the database driver is out of date, if AOLserver cannot connect to the database, if any modules are missing or out-of-date, or if there are any problems with filesystem permissions on the server side. But if everything is fine, you can click Next to proceed to load the OpenACS Kernel data model. The next page shows the results of loading the OpenACS Kernel data model - be prepared to wait a few minutes as it works. You should see a string of output messages from the database as the datamodel is created. You'll see the line: Loading package .info files ... this will take a few minutes This will really take a few minutes. Have faith! Finally, another Next button will appear at the bottom - click it. The following page shows the results of loading the core package data models. You should see positive results for each of the previously selected packages, but watch out for any errors. Eventually, the page will display "Generating secret tokens" and then "Done"- click Next. You should see a page, "OpenACS Installation: Create Administrator" with form fields to define the OpenACS site administrator. Fill out the fields as appropriate, and click Create User. You should see a page, "OpenACS Installation: Set System Information" allowing you to name your service. Fill out the fields as appropriate, and click Set System Information You'll see the final Installer page, "OpenACS Installation: Complete." It will tell you that the server is being restarted; note that unless you already set up a way for AOLserver to restart itself (ie. inittab or daemontools), you'll need to manually restart your service. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/aolserver/bin/nsd-postgres -t /var/lib/aolserver/$OPENACS_SERVICE_NAME/config.tcl Give the server a few minutes to start up. Then reload the final page above. You should see the front page, with an area to login near the upper right. Congratulations, OpenACS &version; is now up and running! Installation Option 3: Install from CVS If you want to track fresh code developments inbetween releases, or you are an OpenACS core developer, you may want to install from CVS. This is identical to Option 2 except that you get the files from CVS instead of the tarball: CVS Checkout Instructions. So, instead of tar xzf /var/tmp/&tarballpath;.tgz, cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot co acs-core. Next Steps Use daemontools supervise and svc, or inittab, to automate server startup and shutdown. Install Full Text Search (OPTIONAL). If you have installed OpenFTS and enabled OpenFTS, you can now install the OpenFTS Driver package and Full Text Search Engine package in the OpenACS service. This is a good time to make a backup of your service. If this is a production site, you should set up automatic nightly backups. If you want traffic reports, set up analog or another log processing program. Follow the instruction on the home page to change the appearance of your service or add more packages. (more information) Proceed to the tutorial to learn how to develop your own packages. Set up database environment variables for the site user. Depending on how you installed Oracle or PostGreSQL, these settings may be necessary for working with the database while logged in as the service user. They do not directly affect the service's run-time connection with the database, because those environmental variables are set by the wrapper scripts nsd-postgres and nsd-oracle. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ emacs .bashrc Put in the appropriate lines for the database you are running. If you will use both databases, put in both sets of lines. PostgreSQL: export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib export PATH=$PATH:/usr/local/pgsql/bin Oracle. These environment variables are specific for a local Oracle installation communicating via IPC. If you are connecting to a remote Oracle installation, you'll need to adjust these appropriately. Also, make sure that the '8.1.7' matches your Oracle version. export ORACLE_BASE=/ora8/m01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/8.1.7 export PATH=$PATH:$ORACLE_HOME/bin export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib export ORACLE_SID=ora8 export ORACLE_TERM=vt100 export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data Test this by logging out and back in as $OPENACS_SERVICE_NAME and checking the paths. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit logout [root src]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME ~]$ env For PostgreSQL, you should see: LD_LIBRARY_PATH=:/usr/local/pgsql/lib PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:\ /root/bin:/usr/local/pgsql/bin:/usr/local/pgsql/bin For Oracle: ORACLE_BASE=/ora8/m01/app/oracle ORACLE_HOME=/ora8/m01/app/oracle/product/8.1.7 PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:\ /root/bin:/ora8/m01/app/oracle/product/8.1.7/bin LD_LIBRARY_PATH=/ora8/m01/app/oracle/product/8.1.7/lib:/lib:/usr/lib ORACLE_SID=ora8 ORACLE_TERM=vt100 ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data Test your backup and recovery procedure. Set up . ($Id: openacs.xml,v 1.31 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/overview.xml0000644000175000017500000003026010456621136025755 0ustar frankiefrankie %myvars; ]> Basic Steps The basic steps for installing OpenACS are: Install an OS and supporting software (see or for more details). See the . Install a database (see or ). Install AOLserver () . Create a unique database and system user. Install the OpenACS tarball, start and AOLserver instance, and use the OpenACS web pages to complete installation (see ). Specific instructions are available for Mac OS X and Windows2000 (see or ). Binaries and other shortcuts You can try out OpenACS using some binary installers. In general, they are not yet supported by the community, so they are mostly for evaluation purposes. Installing OpenACS You can see a list of current installers. The packaged version of PostgreSQL in Debian, Red Hat, and FreeBSD ports works fine. Once AOLserver and a database are installed, a bash script automates the OpenACS checkout and installation. System Requirements You will need a PC (or equivalent) with at least these minimum specifications: 128MB RAM (much more if you want Oracle) 1GB free space on your hard drive (much more if you want Oracle) A Unix-like operating system with Tcl, tDOM, and a mail transport agent like sendmail or qmail. (see ) All of the software mentioned is open-source and available without direct costs, except for Oracle. You can obtain a free copy of Oracle for development purposes. This is described in the section. How to use this guide This is text you will see on screen, such as a Button or link in a radio button list or menu. This is text that you will type. This is text from a program or file which you may need to examine or edit: if {$database == "oracle"} { set db_password "mysitepassword" } This is text that you will see and type in a command shell, including text you may have to change. It is followed by a list of just the commands, which you can copy and paste. The command prompt varies by system; in the examples we use the form[$OPENACS_SERVICE_NAME aolserver]$, where $OPENACS_SERVICE_NAME is the current user and aolserver is the current directory. The root prompt is shown ending in # and all other prompts in $. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ svc -d /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ dropdb $OPENACS_SERVICE_NAME DROP DATABASE [$OPENACS_SERVICE_NAME aolserver]$ createdb $OPENACS_SERVICE_NAME CREATE DATABASE su - $OPENACS_SERVICE_NAME svc -d /service/$OPENACS_SERVICE_NAME dropdb $OPENACS_SERVICE_NAME createdb $OPENACS_SERVICE_NAME Setting a global shell variable for cut and paste In order to cut and paste the instructions into your shell, you must set the environment variable $OPENACS_SERVICE_NAME. In order to set it globally so that it works for any new users or special service users you may create, edit the file /etc/profile ( /etc/share/skel/dot.profile for FreeBSD) and add this line: export OPENACS_SERVICE_NAME=service0 Paths and Users Default directories for a standard install Fully qualified domain name of your server yourserver.test name of administrative access account remadmin OpenACS service $OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME (set to service0 in default install) OpenACS service account $OPENACS_SERVICE_NAME OpenACS database name $OPENACS_SERVICE_NAME Root of OpenACS service file tree (SERVERROOT) /var/lib/aolserver/$OPENACS_SERVICE_NAME Location of source code tarballs for new software /var/tmp The OpenACS tarball contains some files which are useful while setting up other software. Those files are located at: /var/tmp/&tarballpath;/packages/acs-core-docs/www/files Database backup directory /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup Service config files /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc Service log files /var/lib/aolserver/$OPENACS_SERVICE_NAME/log Compile directory /usr/local/src PostgreSQL directory /usr/local/pgsql AOLserver directory /usr/local/aolserver
    None of these locations are set in stone - they're simply the values that we've chosen. The values that you'll probably want to change, such as service name, are marked like this. The other values we recommend you leave unchanged unless you have a reason to change them. Some of the paths and user accounts have been changed from those recommended in previous versions of this document to improve security and maintainability. See this thread for discussion.
    Getting Help during installation We'll do our best to assure that following our instructions will get you to the promised land. If something goes wrong, don't panic. There are plenty of ways to get help. Here are some tips: Keep track of the commands you are run and record their output. I like to do my installations in a shell inside of emacs (M-x shell) so that I can save the output if needed. An alternative would be to use the script command. We'll point out where the error logs for the various pieces of software are. Output from those logs will help us help you. Don't worry if you feel overwhelmed by all the information in the error logs. Over time, you'll find that they make more and more sense. Soon, you'll actually look forward to errors so that you can run to the log and diagnose the problem. Search the forums at openacs.org - you'll often find many people who have struggled through the same spot that you're in. The bottom of each page has a link to OpenACS.org, where you can post comments and read other users comments about the contents of the page. Ask questions at the irc channel on freenode.net (#openacs). They're knowledgeable and quite friendly if you can keep them on topic. Post a question on the forums. Make sure you've done a search first. When you do post, be sure to include your setup information (OS, etc) as well as the exact commands that are failing with the accompanying error. If there's a SQL error in the TCL error or in the log, post that too. If you find errors in this document or if you have ideas about making it better, please post them in our BugTracker. ($Id: overview.xml,v 1.28 2006/07/17 05:38:38 torbenb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/credits.xml0000644000175000017500000002312510456621135025545 0ustar frankiefrankie %myvars; ]> Credits By Vinod Kurup Vinod Kurup put together the January 2002 version of this guide from many sources of information. Joel Aufrecht updated the document starting in March 2003. OpenACS 3.x Installation Guide Gilbert Wong's FreeBSD installation guide My own Brief OpenACS4 installation guide Acknowledgments for versions of the above documents go (in no particular order) to Bryan Quinn, Adam Farkas, Brian Stein, Doug Hoffman, Ravi Jasuja, Hiro Iwashima, Ryan Lee, Jonathan Goler, Audrey Mcloghlin, Doug Harris, Zvi Boshernitzan, Michael Yoon, Cesar Brea, Dennis Gregorovic, David Fullagar, Chris Spears, Kevin Tupper, Michael Duffy, Simon Carstensen, Dave Bauer, Tracy Adams, Greg Haverkamp, Philip Greenspun, Jin Choi, Sean Yamamoto, David Cohen, Chris Rasch, Richard Li, Jon Griffin, Roberto Mello, Gilbert Wong, Don Baccus, Ben Adida, Michael Cleverly, Janne Blonqvist, Jonathan Ellis, Janine Sisk, Jade Rubick, Chris Hardy, Jonathan Marsden, Vinod Kurup, Charles Hall, Tom Jackson and Karl Lehenbauer. Several people have helped with this document, including Torben Brosten, Don Baccus, Roberto Mello, Talli Somekh, Dave Bauer, Jim Lynch, Jon Griffin, Daryl Biberdorf, Bjorn Thor Jonsson, Jade Rubick, Fred Yankowski, Dan Chak, Sebastiano Pilla, Reuven Lerner, Malte Sussdorff, Stan Kaufman and Pascal Scheffers. All questions and comments regarding this guide should be posted on the OpenACS forums. ($Id: credits.xml,v 1.12 2006/07/17 05:38:37 torbenb Exp $)
    Where did this document come from? This document was created by Vinod Kurup, but it's really just plagiarism from a number of documents that came before it. If I've used something that you've written without proper credit, let me know and I'll fix it right away. Versions 4.6.2 to present were edited by Joel Aufrecht. These are a few of my sources: ArsDigita installation guide OpenACS 3.x installation guide Gilbert Wong's FreeBSD installation guide Vinod Kurup's Brief OpenACS4 installation guide Joel Aufrecht's OpenACS 4.5 Quick Guide. Please also see the section for more acknowledgements.
    Linux Install Guides Here's a list of some helpful documentation for various OS's Painless Debian GNU/Linux by Stephen van Egmond Official Debian Guide RedHat Mandrake SuSE
    Security Information Once you get your OS installed, it's imperative that you secure your installation. As Jon Griffin repeatedly warns us, "No distribution is secure out of the box." The Reference Platform implements some basic precautions, but security is a process, not a condition. If you are responsible for a computer hooked to the internet, you are responsible for learning some rudiments of security, such as monitoring the state of a computer, maintaining patch levels, and keeping backups. We recommend these resources: Securing and Optimizing Linux - version 2.0 Jon Griffin's notes Linux Administrators Security Guide Installation of a Secure Webserver Bruce Schneier's Crypto-Gram, especially The security patch treadmill and Monitoring First.
    Resources Here are some resources that OpenACS users have found useful.
    Books Philip and Alex's Guide to Web Publishing - A very readable guide to database-backed community websites. UNIX Power Tools - An excellent introduction to the command line tools and basic programs of UNIX UNIX System Administration Handbook (formerly the "red book" - now the "purple" book) UNIX System Administrator's Bible - (LePage and Iarerra 1998; IDG) Running Linux Learning Gnu Emacs Linux in a Nutshell
    Web Sites The UNIX Reference Desk The Linux Documentation Project LPI certification exam preps - A series of articles from IBM developerworks on basic and intermediate Linux skills (requires registration)
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/other-software.xml0000644000175000017500000021650210456621135027064 0ustar frankiefrankie %myvars; ]> Install additional supporting software By Joel Aufrecht This section assumes that the source tarballs for supporting software are in /tmp. It assumes that you begin each continuous block of commands as root, and you should end each block as root. It doesn't care which directory you start in. Text instructions always precede the commands they refer to. Unpack the OpenACS tarball The OpenACS tarball contains sample configuration files for some of the packages listed below. In order to access those files, unpack the tarball now. [root root]# cd /tmp [root tmp]# tar xzf &tarballpath;.tgz cd /tmp tar xzf &tarballpath;.tgz If you are installing from a different method and just need the configuration files, you can instead get them from CVS: [root root]# cd /tmp [root tmp]# cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot co openacs-4/packages/acs-core-docs/www/files/ cvs checkout: warning: failed to open /root/.cvspass for reading: No such file or directory cvs server: Updating openacs-4/packages/acs-core-docs/www/files U openacs-4/packages/acs-core-docs/www/files/README.TXT (many lines omitted) U openacs-4/packages/acs-core-docs/www/files/template-ini.ini U openacs-4/packages/acs-core-docs/www/files/winnsd.txt [root tmp]# mv openacs-4 &tarballpath; cd /tmp cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot co openacs-4/packages/acs-core-docs/www/files/ mv openacs-4 openacs-5.0.0a4 Initialize CVS (OPTIONAL) cvs initializing CVS is a source control system. Create and initialize a directory for a local cvs repository. [root tmp]# mkdir /cvsroot [root tmp]# cvs -d /cvsroot init [root tmp]# mkdir /cvsroot cvs -d /cvsroot init Add PSGML commands to emacs init file (OPTIONAL) DocBook emacs configuration for If you plan to write or edit any documentation with emacs, install a customized emacs configuration file with DocBook commands in the skeleton directory, so it will be used for all new users. The file also fixes the backspace -> help mis-mapping that often occurs in terminals. [root tmp]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/emacs.txt /etc/skel/.emacs cp: overwrite `/etc/skel/.emacs'? y [root tmp]# Debian users: apt-get install psgml Note: The new nxml mode for emacs, when used in combination with psgml, provides a pretty good set of functionality that makes DocBook editing much less painless. In particular, nxml does syntax testing in real-time so that you can see syntax errors immediately instead of in the output of the xsltproc hours or days later. For debian, apt-get install nxml. Install Daemontools (OPTIONAL) Daemontools is a collection of programs for controlling other processes. We use daemontools to run and monitor AOLserver. It is installed in /package. These commands install daemontools and svgroup. svgroup is a script for granting permissions, to allow users other than root to use daemontools for specific services. Install Daemontools daemontools installation download daemontools and install it. Red Hat 8 [root root]# mkdir -p /package [root root]# chmod 1755 /package/ [root root]# cd /package/ [root package]# tar xzf /tmp/daemontools-0.76.tar.gz [root package]# cd admin/daemontools-0.76/ [root daemontools-0.76]# package/install Linking ./src/* into ./compile... Creating /service... Adding svscanboot to inittab... init should start svscan now. [root root]# mkdir -p /package chmod 1755 /package cd /package tar xzf /tmp/daemontools-0.76.tar.gz cd admin/daemontools-0.76 package/install Red Hat 9, Fedora Core 1-4 Make sure you have the source tarball in /tmp, or download it. [root root]# mkdir -p /package [root root]# chmod 1755 /package/ [root root]# cd /package/ [root package]# tar xzf /tmp/daemontools-0.76.tar.gz [root package]# cd admin [root admin]# wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch --14:19:24-- http://moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch => `daemontools-0.76.errno.patch' Resolving moni.csi.hu... done. Connecting to www.qmail.org[141.225.11.87]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 355 [text/plain] 100%[====================================>] 355 346.68K/s ETA 00:00 14:19:24 (346.68 KB/s) - `daemontools-0.76.errno.patch' saved [355/355] [root admin]# cd daemontools-0.76 [root daemontools-0.76]# patch -p1 < ../daemontools-0.76.errno.patch [root daemontools-0.76]# package/install Linking ./src/* into ./compile...(many lines omitted) Creating /service... Adding svscanboot to inittab... init should start svscan now. [root root]# mkdir -p /package chmod 1755 /package cd /package tar xzf /tmp/daemontools-0.76.tar.gz cd admin wget http://moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch cd daemontools-0.76 patch -p1 < ../daemontools-0.76.errno.patch package/install FreeBSD (follow standard install) Make sure you have the source tarball in /tmp, or download it. [root root]# mkdir -p /package [root root]# chmod 1755 /package/ [root root]# cd /package/ [root package]# tar xzf /tmp/daemontools-0.76.tar.gz [root package]# cd admin/daemontools-0.76 [root daemontools-0.76]# package/install Linking ./src/* into ./compile...(many lines omitted) Creating /service... Adding svscanboot to inittab... init should start svscan now. [root root]# mkdir -p /package chmod 1755 /package cd /package tar xzf /tmp/daemontools-0.76.tar.gz cd admin/daemontools-0.76 package/install Debian [root ~]# apt-get install daemontools-installer [root ~]# build-daemontools Verify that svscan is running. If it is, you should see these two processes running: [root root]# ps -auxw | grep service root 13294 0.0 0.1 1352 272 ? S 09:51 0:00 svscan /service root 13295 0.0 0.0 1304 208 ? S 09:51 0:00 readproctitle service errors: ....................................... [root root]# Install a script to grant non-root users permission to control daemontools services. [root root]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/svgroup.txt /usr/local/bin/svgroup [root root]# chmod 755 /usr/local/bin/svgroup cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/svgroup.txt /usr/local/bin/svgroup chmod 755 /usr/local/bin/svgroup Install qmail (OPTIONAL) Qmail is a Mail Transfer Agent. It handles incoming and outgoing mail. Install qmail if you want your OpenACS server to send and receive mail, and you don't want to use an alternate MTA. Red Hat 9: all djb tools (qmail, daemontools, ucspi) will fail to compile in Red Hat 9 because of changes to glibc (patches) Install ucspi This program handles incoming tcp connections. Download ucspi and install it. [root root]# cd /usr/local/src [root src]# wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz [root src]# tar xzf ucspi-tcp-0.88.tar.gz cd /usr/local/src wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz tar xzf ucspi-tcp-0.88.tar.gz Red Hat 9 only wget http://moni.csi.hu/pub/glibc-2.3.1/ucspi-tcp-0.88.errno.patch cd ucspi-tcp-0.88 patch -p1 <../ucspi-tcp-0.88.errno.patch cd .. All platforms continue: [root src]# cd ucspi-tcp-0.88 [root ucspi-tcp-0.88]# make ( cat warn-auto.sh; \ echo 'main="$1"; shift'; \(many lines omitted) ./compile instcheck.c ./load instcheck hier.o auto_home.o unix.a byte.a [root ucspi-tcp-0.88]# make setup check ./install ./instcheck [root ucspi-tcp-0.88]# cd ucspi-tcp-0.88 make make setup check Verify that ucspi-tcp was installed successfully by running the tcpserver program which is part of ucspi-tcp: [root ucspi-tcp-0.88]# tcpserver tcpserver: usage: tcpserver [ -1UXpPhHrRoOdDqQv ] [ -c limit ] [ -x rules.cdb ] [ -B banner ] [ -g gid ] [ -u uid ] [ -b backlog ] [ -l localname ] [ -t timeout ] host port program [root ucspi-tcp-0.88]# qmail rcpthosts error message (I'm not sure if this next step is 100% necessary, but when I skip it I get problems. If you get the error 553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1) then you need to do this.) AOLserver sends outgoing mail via the ns_sendmail command, which pipes a command to the sendmail executable. Or, in our case, the qmail replacement wrapper for the sendmail executable. In some cases, though, the outgoing mail requset is apparently sent through tcp/ip, so that it comes to qmail from 127.0.0.1 (a special IP address that means the local machine - the "loopback" interface). Unless this mail is addressed to the same machine, qmail thinks that it's an attempt to relay mail, and rejects it. So these two commands set up an exception so that any mail sent from 127.0.0.1 is allowed to send outgoing mail. [root ucspi-tcp-0.88]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/tcp.smtp.txt /etc/tcp.smtp [root ucspi-tcp-0.88]# tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/tcp.smtp.txt /etc/tcp.smtp tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp Install Qmail qmail installation Download qmail, set up the standard supporting users and build the binaries: [root root]# cd /usr/local/src [root src]# wget http://www.qmail.org/netqmail-1.04.tar.gz [root src]# tar xzf netqmail-1.04.tar.gz --15:04:11-- http://www.qmail.org/netqmail-1.04.tar.gz => `netqmail-1.04.tar.gz' Resolving www.qmail.org... done. Connecting to www.qmail.org[192.203.178.37]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 242,310 [application/x-gunzip] 88% [===============================> ] 214,620 22.93K/s ETA 00:01 15:04:21 (24.04 KB/s) - `netqmail-1.04.tar.gz' saved [242310/242310] [root src]# mkdir /var/qmail [root src]# groupadd nofiles [root src]# useradd -g nofiles -d /var/qmail/alias alias [root src]# useradd -g nofiles -d /var/qmail qmaild [root src]# useradd -g nofiles -d /var/qmail qmaill [root src]# useradd -g nofiles -d /var/qmail qmailp [root src]# groupadd qmail [root src]# useradd -g qmail -d /var/qmail qmailq [root src]# useradd -g qmail -d /var/qmail qmailr [root src]# useradd -g qmail -d /var/qmail qmails [root src]# cd netqmail-1.04 [root netqmail-1.04]# ./collate.sh You should see 7 lines of text below. If you see anything else, then something might be wrong. [1] Extracting qmail-1.03... [2] Patching qmail-1.03 into netqmail-1.04. Look for errors below: 20 [4] The previous line should say 20 if you used GNU patch. [5] Renaming qmail-1.03 to netqmail-1.04... [6] Continue installing qmail using the instructions found at: [7] http://www.lifewithqmail.org/lwq.html#installation [root netqmail-1.04]# cd netqmail-1.04 [root netqmail-1.04]# make setup check ( cat warn-auto.sh; \ echo CC=\'`head -1 conf-cc`\'; \(many lines omitted) ./install ./instcheck cd /usr/local/src wget http://www.qmail.org/netqmail-1.04.tar.gz tar xzf netqmail-1.04.tar.gz mkdir /var/qmail groupadd nofiles useradd -g nofiles -d /var/qmail/alias alias useradd -g nofiles -d /var/qmail qmaild useradd -g nofiles -d /var/qmail qmaill useradd -g nofiles -d /var/qmail qmailp groupadd qmail useradd -g qmail -d /var/qmail qmailq useradd -g qmail -d /var/qmail qmailr useradd -g qmail -d /var/qmail qmails cd netqmail-1.04 ./collate.sh cd netqmail-1.04 make setup check Replace sendmail with qmail's wrapper. sendmail removing [root qmail-1.03]# rm -f /usr/bin/sendmail /usr/sbin/sendmail [root qmail-1.03]# ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail [root qmail-1.03]# rm -f /usr/bin/sendmail /usr/sbin/sendmail ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail Configure qmail - specifically, run the config script to set up files in /var/qmail/control specifying the computer's identity and which addresses it should accept mail for. This command will automatically set up qmail correctly if you have correctly set a valid host nome. If not, you'll want to read /var/qmail/doc/INSTALL.ctl to find out how to configure qmail. [root qmail-1.03]# ./config-fast yourserver.test Your fully qualified host name is yourserver.test. Putting yourserver.test into control/me... Putting yourserver.test into control/defaultdomain... Putting yourserver.test into control/plusdomain... Putting yourserver.test into control/locals... Putting yourserver.test into control/rcpthosts... Now qmail will refuse to accept SMTP messages except to yourserver.test. Make sure to change rcpthosts if you add hosts to locals or virtualdomains! [root qmail-1.03]# ./config-fast yourserver.test All incoming mail that isn't for a specific user is handled by the alias user. This includes all root mail. These commands prepare the alias user to receive mail. [root qmail-1.03]# cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root [root alias]# chmod 644 ~alias/.qmail* [root alias]# /var/qmail/bin/maildirmake ~alias/Maildir/ [root alias]# chown -R alias.nofiles /var/qmail/alias/Maildir [root alias]# cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root chmod 644 ~alias/.qmail* /var/qmail/bin/maildirmake ~alias/Maildir/ chown -R alias.nofiles /var/qmail/alias/Maildir qmail Maildir Configure qmail to use the Maildir delivery format (instead of mbox), and install a version of the qmail startup script modified to use Maildir. [root alias]# echo "./Maildir" > /var/qmail/bin/.qmail [root alias]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail.rc.txt /var/qmail/rc [root alias]# chmod 755 /var/qmail/rc [root alias]# echo "./Maildir" > /var/qmail/bin/.qmail cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail.rc.txt /var/qmail/rc chmod 755 /var/qmail/rc Set up the skeleton directory so that new users will be configured for qmail. [root root]# /var/qmail/bin/maildirmake /etc/skel/Maildir [root root]# echo "./Maildir/" > /etc/skel/.qmail [root root]# /var/qmail/bin/maildirmake /etc/skel/Maildir echo "./Maildir/" > /etc/skel/.qmail As recommended, we will run qmail with daemontools control files. Create daemontools control directories, set up a daemontools control script, copy the supervise control files, and set permissions. The last line links the control directories to /service, which will cause supervise to detect them and execute the run files, causing qmail to start. [root root]# mkdir -p /var/qmail/supervise/qmail-send/log [root root]# mkdir -p /var/qmail/supervise/qmail-smtpd/log [root root]# mkdir /var/log/qmail [root root]# chown qmaill /var/log/qmail [root root]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmailctl.txt /var/qmail/bin/qmailctl [root root]# chmod 755 /var/qmail/bin/qmailctl [root root]# ln -s /var/qmail/bin/qmailctl /usr/bin [root root]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-send-run.txt /var/qmail/supervise/qmail-send/run [root root]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-send-log-run.txt /var/qmail/supervise/qmail-send/log/run [root root]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-smtpd-run.txt /var/qmail/supervise/qmail-smtpd/run [root root]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-smtpd-log-run.txt /var/qmail/supervise/qmail-smtpd/log/run [root root]# chmod 755 /var/qmail/supervise/qmail-send/run [root root]# chmod 755 /var/qmail/supervise/qmail-send/log/run [root root]# chmod 755 /var/qmail/supervise/qmail-smtpd/run [root root]# chmod 755 /var/qmail/supervise/qmail-smtpd/log/run [root root]# ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service [root root]# ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service mkdir -p /var/qmail/supervise/qmail-send/log mkdir -p /var/qmail/supervise/qmail-smtpd/log mkdir /var/log/qmail chown qmaill /var/log/qmail cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmailctl.txt /var/qmail/bin/qmailctl chmod 755 /var/qmail/bin/qmailctl ln -s /var/qmail/bin/qmailctl /usr/bin cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-send-run.txt /var/qmail/supervise/qmail-send/run cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-send-log-run.txt /var/qmail/supervise/qmail-send/log/run cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-smtpd-run.txt /var/qmail/supervise/qmail-smtpd/run cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/qmail-smtpd-log-run.txt /var/qmail/supervise/qmail-smtpd/log/run chmod 755 /var/qmail/supervise/qmail-send/run chmod 755 /var/qmail/supervise/qmail-send/log/run chmod 755 /var/qmail/supervise/qmail-smtpd/run chmod 755 /var/qmail/supervise/qmail-smtpd/log/run ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service Wait ten seconds or so, and then verify that that the four qmail processes are running. If uptimes don't rise above 1 second, this may indicate broken scripts that are continuously restarting. In that case, start debugging by checking permissions. [root root]# qmailctl stat /service/qmail-send: up (pid 32700) 430 seconds /service/qmail-send/log: up (pid 32701) 430 seconds /service/qmail-smtpd: up (pid 32704) 430 seconds /service/qmail-smtpd/log: up (pid 32705) 430 seconds messages in queue: 0 messages in queue but not yet preprocessed: 0 [root root]# Further verify by sending and receiving email. Incoming mail for root is stored in /var/qmail/alias/Maildir. Install Analog web file analyzer Download the Analog source tarball in /tmp. Unpack, compile, and install analog. [root aolserver]# cd /usr/local/src [root src]# tar xzf /tmp/analog-5.32.tar.gz [root src]# cd analog-5.32 [root analog-5.32]# make cd src && make make[1]: Entering directory `/usr/local/src/analog-5.32/src' (many lines omitted) ***IMPORTANT: You must read the licence before using analog *** make[1]: Leaving directory `/usr/local/src/analog-5.32/src' [root analog-5.32]# cd .. [root src]# mv analog-5.32 /usr/share/ [root src]# cd /usr/local/src tar xzf /tmp/analog-5.32.tar.gz cd analog-5.32 make cd .. mv analog-5.32 /usr/share/ See also Install nspam Install Full Text Search using Tsearch2 By Dave Bauer, Joel Aufrecht and Malte Sussdorff with help from Tsearch V2 Introduction by Andrew J. Kopciuch Install Tsearch2 module full text search installation If you want full text search, and you are running PostgreSQL, install this module to support FTS. Do this step after you have installed both PostgreSQL and AOLserver. You will need the tseach2 module form PostgreSQL contrib. This is included with the PostgreSQL full source distribution. It is also available with the PostgreSQL contrib package provided by most distribution packages. On debian it is called postgresql-contrib. For PostgreSQL 7.3 or 7.4, download the http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_7.4.patch.gz tsearch2 patch to correctly restore from a pg_dump backup. If you installed tsearch2 from a package, you can use the http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_update.sql regprocedure script to update the database after tsearch2 is installed into it. TODO link to section decribing how to fix an existing tsearch2 database with this patch. As of May 9, 2004 there is a source patch available for tsearch2. The patch provides changes to the pg_ts_ configuration tables to allow for easy dump and restore of a database containing tsearch2. The patch is available here : [http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_7.4.patch.gz] To apply this patch, download the mentioned file and place it in your postgreSQL source tree ($PGSQL_SRC). This patch makes the backup and restore procedures very simple. [postgres pgsql]$ cd /tmp [postgres tmp]$ wget http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_7.4.patch.gz [postgres pgsql]$ cd /usr/local/src/postgresql-7.4.5/ [postgres postgresql-7.4.5] gunzip /tmp/regprocedure_7.4.patch.gz [postgres postgresql-7.4.5] patch -b -p1 < regprocedure_7.4.patch If you have a working version of tsearch2 in your database, you do not need to re-install the tsearch2 module. Just apply the patch and run make. This patch only affects the tsearch2.sql file. You can run the SQL script found : [right here] This script will make the modifications found in the patch, and update the fields from the existing data. From this point on, you can dump and restore the database in a normal fashion. Without this patch, you must follow the instructions later in this document for backup and restore. This patch is only needed for tsearch2 in PostgreSQL versions 7.3.x and 7.4.x. The patch has been applied to the sources for 8.0. Install Tsearch2. This is a PostgreSQL module that the tsearch2-driver OpenACS package requires. These instructions assume you are using the latest point release of PostgreSQL 7.4.5. [root root]# su - postgres [postgres pgsql]$ cd /usr/local/src/postgresql-7.4.5/contrib/tsearch2/ [postgres tsearch2]$ make [postgres tsearch2]$ make install mkdir /usr/local/pgsql/share/contrib mkdir /usr/local/pgsql/doc/contrib (2 lines omitted) /bin/sh ../../config/install-sh -c -m 755 libtsearch.so.0.0 /usr/local/pgsql/lib/tsearch.so [postgres tsearch]$ exit logout [root root]# su - postgres cd /usr/local/src/postgresql-7.4.5/contrib/tsearch2 make make install exit Install Full Text Search Engine Package in OpenACS Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install. Click on the Install software link. Click on the Install new service link. Click on the Install link next to Tsearch2 Driver. If you have installed tsearch2 into your PostgreSQL database, the installer will automatically enable tsearch in your OpenACS database instance. Restart the service. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Wait a minute, then browse back to the home page. Click on Admin on the top of the screen. Click on Main Site Administration in the "Subsite Administration" section. Click on Site Map in the "Advanced Features" section. Mount the Search interface in the site map. Click the new sub folder link on the Main Site line. Type search and click New. Click the new application link on the search line. Type search where it says untitled, choose search from the drop-down list, and click New. Click the Parameters link next to the Search package istance. Type tsearch2-driver where it says openfts-driver in the FtsEngineDriver parameter. Restart the service. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Wait a minute, then click on Main Site at the top of the page. Enable Full Text Search in packages Enabling Full Text Search in packages at the moment is not trivial. It involves a couple of steps, which I will illustrate taking lars-blogger as an example package Install the package. Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install. Click on the Install software link. Click on the Install new application link. Click on the Install link next to Weblogger. Install all required packages as well (always say okay until you shall restart the server) Load the service contracts datamodell and enable the service contract [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd packages/lars-blogger/sql/postgresql [$OPENACS_SERVICE_NAME postgresql]$ psql $OPENACS_SERVICE_NAME -f lars-blogger-sc-create.sql Note: Usually this script is called package_name-sc-create.sql Restart the service. [$OPENACS_SERVICE_NAME postgresql]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME postgresl]$ If you are lucky, Full Text Search is enabled now, if not consult http://openacs.org/forums/message-view?message_id=154759. This link also contains some hints on how to make sure it is enabled. Install Full Text Search using OpenFTS (deprecated see tsearch2) By Joel Aufrecht and Malte Sussdorff OpenFTS and tsearch1 use is deprecated in favor of Tsearch2. See . Tsearch2 is much easier to install, requiring only compilation of one module from PostgreSQL contrib, with an automated install process using the tsearch2-driver package. Install OpenFTS module full text search installation If you want full text search, and you are running PostgreSQL, install this module to support FTS. Do this step after you have installed both PostgreSQL and AOLserver. You will need the openfts tarball in /tmp. Install Tsearch. This is a PostgreSQL module that OpenFTS requires. [root root]# su - postgres [postgres pgsql]$ cd /usr/local/src/postgresql-7.3.4/contrib/tsearch/ [postgres tsearch]$ make sed 's,MODULE_PATHNAME,$libdir/tsearch,g' tsearch.sql.in >tsearch.sql /usr/bin/flex -8 -Ptsearch_yy -o'parser.c' parser.l(many lines omitted) rm -f libtsearch.so ln -s libtsearch.so.0.0 libtsearch.so [postgres tsearch]$ make install mkdir /usr/local/pgsql/share/contrib mkdir /usr/local/pgsql/doc/contrib (2 lines omitted) /bin/sh ../../config/install-sh -c -m 755 libtsearch.so.0.0 /usr/local/pgsql/lib/tsearch.so [postgres tsearch]$ exit logout [root root]# su - postgres cd /usr/local/src/postgresql-7.3.4/contrib/tsearch make make install exit Unpack the OpenFTS tarball and compile and install the driver. [root root]# cd /usr/local/src [root src]# tar xzf /tmp/Search-OpenFTS-tcl-0.3.2.tar.gz [root src]# cd /usr/local/src/Search-OpenFTS-tcl-0.3.2/ [root Search-OpenFTS-tcl-0.3.2]# ./configure --with-aolserver-src=/usr/local/src/aolserver/aolserver --with-tcl=/usr/lib/ checking prefix... /usr/local checking for gcc... gcc (many lines omitted) configure: creating ./config.status config.status: creating Makefile.global [root Search-OpenFTS-tcl-0.3.2]# make (cd parser; make all) make[1]: Entering directory `/usr/local/src/Search-OpenFTS-tcl-0.3.2/parser' (many lines omitted) packages provided were {Lingua::Stem::Snowball 0.3.2} processed fts_base_snowball.tcl [root Search-OpenFTS-tcl-0.3.2]# cd aolserver [root aolserver]# make gcc -c -fPIC -DPACKAGE=\"OPENFTS\" -DVERSION=\"0.3.2\" -DHAVE_UNISTD_H=1 -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STR (many lines omitted) n_stem.o italian_stem.o norwegian_stem.o portuguese_stem.o russian_stem.o nsfts.o -o nsfts.so [root aolserver]# cp nsfts.so /usr/local/aolserver/bin/ [root aolserver]# cd /usr/local/src tar xzf /tmp/Search-OpenFTS-tcl-0.3.2.tar.gz cd /usr/local/src/Search-OpenFTS-tcl-0.3.2/ ./configure --with-aolserver-src=/usr/local/src/aolserver/aolserver --with-tcl=/usr/lib/ make cd aolserver make cp nsfts.so /usr/local/aolserver/bin Build some supplemental modules. [root aolserver]# cd /usr/local/src/Search-OpenFTS-tcl-0.3.2 [root Search-OpenFTS-tcl-0.3.2]# cp -r pgsql_contrib_openfts /usr/local/src/postgresql-7.3.4/contrib [root Search-OpenFTS-tcl-0.3.2]# cd /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts [root pgsql_contrib_openfts]# make sed 's,MODULE_PATHNAME,$libdir/openfts,g' openfts.sql.in >openfts.sql gcc -O2 -Wall -Wmissing-prototypes -Wmissing-declarations -fpic -I. -I../../src/include -c -o openfts.o openfts.c gcc -shared -o openfts.so openfts.o rm openfts.o [root pgsql_contrib_openfts]# su postgres [postgres pgsql_contrib_openfts]$ make install /bin/sh ../../config/install-sh -c -m 644 openfts.sql /usr/local/pgsql/share/contrib /bin/sh ../../config/install-sh -c -m 755 openfts.so /usr/local/pgsql/lib /bin/sh ../../config/install-sh -c -m 644 ./README.openfts /usr/local/pgsql/doc/contrib [postgres pgsql_contrib_openfts]$ exit [root pgsql_contrib_openfts]# cd /usr/local/src/Search-OpenFTS-tcl-0.3.2 cp -r pgsql_contrib_openfts /usr/local/src/postgresql-7.3.4/contrib cd /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts make su postgres make install exit Install OpenFTS prerequisites in PostgreSQL instance full text search installation If you are installing Full Text Search, add required packages to the new database. (In order for full text search to work, you must also install the PostgreSQL OpenFTS module and prerequisites.) [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/tsearch/tsearch.sql BEGIN CREATE (many lines omitted) INSERT 0 1 COMMIT [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts/openfts.sql CREATE CREATE [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/tsearch/tsearch.sql /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts/openfts.sql If you get the error ERROR: could not access file "$libdir/tsearch": no such file or directory It is probably because PostgreSQL's libdir configuration variable points to a diffent directory than where tsearch is. You can find out where PostgreSQL expects to find tsearch via pg_config --pkglibdir Enable OpenFTS in config.tcl If you have installed OpenFTS, you can enable it for this service. Uncomment this line from config.tcl. (To uncomment a line in a tcl file, remove the # at the beginning of the line.) #ns_param nsfts ${bindir}/nsfts.so Install Full Text Search Engine Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install. Click on the Install software link. Click on the Install new service link. Click on the Install link next to OpenFTS Driver. Restart the service. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Wait a minute, then browse back to the home page. Click on Admin on the top of the screen. Click on Main Site Administration in the "Subsite Administration" section. Click on Site Map in the "Advanced Features" section. Mount the OpenFTS Full Text Search Engine in the site map. Click the new sub folder link on the "/" line, the first line under Main Site:/. Type openfts and click New. On the new openfts line, click the mount link. Click OpenFTS Driver. On the openfts line, click set parameters. Change openfts_tcl_src_path to /usr/local/src/Search-OpenFTS-tcl-0.3.2/ and click Set Parameters Mount the Search interface in the site map. Click the new sub folder link on the Main Site line. Type search and click New. Click the new application link on the search line. Type search where it says untitled, choose search from the drop-down list, and click New. Restart the service. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Wait a minute, then click on Main Site at the top of the page. Initialize the OpenFTS Engine. This creates a set of tables in the database to support FTS. Near the bottom of the page, click on the OpenFTS Driver link. Click on Administration. Click on Initialize OpenFTS Engine. Click Initialize OpenFTS Engine. Add the FTS Engine service contract Click on the DevAdmin. Click on the Service Contract link. On the FtsEngineDriver line, click Install. Restart the service. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Enable Full Text Search in packages Enabling Full Text Search in packages at the moment is not trivial. It involves a couple of steps, which I will illustrate taking lars-blogger as an example package Install the package. Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install. Click on the Install software link. Click on the Install new application link. Click on the Install link next to Weblogger. Install all required packages as well (always say okay until you shall restart the server) Load the service contracts datamodell and enable the service contract [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd packages/lars-blogger/sql/postgresql [$OPENACS_SERVICE_NAME postgresql]$ psql $OPENACS_SERVICE_NAME -f lars-blogger-sc-create.sql Note: Usually this script is called package_name-sc-create.sql Restart the service. [$OPENACS_SERVICE_NAME postgresql]$ svc -t /service/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME postgresl]$ If you are lucky, Full Text Search is enabled now, if not consult http://openacs.org/forums/message-view?message_id=154759. This link also contains some hints on how to make sure it is enabled. Install nsopenssl By Joel Aufrecht and Malte Sussdorff This AOLserver module is required if you want people to connect to your site via https. These commands compile nsopenssl and install it, along with a tcl helper script to handle https connections. You will also need ssl certificates. Because those should be different for each server service, you won't need those instructions until later. Install on AOLserver3 You will need the unpacked Aolserver tarball in /usr/local/src/aolserver and the nsopenssl tarball in /tmp. Red Hat 9 note: see this thread for details on compiling nsopenssl.) [root bin]# cd /usr/local/src/aolserver [root aolserver]# wget --passive http://www.scottg.net/download/nsopenssl-2.1.tar.gz [root aolserver]# tar xzf nsopenssl-2.1.tar.gz [root aolserver]# cd nsopenssl-2.1 [root nsopenssl-2.1]# make OPENSSL=/usr/local/ssl gcc -I/usr/local/ssl/include -I../aolserver/include -D_REENTRANT=1 -DNDEBUG=1 -g -fPIC -Wall -Wno-unused -mcpu=i686 -DHAVE_CMMSG=1 -DUSE_FIONREAD=1 -DHAVE_COND_EINTR=1 -c -o nsopenssl.o nsopenssl.c (many lines omitted) gcc -shared -nostartfiles -o nsopenssl.so nsopenssl.o config.o init.o ssl.o thread.o tclcmds.o -L/usr/local/ssl/lib -lssl -lcrypto [root nsopenssl-2.1]# cp nsopenssl.so /usr/local/aolserver/bin [root nsopenssl-2.1]# cp https.tcl /usr/local/aolserver/modules/tcl/ [root nsopenssl-2.1]# cd /usr/local/src/aolserver wget --passive http://www.scottg.net/download/nsopenssl-2.1.tar.gz tar xzf nsopenssl-2.1.tar.gz cd nsopenssl-2.1 make OPENSSL=/usr/local/ssl cp nsopenssl.so /usr/local/aolserver/bin cp https.tcl /usr/local/aolserver/modules/tcl/ For Debian (more information): apt-get install libssl-dev cd /usr/local/src/aolserver tar xzf /tmp/nsopenssl-2.1.tar.gz cd nsopenssl-2.1 make OPENSSL=/usr/lib/ssl cp nsopenssl.so /usr/local/aolserver/bin cp https.tcl /usr/local/aolserver/modules/tcl/ Install on AOLserver4 You will need the AOLserver4 source in /usr/local/src/aolserver/aolserver and OpenSSL installed in /usr/local/ssl (or at least symlinked there). The use of INST=/point/to/aolserver is being replaced with AOLSERVER=/point/to/aolserver. We are including both here, because while this module still requires INST, if one just uses AOLSERVER, the default value would be used and could intefere with another existing installation. FreeBSD note: build nsopenssl with gmake install OPENSSL=/usr/local/openssl AOLSERVER=/usr/local/aolserver4r10 [root bin]# cd /usr/local/src/aolserver [root aolserver]# cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver login [root aolserver]# cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nsopenssl [root aolserver]# cd nsopenssl [root nsopenssl]# make OPENSSL=/usr/local/ssl gcc -I/usr/local/ssl/include (many items omitted) -c -o sslcontext.o sslcontext.c (many lines omitted) [root nsopenssl-2.1]# make install OPENSSL=/usr/local/ssl AOLSERVER=/usr/local/aolserver4r10 INST=/usr/local/aolserver4r10 [root nsopenssl-2.1]# cd /usr/local/src/aolserver cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver login cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nsopenssl cd nsopenssl make OPENSSL=/usr/local/ssl make install OPENSSL=/usr/local/ssl AOLSERVER=/usr/local/aolserver AOLSERVER=/usr/local/aolserver4r10 If you have problems starting your server with nsopenssl.so due to missing libssl.so.0.9.7 (or lower), you have to create symlinks [root nsopenssl]# cd /usr/local/aolserver/lib [root lib]# ln -s /usr/local/ssl/lib/libssl.so.0.9.7 libssl.so.0.9.7 [root lib]# ln -s /usr/local/ssl/lib/libcrypto.so.0.9.7 libcrypto.so.0.9.7 [root lib]# cd /usr/local/aolserver/lib ln -s /usr/local/ssl/lib/libssl.so.0.9.7 libssl.so.0.9.7 ln -s /usr/local/ssl/lib/libcrypto.so.0.9.7 libcrypto.so.0.9.7 SSL support must be enabled seperately in each OpenACS server (. If your ports for SSL are privileged (below 1024), you will have to start AOLserver with prebinds for both your HTTP and your HTTPS port (usually by adding -b your_ip:your_http_port,your_ip:your_https_port to the nsd call. If you are using daemontools, this can be changed in your etc/daemontools/run file). To enable SSL support in your server, make sure your etc/config.tcl file has a section on "OpenSSL 3 with AOLserver4". If that section is not present, try looking at the README file in /usr/local/src/aolserver/nsopenssl. Install tclwebtest. Download the tclwebtest source, unpack it, and put it an appropriate place. (tclwebtest 1.0 will be required for auto-tests in OpenACS 5.1. When it exists, the cvs command here will be replaced with http://prdownloads.sourceforge.net/tclwebtest/tclwebtest-0.3.tar.gz?download.) As root: cd /tmp cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/tclwebtest co tclwebtest #wget http://umn.dl.sourceforge.net/sourceforge/tclwebtest/tclwebtest-1.0.tar.gz #tar xvzf tclwebtest-1-0.tar.gz mv tclwebtest-0.3 /usr/local/ ln -s /usr/local/tclwebtest-0.3 /usr/local/tclwebtest ln -s /usr/local/tclwebtest/tclwebtest /usr/local/bin Install PHP for use in AOLserver By Malte Sussdorff To be able to use PHP software with AOLserver (and OpenACS), you have to install PHP with AOLserver support. Get the latest version from www.php.net. For convenience we get version 4.3.4 from a mirror [root root]# cd /usr/local/src [root src]# wget http://de3.php.net/distributions/php-4.3.4.tar.gz [root src]# tar xfz php-4.3.4.tar.gz [root src]# cd php-4.3.4 [root php-4.3.4]# cd php-4.3.4 [root php-4.3.4]# ./configure --with-aolserver=/usr/local/aolserver/ --with-pgsql=/usr/local/pgsql --without-mysql [root php-4.3.4]# make install Once installed you can enable this by configuring your config file. Make sure your config file supports php (it should have a php section with it). Furthermore add index.php as the last element to your directoryfile directive. Install Squirrelmail for use as a webmail system for OpenACS By Malte Sussdorff This section is work in progress. It will detail how you can install Squirrelmail as a webmail frontend for OpenACS, thereby neglecting the need to have a seperate webmail package within OpenACS [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]# cd www [$OPENACS_SERVICE_NAME www]# wget http://cesnet.dl.sourceforge.net/sourceforge/squirrelmail/squirrelmail-1.4.4.tar.gz [$OPENACS_SERVICE_NAME www]# tar xfz squirrelmail-1.4.4.tar.gz [$OPENACS_SERVICE_NAME www]# mv squirrelmail-1.4.4 mail [$OPENACS_SERVICE_NAME www]# cd mail/config [$OPENACS_SERVICE_NAME www]# ./conf.pl Now you are about to configure Squirrelmail. The configuration heavily depends on your setup, so no instructions are given here. Install PAM Radius for use as external authentication By Malte Sussdorff This step by step guide is derived from the installation instructions which you can find at yourdomain.com/doc/acs-authentication/ext-auth-pam-install.html. It is build upon PAM 0.77 (tested) and does not work on RedHat Linux Enterprise 3 (using PAM 0.75). It makes use of the ns_pam module written by Mat Kovach. The instructions given in here do work with PAM LDAP accordingly and differences will be shown at the end of the file. Install ns_pam Download and install ns_pam [root aolserver]# cd /usr/local/src/aolserver/ [root aolserver]# wget http://braindamage.alal.com/software/ns_pam-0.1.tar.gz [root aolserver]# tar xvfz ns_pam-0.1.tar.gz [root aolserver]# cd ns_pam-0.1 [root ns_pam-0.1]# make install INST=/usr/local/aolserver [root ns_pam-0.1]# cd /usr/local/src/aolserver/ wget http://braindamage.alal.com/software/ns_pam-0.1.tar.gz tar xvfz ns_pam-0.1.tar.gz cd ns_pam-0.1 make install INST=/usr/local/aolserver Configure ns_pam Configure AOLserver for ns_pam To enable ns_pam in AOLServer you will first have to edit your config.tcl file and enable the loading of the ns_pam module and configure the aolservers pam configuration file. Change config.tcl. Remove the # in front of ns_param nspam ${bindir}/nspam.so to enable the loading of the ns_pam module. Change config.tcl. Replace pam_domain in the section ns/server/${server}/module/nspam with aolserver Create /etc/pam.d/aolserver. [root ns_pam]#cp /var/lib/aolserver/service0/packages/acs-core-docs/www/files/pam-aolserver.txt /etc/pam.d/aolserver Configure PAM Radius Configure and install PAM Radius You have to make sure that pam_radius v.1.3.16 or higher is installed, otherwise you will have to install it. [root ns_pam]# cd /usr/local/src/ [root src]# wget ftp://ftp.freeradius.org/pub/radius/pam_radius-1.3.16.tar [root src]# tar xvf pam_radius-1.3.16 [root src]# cd pam_radius [root pam_radius]# make [root pam_radius]# cp pam_radius_auth.so /lib/security/ [root pam_radius]# cd /usr/local/src wget ftp://ftp.freeradius.org/pub/radius/pam_radius-1.3.16.tar tar xvf pam_radius-1.3.16 cd pam_radius make cp pam_radius_auth.so /lib/security/ Next you have to add the configuration lines to your Radius configuration file (/etc/rddb/server). For AOLserver to be able to access this information you have to change the access rights to this file as well. [root pam_radius]# echo "radius.yourdomain.com:1645 your_radius_password >>/etc/rddb/server [root src]# chown service0:web /etc/rddb/server Install LDAP for use as external authentication By Malte Sussdorff This step by step guide on how to use LDAP for external authentication using the LDAP bind command, which differs from the approach usually taken by auth-ldap. Both will be dealt with in these section Install openldap Download and install ns_ldap [root aolserver]# cd /usr/local/src/ [root src]# wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.2.17.tgz [root src]# tar xvfz openldap-2.2.17.tgz [root src]# cd openldap-2.2.17 [root src]# ./configure --prefix=/usr/local/openldap [root openldap]# make install [root openldap]# cd /usr/local/src/ wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.2.17.tgz tar xvfz openldap-2.2.17.tgz cd openldap-2.2.17 ./configure --prefix=/usr/local/openldap --disable-slapd make install Install ns_ldap Download and install ns_ldap [root aolserver]# cd /usr/local/src/aolserver/ [root aolserver]# wget http://www.sussdorff.de/ressources/nsldap.tgz [root aolserver]# tar xfz nsldap.tgz [root aolserver]# cd nsldap [root ns_pam-0.1]# make install LDAP=/usr/local/openldap INST=/usr/local/aolserver [root ns_pam-0.1]# cd /usr/local/src/aolserver/ wget http://www.sussdorff.de/resources/nsldap.tgz tar xfz nsldap.tgz cd nsldap make install LDAP=/usr/local/openldap INST=/usr/local/aolserver Configure ns_ldap for traditional use Traditionally OpenACS has supported ns_ldap for authentification by storing the OpenACS password in an encrypted field within the LDAP server called "userPassword". Furthermore a CN field was used for searching for the username, usually userID or something similar. This field is identical to the usernamestored in OpenACS. Therefore the login will only work if you change login method to make use of the username instead. Change config.tcl. Remove the # in front of ns_param nsldap ${bindir}/nsldap.so to enable the loading of the ns_ldap module. Configure ns_ldap for use with LDAP bind LDAP authentication usually is done by trying to bind (aka. login) a user with the LDAP server. The password of the user is not stored in any field of the LDAP server, but kept internally. The latest version of ns_ldap supports this method with the ns_ldap bind command. All you have to do to enable this is to configure auth_ldap to make use of the BIND authentification instead. Alternatively you can write a small script on how to calculate the username out of the given input (e.g. if the OpenACS username is malte.fb03.tu, the LDAP request can be translated into "ou=malte,ou=fb03,o=tu" (this example is encoded in auth_ldap and you just have to comment it out to make use of it). Section Missing openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/maintenance.xml0000644000175000017500000012461111501005400026353 0ustar frankiefrankie %myvars; ]> Production Environments by Joel Aufrecht Starting and Stopping an OpenACS instance. The simplest way to start and stop and OpenACS site is to run the startup shell script provided, /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/run. This runs as a regular task, and logs to the logfile. To stop the site, kill the script. A more stable way to run OpenACS is with a "keepalive" mechanism of some sort, so that whenever the server halts or is stopped for a reset, it restarts automatically. This is recommended for development and production servers. The Reference Platform uses Daemontools to control AOLserver. A simpler method, using init, is here. Daemontools must already be installed. If not, install it. Each service controlled by daemontools must have a directory in /service. That directory must have a file called run. It works like this: The init program starts every time the computer is booted. A line in init's configuration file, /etc/inittab, tells init to run, and to restart if necessary, svscanboot. svscanboot checks the directory /service every few seconds. If it sees a subdirectory there, it looks for a file in the subdirectory called run. If it finds a run file, it creates a supervise process supervise executes the run script. Whenever the run script stops, supervise executes it again. It also creates additional control files in the same directory. Hence, the AOLserver instance for your development server is started by the file /service/$OPENACS_SERVICE_NAME/run. But we use a symlink to make it easier to add and remove stuff from the /service, so the actual location is /var/lib/aolserver/$OPENACS_SERVICE_NAMEetc/daemontools/run. Daemontools creates additional files and directories to track status and log. A daemontools directory is included in the OpenACS tarball at /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools. To use it, first ill any existing AOLserver instances. As root, link the daemontools directory into the /service directory. Daemontools' svscan process checks this directory every five seconds, and will quickly execute run. [$OPENACS_SERVICE_NAME etc]$ killall nsd nsd: no process killed [$OPENACS_SERVICE_NAME etc]$ emacs /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/run [$OPENACS_SERVICE_NAME etc]$ exit [root root]# ln -s /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/ /service/$OPENACS_SERVICE_NAME Verify that AOLserver is running. [root root]# ps -auxw | grep nsd $OPENACS_SERVICE_NAME 5562 14.4 6.2 22436 15952 ? S 11:55 0:04 /usr/local/aolserver/bin/nsd -it /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl -u serve root 5582 0.0 0.2 3276 628 pts/0 S 11:55 0:00 grep nsd [root root]# The user $OPENACS_SERVICE_NAME can now control the service $OPENACS_SERVICE_NAME with these commands: svc -d /service/$OPENACS_SERVICE_NAME - Bring the server down svc -u /service/$OPENACS_SERVICE_NAME - Start the server up and leave it in keepalive mode. svc -o /service/$OPENACS_SERVICE_NAME - Start the server up once. Do not restart it if it stops. svc -t /service/$OPENACS_SERVICE_NAME - Stop and immediately restart the server. svc -k /service/$OPENACS_SERVICE_NAME - Sends the server a KILL signal. This is like KILL -9. AOLserver exits immediately. If svc -t fails to fully kill AOLserver, use this option. This does not take the server out of keepalive mode, so it should still bounce back up immediately. Install a script to automate the stopping and starting of AOLserver services via daemontools. You can then restart a service via restart-aolserver $OPENACS_SERVICE_NAME [root root]# cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/restart-aolserver-daemontools.txt /usr/local/bin/restart-aolserver [root root]# chmod 755 /usr/local/bin/restart-aolserver [root root]# At this point, these commands will work only for the root user. Grant permission for the web group to use svc commands on the $OPENACS_SERVICE_NAME server. [root root]# /usr/local/bin/svgroup web /service/$OPENACS_SERVICE_NAME [root root]# Verify that the controls work. You may want to tail -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/$OPENACS_SERVICE_NAME-error.log in another window, so you can see what happens when you type these commands. Most of this information comes from Tom Jackson's AOLserver+Daemontools Mini-HOWTO. How it Works Program Invoked by this program ... ... using this file Where to find errors Log goes to Use these commands to control it svscanboot init /etc/inittab ps -auxw | grep readproctitle n/a aolserver supervise (a child of svscanboot) /service/$OPENACS_SERVICE_NAME/run /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/error.log /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/$OPENACS_SERVICE_NAME.log svc -k /service/$OPENACS_SERVICE_NAME postgresql Redhat init scripts during boot /etc/init.d/postgresql /usr/local/pgsql/data/server.log service postgresql start (Red Hat), /etc/init.d/postgresql start (Debian)
    AOLserver keepalive with inittab This is an alternative method for keeping the AOLserver process running. The recommended method is to run AOLserver supervised. This step should be completed as root. This can break every service on your machine, so proceed with caution. There are 2 general steps to getting this working. Install a script called restart-aolserver. This script doesn't actually restart AOLserver - it just kills it. Ask the OS to restart our service whenever it's not running. We do this by adding a line to /etc/inittab. Calling restart-aolserver kills our service. The OS notices that our service is not running, so it automatically restarts it. Thus, calling restart-aolserver effectively restarts our service. Copy this file into /var/tmp/restart-aolserver.txt. This script needs to be SUID-root, which means that the script will run as root. This is necessary to ensure that the AOLserver processes are killed regardless of who owns them. However the script should be executable by the web group to ensure that the users updating the web page can use the script, but that general system users cannot run the script. You also need to have Perl installed and also a symbolic link to it in /usr/local/bin. [joeuser ~]$ su - Password: *********** [root ~]# cp /var/tmp/restart-aolserver.txt /usr/local/bin/restart-aolserver [root ~]# chown root.web /usr/local/bin/restart-aolserver [root ~]# chmod 4750 /usr/local/bin/restart-aolserver [root ~]# ln -s /usr/bin/perl /usr/local/bin/perl [root ~]# exit Test the restart-aolserver script. We'll first kill all running servers to clean the slate. Then, we'll start one server and use restart-aolserver to kill it. If it works, then there should be no more servers running. You should see the following lines. [joeuser ~]$ killall nsd nsd: no process killed [joeuser ~]$ /usr/local/aolserver/bin/nsd-postgres -t ~/var/lib/aolserver/birdnotes/nsd.tcl [joeuser ~]$ restart-aolserver birdnotes Killing 23727 [joeuser ~]$ killall nsd nsd: no process killed The number 23727 indicates the process id(s) (PIDs) of the processes being killed. It is important that no processes are killed by the second call to killall. If there are processes being killed, it means that the script is not working. Assuming that the restart-aolserver script worked, login as root and open /etc/inittab for editing. [joeuser ~]$ su - Password: ************ [root ~]# emacs -nw /etc/inittab Copy this line into the bottom of the file as a template, making sure that the first field nss1 is unique. nss1:345:respawn:/usr/local/aolserver/bin/nsd-postgres -i -u nobody -g web -t /home/joeuser/var/lib/aolserver/birdnotes/nsd.tcl Important: Make sure there is a newline at the end of the file. If there is not a newline at the end of the file, the system may suffer catastrophic failures. Still as root, enter the following command to re-initialize /etc/inittab. [root ~]# killall nsd nsd: no process killed [root ~]# /sbin/init q See if it worked by running the restart-aolserver script again. [root ~]# restart-aolserver birdnotes Killing 23750 If processes were killed, congratulations, your server is now automated for startup and shutdown. Running multiple services on one machine Services on different ports To run a different service on another port but the same ip, simply repeat replacing $OPENACS_SERVICE_NAME, and change the set httpport 8000 set httpsport 8443 to different values. Services on different host names For example, suppose you want to support http://service0.com and http://bar.com on the same machine. The easiest way is to assign each one a different ip address. Then you can install two services as above, but with different values for set hostname [ns_info hostname] set address 127.0.0.1 If you want to install two services with different host names sharing the same ip, you'll need nsvhr to redirect requests based on the contents of the tcp headers. See AOLserver Virtual Hosting with TCP by markd. High Availability/High Performance Configurations See also .
    Multiple-server configuration
    Staged Deployment for Production Networks ($Id: maintenance.xml,v 1.30 2010/12/11 23:36:32 ryang Exp $) By Joel Aufrecht This section describes two minimal-risk methods for deploying changes on a production network. The important characteristics of a safe change deployment include: (THIS SECTION IN DEVELOPMENT) Control: You know for sure that the change you are making is the change that you intend to make and is the change that you tested. Rollback: If anything goes wrong, you can return to the previous working configuration safely and quickly. Method 1: Deployment with CVS With this method, we control the files on a site via CVS. This example uses one developmental server (service0-dev) and one production server (service0). Depending on your needs, you can also have a staging server for extensive testing before you go live. The only way files should move between the server instances is via cvs. To set up a developmental installation, first set up either your developmental installation or your production installation, and follow the instructions for committing your files to CVS. We'll assume in this example that you set up the production server (service0). To set up the developmental instance, you then follow the intall guide again, this time creating a new user (service0-dev) that you'll use for the new installation. To get the files for service0-dev, you check them out from cvs (check out service0). su - service0-dev co -d /cvsroot service0 mv service0 /var/lib/aolserver/service0-dev ln -s /home/service0-dev/web /var/lib/aolserver/service0-dev emacs web/etc/config.tcl emacs web/etc/daemontools/run In the config.tcl file, you'll probably want to pay attention the rollout support section. That will ensure that email on your developmental server will not be sent out to the general world. Also, instead of going through the OpenACS online installer, you'll actually load live data into your production server. You can even automate the process of getting live data from your production server. Copy something like this to /home/service0-dev/bin and put it in service0-dev's crontab to run once a night. You'll need to make sure the database backups are set up in service0's crontab, and that if the servers are on different physical machines, that the database backup is copied to the developmental machine once per night. /usr/local/bin/svc -d /service/service0-dev /bin/sleep 60 # this deletes the dev database! /usr/local/pgsql/bin/dropdb service0-dev /usr/local/pgsql/bin/createdb -E UNICODE service0-dev # this is not necessary from Postgres 7.4 on /usr/local/pgsql/bin/psql -f /var/lib/aolserver/service0-dev/packages/acs-kernel/sql/postgresql/postgresql.sql service0 mv /var/lib/aolserver/service0/database-backup/service0-nightly-backup.dmp.gz /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup-old.dmp.gz /bin/gunzip /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup.dmp.gz /usr/bin/perl -pi -e "s/^\\connect service0$/\\connect service0-dev/" /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup.dmp /usr/local/pgsql/bin/psql service0-dev < /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup.dmp /usr/local/bin/svc -u /service/service0-dev /bin/gzip /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup-old.dmp Your developmental server will always have data about a day old. To make changes on service0-dev: 1) change the file on service0-dev as desired 2) test the new file 3) commit the file: if the file is /var/lib/aolserver/service0-dev/www/index.adp, do: cd /var/lib/aolserver/service0-dev/www cvs diff index.adp (this is optional; it's just a reality check) the lines starting > will be added and the lines starting < will be removed, when you commit if that looks okay, commit with: cvs -m "changing text on front page for February conference" index.adp the stuff in -m "service0" is a comment visible only from within cvs commands To make these changes take place on service0: 4) update the file on production: cd /var/lib/aolserver/service0/www cvs up -Pd index.adp If you make changes that require changes to the database, test them out first on service0-dev, using either -create.sql or upgrade scripts. Once you've tested them, you then update and run the upgrade scripts from the package manager. The production site can run "HEAD" from cvs. The drawback to using HEAD as the live code is that you cannot commit new work on the development server without erasing the definition of 'working production code.' So a better method is to use a tag. This guarantees that, at any time in the future, you can retrieve exactly the same set of code. This is useful for both of the characteristics of safe change deployment. For control, you can use tags to define a body of code, test that code, and then know that what you are deploying is exactly that code. For rollback, you can use return to the last working tag if the new tag (or new, untagged changes) cause problems. .... example of using tags to follow ... Method 2: A/B Deployment The approach taken in this section is to always create a new service with the desired changes, running in parallel with the existing site. This guarantees control, at least at the final step of the process: you know what changes you are about to make because you can see them directly. It does not, by itself, guarantee the entire control chain. You need additional measures to make sure that the change you are making is exactly and completely the change you intended to make and tested previously, and nothing more. Those additional measures typically take the form of source control tags and system version numbers. The parallel-server approach also guarantees rollback because the original working service is not touched; it is merely set aside. This approach can has limitations. If the database or file system regularly receiving new data, you must interrupt this function or risk losing data in the shuffle. It also requires extra steps if the database will be affected. Simple A/B Deployment: Database is not changed
    Simple A/B Deployment - Step 1
    Simple A/B Deployment - Step 2
    Simple A/B Deployment - Step 3
    Complex A/B Deployment: Database is changed
    Complex A/B Deployment - Step 1
    Complex A/B Deployment - Step 2
    Complex A/B Deployment - Step 3
    Installing SSL Support for an OpenACS service Debian Users: apt-get install openssl before proceeding. Make sure nsopenssl.so is installed for AOLserver. Uncomment this line from config.tcl. #ns_param nsopenssl ${bindir}/nsopenssl.so Prepare a certificate directory for the service. [$OPENACS_SERVICE_NAME etc]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs [$OPENACS_SERVICE_NAME etc]$ chmod 700 /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs [$OPENACS_SERVICE_NAME etc]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs chmod 700 /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs It takes two files to support an SSL connection. The certificate is the public half of the key pair - the server sends the certificate to browser requesting ssl. The key is the private half of the key pair. In addition, the certificate must be signed by Certificate Authority or browsers will protest. Each web browser ships with a built-in list of acceptable Certificate Authorities (CAs) and their keys. Only a site certificate signed by a known and approved CA will work smoothly. Any other certificate will cause browsers to produce some messages or block the site. Unfortunately, getting a site certificate signed by a CA costs money. In this section, we'll generate an unsigned certificate which will work in most browsers, albeit with pop-up messages. Use an OpenSSL perl script to generate a certificate and key. Debian users: use /usr/lib/ssl/misc/CA.pl instead of /usr/share/ssl/CA Mac OS X users: use perl /System/Library/OpenSSL/misc/CA.pl -newcert instead of /usr/share/ssl/CA [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs [$OPENACS_SERVICE_NAME certs]$ perl /usr/share/ssl/misc/CA -newcert Using configuration from /usr/share/ssl/openssl.cnf Generating a 1024 bit RSA private key ...++++++ .......++++++ writing new private key to 'newreq.pem' Enter PEM pass phrase: Enter a pass phrase for the CA certificate. Then, answer the rest of the questions. At the end you should see this: Certificate (and private key) is in newreq.pem [$OPENACS_SERVICE_NAME certs]$ newreq.pem contains our certificate and private key. The key is protected by a passphrase, which means that we'll have to enter the pass phrase each time the server starts. This is impractical and unnecessary, so we create an unprotected version of the key. Security implication: if anyone gets access to the file keyfile.pem, they effectively own the key as much as you do. Mitigation: don't use this key/cert combo for anything besides providing ssl for the web site. [root misc]# openssl rsa -in newreq.pem -out keyfile.pem read RSA key Enter PEM pass phrase: writing RSA key [$OPENACS_SERVICE_NAME certs]$ To create the certificate file, we take the combined file, copy it, and strip out the key. [$OPENACS_SERVICE_NAME certs]$ cp newreq.pem certfile.pem [root misc]# emacs certfile.pem Strip out the section that looks like -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,F3EDE7CA1B404997 S/Sd2MYA0JVmQuIt5bYowXR1KYKDka1d3DUgtoVTiFepIRUrMkZlCli08mWVjE6T (11 lines omitted) 1MU24SHLgdTfDJprEdxZOnxajnbxL420xNVc5RRXlJA8Xxhx/HBKTw== -----END RSA PRIVATE KEY----- If you start up using the etc/daemontools/run script, you will need to edit this script to make sure the ports are bound for SSL. Details of this are in the run script. Set up Log Analysis Reports Analog is a program with processes webserver access logs, performs DNS lookup, and outputs HTML reports. Analog should already be installed. A modified configuration file is included in the OpenACS tarball. [root src]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ mkdir www/log [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cp -r /usr/share/analog-5.32/images www/log/ [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver/$OPENACS_SERVICE_NAME cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/analog.cfg.txt etc/analog.cfg mkdir www/log cp -r /usr/share/analog-5.32/images www/log/ Edit /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/analog.cfg and change the variable in HOSTNAME "[my organisation]" to reflect your website title. If you don't want the traffic log to be publicly visible, change OUTFILE /var/lib/aolserver/$OPENACS_SERVICE_NAME/www/log/traffic.html to use a private directory. You'll also need to edit all instances of service0 to your $OPENACS_SERVICE_NAME. Run it. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/share/analog-5.32/analog -G -g/var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/analog.cfg /usr/share/analog-5.32/analog: analog version 5.32/Unix /usr/share/analog-5.32/analog: Warning F: Failed to open DNS input file /home/$OPENACS_SERVICE_NAME/dnscache: ignoring it (For help on all errors and warnings, see docs/errors.html) /usr/share/analog-5.32/analog: Warning R: Turning off empty Search Word Report [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Verify that it works by browing to http://yourserver.test:8000/log/traffic.html Automate this by creating a file in /etc/cron.daily. [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit logout [root root]# emacs /etc/cron.daily/analog Put this into the file: #!/bin/sh /usr/share/analog-5.32/analog -G -g/var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/analog.cfg [root root]# chmod 755 /etc/cron.daily/analog Test it by running the script. [root root]# sh /etc/cron.daily/analog Browse to http://yourserver.test/log/traffic.html External uptime validation The OpenACS uptime site can monitor your site and send you an email whenever your site fails to respond. If you test the url http://yourserver.test/SYSTEM/dbtest.tcl, you should get back the string success. Diagnosing Performance Problems Did performance problems happen overnight, or did they sneak up on you? Any clue what caused the performance problems (e.g. loading 20K users into .LRN) Is the file system out of space? Is the machine swapping to disk constantly? Isolating and solving database problems. Without daily internal maintenance, most databases slowly degrade in performance. For PostGreSQL, see . For Oracle, use exec dbms_stats.gather_schema_stats('SCHEMA_NAME') (Andrew Piskorski's Oracle notes). You can track the exact amount of time each database query on a page takes: Go to Main Site : Site-Wide Administration : Install Software Click on "Install New Application" in "Install from OpenACS Repository" Choose "ACS Developer Support"> After install is complete, restart the server. Browse to Developer Support, which is automatically mounted at /ds. Turn on Database statistics Browse directly to a slow page and click "Request Information" at the bottom of the page. This should return a list of database queries on the page, including the exact query (so it can be cut-paste into psql or oracle) and the time each query took.
    Query Analysis example
    Identify a runaway Oracle query: first, use ps aux or top to get the UNIX process ID of a runaway Oracle process. Log in to SQL*Plus as the admin: [$OPENACS_SERVICE_NAME ~]$ svrmgrl Oracle Server Manager Release 3.1.7.0.0 - Production Copyright (c) 1997, 1999, Oracle Corporation. All Rights Reserved. Oracle8i Enterprise Edition Release 8.1.7.3.0 - Production With the Partitioning option JServer Release 8.1.7.3.0 - Production SVRMGR> connect internal Password: See all of the running queries, and match the UNIX PID: select p.spid -- The UNIX PID ,s.sid ,s.serial# ,p.username as os_user ,s.username ,s.status ,p.terminal ,p.program from v$session s ,v$process p where p.addr = s.paddr order by s.username ,p.spid ,s.sid ,s.serial# ; See the SQL behind the oracle processes: select s.username ,s.sid ,s.serial# ,sql.sql_text from v$session s, v$sqltext sql where sql.address = s.sql_address and sql.hash_value = s.sql_hash_value --and upper(s.username) like 'USERNAME%' order by s.username ,s.sid ,s.serial# ,sql.piece ; To kill a troubled process: alter system kill session 'SID,SERIAL#'; --substitute values for SID and SERIAL# (See Andrew Piskorski's Oracle notes) Identify a runaway Postgres query. First, logging must be enabled in the database. This imposes a performance penalty and should not be done in normal operation. Edit the file postgresql.conf - its location depends on the PostGreSQL installation - and change #stats_command_string = false to stats_command_string = true Next, connect to postgres (psql service0) and select * from pg_stat_activity;. Typical output should look like: datid | datname | procpid | usesysid | usename | current_query ----------+-------------+---------+----------+---------+----------------- 64344418 | openacs.org | 14122 | 101 | nsadmin | <IDLE> 64344418 | openacs.org | 14123 | 101 | nsadmin | delete from acs_mail_lite_queue where message_id = '2478608'; 64344418 | openacs.org | 14124 | 101 | nsadmin | <IDLE> 64344418 | openacs.org | 14137 | 101 | nsadmin | <IDLE> 64344418 | openacs.org | 14139 | 101 | nsadmin | <IDLE> 64344418 | openacs.org | 14309 | 101 | nsadmin | <IDLE> 64344418 | openacs.org | 14311 | 101 | nsadmin | <IDLE> 64344418 | openacs.org | 14549 | 101 | nsadmin | <IDLE> (8 rows) openacs.org=>
    Creating an appropriate tuning and monitoring environment The first task is to create an appropriate environment for finding out what is going on inside Oracle. Oracle provides Statspack, a package to monitor and save the state of the v$ performance views. These reports help finding severe problems by exposing summary data about the Oracle wait interface, executed queries. You'll find the installation instructions in $ORACLE_HOME/rdbms/admin/spdoc.txt. Follow the instructions carefully and take periodic snapshots, this way you'll be able to look at historical performance data. Also turn on the timed_statistics in your init.ora file, so that Statspack reports (and all other Oracle reports) are timed, which makes them a lot more meaningful. The overhead of timing data is about 1% per Oracle Support information. To be able to get a overview of how Oracle executes a particular query, install "autotrace". I usually follow the instructions here http://asktom.oracle.com/~tkyte/article1/autotrace.html. Make sure, that the Oracle CBO works with adequate statistics The Oracle Cost Based optimizer is a piece of software that tries to find the "optimal" execution plan for a given SQL statement. For that it estimates the costs of running a SQL query in a particular way (by default up to 80.000 permutations are being tested in a Oracle 8i). To get an adequate cost estimate, the CBO needs to have adequate statistics. For that Oracle supplies the dbms_stats package.
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/os.xml0000644000175000017500000000557610456621135024543 0ustar frankiefrankie %myvars; ]> Install a Unix-like system and supporting software by Joel Aufrecht a Unix-like system You will need a computer running a unix-like system with the following software installed: tdom tcl --if you plan to use the OpenACS installation script gmake and the compile and build environment. BSD Note BSD users: in most places in these instructions, gmake will work better than make. (more information on FreeBSD installation). Also, fetch is a native replacement for wget. Note: Instructions for installing tDOM and threaded tcl are included with the AOLserver4 installation instructions, if these are not yet installed. The following programs may be useful or required for some configurations. They are included in most distributions: emacs cvs (and initialize it) ImageMagick (used by some packages for server side image manipulation) Aspell (more information on spell-checking) DocBook and supporting software (and install emacs keybindings for DocBook SGML) daemontools (install from source) a Mail Transport Agent, such as exim or sendmail (or install qmail from source) In order to cut and paste the example code into your shell, you must first do . To install a machine to the specifications of the Reference Platform, do the walkthrough of the Red Hat 8.0 Install for OpenACS. ($Id: os.xml,v 1.15 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/red-hat.xml0000644000175000017500000005250210456621136025436 0ustar frankiefrankie %myvars; ]> Install Red Hat 8/9 by Joel Aufrecht This section takes a blank PC and sets up some supporting software. You should do this section as-is if you have a machine you can reformat and you want to be sure that your installation works and is secure; it should take about an hour. (In my experience, it's almost always a net time savings of several hours to install a new machine from scratch compared to installing each of these packages installed independently.) The installation guide assumes you have: A PC with hard drive you can reinstall Red Hat 8.0 or 9.0 install discs A CD with the current Security Patches for your version of Red Hat. The installation guide assumes that you can do the following on your platform: Adding users, groups, setting passwords (For Oracle) Starting an X server and running an X program remotely Basic file management using cp, rm, mv, and cd Compiling a program using ./config and make. You can complete this install without the above knowledge, but if anything goes wrong it may take extra time to understand and correct the problem. Some useful UNIX resources. Unplug the network cable from your computer. We don't want to connect to the network until we're sure the computer is secure. security definition (Wherever you see the word secure, you should always read it as, "secure enough for our purposes, given the amount of work we're willing to exert and the estimated risk and consequences.") Insert Red Hat 8.0 or 9.0 Disk 1 into the CD-ROM and reboot the computer At the boot: prompt, press Enter for a graphical install. The text install is fairly different, so if you need to do that instead proceed with caution, because the guide won't match the steps. Checking the media is probably a waste of time, so when it asks press Tab and then Enter to skip it. After the graphical introduction page loads, click Next Choose the language you want to use and then click Next Select the keyboard layout you will use and Click Next Choose your mouse type and Click Next Red Hat has several templates for new computers. We'll start with the "Server" template and then fine-tune it during the rest of the install. Choose Server and click Next. Reformat the hard drive. If you know what you're doing, do this step on your own. Otherwise: we're going to let the installer wipe out the everything on the main hard drive and then arrange things to its liking. Choose Automatically Partition and click Next Uncheck Review (and modify if needed) the partitions created and click Next On the pop-up window asking "Are you sure you want to do this?" click Yes IF YOU ARE WIPING YOUR HARD DRIVE. Click Next on the boot loader screen Configure Networking. security firewall Again, if you know what you're doing, do this step yourself, being sure to note the firewall holes. Otherwise, follow the instructions in this step to set up a computer directly connected to the internet with a dedicated IP address. DHCP is a system by which a computer that joins a network (such as on boot) can request a temporary IP address and other network information. Assuming the machine has a dedicated IP address (if it doesn't, it will be tricky to access the OpenACS service from the outside world), we're going to set up that address. If you don't know your netmask, 255.255.255.0 is usually a pretty safe guess. Click Edit, uncheck Configure using DHCP and type in your IP and netmask. Click Ok. Type in your host name, gateway, and DNS server(s). Then click Next. We're going to use the firewall template for high security, meaning that we'll block almost all incoming traffic. Then we'll add a few holes to the firewall for services which we need and know are secure. Choose High security level. Check WWW, SSH, and Mail (SMTP). In the Other ports box, enter 443, 8000, 8443. Click Next. Port 443 is for https (http over ssl), and 8000 and 8443 are http and https access to the development server we'll be setting up. language installation Select any additional languages you want the computer to support and then click Next Choose your time zone and click Next. Type in a root password, twice. On the Package selection page, we're going to uncheck a lot of packages that install software we don't need, and add packages that have stuff we do need. You should install everything we're installing here or the guide may not work for you; you can install extra stuff, or ignore the instructions here to not install stuff, with relative impunity - at worst, you'll introduce a security risk that's still screened by the firewall, or a resource hog. Just don't install a database or web server, because that would conflict with the database and web server we'll install later. check Editors (this installs emacsemacsinstallation), click Details next to Text-based Internet, check lynx, and click OK; check Authoring and Publishing (docbookinstallationthis installs docbook), uncheck Server Configuration Tools, uncheck Web Server, uncheck Windows File Server, check SQL Database Server (this installs PostgreSQL), check Development Tools (this installs gmake and other build tools), uncheck Administration Tools, and uncheck Printing Support. At the bottom, check Select Individual Packages and click Next We need to fine-tune the exact list of packages. The same rules apply as in the last step - you can add more stuff, but you shouldn't remove anything the guide adds. We're going to go through all the packages in one big list, so select Flat View and wait. In a minute, a list of packages will appear. uncheck apmd (monitors power, not very useful for servers), check ImageMagick (required for the photo-albuminstallationImageMagickphoto-album packages, uncheckisdn4k-utils (unless you are using isdn, this installs a useless daemon), check mutt (a mail program that reads Maildir), uncheck nfs-utils (nfs is a major security risk), uncheck pam-devel (I don't remember why, but we don't want this), uncheck portmap, uncheck postfix (this is an MTA, but we're going to install qmail later), check postgresql-devel, uncheck rsh (rsh is a security hole), uncheck sendmail (sendmail is an insecure MTA; we're going to install qmail instead later), check tcl (we need tcl), and uncheck xinetd (xinetd handles incoming tcp connections. We'll install a different, more secure program, ucspi-tcp). Click Next Red Hat isn't completely happy with the combination of packages we've selected, and wants to satisfy some dependencies. Don't let it. On the next screen, choose Ignore Package Dependencies and click Next. Click Next to start the copying of files. Wait. Insert Disk 2 when asked. Wait. Insert Disk 3 when asked. If you know how to use it, create a boot disk. Since you can also boot into recovery mode with the Install CDs, this is less useful than it used to be, and we won't bother. Select No,I do not want to create a boot disk and click Next. Click Exit, remove the CD, and watch the computer reboot. After it finishes rebooting and shows the login prompt, log in: yourserver login: root Password: [root root]# Install any security patches. For example, insert your CD with patches, mount it with mount /dev/cdrom, then cd /mnt/cdrom, then rpm -UVH *rpm. Both Red Hat 8.0 and 9.0 have had both kernel and openssl/openssh root exploits, so you should be upgrading all of that. Since you are upgrading the kernel, reboot after this step. Lock down SSH ssh SSH is the protocol we use to connect securely to the computer (replacing telnet, which is insecure). sshd is the daemon that listens for incoming ssh connections. As a security precaution, we are now going to tell ssh not to allow anyone to connect directly to this computer as root. Type this into the shell: emacs /etc/ssh/sshd_config Search for the word "root" by typing C-s (that's emacs-speak for control-s) and then root. Make the following changes: #Protocol 2,1 to Protocol 2 (this prevents any connections via SSH 1, which is insecure) #PermitRootLogin yes to PermitRootLogin no (this prevents the root user from logging in remotely via ssh. If you do this, be sure to create a remote access account, such as "remadmin", which you can use to get ssh before using "su" to become root) #PermitEmptyPasswords no to PermitEmptyPasswords no (this blocks passwordless accounts) and save and exit by typing C-x C-s C-x C-c Restart sshd so that the change takes effect.service sshd restart Red Hat still installed a few services we don't need, and which can be security holes. Use the service command to turn them off, and then use chkconfig to automatically edit the System V init directories to permanently (The System V init directories are the ones in /etc/rc.d. They consist of a bunch of scripts for starting and stopping programs, and directories of symlinks for each system level indicating which services should be up and down at any given service level. We'll use this system for PostgreSQL, but we'll use daemontools to perform a similar function for AOLserver. (The reason for this discrepencies is that, while daemontools is better, it's a pain in the ass to deal with and nobody's had any trouble leaving PostgreSQL the way it is.) [root root]# service pcmcia stop [root root]# service netfs stop [root root]# chkconfig --del pcmcia [root root]# chkconfig --del netfs [root root]# service pcmcia stop service netfs stop chkconfig --del pcmcia chkconfig --del netfs If you installed PostgreSQL, do also service postgresql start and chkconfig --add postgresql. Plug in the network cable. Verify that you have connectivity by going to another computer and ssh'ing to yourserver, logging in as remadmin, and promoting yourself to root: [joeuser@someotherserver]$ ssh remadmin@yourserver.test The authenticity of host 'yourserver.test (1.2.3.4)' can't be established. DSA key fingerprint is 10:b9:b6:10:79:46:14:c8:2d:65:ae:c1:61:4b:a5:a5. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'yourserver.test (1.2.3.4)' (DSA) to the list of known hosts. Password: Last login: Mon Mar 3 21:15:27 2003 from host-12-01.dsl-sea.seanet.com [remadmin remadmin]$ su - Password: [root root]# If you didn't burn a CD of patches and use it, can still download and install the necessary patches. Here's how to do it for the kernel; you should also check for other critical packages. Upgrade the kernel to fix a security hole. The default Red Hat 8.0 system kernel (2.4.18-14, which you can check with uname -a) has several security problems. Download the new kernel, install it, and reboot. [root root]# cd /var/tmp [root tmp]# wget http://updates.redhat.com/7.1/en/os/i686/kernel-2.4.18-27.7.x.i686.rpm --20:39:00-- http://updates.redhat.com/7.1/en/os/i686/kernel-2.4.18-27.7.x.i686.rpm => `kernel-2.4.18-27.7.x.i686.rpm' Resolving updates.redhat.com... done. Connecting to updates.redhat.com[66.187.232.52]:80... connected. HTTP request sent, awaiting response... 200 OK Length: 12,736,430 [application/x-rpm] 100%[======================================>] 12,736,430 78.38K/s ETA 00:00 20:41:39 (78.38 KB/s) - `kernel-2.4.18-27.7.x.i686.rpm' saved [12736430/12736430] root@yourserver tmp]# rpm -Uvh kernel-2.4.18-27.7.x.i686.rpm warning: kernel-2.4.18-27.7.x.i686.rpm: V3 DSA signature: NOKEY, key ID db42a60e Preparing... ########################################### [100%] 1:kernel ########################################### [100%] [root tmp]# reboot Broadcast message from root (pts/0) (Sat May 3 20:46:39 2003): The system is going down for reboot NOW! [root tmp]# cd /var/tmp wget http://updates.redhat.com/7.1/en/os/i686/kernel-2.4.18-27.7.x.i686.rpm rpm -Uvh kernel-2.4.18-27.7.x.i686.rpm reboot openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/postgres.xml0000644000175000017500000007101110456621136025754 0ustar frankiefrankie %myvars; ]> Install PostgreSQL by Vinod Kurup Skip this section if you will run only Oracle. OpenACS &version; will run with PostgreSQL 7.3.2, 7.3.3, and 7.3.4 and 7.4.x. 7.4.7 is the recommended version of PostgreSQL. Special notes for Mac OS X If you are running Mac OS X prior to 10.3, you should be able to install and use PostGreSQL 7.3.x. Mac OS X 10.3 requires PostGreSQL 7.4. Special Notes for Debian Debian stable user should install PostGreSQL from source as detailed below, or they should use the www.backports.org backport for Postgres to get a more current version. Debian unstable users: the following process has been known to work (but you should double-check that the version of PostGreSQL is 7.3 or above): For Debian stable users, you can use backports, by adding this line to the /etc/apt/sources.list deb http://www.backports.org/debian stable bison postgresql openssl openssh tcl8.4 courier debconf spamassassin tla diff patch neon chkrootkit apt-get install postgresql postgresql-dev postgresql-doc ln -s /usr/include/postgresql/ /usr/include/pgsql ln -s /var/lib/postgres /usr/local/pgsql ln -s /usr/include/pgsql /usr/local/pgsql/include su postgres -c "/usr/lib/postgresql/bin/createlang plpgsql template1" and proceed to or to the next section. Special Notes for Red Hat Red Hat users: If you install PostgreSQL 7.3.2 from the Red Hat 9 RPM, you can skip a few steps. These shell commands add some links for compatibility with the directories from a source-based install; start the service; create a new group for web service users, and modify the postgres user's environment (more information): [root root]# ln -s /usr/lib/pgsql/ /var/lib/pgsql/lib [root root]# ln -s /var/lib/pgsql /usr/local/pgsql [root root]# ln -s /etc/init.d/postgresql /etc/init.d/postgres [root root]# ln -s /usr/bin /usr/local/pgsql/bin [root root]# service postgresql start Initializing database: [ OK ] Starting postgresql service: [ OK ] [root root]# echo "export LD_LIBRARY_PATH=/usr/local/pgsql/lib" >> ~postgres/.bash_profile [root root]# echo "export PATH=$PATH:/usr/local/pgsql/bin" >> ~postgres/.bash_profile [root root]# groupadd web [root root]# su - postgres -bash-2.05b$ ln -s /usr/lib/pgsql/ /var/lib/pgsql/lib ln -s /var/lib/pgsql /usr/local/pgsql ln -s /usr/bin /usr/local/pgsql/bin service postgresql start echo "export LD_LIBRARY_PATH=/usr/local/pgsql/lib" >> ~postgres/.bash_profile echo "export PATH=$PATH:/usr/local/pgsql/bin" >> ~postgres/.bash_profile groupadd web su - postgres ... and then skip to . Something similar may work for other binary packages as well. Safe approach: install from source Unpack PostgreSQL 7.4.7. If you have not downloaded the postgresql tarball to /var/tmp/postgresql-7.4.7.tar.gz, get it. [root root]# cd /usr/local/src [root src]# tar xzf /var/tmp/postgresql-7.4.7.tar.gz [root src]# cd /usr/local/src tar xzf /var/tmp/postgresql-7.4.7.tar.gz ALTERNATIVE: Unpack PostgreSQL 7.4.7 If you have not downloaded the postgresql tarball to /var/tmp/postgresql-7.4.7.tar.bz2, get it. [root root]# cd /usr/local/src [root src]# tar xfj /var/tmp/postgresql-7.4.7.tar.bz2 [root src]# cd /usr/local/src tar xfj /var/tmp/postgresql-7.4.7.tar.bz2 Install Bison Only do this if bison --version is smaller than 1.875 and you install PostgreSQL 7.4 from cvs instead of tarball. [root root]# cd /usr/local/src [root src]# wget http://ftp.gnu.org/gnu/bison/bison-1.875.tar.gz [root src]# tar xfz bison-1.875.tar.gz [root src]# cd bison-1.875 [root src]# ./configure [root src]# make install Create the Postgres user Create a user and group (if you haven't done so before) for PostgreSQL. This is the account that PostgreSQL will run as since it will not run as root. Since nobody will log in directly as that user, we'll leave the password blank. Debian users should probably use adduser instead of useradd. Type man adduser [root src]# groupadd web [root src]# useradd -g web -d /usr/local/pgsql postgres [root src]# mkdir -p /usr/local/pgsql [root src]# chown -R postgres.web /usr/local/pgsql /usr/local/src/postgresql-7.4.7 [root src]# chmod 750 /usr/local/pgsql [root src]# groupadd web useradd -g web -d /usr/local/pgsql postgres mkdir -p /usr/local/pgsql chown -R postgres.web /usr/local/pgsql /usr/local/src/postgresql-7.4.7 chmod 750 /usr/local/pgsql Mac OS X: Do instead: First make sure the gids and uids below are available (change them if they are not).To list taken uids and gids: nireport / /groups name gid | grep "[0123456789][0123456789]" nireport / /users name uid | grep "[0123456789][0123456789]" Now you can install the users sudo niutil -create / /groups/web sudo niutil -createprop / /groups/web gid 201 sudo niutil -create / /users/postgres sudo niutil -createprop / /users/postgres gid 201 sudo niutil -createprop / /users/postgres uid 502 sudo niutil -createprop / /users/postgres home /usr/local/pgsql sudo niutil -create / /users/$OPENACS_SERVICE_NAME sudo niutil -createprop / /users/$OPENACS_SERVICE_NAME gid 201 sudo niutil -createprop / /users/$OPENACS_SERVICE_NAME uid 201 mkdir -p /usr/local/pgsql chown -R postgres:web /usr/local/pgsql /usr/local/src/postgresql-7.4.7 chmod 750 /usr/local/pgsql FreeBSD users: need to add more parameters. [root src]# mkdir -p /usr/local/pgsql [root src]# pw groupadd -n web [root src]# pw useradd -n postgres -g web -d /usr/local/pgsql -s /bin/bash [root src]# chown -R postgres:web /usr/local/pgsql /usr/local/src/postgresql-7.4.7 [root src]# chmod -R 750 /usr/local/pgsql [root src]# mkdir -p /usr/local/pgsql pw groupadd -n web pw useradd -n postgres -g web -d /usr/local/pgsql -s /bin/bash chown -R postgres:web /usr/local/pgsql /usr/local/src/postgresql-7.4.7 chmod -R 750 /usr/local/pgsql Set up postgres's environment variables They are necessary for the executable to find its supporting libraries. Put the following lines into the postgres user's environment. [root src]# su - postgres [postgres ~] emacs ~postgres/.bashrc Paste this line into .bash_profile: source $HOME/.bashrc Paste these lines into .bashrc: export PATH=/usr/local/bin/:$PATH:/usr/local/pgsql/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib Test this by logging in as postgres and checking the paths; you should see /usr/local/pgsql/bin somewhere in the output (the total output is system-dependent so yours may vary) [root src]# su - postgres [postgres pgsql]$ env | grep PATH LD_LIBRARY_PATH=:/usr/local/pgsql/lib PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:/root/bin:/usr/local/pgsql/bin:/usr/local/pgsql/bin [postgres pgsql]$ exit Don't continue unless you see correct output from env | grep PATH Compile and install PostgreSQL Change to the postgres user and run ./configure to set the compilation options automatically. This is the point at which you can configure PostgreSQL in various ways. For example, if you are installing on "OS X" add the flags --with-includes=/sw/include/ --with-libraries=/sw/lib. If you want to see what the other possibilities are, run ./configure --help. On debian woody (stable, 3.0), do ./configure --without-readline --without-zlib. [root src]# su - postgres [postgres pgsql]$ cd /usr/local/src/postgresql-7.4.7 [postgres postgresql-7.4.7]$ ./configure creating cache ./config.cache checking host system type... i686-pc-linux-gnu (many lines omitted> linking ./src/makefiles/Makefile.linux to src/Makefile.port linking ./src/backend/port/tas/dummy.s to src/backend/port/tas.s [postgres postgresql-7.4.7]$ make all make -C doc all make[1]: Entering directory `/usr/local/src/postgresql-7.4.7/doc' (many lines omitted) make[1]: Leaving directory `/usr/local/src/postgresql-7.4.7/src' All of PostgreSQL successfully made. Ready to install. [postgres postgresql-7.4.7]$ make install make -C doc install make[1]: Entering directory `/usr/local/src/postgresql-7.4.7/doc' (many lines omitted) Thank you for choosing PostgreSQL, the most advanced open source database engine. su - postgres cd /usr/local/src/postgresql-7.4.7 ./configure make all make install Start PostgreSQL The initdb command initializes the database. pg_ctl is used to start up PostgreSQL. If PostgreSQL is unable to allocate enough memory, see section 11 Tuning PostgreSQL (below). [postgres postgresql-7.4.7]$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data The files belonging to this database system will be owned by user "postgres". This user must also own the server process. (17 lines omitted) or /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start [postgres postgresql-7.4.7]$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l /usr/local/pgsql/data/server.log start postmaster successfully started [postgres postgresql-7.4.7]$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l /usr/local/pgsql/data/server.log start PostgreSQL errors will be logged in /usr/local/pgsql/data/server.log Install Pl/pgSQL Set up plpgsq and allow your user to have access. Plpgsql is a PL/SQL-like language. We add it to template1, which is the template from which all new databases are created. We can verify that it was created with the createlang command in list mode. [postgres postgresql-7.4.7]$ createlang plpgsql template1 [postgres pgsql]$ createlang -l template1 Procedural languages Name | Trusted? ---------+---------- plpgsql | t (1 row) [postgres pgsql-7.4.7]$ createlang plpgsql template1 createlang -l template1 Test PostgreSQL (OPTIONAL). Create a database and try some simple commands. The output should be as shown. [postgres pgsql]$ createdb mytestdb CREATE DATABASE [postgres pgsql]$ psql mytestdb Welcome to psql, the PostgreSQL interactive terminal. Type: \copyright for distribution terms \h for help with SQL commands \? for help on internal slash commands \g or terminate with semicolon to execute query \q to quit mytestdb=# select current_timestamp; timestamptz ------------------------------- 2003-03-07 22:18:29.185413-08 (1 row) mytestdb=# create function test1() returns integer as 'begin return 1; end;' language 'plpgsql'; CREATE mytestdb=# select test1(); test1 ------- 1 (1 row) mytestdb=# \q [postgres pgsql]$ dropdb mytestdb DROP DATABASE [postgres pgsql]$ exit logout [root src]# Set PostgreSQL to start on boot. First, we copy the postgresql.txt init script, which automates startup and shutdown, to the distribution-specific init.d directory. Then we verify that it works. Then we automate it by setting up a bunch of symlinks that ensure that, when the operating system changes runlevels, postgresql goes to the appropriate state. Red Hat and Debian and SuSE each work a little differently. If you haven't untarred the OpenACS tarball, you will need to do so now to access the postgresql.txt file. Red Hat RPM: The init script is already installed; just turn it on for the appropriate run levels. [root root]# chkconfig --level 345 postgresql on [root root]# Red Hat from source: [root src]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql [root src]# chown root.root /etc/rc.d/init.d/postgresql [root src]# chmod 755 /etc/rc.d/init.d/postgresql [root src]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql chown root.root /etc/rc.d/init.d/postgresql chmod 755 /etc/rc.d/init.d/postgresql Test the script. [root root]# service postgresql stop Stopping PostgreSQL: ok [root root]# If PostgreSQL successfully stopped, then use the following command to make sure that the script is run appropriately at boot and shutdown. And turn it back on because we'll use it later. [root root]# chkconfig --add postgresql [root root]# chkconfig --level 345 postgresql on [root root]# chkconfig --list postgresql postgresql 0:off 1:off 2:on 3:on 4:on 5:on 6:off [root root]# service postgresql start Starting PostgreSQL: ok [root root]# chkconfig --add postgresql chkconfig --level 345 postgresql on chkconfig --list postgresql service postgresql start Debian: [root ~]# cp /var/tmp/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql [root ~]# chown root.root /etc/init.d/postgresql [root ~]# chmod 755 /etc/init.d/postgresql [root ~]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql chown root.root /etc/init.d/postgresql chmod 755 /etc/init.d/postgresql Test the script [root ~]# /etc/init.d/postgresql stop Stopping PostgreSQL: ok [root ~]# If PostgreSQL successfully stopped, then use the following command to make sure that the script is run appropriately at boot and shutdown. [root ~]# update-rc.d postgresql defaults Adding system startup for /etc/init.d/postgresql ... /etc/rc0.d/K20postgresql -> ../init.d/postgresql /etc/rc1.d/K20postgresql -> ../init.d/postgresql /etc/rc6.d/K20postgresql -> ../init.d/postgresql /etc/rc2.d/S20postgresql -> ../init.d/postgresql /etc/rc3.d/S20postgresql -> ../init.d/postgresql /etc/rc4.d/S20postgresql -> ../init.d/postgresql /etc/rc5.d/S20postgresql -> ../init.d/postgresql [root ~]# /etc/init.d/postgresql start Starting PostgreSQL: ok [root ~]# FreeBSD: [root ~]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/postgresql.txt /usr/local/etc/rc.d/postgresql.sh [root ~]# chown root:wheel /usr/local/etc/rc.d/postgresql.sh [root ~]# chmod 755 /usr/local/etc/rc.d/postgresql.sh [root ~]# cp /tmp/&tarballpath;/packages/acs-core-docs/www/files/postgresql.txt /usr/local/etc/rc.d/postgresql.sh chown root:wheel /usr/local/etc/rc.d/postgresql.sh chmod 755 /usr/local/etc/rc.d/postgresql.sh Test the script [root ~]# /usr/local/etc/rc.d/postgresql.sh stop Stopping PostgreSQL: ok [root ~]# If PostgreSQL successfully stopped, then turn it back on because we'll use it later. [root root]# /usr/local/etc/rc.d/postgresql.sh start Starting PostgreSQL: ok [root root]# /usr/local/etc/rc.d/postgresql.sh start SuSE: I have received reports that SuSE 8.0 is different from previous versions. Instead of installing the boot scripts in /etc/rc.d/init.d/, they should be placed in /etc/init.d/. If you're using SuSE 8.0, delete the rc.d/ part in each of the following commands. [root ~]# cp /var/tmp/&tarballpath;/packages/acs-core-docs/www/files/postgresql.txt /etc/rc.d/init.d/postgresql [root ~]# chown root.root /etc/rc.d/init.d/postgresql [root ~]# chmod 755 /etc/rc.d/init.d/postgresql Test the script. [root ~]# /etc/rc.d/init.d/postgresql stop Stopping PostgreSQL: ok If PostgreSQL successfully stopped, then use the following command to make sure that the script is run appropriately at boot and shutdown. [root ~]# cd /etc/rc.d/init.d root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/postgresql K20postgresql root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/postgresql S20postgresql root:/etc/rc.d/init.d# cp K20postgresql rc2.d root:/etc/rc.d/init.d# cp S20postgresql rc2.d root:/etc/rc.d/init.d# cp K20postgresql rc3.d root:/etc/rc.d/init.d# cp S20postgresql rc3.d root:/etc/rc.d/init.d# cp K20postgresql rc4.d root:/etc/rc.d/init.d# cp S20postgresql rc4.d root:/etc/rc.d/init.d# cp K20postgresql rc5.d root:/etc/rc.d/init.d# cp S20postgresql rc5.d root:/etc/rc.d/init.d# rm K20postgresql root:/etc/rc.d/init.d# rm S20postgresql root:/etc/rc.d/init.d# Test configuration. root:/etc/rc.d/init.d # cd root:~ # /etc/rc.d/init.d/rc2.d/S20postgresql start Starting PostgreSQL: ok root:~ # Mac OS X 10.3: Install the startup script: cd /System/Library/StartupItems/ tar xfz /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/osx-postgres-startup-item.tgz Mac OS X 10.4 can use Launchd: Install the startup script: cd /Library/LaunchDaemons cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/osx-postgres-launchd-item.txt org.postgresql.PostgreSQL.plist If postgres does not start automatically on reboot, see what error you get when manually starting it with: $ sudo launchctl load /Library/LaunchDaemons/org.postgresql.PostgreSQL.plist $ sudo launchctl start org.postgresql.PostgreSQL From now on, PostgreSQL should start automatically each time you boot up and it should shutdown gracefully each time you shut down. (Note: Debian defaults to starting all services on runlevels 2-5. Red Hat defaults to starting services on 3-5. So, on Red Hat, PostgreSQL won't start on runlevel 2 unless you alter the above commands a little. This usually isn't a problem as Red Hat defaults to runlevel 3) Tune postgres. (OPTIONAL) The default values for PostgreSQL are very conservative; we can safely change some of them and improve performance. Change the kernel parameter for maximum shared memory segment size to 128Mb: [root root]# echo 134217728 >/proc/sys/kernel/shmmax [root root]# Make that change permanent by editing /etc/sysctl.conf to add these lines at the end: # increase shared memory limit for postgres kernel.shmmax = 134217728 Edit the PostgreSQL config file, /usr/local/pgsql/data/postgresql.conf, to use more memory. These values should improve performance in most cases. (more information) # Shared Memory Size # shared_buffers = 15200 # 2*max_connections, min 16 # Non-shared Memory Sizes # sort_mem = 32168 # min 32 # Write-ahead log (WAL) # checkpoint_segments = 3 # in logfile segments (16MB each), min 1 Restart postgres (service postgresql restart) or (/etc/init.d/postgres restart) so that the changes take effect. FreeBSD users: See man syctl, man 5 sysctl and man 5 loader.conf. Performance tuning resources: Managing Kernel Resources about PostgreSQL shared memory and semaphores with specific operating system notes. Managing Kernel Resources (development version) This information may be experimental. Tuning PostgreSQL for performance more information about PostgreSQL Official PostgreSQL Docs Migrating from 7.0 to 7.1 techdocs.postgresql.org PostgreSQL Performance Tuning ($Id: postgres.xml,v 1.35 2006/07/17 05:38:38 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/configuring.xml0000644000175000017500000004005611501005400026403 0ustar frankiefrankie %myvars; ]> Configuring a new OpenACS Site by Joel Aufrecht In this chapter, Configuring refers to making changes to a new OpenACS site through the web interface. In crude terms, these changes happen in the database, and are upgrade-safe. Customizing refers to changes that touch the file system, and require some planning if easy upgradability is to be maintained. Installing OpenACS packages by Jade Rubick Installing OpenACS packages An OpenACS package extends your website and lets it do things it wasn't able to do before. You can have a weblog, a forums, a calendar, or even do sophisticated project-management via your website. After you've installed OpenACS, you can congratulate yourself for a job well done. Then, you'll probably want to install a couple of packages. To install packages, you have to be an administrator on the OpenACS webserver. Log in, and you'll see a link to Admin or the Control Panel. Click on that, then click on 'Install software'. Packages are sometimes also referred to as applications or software. At this point, you'll need to determine whether or not you're able to install from the repository, or whether you should install from local files. Basically, if you have a local CVS repository, or have custom code, you need to install from 'Local Files'. Otherwise, you can install from the OpenACS repository If you want to install new packages, click on 'Install from Repository' or 'Install from Local'. Select the package, and click 'Install checked applications'. The system will check to make sure you have all necessary packages that the package you want depends on. If you're installing from Local Files, and you are missing any packages, you may have to add the packages your desired package depends on: If you run into any errors at all, check your /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/error.log file, and post your error on the OpenACS forums Once the package has been installed, then you will need to 'mount' the package. The next section handles that. Mounting OpenACS packages by Jade Rubick Mounting OpenACS packages After you've installed your packages, you have to 'mount' them in order to make them appear on your website. Make sure you are logged in, and then click on the 'Admin' or 'Control Panel' link to get to the Site-Wide Administration page (at /acs-admin). Click on the subsite you'd like the application to be available at. Subsites are a way of dividing your website into logical chunks. Often they represent different groups of users, or parts of an organization. Now click on 'Applications' (applications are the same thing as packages). You'll see a list of Applications and the URLs that each is located at. To mount a new application, you click on 'Add application', enter the Application, title (application name), and URL (URL folder name), and you're done. Test it out now. The URL is based on a combination of the subsite URL and the application URL. So if you installed a package in the Main Subsite at the URL calendar, it will be available at http://www.yoursite.com/calendar. If you installed it at a subsite that has a URL intranet, then it would be located at http://www.yoursite.com/intranet/calendar. Configuring an OpenACS package by Jade Rubick Configuring an OpenACS package After you've installed and mounted your package, you can configure each instance to act as you would like. This is done from the Applications page. Log in, go to the Admin or Control Panel, click on the subsite the application is in, and click on Applications. If you click on the 'Parameters' link, you will see a list of parameters that you can change for this application. Setting Permissions on an OpenACS package by Jade Rubick Setting Permission on an OpenACS package After you've installed and mounted your package, you can configure each instance to act as you would like. This is done from the Applications page. Log in, go to the Admin or Control Panel, click on the subsite the application is in, and click on Applications. If you click on the 'Permissions' link, you will see and be able to set the permissions for that application. Each application may have different behavior for what Read Create Write and Admin permissions mean, but generally the permissions are straightforward. If you find the behavior is not what you expect after setting permissions, you can post a bug in the OpenACS bugtracker. 'The Public' refers to users to the website who are not logged in. 'Registered Users' are people who have registered for the site. How Do I? How do I edit the front page of a new site through a web interface? The easiest way is to install the Edit-This-Page package. Log in to the web site as an administrator. Click on Admin > Install Software > Install from OpenACS Repository / Install new application Choose Edit This Page and install Follow the instructions within Edit This Page (the link will only work after Edit This Page is installed). How do I let anybody who registers post to a weblog? Go to /admin/permissions and grant Create to Registered Users How do I replace the front page of a new site with the front page of an application on that site Suppose you install a new site and install Weblogger, and you want all visitors to see weblogger automatically. On the front page, click the Admin button. On the administration page, click Parameters link. Change the parameter IndexRedirectUrl to be the URI of the desired application. For a default weblogger installation, this would be weblogger/. Note the trailing slash. How do I put custom functionality on front page of a new site? Every page within an OpenACS site is part of a subsite More information). The home page of the entire site is the front page is a special, default instance of a subsite, served from /var/lib/aolserver/$OPENACS_SERVICE_NAME/www. If an index page is not found there, the default index page for all subsites is used. To customize the code on the front page, copy the default index page from the Subsite package to the Main site and edit it: cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-subsite/www/index* /var/lib/aolserver/$OPENACS_SERVICE_NAME/www Edit the new index.adp to change the text; you shouldn't need to edit index.tcl unless you are adding new functionality. How do I change the site-wide style? Almost all pages on an OpenACS site use ACS Templating, and so their appearance is driven by a layer of different files. Let's examine how this works: A templated page uses an ADP/TCL pair. The first line in the ADP file is usually: <master> If it appears exactly like this, without any arguments, the template processer uses default-master for that subsite. For pages in /var/lib/aolserver/$OPENACS_SERVICE_NAME/www, this is /var/lib/aolserver/$OPENACS_SERVICE_NAME/www/default-master.adp and the associated .tcl file. The default-master is itself a normal ADP page. It draws the subsite navigation elements and invokes site-master (/var/lib/aolserver/$OPENACS_SERVICE_NAME/www/site-master.adp and .tcl) The site-master draws site-wide navigation elements and invokes blank-master (/var/lib/aolserver/$OPENACS_SERVICE_NAME/www/blank-master.adp and .tcl). Blank-master does HTML housekeeping and provides a framework for special sitewide navigation "meta" elements such as Translator widgets and Admin widgets.
    Site Templates
    How do I diagnose a permissions problem? Steps to Reproduce The events package does not allow users to register for new events. Go to the http://yourserver.net/events as a visitor (ie, log out and, if necessary, clear cookies). This in on a 4.6.3 site with events version 0.1d3. Select an available event A link such as Registration: Deadline is 03/15/2004 10:00am. » Login or sign up to register for this event. is visible. Click on "Login or sign up" Complete a new registration. Afterwards, you should be redirected back to the same page. Actual Results: The page says "You do not have permission to register for this event." Expected results: A link or form to sign up for the event is shown. Finding the problem We start with the page that has the error. In the URL it's http://myserver.net/events/event-info.tcl, so open the file /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/events/www/event-info.tcl. It contains this line: set can_register_p [events::security::can_register_for_event_p -event_id $event_id] We need to know what that procedure does, so go to /api-doc, paste events::security::can_register_for_event_p into the ACS Tcl API Search box, and click Feeling Lucky. The next pages shows the proc, and we click "show source" to see more information. The body of the proc is simply return [permission::permission_p -party_id $user_id -object_id $event_id -privilege write] This means that a given user must have the write privilige on the event in order to register. Let's assume that the priviliges inherit, so that if a user has the write privilige on the whole package, they will have the write privilege on the event. Setting Permissions A permission has three parts: the privilige, the object of the privilige, and the subject being granted the privilige. In this case the privilige is "write," the object is the Events package, and the subject is all Registered Users. To grant permissions on a package, start at the site map. Find the event package and click "Set permissions". Click "Grant Permission" Grant the write permission to Registered Users.
    Granting Permissions
    OpenACS 5.0 offers a prettier version at /admin/applications.
    Granting Permissions in 5.0
    openacs-5.7.0/packages/acs-core-docs/www/xml/install-guide/recovery.xml0000644000175000017500000005240311501005400025726 0ustar frankiefrankie %myvars; ]> Backup and Recovery ($Id: recovery.xml,v 1.17 2010/12/11 23:36:32 ryang Exp $) By Don Baccus with additions by Joel Aufrecht We will cover some basic backup and recovery strategies. These are intended to be robust but simple enough to set up. For a large scale production site you would probably need to create your own backup strategies (in particular full dumps from oracle, while easy to set up, are far from the best solution). There are three basic things which need to be backed up, the database data, the server source tree, and the acs-content-repository (which is in the server source tree).
    Backup and Recovery Strategy
    Backup Strategy The purpose of backup is to enable recovery. Backup and recovery are always risky; here are some steps that minimize the chance recovery is necessary: Store everything on a fault-tolerant disk array (RAID 1 or 5 or better). Use battery backup. Use more reliable hardware, such as SCSI instead of IDE. These steps improve the chances of successful recovery: Store backups on a third disk on another controller Store backups on a different computer on a different network in a different physical location. (Compared to off-line backup such as tapes and CDRs, on-line backup is faster and more likely to succeed, but requires maintenance of another machine.) Plan and configure for recovery from the beginning. Test your recovery strategy from time to time. Make it easy to maintain and test your recovery strategy, so that you are more likely to do it. OpenACS installations comprise files and database contents. If you follow the reference install and put all files, including configuration files, in /var/lib/aolserver/$OPENACS_SERVICE_NAME/, and back up the database nightly to a file in /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup, then you can apply standard file-based backup strategies to /var/lib/aolserver/$OPENACS_SERVICE_NAME Manual backup and recovery This section describes how to make a one-time backup and restore of the files and database. This is useful for rolling back to known-good versions of a service, such as at initial installation and just before an upgrade. First, you back up the database to a file within the file tree. Then, you back up the file tree. All of the information needed to rebuild the site, including the AOLserver config files, is then in tree for regular file system backup. Back up the database to a file Oracle Download the backup script. Save the file export-oracle.txt as /var/tmp/export-oracle.txt Login as root. The following commands will install the export script: [joeuser ~]$ su - [root ~]# cp /var/tmp/export-oracle.txt /usr/sbin/export-oracle [root ~]# chmod 700 /usr/sbin/export-oracle Setup the export directory; this is the directory where backups will be stored. We recommend the directory /ora8/m02/oracle-exports. [root ~]# mkdir /ora8/m02/oracle-exports [root ~]# chown oracle:dba /ora8/m02/oracle-exports [root ~]# chmod 770 /ora8/m02/oracle-exports Now edit /usr/sbin/export-oracle and change the SERVICE_NAME and DATABASE_PASSWORD fields to their correct values. If you want to use a directory other than /ora8/m02/oracle-exports, you also need to change the exportdir setting. Test the export procedure by running the command: [root ~]# /usr/sbin/export-oracle mv: /ora8/m02/oracle-exports/oraexport-service_name.dmp.gz: No such file or directory Export: Release 8.1.6.1.0 - Production on Sun Jun 11 18:07:45 2000 (c) Copyright 1999 Oracle Corporation. All rights reserved. Connected to: Oracle8i Enterprise Edition Release 8.1.6.1.0 - Production With the Partitioning option JServer Release 8.1.6.0.0 - Production Export done in US7ASCII character set and US7ASCII NCHAR character set . exporting pre-schema procedural objects and actions . exporting foreign function library names for user SERVICE_NAME . exporting object type definitions for user SERVICE_NAME About to export SERVICE_NAME's objects ... . exporting database links . exporting sequence numbers . exporting cluster definitions . about to export SERVICE_NAME's tables via Conventional Path ... . exporting synonyms . exporting views . exporting stored procedures . exporting operators . exporting referential integrity constraints . exporting triggers . exporting indextypes . exporting bitmap, functional and extensible indexes . exporting posttables actions . exporting snapshots . exporting snapshot logs . exporting job queues . exporting refresh groups and children . exporting dimensions . exporting post-schema procedural objects and actions . exporting statistics Export terminated successfully without warnings. PostgreSQL Create a backup file and verify that it was created and has a reasonable size (several megabytes). [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ pg_dump -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ ls -al /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp -rw-rw-r-x 1 $OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME 4005995 Feb 21 18:28 /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit [root root]# su - $OPENACS_SERVICE_NAME pg_dump -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp openacs-dev ls -al /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp exit Back up the file system Back up all of the files in the service, including the database backup file but excluding the auto-generated supervise directory, which is unneccesary and has complicated permissions. In the tar command, c create a new tar archive p preserves permissions. s preserves file sort order z compresses the output with gzip. The --exclude clauses skips some daemontools files that are owned by root and thus cannot be backed up by the service owner. These files are autogenerated and we don't break anything by omitting them. The --file clause specifies the name of the output file to be generated; we manually add the correct extensions. The last clause, /var/lib/aolserver/$OPENACS_SERVICE_NAME/, specifies the starting point for backup. Tar defaults to recursive backup. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ tar -cpsz --exclude /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/supervise \ --file /var/tmp/$OPENACS_SERVICE_NAME-backup.tar.gz /var/lib/aolserver/$OPENACS_SERVICE_NAME/ tar: Removing leading `/' from member names [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ Suffer a catastrophic failure on your production system (We'll simulate this step) [root root]# svc -d /service/$OPENACS_SERVICE_NAME [root root]# mv /var/lib/aolserver/$OPENACS_SERVICE_NAME/ /var/lib/aolserver/$OPENACS_SERVICE_NAME.lost [root root]# rm /service/$OPENACS_SERVICE_NAME rm: remove symbolic link `/service/$OPENACS_SERVICE_NAME'? y [root root]# ps -auxw | grep $OPENACS_SERVICE_NAME root 1496 0.0 0.0 1312 252 ? S 16:58 0:00 supervise $OPENACS_SERVICE_NAME [root root]# kill 1496 [root root]# ps -auxw | grep $OPENACS_SERVICE_NAME [root root]# su - postgres [postgres pgsql]$ dropdb $OPENACS_SERVICE_NAME DROP DATABASE [postgres pgsql]$ dropuser $OPENACS_SERVICE_NAME DROP USER [postgres pgsql]$ exit logout [root root]# Recovery Restore the operating system and required software. You can do this with standard backup processes or by keeping copies of the install material (OS CDs, OpenACS tarball and supporting software) and repeating the install guide. Recreate the service user ($OPENACS_SERVICE_NAME). Restore the OpenACS files and database backup file. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver [$OPENACS_SERVICE_NAME aolserver]$ tar xzf /var/tmp/$OPENACS_SERVICE_NAME-backup.tar.gz [$OPENACS_SERVICE_NAME aolserver]$ chmod -R 775 $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME aolserver]$ chown -R $OPENACS_SERVICE_NAME.web $OPENACS_SERVICE_NAME Restore the database Oracle Set up a clean Oracle database user and tablespace with the same names as the ones exported from (more information). Invoke the import command imp $OPENACS_SERVICE_NAME/$OPENACS_SERVICE_NAME FILE=/var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/nighty_backup.dmp FULL=Y Postgres If the database user does not already exist, create it. [root root]# su - postgres [postgres ~]$ createuser $OPENACS_SERVICE_NAME Shall the new user be allowed to create databases? (y/n) y Shall the new user be allowed to create more new users? (y/n) y CREATE USER [postgres ~]$ exit Because of a bug in Postgres backup-recovery, database objects are not guaranteed to be created in the right order. In practice, running the OpenACS initialization script is always sufficient to create any out-of-order database objects. Next, restore the database from the dump file. The restoration will show some error messages at the beginning for objects that were pre-created from the OpenACS initialization script, which can be ignored. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME ~]$ createdb $OPENACS_SERVICE_NAME CREATE DATABASE [$OPENACS_SERVICE_NAME ~]$ psql -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-kernel/sql/postgresql/postgresql.sql $OPENACS_SERVICE_NAME (many lines omitted) [$OPENACS_SERVICE_NAME ~]$ psql $OPENACS_SERVICE_NAME < /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/database-backup.dmp (many lines omitted) [$OPENACS_SERVICE_NAME ~]$ exit [postgres ~]$ exit logout Activate the service [root root]# ln -s /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools /service/$OPENACS_SERVICE_NAME [root root]# sleep 10 [root root]# svgroup web /service/$OPENACS_SERVICE_NAME Automated Backup The recommended backup strategy for a production sit is to use an automated script which first backs up the database to a file in /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup and then backs up all of /var/lib/aolserver/$OPENACS_SERVICE_NAME to a single zip file, and then copies that zip file to another computer. Make sure that the manual backup process described above works. Customize the default backup script. Edit /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/backup.sh with your specific parameters. Make sure the file is executable: chmod +x backup.sh Set this file to run automatically by adding a line to root's crontab. (Typically, with export EDITOR=emacs; crontab -e.) This example runs the backup script at 1:30 am every day. 30 1 * * * sh /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/backup.sh Using CVS for backup-recovery CVS-only backup is often appropriate for development sites. If you are already using CVS and your data is not important, you probably don't need to do anything to back up your files. Just make sure that your current work is checked into the system. You can then roll back based on date - note the current system time, down to the minute. For maximum safety, you can apply a tag to your current files. You will still need to back up your database. Note that, if you did the CVS options in this document, the /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc directory is not included in cvs and you may want to add it. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs commit -m "last-minute commits before upgrade to 4.6" cvs commit: Examining . cvs commit: Examining bin (many lines omitted) [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs tag before_upgrade_to_4_6 cvs server: Tagging bin T bin/acs-4-0-publish.sh T bin/ad-context-server.pl (many lines omitted) [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit [root root]# su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver/$OPENACS_SERVICE_NAME cvs commit -m "last-minute commits before upgrade to 4.6" cvs tag before_upgrade_to_4_6 exit To restore files from a cvs tag such as the one used above: [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs up -r current [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver/$OPENACS_SERVICE_NAME cvs up -r current
    openacs-5.7.0/packages/acs-core-docs/www/xml/openacs.css0000644000175000017500000000232407766162044022776 0ustar frankiefrankie/* These are aimed at DocBook output, specifically from the chunk.xsl style and derivatives /* body,ol,td,th,hr,h1,h2,h3,strong,dl,a,blockquote,em,.force,dt,dd,ul,li,p { font-family: verdana,helvetica,arial,sans-serif; } a:link {color: #f00;} a:visited {color: #000099;} a.topnav {font-size: 1.2em;} a.bottomnav {font-size: 1.2em;} code { font-family: courier,monospace; } .codeblock { background-color: #fff; font-family: monospace; } .strong {font-weight: bold;} .authorblurb {font-size: small;} /* this is intended to catch docbook Screen stuff */ pre {background-color: #eee;} /* DocBook stuff */ .guibutton { background-color: #fff; border: solid #eee 3px; margin: 2px; } .replaceable { color: red; font-style: italic; } .guilabel { background-color: #ccc; margin: 2px; } .programlisting { background-color: #eee; margin-left: 1em; padding-left: .5em; } .strong {font-weight:bold;} .authorblurb {font-size:small;} .screen { padding:4px; margin-left: 1em; } .action {font-weight:bold;} .table,.informaltable,.informalfigure,.figure { margin-left: 1em; } body { margin: 1em 0 0 1em; max-width: 75em; } div.cvstag { font-family: courier,monospace; color: #999; font-size: small; text-align: right; } openacs-5.7.0/packages/acs-core-docs/www/xml/openacs.xsl0000644000175000017500000003406711226233616023013 0ustar frankiefrankie 0 -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd" UTF-8 openacs.css 1 1 1 1 1 comments
    http://openacs.org/doc/current/ #comments View comments on this page at openacs.org
    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    FeatureStatusDescription
    openacs-5.7.0/packages/acs-core-docs/www/xml/fo.xsl0000644000175000017500000000475010064554467021774 0ustar frankiefrankie 1 book toc,title,index /sect1 toc 1 1 openacs-5.7.0/packages/acs-core-docs/www/xml/images/0000755000175000017500000000000011724401447022070 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/images/arsdigita.gif0000644000175000017500000000173607525303737024544 0ustar frankiefrankieGIF89aIAÕÿÿÿ±È㦦¦ØãñÒÒÒúüý¶ËåÅÖê¼¼¼ëñøéééðõúôôôÀÒè»ÏçùùùÈÈÈâêõõøü···ÝçóçîöÍÍÍîîîÊÙìÎÜîØØØÓàï±±±ÂÂÂÝÝݬ¬¬ããã!ù,IAÿ@€pH,HaÉl:—Å#I­Z«‚¬vËåNŒ«xŒìšÏYH˜Ì£ß]M{NÝV aÒíLé€Cvc [tƒd[‹€l[“s•l[šlœlZ¡d£d [ ¨nZ‹ži¯Wª«[еe±‹|Y »u½ZÂI·dZɼYš¹ÐFËd¥Y®ÕD×c—YÜÝÄÇã‚å€ ¦éBÞbíYïñ°Òb ÿ*$O@(jI DÀ` €Ã‡ `ˆP`˜¾I­’ h±£Ç*Áw…ƒ–mE$4øÈ²£#×Ê&å[êtÁšLÿ:4å)°²¥ƒHs~\P„¤šâˆ `i`A"(8øØ éÏ9P‡*}Ø@ä¢+»¸(ì˜ER`l k jr+$CÚ+S=æ ÅÀÄ,øÞ×6…?ó×1Û@…mí8@Ýå™Z¢j:ÌÙ³ÞI4ƒ…" ±³åÓmO¢býÐõ½ÇlLjïÀßÿ6·6}P6•hï,ýºøç!_ÎÒ¶S,_)Ø¥îÑ:î1óL0R@9÷êÄ'…?5´hË€œîÐûó6ÆÂ1ïÐÀ¦T˜gl€€#€DPÀÒs%!`z±eŠu}Ô“6‡Q9puGû†]ªçÎ ÆÆG!.’ŸB aWd,框è&À„€"2wÛ}c4“Å3C$°ã~Íø#mÌ"€héÑcT¨äuF°¢ÅBHÙ‘cvåwUЄL,5V…Ûâ ÀåîATVh¡G#çh‘‰ ~„AƒX¹"„c<‚]m:@Aƒ $éPbÖ†¨…¢E"IT°ÓQH-å©Þ\‡¿ ¢Ëœ×QO^>„×kp¼ñ§ºza¬MFk­]¨#\˜£G¾. ¬)Ìãô=$‘š7%`­µÆ>¡m à8 ?þüS±ö\;openacs-5.7.0/packages/acs-core-docs/www/xml/images/ext-auth.dia0000644000175000017500000000377307720717702024325 0ustar frankiefrankie‹í\[sÚF~ϯ`È«¼hï«»ã&í´3é4Ó´/}a„XƒZ!QIÄqúÛ{VÂcµÊ&n-˜I&aѧ£Ýs¾s…×ß|Z&ƒ:/â,=bä:²YœÎχ¿ýúý™~sñâõ,_ÁŸy.pEZ˜ÿe¹z5]__£ä¦Ë,GI¼F…ý&I8‚†»WÏÂ2¬ßË2§ëRÒp©Ï‡Ó0úsžgët¶¹"Ê’,| “óáË«ê5]¼Ý»¶j®t¾EY®²"†µòfµ·¶ù{³TÀJ:¿xùN—¥Î_ַݼÙJ†ræó8ÝÀå:LêG!ˆ³¶Ï1u€‘8ÀÈ`ÄÅd•åeÆågše‰ÓªÌ׺-T… œÃqp[€«¸,³&)®Â¤hctO•ÚÝežÇ³J¸³´Õu<+“OÝ®¸éð1.âi¢·2ÄiÙá¦B§½]Ç3]ÚÝÝÅý+›ÕÑÑï–“kÔHkIx£ó Ø·w”6ØìÉFÓëÏfÓ?tTn¤þ>É®£E˜—ƒ³Á·Ù§á+'dzóáÏþG°­Û^ewÛ%¹w&‘„·==7nõ'*Ãtžè-"­&|L}„=â#·i ¯½œDYžniø³%® +½HQ ù¶H ÏemMQ‹ìzòÀ£uf¼U8›51ì|[ˆR*ØËÎÒƒç¨<ÞžOüy¥ÓË7?dEùâ‘WÏy•¥·â˜®ÂeœÜ€,aZ Eyc¬l¢þô›lÇ J-·áÀÙúHµ>‹FKÈÇJyga u«Bœ†pǯ^mQÀÎÓ¥ÞîšN×ËÏàÛÑ5u¢)lKSQïŒ"-XäIQDx(pL(RÜÃb˜¸!©.ò£( +>ÊOÈŸ(j—¢ Œ#Ý{z¢ˆƒI`¤¤Â½&'bKN YmwÂMG*81†C¡Ü³5þC¤ÔAÎ#œ ßQÐt¢#SEÈ }¼çº'„£¬âx¿}Èü?§›·Y´®îûs¨-çp„Á€\0€1gáó1&@Txn¨ÇZÜ#Ä#õ%ÆN¨ÇîÐU¯&‹,ÿ› «jÓABD&=ÜQO¸.¯^…wå ÝŸ’…0zîã¾Sî@AÌÄ”pî8ÈŒéÄŠ„ Ì d5]:È|´‡ÃœÐD¾<5qj¨o€Iò0*{UG…°›j‚è9'Y½Âž‘j眅EXámÉŒÁ‚Ïpuøhá(8ÅE.'`#àm÷§TäCp­å§ ˆv ZÕÙvF@ÔàaQ/«ˆˆwd/ðQòD@NkB}£ó5 ÄzÓFþ=žÿÎ4“1ëš™AI1q3ј,¹Ž‚’¦Û`çåbr°‘ü@Üýø,úÛbczÿغ² ͳd`* jâßÞcOsÚ}ªÛ•à°>·Ó½â ×½‹öE»Ýßo]óÝnì7µÈ¿L¿ó oCv qáèKÄ´*Ü –|L„}ßô”HâªÙm/ò©Õý$¥wo/ß÷®Ñ aƒð$bJ Üë)4l=K$”¢°{ØQúb©P¦ïC%¥c`À´ü$ Tàjí¡ØÍœiµPŠÓ@š½‹î{[¿‡ÞbS]t kÿ k }&°ÓªÄÂ걜öîÙ…9ÔójÜ*Ç:ÙÃW±õuÌÁz8ÓÌTy9vU[7 YÍø\ µ¤æ„¶SÞûÀŒ”•Ÿl¡½-àf[P_æˆ8èR.UÒDwÃ4¸Fdõ4)0€¢C~⮑m/óižæ«ÎÓäú¯uœëIõ»ý¨1?«è—³çT¾m%óþOh^¼øïQÿXopenacs-5.7.0/packages/acs-core-docs/www/xml/images/ext-auth.png0000644000175000017500000011747007720717702024354 0ustar frankiefrankie‰PNG  IHDRç8F ÐesBITÛáOà pHYsÐй‹çŸ IDATxœìÝy\Ôvþ?ðO˜2\ÖÂP†aTPWÁhlm­J/¨öØZm+­-­XµÒj=º\®ZÑz-_«"(¨¨Š"‡ °¨€‚ 7“ßÙ΃—™ÀëùÇnÈ$Ÿ¼“IåÅ'Ÿ$P& îîîlWʈÇv=¢ÊüMÓìÖàáᑘ˜Èv ¼Ð×Ü€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔƒP||¼‹‹‹®®®¾¾þìÙ³oݺ¥ÀÆÇïààÐnæÉ“']\\ôôô„B¡‰‰É¢E‹˜ùqqq:::fffß}÷]»)ŠÊÉÉ‘ÿ˜““CQ”«LZ`°9}úô‚ >ûì³ÊÊʲ²277·¼¼<…4ž–––‘‘qûömùÌÇ¿öÚkŸ|òÉÇ?~œœœ!¤]ÇÆÃ‡™ù„ŸþYOOoéÒ¥×®]#„œ9s†Çã.Z´èÈ‘#éééòµ"""FŒ!‹›šš˜9ÑÑÑ^^^ÚÚÚR©T,3‰„B!³‰NëÑÔÔ\¿~}~~þÕ«W[[[=<<š››Û-“-ÿ’I!„’’’;wîÌŸ?Ÿ2oÞ¼¼¼¼ÒÒR‘H4qâDOOÏmÛ¶ÕÕÕõõ`p R *úúúöööGm;óرcÓ§Og¦ÕÔÔ˜ uuuBˆ†††‘‘QXXXXXXdddÛÛy˜äwôÔÕÕÅÆÆ=z”¢(WTTtèС†††áÇ[XX99944ôÒ¥KR©´±±±çM H-0Ø|÷ÝwëÖ­‹‹‹“ÉdMMM»v튉‰ùâ‹/ä Ð4åååEñööÎÏÏOII166‰D «f;¦¥¥Å\—a:Eª««ãââ(Šúú믃ƒƒýõ׺º:š¦ 6oÞL)--ݲeKQQ³Ê©S§ E"QOöÂÄÄÄÒÒòÈ‘#„C‡YXXˆD¢šššŠŠŠéÓ§oÛ¶­  àáÇLÁOŸ>íãAà¤lf̘±ÿþ==½#F;v,11qÔ¨Q̧æææÅÅÅÛ·o'„˜™™8q"44ÔÈÈÈÂÂÂßß¿«f£££ƒ‚‚ø|>󣕕•s‘háÂ…ÿùÏvïÞm`` ¥¥åééY]]M)))S§N …†††›7o>qâD7Á¨-Š¢8&‘HÂÃÃ>>mgúúúž={–¹’) ÍÍÍÓÒÒ˜O#""¤RéäÉ“œœ˜kIÌ’ VVV`Íš5Ì’2™,&&fÁ‚~~~ûöí“Éd„òòòÜÜ\__ߎňÅbWWW—]»v•——w\€¦é€€‘H$‘HÞÿýîë µ¶¶ž3gNXX³ä±cÇfΜÙö Qnn®‡‡‡‰‰É¦M›:m ­ îîî„„„E5J"77—ÒÜÜÜvfff&Çc.£¬X±¢²²2((ÈÙÙ™¦éÔÔT]]Ýòòrš¦ÃÃÃ]]]išf–\¸paYYY\\ŸÏgÚ9wîœ@ xòäÉÕ«W !çÏŸ§i:''§ãåjkkCBB$ ÇóññÉÏÏoûéÝ»w !ÌÖ»¯gíÚµ555‡=z´L&£izÖ¬Y‡f>¥iZ&“ÙØØ·´´Èd²ÚÚÚN[ƒAÿš±‡º‡¾è}}}BH»Ž‡2ó !?ÿü³žžÞÒ¥K¯]»F9sæ Ç \´hÑ‘#GÒÓÓåkEDDŒ1B,7551s¢££½¼¼´µµ¥R©X,f. …BfÖ£©©¹~ýúüüü«W¯¶¶¶zxx477Ë?‰D'Nôôôܶm[]]]÷õ„„„hiiÍ;·¬¬ìÚµkÅÅÅ7nܘ;w®|ÒÒÒ¬¬¬O?ýTEE…¢(MMÍnZ€þƒÑ¸Ð#úúúöööG}÷Ýwå3;6}útfZMM™PWW'„hhhɯ¹´Å, ¿øRWWS#ŸsèСüqøðáüðûªŠ¢(GGÇhii›››Ë‹INNNLLܽ{÷öíÛ³²²º©GUU•"üýý#"" ßxã ùîÈKe®[1ºi úúZ §¾ûî»uëÖÅÅÅÉd²¦¦¦]»vÅÄÄ|ñÅòhšŽŠŠòòò"„x{{çç秤¤‹D"@ÐU³ÇŽÓÒÒb®ãÐ4]]]GQÔ×_ü믿ÖÕÕÑ4]PP°yófBHiié–-[ŠŠŠ˜UN:ehh(‰ämÖÔÔTTTLŸ>}Û¶m>ìI=o¾ùæþýûÿýï¯\¹²í|ccc;;» 6466¶´´”””ô|ï@Z §f̘±ÿþ==½#F;v,11qÔ¨Q̧æææÅÅÅÛ·o'„˜™™8q"44ÔÈÈÈÂÂÂßß¿«f£££ƒ‚‚ø|>󣕕•s‘háÂ…ÿùÏvïÞm`` ¥¥åééY]]M)))S§N …†††›7o>qâDÛèðäÉ“™3gJ$’ &|þùç&&&=©ÇÑÑÑØØØÆÆF,·OQTlllZZšžžžH$Љ‰éùÞ€ý¯Ož¦i…4çáᑘ˜˜ÀŒ¨‚¡ ''ÇÚÚZQ§€’À¿f¬Àa‡î¡¯¸©úÊÌÌìæÍ›lWƒR ô•@ °µµe» üZ€Z€Z€ðl\r®_¿ÞÍóvÓìíí·lÙÂvÐ_Z`È©ªªJLLd» xnH-0DáòA]hCR QB¡ßàŒÆn@jnP–+D¸& Ï´eË{{{¶«Ö(KjÁmðLUUUl—lR–ÔÂÀmЩ?üðúõëlW,S®Ô‚Û: SB¡í€} Ü€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€Ô08ÕÕÕ%&&²]€"!µôEQ999½[7''‡¢¨nE(…B qãÆ]¹r¥w…ž‹‹‹spp000ÐÑÑ133ûî»ï¾†ñãÇ;88ôbÅââbò<§Y;½^‘“©…MfffÙÙÙ=\8%%¥¢¢¢ªªª¼¼ÜÙÙ9  _kƒšššùó燄„”——WUUÅÇÇ;99 p ÙÙÙiii·oßîu#ÏušBSRRz±bG8i@±ZØ$¬¬¬žw---­•+WfeeõGI WQQQ__?qâDŠ¢(Š’H$nnn\Ctt´···©©iLLL¯yÞÓ¬°°pÒ¤I½X±8i@!ZúEFF†T*•H$R©4##ƒ™1mÚ´Å‹ÛÚÚJ¥RÒ¦ž™HHH°²²kÖ¬é¾ýâââáÇBvìØ1zôhCCÃ×_¦é®6ÄÌ”J¥“'OvrrºuëV?íø`"‹]]]]\\víÚU^^Þö£Nfnn®‡‡‡‰‰É¦M›Ú^^i÷E‡††Z[[wÕŽœL&‹‰‰Y°`ŸŸß¾}ûd2™¼…ÈÈH¡Phnnž––ÖÕL¹¶•´+’tv -[¶Œbaa#_±ã)“XC+ˆ»»;!$!!áyWLHH „¸»»+ª’CÉÎÎn;G&“YZZFFFÒ45räH™L–žž®¥¥UQQAÓttt´££#MÓL÷»|báÂ…eeeqqq|>¿«­444œ?ÞÂÂbíÚµ4Mµ¶¶Þ¿ŸRTTDÓt§JMMÕÕÕ-//§i:<<ÜÕյߋBõú¼êTÏO¶ÚÚÚ‰DÂãñ|||òóóé.¦L&³±± nii‘Édµµµò/—îðE¯]»¶¦¦æ™_ʹsçÁ“'O®^½J9þ¼¼…+VTVV9;;w?³íDÇ"éÎN¡NWìxJ+ÛI«ðC{ÖAá°C÷T" 1%%%wîÜ™?>!dÞ¼yK—.---MJJ5j”¾¾~7+FDD¨««‹Å⦦¦ŽŸ2«ªªŠÅâ7Þxã³Ï>#„…¨¨¨ÂÂBBH}}=!¤Ó 9s†ÇãBÊËËÓÓÓ¶·ƒš¦¦æúõë×­[—žžþå—_zxxtz0KKK³²².]º¤¢¢Â¬ØM³!!!ªªªÏüR¢££½¼¼´µµ¥R©X,މ‰™2e óÑÏ?ÿ¬¦¦¶téÒ_~ùE¾|§3Ûê´ÈާPGžÒÌG8i` !µô¦kéÕ'„èè蔕•Éd2×ÕGuuuùŠegg·dÐÔÔ$•JƒƒƒCBBºÙ†††‘‘QXX˜"ölÈ¡(ÊÑÑñÀZZZÅÅÅÌv_·MÓE566¶©ªªJžõ¥ÔÕÕÅÆÆÖÔÔÈχC‡ýøãÌ´šš3Áœ3ÝÌì¾ÈNO¡®tº8i` a\‹â™˜˜XZZ9r„rèÐ! ‘H4gΜ–––€€€   “'Oòx 8ò¥¥¥ùùùžžž< „TWWB:Ý··w~~~JJб±±H$}ßú WZZºeËæMÓ§N244‰DLccc;;» 6466¶´´”””0¿Î‹ŠŠrssƒ‚‚:¶ßý—rìØ1--­ÆÆFfëÙÙÙÕÕÕqqqòhšŽŠŠòòòj»V§3å:Ùé)ÄTòôéSùŠžÒ½>ª8i ×ZÀÉÉÉàoE8p ,,L"‘„‡‡_&“íÙ³ÇÖÖ–²cÇŽíÛ·———{zzFEEÉ/ÖüòË/ëÖ­ÓÔÔŒŠŠš2eJÛj;m§£ŒŒŒ•+W>zôHOOo÷îÝãÆcÖŽŽ>|øÍ›7ÕÕÕSSSŸ¹ïr„„„„¶Ëwz@ºoùÂ… ï¿ÿþ•+W† Ö·¯Qñz=ô›+ZZZöïßÕÒÒb``óªç7ntüˆ¹D"ŸX¸paYYY\\ŸÏ§iZ&“ÙØØ·´´Èd²ÚÚÚvË·k¤±±Q$ýþûïmg¦¦¦êêê–——Ó4îêêʬUTTÔÚÚzÿþ}BHQQ‘|•wÞy§±±ñ_ÿú—………L&{f;íjÉd–––‘‘‘4MGEE9R&“¥§§kiiUTTÐ4íèèøÌ}—ëê ´[¾ÓÒÍ’ååå‰$##£«oíÕW_%„>|¸ç_4ôPjjêØ±c !E½ûî»Ož_>¿ÓvºÒ®r²²2™LÆãñºÛnß»jªûåÛn–5jÔüñÑG©©©õd ï.]º´|ùòœœ•>ú諯¾RÂks}4˜ï|îž±±±Ý† ZJJJä1¿‰‹ŠŠrssƒ‚‚˜™vvv >>¾¹¹ù«¯¾bfz{{çç秤¤‹D"@@)--ÍÏÏ÷ôô|ðà!¤ºººÝ¦ÿøãÉ“'¿ð ò9¶Ó‘‰‰‰¥¥å‘#G!‡²°°‰DsæÌiii  :yò$‰ú~Úêô€t#44”¢¨   š¦{^ ôÎÓ§OW¯^íêêš““3zôèäääÍ›7#²À 4tS EQ±±±iiizzz"‘(&&Fþ‘©©©ŸŸŸ¥¥å’%KV­ZÅÌÔÕÕݹsçŠ+&L˜`ggÇÌ433;qâDhh¨‘‘‘………¿¿?!D,ûúúš››oݺuÙ²ežžžÍÍÍÌòÓ¦Móññ9wîܾ}ûÚÓi;Ö|àÀ°°0‰D~ðàAŠ¢ôõõ¯]»fmmíææöÞ{ïéèè(ä ´Õé醪ªêâââÂÃÃ{^ ô¹sçÆŒ³mÛ6•àààôôt'''¶‹ègŠ&£T£q‡ˆ¼¼¼œœœæææÂÂB‡õë׳]ѳa4nßUUU­\¹’¹67nܸnÆ>Cï`X(+pØ¡{C·¯eиsçÎÌ™3ù|¾½½ýرc׬YÃvEÐïþûßÿÚÚÚîÞ½›ÏçoܸñêÕ«û CÁ;XÍš5«¨¨ˆí*`€TVV®^½š¹–7iÒ¤½{÷Z[[³]ÀA_ gÄÆÆÚØØÄÄÄ 6ì‡~HJJBd€!}-pÿþý÷ߟ¹}ÌÃÃc÷îÝæææl0ÐÐנ좢¢lllŽ9ò /ìܹ3>>‘†&ôµ(¯’’’·ß~ûÿþïÿ!^^^¿üòËy3@§Ð× Œhšþå—_lmmÿïÿþOOO/222..‘†8ôµ(‚‚‚•+W2/¦~õÕWúé§#F°]ûÐ× DZ[[·lÙ2f̘„„„_|ñСC‡Fd` ¯@Ydgg/_¾üòåË„×^{mëÖ­Ý¿Ê`¨A_ ûZZZ¾ùæ›qãÆ]¾|Y$Û;7H\¿~ý­·ÞÊÈÈ (jåÊ•›6mz®W` H-ƒGYYYvvöíÛ·³³³³²²JJJŠŠŠd2YÏ[hjjjjjªªªêÉÂúúú‰äå—_¶þÛèÑ£AoËŠ¿úê«ï¿ÿ¾¹¹Y"‘ìÞ½{êÔ©l ¼Z¸ª©©éìÙ³ÙËÌ̬­­í¸˜P(”w0%FFFšššò~ù„¦¦fSS“¼ëEÞ SSSS]]-ïªaºmJKK++++++¯]»&ßÇ‹ÅL|±¶¶‹Ånnn<®Bv.%%eùòå·oßæñx«V­Ú¸q£¦¦&ÛE(5¤ÎxôèQZZZêߊ‹‹Û- ££cgg'ïù1bĘ1cž+4MéÜ IDAT@  {²ðÇÿüóÏüü|yO^^ÞÝ»wïÞ½ûßÿþ—Y†Ïç3Fú7UUœr¤®®nýúõÛ¶mkmmµ²²Ú»wïäÉ“Ù. €ð+DyÉd²S§Nݾ}›‰)wïÞ¥iZþ©ªªêŒ3$‰¼oãÅ_Èò†>|øðñãÇËç´¶¶æåå1}?7oÞ¼yófvv6S<³ŸÏwtt”J¥YªRILL\¹re~~¾ªªêgŸ}öÅ_¨««³]7 ’Ôâáá!mƒ£­««ËÈÈ÷¦äå嵕¢¡¡áàà ßÇ‘#G*ÛŦ›G>§¦¦F¾G×®]+((¸|ù2sgïTSS³fÍš;wÒ4=vìØ½{÷:::²]—p>µüãÿ¸sçΣGNŸ>}úôif&ÓÀüvwtt|饗Ø-²+ 7oÞ¼víó{ýöíÛ­­­òO)Š6lX]]óc}}ýŸþiffÖØØÈçó•-²tJ[[{Ê”)S¦La~|üøqÛ‹\ìÖ6ÀN:õöÛoóùüuëÖ}öÙgjjjlÀ1œO-aaaaaa¥¥¥©m<|øð¿ÿý¯|t…AÛû\¬­­E"EQ\jmmmv·oß¾{÷nÛ˜¢¦¦fgg'ïM±³³SSSËÎÎNHHHLL<þ|iiiLLLLL !äå—_vÿ›™™ÙïKïèêêNŸ>}úôéÌm/x b=úè£"## !&LØ»w¯­­-ÛEpçS C$‰D"___æÇ»wïÊLFFFEEERRRRR’|y>Ÿoooïèèøâ‹/¶½¿ÆÀÀ ïÅ477·}J 3XµãøYBˆµµõ„ ˜˜booßqˆÃèÑ£GýþûïÓ4•••˜˜È$˜ââ⨨¨¨¨(Bˆ©©©‡‡“`LMMû¾ càƒãÀûý÷ßß{ï½û÷ïkhh„„„|øá‡***lÀUƒ$µ´#‘H$É‚ ˜ÿúë/&7È;9>|xõêÕ«W¯¶[QEEÅÔÔÔÈȈ¹=¸ãóÖ455;>¢­¦¦¦ªªŠI*=ê´*uuõ‘#G¶íò±´´ìùN(вµµµµµ ¤iúæÍ›L‚¹páŸþA133“÷Á¼üò˽<‚Ðg> úí·ß!S¦LÙ³g¥¥%ÛEpÛàL-í0)D~a‚ÒÐÐššš™™YVVÖö¹±?fîÝíËæTUUE"‘ü))&&&æææÖÖÖŠê] (j̘1cÆŒùàƒd2“`.\¸PXXXXXøïÿ›bnn.O0"‘H!›†žØ·oßêÕ«+**´µµCCCßyçNŒCPrC"µt¤®®îâââââÒn~kkkaaá½{÷¿ã#Ú˜i‰Dblllhh8ûÂãñÆŽ;vìØU«VÉd²7nÈû` öîÝK±°°pww÷ððpss366È ‡”{÷î½óÎ;'Ož$„̘1c×®]ºf ä†hjéŠŠŠŠ……………Û…ôÇ7nܸqã>üðÃÖÖÖ7n0#y“’’òóóóóó÷ìÙC9r¤¼Fio°âš¦÷îÝûÉ'ŸTWWëêênÞ¼ùÍ7ß cw RË ¥¢¢âàààààðñÇ·¶¶fdd0}0IIIyyyyyy»ví"„Œ5ŠÉëææ6bĶ«æªÂ€€€³gÏB|||vìØ8 pH-C‚ŠŠ s›Ò'Ÿ|ÒÒÒ’žžÎ$˜äääÜÜÜÜÜÜ;wReee%ïƒ>|8ÛUsƒL& ®­­544üñÇ-ZÄvQƒRË£ªª:a„ &|úé§---iiiÌHÞ‹/2÷XíØ±ƒ¢¨Ñ£G3ñÅÍÍm€GêpHnnîòåË/^¼HY¼xñ¶mÛp¬úR˦ªª:qâĉ'®Y³¦¹¹955•郹xñbVVVVVÖO?ýDQ” 3’wÊ”) y¤Í ÐÒÒ²yóæ/¿ü²¡¡ÁÈÈhÇŽÞÞÞl0È!µÀÿ¨©©Mš4iÒ¤Ik×®mnn¾zõ*“`.]ºtëÖ­[·n…‡‡Segg'ïƒÑÓÓc»jvdff._¾<55•¢¨·ÞzkóæÍ=|Q6ôR tBMMÍÙÙÙÙÙ988¸©©‰I0 —/_ÎÌÌÌÌÌüñÇy<Þ˜1c˜3eÊ]]]¶«MMMß|óÍ·ß~ÛÔÔ$‹wíÚõüƒí¢† ¤x>ŸÏ<ÛfݺuW®\aú`._¾|ýúõëׯoݺ•yfŒ<Á ÖŽ‡k×®½õÖ[·nÝâñxß~û­––ÛE !H-ðóçÏ?ÿ¼¡¡áÊ•+Ìó`®\¹’‘‘‘‘‘±eË{{{&Á¸ººêèè°]µÔ××ñÅ?üðCkkëÈ‘#÷ìÙãêêÊvQCR ô’ººº›››››!¤¡¡áòåËLÌ•+WÒÒÒÒÒÒ6oÞ¬¢¢2nÜ8æy0.../¼ðÛU÷FRRÒŠ+òòòTTTþùÏnذACCƒí¢†"¤PuuuBH}}ý¥K—˜sõêUæÍÛ›6mRUUupp`ú`\\\´µµÙ®úÙjkk×®]ûóÏ?Ëd2[[Û_ýuüøñl0t!µ€‚ihhL›6mÚ´i„ºº:&Á$$$\»vyÏö÷߯ªª*•J™ãì쬜£CΜ9PTTÄçó×®]û¯ý‹Ïç³]À†ÔýhذaÓ§OgÞ¶ýôéÓ‹/2}0©©©))))))¡¡¡jjjL‚ñðð˜úèwÞ©¨¨ÐÒÒÚ¸qc```»ËFÀ:¤P"/¼ðÂìÙ³gÏžM©®®NJJbžsãÆ .\¸p!$$D]]ÝÉɉI0NNN c;gÏžýõ×_óóó7mÚÔUøØ»wozz:3}éÒ%55µŠŠŠéÓ§ïÚµËÌ̬ÿöz ©””ŽŽÎœ9sæÌ™C©ªªºpáÓsãÆ f‚¢¡¡áääÄ<f„ òÃ|úÃ?ܽ{wß¾}ÇÇTUU­[·®íœÔÔÔÏ>ûì›o¾¡(ªÿwz©8@(z{{3/U~ôè‘<Áܼy3!!!!!¢®®îìììîîîèèx÷î]fÅ£Gº»»?~|ĈmüòË/ËËËÛÎyúôéÕ«Wj‡ 7Z€côôô|}}}}} !•••L‚IHH¸uëV|||||¼³³sÛå¯]»æäätòäI[[[fÎíÛ·þùçŽ-Ÿ;wn÷îݰРo¦¯¯ÿÊ+¯lÛ¶-33óÑ£G±±±ÇêþùçŸ...gΜa~\½zusss§ þóŸÿ,++ëߢ ·Ð×28}øá‡×¯_g» v¤¤¤tœY]]=sæÌ‘#Gª©©Ýºu‹¢(@ ®®Þî¿¿ÿÀ׬ ¶lÙbooÏvÝAjœ®_¿ÎŒH9š¦sssåÓ ì–¤TªªªØ.àZ3üõ =1”{æ€[Z3{{{www¶«e' Ù. G0¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©úÝøñãz¸pqq±»»{ß7š““CQÔ@®ØVÇ]¦(J(…B qãÆ]¹r…™Ÿ““ÓÇÍ H-п²³³ÓÒÒ222nß¾ÝÍb)))„ºººóçÏ÷zsòvÌÌ̲³³`ÅŽºÚå”””ŠŠŠªªªòòrgg瀀€¾l`BjþííímjjÓÍb………“&Mêûæäí++«X±£gî²––ÖÊ•+³²²ú²€!©ú‘L&‹‰‰Y°`ŸŸß¾}ûd2ùÿ/Áȧ—-[F±°°HMM%„$$$XYY ‚5kÖ0KFDDH¥ÒÉ“';99ݺuK¾n»%åíÄÄÄÈ·’››ëááa```bb²iÓ&BÈŽ;Fmhhøúë¯Ó4ÝÕŠR©T"‘H¥ÒŒŒŒ®6úÌ]¸xøðá :ÌC ­ ̈„„„E5½£$_ĹsçÁ“'O®^½J9þ!dÞ¼yK—.---}æF»ÙekkkBˆªªªX,~ã7>û쳞 €þ#“É233Ÿ>}Z]]ÍüeȨ̀(ÊÐÐPGGGSSs̘1<ž²\™AjþRWWS#¿àrèСü‘™¦iš¢¨ÆÆÆN×UWW'„ÈWÔÐÐ022 {æ’1µ½RÓÔÔ$•JƒƒƒCBBºß‹Ž«w³Ñ®v™Y>;;»#fú‚¦éëׯgee¥¤¤¤¤¤Ü»wér~¦#F;99999ÙØØØÛÛ÷ý^ËÞAjþrìØ1--­ŠŠ >ŸOÉÉÉ=zt\\sKpQQQSSSPP³°@ „<}ú´Ó¦¼½½×®]›’’2oÞ<Š¢ÊËË»ÚhÇvŒíìì6lت¢¢RVVÖÜÜœŸŸïééùàÁBHuuu§+š˜˜XZZ9rdÉ’%‡²°°‰D¹¹¹½ØåW_}µgÇ @ñ***þóŸÿ\¹r%66¶]1EQb±ØÐÐP___GG‡ù‹ÒÐÐP]]]YYY^^^TTtÿþýû÷ï§¥¥ýôÓO„>Ÿ?oÞ¼‰'úûûä¾ µ@‰ŽŽ b~B¬¬¬|||bbb^yå???KKK{{ûµk×&%%BLMM½¼¼¬¬¬Ž9Ò±)33³'N¬Y³&((HSSÓÌÌìÌ™3n´c;EÅÆÆ®X±BOOO[[{ÕªUkÖ¬ñõõ577_¼xñ²eË<==>|ØéŠX¾|ùúõëuuu<øÌ¿-ºÚe¤x>ܳgÏüqáÂùL‰Dâìì~ü˜¢®®þÊ+¯¼õÖ[Ó¦MSì0 š¦ãããýõ×ßÿýøñãÇ×ÕÕ]»ví‡~¨ªÚ/©`PinnNOOOMM½~ýú;w îÝ»Gÿ}oHGjjjÖÖÖ‰ÄÌÌÌÕÕU*•š˜˜ dÁÐw»wïÞ¸q#3ºöå—_þøãßxã ~Ý.EQÓ§OŸ>}ú“'O"##7oÞüçŸ~úé§›7o`† *R À`ššzöìÙÓ§O_¼x±ÝˆKUUU}}}]]]ùßܵµµ=ª¨¨xúôifffff&!dË–-„—^ziöìÙ3f̘1cFÿÚƒ¾;~üøÇœŸŸO‘H$ß|óÍ‚ øŸ^x!(((00ðСCk×®½{÷î|°mÛ¶~øÁÛÛ[Bjà°¼¼¼˜˜˜èè袢"fŽŠŠŠ­­-ó,i‰D"‘HÄbq7¿Ãšššnݺ•“““•••ššš’’RVV¶gÏž={öðùüÙ³g/Z´ÈÛÛ[~w (ÊÊÊÅ‹3w'ØØØ|ýõ×>>>lÝ“L¡(Šy2øñãǃƒƒ³²²|||þñìß¿____!›@jàžÖÖÖãLJ‡‡3W !/½ôÒœ9sf̘1sæLmmíž7Åçóäo)§iúúõë§OŸŽ?{öìï¿ÿþû↓X±âwÞ155í—ýçDÓôŽ;Ö¬YS[[«««»aÆwß}·Ÿ†’–™™éîîþÁ<~üØÊÊjß¾}¹¹¹|ðA{Vzhâĉ111yyy+W®TQQÙ¶m›±±ñ÷ßßÕû¿ ŸìرÃÝÝýþýûnnnׯ_wuue»¢qqqÉÈÈ`*÷ððøùçŸ{ÝR (‹ÂÂÂI“&)sËòvÁs½Q¨ÿv †‚æææuëÖ9::ž?^WW7::úöíÛþþþÿB;SSÓ]»våææ¾úê«555kÖ¬±··gn>‚þÖÚÚºzõê÷Þ{¯¥¥eݺuçÎ322b»¨ç`dd¿nݺ–––÷ßÕªU­­­½h©úÝŽ;Fmhhøúë¯3ÃÛ^a‘O/[¶Œbaa‘ššJIHH°²²kÖ¬a–¤(*''§í„¢ZŽˆˆ`n¸prrºuë–|ÝvKÊÛ‰‰‰‘o%77×ÃÃÃÀÀÀÄÄdÓ¦MVÕ¶€ŽÛèFNNÎØ±c7nÜØÚÚº|ùòâââ×^{Ý ”fff‡¾zõª¥¥evv¶T*ݶm[7σ¾knnö÷÷ß¶m›@ ˆŠŠúꫯ”ç%Ì=Çãñ¾úê«èèh@ðã?.^¼¸÷}uŠzÔ.Ƭ$”ê‹(**jmmež}TTTDÓ4sy…ùT>ÝnbáÂ…eeeqqq|>_¾dCCCÛ …´œššª««Ë¼¢=<<ÜÕÕµ«%;6(“Élll‚ƒƒ[ZZd2Ymmm÷Uuº-Ö)ÕÙ¢<”á°ÄÄÄ0®577ONNf±’NÕÕÕ­ZµŠùõ9mÚ4æÄî#e8ìʦ®®nöìÙ„aÆ]ºt‰íràòåË̉=kÖ¬ç}É€r 9†AI(FEEBêëë{¸VDD„ºººX,–‡qùEù„BZ>sæ Ç $„”——§§§wSC;¥¥¥YYY—.]RQQ!„0¯ä親n¶ÐMÓ_ýõçŸNyýõ×÷îÝ«¦¦ÆvQíihhlݺÕ×××ÛÛ;>>ÞÎÎî?þ3f Ûu *MMM¯¾úê©S§ ÿøãqãÆ±]‘899%''Ïœ93..î•W^9~ü¸ü¥³ÏĽ.&à–¦¦&©TJa~U·EÓ4!¤±±±Ó™GZuÿh,…´¬¡¡addÉ\{êa ÌG2™¬'Uu¿-¹úúzŸÏ?ÿœÏçïܹ3**J #‹œ»»{NNΤI“îß¿ïììüǰ]ÑàÑÚÚºdÉ’S§Nikk_¸papDƸqã.\¸ ­­ýÇøûû÷|Œ R ô¯ÒÒÒüü|OOÏBª««Éßi ¨¨(777((ˆY’y]ÅÓ§O»j*''‡ "Ì„¢ZöööÎÏÏOII166‰Dݼ5£c;ÆÆÆvvv6lhlllii)))é´*ùŠ=ß Y?ž2eʉ'´µµ“““ß~ûm¶+z6##£äää¥K—ÖÖÖÎ;766–튉¥K—ÆÆÆ … .<ל`ee•””¤««{øðá×_ýùVVÔÅ*\’TÊóE´¶¶úúú6lùòåË–- …MMM2™ÌÏÏOEEÅÑÑ‘ùŽYÒËËK$]½z•t›BÓ4!$;;[>¡À–Ïž=ëèè8bÄssóéÓ§Ó]Œé´ÜÜ\WW×aƽøâ‹ß|óM§UÉW|òäIÇm±NyÎ¥ÂÊa©ªªrtt$„˜šš2g;‡Èd2fÜ:Ç‹ŒŒì]#8å¶nÝJQUUcYºrùòeæùx[¶léÉòH-ƒ¾è9œ-øÃòäÉæù—^z©´´tÀ¶«X¿üò !DEEåàÁƒ½Xg##!!ÇãQuàÀ¶kéw¤(ŠÇã;wî™ ã ûZZZæÎ{ùòe±X|åÊccc¶+ꥀ€€ÖÖÖ×^{íâÅ‹l—ÃI¥¥¥~~~2™ì‹/¾X¸p!Ûåô» |ùå—2™lÁ‚%%%Ý/ŒÔÀ¾   óçÏkkkÇÇÇ›˜˜°]NŸ¬_¿þí·ßnnnž3g†œ?¯––ÿŠŠ ///æ&²¡`ýúõ³fͪ¨¨ð÷÷oiiéfI¤–mß¾}çÎgΜ‘H$l—£?ÿüó¼y󪪪æÌ™ÓÐÐÀv9\š””dll5tÞwFQTdd¤H$JNNþöÛo»Y©€M©©©Ÿ|ò !$22râĉl—£</&&f̘1¯½öÛåpÆ­[·¾úê+Š¢~ûí7e~'b000øí·ß(Šúúë¯oÞ¼ÙÕbH-¬yòä ó\ó>øÀÏÏírI]]ýèÑ£:::‡îËÛò†š¦ß|óͦ¦¦wÞygòäÉl—ÂI“&½ûî»MMMo¾ù&ÝÅ;"Zz©®®.11‘í*€Û>ùä“üü|‡ï¿ÿžíZÏÌÌl÷îÝ„O>ù¤  €ír”Ý®]»ÒÒÒD"ÑæÍ›Ù®…5›7o611IOOgnFë©”Eqq1sÓã€iûªÅ^(..öððÈ- sþüù={öðùü ÖGúùù-]º´¾¾>  «¿žòøñãuëÖB¶lÙ¢¡¡Áv9¬QWWß²e !dýúõ=ê¸R °¬±±1%%…RWWwþüùÜ´™™ó¹A¼EPZ2™ŒùE¾nÝ:KKK¶ËéG?üðÃðáÃÏ;Év-Êë믿®¨¨ððð˜?>Ûµ°lÞ¼yÓ¦M«¨¨øúë¯;~ŠÔ,+,,dž¬5ðÁ?${à·JkÛ¶myyy#GŽ\»v-Ûµô/}}ý~øò¯ý«›Wv eýõ׎;(Š g»¥°}ûvŠ¢vìØqïÞ½v!µ@Ù±cÇèÑ£ _ýu¦g¸íõùô²eË!©©©„„„+++@À<œBQóÈf‚Y144ÔÚÚš!•J'OžìäätëÖ-f•¼¼oÁÝ´Ù½’’’;wî0W£çÍ›———WZZš””4jÔ(}}ýçÚY žBHrr2ÝÙ zCDbb"Ajéæ(1G ©` \¹r…âììÌv!ì³°°044|øða»'0 µµµ·oßVSS›0aÛµpÀøñãù|~vvvMMÍà×(ô“¢¢¢ÈÈH¶«¢LMMß|óM¶«€ç“••E3f Û…(…qãÆ>}:++K"‘°] ®_¿.“Éìííù|>Ûµp€ššš]ZZÚõëבZ —ŠŠŠ¾üòK¶«¢ÜÝÝ‘Z¸E&“eggSeccÃv-JÁÆÆ†I-òX)„¶ á ‡´´´ôôt¤è±XüÆo°]ÅòçŸvòpkPz%%%uuuFFFx·ÃÚÚš’——Çv!ì`îúÆszŽ9V¹¹¹H-Ð'b±=.)11©…‹þúë/BˆH$b»eÁŠ{÷î±]; !æææl„üü|ŒÆèwLj122ê~1Š¢„B¡P(ÔÐÐ7n3†—1~üøv×(ŠÒÓÓknn–Ïñõõ¥(ª]³qqq:::fffß}÷]ïö"''§cã½Ãв²2…´Æ9ùùùäïßÄÐLÂ+((@jèw>$„Œ1â™K¦¤¤TTTTUU•——;;;0ó³³³ÓÒÒ222nß¾Ývù'Ož0Oß"„TWWŸ9s¦]ƒ555óçÏ )//¯ªªŠwrrêÝ^˜™™1o$í»_|‘òàÁ…´¦„[[[»ú”I±&&&X·½üòË„¿þú © ßÕÕÕB† ÖóU´´´V®\ÉÜyD‰ŽŽööö655‰‰i»ØÔ©Så/–;zô(ó(”¶***êëë'NœHQEQ‰ÄÍÍ­w{!¬¬¬z·n;Ì›¹êëëÒšzðà±±ñO?ýÔ¶'ŒQ[[[__?lØ0¼ž¬ç444´´´Zú]CC!DCCã¹Ö*..>|8!D&“ÅÄÄ,X°ÀÏÏoß¾}2™L¾ŒŸŸßÑ£G›šš!\´hQ»FÄb±«««‹‹Ë®]»ÊËËÛ~!•J'OžìäätëÖ-ò÷5 ÐÐPkkë9sæ„……1K;vlæÌ™m¯åææzxx˜˜˜lÚ´©ÓÖºÁЧOŸ†……mß¾}÷îÝÑÑчª¬¬$„dff^¹r对¹¹EEE÷ï߯ªªª¯¯çÐSéþÿ±wçñP}ÿÀÏŒeȾµ ¬•¥Ý(-¾ñiÓBöTD‹´(ÚTŸvmŠD{$DY³¤ä“í i!Y+EYÃXæþþ¸ßÏ|ýcî ïçŸ3÷œûróáížsϹ7qâÄœœœö£?$éöíÛžžžÇŽ[»v­¡¡á‰'TTTÒÒÒ6oÞœ““#--}öìÙuëÖ=zôoR]]’’’°oß¾-[¶H$FŸ†™™™ß½{—L&×ÕÕuÒ[‡xyyI$Nß¶m[ûwœœ:lE"‘øùù)Š€€€€€@'tþnçððð0ùÏÔ ¼NEåææZYY¹»»»¹¹Íœ9!TSSƒbíÓdÉÉÉjjjuuuAAAóçÏŸ1cþ>¶ˆaØû÷ï544Ú4AÕÖÖîØ±cõêÕoÞ¼aa$–EPµ@¯ÊÍÍõôô¼téB¿#Ò9ü‘`^^^|Y;v „‚‚‚æÎ+""B¥RƒƒƒU ©©iDDDII‰©©i‡³e…„„öìÙ³{÷îW¯^íß¿___?///11‘L&;::"„ÊÊÊ^½zÅ8ÞÕÕ•——×ÐÐpõêÕ)))ƒ~óæ¡¡!þä B¨¤¤$33óÙ³gø/x!!¡NzëPss3~ûaܸqÓ¦M£Ñh <(//3fŒ  `ÿïÒþU]]ýÇ+Ùm|||=¬{***Z÷™––6kÖ¬Ù³g=zŸïB¡PXž|À€>|8|ø0£jÁÇ_¿~|äÈ‘ö­ð±È .°<káW ªè)))îîîQQQ---x1ÁÌ4ެ¬¬6sGêêê"##kjjIDDÄ©S§ðOÍÍÍMMMóòò<==;é™D"iii…††  ÊÊÊ2Æ€ZãååEQ(”%K–ÈÈÈØÚÚòññµî !Ôz ª“Þ:ĸ999‰‰‰ÒÒÒø§úúúIIIÞÞÞzzzí[aÖØØØ¦Žaþ&kjjjjjÂïˆt[‡‹ ß¹sçîÝ»ø^€½Qµà.\èë닌-º¹¹ >üêÕ«‡"“;˜Â‹ÄaæààÏÏÏ?wîܳgÏ"„Μ9ÃÏÏO§Ó/]º4jÔ¨ììluuõ£Gª¨¨èéémݺ!{îܹþù§ó&]Ù U °†a·oßvwwÇ7{à <øëׯøœÜ®Š.//ǘ²³³544âããMMMñtuuùøø¾|ù2a„>´i^RRabb¢  €JHH‘‘‘——722Ú¹sgrr²™™‰Dj3åggg7kÖ,‘6Ã=rrr£G>pà€››Ïׯ_™é­µ_¿~!„(J]]Ý™3g˜\ö‰D"Q(”Þû}kjjêaÝC£Ñ(ÊÛ·oÛwÎÏÏߥIÙÝ %%ÅøNëdl×f,WPPàëë[VV&--ß ìÆxâ›tõëÂke¨Z€5šššBBBÜÝÝÛÏEUSSûúõkiii7º Ú°acNŒššÚÂ… ƒƒƒU //o``   `‡ÃC %99ùôéÓ?~üàãã1bD\\…BQRRŠ‹‹Û¾}û† „„„”””Ú?5­¥¥%''7tèPEEÅÖ¯“H¤ÈÈÈU«VIJJŠˆˆ899íܹ󽵆?ó,''÷éÓ§³gϺ¸¸ôöïræññññññ‰ˆˆô¤“›7o†††¶~E\\|íÚµ7n,..¾qãFëYÌß*++2dþq'c‹ŽEâäåå'Mšd```ccckkËÏÏßñÄ'NtÞ¤«_~Å jÖxñâźuëð»mhkk?xð_¥£>#ßæ•èèè6ÇÏ;ÿ@MM­M'222aaažnÆŒ©©©­_iÓœD"µ®ÀZ¿;bĈ67`Ú÷Ö üR¨ªª8099ùòåËø¯·>ƒ1!$//ïìì¼zõj¼Âï齪%..ŸöÛùØbû±H>>¾'Ož$%%ùúúž>}:33³ã‰lÒUøƒ'Ÿ€5¦M›öòåË#F´ Ÿ¥QRRÂîLœ ¿rrr...!OOÏææf¢C±^µhhhøûûçååmÙ²…qóFXX!ÔŠëëë/^¼´gÏôïØ"FÃ0 𬬬ªªªöEp{555ååå3gÎôööÎËËûþý»‘‘Qnnnrr²œœœ¼¼|‡ƒtvvv!!!þþþööö!fšt ~Å j–ÑÐÐxñâ>Ý’AHHhÆŒ øúõkUUQÙ8 >sĈ .1bD~~~dd$Ñ¡XI^^>666##ÃÎήÍïøº#œúó;:::ÒÿbìJ¦££#%%%''wûöí‡âëßÿnlñ§¨®®ž3g޲²òĉ÷îÝ;tèP|<ÑÍÍMVVVUUuÉ’%í[á㉚ššøx"3Mº¿G#DÀJïÞ½{úôéôéÓ=z„§hiiñóó«««§¥¥effN™2…èŒÄÃ×üÕÔÔ$“É[·n]½zµ»»{û%ò¸W‡Ï@áDDDýúUWW×ÕÙ<Ž!þnñ=fÆ;$''×~í–®Ž'2Ó„yõõõµµµ îµË”””XXXÐh4mm툈|,`Ò¤I!MMM„P‡Ï•ôCéééèßkbcc3xðàW¯^µ_Ôµ¯ÂgË„kàCв²²PµÎUTTÔÉß+œÐ3 ·À}@CCƒ©©é·oßfÍšåææffföüùsUUU¼jÁÿûôéS¢c/77·¬¬làÀJJJ!7"„ðúÆÆDáø.Ù***PµŽC£Ñ’““Buuu>äÀžýtu \FCÐ'­]»6%%EYY944_4vÔ¨Qúúú!]]]„ÐãÇ NÉž!«õ ããåË—#„TUUñi\®ƒot0räÈöo-[¶ ÿ•Ôç¿«ªªÈd2…Bill$: hjj¢P($©²²ž|ì#..~åÊ•üü|ÄÜ6r¸€€EEEÆ~¹ŒAÆ,鹓%«Ûgh£ý¸§êê¹€cÕ××›šš~ÿþÝÀÀàðáü`Á~~þ'Ož”——3ö ìoÂÃÃBÆÆÆíßÚ¶mÛ•+WPï¬ÀÆQDEEGŽ™•••šš £Æ”––F£ÑÔÔÔÄÄÄ`„°Icc#•JEµ_·Ã0ôûõ­ñŧ;yT‡U=3ÖŸöðð ÄÇž˜ÌÐ~ ÜNRu~.À]ð]âTUU¯]»†×¬644lnnöóócOG¿{ :Ǹnj`m\À6%%%¹¹¹ø®iø ¡x5PPPðáÇ 6àGâ ?w¸™ .;;/DðXÕ3óëO·ï‡±.Fknn...î0£!Ë׺„ðòò ŽŽŽ–`¦ÉŠ+B~~~X·ÖÚâvÑÑÑÚÚÚ£Gîð€¡C‡â‡1Ó”K1† ‰Âîß¿þ­ó jl¢¨¨hll¬¢¢âååµ|ùrƒ¦¦& ‹áÇ/]ºÔÉÉ ?RAAaîܹjjj555v¥®®Ž»à°ªgæ×Ÿnß¾nZZ𤤤¼¼|ppðïRá ¥¥¥Y»Ö5`¿û÷ïoÛ¶D"Œ5ŠÉVC† ùøñã;wz5g:}ú4BhåÊ•¿;@\\!TYYéïïϾXD˜1c™L~üøqŸ롚ššG‘Éä3füïUVM™i}‚3gゞƒÙ¸lÓùe)((À'¦üý÷ß]íùرc!}}ýžFä6ø"IÒÒÒ¿~ýúÝ1ŒåUTTš››Ùý¦OŸŽ !:GÃw,ÿÏþƒ ÷Z kêêêLLLÊËËçÍ›wðàÁ®6_³f˜˜ØƒÚoõÒ·á嚣£ã7ß‘——ÏËË»~ý:[rŸ’ÌØt(** µš¾ U t½½}zzúðáï^½J&wù§¨¨¨èºuëB›7oî…têñãÇñññ"""[·nýãÁ–––¨,ðoiiI"‘âââ*++‰Î¡ªªªnܸA"‘ðo U tɉ'®]»&""ƒOÂè†mÛ¶IJJÞ¿ÿöí۬Ǚ0 Û¶mBhëÖ­øº›3gΠAƒRSSñi˜}•¬¬ìŒ3êëëñAÐ^XXX}}½¾¾¾œœþ T-À¬»wïnß¾D"jhht» ‰Ý»w#„œ›››YC]»víÅ‹C† Ù²e 3Çóóóãþ?~¼—£ÌÎÎ!tîÜ9¢ƒp(üÊ૊ã j¦äçç[YYµ´´ìÞ½ÛÄĤ‡½9991"''çèÑ£,‰Ç±~üø…9r„™-¸µk× ß¹s§oÏþ155ûöí³gψÎÂqž?þæÍ111333Æ‹PµÀŸýúõËÄÄädž††û÷ïïy‡d2ÙÇLJD":tèãÇ=ïcmÞ¼ùû÷ïýõ—­­-ó­$%%W­Z…aXßžÝ"((¸~ýz„ÐÉ“'‰ÎÂq¼¼¼Bëׯd¼U ü†a+W®|óæÍÈ‘#ƒ‚‚º1·CÓ§O_µjUcc£••ÕïVpævW®\ÄK´.µÝ´i_xxxaaa/Åãëׯçç玎†ÍÀ[+,,ŒŠŠâççÇ«:¨ZàÜÝÝÃÂÂDEEcbbÄÄÄXس‡‡‡ªªê«W¯\\\XØ-‡ÈÏÏ···Gyxx¨¨¨tµù°aÃ-ZÔÔÔÔ·ïC 2ÄÎή¥¥e×®]Dgá »wïnnn¶µµ•••mý:T-Йþùçï¿ÿ&“ÉAAAŒ ;YETT4$$„ŸŸÿÔ©S¬íœX ÆÆÆUUUfffø“ÞÝ€¯>ìçç÷óçOÖÆã(»ví¢P(¡¡¡999Dgá?~¼ví…BÁ'­·U üÖ—/_–,YÒÒÒ²wï^##£Þ8•Jõðð@ÙÚÚ¾xñ¢7NÁ~t:ÝÚÚúíÛ·***ÁÁÁÝîg̘1sæÌ©­­íÛOÙ 6ÌÞÞžN§3¶é眜œètúªU«† Öæ-¨Zà·öìÙóóçÏ… îÝ»·÷βaÆ5kÖÔ××Ïš5ëÓ§O½w"¶Y·nÝõë×ÅÅÅoÞ¼‰oeÚmøØÙéÓ§ûö~Šûöí“HHHˆ‹‹#: ÁnÞ¼yûömqqñ}ûöµªø­OŸ>©««_¹r¥«3I»êôéÓÓ§O¯©©™1cFqqq¯ž«·•Jýþý{`` Kâq&iié „6nÜØØØHtÂ466nܸ!´ÿ~™öð²=èS Xò(`Rß~˜‚£!„„„„bbbDEE{ût¼¼¼qqqsæÌyþüù¤I“RRR‹rŸ½{÷òððO:•%}º¸¸XZZž8qÂÞÞž‡‡‡%}r õë×ûúú¾{÷nûöí}{r'vîÜ™ŸŸ?jÔ(|™ÁßbÕÞŒ°y,‡`۞π°çso‹Ço®=z”ç­¬¬ÔÒÒB)((dee±óÔ=G§Ó·oߎ"“ÉÝë¤ÃïÆææfü¤ˆˆå`iii|||d2ùåË—Dg!@JJ ™LæååMMMýÝ1p¯t“¢¢b‡ƒŽ\!00°  ÀÖÖVQQ‘è,ÝÁ¥±¹ÅÇ—,Y‚aBHGG‡§KLLœ={vjjêĉïÝ»§­­ÍÎÝF§Ó—/_~åÊ>>¾k×®™››³°sž-[¶¬[·ÎÝݵ=sš &lß¾ýСC–––¯^½’ :ûTVVZZZÒéô;vàµ{gXU(Ámþ!:×§5¸­UWWkjj"„ð1uB.K]]¡¡!BˆŸŸÿÂ… ìÐUŸ?žxðà§OŸÎ™3§7Î"((èèèˆúÁ~ŠüüüaaaâââÑÑÑ}{7ƒÖNœ8%..ÆÏÏßÉ‘PµÀ>|8**JBB"&&†ØYŸ$iÏž=ÁÁÁ  RWWúô)y:T__ïìì|ø`mmÿèœ;w.ÑqþGMMíÍ›7»víâááñóó6lXpp0†aFÊÏÏ733›8qâÇÕÕÕSSSœœz{=ܦM›xyyCCC¹}IfìܹÓÌ̬±±qΜ9YYYDÇéYYYsæÌill455ýûï¿™iU  ¿«®®611©ªª²°°ÀŸÝå(|||‡JKK›>}zEE…††Æµk×èt:›“®^½zäÈ‘QQQ"""ÇŽ{ýúu¯Ž µ¡¨¨hiiÙç÷Sd Y°`AyyùÔ©SûƢɭåççO:µ¬¬lþüù¡¡¡L¶‚ªЯÑéôeË–eee=Úßߟ=÷ ºa̘1III§N’¡æªÀ IDATÈÎÎ^ºtéÈ‘#O:USSƳ¿xñÂÚÚzĈ¾¾¾---NNNŸ?vqqé|âdoÀ÷S¼téREE›OÍ~|||ááázzzºººïß¿':˼ÿ^WW·¢¢búôé|||L6„ªЯvìØ¶mÛº×T-€~‡N§[[[øðaìØ±~~~\÷7k‡¨T*•JݱcGSSÓ«W¯RSS_¿~ýñãǼ¼¼ÏŸ?ûöíÛ·o6äããSWWWVVVRRÒÕÕ¥R©C‡esø®277WVVÎÉɉ‰‰ÁW‚ï'¶nÝ:~üxKKË„„„ñãÇ߸qc„ D‡ú³ôôtCCÃÏŸ?KJJ†‡‡Ï˜1£Û]AÕèwöïßóæM))©èèè‡Åøøø&Mš4iÒ$Æ+MMM?~ü¨¨¨(//g¼($$$!!1hÐ n¼<<<›7ovtt<~üx¿ªZBø2ÄÏž=£R©Ë—/÷ôôäÌ[b¡êêêÍ›7_¾|ðɓ'GFFÊÊÊö¤C¨Zú²ÀÀÀ¤¤$¢Sp¢‚‚„P@@\ôïÕè?¢££:„/VöÇåÃû>>¾Áƒ<˜è ¬´|ùòýû÷¿xñâÑ£GÿùψŽÃV²²²=òôôÜ»wïåË—oݺuäÈ;;;Ž,£Óéÿýwii©€€À¶lÙ²2Xµm#lË!ð˜×Oþ·ÍÌÌÄÙ=qâDçGÂO3Bté²ïß¿!4þü^ʾ|ù2uêTüa*•š˜˜Ht¢ÿJLL¤R©x°)S¦|ùò…U=ý–¾ÉÖÖvúôéD§à\¶¶¶ŠŠŠDgáýáRTVV×ÔÔ,]ºtóæÍDÇ=µ~ýúãÇÇÇÇãÛt‡C† yüøqhh¨‹‹Kjjê¬Y³FuäÈCCC¢"ݼysçÎ!yyùcÇŽ-^¼˜õSÇXUÁ_'€+À7j?ÔÒÒ2oÞ<„ÐøñãýúõÇãᛄ]½ìŽŽŽ![[Û^ÌÄ jkkÝÜÜ$$$ðßéjjj~~~uuul PWWççç§®®Ž?zôhmm-ËOÄAc`Ð{öìÙ/##Ó'gàö[›7oæåå )))!: ‘„„„¶oßþõë×ýû÷ ggg¯\¹rРAöööOŸ>íÕS?{öÌÞÞ~РA+W®ÌÊÊÞ¿iiéŽ;zc±i¨Z}_ddäÑ£GyyyÈŽXFIIÉÜܼ±±ÑËË‹è,Ä£P(ûöí«¨¨ š9sfMMÍ¥K—¦M›&))¹jÕªØØØ¦¦&–œ¨©©)66vÕªU’’’S§N½téRMMÍÌ™3¯\¹RQQ±oß> …Â’µóZ}\FFÆòåË1 óððÐ××':`±mÛ¶…††úúúîÞ½[\\œè8Äãååµ¶¶¶¶¶.,,ôññ ÉÏÏ÷óó×&5jÔÔ©SÇŽ;fÌ•Aƒ1Óç·oßòòòÞ¾}ûæÍ›gÏž½{÷Ã0ü-EEÅÅ‹;88°çï¨Z}YEE…±±qmmí²eËœœœˆŽXo„ 3gμ{÷î… vìØAt¢  pøðáÇ¿{÷...îåË—7oÞ|÷îÝ»wïÇðòòª©©ÉÈÈHII‰‰‰162lhh¨¬¬üñãGYYYvvvsssëžyxx,X0qâDCCÃÑ£G³ó‹‚ªÐgµ´´,^¼8//J¥^¸pè8 ·¸¸¸Ü½{÷Ô©S›6mê½± î5zôh¼¶hiiyþüyfffrrrrrò‡š››ñç}:G"‘FŽ©££££££©©9yòd–­¼ÒEPµú¬]»výóÏ?ŒŠŠbü úžY³f?>===((hÕªUDÇá\<<<Ó¦M›6mšƒƒþÊÏŸ?³²²~ýúUUUUVVF§Óñ×Éd²ŒŒŒ˜˜˜ººº¤¤$q©ÿ¨Z}SXXØñãÇñ=ç8cÐCÛ¶m[²d‰‡‡ÇŠ+8j‰X‡O§%:EÀ?- zóæÍÊ•+1 óôô„û EEÅ>ܸqƒè, AÕèk~üøabbòë×/;;;|2Ðçñòòâë?~œè, AÕèSZZZ¬¬¬òóó'Nœxþüy¢ãöY±b…””ÔóçÏŸBBBëׯGp»¥OƒªÐw\»vÍÃߟ?22R^^žè8€Ý póæÍ÷ïßô x†¨ (,,$:Ç)(( :`½ôôt{{{„——×´iÓˆŽ ##cggwîÜ9Ë—/°T-}\```RRÑ)èuåå妦¦uuu+W®\»v-Ñqa¶lÙrñâÅ«W¯hãÆ±±±>| : è2¨ZœâóçÏ[¶lY²d Ñq@ß4hРeË–ÑétX´AÕà ¦¦¦¥¥¥3gÎtss#:è˶nÝJ&“ƒ‚‚JKK‰ÎºªGX·nÝË—/•””BCCa.èUÇ711ihh8uêÑY@×@Õ ÞÙ³gýýý…„„¢££¥¤¤ˆŽú>|ÿóçÏ×ÔÔtT- ×ikkO˜0Ƀ‹ŠŠôôôz~Òììl‰ÄΆ 7oÞœ6m𤤤¸¸øÐ¡C­¬¬zÒ[ðèÑ£M›6‘H$??¿±cÇô “&Mš>}zee¥¯¯/ÑY@@ÕzWVVVZZZzzúû÷ï;9ŒF£áË'ÔÕÕ=|ø°Û§cô£¤¤”••ņ†m\¿~ÝÚÚzëÖ­ß¿¯¨¨xò䉡¡a—z`$醞´%Jqq±……ESSÓ¶mÛ-ZDtÐ0öSljj": `T- w)((wrX~~þäÉ“{~:F? EMM [Ã0l×®]nnnÆÆÆ¼¼¼$IAAaéÒ¥]ê¤'—‚U—‘mð¸ß¿Ÿ={ö‘#GˆŽú—yóæ5ª¸¸8$$„è,€YPµ€^D§Óƒƒƒ----,,®^½J§ÓÑÿ‚a|¼|ùr„ªªjjj*BèÁƒjjj eûöíø‘T*uÊ”):::Œ¶mŽdôÌ8ˇôõõ¥¥¥‡Š/þüy |µ¦§§S©Teee*•šžžþ»“2”••}øðÁØØ¸Ã«Ádom’¸¹¹©««w˜¹ý—ÆhÛã:6qppHMMUQQ ááá!:è_û)º»»Ã~Š\c|FƒXÕ!è¡ÞøyðàBHOOïGÞ¿ŸB¡TWW¿|ù!ôðáC ÃðñüÆÇm>X´hÑׯ_ãããùùù1 KMM•(++Ã0ìÌ™3ººº¿;²}‡t:]SSs×®]ÍÍÍt:½¶¶ð‚‚‚––ü¡Ç‚‚‚ß5>|x`` †aW®\1bNïð¤ ÙÙÙ¡¦¦¦ö—‚ùÞÚ$Ù¹sgMMM‡™Ûi­¯mÏÿùz›··7BHXXøíÛ·Dgéü4#›/{cc£¼¼)))ÅÅŹ¹¹ÉÊʪªªv²CMû~H$RdddZZ𤤤¼¼|pp°¢¢¢±±±ŠŠŠ——×òåË ššš:lêáᡬ¬|æÌ™°°0fÖqY´hѵk×|}}¥¥¥……… ð ƒùÞ:¼fnÿ¥1Úþ1'ìíí_½z5|øð«W¯’Éð#ÏÉɉB¡DGGüø‘è,€9¬š&ó×8 ±³q"öŸ¿ó$""’‘‘AHæÁO3BuÙíííBl>/è*øCÀ&÷îÝÛ¾};‰D ÐÔÔ$:ÿ³eË2™ˆÂŽU èØïæÉÐ=VVVÍÍÍ»ví255%:ÿÏÈ‘#.\ØÐÐpúôi¢³€Î@Õ:öüùs}}ý¤¤$¢ƒ€¾ ®®ÎÄĤ¼¼|Á‚ :Àø?wî\mm-ÑYÀoAÕ~+))I__jÐs«V­zýúõˆ#‚ƒƒa.àL“'OÖÕÕ­¨¨¸téÑYÀoÁðP»€rww ‰‰#:¿…ßn9yò$ì§È±`mÜ~¡´´´   KM~þüÙúÓ¤¤¤¤¤$==½}ûö±2èëwîÜI"‘®\¹‚o¨ÇZ°`††Æû÷ïì­­‰Ž:UK¿°xñâ®67n\ûñÚECCƒ¡@ß÷éÓ'++«–––}ûö-\¸è8ü¾ŸâŠ+ÜÝÝ—.]ÊÌM€Í jé㬨¨Ø†’’’¾...®­­ýþýûÅýÀ¯_¿LLL~þüidd´wï^¢ãÀ”¥K—îÙ³çíÛ· sçÎ%:h ª–>.$$¤{ “’’îß¿ßúqqq'''ggçׯ_v©·€€€ÂÂÂî%ÌSPP°³³#:Ba¶bÅŠ·oߪ©©Á \À-øùùœœ\\\ÜÝÝ¡já@Pµ€?cÔ+øžÆÝ“yÙ@OOCª–cÇŽ…‡‡‹‰‰ÅÄÄˆŠŠ€.ppp8|øðƒRRR´µµ‰ŽÓS/_¾ÌÍÍÍÍÍ-**úöíÛÏŸ?«ªªx“H$III111QQQ•aÆÉÉÉikk«ªªràT- 3=¯WZ³³³SPPèy? ½Â€€¢SüWBBÂîÝ»ÉdrppðÈ‘#‰Ž@×ˆŠŠ®Y³æØ±cîîîáááDÇéŽÌÌÌG=zôèÍ›7YYY<þË—/í_$“ÉT*U___WWWWW—Cþü€ªtLXXxß¾}›7ofáwª­­-¾É`¹¤¤$©Zrss—,YÒÒÒâêêº`Á¢ãÐ7nôòòŠŠŠÊÍÍUUU%:S0 ûçŸnݺÑz_^^ÞqãÆ3fذa rrrââââââBBBø­ Ã~üøQUUUSS““““]\\üöíÛâââ—/_¾|ùòرc¼¼¼úúú†††¦¦¦rrrÄ}•Pµ€ß R©T*•è€ËÔÖÖš˜˜TTT˜˜˜ìÞ½›è8t“¬¬¬µµµŸŸŸ§§ç¹s爎óÙÙÙ—/_(++Ã_2dÈ_ý¥««;}útf6—••Å?h=•§¢¢âÅ‹ø=›gÏž%&&&&&:;;Ïœ9ÓÞÞÞÔÔ”ùjPµXÃ0;;»ŒŒ ÀÀ@€y[·nõ÷÷Ø¿ÿÀ‰ŽÓ:~ûömooï»wïb†]¹råâÅ‹©TjÏÿ”000000@ÕÖÖÆÄÄܾ};,,ìÎ;wîÜ‘‘‘qppX·nÝ!CXðÅ0 &öXãÈ‘#ׯ_‰‰!:=¢¦¦fhhX__æÌ¢³´…aØõë×ÇŽ»`Á‚ÄÄD{{ûçÏŸWUUyzzjkk³üoaaakkë«W¯VUU]¸pAKK«¬¬ìСCJJJŽŽŽŸ?fíé:U €nݺµwï^2™|õêÕáÇÀø?{öì¯_¿ˆÎò?™™™ãÇ777ÏÈÈ:t¨‡‡ÇÏŸ?}||tttØpv!!!‡ÔÔÔÇÑh´³gÏ*((899ÕÕÕ±!T-€žÊÉɱ¶¶¦Óéœ7oÑq`©S§N:õçÏŸ~~~DgA¡ÂÂBSSÓQ£F½yófèСçÏŸÏÍÍݲe !·6§M››™™iii‰aØ©S§.]ºD§Ó{õ¼Pµz¤¦¦ÆÄĤ²²ÒÜÜ|çÎDÇ€•ðÛ-žžžÍÍÍÆ ÓéÞÞÞÑÑÑBBBnnn?~\³f ???©Baaa¯_¿ž8qbyy¹½½½žžÞÇ{ïŒPµºðeË–½ÿ~Ô¨Qþþþ0ô1†††êêê………aaaDeøôéÓˆ#œëêêV­ZõùóçíÛ·S(¢ò´7zôè/^xzz0àñãÇ£Fòòòê¥sAÕ较ÆÄÄHHHÄÄÄ #“É[¶lAyxxàÏé°YTT”––V^^ž¬¬ì7|}}ÅÄÄØƒ›6m*))Y¶lYccã¦M›Œ+**X~¨ZÝwàÀž¢ãÐ+¬­­eee_¿~}çÎvž—N§oÙ²ÅÌ̬²²ROO/##ÃÐкABB"00ðöíÛ¢¢¢±±±ãÇ/..fí) jtGvv¶ N?|øðœ9sˆŽ@o¡P(NNN!www¶´ººÚÐÐÐÓÓ“ŸŸßÛÛûþýûl;{¼}ûvâĉ………±±±,ìª@—UWW›˜˜TUUYZZº¸¸€Þåàà **zïÞ½´´46œ®²²rÊ”)ñññ222÷îÝÛ¸q#×ÍSPPxüø±­­-¾^ö… XÕ3T-€®¡Óé666ÙÙÙcÆŒ¹|ù2×ý< «ÄÄÄ[n·P©ÔÌÌÌ‘#G¦¥¥M›6­·ÏØKøùùþþûo ÃÖ®]{ðàA–t U  k8pãÆ )))ü!L¢ãÀNNNüüü‘‘‘Ÿ>}ê½³äææŽ;6//O[[ûÙ³gC‡í½s±ÇáÇýýýyxxöîÝ»nݺžwU ÿUWW—””Dt NsðàA|®²²2Ñq`99¹¥K—¶´´xzzöÒ)JJJfÍšU]]=eÊ”û÷ïKJJöÒ‰ØÌÎÎ.66–ŸŸÿüùó‡êaoPµ.F"‘²³³YÕ[QQ‘¾¾~ûS໺‹ŠŠêééݽ{·}Ãììì~2JòþýûeË–aæææ6kÖ,¢ãÀV[·n%‘HþþþŒ­•Y¨¼¼|Ê”)“'OþçŸúØ:óçÏæááÙ³gOPPPOº‚ª€?HNN®¬¬,--]¼xñüùóïÝ»×æ%%¥¬¬,B²±See¥‰‰IMMÍâÅ‹·nÝJtØMCCcÁ‚uuugÏžemϦ¦¦ÅÅÅcÇŽ½uëV+Yp>>>$iùòå7oÞìv?PµÀ”888¬_¿þðáÃmÞ¢P(jjj„¤b:nmm““3nܸK—.bôÒ~Š?–——OHHà¢'œ»jÅŠ®®®---K–,y÷î]÷:ªô5éééT*UYY™J¥¦§§ã/~øðA___ZZzèСøSçÏŸ×ÐБ‘±±±a~ÉË… ¦¤¤ G…ÜÜÜÔÕÕ#D ,ðððÀŒÅW1  R©S¦LÑÑÑÉÈÈhÝ–Õ_z/Ú»wï­[·¤¥¥£££ @tˆ¡««;yòäòòòË—/³ªÏ3gÎ ÅÅÅ <˜UÝr¦]»v-]º´¦¦fáÂ…ÕÕÕÝèªЧ`¶+k?$«IDAThÑ¢7~úôÉÉÉÉÊÊ Ã0 ÃÌÌ̦NúíÛ·¢¢"|û¼yó222222‚ƒƒ‹ŠŠ˜ì_JJªõnìÕÕÕxƒ³³³ó÷÷Çk ‡´´´Í›7'$$<{öÌÆÆ¦õúîýKˆëׯ9r„——7,,LQQ‘è8 ¿ÝròäI–짘––†·FDDŒ7®çr8‰tåÊ--­üüü•+Wv£¨Z@ŸR\\üñãGsss„™™YNNNIIIIIIff¦‹‹ ‰DÂÖ¿råʹsçBõõõLö_VV6dÈƧ®®®­G  ¿~ýš’’RTTôæÍCCÃÄÄD2™ìèèheeõêÕ«ÖmYò%÷¶ÌÌL;;; ÃŽ?þ×_‚-\¸päÈ‘ùùù=쪱±qÑ¢E4ÍÑÑqîܹ,‰ÇùÈdrXX˜˜˜Xddäùóç»Ü¼72@,|¼†N§wø)B¨±±‘J¥"„»Ôs\\ÜÌ™3Ÿòòò¶~—B¡,Y²$ ÀÏÏÏÖÖ–OPPPVVÖÃÃÃÃÃ#00°õOmÚr¦ŠŠ ccãÚÚZkkëM›6â‘ÉdüîHÏWœÛ´iS^^Þ¨Q£zïijΤ¢¢€rqqÉÏÏïR[¨Z@Ÿ2tèÐáÇGEE!„"""TUUååååääF}àÀÖÜÜ\\\\RR’››k``ðíÛ7„PUUÕ{®¯¯¿xñbPPО={:9ÌÎÎ.$$ÄßßßÞÞ!ddd”›››œœ,'''//ÏQ›Ëÿ>i.77w„ >>>DÇ€SØØØ 2$===11±Û$%%?žŸŸÿÚµk|||,ŒÇŒ/^\[[»jÕª.m¦ U àn:::Òÿ  ‘H¡¡¡ÊÊÊgΜ #‘H$)222--MRRR^^>88XQQÑØØXEEÅËËkùòåMMMœBJJJNNîöíÛ>ì|sc---999MMM|þ‡’’R\\œ›››¬¬¬ªªê’%KX~zÏîÝ»ddd¢££‰Ž§ P(7nD=¸ÝÒØØˆÿ¶Þ½{÷èÑ£YšŽkœ:ujàÀ÷ïß ìrcŒEôôôB<`U‡€=xð!¤§§Ç|øÆèmÌÿ£0ydxx8‰Dâããë·ÿjðMKn¹ì"""¡W¯^u£ùñãÇBªªª,ÏÆE‚ƒƒBƒ®ªªb² Ük´õîÝ»åË—cæááÿ´&..¾zõjÔ­Û-߿߿?Bèܹsýpl¨µ%K–L:µ´´”ù•þ¡jü??þ466þõë—­­-~О³³3??DDDWç“:t¨®®náÂ…°-‰D:uê‰D:}úôçÏŸ™iU àZZZ/^üéÓ'mmí .Î%//¿xñâæææ“'O2ߪ¸¸ØÇLJL&·_e»š0a‚¥¥eCCÑ#G˜9ªÀÿìܹóÎ;ƒ º~ýº€€Ñqàhø~Š—/_.//g²ÉÑ£Gi4Ú¢E‹455{5Ù·oÏÅ‹KJJþx0T-€ÿ¿âã㋈ˆ:t(Ñqàt£Fš7oÞ¯_¿˜ÜO±¼¼<00D"qË"“ì¡®®niiÙÒÒrúôé? U !„^¿~½råJ ÃNž<©««Kt¸c?ÅÖ{}üÎÅ‹ëêêæÍ›§ªªÚûÑ¸ÉæÍ›B¾¾¾µµµ U ýøñÃÔÔ´®®nÅŠëׯ':\cúôé“&M*++ó÷÷ïüH:~æÌ„,3Ý•J6mZEEþ,t' j ¿knn^´hQ~~þ¤I“ð™ÌsqqAyzz¶´´trXBBBii©ªª*ìçÕ!|sÙ?PµÐßmß¾ýÞ½{ƒ¾~ý:wí9'0661bħOŸ"##;9 ßygåÊ•øÎh  cccqqñ—/_fffvrT-ôkW¯^õôôäç猌”““#:܇L&oÙ²uºâܯ_¿nܸÁÃÃcggǾd\EPPÐÊÊ !tõêÕNƒª€þëÕ«Wø.ÞÞÞS§N%:ÜjÙ²eƒ JKK»wï^‡ܼy“F£M:uðàÁlÎÆE,--BÑÑÑU ýTYY™©©i}}½½½ýš5kˆŽè|?Ř˜„‰‰ [cq]]]))©ììììììßÃËÎ@ Ÿ LJJ":EßTXXØ¥ã1 [´hQaaáäÉ“™Y#йµk×=zôÎ;oÞ¼;vlë·ZZZâããBÆÆÆ¥ã¼¼¼ , ¼uë–ššZÇǰ9èÏðÉh€äåå•””ÈÊÊ \XBBBÂÞÞþäÉ“îîîmß}õêUuuµªªª¢¢"A鏯¬Y³œè8ôA£G600øõëשS§‚ƒƒÇŽ;wîܲ²2QQQØ{ˆIø-–ßU-0B@±yóæGIKK———Ãêœôgg纺ºK—.}þü™ñâ¸qãà:&?!ôöíÛß…{-ô þþþgΜ¡P(®®®Dg oúöíÛîÝ»/^üðáÃÖ% ‚»›]1bÄ„Pnnn‡ï½ú¾—/_â;“;wNYY™è8ôA‰‰‰óæÍknnîð]bž¬¬¬  à·oßjjjDDDÚ¼ U `Ÿ€€€®.†˜¡  ÐÉSZ¥¥¥fff ëׯ_±b,ô@o˜9sæîÝ»]]]étzûwá¯æ‘ÉdEEŬ¬¬ÂÂÂQ£FµyªÀ>°6n/ÑÓÓû]ÕÒØØhaaQRRòŸÿüçäÉ“ìÍ@?B"‘öíÛ7a›ªªª6ï4ˆT\jРAYYYø£m@ÕØÍÎήõúK ' ;_qØÙÙùÉ“'C‡ çããcW.ú)CCÃääd“6;éÈÈÈtÒŠD"‰‰‰ñððÐh4qqñÝ»w·ÙL[[»¥¥¥õc5x„NŸ0aÂîÝ»gΜÉx+++KMMñþzvv¶ºº:†a¡øøøÝ»w555IJJ®Y³fûöí¬¸¬1pà@„PYYYû· jìfkk «-±JRRR'UË¥K—Ο?/ êÀjjj/^¼°±±¹qããEiiéÎ[%''«©©avãÆ SSSKKKIIIü­¬¬¬´´4 ÃÞ¿¯¡¡Ñ¦I]]]PPÐüùóãããg̘ÁLššssóðððùóç#„òóó‹‹‹»üuö&)))„Ð?Ú¿ÏÐ7%'';::"„.\¸€¯Ú`QQÑèèè}ûö‘Éÿý%+((ÈLC‰4sæL:^SSÃx1((ÈÈÈHAA¡ÍöF¸888¬_¿þðáÃLÆ+//¯¯¯Ÿ4i‰D"‘HÊÊÊœ¶ã ~¹Ú¿U }Ðׯ_ÍÌÌh4ÚÆmmm‰Ž@¿C&“÷ïßÊÌ¥†•––îØ±cÒ¤IÆ Ã_¤ÓéÁÁÁ–––W¯^ípª/BháÂ…)))LfSTTÔÕÕ6mšO‡£0†­^½Z^^^YYyýúõø‹T*uÊ”):::¡ììl‰äææ¦®®¾`ÁüÈØØØ9sæü±I' ñËE£ÑÚ¿U }Mcc£¹¹ù—/_ôôôNœ8Atú/###|q¹?Î*SWW'“ÉC† IIIIHH`,I÷ðáÃïß¿ZZZá[µ'%%UWWÇd*‰tûömkkëcÇŽ <ØØØ8//¯õ¾¾¾¯_¿þôé>‹?--móæÍ Ïž=³±±ÁWRÀUWW§¤¤ØÙÙùûûã“f|||þؤ“„øåêp]>¨Zèk6lØðìÙ³aÆ…‡‡w¸i*€mð_ÀMMM–••…aX\\Ü»wï***¯Í;WDD„J¥***v8H„*++ëpÿv¼ŒÀµ¾O#$$´gÏžÜÜÜ—/_¶´´èëë·N(//?iÒ$ooo¼JLL$“ÉŽŽŽVVVQQQ­ç»ºº ~ýú5%%¥¨¨èÍ›7†††lÒÉÕÀôÏ?ÑèS.^¼èãã#((Ýùc 6 P(4ŸŸÿ/X°`æÌ™ëÖ­‹'‘Huuu‘‘‘555Œ»§NhÓ0..Žñ ƒŒŒ cG„PYYY›EÛH$’––Vhh¨°°pQQ‘ŠŠ þ:ß“'O’’’|}}OŸ>™™)(((++Ëj ÿÓˆB¡,Y²$ @FFÆÖÖ–ïM: u8¬÷Zè;ž>}ºqãF„O‡›¼Ø ¯0êëë™<ÞËË+)))44!+,,L£Ñ0 Ã0,++«ªª*>>¾õñõõõ/^ Ú³gO›®ÌÌÌqâÄܹsB%%%'Ož,((À»MHH‘‘‘——g4¬©©)//Ÿ9s¦··w^^Þ÷ïߌŒrss“““åäääåå;¬'ìììBBBüýýñýä™iò;øåj_œ!¨Zè3>þlaaÑØØ¸iÓ&kkk¢ãú÷!Þòòr&WRRúûᅵœ~þü´aÃÆM55µ… 2‰ttt¤¤¤ääänß¾ýðáCÆUUÕ &HII1bРA>>>! …’œœü×_‰‹‹ËÈÈœ8q"..®uUQ]]=gÎeeå‰'îÝ»wèСJJJqqqnnn²²²ªªªK–,iŸ\KKKNNNSSSQQÿBþØäwðgžñK׌ÐÐh433³¯_¿Î˜1ãøñãDÇü—ŒŒLvvv‡ê0´™À±gÏüÆI›Û*!ÆCIÎùhó–Й3gΜ9Ó>RXXX'yäääÞ¼yÓæÅ3f¤¦¦¶~_`†ñ)‰DÂb¾Éïà«âv8Æ ÷Zè Ö¯_ÿâÅ EEÅÐÐP˜ çÀ—yýöíÑA¸ ~¹ðK×üt€ë}ùò%))iÀ€ÑÑÑ\‚ÀNøpɧOŸˆÂ5ètzAAB¨Ã½_à^ \ïãÇ¡K—.7Žè,€ÿGUU!”››Kt®ñåË—úúúAƒµyâ U \ ,Ç0lëÖ­‹/&: -¼jÁÿ´ÌÈÉÉAÿ^·ö j€[544ìÝ»!$!!áææFt@Fzýú53³PB(==!4f̘ß…ªnµvíÚììl„¦¦&Ñq4hœœ\uu5 1 _E÷w+NAÕ¸‰D—––?~ü‹/ïjkk·ùÖ'‘H’’’­×®666n¿ÛÞ­¸¸¸¨¨¨žžÞÝ»w۟ߌ¥_Mœ>}: _… €“iii!„˜ßݰŸÃ–†ªôYÉÉÉååå•••eeeS§N]½z5þzVVVZZZzzúû÷ï[_]]}ïÞ=ü㪪ªÄÄÄßu[YYYZZºxñâùóç3š0())eee±ú«aÊË—/7oÞL"‘¶oßNHó¦M›†JJJ":øüùsNNލ¨(Œ¾OXXØÞÞ>33ÿ4((ÈÈÈHAA¡Í~cýõWxx8þqLL þåw ààà°~ýúÇ·y‹B¡¨©©±.~¨©©Í›7ÏÅÅEOOæáÿŸ>xð€è \¯ítuuw ªЧá Ñéôàà`KKK ‹«W¯¶ÞìÔÂÂ"&&¦±±!feeõÇn.\ˆßÝÅG…ÜÜÜÔÕÕ#D ,`ì;g΄P@@•J2eŠŽŽ¾^dë¶=ü2EEEcccÛR4aÂQQÑÜÜ\|Ð üæ·¾¾þô4íÑ£G›7o¶³³C=|øðû÷†–––EEEOžuuuf|jhhøõë×”””¢¢¢7oÞ&&&’ÉdGGG++«¨¨(|J|‡mý±±1jµ‹èÐãÇüø¡¦¦ÖÉà;}ZZZ:xð`¢ãp(|Æ¡‰‰I'ÇÀ½ÐÅÆÆ Óh4 Ã0 ËÊʪªªj½{ª®®.ß—/_~÷pC}}ýÅ‹ƒ‚‚ð-XÇÎÎ.$$ÄßßßÞÞ!ddd”›››œœ,'''//ßz x@?$$$dddÔÒÒ@tU__ŠZºti'‡AÕú     6ðóó㟪©©-\¸°õ //o`` ¯¯o'ÃC:::RRRrrr·oß~øð¡ŠŠJ'gÔÒÒ’““ÓÔÔÄwJSRRŠ‹‹sss“••UUU]²d k¾0×§ÜùùùÁ"¹Љ‰©¬¬œ8q¢¦¦f'‡ÁÍjÀÝ:üÿ¿õmc8™qüܹÿ×Þ½†4ÕÇßY2cÕ´°0fiÍ@XÉ" ‡©T–•dEÐm i­RCzQiÑýF±nt¡žš‘Ev¿ß †™•ºdevÁ¨%e)–-lÏ‹ÁóÄót1Ûvö¯ïç¾8ç~/D¾œíœÿp÷/QQQÿ_ä[ÿV¾<øËß%Ir?(ôÄÄD÷»’¾z.€?MRRRhhhuuõ•+WåÇïlÛ¶M¡P¤¥¥}ÿ0îµàuîoè+ ³Ù,÷,~§¼¼¼¸¸¸}ûö“'Oþþ‘T ¾0cÆ µZ}îÜ9ö$ú÷ƒééé?|Ä’jÀBBBŒF£ËårïÖ·û÷ï¶jÕ*33ó‡S-øÈ‚ :ôÏÞ#XºtiSSÓŒ3ÂÂÂ~x0Õ€téÒ%##ãóçϹ¹¹rÏânß¾]XXغuë… 6çxªßÉËËS«Õ'OžüÖ†ó—Ë•••år¹233µZmsN¡ZðN:-Y²D¡PÌš5ëÓ§Or#§\¿~=444//¯™§P-øTvv¶N§«®®^³fÜ³Èæõë×999 …bõêÕ¦™gQ-ø”J¥Ú½{·$I+V¬¸{÷®ÜãÈ#++ëÕ«W F£±ùgQ-øÚàÁƒM&“Óéœ8qâø9щ'<ضm[w½5ÿDª˜ÍfNWYYéþ äÏñøñc÷®LëÖ­ëÖ­ÛOKµ •JuèСÀÀÀ­[·ž?^îq|äóçÏ&Lhhh7nœÉdúÙÓÙ=¾–ŸŸoµZåžâ7áp8ä@ËÅÄĬ_¿>33süøñÅÅÅÑÑÑrOä].—kêÔ©6›­[·nýõW V Zàk‹EîÀ_Ì™3Çf³Y,–Q£F•••…††Ê=‘­\¹²   ]»v'OžlþsC_¢Zà;F£1..Nî)~Cr åvîÜùøñãk×®%%%]½zµ}ûörOä{öìY¼xq«V­8ЫW¯–-BµÀwÜ_¿|I¥R;v¬oß¾v»=99ùÒ¥K?ÜúX8‡ÎÈÈp¹\{÷î9rd‹×áÛ¸È,$$¤¤¤$""âÆÆ kll”{"O:{öìäÉ“›šš–/_>eÊ”_YŠj@~aaa—/_Öh4%%% uuurOä‹%%%ÅétšL¦æ¿¹ÿ[¨üBdd¤Ýn×éteeeƒ ª©©‘{¢_•›››––ÖÔÔ´lÙ²mÛ¶ýú‚T þ"""¢¼¼\¯×?|ø0&&¦¸¸Xî‰ZÈétN›6mÕªU’$mß¾}Ñ¢EY–jÀ—””Œ1¢¶¶611qóæÍ.—Kî¡~ŽÃá0 ùùùmÛ¶=~üøÌ™3=µ2Õ€Ñh4§OŸÎÉÉq:ÙÙÙ õõõrÕ\.\èÝ»wiiixxxUUUJJЧZð;J¥rÆ G ¶Z­={ö<}ú´ÜCý@}}½Ñh>|øÛ·oSRR***ºtéâÙKP-ø©ÔÔT›Í¦Óéž?>zôèôôô††¹‡ú:³Ù¶oß>•Je6›Oœ8á×åQ-ø¯îÝ»?zôhãÆjµz÷îÝZ­víÚµ?~”{®ݽ{wÀ€999>|0 •••sçÎõÒµ¨üšR©ÌÎήªª3fÌû÷ïçϟߣG;v8Ny«ªªš0aBtttiiiHHÈ®]»¬Vk=¼wEª„‡‡;v¬²²²OŸ>555&“)22rÆ ïÞ½óý0ÅÅÅ)))z½¾°°P’¤¬¬,‡Ã1}út¥Ò»]Aµ …¬V«ÅÇÇËý· åôz}EEÅ‘#GzöìYSS3oÞ¼:dddܼyÓWÿþýÎ;ûõëg0N:8{öl‡Ã±iÓ&µZ탨D"IÒØ±cívû™3g† ÒÔÔ´k×®åä䔕•yüý.û÷ïŸ4iRPPÐÌ™3m6[ÇŽóòòžã§ }*÷þË+Õb±X¼±,ø“y¸ZŒFc\\œg×¹DDDÈ=€y¸Z¦M›æÙÜø6.ÕÄ@µ1P-@ T ÕÄ@µ1P-@ T ÕÄ@µ1P-@ T ÕÄ@µ1P-@ T ÕÄ@µ1P-@ î’$É;À÷q¯ˆáoó²¾®¹¿IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/xml/images/context-hierarchy.gif0000644000175000017500000001730507525303737026234 0ustar frankiefrankieGIF89a¤”¢žžžîîîwwwÙÙÙ¾¾¾IIIÿÿÿ!ù,¤”ÿxºÜþ0ÊI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ p8 ƒä Àl:•G#qJ­Z¯ã `0aL. æô9옃vN¯Û;ÈB÷‹&³Ý\pqQ„…GJL\ma~`^orw’“”@H]bk€ƒ4Zz^™^œ‘•¨©ª#|šUy˜}¤±«¸¹º —™¶q¨­˜gn»ÇÈX_ÄÆÉ—Ì¿ÉÔÕ9µ§Ö ØÒÛÝÞäå"Ëh¤ÜæصãìòóÙ£Îô®éðúÿìZ #à@ ú<È0ײQvp…/žÄ‹sŽ*€ñÿ6‚;Š¢1âH%Cž\Yc*YfH)³æŒ ,´ùA#Gž@UØ”€Q1‹*Å0PÀRÐü|JõBT;«~8 @«×~1Ô騳a œ%1€€ÙµZÁÀeëv.Õ/véNÍËshVþ:MÊ#)aÁT±l_×8 S¨[¸æPÉtÓÌ É‚S‘äÈ1Ö–#h•ž?ëÉï‚ÕRxÀ›™×jÛ‘Jƒ8ú·²á·¾TptÌÏ£’­Óå@—.ñˆdàqƒ«bsà˜­¼t¢×ÊñKqà „«=Šæ1{]ûôÆà³ozön8 ÝõÑÿ¼@J[¢aÕVA‰…Å |¸æÀFTçßr\ÍF@ƒË èT[ñå·Ýlj=PV+úE†q|Â@ëÜ×Qb ”ˆMlwØyd˜X[Æ$ˆˆ@fÁ`xÎñ²]6 …!†o‡ãpA:0X”ÕÑ&`W?îß|.êCàné\ÅGAÕ1pŽêˆŒ—•)ä^7pdˆm-9I¥€• Ie –åVðµØeC0zàOX˜ðòY]|é×—>>CÊt é† ðègJò˜$w£`Ê'~Ò¦ ªÛ%Jè\*O~€±Äv:9 º¥‘rSŸ…è¡ ßQœ*—Ÿÿ—q(`~È:[‹üž[][^a-c¡·É §¸ÆcÂyÛºçÂŽ‹eCšŠt÷Sw‹éÑ©YœâG®$ “KÖufzÏ LœN àcЏ 9ħ€(¢Ÿ àpÑEÁ1”«}S'Ôâè0œÌD í>2@’+9G¹ÁI¸/Ó3ÈâÞH'9$WдU]“8-OT˜*ÝA?Çæ4=Ló\Ù›$aõÔ»”LtNß,5×úÔ¼õYÑ +ÐdÔ½²"W±Øg·½ NÉZœÚ‚Œm÷A%Íì•F¶B÷ß¹C”]÷Žô u#N=ýDŽÑCÿ…}3Û’¿H9A‚ŸÔŠ6šÓmyçÖäÜ€AQDÐÜ}ûºè[h:Õ®g®9²Ïε“áÆé¸|ÞLé¼ïû<Ÿ€¢¡æØƒD7¹yËW¥ÅÎû±Mê÷x_}J@®|ö 5ï|™'-‰0ÌÀ¢±õ››þ\Û7¡ûÔ;Ó{³x…øæG¿òâ~•9Dô·‡0ÔÂ6ãÜ >¡>°ïÕ£_ýˆ@YE l (ÊðäiÍ…¡ö`A5`€Ü ;´–ïdókC ÕÀÃú°T¤Ð! ÷„ò™ï4T!Œ¨²D Q‡P\D¡8D6±~ÉÃ^ÿï—B#.ðŠW”Ñ ‰Æ“y1‹ZÜ¢¯cˆ3º1:Îx£Xˆ5Ú‘(\âòÈÇ#Üñ/(ΠIȰc…L¤ ÂâE:ò‚4Î#')þQ†’˜\ÁÛÌp¾Lz²Ëè±fôÉR– ,4¥*”ÊUš•®Œ%\%ËZf€–¶Ì%p©Ë^>€—¾ ¦‘n'LW³˜½T2—©Ìe³™Î&­¢)Í‹QÓ–Ó¼f/³©Í\º©›ÞD$8]ùÍqʲœæ$§8ÓYJt²Ó”î|ç'ã)ÏLÒ³ž[T sˆ >ÎøäÚ,h1Â58‚u`J‰VÔsëkÄ#–ÿF |0¡…#nñPªÀï€ ŒŠøµÏ¡Ý…ôH=v¯})½ˆñ~Ò êA ¶¨iL­Àˆ´+…1wJ ×Ug¨’ø눪 ̉ci S+A8©êCqÜœê>‚­Ž<$«Z¥Bq¬ú¢œX3¬?Êj‚7†¡ÕP ÞŠõVÜ ©¹k]uP³¯ ¯{%AYÎò×ÀÒ`WpyŽacà¬4æ—ä¢ÀcS 2åAh±/YU@I é¤fÁ2HŒ³'8•\Á:•âI ‰Fól`o뇺¼ð gt`D‘­{a ±¨E4{‘QÿhKFWéPwn{-E‡®Ïâ€ÜB­—°H­ "Å´–C³‰@±É=Ä@p£hˆ8BÒ»t&ú^h½fútT„Êæ0´9“ºrÌ pH§‹õÓ,UZˆˆÁ{ð™P Ú =(DI²ð`Üô_§¼D 1Ú0YÑÕô–@µxTQ6ºå©¥,L o†ìKÝ ¿FbHâ°‡=œŸ&È¡8=*m­òƒàÀ*˜½!Bóæâí ?ÚY…-â¿ é¿yÚq8[¹,×#nñŸ‰ÉbáãQ-FÓ’Ò<œt D×Âp´Óö€A:¶P‡Ú³dg6ó˜!7@âÿؘ:õ†ð˜† ‹^´£ ‘$RÚ#0«Y 'pÄ…gdºG?å@S8:èÉybQl Òò±Rz_µË\Íܳj¥fQ£uÐ{Ÿ­­È‹õšWØc8‘êšò Ø~æ¾cG,O¹nØNèlVð¹(x ó?=æâØZ${Û±«}\°ýno°£6¹Q øp»˜s\ìÞ­kœáÛåPœî7îuŸr ñûÞÒŒ:¾ë!Ñß& ðBÝÔðí›ßEøH(Jb0|¹`Á No‰³‘â&U‡ªyTbl<‹¿ðVhÒ“Ná£$œ¨ Oxð”ßdåmùFgí‰-Pÿ,âm.„íqoŒ?7è#àq<6O„ bÐ…>t¢SA_ÜgF-i†„J]‡^÷á ­Hõª[6Ìz+v¯?ÐíS¬b ±Xdz§"í7¼¢ÜÍ#w–ñŒ(´;5ºøF•I¥Œ‚cÿ>jD­z£ã›Îx È G|¬<þÊÐqÍ® øöüZø‡]ÑÃe“dè¼éå1=2Àzõ±öÅ%aÏ—ÓÒÞ.¶¿=\r¯{–¾÷cá=ð½rÏáÿõƯJñ“O•å3)Î~Q¢/} P¿ú6¹>öe¢ýí¯¤ûÞ XÃ?ýГŸ%ã??OÒ¯þš°¿ý+ù2üÙZèùËDþöÿýó/:!ó$ö€ˆ(þW€x€h€#·€Õ@€xU ¹ðt,ävnæumÀl5GˆásIç@Bäwû¤1m7BDjh§Q…c EAå=*¸‚)q°pq1@Tƒ6èààfOE%§ª·}èSwÐ g@V?X4Ò@Jw×SÕq„´‡UNèÒ`~˜m&A_…|ÿ×V\x \%†óÇeX j¸€Ñ•8MQ€wb…V`4tXmˆÅR¸I±2§ôfö—‡,~¤+n0hˆwÝ„á!á’8"’V4°ñh Á“ø^¶Â÷|G¦ÎÿAò8…gñ±:0=Æ0Me2 {´]zcЫӀº¡~„ø㵊³ae‹Ó±‹ p&œreXRŒîö#9¦eâ^C¦~(¢b-ܲu‹?O¹ Ê('Ç1AZö/ÅÕ€Èr~_Ò_’*ëÑ\†%–²Ní†%yBL†9Àø_nD ¸+ XyÕX4â¨X&'õ("÷²±Õ+ÇQè²æ‰Ø`9\¡ƒÆ×‹öc!Ò_Û‡±Ø rñ/2"'Ð’&΀ÿ5»â$µ.ä7%° r / ÒÂñ:ÑhêrVø2-ƒˆÿ²0¶ C+EÿùÆsØŠzX1ÃCÑÕjá‡\4pt>F/‘kä7Xñ–¿¦~F3È V›ƒí÷†˜mÙoÛçmés»ÓØ×VYè Ùö‚¦#€íö…ÞÐnòv8hoø –T;2—xzIÁãSw¨\¹ã8™ŒHq$hu€ƒÇCDÉó„˜Ç=ÃÐ ŒÉÑ q'Gs•éy8·?1§•7 :'s¢‰r¤ FçD3(QD—ðt¡ÐuRG‚‰g?»YXçáÀuðu}g‚‹PPÑ) ¶ÐDTQËIŠ=u‹cÄBI÷Cä A¸©1fœhÔxð£vk7?¶0EQ„ Ó‰C.ÿä.šÉžI„w*Äb„xú³WäEÙfkÈŸÀuYBq0VstCgx(dI¿Ç ¤h‰Ø)d`“·I˜2C ¤ züsjízVAB˜!HMñší7‡Èq;Ø!I¢˜1ѱ 'Ê +‰&* &š£]'8:¹1ú£û7¯a­‡£¥ûW=ʤí¤ÑrkØz>*%K‰¥' mf†kX31„Z*¦zFܲ‡(ölnŤёš °Vî8·´¦ ÚW%€_0§á¤ìy_Ú z¢×¶œsxø'j‹ºì!£gç§F¡¢å§xô¨x§*ÿà‘@•ÈF¦¨)ШŽå©xªˆ¨,@¨¦U©Š‚ªù©, §d†§õ 'ü§©ìVf%`ª„â-í'ª.`¬¦« ¬çg^.0©"À¬ÇŠ©‹%«00Š& ¨Œ­Ò§«0@ª`­Z‚¬É'¬,Àª)à­š®½§¬2@«$`®»f\º'­3À«íJ¬/p¥W«㯣j«©5{ž§W6`¯…j…òZyê:RUš ;qÈx Iœº8Y kuúzäÊ#{¯[jp™ìH;ëo/‹ô:ªCŠ1ëjËüʲ˜³®–±;à®™U³+€[Dz;P±"À­vÿe¨&f´?@­Óº³µy³uå³;À´2 µM[§Á†°>P² F´Ó*°h´?°²5Àµ9p©{…´?0³Dµ:²SµD@·3À¶|…«)…µiÕ²«6±;`·•³S ´( ·më·”dCä–Œ ¯E@¸ž`¹;€¶…´š)Š$”*á¶VÀ·5À¸}‹®vš;G—GPR¤V b›p˜Kr”ËœyžÅ¶ŸZ¡o¢<«é0azj»¦›µø ‚aœ›6„#pŒ?d›Ç+R š{S99¼)ƒ¾0„u¾j¥÷€ºy[½/p½Èëà`qÀûU¨|iW/ÿ­ ´™[»i[â+©T˜¨ôp'¬^f¶'[ºç[À9‰})†´NëÙ«Æ8cE‡ŠÁn㸅+l=@ºÆ+g‹×´z+àÕdIÉvs”v%/G ÅC"H›E‹¸< º“Â= ˆ7èºÖٙÑ;ÈÚ0—ZsC¾pÚª^kÁ·+\Ù˜ükQH,?ÉùE&è FØ•á#r‘s_Lf \ºWœ Š»¶®j¥ñ#ÆxP„O|I8 (¥oÒ»Z>¼Ã{œ ì›Zx54î¸:sð°ÐÂBàÑ¥z²ç"´‘cÜ5-Õ¡dòÂg#­Ñ€,ø;·>Ú^äGÞl/|Ð# ‚^}¾2/,"@<"¦Í-J`¸ÿ"9ÆÔ )M†$ÖǾXÈÇ~4퉇ÁH¢ÊÔL=ý4Å`CAÝYT]·`ûm _]E.9öö•7H‚$9! Ìb1í‘•£gaêe”¡oÁÐ}fI < 3bà‘h i<&“Ù⥥Ö?0¼l½Ü‡fRù€k=1Ú&¹ëÝŠ¥ò!nö!iö#wRXÆHà! ‚ûÎV¥¿UÀ"ñ0ÞÑ}4^ 2ºø@Q§ ·€è^A^ÙM.þøŠI†a2îßf½%Þ10àÿ} v8ËÆtÝàÞ!í¡Er-»x& °î«bJþâQžáä@°‘ñ°ã­ýበڪ½fÙ7Ó]©7’nRYr£v‘ͤ`K>ÝGÕ ì²±è'°‘ÒŽã .ìqÏj 5Û6gzîÔKæbÿ "Ÿ~‘rÒÊg2ªmݤxæ6~^àbpNY>éóp]2ÊUé&R$Ü+é] R3½^%Hq#Àî\Ù¢¿(Ä]ÃËΛÓlÝÒÆ A¾,¸:¹Þ;Å{Œü€.ß¾ö²/j^ÏëbÛPÑ|Œ¾æ‰þÈÆ-ôŒrSls^ñ¶î§ÆÛŽDR>í¡•Ÿ¾U=žãùÍ}Ûã™>€3eÕÇåpipÝVlܧàÚW kZ³KrÃÁè&n¼›o-è>xK/Dó™z ÛµYÞc3Ë<ž5‘oF¨Úò![pš¥’5tt,‡‚¸I>4×¢gœaÿÉtLîÒ‘níVñWyƒ·o*ϱI äiÃ(œº‰±N£v–Lžê60ë÷~E8Ö†Ìó˜©ò{mù³vôYŸd—œ$ZÏ.År>n±Ûò.6x€/)ºtÞËFt›õNô…ÿÍ©wÈ©2Ft÷9iáû÷tÉÃ#Œé±3œáã 97Äk vh‚$¯œc ù’?K}r¹»„aë<½öò˜s¥é•ÔY_7ú/Mhéä.ìnÚ.ê_ÿIö]o†lâòëfxK€ÐŒœ`S†Æ ™ s¢‘ŸÞèw?½/£×H0»ÄM[Sƒê°€lc4Zcж«ef¸‚`¸Æ%±.<ªÚéÔÀª4×è“üw™¬™`ix@žúæ ÎÏ…o ¢ ÿ¡„&˜E ‰Ä?²¢©¢ùP€ì«¸¼h= Z¢ v›½L0½8@#bªÖ'&¦‹ŒÙ6·Aˆ$WÖöLðfxT©`GÊ19&|ŒãèÁU`ÈS`%% Å d25˜Â>xF<ª@”pbs°ÅEæêw–ùVŸv¿<2Êºà‘—1-ï-:ãb@¦RRÂì“ «£X|ÆEºé„ÇD& K`Càu4ÕK‘×€ È‚šôšÑ2SÖQÀo—QF¥Ê7|Ó/ö:ç9Š9¥î??ˆ\âÄ ' (’ÒŒ@Øn‡»5Y1§Ê’™ÿÎ^Å•U+ðŸyþ£žFƒŸ¢ƒ {ösvf«šK@ÐNa ™éÄûúB-pA ´Ã§ùR~æ ’Úܧ}lxÆ—ˆE‘(XZRêN„–TöêI¦¥ÒH˜á™¸‹> ¢ÎÚÀ|Ù1et àD ‡˜Ó‰íA©Cý¸Ú-`ÙÉO÷dA²`‰·~ñW¼`«l ªÿÕÓí€k :öUô-@ ªQËJÔ4¶d«R¡MÍh‘§OY—º\¡2¶"ÄÚézœ…ÙÌ΢”|L;){¼2M[ë!7{’Ks±Éí¶•\ó2^M¥"œ•ÚÿV Z€D` ›AìÉQiӍЛÙs%–1è–\ ©eB¶·ýÈh‘K›l0B¡º ±”(,@—*ßEÁ0k5RQ]i¦(Ö©+òã±à]:´Q*Œ 8 òØon_«¼°¢4¾w‚ÙnQ—L€ï) Ýô÷@ÿ•I_¿b —Ã&†AÜü2.•N˜ë€p.üâFa¸î†I‘žÌ‰ WˆÂ€Õd^¨|%‚Ñá…|# ÖU¤kã_)'l©2[¬‡i=Pak¦‘Je©,d#=ñq‰¥\À¨Y¸îú"KÈVÜb™aŽ ­Œ4 Š€ÁmØ­p«Yج0zSvg; =9€ržs¡ý”Oaá¾±mh3eH—•ä]:»öàú¦¬Ö´©!Þôª)ÄkÄŒÍ!ÝSË:I¾…;%Žnô‚ÌO>ó¬ 3ŒxdÇ4éqUÚ ìd/¡Îb.s[~¬ìhÓb-V†2´¥mÚ¨9ÛÜ~t;openacs-5.7.0/packages/acs-core-docs/www/xml/images/rp-flow.gif0000644000175000017500000000474107525303737024162 0ustar frankiefrankieGIF87a…ˆ€ÿÿÿ,…ˆþŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦ª´-¹É»..-5rë—ïî=Oh»eœ"T§ÔªõJ"™3!®ªÅÆX\ñ¦ü Ðö¯á?ÜæºýŽ}×qÜ~½òwf"7Cˆ‚Ö7QFW‘8×H™GYiy)É—)¹gsä'ƒèUdÔ£ *ØDFöâiêÄyJãÚ ;£Dk«J»{+ë1{ÄÛ…*ü |ŠÙìü¬â÷)Xë¸y¢L-ö "5‹ÊZÍ“f*"WÌ|ü®…«F?-zœ¹^-^- ÀIî©2'¯@ ®H¥’‡Î›}ÿ*jiè.]1þN =QŧÄ-ó40q§èc«i | 3f¶üHnZ§P9„žTÞì¹°¾ž}òd¹ï›ÄU-oò¸ˆrdÆ¥Kz!%EŽæÕ{%ezýjé¹|ÈX‰#;B,Æ`Pµ²û" #G ¥èÅÅ”ٱζýé¶ \³}÷“;·ØÅŒçp 92¥¼’+[fLù²æÍ‹2sþ z²çФ7ƒ,:µêÕ¬[»~ ;¶ìÙ´kã)…;·îݼ{ûþ <¸ðáÄ‹?Ž<¹òåÌ›÷¶ ]ÌhhÓëT7s]zôí­³cò~¼ñ`¸›OM~2æõ‹ÓŸ_Éýmö`åï°??öÏøþÑÿÚŸ~fÁß^˜‚.Mí(“‚ NX‚„ãA“…RÈa†Ö‡!LvH¢IâK#–È¢#Äób[L·";)Tc‹:ÎcW0‚Õ07”cG;y@§ydƒ^¡èÕ#ˆN‰d•Ú½è,ßøEÒTùP#•(Šie™SµM;]mÔOeÃ#™if$äÕF\¥³ÔQnºd”‚Žiçœh˜µ9—]\Ù´Œ7€ÂAg@ˆ Y¨¡q*ß"Žp³ `äÀƒJ\h%z`¥Ôe:'KbÃTZ>2Id”„Þš*«*öJ[þœ•1k­dK0!ñ þÒ¥¶>&§‡ÍêêŒVפ&?’ ©ƒÒ©DÑĈŠJªúŒ²±Bk©AzÂyW£AŧJ;Á‰Žš³š+X¸Ïîº/º4Ö9ÀlÖ?¯¯Sï")”˜Å2+U3»a¿µú»ê£¦"¬-²Zvlj¨ÂpÄíZÆÊè\ÊÉIL¯U,sJéäF‹1ƒœJqÌíÕuo²l6Y$.Z,¾5(ž0ˆ3?ãD-/ºð¤í/ÆèŒ«¦G÷$Î9Ða´‰XJ¶´ºìIT¼·Ä1s3aoÍÝÛ²öÂÍ£HÙ­TDE"÷²Zà ø¦š¤6Þ5ÄhÇ[¡úwã?Nëe'=þ4²b”†°^Ç›µ³9Óc;.bÛ CÛ÷Ä]õLц'šŒòg;~mÑ_UŒ¢ÛFW»ŽQWe„ÁH?¦qý뢠¯j9KæM<&w6Tí±f¤ãõìx(G±$ƒ8ySÉÄÉq„f¬«˜!©ˆH!uXM¡ÂX?Šr~•Äá%1É™#ZËM>‚Útè6>¥j[£f¤SÚ© ÇÔp‰E>0‰^ô ½¦Ò§¨ºD/«’14Þn~ˆáöfÊf2•åÊá3鲨$³) K¤6·išr B†‘Ê^³Aï|óœb\ó0ÏQÒóHùZ¥ˆ£}‘›Cv°Vu«a™dÍ’L*m>5¬«¤gESJ6›ö<ê¿HÊR-ivµ¬5^åC-½2Ls3á™±š¸Ç :PX©åvFëØ¶>•°Œ«V'aþ©r¶e‡ã™Ý¦µ<òMƒœ ÷–ù-EB¸Ô¬ìp½»´m%·pð«U¾´=¸Ì6oFémÉ^h°kl©M‚xÅû¸Ú(l®›¦Õâ,‘¸„PBõ²äµ®r9§kÄÏ{sŠš(0/][Äú–bHVN/v»ŠÊ'M?N÷”’¯ŒÝkóNœá©¶rº…mva¶ÔÒ‚{¦Š+\A÷…´ ®Š&W û¦#®•ª:¥Þyy3—6IþoŸˆ(Ëé(LF]P|Òæ ¹¦5 ,ù;1¥‡o±•T¯ö{Ÿ{Böj@üï—`ZÀe v¤Ñ¨šÃÒ<á7—Bƒg„×Lþ\0òÍò«°H §dbŽ® I 6Yi5E'HÍ Õ x0› ÷“Df,£C“gŲëXÖ¡´ùdqLÇ»-Õ$2³çOÏ2RFíwI,ë­JÎԥsí˜X×úÇ>0°åÊëý4ëÎøübgm§i¼@Ö”s£yí-C›Ö݋ᢗ ~pñ›™–-kÅ>8ÿÙl. ""’}%~c<®t»±T”.[’Ø‚¶øÈÊìbšf/grÌ[>sɃÖ\¥7§¹Èe¾s­®.Ø ÇBƒ.ôl³ÜçK×9ÒyZî¨K}êTdÑŸn(y_ýBî>5Ö¥Zò©Ú@ÿziîòºRvífuÏžöj·4ÂÞzyº>w²ÿçzgzÞéþöïØ@GMÝñ®ì½žèºÎ¹à¿x¹Kfìl¿xäK›NÈ}ð—?-æ›þxÅwô}‡»ãÿ=úÌ«žôHÕ|ê[¿ú¸—]¸¯w=ìYïyÙ×þô•¿5í%¿{κô¡Ç}ð| ;openacs-5.7.0/packages/acs-core-docs/www/xml/images/permissions-er.png0000644000175000017500000001661407525303737025574 0ustar frankiefrankie‰PNG  IHDR¾•V躊 pHYs M MÒέNtEXtSoftwareGNU Ghostscript 5.10—NIDATxœíÝÛº¢8»PýŸ¾ÿ[v¸šf²‰²ÏGU–Bäó5Dëýù|^À/ÿ«Ýèƒè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢üS»$ö~¿3mùóùdÚ2@ŠÎùjýžê¿¦ç¡Sgƒ7ß@+¿Ç=,ª:Zö®5D÷•¥dKëÚ$ÕJÏC§êÞ°–Û–C8?<ö¬*»¨ª›F6ØÂô:¨"Atž°èU?ðê ¨eÚg<.æ÷»ò·Õ'é|RyT³º®;©êu•Nh¤çïõa×=©”¹€ÃÃmý¯SEØ™«ÇÌÇIÜÿ]çŠuö’Ãv&ü%ãïÆKöF/=¨ëž‡TŠ]·á½42vJŽeÁQ儇nþGܺÃv&oüçó)ó‹tÔó‡úíyH¥÷QœI±üíyÿú··O¸áάsòº?ÆÉ·e=:ª…6lèyH%áµzøC ‡¿@¼YçúmC`þu¿åðf϶sUÖ±\fËÕ"ÓÏpÏåèœ#7¯7»®æ›¿ß!Κ´yoÈý »»ºèÞߜ¬ý6ŽÑóЬeœ®¯ÿõ@XjàÏì{æ0F®‚k9=Ço3òÉò„uUŒy;û¹Ó×Iù 4#ð’ŸO¸êZtÎ1À"Çíá;Äφ­ß Çè´ò•¶ÃÉ’ÃÎYÞÖ-Ù¿d?ÓuÏCûbBðáGßC‡³Ñûíw´højý  YwŦ*>‰¡ùˆ³4S±o´»ÿ5ÁLÖõýç¿^­ êÈHŸà¾5êyx5fnp]/d”~ ¹Ôá·³{ ¸}vO¸äæ×s›ª@“¨û­ÖøÀ·þëz®ú+ð´U…·ßΖ>ÏÐ(ྣsL¥¸Wµ ÷êe:¡„ozrxÿk³¾y³¨`ý’À¸Þüy³å÷J¸»ZowËšÙˇèÝåz—£D.#üp×ëo ¸ô5Á×ßOüûRRñË(-lyß9›o´VÝm1.¼ ,Åë¨ç!­T×jùk>²ê>ÜEÝâ~»ùý®È῞½v(¿¯£’~É¥nT?!^Íÿ .~½ŒêÜíì¥ÊÓ3ô%É[ì²?œËȱërò6´pPaí·šrçk‚¹¿Rpï6ÓÙ× 7çBrïΗ9éºÓ×XÞ/ÑÎz,‡Z½½é·êïS{]‡Ðˆûc¦ÌÊ|ûJ«d Ûï’ôýzžǸþËEä^.§ùþ¡å4Æõ…=6Iæ ª•!Iû«¬8ÔóÏ7Õݾ’«á½_ž¹ñªÛ"w7C T?á¶4ëí^SŽÀê^½µL{à ¬‹IÊTêìädòÇç’}¶ž§î·v¤­µ'ŸyŽ”™ |7uhM5¦ ¡’(·^¹wíWû-¼gÔã‚°¿W@ûG1| TB!­B?”ÑãˆÍýò|ô< ¦£AÝéøí¨‡c v8Дr? ºy¤ÁÁÜiÅÓó0˜¦~ଋ sU§¹³ÓfCwª}¸nõoê½§0=ãùùk÷FY¦Ív¤ÙÏÍ6 †×ÖOðû­¥¦ŽºzÆvoŒ°{žÌô?,Û£­è|ÃðßðhÓ ¿{ “0œSÉ1áÔ@k©˜JIzc¢$%º6ÎVŒÊÐÏ0*£» ½j +I¹éa›é笔PÀhÃXaÊGßÂ$ öô*ŒaÀ‘¬<å Wa*¦ŸÓRBacfE*-ý s2ö“Ð0’adzR•Šž„™™~~H …ÁŒ<¤¬çô!ðR îÒo0žÁGµ²õ„Þ¦Ÿ¯RBaHãlÅëýì© ‘tŒjб­„]¥Ç€3¦ŸRBa`³ o…,ž¾~R(ÎèÛD#ÜLI Eˆ¤\ìéÞtƒ\] Ð9À%¦$Ö”P˜ÁŒã\u;¤[€{T—N€iL:ÔÕ¸ <1ùô³ ó˜w´«t_“¿á ÍYWçÐŽk¬* |©§†)”Ã0’ŽJSGMrSB(—0ª. Tdß›6 gy*Â]Í®OãÖåÛeÆm/ÞPEiÄRr7äÙãä£(üÖiéì´Ù´oŸuÔnj³^µÙ*fùñR.F]ˆÒ]í®Á´/¦.7>ƒHËZ»xTQ꺅[Jãi¥4lÖî0žF®4®ºQ¾M~tJž!Ù¾TõSÎçŸÚ ø³;0oÉ=º=u±¼DíîŽ350u¸qig‹Õá|ŠÎ@ ÖÙMíV¸6rG[u89Ñx½2—ïï6M~|•¯‡êp*¢3Ì®ØT„ˆugÕáçDg˜Tźé"0›Ö¢ª:|›è siª|»Œ­ýú¦_%:Ã,šZpO³%÷:Ot†ÁuTÝ@z×QÉ=¤ÿ$:غ.ßn }¯^©ÃgDgÍ0Sn í¦äR‡÷DgÄÀuÍ D 5—ÜCêðBt†¾MU¾Ý@êRÔaÑz5íG7ò¦-¹‡f®Ã¢3tfÂ:uÆ D 7%7lÂ:,:C”ï7´Ô“«æ©Ã¢3´nžòÍ|HEÉ}b†:,:C£®;¹MxxHÉMkà:,:C[”ï„æ¹Ü£>ä6^¡ã}4oÄ 7«”Ü’FªÃ¢3T6@éÅÀ7HJn]ÔaÑêP¾+ï"f¼·¦ß:,:Ciý~ÔÌH73JnËz¬Ã¢3ÒQ]˜Mû7›m¼Z½>•ܾ´_‡¢3jjà)ßé÷"ðeüö®ý:,:C.M%xâ5rñý~Ÿí7ðOPFƒ×§’;’Fêð!Ñ™A´SÇçÜSýâþÒ]®.¨®‘ëSÉ[õ:¼':3Žºu\ùX•ˆŸÏçý~/ïB3M©~}*¹³ig!‡èÌ *Öñv> “UùˆË[E ï°QëúTrgÖÂBÑ™q®ãÒÌ´jÝ@´Ä™–å¾>•Ü'ªT¬;­¸CtfX™­òɽóU7Mf½¸¾sò½‘²¾âò£®b×gï×üϵ~BùoætÚ«kårˆÎ ¢@oö.aË¥9«$ËržwHÖˆûw‹žiGÖë³Ù’{ÉÏöWÿð?†’ 9Dg†’£Ž·?çÑriΪµ™öâÙËG=›ô%ßõÙ~É¥erˆÎ "yW¾ i |­o‚C/Š—Í-Êýƒ¯ÝÇòÀ/ŸþÜÔë¤ ¬on¿ñÃ-Ç´ópƒ›]‡ww¸£ÀΞóú›h ,†Îq]‰Î°õü£êœ¥90¨³›Å$ûí _üLs¸£öÇòó½!r¿g ~rQÉßIDŽî1– ”ô¼`–ìíÍè>[ÒÓ¤õ×Ó_¾ yëì°4V°@›÷Ó±g»^¶³ÙZ *þìÃZws,äÛõðÓØä¥ÿƧýlª4‡+æë×[Û¿dßo™’p“^¿:ê°…¯×ÃóˆÓäFL^Nº×3µnË„‡ÿ¾bDVé˜2{8epèp×û]¤º2c¶yŒñÛ)¦Ÿ×á…è<¬ø«|<—†DŽò­4GîîžLo´á©è¨D±ò"û|?Ù6m9M®úõ¿ÔÆð9=œ³HÕ€{/üüýï 6)Fd¿ÅoíUéx^‡Eç†d]ôÃ^¾¡«4#Ç9Êqb´ð îÕþs‰ÂæÏÉ?5]Y7i_…Ÿö¼UûíDÞº<ìß»«âIž7:ŸuÖÙ"žýƒ-on+îkóàúþEàiávÞxþ„rç¥9~w7¶óðµËöZ˜©Ð'¼Ø‹|…7üüMA>«Ì‡O»w 1—/Ë-ÄÖº“DëÙ¥1›/ÍJÎl Gî/Ã'Ÿ]¢gþlêá]µŸ»ÛwÑfõáÙNcZÛ²V¦9 ¥ðeº¹ ö—HxËß?¬ßk÷/?Üæ¦³?„³!úsw%Uÿ|¹‘»6Ç»ŸŽ/Í1…2py¬ŸxaxZ ©?/¿³8 á7p«ÎÞ ÷>9GI42F²fîÂ>¡kgZ;=l|øå¯“!P«,×ͬkņUnUº´ü'®ª_O.ÂygϬ;qÿ1ñçÛÛºâþÎá¾|ù vxòÎ^»ßì{7eØ]ø2ij„ç.Üá³~Ú^zBà ­ÞÔ¿]¦d®¶óðÏáv^mäÕ&½0Õ¾îi*CTŒï ïëïe¶”ÄÏÑ”Mò8ÜxüN øá~Ïž_±,×röÑ¥YgIá6,Ñâ¬Ig·ÖÃ/ø$%wÒè¾òÖÏùZ†w’ëï½Z›‘DLåM{½ ÌhÖÒB½ë·47ؤ°v.¼’ŠÞ«at?õ~òëè(Âãåð_•åÃIúµÐ°ýU9GÓ”Zç:í~'Î1wôËõšöþBÉë&Ó!   ÝÂyé·47ؤCÕ/³ºZ(¼]}U`;1kŠ”åE;uøªøO\©vWfGùt˜“Fç×Å~\j}¿5n€CȪÙÚ­4 µ‹ª¢f oªÛ€—ε²¼Ñlh¿…Ê}ýü/ÇF.‘ëiƒÍ¶Tç`3é²ìèÒΖ>n ¾ òŸ½ÿU»EÎZÇÖ‹n'?% ï½$ù’³¾^}±ÞTøùñûJƒu˜ö-WKî’ÛÊ'ÝŸ¹wÓÖÿ´¿±ø³‘ëj¸yáúfexG뿞-;kÕá¡]:„ºžSñÇU^3¹Çi¿ÙÍ67Ç~XÃ[4ãù&¡3¤ò×F+©ë!ÍOcœ_µ›°Þ¯~Çi -¯~ÑQ½Uk-ôÒs½2R©x%Ì»Öù‰ÀÍ#ƒy`=®Ã£×C]ܵßä9uxr-œwÑùurj7/g¿¸@?7R7_;qad¥O¥©³,:Ã}j÷„œëÖ4’›—ï´-­Ûžy¨ÃkóœŠÎ€Ú=sf:v–’¥çÌ:@Ñ`&›³!7ç&:@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè Qþ©Ý¦ó~¿_¯×çó©Ý¶|»h™è õù ]°`€Sªf[^ˆÎ²Èï÷[n:":PÂwAÂ7+[œtÊZg Y§çõ#½0ë @–jÝ1ë @ ë üù|¾Ë6L?}1ë @9ŸÏGbúeÖ€ÎR²ô tĬ3D¨Àd3Ð#Ñ€Òäf S¢3D Šÿ •¾ù/f LõÂOÎÃóãttÏ›ôØ|:jß>1ËÐÀ¨Dgîäc•è À5ß@“†7Z€z':åÉò÷%&¡Þ‰Î„$Ì»r½8–o•……@§Dgþ(9%l!Ðр׫j~µè…è 0»vVMXÈ4Nt˜TËS¼rmæÒQµhè 0‹~WAXÈ4BtÜHS¶ru‰Îc8_ZÈÔ":ŒfžU r…‰Îƒ˜y ÖB  Ñ oòâÂB 7Ñ WV)œ±ÈDtèŒ)Õxri‰Î}ÿn³HEthU©XÈ<$:4Êi>r÷ˆÎm‘犱¸Jth…UµXÈD*3åÙ 9€0Ñ ù¬YrgDg` M݈oª1XÈlˆÎ…˜Âì—…À—è ëý~ŸEœÀ?åhÆ÷òVï,äDg`dûˆ¼„ž2{IW#²¦%:Ãú|>ï÷{ 7ÅB³)ÉyXȳ‘-ɦ@¸‘Ÿ¦e!ÌCt†A¸q#ÓgÏ—…0<ѺáÍøªõ ï‚õ²ç=iŠñ’KŸ[J~3 9`T¢3t#¼Z×{ó™}ˆy¸èYºçRwÑ·rÀxDg˜]ïÓ{gÇuûxMüs…0 Ñ9›LÚ,<øsËï_?rø´ý†×îíüR;gÐË”áþÄmæ×73î½Þ?ççƒË~[Ûo*|1ïí¬‘M±z':Ã}먺ùóëïo;, m_Ñic¿…ÍŽö¶mý´pÃö/¼Þ%M»SzÌ7ëswv}ÆÎá5¶8ÜÚÏápvÏY?ùç´Ÿ˜7,ä€~ý¯v`Lë7ÂÍ›bÌ{ä>ìßb#§¯O ·d°÷òK‡³DƯ|­Jký;ÖûZþ|öœÀ«–ø›°Oö͈oإͶléϾš 33ë ÷ÅÌÎî'Òn$³o¶=¾^†Ӱ×÷•“è} 0æŽAx:¹˜}3’4¬‘£»ÁBè…Yg¸o=7ùóÉW—‡>÷ù+þUß?Ì3öþWwÓÌkQû?ßøðös_7„×l$Ül/6“ÐóŒAèˆYgxäÒ›t/Sb­µ³L€háHŸØÜô_²o&2#ç5ŸxpÙøá¢äõ“ÏšqøÈ2!}¶ë³L?ÆÙ¬Ý à@ï‹p[Ål·N ¯]hxýM*Ÿ¿ßÆ‹iöáó7/ üõ¬ á†í·¢bm&u=×ÂyŸ–ë§>Ò·ºïñûi¡ÃÕûå§1m>|þfû)·Ã9ÂȆÝkgnåOñæCÑÀ èg8ü¦HÌÐ õ‘¾y_²7jÔÌQfÈ ©M3_fÐ)k¡šŸ?ƒ@E5¸Ã3ñ\À<77`0¢3T“ê]SÊÉjÎ =Ã1V1ÕUCaf° ˜3C“„k†!:C÷¼&CÉãn’¡9äz€‰ÎOÉмœ}˜ƒè Œ =!ç¦":¤'CÏ™…9‰ÎÉЃqar¢3@ 2tל5àKt(J†îˆslˆÎuÈÐÍrF€3¢3@e2t#ô?ð“è Ð º ½ Äš#C oDg€vÉÐÉéIà Ñ 2ôCú HBtèÉ&C ‚a3–è Ð¥o é Ñ crl˜Œ²F0y†žó¨òDg€¡L•¡g8F )¢3À˜ÎÐãÐ Ñ`pÃdèÞÛ @t˜E§º¯Öc¦ÓE†n¹mÀ´Dg€y5˜¡Ûi Àžè @ý -1]øOá -1}85CKÌ@§DgBfh‰èè @”ÛZb†!:pMd†–˜ñˆÎÜt˜¡%f``¢3Ý[Þ§ZÖZb&:Ó7oÒ@1ÿ«Ýèƒè QDgˆ":PÚûýö_ G¢3D(!0Ílè…è @!ûˆlåÐÑ€¾¿ÂþÍÊ~‘è”ÿ€BÖéyý@/Ì:P‡¥@wÌ:PÂ:(>Ÿï² ÓÏ@_Ì:PÎçó‘˜~™u „³”,=1ë QDg*0Ù ôHt 4¹è”è QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(ïÏçS» cz¿ßµ›@vÞFa*ÿÔnÀÈ䪱ùt³±`¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":Åûý~¿ßµ[’è Qþ©ÝÆôù|j7 1³Î¤ay0<³Îü±NÀËÌñòàf.ùûøçóùþaùëò¯‘[8ü'€ÖˆÎü¿uð]'ÚM^‚òæ ë§máûÝÁ}¶6c tÁ‚ þ³„Úp¢ýþëg%°©ýƒûÍšoº`Ö€cËìòÉáõZ޳=ËßMø!I€>›„^‚µè ´Ï‚ ~Ë—k—ùfËö‰Î;üFà ›d¼þ_Ï~v MnäÒÝ"„MJÞÿ®Ü¡³ŸŸ;ûëÙ–ûꫯîN1ðµÎü'þ·2~>-ü×K[h„Et€(¢3¯—¸ˆ :ðzù‘8€¢3øêÀÑ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Ê?µ0²÷û]» $óþ|>µÛ°`¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QþÃEÈŒ©FgIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/xml/images/code-model.png0000644000175000017500000102263307752161574024627 0ustar frankiefrankie‰PNG  IHDR„»Û pHYs``zxEtIMEÓ 1.2D IDATxœìÝy|LWÿðÏ}&û"²IDd!‘„b‹5©P¥¨Ú«Z][mý©zªªj+Uª”¨jKk«½¶ ±•HD$!²ï“Ì>óûãÔ<ÓˆUC}߯yyeî=sî¹gî˜ïœírƒ„B!„˜ÏÜ „B!Ï/ F !„BˆÙP0J!„B̆‚QB!„b6ŒB!„³¡`”B!„˜ £„B!Äl(%„B!fCÁ(!„B1 F !„BˆÙÌ]€?½^_WW§ÕjÍ]Bþ.Žã$‰X,6wA!„ü{P0úO©¬¬,..–Ëåuuu"‘H(š»D„ü]z½^¡Pðù|KKK;;;€þ!„ò·pƒÁÜeø·ÑjµÙÙÙeeeÎÎÎ666VVV‰’ ÖÒ/—Ë‹ŠŠ´Zm‹-ìììÌ](B!Ï0 F³šššŒŒ ±Xìãã#•JÍ]Bþ)z½¾°°077×ÅÅÅÓÓ“ã8s—ˆBÈ3‰‚ÑÇI£Ñüþûïvvvîîî<M#ÿ~µµµéééÍ›7wvv6wY!„<“(`zœnß¾Íçó›7oN‘(yNXXXxxxäää( s—…BÈ3‰b¦Ç†ÍXòööæóùæ. !OŽ£££­­í7¨›…BÈ# `ô±©¨¨°³³³´´4wAž1:î¿ÿýï_|ÁžVVV*•J󉩨¨¨ªª2w)žÇ5kÖL¡P¨T*s—…Bȳ‡‚ÑÇF.—[YY™»ÏŽãlmm/^ @¯×:týúõ'ÃO>ù䱬ꚜœœ––ö÷óyˆD">ŸOÁ(!„G@Áèã¡V«Õj55‹>mü{ݺuÆ û;Μ9S­VÿÍRݺu«¸¸¸M›63Ÿç„@ ‹Åuuuæ.!„g-Xýxèt:Žãhðg0öìÙ³hÑ"[[[cÌ·oß¾O>ùäå—_~ñÅGUXXÿÕW_ ‚íÛ·gee-X°@¯×{{{/\¸-o¹råÊï¾ûN 4oÞü½÷Þ[°`Z­NHHàóù?üðCMMͼyó®\¹Âãñ¦L™·zõêü±k×®¿þúë­[·ÜÝÝY3ê²eË222V¬X7iÒ¤}ûö…„„X[[›³ŽžÇYXXÈårs„Bȳ‡‚§Ç†ã8ZjñÁ•””Œ=zýúõ;w~÷ÝwÙÆîÝ»>|øÆÇ­X±ÂÒÒ²E‹?üðüyó †ºeË–ÐÐÐ3fL›6mõêÕ)))Ë—/ß¿¿L&‹‰‰¹|ùòÒ¥K7mÚôÍ7ßH¥R±XüÆoètº;w¦§§'&&¶lÙò•W^¹téÒÖ­[7nܘšš*‘HÖ¯_ëãã#“É„BáK/½`ÿþý/¼ðýºxp|>_£Ñ˜»„Bž=ÔMOÌãèÑ£½{÷¶°°:t(Û( w«’Éd^{í5WW×åË—ß¼yS­VŸ>}zÕªUJ¥r÷îÝ:nÇŽlÖ¬™½½ý† ÂÃÃÙ«,,,,--õzý7ß|óÊ+¯XYYEDDïÞ½[, …ÂÁƒ=zèСcÆŒùöÛo•Jå®]»z÷îmkk[TT”––Ö­[7sU!„òü †bJ¥R&“±¶äFÆÚŠÅb@¡PØÛÛ{{{sçííݧO>Ÿ_SSc|mPPP½×* NgaaÁžòxŒ>£>üÝwß †¶mÛŽ3€N§Ójµl¬*ypŒBy4ÔMOžkÞÞÞÆ.{>ŸÏçóÍ[*B!äùAÁ(y®yxxL˜0ÁÜ¥ „Bž_4›žB!„˜ £„B!Äl(%„B!fCcFŸ„C‡]¹rÅÜ¥ äñðññéÛ·¯¹KA!ä_‚‚Ñ'!%%eÍš5æ.!Ç Aƒ(%„ò¸P0úätíÚ500ÐÜ¥ äÑ]¿~}ß¾}æ.!„ FŸœ!C†Œ7ÎÜ¥ äÑmÛ¶‚QB!M`"„B!fCÁ(!„B1 F !„BˆÙИQBEyyy]]½½½L& Ñh.]º 88X(š»t„BÈ3ƒ‚QBÚáÇß{ï=__ß‚‚‚-ZDDD 0`Û¶m»wï>pà€³³³¹ H!„<3(%ä¡mÙ²%>>~òäɧNª««srr²¶¶~ã7~ùåƒÁ`îÒB!Ï F y8gΜ9þ¼J¥Ú¾}{PPPff¦¥¥e½4J¥r×®]iiiÎÎÎ/¾ø¢i[i]]ÝŽ;„B¡““ÓÁƒÝÝ݇.•J«««÷íÛwáÂ++«øøøÖ­[îÞ½ÛÖÖV¯×Ÿ?¾gÏž¾¾¾_ýµH$9r¤ƒƒ€[·n¥¤¤TTTDDDôíÛW$=Ѻ „Bþ6šÀDÈÉDb±X&“Éd2¡PxàÀ7ÖK³lÙ² 6ôêÕ«´´tâĉr¹Ü¸‹ÇãUTT¼ýöÛ_~ùeóæÍ?û쳯¾ú ÀåË—W­Zåèè8bĈ¼¼<—žž>bĈ3gÎÈd²ñãÇO™2ÅÎÎî§Ÿ~Z´h€òòò#F(ŠÎ;/]ºtíÚµO²!„Ç‚‚QBNÛ¶m›5k‘””àïï_/AMMÍçŸÞ·o_™LÖ£GÔÔÔ«W¯÷J$’.]ºˆD¢™3gŽ7.))‰Í| š3gÇsvv–ËåW®\qrrŠŠŠòññy÷Ýw§M›&“ÉúôéÃBÒôôtG-..ŽŒŒ´³³‹‰‰Ùºu«iÔK!„<¨›žÇ¬¤¤D.—Ÿ?þæÍ›âââîHêââbgg@*•–––Ø·oß‚ mmmR©d)e2™X,æóù<ÏÖÖ€@ `Þ¹sG.—ÿüóÏ<O«ÕvíÚU£Ñ<É3%„Bþ> F yÌœœœlllØ¿½^?wîÜfÍšÕKÃqÇq¦[¾ýöÛ®]»Îž=ÀŽ;ä@Í›7wpp˜5k–ƒƒÃõë×wîÜieeõ¸Î‚By2(%äáœ={6;;ûرc-Z´pvv>þ|EEÅñãÇ/^¼XVV¶{÷î—^ziÒ¤I~øammíµk×nܸammm|¹B¡Ø·o_QQÑO?ýÔ¾}û3gÎäææž9s&""âË/¿Ü²eË;w222~ùå??¿#GŽ>|X&“•––Ñ„Bž1ôÕEÈÓ&MbðùüAƒ±¿›4i2þ|;;;Žã&L˜xùòeÿÉ“'›6Xrçíí=kÖ,[[[>Ÿ€ÇãMž<ÙÏÏ/+++00pýúõ%%%</<<<$$ÄÒÒ’ã¸ùóç³”íÚµ ¶¶¶7nÜ¿aaáÛo¿f¦*!„B£„<œãSöG‡L“õèÑ£G÷¾\"‘¼ð Ƨ­Zµ2þW/±éÞ7:99 6ì!JO!„?ŸZCÉ?ǃ’S*9e%¯2[®NÏWæwÓuë(íÈßÜ¥#„òÜ¡`Ôü´mª"u·g›l›’Sš»8ä9¢…6M”v‡G_«wâ;ù‰üÌ]"B!Ï FÍ/K“uLìg‹Ÿ)%Ož†~ÁO’Ÿš+›»\lx6æ.!„ç 3³Z}í)Õ©ÝâÝe¼2s—…<¿.Š.9¯ô«[@ p˜uÿê*¾®ŽÀ )Pl.Í€×î¶Ë¶ÀÚ$ÝìÀP »Cû6 ÐÂdË^ 3p¸„ÞÝ8pÖïn|hœâ€\ pºk€‡o %„Bþ¨eôiR \†6ÀI@!pèð°ø€#¤¹€?Ì!nƒè¬¾j%€Ø¤EÀ6@,Ñ€Ý'à  è£€ @ Ø@Øßížæ ðÏ}ô¿ïn@0 ¨ôÀ(àw ø˜}ÿ‘€L` ²ó€ï€ÞÀ`" r€Á@ =°`­~;×€V@0Èl´ÆÎ­M*YìíÝN)ú¹@ÕŸ·×:“ ¾=põÁZ— !„経>M®r =Ðø Ô5÷„›€ËÀ`&Ð øð|àCl,€è|ô$@/àШ.xÀÀ p8 h(ÃHÀ¸H$@S`âÝd¼»­ùuÆ`pp7€æ€°ýþ'r (~,€>€Ð€í@O %Ð(v^À»€Ƚ;ˆv„<ÀøhäÆC×LZ:\².€Ø ¼ùçÄ€Û€ ðÊÝ:‰šßMÓ ¨äwÃtb>UUU§OŸ¾pá‚V«åñxíÛ· ³¶~*ÞFsêÔ)NתU+WW×û%+..>yòdzzº^¯wrròòò µ··7MSXXxôèÑììl½^oeeåëëØ´iSï¾¹¹¹ÙÙÙÆ§"‘ÈÎÎÎÃÃÃÂÂⱜ݃;wîÜK/½4vìØ·Þzë úA”••%&&zyymܸñ=PFFF|||§NÖ­[÷xsž9sæöíÛ÷ìÙãííýש“o¿ývÖ¬Y .8pà;(yšQ0ú4Ù}·Óü&ðp Ö€öÏÉlÿïéÀ `°êq(´w;ÍE€#€Øu!à.@qC¹€ ÀJ °T?,Õêîq èïÆm-{r@à!pPÜÐÐE@àv÷2÷®rj`@}7“t àBàPp7îd€pî‹î€'à´½§Ðº‡ºJ+ƒÁpðàÁwÞyçÚµkJå «Éd²ÀÀÀ ôìÙÓ¼ÅpüøñªÕêI“&}øá‡÷Žz½~Íš5K—.½yó¦ZýÇê°R©´E‹“'O9r¤H$’’2sæÌœœîÑÀb±ØÁÁaÙ²eIII÷;ú¶mÛæÎk|Êçó%‰­­m÷îÝGŽÑH Û  ÈåòwÞy§^ ü— EfffiiéC½ê‰ÑjµÙÙÙÁ?þMªV«333==={ÎEEE™™™ÆKèɨªªÊÌ̬ªªúë¤äù@ÁèS£8„  9 \¢àÔÝYðµ€àà¸}_æ(ÍV€ñ7<¨¸†Ækh€;PØÝM/½ÛÙÍvm¦Ã°çÏ9<ÂL€äÀ•FSº¥€Ödä¥ Ø}¬XÉ›nÀo€à™w‹ä$£ïmüCà Ü4yº t@ÀØ$šì=8öwƒÑa …Ô€ œÎNž˜]»v½üòË …bèСÆ kÖ¬YAAÁºuë¶lÙ’œœ¼mÛ6³Ç£[·n­¬¬äóù)))3f̰µµ­—`îܹ}ô‘T*7n\RR’‹‹K]]ݾ}û¾þúë  8ÐÑÑñÒ¥Ko¼ñFEEŨQ£^|ñŦM›VTT=zôû￯¬¬lä覮®nÈ!:u P(222NŸ>½víÚíÛ·OŸ>}Ê”)íÚµ«¸¸x„ ŒBžŒ>5®ÅÀ: зÝ@,0ø¨Àqàsà𠨀¯€¡s”$à`5и4bî“R,ìs€únWµÖ p¾;£¿°ëÏA› ð-à¸Ñ@>p8)€3е¡ƒ6ú£€AöÑ耷Ào@ fÓ€M@WÀè,–Àz ð*°pl€_á@«û( 8 ¨p 8¤Ü-¼ Ø ô¬Ê€£ÀtÀȽ†g »MÂÄŠ‹‹ßxã ¹\>þü·ß~›µ úùùuèÐÁÝÝýƒ>xíµ×Μ9so½Z­®¨¨àìì|¿Ì+**Ôj5ŸÏwttl¼ ƒÁÉɉã˜=WVVöý÷ß{xxDDD|ûí·xá…LìW&ÇqŽŽŽÓ§O3fŒ\._¶lYmí³ð.^¼8qâÄÐÐPV9íÚµ›={6ûnfe>|xFFFQQѨQ£ú÷ïß¿ÿo¾ù€B¡øê«¯zõêe¬´Þ½{ïÝ»×8¢ÀH©T~þùç‘‘‘ì-:thVV–q¯V«Ý»wï AƒBBB"""ÂÃÃ;vì¸zõj…BaL£Óé~üñÇnݺ±c…‡‡·oß~Õªÿp2 ©©©C† a'6|øðk×®=Håèõúýû÷ÇÄÄtèÐ!22²OŸ>ÇŽ3Mpþüù‰'²â±*š5k–±ŠŒ222Æß¶m[–,<<üƒ>¸ßAårùÔ©Sccc?ûì3¶¥¬¬lîܹwuèÐÕ³©´´´¸¸8VÎÈÈÈÍ›7 R*•ÉÉÉ£G6öã_½z511±ÿþyyyl‹F£6lبQ£X @¥R}ñÅÑÑÑì:ˆˆxÿý÷ïmŒW(üqDDDÇŽÛµk7aÂcž÷3vìØñãÇïÛ·oÀ€aaa]ºtÙ¹s§é5sãÆwÞy',,Œ½]»v“'O¾7ç#GŽôêÕ‹¥éÖ­ÛO?ý´hÑ¢_|ñÖ­[¦•¼|ùò¨¨(v‘‘‘Ÿ}ö™ñ4”––NŸ>ÝøÎ†„„ÄÆÆ^¿~½ñ³ 0Ç¡®®.--M¡P4¸wìØ±V¯^}ï®j~ðWûÀ§ëQD§Íqè=À¯ÀEà= §¹ë=>>ô#«½Àë€ÊÜgtŸGrmò%å¥F®ó””ƒ ºwW^^^ffæ£}|ž$µZÇqÜG}tï^½^ÏÆJ¾øâ‹lKzz:™LšœœÜ¶m[®®®¦ç{æÌÉÉɽzõ‹ÅÎÎΗ.ý¯>Åb±‹‹‹¿¿RRRß¾}%‰•••i¦{÷î|>ÿôéÓ*•ÊßßßÒÒòÆƽÅÅÅŽŽŽ<ïÊ•+Ÿì§Ÿ~Êq\Ë–-ÓÒÒôzýƒ×Ò‚ ,[¶ìÞ]gÏžµ··wrr2iÊ”)ÎÎÎ=zôHNN0`€‡‡Ç>|¸\.7 yyyIIIÖÖÖ2™,222:::::ú«¯¾2 YYYÞÞÞ HNNîÚµ«D"qppصk—ñp,ªóõõµ±±éرã€üüü8ŽëСí[·XšªªªŽ;¶hÑ"...99¹wïÞ666b±øÃ?4æsðàA;;;›>}ú$''ÇÆÆúùù%&&8p iÓ¦B¡022299¹K—.‰$000##£‘Š*,,tsssqqqrr JJJêСÇsuu=qâ„1Ù¤I“\]]cbbX±ÙcÉÉÉjµÚ˜æâÅ‹-Z´à8Îßß?!!aàÀ!!!¡¡¡lï¥K—ôêÕ‹=-**Šåóù£Fªªªb•Ãqœ——×€¥Ré§Ÿ~j?<<|À€mÛ¶uqqñññqpp0~¬jjj^}õU@àââ7pà@ooo‘HôöÛok4ƒÁ R©&NœÈçó[µj•””4hРèèh;;»ýû÷7r ¤AŒ>ÿ¶`´x ¸jŽC¯q@®¹ë=@Õã«ØsŸÎýÏC0Z[[ëïï/‰>Ü`‚;vfOY0ÊqÜØ±cËÊÊ Ciiirr2€ádz4Z­¶]»v-ZÄzý ÅêÕ«y<Þ /¼ ÓéX2Ö™˜””TPP ÓéT*Õûï¿Ïãñ&NœhLc0._¾laa^WWg0æÍ›ÇqÜ¢E‹ŒÑdjjª……EóæÍÙ±‘““ãëë ÀÉÉ)66vÁ‚())ùËZj$­¨¨ðññá8.--m9uêTff&+­N§»qãFÏž=%ÉñãÇÙ–ÚÚÚððp//¯k×®Éår¹\΂°òòò£G–””hµZƒÁ —Ë¿ùæ›^½zÿ/eÁ¨@ ˜={vUU•V«½q㋺Þ}÷]–F¡P:tèÎ;,[¥RyìØ1www__ß‚‚–fòäÉ"‘hýúõ,R«Õ………ÆŸÅÅÅ!!!,tc±]MMÍÇÌçó_yå•F*Š£Ç%&&êtºòòò)S¦°ÀÑø¶?~<;;›”V«ÍÊÊŠŽŽ–Éd¿þú+KPWWÍãñÆŒ“ŸŸ¯Ñht:]YYÙo¿ýƘ£7nÜèСƒP(œ6m«v½^?oÞ<ýû÷ÏÍÍÕjµZ­öÒ¥KŽŽŽ¶¶¶lð€Á`>|8»Ù5PVV6vìXÖ3ÞH0:{ölŽã6mÚÄž&$$888…ÂaƱ7nÕªU<oñâÅ,Áž={d2Y‹-Μ9£R©ôzýíÛ·»ví*öíÛÇÒ°`T ¬^½Z.—kµÚk×®………q÷ÙgŸ5Rá-[¶d1kVV–N§«®®^°`X, 1^ØçÏŸ¿råJmm­^¯×ét·oß~ñÅù|þÖ­[Y¥R`Ê”)eeeZ­¶¸¸xäÈ‘LƒÑuëÖ ‚öíÛ_¾|Y­Vëtºôôô;;»3gÎ †›7ozzzæääèõz½^/—˯^½j¬pòà(}<þmÁ¨PÜôýä @þ˜Z"éñ0ç!•Ëåîîîb±øØ±c &`ýï~~~ì) FmmmMc¸ììl‰D"•JÙGþìÙ³<¯]»vƆƒÁ V«CCC-,,Xpc0Äb1ŸÏ¿yó¦1ÍÍ›7%I=L[ÈÞ{ï=Žã>üðC}^ºtÉÂÂ"$$„54 †C‡I$’¶mÛÖÔÔüåùž?~À€Æ¬,Jøè£jkkyU#Á¨Á` `Ú~ÉTVV²îoctb0Ú·oïåå•››Û`†¦¸¸¸°°0//¯]»vžžžÆv8ŒÓ:tH*•›¶u NWZZZXXXPP0zôh 㻟_¯±|ÆŒX«¡B¡J¥‰$++˘ ¤¤„èh$=pà€P(1b„V«U(®®®±±±ÑÑÑ>>>ìšdË2¤¦¦²ôC† aí¦¦ñ?ýô“D"1þîbÁhTT”é5¼yóf‘HÔ£GF.NÖÈúóÏ?·TWW‡††òùüC‡ÕK\]]Íjû»ï¾“Édo¾ù&Û~åÊggg///Óãï¿ÿîêêj FÕju=„B¡é± ÃçŸ`Á‚ƒ!==ÝÙÙ9 ??ÿ~&ˆ&0‘†p¹àÑãeÆC“ç^yy9€zócM'$yxxxzzfdddee²NpK—.5}k,,,4Î…ruu5]4´yóæ|>¿¦¦Æ8lT©T¦¤¤H¥ÒAƒ±&«€€€ˆˆˆ£G^ºt)22€H$âñxjµúÞÁ¦÷jÛ¶íæÍ› O:uöìÙÓ§OŸ;wnÆŒ555ï½÷Þ#¬IÄíGVWW¯_¿~×®]999Z­¬YTt¿[eüOZZÚ_|qâĉêêjƒÁÀ^eaaÁ¦à…††:99Ÿúøø¸¹¹••••––²iFYYYëÖ­ûå—_ÊËËYµTUUÕÖÖÇeÆÅÅ¥¤¤L:õçŸŽŽŽŽˆˆ 2¥eï V«5}Õj5›r”——çïïâÄ Ó3 7.´dggÇo0mÚ´9tèPnnn«V­Xa¾üòË;wÞºu‹U‹zoß¾Í^råʽ^ß¾}ûÆWÈÊÊJHHÐëõ7nLLL4N÷¹sçN^^žL&Û¹sç®]»Œésrr°T7oÞT*•~~~^^^ÆŽŽŽÇoä lñÝ“'OªÕê³gÏ–••õìÙ³¦¦fΜ9™™™­[·NMMõðððóûcÆÀ… Ø¿ÆLXÕåååi4ã|£¨¨(KËÿ-,amm““S[[ÛÈ/''§àà`ãS++«°°°´´´«W¯vëÖ @mmí·ß~›’’’••Å[«T*¥R™›ûÇÄÒÜÜÜ’’’=z4kÖ̘¯¯¯››«1V¥ÙÙÙR©ôðá×/_6­RÇ’¹»»‡……íÙ³§gÏž½{÷îܹsHH¦ÒH}’Q0JyŽðù|77·üüü;wî4˜àæÍ›š4ibº±Þ Žã²/Ýk×®-Y²¤^nNNN¦ßLÀt¾ð½“>|óæM›>øÀ)VUUéõú¯¾ú*""‚ÏçÛÛÛóùü¼¼<…Bñ KôK¥R/////¯¡C‡VUU­X±bîܹk×®?~|#ËéßÏ­[·ªªªØb¥êêêÆŽûý÷ß·hÑ"88˜µ:߸qã»ï¾3?Ô ãÇ>¼¬¬,,,¬M›6¬0[¶l‘Ëåõâìzo‡………µµuuu5[#öæÍ›ƒ¾zõjpppûöí›5kÆãñN:õë¯ÿ[÷.11qÕªUk׮ݻwïwß}gccÓªU«yóæõêÕ YΜ9óûï¿×+$;M•J5þüƒ·oذÁŒÖ{—…B¡ƒƒƒV«e!µB¡?~üöíÛ}}}U”——ÇzÙKØO 6ì¸J¥²uëÖ‘‘‘¦ë¬W*•Ÿ|òI½—899±)ùì*upp¨7cý/Û²±±iß¾ýž={²²²~ýõWFÓ¹sg¹\. ?^[[[ZZgœ/Ï…Ý´iS½Y[[[[[›n¬7‹N&“ñùüººº{g°Õ˧ÞôyVo,Ê×jµ3gÎ\µjUóæÍýýý===e2YqqqJJ K@§Óéõz‘HdúcL$™N¨W«Õjµº¶¶vÆ õ‚KGGGv²2™lùòåüñîÝ»?ûì³+V4iÒ$66vîܹðÉzÎQ0JyŽˆD¢víÚ>}zïÞ½ƒ®·W§Ó:t@‡L·×ÔÔ˜>5 ¬É} ²x%..náÂ…÷±iÓ¦^¼M›6i4½^oÚ¾@ ìܹóý÷ßoÒ¤‰¯¯oóæÍ¯^½züøñF®oͤI“V­Z•ŸŸ_PPð_™'Nœ(..öóócâÙ³gwíÚÕ·oß+V¸ºº²¯íÍ›7—#hÄÊ•+‹ŠŠÖ¬Y3pà@Ö¦T*=š™Yÿ½ÅźëFmmmuuµH$baÖöíÛ/\¸ðŸÿüçÝwßµ±±aáÎĉMƒQ‘HôÊ+¯¼ð ùùù©©©{÷îýùçŸÇ·wï^ãj#FŒxûí·ëšÇ㹸¸ðùü÷ßÿõ×_7n 1-ž^¯7†,¦¬¬L °`+--mûöí½{÷þòË/ÙÌ37nܺu«1V™………×XxxxttôÂ… ããã7mÚÄPâî%›ÔÔÔ{_Å:âÝÜܰqƦa½ºmP×®]÷ìÙsôèÑC‡yxx´lÙ’ÇãÙÚÚ8p ªªJ¥RõìÙÓØÙÚÚ–––nÞ¼™W6%•JM¾zóëkkkµZ­­­m#Ë{`G4ÝÂêå|íÚµo¾ù&((hëÖ­žžž¬TGŽaCŒ+++©TZYYY[[kŒ¡«ªªär¹1P(ŽŽŽ,Ÿze06èzzz.]ºtúôéׯ_?~üø·ß~»víZ½^ÿùçŸSûèC¡`ÔÜ8H ‘¡. =ôJ(Ÿ|‰È¿|qý;ÌþAу¯ó÷Œâñx/½ôÒš5k~üñÇ´´´ÐÐPÓ½©©©?þø£D"aS=Œ.]ºdºegggeeYXX°h€eráÂGGGÓnLJ•ŸŸ¿wï^WW×ýû÷×Ëgúôé[·nÝ»wïðáÃÁСCgÏž½xñâèèè{4={öl`` T*U*•b±¸Á÷´^Dò€®^½ºhÑ"F3pà@cÛp]]]ûöí1·N§;pàÀƒä–——çèèØ±cGcŸlFF†±ŸÔTZZZaa¡±á0333??ßÏÏõÝçææŠD¢Þ½{o PVVvoXÆqœMëÖ­_zé¥)S¦¬Y³æêÕ«~~~¡¡¡<ïòåË÷[“’‘hPYYÙÙ³gÛ·oo|zþüy‰DÂfˆgggkµÚèèhãH­VË~ó …“'O5²Š­T*5kÇq|ðÁÀwìØÁ®@WWWÛ·oß¹s§cÇŽ ¾ÖÛÛÛÂÂ"+++;;ÛÇLJm,((¸zõêýgÔ¥K¡P¸cÇŽ³gÏÆÇÇK¥R>Ÿß±cÇS§N•””p×¹óÿnš‘••uþüù=z4;v¬¦¦ÆXál´FHHHã¢âââ .{Ø+++SSSA@@€ŠŠ …Bf}ºººúÞUFPänfbNl¯·×B{ïC÷(·0"ä/è¡oðz`¯··àžôÍÇŸ¼ððð#FTTTŒ9òرc¬G˜Åì¶LãÇg_lF …bÚ´i¬!§¤¤dêÔ©jµ:))‰-SÊ–„¼víÚ;ï¼cV¨Óé~ûí·¯¿þúAFv2ìÆH½{÷fÝ‹¦ $ SRRX›ÐرcÛ¶m›ššúꫯ^¾|ÙxˆÛ·o/\¸ðÕW_e‹€Îœ9sêÔ©/^4~/X° ¨¨¨eË–¦æTWWW\\\\\œŸŸŸ––öé§Ÿ&&&^½zµgÏž'Ndq†£££D"9pà@~~>•JµaÆï¿ÿ¾^VM›6---½~ýºÁdUK''§ââ⃲^òœœœ9sæ48Ò433sñâÅl}Çììì9sæ¨Tª°¦G777¥R¹cÇ– ªªjÁ‚lÆiݦ¥¥[Ôªªªnß¾-•JY'u‡BCCO:õÿ÷¬Ç€R©>>lo½uFµZíÊ•+%I³fÍNž>Þ´*ºtéÂqœµµuÓ¦M---£¢¢‚‚‚UQ[[ËV³µµe·±`—Ÿqa¸‹/:99¹»»‡‡‡'$$ôêÕ‹ ']»vmã•IîÅg+<“¿I«Õ–––6iÒ¤ÁÙ©?ýôÓo¿ýVÿ…Ð^Õ\=+:«ç´ù„B]“Xml˜8LÀÝwôΕ+W¶oß0hРz»ª««µZ-ëº}úI¥Ò>}úÊåò›7o–––*Šˆˆˆùóç¿ñƦ·.,--]±bE\\ܬY³.]ºtãÆ í­]»–M”fÜÜÜù|~AAAIIIii©T*íÚµëØ±c[¶lÉ:Ä/_¾Ø¿Ó¾Ëßÿ½M›6=zô(--MMM zíµ×î½½¡D"Ñëõ‰ÄËË˸th||¼««kMMÍ;wØj¾¾¾Ó¦M›1c›cÞ¦M???•JUWWWXXXQQaee³xñâ¾}û622¯¸¸˜­äââââââééóÊ+¯Ì™3gèС¦÷É”J¥QQQr¹üÎ;ÅÅÅ–––“'O5jTMMMçΣ Zµj"“ÉØZèááá>>>ÞÞÞUUUÁÁÁŸ|ò‰‹‹Kß¾}Y/gmmmAAÁ¨Q£bcc¯\¹’ŸŸ/‹ °xñbÖ ÀÑÑ1,,¬¨¨¨   ¬¬ÌÕÕuΜ9ÑÑÑ:®oß¾¬a’Ïç+ŠÊÊÊ’’’²²2{{û1cÆÌ™3ÇxÅzxxôèу5n•–––••YZZvïÞý•W^iÞ¼ùý*J«ÕÞ¼y³sçÎÓ§O¿víû}¹lÙ²ððpã{Çfü‰ÅâW_}õõ×_/..fó¯Y²&Mšôë×ã8V€ÊÊJOOÏ &°…´Ødðˆˆˆèèh</44ÔËË«¦¦&77722’­çïââRQQÁrP«Õ­Zµzýõ×%±µµek¿—––ººº.Y²„…‰‰‰‰O† …jµºk×®ƒfWŽ““Svv¶——׈#L‡‡òx¼N:UWW•””ÔÔÔ¸¹¹5*>>ž5f———³;H………]¼x±¨¨ÈÒÒòÅ_üè£L—M¸×òåË­¬¬V­ZURR’‘‘¡Ñh‚‚‚–,YÒ§Oö± …ÑÑÑz½¾   °°ã¸áÇÿç?ÿ‘ËåmÚ´1'°µµíׯ‹,===‡ ööÛo³ÎcÆŒa…dYyyyUVV–––×ÕÕùúúŽ=ºW¯^2™ŒÇ㱫ÒÚÚÚ÷ßРA{%÷â Þ Œ< …BqíÚ5ÿo%£ÜÂÂâ/¿¼ÿr¡œÇŽu7’€­4ô–A(6Þ u?ÇYYYÝoÎP=§”J¥5dQì_–ç‘ëJ,7r- …Âz T=ö02™¬ñ‹B¡ðÉ,<$ ÿr±*¦ íN$5’9ŸÏo¼óòò6nÜØ±cG'''½^åÊ•yóæÉåò¤¤¤{C[‰DÒȯ‚¿¼ðȃ `ÔÌ8pâ€hmt–*kŸdMZ"Ož•Á*^ßIÜÉEð×ß„ò¬S©T«W¯^¸p¡………Á``7‚>|øˆ#Ì]´ç£æ'á$QÒ¨’Ú ½Å~Éþ*^•¹KDž8­Gœ2®+¯k(ˆÃ¿|]§G`ii™`zBˆ¹ôìÙ“Çã5>œãAxxx¤¤¤=z”XH$]ºtéܹó?:n4‚‚ѧ‚ß)É"ÉEáâYë¹O²/ŸWͫփ¦4‘ŠCM›uL´(:P(âh¨Sš5köÃ?˜»„X±bÅcÉG$EEEEEE=–ÜÈßGÁèSçÈwìkÑ×SíÙZÙ:ß_•Üáß)ã•é8ê¸'“Ø vÖ9»è]œ Î^<¯ö²ön7j%„b.Œ>EDœ(Xì'ò«Ó×Uê+Ëu嵆ZÎ@QyœxàY ¬ùŽ–ß˜àÎ;éééjµšÇãyzzúøø˜î%„<« äq¨««KKKS( î;v,€Õ«W?áRòx¥¤¤4hн»òòò233Ÿ|‘Ùùóçù|~—.]”JeTT”D"ùí·ßŒ{,XàààÀÊÊÊÕÕÕÕÕµyóæ÷ËêÔ©S666ì?U@àíí½aý^ßHRRRø|þÊ•+[ª««'L˜àììÌq¡Pèïï¿eËNÇœ;wÎÛÛ{È!¯½ö+Çq...Ë—/×h4Æ|ÊËËGŽimmÍÊãââ²téÒîÝ»WVV6R¤o¾ùÆo¿ƒÐ IDATÏÏ…wR©´GS§Nuuuýâ‹/X‚Ë—/7iÒdàÀÆ—lÚ´)((H&“±c‰ÅâÐÐИfÛ¯_?ÿE‹µjÕŠenii9dÈ‚‚‚zÕØ£Gc±‡‡Gjj*Û«R©Ö¯_ߪU+¡P€Ç㹺ºÎ˜1C.—7rF„gµŒBž;z½~óæÍ† &‹‡ ròäÉ­[·†††²:tˆ‹‹Û°aC‡¢££4Ò ˜““#‘HÞyç–-[ …Â'N|õÕW“&M  {ðRÍ;÷óÏ?wssûïÿëìì|êÔ©/¿ürܸqÍš5ëÔ©µZ]XX¸k×.kkëñãÇ·mÛ6''ç£>š1cF—.]‚‚‚X>³gÏÞ¸q£——׬Y³š7o~äÈ‘ùóçWUUµnÝZ¯×ßïègΜyóÍ7+++‡ Ö½{÷’’’/¾øâôéÓµµµr¹ü~¯úý÷ß=<<^~ùeOOO•JuøðámÛ¶MžÓI¨&Õ''˜S%Æ}å­O‡§ÞmÖÛÊPÑÖµ~ D"™9sfVVÖ˜1cú÷ïïêêJ§ÓïÞ½ûùçŸ?ÓUôz=Žã,‹õ”_Tªmkkd\N½4 N¼¡ 5=o,/_Äã=pv†Ny`†„BÄbi 6[Zv Gš:¢Wˆ$Éääd¹\Þ¡CGGGã·,--³³³:4wîܶŸP¥Rýõ×_:tØ·oŸ¡ƒ;//ïY³±±Á0ìÑ£GAÒM…BQQQÁáplllÚx[[[ƒñðáCNgh-..V*•Ôü‰D">ŸÿèÑ£êêjÃc!¢õ¹wï^VVÖÈ‘#·nÝjÈ# ¨Äºí,---,,Œ›f Äb1F³±±Ù¸q£qË1àí=Á&F’xuõ½þ¬½=d¢À”,,­­¼¼|±FSdêX^!FsðàA‹õóÏ?Ÿú¿víÚ…¢–dBQ“rþu·!©TªÕj9ŽaBè—_~yÖÆÈîÝ»³Ùì£GVTT ÷îÝ«P(BCC iî¿ gÏžMKK#I!¤ÓévîÜÙØØØÊQL&³W¯^:nË–-†[¾uëÖ… Z9J©Tj4¡PhÈz•Jå¾}û¨ë¶££c@@@uuõÞ½{ûú :tèàì윕•uíÚµfoétºgº ‚ÿbš˜V[\_¿ÙÅEÏ|Ë»FÁ@,FRin]ÝGÇŦŽåUÉÈȸsçN‡ºvíÚì­Ž;vêÔ)+++--­[·nžžž,ëèÑ£433Ã0,$$äÉÚÛÛ»ººfggoܸqàÀz½þСCÔ¢ÂÏX```ÿþýSRR&Mš”  ÓÓÓB³fÍj{2êéé»aƱcÇN™2ÅËËëôéÓÇÿ×yT3fÌ8vì•þ8°®®nÛ¶m­O¥wss‹Å‡îÞ½{XX˜T*ݲeË… Ú¸€€ƒÁ˜5kÖÅ‹7lØ€9r¤……E}}ý‰'>üðÃÀÀ@—©S§&$$̘1ã›o¾éܹ3‹ÅR(—/_~üø1uàÍɨ‰i4EVÁåš:¢Ñ•YWw™$q { 7¶Áq|ïÞ½AP«5{—ÉdŽ1"33sÿþýݺusss›5kÖŽ;"##9ƒÁ¨­­mñ´?üðÃܹs?ûì3[[[ÇgΜ¹qãÆgŠÁ`¬[·N.—Ÿ?þÖ­[T6Æf³ããã?üðÃgJï–,Y¢T*“““¿ûî;„³³ó‚ ~úé§Ö Ù´iÓ·ß~›œœüûï¿s8œ÷Þ{¯gÏž¿üòËÓ øøøLž¢6Gx&ýû÷_µjÕÒ¥K—/_¾yófsss¹\NÄ AƒB4mîܹ‰ä—_~™6mš@  ’Q*o~ÖkÚHFM¬©)Ã!`â22Ò° ŸÏ_±bŨQ£N:UQQa˜µµuHHH—.]Z¹#À›Á”Û?½Ež{;ÐÇã*+IÂ|½æ/~‹å ÊÊ*éOþ¬’o×v o±ÆÆFãm?›ššæÎK£Ñ¾úê«Öw(-//×ëõ†——.]²³³svv.--}…áÞyÐ2jbz}=5ìÖ-´eËÿy«K4{6ÒhÐèèQ¤T¢#Ðĉ¨±­[‡fÎDNN& ¼ZÞà‘ÉD † ÇaáÆ7Ø­[·zöìéîîÞØØxåʕӧO;::N˜0¡õîþØØX›.]ºXXXŸÿ*.¤×ëËÊʨmÖY,–““—Ë}zz½^¡P`Æår[Ù¶T§Ó•––655!„8ŽX,ÍÏW*•åååjµ!Ä`0lmm…Baë ì«T*FÓ¬F£YZZ¶ …$ÉÊÊʺº:„ŸÏwvvþ×C(¦¤¤D©T2 ‡¶,wx ¼sÎ;«T*y<‡Ã™ï߯*óÍ7—.]R(L&ÓÓÓóÛo¿6lXëI3à5€dðnÑét›7onhhØ·o_pp0F{Ž%9ÿÕéÓ§cccëêêºuë6fÌwÿþý”””™3g¦§§¯]»ÖÜÜü¥_´ípß¹sç;wBûöí mÖ¸¨×ë׬Y³bÅ ­VÛ­[·°°0¡PXUUuõêÕÅ‹?|øpÇŽ¡k×®7®¾¾¾K—.Ý»w·²²*//¿yóæ±cÇæÍ›×J2ZQQ‘‘‘áâââââb(´°°h=5$IrÇŽ ,°±±‰‹‹c³Ù)))+V¬hjjúñÇ™O±$•JgΜyúôéîÝ»GEEåçç=ztêÔ©¿ýö[ÿþýÛþܝīܸþ¢T*ïܹ£R©Z|wúôé¡­[·>ùV^Þ`‰‘$|ÁW{ùºI¥§ZüI>pàBhÔ¨QO¾URRòðáÃùGôÚ(•Ê   .—‹ãø+ºDii©““FKHHÉd†ò«W¯º¹¹!„V¯^ýê®ÞwïÞ …ÖÖÖÞÞÞ•••Í*:tÈÂÂB$íÝ»×ø7[}}ý† fÍšE½?~pàÀðáÃÙl6UáÞ½{¹¹¹...cÆŒyrn†a† !”““£ÓéZé%‰D’žžN„H$rppø×¡´·oß&¢_¿~ÆQõêÕ Ã°ŒŒŒ§U__Ÿ››+‹“N++«Î;gggC2 €ÉÁ¢÷¦G’¦Ž¼‹Zþ(I"’¤cý5GóÚÌž=ûĉ¶¶¶.\¸pá§Ÿ~J’äo¿ý¶aêWúâÅ‹gΜ9rdVVÖ”)Sôz½áp‚ Ξ=»yóæ‹/^¸páÃ?|òUUU¥¥¥,«wïÞO¾Ë`0¨òfÉSJJÊàÁƒÏœ9sñâÅŸþÙÒÒréÒ¥/^¤Þ•H$Ó¦M{ôèѧŸ~zöìÙ‹/?~<00pÕªU'Ož4>ÏÕ«W]\\RRR.^¼xìØ1OOÏܾ}Û¸Õ¬Û¯_?''§=zx{{_¸p¡°°ÐPáÁƒ …ÂÏÏÏÆÆ¦õçùþûï3™Ìÿþ÷¿qqqû÷ïÏÍÍ•J¥­bl×®]½zõêÕ«×{ï½7nܸ»wï¶^?//!äééi\hggÇçó  E‹G)•J©TÊårÓh4___‚ JKKÛ0àU€dÔÄX,•ÊÔA€w‘e‹¥:"“ùò'ô´ÖÖÖžžž ƒF£y{{{{{[[[ëtºíÛ·c¶råÊ‘#Gº¹¹…„„lÛ¶ÍÉÉéÖ­[iiiÆgøä“O&MšäáááééÙ±cÇ'/Q^^N’¤½½½……E‹1¸»»#„JJJ‚0úøølܸ188ØÍÍm„ ³gÏÖh4»ví¢Raªw~È!Ë–- tppˆˆˆX±bNÿí·ßtF;³9::&&&vïÞÝÑѱ{÷îÓ§O×jµÍ’ѨÕêÑ£G³Ùl.—;räH©TzôèQòŸÿSÕù|¾¡­ôi¦L™2g·³ÿþ>ú¨wïÞQQQK–,1Nm[dnn2vìØùóçOŸ>ÝÒÒòÏ?ÿ7nÜýû÷[9J¥R™™™5[‹Á`0™L­V«6,¿üéõzµZÍápšÍ¸§î®ºººõP¯$£&fn[σöC«E$)f2LÈk¥Óénß¾Íáp>øàC¡@ >|8Žã7oÞ4Òh´¡C‡¶~6­VKÕl½ŽãÆ/ d<²3&&†Ãᤧ§S‹q^¼xÇqÿ»wïÞøFc³ÙyyyÆIXXX˜ƒÃÿÿøüýýY,VQQ‘¡¤¤¤äìÙ³žžž½zõ¢J¢££Áü!“ÉZùI<oÕªU§OŸ^½zõСC­­­³³³bbbrrrZ9púôéçÎÛºukBB† Nž<9xðàÜÜÜ7çèOÂ0ìYcÂq¼ÙÓ6F}^‚1£&fnTSÃÀq=ý­ío• ±Ù¾ †•©y­*++µZ­«««ñÀJ Ã|||BµµµÆ•ÿµçÚÕÕðªª*FÓâúM%%%!jº½¡ÐÃÃÃ8Dz³³c0 …‚ÊÌB+W®\¹re³³q¹\ãb±Øxì&•ºÉårCɱcÇjjjøøñcªýÇq[[ÛŒŒŒ¬¬¬ž={"„¬¬¬0 S(Z­Ö0Aêi Fhhhhhh|||mmí­[·¾üòË{÷î­^½zÇŽô§üj³··7~éââòõ×__½zõÚµkR©ÔʪåŸ@&“©T*›%Í8Žëõz&“ù´v\‹eff¦Õj•J¥ñ'B¥¡Æ¹;À$ 516Ûü¥Òû"‘©Cï<½Õ×Ó‚^¦äu£š$36Jcc#BèY¨wpp‹ÅÕÕÕ7oÞìׯ_³w ‚¸~ý:B( À¸¼ÙxG­VK’d³æÕ„„„nݺ5;!‡Ã±´lyÐÅ“ôzýþýûqOIIIIIiöî¾}ûÂÃÃétzÇŽ-,,=z$‘HÚ¾+5÷+::Z«ÕŽ7îÎ; Ôìõ¶°³³ãñxR©´•dÔËË ý“Í444Èd²°°°§ínenn.äryuu55F!D’dQQ†a­¯±x 51ËÁÖö‹ŠŠÙêv°' xw‘$ª©A$.O0u,¯›¥¥¥D"yüø±ar A†Ò—6¢Ñh111[·nݼysïÞ½ŒÿóköÒ¥KÙÙÙ 22Ò¸üîÝ»z½ÞPùþýûZ­–jEyxxPåQQQ/²cÕüéïï?cÆ ãT•JµråÊ“'OVUU9::y{{ß»wïï¿ÿžûL üùçŸ7nTMQÌÊÊš9s¦N§›;wn³&ÃS§Nݾ}›šB$—Ë·lÙ¢Õj DµË>ÜÌÌlË–-¤ÑµµµÏ4ÿ&99Y.—;ö“O>™e$>>~РAEEEçÏŸGñx¼O>ù„Åb-^¼øï¿ÿ6ÐÔÔ”œœüÃ?P/7mÚ”žžn<ìR©T;vL©T:;;?mówµZ]QQa<޳®®nãÆ‰$ À°oS~~þìÙ³—-[FmFŠŠˆˆpvv>yòdjj*UòðáÃ}ûö ‚èèhÃÙ:4{öìƒR/Y,ÖðáõZíÏ?ÿLŠ ˆãÇgffúúúvêÔ©íð*@˨éÑhæNNK n9:&Ý#¼‹pÕÔ š¾µõ\î;×G¢Óé_|ñEJJÊŽ;"##‹ŠŠ~ùå­V;þüçSHMŸ3gÎW_}uöìÙ!C†XYY¥¥¥:t¨¼¼<::ú‹/¾hÖaØèÑ£§L™bccsôèÑÓ§O»¹¹M™2…j•ìÝ»÷ĉ“’’ÞÿýÑ£GwèÐÁ`äääœ9s&666>>¾-QI$’?ÿü“Åb :ôÉÆÎ˜˜˜ääääää?üÐÌÌlìØ±999›6mŠ}¨å“Ξ={ãÆ ÃšV;vìøî»ïzõêìîî.‘HÎ;wöìY‡3yòä§­'PZZ:qâD//¯°°0++«²²²ãÇß¼yÓÝÝÝøÉTTT$&&Ìœ9“:•»»û´iÓ¾ÿþûÉ“'O:ÕÒÒr×®]yyy“'Oîܹ³áüW®\ILLd0£F2ÜÝž={Nž<;bĈÇoÙ²…Ãá,X°àY‡a^>ÓlüôÖyîí@ ´ÚŠ’’ù™™üŠ ÔÔ„4D¦ß¾ÞÞ/N‡T*$‘ ‡iÙÙ¥Ò“¡kýçüíØ´©©),,ÌÛÛÛ¸ ˆ3g΄††R\h4š³³óÂ… år9UÇñèèhGGÇâââ6^èäÉ“‘‘‘†v>333ooïeË–Õ××Wûé§ŸB ,:t(5ê‘Åb………?ž C5¹\¾lÙ2ooojF‹Å‰DÁÁÁþù'U!##ÃËËë‹/¾0>ùùóçÝÜܨµT©wРAOF[UUêããSPP@•¨Tª={ö„……‰ÅbF£Ñ„B¡››ÛçŸþàÁªÎê¤O%O IDATÕ«ÃÃÃíìì¨ç†aŸÏ ݽ{·F£yÚ“)))éׯŸ 5åˆF£Y[[÷ïßÿâŋƷ|ãÆ {{û¾}ûJ$CaSSÓÂ… ét:uàÔ©S«««Ï¿páB{{û… fee–,`2™¾¾¾Û·o×ëõO ðÚ`$ K®¿*•*//Ïßß¿ÅÿdϘ1#))iëÖ­3fÌhå$$©—ÉÎUWoÑj`X .e³‰ÀS„™ZM⸈F³çñØÙÍkËÚ¢ÉÉÉcÆŒ5jµÃ±ÒÒRµZíííýjâ}™‚(,,$âÉh%INNŽL&c0Ôtƒ’’•JåááÑö­†4̓¨•G---}||ìììšÕY³fÍ_|±iÓ¦‰'fffJ¥R‡Ôâ$žŠŠ j-'‡ceeåééi˜µ£V«KKK¹\®ñ%šššÊËËy<5(¶¦¦ÆÒÒÒÁÁ¡Å§………Z­ÖÉÉɸE³±±±¨¨¨ªª !$‹­­­›­ V« ëëëe2F‰D>>>­Œ(¥Èåò’’’ÚÚZ¥RI§Ó<==›-> T*KKKÙl¶³³³ñ¬|Ç ¨ÑÑÑÑ××·Ù”ÿêêj©T* ›-}ÐÔÔ”““SWWÇf³}}}œœZðz@7};‚a > Ÿ¥×7hµÅM™V[òï‡ðìètXìÄb9²XÎ4Ú»ÕMI£Ñšmác  ©µZäââò¬×b³Ùm©laaÞz‡§ àp8O¦×ÔU!¡Pø´Aœ”§jñùü   V6Ìäp8þþþ­‡ý$.—Ûâ–ÆÌÍÍ}}}Ÿ,§ÓéÔ†O;ÐÖÖ¶ÅE,,,ž¶=À„ m‡0CÄ`ˆÌÍCM À«³éÀ”„B¡@ 0u `Ð2 ¦4vìØ÷ßÿiÏà­É(˜’™™™ñ6¤ð®nz`2Œ“d˜ $£Àd ¤Óéär¹V«5u ðÎÙô€þþûïŸ~úiÖ¬YãÆ3u,¨±±Q&“UUU•——óùüÞ½{o†Ùv¥¥¥<ÈÎή¨¨àóùvvv½zõòòò2ÞÌ!¤R©¤RiAANïÛ·oÛg÷«Tªœœœ7nh4„££cxxx³Ý;_"‚ ª««ïÝ»—žž.—Ëœœ‚‚‚ž ÇñÜÜÜK—.Q[§¾÷Þ{þþþOFUSSsáÂ…ÒÒRæçç׫W/Ãöª!’$«ªªrrrrrrªªªÌÍÍííí{õêåííÝì^$£í A’ µ¶Q¥nP(keJ=Ž›:"ðv¢Óiæ,¦ÈÒ\Ä5çrØæ»þ« ººúúõëÇ7u èØ±cË–-£2Q½^ß¹sçË—/7Û´½fΜ™’’Âf³¹\®V«•ËåÖÖÖñññóæÍ3læž™™ùÕW_=|ø°²²R¥RÙÙÙ¥¦¦:;;·åüyyy .b³Ù%%%Û¶m{‘{\³fñËnݺ±X¬Ï>ûìäÉ“ÑÑÑÔ½„……]»vºô_ý%“ÉÚrf½^ÿÃ?¤¥¥ }º¬¬ÌÍÍ !¤ÓéU*ÕêÕ«§NŠ ¦Ñhüñ¦M›z÷îMùòåËçÏŸˆˆX¿~=Õ5ïîîyðàÁ™3g"„8Î?þh@×®]™Læœ9sŽ?É(/ ŒziJëÏå¨iL¾HÄ`² ¯ F3çò,„V÷«%—óŠô8aêˆ^‡ÚÚÚY³fõîÝ»{÷îýúõ[¼x1•Ójµ{öì8p`DDDxxxddäüùóŒë¨Õê}ûö <¸gÏžááá½{÷މ‰IKKkñ¢W®\:tèÊ•+ âÿ<äôôôèèèE‹éõz„¹¹y³lõ%¢FsÊd2’$©‹õcîß¿üøq@°téÒf©|TTT\\œR©LJJ¢’"„H’ÌÉÉ™9sæ{ï½Þ£G,[¶L£Ñœ` &‹keU&U<¨¬3u,¯œ\.Ÿ2eʶmÛt:]TT”ÝÚµk›uˆ±f͚ɓ'çääøùùEFFÖÖÖ®Y³æ?ÿùÕŒ‡Âqüë¯¿Ž‹‹»{÷®››ÛÈ‘#ýüü²²²rss[¼npppfffbb¢\.7.ß¹sçÅ‹}|| ½Ì¯Žã¥¥¥{÷îÅqÜÐ:øÜ®_¿^WW×¥K—Ž;6{‹F£1‚ËåfffÖÖÖR…©©©#FŒØ±cI’}úôéÓ§†a§OŸV©Tl6›ÏçcÆb±D"‘H$²²²jû£hhh¨««³°°àñxTIMMMee¥“““£££¡šH$ruumll,//G©Tªû÷ï›››ûûûGJDFFF‹×Âq¼¼¼|Ïž=L&sÀ€mŒð¯Þ•.¹v‹ É{Å•2Áµu°?¯Î0çñî–TÚ ¸V–oóVé|X(q¾tß}÷]NNŽV«ÍÍÍ­­­7oÞøñã_ðœÙÙÙ$IvèСÅ1 ®®®b±¸¢¢¢¾¾ÞÉÉI¡P|óÍ7S§N]¶l™X,F)ŠÇ[XXDEEY[[÷ë×oÀ€Û·o¦0t:]RRRqqñèÑ£]]]©Â’’Ngoooœp››› …B¹\^SSC]½ººÚÌÌL(ŸÐÎÎ!D%¬fåÊ•YYYZ­–šé5cÆŒØØØg Ð h‡31™Jó¸FbÉçC›(09›££1ò*kMÈ+¤Óé>L§Ó?ùä///„F‹íÙ³§qµ#GŽ(•ÊáÇæ×{yyÍŸ?Ÿ$ÉP%»wïÆq|Μ9†L!äîîn<­»™¸¸8ƒ±gϪG!tüøñÚÚÚaÃ†ÙØØ¼Ü;5xøðáíÛ·oܸQRRbffÖ±cÇŸIõ¿f7Ãf³ †J¥¢ÖmÍÎξ}û¶§§çâÅ‹©L!diiÔÆN-"bß¾}7ntssûæ›o §Âq!dh(5°±±!I’#ã¸N§{òœÆ©$I>zôˆz†?¶´´ìСËDh kTªµbÀï5Ð`›Ã©•5¾}t:ÝÇY,V= …L&³_¿~†—AäææÒh´fóoˆÊÉÉA‘$Iuæ6¬íWïÓ§‡‡ÇÅ‹KKK©’}ûö1~üøW·tFbbâ7Ο?¿cÇ7sæÌýû÷¿àGL¥bO›íDI’t:š#•››+“ɺtéÒbª÷|‚8qâÄ×_mff¶nݺ€€€fžl-†aO›‹öd!›ÍÞ´iõ ·mÛÆãñ>ûì³={ö¼ðMþ’Q«W(™,˜±Ú :ƒÙ¤Õ5iZh4z;$©Ñhh4ŸÏ7.7´ØQ´Z-†aÍæÊPuêêþ7¬V­V£:vÛˆÉdŽ;V£Ñ8p€$É¢¢¢ .øúúFDD<ßí´…P(´··ˆÝ¼y3‹ÅÚºuk³q«ÏŠjÇ-((h6‹ÒÐÐ —Ë­¬¬¨¹A*• !$^äŠÆ¨LtêÔ©:î¿ÿýïСCߥ=h–VÑÔÔÄf³---BfffàÉöÑÊÊJ„ñº÷! Ãõ 'NœøóÏ?ã8¾~ýzÖà%dÔÄêäM ÖÿoÕiµ õ²†züŸ^<„ªIÑX_§U«©—$IjÕj²¥¿´ÑÓšÅhtšŽ •oﮘ†±Ùl‚ ¤R©qyEE…ñK‹E•š4«cÈ>©] mœmôŸÿü‡Ãáìß¿_£Ñ$''+•Ê>øàùÖ´;v´´´¬¨¨ ÄçÖ­[76›žž^UUõä»·oß®­­uww§rV Ãêêê^J‹;I’§Nš:uªR©\³f͸qãšMÆrtt …………ÆM¡õõõEEE<Z`aaáàà P( “ë)yyy!??¿Vðõõµ³³«¯¯7ü·ð‚ 51ž ýÓ=W]V’øíç?Κ´rÖÄ]+—hTJ„Pö­ë?ΞüãœÉ뿚[UR„’ÖÕ&%,¨©(kå´´N÷”%œh4ºžDÝ[ÛäÃd2;tè ÕjÏŸ?o(Ôh4—.]2¼¤fU“$yôèQãcOœ8êСBð.]º „Ž;öLøùùõèÑ#33óÆûöí£ÚJ[ì2n]]]]MMM‹[QZZªR©,,,^pæ~·nÝ:uꔟŸOMÏ7~«¢¢bãÆ$IŽ5ŠšÀçóÓÓÓ‹ŠŠZ<“Éd0ÔÔ¢Ö‘$yëÖ­Y³fÉåòE‹}ôÑGO. ààààççWVVf<)þÑ£Gùùùîîîžžž!:Þ»woNwâÄ Cã®R©¼xñ"›ÍîÖ­[+1ÔÕÕÕÕÕ±Ù춬Òh HFÛ ×ï_÷c“¬qÒ7 ¾\ìâí‡ã¸BÖ¸ýÞA!“¿ùžÀñÃII’ÔiÔùY÷4ÿ¬/h;&“9zôh’$ׯ_Ÿ––¦Ñh¤RéöíÛ¯]»f\-&&†Çã}¨¬-º{÷îîÝ»ËÊÊÔj5µ®~nnî¢E‹d2Yß¾}G)Ô×××ÔÔÔÔÔà8N„á¥Þ¨¦¡P¸`ÁKKË+Vlݺµººš •J•——÷ñǧ¥¥uïÞÝ0g¿cÇŽ=zôxüøñ‚ òóóÕjµF£¡ö_¥&Bq¹\.—[TTTPP P(”Je‹½ÿ¡ôôô &”——Ïž={ìØ±‰¤æÚšóy<Þ¨Q£ ÅòåËKJJp/..^ºt©N§?~¼aûaƹ¸¸:t(%%…ÚÈtß¾}—.] §êdee%&&–——žáƒ¾üòKFóÞ{ï5éxn°´S{¡U««ËJz æŒa˜_h„PQ^n}Ue¿˜1önQcb·ÿm“¬ÑÔ‘ðf‹‰‰=zôÞÿý†††ÌÌLŸû÷ï길¸,[¶ìË/¿œ2eJHHŸÏ¿}û¶D"ùàƒFMÕyï½÷¾úê«Õ«W?>00ÐÙÙ¹ºº:''gýúõÞÞÞ­meeEµÛÅÆÆ6›—••5yòdFC„R©|øðáÀ1 ëØ±ã¯¿þJåRAý½C-ùü†êJ“i)"„Äöz®±¾ŽÉb™:XÞ`fff‰‰‰üñGNNŽX,^±b…³³óŽ; †a³gÏvvvÞ´iS~~~EE…‡‡ÇÈ‘#?ýôS–Ñ?ÀÅ‹‡„„lÛ¶-77·ººšÃáLš4©oß¾­ >ýôÓk×®q8œ'—e³ÙnnnT–I->Eqpp0ôæh4š:Wh&444!!áĉ………Ã0ÿaÆÅÅÅ5›tEmË„j–z¶¾zƒÁ˜>}zPPÐîÝ»¯^½zûöm:îëë;þüqãÆ5[©*888%%%111%%åþýût:ÝÓÓsÚ´i!:þÃ?SƒPY,ÖÓÖä÷÷÷7^H˘ñ¸[‘H´{÷îuëÖ;v,==ÇãÅÇÇÇÇǯ*J£Ñ¦N*‹þùçû÷ïc6pàÀ¹sç|!!!+V¬8}útAAZ­¦Ñh~~~ÑÑѱ±±Ï4q Ð:ì-^Ãåu¢ú§üýý[E4cÆŒ¤¤¤­[·Î˜1£Ù[Ç3ÈhL6Ç !¤njºqúï›§Oäf:yúÌûqÃÃ{wöþwùSÌ,,+‹ –}<áË;8ffË?Žûü¿[\|ZeÀó‘ÔÖDù»9‹Zè‚LNN3f̨Q£’““›½UZZªV«[olo”J¥\.‹Å­/«ÔÐРÓéZ¯&‘H´Z­P(d½–ÿ+8p`„ ›6mš:u꿎7¥†"0 ++«çœÚz½^"‘0™Ì2¯Õj% ‹Åj¶Úü+BÝ»@ he‡U‚ $ Fk%$*l:ÞlÕÀK-£íÇ¢o̘¾1cJæ­þdêÝë—œ<¼õZ­J¡0³°l’ËÔÊ&hàe177oË4v++«­ózR+ƒ‚‚‚>}úŒ5ª-É%›Í¶µµ}¥ñ0ŒfË`= ‹ÅzÕÁk˽Óh4‘HÔz×6ï˜ÀÔŽT=–K%ZµšÉbÑ ’ …Ö6l3³ÂûÙZµ*ãÊk'k'„I’MòF™¤A&iP4JI–yàòõ×_Ÿ>}ú%®Ü &-£íÈ‘m›Ë òùV¢†ê* ? {„ÐÆ®Ç ÷w¯Z*²µ/y”÷Õw &ÃhzvÛÒo©}›„Ö6sW®·äß%¼y mG&Ì_Töø®ÓÑèt?*¿Œ™>' ¼gÖ+E‘!Ä‹ç¬X‡ÿ3‹–ÉfsÌ-L7Àó‚d´á „þ»6+d0™~¡]|‚BÜ=u:-BˆÅæYØÔÔ$Àf žÖzch»ÌÌL;;;SÀë¦Óé²³³ÝÝÝ!ð¬ [í¥±´´”Éd¦ŽÐét8Žs8SàÍÉèK# %‰R©4u ¼V$IVWW³Ùl6›mêX¼y }iÇ+(( ÂÔ±ðúH$’ššwww ÃL €7$£/ †annn¦¢¢Fâ‚w„J¥*,,ttt´´´4u,ÞH0é%“H$<îîîÐk ÞbAÔ×× OOO:nꈼ‘ }ùÔjõãÇU*•Ç377§ÑhЃ Þ$I’$©×ëårymm­L&sss³±±oÏ ’ÑW‚$ÉÚÚÚšš…B233c0`IWðÆ#B­Vët:‡Ãçóa=€Éè«E’¤Z­V«Õ8Ž›:^†a,ËÜÜ:å¼,Œ“ÙôÀd` #o’$ssse2ƒÁðððpqqÈÞÐM@{‡ãø;wΟ?¯R©¨ ü½½‡ {ÁxÓA2 @»F’äõë×Ï;÷äÎ^ÿùÏx<žI^ 3 @»V^^~õêÕ÷˜­¨¨¸|ù2l? àc΀ièt:È¢Ú"##ÃÐ;ÿ¤ôèÑÃÊÊêu†¼DŒ b÷îÝeee¦ä'—Ë $£Þ\ŒÓ`2™,ËÔQ¼ôz}ëMȰ'€7$£Àh4Z\\œ©£x3œ9sæÚµkO{—Ïçs¹Ü×ðrÁ&Úµààà§¥›†ðùü×ðA2 @»fmmÉf³›•cæááѳgOè¦ðFƒuFxäææž9s¦±±‘  ØLf```ÿþýÍÌÌLðB í‹^¯'I’Éd¾”³ã8N§ÑÞøN­V[XXX__Ïf³]\\Äb1´‰x ¼ñ¡A;ãø±cÇ _ä$AÄÆÆöéÓçeEuðàÁ¾}û>|¸í‡œ;w.77÷eð±X,__ß=z„†† C&zòäÉö0ÐŒ‚—C¯×9räáÇ/r¶wïÞ[·n½¬¨ÆŒTSSÓöCþú믌ŒŒ—À«pï޽ɓ'+ êå©S§ ðæ‚¥ÀËA§Ó©îuFƒÂ0,??ŸÏç;88$©ÕjBL&“F£Q¨I9UUU‰ÄÊÊÊÖÖÖ¸ßY¯×ëõzª†a:îÑ£G ÃÃÃÁ`P=zD’¤‹‹‹……E³>k¹\žíââbˆb¸(AZ­–Á`0 N‡ã8ƒÁ(..Öh4ÎÎΫV­¢Óé!­VæFH IDATKƒÁ(((`³ÙÎÎÎT_¿^¯/((`±XÔ}Ñh´fƒ šššJKK †‹‹ ‹Å¢.aƒÁ !Pw¤T*KKKétº³³3õ(H’”H$UUUÇÉɉ :?õ4¨§'—Ë+++U*‹Å¢Ñh+V¬ u¥¥¥$I:99™™™QÃ0•JU^^nkk+‰^ŧœ$Éýû÷{xx$''WVVN˜0ÁÑÑ1..nùòå)))!!!?üðI’ÕÕÕƒ 9r䨱c#"">|X\\üá‡:99EFFvéÒÅËË‹J߀ö’QðÒÌ›7oíÚµ$I666²Ùì«W¯±xñâ™3g’$yìØ1­V«Ó颣£‹‹‹+**A^^I’¹¹¹–––õõõT2Z__?tèÐ 6Pgž?þ¤I“t:N§ëß¿ÿöíÛ ---sssõzýúõë+**Œ#™6mÚÔ©Sq'I2,,ŒJF‹‹‹ýýý I’ëÖ­£’QªÂòåËqÏÌÌ,**Ч’Q’$mmm÷íÛG’äúõëGŽ©ÕjÿøãÐÐP©TJ’ä‚  ¤R©Œ/=eÊ”¹sçj4FÓ³gÏýû÷“$ùûï¿»»»¯[·nüøñTóæÍ›>}:U­ÿþ;wî”J¥‡&I²¨¨hÞ¼y …âÈ‘#T2J’ä‡~˜œœL’äÍ›7 ÐØØH•þùçT2ºbÅŠaÆ©Õj’$gÏž=qâD’$Ïž=ëææVXX¨Ñhz÷îýÛo¿½ÄOxq0f¼L&388Ã0[[[ªdÀ€t:ýï¿ÿÎÈÈàóù...™™™t:Ý××!äíímaaq÷î]„I’QQQ………3fÌ Ž½qãÆ•+W"#####óóóïܹãêê×½{÷ÈÈH±Xlccc|õ¬¬¬Î;S½ê]»vý×hÃÂÂh4Z@@€««k³·z÷îòôô$I’ ˆ´´4*T„Phh¨¡Ü ##ãìÙ³QQQQQQ%%%÷îÝC3&::zÉ’%óçϧŽMMM½téUíñãÇ™™™%%%jµ: !äêêºnÝ:ªfÛedd„††R=þ!!!¹¹¹Ô¸R777jÀ€§§§Z­~¦s¯Œ¯Fk–K±ÙìiÓ¦mÛ¶ÍÍÍmÒ¤I!'—Ëu:“ÉÔjµr¹œÇãQ•×®]»hÑ¢øøø 6`Æãñ¢££¿üòK„УGBz½þÛo¿]²dÉŸþ9gÎ++«Aƒ®Åãñ”J%õ½L&3”+ jŸ÷ÆÆFãØÁÓn¤YºÉçóe2™^¯g0jµúÉ]ãy<ÞäÉ“gÏžM…J­ª×ëÄbñ/¿ü²zõj&“)‰>øàƒøøx„PAAaô*5²V«Õfff`¦Õjõz=N7¾ ŽãÆKVßµJ¥233c±XÔgñ¬làm¢ÀËã8µ¨'AÔ4Ng(Áq!{ëÖ­¬¬¬~ýú!„BBBüüü¶lÙ¢Óé¶oßîåå¬×ë1 ß½{÷öîÝ‹ãøèÑ£wïÞ]]]]SS'•JËÊÊbbb Ƙ1c<==u:q0111û÷ﯪªÊÏÏ?þ<ƒH$ÒjµÇŽKMMýý÷ß©¨¨Põz=•V¦îý³î)ÕããøÀ>|˜••ÕØØ¸gÏž'“ÑÑ£G:t¨ººº¼¼üã?®ªª"bݺuŽŽŽÇŽ;räu阘˜¿þú«¢¢¢²²rÖ¬Y¥¥¥nnn;vìP©T‡þñÇõz½P(,((¸téÒÒÒҨؘL¦F£©­­‹‹+,,4Ä\£Ñ¬Y³æ¯¿þŠ‹‹8p Nïß¿ÿùóçËÊÊ–-[fkkkkkÛÐаwï^‚ ¢¢¢ÒÒÒœœœüýýý$6›Ò½{w×bàÝô´wµµµÆÝô†4”Ïçkà -£àÿ±wßñQTëÿÀ?³}“l6uÓ©@º@ H 6¼Š¢ˆŠ/"vìÂÅ~Q¸P¤JiB 5ÔÒÛf“ì&ÛûÎï¹Ù_B3ÉJxÞðÚìœ9çì²3óÌiCn†Bi{(%ä6 ‹SRR( %„ÒöP7=!ÿt6›Ín·{yyQJ!¤í¡`”´Z­öìÙ³2™¬k×®-·eeeétº>}úˆÅâk§,)))))ILL m‰šB!m-zOÚFóõ×_¿òÊ+‡£…Š8vìØ¸qã¸%¥¶nÝúì³ÏšÍ櫦,((xõÕW7mÚÔB5!„BÚ FIÛóÐCqK8µçŸÞËË‹ëOHII?~¼{=¦Ë 4¨k×®-ZB!¤   L¤ Z½zõÑ£G‡ 2vìØ½{÷fee}:''§sçÎÏ>ûlVV–B¡øóÏ?:äëëëíí½bÅŠ   ¨¨¨÷Þ{oéÒ¥=ôPMMÍĉÍf³^¯ðÁNç„ ~øá‡¯¾úŠeY??¿yóæ-X° G7näž·@ °,ûí·ßšÍ怀€mÛ¶½ôÒK"‘Èn·Oš4I­V»ëãt:ùå—ÊÊÊÆkÝB!„C-£¤­INN~çwÄbñúõë³³³Ÿxâ‰3fÌž=;<<¼¨¨(99yðàÁB¡P(Μ9³G:uнxñ¢R©¬¯¯ïÕ«—Ëå>|øªU«^xá…{î¹G(~þù牉‰ãÆ“H$\)‰¤OŸ>«V­””Þ³gÏW^y¥²²ò÷ß×ëõÜ““ª««§L™òÄO<ÿüó×óD!„Ü(%mX,æžçÉãñt:€!C†0 ³cÇŽãÇ?ñÄB¡K€[¹³¤¤¤¦¦F«ÕîÚµK(²,;nÜ8àˆL& •J¯Q®Ã0<Ïétº‡Š~÷Ýw‰¤sçÎî¬!„Ò] IÛ'‰&Mš´téRƒÁ0wî\÷û/^LMMU©T,ËvèÐÁÇÇÇÏÏïwÞñõõ-..^¾|¹û!õ·lÚ´i÷Ýwߘ1czôèñÀüÍÜ!„¶‡ÆŒ’¶£¼¼|ûöí•••Û·oß½{wIIÉÞ½{ <üðÃ'Nœ:t¨···;ýÂ… ׬YóüóÏß{ï½ñññ ˆŸ9sæš5k^xá…èèh±Xü믿Z,–¥K—Fk×®5 ÿý﫪ªþøãÊÊÊmÛ¶eddäää9räüùókÖ¬1kÖ¬Ù³gÏÅ‹Oœ8a4»uë6mÚ´%K–4µ!„rÇ¢EïIÛQ[[{àÀ–e£¢¢„Baaa!€~ýú………0`À?üÇ%ö÷÷ß³gω'$Éøñã}||ÆÍ›7×ÕÕuëÖ­W¯^|>ëÖ­‹À¨Q£$ɾ}û¸ÉIƒ :tèÕj •Ëå¹¹¹zôè‘““c4%Ixx8WN:šÍf__ß4µ!„rg¢`”´quuu«V­jß¾ýÊ•+—/_ÎÝÌÊÊJKKÛ°aÀø|¾§ëH!„ܹ¨›ž´}GŽùí·ßÞ|óM÷,¢<ûì³™™™-÷¬&B!„Üj%mŸÃá`†Z@ !„ F !„BˆÇP7=!„Bñ F !„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!CÁ(!„Bñ F !„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!#¸ê»,ËšÍf›Íær¹Z¹B„B!¤Íàñx"‘H*•2 sÕ—£555*•Êh4‹ÅÁÕ£UB!„B®ËápØl6–e½½½ƒƒƒ ÅeQ)ò,÷Êjµêtºððp¹\.‘Hø|~S1,!„B!×Ų¬Ëå²Z­Z­¶²²ÒËË+>>^,»ü/Õét999¾¾¾1117B!„Ò,l6[qq±F£éСƒ¿¿?÷&ò¬Ãá8uêTxxxxx8GSš!„BH‹`Y¶ººº¨¨¨{÷î"‘Ülú¢¢"‰DA‘(!„Bi9 Ã( __ߢ¢"îžN§«©©IHH á¡„B!¤¥1 ¯Ñh4 þ”)SD"Qhh¨§+Fiû\.—F£ …|>ÿ–3Ù°aƒÁ`oÆŠ]‰eÙšš‰Drk]Füå—_ªªªjkk/]º×ì5¼)•••kÖ¬IJJ …Wn-,,ܺukRR÷ÿb0ŒF£T*mõjBî|>ßn·›L¦€€ž^¯—Ëåž®!äŽPQQ1~üøêê꿓ɶmÛNŸ>Ý\UjJYYYZZÚ­­µ\WW÷È#H$…B‘———}#{Mž<9??Ÿ{½~ýúÅ‹_;ýƒ>XWWwƒUÒjµ´ÛíWÝZ\\¼fÍ÷Ö·ß~{íÚµ7˜3!„Ü™L¦×ët:]»ví<]BÈ!##ÃÇÇ'444??ßßß¿¼¼œeÙ:ppjµº´´ÔårÉd²ÄÄDn–e+**T*Ç‹‰‰ñóósçæt:óòòÄbqddä¥K—, ŸÏïÔ©“»ñO¥R•——ûùùqc䣢¢Øíöììl»ÝÂqñâE‹Å"¹ÊìÙ³'%%E œ?>666//a˜¤¤$–e¹à²sçÎ|>?77W&“qÍ´N§3+++11qË–- 䦦FDD´k×ÎápÐh4Z­V(–••ÅÅÅùùù?žeY‰D’˜˜XUU•‘‘1dÈ­V}ôèÑòòò¾}û*ŠÐÐм¼¼Ž;r ÜëK—.íÛ·ïøñã]ºt …UUUb±ØÝÀ™››«P(*** C‡^yå///—ËURRÂuµk×.((è²ÿ£úúúÝ»wÿë_ÿjÉ!„À×××h4²,+àãããéúBÚ>§Ó¹cÇŽÑ£G[­ÖÙ³g«Tªššš   åË—ûúú.X° ''ÇÛÛûÂ… S§N|X¥RýðÃr¹|Ò¤Iû÷ﯯ¯ÿì³Ïî»ï¾aÆ=ûì³»ví’ÉdÕÕÕÏ=÷ÜŽ;~þùg“É´xñb‰D²téÒ'N̘1#11±¤¤¤_¿~óçÏ‹Å3gÎ4™L~~~'Nüä“OV¯^mµZ§M›æëëk0ÊËËW®\Ù±cÇÆÿMgÏž jß¾}ëÿB!w±X,‰l6ÒÓÓYBiy•••={öÌÊÊ2÷Þ{ï+¯¼b0 ’““þùg–eëêêôz}yyùêÕ«“’’,KEEEûöíW­ZeµZõz½N§cYvòäÉ .œ>}zjjê… X–5 uuuæôéÓ½zõÚ±c‡Íf{ä‘Gž|òI£ÑXUUÕ­[·iÓ¦¹\®Ï>û¬_¿~Æb±|ÿý÷Ç7›Í:tعs§Ýn×jµ\uuu¡¡¡J¥Òf³ÅÆÆ~üñÇ‹%''G ,X°Àb±œ>}ÚÇLJeÙ¬¬,///®‰÷‰'ž˜9s&sÇÆÆêõz»ÝþÑG½ñÆ,Ë®Zµ*""¢¤¤„Ë*<<¼¸¸Øn·k4›Íf³ÙºtérôèQ“Éäp8æÏŸÿÒK/™L&›ÍVZZÚ©S'­V˲lYYYJJJ]]ÅbQ(ÅÅÅ\ú^½z½ÿþû&“éܹsááá;wîdYvÀ€Ó¦M3 ƒáرcýû÷×h4‡C­Vsßü“O>9wî\–e÷ìÙ3zôh®‰â7Þxíµ×\.—‡~&„;ÈÑ£GÍf3=í“ÒJÎ;'‘H:uêd³Ù$É}÷ÝçííÓ¥K—“'O>úè£ëÖ­[¶lÇ …z½^£Ñ\¼xÑápŒ7N$q]íœÏ?ÿ¼}ûöëÖ­‹ˆˆP^^>sæÌªª*__ß²²²¢¢"«Õš››ûÖ[oyyyI¥Ò¾}ûp8ƒaÚ´iÌfó±cÇAZZÚ³Ï>›––6räÈ1cÆØ¿rrrhh¨ÝnçñxC† ‹Åñññ!!!cÆŒ‹Å]ºtá›Ü¥K—~ýúýøã“'OÞ²eËÁƒ¹ú3 #•J/›§Õµk׈ˆ>Ÿß®]»öíÛ1"--mܸqÇçñx<O,sƒ„B¡@ ¸Æ"±XÌ0ŒD"‘J¥J¥²°°ðJ¥)))ÉÉÉçÎ:t(îKàž†U__ÿæ›o?~œkg½l«ÕºwïÞO>ù„ÖW!„´ F !­eÙmÛ¶ 2D p)ææq7Ç ªªê“O>Y¶lYJJJyyùèÑ£Y–‹Å.—‹sÙX¯^½ÎŸ?¿wïÞ‰':Îùóç'$$,[¶Œa˜§žzÊét2 #‰Ìf3W„Õjx<^—.]ž~úi.Ÿ—_~Y |ùå—gΜٷoß§Ÿ~záÂ…>ø`Ó¦M#GŽäÒ0 ãX)•J¹|܆yá…Þyç±XÜ­[·äääk| ~~~\'‘H¶lÙrôèÑýû÷¿øâ‹ ,x衇8ÎkÜWwٛܣ›ÝÓL&“;ô”H$—%^»vmAAÁÚµkårù—_~Y\\ÜxëÅ‹y<^§N®] BiF´Ê=!¤5h4šS§N <˜ûÓjµ®^½Úl6çäädeeõíÛ×ét:ÎÈÈH??¿5kÖp¡jbb¢¯¯ï¯¿þêr¹ CYY·û¨Q£-Zôá‡þøã.—K¯×‡„„„……•––ž8q€D"IMM]¶lY~~þñãÇ·mÛ@(>üäÉ“ñññƒîÑ£‡D"q:çÏŸïѣǜ9s{챜œ‹Å²ÿþQ£FÝàG»ÿþûÍfóüùóŸ~úé\J¥R]ºtiøðá~øa¯^½¸•Ÿ¥Ré‰'¸˜R(*•Jnž©··w]]]~~>7’Õd2q™ðùü¢¢"—Ë”””´råJ»Ý~äÈ‘âââž={6U´ÃáðööŽŒŒ´Ùl;vì¸lkzzzRRR``à ~vBùû¨e”Ò M&S·nݸ?Åbquuõ½÷Þ[[[;tèÐ#Fðx¼|pâĉÞÞÞ …¢C‡|>_¡PÌŸ?ÿóÏ?ß¼ys}}ý“O>ù /ÈårŸ‘#GŠÅâ9sæðx¼gŸ}vΜ9{öìq¹\;vôööæóù³gÏž9sæ¿þõ/…B‘”” à©§žÊËË{ì±Ç|}}M&SZZZ·nÝæÍ›WWWçïï¯ÕjçÏŸúôi///n:?Ã0ÁÁÁîÞöƯÃÂÂÜŸåÑG]ºté<À½#‰¸âøøøp­¡R©Ô½ŽžR©|ùå—¥R)וÿðØ:uêwß}·bÅŠüqÀ€7n;vì˜1c¦OŸþâ‹/>öØc …"22244” yŸ{î¹7ÞxÃáplذá‹/¾xíµ×†®×ë§L™Ò»woî±  00a˜Q£Fmܸqøðá:tèÀ­N ‰üýýY–ݱcÇ”)SþÎ*°„r³˜ôôôzº„6nÑ¢EŸ~ú)“É4a„—_~¹S§N.—K¡Pp½ÉV«•[rH.—Æ€€>ŸÏ²¬V«5™L ÃÈår///n$///–ekkk† ¬­­µÛí\>b±ØÛÛÛl6s3rL&Óã?>}út.æs:jµÚápðù|nÕ'n>Ã0b±Øßßÿ³Ï>³Ùlï¼óWóêêêÀÀ@.>küZ©TºãѧŸ~Z&“-Z´ˆûÓjµjµwÅè IDATZ…BÀ`0°,+“ÉÌf³Åbñ÷÷çê Ñh¸FP___nI—ËU__oµZƒ‚‚¸Q³f³Y,Ëår»Ý®R©\.W`` 7AžÇãÙív½^oµZCBBx<÷-ñx¼ÀÀ@n,Z­–Éd\<ÊMÏ àRFî;´Ûí~~~V«Õh4êtºgŸ}ö§Ÿ~âÖÀ"„––™™ÙµkW F !­A«Õòù|.êâ‚Ñ3f 4¨åJÌÎÎ~ê©§¢££ :vìøßÿþ÷—±«««‰DܼŸëª©©™2eÊñãÇ÷îÝÿ÷ªìa6›M§Óq«§ëB¹#P0Jñ §ÓyöìÙvíÚ´\)‡£¼¼Üáp0 ÞB·4›ÍÉÉÉ‘‘‘-‘?!„´a\0JcF !­Ïç»¶@Ð +·K¥ÒaƵt)„Ò†Q_ !„Bñ F !„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!s‹Þ³,k0Ìf3÷Äd–e[®Z„¿a‘Häëë+•J}||¸'ªß,—ËÅ=ä|Òf0 Ããñ$‰······———Gž€êr¹ ƒÉd2 ‹….rûb†a±XìããÃS7uŹÑ`Ôd2X­V®¤àà`€žÞDÈ?šÓé4™LjµÚb±ðùü˜˜¹\~S9X,–ââbƒÁÀ=«=((H 0 ÓB&¤Õ8N£ÑX]]m³Ù¼¼¼ÚµkçååÕšÐëõN§“»ª*Š[»]$äÂétšÍæêêj»Ý. ccc}||npßë”,ËVUU•––úûû'&& …BÜABn ˲v»]¥Råææ*ŠÈÈȹ“t¹\µµµ¥¥¥2™,99Y"‘ÐOÚ—Ëe³ÙÊÊÊ.\¸Ò ÷Z.—«¢¢¢²²288822R(Ò i3\.—Ýn///?þ|TTTXXØ\;®MR*•åååñññtÀrÛá:ë###åryAAÃላ‹»î±\[[[\\Ü®]»àà` CI[ÅuÖÇÅÅÕÖÖ–”” mÑY–---U«Õ:tËåtU%m Njű±±þþþ………‡£]»v×ßëÚ›ÍfsIIIBBB`` 3„ܾ†ñõõMHH¨««S«Õ×Nl6›KKKÛµkB‘(ióx<žB¡ˆ‰‰)++3™L-Z–^¯W©T‰‰‰~~~tU%mÃ0 z½þºé¯u™aYöÒ¥KÁÁÁþþþÍWCBˆÇøøøDFF–––Z­Ö¦Ò¸\.®w>88¸5ëFˆgúùùº\®*Âápäç燅…Éd²*‚¹\™ŸŸït:¯òZÁ¨N§3›ÍíÛ·oΪB<*$$D(^£qÔl6ëtº¨¨(jmQ%%%çÏŸ¿ì®@©Tž?^§ÓyªVw2†a¢¢¢,Ë4äÜFòlddd åO®«ªªŠ±Öát:µZíµ“]ëbc0|}}iÖ<¹ŒÙl~ï½÷*++=]r+x<ž¯¯ï5.·F£Q$I¥ÒÖ¬ÕhãÆãÆ+,,™™9wî\»Ý~àÀÇüÀW¦/++›5k–ÙlnõšÞAÄb±T*m¹žzƒÁàïïO·y-J§Ó•––6µõÀ'NÜ·oŸû ìÙ³§5jvGâóùr¹üºÑÿuZF©+\)77÷·ß~ òtEÈ-’Éd&“©©¾H½^/“Éh4[K›6mš———ÃáàååÅÍ0aBTTÔUQ¤§§«Õj¡PØê5½ƒ0 ãããÓBÍf.—Ëh4Þøb7äÖddd¼ûî»Mm}ä‘G, ÷§F£Ù°a]ÎZ”L&»noõ‚Q³ÙìííݬU"­jíÚµ«W¯=sæÌÂÂB–eøá‡]»v:tè믿 V«_}õÕ#GŽØ¾}û÷ßéÒ¥·ß~ÛápÆ·ÞzkÓ¦M²²²>ÿüs.ÛÍ›70@$yî“‘¿E"‘°ÙlWÝj6›ézÙÊŠ‹‹;wîì¾P«Õ+W®üöÛo‹ŠŠÜi¶mÛ6dÈêªji2™¬…šŸ¹e¤¨Ï¡EUVV8p ''ç?þÈÌÌ ÑhÖ®]ûÍ7ßlݺµ¦¦æ²ôgΜ‘Édñññž¨ìâFŽ©k£Üb¼ÍZ%Òªl6ÛâÅ‹].×æÍ›-Z´cÇN÷ã?F@ðå—_jµÚÇ/Y²díÚµv»ý‡~¨­­õòòúùçŸóòòJJJ.\¸téR–e׬Y“ Àl68pàþûï÷ô‡#·ŽÇã1 ÓÔã^\.5¿µ²³gϾüòËîÑ~øÁh4Ž?žSWW—••5xð`VóŽ ‘Hìv{ eβ,ÝÆ·(£Ñ¨R©¸ÃG¥RÕ××Ož}¨Ý­EI¥ÒkL™å\g6}³Ö‡´¶>}ú(•Ê‹/fffŽ?>##C¥R•––véÒ%..N&“>}zïÞ½<ðÀþýû5Mnnnjjj@@@bbâñãÇ÷íÛ7pàÀüüü²²²cÇŽ :@UUU~~~ß¾}=ýáÈßrí£›ŽýVöä“O6nò>|øäÉ“?þøc™L¶nÝ:‡JHHð\ï -÷û§#«¥%$$Œ3&!!aÖ¬YcÆŒIOO/,,|÷ÝwŸzê©>ú販cƒáðáÃ#GŽôTmï×]¡‚†Q·e!!!QQQéééEEEÏ?ÿü… ¶nÝÛ¾}{¹\žœœü矞;wnâĉ`óæÍƒ¡sçΉ¤wïÞÛ·o?tèÐøñããããwïÞ““Ó«W/;vìèÓ§ŸŸŸ§?!mVbb"Ã0 ]»vÜ §-[¶Üwß}ÔUEÈM).. 0pàÀx ñÖœœ†aâââ}ºK—.4ö÷Ÿ@¥RåååõïߟžAÐÒ\.WFFÆ€®º533³k×®Ô2Jn%¤õ¹ÇÏBšKHHHHHˆ§kAþ‡n!„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!CÁ(!„Bñ F !„BˆÇÜʘNŸ>=mÚ4‡ÃÑìµ!„4¯·ß~»¹ßZZZúüóÏkµÚfÉÏ’J¥ .¼ë®»>>z½Þ³up:§OŸ.++ól5i|>_­VßÚ¾·þlúäää%K–…Â[ÎÒræÍ›·cÇŽfÏ6**ê»ï¾óóóköœ if³yæÌ™ž®Èÿxyy­\¹’ž“Nn_.—ëwÞÙ¿ÿ-çpëÁ¨ÏÝwß-‰n9BHË n‰l¥Ri¯^½‚‚‚Z"sBZÁ`Édž®ÅÿÇçó{ôèåéŠr‹œNg``àßÉ&0B!„¡`”B!„x £„B!Äc(%·Ï?ÿ\£ÑÜHÊ~ø!''§…ªñí·ß·Pæ„Ü.222æÌ™³uëV6›-77×jµ6WæJ¥òý÷ß_ºtiseHH+«¯¯ÿî»ïny^ù‰‚Qr8xð Édº‘”«V­ºtéR UcåÊ•´ i«6mÚ´dÉ’I›———žž ªªê¥—^*--½jÊ%K–=zô¦ªáëë«P(~ýõ×›Ú‹´a³fÍ:v옧kñŸ~úé²eËšÚªÕjþùg FoʭϦ'¤ÕÌ;—›©wéÒ%ÿÒÒR“É”””äž¾———WYYÛx¯úúúââb–e#"" Emm­J¥JJJâñxZ­¶¨¨¨S§N×&S«ÕÅÅÅZ­688¸cÇŽÜ&—ËuáÂF“˜˜èNY\\,‘HÔjµÍf mo[åt:u:D"‘J¥î7µZ-˲¾¾¾<ÀÙ³g/^¼øâ‹/ºèõz§ÓéNàƽ_¶lYDD÷§N§s8¾¾¾Àþýûýýýï¾ûî+«tYJ,Ëêõz†a’’’.K¬×빪þÍïüs\ºtI&“UUUéõú„„÷Y´¼¼¼ººZ ÄÇÇ{yyUUU>|8..N(ÆÅÅùúúêõú¢¢"§Ó©P(ÂÃÆiœmYYŸÏ7 F£Q¡Pp¿Ìêêj«Õj·Û«««¹Ó~~~¾ÕjU(‘‘‘\‹%??ßn·K¥ÒØØX‘HTQQÁ=Àßß?::Ú}¨Õê£GõìÙ3:::00Ðjµ^ºtÉn·K$’Ë.CäQ0JnS§N]¿~}LLÌôéÓ-K@@@mm­P(ܸq£T*ݼyóìÙ³ãââ¬V«{íÀ¼¼¼)S¦Èd2±X¬R©V¬Xa³Ùüñ?þxذa¯¿þz]]ÝO?ýÔ8]µjÕ¶mÛ|}} ~øáY³fñùüï¾ûnñâű±±,Ë–””p)?øàƒââb???£Ñh±XV¬Xíï…kª««{ýõ×U*ULL w±ü¿ÿû¿øøx‹Å2þü3gÎðùüÈÈÈ·Þz+;;û÷߯««›8qâ˜1cÆÿý÷ßïܹS$ùøø¼ûî»îpó2ß|óÍæÍ›—,YûÓO?ýùçŸÀn·/\¸ðÀ™™™J¥rëÖ­S§NíÛ·¯{¯?þøðáÃ.—ë7ÞèÔ©“Ífûæ›oöíÛçççç:?ùä“ôôôîÝ»+•ʺººAƒ½ôÒK´¸uÛ0}útîÎ_§ÓX½zuppðž={æÎ¥T*“’’¾ú꫌ŒŒÂÂÂU«VíÙ³ç­·Þ xõÕWm6›\.///ÿꫯºwïÞ8Û/¾øâÔ©S6›M©TþôÓO)))ëÖ­ûå—_ù|þ[o½õÓO?9s&88¸¤¤ä£>1b„Z­ž3gNIIItt´F£™?¾V«1cFtt´ÃáðññY¸p¡{9°¬¬¬¬¬,©TZWW7uêÔnݺ͞=»¨¨(66¶ººúÓO?õòòòÀz»KOOg›™™i4¯|ß¾}B¡°wïÞV«µ©} iFqqqùùù,˦¥¥Íœ9Óf³éõúøøø}ûö±,›°`Á—ËuñâE™L¶iÓ&–ezè¡)S¦˜L&«Õ:sæÌÙ³g»\®+V$''üñÇ yyy—•¢V«ÕjuaaáêÕ«5MUUU»víÖ¬Yãt:wíÚåããsàÀ–e'L˜0lØ0F£Óé†:gΗËÕêßÊuLœ8Àòå˯Üd6›O:e2™®ºã™3gÔjõ•ïçää%&&ÖÔÔ4s]IËp8[·nõ÷÷_²dI~~þ<ðÑG±,»råʾ}ûæææVVVÞÿý~ø¡N§{íµ×ÆŒSXX¨Ñh>|×]weÊ”½{÷j4šO?ýô©§žbY6###%%åèÑ£\‰ `YV©TöíÛ÷™gžQ©T‡êҥˑ#Gþþ×¢×ëSSS݇óeŒFcffæß/åJv»ýرc‹ÅýŽV«ŠŠ’Éd¥¥¥-Qâ?YZZÚ¤I“ŒF£Á`èÓ§ÏúõëNg¿~ýæÎk·Û³³³cbb6oÞ̲ì°aÃþüóOn¯—_~y„ õõõv»ý£>zæ™gGãl§L™Ò·oߪª*“ÉôØc½ð N§sáÂ…‰‰‰¹¹¹6›mÓ¦M‰‰‰çÏŸ·Ûío¿ýö½÷Þ«Óé/^|÷Ýw—••±,«Ñh,ËgŸ}6zôh®s@¥R]VʤI“Þ|óMîõ·ß~Û½{÷¢¢"–eÕjµÉd*..îß¿nnnË‹ÿ‡ãá‡æóùkÖ¬¹r«Óéä.ÖWuôèQ³ÙL-£ä63dÈ¡P( ###KKK«ªªŠ‹‹GŒÁõîuíÚ•K–‘‘‘œœ}º\.÷ööމ‰°ÿ~ƒÁ°víZ>Ÿ¯Ñh ׬Yc4Û·oÿ¯ýË]DHH÷è™Lÿæ›oŽ9òÁŒ‹‹‹ÅÞÞÞAAA\žn,ËŽ?~óæÍ[¶l)--­««päÈ‘ààà^½zñx¼ûï¿Ñ¢EBCC¥Réý÷߯P(xðàÈÈH܉½OŸ>Ë—/3fLZZÚøñã¯ñ ‘S§N¥¥¥µoß@@@@‹}[m£ä6ÓxøšÍf“H$\.÷wÞ ú÷ï?dÈîO™LÆçókjjòòò Å… \.ŸÏwg¥ÓéfÏž½xñâ=zÔÖÖ¦¥¥qeY­V›Í€»3v§w—hµZ/QGÈ? ŸÏw«s8\.—@ àÞäzÕNgã]X– >|8ÇKKKs82™,&&Æb±„„„\6J#‰¾øâ‹“'OnÚ´éé§Ÿþúë¯ï»ï¾«Ö§°°pæÌ™S¦L¹çž{233׬YÃUŒa.çËîë¸cœÇãñx<®þ¤MâN¤î•ìv»{ýôÓ¿ÿþ;n^µÚ͸šÄ‹.¢äöæçç×§OŸ_~ù¥¾¾>==ݽ®ÓÈ‘#OŸ>Ó½{÷ððp¹\îp8^ýõ„„„µk×®ZµjÆ ,ËjµÚ>ø ¢¢ÂápX­Öàà`Ÿ7r'¦¤¤$¹\¾nݺººº 6hµZw¹6l(,,,--ݰaCÿþýÿÉÏÅu8*•êÂ… §OŸ¾téR}}}㨚ÜRSS9R[[k6›÷ìÙÓ·o_™LƲ,7ÀºS§Nƒ!:::--­¬¬ìôéÓÁÁÁ=öØ3Ï<3räÈ«ŽÚ,))ùðÃSSS—,YÒ«W¯ .‹Åz½þüùó¿ÿþ»F£Ù¸q£Á`ÐëõV«µG)))î ¸gÏž*•Š›AÂÍÓwÛ½{·Ãá(,,äF´Â÷C<"00°k×®?þøcMMÍrss{õê@$åääTWWÛíö#F\¼x144´{÷îQQQ>>> …‚ûeŽ?ž›Ÿ·{÷îìììÊÊÊ7öë×ﲜ={ö,((8tèPmmíêÕ«Û·oœ––¶oß¾¬¬,“ÉTTTd2™.\¸àt:ÇŒóÆoðx<½^Ï%åV÷ ©®®V©T6›---mÿþýÇ7 %%%—µäQË(¹ „……q·È!!!îéÀ!!!ÞÞÞ>ýôÓW_}5;;Ûn·ß}÷Ý\‚÷ßÿõ×_î¹ç|||¸¡è999yyy¿þúkûöíß{ッ¿þ:55Õét®ZµjìØ±]ºt™ÿüsnÀh=¸F®ôiÓ¦i4šöíÛOš4éªmEÇ0ŒZ­þí·ßJKKÍf3÷ŽŸŸ_Ïž=Ý„´aõõõ\÷‚ œžžn±XþøãÇüÂ… ¯¼ò ŸÏ·ÛíÓ§Oçñx©©©Û·oŸ3gNttô믿~úôé™3gFFFªTª?þ¸ñ/|ûöí§Nâñx;vìÈË˳Ùl_~ùå+¯¼RYY9mÚ4…Ba±XFŽ `РAëÖ­Ûµk׸qãrssß}÷Ý:ÄÇÇ4hÞ¼y eee555Ÿ}öÙ´iÓÆŽûïÿ›Û]£Ñ,[¶lòäÉŠ‹‹_~ù劊 ®ÏÔS_&i^ …ÂÇLJ{Ƚþä“Oþýï?ýôÓõõõ“'Oîß¿?€'žxbÙ²eþùç|0cÆ N7uêT¹\®ÕjŸxâ‰+×^ˆŠŠzýõ×µZ­Ï”)Sx<žL&ã:ßôïßÿ™gžy÷Ýw½½½- 7ß衇ÊÏÏŸ5kV@@€Ífûâ‹/ÒÓÓ×®]l4‡ – R©Ö¯_ÏõÈ5êý÷ßî¹ç¦M›6f̘¼¼¼×^{-((Èn·þùç2™,44”fÚÝ&==}àÀWÝvìØ±”””+ç…íß¿èСݺuËÈÈø'7‘6£´´4<<\ (•J???.ÜT*•ÞÞÞÜÄÛšš½^ïççgµZår9÷£åfS:N©TªV«ív{hh(Ã0‡£¬¬L¡PˆÅâ²²²ððp±Xìp8ÊËË].WDDDUUUdd$×_QQÁ-¢Õj%É£>:lذaÆéõúèèh.&þ§yê©§öíÛ÷øã_w ‚Î;6¬ñB?ngÏžŒŒ¼rðSnnnjjj@@À¡C‡‚‚‚ZªÞ¤ù8Îòòr§Ó)‰d2·ð¡¿¿¿¿¿¿Íf«¬¬t¹\aaaÜÏÀårUVVÚívîpp:\APPÐek*iµZ.«ÀÀ@³Ùl2™x<^DD„ÝnW©T,Ëøùù°Ûí•••</,,ÌårUWW‡„„…B«ÕªT*¹Ê¨Õj©TƽÉãñüýýkjj¸F¯ÁƒÏž=;11Ñét¶k×®Y.ðƒá¾ûîËÊÊÚ¶mÛ=÷ÜsÙV“ÉtþüùÞ½{ÿý‚.ãp8NŸ>Ý¥K÷8N—’’R__áÂ…¨¨¨f/ñŸ¬²²Ò××—‹A«««¥R)7(Ÿûu ‚ˆˆ÷H*­V[WWÇ5F8¥Ri·ÛÅbqXXØe£¤^|ñÅ„„„G}´¾¾ž›Æíîp8ÜK:Ϊª*«Õêþ¡p¹\J¥ÒjµJ$’®CÉápîêãp8*++ wF5uuur¹\&“9NîØ‹Å¡¡¡,ËVWWß9ñ¨Óé|ì±Ç~ÿý÷_ýõ‘G¹l«ËåÊÈÈ0`ÀU÷ÍÌÌìÚµ+µŒ’Û€{á$÷ꆗ½¾r€¹H$j×®ûÏÆñ“@ pOªp¿îQAwt/jã¾À0 7ÚýK,4èª- \§§Ùl¾j0JÚ >Ÿßø—,—ËݯE"Ñecàx<^ãŸ4ŸÏojÁ2¹\îΪqžB¡ð²¹JB¡°qÜù‹Åbwéî¿ÉÅ?þøcaaáºuëæÍ›×øx'm@xx¸ûµB¡p¿nüëºê›àÚ;Ã0áááó¿,C>ŸåReÜ Uã4—ýþAãw¼½½ÝÍ|>ÿ²*5.܈V FÏuy IDATm¬ÍÂZZ³DBZ«o¾ séZ§8Œˆ‰ƒ› pÁ:®ªªªuæ~ÚY»•µºàj…²H[Û%ö‹e_——ëÊÃ;.Ä ­bAþ¿éÓ§Ó2Ÿ·£F¬CéTV;ª+•Z—V4’ÜæÚZkœ:áùÁÏñ 准òCÃa7r¾v«'7U%99¹ùªù.¸T•Ò©¬rVÕ;ëkQK>¹i O=ËCÞ•‡<ÆßŸñæ‡óÃÃa"††Ýé:tèàé*[ѲÁh«î¨ùh¦33[­(+øFÆèdœ×ß“Ò@ ©Ø%v‡;Ããìq½˜^ý%ýC¡×n(基ƲSîÕ©šÎ¥;a9qÄq$—Ÿ[&(«Uj-ø¤y‰!–¹dþNÿ(gT¬=¶7Ó»Ÿ´_?ÄÓõ"„Ü´– FY°ö‚½æ½ûûwøìÐð4-T!mž¼!‹Žýâý½½{:{ð[cå2BÈß×üÁ¨Æ©©fª«yÕÍž3!¤±:^’§Ô¸4M£Ÿ„„„ÆïX,÷¦´´´¤¤¤#GŽ\¼x‘{tXXØ-,0nfÍJV©ä+ovGBšW=¯¾‚©Ðº´Œr»hþ`TíTWð* ­)HHËrÁUÎ/¯uÔ&®Ÿº Ã(ŠÑ£G'''gddTTTTWWëõú´´´ÈÈÈk¬ uƒËPÃÔкÄã,Œ¥‚_¡qjb„1×O}Ûr¹ ,KS2HK`ø|ŸšSÔ”– Fùן·ôðpù¹®©X 8€` ×}; ßLAÍË ”A@-\å錄\‹ަFaVð+4öfˆÿø|~BBBTTÔ¹sç222òóóËËËïºë®Þ½{ûûûßÈ@RµS]Å«jòÀ¯¾/þu“X<ø\e?Or×9˜êáºü]  T@»V|ôž¨‚54듺]p55-¡Š_Uëhrnßm‹µÙÊÌæl“éŒÑxÊéT²ìU¦'ò7±,Ãç+¤Ò®ÞÞÝ¥Ò$‰¤ôøðëæ?'9àÐò´×O·r“Á¨ûñ7\÷ €ŸGƒQ0˜ ,Þºz®&äödC“3Ó ŒÁÁ6[/„D"éÕ«—Ëå*///((8zôh^^^ïÞ½odù''ë43æ&7ó@à<°òŠ`Ôì&^/Ý œæ\ï3YÀ‡@ÐõR^Wç*`Ñ£÷Ûp3OlmEµÀ$`.ð°P\¿øˆÆÝ|¹¥ å.¾"o>‡¦Ùaoj“–§mc ¹¸\&µzuUÕG SèåÆÛÛ‹Çk­§À‘; ËÂbѸµª G ŸßÓaa³…›=kÜœV|6½PQ@=P,hx¦"îÚ½€RÀHÄÿ&A²@ PˆX x?7ÊÖ”‘€Ðú†·($øËùªPB ñš-”z °þ@LÃÝ|1àÔz àÆÔÕ倛ȴ€ÐˆHþù¤RéÀ{÷î}ðàÁ‚‚‚;wfgg§¦¦:·tu7J xØìýëÖJ@|Ƚi b>Pœc!µ‚X ¨öçP ²!ÀU¥$Þ€¨´@ Pø± mx P  €?ð"¬ýkAu@`ä@"À*-ð' 0@xÃÇÑ% $6j›% ª€ `;P Ô" ðô€¨‚z@Ä<À m:v5œ…êñ¿Fv    ðoøžÔÅ€ˆd€ (U@À ˆx€ (ô §>¦á{.@0 ðʵÚ†rË9Ðä£ÈUX,—ÊËß¶XÖEF:år4ŒiÅË7¹Ãøø (, “I]^¾ðÒ¥ýÉåÃZ®Ä–ÿ5»€r`°èü8 üp ØôÔa€8 | Œ,~¢€J`&ðÐÕòWÏ?aÀn`°¸<°¸< ؼµÀ àmàªÏ÷Ö/Õ€°K‚æ)€¨,ÀX`p˜ð | Tÿ5ö €¼à Zi„܆‰ŠŠz衇rrr>\ZZºvíZ¹\îççw£k?±€Ø¬„ÀïM$[ ìªÝ÷G0(d€øæg€Zà5 Xqµ¬œÀÀA  øðÞîί6Ä €o€}ÀL ¨"%¨€Q@8à” M|®7€l Èž¦«€½ ü0dS_@„+š8áœ&ñ€Èþ:G€÷bP?`9px ª€8 8ÿN~€ø? P¿ô]{¯á,$kó€§`€ä«€^@0`|”ï'€óÀ ð>ÀoÇ9P | ô”ÀdHÅ€à>€ðnö p ÚÓ)ñúŽšüü Réé lÖq„\ÃÀÛ luõ‰¢¢Çãâ6Êdý[¨¬F3€•À ˜ „À(`Ú¨™Ð”÷o›‘À%`ð_`P4µNÛè^ß èß2`5`†LÀÀx`P Œ®úðšBà,°è ¨ÝÁsí(¿¾ %¾Ä_|  0s€üFYÅ‹`>|Dýo“V% ;wîÃ-ÿT[[;zôèsçÎ]g7'pX |G€AM'þ7ð0ÿL¬Ø ¬z@ HÀÀN`UÓY €w€zà`yC° ˜ô>´Àà`"Ÿ€d dr Xô¯¹Mô*àØÃÀl`:0 ˜ð€ÍýϺ_` p¨‰ïÁ¨-@"ðt:?|ÀŒ2+à,îv—€Là °ˆ>¾¦³€Æ# GoÀ·@ð=ÀM1wµÀR ;0 Ø ô~¼€µ€¤cõÀ @2ðjCž›€À: øXôΕÀ@; ðDK ¦alÀ `?°Xtžú7óXÒ¶„e•• §cbpÓ iN<BBàr©ËÊfuè°‹Ïo‘~FŸXà#` àuÍ”~@O€bàØð¦ÿM–{ÔÐ/Æ-›X›}€b ¨‰`”ë‚èŒmh£åŒo ê€à? Ýý±€xí¯—/À àÜ£é|oòSòàãã3`À€¤¤¤lݺµ¶özóBê—Rà}à¡¿ö¿ß9Ð ˜ t6R¼¨à—&ÒX3@)0p@x~D ¡p$p7à^`6 m¢ò‡Õ¯a|QS‘ÀX@uÃI骂€vŠeÀ{€@ ˆ€pÀ`/ ¨ÎUÀ€T7tÅ|‚¿Œ– ˆNw~6Eíp‹}]îd€ ˆÎ7Ôÿ2Ç€j`À4ÔÍÄRà ;ðp@¤htW£€?wL`WÓcœîx:Ý^µú»Ž)%žÄ0 V{\©œ9¯%Šhá`ô`5°XŒ†aMŒjº² ›\¸Ê\IÁ ¸µŒrxš]¹~s®ç艆¶É—€îMÔ9ø8ì^ü ›÷²±2瘀E@Q£wÚÿ¡ÑQ¤-àžÛ4cÆ /¯kßVr`1ð° XŒ†Ü;7Ò&þ œvs `T)…À½€ñz7ºàஆ?“€SM¤´.€×̹Ï3W2¨þ ¬’€ ýŠÜg 0¦a$€¸kVò2ïIÀÀ¸¯ÑqŸ<¹RX x¹á}_ ˜4žH6˜ÕD)ü«Ý·Óοžñ  x©aw@ Äë€ÀV`"°»á&ü2J X(4`BC¸L®À²ŽššïBC-×›=HH‹ãóíÊËû.<|w½«ÀÍká`ônàn Øüdó `œ@ PÞ0èJ°Ô‚†82¨ ¸¡åà"àìh89ÞìžÌÀ`  ÄÕÀƒ¯a6ÒU©  Ð84µlŽ?ÐXô„@9Ð xùŠ–Q:‰f³Úìb»°åG“¹\.‹Årý`Ttº5À^`° ؈lÀ@„, ªP0@(`r®@'à$Pß­ (ŠqÃIC{¯93sfµ×þ/ˆ‘3S‹ä¬ƒæ°Ê·‘'À*Ê~jp€Uö‡{Ã&¨ ž ƒ§à:4 \¼ÃàŸ*€'샳Åwkk ‚!Ì“‹ŠŒÞ&-`#\ƒ›pÂåvw8WÀ | üþPR![Þ€•O@-ØnïÛ2Bè•Vñ‡I2dg¸óÁ=ÁÑ•*='ç˜N׬Ì¿/Ûñ*Àó0âAŸÀð…¹ % †92êç0~yÃÐÂ8¨3ÀÁù·Í*þ=öÁp°€ø€|a7(@ ßã^‡ÑàF¨,/6Yí±]g·¦ð¿σ *Â×P·ìOž@Pš$Í…µöTÛÓªU«Û¨¿OøBèc³–ýàu†Ù`†ñòîõIrFc2¼  OQ¶Ö°^„ b60YÑÁ@øÜa´€á5x$0À2p…  „j €`9¶ê 3Áâ`¦< Œ‚×@+!À0p—·ÉçóLWá}xž¤ÁOÅ,’8C¨ì“ùË—äÑðl€\h ®  YI@Aà ‘p^wH†1PšÜÞ»ã(ox¼åEž¡°†Cô´É+oÂKP>‚¶0ÞwH‡þ§á-„ˆ”/Å…y ¼Å]úma2%WEXTð TâèhÈÉ9ñÈ:£ùSY.ß·W8²fe-–]½§m–¥úB{Hµ”æAš¼Ox†€ üå€üWÁ <åå¶ð;Ä‚ŠŒÖß TZ¹ýëBÐ*°®É ྣJSéoè·Çm÷ññ /ý€ûZ^£aºì´~ñçÚ¬ÿZ£ ð$ƒ‚m$ØàOù‹_òt“`XäKJ(,‡«`†Š ƒvÐt°´0œá4Á/^6JœJø’e;0. ™6SO„‘`‘¯-!òõÁAŧŒ×‡Ÿåñq²WÚ êC&øZ> ÍÀÖ|ZPÃ{0ÒÁí¯B5`¾lÕórÞQEø®É‚ü߇F°²@ €ñ0ÒÁEú>Ah!¸øß–2•-ßdgst´i'µ¶w/ß{³î[¶P»6¾6Qü­[‰hÛûÕŒðô¤êå½”;’“Ù³Ú´¹“*8;[²³OÝ‹Á„P™GQùéíä?½¡pÙmµ}£º(ÝAg¨Y¨QgÉ(øµ–W¤ÙŽÅH ÷…Üʹººœ9ëׯ÷òòò÷/aúá@)ïæ¶R¸x¸üŠQe×Üž”½¢Ð°ößS­|“i½Œ¸Ë†¹sÁ)`§Êæ2âX|7ë¼¥þdjl®~¶wÈ…6[›mƒ¬%ˆ—€Úf{–mæ…®¨+'²¬A>ÊBóªî°ˆ‰ 4,–\U±ÒW’íÅÂܹtíÊ A÷Ų²æÃ™2…öíoµ?ιsüñ Ò±£]ç¥K©[÷Þ:£³gÓ³'¡÷·š¬^Ï¢EtêTú¼F#o¿Í™3 x_Q@­F¯Ï½'#ß‹AÁ}BIH³)C:yòäÚµkûöíëâò°UÕ|D…¯´  …ÒVÕ7;›„L&üüp•ïFÒӉǭD©³™„t:nÜÀÓùŽ.5¥“‰œœñôHJ"9||ÈŸ=3“´4OOJMÏÇ` %ñðÀÛ…‚¬,ŒF<<pwG«0‰‰A’¨P†Ñ£Nž´Ðh$1‘Áƒ °k7™HHÀbÁÑ//Š”BÎÌD¯Çb!=Ýî&%‘’‚«+~~(¤§“‘AT¡¡hµ¸¹åõ4‰Çd"0‡"ƒ‹''‡¸8­9—¸»çÙ“˜ˆVK@J%™™\¿Î/¿€V‹‹K^·âNìµk¼÷^A7ý~qOòÁ„3*<ÚhµÚ¶‘m“’’bbb¶mÛ©V‹ïõã õ´ A1äæòì³èõZ-óæQ¹2çÏó HZ-ׯӵkÑÇ^¿N¯^™‰ÁÀÇóÔS3fËÕ«(•„„ðí·lÝÊ”)(˜ÍLšD÷î(;ÆÄ‰hµdgÓ­cÇ=KaNžäÕWqs#'“‰É“éÔ‰U«8z”iÓÆŽåõ׉ˆÈ3F¡ -'ŸäÃq,ªDâÕ«LšÄÅ‹¼þ:ƒç5fd0c{÷¢ÓáìÌW_áUx½~ûo¾Á×—›7©\™ÿþOOvîäÝw‘$ôzFfÈ~ý•å˹pO?ÅÓ“!C4ˆäd>ücǰX cÆŒ§4›³!2l2é-rKV¡Î’\+¿gá>…ÑË~ß²R·•‡ç³a”m.œZc„ì¢Ôsÿ5!!!mÛ¶6oÞ|¥„ߥ‡Šü7×Pè)cQgïa ›‚{†Å•+¼ü2£F±o§Na6³};}ûâîNƒÔ+1®¯Ó1h®®ôëlj·œ¹gŸ¥];BBhÚ”Œ Ž¥gO<=éÝ›sçˆ%!ýûyé%t:‚‚¨_¿¤Y¾úŠÏ?gÁ‚¼.àãCïÞ¸»Ó»7.’Rì±]»âëKDÕª±kWÑ}Ôj¼½ ÖDÝ´‰nݨ]gg7.)‹ ,Œºu E§#&†ÄDΣwo<=‰Œ$7—7ÐéðõE­ÆÃ_ß¼ÑÖ¯G§ã·ßøñGŒF¢£ó å·ß ž“Áƒ‰Š"(ÀlfÛ6ºw§R%jצuk€øxNž$7—ï¾cËÒÒ¸x''||Ðjóæ-!ÙjÙ2 @£!¬HßG–ûèŒþ Ûÿõ ?_jå^°ÖÜùQ»` ƒ­6ïÀỲ!nj¼a¿·8Òàú]M a*ì+¾ƒÞ‡aÐò3{b` ÑEõ·­ærE®d]$üÑð' ƒ>ðc¡>›a†c÷3|_ü€ 0ÒŠïP$I6:—·ÏNÏÂg…žÚ oÃiN(4ïyø.[ä]¡P4lذQ£FÙÙÙk×®M)áªÿÀÉÅp–Ëoî’B}þ.êì@‚8H/­ q¥÷º-J°¹Èy¯•Ѽ‚;AQîôK7nä‹/=šiÓèÖ £IÊË’´Rò¢­Z—Iiõärå;=W×[–¹¹HÖ-SZ- &&P’od˵k\¹Bll^äP©nÍ+I˜íò"¯V´²pƒƒ]7£‘’1› º§Å¡TÚ¥“šÍHRÞyÓhP(n™]x ggÔjÔjºt¡›\†ÃÙ™¦M &wVªD“&X¹,L¦¼)$)ovë¤:j5ŽŽ¼ôÒ­U~ë{Z2ôïONNIžý£HÙ;£jÔ–B;Ïca¬}¤ðî¸z/î±0¾xéæøÁ4{Á¿'ŠÙ \*K`R¡Æw •~)’ßaÜ]M (¡…¬ùZ$x&CŠCÓ`8)Ô_½mþÍèB}ò9ãÀž„iP£¨º‹Áaóo,Ä?àBø½ÐÞçRùê®n~À4h ç =U Ú*6V˜™°ôÖ8¨OªY'a‘]GWÉU)‹Õju»víBBBnܸ±qãFƒá¾Æî” ¥NÒÝV×]0 ÔЦAµ¢ÞÜPû7·HŒð–,§_2aüm™V:V›«–X4Ÿàå <‚2CƒF{K{Ïw‹»ò‘[÷+‘ØXjÖ¤C*TàÈ•Šðp¶nÅl&)‰³%G€´4öîص _ß‚€¬øùÀ¾}Hû÷ãéIp0„†ò믘Í ·VØ‹äÓO™;—©SÉ×F½y“$vîÄ×ww4âãÉÍåÒ%Ο¿uìÞ½ÄÆrö,µåJÝ~~œ8AzzžKš›KFFž%y±m‰‰H7oæyÏ·ƒ•*åÀãÇQ(n%›ªÕܸAFFž»Ü¤  #G2v,ä8Ë—2„cÇì†ýùg^xë×4""X»–ë×9s†;<=ñ÷§jU^{1cèÓ‡ ò&•$.\ #ãVh¹0Uª0dîî\½KУCÙgÀú¨|**¨P™m¯ÁK¡*´`%X ÌÐꃶÈ厚@OYj$þ€Sàƒ ŠÍ4—`=t‚Ø ;!U®&ï fØÿ@ øÊ€6ÁNð€~@,‡ à=l*Ž+Àž‚ø de# ‡°údÁ¯Ð2`X ‘à'a-`ï›fÀ€ Á(¨gàOH‚ê0L𬇋ð¸Ã`8›á˜á,Ô‡p¶ÊÕhV/Ô‚(Ø Gá ÐÁPÐA"ü— €Õy8Ñà[¡¼ I° TPK6X‚£° *ôOì~¡VQ+˜[á@¡›–ÂAƒ6º6Ì…²¸¬/øÚW#¾ƒTû÷Ëún~©Ð:Úø|ið=| pV;€ºÐÀ`8 ¨ aìGÐCè*¸ Ëá´€.ýSèpNØ·)rí†üWº ¶@4€>¿Ãn8 9}PiUR¥ý›ð´$Ð7ÐOsë.ÇÙÙ¹sçÎ?ÿüóÉ“'Fãý”Á÷RyùéýÔ¨M¶¹F8Ñ0PnÑÃwÐU~sý ©5eÁeóÙL° 6ƒÚB78 «à(è!jÀÓE™e€E°Gþ"8ÀÒ`œ€*ògo \ƒh ;àihÛ! CDB;YvªpY£•pr t Ì‚Cpf^dÂr8!0<áh ÕïüNé±G‰²83Ðè­*R£ëQ¥}{¾ü’!CÈÌ$6–jÕP©˜4‰#ˆ%9?¿’’u:Æ'8˜#GøôÓ¼J÷®±Ešî IDAT®èìï§Nå³ÏØ´‰ãÇyóͼmãŸ|Âûïsè™™4nÌÛoßÙZ-“'óÝwœ:Ř1xxм9³f1t(z=ÞÞyQöìaȉˆÈÛ_ ̇²s'¯¼B§N|÷7rñ"çα};#GÒ¥ ÇsàÏ=G` ™™Ìk§Wš“Ó­¦—ŽŽ891n|@t4/Ò¯!!yºvå³ÏˆŠbÀž}–W^aÔ(ÆÍ+W˜5‹Æ²³Ù¿?Og Ÿk×8xðVìyäHfð`4L&t:¼½yë->ù„M›°XHKcÞ<ªTÁɉ®]™;—+èÜ™—^*鬺¸”C}´({gÔ[åh TKj³BvF“àk˜);s‹`/¼ ±ð ¬‡j0Z@XWa<áHApŽØ8£Çàeˆ”ãv ¡ÔƒÿÁ9x6ÃH ð>Œ‚'à+øFÀ ?‚'L t†SpÔÆ¹I„E0 <à,L‡>ð< ÇÁêÂ4¨ á0|nS«‰¢jÜ}õdHÀž„Tˆ-Œ‚vPÎA2¸ƒÂf(…Í’tñOÂç²3ºê@­BÇxb ,„ø€½ð–|þËkÙfˆ‚ê²P¢ ¢ÀÃï°·`ˆ®`„)`»ó ü½`œ…ÏåvëbtÉ¡_†CÐÙæeþ ÿ>ð<ü"åöÿ'tà"¼ Ï@[˜ >ÐÖÃHx ÎÀ3°Iž¢ÀMö è ¡L‡,x‡õ £aµì¬'a Œ€8)¿…Í{—?¸„Ê ÖÀ—\¬ñü€ó5šÖðôÌ« èСÊ+ªW¯^£F©²ºe†›ÒÍ_/‹×MåM$H€ð œ„66Îè!Ø+Jî ¶©±ÆÀxÈ…ƒ6ÕêÍ·qþ ŸO=Œ…0VÀ1˜ ÿƒLPÀ/0ރͰ¾†1ààOhYÌ,ó ¸Â{`‚¾63æ[(ÁÿÁÁ˜Ga„Â`h ~¢Bæ¿ÅAr0xkÊ•3Zµ*ÿÍ•+88P©Rž¯ÁêÕ\»†‹ >>=K[üýY¼˜sç º•]:aBÁÅýaÃhÔˆ´4\\¨W/oY¹G5âÊ$ÉnÛøíàíÍüù$'@x8J%aa,_ÎÍ› PäÅhgÍÂÑ‘˜ j×¾•Ð¥ áádeå¥`öîm·ƒÊZ(ÕúÒNÊón‹ÜJôíKùz²`Až¾U„…‘”„‹ áá·–ûßz‹>}0ðóòbçNa2áíM5Y´¸Jþú‹J•ì&6Œ§Ÿ¦¢¬\±"?þHBj5o½•wlÏž4lHl,@¥J·:C÷îèõž +Ö{‰ƒ©Q#/ªZ({gÔSå øYü®ªä òOàkãCàuöÁJ à<Ü„f°ÆÀ Ødg(‰ÿ,‡ð†\¶d\€ÐvC,®`½;@,„÷àIˆ„§á 4‡SÐ šB{é¿@=äýà¹ÞýJ8ý¡.¬€†ð;4‡Ê ‚:° úA¾~o-¨u²Þ…^ !êC3è'¿´W ”ð¦|ˆµê÷nè}Š\aHjsìUX¿@ …Wá-¹‹ ,?Ù%Œ…½6j`\‚«Ð>.~ê"iM`ª}£ ¾?†~ð©ËœmKÓÙŽ…2z›Ã †ˆ‚ „\Xä00à_‚€íÐ~„¾ð`†ú°Âëp|lNà_ò{á FXÏ€#¤€5}'°Ä:‡#À ¾µiI4‚šà-{¨¯Ái¨b3/ÐÚÐøAÍùhÎ×ʯGŽ9tèPkßðððøøø;vtìØÑÕÕöc}qV8)ƒüÍþ7õ7™Ë@}à#áw#| OÚG=  ƒQ ²O¹ŽWh r$µT…mÐ^¶é™ 7poÐÂKà‰6çó,ü [ÀêÃSð ( 7˜Á lÒ3ZÃG Á ø±xgô;8)ÐÖ@Kጓ?ØgáØ• ZÃç0 ®À?°¾„ÎðŽüIÜžÏ Re‘uJa*U*è÷!!·ây’ÄéÓv‰˜:Ý-qøªU ÅU+¡N"+V¼å0Ý)¡¡4jd×R½zA§Ö*óXT ±Ê•o= *ÚfŽ&¥UÁõöÆ[¾=©"¶¬ÎqaÔꂺ¹Ñ¬P LGÇ"÷õµ Íž=Ë;ïPµ* ddð¤\b78¸ˆrYjõ-O·œœ5Š ¸y“ÏJÍ­D({gT…ª¦¶f÷œîßë¾×+ô¤Ãa¢}‘Zr¶ª?\†dx2¡\ƒ$0ÂUûj(ùWçÍ I¶=FB"Ô’„€ëÐUžÂ=‡tø¢ä_kšã;ð ,ƒ˜MÈ€ÿÁ@ûD-h@+ÿ®¨a°1Ý3n#°žòO²5vRÂÐBm˜y·9¦%&°~Â!dg´Š<¢˜ÀL6¼ ¡!ä–Q\ ]àe¨Ýà0$Ÿà‹ämþp, A"x€'èàh(c½Ruƒp¦Ãly‡ìÈ€¾¥½ÎV`†9àt›-JÅÞ…Ñp ÆÀ:°ºÎ…Ò%­ØºƒZä×k›¯©°Wr%$Bˆmñõ² s 6Âið†-6!I…¼o‹Ò@*mÁ1 rÀ ’@ >r¶hhmßS{{×®‚T #üÆØ‡½ ã‰ò9¼aÿ‘³=P¾–}µœçÚ_„(ãf)í$¸Ã<¸»áU P”¦”‰f±æÌgâRã";D._¾¼ž½²‹ƒƒÃÅ‹M&“B¡°*᫊/,XVÔÑÖialqÆéÌš¨5–ý–Á0†AÐÌðœ R€R÷Â2ˆƒí0Ê)§>á@kXJEµý¾‚ ,ÃØ ›Â˜Ê¶ÊdIo³ŸOm/w°ªÁ¯Œ·Ù¹¯¶÷ÁæÙ|ï¼`%ü !| -Dòè¿¢¾±~;S»f.ÍTwxäQ*Y° ˆvwwF– ]rÏ dĈ0ïC…‹ :+>ÅrüëãÒKRA§g)´†ëp>$ÁP×rÌ£øÁ4x΃?Xk°ºAx &BUð„ 80[ޤ‚ÿƒÙ`€­P  3̇I`†­0üás¨>`’:³á[èåžý 3|ÙT—.Ì.H€Ø ÙТ˜çuX*;¸¶¿Žµ`®œêÐFþ¥¬KÁ*C}¨zø”°ò×DjÀEX>м¡Ì…‘ð ´)j`} ×aX )¸‚ƒ¼²9ݦ³ªÃMä¨R0(ák¨ÝÀ«Af9ÿÁzK— S¡¯`Ö@,.*µ9Œ…å à‚ƒp V@%ù%o†•àËàsPÁ*H‡>¥¹Å½á}h—!Þ&ÅÂÖAu¨M¡3|k 9œgyÓL‘µÔ+À ø *C3H=p`5T&°ö@p7›%þš°ªA 4/ø5U¢ º°?`äÈ‘}:ôñÎ_|²'55uÇŽýúõ;xð ŸŸ_£FE–É+;´ mk§ÖqYqIŽIž8`|ÂÈ5Ø›¡?œ‡°°PP³&Ì !¢áÜ€¿ä7wœ‚f Îò‰²~öÖ@ T}\w{ÏÒJ…¥à]¡Ô…Yð"ÄÁ9˜Z$ëa%8ÂJ˜)76ƒ °ª@C…a\ƒŸå+ò¦ûŸAOC-¨ 3åløƒ0VB[˜Á"[ô_¡BUÃX£GnÖŽ­=•%\‘ÁCǽª'UI]©›S·SQ§bsbÍýÌi#`6HðÔŒ…oÀ^‚LЂ,†9ð!8ÉÊ,ù1•Q'¡Œo@ /‚4 _À?à -Á”ð1|Ÿƒ"lÒ€Âä4Ö ýl¬õ€Þà ½ÀZØÄN:@”Mj©•`›S¼Î@ ˆƒ8¨~à ½í#pˆ•ó&_†ü{©f0¶4—§¶fÙþ O@}¨a1T„W¡±|l+˜;ÀZ€|³a:„À[r·pûÈ8Ç¡$Â::0¢@‚>6 jøæÁßPQvF]á;øNC70Ë)³ÃáoÐ@wð„q`¡ª¼fºBà) Ò^… Ð ÁuY  ÖASh a<ü©0zƒ >‡—m’=€@ ‡6[Éqµ>ó@_ËQ7àyÈ€õPC-XßÃ*ð‚Q…ì,`óë°  $Á?`„Ö°Ò¡ 8ÃQØZøÈf‹Þ`È„MPšÚ}Mu’®¥¾e¿.O,x¢Cµ¢¤¯ðåË—­ÑÍ›7ûúúÎQ*küT~Ýœº¹ä¸T5V]ç´.±R¢ôœÄsrX´^Q9—Ï@¬‡Ð®ÉŸ–êð7D@#p’ãñ:˜ þ€œ¿kýì5**àšO3˜ÛÁ º‚~€¹ðh¡( T…,p/xQ>6–Á ùCe¥Œ‚ ÐÂÓp¦+|hãS6€we}eë®5ë5í}p€n „oþÝàfqk§oiˆláØ¢†öþíÛeÂ=,nZS[3èjЈ7F¸¨]ÎdŸ¹ªºzU}5S‘™A†ö)­výbØKP@ÈÀ•a–}KWùÖ&˜ñ¼`w¨ñš1Ó=S5N%%J¬Äµ±«Ò¢ÄÞ(4Å›…ZNÂ(±Y÷‘Õ:­Þ[e‹Á’}#Ûø—ѹ©³C5»•ô±òPVþ¯Ð©±€»hRÈó #t´o¼ð¼¼+ËJ(| ÓÇÆÂ±ö;ý­xÁûöÍì³BK×PÂ0ȯêVfÛw°@mûýLùzØÅê-Ž’ƒÙ§‚¹BuSõED+çVꢲýí‘$©jÕªþþþüûï¿ûõë—¿éþ¡@ª õQùTÊ­T3³æIõÉëªëWTWÒÓÒ¥‰q ,tÒòå– ´5à°ill/2Ÿ?B Í^ºÞ •̓µ[øÔ¾Ïpûÿ²¥lEm…ÓÛ6Yo–¼×yk×”õr4ÙþpIÎÐ(ð¬Pèc_¾ôYî'Z´:Içkö­hªXÍ\­©¢iK]Ëu ÚÈ; ²²¸ëK§ŸR¯]»ñÔ /ðå—¸Ý~˜à±ç:£À‡ïhÆkŠ3Å%šõ‰ŠŒ?¼þ¨¡©ž^úñwKâÍÄuÓÖådç¨ÕêÃÔmZW•uÛùCÖÒAÙ¥ôJ‹Mûó?¹ŠÎS;ûüDmÀ²Áªît;eBo‡¹&SY øàp‘\|”>¾j_GÿŠêŠZEÑZß…Ñh4íÛ·OHHˆ‰‰Ù¸qc=´ÚÛ=ö®qUº¶wnf ‹7Åß0ÝHÒ'¥kÓÍ3Ìðˆ½Û\¶i´Í³š?hCE @á‚‹—ÂË_íï§ñ»£ï…8|˜9søñGîNØ`(XQ)Ÿ•+ùäጠî€{ëŒ*TÁêà`u0`’L ýfösppÐ:ÞË«FcÞþûmÉ")÷ª,œ¥šåŨ]Ý\•ªrUçCð¢@¡F­QÜåkN—¯„ïïïߪU«²5¯H”(+¨+TPW̘ ’¡ nÿ£À ±ƒ …“îñÞü°ò/¿åIb÷n¼½Ù»†îݱj»¥¤ð÷ߤ¤Ð®µjlÞ̾};ƪU(•tíŠR‰Éıc8@ÅŠ´m[l÷”vï¦Q£[¥’€ìl6o&&†V­Ê›»à>pÏQ»Éj5jgb>àeÎ=ÝL©ÆÅëöêõ šÀÀÀÈÈÈ¿þúkçÎ~~~÷!yÔ*'Å#éÏ9»Þ¯‹•@PHãÇ“•ÅSO±q#ÑÑ̘ÁÀ³Ïb±Ð 3f°l-Z°q#ÇŽ‘œÌÊ•(tîŒRÉìÙ,YB‡,Y† |öEŠp$'³z5k×òúëüßÿåÍ;y26ж-‹,J$”Ê}uFÁƒ",,,>>~ûöíëׯïÑ£Gé‚G…‚W^áå—Y»– ˜1ƒ½{9x+Wpq!7—¹siÞœ?fÓ&¦LaÁ‚<óÆ ¦Oç?hÒ„„""˜2åV M[ªVeÞ<ž¶ÙöÇ?°z5Í›óÏ?ôìYÄQA gT x,P*•-[¶¼yóæ©S§þùçŸ:EZ>ÖêAÕ«““pî5kæÕØŒˆ`þ|$‰Â:o.•ÅìÙy)¤Z-ׯíŒæòetº¼rDµjåµnጠ ‘‘‘III±±±uëÖ}Ð ‚{Ž£#yÓÒpt¼å‰J6‰Ü®®8:2~ü­Òð¡ªx“YYèõÙÙvà ·ƒØ|#ÌéÓH5jÎÆxzâäÄÑ£¨‹‰VÅÇsú4™™yRR¨U‹-âÊ-"ë‘Í< gT x¼¨R¥ÊOË{ïñÞ{Ûµ£]»;µW ÈC8£Ác‡Z­®Q£†^¯Ý°aC=4!Ö(ì¸t‰~°S¶úiš5+þànΨ@ð8âääÔ¡C‡+Vœ8qÂßß¿eË–Ê»+Ã"Ê):ááv ö÷¸œ°àñåîÑ .<÷ÜsâL x8Ù½{wÉ‚‚‚:vì¸bÅŠíÛ·ûúúÖ¬Yóv†‹‹5j”ƒÐn<²˜L¦3gÎàß!.pA9äêÕ«V ÑË—/Ÿ>}ºäÎ^^^]ºtqrr:xð`tt´Xô¸ÿlݺ5))©È§öìÙsŸíZ-ï¿O… ”ÞY¡`áBΟÇÁáÞ[&”ÂÊ'UªTyæ™gJÞ©]‹Å_B‡„„ƒÁ \¥{JNNŽ$I",*°¢TÒ¸ñôW©ŠÝä$<„gT (ŸxxxÜÝÆI’J¦Z,“É$œÑ{„ƒƒÃ]ijàÑEäŒ ;¬ëû%tpvvvtt¼oöÿ£‘s碣9s†_~Áߟ˜îP³NðP#v!å“þýû÷îÝ[T6…iÕŠ  œé×Í›±Xøûoú÷ÇÏ Y3T*€°0\]ñõÅÅ…¸8Ìf*W&;›^`ΔʼnEâëË3Ï TòÌ3\¸@zz^ûÓOÓ®*AF/2h O>IB ܼɉŒ‰ƒ..4làåEb"/¿Ì—_’]Ò¼‚Gጠ@ð`2Q8‹X¯§€ô‚Å£æ¥ IDAT‚^O©Ê`jyeT£É!'§ØZöÞÞ(• HU«²f mÛ²v-O=E\\±Säû‹Z-J%ùeÝ*W¾•îi6#IyÿªÕ( yöˆ¹†‡ó×_tìÈúõtéBLLI¯Îdʳ6IÂ`Àd²ëfm*jœ»Y¦7›ÍÙÙÙenŠ@ðð Ñhõ= f³ÙºýE­V«Õ"!G x´±Xøâ ®\aÞ¼[F#}û2lýúÝj¹5iFãÇÓ¸1/½t«Û¹sLžÌèÑ´iSÒ¹Ükîæ'êÈ‘#/¿ü²©Àý…@PŽxöÙg'Mšô ­øWìܹ3::Z’¤fÍš5oÞüA›#(·$%%FoooF#I’ÅbQ•ݪÉdJNNV«Õ^E:2’ĉœ>m×h±°y3mÛÚ5&%±e ))%¦Õb2ñÌ3¸¹qìÓ§£P0f Ï<Àqþ66vôèÑiiiÛ·oÿ7/§ T2e YYvZ-6P©’]cÓ¦lØ@xxI£ ÌÀ$%‘›K•*yy¢þþlÚÄñãøû£Õòúë89¡VS·.¬^NGd$ÁÁyY›õêQÂgÄË‹¨(®]cÊÂÂòÖâ_|‘E3$"‚„<<¨Q#ïÙ§žbóf.\Àb¡F €ˆ~øŒ 4êÔ)i^`ìXžoï[-üïѰ0þú‹*UJJp¸ûÅ»Zµjý÷¿ÿË‚rÆòåËgΜù ­0­[·ž9sf·nÝJíùî»ï®^½ÚúØÓÓ388¸H­þ .Œ1béÒ¥ÁÁÁ¶í—.]êÓ§OTTTݺu 2qâÄwÞyç®^D¹B¡ Zµ" /{¸»SªN€µÈZ/pp@ÖϨ\9ïÕ«kÚÈóAo“àà‚Ù…'ªV-"ÂêímçM:8P»öíΛoy>juy ..y/Jð`¹{WÒÉÉ)""B[œ¨ƒ@ðhr¨¼ÔÈsppÐ í /^ܳgOÅŠ“’’®]»Ö¾}ûÚµk+ “É´k×®£GzzzvêÔÉÇÇgóæÍééé;vìHKKëÖ­›‹‹Ë‘#GvíÚåììܵk×€€€"ÇOOO‰‰ ²J8vìØ®]»t:]óæÍCBBvìØ‘’’²bÅŠààà:8;;ƒaÇŽééékÖ¬9sæL‡\\\8pàÀN׬Y³°°°ûzŽeGh(|P´©@P±›^ (ŸtíÚuüøñãÇoß¾ýƒ¶EðP`0–,YÒ¿ÿÍ›7ŸÉÉÉÙ¿ÿ‹/¾èééyñâÅ1cƤ§§gddèõúÔÔÔôôt³¼ý[’¤ÌÌL£Ñ˜‘‘‘––f2™¾ûî» &¸ººž}I’æÌ™³sçÎ;M§Ó…††þþûïÂ-‹Årâĉ}ûöíÛ·ïteBÁãÊ¥K—Μ9sùòåãÇoÞ¼933sÇŽjµú¹çžûì³Ï6mÚôÅ_(ŠŽ;5kÖl?11qÏž=æ¬ ‚{X¦¼°$ÔjµÉd2›ÍNNNùâ\z½^¯×«ÕjgggkôbÆ ýû÷¯X±¢£££B¡0 ¹¹¹*•ÊÙÙ¹°t‹ÅbÉÎΖ$©ð˜•*UÊ/Þ¦M› 6ƒaïÞ½^^^7Öjµ¶aÖ¡,‹V«Íײµ65¬Šs ×ëÍf³V«ÍÍÍ•$I§Ó)•âæ*½^o0T*•ðÚùäææ¶jÕ ÈÎÎNKK{÷Ýw³ÙP(ûöí›:u*`0FÝ¡C‡)S¦ÄÆÆNœ81((è믿ÎÈȘ0aBvv¶Ñhìׯߋ/¾hë †™3gnÙ²E¥R~ñÅžžž×®]3fŒÁ`pww‹‹ŒFãK/½téÒ¥;wFEEíØ±ãäÉ“K—.8qâ“O>iJ’¤éÓ§ÿóÏ?>>>YYYÿùÏÂÂÂ$Iš1cƪU«üüüü¬êÌ0yòäíÛ··jÕêâÅ‹ñññݺu›8qb–~yÔQ©TÖP“ɤ×ëoG½\P¾ /F }À€ °m©]»ö'Ÿ|’ÿoçÎ;wî\ܱù_xá…üÇ#GŽ,Ð322222ÒúØ6Ó´M›6mlª1öíÛ·¯MIœÂã‚r†pF/†ºaÆcÇŽ­X±âÂ… V·ÒÃÃã7Þ2dȨQ£víÚ5hР7Θ1cÇŽ³gÏnÖ¬™Á`7n\5¦M›vúôéîÝ»·k×κãÁÊ–-[–.]ºuëVww÷¡C‡ÎŸ?âĉï½÷žŸŸßüùó¯]»h4šo¿ýÖÛÛ>|ø¦M›ºwï>pàÀF^¾|yþüù5jÔX¸pá»ï¾»|ùòƒ~þùç‡ 9r¤5Ú÷ÙgŸ=ùä“7oÞüí·ß®^½Ù¤I“ûx:^zö왞žn.kl«ï @ð0!œÑÇ‘:x{{›L&ggçøøx£ÑxîÜ9kØ£víÚ¾¾¾ÑÑÑíÚµËoß>Ãÿ³wßáQm‡gKʦW’@H$ôÐ{ïH ŠTi" ¢ øêûZ>±#Š"v±bCPP‘ÔÐ$BzßdÛÙïÝM6•baîËËkwöœ3s–’‡93Ï£×?öØcƒA–常¸äää7*ŠéÓ§ÿúë¯&“iÙ²e@VVÖž={ôzýáÇŸþy¥R}c“$iÖ¬Y+V¬Ðétiii–ô1üñGëÖ­-û*ÆŒsòäÉâãcbb EHHHÛ¶mwìØ!‚Q …BPYròÚa6ëeY§×'hµGÆ,³ÙP‡ƒ.³Ré¡Ñ´srj¡P8I’H%7Œ ˜L&û•…²,—Ùän6›Ífs¿~ý,ùY†¥Óézõê%I’^¯oѢŘ1c€#FÏï½ö•‹™™™Ã‡ã7¼oß¾·Þz $©²õ Å}ɲ\aB¡.È&%=SX+ËWœqrBüâ5ÁlF¯') ðÕhº=áâÒM’ÄrA¸™ˆ`ôÖbÙ·d4F£^¯7›Íz½ÞÏϯyóæ»ví :sæLVVVçΕJ¥«««Á`ذaƒO»víRRR:w—wçw¾ûî»á¶JÉýû÷ß¾}{TT”‹‹Ëk¯½¦×ë»uë½uëÖ!C†dff9rÄ2¥ªÓéÌf³N§S«Õ™™™qqqÇŽ‹‰‰Y»ví¤I“òóó‹ŠŠºt阕•%˲^¯ïÑ£Ç /¼œœìëë»{÷nY– ƒeäöíÛ‡ ’}òäÉ%K–Ôå—[Ÿ˜L¦ŒŒ Y–Ífsaaappp­=©7™òRSßJIyÅ×7+8X„¡Bm0›)*JÏÊÚræÌ.?¿Å‹T*¯º” ×J£·–¯¾újÿþýqqq:uúñÇsss_|ñÅÏ>ûlùòå‹-Ú°aÃåË——,Yf4ûôéóÌ3Ï~òÉ'Ï?ÿüüùóÿúë/­VaÙ‘#GîÝ»wèСM›6U(ï½÷žJ¥zâ‰'&OžgΜáÇ·jÕÊ`0\¾|ùµ×^ûïÿ œ?~Ò¤IñññóæÍëÝ»w}¯õNNNÎ_|aÉëèè8sæÌâ„5ÊhÌ:þnîûæÍqs«…@’pvÆÙw÷‚„„góóÿ_§Ry×õ¸A¸&"½µLŸ>}úôé–×ãÇ/nïÙ³ç¾}û._¾ìëëëìì ¨Tª×_ÝþÜß~ûíÊ•+¾¾¾å ô©Õê—_~9++ ðò²NHDDDXÝÛûú믋_—Ù3{îÜ9ooo`ùòåEEE–­N/¾øâ‹/¾XþŽæÏŸß»woƒÁ`°`áää$˲Éd*.^ÃÌ©©ïëõßGF¢µuÁÕ•ÈHΜÙqåÊëMš<#ri ÂMAüA¬”Jepp°%­B¡ ª¢T´——Wq$z,‘¨…‹‹ËUƒËU«V%&&®^½Z§Ó‰H´ ƒÁ`4-¯-k3j¡Óüü©©Ëš4‘¨P—”J‚ƒÍ™™oåå]_M AêJ]þÐ0c–ͲŒlFäå®[§îÞÿä}ÀÁÅAoÖ—ùTBRH  ‰[qÅ¢““Stt´ƒƒƒ,ËF£±ŠcTYÖ]¾¼ÔÇ'Ë㦻„«pqÁÏ/;)陈ˆŸ%IüÛH껺ùSš#ç\0\H3¥]1]É’³ Í…u2 áæ Á‡õ‡)‹¢Qh¼$/¥*¨©ª©›âÖZÀèááa)êXkŒÆ ƒáxéÒ<‚Pg¼¼ÈÈøG¯¿èèV×cá*j;•‘êŽî.Ú§ŒKT%&©“U‰y’¨ó&T³9ÄÙäÜÔÔ4DÒ¡°C_ç¾QQJD—šb4f˜L‰¢Ì“PO¨T(éz}‚F¡þ«Õ`4_Îß®Ýþ—ü×7.ßœQOç…š“£ÈIP$œRŸ"‘IÚ¤†œ¸(\êzhµÁl6›L&KâU³Ù¬T*k: «V{ØÁÁ RU¸ ÝÌ¿øÃn2QX I¸Ô⯞,£Õ(h4e?ÍÏÇÕµö#TI¢Üj• ‡¢ÂÂÜÜú×ÅA¸µŒš0m×nÿNñÝ.?HµÖ¯ œRZá¶â’ö’Akã2Fy $ľxñâúõë›6mêêêzâĉ &4®á'èFcº““8YÞjµ:D÷î8:fЂñÆ®üçŸÌ™CA:/^å`ƒß§W/œœn¬·.ƒN‡$aWó @–ñöF_nqH/’@¯^õ"Ó꟢Ñy}g]¾ÌÇ3w.þþ53¬j — 7ã:;ë Õþ€A¸^µ·›þ¨îèAóÁõÎëE$*Ô>­¤ýVóm¬{LKüp2ÙÙÙùùùZ­6;;Û’u«F™Íè rd9'99çÑGs23sL¦³9·85™(ÞÙo6#˘LÖ–*]ů-í@—.ÄÅñÑGtj9½¸^˜,“›ËÂ…¤¤”œ^Üoé²bW׬qqüðCÊ2«W—m·ÜZq/&»vñØc ÜX2ƒ2wg¹fq{™ÃìoÖòíŸhy»|9ß|Sö‚åÏ-ÃÏmÛX½ºªcêš y–ßxeþS(Šêzl‚ \“ZšÍ2eí)Ú³Îe]¡$ö* uC+i×kÖ†¨C<µ‘¾Î¹»»[^§yªo¼ÁŽÄÇsß}xzòè£DEQXȧŸ²oJ%wßMïÞlßΦMdgÓ¬—.Ѭ>Ê©S¬^RÉÅ‹„…ñè£Øn¢YfãF~ø£??x€¦MY±‚ýû¹t‰ÄÝ… éÜŽ/¾à·ßpp`Ú4 ²^áÊbc4ˆâLf3‡“›ËÀUÝÝwß±~=f3“&•4îÙÃûïc6ãèÈÒ¥øú2cçÎqîÓ§#I|þ¹5ãUR‡3`@©¢ ×Ó«ÅUoÿù‡+ÈÍÅÑ‘çŸ'0`Þ<¦NåóÏÑj™;—ùûoÞ{ü|Z·fáB4yë-._F¥âŽ;9’£Gyí5àèQN¢];/ÆÁ¸8Þ{¼<:vdþü –"j5÷ßÏK/1m×ðk/‚pýjifô¬áì~ÕþóªóµÓ Tè”êÔAÕÁxC|]¤ÆI’äéééàààîîÞ¨Q£ZHíd¯[7†ÅË‹‘#=__d™—^âóÏ™5‹þý¹÷^.^äìY~ÿ>}X¹’ŽY³†Ó§IIaåJ4æÌáÐ!žzªâ.L&.^äöÛY°Ibî\ ºwç¶ÛpwgøpÆŽ%(Yæ•Wxë-æÌaØ0k¿{÷2q"©©%×´üàƒW¹»¨(ÆcݺRwÜÁС,ZDß¾ÖIıcéÜOOÆ#&¦$ÊüãbbHH(uú’%,^ŒÁ`}›šÊ!øøðÀtîl]º lØÀ#УC†PXH|<#GÒ¶-÷ÞËÖ­|ø!@ZÍšqÿýÄİ`§NѨcÆDT11ôì‰RI|<ãÇÓ¢óæ±y3ï½WéýŽƒ6\åkA¸aµ43šfJ;«>+sÏÉ¡ºWO3¦™Í ;ÿhXXØ¢E‹,¯V=ÑWzö$(ˆÏ?gìXëZô46mâî»ñóÃË bc""8†þýùüs22xøa\])(`þ|^|±‚}Kj5'òóÏüõùù;†BAïÞ´iÃòåŒM“&¬[ÇÌ™Ö~›6å÷ß™: Mžû* S§’ž~•»kÓ†V­˜2¥TcA—.Ѧ 'Z–É2a‡3aJ»UÊíÛ³tiÙYƻ聆°¤XÀÏ?ãïÏããìL·n¥Ž|î9FŽ´¾~á""èÙµšÛogëVæÎ¥C²²8p€ÔT”Jöïgöln¿ï¿§eKî¼Ózî÷ßHÿþ880a›6qï½Tøo†{îáÙ0oQ_S„PKÁèã•+NWj§/A¨BŠ2åŠîŠÉlR‰Tص¨°Œ ¾þš”J<=IN.Ùî쌿¿ujÐÃÃÚ‚ÑHnnÁhv6£F€x{[/[žÉDn.k×òÓO EI¼Õ²%-[–:X’3æopÝ:>ø€×_G£á§ŸªÚ'YÁ§veq23 ®¸U»v%¯328{–dz¾mÞ¼dzòdÚ´aëÖJ‡qáçÎñßÿZ߆„`0TŒ&ðÖ[lÚÄŒ•^Pá†ÕÆÏã|9?GÊÑ)tžT°PO^‹ ¾€d ýÿu¯2˜©ž´’ûa#˜¡Œ»ÚÁfÿE¿Áz•kσ/!Urâ%p‡\pƒë-cÓ5ü^È…\p‡k¶ùúL¢ÂßoùÊü 2n©Iz³Ù Ôtj§òL&ŠlH45â‘Gˆ‰±~¤P”Ý¢^,=ÔTüý9yWW,¥^-+GeÙú¼;>žK—Ø·•Šo¿-uºe ”…JE£F<ü0&”ôkqþ<;v0aBÉÚM³™_%+Ëz°…$¡Õ–ô[™Áƒ6Œ¢"†gãFk¸éì\Á¾Ÿøx~ûÛo/5˸e :cÆXçP9}š¢"ÔjdI*ÙoŸ% $„ŽY»GGÌfÌf ¶oç™g˜4 ­–^(u#öƒ‰Œ¤}{Ö¯·R–KMß–áéÉ=÷ðÁŒ‡¨°%Bµ«¥É¡"вÈ*¢Ê½¯ÀI¸³òxëºì€ï`9üûÅr>Ð~­×ŒþÂ;7Ú×q®(͇/ Oå_ÎbßÃ8˜TÉ1•ù–ÀUׄýßÂX ß_gµ.“Ì Û³¥lƒlhð9n/\¸pöìÙfÍš9::þõ×_aaa­[·®Í¸»ãàÀ“OÒ·/£FÈÌ™<ñW®àèÈîÝ<úh¥ç¦§óØcôíËŠÜuM›âîÎÃÓ¥ S§Š›K—âçÇòå%çªÕxxðŸÿ0p ÇӴ)sçòĤ¦¢Ñðë¯,[FPÀ_ñÀ TŒÊ2«Vqüx©`´ys4|˜3³™U«¬‘ß IÜsÀèÑŒ‡³3 %“—­ZqâO?MÓ¦Ü}·5Ú‹eþ|zô(Œ¾ù&Œi=fÄ–-ã¾û˜0_~aÞ<*üÕ›0wßeñbzõ".ŽˆfÍ¢K>ýIâ»ï¸t©äàÞ½yûm4Z·fèPÆçãyäz÷&.Žî½·ª_Ð;îàí·Ù¶­Ô—#‚P-êôI¥ © \£Ð:€Ÿí€ ˆhjŒpá8@ȆH„Öp Úƒ+œ‡88'À Â@ fHƒ8h €K ƒdh'¡-ø@ ˜ Ò¡+¸C hYpÄnðfȇcÑà2$ÀQˆ…“ †[¿©p ²ò=c…pÆ•7e8 ‰p½9"eH8t éÐülc>á$( œÀ ™p¼¡m%c6B2UÓô³P­Îœ9³gÏ•Jåææk6›k9õöæóÏÙ·ôt,[ùçϧuköïG’7ް0 ÅLJÿýoo¦O'<œ³géÚ•Þ½9p€… ™6ÍzA6mbûv²³­×_·ŽŸ~"7—O>áÏ?­‡¹¸ðÕWìÙCRz=’ÄÌ™DD°{7ùùŒcgÚ´áÙgË®2…´´R7¢R±u+[·’™ `6[_¼ø¢õ…Ř1Ö·ï¼ÃðáÖÆˆ¶mãèÑR×l׎_¤QéUΚUjͨ»;¿üÂW_qâáá% LŸ|²Ôž÷  ~ûuëHH 8˜þýž~š¯¿æüyÆŽeÂ""Jº åÌòò¬çþô“õܦM¹jíØ€fÎä½÷1Bdû¡šÕQ0j„=° ¶Ãf¸¯ÃIH€Ÿán˜Ça „ÃEèoƒÒ „A>Àc°ö dð‡0xþŽA2ü¼á-€àè'`< á˜íÁz4‚¯á%øZÒáhYÑ-$ÀDpO8 ïCgX ‡á,x ásXà$ÌÅ•|'‰°ÎÀ#`ÙÏ+Ã2X ]á¤-Q£RO˜%Pƒ*PØþÁ=pBá8Œ‡W „Ðâà;h K!²ahàUˆ€`1t‚8K»ë«l]Œ‚ÆpŒ×ò5P„ºWûOç‹5oNóæ%o•Jú÷·L;Z_,X¶u“gÏúTS£ IDATâäÄÝws÷Ýe/جóæY_KíÛÓ¾½õm/»‡ !!„„”¼U(èÕ«Ô-[²¸ôFIbìØ n¤iSëô§åjÅë,íÍŸ_A#е+]»–j‰Š"*ªìaÅûŠŠyyqÿýe.,ÛT¶Ñ͹s+‰ƒÆ1lXIK£FÖoþ͘«ëÕSý ‚ \¯ZF“á øLp<¡Üa$/_á]H‚ }m ‡ÇÐÂ^¸a3<ƒ¾†µðlËÖ‡xX AøØžeßn°^€À²‘¶l L‚÷Áî!`‰Fð3¸‚^ƒ5Ð>€°~µ–ËàmÇ`.ÜYÉ‚Ëøì®$Â'ð!Œ„`ùi7 ì³p‡Àà+@ý¡xâÄ·ÃÓðÌWàü; ‚å°Ö6æévc΄Ça)ÜI0æC(Œ†A ¸Â.Ø«àp'Ì„Z}*%I’$IÎÎÎuÞoo:t¨ëA ¨ >Aø÷j=}VÀðxT9—væ B NØ£m†-‹½Tà .àTùã¡Þ…O !ÇöQ ¨mU -+ »Ùöõ„ŸÁXÑ÷¤‡Ça8‚FUÒïeH‚UðA*¤^óîŸ,(²…w­Á²Âì«rU¾-c³¬m°ßtì°Íª7°<¶ëh›ï,/ÎÃ7° Œ ƒs .¶ë÷â3` | ™ҲPwºuëîíí­V«g̘ázóÐ *M¶õ Å/Àv€~ƺ;üiØf÷ßç¶ðúZt=ì-l…î¶vo(‚Û˜A[¸} '(+ vsávÛZ‚8X`·óLAáÚÔz0Z¬9¼gl’@°/Bý0B[¸îË’%4+=KÚ<ÀÁ‚mó¬= A?¸ þð¼­ >'¸@íÜâ9ב¶ýæÅûFC tËV†`€HP\O¥5t…A0.‚?,ƒ÷¡%´„·m3å½m`¼màsð‡àˆ€5Ð l›´Šÿ ®d^Y‚ƶõ£@ x¦B\†â}-` …®p\á ØÐ–U2`WØÙµBý`4M&“N§;wîÜÅ‹eùJ­Z½Êç ½áë˜LÕs)A„†¤®‹ÐØOO®(ýQ ì*w¼?üQº¥xáãm|m{ë_”>²_¹YØ7m/•>w,Ø/´ó†ÕvoàçrÃ<á£Ò-½a_EG–ñ$ù„ØXþù‡¢"Þz ΜaÕ*ºuãÌNžÈÎfÆ ^z‰'X³¦¤„æ+¯Ë‘#œ:U¶º’½^½ˆŽæý÷Åä¨ B‰º^3*BuóððèׯŸåµ%0­ÛñT!7—÷ß'?oï’JBM›Òª@P:€^ÏSOqö,W®‘Az:€Ÿnn8:Ò¤ ’D~>[¶ ÑXƒË´4ÎW¾ÞZ­¦o_€€k­ÎèÒÅZºiìXvî¬øÄ¸8ÒÓ‰‹#.àâEÒÒðó#"‚‘#6ŒáÃéÓ§ª[^¸yóX´¨T%RA„[ÙÍŒZ¦ê[™â‰ú60A¸yHJ%J%öó¶e¢´ÂB-",Œ?Æ``Μ²Q*‘e 0™ $< <ß S’UÂh—æB¥*õ¶ÌannÖ.€Õ«±ì ûýw6ofçNfÓ¦RU7Ë5Šà`ÞŸÇ㦪%‚PSê_0ú+¤Á[Æ¢`%Â.hò¯/žj[u¥i"`Í5ä@MÇÒ‰«A77~ø*Ç äærÛmDFò矕Îw*téÂêÕÜy'ŽŽdf^ÇH,õ³³qsc÷nÚµ+ù(/¯äuûöÒ¾½õ€ÄD,µ ™6iÓÈÎæð᪂Qà‘GxôQ,àæ)Œ%‚Pƒj#UH 'œ¼ð*¤°ü§zôZ´Ö7:xþc‹DóàX ÑÕ4”§ \í‡ß5Y @(º†ƒŸ„N0·:ú®/¾ÆŠrººš]NRƒžÐÞ¼yó‘#Gbbb"##‹ŠŠÖ­[wåÊ•éÓ§7ªb1c=æêÊØ±ÌKÛ¶œ?§g¥GΚÅÞ½tè@³f?ÎÓO3kÖµö2r$;Òµ+$'³Â–i®GrrhÓ__vîÄ×—7Þ`Ⱥv%9IâÐ!€ÐPzöÄÝãÇYZY¡]›±cyúi>ý” ®ux‚  Xm£I㉧«É5YUzi.l†>vSžëÀw°òákØ Á²ác8 Ñp­ÜåyØÎpœ`*lËFZ/H„Åë ÎCDÚjW^‚Ï †Àm`€Ïá (Á.Â"‚À ~O˜áT, ¾ƒ¿À ¦B´­@ÑaH†d†Ù¤À§púÃÈ„Í0ü«éK¿å1f“]¾=Àà…—¢AoÝ+,,Ôét–K:îfÙJôêÅj[BßeËprB¡`ñb¦MC«Å×—ÂBÜÜe†ÇLJýûqqaýz<<Ðhøüs’“ÑéððÀǧâ.4~ù€aÃèÒ@­fËbc),¤kWŠS²zyqú4/–<¸Ÿ3‡ñãÉÎJ2†¦¤•ˆs™2¼å¨Tüï<û,sæ r¿ ‚ ÔÒcúe@ )ðŒêŒõýßð>¬ƒ¶võ{t°æÛJ¢ûA°­0’‡m¤s!ÀJÛEÔpAk Çà¼÷À*è ð>Üaà>f‹ùÎÁ(¸ zÂó ‡AðL¡Ȱ ž†! ž€?a2l©¤ôå^8 # ¦Ázð‚0p³õk9ë2Œ‚>ÐÞ€< Û`1 „90 t•)¡ú™‚”JéfJ½y½rrr$Irvv …R©Ôétz½¾®ÇuMœK‚9?ÛŸ2I"ÀVäÌݶÜÅòŒÛ²å((ÈÚ¨PиñUº$š6µ¾ÖhÐhJÚ»T´äÆþx oo¼½Kµxy]߆¤‰éу›$à Bͪ¥`ÔWéÛÜØ|ãÓvO@&L…=ÐÒnÐVȂɶ·}!>…‰¶Ø1vÂOÐ |a>¤C ÞðX~ ¥€/Üûa(\†Té°ZÀt[k ^58Àg0|a2œ„Û NÚþÌ‚qÐvÁÝçXˆ‚¿mŽ…©0ö@'»~ׂ,5¸À ˜_ÂX OB.<wUÇW/”f óSù5àÇôƒÁÛÛ[–e-ÈrssóòòR©êßñ[˜J%ê0 ‚ XÕÒϧ‡ˆ®y]œH8A<ô‚hhj‰šà˜ •†W œGiðô«é¶Ùc’vRwU÷H‡Èº‹ ‚ %juýü Í ;w,Î[­V(´‡7 5ì„cpo¹á¸Á°m/@ ŸCSX íàup &Ú=UwÙà¡ô„Ûm-‚8 I´†oá"|g¡9h`&xÃxha¸íÜáð)œ‡¡x7ÃÿÁ8 ¹,ƒ@øü`™]Fª»aœƒ"`\á$DASx‰H´Ft4t|8ïáÛ·Ð hØûèäää5kÖìÝ»·¸åÏ?ÿܰaCFe•ÚoN_~IÿþôïÏ\ý`“‰gžá÷ßk~XµëôiNœ•Eo …… ÀÂ…¤¤ÔõP¡Ôjìã,9Ñ 5„jéŽ]T^LP%¤*Só.å™6+ƒ””É?ã–ÒÏÅíð2˜mOó-í¡j÷VcËè9€vyÂý¶KYZÚÂr[‹åšw¥÷'Éäšs5£4ªgUÖÊÇãÚ]ЖÚ]ª¸x tK+xÍîHK£ø¡R}Ìá¦ð&¦&aư(9j f`3u³¼o©Xnnî©S§”Ê’t‰‰‰ÿýw‡|*Ëut1‚.]XµŠøøRíÙÙôïÏ?Ò¤t oï«g\ª÷ÝGt4÷ÜS —:q‚GeïÞ’´BCåèÈk¯ñØc|ü1ÿû_]Fª[mOÄIH-Õ-»7N6&'“ÓõéÙr¶-Av6'OâäÄÉ“4ib­zœ:Å¡C¸¸0x0îpâÉÉ8;³cþþ´j…$QPÀÎääM”m_ãùó8€,NçÎ'=šgžaýzæÍ«¦_¡¾R(ˆŽ¦C+Û+7³ºy*ì"¹„«ÃÃÕáfÌæ›a>pú÷Ó Å-0­Ö HH·ÂTh999@q^§bÆÊª­×':>JQZ-iitéÂúõ¬[Ç«¯ÈsÏ‘“ÃìÙ|öY AM&¶oçÀ23ùúkÜÜxàüüHOçÃ9p€W_eܸ’Žîº Z¶¤°”æÌ¡š5#8˜dëVà?øæë)ýŬY\¸PÁ°fìXúô¡}{íÛéÜ™ýû6Œ38{–%K8xóçùäŽ'9™ÔTºu#*ŠÜ\FŒ 0-xê)V¯¦W/ΞeÄÆG©dçNÚµ«87¾JÅÃóê«Lš„GµT9ê7•J¬Ê¦:^¢x³„ e_h(4}ûöíСƒ£cÉLðàÁƒ{÷îíævsä0›™=›Œ þü“'ž`ÄkcñÏ`Y®øç±JÅC‘MŸ>¼þ:ÁÁXR„…ñÉ'L›Vö,Y桇˜=ÛúvÍ Ö­C©$7—>`æL^yYæ³Ï8ØX:t¨tÌj5ëÖáêÊÅ‹Ö`tÅ ¦LaÅ ŠŠ cÛ6F¦[7æÏ':Ú:—)I|ó *_~‰“Í›óæ›tëÆ‘#øùñÈ#øù!ËUåÆ¿óN–-㇘1ã:¾dá&Õ²%|@J 7ge_A¨”ˆ±¡AQ«Õ>>>®®%YÊ\]]}}}íÃÓú#%…¾}‰Šbذ’FIÂ9—›Þ½ I²þ§P`ŸÌªÂÄV €Baý/>žP*éÖ„ºt¡¨ˆ¸8,àË/9tˆÁƒ+íÚÛËʈˆ´Z€³g­×5Z·æòeëØìÇ ÄÅqì˜õý /pþ>|ôF#UVCÕ£Ôv…-|})²Ѹr''T*¢£yûmmÛÈÍeþü«_³8ðuu¥ Àú:'‡r‹x­<<ˆ‰áí·­'*¨Õ89±};))lØÀþÃС„…U|:p×]¼õÛ¶1~üÕ‡'ÜÔ6o¦kW¾ÿ¾¦þDB]3£‚ÐpÆ'Nœ>}Ú¾}zzúÉ“'³²²êp`•Q©hÑ‚¨¨’}BŠŠâàAÒÓùö[._.i÷õeï^Nœ -ÍÚ¢P Ëüø# hµ˜Í¤¦’@A©©\¸P –ѳ'‡óË/üó?üÀðá(•ôèÁêÕL™‚$qá;^Ç­ ʇ’”Ä–-üó½lɉ]]Ù½»dÌ11lÙÂîÝ <ÈöíGް};..ô쉃ÃUJØ{z2mï½Gae%ß„†">ž&MP«+žì„›—F¡á(**úí·ß¶lÙR`s:thíÚµ u8°k¤P…¯/´h£#ÑÑ&àèHß¾ìÛÇÀ/4‰ž=yè!Þ|ÓÚâêÊsϱa³fqø0&+W2{6ÙÙ|ñ³gkí¨}{ìW.´iòe<òãÇ3t¨5õÒˆôëG÷îL™Â]w•šIµçéY²œ´qc‚ƒ.¤W/† ãÿþU«J¦6x…‚ùóyûmd™.]xã –.¥Kž{ÎdñòËtïÎ}÷±|¹õ‚U˜;—S§Ø½û:¾jáfd6‹9Q¡a¿¯¡áÐétz½^©T*ì&ÓÌ7É\K2EK@6r$ ëÖ4nÌ?`2¡R!Ë'QuqaéRL¦’‰"…‚ñã;³¥Iâ™gJm]²œëäÄ_”ú¹®Trï½Üsõç½åûëÚ•Ÿ~B¥âÚÅÜ©ß|cÃÌ™%c{ûmŒF$©TʧŸ"ËÖµ­Àw2~¼u£’eH]º°}»õ•êêÓ`ñŸÿ°cŠ`¥a2xå¾ý–ÿû¿ºŠ Ôñ÷– 4ƒÁ`0¸¸¸ÔÏíJ×Â.[?Ø­U*­•yfm ת¸H™ –¿²ý¥ÊÌ}_¼êåöc°?R¡¨x-¬eËTƒ©ð¦ªvÿýȲˆD2__V¬`øð«)7ñW— 4îîîÆ 3›ÍvAPHHˆ,Ëþþþu80¡¦•p…†D­fîܺ„ ÔŒ BáÑh:”K†^'ãA„«ºñ`ôìÙ³·Ýv›$6õ ËÅ‹ëz‚ ‚p ¹ñ`433s»% ‰PcœœœZ·nݼys•J•’’räÈ‘´â6‚PNQQ‘ÑhtqqiHÿJ,*"%@©¤I“ºÍÕ$%Ѩ‘X»)‚pnä¯Ì6mÚ|ûí·²,Wûh{—/_¾té’Z­¶-Z´èÞ½»F£‰ŒŒTˆÕa5,¬Š$ãõØ®]»bccGŒÑÑ.%æÎ;÷îÝÛ»wï¾}ûÖáØnØ©S,\ˆVKv6gÎÔ`G&“5Ãhe ê«–”dM;µaW÷àA® F}||ÆŒSíCì]ºtiÍš5¥÷âªT*Y–5jÔ«8ƒ¶ Ø)((0 NNNö&“I¯×›ª¨)Y¿µkÇöíüþ;³fÕlG:Ó§sâÄ £üAP[¶PúëA®Bù„ƒÑéxê)<<˜9“NeV®dëV$‰ÎyöÙªFn0Ф NN¢:Ž ÂõO{ë£ÔÔÔ .Tö©V«=~üx-G¸9˜Íæ&Mš„‡‡»”žÙóöönܸ±»»{] ìºìÙÃŒŒÍÿ˺u|ùeŇåå1u*/¼€›÷ßÉÄ–-H~~üô11¼ù&²ÌË/óùçüç?̘Á½÷’˜ˆÁÀgŸqàÏ>‹‹ K– I´mË€(ôëÇÀ4j°};ï¾Ë’%<ûìU –BIi{AẈ`´>ÊÌÌ4U ¶1 åI’4pàÀÉ“'{yyÙ·wèÐaÖ¬YіšõŒNÇìÞm­Ò ¬[G›6„†ôèÁO?U|â_qâ#FPP@¯^üý7mÛÒª3`§OSXȺuÜv’„‡MšXkfªÕ<ðÑÑÜv'N Itíʘ1( DLŒu§”Á€VK|óh}Ö¢Û¶±i'OÒ­ÅI̼½ùñGvíÂ’¢ÊÙ™U«øáŽÇË‹ùóQ*¹çBC1‰ˆÀÅ…—^˜8‘vˆÉ“ñ÷G’xòIš5h׎ÿþ×Ú…ZÍš5üú+Z­uv³[7._æï¿ b÷n4šªF®TrùrÍ|)‚  šFë)F³gÏžC‡ét:@¡P4kÖlÈ!þþþu=:¡>ÊÈÈ|||êz ÿŠ$Ñ´)÷ß_A{h¨uc“…‹ S§–:fôhë Ëf­{îP*éÕ‹2™y§O·¾hÞ¼Ô6ùfÏ.yÛ¬‹_ëÈ{ödÉ:t`Ó&Ä:A„k'‚ÑúËÙÙyàÀÑÑÑß|óMfffLLLDDD½Ý‰"Ô¹¢¢"¥Ry³£7¯Æ`°.oA®‘ˆlê5…Báæææèè¨P(ÜÝÝE$*TaðàÁ}úô)Sµ ˆŒŒ ÐTýŒY¨®®u=A„›n¡P©TþsE£ÑˆHTA¨·DÒ{AA¡Îˆ`T‚ÔÔÔmÛ¶:uªüGZ­öôéÓW®\©ýQÕ­–?.yû×_lÙrƒ—2›ùãÞßšT_A¨"„† !!aïÞ½çÏŸ/ÿQJJÊÚµkc‹ n68¹¹<þxÉÛC‡X¿¾Ô{÷òâ‹×t©ƒ™4‰„‘1T¡öˆ5£‚Ф§§ž–b—å˜L&£ÑX»#ªf²LZ’„}f³Œ òò(SwÆ ¦M+Õréû÷_S/GŽÐ±#/¼ ª( ‚ ÔŒ BC••x{{Wv@nnnµt¤V«óòò|}}³Ù|øðáøøø‚‚‚£Cƒg IDATüüÌAƒ| £Zz)ãÜ9æÍC«¥¨ˆAƒX¶ “‰•+Y¹’à`t:ëayyÜy'gÏÒ³'Ÿ}PPÀ„ œ:Ef&;âæÆ®]Uu$ËŠHT¡V‰`T‚aÆEGG—ÿÈÛÛ{ذaå+3UA«ÕF­Vëîîn póòòöîÝ;sæLµZ½cÇŽ°°0@’¤„„„“'O*•l0hj"Õéxâ Z´àå—IKcÊÄLJ+xçúöåõ×yçWW¾ù†7ߤxI‚FÚ5¬_Ï7ßðõ×W‰2ÍfÒÒùÓAj™ø{WŸÊÒÝ{xxôèѣ²²²rrròóó [¶léáádffnÞ¼Ùl6˲ܽ{÷Áƒ’$iµZF£ÓéÔjµN§sttºtééááQTô…RY#Õ0óóùóOZ·æ™ge239yOO †G©dÜ8k0*I¸»ãäTr®¥E£A­¦’% V:cÇrø0«W×ÄM‚ •Á¨ 4|&“éìÙ³ééé999 …¢86=pà€,Ëf³ÙÇÇÇŒªÕjGGGgggWWW[5!FÓ¥K—;î¸ÃÃÃcáÂ…–Hhj+|™œ¬ÖéL51x³…‚èhkÝÎÎéÚ•cÇ$”J zæ2ÕjžzŠÿû?bc1¢.(‚ \#Œ ÂÍÍl6_¹r%//ÏÏÏÏËË+77wÿþý!!!C† dYþý÷ß“’’OOÏöíÛ[Îõññ quuuwwwµ•ruu}ú¸»»{xx¸¹¹YÒŽ¶oß¾]»vJ¥R²[M)I’££cñÜgsvæé§Y°€;P*ÑéøðCÂÙ>É“iÑ‚ädë‘[·òÌ3\¾L~>={2i>н;f3;ãïÏÖ­Uõ¥TRPPãw$‚ ØÁ¨ \+“É$I’BQƒÙyM&SZZZ~~~AAZ­ŽŠŠ²„‰ß}÷]||¼Édrttœ9s¦ey¨^¯¿té’%”4™L–¼NîîîÆ sppððð°´(•J½^ïçç7hÐ K/EEE–Ê*¦ ë“Nؾ¤$ôz‚ƒqwG©ä¹ç˜=›ìl""Ðëúõ+•aÔÅÅú"(ˆ­[Ñj¯Þ‘¿?G²omÚàæVw"‚ ”#‚QA¸&iii?ýôS=Z´hQ-ÌËË‹ÏÍÍÍÍÍmÙ²eË–-üüüuëÖåää˜L¦&Mš4oÞÜ2Céèèèàà Ñh\]]‹g1#""æÏŸïêêºfÍš¤¤$Kº%ggçâ§ðJ¥²FèZ I¸¹YªÑÁˆˆR-NNT|WWl˪2h¿ÿΛoòÔSDEÝèpA„ë!‚QA¸ ƒÁpàÀ½{÷jµÚV­Z]Ë)²,9;;[Ç'Nœ;w.777??üøñ–¨1%%åÇ´ä¢wtt´£NNN–¥ŸnnnÅqç°aìP(ì×q:99Ȳܵk×ÔÔÔÊ’ŒªTªFU‘‚T(æîÎòå eé ‚ 5G£‚P•‹/þöÛo ²,v+ M&SAAA~~¾J¥ò·ÕÚ°aCJJJ^^ž§§ç”)SœK—.WãÌÎζ£ÑÑÑÆÝݽQ£F–Oo¿ývI’ʬã´,­B¡h×®]·àãã3uêTIdr¿6 õf¹¬ Â-A£‚P±¢¢¢½{÷2yî9¦OŸJO/*b̶m«žÁ$'3y²µÒýW_U•ßô­_ÏŠ11<ôÐ_'#ƒÇãå—±”ëÚ¶Ÿ~béÒ’• :ùùx{_¥têµøî;Þx`üx-ú·W¡»ñÇôÁÁÁsçνYRÃ4}ªøA*TŸýû÷oÚ´Éh4Nœ8ñøñãñññZ»œ@………–ùiI’,ëAë\jjªV«u)ÎcTNQQÑÉ“'==={÷îÝ€ƒQ''^z‰ìl¼¼RIAAWÙMo2±gOµ ÆÏ/¿$1‘éÓ)÷/š1t(]»òÙgÄÇÿ«ëèõüù§5àîN“&¥âÎC‡xç>üæ_u F·n|ögÏþÛK ‚аÝx0øè£ŠµhBóÎ;ïlܸQ’¤ÈÈÈ-ZäççŸ9sæÄ‰‰‰‰F£±   ^-P1™LYYYJ¥Ò³êÊë·IÂßßZ†Þ^N{÷JPµÅwº¹qø0..Œ‡ý?+ÌföïG©¤Â‰f³™Ý»é܆ôtާ_?€ôtΞE£aß>Ü݉‰¡qã’˜ïªöïçÄ  úô±V==|˜?ÿD£aÈüý­©©<=K2üWáìYk`=`–r­yyüò ©©4n\ïÚ…VKŸ>%·¿ÿξ}Ädzmîîô쉓S×ÏËãøq¢£qtäüyt:kÖ-Ë-$&rþ<ôéscáVvsg„¥T*=<<:wîò/½Db"Ï?OzºõÈß~ã7X²¤$hÞ±ƒ}ûHI᧟ؾÊ~§_¼Èã“•°ilmÿè#&MâÕWÙ³‡¯¾ªôtA„2ÄnzA¸:µZíïïïïïߣGzõ¤ÛÁÁaذaF£±ŠQùùùÝwß} …¢þTø¬M!!¬\ÉÔ©oÿ3›1™xäÈHV®´¶Ë2Ë–ñÙg¬]KÛ¶•^P§³N.ÊrI'Ë\¹Âöí4kFAAÅŠÊÏgéR>ý”áÑet:€wÞaÔ(–/G§£U+víb̘k½à«¯2~aðeXXØO?ýtïÞ½²Xšˆ*?ÿŒ‡Ó§SüwÓ¸Cç4"¬W{¤Ra3=kkòª+ÄÆ>‚Ÿ°²âÝw9p€8uŠ‘#±¶F¯ÃññÉZ<Èwhk[°LV0ŸLDDD¤¢1*Rz½þرcÁÁÁO>TBB—_~¹nÝ: --­Q£F!!!@HHÈéÂ2™£¢¢:TÔh±±±‹-:jtÕTNœ8ñÕW_………Ó&77÷öíÛ·oß® rlJ%NNìÝËÅ‹$%a0pë/’’­[\¸ Ø‘…"•âëËš5üü³)ò¿xyñÝw„†²aC ‹±µ%9™~àÂ…"sêÝÜhßžùó åÒ%Œß÷®]Ùµ‹+Wع“{÷hÛÖÔøÏ?9y’[·Špð`¾ü’ÈHøá¢¢¨_kk6l 4”õëIIHIáâEÂÃIOçòeÂÃ…îj5üú+W®i¶Z[ÏÙ³\¸ÀÁƒ%Ü??._æ—_ )¡¥ˆˆHE4FEJ@«Õ~üñÇÇò¡7nܱcG£Idff¶xñb777àäÉ“_öð¿~ýúûï¿_Ôh­[·ö÷÷¯R¹íOtttXXXñ7!--íÀßÿýõLŸV”J, %…•+ A¯gÿ~V­B¡àôi>ø€ÿE&£m[Á‡çìL›62:øúòé§?N¡ª¾R)óæñûïL˜€¯¯ÉL´·'(¨`cÖ®åÀ–//èF}xÀ±´dâDfÎ$>`ôh^x·ßæóÏùøc!WèÒ…>}øüsöî-Òw;y2]º0w.'rò$r9––¬YÃÅ‹¼ù&2]º RÁêÕ\¼ˆ½=}d²)›7gÌvìàÓO³õ¿xx0a̲eôê…ŸŸpÞß_Tx˜6m1‚Í›ùöÛÂGcFk(ááá[¶lquuÕëõgÏžmÙ²åøñã¥RinnîÎ;ùå ‹¡C‡>óÌ3‡ Öëõ±±±ƒ òññ9tèÐ$I¿~ýºwï^`䈈ˆuëÖEEE5nÜxÔ¨Q¶¶¶z½þûï¿ÿî»ïììì,--ƒÁ°ÿþëׯ7mÚ4**êÀwîÜ™7o^Ó¦MŒ€[·nmß¾ýÞ½{óæÍóôô5jTXXØgŸ}ëêêúÚk¯Tô]«bäää$%%)•ÊâCB ƒV«•H$ÿÕð* dò³Q(ɘ4Éd·I$ÂÉu먠 š703c×.¡MïÞtëFQ¸mÛòý÷èõXX˜LÌÆ (D(~Àúö%7· àÔÃxx°f F5[£(‚…+W’šŠL†……iX†Ù³‡eQQÌšEFz=Ь];š7''½¥6n4¹WóÔ &Oæ­·Ðë)*áM"á­·xõU ”JÓ £GrÌ̘2¥Œcjƒ®ØŸ¬ŠxÅ)  \@¢1ZC±±±ÉÎΞ5kÖüùó»uë6oÞ¼-Z´nÝzýúõ;wî\·n]XXؘ1cvìØQ¯^={{{ŸvíÚ988œ8qböìÙ6lÐétãÆ³±±icô,––öꫯöéÓg̘1‹-Z¸pá‡~xêÔ©·ß~{Ë–-jµzäÈ‘Fõ~??¿¥K—>÷Üs5òóóËÍÍmß¾½[ž$ØÚÚ6jÔèÊ•+íÛ··±±IMMíß¿ÿøñã'L˜0o޼ݻw/X° n\U";;ÛXŒ´ ¦UU.‰)βP›2ÏÌ’ÉLvX^‰•Šuë8sÆÔE&cËás^P^_©´Hã5oŠ™3‰Š2 bÜ8¤R¹œ/2EIÇ–(î,“’¥dnž/©èá[T̳fñpT¶Ÿ#J…TеuÁ^ÅÜ¢ õc P¸Õ CæP„ïZD¤|ÈÊB¥r-‘Ec´†bkkëãããïï?qâÄœœœ­[·îÙ³gôèÑ5 ؽ{÷Ž;-Zäàààïïß¡CN·}ûv__ßôôtƒÁàéé¹wïÞ€€€sçεjÕŠ‰‰¹víÚìÙ³ÃÃÃ[´h±`Á‚•+WîÙ³ç¹çž{þùç C¯^½’’’$Iƒ ŒEƒìííýýý^xá…‡Whgghaaa<äÈ‘¤¤¤#FÈåò¥K—Þ$!ǧ ‹ÁƒkµÚbÊ/jµú™gž1~¨¨¥= øûç³®¤OÓÔ¢II¦ÃºuË äfyÓ¼¹ ÂoÄÅ¥ îƒH)17o Ó™çädaÊWùoÈÓ…^OV–ÂÖ¶aÉMѭј››Ëd2‰D"•Ju:]nnnrr²³³3 “É,--cógùêtºøøx½^éÒ%à™gžñññILLÜ»w/СC¹\®V«ÿþûo@¯×O:5==ýÁƒuëÖ$‰³³sÒÃäRçàà`,?ëáááááñÄW_í)eIRµZݺuë XÏÓ„DBÇŽtìX–cX–£U ÕqÍO R©ÚÌ,03óœèW© èõde©ÔêÆå1¸hŒŠ˜P«ÕîîîW¯^íÑ£Gvvö½{÷:wî,‘HŒ»À ‘‘‘õêÕ‹Ÿ1c†Á`ؼy³R©¬]»öúõë#\¾|Y¯×¿öÚkÎÎÎwïÞ]¶l™µµu@@À™3g½^õêÕB¥×333 éS§Úµkæêêú°™uúôézõê…‡‡§¦¦ZYY8qâÂ… S§N­»""""R H$ +«¢£ÏYYU'ºÈSO|< …¿JåYƒ‹Æh %""âСCûöíBCC:Ô¾}ûwÞygòäÉÙÙÙqqq)))C‡U(‡¾p႟Ÿß¸qã 4cÆ ›ãÇoÚ´éáa4h0pàÀ×^{­W¯^‡8p 0bĈ¯¾újæÌ™*•êêÕ«R©ôÔ©SÑÑÑÑÑÑ;wîlÚ´iýúõ—-[¶jÕªß~ûíÙgŸ}þùç,X0räH77·;wî|òÉ'û÷ï?zôhŸ>}^yå•îÝ»ïܹsÅŠ§Nºxñb\\\Ó¦M›5kV9÷±R9þ|FFF`` íÕÂ`0m}µZ-­1›¬±±äæ JïØÚ…Y(YYܸ RÑ A¹,ò Òž|}Miÿ1Ðj…Lc±‘ Aêì<9!áÛØØñ¶‹T.DGk¼½W—“ Se£¹¹÷³³oggß2ô%·)Srs °0 ÝŸ‰dáÂg¤R©N÷c@€ÝÆýoÞ¼Ù zâÄÉOqq¼òн¿¿½D¢kÕÊR£ùcëÖ!×®]“J¼ôRsó“y¥®ÌšÕøòeÒÒþœ:µ~@qqÛÌÌ ;wŽ677ïÞ½WDD„JuÜÁ!mñâ¶IvZÚ·ÞÞÊ?ìššzmٲ綯YÓ£^½„¸¸mNN†µk_JN¾ðÁ’’vΛtáÂ…ÌÌsK–´­W/4<<üw™ìh\Ü?…^¦\n£P¸š™ùÈdO[ "ƒÁpíÚµÈÈH//¯âÑÌÌÌÝ»wçææ4Èú¿Y'O){öpïK–èt,\Hÿþ¼øâ#ŒÏÒ¥¤§ÇŸ–ÙÂÎÃΟ2ꫯø÷_ΟgçÎB„¥ pú4VVÅ•9-žI“8žqã1â1Gy  §Úµ×„‡÷±°È*ï÷ ‘¢ÈÍåöm©½ýDK˶%·~,*ÁÕë3bc?OHø677B¡H“ËSe²¡8S¥JiÕÊt˜™’‚Ï<#&' Œò7ZíæädÔjSß¼“çFÊ+´hmmêâä`g‡§'@vöÖìlê×7 ذ¡iä< CãaÞ£49;»–èõÙÙrÎJ¥ªïèøšÝ ‰DVxÓêFFFFZZš¹¹¹yI…³³³½¾½õee‘™)|–ɘ2—GÁÍ­[ù÷_† )Ë…}ù%Íš•1:w.:/¼PB½(#ëÖáëû˜Æh|<'NðÅ´hñ8ÝEž+«œœæ„„,vqÉrrÈD*š”"#¥Je7·wË/m®¢ÑŒŒKwîüO§;æâ’«Ñ¢'b4ŒH9¡×Ëuº$­6)--ò޽ߒ’yx,V©jWöºÊ€ŒŒŒììlµZ]h îà ƒÁ ©?³Ü\6mâàAÌÍ1„·ˆ,@&ã­·„!àöm–,áöm”J&O¦S'îÝcùr$‚ƒñòâ½÷psÃܼ þ‘ÁÀÞ½ìÜIj*nnÌš…Ÿß~ËÝ»L™"L·lŸ|Rˆ˜Ñ¹slØÀ¹süý7gÏÒªcÇ"•râëד˜È³Ï2m ãÆ‘Mf&®®„†²d ²p!R)ü™ãÆÑ±£ PUÀ:‰ŒdÅ BCQ«2„~ý¸qƒ5køóOþù‡ðp˜<…‚'øòKbbhÕŠéÓ ‘jÊC«ÅÒw÷"•GEʉDîê:Ãܼé;襤üã舙™ ®%"R~de‘“CR‰‰NÎγœFI¥å7]…£‰‰û"#ÇÙÛǸ¸ø€Y³˜9“¯¿.|–°0Þx//vîdìXNœÀñc=KK¶nåÎÂ7==<˜˜êÕ£G\\HøçFŒ`Ñ"š4aÆ ¾úŠ7ßdÇÖ®eéRœ©U‹Ý»iØ~@£aåJNžæ­U«YhÖŒñ㉊bÜ8ê×ÇÕ•‰ˆÀÕ•Áƒqp@&ãÆ Þz‹iÓhÙ’… Y¿ž3Šô ää”Êù*RNH$ ›MóèèU11ç´Ú0­ö®™YfÉ=EDƒ­ƒÁZ¡ðS©øøL17,o)±Š3 sr"##§zxÄØÙ‰®P‘J@¥¢n]¢¢Boßžèë{°ºG‘Êåò‡kƒ……EŸ>} ƒü©~4øþ{ºt¡{w “&‘•;›ôê-³²¸wà`üüL;æÖÖüï¨TÌœIÏžètü×z—H6ŒøóOâãUü  œùî;†eÛ6ÁÃú_\]queï^4 kWáäþý¸¸à⃴lÉáÃŒ Эß|C«Vþ˜å˹}›Ù³yóMGGÁKjgGN‰‰88웕EïÞøúòÌ3H$äæH¥¼þ:_~‰›99ü§DnqÜ»GzºP‰T¯§ñÿKøåUfâ℺£Æ·¹kk!·ý¿¬^Íwß1dJ%J¥©`iîÞ%9™½{…y›6¥¨Ê“QQDE!‘bš‹T<2™…Lf¡P”êETD¤ºPA¨ääcûýý ¢%*R¹ÈdÔ®m Ymg7X­®_r‡*Innnpp°•••››[M04KƒL†—W®hµ\¹‚½}‘==ùðCRRøòK¾þZ0FïÞ%.""°´º+•¤¥™¼¤FêÉ“˜™qø°iÀaÃX¼˜¥K2„ <\¨ÝߟðpÖ­vösr ÙâÏ3oÜ }{22ˆ‰T«µšÄDSãcǘ<™¡CIIá“OLç•JN`óñ¡^=Ö¬V[¨ØHŸ>2h‰‰k–Šˆˆˆ” ôKJúÑÆ&K,#!R°°@­NËȸP}Ѥ¤¤#GŽXXX¼úê«%•§§§ÿñÇ …âÙgŸUS>¼ú3|8]»2o ?þÈðáèõìÛÇܸÁÞ½Ó§>>Ì™ƒÁ@` ?þÈ³Ï Ýssyýuzô`ýzÆŒöpÜݱ¶fìXêÕcÖ,Üݱ³céRذÁ4µ‹ =zðí·¬YSÂ"6dýz’“  OdÓ&&O¦eK.\ÀÝwß-²ïªUääpî66´o/œìÚ•ùó¹p~ýhØ–-Ù²…ÌLâÁSß  Á6õócà@úõcûv¦L¡U+®\Á×—ñ㋜×¹¼HשˆˆˆÈRAÆhFÆUQ³W¤ê ÑšzÎÞþ•jZß9111##ÃÉÉ©4å@³³³¯]»fnnÞºuë§Ûõña÷nF¥bÓ&a“]£ÁÖ–±c!›M*¥gONžäÆ Þxƒž=…î^^ Î¥KLŸNß¾ÂI•ŠÃ‡ùãa[ÜÌŒC‡øî;RRX¿ž«WM³7i½{&‘²¢5Šºu‰ˆÀ(ÉåêÊ¡CìßÏ­[4nL·n+W¢VóÖ[øù‘žŽà¶œ6ØXY¸íH$´lIË–ùNÁÙ¶-mÿ#Þ,—3`<_«/¿l:¬_ßdq¶k˜È_±e sæ”üÉÜÜdþqwg„|gÆŒèÑC8lôÿÚM›æ“ΰS':u-,xýõBæU«éÜ™Îó]—ÑF/[[ºveÂ^]i)C*ÂÕj”J”Jë"¼P9‘wpà—.±|y‘£%&2e áá´iÂ5Q÷.'‡ë×˲ ÁÀ7ß°f ööÌ›WðY^Vde1|811,XÀóÏ—Ë…a€BJ@ªÕ:½>´P-¿@ÞÞÞ‰¤víÒ ¦ÄÖ’°¶¼’At4;v0l˜É]¾œ#GòµùùçÂõžJOçÎØÙ=ÑTÊ’%ÄÅQRHˆˆˆˆÈãP1Ûô½>RJÓ4-­È,Q#gÎÁÆ8:"+]HLdÆ >úˆ€€²0-™4‰NÊQ½åß9s†S§*¸¶uᥙd2´Ú´êk¢¹¹¹•R× ppp3fŒT*-Q¿&ãéÉʕٷAƒ|ÒQÀèÑë6=yš™±´ieaffªÓ&"""R¶TBîÉ“|ÿ=))x{3|¸ ÅòóÏ8 „sEZ[¶ðûï$%±w/uê0`r9þÉÎdfÒ±#}úî‡#GË9ž°0Z·&(ˆ£G‰ˆ NîßÇÑ‘ñãa³ø«¯P«ùýw”JÞx__23Ù·Ó§ÑëiÕŠ—_F&c÷nnÝB¯ÇÑ‘ˆ&NÄË‹ädvîäòe\\xýõÂuª³g çÖ-¢¢èÙSØÈKJbÓ&‚ƒ©U‹Ñ£quå×_9~œðp¾üGG:t (­–'8tˆÜ\ú÷4¿ã¡Cüõ‘‘œ=˽{ôí‹·7IIlÞ̸¹1z´ðŠŠb÷n||øñG,-™8‘_åÞ=bciÔˆ¿þbÂS!Ðÿ‰ ¥ö剔r¹Ü¾˜Är‘rÀÞ¾¸\~‘ÇÅ“•“‘™yC««ìň< Èdæff~ff>Je-‰¤"2 *Á=too<<Ø¿ŸY³øâ .]bìXÆÃÜœ÷ß/r³L"ÁÌLÏ376èÃÂ9’—_¦Iþ÷?$a§lß>ާ[7|}…¢Ÿ~Ê«¯²d Ó¦±q#={âï_Ú5¯[‡¹9cDz?óçóõ×$&ráAA˜›óÉ'df2t(Ÿ|B÷îìÝK` 72w.Ó§óàÆqü83g²iSáÊ/dzf 3fàåÅÌ™øúâåżyüý7cưk&°c ffH¥¨T˜› î–~àÿcâDôzfÌ`óæGpš*•¦Õj£ËE‹8uŠiÓØµ‹7ÞÞ"#™>矧G‰Žæ³ÏhÛ–?þàß©S‡>âóÏ‹œH¯ÒmJ#III™™™¶¶¶f•{+""RA22.ß¹ó¿ìì¿åò$¹<ÍÌL)‘dWöªDžB 23‰Wétv‰››Û»vv}Ë[ú¾ŒÑwÞ᯿HMÅ×—-[HOgß>Z´àí·Q(¸r%ŸÞÃh4ŒR‰D¤IÂÉ?þÀ‚I“°±áÒ%öï§_?Á½Ú¦ «V ²Ïß}‡‡Ý»³gƒqð ·oiŒFGàí-d¼ãÇÓ¯NNÌ™Cz:..LšÄÕ«dgãëË•+ Š…J‡Èdüþ;¡¡üöK–àë‹¥%³g7oÛ¶LšDJ GއF￲|9=zàçGÿþ„…Ñ®>>>Ì!dg³y3Ï?ϳϢ×sü8ÇŽiŒæä `k+ø;;u¢E dà@!Z4)‰cǘ?Ÿ¾}iÚ”gžáæMa.ss>üPøœšŠBAß¾dgS§µkóÕW…Oª×sæ »v ÅEžsçÎ]¾|ù…^hÑ¢EiÚgeeEDD˜™™Õs¡‹F«Í dnŽ¥¥éÐWݶ­PbÔ``åJf̨èEŠÔLôú̘˜511+íìâj×F.G&“H$f £"å…V›­ÓE§¦Fß½ûZrò!w÷…J¥{ÉÝ—Š6FÓÒ9’œ5âÁrs1ˆŒÄÍMp›ùûóÏ?0`d$vv‚¯ÑÕ•k×ÈÊ,ÈfÍ„ R¹‰[[“eéìLFF#ž=BA”/¾0¥Í#ô,-Q©Ð뇥îîDE™¨ssd2AŠ%)‰ØX¶nE¥Â`Àݽ¸d[WW¡–ºÑß™‘V‹‹ €•Ri>ië<ÒÒ¸s‡ØXæÏHO/Òšââxë-€nݘ3§ð6¹¹¤¤Wdoi^336>/P*E&+!xW§cÏ~ÿÙ³‹k&Rôzýýû÷³²²ló¤}J"))é»ï¾suuÑb¸u‹îÝqtûôɧ÷©×³v-..&ctË–‚ÆhïÞ|÷¨ï!RÆ ¹ã22¶yyi­¬Ä/˜H!—#—£Raa‘~çÎæàà?ýü+•å9^ÑÆèܺÅÑ£¸¹qä§NxzŽV‹\Nxø£ èîNBYY¨TÄÄàà`Š-~*“•ögÚôt Sv‘NGžV¹9ÎÎté"ÈÁ@q»áÎÎBÀb6xe2Ôjbb’’HNÆæÿóÑ%’ÇùS¨P°z5Mš°e‹¨ 󤤥¥%%%™››—ÞÕëõÕ7U«ÂÈÉáþ}~ýU8Ìs‹&$ÅÃ7;=ÝTÀÓHJ YYú//öïgáÂâR J‰¥e¾ºBqr"$„C‡ˆŽfçNºt)¼™Íš±|9¯¿Nr2—/3kVi3Ö bÅ rrز…Fýj++ìíùøc^z‰† ñóãµ×xÿ}œœppàÌúô¡I“ÂÇ”ÉJNf·¶¦kW>ü•Š;ðõ-YÇ»DŒžé81àþ‰‘Éd™™™šR+{eggç<\€R¤$’‚¢î.0jnn¤¦rë–prï^vì $ÄtæóÏ9v ƒ#¦N-ò‚ˆÈ#‘•zïÞ¬ÚµEKT¤2‘ɨUËpóæÞøø^ööƒËcŠŠ6F=<øì3vïF§ãí·¹s33ZµbÍöïÇÌŒùó)ÞãoSØßŸM›Ø±ƒÐPæÎeà@á|çÎBž¾__^z FŽÄÆF( Xz^yEÍÙ™AƒP©èÚ•¨(öíÃÚšE‹ÐhP©<''ºu£vm¤RÌÍ13cõj¶mc×.ÌÌxî¹"]&AA¤¥(• €›J%‹³aÛ·ãëËonnÎpàgÏbg'„“ZXpð ™™4jôÈ ,*C†ñ€LÆìÙ¬[ÇÖ­8;³i“àjuueÜ8S/¹œ!Cps£cGìí±´4­){{23‹+-R4MÇŽu:]iäîØÙÙuéÒ¥4µšj8YY&yù·ßæµ×˜7Ö­Y¶Œ“HE¿~tê”OcÌ^}776oF")G}4‘…Á ‹ŽþÀÊêM!ZÉ""ŠJ…§gvdä;»þå‘__ L É£woz÷.U÷æÍóåÁH$<÷Ï=W°YžUj$0PH»™6 `øðGY1¦ú(¦š%cǬ_b܃Λژ^âì,LZ<; ÌÌLî..Ì›WHcÿ|YP /¾XBA¿bP« –¥vtdîÜ‚Íj×η¥Rè•çLjܸ¸Yê×G©¤[7æÍ+¤øÈ#QzK°¶¶nÓ¦Mù-æ©A¡`Ñ"ásƒèt\½*$G6kfŠ–¶°0EŸ±¶ Pgç2Ø™1b0äfdœ«UKŒ©XY÷³²n©Õ¥–"*5•`Œ–†U«„pR#vv¬Z…øvX­±µåèQâã…‘Ç@¯×§¤¤XXXÈŸ\B]ä?Èdù^‰srÐëMŽüÒØÿz½hŒŠ”:]jVÖ?Þ|DD* ‰•*+3ór 2FÌWCY.ËÐU{$ÜÝóɈ<*ÉÉÉ»ví²´´ìÛ·¯y©ŸQ:.++K.—‹˜ŠÇ` 6Vø¬RaaA£Füü3/¼@ddÉ* W¯Ò¬Yy/S¤¦‘qE©Ì-úÅ3_Vâ½{h4ÕÕeŽ“S¾×¤§Ô©S°ðuTju á|Õ½ž;wptÌ·Ù’•Ž{x{—Ð1"™¬BëÈH¥¨ÕºŒŒ¿Ë£.q}‹÷ô¤Q#Ó ”A1=‘êNbbb\\\NNŽòQÒ¢¢¢6nÜxêὑÿ —ce%Ä õîÍœ9ÈdÌŸÏ¡CtîÌ«¯boB^OçÎt튃;çKT?žñãéÜ™Ÿ®¼ËyŠÐé’‹þ¡ Ít``É“DµcêT._ÎwfËÞ{~ý8¾`ã•+Ù¿¿|×sòd‘ 9eKF3fpýz¾“aaŒU\/½žÕ«:´HmïòC¥B§+Ui÷GE4ñDDª ÷ïß×jµ®®®´M¯ÕjÓ~‘"ðöæôiÓ¡1Ý«U+&>KK”Jìí‘JY¿¾ð.$* '§ŠX°ÈS¤„XQ“ ´Á è‹US’’( ø1s&Z-½{< VîàY³øàžy¦|g ’’ÐjóÔjK0…³²8~œ)Sxé¥r]]Q”KsU7F32øçrsiÑ¢B‹Iž?«k!{Êii\ºDóæ3ŒDFrçÏ>û83FE‚»;õê=Nw‘š€B¡ðððð|Ĩ[NWNëyšP* ßóð((OQÔö™RYPJD¤¬ÈÍeñb®_G­¦V-fÎÄÚš¤$ÞŸS§ðô$*ªÈ¾11Ìžwî`aÁ¢E‚8ÌgŸ‘“Ch(÷ïÓ¨ï½ÇÝ»,X@r2 3gÒ @|ÂÛ`—îðpæÏ'-Ñ£©[W8©ÕòÃìÙƒ^—³f®Ìxð ?ý$¬éÞ©SQ©ˆŠâà G£aâDZ´`ëV¾ÿžà`fÏÆÞžAƒxùe²³Ù»—ÇÑjyî9FŽª‘§¤pê­Záà`š(8˜ˆž}Vˆ-Œ‰aÅ îÝC¡ (ˆQ£P« eÙ2nÞ¤ARRôzŽaíZ22hÚ´„k0 ‘àäôTéWÑmú<>ü 8tȤñ^J.^ä“O y©*%ŸÎ_r>:šwßåÁƒÂ{;VdY£‰Šâ³Ï6Ì$^("R€–-[6Ì××÷‘z †ZµjÙ•G˜ˆˆH… ×“›Ë¬Y̘ÁåË|ñkÖðë¯|ú)/¾È™3EöMOgˤRþ÷?²³;cŒ‹Y²OO†ÇÉ ƒÉ“IKã½÷P*yûmá±;cgÎðöÛLœøhÂ| ìØ^ϬYhµ¼ó™™DDpé’Ðà·ßLâÓ—/³h¯¼ÂÔ©BÍêÿââÂôéèõ„…™N=Ê»ïÒ«3gR·.E½zߺÅ7ßо=³g³e ÁÁètÌ›Gp0ヒS¦O§NÌ™ƒ‡#F0gŽ Ôsð +VðÊ+ŒËW_qò¤0fD¯¾ÊÕ«ù&Ú¹“Q£ˆŽÓÒpueÖ,Þ|“íÛ9z”ÌLæÌ!-O>ÁÞ^¸Ø°0¦O§[7–.åÊ•nlv6))O[ìbU¿šÓ§yí5á-*„Š|o?ÉÉhµØÚšRYCCÙ·Q£ò‰’êt$%an^òûÄÂ…S¦ÒÓÉÊ*èN/%Z-Éɘ™ Ä~˜-ذ_$"¢„Èe‘šÌc$!y{{{zz>’”ˆˆH•B©¤~ú‰û÷ÉÌäÔ)&OæàAÞ|“¦MiÔˆU«ŠënT¶¶fútZ¶$#CxõèÁŒ‚tTv6?ÿÌ/¿Ð¸1o¿MË–$'£Rñí·üúk>EÅ¢øë/´Z”Jš4ÌV++fÌÀ÷ߦsg’“‹ìûê«´nM«V¬]ˉ‚S¶j5+#îÙCçÎ ˆTZ‚¼`«V €L†…·náæÆï¿³jÍ›£Ñðý÷ܹC“&¸»£ÑàëkòPnÛF` ÆZ¬^^;&$X»º2~ÁÍÌ.]pv6ùJkÕ¢I¾ûŽ„ÒÓù÷_5âÚ56l Y3ìì8xP¸u‰à7}ýu–-+ò*NŸfï^rsñò*îb«UÝ3š™™ÏšìÕ‹±cyå:wæÈ­–•+éуþýyýuââHLdØ0–.åêUz÷fð`¡²å™3ôêÅ+¯Ð«—éÍæ¿Ü¼I¿~ôëǘN~ÿ=Ý»3x0S§æ+j¿m+V™™oƒ“'éÓ‡'.\ _?† ¡woŽz-xm¯^¥_?îÝÉÐé Ž&"bD«Õêõú’Ûý©TªR©D5(‘êËùó Lz:­Záë+ˆNH0+)¾j`ž®:ññÂyOO“ˆi|œ÷ß')©ðIëÔaåJlmILÎܿϼyôëǦM4ož¯ãÑ£ìÜ)5Í[óþýLžÌ!´kGBӦѺ5›61z4K–ðàqú´ ³g üA13ÃÂ"Ÿ±+"’ÇÙ³g·lÙRÙ ©h.^¤iS–,aèPáŒTŠ»;7nhµ¦}áB‰‹#2 <µÚdÂ>Œ³3 w¢Ráá‹ &×Lññr›7³gë×›r*bcWË­[˜™acƒTJF:iiÂ’Œ„„`0•EX˜É¼³°ÈצP¼¼¸rEpîèt”þ…ÝÖkkBCÁcõ°Aÿð•z{óì³|ý5Û¶±s§©a\ë× w,sçØ´Éd'œ9ÃàÁÌ™CïÞ俢×caR)ôJI!5U˜"&F°Â ìû gOÖ¬A&þ×?5T]gÉÙ³¬YCJJÁ2ë/¿Œ§'Ï<Ãùóhµ\¾L­Z´nFC—.üñ‡ÅìêŠZ··ðZöÏ?Ü»Gj*ûö‘’Bh(ž‘gf†·w¾/eXÙÙôî§'ýúqèéŸÆ'%%ßæûß3no½%l„‡B۶¼11Ü»Gƒ°?9¬YÂŽ†RÉ‹/²`7o2mZq{ú"5Û·oGFF>F6RXXØ… ¼½½›=í˜ J½z¼÷^¾—X‘êNƬXÁ'ŸÅ?r‡£F1w.J%ׯ æTQ(¼õ={²mo¼Qx6°L& ž= ŒFƒLÆôéÌžMd$©©¨TL™Rä,ÿ•7Æ¡öéÃ×_Ó·/¶¶øû³t)+V‘ϳóÕWÈdܾ™™©FcÇŽlÜȃôìI` ÇŽqý:ÁÁ¤§£ÕÒ¡1r$#G2c\»Æœ9ùÒ‰ŠÁÊŠAƒXµŠ˜~ü‘FLàÀ@æÎ¥K:u"(ˆ1c˜8‘÷ÞÃͳg™Íôé•%&RuÉÊÊÒh4666¥/¼TéSóG«härZ·¦aC1ðZäiC*¥GzôÈwR¥¢OŸ|gòíS+Bl¢LÆ€ ¯q÷îg±´ä•W žT* ™ºôË~é%^{ÍtF.§o߂͌±ÿB­¦kWºv5-ø¿k–Hð÷/ÎH0Ò¢-ZŸGŒ0_àžqtÌ·H©”À@ 6srâí· ž|æ™|¥j5C†lccSÈ}®]›‰‹¿33:t`Íþþ›Å‹KÕ¥êSuQ#2Åkuw耧'¯¿Ž³3W®°u«ðÒа!99 ˆ—‹S¯¯¼Âĉ´jEL ŽŽ¬ZU¸VèGqæ gÎɾ}LšDP={2iÍšqñb>m‹ŸæÚ5FΗž¯Ñ°`/¿ÌÊ•Ì˨Q̘AP‰‰H$lØ€µ5ÎÎtíÊúõùþ”èthµ¢OT¤lmm‡ ¢ÓéÌ=j]*•>F¯jMJ¹”©ÒèõL›–o¿>0åË17§C‡JX Ï?_¡á5©”I“<˜ª"T+ªºáãêJd$xz"•òÝw‚}«V¬Z…™æælÛÆùódf²p¡)æÃLJ={ˆªüI¥LŸÎ‹/‚FCÆEª;õê•OµÞÛ¹œE‹¸p¸8¦LA*|¥Àüùdd˜L_zIx%òòâÛoIKC&cÂ:u"4¥’€¡±D‚…-[š"bSS¹vœìíËòŠ<H¥ÒÇö‰úùù¹»»×{ÔߟᆪwoêÖ}ÚNEDŠA*eéÒ|B›Æ}B6n¬„õøû³aC%Ì[P* ã¨îTucôµ×øä’“Y¼ !ΰ²(ºu+¤¯§g>Í…"Ÿ§=3“»wóíh¸¹ai‰·w!2Ÿ íÛ2EÁ S¤HíÚ¦ó Ò°¡é0!íÛÙ¾yóLÂUW®°|9AA%o7ˆˆ<jµZý4Uê(‰¶mY´ˆwÞaõjSt—ˆHM ÏQ""R½¨êÆh×®´m‹ÁPö©å,\˜/¶lÆŒŠ¨E èõhµ,Y’/ü%(ˆíÛ…ìE‘‡III9~ü¸³³sóæÍâ¦WI:Äóϳv­IêODDDD¤*SÕQ(/…#__6lª¢yÜ]ÐGÆÁ¡u …BŒ­)œÄÄÄ¿ÿþ;>>þñ´™âããmmmíkFHT­[—VÞEDDDD¤Òyúl‹B&ÃÊJ¨KaüO´Eª&ÑÑѹ¹¹ÎÎÎʇˑ•šË—/oÛ¶íÚµke¾°*ˆÁ€VË£×L©4ªgTD¤†“––&—Ë]Ÿ,̲ørOiiÌ™Ã/¿¢ÿ""RC¸s++"#‘J©__СLK#* ÀÑQ_ þÉÜœÄD¼½…±¸8P«ñðxª’µEª8UÝ eÛ6d2¦N­®‰¾þš›70€¦M+{)"Õ“6mÚøûû?¡j½¬#Ëå´jEïÞ´iSÙK© ôz&N$'¹œ[·˜<™7ÞèÑkkÔjbcY³†À@†G£áöm¼½‰eút âèQæÏÇÅ…˜ÆŒaøpÑ© ªú6ýòå\¿N³fº‡þÇLŸþ˜}/]büø|g|}IKãwò•°)=ÆÃÃã±¥¼½½;tèð„ŽÕj™C‡Ò¡ƒ¨è$Rsyð€&Møæ¦M3):-[Æ–-¬^M`  ·Â8;Óº5C‡rä¼ù&£G³u+Ë–ñÞ{ddTâuˆÔ,ªºg4"‚ÁƒéÙS8´½¥ IDAT¼v þý•Š-03C¯çÖ-nߨ[//´ZBBÕkµšÄDZ¶D£A§ãŸˆ‰ÁÚšÆMšJ©© XZ"‘ Õró&ýÅÙ³\¸€\ŽŸffèt…•Mš Tr÷.ééøú"‘C\ÞÞ„…™ú*øù¡R„ZÍ[o‘ž.†²‰TuêÔ©S§Ne¯BDD¤"HèØ†Ö­Yº ;›ßgÎT*îß§aC!s×Ö//\]17';›k׈ŒäÒ%nÜHJâî]QM¤‚¨êƨV›Ï'úê«ØÛãíÍ™3ŒÉÔ©$$0{6R)ffܸÁêÕøú2duëò×_Ô¯O\“'3|8kÖ°s' ÌÀLš$D̼÷ðùçh4ddðÅ\¼HXË—ciÉÂ…¸¹ñÙgì܉Ÿ¡¡tïάYDF2m«VÀ›oÒ¬“&±y3çÏsçË—coϼy¸¸H¥¢`“Ècœ””äããSŠË‹ˆˆ<9ÆG[žÃåøq¾ü’¯¾Âɉ;ù矂-èõXXЬ™PpíZœ+lÉ"5ªkŒfgEll>aùÔTÆŒaÜ8¾ù†o¾aüx¬¬øè#rsÉÉaõjvíbδZ–/gÂúö%!7¸u‹ X»–çŸçüy¦McÈá—–MV–ð¦heÅÇóã¬]Ëîݤ·n±q#|@çÎ\¼Èĉ FPC†ðî»øú¢Õ2nÖÖ¬\ɉÌŸoêkD¡ ,µlYqR"Oƒáüùó!!!–––mŒ¦¥¥åääh4Uµõ̧¦ƒ³35 KD¤Œ‰‰¡vmš5#3“_~)Rßßkkúô!7—à`Se‘ò¦ê£'O2k* ä;ÿ H¥8;#•¢×“šÊ»ï…FCD„ÐX£ÁÌ • wwRR¸{—Û·yð€÷ßçÃÉÍ%:šädÁ]¸®812’»wùà>ý”Ü\RSIOG&ã78r„øá‡jxº»S«cÇ2k#F<ñ­©1¤¤¤ÄÆÆš››;?âôéÓׯ_ïÚµk@@@®­"ùóO–-Â;ÅX‘â°²\›266;óÙg¼ú*IIdg ©À66Èdh4¨T(•XX`mÍdzl;v–†FÃŽ<–šœˆÈ#SuÑ6mظ‘¹qƒ¶mMç <Šöí#6–/¾ÀÖ–¥K¹s'ß¿÷ rrP*qvföl“v^¥Pµ½¾`Π^^oÚìpqaæLÁx•Ëgmp0ÑÑXYqò$Í›·ÿ>wï²zµ˜ä+òh$''gffº¹¹Y="333%%E«Õ–áÂ*˜vípw§o_nÞ¤qãÊ^ˆHUE*åÓOqrpwç›oÜÜøábc‘Ëqp + ‰„íÛñð`æLÌÍ‘J B*¥‚‚HNÆ`ÀÕU´DE*ŽªkŒZXд)µjqëV>cô¿((•DFräE¹~üüÐh& €”îÝ3ÅÊcF7l0IG™›Åùó8:â/66ܼI` ))ܾM:ÄÇ3s&}ûÒ®'Ò¸1;(•ÄÅñçŸ89áî.¼feaaAPXŸPäÑpqq2dˆN§{ò* ÕZgT©ÄÕ{{rr*{)""U›ºu…J%>>Âg''ÁBÍÃøOîµðÁÃr_¤ˆHª®1jD*åa‡N@€àµ´¤n]¤RzõâØ1^ (!^©¤n]¬­qvÆË ggV¯fÙ2$;›fÍhÕJS.65òhÑ‚ŽY°[[–-ÃÃåËY¾œÃ‡ÉΦIÚ´á‡prbâD¬­™0;iÙ6¤S'æÏÇÕ•%K„&Nlyd”J¥×ÃAÓ…£££‡‡‡Z­.“%U"¹¹•½‘²¦ª£ÞÞ<ˆ /¾ˆJÅöíXX4oNƨT¸¹±e qq¨ÕX[£ÕbnÎÚµh4,Y‚JE«V‚9Û¶-»v\Ž‹‹É3:>z}¾˜QKKV­"5¦k׎¦MIH@¡ÀÉ ™Œ~ý8Pè5f C‡ ŽU++V¯&-ÍÔ÷÷ßÙ¶ ‹ê*Ú/RÝyöÙg[µjUÝEïÍÌðõeÅ FæÅ+{5"""""eGU7Fß{o¾!&Æ”ínäaw¦Fc²óòü¦ü¿-ÈCa¦·Ì£PQ*5m[±°0 ˜7…c™û‡û>|˜@­ZLœ(&^ˆ< ÞÞÞÖ¾‹Î“ïòW:R©SÙK)Sªº1Z«3fTö"žŒÞ½éÝ»²!R ¹téÒ•+WzõêÕ¼yóÊ^Kå“‘Áõë¼ÿ>íÚUöRDDDDDÊ”ª^TD¤f’™™yïÞ=¥Réž—bð¸œ:uêÀñññe²°ÊE¬ó)R3ÉÊ¢wo&M"2²Tí¿ù†ùä“r^–ˆH!£""U‘„„„´´4{{û'ߣ ¹téRš1¹z’“CTññb¬‹H E©dî\BCÙ¹³äÆz=3fУ}û–ÿÊDDÊ‚ª»MŸMF––SÝŸŽŒ 4!‡)7—ìì|ñ Oƺ …Xù©šaooß»woNW&Yð‰DRÕNždùr6+e‹ÔP¤R!m7,¬äÆQQ "î$ˆTª®gôäI bÜ8ÊÜ¡Á¤I$$‡§O3gN¾))„‡—ñ¤eˆVKh(YY¥j¹jðÅå¿,‘2ÅÌ̬~ýú 6|ò¡”J¥µµµYu~.ñùçlÞ,zFEj4¤B_ñ"5ŽªkŒ¶nÍŠüðƒÉj,+²² 1 Ö­KÏžùœ=Ë»ï–ñ¤eHB'–êý8%…ýûyã †-ÿe‰TUºwï>tèÐÇ.m_°´ÄËë©Ý¾)%\¼ÈõëÅ9#bbøöÛ*T‹ˆT5ªî6½¥%M›¢P¢NDv6‡ñë¯Èd LP ÿþËöíÜ¿³³IHÝ:¢£ñ÷32ظ‘3g¸p¹s17gÔ( Ÿ%,Œ_~ÁÁŸ~ÂÁ)S°´äçŸ9z½žAƒhÛ‰„ØX6o&$„ P«éÝ…‚ï¿gèPÔj~ÿŒ ºv%'‡_~á§ŸÈÍåå—i׉„ÄD¾úŠk×P(8Ž9r„£G¹y“O?ÅÁ.]Š+Oe¬hZ¯^‘— R5¹ÿ~|||­Zµž¤ hÕÚ É£IÂÙ8‘O>¡Ð]ƒ¯¾bÝ:¡" ˆHu¡êzFH¥ãݾE‹hÓÆ'<œ´4ÆŒ!"‚nÝ8{–ÄD¡¥‹ ìÚešÎÕGGÔj<=ñð }ư0Þy‡/¿¤At:Ù³‡ÿý¦M©_ŸéÓ¹y­–… 9tˆž=ùçæÍ#:šز…Œ €“'ùùg€ýû™=›¦MiØwÞ៾ü’_eà@Ú¶%.ÀÖÌÌpuÅÓ“âmެ,“¼¿HuáÒ¥K{öìùÇø%àäIZ´`×.“¥ ãÆ±oTìÊDDžŒªë5Ò¼9ŸΨQ4iRd&Sz:èõ89áìŒNÇgŸÑ½; ìÛÇÉ“øùË–-xyamÍôéBß¾}‘ÉØ´I843ê*ݺÅèÑ%/ÏÆ†Õ«ññÁ` '‡±céÒ…æÍÑëùþ{~û Nœà£èÔ‰Æ9w®ðq²³Ù¼™víhÖ ƒŸæ×_ àþ}”JllhÜgg€  j×fï^úô!0°¸µsð z=O, $R¡hµÚÛ·oK$77·'M§Ó…††æææÖ«W¯Z‡V Z-Çsÿ>]º¿8‘ªCx8µk—°Ó¥ÑHffE­ID¤,¨êÆhƒlߎ¥%õëiŒ^¿Îĉde1z4'’œLB¿ýÆßH¥h4$&"—cÌKvv.³ÔrwwjÕHÈÈ .Ž3gø÷_­©”´4rs1n“Z[SÔ~iz:”ÄíÛ‚;säH-â­·Þz‹1camÇŽñÍ7xx”à=©jÄÇǧ¤¤ØÚÚÚÚÚ>ùh999¿üòKjjêˆ#Dc´DÎcÔ(† +.úED¤²ÈÉ)m“TJl,NNå¼ ‘2¢ª£»w³f Ý»SŒ.MÆìØÁ€ñÙmmµ5ãÇ3d „œž;'ìY”üÖ˜•UªŸ½ZmÊX47ÇÆ†‘#1@¯¸{…‚¤$€ädSx€NGn® Àaf†Fƒƒ æf^˜¬¯/Û¶Ëþý¬[ÇÈ‘ÈåH$¦k)†ñãéܙ޽ ¥Aƒ‹T¬­­»uë–­)´Rm$.‰„äd²²ðòÞ*³³‰Œ$'kk<<0xð€ìlRSqrâÁ<<„²½))DG#‘àåU\à pó&-Z°dIE\”ˆHéÉÉañbŽaöì’K$4nÌÔ© @Ÿ>å¿8‘'¦ª£™™Ô¯_œ% ˜›ãím:”É3†?F&ÃÚš~`Ú4°³cÉú÷gÍA.êÎNœàâEîÜáë¯ñð CWW¢¢øøcjצkׂEê‹B¥bØ0Ö¬A¥ÂÚšcÇxå7¦];–,!3“~àþ}[[²³Ù¶ WW~þ™—^B¥bøp>þKKll8}šÁƒ àÿØ»ïøïþñ㯳³ÇÉI„$Æm×UóFkÖwµ”¢µŠ~[”jq¥ªTÝf'¥jµÔ¦¡µ7‘Ùë¬ß¹~ŽÄIbdû<}ô‘s庮ÏçœDÎû|ÆûýÙghµ €½=|õ/¿LýúÔ¬™o—´Z´Z²²ž¨ÿBaeeU§N¢½gyÏ3:>ÇcgGb"uë²d F#̱cØÙ‘œÌ˜1ôèÁôé\¿Nb"NN4hÀâÅ„‡3nF#éé4hÀüùÒ¿#‹ôz1˜$”E2UªðÅOTW.çûï9s'§âï™ …2Œ¦¦J“ÝO+g üÞ½ètÔ­‹‹ öö¬\ɺuüð/¿L§NØÙÉ… ¨Õ´oÏ…  Òåµkóßÿrìéé´i“o+U«òú빎 ŒVËMH¾¾(•̘ÁÊ•üø#þþRÐìéÉìÙlÞLL Ó¦IKÓúöÅёݻÉÈ V-¼¼BBؽ›ÐPüüX²D ÊmlX°€Ÿ~âÂ|| y)L&±xè…¦V«[´h‘’’bŸ3HX>ÅÇccÃÆÜ¹C×®LŠ·7ýû3jvvüö³góÚkÄÆÒ½;™™8ÀÌ™¼ó:³fáíÍÂ…ÄÇÓ«'Nд©åVL&nÝ*ú*‚ðüTª§[¦H``±õFŠZÙý»»oóæÀ3¼‡ZYÑ·/}ûæ:ÂgŸå:R³&óæY¸\¥âßÿΛ|ôqÕªQ­Z®# ={Ò³g®ƒžž|ô@b"‡ÈdtéB—.y¯íÞîÝs|ün9ùàƒBºØÙÄ´iôí˘1…Ÿ/”ºøøø„„///»"Jª©P(Š|œµT4h€“z= ÷îáíÍ… l܈\NVqqÒi93øvvEf&¡¡T«Æ¤I$&rñ¢å`4+‹>}8q‚U«JîI ‚ ”å`´NæÎ¥R%ŠbdzKI᣸sÇ|¤N¼›žRIÍš”ä:@++.äæÍR~ …'wþüùC‡µnݺuë֥ݗ2íÎ&NdéRj׿êU ¹/pÊå¼ü²”z¢wï| ŠªTL™Âܹœ?O×®ÅÖoAá1e7uuÅÕµ´;ÖÖŒ‘k·Ð3oN·³cÉ’"éÔSpr¢^½’nTx6F£ñÖ­[&“É+g•FÝ3-- °µµ•W ”³ÉÉ ´nµ5k׿{šFC­ZÄÇÓªr9ù¦Å‘ËiÑ‚®]9w®˜º,‚ XVvƒÑ2"g8SJÀƒâââ<Š.ÅeJJʦM›d2YïÞ½‹¤žS©pr’>Êåxx VãçGëÖôï•2žžÈd¸¸`k‹B‹‹TÀB­fÖ,ÆŽ•rk¤¦²aCA™Ý iw£ ‚PbD0*e…­­mÛ¶mÓÓÓ‹0©“Á`HJJ’Ë冇ôÊ¡)S¤iwGGÖ®ÅË †Õ«¹~ÀÏû÷Q*ùäll0™èÞGG¶n aÓ&¢¢Ðé¨T©TöÞÞœ:ÅÑ£Ô®-ô ‚ ”Œ ááØÛ[˜ÁÔë¹t‰  ‚R®&'£×ç›Ï¿øÜ¹ƒÑ(ÈãÜ9ªU³<–šú¤Y£Kž••Uƒ J»eÑÃR¡ jUék[[êÖ•¾ÎÉ¿–§dÕÃŒoÎÎOºlºukºveÑ"¦O§~ýçê³ ‚ð„*β'ñûïœ8Q íîØÁéÓÅÛDX_ýì—/[ÆÞ½Ž''3h±±ù^h2±{7ëÖ‘ýÔÆÇ?WŸ7ofãFËß8ðpËßš7 ¤’/¥Réåååéé©)‹ž€ƒóç³i“ˆDAJN¹Ò륤îàäÄÃ|8ÙÙÄÅ¡Tâæ†\ŽNGF›6@PJ¥4lf2‘˜HZ..RR˜'g0‹L†“&“t¹^Ïýû˜L¸»£P`0–ƦMÔ­K@ ÅSì¦7™HOG©äÁärÜܤ<£&ññdfJ}6™HKãôi-bÀd2ll¤´Þwë–·šNb"))=Y m[ bðàBžZÉKMM}ðàV«-ÚÂKýsÖK ‚ B™TîƒÑÓ§™;W*¹icòeTªÄ½{L™Â; ôéÃÈ‘üý7óçsñ"ÿMh(Mš0u*ÙÙ|ó Û¶a2áéÉgŸIÓ|©©,ZDãÆtìhnèòe–-câDüü23ùïù㬬pv¦N>ø€øxæÌáâE ÚµcâDnÜ`útΞåìYöï'((o®Ódd0~<:ññþ˜S§¸w!CP(X¾ww®_gútÒÒHOgìXzõ²ÜîýûŒEr2½zñöÛÒÁ¿þbútT*ìí¥PØ¢V­¨QƒÕ«éÑã‰~ %æâÅ‹üñG³fÍÚµkWÚ}A„’Sî§é““9vŒY½šعà믉Šbùr¦NåóϹt‰Úµ™7ÆéÒ…yó¤±#GX¶Œ÷ßgõj ¾úJºgf&7ròd®†"#Y¶Lªç ÒÜôœ9ÒÁ›7/æêU¾ü’Ï?gÛ6ŽÅÏOj·gOæÍcôè§xj—.!—³b°d &×®1>ãÆñÍ7dd°x1vvLœÈðḻ3o3fàåERï¾Kõê¬ZŸq̘ALŒåVœœ˜7sÚðœÔªmÛò¿ÿÑ®IIùö0;½½ggš7' @êab"+VðöÛ|ü1@\S§òÎ;|û-J%sæ —3f 'âæÆ¼yÌ‹³3F##Gâã÷ßòñÇL˜Àƒ–ÛuvæÓO©]›Û·ÍÇ£IÖ¬¡]»|Ÿ, T2y2k×°–<“Én0\ËB>3AA(Aå>||hޜʕ©V¨(€£Gù÷¿©QƒprâÄ ìí©Q\]©QƒJ•vïF¡ 4”õëÑé •>:8°bEÞRŸõë³cAAÒãGiÔˆ–- ”ðRSÙµ GG6of×.t:NœÀÚš5prÂÝ5 ©ÞùÇ|ú)Ÿ~JX˜ù`÷îTªD‹ÄÅ‘˜ÈéÓh4¼ú*þþtèÀÁƒ(øùáíZMT«†FCt4gÎÍúõüó©©R¸ü8•Š5¤ý9âã gÀ¼½4¨ mÛÒ´)_ÍÊ•Lž,--U(xýuªT¡cGîÞ8}¹œ>}ðñ¡_?þú ™ |}¥>רJEB “±f Gb0pñbA}~4l‹‰áÜ9†ÅÛ›áà ٢ԡ®®ìÙcSAç• ´´´˜˜++«Ê•+í*'}MZš´0Q¡ÀÞ^ZTú¸ìlœ±·ÇÎŽ—^bäHé¸ZMëÖæ­¸9ÜÜèÒÅ™ét¨ÕÒ"Μ•‹Z-vvØÙ1lÖÐy’3wïræ gÎäŒ|¸æÒ`@§#- ¹\JsãàïSÓë1™pvÆÎ77Æ—âï'‘“gQ£P*¥/,rtdùr¦O§m[nÜ`î\éxN,˜ó#23ÍKB­¬ÈȰ|·´4)adÎ øþûæ}Ó…Ê ´r²h4ÒÏ%?J%ï¾Ë¦MóéJ‰S©TMš4iРAQU}(++ëÆ·nÝ2VôM[*0r$7nä;¦žÃ`ààÁ‡ƵZƧW/,¼õÇY¶ŒÍ›ùòK)}ï=^}Uú„6{6ßÿ„Ï#_ññLšÄíÛLžLZÚóÞM¡ì(÷kF- áÌt:îÝãöms@¹œ”ŒF)0ªY“sçèßWWRSÉΖ¢¨ÔT¾ø‚FèÐÁ|Ï+WX¾œwߕ֌֭˒%„…áéÉŸJ{§ªVÅɉ‘#Q©¸ßœZH¥âÆ s»ù6Œaà jii\»F@'N"÷òÂ` #CÚGåâB•*Ô¯O—.ÄÄðä5}<=±·çìY*WæÂóôýãnÝB.—Fƒ‚ µ|ZժܹCXüý·ytY©”våìØ©\//ªUãµ×¤›?ù(¡§'ÎÎ8@¯^üóz}!çwëÆœ9i[·þöÆoU*±µ•F¬¬¤a¼‘#yã † ãÞ=êÖ¥qcéä¦Mùüs._楗xï=z÷fÿ~†§R%"#é×!C²²øå¬¬r£wî°f Jof={òçŸ ‚›4j„BÁ´iL˜À°aØÙqý:óçÓ¨@ÇŽ|ø!QQ1sæS<;[[iT.ÇΙŒzõhÞœáà àìYs}ÑÊ•ñöæõ×ñòbútªTaÌfÍbÛ61ùé'ËM¬\ÉÁƒœ=˵kìÛLj´jŰaLÊöíœ>ƒC¾1ôÑ£¬ZEf&ØÛóÉ'ÖÖÒP±L†½=@­Z¼öÆÄ¡C¹ú@Ÿ>¸¸°p¡´kæLvï&#ƒ78rÄr»[·òóÏ\¿ŽÁ@DÝ»óúëLŸÎŒìÝ˹shµ…ÄýVVôè¡^±byß¾}íszYAÉår+++u™Í­ZüvïfËê×çòe–/gß>4t:¾ø‚ÁƒÙ¿Ÿ-[ضøxzõÂߟêÕ:”•+iÕê)Zqq¡jU¼¼rM ÷èÁÚµ¼óŽùȼyÈdñí·=ÊÂ…¬ZÅùó¨Õ,[F»vŒÇŽ9¸q¼ú*ÉÉ À–-¸¹¡VS³&VV„„Hé2A*†rŒÖ­ËÒ¥R­” ¤¡ÍÆùùgnÜ@£¡aCóØFÿþ4lHb¢”¡ÝÙ™+8{VJ õ0¶ƒß~›7|ƒüþ;ÁÁÒÜBóáá(lÚ$M 6nÌ?réÙÙTªd>¹sgILä©Â-’¦×X³''T*–-ãÄ ²²˜6Í<2êîÎ?JC•®®Èå¼ù&­Z˜Ç†×®uê˜úû£P0u*íÚ‘˜È[o¡Pä›e©š7ç»ïHH`Ò$<<0™øà)¹’µ5¿þ  Tòõ×üý7iiŒgn.ç„ëבɤŸàë¯S·.7nT¯žoŸ5ÂÓÓü0'Â;ïШññŒÑXø·n®?ÿ³cÇŽ~ýúrj1KOOOIIqpp°~ÚìbO@«Õöë×O&“½°ñè¿ÿMÓ¦$&’žÎpò$Íš!—3e ÿù÷ïS¯Çsü8:Ÿ~*}ŒyÚ`´KºtÉ{°ys.]Ê5Ë?{6ññ¤§ãíÍÔ©Ì›л7Z-›73q"¯½†^ÏܹtëÆèÑÈdôïÏþýô틇?þHÿA¨0Ê}0êèHíÚÒ×®ò 2O?¤Pä=hoO‹yOS©ÌéCNN<:ÍGáãCVþ) •*YX©TZèL¡ jÕ’¾¶±¡^=ék^y‚·›ª IDATÅÂù¹JÊå›bN L=ßÁ€€¼«cÆÂËò8™ __êÖ%.NjZ�ÐÜÿœaÀÎŽ¶m-ÜÁÅ%oZМýLùõY«ÅÅÅò‹,—Ó´iá}~ÈÖVùÃTªç›…- aaaÛ·o¯W¯^§Nd/w}zJ¥ÒóÑÈýc2±gsæàå…µ5ññRª2¥RúEµ·§reÂùx‘¤…ãøúAë #G²|¹´dÜhä“O8tt:¢¢¤5î*ÖÖXY¡RI“</’–&íyÊÎ&=½:#‚Pf•û`´´hµôéÃÕ«h4üïÏk–°û÷sM'æZ‡ðÌ^~¹¸ =Þ祥E¢nÝz Eoz7oÞÌÎÎvrr*òHô…eúÿi²²X¶ŒwÞaÄRSÍWL&23 ’’ptD«¥iS.”Nx8Ž,“=×ÖõÞ½™9SÚÌÃÆœ8ŸdzgO¾W¹¸ðæ›RÞ_ ¨wµ ‚ ”-"}FVVtì˜++~çåÅï¿Ë ØnÿœŠ¯ÏeGfffTT”R©ôËYŒ\Ô’’’¢¢¢\\\¼ž| [y¦VS¹2¿ý† ~~XYaoÏÝ»\¿Î¶mæ¤iÙÙ,[†ÇŽ‘’B‹¸»3p ÿüC` —/ãà eÃðö&9™mÛðñ±0aR(GGz÷fñbµšë×ÉÊbÞ¼‚¶Ù ÀwßQ·.¶¶=JÇŽO±™O¡ÜÁ¨ ”&™LV§N„„Ççܶ›7onݺµAƒݺu+Žû—5j53g2>Ÿ~ʤI4jÄìÙLÊ‘#x{óŸÿP©J¥Tìw0Y¾WW´Zþû_¾ü…‚éÓ¥ÚÙñÕW|÷&ÓÓ-ÖìØQZ¸üÖ[ܹC­ZhµÌ™#-KmÖ ¥¥’ºuñõÅÁƱµ¥}{”JÆŽE©äƒÈ̤jU «QA*Œ BiÒh4­žj§ÌS2 €¼àäKP«W›þë_ìÚ•÷œ‡åÖ’ËéÕËBZ™ŒÞ½éÝû©»ñ0kDp°9—Åðá žë´·Þ’¾ÈYBðÅ ï¿Ïûï?u£‚ åÑ ôUNeeQÑKçÅ('µÉ“{SAÊ Œ–u+W²eKiwB(©©©qqqÅZ¨ÓÓÓ³cÇŽÕªU+¾&Aáy¼ÐÓôz=·osé&5jàï/¥¼{“‰ØXnÝ’2 ™LDD`oÏ… deÑ ..ܾÍåËèõáïpãnn89ÄÅ‘’"Ï#3SÊêrí¾¾Ôª…BÉDd$. ÑP·.®®ddpý:'NàéIp0Ò´œ L9•¥ó-}™À•+ÄÆâåE:Re¦ìlnÜÀÑ‘3g°¶––©ÅÆ¢Óñà7nH©š¹r…èhÜÝ©[bbHM•’@ \¹‚¿?ÅóÅròäÉcÇŽµjÕªyóæÅÔ„(à#‚ ”a/t0ɘ18:bkËɓ̟/¥:Z°€ƒQ«±³ÃÖ– ÈÎfÀ¬¬0ÉÎfà@zô`Ü8¬­Ñh¸p hÕŠ)S¨Y“9s¤Üï K—Zh7<œN ¤R%BCY¹’6m¸r…Aƒðó#!•ŠINfÆ ÎŸÇÆ†°0š4áý÷IJb®^¥F ÎcÞ<^~Ùò³[¼˜ÐPªUãêUêÕcþ|ärnßæ¥—xé%L&âãY¼˜Ö­ùæ~ý™ ­–ÔTfÅ öïÇߟóç©WÅ‹9z”É“9y''Nœ woNÁèsÑëõW¯^ÍÎÎvËS_AA^$/P0j2‘‘!ˆ·¶F&ÃÓ“¯¿F¡@§cÑ"~ýÕœwÓÚš_~ÁÍ»w±¶&;›”^y…3’’¤ Lr9z=+V°i/¿Ì AÌËøñdfj9ÍakË‚ԫǨQìÙC›6¬^¯/ßO\;³?}ú°e &P¹2&HþñÇŽ±};îî¬]Ë’%ù£o½ÅÛo“™Ix8cÆ0i’TµÈhäí·éÙ“ÄDs:Æ´4þübb†eÈ23‰ŒdÈ>ø€¶m±¶fÏzõâ»ïèÒ%W‚}áDGG'$$hµZïœRÅ#===;;ÛÖÖV•S¤µ|JI!>gçç­/‚ ”A/P0š˜È¨QÜ»G•*,Y‚‹ ii̘Ax8*•4ëýPÇŽR°õ0½Ÿ½=}ûJ©°Ý܈gî\.^ÄÊŠ»wiÖ  E L&Ž“ê‹6hog\\¨R™ .]¢eKT*¼½ñõåêUËž;GZ“'¤¤H‰»g0°g«W£T¢×“˜HLŒŒººÒµ+ -'ÈÑ¡ƒô]OO ¶mcà ŒFt:t:ÜÝéÙ“~ M~ÿ•+ ~±…ÂÙÛÛ7hÐ@£ÑØÚÚ_+û÷ï¿råJß¾}«T©R|­·#G˜;gg~üQŒÇ ‚ T4/P0jcÃðᤥI“ïÀܾ֭͆ T©Âܹ?n>ùñQ$µ:×Á]»¸|™ï¾ÃLJyó¸~ÀÃöíY»–´4zô(¨nŠLFžd;j5IIz=ÙÙüÒÒ:Ô\nûQ®® ÌGao½=Iñ·ZM``Þ“ÝÜrM÷;91j3f`g'í¸Ïé¡FCÏžù¿¦Â“‰ŠŠ²±±qrrRäü›*UªÈåòb] P’D0*‚Pñ¼ÐÁ¨»;6ðàÖÖØÛ›?^øÄɉuërñò’®ÕhppfgIB&P@Œ`¾ÛÃú+®®¬YÃÒ®ö‡‚ƒÙ¾ÝüP¥bøp 1{{òËe®T2~äP(xçF§ÃÅEºÖd"%…3ghÓFÊ0%<³ìììß~û---mèСîîîÅÚV ¬(ÖÖT«Æ§Ÿ2t¨ø8$‚P¡¼ÐÁ( RñÌÁ€RIžœ<›7³r%!!´lù,7”Ëqqy¢35ófö£G9yÒü-++zöÄÕ™ gçgé “åÚÞ$'3t(,_þŒ÷ºsçNbb¢££c…°,2vv„…‘˜XÚ]AŠÔ‹Œ­—_¦N|} ÚºTät:ÒÓÍM&Šc³Š­-ŒVkN/ <³7ndggW¯^½¸ƒQ“Éd2™*FaúôtNbþ|Z´(í®‚ EJ£EÉã²o¶iC›6ÅÞŠRI:ÅÞÊ "000%%¥fÍšÅÝPjjêŸþ©V«Û´iSÊÓËåù¦AÊ/Œ BIóõõõõõ-†t:]xx¸UÎæµòL§ãî]âãEA„ ¨ìÎßefGVVi÷#7ƒÄÄb™Ïa2‘”DBB16!¼8t:^¯—Ëåå}¦þÐ!FŽ$(ˆààÒîŠ ‚PÔÊî[ÔÁƒôí˘1æ<—eÁíÛŒKtt¾'¤§ùì÷ß¿Ÿ×^câIJõ¬…¢’••uýúõäädÓÃJ¬ÅL£ÑXYY•÷<£õë³n?ü ¦éA* ²Œ¶jÅòåìØÁƒ¥Ý•Gdgsó&:]¾'œ8Á!Ï~ÿíÛù׿˜7/Wª)¡ÂˆŠŠúé§Ÿ¶mÛ¦+àw¨èhµÚþýûwïÞ]ýxÑ­rÅÙ™ªUE$*‚P1•Ý5£ÖÖ¡Vó CHrãׯK¯^tê„\NBë×sá•*ñæ›ìØÁ Aæïë×l.}ô¨7øæîß§re©8gz:›7sì/½D¿~Èå|û-Çsó&ÿ÷8:òÆhµüó›6K•* Š¿A=7xölSBwíÚ5NW¥J•’‰U*Uqç1A„çTvGFs(ùV¼,À±c|ø!~~2m11dg3f н;·o3m©©,_ν{Ò%‰‰Ì›g¹¾KZo¿ÍÝ»tëÆáÃRYθ8Μ¡U+ºwç»ïX½…‚€ªVÅÖ–ªW—JÀ?N•*ôëGJ cÇ’‘‘o·M&¢£Q–ÝÂsÉÊʺyó¦R©¬^½zi÷EAÊŠ²øÔ«ÇÒ¥ŒÁK/廑6=»w1™ÐjÍIã»taÄ’“Y½šˆŠâÄ V¬À×&L@¥ÂÁk×8uŠ»wyùelm©RÅÂý/_&2’/¿¤zuœ3ÀLJqã %* ooΞE­¦sg¬­9|˜Ì—Ìñã„…áäDd$wîP­š…V¢£Ù»—óç5ê¹^1¡Ì’Ëå­ZµŠÕæ©6[lâââ"""ÜÜܪV”ªY{öÌãÙt:~ý•¸8”Jºw/ö$kW¯²oYžKAž\YFkÕbü½©_?ß`ôôi† ##ƒqã˜2E:èêŠ\Ž““4Ñÿ> |ò‰´ìÌË ¥’† 9vŒ«W¹y++ÜÜðô´pÿÄD ©¶»‡‡TüóâE&8˜5HNÎ[Šé¡”Þz‹;whÝZÍoÕAd$ëÖa0ˆ¬ò–J¥ª]»vI¶¹cÇŽ T˜`T¯gåJFŒ°ŒšL$&rï?þH­Z…£F#_}EãÆ4nü,Ý0éÚ•W^¡øsÅ ‚ T|e=ýñG–-£S§‚ÎiÔˆ#G0™( œ§'U«²z5~~ M›òÙgT«FP›7Ó²¥åx×Ù¥’´4€˜’’ŽÃߟµkQ(xÿý\»¬ éþÀíÛ\¿Î?ÈÁƒ¹ªÌçѸ1;vн;‡XÐó„'”³gßÚÚº´;ò¼L&âãIL̵ˆ<çCfr266xz¢V3b©©ìÛ—÷òÔTîßG&ÃË µšŒ ââØ³µšÊ•Ñh¤Ž˜23qsÃѱ.…‡óå—Ò?sAáy”õ`4#£ðÌ‚juáSr!!ðþû BB‘‘LœHp0·oÓ­!! Ìûï[¾68˜ªU™=›^½X³FàôöæÆ ¶n%:šï¿7‡ËZ-11|ú)~~të†V‹µ5?þHÍš,]jyMêC*¤¦ò\„ò(:::99ÙÇǧ$SЧ¤¤Šò1;ÆØ±Rä—óÁÏhäçŸY´†”>þ˜®]-_{íï¾KR´kǧŸrü8ÿ÷\»Æµk¬_OãÆ|þ9™™L›ÆXYamÍÚµ–íäÈÙÅXþ_WA„2¡ì£9éßFž!CbË–ælùcÆà+V°v-[¶ Rѽ;j5̘A»v89±`uëZ¾› Ë–±r%;vСÝ»ãäÄ+¯Ï®]8;³`yK~p0‹sêqq xx0>ë×É›o’•e^Õj‘RIz::¨4SÑ„††ž9s¦[·n 4(±Fƒ‚‚ìììÜò[DRN¤§3gmÛ²`§Nѹ3ÀíÛL™ÂÒ¥tëÆŸ2i;[ˆu:fÎ$ €… IH cG^{6m8p€Aƒèݛ޽¥3û;8|77&MâË/™7Ïr²²8¾ yAá©”Ý`ôÈæÎ¥J•gù£ß¢…ùë·ß–¾pqa„\§)Òn$`üx½>×9VVÈdøûóÙgy[:”¡CóT©èÒ….]ÌGš5£Y³'íy:|ñqqÌšep…ò.---""B­Vûøø”d»^^^^^^%ÙbqHKãÖ-¦NE.'0€€3gHH 4”M›ÈÊ"6–ØX®™™œá78¥’{÷ض ++  bÜ8Ž¥qc>ù„ž=9|˜=¨\™¨(Fbذ‚º˜Lϲ¢]AÈC£‚Paeff¦¥¥rö~—g­ZñÇܽ‹§'66ØØ P0d:qû6 5jHgÊdôéCûödfâì ÄÞ½„…¡× å Ú·çøqÒÒ¤ÜÃVV|õ×®‘šŠV+å€+€£#ßO—.89Ó“AxQˆ`´¸œ>‡G®•™™\ºDp0§}4IMÅÚZl¢¯€Î;çààP¥J•ž+7™L&“I£Ñ”ðÚ€bâå•w’L†‡‡…´n2™†>dmÅjæØ4ç‡AmÁär–.eçNôz† y¢KA„ü”õÚôEkçNBCK¨­‰Ù¹3ב˜Æãöm 'ge1q¢4Ï(T$ÉÉÉ{öìùñÇ“““K¸iNçæææççW’™M_²aƒˆDAŠ@¹ÕëÉÈ@&#=s:¤ÌL’“Q(pvF.G§#-_~Áߟ  T*)c”Ñ(mV°·çiß²³²HIÁdÂÎÎ<Ø™žnžøËa2‘œLV–”-ß"kk)w ÔÔJRDDDZZš¿¿¿]‰gêR«ÕÝ»w/áFAái•û`ôäIfÌ@­æÞ=œY³oonßfòdÂÂ0™:”Q£ eÖ,°±aß>Z´`æLôzV¬àçŸÉÊ"0Ï>“fÕÓÓY»–Úµså+ ç»ï6Lªôi\¹‚É„ŸsçRµ*7o2i‘‘89qåŠtáÖ­,\ˆN‡ƒ))ù>‘ŽY²„ß~cĈâ{µ„’võêU£ÑX½zuU…^a0 J¥² ?[AQî§éSS9uŠÑ£Ù½Nʺ|9ÑÑüú+sæðùçœ?OƬ[ÇË/Ó¿?ëÖ1nÀ¾},]Êdzcj5_|!Ý3#ƒåË9v,WC7nðÉ'æIv•Š×_ç§Ÿ¤k—-Ãdbî\är~û÷ß— ÆÄ0g}ú°gM›’ïqvfȾý6W™{¡¼kÑ¢E»ví‚J#_—Éd2 %³{)&&fË–¬ÐÐ:]iÆÜÙÙdf’™™+hŽB_‰ÌÌ"ë‰É$õ$«ˆ‚sƒAºa9§WÀ³.àµ*a&YYÒke2•rgA(å>|}iØüý‰ˆ åÕWñö¦C\\8ykk¼½Ñh°µÅÛ[J¤¿w/66>Ìòådeqò¤ôÎaoϲeôê•«•zõزŜÔÞž¸8¦Oçí·¹t‰HIáäIzöÄÓ“¶m¥3#"HJ¢KìíéÝ»·={¢Ó±kW¿>B)òòòjÙ²¥Ã£ÛdJJjj꯿þºk×®¬¢ ˆòwýúõìlƒ•U†Jõ4±R‘ÊÌä£2„¹z5×· ,àøñB.ïׯÈ:ǰa ÂÈ‘…ÁObφ¥¾ùæ)®Z¸?ÿ´ü­yó:”>}8s¦ðû¤¤´Êè9ÅÆòÞ{ ̨QÄÄW+‚ ”e!}\Fr9€L†ƒC¾YYR-øôt||èÓG:®VÓ²¥Tuð!WW:u2G“{öðÉ'tî̤I´o`4b4J‹Vår©9ecrfhÕêBê*¹»Ó§«V‘žþ OZrÉÈÈ »s玩˜‡›²²²®_¿.—ë}}/kCS«2„±c¹u‹ÄÄ\ßÊ©è[põ+ƒ={Ь3NNLšÄ!=Z4£}õë3i\zš×øìYË;&¾}™4‰¸8îß/ü>sæ°qãS´ûTœœ5ŠAƒ¸|¹C^Aʲr¿fÔ¢  Ο';›»w‰ˆ0§k‘ËÉÈ 3…•ŠZµ8wŽwßÅÕ•ôtL&iãQj*Ÿ}F³f¹JÌ_¼È¢EL›&©wïR§}ú•ŧŸ¢ÕboGÒ¥ ‘‘ܹàîŽJEDUªHå^ 6p 7òûïôèQô/‹P’’’’.^¼X­Z5777YiäF7 Æ™‚•ÉdÕ«W—ËÜî”@sù‘Ë !55ïNÄøx~û ™Ì¼»Q¯ç×_ñò"4úöÍ•àÉ`ààAôz:t°ÐŠÉÄ/¿Ð±#vvÜ»ÇÑ£ôî ÍéÓhµ:„“ƒѰ¡T,ªPÙÙ9¹sÈå´oOp0F#'Npð vvôè·7îsâ—/r7½ž¿þâØ1ªV5¬ÍÊâÐ!N¢reºuÃÁAú«˜gÈÞhäÚ5"3“nݨZ•˜öîåäIîÝC©ÄÃöíQ*¹Ÿ={¸s‡zõhÝe>ï$Û·Ó¤ ®®Ü¿Ï±c´k‡­-÷ïó÷߸¹qè66¼þ:uê`k›ïMA¨ðÊýȨR‰TÅÊJŠ&GæÐ!þó†ç_ÿ¢iSéäæÍùá––‡ö쉗ƒ3f ½{›?úge±kWÞ?úÑÑüôññÒúu¹|™#4ˆ ¤š.&°};o¼Á›oJ…¿?¯½ÆÄ‰ŒÉìÙ89I#¦ù©\™=XµªÈ–š ¥%,,lÏž=ûöí+™ˆðqr¹ÜÆÆÆÎή¸óŒªÕêV­Zuîì¢V—Å!ýÌL®\aÁN’ŽädR=૯˜=Û|²NÇÒ¥Œ‡»»å»™L¼ÿ>qq.0uªtüÂÞz‹Q£ˆŒdÃîÝ{Š.\È;ï Óqó&›68À«¯’žÎÞ½téòtëÈ·laÀ23ùùgöí“ú|¸^¯—ü¨¢«T‰Ù³¥è!¥’?¦{w||øüsé ÑÈâŬ[Ç÷ß[N’_°ädNœÀËëé‰&%1>ßOÇŽ€ô)ô›oxýufÌ +‹ZµØ¿Ÿž=Ÿô†+V0v,“'“šJƒaaüï¬_OƒôèA¯^ÄÅY®{¼p!ݺ1u*2ƒ³};£F1s&÷îÂøñÒi[·’”ÄêÕ89áîκu¼új!kòËùúk5B¯%UA(ÿÁ¨ƒƒ9@¬ZÕ|Üßÿ¼'ËåT¯žëˆ•× W*-¼9:Ò¸q®#~~jV¯ž· µ:ï… `õêBÖ· e\LLL||¼³³s@ž¥Ç%H¡PØÛÛw+IIIYYYÚœ-å‡\.}"U(rÍe/Y‚V›ï°hÁBBðô”îùänÝ"=æÍ¥‡9s;wîд)r9ÖÖù7¼r…ñã‘ɤ…CÀíÛdd0c†´x=1Qúðü¸°0¢£9qàî]š4±|ÚÕ«DF2|8@z:..dg?]0Z¥Šô÷YLÍ ‚@F+™ìé‚W¡ òððèÛ·ozzºmNq…Šëرc'Ožìܹó£•oK‘L†LöŒéЬ¬ eð`&NäÿË·6¯LÆýûøùåͲd1-´'îî(•ÄÆòhU;;’’L&bcsU7-ô†Z­4n0š `o‹ ‹I±2˜+kÈd¹ÆqµZ 0Â>úYæÑÓ\\ø×¿øæ)”T«Éï×\.—–4èõ¹6r)^.“I¤v„Ô ÍÍ;Ä IDAT='ÅD.—ûøø•ÊÖ¥ÑÑÑÿüóÏíüvS…´´´›7o* 2S7L­¦R%6mâØ1âã1™¸|™cǸŸ+W¤ƒù‘ɨT‰U«¤toùFìÜIddáõ{]]ÉÈ`ËŽÍ7ˆôôä•WøðCnÞäÌ~û  C6oæÜ96oæÞ=ó¸©ÿÍŸrùr¾ÝëÚ•¹vï¿—¶Þ‡„àãÃÆèõÄÆ²k—yIzµjüô‡ л7?þH\z=»v™óøú²kû÷sþ<íÛsû6‡!—sáÇç;ÕÌîÝ„‡³~}A%?ggd2¶m#4”´´‚ΡâÁ¨ ±’É3_¨;wîlß¾ýr¡»¯ŸÃ½{÷îß¿ïââRv‚Q•ŠY³HIaéRÂÃ1Ù¾/¿ÄÅ…S§X²„°0”J:uÂÍ  re)5›R)¥°ð÷ç›o8wŽäd ÷—Ëùè#fÈjÔ S'鸧'/¿œ÷d{{V­bÓ&/.h!éò帹1dï¾+­9’®]3†åËY²Ä¼â¨cGzödÅ ~û-ßN™Bp0o¼ÁÖ­¼õþþØØ°j©©Ò ob¢yr|útllX²„óç¥v_}•wßeà@Ž1‡˜Ã‡ÌW_ñóÏètԯϒ%lÛFŸ>|ùe¾CÈÀرDDðÆØÚòÚkØØ89ѺuÞi}­–¹s9uŠ+ž(Û” ‰˜¦„¢¤×ë·mÛæííÝ AƒÒ-šžžk6lèææV¦ŠÖ¨ÁªU懓'[8gÉé‹FhÔ@£aÃé`‡–ó:åhÖŒ½{ó¬U‹Zµ,œÜ¥K® qyy±xq®#ÖÖÌ™cáLµšiÓ ¹›““ùÙ=Tµ*+WZ8¹R%–-3?´³còd ¯˜—WÞ{¾ò ¯¼RHO€úõ¥±ÞGðÑGNnÕŠV­ ¿§ FKÈÎ4mškí—P!ݺuëòåËwïÞ­S§Né†h%PxÉÍÍ­K¡¡Vùd2±n9 —³hÑsÝóÓO¥Ùðõê1dH!¹ÞÊ‹M›8|ØüÐÖ–wß}Æ}`‚ ¼€D0Zì ¢£Y¾œìlš5ÃÍM¤2©°L&ÓÙ³gu:]íÚµmr¦$KOHHˆ““S•*UJ·åWíÚ¸¸˜>ÿ?Û¦M¥E9¼¼*Ο‚  \µ ØÒ$‚ð¸:MI!* ™Œsç¦V-ärt:®]ãÒ%lmiÒ­–ÄDnÜ :__bc±¶¦qc ÒÒ8wNªAâç—ïÇÆ,ZDb"‹±b?ü€ZMXj5§OS­õê¡PÍœ? Íš¡Õ’–&U½×jINÆÎކ ¥"RçÏNݺT¯^AFV*†ìììøøx[[ÛZ§lK–···w±mq7Z­ÖÁÁ¡Bæ1•ɨ_Ÿúõ‹òžmÚåÝÊ”üV)‚ <‰:=žðñÁLJɓùî;Z´àÈ&O¦^=ââX´ˆ 8}šyé%BCiÒ„°0~ýOOFæÖ-ùè#¾þÚòj'£‘5k˜6]»˜>//ll¸r…®]ñóÃ×—ƒY³†6møã¦O§IââX¸õ뉥}{Ú¶eÿ~š7çæM¾û??ÆçʪWç“OXº´"¿Ã•;fذa9FK»/Å+%%eÛ¶mr¹|ðàÁþÉ ‚ ÅêÅ Fu:L&d2”Ji‚L­æÛo dð`Ž¥E 7æ?0É̤{wNžD.§fM>ûŒÁƒùüsFŒàþ}NœàÚ5vì@«åÿcÙ2ËÁ¨\NP«V‘ML >>Ò@¦µ5 R¿>cÆðÇ´iCëÖ8€ÑHVJU¤}}ùüsúôaölfÌàæM®\áŸØ»­–uëøâ Œ–-*•Êóa:ÇR•™™i0¬¬¬Š£TTTTbb¢ŸŸŸcY-ÏžŽÑhNÞ™œŒF#¥”Bz= J%e3©ÿƒR®Sgç‚¶´‰¬,RR°²Ê•U¡HTÀùµü$%I)Kr’›ä¨TI*ûùðÍæŸèу–-éÝ›ˆ)õ´­-VVØÚbm Á©S$$ðÞ{ ʦMÜ»—on¼Ù³iÓ†7èÕ‹‘#¥|1nnøúx{K9ÿ®\¡woš7§W/iöP(°²ÂÚFz³¹r…äd©Ý­[‰Š*Ž—Jx:NŸ_e›ÒðÝwß-X°àNÎoR‘2—.]‚‚‚Êìý×_›·lëtŒÅîÝOw‡¨(ºw§CsšÏ"ñ÷ß\¿^4·š2…îÝ àï¿ ?94” ž±!“‰÷Þ£Y³ÂS« ‚ <ƒhdÔÊŠ=HO7Ç”€F“·Ýܹtî̤IÈdyß„äró†;;jÕbìXéHN´j‘VËôé\¿Îðá¼÷ÿüƒÅ³ hÙ’?Ä` KòÛ ­Rhn·´7ɓɴuëÖ¬¬¬öíÛ—‘¤›&“I©T*‹§Þbýúõííí«U«V7&™™¹6™L¼óŽôñï!ƒÌL 4d2L&©NzV–ôgÁÏÐP®\‘ò>*;µZúˆ˜“ò3g:ç>ç^e4b0°r%õêQµª4Eóð†z=VVÒÌIÎŽÉ„B!ôzär23‘Ë¥#ß|Xˆ• ²²Ì§å´»t)Ô¨‘«]¦¦ññ:ĦMÔ©SÐi‚ Ïæ F5š'JŒ§R¡ÑšÊŽ/ü•WøõWär‚ƒ¹{—´4ËÍÓÒX»–—^"3“{÷ w…½G™Lh4¤¥±o'OÒ½»åÓZ·fýz²²¨_Ÿèh©ÔžPêâââÂÃÃår¹æ©f‚‹Mvv¶N§S©TÅŒÊåòjÕª•ÁHT¯çÛoùùgi2!§2ûÍ›|ð&P©’tfTsæpívvŒK‡DF2kj5—/KËcr²âça2±a[·OåÊ|ø!5j°nÑÑRÐ7øðC¾ýÖÂÅÐP¾ü’¿ÿæìY¦IéSå|õ 4oÎÔ©ØØ0t(@RÕªqõ*‹,}믿P(xï=Ú··¼yñæMæÏçêU4äõ×¹t‰Ï?çøqΟçêUêÔaâDT*båJ¢£©_ŸéÓ J>xyLžÌ† ´hÁÆüû߸¸àèHõêXYŒFCp0®®´lÉøñŒC›6 DD„å&”Jôz>ø€½{ùúk&O¦A¬­ –'¼¼ÈɽóÞ{üò -[²bmÚàá 5k¢RŒµ5ÕªáìL“&LŸÎûïÓº5}úV"¯”P˜‹/fdd:”™wl__߀€€2•޾¸8À¬YLžÌ„ œ<)ôð`ôh’’¤Oƒ€ÑÈìÙØÛ³z5S¦HAXr2ëÖQ¹2‹“‘Á„ ù¶ÏÛo³jAA¼ñ@PóçKKz6l ;Û<÷ò¨êÕ;–:uhÛ–±céÜ™ŒK—èÛ—W_eÉþùG*Cºs'Ý»s÷.&þþ¬[pèþÉ'ŸÐ³'ÿù‘‘–»—šJ«V,]Êĉ̜Éùóøú2z4Õ«Ká﫯¢Trñ"ÇӶ-‹qõ*_~YP]øÌÌ‚*H ‚ <§hdôquê˜ËŠLœ(}Ѻµùm졦MáÿOŠ=,îò曼ùf!Mh4ŒǸq Îôéøù™«¡üç?ÒÍšñÏ?y/_¿ÞÜîüùÒÁ!C2¤Ð''”(¹\îààP§N2²†R­Vwîܹ8î¬×ëoÞ¼ikkkm1à*U[·Òµ+;b2ѧ9+xsr´=ºÏ*gâþüyΜ¡n]iÐj™<† xùeÖ®µ0ô(“ѧ¿üÂŽ$'sü8@Ó¦øø°y3C‡²v-‹YN êê*ýçïO³fÒÁ~ V-ªU#=6mØ»—±c:ubãFš6%.ŽK—¤Hñwhܘ Xº”#G¨ZÕB+Õ«så ëÖ¡Óa0pæ õëKYê*W6·»s'•*BVíÚñûïddX^ö³w/7âä„“S¡?A„gñB£%©CQ~©"kݺu“&M^„aH­V»cÇŽ»wï¾úꫥݗ\ Èɬ*“ááA~{· fÎä‹/øï¹x‘9sxç77i»½ƒF#ÑÑ<ž§5#ƒ¶miÝš6mHIáÿ“ŽΚ5Ò2€§*J•@d$Ÿ~*=¬U+W ›3#Ö•+Ký·³#6Öò gÏf÷nÞxOOʷݨ(""˜7Oz@~»ïr288²®Tᙉ`´„ôï_Ú=ŠYY-šÃd2 ¹\^´#µ*•*$$D.—ûûûám‹„B¿?.`0`2qútAå(ÝÝ¥©†eËøá) '&ÂÃqr’"Q¹œ¤$iOpç |ý5 [·šo8`Ó§3gýú¡VÔO™ŒŒ óÀùñG¬¬00 JÒtò$-ZšJ\~~ÒA†˜ó9GŽ0apÿ>))æãr9z½”Û¨]›kר¸;;©ÝüºÝ¥ !!ôìI||¾KÞAž‡FṤ¦¦F;;»22AŸ#))iÇŽZ­ö•W^)ÂñZGGGŸ‡sÛeÉÀ´oϤIh4ìÜÉo`0°~=çÎqáëÖñ×_ LH3gb4âáÁöíæ™k½ž#hÛ–åË?^:èï»;C‡R©óçãニ g·7kÖ˜·¥»»Ó»77J‹j P§Ë–I½z È!üðcÇR«çÏ„ R<ªP “!—›‡$—.%#CŠ³Û·—¶kÇüù9Bÿþ4lH«V¬XAt4þIr²y¥A›6ÌŸOr2!! N¬]ËØ±Ô­ËµkÔ¬ÉèÑùöÙÚºØó˜ ‚ð"Á¨ <—ÇŸ;w®cÇŽuëÖ-í¾˜eddDEE¥¦¦ †" FSSSÿþûï3f”Í\÷AAìÙþ}(•üú+NNÈdáèHË–2..ÈåôèÁÿcï<㪶üž)™L*é!„„ÐB % UD¤))"+"XðZðzQ¯èUD)^D¼RT@Š銂té% IHBz2©S¾s¾ I&•„öûÌ“gfÏ.kNæÌYgíUŽE¯gêTx@Þ¶-“'sþ<}ÄCÉ*{ö°¿¥LÆöílÙ‚$ñÓODG[V¦_?Úµ«DÈ矧];²²hÑIÂÝ;ùå238PÎøñÝwØÛ󿛸úRP@Ïž²>:kII ăZ’Ï¿õ}ú•%[‚ßxƒvíHIáÅqq±xLžL` ééxz¢PàáÁæÍìØAJ ½{3xpE2«Õää”D‹B+µOÃUF‹Š(,´dò«EÌUŽlmå«‹^oÉäW3ŠŠ0«WÜ¥Z˜"ªTu¸„ fäææFDDº›k'40j=Ïh~~~BBB§†Z†\’èÐJ4öéc¥g¯^ôêUºQ¡`Ü8Æ+Ýîî^"Õh` Ånj¾ÉÎæàA–.å£ä_•‚¹6R1ź£RÉ!%ÞrqáÉ'K´Ü?üÜ$кµü¤sg9~ÿfJMèàÀ£–îcîVªZ›››õžequeÈ&Oæå—™:µJC ê4 ÅRlÝÊ]w1m¹¹µž•+¹x†Ç£bbX²„ǹz•K—ð÷gÚ4òòøùg /»îâñÇ-[xe1Q©ps«öAÜ|}}}ÍE ’$9Tð­ª>ùùùçÏŸ=zôñ²ép@ ¸î6½…¢&ÜË—3{6wßM×®LJt4ùù<ý4©©LœÈ–9;wF¥bófù¥JE×®´kG³fôî-WK²ÊÙ³<÷íÛÓ¯ŸÅ(rú4:>JLÊùó8:Ò»7žžл7;ddpîC‡òøãlØÀâÅ}£Q.™-Ô#ÉÉÉIIIéé鉉‰õ-‹@ š Ú2 tíÊ×_óÈ# Pn$“Á û•ÚØ Ñ`2±h3fÈ©§÷îåÏ?i׎øx¾ýœœxåyì!èt–ô Æ¡×sú4cÇV$ØúõóꫨTDFÊ•‡ ÃË‹'ä ¨Ó§éÜ™±cÙµ‹îÝ-z{óòËìßOd$œE@ hè7ò«V±`ÆUÔgРH<=qqaæLÀhD’8|˜ÂBÙò‘’RI„¾$‘ŸOAAE©”Ü܈Œ¤°µšØX¹qíZ>úˆñãÉÈ`Õªý32,Ïwï¦C~øIâí·‰‰)w•éÓ9’‡":šöí+’Yp;1 §N2™LíÚµS6È"‰999µ;¡‹‹‹ŸŸŸN§k˜–àZA«µl’ëäæréÍ›[ºRXH\œ¥%?½žŸ&;…F$ã‚jÐЕÑüüš(aÏ?/×ú³³cÏÞ|“®]ññá½÷xðA¾úJÖJ££Ù¾³g¹z•Å‹iÕJÞÙ÷ö&.Ž?ÆßŸ°0š5³²ÄÈ‘üïÌŸ»;Ë—3|8@§Nüðj5»vqþ¼¥sÇŽ¬\‰­--[òÐCtèÀÿ˪Udgóý÷¥“ÿ•B«ÅÑ‘i}»s‰½q㆛›[ëâ I’ …]} Ò˜$‹Òi¾Å8s†ÄÅ…ìlK Ïo¾aéR¹î¨™ÿ›­[1™äÔú|À˜1·Yv@ hÄ4\eÔd"'G¶kV—çž#0íÛ),$$wwììX¹’eËØ»—I“°³ÃÉ ŽÜ\Z·¦ukrs)(‡wëÆW_qæ ¹¹r~¨²ôèÁ·ß²iÉÉ|ü±qÿþû,\È®]³d‰%«ö“Oâà@Zš¼qÏ=¼û.àâÂÿ[ÉN½$É;þFc%=· ŸQ£Féõzí­;|Ô ;wöñññöö¾õ©òòòNŸ>Ý0ëÖ.ùùÜsü|êT&NäÝwyðA>ÿœK—èÜY~kÚ4¦N-aûœ3‡9sP(8yRœ¤@Pm®2ú矼ó¥=*¥’aÃJoîûúòþû%Z‚‚J{†™Q(¸ï>î»O~YTTÂL¡]Eï¾»´QÓÕÕzö{''¦L±¼T«™4‰I“ªôY\]ñóã™g˜>½Ä$‚zD£ÑtíÚµ¾¥¨/////¯Z™*66vçÎ>>>}‹‹¸7Qlløè#ùy@Ç3}ºü²!U{‚&EÃUFÛµcÁ‚ƒo©Pç­“•ÅK/•pëìÕë¶CÒhXµŠÈHQ ´¡`2™j7™|'""Âd2µoß¾ÉsR(J”–(,D¡°X:«bòL@PîÕÅÛ›ÚØc¼UøÏJÄòß~åX¥"8øv/*°Š^¯ÿã?‚‚‚üüü²Jšžž®P(œœœnQÈœœœ¸¸8­V”••U[â5XŠC•JT*:wfóf :šS§ä·Ì¹2ÌOÀr—hoÏÉ“rêâÕ& ”†«Œ6 ||ê[Aƒ!::úСCS¦L±­_£}…lذ!!!á©§žjiNŒYSìííÇŸ˜˜èééÙ´•Q…“É’Ðwð`¶mãý÷7Ž“'IKÃÓ¥ƒL&4BB.\‡¼ü2#GâîΜ9„…Õϧ‚ƈPF‚jð÷ßëõú®]»6dM4??¿°°ÐÆÆÆÆÆæ§’$ÉÃÃÃÃãVkÈtìh%ã[¯^„‡“”„‹‹%×o±öYŠ?äÃëPB@ hªˆÈϺâÐ!®]“ŸçåqèP%ÉMËb2•ŽÔ/ÙÙÙñññ¶¶¶Íu]*z½^¯×«Õê[ôò4‰/hµ´j%ªNArg)£›6qàÀmZëwعS~žœÌ¬Y$$XÞÍÈ`Á‚y³ËÃСœ9S‡B ª…££ã³Ï>æXœ½A"IRPPP«V­n1A}ddäþýû3n.Ø AmÓè·éM&9õ´Á ǘ1Ðë‘$Ôj9U§ÁÀöí´iCïÞH’ÜÓdB¯ÇdB©¬vÌÕ±æuo¼5ðôdÅ K<–Á@j*Ë—Ó«^^(•Öu}|hÞœo¿åË/k’lUP899999Õ·•`oo?bĈ[œÄh4ž8q"""B£Ñ„††ÖŠ`@ ”¥Ñ[FbÐ † #(ˆ»ï–wÆ?ž–-i׎yó(*b÷n:wfíZæÎ¥sg^y@¯gáBºu£m[¸~]žS§ãóÏÙ·¯ÄBQQÌše©üi0°lÝ»ȨQrûåË Ž}úXË/¦[7~˜øx¹åùï>ÂÙ8‘ÎùñGëÍÆ†éÓùõWK‰BA=b4ï¨m댌Œ„„GGÇ[eJ MƒF¯ŒæåÉ;ï…½½¼3¾`YYDG³lóçsú4ÆÉÊß›oÎÂ…{öðõ׬\ID~~Ìk™sÙ2.±Pt4Ÿ~jQ(ÿü“Ï>cùr®\¡cGæÍø÷¿±·'&†/¾@¯—{NŸÎÎ(–üP³góûïtèÀÏ?Σ–ûéºw'8˜Õ«kçX jŒ^¯_µjÕÎ;‹nÎòÕP1™L·®:_»vM§Óùøø¸ººÖ–`·ƒ¡Üªi@ h˜4úmz U+ºt‘+¿GG=JX ‚ÿMÏžVîÙƒ³3'OÊEüNŸ¦ gg¾ûÎR¥ÚLÏžìÞmÉ÷¹gœ9Ù3rÀ”NŸæwpp _?:uª…fkËôé¼ø"Ï=‡¿-L(¨.\¸zõjAAA£0ŽFFFþñÇÁÁÁýû÷¯ñ$;wvww—$©!§S-Ez:cÆÄG5ˆ,Å@ ¨ Þ2jÎòÜÞ^®_–‚$‰¤$’’ðöæ‰'ävµšÐP|}Ktvuåî»-Aµ:J¥<ÖÅ…É“)*ÂhÄÞ(Q¸åéߟ¶mY±¢vfÔ½^ðàA£ÑrëÉ’nÙÙÙ 999·2‰B¡hÑ¢…O£Ê²ëäIJeÄÅñË/õ-Š@ ªLS°Œ–¥ukΜA¯'1‘èhÚµ“Û%‰ÂByO¡ KNbêTš5Ãh”Í¢@v6ï¿ÏÀŒm™óÌ>ù„÷Þ£M€îÝ9qBk2‘—‡VK` û÷3lqq–¼NF£¼¢ù‰YIµµÅÆF.å"IÅ'iµL™Â?ÿÉÓO‹ôûõC^^ž‡‡G§Z1w×=™™™@C΄ZG(•´mK›6'@ 4|½eT’J6?ÿÇ?س‡°0ÆŒ!$„~ý䃳hòî»&àæÆ¨QL™BïÞ|óÜ­ €_-Ú:1‘5kHI‘_Žƒ··<¶o_¾ü…‚3X½šñãyøa$™8‘I“ç‰'?^NçäêJh(?ΠAlÚTÉg://V­ºÕc%¨ŽŽŽO<ñÄäÉ“‹zg2™Ìµ@k6Ü`0ìÝ»÷رcæz— I"-­¾…A•iô–Ñ»îbãFÌ!,+£!!:ÄÅ‹h4ôèa)=~<÷ÜCVvvÎά[Çùó¤¥áæfñòtue×.J¥’0€¨(‹mÒÙ™~àÂRRpq¡sg€Áƒ9p€¨(<=qqÁÉ ­–yó,v• //ùÉüù¼ù&EE¸¹Uòœxáþóž}—[9Z‚š `Ù  IDATãààPß"T•{ï½÷Þ{ï­ñð¼¼¼ˆˆˆ„„„víÚÝb¦Òz¡];Ö¬aÂüýi$·@pGÓè•Q­­V~^\Wðö¶ÁàæVBùS«éÖ­t…‚²½µZJ´¨TtéRº›¯oigÓR/o^õ²ácÆàç'²ÖÑÑÑ~~~Êê&¡m̤¥¥éõzÿ†ŸQÕ*wßÍìÙ„…±jÝ»×·4@ ¨ŒF¿M‡ ÕÒ·/ÍšÕ·wÑÑÑ«W¯^½zu£ÈèT+èõúÔÔT…BÑ¡C‡ú–¥†¬YÃðá\¸ 4Q@ h4z˨@Pw8p@¯×ûúúªÕêú–¥ªÌâÅ• ß²…7êB®ŠÈÉáÍ7¹rÅÊ[‡óÞ{·[žÛF£éÓ§OïÞ½Q " °°°°°P­V×Àµ >>~Íš5±±±u!Øm@©¤GÖ®-‘!X hJÜ1îë‚; ¡ŒV•×^㫯j8V¯'!ÁúHt4û÷W461‘eËØµ‹ÌÌj¯;~Íe6¹v «;½ÑÑlß^Ãiu««ëĉï»ï¾‹:þüÅ‹“““ëB°Û€­->Jhh}Ë!Ô ~~¤§×·ApGoÓgdƒ§NÑ®%OS\Ь`oOj*'Oræ YYìÙƒ›!!z=G’˜HHHé¬O7ÍåË<òH‰”R:¿ý†ÉDÅ%W®ä£ÐëY²„¯¾bóf9w77NžÄÏ^½äž©©üþ;Z-ƒáà Ë|â {öàê*Gëõ;Fl,½zXîºW¯réÏ>K‹–Ƽ>>‰‰‰Þ°À¹F£iÕªU æææ^¾|Y­V{xxÔ¶P =š> W/–-£k×ú–F ¨=îheôÂ&N$0  fÌ`Ý:ú÷çèQÂÂèÛ—øxlmÙ°øxV¬àÊ22(,¤S'BBHKã‰'HK£}{Þz‹¥K¹ûn뫜:ÅêÕ\¼È¦Mr)Ñ7;µww~ÿ!C¬,*bõjfÏæ÷ß™1ƒà`$‰èhÂÂhÞœÎÙµ‹o¾aÄ¢¢>œ22øè#¶l‘e>sF®€Ú©Ý»£Óñâ‹\¸@×®¼ý6‹3|¸õ¥ÏcåJöícófz÷ÈÉÁœF=0íÛiÛö}ƒ¦OŸ>z½þèÑ£÷ß¿Bq§ìäääèt:wwwOOÏú–E Xaÿ~Z¶ä¿ÿµÔ¸šw´2 h4|û-­[óÔSÛ‰$$ðàƒ ÄÂ…ÄÅ‘›[UIbciÓggŠJüÛæÌaÂâã?ž°0YmupkŠ’^OD½{#I¸ºÄ¥KÖg;ž”Yæùó¹p¡ªW®"Ë\¶îTSÂÅÅE¥R6RáÑ£G—/_~äÈ‘ŒÕh4 óSÿù'Çӷo5Î2 éQ\YZ hbÜA–Q;;¦M#7{{ŠËŒÛØP*Nñ[F#YY”WÜÑ‘¾}ùøcù¥FSÔ†¶¶äçËϳ³+êéäÄ+¯pá“'óæ›üõÁÁ–wÍAÞ*Z­ì{ª×“Ÿ_®Ì¶¶tïn iªV°µ­­Å½µiÿ ^ºtiÑ¢EÏ=÷ܤI“ê[–šPXXh2™šÕCµ.½ùv®.1‚ž=2„ˆÙc[ ¨£“ÉXßRÔ“ÉP|N üþ;gÏÒ¿½Ê$¸ã1™ u1ídµ±aÀ† £*ˆ3î×-[ÈÌ䯿HMµD5oNd$QQ˜÷0ﻋIM¥MŠŠHJÂꎮ^ϵkÄÇËõ×®QTÄÀœ:ÅñãddðóÏåJ’ŸÏ7ßð×_ètDD“ƒ««õžC†ðË/\¿Î‰œ=k‘Y«åøq.]’e4ˆ‹IH M$‰Ë—­Ïf4Ol,z=IIÄÄ`0p÷Ýœ8Áñãdgóý÷åÊÜ4HOOÏj´QZæ\÷¦Z£víÚµaÆ”””¯«R¹×]ÒIB£ÁÙ¹‰ß j—ü|´Úöõ-EÍQ*›áõz¾ÿžöí™2ÅÜ s½I&¸S),D©´¯‹™ï ËhY4¼¼d%ÒÕgg€gŸ%*ŠÐPT*¦O·˜až}–7ßdìXºwçÿ£_?Þz‹—^"7­–Y³,*àÍ$&òØcÄÇc2ñôÓx{³j0e “'£PàçGyû¢J%’ćrú4ׯóî»ôéC\>>²5×ÉIö1˜8‘¿ÿfÐ Ôjž|’å{Œ' £gO¾ûŽ>ûŒ™3e™§Nµ¾nn./¼ÀÅ‹¼öÍš±u+:ñöÛLžŒÁ@@>>5<æ ™‚‚‚Æè$Z ___I’ªŸ™™ž——×·o߯ko’˜¨2ôw^®}ACD¯§ ÀÆÃ£+£vv]óó•ƒA©D£aÅ øÿ 1àöc2‘—§ôð¨“<w´2Ú½;ß}'+£ï¾+Ÿäžž|÷F#€Ba9óÛµcÃL&¹E©äñÇ)ÞÈ-O‡iÙ²t¬ùR=ko½þ²¨Õ<ó S¦ð ̘A§N¾¾üü³¼Ü“OÊ~®NN|ýµ™ýüX»¶„ÌãÇóÐC•ÈìàÀ¦MVd~í5^y¥™5GŽ9~üø¥ò\n ½zõêÙ³gµõ_»v---ÍßßßÝݽÆëªT’Ô¢  ÆÎ®ÆsT„VK›6̚ŋ/V'Kšz=F£§FS~»Ré¨Ñ´ÉÍ 7×€kª?¼‚Æ‚ÑH~¾ÆÖ¶s]L~G+£’d9½oÖÌ$©´#iÙ>fnî¶oZ^::òØc¸¸XŸª¼%¬.:rd ëi±7Ë_3™àÏ?-/ml˜4Éby­±Ì‘ÜÜÜcÇŽeggkµÚú–åV©nɨÌÌLµZÝ¡C•ªæ?*•‡ZÝ.+«®”QÀÞžÂBRSëj~AS";Iò±±iYß‚ÔI²±·MOoT‰M–œŒFW­¶C]L~G+£µKq»{ûZSÝ|°væ)K)™ÕêêE55%Μ9“““YƒRWœ¾}ûvéÒ¥åCoF¡°mÞüèèCNNÙu¡æåqò$sçr ®‚;…¼<ìýüfIRµë5$IÙ¼ù?.^Üäâ’%ôQAý¢×£jÑâ_’T'z£PFkž=éÙ³¾…¨&ݺѭ[} Ñ0pww÷ññ0`ÀŽ;ê[–š“ššºfÍWW×1cÆTÝÄ+I’cm\뜜»¹½tíÚÇmÚ”ër+HÒ{³$¨:æRÆNN4k6ª¾e¹U´ÚŽ>>ÿŠŽ~½cǦ¼1%hà˜LÄÅak;ÜÓó™:Z¢Ñ‡kµBPPÐÓO?XAÔÆ@AAAVVVVVVuwêk …·÷L£q`T”%yYm¡Ó‘’RQ ((àÒ%ŠŠz¶lùa™pn/’§çKͰˆˆÚ?§‚ª ×sõ*¾þþ  ®®,Bdš@(}QQQQQ‘V«­bù¥ÔÔÔo¾ùfïÞ½………µ"€JåÖ¦ÍÏÍÔ‹UÉÉrPÝ­³~=½{Óµ«¨‚((£‘7¸pA¥T>Þ¶í6µÚ«ò1…BÓ¦Ízgç]¸ ¾~C$y¬`2‘žÎ¹s ½>¬C‡ýM@Ý­Õn³fñüóøû×·‚2DGG›L¦€€€z²&Ö&’$999999U±ÿ•+WâããnÑaôfT*ÿ..£cc߈‰9«Õbg‡£ã-mÜÀ‘#¨Tètètµ%© )`4¢Ó‘›K^ždcÓÁß¶‹ËXIjR[Ú …}‹³›5{ &fz\Üa;;´Z ÄÆ½ .0™ÈÍ5ŸV’Jåß²å{nnÕõ9%”Ñ:'3“Õ«ùå>œ1c¨f>rAb0vìØqãÆ &´o߈Sšñõõ}饗ª¨U †ˆˆI’‚ƒƒkW—$•³óðN†]ÏÍ=››{R§‹1*¬6&Ô•­mëæÍ{ØÛ‡¨ÕÞ’ÔTÝŠöö=;tØ¯×§ææžÑéþÎͽ,Î)AÝ Ðh¼¼ºÙÛw·±ñ½=Q€w´2zù2ëףѰw/={òê«8:Dze\¿ŽZÍĉôïÏùóü拉áï/çœÿÇ?°·çüy–/''‡nÝxê©r˾ñééx{Ó®‘‘–Æ·ßboÏŸÒ¥ 3gâäD\ß~KBj5£Gsß}ÄÆòé§äæÒ¼9™™88ðÎ;8:Á²edeѵ+S¦T£ © ,7nÜpqq ¨Ã ˆÛ†$IÊ*[K T*•‹‹‹ÝXì%Imcãgcã׬Ù(hÄU žFï`SE$I¥V{9;uv*Î)A]r»Ï©;å¶JRÿùññ¼ð?ýÄ–- ØÚòðÃôìÉóÏεküü3ÁÁ,YBp0›6Î¥KL˜@³f<ôk×ò¿ÿY_Âh$*Šñãñó㡇x眜HOgáBâãyöY6oæ—_®\?žþý™9“£GIMå—_èÕ‹o¾Á×—½{9vŒ˜ÆÃÖ–Ñ£Ùº•E‹nÓ±jªœ8qÂh4Þu×]Õ­ŸÙ°³³›0aÂ3Ïý”.]P©èÚ•M›ðõÅ͉1kìÓ‡»ï˜=›!C8|˜=øì3ºwÇÓ“ÇÇÁGÁÝ1chÓ†-زooþú IbĈÛr¤šqqþ‰‰gÏžk¹E‹Q*•ãÇŸ8qb¥yF322²²²ÜÜÜZ¶ly{d <îh»H«V<û¬üüÁå'¼ùféžf¼iÓ^zIn dÖ¬J–$‚‚ âÏ?yè!š7ðò’§† ‘Ÿ¸º2sfé᯾jYwòd¹ÑÇGXCo›øvíÛÛÛ×·,µ†B¡psssss«´gAA]@@ÀmøøFŒi†´BS¡ á¢*¨4’ÆEé¢äÎIoÊË» ×§Üáæ$AaR(´ZmG…âö…·ÞÑÊèíäƒðj"Õéšžž‰wÝõ{pð—MÉ2ZuZ´h1pàÀ:Mò_`*8]púº>!IŸ¨–ÒéeTPQæ›òž*U‹.š.ZI[ßBÕ F£.)iIfæžÜÜ“’”¥Ñ(@_ßB š &ƒTX¨±·ïjoêí=ÃÆ¦Îc¥…2z›ðõ­o %‘$S(F3ùùù×®]srròªì¾G’$…BQGß„éš>vîŠClŽô×^wR¤)$‘ [P7˜0¡È19§|" {þœÝ¿¿vP+u+‰&uŸ™›{":z*÷ò2jµhµ8Bn}Ë%h²ètûÓÓ÷Ÿ?¿Ú×÷w÷'êt9¡Œ M„ëׯÿôÓO–þ@NNNÕ«4U†£ùG/ìïm»©½Íq•TTG 2@3éF3ÅõùˆÂ³ûr“múô×öo*÷Ƥ¤¯ããßôöÎñöæ¦[È&¥m   ..dd$ÆÆ>›•õ[@À%©®ªÃeT h" †Š“ØëtºÕ«W«Tªªä"­WŠ.Gîíð_we‚$öå·%ú6Ǽ”×vææDzt° ®o‰jîX|ü̶mó­æ±êIÂÅ{ûÂÈÈU A-Zü³Žj¸Û”W¯²e ±±µœiÓhÞww.´¾nf&O¥’´4*Ì“SšŒ Úµ£{wy„±cIN¦eK\\ähý ,ß¹¤$ÂÃiޜӧQ©ªwj©T $%ѹsEÝúôÁߟ­[‰‰¡Y³jÌ/hŒéõz•µû6“ÉžŸŸïìì|„1™8uŠ­[qr*ñ3š”ÄÂ…¤¥1j=zX¨×³m©©@d$ýúÂÞ½ØÛÓ§yy¬_ÏСxy¡Õ¢ÕZöL ¶oçâEbcY¾77†'0ädÖ®E¡àæä8z=kÖЩb42r$DG³ctïÎÀìÛ‡ }ûÊCòòX¾œgž±ò›pß}4kÆêÕ<ÿ|­CàfŒF~ûðp€  †0™Ø¾hÓ¦"K^V›6áì̵kxx0v¬lÜÙ»†ë×IJ"0#(,dËââpw硇(ÎY¼g¼ôÀån –%1‘={pv&&°³ãüy’’d§¸ èÝ›-¢¢8tÆŒ¡MJåüHIaãF èÔ©D{L ;wRXHË– nÝ3íÔ).]Âh$9™nÝè×I¢°]»ˆŠÂÑ#qu寿8y’Ë—Y³†cÇ %4Tï·ß0¹ë.ºu“ç,*"9w÷¿ YYääàéi± EEñûï ôï/_µsseÂà`‹ÕsÛ6¢£ñó³L¾y3ÿÍõë,[†‹ < +«èõ¨ÕôêUñÿ¤áÒÐ-£&Õ5q"ï¿Ï#ðÄ•X]]éÛ—±c5Šƒ‘$Þ{_å cÀ®\©Æº;vÂĉ<ù$Í›ˆ$1b³f1~< XN½ž—_&,Œ·ßfÆ <=­Ì––Æ‹/òôÓDEñÊ+Lž,›Z]\<˜çŸgäH6n¬Hµ{û*Yø“ÉäæææééiÕ2š––cooߪU«Û ÌÉ“Œ‹NG\ß|ciÿþ{ââÈÊbüx놇¢"-bãFÖ¬aæLΜáÝw~ø­[t:>ü˜r¢9 ŠŠ0™Ðëå'€ÉD~>ß~kÙ  y÷]&MâÔ)Žeß>23yàNœ ;›ñãÙ· øüsËÓ§ùüsëŽ1J%ï¼Ã§ŸZ¶>‚Ú¥ €O?%'•Š7ÞàÇV¬àÅñð௿ؾ½Ü±))L™ÂÒ¥˜L|öo½%Ÿ?üÀŠ”š IDATC±jl܈ÑȬY|ú)’Ä×_óò˲»ËܹL›FQ©©üþ{5d¾z•_äóÏ1˜77ßD¯çàA~úIîðå—–´ƒŒÉÄ¥K„…•›¸ÐhD¯gÕ*öï·4ž?ϨQœ;‡BÁ®]åæLÜ·'ŸäèQâãyöY¢£,à_ÿÂdâ»ïxî9òò,¿!æ'æ#pè£GÍ<ù$gÏÊsšï–K9,^Ì!–ߨcÇxðA.]âÆ žx‚S§0™øàæÍÃÍ•+-¿„11|ò‰e*ó- ×£×S±IòöøÔ ×2ªÓqîEE5 ¨Ÿ6{ïE§ÃË‹¼<Š“´ \Úš(IÌ›Ç?ÿI|<Ý»³kW¯¢×ãë+«‰ÎÎ,]J¥×ñ±c !;†Ö­eKÌôéÜuyytêDz:ÎÎØÙ±c$%áêJ@+WâïÏk¯ak‹ZMHŽŽ¼ð‚åò¦VË›øJ%ï½Ç+¯@ÅEÈ L&ΣU«:Ü£4'L˜XµŒªÕê   £Ñèææv„ùázödÎ âã-í<Àœ9èõÄÆòý÷C)ÆŽ%%…“'™9“#ªº¨Rɘ1 Ä?òì³´l)·{yñòË=Zº¿$ñ0y2F#?ÿ °d W®ð¿ÿ1cÿùF#óç3bGŽÐ»w¹7·&ð¯±~}%1…AͰµå§ŸˆŠ"1‘Þ½Ù²…ñãY¾œiÓxõUòó+Q /–FŽä“Oä,+ݺ±f ¶¶äç£T²|9?þÈðáôéÃС|þ9vvÌ˲eŒÉ$ãV¥’… 騑®]yôQùÞÒ*“'3k„†²s'O>i¥§'S§–ö.]¶Œ.]øì3ll(,,mL½™ž=ùàÔjvì <V®äÿà±Ç0€‡æòedà@Ö­ãá‡-»"ß|ÃС̙ƒBAz:7ÊŠ„½=ýû—Þx  o_‹QyéRæã‘$23Y·¶mã?ÿaÔ(† ã䞣GãïO±#•ZÍ„ ³v-Ï=WѵÞd"&†~°XU# WýóO>ûŒgž©‰eT¥²î*êâbE'Óhðöææ¬Â®®¥ÝCU*:t°¼ÌÌäÂ…‚‚ðð@£)Ñ­xþ~ýäçæUŠÅó÷—Û•J¹¥x'Ñ,@y"66xzZ·§ÞL³fLÊO?qý:o¼QIgA£Æ&_Þ»NNN<ð€Ñh¬»ªô7sõ*ݺ¡T¢Tâç'§3Ú·—Û´©¨ƒB³3’„­mÚõml4I’Eºr…-äµÐP6l 8ƒ£Gù÷¿ÉÈ *Š»ï.w6•ŠW_åã™0¡¢Ë¡@P3ââ=ooüüˆŽF’0IH] ÕjËÝ—U¼¼äËM@ùùÄÄг§¼_gkKl,¹¹²BHQ×®áèHNƒHRE!³@»v¤¥Ñ¢þ‰“€‡>>­[“Ÿ_‘ïc‡ò)P:Ü¢b®\aÀY°ŠÅ3[‚¥’œÒÒÈÌÄœsÙϵºÜøŠË—‰ŽæÀŽ”Ûýýùî»Ò-ãÆñÐCrcQ—/ÉÁƒ¹¹Œ!¯b6~9;sëžS……,XÀš5¼òÊ­NU4\etèP ÂÖ¶†©Fë”ØX,(Ñò òéÚ P(xôQÆ9“(ŠºÈèd''9®Èd*±kfvž6™ÈȨž©¾Ø%Ëh¬¶m¦nÖÌ=<äP ³™ÁεšnÝøòKžzŠ}ûHOgæÌŠf{ê)æÎeófÆŽ­5 3Û·ãïÏ?¢ÑðÁüõ—œ"&!AîPqI¿”t:ìíIOÇd’7Ù ÄåÕË I’Ï‚ÔTŒFš5ÃÁI"2²JΈfl…BöørsÉÍÅÅ…Œ ù&00™0IJ²ŒMûÿ Å7nXŒAMå±;..ÄÄ`2Uû2gg‡F#ß*gdPTT®.ëàÀ´i¼ð‚ü²¸[^çÏÓ¶m …21‘¤$‚ƒ±µE¥¢Y3ž~š×^“ßU«IL¤°P^W¯¯¤0¸RYQô¶†>¢_?Þ{ü£’Î –†«ŒªT•ÿꋎùþû- VT󽦠ÉsåÊ•cÇŽw.×–’’bkkëp‹[?ôÓ§³u+ [·ÊÁÀúõrà®]Ì›W ÛµãçŸ9y’_~)Q{Ì×—µkÙ³Ú´ÿwMY±‚!ChÓ¢¢HN&#ƒÈHŽ‘#ËÒ¿?o¿ÍêÕøù±no¿RIß¾|ø!¿ÿNDtï^‘vvLʼy„…5Ä[hA£ÆÓ“èhÂÉçÛoiß•а0.¤kWΜ±82ZÅ`à£7Ž :Ô¢,ÞŒFÃðá,X€ZÍÒ¥ €‡j5ãÆñÎ;Ì+—ô=ºÜUÊžY|þ9“&±p!Ý»ãâ‚»;ÇsègÎkéùÝwtéÂ¥K\»ÆàÁrc»v¬_OË–´m‹§'W®œLj*±±>L@^^L˜ÀŒ¬_O§N;ÆT5`×ÍÐP/–}7ÝÜðõ•ßrrbõj iÑ‚‰ùôSºuÃÓ“¿ÿfÀ¹&â•+„…±zu SÔŠ,_Îöí!I<òï½Gh(>>œ8A¯^´oO,X€kÖÈ÷í:gÏ…NÇáÃØÙÉû¢¨Õ¬[Gh(íÛËöæ²ØÚÒ¥KE0>â'³&˜sˆÞü×Aý’ššzñâÅëe<ÿ ÃÎ;¿þúë«W¯Þ6aî½—×_gÅ Ö®eÊy'±C~˜Ÿ~⇘9“‘#­ T*éÓ‡–-ñ÷§{w´Zî½àÑG â7ÈÏgüx‹UõÁ™4‰•+Ù¶Mnqtdñbâãùê+®\ÁhdË.ÄÁãÇY°@N¯¡T2x07×¶ æûïÙ²…E‹xúižx`øpÂÂèÕ‹É“yþùÊ‹™½ðW¯²cGÍ@`•áÃ3†¹sY·Ž3¸ë.$‰W_eÐ æÎeÿ~¦O¯(ÔºE xùe Y¾\6"víJûö%º}ñZ-óæ‘—Ç_È'_}Å]wñé§|ùe%f¼²xz’—ÇÌ™±p!Z-Ç3|8³gsù2S¦Èúkß¾ Î’%lßÎüù–ò×o¼A›6,Y"GîÞÍ_ÈN5_|!‡þ ÆÜ¹lÚćrþ|¹×âÀ@‹qwà@||P(øøc‚‚˜7ôt–,±Œ?û †ÿþ—Çy„·ßfåJæÎåÄ ‹}ÇÁKoòп¿ÅgtÌfÏæÇ™;—ãÇqpÀƆ?ÄÙ™¹sÉÏçÉ'å”;_|ÁÖ­tìÈ_°j•<ÜLJ?äÂ/.Æ®fÏZÜ8ºÝüþûï¦r8räˆN§+Û¾oß>µZZPPPÞØ›)(ˆ=}ÚÉ &âÑœ>í§×g—ýº.Z´˜:ujU¾Û ‡Ý»wÏž={ß¾}¥Ú“’’>ùä“ùóç§§§7æåå8q"77×êT§OŸNMM-ÛîîîÞ¶mÛ7n”}÷_Ó+>ÂF#ZÛÍ¡……`4–û¯1G°šCYF -í:……¥‡ÉK”ú›w‹Š((°<Ì&“•yÌ7‹W,@qŒm¥… ùôÓŠ> xܶÇñ¼{öéö•wÊDGG{zz¶jÕ*11ñævNwäÈ‘ εSTTtôèQs¥43™™™¾¾¾ŽŽŽ±±±eû§¥­·|ƒ‚ù)þ67šÛ­‡Ë— D¯';ÛrB™Lr^íRÍçK©o»ùt.(¨Þñ?tˆ¶m¹qƒœœëêõètò¯ùL),”Oí²g¥ù¬ø\6ýÿ™[šQüCT¼\q{ÙÏ[Üíæ ÍKܼ¨ù°”:ì7® Ä3¯k–Êh´aóãæÃUÞB¥IItèÀ„ ?^'g“ùqý:W¯Î(û]ÕëõãÇW*•kÖ¬)û®Á`({m*æðáÃyyy uw¹öøøc†­$SiÃ'=Ï?ç¹çä}„ãÇÙ³‡·Þº­2¤¦’–†›©©ò–¨UŒFΞ¥m[Σk×J<ʵEQQPv/>22277·uëÖ·'Ãh1ecÌfÅbãbj*o¾)W33x0Ó¦Y<^ÌŽâ` b¿²–«N2Å«—çBc5̨T£$É- EUw?^x£Qxi jŸ›«úon4™:UöÌ6Ì TâíRI©Ÿ«§†ÕÆJC—¬bcƒ··œaðf”JK ‘™â³ÌêÒ7ÿ”G¥Qƒ7okÜÜÙ¿X•9Ë.aõ°X°ìزÝ*8ÂU9þlßΩS•Wçi˜4}eôÐ¡Ò rkÆ´iñꫵ0U 0gî˜8Q~i¾3®-dútþþ»’n{÷²iaalØ g¹+OÔ)SX¹’‘#9qÂâ…#¨Sî¹çžÐÐPíÍÏx{{wëÖMj`ú‘£#Ï?_âk\ivˆFA×6 N‘$žy¦D¾Ió¨¯o­”ˆ¬6]º°ys¹nŽ‚ÚE’är唦 ŒFDpù2F#mÛÒ¦l“8s†'hÓ¦¥-)‰K—pwçòe´Zîº [[ââ8{I¢gOÜݹqƒ#G8ž¬,¶nÅÃ޽ÉÌäâEzô@­&<I’Ý\ΜA©$7—¤$|} æða¼¼¸rI¢Où×!= hÑ‚ °±¡OHHÐ{ôW 8|¸DU½ž£GIM•}éŠ1Ë Ó‘€§'¡¡˜L„‡sù2Î΄†ÊñÈæ-›ðp Ú·Ç×—C‡8xØX¶nE¥¢OŸr½¿õzòóå¿`2‘—‡ÑHn®È·ûÐh4kå‚‚‚š& ØØ4âb!AD’¬6+c¿Í¨Tõ³® 1Òè•ÑädfΤU+”JÞ}—/¾`Ð 6làwè×5k8p€_,wøÑ£¼ð͛Ӳ%:ÿý/ׯóÒKôìIn®ìGœ’®]$&RPÀ®]´oOïÞ\¹ÂìÙ¬Y#—T©˜=`Ñ"ÄÉ wwœœøê+^Ž{î‘k‹}ù%@d$?LëÖ4kFn.Ÿ|‚ÑÈÓOÓ½;Ÿ|Â?àáÁ{ï±s'}ú°h‘¼ùb0pì¿ý†JÅúõ–²z5»wc2áãCQ[¶ðõ×|ó N@K–¬[Çpï½äå±w/~ÈÁƒ;F~>»vÉyRËSFµZ\]å¿ Ixy¡Vãã#LD ‚Û“[T ‚šÑè•QwwV­"+‹ÄD²²øá9ºpÊfÎ$.Žþý+n4’—ÇW_ѽ;……ØÙñ꫌Éûï£×Æo¿1a ð裴oo) aº©…Á`qÓëqvfýzœe/æ¢"^|‘©SÙ½›·ß&'L&rsù׿è×½•Š'ŸdäHþýoôzžx‚;4ˆY´ˆ{îaçNž}@£áå— àÛoK|³gô¦M¸º’ŸOb" 2w.#F˸qDFâéÉüù¼ü2O?-Û/µZÞz‹}û8v¬tæÔ²Œɽ÷bcÃ!uÓjÙ¸GGŽ©jŠ Á-¢×ë###Õjµ¿¿¿Íÿû%$$xzz–Ý»c0pòdå>åqq¤¦Êi…£c‰z1Åœ8Aç΢úƒ 4úŒDׯ3i&ðñÇœ;GVii$&Ò¹3 ¾¾´n]É mÛŒFƒ£#™™DD°~=ƒ3t(gÎȉ`ªEÿþxyakkñ•iÛIÂÇ­ÖâÐ@¿~ØÚâà@n.QQlÚ$¯û×_\¸@F´k‡$ѦMåûƒѼ9 ÎΤ¦rù2ï½ÇÀLœHl,ׯ£Ó‘”DH …göJ1"óß $š5C©ÄÕUd¼ºMètºÝ»wïØ±#ï¦DsIIIkÖ¬Y³fM~­˜n0°c/ÞÒ$yyÜ%}ÌÅ—-»¥…‚†FB›7cª°âyÌšÅÆÖß;¶Dl¢@P)Þ2º~=*›7ãèÈGqé’\:Å|Q6*?%nŽ“µµÅƆ×_·xdV x™Ð%¢üÊ‹ø“¤Ê™%]™ZFÃÔ©–ä‹ööÄÄò1Ñë+ù 7g;Óhðô䫯äø!IÂÕ•ôt4šJ<>«‹ÉDJ 66Â7¨>Ñëõz½^£ÑÜ\céÂ… ¹¹¹¶M´ì^ÏÂ…<ð€•¼Õ¢¼€fŒFvì`Æ ¦L¹¥U‚†Fx8Ÿ~ʨQ5ô§zÿýr÷¾tºšë¸‚;“Fo¹2דÕë9ž5klm¹ë.¹°Á/¿påJ5f³³cäH6lSû>,×Füü¸pˆ¹:™¹®ÚÉ“DFòûï·ú)9’uëÐéP*9wŽœZ´ÀÛ›uëHJâûïe­:?ŸøxRS-O¬âåE›6lÚ„ZMA¢ÑЬ]º°t)ÿÇÞ}‡7U¶ÿž“Ý$MÓ¦{è –BËZö”¡P6È.[†"‚( ¢¢"*äÙ  ²÷^e´´¥{ï4;'¿?’_[JÚ2;ŸÏõ^×Ûœ>9çI-Íç<÷}ge!%'N˜;8@«Å©SHK{á$}• C‡âë¯_áůL­VkµZ.—[Òž^©TÆÅűÙlÿWŒÔªN‡={У:wÆ_ ¨ ¦M3õ<ËËÈ8rG¢sg\¼ˆo¿Ex¸iÿŒ^½{ѳ':u§Ÿš>w­Z…9sг':t(]ݼx]º (‹W1c?‰æÒâvaL™‚?D·nèÜgΘŽïÚ…N†™3MŸ¾†ǬY¸w: <Üô—?- ãÇ£S'ôêUY}•;wй3&M2µ\7ºq}û"0sç>•ÑOϣΣpsÃûïcáBôîmªk°d ØlŒ…mÛЦMe¥%,-ѨÑS –sæÀÛ&àý÷±m[ézäèÑàr1k–)ðòòBDæÎŬYð÷‡££i˜‹Ké×X,4nlZ^åóáímZ7µ°€Oé0ŠÂÔ©hÖ S¦`ÄlÝ µ66øüsœ<‰#‹°0ðù¸q£FaófäåaÔ(|ÿ½é ŽŽ°·êu­Z…„ †ÈHœ?ošÀ·ß‚ÃÁ°a=7n˜{x`út|ÿ=&N|±ØÝ8s;;²7´†YYYuíÚµuëÖ%FY,V‹-š7oîXö×±.8wóçcî\¬[‡+W°}; €¥Kqþ<>û Ú·Góæøüsøú¢_?,]ŠaÃàòeÌ›‡9s°nnݯ¿@l,ŽÅŠøè#|ö —‡qãЧzª(c%Jú©D-wû6’“±aÂÂðù県 0q"6nÄ?ÿ`Ø9&ÀË K—béR°XÐë1lX,lÝŠþýYa¿%Ó™SSMG4LŠ&Mp䈩?A¼:›ÞÖk×B¥‹.×;º¹aÓ&¨Tàp`0T¶¤Ñ®Z¶|êF&ÊP(LO,¹Ãéë‹¡V›r•8|ò ¦M‡§4é㟠mE"lÜh:‰‡~úÉt­&MLéí%¤R,[fº»Áç›æÜµ«)Éǃ^nnO%Ñ—l ˆŒ,_g;0[¶@¥E•ÖvuÅš5P*AQ¥½ù||ü±© E¹êÄUâñ°~}eµˆ‰j`aaòtM.—¢×ëky*½J…  VÃÂÂÔßyß>xyA­FL ¼¼pâ&NDûö˜5 ƒÁÞÀÂh×ÖÖhÔáá`0`ϸ¸@£ÁãÇðóÑ#˜4 ºwGP¼¼`i‰‚ÄÆ"9‘‘0y2þø£Âé=|ˆ‘–†ààjùqÄ+£(Œ ww¼û.~ÿ.\€³3 E!2`Æ ´h¢"Ó¿#ã‰û÷qá&LÀ½{pp@l,RSááaæ––h×î©­YâáCìßDF–ϯ%ˆ*Õ‡ ‚Ç+ 7Kº”=X\Œ~@^^éS0|8S(Y›m~1µÜ`6ÛL‘£r‰ËUš'Äb•†zfó‡X¬ò×-GUT1Îì¶À²?„\®™^4  üäŸGÙHÔ6µ<P\ŒmÛ—´o†AVòóqèèõ¦Z¤4ÐP E T´ÔË0ÈÌ46>lÕÊô­’Î Æl¹¹¦"e¨ªÒ¾Jƒ……dQ—ß§Œe[Èå°±1ýòÛÚB.‡Á`¦IXNx<œ=kZO8ðÒáårXZšþM‰Å$u•xaõ!­‹wwØØ”©k·. ¢2r¹\¯× ãmúœœœ‚‚n­oÆjm5kJßiÐé°z5h cÊLKÃìÙøðC9‚Õ«1{6ðÿ}°X@Q~þxºøZ¹·F??äæ"!îî¸}»²é£Iœ;‡7àéù_7ATWWýÎÎøätíŠ1cŒNÀå"<?þˆÇѲ%† ÁèÑ8p#G" ·n¡GŒcæ¢>>èÒ£F¡[7ìÝ[Å il6IÈ ê°öíáîŽAƒÐ²%¶oÇîݦ`4(5Ê´ÔÑ|€‘#¬,ܾ¿þ2¿Éíï¿qñ"?†FƒÌLôê…6m ðî»8vŒ£Ä kÁ(AÔoJ¥R¡PXXX(,,|òä MÓ...5=¯—áá?ÿÄÿA£A` Ú·‡Fƒ.]о=x<¼ý6Ö­+Ý£663ÆÌ†.#xyá£L%PV®ÄHJÂW_!.Ž´¤'^LýFssaaa~Kå«S( T>µà52“‘èMMž¨7ŒeíõDSSSóóóÝÜÜì*ßY[Q1bÄS‡5}AÓèÔ©ô¸@€°0„…•>×ÖÖ´¼DëÖ¦/8 `úÚÊÊÔÒ 0mK­Mcøp|þ9®^ÅÎ/ür¢:QTi±j±¸ô– ­-¦N53ÞÇ空.<:vDÇŽ¦‡ rržÚ0-‘@(DëÖ¥ÿ¬J…¥ÿôÞ~û_ÑàÔÿ`tæLŒnÝÞÈÉÿøT}§ïþ}XZâEªŠ‹1z4¦MC/9½ÇAQU÷ "ê:KKK///©T ÀÁÁ¡cÇŽR©”Cšñ½&}ú mÛšžAT»GðÑG¥Û²L›†~ýjnBDýUÿƒQcSÍ7¤E 3 õÏúå4k†qã^ìärs_iòÛ·ƒÃÁüù/¢NèÔ©Ã0l6€••UXX˜¤¿>õ¦î~Dmæï;ž:B îoHFÕjlÚ„Ë—Á0xûmŒ EEX»/ÂÇ•=ýÊlÚ…R)>ùðè6l@F¬¬0>œœ —ãûï„Ç¡Raôh´l‰¥K‘œŒ€€ÒÛ"ûö!>ÉÉÈËCÛ¶1IIXº—/ãÖ-œ:…F°h‘ù™$%aÃÄǃÃÁ{ïáwLÇÿý;w‚ÍÆøñ¦BŒ×¯cÃ( Ř1¦Šú»vA«E|<¢£€wÞÁ7ßàömp¹¸˜7ïuü¸‰Z‰Åb•«âD=[¸… âE°ÙOu™&ˆ7§ÎWS(“ƒáÃ1z4víÂo¿ÀŠøóODFB$½{>7;Ó§£qcLž __SÁüädŒ'ÂÃÃÔIB­ÆÞ½XºþþF^Øl„†‚ÃÁñã¥'¼yß|ôí‹ï¿Ç_A"Ax8M¥¹+)˜£F¡S',ZTÚéÒ% Ž·Þ”)ˆEBÆŽ…£#ú÷ǦMضÍ4ìÖ-,X€ìl„…A§ƒµ5ÂÃáîww„‡ã­·^ågLÔ ÃÜ»w/%%…a˜šž AA<¯:¿2je…¾}qû6àìYŒ‹ðñÇèÑíÚ•¿ËP–Á…j5ø|Œcºqæ X,|ô¬¬žÚ(¦×cþ|¼÷( 𯀦j…eµm‹É“AÓ¸~{ö`ÈL˜€k×Rš0a–1Ãñþ}$'C.Gl,|}`âDôî°08€³g!•B¥Â¬Y°´DTöíÃäɦ34mjêöiœÞ„ HL—[Åu‰º.--í¿ÿþsqq øçŸ8ÎÈ‘#¥ iAC.ÇÚµ˜3ÇôðÂ$%aðà7r­'Lý¾;v4Ý© ˆj Ñ૯àïÞ½Ÿ«;Ƀø÷_S&‚¨ýêüÊè¹s6 .ÀÒÐ韹¶¶ ÁÙ¹ÂçÊdXº—.aÌ´kgZC}ò66¦f„S;d IDATëÆjF |}KKsWD*‹e*óœm¯Ö­ÃŒˆ‡ƒ,,JwkÖˆÅÉ“ƒ´4ðx¦ªHO/=ƒq¥¶òéõ\.MKKKNN–Ëåvvv– ¬ªŠ\Žo¿-}‹Ÿpú4.|=׋áä„k×púôë9!A<Š‚TŠ%KL>+Ç09QQ¦72‚¨ýêüÊè¹shÖ ?ÿ  ÷ÖÖ°´DJ ÈåHN®ð¹…~ýн;rs1iþýðôÄ '§|ÊM›éŸö¬ÌLhµàpcÚjT¶©YÇcÆ Œ‚lÞ\ZM#) ž{{XYA©D^¤RÄÆ>•¡o6yºl"$Q/ ±XüðáCƒÁàëë[û»€¾„ÂBÓŽêFL¿ê ƒGPPPº­aöíMF ÈÊÂãǸv ii iÓ§»gétÈË3}ˆ-**ís›ŸÈ˃£#Z´@‹•ýU!ˆ7ÃÁôéHHÀ­[U6pû6þù‡$ÞuFFýýñÛoؾ øûo´kšÆ¨Qøùgp8¸|¹ümô²bbðí·hÝ,ââ0z4tìˆ5kðñÇx÷]œ:…ѣѤ‰™ç¦¥á¿ÿpéÒÓ±m||Lu×.]ÂW_A*ÅÁƒX¹Ò48 ›7C(D£FèÞÝüd5ÂÎàñð߸¿ôø?B À½{P©Ð±£©ý¢E ¶m¥e‡ÍòòÂwßÁÊ o½UúöLÔ3F ˆD¢fÍš¹¸¸x×ÇR^QQ˜0ÖÖP«á鉵kÁ0X¾ü77Ó'O fÎÄ£GƦM TbÖ,  |÷©Óî³d2„„ !4åËMa¢ƒ¶mÃàÖ-X[›VJŒmúÚH¡@L \\˜SJ;€Þ½¡ÕâÖ-¬XQše?f œœoZæ4kþ|ìÚ…‡ѪBC.cÇ‚ÇÃåËàp°e œa0à·ß°u+._ÆâÅ¥E¼;w6Ó-cÐ ˆDˆ-}·&êŸÀÀ@‡#œ+Ù•Rg©Tøì3„…™âÂ!Cpé’©©ý¾} Â/¿˜>ø …øùgüôSiþŸ@€Ÿ~ÂؽÛ¶UvsC«-ÝWSTTÚä)7QQ8xB! ßÜ«$ˆªyxàèQèõ¨üæÇ“'6O"ˆÚ©Î£<† 1s02‘‘UuÄ¢|•Poo|þ¹™ç:;ã‹/Ê´´,í„Q™ÌL‡Œñã`äÈÒ#…€¬XQ~d—.fÎ)V}]¢®ãñx<³ ¤ë ¹·n¡ |ƒééxôÈ´®U+Ð4zö4£Æ}ueK!…àp^~¡("nnÈRQúvÅÂ… ÅÖ­ 23À`À²eøåôï_í“#ˆWPçƒÑç‘—‡‰ŸÊõ òe¯ÿBÏsƒôÞ=L™òÔ‘™3Éâ•äää<~üØÇÇǦž†K<úô1Õ—:Mš”®}¾väòÒ}¨3Ã4š75‚¨È;ðñÁ¦M¾×PƇ‡éuBÔ1 "•HðãO¥ò¼¡nïåj›Õ¸qùjSÉ™ ѨTªÛ·o'%%EEEµhÑ¢WÉÖzD$B@1q"ØlÜ¿pâ:vľ}UœËEr²™¬Ä²df"'…S§žºÁ~æÏ¤»;ví‚Rù\Evâu¹qÁÁ ¬lŒƒƨQÕ5'‚xD0JÓO%¶¿9ÏÓ œË­¬ÚA¼¹\~îܹ¢¢"š¦}||jz:oŸÅ‹1ozõ‡šÆªUðò‚˜1B!,-agÇŽaéRäåA©Dûö8Ó¦@x8œœÐ¯$üý·ù«¸¹!<;ÂÁvv MÇ­¬Ì|víÛ»w£W/tíŠO>yC¯› ÊÓjŸ«¨‹±ºŸ\nªAµ_ƒF ¢¾R«Õ€T*utt¬éé¼)Mš`Ç€…¤RP&NDŸ>Ðh “A©€¶mŸªÂXòNlm;«H?âr±y322`a S‚McÉ3Á¨­-öíCa᛺ÇBåèõ8y—.=מ.Š‚£#Ö¯GÏžð÷ó“#ˆWVÁè±c0ТizK¯J©Tj4{{û¶mÛŠêõ2ˆX\Z³ÂˆÍ6å¦|&ci–HdŠMu:> …¢ô[èÐÁü%X[WqB‚¨:vîD›6ÏÕZŒ¦±nþüVV$%ê†F££±k‚ƒñý÷UÔ§ ¢rŽŽŽäóù^^^5=—ºÁX*??¿ôˆJUs³!ˆçÃãaãÆÿÎ;xç76‚xÝj :žžøòK(•di ^‰P( 0æòχ˭¢UAQÍjfÏhEw¾‚x!ׯ_§(Êßß_@òº ‚ ˆº©f‚QšFq1)ÔG¯D¥R]¹r%''ÇÎÎÎÅÅ¥¦§CA/ƒ®‘«úú‚ÍFÿþ8r¤F®OõAjjjnn.EQìg+aÖS >øgΘù–R‰ÈHtè€V­pëVç1˜hJÏÒÒÐ¥ Ú·G·nOU8&‚ žU3Áhn. 1p`…]ã ‚¨R||¼V«åñxÜÓˆÚ`@r2är3ßâóñùçX³€©ÒS%K–˜j_ [[lÞŒ/¿D|< †7u‚ ˆú¡:ThšÏ0¬²‘32`m÷ß7SH… ^+!PüìQµ4-¦¨šù0öºøúúÞ¸qƒÏçsž§ÝB]¦Õ⯿píüü V›Êå8t pqAŸ>°´„£#Äâò½'/âÒ%°ÙèÛžžHNÆùó¸––P©àà€°0HMÅþý(.Fp0ºu3?ƒG"<B!22pãzö€ÌLDEÁ`ÀÕ«‹1z4ÜÜÈš(AÄs©Ž7c6[FÓve×*´ZÐôsu’ ˆWc>JS(ÀçûSTÝ^P”H$Íš5óóóã×ëÚëÖ­Ã_@&ÃÑ£¸pÔj̘͛ÁåbÇ|þy…Oß½‘‘P«‘œŒÁƒQP€¼<\¿Ž¼<ÄÆâÚ5DG@r2ºwÇ£G`³ññÇøçŸ '3}:23àÎLŸn:~çÄ¢EÈÍÅÑ£ÈÎ~?‚ ˆú­z¶šQÁÅŌ렱±8s)2JÔ˜âbXX4£¨º½ÕR,wéÒ¥¦gñÆbëVÌœ‰1c’‚k×àþ}<ˆƒá鉶m1d/6s§E©ÄO?aôhŒ• ׯãÄ ¼÷¾ü‰‰ˆˆ@D„iäöíJññÇ`±@Qض Ý»¿Ø<µZìÙGG(•h0û&‚ ^ƒjz3‰ZÉå» EaÃû 4 ¯z®Låed€Ín)¶ªé‰¼¼ÄÄÄ+W®¤¦¦º¹¹Õû`”Ã@€¬,ÐéL-æ!bÍSäGÓÉJŸÂ0¦/X,H$˜9ÓÔð€¥¥é ƒ¡tû)MÃÑ¡¡XµÊt¤’?P4œxz–O“2{«§d&ADEª)ƒÇórrú,1‘£Ñ@ ‘(Qc ddÝܾg±êjöœÁ`ˆŠŠÒëõEEE›6mЉ‰©é½Y––ÇÏ?ãÊlÚ„øxxë-4j„õë‘’‚»wñÛo iàráæ†­[qþz=23‘™)•ɦ98Ì©© »¯…@ 4hPVVÖ±cÇX,–……EMÏèstÄêÕÆ´3”ÄÞaõjS¶PÙ­ žžøòËÒ‡b1fÎÄÔ©ÐëŸÚ§î₯¿.}HQèÙÝ»C¡€HTÙdZ´Àž=ÐëŸÚ„  3ƒ»tAÈ1#‚x%պیñ÷ðX—×%9y~VVœP¡<I«'Þ­V§VC.Gq1hº¥—×·"ÑÛU·áhš–J¥¶¶¶\.·~×u*AQfbDŠÂs†âNùú£fÑ´é*¾ÿçΕ~‹Åž=¦¯I²½Z+Ö»¡¶mûòEL—.E»v°²ªbX^._Æ–- }É AT‚£Qg°Ùl;;;ã×*• €D"©Ñ½*š†½}Õ±Ôš5xüOž ;Ç#2nÜÀâÅP( “áóÏáí•+qñ"1iÄbÌž-—‡•+qù2h£GcèPxø‹¡° ƒY³Ð³§ùënߎ¨(Ü¿œ¼û.fÏ€›7±hÔjˆDX±á§Ÿpæ   ŠÂ”)èÐøá\¼†ÁС=…ØXÌ›‡¢"èt?Þ4™g©ÕXº/‚¦Ñ´)–-—‹˜|ý5’’ à³Ïlþ¹r9~ùÇŽ¦ñî»?T*l܈ƒ¡×# Ë—cËœ9ƒŒ |ðD"Œ‡îÝ+üùët akKŠCñF`” ê½^Ï*³×¹sç–-[ÚVÔ)¨îàp”î©Âõå\»†+Wðë¯xò}„þýÁçcöl„„`üx¬Xùó±o @«V¸wS¦ÀÁ^^Ðëñí·¸v +W";|€ÐPxyá»ïШF‚\^ÙuïÞÅ`Çdgcð`Œ‘S§¢ukLš„Õ«1~'bâD´lYá°=77p¹HL„L†{÷°~=7ÆÄ‰è×¹¹ðñLAApq€âb:„^½˜½––¸t ÞÞàóqáš4A@+›^ÏžhÞ:¤Rää@¥ÂÕ«øõW4nŒqã• ¦4$¤´AÔÎx÷]$%€£#Nž„·7„B\½Šà`4iRÙ‹¥i¤¦âÈ´iƒfÍÀfãêUDE!2ÃÞ7o"?ß|0ºcZ¶DZX[ãòe´j…ýû1p ÂÃAQ0&¼çÌã!0>>•ýŽÇÆÉPÇWá ‚¨½H0Ju@zzúÇE"QHHH=k¹Ä0P© B«­l˜± ªñ6±N‡¼< ÀÖ:”J3ÏÒëQT„ØX@h(\]AÓX°6`ëVÄÆ"2sçVxÝ’ ZÆUé¢"0 ll@,à /ŽŽfž˜•…ØXÓ¬‚‚àäÀtÝíÛñø1ÆŒÁ'Ÿ”¯eµno¿Åر¶¶8p……`±pþ¼©ìÀðá.Ufe!#ÿþ ¦Ð³¨öö/y“Ýx!†!÷è ‚xSH0JuÀãÇÕjuÓ¦MKr¹<99Y"‘888PuæÌÁ¯¿bëVÌk¾¦•Fƒþý„#!îîðÁ€¢"S €ÇCÙš þþhÝs怦¡R™"Hoo\¼ˆqãÀá@¡xª s%»Œºw‡Ÿ @AAÕ©NA/áåƒÑ¨¨¨¶mÛÖõ7B‚('33³¦§PžÁ`(,,äóù~~~Æq™™™»wïöññZQ LÝ¡ÕÂÉéÅ"QÖÖ0}„nÝðçŸ?ÞÕñxðò”)Æûï#0³faÁÄǃÅÂÝ»X·¶¶X¸EEÀÁƒ•%î<‹ÇÃøñ˜9b×.̘Qº´Ùµ+FŽDóæ2-[báBL›†¸8…8{7ÂË 3g‚¦ˆ¿þBûönW=së×#$))xë-¸¸ÀÒC†`Ü8ôì‰ìläçcíZÓmúþýñå—8}ï¿Ì™ƒ?Df&,-qî–/GH&NÄØ±˜=..¸«V™ÂÊ–-1c‚ƒ1hÚ´©ðUóù`±ª»pA ÇË£ÅÅÅ×®]{S!Â,Š¢zôèѦM©TjÞü­ê²&N„@b1¾û>>àp°t)þùOž`Étíj)`Ó&\»¹R)( }úÀÓ/B¥Â¼yÉÀbaüx?¥óç£]» ¯;t¨)^d±ðý÷°³EaÙ2üó>Ä’%èÖ­tð–-¸qyyÉ [7ìÞK— P`Ñ"8;ÀŒ8˜?mÛVøÂ[·FAâãѺ5>ýÔ8~ñÎÃíÛ°³Cx8J6kŒ‡Ö­oÚ<Ð¥ vìÀ¥K(*‚ð÷€æÍ±oΜAf&F.­{õã¸u ÙÙ¨<ŽÃ\ޏ8ØÚ–®ÈA¼./Œ6oÞüüùóò1™¨¿J*(Õ<¯ì” ëx\ Ñ`Å \¸€Q£ªY’ëÃã¡W/Ó×R)† 13ØÎ®t šFP‚‚žÓ¤ š4©z†%Ï2¦Ÿ …èßßÌ`[Ûò‹¬ÁÁå 0•;¢T")é©GggˆDæ_Ÿ.]Ð¥KùãBCK+€R”ùWçí oïòe23'|–TŠAƒ°d FŽÄرU'‚x!/ŒŠÅâ-Z¼ö©ñ,†aÐO¯¡yxxtèÐÁµdbÝÄåbæLÌœiZÒk€âã±páS©HŒÖ­knB (,X€ ÌçïA¼"’ÀDµZBBÂÙ³gƒ‚‚š6mZrSÞÍÍÍ­òÊuE¡–-@W7__lÙòÔÊh­öØlSA‚ ˆ×Ž£Q«Ý¿?..ÎÙÙ¹No%Ìb±`iYÓ“ ‚¨iU%Qs E||<—Ëõ7æ¡ôz}^^ž\.'û¶ ‚ ˆz€¬ŒDí%—Ëy<ž³³³M™m•{öìáóùu=‡éua ìÜbÏüb¹wÂM®ªó]R‰²Ø´F,HµÅÙˆK,’ÄüôªŸCDÝA‚Q‚¨½ìì솮ÑhxÆDµZŸŸ/•J˶ªoÈ ®×âÇ%çµÓAÆárÙ‹Gþ²Õ+ Ú„ £SZ°šºokäp”M«kz^A¼äO6AÔjOgµ¨T*F#¸f»÷4$+.«ý•Ø)jø ¥–,6 ;kë'.ÀÀ0j•õÅX—Ô¼f¡ž›$I5=/‚ ^²g” j)•Je¬ëT‡Ãquuuqq¡«,_ÏQ±™N?\là7K­Yl‰Dë=Цùbk礢'î¦ÔX×ôŒ‚x ø›AÔRƒáرc;wîÌÎÎ.÷-—÷ß?,,¬F&V{*¯ÄMâ‹øBRj Aa±Ùb‰4OÝüVÂpÆ@6«DG‚Q‚¨ bbb’““Í~—¦ivE}Í=ù?^ƒÆ| AMÏ…¨M‹,­eôOÉ ­z4Aµ F ¢6JHHËåNNNVÆÆäÄÓŠTq™=„+rk¾Ábs¹,¾ãýä÷jz"A¼*ŒDm¤R©¤R©¿¿¹PƒÁð×_íÞ½ÛØž¾ÁÊ,lB±-H=ŽËãç+Ÿ/•JŸ]4m8ô G¡‘Ñl6 0ó?s†IxøàþµK[W|‘ú$î%.Ê0ÌŽU_¿Ò¼Ÿ–ýàü‘¿^º§ë…#£>{¼¸¨`÷Ï+•ŠâW›]ícî¿5 `‘„z‚¨ëîâ AÔNÙÙÙpuuíܹó³eí­­­‡j0r0 À``1®þÿW@µunF:EQO`ê (*,ÊÏJ$"K ›Ã‰˜2S¥P<ºu½Ü©´u~v6MSÖvÔÿ—nÕëtùÙY:­ÖJfËÔJ…Z©Ü¿~uŸ1„BËüO…¼ˆËãåef°8\k;{Ól&'#]¯ÓZÛ;p¸<Å…q÷î\;uì­ÖíØl¶…H Š ”Ë ós-Db±•´¢×ÎèõÊbyïÑ‘åÖwó³2Õ*å þ ëh½Áü/<ÃH” ê<ŒDퟖ–&“ÉÌÞˆg³ÙRi…aJÔ“ž¶ùË…*…€½‹käâsýÔ·¬ãòµjØÌy¾ÍÌÊLIúß7KTÅÅZµ:èíð“>P˜›ó¿o–ægg2 ãäá5îÓ¥ÿìü߽ˆY=†Î˜çîëoö„«>š& •ÅÅ9éÃfÎkÞÉÀ0ÿûviô­l6ÛÒÚfâ_‹,%¿,œ“•œ”Ÿ“õÓü™ÙÄÅ_±9Ü›gOüu=‡ÃU ˜øAp»f/‘žødû+r3Ó#&ÏlÞÉxðÔŸ{Žþþ«P"a±Ø•êÕªAÕ†£Q‹èõú¨¨(¾¾¾ ¾ÁÒóº}þTQ~އ߯3 ò‚|9Ù›—-:s^Ó¶í¯;ò¿¯—,Ûñç³OÔëu;W}m![°´¸0ù¤Q­ºötöôÞ¿á県´éË h:+%‰¢¨öý"B;v»yöäØO¾(©]E“I‰{ܶgßÞ£&ü³óÿîú­Y»n_?}`ï¢Í;Dé×ÓÆþ·w{¿1“F}´èúéã·ÏŸ5o›Ãe±9Eùyë?Ÿ?pÊÌ–{Ü<{rïÚU-Z{`–cëìúþG ×>ßøbäf¤í\õõ°™7mÛþ¯-kÝM?Z‚ ˆê@‚Q‚¨E4Á`puu5;àÑ£Gyyy~~~¤þh ™£sfrâÎÕßø·k úÖÂüܤÇÑɱ1j¥"1桼 _$)ÿÓi´÷®\x«UÛ£Û5 /%.ÆÁÝ#êêÅÞ£&XÛ;ÚÚXËD–V(ûg†žõv¯¾b©uãà›gO€è›×Ý}ýÜùÑ,VHÇ®¯_í3*ÒÎÅUb#ã ö.n4‹àÉèâ‚üԸ؃Iëõ:í“÷´Ù`”ÃåÚ¹¸òø¥ßJzÍæp›‡wYYµéÞûê‰_á›J•¥ IDATÇIQÝH0Jµˆ@ èÛ·oqq±P(4;àÎ;QQQVVV$-تí_ÿtçâÙã{~?±oǢͻôzPliïâf0náR³u  ƒV­¶uvµurÐgÌ$¿@ U«ÙÎKÏÇAÒÔÿo?Õë¸| ã–P‡«Q›¿‡®U«-Ä–¶.®l6À˜ù_” 7«Äáò(š@³Xi@DB‚Q‚¨](ЉD}·°°¢(KKRå»TQA¾[#߀ÐVmº¿³tÂp…¼ÈÙÓÇÀ¼›zøè´š‚œlcV͢ũ£'6n>tÆÜ-Ë?{|ï¶^§SÈ §/_%µ³8eæÚ…}?{‡Ëã “¾øMÓ­ºöüù“Ùb+«Sg»76ŸÀd!7ûÒl¶@(дm¸‹wão¦çYXd§¥Žýt©ñ¿oãà­ZõݬIÖöŽã|áäéÝgÔ„K8yzË ò%6² ‹–›]Ð=°ñ—˜;7cæçd]>vä‘ãüC[vè7pýç»x5JON”ùzpãÊõSÇûOœþf~öA¯ÁË£wîÜ6lXoC4ûöí ©žk]¹råîÝ»:t 4;€Ãá¼óÎ;r¹œ¬Œ–Õ²KOgïÆ¥’/º5ò5nÁ|wÂ´ÐŽÝ r²¹|¾“‡—q$EQ=‡j¦Óhl]\ø5o1wõÆÌ”$FÏȬd¶\}|çý¼%5!N«V—¬ƒR4=éó¯3““ôz]%‹£|ý£q³©§“± –Ð4Íåñg·&!ú!£×;yzYÛ9GZÉllØ–“žÎæ°Yl6€¾c'…vê–›™ÁárÝ=9\ó[ÚtïÝ´mxÉC['Š¢Mû°eçîj•ÒÖÙU§ÑXˆM¿!qQwÂz¿'“_‚ j¯— F•Jebb"MÓ2™¬¢%‚¨ë2335Zm¦ÇÏ› V«år¹ÞÞÞdïQ_ñ_$—ùÕñx|øM_èµ+..Þµk׎; +éêêhkk[=#‚ ˆj@nÓ¥~øá??¿=z<ÿS¸\îÈ‘#;wîlö»,kÈ!›7oÎËË3;À`0|ýõ×-[¶ìرãË̸ŒÖ­[oÛ¶-99ùÏSýsrrž§º~«V­Zµzdj¢úÅ?ˆ…q÷ïòø‚&-Ûð-„Œ^Ÿú$öÉÃûƒÁÃ/ÀÅ»1EQ1wnªÅŒ^/‰ò³²‚ÛuàòùzöÉÃûi ñ6N>M9ÕÕm ¢f‘`´žÓét©©©|>ŸÃádddÈd2™LfüVqqqjj*MÓNNN °°ðòåË& ÀÚÚZ$©Õꤤ$ƒÁàââ"Ê™a˜¤¤$µZmggWöxVVVvv¶X,vqq¡(ÊÅÅ¥ì>H¹\ž’’ÂápÜÝÝY,V~~þ•+W,,,¼½½mll„B¡J¥JJJàææölpVTT”žžÀÑѱ$£¼°°055U"‘”IJJb±X‰$))I(gòÚ~¦¯Û£Gôz½ŸŸ_µµz"Þœ•3#ÅRk¿f-nœù¯Ã»ƒÞ›05?'{ã’nž<¾`×êo§.ûÎ?´ÕgïG¼Ý³Ïµ“LJd&'iÔêvïôÛµzåÍs'›„¶9üÛ¦ÐNÝÞ?•&õA ‚hH0ZÏeggOžŸÏ§(êÇ”J¥%§eæ÷ßß°aƒŸŸ_Ù^\Ç_¾|¹ñü#FŒ>|xÙɤ¤¤LžŸéææÆ0Ltt´OÙip8œwÞy§oß¾ƒ!!!¡Üwp¹Ü6mÚ¯’™™Y® æîÝ»·mÛöÏ?ÿXYY£dãEKö ”­¯Õj/óÕomß¿ÿÖ­[f;$éõz…B¡Ñh†áp8‰äyv(•Ê¢¢"‰Dò<»E³³³ØØ”o˜NÔrl6›Ñëò¢Ô'qçôiiv˜»_‡Ç‹½w»YXGZýäÁ={WwA4ä/]=§ÓérrrÔjuVVVaaaqqqQQÃ0Ý»wÿóÏ?ÓÓÓ?~üßÿõéÓ€µµullìÕ«W¿úê«^½zݼy“ÃáX[[ïØ±#::Z$µlÙ²eË–5òõõuppØ»wo^^Þž={†IMMµ²²jÓ¦ÍÕ«WmmmÕjõÒ¥K-,,²²²ôz}NNEQ]ºt¹té’µµµX,þê«¯ŠŠŠ(Š …±±±'Ožüæ›oz÷î}åÊ¡P(•J×®]kÌU:{öìo¿ýÀ`0°Ùl¡Ph0’’’Œ/§K—.{÷îMOO?þ|^^ž±§J¥:tèP^^Þþýû}}}]\\^åǨV«Ï;wéÒ%†a†),,4®1äääüþûï›7oÞ´iÓ±cÇJbú'N8pàØ±c111ÏvWzðàÁæÍ›O:e0ªœEQ666%ùgDíäÞØŸÃåˆD.Þ>ðvϾ¡hÝgóv®úºéÛá®îàÕ$ˆ¦i'/¡¥¥•­ÌÑYl%öå÷WÿûgígóÖ}6/õI\M¿‚ ˆjBVFë¹ìììÝ»wX¿~½¯¯onnnqqñ7"##ÓÓÓ§NÊ0LçÎß{ï=ýúõ[¼xñãLJÚ³gϨ¨¨éÓ§K$OOÏAƒ•=­µµõêÕ«W¬XqôèQOOO??¿… nÚ´iåÊ•Ÿ~úé½{÷ôzýòå˹\îºuëwîÜ6wîÜyóæM›6¦éAƒïª2dÉ’%W¯^0aB÷îݿ䜿þúk¹ƒ <ï›o¾).. …e¿„ÂÂBã‚(µZ}öìY½^/Ê‘VVVÆ ãp8|>¿ì–Á^½zfdd0 SrÿìÙ³>>>©©©"‘ÈËËëy¦AÓ´l"¬›hš[Y?ÏHЦÅVÒªÇAÔ#$m¸(Šz6Ê,—rn\É«HÙ˜²›Í®äV2EQÖÖåß•ÅbqÙ‡åÚ]““Jš=y¹ƒ‹/Öét .üòË/_})ñâÅ‹e{#ét:77·=zÈd2.—k}îß¿óæM™LÖ­[·çI¥ÏÌ̼xñ¢‡‡GPPP­-˜JA/¡&ƒQ­A¯OÒ%å09é†t9%ž4‚¨š«éÿ)%Å5pm)[[ÚÖžeߘÛXL¿À2$EQQQQ%eJhµÚ'N899™] ­òœ2™,<<<((È`073h4šøúúV´£ 33óæÍ›z½¾¤TAAÔ5Œæès.¨.œcÎÝåÜMà$äÑylšóÌ âåP ø¾cå¬wöÖz·Ñ´i/hïÅñ¢Ÿ¯Ž„››[qq1—Ë¥(ŠÇãq¹\'‹%‰T*-I™ ©©©§¤©UTTÔßÿýðáÃîÝ»›-eJê:½.ƒ¡(?W§ÕZˆÄ¤¿ADmP3Áè̓“ª“Ç9ÇONÐƃV°’C^#ó!ê±"ª(‹ÎŠaǜ㻧¹—ªLm§k×–ß–Kq«|®““S£Füýý¥R©H$B¡ðÕ;Èëõú#GŽäää 2ĸ©ÔÒÒR,?xð °°0""¢lçU#¥RÉårßPÉýåæÙ“¬_Í·v8¼Uמ5=òÒ,D"Kkò©ƒ ˆ¤‚Ñt]ú1ձ͂Íw9w~wD5ÑAw™{9–›[œ+T [ð[P¨bóåÅ‹¿ýöÛÖ­[¿Þ™dfffgg[XX”äry{{<ØØÕlƒ¥·ß~»I“&쩀 aôúÓímÙ¹{‡~kç²è¦eŸ6ëØsÄØšžADõ©î`TcМRž:Ì=L"Q¢FdÓÙXüá"wqa»8±_&éÕÅÄÄ(•Ê€€€²¥š¬ÓéÌîC•H$/±?•(ëÁµË—ŽŽ‹º«*.ÎÍHoѹ{“m sæà"‰Õͳ'r2ÒC;tí14+5ùÏMk órí]Üzš`imsöà©ñ±i ñ¾Í[<¸~¥Ûàoµn§V)Ïÿýçýk—(Šê1̯y ³×MKˆ¿rü¨F­J~íìåóÞ„iO£VÛµ-úÖu._ÐmÈHŸ·‚£œþsoJlŒF¥ÊHNtoìßþÝ4M?¼qõüá? ór[½Ý¡ß@§ÓiÏüµïîÅszηYh÷¡£Ø¤ú,AuYuw`º­¾}WÎòÎ’H”¨)‰¬ÄyÿžQžÑt52ooï·Þz«\^¼H$*¹Ÿœœœ””DRú^#k{ÿV–RWŸÆ-ZÛØ;0 ×NÛ´ìSçV{æåêuºµ‹æªÅ]"†>¾{sÛÊenœ=Q›CQÔ‰};}ƒCvþø €#Û6ù}K»wÞ lÕvÕÜé9Ùf¯›“ž¶kõ·,»Ó€!Ç÷î¸wå€ûvù}Kxß6ŽŽ?Ì™Z”Ÿ'–Úø‡´I¬Ý<Z´vñiLQTbôÃçNwòôîÔð©{.?àÁµËGÿµ}ß]à[X_‚ êºê^ÑÆüÇÿOA)ªùºQÖiÞévêvL «6ç9;;;;;W2 33sÏž=E <ØÑѱ   ..ÎÑÑÑÁÁ¡Ú&YÿØ»ºË/ùËç­f-;÷(ý†mº÷~oÂT㣜ô´ûW/}ð„ƒ›Íb­˜:vòÒo)P-Z«Šå,'¤C—£Û5 ÿîü­Û÷­d¶V2[‰ìÁõ+­»õ2{i‰¬ÏèHôvXvZ €ËÇŽtŽÒ¡Kp»§öï¹õRën½¬;wÿw÷6w_ÿ’é;|ÀÖÉ¥qp‹ÅnÞéòñ#mº÷V+•j•R¥Tzøyú6åp«ÞýLQ›Uk0ª0(ò˜¼DVbu^” ž¥¦Ô)¬”L}f£U’H$...÷ïß?|øpDDDRRÒŸþX¶VƒÇ¼®AЦ½Þ*y¨°sq`ek§Q«”rSb%‹Í¡Ë…ÍJK¹}þtô­ë¬míE’ Óˬÿ½û“ª¼8þ™Ù¾Ë.,m)KGª€"ˆ±÷Ž¿Ø5Æk¢QSŒ1ÑăÆh4¶¨±ÅAÅ "ÒwY¶°mf~ì,°K‡¼ß‡‡çÎ;o9÷ÎìÜsÏ{JNË„ÄD$&Vï§ä-ËnÚ ‰‰™Y+ó—×:pé‚ùùK?û—{ª^¶êÐ1î¹ßýüC÷––wÝ»ßy7þ*9e«jŒíÒĈł̻»6;TÍä//XZµ# ¨•y óGw×}G.ZVVöÝwßåää4jÔh¹ëSRRFŒQPP°|ùòüüü ¯Ó:$&”e¥Í_ZQa«3 ¯Q135…B ç|׺cç¥óç¥7ÈLϬ½Y‹6íFžræ€CG¤²r³Šd7m¾tá±XEEÅÊy›WÛ¼Ãᄚ)ÃZwìF/ûÍŸª”àÊŠòĤäP…ã~rù˜±—Ìšúå¯Î?õ”˯ýÑ*£±h4¬41¡¼¾ Ø*v¨2Z-\’°$#”‘&^Cr6:V.øA©oŠˆ±Ñ¬ðäÓ|ëÖú;錩í­O?aðÆæÙ˜Ì™2ÔRâ¨(¡¨ ¢ *º‰9G· ,xöÙgsssO:é¤ §ˆÊÊÊ:ꨣJKKÛ¶m;iÒ$ëUIý1U6n0û‡ÅåiÛ! >+»qßÁÃÿݯ:rÌKã<úøZ»…B¡#ÏûÌŸï.),LHLœ<þýS®¸¶ÊuS8è¨cŸùóÝš6ŸýõW ²ºîµOU{ç^}&¼þr$iÕ¾ã>ƒ‡xøÑwþä¬Þû»öÝz~÷õ”=öÜĨ‰o¿9㋉{ôé»pÎì&-[ý˜·é£ÑHR(/#eI} °UìPe´âNàu~W7¿æM–òßázÔ¡ŒVðŸQÊ#$Ó‰F<ÅõÉxöã>µÛ?e #ã“\FŒ§¸ƒáLç ­cìlŽc2¹–ÿ’À_™A%å4g(Q.g:½ù€ë8±Ž w8ápxèС‹/^mòÜ ÿõ¯4lذU«úIŒº’ž¼|ŸöòÝÏ“[ÖZ& `·§lUIZèëž¹ÏÖ· [Ký)£•ü›‹hÁU¬¤qü­ þICV0‡Çyœ½˜ÎXίÍfædîâ òù˜«Èã1~ÏѼÀÍœº9~È`®¡±'EmÂó4e˸ŸÛÎ7\Ä<Ú¯7$‘S¸‚…D™ÀXÆ£\Å™¼Ãùœ¿iÒ&r YÉóŒâЀ?PF1Ù<Î  %£ŒÃ™Â0^ävЏ½îUR¹›Å‹ñÆUÜÇ•\Æ å§tZol”ûÎC”²?¨äjng ÅìËìÚÆâ:ò¸œq\ÇóëÉ<ž—ø€¼ÅoÃÎáS—””Ô£G=zlÖ¨ää䌌Œ… ~ôÑGG}tBÂNcé­WB¡h÷Öÿž·|¿¥#l0,`·¤²¢¢¬hñA]ÎJû¡¾e ØZêOÆlZÎ|Á°ø[C⸘H ¿&™Jò¨kCf(7ñ³èJ7¾­± ߉BuxÖÁh®ç}öàgì½ÁÎÑ4e&‹yˆÇ©¤„•uŒÚ—†¼O%™ôg ÅñÝÿ¤°”MŒ¢ÞGø˜ËIa§SȵL'•Â[d÷ IDATV‡w¥j{³›6]T°€~`1¯6…2 NÉñÏe?ðO^$F*?Ô¡Œ~Ig‚ïI'V›Éó b\MˆRJ7áAbçföìÙ³fÍ …B³fÍZ¶lYNNN}K´³.=`{^ÿªea^ÏŒ† ƒ*D? b±XÙªUeE‹»ä<Û¾Ù{õ-N@@À6 þ”Ñ7ˆqU\Š×98®[Ô fJ£ WÕ°›Öu/nÎ1ŒcN T%’ª$‰DÂ54˜Ê ÚÌF±/_ò0×ð(«nåqe®Ššæªšq UyÍÃt¬c‰ÆÉ#¤p< È#Qu^²¸Øª’邺nG:p$Ï‘OWÞâ ^£÷³=v´B¤R Ê)¡Öàœ¬±xÿ$Õ¸VÖ¾V‘Ç©ŒŒë²hTãs¬©L7¤7į[ÒÎbýá‡V¬XÑ¡C‡´´Z½žëdùòå±X¬}ûöp@Ó¦M·“x»(2æ±×åŸÍ9{Ö’Q)Í“SSCáP8ÞY<3¶±X,F++W¦š>pG:6;!¼•OÒ;õ¤ŒÆxƒ ¹÷ó7Ô°Û­¦i|ÉhJù”Nu«Çs8 ¨Š(hG;å2þIKš¡”i,âFÔ-äË´¥ò2!²XÎDry‡£ëØ6|Æž”2•uôıÜO¿MéÀÓtàYÑ‘BÊ™HGÞ`¯:¦jDS>ç Ρ­âsSyŒ §ÂÉd<ÓÉ®[éG b|HrHc?ž /Ò°Ž˜°FÆý–óû’ÅpþÃÕDx‡ÕÙÇ;óƒiLCŽå/œNcfÔÐw›ófЀV äæ²/+˜Íf mG>þøãÉ“'uÔQ}ûöݬùùùèÝ»÷f…=ýxhºxP×ß¶Îþlêü1E­*cÙQY I;Ç#HÀ6"F#«¬H/ï”ýYŸvÿÈJ[PßBl3êI]BGÅíƒyŒedÑzíŒ?y_ñ2% dtÝÓö¡{Ræ‘ʯ¹ž“Hçv’Á(®£)]7¨rMæv²)çFÒèÄñÜH ºÑ,Þ³ùÚ–Ñl~Ímñý÷þTy;ћ̸ΔÎÍñ°›nË| 7Ђ=âÖ'•äЗAqã``,aö¡$.a•%2DÄg8†Ï¸ˆžü±n™[ñ3~Iˆß±'¿àBN"½udý q6_p.aÑ„îã*Î¥œÖœï?–+8›³8‹3Èã'dRÉÝñnGñ!—Ò˜ÇiÏCüš)áôÂF¶råÊ9s椤¤´iÓfsǶjÕª¨¨¨eËMM`ù#$ŠtÎy³sÎKʳW®j]PÒ¦¤,0!ïV$„货 uQVú‚ v> `÷£ž”Ñœµ³Tvg|üø®õ:ïÃs›0g3YÆi5TÃýy4ŽŸk"w²‚;ûë¹~í–náR2ã»ÀU\¾Þؾ›,ówüÀ/¬É¼Þ×ȧa|•D®â|Ò6¶é|IüàÁøAþ¼^·ã¨ª+™ÂŸj´çò·M;‰k¸¦FKþÃ®í½°xl½Æöü«¶Î-x²ÆËd®æêõº5çѵ[‰›Æw,XPTTÔ®]»Fê¬YýúõëׯJJJ¦M›–œœÜ«W¯ŽúQKOÎKOÎkÑð«ú–$ `3¨×ÔNÛ–ó;†ÓíöäÚ¢ï7[%¨AãwÙTþÍÝôbèÚí ñp¨šìä™­C43ÿ¸ÉÍÍ9rdvvvRÒ–Ù,Z´èµ×^kÖ¬Ù{쑺9É5vfv#et=Øc—:§At£Ó­‰»>™™™ýû÷ßx¿õˆD"åååÉÉÉ -Z´hذá²eËòóóƒ]û€€€€€Ý†Ý(YtsºïRš(šÓ3ÐDêä»ï¾7nÜ„ žžž››‰D–,ÙM*qÇbŠŠ¬ZµCÊÊm7êƒÝH ØùˆÅbŸ|òɬY³"‘ÈÆ{¯Ç?ü°hÑ¢²²êˆœxâ‰íÛ·ß–"Öee~ùK'Ÿì?ÿÙ¤þÿý¯OtË-ÛWª€€€€€ÌN¦Œlf^ú€€›åË—¿ûî»/¼ðBqqñ _±b6¬önÙ²e—.]V¿ÜÕINvÁúöõ—õËÛ®GE…л· .Øþ’ì@êU-åíµ+*Ý·iÑÜ[I9Å“m.1VðK·giŸòCüâTò c9ƒqñ”ø»³fÍZµjUnnnFƆS¼ÖN$ÉÊÊÚ¬Zö»á°Nì·ŸòMøJG"*+í¿¿=öØþ’ì@êÕÅrÇñu’K…„ˆÕ¨<´MX§nä ®àïu”Ü•<Ãc”PÁ%œ´ÒX~ͯ˜G„½¹¦/®£%‡nëE¶³gÏFÏž=·¬¦üèÑ£‹‹‹Wmª¬¬ÌÏÏ///oÙ²e8¼“mkl)¡•+Åb6\^>SY¹£d ØÔŸ2ú$ŸPÊohÀ˜xa¡Y\Å\Î`añóiÌÿÑ®Ž ßã¾e £8†0sx€Å4á2ry‰÷˜ÇÈæ$zPÆ‹¼MŒÑŒ¨Ãdü.ðkzñ¿bS˜Á<–r§“À»ô7î`ðsfÔ6„û¸œ Æò8y,çmn£ûs³Á öåTR¸Œ•¼Â—¤ó½¸‡•üƒ›9ˆ!ü’/yvÍ/¹Œ>'‰ J¹0ƒ·é°=iѢŀ6·}]$'''&&VTTlY8ÔÎINŽ-\yå†Â˜ÆwÕUÂá`> `7¤þ”у8†dŽå´xíJŒäDÆRA_ð5çÓž1|Îòºç<¤ÆØ•Ìa"×r(×0‘…ì˱4åhN£-þÊqôe y«¶É—RF'~ÉHưZ8˜3C"‹À d2‘,¢*O7ö£G‘ÀBžàhúӟμÍdFð(¥ü”$V'²yžðWÚnÝ•ØE˜?þË/¿<}úôÕ-‘H$†B¡Ð†·´w)¦O·h‘ œvZ}FŽôî»ÒÒ|öÙ”, `‡°ó¥ålKˆ¤¸/fÅÜw!m»vøuhI˜Ôøi“¯ ŸNIVÕ¬àÞ‹·ÔºXH"«Hå²økü­ B„‰a%çS̾$Õ&p"a )àuVß_ÓYJc¾æ\öcóâï~Æ ‚J»Ë–-ûú믻víš“³…•©fÏžýé§Ÿ¦¥¥uëÖ­ª%55µ_¿~±XlwªÀTT¤S§:7èW“‘!7WEÅ‘) `R¯Êh"!6|wiB3þw-%e“çϦŒt`TyÙU-ZQ£[cÎæüø[µÚ‹³© ‘rÞ§sêXwßòOºò6¯ÔÑ-&ÎÅ„âvÖïXD^¦ïÖˆ²:‚ €c×᫯¾zï½÷ Fµe†Ìuò:!##cðàÝÍK£´Ô¦w…Bb1[” + `§¦^•Ñtã`këÓ›^\Îñ,å[~UÃÁtôf(·pcßx‘ú†4â— â0Ús¿¡‚†¼ËÕtYo¶Æ4f:?ã·”Ó;îrºMÉâ :0®nm;™ÿãçTÒŒ/8—>¼Ìo¹‘3èZC’XÅ!›vîõJeeåŒ3B¡PÏž=·xK}ÕªUIIIM›6ݶ²í<”—»÷^Ï>kSJ¥&%éÙÓ]w™3ÇUWmávõ½Mÿ7^e!Uá$Çߺœ†$ñ0Oñ MzS ª¡ö]DSÂüž¿ò'nUMæ^c1U¥O¡²”ÔZ÷;ÌO¸–_ò‰q€áqáSù?ÚÓŒ?òæq)+hÌ(Òhι4äš0І¼O=hMkžæ ~K¡ç; °Œî2,[¶¬¸¸¸iÓ¦-Z´Øxï:6lX¿~ýjÎPVVF“’’ëû/w[`ð`ýûëÓgãÃa7Ü`ÄéuýìšÔ÷-mj†Ç«q|eü çmÂTÕ8¾8~ÍOkë܉‹j¼ s0ol‰¸˜›ãáíWpp ™ÓøIüx¯x¦ªÕ?è Ή¿µ{þš›ù7MéÍ­ñö/`§¡Y³f'œpªU«¶&޾iÓ¦ë˜E?üðï¿þzàÀ{íµW]£v!ì³ÏfôOKsÐAï°kQßÊè®E˜“8†oˆÑuû¬Òð=ùAàü®JBBB›6m¶íœÑhô‡~X¾|ùî½(£›OÊöiO ¶ó*Û‡X,¶õ©—òóó,XЪU«Æñ8ó¼¼¼E‹effnÍÖ@@@@@ÀÎÆnRQ0 `çá£>úàƒŠ·.ð{Ú´iÿú׿¾øâ‹š999íÛ·ÏÌÌÜ:6BQ‘å5ò/Z´£ø.4w®¹s•—o¼sa¡¹s-\(Û^òìÌTVþxs{ÅbæÎõÃv£zk”Ñ€€mIiiéĉßyçüüü­™'//ÏÚyš6mzúé§yä‘[VæþGBy¹çžÛZÝñÿðóŸWG"Î8cÝêPï¿ïÛo·j‰ÕÜx£³ÎÒ³§iÓ6Þù±Çx ›oVZW!ºíÃøñ¾þz‡®X+o¼áª«””Ô·õAY™3Ï4p ·j­É°‹óãSFóïxý–QÎçüƒIu÷‰RD…D7mÚ7©ënôå¯ÌÝla·1å<Å_ù{<‡À¨ 8þ½PUˆkÇÚæÍ›·råÊÖ­[7kÖlkæ©Òe×Ïë”””´5ÓîºTV*(PP°–m¬¼ÜŠk4³Š ùùn¼ÑÂ…JK7bCZg,b1+W*,\Ó*/÷ÛßZÝ5µj•ûï÷ÁJK7d¨«¬TOQV¶Æ–YZ*SX¨ @4êᇽóŽÎµ&¶«Ñ£=ø šqq%%V¬X#IYÙš¯¨¨n//¯¾€EEk$‰Å)(X#gÕÊJeeÕ'UZêÑG½úªÒÒ:Í·±ØZëF"Õ=c±jñjjUW5YKžhÔÊ• 6d!îÑÃÿëƒ6éBíf¤¦zçGåÍ7ë[”€€íÀÏgt&¿ ?[åü~ÇálÀso!×sá÷T…²”2…i4æ ÖÙký#é^Ûl‹˜Í¿ÈŽ'ÿßϑ̨Í8¡Í Ê÷,⯠Ž@Œy|Ä*Š{»~À³Ç3üyûȳaþÁ[</ßµC˜;wn(êÒ¥KJʦ—g¨…~ýúµiÓfµ2ZXX˜––¶;Ýt Ü|³)SÄbößßm·‰ÅLêöÛ-Z¤I7ݤ{wwßm ¸â ™™®¸¢Î ¦S§ºóN?ü +Ë­·ÚsO~û[o¾)9YZšª²Y“'»ã¥¥®¸BóæðÕW~õ+'š=Ûk¯<Ø…Ö¾Ä3Ï(/wæ™pÉ%n¼QUHÛ‰'<ØK/)/wË-ÙŠÌÁѨÿÛ£Z¹R¯^~ñ ÙÙî¼SÆ.¹ÄªU~úS£F9òH7Þ¨¸XUeÙ3Îpê©ÂaãÆùÇ?TTØsO7߬ê»vß}òóÍœiî\ûíç´ÓÜ}·?6i’O>Ñ­›ë®³~],æ† âˆ#ࡇTT¸äO<áé§kÐÀر?\(dÖ,þ³ôtÿûŸÄD÷ݧC÷ÜãÍ7Åb:vô«_©õQ®m[#Gºÿ~C†Øº?¯]’PHr²•+ë[Ž€€íÀΡŒVÙPN”2*É$•’x…Ï Œ-ŽkE+ãõ“nìÌŠYHFüù¥„(£ŒT2‰QD)Id¦’bÞãd.Þ Tå|ËJ¾¡ äs ³Ù‹É<ÏŸI¦˜BR×6౪ƺ§‚õ·ÉV[þ²H&J!ãIg‰ñË¥€ÊøyÕE É$Æ?Žª+£d Óˆ«YV£jÕü/r3â·çÙ³­ŠïÀ|ð¢¢êã7ß´l™[n ÉȨkô&ñùç.»Ìï¯W/7ÝäpóÍŽ=ÖqÇéÐÁÿþgþüêdX'JIñ§?™4ÉÕWëÛWR’[nqûíöÜÓùçûÓŸªEúê+/½äÖ[õêeáBmÚ¸ürwÜ¡}{'œ 3Srr-’„Ã22üýïFŒP\ìᇫý’’\u•¼÷žÛnÓ¿¿æÍ­\é‰'wœÛo÷ý÷RR|ñ…'Ÿôàƒš6õí·µ(»«W9ÿ|£GûðCo4ßîHóæky3ì6Ô·2ZÂLþÁ4ã1ވףïÉ=<ÉœÂÐxûÕ¬bO°€û˜ÂÏ)'Ä n©a·[‡e\À|Zòp¼òÓù),c/þÌ'üЏ–£™Äµ|Íg¼Ã™œJñÚñÉñdõÉ„I¦Ê’õ«xšrq 3IãBæÐœY>æFVÄÅœŸa–rSˆp ·±”s˜MãéÇTò¡wÓ£¶ÙʹžcÈ2N¥j3h9G±'“ÊõeXÄ-kÀ€êÔ¤ŸnæLMšxÿ}fδ|¹Î5m*5U¯^rsëœmÒ$3fÈÉñÎ;RRLžlÙ2/¿lăÁ˜1Õ·ü† õë·ÖžxV–~ý4j¤C‡M*U+¿þµ·plM^yE³fV¬0~¼œãÇ++«6s^t‘´4/½dµ×ñyçéÞ]×®þøG&ÈÈЪ•Q£de9ùd/¿lÕªê‚Gíüó…ã?¶M›jÜXnîFÎ÷È#½ø¢ùóÍž-sÀ°ß~žxÂSOY¹Ò¢Eòòª ̹¹®½VÛ¶< ¬\éé§ ®o_ˆÐëÒÅ¡‡zäƒoRÙÝŒÝs[nqöÙÚmt—, `סþ”Ñ¥¼Â3|Ç®'“…ÌáU28Œ‡8“âN†q=)àuþÉ· ãR²Èå^º°„Ã8šº~îK¹šÁÇË\ðÒ•y¬àÎæ<^çw@/Æqq,Y,äRטü®£9·Ó»iI¯rOð(I,¢„ûHc"S9,ç§Í¼Ç5 ¦Õz§ãæòœÈkÉ8~C*—Æm„Ÿr³/·r'ÕvM¢Ì¡Ê[®¢†¶’‰ áEV’SÛØ—8„$FÂ|ŽhEÛxE«$~ÆÓœ@gNå0²hË£ôc.Ïr3¹Œ9€»ø9Ïó-Ï0…f|7TOå ^§qü‰Eü~Í¥ñúU™ÜBoJ8ž—8NÆy=þÑavÀþœ~úéûî»oúV×ö‰D"Û$º¨¬¬¬¼¼<%%%99¹¼¼|„ ‘HdÀ€YY›X wwãÐCýâ^}ÕèÚÕ /ÈË“’âûï«;Œ[§9m}òò4h`Μꗗ_.¶bÅšÚN-ZlcûStmÇñìì÷ÙòóE£fÍ‚Œ G]­Aö飢BçÎZÖ(&W¥•†ÃÒÓ…¤¥©z kÒDqñÏÑæÍ×h¢›N¯^23½ý¶/¿tÀrr¬\éœs´kç˜c,^lâÄ5îªÙÙj~—{÷öç?{úi—\¢IÏﳜ‰u_–ºÈæÚþ ë3‡¾Œãx®ä†¸RÛ"îV[uB d ‹y‚ 9”2–c¹§LGþF2ïñùŒÍIe,0‚_0ˆ!ÜËÀµíǯ²‚Óâ¼ÎïÁ|æÑ@ÓÑMo<üÆNßwºïO÷9òÞ{ï=ï¼M©ôU'+W®|ã7:wîÜ«W¯­TI?ûì³·ß~{ðàÁƒ ‡ÃýúõËÊÊÚsÏ=·fÎ]šhÔñÇ;í43f8ì0sæèÚU8ì¼ótì(UT´F¹©ŠËÙ={ª¬\3¶°Pƺuóî»Õá>}´!ãÂayy‘9¶t©XL~¾yó6Ò9;ÛwßÙ{ït[‡nÝ|ù¥k¯••Ux”’¢ À…:ç'úÍoüâÕçgŸ6L~¾ùóµk'=Ý‚–/—šjÒ$­[Û@±°„K–ˆÅlÀc99Ù±Ç7Îòåî½W(dÑ"®½Ö{xã eeuŽD dÄ 8ä³goȰݫ—!C<ø þý·DiÞ¥ùðCC†¸úêú–# `[SÊè<Âý|ʉ ˆ«;)q"…JʘËóü‡"n¦k¼êæÃ|Ycìµ$r)IÌØd1jÆÛ6Z»=&TÙ0®®Ã(¸‚©iD9˜.ëu«$_«!Yd!ÿÂq„ªu[Ä×½¦Žˆ¥å4§ÊeíTºÕ}‚ÍâÝš®]4ubqƒuÂÏjÓDkÞ*I¤€¾„éÈä:–(`<ÿd"‡Å?ÇýhÎó<Ám ô2W5fó¯òwò1{p Oq‡qmH"Âï9¯†Øæmn%…ß‘GDÙ¢²W^|¥àÂâ¢âK/½tèС¶Ž9sæ|ýõ×¥¥¥={öÜJe4//¯²²²**11q¯½öÚ=ên1/½ä‰'ìµ—9stë¦];á°Np晆 ³t©¢"ãÆAJжm]z©=œsŽÞ½k™­}{çŸï´Óv˜¥K-Yâ©§œ~º‡rÁÒÒ¼ÿ¾£‹7ÎĉæÏ÷øã>úÈÅëÒE(äÀÝu—™3í»¯ÓO¯]æý÷÷§?iÕÊ_HO_£Æ%'×¢Ò}´;îðöÛÎ;ϦÔ'žèŸÿtÁzô0}ºƒvöÙ~ýkYYn¸Á‚F¶ß~F‚”—gÊÍ›>\8¬iS—\¢sgÏ=çþûUåiHL´¾ÓÊAùÅ/,_®[7?ùIÁCÇûýïåæêÓrsµjåúëuëæ•WD£Õ' IJZë"|ö™otÀ–,‘•µ‘ è„gœáÜsMª×ö®?²“‘—ØDvOv´2J¨òõ;„C˜Å¿ø©X›Xì©XLÌ','‰ìÍSÜÁþñ ëªg÷a cÏr y˜¹\̦¯½o¾e´¦}B%+Ö6ß®&““×¶ŒÖú@ŸMˆ¹ü’L&Ó€v¼ÇQ,bhNKº3’ù4ŽO’Ä÷ñ€ªLz‘Êi$QÀêÛC"óYE"Iôâ1£«êβ”@Ó9” »8I´`!ÍI&—iÂ,äa×6ªœ“XÌéÜBûŸÍ­TĽfûQÌäPFUôhÙü$nýŽÎ\Ë•¼Çãü…{8Š·˜ÅÓÕO5 b?ÄbÇ„c±è”h¨u(4!4û¼Ù Û5<þÐã‹ ‹zöìÙ¶íV•^ÅbÓ§OF£]»vÝúìKUy²³³ËËË“ƒ›ƒW§þÙsOÇWïÈßu—>0k–.]ì»ouÏ´4?îóÏUVV!­Ob¢;îðÁfÎÔ¡ƒý÷‡6m¼õ–wß•”ä쳫õ­>}4o^!Žx1,cÇêÞ]a¡Ö­k[ â¯5ož#”•­1õ=õ”õ+Å^r‰äçÛhu­… Mš¤W/ ²³½ø¢wÞ±d‰>}p€òrC‡ºðBºtñÄ**ª7Ço¸z÷6|xµŸÀ³ÏzçÅÅž{®Z}ÄEÕâðp :u²t©ìì yjvïîï× AõüééyÄÿ«´Ôý÷¯¹:ùÅ/ÔtŠéÑÃEYºTçή»ÎFÿû÷×·¯‡ö‡?lÈX»[ªzôÅ,_]¾<–“Žl¢;:q]ÀˆÚÿÎC¡íõ•Û¡ÊhZ8­Ie“L™‘ÕÉN\#vY¬|jyJjJ¡Bßq˜Ç)å-ÚÕÄÓžŸr1ÓHã~Ík|KZÝg–@z ãëê}Íã*Á®àgìXëN©‘*(ƒM êÌ¢'/sÏSÁèÈeŒå$ŠXJ­¹’›ø«È癸Éöt®çÎäH®â„=¹?næ¼´FûÅë)Ig1ŒH¤SC×Õ–Wh£\Ê)q2 iBcšñShArÜzƒXDk¬5ŠÌ‹»váU¦¡)«³ØÈûÌ¥HãN¦QBZyL«8™äÑ»†+mcžY¯g7sËhEÇr×s¥µ9* ÷£]ŸRY½ÝâNÎd%‰T¹JàŸqËnŸÚòjµ“øŒ?­yz)Vì^S<µXÒ”‡ÊµÕºYëÆ¡ÆÍš69räK/½T\\F·x{===ýœsÎY¾|ù6‰1:ôÐC§OŸþüóÏG"‘%K–ÊèÎÌ矻øâµZnºÉ‘Gn—µFެ]—Ý('´qsã&2eŠË.[+‰ý¥—Öé«°ýèÖM·º|“vÒÓ{¯ZU‹VE›M¬öø/g"ü‘†3lbµî¢ÆbJJB n—ô‚;TmnÜ<Ö<#–±®2Z“„¸…o èU[â¡uȤgü¸¦gR­¿ÔmâùêkRGòÂЊ¿ó0Wã6­k­¦]®¢ÍÖVÐ3è· Ý×¾,ó¨N‘@O@ßxcóøAµZ†Âtˆ'·Ç5tàA–2„[kR+1^æ!³ŽIf½9%®•n˜æ¼^›³Äz—´Me›œÔôìÙ³Q£F-[¶ o]4DZZZîÂ.6‡‚‚‚7ß|³¢¢bàÀÝvû[î.΀«µ„—±c·ÙT{íå½÷¶Ùl 1±YBBnIɼ­ÌG°MˆÅ”–¦´lYÛîÉV³C•ѤPR³„f+;/O®#oÊèÚöpwr¹¥¾eÀž®ñ2[âfÔ-&‘S8e‹Æ¦s,Gm«iU[òõÈŠeµŒ¶ÌI¨¶Ÿ·Ž»þE"‘¢¢¢šá7…h4‹Å¶UÉøH$’œœ¼×^{åçç80¨Dðã$JJKë]T(£;ee**ÒÓÓ·K4íŽv·Ù3yÏÃKŸž8½ \[î¥_Þ¸zàN¨oVS•ÃkÇ>lÕa½{g„×úÅbo½õÖÔ©S;î¸6ëǘÔÍäÉ“gÍš5`À€Íµ>±X,Nž<ù‹/¾ØgŸ}<ðÀ­4Ö캄BIÍ›3çììŠ Ž1 ~‰FÍ›nÒä”px+mWµ³£ou]’»ôOèDé‰õ^ü)àÇÊž{­:0m`xíï$YºtéÊ•+Ÿ~úéÙ³gÇb›6‹Å&Ož¸ÚõÌÒ¥ÊÊöÌͽm;Í¿£ïv!¡Aiƒ†UZ:45¶É%S¶ ºUv;¶äØ!iC2Ãë¦5OLL3fL÷îÝ‹‹‹?ùä“H$Rë$ë°xñâE‹eeeµÛŠò|~øá /¼ð駟Μ9?ÚÊŸÛœ_ô¿ÿm÷UžyÆÅ»ë._¼%zÃ駯)d¿ yòÉ5þ¬¥¥Þzk]óâ‹-Z´VË)§xûm§žê­·êœö¹ç nÙ²m-nÀz„B ­[ßZRÒmþ|›öƒ°‰F-_náÂÌvíþ°y>l›N=˜^„‘qĨбc‹Ç¶‰´ L¤;€°pf,stÉèËJ.;&õ˜=’÷¨µ[ZZÚ˜1c>øàC=´ª`}•?èfÎËË ‡Ã;vLÛ@›1eÊ”wß}7tÐA5ÊÌÌlÔh R6ÔNE…éÓMœ¸¦2SI‰iÓ|ü±¹s×ÜãËÊ̘áãÍ™³¦6fa¡)S|ýµÒº£.k¥¤DA™3}úéšu£QsæøøcóæU¯[Xhɯ¼báBK–¬Q‹Š|õ•¯¾Úˆ’ZQaî\lùòj%8³x±O>1gΚ£ÅÅ¢QwÝeõ×jåJK–xã óæY²dóTáÃSQáÕW7cHÀ“””Ó¹óÓEEƒ§OO(*Ú’²±[F,¦¬ÌìÙ¡ :µmûHVÖÖ–†Ùõ£æ$äÝàè6em:uü&᛹ sç%Î[™°²2T¹ñÁ›L8nmÙº²uëHëΑν½†6Ú(¼!=/11qàÀ«_N:µ²²rŸ}öɬ£@d=Ú´iF7wW½ÊC´*>©[·n³fÍêÑ£G÷îÝ\RR’ºé¥Ö6Æ_þâ_ÿŠÅ<ÿ¼-Üt“7Þб£3\|±‹.RYé²Ë|ñ…V­ÌœéÑGõï﫯œy¦FëÔÉã×™ò=9YzºÔÔ5¹Üï¾Û¸qZ¶TZ*3Ók¯ILôä“®»NïÞ¾üÒÍ7;çù‹çžSZêÄ%$¸ãC‡š6Í™gJIQV¦kW<°VŠøÕ”–ºòJ￯uk xòI½zùøcgœ!7W^ž¼<‡ ÿ»´|¹>ªÎ«÷Ý^}Õ¢EÆŽ•šêg?s챑!1±úÿºhÖÌùç{à£F­)°ýHOïÕ­Ûë Þ5sæïÒÓW¦§GÒÓedD‚àÆ€íA,¦¤¤ê_¸¸8-#cT·n¿KNÞ6¹bê¢Þ¬’I¡¤©º$uYY´¸rq^YÞŠèŠÊh Œlc$4hnš“˜Ó4¥i‹Ä u–¨•ôôô¹sç.\¸ð‹/¾Øÿýû÷ï_kl{]zêXµjÕäÉ“óòòªL°iiiÇw\Íu7w€*¢Ñj£fBÂűyso½%uÄzÈÍ7»øb7Ý$3a‚ .pÑEÊË=õ”Ï>Ó¾½Š ¡HÄ-·4Èo«¼Ü!>üÐAuÔ5Ê!‡HLTY¹¦&PëÖ^]i©Ü\?ü uk×]çŽ;œzªÇsãN=ÕÕW»új™™Þ~ÛêïÑ-·Øk/÷Ü#1|¸wßuøáÄ]<«Êiâ•W¼û®W_Õ²¥ßýÎ]wyøa·ßnÄwßmÑ"ýâ©ß.¸À‘GV×­âæ›Ý|³Îýë_jjøóŸefÚ{o 6¥pÜqî½×ûïo^²ú€-&JiÕêºÆ+.žX\¥¥¥ßÿý×_Ý·oß*e4‰TTTT$&&nnݦ‰'~òÉ'K—.MMMíÛ·o‹% c±ØW Àÿþç÷¿‡£ŽrÎ9ÕT—<ؤIb1¯¿î‰'ŠDäåAb¢}÷uÔQúöuè¡N:I$büx=z8óLX¹ÒÔ©u*£ÖÏ¿3`€ädÉÉZ·V\lÞ<‹>¼Z’Å‹ååiU[&²>Ò±cµüfÏ®n?ç……š4ñÇ?ÊÈ0a‚âb×\#²x±PHY™É“}¶ÄD¹¹[Rº½ªÀÂFíò-Z8ûl÷ÞkØ0›ÿ,°e„RS»¤¦viÒäÔú–$ `øklˆ6mÚì¿ÿþÓ§OÏÈȨ*_QQñÒK/5kÖ,77÷ƒ>hÒ¤ÉðáÃSªê?®G4F£‘H$//¯Y³fU~¨yyyyyy­[·8p`óæÍköÿæ›oæÌ™Ó­[·­ ‡ú1Ó¢Eµ¶×¥¶2`åå,XàÚkýûß8ÀôéöÛ’“½ø¢ñãï§?•”dÌÉÉÆŒÑ7^ bs3w­³Ó]åÇQ剅ÖêPÓ39rÌ1k*p®þ. bÕ* ¬اK/­¶ÅfdHM•˜X›‹­ñ|Ýœ~ºGõÁÕVÛ€€€€-&PF6B(êÞ}ñ~þüù3fÌøòË/«^F£QLš4)!!!999##£U«VU.¤&L˜>}zAAAEEÅØ±c³³³Ñ¯_¿öíÛwêÔ)q=¿¼Y³f}òÉ'ÙÙÙ2ºetéR‹úßÿZ´HB‚÷ßwÜq*+…Ã:wV\ì‘GªûD"¾üÒ€ú÷7a‚åË%&:Ô¤IÎ8C(dÎÙÙ[%[Û¶:wö Î=×sÏéØÑêê ™™&NÔ¿¿´4II† óÅÎ8CR’ï¾[ã0zî¹kM8l˜W_Õ´©Ü\…… «kÜ¿þº‘#}÷É“~ºXLQ‘¢"‘ˆ¢"……4¨Ö_LŸ®ys©©67“e«VŽ9ÆC:ÔVïÊh@ÀfÒªU«1cÆ|ûí·Ó¦M+**êØ±cjjj,{÷ÝwW¬Xœœœ³Î:«*¸>//oáÂ…áp¸qãÆ«V­ªRF›4iRWæ¦üü|A^§mJF†¬,£F)+Ó¦³Ï–‘áÔS)=]Ë–Õ!8ååŽ=VëÖ’’ÄbF»õVcÇ:ø`‰‰JJ¼ùf-{ñuQS?kÔ¨ÚõŽ;\y¥çž3ož?þÑj{úÏ~æÿþOF†»î2l˜Ûn3v¬C‘œ¬¸Ø3Ϩ5¹Â¡‡:ùdcÆhÖÌÂ…n¸AçÎnºÉÉ'1By¹N¤¤X¶ÌI'YºÔҥƌ‘“ãÉ'5m —^êg?“’âç?wÂæ×Â8÷\‡n¼ÙcV(£›GJJJ×®]»víZ^^>cƌ޽{‡B¡²²²>}úäçç—••eff®Ž¬?ðÀûôé“™™Ù°aÆÛW#MMMÝÜz¤àŽ;Äb–/WV&^öÕ=÷X²D,fµ¿nZšï¾³h‘PHn¼#o4OžÌ/¿””­ù“NÇÆœ£ØÛÛç’èäääääTdúLlܸqÅŠy” }lRRR222r Ì„”ÞŸC‡¨_?Ûxp0€$am pó&Z­l úû£Ñpÿ¾…Ù ®_çë¯iÒ„¦M¹ŸA™ë×å&O*YSÝÜܨX‘ ؾý‘NNðÒa4j32.æh¯%ÖÖØØ¨ÓÓ %_EÄŒ>£XYYÕ©SçöíÛ­…BQ¯^=Õ#µÊ<1 wïÞÕëõO}عsghhh¯^½žz’þ˃«+û÷3y2›6Ѷ­y<7 œÞ9—$ìíÕa¹pžˆmúg++«Ž;6lØÐÚÚÜüÀÚÚºAƒ]ºtnÑ¢G©T–(Q¢J•*O½Âkrrrzzº“““­¨ÝòÄ8;c0Ù”£Iy›ÞÊŠÞ½qrÂÆ†+$¦LÁˋŋeI~ø¨(vì 2IbìX† áë¯ùøc22È-µ,"‚;HO§bEvìàìYŒF¦N¥m[>þ˜°0¦L¡lY£GGQdT?’$)•ZHÌåaΧ3Ù¾ÐÐbTö‰X¿>gIµŠ©]›;¸u+§ðùóŸ.#GrþüÓŸvÏöîµü–é6$„ãÇóŸgÓ&fÏ~L´Z&L $$ïÊwFH¶øW§P¤Rþ¥0hži¬­­Û·o_«V­K—.ùûûwèСT©RÅ­×KJ­ZµjÖ¬Y½X%I*_¾< ŒÑ''8˜3:”3([–7ÞÇmløøcùyÙ²,_náØ† ÉÚýÊÚš#1Â%JàíR‰V‹VËùóÄÆ’–†••¼‰¡Õrë:~~æ›RÓ½eª©[ÖÁ”.]ÂÍ ½“Éh$%…»w±µÅÏ¥’5¨Qƒuërª­Ñpû6Z-¾¾8:b0‘ÁíÛ\¹BZ …\zÖ` 6–èh¼¼ððÈë^7=;w˜>6mr•)„1úàéééããséÒ¥’%K K´x‘$éé¶5áêêúÚk¯=õi_N4 $„{÷xê[ Æ'&Æ<Ò´)Æ= ¦€Úµ…1*x4ÒÓ ÆÏkk®\aýzêÕãüy:w& €¨(’“éÔÉò±ááÔ¨AÙ²øùqäK–ЫÀˆ\¸@d$NNxx°{7¿ÿÎûïLh(“'3j’$¨T¬HJ -[òÅÕùØ1ºt¡dI¼½¹x‘?fØ0V¬àøq~ü ];>ûL¶;GÆÛ›èhêÕcÑ"ËÞ+W<˜ÐP>ÿœQ£äÁØX† ãÆ J—&5• ðô´pì‚|þ9hµHü§'ýňøûΰaL™Âüùüü3áá ‚#G2r$÷ïóöÛ$%ae…£#«Vaú¾~#˜9“ºuÍ ­\É–-,\ˆ© WXo¼F#·nÑ·/ÀÞ½Œ—ññ´mË·ßZ6cb4Hþ*S(X·ŽŒ ºv%!ôtNœÀߟmÛÐjùæ–,! €[·˜7ÎsýO1y6[¹ cT ȣјššjoo/º <ûH•+Si`’Ä›o’‘ayÔ{Ã-žªB‚—öì¡tiôzæÌá§Ÿ¨]›iÓèуyóHHÈX™ƒ”V¬ ^=Ö­ã½÷èÑC¾ŠçÔ)J” * ¥’I“øê+ bËFŽdð`lm3†1c;I"22¯U2³m3¿&ÓÓùþ{Z·fÝ:¦O7oS¦ wÕªe+”abʦL‘Ÿëtò¹ØØ`c#{˜Öýã@¯çÞ=Ë&¾)n!:š¡CnÜ0¸98wޤ$9((5•øxbb,»‡W¯fÚ4üýyóŸ…1*äϵk×ÒÒÒ¬¬¬žzê ÑhÖ­[geeÕ­[7Ñ T <̦M;FHžž|ÿ=[·"IXYÉqŸ`n9kS¬³$Éb™·½YcÔ­­‘$9öT£‘åM’¹™A9èе{{s±£QžP§3·FË oÍZ¸7óD4šl!¡iiù,ªP<æ¾³$!Iòºz=’”kðŒBAË–æ®™y¾1£ Je¶S³µE©ÄÙ™^½ð÷6ŒjÕÌ*eUO¡ iS2¸L–´EõJ—æÝwå—66æâtë†#FpõªyÑgá‰ò',, ¨Zµja8/“““£££ãââ #5ê…!"‚ÐP ~àeÀ`ÀÛ7Þ‡v IDAT7ââX½@©¤^=6oF«åÆ ÎœÉëð”þø­–mÛ°¼KëâB¥JlߎFömx{S¦ žž³d j5éé\¾œ×*¯½Æ›oÒµ«ÙŠbï^´ZþþÜݱµ%<œädÎãæMó±;všÊ•+\¸`.PU¶,Ç›Ûóêõhµr­ Ó I~ÿÛ·Ñé¸z5[MÞxxP¾<[·¢Vóï¿X[Ë]*…‚ë×Ñhd3·U+Μ¡Z5^y…²eÍWïòeêÕãðálÓ.X@Ó¦ò©)4lÈîÝ$%qý:”,‰—‘‘4lH£F¸¸˜àjÕ—×U©hÕŠsçäuýýÍYkkîÝ#%S7ÀzõHOG’xåêÔÁhÌ™à•‰«+uëâîn¹ÍGñ"ŒQÀ:N«Õš¬CFãëëëëëëmª–þ´ILLT«Õ..."•>Ö¬¡KÆ/n=‚â sgbb¨Y“ °¶–“Ð?úˆ'¨S‡®]ñ÷';eww¦M£AæÌáûïeI•*§/ð›oX´ˆ:uøê+¾ùFö›.[ÆŸÒ´)uê°aã©íìÌçŸS¯³góÕW¸¸Ð¦ ‰‰4nÌÈ‘”(!kbeEx8¯¼BëÖôêe®h1|8»vQ½:ë×LŸNp0Û¶1{6ÁÁ¬YЯ-[ÒªMš0hPÎÎL 2Ë!š®ž 3fð¿ÿQ·.Ó¦1y2~~²ÀèÑ|ú)rÝ·‘#ññ¡aC4 ];îÞ•Å´Z¢¢ÌŽO))DG›µ#G¢PP·.;£T¢RáäÄܹlÝJݺԪń ¤¦ÊÂpþ<Õ«óùçï¾K•*r±ŽvíÌåŠ;t@«%0PNT ä‹/2„F¨^ßÏç?ÅäÐ}ÖÛô’’’V¯^]¦L™jÕª•/_¾}ûö…‘DoB£ÑX[[—,YRԎ̓ Ðh8w®¸õŠƒ%8|˜ÈHœÍ™æ•*qé·nQªyßɺºrú4wïf“\²$§XÛ¶\»Æ½{x{›½›ÕªåãvÍ''öì!- //¹&TéÒ:DDeʘ­Ã¿ÿˆÌíЀ:u8zÔüò«¯øê«œK8;3oóæå£É{ïñÞ{òóL_fÓ¦œ?Od$žžÙJV½ù&o¾i~鿯²eæ æáÎÐS§2uªù¥—Û¶…££9¹ªvm²0a@ûö™_:9±p¡1??vï6¿T(èÓ‡>},H>ŒÞÞlÝŠ›è¢Aüø pvvÖjµ/^¼xñ¢££cÅŠ«V­êïï_öb•*U‚‚‚49î¯ ’$gå4…F#6d Äôò’g&¿`¦d¨Trƒ†'Ç…©Tš=Ž&¬­-/‘Õ -2¬¬äL…‡)¦óÁÚš/¿déRþýW£Á3•••³³sjj*’’rúôéÓ§O;;;ÕªUë©W{•$ɦ൤à!ŒF¹¨{&¦ØAooV­*}ªTaùò¼j- Š…*UøöÛâVâ!„1*XÆÅÅ%"ûLrrò•+WêÔ©ót2… ^ FŽ´0nk[<>0'§lýÌ‚< Le\\\rŒ¸¹¹õéÓÇÓb·Ç%..nëÖ­'NœÐ?›m1@ (d„1*X¦Döªnnnn}ûö}º–({öìÙËyWL‚g SíÒÜÞ aŒ –qvvÎ,qo²DKBµ˜˜ƒÁàååUåô 7ÒÓÍUŠƒ!CX¹Òò[õë÷ø3 ^B„1*XÆÑÑÑd z{{¿óÎ;…a‰111’$•È­·†à?.^äÚµâVB x8|˜7ß|ÌöE@Û¶¹ö ½}ûñ§¼œ¦V«Å5/2ŒF㯿þ:jÔ¨âVD  Š$ññǼþ:ôï°c:?üÁ?Э›lq^½Ê´i²Åy÷.?þHh(åÊÑ«>>ÄÆšÛµgÅÏ)S²õd¿v]»8uŠ ¦Y³"8QÁ Åã£õë×ß¿¿µ©¨®@ðÂѸqãÃY¿n ÈÈÈû÷ïûùùyKï@ð"âæåž@¹ròóJ•øûoŒFvk\»†$Ѧü–«+‰‰–ч‰Ž¦dIyEOODccÁ£"þd‚bãÒ¥Kÿþûo«V­š O‚@ (œœÌ-Ô#"pt´`‰¥JamÍ©S¸º>òÎÎÄÅ‘’‚‹ II"fTðÈcT (67“CPh4|ó }dá­˜-ðð Øƒ5Ž㯿êÕ£cÇ|„ïÝcõjÔjÆã%LS«‰Šz†º;mÚÀüù4lÈÂ…Lš$£¥KsáëÖQª­ZHýú¼÷ãÆþ}|ò VV&¼r…Û·IHàÊvï¦R% bÊFfÑ"RRŠøÏ=¢´“@P<èõúˆˆ¥RéUÀ0AHIáí·‰‰)¨¼FÃW_Y~ËÊ llX° @S5k–k ð'ÇÙ®_çÏ?ó¾ŸE‹(QÂröIáqáãÇ“–V¤‹>L\;³uk1«Q,H:Pª€³3Ý»¸¹ñ÷ßìÞÍäɌŻïÊÂAA,]Êþý¬Z%û27o¦|y&MbÑ"Päb =ʪU”/Or2«VŠJÅúõ¨TLœH•* Œ­mœ®àÅAxF‚bãÕW_MHHu Bz:gΠÑP»¶¹ LTaa”-‹¿?F#ÑÑDFrô(W®’‚§'–g3¹|™ˆs.°iðÊîÝ£~}queÀÂÂ,TöމáÒ%üüäP¼˜<àÀnÜ@’(YRÖ0#ƒóç1¨_ßòƨI&&$I®nª9‡JERW¯L` ¤¤Z ËeoOïÞÙN?!sçðö¦B$I¶×MA~ééÄÆRº4)) Ü¿OBµjáè({÷.W®P®œ9ô0#ƒÄD\\8u GG‚‚ˆŠâòeŽãúuœñö¶ìT‹Ç`À#­VË)2*qq\º„Õ«cÊD0ˆˆÀÕ•›7‰§vmùtnÞäúu¼½©\Ù²µäíM,[ÆŒvð’µ’$¦M“Ÿ{zòõ×òóºueë<ÇßaÏžôìi~éäÄ'ŸÈ÷TyäÊöï/§FeÅÏeË,G£ ù"<£‚§ƒ^¯Ÿ>}z«V­ö™ Ü=ÄâÅ‹›7o¾víÚ"PfÀ€Í›7/‚µ¥RP·n][áCÈ+Wfξúо}ôz, A¾ûŽ–-Y·Žyó>œ{÷˜0Aƒ8uÊòlz=ӦѦ sçÒ¦<¨Õòæ›tíÊwßQ»6ׯçªÌ²eÔª%¯»t)À?2`F#ï¼Ã€ìßpó&Õª1y2cÆÐµk®5À§M22>ùÄì¦ýì3:w¦aCƧk×'u7®^MíÚÌKÇŽ,^ŒÑÈÙ³4n,Û÷ýúñÅèt,\Hp0ƒñÑGÔªÅÕ«k×R¿>sçÒ¨‘ÙI|ò$íÛS¯cÆÐº5‡1q"ŸNh(Ç3j”9H1›6Ñ«ééýE÷î$'sð uê0g|@›6ò±IItéBëÖôèÁÀ|õ'Ò¥ K–л7»wçz¾pý:ûBDè¢I*¨™˜)yî­[Ó¼¹ù±iSþÇ ðŒ ,°yóæß~ûmݺu?D©T~ôÑG­[·ŽË¥ Ü!CöîÝ{7÷ös¿ÿþûñãÇgÍšUå>úè£:uêôÌzSŸ…+V899¥ˆÀ¥…ƒ –MŽoÞdÖ,6o¦n]Žã­·xã fÎ$1‘fÍX¿_ß\ïÝcñböî%8˜Ÿ~b€å˹x‘Ó§±µå«¯˜;W.…“ƒØXÞŸêÔ!,Œ¦My÷]¦LaÊ”JBB̾º÷ß§cG¾ûI¢vmöì¡]; æl£1ÛFÿƒœ;‡»;QQØØ<Îu3Áôéüø#mÛréo½Åë¯Ó¦ Æ1f -Zpÿ>?ý$ï«–,ÉŸâêJß¾|ÿ=3g2{6Ÿ}ÆàÁlÙ”)tïŽF#÷ï³t)]º˜ˆ­-Í›sø0Ÿ|† 8;çzñ[·æÿþÐPj×fÃ:vÄÝà`ÎÃÉ ­–®] ¡Où‚±x1*))$&rð Ьz}^vO¹rtïΆ%÷ê·öèãS©K–dû›,œ>t0F_> CDD„½½}Ö¼™ØØØ´´´2eʘ`>xð ‡Õ˜”””˜˜èããc±…ºF£¹ÿ¾kö$L£Ñx÷î]{{{S¯KI’rI‰‰Q«Õ>>>™KDGGgHHHHLL,—¹5˜…èèèäää¬#‘‘‘Z­ÖÇÇG’$En±Nϱ±±€»»ûs¡mñR³&S§R»6uëòî»4hÀ¹s$$È F÷JD„¼Ù (yY*gÎ`oO€ÜÒÉhääIt:FÆhäôé\tÏžE£‘׎&.Ž;wðõ•ßÍê|:r†wß%%…ØX.^´lŒæAÏžòvöæâ\»FZ+Vðë¯DGsù²ìg;–}ûX¼˜Ý»qw—…ƒƒåE[¶ä·ß¸z•èh5B’¨R…HJÂô‘ ¤I ó±¦ÓÏÛW®AAlߎ»;çÏ3v,À½{|ð'NàêJTo¼a–ïß_¶’]]Ñé¦gOêÖ¥];Î+=kÀÖv¾~,¼e«–{å^vlm©P¡¸•¼côe!99yĈ!!!-[¶¼|ùò;w–/_Þ±cÇŒŒŒñãÇ?~¼téÒ‘‘‘+V¬Ðét³gϾwï^³fÍZ¶l9}úô9sæüöÛoAAA—.]Z¹reÍš5³Î|ðàÁÔ®];666æ¿Ì‘Û·o÷ìÙÓÛÛ;!!!00pÉ’%YÑëõC‡ sssKLLܲeË7fÏžššÚ¬Y³Ž;Nž!;wî¼víZ¿~ýŠ[—gZµ¸x‘Çٲ…Þ½9q[[œœèÝ[°²zŸ¼-æÝs¥’jÕd3¨wor+üªRáìl¶–FÎUÒÆ†fͨU `Ð Ê—/¨z™<­Xb…''ºwÇÅ`ôh9Áåþ}nÞÄÖ–#G¨QC¶ 3/ˆZ•VVfËR¯G©4»~y¼2Ó}û2g%KâîNÕªsæàçdž ØÙ‘Ën€JÅÂ…Œþ},ZDF†å2&éðªbËâ-ƒZ‰Î]Á³Žpɼ,8;;Ï™3ÇÊÊêÕW_=zôèèÑ£M»ð;vì ùûï¿7mÚÔ±cÇI“&øá‡ÕªU ùä“O._¾¼páÂíÛ·¯]»vôèÑãÇÏ:mFFÆŒ3† ²~ýú5kÖFM¿—›7II¡cG&ND¥"9™jÕ°³#5•hÞggy#ÛÔØ0·€EÁÁH;wb0°aƒ|T»vœ9Cõêtè@­ZfCÐÕ•{÷ÈÜ'¨Q´Z:t M°³“ßrsãßÍ«´nÍÕ«´jE‡”.-ÛS¦ ‰‰$%‘šÊÁƒù\''®]C­ÎG,•+Ëöw»v´j%gÙ§§3lÍ›³r%³fqè,|èW®‘ÁÎÔ®MùòøúòÇ>Œ»{®Æ7 TÊç’7õê‘–Æœ9t=@ZåÊáèÈ‘#fM&5•³g©\™áÃiÓ†¨¨¼VQ(èøvÙS'O9s&…žôzBBò9å¬ètœ>]Ðt7 ØÆèK„B¡prrª]»¶B¡(UªÔýû÷Ô¨QÃÕÕU©T¶hÑâäÉ“ééé …Â´Ù-IÒáÇSRRúõëתU«¥K—ž;w.>>þ7ÞhÙ²e·nÝÔjõåË—›4i"I’««kùòåFsèСþù§uëÖ:uŠ?qâD¦F£ñäÉ“±±±­[·nÓ¦ÍáÇ÷ïß/ý‡iÑ£GÝ»woÕªÕ¯¿þzäÈc–À¥LI“ðþýûëÖ­kee¥P(V®\Ù¹sç"¿´Lrr²Z­vrr²y’`À—†Ó§©U‹ hÑ‚>}(_æÏgÚ4*T bEV­’%èÓ‡þý©Z•={,ÏVª3g2`AA8@Ù²]º0` R¹²`ÂÓ“ hÙ’*U\]ùõW>úˆÀ@X¼Ø<í´iŒA¥Jrlë_”DÅŠøû3`XV& €¶m©^F(Q¼åíînÁ3Úµ+NNT¯ÎðárìlAðð`áB¾ûŽÊ• `áB´Z–/ÇÚš/¾ uk>ø€¯¿–H:v”3îÇŽÅÎŽÙ³ùåÊ—çÓO™:Uö@ÛÚâå•3™=0à`Ú´¡aCòÈôö¦MœœèÔI5ŠeË(WŽáé^]®E Pàím¶õ;*Tàðas‰¢Üð©æU®q¹ï¿ÿ¾ WêF§ãÛo©^mÛò6éÞ¾}å\:àÙGlÓ¿\X[[gºâLæ]VcH­V[YYåhñêèèX¾|ù¿ÿþÐh4§OŸvqq™9s¦N§S*•’$YYY©Õj 3$T’$GGÇ¡C‡öéÓ¸~ýº‹iƒð?lllZµjõÓO?ñññ¦èÉ+V4-š‘‘*å†fcc£ÿosñæÍ›666eÊ”yôkS¤XYY™¢D*}AèÞÌ[ S§AI¢kW:v”³+2#™U*¦LaÒ¤lƒ9P(<˜äç¦T*¦McòdyòÌc ¦OgÊóáM›rö¬œu”u‰±c3Æý”´4ä‘-8sF.Ù“Ùæ±N–-Ë©ƒ³3?þháÊ<ÌìÙÌše¶e›5#4T^B’äq¶nÍfï–*ÅÞ½òüy_R ¥¢Ç° .¼páBµjÕò‘~¶±±aË>ø€þ!ßÛmƒÝ» Åß¿(tžá}ÙéÒ¥Ëáǯ_¿®V«×¬YÓ­[7•JåêêªÓé’““‡ V¯^½ìß¿_¥R­_¿þ§Ÿ~2Õ$ª\¹r… ììì^yå•-[¶/^¼xñ"`mmݱcÇõë×k4š´´´!C†˜¼°&$IêÚµë?ÿü­T*?þøãƒŽŽŽiii={ölß¾ýÕ«W/_¾leeµ|ùò•+W7oÞœ;wnzz: R©RRRNž<9wîÜ.]ºìر#!!!##£ÿþ1¯x^|¸¸¸´mÛ¶M›6*ÑŹH’¿˜5„P©äÁ¬&‹ÉfR©òJ£ÉœP©4X™ƒ9ŽÍœ0¥²@ë*æU€?ÿdÝ:óãàAÙ6‰©TÙ"2 ËE4 Y2*UbÕ*úö•7Á-ê¬Tš'ÉjÚšÎÂÙ9Û¦ëœõ äf ›Ô3]„;³oHH61¥ÒÂ¥éÔ2ÇsÈd=‹Öó¯U§VhhhUShêsŽBµuA‹|iµ”+' - žÄáËBrrò”)SlmmGŽ9jÔ¨•+W †/¿ürÒ¤Iüqÿþý%IªY³æÔ©SÆ—.]ºS§NmÛ¶-_¾üÂ… ?ûì³™3g–)S&Gé%++«¹sçŽ=ºY³f*TèܹóÂ… +UªôþûïGFFvèÐÁÎÎnРAµk×^²dɽ{÷"##ëÖ­Û¢E‹‰'öèÑÃÓÓ³råÊï¼óвeËeË–uìØ±]»v¾¾¾Ë—/:t¨‹‹‹——×wß}DEE­^½zàÀvvvýúõ›þøãf͚ݽ{·K—.¶¶¶}úô©^½ú;ï¼S£FÑ£GïØ±Ã.ë>ß3Fî^Á‹ÇÕ«ÙZCÞ¾‹Ë#gî›xóMtº§¦ÆÜ»g~©Ñ<µ™ Ž„de±øþó‰‡Ù+ŽX&3?O xnØ»w¯1Ž=šššúðxHHˆ••UýúõÕjunÇ žAt:V«ÕétƒA«ÕjµZ½^o4M/5ée¦pÖ‘‡rÌlz×´„Á`0z½^£ÑhµZ“Œ^¯7-jz7SÓˬódŽäXÔtH¦°éð¬oeÎfR#«ðcШQ#ààÁƒO2Inïg'==ýÔ©Siiiß={öl\\ÜÃãaaa•*UЉ‰yøÝ“é'ÿIíiª”)âñ,>þ÷°°lgtô(¾¾ŒÇ­[–OÙ`àÿ£m[Ú·/þë//Þ#"‚›7ß{øoU§ÓõêÕK©T®_¿þáwõz}HHHnŸ‹#Gޤ§§ ÏèKDÖ¡Yw‡%Izx³X©Tæ&oqæ‡ëšŒr{ù‹æ8$S°X õÙ!##ã§Ÿ~²±±éÓ§SfkK@ È“ôt$‰€rû>–$œœðóãäÉ¢ÕL x2žcT¯OÐë“Fcþ¢Á#"I’Ba¯R=+ÍCÓÒÒT*Õ3n4 ‚gŠýûéÐQ£ò’iÙ’† 7¹‚ç‹â4FFMlìšää=©©'4šÛÖÖJ£±8¢Š/: …F£U©JÛÛ×rrjV²ä ¥²8¿ª“’’Ôjµ«««H¥/¾úвeyë­Â]åâEÂÃqs#!!ÿd燹}ËKdÃþù‡ùó-¢ß¼YÎÍïÖ/¿ÌgžŒ ’“)Y2ŸÖ+W¸xîÜ¡GË2QQlÝÊ믛ëU žää…[[#;‚ç‹b3F32®†‡Öé•(¡÷ðÀÞ•ÊD3qAa`k4jÒÒÂÓÒÂãâ6ÇÄ,ñ÷ÿÁÉ©)OþÑhôòò*S¦ŒhZDFâèX諜:Å®]T¨ÀÕ«têôÈÉIµkþDÞ¬„îܱl‚tíJ‡¬^W=ùLŽå»ïX³&[&þÃ\¼ÈêÕ4iÂþý¹£vvüø#J%ƒD ¤§^Ï;°_›ƒ'NP·n!ë$<%ŠÇ‰Y~÷î‡ñÞÞ­Ð!< ’„£#ŽŽ”,iŒŠ ½v­}É’ãË”ùD’Šá#P¹råŠ+ŠTú"ãþ}>ûŒøxºw§E ŒFΞå?¸ŸJ•Ì-ί]ã—_ˆŠ¢Bú÷ÇÓ£‘vîÄhdð`*Uz„E&.Ž ¸{—·ß¦~}€ÔT–.%,Œ*U4víâôiRRøî;llèÞ]^åÀvì@«eà@s]åìYÖ®E¡ =Ýý”S§øì³Â×L xµ[H¯pûöOÏÙ;òEŠ­-eËnÞœìäÔÜÆ¦|q«#(\:t`âD ΟççŸiÒ„‰9{–;w¨[W£Ôë¹y“À@Úµãõ×ῌ3f0hzJâé IDAT=Gްk={Z^¢}{Ú¶E’0Í{ô:1|8’Ä…ܺEéÒ¬Yî]¼ò åËÓ©j5M›Ò´)~È Aæmúï¿g† Ãhäôivîäw,,ºi*0mööܹÅ ‹1nœœãrö,ÿÍàÁŽÝ°’%™3ììX³†>}xóM¼¼¸r…Áƒqp eÏ6o¦Z5:t }{îÞ¥Bš5£I zõÊëÊ»¹1`K—Ò­â;ÿ y¤ÎÁ Å£É ÅKQûf"#¿Q*O”.]ÄË 9qsÃÅ%úÎ)Fc›|? L¥û÷ïߟÙÂTðùí79ã£Ìƒ¾¾rÇ ªU‰ŒD­¦gO>ø€¸vM.ÆnkËìÙ|ú)ÞÞtìHd$wîðùçT­Jõêœ?OTT®ëf6FÊZsÇ”“$I¸»c4’€^O­ZeÊ‘AnÍÂ.\à믩Z•jÕÌm<²eqt¤reÙG{ç*ÈÁåÊÉ2×®ñÍ7T«Fµj?žkýók×8~œúõ©Z•iÓÈÈȶџIL ññ¼þ:U«Ò²%IIæ§*•üoÞôéCB;vä#&^fŠÚ3ÿ»¯¯AìO ž¼½ ýÛ`HS*‹ÎisãÆ ;;;±M_ôèAÇŽ@¶ɸ8£‘7ððàÚ5Nž$<;;`õj@n×>p wîðöÛüþ;ÆQªŸ|«¯ÊóIQ॥HµÚ(îži÷G (vlm‘¤„ôôËE¹htt´Ñhôôô L…J%{F³£[¶°n›7ó×_¼ù&¥Ja4òûïìÚÅ„ ²ŒZÍØ±8ÀÍ›¤¥áé‰JÅ[oñé§ìÛÇñã|ù¥lÔ>6nn4iÂ石oS¦Ð¾=™¥½üý™3‡¹{`ð`æÌaÏŽaæLnÞ”ÅptÄÞ^6s{öäØ1V®dË–-“eÞ}—y󨳇£G™9“Ëÿýu{yqø0?ÿÌ¿ÿ¢×óÚk„…±|9'N°a[¶Èsººrõ*+WòǤ¥Q¥ +òÅ9ÂÞ½|ûm^³¹Ñ¿?·n±oßã^8@ð¢S¤žÑôôKÖÖéÂ$xvpp =ý¢£cý"[1==]’$wQz±¨hÕŠªUÙ½›Œ ¾ü’ví$~ù…U«$&OæøqøÏ‹¹|9’Äðá¼þ:’ÄàåÅš5 =Zé¥ Ðþ’™„þóÏÌžÍ?ÀG™÷¸W¯æ×_9~œÀ@||96nD«¥R¥\SÑ«TaáB6mB©dìXœœP*26mB­& €’ÿµzh׎38ŽF¨P øé'ŽÃݾ}e±5øòKN">ž¦M±·gùr~ü‘åËQ(hÞüq¼›eËÒ»7 Òª•d(Rc4#㊭­:«1úçŸ\¿Î˜1¦WrÈÒž=,]JR+Wš¿I&9™¯¿æÔ)~üoï¼Ö]³†žZm‘¨(fÏ&,Œ~ýÌßàß~Kõê´iót–(GòÅ4oÎèÑä[:=#ƒ 8|˜iÓäµ—ŒŒÜ²æííIK;[”ª´oß¾yóæ6â7¹¨èÞ`ÈŒFsùŽvíhÝ@©äµ×¬­ùî;ôz9ºÔ„•ï¼Cÿþ²ä#‘õÛ`âDù‰óçc0 TfÛįY“š5Í/•JÞ~›·Þ’uÎ͇.IôèA·n9ÕëÓ‡7ÞÈy¬R™³òõê²2 …¹Þ¾BAïÞæ]~ÀÝI“ä¸ÕǮҿ?qqÄÄàãó˜3‚˜"5FFRiÌúŪReÝMS £G3u*Õªå“}ùï¿lÙÂwßåcež>ÍÊ•h44mJ@À#£~˜Ÿ~âî]¾ø‚2ẽ66E]¦*(ˆ1c˜4‰W^¡Q£|„CCùæÖ®¥B…"Qî™#×Î^J%:!·w •JåXEØÙyxCæá¬$YNÇyºí¬–_Þp]‹b<¶€Êd5ЀæÏ¢Sà¦8ÛnßNz:uê˜GŽåüyÒÒÐj¹~J•,jÎ$1‘à`Z¶Ì˾œ7õëIIaûvdþ|¹^ÉéÓܸ!gךêä]ºÄ¥K¨T¼òŠìŽÝ»—R¥8y…‚.]pr"*Šؽ›  ÂñµÅË‹ÄDöïÇÓóº GŽàïÏÙ³ètT¯Nr2‘‘Ü»G½zœ:E­ZÙ!™hµ8€³3wî Pа!žž–OÍÙ™Æqu%22×ÓÏ$6VN†‚¢çÉÍY@ðSœÆèÉ“:Dùòæ–eW¯rò$ééœ<‰­[çŸ$Iùx:W¯æË/ùýw>úÙ´ýá.äõ׉Œäüy¦Ogß>æÕW¹}›9sزOO¦NE­¦];öîåèQæÏ')‰#Gˆ‰ÁÁ#Gpr¢JÒÒ8~œÿý>0WWIKcêTâã©X¥’ºu¹s‡Ã‡qsã“OhÕŠeËØ½ÛÂözz:Ó§sçݺqã³g³eK^± :]žWù?„OâYàæÍ›7nÜ ôÎ;²D ‚—†â4FgÌ`ÉNŸ6ôëGË–>ÌÇçeéõܿϞ=ù‡6kÆgŸ¡×ŠŸ’DDß~Ëܹtíj¶äV®¤];æÏ'.ŽfÍØ»—Þ½Ñé8Q£Ø³‡O?%9™J•˜;—ÈHÚµ“ÃÈoo>ûŒ;w̵£‘”Þz‹?0xï=Ú¶¥Z5/fÚ4Þy‡èhüü,ŸÝ ALŸNT¯¾JHH®e¥ííñöæÐ!^y//ËŽƒˆvî§Ÿ ._¾|øðaaŒ @`â¹t—ÅÇÓ·/7Ò©S>’_|Á AcÜ8\]-ËôïOß¾ Ê”)ȃþþ,^,‡m™¬WWæÌA£¹E$À’%ò»AAÌ›g.25}z¶T¡?dÜ8óK“˜£#óçgë ýá‡rÌh«VX[³`A^U«¤m[;»\]žáá,ZDxx¶r§¹Q¶,ׯ3}:C‡š{L /$ju¶t½Û·Ù¿Ÿ­[¹}›ž=:GGÆŽ¥CÞŸ37Ž]»˜6Ñ£©PU«ðõÅÑ£‘Ï?çÒ%þþ›¸8:w¦uk-/ºb¿þÊÁƒògvâD$‰3g8p€×_7K:9¡ÑcT Ì›1ªRYvšò{ B“&¬ZÅ©Sùˆ)•ôé“37ÿáÕ•ÊlŽL0«¡Pd3Žs‘ÖÖÌJIÊiOgʘ YvíâÏ?ÍÎÎŒ%/ªPäïï4([–5k¨^=I B¶mãìYñXœÜºuK§Óùúú Ïh!‘’ÂG±};sçfïØ‘²e)QwwÒÒÐh¸t‰5k(Q‚hÕŠ„ÜÜäq9[«eûvºvåÈŒF|}9p WcÔÕ•Á!!|ÿ=îîtéBp°y¼Z5\]é×èÒåiž¾@ <§gi§'ÄT þ•Wò—,Ê.ÇÇ'[<¨vv8:²cGN³Ø"Œ]е êÖ5×s ÿüóÏÝ»wè#Z"*AAìÝ›3t»tiù‰Ég™”„Ñ(ß.zx`0šŠ›[ÎÙŒFbc¹qCÞ3©UËr-¶ÜHL”ï<%)[¢)Ô»uk±G!2ϱ1ú¼DP…qQô…$###))ÉÊÊJd/¶¶ŒɃ<Ȉ¹Š•)ƒááøùqînn˜ª¾š¬FͽcM5àš7gÔ(îÑš W®LX¯¾Jr2aaæñ°0lløòËÝs ÁË€0F‚¢ !!!##ÃÅÅEìÑ6*U>éz °atèÀÖ­Œ+oÐ[YÑ¢o½…¯/ãÆÑ´)3f0lçÎáàÀ?ÿ°}»åí½{ù¿ÿãÎâãéуæÍyÿ}¦Laà@nÜàܹlú¤¥=B{zÀDz:ÍšááÁ¼y¹ÆŠÏ/ÂÍŽ„ÜÝ-´8Ò鈉A¯G©ÄÓS4_䊳³s‹-”J¥Íc—ŸŒR¥ˆ‰!>^ý?^Þ‘·³ã×_)U ¥’O>¡m[¢¢èÙ“ äU*~þ™ $9ß±ysvíâèQt:ú÷7o÷ç 8˜É“Í/=<$:wfÇ®]£GJ–Äš¡×sý:Â<¶¶üõcÆðÛo̘QÜÚO›Ê½w[·hÐà)…7o2z4K—òp¤_t4|À­[dd°e eËæ5VˉT©òÈñ{öÊÈ‘âì9ÆÁÁ¡a5cO-X³†®]Y¸5ÌŸJ¥ÒœígcC«VŽup0Û¦€$áç—-T4""[99{{ÜÝñðÀÃ#çT õêå,Í6j'N0rdª× ™HøúQܪ…À õxàË–±eKJoƒ”ËSJ•bùrΜaĈü[ª¤¥ñé§|õµk?š|÷uêШѣ(¼„”)æMh4Où{0?>[c§öí™4éføúkŒÆ¼ºTyààðøÂ‚g™çÀ>œ5øë/ll˜65¶oç—_ÐhhØÑ£Q«™8‘³g¹u‹·ÞÂÍÙ³)Y’ˆ, ,Œ%7Μ0tâj5 ˜ý àåEÕªòHh(sæpû6Õª™sbÙ2©Y“±cqrÂÞ{ûœ?-11Ì›ÇåËxx0~<•*ñÃìØÁÙ³|ø!®® Jûöh4lØÀ`4Ò½;½{[ö}V­J›6üðƒ0FŸcbccm X·LðdØÚ´BÜ#¡PðÓOÙê£e­%\DöšàI¨Z•_e÷n4È«S´@ðÜñìûîØÁ¾}L›F‰Ìœ‰VKXcÆÐº5#G²l›6áàÀ°atêD™2¼÷#GâìLz:ƒÃÔ©øø0eŠ9`ΦNÍÖ¡>9™1cÌ TRR1''fÍ""‚¸8€ :”:u˜<™'X²Ä²ÂiiŒÉ;LžŒŸãÇ“šJ»vŒE™2ôëÇ„ Ô¬ ðË/Ì™ÃÀ¼ý6ß~˱c–'T©4ˆƒ9þi\PA‘óàÁƒuëÖ­X±"%%¥¸u<8:š"XP”T«FRóæq÷nq«"ŒÑÙñeË’˜ˆZ—.áé)[{¦ØÍ̈®Ò¥ñôdÖ,Ù–%KOοÿ&=ŽÍ!_¦tx??7pwÇ`CÅïÞ%1ÀÏÿgï®ã«ªÿ?€¿n÷vW÷®“±Ñ=J HIJKH)NA)t(¡ Cé”Pº$FëÞîòvþþ¸ç»À»ÁÆêó|ðÇîىϹìÞû¾Ÿx¿½½±s'¤ÒéÔá,V©©cb1¤R|÷5½•F+þ­ÉT¼Î‰Ï‡úôÁŒ–oó%­Z¡E ìÙƒ•+_á)#j.—Û¨Q#OOOY·òº\\pø0H0J4\z=‚šnATƒºŒ¾¤G,]Š%Kàæ†ãDZkµîÇÛññX¸mÛbèP4k†Nðå—øè#ää 9+WR¯äíÛ‘™‰÷Þ+ ±x1úõ£‚ÑfÍв%fÏÆðáØ½›š]úá‡8tsçâwðð!|}1u*¸¹ÁÎË–á½÷0h|}ñþû˜?Œ¼AAÐé°nŽ…H½?ÿ GG|û-ž?GJ Ƈ•Ö¯‡—®]Ãܹ°µEZfÌÀäÉ–¯›•…ñã‘”„O?ży`2áØ1,\Èå(,|“g(véÒ¥üüüwÞyÇÞ¾ºº k &ÙšÓ+3Ú–‘QÓÍ!´<£Ã}uÿöÜv ²¨Ž ê‚z>t(“¡m[=Š9spàT*ܽ‹?þÀ?àèQ0™Ø¾VVزóæ¡Q#„†b÷n89!3 `âD:„ÿû?#-Íò%¼¼°gÚ¶-âOLÄÊ•˜;Çcôèò;>99HH—‹Æac“ ¹¹hÙGŽ`Ù2ìÝ µááøåãða8;#8b16mBp0ÜÜpø0v;rs±p!>ù`Û6lÛ†ÄDËוHpø0Úµ+”óò°lfÌÀñã˜1£‚I®Ä+2ááá=Òét5Ý–·ÁƒåáÎzç†j`õÍ%ˆ éM¬;ê>Rf'_¶oM·… ˆWR¯zFOžÄýû0fLq}¦^½ S|?†³3š7‡@€^½pö,´ZXYA(ƒkkªtgt422ðì6l€B”dgÃâb1Ø%>|ÓÒ Ñ b1ñË/e6øƒðô)~ÿ™™xðË—SWï=ˆÅðõEa! ñìxåDyòòò”J¥•••PØ –™ÓAoÇéð§"õ¢JÝ…{ZDÏ«é ŽÂhõ¯ºo¶¾÷agz}ïm!ˆz£^£45o²dñEÛÒ‹) ÐéÔt:ŒF˜LNe4‚É„«+5«²IH¥¯Ú £±¸ ,VyÓFE"|ÿ=||‰˜„„`Ñ"ªa%éõ Ñ¨²Ù0ÊþþHMEb"¼½qëüüÀ函Z-µ›§'D"4o޾}¡×#)éå ¶ŽŽ`0ðü9||pï^y9’""@£Ë…DBõeZä燂<} ??\¾Œ-¨í44äæR£66psƒ£#ÆŒÑˆØØòÖ0½ÄÚöö¸rcÇâöí –ÿ¯ÈÙÙù³Ï>ÓëõLf½z¡•ÏŠnõ‘ßHïƒfLœ¾æ¬Ë€ îRf¢˜NR…ÕÂZÑ6SïžktdÑÜZs;û±ü˜´ôŠ#ˆz Á½b»tA@>þb1òó±x1µ½U+H¥èß..ؼ®®˜3K–`óf¨TðòÂÖ­°Q¬]‹óçŽ;w°oæÌAŸ>˜9sçbÛ6dd€Ã)³1Ïžaófdd@«EË–X³Æòn­[cØ0L˜kkÈdؽ›Úî䄿ÍÑ»7ÜÝ©L `åJ8…"öîµ|õ_Eh(ÂÃÁåâÖ-ªÍæû=t©©åµ™xu CüR‚†ÍdwöîÜ£mO\И=*Ûª×L¤‹”¨\:ׇm'eHt—Æ¥¡ÞŒì0Ê£|@ñ6[Cz=h´jYXσÑs稌K:`÷nðù Ó±};²²`4Âʪ¸ïP*Åþý(,„^©4ÆŒAß¾ËA§C,ŸoùŸ~ŠáË:8€NÇôéøðCèt`0”™,iÈôèÇ‘›‹Y³ ÂhıcÔ8{Ó¦¸x¶¶`0°|922`0@$BѲlìÝ‹‚èõpr†!CðÎ;Ë©I¥eB k×—Ûüé§èÛZ-x<*ïAÄFÿ® IDAT¼ 6‹mE·jÊnZÓ !ˆ:‰Ïo©RÁh|yâÖÿÔóo¢¶1™ TÒmlü«ãäõü¯ÙÕ•úË-^”#@ °°³yIP:IqLVP€°°R©é›5ƒ“,ÄšL&ÜÜ*n;;4i‚ü|˜—¸Ðé(*Éោ˅‡‡…3ˆD‰ŠÒh¥Ú¬TâæÍRû{{ÃÛ66ÅËžŠ0ÅOñæòòò>|èâââããSï3Þ[$‘HN:Õ®]»Ž;6%\Q…X,)‹å¥VÇ•ÕBo“ɆÍãµªŽ“×ó`´ åæâĉR%š„BËëë+«[7Ë‹¨Þœ\Ž#GJm0ÞÞÕr-â%×®]óñññn¨ÏxÓ¦Mׯ_¿cÇŒDeÑhl.·yA F‰ZA­†NÇçñªe°‹£¯ÊÛ6U˙Ֆ•Y"ÁŽÕur¢|)))ƒÁÑÑ‘Q}ÿÁµÛµk×FµlÙ2®y‘ A•A£1¥ÒÏãâΊÅ:ò"j–ш¤$ºƒÃg †¨â½+¯!ŽÄ[ @úê)ÁêƒÁ •Jù|~Ü¥@oÎʪ§XüYBBužÄ+ÊÌ„N×ÒÙy~5Ÿ|HDµèÕ«×°aÃì½ÉdJIIi°½ÂQ%h4–‹ËbÆ7!¡ÔŠ‚xkL&de!-Mèá±™Á¨®ô½u>½x±ÌŒH•¢Ñ@&«ÉoŸ‹ãäIêçìl|ýu™Å<+ËhDNNÅod:îÜ\Ž;w Ñ”·gT’’ðø1’“«¦…õ’­­m‹-Nºû’’““G}çÎŽ;Öt[¢nc±$¾¾'4š~¤P3ñ¶©Õˆ‰AFF/¯C"Ñ;Õw¡:?g4- WÁy®^ÅÖ­Ø·5µÐâþýâUùæÂ¤UÕ©”ŸÉ“±t)š7¯`·Y³ðÓO˜5 Ç/êÿ¯íÛáík×г'¦M«šFuEffæW_}Å*§° R©ž={æââòÓO?í.Ê‹Kµ‰\./,,ä×…ÅA<^ÓFegï‰ý?KfNÃåêÉÀQL&h4P( P@­æŠÅ“<=°XU±^»lu GX4ˆÅx÷]*ßg\.\“ ™¬¼cÕjœ?¦MñèôzÀË 99¸v J%¼½Ñ¾=ôzœ?«Wñü9†XŒÞ½!áÜ9´o;;ääàáCtë ééxôvvˆ‰ŸÀ@ÄÄ 'J% ЬZ¶­×®ÁË A£A»vðõE~>®^…\ŽFЮèt xð7oÂË«¸üRx8=BË–¥Ââ¼<ܺoo<| °¶Ft4>€€€âÄO©©¸u Z-¤RtïŽçÏqëÂÃqêžê*%//ï·ß~«éVDÃÂ`ˆ¤ÒÏÅâA Åm¥òqnîcƒ!ÕdR×t»ˆz‰F§;òxþöö|~k¯ V^ïC•¨Áhp04¸¹áæM\¼ˆ•+‘œŒ#Ц Ølœ8wß-óXsoŸÜÝa4B­†H„ ÀfÃÏ6`Õ*t숋†Ü\üõlmѹ3D",Z„­[ag‡/°r%Žƒµ5?ÆÈ‘hÖ nnP©àïƒñóÏ1*BBðûïpr‚BE‹ ÑÀÕ 220f ¦L€&M°u+fÏÆÐ¡8w_}…>À­[¸sC‡@L ³gøãX[S7’€Q£±j5ÜÜ`4bÚ4tí :[·bï^xx * £G£U+¸¹áôi´l‰ˆœ;‡œ\¹‚'OÀf—Œ2ðò— oo”ÛíGGØÙÁÍÍB²RÂìêÕ«‰‰‰£Göòòªé¶T©Tºzõjµš|þõ‡••••U]©bOãp<8[Û‘&“Ö`eh"ˆ7@£Óùtú[íI©Áè’%ÈÎFNÄbüôæÎÅÑ£ ±aø|¨Õ¥rZ4~<¦O­{ö@©Äo¿ÁÚ>>øùgbãFœ:…•+±k*|_b³Œ€(•`³ 6 ?}û"!J>ªRaøp|ó èt¨Õøýw¤¤à¯¿`cƒ°kÄ?bÐ ¬Yƒ¬,DDPç4íÚaäÈ—¯K£aþ|tïF#¦LA` ֬шI“pú4fÎÄÎpuÅ?‚ÍFa!ø||ôÞ{ƒcÕ*´iSÞ}‰Åؽ"vï.‚- ƒ?¬ fm°ÔjµL&£Óéõ¬¨X,ž4iRM·‚ Ðhl&Ó¶¦[AU¦¶£z=-£Gpv†V‹ü|èõˆˆ€ŸUy¨ukܺUÁIzô Â& xþ~r9\\ RY.ÈTWW4n ­ø(ggp¹0×m+ê6 Ñ«­ …xú±±Tß§ùŠ™™ÈÌÄgŸQ¥žÊ™£Yt•ÎA§ƒÇC~>bcñàîÝ€¬,xx@§Cd$¨‹Š*™ ŒN§z:+ìï4Ïh+s^‰L&S«Õ¶¶¶$¿&AAT¨¶£QQ¸xG¢Q#ܹƒÉ“@,FZU±73³â“”œå-¡KlØ@md³Ë ª´ZËK­.§ÓA£U|Q&NñC±íÛcûvªÊ0“ ¡,ÒÒ@§C…ƒŸ%OÈbQ½ž#FP[0™°¶F^ž…cM&èt·Ù¢äd ))0þÊlllpJþAaImOíÄáÀ`@r2¢¢…zõ½{¸|wïâĉʰ<ް0hµxþwîPÑ¡½= \»†gϨÐÓÙ§O#2¿üRq¤X¡^½œŒ;w V#2OŸB(DÏžøõWܿߧ–"™{7#" V#* áá–³,ñù8ú—Ëq÷.rr@£að`œ:…Ë—‘˜ˆ#G¨< ¸\œ=‹‡‘‘Qé–oÚ„áÃßìæ>Ÿ@’½AD…j{Ϩ—fÏÆÎ`0àá.l61~<¶l‹…îÝáèXæál6:u*5 ß±#V¬À8r:ÆŒ¡¶·nqã°?Øl¬XggÌ‹¥KñÍ7ðóƒ­-˜L°±AÛ¶ÔÏfÞÞ°µ&íÛÃ}zžÅ(Q×Ðh4ÿ×]bRO‚Q‚¨%\\\ …««kM7äõ ‚s"‚hx …¨²Yš_—Ë?þÛ¹AÔf5Œêtˆ…D±ø•Òv–Gåxòô,µbýÍed@©„‡HNâõ´k×®M›6u·[€H$JOO×ëõÌ×XïFu™Á`P*•ööö5Ý‚hXj,æ*(À÷ߣGª†P¥„†bñb|ðÁë[ŽßÇ€ضÍrjO‚xEt:½N£<Á`d¾J= ‚¨_²³³õz½°j;9‚¨H£¶¶Ø¾-[âêÕJ;oöî‹EUHª*ÇŽaÀ,YRæZ{‚(ŸR©T¿y„šÆf³ÝÜÜ’““åryM·… Þ•J•””äááAò`Ä[VcÃp4¬­áì ƒ¡‚=‚ÄDØÙáë¯Ñ¸1µRþ¥¾'µ»váÊèõhݳgC @b"¶lA\?¿ò.¤ÕÂß¿ruê ¢¤K—.ÅÆÆöíÛ×××·¦ÛòFìììòòòbccýüüHQS¢!Ðjµqqq"‘ˆŒÑÄÛWóS#33©¤ñ)•˜4 Z-¾ûŽŽX¸*•å=oÝž=˜9ß}//˜LP(0s&T*,X©óç£üŽ­–L%^ŸÑhLJJÊÉÉ©c|4ÍÝÝÅb=}ú4;;ÛTÎK” ê8“É”““óìÙ3“ÉäååU§çØDUÃÁWçÎ8Û¶A&³¼ÃÓ§ˆŠBÏžP*Ѫ<@NŽå=Õjäå!&t:†…PˆçÏŽnÝ T¢ukDF–Y™==«W#* ÞÞUs_D”ŸŸ_PP ‰ÞÚRÜjÅf³7nìì왑‘QPP ­Ú™1Qst:]aaaFFFTTÔ‹/$‰¿¿? 'ˆQëe­¬PXˆÇѯìì,ì› ‡Q…ŽZ´(³ eøâ ?Žà`´hŸ~‚L¹G‚Ë…É”•ßÓÓÓd2ét:òÑHÔ ƒÁ`°X¬Ú3.¯Óé’““³³³9ŽP(”J¥²ˆ¨e´ZmAAANNNjj*‡Ãñööæ[¬º^I5Œêõpw/o¦fÓ¦èÕ 3gbèPdg#:›6ÁÚú÷Gp0¢¢Ð§Z¶Äùó8~]º "nn°±­-:wÆ_`èPäå!5«VY.U€É„•Uy³W ¢B,«žE¢Eh4Á$ˆêSPPðâÅ &“éïï/ kOˆL/±µµ5™LZ­611ñéÓ§îîîR©ô ÿbk25‘•‡òöa±°v-NBr2¸\LZœåþë¯Ñª^¼ "È-™ ÎÎØ³ Ñ°~=þú `2ñÉ'älâpðü9ŒF²Œ‰¨4“Éd4IUw‚ ^ƒR©|þü¹³³³³³3y!j?Æáp5j$“Ébcc8::¾É k,ÍÎÆgŸ!9S¦T°§PˆO>±¼}ðàâ‡nn zy‘#F¼j“úõCH²³±zu™¨aQnnîüáææÖ½{÷úÚ9JDu0 111vvvnnn5Ý‚¨fN…#‹¹o¤½Æ‚Q±ëÖA €TZSMxÙˆx÷]$é=Qi2™,99™Éd’Á5‚ *%==]«Õ6%눺ÉÎÎ.'''&&¦Y³f¯ý XcÒL&||àèXéÂôՇɄ‹ ÜÜÈ0=Qi©©©z½ÞÙÙ™Ôs'âÕ †ŒŒ OOOòÖAÔQ4ÍÓÓÓœâµOBÂ.‚¨F HkO??AuÁ`P©TÖæe¹Äk‘Édááá•Jô‘žžYrËÁƒW¯^]ÕMk(X,ŸÏW(¯}ŒDèÞ½ûĉëzP‚ Þ2…BÁãñÈDó7qõêÕÙ³g«Kæz¬È‰'-ZTôÐ`0>|Ø›”½y]4M$¼öȸ@ƒ”„û÷ñá‡~õÏ?pr*/»ªN‡'OжmõµÎ²¤$\º„qã,üêŸ  S' ¿R© Õâí÷2p¹Ü7™»]›™L&µZ­Ñh Eaa¡Ñh¬éD¡Óé\.W(òx<.—ûæ+ßåry•¤il°rrrîß¿Ÿœœ|öìY//¯¶mÛfggŸ;w.''ÇÇÇ'00ÃáÈåò3gÎdffÚÚÚ¾÷Þ{ ãáÇñññgΜñôôlÖ¬™9½k‡júnê0‘H”œœüڇ׫`ôæMüý7æÍÃ[®€óìŽG‰oYU/7k×bÂøù½Îá øýwËÁè¾}xç2ƒQ“ ‰‰X¸»vA*­ÜlZË—ããѤÉë´91¿üb9Ý·ÎΖƒÑ°0ÌŸ“'acó:%^¢Õj“““srr —ˇ,Ò",½^¯R©’““ܼͩ¼¼¬¬¬Þä„4Ì}z½^­V ¹\®R© ÅôéÓ{õêµqãÆÈÈÈ   õë×'$$|òÉ'»wïÎÊÊ1b„Z­Öëõr¹ÜÜŸzûöm‰DB²¼ ‡£Óé^ûð:ðÈ͇ƒ”°Xps£ª(éõHH€^WW0‘ŸgÏpþ<>ýÄb*r’É “A(„“SåK™LHJ‚J©4D"Ðé0–…NNT’üü|DGãüyLŸÖÖ•ˆØT* ÈχBgçâªÈ˃PP(–†³gÑ­ìì PeK5¤¤Àh„›[™ñ·É„ÂBxy½+çç#) å¿‹ øé'üú+âã1v,Ú·ÇêÕÐh Ñ@©D~>‹û e2dgƒÇƒ»;Õæü|\¸€ŽáàPÜf­II0àáQÞw†ü|xzâ‡Jm”˛۷‡Býû1cÆÛ[&“ÉZ´hñ†‰Öj“É”›››Àb±üüüx<ùÈ$3£Ñ¨Õj322"""ÉÊÅ$‘H:vìx÷îÝaÆ …ÂK—.={öì‹/¾J¥Ã‡ß³gϸqã …Bá²eËŒF£³³³¹uäÈ‘æ“\¸páý÷ß'ÿ‰o‚N§¿I?ExꇇD¥Éɘ3 ­ àßÁçƒNÇŽ‰„ǩĥvvØ´ øë/¬_‘2‚‚0t( #?óçgq*(À’%hÓ¦¸+î矱cœœPP‘?ý¬^Ë—!B¯ÇÆps¸11? V­Â«$¡¡8u T*¸¸àÇ!áâE,X[[dgcútL˜€ýûqø0°|9ll0i†Ej*æÍCV øø`Ý:ˆD.¡ÕbÍüû/<<°kµ16–JïJ§#* ï¼c¹yùù ÁÊ• EH à￱q#¸\h4 Ñpü8„Bܼ‰Ï?‡‹ ÒÒ0y2¦MÃ8v 11X¹ÖÖ˜8Æ!7AAHK±¿üBE¨/1™°|9ÂÂÀ`àüyjcFÌït:âã1j”å6s8˜1›7c¼µBzÏž={ñâ…››[} FssscbbœœœœœœÈ{4A”d¬www‹Å±±±jµÚ××—ŒÔ™™™¹¹¹»víb2™:Î××W¯×Ï›7oݺuŸþ¹@ Xºt©_鯴´´ˆˆˆÙ³g×T› Ô‰L/^À×{ö`Â87nàøq„„à·ß`2a÷nXYaÕ*Lš„Æ±y3Ö®… ÒÓñí·;¡¡˜;ÁÁÈÊ¢Îùèî݃^_|7o""‚z˜˜ˆM›„_ŰaˆŠ‚N‡þÁ±cذ{÷¢uklÙ>‹!(~~ؾ+VÀÞ¾·&“!%?ü€Í›ñü9¢¢ŸeËðÁøõWL›†à`ddࣰz5\]1g¶oGïÞ0±y3 Š]»‡sç,_‚ÍFP&MBRµÅhÄÖ­ q𠂃Ëë>¤ÑÀ` &Z-¤R4oˆÇÖ­øé'¤¥áÁh4X¶ Ý»cï^Ì‹ï¿Gv6†ÇÖ­ðòÂ×_cûvôé“ ;v .¡¡ EAŽ-óºß|ƒÉ“[¼qÇ8t»v¡üY‹Ÿ|Ç—·OÒét2™ŒÅbÕ§¥ô&>>ÞÕÕÕÍÍD¢aF³¶¶ö÷÷ÏÏÏÏÎήéæ4\ ƒN§ˆŒŒ´²²²··_µjÕ®]»V®\Ù£G±XœššºvíÚ“'OvìØqݺuZ­Ö¼bL¯×GEE………ÙØØxzzÖðm4luãcfà@ØØÀÏ@­Æóçðð€Ÿôì‰K— ÓÁÙvvàpàâBu‰ED ;·oãéS¨TˆGn.$X±C©2Kb1öï/(‹ƒÉ„îÝ!#0ÀõëP©°?h4$$ 5 !‘€ÃA…³MÌ1€6m0z4µ±];xz¢ ¶¶Ðë‘›‹Œ ÂÖÝ»cíZ$%¡}{8;ƒÅ‚DB]¥°ׯƒÇúu›‹°0 ná¢4J…ÈJ%îÜÁøñpp€ Ê™±mmU«Œ‡Ñ·/fÏÆÀЬ<=¡ÕÂÛ24DD`î\ØØ o_0™ˆŒD×®àñÀbÁÁj³N‡ `0`ÃÈÏÇ;;Öò¥%’—Ãú+W0x0U"¡[·òžg>_~‰­[ñÑGo£~Ann®Á`°µµåYìæ­ƒL&SRR‡Ã©Oá5ATçææ'‰êë*ÆZÎÉÉI¡P>|øÄ‰[¶lñòòZ·n]ß¾}<جY36›½sçNOOÏ>}úäååy{{3™LooïìììÐÐпÿþ[ tëÖ­Þ¼×Qu#5GôzÐjA§S]zlv™G™L Ѧ 5~ݵkqµ'W×—wf0àãSüÐ<ïÓ\õÞd*þÁÕíÚ@Û¶°µE¥VR2™‹”>6o)Ùfóµ,>|‰¿?µÈ½m[4jôªÍ0ŸÓÜrsßgYèt ˆví0i†Çœ9èÞÚn>¶ä¤OóF: ÊJ÷f2¡iÓ×i3ƒE=t>í#GbÍüù'†­Ä%^ÍØ±c5 »œ¿Å:E¥Rååå5iÒ„ÔÈ®Íòóóõz½µµ5麮q‰D&“¥§§“ÞµѶmÛ   ÄÄĹs纻»ïܹóäÉ“<4hPß¾}i4Ú‚ Ξ={÷îÝN: :”N§wëÖmêÔ©YYY“'Oþ¿ÿû¿™3gÖôM4tuò]¬iSlÛ†äd¸ºâÊøùQQ‘½=ÔjäåQÑžØl¸»ãý÷¡Õ"9¹xVå·ß"77wŽæåá³Ïй3¾ú ¼½Á`àìY ŽÓ§!“@ÇŽ¸t ]ºÀÓ99P(¨P˜ÅBn.Õžr¸ºbá nÍÆvv¸{:áþ}Ô T\.RR`0€Á€@€–-!—cð`ðxHN®`YOI<Z¶ÄßcìX$%áÞ=ôécyO• 7nÀÝš6¥¾ ü‡__\»†wßÅ¿ÿB£9Û¦9ÒG×® ÓÁd" áá<µ"íÕµiƒ?ÿÄ”)P«qû¶ånà"¶¶˜9ÁÁ0 ¼¯+U‚ÅbIо-Õ …‚Éd’t3µ\HHȱcÇBCC[·nmÞ2þü©S§’xèí£ÓévvvYEóÀˆ·‹ÃáŒ*±ŒÀÑÑqêÔ©%whÞ¼ysó<³ÿáóùŸ~ú)€ÂÂÂÅ‹û½^ž¢êÔ`´h]<› ++Ðhx÷]´oÑ£ÁçC£ÁŠT/ióæ°±ÁèÑpsCp0ÜÝ1gV¬ÀöíP«áム¨3iiÈÊ*Z ˆ/î«sqÁüù Á¡C`2©˜µO\¿Žqã`oÜ\ŒÉ“ÀÏžž3ÞÞX¹² ˜x<êÌæÕúæ®Ó/¾À²e8}éé˜9“ pÅb ŒŠÉ“1t(¾ù_!C¨µD«W£M — Ã’%ÈËCj*D«VX¾_~‰‰Ñ·/t:ÐheŽe«Õظ‘šQXˆ… ac6»8¦ ÁfƒÃÁ¼y˜=×®!#sæÀÉ ˜LŒû »wãÝwQ}Ø*•êáÇR©ÔÃÃ£Þ j+•J;;»šnEƒõâÅ ‹åëëëîîN£ÑÒÓÓ>|ÈãñÜÝÝsrrÜÝÝKÆ=—.]jÑ¢©*YS8“ÉT«ÕU5¤ Õj§OŸþðáÃ*9AT>Ÿùòeggçª=mF‹*, (*Ö%ácS¥XY• ­h4¸»GEþ1/Oa\»ÑÑJqÿ>FޤÖÓ°ÙÅÁVIbñ˳?_…ƒõâ–øø”šÀjÆdâ¥ñ7++´hAýl0àÞ=äæÿÖÎmÛB(´œÐÞɉê¿,//tíZÜÝkmM 4Zñ´ Å·P„Á€—W©-æ f&îÜA~~ñoù|tí 6Ûr›ŠŸ±WñÕWÈȨܼÞÊÊÉɹ|ù²ÝøñãëM0j0êÍü׺(22òÓO?íß¿RRRJJÊ‘#G ÅСC[´háââò矪ÕêÅ‹»—~_;sæÌèÑ£ÉüÑšB£Ñ F¥Ê£—Ïd2eff¦¦¦:99‘×#Q˜L¦””.—«/™Š¨Šw®2}öRR`2aêTøûW®øÐÛ§×ãêUDEoiÖ¬jjxŠDOu}=&.]B\\ñ‰]»VÙù_úfR233µZ­½½}}ú´0™L¦rÖÍÕ,&&F.—÷îÝ»iÓ¦'Nœ`0d2™ÁÁÁ °°0**jÀ€%IKK‹ŒŒìÒ¥KMµ™P¯&“BÊTµB¡èÝ»÷› / FËd±«¯Öâpðõ×5݈J¢Ó1o^M7âͤ¥¥™L&2Ã’¨*;wîҥ˔)Sììì¦NJ§Ócbbš6mjÿõôôŒ*ù¥píÚµV­Z‘ÉõF3Ϫé†äryõ½`” ^_‡ìíí}þ;©‚ ^—^¯Ÿ?¾^¯¿páÂÌ™3»tébmm§×ëY,–Å-§OŸîÙ³g}êž'¢A©ÝcÏQ»988)¢ ]¿~ýÛo¿U©TÍš5ãóùl6»ÿþ=:sæÌ½{÷Žÿ¯¶XTT”N§‹ŠŠ’Éd÷ïßïÝ»wÍ6› ⵑžÑ¦V#;»‚¥A4;v ;xð Á`øå—_¤RéúõëÿýwGGÇöíÛ'$$¸páÂðáÃ=z$‰ÜÝÝI¹,‚ ê.ŒÖ°ˆ,Z„S§jºDåeffªÕjRGލB...Ë—/iã°aÆ ¦ÕjCBB¢££•JeQ͘7n|õÕWä¨q………7nÔh44mðàÁz½¾S§N¯2Ÿ>//ÏÊÊê S´FDD,]ºÔÇÇgÙ²eorž'—ËÙl¶ÅY7K—.ŽŽÞ°aC£JÕ0¬õêy0‹;w —ÃÙ]»R9‰òó½OŸB(Dÿþàñ “ ññHL„ŸºtARîÜAAѵ+ll•ŠÊ¦$—ãÙ3´ha9ûúƒ Ñðä ètRy‘ÒÒpñ"T*4kFU„øwî &—.ÍF›6àó¡ÕâÎDDÀÞ=z”™1J.ÇíÛˆ‡ƒŽѸ1ètxô"=‚B®]Ѹ1T*<|;;ܼ .}û‚ÍÆíÛˆ‹…€4i• ÷ï£uk…0ñô)Äb )±ˆ’nܸñìÙ³?üð¥ÚQMž>}zýúu¥Ryâĉ &˜7v­Â ñN:u÷îÝõë×oß¾ýúõëyyy;v|•`täÈ‘{öìqz•tƒeóôôìÞ½ûßÿý&'© -Z4`À€@KõZÁÈ‘#ÇŽ«P(Þ~êU=F·o§ÁÃéÓØ¸ž<Á˜1pv†¯/ärtèlÝŠþ‹ qý:Ú¶ÅîÝHM…³3ŽÇéÓØ¼wî`Ãüõ$üù'6lÀ™3–ƒÑÙ³¡P Güû/®]ömÈÉÁ§Ÿ‚Å‚·7Ö¬ÁÆ ÄÙ³¸{2ö탵5¼½Áfcóf=ŠÀ@œ:…sç°y³å²™!$-["?›6á×_Ñ´)òò0it:ªDªV‹Æ‘’BeªwsC^\]Áç#$ÍšA¡ÀÆ8p >ÿß}‡#—‡qãðý÷$-ÉdÊÈÈÐëõâ×H0K¯¥E‹¡¡¡&“‰c®€LÕC.—gff ­V›——çééÉ`0bbbø|¾F£IMM5™LB¡P"‘$$$ [[Û¨¨(&“¹bÅŠ””6›M£Ñ222är¹½½}zzºJ¥òööO§ÓœœìììRSSŸ>}£T*²³³…B¡J¥ÊÍÍ•J¥ŽŽŽ4Í`0$&&æççs¹\ooï¢^Ãääd™LÆd2=<<„B¡Ãÿ2Q'''k4çèè¨ÕjT*•‹‹‹¹ÿU­VÇÅÅ —¼¼<.—ëääd4òóóíìì\]]K†Ñ*•*55•Çã™L¦¬¬,£Ñ˜ššj4­­­“’’ †¹·2!!A¡PH$’¢ðZ.—ÇÇÇF©Tj.’’’Íçó=<ÅÝ»;âÀ Žëסӑ*š(,,,((‰D6665Ý¢¡`±XäËñ<{öléÒ¥æ.;;ÛÙÙÙÁÁ!>>>::zûö펎ŽsæÌ‰4iÒ_|1kÖ,F3}úô¿þú+??éÒ¥AAAË–-³µµÝ¶mÛ‘#GvìØáëë **ꫯ¾ºpá‚H$œœ|àÀÐÐÐüüüM›6 … &lذA©TúúúÒéôçÏŸ‡„„´jÕêï¿ÿ^´hQ§N›7o¾hÑ"‡óÇüðÃMš4‰ŒŒtqqÙ²eKQûçÎ9xðà¹sç.^¼øÉ“'~~~ÑÑÑ'N6l˜Z­^´hQdd¤——WFFFttôˆ#æÎ»eË–sçÎ5nÜøùóçÓ¦M2dHÑ ãââ¾ýöÛ´´´6mÚÐéô'Ož¬\¹²C‡!!!W®\ñññQ*•YYY»wï>xð`XX˜§§gDDÄܹs{õê•””dmm­×ëcccwìØ‘’’ìïïX²Šïùóç#"">|ûöí/¾øÂÙÙyÖ¬YB¡F£EFFþøã¶•*óXwÔ«`tëVüù'¬^N ÕbåJܽ {{ÈåÈÊ¢BUÞÞðóþWjÒ¬{wjLÜÚ:‚ƒqõ* P@©„Ñ©}ûâÐ!x{#:K–”×󸹽=ø|ªð½ÜÝA§£eK\¾ ­ÿ’“ƒädìØ={`0Àh„Riùü7n`Ñ"ØÚ‚ÃAL Š p¹xï=ªfQ¯­­-ºwó°Ë—ñÝw°±‡ƒ/ ×ƒFÈ ÅÓ§8tƒ ',b2™;w6 ¤Š ˆz¦cÇŽãÇ_µjÕ¡C‡´Zm“&MÖ®]»aÆٳgŸ:ujíÚµ+W®ìׯßG}Ä`0¦M›Ö¡C‡ää䈈ˆ­[·øôÓOͽøŸþù\]]×®]{ëÖ­¸¸¸ððð}ûö5nÜxÇŽ cþüùÛ·o6§SMLL\³fͯ¿þêää4wîÜ5kÖìÙ³ÇÚÚ:((¨oß¾III#GŽœ4i’­­í’%K¾ûî»áÇGDDü\Ô£ܾ}[¥R­[·®Gt:ÝÛÛ{Ô¨Q§OŸÞ½{wÿþýïÝ»wæÌ™ãÇûùù­_¿>..nÚ´iqqq{÷îݼys×®]ÿøãõë×wëÖÍþNM›6 úì³ÏæÍ›çéé¹jÕªõë×;vlÆŒ'Ož4hаaÃNœ8ñäÉ“#GŽœ8qÂÇÇççŸ^¶lY§N¶mÛÆçó·mÛf2™,X`4/\¸ ‘H–,Y’––öøñã’Ïü'Ÿ|räÈ‘1cÆ :À’%K ÆöíÛétúwß}W¥j‰zŒ~ò ÞU‚26—.a÷n´iƒ[·0aŠ d0øï<–’É\pþ<~ø¸wÓ¦QÛ?ú'bËøøXî°,‹@………°¶Fn.øüâY“ &Õ æÍ£nN/®Ãù’ÐP ˆÙ³a2aРâítº…˜tzñå üü3ÞóçÃhćRÛ}}Ѻ5ví­[˜;··Ö0ñùünݺÕt+‚ ªK“&Mlmm †Édêܹ3ƒÁpwwONNЬY³–-[îÛ·oÔ¨QÙÙÙ-Š*S—¡C‡\.·gÏžmÛ¶½pá˜1cüýý'L˜`qá]“&M¤R)Nçw–/_.—Ëœ:uêÏ?ÿ¤ÓéiiiZ­6))I©T¶oßžF£ùûû/]º”Ëåxüøñ”)S»uëF§Ó ƒ@ X¶lŸÏ—Éd …B§Ó…‡‡ÛØØ˜â;vìxæÌqqqñññ›6mÚ±c‡B¡Ðh4ùùùÁÁÁB¡Ð¼¦ÐÕÕÕËË‹N§wéÒå×_ÍÎÎ`gg×¶m[6›=bĈàà`[[ÛFÑh´Î;oÚ´)!!áÖ­[C‡5w[,_¾œÅb}ðÁóæÍëß¿=&NœXÖ“¦Ñhn߾ݳgOó­-_¾œÉd¦¦¦¾îÿg­V¯‚Q7·REç9 HI‹…Daa%NÅdÂ`@z:ž=ÃÎÅõÓ[´€³3ÄO?Yè×,GûöÐëqâZ´À±cèуŠ>y<äæâÔ)4j¸º¢qcœ>iÓ TâÁ|ô¸\ 'ä󑚊„\»†ÿÅäɯÚ VVHME|}”Jåo¿ýÖ¯_?2™¬   ##C­VgffªTªÌÌÌŒŒ F#“ÉÌœ‹/–H$“&M²³³3W³³³ 6wR>yò$,,,))éÈ‘#VVV\.W£Ñ †Gåå奥¥yxx´k×îСCééé'Ož\³f\.ÏÊÊrqqéÝ»÷ǼhÑ¢{÷îFsتÓéÂÂÂòóóÓÓÓÛµkWXXxùò夤¤'N˜ƒQ???©T.îß¿ðàA&“Ù¨Q£V­Z5oÞÜmGGG_ºt)))éàÁƒï¼óŽX,ÎÌÌÔjµ©©©æ±[·njµúï¿ÿNJJúõ×_;wîìéé9pàÀ3gÎÄÄÄ<{öì믿NMMݶmÛŋ۷o?bĈ‚‚ó}}ÿý÷………x<^zzúï¿ÿ¾cÇŽ~ýúýóÏ?ÑÑÑááá_|ñErrrFF†N§ËÌÌ4MΫêUÏèKh4LžŒQ£`0@(,—oÑëÖ½¼ó¬Y/;f † £Ž53“ƒk×0hœË»ô¦MÔÞÞØ¼™úyÄ VVÅáp0kV©«ûúbÇÈå`2-÷‰šùûãÐ!@$*ž` cçΗ÷tqÁþý¥¶x{ãàAêØ¢ ¼°7o‚ÃA¿~åÝ //oÿþýb±xĈ¯Þ%@Q'<}úôÊ•+:îÂ… Ož<éСÃÞ½{ù|~xx¸V«={öìèÑ£y<ÞСCsrrÌÝuÿþûïƒôzýþýû?øàƒ‹/šL¦Ã‡Óh4[[ÛëׯwèСk×®R©”Ãá,]ºÔh4Ž?ÞÜ-:mÚ´#GŽ †¡C‡^¹rÅßßÿÈ‘#IIIR©tÖ¬Yt:}ùòå«W¯þꫯÜÝÝ;uêtàÀ-Z¬]»výúõK–,ÑëõóæÍËÌ̼ví€ .ðù|[[Û 6¬Y³fáÂ…‡:wîœD"Ù·oŸyUÓ®]»Ž;fŽtH$’uëÖmÞ¼9,,ŒF£-^¼ø¿S$Éùóçþùg±X¼páBNwâÄ ›ÐÐP777OOÏ&Mš,]ºtß¾}L&ÓÊÊêûï¿g±XcÇŽÍËË[¶l‹Å=z´¿¿›6m//Ï`0mÿï–W§Õj Kn1Ëå?üðÇ~ø*ïäÿüóOÏž= C~~¾^¯/ç×kg-WXXèîî. þû[¹\~÷î]‹ †Ë—/—uZó‚³úÜ3ZåÜܰ~=ììð6¿ˆÅøøãR[|}«þ*L&¦NÅäÉôøfiiiz½^*•2™äDDƒ3oÞ<'''ƒÑ²eË*<íÓ§O9’™™¹{÷î)S¦”üƒÁxíŽ@óüÎ’[îÞ½{ãÆ ‰DµhÑ¢ ßÉÃÃÃCBB²³³÷ìÙSÎ’£"oXMª"¥•ÀáÀÛûm_T$z)?i4¼Yñ‹†ÅÚÚÚËËËœˆ„0™Lz½^§Ó™{ jº9ñ¦ÌKRØlv )ŒF¥V›úÿìw\UõÿÇŸw°÷^‚¨€PÜšÛiZnùº·©¸pf®rÔÌQæÖL3ÓrfnMs‡(Ê‘½á.îýýqÏO„±\Ø}>üãrøœÏçsŽ—{ßç=^o•*M£Q¼Ò…–. ÊÊʪR¥ŠBqUñò–²³Ë[° ‡F£133ËÎ>ÿÒæýË–ýïÑ£GùùùNN-ííyîZ¶¶ùsætÌÍÍ_éÆÞDR©¥Tj§§gûÚ*‹tƨ/ŒŸŸßs¥Lþ hË233•J¥H$‰D:cTÇ;€6z(‘HLLLlmm---ËÓÓò ¢VË32~ÎÈøU&»§VljDÉ"Ñ«5F¥R¬­ÉÌ,”šyYhej ââ^òÌÅ02Âȹ¼¼ i‹˜Ë?¾â¢ÑˆÀõô:EÿF£T¦*©2Yhzúáðð=.._XZv|¥‹¾SoØèhNœàíéP°u+ññÿäÄ«W¹wïeïæ¥’“ÀDD¼ªùÕjú÷'<üUÍÿoÈÏÏ*üößD¥REDDDGG»¸¸øøø8::š™™è,Qïzzz¦¦¦¶¶¶>>>999¡¡¡Ze¢·ÌÌ“÷ï·†Ýի˱°ÀÈHg‰êøWˆDèëcjŠ­-žž‡»õ‰§V翺Eß©÷ì¥K,\ÈÛ`'$&2>ß|Ãĉ|ù%ùeþj˺ŸeçNŽ{¥ü·= àïÿªæ××§}{–,yUóÿΜ9³uëÖÈÈÈ7½‘7ƒF£IHHÈÊÊòõõuttü{ˆu¼ó˜™™Õ¨QÃÜÜ<""âmkƨT>ŽŽæèåéùbMXtè('b1vvxyååæ~“”´áÕ-TBÈ‘‘¬^-¸û÷§sg4Nžd×.²²¨[—qãP«Y¸?ÿäþ}‚ƒ±¶fêT¬­K˜-"‚Í›Q«yðWWfÏÆÊŠ¨(–/çÉ$ºv¥{wîßçÛoINÆÚš¼<Œ™?33Îc˲²`ìØRËêçÏG&£^=7F©¤ €ÇùæT*îÞÅÎŽyó„®÷ë×sþÿÀԬɲeÅ5üß,jµ:"""%%å?Û’>'''!!ÁËËËÄÄäMïE‡Ž×T*uss {Ê5elìSÓh{û7½ï:FF¸ºªÂ–:8HÓÒ^ÉÀ«±t)„„0r$ææ×¯3nMš0i.°m´oO` vvtîL‡—<[B_¹9&pá?ÿ •E­Z„„Ä‚üõ±±>L“&ìßOÓ¦œ9Ãýû„†L` “&qý:ë×—ºçˆêÔÁɉ–-5 SSÒÓY¿©”à`nÝbß>€Ã‡ùæ† £}{fÍâöm¬¬èÖ OOjÕ¢[7Z¶xøQ£ðócÂÂÃY·®ÔuSRøøcBB¨S‡ñãÉÊÈÌdåJNbÔ(Ú¶EÛµáÏ?™=KKÆ:0%'óÑG„„а!£F‘Ÿ­-ë× pèÇ£mE&—óð!Õª ‹ªÕ=Ê?2z4õê1eŠp0;›±c™2…ÔTæÍC­æ§Ÿ°³#'‡k× dÃÔjBBøóOBBhÙ’ Ûîîèëó×_χ¼NÒÓÓsrrÌÍÍ­^Q¶ìÛZ­Ž‰‰±±±ùo^¾Žÿ,R©´J•*‰‰‰oO°>#ãhvö·W^X¢C€™ÎÎY}û¾S´B£ áá$$àêJÓ¦bo·7b1 pì"Í›S»6ÖÖ´nM‹eõ.ru¥š4¡~}!5³Z5œœ8q‚[·P*yðÀɉF°±¡aC¬¬ˆ‹ãÐ!ôõ©]±˜F8~¼ÔüÔAƒØ´‰]»Xº”?ÿ¢ðNNôïOÓ¦´iƒ6ÆûË/´iCÇŽô뇣#§OcnN»vT®Œ·7íÚ ®Í£G‰ð÷G$¢U+*õÒÚ·''‡£G‰'9™˜ḥ% й3ÇS³¦p00Ù³éØ‘€6mÈÎæèQbcÉÈ &†*UhЀD&ãûïéÓGˆ¥¤”„‹Káºb1ÿûM›2|¸pizz|ø!7npì þ) kÞœ€4 €ÔTòòرƒ®]Q«ñõ¥ €ë× §õò"6¶Ô‹}#¨T*;;»*Uªü7=£Úª''']zhE'22rÑ¢E;wî|zÎÍÍ‹‹{¶E¸Žg133355MOOÓÑ¢NO?`g§~[«ªt¼kˆD8: ø¤^: L?}:+VÂê IDAT0>3z4‘œÌ×_ 4(žsY6Ria~·Ö·t)¿üB¯^fÞ˜™ñ´˜‹ r9Éɤ¥:D6D./¹X¾G™;™ŒÁƒùþ{Á³«§'d‘&' ㆆ“˜Xò†ÉÊ*\Wë.ý;ÙÙŒXLË–Â>m]kjJ•*ÅÇk­y-yyŒƒJEëÖPP@V1c:ñ×_…YCC¤Ò"¹¹Ú´þ_üˆŽ¦sg>ú//ÌÍ‹ –H {¦¤ Trì§NÔ«‡™Y‘+zÛ´ú÷ï/—Ë%O¯á¿„L&‹Åï’§ãe±iÓ¦÷Þ{¯ú«’°°°‹Å»víêÖ­›VñûðáÃgΜY³fÍ«^º‚"‰ÌÌÌrssßôF4š™,ô™:t”ˆD‚¹9žž¯dò·ì«¾$llXµ ™Œ¯¿æàA¤zuÒÓÙ¼4òóÈеšð`â£G3`Ož°re©ÃªUÃÃo¾Áȵ¥’Ò¼cé鸻ãéÉG1r$QQ”˜h俯ƒBD;5µÐ^”Hx6-ÃÓ“J•„uµ×["™™DE±{7>>\ºTV4_˳Թ¹Ü»Ç¾}x{óçŸ,Z$oÞ==&O&0wwá ™NNÄÇãë[êä·oãàÀòåh4,XPê0GG¬¬¦qcaOU*bbðö~ÎU¼~¤Ré¶ñRvv¶‰‰‰Î-ZÔjuvv¶™™Ù³5^¹¹¹"‘Èø™,¢üü|FóôȺu묭­Ÿ£jµ:''ÇÈÈèïºB999b±X{¢B¡Ë妦¦Oÿk òóóŸýÏR©Tyyy¦¦¦ÚýØØØÔ©SçüùBùîƒvêÔé¿ù”UNLMMŸ`ï^Æ£^=ÂÂðócàÀ’GÎKNÑÑܼ‰©)µk—¬ ܳ'ÇóÙgdd Pж­pÜߟ… Q©ðð`ÈÚ·gÇÆŒ¡qcBCqqaòäf37ÇÅ…åË©U‹}ûx¡®FF¸»³t)þþüðCáqKK:vdÕ*öî-ú33ºtaË*UÂɉ „?×èÖ  E ¾ù†‚ììØ²¥Ð3Ú£«WS©¦¦ÎÎìØAÆCF§åT6•+Wؽ{÷ûï¿¿lÙ²ôôô… j4šýû÷oݺuΜ9óçÏß»wïÞ½{,X0iÒ¤/¾ø">>^©TvïÞÝÞÞ¾k×®!!!ŽŽŽëÖ­ [´hQ=öíÛ§Õ¼üä“O.]º7gΜªU«ÆÄÄ÷ïßÉ’%*•jñâÅ*•jáÂ…¾¾¾K–,ñöö¾}û60kÖ,‰D²dÉÿ~ø¡M›6–EU*._¾\¥J—g3Áuü7î} È!£”¯ÉŒñôä¹þôC‡(úøóV#•²e «Vý“@ë;²þþ¾‰2Œ^Õ©žÑ-hÑ¢øAWWÆŒ)~P,¦^=êÕ+k6''zö^7k&¼°°`Èâ#µõÞ½Úµ+\wôèçïÙÃîß§E ¡VÝÚZ0@À@á…DBË–%µ††´iC›6…Gœ>¼ðÇŒ Á|:zzxx0ujñÙ,, *~ðïwÉÍiÓŠQ*ùãÖ¯gÀÁ,~ŠŸÍ›JƈŅÏúú‚—Z,æ½÷xï½"giMggáGí–JéÔ‰NŠŒÌÏ'=½È%¿ ÄÆÆFGG»¹¹½MßI:Þ.Œœœ|}}[¶l)‹ûöí;mÚ´/¾øb÷îÝ|ðеk×}ûöuîÜÙÜÜ|ÆŒ={öœ?¾‘‘‘‰‰‰£££6LÿóÏ?÷ë×ÏÓÓÓÓÓ³nݺvvvffffff‰dÔ¨Qß~ûíŽ;²³³/\¸põêÕ¼¼¼?þø#77×ÕÕu×®]*•ªmÛ¶Õ«WÏÌÌyy¬XÁŠ…e¾ÅhÞ¶m{±òhÿ˜ à­¸¼ºRÇÞ½‹ëÅâWb·YZ²gÏËŸ¶‚"—ËÕjµ………½NcZÇ󈊊ÊÌÌ´²²ºpáBíÚµ%I½zõN:5tèP‰DrùòåfÍš¥¥¥mÛ¶múôéC‡mӦͭ[·´~€Û·ogffÖªUëܹs½{÷–Ëå-þ!‚5jäççûûûW©RåäÉ“çÏŸÿè£V®\9tèÐîÝ»/Z´èĉƒvss»téR```llì£GŠMróæMGGÇJÿÕü¸ŠŽDÂúõdf’“ƒHÄÎãäÄæÍ¤¥ ¶à‘#B&UiLŸÎ V£P0s&¬XDBV{öàëË—_²r%=z_˜Ê?dˆPóú””?¦wo|}™6Mß/XÀ† \¿Îа˗9q‚~ÀË‹&M˜9“„ŒR•Šñò"'‡Òt;V¯¦cGæÎE,&7CCÜÜX»–ÔTd2>ääIZµâÞ=Œ ÂÉ CC$®_çèQ6o¦F ZµbêT. Ö=‹¡!C‡2s&C‡¢s} èŒÑ ‰‰I©%A:^ýúõÓ–“¿é½èxÛÑh4ÁÁÁVVV—/_^·nX,;vì!CÆŽ«ÑhrrrÆŽ«V«>œ˜˜hdddllܤI iÓ¦»wïÎÏÏ1bÄ”)S† 6nÜ8…BñTk}„ FFF“'O^»v­¹¹yƒ :uêìããsóæÍO?ýTOO/22rüøñ^^^·oßîß¿¿¡¡áœ9s,Xžž®Åß½{wãÆ±±±Û·oŠŠjÔ¨‘Ù³²j:*r9&‹½=¹¹B±ìÝ»Œ‰Tг3憕FëÖb1††„†òèƒ$%áçGb"éé‚|Š‹‹{V"•+Ó¹3cÆ`bB³fÌœ)#"‚ìl>û ‰¥µºÐCY«–`üý̓/ Pp÷.ƒ ¹ÚÏã‡?…{{ÂÃqphтݻéÓ33‚‚0€„’’øüs¤R”JŠBŸîßiÕ víbêTt™Y¯1ªCGy144Ô%Õé(sçÎMLL qvv´…ð¦zõêÚXù/¿ü#‰fΜ©mj5kÖ¬»wïøúú>~üø³Ï>355µµµŠŠrppF=bÄ@+k ‹—.]zïÞ½¼¼¼ñãÇ;::_ýuDDDnnîèÑ£]]]:øøø$&&VªT©ÿþ@åÊ•çÏŸ¯ÑhÌÌÌ&Nœ8õïÉæ:*W®pó&/bcþ}̘FÃúõÔ®ÍÚµèéѯßó'y¶ÉƆʕ ,033lm10 % ;›2„ÿ¥R¾úŠØXnÝbìXš4¡KáWJ%0§¹9vv|ú©`ªJ$…mŸ­¬([«@_ ‹âº7ûöaoÏ7ß`lÌÈ‘ÂÁ*Uøùg"#ùõW–/§MŒŒprbútll„uˈ˜™1|8‹1p`Yö·Ž—ÂÚ}ð€;w„ªšb\¿Î‰…ÕKoŠšBuëö|‰¯78~kk¡è¿Fv62¶¶/ÿAV­Vë Éu<—ØØØÃ‡'$$ܹsçƒ>x¶ÖÍÜܼNÑB;;;»¢B)FFFuëÖÕ¾¾}ûöìÙ³ÇwêÔ©œœm˜¾jÕªÅV”J¥5ŸöUÀØØ¸V­Zņ¹»»»»»ïÞ½;66vÿþýÚ2)µZ½aÃóýW:*Ú®"11ÄÆ²v-€H„ƒ·oɃ?ÎßÞ5eÑ£Ÿ}Fr2NNܹƒ£#..ôèÁ‚H¥üü3Zá…‚ÐPîßG.çÆ ìì¨^˜Σ~}<<°´,ìZbgÇœ> ¾¾4lˆDÂÅ‹tè@f&‘‘…:ÖåÜá7ßP»6¦¦Ü¿O§N˜š’–Fd$±±üú+½zœ?OFU«R­ææH$Ô®¥%çÎÑ­„‡ãêZÖBíÚ±zµÐìZÇ+å2FÏžåØ1fÏ.¯Ph(Û¶•lŒJ$rîqqÏ7FoßæûïùüóÞp9Ñ×ÇÐÍ›©VíùÆèÅ‹:ôêÐ"!áÍ׿߹ÃäÉüòËK´“Ëå‡vpphذáVñ^Gy066îׯ_ß¾}]\\þ¥êB³fÍæÌ™igg·gÏçSÛ^ww÷+VO•2Åbq1™'‹Úµ6ŒI“JùàââFfÌ>ùSS&M*«kމ \¤¾KÒÒøâ CCfÍX°€+øòKjÖÄÎNH']¹’ü|ê×gÍ<<˜7‘ˆýûÙ±•Š?,TÂiÓ†+WX·–.ÅÎŽM›X½š£GÑhèÞ]Ø@åÊÏÑÃÑ2r$j5Ÿ~ŠZM£FtêÄÿþǽ{ciIP>>yy¬\‰D‚¾>Ó§ãä„Dºu¬XÁر¨ÕtìXª ¤++†gíZºwGW,ðJ©_«ZJ‰{{!D©$1‘ü|lm±²B­&)‰¿þâÌââ05þZJ$/Ç‹‹ÈÂçæòä "..à營R)Å*\•J’’ÈËÃÆkkÔjRR¸wÓ§‰G*ÅÖ‰†”2312ÂѱÔää VcnŽFCZffèë ¯ŒHJ¢ {{AôÌ™òÞ®êÕéß¿ðÇ‚ž•* ÷J¥"533á®Vª„ž2ññ¨Õ—*SP¯*;w2fÌËtŽ&&&Þ»w/--­~ýú/mRï"¶¶¶<+áû/033{YS=¥Q£F/wBo±˜™3™9³ÈA{û"íKÊÀÞ¾x¡ªXÌàÁ \ä`v6ƒcl̽{lÞŒ«+VVlÛV|6ww,asóÂÆ~Z4`çÎâÃJTr,q¶iÓŠhÚÛ³iSñaíÚ•àKª]›-[ž¿ÄSÚ·ç矹wOgŒ¾Z*€1zäK—"•¢RÄàÁÈå̛Dž H¥B†Šµ5!!ܾM|0dHɆÑöídf2m¹¹LšÄ„ øù‘›ËĉH$„…¡TÒ³'!!ÿüî)•|ý5?ü ´]¼öìáÒ%6m"#ƒáà ¢[7¦O'&FHè®S‡eËJY½š={05E­fÍ´¡¿½{9yR0pµšöãÇC~>ññxx¡¢b¨ÕÌŸ‡ãÇ£ÑÔŸÎöílÝŠ2íÛ3}:ÀãÇQ¥ ÷î¡T²nuë2|¸`›æçóûï%›øzzŒÍŠ ÀK¬ÇˆW©TŽŽŽÿåöK:t訸¬^MTTá66̘ñ¿à³üñëÖaf†\ÎêÕ¯IwoçÎ"¥ú‚¯÷uâàÀþý¯uÅÿ&Àݾ–-™1ƒÜ\!UåÐ!f÷n¼¼˜1ƒ5kX¾œ•+Ù¿ŸmÛØ¸SSJ‹;>ÌpàVVôé#üüs$D&ã£8¾PÅýYNb×.¶m£F >ûŒeËØ¸‘Ï?çôiV¬`ëV$,,xü˜Y³1‚Áƒ9s†Y³èرdñˆ´4¡½ZÍãÇBYŸZMx8nnìØQÜ}û¸t‰µkÙµ –/gÉöì¡wodÁRS15¥kW4bc15eóf?¦sgÚ·§zu–.eçNš4aìX¾ø‚Ý»22øí7¾ÿ__¢¢¨R…­[Ù´‰¨(¾ø‚Ò‚Ø M›2>Ÿ|‚BÁ®]¬\ Ф -Z`kKd$Íš1|866(\¼H§N,\HFvvDFrìý…ááe}†öìÉÒ¥ìÛ'Tƒ¾233õôô\]]ur÷:t計ԩS$/ÓØøÅbG}úо=*¦¦¥*.½t|}‹øLMŸSÛ¤£âRŒÑ€6oæÁ7ò;ÏžE.gÓ&D"""P(P*±±Âܶ¶eÉ]¹BÍšT©‚HDË–\ºDN.àêÊgŸdgó×_%£.ŸÏöí±±‚ùhe……zz<­CxôˆG¸|™{÷ÈË#%…¤¤’ÑÒ04dðಲ|ÊÏåËäç³k»v‘˜ÈÍ›¶¶¬XA‡X[s솆ÈdˆÅt숹9††øøpãr9 -Z Ó¼9sçNÛ®LѺŸíì05ÅØ˜²»Ö¶m˸qܼIn.YY ©©,[VØu-+«°Îqüx …[§ýŸíÕ‹¦Miݺ¬||ccFŒ`ýzz÷~išÍš5óõõµ{EMyuèСãÓ´é¿áõw– àu/ªãPŒÑ±c äâEÖ®åÆ ¾ú ¥//š7G$¢yslm)ì´  pð³ÞµúõÑÖ°6o.ä>ÿ†*UhÞ\øÑ¢Р¨ÑŠVh“›4Dï»t)l:ÿw”ÊÂÓŸ¢¯_²6Û?  €Ê• ÷ù„U«Ë˾=:tèÐñ_G¥"6ö…û^¦¤AD„ð òË…šÔ·¬¬âR¦o'©©DE &J…¦£_|A¯^±q#={bdÄÇS£ƒÓ¯½{sø°0²fMLM6Œ±cIM-y¶®]qwgà@úô!!AÈž5‹ðp‚‚è׈·l‰JÅÀ,[о=3lAAôíËÏ? Ã|}ñð`øp&N$9BBX¾\˜ðÓOK}£´nMv6½z1k‚i+ciY‚¯wð`ŽaÀŽy»×¢ݺ1x0AAôêÅ–-(¬Z…—£G‚¡!ëÖH¥ÜºEß¾ DÍš´l‰—ƒ3~<}úpá' s•BÞ¬ħŸ>g?VV8: }í¥RFb‚‚X»–ªU…ç ‰¤°x_˃tïNß¾akKQ¹Æèׇ9}º|·©L._¾|åÊ•ììì—0—:t¼e<~LÏžEb_åáûï9’.]øþû玊’Äžåî]FŒàíüd=p€%Kþùéqq/ €SŒ„._.×Ș>üQ£¸wï®õöPÂôË–‡L†³3îîˆD˜š²~=‘ ^^ÂHggLÉÒ ˜´jZÁ&wwÁL¬^={ˆŠB&£R¥ÂüN77öîåÉÁ445eÙ2>$- këÂummÙ½[X×Ú {w5âÑ#ôõñð(µð°Z5~ø¸8\\Ðh„Ø·±1K–”|Ùª$%='/ ã»ï„òCCæÍãáCRS±° Z5Äb†ÇÉ }}ôõùî;Áp—J™;77$||oîçŸÓ§yyxz Ö€=JøØª][з*»E‘¡!Â-‰øôSºvE.§jURS·´‹‹›û”zõؽ›äd ðñy~7TGGFbëVZ·.µ¦ª<¨Õê«W¯fddT®\Y×/Q‡ï¶¶ÌŸ_\ŸD&Ê JûH3†1c.ÁÛ"—£Ñ9ñøq®_gÆ"ÃÜÝ ÁظøºMñp¢BAAÁK«P(„T4©´0'—£V.!“•j%Ëdèë?GˆàìY¾úŠ‹K8WO¯TµG-üÁÖ­ÂeÙüù' ?ýôœ¯Ý A0FííKÈPÔ×§Fãíýœ MMKˆ8››ãçWòà§F' •–<¿¡aq9z—B-ÌÔTÎ+ò[??!bîêZ¼„XLåÊ%,!am-»eФ ùùE.ßsõê…¯ml°± ù‹ß©ÿâKhsaÿŽ¥¥ð  Rº«µÔ¬)ÜF‘¨øÕI¥…)êO½¡úúÅï§ž^¹4ÿŸ%8X”ý7¤¦¦æååYYYY¼-“ЉR©ŒŒŒ”ë²"t¼CˆÅbwwwÓ׬$ô*ÉÉaÞ<22P(¨QƒÉ“‰X´ˆÐPLMiÕJ6w. ÄÄP§wï2|8:°i•*Ñ¡Àÿþdž ÅH-ÉɬZÅǨT4mÊÈ‘äç3k7n–Æ€XY±`¦¦¬[ÇÅ‹88P·®à›P«ùá¾ÿ•ŠÎ0}}Ö¬!'‡»wIMåÿ£W¯øHÏÉaõj""((À×—ñã¹}›/¿D¥ÂƆœœ™5 CCöìáÇQ©hÙ’áË\ÚíÛ¬[Ç A4h@D„ÐìÔÊŠ‰K./IIaáB®\ááC ÀÒ’éÓqt$2’¯¾"&KK&NÄ×µšcÇ£S,fÚ4,-ùä2 IDATâ ®^%"BP'œ6­¬†¥‰‰BÍñ;@0Fß’’Š«ìŽQVUÓ¿Áß¿óñ¹èë3uêKÛ’BQüz,bÓ¿LM_Ìx-‘ÔÔTFãää¤S-ƒ”””Î;?Ðv­Õ¡ãÀØØøÐ¡C­žÚhŸï¿Äþòòˆ‰vê„§'3f V »óçiÒ„¤$.\ KÖ¬¡MnÞ,,W8t¨d1i 5¡}p0®®tîLÿþ˜˜ΰaèë -[µB_Ÿo¿ªx›7™>yó°µå“Opt¤sg®]ãÆ –-#<œ%KhÝúÊgçÀ¾üàñc4žøàƒ?þøãMoä%Ó£‰‰lÚÄôé´oφ e…¼Åâ’SUª²lÓ_eêTzõ¢^=îÝ{±*ïÌLìí_£¡¡B›XL^^¡µ<´oOB;w2g-[–êÍ}òcca]îߎÇÇS£çÎ1z466df’’—_ IÚŒr’šJZ«V ¢ýÞÞˆÅØÛ³p![·2t(††lÚ$èK–“„²³ß€øë+¢TÓÿòò^‡l„Z-t‡*çZ*•£ù–#“‘“Cnnñr%¥’œœwAKB‡:þ;H¥L›Æ™3ìÜÉÎ/öå( _[ááE,B©”¬¬BóôìY>üÏ>£k×"óK$¤¥=Ç”tqT ¸W×U{ªÝÛèÑ?Îöí\¿NbbÉêT!5•ÌLÔjîß/¬jèÔ‰mÛÈÉaéR ¨\™/¿äàA~ú‰o¾)+±M*¥ @0¦77\]Y¾\8wÓ&ªVE­¦iS¶oçìY\\ «ï%’“ Ï-33æÏgð`ޱ{òÖòŽ{FGbîÜ"=Ð^Lš„¹9 ”k­ßçòåçH ½q”JV¬àÚ5d2fΤqãÂ_9ÂæÍ88/|–ÈH=â½÷^ÃN_!NNN‰‰‰YYYæ/« :t¼!vìàî]ªV%,Œúõ‹IKcéR22HIaÆ lm™<¹äsýüøòKD".^,¢uݪ3g’™É{ïÑ¥ ,[†ÑÑ\¼H¯^°jÕX²„)S°·'8˜ÔT6m"&†˜æÌ¡reFŽäý÷Y»–™311áòår)F•;}œ=KíÚ*yس9%÷jöó+®±øTmÐÐ>@­&%¥H€††Å»@YX``€§'Ÿ|R丳³ #®½¨Ö­…ã¾¾ÅûK?­‰ ƒ¦¦En—RIzz‘³,-…¬P©” hРðWÆÆÅ/ÙĤÐsü, ‚)\6µk#1p _|A­ZÏÿ6óîÞ}ú):qó&»v±k™™|ö¾¾èé1bŸ}F·nÜ»ÇÀ´m‹±1‡ˆ‘ŸαctêÄ¡C\ºÄâÅ/¿²y3ÑÑT­Êž==Êúõ>"—ÿØz!ôô˜<™Þ½;¶,™´·kkk###ûòK‰è¨àh4š;vìÝ»W&“ 4(<<|ìØ±6ź•Dnn®L&+ÏȲY»ví¾}ûvíÚåS¢†á[CAAArr²­­myŒæüüüÌÌL{{{qI.\˜;wn¯^½>)f8èÐñ723 .Ò¨ó½÷hÖŒÏ?/2lÎ5z囹w¯xVâE…²Ù¯*U8r„„„ÂN=—wÊÍΪjž>#FðÉ'$'Ó¨W¯Ò¶-ß|#¨Näå±?ݺXÌÀTª$ˆ\„‡óý÷¬\I½z´oÏøñÄŽ@ÄyÜ8ÒÓÉϧV-fÏæñcŽA$bÓ&¡‘fBB©çn܈·7ë×£§‡\Žž§NÆéÓTª„ß~+¨9Ô¬É×_““ÃGI:¨T À¤I\¿NÏžÈå%¨ •Z͇²`"Q‘¬ Fƒøø°u+3gþÛ©Þ*•êðáÃóçÏ7x¡›¨£"£P(.\¸k×.™LöäÉ“¨¨¨ÜÜÜò˜˜GŽ9}úôÚÒêuËÍÌ™3÷ïß/{ëÁÒÓÓ‡ ²nݺòÄ .]º´dÉ’½{÷–˜{ݦM›ß~û-¹B4×ñ¦±°`Õª"Å=Ú ø¶mE†•–úr©^½øº¯¿¶ÝÌŒw£3à;eŒ®[Ç¡CK—>i}×vv88ðà5j0f ÉÉØØðè‘`_âáAÏžX[Ó£ÇOj*Ë–¡¯/Ëçä”wr9K–ðë¯ØÛ£Pµ‘‘x{ ošÚµK5F §];A=ºsçŽF£©Zµª———H$RSSoܸ¡P(\\\¼½½Ÿ>ùdggÇÇÇÎÎÎFFF>ŒŽŽ‹ÅZW}AAAXXX\\\¥J•,--sss+W®ldd{÷î]©TZ»ví¿;õóòònܸ‘™™ieeåãã#‰ŒÓÓÓãããÝÜÜjÔ¨ùàÁ???kkk !!!44T¡PT®\¹zõê"‘(***>>><<\{P,ß¿?&&ÆÒÒÒÏÏïÙ€»L&‹ŠŠzüøñýû÷]]]e2ÙíÛ·SRR,,,|||¬ŸÛVN‡ŽÿG,.¹àQ7Ö×/ì’­ã_òN£ýúѾ=<“í$%(•deamÍ/¿ RqâffÌËööìÞMD¿ÿÎâÅ´n©©PFçæ&ÌSþ̘~ù…õëiØë×…ñÖÖÜ¿OAÁsrF%,-yü¸ÈA rs11!1±¬¶ìRiyÿ&µÆ«RY<Õ¦""Q©-zŸK»v¸¹±e “&ýÃtèøg9räÓO?õ÷÷wss;{ölëÖ­322222òóóûí· .Lš4©yóæ .Œïի׺uëó<ªP(&L˜‘‘Q¯^½={öôìÙ³cÇŽÁÁÁ>lذazzº½½ýðáÃCBB:vìµjÕªï¾ûÎÚÚ:((¨J•*Õ«WŸ7oÞÔ©SßÿýÓ§O§¥¥;v¬R¥J 8|øð×_ݱcÇ[·n999-Y²äi´´+W®¤§§:tÈ××÷ã?ž={vXXX‹-~þùçúõë/]ºô ¼?tèÐñ6ñN£•*•ž¸e ¾¾\¼ˆJEÆ\¾L^‘”Ä?=*CC¹{—zõ¨V CCD"¡vççŸ4ˆìlþú‹nÝ(g?H}}Äbbc±´díZ22ZµbûvŽÅÅ…½{)CF½{wfϦsg*WæêUÞŸÚµ)(`×.7æÀ:uúg·§GGnÜ 4”°0ÂÂÊ©§‡·7?ýDíÚ¸¸¼pìC_Ÿ‘#™3‡áÃ+X(A.—;88XXXˆŠu&ÑQAÐÓÓëׯ߲eËFŒÑ£Gùóç=zôìÙ³uëÖMLLìÞ½ûÕ«WÓÓÓ]]]?~Ü®]»N:åååM›6môèÑîîî*•jùòå€ÍÇ|àÀM›6ÙØØœ8qbëÖ­ÕªUûè£Úµk—””äîîÞ¹sç'N̘1C»ú¼yóúöíÛ¯_¿¬¬,+W®4iÒdèСíÚµ‰DÛ·ooÒ¤ÉöíÛ W®\©§§çììlüÿ%ÊIIIÛ¶m 7nœT*Ÿ1cF³fÍD"Q¯^½Î;×µk×U«V 8pâĉùùù¿ÿþ{ÇŽ+Uª4oÞ¼zõêMœ8èÛ·ï?ü0bĈ¬¬,FchhxãÆ3gΜ:uÊÙÙ¹qãÆqqq5kÖ|ï½÷ ¾ýö[­ sÖ¬YmÚ´9r¤L&ëܹóÙ³g»víú¿ÿý¯Aƒ¦¦¦‰dï޽ݺu0`À?þ8jÔ(OOÏŒŒŒ+VL˜0¡C‡?îÝ»÷ýû÷ýþ¿ÅÙÙ¹k×®7nܘ4i’……Åõë×>¼ÿ~ŸÖ­[¿{Âò‹‚‚B±##!‹ì…xò„“'éÙ³05îíG¥âÏ?¹y[[ºt)kçqqœ\h«E©dÖ/Ç‚3ðòBO¯¾bñb¡-X—.ÏÑMÐhÉP«‹©\™)Søê+”J7¦KŒ dòd,@,Æß¿,c´sgÒÒX°€ü|||hßž*UøüsÖ¬aÓ&êÔàʕ…-I$‚\…ö…öÆÄ„–-K µ·hAóæ DÕªô쉀TJ£FÂ마DŒÍ’%L›ÆÈ‘‚¬T¾€¶Y·n,[ÆöíŒ]ÞSÞ?~\·n]333]Œ¾B#•J]\\sssooo‰Dbhhhll¬V«ÅbqÿþýÛµk÷èÑ£;v•=•­­-Ю];KKË)S¦tèСfÍš³gÏ.q¼¶•¹¹¹‡‡GxxxíÚµO:õóÏ?{{{?|øPô¿~ýz­Zµôôô€!C†<=7$$$))iêÔ©Úò äääÍ›7{xxxffæÈ‘#ÜÜÜÌÌÌÛ·oÏ™3G©T¶mÛÖÁÁÁÎÎÎÌÌ hüŒt°‹‹‹¶˜ÝØØøáǹ¹¹ýõ—öî%%%åææ^»vmÇŽµk׎yÚÑüžôéS|Ø!<óuS* ÎðáEvï^\€ã©H„¡!óæ ¯çÎ^¸¸°}{©K˜™•pgLLJ¸3€³sñãG²f å”76fÊ®_/×à·‡øøx•J•’’RðR>„t¼˜þÍíãíí]¯^=mt¾iÙ­ ÿÆñãÇþüòËÉ“'>|ж2OKKÓ&Aj 2µZ˜˜hccsöìÙß~ûíþýû–––ß}÷ÝñãÇ77·øøx­e|åÊ333m}HHHhhèˆ#>lcc³yófKKË;wêééݽ{W»{{{mÑZ­Nÿ›víÚMŸ>]$]¾|ÙÈÈÈÛÛûÛo¿Õh4FFFçÎËÏÏW*•@TTTTTTK­ÂÍÿcdddii9dÈ'Ožôôô¼uëÖÑ£G:äííýÃ?ìÙ³çÙSrss MLL¾øâ‹† ªÕêÇkML…B!•JÅb±X,ÖF²²²LLL”J¥¶,ìÉ“'·nÝz¿Ø—³Ž×ˆBAX—.!•²v-Ó§sü¸Ð-)3{û VF†P;af&h¦¤`cÃÚµÅå0““‘ˉ°µ-Ù'’›Kz:GŽ`jЧ'&&BéBARr9vv…_1YYde˜šbaA~>ii;†£#vv•å³LO'%œœÐÓC©$%…sçptdÔ( J x¦¥FZ³gãjµ è©­-ÎÊÂιœôt¤R2317ÇÖm,­ €ädT*¤RlmQ(HKãÌ<=©Qcc¬­™ªêÕ )²´¶ž‚¹œšŠžiiH$8; Â> … r%‘`k[ÞÈí[Ë;nŒ¾´R½À I>Ío¿þhjÊàÁÅ“o' àêZ(zü\úö¥oßW¹¡WÀ£G€ØØXMÎ:ÞbÔjõ£G E|||zzzrrrFFFbbbFF†B¡ˆŽŽvvvÖÓÓ0`@PPТE‹$‰F£‰‰‰Ñh4ÑÑÑöööiii2™,>>>777>>^{–»»»F£™2eJïÞ½Û·o_µjÕ¼¼<ÀÞÞ>::úÖ­[³gÏÖ:·lÙâîî~þüy##£fÍšEEE©Õê‹/zyyíÛ·HIIéÑ£GÏž=Ož<éèè8a„õë×ÇÇÇËår“ààà#GŽL›6í³Ï>suu½páÂÝ»w³²²n߾ݼys™LÖ·oßí۷׫W/44ôÁƒÚ«îׯßâÅ‹[µj%•J'Nœ¸víZ‡ÿ/²hРT*Ý·o_‹-V¬Xáç瘚ššýäÉmvéàÁƒwîÜY§Näää%K–lܸÑÌÌL£Ñ\¼xQ$ýôÓO999  …B›WÔ¹sçµk×ZXXÜ»woëÖ­Mš4‘Éd'NlÛ¶m·nݬ­­E"Ñ7¶oß>eÊggç;vôìÙsãÆ666ÚtU©Tªkuö¦¨úìu\TYÇwº`fèn´ ÛUQ±»cí^]׎5×\EQ1ÖÕ×XŒU±[QD@énf˜ºï3Râ(÷ûñ³{çpÎ=Ͻ0sŸyÎs~=ètXZj²¶RRп¿¦Àµ‘þøúúˆŒÄˆ‹‘“,[:«W#4$‰Ë—‹—øOžÄ¯¿ÂÈ))˜7¯ü˜ßåËXµ ááØ¾'O¢S'üü3òò0oÂÂ@’ÐÕÅÀÄoÞ`âD°ÙÈ˃£#V­BX/ÆóçHIÁ®]hÝ‹•]áá;™™P©Ð¯¦OGB&OƳgÈÌÄ€pvÆš5åoÃøýwœ>ˆL™}}lÜbùr89áþ}¬^<|ˆAƒ`e…ÌL0™Ø·ööɰ~=N‚¾>rr°q#’“±x1Þ¼—‹ 46K¥X¸·o£aCìÚ¥™7* Æ!=*Ú¶ÅêÕË1n²² •".óçcÈ(X±/ÂЙ™øõ×bAÖïÊý p¹Ÿ¢7«§‡’J‚j}Šïƒê¹Ýß#uëÖ½víZ¹‹’ßJ¥2,,løðáÑÑÑÇÞÞþÞ½{ÉÉÉC† «W¯žP(lÛ¶­‘‘Q¿~ýÔC.]º4þü›7oZ[[?xð {÷îïÞ½KJJJJJ6lØÙ³gÇŽKÄüùóCBBÂÃõ´´Ö®]  Y³f;vì>|¸ZMÓÇÇgÙ²eL&388X,‹Åâ-[¶?~\$ 4(22òÙ³gmÚ´ÙºukHHˆR©œ5k–‹‹Kpp°¿¿ÿ³gÏ\]]ûôéSt………Û¶m300˜9sfzzzzzz`` A«V­rvvvttT/èwïÞ]¡PìÛ·À¢E‹Ê,‚ëëëïÙ³g×®]¸röö ÃÎøóOxzâí[hkÃÕmÚ`ÂÔ©S¬ÃÏãaëV?Ž  ây·n…¶6ΜADúõÃO?¡~}$'£U+ÌŸ]»ðÇ2©©8~kÖ ];¤¤|÷aQPÎè7ÄÕ®®ßÚŠ pvv~ôèQÞÇ zQÔ0˜LfÉ,LÏRábbb^¼x‘íë뫎2Œ &u°´´ìñ>fÞ¼y%ǶmÛ¶mÛ¶%[Áš÷rsrrT*•››Û!CJæ÷éÓ§OQ¢ú{Ú´iÓ¦¨  v‹ÕÌž=»è¸Œ¸\îÆwíÚ¥vãh4Z¹³áää´¦D%_777·ÒߤY,Ö°aÆ•.¶Ó½{wµ«Z’~ýú•´vÒ¤I%Êf³‹²iy<Þ¬Y³Š~dcc³bÅŠ¢— 4hð5…Â)>`âDâÀìßž=!—ãÀ<~ ‚@t4Þ½[[¬Yƒáå…ž=QÑÆÎðp$:uªPƒ©®\€; ;@¡€“¢£€ÆñÓO(¯lB…Ü»‡qãÀåÂÃB!ž?GÆÕ3éc04D:àr5q\wîÀÁAª¬Vý>©û¤ÚX IDAT¢Cpp€‘ž>EýúàrѪètxyi²æ´µao ð÷ßhݺlê÷åŒRPPÔF"""æÏŸoddTÒ1ú,¨…–,Y²cÇ“/V…Ãáœ:uêöíÛéééS§NuppøBQüðøø€Å‚£#\]‡Ã‡ñè~ùææÅ%K|}qô(n߯±c8~—/W(#H£U¶+¨ ˜šj*ÿÕ©##¼½qä®_Ç©S ÁùóÅ¢Uæó“¤f›¯Ú…ýïùÿ*•F±d=ÒQ(@§Wè¯WAh¬¥ÑÀ`hl.j,Ú%ÆçcçN\½ŠÐPŒ5k4ÛTÔ{©Õäß?š3ªP =J% «ØÿNAQ)))\.—Êýr€\¡”+•¹RYޤPþ-v‰™:×_»û‡Í!¹œçñ)ŸñÌþc&ú™ “Dæg=sIX¦›ÎÊÌâpØ.÷UrFÕcj4‚Ðâ°µ8,6“ÁbÐi”L[$&‚ÉÄåËš*©©pqAݺÈÊš‚II07‡‹ <<àë ™ ,²²“• P© ­:u T"4~~H PTÕÕEj*ÒÓÁfC €·7NŸFëÖ‹‘ ‚ޏ8cøp4mŠÁƒ5EðxxùM›‚ŪP7ÐÍ ¡¡èѯ_#?¿lõùêÂfC.GDìíqýze=Ýݱw/?†³322 hji4$&"=]c³º&N^d²âF„…!7ïÞ!!¡ÂåS©h×íÚ!+K½‘±cѹ3 úOûõùќѠ ¬[''lÙò• ‚Qü`¨Tªƒ’$YXXø­mù1)ÉŸÆ&ÇgääÊdJƒÉü¦b®2 çÛÍþ9È•ŸZ—âGG¥TJ•‡¥Ã纘 ”KZu™__°X(,ÄêÕ00€¿?FŽÄСHH€©©f§üéÓØ½66ˆ‹Óh#¦¥aà@dd /þþpvÆæÍ06ƲeX¾!!HKØ1ø ¿£˜^½°jΜAÇŽ˜=âöm@O11˜>½{ãØ19ss$&Âǧ8,êï¥Kqæ Z¶,Ö“)Ä 1"%ݺ¡(!™Í®¬vLÉ›£¥UœÀçkÊe#=]ã_2šâ¸\ͽòöFÏž=HLÄêÕš©}}1g®_ר|ó&æÍÓ t놖-±|9F°aè×ÙÙhÒ^^P*!+9ª÷øed`ð`èè€ÉDJJq[.ÇãÇ_$áKó£9£§N¡o_Ìœù‰r Šääd‰DBÉÝ T$Ÿ‘sëMl®\Åå x<€Î î3Å‚F¹B¡”+ $±O^»šÔ57b3´ß'cd„ @’ ‹UœÜÝqö,’’ ƒÇƒBƒ¡IÈåàóáà‚€XŒß~+^ûæó5‹È¢m[M´µEm¼/š˜˜¨™W$ÂîÝxýR)ÄbM¶e` ÚµCa!¸\ØÛkTôì‰V­”TVUª$ãÒ%ÄÅÅ‚½}ñÊuÏž(ò]>¦¦Ø¸±TIí©Sáç’„±1Ôrjuëb×.ƒ8uªÆ<Ë–áÝ;dfB (¾ ;ÂÓ³Øæúõ±qcñÉÕá3ggœ?7oÀbÁÁAS|Å MÝQ ìÙFFFr2––Å"uuqôè÷!ËS†í=YP>ŸòD)>ÄÄD¹\nllÌüî’nj6*’|›ô &‰Íµù”Jñu Ñè46Éf˹Ü'ñiÉÙy­]ly,êÝ ,Vùºñ&&(“íÌá”a2Q‘ø‘Q)®tuK©„2™eÓ¹\¸¸”?VG§ê2Ýzzåä èë”»ÆfÃÞ¾T ‹U¼n®>­@P¬ŠST<kk¼/FQ¾Í"Qù!L¡°T;[[Í1‡£¹?4LMajZv,“ù)Ú>5êìL«ñ¨TË5Ú¹Ÿ†X,vvv¶±±¡Ukß&EU$fæ>z›Ä‹¹å‰R|}˜,¶HO?U"¿¯¢2Â)(j?NdôÍ>ŒÈHÔ­û­M¡øž±¶¶¶þðû,ÅC"“ߎŠcðøLÖw¢¦Kñ#BÐh|madJº©Ž¶­AUQ5 НÅû)(@LLq1EÍáE|J–TÎå—-ÈIAñ•a0™làALB¡‚ªôKAQSøqœQ77lßÜ¿ÿ­M¡øn‘J¥ùùùªÊEä(ª‰R¥JÌÊåð©ÕyŠ›Ã-+³ ¤ßÚÏFa¡f›ÑG"—C&ûbÖPPTŸÇ@£ÇCjê·¶ƒâ»%44tçÎE•¾)> R¹2G*c0~œ¤ Šï¦‘#ùAœQ¥S§bÐ ÁžšA n]´k‡¸¸ê OOMÕM ŠÂæŒàÒ%¬X¡¡¥ øxär¹•••­­-¥0úù©fÆÙ£É„_7zµïœšÿiÞøÛÑß?.Rô©¤ÆÇÍØãÓÆ¦''.Ü[ñ‰{¿ŒüöUø§ÍRsHŽ}ûÛ„‘)IŸ06=)á· #S>ÎÕ*‰ –ÈHòÁÕ˜4˜™™}‚=5öGËT$¨”ŠšÆø'IEµ(> ===•JE)Œ~Qb¢®œ<šŸ%‰Û÷¨kd¢R©žÝºñøæ5¥BîÙ®£SC6‡ËæpËî¾'É´Ä„«§e¤$[Ø×iÝËŸÉbÈÉH¿rêXÒ»ž@Ë·ÿ`~ùDð›gitúñmņ­{ö­È˜¼ì¬+'&ÄDq¸\ßþC Ì, %’Рw¯´Ä:üé«Tª“»¶˜ÚØ=¾qM[G§û°±lï|ÐþäØ˜¼ì¬ãÛ6ðí?˜¯-”Ë ÃΟyýø!‡Çkßo¾‰€;7›ÚØ?¾qU¬oÐeÈ(6—w1ø`âۨܬÌ»¶Ð錶?õê–SÀ;òé£Ç7®e¦&‡†~týª­kÝúÞ­®ý¢c`äêÙ@\Ôëð»·[õøéþ•ä²ÂèÏd…¯ö]<š‘‘’tý̉ä¸X+Ÿž}y‚ x—‡B!|ýêó;arYa}ïVZµþ¼PRñø¾‰•­oÿ!tãÎ¥sá÷ïrø<Ÿî}L¬m< û÷ñÍky¹¦Öv-ºöÒ‰/Ÿ8òöUxFrâ¹?÷ð´´[õøI×ÐX!“Ý¿zéÅÝ[ ˧G_3[ûr-ù÷¯èðçɉçƒö „âæ~ݵÄ:×ÏœtkâmdaàÁÕH’tjìyóÜi’ÄÛˆp.׺g?c+’$ßE„‡]ø;?;ÛÙÝË£¯:W$/'ûÚ_!#ÆŽÿ‘ÞéB!Þ½ÃÓ§°µW~Ÿœ<{†ÌÌ eä)(¾?Î[‘‚â³ð#=Ÿj ’üü=¿,P)ZµÕëäçæ¸wùâÎ¥s ÍÌM¬mw,šYîØìŒôÕ“Ge¥§ÖmÒüÖ…¿Ïí ÉÏÛ0s›g¶hÍRâcL¦HOŸÍå²¹<‘ž¾–PT‘12©tíÔÑá÷o7lÙš§¥ý†$É»¶\ >T¯YË´„¸Í?OR©T*¥òຕÿž9ѰEë»ÿ\=q„´Å:Zb:.ÒÓééÓètG_ÿ÷þ?ܼ¼ }ãÌ ¹Àá¿]=u´AsŸ»¡.=@K$ÖëÒè ‘®žHO¿¢lZ6—+ÒÓg0˜¡X¤§ÏhÈHI Þ²V&•8÷çž×OÒèŒëŸÜ»r‘‘¥•Xßpã¬I 1Q’ü¼õÓÇ%ÄDÕkÚüñÍk§þø½ZWOÛ»r‘©CýFñïï^¿Ú±xÖãW-ë8g¥¥J%göí<½{›}Ýúlwëüé9™î„^00³hؼõó;aAëU)•¡XK¤Cg0´ttÔWD’ä¹C{ŽoßdW·—/ؾhVVjJ¹–ð…"-±ÁÐëˆôôL‹Íyrë_õ,ÈÍ9¾mcNFº$/7dÇæŽrn왟“³uþôüÜœw/×MÇ 3ë4h²}Ó½Ë5Héi™)ÉzF&åÎøâä…¾¾8¾Â>»w£GØØ”S”ˆ‚âÛòFF)(>•J%“ÉX,åŒ~QrYnv_[hn_ÇÙÝ‹ÃãËe…ÿ;Ô¸UÛF­Ú‘¤*üþ×þ)7NöèÆÕB‰¤ËàQt³e·Ÿþ´ÏoðÈ×OƼ|±ñìU¾¶°±O;uÏ6½ý£ÃŸ1˜Ì6½ý+1&âñƒ¨çO¿x‹§¥Õ¸U;r™ìæÙS¦Îñl×ѱ¡{ {bÌCs+:6xæ}³ä¸wÑ/ž‚ švì’ô.æŸcAESÈ ÿÚ³mÚúÖN®¶®õþý+$îM„•£ €¡?/Ö31Mxò€T©¼ÚwJMˆ =äÓ£/³âåUs»:ævuÎÞïѦƒ­«¦ð¢w§îgözm`j~ÿê¥)«§Óé|zôi×g A/îÞºûÏy ‡:™)É#æ-çk I'wýÞuèh¾¶ðc~G¤Juáðþ΃F|x÷ Í-G-Z)Šäfe††î>|¬‹GSG¥âöÅso_½póòî;~ZäÓG™©)f¶ö/îÝ–J Ü[·7µ¶}p-Ô»S7=cSõØŽù éÜØË±¡ûƒk¡Ñ/Ÿ7Ð7øÐ˜†-Z›ÙÚß»|±©ou(@ ¿žAWu2*îÍë‚ü\·&Í0˜Ìž£Æ{´íX§~ã%ÃûE={òøæ5Cs‹V=~"ZJ\ì­ g=Ûu–@»ÊR’ß@[7ojê¼—ËäÉð÷‡³3Þ½«¢j<ÅW†rF¿YYøë/øù•Sžôùs¼yƒ®]¿…YsáÂgggoooÊýr„¢^£&„ìÜ|îÏ=ÆV6#æ/×10ÌHINŽ}ùô±º›g³rǦ'Æg§§múy²ú¥Ž!€ÌÔC3ót³Ê™š¬chÄ+ñô&UªÌÔµ³%Š´ÅâÌÔTCs+4õš;¯bÝþÌ´¹Lvrׂ Ð36•ª$Ò× ­£«ÞPó_61ë›8»7¹qö”¥ƒ“XÏÀ²Ž¦0¶¡™¥ZÆUd`˜ø6ZK$ÊÉÌØ±øgµ1bÃÙ,¥&/';;#ÝÀÔüØZÞGšs33¤ùùçƒö]> €ÃãÓh´œŒô5“é †µ³kVZ*Pþ¤yÙY…Ʌîž:€N¯Þ“¨NƒÆ 3üþ§aÿ:6ôÐ36IOJ`±9b#\€'ÐÊJOM}¾aÆõ(gw/õA£«ÿ_­Ik82ôô*óDÕBG¯_SÎ(EÍ‚rF+#8:uú”±99 Aóæå8£áìYÊ­Y¼{÷.))ÉÆÆ†fÿ¢Ñا]ãÖíÓ“þX6ÿê©c}ÆOéé7ðnÕ)`8d‘ÛD£ÑJî¡Öë˜ÙÙ/Ü}D½®­Þš-ÒÓOOJ,ÈËUçD’*•zÛ>“ÍV)«Ø-ÒÓÏJK-”°¹<*•Š ÑÄúù¹Ùòr²r23ÊÍæ,B¥T’$©þ›êê1˜Ì±ËÖ¨S'UJ¥zí¾Â±*ÕÇ8ˆ4M’ŸW²¥Moÿ=+¾|p·©oW“˜ÿŽ$IÈḚ̈q­§%›ÚØÍÞºOí¦WiLIÚBž@«h³IªÔmÙnB‡Ï4s‹Gêkyq÷–¬P:gÃ~-±Îõ³§ÎîßUÔŸ,ñ›åiiñ´´NŸ[·Isõ­¨â}G’d‰4mÝ-Zÿ½§$?oÈÏ‹Õ ¹,73€´ _*)êêš[²¸Ü±ËÖQòïJߨ„F§çd¤ä ù.ÈÈÀGþ†ét|’ªÅ¤Ö9£ òó¡RA"— ‘H³Í77¹¹ Ñ £ 2rsqå Äbxz‚ÉÔlÏW(™ ¹Aeö Àçc÷îR}¤Rde J_ÔDbccXZZRÎè¥ 7÷ï˜ÙÚóµµ%ùybC›Óª[ï£[×óµ…"}ƒ×4öi§^ݶrr9¶uý…Ãû Ì,ê{·jТõ¹ƒ{oú­AsŸ¸7¯eR©ßà‘v®õôL̬^Ö¬c·äw1Žöõ°vr=¹kË•“GµDbõþ›±¯×ÐÀÌ|÷/ šûõL|mfcçØÈã­ïñmØ\Þͳ§m\êšZÛV”m©­£›Ÿ›sj×ï"}¯ö8<~û¾ÛÍê9j‚\&»z>pѯ¹€<–´ àÌþ:Fî­ÛWÙ5±¶½pø@Zb‚©}Ý\Ü›Ðh´·¯Â'®ÚT$Spí¯öNy9QáÏúNœa`j²cóá¿yµï”û673Ãoð(ÆÇÉD4Z»¾ÏíˆÄl/#9¡Mïþå^~“ƒ·¬éZ0ñúñýþƒµute…Ò;¡çÚÂÓl-J‡åk rÙùCûÌì¶h-ÔÑójßéÈÆß %:ƒñêÁݶ}¨cÏÂáòT¤êâуöŽõš¶hÖ±ëùÃû-­íÜê«»Ée²»¶€ ž†ýËbs¬\Ú¢³&ü½—•£säÓÇæöuµlMÌ['-éGÐu Raûvüù'Ú´ù¨þžžØ¸ii ¤F)j µÎ}øcÇ‚ÇC^är9''¼{‡¡C‘’©ݺaéRÙ‹»·ÕÁN=#“ië¶…†9÷çmÝ]zàk §­ÛváÈóAû´ut]½4Kü^í:J%qo^ëWd ‡Ë›¾~祣Ïíãk ]<šÑkô$‡s)ø Xß`ÒªMjo²ûˆ1ê!Žœ÷5x­év<¹ùo^N¶z¯Ò€isBV/[»x6U›ÝmøXÀÔÆ€úÛ_[8eÍïn\‰{óº¾wËJîXÿÉ?_=},îÍë"‡•ÁdÚ¹Ö7¶´Ñ5,¾4Ïvß¼ªR*G/^eíèBÐhÓ7ì¸tôÐùÃx­f»~|d@û¾B]½{¡ä2YQ&®©µ­:粈^£'Ý8{úúÙS I§Æž\¾@¬oØoâ̰ÿýE£Óý†Œ’ª„ºzÃç.}øïå¸7¯]<šè6lŒž±iØù3*¥Ò±‘‡ â}fÚ:ºÃç.½åRÜ›×u4V7ꛚ7õíÂy¿uœÍåÙºÔ½öW—ϵh¥–H,ŠÆÿ²þÊ©àWï雚™[ª{j‰ušúv¹ò÷éiÃý99"fÌøXgtÍ\¹ë ÛDAQj3ZXˆÄD9OOøûãüy89iǰ0ÄÆ¢Ktî ܹƒiÓ £ƒ¹s5c/\À±c8zvvX²+V`Ïžòg=:  x5äâEܸ `d„€€¯q¥ÕbàÀùùù¼Š4Q(>,6§ó K7ÒéôÆ>튜ž"htzÃm¶(~ÆšÚØLŸ[¦›Ž¡Q¿‰3ÊNÄá´ûi@•öè›”Ëå úŒ›VÆŒþ“VÛºÖ+ÚK n“æê…f5l·ã€¡ -9¼ÿäYê+Gg+Gç¢v&ênJ…¢dü•  ³ÈÂ^‹~$/,Lˆ‰zzëú¨E+KF:m]ê¶ìÖ»ô¥™–¼4•J%/½(Ã`2TJU©y B}N:ƒÑÔ·KSß.%û[88Z88–la±9>=úøôèS²Ñ½u{÷Öíñu4.r%°8¥Æ’$©ËKæ-Ðh´¢Àª[ý¢(€‚ÜÜ'a×$yy}Ú–ì߬S7uð¸èrìêÖ·«[<°¯÷ß¹cóýçNÒhð¯lŸ^YôôлwÕÝ((¾&µÎ`h004Ä»wpëÚ·‡@''˜›ãáCøø”3ðÖ-äåaófˆGZšf­ÿcxøõêÁÚ:tÀ•+Ÿéb(>TPŠoÅé=ۢß½4²°ê3nZ¹«ê‘Ïmøµe×Þn^ÞE¦Ö¶Ú:U,‡ß»}þð¾’-½GO¾zþmD±¢¾®¡IŸñSËÊ»~r2Òƒ·¬ÍÍÊ(jqqoÚÁP¹/=xÿꥣÆ[j\I“eåäÂýè·°PGoþú­?€'JAñcPÑ)Jè&ID…ÉÝ2ììÐþýw~¡°zu,ŠVɪ³\Fñ5P(t:Ê¥øVx¶ëèêQ¬!ÀáóèŒò?&œy,Ù¼L£ÿûàk%˜Û9tX²EÏÄÔ«}çºMZµ°¸‡S »?<-í¶? (Y’ª饮ÃFw6ºd‹PWoü/_¶àÅ—ƒrFÀÕaaÈÊBr2bcѨ‘¦FCz:rrÀd‚ËE³f¸v ÎÎ01AA$”»@½;J½M*?ùùàrQ·.Nœ@Tôõú5/Ž¢  epp°¶¶v‡¨B ß+Û/=…¶Žî‡ÑÓj•eú¢0Y,k'ª.òò TBX±V›J…ôtˆÅß²¨©BìlˆDThé³ñ#änW ÚÚPç¬óxšEö±c‘œŒÞ½€V­àé©éìë‹ÿý~~X¼Ú·GÓ¦èÝþþhß'N”?EJ FŒÀ˜1HHÀ¸q>IIðõEýúèß½zááCP Â5‡””äèèèwïÞ}¼#Å—`íZLZª%:7n¿LIA£Fˆ,¿L[Ybcqõêç4OÍóçhÓ11Ÿù´ V­ú"×|j]d´A9¢©_?gަÑÖ¡¡› '§âï[mÚàî]dfB½rÅãaÍÄÆ"1FF°°( }}¬[‡"yD:úú`0°oÂáRÁÊ Õ©ÌGñeIHHU(¦¦¦TX´¦A’¤L*e²ÙUny–JãÞD*å2c+›Jöe %‡Ce}PÔ@ ¨T ˆRËzêä•¿Ï ÐhP© Ri:Ëdš]ùEê‚€T §üÀ!IB.“Y,,¥E§C¡@x_,$ …×®áüy¸»—2›$!‘€FCE%ÌÔco߯hÒC3£R ¥tz±yj“€RV©¯—$¡Tß™ Ê.är¤f¬B‚(uf… ”JÍ#ˆ mær!‘`åJxyUØçG¥Ö9£l6 Þל•xfñùhܸœþ|~©(&KKXjB‹øøR'wv› #£rNÅdRŠN5‘‚‹Å²°° ¼‡šF^vÖ¶ù3ü'Ï*·:hJ…"hý¯ÏïÞ24³è6|LÉmן ’$oœ=U§»¾IÕâ_ë§>o™ºî%EÍáî]lÞ¬ ” ¦‘‚Ú¸7o‚N‡Pˆ9s`V¾Ø+,_SS\½Š‚´l‰ñã1dvì€@€;wpõ*¦MÃýû L†GЬæÍÇIÈR)ÆŒÁ¢EÝCAAÈÌÄ€˜=iiðöÖ<޳³1g>Db" ‚™.Ô Ù½/^€ÁÀòåpu-ÇÚøx,]Š/Aƒ`lŒ ãͬ_ôthiaæLØÚ"+ ›6!<$ 77Œ«ñ 6m‚H„{÷”wwüü3°v-23am­¹*ŽGHT*4nŒ1c…ÆïŚ5˜<»wƒÃÁ; ,Z„ú|J (¡¡èرü?*µn™þóríV­*þ·m›FÖžâ;¢E ËQ£F9;;WÝ•âë¢R*âÞDJ$ê— ¹\&•äå*d²‚¼\µ´§\&ËÍÊ|õð^À´¹ãV¬³qv —*ärI^ž$?¯"ÉzJ…BVXX(•äæ¨Ï¦F.+ÌÏÍ‘ä« ¹\šŸwöÏݱ‘¯¤E=U*¥$?¯ 7WUzÏcläk¹¬5ŒÄDtíŠY³Ð½;üý‘ ¹¹7³fÅÂŒ•­ÚݾE‹Ð²%„P’Ĺsš€bRîßI") [·¢n],_ŽýûVÎy¸\ÄÆâÖ-(•H@’A@ ÀÈ‘ÐÑÁÇšž|>†G‡ptÄäÉ(–¯IIÁâÅ ±iSÙ8¥]]Œ??ØÚbòd  ÙÙŸ3 £ƒ9sPP€‚`Ò$L™‚ÐP:¤9ÃÇX¼ŽŽ8ººHJ˜1°³ÃŠÈÉAN<ŽÙ³Ñ¡þÔ IDATFŒÀž=†  Í֥ϟãæMðx¸p÷îaÁ˜šbÉ’ o²µ5zõ¦Mµ®JV­‹Œ~^ À€ª¥ )j:ººUÈâP|#:ƒY°¾zúصÓÇs33 -,Óº›»ô‡öÞùç 1Q®ý…¯-ì;~š[ý õ«2R’ßF“*•{›½FO*w¡ÿöų×Μf¤$ÙºÔ»l5N{±wåâÌÔ›Ýwü´úÍ}®ž:zí¯„è7‡7þÆå Z÷êײk/…\¼yí“°r¹›—wÀô¹Eªò &ã«{NñcàãƒcÇpø0$H¥HN†Pˆþýqæ Þ¼A|<ÂÃ5«É1q"FŒ¨b–úõÑ·/x<¸»#¡‚*WãömcÓ&lÚ„/°|9˜L4jcãâ\LuËË—ˆŒ„—W©3LŠzõ4~›ºäa¸\4j¤ñz‹ÆÞ¿ôt4o™ îî¸xÉɰ°€›._FR¤R<}Z|’=0a‚æøÊH$3˜<Àµk00@ÿþ`±Ð½;þþ‹!3/^`Ù2 Š;wàé ,ÆC£FJ1yr…w 0p ŽEX¼½+ìöãAEF)j5$IPÛ–j,<-í¡s–¾/œ“–jdaÕeh`lÄˉ¿n¼wùbnV¦OϾ£—üfliÓgÜÔq¿¬µvv%I2ámTFJòÏ[öŒ\¸â|оWî–{þœÌŒˆG÷‡Í]úóï{_Ü ‹zþT¥TZ÷«¶Xgù¡S>=úþ>ºTRФC—ñ+Ö[Úô9~â¯ÒÒàùsbýzøûC$ªÂý ðúuõ–•œ‡;w0y2¶n…µµÆQ+‚@AAñžàê¢Þ³¥F_FFX»'N $;vÀÄW¯¢M,\ˆž=QºHY)¯ÚÐHJ€¸8ä瀽=²²•• qq°·‡®.¬­±{7úôÁãLj…›[õ ¦Ó1|8<(NW¨ PÎheH¥ÅÛú¾!6`Ð ôë‡;>R)>‘øx«gÏ”’÷Y‰?4MSŒ‡ƒÁ|Ì(•JI’dAn®º”¤ù|m!ƒÁd0˜[µkتm¹Ý((jžžX¼»vaÀ›eoäd,[†U«°vmµÑ&MðóÏØ°»wWo  ˜šÂÏ11hÔL&^¼Àºu¸}ááX··ni:[Yáùs̘½{QÝjSSDD`Ò$üñòòP¿>êÖÅĉؼ `òdäç£Y3„…aÍL›†ÿ­ðT..ppÀ”)ظsæhœã–-A˜=Ë–áâEôëÍš!:=zÀÂry…Â;•P§Z¶Ä¶mµ(EåŒVƪU‹‹SF¾;£IÌžÄÄolÉGÛ¶AII£Ê•? ønQ*•¯ÝoÚ±«4??9.¶Y§n9F£[ÙÄF¾rv÷Šz--È7¶Ò¬Û!—* ‚F£ÑhVN®*¥²}¿:^(•”[º³ˆ¨çO.Ÿ<Ú+p¢HOÿ¿^ŧ²gއD‚%KˆD8y7n€NÇþýˆŠªl…}ôh¸”®K°s'þø*¶oGAèt¸¹aØ0ÍI†‡mÅÅV¬€P¬]‹&MhÔ—:wÖt(J]mÚ 2Rã+kkcÉ€FÖ¬’—‹»;@D„¦¼"›]»pîâãanŽž=ÁãÁ×,^½‚»;zõ*ñÀܼøT|>öîÅéÓÈÏÇòåÈÍ…ž„BãÒ%(8p@“œÚ¥ ´´àà€iÓ ¡2ÆÓèðXX`úô VÃdbÌøûãåKÔ’½µµÑMMÅ‹pó&tuÑ­¸\DDàÚ5èØææHLÄ¿ÿâþ}hiÁÐFFhÑxòÍšÉÄÓ§ Ó5%ÏžA.G\Þ¼³3Ú´Á¿ÿ‚Ïǃ Óѽ;ôôÊ·$<2êÕƒ\Ž›7áê ]](¸qFF¸~R)Ú´£#P{l¾b1³JKŠšÎ 34Ád“ÅRo"0Y¬’¿D‚ nž;]()ÈHJds¹}ÚUpB:ƒ©yŽ1™,Æ`2» ܳrQldÄ«G÷[÷ì«Îþ$©‘ûÁu+®œ:ÖÔ·‹g»ŽÝ†þmÒ¨ 3Ç‹ô "Ÿ<0u¶‹G“Š,ñò|Ð>¿AUmý  ø’èè`äȲ  AÍq³fË5 ÐEðù¿°kײc1o^©›â´ËN@")µÂNàóAèÐAÓ2p æÀÉ NNå[îáâ—C†hLMaj …¹¹¥ús¹Å^u™±\.zö,Õ™FCûöÅ…¾‹h÷Ádžž^±fS¶¶e}n33ÍEÝ[õö&5èÛ·œk,ƒ›–-«v¬úû¥6:£¯^að`èê¢qc$'ÃË ‘‘;½zA"ÁîÝ AVnÞDb"23qó&œœÐ¢¢¢°lއPˆƒÁá`Ñ"8tGŽÀÆÖÖ¸rX²‰‰è×7nàÎlߎr%,CB‘5k ‘`ùr,] ]]`ÁddÀÉ 4RS5³PPÔršûu'I’¯-:{W 5zÉoÚb],wØÜ¥¦Å‰t:#`ú5ÐPÌž]juøèQØW¦ó[óæáŸŠ_ 8¸”È÷'43g–jY·>>ŸsН‡£Yô¯%ÔFg‹…}ûàêªyË…þý5kýû㟀õë1mtt0wnÕ'´¶ÆÉ“àó!“i¾MžŒÀ@üû/¦LAnneÙÙ"—Ãß_S ª&$­RPÔtLÔNŠJ™Óh4 û:e:óµ´¶l£>&I2?7§äOÙ“ÅëŠõ aáà¨þAÖN®ÖNèh„Uéâé<-­zÍZ|Œål.¯÷˜òå¥((j:Ç,? kÖ|γ•K¹qMŠï‹ZêŒZYirŠi4de!>àÔ)ÈÊÒl3¬M›jtΊ’W@$Ÿ_ím€|>Z¶Ô×¶š`ÿÞºg_S›bI~Þ’¡¥ƺ Õ¼Kφ~)N›Su' ŠÚJ-uFéôâus>\.–,ÁO?U1J]oWªüd™‰2'T×ÀP*KF+_v¸öl¬£ ødh4ZQLT O µêøÿ¾•=•C-ÉDÏžøýw<}Š„ì܉·o5?ÒÒÂ;¸}‘‘ £ƒ‚Ü¿‡qæÌg˜ÚÞ÷ï#* ÿׯ«èle…Ó§qïRR>ÃÔŸ—;5E•Š4˜’’°m6mBPP)Ï={—÷‰³üõWq•¦Š IÔº¢šß/µÑ‹áî^JÀbÊøúbôht놰°â¥öaÃ`nŽ¥K±?XZ"0 bÞ<øú¢Îû,5GÇâc5žžšÍïZZðòªPx¢}{¸»£O\¼ˆ®]59ÝL&<< —íO E’dZB<“ÍŽ}ýŠ$IÇFî,6'#9)=%1úų˜Wá$IêiëèäåE¿|&ÉÏwlèÎ×ÒšÏd±Þ¾ 'I•sc/‡“™š’•šýâÙÛW/ètºHß@¤[a!¥¤w1Z"qldDvzš‹GP¤R*b¢â£ßX:8š[‘%ÔÕSO——•—ehnY—›š×ö§þbâ³)•ÊØ×¯’ãÞ uôìÜê1˜,¥BiëR·d7’$Sãcß¾ êêY;»1Y,¥B‘û–¯­ýúÉ#‘®žµK]:þå~/µ„¸8çÎ!8gÏÂÞ11ÅΤ$ôïsslÞ¬‘²ù †mÛàç¡ð¿^;Å…rF¿zzèÝû[AAñýA0Ù‚V¼,÷4ìúÖùÓê7*,(¸!:5~Åú´ÄøECú蛚K ò ‚˜³m?‡Çß½bÁÛWáõ¾}îêÑdø¼å÷._¼}é\J|ì… ý\V»><ÛuLMˆ[5~¸¶Ž.›Ë=¼aÕ‚?‚øBÑÕË^?yP§~㘗Ïy.þõÑõ+7ΞJ‰½|ˆ§¥Ýª{oïÎÝ+²xËÜ© ¹\)—ә̻—/Œ]¶zïÊEn\«Ó Ñ¾_˜·¼aË6'wýÎáñ†Î^LÄ¡õ¿9ù»ˆ—'vn¿w{ÉãE*§Ç¶®»}ñŽ ÝßE¼ì2d”g»Ž¹9Á›×Ƽ|Þ¾o@×a£Õݞܼöû¼iŽ Ü£ÃŸ»x6>giNVÆÒ‘„:ºf¶ö®]:{Qs¿êÎt“@yE8((Þóè„J…^½Ð´D2ȨQš:œNN¸~,||@èØ‡C*­ž3Ú§èt´n ’ijgðñÁ¾}¸qYYHIÑ(퇅¡aCM‰#+«â±óçƒFömz¢ESlߎk×Ð¥K5 £øúPÎ(E EK,ž»ý€–XGýR’ŸwxÓo~ƒGv4‚$Éüœl—Ž24³˜»ãOI~Þ‚A½ï]¾èݹ;I’Þ»õŸüsÔ‹§+F>oyû~­zü´xh¿€ész UªS»·šÚØÿeJ¥Ú~ƒFriAþø_Ö¹x49³oçÃk¡Þ» Ó€¡Ÿç×CñãÂåÂØ$YÖÕ+_T©@šz•EE|XÇòÃ2„Äûr¾:ûöáÖ-lÚGG,XP|žrë„DZ`vî¬Ì55ÅàÁØ´ >>*ìFñÍ©½Î¨T …<^ùŠžŸ™ 2h4p¹š·“B¹\î—š±”JÐhå¿«ÕB¡‹&ó+šEAQ14½äbt¡D’ž”P§AcA„"¥BiåäB£Ó¹|™­}Ü›× ¦½[ú&f² Š˜)ЍgO²3Ò— ÷‘š¬c`€F#¬ÜX9¹H òË[9M;uS»}B]½ëŸT)•ë¦%@(•мì,’$]<šªTª7Oççf󵄶—õlëûûÜ©æöŽöõt¨.ú!ñQ‘=FAX9:3X¬äØ·VN.<–‰µ-ž–VvFº\&c±ÙxZÕ)GQ+©S§¬Ḋ88@*ÅÝ»hÑ¡¡°µ-‹êëãî]´o&SóÐÑÕ…TŠ‚p8Åò2'N`Êܽ ’D:¸u nnprBNBCáç^^8u ÑѰ´DRtu5ÐæÍˆöí±};&MB%I(þþسwî uëÿvS(¾$µÔŽFïÞÈËéSptü"S¤¦bèP¼~ ìÙ£ùBŒmÛpíÚ™±\T*„…áüy¼}‹iÓP·âÚ+V`Ï´k‡]»¾žyAt:C!—·Ðh,GÝB’¤B.cT¤£VÞÙØ<~»¶¾Í:uS·pùŸ'rR2;“Ãã™XÛŽ_±^] ”N§Ó ‚ Ü[·¿öWˆ¬PêÕ¾³b›{NlÞ¥g䓇!;·€$LC”÷…’ÁdÊ¥…r9©"Y\.ÿ‘y¢ê[G£ÑéŒZúD øX¬R>Ÿ‘æÍÃðá°µÅë×8xE¢S¦`˜›cÛ68;€»;œÑ®°{7„B°ÙÆÅ‹xó°¶ÆO?¡o_tîŒìlÈåùÅÎqãºw‡ƒ>ÄÅ‹°µÕXbe…Õ«1e <<àí]¡ÙVVèÞ›7£iS|&YŠÏO-ýèyô::¸y³Š’„R ’^@U(@’`04_øHRóO¥*nT©Ž´4pnìu`õ/Y©)6ÎnyÙY)ñïÄFZté¹zÒÈüœœ%†¨?5d…RR¥"U*Y¡´PRÀbsíÙí›ÖN.}ÚG¿ü‚¨(ØÚ¢aÃâYöìAv6"#ñä š4Á˜1X¸YY04D~>¸\¬]«Ã/ùs¸~QQHJ‚·7~þ¹ü„kÖ !W¯~Ô=Q(•E9£5&‹5hƼ½¿.žÙËW!—7íØÕ¡~£v}¢ÃŸÏõï I‡Îõ›µ$IRÏØ„+Ð@§ÓÍm4ÃÙì®Cþ¾þÜÁ=݇mÙ­wçÁ#3RSf÷ó#‡Ç\ü«¡©¹®‘‰zŸ;AÐÌí4K•4­ÛðÑG6­>{pwÇCÛ÷­ð‹¡©‡Wüþ1¶² \üëÖùÓI’,”H:îP¿1[×zÆV¶|-m3{uÏ3'ÆGGض`&€ië¶›ÙÚ_Ÿ§¥=î—µ4í¯=Û¯œ:ªòïß'º ôéÙ·ï„¿Ï›6½G{¥\>`ÚC㜌tcKk@ -205/7¤ªF’Ÿ—ËbSQ#ŠÊ(WF¿a  eE¢âÇ™™˜›—ê ”ÿ 34,õ²¤%&&\„£#BC©çZ¦–:£ÙÙ•eOª9zK—býz˜šâñc(•ˆŒÄäɘ9uê`Ü8ˆD˜4 OžàðalÝŠÂBÌ‹¶mamþýqç’“1r$ø|×Û³'NÂÅ‹¥4í>Ä¡C˜1=zàÍddàúu¬\‰éÓ±d öìÁ­[ðõ-ǼˆlÙ‚ `g‡1c``€‰ÿëm¡ÓÁç—“xNAQC00³˜¹é¥RY´Íæp'¬Ü’T©T´÷C~^¤>àii/;t²h¸{ëî­;½d±9Ãç.>w©J©,0}žú€Ádþr¾¨sÃm¶(Uò¾\Ư\_¦¥I‡ÎM:t.i³š•|9}Ã0€)k·(9¶Ûð1݆)ÓÍÌÖþ— Ó*¥’ ÑŠÒU‹NèÑÖ×£my"ïIz#ÒÓoÒ¡s•WGAñblü­- ¨”ZçŒfd $;v OŸ*z9‚>}С¸ºÀ½{àñУtt0`þúKãÿµnN™ 6©©pr‚§' !¢eËâ6lˆ/pñbÙ‰ºtÁìÙЮî݃®.¼½ai //œ<‰ v_€—† €AƒpòägpFµµaoE‹Ð·/Úµû¯g£ øB”“ I´ÿ £Yݱ 1QÏoß,ÙÒ¬s7ž@«¢þ(׿æ#Ç~ò0²°š°bƒPWïÓ†SPPPüGj3ªR!- ùù¥\Ê%9––¥Z²³‹3c„Bäå!?(‘Ö©Rir@«…Þ§>ŠV.„B$'âIJB‰€‚‚Ïp6 Š…L–—“]²…T}Ç †æ–Uw¢   øbÔ:gTO?ÿ ¡çÎaÔ¨Êzººâþ}  :]³»ÈÜ))HM…‘ââ`høuË""4"Ã11MàrQorÂ{_¹)«œÜ»‡«WËÉõ¡  (ÂÂÁÑÂáËÈpPPP|4E[x?m A|AmGŠjQKFFU÷9/bÖ,l؀ɓ‘ OOp¹˜>‹aÏŒ ¼ìUSRȳÌ_ùÛ·˜;ÇŽ!.sç"8¸¸[ÉìÕ¢QEÿ­$·õùsŒ‡¥KT™c½u+&NDZV­Â´i•]²B¼¼OycSPPPPüØ(•(¡«Ví± Ågµ…qã™Y½Q$‰mÛе+‚‚ªîLñu¨u‘Q5¼<äåϯÐÛóôĹs¸xYYðóŸý…'›‹Ã‡5EÒúö…L|>V¬€““f¸£#æÏ/>Ÿ77¸¹¡_? ÄÂ!CJ`m¥K!cÁ˜˜`êTØØTxÝ»£Y3¤¥aïÞRÉ©ehÐ::šÙJ¶*•ÈÉ“  ûPPPPPÔN6lÀÍ›8|¸BÁÁJص `ûöÏlR~>ž=«¶‹ƒ­[±p!Ú¶ýÌöP|2µÔ­[99psÃÙ³Åîã‡ØÚ–]þ62˜Ò;YëÕÓ°X¥¶½ëëãÿìÝw\SWðßÙ@ÂÞ .@Ž÷ÞVëª{´ÎÚº·Vmmõmµ¶U[­¶Vk«ÕZµî=pï²÷Þ!û¾$DÀð|?þ‘œœ{îITxrï9ÏÓ±ÐÖ[SZD‘´gr¹iË”ñ?I۶ยÿÓò³ŠJ$;¶ÄÉçkÙ-[¾¼Û’%øùgôïožQñ"•2÷äÞ]­º÷‘Û;èõºóïÏNOë=fEQ·ÏŸ}x¯ÇÈq¹Y™Ç÷ü’HÝ&ÍýÛ´»p诘ПoëäR¿u€Â¾˜´œÁpñÈÁ”ø¸~ã?2¨Õjšu,q×yr|¬ÔZ.¾ü¿ÇßÛ7·ï÷^~S‚¨êrrðçŸ BD¶mƒTŠAƒÀ²P«qü8áæ†LAj\އN¹½zA«Åþý¸t ‘‘øñGH$èß¿Ääó.\À³gàñ77p®\Áƒ‹Ñ£‡éZIf&@RÒs+Ê’“qêrrФ 4(í¦¢J©Í›?WÝ”0¯wô6½—‚‚ðø1¼ë)Ñð IDAT½Í=•—yò~~ÏýÙ¾üüJ«9ñfÏFl,6m*Ë1 âm¨ó”'öþšžœÀ ×_:zpï¦õÏîßQçåýµuÓ?;¶ªrsSãÿÙ¹5+=ÕøG­Tô†+Ç?¼~%51þ⑃Ÿôíôìþç8.èÄÑ=Ö>¸zÀý Kw.œ-üjá΃áëO¦„ܹUÜ0E·.ßóKNVÆÛ¿}‚¨$4\»†ÈH¤¦"(·n™ÊÁŒƒõë‘šŠ¹s±a df¢{w\¿nº˜“7n , II¸z·n•x¿žã0>fÌ@J ®^5•*üë/¼ÿ>¢¢ðÇ>YYP«1t(öî…FƒÅ‹‘–‘‘èÒÿüƒèh¼ÿ>‚‚*îÃ!ÊDiWF†Q«Õb±¸ÂfSÁªDe°ºuñôi1íe~¡ØÔúDµ¤×ë9Ž+% z¥eçìtâËãe¦¥XÙ˜2_‹-¤®ü*¿±:hÛ^ý»£Õ¨WMyõÄïzþÅ(·s8½ÿ÷z-Ûæ·hTªc»w„=~ ·³ï=z’•íÝËç]N‰‹9µÏý ‹õZ¶õkÖ @胻çþÞ§R*zðkÞªß6AT,cQ@4 š†\Žï¾Ãúõ¸|›7›®€^¼ˆK—põ*lmѹ3&LÀĉHLDj*ÆG½z˜9Ótyò›o°yóËoÓã×_qôèse«·nÅĉX´‰‰hÒ·neŽ'àâ//¬^ [¶ÀÍ ›7C €L†­[Ñ¢EñgÉÊ¿ÿB§#÷+—Ò®ŒŠD¢\cî"‚ ªF€ÿÊeÜÍ…ayÞõŠ %­hÒ¡ëí‹g/Úß¼S÷ü´š:úöù3·ÏŸ¹sñlfjŠ©+g,¹®ËËÍay%VïlÓ«ÿ£A© q¦ƒ8î÷o¿:{ð¶=û¥&Ä­:àdrïZ‘ÈÎÉÅ¥F-©µÀ“[×WNîQÛÇ¿u» s¦Å„†äY³ACþ+ÜÍ'ˆJëèQøú¢n]üþ{‰}žÿ¦p‹ÜÞÁÎÙõÜßûçmÚvãìIc£*Où×›0,;dÚ'Þ~þÎüãÑ«aï8.°ï{%žB*mԮé}{ŒOuZíµ“ÿŸµ Q»Ž^¾õ'6Ž ~êQÇÇ­Vc»wÖkÑÆ¯EkÇý³cK×!#[vëžœØ0 Ãù¿÷ ûxžqk7–ÇA§];üû/(%ö±·‡ÎC‘»§ë×ã³Ïpí&ND@4µëtà¸Ò–rZZ"#*Õsr9’’@­†Á¹4Ó¾áÌLS]¹ãÇcíÚ—¿µ}ûpâæÏÇÔ©¤,S%RZ0*‘Hbbb Cåÿ¥ , çΡAøû“ÌaQ"ƒÁ‘‘aóƵÌŠÇãõ1¶†o}wÏüF ™õŠæ?5Þ¦wõ®åß:°Ë‘5ê5(¥6E3ýúÓüÛ´À )ñq–VÖ,dV2…MVFZ±¦''=¾yýò¿‡ŒO›vìZl7‚¨Š$xzmtwÇÏ?ãòe¸ºÂÝ­[#5?þˆƒÐP ‚ðpœ;‡`g‘¨ Nµ³Ãõë8}žžpw/>`½zððÀŠXµ aaà8´höí±cڵùsà8øûƒÏ‡J…½{Ñ¿?¶l1¯ýúaÚ4 iS\½ ™ %¾;…¦uD%ñ’+£ ""«”ôB•F^nÞIJe8¾hå$‚ ò%&&j4E)W<*·z-ÚÔkÑ&;ã%©kø5hÓ«ß« èY××ÞÕýöùÓ Z·£hÚÖÉ97+€2;+35Ef]ðAÞ©d!³ê5ªKÿ S^åéɉ‘OŸÔmÜT ª¶Kð‰j¯[7<|ˆo¾Ã`ÇÈå8rË–aÿ~1( ÿþ‹_~€>(H)Óµ+>Ä÷ßÀO?¿]$®]X±ï½†ÁÂ…0w.”J lÜwwP¾ýkÖàÇðxèÖ _~‰o¿…JÌ™SQ†J F)Šª]»ö­[· …¬Ò§@ðõÅ·ßâäIäå™{*QY)•ʨ¨(///@`î¹T Ëk×÷½ofOm°<^ó.=önZÏ />P÷¾kÍÚ(@*—Ÿúó·”øXϺ~u|zŽ·qþL+[û‡×/·èܳ†_ý’NñðÚ•¯gOýúЗ5+ðDY’H°dÉs-uê`ÏžçZjÔÀs¬XŒE‹ žIA‘ïÞÕ[·>÷’\Ž/,{éÚÕ”±°~ýÐ~B¡@N-¸qhÛöåý‰ ð’<£"‘ÈÃÃãÑ£G>>>•?%¢999!!!r¹¼*Þ£§¶]ŸAùÁœ@(ê6l”ÈÂÂÖÑ¹ßøžïÉ´íÕßÞå%5m)šjÝ£1i‹Î=R>žïQLJ¢¨ÁSf‰-¤Zˇ¬ÿá¿Îô„Å«/ü³?%>ÖÁÕ@ýV3¿ÚtõØá¼Ü'϶NÎ¥œ+>2ÜÑÍÃÎÙµ”>ñŽHOÇ¢EÏí1 Àøñ7;;üó.]"{˜*‘—'½wvv¦(êÁƒöööžžžLå.)áÆ Ô®]Ú*i‚x× †˜˜˜ØØX'''—ª˜Ô‰a˜¶½úç?å …]†Œ ’Xôý\1\š¦[wïóÒ)ŠnÙµWþh&M3>æñÅÞ|—Û;ô÷\ÔëÛ´¥oÓW¨'„Ü»ýþô9ü*‘LŽ Ê™XŒ!Cž+æRñ‰\\0dHEŸ”(Å+U`rrr’ËåÁÁÁAAAqqq/æy®$>ø³fáèQlÚDge ;;;ýu+W:.///+++''‡Çã‘ûæ²à‡æžATÌ= ¢’yÕr B¡°~ýú¹¹¹ÙÙÙ>,×9½'0x0¦O‡e‰Ûg â5$$$DDD˜{oˆ¦i@ P(ÜÝÝ-,,ªâQ‚ ¢Ú{½Úô‰D"‘899UÚßjaaX¾µj™{DuQ³f͆ š{AÄ+ÉÌ„NW4CjL ¬­Mò«±±pt¬¥"ß^5LÈI®‰AD匫W+è\[·âóÏ‹6öécJã_©9bª€úë¯z=fφ&N,¾xI4¬]‹3gðõ×xð Ì'[¾^ïÊhe–€ “S|6]‚ ‚ ÌâÌܺUb½øwÖƒˆ‰«+¢¢L‰Z$'ãòeìÛ‡ ^o4½'NÀÊ gÎÀ×~~e>ßrT}®Œ>x€½{±p!Ü^’Ñ… ˆª!;=må¸aQÁh5šïÎZ4¼_^nÇölX;gP÷Œ”ä°‡÷¦ti•ÿç¯-õ:Ýæ¥s§ti5£gàÒQïúó7CqµV zý+Î}¯‡2; À_[7íÙðeI3á8îôþß“b£ßìß½µþãÉÅNƒ ª®>ÂÚµ D¯^75nߎö퀡Ó!=S¦`Çœ=‹Ñ£ññÇÈÉ€Œ…€Œ˜˜‚1OžÄɓϕGJKÃÞ½Ï]#ܹ;# #GšÎ«×côhÎqþ¼©[r2¦LAÆ7©©¯÷ÖöîÅgŸ¡_?â§Ÿ ÎÛ­0t(=€mÛ0a:uÂìÙ Ķm TbÝ:tìˆÎ±oßëwãFLŠ'O°|9&M2½ë°0 Š€ ŽgÏ€ãpð ºvE` –,©éÕ«Ï•ÑNб#ÉèDÕ‡Á O‰ÑjŒ9`¸´äÄðG]¿R»aÓ‹‡ªò”½^£QçdfÌZÿ½ñ[gWŽãÒS’¶mß´C—ʨ_¬Š%­{ô}q|c,tòßöýgg¤©rsKš Çq§þÜmçäòf¹B5*Ujb‡Jš„„ ÞÌîÝ:Û¶aÁ¬[‡ pó&.ÄO?ÁÊ ýûÃÃ]º`Ð °,ž=ða  #}ûbèP,X€;1o¶mŸŸšFëÖ‰Lg‰ŒÄäÉXµ µk›Z8K–ÀÕÛ¶aÆ ìÝ‹S§ðÍ7øö[…5ÊÔsöl¤¥á—_pò$~ûíõÞÚÍ›øë/ìØ°0|þ9:v„‡T*,^ GGìÙƒ3pè._†Hooœ>?ƦM2ë×ãØ1lØ€¤$Ì›‡ZµP¯^ñgiÕ YYÉàãcjiÛ2nÝBðô„T*Ìœ [[|ÿ=¾ü&àØ1„‡cÚ4,^ Œ[[L›–ňðõ……ªBÝÌçTŸ` ‘(ATs~Í[ÿ{?M36ŽÎY馪ñ,ß u»ü>ÆÚôÎ^Þ Z·Óë´·/œ ¾{«Ø`€_óÖGwmkßp~KlسoæLMЉ–Hec¬hØéÐöÍÇöìLMŒß0o:_ ì5jB·a£õ:Ýž _^<|@£V5ïÜ}âÒϤ''mZðqlØ3•2·Û°Ñƒ§~Ri÷zD™øäxyaÐ üþ;ôz;†úõÑ¡ôí‹C‡Ð«Ú·Gp0T*téb:êâEhµ¨_11¨S‡#+ ÆZ³gƒ¢L©‘›¾ý´´o}ûðçŸ Et4²²pèºvE÷î0p ¤¦âÒ%|÷üüàæ†Í›K{©©¸sœQ§Ž©±O´l //|÷)E8pûö!4‰‰HK€ Àã!/þþàñ‹}ûЯÒÓÁãA.Ç%£mÚmñ÷‡T ±-Z˜î³GD $K–Àן~Š®]K—`k‹±cÁ0>ÇŽaÚ4ðx5 š4)íÍVNÕ*%¢:YXûx¾­³K~KÆÍ.>xt×Ï-»ö<¶çc£2'kÓ‚Ð ÛmØhWoS6 Fóäöõ°÷üÛ–t ßf­.9ðøfñ©A¯ßùåJϺõ>ÿýð©?w¿øÓo]ê5zb÷c—Ž4dÚ§~Í[Q àÄÞ_o?½vßQž@¸rÜЋ‡´éÙïÌ_{åö 6ï4èôq‘aù‘¨³W“¦Ñ4YÏNT7r9°¬ébPz:\]M¡¤TŠˆètàñŠ•žŽÜ\üþ;X‡¶m ú¼XçS¡À°aOÑ»7Z¶D³fÉiiðô4u°³CZrs¡VÃÎÎ4“üë¬Å ÁҥЯ_A0jÜ Íãe !ýû£aC´l ++s\©D^‚‚ÎÎp}»Êkj5rr`¬ßli KKäå!/öö¦2r9’’Þê• F ‚¨¤øaóÎÝ ·XȬk7lrýô±1 –ç£,çÓ¤Ц-­Lþ~Zµxûê¥2…M“ÛõXò)í 9³¯…•½Nñøáôµ“i† ìÿÞÏ_,‹ yZ«A#šaЦhc@Éq\ÐÉ£n5kß¹p€•Â6øî­6=ûYÙØÞ¹u×ú5u6-|±ÖÚÖÞº}Ù~8Q ¹¸àÀ¨T‰ Wׂ(3;z½)~ru…L†uëàà`z5ÿ¯¿‚¦1x°)€_EûöhÜž>……V­‚B;¡Ñ€£#¢£¡Óeqë<< P@&ý{hÐqqÈÈ(mÚÍ››Vš–r'#!|>V¬€ƒöî…JU|7¹¶¶4cÇ}koÆÂ––HH@½zˆŠBn.llàèˆ'O•KK<{V¶Ê˜-MIÁ˜1°²ÂÚµf(FDUDÓÔ gt8ÔBVP`/µPPÚÏx›~ìüå]‡¢@Q4]Ú½rŠ èÕîàu7[Xràò”9ÿ½BñBM ¿s4*•J©Œ {ÀÅ»–G_íû–É·/œùù‹å®Þµæ~»¢«Ï&Q‚x©¾}±nf΄TŠ'pꔩ½A¬XiÓP§&L@›6ðóðaè×QQÈÊÂÆ¦„šÛ·ƒaпA0Õ«!‘˜‚Ñ5‘Õ«!•bÛ6H¥0y2úôÁÂ…P«qü8&N„D‚±cñÙgˆˆÀ•+ˆ.uó!E½ ߣb'C¼ªÜ¬ÌM fÅ…‡–ÞM£Vÿüù2Ÿß( ƒLaS31 æL ¹{ëÍü`Ûª%ƒ¡lgEæµ};Z´ÀرèÖ [¶@v6FŽD»vxÿ}"9‰‰hÑË–aï^øø }û+sž< ??´k‡Ñ´)¢¢àÞ=4k†¡CѺ5-‚Fƒ#Gàãƒóç1y2||L9M³³1q"ÚµÃ!èÐ11%Î9&]»¢{w¼ÿ>úôANrs1f ºtAÿþèØÑtì¢EX½ÒÓÑ¥ >Dz:ÚµC@† AӦر–,A—.¸}ݺÁÇW®”á§ûn©Ð5£"‘Z-2Ô4 ‰ƒWäÉ ¢¹¹°³ó1÷,ˆ’p½.ÿrHr\lVZjzr¢[ÍÚQ!O<ëú)œâ#££Òšvè*¶°dX–ã¸Ø°g|¡0:ä)EQu›4I,Š=-1!'3C§Ó&FEÖòo¤pp2¶Ç„†D?±¶³¯Û¸€¤˜è¤Øè¨'!÷ïh5[gW['gZµúáõ«ZÚ§i ‰¥ô¿IÆ„=¼Çã Ükûäç¢â8N¯×äÊ(Q­lߎeËðÞ{0L—þ8w2¦MÃ?bÞ<œ;‡ÄíÛØ´ …’Rë ÈÍÅÁƒpuEÏž8#F`ýz4k†ñð!úöÅÀèÚ;¢_?Lš„îÝMe9ÿwïâìYX[cî\lÞŒ•+‹?Ëš5P(°oø|ÄÄ@(Äß#(GŽÀƃaûv,^ ­Öt•”ã VÃ`Ç!=“&aÂìÞ]»0j–,Áðá;[·¢FßñRŒòùN ã Tf5De VC¯‹Å _Þ•¨.þëÔŸ»åvÑ¡Á¾ÍZþñÝ×köztóÚÝKg3R“¯>öäöõžŒI,÷lXûäæußæ-³ÒRüøÝüv^?}|ÏÆ/køÖŠ%?±lÝ“2«sïÛñù²¦º>¸v¹iûΣç/vÿöµSÇ2R’ož=|÷V«®½lœSâ–yßɳ†P,ÞùåÊÏ÷–XJ]¿úÝ¢OvÊÉ̸téƒÙ‹É–y¢kÝsæàÐ!bäH8sÙÙX²?FVôz`Y0Ì˳‰×® ðùpt4E·×®aþ|ˆDhÜ ‚ƒÑ¨4 >¿`À³g¡VcÙ2 …¥eñã«Õ¸t ³gÀ©ŒÓãÇðô„§'( ­Z•¶U"A³fàóáînZ À²àóAQÏM†x¼›ž’ɺ$$<µ°àh3o"$%A"iCÓsO„(žTnóåþãìÉ89ƒ¡i‡®¾ÍZîývÝøE«‘šÜaÀà–]z¬šôÁ É3j6hHQ´^§ÓétÍ:u¿xUž2wѰ¾×Oè=àÅñ9Π°w˜ÿý½N»xäÀ°‡÷|š¶<´}óiŸv22ôá½EÃû÷÷aËn½›uê¾tÔ{}Ç}è×¼EÑþô½—o½i_|CQÔ÷‹fŸúã·>c'?¼~¥N£¦£ç-ã8Ž3èó#QŸ¦-–nßÃ0fÎ^BekåJô郳gñÕWxú_}eZ€g,éÙ­ðZ¿ë‚¢ýiÚ´TÔøŸ©ð:Ô"Ýj×.(%êèX|7ã EÖËèõ ¨‚—ŠL@§ƒNW0=q–“Š œäåy¥¦Vði ¢¨ìl¤¤X¹º®¥iòÓ¥’¢(Š/Ò…~9ðø|±¥T 1,ËÀ¢hŠfP4MÓŒ1þcÆ·YKša„"‘ƒ›g\D‰«N­lì–¥–aÙœ¬LƒAŸãR£EÓµ}Ä––ñáEËÇÓ”éÇ…=ºüxõ¤VMùèÆÕ˜°þ­ÛÝ»|aZ·6ç͈xR°•ЦicÝQ‚¨N<@³f˜?}„øx @T:t@ß¾hÓ¦ØN,FDòò^ûõêáôi¨Õ ‚R __S»D‚»w ¶4µh¸8´je:¯½}ñ£ñùhÞšf ­  4¡¡ÈÎÆ¥K¦šò¢£a0àÑ£—ì”gYäæ>·¥éµLŸ^´î|L Ú·ÇÏ??×xîZ´Àox–ʯ¢¿©óxöÃÃJ$yb²a‰0­‘‘prZ.×7÷\ˆ²ÇqœF£6>Ði5áKêÔç£@ñBƒA@¯×ååæ–Tãžåñ[tîÑ¢KOãS‰L fƒFß9þèÁé}{¾™3íëCgŒQ,ATKsç", nnˆŠÂÆ`YŒ‡;wи1ìí‹~@—.€Í›áãooüñ¬¬^õóçcøp´näd  ŸÿVøŠ9sðë¯èÑ_~‰#pÿ>Z¶„£#±|9ÜÝ‹pÁL˜€æÍ!•B.Ço¿¡cG4nŒnÝ @¡Àĉп?D«VàñPz¡4''ô쉑#aa­[Ѣū¾5£ÈHDG?×¢ÑàÑ£¢¹²³ñàr_žY¤ª2Ãm#™¬›Ýâ§OW:8ä98<£DEKOGT,-ÇÙÚN,i—=Q¥ †sþlѹGRLTÄ“G'ÏxÅi–õòñ»xø€O“—Žü-µ¶v­YÛøÏ ~lïæ!±”Š--v:h_ç!#ävOoß[Zü@ ù4m¡Vçݹ|r9Õl IDAT®ôs}1e¬2;kñO»Y²ë¨šDb"T*¸¸ÀxuI"Á–-ÈÌDj*œœÉÉݧNA«E¡¤ëP;¢m[¿ýmÙã÷¸úõqõ*"" —ÃÖì1K¿~èÖ z½©E*ÅÆÈÈ@J œœ )yí•»;þùÉÉÈÉ«+D"Pvì@|<òòàæfš€¿?®_Gb"\]Á0 AQ8zÔt›¾m[=ja°|9æÏ‡ÁPâ[ËwëvíÂðá-{ö HÎ7„…Ý Õ­PÂWãêÀ,k˜(GÇ9––-ÃÃ'gd<µ³ƒHdúAåG¥B^ÒÒmïêº^.DQ$µmUbek¯U«EÎ^Þ Ã¸Õ¬m ãh†võ®%*ôû‡¦ƒ^?{@WŽãº¼?²vÃ&Å(“Û8{y (ʵF- ©Ã0£æ.ý~ñìOûwfyüñ‹W¯ªÒ4ÝoüGmÝtâh‡ACûê:tTzrâêIŠÅ“W¬ùôñ¡Ÿ·ôz†eÇ.XQúeѬôT…ƒ#M–ÏU–PXÌH–…B…¢hûK\2LA°U¸.£DRpw>EÌX66°ù/·Û•+ˆ-xÕÂíÚ™áóáìüܱ<ÜÜŠŽÿâ»È?c᩟–þæëÚ2YÑë¬/Æ—ÆtCE°¬iÓUuežõÅXZúø\LLü>%åB^Þmƒ!U,Î#ñ(Q(J›ËqœD$j 7õñ™Å绽ü0¢’ ì;ˆhš¿x5Ëc§®ùšeY¡hüâU [ðÓŒ¦éžŒ÷oÓ xAI[Ú›wîÞ¬SW ËNXºÆ;:yÖXºmÞ §(ªðBOÿ6~Í[qg܇ÄF|²P7MãišÇè= U·Þ8Š¢ø¥þâUçåņ==w)¹O¼;tAF®{jNÍä¬:YyN\yÞ˜ºóÉIOEb(­`æ•Û ýhQlVK…‚ìÕ+GEQ”ØRªïÄLÉÊs ¬»†¢ªL br¿’ ‚ ˆrñ$¾wlF LnK"ÑŠÁòùR¹]xJ·ðäsÏå5`” ‚ ˆ²—•çt=l¢DfG6êU$†e…–ŽA¡S”j›—÷®H0JD%•—›³󆔄R럔 1:2)6úåýŠ£ÓjçêžûâK÷¯\\=ùƒü§·/œ¹}áÌ›… ª½G± ¬[é™%ˆò ‰T\­§ñÝÍ=‘WE‚Q‚ *)*ïÜÁ?3‹”"y5G~Ývìùô¯Žf˜î#ÆJ,¥/¾¤×éT…ª ß¹r÷Ö›… ª½”ìš|É"nEñøÂÄ,?sOäU½ù&½^Ã#«@ˆjJ£©’ÙÚª±Ü쬃?}ïV³ö3'ìÝÜûŽýPlaiÐëƒN½zü_ hÛ{@ý–m“ãbþÙ±õAÐ%𦷝YjãàÔ{Ì$I±Ñ§÷íŽ ©Ó¨Y—!#ø%Ô}zûÆåÑ Ó¤}çüÆÈ§ïüI•§tpó¨˜7KUÎ HÉ®)Q Áo ª<^ÀQ|½AlàŠYXlù¥ÜÌŒÇ7¯%FGj5êO¾Þ̼v0ú è²*7§I‡.o2ã·úàn\DXÛ^ý‹´Þù£V­6£zŽã ·ÎŸÎLMí8è}ÎÀëÆE…<ùgÇ–é_l Þ¨8°ãqúbb9ƒÁÀA ÕUzöoŒ6iÒäÎ2­fE••äUJå¦p‘O<ÐÎÉÍ0Êì,N—‘’ääá€åóöNé…+’“‘š¼iÁ,½^l)+¶[±c¢ercù"LIey‚(¯\öÓɳÆÈOÞ½|þè¯ÛÀ½ÉéBÜÍLKyã`Ô ×¿ÙÆÿègÁ÷¯^,Œ&ÇF_?}lòòµùsÛ·y£½«›F¥ ¾s£a@‡VÝzhÐ*àØî!÷n×òoüF³¦Šì9àÕ?y³{“`”eY©´˜¥ýA劢PøâËãYÛÚg¦¦ÐiµiI u}/ D"}¡»76NÎö.nó6m§ãá¯ñ3ÚÖÉ9'3Ãø8)æå;ôoœ>îèáåìåýê§ ˆjïúé㻿ùB ©ò”Ì^ܰm{Z½ÿ‡o‚Nþk0è}š´=oi~ ߢǞ:¶oóƒ^/KÆ/YåV³€ûW/þ±éy¹9µêýi³=}ü¶®X¢×i]¿jãèuÍÿr²2·,›—©ÌÉž7¸§½«û¤å_ˆ-,ܺÄòøuL?”¼ë7ì=zÂw‹>Ufg[¸²yçÆvk;{Ú>WO}Ó`´: ˜‚¨ÂšwêöÝÂONþñ›2;+úYð„%«ín5ëîÛü­³«ÜÖ¾e·^ Û¶?ðãwû6S·I‹Ä¨†Çëúþ/ŽfÐë/üóWNVfnvÖ¹ƒJ­}4j×ñ×õ«wý…§ßßÛ¿WØ;•2ƒ^¿îãI&Íxåò† ¢jÚ¿ecÿ S›vRæä¿ žýë÷[çOÏÝ´M(‘l˜3íÊ¿ÿöüâqa;¿úìƒÙ‹}›µ<ñû/{¿]7ý‹ê<å¶ÕKzŽײk¯Ì´TFcçì:ó«MG~Ý–ž6xê,šfŠMˆ #%iÛê%íûn×gPvFºñRè_[¿[H—íøæÉÍ _¾ZU§Q3©µ<&4D£RPæddž…Pæä<{p÷“¯7;ºy|1uÜÃëWšvèúñúï/>ðøFÐø%«hšI,Œ'Šwö¬‘{'øÎÍc»w6ì¤Óhî]â -ºô@Q”­³Ë“[×Ëü3¯BH0JDÕ ¶”¾÷áÇÆÇõZ´qõ®m|0yÅÚ[Î0 3ký÷Nž^Æ-»õ¸¬´TV@j­X´e×™¿~¿wù<_ (¥.¼V£1ètýÇO Õ¨9޳´²žûí¶ ÿx|óÚÐs¨RëÚG>}l0·ëPVïš ªG§#¿ü”éÛ¬•ñàí gd ›;ψÄOïÜ,6 ¹w[«VÇG„¥&ÄegdƇ*s²£CžhØI"•I¤¦U7–VÖB‘X§”Z+J™I|D¸N£iÖ±[þ±ê¼¼°‡÷z™,“+ê6iΰlbt¤´„«ªŽîžu6ay|÷Zus23i†±´²I,xA‘óÆ…‡Ú¹¸å?õ®ï?uÍ×÷¯^ÌJOmÛkÇÔê´wq¿üï?œÁðfËF«ŒQ5ˆ$‡Œ0>ö®ço|@3LÀ Š|°]ßA…[Žƒ>|ÉÕJša:½7ìÅvïzþùg,]Ø£{MÚwö¬[eÒûDŘ´ì‹k'ÿ½õâñ=¿ô›0¥Çˆ±•Jdai¼ôX·Q3ךµ‹=P«V±<ž^§Õ¨ µ–w6Z iµšfÞl}§V«1 …¿UêuZN'‹0 KÓLÞóÙTÔyyùy<>Ëã è—¬öQ88ªU²,eyþm9Žã=¿56=%ÉÒÊúDA‚Q‚ ÞMWþ{ÛùOYÿãõß[ÛÚ½å°mzöoݣ߻üK… Š¥Ój; Øï½}›7„?~Àqœ[­ºYi)=FŽcy<­Z­Q«Œ=išV)só×|;yÖ`X¶e·ÞÆ,¿Yi©"‰…ƒ«»2;+.,T&·Ñët*e®ñ'Ëç'ÇÆ †R6Ú88éuº¸ˆ0…ƒ£^¯Óiµ" K;g×»·šuì–«V)ÜÜh5jen€Ðw_ús³²Š\Ú´wu¿qæD‘nlqÙÙ“b¢\½k½ôÕ F ‚x5 èð|ò?ÊÒÚú퇈ªF"‚¨`ËÇ ±sqµ²±{tãêè¹K(Šê>bÌÆy3ÖLþ@nïùôñÀÉÓ{z<ëúq·rüК 1»væ:¬›9É£ŽOZb‚‹w­1ó—;zxõ1vËòy>MZ$DE4ïÒ³Ëê4lòï®íËÇ v«Yçýé³óïàæèîÙmØè-Ëçù5o•Óiðð{ô9î‡%sâ"£#}š´põ®Íòxžuý~Z¹ÐÑÃ+6,Ęu¸$Þõü÷mÞ°xä€~ †Î˜#KÔmÜìä¿%D…;¸y–rlnVfÄ“‡½GOz«Ï·Š#Á(Aï"¾PTR&‚ ÊÜ‚Í;Ó“9pƒ&ÏP8:°sv]¸ù—˜Ð½^g)³¶s1åM³YÍûnGZb¼V£á  à ÿdA|D¸2'‹/Ú»º (ªçã›vè’™žÊòøÆün¼|ë¯ÚýwRl4Ã0qñ{ó)šî1bl“ö3ÓR–çâU@½–m—nÿ=ìá}+[;/ŸzÆÛè#g/ ¾s“åñÜ<órsxùÖ¿d•qœ§åïUröò^µë@R\ ˲<ÀØè^Û§†_ƒë§Ž‹À•äÑõ« ËkЦÝ[}¾U F ‚ ‚(_¶N.¶N.E…bI±«±EIáäh,Ë{ñ.6Í0îžîÏ]t¤(Jj-/iïÑsǺy®îKÓt‘b Kÿ6EZÄÞ¦µ­…;S%•+¤òç601,Ûoü‡w.+}2*eîà)³ïöwcŒQUé´ÚÇ7‚4jËãÕmÒœ/HKLü€•m ¿æž#Aï.—µ\j¼d1hÛÞ*f2• F ‚¨ªô:ÝÃëWÒ“oœ=ñå¾cr{é)Iw.žMˆŠˆDŸ~³ÅÜs$‚ ^‚£AT^jUžA¯Ï_˜U„@$zú쌔¤«'sÿU¬á[¿†oý‹G."OATZ$%¢ÒÑjÔ?,™£R*3’“2ÓR}8#°ßàô¤Ä5ŽZ»ï_Gwm ~2iùæž)Añ¶H0JD¥Ãq\FJ’•Ýüï¾yþô7öl0è3R“TÊÜüzñAT3·ÎŸ¾}þ´N«>kAé9•ÊÖƒ K7ΜPfg™ö‰Â¡´Â¿DÙ"™™ ‚¨Œ†mÒ¾³…•uÝÆÍ”ÙÙæžA$%>î—¯>ó¨ëÛaÀûÂÒ3•‡´Ä„]ë?wôðêôÞ0 Yd~Qbtäò1C¢"Êcð*\%¢2¢YVla  p%ÎÀétZ–-¦„ AÕ@äÓG‘ÁO†µsreù€ Q©¢"$2Y̳`Š¢jù7Š%Yi©¡ïð¬ëkec§Q«’¢£²ÒÓ"Çq•ªfƒ†<¾àÅSD? ÎËÍQ+•r{‡äØO?™Â&&4$üу¼Ü'_@Q”A¯ #ŠjøÕ/)3qRL4ÍЉё:­ÖË·¾¥•5Vöð^VFšÂÞÑ£¶EÓqaQO'ÇÅD<~˜“™áèî%‘J¤&Ädž…P4]³^C¡DR~ŸmeF‚Q‚ ªšf(šN‰‹µur‰ {–ßβ<©ÜF­TîÌãñs²2J¯ HDesbﮄ¨ˆôäÄ£¿m—Ê#f-´Éâ#Ã×}u|É>'‚¨xÅÑÐòè¬b¿r µzËÛGÍ]þøÁŽ/–OX²ÆBfe¬än0²ÒÓ}8³Eçz½ŽåñOïÛÍãó§¬þŸ@$^5iÄ¥#µë(±°³`ùªI#{žxõØáذgÅ£ê“YìQ<>ŸeyÅãó59¤Vrߦ-ùB¡ñiÄÓGîžÆ½M®QÏž6jבáñwØ­lli†1”üŸaY…½cBT„H,aXÇq,ÇòøEñxçµÊjÖoDÑ´½«;/HŒ‰.6àV«ð|aXŽãr234µ£EÓîµ}²ÒÓÒ““Ý=YÅòøÆõ9™IÑQgüqíô1Ñ!O¢"^7ÕsB½^øb»N«¥8¥TûZ£™ F ‚¨t(šv­iª¹Çã j5hd|laeíÛ´å‹ýùá‹¥ü$R™§TVÎ3%¢x6ÛZ™§õ.6}]Mƒ*xʈr238ƒ¢iƒ¡ÄTÄ/ðetZ­V£`Ðëõz])g)²Ö“fš¦ z=­FM3L±«W–[Xœ<£fƒ†ÆIÙýÈÒi4VâH–Q•Հ劬¦"‚ ¢ì),ƒÁ\™«Ó¨Iø£aîG?{úôö:š–ÇYTyÊsÿÌLM¹}á Í0Žîž¯x ÂÁQ"•ÝbX€•íøÅ«ŒÛá›tèâÛ¼•V­ˆDÂÿfΰl÷ác;ô_¯×ß ÂÞqü’Uy99à8X̳úóu efrSm,Ÿ½¼wå@‚Q‚ ‚ Êçïþ[LZ‹¬Ì–©”¦™—Ð #za ¦1ëpa ËJ­å}hÚx”ÈŸ)1AR‘¥Ÿù‘"Í0/® åñøùWXÃÝ¿vê߯vè?ÄÎÅ-?õßP%¶°Ä Ó¦(ªÈS–åS“– ƒ^Ÿ“™aoy¹®óA€+«aËY3JD…ÊJKݵ~u^n޹'BD¹ã1ʾËì„G3S5ªª±™ÆHl)õ¿=¼ò[„b±ƒsá?ÅnK2#µ*/3%ÞÉâP@µlqùž*-re” ˆ ÅŠ¢‚ŸÜ¾p¦U·Þæž AåN&Šéì·èQ\ßÛc”ÙŽ<Ÿåñ8ž^oИ{j/a)³Çé4¦yÚ9¹Úõu-Ò'ÿUsáƒN§Õjt ŸŠnå½¥¦Ãñª‰‚£A”7–¡i |Æt†oiÑ®÷€{v¶îÜÇçë œ«2÷’ˆ*„¢(]ü"?-8AYä"^˨ê¹îuW\ŠÏôOÉ®–SCkÿ·C¼z›©°zfcùÔÑêŽT_…îÎç#ÿ ‚(_ß Ó«4Úüí±5ê7üåk¢#Ã]¼j[r³2ÿ÷ÉG®5kš³Ä|3%ª ÐsœÞPÌ/f•J-%9h+N&Ž‘‰càøN/Ôø$-ÇPÚª’O´$$%¢| y¬…§×ëòƒQ¡X,KRããòƒQŠ¢xïuò¿Ä›á8N¯Ó*,Å/ïJ”–QUõà‰([$%¢|ñYF*à§j´ù‹ý)šá@ååææ÷YXN[ó5ÍŸHD¹3ô< 2qäÐ!¢LÝôA”/š¢¼ìäªÜƒÁTM^§ÑtZcéù|:Îð_¹y‚(7\^NŽÂB$‘`” * ŒQî<íä®Ö–9™Æ§™©)j•ÊÖÉ%¿ƒ2;kÝÇ“ölüÒL$ÞµšÒ¨›y¹0%ìm"¢â‘`” ˆrÇcè¦^άA——“c0®ž8Ò°m µ­m~­Fe,ßLåD§Õ(33¸;Ø£Q™`” ˆŠ`%µ­íÎjU1¡!÷.Ÿï6ltáò€)ñq<¾ Ã€÷Í8C¢ã8N™““–V×QáãD¾óDåB¶ Q(ÀÝÆJn! Ž;¹ÜÎA¥T²,ËðXŠ¢Å–Ò‰K×È6æž&Qpz­^£Õjµ­JeÉg|½\äRº„ ãA˜ F ‚¨8–BA Ÿw-g»˜´¬ÔevNn¶V¯7p|ÈÁÍ+%>ÞÜ$ªš¦D,#æ³vb¡½ƒµ‡­µDÀ3÷¤‚( F ‚¨P,M»)¬ÜV:ƒA£ÓkõzR€‰(À24ax,C®…DeF‚Q‚ ̃¥i–OäbATIII5 11ؽ~~æž Q•‘ LAA¼6…[·‚¦¡"Õ”ˆ·C‚Q‚ ‚ ^ÃÀÅ|RÄ—xk$%‚ ‚ ̆£AA„Ù`” ‚ ‚0²›ž ˆ²¡Õjoܸ‘ššjî‰Ä[Q©TæžA¼CH0JDÙÈÈÈøè£hšÜo!ª6ŽãT*•@ 0÷Dâ]A‚Q‚ ÞŸÏoÚ´©ƒƒƒ¹'BeF(ZYY™{ñN Á(AoK.—oݺÕ`0˜{"Qf(Š …æžE¥–”„q㜠–„ÄÛ!ÿ‚‚x[E‰ÅbsÏ‚ ˆ %—ãÛoa0ÀÉÉÜS!ª8ŒAñÚXîîæžQ-­AA„Ù`” ‚ ‚0ŒAAfCÖŒñ¶t:]DD„F£1÷D¢ÌPåææ&‘HÌ=‘jkï^øúÂ×·OñÉ'˜6 7bêTxz¾Þ±÷î!$–ÏÌ998|;C.ícEh(¼½ñì¦N-¾Ox8V­ÂÊ•pt|Ë™–;Œñ¶RSS?øàƒÐÐPsO„ ÊŒX,þå—_Ú´icî‰T[›6aôèò FOÂÈ‘8}#F¼ö±W®àÏ?Ë7ÍÌÄ·Ù IDATƨWïM‚Ѱ0ܾ šÆ­[%ö±µET¶oÇ‚o3ÍŠ@‚Q‚ Þ–Á`HIIIKKsqqáñxæžA¼ŽãâããsrrÈÅþÒýï8|4 ™ _|//ÄÇcåJÿ.àéSÌœ ©sæÀ×+V sgtê;w") Ÿ~úf9`aiÓðÉ'?¾øùW$%¢lXYYmß¾½V­ZæžA¼•¼¼¼Q£Fݾ}ÛÜ©ì¤R¬Ykküü3-ÂÏ?C¥BÓ¦˜:¦OÇ?ÿ`èÐblØ "<={¢o_(¦öÈH|ù%fÍ·ßâÉ0 nÞ„ñë­J…#Gðé§HMŇbÀ,Z„={°b¶mCIiŽg΄“f΄³3¨Õ8v :à믱y36lÀޏ}Ÿ}†¥Káå…?„‡†Åô騳'ObáBðù(©×åËX´+V vm¬X_~A¯^8ssæ`Ý:øø€ÏÇÁƒøøc;|õ.^Ä‚ðóÃàÁhØóæaÒ$xyÁË b1( ßö푟~ÂèÑ%~ø­[ÃÛðò*íï¨];ØÙaÏLŸ^Z7³#Á(Aeƒ¦i[[['’ÿš¨â”J%ŸÏ7÷,ª€æÿoï>㣪¶>ÿÏ™ÞgR&½BJB“^TA¢à¬Ø@±\l€¨ˆ¯×‚€ ˆ…"J‘b ”Þ'}z=!@’L€õüòafÏ9{¯™$d±klØ€òr#;ÂÂP“• 8r¤þdÔÛÞÞˆÎ/z)&3f@©DÏžõ7úÏ?(.†¿?΃Ÿ6mByyƒÉ¨;™›2å¢ÂÉ“‡ÁƒñÁ0™°?‚ƒ1v,„B ŒíÛñè£èÐ!!P(. ïÛ¶A£@€ÌL„„`ûvŒ¥Ý»C«EÏžHNFQ°,{ :!$_ãÇ1f D"Èdˆ‹»Ð¹;~<ÆŽEJ t:””àž{lºS§š WŠP©ÄÓOcáBLšt!éo…h5=!„B®Ma!ÆŽ…Ó‰~ý–€ñÒKFÿþð÷‡ÕzÍÕFDàÊkƪª`·ãÈìÚ…ÔTŒu•ë/'ËÂfƒÃÒRˆÅpÿïC«EEÅ5TU^»»wc×.¸\5Ãë@M`åå B£B!tºú+ŒEûöزë×cèЦYxtï½ËñóÏMPUó¡žQB!„\›ädH$˜3R)–-ƒÃGŽ`äH<÷ìv|ñÅUj‹átÖSÈã]ô4' C­ÆK/!2ª«!—ßЉŠÂލ¨€Z3gjªàí ‡ø 'J‘‘(,Ä¢EHàrÁh¬I=/g±àÌôïŠ TU]hÅá@Ý™Éb1zsçB*ÅgŸÝÐûª¥VcêT,_Žqãnô³j>”ŒB!äÚÄÆÂlÆë¯ƒÏÇo¿Õ ”÷éƒ×_‡J…Ó§qüø…”«^ýúáÓO‘”„Þ½ëÍ0x0æÏ‡\ŽÃ‡¡×@×®èÓO=…{îÁùóp¹°t)$’ë#C‡â‹/0}:üüpèV®¬)‰AAžxááxöÙú¼‡­[ñÄèØIIèÞ÷ß_+<>ýyy8u ÁÁ5“4„„àå—Ñ¡¦NEÇŽ0p h4èÞýúßT] ƒÀŠøåLœØ4u69JF !¤~Ç­ZµjË–-‹åÙgŸÍÈȘ:ujc¶ 0™L¤ Mdk´9sæìÚµë?þP*•7XÕœ>}ú¿ÿý¯¯¯ïâÅ‹ÅbñWèp8 ƒR©dÙzf‚þ*u_Ú­;hôïî߀ª*0 Úµ«§³S«Åðážž=‹ŸFy9FnÜ[j†Áþ±F#%£„â!.—+33Óétzyyeddh4šÈÈȳgÏšL¦víÚI¥Òœœ³Ù̲l›6m*++ËÊÊ|||’’’ŒF#Ç1b„Ñhlß¾½H$2™L999î^Ï¢¢"¥RÙ¶mÛS§NY­V‰Dk6›SSS­VkJJŠ···^¯·Ùl~~~iiiB¡°C‡|>@AAA^^€€ÿ*–——Ÿ?žã8­Væçççî\¬¨¨(... ÓÓÓ+++ù|~\\œäßþ“ÔÔÔªªªÀÀ@§Ói6›£¢¢ø|~aaa^^ŸÏ‰‰¹¼§V¯×Ÿ>}Z(Êår†aÜ免²ÒÇǧ¤¤Ä`0„††úûûgffêt:±X'òòò ƒV«ÍÌÌd&66¶nÍ6›íüùóiiiî!$$„a˜óçÏ——— ‚ˆˆ•J¥R©šû;NZ‰O>Áþýžz{cùr4gGk$aÔ(øù]ýÊÔT””à“OÖÄ1øøà¹çš¸Î&DÉ(!äÖçp86oÞ¼lÙ²ž={HII5jTjjjQQQttô_|ñǼ÷Þ{#GŽ|ýõ×çÍ›·téÒ-[¶¸\®M›6õïß?==ýý÷ßß¾}»Ãáxçw’““£¢¢ôz=Çqƒ :|øpï޽ׯ_?oÞ¼¨¨¨ääd»Ý¾iÓ¦Þ½{§¦¦.X°`ذaþþþÇŽë۷﫯¾Ê²ìðáà  P(öïßÿõ×_·iÓ¦¨¨è‘G‰°uëÖM›6Åý;fyâĉéÓ§:töìÙiii³fÍ>|xvv6€åË—K$’üqéÒ¥¬¬¬}.\˜––6sæÌäåå±,»lÙ²º‡[Æÿüç?</22òäÉ“N§À?ÿü³téR@ V«³²²¦L™âëë»|ùr÷ [°`ÁáÇßzë­N:gffúúú¾÷Þ{µùhuuõÁƒ+++·mÛ;a„U«VmÚ´©W¯^‡ üꫯZø»O<èÉ'ñÈ#žòx­w Mó‹<±ó÷ßßà¬Ó[ÜîÝ»9BùWRRRYYY½/¥¥¥ååå]^^PP­ÕjOŸ>ÝÌÑ]¿ŠŠ ‘H´uëV‡Ã1iÒ¤aÆ™Íæ””µZÍqœÝn5jÔûï¿ÏqܶmÛfΜÉq\rr²P(tßîp8¢¢¢2228Žûæ›o‚‚‚ÊÊÊ ßþÙ»wïE‹éõú;w>|˜ã¸·ß~{Þ¼yµM …ÂM›6qwæÌµZ““ÃqÜ»ï¾[PP Óé&Ožüî»ïr7gΜqãÆY­V§ÓùÒK/={–ã8//¯sçÎMž<ùÃ?´Z­ÇܹsçÜÜ\Žã²²²:tèðǸ#w,Ÿþù“O>Ùôßã&b4 $•JwîÜY·Üjµ;vÌý]¸„ÝnOLL¬®®¾Bµv»ýèÑ£‹¥nannnZZÚå›Íæ;î¸C(îÝ»÷òWM¦ÓIIà8ú¢¯ý*,Äë¯Ë³³³/ÿ™4 ÿýw½?ùN§ó’"ê:|ø°Ùl¦žQBÈíB ´oßžÇãiµÚÈÈH±Xäž‘Éçóüñ™3gNŸ>ýû￟9sæ•«Šˆˆðòò0xðࢢ¢Å‹oܸñÞ{ï}®‘°h×®˲gΜ‘ÉdgÏž}öÙgƒ‚‚²²²|}}œ8qbèСîíÖ,XP;9uÚ´iùùùï¼óŽû%‹Å²jÕªß~ûÍÇÇG¯× †ÒÒÒœœœ=z0 ä>møûï¿‹ŠŠ~øa.—«¸¸xçÎK–,0qâĬ¬¬ÐÐP†aºvízäÈ‘Úh»wï.‘H"##“““u:]·n݆ >uêÔÀÝïˆeÙ°°0¥R™””ä~ƒ—+..fY6::@ûöíç͛׸ï!ä6BÉ(!ävtù´ÅAƒ‰ÅâU«V•••uto²Ò8:uÚºukbbâ»ï¾k0>üðÃ˯)--õòò²Z­6›M¥RmÞ¼ùèÑ£¿ÿþ{PPТE‹***ˆÅ⊊ Žã†9w¿¿V«0}úôõë׿öÚk+V¬H$üq@@À‡~¨R©:侑Ïç»+q÷ƒºU«Õ£F3f €¤¤¤¶mÛúùù-^¼€Ïwß}g0ìv»@ 0 Î:[>Ö®‚—J¥,ËFv»½¼¼\þï «»9›Íf·Û½êÝöÀãñìv»Ýn`2™RSS®|b ¹ù½ñŒFLšt•㋚œ^œ´oߢ¶r‡¢"äçÃßÁÁ5…™™X¾R)^~¹µÌߥ˜!·>—Ë•••år¹rss+*****t:]YYYff¦ËåJOO ‘HÆ?wîÜñãdz,Ëqœ{<ýܹsv»=77×n·ggg›L¦ââb«Õê^~à‘GINNîØ±cß¾}­V+µZ}þüùC‡=ÿüóî%ê«W¯NKK[¹reTTT||¼———ÉdÒétéééþùgEEEeeåäÉ“·nÝš””túôé'Ÿ|²ºº:;;ÛétFEE½ýöÛ{öìùâ‹/JJJD"QQQ‘N§Û»wïùóçóóóårùСC¿ýöÛÔÔÔ~ø¡¬¬Ìؘ1cvïÞm2™ -Zät:U*Ulllll¬ÏwÞ™““³k×®ÔÔÔ7Z,–âââââb½^_ZZZYY 88xРA+W®LKKÛ´iþíâ°aÆäää_~ù@=¼ûî»ßÿ=¥RÉãñ²³³Ÿyæ±XܦM›U«Veffþïÿûúë¯Ýo¼ªªª¼¡ýÁÉMnÅŠšs†Z’ÝŽ°`²².ÚF¾1 ñÖ[ø÷÷ÆÃŽÃÒ¥MVÛ¡C>Ó§cÄìÜYSÈçC(Äš55[·¶¼G}4ü’­!·±ââb¥R)©o;÷‚èË÷¼4 +W®´Z­S¦Lqwæµ6v»}Æ ¡¡¡ÕÕÕ*•*++‹eYFsèСÂÂÂ>}ú¸G¢W¯^ýÉ'ŸˆD"§Ó¹nݺ˜˜˜¼¼¼„„„ßÿ]©T–••µiÓæðáÃf³ÙÝÉÇqÜæÍ›Ýó¥^yå•Jåçç·oß¾ÄÄÄ‘#GÆÄÄ,X°`„ «W¯.,,\¸pahhhXX˜ÉdÚ¶m[rrr÷îÝNg@@@¿~ýx<Þ† >üØcõêÕkÓ¦MZ­Ö`0„‡‡;Îêêj‰Dòàƒ&&&}8°k×.“ÉôòË/Æ£GÊd2FÖäk†›‚Ýn_»vm~~þĉÛÔî 8Î’’???^Ý3‚.—«¤¤ÄËËKÔð¦—.—«¨¨ÈÏÏ_çHŸêêj‡ÃqyײÃáøæ›oŠ‹‹'Ož|ù§äpèÊË?kÌêløà¬^:ŸJKqît:h4àñ ×£° Xf3²³!“ÁjEi)JJ‘— EÍ¡šyyp:‘›‹ÌL°lýëŸÌfÌ™ƒ5k’‚ ¡cGèt0™›‹Ü\Èå5{…:ÈÈ@Fìv¨T`âÔ)|þ9:w†Õ ¡°æÊŠ ¤¤ ¤jõ•aŸôtA*­Ù8©¸©©(+ƒJ>.òó!‚χł‚¨T5 œ;‡*ää`ï^üò zöDe%är\ö³— yy‹¯«³f¡}{|ú)Ê˱a&LËB¥BB֭äI×Ö3j0àØ1a—.Ó/Y²Ûí¥¥¥—ßåþ}C©f~~¾¿¿?-`"„\äV]Àte999¹¹¹7n|õÕW›¼r¡Ph±Xl6[“×\kóæÍßÿ½Åb9{ölDD„»O· ¹\.—ËUû4>>þĉv»Ýét6mC­-`ºÁ/___xzì À¨Q¸óNÌ «ÙÙè׿þ §#ñãQU…={Эú÷Ç}÷!!»vÕÜ>a†Gß¾èÛ3gÖßâ¡CèÕ ›7ã±Ç—‡¢"pæÎE¿~¸ÿ~ôë‡iÓ`6ƒãðùçèÖ #F !›7ƒãðÁ2Z-î¾#GbÏpNœÀàÁ¸ï> „éÓa04øf·lAïÞ=ƒcÉpNŸFŸ>¸çôî3`6£ºãÇ#1±¦æaÃÀq8y119#G¢[7$%¡¼O?=€‘#ñÈ#Èή§E“ O<{îÁš5ÈË»Ò7¢¸±±øóOpáë{ázññW¹0BH‹Ú»wïºuë„Báûï¿ß´5¿üòËÁÁÁ>úèªU«š¶æº„Bá’%K8=kÖ¬zû'n„{R·%K–8ÎÅ‹øá‡­³#œ´*¯¼‚Aƒ0{6*+1t(ÆŒAçΘ>óç#?kÖ`íZ(•°Z‘—‡_~A|<ÞxK– GH¥(+ƒÑˆ/¿„·7ªªêoB©„ÁPs”‘R …*+¡VãÛoqþ<{ …… ±læÏÇèÑX¶ ‹£<ó  ÂsÏaÉA*…Ãÿþ X°åå?ÿüS³‰ý%ŠŠðæ›xôQ<þ8 TWÀŠð÷ÇÊ•HKÄ xàtìˆÒRØí`·C§› ee˜5 wÜÉ“±w/¦OÇ{ïá—_ðý÷Xµ S7°XŒ×^ÃŽøþ{|ü1zôÀĉ¸ãŽzúP-”–¢°Çãµ×À磸ÿ®ol](%„xXí£Õfµ;œ.ÎÓá Kßáí:Š%¡Ú'·¬¿x×e씩£'MPTm˜«^}ÚßÑóÃϾ°Ù¬B¡ÐÏϯ ÒÐL xïȃ†°,ÏÈñšö³jZ,Ã<1Ÿ/ Y¶¹>yre:’’ÀãáñÇ ¼¼æÏ1c°?fÌÀ'Ÿ\8å(&11‰0d~ùz}Í‘÷cÆ 6|}ëo%&¯¿ŽO?ÅÙ³1  _?èÕ J%‚ƒ!‘ÀéDA\.tï±ýûãë¯Q^ŽÈHÈå5܃ÏîûŠ <ñäåáäÉú“ÑÂBèõ2¤æ4y6NÂØ±Ë¤¤ ¡õþþèÒ"‚‚`³a P@&ƒ@€+œ Á0 ÁÔ©xè!lÞŒ7ÞÀ®]Ø»—/#d°,d2t艦µþP2JiQ6‡3µ°4§¬Ò`±Y].'Ǹ8Ï'£5Œ&”f5SÝ)g³›©æ‹­¨Èi‰†àHÖçµHC׉e˰à$¾V)‹ ðõQ\zinîìgÚ´š¥ÜO?¨(0™•çÏÃé¬9 ´ö_wÚT›9]õKcÆ m[¼÷ڵâEèÒÀ¥‹¨Üº[¹¤ ÷0t-–Ÿq5YòÓO#$¤ÁwÇq¸ä]wamµº Íæ W …¸ìX4¨³³E=ÜÃåûöᇟ{îÁĉõ'¯"¼½¡Vã½÷pâœÎF唌BZÇA§7IÏÕ™¬"©T SJy<–e[ïÿÖÉÍŒep.›ÝaqØÓË ™ºÊ„PÿØ@_¶‘i9>>èÜ'OÖœÀ~ò$ ¸\øàX,X·O?0~<¤¤àÔ)t[]3ÚÞyy5I-Ÿ_³FªÞT‚‚ÀãáàAaçNÀÛ$ HKƒB¹¾¾HHÀùó˜4 ÒÓì§ „Z­[½:bcÑ©vîÄäÉHMEi)ââ ‚ãpö,°eËUÞ‹TŠŒ ää@¡€RYÿàûë¯#;cÇâ®»Öà¿ *Ú·ÇúõˆÅš5èÜ™’QBÈí㸳ºc™Š•Þ>u—uÒL–å |@$–X-æ£YE•ú~±ábýík9~ˆÙ³ñàƒ`µâÇqêvîÄŠˆÇÛoã³ÏjFÕU*Ì ‘øè#¸·ôðó»zVj6ã“OPZŠìlèõxí5H¥ðö®I"y<øûƒÏG@^yË—ã»ïP^Žÿþ·æ‚  Œ —ãå—1p Þx¯½†qãÀ0°tiý«ÎµZ¼ó.ÄîÝ0™pÿýˆÅÓOã¹çðàƒ0™ðàƒèÚ"xË–áÇÁ0‘¨ææB¾Ûµ+:tÀ´iðõÅÂ…õR/aÞ<øùÕß«zÉ•3gâùçñÀ°Ù°xq=©m+A¿„– Ó›þÎ,*”"q=›FÒ¼F$‘òÂÜʊĬ‚^Q! õÇ7§ 0u*Üç$$`ýz€¿MÏåÆ5½tîµäîʸ8|ø!¬Vøú¢viÜ\=늎ÆwßáàA¬\‰+j®ñÅšÍÔj,_xä ½^^rAóçcÚ485ÓR۵÷ߢ N'´Úšðê5x0 ÓÕLåƒ~@Aø|„…ÕlõÄ:N'a2@Û¶øâ‹šJ¦O¿°O“·7¾ù%%`Yøû×Ó"Ë^´mÖ•õê…ß~Ci)Ôê K—²²ðÑG5Ë­Z JF !ÍÎjwIÏeEbÊD‰ñø|™Ru®¨,ÄKâÝð rc>ùËE]‰*ÕE#ÝÍ…Ç<ÞE32Ý‹êjäȲH„¶m1tè…̵vAË^È;Y¶ž¾Fwµ¹)ˆ‰©yl·#1†:ËWóØÇ§&Ó­¥VC­¾¨D @Û¶5Ý…PˆÚM/.Y{$‘Ôäõñó»ô3”Jѹ3zõºèáY”ŒBš]jai‰Ñ¢öi`),!-E Ú%²c™ù~*¹ßZÇ,or=t=wÝq-BÇ\]P~øúo¿› Û¶!?ÿBIŸ>’Ñ›ŽV‹)S<ÄÅ(%„4/§Ë•[^%‘Éš'JZ±Tª¯(Ó[¬ÞrZ\ߊ¸·Fjd2¼ù¦§ƒ¸¥ÑßBHó²:œz‹'x:B€aY‡J“ÅÓBjP2Ji^f›Ý`µóhH”´ Ãð‚’ªf<€rM(%„4/“Í.ÄÇ^þÅÖ·¨9éàÞ÷ŸúΓlXñÑõ5ª¯(×WVÜXàWát8J ó¯~]½÷:¥…\#vû/+.´Ûl××ÊËJ9óù믪›å˜%³ÑP]^Ö´už:´Íâ….— ŽÇ0õþÔ‰Ä"£ÍÞ´Mß2JJ0f }ååž…Ü6(%„4/—‹srœÍéª÷«Þã—"Úu|è¹—¢;vÊËH¿¾F·¬þrûÚ•7÷Õ”—}ôòôë»·²´ä“ÙÏ;ìWχþïٙ篯•gÒë3Μt6"Îëpl÷¿|óMX¡Íjù}ݪàÈh÷.¶‡†ê»ãЧÜÜÆÔjÌŸ_³(!-ƒ0BZTiaÁÑÛ«ÊJ5>Ú>ÃG)ÔŽse=“tp/Çq]úßÓN¡Ö(ÔšôSIÙ™uï­,Õ%þµ³¤ /"®C׃y|cuÕñý{rÓRj¯~#îgXæØ“B¾L IDATî?Sñx¼]›Ö+5šnƒîj(³Áp|ÿîìÔ³2¥jà¨1J/o›Õšø×Î̳§5>Ú¾#Ԝ˵çç ~Á!I÷yùù5V$Ú±¥('» +cצõzÝ=\"“;ŽS‡öŸKJ”)UýFŒVj¼ìÙü£o`ð©Ãû5¾~ƒ'‰ü¹­('+?3}Ïæx|A÷!÷È•õl3”›~.íäñÜôÔC;~;ædpdtÛ„.IþRh¼"ÚuP’—“•’ÜeÀà”ãs..#ù¤Ýjí:pHxl{†aŒÕUÇöüQ”Ý}ð=‚kY¥\ZXpxÇ³Ñ Kj»oKòs ³2v{ÚÉãþ¡á}î §ŽìO;yB®Tõ¼k¸·€ÝfM:¸—eØôS'd*UÏ¡÷zû^^¿Ù`HÜ·ëÄþ=º‚¼]›Ö+ÔšÎýUèŠ3ΜìÜïN¡Xl³ZOìßÑ®#_ LI<êr¹²SφFÇÜqçÝB±Øépœ;ñÏÙŽò‚îCîñ wW›yötQNfç~ƒÿNÉå„B$$ !eMÜmMHƒ¨g”Òr¬fóÊ÷ÞÌ8sÒ' HW˜¯+Èü÷ág?o2,&ã'¯¾ØPG ¾²âãÙÏŸ8°G¥ñúùë{~ÞÀb2}ñÖœ=?ýàåç_˜‘›žj·ÚŠr2M†j³ÉX”“YZXÐP0v›õó7^Ù½i½·_@I~Nú©Çýþý·ß-Y¨öñ=öןŸ¿>‹s¹œNçò¹3¶¬þÊËÏ˪/÷oÙ̺ü¼ò’B§ÃQ”“Y”“ét8l]õÕÚ¥ï*Ôê¼ôÔåsg¸ WÌùç¯Wh´~;Ö¯Ú÷ÛOJ òËŠ vGQNvQN¦£Qx“¾Úýj¥®¤('Ó=¢}.)qݲÜ÷¿¯[}xdža¶·ò“ÙÏ[M¦ªòÒ%3žÒäY-æó_>üûV…ÆkÇú5ÛÖ~Ã]r~vÃLý§s_<:I,•íÚ¸Îf­YèsþôÉf=»míJ›Õ’|ì°Ù`8°íç•ï¾%‰Sûâ­Wúj³Ñ¸úƒ?|¶T"“'íÿ뫯YÜ|_Ìá°ëòó U•fƒÁý=r¹\“é»%‹²Ï›žºvé»V³¹ +cÙ+ÏÞ±U*—oü¿_· ÀÞ_7ýïíy Ë”~þú¬ª²RwµçŽÿ£ôòQyû\Þ"¹VBá¥G®Ò|¨g”ÒrlVKyQ᱓â{÷×øjy|¾Ãnß¾öÛvÝz3Áét楧%ÜØ&òò{OÜ«ËÏ}töb©T(‘ìÞ´~ðƒ²RÎ$ÿ}èý¿k|µÇ9ìvP8ñÅWMz=_ ˜øâ«W&#ùtÒ¿>ÞºWéåÍqœÍjq:ì»6®{àÉç×eÀàîí_RçíÀ°ìÃ/Í kc6èÓN&3aäcOåd%þµ«¶ ‡Ýö㊦Î{;®k÷N}½ùèØ¢œ¬ ˆ(Î~#°M¤ÝjMþûð£>yš® ïľÝãŸ{ù –1»Åtîvbÿ_CÇ=Ù!Á]ØëîÛ×~[”“åxø÷ߦ½¾Ççè1tؘgfp.çÛi©Gvl ‰ËNMyî½ejo¥ÆkÛšo™(SÔw áeÎÿ§ª´ô…÷>Ñhý¤rÅoßþ¯ö%µ·ïÓoàíà°ÛXÿÏ×=îþiÏçf¿õØC™çýBÂ\.ט§^è6hhçw.|â‘‚Ìôˆöñ—4¡PkîŸöŒL©<údíÚ6öï];¢ã;Ûµ#$ªm@X›ªò2µ·ï¤™sü‚CÕ>Úß¾ý_Ï»îýcýê~#F÷vŸÕbY>wFFò)wohaNfÀ¿½¤ä…„`ûvôì‰N@{²‘æFÉ(!¤åÈÊ£ÆlýîëíkWjƒC'Íœ£ôò.ÉÏ-ÊÉúrÁ|&CuCÇÖ—äçšÆ5Kp:ì‘@aV†· ÆW €aPØø`Jòr4Z?¥—·û^‘Xb³ZÊŠ µA!¼ýüeJ•.?ÏÛ/€aXÿ0*/Ÿü¦±VèJLúêý[6Øö+•·oí *mp¯6ý”ƒnäÊàÈ趺ØúsXL;‰\ÛùwyHT ˲`YÂìL™Re¨ªøqù†å9v±TÊ9;E²BW¬Pk$r€€°6u?Rÿ°p/­?¾@h6ªËËÃ#†ñö Ke¥…ù~!aR¹Â=n®Òxó]AþåÉh½x|þ€Qcøtq¿£ïÛýà“ϳ<•·»ÑÀ𣾺87»º¢üØž?ÎþsXÍ5¯fƒA¦T_¡ Òx]»âã1w.6o†XìéhÈ­Ž’QBHËay¼»ÇOîuÏ}ŹÙk—¾»kã÷cŸ™)W©;õ0htͱ-Âÿô1,ãr8jï•)UÁQÑϽû‘ûTq÷ú*ŸÊRÕb¾ä Q~#¶5U¨5úŠ »Í*ÖtO2 «P«m ‹ÉdÒëå*õ¿ÁÔ“"×û–«Ô<>âŒW}kN”ÈäWhÝÕèAP›ÕZ÷éÀQc7¬Xš~êD»†‰e2waei Çq Ã*+|bÚI ¿°'ßzO,•¹ƒ—ÊlNªPšŒz»Í*–J ÕUÎ:Y,ËòjtI¤"‰ÄdÐ0ªíV«û³²˜Œ†ªJwØN§Ó=q¶!ö‹ßZl—;x|þÖÕ_q.WÛN]Ý…f“ÑlÐ ¼¼«+ÊB¡ÊËG"“ß7åñ=úÔFâ~qæd#ß&¹²mÛ0e ,ÀµüÿŽëDï„–c2è·­]Y™Îãñ"‘T¡ŠD½î±ï·ŸÎŸNÒåçÞ±¥(;Ë}qPDTæÙÓ‰{w¹ç&ôî_^\´ï·ŸÊŠ “ÞÿÛfQ:©¼½\¾4;5ùï];2’O¹ï ‰j›züŸ3Gf=ÓP0mºzùùÿðé’ìÔä£nOKJäóùúúmÕ™gOÿúÍÿEDGF5t»L¥ÒWUîûí§³ÿµY­™¼Ï½£6¬ø¨8/'?#}óWŸ1lƒ} b‰Ôl0¸ï­íØ«—68dÏæ“)ÊÍv—$ô`µXROë3lTmj¸ËæÓGùc[ÖÙ3ûŠëÚÃn³íûuSYQÁ¹ÿìýyƒÓÑØñÑñ]NçÞ_6¦Ÿ:±í»¯í6k½—±,ÛeÀàÖýç螟~Keî9 .—këê¯ÒOÿ}Ý*…ZÑPC^~i'íþ#óìiwÊ«Pkº²û§õú ªúY’—»sã÷i'·®ù:¾wÿ€ðˆ.ýïüóǵ¹éç ³2voZ_»ÁV›¸öÅyÙîü˜Ü «”‰’B=£„–Ããñ*JŠíÚ!‹£:v:îa0Ì€Qc\Nçöµß:ÿÐð„>ÜG¶O¸ÚôCÛ k§ }váÒß×­J:ðÏ¿óñ¯g~´uÍ×ß-}W$‘Œ}úE÷½Ý‡ ++*ܵi½_phx\ûzƒ‘*/~¸üç¯>ûné»|>Ì33–7}æÚÞ[»ô]‘DúÌ‚Å|Ðåtù ûÿÐðÚžB…J3mþ;'öï!‰›ûßß¾ýßúO>t:mº0` ù »WU×µ‡;}Th¼›÷ßãûvŸùûЄf×öí]nâ ³w¬[½sÃÚø^ýÜSÄilç;ª+˵ÿvÁˆNè²uÍ×›mü󳢺òx¼g.ù}ݪï—} ßˆûY¶±‡xùùÿgÎ[Û¾ûæäÁ}mâ:¶ïâžØêÜ¡{¯ºWŽ˜2Ía³mü|™H"ylî[_?}e…L¡Ke?®øH =úêj߆êн×Ї9¼c«O@``x$O"бgß?Ö¯é>äžÚË|ƒÊ‹‹Ö²8 ¬ÍèÇŸå £¦=³cݪ_¾ùÜép´‰m_;6¦s7…Æëì±#]iä›% ))ŸÒRègÒrDéÄ—.*…wä®ñ\RΙ0xÌ÷S†aÚvêZ;z[[óä[ï]r¯B­÷ìKW'0<âé·?¬[¢òöyúíê–°<Þô…KÜãºõˆëÖ£ö¥#¬ÍSÈUêñÏϺ¤‰gÞ©¹7:¡KtB—Úò>÷Žês飼GØ&òÑ9oÖ>µZ̺ü¼³‰GÇ?÷2¿N·U|¯~F©{c›vŸúïEo¤ñ:öìÛ±gßK £:&DuL¨[¢P{=2ëµK.cy¼ûŸØp‡h-‘DzߣOÔ>å\®ÊRÝß»v´i×!4:¶¶\©ñžúÚ‚º7JåŠû§Õ³Ã«\¥:vÒñ}»» ÌÔw˜iŒ²2Ì‹ãÇ1{¶§C!· JF !Äö®þ*7ý\íSßÀàQSŸrï¢z‰œÔ³ë?ý°ý½º Z[è(«o§ÒºRÛ³ùǺ%Ã'OK:°7ïü…v5¾Ú‘ÿyªvêuàñx~Á¡Á…,9'-uÛš¯ë^sÿ´güBÂ.¿×j1oü¿ó3Ò'¼ðJíª)‘Dâ^þÕH=† ‹írÇuÅNjH¥7?Ž®]¯~1!M‚’QBñ°Ø®Ýƒ"¢kŸJå ¦Qõ6í:¾øág¹‚Ç»pÁøçg]uÁ–oPHÏ»†×-QyûÄuíy¡]±TÊ¿±I‚R…òñ7‰¥fh||/iW®ÖÔ{¯H"øâ«,W÷öð˜vϧñð…Âz·Ù''‘`ð`OAn3”ŒBˆ‡¹OTj ¾@P»À¿–{Éü•yiý¼´~—*È ¯Ã0—,ÛWh¼úôo콊K—üóø|I£÷ „ܤh5=!„Bñê%„ÜôœGq^6çâ¼ýndÊ#!7ŽÃùóà8„‡£»ëÒQÏ(!¤•2VW­˜?«0+óÊ—¹œÎ_¾ùüÓ93Ö,^˜[g9Nâ8îäÁ}µg _Ùgóf–5G„\Îå¢E?_~ééP¹^”ŒBZ)‡Ý–òÏ‘º{˜sg19—Ëb6¹\5û}Ú¬–c»ÿÿü¬ÙË¿ŽŽï\{±Õb¶ZÌWmÅép˜ zŽãjK\.—É ·ÛluÛ]ÿéâÜ´ÔKîµÛ¬f£á’ÂäcG­–+ícOHâñðÕW˜6 ?ÿìéP¹^4LO¹9ØúóÑ¿ë++üCÃuyQ;=ôìKþ¸öø¾Ý™çúßòÝ›Öß÷èa±í~úâS“ÁŸ‘ær:»¹gÈØIõî:yl÷‰í´ZÌ•eºˆ¸^˜Íòx¥…ß/{Ï}¬üO<ÛåŽý[>úǶ‚Ìó?®øhÇkz»¯çÐ{vûŽõ«OÜë°Û;öì3ò?OÕ{^(!-#<ÖúÊ"ä&@ÿzBZ)‰L>晾Aî§Å¹ÙN§£cÏ>ÿìùã¾GŸøkóÆêê„Þýî}ø1/?ÿ~#F˜ò¸_H8çâÒO'¥$ûÌŒ!c'®ÿdñùÓIõÖ_Z˜pû¯F>øÐô—ölÞw>Íår­ûø}CeåÃ/ÍëÚý³y/Ùm¶¸.Ýï{ô /?ÿÞ÷Ü7ò?O¶Mè àðŽ-ÛÖ|=úñg'¾8{ï¯?:¼¿¶ÚqÏÎPyù´ÀçCng.×EOYæ«rCê 51JF !­”P,é7b´ÒË»¶$0,¢mBWmPH›¸b™Üj6ù…D´KeÁ‘Ñ‘dJ%†aú¿?ªc§.†„µM>v¤¡&"ÚÇÇ÷îÑ>Þ7(¸87Ûé°Ÿ9zèî “C£cïž0EW˜—“–âíÙ±“X* jÕ±“—Ö㸽¿n ‰ŽÕædgjƒ‚ïßS[gÿû”þ{@%!ÍÏ÷u8ئ€¸8ääà•Wpú´çÂ"·:«ÕÕÍR3 ÓBn& gYžÆG €eY¡DRUÞàÂ#¶Nmv»ã8“Aï>)^(Idr«©þÙŸÆê*©\‘~ò8¿°ÆoJÈãóÕ"QŒÉt¶vcVކ¡õ¤¹¸\Ðë‘y•¥×‰’QBÈ­Æét¤Ÿ:ÑëžV³©¼¸¨ûà{y#Ëò|ƒ‚ ²3Úwï¥ËÏ3 >ÿN`³ZÜ 0ÿ®qoþß§•º’“‡öõ:Lâ®0¢]ÇŸ/;¾O׃;õ8bÊÏ~nå¢7U>Ú´¤Æ<3#²}|CÕfœ9ùýÇï÷v%£¤‰°*Õ]%%ëµZ¸;÷].ˆDžŠÜÒÊÊ“ƒüüf©œ’QBÈÍ¡÷=÷9]N•—ÏÃ/Í“ÈäÓæ/pçvB±xò¬×‚ÚDÖ^Éãñ‡?2U(„µyè¹—ëÎ:­«ë€!‘ðx¼É³æû…„2 3xÌDŸÀà¢ìÌ»'LéÜw ûJ†a&¾8;íd¢Ýfó 7ûÓ¯Ï&5VU 31¸ÎÉò—Ë<{ºCÞ¾ÁMôI/¯q:Ý—‡‚‚P\ŒS§pÙYª„4³99‚•+ÅNg³,b¢d”rsðkã~Ó¹€vÝzºŸòxðPݱTúÜ{_T"‘¶lP„4Æßÿy©´CNÎLî$Ÿ‘|>¨ žÜ ŽƒÃ»••Ðé4ÞÞÏøûÏ´X„Í×"%£„[Ã0J õ‘[£TމÙQTôQvöo,[Î0¥"‘OÛÉõâ8X,ŒËååtjD¢ömÚ¼ T\zôq¢XB!ä&&ø…„, zÃf˵Z³m¶,§³órkcV¥ ‰Â‚ À·e¥d”ÒJ¹œÎò’"•·@x•MkªËËøB¡TNˉÉí‹eÅbq´X|¥iè8PBH+e¨ª\:ó™üŒôÚ«ÙüÝ’E…Ù—ž²ù«ÏŽü±­e£#„Ò4¨g”ÒJqœËPUátÔœÀm¬®Òä%Ü߉eY¥Æ["—»_²6‹Ås‘B¹~”ŒBZ)†aåj ïßµÇ÷íþã‡5E9Y?}ñ©T®1åñ.ÿ­$–É„b±ç"%„rý(%„´R2•êÙEyûºŸö~—þƒßyò‘ÿÌy3ªc§ºWÞ7å †H!7'JF !­Çø÷Ô¥+Óhýš;B!Í„’QBÈ-ˆã8«Ù$ y|§c!äú•——y: B`4Ng3UNÉ(!ä¦Á° €¼ói>AR¹\(–4t¥Ù _øÔ”S¦õ¼kx Hȵa†a˜†^µÛí/¼ð‚˜æC“VÀår•””ˆ˜ÅqÜ~’¯Š’QBÈMC,‘ö¿oôÖÕ_íûí§á“§uégCW««SO»{Âä– kÅ0ŒÝn¯·\£Ñøøø˜L&“ÉÔòr9µZ-•Jyõ8k2™„Âë?/”’QBÈMƒaÙ»'Lî;b´Ãf«Ýש^é§“Ã#ºÒb±r¤RiAAÁååB¡ð³Ï>£4”´6,ËjµÚËËõz½L&»îj)%„Ü\™ByÕ‹¼üüŸ|ë}:“‰´rR©Ôf³Ùl¶Kz•†‰ŒŒôTT„\Žãôz}``àu×@É(!äÓ©«§C äêø|¾X,®¨¨ðó£!ÈÍÊf³™ÍfùG«®ŒŽ%„B<ƒeÙ€€€¬¬,›ÍæéX¹.—+==]£ÑH$ ®(½*JF !„ñóóS*•Çy:B®™N§3 7²šž’QB!ÄcX–mÓ¦^¯ÏÈȨwe=!­“Ëå*..ÎÊÊŠŒŒ¼‘¥ô d”ÒjY-潿nª./«-á8WU™Îa¿t@óôу9çRZ6:BšŒX,n×®Ñh2åÕ7%ăX–‰D‹åÊ;àˆÅb±X¬ÑhZ,0BšUuuõU÷çd”ÒJ)Ôšy_¬©}ÛåŽÐèØS‡ ¼lTÇNu¯|è¹—[<:B® ˲R©T¯×ßø;Bn"ƒAyµÎZÀD!„´…BQ]]M#ïäöár¹ª««Š«†GÉ(!äæÂ¹\.OÇ@ÈõP«Õv»½¤¤ÄÓÒBŠŠŠÇU§P2J¹ið|‰Tö×ÏNìßSVTèép¹6"‘(<<<++Ëd2y:BšÉdÊÎÎŽŽŽ¾ê&JF !7 ‘X2qÆ«öoù¹('ËÓárͼ½½½¼¼Î;g4= !ÍÈh4¦¤¤hµÚƬƣL„›IDûøˆöñžŽ‚ëÄ0L›6m²²²Îœ9¢Õjy<ž§ƒ"¤)9Ž’’’œœ__ß°°°ÆÜBÉ(!„Òrø|~dd¤——WFFFqq±L&“Ëå …‚²RrSs:ƒA¯× —ËÓøÊ(%„BZÃ0^^^ …¢ªªÊh4–••8OÇEÈõãóùb±X&“…††ªTª«Î½èÞæ ‹B! >>>´í(!´€‰B!„x %£„åt8ÊŠ ißoB!n”ŒBZTuEùûÏNÍMKõt „BZJF !-Jíí“лÿöï¿uŽB¡d”Ò–íy÷ðÄ¿vV••ÖÚm¶#lK>văBñJF !-Míí#‹‹órjK,&ã÷¿¿óǵŒŠBˆGÐÖN„–ÆŠø|A¹®¸¶D,•Mxá…Ú˃QBñJF !Í‹eÃx,óo Ã@.— y¬ÃŹ8N ö2Ì“Q’[Ã@ÀÖ?úgg8^/BZ%£„æ% ‡Õî`ÿýó¯7LF£Z`sºÜ%6‹å¯Ÿ7¨}µwÜy—ç"%·Œ“㜮zÖÉY-6•¢åC"„Ô‹þkHi^"_&ä;ëu˜vò¸ÚÇ×/$¬¶Äj6ý¶êËûw{"@r{á8Îa·ûÈ¥ž„Rƒ’QBHó øJ‰Èé°»ŸZ-æ[:n’@(¬½Æ¨¯6TUô6ÊC1’ÛçrñN%{:BH JF !Í‹e˜ Òl0p.‹ÉÑë®áu¯©()îu÷ˆØ®Ý=#¹XLF•X¨¦d”VƒæŒBš]\ oNie…¾Z®R«¼¼'¿2ÿÒ ºõˆëÖÃ#±‘ÛŠÝfs˜MÝ:DòyÔCHkA¿„f'äóºGsV‹Õlöt,äöåt:U•í}ƒ4JOÇB¹€’QBHKÐ*å="ƒí†jCU¥Ëåòt8ä6ÃqV³¹ºT¬’%„ú{:BÈEh˜žÒ±¾¾JÙsÙºRX&ã <¾€a˜«ßLȵãpœÓá´Ûlv«…uØ{G·õ÷©³ã-!¤U d”Òr¼åÒa 1çŠJsJ+˪+MNŽáó(%ÍÅéÇ©¤be\¯JB‹–i(%„´(m¤m¤uq\•Éb´ÚêÝ–œÄ0 j©XÈçy:BÈ•P2Jñ –a42‰F&ñt „B<‰0B!„¡d”B!„x %£„B!Äc(%„B!CÉ(!„BñZMOi.—«¢¢¢´´ÔÓrCL&“Ýn÷t„ÜF(%„\ƒ+œäYZZÚ¯_¿– †æ#•J/)á8ŽãhO\Bš%£„Æâóù6›íòr†a4··wˇDH3‘J¥ n‰Ãáp:<m¡OH£d”ÒX2™¬  àòrÿ#GŽ´|<„´$ƒÁ •J)%¤ÉÑ&BHcI¥R»Ý^oç(!·<½^/“É<!· JF !%X–­¬¬ôt „´4»Ý^]]­R©<!· JF !% srr,‹§c!¤åp—™™Éçó5§c!äDÉ(!ähµZ¹\ž••u…eõ„ÜbÊÊÊÊËË£¢¢X–þhÒôè÷Šr X– ×ëõ©©©V«ÕÓáÒ¼œNgAAAzzzXXØå›=Bš%¢ò_»®IDAT£„k#‹ãããœþ¼X,–ÉdR©”aO‡FȲZ­F£Ñb±Øl6­V{Ɇ£„¦EÉ(!ä",Ë6æ,D†a´Z­V«µZ­z½Þb±X­Vê"%·¡Pèçç'•J¥Ri#'‰rçr¹h RB®%£„‹H¥RƒÁàçç×ÈëE"‘H$jÖiål6›Íf‹Åž„›Í%„\D¡P OGAÈÍÄ`0( ZkOÈõ¡ßBÈE¤R©Íf3™Lž„›ƒËå*++£Ã™¹n”ŒB."•J•J%í$JH#•••UWWÓr{B®%£„‹0 Ó¦M“ÉT\\ìéXií¬VkVVVDDM%äºÑ&BÈ¥„Baxxxzz:Çqþþþ4Žz †ôôt¹\îëëëéX¹‰Q2J©‡Ã0çÏŸwŸ‚(‰hQBÜÜ9äåå„„„Ðo!7‚’QBHý¼½½•Jefffbb¢{[{¹\. éï.¹m9N“ɤ×ëÍf3Çkß¾½R©ôtP„Üô(%„4H ´mÛ6,,Ìh4êõúŠŠ §Óéé ñ–e¥R©ŸŸŸ\.§#Çi*”ŒB®Â½­½———§!„r ¢u „B!Äc(%„B!CÉ(!„BñJF !„BˆÇP2J!„B<†’QB!„â1”ŒB!„Ïà8Žàr¹< !„B¹½X­V†aX©Tj0< !„B¹ '‹Y™L¦×ë=!„B¹F…B€U©TUUUžŽ‡B!„ÜFªªª”J%ÖÛÛ»¼¼¼ººÚÓ!B!„Û‚Éd*))ÑjµX‰Dž’’B˘!„BHsã8.%%%$$D*•½µSpp°H$:wî壄B!¤ùp—žžÎq\hh¨»„á8€Íf;{ö¬ÕjußB!„Ò„ CJJ Ç‹‹‹‹ÅîšdÔ-///++ËËËK¥R) ¹\β´+>!„B¹N.—Ë`0èõúêêêÒÒÒÐÐÐÐÐP†aj/¸(`6›ËÊʪªªŒF£Édjñ€ !„BÈ-E"‘Èår•Jååååž'Z×ÿ–ÜÕ襻q˜IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/xml/images/alex.jpg0000644000175000017500000002112407525303737023532 0ustar frankiefrankieÿØÿàJFIFddÿìDuckyPÿîAdobedÀÿÛ„      ÿÀP¸ÿÄ   !1AQ"aq2B#¡Rr3SÓ$•‘±Ñ‚’tW b¢“³”´ÔuÕ6V–7  !1AQq"a‘¡±ÁÑ2Rbr’²“TðáÒ3CScsÓ45ñÿÚ ?¿Í- Üå¬}ø÷­TÅ*úºlšºZI‘ž‚¶óX|¢ ÁyðFÞi_uµ!lQ\=7Òˆ°¬/9Šä¸µ%¯*:Aƒ`ÓÏ5Œz΂wÙ¾†k-¸ì.äQÑIÒTFÁÅBõ†h‹?þò1ø,㜗g8°µ‹ÈõP’¹-LOY%Õ‰º1_îÝEpÛ4êž™~ÏJ"Éc(ÎuÌ ¸#pæÁì%䞯5 7FÞ 7aBŒª£Š O!¶¿²#pHDX%r~?UE Eä ©²v‹$ŒÀUAd_32f{>£ÄÓQ7Al\qÆûPpÔEЙ½ÆˆÜÍä±—’Zã®ÊrEž1C4›Ÿ¤0äxMµmA³FTIâÜÁW»æDÒˆ‹ú„C,ó—0¾=z%u¼Çì2+-’§©d¦ÙÊUðôã·Õ|”ÔSí×wIåËÍLÆcoµ#Ï méqó •ÀÖ9–ÏK!’’é]ìÆÁÅ#º=4 ³0æëñI4œYWŒÂ4Uar«… DžJq Ç‘éýÊ{ëyúnlxeº|ŽÛÝGVõ9îm|KAšž·sچё·g{%ÖÖ5Ôè%},ç: YÜ[K”Eîy1›²I‰â¢ÄøÌ#‹ö!ï£4ýàÒ;§Æ‹gëFçSÄŽÔµËaYm# N×Õ‘­¯@)Á‚sŸM™IæRe•‚¥k‡]G(vL ª"’´[¡Šn@‰>;o­=[–îôÖ6Wð¾'{20ñ0õì>ÝÑùšÓRy‰œL™¾Ôo/[z‰Z®Räë¼÷Ʊìf6GmŸK—Ëš°šhâ¶|ÆŒ½¿rùykc@Ð¡Ô ¸žiLl„4š7Œž"FUnå¯Ì:üútöðA‘ó—WpÂÎŽÞº¿µìÞæ|QÈñeœ™DËø*pºõî!À]È:aõ=xÿ!®ŒMœg¢l|±Ñ}Äy®®ó*<'Ǭ° õ)±û_MÆå´(¤¥S$M¼›"¯M¼mö]£Qåy-í½ò 5½h^Ê‚ÓóÚqoçÂ7šâ¸º÷+ˆÝÅ*úáó0vߦE5p^Yå^F¡L›ãŠÊœ—&#K2ùÖRŒâ´J 0 uNuÐÕ¹wLÒçî'¹“Ž€á#´+Ÿ\Ý#™5]Vþ Xø*GjRdÓ.ì§çüçþÎqýÆÿþ®o¹è¿‰—î‡õSßußÂÃ÷Çúk]Êœ³}Åá®Gs•ðÌÕÚ‘¤;¤´µÀò¾ôî“[úоý»øk±ÌÚ ÑïjÇ­)˜®U+‹ÊúáÖ¬[tYÁÄ\)Zû$Œè<Éß•åU¸uHÛÚ52C/M‡],ÎJ}év‹¡ÑP}Gî5÷2ÝuÀV¥‡Ua:þÃ#±vʶÈUÍVPç@£½ä“äë1Ÿ8ÿµG[EÙIW·æðMz¢3,CFB4X€-Å`@E;Qð×¾¡vî¿J%©D»¶N¥²yõé¥.©ÓÃã¨E©¿‹a>ŽÆ%YC"l\¯;RŽ4bàv¢¨¨¨¢‰l]¥±v–Ý«åÁ;¸WÅ’À§Èà:ë /ÊrÇäI¶'#«¤Jû’|Õ&ûÃbÛ°‡´E>TËg¼ODÓ‰Áµé4Z××ïo$ W®u7ð‚P×Û?Ó k–îÄ-óüþDÉvÙâ†ø2œvã2K¿¦Ø‹IòŽßM]9òñðÝ:.ͼ!¡¬@âã½Ä»3éTž@²dÖcRš¸œ¸¹ç:†Í£r¥¨Kè hŠ.{«¡f?=É4î .oʉ.›$ŽˆÜ´mÇŇ#ú©²¨;¿jî‹·‡UÕ÷áýÙuø±—·ÁÁÌ8¶ qSxáÏ5ó–ú#Á<%¥¯:„ð–×wj´ËƘœ“™;:ßÚVu6®lÉ "Î]Ulr‘$Ü‘1˜°È®åÔ·DO-uô=0G¯h×´Ñ¡Î4m÷{NÙ—qõÝTÉ.xö8—Uå­N«šÂx[·?9—61²ú\]ȯ9ú&<è©/øÌE?ÕLr³¶Ý[üÑèVÓÍÙitOò¤€†ñp¬ó”ùwå·^?Æ0\þÏÑÊ}§­&¼}ËÞú0¤ ŽêŠ¢¤«ÓoÖUNÜš¥–‘¥Mao/,Äq¸#hÜÞ,\|4Ûà¢âG¥_k´:…Ì]ÄPŽÃIGîáÁ¢»+²›jš¾Ûy1Î1f­pœºñZ¸´?Ì)êŽ\Rï”k°º&ˆªž ›t]t9ßE7Z‘“¿…†`÷†»Ù(¹¼‹® M0GÜNþÛñdeÍö·Õÿ¾&ÿÙ—!P9üæª?óGñVßz=JáÿP? s÷GÖƒ~ïç%ŸÓX¤IPmõ[É kj̆»Ûy{mUTI7ÙSÉueøou¬½•¤oi«N#v…Xø›7}¢1ü%¼R0ÑÂŽÀ‡z7g¼SQœ[˜3¤â9Õk=´™ÍRúSYùvôTÛÖewù›>Ÿ µVÒ9‚]<˜žÑ,=¨Ÿ‹O„|—np몶ë» ¬qŠá£³+0pð”Ýí=TLÌ;•2\w ‡Ç× šœŽYXÆq;*/P|IvF_TñmvÝ|7D^ž¥ [Ý@ot·F1|Gõ‘~“>vÍ»W/Læ›YÅŽªÐÙ ”~®_ÑÍÚwTiËÿòžQÿtMÿ˜=V4ßî¢úmó…iÔÿ´›è;ì”ö{ÿÁ×úÝýiÍ[þ$ÿ»—¡Ÿd*wÃ/ôqý'ý¢ŠœƒP.Ô`oFz~G™7&V=DÛi´©6vc’»TúSq§QUÂ_âÛ4í¢ ×NšÙNÍn\ƒu]oêŒ#/jÀˆžI÷ùënhÄd6˜Ó•ä¬ç ZlÜ4%MÔE7%ûÅWËXÀ©¢•ÅŸQ[w£®'y‡ªõíO»ÃGR¸d‹·ìó_ B/†¨ àî&*„+抛.€í°ÈeÆútI­6?ļ}®¦ÉÑö^ïó“·YkkàËų©BÒË›8©o,eãònb”nÆ1ˆÂÚ¿ ;\Ù6ÑwBÝQWuDùQWdY¹kF´Ôí>„mSoŽá;kù–@ß#ž_ŠØ´åtLA‚feu{ì¼c,\›$²zHžìº/>"ª?NÙ"íª×F#š8‚„•psonvV5õ˜äÜç„gIre{B²-±óy{AW¹ö;·^Šªž;¢î…ô9峿ˆÚù$l7Àx»1ÍLMå–_8·†÷•ds#‰ÓX¸Ôpö¤†¹ŽÜßý­kS-5ñNJÊ9]Ô²÷ƒµÓä m’x‰Ç”­8Š‹ÓôuY¼å}NÔÑð<ím=mG•Z,ù¯J»eÃÜâáÒ×Pùe÷4qN6שiŸS!ª~Î$YA2A¯’•Ç WËaÔZrƧti»úH-o[AåSyÍZU ¬—ô;©­©ò ¥ì|«Ü¤¸4.ã–XW Â’ÔëkKFÖ-•é2]Í1:ª,¯Š™&þ ãÓV‹GÛr«0‘²ÞZÖ´ñ2æç;';À<تµÛ.¹±í„ÄèlAsž8_52k[›[·‹¯<עĮåkÕðš°áÛÙG‡:4ÔF@Sà(ˆšÃË’:]/T{Ic ;Éq©Y¹–&EªiL`£Z÷€7Ö€¥N¾~¾†¸—è—ܺ‘š‚¡¯¶>Gãìw‹#ÕäÍ%“w¦å|ûÑÞ9F¢JÛŽ "*uNšúg=è—÷Z™’${x‹Xçdm|»uÝ>ÓKÏqÆüö´âì0%H?ÿÚ†)ýq ùÝSæu_ÂÍ÷nõ+§ýN“ø¸~ñžµ}ÞÝÓ_p}]½´;Š©y,¥³„ø?ÎÄØëjB»ª.Ë⚸ü8µšßYtr±Íx‰Õk{'qT¿‰—pÜ茖µì2¶ŽiÕ¡aE1Ùþ)¯àøµóWfWÔMÜ¿ÆóÊ)xÞWVݵDÎÕr9© ‚î6à*¯ ¢þÜÓu;:q=»Ë^6ú8à+KSÓ-µ(  aÙéb„(Ñ•¹É<)Qq\™|ÃÏ×IˆÝDrò€\hÁµxÓoª`UQ׿ñÛošó§?^•Žh^A„SP‚iòwdON=IÚ/Âö¸›‹"Ò+œ°Ô8¾[üÀÝLwÞÏvþâ1­•i–)ÓýmÍj|Iÿw/ÑgÙ sá—ú8þ“þÑD̆¹âϱÉäI¾~bv9E&Zµ’+ >elÔfÛì}ã}Zeþâë»$Ú¨TVÓhWõ‘ ÅÚ§$'Աܢë+¸î¢»wET_Ã]©ar+4O&Û2!}òq}îÀO$_TñU×0‘J —µ˜Û}ëðñ]cq¢•ÎÌɌ̦öo‚ïã×É~íD­,qiØs}Èí£c!ÐkÖ4mžòAî5ßaüUv^‰¯ÑM®´Ô ŠEØã£ÞÇwD=—¨Šø)'ÃYÚÒ[Űf¡3ù› X6M­ò‰a"/§ǼŸ„¤›J|[ùœe»Ým}@ENÒ]crœøå= %S1ñÊÚÊÚéJ³*#µ+ÎÈùÜ|Ÿ•}U^í÷U_5_cE½Ñj{Ñæ©8ŽaG†bÕnY³,rK[:¨VFC ˆ#Ç”ˈ; )ª§^£öëvßQº·ŠW³è¸·ÌVΙirk4LyùÍó…ê}Îòå ú´Rñêg•ƒŽTÇ/ô›Œ+¥Æ¥ur),¯xùÎ'ÎRÛK³¶5†0üÖµ¾`¦´syß#çVØ?#ZG·v}qNÇ&·ˆ¤Û±U=v;YCClûÑWªv/ÇZKyXcðaIz4‰0Ø‘")Ã}ÆÄÍ¢$ÙU²TUTñÛY+Ø ZH1\úw¬o‰!Îh$dHË£rãcc¢ËKIm@®¯däNšù 6ÓM¢‘™’ôDDM×XÖEYœ•þð «.uobñÖj­ÆÊnûÈÛ¢¸Ô PíEý_P÷øŠxhŠÚóÿ,Û¾ãïdìÃõUYW[´Ýwٸȿá]þÝm{ýÏï_õëZã­sÔo©eS{ˆåŠcÊûfÇÆ=¥=l $ø*”d4ü 5#P¹µÖw­AÓmìcúõ)ñí«Ü¼žbÈã ³¨£ ò,cϯшwÞ ¢à‰¸«¸Ÿ—]xs™8ÝÄvÔ×ÇšÊlà,ð7„l §‹$W÷)îf³SOQU"Ì®Ú9 W>ñ6Ä8¢½£"Gb)î (©¾ÅÕ6ë®¶fä^ì9û"”rO$Ò4ªªÜvYˆÈ'Áœ_óWD[,cÝÿ;ã²Y¹[y}r®Òê/"²ûo‚ô W[ÝÓ§BüR £5¡Â‡%eþÙyæ§š¨¯‡‰eŠ9lë¢#Iž©6ärmSuh»„‡§Åw×¹e|®ây$ï&¥xŠ&DÞ44nƒÈ·Y yX?!ØÞtå|¹-Ç¢àù,ÉŒóuQXiу)µ&+1ÁQÂ7Å × ¶Ü5_dFÔŒÛS$ÌAþ‘%L—õDEaûÕ7ßYøË˜°(¦+ªd¦áFvS¢F-íòŠ©.É×É7óר£284(&Š<ûš¦÷-“`Pb{Uä «,Y‘tíÔFd±2Œ9»,»&$æÛ/Q@ú³ó"mÞ­­4n##^œÄf!Ô®&´ðû8ã¿nÆ¡ùÀ÷\ƒmÇìrÅTzžE¦~«#ú0F£O*éÏà Hí"¯¦Ôáe$y!ôù{uèµü!ÎÌú?5 ›‘d"3VÐŽ¢HÇø¡_¼jÌû²Ã°¼.Vq;ƒdŸ›ÛM†ßÔˆG_2ñÁƒ1kÕ4ˆ/¦Š{"ï²ásI …ê # sdi Ó#ÂjÑÝí¦$ ÊCÓaô¸–Žá”âðRáU0«(VC¤ûàÅ[ÄuqÓU#.ÆÑ•w.¿l[8ÆàGRÁ3ûÇ*IYVLÖÐLÈ%GJyèì=9[EûÑ–\q}Õ<7ðñש[ÂâÝÅx¦ßb°ÒgPã“Øc"ðBWe¦%™:RkæÍŽÐHuÂG½³ý A "À¥²Œ’«Ç.ò›Çþš§„ôéîôÝd•Sr-¶Dó^š"óÏÈyµŸ#æÙ.ooÜ32)§$cª÷z 'ÈÿšÃDX!‰ÞþtqÈ×DôÞ¿,ÇY">l ž?š"îÁòû<0Ç3:r_Ì1¹íMi½öG@WgY/ø.¶¤ ö.ˆ½ âMNo‹ÐåÔozÕ9 &gB5Û¹ÑEP4Mö ]Ä“ÉQtEYÞúy®e…ØðÍ “SPŒËÍl¶ú©.»*ª/PhI ‘|IG÷º"®¥TDUUÙª®ˆ¦û#ä\þŠ«'ºº„Ô\6 Å’Ó’§œgVA@ tB=öñDÑB×ýÝ·-²…GÊPåÈón}[ŒúmHuâè‹gíÇÛï$ðÇ?Ds*­je$º áäõ¤oA7YThÈ„ ³TETßõwÑI÷Ik>ߟ¹1Û"86A_Kõ#Æa°hGìTù¾õßDL~%Âêù‘1Œ.ç! ZºúA²õÁ ’Š‹d`Ð!ª{¤(¿NåO XYþïJC¯3Á³éñ­[ÙǼi§£:_r86mïñA/»DN/e\s˜q~E̸ÆiPå]‹_’wN<¦§"=äù\û:¢ô$Eé¢)»•Á¬ŸZ…¶4™„XÑÜ”˜â3÷%¸À+€Ó!(ÛkÕ%MLÅ•7!Nº"kqì‰Ïc¬1mõn™¤Ycr\ú—)SbãU…+mß&nã"%%^äTlÛQ=œm·›u‡SvŸì_?ÃY‹H#0¡1™9Õ2Ÿi“VŸÙº=¨BbEv_³ªk¬àÉš ÉcÉk%dtøtI9NI{¡©ë‹‹984j‰±8á"w*íÚž*[""ëÑo©KsMÝ—òNfÞˆæË;$šá·JÃÐ'EfÅZŽR]X¾À6ç`oó"¯jöî›*ñ–Dp[¸Ó\Èkë;¦O VãÏlS` /²2ŽõÙ;ý'5O$1øë$@ š ¨)­™eUü}ŠÉÉ%¹¾‡‡ëŠÁÌۨ¨jÛM›Ä‡²ú@Ä›ön» û•åÇNýèÎÀ1ü£¨›U“dqrA ÇN47¢”*× ¨/8ô©E$˜>ñ—±U¯LHTÄœs•½ûò»piiøŽ¢Z}uÙ·k–kÕ¸L–ñ™=¿•t{Õ>žE¢*³7 i²u×I¦7""]„E<ÕUvM]-g·6ÃÚ«œG"3a“Ϭ+i®Ê£~j’ƒæßo‘ÁwýêhŠ—eøÏ=S%Tg ™1Í6&ÜmTL <”IDV‰ì•[•UyÄVÒö™Vgo‰ªîq]_él†ÿÉ:¨hŸ_†ˆ G7ΑcÌœ§2R¯¬æSfÚ¡xˆ³ Úü4EªâÚ87&qö;k²Ö]äU°ìº!2ì€Cþ|¿Žˆ½` ¶ÛmŠ mŠ"Š&Ȉ‰à‰¢.Z"Z"¬¯z>ݲ kßïk¦‘uõ‘3z¨‚†óe´æ¶Ú/q¢¶=® ¢ªv¡y®ÄU—ã÷¢þ(¨¿ãEÑÁáŸxü‹Ç@§ÊŸs;ÃQlãK.ë(¬¦É¼iD»Ÿjxª©ä„:"¶¾;äÌ/•h$Â.Bڽіßi6üg»P•—Ú4BD$ûÅS®ˆŸº"Q©W‹r :»ûSg.ä2-Lâ=3ì<é‰ÈyégY]pÞxAƒb(¨„(;jADXÆîÛÉ*BѨË–TèoB'[xÊùoCwçiHU;Ù_Ö@T-VaF6±žÜ‘,æ—gÅ^×⺠„̆ËÈ€HUzn›.è»krÝÁÌ,Û˜^NuQ’ª"óßçžÞ-òªìšd@cdÄõÀܬ–ÓñîëcIFÒd”A&Tþ]ôípv\¸¼í—åëS–*ð—µnHá¼ûæq\YC‹p¡L”í¥TÑ_í<ÛD80 øM)ƒ6Ûm¢z¯8BÛm9Ó\´Œ×¡ÚŒ‚¶ì&“4g2â¼êî²9ó-ì«Ý6Üy„’é,v6”€˜ÈÓEÚD;†ÈD›.¥»Ñ2 gµ97)À§Â›k7¯¤a <É" ;_ÍŒDÛLý•³˜n#Œ¿¢'NÓ{ÑD{É5De:d)–V[‡½—$Í–é ¶ÓM ™™ø Š*ªêyèåìðù7’óã´‚5äòZÆw †À£1…~ßHU>*º"kb¹ئKE“ÇÎN?9›°'‰g`»ÛG@… vBO Lÿ@9ÿMâ?ôYßöÝCÜÇ&‘™å7ÙlÈë&äSŸ60Œ;ÕÅl\3$B-ÉQIzªè‰ÉÄÚñŸ&a¹º¡Z;[FÃôŠâ¬IDø¯¤á*'ÅDDoux‰ã|Ë‘[ÆÚF;Ÿúy67jßV$³8ÝVÍ:k½Ûí䢾i¢(÷tʹЬëßXÖ²—Hø¶óŽ6I÷¢èŠôxÜ×r^9_*VQ]Ždí°ØÞãöo· Æäö§¨¬úÄ(ëj[¨ªôñÙzhˆ­7’øæµ“‘?>Ça²¤N;gSdûÜë¢!V+îo3ÞQ…Æx;®ädì s¦äí"· µŠ€¾“]â„ê—wRDíO%]mh}Æñ…¾c—`VWŒâ¹6#fýsñ.n3RýQõb¾D€h¾bª„Ÿ ºèˆMî+Û—gx½ö{]"· ÉâErpå1Ü Ì&ÅK¶` #gêm·¨?>ë¾åú*EL½Â%¶Û¦ûhŠnû Èì+yŠÇeÓZÌšŠIοÉêÁ6ÜeÝ¿|(f;ü DW¢%¢!ŒÞ8¯¨¢¹7‡]Še/ΗyWhãN8ÁÚÊìÇ~µÅ×#ÈyçÖÄÇä2ôû µD‰©ã|Ù\P+øòïY$Rç3ʾ¶Gå³Z!Ú]u$u•õá7èœÈàȶÒ÷=óÍQiy]•–pÆM-ælfq¤‹evÞK`ÛÒ·¦v¾G¦-‚ÈVÌ€vß艮£;×mÚ·tÆ“pÜOˆ‚´7Xk™EMÖ=Kr¸uÕÜ YdHŒH~ ˆRáÎaÀiñ&ϵƑ;K§U׿voÔÃrð­z¹|öàë¿TGÁy§œ!ç.c«g ¨²“‰¹>L*K)rã° `qþ±¸’\{éÐĽFÜP4ØK\pTtKű\oǪ1,BŽ5ŒÐÇ”ÔuÌ‹£2>Û`ˆ‰ÕUU|UUUz®¡3÷ÙÊI‹ñü.;­“ÙsŸšþd‚¿3uQ‰ÝüÓÖsµ´øzhŠ wOŽˆ¬ŸÛ—´L ‘8²£4ämÂÒþD‡ëÕŽßÐ úl‚õ5-üÑSDG_þˆp?òyõ¡7¢ W¸ßh˜ñe¾i€3nv”#?d&¬€ú?Mò@PN ¦%¿’"芶7OŽˆ¬sƒih}Íð,î"Ȧ LÓ‹^W0ËÅD'X‹% cª§‰4„„˃ûÔý$A\ëó4»Íèߣ±eWÒ7xòdr;éò8 ñûeé¢&bˆ’lB„ŸMôEÅh:£`?j"&ˆ¦±è629Þ¦Ê%t©Uêì›±²i£(ñÕÖ?g꺈¢=Ä›"*õ]}òmsŸ+„–I¥w%œã`è¨÷âB„‰º*uEM•Ǥa]5Ž+¸°¤ª©æƒ¾ß¹¢.µ!·TMú&ú"´ßc%yŽ•¯,eUîÕ¹qòìJºH(6ˆÉoÜ­Ç—9†ÿäÛ#·Ù¶ˆžø§pö &c> stream H‰­WëŽ\5~‚~ÿÄœñÝÇh…4a†UV —L#~ U†MØ…]íÛ¯]WûôéF4I—«ê«r¹ªl?9¼[ŸLÉi)ɘãíÁšþ÷ëæpý¹5À5Çׇ+»xkK?»¸T|¾7Ü=qóÕ³_Ü}k®®Ìí›ÿüûñåÿœ¹6{öòÍÏæþ·ïß¾zø¯¹ùõÕËO?4Ç·‡f°Yº*1vs¦áÚ´&µ.!¬ûØ8ÓPÚ·jÈÎbí'v57ÏÌǦ^ûöÏZ wǃ3ý¯{íV½I%›âÛ:^™×Û-¾o,óþóÖÐ"ŸÿÝRô}‰n­]èÝ0‘Í£9Ü÷ ;±ã"â,Œ«¹0ì<Æ©aÙæ¡ ºE™à è1E‚DºÀjvÄ´‚9L '¤î'søþ£Ã/ãºMrÝBˆ¥O´€ýd¾5?›ƒùVÚþÿ³ÅʘÎÆ*äÐCQS‡)äÎÄ}Ý„kÛ¢ Fºê #—ë"qÜHC¤÷%ŠÚ‰bYä™÷‹LÀzMè]oª±ñVÔƒ!lGÛ"ñ3µ-â1D¼Bè˜éT †,Ã.Šx°²`‘!dFUŠ‚…»÷õ°”.ŒW’]]Ò¨lÓ¨Á'Ù­{E\}ˆ|³±ƒ2Qt{bà1 T’&n+^TêL ¢±®¹Q]ÜÈËÌ_)3‘ ÂÕþp€€@DgÙ£h»ç}ÔƒÞ :(2VwH¦QW"ž‡dØ@·åD\ÜÑ Þ‰³¬TíâÂtÛ6û–b6Éû¹h“ÖÌ>Û-¿'áÇØ%’HtÊîD?ÅÖo|XH¬˜3qe§RkD8¦–¡¢€‘U< ɰ7"î‡û(茪âuÀš#šØ"ÚC­¥U,4×Væ°"%ƒ'{…E°Ûí ΄ "’«SWà%îg@ÙÓ¨†(8„Å…€`½§ÐÛ Ž!»>1*¡3$ÓÆ¸Ù,î,'Xd™Q•¢`al!®^̳™íÊr‰[ç •äsyÌÍ~Æé™U)7%%è”ÄtbÊ<§‡j™á$ùš,Ž*BCbÌ?fWRª#–& F¾¨Îç¹ÁïÍšCÙfN >¤±›çÒýÚ6|×ó<þB·r[¾ƒC^E¼ –èJå¤ÀÍì ׃õ H|àŒNNšÓ+.ò!Têíµí¢L6±uÃ’…]D­0‰uÒˆxÑ‚¢‘1d£KfpMSát£w·¤X>('×ONb¦Ó£=|x,¯§„±6w%üPžûuÃX¤,<ÔéÐÏVGÊ\´4 ×þKÎ¥2DA¥•ªÌuPÿ¤tÕcPòëˆèµvÑ ±Å73»90CÃÇ¥1Úg‹8;´SéŠn`ùª«{ùÉý4ÙŠÁ@°Á+ÓjnEIyq Rš“"¢AbGUŠÄóçÏÞÞTÞ4°¥§à 9@̲“q…§U¦ LNHÚà#騆B­Š*¬¹)\ä^Ö:8ðÙ8Rq7Z·Ôe%‰ µû¡Ëö´ÞZñ ÙŽ=€ÅãJü!¢D’‘’ä[!6û¢#ÝëmÈ}@dZ´Ú<éØÀÑûªî¢†ÁµžÒó‚:*’ÉÂ%Å9–¬ëCøv¯_¹Ú4]¹P„9¢a3H©Q€Õ¿ˆå0Oû´Åý„ÅYoçÅœýáª`üv’¼Sk+ܼÅvÙ«áîôÁá›ðœHÜud¢…>­ý !Ô!Ü6¦3açAGúZ¡‰Ž”²"fE\z€J£&’)ðU¿¯ˆ´âÓlCZÕÉ Y—B–9’AÂâ)¦¸>?ÇÒM±´¢d·±´C,ÝK?Ç’Ì3 jaùK‚£å£Z¤¼aÅüL *s/Ä5À}2F~ÊD1mØ¿`/Ÿ(ˆl²°£*Å%i²‚Ôℵ(³Œjeƒú‡3Õe>‰ûj;… ƒ§y¯æ§uœo™ÉF²ÀtëZkÅv=·Q<„V·â…™E”ŠÂ¡ Nô\%¯ˆ^É2É P]üS‰ê´Öà‚Ò½‡â…B'æÊÜp1žx ÅR9 4±Úvã |óvÞã•ÙÊú½[’²­*Ù%i¦Ÿ¤¤VʈZŠ¢e†Q-lPÿpPÁ.~$\ļ[ŸZÞIh‘µj{8¤\ŒÑ´e`½4æ9õ÷θwJÃ3#§¦¡rò0¯å[,“½œòªl0Œ8t¢.QêTF9ÐDzè –Èt`[àU ¯À[Ä`B6·¥=j8è^‹Ü5OŽÄïæx{¸þÜš&[R'_®ìâV߆}ãŽïÍ7ŸÝ¿¸9Ÿ?}òÍñîÅíÝýgÏŸ~u|úå÷šãÛÃÝq4C·¹ÙâÌaGZc ÃF_eކõ¡©\¿yçÌí¿ÿ¡û|« endstream endobj 9 0 obj 2258 endobj 10 0 obj << /Type /XObject /Subtype /Image /Name /im1 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 11 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 11 0 obj 456 endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode >> stream H‰5Ž» Â@D¿àþÔI‘ÍÍêÝ]ìòD´Ð„%",XE…(Úøû&‚L3bN zÄhqÈDiÁûŒ+x€ ÿ•ÀW”6Œ¥²Væx¡„•f“M~«…usýA´+6uéOþ¸¯Wèó®\çQÆb„¨Ù†8†¿Sí©ý1ð¤Ä@ŒS2=Ú™dAémÔ¨žô\ú%9 endstream endobj 15 0 obj 151 endobj 12 0 obj << /Type /XObject /Subtype /Image /Name /im2 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 13 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 13 0 obj 456 endobj 18 0 obj << /Length 19 0 R /Filter /FlateDecode >> stream H‰5Ž1‚@DOðï0%,þ.±[£…&U ¢Q4Úx}3Í›Lñ¦½@â,Œè ¢Œà}ÆG<@uøÊ ÊWŒR9's½PÆÊì"`Ur¡#~øúM½íiç·íß/×¾7C¢™‡4E¸S¨ûù-8&³[)‰6=¿'P~› 4Oú¿@$> endstream endobj 19 0 obj 149 endobj 16 0 obj << /Type /XObject /Subtype /Image /Name /im3 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 17 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 17 0 obj 456 endobj 22 0 obj << /Length 23 0 R /Filter /FlateDecode >> stream H‰}QaOÂ0ýý÷LÝÚÞm|ÛŒ¨abB²D¢¢|ñïÛ[·AÉÒõÞõúÞëÝ ÄC‘Fc0Ad`ÿ x€cÛdl.†—t@d¾ˆ "e”‹× -‰\ø ½¼XdóÉ”Óê¦xÁ}:Ï®Òy´ê…R®ú}°ï¢°bv0 èŒEg H£Š(þc`Ùm9^õ´<¡Œš‰Qˆ–ŽLp¬ûW¨@$wºk[ŠH’ÿ ›ÖL\;ö‰-cdz[UÇÐ…Ô]lżmÄ-6œlU<âëµ ·Œjצ=‹ãöÒÄÓůŽ`›oʉ¡4Uþ½ÿŒ%‰ýXüDÒlQ•ãë"³UVNm±´ÕdšËÓ1ú /9<Èw%æh5p/^@C„NWÂ»Ž¹f¯]õðm§!ÿ?ãñžJ endstream endobj 23 0 obj 340 endobj 20 0 obj << /Type /XObject /Subtype /Image /Name /im4 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 21 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 21 0 obj 456 endobj 26 0 obj << /Length 27 0 R /Filter /FlateDecode >> stream H‰EN½ Â0|‚ïnl‡¦IÛ/ǘTT*).‡¢¨PE_ߤ‹ÜÜu 7ˆM- CëY*)*'ú\pà O ÿV#ŽÊV¢ÆpŠW*¤Pfa¢!EÍJEûEv°¿ çµ[bßï¬?bÈÚíçòºùƒ†Œ(4Xë4Ï`œ@å}b¸ýÔf$: endstream endobj 27 0 obj 145 endobj 24 0 obj << /Type /XObject /Subtype /Image /Name /im5 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 25 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 25 0 obj 456 endobj 30 0 obj << /Length 31 0 R /Filter /FlateDecode >> stream H‰‘mKÃ0Ç?A¾Ã½Ü„uéÚ˃ïÖ-“ùÐ=4" `Q§lŠ{ã×7—4Ý èÝÿz¹üòÏ Ø0”Y"J #žŒ>‡gØÂ|+ì±K%`§l8ã'R"É6pû8f.o€'™”Ò¥ßЗSÙźžO/¡¼¿+Ì6½ÙͦßûÎŒe«3Š\ý‡"×S¤z)t*EY_™Ò¬Çv¾(«Èq­Ã«ãPÂN%]sßIÅÅÔ)TYsh\÷´¡°–k‡ s-ÃOÞ¥~6mŒÔÔ¿;)( q ñ” ü¹#v¤Í;̉BÇ[`Odg—¶vr E>üö¼ƒ±íËNªzQ\›‰­íãÒÔv\Üš*šG qf¤—޵ò.üq᮪[›×;|Û ˜~²hlŠž endstream endobj 31 0 obj 323 endobj 28 0 obj << /Type /XObject /Subtype /Image /Name /im6 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 29 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 29 0 obj 456 endobj 34 0 obj << /Length 35 0 R /Filter /FlateDecode >> stream H‰Œ½ Â0FŸà¾Ã7&C¯7±I¬["¢ƒZ.‚pè¤PÄÉ×·å,‡3œ¨S Ù¸8:P%ì%ºÅ'oÓnÍ?˜Kwʽ>õqÍ{ÜÛ±?¶£/Ɖ‹bçb-ôMYé Š…*¢n^÷5¦´yÍ Ã‡þŒãX endstream endobj 35 0 obj 123 endobj 32 0 obj << /Type /XObject /Subtype /Image /Name /im7 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 33 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 33 0 obj 456 endobj 38 0 obj << /Length 39 0 R /Filter /FlateDecode >> stream H‰mPÍj„0|‚¼ÃwÜ-hóí-«BuínÚÓ‚PýÁ¥´—¾~ó%©R(¹ÌL2Ãd€QTç\Óe®\M2ê¹ÖÏ@sÉK¾açì¡k¦ÁöÍ<ÙSuoOü²ô²ßƒ{'2|XÚ ¦~íJF{[OÕ±{ì‡Ý ð|½i‘Tø*вÜ(¸ÂÊö””{(ñJRô@`"¸A˜”…ð·$.ãuZÛì1¶ÄØeãE )H&G§‰:4Æ"‘/Hy"±9$¢Ñò äùç_k¨4?<8…_’Áâ’qE;ö“Ç®­¬kÃ9Œ×¸­ºú³Yâ¾ÓÈ'²3 ë0aŠÙnß®Ôä¶l¬ endstream endobj 39 0 obj 279 endobj 36 0 obj << /Type /XObject /Subtype /Image /Name /im8 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 37 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 37 0 obj 456 endobj 42 0 obj << /Length 43 0 R /Filter /FlateDecode >> stream H‰U‘MnÂ0…O0wxK¨„kÇvBØ’V¸;$$²hAEU»éõëqìT•%{>Ëo~ž÷ ¥#­µ(,L9箦™ªÈr÷B¾ýÁ¤êº—vU¹v·=·õÛ×Ͳ9à4yZŸ¦S¸)ðú~5ެQÂÂjë÷;F,`ôç<Ðߎd¬ùƒQG06‰SdGI`¥’d@‰ –ƒ8d•©J¬*c•ÐN€Ø¢§HEÉ;èòÀf¥ò¥È¯$xñÈÞµLÉbp-9¶9wÕj]=7Ç`P3fÈʶôÍA_ <$å< ÞûÇ×{‰ú“~hX endstream endobj 43 0 obj 245 endobj 40 0 obj << /Type /XObject /Subtype /Image /Name /im9 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 41 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 41 0 obj 456 endobj 46 0 obj << /Length 47 0 R /Filter /FlateDecode >> stream H‰]‘ÍJÄ0…Ÿ ïp—ajþÛÎ.ÓF-µ¡v¢ ºTq6¾¾¹éŽÒ4§ç»‡Ó {O¤f)W O€¯È–¦¬áxš ­ñøIgÊÆÜÚ±®vàÛ½íaHnša³ÿA(l tCps®ùb/r}ioìóžL_Þ™ž £tØüé´r¤sŒÚ¼q¥ií_’@RDø«É\°Å-™šÜÖ™ý½­Ænh ógõ„®ó‘åi¦ ãy†»PØÒù^Q^µ<”&4Þb›QS5ì’.db"™M¦,¦kÇ¥•ÊvÖUÖ•µ=,y"JÆá'¿I‡Qóû'0üÐ˜È ”ULy ß_¿Ÿ…ê‹üjk: endstream endobj 47 0 obj 288 endobj 44 0 obj << /Type /XObject /Subtype /Image /Name /im10 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 45 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 45 0 obj 456 endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream H‰e‘]kƒ0†Aþù´³|š¤wVÓMº:§V(^”ml¬Œõf‰šÒ®9¯Ãóž÷$/€V-âZ’+ Ðæ(&˜i¢Ýþ É™ÛþB”ÛÊ–¹-³ýPäK(wÛ•­Ð~"±ñ(8”j#g”'ÔLhgë¦x./8è£õ¦_< 8S,vã¦p»¯ìº´ÎÓšõ#³F{7Ò‰ægœ¨ olÝ™vuq‰RIþÁBç‚&æž;¸8ó¶E|œÞ “` Š ÿžJ3˜I8½Â›KÉñ2äü̉Ï5ãG„¼xú >¼ªYÃææ&kiµª4Û¤vXO¶ ^‚ ÷FŽ€¤8¿¹Z?€’Q:–Þœ0Ê/Jp¿rÿq¤òoô½ƒz endstream endobj 51 0 obj 300 endobj 48 0 obj << /Type /XObject /Subtype /Image /Name /im11 /Filter /DCTDecode /Width 8 /Height 7 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 49 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?ôWÖ£ÔhwR»>ƒï¹„ êÞ×k6½Ž’=ÅÚ7øAÇÐ:5_XzQ¡ÝJìú?¾æ+«{\=¬Øö:H÷hßá©ìþÚ½k냛õ–üÜ:ÿÑ0UU®†Ô ~›N¤™´#tŸÿÙ endstream endobj 49 0 obj 452 endobj 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream H‰¥RMOÂ@ýûæ&ÔýþàV A –‚!!é¨ÑHŒ\üûîl·Mk¢³‡ÝÉì{3óÞ<™”DQ™FX¼ œ‘M˜sþyšä~Á`¾¼Ïªål ù~=ÉŠ!”o„ÂÈ&<ÀaÖ©§™«q‡¬Ø-7y §Á|u6 ºsíd„KÉl ߦåb ‡´˜.Ò‚ŸLQ±åM(Ú©iº½–ÇmÖE*ë–ÎJÂÏõw1Ô„Ë‚‰‚ë<n]ÒÉ LBáÛgwAÃøCЍ…Ÿ òâXœéºÃº¹t»®¶ét•ÞeÕæ1÷ò4íD¡àDè -Fï@b!gñw­QÿTÙÅU„‡žª}±üSvn(k¡aìš§ëžðü'”é¶ikcÕݦ(«UvìíWÏ")ƒEÂp´Àj o\’µk’”èYT§%×Í–÷-¢Tþf®QëP¤ai¼IʶqmÓ'¸½Ì~1!9.ÓÙÿ¿}½0³ò ÒñÄä endstream endobj 55 0 obj 388 endobj 52 0 obj << /Type /XObject /Subtype /Image /Name /im12 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 53 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 53 0 obj 456 endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream H‰}’]o‚0†Aÿùœ&²~¼C픈Ƞš˜˜Ì‹}D³l7ûûkKÁa¶… úú>çô¥€fqžDT§À,Ð[Eˆ]ŸGœ2a—_pW¦óuºÔÍZ¦°O«ù*­èñŽ`|À¼! “Ø,<«+„H¥94EºÑBdOP˜uNÕ€Pæ»*Íg˜±wKÆ;7Éð»*xÅ­™Å}k‚ÕÐlå`zvkX^OÞzëRÏ›‡,×M™šÕ¿½I"â`g2¦·þÉ\xÅn3ÓU—™ø<æ´ó+)ƒ?+–¹6Û¢)§à:ÛÆ¡+÷|>Òö2(éPR%‘€ ô:&À”[Rû‰+ÖÖ€ fw´êl…··’©ØÛýÛ×ýv«„xîwÄÖ*uŸ4,)4 •³+ø‘B!Ì@½ýÐÓØÝøv$2³ù¹ÇàÓ‹“6½6¸´Ü4ÝßëªÎ¶EícÓcg$åµ­ôHz¶½Ó]$Nvóýë…0X¼£oÆ/Äf endstream endobj 59 0 obj 398 endobj 56 0 obj << /Type /XObject /Subtype /Image /Name /im13 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 57 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 57 0 obj 456 endobj 60 0 obj << /Length 61 0 R /Filter /FlateDecode >> stream H‰…•ÛŽ›0†Ÿ€wðåf¥M}À6ä΀7EáµH•"!5=¨«ª½éëׯÆI»+$Ä€¿f~Oœ&!Œ³5ÀTÉ\£,wÏgׄ¡Ü>þG©tÝwC]m@wh ©ÀéáywZ­€ù™@ðäÖUÀâ3<áyÆ<¾åNlå°“_6à(TùY(|z@žV3!ºÆ4jQÆ‚VŠg•t¢•wZ“»(äÙ¤@0¾•8¨úFF ó8ÂÍ'˜fÄÃúжBÝ´AàD,Z˜…º+©KUïKüÜ«V˜åêƒBŠÐ”z'qͦwéaÌÎyêY%)´*a¬mî¾hx†£]”F»ºªW×é²×»Å®Ñfyì6E¡[Ù‰¢‘Õ°ßÇYì–!qo MÖ6¢yоà€±Ý¾³r7¢¥Ý÷Ê,AwãËÉe|yØDaÄÐö•l†¦Õ2S1}Bf°<êÁW1(©ÑV¢é‹…Y@Æ ˆÒÔG1Žâl”Æ$xš½¡<ºËÒànUk£êâ0RF¨ÂîÎË¥b> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 63 0 obj 456 endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream H‰­—ëjÝ8ǟ༃>¦…Ým•eÁÉq²&ç’ú8ÒCš’²œîÂnð¾þê6²|χ6hìÑߣ™‘ôë'´¹¬7Œ‰„ $ORP½Ý|À QJéñ7„–R¦‡ÿ¡‹SQ=”WESn?¢Ãýþ²¨ÐãÅõíã»w¨þsCùùçmÐl¤Þðë+¡çMQo¨‰@’ýû' &CT˜¿\[T°ÆèÚHf4œ}Ö&5ëp¦Äî #“¬-°]í¹³™l%&nŽ{c 3Õ}ß?8;X.\¯‡‰?Ðæé½É5c3nR‘ù1IÓI§LJ—t—ïün߇ürWl›»üê6¿)š‡¢:•ÇÃɦ\µÒ× ™ºeLBÝ„t20õ¶øüÍVS®Iäeµ±UŠ% Ý dï«ò ²ÚËÊÖï}˜AP„8«¢®?7‡|_, v^'dÓ*‹Ð·Œp'æot;§Ñò‰¢D%}Ñ•pc·(ÛMå2ÊÓ¾ärF#¯ž Nƒ #~ÃÞï÷yµTuï—Fv¥ -´-NWUyW›y×ÇjŸ× šcçX^tqRˆ3šñ6Ý©ÊSLH—_¥ªØù©h¶y½T¥Øm\þT‰Ð¬DA­ÛcµX&ãW Î1å±Èj½Á)#‚CLYš9¹pV,¨Ÿ¸&*œ2󡕇SïÖÔ"¯^ á®…¨o¡:¿¹YQ—žT§>´ýݱª×" N“½¢ÿ¬‚í§‹Ÿ7ûã¶Ø5»c¾]ùÀ„÷¸sxªD±¯R~U—¹Ý+]9ðìí¢.-ŒÂ&z»òÈ·× !f)9¯ºÔunvÅá¦þc±„±c¬šòpàq /OuU^Þ×ë§Þе— ö'ÍÔ„ôZ6†¾¿‚gDjïeΕé;M4ð@`¤‡æ¯Å‹Ôö¥· ,ŽÁÔŒ!˜ŠÞ –%^œºæX9w65(âE¸eû¨"à€56:ï ‹°*`0øfàˆËBÖk—|ˆ5×å®°Éÿ©&™ L*ÇŽ`§Z5s‹KÍ4u¸çXÐÄëLK‚~,ìbôl7°²6SÆ4ÇÐ9Œ±eMĘBVÌ Œ«ÿ”1ÏÆ²QËÇæfƒÒ™…¸ÆÙÌ<™_Ìõ³CÃÞ&²°÷2:A…íþ…ù©Ì·ÛöuŽó$íÎ)1y¯#žói™*9æ¸vlpx…s}†ÔÚY$#$Äš ÈÑ.²¡×ðV!Ý­’Á­¬íÁVÿš\t«Ì#W»ÂV$d›NÈ æ÷à1 P–2…N협Âe‚—=ÐQ;A2…ÊrŽ)P;$ža–9Ä焱ú´Æé“|‡r)àDL:íÒhà ýÈÔiÚIv1G”U‰1¼´CJPT$,@§à¤¥hˆT…¨1›áv 4XG„d³¤ÑÎ ÅðgªÃV Ø:„‹ßžŸ~þÛœÿ~J^¾¿ž¿ÿõòúãñâ9I’ßÇõœ8_ÆPÑ.ÒëÀO‚IXá$&Øû¥’º›é«Ò]£§È4׿²×füº÷¨s1Z=‡N¼{õ?P5ü endstream endobj 65 0 obj 1178 endobj 4 0 obj << /Type /Page /Parent 5 0 R /Resources << /Font << /F0 6 0 R >> /XObject 66 0 R /ProcSet 2 0 R >> /Contents 67 0 R >> endobj 66 0 obj << /im1 10 0 R /im2 12 0 R /im3 16 0 R /im4 20 0 R /im5 24 0 R /im6 28 0 R /im7 32 0 R /im8 36 0 R /im9 40 0 R /im10 44 0 R /im11 48 0 R /im12 52 0 R /im13 56 0 R /im14 62 0 R >> endobj 67 0 obj [ 8 0 R 14 0 R 18 0 R 22 0 R 26 0 R 30 0 R 34 0 R 38 0 R 42 0 R 46 0 R 50 0 R 54 0 R 58 0 R 60 0 R 64 0 R ] endobj 69 0 obj << /Length 70 0 R /Filter /FlateDecode >> stream H‰­WëŽ\9~‚~ÿÜEÛg|¿¬Ò„Ì"‚HÒ(?вCBÍvE¼=v]ì²Ow(»=.×WŸËUv¹Î³ÓÁš¼Ù R [ Jž´jÿ~þ«:Üü hÕéÃá¨7«uªã{¥7’­Ã¯ê›»WooÿðâíïïÞ¨ãQ=ÿô¿?¼û·Q7ê—/Þ}ú¢^ÿëÇÏïïÿ©n~ÿîWߪÓçC]°®tLÞ·åTåÕ!âÕ& ­ùNÕnþ­ÌÆ~¯õ÷:«Ûê;UnlýOk ”w§ƒQí_óÚdå­ )ªdë>Þ«ÝVüZUêwíç³¢M¾ú:ødTȾmó±I¾aiâA^3"nh‚Zg…ECØR%çU„½®ög–`XžÜ OU‡ì‘w 'IÝ7œÛ„Ú#é"i¦°™Xí`Ê ÍÂÂúQ~üÅAýÉW­©ÿÿ¹æE©¿¬y f“i™½ÃŒƒ;y ɇ8 &8e’o¤Æ—fÝ$d@]¤5Q2¤sE«àXçrnþx}^[,Äã¢ZK]Nà¬P;–È­~¶]088¤Cõ·² ±b‹²Ë°UV¢÷hFcϩ몹Áè:#/GJÃFÒÅk ‰hÔ”á÷šUT…}J]ÊKSœ³³d½$hOVs1M©Ìi"â=­T¥)M)É4á6È,.iâ ÕÜ`iâåHYºQ9—¦Ÿ ~š\”‹-YÎw óGõF}Qgòx¬Ô•£ÚÐniÂE EfiŠÛË)É 8“ç·ÊÝV!A ¢¨»20’4všrÔ:Iß6yEM² eàõdDµ™bÅrKFYMëµä@.X©…‰tä …&6 >æºÊu·pá‰8t«7ØÚäçz][Î\XkqN|‘\Áj "ÊF€8WzZaï— ¶Jy»¬OèQ–x['Š6¢‰5­6x„;ÚSŸðjZlZ«ë‚7âéo¿Ä(Ú 7’Í 61Ñ}@CéáH¯sŸîÔ=·s6f×,÷ íÞÙÜîP4†_Ól†Lñ#ˆÛ¢Î"ÑtäGðxN©Úaœ]³¹‡Ð„À´+ NXìÒí zÑÓÍ5uÎôlNËB~ðÖ’š÷âÇp¤œg ydf&Ö‘uX’”F˜MnŽœ¯©aÆž›Ùñ]Ê»vw¯=2—ùjó„ïqvµ9—€$,FE#_q×Ñ^«’&„êÄàÝCîñÖCKô(dhŒªVb5xr=\ PØ ni@2Ë©óÕ!Âx:Lð0³Ñ}¾”‚H)Îî,^Ü]ï³Ç65R(XNV\hß^í z˜¬¡¥æ;Ä$Zñ*A/ásç™Ömû¬]'#–F"üA£ ùBçÃÅPY&£"åå ¥ÌuMkQ(ÎBBIOCÊ®:j#«c%éê´0$ô£vbNºT%ÂnsÀ&‚”¾ ‡(&È*{eÄâ`5V%i”fÊ‹_Ž–ãh˜’W©GêL䯉feÞ÷ %‹¾†ÙL–ÈJ£ÍÜM§cîàÚÌ7a…ä'ô η0\¹K.É»Ô%H±Xɸ°Ü%7T~2òÓ]b¯…ë×…ùú]¢ÅP™&£´¿Kû£p&+ôúÀì«,C"2OºÔ³>R4ZîØá‹•Däa¿ï$×O#Ô”=¿ ¡m8úpI _Ñ“ÜõHÇêúyAšxè_¢ã//½†³$–‰G-ö!¢7¨ Ã$ 2À‘¬ÈŸ”Æ…#Àà2¤Êlg&ÌööÆÔƒ>\\3É;Ñû;LŒ:Òþ1‘(N‰Ô!–G?‚¯n5F*Võ5›8,-EBÖ<ò£Ín’ rjF.[C*#LŒ O¨Ñ}×È%.DJß üÂ5%³‡žØzì'O×”Ò–ÎdÔÕ¢6ðDšÎ“Ún¾+‹¦Ž,Ç$×Öœ™%¨bº ÒºVD°$ÁöhŒEf6KVÛÃ;ÏoJø(zŒà”‰V4F&z±Ã3j½]ÓÚIGÍY†"Z’’£RË“ Ax`”l`[ºê®vÝÌ1ÁÀ7’m„ž#u$£(¹.öO ü`DHÖ*S|vѯ «Ì™Îoˆ‰‰ozf ê×=Ƴþ§Ö§4¹Ó:âþ¨Þ¨/Ó‰n¸ŒížbïÒÁá‹1š¸=P…n#°« ƒ%2 -³}oäÊÈÇ˱“†´©‡ˆ¶±ÆÉi§á ¥²¹ìk×Ý$Ï-˜Ë[Ä¡N,Ñq.°Yë<ŸèÒ¤§v{àÅa6^,è¹³ÚÌl}¢½³U`st“Bd ´ ÒD_š¬ÉEÄòŒb37±:fÅ%Iɾ©ÙMña¹ËƈDëȧ¸ˆ›3ÜYK=TTî±Q ¸±IêáöË ¬¦ö«ªµndoA8{]¢àúÂ<°¢ÒŠœ> BY/ÚQ¥G²UŸVeiÔ%‚‘ˆoG32Ið€ 85Œ†‹â¡9“Ó«£p|ß^#¶œi¯õÓ— ŠÓ·µø1Ð!iiä±’[k¿†ªà[M%ñìÖÒ<ÖÚ2$,'HéŠÅb”ã\¢öoʱös®8ªWmô£PãÈ áŠD/Ù‚·„ªZ¨tð832ž+®ù‘zï‚"ÄÜÁã0›Îñ¨åÔY¤G•&fŽdEx¸×èVhRy6ð3ž"Œ,aëH?Ô)H¦l=FNëåèÖUêïÃ8IŒHÛÔÞ‹³†ÎaÇŸð¢Íî­‹ºløq:bû0&Ð×Ö¡FÏoJ²ÚP?<™%FTuÔüÒ8h‘£ß.éÁô`Õ¢YbD»b¿U»\?>+—°ë`ÅÁVºnäq"CiB#ü¶F"—cefqæä*¶ }p½ˆ…y›²†¡§kù/¶mGÓCú8Ä€/ ¼k¾v¦uáMµX­`:JxìTˆCÙás@Fޏah‰6]$¼L\Ü}\ÿé·Ðâ#V¬Èn_óB ÛnÖàá|8Ó‹W1A+á3$ö xž’©£,zc’à @ÏÊjì[ÉŒ…ØÏKŸQl&ÖÐYaIRšn4¹ù¿DÔjQK«Gñ¥AÒ| Yu=˜X¦Še®¬ö½P3´N0l[È­;D…`#„ — à9w(Ñtà$XþÛXUâva7Ên™y;k”Úü´¨” ÃoAÆ’§•Ä*Q€£Ø ¸g€C$§¨ÒãtàòP¡¶ _>z˜ÄfÖH‘êz°œoOaýžÂ#4~çl€Õ™·^•u©g'ÄÚý¨Ós±øÍZÕc•B ÎéÃá¨7“¼¯ãû¶«ÓWõÍí¯_¿½=^ýöÙOw¯¿U§Ï‡»Aˆ—¦nØc7Aý)°Ò1ÖNÄ ¼¾¯7ŸëGäó¿þ$…ÄÙ endstream endobj 70 0 obj 2619 endobj 71 0 obj << /Type /XObject /Subtype /Image /Name /im15 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 72 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 72 0 obj 456 endobj 73 0 obj << /Length 74 0 R /Filter /FlateDecode >> stream H‰¥U]oÓ0ýù÷q›´âo'{KÓ mÓ¥î`R¥HLˆ6{áïcûÚNÝuUj}œœs¯Ïõ½½‚bj .ʉ– Ÿ0 `fÅ9™Ð’s»¾2áRj»ü 'µ1ý|º5í0Ÿ]Àj»œ¶ý)˜ïóÊ1Á2Q42u)‘ÙMß·Ìͺ½€ëºoÞÕ=ÛPBv§°;¹ü°;B2dáµXµ¡AËÔÓE;¬êe&ÅŸ*©$ÉN2œæPÊgåEÌ™§Ë‘Î"}Ý·ÆÜ¼ÎÕ$ú(Ów½ØöõâE¶P,²i©½éz3tý¬í³a*¹ ›Õ¦>t^¾b¼–Éx‘tÚËz»0Ãu½Øfb‚¤¼3ÛUUŽgg(²œ¯†JlŽå¯ÅÈÑ‘Sz‘Ãht‰W<ºdº¾~›×†çæRZEZ)x¤ÕfÞ ëŒ—Ó*’j¢XˆÖt‹íruôRzjkŠ_PР8pâZîñ ÜÁGøaŸ€û<~…¢t÷ ˜¢î…‡ûæÔ¾S™îGk|âÜBaèÞ=Ims¿¢‰`בà€ò/y*GªŠ+G!y òA2Et¤ÞAñù¬¸‚èf&¤ûö7o4ÃÎ$Ÿ§œì£àyèÝf3Œý;k7M?_›y·ÚD·Ç@¶²Öð¿¾à¹Åˆí©6°G—%XÃŽåè%ísBLó¿f_–µd +òÙ¸l?Ü)НÆ*‹)Ód#ZÇ‘J1|hoþ"(× È þ†ý•"ù«Ë'1/ YtÓl a°±¿˜*m4…51ÅÎÒvɱ¯¤ßÇ?E{i%Ü2ìÜ» _‚°A+нPBd¤ãŽb‰6P ‹c!rônÜ;¬# '@X$bßY;SJ»IÀ}œ#~²òùþÂÁÝLyW{öY€c«ª¼²´â£µ·öå7ߨ‚ÙÏâÎ6Ø% endstream endobj 74 0 obj 725 endobj 75 0 obj << /Type /XObject /Subtype /Image /Name /im16 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 76 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 76 0 obj 456 endobj 79 0 obj << /Length 80 0 R /Filter /FlateDecode >> stream H‰Œ± Â@¿`ÿá•I‘õ6a³jyÞ **ÊÚ,R)±ò÷½cŠ™jn èÔ‡À½b4«‚'ê‹­­ôŒÀƒŠ”ü¡¹ÆcÞùó¶¸<Î1ß15ûÓÔ¶ð7e§/hD(tZW²¸~•M1/ ÕkCúÐô& endstream endobj 80 0 obj 117 endobj 77 0 obj << /Type /XObject /Subtype /Image /Name /im17 /Filter /DCTDecode /Width 8 /Height 7 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 78 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?ôWÖ£ÔhwR»>ƒï¹„ êÞ×k6½Ž’=ÅÚ7øAÇÐ:5_XzQ¡ÝJìú?¾æ+«{\=¬Øö:H÷hßá©ìþÚ½k냛õ–üÜ:ÿÑ0UU®†Ô ~›N¤™´#tŸÿÙ endstream endobj 78 0 obj 452 endobj 83 0 obj << /Length 84 0 R /Filter /FlateDecode >> stream H‰EÍjÃ0„Ÿ@ï0Gç`UÖÏÊÎMŽ]úCkË‚Á‡”–†Ò\úúÕº6e³»ƒ>;@ÔQh¥¤v _° 6"W² S¦þ%!Úd!Æn_±öÍOÃcÝv³Ûûq³Aü y¹0šˆ†5Õ?b:„‡¡ÝâºÝ]èô˜Y¥ÔÂh£(Àu}ƒ°ÞIç DÒ;%®'œÓÞò8^òžÇdõóE«]ÍÂ)p1’s©ÂþåZ2íú© 1Ä×ç¶_C¬ŒÒ±\ œÕ|Û²ø„H}CÐLÎ ÖÓìW†å˜^ܼ_RàæKüwoM› endstream endobj 84 0 obj 238 endobj 81 0 obj << /Type /XObject /Subtype /Image /Name /im18 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 82 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 82 0 obj 456 endobj 87 0 obj << /Length 88 0 R /Filter /FlateDecode >> stream H‰MPÉjÃ0üýÓ‚]-¶Ÿ”› zhB+¡…€¡>t¡¡´—þ~µÙÞŒôæ-ó¶õ¬Ñª¦­Ö1À÷¬âµ”DOàuùð«ÞzëŸÜg{ÜÝÙ£¼¬Z~Y¯á?Ge¢QMžÕ ɬÞÛ§ñ0žíýÉ Nû­;&¥@#å…H£Ó‡Z(’Ì;CY2ÓQÜ™Ô#UÍ8u¡™Åi˜’LÒ©¤¿½ÜDkçÖm-³³ñÄUƒKŠK‘]ÊÙÝ0ºàKñ(yã–"Üüó$‘0Ëö Ö¥ªUÞ ®<…¼Û÷«0è¿Ø$¥có endstream endobj 88 0 obj 272 endobj 85 0 obj << /Type /XObject /Subtype /Image /Name /im19 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 86 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 86 0 obj 456 endobj 91 0 obj << /Length 92 0 R /Filter /FlateDecode >> stream H‰ Œ± ƒ@¿`ÿá•ZxY]r'vw‚H‘µRX)ˆXå÷³ SÍ•„ƒ{"Ô­š¨bW{i­7°ñåE¯:qÑüS‡÷òŠyÆZ ÓZ–Ѓ²Ò ò`£òf›l'豟 #]ôˆ endstream endobj 92 0 obj 113 endobj 89 0 obj << /Type /XObject /Subtype /Image /Name /im20 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 90 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 90 0 obj 456 endobj 95 0 obj << /Length 96 0 R /Filter /FlateDecode >> stream H‰]ËjÃ0E¿`þa–ÉÂîH²%+;?¥4q++@À‹Ð–†„Òlúûɉ E0 ó8÷Ž^šŠL^¢’#†2Ê‘äüˆ”FjNpá6Ûõ¸«Ÿ·n…»Ú·µ—‡… ¢Ãr‰á„™d‚,ÉÜ R‰‰ðâ]ûqS¯ÿ#þ%¯ÎBÏ6Du³1ô>Œ½ïœ_!;jœO«.€Àø®VFJiV_¥ ×7|+ò[ÝÆ Ô¸3¤ŸH]­Òì%¾H‹N¨(&'“‰ºƾyrmîêÓ²LÜ ‚¨(7sáŒÀß:Q3V±’Ž#Gž~ø¼HÝü†Wd endstream endobj 96 0 obj 255 endobj 93 0 obj << /Type /XObject /Subtype /Image /Name /im21 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 94 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 94 0 obj 456 endobj 97 0 obj << /Length 98 0 R /Filter /FlateDecode >> stream H‰TÛnÛ0 ýÿ›I%Y’­¼9±Úz[ÖV¶``Ŷnh7¬/ûý‘ºÄNÛ C‡²|xŽIÝ@¶rgl¡@çb!€«³9[¦4Æ÷ÀyQbôN6«wv톦^B»½ZÙnîGÆ`n¥ùˆR0wwm—ð±êÖ—U'v'Ⱥ›Áîäüýn–锈—û<*—!ÏzÓ:{;åVQ¿WÂË"e0œ‡ ½]o»ÆÝ M{i1®—@jPÌ„Ìó˜BrUD­\³i‡mo»Ü©^ä&ñJ¿Õ•Cè91Zmʈæzê™bQg$ËLHÎM€~¨z7\mêæ¼±õk2&ƺÆùïšöâ行ؗCËW¨#­Ë~CÆK ˆT ¤ íù <À'ø‰{@¿ço¡SZ¸ùcšSS¾5Y à²yIeëG\J–sÎý¢÷a‘`ñ…,éûÇÉ‹‚þbš 3R„I@X!0 KÒø¨L€È>Ÿf7Ð>}MGp“”pÆ4€¾Ðó`wµî‡8IûAhk{›¬¹”$– ÑcäJDJVûÕÃToîõ’yoÉ%´Åòbœ6•¦íÕu1×CÅ…W,‰é*§Þ¨|ßÄEœÌª]ÛÞmºÿ! …’ìÇ“f‡0^&:ðµÃ…mmçÇ´?š@56w`㹯ˆ‰á+n¦x 'A½ƒÛ‚qßV¨…ý(§ŸJ%tݵ}ÒB ¨ËÍ%™H‹PotCûŒxéùórCÏ{üôìû“PÿÊþC¦VÒ endstream endobj 98 0 obj 616 endobj 99 0 obj << /Type /XObject /Subtype /Image /Name /im22 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 100 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 100 0 obj 456 endobj 101 0 obj << /Length 102 0 R /Filter /FlateDecode >> stream H‰…“ÏNã0ÆŸÀï0Ç‚DÖvì8ææ¦Þ¥¶!qH•,ÑÃ.´Z.¼>þ›¶€r°Çö÷›ÏÏ5 ¹A\‘À,Ð.(µ›ï cꦯ0ÛÌ/uc¬¹ëô9ܨ¾¹P=ÝÍÆ»“0ÙôIFá‘0l;ÝÕÃnöójÂT†ò„)%“£æƒé•³Òƒ‡8Æ$åEPD5Ç"› %‰ê®×ÆÜÙµZ}~)¿Àe&0*ÞºvÛ«ö8ÜÆüU5æOæš·ú¿ìåaMòµgQ¸\ØfÓnWë¯tœ:Z¥Œj®Ô¯ïsr™¥%I9½Ä®´¹Ø,Ž*?Ö›°|ß²NÅò¿Ûê[£×Ãr³¶áúGYü÷ò6ˆHæ¹ÔñžaŠDÁÝ3¥…ðtS×ó½;†ë¼óä#‘7 æq#èsP%Q i8ýt°†L¡ÁAΣ O⊗'{Iœ'XŽD–ÿtêûot%ýàÛƒÿ|=|eqÚ)µ@3ØÁ(³l¬2¦·7ªÝê!ÔQO°’VÏEÎßè *ÀÝ;«äK³w§<<ÓÑmŠæ endstream endobj 102 0 obj 436 endobj 103 0 obj << /Type /XObject /Subtype /Image /Name /im23 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 104 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 104 0 obj 456 endobj 107 0 obj << /Length 108 0 R /Filter /FlateDecode >> stream H‰Ì» 1Fá'˜wøË¤Ø8“ÍEìö&¢…º ‚°ØJa+_ßÈi¾ê\A½’Hp9‡Бvž“T/`׿m¬üœûã4èCï—i‡[7‡nöÅs±(f*ÖB_4)}@ \k„³óÿ»¸ˆemž«ßôÅ8¢ endstream endobj 108 0 obj 124 endobj 105 0 obj << /Type /XObject /Subtype /Image /Name /im24 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 106 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 106 0 obj 456 endobj 111 0 obj << /Length 112 0 R /Filter /FlateDecode >> stream H‰EÁjÃ0 †ŸÀïðÛC<ÇNm§7§q·Ðv¤©Sr(ÛØXëe¯?)¤ ‘,ÿŸ~ùQ%‘ç…t+hã€T‹LÉÜOùJc5¥¿X„”º¦êS›zçþPÅÃb»–K¤O¡• ´µv¦ü×ç°ïãçÐmžB§‡E¡”𑬀ãöA*§œgk¹“z…Û+Þ„ñœN­RRÇóõiÚcn™I›(p0wò~¶4Ûic6»ðÇm³cziãénä>¦ÄôAŽ‘\}Aа;±3‹BIjé¼ÐÛ‡+ ëoñV!L endstream endobj 112 0 obj 241 endobj 109 0 obj << /Type /XObject /Subtype /Image /Name /im25 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 110 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 110 0 obj 456 endobj 115 0 obj << /Length 116 0 R /Filter /FlateDecode >> stream H‰UËjÃ0D¿@ÿ0ˤ`W’m=ºsõ™¦©# †€¡^ôABi7ýýêJrhÐfFÒœ{™g°…gµ®$àW¬à¥”"ȼ¬lUù‹ÙõÝÚ ¾ßºáÁõWxi»åmÛÉý¬áûùþ“q– BÃuFÔ² ±íœ÷ý°iÝ€äA€ÎϘóLh eT@áˆìt©Ý”M0–ž„®'‰Ì6¤òÅ!øŠÙ[™#e2êMÊLÑìUü8*âód(—Hö@.î—|Ü;1’4Sèìõ‚ºÏƒ,õsС¨F¡Lª15xã6®k×ÃÓâÞ-ý.–æNÃÏÊâyŸØ7˜ŠÜBÁÖå©„1|¾ü8J…Õû;9ká endstream endobj 116 0 obj 281 endobj 113 0 obj << /Type /XObject /Subtype /Image /Name /im26 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 114 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 114 0 obj 456 endobj 117 0 obj << /Length 118 0 R /Filter /FlateDecode >> stream H‰ÕUMoÔ0ýùsÜVjäÏØî-› ìÍ.‰ E,ŠD‘@h¹páïãÛÉnW­8ôP)žÏ{žÌ<%ï¡Xú‚3••¥Ð~U\±’kB|¬”šóþÅvù¦mü¸Y]Cw{³l{Ø/^½Ý_\€ÿY0¸rȆÀZÚÄV¢‰Ý×›f=úzù®½†u߬ë^ì’ÍÕ¤!´È8SiÔÇ%^¿¿CŸYi4üÃí 0øV´¾Ì””Rð & Ã]²*D&¬Šž…–ÜCÁ5 <¤ö W&n w*’.’2”DY:„HJçt@PQ˜ $jŽ¥ÿ€âë%Í3ŸM Ž”^Ø!®Ói<±«u3Œi¶Í¶óí¨­.Œ# àD¸¶Užˆ<·Ä¹Ê¸éVí]9åœÍ˜[5»Ì$ɺkÚÁoû§E²²¬Nþ%eÇ&å*Û¯Û®ík¿ÙvÃÚ'yÏb0)A9…õ¡ÃiÌ }Äù9ƒ[R²’cŒž÷Ð3FeÄ -ÒÈ@ÍDz`l™x¢©&mº“ÑðhBh´XAª5PãjSúl´t¶=7™àÜ=b²]í×ÿŸÃüåË3—,GSňü É 'Ã¥,SˆsSÅP‘§"9Ç1€!—fh茨gfçÑq£ób%c&/4óc#¥s§_Ð+Uê+ùO»vnwmOÑM½£¶bkB‘á׃­±á ™Þa8‚aK;?½óöÉ£9µNfñyë/y•“b endstream endobj 118 0 obj 587 endobj 68 0 obj << /Type /Page /Parent 5 0 R /Resources << /Font << /F0 6 0 R >> /XObject 119 0 R /ProcSet 2 0 R >> /Contents 120 0 R >> endobj 119 0 obj << /im15 71 0 R /im16 75 0 R /im17 77 0 R /im18 81 0 R /im19 85 0 R /im20 89 0 R /im21 93 0 R /im22 99 0 R /im23 103 0 R /im24 105 0 R /im25 109 0 R /im26 113 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /Name /F0 /BaseFont /Arial /FirstChar 32 /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 750 556 750 222 556 333 1000 556 556 333 1000 667 333 1000 750 611 750 750 222 222 333 333 350 556 1000 333 1000 500 333 944 750 500 667 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 552 400 549 333 333 333 576 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 549 611 556 556 556 556 500 556 500 ] /Encoding /WinAnsiEncoding /FontDescriptor 7 0 R >> endobj 7 0 obj << /Type /FontDescriptor /FontName /Arial /Flags 32 /FontBBox [ -250 -212 1217 1000 ] /MissingWidth 278 /StemV 80 /StemH 80 /ItalicAngle 0 /CapHeight 905 /XHeight 453 /Ascent 905 /Descent -212 /Leading 150 /MaxWidth 1014 /AvgWidth 441 >> endobj 120 0 obj [ 69 0 R 73 0 R 79 0 R 83 0 R 87 0 R 91 0 R 95 0 R 97 0 R 101 0 R 107 0 R 111 0 R 115 0 R 117 0 R ] endobj 2 0 obj [ /PDF /Text /ImageC ] endobj 5 0 obj << /Kids [4 0 R 68 0 R ] /Count 2 /Type /Pages /MediaBox [ 0 0 612 792 ] >> endobj 1 0 obj << /Creator /CreationDate (D:20000928234927) /Title /Author /Producer (Acrobat PDFWriter 4.0 for Windows NT) >> endobj 3 0 obj << /Pages 5 0 R /Type /Catalog >> endobj xref 0 121 0000000000 65535 f 0000036019 00000 n 0000035889 00000 n 0000036523 00000 n 0000017847 00000 n 0000035928 00000 n 0000034432 00000 n 0000035517 00000 n 0000000019 00000 n 0000002353 00000 n 0000002373 00000 n 0000003009 00000 n 0000003278 00000 n 0000003914 00000 n 0000003029 00000 n 0000003258 00000 n 0000004181 00000 n 0000004817 00000 n 0000003934 00000 n 0000004161 00000 n 0000005275 00000 n 0000005911 00000 n 0000004837 00000 n 0000005255 00000 n 0000006174 00000 n 0000006810 00000 n 0000005931 00000 n 0000006154 00000 n 0000007251 00000 n 0000007887 00000 n 0000006830 00000 n 0000007231 00000 n 0000008128 00000 n 0000008764 00000 n 0000007907 00000 n 0000008108 00000 n 0000009161 00000 n 0000009797 00000 n 0000008784 00000 n 0000009141 00000 n 0000010160 00000 n 0000010796 00000 n 0000009817 00000 n 0000010140 00000 n 0000011202 00000 n 0000011839 00000 n 0000010816 00000 n 0000011182 00000 n 0000012257 00000 n 0000012890 00000 n 0000011859 00000 n 0000012237 00000 n 0000013396 00000 n 0000014033 00000 n 0000012910 00000 n 0000013376 00000 n 0000014549 00000 n 0000015186 00000 n 0000014053 00000 n 0000014529 00000 n 0000015206 00000 n 0000015893 00000 n 0000015913 00000 n 0000016550 00000 n 0000016570 00000 n 0000017826 00000 n 0000017982 00000 n 0000018177 00000 n 0000034111 00000 n 0000018303 00000 n 0000021000 00000 n 0000021021 00000 n 0000021658 00000 n 0000021678 00000 n 0000022481 00000 n 0000022501 00000 n 0000023138 00000 n 0000023373 00000 n 0000024006 00000 n 0000023158 00000 n 0000023353 00000 n 0000024362 00000 n 0000024999 00000 n 0000024026 00000 n 0000024342 00000 n 0000025389 00000 n 0000026026 00000 n 0000025019 00000 n 0000025369 00000 n 0000026257 00000 n 0000026894 00000 n 0000026046 00000 n 0000026237 00000 n 0000027267 00000 n 0000027904 00000 n 0000026914 00000 n 0000027247 00000 n 0000027924 00000 n 0000028618 00000 n 0000028638 00000 n 0000029276 00000 n 0000029297 00000 n 0000029813 00000 n 0000029834 00000 n 0000030473 00000 n 0000030719 00000 n 0000031358 00000 n 0000030494 00000 n 0000030698 00000 n 0000031721 00000 n 0000032360 00000 n 0000031379 00000 n 0000031700 00000 n 0000032763 00000 n 0000033402 00000 n 0000032381 00000 n 0000032742 00000 n 0000033423 00000 n 0000034090 00000 n 0000034249 00000 n 0000035770 00000 n trailer << /Size 121 /Root 3 0 R /Info 1 0 R /ID [<002b8f19347118ab218c3c3dd24e70e8><002b8f19347118ab218c3c3dd24e70e8>] >> startxref 36572 %%EOF openacs-5.7.0/packages/acs-core-docs/www/xml/for-everyone/0000755000175000017500000000000011724401447023243 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/for-everyone/acs-faq.xml0000644000175000017500000002556410456621135025313 0ustar frankiefrankie %myvars; ]> Open Architecture Community System FAQ Updated for OpenACS &version;, March 2002 I have a site made of static html pages. How can I add some collaboration features without setting up my own machine? Some of the basic Open Architecture Community System modules are available as free services. Just sign up for them by filling out a form. Spam will allow you to maintain mailing lists LUSENET will run a discussion group for you BooHoo link manager will allow your users to post related links Loquacious will allow your users to post comments clickthrough.net will track how many people follow links from your site to sites that you recommend I would like to use the Open Architecture Community System. How do I set up the basic infrastructure? To use the Open Architecture Community System, you need a computer with Unix or Linux, Oracle or PostgreSQL (currently), AOLserver and the Oracle or PostgreSQL driver for AOLserver installed. We have written an installation guide to aid you in the process. It takes you through the detailed steps necessary to build a working system from a bare hard drive through a basic OpenACS install. Followed closely on a reasonably fast machine, this document will give you a complete system in 4-5 hours. The Open Architecture Community System can now be run under Windows. However we advise the use of Unix, as it is the most well-tested and best documented platform for OpenACS. I have a machine with Unix/Linux, Oracle or PostgreSQL and AOLserver installed. How do I install the Open Architecture Community System? We strongly recommend that you thoroughly examine the step-by-step OpenACS installation guide, even if you already have a working Unix and Oracle installtion. The guide contains up-to-date information on the default settings that OpenACS developers use to generate properly running sites. Deviations from these defaults are recommended only if you are an expert system administrator. Once you have a working OpenACS installation, there are several utilities written by ArsDigita and the OpenACS community that can be installed to ensure that the server keeps running reliably. The overview of the ArsDigita Server Architecture is a good starting point for the development of a reliable service. The following documents will also help you keep your system running properly: Uptime Installation ArsDigita Server Architecture Audit (mainly for OpenACS 3.x) Where can I find Open Architecture Community System documentation? The latest documentation and developer/user resources are always available at http://openacs.org/doc/ What teaching and training is available? How can I sign up? During the exuberance of the dot com boom, training was provided for free at ArsDigita and other locations. But now you'll probably have to pay for some training from one of the companies that do OpenACS work: http://openacs.org/community/ See also: Teaching What resources are available for learning and reference? ArsDigita offers a variety of free teaching material: NOTE: This material was provided by ArsDigita Corporation. As ArsDigita has ceased their operations, we don't know for how long the following URLs will be operational, and we could not simply mirror them before asking permission from the authors. If arsdigita.com goes dead, you can find these documents under http://web.archive.org/web/*/http://arsdigita.com. Philip and Alex's Guide to Web Publishing SQL for Web Nerds (tutorial for the SQL language; links into online Oracle docs for completeness) Tcl for Web Nerds (tutorial for the Tcl language; in rough shape right now and you might consider using the Welch book (below)) Common errors made by database backed web developers Tips for using Oracle Problem Set 1 (basic db-backed Web sites; AOLserver, Tcl, SQL) Question and answer forum Problem Set 2 (extending the Open Architecture Community System, Web sites to support collaboration) Question and answer forum Problem Set 3 (content management) Question and answer forum Problem Set 4 (all about metadata) Question and answer forum Problem Set 5 (how to build collaborative authoring environment, Oracle full text indexing system) AOLserver Documentation AOLserver Tcl Reference Manual Recommended purchases Unix Power Tools (helps students with the mechanics of the Unix shell and Emacs) Oracle 8: The Complete Reference (more concise than the online Oracle docs) Practical Programming in Tcl and Tk (Brent Welch 1997; Prentice-Hall;) Visual Explanations : Images and Quantities, Evidence and Narrative (Edward Tufte 1997; Graphics Press; order directly by calling (800) 822-2454) - general design principles I am stuck. Where can a ask a question? OpenACS Forums #openacs IRC Where do I make feature suggestions, report bugs, and look for code patches? Go to the OpenACS developer site for the latest details on how to contribute. What ISPs and independent developers support the Open Architecture Community System? How can I let it be known that i'm an OpenACS developer? The most current list of outside firms and people who implement and host OpenACS-based systems is available on the OpenACS Community site. How can I contribute to the development of the Open Architecture Community System Please go to the online discussion forum if you would like to contribute. We need: OpenACS buddies: Many interested users need a little help with the first installation and initial questions. Module experts: We need experts for both existing and modules in development to suggest extensions, test new releases, write documentation and answer questions. Teachers: Use our teaching materials to teach your company, friends, or at a University. ($Id: acs-faq.xml,v 1.8 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/for-everyone/release-notes.xml0000644000175000017500000005331111456662500026537 0ustar frankiefrankie %myvars; ]> OpenACS Release Notes The ChangeLogs include an annotated list of changes () since the last release and in the entire &majorversion;.&minorversion; release sequence . Release 5.6.0 Added new package dependency type, "embeds". This is a variant of the "extends" package dependency type added in OpenACS 5.5.0. It allows one to write embeddable packages, with scripts made visible in client packages using URLs which include the embedded package's package key. An example embeddable package might be a rewritten "attachments" package. The current implementation requires a global instance be mounted, and client packages generate urls to that global instance. Among other things, this leads to the user navigating to the top-level subsite, losing any subsite theming that might be associated with a community. Using "embeds", a rewritten package would run in the client package's context, maintaining theming and automatically associating attachments with the client package. Added global package parameters - parameters can now have scope "local" or "global", with "local" being the default.. Fixes for ns_proxy handling Significant speedup for large sites Optional support for selenium remote control (acs-automated-tests) New administration UI to manage mime types and extension map Added acs-mail-lite package params for rollout support Support for 3-chars language codes in acs-lang Added OOXML mime types in acs-content-repository Release 5.5.0 PostgreSQL 8.3 is now fully supported, including the use of the built-in standard version of tsearch2. TinyMCE has been upgraded to 3.2.4.1 with language pack support. acs-mail-lite now correctly implements rollout support. Added new package dependency type, "extends". Implements a weak form of package inheritance (parameters and, optionally, templates). Multiple inheritance is supported. For instance, the non-core "layout-managed-subsite" extends the "acs-subsite" and "layout-manager" packages, resulting in a package that combines the semantics of both. Added new package attribute "implements-subsite-p" (default "f"). If true, this package may be mounted as a subsite and is expected to implement subsite semantics. Typically used by packages which extend acs-subsite. Added new package attribute "inherit-templates-p" (default "t"). If true, the package inherits templates defined in the packages it extends. This means that the package only needs to specify templates where the UI of an extended package is modified or extended. This greatly reduces the need to fork base packages when one needs to customize it. Rather than modify the package directly, use "extends" rather than "requires" then rewrite those templates you need to customize. Added a simple mechanism for defining subsite themes, removing the hard-wired choices implemented in earlier versions of OpenACS. The default theme has been moved into a new package, "openacs-default-theme". Simplifies the customization of the look and feel of OpenACS sites and subsites. The install xml facility has been enhanced to allow the calling of arbitrary Tcl procedures and includes various other enhancements written by Xarg. Packages can extend the facility, too. As an example of what can be done, the configuration of .LRN communities could be moved from a set of interacting parameters to a cleaner XML description of how to build classes and clubs, etc. Notifications now calls lang::util::localize on the message subject and body before sending the message out, using the recipient locale if set, the site-wide one if not. This will cause message keys (entered as #....# strings) to be replaced with the language text for the chosen locale. Release 5.4.2 This is a minor bugfix release. Site node caching was removed as doesn't work correctly Critical issues with search on oracle were fixed More html strict work etc Release 5.4.1 This is a minor bugfix release. Release 5.4.0 New Templating API added to add scripts, css, etc to the HTML HEAD and BODY sections of the generated HTML document. Please see /packages/acs-templating/tcl/head-procs.tcl or visit the template::head procs in the API browser for details. Templates have been modified to comply with HTML strict The Search package's results page has been improved TinyMCE WYSIWYG support has been added, RTE and HTMLArea support dropped acs-mail-lite's send has been cleaned up to properly encode content, to handle file attachments, etc. "complex-send" will disappear from acs-core in a future release. The ChangeLogs include an annotated list of changes () since the last release and in the entire &majorversion;.&minorversion; release sequence . Release 5.3.1 Bug fixes. New TIPs implemented. All Core Automated Tests for Postgres pass. New Site and Blank master templates and CSS compatible with the .LRN Zen work. Compatibility master templates are provided for existing sites. The ChangeLogs include an annotated list of changes () since the last release and in the entire &majorversion;.&minorversion; release sequence . Release 5.3.0 Bug fixes. New TIPs implemented. All Core Automated Tests for Postgres pass. Release 5.2.0 Bug fixes. New TIPs implemented. This release does not include new translations. Release 5.1.4 Bug fixes. The missing CR TCL API has been filled in, thanks to Rocael and his team and Dave Bauer. This release does not include new translations. Release 5.1.3 Bug fixes, primarily for .LRN compatibility in support of upcoming .LRN 2.1.0 releases. This release does not include new translations since 5.1.2. Release 5.1.2 Translations syncronized with the translation server. Basque and Catalan added. For a complete change list, see the Change list since 5.1.0 in . Release 5.1.1 This is the first release using the newest adjustment to the versioning convention. The OpenACS 5.1.1 tag will apply to OpenACS core as well as to the most recent released version of every package, including .LRN. Translations syncronized with the translation server. Bug 1519 fixed. This involved renaming all catalog files for ch_ZH, TH_TH, AR_EG, AR_LB, ms_my, RO_RO, FA_IR, and HR_HR. If you work with any of those locales, you should do a full catalog export and then import (via /acs-lang/admin) after upgrading acs-lang. (And, of course, make a backup of both the files and database before upgrading.) Other bug fixes since 5.1.0: 1785, 1793, and over a dozen additional bug fixes. For a complete change list, see the Change list since 5.0.0 in . Release 5.1.0 Lots of little tweaks and fixes Complete Change list since 5.0.0 in Changelog Many Bug fixes Release 5.0.4 New translations, including for .LRN 2.0.2. Release 5.0.3 Bug fixes: 1560, #1556. Site becomes unresponsive, requires restart Release 5.0.2 Bug fixes: #1495. Croatian enabled by default, #1496. APM automated install fails if files have spaces in their names, #1494. automated upgrade crashes (halting the upgrade process) Complete Change list since 5.0.0 in Changelog File tagging scheme in CVS changed to follow TIP #46: (Approved) Rules for Version Numbering and CVS tagging of Packages Release 5.0.1 All work on the translation server from 7 Nov 2003 to 7 Feb 2004 is now included in catalogs. One new function in acs-tcl, util::age_pretty Complete Change list since 5.0.0 in Changelog Many documentation updates and doc bug fixes Release 5.0.0 This is OpenACS 5.0.0. This version contains no known security, data loss, or crashing bugs, nor any bugs judged release blockers. This version has received manual testing. It has passed current automated testing, which is not comprehensive. This release contains work done on the translation server http://translate.openacs.org through 7 Nov 2003. Please report bugs using our Bug Tracker at the OpenACS website. You may want to begin by reading our installation documentation for . Note that the Windows documentation is not current for OpenACS &version;, but an alternative is to use John Sequeira's Oasis VM project. After installation, the full documentation set can be found by visiting http://yourserver/doc. New features in this release: Internationalization support. A message catalog to store translated text, localization of dates, number formatting, timezone conversion, etc. Allows you to serve your users in their language. External authenticaiton. Integrate with outside user databases through e.g. LDAP, RADIUS, Kerberos, MS Active Directory. Imports user information through IMS Enterprise 1.1 format. Easily extended to support other authentication, password management, account creation, and account import mechanisms. This includes improvements to the basic cookie handling, so logins can be expired without the user's identity being completely lost. You can set login to expire after a certain period (e.g. 8 hours, then password must be refreshed), or you can have all issues login cookies expired at once, e.g. if you have left a permanent login cookie on a public machine somewhere. User interface enhancements. All pages, including site-wide and subsite admin pages, will be templated, so they can be styled using master template and site-wide stylesheets. We have a new default-master template, which includes links to administration, your workspace, and login/logout, and is rendered using CSS. And there's a new community template (/packages/acs-subsite/www/group-master), which provides useful navigation to the applications and administrative UI in a subsite. In addition, there's new, simpler UI for managing members of a subsite, instantiating and mounting applications, setting permissions, parameters, etc. Site-wide admin as also seen the addition of a new simpler software install UI to replace the APM for non-developer users, and improved access to parameters, internationalization, automated testing, service contracts, etc. The list builder has been added for easily generating templated tables and lists, with features such as filtering, sorting, actions on multiple rows with checkboxes, etc. Most of all, it's fast to use, and results in consistently-looking, consistently-behaving, templated tables. Automated testing. The automated testing framework has been improved significantly, and there are automated tests for a number of packages. Security enhancements. HTML quoting now happens in the templating system, greatly minimizing the chance that users can sneak malicious HTML into the pages of other users. Oracle 9i support. Who's online feature. Spell checking. Potential incompatibilities: With the release of OpenACS 5, PostgreSQL 7.2 is no longer supported. Upgrades are supported from OpenACS 4.6.3 under Oracle or PostgreSQL 7.3. The undocumented special handling of ~ and +variable+ in formtemplates, found in packages/acs-templating/resources/*, has been removed in favor of using <noparse> and \@variable\@ (the standard templating mechanisms). Locally provided formtemplate styles still using these mechanisms will break. Serving backup files and files from the CVS directories is turned off by default via the acs-kernel parameter ExcludedFiles in section request-processor (The variable provides a string match glob list of files and is defaulted to "*/CVS/* *~") ($Id: release-notes.xml,v 1.28 2010/10/17 21:06:08 donb Exp $) Release 4.6.3 Release Notes for 4.6.3 Release 4.6.2 Release Notes for 4.6.2 Release 4.6 Release Notes for 4.6 Release 4.5 Release Notes for 4.5 Changelog (most recent release only) ChangeLog missing --> Changelog for &releasebranch; ChangeLog missing openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/0000755000175000017500000000000011724401447022103 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/kernel/ext-auth.xml0000644000175000017500000012537111501005400024353 0ustar frankiefrankie %myvars; ]> External Authentication Requirements Vision People have plenty of usernames and passwords already, we don't want them to have yet another. We want people to be able to log in to OpenACS with the same password they use to log in to any other system. Besides, administrators have better things to do than create accounts for people. So we want them to be able to create just one account on a central server (e.g. LDAP or RADIUS), and when they log on to OpenACS, an account will automatically be created for them here. Finally, security is increased with fewer passwords, since users generally can't remember all those passwords, so they tend to keep them all the same and never change them. Design Goals Transparent: Users don't have to do anything special to get an account on the local OpenACS system, if they already have an account on the external authentication server. Fall-back: Users who don't have an account on the external authentication server are still allowed to create a local account on OpenACS. This could be for external students who should have access to .LRN, but not to the rest of the university's resources. Authentication Client Only: We want OpenACS to be able to authenticate by asking some remote authority to verify the user's username/password combination. The goal is explicitly not (at this point) to have OpenACS act as an authentication server for other systems, although this could be easily added later. The goal is also not to devise an infrastructure for letting OpenACS access resources in various other systems on the user's behalf, such as IMAP, iCalendar, SMB file servers, etc., although this is definitely an interesting use-case. Easy configuration: We would like people to be able to configure this without having to write code. In particular, we want to build drivers that know how to talk with LDAP, RADIUS, PAM, etc., and which won't have to be locally modified. Only configuration and policies should change, code should not. Usability: The solution must be easy to use for end users and administrators alike. There's frequently a positive feedback effect between usability and security, because when authentication schemes have poor usability, users will think up ways to circumvent them. Open and modular: The design should be on the one hand open to add other authentification mechanisms when needed and on the other hand very modular to enable a start with minimal requirements (driver implementations) as soon as possible. The problem can be split into several logically separate parts. Each has a section below. Terminology Authority: The name of an authority trusted to authenticate users. Authentication Driver: An implementation of the authentication service contract, which talks to an authentication of a certain type, e.g. PAM, RADIUS, LDAP, or Active Directory. Authentication API: The API through which login pages and applications talk to the authentication service. There's one and only one implementation of the authentication API, namly the one included in OpenACS Core. Authentication Driver API: The service contract which authentication drivers implement. Conceptual Pictures Authentication: Account Management (NO PICTURE YET) Batch Synchronization (NO PICTURE YET) Requirements New API New API EXT-AUTH-01 A Extend Authentication/Acct Status API EXT-AUTH-03 A Account Creation API EXT-AUTH-05 A Password Management API EXT-AUTH-30 A Authority Management API Login Login EXT-AUTH-04 A Rewrite login, register, and admin pages to use APIs EXT-AUTH-38 A ad_form complain feature EXT-AUTH-19 A Rewrite password recovery to use API EXT-AUTH-21 A Rewrite email verification with API EXT-AUTH-28 A Username is email switch Users will log in using a username, a authority, and a password. The authority is the source for user/password verification. OpenACS can be an authority itself. Each user in OpenACS will belong to exactly one authority, which can either be the "local" OpenACS users table, in which case the password column is used, or it can be some external authority, which will be communicated with using some protocol, as implemented by an authentication driver. Username will be separate from email address. It can be an email address, it can look like an email address but not be the name of an actual email mailbox, or it can be something else entirely. We're assuming that user information (name, email, etc.) will either already be in the users table through a batch synchronization job, or that the relevant authentication implementation supports real-time synchronization of user data. Specifically, if you want remote users who haven't yet logged in to OpenACS to show up in user searches, you'll have to do the batch synchronization. All in all, the login box will be an includeable template and look like this: Username: ________ Password: ________ Authority: [URZ ] Athena Local [Forgot my password] [New user registration] If there's only one active authority, we don't display the authority drop-down element at all. Configuration Configuration EXT-AUTH-07 A Admin pages to control Ext-Auth parameters The site-wide systems administrator can configure the authentication process from a page linked under /acs-admin. Authorities - ordered list of authorities defined Account Registration Allowed: Yes/No. Account registration can be disabled altogether. Registration authority - the authority in which accounts should be created, using the relevant driver, if account registration is allowed. Username is email? - instead of asking for username, we'll ask for email. And we'll store the value in both columns, username and email. This is a setting that spans all authorities, and is primarily meant for backwards compatibility with the old OpenACS login process. The local authority driver is an encapsulation of current functionality within an driver matching a service contract. The other drivers call external functions. The possible functions for each authority are split into several drivers for convenience. One driver handles authentication, one account creation, and one changing passwords. create service contract EXT-AUTH-16 A Create service contract for Authentication EXT-AUTH-17 A Create service contract for Acct. Creation EXT-AUTH-29 A Create service contract for Passwd Management EXT-AUTH-18 A Authority configuration data model Each authority is defined like this: Authority pretty-name, e.g. "URZ" Authentication Driver, e.g. "RADIUS". In practice, this would be a reference to a service contract implementation. Authentication Driver configuration settings, e.g. host name, port, etc., as required by the particular driver. Note that this is per authority, not per driver, i.e., you can have multiple authorities with the same driver but different configuration options. AuthenticationAllowed - true/false, so you can disable login through some authority without having to delete the authority, and hence also all the users who belong to that authority. ForgottenPasswordUrl - a URL to redirect to instead of trying to use the authentication driver's password management features. ChangePasswordUrl - a URL to redirect to instead of trying to use the authentication driver's password management features. Account Creation Driver, e.g. "RADIUS". In practice, this would be a reference to a service contract implementation. The reason we have separate drivers for authentication and account creation is that organizations are likely to have a home-grown account registration process. Account Creation Driver configuration settings, e.g. host name, port, etc., as required by the particular driver. Note that this is per authority, not per driver, i.e., you can have multiple authorities with the same driver but different configuration options. RegistrationUrl - instead of registering using OpenACS, redirect to a certain URL site for account registration. RegistrationAllowed - true/false, so you can disable registration using this account. Sort order: Preference order of authorities. HelpContactText: Text or HTML to be displayed when user has trouble authenticating with the authority. Should include contact information such as a phone number or email. Each authority driver will have a set of configuration options dependent on the driver, such as host, port, etc. We will need to find a mechanism for the driver to tell us which configuration options are available, a way to set these, and a way for the driver to access these settings. OpenACS will come pre-configured with one authority, which is the "local" authority, meaning we'll authenticate as normal using the local users table. This will, just like any other authority, be implemetned using a service contract. Synchronizing and Linking Users Synchronizing and linking users EXT-AUTH-28 A Create service contract for Batch Sync. EXT-AUTH-38 A Batch User Synchronization API EXT-AUTH-38 A IMS Synchronization driver EXT-AUTH-08 A Automation of batch Synchronization EXT-AUTH-15 B On-demand syncronization Regardless of the login method, the user needs to have a row in the OpenACS users table. This can happen through a batch job, in real-time, or both in combination. We use the IMS Enterprise 1.1 specification. Batch job means that we do a synchronization (import new users, modify changed, purge deleted) on a regular interval, e.g. every night. You can also decide to have a monthly full synchronization, plus daily incremental ones. That's up to you. The advantage is that you have all users in OpenACS, so when you search for a user, you'll see all the organization's users, not just those who happen to have used the OpenACS-based system. The down-side is that it takes some time for user information to propagate. This can be remedied by using the real-time solution. The batch job will also require error logging and an admin interface to view logs. If an email already belongs to some other user, we log it as an error. A user will always belong to exactly one authority, which can be either the "local" authority or some other. Thus, the OpenACS user's table will have to be augmented with the following columns: Authority. Reference to the site-wide authorities list. The authority which can authenticate this user. Authority-specific username. Real-time means that the first time the user logs into OpenACS, we'll query the authority that authenticated him for information about this user. That authentication authority will then give us at least first names, last name and email. The pros and cons are the opposite of batch jobs. Using both in combination is ideal. Note: One solution to the "two users from different authorities have the same email" problem above would be to allow users to belong to multiple authorities. Then we would notice that the email already exists, ask the user if he thinks he's the same person, and if so, ask him to prove so by authenticating using the other authority. Thus he'll have just authenticated in two different authorities, and we can record that this is the same person. We'd still have a problem if there was an email conflict between two accounts on the same authority. Hm. I don't think it's worth spending too much time trying to solve this problem through software. EXT-AUTH-31 EXT-AUTH-31 A Upgrade user data model for ext-auth After having authenticated using the relevant authority driver, we'll look for the username/authority pair in the users table. If we don't find any, that means that we're either not doing batch synchronizing, or that the user has been added since the last sync. In that case, we'll try to do a real-time synchronization, if the driver supports it. If it does, it'll return email, first_names, last_name, and other relevant information, and we'll create a row in the local users table using that information. If that doesn't work, we'll tell the user that their account isn't yet available, and the driver will supply a message for us, which could say "The account should be available tomorrow. If not, contact X." Account Registration If a user doesn't have an account, the site-wide configuration can allow the user to register for one, as defined in the configuration discussed above. This section is about normal account registration through a authority driver. The account creation service contract implementation will need to tell us which information to ask the user for: Required Fields: A list of fields which are required. Optional Fields: A list of fields which are optional. The fields to choose from are these: Username First names Last name Email URL Password Secret question Secret answer It should return the following: Creation status (OK, Try-Again, Fail) Creation message: What went wrong, or a welcome message. Account status: Is the account ready for use? User information: first_names, last_name, email, url, password, password_hash, secret_question, secret_answer. The driver only needs to return the columns which were changed or added through the registration process. Typically, only the "local" driver will return password and secret question/answer. After creating the remote account, a local account is created with the information gathered through the form/returned by the driver. By default, a local account creation implementation is provided, which will create a new OpenACS user, and, in addition to the default local account creation above, also store the password in hashed form. Password Management Password management is about changing password, retrieving password, and resetting password. It's up to the authority driver implementation to decide whether to support any or all of these features, and to say so using the CanXXX methods (see driver API below). Additionally, the authority can be configured with a URL to redirect to in the case of forgotten passwords, or when the user desires to change password. Login Pages Over HTTPS EXT-AUTH-20 EXT-AUTH-20 A Login over HTTPS Login pages must be able to be sent over a secure connection (https), so your password won't get sent over the wire in cleartext, while leaving the rest of the site non-secure (http). I believe that this requires some (minor) changes to the current session handling code. Email Verification Email verification needs to be handled both at registration and at login. In both cases, it'll be handled by the driver sending automatically sending the email containing a link for the user to verify his account. Then the driver will return an account status of "closed,temporary", and a message that says "Check your inbox and click the link in the email". OpenACS will have a page which receives the email verification, for use by local accounts. Other authorities will have to implement their own page, most likely on the authority's own server. Other Items There are a number of items which touch on external authentication and session management. And even though they're not directly linked to external authentication, I would recommend that we handle a number of them, either because they're important for security, or because it makes sense to fix them while we're messing with this part of the codebase anyway. Recommended: Untrusted Logins and Login Levels EXT-AUTH-33 EXT-AUTH-33 A Untrusted Logins I like the idea of having multiple login levels: Not logged in Untrusted login: We'll show you un-sensitive personal content, but won't let you modify anything or see personal data. A normal login becomes untrusted after a certain amount of time, and the user will have to re-enter his/her password in order to gain access to personal data. Untrusted login never expires, unless explicitly done so through either changing password or clicking a special "expire all logins" link. Normal login: The user is logged, and has type his password sufficiently recently that we trust the login. All normal operations are allowed. Will degrade to untrusted login after a specified amount of time. Secure login: The user is logged in over a secure connection (HTTPS), potentially even using a special secure password. This would be for sensitive actions, such as credit card transactions. There are two advantages to this. First, when people's login expires, we can ask them to re-enter only their password, and not both username and password, since we'll still remember who they were the last time their login was valid. This is a much faster operation (the password input field will be focused by default, so you just type your password and hit Return) that typing both username and password, which will make it practical to have your site configured to expire people's login after e.g. 2, 4, or 8 hours. The other advantage is that we can still offer certain functionality to you, even when your login is not trusted. For example, we could let you browse publically available forums, and only when you want to post do you need to log in. This makes it even more feasible to have a more secure login expiration setting. By default, auth::require_login would bounce to the login page if the user is only logged in at the untrusted level. Only if you explicitly say auth::require_login -untrusted will we give you the user_id of a user who's only logged in in untrusted mode. Similarly, ad_conn user_id will continue to return 0 (not logged in) when the user is only logged in untrusted, and we'll supply another variable, ad_conn untrusted_user_id, which wlll be set to the user_id for all login levels. This should ensure that we get full access to the new feature, while leaving all current code just as secure as it was before. Recommended: Make Non-Persistent Login Work EXT-AUTH-34 EXT-AUTH-34 A Expire Logins Currently, OpenACS is unusable in practice without persistent login. The login will expire after just a few minutes of inactivity, and you'll get bounced to the login page where you have to enter both email and password again. Unacceptable in practice. We should change the default, so a non-persistent login doesn't expire until you either close your browser, or a few hours have elapsed. Even if you are constantly active, the login should still expire after at most x number of hours. We can still make the login expire after a period of inactivity, but the amount of time should be configurable and default to something reasonable like an hour or so. This will require looking into and changing the design of the current session handling code. Recommended: Single-Sign-On EXT-AUTH-23 EXT-AUTH-23 Single sign-on Instead of redirecting to the login page, auth::require_login can redirect to an authentication server, which can redirect back to a page that logs the user in. This should be very easy to implement. Alternatively, if you want to combine this with fallback to OpenACS accounts, we would instead present the normal login screen, but put a button which says "Login using X", where X is the redirection-based external authority. Recommended: Expire All Logins EXT-AUTH-22 EXT-AUTH-22 B rewrite cookie handling Currently, if you've ever left a permanent login cookie on someone elses machine, that person will be forever logged in until he/she explicitly logs out. You can change your password, you can do anything you want, but unless a logout is requested from that particular browser, that browser will be logged in forever. I want to change our session handling code so that old login cookies can be expired. This would be done automatically whenever you change your password, and we could also offer a link which does this without changing passwords. It's an important security measure. The implementation is simply to autogenerate some secret token which is stored in the users table, and is also stored in the cookie somehow. Then, whenever we want to expire all logins, we'll just regenerate a new secret token, and the other cookies will be void. Of course, we don't want to incur a DB hit on every request, so we'll need to cache the secret token, or only check it when refreshing the session cookie, which, I believe, normally happens every 10 minutes or so. Recommended: Email account owner on password change EXT-AUTH-24 EXT-AUTH-24 A Email on password change As an additional security measure, we should email the account's email address whenever the password is changed, so that he/she is at least alerted to the fact. Optional: Password policy EXT-AUTH-25 EXT-AUTH-25 A Implement password policy Again, to increase security, we should add password policies, such as passwords needing to be changed after a certain number of days, change on next login (after a new random password has been generated), or requiring that the password satisfies certain complexity rules, i.e. both upper and lowercase characters, numbers, special chars, etc. It would good to extend the current maximum password length from 10 to at least 32 characters. Optional: Login Without Explicit Authority EXT-AUTH-26 EXT-AUTH-26 B Login without explicit domain In order to make it easier for people, we've been toying with the idea of a functionality like this: If the user enters "foobar@ix.urz.uni-heidelberg.de", it is translated to mean username = "foobar", authority = "ix.urz.uni-heidelberg.de". If the user enters "foobar", it's recognized to not include any authority, and the default authority of "ix.urz.uni-heidelberg.de" is used. If the user enters "foo@bar.com", it's recognized as not belonging to any known authority, and as such, it's translated to mean username = "foo@bar.com", authority = "local". If this is deemed desirable, a way to implement this would be through these settings: Split: A regexp which will split the user's entry into username and authority parts. For example "^([^@]+)(@[^@]+)?$". An easier to use but less flexible method would be that you simply specify a certain character to split by, such as "@" or "\". If the regexp doesn't match, or in the latter case, if there's more than one occurrence of the specified character sequence, the split will fail, signaling that the user's entry was not valid. Default authority: The default authority will be the first one in the sort order. The relevant code in user-login.tcl would look like this: if { ![auth::split_username -username_var username -authority_var authority] } { # bounce back to the form with a message saying that the login wasn't valid. ad_script_abort } # username will now contain username # authority will now contain authority Optional: Who's Online EXT-AUTH-27 EXT-AUTH-27 B Who's online list While we're touching the session handling code, anyway, it would be nice to add a feature to show who's currently online, a nice real-time collaboration feature frequently requested by members of the community. This is particularly interesting when integrated with a chat or instant messaging service like Jabber. What I'm concretely suggesting is that we keep a record of which authenticated users have requested pags on the site in the last x minutes (typically about 5), and thus are considered to be currently online. There's nothing more to it. This lets us display a list of "active users" somewhere on the site, and make their name a link to a real-time chat service like Jabber. We've already made the changes necessary to security-procs.tcl to do this on an earlier project, but haven't quite finished the work and put it back into the tree. Optional: Subsite-level configuration EXT-AUTH-28 EXT-AUTH-28 implement subsite-level config If we want to, we could let subsite administrators configure the login process for that particular subsite. This would probably only entail letting the subsite admin leave out certain authorities defined site-wide, and change the sort order. I think we should leave this out until we have a use case for it, someone who'd need it. Future: Making the Authentication API itself a service contract EXT-AUTH-32 EXT-AUTH-32 A Parameters for Service Contract Implementation EXT-AUTH-35 A Make the Authentication API a service contract For completely free-form authentication logic and mechanisms, something like Andrew Grumet's Pluggable Authentication for OACS Draft is interesting. He's proposing a scheme where the entire user interaction is encapsulated in, and left entirely to, a service contract. This certainly opens up more advanced possibilities, such as perhaps smart cards, personal certificates, etc. I have chosen not to go this route, because I think that most people are going to want to use a username/password-based scheme, and having easy configuration through a web UI is more important than total flexibility at this point. Besides, we can always do this in the future, by letting the public Authentication API (auth::require_login and auth::authenticate) be implemented through a service contract. Future: Authenticating against multiple servers simultaneously EXT-AUTH-36 EXT-AUTH-36 A Authenticate against multiple servers Both OKI and OpenACS supports a form of stacking, where you can be logged into multiple authorities at the same time. This is useful if, for example, you need to get login tokens such as Kerberos tickets for access to shared resources. I can see the value in this, but for simplicity's sake, I'm in favor of keeping this use-case out of the loop until we have someone with a real requirement who could help us guide development. For now, OpenACS is still more of an integrated suite, it doesn't access many outside applications. I think it would be excellent for OpenACS to do so, e.g. by using an IMAP server to store emails, an iCal server to store calendar appointments, LDAP for user/group data and access control lists, SMB for file storage, etc. But at the moment, we don't have any users of such things that are ready. We have some who are on the steps, but let's wait till they're there. Implement Specific Drivers Implement specific drivers EXT-AUTH-09 A Create Auth. drivers for Local Authority EXT-AUTH-10 A Create Acct. Creation driver for Local Authority EXT-AUTH-11 A Create Auth. driver for PAM EXT-AUTH-12 X Create Acct. Creation driver for PAM - this functionality is explicitly excluded from PAM EXT-AUTH-13 A Create Acct. Creation driver for LDAP EXT-AUTH-14 A Create Auth. driver for LDAP We'll need drivers for: Operating system (Linux/Solaris) PAM: Delegate to the operating system, which can then talk to RADIUS, LDAP, whatever. This is convenient because there'll be plenty of drivers for the OS PAM level, so we don't have to write them all ourselves. The downside is that we can't do things like account creation, password management, real-time account synchronization, etc., not supported by PAM (I'm not entirely sure what is and is not supported). RADIUS LDAP RADIUS RADIUS is a simple username/password-type authentication server. It also supports sending a challenge to which the user must respond with the proper answer (e.g. mother's maiden name, or could be additional password), but we will not support this feature. A RADIUS client implementation in Python can be found in the exUserFolder module for Zope (documentation). Feedback We'd really appreciate feedback on this proposal. Please follow up at this openacs.org forums thread. References IMS Enterprise Threads and links collected by Carl Blesius. Solaris/Linux PAM specification Draft Proposal by Andrew Grumet. Yale CAS, a centrl authentication service a' la Passport. Revision History Document Revision # Action Taken, Notes When? By Whom? 1 Updated work-in-progress for consortium-sponsored ext-auth work at Collaboraid. 20 Aug 2003 Joel Aufrecht openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/apm-requirements.xml0000644000175000017500000012550211126246520026123 0ustar frankiefrankie %myvars; ]> Package Manager Requirements By Bryan Quinn and Todd Nightingale Introduction The following is a requirements document for the OpenACS Package Manager (APM), version 4.0 (APM4). APM4 offers a superset of APM v3.3 functionality with the following specific enhancements: A public procedural API. (v 3.3 only has web-based UI) Support for dependency checking. Support for compound packages (to support installation chaining). Support for on-line parameter setting. Support for sub-site level configuration (requires revised parameter and /admin pages at sub-site level; deprecation of site-wide parameter file). To differentiate these new requirements from the requirements of version 3.3, all requirements new in v4 are prefaced with the number 4. We gratefully acknowledge the authors of APM 3 for their original design documentation which suggested these features, as well as the influence of the design and open-source implementation of the Red Hat Package manager, the Debian packaging system, and PERL's CPAN in the development of the ideas behind this document. Vision Statement A typical website will tend to offer its users a number of web-based services or applications, e.g. a bulletin board, calendaring, classified ads, etc. A website may also have underlying subsystems, such as a permissions system, content management system, etc. For such applications and subsystem components, modularity - or the degree to which a component can be encapsulated and decoupled from the rest of the system - is of great value. Thus the OpenACS Package Manager (APM) was created to allow website components, or packages, to be added, removed, and upgraded easily, with minimum disturbance to the rest of the system. This allows site owners to steadily offer users new and improved services, and also allows programmers to quickly and easily distribute their OpenACS components in a standardized manner to other OpenACS sites. In general terms, a package is a unit of software that serves a single well-defined purpose. The OpenACS Package Manager (APM) provides a mechanism for packaging, installing, and configuring OpenACS software in a consistent, user-friendly, and subsite-aware manner. System Overview The OpenACS Package Manager (APM) consists of: A standard format for APM packages including: Version numbering, independent of any other package and the OpenACS as a whole Specification of the package interface Specification of dependencies on other packages (if any) Attribution (who wrote it) and ownership (who maintains it) Web-based tools for package management: Obtaining packages from a remote distribution point Installing packages, if and only if: All prerequisite packages are installed No conflicts will be created by the installation Configuring packages (obsoleting the monolithic OpenACS configuration file) Upgrading packages, without clobbering local modifications Uninstalling unwanted packages A registry of installed packages, database-backed and integrated with file system-based version control Web-based tools for package development: Creating new packages locally Releasing new versions of locally-created packages Uploading packages to a global package repository on the web Use of these tools should be safe, i.e. installing or removing a package should never break an OpenACS installation Web-based tools for package configuration: The ability to change package parameter values on-line through a simple web interface. A new ad_parameter which does not require a monolithic site-wide parameter's file or server restarts for changes to take effect. The ability to manage multiple package instances at the sub-site level. Use-cases and User-scenarios The APM is intended for the following classes of users, which may or may not overlap: Developers (referred to as 'the developer') use the APM to create a software package for distribution and use the procedural API for direct control of the APM system. Site-wide administrators (referred to as 'the administrator') use the APM to install packages for their OpenACS instance, and optionally make them available to sub-sites. Sub-site administrators (referred to as 'the sub-admin') use an administration interface to configure and enable packages for their sub-site. Initial Package Development David Developer writes a piece of software used to do knowledge management (km) for the OpenACS. He distributes his data model, procedure code, UI pages, and his documentation according to the APM specification. He splits the documentation and the code into sub-packages, and creates a KM installation-chain to install both with the APM developer UI. Noting that his software was built with Patricia Programmer's Super Widget toolkit, he specifies that as a dependency. Moreover, since this package is capable of being used at the sub-site level, David configures this option in the package. When the package development is complete, David uses the APM developer UI to construct a distribution file. He assigns it a version number, 1.0, and makes the package available for download at the OpenACS package repository. Initial Package Installation Annie Admin learns of David's KM system by browsing the OpenACS package repository. Annie Admin uses the APM administrator UI on her system. She selects to install a package from a URL and types the URL displayed on the system. The APM automatically downloads the package. The dependency checker notices that Patricia's Super Widget toolkit is required, so it warns Annie of this. Annie selects an option to find a package that satisfies the dependency at the OpenACS APM repository. The APM informs Annie that it can download and install Jim's Super Widget toolkit. Annie confirms this option. After successfully installing Jim's toolkit, Annie proceeds to install David's KM system. The data model is loaded and all of the files necessary for the software are installed. Because installation was successful, the package is available for use. Since the package is available for use, its initialization routines are set to run automatically on server startup. Annie is warned that since there are initialization routines, she must restart the server for the package to be ready for use. Annie restarts the server. Initial Subsite Use of Package Annie Admin decides to make the KM module available only to a particular sub-site type on her OpenACS system, and not others. She specifies this option using the Sub-site type UI (not part of APM). Annie Admin notifies Sally SubAdmin by e-mail that a new package is now available for use. Sally goes to her sub-site /admin page and sees that a new entry, KM, is available. Sally clicks on it and finds links to the installed KM documentation and to the web based configuration utility. Then, Sally configures the package using an automatically generated web interface and enables KM for use on her sub-site. After some initial use of the package, Sally decides to change some parameters using the SubAdmin UI. These changes take effect immediately, without any server restarts. Upgrade Process Sally SubAdmin finds a bug in the KM system and sends a report to David Developer. David reads the bug report and verifies that the bugs are present in the current version. Because the bugs are present in the shared procedure file, David assigns a watch to the file. David makes the necessary modifications to the source code and saves the file. Because a watch was assigned to the file, the APM automatically reloads the updated code. David tests the program and confirms that the bug is fixed. He increments the minor version number and makes km v 1.1 available for download at the repository. Sally SubAdmin asks Annie Administrator to upgrade the package using the APM UI. This upgrade supersedes the old version of KM at the site-wide level. Once Annie upgrades the package, the new version starts working immediately in Sally's sub-site. Procedural API Danielle Developer wants her software to perform different actions depending on what version of another package is installed. She uses the APM procedural API to check if KM version 1.0 is installed or version 1.1. Based on the results of this procedural call, the software exhibits different behavior. Related Links APM 3.3 Design document Five minute guide to packaging a module Sub-communities Requirements: Data Model 4.500.0 Package Identification (All of these items are entered by the developer using the developer UI.) 4.500.1 A human readable package key that is guaranteed to be unique to the local OpenACS site must be maintained by the APM. For example, "apm." 4.500.5 A package id (primary key) that is guaranteed to be unique to the local site must be maintained by the APM. For example, "25." 4.500.10 A package URL that is guaranteed to be unique across all sites must be maintained by the APM. The package URL should point to a server that allows download of the latest version of the package. For example, "http://openacs.org/software." 4.505.0 Version Identification (All of these items are entered by the developer using the developer UI.) 4.505.1 A version id (primary key) that is guaranteed to be unique to the local site must be maintained by the APM. 4.505.5 A version URL that is guaranteed to be unique across all sites must be maintained by the APM. The version URL should point to a server that allows download of a specific version of the package. Requirements: API The API for APM v3 is explicitly a private API. However, it would be useful to obtain information from the APM through a procedural API. Implementing the API specified below is quite easy given that there are pages that already do all of the below in raw SQL. 4.400.0 Packages Status Predicates 4.400.1 Given defining information such as a package URL, the APM API can return the status of the package on the local OpenACS instance. 4.405.0 Package Information Procedures 4.405.1 The APM API can return information for any locally installed packages, including the version number, paths and files, and package key. 4.410.0 Sub-site Procedures 4.410.1 After a package has been installed at the site-wide level, the system API will provide means to check for package presence, creation, enabling, disabling, and destruction on a subsite. 4.415.0 Parameter Values (replaces ad_parameter) 4.415.1 The system API shall allow subsite parameters for an installed package to be set by either site-wide administrators or sub-site admins. The subsite parameter can be set to be non-persistent (but default is to survive server restarts). The subsite parameter can also be set to only take effect after a server restart (default is immediate). 4.415.5 Parameters for a given subsite and package can be returned by the system API. Requirements: Security Provisions will be made to assure that packages are securely identified. 4.600.1 Each package will have a PGP signature and there will be MD5 time stamps for each file within the package. 4.600.5 The APM will provide a facility to validate both the PGP signature and MD5 stamps information before a package install. Requirements: The User Interface The user interface is a set of HTML pages that are used to drive the underlying API. It is restricted to site-wide administrators because the actions taken here can dramatically affect the state of the running OpenACS. Requirements: The Developer's Interface The intent of the developer's interface is to enable the developer to construct and maintain APM packages. It will be possible to disable the developer's interface for production sites to help reduce the chance of site failure; much of the functionality here can have cascading effects throughout the OpenACS and should not be used on a production site. 10.0 Define a package. The developer must be able to create a new package by specifying some identifying information for the package. This includes a package name, a package key, version information, owner information, and a canonical URL. 10.1 The APM must maintain the state of all locally generated packages. 10.50 If the developer fails to provide the required information, the package cannot be created. 10.55 All of the package information should be editable after creation, except for the package key. 4.10.60 The package creator must specify whether the package is capable of being used in sub-sites, or if only a single, global instance of the package is permitted. 4.10.65 If the developer fails to provide unique information for unique fields specified in the data model requirements, the package cannot be created. 20.0 Add files to a package 20.1 The developer must be able to add files to the package. This is done by copying the files into the package directory in the host OS's file system. Files can be added at any point after package creation. 20.3 Once a package has been versioned and distributed, no new files should be added to the package without incrementing the version number. 20.5 The APM's UI should facilitate the process of adding new files, by scanning the file system for new files automatically, and allowing the developer to confirm adding them. 20.10 The developer cannot add files to a given package via the UI that do not exist in the file system already. 20.15 Package file structure must follow a specified convention. Please see the design document for what we do currently. 30.0 Remove files from a package The developer must be able to remove files from a package. This can be done in two ways. 30.1 Access the APM UI, browse the file list, and remove files. 30.1.1If a file is removed from the package list, but not from the file system, an error should be generated at package load time. 30.5 Remove the file from file system. 30.5.1 The APM UI should take note of the fact that the file is gone and offer the developer an option to confirm the file's deletion. 40.0 Modify files in a package. 40.1 The developer should be able to modify files in the file system. The APM UI should not interfere with this. 40.5 However, if the developer modifies files containing procedural definitions, APM UI should allow a means to watch those files and automatically reload them if changed. See requirement 50.0 for more detail. 40.10 Also, although a change in files implies that the package distribution file is out of date, it is the developer's responsibility to update it. 4.45.0 Manage Package Dependency Information. 4.45.1 The developer should be able to specify which interfaces the package requires. 4.45.5 The developer should be able to specify which interfaces the package provides. 4.45.10 Circular dependencies are not allowed. 50.0 Watch a file 4.50.1 The developer should be able to assign a watch to any Tcl procedure file, whether in /packages or /tcl. 50.5 If a watched file is locally modified, then it will be automatically reloaded, thus allowing for any changes made to take affect immediately. 4.50.10 The setting of a watch should be persistent across server restarts. 60.0 Display an XML package specification 60.1 The developer should be able to view the XML package specification that encodes all package information. 70.0 Write an XML package specification to the file system 70.1 The developer should be able to write an up-to-date XML specification to disk. 70.5 The developer should be able to request the current XML specification for all installed, locally generated packages. 130.0 Distribution file generation 130.1 The developer should be able to generate a .APM distribution file for the package with just one click. 130.5 Generating a distribution file implies doing an "up-to-date" check on all of the files. If any of the files have changed since package installation, then a new version of the package is created. 140.0 Access CVS information 140.1 The developer should be able to determine the CVS status of a package, or all packages, with a single click. 4.400.0 Compound Package Construction 4.400.1 The developer can include .APM packages (sub-packages) within a package (the compound package) like any other file. 4.400.5 The recommended usage for this feature is to allow for separation of optional and required components from the installation as well as better organization of files once installed. For example, all documentation for the community-core can be packages as community-core-doc.apm. It is legal to include sub-packages with dependencies that are not satisfied by the packages in the compound package, but this is discouraged. In such a case, the sub-package should really be a separate package that is required by the compound package. 4.400.10 If a sub-package is required for the installation of the compound package, the compound package should have a registered dependency on the sub-package. Requirements: The Site-Wide Administrator's Interface The requirement of the administrator's interface is to enable the administrator to install, enable, upgrade, disable, deinstall, and delete packages. 80.0 Package Enable/Disable 4.80.1 The administrator should be able mark an installed package as enabled. This means that the package is activated and its functionality is delivered through the Request Processor. As of OpenACS 4, this is done through the sub-site system. 4.80.5 Moreover, the administrator must be able to disable a package, thereby removing the functionality provided to a sub-site. As of OpenACS 4, this is done through the sub-site system. 90.0 Package Install 90.1 The administrator must be able to install new packages either from locally maintained .APM files or from URLs. 90.5 In the case of an URL, the APM transparently downloads the APM file off the web, proceeds with a file based installation, and then optionally removes the .APM file just downloaded. 90.10.1 If .APM files are present in a package, then it is considered a compound package (use 4.410.0). 90.15.0 Installation requires these steps: 90.15.1The package dependencies are scanned. If some dependencies are not present, the system warns the administrator that installation cannot proceed until those packages are installed. 90.15.2 Assuming all dependencies are present, APM extracts the contents of the APM file into the /packages directory. 90.15.3 The administrator is offered the option of importing directly into CVS. 90.15.4 The administrator is given a list of data model scripts found in the package and can select which ones to be executed. 90.15.5 If no errors are recorded during this process, the package is enabled. 4.410.0 Compound package Install 4.410.1 If .APM files are present in a package, then it is considered a compound package. 4.410.5.0 Installation of a compound package proceeds according to the following sequence: 4.410.5.1 Identify the set of all sub-packages within the compound package by scanning for all files with .APM. 4.410.5.2 Identify which sub-packages are required by checking the dependencies of the compound package. If there dependencies not satisfied by the current system or the packages included with the compound package, halt installation and inform user to install these packages first. 4.410.5.3 Present Administrator with the ability to choose which sub-packages to install. Required sub-packages must be installed. 4.410.5.4 Proceed with the installation of each sub-package, starting with required packages. If the sub-package is already installed, then do nothing. Else, If the sub-package is a normal package, proceed according to 90.15.0, otherwise if it is a compound package, proceed according to 4.410.5.0. 4.410.5.5 If all required sub-packages are installed, proceed to install non-required sub-packages. If there was a failure during the installation of a required sub-package, then the installation of the compound package is also a failure. 4.410.5.6 Any attempt to install a compound package in the future involves a choice presented to the admin of installing any uninstalled sub-packages. 4.420.0 Recovering from failed package installation 4.420.1 If any error is generated during package installation, the package is not considered installed. To recover from this failure, the package should be selected for installation again. 100.0 Version Upgrade 100.1 The administrator can upgrade to a new version of a package. This entails 100.1.1 Running any necessary and included upgrade scripts. 100.1.5 Replacing any old files with new versions. 100.1.10 Marking the old version of the package as 'superseded' and disabling it. 100.1.15 Assuming no errors from above, the new package is enabled. 110.0 Package Deinstall 110.1 The administrator must be able to deinstall a package that has already been installed. Deinstallation entails: 110.1.1 Running any data model scripts necessary to drop the package. 110.1.5 Moving all of the files into a separate location in the file system from the installed packages. 4.110.1.10 If the package is a compound package, then the administrator must confirm removing all sub-packages. Optionally, some sub-packages can be kept. 110.5 Deinstalled packages can be re-installed at a later date. 4.110.10 If deinstalling a package or any of its sub-packages breaks a dependency, then deinstallation cannot proceed until the package registering the dependency is removed. 120.0 Package Deletion 120.1 The administrator should be able to completely erase all records of the package. This involves removing all instances of the package, all related database tables and content. 120.5 This option can only be used if all package instances are deleted or marked as disabled. This is purposefully cumbersome because deleting all instances of a package can have far-sweeping consequences throughout a site and should almost never be done. 150.0 Scan for new or modified packages 150.1 The administrator should be able to scan the file system for any changes made in any of the installed package files. 150.5 The administrator should be able to scan the file system for any newly installed packages. Requirements: The Sub-Site Administrator's Interface If the developer is in charge of creating packages and the administrator for installing them, then the sub-site administrator is responsible for configuring and enabling packages. In order for a package to be available for a sub-site it must be associated with the sub-site's type specification. This interface is part of the sub-site /admin interface. 4.300 Creating a package instance. 4.300.1 From the sub-site /admin interface, there should be an option to view all packages available in the system as well as an option to add a package to the subsite. 4.300.5 From the "add" option, the sub-admin can select from a list of packages registered as available in the sub-site type to which the sub-site belongs. 4.300.19 Once a package instance is added, it is available on the list of the subsite's available packages. 4.305 Configuring a package instance. 4.305.1 An automatic web interface that lists all parameters with current values must be available. 4.305.5 Changing the values for the parameters is accomplished simply by submitting an HTML form. 4.310 Enabling a package instance. 4.310.1 The sub-admin should be able to enable a package with a single click. Enabling a package means that the OpenACS will serve its URLs properly. 4.315 Disabling a package instance. 4.315.1 The sub-admin should be able to disable a package with a single click. Disabling a package means that the OpenACS will no longer serve those URLs. 4.320 Deleting a package instance. 4.320.1 Deleting a package instance involves deleting not only the package instance, but any and all content associated with it. It is questionable whether this option should even be available due to its drastic consequences. Reviewer comments appreciated. Implementation notes Despite the fact that requirements are meant to be design/implementation neutral, the following thoughts were in our head when specifying these requirements. You must be familiar with the new object design for this to be comprehensible. When a package is installed system-wide, a corresponding acs_object_type is created for it. All parameters registered for the package are registered for that acs_object_type. When a package instance is created, it is an acs_object. Its parameters are set using the acs_attribute_values table. The automatic web interface for setting package parameters should be one and the same with the interface for setting acs object attribute values. Consequently, the implementation of these features should be quite straightforward. Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 8/10/2000 Bryan Quinn, Todd Nightingale Reviewed 8/11/2000 John Prevost, Mark Thomas, and Pete Su 0.2 Revised and updated 8/12/2000 Bryan Quinn 0.3 Reviewed, revised, and updated - conforms to requirements template. 8/18/2000 Kai Wu 0.4 Minor edits before ACS 4 Beta. 9/30/2000 Kai Wu openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/security-design.xml0000644000175000017500000010112110456621136025737 0ustar frankiefrankie %myvars; ]> Security Design By Richard Li and Archit Shah Essentials Introduction This document explains security model design for OpenACS 4. The security system with the OpenACS core must authenticate users in both secure and insecure environments. In addition, this subsystem provides sessions on top of the stateless HTTP protocol. This system also provides session level properties as a generic service to the rest of the OpenACS. The atoms used in the implementation: Cookies: RFC 2109, HTTP State Management Mechanism Cookies provide client side state. They are used to identify the user. Expiration of cookies is used to demark the end of a session. SHA: SHA-1 This secure hash algorithm enables us to digitally sign cookies which guarantee that they have not been tampered with. It is also used to hash passwords. SSL with server authentication: SSL v3 SSL provides the client with a guarantee that the server is actually the server it is advertised as being. It also provides a secure transport. Design Sessions A session is defined as a series of clicks in which no two clicks are separated by more than some constant. This constant is the parameter SessionTimeout. Using the expiration time on the signatures of the signed cookies, we can verify when the cookie was issued and determine if two requests are part of the same session. It is important to note that the expiration time set in the cookie protocol is not trusted. Only the time inserted by the signed cookie mechanism is trusted. Authentication Two levels of access can be granted: insecure and secure. This grant lasts for the remainder of the particular session. Secure authentication tokens are only issued over secured connections. One consequence of this security design is that secure tokens are not automatically issued to users who authenticate themselves over insecure connections. This means that users will need to reauthenticate themselves over SSL when performing some action that requires secure authentication. Although this makes the site less user friendly, this design significantly increases the security of the system because this insures that the authentication tokens presented to a secure section of the web site were not sniffed. The system is not entirely secure, since the actual authentication password can be sniffed from the system, after which the sniffer can apply for a secure authentication token. However, the basic architecture here lays the foundation for a secure system and can be easily adapted to a more secure authentication system by forcing all logins to occur over HTTPS. Details The authentication system issues up to four signed cookies (see below), with each cookie serving a different purpose. These cookies are: name value max-age secure? ad_session_id session_id,user_id SessionTimeout no ad_user_login user_id Infinity no ad_user_login_secure user_id,random Infinity yes ad_secure_token session_id,user_id,random SessionLifetime yes ad_session_id reissued on any hit separated by more than SessionRenew seconds from the previous hit that received a cookie is valid only for SessionTimeout seconds is the canonical source for the session ID in ad_conn ad_user_login is used for permanent logins ad_user_login_secure is used for permanent secure logins contains random garbage (ns_time) to prevent attack against the secure hash ad_secure_token is a session-level cookie from the browser's standpoint its signature expires in SessionLifetime seconds contains random garbage (ns_time) to prevent attack against the secure hash user_id is extraneous Authentication Process The Tcl function (sec_handler) is called by the request processor to authenticate the user. It first checks the ad_session_id cookie. If there is no valid session in progress, a new session is created with sec_setup_session. If the user has permanent login cookies (ad_user_login and ad_user_login_secure), then they are looked at to determine what user the session should be authorized as. Which cookie is examined is determined by whether or not the request is on a secure connection. If neither cookie is present, then a session is created without any authentication. If the ad_session_id cookie is valid, the user_id and session_id are pulled from it and put into ad_conn. Authenticating Secure Connections Secure connections are authenticated slightly differently. The function ad_secure_conn_p is used to determine whether or not the URL being accessed is requires a secure login. The function simply checks if the location begins with "https". (This is safe because the location is set during the server initialization.) If secure authentication is required, the ad_secure_token cookie is checked to make sure its data matches the data stored in ad_session_id. This is true for all pages except those that are part of the login process. On these pages, the user can not yet have received the appropriate ad_secure_token cookie, so no check against it is performed. The set of pages that skip that processing are determined by determined by ad_login_page. Since the ad_secure_token cookie is a session cookie, it is deleted by the browser when the browser exits. Since an attacker could conceivably store the secure cookie in a replay attack (since expiration date is not validated), the data in the secure cookie is never used to set any data in ad_conn; user_id and session_id is set from the ad_session_id cookie. It is important to note that the integrity of secure authentication rests on the two Tcl function ad_secure_conn_p and ad_login_page. If ad_secure_conn_p is false, secure authentication is not required. If ad_login_page is false, secure authentication is not required. Login Process The Tcl function ad_user_login does two things. First it performs the appropriate manipulation of the permanent login cookies, and then it updates the current session to reflect the new user_id. The manipulation of the permanent login cookies is based on 3 factors: previous login: other user, same user permanent: was a permanent login requested? secure: is this a secure connection? Both the secure and insecure permanent login cookie can have one of three actions taken on it: set: cookie with no expiration is set delete: set to "" with max age of 0, so it is expired immediately nothing: if the cookie is present, it remains The current state of the permanent login cookies is not taken into account when determining the appropriate action. previous login state permanent login requested secure connection action on insecure action on secure other y y set set same y y set set other y n set delete same y n set nothing same n y nothing delete other n y delete delete other n n delete delete same n n delete delete ad_user_login callssec_setup_session which actually calls sec_generate_session_id_cookie to generate the new cookie with refer to the appropriate user_id. If the connection is secure the ad_secure_token cookie is generated by a call to sec_generate_secure_token_cookie. This function is only called from sec_setup_session. Only sec_handler and sec_setup_session call sec_generate_session_id_cookie. ad_user_logout logs the user out by deleting all 4 cookies that are used by the authentication system. Session Creation The creation and setup of sessions is handled in sec_setup_session, which is called either to create a new session from sec_handler or from ad_user_login when there is a change in authorization level. The session management code must do two things: insure that session-level data does not float between users, and update the users table which has columns for n_sessions, last_visit, and second_to_last_visit. If there is no session already setup on this hit, a new session is created. This happens when sec_setup_session is called from sec_handler. If the login is from a user to another user, a new session is created, otherwise, the current session is continued, simply with a higher authorization state. This allows for data associated with a session to be carried over when a user logs in. The users table is updated by sec_update_user_session_info which is called when an existing session is assigned a non-zero user_id, or when a session is created with a non-zero user_id. Passwords ad_user_login assumes a password check has already been performed (this will change in the future). The actual check is done by ad_check_password. The database stores a salt and a hash of the password concatenated with the salt. Updating the password (ad_change_password) simply requires getting a new salt (ns_time) concatenating and rehashing. Both the salt and the hashed password field are updated. Performance Enhancements A session is labeled by a session_id sequence. Creating a session merely requires incrementing the session_id sequence. We do two things to improve the performance of this process. First, sequence values are precomputed and cached in the Oracle SGA. In addition, sequence values are incremented by 100 with each call to nextval. These sequences values are cached on a per-thread basis. The cost of allocating a new session thus becomes the cost of executing an incr Tcl command per thread. This minimizes lock contention for the session ID sequence and also minimizes the number of DB requests, since each thread can allocate 100 sessions before requiring another DB hit. This cache works by keeping two counters: tcl_max_value and tcl_current_sequence_id. When tcl_current_sequence_id is greater than tcl_max_value a new value is requested from the db and tcl_max_value is incremented by 100. This is done on a per-thread basis so that no locking is required. In addition, two procedures are dynamically generated at startup in security-init.tcl. These two procedures use ad_parameter to obtain the constant value of a given parameter; these values are used to dynamically generate a procedure that returns a constant. This approach avoids (relatively) expensive calls to ad_parameter in sec_handler. The impact of this approach is that these parameters cannot be dynamically changed at runtime and require a server restart. Session Properties Session properties are stored in a single table that maps session IDs to named session properties and values. This table is periodically purged. For maximum performance, the table is created with nologging turned on and new extents are allocated in 50MB increments to reduce fragmentation. This table is swept periodically by sec_sweep_session which removes sessions whose first hit was more than SessionLifetime seconds (1 week by default) ago. Session properties are removed through that same process with cascading delete. Secure Session Properties Session properties can be set as secure. In this case, ad_set_client_property will fail if the connection is not secure. ad_get_client_property will behave as if the property had not been set if the property was not set securely. Digital Signatures & Signed Cookies Signed cookies are implemented using the generic secure digital signature mechanism. This mechanism guarantees that the user can not tamper with (or construct a value of his choice) without detection. In addition, it provides the optional facility of timing out the signature so it is valid for only a certain period of time. This works by simply including an expiration time as part of the value that is signed. The signature produced by ad_sign is the Tcl list of token_id,expire_time,hash, where hash = SHA1(value,token_id,expire_time,secret_token). The secret_token is a forty character randomly generated string that is never sent to any user agent. The scheme consists of one table: create table secret_tokens ( token_id integer constraint secret_tokens_token_id_pk primary key, token char(40), token_timestamp sysdate ); ad_verify_signature takes a value and a signature and verifies that the signature was generated using that value. It works simply by taking the token_id and expire_time from the signature, and regenerating the hash using the supplied value and the secret_token corresponding to the token_id. This regenerated hash is compared to the hash extracted from the supplied signature. The expire_time is also verified to be greater than the current time. An expire_time of 0 is also allowed, as it indicates no time out on the signature. Signed cookies include in their RFC2109 VALUE field a Tcl list of the value and the signature. In addition to the expiration of the digital signature, RFC 2109 specifies an optional max age that is returned to the client. For most cookies, this max age matches the expiration date of the cookie's signature. The standard specifies that when the max age is not included, the cookie should be "discarded when the user agent exits." Because we can not trust the client to do this, we must specify a timeout for the signature. The SessionLifetime parameter is used for this purpose, as it represents the maximum possible lifetime of a single session. RFC 2109 specifies this optional "secure" parameter which mandates that the user-agent use "secure means" to contact the server when transmitting the cookie. If a secure cookie is returned to the client over https, then the cookie will never be transmitted over insecure means. Performance Performance is a key goal of this implementation of signed cookies. To maximize performance, we will use the following architecture. At the lowest level, we will use the secret_tokens table as the canonical set of secret tokens. This table is necessary for multiple servers to maintain the same set of secret tokens. At server startup, a random subset of these secret tokens will be loaded into an ns_cache called secret_tokens. When a new signed cookie is requested, a random token_id is returned out of the entire set of cached token_ids. In addition, a thread-persistent cache called tcl_secret_tokens is maintained on a per-thread basis. Thus, the L2 ns_cache functions as a server-wide LRU cache that has a minimum of 100 tokens in it. The cache has a dual purpose: LRU cache Note that cache misses will only occur in the multiple server case, where a user agent may have a signature guaranteed by a secret token issued by another server in the cluster. signature cache Since the cache always maintains a minimum of 100 (set by a parameter) tokens populated at startup, it can be used to provide a random token for signature purposes. The per-thread cache functions as an L1 cache that indiscriminately caches all secret tokens. Note that this is not an LRU cache because there is no cache eviction policy per se -- the cache is cleared when the thread is destroyed by AOLserver. Security Storing information on a client always presents an additional security risk. Since we are only validating the information and not trying to protect it as a secret, we don't use salt. Cryptographic salt is useful if you are trying to protect information from being read (e.g., hashing passwords). External SSL External SSL mechanisms (firewall, dedicated hardware, etc.) can be used by creating two pools of AOLservers. In one pool the servers should be configured with the location parameter of nssock module set to "https://yourservername". The servers in the other pool are configured as normal. The external SSL agent should direct SSL queries to the pool of secure servers, and it should direct non-SSL queries to the insecure servers. PRNG The pseudorandom number generator depends primarily on ns_rand, but is also seeded with ns_time and the number of page requests served since the server was started. The PRNG takes the SHA1(seed,ns_rand,ns_time,requests,clicks), and saves the first 40 bits as the seed for the next call to the PRNG in a thread-persistent global variable. The remaining 120 bits are rehashed to produce 160 bits of output. API Login/Password ad_user_login user_id Logs the user in as user user_id. Optional forever flag determines whether or not permanent cookies are issued. ad_user_logout Logs the user out. ad_check_password user_id password returns 0 or 1. ad_change_password user_id new password Digital Signatures and Signed Cookies ad_sign value Returns the digital signature of this value. Optional parameters allow for the specification of the secret used, the token_id used and the max_age for the signature. ad_verify_signature value signatureReturns 1 or 0 indicating whether or not the signature matches the value specified. The secret parameter allows for specification of a different secret token to be used. ad_set_signed_cookie name data Sets a signed cookie name with value data. ad_get_signed_cookie name Gets the signed cookie name. It raises an error if the cookie has been tampered with, or if its expiration time has passed. Session Properties ad_set_client_property module name data Sets a session property with name to value data for the module module. The optional secure flag specifies the property should only be set if the client is authorized for secure access (ad_secure_conn_p is true). There is also an optional session_id flag to access data from sessions other than the current one. ad_get_client_property module name data Gets a session property with name to for the module module. The optional secure flag specifies the property should only be retrieved if the client is authorized for secure access (ad_secure_conn_p is true). There is also an optional session_id flag to access data from sessions other than the current one. Parameters SessionTimeout the maximum time in seconds (default 1200) between requests that are part of the same session SessionRenew the time in seconds (default 300) between reissue of the session cookie. The minimum time that can pass after a session cookie is issued and before it is rejected is (SessionTimeout - SessionRenew). This parameter is used so that only one session_id cookie is set on a single page even if there are multiple images that are being downloaded. SessionLifetime the maximum possible lifetime of a session in seconds (default 604800 = 7 days) NumberOfCachedSecretTokens the number of secret tokens to cache. (default 100) Future Improvements PRNG implementation The pseudorandom number generator used in the OpenACS is cryptographically weak, and depends primarily on the randomness of the ns_rand function for its randomness. The implementation of the PRNG could be substantially improved. <computeroutput>ad_user_login</computeroutput> Add a password argument. It is non-optimal to make the default behavior to assume that the password was provided. Secret Tokens The secret tokens pool is currently static. Ideally, this pool should be changed on a random but regular basis, and the number of secret_tokens increased as the number of users come to the web site. Since the security of the entire system depends on the secret tokens pool, access to the secret tokens table should be restricted and accessible via a strict PL/SQL API. This can be done by revoking standard SQL permissions on the table for the AOLserver user and giving those permissions to a PL/SQL package. Robots Deferring session to creation until the second hit from a browser seems to be a good way of preventing a lot of overhead processing for robots. If we do this, send cookie on first hit to test if cookies are accepted, then actually allocate on second hit. To preserve a record of the first hit of the session, just include any info about that first hit in the probe cookie sent. Look at how usca_p (user session cookie attempted) is used in OpenACS 3.x ecommerce. Client properties Currently there are only session properties. Because sessions have a maximum life, properties have a maximum life. It would be nice to expand the interface to allow for more persistent properties. In the past, there was a sec_browser_properties table that held permanent properties about each unique visitor (for logged in users, these are just user properties). This was unscalable because there was no way to delete these properties, and the table tended to grow to millions of rows. It would be nice to view browser and session properties as two types of client properties, but with different deletion patterns (there are other differences as well, browser properties can be shared between concurrent sessions). The applications should have control over the deletion patterns, but should not be able to ignore the amount of data stored. Session information It would be nice to keep some info about sessions: first hit, last hit, and URLs visited come to mind. Both logging and API for accessing this info would be nice. WimpyPoint is an application that already wants to use this information to show how long the current presentation has been viewed. The right way may be to put the session_id into the access log and use log analyzers (leaving it in server memory for applications to access). Putting it into the database at all is probably too big a hammer. Certainly putting it into the database on every hit is too big a hammer. Cookieless Sessions Two trends drive the requirement for removing cookie dependence. WAP browsers that do not have cookies, and publc perceptions of cookies as an invasion of privacy. The rely on the cookies mechanism in HTTP to distinguish one request from the next, and we trust it to force requests from the same client to carry the same cookie headers. The same thing can be accomplished by personalizing the URLs sent back to each browser. If we can store an identifier in the URL and get it back on the next hit, the sessions system would continue to work. Problems that arise: URL sharing could be dangerous. If I happen to be browsing Amazon while logged in and I email a friend, he could conceivably receive it and follow it before my session has expired, gaining all of the privileges I had. User-entered URLs are harder to handler. If a user is in the middle of a session and then types in the URL of some page, he could be kicked out of his session. Both of these problems can be mitigated by doing detection of cookie support (see the section on robot detection). To help deal with the first problem, One could also make the restriction that secure sessions are only allowed over cookied HTTP. Vulnerability Analysis This section is not meant to be a comprehensive analysis of the vulnerabilities of the security system. Listed below are possible attack points for the system; these vulnerabilities are currently theoretical in nature. The major cryptographic vulnerability of the system stems from the pseudorandom nature of the random number generators used in the system. Cryptographically weak PRNG see above. Dependence on sample SQL command The list of random token that are placed in the secret tokens cache is randomly chosen by the Oracle sample command. This command may not be entirely random, so predicting the contents of the secret tokens cache may not be as difficult as someone may anticipate. Dependence on ns_rand The actual token that is chosen from the cache to be used is chosen by a call to ns_rand. ad_secure_conn_p As discussed above, the security of the secure sessions authentication system is dependent upon this function. openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/rp-requirements.xml0000644000175000017500000000770310456621136025776 0ustar frankiefrankie %myvars; ]> Request Processor Requirements By Rafael H. Schloming Introduction The following is a requirements document for the OpenACS 4.0 request processor. The major enhancements in the 4.0 version include a more sophisticated directory mapping system that allows package pageroots to be mounted at arbitrary urls, and tighter integration with the database to allow for flexible user controlled url structures, and subsites. Vision Statement Most web servers are designed to serve pages from exactly one static pageroot. This restriction can become cumbersome when trying to build a web toolkit full of reusable and reconfigurable components. System Overview The request processor's functionality can be split into two main pieces. Set up the environment in which a server side script expects to run. This includes things like: Initialize common variables associated with a request. Authenticate the connecting party. Check that the connecting party is authorized to proceed with the request. Invoke any filters associated with the request URI. Determine to which entity the request URI maps, and deliver the content provided by this entity. If this entity is a proc, then it is invoked. If this entitty is a file then this step involves determining the file type, and the manner in which the file must be processed to produce content appropriate for the connecting party. Eventually this may also require determining the capabilities of the connecting browser and choosing the most appropriate form for the delivered content. It is essential that any errors that occur during the above steps be reported to developers in an easily decipherable manner. Related Links Requirements 10.0 Multiple Pageroots
    10.10 Pageroots may be combined into one URL space. 10.20 Pageroots may be mounted at more than one location in the URL space.
    20.0 Application Context
    20.10 The request processor must be able to determine a primary context or state associated with a pageroot based on it's location within the URL space.
    30.0 Authentication
    30.10 The request processor must be able to verify that the connecting browser actually represents the party it claims to represent.
    40.0 Authorization
    40.10 The request processor must be able to verify that the party the connecting browser represents is allowed to make the request.
    50.0 Scalability
    openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/security-notes.xml0000644000175000017500000000654010456621136025627 0ustar frankiefrankie %myvars; ]> Security Notes By Richard Li The security system was designed for security. Thus, decisions requiring trade-offs between ease-of-use and security tend to result in a system that may not be as easy to use but is more secure. HTTPS and the sessions system If a user switches to HTTPS after logging into the system via HTTP, the user must obtain a secure token. To insure security, the only way to obtain a secure token in the security system is to authenticate yourself via password over an HTTPS connection. Thus, users may need to log on again to a system when switching from HTTP to HTTPS. Note that logging on to a system via HTTPS gives the user both insecure and secure authentication tokens, so switching from HTTPS to HTTP does not require reauthentication. This method of authentication is important in order to establish, in as strong a manner as possible, the identity of the owner of the secure token. In order for the security system to offer stronger guarantees of someone who issues a secure token, the method of authentication must be as strong as the method of transmission. If a developer truly does not want such a level of protection, this system can be disabled via source code modification only. This can be accomplished by commenting out the following lines in the sec_handler procedure defined in security-procs.tcl: if { [ad_secure_conn_p] && ![ad_login_page] } { set s_token_cookie [ns_urldecode [ad_get_cookie "ad_secure_token"]] if { [empty_string_p $s_token_cookie] || [string compare $s_token_cookie [lindex [sec_get_session_info $session_id] 2]] != 0 } { # token is incorrect or nonexistent, so we force relogin. ad_returnredirect "/register/index?return_url=[ns_urlencode [ad_conn url]?[ad_conn query]]" } } The source code must also be edited if the user login pages have been moved out of an OpenACS system. This information is contained by the ad_login_page procedure in security-procs.tcl: ad_proc -private ad_login_page {} { Returns 1 if the page is used for logging in, 0 otherwise. } { set url [ad_conn url] if { [string match "*register/*" $url] || [string match "/index*" $url] } { return 1 } return 0 } The set of string match expressions in the procedure above should be extended appropriately for other registration pages. This procedure does not use ad_parameter or regular expressions for performance reasons, as it is called by the request processor. ($Id: security-notes.xml,v 1.6 2006/07/17 05:38:38 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/subsites-requirements.xml0000644000175000017500000001735411126246520027214 0ustar frankiefrankie %myvars; ]> Subsites Requirements By Rafael H. Schloming and Dennis Gregorovic Introduction The following is a requirements document for OpenACS 4 Subsites, part of the OpenACS 4 Kernel. The Subsites system allows one OpenACS server instance to serve multiple user communities, by enabling the suite of available OpenACS applications to be customized for defined user communities. Vision Statement Many online communities are also collections of discrete subcommunities, reflecting real-world relationships. For example, a corporate intranet/extranet website serves both units within the company (e.g., offices, departments, teams, projects) and external parties (e.g., customers, partners, vendors). Subsites enable a single OpenACS instance to provide each subcommunity with its own "virtual website," by assembling OpenACS packages that together deliver a feature set tailored to the needs of the subcommunity. System Overview The OpenACS subsite system allows a single OpenACS installation to serve multiple communities. At an implementation level this is primarily accomplished by having an application "scope" its content to a particular package instance. The request processor then figures out which package_id a particular URL references and then provides this information through the ad_conn api ([ad_conn package_id], [ad_conn package_url]). The other piece of the subsite system is a subsite package that provides subsite admins a "control panel" for administering their subsite. This is the same package used to provide all the community core functionality available at the "main" site which is in fact simply another subsite. Use-cases and User-scenarios The Subsites functionality is intended for use by two different classes of users: Package programmers (referred to as 'the programmer') must develop subcommunity-aware applications. Site administrators (referred to as 'the administrator') use subsites to provide tailored "virtual websites" to different subcommunities. Joe Programmer is working on the forum package and wants to make it subsite-aware. Using [ad_conn package_id], Joe adds code that only displays forum messages associated with the current package instance. Joe is happy to realize that parameter::get is already smart enough to return configuration parameters for the current package instance, and so he has to do no extra work to tailor configuration parameters to the current subsite. Jane Admin maintains www.company.com. She learns of Joe's work and would like to set up individual forums for the Boston and Austin offices of her company. The first thing she does is use the APM to install the new forum package. Next, Jane uses the Subsite UI to create subsites for the Boston and Austin offices. Then Jane uses the Subsite UI to create forums for each office. Now, the Boston office employees have their own forum at http://www.company.com/offices/boston/forum, and similarly for the Austin office. At this point, the Boston and Austin office admins can customize the configurations for each of their forums, or they can just use the defaults. Related Links Test plan (Not available yet) Requirements: Programmer's API A subsite API is required for programmers to ensure their packages are subsite-aware. The following functions should be sufficient for this: 10.10.0 Package creation The system must provide an API call to create a package, and it must be possible for the context (to which the package belongs) to be specified. 10.20.0 Package deletion The system must provide an API call to delete a package and all related objects in the subsite's context. 10.30.0 Object's package information Given an object ID, the system must provide an API call to determine the package (ID) to which the object belongs. 10.40.0 URL from package Given a package (ID), the system must provide an API call to return the canonical URL for that package. 10.50.0 Main subsite's package_id The system must provide an API call to return a package ID corresponding to the main subsite's package ID (the degenerate subsite). Requirements: The User Interface The Programmer's User Interface There is no programmer's UI, other than the API described above. The Administrator's User Interface The UI for administrators is a set of HTML pages that are used to drive the underlying API for package instance management (i.e. adding, removing, or altering packages). It is restricted to administrators of the current subsite such that administrators can only manage their own subsites. Of course, Site-Wide Administrators can manage all subsites. 20.10.0 Package creation 20.10.1 The administrator should be able to create a package and make it available at a URL underneath the subsite. 20.20.0 Package deactivation 20.20.1 The administrator should be able to deactivate any package, causing it to be inaccessible to users. 20.20.5 Deactivating a package makes the package no longer accessible, but it does not remove data created within the context of that package. Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 08/18/2000 Dennis Gregorovic 0.2 Edited, reviewed 08/29/2000 Kai Wu openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/apm-design.xml0000644000175000017500000011624711501005400024642 0ustar frankiefrankie %myvars; ]> Package Manager Design By Bryan Quinn Essentials OpenACS Administrator directory ER diagram Tcl API apm-procs.tcl apm-install-procs.tcl (Supports installation of packages) 20-apm-load-procs.tcl (Bootstraps APM for server startup) apm-admin-procs.tcl (Supports APM UI) PL/SQL file apm-create.sql Introduction In general terms, a package is a unit of software that serves a single well-defined purpose. That purpose may be to provide a service directly to one or more classes of end-user, (e.g., discussion forums and file storage for community members, user profiling tools for the site publisher), or it may be to act as a building block for other packages (e.g., an application programming interface (API) for storing and querying access control rules, or an API for scheduling email alerts). Thus, packages fall into one of two categories: OpenACS Applications: a "program or group of programs designed for end users" (the Webopedia definition); also known as modules, for historical reasons. Examples of applications include Forums and News. OpenACS Services: the aforementioned building blocks. Examples of services include the OpenACS Content Repository, the OpenACS Templating System, and the OpenACS Kernel, which includes APM. An installation of the OpenACS includes the OpenACS Kernel, some services that extend the kernel's functionality, and some applications intended for end-users. Packages function as individual pieces of subsites. A subsite can contain multiple application and service instances that provide the end-user with capabilities and content customized to the particular subsite. This architecture supports the growth of collaborative commerce. For example, Jane User starts a forum focusing on the merits of View Cameras by creating an instance of the Forum application for her personal subsite on an OpenACS Installation. Jack User discovers Jane's forum and includes a link to it in his subsite. As interest in Jane's forum grows, she creates a subsite specializing in providing information about View cameras. This subsite now includes several package instances beyond Forum; it could potentially include its own Ecommerce capabilities (ala Yahoo! Shopping). This could include a knowledge management application that allows users to spread expertise about view cameras and a portal application that links to reliable camera models and resellers. Any subsite enabled package that is added to the OpenACS installation through APM is another potential package instance that can become part of Jane's View Camera subsite. The APM provides an architecture for packaging software, making instances of that software available to subsites, specifying configuration parameters for each instance, and managing the creation and release of new packages. Historical Considerations Prior to ACS 3.3, all packages were lumped together into one monolithic distribution without explicit boundaries; the only way to ascertain what comprised a given package was to look at the top of the corresponding documentation page, where, by convention, the package developer would specify where to find: the data model the Tcl procedures the user-accessible pages the administration pages Experience has shown us that this lack of explicit boundaries causes a number of maintainability problems for pre-3.3 installations: Package interfaces were not guaranteed to be stable in any formal way, so a change in the interface of one package would often break dependent packages (which we would only discover through manual regression testing). In this context, any of the following could constitute an interface change: renaming a file or directory that appears in a URL changing what form variables are expected as input by a page changing a procedural abstraction, e.g., a PL/SQL or Java stored procedure or a Tcl procedure changing a functional abstraction, e.g., a database view or a PL/SQL or Java stored function changing the data model This last point is especially important. In most cases, changing the data model should not affect dependent packages. Rather, the package interface should provide a level of abstraction above the data model (as well as the rest of the package implementation). Then, users of the package can take advantage of implementation improvements that don't affect the interface (e.g., faster performance from intelligent denormalization of the data model), without having to worry that code outside the package will now break. A typical ACS-backed site only uses a few of the modules included in the distribution, yet there was no well-understood way to pick only what you needed when installing the ACS, or even to uninstall what you didn't need, post-installation. Unwanted code had to be removed manually. Releasing a new version of the ACS was complicated, owing again to the monolithic nature of the software. Since we released everything in the ACS together, all threads of ACS development had to converge on a single deadline, after which we would undertake a focused QA effort whose scale increased in direct proportion to the expansion of the ACS codebase. There was no standard way for developers outside of ArsDigita to extend the ACS with their own packages. Along the same lines, ArsDigita programmers working on client projects had no standard way to keep custom development cleanly separated from ACS code. Consequently, upgrading an already installed ACS was an error-prone and time-consuming process. Consistent use of the APM format and tools will go a long way toward solving the maintainability problems listed above. Moreover, APM is the substrate that will enable us to establish a central package repository, where developers will be able publish their packages for other OpenACS users to download and install. For a simple illustration of the difference between ACS without APM (pre-3.3) and ACS with APM (3.3 and beyond), consider a hypothetical ACS installation that uses only two of the thirty-odd modules available circa ACS 3.2 (say, bboard and e-commerce): APM itself is part of a package, the OpenACS Kernel, an OpenACS service that is the only mandatory component of an OpenACS installation. Competitive Analysis The OpenACS is a platform for web-based application software, and any software platform has the potential to develop problems like those described above. Fortunately, there are many precedents for systematic solutions, including: Debian GNU/Linux and the Debian Packaging manual FreeBSD has the Ports collection Red Hat Linux has the Red Hat Package Manager (RPM) Borrowing from all of the above, OpenACS 3.3 introduces its own package management system, the OpenACS Package Manager (APM), which consists of: a standard format for APM packages (also called "OpenACS packages"), including: version numbering, independent of any other package and the OpenACS as a whole specification of the package interface specification of dependencies on other packages (if any) attribution (who wrote it) and ownership (who maintains it) web-based tools for package management: obtaining packages from a remote distribution point installing packages, if and only if: all prerequisite packages are installed no conflicts will be created by the installation configuring packages (obsoleting the monolithic OpenACS configuration file) upgrading packages, without clobbering local modifications uninstalling unwanted packages a registry of installed packages, database-backed and integrated with filesystem-based version control web-based tools for package development: creating new packages locally releasing new versions of locally-created packages Design Tradeoffs The design chosen for APM was meant to satisfy the following constraints: The process of authoring a package must be as simple as possible. Strict conventions must be established that provide a set of canonical locations and names for files and patterns, for OpenACS application development. The processes of installing, upgrading, and using packages must be straightforward and accessible through a web-based UI. Package instances must be able to have subsite-specific content available at an easily configurable URL. All of these requirements were met, but at the cost of development simplicity. As demonstrates, a set of strict directory conventions are required in order for a package to use APM. This contrasts with the apparent simplicity available to developers of the OpenACS 3.3 system. However, while the system has become more complex for developers to build packages, this complexity is easily managed and is compensated for by additional capabilities. For example, to make a new application available to the system, a developer must: Create the necessary files to support the data model, Tcl API, and UI pages. Put the files in the correct locations for APM to be aware of them. Use APM to create a new package and enable it. Use the Site Map facility to create an instance of the package, mount it on an appropriate URL, and set parameters for that particular instance. While this is complex, especially to a new OpenACS developer, the documentation walks the developer through each of these steps. Moreover, from following these steps, the package can be subsite specific, available to subsites across the system, and be available for distribution to other OpenACS installations without doing a monolithic upgrade or reinstall. API The APM is composed of systems for accomplishing a set of package-related tasks. Each of these tasks comprise a feature area that has an API, data model, and a UI: Authoring a Package Maintaining Multiple Versions of a Package Creating Instances of the Package Specifying Configuration Parameters for each Instance Authoring a Package Full instructions on how to prepare an OpenACS package are available in . The API here can be invoked manually by a package's data model creation script, but need not to be used. This API is part of the APM PL/SQL package. -- Informs the APM that this application is available for use. procedure register_application ( package_key in apm_package_types.package_key%TYPE, pretty_name in apm_package_types.pretty_name%TYPE, pretty_plural in apm_package_types.pretty_plural%TYPE, package_uri in apm_package_types.package_uri%TYPE, singleton_p in apm_package_types.singleton_p%TYPE default 'f', spec_file_path in apm_package_types.spec_file_path%TYPE default null, spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null ); The procedure above registers an OpenACS application in the APM. It creates a new OpenACS object and stores information about the package, such as its name, in the APM data model. There is an analogous procedure for OpenACS services, called apm.register_service. To remove an application from the system, there are the calls apm.unregister_application and apm.unregister_service. -- Remove the application from the system. procedure unregister_application ( package_key in apm_package_types.package_key%TYPE, -- Delete all objects associated with this application. cascade_p in char default 'f' ); Use the cascade_p only if you want to completely remove the package from the OpenACS. In order to determine if a particular package exists in the system, use the register_p predicate. It returns 1 if the specified package_key exists in the system, 0 otherwise. function register_p ( package_key in apm_package_types.package_key%TYPE ) return integer; Maintaining Multiple Versions of a Package While the package authoring API provides a means for registering a package, some information about a package is version dependent. For example, between versions, the owner of a package, its vendor, its URI, and its dependency information may change. The API for package versions allows this information to be specified. All of these APIs are part of the apm_package_version PL/SQL package. To create a new package version, use the apm_package_version.new constructor function. function new ( version_id in apm_package_versions.version_id%TYPE default null, package_key in apm_package_versions.package_key%TYPE, version_name in apm_package_versions.version_name%TYPE default null, version_uri in apm_package_versions.version_uri%TYPE, summary in apm_package_versions.summary%TYPE, description_format in apm_package_versions.description_format%TYPE, description in apm_package_versions.description%TYPE, release_date in apm_package_versions.release_date%TYPE, vendor in apm_package_versions.vendor%TYPE, vendor_uri in apm_package_versions.vendor_uri%TYPE, installed_p in apm_package_versions.installed_p%TYPE default 'f', data_model_loaded_p in apm_package_versions.data_model_loaded_p%TYPE default 'f' ) return apm_package_versions.version_id%TYPE; In order to use this function, an existing package_key must be specified. The version_name parameter must follow a strict convention: A major version number at least one minor version number. Although any number of minor version numbers may be included, three minor version numbers is sufficient and is the convention of software developers. One of the following: The letter d, indicating a development-only version The letter a, indicating an alpha release The letter b, indicating a beta release No letter at all, indicating a final production release In addition, the letters d, a, and b may be followed by another integer, indicating a version within the release. For those who like regular expressions: version_number := ^[0-9]+((\.[0-9]+)+((d|a|b|)[0-9]?)?)$ So the following is a valid progression for version numbers:
    0.9d, 0.9d1, 0.9a1, 0.9b1, 0.9b2, 0.9, 1.0, 1.0.1, 1.1b1, 1.1
    To delete a given version of a package, use the apm_package_version.delete procedure: procedure delete ( package_id in apm_packages.package_id%TYPE ); After creating a version, it is possible to edit the information associated with it using apm_package_version.edit. function edit ( new_version_id in apm_package_versions.version_id%TYPE default null, version_id in apm_package_versions.version_id%TYPE, version_name in apm_package_versions.version_name%TYPE default null, version_uri in apm_package_versions.version_uri%TYPE, summary in apm_package_versions.summary%TYPE, description_format in apm_package_versions.description_format%TYPE, description in apm_package_versions.description%TYPE, release_date in apm_package_versions.release_date%TYPE, vendor in apm_package_versions.vendor%TYPE, vendor_uri in apm_package_versions.vendor_uri%TYPE, installed_p in apm_package_versions.installed_p%TYPE default 'f', data_model_loaded_p in apm_package_versions.data_model_loaded_p%TYPE default 'f' ) return apm_package_versions.version_id%TYPE; Versions can be enabled or disabled. Enabling a version instructs APM to source the package's libraries on startup and to make the package available to the OpenACS. procedure enable ( version_id in apm_package_versions.version_id%TYPE ); procedure disable ( version_id in apm_package_versions.version_id%TYPE ); Files associated with a version can be added and removed. The path is relative to the package-root which is acs-server-root/packages/package-key. -- Add a file to the indicated version. function add_file( file_id in apm_package_files.file_id%TYPE default null, version_id in apm_package_versions.version_id%TYPE, path in apm_package_files.path%TYPE, file_type in apm_package_file_types.file_type_key%TYPE ) return apm_package_files.file_id%TYPE; -- Remove a file from the indicated version. procedure remove_file( version_id in apm_package_versions.version_id%TYPE, path in apm_package_files.path%TYPE ); Package versions need to indicate that they provide interfaces for other software. An interface is an API that other packages can access and utilize. Interfaces are identified as a URI and a version name, that comply with the specification of a version name for package URIs. -- Add an interface provided by this version. function add_interface( interface_id in apm_package_dependencies.dependency_id%TYPE default null, version_id in apm_package_versions.version_id%TYPE, interface_uri in apm_package_dependencies.service_uri%TYPE, interface_version in apm_package_dependencies.service_version%TYPE ) return apm_package_dependencies.dependency_id%TYPE; procedure remove_interface( interface_id in apm_package_dependencies.dependency_id%TYPE, version_id in apm_package_versions.version_id%TYPE ); procedure remove_interface( interface_uri in apm_package_dependencies.service_uri%TYPE, interface_version in apm_package_dependencies.service_version%TYPE, version_id in apm_package_versions.version_id%TYPE ); The primary use of interfaces is for other packages to specify required interfaces, known as dependencies. A package cannot be correctly installed unless all of its dependencies have been satisfied. -- Add a requirement for this version. A requirement is some interface that this -- version depends on. function add_dependency( requirement_id in apm_package_dependencies.dependency_id%TYPE default null, version_id in apm_package_versions.version_id%TYPE, requirement_uri in apm_package_dependencies.service_uri%TYPE, requirement_version in apm_package_dependencies.service_version%TYPE ) return apm_package_dependencies.dependency_id%TYPE; procedure remove_dependency( requirement_id in apm_package_dependencies.dependency_id%TYPE, version_id in apm_package_versions.version_id%TYPE ); procedure remove_dependency( requirement_uri in apm_package_dependencies.service_uri%TYPE, requirement_version in apm_package_dependencies.service_version%TYPE, version_id in apm_package_versions.version_id%TYPE ); As new versions of packages are created, it is necessary to compare their version names. These two functions assist in that task. -- Given a version_name (e.g. 3.2a), return -- something that can be lexicographically sorted. function sortable_version_name ( version_name in apm_package_versions.version_name%TYPE ) return varchar; -- Given two version names, return 1 if one > two, -1 if two > one, 0 otherwise. -- Deprecate? function compare( version_name_one in apm_package_versions.version_name%TYPE, version_name_two in apm_package_versions.version_name%TYPE ) return integer; Creating Instances of a Package Once a package is registered in the system, it is possible to create instances of it. Each instance can maintain its own content and parameters. create or replace package apm_application as function new ( application_id in acs_objects.object_id%TYPE default null, instance_name in apm_packages.instance_name%TYPE default null, package_key in apm_package_types.package_key%TYPE, object_type in acs_objects.object_type%TYPE default 'apm_application', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return acs_objects.object_id%TYPE; procedure delete ( application_id in acs_objects.object_id%TYPE ); end apm_application; Just creating a package instance is not sufficient for it to be served from the web server. A corresponding site node must be created for it. As an example, here is how the OpenACS API Documentation service makes itself available on the OpenACS main site: declare api_doc_id integer; begin api_doc_id := apm_service.new ( instance_name => 'OpenACS API Browser', package_key => 'acs-api-browser', context_id => main_site_id ); apm_package.enable(api_doc_id); api_doc_id := site_node.new ( parent_id => site_node.node_id('/'), name => 'api-doc', directory_p => 't', pattern_p => 't', object_id => api_doc_id ); commit; end; / show errors Specifying Configuration Parameters for each Instance A parameter is a setting that can be changed on a package instance basis. Parameters are registered on each package_key, and the values are associated with each instance. Parameters can have default values and can be of type 'string' or 'number.' There is support with this API for setting a number of minimum and maximum values for each parameter, but for most instances, the minimum and maximum should be 1. It is useful to allow or require multiple values for packages that need to store multiple pieces of information under one parameter. Default values are automatically set when instances are created, but can be changed for each instance. All of the functions below are in the APM PL/SQL package. -- Indicate to APM that a parameter is available to the system. function register_parameter ( parameter_id in apm_parameters.parameter_id%TYPE default null, parameter_name in apm_parameters.parameter_name%TYPE, description in apm_parameters.description%TYPE default null, package_key in apm_parameters.package_key%TYPE, datatype in apm_parameters.datatype%TYPE default 'string', default_value in apm_parameters.default_value%TYPE default null, section_name in apm_parameters.section_name%TYPE default null, min_n_values in apm_parameters.min_n_values%TYPE default 1, max_n_values in apm_parameters.max_n_values%TYPE default 1 ) return apm_parameters.parameter_id%TYPE; function update_parameter ( parameter_id in apm_parameters.parameter_id%TYPE, parameter_name in apm_parameters.parameter_name%TYPE, description in apm_parameters.description%TYPE default null, package_key in apm_parameters.package_key%TYPE, datatype in apm_parameters.datatype%TYPE default 'string', default_value in apm_parameters.default_value%TYPE default null, section_name in apm_parameters.section_name%TYPE default null, min_n_values in apm_parameters.min_n_values%TYPE default 1, max_n_values in apm_parameters.max_n_values%TYPE default 1 ) return apm_parameters.parameter_name%TYPE; -- Remove any uses of this parameter. procedure unregister_parameter ( parameter_id in apm_parameters.parameter_id%TYPE default null ); The following functions are used to associate values with parameters and instances: -- Return the value of this parameter for a specific package and parameter. function get_value ( parameter_id in apm_parameter_values.parameter_id%TYPE, package_id in apm_packages.package_id%TYPE ) return apm_parameter_values.attr_value%TYPE; function get_value ( package_id in apm_packages.package_id%TYPE, parameter_name in apm_parameters.parameter_name%TYPE ) return apm_parameter_values.attr_value%TYPE; -- Sets a value for a parameter for a package instance. procedure set_value ( parameter_id in apm_parameter_values.parameter_id%TYPE, package_id in apm_packages.package_id%TYPE, attr_value in apm_parameter_values.attr_value%TYPE ); procedure set_value ( package_id in apm_packages.package_id%TYPE, parameter_name in apm_parameters.parameter_name%TYPE, attr_value in apm_parameter_values.attr_value%TYPE );
    Data Model Discussion The central piece of the data model is the apm_package_types table where each package is registered. When a new application or service is installed on an OpenACS instance, a corresponding row in this table is inserted with information about the type of package, e.g. if the forum package is installed on your OpenACS server, a row in apm_package_types will be created, noting that it's an application package type. The apm_packages table is used to contain information about the instances of packages currently created in the system. The package_key column references the apm_package_types table to ensure that no package instance can be created for a type that does not exist. The apm_package_versions table contains information specific to a particular version of a package. Several tables reference this one to provide further information about the particular version: apm_package_owners Stores information about the owners of a particular version of a package. apm_package_files Stores information about the files that are part of a version. apm_package_dependencies Stores information about what interfaces the package provides and requires. Parameter information is maintained through two tables: apm_parameters This table contains the definition of each of the parameters for a package. apm_parameter_values This table holds all of the values of parameters for specific package instances. A number of views are available for obtaining information about packages registered in the APM. apm_package_version_info Provides information about all of the versions in the system with information available from the apm_package_types table. apm_enabled_package_versions A view (subset) of the above table with only enabled versions. apm_file_info Provides a public interface for querying file information. User Interface The APM's user interface is part of the OpenACS Administration Service. The UI is the primary point of contact with APM by developers and administrators. It is part of OpenACS Administration, because only the site-wide administrator should be able to access it. Thus in order to develop a package, the developer must be granted site-wide administration. Configuration/Parameters APM has two parameters for configuring how it interacts with the UNIX filesystem, accessible via the Site Map admin page. These parameters need not be changed under most circumstances, but may need to be tweaked for Windows compatibility. GzipExecutableDirectory This directory points to where the gunzip program can be found for uncompressing gzip archives. This is needed for the installation of .apm files which are simply gziped tarballs. Default is /usr/local/bin InfoFilePermissionsMode This sets the default UNIX permissions used when creating files using the APM. Default is 775. Future Improvements/Areas of Likely Change APM has been in production since OpenACS 3.3, and as of version 4.0 offers a stable set of features. One major feature planned is integration with the OpenACS Package Repository for automatic dependency satisfaction. When a user tries to install a package that depends on other packages, the APM will contact the package repository, determine what packages depend on it, and offer the user a chance to download and install them all. This improvement offers value to end users by facilitating the extension of their OpenACS systems. Architecturally, minor improvements to the data model and the specification file are planned to increase modularity. The current implementation puts all package specification information in a single file. This approach has certain advantages, such as centralization, but splitting this information into several files allows for flexible extensions to the APM architecture over time. APM packages currently lack provisions to verify security information. There are plans to add MD5 time stamps and PGP signatures to packages to enable secure authentication of packages. These steps are necessary for APM to be usable as a scalable method to distribute packages on multiple repositories worldwide. Another anticipated change is to split the APM UI into separate systems for authoring, maintaining, and installing packages. The current UI presents all of this functionality in one interface and it can be confusing from a usability perspective. Authors System creator: Bryan Quinn, Jon Salz, Michael Yoon, Lars Pind, Todd Nightingale. System owner: Bryan Quinn Documentation author: Bryan Quinn, building from earlier versions by Jon Salz, Michael Yoon, and Lars Pind. Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 9/25/2000 Bryan Quinn 0.8 Ready for QA 9/29/2000 Bryan Quinn 0.9 Edited for ACS 4 Beta release 10/02/2000 Kai Wu 1.0 Edited for OpenACS 4.5 Beta release 03/02/2002 Roberto Mello
    openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/groups-requirements.xml0000644000175000017500000007024010456621136026670 0ustar frankiefrankie %myvars; ]> Groups Requirements By Rafael H. Schloming, Mark Thomas Introduction Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services for different user communities. Vision Statement A powerful web service that can meet the needs of large enterprises must be able to model the the real world's very rich organizational structures and many ways of decomposing the same organization. For example, a corporation can be broken into structures (the corporation, its divisions, and their departments) or regions (the Boston office, the LA office); a person who is employed by (is a member of) a specific department is also a member of the division and the corporation, and works at (is a member of, but in a different sense) a particular office. OpenACS's Parties and Groups system will support such complex relations faithfully. Historical Motivations The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships expensive. In addition, the Module Scoping design in OpenACS 3.0 introduced a party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer to: add these three columns to each "scoped" table define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null group_id) perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and group_id values In sum, the goal of the Parties and Groups system is to provide OpenACS programmers and site administrators with simple tools that fully describe the complex relationships that exist among groups in the real world. User Scenarios Pat Developer has a client project and wants to model the company, its offices, its divisions, and its departments as groups and the employees as users. System Overview We start with Groups, which contain members; the member can be either a person or another group (i.e. a member is a party). In addition to membership, the party and groups system defines a composition relationship that may exist between groups: A group can be a component of another group. The child group is called a component group; the parent group is called a composite group. A group Gc can be a member and/or a component of another group Gp; the difference is in the way the members of Gc are related to Gp: If a party P is a member (or a component) of Gc and if Gc is a component of Gp, then P is also a member (or a component) of Gp If a party P is a member (or a component) of Gc and if Gc is a member of Gp, then no relationship between P and Gp exists as a result of the relationship between Gp and Gp. Consider an example to make this less abstract: Pretend that the Sierra Club is a member of Greenpeace. The Sierra Club has chapters; each chapter is a component of the Sierra Club. If Eddie Environmentalist is a member of the Massachusetts Chapter of the Sierra Club, Eddie is automatically a member of the Sierra Club, but being a Sierra Club member does not make Eddie a member of Greenpeace. In the OpenACS, Greenpeace, Sierra Club, and the Sierra Club chapters would be modeled as groups, and Eddie would be a user. There would be a composition relationship between each Sierra Club chapter and the Sierra Club. Membership relationships would exist between Eddie and the Massachusetts Chapter, between Eddie and the Sierra Club (due to Eddie's membership in the Massachusetts chapter), and between the Sierra Club and Greenpeace. Membership requirements can vary from group to group. The parties and groups system must provide a base type that specifies the bare minimum necessary to join a group. The parties and groups system must support constraints between a composite group GP and any of its component groups, GC. For example, the system should be able to enforce a rule like: Do not allow a party P to become a member of GC unless P is already a member of GP. Related Links Requirements: Data Model The data model for the parties and groups system must provide support for the following types of entities: 10.0 Parties A party is an entity used to represent either a group or a person. The data model should enforce these constraints: 10.10 A party has an email address, which can be empty. 10.20 A party may have multiple email addresses associated with it. 10.30 The email address of a party must be unique within an OpenACS system. 20.0 Groups A group is a collection of zero or more parties. 20.10 The data model should support the subclassing of groups via OpenACS Objects. 30.0 Persons A person represents an actual human being, past or present. 30.10. A person must have an associated name. 40.0 Users A user is a person who has registered with an OpenACS site. A user may have additional attributes, such as a screen name. The data model should enforce these constraints: 40.10 A user must have a non-empty email address. 40.20 Two different users may not have the same email address on a single OpenACS installation; i.e., an email address identifies a single user on the system. 40.30 A user may have multiple email addresses; for example, two or more email addresses may identify a single user. 40.40 A user must have password field which can be empty. The data model for the parties and groups system must provide support for the following types of relationships between entities: 50.0 Membership A party P is considered a member of a group G when a direct membership relationship exists between P and G or when there exists a direct membership relationship between P and some group GC and GC has a composition relationship (c.f., 60.0) with G. 50.10 A party may be a member of multiple groups. 50.20 A party may be a member of the same group multiple times only when all the memberships have different types; for example, Jane may be a member of The Company by being both an Employee and an Executive. 50.30 A party as a member of itself is not supported. 50.40 The data model must support membership constraints. 50.50The data model should support the subclassing of membership via OpenACS Relationships. 60.0 Composition A group GC is considered a component of a second group GP when a direct composition relationship exists between GC and GP or when there exists a direct composition relationship between GC and some group Gi and Gi has a composition relationship with GP. 60.10A group may be a component of multiple groups. 60.20A group as a component of itself is not supported. 60.30The data model must support component constraints. 60.40The data model should support the subclassing of composition via OpenACS Relationships. Requirements: API The API should let programmers accomplish the following tasks: 70.10 Create a group The parties and groups system provides a well defined API call that creates a new group by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in the data model. 70.20 Create a person The parties and groups system provides a well defined API call that creates a new person by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in the data model. 70.30 Create a user The parties and groups system provides a well defined API call that creates a new user by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in the data model. 80.10 Refine a person to a user The parties and groups system provides a well defined API call that creates a new user by running the appropriate transactions on an existing person entity. This API is subject to the constraints laid out in the data model. 80.30 Demote a user to a person The parties and groups system provides a well defined API call that demotes an existing user entity to a person entity by running the appropriate transactions on the existing user. This API is subject to the constraints laid out in the data model. 90.10 Update a party The programmer should be able to modify, add, and delete attributes on any party. This API is subject to the constraints laid out in the data model. 95.10 Get the attributes of a party The programmer should be able to view the attributes on any party. This API is subject to the constraints laid out in the data model. 100.10 Delete a party The system provides an API for deleting a party. This API is subject to the constraints laid out in the data model. 100.30 The system may provide a single API call to remove the party from all groups and then delete the party. 100.40 In the case of a group, the system may provide a single API call to remove all parties from a group and then delete the group. 110.0 Add a party as a member of a group The parties and groups system provides an API for adding a party as a member of a group. This API is subject to the constraints laid out in the data model. 115.0 Add a group as a component of a second group The parties and groups system provides an API for adding a group as a component of a second group. This API is subject to the constraints laid out in the data model. 120.0 Remove a party as a member of a group The parties and groups system provides an API for deleting a party's membership in a group. This API is subject to the constraints laid out in the data model. 125.0 Remove a group as a component of a second group The parties and groups system provides an API for deleting a group's composition in a second group. This API is subject to the constraints laid out in the data model. 130.0 Membership check The parties and groups system provides an API for answering the question: "Is party P a member of group G?" 135.0 Composition check The parties and groups system provides an API for answering the question: "Is group GC a component of group GP?" 140.0 Get members query The parties and groups system provides an API for answering the question: "Which parties are members of group G?" 145.0 Get components query The parties and groups system provides an API for answering the question: "Which groups are components of group G?" 150.0 Member-of-groups query The parties and groups system provides an API for answering the question: "Of which groups is party P a member?" 155.0 Component-of-groups query The parties and groups system provides an API for answering the question: "Of which groups is group G a component?" 160.0 Allowed membership check The parties and groups system provides an API for answering the question: "Is party P allowed to become a member of group G?" 165.0 Allowed composition check The parties and groups system provides an API for answering the question: "Is group GC allowed to become a component of group GP?" 170.0 Efficiency Since many pages at a site may check membership in a group before serving a page (e.g., as part of a general permissions check), the data model must support the efficient storage and retrieval of party attributes and membership. 180.0 Ease of Use Since many SQL queries will check membership in a group as part of the where clause, whatever mechanism is used to check membership in SQL should be fairly small and simple. Requirements: User Interface The user interface is a set of HTML pages that are used to drive the underlying API. The user interface may provide the following functions: 200.0 Create a party 210.0 View the attributes of a party 220.0 Update the attributes of a party 240.0 Delete a party 250.0 Add a party to a group 260.0 Remove a party from a group 270.0 Perform the membership and composition checks outlined in 130.x to 165.x Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 08/16/2000 Rafael Schloming 0.2 Initial revision 08/19/2000 Mark Thomas 0.3 Edited and reviewed, conforms to requirements template 08/23/2000 Kai Wu 0.4 Further revised, added UI requirements 08/24/2000 Mark Thomas 0.5 Final edits, pending freeze 08/24/2000 Kai Wu 0.6 More revisions, added composition requirements 08/30/2000 Mark Thomas 0.7 More revisions, added composition requirements 09/08/2000 Mark Thomas openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/permissions-design.xml0000644000175000017500000004540510456621136026457 0ustar frankiefrankie %myvars; ]> Permissions Design By John Prevost and Rafael H. Schloming Essentials Tcl in packages/acs-kernel SQL file ER diagram Introduction The goal of the Permissions system is to provide generic means to both programmers and site administrators to designate operations (methods) as requiring permissions, and then to check, grant, or revoke permissions via a consistent interface. For example, we might decide that the transaction that bans a user from a sub-site is an operation a site administrator is able to assign to a particular user. Or perhaps an application developer might decide that viewing a certain set of pages within the application is an operation to be individually granted or revoked from a user. It's expected that the Permissions system will be seeing a lot of use - almost every page will make at least one permissions API call, and some will make several. For programmers, the Permissions API provides a means to work with access control in a consistent manner. If a programmer's OpenACS package defines new methods for itself, the Permissions API must provide simple calls to determine whether the current user is authorized to perform the given method. In addition, using the Permissions API, queries should easily select only those package objects on which a user has certain permissions. For site administrators and other authorized users, the Permissions UI provides a means to aggregate the primitive operations (methods) made available by the programmer into logical privileges (like read, write, and admin) that can be granted and revoked. Historical Considerations In earlier versions of the OpenACS, permissions and access control was handled on a module-by-module basis, often even on a page-by-page basis. For example, a typical module might allow any registered user to access its pages read-only, but only allow members of a certain group to make changes. The way this group was determined also varied greatly between modules. Some modules used "roles", while others did not. Other modules did all access control based simply on coded rules regarding who can act on a given database row based on the information in that row. Problems resulting from this piecemeal approach to permissions and access control were many, the two major ones being inconsistency, and repeated/redundant code. Thus the drive in OpenACS 4 to provide a unified, consistent permissions system that both programmers and administrators can readily use. Competitive Analysis None available as of 10/2000. Design Tradeoffs The core of the permissions data model is quite simple. Unfortunately, the hierarchical nature of default permissions entails quite a number of tree queries which could slow the system down. Since every page will have at least one permissions check, a number of views and auxiliary tables (de-normalizations of the data model) have been created to speed up access queries. As a consequence, speed of updates are decreased and requirements for additional storage space increase. Data Model Discussion As described in section V., the core of the permissions data model is simple, though a number of views and auxiliary tables exist to ensure adequate performance. The core model consists of five tables: acs_methods The set of all defined methods. acs_privileges The set of all defined privileges. acs_privilege_method_rules A relation describing the set of methods directly associated with each privilege. acs_privilege_hierarchy A relation describing which privileges directly "contain" other privileges. acs_permissions A table with one (party, object, privilege) row for every privilege directly granted on any object in the system - this is a denormalization of acs_privilege_method_rules and acs_privilege_hierarchy There are also a number of views to make it easier to ask specific questions about permissions. For example, a number of the above tables describe "direct" or explicit permissions. Inheritance and default values can, however, introduce permissions which are not directly specified. (For example, read access on a forum allows read access on all the messages in the forum.) The following views provide flattened versions of inherited information: acs_privilege_method_map Map of privileges to the methods they contain either directly or because of another privilege which is included (at any depth). acs_object_grantee_priv_map Relation on (object, party, privilege) for privileges from acs_privileges) granted directly on the object, or on the context of the object (at any depth). acs_object_party_privilege_map Relation on (object, party, privilege) for privileges directly from acs_object_grantee_priv_map or also because a party is a member of a group (at any depth). acs_object_party_method_map Relation with every (object, party, method) tuple implied by the above trees. In general, only acs_object_party_method_map should be used for queries from other modules. The other views are intermediate steps in building that query. The data model also includes two simple PL/SQL procedures (acs_permission.grant_permission and acs_permission.revoke_permission) for granting and revoking a specific privilege for a specific user on a specific object. To sum up, the PL/SQL procedures are meant to be used to grant or revoke permissions. The five base tables represent the basic data model of the system, with a set of views provided to convert them into a format suitable for joining to answer specific questions. The exact means by which this transformation takes place should not be depended on, since they may change for efficiency reasons. The transformations done create a set of default permissions, in which: parties get the privileges of any groups they are directly or indirectly a member of privileges get associated with the methods of any other privileges they have taken methods from (at any level) (see acs_privilege_hierarchy) objects get access control from direct grants, or inherit permissions from their context (unless the "don't inherit" flag is set) Legal Transactions There are three essential areas in which all transactions in the permissions system fall: Modification of methods and privileges Modification of permissions Queries on permissions "Modification of methods and privileges." This refers to actions that happen mainly at package installation time - a package will create a number of methods for its own use, then associate them with the system's standard privileges, or new privileges which the package has created. The association step might also happen later, if the site-wide administrator chooses to change permissions policy. These steps involve directly manipulating the acs_methods, acs_privileges, and acs_privilege_method_rules tables. A web page for manipulating these features should be limited to site-wide administrators. "Modification of permissions" - involves fairly common operations. Users are typically able to administer permissions for objects they themselves create. The two basic operations here are "grant" and "revoke". Granting permissions is done via acs_permissions.grant_permission, and revocation via acs_permissions.revoke_permission. These directly manipulate the acs_permissions table. Web pages for making these changes are available to all users, so they should not be in an admin area. In order to grant and revoke permissions on an object, the user must have the administer_privileges method permission on that object. "Queries on permissions" - by far the most common operation is querying the permissions database. Several kinds of questions are commonly asked: First, and most commonly, "Can this party perform this method on this object?" Two Tcl functions are provided to answer this - one which returns a boolean, the other of which results in an error page. These tcl functions directly access the acs_object_party_method_map. The second most commonly asked question occurs when a list of objects is being displayed, often in order to provide appropriate UI functionality: "For this party, what methods are available on these objects?" Here, the SQL query needs to filter based on whether the party/user can perform some operation on the object. This is done via a join or sub-select against acs_object_party_method_map, or by calling the Tcl functions for appropriate methods. Finally, when administering the permissions for an object, a web page needs to know all permissions directly granted on that object. This is done by querying against acs_permissions. API The API to the permissions system consists of a few well-known tables, plus a pair of PL/SQL procedures and a pair of Tcl functions. Tables acs_methods, acs_privileges, and acs_privilege_method_rules manage the set of permissions in the system. At installation time, a package will add to these three tables to introduce new permissions into the system. The main table for queries is acs_object_party_method_map, which contains (object, party, method) triples for all allowed operations in the system. Also of interest for queries is acs_permissions, which lists directly granted privileges. Neither acs_object_party_method_map (which is a view) nor acs_permissions should be updated directly. PL/SQL Procedures acs_permissions.grant_permission introduces new permissions for an object. It should be given an (object, party, privilege) triple, and will always succeed. If the permission is already in the system, no change occurs. The interface for this procedure is: procedure grant_permission ( object_id acs_permissions.object_id%TYPE, grantee_id acs_permissions.grantee_id%TYPE, privilege acs_permissions.privilege%TYPE ); acs_permissions.revoke_permission removes a permission entry given a triple. It always succeeds--if a permission does not exist, nothing changes. The interface for this procedure is: procedure revoke_permission ( object_id acs_permissions.object_id%TYPE, grantee_id acs_permissions.grantee_id%TYPE, privilege acs_permissions.privilege%TYPE ); These procedures are defined in permissions-create.sql Tcl Procedures Two tcl procedures provide a simple call for the query, "Can this user perform this method on this object?" One returns true or false, the other presents an error page. To receive a true or false value, Tcl code should call: ad_permission_p $object_id $object_type $method -user_id $user_id If the user_id argument is left out, then the currently logged in user is checked. To create an error page, Tcl code should call: ad_require_permission $object_id $object_type $method These procedures are defined in acs-permissions-procs.tcl. User Interface All users of the permissions system are the same at the user-interface level. If you have the administer_privileges method permission on an object, then you may edit privileges for that object with the UI. The UI currently provides a list of all granted permissions on the object. If the user wishes to revoke privileges, she may select a set of grants, choose revoke, confirm their deletion, and be returned to the same page after those privileges have been revoked. Granting permissions currently (as of 10/2000) works by providing a list of all possible permissions and a list of all parties in the system. (For large sites, some future search mechanism will be necessary.) After choosing privileges to grant, the user is returned to the "edit privileges for one object" screen. If it makes sense, the system will also display a checkbox which the user may select to toggle whether permissions are inherited from the object's context. There are a number of potential future enhancements for the permissions UI, outlined below. Configuration/Parameters There are no configuration options for the permissions system. Future Improvements/Areas of Likely Change The most important future changes to the Permissions system are likely to be in the UI: There should be a page displaying a list of all objects for which the current user is allowed to administer privileges. Users should be able to view the permissions on any object, or perhaps on objects which they have the "read_permissions" method. This would allow them to see what grants are affecting their objects through inheritance. Authors System creator Rafael H. Schloming System owner Rafael H. Schloming Documentation author John Prevost Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 9/11/2000 John Prevost 0.2 Edited for ACS 4 Beta release 10/04/2000 Kai Wu openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/object-system-design.xml0000644000175000017500000017432510456621136026700 0ustar frankiefrankie %myvars; ]> Object Model Design By Pete Su, Michael Yoon, Richard Li, Rafael Schloming Essentials Data Model acs-metadata-create.sql acs-objects-create.sql acs-relationships-create.sql Tcl Files Not yet linked. Requirements Object Model Requirements Groups Requirements Permissions Requirements Introduction Before OpenACS 4, software developers writing OpenACS applications or modules would develop each data model separately. However, many applications built on OpenACS share certain characteristics or require certain common services. Examples of such services include: User comments Storage of user-defined or extensible sets of attributes Access control General auditing and bookkeeping (e.g. creation date, IP addresses, and so forth) Presentation tools (e.g. how to display a field in a form or on a page) All of these services involve relating additional service-related information to application data objects. Examples of application objects include: forum messages A user home page A ticket in the ticket tracker In the past, developers had to use ad-hoc and inconsistent schemes to interface to various "general" services. OpenACS 4 defines a central data model that keeps track of the application objects that we wish to manage, and serves as a primary store of metadata. By metadata, we mean data stored on behalf of an application outside of the application's data model in order to enable certain central services. The OpenACS 4 Object Model (or object system) manages several different kinds of data and metadata to allow us to provide general services to applications: Every application object is given a unique identifier in the system. This identifier can be used to find all data related to a particular object. Every object is created in a particular security context, so the system can provide centralized access control. Objects are instances of developer-defined object types. Object types allow developers to customize the data that is stored with each object. Relation types provide a general mechanism for mapping instances of one object type (e.g. users) to instances of another object type (e.g. groups). The next section will explore these facilities in the context of the the particular programming idioms that we wish to generalize. Related Links This design document should be read along with the design documents for the new groups system, subsites and the permissions system History The motivation for most of the facilities in the OpenACS 4 Object Model can be understood in the context of the 3.x code base and the kinds of programming idioms that evolved there. These are listed and discussed below. Object Identification Object identification is a central mechanism in OpenACS 4. Every application object in OpenACS 4 has a unique ID which is mapped to a row in a central table called acs_objects. Developers that wish to use OpenACS 4 services need only take a few simple steps to make sure that their application objects appear in this table. The fact that every object has a known unique identifier means that the core can deal with all objects in a generic way. In other words, we use object identifiers to enable centralized services in a global and uniform manner. Implicit Object Identifiers in OpenACS 3.x The motivation for implementing general object identifiers comes from several observations of data models in OpenACS 3.x. Many modules use a (user_id, group_id, scope) column-triple for the purpose of recording ownership information on objects, for access control. User/groups also uses (user_id, group_id) pairs in its user_group_map table as a way to identify data associated with a single membership relation. Also, in OpenACS 3.x many utility modules exist that do nothing more than attach some extra attributes to existing application data. For example, general comments maintains a table that maps application "page" data (static or dynamic pages on the website) to one or more user comments on that page. It does so by constructing a unique identifier for each page, usually a combination of the table in which the data is stored, and the value of the primary key value for the particular page. This idiom is referred to as the "(on_which_table + on_what_id)" method for identifying application data. In particular, general comments stores its map from pages to comments using a "(on_which_table + on_what_id)" key plus the ID of the comment itself. All of these composite key constructions are implicit object identifiers - they build a unique ID out of other pieces of the data model. The problem is that their definition and use is ad-hoc and inconsistent, making the construction of generic application-independent services unnecessarily difficult. Object Identifiers in OpenACS 4 The OpenACS 4 Object Model defines a single mechanism that applications use to attach unique identifiers to application data. This identifier is the primary key of the acs_objects table. This table forms the core of what we need to provide generic services like access control, general attribute storage, general presentation and forms tools, and generalized administrative interfaces. In addition, the object system provides an API that makes it easy to create new objects when creating application data. All an application must do to take advantage of general services in OpenACS 4 is to use the new API to make sure every object the system is to manage is associated with a row in acs_objects. More importantly, if they do this, new services like general comments can be created without requiring existing applications to "hook into" them via new metadata. Note: Object identifiers are a good example of metadata in the new system. Each row in acs_objects stores information about the application object, but not the application object itself. This becomes more clear if you skip ahead and look at the SQL schema code that defines this table. Object Context and Access Control Until the implementation of the general permissions system, every OpenACS application had to manage access control to its data separately. Later on, a notion of "scoping" was introduced into the core data model. "Scope" is a term best explained by example. Consider some hypothetical rows in the address_book table: ... scope user_id group_id ... ... user 123 ... ... group 456 ... ... public ... The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address book. In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people). In OpenACS 4, rather than breaking the world into a limited set of scopes, every object lives in a single context. A context is just an abstract name for the default security domain to which the object belongs. Each context has a unique identifier, and all the contexts in a system form a tree. Often this tree will reflect an observed hierarchy in a site, e.g. a forum message would probably list a forum topic as its context, and a forum topic might list a subsite as its context. Thus, contexts make it easier to break the site up into security domains according to its natural structure. An object's context is stored in the context_id column of the acs_objects table. We use an object's context to provide a default answer to questions regarding access control. Whenever we ask a question of the form "can user X perform action Y on object Z", the OpenACS security model will defer to an object's context if there is no information about user X's permission to perform action Y on object Z. The context system forms the basis for the rest of the OpenACS access control system, which is described in in two separate documents: one for the permissions system and another for the party groups system. The context system is also used to implement subsites. Object Types As mentioned above, many OpenACS modules provide extensible data models, and need to use application specific mechanisms to keep track of user defined attributes and to map application data to these attributes. In the past, modules either used user/groups or their own ad hoc data model to provide this functionality. User/Groups in OpenACS 3.x The user/group system allowed developers to define group types along with attributes to be stored with each instance of a group type. Each group type could define a helper table that stored attributes on each instance of the group type. This table was called the "_info" table because the name was generated by appending _info to the name of the group type. The user/groups data model also provided the user_group_type_member_fields and user_group_member_fields tables to define attributes for members of groups of a specific type and for members of a specific group, respectively. The user_group_member_field_map table stored values for both categories of attributes in its field_value column. These tables allowed developers and users to define custom sets of attributes to store on groups and group members without changing the data model at the code level. Many applications in OpenACS 3.x and earlier used the group type mechanism in ways that were only tangentially related to groups of users, just to obtain access to this group types mechanism. Thus the motivation for generalizing the group types mechanism in OpenACS 4. Object Types and Subtypes In OpenACS 4 object types generalize the OpenACS 3.x notion of group types. Each object type can define one or more attributes to be attached to instances of the type. This allows developers to define new types without being artificially tied to a particular module (i.e. user/groups). In addition, the OpenACS 4 object model provides mechanism for defining subtypes of existing types. A subtype of a parent type inherits all the attributes defined in the parent type, and can define some of its own. The motivation for subtypes comes from the need for OpenACS to be more extensible. In OpenACS 3.x, many applications extended the core data models by directly adding more columns, in order to provide convenient access to new information. This resulted in core data tables that were too "fat", containing a hodge podge of unrelated information that should have been normalized away. The canonical example of this is the explosion of the users table in OpenACS 3.x. In addition to being sloppy technically, these fat tables have a couple of other problems: They degrade performance. Denormalization can make it hard to maintain consistency constraints on the data. Object subtypes provide a way to factor the data model while still keeping track of the fact that each member of a subtype (i.e. for each row in the subtype's table), is also a member of the parent type (i.e. there is a corresponding row in the parent type table). Therefore, applications an use this mechanism without worrying about this bookkeeping themselves, and we avoid having applications pollute the core data model with their specific information. Object Attributes, Skinny Tables As we described above, the OpenACS 3.x user/groups system stored object attributes in two ways. The first was to use columns in the helper table. The second consisted of two tables, one describing attributes and one storing values, to provide a flexible means for attaching attributes to metadata objects. This style of attribute storage is used in several other parts of OpenACS 3.x, and we will refer to it as "skinny tables". For example: In the Ecommerce data model, the ec_custom_product_fields table defines attributes for catalog products, and the ec_custom_product_field_values table stores values for those attributes. In the Photo DB data model, the ph_custom_photo_fields table defines attributes for the photographs owned by a specific user, and tables named according to the convention "ph_user_<user_id>_custom_info" are used to store values for those attributes. In addition, there are some instances where we are not using this model but should, e.g. the users_preferences table, which stores preferences for registered users in columns such as prefer_text_only_p and dont_spam_me_p. The "standard" way for an OpenACS 3.x-based application to add to the list of user preferences is to add a column to the users_preferences table (exactly the kind of data model change that has historically complicated the process of upgrading to a more recent OpenACS version). The Objet Model generalizes the scheme used in the old OpenACS 3.x user/groups system. It defines a table called acs_attributes that record what attributes belong to which object types, and how the attributes are stored. As before, attributes can either be stored in helper tables, or in a single central skinny table. The developer makes this choice on a case by case basis. For the most part, attribute data is stored in helper tables so that they can take full advantage of relational data modeling and because they will generally be more efficient. Occasionally, a data model will use skinny tables because doing so allows developers and users to dynamically update the set of attributes stored on an object without updating the data model at the code level. The bottom line: Helper tables are more functional and more efficient, skinny tables are more flexible but limited. Relation Types Many OpenACS 3.x modules use mapping tables to model relationships between application objects. Again, the 3.x user/groups system provides the canonical example of this design style. In that system, there was a single table called user_group_map that kept track of which users belonged to what groups. In addition, as we discussed in the previous section, the system used the user_group_member_fields and user_group_member_fields_map tables to allow developers to attach custom attributes to group members. In fact, these attributes were not really attached to the users, but to the fact that a user was a member of a particular group - a subtle but important distinction. In OpenACS 4, relation types generalize this mechanism. Relation types allow developers to define general mappings from objects of a given type T, to other objects of a given type R. Each relation type is a subtype of acs_object, extended with extra attributes that store constraints on the relation, and the types of objects the relation actually maps. In turn, each instance of a relation type is an object that represents a single fact of the form "the object t of type T is related to the object r of type R." That is, each instance of a relation type is essentially just a pair of objects. Relation types generalize mapping tables. For example, the 3.x user/groups data model can be largely duplicated using a single relation type describing the "group membership" relation. Group types would then be subtypes of this membership relation type. Group type attributes would be attached to the relation type itself. Group member attributes would be attached to instances of the membership relation. Finally, the mapping table would be replaced by a central skinny table that the relation type system defines. Relation types should be used when you want to be able to attach data to the "fact" that object X and object Y are related to each other. On the face of it, they seem like a redundant mechanism however, since one could easily create a mapping table to do the same thing. The advantage of registering this table as a relation type is that in principle the OpenACS 4 object system could use the meta data in the types table to do useful things in a generic way on all relation types. But this mechanism doesn't really exist yet. Relation types are a somewhat abstract idea. To get a better feel for them, you should just skip to the data model. Summary and Design Considerations The OpenACS 4 Object Model is designed to generalize and unify the following mechanisms that are repeatedly implemented in OpenACS-based systems to manage generic and application specific metadata: Why not Object Databases? The presence of a framework for subtyping and inheritance always brings up the question of why we don't just use an object database. The main reason is that all of the major object database vendors ship products that are effectively tied to some set of object oriented programming languages. Their idea is to provide tight language-level integration to lower the "impedance mismatch" between the database and the language. Therefore, database objects and types are generally directly modeled on language level objects and types. Of course, this makes it nearly impossible to interact with the database from a language that does not have this tight coupling, and it limits the data models that we can write to ideas that are expressible in the host language. In particular, we lose many of the best features of the relational database model. This is a disaster from an ease of use standpoint. The "Object relational" systems provide an interesting alternative. Here, some notion of subtyping is embedded into an existing SQL or SQL-like database engine. Examples of systems like this include the new Informix, PostgreSQL 7, and Oracle has something like this too. The main problem with these systems: each one implements their own non-portable extensions to SQL to implement subtyping. Thus, making OpenACS data models portable would become even more difficult. In addition, each of these object systems have strange limitations that make using inheritance difficult in practice. Finally, object databases are not as widely used as traditional relational systems. They have not been tested as extensively and their scalability to very large databases is not proven (though some will disagree with this statement). Oracle The conclusion: the best design is to add a limited notion of subtyping to our existing relational data model. By doing this, we retain all the power of the relational data model while gaining the object oriented features we need most. In the context of OpenACS 4, this means using the object model to make our data models more flexible, so that new modules can easily gain access to generic features. However, while the API itself doesn't enforce the idea that applications only use the object model for metadata, it is also the case that the data model is not designed to scale to large type hierarchies. In the more limited domain of the metadata model, this is acceptable since the type hierarchy is fairly small. But the object system data model is not designed to support, for example, a huge type tree like the Java runtime libraries might define. This last point cannot be over-stressed: the object model is not meant to be used for large scale application data storage. It is meant to represent and store metadata, not application data. Data Model Like most data models, the OpenACS Core data model has two levels: The knowledge level (i.e. the metadata model) The operational level (i.e. the concrete data model) You can browse the data models themselves from here: acs-metadata-create.sql acs-objects-create.sql acs-relationships-create.sql (Note that we have subdivided the operational level into the latter two files.) The operational level depends on the knowledge level, so we discuss the knowledge level first. In the text below, we include abbreviated versions of the SQL definitions of many tables. Generally, these match the actual definitions in the existing data model but they are meant to reflect design information, not implementation. Some less relevant columns may be left out, and things like constraint names are not included. Knowledge-Level Model The knowledge level data model for OpenACS objects centers around three tables that keep track of object types, attributes, and relation types. The first table is acs_object_types, shown here in an abbreviated form: create table acs_object_types ( object_type varchar(100) not null primary key, supertype references acs_object_types (object_type), abstract_p char(1) default 'f' not null pretty_name varchar(100) not null unique, pretty_plural varchar(100) not null unique, table_name varchar(30) not null unique, id_column varchar(30) not null, name_method varchar(30), type_extension_table varchar(30) ); This table contains one row for every object type in the system. The key things to note about this table are: For every type, we store metadata for how to display this type in certain contexts (pretty_name and pretty_plural). If the type is a subtype, then its parent type is stored in the column supertype. We support a notion of "abstract" types that contain no instances (as of 9/2000 this is not actually used). These types exist only to be subtyped. An example might be a type representing "shapes" that contains common characteristics of all shapes, but which is only used to create subtypes that represent real, concrete shapes like circles, squares, and so on. Every type defines a table in which one can find one row for every instance of this type (table_name, id_column). type_extension_table is for naming a table that stores extra generic attributes. The second table we use to describe types is acs_attributes. Each row in this table represents a single attribute on a specific object type (e.g. the "password" attribute of the "user" type). Again, here is an abbreviated version of what this table looks like. The actual table used in the implementation is somewhat different and is discussed in a separate document. create table acs_attributes ( attribute_id integer not null primary key object_type not null references acs_object_types (object_type), attribute_name varchar(100) not null, pretty_name varchar(100) not null, pretty_plural varchar(100), sort_order integer not null, datatype not null, default_value varchar(4000), storage varchar(13) default 'type_specific' check (storage in ('type_specific', 'generic')), min_n_values integer default 1 not null, max_n_values integer default 1 not null, static_p varchar(1) ); The following points are important about this table: Every attribute has a unique identifier. Every attribute is associated with an object type. We store various things about each attribute for presentation (pretty_name, sort_order). The data_type column stores type information on this attribute. This is not the SQL type of the attribute; it is just a human readable name for the type of data we think the attribute holds (e.g. "String", or "Money"). This might be used later to generate a user interface. The sort_order column stores information about how to sort the attribute values. Attributes can either be stored explicitly in a table ("type specific storage") or in a skinny table ("generic storage"). In most cases, an attribute maps directly to a column in the table identified by the table_name of the corresponding object type, although, as mentioned above, we sometimes store attribute values as key-value pairs in a "skinny" table. However, when you ask the question "What are the attributes of this type of object?", you don't really care about how the values for each attribute are stored (in a column or as key-value pairs); you expect to receive the complete list of all attributes. The max_n_values and min_n_values columns encode information about the number of values an attribute may hold. Attributes can be defined to hold 0 or more total values. The static_p flag indicates whether this attribute value is shard by all instances of a type, as with static member fields in C++. Static attribute are like group level attributes in OpenACS 3.x. The final part of the knowledge level model keeps track of relationship types. We said above that object relationships are used to generalize the 3.x notion of group member fields. These were fields that a developer could store on each member of a group, but which were contextualized to the membership relation. That is, they were really "attached" to the fact that a user was a member of a particular group, and not really attached to the user. This is a subtle but important distinction, because it allowed the 3.x system to store multiple sets of attributes on a given user, one set for each group membership relation in which they participated. In OpenACS 4, this sort of data can be stored as a relationship type, in acs_rel_types. The key parts of this table look like this: create table acs_rel_types ( rel_type varchar(100) not null references acs_object_types(object_type), object_type_one not null references acs_object_types (object_type), role_one references acs_rel_roles (role), object_type_two not null references acs_object_types (object_type), role_two references acs_rel_roles (role) min_n_rels_one integer default 0 not null, max_n_rels_one integer, min_n_rels_two integer default 0 not null, max_n_rels_two integer ); Things to note about this table: The main part of this table records the fact that the relation is between instances of object_type_one and instances of object_type_two. Therefore, each instance of this relation type will be a pair of objects of the appropriate types. The role columns store human readable names for the roles played by each object in the relation (e.g. "employee" and "employer"). Each role must appear in the acs_rel_roles. The min_n_rels_one column, and its three friends allow the programmer to specify constraints on how many objects any given object can be related to on either side of the relation. This table is easier to understand if you also know how the acs_rels table works. To summarize, the acs_object_types and acs_attributes tables store metadata that describes every object type and attribute in the system. These tables generalize the group types data model in OpenACS 3.x. The acs_rel_types table stores information about relation types. This part of the data model is somewhat analogous to the data dictionary in Oracle. The information stored here is primarily metadata that describes the data stored in the operational level of the data model, which is discussed next. Operational-level Data Model The operational level data model centers around the acs_objects table. This table contains a single row for every instance of the type acs_object. The table contains the object's unique identifier, a reference to its type, security information, and generic auditing information. Here is what the table looks like: create table acs_objects ( object_id integer not null, object_type not null references acs_object_types (object_type), context_id references acs_objects(object_id), security_inherit_p char(1) default 't' not null, check (security_inherit_p in ('t', 'f')), creation_user integer, creation_date date default sysdate not null, creation_ip varchar(50), last_modified date default sysdate not null, modifying_user integer, modifying_ip varchar(50) ); As we said in Section III, security contexts are hierarchical and also modeled as objects. There is another table called acs_object_context_index that stores the context hierarchy. Other tables in the core data model store additional information related to objects. The table acs_attribute_values and acs_static_attr_values are used to store attribute values that are not stored in a helper table associated with the object's type. The former is used for instance attributes while the latter is used for class-wide "static" values. These tables have the same basic form, so we'll only show the first: create table acs_attribute_values ( object_id not null references acs_objects (object_id) on delete cascade, attribute_id not null references acs_attributes (attribute_id), attr_value varchar(4000), primary key (object_id, attribute_id) ); Finally, the table acs_rels is used to store object pairs that are instances of a relation type. create table acs_rels ( rel_id not null references acs_objects (object_id) primary key rel_type not null references acs_rel_types (rel_type), object_id_one not null references acs_objects (object_id), object_id_two not null references acs_objects (object_id), unique (rel_type, object_id_one, object_id_two) ); This table is somewhat subtle: rel_id is the ID of an instance of some relation type. We do this so we can store all the mapping tables in this one table. rel_type is the ID of the relation type to which this object belongs. The next two object IDs are the IDs of the objects being mapped. All this table does is store one row for every pair of objects that we'd like to attach with a relation. Any additional attributes that we'd like to attach to this pair of objects is specified in the attributes of the relation type, and could be stored in any number of places. As in the 3.x user/groups system, these places include helper tables or generic skinny tables. This table, along with acs_attributes and acs_attribute_values generalize the old user/group tables user_group_map, user_group_member_fields_map and user_group_member_fields. Summary and Discussion The core tables in the OpenACS 4 data model store information about instances of object types and relation types. The acs_object table provides the central location that contains a single row for every object in the system. Services can use this table along with the metadata in stored in the knowledge level data model to create, manage, query and manipulate objects in a uniform manner. The acs_rels table has an analogous role in storing information on relations. These are all the tables that we'll discuss in this document. The rest of the Kernel data model is described in the documents for subsites, the permissions system and for the groups system. Some examples of how these tables are used in the system can be found in the discussion of the API, which comes next. API Now we'll examine each piece of the API in detail. Bear in mind that the Object Model API is defined primarily through PL/SQL packages. Object Types and Attributes The object system provides an API for creating new object types and then attaching attributes to them. The procedures create_type and drop_type are used to create and delete type definitions. The two calls show up in the package acs_object_type. procedure create_type ( object_type in acs_object_types.object_type%TYPE, pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, supertype in acs_object_types.supertype%TYPE default 'acs_object', table_name in acs_object_types.table_name%TYPE default null, id_column in acs_object_types.id_column%TYPE default 'XXX', abstract_p in acs_object_types.abstract_p%TYPE default 'f', type_extension_table in acs_object_types.type_extension_table%TYPE default null, name_method in acs_object_types.name_method%TYPE default null ); -- delete an object type definition procedure drop_type ( object_type in acs_object_types.object_type%TYPE, cascade_p in char default 'f' ); Here the cascade_p argument indicates whether dropping a type should also remove all its subtypes from the system. We define a similar interface for defining attributes in the package acs_attribute: function create_attribute ( object_type in acs_attributes.object_type%TYPE, attribute_name in acs_attributes.attribute_name%TYPE, datatype in acs_attributes.datatype%TYPE, pretty_name in acs_attributes.pretty_name%TYPE, pretty_plural in acs_attributes.pretty_plural%TYPE default null, table_name in acs_attributes.table_name%TYPE default null, column_name in acs_attributes.column_name%TYPE default null, default_value in acs_attributes.default_value%TYPE default null, min_n_values in acs_attributes.min_n_values%TYPE default 1, max_n_values in acs_attributes.max_n_values%TYPE default 1, sort_order in acs_attributes.sort_order%TYPE default null, storage in acs_attributes.storage%TYPE default 'type_specific', static_p in acs_attributes.static_p%TYPE default 'f' ) return acs_attributes.attribute_id%TYPE; procedure drop_attribute ( object_type in varchar, attribute_name in varchar ); In addition, the following two calls are available for attaching extra annotations onto attributes: procedure add_description ( object_type in acs_attribute_descriptions.object_type%TYPE, attribute_name in acs_attribute_descriptions.attribute_name%TYPE, description_key in acs_attribute_descriptions.description_key%TYPE, description in acs_attribute_descriptions.description%TYPE ); procedure drop_description ( object_type in acs_attribute_descriptions.object_type%TYPE, attribute_name in acs_attribute_descriptions.attribute_name%TYPE, description_key in acs_attribute_descriptions.description_key%TYPE ); At this point, what you must do to hook into the object system from your own data model becomes clear: Create a table that will store the instances of the new type. Call acs_object_type.create_type() to fill in the metadata table on this new type. If you want your objects to appear in the acs_objects table, then your new type must be a subtype of acs_object. Call acs_attribute.create_attribute() to fill in information on the attributes that this type defines. So, suppose we are writing a new version of the ticket tracker for 4.0. We probably define a table to store tickets in, and each ticket might have an ID and a description. If we want each ticket to be an object, then ticket_id must reference the object_id column in acs_objects: create table tickets ( ticket_id references acs_objects (object_id), description varchar(512), ... ) ; In addition to defining the table, we need this extra PL/SQL code to hook into the object type tables: declare attr_id acs_attributes.attribute_id%TYPE; begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'ticket', pretty_name => 'Ticket', pretty_plural => 'Tickets', table_name => 'tickets', id_column => 'ticket_id', name_method => 'acs_object.default_name' ); attr_id := acs_attribute.create_attribute ( object_type => 'ticket', attribute_name => 'description', datatype => 'string', pretty_name => 'Description', pretty_plural => 'Descriptions' ); ... more attributes ... commit; end; Thus, with a small amount of extra code, the new ticket tracker will now automatically be hooked into every generic object service that exists. Better still, this code need not be changed as new services are added. As an aside, the most important service that requires you to subtype acs_object is permissions. Objects The next important piece of the API is defined in the acs_object package, and is concerned with creating and managing objects. This part of the API is designed to take care of the mundane bookkeeping needed to create objects and query their attributes. Realistically however, limitations in PL/SQL and Oracle will make it hard to build generic procedures for doing large scale queries in the object system, so developers who need to do this will probably have to be fairly familiar with the data model at a lower level. The function acs_object.new() makes a new object for you. The function acs_object.del() deletes an object. As before, this is an abbreviated interface with all the long type specs removed. See the data model or developer's guide for the full interface. function new ( object_id in acs_objects.object_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_object', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return acs_objects.object_id%TYPE; procedure delete ( object_id in acs_objects.object_id%TYPE ); Next, we define some generic functions to manipulate attributes. Again, these interfaces are useful to an extent, but for large scale queries, it's likely that developers would have to query the data model directly, and then encapsulate their queries in procedures. For names, the default_name function is used if you don't want to define your own name function. function name ( object_id in acs_objects.object_id%TYPE ) return varchar; function default_name ( object_id in acs_objects.object_id%TYPE ) return varchar; The following functions tell you where attributes are stored, and fetch single attributes for you. procedure get_attribute_storage ( object_id_in in acs_objects.object_id%TYPE, attribute_name_in in acs_attributes.attribute_name%TYPE, v_column out varchar2, v_table_name out varchar2, v_key_sql out varchar2 ); function get_attribute ( object_id_in in acs_objects.object_id%TYPE, attribute_name_in in acs_attributes.attribute_name%TYPE ) return varchar2; procedure set_attribute ( object_id_in in acs_objects.object_id%TYPE, attribute_name_in in acs_attributes.attribute_name%TYPE, value_in in varchar2 ); The main use of the acs_object package is to create application objects and make them available for services via the acs_objects table. To do this, you just have to make sure you call acs_object.new() on objects that you wish to appear in the acs_objects table. In addition, all such objects must be instances of some subtype of acs_object. Continuing the ticket example, we might define the following sort of procedure for creating a new ticket: function new_ticket ( package_id in tickets.ticket_id%TYPE default null, description in tickets.description%TYPE default '', ... ) return tickets.ticket_id%TYPE is v_ticket_id tickets begin v_ticket_id := acs_object.new( object_id => ticket_id, object_type => 'ticket', ... ); insert into tickets (ticket_id, description) values (v_ticket_id, description); return v_ticket_id; end new_ticket; This function will typically be defined in the context of a PL/SQL package, but we've left it stand-alone here for simplicity. To summarize: in order to take advantage of OpenACS 4 services, a new application need only do three things: Define a data model to describe application objects. This can just be a normal SQL table. Create an object type, using code like in the example from the previous section. Make sure application objects are created using acs_object.new() in addition to whatever SQL code is needed to insert a new row into the application data model. One of the design goals of OpenACS 4 was to provide a straightforward and consistent mechanism to provide applications with general services. What we have seen here is that three simple steps and minimal changes in the application data model are sufficient to make sure that application objects are represented in the acs_objects table. Subsequently, all of the general services in OpenACS 4 (i.e. permissions, general comments, and so on) are written to work with any object that appears in acs_objects. Therefore, in general these three steps are sufficient to make OpenACS 4 services available to your application. Relation Types The relations system defines two packages: acs_rel_type for creating and managing relation types, and acs_rel for relating objects. These two procedures just insert and remove roles from the acs_rel_roles table. This table stores the legal relationship "roles" that can be used when creating relation types. Examples of roles are, say, "member", or "employer". procedure create_role ( role in acs_rel_roles.role%TYPE ); procedure drop_role ( role in acs_rel_roles.role%TYPE ); The main functions in the acs_rel_type package are used to create and drop relation types. procedure create_type ( rel_type in acs_rel_types.rel_type%TYPE, pretty_name in acs_object_types.pretty_name%TYPE, pretty_plural in acs_object_types.pretty_plural%TYPE, supertype in acs_object_types.supertype%TYPE default 'relationship', table_name in acs_object_types.table_name%TYPE, id_column in acs_object_types.id_column%TYPE, abstract_p in acs_object_types.abstract_p%TYPE default 'f', type_extension_table in acs_object_types.type_extension_table%TYPE default null, name_method in acs_object_types.name_method%TYPE default null, object_type_one in acs_rel_types.object_type_one%TYPE, role_one in acs_rel_types.role_one%TYPE default null, min_n_rels_one in acs_rel_types.min_n_rels_one%TYPE, max_n_rels_one in acs_rel_types.max_n_rels_one%TYPE, object_type_two in acs_rel_types.object_type_two%TYPE, role_two in acs_rel_types.role_two%TYPE default null, min_n_rels_two in acs_rel_types.min_n_rels_two%TYPE, max_n_rels_two in acs_rel_types.max_n_rels_two%TYPE ); procedure drop_type ( rel_type in acs_rel_types.rel_type%TYPE, cascade_p in char default 'f' ); Finally, the acs_rel package provides an API that you use to create and destroy instances of a relation type: function new ( rel_id in acs_rels.rel_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'relationship', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, context_id in acs_objects.context_id%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return acs_rels.rel_id%TYPE; procedure delete ( rel_id in acs_rels.rel_id%TYPE ); A good example of how to use relation types appears in the OpenACS 4 data model for groups. As in 3.x, group membership is modeled using a mapping table, but now we create this mapping using relation types instead of explicitly creating a table. First, we create a helper table to store state on each membership fact: create table membership_rels ( rel_id constraint membership_rel_rel_id_fk references acs_rels (rel_id) constraint membership_rel_rel_id_pk primary key, -- null means waiting for admin approval member_state varchar(20) constraint membership_rel_mem_ck check (member_state in ('approved', 'banned', 'rejected', 'deleted')) ); Then, we create a new object type to describe groups. acs_object_type.create_type ( object_type => 'group', pretty_name => 'Group', pretty_plural => 'Groups', table_name => 'groups', id_column => 'group_id', type_extension_table => 'group_types', name_method => 'acs_group.name' ); In this example, we've made groups a subtype of acs_object to make the code simpler. The actual data model is somewhat different. Also, we've assumed that there is a helper table called groups to store information on groups, and that there is a helper table called group_types that has been defined to store extra attributes on groups. Now, assuming we have another object type called person to represent objects that can be group members, we define the following relationship type for group membership: acs_rel_type.create_role ('member'); acs_rel_type.create_type ( rel_type => 'membership_rel', pretty_name => 'Membership Relation', pretty_plural => 'Membership Relationships', table_name => 'membership_rels', id_column => 'rel_id', object_type_one => 'group', min_n_rels_one => 0, max_n_rels_one => null, object_type_two => 'person', role_two => 'member', min_n_rels_two => 0, max_n_rels_two => null ); Now we can define the following procedure to add a new member to a group. All this function does is create a new instance of the membership relation type and then insert the membership state into the helper table that we define above. In the actual implementation, this function is implemented in the membership_rel package. Here we just define an independent function: function member_add ( rel_id in membership_rels.rel_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'membership_rel', group in acs_rels.object_id_one%TYPE, member in acs_rels.object_id_two%TYPE, member_state in membership_rels.member_state%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return membership_rels.rel_id%TYPE is v_rel_id integer; begin v_rel_id := acs_rel.new ( rel_id => rel_id, rel_type => rel_type, object_id_one => group, object_id_two => person, context_id => object_id_one, creation_user => creation_user, creation_ip => creation_ip ); insert into membership_rels (rel_id, member_state) value (v_rel_id, new.member_state); end; Another simple function can be defined to remove a member from a group: procedure member_delete ( rel_id in membership_rels.rel_id%TYPE ) is begin delete from membership_rels where rel_id = membership_rel.delete.rel_id; acs_rel.del(rel_id); end; Summary and Discussion The Object Model's API and data model provides a small set of simple procedures that allow applications to create object types, object instances, and object relations. Most of the data model is straightforward; the relation type mechanism is a bit more complex, but in return it provides functionality on par with the old user/groups system in a more general way. Future Improvements/Areas of Likely Change Nothing here yet. Authors Pete Su generated this document from material culled from other documents by Michael Yoon, Richard Li and Rafael Schloming. But, any remaining lies are his and his alone. Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 9/09/2000 Pete Su 0.2 Edited for ACS 4 Beta 9/30/2000 Kai Wu 0.3 Edited for ACS 4.0.1, fixed some mistakes, removed use of term "OM" 11/07/2000 Pete Su openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/object-system-req.xml0000644000175000017500000010324310456621136026205 0ustar frankiefrankie %myvars; ]> Object Model Requirements By Pete Su I. Introduction A major goal in OpenACS 4 is to unify and normalize many of the core services of the system into a coherent common data model and API. In the past, these services were provided to applications in an ad-hoc and irregular fashion. Examples of such services include: General Comments User/groups Attribute storage in user/groups General Permissions Site wide search General Auditing All of these services involve relating extra information and services to application data objects, examples of which include: Bboard messages A user home page A ticket in the Ticket Tracker A photograph in the PhotoDB In the past, developers had to use ad-hoc and inconsistent schemes to interface to the various "general" services mentioned above. Since each service used its own scheme for storing its metadata and mapping this data to application objects, we could not implement any kind of centralized management system or consistent administrative pages for all the services. Consequently, a large amount of duplicate code appeared throughout the system for dealing with these services. Unifying and "normalizing" these interfaces, to minimize the amount of code repetition in applications, is a primary goal of OpenACS 4. Thus the Object Model (OM, also referred to later as the object system) is concerned primarily with the storage and management of metadata, on any object within a given instance of OpenACS 4. The term "metadata" refers to any extra data the OM stores on behalf of the application - outside of the application's data model - in order to enable certain generic services. The term "object" refers to any entity being represented within the OpenACS, and typically corresponds to a single row within the relational database. Vision Statement The OpenACS 4 Object Model must address five high-level requirements that repeatedly exhibit themselves in the context of existing services in OpenACS 3.x, as described below. Object Identifiers for General Services Generic services require a single unambiguous way of identifying application objects that they manage or manipulate. In OpenACS 3.x, there are several different idioms that construct object identifiers from other data. Many modules use a (user_id, group_id, scope) triple combination for the purpose of recording ownership information on objects for access control. User/groups also uses (user_id, group_id) pairs in its user_group_map table as a way to identify data associated with a single membership relation. Also in OpenACS 3.x, many utility modules exist that do nothing more than attach some extra attributes to existing application data. For example, general comments maintains a mapping table that maps application "page" data (static or dynamic) to one or more user comments on the page, by constructing a unique identifier for each page. This identifier is usually a combination of the table in which the data is stored, and the value of the primary key value for the particular page. This idiom is referred to as the "(on_which_table + on_what_id)" method for identifying application data. General comments stores its map from pages to comments using a "(on_which_table + on_what_id)" key, plus the id of the comment itself. All of these composite key constructions are implicit object identifiers: they build a unique ID out of other pieces of the data model. The problem is that their definition and use is ad-hoc and inconsistent. This makes the construction of generic application-independent services difficult. Therefore, the OpenACS 4 Object Model should provide a centralized and uniform mechanism for tagging application objects with unique identifiers. Support for Unified Access Control Access control should be as transparent as possible to the application developer. Until the implementation of the general permissions system, every OpenACS application had to manage access control to its data separately. Later on, a notion of "scoping" was introduced into the core data model. "Scope" is a term best explained by example. Consider some hypothetical rows in the address_book table: ... scope user_id group_id ... ... user 123 ... ... group 456 ... ... public ... The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address book. In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people). The problem with this scheme is that we are limited to using only users and groups as scopes for access control, limiting applications to a single level of hierarchy. Worse, the scoping system demanded that every page needing access to a given application had to do an explicit scope check to make sure access was allowed - if a developer was careless on just one site page, a security problem could result. Thus the OpenACS 4 Object Model must support a more general access control system that allows access control domains to be hierarchical, and specifiable with a single piece of data, instead of the old composite keys described above. Extensible Data Models Another problem with previous OpenACS data models is that many of the central tables in the system became bloated as they were extended to support an increasing number of modules. The users table is the best case in point: it became full of columns that exist for various special applications (e.g. user portraits), but that aren't really related to each other in any way except that they store information on users, i.e. the table became grossly denormalized. Normalizing (breaking-down) this table into several pieces, each of which is specific to a particular application, would improve maintainability greatly. Furthermore, the ability to allow applications or users to define new extensions to existing tables, and have some central metadata facility for keeping track of what data belong to which tables, would be very useful. Thus the motivation for providing object types and subtyping in the OpenACS 4 Object Model. The OM should allow developers to define a hierarchy of metadata object types with subtyping and inheritance. Developers can then use the framework to allow users to define custom extensions to the existing data models, and the OM does the bookkeeping necessary to make this easier, providing a generic API for object creation that automatically keeps track of the location and relationships between data. Design Note: While this doesn't really belong in a requirements document, the fact that we are constrained to using relational databases means that certain constraints on the overall design of the object data model exist, which you can read about in . Modifiable Data Models Another recurring applications problem is how to store a modifiable data model, or how to store information that may change extensively between releases or in different client installations. Furthermore, we want to avoid changes to an application's database queries in the face of any custom extensions, since such changes are difficult or dangerous to make at runtime, and can make updating the system difficult. Some example applications in OpenACS 3.x with modifiable data models include: User/groups: developers and users can attach custom data to group types, groups, and members of groups. In the Ecommerce data model, the ec_custom_product_fields table defines attributes for catalog products, and the ec_custom_product_field_values table stores values for those attributes. In the PhotoDB data model, the ph_custom_photo_fields table defines attributes for the photographs owned by a specific user, and tables named according to the convention "ph_user_<user_id>_custom_info" are used to store values for those attributes. Thus the Object Model must provide a general mechanism for applications and developers to modify or extend data models, without requiring changes to the SQL schema of the system. This ensures that all applications use the same base schema, resulting in a uniform and more maintainable system. Generic Relations Many OpenACS applications define simple relationships between application objects, and tag those relationships with extra data. In OpenACS 3.x, this was done using mapping tables. The user/groups module has the most highly developed data model for this purpose, using a single table called user_group_map that mapped users to groups. In addition, it uses the the user_group_member_fields and user_group_member_fields_map tables to allow developers to attach custom attributes to group members. In fact, these custom attributes were not really attached to the users, but to the fact that a user was a member of a particular group - a subtle but important distinction. As a historical note, in OpenACS 3.x, user/groups was the only part of the system that provided this kind of data model in a reusable way. Therefore, applications that needed this capability often hooked into user/groups for no other reason than to use this part of its data model. The OpenACS 4 data model must support generic relations by allowing developers to define a special kind of object type called a relation type. Relation types are themselves object types that do nothing but represent relations. They can be used by applications that previously used user/groups for the same purpose, but without the extraneous, artificial dependencies. System Overview The Object Model package is a combination of data model and a procedural API for manipulating application objects within an OpenACS instance. The OM allows developers to describe a hierarchical system of object types that store metadata on application objects. The object type system supports subtyping with inheritance, so new object types can be defined in terms of existing object types. The OM data model forms the main part of the OpenACS 4 Kernel data model. The other parts of the Kernel data model include: Parties and Groups Permissions Each of these is documented elsewhere at length. Use-cases and User-scenarios (Pending as of 8/27/00) Related Links Requirements: Data Model The data model for the object system provides support for the following kinds of schema patterns that are used by many existing OpenACS modules: 10.0 Object Identification and Storage Object identification is a central mechanism in the new metadata system. The fact that every object has a known unique identifier means that the core can deal with all objects in a generic way. Thus the only action required of an application to obtain any general service is to "hook into" the object system. In OpenACS 3.x, modules use ad-hoc means to construct unique identifiers for objects that they manage. Generally, these unique IDs are built from other IDs that happen to be in the data model. Because there is no consistency in these implementations, every application must hook into every service separately. Examples of utilities that do this in OpenACS 3.x system are: User/groups: Information is attached to group membership relations. General Comments: Comments are attached to objects representing some kind of document. General Permissions: Stores access control information on application data. User Profiling: Maps users to pieces of content that they have looked at; content identifiers must be managed in a uniform way. Site Wide Search: Stores all content in a single flat table, with object identifiers pointing to the object containing the content in the first place. This way, we can search the contents of many different types of objects in a uniform way. The OM will support and unify this programming idiom by providing objects with unique identifiers (unique within a given OpenACS instance) and with information about where the application data associated with the object is stored. The identifier can be used to refer to collections of heterogeneous application data. More importantly, object identifiers will enable developers to readily build and use generic services that work globally across a system. The object identifiers should be subject to the following requirements: 10.10 Uniqueness The object ID should be unique among all the IDs in the entire OpenACS system in which the object lives. 10.20 Useful as a Reference Applications should be able to use the unique object ID as a reference, with which they can fetch any or all of the object's attributes. 10.30 Storable Object IDs should be storable in tables. e.g. you should be able to use them to implement mapping tables between objects, to represent relationships. 10.40 Moveable Objects should be mobile between databases. That is, information will often need to be moved between multiple servers (development, staging, and production), so a mechanism for moving this data is necessary. In addition, a mechanism for tagging these objects in a way similar to CVS would be useful in determining which objects need to be synchronized. 20.0 Object Types An object type refers to a specification of one or more attributes to be managed along with a piece of application data. The object system should provide a data model for describing and representing object types. This data model is somewhat analogous to the Oracle data dictionary, which stores information about all user defined tables in the system. The canonical example of this kind of data model occurs in the current OpenACS 3.x user/groups module, which allows the developer to create new group types that can contain not only generic system level attributes but also extended, developer-defined attributes. In addition, these attributes can either be attached to the group type itself, and shared by all instances, or they can be different for each instance. At its core, the OpenACS 4 object system is meant to be a generalization of this mechanism. The data model should allow developers to at least do everything they used to with user/groups, but without its administrative hassles. Therefore, the data model must be able to represent object types that have the following characteristics: 20.10 Type Name A human readable name for the object type. 20.20 Type Attributes Attributes whose values are shared by all instances of the object type. 20.30 Object Attributes Attributes that are specific to each particular object belonging to a given type. The data model must also enforce certain constraints on object types: 20.40 Type Uniqueness Object type names must be unique. 20.50 Attribute Name Uniqueness Attribute names must be unique in the scope of a single object type and any of its parent types. 30.0 Type Extension The Object Model must support the definition of object types that are subtypes of existing types. A subtype inherits all the attributes of its parent type, and defines some attributes of its own. A critical aspect of the OM is parent types may be altered, and any such change must propagate to child subtypes. The OM data model must enforce constraints on subtypes that are similar to the ones on general object types. 30.10 Subtype Uniqueness Subtype names must be unique (this parallels requirement 10.40). 30.20 Subtype Attribute Name Uniqueness Attribute names must be unique in the scope of a single object subtype. 30.30 Parent Type Prerequisite Subtypes must be defined in terms of parent types that, in fact, already exist. 30.40 The extended attribute names in a subtype must not be the same as those in its parent type. 35.0 Methods 35.10 Method and Type Association The OM data model should define a mechanism for associating procedural code, called methods, with objects of a given type. Methods are associated with the each object type - not each object instance. 35.20 Method Sharing All instances of a given object type should share the same set of defined methods for that type. 40.0 Object Attribute Value Storage In addition to information on types, the OM data model provides for the centralized storage of object attribute values. This facility unifies the many ad-hoc attribute/value tables that exist in various OpenACS 3.x data models, such as: User groups: Each instance of a group type can have custom data. Photo DB: Users can define their own custom metadata to attach to photograph objects. Ecommerce: Vendors can attach custom fields to the data model describing their products. 40.10 Generic Retrieval Attributes should be stored so that they are retrievable in a way that is independent of the type of the object that they belong to. That is, the only data needed to retrieve an attribute should be the system-wide ID of an object (see requirement 10.20 above) and the attribute name. 40.20 Inherited Attributes The system should allow for the automatic retrieval of inherited attribute values, for an object belonging to a subtype. 40.30. Constraints on Attributes The system should allow the developer to put down constraints on the values that an attribute may hold, for the purposes of maintaining application specific integrity rules. 50.0 Object Contexts In OpenACS 3.x, there was a notion of "scope" for application objects. An object could be belong to one of three scopes: public, group or user. This provided a crude way to associate objects with particular scopes in the system, but it was awkward to use and limited in flexibility. The OpenACS 4 Object Model provides a generalized notion of scope that allows developers to represent a hierarchy of object contexts. These contexts are used as the basis for the permissions system. In general, if an object has no explicit permissions attached to it, then it inherits permissions from its context. The context data model also forms the basis of the subsites system, and is a basic part of the permissions system, described in separate documents. The context data model should provide the following facilities: 50.10 Unique ID Every context should have a unique ID in the system. 50.20 Tree Structure The data model should support a tree structured organization of contexts. That is, contexts can be logically "contained" within other contexts (i.e. contexts have parents) and contexts can contain other contexts (i.e. contexts can have children). 50.30 Data Model Constraints All objects must have a context ID. This ID must refer to an existing context or be NULL. The meaning of a NULL context is determined by the implementation. Note: The current system interprets the NULL context as meaning the default "site-wide" context in some sense. I wanted to note this fact for others, but there is no need to make this a requirement of the system. I think it would be reasonable to have a NULL context be an error (psu 8/24/2000). 55.0 Object Relations The data model should include a notion of pair-wise relations between objects. Relations should be able to record simple facts of the form "object X is related to object Y by relationship R," and also be able to attach attributes to these facts. Requirements: API The API should let programmers accomplish the following actions: 60.0 Object Type Creation 60.10 Create a New Object Type The object system API should provide a procedure call that creates a new object type by running the appropriate transactions on the object system data model. This API call is subject to the constraints laid out in the data model. We call this operation "instantiating" an object. 60.20 Create a New Object Subtype The object system API should provide a procedure call for creating subtypes of a given type. Operationally, this API is the same as requirement 60.10. Instances of subtypes automatically contain all attributes of the parent type in addition to all attributes of the subtype. This API is subject to the constraints laid out in the data model. 60.30 Create a New Relation Type There should be an API call to create a new type of object relation. Relation types can be modeled as object types. The API below for manipulating attributes can then be used to add attributes to relation types. 70.0 Update an Object Type The object system API must allow the programmer to modify, add, and delete attributes from any object type. Updates should be propagated to any child subtypes. This API is subject to the constraints laid out in the data model. 80.0 Delete an Object Type The system provides an API call for deleting an object type. 80.10 Deleting an object type destroys all instances of the type. It should be an error to delete types that have dependent subtypes. This API is subject to the constraints laid out in the data model. 80.10.10 However, the programmer should also be able to specify that all the subtypes and instances of those subtypes be destroyed before destroying the object type. This is similar to a "delete cascade" constraint in SQL. 90.0 Object Instance Creation and Destruction The system must provide API calls to manage the creation and destruction of object instances. 90.10 Create an Instance of an Object Type The system should provide an API call for creating a new instance of a given object type. The new instance should be populated with values for each of the attributes specified in the definition of the type. In addition, it should be possible to create the new instance with an optional context ID that refers to the default context that the object will live in. 90.20 Delete an Object Instance The OM should provide an API call for object deletion. Objects can be deleted only when no other objects in the system refer to them. Since it might not be practical to provide a mechanism like "delete cascade" here in a reliable way, providing such a facility in the system is optional. 94.0 Object Relation Creation and Destruction The system must provide API calls to manage the creation and destruction of object relations. 94.10 Create an Object Relation The OM must provide an API call to declare that two objects are related to each other by a given relation type. This API call should also allow programmers to attach attributes to this object relation. 94.20 Destroy an Object Relation There should be an API call for destroying object relations and their attributes. 95.10 Create and Destroy Contexts The system should provide an API to create and destroy object contexts. 100.10 Set Attribute Values for an Object The system should provide an API for updating the attribute values of a particular instance of an object type. 110.10 Get Attribute Values for an Object The system should provide an API for retrieving attribute values from a particular instance of an object type. 120.10 Efficiency The Object Model must support the efficient storage and retrieval of object attributes. Since the OM is intended to form the core of many general services in the OpenACS, and these services will likely make extensive use of the OM tables, queries on these tables must be fast. The major problem here seems to be supporting subtyping and inheritance in a way that does not severely impact query performance. 130.10 Ease of Use Most OpenACS packages will be expected to use the Object Model in one way or another. Since it is important that the largest audience of developers possible adopts and uses the OM, it must be easy to incorporate into applications, and it must not impose undue requirements on an application's data model. In other words, it should be easy to "hook into" the object model, and that ability should not have a major impact on the application data model. Note: Is the API the only way to obtain values? How does this integrate with application level SQL queries? Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 08/10/2000 Bryan Quinn 0.2 Major re-write 08/11/2000 Pete Su 0.3 Draft completed after initial reviews 08/22/2000 Pete Su 0.4 Edited, updated to conform to requirements template, pending freeze 08/23/2000 Kai Wu Final edits before freeze 08/24/2000 Pete Su 0.5 Edited for consistency 08/27/2000 Kai Wu 0.6 Put Object ID stuff first, because it makes more sense 08/28/2000 Pete Su 0.7 Added requirement that knowledge-level objects must be moveable between databases. 08/29/2000 Richard Li 0.8 Rewrote intro to match language and concepts in the design document. Also cleaned up usage a bit in the requirements section. Added short vague requirements on relation types. 09/06/2000 Pete Su 0.9 Edited for ACS 4 Beta release. 09/30/2000 Kai Wu openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/db-api.xml0000644000175000017500000013211410456621136023763 0ustar frankiefrankie %myvars; ]> Database Access API By Jon Salz. Revised and expanded by Roberto Mello (rmello at fslc dot usu dot edu), July 2002. Tcl procedures: /packages/acs-kernel/10-database-procs.tcl Tcl initialization: /packages/acs-kernel/database-init.tcl The Big Picture One of OpenACS's great strengths is that code written for it is very close to the database. It is very easy to interact with the database from anywhere within OpenACS. Our goal is to develop a coherent API for database access which makes this even easier. There were four significant problems with the way OpenACS previously used the database (i.e., directly through the ns_db interface): Handle management. We required code to pass database handles around, and for routines which needed to perform database access but didn't receive a database handle as input, it was difficult to know from which of the three "magic pools" (main, subquery, and log) to allocate a new handle. Nested transactions. In our Oracle driver, begin transaction really means "turn auto-commit mode off" and end transaction means "commit the current transaction and turn auto-commit mode on." Thus if transactional code needed to call a routine which needed to operate transactionally, the semantics were non-obvious. Consider: proc foo { db args } { db_transaction { ... } } db_transaction { db_dml unused "insert into greeble(bork) values(33)" foo $db db_dml unused "insert into greeble(bork) values(50)" } This would insert greeble #33 and do all the stuff in foo transactionally, but the end transaction in foo would actually cause a commit, and greeble #50 would later be inserted in auto-commit mode. This could cause subtle bugs: e.g., in the case that the insert for greeble #50 failed, part of the "transaction" would have already have been committed!. This is not a good thing. Unorthodox use of variables. The standard mechanism for mapping column values into variables involved the use of the set_variables_after_query routine, which relies on an uplevel variable named selection (likewise for set_variables_after_subquery and subselection). Hard-coded reliance on Oracle. It's difficult to write code supporting various different databases (dynamically using the appropriate dialect based on the type of database being used, e.g., using DECODE on Oracle and CASE ... WHEN on Postgres). The Database Access API addresses the first three problems by: making use of database handles transparent wrapping common database operations (including transaction management) in Tcl control structures (this is, after all, what Tcl is good at!) It lays the groundwork for addressing the fourth problem by assigning each SQL statement a logical name. In a future version of the OpenACS Core, this API will translate logical statement names into actual SQL, based on the type of database in use. (To smooth the learning curve, we provide a facility for writing SQL inline for a "default SQL dialect", which we assume to be Oracle for now.) To be clear, SQL abstraction is not fully implemented in OpenACS 3.3.1. The statement names supplied to each call are not used by the API at all. The API's design for SQL abstraction is in fact incomplete; unresolved issues include: how to add WHERE clause criteria dynamically how to build a dynamic ORDER BY clause (Ben Adida has a proposed solution for this) how to define a statement's formal interface (i.e., what bind variables it expects, what columns its SELECT clause must contain if it's a query) without actually implementing the statement in a specific SQL dialect So why is the incremental change of adding statement naming to the API worth the effort? It is worth the effort because we know that giving each SQL statement a logical name will be required by the complete SQL abstraction design. Therefore, we know that the effort will not be wasted, and taking advantage of the new support for bind variables will already require code that uses 3.3.0 version of the API to be updated. The Bell Tolls for <computeroutput>set_variables_after_query</computeroutput> set_variables_after_query is gone! (Well, it's still there, but you'll never need to use it.) The new API routines set local variables automatically. For instance: db_1row select_names "select first_names, last_name from users where user_id = [ad_get_user_id]" doc_body_append "Hello, $first_names $last_name!" Like ns_db 1row, this will bomb if the query doesn't return any rows (no such user exists). If this isn't what you want, you can write: if { [db_0or1row select_names "select first_names, last_name from users where user_id = [ad_get_user_id]"] } { doc_body_append "Hello, $first_names $last_name!" } else { # Executed if the query returns no rows. doc_body_append "There's no such user!" } Selecting a bunch of rows is a lot prettier now: db_foreach select_names "select first_names, last_name from users" { doc_body_append "Say hi to $first_names $last_name for me!<br>" } That's right, db_foreach is now like ns_db select plus a while loop plus set_variables_after_query plus an if statement (containing code to be executed if no rows are returned). db_foreach select_names "select first_names, last_name from users where last_name like 'S%'" { doc_body_append "Say hi to $first_names $last_name for me!<br>" } if_no_rows { doc_body_append "There aren't any users with last names beginnings with S!" } Handle Management The new API keeps track of which handles are in use, and automatically allocates new handles when they are necessary (e.g., to perform subqueries while a select is active). For example: doc_body_append "<ul>" db_foreach select_names "select first_names, last_name, user_id from users" { # Automatically allocated a database handle from the main pool. doc_body_append "<li>User $first_names $last_name\n<ul>" db_foreach select_groups "select group_id from user_group_map where user_id = $user_id" { # There's a selection in progress, so we allocated a database handle # from the subquery pool for this selection. doc_body_append "<li>Member of group #$group_id.\n" } if_no_rows { # Not a member of any groups. doc_body_append "<li>Not a member of any group.\n" } } doc_body_append "</ul>" db_release_unused_handles A new handle isn't actually allocated and released for every selection, of course - as a performance optimization, the API keeps old handles around until db_release_unused_handles is invoked (or the script terminates). Note that there is no analogue to ns_db gethandle - the handle is always automatically allocated the first time it's needed. Bind Variables Introduction Most SQL statements require that the code invoking the statement pass along data associated with that statement, usually obtained from the user. For instance, in order to delete a WimpyPoint presentation, a Tcl script might use the SQL statement delete from wp_presentations where presentation_id = some_presentation_id where some_presentation_id is a number which is a valid presentation ID of the presentation I want to delete. It's easy to write code handling situations like this since SQL statements can include bind variables, which represent placeholders for actual data. A bind variable is specified as a colon followed by an identifier, so the statement above can be coded as: db_dml presentation_delete { delete from wp_presentations where presentation_id = :some_presentation_id } When this SQL statement is invoked, the value for the bind variable :some_presentation_id is pulled from the Tcl variable $some_presentation_id (in the caller's environment). Note that bind variables are not limited to one per statement; you can use an arbitrary number, and each will pull from the correspondingly named Tcl variable. (Alternatively, you can also specify an list or ns_set providing bind variables' values; see Usage.) The value of a bind variable is taken literally by the database driver, so there is never any need to put single-quotes around the value for a bind variable, or to use db_quote to escape single-quotes contained in the value. The following works fine, despite the apostrophe: set exclamation "That's all, folks!" db_dml exclamation_insert { insert into exclamations(exclamation) values(:exclamation) } Note that you can use a bind variable in a SQL statement only where you could use a literal (a number or single-quoted string). Bind variables cannot be placeholders for things like SQL keywords, table names, or column names, so the following will not work, even if $table_name is set properly: select * from :table_name Why Bind Variables Are Useful Why bother with bind variables at all - why not just write the Tcl statement above like this: db_dml presentation_delete " delete from wp_presentations where presentation_id = $some_presentation_id " (Note the use of double-quotes to allow the variable reference to $some_presentation_id to be interpolated in.) This will work, but consider the case where some devious user causes some_presentation_id to be set to something like '3 or 1 = 1', which would result in the following statement being executed: delete from wp_presentations where presentation_id = 3 or 1 = 1 This deletes every presentation in the database! Using bind variables eliminates this gaping security hole: since bind variable values are taken literally. Oracle will attempt to delete presentations whose presentation ID is literally '3 or 1 = 1' (i.e., no presentations, since '3 or 1 = 1' can't possibly be a valid integer primary key for wp_presentations. In general, since Oracle always considers the values of bind variables to be literals, it becomes more difficult for users to perform URL surgery to trick scripts into running dangerous queries and DML. Usage Every db_* command accepting a SQL command as an argument supports bind variables. You can either specify the -bind switch to provide a set with bind variable values, or specify the -bind switch to explicitly provide a list of bind variable names and values, or not specify a bind variable list at all, in which case Tcl variables are used as bind variables. The default behavior (i.e., if the -bind switch is omitted) is that these procedures expect to find local variables that correspond in name to the referenced bind variables, e.g.: set user_id 123456 set role "administrator" db_foreach user_group_memberships_by_role { select g.group_id, g.group_name from user_groups g, user_group_map map where g.group_id = map.user_id and map.user_id = :user_id and map.role = :role } { # do something for each group of which user 123456 is in the role # of "administrator" } The value of the local Tcl variable user_id (123456) is bound to the user_id bind variable. The -bind switch can takes the name of an ns_set containing keys for each bind variable named in the query, e.g.: set bind_vars [ns_set create] ns_set put $bind_vars user_id 123456 ns_set put $bind_vars role "administrator" db_foreach user_group_memberships_by_role { select g.group_id, g.group_name from user_groups g, user_group_map map where g.group_id = map.user_id and map.user_id = :user_id and map.role = :role } -bind $bind_vars { # do something for each group in which user 123456 has the role # of "administrator" } Alternatively, as an argument to -bind you can specify a list of alternating name/value pairs for bind variables: db_foreach user_group_memberships_by_role { select g.group_id, g.group_name from user_groups g, user_group_map map where g.group_id = map.user_id and map.user_id = :user_id and map.role = :role } -bind [list user_id 123456 role "administrator"] { # do something for each group in which user 123456 has the role # of "administrator" } Nulls and Bind Variables When processing a DML statement, Oracle coerces empty strings into null. (This coercion does not occur in the WHERE clause of a query, i.e. col = '' and col is null are not equivalent.) As a result, when using bind variables, the only way to make Oracle set a column value to null is to set the corresponding bind variable to the empty string, since a bind variable whose value is the string "null" will be interpreted as the literal string "null". These Oracle quirks complicate the process of writing clear and abstract DML difficult. Here is an example that illustrates why: # # Given the table: # # create table foo ( # bar integer, # baz varchar(10) # ); # set bar "" set baz "" db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)" # # the values of the "bar" and "baz" columns in the new row are both # null, because Oracle has coerced the empty string (even for the # numeric column "bar") into null in both cases Since databases other than Oracle do not coerce empty strings into null, this code has different semantics depending on the underlying database (i.e., the row that gets inserted may not have null as its column values), which defeats the purpose of SQL abstraction. Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the empty string): db_null. Use it instead of the empty string whenever you want to set a column value explicitly to null, e.g.: set bar [db_null] set baz [db_null] db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)" # # sets the values for both the "bar" and "baz" columns to null SQL Abstraction We now require that each SQL statement be assigned a logical name for the statement that is unique to the procedure or page in which it is defined. This is so that (eventually) we can implement logically named statements with alternative SQL for non-Oracle databases (e.g., Postgres). More on this later. Placing Column Values in Arrays and Sets Normally, db_foreach, db_0or1row, and db_1row places the results of queries in Tcl variables, so you can say: db_foreach users_select "select first_names, last_name from users" { doc_body_append "<li>$first_names $last_name\n" } However, sometimes this is not sufficient: you may need to examine the rows returned, to dynamically determine the set of columns returned by the query, or to avoid collisions with existing variables. You can use the -column_array and -column_set switches to db_foreach, db_0or1row, and db_1row to instruct the database routines to place the results in a Tcl array or ns_set, respectively, where the keys are the column names and the values are the column values. For example: db_foreach users_select "select first_names, last_name from users" -column_set columns { # Now $columns is an ns_set. doc_body_append "<li>" for { set i 0 } { $i < [ns_set size $columns] } { incr i } { doc_body_append "[ns_set key $columns $i] is [ns_set value $columns $i]. \n" } } will write something like: first_names is Jon. last_name is Salz. first_names is Lars. last_name is Pind. first_names is Michael. last_name is Yoon. API Note that you never have to use ns_db anymore (including ns_db gethandle)! Just start doing stuff, and (if you want) call db_release_unused_handles when you're done as a hint to release the database handle. db_null db_null Returns a value which can be used in a bind variable to represent the SQL value null. See Nulls and Bind Variables above. db_foreach db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] \ code_block [ if_no_rows if_no_rows_block ] Performs the SQL query sql, executing code_block once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes if_no_rows_block (if provided). Example: db_foreach select_foo "select foo, bar from greeble" { doc_body_append "<li>foo=$foo; bar=$bar\n" } if_no_rows { doc_body_append "<li>There are no greebles in the database.\n" } The code block may contain break statements (which terminate the loop and flush the database handle) and continue statements (which continue to the next row of the loop). db_1row db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] Performs the SQL query sql, setting variables to column values. Raises an error if the query does not return exactly 1 row. Example: db_1row select_foo "select foo, bar from greeble where greeble_id = $greeble_id" # Bombs if there's no such greeble! # Now $foo and $bar are set. db_0or1row db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] Performs the SQL query sql. If a row is returned, sets variables to column values and returns 1. If no rows are returned, returns 0. If more than one row is returned, throws an error. db_string db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] Returns the first column of the result of SQL query sql. If sql doesn't return a row, returns default (or throws an error if default is unspecified). Analogous to database_to_tcl_string and database_to_tcl_string_or_null. db_nextval db_nextval sequence-name Returns the next value for the sequence sequence-name (using a SQL statement like SELECT sequence-name.nextval FROM DUAL). If sequence pooling is enabled for the sequence, transparently uses a value from the pool if available to save a round-trip to the database. db_list db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a Tcl list of the values in the first column of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. Analogous to database_to_tcl_list. db_list_of_lists db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a Tcl list, each element of which is a list of all column values in a row of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. (Analogous to database_to_tcl_list_list.) db_list_of_ns_sets db_list_of_ns_sets statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a list of ns_sets with the values of each column of each row returned by the sql query specified. db_dml db_dml statement-name sql \ [ -bind bind_set_id | -bind bind_value_list ] \ [ -blobs blob_list | -clobs clob_list | -blob_files blob_file_list | -clob_files clob_file_list ] Performs the DML or DDL statement sql. If a length-n list of blobs or clobs is provided, then the SQL should return n blobs or clobs into the bind variables :1, :2, ... :n. blobs or clobs, if specified, should be a list of individual BLOBs or CLOBs to insert; blob_files or clob_files, if specified, should be a list of paths to files containing the data to insert. Only one of -blobs, -clobs, -blob_files, and -clob_files may be provided. Example: db_dml insert_photos " insert photos(photo_id, image, thumbnail_image) values(photo_id_seq.nextval, empty_blob(), empty_blob()) returning image, thumbnail_image into :1, :2 " -blob_files [list "/var/tmp/the_photo" "/var/tmp/the_thumbnail"] This inserts a new row into the photos table, with the contents of the files /var/tmp/the_photo and /var/tmp/the_thumbnail in the image and thumbnail columns, respectively. db_write_clob, db_write_blob, db_blob_get_file db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Analagous to ns_ora write_clob/write_blob/blob_get_file. db_release_unused_handles db_release_unused_handles Releases any allocated, unused database handles. db_transaction db_transaction code_block [ on_error { code_block } ] Executes code_block transactionally. Nested transactions are supported (end transaction is transparently ns_db dml'ed when the outermost transaction completes). The db_abort_transaction command can be used to abort all levels of transactions. It is possible to specify an optional on_error code block that will be executed if some code in code_block throws an exception. The variable errmsg will be bound in that scope. If there is no on_error code, any errors will be propagated. Example: proc replace_the_foo { col } { db_transaction { db_dml "delete from foo" db_dml "insert into foo(col) values($col)" } } proc print_the_foo {} { doc_body_append "foo is [db_string "select col from foo"]<br>\n" } replace_the_foo 8 print_the_foo ; # Writes out "foo is 8" db_transaction { replace_the_foo 14 print_the_foo ; # Writes out "foo is 14" db_dml "insert into some_other_table(col) values(999)" ... db_abort_transaction } on_error { doc_body_append "Error in transaction: $errmsg" } print_the_foo ; # Writes out "foo is 8" db_abort_transaction db_abort_transaction Aborts all levels of a transaction. That is if this is called within several nested transactions, all of them are terminated. Use this insetead of db_dml "abort" "abort transaction". db_multirow db_multirow [ -local ] [ -append ] [ -extend column_list ] \ var-name statement-name sql \ [ -bind bind_set_id | -bind bind_value_list ] \ code_block [ if_no_rows if_no_rows_block ] Performs the SQL query sql, saving results in variables of the form var_name:1, var_name:2, etc, setting var_name:rowcount to the total number of rows, and setting var_name:columns to a list of column names. Each row also has a column, rownum, automatically added and set to the row number, starting with 1. Note that this will override any column in the SQL statement named 'rownum', also if you're using the Oracle rownum pseudo-column. If the -local is passed, the variables defined by db_multirow will be set locally (useful if you're compiling dynamic templates in a function or similar situations). You may supply a code block, which will be executed for each row in the loop. This is very useful if you need to make computations that are better done in Tcl than in SQL, for example using ns_urlencode or ad_quotehtml, etc. When the Tcl code is executed, all the columns from the SQL query will be set as local variables in that code. Any changes made to these local variables will be copied back into the multirow. You may also add additional, computed columns to the multirow, using the -extend { col_1 col_2 ... } switch. This is useful for things like constructing a URL for the object retrieved by the query. If you're constructing your multirow through multiple queries with the same set of columns, but with different rows, you can use the -append switch. This causes the rows returned by this query to be appended to the rows already in the multirow, instead of starting a clean multirow, as is the normal behavior. The columns must match the columns in the original multirow, or an error will be thrown. Your code block may call continue in order to skip a row and not include it in the multirow. Or you can call break to skip this row and quit looping. Notice the nonstandard numbering (everything else in Tcl starts at 0); the reason is that the graphics designer, a non programmer, may wish to work with row numbers. Example: db_multirow -extend { user_url } users users_query { select user_id first_names, last_name, email from cc_users } { set user_url [acs_community_member_url -user_id $user_id] } db_resultrows db_resultrows Returns the number of rows affected or returned by the previous statement. db_with_handle db_with_handle var code_block Places a database handle into the variable var and executes code_block. This is useful when you don't want to have to use the new API (db_foreach, db_1row, etc.), but need to use database handles explicitly. Example: proc lookup_the_foo { foo } { db_with_handle db { return [db_string unused "select ..."] } } db_with_handle db { # Now there's a database handle in $db. set selection [ns_db select $db "select foo from bar"] while { [ns_db getrow $db $selection] } { set_variables_after_query lookup_the_foo $foo } } db_name db_name Returns the name of the database, as returned by the driver. db_type db_type Returns the RDBMS type (i.e. oracle, postgresql) this OpenACS installation is using. The nsv ad_database_type is set up during the bootstrap process. db_compatible_rdbms_p db_compatible_rdbms_p db_type Returns 1 if the given db_type is compatible with the current RDBMS. db_package_supports_rdbms_p db_package_supports_rdbms_p db_type_list Returns 1 if db_type_list contains the current RDMBS type. A package intended to run with a given RDBMS must note this in it's package info file regardless of whether or not it actually uses the database. db_legacy_package_p db_legacy_package_p db_type_list Returns 1 if the package is a legacy package. We can only tell for certain if it explicitly supports Oracle 8.1.6 rather than the OpenACS more general oracle. db_version db_version Returns the RDBMS version (i.e. 8.1.6 is a recent Oracle version; 7.1 a recent PostgreSQL version. db_current_rdbms db_current_rdbms Returns the current rdbms type and version. db_known_database_types db_known_database_types Returns a list of three-element lists describing the database engines known to OpenACS. Each sublist contains the internal database name (used in file paths, etc), the driver name, and a "pretty name" to be used in selection forms displayed to the user. The nsv containing the list is initialized by the bootstrap script and should never be referenced directly by user code. Returns the current rdbms type and version. ($Id: db-api.xml,v 1.10 2006/07/17 05:38:38 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/groups-design.xml0000644000175000017500000006253610456621136025427 0ustar frankiefrankie %myvars; ]> Groups Design By Rafael H. Schloming and Mark Thomas Essentials User directory Sitewide administrator directory Subsite administrator directory TCL script directory Data model PL/SQL file community-core-create.sql groups-create.sql ER diagram Transaction flow diagram Introduction Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services for different user communities. Historical Considerations The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships expensive. In addition, the Module Scoping design in OpenACS 3.0 introduced a party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer to: add these three columns to each "scoped" table define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null group_id) perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and group_id values Competitive Analysis ... Design Tradeoffs The core of the Group Systems data model is quite simple, but it was designed in the hopes of modeling "real world" organizations which can be complex graph structures. The Groups System only considers groups that can be modeled using directed acyclic graphs, but queries over these structures are still complex enough to slow the system down. Since almost every page will have at least one membership check, a number of triggers, views, and auxiliary tables have been created in the hopes of increasing performance. To keep the triggers simple and the number of triggers small, the data model disallows updates on the membership and composition tables, only inserts and deletes are permitted. The data model has tried to balance the need to model actual organizations without making the system too complex or too slow. The added triggers, views, and tables and will increase storage requirements and the insert and delete times in an effort to speed access time. The limited flexibility (no updates on membership) trades against the complexity of the code. Data Model Discussion The Group System data model consists of the following tables: parties The set of all defined parties: any person, user, or group must have a corresponding row in this table. persons The set of all defined persons. To allow easy sorting of persons, the name requirement 30.10 is met by splitting the person's name into two columns: first_names and last_name. users The set of all registered users; this table includes information about the user's email address and the user's visits to the site. user_preferences Preferences for the user. groups The set of all defined groups. group_types When a new type of group is created, this table holds additional knowledge level attributes for the group and its subtypes. membership_rels The set of direct membership relationships between a group and a party. group_member_index A mapping of a party P to the groups {Gi}the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table. composition_rels The set of direct component relationships between a group and another group. group_component_index A mapping of a group Gto the set of groups {Gi} that G is a component of; this mapping includes the type of relationship by including the appropriaterel_id from the composition_rels table. New groups are created through the group.new constructor. When a specialized type of group is required, the group type can be extended by an application developer. Membership constraints can be specified at creation time by passing a parent group to the constructor. The membership_rels and composition_rels tables indicate a group's direct members and direct components; these tables do not provide a record of the members or components that are in the group by virtue of being a member or component of one of the group's component groups. Site pages will query group membership often, but the network of component groups can become a very complex directed acyclic graph and traversing this graph for every query will quickly degrade performance. To make membership queries responsive, the data model includes triggers (described in the next paragraph) which watch for changes in membership or composition and update tables that maintain the group party mappings, i.e., group_member_index and group_component_index. One can think of these tables as a manually maintained index. The following triggers keep the group_*_index tables up to date: membership_rels_in_tr Is executed when a new group/member relationship is created (an insert on membership_rels) membership_rels_del_tr Is executed when a group/member relationship is deleted (a delete on membership_rels) composition_rels_in_tr Is executed when a new group/component relationship is created (an insert on composition_rels) composition_rels_del_tr Is executed when a group/component relationship is deleted (a delete on composition_rels) The data model provides the following views onto the group_member_index and group_component_index tables. No code outside of Groups System should modify the group_*_index tables. group_member_map A mapping of a party to the groups the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table. group_approved_member_map A mapping of a party to the groups the party is an approved member of (member_state is 'approved'); this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table. group_distinct_member_map A person may appear in the group member map multiple times, for example, by being a member of two different groups that are both components of a third group. This view is strictly a mapping of approved members to groups. group_component_map A mapping of a group Gto the set of groups {Gi} group G is a component of; this mapping includes the type of relationship by including the appropriaterel_id from the composition_rels table. party_member_map A mapping of a party P to the set of parties {Pi} party P is a member of. party_approved_member_map A mapping of a party P to the set of parties {Pi} party P is an approved member of. API The API consists of tables and views and PL/SQL functions. Tables and Views The group_types table is used to create new types of groups. The group_member_map, group_approved_member_map, group_distinct_member_map, group_component_map, party_member_map, and party_approved_member_map views are used to query group membership and composition. PL/SQL API Person person.new creates a new person and returns the person_id. The function must be given the full name of the person in two pieces: first_names and last_name. All other fields are optional and default to null except for object_type which defaults to person and creation_date which defaults to sysdate. The interface for this function is: function person.new ( person_id persons.person_id%TYPE, object_type acs_objects.object_type%TYPE, creation_date acs_objects.creation_date%TYPE, creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, email parties.email%TYPE, url parties.url%TYPE, first_names persons.first_names%TYPE, last_name persons.last_name%TYPE ) return persons.person_id%TYPE; person.delete deletes the person whose person_id is passed to it. The interface for this procedure is: procedure person.delete ( person_id persons.person_id%TYPE ); person.name returns the name of the person whose person_id is passed to it. The interface for this function is: function person.name ( person_id persons.person_id%TYPE ) return varchar; User acs_user.new creates a new user and returns the user_id. The function must be given the user's email address and the full name of the user in two pieces: first_names and last_name. All other fields are optional. The interface for this function is: function acs_user.new ( user_id users.user_id%TYPE, object_type acs_objects.object_type%TYPE, creation_date acs_objects.creation_date%TYPE, creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, email parties.email%TYPE, url parties.url%TYPE, first_names persons.first_names%TYPE, last_name persons.last_name%TYPE password users.password%TYPE, salt users.salt%TYPE, password_question users.password_question%TYPE, password_answer users.password_answer%TYPE, screen_name users.screen_name%TYPE, email_verified_p users.email_verified_p%TYPE ) return users.user_id%TYPE; acs_user.delete deletes the user whose user_id is passed to it. The interface for this procedure is: procedure acs_user.delete ( user_id users.user_id%TYPE ); acs_user.receives_alerts_p returns 't' if the user should receive email alerts and 'f' otherwise. The interface for this function is: function acs_user.receives_alerts_p ( user_id users.user_id%TYPE ) return varchar; Use the procedures acs_user.approve_email and acs_user.unapprove_email to specify whether the user's email address is valid. The interface for these procedures are: procedure acs_user.approve_email ( user_id users.user_id%TYPE ); procedure acs_user.unapprove_email ( user_id users.user_id%TYPE ); Group acs_group.new creates a new group and returns the group_id. All fields are optional and default to null except for object_type which defaults to 'group', creation_date which defaults to sysdate, and group_name which is required. The interface for this function is: function acs_group.new ( group_id groups.group_id%TYPE, object_type acs_objects.object_type%TYPE, creation_date acs_objects.creation_date%TYPE, creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, email parties.email%TYPE, url parties.url%TYPE, group_name groups.group_name%TYPE ) return groups.group_id%TYPE; acs_group.name returns the name of the group whose group_id is passed to it. The interface for this function is: function acs_group.name ( group_id groups.group_id%TYPE ) return varchar; acs_group.member_p returns 't' if the specified party is a member of the specified group. Returns 'f' otherwise. The interface for this function is: function acs_group.member_p ( group_id groups.group_id%TYPE, party_id parties.party_id%TYPE, ) return char; Membership Relationship membership_rel.new creates a new membership relationship type between two parties and returns the relationship type's rel_id. All fields are optional and default to null except for rel_type which defaults to membership_rel. The interface for this function is: function membership_rel.new ( rel_id membership_rels.rel_id%TYPE, rel_type acs_rels.rel_type%TYPE, object_id_one acs_rels.object_id_one%TYPE, object_id_two acs_rels.object_id_two%TYPE, member_state membership_rels.member_state%TYPE, creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, ) return membership_rels.rel_id%TYPE; membership_rel.ban sets the member_state of the given rel_id to 'banned'. The interface for this procedure is: procedure membership_rel.ban ( rel_id membership_rels.rel_id%TYPE ); membership_rel.approve sets the member_state of the given rel_id to 'approved'. The interface for this procedure is: procedure membership_rel.approve ( rel_id membership_rels.rel_id%TYPE ); membership_rel.reject sets the member_state of the given rel_id to 'rejected. The interface for this procedure is: procedure membership_rel.reject ( rel_id membership_rels.rel_id%TYPE ); membership_rel.unapprove sets the member_state of the given rel_id to an empty string ''. The interface for this procedure is: procedure membership_rel.unapprove ( rel_id membership_rels.rel_id%TYPE ); membership_rel.deleted sets the member_state of the given rel_id to 'deleted'. The interface for this procedure is: procedure membership_rel.deleted ( rel_id membership_rels.rel_id%TYPE ); membership_rel.delete deletes the given rel_id. The interface for this procedure is: procedure membership_rel.delete ( rel_id membership_rels.rel_id%TYPE ); Composition Relationship composition_rel.new creates a new composition relationship type and returns the relationship's rel_id. All fields are optional and default to null except for rel_type which defaults to composition_rel. The interface for this function is: function membership_rel.new ( rel_id composition_rels.rel_id%TYPE, rel_type acs_rels.rel_type%TYPE, object_id_one acs_rels.object_id_one%TYPE, object_id_two acs_rels.object_id_two%TYPE, creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, ) return composition_rels.rel_id%TYPE; composition_rel.delete deletes the given rel_id. The interface for this procedure is: procedure membership_rel.delete ( rel_id composition_rels.rel_id%TYPE ); User Interface Describe the admin pages. Configuration/Parameters ... Acceptance Tests ... Future Improvements/Areas of Likely Change ... Authors System creator Rafael H. Schloming System owner Rafael H. Schloming Documentation author Mark Thomas Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 08/22/2000 Rafael H. Schloming 0.2 Initial Revision 08/30/2000 Mark Thomas 0.3 Additional revisions; tried to clarify membership/compostion 09/08/2000 Mark Thomas openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/permissions-requirements.xml0000644000175000017500000002657610456621136027741 0ustar frankiefrankie %myvars; ]> Permissions Requirements By John McClary Prevost Introduction This document records requirements for the OpenACS 4 Permissions system, a component of the OpenACS 4 Kernel. The Permissions system is meant to unify and centralize the handling of access and control on a given OpenACS 4 system. Vision Statement Any multi-user software system must address the general problem of permissions, or "who can do what, on what." On web services, which typically involve large numbers of users belonging to different groups, permissions handling is a critical need: access to content, services, and information generally must be controlled. The OpenACS 4 Permissions system is meant to serve as a consistent, unified interface for higher-level OpenACS applications to handle permissions. Consolidating access control in such a manner reduces both cost and risk: cost, in that less code has to be written and maintained for dealing with recurring permissions situations; risk, in that we need not rely on any single programmer's diligence to ensure access control is implemented and enforced correctly. Historical Motivations In earlier versions of the OpenACS, permissions and access control was handled on a module-by-module basis, often even on a page-by-page basis. For example, a typical module might allow any registered user to access its pages read-only, but only allow members of a certain group to make changes. The way this group was determined also varied greatly between modules. Some modules used "roles", while others did not. Other modules did all access control based simply on coded rules regarding who can act on a given database row based on the information in that row. Problems resulting from this piecemeal approach to permissions and access control were many, the two major ones being inconsistency, and repeated/redundant code. Thus the drive in OpenACS 4 to provide a unified, consistent permissions system that both programmers and administrators can readily use. System Overview The OpenACS 4 Permissions system has two main pieces: first, an API for developers to readily handle access control in their applications. The second piece of the system is a UI meant primarily for (subsite) administrators to grant and revoke permissions to system entities under their control. Consistency is a key characteristic of the Permissions system - both for a common administrative interface, and easily deployed and maintained access control. The system must be flexible enough to support every access model required in OpenACS applications, but not so flexible that pieces will go unused or fall outside the common administrative interfaces. Use Cases and User Scenarios Terminology The primary question an access control system must answer is a three-way relation, like that between the parts of most simple sentences. A simple sentence generally has three parts, a subject, an object, and a verb - in the context of OpenACS Permissions, our simple sentence is, "Can this party perform this operation on this target?" Definitions: The subject of the sentence is "party" - a distinguishable actor whose access may be controlled, this special word is used because one person may be represented by several parties, and one party may represent many users (or no users at all). The object of the sentence is "target" - this is an entity, or object, that the party wishes to perform some action on. An entity/object here is anything that can be put under access control. The verb of the sentence is "operation" - a behavior on the OpenACS system subject to control, this word is used to represent the fact that a single operation may be part of many larger actions the system wants to perform. If "foo" is an operation, than we sometimes refer to the foo "privilege" to mean that a user has the privilege to perform that operation. Examples of the essential question addressed by the Permissions system: Can jane@attacker.com delete the web security forum? Can the Boston office (a party) within the VirtuaCorp intranet/website create its own news instance? Related Links Functional Requirements 10.0 Granularity The system must support access control down to the level of a single entity (this would imply down to the level of a row in the OpenACS Objects data model). 20.0 Operations The system itself must be able to answer the essential permissions question as well as several derived questions.
    20.10 Basic Access Check The system must be able to answer the question, "May party P perform operation O on target T?"
    20.20 Allowed Parties Check The system must be able to answer the question, "Which parties may perform operation O on target T?"
    20.30 Allowed Operations Check The system must be able to answer the question, "Which operations may party P perform on target T?"
    20.40 Allowed Targets Check The system must be able to answer the question, "Upon which targets may party P perform operation O?"
    Behavioral Requirements 40.0 Scale of Privileges Privileges must be designed with appropriate scope for a given OpenACS package. Some privileges are of general utility (e.g. "read" and "write"). Others are of more limited use (e.g. "moderate" - applies mainly to a package like forum, where many users are contributing content simultaneously). A package defining its own privileges should do so with moderation, being careful not to overload a privilege like "read" to mean too many things. 50.0 Aggregation of Operations (Privileges) For user interface purposes, it can be appropriate to group certain privileges under others. For example, anyone with the "admin" privilege may also automatically receive "read", "write", "delete", etc. privileges. 60.0 Aggregation of Parties (Groups) The system must allow aggregation of parties. The exact method used for aggregation will probably be addressed by the OpenACS 4 "Groups" system. Regardless of the exact behavior of aggregate parties, if an aggregate party exists, then access which is granted to the aggregate party should be available to all members of that aggregate. 70.0 Scope of Access Control
    70.10 Context There must be a method for objects to receive default access control from some context. For example, if you do not have read access to a forum, you should not have read access to a message in that forum.
    70.20 Overriding It must be possible to override defaults provided by the context of an object (as in 70.10), in both a positive and negative manner.
    70.20.10 Positive Overriding It must be possible to allow a party more access to some target than they would get by default. (For example, a user does not have the right to edit any message on a forum. But a user does possibly have the right to edit their own messages.)
    70.20.20 Negative Overriding It must be possible to deny a party access to some target that their inherited privileges would have allowed. (For example, a subdirectory in the file-storage might normally have its parent directory as context. It should be possible, however, to make a subdirectory private to some group.)
    100.0 Efficiency At least the basic access check (20.10) and the allowed targets check (20.40) must be efficient enough for general use, i.e. scalable under fairly heavy website traffic. It can be expected that almost every page will contain at least one basic access check, and most pages will contain an allowed targets check (20.40). In particular, constraining a SELECT to return only rows the current user has access to should not be much slower than the SELECT on its own. 120.0 Ease of Use Since most SQL queries will contain an allowed target check in the where clause, whatever mechanism is used to make checks in SQL should be fairly small and simple. In particular, constraining a SELECT to return only rows the current user has access to should not add more than one line to a query.
    Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 8/17/2000 John Prevost 0.2 Revised, updated with new terminology 8/25/2000 John Prevost 0.3 Edited, reformatted to conform to requirements template, pending freeze. 8/26/2000 Kai Wu 0.4 Edited for ACS 4 Beta release. 10/03/2000 Kai Wu
    openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/subsites-design.xml0000644000175000017500000002734711226233616025750 0ustar frankiefrankie %myvars; ]> Subsites Design Document By Rafael H. Schloming *Note* This document has not gone through the any of the required QA process yet. It is being tagged as stable due to high demand. Essentials Introduction An OpenACS 4 subsite is a managed suite of applications that work together for a particular user community. This definition covers a very broad range of requirements: from a Geocities style homepage where a user can install whatever available application he wants (e.g. a single user could have their own news and forums), to a highly structured project subsite with multiple interdependent applications. Thus, flexibility in application deployment is the overarching philosophy of subsites. Meeting such broad requirements of flexibility demands architecture-level support, i.e. very low level support from the core OpenACS 4 data model. For example, the subsites concept demands that any package can have multiple instances installed at different URLs - entailing support from the APM and the Request Processor. Since the design and implementation directly associated with subsites is actually minimal, a discussion of subsites design is, in fact, a discussion of how core OpenACS 4 components implicitly support subsites as a whole. Historical Considerations The subsites problem actually has several quite diverse origins. It was originally recognized as a toolkit feature in the form of "scoping". The basic concept behind scoping was to allow one scoped OpenACS installation to behave as multiple unscoped OpenACS installations so that one OpenACS install could serve multiple communities. Each piece of application data was tagged with a "scope" consisting of the (user_id, group_id, scope) triple. In practice the highly denormalized data models that this method uses produced large amounts of very redundant code and in general made it an extremely cumbersome process to "scopify" a module. Before the advent of scoping there were several cases of client projects implementing their own version of scoping in special cases. One example being the wineaccess multi-retailer ecommerce. (Remember the other examples and get details. Archnet?, iluvcamp?) The requirements of all these different projects vary greatly, but the one consistent theme among all of them is the concept that various areas of the web site have their own private version of a module. Because this theme is so dominant, this is the primary problem that the OpenACS4 implementation of subsites addresses. Competitive Analysis ... Design Tradeoffs The current implementation of package instances and subsites allows extremely flexible URL configurations. This has the benefit of allowing multiple instances of the same package to be installed in one subsite, but can potentially complicate the process of integrating packages with each other since it is likely people will want packages that live at non standard URLs to operate together. This requirement would cause some packages to have more configuration options than normal since hard-coding the URLs would not be feasible anymore. API This section will cover all the APIs relevant to subsites, and so will consist of portions of the APIs of several systems. Packages The following package is provided for instantiation of packages. The apm_package.new function can be used to create a package of any type known to the system. The apm_package_types table can be queried for a list of installed packages. (See APM docs for more detail XXX: insert link here) create or replace package apm_package as function new ( package_id in apm_packages.package_id%TYPE default null, instance_name in apm_packages.instance_name%TYPE default null, package_key in apm_packages.package_key%TYPE, object_type in acs_objects.object_type%TYPE default 'apm_package', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return apm_packages.package_id%TYPE; procedure delete ( package_id in apm_packages.package_id%TYPE ); function singleton_p ( package_key in apm_packages.package_key%TYPE ) return integer; function num_instances ( package_key in apm_package_types.package_key%TYPE ) return integer; function name ( package_id in apm_packages.package_id%TYPE ) return varchar; -- Enable a package to be utilized by a subsite. procedure enable ( package_id in apm_packages.package_id%TYPE ); procedure disable ( package_id in apm_packages.package_id%TYPE ); function highest_version ( package_key in apm_package_types.package_key%TYPE ) return apm_package_versions.version_id%TYPE; end apm_package; / show errors Site Nodes This data model keeps track of what packages are being served from what URLs. You can think of this as a kind of rp_register_directory_map on drugs. This table represents a fully hierarchical site map. The directory_p column indicates whether or not the node is a leaf node. The pattern_p column indicates whether an exact match between the request URL and the URL of the node is required. If pattern_p is true then a match between a request URL and a site node occurs if any valid prefix of the request URL matches the site node URL. The object_id column contains the object mounted on the URL represented by the node. In most cases this will be a package instance. create table site_nodes ( node_id constraint site_nodes_node_id_fk references acs_objects (object_id) constraint site_nodes_node_id_pk primary key, parent_id constraint site_nodes_parent_id_fk references site_nodes (node_id), name varchar(100) constraint site_nodes_name_ck check (name not like '%/%'), constraint site_nodes_un unique (parent_id, name), -- Is it legal to create a child node? directory_p char(1) not null constraint site_nodes_directory_p_ck check (directory_p in ('t', 'f')), -- Should urls that are logical children of this node be -- mapped to this node? pattern_p char(1) default 'f' not null constraint site_nodes_pattern_p_ck check (pattern_p in ('t', 'f')), object_id constraint site_nodes_object_id_fk references acs_objects (object_id) ); The following package is provided for creating nodes. create or replace package site_node as -- Create a new site node. If you set directory_p to be 'f' then you -- cannot create nodes that have this node as their parent. function new ( node_id in site_nodes.node_id%TYPE default null, parent_id in site_nodes.node_id%TYPE default null, name in site_nodes.name%TYPE, object_id in site_nodes.object_id%TYPE default null, directory_p in site_nodes.directory_p%TYPE, pattern_p in site_nodes.pattern_p%TYPE default 'f' ) return site_nodes.node_id%TYPE; -- Delete a site node. procedure delete ( node_id in site_nodes.node_id%TYPE ); -- Return the node_id of a url. If the url begins with '/' then the -- parent_id must be null. This will raise the no_data_found -- exception if there is no matching node in the site_nodes table. -- This will match directories even if no trailing slash is included -- in the url. function node_id ( url in varchar, parent_id in site_nodes.node_id%TYPE default null ) return site_nodes.node_id%TYPE; -- Return the url of a node_id. function url ( node_id in site_nodes.node_id%TYPE ) return varchar; end; / show errors Request Processor Once the above APIs are used to create packages and mount them on a specific site node, the following request processor APIs can be used to allow the package to serve content appropriate to the package instance. [ad_conn node_id] [ad_conn package_id] [ad_conn package_url] [ad_conn subsite_id] [ad_conn subsite_url] Data Model Discussion The subsites implementation doesn't really have it's own data model, although it depends heavily on the site-nodes data model, and the APM data model. User Interface The primary elements of the subsite user interface consist of the subsite admin pages. These pages are divided up into two areas: Group administration, and the site map. The group administration pages allow a subsite administrator to create and modify groups. The site map pages allow a subsite administrator to install, remove, configure, and control access to packages. The site map interface is the primary point of entry for most of the things a subsite administrator would want to do. Configuration/Parameters ... Future Improvements/Areas of Likely Change The current subsites implementation addresses the most basic functionality required for subsites. It is likely that as developers begin to use the subsites system for more sophisticated projects, it will become necessary to develop tools to help build tightly integrated packages. The general area this falls under is "inter-package communication". An actual implementation of this could be anything from clever use of configuration parameters to lots of package level introspection. Another area that is currently underdeveloped is the ability to "tar up" and distribute a particular configuration of site nodes/packages. As we build more fundamental applications that can be applied in more general areas, this feature will become more and more in demand since more problems will be solvable by configuration instead of coding. Authors rhs@mit.edu openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/bootstrap-acs.xml0000644000175000017500000001660210456621136025413 0ustar frankiefrankie %myvars; ]> Bootstrapping OpenACS By Jon Salz Tcl code: /tcl/0-acs-init.tcl and /packages/acs-kernel/bootstrap.tcl This document describes the startup (bootstrapping) process for an AOLserver running OpenACS. The Big Picture Before OpenACS 3.3, the OpenACS startup process was extremely simple: after AOLserver performed its internal initialization (reading the configuration file, loading shared libraries and module code, etc.) it scanned through the Tcl library directory (generally /var/lib/aolserver/yourservername/tcl), sourcing each file in sequence. While this overall structure for initialization is still intact, package management has thrown a wrench into the works - there are a few extra things to do during initialization, most notably: Examine the OpenACS file tree for files that should not be present in OpenACS (i.e., that were once part of the OpenACS distribution but have since been removed). Scan the /packages directory for new packages. Initialize enabled packages by sourcing their *-procs.tcl and *-init.tcl files. This document examines in detail each of the steps involved in AOLserver/OpenACS startup. The Startup Process As soon as the nsd daemon is executed by the init process (or otherwise), AOLserver reads its configuration file and chroots itself if necessary. It then loads shared libraries indicated in the .ini file (e.g., the Oracle driver and nssock), and sources Tcl module files (generally in /home/aol30/modules/tcl). This step is, and has always been, the same for all AOLservers, regardless of whether they are running OpenACS. Next AOLserver sources, in lexicographical order, each file in the /tcl directory. The first such file is 0-acs-init.tcl, which doesn't do much directly except to determine the OpenACS path root (e.g., /var/lib/aolserver/yourservername) by trimming the final component from the path to the Tcl library directory (/var/lib/aolserver/yourservername/tcl). But 0-acs-init.tcl's has an important function, namely sourcing /packages/acs-core/bootstrap.tcl, which does the following: Initialize some NSVs used by the core. These NSVs are documented in /packages/acs-core/apm-procs.tcl - no need to worry about them unless you're an OpenACS core hacker. Verify the deletion of obsolete OpenACS files. The /tcl directory has evolved quite a bit over the months and years, and a few files have come and gone. The /www/doc/removed-files.txt file contains a list of files which must be deleted from the AOLserver installation, at the risk of causing weird conflicts, e.g., having several security filters registered. bootstrap.tcl scans through this list, logging error messages to the log if any of these files exist. Source *-procs.tcl files in the OpenACS core. We source each file matching the *-procs.tcl glob in the /packages/acs-kernel directory, in lexicographical order. These procedure are needed to perform any of the following steps. Ensure that the database is available by grabbing and releasing a handle. If we can't obtain a handle, we terminate initialization (since OpenACS couldn't possibly start up the server without access to the database). Register any new packages in the /packages directory. In each directory inside /packages, we look for a .info file; if we find a package that hasn't yet been registered with the package manager (i.e., it's been copied there manually), we insert information about it into the database. (The first time OpenACS starts up, no packages will have been registered in the database yet, so this step will registers every single package in the /packages directory.) Note that packages discovered here are initially disabled; they must be manually enabled in the package manager before they can be used. Ensure that the acs-kernel package is enabled. If the OpenACS core isn't initialized, the server couldn't possibly be operational, so if there's no enabled version of the OpenACS core we simply mark the latest installed one as enabled. Load *-procs.tcl files for enabled packages, activating their APIs. Load *-init.tcl files for enabled packages, giving packages a chance to register filters and procedures, initialize data structures, etc. Verify that the core has been properly initialized by checking for the existence of an NSV created by the request processor initialization code. If it's not present, the server won't be operational, so we log an error. At this point, bootstrap.tcl is done executing. AOLserver proceeds to source the remaining files in the /tcl directory (i.e., unpackaged libraries) and begins listening for connections. ($Id: bootstrap-acs.xml,v 1.7 2006/07/17 05:38:38 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/tcl-doc.xml0000644000175000017500000003236410456621136024162 0ustar frankiefrankie %myvars; ]> Documenting Tcl Files: Page Contracts and Libraries By Jon Salz on 3 July 2000 Tcl procedures: /packages/acs-kernel/tcl-documentation-procs.tcl The Big Picture In versions of the OpenACS prior to 3.4, the standard place to document Tcl files (both Tcl pages and Tcl library files) was in a comment at the top of the file: # # path from server home/filename # # Brief description of the file's purpose # # author's email address, file creation date # # $Id: tcl-doc.xml,v 1.7 2006/07/17 05:38:38 torbenb Exp $ # In addition, the inputs expected by a Tcl page (i.e., form variables) would be enumerated in a call to ad_page_variables, in effect, documenting the page's argument list. The problem with these practices is that the documentation is only accessible by reading the source file itself. For this reason, ACS 3.4 introduces a new API for documenting Tcl files and, on top of that, a web-based user interface for browsing the documentation: ad_page_contract: Every Tcl page has a contract that explicitly defines what inputs the page expects (with more precision than ad_page_variables) and incorporates metadata about the page (what used to live in the top-of-page comment). Like ad_page_variables, ad_page_contract also sets the specified variables in the context of the Tcl page. ad_library: To be called at the top of every library file (i.e., all files in the /tcl/ directory under the server root and *-procs.tcl files under /packages/). This has the following benefits: Facilitates automatic generation of human-readable documentation. Promotes security, by introducing a standard and automated way to check inputs to scripts for correctness. Allows graphical designers to determine easily how to customize sites' UIs, e.g., what properties are available in templates. Allows the request processor to be intelligent: a script can specify in its contract which type of abstract document it returns, and the request processor can transform it automatically into something useful to a particular user agent. (Don't worry about this for now - it's not complete for ACS 3.4.) ad_page_contract Currently ad_page_contract serves mostly as a replacement for ad_page_variables. Eventually, it will be integrated closely with the documents API so that each script's contract will document precisely the set of properties available to graphical designers in templates. (Document API integration is subject to change, so we don't decsribe it here yet; for now, you can just consider ad_page_contract a newer, better, documented ad_page_variables.) Let's look at an example usage of ad_page_contract: # /packages/acs-kernel/api-doc/www/package-view.tcl ad_page_contract { version_id:integer public_p:optional kind { format "html" } } { Shows APIs for a particular package. @param version_id the ID of the version whose API to view. @param public_p view only public APIs? @param kind view the type of API to view. One of <code>procs_files</code>, <code>procs</code>, <code>content</code>, <code>types</code>, or <code>gd</code>. @param format the format for the documentation. One of <code>html</code> or <code>xml</code>. @author Jon Salz (jsalz@mit.edu) @creation-date 3 Jul 2000 @cvs-id $Id$ } Note that: By convention, ad_page_contract should be preceded by a comment line containing the file's path. The comment is on line 1, and the contract starts on line 2. ad_page_contract's first argument is the list of expected arguments from the HTTP query (version_id, public_p, kind, and format). Like ad_page_variables, ad_page_contract sets the corresponding Tcl variables when the page is executed. Arguments can have defaults, specified using the same syntax as in the Tcl proc (a two-element list where the first element is the parameter name and the second argument is the default value). Arguments can have flags, specified by following the name of the query argument with a colon and one or more of the following strings (separated by commas): optional: the query argument doesn't need to be provided; if it's not, the variable for that argument simply won't be set. For instance, if I call the script above without a public_p in the query, then in the page body [info exists public_p] will return 0. integer: the argument must be an integer (ad_page_contract will fail and display and error if not). This flag, like the next, is intended to prevent clients from fudging query arguments to trick scripts into executing arbitrary SQL. sql_identifier: the argument must be a SQL identifier (i.e., [string is wordchar $the_query_var] must return true). trim: the argument will be [string trim]'ed. multiple: the argument may be specified arbitrarily many times in the query string, and the variable will be set to a list of all those values (or an empty list if it's unspecified). This is analogous to the -multiple-list flag to ad_page_variables, and is useful for handling form input generated by <SELECT MULTIPLE> tags and checkboxes. For instance, if dest_user_id:multiple is specified in the contract, and the query string is ?dest_user_id=913&dest_user_id=891&dest_user_id=9 then $dest_user_id is set to [list 913 891 9]. array: the argument may be specified arbitrarily many times in the query string, with parameter names with suffixes like _1, _2, _3, etc. The variable is set to a list of all those values (or an empty list if none are specified). For instance, if dest_user_id:array is specified in the contract, and the query string is ?dest_user_id_0=913&dest_user_id_1=891&dest_user_id_2=9 then $dest_user_id is set to [list 913 891 9]. You can provide structured, HTML-formatted documentation for your contract. Note that format is derived heavily from Javadoc: a general description of the script's functionality, followed optionally by a series of named attributes tagged by at symbols (@). You are encouraged to provide: A description of the functionality of the page. If the description contains more than one sentence, the first sentence should be a brief summary. A @param tag for each allowable query argument. The format is @param parameter-name description... An @author tag for each author. Specify the author's name, followed his or her email address in parentheses. A @creation-date tag indicating when the script was first created. A @cvs-id tag containing the page's CVS identification string. Just use $Id: tcl-documentation.html,v 1.2 2000/09/19 07:22:35 ron Exp $ when creating the file, and CVS will substitute an appropriate string when you check the file in. These @ tags are optional, but highly recommended! ad_library ad_library provides a replacement for the informal documentation (described above) found at the beginning of every Tcl page. Instead of: # /packages/acs-kernel/00-proc-procs.tcl # # Routines for defining procedures and libraries of procedures (-procs.tcl files). # # jsalz@mit.edu, 7 Jun 2000 # # $Id: tcl-doc.xml,v 1.7 2006/07/17 05:38:38 torbenb Exp $ you'll now write: # /packages/acs-kernel/00-proc-procs.tcl ad_library { Routines for defining procedures and libraries of procedures (<code>-procs.tcl</code> files). @creation-date 7 Jun 2000 @author Jon Salz (jsalz@mit.edu) @cvs-id $Id$ } Note that format is derived heavily from Javadoc: a general description of the script's functionality, followed optionally by a series of named attributes tagged by at symbols (@). HTML formatting is allowed. You are encouraged to provide: An @author tag for each author. Specify the author's name, followed his or her email address in parentheses. A @creation-date tag indicating when the script was first created. A @cvs-id tag containing the page's CVS identification string. Just use $Id: tcl-documentation.html,v 1.2 2000/09/19 07:22:35 ron Exp $ when creating the file, and CVS will substitute an appropriate string when you check the file in. ($Id: tcl-doc.xml,v 1.7 2006/07/17 05:38:38 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/security-requirements.xml0000644000175000017500000001053110456621136027215 0ustar frankiefrankie %myvars; ]> Security Requirements By Richard Li Introduction This document lists the requirements for the security system for the OpenACS. Vision Statement Virtually all web sites support personalized content based on user identity. The level of personalization may be as simple as displaying the name of the user on certain pages or can be as sophisticated as dynamically recommending sections of site that the user may be interested in based on prior browsing history. In any case, the user's identity must be validated and made available to the rest of the system. In addition, sites such as ecommerce vendors require that the user identity be securely validated. Security System Overview The security system consists of a number of subsystems. Signed Cookies Cookies play a key role in storing user information. However, since they are stored in plaintext on a user's system, the validity of cookies is an important issue in trusting cookie information. Thus, we want to be able to validate a cookie, but we also want to validate the cookie without a database hit. 10.0 Guaranteed Tamper Detection Any tampering of cookie data should be easily detectable by the web server. 10.1 Performance and Scalability Validation and verification of the cookie should be easily scalable and should not require a database query on every hit. Session Properties Applications should be able to store session-level properties in a database table. 11.0 Storage API Session-level data should be accessible via an API. 11.1 Purge Mechanism An efficient pruning mechanism should be used to prevent old session level properties from filling up the table. Login The security system should support the concept of persistent user logins. This persistence takes several forms. 12.0 Permanent Login Users should be able to maintain a permanent user login so that they never need to type their password. 12.1 Session Login The security system should support the concept of a session, with authentication tokens that become invalid after a certain period of time. 12.2 Session Definition A session is a sequence of clicks by one user from one browser in which no two clicks are separated by more than some constant (the session timeout). 12.3 Stateless The security system should not require state that is stored in the server. Required state may reside only in the user request (including cookies), and in the database. A single user should be able to log in to the system even if the user is sent to a different AOLserver for each step of the login process (e.g., by a load balancer). 12.4 Secure The security system should not store passwords in clear text in the database. 13.0 SSL Hardware The system must work when the SSL processing occurs outside of the web server (in specialized hardware, in a firewall, etc.). openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/rp-design.xml0000644000175000017500000003466010456621136024526 0ustar frankiefrankie %myvars; ]> Request Processor Design By Rafael H. Schloming Essentials /packages/acs-tcl/tcl/request-processor-procs.tcl /packages/acs-tcl/tcl/request-processor-init.tcl /packages/acs-tcl/tcl/site-nodes-procs.tcl /packages/acs-tcl/tcl/site-nodes-init.tcl /packages/acs-kernel/sql/site-nodes-create.sql Introduction The request processor is the set of procs that responds to every HTTP request made to the OpenACS. The request processor must authenticate the connecting user, and make sure that he is authorized to perform the given request. If these steps succeed, then the request processor must locate the file that is associated with the specified URL, and serve the content it provides to the browser. Related Systems Terminology pageroot -- Any directory that contains scripts and/or static files intended to be served in response to HTTP requests. A typical OpenACS installation is required to serve files from multiple pageroots. global pageroot (/var/lib/aolserver/servicename/www) -- Files appearing under this pageroot will be served directly off the base url http://www.servicename.com/ package root (/var/lib/aolserver/servicename/packages) -- Each subdirectory of the package root is a package. A typical OpenACS installation will have several packages. package pageroot (/var/lib/aolserver/servicename/packages/package_key/www) -- This is the pageroot for the package_key package. request environment (ad_conn) -- This is a global namespace containing variables associated with the current request. abstract URL -- A URL with no extension that doesn't directly correspond to a file in the filesystem. abstract file or abstract path -- A URL that has been translated into a file system path (probably by prepending the appropriate pageroot), but still doesn't have any extension and so does not directly correspond to a file in the filesystem. concrete file or concrete path -- A file or path that actually references something in the filesystem. System Overview Package Lookup One of the first things the request processor must do is to determine which package instance a given request references, and based on this information, which pageroot to use when searching for a file to serve. During this process the request processor divides the URL into two pieces. The first portion identifies the package instance. The rest identifies the path into the package pageroot. For example if the news package is mounted on /offices/boston/announcements/, then a request for /offices/boston/announcements/index would be split into the package_url (/offices/boston/announcements/), and the abstract (no extension info) file path (index). The request processor must be able to figure out which package_id is associated with a given package_url, and package mountings must be persistent across server restarts and users must be able to manipulate the mountings on a live site, therefore this mapping is stored in the database. Authentication and Authorization Once the request processor has located both the package_id and concrete file associated with the request, authentication is performed by the session security system. After authentication has been performed the user is authorized to have read access for the given package by the . If authorization succeeds then the request is served, otherwise it is aborted. Concrete File Search To actually serve a file, the request processor generates an ordered list of abstract paths and searches each path for a concrete file. The first path searched is composed of the package pageroot with the extra portion of the URL appended. The second abstract path consists of the global pageroot with the full URL appended. This means that if an instance of the news package is mounted on /offices/boston/announcements/, then any requests that are not matched by something in the news package pageroot could be matched by something under the global pageroot in the /offices/boston/announcements/ directory. Files take precedence over directory listings, so an index file in the global pageroot will be served instead of a directory listing in the package pageroot, even though the global pageroot is searched later. If a file is found at any of the searched locations then it is served. Virtual URL Handlers If no file is found during the concrete file search, then the request processor searches the filesystem for a virtual url handler (.vuh) file. This file contains normal tcl code, and is in fact handled by the same extension handling procedure that handles .tcl files. The only way this file is treated differently is in how the request processor searches for it. When a lookup fails, the request processor generates each valid prefix of all the abstract paths considered in the concrete file search, and searches these prefixes in order from most specific to least specific for a matching .vuh file. If a file is found then the ad_conn variable path_info is set to the portion of the url not matched by the .vuh script, and the script is sourced. This facility is intended to replace the concept of registered procs, since no special distinction is required between sitewide procs and package specific procs when using this facility. It is also much less prone to overlap and confusion than the use of registered procs, especially in an environment with many packages installed. Site Nodes The request processor manages the mappings from URL patterns to package instances with the site_nodes data model. Every row in the site_nodes table represents a fully qualified URL. A package can be mounted on any node in this data model. When the request processor performs a URL lookup, it determines which node matches the longest possible prefix of the request URI. In order to make this lookup operation as fast as possible, the rows in the site_nodes table are pulled out of the database at server startup, and stored in memory. The memory structure used to store the site_nodes mapping is a hash table that maps from the fully qualified URL of the node, to the package_id and package_key of the package instance mounted on the node. A lookup is performed by starting with the full request URI and successively stripping off the rightmost path components until a match is reached. This way the time required to lookup a URL is proportional to the length of the URL, not to the number of entries in the mapping. Request Environment The request environment is managed by the procedure ad_conn. Variables can be set and retrieved through use of the ad_conn procedure. The following variables are available for public use. If the ad_conn procedure doesn't recognize a variable being passed to it for a lookup, it tries to get a value using ns_conn. This guarantees that ad_conn subsumes the functionality of ns_conn. Request processor [ad_conn urlv] A list containing each element of the URL [ad_conn url] The URL associated with the request. [ad_conn query] The portion of the URL from the ? on (i.e. GET variables) associated with the request. [ad_conn file] The filepath including filename of the file being served [ad_conn request] The number of requests since the server was last started [ad_conn start_clicks] The system time when the RP starts handling the request Session System Variables: set in sec_handler, check security with ad_validate_security_info [ad_conn session_id] The unique session_id coming from the sequence sec_id_seq [ad_conn user_id] User_id of a person if the person is logged in. Otherwise, it is blank [ad_conn sec_validated] This becomes "secure" when the connection uses SSL Database API [ad_conn db,handles] What are the list of handles available to AOL? [ad_conn db,n_handles_used] How many database handles are currently used? [ad_conn db,last_used] Which database handle did we use last? [ad_conn db,transaction_level,$db] Specifies what transaction level we are in [ad_conn db,db_abort_p,$dbh] Whether the transaction is aborted APM [ad_conn xml_loaded_p] Checks whether the XML parser is loaded so that it only gets loaded once. Set in apm_load_xml_packages Packages [ad_conn package_id] The package_id of the package associated with the URL. [ad_conn package_url] The URL on which the package is mounted. Miscellaneous [ad_conn system_p] If true then the request has been made to one of the special directories specified in the config file (somewhere), and no authentication or authorization has been performed. Documentation [ad_conn api_page_documentation_mode_p] openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/i18n-requirements.xml0000644000175000017500000007265311226233616026140 0ustar frankiefrankie %myvars; ]> OpenACS Internationalization Requirements by Henry Minsky, Yon Feldman, Lars Pind, Peter Marklund, Christian Hvid, and others. Introduction This document describes the requirements for functionality in the OpenACS platform to support globalization of the core and optional modules. The goal is to make it possible to support delivery of applications which work properly in multiple locales with the lowest development and maintenance cost. Definitions internationalization (i18n) The provision within a computer program of the capability of making itself adaptable to the requirements of different native languages, local customs and coded character sets. locale The definition of the subset of a user's environment that depends on language and cultural conventions. localization (L10n) The process of establishing information within a computer system specific to the operation of particular native languages, local customs and coded character sets. globalization A product development approach which ensures that software products are usable in the worldwide markets through a combination of internationalization and localization. Vision Statement The Mozilla project suggests keeping two catchy phrases in mind when thinking about globalization: One code base for the world English is just another language Building an application often involves making a number of assumptions on the part of the developers which depend on their own culture. These include constant strings in the user interface and system error messages, names of countries, cities, order of given and family names for people, syntax of numeric and date strings and collation order of strings. The OpenACS should be able to operate in languages and regions beyond US English. The goal of OpenACS Globalization is to provide a clean and efficient way to factor out the locale dependent functionality from our applications, in order to be able to easily swap in alternate localizations. This in turn will reduce redundant, costly, and error prone rework when targeting the toolkit or applications built with the toolkit to another locale. The cost of porting the OpenACS to another locale without some kind of globalization support would be large and ongoing, since without a mechanism to incorporate the locale-specific changes cleanly back into the code base, it would require making a new fork of the source code for each locale. System/Application Overview A globalized application will perform some or all of the following steps to handle a page request for a specific locale: Decide what the target locale is for an incoming page request Decide which character set encoding the output should be delivered in If a script file to handle the request needs to be loaded from disk, determine if a character set conversion needs to be performed when loading the script If needed, locale-specific resources are fetched. These can include text, graphics, or other resources that would vary with the target locale. If content data is fetched from the database, check for locale-specific versions of the data (e.g. country names). Source code should use a message catalog API to translate constant strings in the code to the target locale Perform locale-specific linguistic sorting on data if needed If the user submitted form input data, decide what character set encoding conversion if any is needed. Parse locale-specific quantities if needed (number formats, date formats). If templating is being used, select correct locale-specific template to merge with content Format output data quantities in locale-specific manner (date, time, numeric, currency). If templating is being used, this may be done either before and/or after merging the data with a template. Since the internationalization APIs may potentially be used on every page in an application, the overhead for adding internationalization to a module or application must not cause a significant time delay in handling page requests. In many cases there are facilities in Oracle to perform various localization functions, and also there are facilities in Java which we will want to move to. So the design to meet the requirements will tend to rely on these capabilities, or close approximations to them where possible, in order to make it easier to maintain Tcl and Java OpenACS versions. Use-cases and User-scenarios Here are the cases that we need to be able to handle efficiently: A developer needs to author a web site/application in a language besides English, and possibly a character set besides ISO-8859-1. This includes the operation of the OpenACS itself, i.e., navigation, admin pages for modules, error messages, as well as additional modules or content supplied by the web site developer. What do they need to modify to make this work? Can their localization work be easily folded in to future releases of OpenACS? A developer needs to author a web site which operates in multiple languages simultaneously. For example, www.un.org with content and navigation in multiple languages. The site would have an end-user visible UI to support these languages, and the content management system must allow articles to be posted in these languages. In some cases it may be necessary to make the modules' admin UI's operate in more than one supported language, while in other cases the backend admin interface can operate in a single language. A developer is writing a new module, and wants to make it easy for someone to localize it. There should be a clear path to author the module so that future developers can easily add support for other locales. This would include support for creating resources such as message catalogs, non-text assets such as graphics, and use of templates which help to separate application logic from presentation. Competitive Analysis Other application servers: ATG Dyanmo, Broadvision, Vignette, ... ? Anyone know how they deal with i18n ? Related Links System/Package "coversheet" - where all documentation for this software is linked off of Design document Developer's guide User's guide Other-cool-system-related-to-this-one document LI18NUX 2000 Globalization Specification: http://www.li18nux.net/ Mozilla i18N Guidelines: http://www.mozilla.org/docs/refList/i18n/l12yGuidelines.html ISO 639:1988 Code for the representation of names of languages http://sunsite.berkeley.edu/amher/iso_639.html ISO 3166-1:1997 Codes for the representation of names of countries and their subdivisions Part 1: Country codes http://www.niso.org/3166.html IANA Registry of Character Sets Test plan Competitive system(s) Requirements Because the requirements for globalization affect many areas of the system, we will break up the requirements into phases, with a base required set of features, and then stages of increasing functionality. Locales 10.0 A standard representation of locale will be used throughout the system. A locale refers to a language and territory, and is uniquely identified by a combination of ISO language and ISO country abbreviations.
    See Content Repository Requirement 100.20 10.10 Provide a consistent representation and API for creating and referencing a locale 10.20 There will be a Tcl library of locale-aware formatting and parsing functions for numbers, dates and times. Note that Java has builtin support for these already. 10.30 For each locale there will be default date, number and currency formats. Currency i18n is NOT IMPLEMENTED for 5.0.0. 10.40Administrators can upgrade their servers to use new locales via the APM. NOT IMPLEMENTED in 5.0.0; current workaround is to get an xml file and load it manually.
    Associating a Locale with a Request 20.0 The request processor must have a mechanism for associating a locale with each request. This locale is then used to select the appropriate template for a request, and will also be passed as the locale argument to the message catalog or locale-specific formatting functions.
    20.10 The locale for a request should be computed by the following method, in descending order of priority: get locale associated with subsite or package id get locale from user preference get locale from site wide default 20.20 An API will be provided for getting the current request locale from the ad_conn structure.
    Resource Bundles / Content Repository 30.0 A mechanism must be provided for a developer to group a set of arbitrary content resources together, keyed by a unique identifier and a locale. For example, what approaches could be used to implement a localizable nav-bar mechanism for a site? A navigation bar might be made up of a set of text strings and graphics, where the graphics themselves are locale-specific, such as images of English or Japanese text (as on www.un.org). It should be easy to specify alternate configurations of text and graphics to lay out the page for different locales. Design note: Alternative mechanisms to implement this functionality might include using templates, Java ResourceBundles, content-item containers in the Content Repository, or some convention assigning a common prefix to key strings in the message catalog. Message Catalog for String Translation 40.0 A message catalog facility will provide a database of translations for constant strings for multilingual applications. It must support the following:
    40.10 Each message will referenced via unique a key. 40.20 The key for a message will have some hierarchical structure to it, so that sets of messages can be grouped with respect to a module name or package path. 40.30 The API for lookup of a message will take a locale and message key as arguments, and return the appropriate translation of that message for the specifed locale. 40.40 The API for lookup of a message will accept an optional default string which can be used if the message key is not found in the catalog. This lets the developer get code working and tested in a single language before having to initialize or update a message catalog. 40.50 For use within templates, custom tags which invoke the message lookup API will be provided. 40.60 Provide a method for importing and exporting a flat file of translation strings, in order to make it as easy as possible to create and modify message translations in bulk without having to use a web interface. 40.70 Since translations may be in different character sets, there must be provision for writing and reading catalog files in different character sets. A mechanism must exist for identifying the character set of a catalog file before reading it. 40.80 There should be a mechanism for tracking dependencies in the message catalog, so that if a string is modified, the other translations of that string can be flagged as needing update. 40.90 The message lookup must be as efficient as possible so as not to slow down the delivery of pages.
    Character Set Encoding Character Sets 50.0 A locale will have a primary associated character set which is used to encode text in the language. When given a locale, we can query the system for the associated character set to use. The assumption is that we are going to use Unicode in our database to hold all text data. Our current programming environments (Tcl/Oracle or Java/Oracle) operate on Unicode data internally. However, since Unicode is not yet commonly used in browsers and authoring tools, the system must be able to read and write other character sets. In particular, conversions to and from Unicode will need to be explicitly performed at the following times: Loading source files (.tcl or .adp) or content files from the filesystem Accepting form input data from users Delivering text output to a browser Composing an email message Writing data to the filesystem Acs-templating does the following. When the acs-templating package opens an an ADP or TCL file, it assumes the file is iso-8859-1. If the output charset (OutputCharset) in the AOLserver config file is set, then acs-templating assumes it's that charset. Writing Files When the acs-templating package writes an an ADP or TCL file, it assumes the file is iso-8859-1. If the output charset (OutputCharset) in the AOLserver config file is set, then acs-templating assumes it's that charset. Tcl Source File Character Set
    There are two classes of Tcl files loaded by the system; library files loaded at server startup, and page script files, which are run on each page request. Should we require all Tcl files be stored as UTF8? That seems too much of a burden on developers. 50.10 Tcl library files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename. 50.20 Tcl page script files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.
    Submitted Form Data Character Set 50.30 Data which is submitted with a HTTP request using a GET or POST method may be in any character set. The system must be able to determine the encoding of the form data and convert it to Unicode on demand. 50.35 The developer must be able to override the default system choice of character set when parsing and validating user form data. INCOMPLETE - form widgets in acs-templating/tcl/date-procs.tcl are not internationalized. Also, acs-templating's UI needs to be internationalized by replacing all user-visible strings with message keys. 50.30.10In Japan and some other Asian languages where there are multiple character set encodings in common use, the server may need to attempt to do an auto-detection of the character set, because buggy browsers may submit form data in an unexpected alternate encoding. Output Character Set
    50.40 The output character set for a page request will be determined by default by the locale associated with the request (see requirement 20.0). 50.50 It must be possible for a developer to manually override the output character set encoding for a request using an API function.
    ACS Kernel Issues
    60.10 All OpenACS error messages must use the message catalog and the request locale to generate error message for the appropriate locale.NOT IMPLEMENTED for 5.0.0. 60.20 Web server error messages such as 404, 500, etc must also be delivered in the appropriate locale. 60.30 Where files are written or read from disk, their filenames must use a character set and character values which are safe for the underlying operating system.
    Templates
    70.0 For a given abstract URL, the designer may create multiple locale-specific template files may be created (one per locale or language) 70.10 For a given page request, the system must be able to select an approprate locale-specific template file to use. The request locale is computed as per (see requirement 20.0). 70.20A template file may be created for a partial locale (language only, without a territory), and the request processor should be able to find the closest match for the current request locale. 70.30 A template file may be created in any character set. The system must have a way to know which character set a template file contains, so it can properly process it.
    Formatting Datasource Output in Templates 70.50 The properties of a datasource column may include a datatype so that the templating system can format the output for the current locale. The datatype is defined by a standard OpenACS datatype plus a format token or format string, for example: a date column might be specified as 'current_date:date LONG,' or 'current_date:date "YYYY-Mon-DD"' Forms
    70.60 The forms API must support construction of locale-specific HTML form widgets, such as date entry widgets, and form validation of user input data for locale-specific data, such as dates or numbers. NOT IMPLEMENTED in 5.0.0. 70.70 For forms which allow users to upload files, a standard method for a user to indicate the charset of a text file being uploaded must be provided. Design note: this presumably applies to uploading data to the content repository as well
    Sorting and Searching
    80.10 Support API for correct collation (sorting order) on lists of strings in locale-dependent way. 80.20 For the Tcl API, we will say that locale-dependent sorting will use Oracle SQL operations (i.e., we won't provide a Tcl API for this). We require a Tcl API function to return the correct incantation of NLS_SORT to use for a given locale with ORDER BY clauses in queries. 80.40 The system must handle full-text search in any supported language.
    Time Zones
    90.10 Provide API support for specifying a time zone 90.20 Provide an API for computing time and date operations which are aware of timezones. So for example a calendar module can properly synchronize items inserted into a calendar from users in different time zones using their own local times. 90.30 Store all dates and times in universal time zone, UTC. 90.40 For a registered users, a time zone preference should be stored. 90.50 For a non-registered user a time zone preference should be attached via a session or else UTC should be used to display every date and time. 90.60 The default if we can't determine a time zone is to display all dates and times in some universal time zone such as GMT.
    Database
    100.10 Since UTF8 strings can use up to three (UCS2) or six (UCS4) bytes per character, make sure that column size declarations in the schema are large enough to accomodate required data (such as email addresses in Japanese). Since 5.0.0, this is covered in the database install instructions for both PostgreSQL and Oracle.
    Email and Messaging When sending an email message, just as when delivering the content in web page over an HTTP connection, it is necessary to be able to specify what character set encoding to use, defaulting to UTF-8.
    110.10 The email message sending API will allow for a character set encoding to be specified. 110.20 The email accepting API allows for character set to be parsed correctly (the message has a MIME character set content type header)
    Mail is not internationalized. The following issues must be addressed. Many functions still call ns_sendmail. This means that there are different end points for sending mail. This should be changed to use the acs-mail-lite API instead. Consumers of email services must do the following: Determine the appropriate language or languages to use for the message subject and message body and localize them (as in notifications). Extreme Use case: Web site has a default language of Danish. A forum is set up for Swedes, so the forum has a package_id and a language setting of Swedish. A poster posts to the forum in Russian (is this possible?). A user is subscribed to the forum and has a language preference of Chinese. What should be in the message body and message subject? Incoming mail should be localized.
    Implementation Notes Because globalization touches many different parts of the system, we want to reduce the implementation risk by breaking the implementation into phases. Revision History Document Revision # Action Taken, Notes When? By Whom? 1 Updated with results of MIT-sponsored i18n work at Collaboraid. 14 Aug 2003 Joel Aufrecht 0.4 converting from HTML to DocBook and importing the document to the OpenACS kernel documents. This was done as a part of the internationalization of OpenACS and .LRN for the Heidelberg University in Germany 12 September 2002 Peter Marklund 0.3 comments from Christian 1/14/2000 Henry Minsky 0.2 Minor typos fixed, clarifications to wording 11/14/2000 Henry Minsky 0.1 Creation 11/08/2000 Henry Minsky
    openacs-5.7.0/packages/acs-core-docs/www/xml/kernel/ext-auth-design.xml0000644000175000017500000022560711126246520025642 0ustar frankiefrankie %myvars; ]> External Authentication Design EXT-AUTH-1: Authentication and Account Status API (4 hours) by Peter Marklund Current Design Procedures to support this feature have already been written by Lars. We are using the existing procedure ad_user_login and are deprecating ad_maybe_redirect_for_registration and making it invoke auth::require_login. Execution Story The auth::authenticate procedure will be called by the login page and the auth::require_login procedure at the beginning of any application pages that require login. Tradeoffs: For this feature reliability and testing are the prime concerns. External Design The authtentication API has the following public methods: ad_proc -public auth::require_login {} { If the current session is not authenticated, redirect to the login page, and aborts the current page script. Otherwise, returns the user_id of the user logged in. Use this in a page script to ensure that only registered and authenticated users can execute the page, for example for posting to a forum. @return user_id of user, if the user is logged in. Otherwise will issue an ad_script_abort. @see ad_script_abort } ad_proc -public auth::authenticate { {-authority_id ""} {-username:required} {-password:required} } { Try to authenticate and login the user forever by validating the username/password combination, and return authentication and account status codes. @param authority_id The ID of the authority to ask to verify the user. Defaults to local authority. @param username Authority specific username of the user. @param passowrd The password as the user entered it. } Testcases Procedure auth::authenticate Need to stub ns_sendmail? Test auth_status not "ok" for: Invalid password Invalid username Invalid authority Test account_status "closed" for Member state in banned, rejected, needs approval, and deleted. Error handling (requires stubbing the Authenticate service contract): The Authenticate service contract call hangs and we should time out. Can we implement this in Tcl? The Authenticate call returns comm_error. The Authenticate call returns auth_error. The Authenticate service contract call does not return the variables that it should Page Flow None Data Model None TODO Write test cases Deprecate ad_maybe_redirect_for_registration and make it invoke auth::require_login New proc acs_user::get_by_username EXT-AUTH-3: Account Creation API (5 hours) EXT-AUTH-3: Account Creation API (5 hours) by Peter Marklund Current API ad_proc ad_user_new {email first_names last_name password password_question password_answer {url ""} {email_verified_p "t"} {member_state "approved"} {user_id ""} } { Creates a new user in the system. The user_id can be specified as an argument to enable double click protection. If this procedure succeeds, returns the new user_id. Otherwise, returns 0. } New API TODO: Make a auth::create_user return values from auth::registration::Register. TODO: Make the auth::create_user proc honor site-wide setting for which external authority to create account in. Holding off on this feature for now. TODO: New procs: auth::registration::get_required_attributes auth::registration::get_optional_attributes ad_proc -public auth::create_user { {-username:required} {-password:required} {-first_names ""} {-last_name ""} {-email ""} {-url ""} {-secret_question ""} {-secret_answer ""} } { @param authority_id The id of the authority to create the user in. Defaults to the authority with lowest sort_order that has register_p set to true. } { set authorities_list [list] # Always register the user locally lappend authorities_list [auth::authority::local] # Default authority_id if none was provided if { [empty_string_p $authority_id] } { # Pick the first authority that can create users set authority_id [db_string first_registering_authority { select authority_id from auth_authorities where register_p = 't' and sort_order = (select max(sort_order) from auth_authorities where register_p = 't' ) } -default ""] if { [empty_string_p $authority_id] } { error "No authority_id provided and could not find an authority that can create users" } lappend authorities_list $authority_id } # Register the user both with the local authority and the external one db_transaction { foreach authority_id $authorities_list { auth::registration::Register \ -authority_id $authority_id \ -username $user_name \ -password $password \ -first_names $first_names \ -last_name $last_name \ -email $email \ -url $url \ -secret_question $secret_question \ -secret_answer $secret_answer } } } ad_proc -private auth::registration::Register { {-authority_id:required} {-username:required} {-password:required} {-first_names ""} {-last_name ""} {-email ""} {-url ""} {-secret_question ""} {-secret_answer ""} } { Invoke the Register service contract operation for the given authority. @authority_id Id of the authority. Defaults to local authority. @url Any URL (homepage) associated with the new user @secret_question Question to ask on forgotten password @secret_answer Answer to forgotten password question } { if { [empty_string_p $authority_id] } { set authority_id [auth::authority::local] } # TODO: # Implement parameters return [acs_sc::invoke \ -contract "auth_registration" \ -impl [auth::authority::get_element -authority_id $authority_id -element "auth_impl_name"] \ -operation Register \ -call_args [list [list] \ $username \ $authority_id \ $first_names \ $last_name \ $email \ $url \ $password \ $secret_question \ $secret_answer]] } EXT-AUTH #4: Rewrite login & register pagse to use APIs EXT-AUTH #4: Rewrite login & register pages to use APIs Current Design Login is handled by acs-subsite/www/register/index.tcl and user-login.tcl without use of an API. All the logic is in the pages. Registration is handled by acs-subsite/www/register/user-new.tcl. Again, all logic is in the pages. External Design We will have to rewrite the following pages: User login: /register/index User registration: /register/user-add Admin: /acs-admin/users/user-add, which includes user-new (which can then be included on other pages as well) Bulk: /acs-admin/users/user-batch-add Authentication of users is handled by the auth::authenticate proc and registration by the auth::local::register proc. The code to handle the login process in /register/index.tcl would look like this: ad_form -name user_add -form { {authority_id:integer(hidden)} {username:text} {email:text} {password} } -on_submit { if { [parameter::get -parameter UsernameIsEmail] == 't' } { set email $username } array set auth_info [auth::authenticate \ -authority_id $authority_id \ -username $username \ -password $password] # Handle authentication problems switch $auth_info(auth_status) { ok { # Continue below } bad_password { } no_account { } auth_error { } default { } } # TODO: form builder validation of auth_status # Handle account status switch $auth_info(account_status) { ok { # Continue below } default { } } # TODO: form builder validation of account_status # We're logged in ad_returnrediredt $return_url ad_script_abort } The code to handle the registration process is in user-new.tcl would look like this: array set registratoin_info [auth::register \ -authority_id $authority_id \ -username $username \ -password $password \ -first_names $first_names \ -last_name $last_name \ -email $email \ -url $url \ -secret_question $secret_question \ -secret_answer $secret_answer] # Handle registration problems switch $registratoin_info(reg_status) { ok { # Continue below } default { } } # User is registered and logged in ad_returnrediredt $return_url Page Flow User is redirected to /register/index.tcl if login is required (i.e. auth::require is specified) and the login is taken care of by user-login.tcl. If user not registered (i.e. $auth_info(account_status) == "no_account" ), user is redirected to user-register.tcl. Error Handling <literal>auth::authenticate </literal> Returns the array element auth_status, which can either be: ok: login was successful, continue bad_password: Username is correct, password is wrong, redirect to bad-password, display auth_message no_account: Username not found, redirect to user-new, display auth_message auth_error: Authentication failed, display auth_message, display auth_message failed_to_connect: The driver didn't return anything meaningful, display error message Also account_status is returned, which can either be: ok: login was successful, continue closed,permanently: account permanently closed, redirect to account_closed, display error message No match: account_status doesn't match any of the above, display error message <literal>auth::register </literal> Returns the array element reg_status, which can either be: ok: Registration was successful, continue failed: Registration failed, display reg_message No match: reg_status doesn't match any of the above, display error message Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT-AUTH #5: Password Management API Current Design proc "ad_change_password" updates a user's password. Other password update/retrieval/reset functionality is hard-coded in the pages. TODO Decide on generic "failed-to-connect" and "connected, but auth server returned unknown error". Test cases Execution Story User login scenario: The login page will have a link to assistance with forgotten passwords ("Forgot your password?"). The URL of that link is determined as follows: auth_authority.forgotten_pwd_url Otherwise, if the authority's pwd mgmt driver's CanRetrievePassword or CanRetrievePassword returns "Yes", we offer a link to the OpenACS forgotten-password page, query vars authority_id, maybe username. Otherwise, no forgotten password link. The OpenACS forgotten-password page may require the user to fill in question/answer fields. These will be the OpenACS question/answers only, we do not support question/answers from external authentication servers. The email is reset or retrieved. The new password will be emailed to the user, either by the driver or by the authentication API (i.e., from one or the other side of the service contract). User changes password scenario: User visits "My Account" "My Account" will provide a link to changing the user's password as follows: If the authority has a 'change_pwd_url' defined, we'll offer a "Change my password" link that goes there. Otherwise, if the authority driver's CanChangePassword returns "Yes", we'll offer a "Change my password" link that goes to the normal OpenACS change password page. Otherwise, no "Change my password" link. The change password page will call the Password Management API to change the password. External Design ad_proc -public auth::password::get_change_url { {-user_id:required} } { Returns the URL to redirect to for changing passwords. If the user's authority has a "change_pwd_url" set, it'll return that, otherwise it'll return a link to /user/password-update under the nearest subsite. @param user_id The ID of the user whose password you want to change. @return A URL that can be linked to for changing password. } - ad_proc -public auth::password::can_change_p { {-user_id:required} } { Returns whether the given user change password. This depends on the user's authority and the configuration of that authority. @param user_id The ID of the user whose password you want to change. @return 1 if the user can change password, 0 otherwise. } { # Implementation note: # Calls auth::password::CanChangePassword(authority_id) for the user's authority. } ad_proc -public auth::password::change { {-user_id:required} {-old_password:required} {-new_password:required} } { Change the user's password. @param user_id The ID of the user whose password you want to change. @param old_password The current password of that user. This is required for security purposes. @param new_password The desired new password of the user. @return An array list with the following entries: <ul> <li> password_status: "ok", "no_account", "old_password_bad", "new_password_bad", "error" </li> <li> password_message: A human-readable description of what went wrong. </li> </ul> } { # Implementation note # Calls auth::password::ChangePassword(authority_id, username, old_password, new_password) for the user's authority. } ad_proc -public auth::password::get_forgotten_url { {-authority_id:required} } { Returns the URL to redirect to for forgotten passwords. If the user's authority has a "forgotten_pwd_url" set, it'll return that, otherwise it'll return a link to /register/email-password under the nearest subsite. @param authority_id The ID of the authority that the user is trying to log into. @return A URL that can be linked to when the user has forgotten his/her password. } - ad_proc -public auth::password::can_retrieve_p { {-authority_id:required} } { Returns whether the given authority can retrive forgotten passwords. @param authority_id The ID of the authority that the user is trying to log into. @return 1 if the authority allows retrieving passwords, 0 otherwise. } { # Implementation note # Calls auth::password::CanRetrievePassword(authority_id) for the user's authority. } ad_proc -public auth::password::retrieve { {-user_id:required} } { Retrieve the user's password. @param user_id The ID of the user whose password you want to retrieve. @return An array list with the following entries: <ul> <li> password_status: "ok", "no_account", "not_implemented", "error" </li> <li> password_message: A human-readable description of what went wrong, if password_status is not "ok". Not set if password_status is "ok". </li> <li> password: The retrieved password. </li> </ul> } { # Implementation note # Calls auth::password::RetrievePassword(authority_id, username) for the user's authority. } ad_proc -public auth::password::can_reset_p { {-authority_id:required} } { Returns whether the given authority can reset forgotten passwords. @param authority_id The ID of the authority that the user is trying to log into. @return 1 if the authority allows resetting passwords, 0 otherwise. } { # Implementation note # Calls auth::password::CanResetPassword(authority_id) for the user's authority. } ad_proc -public auth::password::reset { {-user_id:required} } { Reset the user's password, which means setting it to a new randomly generated password and informing the user of that new password. @param user_id The ID of the user whose password you want to reset. @return An array list with the following entries: <ul> <li> password_status: "ok", "no_account", "not_implemented", "error" </li> <li> password_message: A human-readable description of what went wrong, if password_status is not "ok". Not set if password_status is "ok". </li> <li> password: The new, automatically generated password. If no password is included in the return array, that means the new password has already been sent to the user somehow. If it is returned, it means that caller is responsible for informing the user of his/her new password.</li> </ul> } { # Implementation note # Calls auth::password::ResetPassword(authority_id, username) for the user's authority. } Implementation Details Create auth::password::CanChangePassword and friends wrappers that take authority_id plus specific parameters for the service contract call, finds the relevant service contract implementation, and calls that. Error Handling Error codes are defined in the API stubs above. This API should check for bad return codes, drivers throwing Tcl errors, and timeout, and replace with "failed-to-connect" error. Related Stories #19 covers password recovery pages (and should also include change password pages). Info about these pages belong in that story. This section belongs there: Pages: acs-subsite/www/register/bad-password acs-subsite/www/register/email-password (-2, -3) acs-subsite/www/user/password-update (-2) #29, service contract for password mgmt, will have to change as implied by the return values of this API. #9, local authentication driver, should take this section into account: Parameters: acs-subsite.EmailForgottenPasswordP acs-subsite.RequireQuestionForPasswordReset acs-subsite.UseCustomQuestionForPasswordReset Time Tracking Design: 2 hours Estimated hours remaining: 4 hours EXT-AUTH #8: Automating Batch Synchronization Execution Story User goes to Administration. Visits site-wide admin pages. Link says "Authentication Management". The link goes to a list of known domains. For each domain, a page: Local Authority Administration ... other stuff ... Enable/Disable nightly batch Status of last run B: history of previous runs (30 days?) Tradeoffs Which one or two of the following are emphasised in this design? Performance: availability and efficiency Reliability and robustness External Design Administration auth::authority::enable_batch_sync -authority_id integer . This API toggles the value of batch_sync_enabled_p column in ?some_table?. Returns 1 or 0. Scheduled proc auth::batch_sync_sweeper . Runs every night. Runs through all enabled and batch-enabled authorities and calls auth::authority::batch_sync -authority_id integer . Internal Design Administration ad_proc -public auth::authority::enable_batch_sync { -authority_id } { db_dml toggle_enbaled_p { update some_table set batch_sync_enabled_p = 't' where authority_id = :authority_id } } Scheduled proc: ad_proc -public auth::batch_sync_sweeper {} { db_foreach select_authorities { select authority_id from auth_authorities where active_p = 't' and batch_sync_enabled_p = 't' } { auth::authority::batch_sync -authority_id $authority_id } } ad_proc -public auth::authority::batch_sync { -authority_id } { set driver [auth::get_driver -authority $authority] acs_sc::invoke $driver Synchronize -authority $authority } Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT-AUTH #9: Create Authentication drivers for Local Authority External Design auth::authenticate calls auth::authentication::Authenticate which invokes the service contract implementation for the authority. Returns: auth_status: "ok", "bad_password", "no_account", "auth_error", "failed_to_connect" auth_message: Message to the user. account_status: "ok", "closed" account_message: Message to the user. account_status and account_message are only set if auth_status is "ok". Internal Design ad_proc -private auth::authentication::Authenticate { {-authority_id ""} {-username:required} {-password:required} } { Invoke the Authenticate service contract operation for the given authority. @param username Username of the user. @param password The password as the user entered it. @param authority_id The ID of the authority to ask to verify the user. Leave blank for local authority. } { if { [empty_string_p $authority_id] } { set authority_id [auth::authority::local] } # TODO: # Implement parameters return [acs_sc::invoke \ -contract "auth_authentication" \ -impl [auth::authority::get_element -authority_id $authority_id -element "auth_impl_name"] \ -operation Authenticate \ -call_args [list $username $password [list]]] } ad_proc -private auth::local::authentication::Authenticate { username password {parameters {}} } { Implements the Authenticate operation of the auth_authentication service contract for the local account implementation. } { array set auth_info [list] # TODO: username = email parameter ... set username [string tolower $username] set authority_id [auth::authority::local] set account_exists_p [db_0or1row select_user_info { select user_id from cc_users where username = :username and authority_id = :authority_id }] if { !$account_exists_p } { set auth_info(auth_status) "no_account" return [array get auth_info] } if { [ad_check_password $user_id $password] } { set auth_info(auth_status) "ok" } else { if { [parameter::get -parameter EmailForgottenPasswordP] == 't' } { set auth_info(auth_status) "bad_password" ... display link... } else { set auth_info(auth_status) "bad_password" } return [array get auth_info] } # We set 'external' account status to 'ok', because the # local account status will be checked anyways set auth_info(account_status) ok return [array get auth_info] } Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT-AUTH #10: Create Account Creation drivers for Local Authority External Design auth::registration::Register returns: creation_status creation_message element_messages account_status account_message Internal Design ad_proc -private auth::registration::Register { {-authority_id:required} {-username:required} {-password:required} {-first_names ""} {-last_name ""} {-email ""} {-url ""} {-secret_question ""} {-secret_answer ""} {-parameters ""} } { Invoke the Register service contract operation for the given authority. } { if { [empty_string_p $authority_id] } { set authority_id [auth::authority::local] } return [acs_sc::invoke \ -contract "auth_registration" \ -impl ??? \ -operation Register \ -call_args [list ???]] } ad_proc -private auth::local::registration::Register { parameters username authority_id first_names last_name email url password secret_question secret_answer } { Implements the Register operation of the auth_register service contract for the local account implementation. } { array set result { creation_status "reg_error" creation_message {} element_messages {} account_status "ok" account_message {} } # TODO: email = username # TODO: Add catch set user_id [ad_user_new \ $email \ $first_names \ $last_name \ $password \ $question \ $answer \ $url \ $email_verified_p \ $member_state \ "" \ $username \ $authority_id] if { !$user_id } { set result(creation_status) "fail" set result(creation_message) "We experienced an error while trying to register an account for you." return [array get result] } # Creation succeeded set result(creation_status) "ok" # TODO: validate data (see user-new-2.tcl) # TODO: double-click protection # Get whether they requre some sort of approval if { [parameter::get -parameter RegistrationRequiresApprovalP -default 0] } { set member_state "needs approval" set result(account_status) "closed" set result(account_message) [_ acs-subsite.lt_Your_registration_is_] } else { set member_state "approved" } set notification_address [parameter::get -parameter NewRegistrationEmailAddress -default [ad_system_owner]] if { [parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0] } { set email_verified_p "f" set result(account_status) "closed" set result(account_message) "[_ acs-subsite.lt_Registration_informat_1][_ acs-subsite.lt_Please_read_and_follo]" set row_id [db_string rowid_for_email { select rowid from users where user_id = :user_id }] # Send email verification email to user set confirmation_url "[ad_url]/register/email-confirm?[export_vars { row_id }]" with_catch errmsg { ns_sendmail \ $email \ $notification_address \ "[_ acs-subsite.lt_Welcome_to_system_nam]" \ "[_ acs-subsite.lt_To_confirm_your_regis]" } { ns_returnerror "500" "$errmsg" ns_log Warning "Error sending email verification email to $email. Error: $errmsg" } } else { set email_verified_p "t" } # Send password/confirmail email to user if { [parameter::get -parameter RegistrationProvidesRandomPasswordP -default 0] || \ [parameter::get -parameter EmailRegistrationConfirmationToUserP -default 0] } { with_catch errmsg { ns_sendmail \ $email \ $notification_address \ "[_ acs-subsite.lt_Welcome_to_system_nam]" \ "[_ acs-subsite.lt_Thank_you_for_visitin]" } { ns_returnerror "500" "$errmsg" ns_log Warning "Error sending registration confirmation to $email. Error: $errmsg" } } # Notify admin on new registration if {[parameter::get -parameter NotifyAdminOfNewRegistrationsP -default 0]} { with_catch errmsg { ns_sendmail \ $notification_address \ $email \ "[_ acs-subsite.lt_New_registration_at_s]" \ "[_ acs-subsite.lt_first_names_last_name]" } { ns_returnerror "500" "$errmsg" ns_log Warning "Error sending admin notification to $notification_address. Error: $errmsg" } } return [array get result] } Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT AUTH #11: Create Auth driver for PAM Execution Story When a user authenticates against an authority which uses PAM, the PAM authentication driver will be invoked. Tradeoffs Reliability, robustness, portability. External Design Will implement the authentication service contract. Parameters: Don't know. Internal Design Mat Kovach will implement a thread-safe ns_pam AOLserver module in C, which will provide a Tcl interface to PAM. We'll write the service contract implementation in Tcl as a wrapper for the ns_pam calls. Test Cases Set up authentication against /etc/passwd on cph02 and test that we can log in with our cph02 usernames and passwords. Using PAM driver without having the ns_pam C module loaded. Error Handling Need to catch timeouts and communications errors and pass them on to the caller. Estimate Mat says: 20 hours x USD 50/hr = USD 1,000. We need to sort out with Mat what happens if it takes him longer (or shorter). Adding the service contract wrappers for authentication and password management: 8 hours. EXT AUTH #14: Create authentication driver for LDAP Status ON HOLD awaiting info from clients on whether we can use PAM instead of talking directly to the LDAP server, or how we should implement this. Execution Story When a user authenticates against an authority which uses LDAP, the LDAP authentication driver will be invoked. Tradeoffs Reliability, robustness, portability. External Design Will implement the authentication service contract. Parameters: Don't know. Internal Design We'd look at the extisting ns_ldap module, or we'd find someone to implement a new thread-safe ns_ldap AOLserver module in C, which will provide a Tcl interface to the parts of LDAP which we need. We'll write the service contract implementation in Tcl as a wrapper for the ns_ldap calls. Test Cases Set up an LDAP server, and configure authentication against that. Using LDAP driver without having the ns_ldap C module loaded. Error Handling Need to catch timeouts and communications errors and pass them on to the caller. Estimate Implementing ns_ldap: unknown. Adding the service contract wrappers for authentication and password management: 8 hours. EXT-AUTH-16: Authentication Service Contract (1 hour) by Peter Marklund Already done by Lars. We should ocument which messages can/should be HTML and which should be plain text and in general try to document expected values of return variables more clearly. by Peter Marklund EXT-AUTH-17: Account Creation Service Contract (1 hour) by Peter Marklund Already done by Lars. Todo: improve documentation of return values. by Peter Marklund EXT-AUTH-18: Authority Configuration Data Model (2 hours) by Peter Marklund The table auth_authorities already exists in acs-kernel for Oracle. We need to create the table for PostgreSQL and provide upgrade scripts. Rename column auth_p authenticate_p for readability and clarity? Change column name active_p to enabled_p. TODO: new column: help_contact_text with contact information (phone, email, etc.) to be displayed as a last resort when people are having problems with an authority. create table auth_authorities ( authority_id integer constraint auth_authorities_pk primary key, short_name varchar2(255) constraint auth_authority_short_name_un unique, pretty_name varchar2(4000), active_p char(1) default 't' constraint auth_authority_active_p_nn not null constraint auth_authority_active_p_ck check (active_p in ('t','f')), sort_order integer not null, -- authentication auth_impl_id integer constraint auth_authority_auth_impl_fk references acs_sc_impls(impl_id), auth_p char(1) default 't' constraint auth_authority_auth_p_ck check (auth_p in ('t','f')) constraint auth_authority_auth_p_nn not null, -- password management pwd_impl_id integer constraint auth_authority_pwd_impl_fk references acs_sc_impls(impl_id), -- Any username in this url must be on the syntax username={username} -- and {username} will be replaced with the real username forgotten_pwd_url varchar2(4000), change_pwd_url varchar2(4000), -- registration register_impl_id integer constraint auth_authority_reg_impl_fk references acs_sc_impls(impl_id), register_p char(1) default 't' constraint auth_authority_register_p_ck check (register_p in ('t','f')) constraint auth_authority_register_p_nn not null, register_url varchar2(4000) ); EXT-AUTH #19: Rewrite password recovery to use API Current Design Password recovery is currently handled by /register/email-password.tcl, email-password-2.tcl and email-password-3.tcl. All logic is placed in the pages. Execution Story User is prompted for login, but types in a bad password. The CanRetrievePassword service contract is called if retrieving passwords is allowed user is redirected to bad-password.tcl Here the RetrievePassword service contract is called, which returns successful_p, password, message If password is empty and successful_p is true, the authority server has send out the verification email. If successful and password is not empty, we email the user and ask for verification. External Design auth::password::CanResetPassword .Input: driver Output: 1 or 0 auth::password::ResetPassword .Input: username, parameters.Output: successful_p: boolean, password (or blank, if the server sends the user its new password directly), message: To be relayed to the user. auth::password::CanRetrievePassword .Input: driver Output: 1 or 0 auth::password::RetrievePassword .Input: usernameOutput: retrievable_p: boolean, message: Instruct the user what to do if not. auth::password::CanChangePassword Input: driverOutput:True or false. auth::password::ChangePassword Input: username, old_password, new_passwordOutput: new_password The logic of bad-password will be moved into /register/index as part of ad_form, but the logic should look like something along the lines of: set user_id [ad_conn] set authority_id [auth::authority -user_id $user_id] set driver [auth::get_driver -authority $authority] set retrieve_password_p [auth::password::CanRetrievePassword -driver $driver] set reset_password_p [auth::password::CanResetPassword -driver $driver] If $retrieve_password_p and $reset_password_p is true, this text will be displayed: "If you've forgotten your password, you can ask this server to reset your password and email a new randomly generated password to you ." And email-password, should look something like this: # Fetch the username. What proc should we use? set username [auth::username] # Reset password auth::password::ResetPassword -username $username set subject "[_ acs-subsite.lt_Your_forgotten_passwo]" # SIMON: how does the password get inserted here? # Should make use of auth::password::RetrievePassword set body "[_ acs-subsite.lt_Please_follow_the_fol]" # Send email if [catch {ns_sendmail $email $system_owner $subject $body} errmsg] { ad_return_error \ "[_ acs-subsite.Error_sending_mail]" \ "[_ acs-subsite.lt_Now_were_really_in_tr] <blockquote> <pre> $errmsg </pre> </blockquote> [_ acs-subsite.lt_when_trying_to_send_y] <blockquote> <pre> [_ acs-subsite.Subject] $subject $body </pre> </blockquote> " return } We'll want to add a check for CanChangePassword in /pvt/home. Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT AUTH #20: Login pages over HTTPS Current Design Current login pages are over HTTP. Just bashing them to be HTTPS has these issues: Browsers will not send cookies over HTTP that were received over HTTPS. If images on the login page are over HTTP and not HTTPS, browsers will warn that you're seeing unsecure items as part of a secure web page, which is annoying and unprofessional. Browsers may also give a warning when redirecting back to the normal pages not over HTTPS. Execution Story Beginning with a human being using a computer, describe how the feature is triggered and what it does. As this story becomes more detailed, move pieces to appropriate parts of the document. Tradeoffs Security, Reliability and robustness. External Design Parameters: acs-kernel.RegisterRestrictToSSLFilters: If set to 0, we don't restrict any URLs to HTTPs. acs-subsite.RestrictToSSL: A Tcl list of URL patterns under the given subsite to restrict to SSL, e.g. "admin/* register/*". Currently defaults to "admin/*". Only takes effect if SSL is installed, and acs-kernel.RegisterRestrictToSSLFilters is set to 1. To do Install SSL on a development server and integration server. Try setting RestrictToSSL to "admin/* register/*" and test what happens. Identify and fix issues that show up. Time Estimate Original estimate: 8 hours. Hours spent: 0.25 Estimated hours remaining: Risk: EXT-AUTH #24: Email on password change Execution story User: User visits /pvt/home Clicks "Change my Password" Enters password User is redirected to /pvt/home Email goes out Admin: () Internal Design We'll first want to check whether changing the password is allowed: set user_id [ad_conn user_id] set authority [auth::authority -user_id $user_id] set driver [auth::get_driver -authority $authority] set change_password_p [auth::password::CanChangePassword -driver $driver] If $change_password_p is true, we'll display the "Change my password" link on /pvt/home. update-password would look something like this: if {![db_0or1row select_email {}]} { db_release_unused_handles ad_return_error "[_ acs-subsite.lt_Couldnt_find_user_use]" "[_ acs-subsite.lt_Couldnt_find_user_use_1]" return } set system_owner [ad_system_owner] set subject "some other i18n key msg" set body "some other i18n key msg" # Send email if [catch {ns_sendmail $email $system_owner $subject $body} errmsg] { ad_return_error \ "[_ acs-subsite.Error_sending_mail]" \ "[_ acs-subsite.lt_Now_were_really_in_tr] <blockquote> <pre> $errmsg </pre> </blockquote> [_ acs-subsite.lt_when_trying_to_send_y] <blockquote> <pre> [_ acs-subsite.Subject] $subject $body </pre> </blockquote> " return } Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT AUTH #25: Password Policy Current Design This has already been implemented on oacs-4-6 branch. Expiration of passwords: Password must be changed after a certain number of days. No password history, though. Approval expiration: If a user is approved but doesn't log on before a certain number of days, his approval will expire. To do Merge changes from oacs-4-6 onto HEAD. (Commits made around June 6). Sort out the upgrade script sequence. Time Estimate Original estimate: 6 hours. Hours spent: Estimated hours remaining: Risk: Who's online list Execution Story A page showing who has requested a page during the last 5 minutes. Could be integrated with a chat or instant messaging service. Internal Design We keep a record of which authenticated users have requested pags on the site in the last x minutes (typically about 5), and thus are considered to be currently online. We've already made the changes necessary to security-procs.tcl to do this on an earlier project, but haven't quite finished the work and put it back into the tree. Lars? Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT AUTH #28: Create Service Contract for Batch Sync Status NOTE: We'll need to keep a pretty close transaction log of any action taken during batch sync, and also offer a mechanism for storing transactions that couldn't be completed for some reason, e.g. email address already taken, etc., email the admin, offer a list of transactions that failed for manual resolution by an admin. Design To Do/Notes Performance criteria: Nightly batch run should be able to complete within 3 hours with 10,000 users. We'll want to design an API for an incremental or snapshot run to call, which takes care of all the updating, logging, error handling, emailing admins, etc. We need examples of how the communication would be done from our clients. We might need a source/ID column in the users table to identify where they're imported from for doing updates, particularly if importing from multiple sources (or when some users are local.) Current Design None. Execution Story This is executed in background thread, typically nightly. There's also a link from the authority administration page to run the batch synchronization immediately. The process runs like this: OpenACS retrieves a document from the enterprise server containing user information. Example mechanisms: A file is delivered to an agreed-on location in the file system at an agreed-on point in time. OpenACS does a normal HTTP request to a remote server, which returns the document. OpenACS does a SOAP (Web Service) request to a remote server, which returns the document. OpenACS retrieves a file from an SMB server or an FTP server. The document will contain either the complete user list (IMS: "snapshot"), or an incremental user list (IMS: "Event Driven" -- contains only adds, edits, updates). You could for example do a complete transfer once a month, and incrementals every night. The invocation should decide which type is returned. The document will be in an agreed-on format, e.g. an XML format based on the IMS Enterprise Specification (example XML document Tradeoffs The design should favor interoperability, reliability and robustness. External Design NOTE: Do we really want to do this as service contracts? We might be better off getting one implementation running, and only do the service contract when we're certain what it would look like. TODO: Look at how Blackboard and other systems implements this, specifically how do they get the data out of the other system. Which enterprise servers already support the IMS Enterprise specification? TODO: Find out if Greenpeace needs an different exchange format from IMS Enterprise, given that they're not in the University business. Service contract for retrieving the document: GetDocument ( type: 0 = snapshot 1 = incremental since: date that you want the incremental update since? parameters: values of implementation-specific parameters ): document as string Performs the request necessary to get a document containing enterprise information. GetParameters ( ): list of parameters specific to this implementation. Parameters would typically be the URL to make a request to. Service contract for processing the document: ProcessDocument ( type: 0 = snapshot 1 = incremental since: date that you want the incremental update since? document: the document containing either incremental or snapshot of enterprise data. parameters: values of implementation-specific parameters ): document as string Processes the document and updates the OpenACS users and other tables appropriately. GetParameters ( ): list of parameters specific to this implementation. Not sure what parameters would be. It looks like we'll use the IMS standard for formatting of the doucment, but not so Standards Consolidation before the leap; IMS Enterprise 1.1 : This sect2 says that IMS Enterprise 1.1 (current version) does not address the communication model, which is critically missing for real seamless interoperability. IMS Enterprise 2.0 will address this, but Blackboard, who's influential in the IMS committee, is adopting OKI's programming interrfaces for this. IMS and OKI, the wire and the socket Page Flow For features with UI, a map of all pages, showing which pages can call others, which are includeable, etc. For each page, show all UI elements on the page (text blocks, forms, form controls). Include administration functionality. Internal Design Describe key algorithms, including pseudo-code. Data Model Describe data model changes. Error Handling What error codes or error conditions could result? How are they handled? Upgrade Describe in pseudo-code how upgrade will be implemented. EXT-AUTH-29: Password Management Service Contract (1 hour) by Peter Marklund Already done by Lars. Todo: improve documentation of return values. by Peter Marklund EXT-AUTH #30: Create Authority Management API External Design We'll want an API that lets us add authorities: auth::authority::new delete authorities: auth::authority::delete and edit authorities: auth::authority::edit authorities. Here goes: Internal Design ad_proc -public auth::authority::new { {-authority_id:required} {-short_name:required} {-pretty_name:required} {-sort_order:required} {-auth_impl_id:required} {-auth_p:required} {-pwd_impl_id:required} {-forgotten_pwd_url:required} {-change_pwd_url:required} {-register_impl_id:required} {-register_p:required} {-register_url:required} } { db_dml new_authority { insert into auth_authorities ( authority_id, short_name, pretty_name, active_p, sort_order, auth_impl_id, auth_p, pwd_impl_id, forgotten_pwd_url, change_pwd_url, register_impl_id, register_p, register_url ) values ( :authority_id, :short_name, :pretty_name, 1, :sort_order, :auth_impl_id, :auth_p, :pwd_impl_id, :forgotten_pwd_url, :change_pwd_url, :register_impl_id, :register_p, :register_url ) } } ad_proc -public auth::authority::delete { {-authority_id:requied} } { db_exec delete_authority { delete from auth_authorities where authority_id = :authority_id } } ad_proc -public auth::authority::edit { {-authority_id:required} {-short_name:required} {-pretty_name:required} {-active_p:required} {-sort_order:required} {-auth_impl_id:required} {-auth_p:required} {-pwd_impl_id:required} {-forgotten_pwd_url:required} {-change_pwd_url:required} {-register_impl_id:required} {-register_p:required} {-register_url:required} } { db_exec edit_authority { update auth_authorities set short_name = :short_name, pretty_name = :pretty_name, active_p = :active_p, sort_order = :sort_order, auth_impl_id = :auth_impl_id, auth_p = :auth_p, pwd_impl_id = :pwd_impl_id, forgotten_pwd_url = :forgotten_pwd_url, change_pwd_url = :change_pwd_url, register_impl_id = :register_impl_id, register_p = :register_p, register_url = :register_url where authority_id = :authority_id } } Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: EXT-AUTH-31: External Authentication Datamodel (2 hours) by Peter Marklund The columns authority_id and username have been added to the users table for Oracle. We need to add them for PostgreSQL and provide upgrade scripts. create table users ( user_id not null constraint users_user_id_fk references persons (person_id) constraint users_pk primary key, authority_id integer constraint users_auth_authorities_fk references auth_authorities(authority_id), username varchar2(100) constraint users_username_nn not null, screen_name varchar2(100) constraint users_screen_name_un unique, priv_name integer default 0 not null, priv_email integer default 5 not null, email_verified_p char(1) default 't' constraint users_email_verified_p_ck check (email_verified_p in ('t', 'f')), email_bouncing_p char(1) default 'f' not null constraint users_email_bouncing_p_ck check (email_bouncing_p in ('t','f')), no_alerts_until date, last_visit date, second_to_last_visit date, n_sessions integer default 1 not null, -- local authentication information password char(40), salt char(40), password_question varchar2(1000), password_answer varchar2(1000), -- table constraints constraint users_authority_username_un unique (authority_id, username) ); by Peter Marklund EXT AUTH #32: Service Contract Implementation Parameters Execution Story When the administrator configures an authority to use a specific service contract implementation, e.g. PAM, that implementation can say which parameters it supports, e.g. Host, Port, Root node, etc. The administrator will specify values for these parameters as part of configuring the authority. These parameter values will be passed along to the service contract implementation when its methods get called. Tradeoffs Flexibility, usability. External Design We're considering whether to implement a very simple solution a' la current package parameters, or a general configuration solution as outlined in the Configurator Spec . Data Model Simple solution: A table with key/value pairs attached to the auth_authorities table. Time Estimate Original estimate, simple solution: 8 hours Original estimate, complex solution: 50 hours Hours spent: Estimated hours remaining: Risk: OACS-COL-1: Automate install and self-test (5 hours) by Peter Marklund I need to make sure the install scripts work. I then need to: Schedule nightly recreation Make sure the install script invokes acs-automated-testing tests and checks results Make sure emails go out to appropriate people by Peter Marklund EXT AUTH #x: Title of feature Current Design Describe how any functionality to be replaced works. Execution Story Beginning with a human being using a computer, describe how the feature is triggered and what it does. As this story becomes more detailed, move pieces to appropriate parts of the document. Tradeoffs Which one or two of the following are emphasised in this design? Performance: availability and efficiency Flexibility Interoperability Reliability and robustness Usability Maintainability Portability Reusability Testability External Design For a feature with a public API, write the stub for each procedure, showing all parameters, a preliminary description of instructions, and expected return. For a feature without a public API, describe how the feature is invoked. Include admin-configurable parameters. Page Flow For features with UI, a map of all pages, showing which pages can call others, which are includeable, etc. For each page, show all UI elements on the page (text blocks, forms, form controls). Include administration functionality. Internal Design Describe key algorithms, including pseudo-code. Data Model Describe data model changes. Error Handling What error codes or error conditions could result? How are they handled? Upgrade Describe in pseudo-code how upgrade will be implemented. Time Estimate Original estimate: Hours spent: Estimated hours remaining: Risk: openacs-5.7.0/packages/acs-core-docs/www/xml/index.xml0000644000175000017500000004436710456621135022471 0ustar frankiefrankie %myvars; ]> OpenACS Core Documentation OpenACS For Everyone High level information: What is OpenACS? Overview OpenACS (Open Architecture Community System) is an advanced toolkit for building scalable, community-oriented web applications. If you're thinking of building an enterprise-level web application, OpenACS is a solid, scalable framework for building dynamic content driven sites. OpenACS is a collection of pre-built applications and services that you can use to build your web site/application. Through a modular architecture, OpenACS has packages for user/groups management, content management, e-commerce, news, FAQs, calendar, forums, bug tracking, full-text searching, and much more. OpenACS relies on AOLserver, the free, multithreaded, scalable, Tcl-enabled, web/application server used by America Online for most of its web sites, and a true ACID-compliant Relational Database Management System (RDBMS). Currently OpenACS supports PostgreSQL, an open source RDBMS, and Oracle and is easily extensible to other databases which support a comparable feature set. The OpenACS toolkit is derived from the ArsDigita Community System (ACS). ArsDigita (now part of Red Hat, Inc.) kindly made their work available under the GPL, making all of this possible. The OpenACS project was born when Don Baccus, Ben Adida, and others decided to port ACS from Oracle to PostgreSQL, thus making it a fully open-source solution. With OpenACS 4, Oracle and PostgreSQL support were combined in one code base and with OpenACS 5, support for internationalization and localization has been added. A vibrant and productive community has sprung up around the OpenACS software and there are many volunteer contributors as well as a commercial companies able to provide support, hosting, and custom development. Many of the production users are actively funding and contributing work back to the project. Formal, consensus driven governance has been established (with semi-annual elections) which ensures the project serves the needs of it's constituents. The OpenACS community would like to hear your comments and can help you in your endeavors with the system. Visit our web site and feel free to ask questions or provide feedback. Release Notes Section Missing Administrator's Guide Installation Overview by Vinod Kurup Overview Section Missing Section Missing Complete Installation Section Missing Section Missing Section Missing Section Missing Section Missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Credits Section Missing For OpenACS Package Developers Tutorials and reference material for creating new OpenACS packages. Development Tutorial Section missing Section missing Section missing Section missing Section missing Development Reference Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Engineering Standards Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Documentation Standards Section missing Section missing Section missing Section missing Section missing Section missing CVS Section missing For OpenACS Platform Developers Kernel Documentation Overview The OpenACS Kernel, which handles system-wide necessities such as metadata, security, users and groups, subsites, and package management and deployment. The OpenACS Core, which comprises all the other packages that ship with the kernel and are most frequently needed by users, such as templating, forums, and user registration/management. The packages tend to be developed and distributed with the kernel. OpenACS Application packages, which typically provide user-level web services built on top of the Kernel and Core. Application packages are developed separately from the Kernel, and are typically released independently of it. This document provides a high level overview of the kernel package. Documentation for other packages on this server Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing Section missing 'Releasing OpenACS' missing openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/0000755000175000017500000000000011724401447024066 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/packages.xml0000644000175000017500000007571510456621135026404 0ustar frankiefrankie %myvars; ]> OpenACS Packages By Pete Su and Bryan Quinn Overview This document is a guide on how to write a software package for OpenACS. OpenACS packages are installed and maintained with the OpenACS Package Manager (APM) which is part of the acs-admin package. This document presents reasons for packaging software, conventions for the file system and naming that must be followed, and step by step instructions for creating a new package for the "Notes" example package. Server file layout Here is how an OpenACS &majorversion; server is laid out starting from the Server root (ROOT):
    Server file layout diagram ROOT/ bin/ Various executables and scripts for server maintanence. content-repository-content-files/ content repository content stored in the filesystem. etc/ Installation scripts and configuration files. packages/ acs-admin/ acs-api-browser/ ... many many more... workflow/ log/ Server error and access logs tcl/ bootstrap code www/ Pages not in packages (static content, customized pages)
    What a Package Looks Like Each package encapsulates all of its data model, library code, logic, adminstration pages and user pages in a single part of the file tree. This means developers can track down everything that is related to a particular package without hunting all over the file system. Encapsulating everything about a package in one place also makes it much easier to distribute packages independently from the OpenACS Core. In order to make this work, we need a system that keeps track of the packages that have been installed in the server, where those packages have been installed, and a standard way to map URLs that a client sends to our server to the right page in the appropriate package. While we're at it, this tool should also automate package installation, dependency checking, upgrades, and package removal. In OpenACS &majorversion;, this tool is called the APM. OpenACS Package To illustrate the general structure of a package, let's see what the package for the "notes" application should look like.
    Package file layout diagram ROOT/ +-- packages/ APM Root | +-- notes/ Package Root | | | +-- notes.info Package Specification File | +-- sql/ | | | | | +-- oracle/ | | | | | | | +-- notes-create.sql Data Model Creation Script for Oracle | | | +-- notes-drop.sql Data Model Drop Script | | | +-- *.sql Data Model Files | | | +-- upgrade/ | | | +-- upgrade-4.1-4.5.sql Data Model Upgrade Scripts | | +-- postgresql/ | | | | | | | +-- notes-create.sql Data Model Creation Script for PostgreSQL | | | +-- notes-drop.sql Data Model Drop Script | | | +-- *.sql Data Model Files | | | +-- upgrade/ | | | +-- upgrade-4.1-4.5.sql Data Model Upgrade Scripts | +-- tcl/ | | | | | +-- notes-procs.tcl Tcl Library | | +-- notes-procs.xql SQL92 Queries for notes-procs.tcl | | +-- notes-procs-oracle.xql Oracle-specific queries for notes-procs.tcl | | +-- notes-procs-postgresql.xql PostgreSQL-specific Queries for notes-procs.tcl | | +-- notes-init.tcl Tcl Initialization | | +-- notes-init.xql Queries for notes-init.tcl (work in all DBs) | | +-- *.tcl Tcl Library Files | +-- lib/ | | | | | +-- *.tcl Includable page logic | | +-- *.adp Includable page templates | +-- www/ | | | | | +-- admin/ Administration UI | | | +-- tests/ Regression Tests | | | | +-- index.tcl Regression Test Index Page | | | | +-- ... Regression Tests | | | +-- index.tcl Administration UI Index Page | | | +-- ... Administration UI Pages | | | | | +-- doc/ Documentation | | | +-- index.html Documentation Index Page | | | +-- ... Administration Pages | | +-- resources/ Static Content | | | +-- ... Static Content files | | +-- index.tcl UI Index Page | | +-- index.adp UI Index Template | | +-- index.xql Queries for UI Index page | | +-- *.tcl UI Logic Scripts | | +-- *.adp UI Templates | | +-- *-oracle.xql Oracle-specific Queries | | +-- *-postgresql.xql PostgreSQL-specific Queries +-- Other package directories.
    All file locations are relative to the package root, which in this case is ROOT/packages/notes. The following table describes in detail what each of the files up in the diagram contain. A special note on the PACKAGE-KEY/www/resources directory. Files in this directory are available at http://yourserver/resources/PACKAGE-KEY/... and are returned without any permissions checking or even checks that the package is installed or mounted. Files are returned directly, so .tcl or .adp files are not sourced in these directories. This makes it suitable for storing icons, css files, javascript, and other static content which can be treated this way. Package files File Type Its Use Naming Convention Package Specification File The package specification file is an XML file generated and maintained by the OpenACS Package Manager (APM). It specifies information about the package including its parameters and its files. notes.info Data Model Creation Script Contains the SQL that creates the necessary data model and PL/SQL packages (or PL/pgSQL or whatever) to support the package. The name must match the convention below or the package will not be installed correctly. Notice that the script must be under the appropriate directory for the database you are developing your package for (hopefully all OpenACS-supported databases :-)) sql/<database>/notes-create.sql Data Model Drop Script Contains the SQL that removes the data model and PL/SQL packages generated by the creation script. The name must match the convention below or the package will not be installed correctly. sql/<database>/notes-drop.sql Data Model File Any .sql file that does not match the naming convention above is recognized as a data model file. It is useful to separate the SQL in the creation and drop scripts into several files and then have the scripts source the other data model files. In Oracle this can be done by including @@ filename in the creation or drop scripts. See the Oracle FAQ for examples. In PostgreSQL the same is acomplished by including \i filename. sql/<database>/*.sql Data Model Upgrade Scripts Contain changes to the data model between versions. The APM can automatically load the appropriate upgrade scripts when upgrading to a new version of a package. sql/<database>/upgrade/upgrade-<old>-<new>.sql SQL92 Query Files Files with queries that are supported by all databases. These are usually SQL92 queries. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *.xql Oracle-specific Query Files Files with queries that are Oracle-specific. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *-oracle.xql PostgreSQL-specific Query Files Files with queries that are PostgreSQL-specific. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *-postgresql.xql Tcl Library Files The Tcl library files include a set of procedures that provide an application programming interface (API) for the package to utilize. tcl/notes-procs.tcl Tcl Initialization The initialization files are used to run Tcl procedures that should only be sourced once on startup. Examples of statements to put here are registered filters or procedures. Tcl initialization files are sourced once on server startup after all of the Tcl library files are sourced. tcl/notes-init.tcl Administration UI The administration UI is used to administer the instances of the package. For example, the forums administration UI is used to create new forums, moderate postings, and create new categories for forums postings. www/admin/* Administration UI Index Page Every package administration UI must have an index page. In most cases, this is index.tcl but it can be any file with the name index, such as index.html or index.adp. www/admin/index.tcl Regression Tests Every package should have a set of regression tests that verify that it is in working operation. These tests should be able to be run at any time after the package has been installed and report helpful error messages when there is a fault in the system. www/admin/tests/ Regression Test Index Page The regression test directory must have an index page that displays all of the tests available and provides information on how to run them. This file can have any extension, as long as its name is index. www/admin/tests/index.html Documentation Every package must include a full set of documentation that includes requirements and design documents, and user-level and developer-level documentation where appropriate. www/doc/ Documentation Index Page The documentation directory must include a static HTML file with the name of index.html. www/doc/index.html UI Logic Scripts Packages provide a UI for users to access the system. The UI is split into Logic and Templates. The logic scripts perform database queries and prepare variables for presentation by the associated templates. www/*.tcl UI Templates Templates are used to control the presentation of the UI. Templates receive a set of data sources from the logic scripts and prepare them for display to the browser. www/*.adp UI Index Page The UI must have an index page composed of a logic script called index.tcl and a template called index.adp. www/index.tcl
    The APM The APM is used to create, maintain, and install packages. It takes care of copying all of the files and registering the package in the system. The APM is responsible for: Package registration Automatic installation of packages: loading data models, code libraries, and so on. Checking what packages depend on what other packages. Storing information on the package including ownership and a file list. In addition for packages that are applications, the APM is responsible for keeping track of where in the site a user must go in order to use the application. To do this, the APM defines a set of objects that we call package instances. Once a package is loaded, the administrator can create as many instances of the package as she likes, and map these instances to any URL in the site that she wants. If packages are analogous to executable programs in an operating system, then package instances are analgous to multiple running copies of a single program. Each instance can be independently administered and each instance maintains its own set of application parameters and options. The following sections will show you how to make a package for the Notes application. In addition, they will discuss some site management features in OpenACS &majorversion; that take advantage of the APM's package instance model. The two most important of these are subsites, and the site map tool, which can be used to map applications to one or more arbitrary URLs in a running site. We will also discuss how to organize your files and queries so they work with the OpenACS Query Dispatcher. Making a Package Here is how you make a package. Login as a site-wide administrator on your web service. Go to the package manager on your server. The URL is /acs-admin/apm. Click on the link /acs-admin/apm/package-add. Fill out the form for adding a new package. The form explains what everything means, but we'll repeat the important bits here for easy reference: Package Key This is a short text string that should uniquely name your package to distinguish it from all the others. It is used as a database key to keep track of the package and as the name of the directory in the file system where all the files related to your package will live. Example package keys in the current system include: forums, acs-kernel and so on. For the example application, we will use the package key notes. Package Name This is a short human readable name for your package. For our example, we will use the name "Notes". Package Plural If your package name is a nice singular noun, this should be the plural form of it. I assume the plural form is used when multiple instances of the package are used by a single service. We'll talk more about package instances later. Our example apllication doesn't really have a good plural name. So just make it also be "Notes". Package Type Generally we think of packages as either being applications, meaning that the package is meant primarily for use by end-users, or services meaning that the package is meant to be a reusable library of code, to be used by other packages. forums is a good example of an application, while acs-templating is a good example of a service. Our example is an application, so pick that. Package URL The URL from which people will download your package when it is done. Just use the default for this, you can change it later. Initial Version Just use the default here, which by convention is 0.1d. Version URL Just use the default here. Summary and Description Enter a short summary and longer description of what the Notes application will do. That is, something like "this application keeps short textual notes in the database", and so on. Click the button "Create Package". At this point, APM will create a directory called ROOT/packages/notes. The directory that APM created will be empty except for the notes.info file. Create a file called ROOT/packages/notes/sql/oracle/notes-create.sql. We'll fill this file with our data model very soon. Create a file called ROOT/packages/notes/sql/oracle/notes-drop.sql. This will contain the instructions to drop the data model. To be complete, you would also create the PostgreSQL versions of these files as well in ROOT/packages/notes/sql/postgresql/notes-create.sql and ROOT/packages/notes/sql/postgresql/notes-drop.sql. After you do this, go back to the main APM page. From there, click the link called "notes" to go to the management page for the new package. Now click the link called "Manage file information", then the "Scan the packages/notes directory for additional files in this package" link on that page to scan the file system for new files. This will bring you do a page that lists all the files you just added and lets you add them to the notes package. Note that while the .sql files have been added to the packge, they have not been loaded into the database. For the purposes of development, you have to load the data model by hand, because while OpenACS has automatic mechanisms for loading and reloading .tcl files for code, it does not do the same thing for data model files. Now go back to the main management page for the notes If your package has parameters, create them using the "Manage Parameter Information" link. Define package callbacks via the "Tcl Callbacks (install, instantiate, mount)" link. The new package has been created and installed in the server. At this point, you should add your package files to your CVS repository. I'll assume that you have set up your development repository according to the standards described in this appendix. If so, then you just do this: % cd ROOT/packages % cvs add notes % cd notes % cvs add notes.info % cvs add sql % cd sql % cvs add *.sql % cd ROOT/packages/notes % cvs commit -m "add new package for notes" Now you can start developing the package. In addition to writing code, you should also consider the tasks outlined in the package development tutorial. The Site Map and Package Instances At this point, you are probably excited to see your new package in action. But, we haven't added any user visible pages yet. By convention, user visible pages go in the ROOT/packages/notes/www directory. So go there and add a file called hello.html with some text in it. Now we have to make the user pages visible in the site. Since we didn't put the pages underneath ROOT/www they will not appear on their own. What we have to do is mount the application into the site map. That is, we have to define the URL from which the application will serve its pages. In OpenACS &majorversion;, administrators can define an arbitrary mapping between the URLs the user types and the actual file in the file system that is served. This mapping is called the site map and entries in the site map are called site nodes. Each site node maps a URL to an OpenACS object. Since package instances are objects, the site map allows us to easily map package instances to URLs. As we said before, each instance of an application has its own set of parameters and runs from its own URL within the site. What this means is that even though all the code for the notes application lives in ROOT/packages/notes, the application itself can run from any number of locations in the site. This allows developers and administrators to build sites that look to the user like a collection of many indedendent applications that actually run on a single shared code base. The request-processor document shows you how OpenACS figures out which instance of your application was requested by the user at any given time. The page development tutorial shows you how to use this information in your user interface. In order to make the new notes application visible to users, we have to mount it in the site map. You do this by going to the Site Map page, which is by default available at /acs-admin/site-map. Use the interface here to add a new sub-folder called notes to the root of the site, then click "new application" to mount a new instance of the notes application to the site. Name the new instance notes-1. Then type this URL into your browser: http://yourserver/notes/hello.html Now you should see the contents of the page that you added. What has happened is that all URLs that start with /notes have been mapped in such a way as to serve content from the directory ROOT/packages/notes/www. At this point, you can experiment with the site map by mounting multiple instances of the not yet written Notes application at various places in the site. In a later document, we'll see how to write your application so that the code can detect from what URL it was invoked. This is the key to supporting subsites. Summary The APM performs the following tasks in an OpenACS site: Manages creation, installation, and removal of packages from the server. Also keeps track of what files belong to which packages. Manages package upgrades. Manages information on all package instances in a site. For correctly written application packages, this allows the site administrator to map multiple instances of a package to URLs within a site. Writes out package distribution files for other people to download and install. We'll cover this later. Additional Reading package development tutorial ($Id: packages.xml,v 1.9 2006/07/17 05:38:37 torbenb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/subsites.xml0000644000175000017500000003103710456621135026454 0ustar frankiefrankie %myvars; ]> Writing OpenACS Application Pages By Rafael H. Schloming and Pete Su Overview In this document, we'll examine the user interface pages of the Notes application in more detail, covering two separate aspects of page development in OpenACS. First, we'll talk about the code needed to make your pages aware of which application instance they are running in. Second, we'll talk about using the form builder to develop form-based user interfaces in OpenACS. While these seem like unrelated topics, they both come up in the example page that we are going to look at, so it makes sense to address them at the same time. Application Instances and Subsites As you will recall from the packages tutorial, the Request Processor (RP) and Package Manager (APM) allow site administrators to define an arbitrary mapping from URLs in the site to objects representing content. These objects may represent single files, or entire applications. The APM uses the site map to map application instances to particular URLs within a site. We call creating such a mapping mounting the application instance at a particular URL. The tutorial also showed how a given URL is translated into a physical file to serve using the site map. We'll repeat this description here, assuming that you have mounted an instance of Notes at the URL /notes as we did in the packages-example: AOLserver receives your request for the URL /notes/somepage. This URL is passed to the request processor. The RP looks up the URL in the site map, and sees that the object mounted at that location is an instance of the notes application. The RP asks the package manager where in the file system the Notes package lives. In the standard case, this would be ROOT/packages/notes. The RP translates the URL to serve a page relative to the page root of the application, which is ROOT/packages/notes/www/. Therefore, the page that is finally served is ROOT/packages/notes/www/hello.html, which is what we wanted. What is missing from this description is a critical fact for application developers: In addition to working out what file to serve, the RP also stores information about which package instance the file belongs to into the AOLserver connection environment. The following ad_conn interfaces can be used to extract this information: [ad_conn package_url] If the URL refers to a package instance, this is the URL to the root of the tree where the package is mounted. [ad_conn package_id] If the URL refers to a package instance, this is the ID of that package instance. [ad_conn package_key] If the URL refers to a package instance, this is the unique key name of the package. [ad_conn extra_url] If we found the URL in the site map, this is the tail of the URL following the part that matched a site map entry. In the Notes example, we are particularly interested in the package_id field. If you study the data model and code, you'll see why. As we said before in the data modeling tutorial, the Notes application points the context_id of each Note object that it creates to the package instance that created it. That is, the context_id corresponds exactly to the package_id that comes in from the RP. This is convenient because it allows the administrator and the owner of the package to easily define access control policies for all the notes in a particular instance just my setting permissions on the package instance itself. The code for adding and editing notes, in notes/www/add-edit.tcl, shows how this works. At the top of the page, we extract the package_id and use it to do permission checks: set package_id [ad_conn package_id] if {[info exists note_id]} { permission::require_permission -object_id $note_id -privilege write set context_bar [ad_context_bar "Edit Note"] } else { permission::require_permission -object_id $note_id -privilege create set context_bar [ad_context_bar "New Note"] } This code figures out whether we are editing an existing note or creating a new one. It then ensures that we have the right privileges for each action. Later, when we actually create a note, the SQL that we run ensures that the context_id is set the right way: db_dml new_note { declare id integer; begin id := note.new( owner_id => :user_id, title => :title, body => :body, creation_user => :user_id, creation_ip => :peeraddr, context_id => :package_id ); end; } The rest of this page makes calls to the form builder part of the template system. This API allows you to write forms-based pages without generating a lot of duplicated HTML in your pages. It also encapsulates most of the common logic that we use in dealing with forms, which we'll discuss next. Using Forms The forms API is pretty simple: You use calls in the template::form namespace in your Tcl script to create form elements. The final template page then picks this stuff up and lays the form out for the user. The form is set up to route submit buttons and whatnot back to the same Tcl script that set up the form, so your Tcl script will also contain the logic needed to process these requests. So, given this outline, here is a breakdown of how the forms code works in the add-edit.tcl page. First, we create a form object called new_note: template::form create new_note All the forms related code in this page will refer back to this object. In addition, the adp part of this page does nothing but display the form object: <master> @context_bar@ <hr> <center> <formtemplate id="new_note"></formtemplate> </center> The next thing that the Tcl page does is populate the form with form elements. This code comes first: if {[template::form is_request new_note] && [info exists note_id]} { template::element create new_note note_id \ -widget hidden \ -datatype number \ -value $note_id db_1row note_select { select title, body from notes where note_id = :note_id } } The if_request call returns true if we are asking the page to render the form for the first time. That is, we are rendering the form to ask the user for input. The tcl part of a form page can be called in 3 different states: the initial request, the initial submission, and the validated submission. These states reflect the typical logic of a forms based page in OpenACS: First render the input form. Next, control passes to a validation page that checks and confirms the inputs. Finally, control passes to the page that performs the update in the database. The rest of the if condition figures out if we are creating a new note or editing an existing note. If note_id is passed to us from the calling page, we assume that we are editing an existing note. In this case, we do a database query to grab the data for the note so we can populate the form with it. The next two calls create form elements where the user can insert or edit the title and body of the Note. The interface to template::element is pretty straightforward. Finally, the code at the bottom of the page performs the actual database updates when the form is submitted and validated: if [template::form is_valid new_note] { set user_id [ad_conn user_id] set peeraddr [ad_conn peeraddr] if [info exists note_id] { db_dml note_update { update notes set title = :title, body = :body where note_id = :note_id } } else { db_dml new_note { declare id integer; begin id := note.new( owner_id => :user_id, title => :title, body => :body, creation_user => :user_id, creation_ip => :peeraddr, context_id => :package_id ); end; } } ad_returnredirect "." } In this simple example, we don't do any custom validation. The nice thing about using this API is that the forms library handles all of the HTML rendering, input validation and database transaction logic on your behalf. This means that you can write pages without duplicating all of that code in every set of pages that uses forms. How it All Fits To watch all of this work, use the installer to update the Notes package with the new code that you grabbed out of CVS or the package repository, mount an instance of Notes somewhere in your server and then try out the user interface pages. It should become clear that in a real site, you would be able to, say, create a custom instance of Notes for every registered user, mount that instance at the user's home page, and set up the permissions so that the instance is only visible to that user. The end result is a site where users can come and write notes to themselves. This is a good example of the leverage available in the OpenACS &version; system. The code that we have written for Notes is not at all more complex than a similar application without access control or site map awareness. By adding a small amount of code, we have taken a small, simple, and special purpose application to something that has the potential to be a very useful, general-purpose tool, complete with multi-user features, access control, and centralized administration. Summary In OpenACS &version;, application pages and scripts can be aware of the package instance, or subsite in which they are executing. This is a powerful general purpose mechanism that can be used to structure web services in very flexible ways. We saw how to use this mechanism in the Notes application and how it makes it possible to easily turn Notes into an application that appears to provide each user in a system with their own private notes database. We also saw how to use the templating system's forms API in a simple way, to create forms based pages with minimal duplication of code. ($Id: subsites.xml,v 1.8 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/tutorial-advanced.xml0000644000175000017500000022205611501005400030203 0ustar frankiefrankie %myvars; ]> Advanced Topics by Joel Aufrecht This tutorial covers topics which are not essential to creating a minimal working package. Each section can be used independently of all of the others; all sections assume that you've completed the basic tutorial. Write the Requirements and Design Specs Before you get started you should make yourself familiar with the tags that are used to write your documentation. For tips on editing SGML files in emacs, see . It's time to document. For the tutorial we'll use pre-written documentation. When creating a package from scratch, start by copying the documentation template from /var/lib/aolserver/openacs-dev/packages/acs-core-docs/xml/docs/xml/package-documentation-template.xml to myfirstpackage/www/docs/xml/index.xml. You then edit that file with emacs to write the requirements and design sections, generate the html, and start coding. Store any supporting files, like page maps or schema diagrams, in the www/doc/xml directory, and store png or jpg versions of supporting files in the www/doc directory. For this tutorial, you should instead install the pre-written documentation files for the tutorial app. Log in as $OPENACS_SERVICE_NAME, create the standard directories, and copy the prepared documentation: [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/ [$OPENACS_SERVICE_NAME myfirstpackage]$ mkdir -p www/doc/xml [$OPENACS_SERVICE_NAME myfirstpackage]$ cd www/doc/xml [$OPENACS_SERVICE_NAME xml]$ cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/myfirstpackage/* . [$OPENACS_SERVICE_NAME xml]$ OpenACS uses DocBook for documentation. DocBook is an XML standard for semantic markup of documentation. That means that the tags you use indicate meaning, not intended appearance. The style sheet will determine appearance. You will edit the text in an xml file, and then process the file into html for reading. Open the file index.xml in emacs. Examine the file. Find the version history (look for the tag <revhistory>). Add a new record to the document version history. Look for the <authorgroup> tag and add yourself as a second author. Save and exit. Process the xml file to create html documentation. The html documentation, including supporting files such as pictures, is stored in the www/docs/ directory. A Makefile is provided to generate html from the xml, and copy all of the supporting files. If Docbook is set up correctly, all you need to do is: [$OPENACS_SERVICE_NAME xml]$ make cd .. ; /usr/bin/xsltproc ../../../acs-core-docs/www/xml/openacs.xsl xml/index.xml Writing requirements-introduction.html for chapter(requirements-introduction) Writing requirements-overview.html for chapter(requirements-overview) Writing requirements-cases.html for chapter(requirements-cases) Writing sample-data.html for chapter(sample-data) Writing requirements.html for chapter(requirements) Writing design-data-model.html for chapter(design-data-model) Writing design-ui.html for chapter(design-ui) Writing design-config.html for chapter(design-config) Writing design-future.html for chapter(design-future) Writing filename.html for chapter(filename) Writing user-guide.html for chapter(user-guide) Writing admin-guide.html for chapter(admin-guide) Writing bi01.html for bibliography Writing index.html for book [$OPENACS_SERVICE_NAME xml]$ Verify that the documentation was generated and reflects your changes by browsing to http://yoursite:8000/myfirstpackage/doc Add the new package to CVS Before you do any more work, make sure that your work is protected by putting it all into cvs. The cvs add command is not recursive, so you'll have to traverse the directory tree manually and add as you go. (More on CVS) [$OPENACS_SERVICE_NAME xml]$ cd .. [$OPENACS_SERVICE_NAME doc]$ cd .. [$OPENACS_SERVICE_NAME www]$ cd .. [$OPENACS_SERVICE_NAME myfirstpackage]$ cd .. [$OPENACS_SERVICE_NAME packages]$ cvs add myfirstpackage/ Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage added to the repository [$OPENACS_SERVICE_NAME packages]$ cd myfirstpackage/ [$OPENACS_SERVICE_NAME myfirstpackage]$ cvs add www Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www added to the repository [$OPENACS_SERVICE_NAME myfirstpackage]$ cd www [$OPENACS_SERVICE_NAME www]$ cvs add doc Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc added to the repository [$OPENACS_SERVICE_NAME www]$ cd doc [$OPENACS_SERVICE_NAME doc]$ cvs add * cvs add: cannot add special file `CVS'; skipping cvs add: scheduling file `admin-guide.html' for addition cvs add: scheduling file `bi01.html' for addition cvs add: scheduling file `data-model.dia' for addition cvs add: scheduling file `data-model.png' for addition cvs add: scheduling file `design-config.html' for addition cvs add: scheduling file `design-data-model.html' for addition cvs add: scheduling file `design-future.html' for addition cvs add: scheduling file `design-ui.html' for addition cvs add: scheduling file `filename.html' for addition cvs add: scheduling file `index.html' for addition cvs add: scheduling file `page-map.dia' for addition cvs add: scheduling file `page-map.png' for addition cvs add: scheduling file `requirements-cases.html' for addition cvs add: scheduling file `requirements-introduction.html' for addition cvs add: scheduling file `requirements-overview.html' for addition cvs add: scheduling file `requirements.html' for addition cvs add: scheduling file `sample-data.html' for addition cvs add: scheduling file `sample.png' for addition cvs add: scheduling file `user-guide.html' for addition cvs add: scheduling file `user-interface.dia' for addition cvs add: scheduling file `user-interface.png' for addition Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc/xml added to the repository cvs add: use 'cvs commit' to add these files permanently [$OPENACS_SERVICE_NAME doc]$ cd xml [$OPENACS_SERVICE_NAME xml]$ cvs add Makefile index.xml cvs add: scheduling file `Makefile' for addition cvs add: scheduling file `index.xml' for addition cvs add: use 'cvs commit' to add these files permanently [$OPENACS_SERVICE_NAME xml]$ cd ../../.. [$OPENACS_SERVICE_NAME myfirstpackage]$ cvs commit -m "new package" cvs commit: Examining . cvs commit: Examining www cvs commit: Examining www/doc cvs commit: Examining www/doc/xml RCS file: /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc/admin-guide.html,v done Checking in www/doc/admin-guide.html; /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc/admin-guide.html,v <-- admin-guide.html initial revision: 1.1 done (many lines omitted) [$OPENACS_SERVICE_NAME myfirstpackage]$
    Upgrading a local CVS repository
    OpenACS Edit This Page Templates by Nick Carroll Goals Learn about the OpenACS templating system. Learn about subsites and site-map administration. Introduction The OpenACS templating system allows you to give your site a consistent look and feel. It also promotes code maintainability in the presentation layer, by allowing presentation components to be reused across multiple pages. If you need to change the layout for some reason, then you only need to make that change in one location, instead of across many files. In this problem set you will familiarise yourself with the templating system in openacs. This will be achieved through customising an existing edit-this-page application template. Before proceeding, it is strongly advised to read the templating documentation on your openacs installation (http://localhost:8000/doc/acs-templating). The documentation lists the special tags available for ADP files. Exercise 1: Create a Subsite Create a subsite called pset3. A subsite is simply a directory or subdirectory mounted at the end of your domain name. This can be done in one of two places: http://localhost:8000/admin/site-map or the subsite admin form on the main site, which is available when you login to your OpenACS installation. Exercise 2: Checkout and Install edit-this-page (ETP) Checkout ETP from CVS: cd ~/openacs/packages cvs -d:pserver:anonymous@openacs.org:/cvsroot login cvs -d:pserver:anonymous@openacs.org:/cvsroot co edit-this-page Go to the package manager at http://yoursite/acs-admin/apm. And install the new package: edit-this-page. Or use the "Add Application" form available on the Main site. Change ETP Application Work out how to change the ETP application. Investigate each of the available ETP templates: Default News FAQ Exercise 4: Create a New ETP Template Browse the files for each of the above ETP templates at: cd ~/openacs/packages/edit-this-page/templates Use the article template as the basis of our new col2 template. cp article-content.adp col2-content.adp cp article-content.tcl col2-content.tcl cp article-index.adp col2-index.adp cp article-index.tcl col2-index.tcl The template should provide us with the following ETP layout: table showing ETP layout Header Sidebar Main Content Pane
    The "Main Content" pane should contain the editable content that ETP provides. The "Header" should display the title of the page that you set in ETP. The "Sidebar" should display the extlinks that you add as a content item in ETP.
    Exercise 5: Register the col2 Template with ETP Need to register your template with ETP so that it appears in the drop-down menu that you would have seen in Exercise 3. cd ~/openacs/packages/edit-this-page/tcl emacs etp-custom-init.tcl Use the function etp::define_application to register your template with ETP Uncomment the "asc" definition Set allow_extlinks to true, the rest should be false. Restart your server for the changes to take effect. Exercise 6: Configure ETP to use the col2 Template Configure your ETP instance at /lab4/index to use the col2 template. Create external links to link to other mounted ETP instances. Check that your external links show up in the sidebar when you view your ETP application using the col2 template. Who Wrote This and When This problem set was originally written by Nick Carroll in August 2004 for the University of Sydney Course EBUS5002. This material is copyright 2004 by Nick Carroll. It may be copied, reused, and modified, provided credit is given to the original author. ($Id: tutorial-advanced.xml,v 1.49 2010/12/11 23:36:32 ryang Exp $)
    Adding Comments You can track comments for any ACS Object. Here we'll track comments for notes. On the note-edit.tcl/adp pair, which is used to display individual notes, we want to put a link to add comments at the bottom of the screen. If there are any comments, we want to show them. First, we need to generate a url for adding comments. In note-edit.tcl: set comment_add_url "[general_comments_package_url]comment-add?[export_vars { { object_id $note_id } { object_name $title } { return_url "[ad_conn url]?[ad_conn query]"} }]" This calls a global, public tcl function that the general_comments package registered, to get its url. You then embed in that url the id of the note and its title, and set the return_url to the current url so that the user can return after adding a comment. We need to create html that shows any existing comments. We do this with another general_comments function: set comments_html [general_comments_get_comments -print_content_p 1 $note_id] First, we pass in an optional parameter that that says to actually show the contents of the comments, instead of just the fact that there are comments. Then you pass the note id, which is also the acs_object id. We put our two new variables in the note-edit.adp page. <a href="@comment_add_url@">Add a comment</a> @comments_html@ Admin Pages There are at least two flavors of admin user interface: Admins use same pages as all other users, except that they are offered admin links and buttons where appropriate. For example, if admins have privilege to bulk-delete items you could provide checkboxes next to every item seen on a list and the Delete Selected button on the bottom of the list. Dedicated admin pages. If you want admins to have access to data that users aren't interested in or aren't allowed to see you will need dedicated admin pages. The conventional place to put those dedicated admin pages is in the /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin directory. [$OPENACS_SERVICE_NAME www]$ mkdir admin [$OPENACS_SERVICE_NAME www]$ cd admin Even if your application doesn't need any admin pages of its own you will usually need at least one simple page with a bunch of links to existing administration UI such as Category Management or standard Parameters UI. Adding the link to Category Management is described in the section on categories. The listing below adds a link to the Parameters UI of our package. [$OPENACS_SERVICE_NAME admin]$ vi index.adp <master> <property name="title">@title;noquote@</property> <property name="context">@context;noquote@</property> <ul class="action-links"> <li><a href="@parameters_url@" title="Set parameters" class="action_link">Set parameters</a></li> </ul> [$OPENACS_SERVICE_NAME admin]$ vi index.tcl ad_page_contract {} { } -properties { context_bar } set package_id [ad_conn package_id] permission::require_permission \ -object_id $package_id \ -privilege admin] set context [list] set title "Administration" set parameters_url [export_vars -base "/shared/parameters" { package_id { return_url [ad_return_url] } }] Now that you have the first admin page it would be nice to have a link to it somewhere in the system so that admins don't have to type in the /admin every time they need to reach it. You could put a static link to the toplevel index.adp but that might be distracting for people who are not admins. Besides, some people consider it impolite to first offer a link and then display a nasty "You don't have permission to access this page" message. In order to display the link to the admin page only to users that have admin privileges add the following code near the top of /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.tcl: set package_id [ad_conn package_id] set admin_p [permission::permission_p -object_id $package_id \ -privilege admin -party_id [ad_conn untrusted_user_id]] if { $admin_p } { set admin_url "admin" set admin_title Administration } In /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.adp put: <if @admin_p@ ne nil> <a href="@admin_url@">@admin_title@</a> </if> Categories extended by Nima Mazloumi You can associate any ACS Object with one or more categories. In this tutorial we'll show how to equip your application with user interface to take advantage of the Categories service. We'll start by installing the Categories service. Go to /acs/admin and install it. This step won't be necessary for the users of your applications because you'll create a dependency with the Package Manager which will take care that the Categories service always gets installed when your application gets installed. Now that we have installed the Categories service we can proceed to modifying our application so that it can take advantage of it. We'll do it in three steps: The Categories service provides a mechanism to associate one or more category trees that are relevant to your application. One example of such tree is a tree of geographical locations. Continents are on the top of such tree, each continent containing countries etc. Another tree might contain market segments etc. Before users of your application can take advantage of the Categories service there needs to be a way for administrators of your application to choose which category trees are applicable for the application. The way to achieve this is is to provide a link to the Category Management pages. Add the following snippet to your /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.tcl file: set category_map_url [export_vars -base "[site_node::get_package_url -package_key categories]cadmin/one-object" { { object_id $package_id } }] and the following snippet to your /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.adp file: <a href="@category_map_url@"<#categories.Site_wide_Categories#</a> The link created by the above code (category_map_url) will take the admin to the generic admin UI where he can pick category trees that make sense for this application. The same UI also includes facilities to build and edit category trees. Notice that the only parameter in this example is package_id so that category trees will be associated with the object identified by this package_id. The categorization service is actually more general than that: instead of package_id you could use an ID of some other object that serves as a "container" in your application. For example, if your discussion forums application supports multiple forums you would use forum_id to associate category trees with just that one forum rather than the entire application instance. Once the category trees have been selected users need a way to categorize items. The easiest way to do this is by adding the category widget type of the form builder to note-edit.tcl. To achieve this we'll need to use the -extend switch to the ad_form command. Here's the "meat" of the note-edit.tcl page: #extend the form to support categories set package_id [ad_conn package_id] category::ad_form::add_widgets -form_name note -container_object_id $package_id -categorized_object_id [value_if_exists item_id] ad_form -extend -name note -on_submit { set category_ids [category::ad_form::get_categories -container_object_id $package_id] } -new_data { .... category::map_object -remove_old -object_id $item_id $category_ids db_dml insert_asc_named_object "insert into acs_named_objects (object_id, object_name, package_id) values ( :item_id, :title, :package_id)" } -edit_data { .... db_dml update_asc_named_object "update acs_named_objects set object_name = :title, package_id = :package_id where object_id = :item_id" category::map_object -remove_old -object_id $item_id $category_ids } -after_submit { ad_returnredirect "." ad_script_abort } While the category::ad_form::add_widgets proc is taking care to extend your form with associated categories you need to ensure that your items are mapped to the corresponding category object yourself. Also since the categories package knows nothing from your objects you have to keep the acs_named_objects table updated with any changes taking place. We use the items title so that they are listed in the categories browser by title.Make sure that you also delete these entries if your item is delete. Add this to your corresponding delete page: db_dml delete_named_object "delete from acs_named_objects where object_id = :item_id" note-edit.tcl requires a note_id to determine which record should be deleted. It also looks for a confirmation variable, which should initially be absert. If it is absent, we create a form to allow the user to confirm the deletion. Note that in entry-edit.tcl we used ad_form to access the Form Template commands; here, we call them directly because we don't need the extra features of ad_form. The form calls itself, but with hidden variables carrying both note_id and confirm_p. If confirm_p is present, we delete the record, set redirection back to the index, and abort script execution. The database commands: [$OPENACS_SERVICE_NAME@yourserver www]$ emacs note-delete.xql <?xml version="1.0"?> <queryset> <fullquery name="do_delete"> <querytext> select samplenote__delete(:note_id) </querytext> </fullquery> <fullquery name="get_name"> <querytext> select samplenote__name(:note_id) </querytext> </fullquery> </queryset> And the adp page: [$OPENACS_SERVICE_NAME@yourserver www]$ emacs note-delete.adp <master> <property name="title">@title@</property> <property name="context">{@title@}</property> <h2>@title@</h2> <formtemplate id="note-del-confirm"></formtemplate> </form> The ADP is very simple. The formtemplate tag outputs the HTML form generated by the ad_form command with the matching name. Test it by adding the new files in the APM and then deleting a few samplenotes. We will now make categories optional on package instance level and also add a configuration page to allow the package admin to enable/disable categories for his package. Go to the APM and create a number parameter with the name "EnableCategoriesP" and the default value "0". Add the following lines to your index.tcl: set return_url [ns_conn url] set use_categories_p [parameter::get -parameter "EnableCategoriesP"] Change your to this: <a href=configure?<%=[export_url_vars return_url]%>>Configure</a> <if @use_categories_p@> <a href="@category_map_url@"<#categories.Site_wide_Categories#</a> </if> Now create a configure page ad_page_contract { This page allows an admin to change the categories usage mode. } { {return_url ""} } set title "Configure category mode" set context [list $title] set use_categories_p [parameter::get -parameter "EnableCategoriesP"] ad_form -name categories_mode -form { {enabled_p:text(radio) {label "Enable Categories"} {options {{Yes 1} {No 0}}} {value $use_categories_p} } {return_url:text(hidden) {value $return_url}} {submit:text(submit) {label "Set Mode"}} } -on_submit { parameter::set_value -parameter "EnableCategoriesP" -value $enabled_p if {![empty_string_p $return_url]} { ns_returnredirect $return_url } } and add this to its corresponding ADP page <master> <property name="title">@title@</property> <property name="context">@context@</property> <formtemplate id="categories_mode"></formtemplate> Reference this page from your admin page #TCL: set return_url [ad_conn url] #ADP: <a href=configure?<%=[export_url_vars return_url]%>>Configure</a> Change the note-edit.tcl: # Use Categories? set use_categories_p [parameter::get -parameter "EnableCategoriesP" -default 0] if { $use_categories_p == 1 } { # YOUR NEW FORM DEFINITION } else { # YOUR OLD FORM DEFINITION } You can filter your notes using categories. The below example does not support multiple filters and displays a category in a flat format.The first step is to define the optional parameter category_id for index.tcl: ad_page_contract { YOUR TEXT } { YOURPARAMS {category_id:integer,optional {}} } Now you have to check whether categories are enabled or not. If this is the case and a category id is passed you need to extend your sql select query to support filtering. One way would be to extend the mfp::note::get proc to support two more swiches -where_clause and -from_clause. set use_categories_p [parameter::get -parameter "EnableCategoriesP" -default 0] if { $use_categories_p == 1 && [exists_and_not_null category_id] } { set from_clause "category_object_map com, acs_named_objects nam" set_where_clause "com.object_id = qa.entry_id and nam.package_id = :package_id and com.object_id = nam.object_id and com.category_id = :category_id" ... mfp::note::get \ -item_id $item_id \ -array note_array \ -where_clause $where_clause \ -from_clause $from_clause ... } else { # OLD STUFF } Also you need to make sure that the user can see the corresponding categories. Add the following snippet to the end of your index page: # Site-Wide Categories if { $use_categories_p == 1} { set package_url [ad_conn package_url] if { ![empty_string_p $category_id] } { set category_name [category::get_name $category_id] if { [empty_string_p $category_name] } { ad_return_exception_page 404 "No such category" "Site-wide \ Category with ID $category_id doesn't exist" return } # Show Category in context bar append context_base_url /cat/$category_id lappend context [list $context_base_url $category_name] set type "all" } # Cut the URL off the last item in the context bar if { [llength $context] > 0 } { set context [lreplace $context end end [lindex [lindex $context end] end]] } db_multirow -unclobber -extend { category_name tree_name } categories categories { select c.category_id as category_id, c.tree_id from categories c, category_tree_map ctm where ctm.tree_id = c.tree_id and ctm.object_id = :package_id } { set category_name [category::get_name $category_id] set tree_name [category_tree::get_name $tree_id] } } and to the corresponding index ADP page: <if @use_categories_p@> <multiple name="categories"> <h2>@categories.tree_name@ <group column="tree_id"> <a href="@package_url@cat/@categories.category_id@?@YOURPARAMS@&category_id=@categories.category_id@">@categories.category_name@ </group> </multiple> <a href="@package_url@view?@YOURPARAMS@">All Items</if> Finally you need a an index.vuh in your www folder to rewrite the URLs correctly, : set url /[ad_conn extra_url] if {[regexp {^/+cat/+([^/]+)/*} $url \ ignore_whole category_id]} { rp_form_put category_id $category_id } rp_internal_redirect "/packages/YOURPACKAGE/www/index" Now when ever the user select a category only notes that belong to this category are displayed. Profile your code by Jade Rubick There are several facilities for profiling your code in OpenACS. The first thing to do is to install the developer-support package and play around with it. But there is also support in the API for profiling your code: profiling your code using ds_profile Prepare the package for distribution. Browse to the package manager. Click on tutorialapp. Click on Generate a distribution file for this package from the filesystem. Click on the file size (37.1KB) after the label Distribution File: and save the file to /var/tmp. The publish point for new packages should be fixed. Package development guidelines Distributing upgrades of your package by Jade Rubick The OpenACS Package Repository builds a list of packages that can be installed on OpenACS installations, and can be used by administrators to update their packages. If you are a package developer, there are a couple of steps you need to take in order to release a new version of your package. For the sake of this example, let's assume you are the package owner of the notes package. It is currently at version 1.5, and you are planning on releasing version 1.6. It is also located in OpenACS's CVS. To release your package: cd /path/to/notes cvs commit -m "Update package to version 1.6." cvs tag notes-1-6-final cvs tag -F openacs-5-1-compat Of course, make sure you write upgrade scripts () Notifications by David Bell and Simon Carstensen The notifications package allows you to send notifications through any defined communications medium (e.g. email, sms) upon some event occuring within the system. This tutorial steps through the process of integrating the notifications package with your package. First step is to create the notification types. To do this a script similar to the one below needs to be loaded into Postgresql. I create this script in a package-name/sql/postgresql/package-name-notifications-init.sql file. I then load this file from my create sql file. The following code snippet is taken from Weblogger. It creates a lars_blogger_notif notification type (which was created above). create function inline_0() returns integer as ' declare impl_id integer; v_foo integer; begin -- the notification type impl impl_id := acs_sc_impl__new ( ''NotificationType'', ''lars_blogger_notif_type'', ''lars-blogger'' ); v_foo := acs_sc_impl_alias__new ( ''NotificationType'', ''lars_blogger_notif_type'', ''GetURL'', ''lars_blogger::notification::get_url'', ''TCL'' ); v_foo := acs_sc_impl_alias__new ( ''NotificationType'', ''lars_blogger_notif_type'', ''ProcessReply'', ''lars_blogger::notification::process_reply'', ''TCL'' ); PERFORM acs_sc_binding__new ( ''NotificationType'', ''lars_blogger_notif_type'' ); v_foo:= notification_type__new ( NULL, impl_id, ''lars_blogger_notif'', ''Blog Notification'', ''Notifications for Blog'', now(), NULL, NULL, NULL ); -- enable the various intervals and delivery methods insert into notification_types_intervals (type_id, interval_id) select v_foo, interval_id from notification_intervals where name in (''instant'',''hourly'',''daily''); insert into notification_types_del_methods (type_id, delivery_method_id) select v_foo, delivery_method_id from notification_delivery_methods where short_name in (''email''); return (0); end; ' language 'plpgsql'; select inline_0(); drop function inline_0(); You also need a drop script. This is untested for comptability with the above script. -- @author gwong@orchardlabs.com,ben@openforce.biz -- @creation-date 2002-05-16 -- -- This code is newly concocted by Ben, but with significant concepts and code -- lifted from Gilbert's UBB forums. Thanks Orchard Labs. -- Lars and Jade in turn lifted this from gwong and ben. create function inline_0 () returns integer as ' declare row record; begin for row in select nt.type_id from notification_types nt where nt.short_name in (''lars_blogger_notif_type'',''lars_blogger_notif'') loop perform notification_type__delete(row.type_id); end loop; return null; end;' language 'plpgsql'; select inline_0(); drop function inline_0 (); -- -- Service contract drop stuff was missing - Roberto Mello -- create function inline_0() returns integer as ' declare impl_id integer; v_foo integer; begin -- the notification type impl impl_id := acs_sc_impl__get_id ( ''NotificationType'', -- impl_contract_name ''lars_blogger_notif_type'' -- impl_name ); PERFORM acs_sc_binding__delete ( ''NotificationType'', ''lars_blogger_notif_type'' ); v_foo := acs_sc_impl_alias__delete ( ''NotificationType'', -- impl_contract_name ''lars_blogger_notif_type'', -- impl_name ''GetURL'' -- impl_operation_name ); v_foo := acs_sc_impl_alias__delete ( ''NotificationType'', -- impl_contract_name ''lars_blogger_notif_type'', -- impl_name ''ProcessReply'' -- impl_operation_name ); select into v_foo type_id from notification_types where sc_impl_id = impl_id and short_name = ''lars_blogger_notif''; perform notification_type__delete (v_foo); delete from notification_types_intervals where type_id = v_foo and interval_id in ( select interval_id from notification_intervals where name in (''instant'',''hourly'',''daily'') ); delete from notification_types_del_methods where type_id = v_foo and delivery_method_id in ( select delivery_method_id from notification_delivery_methods where short_name in (''email'') ); return (0); end; ' language 'plpgsql'; select inline_0(); drop function inline_0(); The next step is to setup our notification creation. A new notification must be added to the notification table for each blog entry added. We do this using the notification::new procedure notification::new \ -type_id [notification::type::get_type_id \ -short_name lars_blogger_notif] \ -object_id $blog(package_id) \ -response_id $blog(entry_id) \ -notif_subject $blog(title) \ -notif_text $new_content This code is placed in the tcl procedure that creates blog entries, right after the entry gets created in the code. The $blog(package_id) is the OpenACS object_id of the Weblogger instance to which the entry has been posted to and the $new_content is the content of the entry. This example uses the package_id for the object_id, which results in setting up notifications for all changes for blogger entries in this package. However, if you instead used the blog_entry_id or something like that, you could set up per-item notifications. The forums packages does this -- you can look at it for an example. The final step is to setup the notification subscription process. In this example we want to let a user find out when a new entry has been posted to the blog. To do this we put a link on the blog that allows them to subscribe to notifications of new entries. The notifications/requests-new page is very handy in this situation. Such a link can be created using the notification::display::request_widget proc: set notification_chunk [notification::display::request_widget \ -type lars_blogger_notif \ -object_id $package_id \ -pretty_name [lars_blog_name] \ -url [lars_blog_public_package_url] \ ] which will return something like You may <a href="/notifications/request-new?...">request notification</a> for Weblogger. which can be readily put on the blog index page. The pretty_name parameter is what appears at the end of the text returned (i.e. "... request notification</a> for pretty_name"), The url parameter should be set to the address we want the user to be redirected to after they have finished the subscription process. This should be all you need to implement a notification system. For more examples look at the forums package. Hierarchical data by Jade Rubick with help from many people in the OpenACS community One of the nice things about using the OpenACS object system is that it has a built-in facility for tracking hierarchical data in an efficient way. The algorithm behind this is called tree_sortkey. Any time your tables are subclasses of the acs_objects table, then you automatically get the ability to structure them hierarchically. The way you do this is currently via the context_id column of acs_objects (Note that there is talk of adding in a parent_id column instead, because the use of context_id has been ambiguous in the past). So when you want to build your hierarchy, simply set the context_id values. Then, when you want to make hierarchical queries, you can do them as follows: db_multirow categories blog_categories " SELECT c.*, o.context_id, tree_level(o.tree_sortkey) FROM blog_categories c, acs_objects o WHERE c.category_id = o.object_id ORDER BY o.tree_sortkey" Note the use of the tree_level() function, which gives you the level, starting from 1, 2, 3... Here's an example, pulling all of the children for a given parent: SELECT children.*, tree_level(children.tree_sortkey) - tree_level(parent.tree_sortkey) as level FROM some_table parent, some_table children WHERE children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey) and parent.tree_sortkey <> children.tree_sortkey and parent.key = :the_parent_key; The reason we substract the parent's tree_level from the child's tree_level is that the tree_levels are global, so if you want the parent's tree_level to start with 0, you'll want the subtraction in there. This is a reason you'll commonly see magic numbers in tree_sortkey SQL queries, like tree_level(children.tree_sortkey) - 4. That is basically an incorrect way to do it, and subtracting the parent's tree_level is the preferred method. This example does not include the parent. To return the entire subtree including the parent, leave out the non-equals clause: SELECT subtree.*, tree_level(subtree.tree_sortkey) - tree_level(parent.tree_sortkey) as level FROM some_table parent, some_table subtree WHERE subtree.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey) and parent.key = :the_parent_key; If you are using the Content Repository, you get a similar facility, but the parent_id column is already there. Note you can do joins with tree_sortkey: SELECT p.item_id, repeat(:indent_pattern, (tree_level(p.tree_sortkey) - 5)* :indent_factor) as indent, p.parent_id as folder_id, p.project_name FROM pm_projectsx p, cr_items i WHERE p.project_id = i.live_revision ORDER BY i.tree_sortkey This rather long thread explains How tree_sortkeys work and this paper describes the technique for tree_sortkeys, although the OpenACS implementation has a few differences in the implementation, to make it work for many languages and the LIKE construct in Postgres. Using .vuh files for pretty urls .Vuh files are special cases of .tcl files, used for rewriting incoming urls. We can use a vuh file to prettify the uri for our notes. Instead of note-edit?item_id=495, we can use note/495. To do this, we will need a new .vuh file for redirection and we will need to change the referring links in note-list. First, add the vuh: [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www [$OPENACS_SERVICE_NAME www]$ emacs note.vuh Paste this into the file: example missing We parse the incoming request and treat everything after the final / as the item id. Note that this simple redirection will lose any additional query parameters passed in. Many OpenACS objects maintain a pretty-name, which is a unique, human-readable string, usually derived from title, which makes an even better 'pretty url' than a numeric id; this requires that your display page be able to look up an item based on pretty id. We use rp_form_put to store the item id in the internal register that the next page is expecting, and then redirects the request in process internally (ie, without a browser refresh). Next, modify note-list so that its link is of the new form.: [$OPENACS_SERVICE_NAME www]$ emacs ../lib/note-edit.tcl db_multirow \ -extend { edit_url delete_url } notes notes_select { select ci.item_id, n.title from cr_items ci, mfp_notesx n where n.revision_id = ci.live_revision } { set edit_url [export_vars -base "note/$item_id"] set delete_url [export_vars -base "note-delete" {item_id}] } You may also need to change some of the links in your package. Commonly, you would use ad_conn package_url to build the URL. Otherwise, some of your links may be relative to the virtual directory (note/) instead of the actual directory that the note is being served from. Laying out a page with CSS instead of tables .LRN home page with table-based layout A sample of the HTML code (full source) <table border="0" width="100%"> <tr> <td valign="top" width="50%"> <table class="element" border=0 cellpadding="0" cellspacing="0" width="100%"> <tr> <td colspan=3 class="element-header-text"> <bold>Groups</bold> </td> </tr> <tr> <td colspan=3 class="dark-line" height="0"><img src="/resources/acs-subsite/spacer.gif"></td></tr> <tr> <td class="light-line" width="1"> <img src="/resources/acs-subsite/spacer.gif" width="1"> </td> <td class="element-text" width="100%"> <table cellspacing="0" cellpadding="0" class="element-content" width="100%"> <tr> <td> <table border="0" bgcolor="white" cellpadding="0" cellspacing="0" width="100%"> <tr> <td class=element-text> MBA 101 .LRN Home with CSS-based layout A sample of the HTML code (full source) <div class="left"> <div class="portlet-wrap-shadow"> <div class="portlet-wrap-bl"> <div class="portlet-wrap-tr"> <div class="portlet"> <h2>Groups</h2> <ul> <li> <a href="#">Class MBA 101</a> If the CSS is removed from the file, it looks somewhat different: Sending HTML email from your application by Jade Rubick Sending email is fairly simple using the acs-mail-lite package. Sending HTML email is only slightly more complicated. set subject "my subject" set message "<b>Bold</b> not bold" set from_addr "me@myemail.com" set to_addr "me@myemail.com" # the from to html closes any open tags. set message_html [ad_html_text_convert -from html -to html $message] # some mailers chop off the last few characters. append message_html " " set message_text [ad_html_text_convert -from html -to text $message] set message_data [build_mime_message $message_text $message_html] set extra_headers [ns_set new] ns_set put $extra_headers MIME-Version [ns_set get $message_data MIME-Version] ns_set put $extra_headers Content-ID [ns_set get $message_data Content-ID] ns_set put $extra_headers Content-Type [ns_set get $message_data Content-Type] set message [ns_set get $message_data body] acs_mail_lite::send \ -to_addr $to_addr \ -from_addr $from_addr \ -subject $subject \ -body $message \ -extraheaders $extra_headers Basic Caching Based on a post by Dave Bauer. Caching using the database API is described in the database API tutorial. Caching using util_memoize Implement your proc as my_proc_not_cached Create a version of your proc called my_proc which wraps the non-cached version in the caching mechanism. In this example, my_proc_not_cached takes one argument, -foo, so the wrapper passes that on. The wrapper also uses the list command, to ensure that the arguments get passed correctly and to prevent commands passed in as arguments from being executed. ad_proc my_proc {-foo} { Get a cached version of my_proc. } { return [util_memoize [list my_proc_not_cached -foo $foo]] } In your code, always call my_proc. There will be a seperate cache item for each unique call to my_proc_not_cached so that calls with different arguments are cached seperately. You can flush the cache for each cache key by calling util_memoize_flush my_proc_not_cached args. The cached material will of course become obsolete over time. There are two ways to handle this. Timed Expiration: pass in max_age to util_memoize. If the content is older than max_age, it will be re-generated. Direct Flushing. In any proc which invalidates the cached content, call util_memoize_flush my_proc_not_cached args. If you are correctly flushing the cached value, then it will need to be reloaded. You may wish to pre-load it, so that the loading delay does not impact users. If you have a sequence of pages, you could call the cached proc in advance, to increase the chances that it's loaded and current when the user reaches it. Or, you can call (and discard) it immediately after flushing it. Scheduled Procedures Put this proc in a file /packages/myfirstpackage/tcl/scheduled-init.tcl. Files in /tcl with the -init.tcl ending are sourced on server startup. This one executes my_proc every 60 seconds: ad_schedule_proc 60 myfirstpackage::my_proc This executes once a day, at midnight: ad_schedule_proc \ -schedule_proc ns_schedule_daily \ [list 0 0] \ myfirstpackage::my_proc See ad_schedule_proc for more information. Enabling WYSIWYG by Nima Mazloumi Most of the forms in OpenACS are created using the form builder, see . For detailed information on the API take a look here. The following section shows how you can modify your form to allow WYSIWYG functionalities. Convert your page to use ad_form (some changes but worth it) Here an examples. From: template::form create my_form template::element create my_form my_form_id -label "The ID" -datatype integer -widget hidden template::element create my_form my_input_field_1 -html { size 30 } -label "Label 1" -datatype text -optional template::element create my_form my_input_field_2 -label "Label 2" -datatype text -help_text "Some Help" -after_html {<a name="#">Anchor</a>} To: ad_form -name my_form -form { my_form_id:key(acs_object_id_seq) {my_input_field_1:text,optional {label "Label 1"} {html {size 30}}} {my_input_field_2:text {label "Label 2"} {help_text "Some Help"} {after_html {<a name="#">Anchor</a>}}} } ... You must not give your your form the same name that your page has. Otherwise HTMLArea won't load. Convert your textarea widget to a richtext widget and enable htmlarea. The htmlarea_p-flag can be used to prevent WYSIWYG functionality. Defaults to true if left away. From: {my_input_field_2:text To: {my_input_field_2:richtext(richtext) {htmlarea_p "t"} The richtext widget presents a list with two elements: text and content type. To learn more on existing content types search in Google for "MIME-TYPES" or take a look at the cr_mime_types table. Make sure that both values are passed as a list to your ad_form or you will have problems displaying the content or handling the data manipulation correctly. Depending on the data model of your package you either support a content format or don't. If you don't you can assume "text/html" or "text/richtext" or "text/enhanced". The relevant parts in your ad_form definition are the switches -new_data, -edit_data, -on_request and -on_submit. To allow your data to display correctly you need to add an -on_request block. If you have the format stored in the database pass this as well else use "text/html": set my_input_field_2 [template::util::richtext::create $my_input_field_2 "text/html"] Now make sure that your SQL queries that do the data manipulation retrieve the correct value. If you simply use my_input_field_2 you will store a list. Thus you need to add an -on_submit block: set my_input_field_2 [ template::util::richtext::get_property contents $my_input_field_2] set format [ template::util::richtext::get_property format $my_input_field_2] #This is optional Now the correct values for my_input_field_2 and format are passed to the -new_data and -edit_data blocks which don't need to get touched. To make HTMLArea optional per package instance define a string parameter UseWysiwygP which defaults 0 for your package using the APM. In your edit page make the following changes # Is WYSIWYG enabled? set use_wysiwyg_p [parameter::get -parameter "UseWysiwygP" -default "f"] ... {htmlarea_p $use_wysiwyg_p} The -on_request switch should set this value for your form. set htmlarea_p $use_wysiwyg_p All you need now is a configuration page where the user can change this setting. Create a configure.tcl file: ad_page_contract { This page allows a faq admin to change the UseWysiwygP setting } { {return_url ""} } set title "Should we support WYSIWYG?" set context [list $title] set use_wysiwyg_p ad_form -name categories_mode -form { {enabled_p:text(radio) {label "Enable WYSIWYG"} {options {{Yes t} {No f}}} {value $use_wysiwyg_p} } {return_url:text(hidden) {value $return_url}} {submit:text(submit) {label "Change"}} } -on_submit { parameter::set_value -parameter "UseWysiwygP" -value $enabled_p if {![empty_string_p $return_url]} { ns_returnredirect $return_url } } In the corresponding ADP file write <master> <property name="title">@title@</property> <property name="context">@context@</property> <formtemplate id="categories_mode"></formtemplate> And finally reference this page from your admin page #TCL: set return_url [ad_conn url] #ADP: <a href=configure?<%=[export_url_vars return_url]%>>Configure</a> Adding in parameters for your package Each instance of a package can have paramaters associated with it. These are like preferences, and they can be set by the administrator for each application to change the behavior of your application. To add parameters for your package, go to the Automatic Package Manager (/acs-admin/apm) Click on your package Under the Manage section, click on Parameters It's fairly self-explanatory at this point. Create the parameters you want, and then access them in your code using the parameter::get procedure. Writing upgrade scripts by Jade Rubick If your package changes its data model, you have to write an upgrade script. This is very easy in OpenACS. First, you want to make sure you change the original .sql file so that new installation will have the new data model. Next, check what version your package is currently at. For example, it may be at version 1.0b1. Create a file in sql/postgres/upgrade called packagename-1.0b1-1.0b2.sql and put the SQL code that will update the data model. For example, if you add in a column, you would have an alter table add column statement in this file. Test this out very well, because data model changes are more serious and fundamental changes than the program .tcl files. Now use the APM to create a new package version 1.0b2. Commit all your changes, tag the release (), and both new installations and upgrades will be taken care of. Connect to a second database It is possible to use the OpenACS TCL database API with other databases. In this example, the OpenACS site uses a PostGre database, and accesses another PostGre database called legacy. Modify config.tcl to accomodate the legacy database, and to ensure that the legacy database is not used for standard OpenACS queries: ns_section ns/db/pools ns_param pool1 "Pool 1" ns_param pool2 "Pool 2" ns_param pool3 "Pool 3" ns_param legacy "Legacy" ns_section ns/db/pool/pool1 #Unchanged from default ns_param maxidle 1000000000 ns_param maxopen 1000000000 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database == "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource ${db_host}:${db_port}:${db_name} ns_param user $db_user ns_param password "" } ns_section ns/db/pool/pool2 #Unchanged from default, removed for clarity ns_section ns/db/pool/pool3 #Unchanged from default, removed for clarity ns_section ns/db/pool/legacy ns_param maxidle 1000000000 ns_param maxopen 1000000000 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug ns_param driver postgres ns_param datasource ${db_host}:${db_port}:legacy_db ns_param user legacy_user ns_param password legacy_password ns_section ns/server/${server}/db ns_param pools * ns_param defaultpool pool1 ns_section ns/server/${server}/acs/database ns_param database_names [list main legacy] ns_param pools_main [list pool1 pool2 pool3] ns_param pools_legacy [list legacy] To use the legacy database, use the -dbn flag for any of the db_ API calls. For example, suppose there is a table called "foo" in the legacy system, with a field "bar". List "bar" for all records with this tcl file: db_foreach -dbn legacy get_bar_query { select bar from foo limit 10 } { ns_write "<br/>$bar" } Future Topics How to enforce security so that users can't change other users records How to use the content management tables so that ... what? How to change the default stylesheets for Form Builder HTML forms. How to make your package searchable with OpenFTS/Oracle How to prepare pagelets for inclusion in other pages How and when to put procedures in a tcl procedure library More on ad_form - data validation, other stuff. (plan to draw from Jon Griffin's doc) partialquery in xql How to use the html/text entry widget to get the "does this look right" confirm page APM package dependencies See also the OpenACS Programming FAQ
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml0000644000175000017500000001500011501005400027010 0ustar frankiefrankie Setting Up Database Objects by Joel Aufrecht Code the data model We create all database objects with scripts in the myfirstpackage/sql/ directory. All database scripts are database-specific and are thus in either the myfirstpackage/sql/oracle or myfirstpackage/sql/postgresql directory. Packages can support Oracle, PostgreSQL, or both. In this tutorial, we will be working with PostgreSQL The first file will be myfirstpackage-create.sql. The package manager requires a file with the name packagekey-create.sql, which it will run automatically when the package in installed. This file should create all tables and views. Our package is going to store all of its information in one table. It takes more than just a CREATE TABLE command, however, because we want to integrate our table with the OpenACS system. By making each record in our table an OpenACS object, we gain access to the permissions system and to services that integrate with OpenACS objects, such as general-comments and notification. The cost is that our table creation code must include several functions, stored procedures, and is complicated (even for simple tables). There are many kinds of OpenACS objects in the system. (You can see them with the psql code: select object_type from acs_object_types;.) One such object is the content_item, which is part of the content repository system. To use it, we will make our data objects children of the content_revision object, which is a child of content_item. Not only will we gain the benefits of both OpenACS Objects and content objects, we can also use some content repository functions to simplify our database creation. (More information about ACS Objects. More information about the Content Repository.)
    Tutorial Data Model
    The top of each sql file has some standard comments, including doc tags such as @author which will be picked up by the API browser. The string $Id:$ will automatically be expanded when the file is checked in to cvs. [$OPENACS_SERVICE_NAME ~]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/sql/postgresql [$OPENACS_SERVICE_NAME postgresql]$ emacs myfirstpackage-create.sql Paste the text below into the file, save, and close.
    The Database Creation Script example missing
    The creation script calls a function in PL/pgSQL (PL/pgSQL is a procedural language extention to sql), content_type__create_type, which in turn creates the necessary database changes to support our data object. Notice the use of "mfp." This is derived from "My First Package" and ensures that our object is unlikely to conflict with objects from other packages. Create a database file to drop everything if the package is uninstalled. [$OPENACS_SERVICE_NAME postgresql]$ emacs myfirstpackage-drop.sql
    Database Deletion Script example missing
    (like the creation script the drop script calls a PL/pgSQL function: content_type__drop_type Run the create script manually to add your tables and functions. [$OPENACS_SERVICE_NAME postgresql]$ psql service0 -f myfirstpackage-create.sql psql:myfirstpackage-create.sql:15: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'mfp_notes_pkey' for table 'mfp_notes' psql:myfirstpackage-create.sql:15: NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) content_type__create_type --------------------------- 0 (1 row) [$OPENACS_SERVICE_NAME postgresql]$ If there are errors, use them to debug the sql file and try again. If there are errors in the database table creation, you may need to run the drop script to drop the table so that you can recreate it. The drop script will probably have errors since some of the things it's trying to drop may be missing. They can be ignored. Once you get the same output as shown above, test the drop script: [$OPENACS_SERVICE_NAME postgresql]$ psql service0 -f myfirstpackage-drop.sql content_type__drop_type ------------------------- 0 (1 row) [$OPENACS_SERVICE_NAME postgresql]$ Once both scripts are working without errors, run the create script one last time and proceed. [$OPENACS_SERVICE_NAME postgresql]$ psql service0 -f myfirstpackage-create.sql
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/templates.xml0000644000175000017500000002116610456621135026613 0ustar frankiefrankie %myvars; ]> Using Templates in OpenACS By Pete Su Overview The OpenACS Template System (ATS) is designed to allow developers to cleanly separate application logic from display logic. The intent is to have all of the logic related to manipulating the database and other application state data in one place, and all the logic related to displaying the state of the application in another place. This gives developer's quicker customization and easier upgrades, and also allows developers and graphic designers to work more independently. In ATS, you write two files for every user-visible page in the system. One is a plain .tcl file and the other is a special .adp file. The .tcl file runs a script that sets up a set of name/value bindings that we call data sources. These data sources are generally the results of Tcl and/or database queries or some combination thereof. The template system automatically makes them available to the .adp file, or the display part of the template, which is written in a combination of HTML, special template related tags, and data source substitutions. In the overall context of our example OpenACS Notes application, this document will show you how to set up a simple templated page that displays a form to the user for entering new notes into the system. In later sections of the DG, we'll discuss how to develop the pages that actually add notes to the database, how to provide a separate instance of the Notes application to every user and how to design appropriate access control policies for the system. Entering Notes In order for the Notes application to be useful, we have to allow users to enter data into the database. Typically, this takes two pages: one that displays a form for data entry, and another page that runs the code to update the database and tells the user whether the operation failed. In this document, we will use the template system to build the first of these pages. This isn't a very interesting use of the system since we won't be displaying much data, but we'll cover more on that end later. The .tcl file for the form entry template is pretty simple. Here, the only thing we need from the database is a new ID for the note object to be inserted. Open up a file called note-add.tcl in the ROOT/packages/notes/www directory, and put the following code in it: ad_page_contract { Form to add a note in OpenACS Notes. @author Jane Coder @creation-date 11 Oct 2000 } -properties { note_id:onevalue submit_label:onevalue target:onevalue page_title:onevalue } -query { } set user_id [ad_verify_and_get_user_id] db_1row user_name { select first_names || ' ' || last_name as user_name from users where forum_id = :user_id } set page_title "Add a note for $user_name" set submit_label "Add" set target "note-add-2" set note_id [db_nextval acs_object_id_seq] ad_return_template "note-add" Some things to note about this code: The procedure ad_page_contract is always the first thing a .tcl file calls, if it's under the www/ directory (i.e. not a Tcl library file). It does validation of input values from the HTTP request (i.e. form variables) and in this case, the -properties clause is used to set up the data sources that we will ship over to the .adp part of the page. In this case, we only use the simplest possible kind of data source, called a onevalue, which hold just a single string value. Later on, we'll see how to use more powerful kinds of data sources for representing multiple rows from an SQL query. You also include overall documentation for the page in the contract, and OpenACS has automatic tools that extract this documentation and make it browsable. After being declared in the ad_page_contract, each property is just a simple Tcl variable. The template system passes the final value of the variable to the .adp template when the .tcl file is processed. The call ad_return_template tells the template system what .adp template page to fetch to display the properties that have been processed. By default, the template system will look for a file by the same name as the .tcl file that just ran, but with an .adp extension. Next we write the corresponding .adp page. This page outputs HTML for the form, and also contains placeholders whose values are substituted in from the properties set up by the .tcl file. Create a file called note-add.adp in your editor, and insert this text: <master src="master"> <property name="title">@page_title@</property> <property name="context_bar">@context_bar@</property> <form action=@target@> <p>Title: <input type="text" name="title" value=""> </p> <p>Body: <input type="text" name="title" value=""> </p> <p> <center> <input type=submit value="@submit_label@"> </center> </p> </form> The main point to note here is: when you want to substitute a value into a page, you put the name of the data source between two "@" characters. Another point to note is the use of a master template: Master templates allow you do centralize display code that is used throughout an application in a single file. In this case, we intend to have a master template that does the standard page headers and footers for us - create the master.adp file, which looks like this: <%= [ad_header $title] %> <h2>@title@</h2> <%= [eval ad_context_bar $context_bar] %> <hr> <slave> <br clear="all"> <%= [ad_footer] %> The main subtlety in this code is the inline Tcl code for running procs to build the header, footer, context bar, etc. Also, note the property substitutions that happen here, the values of which are set up in the <property> tags in the slave page. After putting all these files into ROOT/packages/notes/www, you should be able to go to /notes/ URL for your server and see the input form. Summary Templates separate application logic from display logic by requiring the developer to write pages in two stages, one file for database queries and application logic, and another for display. In OpenACS, the logic part of the page is just a .tcl that sets up data sources that are used by the display part of the page. The display part of the page is an .adp file with some special tags and notations for dealing with display logic and inserting properties into the text of the page. Later on we'll get into templates more deeply, and show how to use database queries as data sources. Documentation Templating system documentation ($Id: templates.xml,v 1.10 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/cvs.xml0000644000175000017500000001365310456621135025412 0ustar frankiefrankie %myvars; ]> Using CVS with an OpenACS Site By Joel Aufrecht Add the Service to CVS - OPTIONAL cvs setup These steps take an existing OpenACS directory and add it to a CVS repository. Create and set permissions on a subdirectory in the local cvs repository. [root root]# mkdir /cvsroot/$OPENACS_SERVICE_NAME [root root]# chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /cvsroot/$OPENACS_SERVICE_NAME [root root]# mkdir /cvsroot/$OPENACS_SERVICE_NAME chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /cvsroot/$OPENACS_SERVICE_NAME Add the repository location to the user environment. On some systems, you may get better results with .bash_profile instead of .bashrc. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ emacs .bashrc Put this string into /home/$OPENACS_SERVICE_NAME/.bashrc: export CVSROOT=/cvsroot [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit logout [root root]# Import all files into cvs. In order to work on files with source control, the files must be checked out from cvs. So we will import, move aside, and then check out all of the files. In the cvs import command, $OPENACS_SERVICE_NAME refers to the cvs repository to use; it uses the CVSROOT plus this string, i.e. /cvsroot/$OPENACS_SERVICE_NAME. "OpenACS" is the vendor tag, and "&cvsversiontag;" is the release tag. These tags will be useful in upgrading and branching. -m sets the version comment. [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs import -m "initial install" $OPENACS_SERVICE_NAME OpenACS &cvsversiontag; N $OPENACS_SERVICE_NAME/license.txt N $OPENACS_SERVICE_NAME/readme.txt (many lines omitted) N $OPENACS_SERVICE_NAME/www/SYSTEM/flush-memoized-statement.tcl No conflicts created by this import [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit [root root]# su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver/$OPENACS_SERVICE_NAME cvs import -m "initial install" $OPENACS_SERVICE_NAME OpenACS &cvsversiontag; exit Move the original directory to a temporary location, and check out the cvs repository in its place. [root root]# mv /var/lib/aolserver/$OPENACS_SERVICE_NAME /var/tmp [root root]# mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME [root root]# chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /var/lib/aolserver/$OPENACS_SERVICE_NAME [root root]# su - $OPENACS_SERVICE_NAME [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver [$OPENACS_SERVICE_NAME aolserver]$ cvs checkout $OPENACS_SERVICE_NAME cvs checkout: Updating $OPENACS_SERVICE_NAME U $OPENACS_SERVICE_NAME/license.txt (many lines omitted) U $OPENACS_SERVICE_NAME/www/SYSTEM/dbtest.tcl U $OPENACS_SERVICE_NAME/www/SYSTEM/flush-memoized-statement.tcl [$OPENACS_SERVICE_NAME aolserver]$ exit logout [root root]# mv /var/lib/aolserver/$OPENACS_SERVICE_NAME /var/tmp mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /var/lib/aolserver/$OPENACS_SERVICE_NAME su - $OPENACS_SERVICE_NAME cd /var/lib/aolserver cvs checkout $OPENACS_SERVICE_NAME exit If the service starts correctly, come back and remove the temporary copy of the uploaded files. openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/tutorial.xml0000644000175000017500000002100611501005400026430 0ustar frankiefrankie %myvars; ]> Creating an Application Package by Joel Aufrecht The intended page map Overview To start developing new code in OpenACS, we build a new package. A package is a a discrete collection of web pages, tcl code, and database tables and procedures. A package with user interface is called an application; a package which provides functions to other packages and has no direct interface, a service. A package can be installed, upgraded, and removed. It communicates with other packages through an API. This chapter walks you through the minimum steps to create a useful package, including writing documentation, setting up database tables and procedures, writing web pages, debugging, and automatic regression testing. This tutorial uses the content repository package. This radically simplifies the database work, but forces us to work around the content repository's limitations, including an incomplete TCL API. So the tutorial is messier than we'd like right now. Code that is temporary hackage is clearly marked. In this tutorial, we will make an application package for displaying a list of text notes. Before you begin You will need: A computer with a working installation of OpenACS. If you don't have this, see . Example files, which are included in the standard OpenACS &version; distribution.
    Assumptions in this section Fully qualified domain name of your server yourserver.test URL of your server http://yourserver.test:8000 Name of development account $OPENACS_SERVICE_NAME New Package key myfirstpackage
    Use the APM to initialize a new package We use the ACS Package Manager (APM) to add, remove, and upgrade packages. It handles package meta-data, such as lists of files that belong in the package. Each package is uniquely identified by a package key. To start developing a new package, use the APM to create an empty package with our new package key, myfirstpackage. This will create the initial directories, meta-information files, and database entries for a new package. (More info on APM) Browse to http://yourserver:8000/acs-admin/apm. Click Create a New Package. Fill in the fields listed below. Ignore the rest (and leave the check boxes alone). (Some will change automatically. Don't mess with those.) Package Key: myfirstpackage Package Name: My First Package Package Plural: My First Package Package Type: Application Initial Version: 0.1d Summary: This is my first package. At the bottom, click Create Package. This creates a package rooted at /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage. This is the "home directory" of our new package, and all files in the package will be within this directory. More on the structure of packages). Add an Application Instance to the Server In order to see your work in progress, you must create a map between the URL space of incoming requests and the package application instance. You do this by adding the application in the main site administration). This creates a link between the incoming URL requests and an instance of the application. (More on applications and nodes) You can have instances of a package on one site, each with a different URL and different permissions, all sharing the same code and tables. This requires that a package be developed package-aware. You'll see how to do that in this tutorial. Browse to http://yourserver.test:8000/admin/applications/application-add/. Choose "My First Package" from the list and click OK (the other fields are optional). By mounting the package, we've caused all requests to http://yourserver.test:8000/myfirstpackage to be satisfied from the files at /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www. Quick start The remainder of the tutorial walks you through each file one at a time as you create the package. You can skip all this, and get a working package, by doing the following: cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/tutorial psql $OPENACS_SERVICE_NAME -f myfirstpackage-create.sql cp note-edit.* note-delete.tcl index.* ../../../../myfirstpackage/www/ mkdir ../../../../myfirstpackage/lib cp note-list.* ../../../../myfirstpackage/lib/ cp myfirstpackage-*sql ../../../../myfirstpackage/sql/postgresql/ cp myfirstpackage-procs.tcl ../../../../myfirstpackage/tcl/test/ cp note-procs.tcl ../../../../myfirstpackage/tcl/ After restarting the server, the tutorial application will be installed and working at the url you selected in the previous step.
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/i18n.xml0000644000175000017500000014031511501005400025351 0ustar frankiefrankie %myvars; ]> Internationalization By Peter Marklund and Lars Pind Internationalization and Localization Overview Internationalization and Localization Overview Stage Task Who Internationalization Package Developer uses the acs-lang tools to replace all visible text in a package with message keys. (More information) Package Developer Release Management The newly internationalized package is released. Package Developer The translation server is updated with the new package. Translation server maintainers Localization Translators work in their respective locales to write text for each message key. (More information) Translators Release Management The translated text in the database of the translation server is compared to the current translations in the OpenACS code base, conflicts are resolved, and the new text is written to catalog files on the translation server. Translation server maintainers The catalog files are committed to the OpenACS code base. Translation server maintainers A new version of OpenACS core and/or affected packages is released and published in the OpenACS.org repository. Release Manager Upgrading Site Administrators upgrade their OpenACS sites, either via the automatic upgrade from the Repository or via tarball or CVS Site Administrators Site Administrators import the new translations. Existing local translations, if they exist, are not overwritten. Site Administrators
    How Internationalization/Localization works in OpenACS This document describes how to develop internationalized OpenACS packages, including writing new packages with internationalization and converting old packages. Text that users might see is "localizable text"; replacing monolingual text and single-locale date/time/money functions with generic functions is "internationalization"; translating first generation text into a specific language is "localization." At a minimum, all packages should be internationalized. If you do not also localize your package for different locales, volunteers may use a public "localization server" to submit suggested text. Otherwise, your package will not be usable for all locales. The main difference between monolingual and internationalized packages is that all user-visible text in the code of an internationalized package are coded as "message keys." The message keys correspond to a message catalog, which contains versions of the text for each available language. Script files (.adp and .tcl and .vuh), database files (.sql), and APM parameters are affected. Other differences include: all dates read or written to the database must use internationalized functions. All displayed dates must use internationalized functions. All displayed numbers must use internationalized functions. Localizable text must be handled in ADP files, in TCL files, and in APM Parameters. OpenACS provides two approaches, message keys and localized ADP files. For ADP pages which are mostly code, replacing the message text with message key placeholders is simpler. This approach also allows new translation in the database, without affecting the file system. For ADP pages which are static and mostly text, it may be easier to create a new ADP page for each language. In this case, the pages are distinguished by a file naming convention. User Content OpenACS does not have a general system for supporting multiple, localized versions of user-input content. This document currently refers only to internationalizing the text in the package user interface. Separate Templates for each Locale If the request processor finds a file named filename.locale.adp, where locale matches the user's locale, it will process that file instead of filename.adp. For example, for a user with locale tl_PH, the file index.tl_PH.adp, if found, will be used instead of index.adp. The locale-specific file should thus contain text in the language appropriate for that locale. The code in the page, however, should still be in English. Message keys are processed normally. Message Catalogs Message Keys in Template Files (ADP Files) Internationalizing templates is about replacing human readable text in a certain language with internal message keys, which can then be dynamically replaced with real human language in the desired locale. Message keys themselves should be in ASCII English, as should all code. Three different syntaxes are possible for message keys. "Short" syntax is the recommended syntax and should be used for new development. When internationalizing an existing package, you can use the "temporary" syntax, which the APM can use to auto-generate missing keys and automatically translate to the short syntax. The "verbose" syntax is useful while developing, because it allows default text so that the page is usable before you have done localization. The short: #package_key.message_key# The advantage of the short syntax is that it's short. It's as simple as inserting the value of a variable. Example: #forum.title# The verbose: <trn key="package_key.message_key" locale="locale">default text</trn> The verbose syntax allows you to specify a default text in a certain language. This syntax is not recommended anymore, but it can be convenient for development, because it still works even if you haven't created the message in the message catalog yet, because what it'll do is create the message key with the default text from the tag as the localized message. Example: <trn key="forum.title" locale="en_US">Title</trn> The temporary: <#message_key original text#> This syntax has been designed to make it easy to internationalize existing pages. This is not a syntax that stays in the page. As you'll see later, it'll be replaced with the short syntax by a special feature of the APM. You may leave out the message_key by writing an underscore (_) character instead, in which case a message key will be auto-generated by the APM. Example: <_ Title> We recommend the short notation for new package development. Message Keys in TCL Files In adp files message lookups are typically done with the syntax \#package_key.message_key\#. In Tcl files all message lookups *must* be on either of the following formats: Typical static key lookup: [_ package_key.message_key] - The message key and package key used here must be string literals, they can't result from variable evaluation. Static key lookup with non-default locale: [lang::message::lookup $locale package_key.message_key] - The message key and package key used here must be string literals, they can't result from variable evaluation. Dynamic key lookup: [lang::util::localize $var_with_embedded_message_keys] - In this case the message keys in the variable var_with_embedded_message_keys must appear as string literals \#package_key.message_key\# somewhere in the code. Here is an example of a dynamic lookup: set message_key_array { dynamic_key_1 \#package_key.message_key1\# dynamic_key_2 \#package_key.message_key2\# } set my_text [lang::util::localize $message_key_array([get_dynamic_key])] Translatable texts in page TCL scripts are often found in page titles, context bars, and form labels and options. Many times the texts are enclosed in double quotes. The following is an example of grep commands that can be used on Linux to highlight translatable text in TCL files: # Find text in double quotes find -iname '*.tcl'|xargs egrep -i '"[a-z]' # Find untranslated text in form labels, options and values find -iname '*.tcl'|xargs egrep -i '\-(options|label|value)'|egrep -v '<#'|egrep -v '\-(value|label|options)[[:space:]]+\$[a-zA-Z_]+[[:space:]]*\\?[[:space:]]*$' # Find text in page titles and context bars find -iname '*.tcl'|xargs egrep -i 'set (title|page_title|context_bar) '|egrep -v '<#' # Find text in error messages find -iname '*.tcl'|xargs egrep -i '(ad_complain|ad_return_error)'|egrep -v '<#' You may mark up translatable text in TCL library files and TCL pages with temporary tags on the <#key text#> syntax. If you have a sentence or paragraph of text with variables and or procedure calls in it you should in most cases try to turn the whole text into one message in the catalog (remember that translators is made easier the longer the phrases to translate are). In those cases, follow these steps: For each message call in the text, decide on a variable name and replace the procedure call with a variable lookup on the syntax %var_name%. Remember to initialize a tcl variable with the same name on some line above the text. If the text is in a tcl file you must replace variable lookups (occurences of $var_name or ${var_name}) with %var_name% You are now ready to follow the normal procedure and mark up the text using a tempoarary message tag (<#_ text_with_percentage_vars#>) and run the action replace tags with keys in the APM. The variable values in the message are usually fetched with upvar, here is an example from dotlrn: ad_return_complaint 1 "Error: A [parameter::get -parameter classes_pretty_name] must have <em>no</em>[parameter::get -parameter class_instances_pretty_plural] to be deleted" was replaced by: set subject [parameter::get -localize -parameter classes_pretty_name] set class_instances [parameter::get -localize -parameter class_instances_pretty_plural] ad_return_complaint 1 [_ dotlrn.class_may_not_be_deleted] This kind of interpolation also works in adp files where adp variable values will be inserted into the message. Alternatively, you may pass in an array list of the variable values to be interpolated into the message so that our example becomes: set msg_subst_list [list subject [parameter::get -localize -parameter classes_pretty_name] class_instances [parameter::get -localize -parameter class_instances_pretty_plural]] ad_return_complaint 1 [_ dotlrn.class_may_not_be_deleted $msg_subst_list] When we were done going through the tcl files we ran the following commands to check for mistakes: # Message tags should usually not be in curly braces since then the message lookup may not be # executed then (you can usually replace curly braces with the list command). Find message tags # in curly braces (should return nothing, or possibly a few lines for inspection) find -iname '*.tcl'|xargs egrep -i '\{.*<#' # Check if you've forgotten space between default key and text in message tags (should return nothing) find -iname '*.tcl'|xargs egrep -i '<#_[^ ]' # Review the list of tcl files with no message lookups for tcl_file in $(find -iname '*.tcl'); do egrep -L '(<#|\[_)' $tcl_file; done When you feel ready you may vist your package in the package manager and run the action "Replace tags with keys and insert into catalog" on the TCL files that you've edited to replace the temporary tags with calls to the message lookup procedure. Dates, Times, and Numbers in TCL files Most date, time, and number variables are calculated in TCL files. Dates and times must be converted when stored in the database, when retrieved from the database, and when displayed. All dates are stored in the database in the server's timezone, which is an APM Parameter set at /acs-lang/admin/set-system-timezone and readable at lang::system::timezone.. When retrieved from the database and displayed, dates and times must be localized to the user's locale. APM Parameters Some parameters contain text that need to be localized. In this case, instead of storing the real text in the parameter, you should use message keys using the short notation above, i.e. #package_key.message_key#. In order to avoid clashes with other uses of the hash character, you need to tell the APM that the parameter value needs to be localized when retrieving it. You do that by saying: parameter::get -localize. Here are a couple of examples. Say we have the following two parameters, taken directly from the dotlrn package. Parameter Name Parameter Value class_instance_pages_csv #dotlrn.class_page_home_title#,Simple 2-Column;#dotlrn.class_page_calendar_title#,Simple 1-Column;#dotlrn.class_page_file_storage_title#,Simple 1-Column departments_pretty_name #departments_pretty_name# Then, depending on how we retrieve the value, here's what we get: Command used to retrieve Value Retrieved Value parameter::get -localize -parameter class_instances_pages_csv Kurs Startseite,Simple 2-Column;Kalender,Simple 1-Column;Dateien,Simple 1-Column parameter::get -localize -parameter departments_pretty_name Abteilung parameter::get -parameter departments_pretty_name #departments_pretty_name# The value in the rightmost column in the table above is the value returned by an invocation of parameter::get. Note that for localization to happen you must use the -localize flag. The locale used for the message lookup will be the locale of the current request, i.e. lang::conn::locale or ad_conn locale. Developers are responsible for creating the keys in the message catalog, which is available at /acs-lang/admin/ How to Internationalize a Package For multilingual websites we recommend using the UTF8 charset. In order for AOLserver to use utf8 you need to set the config parameters OutputCharset and URLCharset to utf-8 in your AOLserver config file (use the etc/config.tcl template file). This is the default for OpenACS 5.1 and later. For sites running on Oracle you need to make sure that AOLserver is running with the NLS_LANG environment variable set to .UTF8. You should set this variable in the nsd-oracle run script (use the acs-core-docs/www/files/nds-oracle.txt template file). Replace all text with temporary message tags From/acs-admin/apm/, select a package and then click on Internationalization, then Convert ADP, Tcl, and SQL files to using the message catalog.. This pass only changes the adp files; it does not affect catalog files or the catalog in the database. You will now be walked through all of the selected adp pages. The UI shows you the intended changes and lets you edit or cancel them key by key. Replace the temporary message tags in ADP files From the same Convert ADP ... page in /acs-admin/apm as in the last step, repeat the process but deselect Find human language text ... and select Replace <# ... #> tags ... and click OK. This step replaces all of the temporary tags with "short" message lookups, inserts the message keys into the database message catalog, and then writes that catalog out to an xml file. Replace human-readable text in TCL files with temporary tags Examine all of the tcl files in the packages for human-readable text and replace it with temporary tags. The temporary tags in TCL are slightly different from those in ADP. If the first character in the temporary tag is an underscore (_), then the message keys will be auto-generated from the original message text. Here is an unmodified tcl file: set title "Messages for $a(name) in $b(label)" set context [list [list . "SimPlay"] \ [list [export_vars -base case-admin { case_id }] \ "Administer $a(name)"] \ "Messages for $a(name)"] ... and here is the same file after temporary message tags have been manually added: set title <#admin_title Messages for %a.name% in %b.label%#> set context [list [list . <#_ SimPlay#>] \ [list [export_vars -base case-admin { case_id }] \ <#_ Administer %a.name%#>] \ <#_ Messages for %a.name%#>] Note that the message key case_admin_page_title was manually selected, because an autogenerated key for this text, with its substitute variables, would have been very confusing Replace the temporary message tags in TCL files Repeat step 2 for tcl files. Here is the example TCL file after conversion: set title [_ simulation.admin_title] set context [list [list . [_ simulation.SimPlay]] \ [list [export_vars -base case-admin { case_id }] \ [_ simulation.lt_Administer_name_gt]] \ [_ simulation.lt_Messages_for_role_pre]] Internationalize SQL Code If there is any user-visible TCL code in the .sql or .xql files, internationalize that the same way as for the TCL files. Internationalize Package Parameters See Internationalize Date and Time queries Find datetime in .xql files. Use command line tools to find suspect SQL code: grep -r "to_char.*H" * grep -r "to_date.*H" * In SQL statements, replace the format string with the ANSI standard format, YYYY-MM-DD HH24:MI:SS and change the field name to *_ansi so that it cannot be confused with previous, improperly formatting fields. For example, to_char(timestamp,'MM/DD/YYYY HH:MI:SS') as foo_date_pretty becomes to_char(timestamp,'YYYY-MM-DD HH24:MI:SS') as foo_date_ansi In TCL files where the date fields are used, convert the datetime from local server timezone, which is how it's stored in the database, to the user's timezone for display. Do this with the localizing function lc_time_system_to_conn: set foo_date_ansi [lc_time_system_to_conn $foo_date_ansi] When a datetime will be written to the database, first convert it from the user's local time to the server's timezone with lc_time_conn_to_system. When a datetime field will be displayed, format it using the localizing function lc_time_fmt. lc_time_fmt takes two parameters, datetime and format code. Several format codes are usable for localization; they are placeholders that format dates with the appropriate codes for the user's locale. These codes are: %x, %X, %q, %Q, and %c. set foo_date_pretty [lc_time_fmt $foo_date_ansi "%x %X"] Use the _pretty version in your ADP page. %c: Long date and time (Mon November 18, 2002 12:00 AM) %x: Short date (11/18/02) %X: Time (12:00 AM) %q: Long date without weekday (November 18, 2002) %Q: Long date with weekday (Monday November 18, 2002) The "q" format strings are OpenACS additions; the rest follow unix standards (see man strftime). Internationalize Numbers To internationalize numbers, use lc_numeric $value, which formats the number using the appropriate decimal point and thousand separator for the locale. Internationalizing Forms When coding forms, remember to use message keys for each piece of text that is user-visible, including form option labels and button labels. Checking the Consistency of Catalog Files This section describes how to check that the set of keys used in message lookups in tcl, adp, and info files and the set of keys in the catalog file are identical. The scripts below assume that message lookups in adp and info files are on the format \#package_key.message_key\#, and that message lookups in tcl files are always is done with one of the valid lookups described above. The script further assumes that you have perl installed and in your path. Run the script like this: acs-lang/bin/check-catalog.sh package_key where package_key is the key of the package that you want to test. If you don't provide the package_key argument then all packages with catalog files will be checked. The script will run its checks primarily on en_US xml catalog files. Avoiding common i18n mistakes Replace complicated keys with longer, simpler keys When writing in one language, it is possible to create clever code to make correct text. In English, for example, you can put an if command at the end of a word which adds "s" if a count is anything but 1. This pluralizes nouns correctly based on the data. However, it is confusing to read and, when internationalized, may result in message keys that are both confusing and impossible to set correctly in some languages. While internationalizing, watch out that the automate converter does not create such keys. Also, refactor compound text as you encounter it. The automated system can easily get confused by tags within message texts, so that it tries to create two or three message keys for one long string with a tag in the middle. In these cases, uncheck those keys during the conversion and then edit the files directly. For example, this code: <p class="form-help-text"><b>Invitations</b> are sent, when this wizard is completed and casting begins.</p> has a bold tag which confuses the converter into thinking there are two message keys for the text beginning "Invitations ..." where there should be one: Instead, we cancel those keys, edit the file manually, and put in a single temporary message tag: <p class="form-help-text"> <#Invitations_are_sent <b>Invitations</b> are sent, when this wizard is completed and casting begins.#> </p> Complex if statements may produce convoluted message keys that are very hard to localize. Rewrite these if statements. For example: Select which case <if @simulation.casting_type@ eq "open">and role</if> to join, or create a new case for yourself. If you do not select a case <if @simulation.casting_type@ eq "open">and role</if> to join, you will be automatically assigned to a case <if @simulation.casting_type@ eq "open">and role</if> when the simulation begins. ... can be rewritten: <if @simulation.casting_type@ eq "open"> Select which case and role to join, or create a new case for yourself. If you do not select a case and role to join, you will be automatically assigned to a case and role when the simulation begins. </if> <else> Select which case to join, or create a new case for yourself. If you do not select a case to join, you will be automatically assigned to a case when the simulation begins. </else> Another example, where bugs are concatenated with a number: <if @components.view_bugs_url@ not nil> <a href="@components.view_bugs_url@" title="View the @pretty_names.bugs@ for this component"> </if> @components.num_bugs@ <if @components.num_bugs@ eq 1> @pretty_names.bug@ </if> <else> @pretty_names.bugs@ </else> <if @components.view_bugs_url@ not nil> </a> </if> <if @components.view_bugs_url@ not nil> <a href="@components.view_bugs_url@" title="#bug-tracker.View_the_bug_fo_component#"> </if> @components.num_bugs@ <if @components.num_bugs@ eq 1> @pretty_names.bug@ </if> <else> @pretty_names.bugs@ </else> <if @components.view_bugs_url@ not nil> </a> </if> It would probably be better to do this as something like: <if @components.view_bugs_url@ not nil> <if @components.num_bugs@ eq 1> <a href="@components.view_bugs_url@" title="#bug-tracker.View_the_bug_fo_component#">#bug-tracker.one_bug#</a> </if><else> <a href="@components.view_bugs_url@" title="#bug-tracker.View_the_bug_fo_component#">#bug-tracker.N_bugs#</a> </else> </if> Don't combine keys in display text Converting a phrase from one language to another is usually more complicated than simply replacing each word with an equivalent. When several keys are concatenated, the resulting word order will not be correct for every language. Different languages may use expressions or idioms that don't match the phrase key-for-key. Create complete, distinct keys instead of building text from several keys. For example: Original code: multirow append links "New [bug_tracker::conn Bug]" Problematic conversion: multirow append links "[_ bug-tracker.New] [bug_tracker::conn Bug]" Better conversion: set bug_label [bug_tracker::conn Bug] multirow append links "[_ bug-tracker.New_Bug]" "${url_prefix}bug-add" ... and include the variable in the key: "New %bug_label%". This gives translators more control over the phrase. In this example of bad i18n, full name is created by concatenating first and last name (admittedly this is pervasive in the toolkit): <a href="@past_version.maintainer_url@" title="#bug-tracker.Email# @past_version.maintainer_email@"> @past_version.maintainer_first_names@ @past_version.maintainer_last_name@</a> Avoid unnecessary duplicate keys. When phrases are exactly the same in several places, use a single key. For common words such as Yes and No, you can use a library of keys at acs-kernel. For example, instead of using myfirstpackage.Yes, you can use acs-kernel.Yes. You can also use the Message Key Search facility to find duplicates. Be careful, however, building up sentences from keys because grammar and other elements may not be consistent across different locales. Additional discussion: Re: Bug 961 ("Control Panel" displayed instead of "Administer"), Translation server upgraded, and Localization questions. Don't internationalize internal code words Many packages use code words or key words, such as "open" and "closed", which will never be shown to the user. They may match key values in the database, or be used in a switch or if statement. Don't change these. For example, the original code is workflow::case::add_log_data \ -entry_id $entry_id \ -key "resolution" \ -value [db_string select_resolution_code {}] This is incorrectly internationalized to workflow::case::add_log_data \ -entry_id $entry_id \ -key "[_ bug-tracker.resolution]" \ -value [db_string select_resolution_code {}] But resolution is a keyword in a table and in the code, so this breaks the code. It should not have been internationalized at all. Here's another example of text that should not have been internationalized: {show_patch_status "open"} It is broken if changed to {show_patch_status "[_ bug-tracker.open]"} Fix automatic truncated message keys The automatic converter may create unique but crytic message keys. Watch out for these and replace them with more descriptive keys. For example: <msg key="You">You can filter by this %component_name% by viisting %filter_url_string%</msg> <msg key="You_1">You do not have permission to map this patch to a bug. Only the submitter of the patch and users with write permission on this Bug Tracker project (package instance) may do so.</msg> <msg key="You_2">You do not have permission to edit this patch. Only the submitter of the patch and users with write permission on the Bug Tracker project (package instance) may do so.</msg> These would be more useful if they were, "you_can_filter", "you_do_not_have_permission_to_map_this_patch", and "you_do_not_have_permission_to_edit_this_patch". Don't worry about exactly matching the english text, because that might change; instead try to capture the meaning of the phrase. Ask yourself, if I was a translator and didn't know how this application worked, would this key and text make translation easy for me? Sometimes the automatic converter creates keys that don't semantically match their text. Fix these: <msg key="Fix">for version</msg> <msg key="Fix_1">for</msg> <msg key="Fix_2">for Bugs</msg> Another example: Bug-tracker component maintainer" was converted to "[_ bug-tracker.Bug-tracker]". Instead, it should be bug_tracker_component_maintainer. Translations in Avoid "clever" message reuse Translations may need to differ depending on the context in which the message appears. Avoid plurals Different languages create plurals differently. Try to avoid keys which will change based on the value of a number. OpenACS does not currently support internationalization of plurals. If you use two different keys, a plural and a singular form, your application will not localize properly for locales which use different rules or have more than two forms of plurals. Quoting in the message catalog for tcl Watch out for quoting and escaping when editing text that is also code. For example, the original string set title "Patch \"$patch_summary\" is nice." breaks if the message text retains all of the escaping that was in the tcl command: <msg>Patch \"$patch_summary\" is nice.</msg> When it becomes a key, it should be: <msg>Patch "$patch_summary" is nice.</msg> Also, some keys had %var;noquote%, which is not needed since those variables are not quoted (and in fact the variable won't even be recognized so you get the literal %var;noquote% in the output). Be careful with curly brackets Code within curly brackets isn't evaluated. TCL uses curly brackets as an alternative way to build lists. But TCL also uses curly brackets as an alternative to quotation marks for quoting text. So this original code array set names { key "Pretty" ...} ... if converted to array set names { key "[_bug-tracker.Pretty]" ...} ... won't work since the _ func will not be called. Instead, it should be array set names [list key [_bug-tracker.Pretty] ...] Design Notes User locale is a property of ad_conn, ad_conn locale. The request processor sets this by calling lang::conn::locale, which looks for the following in order of precedence: Use user preference for this package (stored in ad_locale_user_prefs) Use system preference for the package (stored in apm_packages) Use user's general preference (stored in user_preferences) Use Browser header (Accept-Language HTTP header) Use system locale (an APM parameter for acs_lang) default to en_US For ADP pages, message key lookup occurs in the templating engine. For TCL pages, message key lookup happens with the _ function. In both cases, if the requested locale is not found but a locale which is the default for the language which matches your locale's language is found, then that locale is offered instead. Translator's Guide Most translators use the OpenACS Public Translation Server, because the process of getting new message keys onto the server and getting new translations back into the distribution are handled by the maintainers of that machine. You can also do translation work on your own OpenACS site; this makes your own translations more readily available to you but also means that your work will not be shared with other users unless you take extra steps (contacting an OpenACS core developer or submitting a patch) to get your work back to the OpenACS core. The basic steps for translators: Go to the Localization page and choose the locale that you are translating to. If the locale is not present you need to visit Administration of Localization and create the locale. Translating with Translator Mode To translate messages in the pages they appear, Toggle Translator Mode and then browse to the page you want to translate. Untranslated messages will have a yellow background and a red star that you click to translate the message. Translated messages have a green star next to them that is a hyperlink to editing your translation. There is a history mechanism that allows you to see previous translations in case you would want to revert a translation. While in Translator mode, a list of all message keys appears at the bottom of each page. Batch translation To translate many messages at once, go to Administration of Localization, click on the locale to translate, then click on a package, and then click Batch edit these messages. When creating a new locale based on an existing one, such as creating the Guatamalan version of Spanish, you can copy the existing locale's catalog files using the script /packages/acs-core-docs/www/files/create-new-catalog.sh.
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/programming-with-aolserver.xml0000644000175000017500000003255610456621135032115 0ustar frankiefrankie %myvars; ]> Programming with AOLserver By Michael Yoon, Jon Salz and Lars Pind. The <computeroutput>global</computeroutput> command When using AOLserver, remember that there are effectively two types of global namespace, not one: Server-global: As you'd expect, there is only one server-global namespace per server, and variables set within it can be accessed by any Tcl code running subsequently, in any of the server's threads. To set/get server-global variables, use AOLserver 3's nsv API (which supersedes ns_share from the pre-3.0 API). Script-global: Each Tcl script (ADP, Tcl page, registered proc, filter, etc.) executing within an AOLserver thread has its own global namespace. Any variable set in the top level of a script is, by definition, script-global, meaning that it is accessible only by subsequent code in the same script and only for the duration of the current script execution. The Tcl built-in command global accesses script-global, not server-global, variables from within a procedure. This distinction is important to understand in order to use global correctly when programming AOLserver. Also, AOLserver purges all script-global variables in a thread (i.e., Tcl interpreter) between HTTP requests. If it didn't, that would affect (and complicate) our use of script-global variables dramatically, which would then be better described as thread-global variables. Given AOLserver's behaviour, however, "script-global" is a more appropriate term. Threads and Scheduled Procedures ns_schedule_proc and ad_schedule_proc each take a -thread flag to cause a scheduled procedure to run asychronously, in its own thread. It almost always seems like a good idea to specify this switch, but there's a problem. It turns out that whenever a task scheduled with ns_schedule_proc -thread or ad_schedule_proc -thread t is run, AOLserver creates a brand new thread and a brand new interpreter, and reinitializes the procedure table (essentially, loads all procedures that were created during server initialization into the new interpreter). This happens every time the task is executed - and it is a very expensive process that should not be taken lightly! The moral: if you have a lightweight scheduled procedure which runs frequently, don't use the -thread switch.
    Note also that thread is initialized with a copy of what was installed during server startup, so if the procedure table have changed since startup (e.g. using the APM watch facility), that will not be reflected in the scheduled thread.
    Using <computeroutput>return</computeroutput> The return command in Tcl returns control to the caller procedure. This definition allows nested procedures to work properly. However, this definition also means that nested procedures cannot use return to end an entire thread. This situation is most common in exception conditions that can be triggered from inside a procedure e.g., a permission denied exception. At this point, the procedure that detects invalid permission wants to write an error message to the user, and completely abort execution of the caller thread. return doesn't work, because the procedure may be nested several levels deep. We therefore use ad_script_abort to abort the remainder of the thread. Note that using return instead of ad_script_abort may raise some security issues: an attacker could call a page that performed some DML statement, pass in some arguments, and get a permission denied error -- but the DML statement would still be executed because the thread was not stopped. Note that return -code return can be used in circumstances where the procedure will only be called from two levels deep. Returning More Than One Value From a Function Many functions have a single return value. For instance, empty_string_p returns a number: 1 or 0. Other functions need to return a composite value. For instance, consider a function that looks up a user's name and email address, given an ID. One way to implement this is to return a three-element list and document that the first element contains the name, and the second contains the email address. The problem with this technique is that, because Tcl does not support constants, calling procedures that returns lists in this way necessitates the use of magic numbers, e.g.: set user_info [ad_get_user_info $user_id] set first_name [lindex $user_info 0] set email [lindex $user_info 1] AOLserver/Tcl generally has three mechanisms that we like, for returning more than one value from a function. When to use which depends on the circumstances. Using Arrays and Pass-By-Value The one we generally prefer is returning an array get-formatted list. It has all the nice properties of pass-by-value, and it uses Tcl arrays, which have good native support. ad_proc ad_get_user_info { user_id } { db_1row user_info { select first_names, last_name, email from users where user_id = :user_id } return [list \ name "$first_names $last_name" \ email $email \ namelink "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>" \ emaillink "<a href=\"mailto:$email\">$email</a>"] } array set user_info [ad_get_user_info $user_id] doc_body_append "$user_info(namelink) ($user_info(emaillink))" You could also have done this by using an array internally and using array get: ad_proc ad_get_user_info { user_id } { db_1row user_info { select first_names, last_name, email from users where user_id = :user_id } set user_info(name) "$first_names $last_name" set user_info(email) $email set user_info(namelink) "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>" set user_info(emaillink) "<a href=\"mailto:$email\">$email</a>" return [array get user_info] } Using Arrays and Pass-By-Reference Sometimes pass-by-value incurs too much overhead, and you'd rather pass-by-reference. Specifically, if you're writing a proc that uses arrays internally to build up some value, there are many entries in the array, and you're planning on iterating over the proc many times. In this case, pass-by-value is expensive, and you'd use pass-by-reference.
    The transformation of the array into a list and back to an array takes, in our test environment, approximately 10 microseconds per entry of 100 character's length. Thus you can process about 100 entries per milisecond. The time depends almost completely on the number of entries, and almost not at all on the size of the entries.
    You implement pass-by-reference in Tcl by taking the name of an array as an argument and upvar it. ad_proc ad_get_user_info { -array:required user_id } { upvar $array user_info db_1row user_info { select first_names, last_name, email from users where user_id = :user_id } set user_info(name) "$first_names $last_name" set user_info(email) $email set user_info(namelink) "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>" set user_info(emaillink) "<a href=\"mailto:$email\">$email</a>" } ad_get_user_info -array user_info $user_id doc_body_append "$user_info(namelink) ($user_info(emaillink))" We prefer pass-by-value over pass-by-reference. Pass-by-reference makes the code harder to read and debug, because changing a value in one place has side effects in other places. Especially if have a chain of upvars through several layers of the call stack, you'll have a hard time debugging. Multisets: Using ns_sets and Pass-By-Reference An array is a type of set, which means you can't have multiple entries with the same key. Data structures that can have multiple entries for the same key are known as a multiset or bag. If your data can have multiple entries with the same key, you should use the AOLserver built-in ns_set. You can also do a case-insensitive lookup on an ns_set, something you can't easily do on an array. This is especially useful for things like HTTP headers, which happen to have these exact properties. You always use pass-by-reference with ns_sets, since they don't have any built-in way of generating and reconstructing themselves from a string representation. Instead, you pass the handle to the set. ad_proc ad_get_user_info { -set:required user_id } { db_1row user_info { select first_names, last_name, email from users where user_id = :user_id } ns_set put $set name "$first_names $last_name" ns_set put $set email $email ns_set put $set namelink "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>" ns_set put $set emaillink "<a href=\"mailto:$email\">$email</a>" } set user_info [ns_set create] ad_get_user_info -set $user_info $user_id doc_body_append "[ns_set get $user_info namelink] ([ns_set get $user_info emaillink])" We don't recommend ns_set as a general mechanism for passing sets (as opposed to multisets) of data. Not only do they inherently use pass-by-reference, which we dis-like, they're also somewhat clumsy to use, since Tcl doesn't have built-in syntactic support for them. Consider for example a loop over the entries in a ns_set as compared to an array: # ns_set variant set size [ns_set size $myset] for { set i 0 } { $i < $size } { incr i } { puts "[ns_set key $myset $i] = [ns_set value $myset $i]" } # array variant foreach name [array names myarray] { puts "$myarray($name) = $myarray($name)" } And this example of constructing a value: # ns_set variant set myset [ns_set create] ns_set put $myset foo $foo ns_set put $myset baz $baz return $myset # array variant return [list foo $foo baz $baz ] ns_sets are designed to be lightweight, so memory consumption should not be a problem. However, when using ns_set get to perform lookup by name, they perform a linear lookup, whereas arrays use a hash table, so ns_sets are slower than arrays when the number of entries is large. ($Id: programming-with-aolserver.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/parties.xml0000644000175000017500000004533210506036345026264 0ustar frankiefrankie %myvars; ]> Parties in OpenACS By Rafael H. Schloming Introduction While many applications must deal with individuals and many applications must deal with groups, most applications must deal with individuals or groups. It is often the case with such applications that both individuals and groups are treated identically. Modelling individuals and groups as specializations of one supertype is a practical way to manage both. This concept is so mundane that there is no need to invent special terminology. This supertype is called a "party". A classic example of the "party" supertype is evident in address books. A typical address book might contain the address of a doctor, grocery store, and friend. The first field in an entry in the address book is not labeled a person or company, but a "party". The Data Model The parties developer guide begins with an introduction to the parties data model, since OpenACS community applications likely require using it in some way. Parties The central table in the parties data model is the parties table itself. Every party has exactly one row in this table. Every party has an optional unique email address and an optional url. A party is an acs object, so permissions may be granted and revoked on parties and auditing information is stored in the acs objects table. create table parties ( party_id not null constraint parties_party_id_fk references acs_objects (object_id) constraint parties_party_id_pk primary key, email varchar(100) constraint parties_email_un unique, url varchar(200) ); The persons and groups tables extend the parties table. A row in the persons table represents the most generic form of individual modeled. An individual need not be known to the system as a user. A user is a further specialized form of an individual (discussed later). A row in the groups table represents the most generic form of group modeled, where a group is an aggregation of zero or more individuals. Persons If a party is an individual then there will be a row in the persons table containing first_names and last_name for that individual. The primary key of the persons table (person_id) references the primary key of the parties table (party_id), so that there is a corresponding row in the parties table when there is a row in the persons table. create table persons ( person_id not null constraint persons_person_id_fk references parties (party_id) constraint persons_person_id_pk primary key, first_names varchar(100) not null, last_name varchar(100) not null ); Users The users table is a more specialized form of persons table. A row in users table represents an individual that has login access to the system. The primary key of the users table references the primary key of the persons table. This guarantees that if there is a row in users table then there must be a corresponding row in persons and parties tables. Decomposing all the information associated with a user into the four tables (acs_objects, parties, persons, users) has some immediate benefits. For instance, it is possible to remove access to a user from a live system by removing his entry from the users table, while leaving the rest of his information present (i.e. turning him from a user into a person). Wherever possible the OpenACS data model references the persons or parties table, not the users table. Developers should be careful to only reference the users table in situations where it is clear that the reference is to a user for all cases and not to any other individual for any case. create table users ( user_id not null constraint users_user_id_fk references persons (person_id) constraint users_user_id_pk primary key, password varchar(100), salt varchar(100), screen_name varchar(100) constraint users_screen_name_un unique, priv_name integer default 0 not null, priv_email integer default 5 not null, email_verified_p char(1) default 't' constraint users_email_verified_p_ck check (email_verified_p in ('t', 'f')), email_bouncing_p char(1) default 'f' not null constraint users_email_bouncing_p_ck check (email_bouncing_p in ('t','f')), no_alerts_until date, last_visit date, second_to_last_visit date, n_sessions integer default 1 not null, password_question varchar(1000), password_answer varchar(1000) ); Groups The final piece of the parties data model is the groups data model. A group is a specialization of a party that represents an aggregation of zero or more other parties. The only extra information directly associated with a group (beyond that in the parties table) is the name of the group: create table groups ( group_id not null constraint groups_group_id_fk references parties (party_id) constraint groups_group_id_pk primary key, group_name varchar(100) not null ); There is another piece to the groups data model that records relations between parties and groups. Group Relations Two types of group relations are represented in the data model: membership relations and composite relations. The full range of sophisticated group structures that exist in the real world can be modelled in OpenACS by these two relationship types. Membership relations represent direct membership relation between parties and groups. A party may be a "member" of a group. Direct membership relations are common in administrative practices, and do not follow basic set theory rules. If A is a member of B, and B is a member of C, A is not a member of C. Membership relations are not transitive. Composition relation represents composite relation between two groups. Composite relation is transitive. That is, it works like memberships in set theory. If A is a member of B, and B is a member of C, then A is a member of C. For example, consider the membership relations of Greenpeace, and composite relations of a multinational corporation. Greenpeace, an organization (ie. group), can have both individuals and organizations (other groups) as members. Hence the membership relation between groups and parties. However, someone is not a member of Greenpeace just because they are a member of a group that is a member of Greenpeace. Now, consider a multinational corporation (MC) that has a U.S. division and a Eurasian division. A member of either the U.S. or Eurasian division is automatically a member of the MC. In this situation the U.S. and Eurasian divisions are "components" of the MC, i.e., membership is transitive with respect to composition. Furthermore, a member of a European (or other) office of the MC is automatically a member of the MC. Group Membership Group memberships can be created and manipulated using the membership_rel package. Only one membership object can be created for a given group, party pair. It is possible in some circumstances to make someone a member of a group of which they are already a member. That is because the model distinguishes between direct membership and indirect membership (membership via some composite relationship). For example, a person might be listed in a system as both an individual (direct membership) and a member of a household (indirect membership) at a video rental store. # sql code create or replace package membership_rel as function new ( rel_id in membership_rels.rel_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'membership_rel', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, member_state in membership_rels.member_state%TYPE default null, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return membership_rels.rel_id%TYPE; procedure ban ( rel_id in membership_rels.rel_id%TYPE ); procedure approve ( rel_id in membership_rels.rel_id%TYPE ); procedure reject ( rel_id in membership_rels.rel_id%TYPE ); procedure unapprove ( rel_id in membership_rels.rel_id%TYPE ); procedure deleted ( rel_id in membership_rels.rel_id%TYPE ); procedure delete ( rel_id in membership_rels.rel_id%TYPE ); end membership_rel; / show errors Group Composition Composition relations can be created or destroyed using the composition_rel package. The only restriction on compositions is that there cannot be a reference loop, i.e., a group cannot be a component of itself either directly or indirectly. This constraint is maintained for you by the API. So users do not see some random PL/SQL error message, do not give them the option to create a composition relation that would result in a circular reference. # sql code create or replace package composition_rel as function new ( rel_id in composition_rels.rel_id%TYPE default null, rel_type in acs_rels.rel_type%TYPE default 'composition_rel', object_id_one in acs_rels.object_id_one%TYPE, object_id_two in acs_rels.object_id_two%TYPE, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return composition_rels.rel_id%TYPE; procedure delete ( rel_id in composition_rels.rel_id%TYPE ); end composition_rel; / show errors Views The parties data model does a reasonable job of representing many of the situations one is likely to encounter when modeling organizational structures. We still need to be able to efficiently answer questions like "what members are in this group and all of its components?", and "of what groups is this party a member either directly or indirectly?". Composition relations allow you to describe an arbitrary Directed Acyclic Graph (DAG) between a group and its components. For these reasons the party system provides a bunch of views that take advantage of the internal representation of group relations to answer questions like these very quickly. The group_component_map view returns all the subcomponents of a group including components of sub components and so forth. The container_id column is the group_id of the group in which component_id is directly contained. This allows you to easily distinguish whether a component is a direct component or an indirect component. If a component is a direct component then group_id will be equal to container_id. You can think of this view as having a primary key of group_id, component_id, and container_id. The rel_id column points to the row in acs_rels table that contains the relation object that relates component_id to container_id. The rel_id might be useful for retrieving or updating standard auditing info for the relation. create or replace view group_component_map as select group_id, component_id, container_id, rel_id ... The group_member_map view is similar to group_component_map except for membership relations. This view returns all membership relations regardless of membership state. create or replace view group_member_map as select group_id, member_id, container_id, rel_id ... The group_approved_member_map view is the same as group_member_map except it only returns entries that relate to approved members. create or replace view group_approved_member_map as select group_id, member_id, container_id, rel_id ... The group_distinct_member_map view is a useful view if you do not care about the distinction between direct membership and indirect membership. It returns all members of a group including members of components --the transitive closure. create or replace view group_distinct_member_map as select group_id, member_id ... The party_member_map view is the same as group_distinct_member_map, except it includes the identity mapping. It maps from a party to the fully expanded list of parties represented by that party including the party itself. So if a party is an individual, this view will have exactly one mapping that is from that party to itself. If a view is a group containing three individuals, this view will have four rows for that party, one for each member, and one from the party to itself. create or replace view party_member_map as select party_id, member_id ... The party_approved_member_map view is the same as party_member_map except that when it expands groups, it only pays attention to approved members. create or replace view party_approved_member_map as select party_id, member_id ... Extending The Parties Data Model The parties data model can represent some fairly sophisticated real world situations. Still, it would be foolish to assume that this data model is sufficiently efficient for every application. This section describes some of the more common ways to extend the parties data model. Specializing Users Some applications will want to collect more detailed information for people using the system. If there can be only one such piece of information per user, then it might make sense to create another type of individual that is a further specialization of a user. For example a Chess Club community web site might want to record the most recent score for each user. In a situation like this it would be appropriate to create a subtype of users, say chess_club_users. This child table of the users table would have a primary key that references the users table, thereby guaranteeing that each row in the chess_club_users table has a corresponding row in each of the users, persons, parties, and acs_objects tables. This child table could then store any extra information relevant to the Chess Club community. Specializing Groups If one were to build an intranet application on top of the party system, it is likely that one would want to take advantage of the systems efficient representation of sophisticated organizational structures, but there would be much more specialized information associated with each group. In this case it would make sense to specialize the group party type into a company party type in the same manner as Specializing Users. Specializing Membership Relations The final portion of the parties data model that is designed to be extended is the membership relationship. Consider the intranet example again. It is likely that a membership in a company would have more information associated with it than a membership in an ordinary group. An obvious example of this would be a salary. It is exactly this need to be able to extend membership relations with mutable pieces of state that drove us to include a single integer primary key in what could be thought of as a pure relation. Because a membership relation is an ordinary acs object with object identity, it is as easy to extend the membership relation to store extra information as it is to extend the users table or the groups table. ($Id: parties.xml,v 1.9 2006/09/25 20:32:37 byronl Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/permissions.xml0000644000175000017500000002767511501005400027162 0ustar frankiefrankie %myvars; ]> Groups, Context, Permissions By Pete Su Overview The OpenACS &version; Permissions system allows developers and administrators to set access control policies at the object level, that is, any application or system object represented by a row in the acs_objects table can be access-controlled via a PL/SQL or Tcl interface. The permissions system manages a data model that then allows scripts to check permissions using another API call. Although object level permissions seems appropriate, no developer or administrator wants to explicitly set access control rights for every user and every object on a site. Therefore, OpenACS has two auxiliary mechanisms for making this easier: the Groups system allows users to be grouped together in flexible ways. the object model defines a notion of object context, which allows applications to group objects together into larger security domains. The rest of this document discusses each of these parts, and how they fit together with the permissions system. Groups OpenACS &version; has an abstraction called a party. Parties have a recursive definition. We can illustrate how it works with the following simplified data model. First, we define the parties table, where each party has an email address and a URL for contact information. create table parties ( party_id integer not null references acs_objects(object_id), email varchar(100), url varchar(100) ) Now we define two subtypes of party, one for persons, and one for groups: create table groups ( group_id not null references parties(party_id), group_name varchar(100) not null ) create table persons ( person_id not null references parties(party_id), first_names varchar(100) not null, last_name varchar(100) not null ) The users table is also defined in this data model as a subtype of person. Finally, we define two relations, one for group membership and one for group composition. The composition relation expresses that every member of group A should also be a member of group B. This relation allows us to define a hierarchy of groups. The membership relation maps groups to parties. Each member of a group is a party rather than just a user. That is, groups consist of members that are either a person or an entire group. This allows us to say that group A should be a member of another group B. The groups data model is recursive. Modelling parties as either a person or a group provides a way to model complex hierarchical groupings of persons and groups. The full details of the groups data model is beyond the scope of this tutorial. See or for more details. Permissions NOTE: Much more detailed information about the permissions system and how to use it is available in the document. The permissions data model is a mapping between privileges, parties and objects. Parties and objects have already been discussed. Now we focus on privileges. In OpenACS, a privilege describes the right to perform some operation on some object. Privileges are the basic units out of which we build access control policies. For example in the Unix filesystem, access is controlled by granting users some combination of read, write, or execute privileges on files and directories. In OpenACS &version;, the table of privileges is organized hierarchically so that developers can define privileges that aggregate some set of privileges together. For example, if we have read, write, create and delete privileges, it might be convenient to combine them into a new privilege called "admin". Then, when a user is granted "admin" privilege, she is automatically granted all the child privileges that the privilege contains. The OpenACS &version; kernel data model defines these privileges: # begin acs_privilege.create_privilege('read'); acs_privilege.create_privilege('write'); acs_privilege.create_privilege('create'); acs_privilege.create_privilege('delete'); acs_privilege.create_privilege('admin'); acs_privilege.add_child('admin', 'read'); acs_privilege.add_child('admin', 'write'); acs_privilege.add_child('admin', 'create'); acs_privilege.add_child('admin', 'delete'); commit; end; Note that a user does not gain admin privileges when granted read, write, create and delete privileges, because some operations explicitly require admin privileges. No substitutions. To give a user permission to perform a particular operation on a particular object you call acs_permission.grant_permission like this: # sql code acs_permission.grant_permission ( object_id => some_object_id, grantee_id => some_party_id, privilege => 'some_privilege_name' ); Using just these mechanisms is enough for developers and administrators to effectively define access control for every object in a system. Explicitly defining permissions to every object individually would become very tedious. OpenACS provides a object contexts as a means for controlling permissions of a large group of objects at the same time. Object Context In OpenACS &version;, object context is a scoping mechanism. "Scoping" and "scope" are terms best explained by example: consider some hypothetical rows in the address_book table: ... scope user_id group_id ... ... user 123 ... ... group 456 ... ... public ... The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address book. In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people). Every object lives in a single context. A context is just an another object that represents the security domain to which the object belongs. By convention, if an object A does not have any permissions explicitly attached to it, then the system will look at the context_id column in acs_objects and check the context object there for permissions. Two things control the scope of this search: the structure of the context hierarchy itself, and the value of the security_inherit_p flag in each object. If security_inherit_p flag is set to 't', then the automatic search through the context happens, otherwise it does not. You might set this field to 'f' if you want to override the default permissions in a subtree of some context. For an example of how to use context hierarchy, consider the forums application. With only row-level permissions it is not obvious how to reasonably initialize the access control list when creating a message. At best, we have to explicitly grant various read and write privileges whenever we create a message, which is tedious. A reasonable thing to do is to create an object representing a forum, and point the context_id field of a new message at the forum. Then, suppose we grant every user in the system read-access to this forum. By default, they will automatically have read-access to the new message we just inserted, since the system automatically checks permissions on the message's context. To allow the creator of the message to change the message after it has been posted we grant the user write-access on the message, and we are done. This mechanism allows developers and administrators to define a hierarchy that matches the structure they need for access control in their application. The following picture shows a typical context hierarchy for a hypothetical site:
    The top two contexts in the diagram are called "magic" numbers, because in some sense, they are created by default by OpenACS for a specific purpose. The object default_context represents the root of the context hierarchy for the entire site. All permission searches walk up the tree to this point and then stop. If you grant permissions on this object, then by default those permissions will hold for every object in the system, regardless of which subsite they happen to live in. The object security_context_root has a slightly different role. If some object has no permissions attached to it, and its value for security_inherit_p is 'f', or context_id is null, this context is used by default. See the package developer tutorials for examples on how to use permissions code.
    Summary OpenACS &version; defines three separate mechanisms for specifying access control in applications. The Groups data model allows you to define hierarchical organizations of users and groups of users. The Permissions data model allows you to define a hierarchy of user rights. The Context hierarchy allows you to define organize default permissions in a hierarchical fashion. A PL/SQL or Tcl API is then used to check permissions in application pages. ($Id: permissions.xml,v 1.17 2010/12/11 23:36:32 ryang Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/db-api.xml0000644000175000017500000011520111226233616025742 0ustar frankiefrankie %myvars; ]> The OpenACS Database Access API By Pete Su and Jon Salz. Modified by Roberto Mello. Overview One of OpenACS's great strengths is that code written for it is very close to the database. It is very easy to interact with the database from anywhere within OpenACS, and we have a coherent API for database access which makes this even easier. More detailed information about the DB api is available at . DB API Examples The OpenACS database API is meant to save developers from making common mistakes and to provide a more structured syntax for specifying database operations, including transactions. Here's an example of the API. set count 0 set tcl_var "foo" set sql { SELECT foo, bar, baz FROM some_table, some_other_table WHERE some_table.id = some_other_table.id and some_table.condition_p = :tcl_var } db_transaction { db_foreach my_example_query_name $sql { lappend rows [list $foo $bar $baz] incr count } foreach row $rows { call_some_proc $foo $bar $baz } } There are several things to note here: No explicit code for grabbing and releasing handles. Usage of the Database API implicitly deals with all handle management issues. The db_transaction command makes the scope of a transaction clear; db_transaction takes the code block argument and automatically runs it in the context of a transaction. If you use something like db_foreach though, you need to make sure that there are no calls in the code block which would take a second db handle since the transaction is only valid for one handle (thats why we build up a list of returned values and call a second proc outside the db_foreach loop). The command db_foreach writes our old while loop for us. Every SQL query has a name, which is used in conjunction with .XQL files to support multiple databases. Finally and most importantly, there API implements bind variables, which we will cover next. Bind Variables Bind variables are placeholders for literal values in an SQL query being sent to the server. In the old way, data was generally passed to directly to the DB backend, via Tcl string interpolation. In the example above, the query would look like: select foo, bar, baz from some_table, some_other_table where some_table.id=some_other_table.id and some_table.condition_p = '$foo' There are a few problems with this: If the value of $foo is a huge string, then we waste a lot of time in the database server doing useless parsing. Second, if the literal value contains characters like single quotes, we have to be careful to properly escape them, because not quoting them will lead to surprising errors. Third, no type checking occurs on the literal value. Finally, if the Tcl variable is passed in or between web forms or otherwise subject to external modification, there is nothing keeping malicious users from setting the Tcl variable to some string that changes the query textually. This type of attack, called SQL smuggling, can be very damaging - entire tables can be exposed or have their contents deleted, for example. Another very important reason for using bind variables is performance. Oracle can cache previously parsed queries. If there are values in the where clause, that is how the query is cached. It also performs bind variable susbstitution after parsing the SQL statement. This means that SQL statements that use bind variables will always match (assuming all else is the same) while SQL statements that do not use bind variables will not match unless the values in the statement are exactly the same. This will improve the query cache considerably, which can make the server much more efficient. What the DB API (in conjuntion with the database drivers implemented for aolserver) do is send the SQL statement to the server for parsing, then bind values to the variables and sends those values along seperately as a second step. This seperate binding step is where the term bind variable comes from. This split has several advantages. First, type checking happens on the literal. If the column we are comparing against holds numbers, and we send a string, we get a nice error. Second, since string literals are no longer in the query, no extra quoting is required. Third, substitution of bind variables cannot change the actual text of the query, only the literal values in the placeholders. The database API makes bind variables easy to use by hooking them smoothly into the Tcl runtime so you simply provide :tclvar and the value of $tclvar is sent to the backend to actually execute the query. The database API parses the query and pulls out all the bind variable specifications and replaces them with generic placeholders. It then automatically pulls the values of the named Tcl vars out of the runtime environment of the script, and passes them to the database. Note that while this looks like a simple syntactic change, it really is very different from how interpolated text queries work. You use bind variables to replace what would otherwise be a literal value in a query, and Tcl style string interpolation does not happen. So you cannot do something like: set table "baz" set condition "where foo = bar" db_foreach my_query { select :table from some_table where :condition } SQL will not allow a literal to occur where we've put the bind variables, so the query is syntactically incorrect. You have to remember that while the bind variable syntax looks similar to variable interpolation in Tcl, It is not the same thing at all. Finally, the DB API has several different styles for passing bind variable values to queries. In general, use the style presented here because it is the most convenient. Usage Every db_* command accepting a SQL command as an argument supports bind variables. You can either Specify the -bind switch to provide a set with bind variable values, or Specify the -bind switch to explicitly provide a list of bind variable names and values, or Not specify a bind variable list at all, in which case Tcl variables are used as bind variables. The default behavior (i.e., if the -bind switch is omitted) is that these procedures expect to find local variables that correspond in name to the referenced bind variables, e.g.: set user_id 123456 set role "administrator" db_foreach user_group_memberships_by_role { select g.group_id, g.group_name from user_groups g, user_group_map map where g.group_id = map.user_id and map.user_id = :user_id and map.role = :role } { # do something for each group of which user 123456 is in the role # of "administrator" } The value of the local Tcl variable user_id (123456) is bound to the user_id bind variable. The -bind switch can takes the name of an ns_set containing keys for each bind variable named in the query, e.g.: set bind_vars [ns_set create] ns_set put $bind_vars user_id 123456 ns_set put $bind_vars role "administrator" db_foreach user_group_memberships_by_role { select g.group_id, g.group_name from user_groups g, user_group_map map where g.group_id = map.user_id and map.user_id = :user_id and map.role = :role } -bind $bind_vars { # do something for each group in which user 123456 has the role # of "administrator" } Alternatively, as an argument to -bind you can specify a list of alternating name/value pairs for bind variables: db_foreach user_group_memberships_by_role { select g.group_id, g.group_name from user_groups g, user_group_map map where g.group_id = map.user_id and map.user_id = :user_id and map.role = :role } -bind [list user_id 123456 role "administrator"] { # do something for each group in which user 123456 has the role # of "administrator" } Nulls and Bind Variables When processing a DML statement, Oracle coerces empty strings into null. (This coercion does not occur in the WHERE clause of a query, i.e. col = '' and col is null are not equivalent.) As a result, when using bind variables, the only way to make Oracle set a column value to null is to set the corresponding bind variable to the empty string, since a bind variable whose value is the string "null" will be interpreted as the literal string "null". These Oracle quirks complicate the process of writing clear and abstract DML difficult. Here is an example that illustrates why: # # Given the table: # # create table foo ( # bar integer, # baz varchar(10) # ); # set bar "" set baz "" db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)" # # the values of the "bar" and "baz" columns in the new row are both # null, because Oracle has coerced the empty string (even for the # numeric column "bar") into null in both cases Since databases other than Oracle do not coerce empty strings into null, this code has different semantics depending on the underlying database (i.e., the row that gets inserted may not have null as its column values), which defeats the purpose of SQL abstraction. Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the empty string): db_null. Use it instead of the empty string whenever you want to set a column value explicitly to null, e.g.: set bar [db_null] set baz [db_null] db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)" # # sets the values for both the "bar" and "baz" columns to null Sequence Pooling The database library can transparently maintain pools of sequence values, so that each request for a new sequence value (using db_nextval) does not incur a roundtrip to the server. For instance, this functionality is very useful in the security/sessions library, which very frequently allocates values from the sec_id_seq sequence. To utilize this functionality for a particular sequence, register the sequence to be pooled, either using the db_register_pooled_sequence procedure at server startup time, or by including a configuration parameter of the form PoolSequence.sequence_name_seq=count in any configuration section in the yourservername.ini file, e.g., [ns/server/yourservername/acs/security] PoolSequence.sec_id_seq=20 The database library will allocate this number of sequence values at server startup. It will periodically scan pools and allocate new values for sequences which are less than half-full. (This normally occurs every 60 seconds, and is configurable via the PooledSequenceUpdateInterval parameter in the [ns/server/ yourservername /acs/database] configuration section.) Basic API The Database API has several functions that wrap familiar parts of the AOLserver database API. Note that you never have to use ns_db anymore (including ns_db gethandle)! Just start doing stuff, and (if you want) call db_release_unused_handles when you're done as a hint to release the database handle. db_abort_transaction db_abort_transaction Aborts all levels of a transaction. That is if this is called within several nested transactions, all of them are terminated. Use this insetead of db_dml "abort" "abort transaction". db_multirow db_multirow [ -local ] [ -append ] [ -extend column_list ] \ var-name statement-name sql \ [ -bind bind_set_id | -bind bind_value_list ] \ code_block [ if_no_rows if_no_rows_block ] Performs the SQL query sql, saving results in variables of the form var_name:1, var_name:2, etc, setting var_name:rowcount to the total number of rows, and setting var_name:columns to a list of column names. Each row also has a column, rownum, automatically added and set to the row number, starting with 1. Note that this will override any column in the SQL statement named 'rownum', also if you're using the Oracle rownum pseudo-column. If the -local is passed, the variables defined by db_multirow will be set locally (useful if you're compiling dynamic templates in a function or similar situations). You may supply a code block, which will be executed for each row in the loop. This is very useful if you need to make computations that are better done in Tcl than in SQL, for example using ns_urlencode or ad_quotehtml, etc. When the Tcl code is executed, all the columns from the SQL query will be set as local variables in that code. Any changes made to these local variables will be copied back into the multirow. You may also add additional, computed columns to the multirow, using the -extend { col_1 col_2 ... } switch. This is useful for things like constructing a URL for the object retrieved by the query. If you're constructing your multirow through multiple queries with the same set of columns, but with different rows, you can use the -append switch. This causes the rows returned by this query to be appended to the rows already in the multirow, instead of starting a clean multirow, as is the normal behavior. The columns must match the columns in the original multirow, or an error will be thrown. Your code block may call continue in order to skip a row and not include it in the multirow. Or you can call break to skip this row and quit looping. Notice the nonstandard numbering (everything else in Tcl starts at 0); the reason is that the graphics designer, a non programmer, may wish to work with row numbers. Example: db_multirow -extend { user_url } users users_query { select user_id first_names, last_name, email from cc_users } { set user_url [acs_community_member_url -user_id $user_id] } You can also iterate over a multirow after it has been created - check the documentation for template::multirow For example, db_multirow assets assets { select asset_id, from ... } .. set asset_id_l [list] multirow foreach assets { lappend asset_id_l $asset_id } Technically it's equivalent to using a code block on the end of your db_multirow. db_null db_null Returns a value which can be used in a bind variable to represent the SQL value null. See Nulls and Bind Variables above. db_foreach db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] \ code_block [ if_no_rows if_no_rows_block ] Performs the SQL query sql , executing code_block once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes if_no_rows_block (if provided). Example: db_foreach select_foo "select foo, bar from greeble" { doc_body_append "<li>foo=$foo; bar=$bar\n" } if_no_rows { doc_body_append "<li>There are no greebles in the database.\n" } The code block may contain break statements (which terminate the loop and flush the database handle) and continue statements (which continue to the next row of the loop). db_1row db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] Performs the SQL query sql, setting variables to column values. Raises an error if the query does not return exactly 1 row. Example: db_1row select_foo "select foo, bar from greeble where greeble_id = $greeble_id" # Bombs if there's no such greeble! # Now $foo and $bar are set. db_0or1row db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] Performs the SQL query sql. If a row is returned, sets variables to column values and returns 1. If no rows are returned, returns 0. If more than one row is returned, throws an error. db_nextval db_nextval sequence-name Returns the next value for the sequence sequence-name (using a SQL statement like SELECT sequence-name.nextval FROM DUAL). If sequence pooling is enabled for the sequence, transparently uses a value from the pool if available to save a round-trip to the database (see ). db_register_pooled_sequence db_register_pooled_sequence sequence-name pool-size Registers the sequence sequence-name to be pooled, with a pool size of pool-size sequence values (see ). db_string db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] Returns the first column of the result of SQL query sql. If sql doesn't return a row, returns default (or throws an error if default is unspecified). Analogous to database_to_tcl_string and database_to_tcl_string_or_null. db_list db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a Tcl list of the values in the first column of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. Analogous to database_to_tcl_list. db_list_of_lists db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Returns a Tcl list, each element of which is a list of all column values in a row of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. (Analogous to database_to_tcl_list_list.) db_dml db_dml statement-name sql \ [ -bind bind_set_id | -bind bind_value_list ] \ [ -blobs blob_list | -clobs clob_list | -blob_files blob_file_list | -clob_files clob_file_list ] Performs the DML or DDL statement sql. If a length-n list of blobs or clobs is provided, then the SQL should return n blobs or clobs into the bind variables :1, :2, ... :n. blobs or clobs, if specified, should be a list of individual BLOBs or CLOBs to insert; blob_files or clob_files, if specified, should be a list of paths to files containing the data to insert. Only one of -blobs, -clobs, -blob_files, and -clob_files may be provided. Example: db_dml insert_photos " insert photos(photo_id, image, thumbnail_image) values(photo_id_seq.nextval, empty_blob(), empty_blob()) returning image, thumbnail_image into :1, :2 " -blob_files [list "/var/tmp/the_photo" "/var/tmp/the_thumbnail"] This inserts a new row into the photos table, with the contents of the files /var/tmp/the_photo and /var/tmp/the_thumbnail in the image and thumbnail columns, respectively. db_write_clob, db_write_blob, db_blob_get_file db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] Analagous to ns_ora write_clob/write_blob/blob_get_file. db_release_unused_handles db_release_unused_handles Releases any allocated, unused database handles. db_transaction db_transaction code_block [ on_error { code_block } ] Executes code_block transactionally. Nested transactions are supported (end transaction is transparently ns_db dml'ed when the outermost transaction completes). The db_abort_transaction command can be used to abort all levels of transactions. It is possible to specify an optional on_error code block that will be executed if some code in code_block throws an exception. The variable errmsg will be bound in that scope. If there is no on_error code, any errors will be propagated. Example: proc replace_the_foo { col } { db_transaction { db_dml "delete from foo" db_dml "insert into foo(col) values($col)" } } proc print_the_foo {} { doc_body_append "foo is [db_string "select col from foo"]<br>\n" } replace_the_foo 8 print_the_foo ; # Writes out "foo is 8" db_transaction { replace_the_foo 14 print_the_foo ; # Writes out "foo is 14" db_dml "insert into some_other_table(col) values(999)" ... db_abort_transaction } on_error { doc_body_append "Error in transaction: $errmsg" } print_the_foo ; # Writes out "foo is 8" db_resultrows db_resultrows Returns the number of rows affected or returned by the previous statement. db_with_handle db_with_handle var code_block Places a database handle into the variable var and executes code_block. This is useful when you don't want to have to use the new API (db_foreach, db_1row, etc.), but need to use database handles explicitly. Example: proc lookup_the_foo { foo } { db_with_handle db { return [db_string unused "select ..."] } } db_with_handle db { # Now there's a database handle in $db. set selection [ns_db select $db "select foo from bar"] while { [ns_db getrow $db $selection] } { set_variables_after_query lookup_the_foo $foo } } db_nullify_empty_string db_nullify_empty_string string For true SQL purists, we provide the convenience function db_nullify_empty_string, which returns [db_null] if its string argument is the empty string and can be used to encapsulate another Oracle quirk: set baz "" # Clean out the foo table # db_dml unused "delete from foo" db_dml unused "insert into foo(baz) values('$baz')" set n_rows [db_string unused "select count(*) from foo where baz is null"] # # $n_rows is 1; in effect, the "baz is null" criterion is matching # the empty string we just inserted (because of Oracle's coercion # quirk) To balance out this asymmetry, you can explicitly set baz to null by writing: db_dml foo_insert "insert into foo(baz) values(:1)" {[db_nullify_empty_string $baz]} ($Id: db-api.xml,v 1.13 2009/07/12 01:08:30 donb Exp $) Caching Database API Results The database API allows for direct caching of query results. Repeated calls will return the cached value until it is either explicitly flushed using db_flush_cache, times out (configured the ns_cache is called to create the cache), or another cached query fills the cache, causing older entries to be flushed. Values returned by a query are cached if you pass the "-cache_key" switch to the database procedure. The switch value will be used as the key in the ns_cache eval call used to execute the query and processing code. The db_flush proc should be called to flush the cache when appropriate. The "-cache_pool" parameter can be used to specify the cache pool to be used, and defaults to db_cache_pool. The size of the default cache is governed by the kernel parameter "DBCacheSize" in the "caching" section. Currently db_string, db_list, db_list_of_lists, db_1row, db_0or1row, and db_multirow support caching. For caching to be effective, one must carefully design a cache_pool and cache_key strategy that uniquely identifies a query within the system, including the relevant objects being referenced by the query. Typically a cache_key should include one or more object_ids and a name that identifies the operation being done. Here is an example from the layout-manager package: # Query to return the elements of a page as a list. The prefix "page_" is used to denote # that this is a page-related query, page_id is used to uniquely identify the query # by object, and the suffix uniquely defines the operation being performed on the # page object. db_list -cache_key page_${page_id}_get_elements get_elements {} # When the contents of a page are changed, we flush all page-related queries for the given # page object using db_flush_cache. db_flush_cache -cache_key_pattern page_${page_id}_* openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/object-identity.xml0000644000175000017500000000610410456621135027705 0ustar frankiefrankie %myvars; ]> Object Identity By Rafael H. Schloming One of the major design features of OpenACS &version; is the explicit representation of object identity. The reason I say "explicit representation" is because the concept of object identity has been around forever. It is inherent to our problem domain. Consider the example of 3.x style scoping. The 3.x data models use the triple (user_id, group_id, scope) to identify an object. In the &version; data model this object is explicitly represented by a single party_id. Another good example of this is can be found in the user groups data model. The 3.x user groups data model contains another example of an implied identity. Every mapping between a user and a group could have an arbitrary number of attached values (user_group_member_fields, etc.). In this case it is the pair (group_id, user_id) that implicitly refers to an object (the person's membership in a group). In the &version; data model this object identity is made explicit by adding an integer primary key to the table that maps users to groups. Coming from a purely relational world, this might seem slightly weird at first. The pair (group_id, user_id) is sufficient to uniquely identify the object in question, so why have the redundant integer primary key? If you take a closer look, it actually isn't quite so redundant. If you want to be able to use the object model's permissioning features, and generic attribute features on a table, you need an integer primary key for that table. This is because you can't really write a data model in oracle that uses more than one way to represent identity. So, this apparently redundant primary key has saved us the trouble of duplicating the entire generic storage system for the special case of the user_group_map, and has saved us from implementing ad-hoc security instead of just using acs-permissions. This design choice is further validated by the fact that services like journals that weren't previously thought to be generic can in fact be generically applied to membership objects, thereby allowing us to eliminated membership state auditing columns that weren't even capable of fully tracking the history of membership state. The design choice of explicitly representing object identity with an integer primary key that is derived from a globally unique sequence is the key to eliminating redundant code and replacing it with generic object level services. ($Id: object-identity.xml,v 1.7 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/form-builder.xml0000644000175000017500000001162510456621135027203 0ustar frankiefrankie %myvars; ]> Using Form Builder: building html forms dynamically Overview ($Id: form-builder.xml,v 1.8 2006/07/17 05:38:37 torbenb Exp $) OpenACS has a form manager called ad_form. Ad_form has an adaptable UI. Error handling includes inline error reporting, and is customizable. However, ad_form can be tricky to use. In addition to this document, the ad_form api documentation is helpful. Multi-part Elements Some elements have more than one choice, or can submit more than one value. SELECT elements Creating the form element Populate a list of lists with values for the option list. set foo_options [db_list_of_lists foo_option_list " select foo, foo_id from foos "] The variable foo_options should resemble {{first foo} 1234} {{second foo} 1235} Within ad_form, set up the element to use this list: {foo:text(select) {label "Which Foo"} {options $foo_options} } This will result in a single name/value pair coming back in the submitted form. Handle this within the same ad_form structure, in the -new_data and -edit_data. In the example, it is available as $foo See also the W3C spec for "The SELECT, OPTGROUP, and OPTION elements". Using refreshes to pull additional information from the database A situation you may run into often is where you want to pull in form items from a sub-category when the first category is selected. Ad_form makes this fairly easy to do. In the definition of your form element, include an html section {pm_task_id:integer(select),optional {label "Subject"} {options {$task_options}} {html {onChange "document.form_name.__refreshing_p.value='1';submit()"}} {value $pm_task_id} } What this will do is set the value for pm_task_id and all the other form elements, and resubmit the form. If you then include a block that extends the form, you'll have the opportunity to add in subcategories: if {[exists_and_not_null pm_task_id]} { db_1row get_task_values { } ad_form -extend -name form_name -form { ... } Note that you will get strange results when you try to set the values for the form. You'll need to set them explicitly in an -on_refresh section of your ad_form. In that section, you'll get the values from the database, and set the values as so: db_1row get_task_values { } template::element set_value form_name estimated_hours_work $estimated_hours_work Troubleshooting A good way to troubleshoot when you're using ad_form is to add the following code at the top of the .tcl page (thanks Jerry Asher): ns_log notice it's my page! set mypage [ns_getform] if {[string equal "" $mypage]} { ns_log notice no form was submitted on my page } else { ns_log notice the following form was submitted on my page ns_set print $mypage } Tips for form widgets Here are some tips for dealing with some of the form widgets: Current widget Common Errors Here are some common errors and what to do when you encounter them: Error when selecting values This generally happens when there is an error in your query. openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/permissions-tediously-explained.xml0000644000175000017500000013017010506036345033151 0ustar frankiefrankie %myvars; ]> OpenACS Permissions Tediously Explained by Vadim Nasardinov. Modified and converted to Docbook XML by Roberto Mello The code has been modified since this document was written so it is now out of date. See this forum thread. Permissions Overview Who (grantee_id) can do what (privilege) on which object (object_id). The general permissions system has a flexible (and relatively complex) data model in OpenACS. Developers who have not had the time to learn the internals of the data model may end up writing seemingly correct code that crashes their system in weird ways. This writeup is the result of my running into such a piece of code and trying to understand exactly what went wrong. It is geared towards developers who understand the general permissions system to the extent that is described in the Groups, Context, Permissions documentation, but who have not had the opportunity to take a long, careful look at the system internals. In OpenACS, most of the interesting tables are expected to extend (subtype) the acs_objects table, i.e. they are expected to have an integer primary key column that references the object_id column of acs_objects. create table acs_objects ( object_id integer not null constraint acs_objects_pk primary key, object_type not null constraint acs_objects_object_type_fk references acs_object_types (object_type), context_id constraint acs_objects_context_id_fk references acs_objects(object_id), security_inherit_p char(1) default 't' not null, constraint acs_objects_sec_inherit_p_ck check (security_inherit_p in ('t', 'f')), creation_user integer, creation_date date default sysdate not null, creation_ip varchar2(50), last_modified date default sysdate not null, modifying_user integer, modifying_ip varchar2(50), constraint acs_objects_context_object_un unique (context_id, object_id) disable ); This means that items that want to use the features of the OpenACS object system needs to have an entry in the acs_objects. This allows developers to define relationships between any two entities A and B by defining a relationship between their corresponding entries in the acs_objects table. One of the applications of this powerful capability is the general permissions system. At the heart of the permission system are two tables: acs_privileges and acs_permissions. create table acs_privileges ( privilege varchar2(100) not null constraint acs_privileges_pk primary key, pretty_name varchar2(100), pretty_plural varchar2(100) ); create table acs_permissions ( object_id not null constraint acs_permissions_on_what_id_fk references (object_id), grantee_id not null constraint acs_permissions_grantee_id_fk references (party_id), privilege not null constraint acs_permissions_priv_fk references (privilege), constraint acs_permissions_pk primary key (object_id, grantee_id, privilege) ); The acs_privileges table stores named privileges like read, write, delete, create, and admin. The acs_permissions table stores assertions of the form: Who (grantee_id) can do what (privilege) on which object (object_id). The micromanaging approach to system security would be to require application developers to store permission information explicitly about every object, i.e. if the system has 100,000 and 1,000 users who have the read privilege on all objects, then we would need to store 100,000,000 entries of the form: object_id grantee_id privilege object_id_1 user_id_1 'read' object_id_1 user_id_2 'read' ... object_id_1 user_id_n 'read' object_id_2 user_id_1 'read' object_id_2 user_id_2 'read' ... object_id_2 user_id_n 'read' ... ... object_id_m user_id_1 'read' object_id_m user_id_2 'read' ... object_id_m user_id_n 'read' Although quite feasible, this approach fails to take advantage of the fact that objects in the system are commonly organized hierarchally, and permissions usually follow the hierarchical structure, so that if user X has the read privilege on object A, she typically also has the read privilege on all objects attached under A. The general permission system takes advantage of the hierarchical organization of objects to unburden developers of the necessity to explicitly maintain security information for every single object. There are three kinds of hierarchies involved. These are discussed in the following sections. Context Hierarchy Suppose objects A, B, ..., and F form the following hierarchy. Context Hierarchy Example A object_id=10 B object_id=20 C object_id=30 D object_id=40 E object_id=50 F object_id=60
    This can be represented in the table by the following entries: acs_objects example data object_id context_id 20 10 30 10 40 20 50 20 60 30
    The first entry tells us that object 20 is the descendant of object 10, and the third entry shows that object 40 is the descendant of object 20. By running a CONNECT BY query, we can compute that object 40 is the second-generation descendant of object 10. With this in mind, if we want to record the fact that user Joe has the read privilege on objects A, ..., F, we only need to record one entry in the table. object grantee privilege A Joe read The fact that Joe can also read B, C, ..., and F can be derived by ascertaining that these objects are children of A by traversing the context hierarchy. As it turns out, hierarchical queries are expensive. As Rafael Schloming put it so aptly, Oracle can't deal with hierarchies for shit. One way to solve this problem is to cache a flattened view of the context tree like so: object ancestor n_generations A A 0 B B 0 B A 1 C C 0 C A 1 D D 0 D B 1 D A 2 E E 0 E B 1 E A 2 F F 0 F C 1 F A 2 Note that the number of entries in the flattened view grows exponentially with respect to the depth of the context tree. For instance, if you have a fully populated binary tree with a depth of n, then the number of entries in its flattened view is 1 + 2*2 + 3*4 + 4*8 + 5*16 + ... + (n+1)*2n = n*2n+1 + 1 Despite its potentially great storage costs, maintaining a flattened representation of the context tree is exactly what OpenACS does. The flattened context tree is stored in the acs_object_context_index table. create table acs_object_context_index ( object_id not null constraint acs_obj_context_idx_obj_id_fk references (object_id), ancestor_id not null constraint acs_obj_context_idx_anc_id_fk references (object_id), n_generations integer not null constraint acs_obj_context_idx_n_gen_ck check (n_generations >= 0), constraint acs_object_context_index_pk primary key (object_id, ancestor_id) ) organization index; A few things to note about this table are these. Number one, it is an index-organized table, which means it is substantially optimized for access by primary key. Number two, as the above computations suggest, the size of the table grows polynomially with respect to the average number of descendants that an object has, and exponentially with respect to the depth of the context tree. The acs_object_context_index is kept in sync with the table by triggers like this: create or replace trigger acs_objects_context_id_in_tr after insert on for each row begin insert into (object_id, ancestor_id, n_generations) values (:new.object_id, :new.object_id, 0); if :new.context_id is not null and :new.security_inherit_p = 't' then insert into (object_id, ancestor_id, n_generations) select :new.object_id as object_id, ancestor_id, n_generations + 1 as n_generations from where object_id = :new.context_id; elsif :new.object_id != 0 then -- 0 is the id of the security context root object insert into (object_id, ancestor_id, n_generations) values (:new.object_id, 0, 1); end if; end; One final note about . By setting an object's security_inherit_p column to 'f', you can stop permissions from cascading down the context tree. In the following example, Joe does not have the read permissions on C and F. A object_id=10 readable by Joe B object_id=20 readable by Joe C object_id=30 security_inherit_p = 'f' not readable by Joe D object_id=40 E object_id=50 F object_id=60 security_inherit_p = 'f' not readable by Joe
    Privilege Hierarchy Privileges are also organized hierarchically. In addition to the five main system privileges defined in the ACS Kernel data model, application developers may define their own. Note, however, that this is no longer recommended practice. By defining parent-child relationship between privileges, the OpenACS data model makes it easier for developers to manage permissions. Instead of granting a user explicit read, write, delete, and create privileges on an object, it is sufficient to grant the user the admin privilege to which the first four privileges are tied. Privileges are structured as follows. admin create delete read write Note that admin privileges are greater than read, write, create and delete privileges combined. Issuing someone read, write, create and delete privileges will not result in the person getting admin privileges. The parent-child relationship between privileges is represented in the acs_privilege_hierarchy table: create table acs_privilege_hierarchy ( privilege not null constraint acs_priv_hier_priv_fk references (privilege), child_privilege not null constraint acs_priv_hier_child_priv_fk references (privilege), constraint acs_privilege_hierarchy_pk primary key (privilege, child_privilege) ); As in the case of the context hierarchy, it is convenient to have a flattened representation of this hierarchal structure. This is accomplished by defining the following view. create or replace view acs_privilege_descendant_map as select p1.privilege, p2.privilege as descendant from p1, p2 where p2.privilege in (select child_privilege from start with privilege = p1.privilege connect by prior child_privilege = privilege ) or p2.privilege = p1.privilege; As the number of different privileges in the system is expected to be reasonably small, there is no pressing need to cache the flattened ansector-descendant view of the privilege hierarchy in a specially maintained table like it is done in the case of the context hierarchy. Party Hierarchy Now for the third hierarchy playing a promiment role in the permission system. The party data model is set up as follows. create table parties ( party_id not null constraint parties_party_id_fk references (object_id) constraint parties_pk primary key, email varchar2(100) constraint parties_email_un unique, url varchar2(200) ); create table persons ( person_id not null constraint persons_person_id_fk references (party_id) constraint persons_pk primary key, first_names varchar2(100) not null, last_name varchar2(100) not null ); create table users ( user_id not null constraint users_user_id_fk references (person_id) constraint users_pk primary key, password char(40), -- other attributes ); create table groups ( group_id not null constraint groups_group_id_fk references (party_id) constraint groups_pk primary key, group_name varchar2(100) not null ); Recall that the grantee_id column of the table references parties.party_id. This means that you can grant a privilege on an object to a party, person, user, or group. Groups represent aggregations of parties. The most common scenario that you are likely to encounter is a group that is a collection of users, although you could also have collections of persons, groups, parties, or any mix thereof. Given that the most common use of groups is to partition users, how do you build groups? One way is to grant membership explicitly. If you have a group named Pranksters, you can assign membership to Pete, Poly, and Penelope. The fact that these users are members of the Pranksters group will be recorded in the membership_rels and acs_rels tables: create table acs_rels ( rel_id not null constraint acs_rels_rel_id_fk references (object_id) constraint acs_rels_pk primary key, rel_type not null constraint acs_rels_rel_type_fk references acs_rel_types (rel_type), object_id_one not null constraint acs_object_rels_one_fk references (object_id), object_id_two not null constraint acs_object_rels_two_fk references (object_id), constraint acs_object_rels_un unique (rel_type, object_id_one, object_id_two) ); create table membership_rels ( rel_id constraint membership_rel_rel_id_fk references (rel_id) constraint membership_rel_rel_id_pk primary key, -- null means waiting for admin approval member_state varchar2(20) constraint membership_rel_mem_ck check (member_state in ('approved', 'banned', 'rejected', 'deleted')) ); The table entries would look like so: rel_type object_one object_two membership_rel Pranksters Pete membership_rel Pranksters Poly membership_rel Pranksters Penelope Read acs_rels: right-side is a subset of left-side, ie object2 is a part of object1. Another way of building up groups is by adding subgroups. Suppose we define Merry Pranksters and Sad Pranksters as subgroups of Pranksters. We say that the Pranksters group is composed of groups Merry Pranksters and Sad Pranksters. This information is stored in the and composition_rels tables. create table composition_rels ( rel_id constraint composition_rels_rel_id_fk references (rel_id) constraint composition_rels_rel_id_pk primary key ); The relevant entries in the look like so. rel_type object_one object_two composition_rel Pranksters Merry Pranksters composition_rel Pranksters Sad Pranksters The composition relationship means that if I add Matt, Mel, and Mary to the Merry Pranksters, they should also automatically become members of the Pranksters group. The situation we are facing in trying to determine whether or not a user is member of a group is similar to the one discussed above in the case of the context hierarchy. Groups can form hierarchies with respect to the composition relationship. The compositon relationship is transitive. If G1 is a subgroup of G2, and G2 is a subgroup of G3, then G1 is a subgroup of G3; that is, any member of G1 is also a member of G3. Traversing the group composition hierarchy requires running hierarchical queries, which are expensive in Oracle. As we saw in the Context Hierarchy section, one way of reducing the performance hit incurred by hierarchical queries is to cache query results in a table maintained by triggers. The OpenACS data model defines two such tables: create table group_component_index ( group_id not null constraint group_comp_index_group_id_fk references (group_id), component_id not null constraint group_comp_index_comp_id_fk references (group_id), rel_id not null constraint group_comp_index_rel_id_fk references composition_rels (rel_id), container_id not null constraint group_comp_index_cont_id_ck references (group_id), constraint group_component_index_ck check (group_id != component_id), constraint group_component_index_pk primary key (group_id, component_id, rel_id) ) organization index; create table group_member_index ( group_id not null constraint group_member_index_grp_id_fk references (group_id), member_id not null constraint group_member_index_mem_id_fk references (party_id), rel_id not null constraint group_member_index_rel_id_fk references (rel_id), container_id not null constraint group_member_index_cont_id_fk references (group_id), constraint group_member_index_pk primary key (member_id, group_id, rel_id) ) organization index; The group_component_index table stores a flattened representation of the group composition hierarchy that is maintained in sync with the and composition_rels tables through triggers. additional comments As far as the group_member_index table goes, I am not sure I understand its purpose. It maintains group-member relationships that are resolved with respect to group composition. Note that information stored in can be trivially derived by joining , , and . Here is a view that does it. (This view is not part of the OpenACS Kernel data model.) create or replace view group_member_view as select gci.group_id, r.object_id_two as member_id from ( select group_id, group_id as component_id from union select group_id, component_id from group_component_index ) gci, mr, r where mr.rel_id = r.rel_id and r.object_id_one = gci.component_id; A heuristic way to verify that group_member_view is essentially identical to is to compute the symmetric difference between the two: select group_id, member_id from ( select group_id, member_id from group_member_view minus select group_id, member_id from ) union select group_id, member_id from ( select group_id, member_id from minus select group_id, member_id from group_member_view ) The query returns no rows. The important point is, if we have a flattened view of the composition hierarchy -- like one provided by the table -- membership relationship resolution can be computed trivially with no hierarchical queries involved. There is no need to keep the view in a denormalized table, unless doing so results in substantial performance gains. Putting It All Together Security information is queried by calling the acs_permission.permission_p function in OpenACS. This is accessible from Tcl via the permission::permission_p procedure. create or replace package body acs_permission as -- some stuff removed for the sake of brevity function permission_p ( object_id acs_objects.object_id%TYPE, party_id parties.party_id%TYPE, privilege acs_privileges.privilege%TYPE ) return char as exists_p char(1); begin -- XXX This must be fixed: -1 shouldn't be hardcoded (it is the public) select decode(count(*),0,'f','t') into exists_p from where object_id = permission_p.object_id and party_id in (permission_p.party_id, -1) and privilege = permission_p.privilege; return exists_p; end; end acs_permission; problem avoidance The function queries , which is a humongous view that joins three flattened hierarchies: the context tree, the privilege hierarchy, the party composition (and membership) hierarchy. It contains an extremely large number of rows. About the only kind of query you can run against it is the one performed by the acs_permission.permission_p function. Anything other than that would take forever to finish or would ultimately result in a query error. For example, do not try to do things like select count(*) from ; To give another example of things to avoid, I have seen code like this: declare cursor cur is select object_id, party_id from where privilege = 'foo_create'; begin -- revoke all 'foo_create' permissions for rec in cur loop acs_permission.revoke_permission ( object_id => rec.object_id, grantee_id => rec.party_id, privilege => 'foo_create' ); end loop; acs_privilege.remove_child('admin','foo_create'); acs_privilege.drop_privilege('foo'); end; / The acs_permission.revoke_permission function merely runs a delete statement like so: delete from acs_permissions where object_id = revoke_permission.object_id and grantee_id = revoke_permission.grantee_id and privilege = revoke_permission.privilege; Note that in the above example, acs_permissions had only one entry that needed to be deleted: object_id grantee_id privilege default_context registered_users foo_create The above script would never get around to deleting this entry because it had to loop through a gazillion rows in the humongous acs_object_party_privilege_map view. Appendix: Various View Definitions create or replace view acs_object_party_privilege_map as select ogpm.object_id, gmm.member_id as party_id, ogpm.privilege from ogpm, gmm where ogpm.grantee_id = gmm.group_id union select object_id, grantee_id as party_id, privilege from ; create or replace view acs_object_grantee_priv_map as select a.object_id, a.grantee_id, m.descendant as privilege from a, m where a.privilege = m.privilege; create or replace view acs_permissions_all as select op.object_id, p.grantee_id, p.privilege from op, p where op.ancestor_id = p.object_id; create or replace view acs_object_paths as select object_id, ancestor_id, n_generations from ; create or replace view group_member_map as select group_id, member_id, rel_id, container_id from ;
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/rp.xml0000644000175000017500000001764411501005400025223 0ustar frankiefrankie %myvars; ]> The Request Processor By Pete Su Overview This document is a brief introduction to the OpenACS &version; Request Processor; more details can be found in the . Here we cover the high level concepts behind the system, and implications and usage for the application developer. Request Processor The &version; Request Processor is a global filter and set of Tcl procs that respond to every incoming URL reaching the server. The following diagram summarizes the stages of the request processor assuming a URL request like http://someserver.com/notes/somepage.adp. Stage 1: Search Site Map The first thing the RP does is to map the given URL to the appropriate physical directory in the filesystem, from which to serve content. We do this by searching the site map data model (touched on in the , and further discussed in ). This data model maps URLs to objects representing content, and these objects are typically package instances. After looking up the appropriate object, the RP stores the URL, the ID of the object it found, and the package and package instance the object belongs to into the environment of the connection. This environment can be queried using the ad_conn procedure, which is described in detail in . The page development tutorial shows you how to use this interface to make your pages aware of which instance was requested. Stage 2: Authentication Next, the Request Processor examines the request for session information. Session information is generally sent from the client (the user's browser) to the server via cookies. The security/session handler is described in detail in its own document. It examines the client request and either extracts or sets up new session tokens for the user. Stage 3: Authorization Next, the Request Processor checks if the user has appropriate access privileges to the requested part of the site. In OpenACS &version;, access control is dictated by the permissions system. In this case, the RP checks if the user has "read" priviledges on the object in the site map specified by the URL. This object is typically a package instance, but it could easily be something more granular, such as whehter the user can view a particular piece of content within a package instance. This automatic check makes it easy to set up sites with areas that are only accessible to specific groups of users. Stage 4: URL Processing, File Search Finally, the Request Processor finds the file we intend to serve, searching the filesystem to locate the actual file that corresponds to an abstract URL. It searches for files with predefined "magic" extensions, i.e. files that end with: .html, .tcl and .adp. If the RP can't find any matching files with the expected extensions, it will look for virtual-url-handler files, or .vuh files. A .vuh file will be executed as if it were a Tcl file, but with the tail end of the URL removed. This allows the code in the .vuh file to act like a registered procedure for an entire subtree of the URL namespace. Thus a .vuh file can be thought of as a replacement for filters and registered procs, except that they integrate cleanly and correctly with the RP's URL mapping mechanisms. The details of how to use these files are described in . Once the appropriate file is found, it is either served directly if it's static content, or sent to the template system or the standard Tcl interpreter if it's a dynamic page. Basic API Once the flow of control reaches a dynamic page, the Request Processor has populated the environment of the request with several pieces of useful information. The RP's environment is accessible through the ad_conn interface, and the following calls should be useful to you when developing dynamic pages: [ad_conn user_id] The ID of the user associated with this request. By convention this is zero if there is no user. [ad_conn session_id] The ID of the session associated with this request. [ad_conn url] The URL associated with the request. [ad_conn urlv] The URL associated with the request, represented as a list instead of a single string. [ad_conn file] The actual local filesystem path of the file that is being served. [ad_conn object_url] If the URL refers to a site map object, this is the URL to the root of the tree where the object is mounted. [ad_conn package_url] If the URL refers to a package instance, this is the URL to the root of the tree where the package is mounted. [ad_conn extra_url] If we found the URL in the site map, this is the tail of the URL following the part that matched a site map entry. [ad_conn object_id] If the URL refers to a site map object, this is the ID of that object. [ad_conn package_id] If the URL refers to a package instance, this is the ID of that package instance. [ad_conn package_key] If the URL refers to a package instance, this is the unique key name of the package. [ad_conn path_info] In a .vuh file, path_info is the trailing part of the URL not matched by the .vuh file. ($Id: rp.xml,v 1.12 2010/12/11 23:36:32 ryang Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/submissions.xml0000644000175000017500000000561210456621135027171 0ustar frankiefrankie %myvars; ]> Contributions by Joel Aufrecht Contributing a Package Get commit access to the repository. Core developers already have this. We should have a process where anybody can register a package name and (possibly after a delay or security audit) get commit rights to a subdir of the same name. Make sure your package is ready to contribute. myfirstpackage.info should have all the basic tags auto-generated by the APM, plus vendor and maturity. Maturity should be: <maturity> <platform id="openacs-core" version="5.0"> <level descr="New Submission">0</level> </platform> </maturity> with the appropriate core version number. has automated tests - at a minimum, every API function should be covered by a smoke test. Has documentation. An install guide, if there are any special installation requirements (such as additional software); a user guide; an administrator guide. Get a clean copy of your package - no ~ files or .# files or CVS files. Assuming you have been developing in a local cvs repository and your local version 1.0.0 is the one you want to contribute, the easy way to do this is: cd /var/tmp cvs -d /cvsroot openacs-4/packages/myfirstpackage export -r 1-0-0 Import it to the openacs.org cvs tree cd openacs-4/packages/myfirstpackage cvs -d :ext:you@cvs.openacs.org:/cvsroot import -m "initial upload" openacs-4/contrib/packages/myfirstpackage your_vendor_tag myfirstpackage-1-0-0 Tag the imported package for compatibility with core: cvs tag openacs-5-0-compat Wait for someone to set up nightly rebuild of the Automatic Repository Generator, less than 24 hours after which point your package will be put in the OpenACS.org repository and become available to everybody via "Install from Repository" openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/objects.xml0000644000175000017500000005065710456621135026255 0ustar frankiefrankie %myvars; ]> OpenACS Data Models and the Object System By Pete Su Overview Developing data models in OpenACS &version; is much like developing data models for OpenACS 3, save for the implementation. As usual, you need to examine how to model the information that the application must store and manipulate, and define a suitable set of SQL tables. In our Notes application, we have to be able to keep track of who entered a particular note, when they did it, and the actual text of the notes that users have entered. A simple data model might look like this: create table notes ( note_id integer primary key, owner_id integer references users(user_id), creation_user references(user_id) not null, creation_date date not null, last_modified date not null, title varchar(255) not null, body varchar(1024) ) We've omitted constraint names for the purpose of clarity. Thinking further ahead, we can imagine doing any of the following things with Notes as well: Define access control policies on notes. Attach user comments on notes. Allow users to define custom fields to store on their notes. Automatically generate input forms or output displays for notes. Allow other applications to use notes in ways we don't know of yet. In OpenACS, the key to enabling these types of services on your application data is to take advantage of the Object System. The first question, then, is "Just what are objects, and what do you use them for anyway?". The short answer: objects are anything represented in the application's data model that will need to be managed by any central service in OpenACS, or that may be reusable in the context of future applications. Every object in the system is represented using a row in the acs_objects table. This table defines all the standard attributes that are stored on every object, including its system-wide unique ID, object type, and some generic auditing columns. To make use of the object system, you as the application developer have to write your data model in a way that is slightly more complex than in the ACS 3.x days. What you get for this extra work includes: The lets you track who is allowed to do what to the rows in an application table, and gives you an easy way to enforce this from Tcl. Every object has an attribute called context_id that provides a way to trivially specify both the default permissions for an object, and the intended "scope" of an object. Just set the context_id to the controlling object and forget about it. And most importantly, any future object-level service - from a general-comments replacement to personalized ranking - will become available to your application "for free." How to Use Objects Using ACS objects is straightforward: all that's required are a few extra steps in the design of your application data model. In order to hook our Notes application into the object system, we make some calls to use our notes table as the basis for a new object type. Object types are analogous to classes in programming languages such as C++ and Java. In Java, a class defines a set of attributes that store data and a set of methods that run code. In OpenACS, we use one or more database tables to store the data attributes, and we define a stored procedure package to hold procedures to define the programming interface to the data model. The object type itself is described using data in the acs_object_types and acs_attributes tables, which play a role similar to the data dictionary in Oracle. As in Java, object types can inherit attributes from a parent type, so the type system forms a hierarchy. Unlike Java, Oracle does not support this inheritance transparently, so we have to make sure we add our own bookkeeping code to keep everything consistent. Below you'll find the code needed to describe a new object type called notes in your system. Fire up your text editor and open the ROOT/packages/notes/sql/oracle/notes-create.sql (ROOT/packages/notes/sql/postgresql/notes-create.sql for the PG version) file created when we created the package. Then, do the following: Describe the new type to the type system First, add an entry to the acs_object_types table with the following PL/SQL call: begin acs_object_type.create_type ( supertype => 'acs_object', object_type => 'note', pretty_name => 'Note', pretty_plural => 'Notes', table_name => 'NOTES', id_column => 'NOTE_ID' ); end; / show errors; This PL/SQL call tells the system that we would like to use the table NOTES as the basis for a new object type called note. This type is a subtype of the acs_object type, which means that we want to inherit all of the basic attributes of all ACS objects. As mentioned, it will take some work on our part to make this happen, since Oracle can't do it automatically. In general, most basic applications will define types that are simple subtypes of acs_object. Add entries to the acs_attributes table to describe the data attributes of the new type. This data can eventually be used to do things like automatically generate user interfaces to manipulate the notes table, though that functionality isn't yet available. declare attr_id acs_attributes.attribute_id%TYPE; begin attr_id := acs_attribute.create_attribute ( object_type => 'note', attribute_name => 'TITLE', pretty_name => 'Title', pretty_plural => 'Titles', datatype => 'string' ); attr_id := acs_attribute.create_attribute ( object_type => 'note', attribute_name => 'BODY', pretty_name => 'Body', pretty_plural => 'Bodies', datatype => 'string' ); end; / show errors; We can stop here and not bother to register the usual OpenACS 3.x attributes of creation_user, creation_date and last_modified, since the object type acs_object already defines these attributes. Again, because the new type note is a subtype of acs_object, it will inherit these attributes, so there is no need for us to define them. Define a table in which to store your objects The next thing we do is make a small modification to the data model to reflect the fact that each row in the notes table represents something that is not only an object of type note, but also an acs_object. The new table definition looks like this: create table notes ( note_id integer references acs_objects(object_id) primary key, owner_id integer references users(user_id), title varchar(255) not null, body varchar(1024) ) The usual creation_date and modified_date columns are absent since they already exist in acs_objects. Also, note the constraint we have added to reference the acs_objects table, which makes clear that since note is a subtype of acs_object, every row in the notes table must have a corresponding row in the acs_objects table. This is the fundamental means by which we model inheritance; it guarantees that any services that use the acs_objects table to find objects will transparently find any objects that are instances of any subtype of acs_objects. Define a package for type specific procedures The next step is to define a PL/SQL package for your new type, and write some basic procedures to create and delete objects. Here is a package definition for our new type: create or replace package note as function new ( note_id in notes.note_id%TYPE default null, owner_id in notes.owner_id%TYPE default null, title in notes.title%TYPE, body in notes.body%TYPE, object_type in acs_object_types.object_type%TYPE default 'note', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return notes.note_id%TYPE; procedure delete ( note_id in notes.note_id%TYPE ); end note; / show errors You might be wondering what all the extra parameters are to these calls, since we haven't mentioned them before. These parameters are needed to fill out information that will be stored about the object that's not stored directly in the table you defined. The OpenACS Object System defines these attributes on the type acs_object since all objects should have these attributes. Internally, there are tables that store this information for you. Most of the data is pretty self-explanatory and reflects attributes that existed in the earlier OpenACS 3.x data models, with the exception of the context_id attribute. The context_id attribute stores the ID of an object that represents the default security domain to which the object belongs. It is used by the permissions system in this way: if no permissions are explicitly attached to the object, then the object inherits its permissions from the context. For example, if I had told you how to use the permissions system to specify that an object OBJ was "read only", then any other object that used OBJ as its context would also be "read only" by default. We'll talk about this more later. Define a package body for type specific procedures The PL/SQL package body contains the implementations of the procedures defined above. The only subtle thing going on here is that we must use acs_object.new to insert a row into acs_objects, before inserting a row into the notes. Similarly, when we delete a row from note, we have to be sure to delete the corresponding acs_object row. create or replace package body note as function new ( note_id in notes.note_id%TYPE default null, owner_id in notes.owner_id%TYPE default null, title in notes.title%TYPE, body in notes.body%TYPE, object_type in acs_object_types.object_type%TYPE default 'note', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return notes.note_id%TYPE is v_note_id integer; begin v_note_id := acs_object.new ( object_id => note_id, object_type => object_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, context_id => context_id ); insert into notes (note_id, owner_id, title, body) values (v_note_id, owner_id, title, body); return v_note_id; end new; procedure delete ( note_id in notes.note_id%TYPE ) is begin delete from notes where note_id = note.delete.note_id; acs_object.del(note_id); end delete; end note; / show errors; That's pretty much it! As long as you use the note.new function to create notes, and the note.delete function to delete them, you'll be assured that the relationship each note has with its corresponding acs_object is preserved. The last thing to do is to make a file ROOT/packages/notes/sql/notes-drop.sql so it's easy to drop the data model when, say, you're testing: begin acs_object_type.drop_type ('note'); end; / show errors drop package note; drop table notes; When to Use Objects While it is hard to give general design advice without knowing anything about a particular application, you should follow the following rule of thumb when deciding when to hook part of your data model to the object system: Anything in your data model that needs to be available to general OpenACS services such as user comments, permissions, and so on should be a subtype of acs_object. In addition, if you want your data model to take advantage of attributes that exist in some object type that is a subtype of acs_object, then you should use the object system. For example, for most applications, you will want to use objects to represent the data in your application that is user visible and thus requires access control. But other internal tables, views, mapping tables and so on probably don't need to be objects. As before, this kind of design decision is mostly made on an application-by-application basis, but this is a good baseline from which to start. Design Guidance In this section we cover some overall guidelines for designing data models that are meant to be integrated with the OpenACS object system. There are two basic rules you should follow when designing OpenACS &version; data models: Never utilize fields in the acs_objects table in application specific ways. That is, never assign any application-specific semantics to this data. In the notes application, we use the creation_date and last_modified fields, but this is OK since we do not assign any application-specific meaning to these fields. In particular, never assign any application specific semantics to the context_id attribute of an object. This field is used for a very specific purpose by the permissions system, and using this field in any other way whatsoever is guaranteed to make your application act strangely. As we'll see later, the Notes example will point each note object's context_id to the package instance in which the note was created. The idea will be that in a real site, the administrator would create one package instance for every separate set of Notes (say, one per user). The instance would "own" all of the notes that it created, and the administrator would be able to use the package instance as the basis for access control, which is convenient. The reason behind these two rules is pretty straightforward: First, the OpenACS Object system itself is meant to be a generic and reusable tool for any application to use for basic services. Second, in order for this to work, the various parts of the OpenACS Objects data model must be interpreted in the same way by all applications that use the data model. Therefore, assigning any application-specific semantics to any part of the core data model is a bad thing to do, because then the semantics of the data model are no longer independent of the application. This would make it impossible to build the generic tools that the data model is trying to support. Another less important reason for these two rules is to not introduce any joins against the acs_objects table in SQL queries in your application that you do not absolutely need. In the Notes example, the result of applying these rules is that we are careful to define our own attribute for owner_id rather than overloading creation_user from the objects table. But, since we will probably use creation_date and so on for their intended purposes, we don't bother to define our own attributes to store that data again. This will entail joins with acs_objects but that's OK because it makes the overall data model cleaner. The real lesson is that deciding exactly how and when to use inherited attributes is fairly straightforward, but requires a good amount of thought at design time even for simple applications. Summary Hooking into the OpenACS &version; object system brings the application developer numerous benefits, and doing it involves only four easy steps: Describe the a new object type to the system. Most new application types will be subtypes of the built-in type acs_object. Define a table to store application object data. Define a PL/SQL package to store procedures related to the new type. You have to define at least a function called new to create new application objects and a procedure called delete to delete them. Define a package body that contains the implementations of the PL/SQL procedures defined above. Try not to write queries in your application that join against acs_objects. This means you should never use the fields in acs_objects for application-specific purposes. This is especially true for the context_id field. ($Id: objects.xml,v 1.9 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/permissions-tediously-explained-es.xml0000644000175000017500000005551110506036345033563 0ustar frankiefrankie %myvars; ]> Sistema de Permisos de OpenACS Tediosamente Explicado por Vadim Nasardinov. Modificado y convertido a Docbook XML por Roberto Mello. Traducido por David Arroyo. Introducción En OpenACS 3.x se consiguió tener un sistema reutilizable de control de permisos y poder contestar a la pregunta clave quié puede hacer qué en tal objeto. Sin embargo, no se consiguió que este control de permisos estuviera realmente unificado. En ocasiones, el control de permisos se construía en base a cada módulo/paquete, ó incluso en base a cada p´gina. De este modo, algunos módulos usaban "roles" y otros no. Otros módulos hacían todo el control de acceso basándose en simples reglas de código. Los problemas resultantes de esto fueron sobre todo inconsistencias y código redundante. De este modo, en OpenACS 4 se busca proporcionar un unificado y consistente sistema de permisos para que tanto programadores y administradores puedan usarlo de manera amigable. En OpenACS 4 la pregunta quién puede hacer qué en tal objeto, el "quién" se responde a través de la jerarquía de party (la generalización de personas, usuarios, miembros de un grupo, etc.), el "tal objeto" también se establece a través de la jerarquía de objetos y por último el "qué" se establece a travé de una jerarquía de posibles acciones. Ahora iremos aclarando todos estos conceptos. En el corazón del sistema de permisos tenemos dos tablas: acs_privileges y acs_permissions: create table acs_privileges ( privilege varchar2(100) not null constraint acs_privileges_pk primary key, pretty_name varchar2(100), pretty_plural varchar2(100) ); create table acs_permissions ( object_id not null constraint acs_permissions_on_what_id_fk references acs_objects (object_id), grantee_id not null constraint acs_permissions_grantee_id_fk references parties (party_id), privilege not null constraint acs_permissions_priv_fk references acs_privileges (privilege), constraint acs_permissions_pk primary key (object_id, grantee_id, privilege) ); La tabla acs_privileges almacena el propio nombre de los privilegios como leer, escribir, borrar, crear y administrar. La tabla acs_permissions responde a la ya famosa pregunta clave quién (grantee_id) puede hacer qué (privilege) en tal objeto (object_id). Ahora vamos a profundizar cómo funciona el sistema de permisos a través de la jerarquía de objetos, de parties y de privilegios. Jerarquía de Objetos La tabla acs_objects se crea de la siguiente manera: create table acs_objects ( object_id integer not null constraint acs_objects_pk primary key, object_type not null constraint acs_objects_object_type_fk references acs_object_types (object_type), context_id constraint acs_objects_context_id_fk references acs_objects(object_id), security_inherit_p char(1) default 't' not null, constraint acs_objects_sec_inherit_p_ck check (security_inherit_p in ('t', 'f')), creation_user integer, creation_date date default sysdate not null, creation_ip varchar2(50), last_modified date default sysdate not null, modifying_user integer, modifying_ip varchar2(50), constraint acs_objects_context_object_un unique (context_id, object_id) disable ); De este modo, supongámos que los objetos A, B, ..., F tienen la siguiente jerarquía: Aobject_id=10 Bobject_id=20 Cobject_id=30 Dobject_id=40 Eobject_id=50 Fobject_id=60
    Esto podría ser representado en de la siguiente manera: object_id context_id 20 10 30 10 40 20 50 20 60 30
    Así se expresa que el objeto 20 es descendiente del objeto 10 y que el objeto 40 es descendiente del objeto 10, etc. Mediante una consulta CONNECT BY es posible computar que el objeto 40 es descendiente de segunda generación del objeto 10. Con esto en mente si nosotros queremos grabar que Juan tiene permisos de lectura en los objetos A,...,F, solo necesitamos introducir el siguiente registro en la tabla . Instancia en acs_permissions object grantee privilege A Juan read
    El hecho de Juan también puede leer B,C,...,F puede ser deducido determinando que estos objetos son hijos de A en la jerarquía de objetos. El coste computacional de estas consultas en la jerarquía es bastante costoso. Una manera de solucionar esto podría ser una delgada vista del árbol de contexto como esto: object ancestor n_generations A A 0 B B 0 C C 0 C A 1 D D 0 D B 1 D A 2 E E 0 E B 1 E A 2 F F 0 F C 1 F A 2
    La solución de crear una vista tampoco es válida debido a que crece exponecialmente con respecto a la profundidad del árbol de contexto, dando graves problemas de almacenamiento y mantenimiento. Finalmente, el árbol de contexto es almacenado en la tabla acs_object_context_index: create table acs_object_context_index ( object_id not null constraint acs_obj_context_idx_obj_id_fk references (object_id), ancestor_id not null constraint acs_obj_context_idx_anc_id_fk references (object_id), n_generations integer not null constraint acs_obj_context_idx_n_gen_ck check (n_generations >= 0), constraint acs_object_context_index_pk primary key (object_id, ancestor_id) ) organization index; Esta tabla se sincroniza con mediante triggers como este: create or replace trigger acs_objects_context_id_in_tr after insert on acs_objects for each row begin insert into acs_object_context_index (object_id, ancestor_id, n_generations) values (:new.object_id, :new.object_id, 0); if :new.context_id is not null and :new.security_inherit_p = 't' then insert into acs_object_context_index (object_id, ancestor_id, n_generations) select :new.object_id as object_id, ancestor_id, n_generations + 1 as n_generations from acs_object_context_index where object_id = :new.context_id; elsif :new.object_id != 0 then -- 0 is the id of the security context root object insert into acs_object_context_index (object_id, ancestor_id, n_generations) values (:new.object_id, 0, 1); end if; end; Para finalizar con tan solo decir que si configuramos un objeto con el campo security_inherit_p a 'f', de ese modo no hay herencia de permisos de unos objetos a otros.
    Jerarquía de Privilegios Los privilegios también son organizados jerárquicamente. Además de los cinco principales privilegios de sistema definidos en el ACS Kernel Data Model, los desarrolladores de aplicaciones pueden definir los suyos propios. Gracias al modelo de datos de OpenACS es sencillo para los desarrolladores administrar permisos. Por ejemplo, para darle a un usuario privilegios de lectura, escritura, creación y borrado en un objeto, basta con darle a un usuario el privilegio administración (admin)y los otros cuatro privilegios le serán dados automáticamente. Por ejemplo, la estructura de privilegios de los foros es la siguiente: Jerarquía de privilegios de los foros admin create delete read write moderate forum create category create forum create message delete category delete forum delete message read category read forum read message write category write forum write message
    Al igual que en la jerarquía de objetos, es bueno tener una representación integrada de la estructura jerárquica. Esto se consigue definiendo la siguiente vista: create or replace view acs_privilege_descendant_map as select p1.privilege, p2.privilege as descendant from p1, p2, where p2.privilege in (select child_privilege from start with privilege = p1.privilege connect by prior child_privilege = privilege ) or p2.privilege = p1.privilege; Como el número esperado de privilegios en el sistema es razonablemente pequeño una vista funciona bien.
    Jerarquía de parties Veamos ahora la tercera jerarquía que juega un papel importante en el sistema de permisos. El modelo de datos de parties es el siguiente: parties persons groups users
    create table parties ( party_id not null constraint parties_party_id_fk references acs_objects (object_id) constraint parties_party_id_pk primary key, email varchar2(100) constraint parties_email_un unique, url varchar2(200) ); create table persons ( person_id not null constraint persons_person_id_fk references parties (party_id) constraint persons_person_id_pk primary key, first_names varchar2(100) not null, last_name varchar2(100) not null ); create table users ( user_id not null constraint users_user_id_fk references persons (person_id) constraint users_user_id_pk primary key, password char(40), -- other attributes ); create table groups ( group_id not null constraint groups_group_id_fk references parties (party_id) constraint groups_group_id_pk primary key, group_name varchar2(100) not null ); Recuerda que el campo grantee_id de la tabla referencia a parties.party_id. Esto significa que tu puedes dar privilegios en un objeto a una party, persona, usuario, o grupo. Los grupos representan agregaciones de parties. En general, los grupos son una colección de usuarios, aunque podemos tener colecciones de personas, grupos, parties, ó cualquier mezcla entre unos y otros. Dado que el uso más común de los grupos es para hacer conjuntos de usuarios ¿cómo construiremos los grupos?. Para entender esto debemos echar un rápido vistazo a lo ya explicado en el y recordar que la manera en que se relacionan objetos es mediante acs_rels. La relación que utilizaremos será la de membresía. Si tenemos un grupo llamado Papiroflexia, podemos asingnarle los miembros Pedro, María y Sara. El hecho de que estos usuarios son miembros de Papiroflexia será almacenada en las tablas membership_rels y acs_rels: create table acs_rels ( rel_id not null constraint acs_rels_rel_id_fk references (object_id) constraint acs_rels_pk primary key, rel_type not null constraint acs_rels_rel_type_fk references acs_rel_types (rel_type), object_id_one not null constraint acs_object_rels_one_fk references (object_id), object_id_two not null constraint acs_object_rels_two_fk references (object_id), constraint acs_object_rels_un unique (rel_type, object_id_one, object_id_two) ); create table membership_rels ( rel_id constraint membership_rel_rel_id_fk references (rel_id) constraint membership_rel_rel_id_pk primary key, -- null means waiting for admin approval member_state varchar2(20) constraint membership_rel_mem_ck check (member_state in ('approved', 'banned', 'rejected', 'deleted')) ); Las entradas en la tabla serían de la siguiente manera: Instancia en acs_rel rel_type object_one object_two membership_rel Papiroflexia Pedro membership_rel Papiroflexia María membership_rel Papiroflexia Sara
    Otra manera de crear grupos es añadiendo subgrupos. Supón que nosotros definimos Papiroflexia China y Papiroflexia Japonesa como subgrupos de Papiroflexia. Esta información es guardada en las tablas y composition_rels: create table composition_rels ( rel_id constraint composition_rels_rel_id_fk references (rel_id) constraint composition_rels_rel_id_pk primary key ); Las entradas que nos interesan serían de la siguiente manera: Instancia en acs_rel rel_type object_one object_two composition_rel Papiroflexia Papiroflexia China composition_rel Papiroflexia Papiroflexia Japonesa
    El significado de la relación de composición implica que si añdimos a Marcos, Teresa y Pablo a Papiroflexia China también los añdimos a Papiroflexia. Así, el modo de determinar si un usuario es miembro de un grupo es similar al problema de determinar si un objeto a un determinado contexto en la jerarquía. La relación de composición puede formar jerarquías entre los grupos debido a que esta es transitiva. De nuevo, las búsquedas jeráquicas son costosas. En este caso lo mejor es hacer una cache de resultados de consultas mediante una tabla mantenida por triggers de la misma manera que lo hicimos en la jerarquía de objetos y contextos. El modelo de datos de Open ACS 4.X define las siguientes tablas: create table group_component_index ( group_id not null constraint group_comp_index_group_id_fk references (group_id), component_id not null constraint group_comp_index_comp_id_fk references (group_id), rel_id not null constraint group_comp_index_rel_id_fk references (rel_id), container_id not null constraint group_comp_index_cont_id_ck references (group_id), constraint group_component_index_ck check (group_id != component_id), constraint group_component_index_pk primary key (group_id, component_id, rel_id) ) organization index; create table group_member_index ( group_id not null constraint group_member_index_grp_id_fk references (group_id), member_id not null constraint group_member_index_mem_id_fk references (party_id), rel_id not null constraint group_member_index_rel_id_fk references (rel_id), container_id not null constraint group_member_index_cont_id_fk references (group_id), constraint group_member_index_pk primary key (member_id, group_id, rel_id) ) organization index;
    openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml0000644000175000017500000002305510456621135027543 0ustar frankiefrankie %myvars; ]> Debugging and Automated Testing by Joel Aufrecht Debugging Developer Support The Developer Support package adds several goodies: debug information for every page; the ability to log comments to the page instead of the error log, and fast user switching so that you can test pages as anonymous and as dummy users without logging in and out. PostgreSQL You can work directly with the database to do debugging steps like looking directly at tables and testing stored procedures. Start emacs. Type M-x sql-postgres. Press enter for server name and use $OPENACS_SERVICE_NAME for database name. You can use C-(up arrow) and C-(down arrow) for command history. Hint: "Parse error near *" usually means that an xql file wasn't recognized, because the tcl file is choking on the *SQL* placeholder that it falls back on. Watching the server log To set up real-time monitoring of the AOLserver error log, type less /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/openacs-dev-error.log F to show new log entries in real time (like tail -f) C-c to stop and F to start it up again. G goes to the end. ? searches backward / searches forward. Manual testing Make a list of basic tests to make sure it works Test Num Action Expected Result 001 Browse to the index page while not logged in and while one or more notes exist. No edit or delete or add links should appear. 002 Browse to the index page while logged in. An Edit link should appear. Click on it. Fill out the form and click Submit. The text added in the form should be visible on the index page. API-001 Invoke mfp::note::create with a specific word as the title. Proc should return an object id. API-002 Given an object id from API-001, invoke mfp::note::get. Proc should return the specific word in the title. API-003 Given the object id from API-001, invoke mfp::note::delete. Proc should return 0 for success. Other things to test: try to delete someone else's note. Try to delete your own note. Edit your own note. Search for a note. Write automated tests by Simon Carstensen and Joel Aufrecht Automated tests It seems to me that a lot of people have been asking for some guidelines on how to write automated tests. I've done several tests by now and have found the process to be extremely easy and useful. It's a joy to work with automated testing once you get the hang of it. Create the directory that will contain the test script and edit the script file. The directory location and file name are standards which are recognized by the automated testing package: [$OPENACS_SERVICE_NAME www]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/test [$OPENACS_SERVICE_NAME www]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/test [$OPENACS_SERVICE_NAME test]$ emacs myfirstpackages-procs.tcl Write the tests. This is obviously the big step :) The script should first call ad_library like any normal -procs.tcl file: ad_library { ... } To create a test case you call aa_register_case test_case_name.. Once you've created the test case you start writing the needed logic. We'll use the tutorial package, "myfirstpackage," as an example. Let's say you just wrote an API for adding and deleting notes in the notes packages and wanted to test that. You'd probably want to write a test that first creates a note, then verifies that it was inserted, then perhaps deletes it again, and finally verifies that it is gone. Naturally this means you'll be adding a lot of bogus data to the database, which you're not really interested in having there. To avoid this I usually do two things. I always put all my test code inside a call to aa_run_with_teardown which basically means that all the inserts, deletes, and updates will be rolled back once the test has been executed. A very useful feature. Instead of inserting bogus data like: set name "Simon", I tend to generate a random script in order avoid inserting a value that's already in the database: set name [ad_generate_random_string] Here's how the test case looks so far: aa_register_case mfp_basic_test { My test } { aa_run_with_teardown \ -rollback \ -test_code { } } Now let's look at the actual test code. That's the code that goes inside -test_code {}. We want to implement test case API-001, "Given an object id from API-001, invoke mfp::note::get. Proc should return the specific word in the title." set name [ad_generate_random_string] set new_id [mfp::note::add -title $name] aa_true "Note add succeeded" [exists_and_not_null new_id] To test our simple case, we must load the test file into the system (just as with the /tcl file in the basic tutorial, since the file didn't exist when the system started, the system doesn't know about it.) To make this file take effect, go to the APM and choose "Reload changed" for "MyFirstPackage". Since we'll be changing it frequently, select "watch this file" on the next page. This will cause the system to check this file every time any page is requested, which is bad for production systems but convenient for developing. We can also add some aa_register_case flags to make it easier to run the test. The -procs flag, which indicates which procs are tested by this test case, makes it easier to find procs in your package that aren't tested at all. The -cats flag, setting categories, makes it easier to control which tests to run. The smoke test setting means that this is a basic test case that can and should be run any time you are doing any test. (a definition of "smoke test") Once the file is loaded, go to ACS Automated Testing and click on myfirstpackage. You should see your test case. Run it and examine the results. TCLWebtest tests API testing can only test part of our package - it doesn't test the code in our adp/tcl pairs. For this, we can use TCLwebtest. TCLwebtest must be installed for this test to work. This provides a library of functions that make it easy to call a page through HTTP, examine the results, and drive forms. TCLwebtest's functions overlap slightly with acs-automated-testing; see the example provided for one approach on integrating them. Example Now we can add the rest of the API tests, including a test with deliberately bad data. The complete test looks like: example missing See also . openacs-5.7.0/packages/acs-core-docs/www/xml/developers-guide/tutorial-pages.xml0000644000175000017500000001310711501005400027530 0ustar frankiefrankie %myvars; ]> Creating Web Pages by Joel Aufrecht Install some API As a workaround for missing content-repository functionality, copy a provided file into the directory for tcl files: cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/tutorial/note-procs.tcl /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/ To make this file take effect, go to the APM and choose "Reload changed" for "MyFirstPackage". Page Map Our package will have two visible pages. The first shows a list of all objects; the second shows a single object in view or edit mode, and can also be used to add an object. The index page will display the list, but since we might reuse the list later, we'll put it in a seperate file and include it on the index page.
    Page Map
    Build the "Index" page Each user-visible page in your package has, typically, three parts. The tcl file holds the procedural logic for the page, including TCL and database-independent SQL code, and does things like check permissions, invoke the database queries, and modify variables, and the adp page holds html. The -postgres.xql and -oracle.xql files contains database-specific SQL. The default page in any directory is index, so we'll build that first, starting with the tcl file: [$OPENACS_SERVICE_NAME postgresql]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackages/www [$OPENACS_SERVICE_NAME www]$ emacs index.tcl Paste this into the file. example missing Now index.adp: example missing The index page includes the list page, which we put in /lib instead of /www to designate that it's available for reuse by other packages. [$OPENACS_SERVICE_NAME www]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/lib [$OPENACS_SERVICE_NAME www]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/lib [$OPENACS_SERVICE_NAME lib]$ emacs note-list.tcl example missing [$OPENACS_SERVICE_NAME lib]$ emacs note-list.adp example missing You can test your work by viewing the page. Create the add/edit page. If note_id is passed in, it display that note, and can change to edit mode if appropriate. Otherwise, it presents a form for adding notes. [$OPENACS_SERVICE_NAME lib]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www [$OPENACS_SERVICE_NAME www]$ emacs note-edit.tcl example missing [$OPENACS_SERVICE_NAME www]$ emacs note-edit.adp example missing And the delete page. Since it has no UI, there is only a tcl page, and no adp page. [$OPENACS_SERVICE_NAME www]$ emacs note-delete.tcl example missing
    openacs-5.7.0/packages/acs-core-docs/www/xml/non-xml/0000755000175000017500000000000011724401447022213 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/non-xml/release-notes-4-6-2.html0000644000175000017500000001256407720717703026330 0ustar frankiefrankie OpenACS 4.6.2 Release Notes

    OpenACS 4.6.2 Release Notes

    by Don Baccus
    OpenACS docs are written by the named authors, but may be edited by OpenACS documentation staff.

    This is a final release of OpenACS 4.6.2. This release has been subjected to an organized test effort, but please bear in mind that we are still in the process of developing testing tools, methodology, and scripts.

    Please report bugs using our Bug Tracker at the OpenACS website. This version of the OpenACS Toolkit supports PostgreSQL 7.2.3 and 7.3.2, and Oracle 8i. It will not work with Oracle 9i (support is planned for OpenACS 4.7.)

    Upgrading from OpenACS 4.6.1

    OpenACS 4.6.2 includes key datamodel changes to acs-kernel and other packages. Your first step after downloading OpenACS 4.6.2 and restarting AOLserver should be to visit the Package Manager, click on the "install packages" link, and select the checkbox to upgrade acs-kernel. After acs-kernel has been upgraded, return to the "install packages" page and select the checkboxes for all other packages you have installed that need upgrading (they are marked "upgrade" rather than "new install") and perform the upgrade step.

    After packages have been upgraded, your installation should run without problems.

    You may want to begin by reading our installation documentation for Chapter 3. Note that the Windows documentation is not current for OpenACS 4.6.2, but an alternative is to use John Sequeira's Oasis VM project.

    After installation, the full documentation set can be found by visiting http://[your-host]/doc. Not all pieces are updated for OpenACS 4.6.2 at this moment.

    Site Wide Searching

    If you're using Oracle 8.1.6 or 8.1.7 Enterprise Edition you may want to uncomment the SQL that causes InterMedia to keep online searching online while indexing. The feature doesn't exist in Standard Edition and OpenACS 4.6.2 now defaults to being loadable in SE. Just grep for 'sync' to find the code.

    Also be sure to read the documentation in the Site Wide Search package's sql/oracle directory. The APM doesn't execute the SQL for this package, in part due to the fact that some steps need to be run as the Oracle user 'ctxsys'.

    If you're using PostgreSQL be sure to read the documentation on installing the Open FTS driver for OpenACS. It's included in the package as a text file and is also summarized at the end of the installation documentation in the section, 4. As with the Oracle version, there are steps you must take manually in order to get this feature working.

    Testing Notes

    OpenMSG has organized the OpenACS 4.6.2 testing process with test servers provided by Hub.org. Visit the acceptance test server to see the current status of various packages. This may not be a permanent link. If it's not working, do a search of the OpenACS forums.

    ($Id: release-notes-4-6-2.html,v 1.1 2003/08/20 16:20:19 joela Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/xml/non-xml/release-notes-4-6-3.html0000644000175000017500000001273007720717703026324 0ustar frankiefrankie OpenACS 4.6.3 Release Notes

    OpenACS 4.6.3 Release Notes

    by Don Baccus
    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This is a final release of OpenACS 4.6.3. This release has been subjected to an organized test effort, but please bear in mind that we are still in the process of developing testing tools, methodology, and scripts.

    Please report bugs using our Bug Tracker at the OpenACS website . This version of the OpenACS Toolkit supports PostgreSQL 7.2.3 and 7.3.2, and Oracle 8i. It will not work with Oracle 9i (support is planned for OpenACS 4.7.)

    Upgrading from OpenACS 4.x

    OpenACS 4.6.3 includes key datamodel changes to acs-kernel and other packages. Your first step after downloading OpenACS 4.6.3 and restarting AOLserver should be to visit the Package Manager, click on the "install packages" link, and select the checkbox to upgrade acs-kernel. After acs-kernel has been upgraded, return to the "install packages" page and select the checkboxes for all other packages you have installed that need upgrading (they are marked "upgrade" rather than "new install") and perform the upgrade step.

    After packages have been upgraded, your installation should run without problems.

    Upgrade Instructions

    You may want to begin by reading our installation documentation for Unix, Windows, and Mac OS X.

    After installation, the full documentation set can be found by visiting http://[your-host]/doc. Installation and maintenance documents are current for 4.6.3 but other documentation may lag behind.

    Site Wide Searching

    If you're using Oracle 8.1.6 or 8.1.7 Enterprise Edition you may want to uncomment the SQL that causes InterMedia to keep online searching online while indexing. The feature doesn't exist in Standard Edition and OpenACS 4.6.3 now defaults to being loadable in SE. Just grep for 'sync' to find the code.

    Also be sure to read the documentation in the Site Wide Search package's sql/oracle directory. The APM doesn't execute the SQL for this package, in part due to the fact that some steps need to be run as the Oracle user 'ctxsys'.

    If you're using PostgreSQL be sure to read the documentation on installing the Open FTS driver for OpenACS. It's included in the package as a text file and is also summarized at the end of the installation documentation in the section, 4 . As with the Oracle version, there are steps you must take manually in order to get this feature working.

    Testing Notes

    dotLRN 1.0 is an e-learning solution from MIT based on OpenACS 4.6.3 The dotLRN 1.0 testing effort was organized by Bart Teeuwisse and made use of the OpenACS Bug Tracker and OpenACS test servers hosted by Collaboraid .

    ($Id: release-notes-4-6-3.html,v 1.1 2003/08/20 16:20:19 joela Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/xml/non-xml/release-notes-4-5.html0000644000175000017500000001162307766162046026167 0ustar frankiefrankie OpenACS 4.5 Release Notes

    OpenACS 4.5 Release Notes

    by Don Baccus and Vinod Kurup
    OpenACS docs are written by the named authors, but may be edited by OpenACS documentation staff.

    This is the official OpenACS 4.5 release. This release has been subjected to an organized test effort, but please bear in mind that we are still in the process of developing testing tools, methodology, and scripts.

    Please report bugs using our Software Development Manager at the OpenACS website . The latest information on installing this alpha release under Oracle 8.1.6/7 or PostgreSQL 7.1.* can be found there as well. Currently the toolkit will not install under Oracle 9i due to Oracle having made "delete" an illegal name for PL/SQL procedures and functions.

    Some users have reported success running OpenACS 4.5 under PostgreSQL 7.2, but there may still be some undetected problems with this platform.

    You may want to begin by reading our installation documentation for Installing on Unix/Linux or Installing on Windows . Note that the Windows documentation is not current for OpenACS 4.5, but an alternative is to use John Sequeira's Oasis VM project .

    After installation, the full documentation set can be found by visiting http://[your-host]/doc. Not all pieces are updated for OpenACS 4.5 at this moment.

    Site Wide Searching

    If you're using Oracle 8.1.6 or 8.1.7 Enterprise Edition you may want to uncomment the SQL that causes InterMedia to keep online searching online while indexing. The feature doesn't exist in Standard Edition and OpenACS 4.5 now defaults to being loadable in SE. Just grep for 'sync' to find the code.

    Also be sure to read the documentation in the Site Wide Search package's sql/oracle directory. The APM doesn't execute the SQL for this package, in part due to the fact that some steps need to be run as the Oracle user 'ctxsys'.

    If you're using PostgreSQL be sure to read the documentation on installing the Open FTS driver for OpenACS. It's included in the package as a text file and is also summarized at the end of the installation documentation in the section, Set Up OpenFTS . As with the Oracle version, there are steps you must take manually in order to get this feature working.

    Testing Notes

    We now maintain our test results using a custom OpenACS 4.5 package developed by OpenMSG . As can be seen from the notes, there are still some serious outstanding bugs in this release. If you don't like this state of affairs consider volunteering to help out. Just drop the project manager a quick note and you'll be signed up more quickly than you can say "wait! I've changed my mind!"

  • ($Id: release-notes-4-5.html,v 1.2 2003/12/11 21:39:50 jeffd Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/non-xml/release-notes-4-6.html0000644000175000017500000001624510207353614026160 0ustar frankiefrankie OpenACS 4.6 Release Notes

    OpenACS 4.6 Release Notes

    by Don Baccus
    OpenACS docs are written by the named authors, but may be edited by OpenACS documentation staff.

    This is a final release of OpenACS 4.6. This release has been subjected to an organized test effort, but please bear in mind that we are still in the process of developing testing tools, methodology, and scripts.

    Please report bugs using our Software Development Manager at the OpenACS website. The latest information on installing this release under Oracle 8.1.6/7 or PostgreSQL 7.1.* can be found there as well. Currently the toolkit will not install under Oracle 9i due to Oracle having made "delete" an illegal name for PL/SQL procedures and functions.

    You may want to begin by reading our installation documentation for Installing on Unix/Linux or Installing on Windows. Note that the Windows documentation is not current for OpenACS 4.6, but an alternative is to use John Sequeira's Oasis VM project.

    After installation, the full documentation set can be found by visiting http://[your-host]/doc. Not all pieces are updated for OpenACS 4.6 at this moment.

    Site Wide Searching

    If you're using Oracle 8.1.6 or 8.1.7 Enterprise Edition you may want to uncomment the SQL that causes InterMedia to keep online searching online while indexing. The feature doesn't exist in Standard Edition and OpenACS 4.6 now defaults to being loadable in SE. Just grep for 'sync' to find the code.

    Also be sure to read the documentation in the Site Wide Search package's sql/oracle directory. The APM doesn't execute the SQL for this package, in part due to the fact that some steps need to be run as the Oracle user 'ctxsys'.

    If you're using PostgreSQL be sure to read the documentation on installing the Open FTS driver for OpenACS. It's included in the package as a text file and is also summarized at the end of the installation documentation in the section, Set Up OpenFTS. As with the Oracle version, there are steps you must take manually in order to get this feature working.

    Testing Notes

    Here are some notes from our testing group. While not quite up to date it should give you some ideas of where things stand.

     Summarised Testing Status
    
    Skin
    Minimal
    Release w/caution
    Comments:
    
    Package: Page
    Test Coverage: Minimal
    Release w/caution
    Comments:
    
    Package: Bboard
    Test Coverage: Reasonable
    Suggested Status: Alpha
    Comments:
    
    Package: Static Pages
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments:
    
    Package: Ticket Tracker
    Test Coverage: Reasonable
    Suggested Status: Alpha
    Comments: Don tested personally
    
    Package: Ticket Tracker Lite
    Test Coverage: Unknown
    Suggested Status: 
    Comments:
    
    Package: Acs-lang
    Test Coverage: Reasonable
    Suggested Status: Alpha
    Comments: Oracle only
    
    Package: Simple-survey
    Test Coverage: Reasonable
    Suggested Status: Alpha
    Comments:
    
    Package: Portal
    Test Coverage: Extensive
    Suggested Status: Alpha
    Comments:
    
    Package: Notes
    Test Coverage: Extensive
    Suggested Status: Alpha
    Comments:
    
    Package: Bookmarks
    Test Coverage: Extensive
    Suggested Status: Alpha
    Comments:
    
    Package: Clickthrough
    Test Coverage: Extensive
    Suggested Status: Alpha
    Comments:
    
    Package: Acs-mail
    Test Coverage: Reasonable
    Suggested Status: Release w/caution
    Comments:
    
    Package: Acs-messaging
    Test Coverage: Reasonable
    Suggested Status: Release w/caution
    Comments:
    
    Package: File manager
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments:
    
    Package: File Storage
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments:
    
    Package: Site-wide-search
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments:
    
    Package: General Comments
    Test Coverage: Extensive
    Suggested Status: Alpha
    Comments:
    
    Package: Acs-events
    Test Coverage: None
    Suggested Status: 
    Comments: Automated Testing
    
    Package: Acs-datetime
    Test Coverage: None
    Suggested Status: 
    Comments: Automated Testing
    
    Package: Acs-tcl
    Test Coverage: Reasonable
    Suggested Status: Release w/caution
    Comments: Automated Testing
    
    Package: Acs-templating
    Test Coverage: Reasonable
    Suggested Status: Release w/caution
    Comments: Automated Testing
    
    Package: Acs-util
    Test Coverage: Reasonable
    Suggested Status: Release w/caution
    Comments: Automated Testing
    
    Package: Acs-Content-repository
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments: Automated Testing
    
    Package: Acs-content
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments: Automated Testing
    
    Package: Acs-kernel
    Test Coverage: Reasonable
    Suggested Status: Alpha
    Comments: Automated Testing
    
    Package: Acs-subsite
    Test Coverage: Reasonable
    Suggested Status: Alpha
    Comments: 
    
    Package: Acs-bootstrap-installer
    Test Coverage: Extensive
    Suggested Status: Alpha
    Comments: Developers have used this extensively
    
    Package: Acs-api-browser
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments: Automated Testing
    
    Package: Acs-workflow
    Test Coverage: Minimal
    Suggested Status: Release w/caution
    Comments: 
    
    Package: calendar
    Test Coverage: Minimal
    Suggested Status: Alpha
    Comments: Don tested personally
    	
    ($Id: release-notes-4-6.html,v 1.3 2005/02/24 13:33:00 jeffd Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/0000755000175000017500000000000011724401447025076 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/style-guide.xml0000644000175000017500000001670510456621135030063 0ustar frankiefrankie %myvars; ]> OpenACS Style Guide By Jeff Davis Motivation Why have coding standards for OpenACS? And if the code works why change it to adhere to some arbitrary rules? Well, first lets consider the OpenACS code base (all this as of December 2003 and including dotLRN). There are about 390,000 lines of tcl code, about 460,000 lines of sql (in datamodel scripts and .xql files), about 80,000 lines of markup in .adp files, and about 100,000 lines of documentation. All told, just about a million lines of "stuff". In terms of logical units there are about 160 packages, 800 tables, 2,000 stored procedures, about 2,000 functional pages, and about 3,200 tcl procedures. When confronted by this much complexity it's important to be able to make sense of it without having to wade through it all. Things should be coherent, things should be named predictably and behave like you would expect, and your guess about what something is called or where it is should be right more often than not because the code follows the rules. Unfortunately, like any large software project written over a long period by a lot of different people, OpenACS sometimes lacks this basic guessability and in the interest of bringing it into line we have advanced these guidelines. Commandments Here is a short list of the basic rules code contributed to OpenACS should follow... Follow the file naming and the package structure rules Some of the file naming rules are requirements for things to function correctly (for example data model creation scripts and tcl library files must be named properly to be used), while some are suggestions (the object-verb naming convention) which if ignored won't break anything, but if you follow the rules people will be able to understand your package much more easily. Be literate in your programming Use ad_proc, ad_library, and ad_page_contract to provide documentation for your code, use comments on your datamodel, explain what things mean and how they should work. Test Write test cases for your API and data model; test negative cases as well as positive; document your tests. Provide tests for bugs which are not yet fixed. Test, Test, Test. Use namespaces For new packages choose a namespace and place all procedures in it and in oracle create packages. Follow the constraint naming and the PL/SQL and PL/pgSQL rules Naming constraints is important for upgradability and for consistency. Also, named constraints can be immensely helpful in developing good error handling. Following the PL/SQL and PL/pgSQL rules ensure that the procedures created can be handled similarly across both Oracle and PostgreSQL databases. Follow the code formatting guidelines The code base is very large and if things are formatted consistently it is easier to read. Also, if it conforms to the standard it won't be reformatted (which can mask the change history and making tracking down bugs much harder). Using spaces rather than tabs makes patches easier to read and manage and does not force other programmers to decipher what tab settings you had in place in your editor. Use the standard APIs Don't reinvent the wheel. Prefer extending an existing core API to creating your own. If something in the core does not meet your particular needs it probably won't meet others as well and fleshing out the core API's makes the toolkit more useful for everyone and more easily extended. Make sure your datamodel create/drop scripts work Break the table creation out from the package/stored procedure creation and use create or replace where possible so that scripts can be sourced more than once. Make sure your drop script works if data has been inserted (and permissioned and notifications have been attached etc). Practice CVS/Bug Tracker Hygiene Commit your work. commit with sensible messages and include patch and bug numbers in your commit messages. Create bug tracker tickets for things you are going to work on yourself (just in case you don't get to it and to act as a pointer for others who might encounter the same problem). Solicit code reviews Ask others to look over your code and provide feedback and do the same for others. Revision History Document Revision # Action Taken, Notes When? By Whom? 0.1 Creation 12/2003 Jeff Davis ($Id: style-guide.xml,v 1.3 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/variables.xml0000644000175000017500000000232610456621135027572 0ustar frankiefrankie %myvars; ]> Variables Date and Time Variables ($Id: variables.xml,v 1.3 2006/07/17 05:38:37 torbenb Exp $) By joel@aufrecht.org Starting with OpenACS 5.0 and the introduction of acs-lang, we recommend retrieving date/time information from the database in ANSI format and then using lc_time_fmt to format it for display. Getting datetime from the database ANSI-style db_multirow -extend { mydate_pretty } { select to_char(mydate, 'YYYY-MM-DD HH24:MI:SS') as mydate_ansi, ... ... } { set mydate_ansi [lc_time_system_to_conn $mydate_ansi] set mydate_pretty [lc_time_fmt $mydate_ansi "%x %X"] } openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/auto-testing.xml0000644000175000017500000000644510456621135030253 0ustar frankiefrankie %myvars; ]> Automated Testing By Jeff Davis Best practices in writing OpenACS automated tests Special characters in Tcl Try strings starting with a -Bad and strings containing [BAD], {, \077, and $Bad. For user input, [BAD] should never be evaluated, \077 should not be turned into a ? and $Bad should not be interpolated. The string -Bad [BAD] \077 { $Bad should be valid user input, should pass through the system unaltered, and if it isn't that's a bug. Quoting issues Put some html in plain text fields and make sure the result is properly quoted anywhere it shows up (I use "<b>bold</b>" usually). Look out especially for quoting errors in the context bar and in round trips via an edit form. For fields that disallow html tags you can use &amp; to check that the field is quoted properly. If it is not displayed as &amp; then the quoting for the field is incorrect. (It's not clear whether this should be considered an error but given that data for text fields can come from various sources if it's text it should be properly quoted and we should not rely on input validation to prevent XSS security holes.) Whitespace input Check that whitespace is not considered valid input for a field if it does not make sense. For example, the subject of a forum post is used to construct a link and if it is " " it will have a link of <a href="..."> </a> which would not be clickable if whitespace was allowed as a valid input. Doubleclick Make sure that if you submit a form, use the back button, and submit again that the behavior is reasonable (correct behavior depends on what the form is for, but a server error is not reasonable). Duplicate names Make sure that if a duplicate name is entered that there is a reasonable error rather than a server error. Check for insert, move, copy, and rename. ($Id: auto-testing.xml,v 1.3 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/requirements-template.xml0000644000175000017500000001776410456621135032172 0ustar frankiefrankie %myvars; ]> System/Application Requirements Template By You Introduction Briefly explain to the reader what this document is for, whether it records the requirements for a new system, a client application, a toolkit subsystem, etc. Remember your audience: fellow programmers, AND interested non-technical parties such as potential clients, who may all want to see how rigorous our engineering process is. Here and everywhere, write clearly and precisely; for requirements documentation, write at a level that any intelligent layperson can understand. Vision Statement Very broadly, describe how the system meets a need of a business, group, the OpenACS as a whole, etc. Make sure that technical and non-technical readers alike would understand what the system would do and why it's useful. Whenever applicable, you should explicitly state what the business value of the system is. System/Application Overview Discuss the high-level breakdown of the components that make up the system. You can go by functional areas, by the main transactions the system allows, etc. You should also state the context and dependencies of the system here, e.g. if it's an application-level package for OpenACS 4, briefly describe how it uses kernel services, like permissions or subsites. Use-cases and User-scenarios Determine the types or classes of users who would use the system, and what their experience would be like at a high-level. Sketch what their experience would be like and what actions they would take, and how the system would support them. Optional: Competitive Analysis Describe other systems or services that are comparable to what you're building. If applicable, say why your implementation will be superior, where it will match the competition, and where/why it will lack existing best-of-breed capabilities. This section is also in the Design doc, so write about it where you deem most appropriate. Related Links Include all pertinent links to supporting and related material, such as: System/Package "coversheet" - where all documentation for this software is linked off of Design document Developer's guide User's guide Other-cool-system-related-to-this-one document Test plan Competitive system(s) Requirements The main course of the document, requirements. Break up the requirements sections (A, B, C, etc.) as needed. Within each section, create a list denominated with unique identifiers that reflect any functional hierarchy present, e.g. 20.5.13. - for the first number, leave generous gaps on the first writing of requirements (e.g. 1, 10, 20, 30, 40, etc.) because you'll want to leave room for any missing key requirements that may arise. 10.0 A Common Solution Programmers and designers should only have to learn a single system that serves as a UI substrate for all the functionally specific modules in the toolkit.
    10.0.1 The system should not make any assumptions about how pages should look or function. 10.0.5 Publishers should be able to change the default presentation of any module using a single methodology with minimal exposure to code.
    For guidelines writing requirements, take a look at the quality standards, along with a good example, such as . Besides writing requirements in natural language, consider using the following techniques as needed: Pseudocode - a quasi programming language, combining the informality of natural language with the strict syntax and control structures of a programming language. Finite State Machines - a hypothetical machine that can be in only one of a given number of states at any specific time. Useful to model situations that are rigidly deterministic, that is, any set of inputs mathematically determines the system outputs. Decision Trees and Decision Tables - similar to FSMs, but better suited to handle combinations of inputs. Flowcharts - easy to draw and understand, suited for event and decision driven systems. UML is the industry standard here. Entity-Relationship diagrams - a necessary part of Design documents, sometimes a high-level ER diagram is useful for requirements as well.
    Optional: Implementation Notes Although in theory coding comes after design, which comes after requirements, we do not, and perhaps should not, always follow such a rigid process (a.k.a. the waterfall lifecyle). Often, there is a pre-existing system or prototype first, and thus you may want to write some thoughts on implementation, for aiding and guiding yourself or other programmers. Revision History Document Revision # Action Taken, Notes When? By Whom? 0.3 Edited further, incorporated feedback from Michael Yoon 9/05/2000 Kai Wu 0.2 Edited 8/22/2000 Kai Wu 0.1 Created 8/21/2000 Josh Finkler, Audrey McLoghlin ($Id: requirements-template.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/cvs.xml0000644000175000017500000011117310456621135026416 0ustar frankiefrankie %myvars; ]> CVS Guidelines ($Id: cvs.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $) By Joel Aufrecht with input from Jeff Davis, Branimir Dolicki, and Jade Rubick. Using CVS with OpenACS Getting Started All OpenACS code is available anonymously. To get code anonymously, use the parameter -d:pserver:anonymous@cvs.openacs.org:/cvsroot immediately after cvs in a cvs command to check out or export code. If you are an OpenACS developer, you should check out code so that you or any other developer can commit it. To do this, use the parameter -d:ext:cvs.openacs.org:/cvsroot immediately after cvs in checkout commands. This will create a local checkout directory that uses cvs.openacs.org but does not specify the user. By default, it will use your local account name as the user, so if you are logged in as "foobar" it will try to check out and commit as if you had specified :ext:foobar@cvs.openacs.org:/cvsroot. The advantage of not specifying a user in the checkout command is that other users can work in the directory using their own accounts. OpenACS.org supports non-anonymous cvs access only over ssh, so you must have CVS_RSH=ssh in your environment. (Typically this is accomplished by putting export CVS_RSH=ssh into ~/.bash_profile.). If your local account name does not match your cvs.openacs.org account name, create a file ~/.ssh/config with an entry like: Host cvs.openacs.org User joel With this setup, you will be asked for your password with each cvs command. To avoid this, set up ssh certificate authentication for your openacs account. (More information) You may want to set some more default actions for CVS usage. To do so, create the file ~/.cvsrc with the contents: cvs -z6 cvs -q -z6 speeds up cvs access over the network quite a bit by enabling compressed connection by default. -q suppresses some verbose output from commands. For example, it makes the output of cvs up much easier to read. Administrator Note: These are the steps to grant CVS commit rights to a user: Create the user's account. On cvs.openacs.org: sudo bash /usr/sbin/useradd -c "Real Name" -G cvs -p passwd username /usr/sbin/usermod -G cvs,username username Grant cvs access to the user account. On any machine, in a temporary directory: cvs -d :ext:cvs.openacs.org:/cvsroot co CVSROOT cd CVSROOT emacs avail Add an avail line of the form: avail|username|openacs-4 cvs commit -m "added commit on X for username" avail Branimir suggests an additional level of abstraction. If you put Host cvs-server HostName cvs.openacs.org User yournamehere into your ~/.ssh/config file, then you can use -d :ext:cvs-server:/cvsroot instead of -d :ext:cvs.openacs.org:/cvsroot. You can then change the definition of cvs-server by changing one file instead of editing hundreds of CVSROOT/Repository files. Checkout for Package Development If you are actively developing a non-core package, you should work from the latest core release branch. Currently this is &releasebranch;. This ensures that you are working on top of a stable OpenACS core, but still allows you to commit feature changes to non-core packages. To check out all packages, cvs -d :ext:cvs.openacs.org:/cvsroot co -r &releasebranch; openacs-4 If you work in the directories created with this command, all of your cvs updates and commits will be confined to the &releasebranch; branch. Your work will be merged back to HEAD for you with each release. Because the entire openacs-4 directory is large, you may want to use only acs-core plus some specific modules. To do this, check out core first: cvs -d:ext:cvs.openacs.org:/cvsroot -r &releasebranch; checkout acs-core Then add modules as needed: cd /var/lib/aolserver/service0/packages cvs up -d packagename ... where packagename is the name of the package you want. Visit the Package Inventory and Package maintainers and status for a list of available packages and their current state. Checkout for Core Development If you are actively developing packages in the OpenACS Core, work from the HEAD branch. HEAD is used for active development of the next version of core OpenACS. It may be very buggy; it may not even install correctly. Do not use this branch for development of non-core features unless your work depends on some of the HEAD core work. To check out HEAD, omit the -r tag. To check out HEAD for development, which requires an OpenACS developer account: cvs -d:ext:cvs.openacs.org:/cvsroot checkout acs-core To check out HEAD anonymously: cvs -d:pserver:anonymous@cvs.openacs.org:/cvsroot checkout acs-core Checkout .LRN .LRN consists of a given version openacs core, plus a set of packages. These are collectively packages together to form a distrubution of .LRN. F .LRN 2.0.0 sits on top of OpenACS 5.0.0. .LRN also uses an OpenACS install.xml file during installation; this file is distributed within the dotlrn package and must be moved. To get a development checkout of .LRN in the subdirectory dotlrn: cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r &releasebranch; acs-core mv openacs-4 dotlrn cd dotlrn/packages cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r &releasebranch; dotlrn-all mv dotlrn/install.xml .. Working with CVS Once you have a checkout you can use some commands to track what has changed since you checked out your copy. cvs -n update does not change any files, but reports which changes have been updated or locally modified, or are not present in CVS. To update your files, use cvs update. This will merge changes from the repository with your local files. It has no effect on the cvs.openacs.org repository. OpenACS CVS Concepts Modules All OpenACS code resides within a single CVS module, openacs-4. (The openacs-4 directory contains code for all versions of OpenACS 4 and later, and .LRN 1 and later.) Checking out this module retrieves all openacs code of any type. For convenience, subsets of openacs-4 are repackaged as smaller modules. acs-core contains only critical common packages. It does not have any user applications, such as forums, bug-tracker, calendar, or ecommerce. These can be added at any time. The complete list of core packages is: acs-admin acs-api-browser acs-authentication acs-automated-testing acs-bootstrap-installer acs-content-repository acs-core-docs acs-kernel acs-lang acs-mail acs-messaging acs-reference acs-service-contract acs-subsite acs-tcl acs-templating ref-timezones search dotlrn-all contains the packages required, in combination with acs-core, to run the .LRN system. project-manager-all contains the packages required, in combination with acs-core, to run the project-manager package. Each OpenACS package (i.e., directory in openacs-4/packages/) is also aliased as a module of the same name. Tags and Branches Tags and Branches look similar in commands, but behave differently. A tag is a fixed point on a branch. Check out a tag to get a specific version of OpenACS. Check out a branch to get the most current code for that major-minor version (e.g., 5.0.x or 5.1.x). You can only commit to a branch, not a tag, so check out a branch if you will be working on the code. openacs-x-y-z-final tags mark final releases of OpenACS. This tag is applied to the acs-core files for an OpenACS core release, and to the latest released versions of all other packages at the time of release. Example: openacs-5-0-4-final. dotlrn-x-y-z-final tags mark final releases of .LRN. These tags apply only to .LRN packages. Example: dotlrn-2-0-1-final packagename-x-y-z-final tags apply to releases of individual packages. For example, calendar-2-0-0-final is a tag that will retrieve only the files in the calendar 2.0.0 release. It applies only to the calendar package. All non-core, non-dotlrn packages should have a tag of this style, based on the package name. Many packages have not been re-released since the new naming convention was adopted and so don't have a tag of this type. openacs-x-y-compat tags point to the most recent released version of OpenACS X.Y. It is similar to openacs-x-y-z-compat, except that it will always get the most recent dot-release of Core and the most recent compatible, released version of all other packages. All of the other tag styles should be static, but -compat tags may change over time. If you want version 5.0.4 exactly, use the openacs-5-0-4-final tag. If you want the best newest released code in the 5.0.x release series and you want to upgrade within 5.0.x later, use the compat tag. For example, if you check out the entire tree with -r openacs-5-0-compat, you might get version 5.0.4 of each OpenACS core package, version 2.0.1 of calendar, version 2.0.3 of each .LRN package, etc. If you update the checkout two months later, you might get version 5.0.5 of all OpenACS core packages and version 2.1 of calendar. oacs-x-y is a branch, , not a tag. All core packages in the 5.0 release series (5.0.0, 5.0.1, 5.0.2, etc) are also on the oacs-5-0 branch. Similarly, OpenACS core packages for 5.1.0 are on the oacs-5-1 branch. These branches are used for two purposes. OpenACS Core packages on these branches are being tidied up for release. Only bug fixes, not new features, should be added to core packages on release branches. For all other packages, release branches are the recommended location for development. For example, if you are working on calendar, which is compatible with openacs 5.0 but not 5.1, work on the oacs-5-0 branch. HEAD is a branch used for development of core packages. Contributing code back to OpenACS There are three main ways to contribute code to OpenACS: To contribute a small fix, if you do not have a developer account, submit a patch. If you are making many changes, or would like to become a direct contributor, send mail to the Core Team asking for commit rights. You can then commit code directly to the repository: Use one of the checkout methods described above to get files to your system. This takes the place of steps 1 and 2 in . Continue setting up the site as described there. Fix bugs and add features. Commit that file (or files): cvs commit -m "what I did and why" filename Because this occurs in your personal checkout and not an anonymous one, this commit automagically moves back upstream to the Mother Ship repository at cvs.openacs.org. The names of the changed files, and your comments, are sent to a mailing list for OpenACS developers. A Core Team developer may review or roll back your changes if necessary. Confirm via the OpenACS CVS browser that your changes are where you intended them to be. Add a new package. Contact the Core Team to get approval and to get a module alias created. Check out acs-core on the HEAD branch. (Weird things happen if you add files to a branch but not to HEAD): cd /tmp cvs -d:ext:cvs.openacs.org:/cvsroot checkout acs-core Copy your package directory from your working directory to this directory. Make sure not to copy any CVS directories. cp -r /var/lib/aolserver/service0/packages/newpackage /tmp/openacs-4/packages Import the package into the cvs.openacs.org cvs repository: cd /tmp/openacs-4/packages/newpackage cvs import -m "Initial import of newpackage" openacs-4/packages/newpackage myname newpackage-0-1d Add the new package to the modules file. (An administrator has to do this step.) On any machine, in a temporary directory: cvs -d :ext:cvs.openacs.org:/cvsroot co CVSROOT cd CVSROOT emacs modules Add a line of the form: photo-album-portlet openacs-4/packages/photo-album-portlet Commit the change: cvs commit -m "added alias for package newpackage" modules This should print something like: cvs commit: Examining . **** Access allowed: Personal Karma exceeds Environmental Karma. Checking in modules; /cvsroot/CVSROOT/modules,v <-- modules new revision: 1.94; previous revision: 1.93 done cvs commit: Rebuilding administrative file database Although you should add your package on HEAD, you should do package development on the latest release branch that your code is compatible with. So, after completing the import, you may want to branch your package: cd /var/lib/aolserver/service0/packages/newpackage cvs tag -b oacs-5-1 See Some packages are already in cvs at openacs-4/contrib/packages. Starting with OpenACS 5.1, we have a Maturity mechanism in the APM which makes the contrib directory un-necessary. If you are working on a contrib package, you should move it to /packages. This must be done by an OpenACS administrator. On cvs.openacs.org: cp -r /cvsroot/openacs-4/contrib/packages/package0 /cvsroot/openacs-4/packages Update the modules file as described above. Remove the directory from cvs in the old location using cvs rm. One approach for file in `find | grep -v CVS`; do rm $file; cvs remove $file; done Rules for Committing Code to the OpenACS repository CVS commit procedures are governed by TIP (Technical Improvement Proposal) #61: Guidelines for CVS committers Which branch? For core packages, new features should always be committed on HEAD, not to release branches. For core packages, bug fixes should be committed on the current release branch whenever applicable. For non-core packages, developers should work on a checkout of the release branch of the lastest release. For example, if OpenACS 5.1.0 is released, developers should work on the oacs-5-1 branch. When oacs-5-2 is branched, developers should continue working on oacs-5-1 until OpenACS 5.2.0 is actually released. Reason: First, this ensures that developers are working against stable core code. Second, it ensures that new package releases are available to OpenACS users immediately. The current release branch is merged back to HEAD after each dot release. New packages should be created in the /packages directory and the maturity flag in the .info file should be zero. This is a change from previous policy, where new packages went to /contrib/packages) Code Only GPL code and material should be committed to the OpenACS CVS repository (cvs.openacs.org) Do not mix formatting changes with code changes. Instead, make a formatting-only change which does not affect the logic, and say so in the commit comment. Then, make the logic change in a separate commit. Reason: This makes auditing and merging code much easier. Database upgrade scripts should only span one release increment, and should follow Naming Database Upgrade Scripts . Reason: If an upgrade script ends with the final release number, then if a problem is found in a release candidate it cannot be addressed with another upgrade script. E.g., the last planned upgrade script for a package previously in dev 1 would be upgrade-2.0.0d1-2.0.0b1.sql, not upgrade-2.0.0d1-2.0.0.sql. Note that using rc1 instead of b1 would be nice, because that's the convention with release codes in cvs, but the package manager doesn't support rc tags. Database upgrade scripts should never go to the release version, e.g., should always have a letter suffix such as d1 or b1. CVS commit messages should be intelligible in the context of Changelogs. They should not refer to the files or versions. CVS commit messages and code comments should refer to bug, tip, or patch number if appropriate, in the format "resolves bug 11", "resolves bugs 11, resolves bug 22". "implements tip 42", "implements tip 42, implements tip 50", "applies patch 456 by User Name", "applies patch 456 by User Name, applies patch 523 by ...". When to TIP A TIP is a Techical Improvement Proposal ( more information ). A proposed change must be approved by TIP if: It changes the core data model, or It will change the behavior of any core package in a way that affects existing code (typically, by changing public API), or It is a non-backwards-compatible change to any core or standard package. A proposed change need not be TIPped if: it adds a new function to a core package in a way that: does not change the backwards-compatibility of public API functions. does not change the data model has no negative impact on performance it changes private API, or it is a change to a non-core, non-standard package Tags When a package is released in final form, the developer shall tag it "packagename-x-y-z-final" and "openacs-x-y-compat". x-y should correspond to the current branch. If the package is compatible with several different core versions, several compat tags should be applied. Reason 1: The packagename tag is a permanent, static tag that allows for future comparison. The compat tag is a floating tag which is used by the repository generator to determine the most recent released version of each package for each core version. This allows package developers to publish their releases to all users of automatic upgrade without any intervention from the OpenACS release team.Reason 2: The compat tags allows CVS users to identify packages which have been released since the last core release.Reason 3: The compat tag or something similar is required to make Rule 6 possible. When OpenACS core is released, the openacs-x-y-z-final tag shall be applied to all compat packages. Reason: This allows OpenACS developers who are creating extensively customized sites to branch from a tag which is stable, corresponds to released code instead of development code, and applies to all packages. This tag can be used to fork packages as needed, and provides a common ancestor between the fork and the OpenACS code so that patches can be generated. For example, adding a new API function wouldn't require a TIP. Changing an existing API function by adding an optional new flag which defaults to no-effect wouldn't require a TIP. Added a new mandatory flag to an existing function would require a TIP. Informal Guidelines Informal guidelines which may be obsolete in places and should be reviewed: Before committing to cvs you must submit a bug report and patch to the OpenACS bug tracker . The only exceptions to this rule are for package maintainers committing in a package they are maintaining and for members of the core team. If you are committing a bug fix you need to coordinate with the package maintainer. If you are a maintainer then coordinate with any fellow maintainers. If you are to commit a new feature, an architecture change, or a refactoring, you must coordinate with the OpenACS core team first. Also, such changes should have a discussion in the forums to allow for feedback from the whole community. If you are changing the data model you *must* provide an upgrade script and bump up the version number of the package. Consider any upgradability ramifications of your change. Avoid changing the contract and behaviour of Tcl procedures. If you want to build a new and clean API consider deprecating the old proc and making it invoke the new one. Never rush to commit something. Before committing double check with cvs diff what exactly you are committing. Always accompany a commit with a brief but informative comment. If your commit is related to bug number N and/or patch number P, indicate this in the commit comment by including "bug N" and/or "patch P". This allows us to link bugs and patches in the Bug Tracker with changes to the source code. For example suppose you are committing a patch that closes a missing HTML tag, then an appropriate comment could be "Fixing bug 321 by applying patch 134. Added missing h3 HTML close tag". Commit one cohesive bug fix or feature change at a time. Don't put a bunch of unrelated changes into one commit. Before you throw out or change a piece of code that you don't fully understand, use cvs annotate and cvs log on the file to see who wrote the code and why. Consider contacting the author. Test your change before committing. Use the OpenACS package acs-automated-testing to test Tcl procedures and the tool Tclwebtest to test pages Keep code simple, adhere to conventions, and use comments liberally. In general, treat the code with respect, at the same time, never stop questioning what you see. The code can always be improved, just make sure you change the code in a careful and systematic fashion. Additional Resources for CVS The OpenACS cvs web and Jeff's cvs browser are useful tools in understanding what is happening with the code. There is a mailing list of cvs changes at willfork.com There is an RSS feed of cvs changes at RSS feed cvs manual adding files/dirs with cvs file locking etc. with cvs Piskorski's cvs refs backup with cvs merging 2 file heirarchies with cvs openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/eng-standards-versioning.xml0000644000175000017500000002214010456621135032531 0ustar frankiefrankie %myvars; ]> Release Version Numbering ($Id: eng-standards-versioning.xml,v 1.10 2006/07/17 05:38:37 torbenb Exp $) By Ron Henderson, Revised by Joel Aufrecht OpenACS version numbers help identify at a high-level what is in a particular release and what has changed since the last release. A "version number" is really just a string of the form:
    major.minor.dot[ milestone ]
    A major number change indicates a fundamental change in the architecture of the system, e.g. OpenACS 3 to ACS 4. A major change is required if core backwards compatibility is broken, if upgrade is non-trivial, or if the platform changes substantially. A minor change represents the addition of new functionality or changed UI. A dot holds only bug fixes and security patches. Dot releases are always recommended and safe. A milestone marker indicates the state of the release: d, for development, means the release is in active development and is not in its intended released form. a, for alpha, means new development is complete and code checkins are frozen. Alpha builds should work well enough to be testable. b, for beta, means most severe bugs are fixed and end users can start trying the release. Release Candidate builds (rc) are believed to meet all of the criteria for release and can be installed on test instances of production systems. Final releases have no milestone marker. (Exception: In CVS, they are tagged with -final to differentiate them from branch tags.) Milestone markers are numbered: d1, d2, ..., a1, b1, rc1, etc. A complete sequence of milestones between two releases: 5.0.0 5.0.0rc2 5.0.0rc1 5.0.0b4 5.0.0b1 5.0.0a4 5.0.0a3 5.0.0a1 5.0.0d1 4.6.3 Version numbers are also recorded in the CVS repository so that the code tree can be restored to the exact state it was in for a particular release. To translate between a distribution tar file (acs-3.2.2.tar.gz) and a CVS tag, just swap '.' for '-'.The entire release history of the toolkit is recorded in the tags for the top-level readme.txt file: > cvs log readme.txt RCS file: /usr/local/cvsroot/acs/readme.txt,v Working file: readme.txt head: 3.1 branch: locks: strict access list: symbolic names: acs-4-0: 3.1.0.8 acs-3-2-2-R20000412: 3.1 acs-3-2-1-R20000327: 3.1 acs-3-2-0-R20000317: 3.1 acs-3-2-beta: 3.1 acs-3-2: 3.1.0.4 acs-3-1-5-R20000304: 1.7.2.2 acs-3-1-4-R20000228: 1.7.2.2 acs-3-1-3-R20000220: 1.7.2.2 acs-3-1-2-R20000213: 1.7.2.1 acs-3-1-1-R20000205: 1.7.2.1 acs-3-1-0-R20000204: 1.7 acs-3-1-beta: 1.7 acs-3-1-alpha: 1.7 acs-3-1: 1.7.0.2 v24: 1.5 v23: 1.4 start: 1.1.1.1 arsdigita: 1.1.1 keyword substitution: kv total revisions: 13; selected revisions: 13 description: ... In the future, OpenACS packages should follow this same convention on version numbers. Transition Rules So what distinguishes an alpha release from a beta release? Or from a production release? We follow a specific set of rules for how OpenACS makes the transition from one state of maturity to the next. These rules are fine-tuned with each release; an example is 5.0.0 Milestones and Milestone Criteria Package Maturity Each package has a maturity level. Maturity level is recorded in the .info file for each major-minor release of OpenACS, and is set to the appropriate value for that release of the package. <version ...> <provides .../> <requires .../> <maturity>1</maturity> <callbacks> ... Level -1: Incompatible. This package is not supported for this platform and should not be expected to work. Level 0: New Submission. This is the default for packages that do not have maturity explicitly set, and for new contributions. The only criterion for level 0 is that at least one person asserts that it works on a given platform. Level 1: Immature. Has no open priority 1 or priority 2 bugs. Has been installed by at least 10? different people, including 1 core developer. Has been available in a stable release for at least 1 month. Has API documentation. Level 2: Mature. Same as Level 1, plus has install guide and user documentation; no serious deviations from general coding practices; no namespace conflicts with existing level 2 packages. Level 3: Mature and Standard. Same as level 2, plus meets published coding standards; is fully internationalized; available on both supported databases. Naming Database Upgrade Scripts Database upgrade scripts must be named very precisely in order for the Package Manager to run the correct script at the correct time. Upgrade scripts should be named /packages/myfirstpackage/sql/postgresql/upgrade/upgrade-OLDVERSION-NEWVERSION.sql If the version you are working on is a later version than the current released version, OLDVERSION should be the current version. The current version is package version in the APM and in /packages/myfirstpackage/myfirstpackage.info. So if forums is at 2.0.1, OLDVERSION should be 2.0.1d1. Note that this means that new version development that includes an upgrade must start at d2, not d1. If you are working on a pre-release version of a package, use the current package version as OLDVERSION. Increment the package version as appropriate (see above) and use the new version as NEWVERSION. For example, if you are working on 2.0.1d3, make it 2.0.1d4 and use upgrade-2.0.1d3-2.0.1d4.sql. Database upgrades should be confined to development releases, not alpha or beta releases. Never use a final release number as a NEWVERSION. If you do, then it is impossible to add any more database upgrades without incrementing the overall package version. Use only the d, a, and b letters in OLDVERSION and NEWVERSION. rc is not supported by OpenACS APM. The distance from OLDVERSION to NEWVERSION should never span a release. For example if we had a bug fix in acs-kernel on 5.1.0 you wouldn't want a file upgrade-5.0.4-5.1.0d1.sql since if you subsequently need to provide a 5.0.4-5.0.5 upgrade you will have to rename the 5.0.4-5.1.0 upgrade since you can't have upgrades which overlap like that. Instead, use upgrade-5.1.0d1-5.1.0d2.sql
    openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/docbook-primer.xml0000644000175000017500000017763711501005400030537 0ustar frankiefrankie %myvars; ]> OpenACS Documentation Guide By Claus Rasmussen, with additions by Roberto Mello, Vinod Kurup, and the OpenACS Community Overview of OpenACS Documentation OpenACS is a powerful system with incredible possibilities and applications, but this power comes with some complexity and a steep learning curve that is only attenuated by good documentation. Our goal is to write superb documentation, so that users, developers and administrators of OpenACS installations can enjoy the system. The history of OpenACS documentation: ..began by building on a good documentation base from ArsDigita's ACS in the late 1990's. Some sections of the documentation, however, lacked details and examples; others simply did not exist. The OpenACS community began meeting the challenge by identifying needs and writing documentation on an as needed basis. By having documentation dependent on volunteers and code developers, documentation updates lagged behind the evolving system software. As significant development changes were made to the system, existing documentation became dated, and its value significantly reduced. The valiant efforts that were made to keep the documentation current proved too difficult as changes to the system sometimes had far-reaching affects to pages throughout the documentation. System integration and optimization quickly rendered documentation obsolete for developers. The code became the substitute and source for documentation. With thousands of lines of code and few developers tracking changes, features and advances to the OpenACS system went unnoticed or were not well understood except by the code authors. Work was duplicated as a consequence of developers not realizing the significant work completed by others. New developers had to learn the system through experience with working with it and discussion in the forums. Informal sharing of experiential and tacit knowledge has become the OpenACS community's main method of sharing knowledge. This document attempts to shape ongoing documentation efforts by using principles of continual improvement to re-engineer documentation production. Managing OpenACS Documentation Documentation production shares many of the challenges of software development, such as managing contributions, revisions and the (editorial) release cycle. This is yet another experiment in improving documentation --this time by using principles of continual improvement to focus the on-going efforts. These processes are outlined as project management phases: Requirements phase is about setting goals and specifications, and includes exploration of scenarios, use cases etc. As an example, see the OpenACS Documentation Requirements Template which focuses on systems requirements for developers. Strategy phase is about creating an approach to doing work. It sets behavioral guidelines and boundaries that help keep perspective on how efforts are directed. OpenACS developers discuss strategy when coordinating efforts such as code revisioning and new features. Planning phase is about explicitly stating the way to implement the strategy as a set of methods. OpenACS system design requires planning. For example, see OpenACS documentation template planning relating to package design. Implementation phase is about performing the work according to the plan, where decisions on how to handle unforseen circumstances are guided by the strategy and requirements. Verification phase measures how well the plan was implemented. Success is measured by A) verifying if the project has met the established goals, and B) reviewing for ongoing problem areas etc. OpenACS follows verification through different means on different projects, but in all cases, the OpenACS community verifies the project as a success through feedback including bug reports, user and administrator comments, and code changes. OpenACS forum discussions on documentation requirements and strategies are summarized in the following sections. Production phases are mainly organized and fulfilled by a designated documentation maintainer. Hopefully the following sections will help spur greater direct participation by the OpenACS community. OpenACS General Documentation Requirements By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003. OpenACS documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here. clarity in presentation. Life with qmail is a recommended example of "rated high" online documentation. Avoid requirements that significantly increase the labor required to maintain documentation. Use best practices learned from the print world, web, and other media, about use of gamma, space, writing style etc. Consistency in publishing -Establishing and adhering to publishing standards Use standardized language -Use international English (without slang or colloquial terms) for ESL (English as a second language) readers (and making translation easier for those interested in translating the documentation for internationalization efforts). All jargon used in documentation needs to be defined. Use standardized terms when available, avoiding implicit understanding of specific OpenACS terms. Document titles (for example on html pages) should include whole document title (as in book title): (chapter title) : (section), so that bookmarks etc. indicate location in a manner similar to pages in books (in print publishing world). Organize document according to the needs of the reader (which may be different than the wishes of the writers). Do not make informal exclamations about difficulty/ease for users to complete tasks or understand... for example, "Simply...". Readers come from many different backgrounds --remember that the greater audience is likely as varied as the readers on the internet--- If important, state pre-conditions or knowledge requirements etc. if different than the rest of the context of the document. For example, "requires basic competency with a text-based editor such as vi or emacs via telnet" Show where to find current information instead of writing about current info that becomes obsolete. If the information is not found elsewhere, then create one place for it, where others can refer to it. This structure of information will significantly reduce obsolescence in writing and labor burden to maintain up-to-date documentation. In other words, state facts in appropriately focused, designated areas only, then refer to them by reference (with links). Note: Sometimes facts should be stated multiple ways, to accommodate different reading style preferences. The should still be in 1 area, using a common layout of perhaps summary, introduction and discussion requiring increasing expertise, complexity or specificity. Consistency in link descriptions -When link urls refer to whole documents, make the link (anchor wrapped title) that points to a document with the same title and/or heading of the document. Consider OpenACS documentation as a set of books (an encyclopedic set organized like an atlas) that contains volumes (books). Each book contains chapters and sections much like how DocBook examples are shown, where each chapter is a web page. This designation could help create an OpenACs book in print, and help new readers visualize how the documentation is organized. The use licenses between OpenACS and Arsdigita's ACS are not compatible, thereby creating strict limits on how much OpenACS developers should have access to Arsdigita code and resources. The OpenACS documentation has a new legal requirement: to eliminate any dependency on learning about the system from Arsdigita ACS examples to minimize any inference of license noncompliance, while recognizing the important work accomplished by Philip Greenspun, Arsdigita, and the early ACS adopters. Use a consistent general outline for each book. Introduction (includes purpose/goal), Glossary of terms, Credits, License, Copyright, Revision History Table of Contents (TOC)s for each book: the end-users, content and site administrators, marketing, developer tutorial, and developers. Priorities of order and content vary based on each of the different readers mentioned. The developers guide should be organized to be most useful to the priorities of developers, while being consistent with the general documentation requirements including publishing strategy, style etc. Use generic DocBook syntax to maximize reader familiarity with the documents. <book><title><part label="Part 1"><etc...> OpenACS Documentation Requirements for End-users By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003. OpenACS end-user documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here. End-users should not have to read docs to use the system. Include how to get help. How and where to find answers, contact others, what to do if one gets an AOLserver or other error when using the system. Include types of available support (open-source, private commercial etc.) including references. Explain/foster understanding of the overall structure of the system. This would be an overview of the system components, how it works, and how to find out more or dig deeper... To promote the system by presenting the history of the system, and writing about some tacit knowledge re: OpenACS.org and the opensource culture. Introduce and inspire readers about the uses, benefits, and the possibilities this system brings (think customer solution, customer cost, convenience, value). A comprehensive community communications system; How this system is valuable to users; Reasons others use OpenACS (with quotes in their own words) "...the most important thing that the ACS does is manage users, i.e. provide a way to group, view and manipulate members of the web community. -- Talli Somekh, September 19, 2001" using it to communicate, cooperate, collaborate... OpenACS offers directed content functionality with the OpenACS templating system. ... OpenACS is more than a data collection and presentation tool. OpenACS has management facilities that are absent in other portals. ...The beauty of OpenACS is the simplicity (and scalability) of the platform on which it is built and the library of tried and tested community building tools that are waiting to be added. It seems that most portals just add another layer of complexity to the cake. See Slides on OACS features...a set of slides on OACS features that can be used for beginners who want to know OACS is about and what they can do with it. Screen captures that highlight features. Example shows BBoard, calendar, news, file storage, wimpy point, ticket tracking. An OpenACS tour; an abbreviated, interactive set of demo pages. From a marketing perspective, differentiate "product" by highlighting features, performance quality, conformance to standards, durability (handling of technological obsolescence), reliability, repairability, style of use, design (strategy in design, specifications, integrated, well-matched systems etc). differentiate "service" by highlighting software availability (licensing and completeness from mature to early adopters or development versions), community incident support, project collaborative opportunities, and contractor support availability differentiate price (economic considerations of opensource and features) Discussion and details should rely on meeting criteria of design, completeness of implementation, and related system strengths and weaknesses. Marketing should not rely on comparing to other technologies. Competitive analysis involves mapping out strengths, weaknesses, opportunities and threats when compared to other systems for a specific purpose, and thus is inappropriate (and becomes stale quickly) for general documentation. When identifying subsystems, such as tcl, include links to their marketing material if available. create an example/template comparison table that shows versions of OpenACS and other systems (commonly competing against OpenACS) versus a summary feature list and how well each meets the feature criteria. Each system should be marked with a date to indicate time information was gathered, since information is likely volatile. To build awareness about OpenACS, consider product differentiation: form, features, performance quality, conformance quality (to standards and requirements), durability, reliability, repairability, style, design: the deliberate planning of these product attributes. Include jargon definitions, glossary, FAQs, site map/index, including where to find Instructions for using the packages. FAQ should refer like answers to the same place for consistency, brevity and maintainability. Explain/tutorial on how the UI works (links do more than go to places, they are active), Page flow, descriptions of form elements; browser/interface strengths and limitations (cookies, other) Discuss criteria used to decide which features are important, and the quality of the implementation from a users perspective. Each project implementation places a different emphasis on the various criteria, which is why providing a framework to help decide is probably more useful than an actual comparison. Package documentation requirements have additional requirements. A list of all packages, their names, their purposes, what they can and cannot do (strengths, limitations), what differentiates them from similar packages, minimal description, current version, implementation status, author/maintainers, link(s) to more info. Current version available at the repository. Include dependencies/requirements, known conflicts, and comments from the real world edited into a longer description to quickly learn if a package is appropriate for specific projects. Create a long bulleted list of features. Feature list should go deeper than high-level feature lists and look at the quality of the implementations (from the user's perspective, not the programmer's). Example issues an end-user may have questions about: Ticket Tracker and Ticket Tracker Lite, why would I want one of them vs the other? And, before I specify to download and install it, what credit card gateways are supported by the current e-commerce module? There are some packages where the name is clear enough, but what are the limitations of the standard package? End-user docs should not be duplicative. The package description information and almost everything about a package for administrators and developers is already described in the package itself through two basic development document templates: a Requirements Template and Detailed Design Document. OpenACS Documentation Requirements for Site and Administrators By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003. OpenACS administrators' documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here. For each requirement below, include links to developer tutorials and other documentation for more detail. Describe a structural overview of a working system and how the components work together. "The Layered Cake view" a general network view of system; a table showing system levels versus roles to help with understanding how the subsystems are interconnected. Provide a comprehensive description of typical administrative processes for operating an OpenACS system responsibly, including reading logs and command line views that describe status of various active processes. Create a list of administrative tools that are useful to administrating OpenACS, including developer support, schema-browser and api browser. Link to AOLserver's config file documentation. Resources on high level subjects such as web services, security guidelines Describe typical skill sets (and perhaps mapped to standardized job titles) for administrating an OpenACS system (human-resources style). For a subsite admin/moderator attributes might include trustworthy, sociable, familiarity with the applications and subsystems, work/group communication skills et cetera Describe how to set up typical site moderation and administration including parameters, permissions, "Hello World" page Show directory structure of a typical package, explanation of the various file types in a package (tcl,adp,xql) and how those relate to the previously described subsystems, when they get refreshed etc. Ways to build a "Hello World" page Show examples of how the OpenACS templating system is used, including portal sections of pages. For example, create a customised auto-refreshing startpage using lars-blogger, a photo gallery, and latest posts from a forum. This should rely heavily on documentation existing elsewhere to keep current. This would essentially be a heavily annotated list of links. Show ways of modifying the look and feel across pages of an OpenACS website. Refer to the skins package tutorial. Describe a methodology for diagnosing problems, finding error statements and interpreting them --for OpenACS and the underlying processes. FAQs: Administration tasks commonly discussed on boards: admin page flow, how to change the looks of a subsite with a new master.adp, options on "user pages" , a quick introduction to the functions and processes. info about the user variables, file locations OpenACS Installation Documentation Requirements By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003. OpenACS installation documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here. state installation prerequisites. For example: "You should read through the installation process to familiarize yourself with the installation process, before beginning an installation." list critical decisions (perhaps as questions) that need to be made before starting: which OS, which DB, which aolserver version, system name, dependencies et cetera. Maybe summarize options as tables or decision-trees. For example, "As you proceed throughout the installation, you will be acting on decisions that have an impact on how the remaining part of the system is installed. Here is a list of questions you should answer before beginning." list pre-installation assumptions Show chronological overview of the process of installing a system to full working status: Install operating system with supporting software, configure with preparations for OpenACS, RDBMS(s) install and configure, Webserver install and configure, OpenACS install and configure, post-install work OpenACS Developer Tutorial Documentation Requirements By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003. OpenACS developer tutorial documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here. list learning prerequisites to customize, fix, and improve OACS modules, and create new ones. You are expected to have read and understand the information [minimum requirements similar to adept at Using OpenACS Administrating Guide] before reading this guide. Refer to development documentation instead of duplicating here List suggestions for installing and setting up a development environment; these can be annotated links to the installation documentation Provide working examples that highlight the various subsystems, tcl environment, OpenACS protocols, aolserver template and ns_* commands, OpenACS templating, sql queries, db triggers, scheduling protocols, how to use the page contract, how to get the accessing user_id etc Show how to construct basic SQL queries using the db API, The life of an http request to a dynamic, templated page General rules to follow for stability, scalability Show the step by step customizing of an existing package that meets current recommended coding styles of OpenACS package development, by referring to developer resources. Use the ArsDigita problem sets and "what Lars produced for ACS Java" as inspiration for a PostgreSQL equivalent tutorial about developing a new OpenACS package including discussion of the significance of the package documentation templates Include a summary of important links used by developers Note any deprecated tools and methods by linking to prior versions instead of describing them in current docs OpenACS Developer Documentation Requirements By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003. OpenACS developer documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here. list documentation assumptions, such as familiarity with modifying OpenACS packages. All kernel docs are here etc. This documentation should be written for ongoing use by developers, not as a tutorial. List of practical development and diagnostics tools and methodologies. List of OpenACS development resources, api-doc, schema-browser, developer-support package etc. Identify each OpenACS subsystem, explain why it is used (instead of other choices). In the case of subsystems that are developed outside of OpenACS such as tcl, include external references to development and reference areas. Show current engineering standards and indicate where changes to the standards are in the works. Sections should be dedicated to DotLRN standards as well, if they are not available elsewhere. Add overview diagrams showing the core parts of the datamodel including an updated summary of Greenspun's Chapter 4: Data Models and the Object System package design guidelines and development process templates including planning, core functions, testing, usability, and creating case studies Standard package conventions, where to see "model" code, and guidelines (or where to find them) for: programming tcl/sql using the acs-api ad_form coding permissions OpenACS objects scheduled protocols call backs directory structure user interface widgets package_name and type_extension_table adding optional services, including search, general comments, attachments, notifications, workflow, CR and the new CR Tcl API Document kernel coding requirements, strategy and guidelines to help code changers make decisions that meet kernel designers' criteria OpenACS Documentation Strategy OpenACS documentation development is subject to the constraints of the software project development and release methods and cycles (). Essentially, all phases of work may be active to accommodate the asynchronous nature of multiple subprojects evolving by the efforts of a global base of participants with culturally diverse time references and scheduling idiosyncrasies. The documentation strategy is to use project methods to involve others by collaborating or obtaining guidance or feedback (peer review) to distribute the workload and increase the overall value of output for the OpenACS project. OpenACS Documentation Strategy: Why DocBook? OpenACS documentation is taking a dual approach to publishing. Documentation that is subject to rapid change and participation by the OpenACS community is managed through the OpenACS xowiki Documentation Project Formal documents that tend to remain static and require more expressive publishing tools will be marked up to conform to the DocBook XML DTD. The remaining discussion is about publishing using Docbook. DocBookDTD is a publishing standard based on XML with similar goals to the OpenACS Documentation project. Some specific reasons why we are using DocBook: It is open-source. A growing community surrounds DocBook (has mailing lists) A number of free and commercial tools are available for editing and publishing DocBook documents. It enables us to publish in a variety of formats. XML separates content from presentation: It relieves each contributor of the burden of presentation, freeing each writer to focus on content and sharing knowledge. It is well tested technology. It has been in development since the early 1990's). Reasons why we are using Docbook XML instead of Docbook SGML: Consistency and history. We started with a collection of DocBook XML files that ArsDigita wrote. Trying to re-write them to conform to the SGML DTD would be unnecessary work. XML does not require extra effort. Writing in XML is almost identical to SGML, with a couple extra rules. More details in the LDP Author Guide. The tool chain has matured. xsltproc and other XML based tools have improved to the point where they are about as good as the SGML tools. Both can output html and pdf formats. Albeit, the road to using DocBook has had some trials. In 2002, Docbook still was not fully capable of representing online books as practiced by book publishers and expected from readers with regards to usability on the web. That meant DocBook did not entirely meet OpenACS publishing requirements at that time. In 2004, Docbook released version 4.4, which complies with all the OpenACS publishing requirements. Producing a web friendly book hierarchy arguably remains DocBooks' weakest point. For example, a dynamically built document should be able to extract details of a specific reference from a bibliographic (table) and present a footnote at the point where referenced. DocBook 4.4 allows for this with bibliocoverage, bibliorelation, and bibliosource. DocBook: The Definitive Guide is a good start for learning how to represent paper-based books online. The following DocBook primer walks you through the basics, and should cover the needs for 95 percent of the documentation we produce. You are welcome to explore DocBook's list of elements and use more exotic features in your documents. The list is made up of SGML-elements but basically the same elements are valid in the XML DTD as long as you remember to: XML guidelines Always close your tags with corresponding end-tags and to not use other tag minimization Write all elements and attributes in lowercase Quote all attributes Tools You are going to need the following to work with the OpenACS Docbook XML documentation: Docbook XML DTD - The document type definition for XML. You can find an RPM or DEB package or you can download a zip file from the site linked from here. XSL Stylesheets (docbook-xsl) - The stylesheets to convert to HTML. We have been using a stylesheet based upon NWalsh's chunk.xsl. xsltproc - The processor that will take an XML document and, given a xsl stylesheet, convert it to HTML. It needs libxml2 and libxslt (available in RPM and DEB formats or from xmlsoft.org. Some editing tool. A popular one is Emacs with the psgml and nXML modes. The LDP Author Guide and DocBook Wiki list some alternates. Writing New Docs After you have the tools mentioned above, you need to define a title for your document. Then start thinking about the possible sections and subsections you will have in your document. Make sure you coordinate with the OpenACS Gatekeepers to make sure you are not writing something that someone else is already writing. Also, if you desire to use the OpenACS CVS repository, please e-mail the gatekeeper in charge of documentation. You can look at some templates for documents (in Docbook XML) in the sources for acs-core-docs, especially the Detailed Design Documentation Template and the System/Application Requirements Template. Document Structure The documentation for each package will make up a little "book" that is structured like this - examples are emphasized: Document structure book : Docs for one package - templating | +--chapter : One section - for developers | ---------+------------------------------------------------------ | +--sect1 : Single document - requirements | +--sect2 : Sections - functional requirements | +--sect3 : Subsections - Programmer's API | ... : ... The actual content is split up into documents that start at a sect1-level. These are then tied together in a top-level document that contains all the information above the line. This will be explained in more detail in a later document, and we will provide a set of templates for documenting an entire package. For now you can take a look at the sources of these DocBook documents to get an idea of how they are tied together. Headlines, Sections SectionsHeadlines Given that your job starts at the sect1-level, all your documents should open with a <sect1>-tag and end with the corresponding </sect1>. sect1 You need to feed every <sect1> two attributes. The first attribute, id, is standard and can be used with all elements. It comes in very handy when interlinking between documents (more about this when talking about links in ). The value of id has to be unique throughout the book you're making since the id's in your sect1's will turn into filenames when the book is parsed into HTML. xreflabel The other attribute is xreflabel. The value of this is the text that will appear as the link when referring to this sect1. Right after the opening tag you put the title of the document - this is usually the same as xreflabel-attribute. E.g. the top level of the document you're reading right now looks like this: <sect1 id="docbook-primer" xreflabel="DocBook Primer"> <title>DocBook Primer</title> ... </sect1> sect2 Inside this container your document will be split up into <sect2>'s, each with the same requirements - id and xreflabel attributes, and a <title>-tag inside. Actually, the xreflabel is never required in sections, but it makes linking to that section a lot easier. When it comes to naming your sect2's and below, prefix them with some abbreviation of the id in the sect1 such as requirements-overview. Code computeroutputcode For displaying a snippet of code, a filename or anything else you just want to appear as a part of a sentence, we use <computeroutput> and <code> tags. These replace the HTML-tag <code> tag, depending on whether the tag is describing computer output or computer code. For bigger chunks of code such as SQL-blocks, the tag <programlisting> is used. Just wrap your code block in it; mono-spacing, indents and all that stuff is taken care of automatically. For expressing user interaction via a terminal window, we wrap the <screen> tag around text that has been wrapped by combinations of <computeroutput> and <userinput> Links Linking Linking falls into two different categories: inside the book you're making and outside: 1. Inside linking, cross-referencing other parts of your book By having unique id's you can cross-reference any part of your book with a simple tag, regardless of where that part is. xreflinkendCheck out how I link to a subsection of the Developer's Guide: Put this in your XML: - Find information about creating a package in <xref linkend="packages-making-a-package"></xref>. And the output is: - Find information about creating a package in . Note that even though this is an empty tag, you have to either: Provide the end-tag, </xref>, or Put a slash before the ending-bracket: <xref linkend="blahblah"/> If the section you link to hasn't a specified xreflabel-attribute, the link is going to look like this: Put this in your XML: -Find information about what a package looks like in <xref linkend="packages-looks"></xref>. And the output is: - Find information about what a package looks like in . Note that since I haven't provided an xreflabel for the subsection, packages-looks, the parser will try its best to explain where the link takes you. 2. Linking outside the documentation ulink If you're hyper-linking out of the documentation, it works almost the same way as HTML - the tag is just a little different (<ulink>): <ulink url="http://www.oracle.com/">Oracle Corporation</ulink> ....will create a hyper-link to Oracle in the HTML-version of the documentation. NOTE: Do NOT use ampersands in your hyperlinks. These are reserved for referencing entities. To create an ampersand, use the entity &amp; Graphics Note: The graphics guidelines are not written in stone. Use another valid approach if it works better for you. GraphicsImages To insert a graphic we use the elements <mediaobject>, <imageobject>, <imagedata>, and <textobject>. Two versions of all graphics are required. One for the Web (usually a JPEG or GIF), and a brief text description. The description becomes the ALT text. You can also supply a version for print (EPS). <mediaobject> <imageobject> <imagedata fileref="images/rp-flow.gif" format="GIF" align="center"/> </imageobject> <imageobject> <imagedata fileref="images/rp-flow.eps" format="EPS" align="center"/> </imageobject> <textobject> <phrase>This is an image of the flow in the Request Processor</phrase> </textobject> </mediaobject> Put your graphics in a separate directory ("images") and link to them only with relative paths. Lists lists Here's how you make the DocBook equivalent of the three usual HTML-lists: 1. How to make an <ul> Making an unordered list is pretty much like doing the same thing in HTML - if you close your <li>, that is. The only differences are that each list item has to be wrapped in something more, such as <para>, and that the tags are called <itemizedlist> and <listitem>: <itemizedlist> <listitem><para>Stuff goes here</para></listitem> <listitem><para>More stuff goes here</para></listitem> </itemizedlist> 2. How to make an <ol> The ordered list is like the preceding, except that you use <orderedlist> instead: <orderedlist> <listitem><para>Stuff goes here</para></listitem> <listitem><para>More stuff goes here</para></listitem> </orderedlist> 3. How to make a <dl> This kind of list is called a variablelist and these are the tags you'll need to make it happen: <variablelist>, <varlistentry>, <term> and <listitem>: <variablelist> <varlistentry> <term>Heading (<dt>) goes here</term> <listitem><para>And stuff (<dd>)goes here</para></listitem> </varlistentry> <varlistentry> <term>Another heading goes here</term> <listitem><para>And more stuff goes here</para></listitem> </varlistentry> </variablelist> Tables informaltabletable DocBook supports several types of tables, but in most cases, the <informaltable> is enough: <informaltable frame="all"> <tgroup cols="3"> <tbody> <row> <entry>a1</entry> <entry>b1</entry> <entry>c1</entry> </row> <row> <entry>a2</entry> <entry>b2</entry> <entry>c2</entry> </row> <row> <entry>a3</entry> <entry>b3</entry> <entry>c3</entry> </row> </tbody> </tgroup> </informaltable> With our current XSL-style-sheet, the output of the markup above will be a simple HTML-table: a1 b1 c1 a2 b2 c2 a3 b3 c3 If you want cells to span more than one row or column, it gets a bit more complicated - check out <table> for an example. Emphasis emphasisbold, italics Our documentation uses two flavors of emphasis - italics and bold type. DocBook uses one - <emphasis>. The <emphasis> tag defaults to italics when parsed. If you're looking for emphasizing with bold type, use <emphasis role="strong">. Indexing Your DocBook Documents Words that are marked as index-words are referenced in an index in the final, parsed document. Use <indexterm>, <primary> and <secondary> for this. See these links for an explanation. Converting to HTML This section is quoted almost verbatim from the LDP Author Guide. Once you have the installed, you can convert your xml documents to HTML or other formats. With the DocBook XSL stylesheets, generation of multiple files is controlled by the stylesheet. If you want to generate a single file, you call one stylesheet. If you want to generate multiple files, you call a different stylesheet. To generate a single HTML file from your DocBook XML file, use the command: bash$ xsltproc -o outputfilename.xml /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/html/html.xsl filename.xml This example uses Daniel Veillard's xsltproc command available as part of libxslt from http://www.xmlsoft.org/XSLT/. If you are using other XML processors such as Xalan or Saxon, you will need to change the command line appropriately. To generate a set of linked HTML pages, with a separate page for each <chapter>, <sect1> or <appendix> tag, use the following command: bash$ xsltproc /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/html/chunk.xsl filename.xml You could also look at the acs-core-docs Makefile for examples of how these documents are generated. Further Reading Using Xinclude The LDP Author Guide has a lot of good information, a table of docbook elements and their "look" in HTML and lots of good links for tools. James Clark wrote nXML Mode, an alternative to PSGML Mode. nXML Mode can validate a file as it is edited. David Lutterkort wrote an intro to the PSGML Mode in Emacs James Clark's free Java parser XP. Note that this does not validate XML, only parses it. DocBook Tool for Linux: Converts docbook documents to a number of formats. NOTE: I only got these to work with Docbook SGML, NOT with Docbook XML. If you are able to make it work with our XML, please let us know. AptConvert from PIXware is a Java editor that will produce DocBook documents and let you transform them into HTML and PDF for a local preview before you submit. In the process of transforming your HTML into XML, HTML tidy can be a handy tool to make your HTML "regexp'able". Brandoch Calef has made a Perl script with directions (now via archive.org) that gets you most of the way. openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/design-template.xml0000644000175000017500000003351410456621135030707 0ustar frankiefrankie %myvars; ]> Detailed Design Documentation Template By You Start Note NOTE: Some of the sections of this template may not apply to your package, e.g. there may be no user-visible UI elements for a component of the OpenACS Core. Furthermore, it may be easier in some circumstances to join certain sections together, e.g. it may make sense to discuss the data model and transactions API together instead of putting them in separate sections. And on occasion, you may find it easier to structure the design discussion by the structure used in the requirements document. As this template is just a starting point, use your own judgment, consult with peers when possible, and adapt intelligently. Also, bear in mind the audience for detailed design: fellow programmers who want to maintain/extend the software, AND parties interested in evaluating software quality. Essentials When applicable, each of the following items should receive its own link: User directory OpenACS administrator directory Subsite administrator directory Tcl script directory (link to the API browser page for the package) PL/SQL file (link to the API browser page for the package) Data model Requirements document ER diagram Transaction flow diagram Introduction This section should provide an overview of the package and address at least the following issues: What this package is intended to allow the user (or different classes of users) to accomplish. Within reasonable bounds, what this package is not intended to allow users to accomplish. The application domains where this package is most likely to be of use. A high-level overview of how the package meets its requirements (which should have been documented elsewhere). This is to include relevant material from the "features" section of the cover sheet (the cover sheet is a wrapper doc with links to all other package docs). Also worthy of treatment in this section: When applicable, a careful demarcation between the functionality of this package and others which - at least superficially - appear to address the same requirements. Note: it's entirely possible that a discussion of what a package is not intended to do differs from a discussion of future improvements for the package. Historical Considerations For a given set of requirements, typically many possible implementations and solutions exist. Although eventually only one solution is implemented, a discussion of the alternative solutions canvassed - noting why they were rejected - proves helpful to both current and future developers. All readers would be reminded as to why and how the particular solution developed over time, avoiding re-analysis of problems already solved. Competitive Analysis Although currently only a few package documentation pages contain a discussion of competing software, (e.g. chat, portals), this section should be present whenever such competition exists. If your package exhibits features missing from competing software, this fact should be underscored. If your package lacks features which are present in competing software, the reasons for this should be discussed here; our sales team needs to be ready for inquiries regarding features our software lacks. Note that such a discussion may differ from a discussion of a package's potential future improvements. Design Tradeoffs No single design solution can optimize every desirable software attribute. For example, an increase in the security of a system will likely entail a decrease in its ease-of-use, and an increase in the flexibility/generality of a system typically entails a decrease in the simplicity and efficiency of that system. Thus a developer must decide to put a higher value on some attributes over others: this section should include a discussion of the tradeoffs involved with the design chosen, and the reasons for your choices. Some areas of importance to keep in mind are: Areas of interest to users: Performance: availability and efficiency Flexibility Interoperability Reliability and robustness Usability Areas of interest to developers: Maintainability Portability Reusability Testability API Here's where you discuss the abstractions used by your package, such as the procedures encapsulating the legal transactions on the data model. Explain the organization of procedures and their particulars (detail above and beyond what is documented in the code), including: Problem-domain components: key algorithms, e.g. a specialized statistics package would implement specific mathematical procedures. User-interface components: e.g. HTML widgets that the package may need. Data management components: procedures that provide a stable interface to database objects and legal transactions - the latter often correspond to tasks. Remember that the correctness, completeness, and stability of the API and interface are what experienced members of our audience are looking for. This is a cultural shift for us at aD (as of mid-year 2000), in that we've previously always looked at the data models as key, and seldom spent much effort on the API (e.g. putting raw SQL in pages to handle transactions, instead of encapsulating them via procedures). Experience has taught us that we need to focus on the API for maintainability of our systems in the face of constant change. Data Model Discussion The data model discussion should do more than merely display the SQL code, since this information is already be available via a link in the "essentials" section above. Instead, there should be a high-level discussion of how your data model meets your solution requirements: why the database entities were defined as they are, and what transactions you expect to occur. (There may be some overlap with the API section.) Here are some starting points: The data model discussion should address the intended usage of each entity (table, trigger, view, procedure, etc.) when this information is not obvious from an inspection of the data model itself. If a core service or other subsystem is being used (e.g., the new parties and groups, permissions, etc.) this should also be mentioned. Any default permissions should be identified herein. Discuss any data model extensions which tie into other packages. Transactions Discuss modifications which the database may undergo from your package. Consider grouping legal transactions according to the invoking user class, i.e. transactions by an OpenACS-admin, by subsite-admin, by a user, by a developer, etc. User Interface In this section, discuss user interface issues and pages to be built; you can organize by the expected classes of users. These may include: Developers OpenACS administrators (previously known as site-wide administrators) Subsite administrators End users You may want to include page mockups, site-maps, or other visual aids. Ideally this section is informed by some prototyping you've done, to establish the package's usability with the client and other interested parties. Note: In order that developer documentation be uniform across different system documents, these users should herein be designated as "the developer," "the OpenACS-admin," "the sub-admin," and "the user," respectively. Finally, note that as our templating system becomes more entrenched within the OpenACS, this section's details are likely to shift from UI specifics to template interface specifics. Configuration/Parameters Under OpenACS &version;, parameters are set at two levels: at the global level by the OpenACS-admin, and at the subsite level by a sub-admin. In this section, list and discuss both levels of parameters. Future Improvements/Areas of Likely Change If the system presently lacks useful/desirable features, note details here. You could also comment on non-functional improvements to the package, such as usability. Note that a careful treatment of the earlier "competitive analysis" section can greatly facilitate the documenting of this section. Authors Although a system's data model file often contains this information, this isn't always the case. Furthermore, data model files often undergo substantial revision, making it difficult to track down the system creator. An additional complication: package documentation may be authored by people not directly involved in coding. Thus to avoid unnecessary confusion, include email links to the following roles as they may apply: System creator System owner Documentation author Revision History The revision history table below is for this template - modify it as needed for your actual design document. Document Revision # Action Taken, Notes When? By Whom? 0.3 Edited further, incorporated feedback from Michael Yoon 9/05/2000 Kai Wu 0.2 Edited 8/22/2000 Kai Wu 0.1 Creation 8/21/2000 Josh Finkler, Audrey McLoghlin ($Id: design-template.xml,v 1.8 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/nxml-mode.xml0000644000175000017500000000222310456621135027516 0ustar frankiefrankie %myvars; ]> Using nXML mode in Emacs By Jeff Davis An alternative to psgml mode is nXML by James Clark, a new major mode for GNU Emacs for editing XML, and which features highlighting, indentation, and on the fly validation versus a RelaxNG Schema. An introduction to nXML mode at xmlhack.com. The nXML mode mail list at groups.yahoo.com. The nXML download page at thaiopensource.com. openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/filenaming.xml0000644000175000017500000003436110456621135027737 0ustar frankiefrankie %myvars; ]> ACS File Naming and Formatting Standards By Michael Yoon and Aurelius Prochazka To ensure consistency (and its collateral benefit, maintainability), we define and adhere to standards in the following areas: File Nomenclature Usually we organize our files so that they mainly serve one of the following three purposes: displaying objects and their properties manipulating or acting on objects in some way (by creating, editing, linking, etc) housing procedures, packages, data models and other prerequisite code Essentially, we want our files named in a fashion that reflects their purpose. Under the page root (and the template root if using the Style package): For naming files that enable a specific action on an object, use this format:
    object-verb.extension
    For example, the page to erase a user's portrait from the database is /admin/users/portrait-erase.tcl.
    However, modules typically deal with only one primary type of object - e.g., the Bookmarks module deals mainly with bookmarks - and so action-type files in modules don't need to be specified by the object they act on. Example: the user pages for the Bookmarks module live in the /bookmarks/ directory, and so there is no need to name the bookmark editing page with a redundant url: /bookmarks/bookmark-edit.tcl. Instead, we omit the object type, and use this convention:
    verb.extension
    Thus, the page to edit a bookmark is /bookmarks/edit.tcl.
    For naming files that display the properties of a primary object - such as the bookmark object within the bookmark module - use this convention:
    one.extension
    For example, the page to view one bookmark is /bookmarks/one.tcl. Note that no verb is necessary for display-type files.
    Otherwise, if the object to be displayed is not the primary feature of a module, simply omit the verb and use the object name:
    object.extension
    For example, the page to view the properties of an ecommerce product is /ecommerce/product.tcl.
    For naming files in a page flow, use the convention: foobar.extension (Step 1) foobar-2.extension (Step 2) ... foobar-N.extension (Step N) where foobar is determined by the above rules. Typically, we use a three-step page flow when taking user information: Present a form to the user Present a confirmation page to the user Perform the database transaction, then redirect Put data model files in /www/doc/sql, and name them for the modules towards which they are used:
    module.sql
    In the Tcl library directory: For files that contain module-specific procedures, use the convention:
    module-procs.tcl
    For files that contain procedures that are part of the core ACS, use the convention:
    ad-description-procs.tcl
    URLs File names also appear within pages, as linked URLs and form targets. When they do, always use abstract URLs (e.g., user-delete instead of user-delete.tcl), because they enhance maintainability. Similarly, when linking to the index page of a directory, do not explicitly name the index file (index.tcl, index.adp, index.html, etc.). Instead, use just the directory name, for both relative links (subdir/) and absolute links (/top-level-dir/). If linking to the directory in which the page is located, use the empty string (""), which browsers will resolve correctly. File Headers and Page Input Include the appropriate standard header in all scripts. The first line should be a comment specifying the file path relative to the ACS root directory. e.g.
    # /www/index.tcl
    or
    # /tcl/module-defs.tcl
    For static content files (html or adp), include a CVS identification tag as a comment at the top of the file, e.g. <!-- file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp --> In addition, all static HTML files, documentation and other pages should have a visible CVS ID stamp, at least during development. These can be removed at release times. This should take the form of a line like this: <p> Last Modified: file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp </p> This can be at the top or bottom of the file. Using ad_page_contract For non-library Tcl files (those not in the private Tcl directory), use ad_page_contract after the file path comment (this supersedes set_the_usual_form_variables and ad_return_complaint). Here is an example of using ad_page_contract, which serves both documentation and page input validation purposes: # www/register/user-login-2.tcl ad_page_contract { Verify the user's password and issue the cookie. @param user_id The user's id in users table. @param password_from_from The password the user entered. @param return_url What url to return to after successful login. @param persistent_cookie_p Specifies whether a cookie should be set to keep the user logged in forever. @author John Doe (jdoe@example.com) @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp } { user_id:integer,notnull password_from_form:notnull {return_url {[ad_pvt_home]}} {persistent_cookie_p f} } Salient features of ad_page_contract: A mandatory documentation string is the first argument. This has the standard form with javadoc-style @author, @cvs-id, etc, and should contain a short description of the recieved variables and any necessary explanations. The second argument specifies the page inputs. The syntax for switches/flags (e.g. multiple-list, array, etc.) uses a colon (:) followed by any number of flags separated by commas (,), e.g. foo:integer,multiple,trim. In particular, multiple and array are the flags that correspond to the old ad_page_variables flags. There are new flags: trim, notnull and optional. They do what you'd expect; values will not be trimmed, unless you mark them for it; empty strings are valid input, unless you specify notnull; and a specified variable will be considered required, unless you declare it optional. ad_page_contract can do validation for you: the flags integer and sql_identifier will make sure that the values supplied are integers/sql_identifiers. The integer flag will also trim leading zeros. Note that unless you specify notnull, both will accept the empty string. Note that ad_page_contract does not generate QQvariables, which were automatically created by ad_page_variables and set_the_usual_form_variables. The use of bind variables makes such previous variable syntax obsolete. Using ad_library For shared Tcl library files, use ad_library after the file path comment. Its only argument is a doc_string in the standard (javadoc-style) format, like ad_page_contract. Don't forget to put the @cvs-id in there. Here is an example of using ad_library: # tcl/wp-defs.tcl ad_library { Provides helper routines for the Wimpy Point module. @author John Doe (jdoe@example.com) @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp } Non-Tcl Files For SQL and other non-Tcl source files, the following file header structure is recommended: -- path relative to the ACS root directory -- -- brief description of the file's purpose -- -- author -- created -- -- $Id$ Of course, replace "--" with the comment delimiter appropriate for the language in which you are programming.
    Page Construction Construct the page as one Tcl variable (name it page_content), and then send it back to the browser with one call to doc_return, which will call db_release_unused_handles prior to executing ns_return, effectively combining the two operations. For example: set page_content "[ad_header "Page Title"] <h2>Page Title</h2> <hr> <ul> " db_foreach get_row_info { select row_information from bar } { append page_content "<li>row_information\n" } append page_content "</ul> [ad_footer]" doc_return 200 text/html $page_content The old convention was to call ReturnHeaders and then ns_write for each distinct chunk of the page. This approach has the disadvantage of tying up a scarce and valuable resource (namely, a database handle) for an unpredictable amount of time while sending packets back to the browser, and so it should be avoided in most cases. (On the other hand, for a page that requires an expensive database query, it's better to call ad_return_top_of_page first, so that the user is not left to stare at an empty page while the query is running.) Local procedures (i.e., procedures defined and used only within one page) should be prefixed with "module_" and should be used rarely, only when they are exceedingly useful. All files that prepare HTML to display should end with [ad_footer] or [module_footer]. If your module requires its own footer, this footer should call ad_footer within it. Why? Because when we adapt the ACS to a new site, it is often the case that the client will want a much fancier display than the ACS standard. We like to be able to edit ad_header (which quite possibly can start a <table>) and ad_footer (which may need to end the table started in ad_footer) to customize the look and feel of the entire site. Tcl Library Files Further standards for Tcl library files are under discussion; we plan to include naming conventions for procs. ($Id: filenaming.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $)
    openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/plsql.xml0000644000175000017500000001727510456621135026766 0ustar frankiefrankie %myvars; ]> PL/SQL Standards By Richard Li and Yon Feldman Like any other part of the OpenACS, PL/SQL (or pl/pgsql) code must be maintainable and professional. This means that it must be consistent and therefore must abide by certain standards. The standards will ensure that our product will be useful long after the current people building and maintaining it are around. Following are some standards and guidelines that will help us achieve this goal: General All PL/SQL code must be well documented. We must write code that is maintainable by others, this is especially true in our case because we are building an open source toolkit than anyone can download and browse the source code. So document like you are trying to impress your "Introduction to Programming" professor or TA. It is important to be consistent throughout an application as much as is possible given the nature of team development. This means carrying style and other conventions suchs as naming within an application, not just within one file. Code Encapsulation of related fuctionality is key to maintainability and upgradeability of our software. Try to bundle your code into packages whenever possible. This will make upgrading, bug fixing, and customizing, among other things, a possibility. When creating functions or procedures use the following template, it demonstrates most of the guidelines set forth in this document that correspond to functions and procedures: create or replace procedure|function <proc_or_func_name> ( <param_1> in|out|inout <datatype>, <param_2> in|out|inout <datatype>, ... <param_n> in|out|inout <datatype> ) [return <datatype>] is <local_var_1> <datatype> <local_var_2> <datatype> ... <local_var_n> <datatype> begin ... end <proc_or_func_name>; / show errors Always use create or replace procedure|function <proc_or_func_name>. It makes reloading packages much easier and painless to someone who is upgrading or fixing a bug. Always qualify end statements, i.e., the end statement for a package should be end <package_name>;, not just end;; same goes for procedures, functions, package bodies, and triggers. Always use the "show errors" SQL*Plus command after each PL/SQL block. It will help you debug when there are compilation errors in your PL/SQL code. Name parameters as simply as possible, i.e., use the column name if the parameter corresponds to a table column. We're deprecating the v_* and *_in syntax in favor of named parameters notation: acs_user.create(first_names => 'Jane', last_name => 'Doe', etc.) instead of acs_user.create(first_names_in => 'Jane', last_name_in => 'Doe', etc.) To achieve this we must fully qualify arguements passed into procedures or functions when using them inside a SQL statement. This will get rid of any ambiguities in your code, i.e. it will tell the parser when you want the value of the column and when you want the value from the local variable. Here is an example: create or replace package body mypackage . . procedure myproc(party_id in parties.party_id%TYPE) is begin . . delete from parties where party_id = myproc.party_id; . . end myproc; . . end mypackage; / show errors Explicitly designate each parameter as "in," "out," or "inout." Each parameter should be on its own line, with a tab after the parameter name, then in/out/inout, then a space, and finally the datatype. Use %TYPE and %ROWTYPE whenever possible. Use 't' and 'f' for booleans, not the PL/SQL "boolean" datatype because it can't be used in SQL queries. All new functions (e.g., acs_object.new, party.new, etc.) should optionally accept an ID: create or replace package acs_object as function new ( object_id in acs_objects.object_id%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_object', creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, context_id in acs_objects.context_id%TYPE default null ) return acs_objects.object_id%TYPE; takes the optional argument object_id. Do this to allow people to use the same API call when they are doing double click protection, that is, tehy have already gotten an object_id and now they want to create the object with that object_id. Style Some general style guidelines to follow for the purpose of consistency across applications. Standard indentation is 4 spaces. Our PL/SQL code is not only viewable in the SQL files but also through our SQL and PL/SQL browsers. This means that we should try to make it as consistent as possible to all source code readers. Lowercase everything, with the exception of %TYPE and %ROWTYPE. ($Id: plsql.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/psgml-mode.xml0000644000175000017500000002006710456621135027670 0ustar frankiefrankie %myvars; ]> Using PSGML mode in Emacs By David Lutterkort Note: nxml mode replaces and/or complements psgml mode. More information. What it is PSGML Mode is a mode for editing, umm, SGML and XML documents in emacs. It can parse a DTD and help you insert the right tags in the right place, knows about tags' attributes and can tell you in which contexts a tag can be used. If you give it the right DTD, that is. But even without a DTD, it can save you some typing since pressing C-c/ will close an open tag automatically. Where to get it Most newer emacsen come with PSGML mode preinstalled. You can find out whether your emacs has it with the locate-library command. In Emacs, type M-x locate-library and enter psgml. Emacs will tell you if it found it or not. If you don't have PSGML preinstalled in your Emacs, there are two things you can do: On Linux: Get the psgml rpm from RedHat's docbook-tools and install it as usual. On other systems: Get the tarball from the PSGML Website. Unpack it and follow the install instructions. Using <computeroutput>CATALOG</computeroutput> files The easiest way to teach PSGML mode about a DTD is by adding it to your own CATALOG. Here is an example of how you can set that up for the Docbook XML DTD. Get the Docbook XML DTD zip archive from docbook.org Go somewhere in your working directory and do mkdir -p dtd/docbook-xml cd dtd/docbook-xml unzip -a <docbook XML DTD zip archive> Create a file with the name CATALOG in the dtd directory and put the line CATALOG "docbook-xml/docbook.cat" in it. By maintaining your own CATALOG, it is easy to add more DTD's without changing your emacs settings. (How about that HTML 4.01 DTD you always wanted to get from W3C ? The DTD is in the zip archives and tarballs available on the site.) That's it. Now you are ready to tell emacs all about PSGML mode and that funky CATALOG What to tell emacs If you installed PSGML mode in a non-standard location, e.g., somewhere in your home directory, you need to add this to the load-path by adding this line to your .emacs file: (add-to-list 'load-path "/some/dir/that/contains/psgml.elc") To let PSGML mode find your CATALOG and to enable PSGML mode for all your editing, add these lines to your .emacs: (require 'psgml) (add-to-list 'auto-mode-alist '("\\.html" . sgml-mode)) (add-to-list 'auto-mode-alist '("\\.adp" . xml-mode)) (add-to-list 'auto-mode-alist '("\\.xml" . xml-mode)) (add-to-list 'auto-mode-alist '("\\.xsl" . xml-mode)) (add-to-list 'sgml-catalog-files "/path/to/your/dtd/CATALOG") If you want font-locking and indentation, you can also add these lines into the .emacs file: (setq sgml-markup-faces '((start-tag . font-lock-function-name-face) (end-tag . font-lock-function-name-face) (comment . font-lock-comment-face) (pi . bold) (sgml . bold) (doctype . bold) (entity . font-lock-type-face) (shortref . font-lock-function-name-face))) (setq sgml-set-face t) (setq-default sgml-indent-data t) ;; Some convenient key definitions: (define-key sgml-mode-map "\C-c\C-x\C-e" 'sgml-describe-element-type) (define-key sgml-mode-map "\C-c\C-x\C-i" 'sgml-general-dtd-info) (define-key sgml-mode-map "\C-c\C-x\C-t" 'sgml-describe-entity) What is a <computeroutput>DOCTYPE</computeroutput> ? All SGML and XML documents that should conform to a DTD have to declare a doctype. For the docbook XML, all your .xml files whould start with the line <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "docbookx.dtd"> If your document is only part of a larger XML document, you can tell PSGML mode about it by appending the following lines to your file. In this case, do not include a DOCTYPE declaration in your file. <!-- Local Variables: sgml-parent-document: ("top.xml" "book" "sect1") End: --> Which says that the parent of this document can be found in the file top.xml, that the element in the parent that will enclose the current document is a book and that the current file's topmost element is a sect1. How to use it Of course, you should read the emacs texinfo pages that come with PSGML mode from start to finish. Barring that, here are some handy commands: Key Command C-c C-e Insert an element. Uses completion and only lets you insert elements that are valid C-c C-a Edit attributes of enclosing element. C-c C-x C-i Show information about the document's DTD. C-c C-x C-e Describe element. Shows for one element which elements can be parents, what its contents can be and lists its attributes. Further reading Start with the ($Id: psgml-mode.xml,v 1.8 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/xml/engineering-standards/constraint-naming.xml0000644000175000017500000001347310456621135031262 0ustar frankiefrankie %myvars; ]> Constraint naming standard By Michael Bryzek The Big Picture Constraint naming standard is important for one reason: The SYS_* name oracle assigns to unnamed constraints is not very understandable. By correctly naming all contraints, we can quickly associate a particular constraint with our data model. This gives us two real advantages: We can quickly identify and fix any errors. We can reliabily modify or drop constraints Why do we need a naming convention? Oracle limits names, in general, to 30 characters, which is hardly enough for a human readable constraint name. Abbreviations We propose the following naming convention for all constraints, with the following abbreviations taken from Oracle Docs at http://oradoc.photo.net/ora81/DOC/server.815/a67779/ch4e.htm#8953. Note that we shortened all of the constraint abbrevations to two characters to save room. Constraint type Abbreviation references (foreign key) fk unique un primary key pk check ck not null nn Format of constraint name <table name>_<column_name>_<constraint abbreviation> In reality, this won't be possible because of the character limitation on names inside oracle. When the name is too long, we will follow these two steps in order: Abbreviate the table name with the table's initials (e.g. users -> u and users_contact -> uc). Truncate the column name until it fits. If the constraint name is still too long, you should consider rewriting your entire data model :) Notes: If you have to abbreviate the table name for one of the constraints, abbreviate it for all the constraints If you are defining a multi column constraint, try to truncate the two column names evenly Example create table example_topics ( topic_id integer constraint example_topics_topic_id_pk primary key ); create table constraint_naming_example ( example_id integer constraint cne_example_id_pk primary key, one_line_description varchar(100) constraint cne_one_line_desc_nn not null, body clob, up_to_date_p char(1) default('t') constraint cne_up_to_date_p_check check(up_to_date_p in ('t','f')), topic_id constraint cne_topic_id_nn not null constraint cne_topic_id_fk references example_topics, -- Define table level constraint constraint cne_example_id_one_line_unq unique(example_id, one_line_description) ); Why it's good to name primary keys Naming primary keys might not have any obvious advantages. However, here's an example where naming the primary key really helps (and this is by no means a rare case! SQL> set autotrace traceonly explain; SQL> select * from constraint_naming_example, example_topics where constraint_naming_example.topic_id = example_topics.topic_id; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 NESTED LOOPS 2 1 TABLE ACCESS (FULL) OF 'CONSTRAINT_NAMING_EXAMPLE' 3 1 INDEX (UNIQUE SCAN) OF 'EXAMPLE_TOPICS_TOPIC_ID_PK' (UNI QUE) Isn't it nice to see "EXAMPLE_TOPICS_TOPIC_ID_PK" in the trace and know exactly which table oracle is using at each step? Naming not null constraints is optional... People disagree on whether or not we should be naming not null constraints. So, if you want to name them, please do so and follow the above naming standard. But, naming not null constraints is not a requirement. About Naming the not null constraints Though naming "not null" constraints doesn't help immeditately in error debugging (e.g. the error will say something like "Cannot insert null value into column"), we recommend naming not null constraints to be consistent in our naming of all constraints. ($Id: constraint-naming.xml,v 1.6 2006/07/17 05:38:37 torbenb Exp $) openacs-5.7.0/packages/acs-core-docs/www/tutorial-cvs.html0000644000175000017500000001574711501005400023341 0ustar frankiefrankie Add the new package to CVS

    Add the new package to CVS

    Before you do any more work, make sure that your work is protected by putting it all into cvs. The cvs add command is not recursive, so you'll have to traverse the directory tree manually and add as you go. (More on CVS)

    [$OPENACS_SERVICE_NAME xml]$ cd ..
    [$OPENACS_SERVICE_NAME doc]$ cd ..
    [$OPENACS_SERVICE_NAME www]$ cd ..
    [$OPENACS_SERVICE_NAME myfirstpackage]$ cd ..
    [$OPENACS_SERVICE_NAME packages]$ cvs add myfirstpackage/
    Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage added to the repository
    [$OPENACS_SERVICE_NAME packages]$ cd myfirstpackage/
    [$OPENACS_SERVICE_NAME myfirstpackage]$ cvs add www
    Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www added to the repository
    [$OPENACS_SERVICE_NAME myfirstpackage]$ cd www
    [$OPENACS_SERVICE_NAME www]$ cvs add doc
    Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc added to the repository
    [$OPENACS_SERVICE_NAME www]$ cd doc
    [$OPENACS_SERVICE_NAME doc]$ cvs add *
    cvs add: cannot add special file `CVS'; skipping
    cvs add: scheduling file `admin-guide.html' for addition
    cvs add: scheduling file `bi01.html' for addition
    cvs add: scheduling file `data-model.dia' for addition
    cvs add: scheduling file `data-model.png' for addition
    cvs add: scheduling file `design-config.html' for addition
    cvs add: scheduling file `design-data-model.html' for addition
    cvs add: scheduling file `design-future.html' for addition
    cvs add: scheduling file `design-ui.html' for addition
    cvs add: scheduling file `filename.html' for addition
    cvs add: scheduling file `index.html' for addition
    cvs add: scheduling file `page-map.dia' for addition
    cvs add: scheduling file `page-map.png' for addition
    cvs add: scheduling file `requirements-cases.html' for addition
    cvs add: scheduling file `requirements-introduction.html' for addition
    cvs add: scheduling file `requirements-overview.html' for addition
    cvs add: scheduling file `requirements.html' for addition
    cvs add: scheduling file `sample-data.html' for addition
    cvs add: scheduling file `sample.png' for addition
    cvs add: scheduling file `user-guide.html' for addition
    cvs add: scheduling file `user-interface.dia' for addition
    cvs add: scheduling file `user-interface.png' for addition
    Directory /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc/xml added to the repository
    cvs add: use 'cvs commit' to add these files permanently
    [$OPENACS_SERVICE_NAME doc]$ cd xml
    [$OPENACS_SERVICE_NAME xml]$ cvs add Makefile index.xml
    cvs add: scheduling file `Makefile' for addition
    cvs add: scheduling file `index.xml' for addition
    cvs add: use 'cvs commit' to add these files permanently
    [$OPENACS_SERVICE_NAME xml]$ cd ../../..
    [$OPENACS_SERVICE_NAME myfirstpackage]$ cvs commit -m "new package"
    cvs commit: Examining .
    cvs commit: Examining www
    cvs commit: Examining www/doc
    cvs commit: Examining www/doc/xml
    RCS file: /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc/admin-guide.html,v
    done
    Checking in www/doc/admin-guide.html;
    /cvsroot/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/doc/admin-guide.html,v  <--  admin-guide.html
    initial revision: 1.1
    done
    (many lines omitted)
    [$OPENACS_SERVICE_NAME myfirstpackage]$

    Figure 9.1. Upgrading a local CVS repository

    Upgrading a local CVS repository

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/aolserver.html0000644000175000017500000005010611501005400022673 0ustar frankiefrankie Install AOLserver 3.3oacs1

    Install AOLserver 3.3oacs1

    by Vinod Kurup

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    We recommend the use of AOLserver 4.0.1 or later. These instructions are retained as a resource.

    Debian users: we do not recommend installing Debian packages for Aolserver or Postgres. Several people have reported problems while trying to install using apt-get instead of from source. If you have the time to debug these and submit what you did, that's great, but if not, you should stick to installing from source.

    1. Unpack the Aolserver tarball. Download the aolserver tarball and unpack it.

      [root root]# cd /usr/local/src
      [root src]# wget --passive http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz
      --15:38:08--  http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz
                 => `aolserver3.3oacs1.tar.gz'
      Resolving uptime.openacs.org... done.
      Connecting to uptime.openacs.org[207.166.200.199]:80... connected.
      HTTP request sent, awaiting response... 200 OK
      Length: 3,858,074 [application/x-compressed]
      
      100%[====================================>] 3,858,074     66.56K/s    ETA 00:00
      
      15:39:05 (66.56 KB/s) - `aolserver3.3oacs1.tar.gz' saved [3858074/3858074]
      [root src]# tar xzf aolserver3.3oacs1.tar.gz
      [root src]#
      cd /usr/local/src
      wget --passive http://uptime.openacs.org/aolserver-openacs/aolserver3.3oacs1.tar.gz
      tar xzf aolserver3.3oacs1.tar.gz

      This section also relies on some OpenACS files, which you can get with Unpack the OpenACS tarball.

    2. Compile AOLserver. Compile and install AOLserver. First, prepare the installation directory and the source code. The message about BUILD-MODULES can be ignored.

      root@yourserver root]# mkdir -p /usr/local/aolserver
      [root root]# cd /usr/local/src/aolserver
      [root aolserver]# ./conf-clean
      cat: BUILD-MODULES: No such file or directory
      Done.
      [root aolserver]#mkdir -p /usr/local/aolserver
      cd /usr/local/src/aolserver
      ./conf-clean

      If you are using Oracle, edit conf-db and change postgresql to oracle, or to the word both if you want both drivers installed. In order to get nsoracle to compile, you may need to su - oracle, and then su (without the -) root to set the environment variables properly.

      conf-inst should contain the location where AOLserver is to be installed. Overwrite the tarball's default value with our default value, /usr/local/aolserver:

      [root aolserver]# echo "/usr/local/aolserver" > conf-inst
      [root aolserver]#

      conf-make should contain the name of the GNU Make command on your system. It defaults to gmake. Debian users: ln -s /usr/bin/make /usr/bin/gmake.

      Set an environment variable that the nspostgres driver Makefile needs to compile correctly and run conf, which compiles AOLserver, the default modules, and the database driver, and installs them.

      Debian users, see warning above, but if you do use apt-get for AOLserver 3.3+ad13 and postgresql from apt-get may need to make these symlinks: ln -s /usr/include/postgresql/ /usr/include/pgsql and ln -s /usr/lib/postgresql /usr/local/pgsql)

      [root aolserver]# export POSTGRES=/usr/local/pgsql; ./conf
      Building in /usr/local/aolserver
      with the following modules:
      aolserver
      nscache
      nsrewrite
      nssha1
      nsxml
      pgdriver
      ==================================================================
      Starting Build Sat Mar  8 10:28:26 PST 2003
      Running gmake in aolserver/; output in log/aolserver.log
      (several minute delay here)
      Running gmake in nscache/; output in log/nscache.log
      Running gmake in nsrewrite/; output in log/nsrewrite.log
      Running gmake in nssha1/; output in log/nssha1.log
      Running gmake in nsxml/; output in log/nsxml.log
      Running gmake in nspostgres/; output in log/nspostgres.log
      Creating  ...
      ==================================================================
      Done Building Sat Mar  8 10:31:35 PST 2003
      [root aolserver]# 

      This takes about 5 minutes. It builds aolserver, several modules, and the database driver. (Upgraders, note that the postgres database driver has changed from postgres.so to nspostgres.so). All of the results are logged to files in /usr/local/src/aolserver/log. If you run into problems running AOLserver, check these files for build errors.

    3. Add a database-specific wrapper script. This script sets database environment variables before starting AOLserver; this allows the AOLserver instance can communicate with the database. There is one script each for Oracle and PostgreSQL. They don't conflict, so if you plan to use both databases, install both.

      • Oracle

        [root aolserver]# cd /usr/local/aolserver/bin
        [root bin]# cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle
        [root bin]# chmod 750 nsd-oracle
        [root bin]#
        cd /usr/local/aolserver/bin
        cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle
        chmod 750 nsd-oracle
      • PostgreSQL

        [root aolserver]# cd /usr/local/aolserver/bin
        [root bin]# cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres
        [root bin]# chmod 755 nsd-postgres
        [root bin]#
        cd /usr/local/aolserver/bin
        cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres
        chmod 755 nsd-postgres
    4. Install tDOM. Download the tDOM tarball, unpack it, adjust the configuration file to match our patched distribution of aolserver, and compile it.

      [root root]# cd /usr/local/src
      [root src]# wget --passive http://www.tdom.org/tDOM-0.7.8.tar.gz
      --16:40:58--  http://www.tdom.org/tDOM-0.7.8.tar.gz
                 => `tDOM-0.7.8.tar.gz'
      Resolving www.tdom.org... done.
      Connecting to www.tdom.org[212.14.81.4]:80... connected.
      HTTP request sent, awaiting response... 200 OK
      Length: 826,613 [application/x-compressed]
      
      100%[====================================>] 826,613      138.06K/s    ETA 00:00
      
      16:41:04 (138.06 KB/s) - `tDOM-0.7.8.tar.gz' saved [826613/826613]
      
      [root src]# tar xzf tDOM-0.7.8.tar.gz
      [root src]# cd tDOM-0.7.8/unix
      [root unix]#
      cd /usr/local/src
      wget --passive http://www.tdom.org/tDOM-0.7.8.tar.gz
      tar xzf tDOM-0.7.8.tar.gz
      cd tDOM-0.7.8/unix 

      Edit the file CONFIG and change this section:

      # ----------------------------------------------------
      # aolsrc="/usr/src/aolserver-3.4"
      # ../configure --enable-threads --disable-tdomalloc \
      #   --with-aolserver=$aolsrc \
      #   --with-tcl=$aolsrc/tcl8.3.4/unix 

      to

      # ----------------------------------------------------
      aolsrc="/usr/local/src/aolserver/aolserver"
      ../configure --enable-threads --disable-tdomalloc \
        --with-aolserver=$aolsrc \
        --with-tcl=$aolsrc/tcl8.3.2/unix

      And configure and compile:

      [root unix]# sh CONFIG
      creating cache ./config.cache
      checking for memmove... yes
        (many lines omitted)
      creating Makefile
      creating tdomConfig.sh
      [root unix]# make
      gcc -pipe -DHAVE_UNISTD_H=1 -DHAVE_LIMITS_H=1 -DTCL_THREADS=1
      -DHAVE_GETCWD=1 -DHAVE_OPENDIR=1 -DHAVE_STRSTR=1 -DHAVE_STRTOL=1 
        (many lines omitted)
                -Wl,-rpath,/usr/local/lib -o tcldomsh;\
      fi
      [root unix]# cp libtdom0.7.8.so /usr/local/aolserver/bin/
      [root unix]# cd /usr/local/aolserver/bin/
      [root bin]# ln -s libtdom0.7.8.so libtdom.so
      [root bin]#
      
      sh CONFIG
      make
      cp libtdom0.7.8.so /usr/local/aolserver/bin/
      cd /usr/local/aolserver/bin
      ln -s libtdom0.7.8.so libtdom.so
    5. Install nsopenssl (OPTIONAL)

    6. Install Full Text Search with OpenFTS (OPTIONAL)

    7. Install nspam (OPTIONAL)

    8. Test AOLserver. In order to test AOLserver, we'll run it using the sample-config.tcl file provided in the AOLserver distribution, under the nobody user and web group. The sample-config.tcl configuration writes to the default log locations, so we need to give it permission to do so or it will fail. Grant the web group permission to write to /usr/local/aolserver/log and /usr/local/aolserver/servers.

      [root root]# cd /usr/local/aolserver
      [root aolserver]# chown -R root.web log servers
      [root aolserver]# chmod -R g+w log servers
      [root aolserver]# ls -l
      total 32
      drwxr-sr-x    2 root     root         4096 Mar  8 12:57 bin
      drwxr-xr-x    3 root     root         4096 Mar  8 10:34 include
      drwxr-sr-x    3 root     root         4096 Mar  8 10:34 lib
      drwxrwsr-x    2 root     web          4096 Mar  8 10:31 log
      drwxr-sr-x    3 root     root         4096 Mar  8 10:31 modules
      -rw-r--r--    1 root     root         7320 Mar 31  2001 sample-config.tcl
      drwxrwsr-x    3 root     web          4096 Mar  8 10:31 servers
      [root aolserver]#
      
      cd /usr/local/aolserver
      chown -R root.web log servers
      chmod -R g+w log servers
      ls -l

      Note: AOLserver4.x does not include a default start page, so we create one for this test. Type echo "Welcome to AOLserver" > /usr/local/aolserver40r8/servers/server1/pages/index.html

      Now, we'll run a quick test to ensure AOLserver is running correctly. We'll use the sample config file provided with AOLserver. This file will attempt to guess your IP address and hostname. It will then start up the server at port 8000 of that IP address.

      [root aolserver]# ./bin/nsd -t sample-config.tcl -u nobody -g web
      [root aolserver]# [08/Mar/2003:15:07:18][31175.8192][-main-] Notice: config.tcl: starting to read config file...
      [08/Mar/2003:15:07:18][31175.8192][-main-] Warning: config.tcl: nsssl not loaded -- key/cert files do not exist.
      [08/Mar/2003:15:07:18][31175.8192][-main-] Warning: config.tcl: nscp not loaded
      -- user/password is not set.
      [08/Mar/2003:15:07:18][31175.8192][-main-] Notice: config.tcl: finished reading
      config file.

      The first warning, about nsssl, can be ignored. We won't be using nsssl; we'll be using nsopenssl instead, and we haven't fully configured it yet. The nscp warning refers to the fact that, without a user and password in the config file, the administrative panel of AOLserver won't load. We don't plan to use it and can ignore that error as well. Any other warning or error is unexpected and probably a problem.

      Test to see if AOLserver is working by starting Mozilla or Lynx on the same computer and surfing over to your web page. If you browse from another computer and the sample config file didn't guess your hostname or ip correctly, you'll get a false negative test.

      [root aolserver]# lynx localhost:8000

      You should see a "Welcome to AOLserver" page. If this doesn't work, try going to http://127.0.0.1:8000/. If this still doesn't work, check out the Troubleshooting AOLserver section below. Note that you will not be able to browse to the web page from another machine, because AOLserver is only listening to the local address.

      Shutdown the test server:

      [root aolserver]# killall nsd
      [root aolserver]#

      The killall command will kill all processes with the name nsd, but clearly this is not a good tool to use for managing your services in general. We cover this topic in the Keep AOLserver alive section.

    9. Troubleshooting. If you can't view the welcome page, it's likely there's a problem with your server configuration. Start by viewing your AOLserver log, which is in /usr/local/aolserver/log/server.log. You should also try to find lines of the form:

      [01/Jun/2000:12:11:20][5914.4051][-nssock-] Notice: nssock: listening on http://localhost.localdomain:8000 (127.0.0.1:8000)
      [01/Jun/2000:12:11:20][5914.4051][-nssock-] Notice: accepting connections

      If you can find these lines, try entering the URL the server is listening on. If you cannot find these lines, there must be an error somewhere in the file. Search for lines beginning with the word Error instead of Notice.

      The sample-config.tcl file grabs your address and hostname from your OS settings.

      set hostname        [ns_info hostname]
      set address         [ns_info address]

      If you get an error that nssock can't get the requested address, you can set these manually. If you type 0.0.0.0, AOLserver will try to listen on all available addresses. Note: ns_info address doesn't appear to be supported in current versions of AOLserver.

      set hostname        [ns_info hostname]
      #set address         [ns_info address]
      set address 0.0.0.0
    10. Install Analog web file analyzer. (OPTIONAL)

    ($Id: aolserver.html,v 1.50 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-more-software.html0000644000175000017500000001114411501005400025126 0ustar frankiefrankie Appendix B. Install additional supporting software

    Appendix B. Install additional supporting software

    By Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This section assumes that the source tarballs for supporting software are in /tmp. It assumes that you begin each continuous block of commands as root, and you should end each block as root. It doesn't care which directory you start in. Text instructions always precede the commands they refer to.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-parameters.html0000644000175000017500000000545211501005400024701 0ustar frankiefrankie Adding in parameters for your package

    Adding in parameters for your package

    Each instance of a package can have paramaters associated with it. These are like preferences, and they can be set by the administrator for each application to change the behavior of your application.

    To add parameters for your package, go to the Automatic Package Manager (/acs-admin/apm)

    Click on your package

    Under the Manage section, click on Parameters

    It's fairly self-explanatory at this point. Create the parameters you want, and then access them in your code using the parameter::get procedure.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-notifications.html0000644000175000017500000002447411501005400025414 0ustar frankiefrankie Notifications

    Notifications

    by David Bell and Simon Carstensen

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    The notifications package allows you to send notifications through any defined communications medium (e.g. email, sms) upon some event occuring within the system.

    This tutorial steps through the process of integrating the notifications package with your package.

    First step is to create the notification types. To do this a script similar to the one below needs to be loaded into Postgresql. I create this script in a package-name/sql/postgresql/package-name-notifications-init.sql file. I then load this file from my create sql file. The following code snippet is taken from Weblogger. It creates a lars_blogger_notif notification type (which was created above).

        create function inline_0() returns integer as '
        declare
                impl_id integer;
                v_foo   integer;
        begin
            -- the notification type impl
            impl_id := acs_sc_impl__new (
                          ''NotificationType'',
                          ''lars_blogger_notif_type'',
                          ''lars-blogger''
            );
    
            v_foo := acs_sc_impl_alias__new (
                        ''NotificationType'',
                        ''lars_blogger_notif_type'',
                        ''GetURL'',
                        ''lars_blogger::notification::get_url'',
                        ''TCL''
            );
    
            v_foo := acs_sc_impl_alias__new (
                        ''NotificationType'',
                        ''lars_blogger_notif_type'',
                        ''ProcessReply'',
                        ''lars_blogger::notification::process_reply'',
                        ''TCL''
            );
    
            PERFORM acs_sc_binding__new (
                        ''NotificationType'',
                        ''lars_blogger_notif_type''
            );
    
            v_foo:= notification_type__new (
    	        NULL,
                    impl_id,
                    ''lars_blogger_notif'',
                    ''Blog Notification'',
                    ''Notifications for Blog'',
    		now(),
                    NULL,
                    NULL,
    		NULL
            );
    
            -- enable the various intervals and delivery methods
            insert into notification_types_intervals
            (type_id, interval_id)
            select v_foo, interval_id
            from notification_intervals where name in (''instant'',''hourly'',''daily'');
    
            insert into notification_types_del_methods
            (type_id, delivery_method_id)
            select v_foo, delivery_method_id
            from notification_delivery_methods where short_name in (''email'');
    
            return (0);
        end;
        ' language 'plpgsql';
    
        select inline_0();
        drop function inline_0();
        

    You also need a drop script. This is untested for comptability with the above script.

          -- @author gwong@orchardlabs.com,ben@openforce.biz
          -- @creation-date 2002-05-16
          --
          -- This code is newly concocted by Ben, but with significant concepts and code
          -- lifted from Gilbert's UBB forums. Thanks Orchard Labs.
          -- Lars and Jade in turn lifted this from gwong and ben.
    
    create function inline_0 ()
    returns integer as '
    declare
        row                             record;
    begin
        for row in select nt.type_id
                   from notification_types nt
                   where nt.short_name in (''lars_blogger_notif_type'',''lars_blogger_notif'')
        loop
            perform notification_type__delete(row.type_id);
        end loop;
    
        return null;
    end;' language 'plpgsql';
    
    select inline_0();
    drop function inline_0 ();
    
    --
    -- Service contract drop stuff was missing - Roberto Mello 
    --
    
    create function inline_0() returns integer as '
    declare
            impl_id integer;
            v_foo   integer;
    begin
    
            -- the notification type impl
            impl_id := acs_sc_impl__get_id (
                          ''NotificationType'',		-- impl_contract_name
                          ''lars_blogger_notif_type''	-- impl_name
            );
    
            PERFORM acs_sc_binding__delete (
                        ''NotificationType'',
                        ''lars_blogger_notif_type''
            );
    
            v_foo := acs_sc_impl_alias__delete (
                        ''NotificationType'',		-- impl_contract_name	
                        ''lars_blogger_notif_type'',	-- impl_name
                        ''GetURL''				-- impl_operation_name
            );
    
            v_foo := acs_sc_impl_alias__delete (
                        ''NotificationType'',		-- impl_contract_name	
                        ''lars_blogger_notif_type'',	-- impl_name
                        ''ProcessReply''			-- impl_operation_name
            );
    
    	select into v_foo type_id 
    	  from notification_types
    	 where sc_impl_id = impl_id
    	  and short_name = ''lars_blogger_notif'';
    
    	perform notification_type__delete (v_foo);
    
    	delete from notification_types_intervals
    	 where type_id = v_foo 
    	   and interval_id in ( 
    		select interval_id
    		  from notification_intervals 
    		 where name in (''instant'',''hourly'',''daily'')
    	);
    
    	delete from notification_types_del_methods
    	 where type_id = v_foo
    	   and delivery_method_id in (
    		select delivery_method_id
    		  from notification_delivery_methods 
    		 where short_name in (''email'')
    	);
    
    	return (0);
    end;
    ' language 'plpgsql';
    
    select inline_0();
    drop function inline_0();
        

    The next step is to setup our notification creation. A new notification must be added to the notification table for each blog entry added. We do this using the notification::new procedure

            notification::new \
                -type_id [notification::type::get_type_id \
                -short_name lars_blogger_notif] \
                -object_id $blog(package_id) \
                -response_id $blog(entry_id) \
                -notif_subject $blog(title) \
                -notif_text $new_content
        

    This code is placed in the tcl procedure that creates blog entries, right after the entry gets created in the code. The $blog(package_id) is the OpenACS object_id of the Weblogger instance to which the entry has been posted to and the $new_content is the content of the entry. This example uses the package_id for the object_id, which results in setting up notifications for all changes for blogger entries in this package. However, if you instead used the blog_entry_id or something like that, you could set up per-item notifications. The forums packages does this -- you can look at it for an example.

    The final step is to setup the notification subscription process. In this example we want to let a user find out when a new entry has been posted to the blog. To do this we put a link on the blog that allows them to subscribe to notifications of new entries. The notifications/requests-new page is very handy in this situation.

    Such a link can be created using the notification::display::request_widget proc:

        set notification_chunk [notification::display::request_widget \
            -type lars_blogger_notif \
            -object_id $package_id \
            -pretty_name [lars_blog_name] \
            -url [lars_blog_public_package_url] \
        ]
        

    which will return something like

        You may <a href="/notifications/request-new?...">request notification</a> for Weblogger.

    which can be readily put on the blog index page. The pretty_name parameter is what appears at the end of the text returned (i.e. "... request notification</a> for pretty_name"), The url parameter should be set to the address we want the user to be redirected to after they have finished the subscription process.

    This should be all you need to implement a notification system. For more examples look at the forums package.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/unit-testing-guide/0000755000175000017500000000000011724401447023550 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/unit-testing-guide/index.html0000644000175000017500000001126407253523116025551 0ustar frankiefrankie ACS4 Unit Tests

    ACS4 Unit Tests

    by Patrick McNeill

    Purpose

    Prior to using these unit tests, all testing had to be completed manually for each revision of a module. When a module is updated several times a day, this can present a problem. The solution adopted here is to create a suite of regression tests for each module to ensure that the required functionality is not broken by new code. The tests are constructed in such a way that they can be run automatically, allowing developers to quickly determine if new code breaks any functionality requirements.

    Installation

    The ACS4 unit testing suite requires several pieces of software to function. First, you'll need to install Ant. Ant is a build tool similar to make. It's used to both build your test cases and run the tests themselves. The basic Ant functionality doesn't have everything needed to automate the testing, so you'll want to obtain David Eison's ForeachFileAntTask.java, available at http://cvs.arsdigita.com/cgi-bin/cvsweb.pl/acs-java-4/WEB-INF/src/com/arsdigita/build/. Compile the files and make sure that they are in your classpath.

    Once Ant is working, you'll need to obtain copies of both JUnit and HTTPUnit. JUnit is a framework to automate the running of unit tests, and HTTPUnit provides an abstraction layer for HTTP. These are both needed to compile the unit tests. Again, make sure your classpath is up to date.

    The final step is to replace the server properties in the build.xml file so it will know how to talk to your server. You will need to give it a base URL, a username, and password for that user. are the "JVMARG" lines in the "JUNIT" section. ). In the near future, this will be moved out of the subdirectories and either into the toplevel build.xml file or into a configuration file.

    You should now be ready to run the tests. Go to your server's "packages" directory and type source ./paths.sh to set up your classpath. Now type ant. Ant should find the toplevel build.xml file, check that it can see JUnit, compile your java files, and finally call Ant on each of the sub-directory build.xml files to run the tests. You should be shown a report of which tests failed and which succeeded.

    Adding Your Own Unit Tests

    Adding new test cases is meant to be as easy as possible. Simple create a new function in the appropriate .java file, making sure that the function name begins with "test". I've adopted a naming convention where the function name consists of the word "test", a short description of what the function does (with words delimited by underscores), followed finally by the QAS testcase ID, if such a testcase exists. If you need to test an area of the site that requires a user id, you can use the ACSCommon.Login function in the com.arsdigita.acs.acsKernel.test package to obtain a Session object with appropriate cookies.

    Within the function, a typical unit test involves requesting a page, saving the result, checking the HTTP return code, then parsing out various strings to check for page functionality. The return code should be checked with "assertEquals", and any other checks should be performed with "assert". Use of "assert", "assertEquals", and exceptions allow JUnit to accurately report where a test fails.

    If you need to create a set of tests for a module, the first step is to create a directory tree beneath the module directory. The current convention is to put all .java files in a "/java/src/com/arsdigita/acs/module name/test" directory. The module name should be the ACS module name, but with all dashes removed and with appropriate capitilization. All .java files that you create that contain test cases must have the word Test in the filename. All of the classes you create should be in the com.arsdigita.acs.module name.test package, and should import "com.dallaway.jsptest.*" and "junit.framework.*" (and optionally, if needed, com.arsdigita.acs.acsKernel.ACSCommon). Next, the public class needs to extend "TestCase", and provide new method definitions for "suite()" and the constructor. Typically, in the constructor, you should extract the system property "system.url" to determine which server to test against.


    Last updated - 2000-12-19
    pmcneill@arsdigita.com
    openacs-5.7.0/packages/acs-core-docs/www/upgrade.html0000644000175000017500000000571311501005400022324 0ustar frankiefrankie Chapter 5. Upgrading

    Chapter 5. Upgrading

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/request-processor.html0000644000175000017500000002423011501005400024375 0ustar frankiefrankie The Request Processor

    The Request Processor

    By Pete Su

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Overview

    This document is a brief introduction to the OpenACS 5.6.0 Request Processor; more details can be found in the OpenACS 4 Request Processor Design. Here we cover the high level concepts behind the system, and implications and usage for the application developer.

    Request Processor

    The 5.6.0 Request Processor is a global filter and set of Tcl procs that respond to every incoming URL reaching the server. The following diagram summarizes the stages of the request processor assuming a URL request like http://someserver.com/notes/somepage.adp.

    Stage 1: Search Site Map

    The first thing the RP does is to map the given URL to the appropriate physical directory in the filesystem, from which to serve content. We do this by searching the site map data model (touched on in the Packages, and further discussed in Writing OpenACS Application Pages). This data model maps URLs to objects representing content, and these objects are typically package instances.

    After looking up the appropriate object, the RP stores the URL, the ID of the object it found, and the package and package instance the object belongs to into the environment of the connection. This environment can be queried using the ad_conn procedure, which is described in detail in OpenACS 4 Request Processor Design. The page development tutorial shows you how to use this interface to make your pages aware of which instance was requested.

    Stage 2: Authentication

    Next, the Request Processor examines the request for session information. Session information is generally sent from the client (the user's browser) to the server via cookies. The security/session handler is described in detail in its own document. It examines the client request and either extracts or sets up new session tokens for the user.

    Stage 3: Authorization

    Next, the Request Processor checks if the user has appropriate access privileges to the requested part of the site. In OpenACS 5.6.0, access control is dictated by the permissions system. In this case, the RP checks if the user has "read" priviledges on the object in the site map specified by the URL. This object is typically a package instance, but it could easily be something more granular, such as whehter the user can view a particular piece of content within a package instance. This automatic check makes it easy to set up sites with areas that are only accessible to specific groups of users.

    Stage 4: URL Processing, File Search

    Finally, the Request Processor finds the file we intend to serve, searching the filesystem to locate the actual file that corresponds to an abstract URL. It searches for files with predefined "magic" extensions, i.e. files that end with: .html, .tcl and .adp.

    If the RP can't find any matching files with the expected extensions, it will look for virtual-url-handler files, or .vuh files. A .vuh file will be executed as if it were a Tcl file, but with the tail end of the URL removed. This allows the code in the .vuh file to act like a registered procedure for an entire subtree of the URL namespace. Thus a .vuh file can be thought of as a replacement for filters and registered procs, except that they integrate cleanly and correctly with the RP's URL mapping mechanisms. The details of how to use these files are described in OpenACS 4 Request Processor Design.

    Once the appropriate file is found, it is either served directly if it's static content, or sent to the template system or the standard Tcl interpreter if it's a dynamic page.

    Basic API

    Once the flow of control reaches a dynamic page, the Request Processor has populated the environment of the request with several pieces of useful information. The RP's environment is accessible through the ad_conn interface, and the following calls should be useful to you when developing dynamic pages:

    [ad_conn user_id]

    The ID of the user associated with this request. By convention this is zero if there is no user.

    [ad_conn session_id]

    The ID of the session associated with this request.

    [ad_conn url]

    The URL associated with the request.

    [ad_conn urlv]

    The URL associated with the request, represented as a list instead of a single string.

    [ad_conn file]

    The actual local filesystem path of the file that is being served.

    [ad_conn object_url]

    If the URL refers to a site map object, this is the URL to the root of the tree where the object is mounted.

    [ad_conn package_url]

    If the URL refers to a package instance, this is the URL to the root of the tree where the package is mounted.

    [ad_conn extra_url]

    If we found the URL in the site map, this is the tail of the URL following the part that matched a site map entry.

    [ad_conn object_id]

    If the URL refers to a site map object, this is the ID of that object.

    [ad_conn package_id]

    If the URL refers to a package instance, this is the ID of that package instance.

    [ad_conn package_key]

    If the URL refers to a package instance, this is the unique key name of the package.

    [ad_conn path_info]

    In a .vuh file, path_info is the trailing part of the URL not matched by the .vuh file.

    ($Id: request-processor.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/nxml-mode.html0000644000175000017500000000634711501005400022601 0ustar frankiefrankie Using nXML mode in Emacs

    Using nXML mode in Emacs

    By Jeff Davis

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    An alternative to psgml mode is nXML by James Clark, a new major mode for GNU Emacs for editing XML, and which features highlighting, indentation, and on the fly validation versus a RelaxNG Schema.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/unix-installation.html0000644000175000017500000001252011501005400024351 0ustar frankiefrankie Install a Unix-like system and supporting software

    Install a Unix-like system and supporting software

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    a Unix-like system

    You will need a computer running a unix-like system with the following software installed:

    • tdom

    • tcl --if you plan to use the OpenACS installation script

    • gmake and the compile and build environment.

      BSD Note

      BSD users: in most places in these instructions, gmake will work better than make. (more information on FreeBSD installation). Also, fetch is a native replacement for wget.

    Note: Instructions for installing tDOM and threaded tcl are included with the AOLserver4 installation instructions, if these are not yet installed.

    The following programs may be useful or required for some configurations. They are included in most distributions:

    In order to cut and paste the example code into your shell, you must first do Setting a global shell variable for cut and paste.

    To install a machine to the specifications of the Reference Platform, do the walkthrough of the Red Hat 8.0 Install for OpenACS.

    ($Id: unix-installation.html,v 1.31 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/openacs.html0000644000175000017500000013246211501005400022327 0ustar frankiefrankie Install OpenACS 5.6.0

    Install OpenACS 5.6.0

    by Vinod Kurup

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Set up a user account for each site.

    AOLserver needs to be started as the root user if you want to use port 80. Once it starts, though, it will drop the root privileges and run as another user, which you must specify on the command line. It's important that this user has as few privileges as possible. Why? Because if an intruder somehow breaks in through AOLserver, you don't want her to have any ability to do damage to the rest of your server.

    At the same time, AOLserver needs to have write access to some files on your system in order for OpenACS to function properly. So, we'll run AOLserver with a different user account for each different service. A service name should be a single word, letters and numbers only. If the name of your site is one word, that would be a good choice. For example "$OPENACS_SERVICE_NAME" might be the service name for the $OPENACS_SERVICE_NAME.net community.

    We'll leave the password blank, which prevents login by password, for increased security. The only way to log in will be with ssh certificates. The only people who should log in are developers for that specific instance. Add this user, and put it in the $OPENACS_SERVICE_NAME group so that it can use database and server commands associated with that group. (If you don't know how to do this, type man usermod. You can type groups to find out which groups a user is a part of)

    [root root]# useradd $OPENACS_SERVICE_NAME
    

    You also need to set up a group called web.

    [root root]# groupadd web
          

    Then change the user to be a part of this group:

    [root root]# usermod -g web $OPENACS_SERVICE_NAME
          

    FreeBSD creates the user this way:

    [root root]# mkdir -p /home/$OPENACS_SERVICE_NAME
    [root root]# pw useradd -n $OPENACS_SERVICE_NAME -g web -d /home/$OPENACS_SERVICE_NAME -s /bin/bash
    [root root]#
    mkdir -p /home/$OPENACS_SERVICE_NAME
    pw useradd -n $OPENACS_SERVICE_NAME -g web -d /home/$OPENACS_SERVICE_NAME -s /bin/bash
    

    Set up the file system for one or more OpenACS Sites

    For Linux Standard Base compliance and ease of backup, all of the files in each OpenACS site are stored in a subdirectory of /var/lib/aolserver, one subdirectory per site. The first time you install an OpenACS site on a server, you must create the parent directory and set its permissions:

    [root root]# mkdir /var/lib/aolserver
    [root root]# chgrp web /var/lib/aolserver
    [root root]# chmod 770 /var/lib/aolserver
    [root root]#
    mkdir /var/lib/aolserver
    chgrp web /var/lib/aolserver
    chmod 770 /var/lib/aolserver

    Installation Option 1: Use automated script

    A bash script is available to automate all of the steps for the rest of this section. It requires tclwebtest. The automated script can greatly accelerate the install process, but is very sensitive to the install environment. We recommend that you run the automated install and, if it does not work the first time, consider switching to a manual installation.

    Get the install script from CVS. It is located within the main cvs tree, at /etc/install. Use anonymous CVS checkout to get that directory in the home directory of the service's dedicated user. We put it there so that it is not overwritten when we do the main CVS checkout to the target location.

    [root root]# su - $OPENACS_SERVICE_NAME
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot co -d install openacs-4/etc/install
    cvs server: Updating install
    U install/README
    U install/TODO
      ... many lines omitted ...
    U install/tcl/twt-procs.tcl
    U install/tcl/user-procs.tcl
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd install
    [$OPENACS_SERVICE_NAME install]$ emacs install.tcl
    

    Edit the installation configuration file, /home/$OPENACS_SERVICE_NAME/install/install.tcl and update the site-specific values, such as the new service's IP address and name, which will be written into the new service's config.tcl file. If your system is different from the one described in the previous sections, check the file paths as well. Set do_checkout=yes to create a new OpenACS site directly from a CVS checkout, or =no if you have a fully configured site and just want to rebuild it (drop and recreate the database and repeat the installation). If you have followed a stock installation, the default configuration will work without changes and will install an OpenACS site at 127.0.0.1:8000.

    Run the install script install.sh as root:

    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit 
    [root root]# sh /home/$OPENACS_SERVICE_NAME/install/install.sh
    /home/$OPENACS_SERVICE_NAME/install/install.sh: Starting installation with config_file 
    /home/$OPENACS_SERVICE_NAME/install/install.tcl. Using serverroot=/var/lib/aolserver/
    $OPENACS_SERVICE_NAME, server_url=http://0.0.0.0:8000, do_checkout=yes, do_install=yes, 
    dotlrn=no, and database=postgres., use_daemontools=true
      ... many lines omitted ...
    Tue Jan 27 11:50:59 CET 2004: Finished (re)installing /var/lib/aolserver/$OPENACS_SERVICE_NAME.
    ######################################################################
      New site URL: http://127.0.0.1:8000
    admin email   : admin@yourserver.net
    admin password: xxxx
    ######################################################################
    [root root]#

    You can proceed to Next Steps.

    Installation Option 2: Install from tarball

    You should already have downloaded the OpenACS tarball to the /var/tmp directory. If not, download the OpenACS tarball and save it in /var/tmp and proceed:

    1. Unpack the OpenACS tarball and rename it to $OPENACS_SERVICE_NAME. Secure the directory so that only the owner can access it. Check the permissions by listing the directory.

      FreeBSD note: Change the period in chown -R $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME to a colon: chown -R $OPENACS_SERVICE_NAME:$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver
      [$OPENACS_SERVICE_NAME aolserver]$ tar xzf /var/tmp/openacs-5.6.0.tgz
      [$OPENACS_SERVICE_NAME aolserver]$ mv openacs-5.6.0 $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ chmod -R 775 $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ chown -R $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ ls -al
      total 3
      drwxrwx---    3 root     web          1024 Mar 29 16:41 .
      drwxr-xr-x   25 root     root         1024 Mar 29 16:24 ..
      drwx------    7 $OPENACS_SERVICE_NAME web          1024 Jan  6 14:36 $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ exit
      logout
      [root root]#
      su - $OPENACS_SERVICE_NAME
      cd /var/lib/aolserver
      tar xzf /var/tmp/openacs-5.6.0.tgz
      mv openacs-5.6.0 $OPENACS_SERVICE_NAME
      chmod -R 755 $OPENACS_SERVICE_NAME
      chown -R $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME
      exit
    2. Add the Service to CVS (OPTIONAL)

    3. Prepare the database

      • Prepare Oracle for OpenACS. If you won't be using Oracle, skip to Prepare PostgreSQL for an OpenACS Service

        You should be sure that your user account (e.g. $OPENACS_SERVICE_NAME) is in the dba group.

        1. Verify membership by typing groups when you login:

          [$OPENACS_SERVICE_NAME ~]$ groups
          dba web

          If you do not see these groups, take the following action:

          [$OPENACS_SERVICE_NAME ~]$ su -
          Password: ************
          [root ~]# adduser $OPENACS_SERVICE_NAME dba

          If you get an error about an undefined group, then add that group manually:

          [root ~]# groupadd dba
          [root ~]# groupadd web

          Make sure to logout as root when you are finished with this step and log back in as your regular user.

        2. Connect to Oracle using svrmgrl and login:

          [$OPENACS_SERVICE_NAME ~]$ svrmgrl
          SVRMGR> connect internal
          Connected.

        3. Determine where the system tablespaces are stored:

          SVRMGR> select file_name from dba_data_files;

          Example results:

          /ora8/m01/app/oracle/oradata/ora8/system01.dbf
          /ora8/m01/app/oracle/oradata/ora8/tools01.dbf
          /ora8/m01/app/oracle/oradata/ora8/rbs01.dbf
          /ora8/m01/app/oracle/oradata/ora8/temp01.dbf
          /ora8/m01/app/oracle/oradata/ora8/users01.dbf
          /ora8/m01/app/oracle/oradata/ora8/indx01.dbf
          /ora8/m01/app/oracle/oradata/ora8/drsys01.dbf

        4. Using the above output, you should determine where to store your tablespace. As a general rule, you'll want to store your tablespace on a mount point under the /ora8 directory that is separate from the Oracle system data files. By default, the Oracle system is on m01, so we will use m02. This enables your Oracle system and database files to be on separate disks for optimized performance. For more information on such a configuration, see Chapter 12 of Philip's book. For this example, we'll use /ora8/m02/oradata/ora8/.

        5. Create the directory for the datafile; to do this, exit from svrmgrl and login as root for this step:

          SVRMGR> exit
          [$OPENACS_SERVICE_NAME ~]$ su -
          Password: ************
          [root ~]# mkdir -p /ora8/m02/oradata/ora8/
          [root ~]# chown $OPENACS_SERVICE_NAME:web /ora8/m02/oradata/ora8
          [root ~]# chmod 775 /ora8/m02/oradata/ora8
          [root ~]# exit
          [$OPENACS_SERVICE_NAME ~]$
        6. Create a tablespace for the service. It is important that the tablespace can autoextend. This allows the tablespace's storage capacity to grow as the size of the data grows. We set the pctincrease to be a very low value so that our extents won't grow geometrically. We do not set it to 0 at the tablespace level because this would affect Oracle's ability to automatically coalesce free space in the tablespace.

          [$OPENACS_SERVICE_NAME ~]$ svrmgrl
          SVRMGR> connect internal;
          SVRMGR> create tablespace $OPENACS_SERVICE_NAME
                datafile '/ora8/m02/oradata/ora8/$OPENACS_SERVICE_NAME01.dbf' 
                size 50M 
                autoextend on 
                next 10M
                maxsize 300M
                extent management local
                uniform size 32K;
        7. Create a database user for this service. Give the user access to the tablespace and rights to connect. We'll use $OPENACS_SERVICE_NAMEpassword as our password.

          Write down what you specify as service_name (i.e. $OPENACS_SERVICE_NAME) and database_password (i.e. $OPENACS_SERVICE_NAMEpassword). You will need this information for configuring exports and AOLserver.

          SVRMGR> create user $OPENACS_SERVICE_NAME identified by $OPENACS_SERVICE_NAMEpassword default tablespace $OPENACS_SERVICE_NAME
              temporary tablespace temp quota unlimited on $OPENACS_SERVICE_NAME;
          SVRMGR> grant connect, resource, ctxapp, javasyspriv, query rewrite to $OPENACS_SERVICE_NAME;
          SVRMGR> revoke unlimited tablespace from $OPENACS_SERVICE_NAME;
          SVRMGR> alter user $OPENACS_SERVICE_NAME quota unlimited on $OPENACS_SERVICE_NAME;
          SVRMGR> exit;

          Your table space is now ready. In case you are trying to delete a previous OpenACS installation, consult these commands in Deleting a tablespace below.

        8. Make sure that you can login to Oracle using your service_name account:

          [$OPENACS_SERVICE_NAME ~]$ sqlplus $OPENACS_SERVICE_NAME/$OPENACS_SERVICE_NAMEpassword
          SQL> select sysdate from dual;
          SYSDATE
          ----------
          2001-12-20
          SQL> exit;

          You should see today's date in a format 'YYYY-MM-DD.' If you can't login, try redoing step 1 again. If the date is in the wrong format, make sure you followed the steps outlined in Troubleshooting Oracle Dates

      • Prepare PostgreSQL for an OpenACS Service. 

        • PostgreSQL:

          Create a user in the database matching the service name. With default PostgreSQL authentication, a system user connecting locally automatically authenticates as the postgres user of the same name, if one exists. We currently use postgres "super-users" for everything, which means that anyone with access to any of the openacs system accounts on a machine has full access to all postgresql databases on that machine.

          [root root]# su - postgres
          [postgres pgsql]$ createuser -a -d $OPENACS_SERVICE_NAME
          CREATE USER
          [postgres pgsql]$ exit
          logout
          [root root]#
        • Create a database with the same name as our service name, $OPENACS_SERVICE_NAME. The full pathname for createdb needs to be used, since the pgsql directory has not been added to the $OPENACS_SERVICE_NAME bash profile.

          [root root]# su - $OPENACS_SERVICE_NAME
          [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/createdb -E UNICODE $OPENACS_SERVICE_NAME
          CREATE DATABASE
          [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
          su - $OPENACS_SERVICE_NAME
          /usr/local/pgsql/bin/createdb -E UNICODE $OPENACS_SERVICE_NAME
        • Automate daily database Vacuuming. This is a process which cleans out discarded data from the database. A quick way to automate vacuuming is to edit the cron file for the database user. Recommended: VACUUM ANALYZE every hour and VACUUM FULL ANALYZE every day.

          [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ export EDITOR=emacs;crontab -e

          Add these lines to the file. The vacuum command cleans up temporary structures within a PostGreSQL database, and can improve performance. We vacuum gently every hour and completely every day. The numbers and stars at the beginning are cron columns that specify when the program should be run - in this case, whenever the minute is 0 and the hour is 1, i.e., 1:00 am every day, and every (*) day of month, month, and day of week. Type man 5 crontab for more information.

          0 1-23 * * * /usr/local/pgsql/bin/vacuumdb --analyze $OPENACS_SERVICE_NAME
          0 0 * * * /usr/local/pgsql/bin/vacuumdb --full --analyze $OPENACS_SERVICE_NAME

          Depending on your distribution, you may receive email when the crontab items are executed. If you don't want to receive email for those crontab items, you can add > /dev/null 2>&1 to the end of each crontab line

        • Add Full Text Search Support (OPTIONAL)

        • At this point the database should be ready for installing OpenACS.

    4. Configure an AOLserver Service for OpenACS. 

      1. The AOLserver architecture lets you run an arbitrary number of virtual servers. A virtual server is an HTTP service running on a specific port, e.g. port 80. In order for OpenACS to work, you need to configure a virtual server. The Reference Platform uses a configuration file included in the OpenACS tarball, /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl. Open it in an editor to adjust the parameters.

        [root root]# su - $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc
        [$OPENACS_SERVICE_NAME etc]$ emacs config.tcl
        

        You can continue without changing any values in the file. However, if you don't change address to match the computer's ip address, you won't be able to browse to your server from other machines.

        • httpport - If you want your server on a different port, enter it here. The Reference Platform port is 8000, which is suitable for development use. Port 80 is the standard http port - it's the port used by your browser when you enter http://yourserver.test. So you should use port 80 for your production site.

        • httpsport - This is the port for https requests. The Reference Platform https port is 8443. If http port is set to 80, httpsport should be 443 to match the standard.

        • address - The IP address of the server. If you are hosting multiple IPs on one computer, this is the address specific to the web site. Each virtual server will ignore any requests directed at other addresses.

        • server - This is the keyword that, by convention, identifies the service. It is also used as part of the path for the service root, as the name of the user for running the service, as the name of the database, and in various dependent places. The Reference Platform uses $OPENACS_SERVICE_NAME.

        • db_name - In almost all cases, this can be kept as a reference to $server. If for some reason, the tablespace you are using is different than your servername, then you can set it here. You should have a good reason for doing this.

        • servername - This is just a *pretty* name for your server.

        • user_account - The account that will both own OpenACS files and connect to the database (for Postgresql).

        • debug - Set to true for a very verbose error log, including many lines for every page view, success or failure.

      2. AOLserver is very configurable. These settings should get you started, but for more options, read the AOLserver docs.

      3. Enable OpenFTS Full Text Search (OPTIONAL)

      4. Install nsopenssl for SSL support. (OPTIONAL)

    5. Verify AOLserver startup. 

      1. Kill any current running AOLserver processes and start a new one. The recommended way to start an AOLserver process is by running the included script, /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/run. If you are not using the default file paths and names, you will need to edit run.

        If you want to use port 80, there are complications. AOLserver must be root to use system ports such as 80, but refuses to run as root for security reasons. So, we call the run script as root and specify a non-root user ID and Group ID which AOLserver will switch to after claiming the port. To do so, find the UID and GID of the $OPENACS_SERVICE_NAME user via grep $OPENACS_SERVICE_NAME /etc/passwd and then put those numbers into the command line via -u 501 -g 502. In AOLserver 4, you must also send a -b flag. Do this by editing the run file as indicated in the comments.

        If you are root then killall will affect all OpenACS services on the machine, so if there's more than one you'll have to do ps -auxw | grep nsd and selectively kill by job number.

        [$OPENACS_SERVICE_NAME etc]$ killall nsd
        nsd: no process killed
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/aolserver/bin/nsd-postgres -t /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ [08/Mar/2003:18:13:29][32131.8192][-main-] Notice: nsd.tcl: starting to read config file...
        [08/Mar/2003:18:13:29][32131.8192][-main-] Notice: nsd.tcl: finished reading config file.
      2. Attempt to connect to the service from a web browser. You should specify a URL like: http://yourserver.test:8000

        You should see a page that looks like this. If you imported your files into cvs, now that you know it worked you can erase the temp directory with rm -rf /var/lib/aolserver/$OPENACS_SERVICE_NAME.orig.

        If you don't see the login page, view your error log (/var/lib/aolserver/$OPENACS_SERVICE_NAME/log/$OPENACS_SERVICE_NAME-error.log) to make sure the service is starting without any problems. The most common errors here are trying to start a port 80 server while not root, failing to connect because of a firewall, and aolserver failing to start due to permissions errors or missing files. If you need to make changes, don't forget to kill any running servers with killall nsd.

      3. Automate AOLserver keepalive (OPTIONAL)

    6. Configure a Service with the OpenACS Installer.  Now that you've got AOLserver up and running, let's install OpenACS 5.6.0.

      • You should see a page from the webserver titled OpenACS Installation: Welcome. You will be warned if your version of the database driver is out of date, if AOLserver cannot connect to the database, if any modules are missing or out-of-date, or if there are any problems with filesystem permissions on the server side. But if everything is fine, you can click Next to proceed to load the OpenACS Kernel data model.

      • The next page shows the results of loading the OpenACS Kernel data model - be prepared to wait a few minutes as it works. You should see a string of output messages from the database as the datamodel is created. You'll see the line:

        Loading package .info files ... this will take a few minutes

        This will really take a few minutes. Have faith! Finally, another Next button will appear at the bottom - click it.

      • The following page shows the results of loading the core package data models. You should see positive results for each of the previously selected packages, but watch out for any errors. Eventually, the page will display "Generating secret tokens" and then "Done"- click Next.

      • You should see a page, "OpenACS Installation: Create Administrator" with form fields to define the OpenACS site administrator. Fill out the fields as appropriate, and click Create User.

      • You should see a page, "OpenACS Installation: Set System Information" allowing you to name your service. Fill out the fields as appropriate, and click Set System Information

      • You'll see the final Installer page, "OpenACS Installation: Complete." It will tell you that the server is being restarted; note that unless you already set up a way for AOLserver to restart itself (ie. inittab or daemontools), you'll need to manually restart your service.

        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/aolserver/bin/nsd-postgres -t /var/lib/aolserver/$OPENACS_SERVICE_NAME/config.tcl
      • Give the server a few minutes to start up. Then reload the final page above. You should see the front page, with an area to login near the upper right. Congratulations, OpenACS 5.6.0 is now up and running!

    Installation Option 3: Install from CVS

    If you want to track fresh code developments inbetween releases, or you are an OpenACS core developer, you may want to install from CVS. This is identical to Option 2 except that you get the files from CVS instead of the tarball: CVS Checkout Instructions. So, instead of tar xzf /var/tmp/openacs-5.6.0.tgz, cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot co acs-core.

    Next Steps

    • Use daemontools supervise and svc, or inittab, to automate server startup and shutdown.

    • Install Full Text Search (OPTIONAL). If you have installed OpenFTS and enabled OpenFTS, you can now install the OpenFTS Driver package and Full Text Search Engine package in the OpenACS service.

    • This is a good time to make a backup of your service. If this is a production site, you should set up automatic nightly backups.

    • If you want traffic reports, set up analog or another log processing program.

    • Follow the instruction on the home page to change the appearance of your service or add more packages. (more information)

    • Proceed to the tutorial to learn how to develop your own packages.

    • Set up database environment variables for the site user. Depending on how you installed Oracle or PostGreSQL, these settings may be necessary for working with the database while logged in as the service user. They do not directly affect the service's run-time connection with the database, because those environmental variables are set by the wrapper scripts nsd-postgres and nsd-oracle.

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ emacs .bashrc

      Put in the appropriate lines for the database you are running. If you will use both databases, put in both sets of lines.

      • PostgreSQL:

        export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib
        export PATH=$PATH:/usr/local/pgsql/bin
      • Oracle. These environment variables are specific for a local Oracle installation communicating via IPC. If you are connecting to a remote Oracle installation, you'll need to adjust these appropriately. Also, make sure that the '8.1.7' matches your Oracle version.

        export ORACLE_BASE=/ora8/m01/app/oracle
        export ORACLE_HOME=$ORACLE_BASE/product/8.1.7
        export PATH=$PATH:$ORACLE_HOME/bin
        export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
        export ORACLE_SID=ora8
        export ORACLE_TERM=vt100
        export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data

      Test this by logging out and back in as $OPENACS_SERVICE_NAME and checking the paths.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
      logout
      [root src]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME ~]$ env
      
      • For PostgreSQL, you should see:

        LD_LIBRARY_PATH=:/usr/local/pgsql/lib
        PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:\
          /root/bin:/usr/local/pgsql/bin:/usr/local/pgsql/bin
      • For Oracle:

        ORACLE_BASE=/ora8/m01/app/oracle
        ORACLE_HOME=/ora8/m01/app/oracle/product/8.1.7
        PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:\
          /root/bin:/ora8/m01/app/oracle/product/8.1.7/bin
        LD_LIBRARY_PATH=/ora8/m01/app/oracle/product/8.1.7/lib:/lib:/usr/lib
        ORACLE_SID=ora8
        ORACLE_TERM=vt100
        ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
    • Test your backup and recovery procedure.

    • Set up External uptime validation.

    ($Id: openacs.html,v 1.49 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/templates.html0000644000175000017500000002606311501005400022674 0ustar frankiefrankie Using Templates in OpenACS

    Using Templates in OpenACS

    By Pete Su

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Overview

    The OpenACS Template System (ATS) is designed to allow developers to cleanly separate application logic from display logic. The intent is to have all of the logic related to manipulating the database and other application state data in one place, and all the logic related to displaying the state of the application in another place. This gives developer's quicker customization and easier upgrades, and also allows developers and graphic designers to work more independently.

    In ATS, you write two files for every user-visible page in the system. One is a plain .tcl file and the other is a special .adp file. The .tcl file runs a script that sets up a set of name/value bindings that we call data sources. These data sources are generally the results of Tcl and/or database queries or some combination thereof. The template system automatically makes them available to the .adp file, or the display part of the template, which is written in a combination of HTML, special template related tags, and data source substitutions.

    In the overall context of our example OpenACS Notes application, this document will show you how to set up a simple templated page that displays a form to the user for entering new notes into the system. In later sections of the DG, we'll discuss how to develop the pages that actually add notes to the database, how to provide a separate instance of the Notes application to every user and how to design appropriate access control policies for the system.

    Entering Notes

    In order for the Notes application to be useful, we have to allow users to enter data into the database. Typically, this takes two pages: one that displays a form for data entry, and another page that runs the code to update the database and tells the user whether the operation failed. In this document, we will use the template system to build the first of these pages. This isn't a very interesting use of the system since we won't be displaying much data, but we'll cover more on that end later.

    The .tcl file for the form entry template is pretty simple. Here, the only thing we need from the database is a new ID for the note object to be inserted. Open up a file called note-add.tcl in the ROOT/packages/notes/www directory, and put the following code in it:

    
    ad_page_contract {
    
        Form to add a note in OpenACS Notes.
    
        @author Jane Coder 
        @creation-date 11 Oct 2000
    
    } -properties {
        note_id:onevalue
        submit_label:onevalue
        target:onevalue
        page_title:onevalue
    } -query {
    }
    
    set user_id [ad_verify_and_get_user_id]
    
    db_1row user_name {
        select first_names || ' ' || last_name as user_name 
        from users
        where forum_id = :user_id
    }
    
    set page_title "Add a note for $user_name"
    set submit_label "Add"
    set target "note-add-2"
    set note_id [db_nextval acs_object_id_seq]
    
    ad_return_template "note-add"
    
    

    Some things to note about this code:

    • The procedure ad_page_contract is always the first thing a .tcl file calls, if it's under the www/ directory (i.e. not a Tcl library file). It does validation of input values from the HTTP request (i.e. form variables) and in this case, the -properties clause is used to set up the data sources that we will ship over to the .adp part of the page. In this case, we only use the simplest possible kind of data source, called a onevalue, which hold just a single string value. Later on, we'll see how to use more powerful kinds of data sources for representing multiple rows from an SQL query. You also include overall documentation for the page in the contract, and OpenACS has automatic tools that extract this documentation and make it browsable.

    • After being declared in the ad_page_contract, each property is just a simple Tcl variable. The template system passes the final value of the variable to the .adp template when the .tcl file is processed.

    • The call ad_return_template tells the template system what .adp template page to fetch to display the properties that have been processed. By default, the template system will look for a file by the same name as the .tcl file that just ran, but with an .adp extension.

    Next we write the corresponding .adp page. This page outputs HTML for the form, and also contains placeholders whose values are substituted in from the properties set up by the .tcl file. Create a file called note-add.adp in your editor, and insert this text:

    
    <master src="master">
    <property name="title">@page_title@</property>
    <property name="context_bar">@context_bar@</property>
    
    <form action=@target@>
    <p>Title: 
    <input type="text" name="title" value="">
    </p>
    <p>Body: 
    <input type="text" name="title" value="">
    </p>
    <p>
    <center>
    <input type=submit value="@submit_label@">
    </center>
    </p>
    </form>
    
    

    The main point to note here is: when you want to substitute a value into a page, you put the name of the data source between two "@" characters. Another point to note is the use of a master template: Master templates allow you do centralize display code that is used throughout an application in a single file. In this case, we intend to have a master template that does the standard page headers and footers for us - create the master.adp file, which looks like this:

    
    <%= [ad_header $title] %> 
    <h2>@title@</h2> 
    <%= [eval ad_context_bar $context_bar] %> 
    <hr> 
    <slave> 
    <br clear="all"> 
    <%= [ad_footer] %>
    
    

    The main subtlety in this code is the inline Tcl code for running procs to build the header, footer, context bar, etc. Also, note the property substitutions that happen here, the values of which are set up in the <property> tags in the slave page.

    After putting all these files into ROOT/packages/notes/www, you should be able to go to /notes/ URL for your server and see the input form.

    Summary

    Templates separate application logic from display logic by requiring the developer to write pages in two stages, one file for database queries and application logic, and another for display. In OpenACS, the logic part of the page is just a .tcl that sets up data sources that are used by the display part of the page. The display part of the page is an .adp file with some special tags and notations for dealing with display logic and inserting properties into the text of the page. Later on we'll get into templates more deeply, and show how to use database queries as data sources.

    Documentation

    Templating system documentation

    ($Id: templates.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-distribute.html0000644000175000017500000000612411501005400024711 0ustar frankiefrankie Prepare the package for distribution.

    Prepare the package for distribution.

    Browse to the package manager. Click on tutorialapp.

    Click on Generate a distribution file for this package from the filesystem.

    Click on the file size (37.1KB) after the label Distribution File: and save the file to /var/tmp.

    Package development guidelines

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/win2k-installation.html0000644000175000017500000006611211501005400024426 0ustar frankiefrankie OpenACS Installation Guide for Windows2000

    OpenACS Installation Guide for Windows2000

    by Matthew Burke and Curtis Galloway

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    NOTE: These instructions were valid for ACS v4, but have not been tested with OpenACS and the ArsDigita binary distributions are no longer available. Currently (10/2003), the best option to get OpenACS 5.6.0 running on Windows is to use VMware and John Sequeira's Oasis VM distribution

    Overview

    With the recent release of a win32 version of AOLserver, it is now possible to run the OpenACS on Windows2000 and Windows98. This document explains the steps necessary to get the OpenACS installed and running on your machine.

    Note:

    We do not recommend running a production server on Windows98. But the platform is more than sufficient for working the problem sets and for getting a feel for the OpenACS.

    You'll need to use the ArsDigita binary distribution of AOLserver for the Win32 platform, which contains patches for several problems we have come across in the default AOLserver binary distribution. See the ArsDigita AOLserver 3 distribution page for details.

    You can download the binary distribution from the ArsDigita download page under "ArsDigita AOLserver 3 Binary Distribution for Win32." Please read the release notes in the distribution for configuration notes specific to the version you are downloading.

    Prerequisites

    It is helpful if you have Oracle interMedia Text for full-text searches. We're also trying to make our system work with the PLS System, available free from http://www.pls.com.

    Although the zsh shell is the only command-line tool required to install the OpenACS, if you are a UNIX person used to typing ls instead of dir you'll get along much better with the Cygwin toolkit from RedHat (available at http://sourceware.cygnus.com/cygwin). This is a development library and set of tools that gives you a very UNIX-like environment under Windows. In particular, it includes bash, gzip and tar, which you can use to perform the OpenACS installation instead of WinZip and zsh.

    Your Oracle installation

    When you install Oracle, a good rule of thumb is "every default setting is wrong." We will not discuss Oracle configuration here except to mention that the OpenACS requires Oracle's NLS_DATE_FORMAT parameter be set to 'YYYY-MM-DD'. Fixing this depends on whether Oracle Administration Assistant for Windows NT (yes, that's Windows

    NT
    ) will run on your machine or not (in some cases, it will complain about Microsoft Managment Console not being installed).

    If it runs on your machine, proceed as follows:

    1. Run Oracle Administration Assistant for Windows NT

    2. Navigate using the Explorer-style control in the left panel and select the Oracle Home for the database you wish to use.

    3. Bring up its properties dialog and add a parameter NLS_DATE_FORMAT with value 'YYYY-MM-DD' (without the quotes)

    4. Verify the date format by logging into the database using SQL Plus and run the following query: select sysdate from dual;

    Otherwise you will need to perform a little registry surgery as follows:

    1. Run regedit and navigate down the registry keys to HKEY_LOCAL_MACHINE\Software\ORACLE.

    2. Choose the appropriate subtree; this will be HOME0 if you only have on einstallation of Oracle.

      If you are an Oracle achiever and have more than one Oracle installation on your machine, you will see HOME0, HOME1, HOME2, etc. Choose the subtree that corresponds to the Oracle installtion you wish to use with the OpenACS.

    3. If the NLS_DATE_FORMAT key is already present, double-click on its value and change it to 'YYYY-MM-DD' (without the quotes). If the key does not exist, choose Edit->New->String Value from the menu and type NLS_DATE_FORMAT for the name of the new value to create it. Then double-click on the empty value to change it.

    4. Verify the date format by logging into the database using SQL Plus and run the following query: select sysdate from dual;

    For more information on Oracle configuration look at http://photo.net/wtr/oracle-tips or search the OpenACS forums. One other note: the "nuke a user" admin page and Intermedia won't run unless you set open_cursors = 500 for your database.

    The ArsDigita binary installation

    Extract the ArsDigita AOLserver distribution onto the C: drive into the default aol30 directory. You can install it on any drive, but it will make your life easier if you keep the AOLserver binary and your OpenACS instance on the same drive. For the rest of these instructions, we'll assume that you used drive C:.

    Untar the OpenACS

    We recommend rooting webserver content in c:\web. Since most servers these days are expected to run multiple services from multiple IP addresses, each server gets a subdirectory from c:\web. For example, http://scorecard.org would be rooted at c:\web\scorecard on one of our machines and if http://jobdirect.com were on the same box then it would be at c:\web\jobdirect.

    For the sake of argument, we're going to assume that your service is called "yourdomain", is going to be at http://yourdomain.com and is rooted at c:\web\yourdomain in the Windows 2000 file system. Note that you'll find our definitions files starting out with "yourdomain.com".

    • download the OpenACS (see above) into c:\temp\acs.tar.gz

    • use WinZip (or equivalent) to extract the files to c:\web\yourdomain

    You'll now find that c:\web\yourdomain\www contains the document root and c:\web\yourdomain\tcl contains Tcl scripts that are loaded when the AOLserver starts up.

    Feeding Oracle the Data Model

    The entire server will behave in an unhappy manner if it connects to Oracle and finds that, for example, the users table does not exist. Thus you need to connect to Oracle as whatever user the AOLserver will connect as, and feed Oracle the table definitions.

    • load the states, country_codes and counties tables using the load-geo-tables shell script in the c:\web\yourdomain\www\install directory. You will need to open a console window and run

      zsh load-geo-tables foo/foopassword
      

      You most likely will see a slew of "Commit point reached . . . " messages. This does not indicate a problem.

    • cd to c:\web\yourdomain\www\doc\sql and feed Oracle the .sql files that you find there. There is a meta-loader file, load-data-model.sql, that includes the other files in the proper order. To use it, open a console window and run

      sqlplus foo/foopassword < load-data-model.sql
      
    • If you have interMedia installed, while still in c:\web\yourdomain\www\doc\sql, run

      zsh load-site-wide-search foo foopassword ctxsys-password
      

      Note that there's no slash between foo and foopassword here. The third argument, ctxsys-password, is the password for interMedia Text's special ctxsys user.

    Configuring AOLserver

    You will need two configuration files. The first is a Tcl file with configuration information for AOLserver. This should be called yourdomain and should be located in c:\aolserve3_0. The second is an .ini file that configures the OpenACS and is discussed below. Note that pathnames in yourdomain must use forward slashes rather than the Windows back slashes. This is also true for the .ini file.

    The following items must be defined in yourdomain:

    • three database pools: main, subquery, and log. They must be named as such. The default pool will be "main".

    • the auxconfig directory which contains the .ini file: c:\web\yourdomain\parameters

    • the pageroot: c:\web\yourdomain\www

    • the directory containing the TclLibrary: c:\web\yourdomain\tcl

    You can use our template file as a starting point (you'll need to save this file with a rather than .txt extension).

    Configuring OpenACS itself

    If you want a system that works, go to c:\web\yourdomain\parameters and copy ad.ini to yourdomain.ini (or any other name different from ad.ini). You don't actually have to delete ad.ini.

    Each section of yourdomain.ini has a hardcoded "yourservername" in the name (e.g. [ns/server/yourservername/acs]). This means that the OpenACS will ignore your configuration settings unless your AOLserver name happens to be "yourservername". Therefore you must go through yourdomain.ini and change "yourservername" to whatever you're calling this particular AOLserver (look at the server name in the nsd file for a reference).

    Unless you want pages that advertise a community called "Yourdomain Network" owned by "webmaster@yourdomain.com", you'll probably want to edit the text of yourdomain.ini to change system-wide parameters. If you want to see how some of these are used, a good place to look is c:\web\yourdomain\tcl\ad-defs. The Tcl function, ad_parameter, is used to grab parameter values from the .ini file.

    Starting the Service

    Now you're ready to start things up. Before installing as a Windows service, you might want to test the setup for configuration errors. Open up a console window and go to c:\aol30. Then run

    bin\nsd -ft yourdomain.tcl
    

    This will print all the AOLserver messages to the console so you can see them.

    Try to connect to your new server with a web browser. If you see the message "Error in serving group pages", you probably forgot to copy the ad.ini file in c:\web\yourdomain\parameters If everything seems ok, you can kill the server with Control-c and then issue the following command to install as a Windows service:

    bin\nsd -I -s yourdomain -t yourdomain.tcl
    

    You can now configure error recovery and other Windows aspects of the service from the Services control panel. If you make further changes to yourdomain or yourdomain.ini you should stop and start the service from the Services control panel.

    Configuring Permissions

    Now, you need to protect the proper administration directories of the OpenACS. You decide the policy although we recommend requiring the admin directories be accessible only via an SSL connection. Here are the directories to consider protecting:

    • /doc (or at least /doc/sql/ since some AOLserver configurations will allow a user to execute SQL files)

    • /admin

    • any private admin dirs for a module you might have written that are not underneath the /admin directory

    Adding Yourself as a User and Making Yourself a Sysadmin

    OpenACS will define two users: system and anonymous. It will also define a user group of system administrators. You'll want to add yourself as a user (at /register/ ) and then add yourself as as member of the site-wide administration group. Start by logging out as yourself and logging in as the system user (email of "system"). Change the system user's password. Visit the https://yourservername.com/admin/ug/ directory and add your personal user as a site-wide administrator. Now you're bootstrapped!

    If you do not know what the system user's password is connect to Oracle using SQL Plus and run the following query:

    select password from users where last_name = 'system';
    

    Closing Down Access

    The OpenACS ships with a user named "anonymous" (email "anonymous") to serve as a content owner. If you're operating a restricted-access site, make sure to change the anonymous user's password. In recent versions of the OpenACS you cannot log into "anonymous" because the account does not have a valid user state. Log in as a sysadmin and change the anonymous user's password from https://yourservername/admin/users. You should read the documentation for user registration and access control and decide what the appropriate user state is for anonymous on your site.

    Where to Find What

    A few pointers:

    • the /register directory contains the login and registration scripts. You can easily redirect someone to /register/index to have them login or register.

    • the /pvt directory is for user-specific pages. They can only be accessed by people who have logged in.

    Making sure that it works

    Run the acceptance tests in /doc/acceptance-test

    Running Multiple Instances of the OpenACS

    You can run multiple instances of the OpenACS on a physical machine but they must each be set up as a separate Windows service. Each instance of the OpenACS must have its own:

    • Oracle tablespace and a user account with the appropriate permissions on that tablespace. Each of these tablespaces must have the OpenACS data model loaded.

    • file with the appropriate settings including server name, auxconfig, ipaddress, and port.

    • Copy of the acs files in an appropriate directory under c:\web.

    Suppose you wish to run two services: lintcollectors.com and iguanasdirect.com. You would need the following:

    • an Oracle tablespace, lintcollectors with a user lintcollectors and password secretlint

    • an Oracle tablespace, iguanasdirect with a user iguanasdirect and password secretiguanas

    For each of these tablespaces/users you would load the OpenACS data model as described above. Then in c:\aolserver3_0 create files for each service, i.e. lintcollectors and iguanasdirect. These files would point to their respective pageroots, c:\web\lintcollectors\www and c:\web\iguanasdirect\www; their respective auxconfigdirs, c:\web\lintcollectors\parameters and c:\web\iguanasdirect\parameters; etc. In the respective auxconfigdirs would be the files lintcollectors.ini and iguanasdirect.ini.

    Now open a console window and go to c:\aol30. You'll start up the two services as follows:

    bin\nsd -I -s lintcollectors -t lintcollectors.tcl
    bin\nsd -I -s iguanasdirect -t iguanasdirect.tcl
    

    In the services control panel you should see two services: AOLserver-lintcollectors and AOLserver-iguanasdirect.

    ($Id: win2k-installation.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/analog-install.html0000644000175000017500000000675711501005400023613 0ustar frankiefrankie Install Analog web file analyzer

    Install Analog web file analyzer

    Download the Analog source tarball in /tmp. Unpack, compile, and install analog.

    [root aolserver]# cd /usr/local/src
    [root src]# tar xzf /tmp/analog-5.32.tar.gz
    [root src]# cd analog-5.32
    [root analog-5.32]# make
    cd src && make
    make[1]: Entering directory `/usr/local/src/analog-5.32/src'
    (many lines omitted)
    ***IMPORTANT: You must read the licence before using analog
    ***
    make[1]: Leaving directory `/usr/local/src/analog-5.32/src'
    [root analog-5.32]# cd ..
    [root src]# mv analog-5.32 /usr/share/
    [root src]#
    cd /usr/local/src
    tar xzf /tmp/analog-5.32.tar.gz
    cd analog-5.32
    make
    cd ..
    mv analog-5.32 /usr/share/

    See also Set up Log Analysis Reports

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/files/0000755000175000017500000000000011724401447021125 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/files/restart-aolserver.txt0000644000175000017500000000242707426545670025372 0ustar frankiefrankie#!/usr/bin/perl ## Restarts an AOLserver. ## Takes as its only argument the name of the server to kill. ## bquinn 6/16/2000 with help from {ryanlee, doug}@arsdigita ## This is a perl script because it needs to run setuid root, ## and perl has fewer security gotchas than most shells. ## ## Make sure that $PIDFILE points to the right location. use strict; undef %ENV; $ENV{'PATH'} = '/sbin:/bin'; if (scalar(@ARGV) == 0) { die "Don't run this without any arguments!"; } my $server = shift; $server =~ /^([\w-]*)$/; my $service_name = $1; my $PIDFILE = "/usr/local/aolserver/log/nspid.$service_name"; my $pid; $< = $>; # set realuid to effective uid (root) # Get the PID of the process to kill. open(IN,"$PIDFILE") || die "No such server\n"; while() { chomp($_); $pid=$_; } close(IN) || die "Problem closing PID file\n"; # Remove the PID file. We have to delete the file to make sure that a subsequent call # to this script will kill some other process. We delete the file before the process dies # because if the service is set to respawn then we may delete the new pid file. my $cmd ="rm -f $PIDFILE"; $cmd =~ /^(.*)$/; my $untaint_cmd = $1; `$untaint_cmd`; # Issue the kill $pid =~ /^(.*)$/; my $untaint_pid = $1; print "Killing $untaint_pid\n"; kill 9, $untaint_pid; openacs-5.7.0/packages/acs-core-docs/www/files/qmail-smtpd-log-run.txt0000644000175000017500000000013607676147035025512 0ustar frankiefrankie#!/bin/sh exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail/smtpd openacs-5.7.0/packages/acs-core-docs/www/files/groups.dia0000644000175000017500000001045310032262136023115 0ustar frankiefrankie‹íÝsÛ6ÀßõWpÜWÆ7ê’N®›»™vrsIïUCKŒÍ«Li(:©ïáþöÃeËéÈ¡{ÓIcÓ4V ±ûËݿüôçí4ùšW‹bV¾;#Ÿ%y9žMŠòúÝÙïŸÿv¡Î~z?øË¤È~4¯«ì61¿Q.ìwïÎnêzþãåå·oßÐô~‘Õ³ M‹;´È/ÿ—M§Ù¥¹éòìý IV˜duf¯5W³º®Š«»:OÊì6wv•ÿ¸®fwåäÌßÕÜ7žMgUò5›¾;ûá‹ûsvÙ4sù¤gÚžg×ùU•gt7Í­wizžWëÍÞÎg‹ÂÜRßÏ7néhÇþåžæ®…¹©¼~ÿÃþƒÿHͅǶÚ>h§ú6«®‹rSŽy6Sÿ (R”Òåsx¹ˆ«ø"¦ñETñE‹Ñ|VÕUVÔ›b®f³iž•^R]Ýå»ËYŒ³©2Ïu…ìÞú—¢®gßùü_²éb›øËÚóRM¼®ŠÉóŠøäŽŽV¾“úfôçs #*vb^À}<_‹Eq5ÍÛúP”µ—ÀÛ¿ï§ùõwälò㯎 ßZ§ÑŸ¨\äâåFÿú®˜ä‹ï ¶§÷t´tÓÜvù½§¾~ß¶Æ_ZC°1Íîóªiþ¯ðMšÜØ•§0»úO>®›î}úå×ä"ùœ-þ8{œG˜YD1ywö?}4ë1 Û·ñl泇$œ_§ŠÐe6ºD\]­K¨ÌçÏÊëiþ Å aCÂÃJŸ_H¤5Uz7¡ù4¿gU¹‰û>ûæÄ83²Ù¿¥ Qc¥T€€›¼¸¾©»%0DqJÈn®fÕ$¯FOÕ³EAÓ/ö¿Ýde¹kòßÄâfömÔ2qÝ‚‚/óeZÌG7³ªøï¬¬³iT1F—ëbOÈ<›LžNG6àÇ‚íÖ|ÿYŸ}1k÷t½[7Ó~rßÚ¤ü‚þ•_‹:¯òIòûÂXÁA6ŸOÍã«9ÙA1?ƒÅ®·cÞ}Û§±×“/Ùm1½7:+gÉ¢¾·öÛXcÿ«ϧ_sûVW1óòO°aZßž ò” möÓYNÎÏ/4"Zr&oÝ>t:‡‡ 2³ðëò6o‰yywÛ2nòÔÆÿ®9Ìå#¾wâ9 å¹yW”ÈÔpj”Ædº•$—’Ôð‚"Ò|+×4*Ù{éå6tOß2×_ݧ®30÷ô™KŸoòäŸwW³ lÂ^”6vL!i ˆí±Ÿrçd¯#–#–¤(݃Ól卯m¾°ÃÃàv/~s܆­Ø l}“lŃßËêÑ¡ýwad̪Áql±½3–0·Nlÿ„­³:oA, G¬B@Ŭ‘ÒˆËiÆì·QÙ íß6|5øD X™†•i y$’‹Áoù핱7Å<ùW>uëщÜ>\Uù ꜤçÖ’rŽó>°Îƒ±n™—Æ$º@ØÉ0ÿ ’ŒÛ‘’ÆÆy@¿¶%¹br9€<ÈÕàç¦e ð’«Áøñ2 <Ê1¢šX*÷ ò”ïê‹PzŽ£ºæ„ -Œ .†”Žy.aD¨˜éÖV+Þãa]øÈyˆX÷ÈF…,g|ð[V”É'Ûvã9 UG‹üÚS kï1\¥«sjÜeœj k|ºÊ`7ÙmXÄÞ]fˆYC…Áôœ#¥"ã5´_[¹ÊaÓ@, ö"V¬ öÃä¶( ó3{rH•´¥Bsã¸hí>¹Òð³Oâœð¨Çž¸‘ÀŒ+kÏ=a!è9I þR÷ØÓîÝÚ*& ˆÜ¼¾M¼r5ø0-Æ ZmÄ„mÅ;|tN솓@Óø»»*§Ü¾0uY؈0¸Á©4Þ+!fÊ—¥a}ÚÎa…}]Ø×`G¶n Ѳ×!Hk·ÁµLÂãÖ¡O] |ìƒÃ©MâÎ »½óÂÁÛ†ä¼bðŠß&dñÊ¢ó /FÆ%þj¼d`j¦Âqá^¡jè4ɪ‰%«Õˆ–´Áy¶Œ¯JãŸhj¤PŒˆ[ræ^$ÇoCÆF“MS£bF£w£Ñ6ø¢YŒõiDD‹o1>Tã6ƒœÈgiè%;Ÿ^ØÊfh3µ¤ÔK2Óð¡Í7€mÖ'û v“kt¹ååÄug—N>“‹* )AVãN‚ÇwÕ×|4)æùŽógÖüvk~Z”ùÈYªõ¦5bË}?û†Ì00cv±ñ,–?InÌ o¬b=sþeòøÓõd¶¿KšßÅOoæ×\û@=;8Û‡vv3j(–XrZµ;Ц×sãêe×9à:®7‡Ük`5=ZV³“aµ´BjbH :©/0Ò:ÕÀë¾yý«y6mºÈ{ÑE;üR„ùΉ²¶ÕF¢˜¶¢aœÚ]i%‰ «)ŒìC'[»Ú}`çóMfÄŽçëæ±ù ‰ªè‡ÖA ƒâ@:|<ЅºÁuÞL‘Tœ©Fÿ„w]© çöœbYÿÚ»Ë$²S‰^ A²/§UöÙŒy*Ïí!-yL%dHyQÜ n#j¸"Û]8~_Ö%·O6‚'Û=Á£íßÔq E¶à“„!A©'4%QíÕŠ(M‰%¥îõÀ^½á²Îq»eì?ƒ£Â™=äm¾æçSÝÙ’YV–ZÙXKå‰wœÛÚËy¦¯yùTH¤CÓ×8gZ^«GÌOïT( XÆï Z:Ÿ4ò®öª(·©mw0ýrr{ÚàGð‡»#¸ÃÜay ¼«Ó:Gí¡v+)UîdšÛTªXÓ±8”àõµ2=äÔš:Óu/êAm ¸ÔLMwÍ»¶µzxQ8µ¢l®&a/ö°!Í[ÇX¤G@ú¢Ôî'ó„M„ŽwM„þž;A”xœÛ*#ïç›]켑ÊWǶ @yz”³ž’§wH‰]’¶ç¸•C1“MÂE»†‹w• ^ùk+`²>ß‚r´ŽÈzA£Èî Ѩ›`¥þŒ.ó $…}ÛQ4CåÇL"ÍÂãðŒ;èÓ;G-аCZ|9‰'°Í$`/"Ú‹ÖÁç⣚Œð¸Ô½5FâÊñ2’1ûõIŒÏ7yb«7.ó"—Vc‘e’%eþ-ù8ÏË?J"æâ¢Î¦¾vÔo̶D£Û–ÍQ ~R¤*Q,<‚O2ÕÓ¢H†°?,ƒmÆ Ž4'ö0,GŒÇ-Ô¹mÊD)„±R*b±(ãÛAÕG¨úøR!¯¨ U6ŸOÍ£²´9¬ƒ;Ð;²…BZ 録æP‹jè–áÁ÷rY?,î‚®´£BÊà{™µ> îð®ºÊ#…úŽ€ÓcÄéx1òV 8Ú?GýY{šî¥8Û›Aè§:«[cn‚cÿ/˜ÜG-G+†y)Æ6T£ö¸&â"*Dƒû¶• ü6 n/p:òv¹o׺½U>X÷kF½yTû)Ï´OÕÌSä×áµb¼ãñ2íK:¦‘]ÞྭÖ@ëÃÐú6¿½2öîÆ<5€u Xs†<«Õû@µî ÕrO¨–«¨æûAµTªÕ§¶>¹-À¥ŽJi”ÞÃ2¯‹ ‰;6€£†GhŠ}ø—D܇©]ëœoûÔ·m-öýµë P ¨>yTC¸Wìp/…T ¬Þ«I_¬æû`5`µ?;¦Å>PÍ#¢œi 4ºwBϳª¾B÷Ohíù›{?Ù‘¾‰‡§XÿÅ^ò6rN} a…mù!–§šWS›/¢çAoíi[ˆEöxiœz…îniNdH¹€Ûæìt”D#,¥¯á¡ˆL‡V2QŒy%aŒ’8[*Ò³Š(*òì®)?áÏ÷àäñ'Nc{ròxt'vLÁÉ'¯'¯Ê}² Þ¾^ÿqÈ~’ ÞÞ½½*_ùJ6,8îDÖ A'ƾM}Ñ×è“×ÖÞ=s£<ÂZ:‡ŸÂŠ4` +”Éš÷p2]Ç΃éü;âkÇÛ/œrH¥¤ ¡·_DW½žp±S9véÍÊÁC겉ô@Ê‘žˆrL¼r˜/†nÇ—7gZ4×ú”c¹ ½kˆèF×Ú>n„ðZL Ñy#‰-DºàE-¢«GG7Ÿ½U‚šl¨IHq#&¤&=®ðq¶±}+F,î ÉΩ¶WÖîuß'azÕ¶|R-„éÃè†i^.§DMçadH)ïCÊ¡=LNã¾5c<¶Šlöò™î~l²#¤Ø-;û!ÈIè‡5Ì’/½sÎ}ˆKï\ȣІàž÷¯Z»ôÜsiC°n´kï}0M¼{n¾8÷\ʦDhF¿ W:b`BöµU)ÂÃvR?.ÁÊÐZ=D&H…”Ò¾ÚQôLáaÜ&:Á‰`. W8D*@¤B¼H3¼JómfTbú¯íAQʹr6…ï/`A𓉼5CDašðt[¦ÐFÞj[IÈ…§3q4‘·£Âoû ¿5°Ø{ø­=…ß7p€kÅ<à;phç &¶0±=ÌÄÖV¶3Æ«²Û’EŒÃµà!w_ÓZy2Û}¢‰¦ò[¤\Ç6_vØÅèšÅŠˆ³XóþÛ4¢‡øBuºeu‘é.I6WHjIö&;¼wÛÌc9T†‚ÊPo-—‡±E³&–ý'óhŽ@òê~“WwTõFP;ÙTÚäG‚òȉ1Ã{‚AÛWi€ŸÑø ô쑞ÿ(?ÞÕmø ?b¿ÿ5­´Â²JKÖTT”‚“¸qBa}Û*P(&9ÕB¥ÀOà瑆ï,òkk:£½c´‰è5n¨Ä”K÷³Å!ÃO4q?ÿ¡ÑûY9)i$¥dxÁJ9µÁâqM£oïiÛ–‡ò7ŠãÛóøÝÍ„å{­¿pà}¶Ö·eàõpTHû§,‘Œ»²”"šú6áåÒ]Gü^+ °%gK¾}¾báÄ Ù(•J!ÃOl¹ÐRÕ>ÙR?ŽŒÊ}áÎûjÝ1åñɸÞǶ[˜ÿ4¯ˆÏµîLàzëzÆ÷Ûð#Vö𸠙Ž;ÇsR ^©Å,AØ[WAʼnTÐÆmËàÊF ,LÙ.û~~Dš!ÂpdÔ !Èž1s?»ÒjD’0NŸoòÄnÿ$æM$ÎR%þ-’¢LjóÓó¼üðó§ä—¬Î’ßf“7gÇ¢ñ׸6)˜±í&>þûivŸWïþó÷ºÊnßþnÄ ÂúPopenacs-5.7.0/packages/acs-core-docs/www/files/qmail-send-run.txt0000644000175000017500000000003507676147035024533 0ustar frankiefrankie#!/bin/sh exec /var/qmail/rc openacs-5.7.0/packages/acs-core-docs/www/files/tcp.smtp.txt0000644000175000017500000000007607653123744023450 0ustar frankiefrankielocalhost:allow,RELAYCLIENT="" 127.0.0.1:allow,RELAYCLIENT="" openacs-5.7.0/packages/acs-core-docs/www/files/osx-postgres-startup-item.tgz0000644000175000017500000000503307766666010026777 0ustar frankiefrankie‹í][oÛÈækø+NÝ‘H꺛ØÜHNÜõ­–‚4OYŠK¬)’;CZÖ&yèî>mP`·@н yHØÞ°oûS²Þ¶h~CÛ3$u±¥È²#Ó…2_àPäœ9gfΜo†ÃÛ¶Ç‚&%µŸ¬«ÒyAÓ Z¹XÄ­¦•KñVËâm I+—K¥R!‡’¦çtM— xn%BȃHmà È9ÛÝM£@éb{àÿÁÏÛÐtm’ÿóåRÏÿ¹‚–Ï£|AËå%Ðf\ޱxËýå²Ú°]•µdù z40“Ú~»…ŠA;˜iÃ0a«?ÍÂ-ÏïBв*±lJÌÀ£]èØA Çoì€Á®íêºÝ íªµX÷Z@Ú,ËKp‹# ìR¯ ¬RB~T«ô¬7º°MB¡j3âÔxKÄAš@ÿ‚ÿñ_u›Ø(3ÎÀÿÅb^ð˜Âÿo<œÄÿå|á8ÿtMð˜+þŸ*KoèYñ|ÿ´V¦ÈrÔÊN<üœÎΔ™ÞlDÿ»ö…¯ÿ”4Áÿi`²ÿSZÿÉç½ ë‚ÿÓÀ\ñÿûß>ïº.*þö¹;6[Æ7œ}âØm⊕ cã•b˜ÝÐæÿùRYð8Ùÿo>œÌÿúñùN/ þOsÅÿ•oÿØ6(å7Xa,Rè]R$È¿‡±ñ›Ð¶á^(ÿ—ÅúO*8ÙÿiðÿÈú?Bð˜+þ’ì_÷­E’б©Õ» @Äu€>ÆÆÿZ€?»à,ëÿÁÿ©` ÿŸûúÿ˜ë¿ù²XÿIsÅÿ+A`ï{Iâ@xªyÿ[Æû=Œÿ¾áFf4œÿ˺XÿOÓøÿM€3¬ÿó%Áÿi`®øÌü^~üõËO¾yùÉç/?þå?¿þËá“§ßýõK±þÓÃØøßó.üú¯XÿI“ýŸÒõ_­Ü÷^+E×sâþÿT0¯üÿê׃WŸ>û÷WŸÂ«'Ï^ýæ‹WÏ¿¬?бñïþð¿xþ+LöZüŸ¹ÿGð:˜+þ}þ«ŸCpÿxŒ?¸hþ/iâùïT0Ùÿi=ÿ[áÿ¼xþ+Ìÿ¯¹¶i®_°-ï´.Úéclü×|ýàç¿ÄýŸé` ÿŸÿó_åÑç¿òâù¯TðŸÿJ‹ÒMé@jKŽÒ¾D$*1É–<É•–$EÒ¥¬¤á0Å•L # $Header: /cvsroot/pgsql/contrib/start-scripts/linux,v 1.3 2001/07/30 ## EDIT FROM HERE # Installation prefix prefix=/usr/local/pgsql # Data directory PGDATA="/usr/local/pgsql/data" # Who to run pg_ctl as, should be "postgres". PGUSER=postgres # Where to keep a log file PGLOG="$PGDATA/server.log" ## STOP EDITING HERE # Check for echo -n vs echo \c if echo '\c' | grep -s c >/dev/null 2>&1 ; then ECHO_N="echo -n" ECHO_C="" else ECHO_N="echo" ECHO_C='\c' fi # The path that is to be used for the script PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin # What to use to start up the postmaster DAEMON="$prefix/bin/pg_ctl" set -e # Only start if we can find pg_ctl. test -f $DAEMON || exit 0 # Parse command line parameters. case $1 in start) $ECHO_N "Starting PostgreSQL: "$ECHO_C su - $PGUSER -c "$DAEMON start -D '$PGDATA' -s -l $PGLOG" echo "ok" ;; stop) echo -n "Stopping PostgreSQL: " su - $PGUSER -c "$DAEMON stop -D '$PGDATA' -s -m fast" echo "ok" ;; restart) echo -n "Restarting PostgreSQL: " su - $PGUSER -c "$DAEMON restart -D '$PGDATA' -s -m fast -l $PGLOG" echo "ok" ;; status) su - $PGUSER -c "$DAEMON status -D '$PGDATA'" ;; *) # Print help echo "Usage: $0 {start|stop|restart|status}" 1>&2 exit 1 ;; esac exit 0 openacs-5.7.0/packages/acs-core-docs/www/files/openacs.txt0000755000175000017500000002670510037754267023342 0ustar frankiefrankie#!/bin/sh # hand off to tcl # The backslash makes the next line a comment in Tcl \ exec tclsh "$0" ${1+"$@"} # program to control OpenACS servers with daemontools ###################################################################### # initialization ###################################################################### set version {$Id: openacs.txt,v 1.1 2004/04/16 12:59:35 joela Exp $} #---------------------------------------------------------------------- # get command line arguments #---------------------------------------------------------------------- set arg_1 [lindex $argv 0] set arg_2 [lindex $argv 1] #---------------------------------------------------------------------- # prepare system settings #---------------------------------------------------------------------- set server_list_file "/etc/openacs/services" set service_dir "/service" set svc_bin "/usr/bin/svc" set svstat_bin "/usr/bin/svstat" set web_base "/var/lib/aolserver" set verbose_status "" set line "----------------------------------------------------------------------\n" ###################################################################### # Procedure Library ###################################################################### #---------------------------------------------------------------------- # inspect services file #---------------------------------------------------------------------- proc init_server_list {} { global servers global verbose_status global hosts global line global server_list_file if { [catch {set fileId [open "$server_list_file"]} result] } { append verbose_status $line append verbose_status "Error reading $server_list_file: $result\n" set file_contents "" } else { set file_contents [string trim [read $fileId] ] close $fileId } while {[regexp {(.[^\n]+)} $file_contents match_fodder row] } { # remove each row as it's handled set remove_count [string length $row] set file_contents [string range $file_contents [expr $remove_count + 1] end] # skip comment lines if { [string equal [string index $row 0] \#] } { continue } set row_data [split $row {:}] set name [lindex $row_data 0] # build an array of all servers in the file array set servers [list "${name}_name" $name \ "${name}_svc_status" "" \ "${name}_time" "" ] } svstat_getinfo return } #---------------------------------------------------------------------- # Inspect the results of svstat #---------------------------------------------------------------------- proc svstat_getinfo {} { global servers global verbose_status global line global svstat_bin global service_dir if { ![catch {set svstat_txt [eval exec $svstat_bin [glob ${service_dir}/*]]} result] } { # pluck out the channel data from svstat: # /service/oacs-5-1: up (pid 21952) 9497 seconds, normally down # ^^^^^^^^ ^^^^^ append verbose_status $line append verbose_status "$svstat_txt\n" while {[regexp {(.[^\n]+)} $svstat_txt match_fodder row] } { set server "" set svc_status "" set time "" # remove each row as it's handled set remove_count [string length $row] set svstat_txt [string range $svstat_txt [expr $remove_count + 1] end] regexp {/service/(.+):} $row match_fodder server regexp {:\s([a-z]+)\s} $row match_fodder svc_status regexp {\s([0-9]+)\sseconds} $row match_fodder time set match_list [array names servers ${server}_name] if {[llength $match_list] > 0} { array set servers [list ${server}_time $time] array set servers [list ${server}_svc_status [string trim $svc_status]] } } } else { append verbose_status $line append verbose_status "supervise error: $result\n" } return } #---------------------------------------------------------------------- # Help #---------------------------------------------------------------------- proc help {} { global version puts "$version Usage: openacs status status report for all sites start {server} start supervised site stop {server} stop supervised site restart {server} restart daemontools-supervised site add {server} Add a server for management by daemontools status verbose verbose status report for all sites help this message " } #---------------------------------------------------------------------- # status report, Mr Sulu #---------------------------------------------------------------------- proc status {} { global servers puts "" puts " all servers |" puts "server | svc |" puts " | uptime |" # 0123456789012345678901234567890123456789012345678901234567890123456789012345 puts "----------------+--------+" set server_name_list [array names servers {*_name}] set real_name_list [list] foreach server $server_name_list { lappend real_name_list [lindex [array get servers $server] 1] } set server_list [lsort $real_name_list] foreach server $server_list { set temp_status [lindex [array get servers ${server}_svc_status] 1] if { [string equal [string trim $temp_status] up] } { set svc_status [lindex [array get servers ${server}_time] 1] } else { set svc_status $temp_status } set channel [lindex [array get servers ${server}_channel] 1] set output [list [format %-16.16s $server]] lappend output [format %8.8s $svc_status] lappend output "" puts [join $output "|"] } return } #---------------------------------------------------------------------- # start #---------------------------------------------------------------------- proc start {server} { global servers # if server is not running, start it set status [lindex [array get servers ${server}_svc_status] 1] if { ![string equal $status "up"]} { puts "Server is not up; starting server" svc_cmd $server start } return } #---------------------------------------------------------------------- # svc_cmd #---------------------------------------------------------------------- proc svc_cmd {server action} { global web_base global servers global svc_bin global svstat_bin global service_dir set flag [string map { start "-u" stop "-d" reload "-t" restart "-t" } $action] set match_list [array names servers ${server}_name] if {[llength $match_list] < 1} { puts "${server} is not controlled by daemontools" return } svstat_getinfo set status [lindex [array get servers ${server}_svc_status] 1] set svc_command "$svc_bin $flag [glob ${service_dir}/${server}]" if { [catch {set svstat_txt [eval exec $svc_command]} result] } { puts "Unable to $action server: $result" return } # TODO: should open up the config.tcl and find the actual # location of the error log # for now, guess at two common locations set error_log $web_base/${server}/log/error.log if { [catch {set fileId [open $error_log {RDONLY }]} result] } { set error_log $web_base/${server}/log/error-${server}.log if { [catch {set fileId [open $error_log_2 {RDONLY }]} result] } { puts "Problem with the logfile: $result" } } fconfigure $fileId -blocking 0 # skip to the end of the log file read $fileId puts "Doing $action ${server} with: $svc_command " # tried to do this with fileevent and simply couldn't get it to work # so instead we used timed loops. Stop is based on daemontools; # start and restart are based on a key phrase in the log file if { [string equal $action stop] } { for { set x 1} { $x<120} {incr x} { # show the log set logline [read $fileId] if { [string length $logline] > 0 } { puts $logline } # check daemontools svstat_getinfo set status [lindex [array get servers ${server}_svc_status] 1] if { [string equal $status "down"]} { puts "${server} is down" close $fileId return } # wait a second after 1000 } if { $x >= 120 } { puts "gave up waiting after 2 minutes" } } else { if { [string equal $status "up"] && [string equal $flag "-u"]} { puts "$server is already up" return } if { [string equal $status "down"] && [string equal $flag "-t"]} { puts "$server is down; attempting a start instead of a restart" set flag "-u" } puts "scanning $error_log" # check the server log every 100 ms for { set x 1} {$x<1200} {incr x} { set logline [read $fileId] if { [string length $logline] > 0 } { puts $logline if { [regexp "accepting connections" $logline]} { close $fileId return } } if { [regexp Fatal $logline] } { puts "Fatal error - shutting server down" eval exec "$svc_bin -d [glob ${service_dir}/${server}]" break } after 100 } if { $x >= 1200 } { puts "gave up waiting after 2 minutes" } } close $fileId return } #---------------------------------------------------------------------- # add #---------------------------------------------------------------------- proc add {server} { global server_list_file # open it or create control file if { [catch {set fileId [open "$server_list_file" r]} result] } { set file_contents "" } else { set file_contents [string trim [read $fileId] ] close $fileId } set fileId [open "$server_list_file" a+] # check for servername in proper file format set already_exists [regexp $server $file_contents] if { $already_exists } { puts "$server already exists in $server_list_file\n" } else { # put the new entry at the end set fileId [open "$server_list_file" a+] puts $fileId $server } close $fileId } ###################################################################### # execution body ###################################################################### init_server_list switch -glob -- $arg_1 { start { if {[string length $arg_2] >0 } { start $arg_2 exit } } stop - restart - reload { if {[string length $arg_2] >0 } { svc_cmd $arg_2 $arg_1 exit } } status { status if { [string equal $arg_2 verbose] } { puts $verbose_status } exit } add { if {[string length $arg_2] >0 } { add $arg_2 exit } } version - help - default {} } help exit openacs-5.7.0/packages/acs-core-docs/www/files/run.txt0000644000175000017500000000015307653123744022500 0ustar frankiefrankie#!/bin/sh exec /usr/local/aolserver/bin/nsd-postgres -it /web/service0/etc/config.tcl -u service0 -g web openacs-5.7.0/packages/acs-core-docs/www/files/acs-start.html0000644000175000017500000000144107253523116023714 0ustar frankiefrankie ACS Installation: Welcome

    ACS Installation: Welcome


    Thank you for installing the ArsDigita Community System, a suite of fully-integrated enterprise-class applications for supporting purposeful online communities. This is the ACS Installer which performs all the steps necessary to get the ArsDigita Community System running on your server.

    Your Oracle driver is correctly installed and configured.

    The next step is to install the ACS kernel data model. Click the Next button to proceed.


    acs@arsdigita.com
    openacs-5.7.0/packages/acs-core-docs/www/files/qmail-smtpd-run.txt0000644000175000017500000000120307676147035024727 0ustar frankiefrankie#!/bin/sh QMAILDUID=`id -u qmaild` NOFILESGID=`id -g qmaild` LOCAL=`head -1 /var/qmail/control/me` if [ -z "$QMAILDUID" -o -z "$NOFILESGID" -o -z "$LOCAL" ]; then echo QMAILDUID, NOFILESGID, or LOCAL is unset in echo /var/qmail/supervise/qmail-smtpd/run exit 1 fi if [ ! -f /var/qmail/control/rcpthosts ]; then echo "No /var/qmail/control/rcpthosts!" echo "Refusing to start SMTP listener because it'll create an open relay" exit 1 fi exec /usr/local/bin/softlimit -m 2000000 \ /usr/local/bin/tcpserver -v -R -l "$LOCAL" -x /etc/tcp.smtp.cdb \ -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp /var/qmail/bin/qmail-smtpd 2>&1openacs-5.7.0/packages/acs-core-docs/www/files/dotlrn-style-1.html0000755000175000017500000004736710721035753024634 0ustar frankiefrankie yourdomain Network

    yourdomain Network

    Groups
    Join/Drop a Class or Community Group ]

    Classes:

    Communities:


    Forums
    MBA 101

    Frequently Asked Questions (FAQs)
    Exam FAQ

    News
    No News

    Day Summary
    back one day June 24, 2004 forward one day
    No Time
    07:00 AM
    08:00 AM
    09:00 AM
    10:00 AM
    11:00 AM
    12:00 PM
    01:00 PM
    02:00 PM
    03:00 PM
    04:00 PM
    05:00 PM
    06:00 PM
    07:00 PM
    08:00 PM
    09:00 PM

    Weblogger
    No Entries

    openacs-5.7.0/packages/acs-core-docs/www/files/winnsd.txt0000644000175000017500000000475507253523116023203 0ustar frankiefrankie# nsd.tcl -- This is a sample AOLserver Startup Script # # By mburke@arsdigita.com, 2000-04-16 # Based on a file created by Curtis Galloway # # This sample script will, with minor modifications, get you # up and running ACS on a Windows box. # # winnsd.txt,v 3.3 2000/06/20 16:50:11 curtisg Exp # set home [file dirname [ns_info config]] set bin [file dirname [info nameofexecutable]] # Setting the following should get you going. set server winacs set httpport 80 set oracleuser winacs set oraclepassword winacs set sroot servers/$server foreach d [list log servers $sroot $sroot/modules $sroot/pages] { if ![file exists $home/$d] { file mkdir $home/$d } } ns_section ns/threads ns_param stacksize 500000 ns_section ns/db/drivers ns_param ora8 ora8.dll ns_section ns/db/pool/main ns_param driver ora8 ns_param connections 2 ns_param user $oracleuser ns_param datasource "" ns_param password $oraclepassword ns_param verbose off ns_section ns/db/pool/subquery ns_param driver ora8 ns_param connections 2 ns_param user $oracleuser ns_param datasource "" ns_param password $oraclepassword ns_param verbose off ns_section ns/db/pool/log ns_param driver ora8 ns_param connections 2 ns_param user $oracleuser ns_param datasource "" ns_param password $oraclepassword ns_param verbose off ns_section ns/db/pools ns_param main main ns_param subquery subquery ns_param log log ns_section ns/parameters ns_param home $home ns_param auxconfigdir /web/$server/parameters #ns_param smtphost your.mail.server #ns_param smtpuser username ns_section ns/servers ns_param $server $server ns_section ns/server/$server ns_param threadtimeout 5000000 ns_param pageroot /web/$server/www ns_param enabletclpages on ns_param directoryfile index.tcl,index.adp,index.html,index.htm ns_section ns/server/$server/adp ns_param map /*.adp ns_param defaultparser fancy ns_section ns/server/$server/modules foreach m [list nssock nslog nscp nscgi] { ns_param $m $bin/$m.so } ns_section ns/server/$server/adp ns_param map /*.adp ns_section ns/server/$server/module/nssock ns_param port $httpport ns_section ns/server/$server/module/nscgi ns_param map "GET /*.bat" ns_param map "GET /cgi $bin" ns_section ns/server/$server/module/nscp ns_param port 9999 ns_section ns/server/$server/module/nscp/users # password is "x" ns_param user nsadmin:t2GqvvaiIUbF2: ns_section ns/server/$server/db ns_param pools * ns_param DefaultPool main ns_section ns/server/$server/tcl ns_param library /web/$server/tcl openacs-5.7.0/packages/acs-core-docs/www/files/dotlrn-style-2.html0000755000175000017500000003110310066530231024603 0ustar frankiefrankie My Space - SloanSpace
    Logged in as Al Essa (Log out)
    SloanSpace

    My Space

    Your password has been saved.

    Latest News

    MBA 101

    Week Summary

    May 19
    Thu 20 Morning meeting MBA 101 9:00 am - 10:00 am
    Lecture B MBA 102 3:00 pm - 5:00 pm
    Fri 21
    Sat 22
    Sun 23 Morning meeting MBA 101 9:00 am - 10:00 am
    Mon 24
    Tue 25
    openacs-5.7.0/packages/acs-core-docs/www/files/note-procs.tcl0000644000175000017500000000412110010203360023675 0ustar frankiefrankiead_library { Procs to add, edit, and remove notes for My First Package. @author oumi@arsdigita.com @cvs-id $Id: note-procs.tcl,v 1.2 2004/02/04 14:51:28 bdolicki Exp $ } namespace eval mfp {} namespace eval mfp::note {} ad_proc -public mfp::note::get { -item_id:required -array:required } { This proc retrieves a note. This is annoying code that is only here because we wanted to give you a working tutorial in 5.0 that uses content repository, but the tcl api for content repository won't be complete until 5.1. At least we can use the pregenerated views for select and edit. } { upvar 1 $array row db_1row note_select { select ci.item_id, n.title from cr_items ci, mfp_notesx n where ci.item_id = :item_id and n.note_id = ci.live_revision } -column_array row } ad_proc -public mfp::note::add { -title:required -item_id:required } { This proc adds a note. } { db_transaction { db_exec_plsql note_insert { select content_item__new(:title,-100,:item_id,null,null,null,null,null,'content_item','mfp_note',:title,null,null,null,null) } set revision_id [db_nextval acs_object_id_seq] db_dml revision_add { insert into mfp_notesi (item_id, revision_id, title) values (:item_id, :revision_id, :title) } db_exec_plsql make_live { select content_item__set_live_revision(:revision_id) } } } ad_proc -public mfp::note::edit { -item_id:required -title:required } { This proc edits a note. Note that to edit a cr_item, you insert a new revision instead of changing the current revision. } { db_transaction { set revision_id [db_nextval acs_object_id_seq] db_dml revision_add { insert into mfp_notesi (item_id, revision_id, title) values (:item_id, :revision_id, :title) } db_exec_plsql make_live { select content_item__set_live_revision(:revision_id) } } } ad_proc -public mfp::note::delete { -item_id:required } { This proc deletes a note. } { db_exec_plsql note_delete { select content_item__delete(:item_id) } } openacs-5.7.0/packages/acs-core-docs/www/files/export-oracle.txt0000644000175000017500000000135207572171161024456 0ustar frankiefrankie#!/bin/sh HOME=/home/oracle HZ= LOGNAME=oracle ORACLE_BASE=/ora8/m01/app/oracle ORACLE_HOME=$ORACLE_BASE/product/8.1.7 PATH=$PATH:$ORACLE_HOME/bin LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib ORA_OWNER=oracle ORACLE_SID=ora8 ORACLE_TERM=vt100 ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data PATH=$ORACLE_HOME/bin:$ORACLE_HOME/lib:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/sbin SHELL=/bin/sh TERM=vt100 TZ=US/Eastern # Change these! SERVICE_NAME=service_name DATABASE_PASSWORD=database_password exportdir=/ora8/m02/oracle-exports file=$exportdir/$SERVICE_NAME.dmp mv -f $file.gz $file.old.gz su - $ORA_OWNER --command="exp $SERVICE_NAME/$DATABASE_PASSWORD file=$file owner=$SERVICE_NAME consistent=Y direct=Y" gzip $file openacs-5.7.0/packages/acs-core-docs/www/files/deploy0000755000175000017500000002153310021355722022344 0ustar frankiefrankie#!/bin/sh # hand off to tcl # The backslash makes the next line a comment in Tcl \ exec tclsh "$0" ${1+"$@"} # program to control OpenACS servers with daemontools and balance # This script assumes: # 1. all affected OpenACS servers are listed as files in live_dir # or standby_dir # a. The name of each file is the servername # b. The content of each file is the port number of the server, # which does not change # 3. all affected servers have config.tcl files that know to look # in live_dir to adjust themselves accordingly # 4. daemontools controls each server at /service/servicename ###################################################################### # parameters ###################################################################### # TODO: this should become a passed-in parameter set system_name cnet set live_port 8080 set stem $system_name set balance_bin /usr/sbin/balance set daemon_bin /usr/local/bin/svc set web_base /var/lib/aolserver set shared_dir $web_base/$stem set live_dir $shared_dir/etc/live set standby_dir $shared_dir/etc/standby ###################################################################### # initialization ###################################################################### set help_p false set status_p false set status_plus_p false set switch_p false set last_flag "" set promote "" set demote "" #---------------------------------------------------------------------- # process command line arguments #---------------------------------------------------------------------- # accepting only two arguments set switch [lindex $argv 0] set arg1 [lindex $argv 1] switch -glob -- $switch { status { set status_p true } statusplus { set status_p true set status_plus_p true } help {set help_p true} version {set help_p true} switch {set switch_p true} demote {if {[string length $arg1] >0 } { set demote $arg1 } { set help_p true } } promote {if {[string length $arg1] >0 } { set promote $arg1 } { set help_p true } } default {set help_p true} } #---------------------------------------------------------------------- # Inspect the results of balance #---------------------------------------------------------------------- if { ![catch {set balance_txt [exec $balance_bin -c show 80] } result] } { # pluck out the channel data from balance: # 0 RR 0 dis 127.0.0.1 8001 # ^^ ^^^ ^^^^^ #01234567890123456789012345678901234567890 # 1 2 3 set channel_data [list] set channel_fodder $balance_txt while {[regexp {(.[^\n]+)} $channel_fodder match_fodder row] } { # remove each row as it's handled set remove_count [string length $row] set channel_fodder [string range $channel_fodder [expr $remove_count + 1] end] set channel [string range $row 9 10] set port [string range $row 33 37] set status [string range $row 12 14] lappend channel_data [list [string trim $port] [string trim $channel] [string trim $status]] } } else { puts "Error checking status: $result" exit } #---------------------------------------------------------------------- # inspect list_dir and standby_dir #---------------------------------------------------------------------- # get a list of files and their contents in each of the live and # standby dirs # serverlist: # 0 servername (foo-a, foo-b, ...) # 1 port (8001, 8002, ...) # 2 channel (0, 1, ...) # 3 status (dis, ENA) # 4 type (live, standby) set server_list [list] foreach type {live standby} { set dir ${type}_dir if { [catch {set files [exec ls [set $dir]] } result] } { puts "Error checking $type list: $result" exit } foreach file $files { if { [catch {set fileId [open "[set $dir]/$file"]} result] } { puts "Error reading $dir/$file" continue } else { set file_contents [string trim [read $fileId] ] close $fileId } if { ![string equal $file_contents ""]} { set channel_match [lsearch -regexp $channel_data $file_contents ] if { $channel_match >= 1 } { set channel_info [lindex $channel_data $channel_match] set channel [lindex $channel_info 1] set status [lindex $channel_info 2] } else { set channel "unknown" } lappend server_list [list $file $file_contents $channel $status $type] } } } ###################################################################### # Procedure Library ###################################################################### #---------------------------------------------------------------------- # Help #---------------------------------------------------------------------- proc help {} { puts {Usage: deploy status status report help this message switch if there is one live server and one standby server, exchange them demote server move server from live to standby promote server move server from standby to live } } #---------------------------------------------------------------------- # status report, Mr Sulu #---------------------------------------------------------------------- proc status {plus_p} { global server_list global balance_txt puts "" puts "type | server | port|channel| status" # 0123456789012345678901234567890123456789012345678901234567890123456789 puts "---------------+--------+-----+-------+-------------------------------" foreach file $server_list { set balance_status [lindex $file 3] set type [lindex $file 4] set should_be [string map { live ENA standby dis } $type] if { [string equal $balance_status $should_be] } { set status OK } else { set status "PROBLEM: is $balance_status, should be $should_be" } set output [format %-8.8s $type]| append output [format %15.15s [lindex $file 0]]| append output [format %5.5s [lindex $file 1]]| append output [format %7.7s [lindex $file 2]]| append output [format %30.30s $status] puts $output } puts "" if {$plus_p} { puts "Additional information:" puts $balance_txt puts "" } } #---------------------------------------------------------------------- # demote #---------------------------------------------------------------------- proc demote {server} { global server_list global web_base global stem global standby_dir global live_dir global balance_bin set demote_server [lindex $server_list [lsearch -regexp $server_list $server]] if { ![string equal [lindex $demote_server 4] live] } { puts "$server is not a live server - cannot demote" exit } set channel [lindex $demote_server 2] puts "Demoting $server" if { [catch { exec rm $web_base/${stem}-standby exec ln -s $web_base/$server $web_base/${stem}-standby exec mv $live_dir/$server $standby_dir exec $balance_bin -c "disable $channel" 80 } result] } { puts "Error demoting $server: $result" } else { puts "Successfully demoted $server" } } #---------------------------------------------------------------------- # promote #---------------------------------------------------------------------- proc promote {server} { global server_list global web_base global stem global standby_dir global live_dir global balance_bin set promote_server [lindex $server_list [lsearch -regexp $server_list $server]] if { ![string equal [lindex $promote_server 4] standby] } { puts "$server is not a standby server - cannot promote" exit } set channel [lindex $promote_server 2] puts "Promoting $server (channel $channel)" if { [catch { exec rm $web_base/${stem}-live exec ln -s $web_base/$server $web_base/${stem}-live exec mv $standby_dir/$server $live_dir exec $balance_bin -c "enable $channel" 80 } result] } { puts "Error promoting $server: $result" } else { puts "Successfully promoted $server" } } ###################################################################### # execution body ###################################################################### if { $help_p } { help exit } if { $status_p } { status $status_plus_p exit } if { [string length $demote] >0 } { demote $demote exit } if { [string length $promote] >0 } { promote $promote exit } if { $switch_p } { # TODO: should check here to make sure there's one live and one standby set standby_server [lindex $server_list [lsearch -regexp $server_list standby]] set promote_channel [lindex $standby_server 2] set promote [lindex $standby_server 0] set live_server [lindex $server_list [lsearch -regexp $server_list live]] set demote_channel [lindex $live_server 2] set demote [lindex $live_server 0] promote $promote demote $demote puts "Promoted $promote and demoted $demote" exit } # not sure how we got here help exit openacs-5.7.0/packages/acs-core-docs/www/files/svgroup.txt0000644000175000017500000000072110005232277023365 0ustar frankiefrankie#! /bin/sh if test $# -lt 2 ; then echo svgroup groupname directories ... >&2 echo for example: >&2 echo svgroup wheel /service/\* >&2 exit 2 fi g="$1" ; shift for i in $* ; do chgrp $g $i/supervise/control chmod g+w $i/supervise/control chgrp $g $i/supervise/ok chmod g+w $i/supervise/ok # just in case chgrp $g $i/supervise/status chmod g+r $i/supervise/status chgrp $g $i/supervise chmod g+x $i/supervise done openacs-5.7.0/packages/acs-core-docs/www/files/oracle8i.txt0000644000175000017500000000114707441607351023402 0ustar frankiefrankie#!/bin/sh # # chkconfig: 345 51 49 # description: starts the oracle dabase deamons ( part of the aD ACS install ) # echo "Oracle 8i auto start/stop" ORA_OWNER=oracle ORA_HOME=/ora8/m01/app/oracle/product/8.1.7 case "$1" in 'start') echo -n "Starting Oracle8i: " su - $ORA_OWNER -c $ORA_HOME/bin/dbstart touch /var/lock/subsys/oracle8i echo ;; 'stop') echo -n "Shutting Oracle8i: " su - $ORA_OWNER -c $ORA_HOME/bin/dbshut rm -f /var/lock/subsys/oracle8i echo ;; 'restart') echo -n "Restarting Oracle8i: " $0 stop $0 start echo ;; *) echo "Usage: oracle8i {start | stop | restart }" exit 1 esac exit 0 openacs-5.7.0/packages/acs-core-docs/www/files/create-new-catalog.sh0000644000175000017500000000220110055046711025111 0ustar frankiefrankie#!/bin/bash # create-new-catalog.sh # @author: Hector Amado hr_amado@galileo.edu # # From each catalog.xml in all packages, # e.g. acs-subsite.es_ES.ISO-8859-1 --> acs-subsite.es_GT.ISO-8859-1 # # USAGE: # Inside packages directory run ../bin/create-new-catalog.sh from new # or # sh ../bin/create-new-catalog.sh from new # where from, new is the language id you copy and create # # eg. ../bin/create-new-catalog.sh es_ES es_GT if [ $# -ne 2 ]; then echo "" echo " USAGE: sh ../bin/create-new-catalog.sh from new " echo " eg. sh ../bin/create-new-catalog.sh es_ES es_GT" echo "" exit 1 fi from=$1 new=$2 echo "Generating .$new. catalog files . . . " for i in $( ls -1 ); do ls -1R $i | grep .$from. > /dev/null if [ $? -eq 0 ]; then cd $i/catalog for j in $(ls -1 ); do t=${j/$from/$new} if [ x$t != x$j ]; then cp $j $t sed "s/$from/$new/" $t > temp.xml mv temp.xml $t echo $t fi done cd ../../ fi done exit 0 openacs-5.7.0/packages/acs-core-docs/www/files/config.tcl.txt0000644000175000017500000003005307653123744023724 0ustar frankiefrankiens_log notice "nsd.tcl: starting to read config file..." # which database do you want? postgres or oracle set database postgres if {$database == "oracle"} { set db_password "mysitepassword" } set httpport 8000 set httpsport 8443 # The hostname and address should be set to actual values. set hostname [ns_info hostname] set address 127.0.0.1 set server "service0" set db_name $server set servername "New OpenACS Installation - Development" set serverroot "/web/${server}" # if debug is false, all debugging will be turned off set debug false # you shouldn't need to adjust much below here # for a standard install # # AOLserver's home and binary directories. Autoconfigurable. # set homedir /usr/local/aolserver set bindir [file dirname [ns_info nsd]] # # Where are your pages going to live ? # set pageroot ${serverroot}/www set directoryfile index.tcl,index.adp,index.html,index.htm # # Global server parameters # ns_section ns/parameters ns_param serverlog ${serverroot}/log/error.log ns_param home $homedir ns_param maxkeepalive 0 ns_param logroll on ns_param maxbackup 5 ns_param debug $debug # # Thread library (nsthread) parameters # ns_section ns/threads ns_param mutexmeter true ;# measure lock contention ns_param stacksize 500000 # # MIME types. # # Note: AOLserver already has an exhaustive list of MIME types, but in # case something is missing you can add it here. # ns_section ns/mimetypes ns_param Default text/plain ns_param NoExtension text/plain ns_param .pcd image/x-photo-cd ns_param .prc application/x-pilot ns_param .xls application/vnd.ms-excel # # Tcl Configuration # ns_section ns/server/${server}/tcl ns_param library ${serverroot}/tcl ns_param autoclose on ns_param debug $debug ############################################################ # # Server-level configuration # # There is only one server in AOLserver, but this is helpful when multiple # servers share the same configuration file. This file assumes that only # one server is in use so it is set at the top in the "server" Tcl variable # Other host-specific values are set up above as Tcl variables, too. # ns_section ns/servers ns_param $server $servername # # Server parameters # ns_section ns/server/${server} ns_param directoryfile $directoryfile ns_param pageroot $pageroot ns_param maxconnections 5 ns_param maxdropped 0 ns_param maxthreads 5 ns_param minthreads 5 ns_param threadtimeout 120 ns_param globalstats false ;# Enable built-in statistics ns_param urlstats false ;# Enable URL statistics ns_param maxurlstats 1000 ;# Max number of URL's to do stats on #ns_param directoryadp $pageroot/dirlist.adp ;# Choose one or the other #ns_param directoryproc _ns_dirlist ;# ...but not both! #ns_param directorylisting fancy ;# Can be simple or fancy # # ADP (AOLserver Dynamic Page) configuration # ns_section ns/server/${server}/adp ns_param map /*.adp ;# Extensions to parse as ADP's #ns_param map "/*.html" ;# Any extension can be mapped ns_param enableexpire false ;# Set "Expires: now" on all ADP's ns_param enabledebug $debug ;# Allow Tclpro debugging with "?debug" ns_param defaultparser fancy ns_section ns/server/${server}/adp/parsers ns_param fancy ".adp" # # Socket driver module (HTTP) -- nssock # ns_section ns/server/${server}/module/nssock ns_param timeout 120 ns_param address $address ns_param hostname $hostname ns_param port $httpport ns_section "ns/server/${server}/module/nsopenssl" # Typically where you store your certificates # Defaults to $AOLSERVER/servers/${servername}/modules/nsopenssl #ns_param ModuleDir ${homedir}/servers/${server}/modules/nsopenssl ns_param ModuleDir ${serverroot}/etc/certs # NSD-driven connections: ns_param ServerPort $httpsport ns_param ServerHostname $hostname ns_param ServerAddress $address ns_param ServerCertFile certfile.pem ns_param ServerKeyFile keyfile.pem ns_param ServerProtocols "SSLv2, SSLv3, TLSv1" ns_param ServerCipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" ns_param ServerSessionCache false ns_param ServerSessionCacheID 1 ns_param ServerSessionCacheSize 512 ns_param ServerSessionCacheTimeout 300 ns_param ServerPeerVerify true ns_param ServerPeerVerifyDepth 3 ns_param ServerCADir ca ns_param ServerCAFile ca.pem ns_param ServerTrace false # For listening and accepting SSL connections via Tcl/C API: ns_param SockServerCertFile certfile.pem ns_param SockServerKeyFile keyfile.pem ns_param SockServerProtocols "SSLv2, SSLv3, TLSv1" ns_param SockServerCipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" ns_param SockServerSessionCache false ns_param SockServerSessionCacheID 2 ns_param SockServerSessionCacheSize 512 ns_param SockServerSessionCacheTimeout 300 ns_param SockServerPeerVerify true ns_param SockServerPeerVerifyDepth 3 ns_param SockServerCADir internal_ca ns_param SockServerCAFile internal_ca.pem ns_param SockServerTrace false # Outgoing SSL connections ns_param SockClientCertFile certfile.pem ns_param SockClientKeyFile keyfile.pem ns_param SockClientProtocols "SSLv2, SSLv3, TLSv1" ns_param SockClientCipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" ns_param SockClientSessionCache false ns_param SockClientSessionCacheID 3 ns_param SockClientSessionCacheSize 512 ns_param SockClientSessionCacheTimeout 300 ns_param SockClientPeerVerify true ns_param SockServerPeerVerifyDepth 3 ns_param SockClientCADir ca ns_param SockClientCAFile ca.pem ns_param SockClientTrace false # OpenSSL library support: #ns_param RandomFile /some/file ns_param SeedBytes 1024 # # Database drivers # The database driver is specified here. PostgreSQL driver being loaded. # Make sure you have the driver compiled and put it in {aolserverdir}/bin # ns_section "ns/db/drivers" if { $database == "oracle" } { ns_param ora8 ${bindir}/ora8.so } else { ns_param postgres ${bindir}/nspostgres.so ;# Load PostgreSQL driver } # # Database Pools: This is how AOLserver ``talks'' to the RDBMS. You need # three for OpenACS: main, log, subquery. Make sure to replace ``yourdb'' # and ``yourpassword'' with the actual values for your db name and the # password for it. # AOLserver can have different pools connecting to different databases # and even different different database servers. # ns_section ns/db/pools ns_param pool1 "Pool 1" ns_param pool2 "Pool 2" ns_param pool3 "Pool 3" ns_section ns/db/pool/pool1 ns_param maxidle 1000000000 ns_param maxopen 1000000000 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database == "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource localhost::${db_name} ns_param user $server ns_param password "" } ns_section ns/db/pool/pool2 ns_param maxidle 1000000000 ns_param maxopen 1000000000 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database == "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource localhost::${db_name} ns_param user $server ns_param password "" } ns_section ns/db/pool/pool3 ns_param maxidle 1000000000 ns_param maxopen 1000000000 ns_param connections 5 ns_param verbose $debug ns_param extendedtableinfo true ns_param logsqlerrors $debug if { $database == "oracle" } { ns_param driver ora8 ns_param datasource {} ns_param user $db_name ns_param password $db_password } else { ns_param driver postgres ns_param datasource localhost::${db_name} ns_param user $server ns_param password "" } ns_section ns/server/${server}/db ns_param pools "*" ns_param defaultpool pool1 ns_section ns/server/${server}/redirects ns_param 404 "global/file-not-found.html" ns_param 403 "global/forbidden.html" # # Access log -- nslog # ns_section ns/server/${server}/module/nslog ns_param file ${serverroot}/log/${server}.log ns_param enablehostnamelookup false ns_param logcombined true #ns_param logrefer false #ns_param loguseragent false ns_param maxbackup 1000 ns_param rollday * ns_param rollfmt %Y-%m-%d-%H:%M ns_param rollhour 0 ns_param rollonsignal true ns_param rolllog true # # nsjava - aolserver module that embeds a java virtual machine. Needed to # support webmail. See http://nsjava.sourceforge.net for further # details. This may need to be updated for OpenACS4 webmail # ns_section ns/server/${server}/module/nsjava ns_param enablejava off ;# Set to on to enable nsjava. ns_param verbosejvm off ;# Same as command line -debug. ns_param loglevel Notice ns_param destroyjvm off ;# Destroy jvm on shutdown. ns_param disablejitcompiler off ns_param classpath /usr/local/jdk/jdk118_v1/lib/classes.zip:${bindir}/nsjava.jar:${pageroot}/webmail/java/activation.jar:${pageroot}/webmail/java/mail.jar:${pageroot}/webmail/java # # CGI interface -- nscgi, if you have legacy stuff. Tcl or ADP files inside # AOLserver are vastly superior to CGIs. I haven't tested these params but they # should be right. # #ns_section "ns/server/${server}/module/nscgi" # ns_param map "GET /cgi-bin/ /web/$server/cgi-bin" # ns_param map "POST /cgi-bin/ /web/$server/cgi-bin" # ns_param Interps CGIinterps #ns_section "ns/interps/CGIinterps" # ns_param .pl "/usr/bin/perl" # # Modules to load # ns_section ns/server/${server}/modules ns_param nssock ${bindir}/nssock.so ns_param nslog ${bindir}/nslog.so ns_param nssha1 ${bindir}/nssha1.so ns_param nscache ${bindir}/nscache.so ns_param nsrewrite ${bindir}/nsrewrite.so ns_param nsxml ${bindir}/nsxml.so # nsopenssl is commented out to prevent errors on load if all # the cert files are not present #ns_param nsopenssl ${bindir}/nsopenssl.so # Full Text Search #ns_param nsfts ${bindir}/nsfts.so #ns_param nsperm ${bindir}/nsperm.so #ns_param nscgi ${bindir}/nscgi.so #ns_param nsjava ${bindir}/libnsjava.so ns_log notice "nsd.tcl: finished reading config file." openacs-5.7.0/packages/acs-core-docs/www/files/openacs-start.html0000644000175000017500000000164307426546162024612 0ustar frankiefrankie OpenACS Installation: Welcome

    OpenACS Installation: Welcome


    Thank you for installing the OpenACS Community System, a suite of fully-integrated enterprise-class solutions for collaborative commerce. This is the OpenACS Installer which performs all the steps necessary to get the OpenACS Community System running on your server.

    Please read the Release Notes before proceeding to better understand what is contained in this release.

    Your database driver is correctly installed and configured.

    The next step is to install the OpenACS kernel data model. Click the Next button to proceed.


    gatekeepers@openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/files/qmailctl.txt0000644000175000017500000000575507677222654023525 0ustar frankiefrankie#!/bin/sh # For Red Hat chkconfig # chkconfig: - 80 30 # description: the qmail MTA PATH=/var/qmail/bin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin export PATH QMAILDUID=`id -u qmaild` NOFILESGID=`id -g qmaild` case "$1" in start) echo "Starting qmail" if svok /service/qmail-send ; then svc -u /service/qmail-send /service/qmail-send/log else echo "qmail-send supervise not running" fi if svok /service/qmail-smtpd ; then svc -u /service/qmail-smtpd /service/qmail-smtpd/log else echo "qmail-smtpd supervise not running" fi if [ -d /var/lock/subsys ]; then touch /var/lock/subsys/qmail fi ;; stop) echo "Stopping qmail..." echo " qmail-smtpd" svc -d /service/qmail-smtpd /service/qmail-smtpd/log echo " qmail-send" svc -d /service/qmail-send /service/qmail-send/log if [ -f /var/lock/subsys/qmail ]; then rm /var/lock/subsys/qmail fi ;; stat) svstat /service/qmail-send svstat /service/qmail-send/log svstat /service/qmail-smtpd svstat /service/qmail-smtpd/log qmail-qstat ;; doqueue|alrm|flush) echo "Flushing timeout table and sending ALRM signal to qmail-send." /var/qmail/bin/qmail-tcpok svc -a /service/qmail-send ;; queue) qmail-qstat qmail-qread ;; reload|hup) echo "Sending HUP signal to qmail-send." svc -h /service/qmail-send ;; pause) echo "Pausing qmail-send" svc -p /service/qmail-send echo "Pausing qmail-smtpd" svc -p /service/qmail-smtpd ;; cont) echo "Continuing qmail-send" svc -c /service/qmail-send echo "Continuing qmail-smtpd" svc -c /service/qmail-smtpd ;; restart) echo "Restarting qmail:" echo "* Stopping qmail-smtpd." svc -d /service/qmail-smtpd /service/qmail-smtpd/log echo "* Sending qmail-send SIGTERM and restarting." svc -t /service/qmail-send /service/qmail-send/log echo "* Restarting qmail-smtpd." svc -u /service/qmail-smtpd /service/qmail-smtpd/log ;; cdb) tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp chmod 644 /etc/tcp.smtp.cdb echo "Reloaded /etc/tcp.smtp." ;; help) cat < # this will update all version numbers to new-version # and release dates to release-date # it should catch any valid openacs version numbers # for example 5.2.0 # 5.2.0a1 # 5.2.0b1 # 5.2.0d1 #--------------------------------------------------------------------- # here's what we're looking for #--------------------------------------------------------------------- # # # # 2006-01-08 daveb # # changing requires statements is new # all the core packages should require only core packages # and it makes sense to require core packages of the same version #--------------------------------------------------------------------- for dir in `find -name *.info` do perl -p -i -e "s/name=\"\d\.\d\.\d\w?\d?\"/name=\"${1}\"/" $dir perl -p -i -e "s/-\d\.\d\.\d\w?\d?.apm\"/-${1}.apm\"/" $dir perl -p -i -e "s/(provides.*version)=\"\d\.\d\.\d\w?\d?\"/\1=\"${1}\"/" $dir perl -p -i -e "s/(requires.*version)=\"\d\.\d\.\d\w?\d?\"/\1=\"${1}\"/" $dir perl -p -i -e "s/()\d{4}-\d{2}-\d{2}/${2}/" $dir doneopenacs-5.7.0/packages/acs-core-docs/www/files/stoplsnr.txt0000644000175000017500000000035007441607351023553 0ustar frankiefrankie#!/bin/sh # Start the oracle listener export ORACLE_HOME=/ora8/m01/app/oracle/product/8.1.7 export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib export ORACLE_SID=ora8 export ORACLE_TERM=vt100 $ORACLE_HOME/bin/lsnrctl stop exit 0 openacs-5.7.0/packages/acs-core-docs/www/files/README.TXT0000644000175000017500000000100707525303736022467 0ustar frankiefrankieALL the files in this directory are *generated*. Do not edit them. Instead, edit the files in /packages/acs-core-docs/www/xml/files/ and then run 'make' from /packages/acs-core-docs/www/xml It's done this way so that everything under /packages/acs-core-docs/www/xml/ is a self-contained version of the most up-to-date docs, able to regenerate the latest HTML and files. Bottom line, if you want to edit docs, make sure you're editing files underneath the 'xml' directory. -- Vinod Kurup (vinod@kurup.com) 2002-08-10 openacs-5.7.0/packages/acs-core-docs/www/files/qmail-send-log-run.txt0000644000175000017500000000013007676147035025306 0ustar frankiefrankie#!/bin/sh exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail openacs-5.7.0/packages/acs-core-docs/www/files/nsd-postgres.txt0000644000175000017500000000055410277471441024325 0ustar frankiefrankie#!/bin/bash # aolserver4 recommends descriptors limit (FD_SETSIZE) to be set to 1024, # which is standard for most OS distributions # For freebsd systems, uncomment following line: # ulimit -n 1024 export PATH=$PATH:/usr/local/pgsql/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib:/usr/local/aolserver/lib exec /usr/local/aolserver/bin/nsd $* openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/0000755000175000017500000000000011724401447022770 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note-list.adp0000644000175000017500000000005210010221046025347 0ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note-list.tcl0000644000175000017500000000153310010221046025372 0ustar frankiefrankietemplate::list::create \ -name notes \ -multirow notes \ -actions { "Add a Note" note-edit} \ -elements { edit { link_url_col edit_url display_template { } sub_class narrow } title { label "Title" } delete { link_url_col delete_url display_template { } sub_class narrow } } db_multirow \ -extend { edit_url delete_url } notes notes_select { select ci.item_id, n.title from cr_items ci, mfp_notesx n where n.revision_id = ci.live_revision } { set edit_url [export_vars -base "note-edit" {item_id}] set delete_url [export_vars -base "note-delete" {item_id}] }openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note.vuh0000644000175000017500000000066510012675572024471 0ustar frankiefrankie# Transform requests of type: a/b # into this internal request: A?c=b # for example, note/495 > note-edit?item_id=496 # a: base name of this .vuh file # b: from the request # A: hard-coded # C: hard-coded set query [ad_conn url] set request [string range $query [expr [string last / $query] + 1] end] rp_form_put item_id $request set internal_path "/packages/[ad_conn package_key]/www/note-edit" rp_internal_redirect $internal_path openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/myfirstpackage-drop.sql0000644000175000017500000000032110005232277027452 0ustar frankiefrankie-- drop script -- -- @author joel@aufrecht.org -- @cvs-id &Id:$ -- select content_folder__unregister_content_type(-100,'mfp_note','t'); select content_type__drop_type( 'mfp_note', 't', 't' ); openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note-delete.tcl0000644000175000017500000000067610010221046025670 0ustar frankiefrankiead_page_contract { This deletes a note @author Your Name (you@example.com) @cvs-id $Id: note-delete.tcl,v 1.2 2004/02/04 16:47:34 joela Exp $ @param item_id The item_id of the note to delete } { item_id:integer } permission::require_write_permission -object_id $item_id set title [item::get_title $item_id] mfp::note::delete -item_id $item_id ad_returnredirect "." # stop running this code, since we're redirecting abort openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note-procs.tcl0000755000175000017500000000417310010221046025553 0ustar frankiefrankiead_library { Procs to add, edit, and remove notes for My First Package. @author oumi@arsdigita.com @cvs-id $Id: note-procs.tcl,v 1.2 2004/02/04 16:47:34 joela Exp $ } namespace eval mfp {} namespace eval mfp::note {} ad_proc -public mfp::note::get { -item_id:required -array:required } { This proc retrieves a note. This is annoying code that is only here because we wanted to give you a working tutorial in 5.0 that uses content repository, but the tcl api for content repository won't be complete until 5.1. At least we can use the pregenerated views for select and edit. } { upvar 1 $array row db_1row note_select { select ci.item_id, n.title from cr_items ci, mfp_notesx n where ci.item_id = :item_id and n.note_id = ci.live_revision } -column_array row } ad_proc -public mfp::note::add { -title:required } { This proc adds a note. @return item_id of the new note. } { db_transaction { set item_id [db_exec_plsql note_insert { select content_item__new(:title,-100,null,null,null,null,null,null,'content_item','mfp_note',:title,null,null,null,null) }] set revision_id [db_nextval acs_object_id_seq] db_dml revision_add { insert into mfp_notesi (item_id, revision_id, title) values (:item_id, :revision_id, :title) } db_exec_plsql make_live { select content_item__set_live_revision(:revision_id) } } return $item_id } ad_proc -public mfp::note::edit { -item_id:required -title:required } { This proc edits a note. Note that to edit a cr_item, you insert a new revision instead of changing the current revision. } { db_transaction { set revision_id [db_nextval acs_object_id_seq] db_dml revision_add { insert into mfp_notesi (item_id, revision_id, title) values (:item_id, :revision_id, :title) } db_exec_plsql make_live { select content_item__set_live_revision(:revision_id) } } } ad_proc -public mfp::note::delete { -item_id:required } { This proc deletes a note. } { db_exec_plsql note_delete { select content_item__delete(:item_id) } } openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/index.adp0000644000175000017500000000026010010221046024541 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/index.tcl0000644000175000017500000000047310010221046024565 0ustar frankiefrankiead_page_contract { This is the main page for the package. It displays all of the Notes and provides links to edit them and to create new Notes. @author Your Name (you@example.com) @cvs-id $Id: index.tcl,v 1.2 2004/02/04 16:47:34 joela Exp $ } set page_title [ad_conn instance_name] set context [list]openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/myfirstpackage-create.sql0000644000175000017500000000111410005232277027752 0ustar frankiefrankie-- creation script -- -- @author joel@aufrecht.org -- @cvs-id &Id:$ -- select content_type__create_type( 'mfp_note', -- content_type 'content_revision', -- supertype 'MFP Note', -- pretty_name, 'MFP Notes', -- pretty_plural 'mfp_notes', -- table_name 'note_id', -- id_column null -- name_method ); -- necessary to work around limitation of content repository: select content_folder__register_content_type(-100,'mfp_note','t'); openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/myfirstpackage-procs.tcl0000644000175000017500000001320710551254373027635 0ustar frankiefrankiead_library { Test cases for my first package. } aa_register_case \ -cats {smoke api} \ -procs {mfp::note::add mfp::note::get mfp::note::delete} \ mfp_basic_test \ { A simple test that adds, retrieves, and deletes a record. } { aa_run_with_teardown \ -rollback \ -test_code { set name [ad_generate_random_string] set new_id [mfp::note::add -title $name] aa_true "Note add succeeded" [exists_and_not_null new_id] mfp::note::get -item_id $new_id -array note_array aa_true "Note contains correct title" [string equal $note_array(title) $name] mfp::note::delete -item_id $new_id set get_again [catch {mfp::note::get -item_id $new_id -array note_array}] aa_false "After deleting a note, retrieving it fails" [expr {$get_again == 0}] } } aa_register_case \ -cats {api} \ -procs {mfp::note::add mfp::note::get mfp::note::delete} \ mfp_bad_data_test \ { A simple test that adds, retrieves, and deletes a record, using some tricky data. } { aa_run_with_teardown \ -rollback \ -test_code { set name {-Bad [BAD] \077 { $Bad}} append name [ad_generate_random_string] set new_id [mfp::note::add -title $name] aa_true "Note add succeeded" [exists_and_not_null new_id] mfp::note::get -item_id $new_id -array note_array aa_true "Note contains correct title" [string equal $note_array(title) $name] aa_log "Title is $name" mfp::note::delete -item_id $new_id set get_again [catch {mfp::note::get -item_id $new_id -array note_array}] aa_false "After deleting a note, retrieving it fails" [expr {$get_again == 0}] } } aa_register_case \ -cats {web smoke} \ -libraries tclwebtest \ mfp_web_basic_test \ { A simple tclwebtest test case for the tutorial demo package. @author Peter Marklund } { # we need to get a user_id here so that it's available throughout # this proc set user_id [db_nextval acs_object_id_seq] set note_title [ad_generate_random_string] # NOTE: Never use the aa_run_with_teardown with the rollback switch # when running Tclwebtest tests since this will put the test code in # a transaction and changes won't be visible across HTTP requests. aa_run_with_teardown -test_code { #------------------------------------------------------------- # Login #------------------------------------------------------------- # Make a site-wide admin user for this test # We use an admin to avoid permission issues array set user_info [twt::user::create -admin -user_id $user_id] # Login the user twt::user::login $user_info(email) $user_info(password) #------------------------------------------------------------- # New Note #------------------------------------------------------------- # Request note-edit page set package_uri [apm_package_url_from_key myfirstpackage] set edit_uri "${package_uri}note-edit" aa_log "[twt::server_url]$edit_uri" twt::do_request "[twt::server_url]$edit_uri" # Submit a new note tclwebtest::form find ~n note tclwebtest::field find ~n title tclwebtest::field fill $note_title tclwebtest::form submit #------------------------------------------------------------- # Retrieve note #------------------------------------------------------------- # Request index page and verify that note is in listing tclwebtest::do_request $package_uri aa_true "New note with title \"$note_title\" is found in index page" \ [string match "*${note_title}*" [tclwebtest::response body]] #------------------------------------------------------------- # Delete Note #------------------------------------------------------------- # Delete all notes # Three options to delete the note # 1) go directly to the database to get the id # 2) require an API function that takes name and returns ID # 3) screen-scrape for the ID # all options are problematic. We'll do #1 in this example: set note_id [db_string get_note_id_from_name " select item_id from cr_items where name = :note_title and content_type = 'mfp_note' " -default 0] aa_log "Deleting note with id $note_id" set delete_uri "${package_uri}note-delete?item_id=${note_id}" twt::do_request $delete_uri # Request index page and verify that note is in listing tclwebtest::do_request $package_uri aa_true "Note with title \"$note_title\" is not found in index page after deletion." \ ![string match "*${note_title}*" [tclwebtest::response body]] } -teardown_code { twt::user::delete -user_id $user_id } } openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note-edit.adp0000644000175000017500000000032310010221046025322 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ note.title openacs-5.7.0/packages/acs-core-docs/www/files/tutorial/note-edit.tcl0000644000175000017500000000201610010221046025341 0ustar frankiefrankiead_page_contract { This is the view-edit page for notes. @author Your Name (you@example.com) @cvs-id $Id: note-edit.tcl,v 1.2 2004/02/04 16:47:34 joela Exp $ @param item_id If present, assume we are editing that note. Otherwise, we are creating a new note. } { item_id:integer,optional } ad_form -name note -form { {item_id:key} {title:text {label Title}} } -new_request { auth::require_login permission::require_permission -object_id [ad_conn package_id] -privilege create set page_title "Add a Note" set context [list $page_title] } -edit_request { auth::require_login permission::require_write_permission -object_id $item_id mfp::note::get \ -item_id $item_id \ -array note_array set title $note_array(title) set page_title "Edit a Note" set context [list $page_title] } -new_data { mfp::note::add \ -title $title } -edit_data { mfp::note::edit \ -item_id $item_id \ -title $title } -after_submit { ad_returnredirect "." ad_script_abort }openacs-5.7.0/packages/acs-core-docs/www/files/analog.cfg.txt0000644000175000017500000001025407653123744023676 0ustar frankiefrankie# Configuration file for analog 5.31 # See http://www.analog.cx/ # modified by Joel Aufrecht for OpenACS Reference Platform 09 March 2003 # # # Here are a couple of configuration commands to get you started. Add any more # you like from the Readme. # # Lines starting with # are comments. # # There is a much more extensive configuration file in examples/big.cfg # # If you need a LOGFORMAT command (most people don't -- try it without first!), # it must go here, above the LOGFILE commands. LOGFILE /web/service0/log/service0.log* OUTFILE /web/service0/www/log/traffic.html # do DNS lookups DNSFILE /home/service0/dnscache DNSLOCKFILE /home/service0/dnslock DNS WRITE HOSTNAME "[Your Organization]" # exclude these hosts # Put your own network here to omit local calls from the total # HOSTEXCLUDE 10.10.0.* ###################################################################### # # You probably don't need to change anything below this until you are # experienced. IMAGEDIR /log/images/ PNGIMAGES ON ALLCHART OFF DESCRIPTIONS OFF GOTOS OFF # ERRFILE errors.txt # REQINCLUDE pages REQLINKINCLUDE pages REFLINKINCLUDE * REDIRREFLINKINCLUDE * FAILREFLINKINCLUDE * SUBBROW */* SUBTYPE *.gz,*.Z # OSCHARTEXPAND Windows # Add whichever of these types of pages you have on your server, or others. PAGEINCLUDE .adp PAGEINCLUDE .tcl # PAGEINCLUDE *.shtml # PAGEINCLUDE *.asp # PAGEINCLUDE *.jsp # PAGEINCLUDE *.cfm # PAGEINCLUDE *.pl # PAGEINCLUDE *.php # More SEARCHENGINE commands can be found at # http://www.analog.cx/helpers/#conffiles SEARCHENGINE http://*google.*/* q,as_q,as_epq,as_oq SEARCHENGINE http://*altavista.*/* q SEARCHENGINE http://*yahoo.*/* p SEARCHENGINE http://*lycos.*/* query,wfq SEARCHENGINE http://*aol.*/* query SEARCHENGINE http://*excite.*/* search SEARCHENGINE http://*go2net.*/* general SEARCHENGINE http://*metacrawler.*/* general SEARCHENGINE http://*msn.*/* q,MT SEARCHENGINE http://*netscape.*/* search SEARCHENGINE http://*looksmart.*/* key SEARCHENGINE http://*webcrawler.*/* qkw,search,searchText SEARCHENGINE http://*overture.*/* Keywords SEARCHENGINE http://*teoma.*/* q SEARCHENGINE http://*infospace.*/* qkw SEARCHENGINE http://*alltheweb.*/* q SEARCHENGINE http://*dogpile.*/* q SEARCHENGINE http://*ask.*/* ask SEARCHENGINE http://*alltheweb.*/* query SEARCHENGINE http://*northernlight.*/* qr SEARCHENGINE http://*nlsearch.*/* qr SEARCHENGINE http://*dmoz.*/* search SEARCHENGINE http://*/netfind* query SEARCHENGINE http://*/pursuit query ROBOTINCLUDE REGEXPI:robot ROBOTINCLUDE REGEXPI:spider ROBOTINCLUDE REGEXPI:crawler ROBOTINCLUDE Googlebot* ROBOTINCLUDE Infoseek* ROBOTINCLUDE Scooter* ROBOTINCLUDE *Slurp* ROBOTINCLUDE *Validator* ROBOTINCLUDE Ultraseek* TYPEALIAS .html ".html [Hypertext Markup Language]" TYPEALIAS .htm ".htm [Hypertext Markup Language]" TYPEALIAS .shtml ".shtml [Server-parsed HTML]" TYPEALIAS .ps ".ps [PostScript]" TYPEALIAS .gz ".gz [Gzip compressed files]" TYPEALIAS .tar.gz ".tar.gz [Compressed archives]" TYPEALIAS .jpg ".jpg [JPEG graphics]" TYPEALIAS .jpeg ".jpeg [JPEG graphics]" TYPEALIAS .gif ".gif [GIF graphics]" TYPEALIAS .png ".png [PNG graphics]" TYPEALIAS .txt ".txt [Plain text]" TYPEALIAS .cgi ".cgi [CGI scripts]" TYPEALIAS .pl ".pl [Perl scripts]" TYPEALIAS .css ".css [Cascading Style Sheets]" TYPEALIAS .class ".class [Java class files]" TYPEALIAS .pdf ".pdf [Adobe Portable Document Format]" TYPEALIAS .zip ".zip [Zip archives]" TYPEALIAS .hqx ".hqx [Macintosh BinHex files]" TYPEALIAS .exe ".exe [Executables]" TYPEALIAS .wav ".wav [WAV sound files]" TYPEALIAS .avi ".avi [AVI movies]" TYPEALIAS .arc ".arc [Compressed archives]" TYPEALIAS .mid ".mid [MIDI sound files]" TYPEALIAS .mp3 ".mp3 [MP3 sound files]" TYPEALIAS .doc ".doc [Microsoft Word document]" TYPEALIAS .rtf ".rtf [Rich Text Format]" TYPEALIAS .mov ".mov [Quick Time movie]" TYPEALIAS .mpg ".mpg [MPEG movie]" TYPEALIAS .mpeg ".mpeg [MPEG movie]" TYPEALIAS .asp ".asp [Active Server Pages]" TYPEALIAS .jsp ".jsp [Java Server Pages]" TYPEALIAS .cfm ".cfm [Cold Fusion]" TYPEALIAS .php ".php [PHP]" TYPEALIAS .js ".js [JavaScript code]" openacs-5.7.0/packages/acs-core-docs/www/files/qmail.rc.txt0000644000175000017500000000027307752161573023407 0ustar frankiefrankie#!/bin/sh # Using splogger for logging. # Using qmail-local to deliver messages to ~/Maildir/ by default. exec env - PATH="/var/qmail/bin:$PATH" \ qmail-start ./Maildir/ splogger qmail openacs-5.7.0/packages/acs-core-docs/www/files/restart-aolserver-daemontools.txt0000644000175000017500000000111307675741465027711 0ustar frankiefrankie#!/usr/sh # Restarts an AOLserver (daemontools version). # Takes as its only argument the name of the server to kill. # joela 06/23/2003 # Much simpler version of restart-aolserver, just for daemontools # improvements when someone feels like some bash programming: # should test for input here and do # echo "usage: restart-aolserver service-name" # if input is empty # if input is not empty, check to make sure it's a subdirectory in # /service # and if it isn't, get a list of valid servers (check permissions, # too!) and print it # meanwhile, this works: svc -d $1 svc -u $1openacs-5.7.0/packages/acs-core-docs/www/files/acs-pgbackup-init.txt0000644000175000017500000000605107611531773025177 0ustar frankiefrankie# Back up the database, scheduled to be run nightly. As written, it # keeps a month's worth of daily backups, cycling over the same files # which are suffixed with the day of the month on which the backup is # created. # Original version by Don Baccus (dhogaza@pacifier.com> # Modified for openacs4 by Vinod Kurup # Last modified: 02 Jan 2003 # This version: ftp only. proc acs_pgbackup {} { # Set these to the appropriate values for your installation. set ftp_user "my-ftp-username" set ftp_password "my-ftp-password" set ftp_dir "my-ftp-path" set ftp_server "my.ftpserver.com" set bak "[file dirname [ns_info pageroot]]/backup" set servername "[ns_info server]" set pguser "[db_get_username]" set day [clock format [clock seconds] -format %d] set data "${servername}_${day}.dmp" # make the backup directory if ![file exists $bak] { if [catch {ns_mkdir $bak} errmsg] { ns_log Error "mkdir failed: $errmsg" ns_sendmail [ad_system_owner] [ad_system_owner] "[ad_system_name] : mkdir failed..." "$errmsg" return } } ns_log Notice "Backup of [ad_system_name] starting." ns_log Notice "pg_dump beginning..." if [catch {append msg [exec "pg_dump" "-U" "$pguser" "$servername" ">$bak/$data"]} errmsg] { ns_log Error "pg_dump failed: $errmsg" ns_sendmail [ad_system_owner] [ad_system_owner] "[ad_system_name] : pg_dump failed..." "$errmsg" return } append msg "\n" ns_log Notice "gzip of data beginning..." if [catch {append msg [exec "gzip" "-f" "$bak/$data"]} errmsg] { ns_log Error "gzip of data failed: $errmsg" ns_sendmail [ad_system_owner] [ad_system_owner] "[ad_system_name] : gzip of data failed..." "$errmsg" return } append msg "\n" ns_log Notice "ftp data beginning..." set fd [open "$bak/ftp_data.tmp" w] puts $fd "user $ftp_user ${ftp_password}\nbinary\nput $bak/$data.gz ${ftp_dir}/$data.gz\nquit\n" close $fd if [catch {append msg [exec "ftp" "-n" $ftp_server "<$bak/ftp_data.tmp"]} errmsg] { ns_log Error "ftp data failed: $errmsg" ns_sendmail [ad_system_owner] [ad_system_owner] "[ad_system_name] : ftp data failed..." "$errmsg" return } append msg "\n" # Replicate the above code to make remote copies to other systems ns_log Notice "vacuum beginning..." if [catch {append msg [exec "vacuumdb" "-U" "$pguser" "-q" "-z" "$servername"]} errmsg] { ns_log Error "vacuum failed: $errmsg" ns_sendmail [ad_system_owner] [ad_system_owner] "[ad_system_name] : vacuum failed..." "$errmsg" } ns_log Notice "Backup succeeded." append msg "Backups succeeded" ns_sendmail [ad_system_owner] [ad_system_owner] "[ad_system_name] : backup succeeded" "$msg" } if { ! [nsv_exists acs_pgbackup scheduled_p] } { ad_schedule_proc \ -thread t \ -schedule_proc ns_schedule_daily \ "00 00" \ acs_pgbackup nsv_set acs_pgbackup scheduled_p 1 ns_log Notice "Backup has been scheduled." } openacs-5.7.0/packages/acs-core-docs/www/files/startlsnr.txt0000644000175000017500000000035107441607351023724 0ustar frankiefrankie#!/bin/sh # Start the oracle listener export ORACLE_HOME=/ora8/m01/app/oracle/product/8.1.7 export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib export ORACLE_SID=ora8 export ORACLE_TERM=vt100 $ORACLE_HOME/bin/lsnrctl start exit 0 openacs-5.7.0/packages/acs-core-docs/www/files/package-documentation.xml0000644000175000017500000003061607653123744026126 0ustar frankiefrankie Tutorial Application 1 27 Dec 2002 Joel Aufrecht First Draft ($Id: package-documentation.xml,v 1.2 2003/04/28 04:02:44 joela Exp $) Joel Aufrecht
    joel@aufrecht.org
    Requirements Introduction This package lets users post blocks of text to the web, which others can then read. It integrates with full text search. It is intended to show new developers how to accomplish basic tasks with OpenACS. Overview This package has a simple data component: text notes, stored in a table in the database. The other component is the user interface. It also needs support Full Text Search. There is no administrative interface. This package depends on the core OpenACS functionality and on OpenFTS. It is PostGreSQL-only - it has not been ported to Oracle. OpenFTS is the third-party PostGreSQL full text search engine. Use-cases and User-scenarios Author Authors write notes, which comprise titles and bodies, both of plain text. Currently authors do this by ftping files to a web server, which generates many support calls. An Author creates a new note, such as the following: Hello World This is my first OpenACS package. An Author changes a note previously written. Authors can't change other authors' notes. An Author deletes a note that is no longer needed. Unless explicitly deleted, notes should never disappear. Reader Readers can see all of the existing notes. Currently readers browse to a web page and read the notes. They use the browser search function to find notes of interest. An Reader browses the notes. An Reader searches for notes. Prioritized Requirements System Interfaces Full Text Search All text entered into the package should be searchable via OpenFTS. The OpenFTS interface is specified at ???. Number Priority Description 100AThe Title and Body fields are indexed by Full Text Search. User Interfaces User 1 Interface A picture of the user interface. An Author browses to the home page of the package and sees a list of existing notes. 200AAn Author can see all existing notes. 210AAn Author can add a new note. 220AIf an author wrote a note, the author can edit that note. 225AIf an author wrote a note, the author can delete that note. 230AAuthors must be OpenACS site members. 235AAuthors authenticate themselves via the OpenACS login system. Reader Interface An Reader can see all existing notes. 300AA Reader can see all existing notes. Internationalization 400BPostings can be in any language. Security The only security need is that authors not be able to change or delete other authors' notes. This can be enforced with built-in OpenACS security. 500AThere is no logging. Design Data Model A picture of the data model Tutorialnote This table holds the notes. Each note is one record. Field Description Relationships Type Sample Value tutorialnote_id Primary Key. References acs_objects(object_id). owner_id Indicates the owner of the note. References users(user_id). title Plain text title of the note varchar(255) Hello, world body Body text of the note varchar(2024) This is my first package Each note is an acs object. This means that each record in the note table has a corresponding set of entries in the core acs tables, where security and other things are handled. This integrates our package with OpenACS to use the existing security stuff. It complicates our database scripts, because there are extra steps to create and delete records. It also greatly complicates dropping the package because we have to carefully clean out any matching records - in the correct order to avoid breaking dependent relationships - before dropping our new table. Use the standard stored procedures for add, delete, and name. Use ??? for full text search integration. User Interface A picture of the page map. index Fetch all existing notes and display them. For each note, if the viewer has write permission on the note, show an edit link. At the bottom of the page, if the viewer has permission to create new notes, show a "new" link. add-edit This page is used show a form for editing notes, to show a form for creating new notes, and to process both forms after submission. If a note id is passed in, make sure that the current user has permission to edit that note. If not, make sure that the current user has permission to create new notes. Use the template system to generate a form for editing/creating a note. If an existing note id was passed in, populate the form fields wih that note's values. User Guide Documentation for an end user. Administrator's guide No administrative tasks are needed or possible Openacs Requirements Specification Openacs Design Specification Software Requirements Specification Construx Software Builders, Inc. 2002 Software Design Specification Construx Software Builders, Inc. 2002
    openacs-5.7.0/packages/acs-core-docs/www/files/tutorial-outline.dia0000644000175000017500000000521110010221046025101 0ustar frankiefrankie‹í]ßs£8~Ï_Ay^ ÄÉ&[³»³u[uSwµ7÷²/.ÙÈ6·\ÇñËþí'ÄlŒ‰7ÊÔL ¬¦…ôõ×ÝjñÃOËÈx¤, “ø~90hó¿sF–ÿFœŠ«ûÁ"ËVŸG£Íf¢mJ²„(\ƒ”Žþ"QDF¼Ñhðpc¯;HFÄg»OI–±p²Î¨“%½LÈôÏ9KÖq0(ZíÚM“(aÆ#‰îŸfùÏ`´ëftÐω¾WdN'Œ’?Ut½¢ì¸Ûå*ICÞ$Û®JMjúÿ¾j³k•òFñüáÓûSqK»^úªºÑZ!Ù’°y—å𱉊€û!¸¼÷‰ÒÞ#¥½3¥½‡éx•°Œ‘0+K˜$IDI\ÉØš¶—“NIħÇI-D¾ëµ—1 ³,9£ÅŒDi5ŠŸ×Ë¥koÎÂàôÒ;hQÓË& ²ÅøéÔ ™áö#Vتð¦á$¢U:„qVH°å»ßvÓýñ3ÊQøåë’s¢è­æbŠ/‡ùù: hzf²¶©éi±k6:7êÇíšLñÑ‘ÑÍEDdKÙ®ûŸ^Ì­±{À;ôy5 ÉätšíÔû5J6Óa™qkü”< ^è'ap?ø—y8>ÇñÞ8 –h•<Ï" |<„.ðµ.#G€É䏯U ñ<¢Ï2„ßAONÈ!”T-= —/p¸.–“uhUjl‹™ÿÈ âüm/iõ¤ñzYÁEOÜ*›Qg÷F/ßÞ@Yà›ã¥ BÀe¦°C„äàó¬Ô¨‰À@¥°€ÆÿW‰ÿCÔØßöÿ‡#h@XÀ¡ÿ»˜òeìGW‚ý\†Çÿ½ó¸+€ÌÖì¶Op¸1¦lÌ»]j”è%*&Ýß&L0ñ¬QóEÅ×~Zšþûÿ1-v³&Krbh¼üïÁííïà¨Ón0ɺ’˜D.á;à‚š^&‘i:.ž‡†¥®a©bÞiXê–L°ôõwH_ã,̶dËB’+x­ ,¬’\óЉu!÷–¹“¬4J*©RÙæ)t’ákH¸¤÷IÂÊÎݽٖïº?Ƴp‰Œ¯‘"sì—‰8Ê¢ål5Ž“ŒV¡K„l^oè8HqdØÊFm™ÄIº"SZ¶l?'kRÖ^ðÙÙkž½ÝÐ1,}Cd¥À'2B.gb÷Ä1_û…dÄø–4ê—ŠMÂŒK¢d)ž51RÊÂYƒ ¬Š˜AÕ´ìxþ)åd¯ÁòÊ8Y7páÈS%“³h ØJ©’!²3 ç¿Àø™c…ñ¬4\(…‹òüÓˆ¡2ÿèÊ"†5t”ò |s¶ËáÂÌ3Ô;L¤4)¡T×ÊHí¬Öµ2ßw~³x¼cF‚pžÒéü©Av™ô晞è®'m¼8”yØh/~+4c{Iø&ÿ}gq ®]àš­%÷›½Ð€Ñ5`ÔN?¹è>sáªÈ\œ'ؾ<ÄóÊBaèý[bŒg ÓGa¨0Èyà^Ûâžl±t9¤ ÐÁóêÜÛ™z¹)örWÏs•šb¥šy“ª+Áµ-Ö¶øc¤¥2º\E$£Ÿ?GaªÌ v‡yæBí"÷–¢rºJQñß–é9=¤¨|àà]ŠÊÏ%C±Q̹ªUÀÍkÍ)C:HR•f£NR)HRYosÐt;(ÌØm-õLÕ›Z÷’`Z.@B¢p3ð•äÕ£pR€–¦=j6¶ÖÌE YÝC–ÿFˆåuý@jkÉr°HEØò «mVŸõ[,B¤$Þ_ØtÁ%L³5£ú¸•°U1!õq/J]µ.ÊQ±czÃ[qÚ´³ž\§;.´ïDÅe~í¶•¬K毟èTN?MtTf^)ÿ®‹¥k)}Wþ !(]tù9:µï«‘Ò¬YFi)ûõïåë!m•¥-®€ ¯ÝHf†páS͉UZ8ñFƒÛÃÝO:}¡Ô¶ÉŒŠýÖª›òbÝŠ·ôõ`ÝdukdÞ´qÓÆí-÷Ç1jOÄ×–­«¼š'Â=Ú¶©ˆ÷üÎÿ ó†1­²pÒ5¤9)Qkß|áÓ[ܲ!`‰IÒ:JͲÅ8¿õ˪iãœn#^ôÒ¸•u)µ2sSkµ}3J®yÂÁ¢ü挚¹z*þÐî{—Ü/Yg ·~Y…éªP+â Bñ溌sË1a,ÙÔº%Ý÷8¢ñü4ÁòBÎÒ†2Z¥ÕÐÑ»¥PiÆU|î¿|TëêõTëŠ¬ŽœØ‹ó_;P|Öƒïµï }‡¿©ï މÐÎCo΃ lí;ôë;Ø×æ;Hñn]‡ƒª‰:Ï¡ui…v´ãðaK…ãÐ]q7îCû¥ßÈ{@æq‰üxBœRˆ­Pªm#qÎ|“6ç‚3b tpFcìGÅØ#˜t/ÂXóM1Öé(DÓ~í·Yå1ð*µZ·âÌ¡NÛi¸Õpûaá¾g¸ý¦U8+]Q'½èÅ €<ÇÛʱã[Þ8VÍ·o-ضXŒé˜ÆÁyÔ­P²ë  aSµ+}ºft„|ÁÄSzê/ˆ,¯íÙ$q Lž{V%/"Þ•oìÉ ê©Ò y +ÜRKظ ˜È*^âຖ+ây^ëdûÌ\ü’Ÿð&¹‹šdÅ÷pIÓÛß“%‰û¨Uñ•§,Ê“PW©t’±¨! ÒÅmÈ"¬öÔid왹Óõà²ò¸ƒÅ¯mˆ]Å䣬`U`æ÷ÓöÔ¯Fìc–ÿ¨eâdoË1]M?d$tcÓ-é ²[qâì­ÊŠÓàæ]ÔYEè_…Eÿglkü[Œ˜¶ç ìyijk®~ÿ»© 100; -- create a sequence create sequence foo_sequence start with 200; -- test whether truncate works truncate table bar; drop table bar; -- test 1) whether has privileges to create a procedure -- and 2) whether rollback segments are adequately sized -- create a pl/sql procedure create or replace procedure thrash_database(v_number_of_rows IN integer) AS i integer; BEGIN FOR i IN 1..v_number_of_rows LOOP insert into foo (foo_key, random) values (foo_sequence.nextval, 'abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij'); END LOOP; END thrash_database; / show errors -- we think any Oracle installation ought to be able to handle -- 100,000 rows of 500 bytes each execute thrash_database(100000); select count(*) from foo; commit; delete from foo; commit; drop table foo; drop sequence foo_sequence; drop procedure thrash_database; -- make sure that NLS_DATE_FORMAT is correct by -- seeing that the following command returns -- YYYY-MM-DD (e.g., 1999-05-22) select sysdate from dual; openacs-5.7.0/packages/acs-core-docs/www/install-qmail.html0000644000175000017500000004320611501005400023443 0ustar frankiefrankie Install qmail (OPTIONAL)

    Install qmail (OPTIONAL)

    Qmail is a Mail Transfer Agent. It handles incoming and outgoing mail. Install qmail if you want your OpenACS server to send and receive mail, and you don't want to use an alternate MTA.

    Red Hat 9: all djb tools (qmail, daemontools, ucspi) will fail to compile in Red Hat 9 because of changes to glibc (patches)

    1. Install ucspi. This program handles incoming tcp connections. Download ucspi and install it.

      [root root]# cd /usr/local/src
      [root src]# wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
      [root src]# tar xzf ucspi-tcp-0.88.tar.gz
      cd /usr/local/src 
      wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
      tar xzf ucspi-tcp-0.88.tar.gz 

      Red Hat 9 only

      wget http://moni.csi.hu/pub/glibc-2.3.1/ucspi-tcp-0.88.errno.patch
      cd ucspi-tcp-0.88
      patch -p1 <../ucspi-tcp-0.88.errno.patch
      cd ..

      All platforms continue:

      [root src]# cd ucspi-tcp-0.88
      [root ucspi-tcp-0.88]# make
      ( cat warn-auto.sh; \
      echo 'main="$1"; shift'; \(many lines omitted)
      ./compile instcheck.c
      ./load instcheck hier.o auto_home.o unix.a byte.a
      [root ucspi-tcp-0.88]# make setup check
      ./install
      ./instcheck
      [root ucspi-tcp-0.88]#
      
      cd ucspi-tcp-0.88 
      make 
      make setup check

      Verify that ucspi-tcp was installed successfully by running the tcpserver program which is part of ucspi-tcp:

      [root ucspi-tcp-0.88]# tcpserver
      tcpserver: usage: tcpserver [ -1UXpPhHrRoOdDqQv ] [ -c limit ] [ -x rules.cdb ] [ -B banner ] [ -g gid ] [ -u uid
      ] [ -b backlog ] [ -l localname ] [ -t timeout ] host port program
      [root ucspi-tcp-0.88]#
      

      (I'm not sure if this next step is 100% necessary, but when I skip it I get problems. If you get the error 553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1) then you need to do this.) AOLserver sends outgoing mail via the ns_sendmail command, which pipes a command to the sendmail executable. Or, in our case, the qmail replacement wrapper for the sendmail executable. In some cases, though, the outgoing mail requset is apparently sent through tcp/ip, so that it comes to qmail from 127.0.0.1 (a special IP address that means the local machine - the "loopback" interface). Unless this mail is addressed to the same machine, qmail thinks that it's an attempt to relay mail, and rejects it. So these two commands set up an exception so that any mail sent from 127.0.0.1 is allowed to send outgoing mail.

      [root ucspi-tcp-0.88]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/tcp.smtp.txt /etc/tcp.smtp
      [root ucspi-tcp-0.88]# tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/tcp.smtp.txt /etc/tcp.smtp 
      tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp 
    2. Install Qmail. 

      Download qmail, set up the standard supporting users and build the binaries:

      [root root]# cd /usr/local/src
      [root src]# wget http://www.qmail.org/netqmail-1.04.tar.gz
      [root src]# tar xzf netqmail-1.04.tar.gz
      --15:04:11--  http://www.qmail.org/netqmail-1.04.tar.gz
                 => `netqmail-1.04.tar.gz'
      Resolving www.qmail.org... done.
      Connecting to www.qmail.org[192.203.178.37]:80... connected.
      HTTP request sent, awaiting response... 200 OK
      Length: 242,310 [application/x-gunzip]
      
      88% [===============================>     ] 214,620       22.93K/s ETA 00:01
      
      15:04:21 (24.04 KB/s) - `netqmail-1.04.tar.gz' saved [242310/242310]
      
      [root src]# mkdir /var/qmail
      [root src]# groupadd nofiles
      [root src]# useradd -g nofiles -d /var/qmail/alias alias
      [root src]# useradd -g nofiles -d /var/qmail qmaild
      [root src]# useradd -g nofiles -d /var/qmail qmaill
      [root src]# useradd -g nofiles -d /var/qmail qmailp
      [root src]# groupadd qmail
      [root src]# useradd -g qmail -d /var/qmail qmailq
      [root src]# useradd -g qmail -d /var/qmail qmailr
      [root src]# useradd -g qmail -d /var/qmail qmails
      [root src]# cd netqmail-1.04
      [root netqmail-1.04]# ./collate.sh
      
      You should see 7 lines of text below.  If you see anything
      else, then something might be wrong.
      [1] Extracting qmail-1.03...
      [2] Patching qmail-1.03 into netqmail-1.04.  Look for errors below:
           20
      [4] The previous line should say 20 if you used GNU patch.
      [5] Renaming qmail-1.03 to netqmail-1.04...
      [6] Continue installing qmail using the instructions found at:
      [7] http://www.lifewithqmail.org/lwq.html#installation
      [root netqmail-1.04]# cd netqmail-1.04
      [root netqmail-1.04]# make setup check
      ( cat warn-auto.sh; \
      echo CC=\'`head -1 conf-cc`\'; \(many lines omitted)
      ./install
      ./instcheck
      cd /usr/local/src 
      wget http://www.qmail.org/netqmail-1.04.tar.gz
      tar xzf netqmail-1.04.tar.gz
      mkdir /var/qmail 
      groupadd nofiles 
      useradd -g nofiles -d /var/qmail/alias alias 
      useradd -g nofiles -d /var/qmail qmaild 
      useradd -g nofiles -d /var/qmail qmaill 
      useradd -g nofiles -d /var/qmail qmailp 
      groupadd qmail 
      useradd -g qmail -d /var/qmail qmailq 
      useradd -g qmail -d /var/qmail qmailr 
      useradd -g qmail -d /var/qmail qmails
      cd netqmail-1.04
      ./collate.sh
      cd netqmail-1.04
      make setup check

      Replace sendmail with qmail's wrapper.

      [root qmail-1.03]# rm -f /usr/bin/sendmail /usr/sbin/sendmail
      [root qmail-1.03]# ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail
      [root qmail-1.03]#
      rm -f /usr/bin/sendmail /usr/sbin/sendmail
      ln -s /var/qmail/bin/sendmail /usr/sbin/sendmail

      Configure qmail - specifically, run the config script to set up files in /var/qmail/control specifying the computer's identity and which addresses it should accept mail for. This command will automatically set up qmail correctly if you have correctly set a valid host nome. If not, you'll want to read /var/qmail/doc/INSTALL.ctl to find out how to configure qmail.

      [root qmail-1.03]# ./config-fast yourserver.test
      Your fully qualified host name is yourserver.test.
      Putting yourserver.test into control/me...
      Putting yourserver.test into control/defaultdomain...
      Putting yourserver.test into control/plusdomain...
      Putting yourserver.test into control/locals...
      Putting yourserver.test into control/rcpthosts...
      Now qmail will refuse to accept SMTP messages except to yourserver.test.
      Make sure to change rcpthosts if you add hosts to locals or virtualdomains!
      [root qmail-1.03]#
      ./config-fast yourserver.test

      All incoming mail that isn't for a specific user is handled by the alias user. This includes all root mail. These commands prepare the alias user to receive mail.

      [root qmail-1.03]# cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root
      [root alias]# chmod 644 ~alias/.qmail*
      [root alias]# /var/qmail/bin/maildirmake ~alias/Maildir/
      [root alias]# chown -R alias.nofiles /var/qmail/alias/Maildir
      [root alias]#
      cd ~alias; touch .qmail-postmaster .qmail-mailer-daemon .qmail-root 
      chmod 644 ~alias/.qmail* 
      /var/qmail/bin/maildirmake ~alias/Maildir/ 
      chown -R alias.nofiles /var/qmail/alias/Maildir

      Configure qmail to use the Maildir delivery format (instead of mbox), and install a version of the qmail startup script modified to use Maildir.

      [root alias]# echo "./Maildir" > /var/qmail/bin/.qmail
      [root alias]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail.rc.txt /var/qmail/rc
      [root alias]# chmod 755 /var/qmail/rc
      [root alias]# 
      echo "./Maildir" > /var/qmail/bin/.qmail 
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail.rc.txt /var/qmail/rc 
      chmod 755 /var/qmail/rc 
      

      Set up the skeleton directory so that new users will be configured for qmail.

      [root root]# /var/qmail/bin/maildirmake /etc/skel/Maildir
      [root root]# echo "./Maildir/" > /etc/skel/.qmail
      [root root]# 
      /var/qmail/bin/maildirmake /etc/skel/Maildir
      echo "./Maildir/" > /etc/skel/.qmail

      As recommended, we will run qmail with daemontools control files. Create daemontools control directories, set up a daemontools control script, copy the supervise control files, and set permissions. The last line links the control directories to /service, which will cause supervise to detect them and execute the run files, causing qmail to start.

      [root root]# mkdir -p /var/qmail/supervise/qmail-send/log
      [root root]# mkdir -p /var/qmail/supervise/qmail-smtpd/log
      [root root]# mkdir /var/log/qmail
      [root root]# chown qmaill /var/log/qmail
      [root root]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmailctl.txt /var/qmail/bin/qmailctl
      [root root]# chmod 755 /var/qmail/bin/qmailctl
      [root root]# ln -s /var/qmail/bin/qmailctl /usr/bin
      [root root]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-send-run.txt /var/qmail/supervise/qmail-send/run 
      [root root]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-send-log-run.txt /var/qmail/supervise/qmail-send/log/run
      [root root]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-smtpd-run.txt /var/qmail/supervise/qmail-smtpd/run
      [root root]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-smtpd-log-run.txt /var/qmail/supervise/qmail-smtpd/log/run
      [root root]# chmod 755 /var/qmail/supervise/qmail-send/run
      [root root]# chmod 755 /var/qmail/supervise/qmail-send/log/run
      [root root]# chmod 755 /var/qmail/supervise/qmail-smtpd/run
      [root root]# chmod 755 /var/qmail/supervise/qmail-smtpd/log/run
      [root root]# ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service
      [root root]# ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service
      mkdir -p /var/qmail/supervise/qmail-send/log
      mkdir -p /var/qmail/supervise/qmail-smtpd/log
      mkdir /var/log/qmail
      chown qmaill /var/log/qmail
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmailctl.txt /var/qmail/bin/qmailctl
      chmod 755 /var/qmail/bin/qmailctl
      ln -s /var/qmail/bin/qmailctl /usr/bin
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-send-run.txt /var/qmail/supervise/qmail-send/run
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-send-log-run.txt /var/qmail/supervise/qmail-send/log/run
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-smtpd-run.txt /var/qmail/supervise/qmail-smtpd/run
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/qmail-smtpd-log-run.txt /var/qmail/supervise/qmail-smtpd/log/run
      chmod 755 /var/qmail/supervise/qmail-send/run
      chmod 755 /var/qmail/supervise/qmail-send/log/run
      chmod 755 /var/qmail/supervise/qmail-smtpd/run
      chmod 755 /var/qmail/supervise/qmail-smtpd/log/run
      ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service
      

      Wait ten seconds or so, and then verify that that the four qmail processes are running. If uptimes don't rise above 1 second, this may indicate broken scripts that are continuously restarting. In that case, start debugging by checking permissions.

      [root root]# qmailctl stat
      /service/qmail-send: up (pid 32700) 430 seconds
      /service/qmail-send/log: up (pid 32701) 430 seconds
      /service/qmail-smtpd: up (pid 32704) 430 seconds
      /service/qmail-smtpd/log: up (pid 32705) 430 seconds
      messages in queue: 0
      messages in queue but not yet preprocessed: 0
      [root root]#

      Further verify by sending and receiving email. Incoming mail for root is stored in /var/qmail/alias/Maildir.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/for-everyone.html0000644000175000017500000000500311501005400023305 0ustar frankiefrankie Part I. OpenACS For Everyone

    Part I. OpenACS For Everyone

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/subsites-design.html0000644000175000017500000003520711501005400024006 0ustar frankiefrankie Subsites Design Document

    Subsites Design Document

    By Rafael H. Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    *Note* This document has not gone through the any of the required QA process yet. It is being tagged as stable due to high demand.

    Introduction

    An OpenACS 4 subsite is a managed suite of applications that work together for a particular user community. This definition covers a very broad range of requirements: from a Geocities style homepage where a user can install whatever available application he wants (e.g. a single user could have their own news and forums), to a highly structured project subsite with multiple interdependent applications. Thus, flexibility in application deployment is the overarching philosophy of subsites.

    Meeting such broad requirements of flexibility demands architecture-level support, i.e. very low level support from the core OpenACS 4 data model. For example, the subsites concept demands that any package can have multiple instances installed at different URLs - entailing support from the APM and the Request Processor. Since the design and implementation directly associated with subsites is actually minimal, a discussion of subsites design is, in fact, a discussion of how core OpenACS 4 components implicitly support subsites as a whole.

    Historical Considerations

    The subsites problem actually has several quite diverse origins. It was originally recognized as a toolkit feature in the form of "scoping". The basic concept behind scoping was to allow one scoped OpenACS installation to behave as multiple unscoped OpenACS installations so that one OpenACS install could serve multiple communities. Each piece of application data was tagged with a "scope" consisting of the (user_id, group_id, scope) triple. In practice the highly denormalized data models that this method uses produced large amounts of very redundant code and in general made it an extremely cumbersome process to "scopify" a module.

    Before the advent of scoping there were several cases of client projects implementing their own version of scoping in special cases. One example being the wineaccess multi-retailer ecommerce. (Remember the other examples and get details. Archnet?, iluvcamp?)

    The requirements of all these different projects vary greatly, but the one consistent theme among all of them is the concept that various areas of the web site have their own private version of a module. Because this theme is so dominant, this is the primary problem that the OpenACS4 implementation of subsites addresses.

    Competitive Analysis

    ...

    Design Tradeoffs

    The current implementation of package instances and subsites allows extremely flexible URL configurations. This has the benefit of allowing multiple instances of the same package to be installed in one subsite, but can potentially complicate the process of integrating packages with each other since it is likely people will want packages that live at non standard URLs to operate together. This requirement would cause some packages to have more configuration options than normal since hard-coding the URLs would not be feasible anymore.

    API

    This section will cover all the APIs relevant to subsites, and so will consist of portions of the APIs of several systems.

    Packages

    The following package is provided for instantiation of packages. The apm_package.new function can be used to create a package of any type known to the system. The apm_package_types table can be queried for a list of installed packages. (See APM docs for more detail XXX: insert link here)

    
    create or replace package apm_package
    as
    
      function new (
        package_id      in apm_packages.package_id%TYPE 
                   default null,
        instance_name   in apm_packages.instance_name%TYPE
                   default null,
        package_key     in apm_packages.package_key%TYPE,
        object_type     in acs_objects.object_type%TYPE
                   default 'apm_package', 
        creation_date   in acs_objects.creation_date%TYPE 
                   default sysdate,
        creation_user   in acs_objects.creation_user%TYPE 
                   default null,
        creation_ip     in acs_objects.creation_ip%TYPE 
                   default null,
        context_id      in acs_objects.context_id%TYPE 
                   default null
      ) return apm_packages.package_id%TYPE;
    
      procedure delete (
        package_id      in apm_packages.package_id%TYPE
      );
    
      function singleton_p (
        package_key     in apm_packages.package_key%TYPE
      ) return integer;
    
      function num_instances (
        package_key     in apm_package_types.package_key%TYPE
      ) return integer;
    
      function name (
        package_id      in apm_packages.package_id%TYPE
      ) return varchar;
    
      -- Enable a package to be utilized by a subsite.
      procedure enable (
        package_id      in apm_packages.package_id%TYPE
      );
      
      procedure disable (
        package_id      in apm_packages.package_id%TYPE
      );
    
      function highest_version (
        package_key     in apm_package_types.package_key%TYPE
      ) return apm_package_versions.version_id%TYPE;
      
    end apm_package;
    /
    show errors
    
    
    

    Site Nodes

    This data model keeps track of what packages are being served from what URLs. You can think of this as a kind of rp_register_directory_map on drugs. This table represents a fully hierarchical site map. The directory_p column indicates whether or not the node is a leaf node. The pattern_p column indicates whether an exact match between the request URL and the URL of the node is required. If pattern_p is true then a match between a request URL and a site node occurs if any valid prefix of the request URL matches the site node URL. The object_id column contains the object mounted on the URL represented by the node. In most cases this will be a package instance.

    
    create table site_nodes (
        node_id     constraint site_nodes_node_id_fk
                references acs_objects (object_id)
                constraint site_nodes_node_id_pk
                primary key,
        parent_id   constraint site_nodes_parent_id_fk
                references site_nodes (node_id),
            name        varchar(100)
                constraint site_nodes_name_ck
                check (name not like '%/%'),
        constraint site_nodes_un
        unique (parent_id, name),
        -- Is it legal to create a child node?
        directory_p char(1) not null
                constraint site_nodes_directory_p_ck
                check (directory_p in ('t', 'f')),
            -- Should urls that are logical children of this node be
        -- mapped to this node?
            pattern_p   char(1) default 'f' not null
                constraint site_nodes_pattern_p_ck
                check (pattern_p in ('t', 'f')),
        object_id   constraint site_nodes_object_id_fk
                references acs_objects (object_id)
    );
    
    
    

    The following package is provided for creating nodes.

    
    create or replace package site_node
    as
    
      -- Create a new site node. If you set directory_p to be 'f' then you
      -- cannot create nodes that have this node as their parent.
    
      function new (
        node_id     in site_nodes.node_id%TYPE default null,
        parent_id       in site_nodes.node_id%TYPE default null,
        name        in site_nodes.name%TYPE,
        object_id       in site_nodes.object_id%TYPE default null,
        directory_p     in site_nodes.directory_p%TYPE,
        pattern_p       in site_nodes.pattern_p%TYPE default 'f'
      ) return site_nodes.node_id%TYPE;
    
      -- Delete a site node.
    
      procedure delete (
        node_id     in site_nodes.node_id%TYPE
      );
    
      -- Return the node_id of a url. If the url begins with '/' then the
      -- parent_id must be null. This will raise the no_data_found
      -- exception if there is no matching node in the site_nodes table.
      -- This will match directories even if no trailing slash is included
      -- in the url.
    
      function node_id (
        url         in varchar,
        parent_id   in site_nodes.node_id%TYPE default null
      ) return site_nodes.node_id%TYPE;
    
      -- Return the url of a node_id.
    
      function url (
        node_id     in site_nodes.node_id%TYPE
      ) return varchar;
    
    end;
    /
    show errors
    
    
    

    Request Processor

    Once the above APIs are used to create packages and mount them on a specific site node, the following request processor APIs can be used to allow the package to serve content appropriate to the package instance.

    
    [ad_conn node_id]
    [ad_conn package_id]
    [ad_conn package_url]
    [ad_conn subsite_id]
    [ad_conn subsite_url]
    
    
    

    Data Model Discussion

    The subsites implementation doesn't really have it's own data model, although it depends heavily on the site-nodes data model, and the APM data model.

    User Interface

    The primary elements of the subsite user interface consist of the subsite admin pages. These pages are divided up into two areas: Group administration, and the site map. The group administration pages allow a subsite administrator to create and modify groups. The site map pages allow a subsite administrator to install, remove, configure, and control access to packages. The site map interface is the primary point of entry for most of the things a subsite administrator would want to do.

    Configuration/Parameters

    ...

    Future Improvements/Areas of Likely Change

    The current subsites implementation addresses the most basic functionality required for subsites. It is likely that as developers begin to use the subsites system for more sophisticated projects, it will become necessary to develop tools to help build tightly integrated packages. The general area this falls under is "inter-package communication". An actual implementation of this could be anything from clever use of configuration parameters to lots of package level introspection. Another area that is currently underdeveloped is the ability to "tar up" and distribute a particular configuration of site nodes/packages. As we build more fundamental applications that can be applied in more general areas, this feature will become more and more in demand since more problems will be solvable by configuration instead of coding.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/aolserver4.html0000644000175000017500000004232011501005400022756 0ustar frankiefrankie Install AOLserver 4

    Install AOLserver 4

    by Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    1. Check suitability of previously installed TCL. Start tcl (type tclsh or find it using which tclsh).

      [root root]% info exists tcl_platform(threaded)
      1
      [root root]% info patchlevel
      8.4.7
      [root root]%
      tclsh
      info exists tcl_platform(threaded)
      info patchlevel
      

      If the first command returns anything other than 1, then tcl is not threaded. If tcl is threaded and the version is 8.4 or higher, then installing tcl from source is optional.

      Retrieve TCL 8.4 (or higher). Download and install TCL 8.4 from source

      Note for Debian users: you can apt-get install tcl8.4-dev if you have the right version (stable users will need to add tcl8.4 to their sources.list file as described on the Install Postgres page). You'll have to use /usr/lib/tcl8.4/ instead of /usr/local/lib when you try to find the tcl libraries, however.

      If you have not installed TCL already, download the latest TCL version from Sourceforge

      Debian: apt-get install tcl8.4 tcl8.4-dev and proceed to the next step. In that step, replace --with-tcl=/usr/local/lib/ with --with-tcl=/usr/lib/tcl8.4.

      Remember that you have to be root if you want to follow these instructions. On Mac OS X type sudo su - to become root.

      Alternatively use curl -L -O instead of wget (especially on Mac OS X).

      [root root]# cd /usr/local/src
      [root src]# wget http://heanet.dl.sourceforge.net/sourceforge/tcl/tcl8.4.9-src.tar.gz
      [root src]# tar xfz tcl8.4.9-src.tar.gz
      [root src]# cd tcl8.4.9/unix
      [root unix]# ./configure --enable-threads
      [root unix]# make install
      [root root]# 
      cd /usr/local/src
      wget http://heanet.dl.sourceforge.net/sourceforge/tcl/tcl8.4.9-src.tar.gz
      tar xfz tcl8.4.9-src.tar.gz
      cd tcl8.4.9/unix
      ./configure --enable-threads
      make install
            
    2. Retrieve AOLserver. Download the aolserver from CVS.

      [root root]# cd /usr/local/src
      [root src]# mkdir aolserver40r10
      [root src]# cd aolserver40r10
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver login
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co  -r aolserver_v40_r10 aolserver
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nscache
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nspostgres
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nssha1
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r v2_7 nsoracle
      [root aolserver]# wget http://www.tdom.org/tDOM-0.7.8.tar.gz
      [root aolserver]# tar xvfz tDOM-0.7.8.tar.gz
      [root aolserver]# cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/tcllib co -r tcllib-1-8 tcllib
      [root root]# 
      cd /usr/local/src
      mkdir aolserver40r10
      cd aolserver40r10
      cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r aolserver_v40_r10 aolserver
      cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nscache
      cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nspostgres
      cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nssha1
      cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co -r v2_7 nsoracle
      wget http://www.tdom.org/files/tDOM-0.8.0.tar.gz
      tar xvfz tDOM-0.8.0.tar.gz
      cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/tcllib co -r tcllib-1-8 tcllib
    3. Configure, compile and install AOLserver. Many people need to run more than one version of AOLserver in parallel. This section accomodates future upgrades by installing AOLserver 4 in /usr/local/aolserver40r9.

      [root aolserver]# cd /usr/local/src/aolserver40r10/aolserver
      [root aolserver]# ./configure --prefix=/usr/local/aolserver40r10 --with-tcl=/usr/local/lib/
      [root aolserver]# make install
      cd /usr/local/src/aolserver40r10/aolserver
      ./configure --prefix=/usr/local/aolserver40r10 --with-tcl=/usr/local/lib/
      make install
      

      If you are using gcc 4 or later, see http://openacs.org/forums/message-view?message_id=309814

      If this is the only version of AOLserver in use, or is the default version, create a symlink. If not, then be sure to use /usr/local/aolserver40r10 instead of /usr/local/aolserver in the steps below and check both scripts and makefiles to ensure they use the correct path.

      [root aolserver]# ln -s /usr/local/aolserver40r10 /usr/local/aolserver
    4. Configure, compile and install the modules. 

      1. Install nscache

        [root aolserver]# cd /usr/local/src/aolserver40r10/nscache
        [root nscache]# make install AOLSERVER=/usr/local/aolserver
      2. Install nsoracle (if you want to use Oracle)

        [root nscache]# cd ../nsoracle
        [root nsoracle]# make install AOLSERVER=/usr/local/aolserver

        OpenACS looks for the Oracle driver at /usr/local/aolserver/bin/ora8.so, but some versions of nsoracle may create nsoracle.so instead. In that case, you can symlink (ln -s nsoracle.so ora8.so) to fix it.

      3. Install nspostgres (if you want to use Postgres)

        [root nscache]# cd ../nspostgres
        [root nspostgres]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib:/usr/local/aolserver/lib
        [root nspostgres]# make install POSTGRES=LSB ACS=1 INST=/usr/local/aolserver  AOLSERVER=/usr/local/aolserver
                      

        If you get errors like:

        nspostgres.c: In function `Ns_PgTableList':
        nspostgres.c:679: warning: passing arg 3 of `Tcl_DStringAppend' as signed due to prototype

        then PostGreSQL is probably not in the standard location. The location of PostGreSQL is very dependent on which method was used to install it. To correct the problem, replace LSB with the path to the path to your PostGreSQL installation. Often this is /usr/local/pgsql.

        You can use the ldd command to verify that all libraries are linked in: ldd /usr/local/src/aolserver40r10/nspostgres/nspostgres.so

        If you run into problems with libpq.a do the following (and repeat the step above)

        [root nspostgres]# ranlib /usr/local/pgsql/lib/libpq.a

        If you run into problems with the linker, edit the Makefile. Add -lnsdb to the MODLIBS var.

        MODLIBS = -L$(PGLIB) -lpq -lnsdb
      4. Install nssha1

        [root nspostgres]# cd ../nssha1

        Now install nssha1:

        [root nssha1]# make install AOLSERVER=/usr/local/aolserver

        If the make fails you will have to edit nssha1.c. Comment out the following 2 lines (lines 139-140):

        // typedef unsigned int u_int32_t;
        // typedef unsigned char u_int8_t;
      5. Install tDOM

        [root nssha1]# cd ../tDOM-0.8.0/unix

        Edit the CONFIG file. Uncomment the instructions meant for AOLserver 4, but edit it to look like this:

        ../configure --enable-threads --disable-tdomalloc
                  --prefix=/usr/local/aolserver --with-tcl=/usr/local/lib

        Note that the location of the Tcl library may vary on differnt platforms (e.g. for Debian 3.0: --with-tcl=/usr/lib/tcl8.4)

        Now you can compile and configure tDOM

        [root unix]# sh CONFIG
        [root unix]# make install
      6. Install TCLLIB

        [root nssha1]# cd ../tcllib

        Configure and compile TCLLIB

        [root unix]# ./configure -prefix=/usr/local/aolserver40r10
        [root unix]# make install

    5. Add a database-specific wrapper script. This script sets database environment variables before starting AOLserver; this allows the AOLserver instance to communicate with the database. There is one script for Oracle and one for PostgreSQL. They do not conflict. If you plan to use both databases, install both. Note that this section requires you to have OpenACS files available, which you can get through CVS, through a tarball, or by other means. You can come back to this section after you acquire the OpenACS code, but don't forget to come back. (Note to maintainers: this should be moved to the next page and integrated into the text there)

      • Oracle

        [root aolserver]# cd /usr/local/aolserver/bin
        [root bin]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle
        [root bin]# chmod 750 nsd-oracle
        [root bin]#
        cd /usr/local/aolserver/bin
        cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-oracle.txt ./nsd-oracle
        chmod 750 nsd-oracle
      • PostgreSQL

        [root aolserver]# cd /usr/local/aolserver/bin
        [root bin]# cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres
        [root bin]# chmod 755 nsd-postgres
        [root bin]#
        cd /usr/local/aolserver/bin
        cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/nsd-postgres.txt ./nsd-postgres
        chmod 755 nsd-postgres

      You may need to edit these scripts if you are not using /usr/local/aolserver as the directory of Aolserver4.

    6. Change startup script (optional). If you want to run AOLserver on a port below 1024 (normally, for a webserver you will use 80), you will have to change the /var/lib/aolserver/service0/etc/daemontools/run script according to the documentation found there (namely: Add the -b yourip:yourport switch)

    7. Test AOLserver.

    ($Id: aolserver4.html,v 1.25 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-vuh.html0000644000175000017500000001201711501005400023333 0ustar frankiefrankie Using .vuh files for pretty urls

    Using .vuh files for pretty urls

    .Vuh files are special cases of .tcl files, used for rewriting incoming urls. We can use a vuh file to prettify the uri for our notes. Instead of note-edit?item_id=495, we can use note/495. To do this, we will need a new .vuh file for redirection and we will need to change the referring links in note-list. First, add the vuh:

    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www
    [$OPENACS_SERVICE_NAME www]$ emacs note.vuh
    

    Paste this into the file:

    # Transform requests of type: a/b
    # into this internal request: A?c=b
    # for example, note/495 > note-edit?item_id=496
    # a: base name of this .vuh file
    # b: from the request
    # A: hard-coded
    # C: hard-coded
    
    set query [ad_conn url]
    
    set request [string range $query [expr [string last / $query] + 1] end]
    
    rp_form_put item_id $request
    
    set internal_path "/packages/[ad_conn package_key]/www/note-edit"
    
    rp_internal_redirect $internal_path
    

    We parse the incoming request and treat everything after the final / as the item id. Note that this simple redirection will lose any additional query parameters passed in. Many OpenACS objects maintain a pretty-name, which is a unique, human-readable string, usually derived from title, which makes an even better 'pretty url' than a numeric id; this requires that your display page be able to look up an item based on pretty id.

    We use rp_form_put to store the item id in the internal register that the next page is expecting, and then redirects the request in process internally (ie, without a browser refresh).

    Next, modify note-list so that its link is of the new form.:

    [$OPENACS_SERVICE_NAME www]$ emacs ../lib/note-edit.tcl
    db_multirow \
        -extend {
    	edit_url
    	delete_url
        } notes notes_select {
    	select ci.item_id,
    	       n.title
            from   cr_items ci,
                   mfp_notesx n
            where  n.revision_id = ci.live_revision
        } {
    	set edit_url [export_vars -base "note/$item_id"]
    	set delete_url [export_vars -base "note-delete" {item_id}]
        }
    

    You may also need to change some of the links in your package. Commonly, you would use ad_conn package_url to build the URL. Otherwise, some of your links may be relative to the virtual directory (note/) instead of the actual directory that the note is being served from.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/maintenance-deploy.html0000644000175000017500000002713311501005400024451 0ustar frankiefrankie Staged Deployment for Production Networks

    Staged Deployment for Production Networks

    ($Id: maintenance-deploy.html,v 1.22 2010/12/11 23:36:32 ryang Exp $)

    By Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This section describes two minimal-risk methods for deploying changes on a production network. The important characteristics of a safe change deployment include: (THIS SECTION IN DEVELOPMENT)

    • Control: You know for sure that the change you are making is the change that you intend to make and is the change that you tested.

    • Rollback: If anything goes wrong, you can return to the previous working configuration safely and quickly.

    Method 1: Deployment with CVS

    With this method, we control the files on a site via CVS. This example uses one developmental server (service0-dev) and one production server (service0). Depending on your needs, you can also have a staging server for extensive testing before you go live. The only way files should move between the server instances is via cvs.

    To set up a developmental installation, first set up either your developmental installation or your production installation, and follow the instructions for committing your files to CVS. We'll assume in this example that you set up the production server (service0). To set up the developmental instance, you then follow the intall guide again, this time creating a new user (service0-dev) that you'll use for the new installation. To get the files for service0-dev, you check them out from cvs (check out service0).

    su - service0-dev
    co -d /cvsroot service0
    mv service0 /var/lib/aolserver/service0-dev
    ln -s /home/service0-dev/web /var/lib/aolserver/service0-dev
    emacs web/etc/config.tcl
    emacs web/etc/daemontools/run
    

    In the config.tcl file, you'll probably want to pay attention the rollout support section. That will ensure that email on your developmental server will not be sent out to the general world.

    Also, instead of going through the OpenACS online installer, you'll actually load live data into your production server.

    You can even automate the process of getting live data from your production server. Copy something like this to /home/service0-dev/bin and put it in service0-dev's crontab to run once a night. You'll need to make sure the database backups are set up in service0's crontab, and that if the servers are on different physical machines, that the database backup is copied to the developmental machine once per night.

    /usr/local/bin/svc -d /service/service0-dev
    /bin/sleep 60
    # this deletes the dev database!
    /usr/local/pgsql/bin/dropdb service0-dev
    /usr/local/pgsql/bin/createdb -E UNICODE service0-dev
    # this is not necessary from Postgres 7.4 on
    /usr/local/pgsql/bin/psql -f /var/lib/aolserver/service0-dev/packages/acs-kernel/sql/postgresql/postgresql.sql service0
    mv /var/lib/aolserver/service0/database-backup/service0-nightly-backup.dmp.gz /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup-old.dmp.gz
    /bin/gunzip /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup.dmp.gz
    /usr/bin/perl -pi -e "s/^\\connect service0$/\\connect service0-dev/" /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup.dmp
    /usr/local/pgsql/bin/psql service0-dev < /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup.dmp
    /usr/local/bin/svc -u /service/service0-dev
    /bin/gzip /var/lib/aolserver/service0-dev/database-backup/service0-nightly-backup-old.dmp
    

    Your developmental server will always have data about a day old.

    To make changes on service0-dev:

    1) change the file on service0-dev as desired
    2) test the new file
    3) commit the file: 
    if the file is /var/lib/aolserver/service0-dev/www/index.adp, do: 
    
    cd /var/lib/aolserver/service0-dev/www
    cvs diff index.adp (this is optional; it's just a
    reality check)
    the lines starting > will be added and the lines
    starting < will be removed, when you commit
    if that looks okay, commit with: 
    cvs -m "changing text on front page for February conference" index.adp
    the stuff in -m "service0" is a comment visible only from within cvs commands
    

    To make these changes take place on service0:

    4) update the file on production:
    cd /var/lib/aolserver/service0/www
    cvs up -Pd index.adp

    If you make changes that require changes to the database, test them out first on service0-dev, using either -create.sql or upgrade scripts. Once you've tested them, you then update and run the upgrade scripts from the package manager.

    The production site can run "HEAD" from cvs.

    The drawback to using HEAD as the live code is that you cannot commit new work on the development server without erasing the definition of 'working production code.' So a better method is to use a tag. This guarantees that, at any time in the future, you can retrieve exactly the same set of code. This is useful for both of the characteristics of safe change deployment. For control, you can use tags to define a body of code, test that code, and then know that what you are deploying is exactly that code. For rollback, you can use return to the last working tag if the new tag (or new, untagged changes) cause problems. .... example of using tags to follow ...

    Method 2: A/B Deployment

    The approach taken in this section is to always create a new service with the desired changes, running in parallel with the existing site. This guarantees control, at least at the final step of the process: you know what changes you are about to make because you can see them directly. It does not, by itself, guarantee the entire control chain. You need additional measures to make sure that the change you are making is exactly and completely the change you intended to make and tested previously, and nothing more. Those additional measures typically take the form of source control tags and system version numbers. The parallel-server approach also guarantees rollback because the original working service is not touched; it is merely set aside.

    This approach can has limitations. If the database or file system regularly receiving new data, you must interrupt this function or risk losing data in the shuffle. It also requires extra steps if the database will be affected.

    Simple A/B Deployment: Database is not changed

    Figure 6.2. Simple A/B Deployment - Step 1

    Simple A/B Deployment - Step 1

    Figure 6.3. Simple A/B Deployment - Step 2

    Simple A/B Deployment - Step 2

    Figure 6.4. Simple A/B Deployment - Step 3

    Simple A/B Deployment - Step 3

    Complex A/B Deployment: Database is changed

    Figure 6.5. Complex A/B Deployment - Step 1

    Complex A/B Deployment - Step 1

    Figure 6.6. Complex A/B Deployment - Step 2

    Complex A/B Deployment - Step 2

    Figure 6.7. Complex A/B Deployment - Step 3

    Complex A/B Deployment - Step 3

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/kernel-overview.html0000644000175000017500000000702111501005400024013 0ustar frankiefrankie Overview

    Overview

    • The OpenACS Kernel, which handles system-wide necessities such as metadata, security, users and groups, subsites, and package management and deployment.

    • The OpenACS Core, which comprises all the other packages that ship with the kernel and are most frequently needed by users, such as templating, forums, and user registration/management. The packages tend to be developed and distributed with the kernel.

    • OpenACS Application packages, which typically provide user-level web services built on top of the Kernel and Core. Application packages are developed separately from the Kernel, and are typically released independently of it.

    This document provides a high level overview of the kernel package. Documentation for other packages on this server

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/update-translations.html0000644000175000017500000001353411501005400024676 0ustar frankiefrankie How to Update the translations

    How to Update the translations

    1. Identify any new locales that have been created. For each new locale, check the parameters, especially that the locale is in the format [two-letter code for language, lower-case]_[TWO-LETTER CODE FOR COUNTRY, UPPER-CASE], and create a sql command. A example sql command for creating a locale is:

      insert into ad_locales 
             (locale, label, language, country, nls_language, nls_territory, 
              nls_charset, mime_charset, default_p, enabled_p)
             values ('fa_IR', 'Farsi (IR)', 'fa', 'IR', 'FARSI', 'IRAN', 'AL24UTFFSS', 
              'windows-1256', 't', 'f');

      Put this command into the following four files. For the upgrade files, the correct file name will depend on the exact version.

      • /packages/acs-lang/sql/postgresql/ad-locales.sql

      • /packages/acs-lang/sql/postgresql/upgrade/upgrade-current-version.sql

      • /packages/acs-lang/sql/oracle/ad-locales.sql

      • /packages/acs-lang/sql/oracle/upgrade/upgrade-current-version.sql

    2. Make a backup of the production database. Restore it as a new database. For example, if upgrading from OpenACS 5.1.1, and the site name/database name is translate-511, create translate-512b1.

    3. Check out the latest code on the release branch (e.g., oacs-5-1) as a new site, using the new site name (e.g., /var/lib/aolserver/translate-512b1. Copy over any local settings - usually, /etc/config.tcl and /etc/daemontools/run and modify appropriately. Also, copy over several translation-server-only files:

      ...TBD
                

    4. Shut down the production site and put up a notice (no procedure on how to do this yet.)

    5. Start the new site, and upgrade it.

    6. Go to ACS Lang admin page and click "Import All Messages"

    7. Resolve conflicts, if any, on the provided page.

    8. Back on the admin page, click the export link. If there are conflicts, the messages will be exported anyway and any errors will be shown in the web interface.

    9. Commit the message catalogs to cvs.

    10. From the packages dir, run the acs-lang/bin/check-catalog.sh script. (This checks for keys no longer in use and some other things. Until it is rolled into the UI, do it manually and check the results and take whatever steps you can intuit you should do.)

    11. CVS commit the catalog files. Done

    12. If everything went well, reconfigure the new site to take over the role of the old site (/etc/config.tcl and /etc/daemontools/run). Otherwise, bring the old site back up while investigating problems, and then repeat.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/packages.html0000644000175000017500000010133511501005400022450 0ustar frankiefrankie OpenACS Packages

    OpenACS Packages

    By Pete Su and Bryan Quinn

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Overview

    This document is a guide on how to write a software package for OpenACS. OpenACS packages are installed and maintained with the OpenACS Package Manager (APM) which is part of the acs-admin package. This document presents reasons for packaging software, conventions for the file system and naming that must be followed, and step by step instructions for creating a new package for the "Notes" example package.

    Server file layout

    Here is how an OpenACS 5 server is laid out starting from the Server root (ROOT):

    Figure 10.1. Server file layout diagram

    ROOT/
        bin/
            Various executables and scripts for server maintanence.
        content-repository-content-files/
            content repository content stored in the filesystem.
        etc/
            Installation scripts and configuration files.
        packages/
            acs-admin/
            acs-api-browser/
            ... many many more...
            workflow/
        log/
            Server error and access logs
        tcl/
            bootstrap code
        www/
            Pages not in packages (static content, customized pages)

    What a Package Looks Like

    Each package encapsulates all of its data model, library code, logic, adminstration pages and user pages in a single part of the file tree. This means developers can track down everything that is related to a particular package without hunting all over the file system. Encapsulating everything about a package in one place also makes it much easier to distribute packages independently from the OpenACS Core.

    In order to make this work, we need a system that keeps track of the packages that have been installed in the server, where those packages have been installed, and a standard way to map URLs that a client sends to our server to the right page in the appropriate package. While we're at it, this tool should also automate package installation, dependency checking, upgrades, and package removal. In OpenACS 5, this tool is called the APM.

    To illustrate the general structure of a package, let's see what the package for the "notes" application should look like.

    Figure 10.2. Package file layout diagram

    ROOT/
      +-- packages/    APM Root
            |
            +-- notes/  Package Root 
            |     |
            |     +-- notes.info                              Package Specification File
            |     +-- sql/
            |     |     |
            |     |     +-- oracle/
            |     |     |        |
            |     |     |        +-- notes-create.sql         Data Model Creation Script for Oracle
            |     |     |        +-- notes-drop.sql           Data Model Drop Script
            |     |     |        +-- *.sql                    Data Model Files
            |     |     |        +-- upgrade/
            |     |     |            +-- upgrade-4.1-4.5.sql  Data Model Upgrade Scripts
            |     |     +-- postgresql/
            |     |     |        |
            |     |     |        +-- notes-create.sql         Data Model Creation Script for PostgreSQL      
            |     |     |        +-- notes-drop.sql           Data Model Drop Script
            |     |     |        +-- *.sql                    Data Model Files
            |     |     |        +-- upgrade/
            |     |     |            +-- upgrade-4.1-4.5.sql  Data Model Upgrade Scripts
            |     +-- tcl/
            |     |     |
            |     |     +-- notes-procs.tcl                   Tcl Library
            |     |     +-- notes-procs.xql                   SQL92 Queries for notes-procs.tcl
            |     |     +-- notes-procs-oracle.xql            Oracle-specific queries for notes-procs.tcl
            |     |     +-- notes-procs-postgresql.xql        PostgreSQL-specific Queries for notes-procs.tcl
            |     |     +-- notes-init.tcl                    Tcl Initialization
            |     |     +-- notes-init.xql                    Queries for notes-init.tcl (work in all DBs)      
            |     |     +-- *.tcl                             Tcl Library Files
            |     +-- lib/
            |     |     |
            |     |     +-- *.tcl                             Includable page logic
            |     |     +-- *.adp                             Includable page templates
            |     +-- www/
            |     |     |
            |     |     +-- admin/                            Administration UI
            |     |     |     +-- tests/                      Regression Tests
            |     |     |     |     +-- index.tcl             Regression Test Index Page
            |     |     |     |     +-- ...                   Regression Tests
            |     |     |     +-- index.tcl                   Administration UI Index Page
            |     |     |     +-- ...                         Administration UI Pages
            |     |     |
            |     |     +-- doc/                              Documentation
            |     |     |     +-- index.html                  Documentation Index Page
            |     |     |     +-- ...                         Administration Pages
            |     |     +-- resources/                        Static Content
            |     |     |     +-- ...                         Static Content files
            |     |     +-- index.tcl                         UI Index Page
            |     |     +-- index.adp                         UI Index Template
            |     |     +-- index.xql                         Queries for UI Index page      
            |     |     +-- *.tcl                             UI Logic Scripts
            |     |     +-- *.adp                             UI Templates
            |     |     +-- *-oracle.xql                      Oracle-specific Queries
            |     |     +-- *-postgresql.xql                  PostgreSQL-specific Queries
            +-- Other package directories.

    All file locations are relative to the package root, which in this case is ROOT/packages/notes. The following table describes in detail what each of the files up in the diagram contain.

    A special note on the PACKAGE-KEY/www/resources directory. Files in this directory are available at http://yourserver/resources/PACKAGE-KEY/... and are returned without any permissions checking or even checks that the package is installed or mounted. Files are returned directly, so .tcl or .adp files are not sourced in these directories. This makes it suitable for storing icons, css files, javascript, and other static content which can be treated this way.

    Table 10.1. Package files

    File TypeIts UseNaming Convention
    Package Specification FileThe package specification file is an XML file generated and maintained by the OpenACS Package Manager (APM). It specifies information about the package including its parameters and its files.notes.info
    Data Model Creation Script Contains the SQL that creates the necessary data model and PL/SQL packages (or PL/pgSQL or whatever) to support the package. The name must match the convention below or the package will not be installed correctly. Notice that the script must be under the appropriate directory for the database you are developing your package for (hopefully all OpenACS-supported databases :-)) sql/<database>/notes-create.sql
    Data Model Drop ScriptContains the SQL that removes the data model and PL/SQL packages generated by the creation script. The name must match the convention below or the package will not be installed correctly. sql/<database>/notes-drop.sql
    Data Model FileAny .sql file that does not match the naming convention above is recognized as a data model file. It is useful to separate the SQL in the creation and drop scripts into several files and then have the scripts source the other data model files. In Oracle this can be done by including @@ filename in the creation or drop scripts. See the Oracle FAQ for examples. In PostgreSQL the same is acomplished by including \i filename. sql/<database>/*.sql
    Data Model Upgrade Scripts Contain changes to the data model between versions. The APM can automatically load the appropriate upgrade scripts when upgrading to a new version of a package. sql/<database>/upgrade/upgrade-<old>-<new>.sql
    SQL92 Query Files Files with queries that are supported by all databases. These are usually SQL92 queries. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *.xql
    Oracle-specific Query Files Files with queries that are Oracle-specific. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *-oracle.xql
    PostgreSQL-specific Query Files Files with queries that are PostgreSQL-specific. Notice that the .xql filename must match the name of the .tcl file that uses those queries. *-postgresql.xql
    Tcl Library Files The Tcl library files include a set of procedures that provide an application programming interface (API) for the package to utilize. tcl/notes-procs.tcl
    Tcl InitializationThe initialization files are used to run Tcl procedures that should only be sourced once on startup. Examples of statements to put here are registered filters or procedures. Tcl initialization files are sourced once on server startup after all of the Tcl library files are sourced. tcl/notes-init.tcl
    Administration UIThe administration UI is used to administer the instances of the package. For example, the forums administration UI is used to create new forums, moderate postings, and create new categories for forums postings.www/admin/*
    Administration UI Index PageEvery package administration UI must have an index page. In most cases, this is index.tcl but it can be any file with the name index, such as index.html or index.adp.www/admin/index.tcl
    Regression TestsEvery package should have a set of regression tests that verify that it is in working operation. These tests should be able to be run at any time after the package has been installed and report helpful error messages when there is a fault in the system.www/admin/tests/
    Regression Test Index PageThe regression test directory must have an index page that displays all of the tests available and provides information on how to run them. This file can have any extension, as long as its name is index.www/admin/tests/index.html
    DocumentationEvery package must include a full set of documentation that includes requirements and design documents, and user-level and developer-level documentation where appropriate.www/doc/
    Documentation Index PageThe documentation directory must include a static HTML file with the name of index.html.www/doc/index.html
    UI Logic ScriptsPackages provide a UI for users to access the system. The UI is split into Logic and Templates. The logic scripts perform database queries and prepare variables for presentation by the associated templates.www/*.tcl
    UI TemplatesTemplates are used to control the presentation of the UI. Templates receive a set of data sources from the logic scripts and prepare them for display to the browser.www/*.adp
    UI Index PageThe UI must have an index page composed of a logic script called index.tcl and a template called index.adp.www/index.tcl

    The APM

    The APM is used to create, maintain, and install packages. It takes care of copying all of the files and registering the package in the system. The APM is responsible for:

    1. Package registration

    2. Automatic installation of packages: loading data models, code libraries, and so on.

    3. Checking what packages depend on what other packages.

    4. Storing information on the package including ownership and a file list.

    In addition for packages that are applications, the APM is responsible for keeping track of where in the site a user must go in order to use the application. To do this, the APM defines a set of objects that we call package instances. Once a package is loaded, the administrator can create as many instances of the package as she likes, and map these instances to any URL in the site that she wants. If packages are analogous to executable programs in an operating system, then package instances are analgous to multiple running copies of a single program. Each instance can be independently administered and each instance maintains its own set of application parameters and options.

    The following sections will show you how to make a package for the Notes application. In addition, they will discuss some site management features in OpenACS 5 that take advantage of the APM's package instance model. The two most important of these are subsites, and the site map tool, which can be used to map applications to one or more arbitrary URLs in a running site.

    We will also discuss how to organize your files and queries so they work with the OpenACS Query Dispatcher.

    Making a Package

    Here is how you make a package.

    1. Login as a site-wide administrator on your web service.

    2. Go to the package manager on your server. The URL is /acs-admin/apm.

    3. Click on the link /acs-admin/apm/package-add.

    4. Fill out the form for adding a new package. The form explains what everything means, but we'll repeat the important bits here for easy reference:

      Package Key

      This is a short text string that should uniquely name your package to distinguish it from all the others. It is used as a database key to keep track of the package and as the name of the directory in the file system where all the files related to your package will live. Example package keys in the current system include: forums, acs-kernel and so on. For the example application, we will use the package key notes.

      Package Name

      This is a short human readable name for your package. For our example, we will use the name "Notes".

      Package Plural

      If your package name is a nice singular noun, this should be the plural form of it. I assume the plural form is used when multiple instances of the package are used by a single service. We'll talk more about package instances later. Our example apllication doesn't really have a good plural name. So just make it also be "Notes".

      Package Type

      Generally we think of packages as either being applications, meaning that the package is meant primarily for use by end-users, or services meaning that the package is meant to be a reusable library of code, to be used by other packages. forums is a good example of an application, while acs-templating is a good example of a service. Our example is an application, so pick that.

      Package URL

      The URL from which people will download your package when it is done. Just use the default for this, you can change it later.

      Initial Version

      Just use the default here, which by convention is 0.1d.

      Version URL

      Just use the default here.

      Summary and Description

      Enter a short summary and longer description of what the Notes application will do. That is, something like "this application keeps short textual notes in the database", and so on.

    5. Click the button "Create Package".

    6. At this point, APM will create a directory called ROOT/packages/notes.

    7. The directory that APM created will be empty except for the notes.info file. Create a file called ROOT/packages/notes/sql/oracle/notes-create.sql. We'll fill this file with our data model very soon. Create a file called ROOT/packages/notes/sql/oracle/notes-drop.sql. This will contain the instructions to drop the data model. To be complete, you would also create the PostgreSQL versions of these files as well in ROOT/packages/notes/sql/postgresql/notes-create.sql and ROOT/packages/notes/sql/postgresql/notes-drop.sql.

      After you do this, go back to the main APM page. From there, click the link called "notes" to go to the management page for the new package. Now click the link called "Manage file information", then the "Scan the packages/notes directory for additional files in this package" link on that page to scan the file system for new files. This will bring you do a page that lists all the files you just added and lets you add them to the notes package.

      Note that while the .sql files have been added to the packge, they have not been loaded into the database. For the purposes of development, you have to load the data model by hand, because while OpenACS has automatic mechanisms for loading and reloading .tcl files for code, it does not do the same thing for data model files.

    8. Now go back to the main management page for the notes If your package has parameters, create them using the "Manage Parameter Information" link. Define package callbacks via the "Tcl Callbacks (install, instantiate, mount)" link.

    9. The new package has been created and installed in the server. At this point, you should add your package files to your CVS repository. I'll assume that you have set up your development repository according to the standards described in this appendix. If so, then you just do this:

      % cd ROOT/packages
      % cvs add notes
      % cd notes
      % cvs add notes.info
      % cvs add sql
      % cd sql
      % cvs add *.sql
      % cd ROOT/packages/notes
      % cvs commit -m "add new package for notes"
          
    10. Now you can start developing the package. In addition to writing code, you should also consider the tasks outlined in the package development tutorial.

    The Site Map and Package Instances

    At this point, you are probably excited to see your new package in action. But, we haven't added any user visible pages yet. By convention, user visible pages go in the ROOT/packages/notes/www directory. So go there and add a file called hello.html with some text in it. Now we have to make the user pages visible in the site. Since we didn't put the pages underneath ROOT/www they will not appear on their own. What we have to do is mount the application into the site map. That is, we have to define the URL from which the application will serve its pages.

    In OpenACS 5, administrators can define an arbitrary mapping between the URLs the user types and the actual file in the file system that is served. This mapping is called the site map and entries in the site map are called site nodes. Each site node maps a URL to an OpenACS object. Since package instances are objects, the site map allows us to easily map package instances to URLs. As we said before, each instance of an application has its own set of parameters and runs from its own URL within the site. What this means is that even though all the code for the notes application lives in ROOT/packages/notes, the application itself can run from any number of locations in the site. This allows developers and administrators to build sites that look to the user like a collection of many indedendent applications that actually run on a single shared code base. The request-processor document shows you how OpenACS figures out which instance of your application was requested by the user at any given time. The page development tutorial shows you how to use this information in your user interface.

    In order to make the new notes application visible to users, we have to mount it in the site map. You do this by going to the Site Map page, which is by default available at /acs-admin/site-map. Use the interface here to add a new sub-folder called notes to the root of the site, then click "new application" to mount a new instance of the notes application to the site. Name the new instance notes-1.

    Then type this URL into your browser: http://yourserver/notes/hello.html

    Now you should see the contents of the page that you added. What has happened is that all URLs that start with /notes have been mapped in such a way as to serve content from the directory ROOT/packages/notes/www. At this point, you can experiment with the site map by mounting multiple instances of the not yet written Notes application at various places in the site. In a later document, we'll see how to write your application so that the code can detect from what URL it was invoked. This is the key to supporting subsites.

    Summary

    The APM performs the following tasks in an OpenACS site:

    • Manages creation, installation, and removal of packages from the server. Also keeps track of what files belong to which packages.

    • Manages package upgrades.

    • Manages information on all package instances in a site. For correctly written application packages, this allows the site administrator to map multiple instances of a package to URLs within a site.

    • Writes out package distribution files for other people to download and install. We'll cover this later.

    Additional Reading

    ($Id: packages.html,v 1.49 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/configuring-mounting-packages.html0000644000175000017500000000773611501005400026630 0ustar frankiefrankie Mounting OpenACS packages

    Mounting OpenACS packages

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Mounting OpenACS packages

    After you've installed your packages, you have to 'mount' them in order to make them appear on your website.

    Make sure you are logged in, and then click on the 'Admin' or 'Control Panel' link to get to the Site-Wide Administration page (at /acs-admin). Click on the subsite you'd like the application to be available at.

    Subsites are a way of dividing your website into logical chunks. Often they represent different groups of users, or parts of an organization.

    Now click on 'Applications' (applications are the same thing as packages). You'll see a list of Applications and the URLs that each is located at. To mount a new application, you click on 'Add application', enter the Application, title (application name), and URL (URL folder name), and you're done.

    Test it out now. The URL is based on a combination of the subsite URL and the application URL. So if you installed a package in the Main Subsite at the URL calendar, it will be available at http://www.yoursite.com/calendar. If you installed it at a subsite that has a URL intranet, then it would be located at http://www.yoursite.com/intranet/calendar.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-resources.html0000644000175000017500000001175111501005400024352 0ustar frankiefrankie Resources

    Resources

    Here are some resources that OpenACS users have found useful.

    Books

    Web Sites

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/rp-requirements.html0000644000175000017500000001517711501005400024044 0ustar frankiefrankie Request Processor Requirements

    Request Processor Requirements

    By Rafael H. Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    The following is a requirements document for the OpenACS 4.0 request processor. The major enhancements in the 4.0 version include a more sophisticated directory mapping system that allows package pageroots to be mounted at arbitrary urls, and tighter integration with the database to allow for flexible user controlled url structures, and subsites.

    Vision Statement

    Most web servers are designed to serve pages from exactly one static pageroot. This restriction can become cumbersome when trying to build a web toolkit full of reusable and reconfigurable components.

    System Overview

    The request processor's functionality can be split into two main pieces.

    1. Set up the environment in which a server side script expects to run. This includes things like:

      • Initialize common variables associated with a request.

      • Authenticate the connecting party.

      • Check that the connecting party is authorized to proceed with the request.

      • Invoke any filters associated with the request URI.

    2. Determine to which entity the request URI maps, and deliver the content provided by this entity. If this entity is a proc, then it is invoked. If this entitty is a file then this step involves determining the file type, and the manner in which the file must be processed to produce content appropriate for the connecting party. Eventually this may also require determining the capabilities of the connecting browser and choosing the most appropriate form for the delivered content.

    It is essential that any errors that occur during the above steps be reported to developers in an easily decipherable manner.

    Requirements

    10.0 Multiple Pageroots

    10.10 Pageroots may be combined into one URL space.

    10.20 Pageroots may be mounted at more than one location in the URL space.

    20.0 Application Context

    20.10 The request processor must be able to determine a primary context or state associated with a pageroot based on it's location within the URL space.

    30.0 Authentication

    30.10 The request processor must be able to verify that the connecting browser actually represents the party it claims to represent.

    40.0 Authorization

    40.10 The request processor must be able to verify that the party the connecting browser represents is allowed to make the request.

    50.0 Scalability

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-steps.html0000644000175000017500000003670511501005400023504 0ustar frankiefrankie Basic Steps

    Basic Steps

    The basic steps for installing OpenACS are:

    1. Install an OS and supporting software (see Install a Unix-like OS or Appendix A. Install Red Hat 8/9 for more details). See the Table 2.2. Version Compatibility Matrix.

    2. Install a database (see Install Oracle 8.1.7 or Install PostgreSQL).

    3. Install AOLserver (Install AOLserver 4) .

    4. Create a unique database and system user. Install the OpenACS tarball, start and AOLserver instance, and use the OpenACS web pages to complete installation (see Install OpenACS 5.6.0).

    Specific instructions are available for Mac OS X and Windows2000 (see OpenACS Installation Guide for Mac OS X or OpenACS Installation Guide for Windows2000).

    Binaries and other shortcuts

    You can try out OpenACS using some binary installers. In general, they are not yet supported by the community, so they are mostly for evaluation purposes. Installing OpenACS

    You can see a list of current installers.

    1. The packaged version of PostgreSQL in Debian, Red Hat, and FreeBSD ports works fine.

    2. Once AOLserver and a database are installed, a bash script automates the OpenACS checkout and installation.

    System Requirements

    You will need a PC (or equivalent) with at least these minimum specifications:

    • 128MB RAM (much more if you want Oracle)

    • 1GB free space on your hard drive (much more if you want Oracle)

    • A Unix-like operating system with Tcl, tDOM, and a mail transport agent like sendmail or qmail. (see Prerequisite Software)

    All of the software mentioned is open-source and available without direct costs, except for Oracle. You can obtain a free copy of Oracle for development purposes. This is described in the Acquire Oracle section.

    How to use this guide

    • This is text you will see on screen, such as a Button or link in a radio button list or menu.

    • This is text that you will type.

    • This is text from a program or file which you may need to examine or edit:

      if {$database == "oracle"} {
                set db_password        "mysitepassword"
      }
    • This is text that you will see and type in a command shell, including text you may have to change. It is followed by a list of just the commands, which you can copy and paste. The command prompt varies by system; in the examples we use the form[$OPENACS_SERVICE_NAME aolserver]$, where $OPENACS_SERVICE_NAME is the current user and aolserver is the current directory. The root prompt is shown ending in # and all other prompts in $.

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ svc -d /service/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ dropdb $OPENACS_SERVICE_NAME
      DROP DATABASE
      [$OPENACS_SERVICE_NAME aolserver]$ createdb $OPENACS_SERVICE_NAME
      CREATE DATABASE
      su - $OPENACS_SERVICE_NAME
      svc -d /service/$OPENACS_SERVICE_NAME
      dropdb $OPENACS_SERVICE_NAME
      createdb $OPENACS_SERVICE_NAME

      Setting a global shell variable for cut and paste. In order to cut and paste the instructions into your shell, you must set the environment variable $OPENACS_SERVICE_NAME. In order to set it globally so that it works for any new users or special service users you may create, edit the file /etc/profile ( /etc/share/skel/dot.profile for FreeBSD) and add this line:

      export OPENACS_SERVICE_NAME=service0

    Paths and Users

    Table 2.1. Default directories for a standard install

    Fully qualified domain name of your serveryourserver.test
    name of administrative access accountremadmin
    OpenACS service $OPENACS_SERVICE_NAME (set to service0 in default install)
    OpenACS service account$OPENACS_SERVICE_NAME
    OpenACS database name$OPENACS_SERVICE_NAME
    Root of OpenACS service file tree (SERVERROOT)/var/lib/aolserver/$OPENACS_SERVICE_NAME
    Location of source code tarballs for new software/var/tmp
    The OpenACS tarball contains some files which are useful while setting up other software. Those files are located at:/var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files
    Database backup directory/var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup
    Service config files/var/lib/aolserver/$OPENACS_SERVICE_NAME/etc
    Service log files/var/lib/aolserver/$OPENACS_SERVICE_NAME/log
    Compile directory/usr/local/src
    PostgreSQL directory/usr/local/pgsql
    AOLserver directory/usr/local/aolserver

    None of these locations are set in stone - they're simply the values that we've chosen. The values that you'll probably want to change, such as service name, are marked like this. The other values we recommend you leave unchanged unless you have a reason to change them.

    Note

    Some of the paths and user accounts have been changed from those recommended in previous versions of this document to improve security and maintainability. See this thread for discussion.

    Getting Help during installation

    We'll do our best to assure that following our instructions will get you to the promised land. If something goes wrong, don't panic. There are plenty of ways to get help. Here are some tips:

    • Keep track of the commands you are run and record their output. I like to do my installations in a shell inside of emacs (M-x shell) so that I can save the output if needed. An alternative would be to use the script command.

    • We'll point out where the error logs for the various pieces of software are. Output from those logs will help us help you. Don't worry if you feel overwhelmed by all the information in the error logs. Over time, you'll find that they make more and more sense. Soon, you'll actually look forward to errors so that you can run to the log and diagnose the problem.

    • Search the forums at openacs.org - you'll often find many people who have struggled through the same spot that you're in.

    • The bottom of each page has a link to OpenACS.org, where you can post comments and read other users comments about the contents of the page.

    • Ask questions at the irc channel on freenode.net (#openacs). They're knowledgeable and quite friendly if you can keep them on topic.

    • Post a question on the forums. Make sure you've done a search first. When you do post, be sure to include your setup information (OS, etc) as well as the exact commands that are failing with the accompanying error. If there's a SQL error in the TCL error or in the log, post that too.

    • If you find errors in this document or if you have ideas about making it better, please post them in our BugTracker.

    ($Id: install-steps.html,v 1.33 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/cvs-guidelines.html0000644000175000017500000012035711501005400023620 0ustar frankiefrankie CVS Guidelines

    CVS Guidelines

    ($Id: cvs-guidelines.html,v 1.8 2010/12/11 23:36:32 ryang Exp $)

    By Joel Aufrecht with input from Jeff Davis, Branimir Dolicki, and Jade Rubick.

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Using CVS with OpenACS

    Getting Started

    All OpenACS code is available anonymously. To get code anonymously, use the parameter -d:pserver:anonymous@cvs.openacs.org:/cvsroot immediately after cvs in a cvs command to check out or export code.

    If you are an OpenACS developer, you should check out code so that you or any other developer can commit it. To do this, use the parameter -d:ext:cvs.openacs.org:/cvsroot immediately after cvs in checkout commands. This will create a local checkout directory that uses cvs.openacs.org but does not specify the user. By default, it will use your local account name as the user, so if you are logged in as "foobar" it will try to check out and commit as if you had specified :ext:foobar@cvs.openacs.org:/cvsroot. The advantage of not specifying a user in the checkout command is that other users can work in the directory using their own accounts.

    OpenACS.org supports non-anonymous cvs access only over ssh, so you must have CVS_RSH=ssh in your environment. (Typically this is accomplished by putting export CVS_RSH=ssh into ~/.bash_profile.). If your local account name does not match your cvs.openacs.org account name, create a file ~/.ssh/config with an entry like:

    Host cvs.openacs.org
        User joel
    

    With this setup, you will be asked for your password with each cvs command. To avoid this, set up ssh certificate authentication for your openacs account. (More information)

    You may want to set some more default actions for CVS usage. To do so, create the file ~/.cvsrc with the contents:

    cvs -z6
    cvs -q

    -z6 speeds up cvs access over the network quite a bit by enabling compressed connection by default. -q suppresses some verbose output from commands. For example, it makes the output of cvs up much easier to read.

    Checkout for Package Development

    If you are actively developing a non-core package, you should work from the latest core release branch. Currently this is oacs-5-6. This ensures that you are working on top of a stable OpenACS core, but still allows you to commit feature changes to non-core packages. To check out all packages,

    cvs -d :ext:cvs.openacs.org:/cvsroot co -r oacs-5-6 openacs-4

    If you work in the directories created with this command, all of your cvs updates and commits will be confined to the oacs-5-6 branch. Your work will be merged back to HEAD for you with each release.

    Because the entire openacs-4 directory is large, you may want to use only acs-core plus some specific modules. To do this, check out core first:

    cvs -d:ext:cvs.openacs.org:/cvsroot -r oacs-5-6 checkout acs-core

    Then add modules as needed:

    cd /var/lib/aolserver/service0/packages
    cvs up -d packagename

    ... where packagename is the name of the package you want. Visit the Package Inventory and Package maintainers and status for a list of available packages and their current state.

    Checkout for Core Development

    If you are actively developing packages in the OpenACS Core, work from the HEAD branch. HEAD is used for active development of the next version of core OpenACS. It may be very buggy; it may not even install correctly. Do not use this branch for development of non-core features unless your work depends on some of the HEAD core work. To check out HEAD, omit the -r tag.

    To check out HEAD for development, which requires an OpenACS developer account:

    cvs -d:ext:cvs.openacs.org:/cvsroot checkout acs-core

    To check out HEAD anonymously:

    cvs -d:pserver:anonymous@cvs.openacs.org:/cvsroot checkout acs-core

    Checkout .LRN

    .LRN consists of a given version openacs core, plus a set of packages. These are collectively packages together to form a distrubution of .LRN. F .LRN 2.0.0 sits on top of OpenACS 5.0.0. .LRN also uses an OpenACS install.xml file during installation; this file is distributed within the dotlrn package and must be moved. To get a development checkout of .LRN in the subdirectory dotlrn:

    cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r oacs-5-6 acs-core
    mv openacs-4 dotlrn
    cd dotlrn/packages
    cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r oacs-5-6 dotlrn-all
    mv dotlrn/install.xml ..

    Working with CVS

    Once you have a checkout you can use some commands to track what has changed since you checked out your copy. cvs -n update does not change any files, but reports which changes have been updated or locally modified, or are not present in CVS.

    To update your files, use cvs update. This will merge changes from the repository with your local files. It has no effect on the cvs.openacs.org repository.

    OpenACS CVS Concepts

    Modules

    All OpenACS code resides within a single CVS module, openacs-4. (The openacs-4 directory contains code for all versions of OpenACS 4 and later, and .LRN 1 and later.) Checking out this module retrieves all openacs code of any type. For convenience, subsets of openacs-4 are repackaged as smaller modules.

    acs-core contains only critical common packages. It does not have any user applications, such as forums, bug-tracker, calendar, or ecommerce. These can be added at any time.

    The complete list of core packages is:

    acs-admin 
    acs-api-browser 
    acs-authentication 
    acs-automated-testing 
    acs-bootstrap-installer
    acs-content-repository 
    acs-core-docs 
    acs-kernel 
    acs-lang 
    acs-mail
    acs-messaging 
    acs-reference 
    acs-service-contract 
    acs-subsite 
    acs-tcl
    acs-templating 
    ref-timezones search

    dotlrn-all contains the packages required, in combination with acs-core, to run the .LRN system.

    project-manager-all contains the packages required, in combination with acs-core, to run the project-manager package.

    Each OpenACS package (i.e., directory in openacs-4/packages/) is also aliased as a module of the same name.

    Tags and Branches

    Tags and Branches look similar in commands, but behave differently. A tag is a fixed point on a branch. Check out a tag to get a specific version of OpenACS. Check out a branch to get the most current code for that major-minor version (e.g., 5.0.x or 5.1.x). You can only commit to a branch, not a tag, so check out a branch if you will be working on the code.

    • openacs-x-y-z-final tags mark final releases of OpenACS. This tag is applied to the acs-core files for an OpenACS core release, and to the latest released versions of all other packages at the time of release. Example: openacs-5-0-4-final.

    • dotlrn-x-y-z-final tags mark final releases of .LRN. These tags apply only to .LRN packages. Example: dotlrn-2-0-1-final

    • packagename-x-y-z-final tags apply to releases of individual packages. For example, calendar-2-0-0-final is a tag that will retrieve only the files in the calendar 2.0.0 release. It applies only to the calendar package. All non-core, non-dotlrn packages should have a tag of this style, based on the package name. Many packages have not been re-released since the new naming convention was adopted and so don't have a tag of this type.

    • openacs-x-y-compat tags point to the most recent released version of OpenACS X.Y. It is similar to openacs-x-y-z-compat, except that it will always get the most recent dot-release of Core and the most recent compatible, released version of all other packages. All of the other tag styles should be static, but -compat tags may change over time. If you want version 5.0.4 exactly, use the openacs-5-0-4-final tag. If you want the best newest released code in the 5.0.x release series and you want to upgrade within 5.0.x later, use the compat tag.

      For example, if you check out the entire tree with -r openacs-5-0-compat, you might get version 5.0.4 of each OpenACS core package, version 2.0.1 of calendar, version 2.0.3 of each .LRN package, etc. If you update the checkout two months later, you might get version 5.0.5 of all OpenACS core packages and version 2.1 of calendar.

    • oacs-x-y is a branch, , not a tag. All core packages in the 5.0 release series (5.0.0, 5.0.1, 5.0.2, etc) are also on the oacs-5-0 branch. Similarly, OpenACS core packages for 5.1.0 are on the oacs-5-1 branch.

      These branches are used for two purposes. OpenACS Core packages on these branches are being tidied up for release. Only bug fixes, not new features, should be added to core packages on release branches. For all other packages, release branches are the recommended location for development. For example, if you are working on calendar, which is compatible with openacs 5.0 but not 5.1, work on the oacs-5-0 branch.

    • HEAD is a branch used for development of core packages.

    Contributing code back to OpenACS

    There are three main ways to contribute code to OpenACS:

    1. To contribute a small fix, if you do not have a developer account, submit a patch.

    2. If you are making many changes, or would like to become a direct contributor, send mail to the Core Team asking for commit rights. You can then commit code directly to the repository:

      1. Use one of the checkout methods described above to get files to your system. This takes the place of steps 1 and 2 in Installation Option 2: Install from tarball. Continue setting up the site as described there.

      2. Fix bugs and add features.

      3. Commit that file (or files):

        cvs commit -m "what I did and why" filename

        Because this occurs in your personal checkout and not an anonymous one, this commit automagically moves back upstream to the Mother Ship repository at cvs.openacs.org. The names of the changed files, and your comments, are sent to a mailing list for OpenACS developers. A Core Team developer may review or roll back your changes if necessary.

      4. Confirm via the OpenACS CVS browser that your changes are where you intended them to be.

    3. Add a new package. Contact the Core Team to get approval and to get a module alias created.

      1. Check out acs-core on the HEAD branch. (Weird things happen if you add files to a branch but not to HEAD):

        cd /tmp
        cvs -d:ext:cvs.openacs.org:/cvsroot checkout acs-core

        Copy your package directory from your working directory to this directory. Make sure not to copy any CVS directories.

        cp -r /var/lib/aolserver/service0/packages/newpackage /tmp/openacs-4/packages

        Import the package into the cvs.openacs.org cvs repository:

        cd /tmp/openacs-4/packages/newpackage
        cvs import -m "Initial import of newpackage" openacs-4/packages/newpackage myname newpackage-0-1d
      2. Add the new package to the modules file. (An administrator has to do this step.) On any machine, in a temporary directory:

        cvs -d :ext:cvs.openacs.org:/cvsroot co CVSROOT
        cd CVSROOT
        emacs modules

        Add a line of the form:

        photo-album-portlet openacs-4/packages/photo-album-portlet

        Commit the change:

        cvs commit -m "added alias for package newpackage" modules

        This should print something like:

        cvs commit: Examining .
        **** Access allowed: Personal Karma exceeds Environmental Karma.
        Checking in modules;
        /cvsroot/CVSROOT/modules,v  <--  modules
        new revision: 1.94; previous revision: 1.93
        done
        cvs commit: Rebuilding administrative file database

      3. Although you should add your package on HEAD, you should do package development on the latest release branch that your code is compatible with. So, after completing the import, you may want to branch your package:

        cd /var/lib/aolserver/service0/packages/newpackage
        cvs tag -b oacs-5-1
      4. See How to package and release an OpenACS Package

      Note

      Some packages are already in cvs at openacs-4/contrib/packages. Starting with OpenACS 5.1, we have a Maturity mechanism in the APM which makes the contrib directory un-necessary. If you are working on a contrib package, you should move it to /packages. This must be done by an OpenACS administrator. On cvs.openacs.org:

      1. cp -r /cvsroot/openacs-4/contrib/packages/package0 /cvsroot/openacs-4/packages
      2. Update the modules file as described above.

      3. Remove the directory from cvs in the old location using cvs rm. One approach for file in `find | grep -v CVS`; do rm $file; cvs remove $file; done

    Rules for Committing Code to the OpenACS repository

    CVS commit procedures are governed by TIP (Technical Improvement Proposal) #61: Guidelines for CVS committers

    1. Which branch?

      1. For core packages, new features should always be committed on HEAD, not to release branches.

      2. For core packages, bug fixes should be committed on the current release branch whenever applicable.

      3. For non-core packages, developers should work on a checkout of the release branch of the lastest release. For example, if OpenACS 5.1.0 is released, developers should work on the oacs-5-1 branch. When oacs-5-2 is branched, developers should continue working on oacs-5-1 until OpenACS 5.2.0 is actually released.

        Reason: First, this ensures that developers are working against stable core code. Second, it ensures that new package releases are available to OpenACS users immediately.

      4. The current release branch is merged back to HEAD after each dot release.

    2. New packages should be created in the /packages directory and the maturity flag in the .info file should be zero. This is a change from previous policy, where new packages went to /contrib/packages)

    3. Code

      1. Only GPL code and material should be committed to the OpenACS CVS repository (cvs.openacs.org)

      2. Do not mix formatting changes with code changes. Instead, make a formatting-only change which does not affect the logic, and say so in the commit comment. Then, make the logic change in a separate commit. Reason: This makes auditing and merging code much easier.

      3. Database upgrade scripts should only span one release increment, and should follow Naming Database Upgrade Scripts .

        Reason: If an upgrade script ends with the final release number, then if a problem is found in a release candidate it cannot be addressed with another upgrade script. E.g., the last planned upgrade script for a package previously in dev 1 would be upgrade-2.0.0d1-2.0.0b1.sql, not upgrade-2.0.0d1-2.0.0.sql. Note that using rc1 instead of b1 would be nice, because that's the convention with release codes in cvs, but the package manager doesn't support rc tags.

      4. Database upgrade scripts should never go to the release version, e.g., should always have a letter suffix such as d1 or b1.

      5. CVS commit messages should be intelligible in the context of Changelogs. They should not refer to the files or versions.

      6. CVS commit messages and code comments should refer to bug, tip, or patch number if appropriate, in the format "resolves bug 11", "resolves bugs 11, resolves bug 22". "implements tip 42", "implements tip 42, implements tip 50", "applies patch 456 by User Name", "applies patch 456 by User Name, applies patch 523 by ...".

    4. When to TIP

      1. A TIP is a Techical Improvement Proposal ( more information ). A proposed change must be approved by TIP if:

        1. It changes the core data model, or

        2. It will change the behavior of any core package in a way that affects existing code (typically, by changing public API), or

        3. It is a non-backwards-compatible change to any core or standard package.

      2. A proposed change need not be TIPped if:

        1. it adds a new function to a core package in a way that:

          1. does not change the backwards-compatibility of public API functions.

          2. does not change the data model

          3. has no negative impact on performance

        2. it changes private API, or

        3. it is a change to a non-core, non-standard package

    5. Tags

      1. When a package is released in final form, the developer shall tag it "packagename-x-y-z-final" and "openacs-x-y-compat". x-y should correspond to the current branch. If the package is compatible with several different core versions, several compat tags should be applied.

        Reason 1: The packagename tag is a permanent, static tag that allows for future comparison. The compat tag is a floating tag which is used by the repository generator to determine the most recent released version of each package for each core version. This allows package developers to publish their releases to all users of automatic upgrade without any intervention from the OpenACS release team.Reason 2: The compat tags allows CVS users to identify packages which have been released since the last core release.Reason 3: The compat tag or something similar is required to make Rule 6 possible.

      2. When OpenACS core is released, the openacs-x-y-z-final tag shall be applied to all compat packages.

        Reason: This allows OpenACS developers who are creating extensively customized sites to branch from a tag which is stable, corresponds to released code instead of development code, and applies to all packages. This tag can be used to fork packages as needed, and provides a common ancestor between the fork and the OpenACS code so that patches can be generated.

      For example, adding a new API function wouldn't require a TIP. Changing an existing API function by adding an optional new flag which defaults to no-effect wouldn't require a TIP. Added a new mandatory flag to an existing function would require a TIP.

    Informal Guidelines

    Informal guidelines which may be obsolete in places and should be reviewed:

    • Before committing to cvs you must submit a bug report and patch to the OpenACS bug tracker . The only exceptions to this rule are for package maintainers committing in a package they are maintaining and for members of the core team.

    • If you are committing a bug fix you need to coordinate with the package maintainer. If you are a maintainer then coordinate with any fellow maintainers.

    • If you are to commit a new feature, an architecture change, or a refactoring, you must coordinate with the OpenACS core team first. Also, such changes should have a discussion in the forums to allow for feedback from the whole community.

    • If you are changing the data model you *must* provide an upgrade script and bump up the version number of the package.

    • Consider any upgradability ramifications of your change. Avoid changing the contract and behaviour of Tcl procedures. If you want to build a new and clean API consider deprecating the old proc and making it invoke the new one.

    • Never rush to commit something. Before committing double check with cvs diff what exactly you are committing.

    • Always accompany a commit with a brief but informative comment. If your commit is related to bug number N and/or patch number P, indicate this in the commit comment by including "bug N" and/or "patch P". This allows us to link bugs and patches in the Bug Tracker with changes to the source code. For example suppose you are committing a patch that closes a missing HTML tag, then an appropriate comment could be "Fixing bug 321 by applying patch 134. Added missing h3 HTML close tag".

    • Commit one cohesive bug fix or feature change at a time. Don't put a bunch of unrelated changes into one commit.

    • Before you throw out or change a piece of code that you don't fully understand, use cvs annotate and cvs log on the file to see who wrote the code and why. Consider contacting the author.

    • Test your change before committing. Use the OpenACS package acs-automated-testing to test Tcl procedures and the tool Tclwebtest to test pages

    • Keep code simple, adhere to conventions, and use comments liberally.

    • In general, treat the code with respect, at the same time, never stop questioning what you see. The code can always be improved, just make sure you change the code in a careful and systematic fashion.

    Additional Resources for CVS

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/requirements-template.html0000644000175000017500000002527111501005400025232 0ustar frankiefrankie System/Application Requirements Template

    System/Application Requirements Template

    By You

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    Briefly explain to the reader what this document is for, whether it records the requirements for a new system, a client application, a toolkit subsystem, etc. Remember your audience: fellow programmers, AND interested non-technical parties such as potential clients, who may all want to see how rigorous our engineering process is. Here and everywhere, write clearly and precisely; for requirements documentation, write at a level that any intelligent layperson can understand.

    Vision Statement

    Very broadly, describe how the system meets a need of a business, group, the OpenACS as a whole, etc. Make sure that technical and non-technical readers alike would understand what the system would do and why it's useful. Whenever applicable, you should explicitly state what the business value of the system is.

    System/Application Overview

    Discuss the high-level breakdown of the components that make up the system. You can go by functional areas, by the main transactions the system allows, etc.

    You should also state the context and dependencies of the system here, e.g. if it's an application-level package for OpenACS 4, briefly describe how it uses kernel services, like permissions or subsites.

    Use-cases and User-scenarios

    Determine the types or classes of users who would use the system, and what their experience would be like at a high-level. Sketch what their experience would be like and what actions they would take, and how the system would support them.

    Optional: Competitive Analysis

    Describe other systems or services that are comparable to what you're building. If applicable, say why your implementation will be superior, where it will match the competition, and where/why it will lack existing best-of-breed capabilities. This section is also in the Design doc, so write about it where you deem most appropriate.

    Related Links

    Include all pertinent links to supporting and related material, such as:

    • System/Package "coversheet" - where all documentation for this software is linked off of

    • Design document

    • Developer's guide

    • User's guide

    • Other-cool-system-related-to-this-one document

    • Test plan

    • Competitive system(s)

    Requirements

    The main course of the document, requirements. Break up the requirements sections (A, B, C, etc.) as needed. Within each section, create a list denominated with unique identifiers that reflect any functional hierarchy present, e.g. 20.5.13. - for the first number, leave generous gaps on the first writing of requirements (e.g. 1, 10, 20, 30, 40, etc.) because you'll want to leave room for any missing key requirements that may arise.

    • 10.0 A Common Solution

      Programmers and designers should only have to learn a single system that serves as a UI substrate for all the functionally specific modules in the toolkit.

      10.0.1

      The system should not make any assumptions about how pages should look or function.

      10.0.5

      Publishers should be able to change the default presentation of any module using a single methodology with minimal exposure to code.

    For guidelines writing requirements, take a look at the quality standards, along with a good example, such as Package Manager Requirements.

    Besides writing requirements in natural language, consider using the following techniques as needed:

    • Pseudocode - a quasi programming language, combining the informality of natural language with the strict syntax and control structures of a programming language.

    • Finite State Machines - a hypothetical machine that can be in only one of a given number of states at any specific time. Useful to model situations that are rigidly deterministic, that is, any set of inputs mathematically determines the system outputs.

    • Decision Trees and Decision Tables - similar to FSMs, but better suited to handle combinations of inputs.

    • Flowcharts - easy to draw and understand, suited for event and decision driven systems. UML is the industry standard here.

    • Entity-Relationship diagrams - a necessary part of Design documents, sometimes a high-level ER diagram is useful for requirements as well.

    Optional: Implementation Notes

    Although in theory coding comes after design, which comes after requirements, we do not, and perhaps should not, always follow such a rigid process (a.k.a. the waterfall lifecyle). Often, there is a pre-existing system or prototype first, and thus you may want to write some thoughts on implementation, for aiding and guiding yourself or other programmers.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.3Edited further, incorporated feedback from Michael Yoon9/05/2000Kai Wu
    0.2Edited8/22/2000Kai Wu
    0.1Created8/21/2000Josh Finkler, Audrey McLoghlin
    ($Id: requirements-template.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/configuring-configuring-packages.html0000644000175000017500000000634311501005400027273 0ustar frankiefrankie Configuring an OpenACS package

    Configuring an OpenACS package

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Configuring an OpenACS package

    After you've installed and mounted your package, you can configure each instance to act as you would like.

    This is done from the Applications page. Log in, go to the Admin or Control Panel, click on the subsite the application is in, and click on Applications. If you click on the 'Parameters' link, you will see a list of parameters that you can change for this application.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/psgml-for-emacs.html0000644000175000017500000000666111501005400023674 0ustar frankiefrankie Add PSGML commands to emacs init file (OPTIONAL)

    Add PSGML commands to emacs init file (OPTIONAL)

    If you plan to write or edit any documentation with emacs, install a customized emacs configuration file with DocBook commands in the skeleton directory, so it will be used for all new users. The file also fixes the backspace -> help mis-mapping that often occurs in terminals.

    [root tmp]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/emacs.txt /etc/skel/.emacs
    cp: overwrite `/etc/skel/.emacs'? y
    [root tmp]# 

    Debian users:

    apt-get install psgml

    Note: The new nxml mode for emacs, when used in combination with psgml, provides a pretty good set of functionality that makes DocBook editing much less painless. In particular, nxml does syntax testing in real-time so that you can see syntax errors immediately instead of in the output of the xsltproc hours or days later. For debian, apt-get install nxml.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/snapshot-backup.html0000644000175000017500000004010211456662500024011 0ustar frankiefrankie Manual backup and recovery

    Manual backup and recovery

    This section describes how to make a one-time backup and restore of the files and database. This is useful for rolling back to known-good versions of a service, such as at initial installation and just before an upgrade. First, you back up the database to a file within the file tree. Then, you back up the file tree. All of the information needed to rebuild the site, including the AOLserver config files, is then in tree for regular file system backup.

    1. Back up the database to a file. 

      • Oracle. 

        • Download the backup script. Save the file export-oracle.txt as /var/tmp/export-oracle.txt

        • Login as root. The following commands will install the export script:

          [joeuser ~]$ su -
          [root ~]# cp /var/tmp/export-oracle.txt /usr/sbin/export-oracle
          [root ~]# chmod 700 /usr/sbin/export-oracle
        • Setup the export directory; this is the directory where backups will be stored. We recommend the directory /ora8/m02/oracle-exports.

          [root ~]# mkdir /ora8/m02/oracle-exports
          [root ~]# chown oracle:dba /ora8/m02/oracle-exports
          [root ~]# chmod 770 /ora8/m02/oracle-exports
        • Now edit /usr/sbin/export-oracle and change the SERVICE_NAME and DATABASE_PASSWORD fields to their correct values. If you want to use a directory other than /ora8/m02/oracle-exports, you also need to change the exportdir setting.

          Test the export procedure by running the command:

          [root ~]# /usr/sbin/export-oracle
          mv: /ora8/m02/oracle-exports/oraexport-service_name.dmp.gz: No such file or directory
          
          Export: Release 8.1.6.1.0 - Production on Sun Jun 11 18:07:45 2000
          
          (c) Copyright 1999 Oracle Corporation.  All rights reserved.
          
          Connected to: Oracle8i Enterprise Edition Release 8.1.6.1.0 - Production
          With the Partitioning option
          JServer Release 8.1.6.0.0 - Production
          Export done in US7ASCII character set and US7ASCII NCHAR character set
            . exporting pre-schema procedural objects and actions
            . exporting foreign function library names for user SERVICE_NAME 
            . exporting object type definitions for user SERVICE_NAME 
            About to export SERVICE_NAME's objects ...
            . exporting database links
            . exporting sequence numbers
            . exporting cluster definitions
            . about to export SERVICE_NAME's tables via Conventional Path ...
            . exporting synonyms
            . exporting views
            . exporting stored procedures
            . exporting operators
            . exporting referential integrity constraints
            . exporting triggers
            . exporting indextypes
            . exporting bitmap, functional and extensible indexes
            . exporting posttables actions
            . exporting snapshots
            . exporting snapshot logs
            . exporting job queues
            . exporting refresh groups and children
            . exporting dimensions
            . exporting post-schema procedural objects and actions
            . exporting statistics
          Export terminated successfully without warnings.
      • PostgreSQL. Create a backup file and verify that it was created and has a reasonable size (several megabytes).

        [root root]# su - $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ pg_dump -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ ls -al /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp 
        -rw-rw-r-x    1 $OPENACS_SERVICE_NAME  $OPENACS_SERVICE_NAME   4005995 Feb 21 18:28 /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
        [root root]#
        su - $OPENACS_SERVICE_NAME
        pg_dump -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp openacs-dev
        ls -al /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/before_upgrade_to_4.6.dmp
        exit
    2. Back up the file system. Back up all of the files in the service, including the database backup file but excluding the auto-generated supervise directory, which is unneccesary and has complicated permissions.

      In the tar command,

      • c create a new tar archive

      • p preserves permissions.

      • s preserves file sort order

      • z compresses the output with gzip.

      • The --exclude clauses skips some daemontools files that are owned by root and thus cannot be backed up by the service owner. These files are autogenerated and we don't break anything by omitting them.

      • The --file clause specifies the name of the output file to be generated; we manually add the correct extensions.

      • The last clause, /var/lib/aolserver/$OPENACS_SERVICE_NAME/, specifies the starting point for backup. Tar defaults to recursive backup.

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ tar -cpsz --exclude /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/supervise \
         --file /var/tmp/$OPENACS_SERVICE_NAME-backup.tar.gz /var/lib/aolserver/$OPENACS_SERVICE_NAME/
      tar: Removing leading `/' from member names
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    3. Suffer a catastrophic failure on your production system. (We'll simulate this step)

      [root root]# svc -d /service/$OPENACS_SERVICE_NAME
      [root root]# mv /var/lib/aolserver/$OPENACS_SERVICE_NAME/ /var/lib/aolserver/$OPENACS_SERVICE_NAME.lost
      [root root]# rm /service/$OPENACS_SERVICE_NAME
      rm: remove symbolic link `/service/$OPENACS_SERVICE_NAME'? y
      [root root]# ps -auxw | grep $OPENACS_SERVICE_NAME
      root      1496  0.0  0.0  1312  252 ?        S    16:58   0:00 supervise $OPENACS_SERVICE_NAME
      [root root]# kill 1496
      [root root]# ps -auxw | grep $OPENACS_SERVICE_NAME
      [root root]# su - postgres
      [postgres pgsql]$ dropdb $OPENACS_SERVICE_NAME
      DROP DATABASE
      [postgres pgsql]$ dropuser $OPENACS_SERVICE_NAME
      DROP USER
      [postgres pgsql]$ exit
      logout
      [root root]#
    4. Recovery. 

      1. Restore the operating system and required software. You can do this with standard backup processes or by keeping copies of the install material (OS CDs, OpenACS tarball and supporting software) and repeating the install guide. Recreate the service user ($OPENACS_SERVICE_NAME).

      2. Restore the OpenACS files and database backup file.

        [root root]# su - $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver
        [$OPENACS_SERVICE_NAME aolserver]$ tar xzf /var/tmp/$OPENACS_SERVICE_NAME-backup.tar.gz
        [$OPENACS_SERVICE_NAME aolserver]$ chmod -R 775 $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME aolserver]$ chown -R $OPENACS_SERVICE_NAME.web $OPENACS_SERVICE_NAME
      3. Restore the database

        • Oracle. 

          1. Set up a clean Oracle database user and tablespace with the same names as the ones exported from (more information).

          2. Invoke the import command

            imp $OPENACS_SERVICE_NAME/$OPENACS_SERVICE_NAME FILE=/var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/nighty_backup.dmp FULL=Y
        • Postgres. If the database user does not already exist, create it.

          [root root]# su - postgres
          [postgres ~]$ createuser $OPENACS_SERVICE_NAME
          Shall the new user be allowed to create databases? (y/n) y
          Shall the new user be allowed to create more new users? (y/n) y
          CREATE USER
          [postgres ~]$ exit
          

          Because of a bug in Postgres backup-recovery, database objects are not guaranteed to be created in the right order. In practice, running the OpenACS initialization script is always sufficient to create any out-of-order database objects. Next, restore the database from the dump file. The restoration will show some error messages at the beginning for objects that were pre-created from the OpenACS initialization script, which can be ignored.

          [root root]# su - $OPENACS_SERVICE_NAME
          [$OPENACS_SERVICE_NAME ~]$ createdb $OPENACS_SERVICE_NAME
          CREATE DATABASE
          [$OPENACS_SERVICE_NAME ~]$ psql -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-kernel/sql/postgresql/postgresql.sql $OPENACS_SERVICE_NAME
          (many lines omitted)
          [$OPENACS_SERVICE_NAME ~]$ psql $OPENACS_SERVICE_NAME < /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup/database-backup.dmp
          (many lines omitted)
          [$OPENACS_SERVICE_NAME ~]$ exit
          [postgres ~]$ exit
          logout
      4. Activate the service

        [root root]# ln -s /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools /service/$OPENACS_SERVICE_NAME
        [root root]# sleep 10
        [root root]# svgroup web /service/$OPENACS_SERVICE_NAME
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/openacs.css0000644000175000017500000000232410010221045022143 0ustar frankiefrankie/* These are aimed at DocBook output, specifically from the chunk.xsl style and derivatives /* body,ol,td,th,hr,h1,h2,h3,strong,dl,a,blockquote,em,.force,dt,dd,ul,li,p { font-family: verdana,helvetica,arial,sans-serif; } a:link {color: #f00;} a:visited {color: #000099;} a.topnav {font-size: 1.2em;} a.bottomnav {font-size: 1.2em;} code { font-family: courier,monospace; } .codeblock { background-color: #fff; font-family: monospace; } .strong {font-weight: bold;} .authorblurb {font-size: small;} /* this is intended to catch docbook Screen stuff */ pre {background-color: #eee;} /* DocBook stuff */ .guibutton { background-color: #fff; border: solid #eee 3px; margin: 2px; } .replaceable { color: red; font-style: italic; } .guilabel { background-color: #ccc; margin: 2px; } .programlisting { background-color: #eee; margin-left: 1em; padding-left: .5em; } .strong {font-weight:bold;} .authorblurb {font-size:small;} .screen { padding:4px; margin-left: 1em; } .action {font-weight:bold;} .table,.informaltable,.informalfigure,.figure { margin-left: 1em; } body { margin: 1em 0 0 1em; max-width: 75em; } div.cvstag { font-family: courier,monospace; color: #999; font-size: small; text-align: right; } openacs-5.7.0/packages/acs-core-docs/www/upgrade-4.6.3-to-5.html0000644000175000017500000002363711501005400023561 0ustar frankiefrankie Upgrading OpenACS 4.6.3 to 5.0

    Upgrading OpenACS 4.6.3 to 5.0

    • Oracle. This forum posting documents how to upgrade an Oracle installation from OpenACS 4.6.3 to 5 .

    • PostGreSQL. You must use PostGreSQL 7.3.x or newer to upgrade OpenACS beyond 4.6.3. See Upgrade PostGreSQL to 7.3; Table 2.2. Version Compatibility Matrix

      1. Back up the database and file system.

      2. Upgrade the file system for packages/acs-kernel. Upgrading the OpenACS files

      3. Upgrade the kernel manually. (There is a script to do most of the rest: /contrib/misc/upgrade_4.6_to_5.0.sh on HEAD). You'll still have to do a lot of stuff manually, but automated trial and error is much more fun.)

        [root root]# su - $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/ $OPENACS_SERVICE_NAME/packages/acs-kernel/sql/postgresql/upgrade

        Manually execute each of the upgrade scripts in sequence, either from within psql or from the command line with commands such as psql -f upgrade-4.6.3-4.6.4.sql $OPENACS_SERVICE_NAME. Run the scripts in this order (order is tentative, not verified):

        psql -f upgrade-4.6.3-4.6.4.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-4.6.4-4.6.5.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-4.6.5-4.6.6.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-4.7d-4.7.2d.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-4.7.2d-5.0d.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0d-5.0d2.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0d2-5.0d3.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0d6-5.0d7.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0d7-5.0d9.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0d11-5.0d12.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0.0a4-5.0.0a5.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0.0b1-5.0.0b2.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0.0b2-5.0.0b3.sql $OPENACS_SERVICE_NAME
        psql -f upgrade-5.0.0b3-5.0.0b4.sql $OPENACS_SERVICE_NAME
      4. Upgrade ACS Service Contracts manually:

        [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/ $OPENACS_SERVICE_NAME/packages/acs-service-contracts/sql/postgresql/upgrade
        psql -f upgrade-4.7d2-4.7d3.sql $OPENACS_SERVICE_NAME
        
      5. Load acs-authentication data model.

        psql -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/openacs-5/packages/acs-authentication/sql/postgresql/acs-authentication-create.sql $OPENACS_SERVICE_NAME
      6. Load acs-lang data model.

        psql -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-lang/sql/postgresql/acs-lang-create.sql $OPENACS_SERVICE_NAME
      7. (This step may overlap with the two previous steps, but I think it's harmless?) Create a file which will be executed on startup which takes care of a few issues with authentication and internationalization: create $OPENACS_SERVICE_NAME/tcl/zzz-postload.tcl containing:

        if {![apm_package_installed_p acs-lang]} {
        apm_package_install -enable -mount_path acs-lang [acs_root_dir]/packages/acs-lang/acs-lang.info
        lang::catalog::import -locales [list "en_US"]
        }
        
        if {![apm_package_installed_p acs-authentication]} {
        apm_package_install -enable [acs_root_dir]/packages/acs-authentication/acs-authentication.info
        apm_parameter_register "UsePasswordWidgetForUsername" \
        "Should we hide what the user types in the username
        field, the way we do with the password field? Set
        this to 1 if you are using sensitive information
        such as social security number for username." \
        acs-kernel 0 number \
        security 1 1
        parameter::set_value -package_id [ad_acs_kernel_id] -parameter UsePasswordWidgetForUsername -value 0
        }
      8. If you can login, visit /acs-admin/apm and upgrade acs-kernel and acs-service-contract and uncheck the data model scripts. Restart. If everything is still working, make another backup of the database.

      9. Upgrade other packages via the APM

      See also these forum posts: Forum OpenACS Development: 4.6.3 upgrade to 5-HEAD: final results, OpenACS 5.0 Upgrade Experiences.

      There are a few things you might want to do once you've upgraded. First, the acs-kernel parameters need to be set to allow HREF and IMG tags, if you want users who can edit HTML to be able to insert HREF and IMG tags. Also, you might need to set the default language for your site. See the above link on OpenACS 5.0 Upgrade Experiences for details.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/ix01.html0000644000175000017500000001671511501005400021462 0ustar frankiefrankie Index

    Index

    Symbols

    $OPENACS_SERVICE_NAME, Paths and Users

    C

    computeroutput
    code, Code
    cvs
    initializing, Initialize CVS (OPTIONAL)
    setup, Using CVS with an OpenACS Site

    E

    emacs
    installation, Install Red Hat 8/9
    emphasis
    bold, italics, Emphasis

    G

    Graphics
    Images, Graphics

    I

    informaltable
    table, Tables

    L

    language
    installation, Install Red Hat 8/9
    Linking, Links
    lists, Lists

    O

    OpenACS Package, What a Package Looks Like

    P

    photo-album
    installation (see ImageMagick)
    Postgres
    Vacuuming, Installation Option 2: Install from tarball

    Q

    qmail
    installation, Install qmail (OPTIONAL)
    Maildir, Install qmail (OPTIONAL)
    rcpthosts error message, Install qmail (OPTIONAL)

    T

    The publish point for new packages should be fixed., Prepare the package for distribution.

    U

    ulink, Links
    upgrade
    OpenACS 4.5 to 4.6.x
    Linux/Unix, Upgrading 4.5 or higher to 4.6.3
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/eng-standards-constraint-naming.html0000644000175000017500000002072111501005400027054 0ustar frankiefrankie Constraint naming standard

    Constraint naming standard

    By Michael Bryzek

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    The Big Picture

    Constraint naming standard is important for one reason: The SYS_* name oracle assigns to unnamed constraints is not very understandable. By correctly naming all contraints, we can quickly associate a particular constraint with our data model. This gives us two real advantages:

    • We can quickly identify and fix any errors.

    • We can reliabily modify or drop constraints

    Why do we need a naming convention?

    Oracle limits names, in general, to 30 characters, which is hardly enough for a human readable constraint name.

    Abbreviations

    We propose the following naming convention for all constraints, with the following abbreviations taken from Oracle Docs at http://oradoc.photo.net/ora81/DOC/server.815/a67779/ch4e.htm#8953. Note that we shortened all of the constraint abbrevations to two characters to save room.

    Constraint typeAbbreviation
    references (foreign key)fk
    uniqueun
    primary keypk
    checkck
    not nullnn

    Format of constraint name

    <table name>_<column_name>_<constraint abbreviation>

    In reality, this won't be possible because of the character limitation on names inside oracle. When the name is too long, we will follow these two steps in order:

    1. Abbreviate the table name with the table's initials (e.g. users -> u and users_contact -> uc).

    2. Truncate the column name until it fits.

    If the constraint name is still too long, you should consider rewriting your entire data model :)

    Notes:

    • If you have to abbreviate the table name for one of the constraints, abbreviate it for all the constraints

    • If you are defining a multi column constraint, try to truncate the two column names evenly

    Example

    create table example_topics (
           topic_id    integer
    		   constraint example_topics_topic_id_pk
    		   primary key
    );
    
    create table constraint_naming_example (
           example_id		      integer
    				      constraint cne_example_id_pk
    				      primary key,
           one_line_description	      varchar(100)
    				      constraint cne_one_line_desc_nn
    				      not null,
           body			      clob,
           up_to_date_p		      char(1) default('t')
    				      constraint cne_up_to_date_p_check
    				      check(up_to_date_p in ('t','f')),
           topic_id			      constraint cne_topic_id_nn not null
    				      constraint cne_topic_id_fk references example_topics,
           -- Define table level constraint
           constraint cne_example_id_one_line_unq unique(example_id, one_line_description)
    );
    
    

    Why it's good to name primary keys

    Naming primary keys might not have any obvious advantages. However, here's an example where naming the primary key really helps (and this is by no means a rare case!

    SQL> set autotrace traceonly explain;
    
    
    SQL> select * from constraint_naming_example, example_topics 
    where constraint_naming_example.topic_id = example_topics.topic_id;
    
    Execution Plan
    ----------------------------------------------------------
       0	  SELECT STATEMENT Optimizer=CHOOSE
       1	0   NESTED LOOPS
       2	1     TABLE ACCESS (FULL) OF 'CONSTRAINT_NAMING_EXAMPLE'
       3	1     INDEX (UNIQUE SCAN) OF 'EXAMPLE_TOPICS_TOPIC_ID_PK' (UNI
    	  QUE)
    

    Isn't it nice to see "EXAMPLE_TOPICS_TOPIC_ID_PK" in the trace and know exactly which table oracle is using at each step?

    Naming not null constraints is optional...

    People disagree on whether or not we should be naming not null constraints. So, if you want to name them, please do so and follow the above naming standard. But, naming not null constraints is not a requirement.

    About Naming the not null constraints

    Though naming "not null" constraints doesn't help immeditately in error debugging (e.g. the error will say something like "Cannot insert null value into column"), we recommend naming not null constraints to be consistent in our naming of all constraints.

    ($Id: eng-standards-constraint-naming.html,v 1.46 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/object-identity.html0000644000175000017500000001205111501005400023763 0ustar frankiefrankie Object Identity

    Object Identity

    By Rafael H. Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    One of the major design features of OpenACS 5.6.0 is the explicit representation of object identity. The reason I say "explicit representation" is because the concept of object identity has been around forever. It is inherent to our problem domain. Consider the example of 3.x style scoping. The 3.x data models use the triple (user_id, group_id, scope) to identify an object. In the 5.6.0 data model this object is explicitly represented by a single party_id.

    Another good example of this is can be found in the user groups data model. The 3.x user groups data model contains another example of an implied identity. Every mapping between a user and a group could have an arbitrary number of attached values (user_group_member_fields, etc.). In this case it is the pair (group_id, user_id) that implicitly refers to an object (the person's membership in a group). In the 5.6.0 data model this object identity is made explicit by adding an integer primary key to the table that maps users to groups.

    Coming from a purely relational world, this might seem slightly weird at first. The pair (group_id, user_id) is sufficient to uniquely identify the object in question, so why have the redundant integer primary key? If you take a closer look, it actually isn't quite so redundant. If you want to be able to use the object model's permissioning features, and generic attribute features on a table, you need an integer primary key for that table. This is because you can't really write a data model in oracle that uses more than one way to represent identity.

    So, this apparently redundant primary key has saved us the trouble of duplicating the entire generic storage system for the special case of the user_group_map, and has saved us from implementing ad-hoc security instead of just using acs-permissions. This design choice is further validated by the fact that services like journals that weren't previously thought to be generic can in fact be generically applied to membership objects, thereby allowing us to eliminated membership state auditing columns that weren't even capable of fully tracking the history of membership state.

    The design choice of explicitly representing object identity with an integer primary key that is derived from a globally unique sequence is the key to eliminating redundant code and replacing it with generic object level services.

    ($Id: object-identity.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-schedule-procs.html0000644000175000017500000000553211501005400025455 0ustar frankiefrankie Scheduled Procedures

    Scheduled Procedures

    Put this proc in a file /packages/myfirstpackage/tcl/scheduled-init.tcl. Files in /tcl with the -init.tcl ending are sourced on server startup. This one executes my_proc every 60 seconds:

    ad_schedule_proc 60 myfirstpackage::my_proc
    

    This executes once a day, at midnight:

    ad_schedule_proc \
        -schedule_proc ns_schedule_daily \
        [list 0 0] \
        myfirstpackage::my_proc
    

    See ad_schedule_proc for more information.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/configuring-install-packages.html0000644000175000017500000001113611501005400026423 0ustar frankiefrankie Installing OpenACS packages

    Installing OpenACS packages

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Installing OpenACS packages

    An OpenACS package extends your website and lets it do things it wasn't able to do before. You can have a weblog, a forums, a calendar, or even do sophisticated project-management via your website.

    After you've installed OpenACS, you can congratulate yourself for a job well done. Then, you'll probably want to install a couple of packages.

    To install packages, you have to be an administrator on the OpenACS webserver. Log in, and you'll see a link to Admin or the Control Panel. Click on that, then click on 'Install software'. Packages are sometimes also referred to as applications or software.

    At this point, you'll need to determine whether or not you're able to install from the repository, or whether you should install from local files.

    Basically, if you have a local CVS repository, or have custom code, you need to install from 'Local Files'. Otherwise, you can install from the OpenACS repository

    If you want to install new packages, click on 'Install from Repository' or 'Install from Local'. Select the package, and click 'Install checked applications'. The system will check to make sure you have all necessary packages that the package you want depends on. If you're installing from Local Files, and you are missing any packages, you may have to add the packages your desired package depends on: Upgrading the OpenACS files

    If you run into any errors at all, check your /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/error.log file, and post your error on the OpenACS forums

    Once the package has been installed, then you will need to 'mount' the package. The next section handles that.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/ext-auth-requirements.html0000644000175000017500000014043211501005400025153 0ustar frankiefrankie External Authentication Requirements

    External Authentication Requirements

    Vision

    People have plenty of usernames and passwords already, we don't want them to have yet another. We want people to be able to log in to OpenACS with the same password they use to log in to any other system.

    Besides, administrators have better things to do than create accounts for people. So we want them to be able to create just one account on a central server (e.g. LDAP or RADIUS), and when they log on to OpenACS, an account will automatically be created for them here.

    Finally, security is increased with fewer passwords, since users generally can't remember all those passwords, so they tend to keep them all the same and never change them.

    Design Goals

    • Transparent: Users don't have to do anything special to get an account on the local OpenACS system, if they already have an account on the external authentication server.

    • Fall-back: Users who don't have an account on the external authentication server are still allowed to create a local account on OpenACS. This could be for external students who should have access to .LRN, but not to the rest of the university's resources.

    • Authentication Client Only: We want OpenACS to be able to authenticate by asking some remote authority to verify the user's username/password combination. The goal is explicitly not (at this point) to have OpenACS act as an authentication server for other systems, although this could be easily added later. The goal is also not to devise an infrastructure for letting OpenACS access resources in various other systems on the user's behalf, such as IMAP, iCalendar, SMB file servers, etc., although this is definitely an interesting use-case.

    • Easy configuration: We would like people to be able to configure this without having to write code. In particular, we want to build drivers that know how to talk with LDAP, RADIUS, PAM, etc., and which won't have to be locally modified. Only configuration and policies should change, code should not.

    • Usability: The solution must be easy to use for end users and administrators alike. There's frequently a positive feedback effect between usability and security, because when authentication schemes have poor usability, users will think up ways to circumvent them.

    • Open and modular: The design should be on the one hand open to add other authentification mechanisms when needed and on the other hand very modular to enable a start with minimal requirements (driver implementations) as soon as possible.

    The problem can be split into several logically separate parts. Each has a section below.

    Terminology

    • Authority: The name of an authority trusted to authenticate users.

    • Authentication Driver: An implementation of the authentication service contract, which talks to an authentication of a certain type, e.g. PAM, RADIUS, LDAP, or Active Directory.

    • Authentication API: The API through which login pages and applications talk to the authentication service. There's one and only one implementation of the authentication API, namly the one included in OpenACS Core.

    • Authentication Driver API: The service contract which authentication drivers implement.

    Conceptual Pictures

    Authentication:

    Account Management (NO PICTURE YET)

    Batch Synchronization (NO PICTURE YET)

    Requirements

    New API

    FeatureStatusDescription
    New API
    EXT-AUTH-01AExtend Authentication/Acct Status API
    EXT-AUTH-03AAccount Creation API
    EXT-AUTH-05APassword Management API
    EXT-AUTH-30AAuthority Management API

    Login

    FeatureStatusDescription
    Login
    EXT-AUTH-04ARewrite login, register, and admin pages to use APIs
    EXT-AUTH-38Aad_form complain feature
    EXT-AUTH-19ARewrite password recovery to use API
    EXT-AUTH-21ARewrite email verification with API
    EXT-AUTH-28AUsername is email switch

    Users will log in using a username, a authority, and a password. The authority is the source for user/password verification. OpenACS can be an authority itself.

    Each user in OpenACS will belong to exactly one authority, which can either be the "local" OpenACS users table, in which case the password column is used, or it can be some external authority, which will be communicated with using some protocol, as implemented by an authentication driver.

    Username will be separate from email address. It can be an email address, it can look like an email address but not be the name of an actual email mailbox, or it can be something else entirely.

    We're assuming that user information (name, email, etc.) will either already be in the users table through a batch synchronization job, or that the relevant authentication implementation supports real-time synchronization of user data. Specifically, if you want remote users who haven't yet logged in to OpenACS to show up in user searches, you'll have to do the batch synchronization.

    All in all, the login box will be an includeable template and look like this:

    Username:  ________
    Password:  ________
    Authority: [URZ   ]
                Athena
                Local
    
    [Forgot my password]
    [New user registration]
    

    If there's only one active authority, we don't display the authority drop-down element at all.

    Configuration

    FeatureStatusDescription
    Configuration
    EXT-AUTH-07AAdmin pages to control Ext-Auth parameters

    The site-wide systems administrator can configure the authentication process from a page linked under /acs-admin.

    • Authorities - ordered list of authorities defined

    • Account Registration Allowed: Yes/No. Account registration can be disabled altogether.

    • Registration authority - the authority in which accounts should be created, using the relevant driver, if account registration is allowed.

    • Username is email? - instead of asking for username, we'll ask for email. And we'll store the value in both columns, username and email. This is a setting that spans all authorities, and is primarily meant for backwards compatibility with the old OpenACS login process.

    The local authority driver is an encapsulation of current functionality within an driver matching a service contract. The other drivers call external functions. The possible functions for each authority are split into several drivers for convenience. One driver handles authentication, one account creation, and one changing passwords.

    FeatureStatusDescription
    create service contract
    EXT-AUTH-16ACreate service contract for Authentication
    EXT-AUTH-17ACreate service contract for Acct. Creation
    EXT-AUTH-29ACreate service contract for Passwd Management
    FeatureStatusDescription
    EXT-AUTH-18AAuthority configuration data model

    Each authority is defined like this:

    • Authority pretty-name, e.g. "URZ"

    • Authentication Driver, e.g. "RADIUS". In practice, this would be a reference to a service contract implementation.

    • Authentication Driver configuration settings, e.g. host name, port, etc., as required by the particular driver. Note that this is per authority, not per driver, i.e., you can have multiple authorities with the same driver but different configuration options.

    • AuthenticationAllowed - true/false, so you can disable login through some authority without having to delete the authority, and hence also all the users who belong to that authority.

    • ForgottenPasswordUrl - a URL to redirect to instead of trying to use the authentication driver's password management features.

    • ChangePasswordUrl - a URL to redirect to instead of trying to use the authentication driver's password management features.

    • Account Creation Driver, e.g. "RADIUS". In practice, this would be a reference to a service contract implementation. The reason we have separate drivers for authentication and account creation is that organizations are likely to have a home-grown account registration process.

    • Account Creation Driver configuration settings, e.g. host name, port, etc., as required by the particular driver. Note that this is per authority, not per driver, i.e., you can have multiple authorities with the same driver but different configuration options.

    • RegistrationUrl - instead of registering using OpenACS, redirect to a certain URL site for account registration.

    • RegistrationAllowed - true/false, so you can disable registration using this account.

    • Sort order: Preference order of authorities.

    • HelpContactText: Text or HTML to be displayed when user has trouble authenticating with the authority. Should include contact information such as a phone number or email.

    Each authority driver will have a set of configuration options dependent on the driver, such as host, port, etc. We will need to find a mechanism for the driver to tell us which configuration options are available, a way to set these, and a way for the driver to access these settings.

    OpenACS will come pre-configured with one authority, which is the "local" authority, meaning we'll authenticate as normal using the local users table. This will, just like any other authority, be implemetned using a service contract.

    Synchronizing and Linking Users

    FeatureStatusDescription
    Synchronizing and linking users
    EXT-AUTH-28ACreate service contract for Batch Sync.
    EXT-AUTH-38ABatch User Synchronization API
    EXT-AUTH-38AIMS Synchronization driver
    EXT-AUTH-08AAutomation of batch Synchronization
    EXT-AUTH-15BOn-demand syncronization

    Regardless of the login method, the user needs to have a row in the OpenACS users table. This can happen through a batch job, in real-time, or both in combination. We use the IMS Enterprise 1.1 specification.

    Batch job means that we do a synchronization (import new users, modify changed, purge deleted) on a regular interval, e.g. every night. You can also decide to have a monthly full synchronization, plus daily incremental ones. That's up to you. The advantage is that you have all users in OpenACS, so when you search for a user, you'll see all the organization's users, not just those who happen to have used the OpenACS-based system. The down-side is that it takes some time for user information to propagate. This can be remedied by using the real-time solution. The batch job will also require error logging and an admin interface to view logs.

    If an email already belongs to some other user, we log it as an error.

    A user will always belong to exactly one authority, which can be either the "local" authority or some other. Thus, the OpenACS user's table will have to be augmented with the following columns:

    • Authority. Reference to the site-wide authorities list. The authority which can authenticate this user.

    • Authority-specific username.

    Real-time means that the first time the user logs into OpenACS, we'll query the authority that authenticated him for information about this user. That authentication authority will then give us at least first names, last name and email. The pros and cons are the opposite of batch jobs. Using both in combination is ideal.

    Note: One solution to the "two users from different authorities have the same email" problem above would be to allow users to belong to multiple authorities. Then we would notice that the email already exists, ask the user if he thinks he's the same person, and if so, ask him to prove so by authenticating using the other authority. Thus he'll have just authenticated in two different authorities, and we can record that this is the same person. We'd still have a problem if there was an email conflict between two accounts on the same authority. Hm. I don't think it's worth spending too much time trying to solve this problem through software.

    FeatureStatusDescription
    EXT-AUTH-31
    EXT-AUTH-31AUpgrade user data model for ext-auth

    After having authenticated using the relevant authority driver, we'll look for the username/authority pair in the users table.

    If we don't find any, that means that we're either not doing batch synchronizing, or that the user has been added since the last sync. In that case, we'll try to do a real-time synchronization, if the driver supports it. If it does, it'll return email, first_names, last_name, and other relevant information, and we'll create a row in the local users table using that information.

    If that doesn't work, we'll tell the user that their account isn't yet available, and the driver will supply a message for us, which could say "The account should be available tomorrow. If not, contact X."

    Account Registration

    If a user doesn't have an account, the site-wide configuration can allow the user to register for one, as defined in the configuration discussed above. This section is about normal account registration through a authority driver.

    The account creation service contract implementation will need to tell us which information to ask the user for:

    • Required Fields: A list of fields which are required.

    • Optional Fields: A list of fields which are optional.

    The fields to choose from are these:

    • Username

    • First names

    • Last name

    • Email

    • URL

    • Password

    • Secret question

    • Secret answer

    It should return the following:

    • Creation status (OK, Try-Again, Fail)

    • Creation message: What went wrong, or a welcome message.

    • Account status: Is the account ready for use?

    • User information: first_names, last_name, email, url, password, password_hash, secret_question, secret_answer. The driver only needs to return the columns which were changed or added through the registration process. Typically, only the "local" driver will return password and secret question/answer.

    After creating the remote account, a local account is created with the information gathered through the form/returned by the driver.

    By default, a local account creation implementation is provided, which will create a new OpenACS user, and, in addition to the default local account creation above, also store the password in hashed form.

    Password Management

    Password management is about changing password, retrieving password, and resetting password.

    It's up to the authority driver implementation to decide whether to support any or all of these features, and to say so using the CanXXX methods (see driver API below).

    Additionally, the authority can be configured with a URL to redirect to in the case of forgotten passwords, or when the user desires to change password.

    Login Pages Over HTTPS

    FeatureStatusDescription
    EXT-AUTH-20
    EXT-AUTH-20ALogin over HTTPS

    Login pages must be able to be sent over a secure connection (https), so your password won't get sent over the wire in cleartext, while leaving the rest of the site non-secure (http). I believe that this requires some (minor) changes to the current session handling code.

    Email Verification

    Email verification needs to be handled both at registration and at login.

    In both cases, it'll be handled by the driver sending automatically sending the email containing a link for the user to verify his account. Then the driver will return an account status of "closed,temporary", and a message that says "Check your inbox and click the link in the email".

    OpenACS will have a page which receives the email verification, for use by local accounts. Other authorities will have to implement their own page, most likely on the authority's own server.

    Other Items

    There are a number of items which touch on external authentication and session management. And even though they're not directly linked to external authentication, I would recommend that we handle a number of them, either because they're important for security, or because it makes sense to fix them while we're messing with this part of the codebase anyway.

    Recommended: Untrusted Logins and Login Levels

    FeatureStatusDescription
    EXT-AUTH-33
    EXT-AUTH-33AUntrusted Logins

    I like the idea of having multiple login levels:

    1. Not logged in

    2. Untrusted login: We'll show you un-sensitive personal content, but won't let you modify anything or see personal data. A normal login becomes untrusted after a certain amount of time, and the user will have to re-enter his/her password in order to gain access to personal data. Untrusted login never expires, unless explicitly done so through either changing password or clicking a special "expire all logins" link.

    3. Normal login: The user is logged, and has type his password sufficiently recently that we trust the login. All normal operations are allowed. Will degrade to untrusted login after a specified amount of time.

    4. Secure login: The user is logged in over a secure connection (HTTPS), potentially even using a special secure password. This would be for sensitive actions, such as credit card transactions.

    There are two advantages to this. First, when people's login expires, we can ask them to re-enter only their password, and not both username and password, since we'll still remember who they were the last time their login was valid. This is a much faster operation (the password input field will be focused by default, so you just type your password and hit Return) that typing both username and password, which will make it practical to have your site configured to expire people's login after e.g. 2, 4, or 8 hours.

    The other advantage is that we can still offer certain functionality to you, even when your login is not trusted. For example, we could let you browse publically available forums, and only when you want to post do you need to log in. This makes it even more feasible to have a more secure login expiration setting.

    By default, auth::require_login would bounce to the login page if the user is only logged in at the untrusted level. Only if you explicitly say auth::require_login -untrusted will we give you the user_id of a user who's only logged in in untrusted mode.

    Similarly, ad_conn user_id will continue to return 0 (not logged in) when the user is only logged in untrusted, and we'll supply another variable, ad_conn untrusted_user_id, which wlll be set to the user_id for all login levels.

    This should ensure that we get full access to the new feature, while leaving all current code just as secure as it was before.

    Recommended: Make Non-Persistent Login Work

    FeatureStatusDescription
    EXT-AUTH-34
    EXT-AUTH-34AExpire Logins

    Currently, OpenACS is unusable in practice without persistent login. The login will expire after just a few minutes of inactivity, and you'll get bounced to the login page where you have to enter both email and password again. Unacceptable in practice.

    We should change the default, so a non-persistent login doesn't expire until you either close your browser, or a few hours have elapsed. Even if you are constantly active, the login should still expire after at most x number of hours. We can still make the login expire after a period of inactivity, but the amount of time should be configurable and default to something reasonable like an hour or so.

    This will require looking into and changing the design of the current session handling code.

    Recommended: Single-Sign-On

    FeatureStatusDescription
    EXT-AUTH-23
    EXT-AUTH-23Single sign-on

    Instead of redirecting to the login page, auth::require_login can redirect to an authentication server, which can redirect back to a page that logs the user in. This should be very easy to implement.

    Alternatively, if you want to combine this with fallback to OpenACS accounts, we would instead present the normal login screen, but put a button which says "Login using X", where X is the redirection-based external authority.

    Recommended: Expire All Logins

    FeatureStatusDescription
    EXT-AUTH-22
    EXT-AUTH-22Brewrite cookie handling

    Currently, if you've ever left a permanent login cookie on someone elses machine, that person will be forever logged in until he/she explicitly logs out. You can change your password, you can do anything you want, but unless a logout is requested from that particular browser, that browser will be logged in forever.

    I want to change our session handling code so that old login cookies can be expired. This would be done automatically whenever you change your password, and we could also offer a link which does this without changing passwords. It's an important security measure.

    The implementation is simply to autogenerate some secret token which is stored in the users table, and is also stored in the cookie somehow. Then, whenever we want to expire all logins, we'll just regenerate a new secret token, and the other cookies will be void. Of course, we don't want to incur a DB hit on every request, so we'll need to cache the secret token, or only check it when refreshing the session cookie, which, I believe, normally happens every 10 minutes or so.

    Recommended: Email account owner on password change

    FeatureStatusDescription
    EXT-AUTH-24
    EXT-AUTH-24AEmail on password change

    As an additional security measure, we should email the account's email address whenever the password is changed, so that he/she is at least alerted to the fact.

    Optional: Password policy

    FeatureStatusDescription
    EXT-AUTH-25
    EXT-AUTH-25AImplement password policy

    Again, to increase security, we should add password policies, such as passwords needing to be changed after a certain number of days, change on next login (after a new random password has been generated), or requiring that the password satisfies certain complexity rules, i.e. both upper and lowercase characters, numbers, special chars, etc.

    It would good to extend the current maximum password length from 10 to at least 32 characters.

    Optional: Login Without Explicit Authority

    FeatureStatusDescription
    EXT-AUTH-26
    EXT-AUTH-26BLogin without explicit domain

    In order to make it easier for people, we've been toying with the idea of a functionality like this:

    • If the user enters "foobar@ix.urz.uni-heidelberg.de", it is translated to mean username = "foobar", authority = "ix.urz.uni-heidelberg.de".

    • If the user enters "foobar", it's recognized to not include any authority, and the default authority of "ix.urz.uni-heidelberg.de" is used.

    • If the user enters "foo@bar.com", it's recognized as not belonging to any known authority, and as such, it's translated to mean username = "foo@bar.com", authority = "local".

    If this is deemed desirable, a way to implement this would be through these settings:

    • Split: A regexp which will split the user's entry into username and authority parts. For example "^([^@]+)(@[^@]+)?$". An easier to use but less flexible method would be that you simply specify a certain character to split by, such as "@" or "\". If the regexp doesn't match, or in the latter case, if there's more than one occurrence of the specified character sequence, the split will fail, signaling that the user's entry was not valid.

    • Default authority: The default authority will be the first one in the sort order.

    The relevant code in user-login.tcl would look like this:

    if { ![auth::split_username -username_var username -authority_var authority] } {
        # bounce back to the form with a message saying that the login wasn't valid.
        ad_script_abort
    }
    
    # username will now contain username
    # authority will now contain authority
    

    Optional: Who's Online

    FeatureStatusDescription
    EXT-AUTH-27
    EXT-AUTH-27BWho's online list

    While we're touching the session handling code, anyway, it would be nice to add a feature to show who's currently online, a nice real-time collaboration feature frequently requested by members of the community. This is particularly interesting when integrated with a chat or instant messaging service like Jabber.

    What I'm concretely suggesting is that we keep a record of which authenticated users have requested pags on the site in the last x minutes (typically about 5), and thus are considered to be currently online. There's nothing more to it. This lets us display a list of "active users" somewhere on the site, and make their name a link to a real-time chat service like Jabber.

    We've already made the changes necessary to security-procs.tcl to do this on an earlier project, but haven't quite finished the work and put it back into the tree.

    Optional: Subsite-level configuration

    FeatureStatusDescription
    EXT-AUTH-28
    EXT-AUTH-28implement subsite-level config

    If we want to, we could let subsite administrators configure the login process for that particular subsite. This would probably only entail letting the subsite admin leave out certain authorities defined site-wide, and change the sort order.

    I think we should leave this out until we have a use case for it, someone who'd need it.

    Future: Making the Authentication API itself a service contract

    FeatureStatusDescription
    EXT-AUTH-32
    EXT-AUTH-32AParameters for Service Contract Implementation
    EXT-AUTH-35AMake the Authentication API a service contract

    For completely free-form authentication logic and mechanisms, something like Andrew Grumet's Pluggable Authentication for OACS Draft is interesting. He's proposing a scheme where the entire user interaction is encapsulated in, and left entirely to, a service contract. This certainly opens up more advanced possibilities, such as perhaps smart cards, personal certificates, etc.

    I have chosen not to go this route, because I think that most people are going to want to use a username/password-based scheme, and having easy configuration through a web UI is more important than total flexibility at this point.

    Besides, we can always do this in the future, by letting the public Authentication API (auth::require_login and auth::authenticate) be implemented through a service contract.

    Future: Authenticating against multiple servers simultaneously

    FeatureStatusDescription
    EXT-AUTH-36
    EXT-AUTH-36AAuthenticate against multiple servers

    Both OKI and OpenACS supports a form of stacking, where you can be logged into multiple authorities at the same time. This is useful if, for example, you need to get login tokens such as Kerberos tickets for access to shared resources.

    I can see the value in this, but for simplicity's sake, I'm in favor of keeping this use-case out of the loop until we have someone with a real requirement who could help us guide development.

    For now, OpenACS is still more of an integrated suite, it doesn't access many outside applications. I think it would be excellent for OpenACS to do so, e.g. by using an IMAP server to store emails, an iCal server to store calendar appointments, LDAP for user/group data and access control lists, SMB for file storage, etc. But at the moment, we don't have any users of such things that are ready. We have some who are on the steps, but let's wait till they're there.

    Implement Specific Drivers

    FeatureStatusDescription
    Implement specific drivers
    EXT-AUTH-09ACreate Auth. drivers for Local Authority
    EXT-AUTH-10ACreate Acct. Creation driver for Local Authority
    EXT-AUTH-11ACreate Auth. driver for PAM
    EXT-AUTH-12XCreate Acct. Creation driver for PAM - this functionality is explicitly excluded from PAM
    EXT-AUTH-13ACreate Acct. Creation driver for LDAP
    EXT-AUTH-14ACreate Auth. driver for LDAP

    We'll need drivers for:

    • Operating system (Linux/Solaris) PAM: Delegate to the operating system, which can then talk to RADIUS, LDAP, whatever. This is convenient because there'll be plenty of drivers for the OS PAM level, so we don't have to write them all ourselves. The downside is that we can't do things like account creation, password management, real-time account synchronization, etc., not supported by PAM (I'm not entirely sure what is and is not supported).

    • RADIUS

    • LDAP

    RADIUS

    RADIUS is a simple username/password-type authentication server.

    It also supports sending a challenge to which the user must respond with the proper answer (e.g. mother's maiden name, or could be additional password), but we will not support this feature.

    A RADIUS client implementation in Python can be found in the exUserFolder module for Zope (documentation).

    Feedback

    We'd really appreciate feedback on this proposal. Please follow up at this openacs.org forums thread.

    References

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    1Updated work-in-progress for consortium-sponsored ext-auth work at Collaboraid.20 Aug 2003Joel Aufrecht
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/docbook-primer.html0000644000175000017500000020652111501005400023611 0ustar frankiefrankie OpenACS Documentation Guide

    OpenACS Documentation Guide

    By Claus Rasmussen, with additions by Roberto Mello, Vinod Kurup, and the OpenACS Community

    Overview of OpenACS Documentation

    OpenACSâ„¢ is a powerful system with incredible possibilities and applications, but this power comes with some complexity and a steep learning curve that is only attenuated by good documentation. Our goal is to write superb documentation, so that users, developers and administrators of OpenACS installations can enjoy the system.

    The history of OpenACS documentation: ..began by building on a good documentation base from ArsDigita's ACS in the late 1990's. Some sections of the documentation, however, lacked details and examples; others simply did not exist. The OpenACS community began meeting the challenge by identifying needs and writing documentation on an as needed basis.

    By having documentation dependent on volunteers and code developers, documentation updates lagged behind the evolving system software. As significant development changes were made to the system, existing documentation became dated, and its value significantly reduced. The valiant efforts that were made to keep the documentation current proved too difficult as changes to the system sometimes had far-reaching affects to pages throughout the documentation. System integration and optimization quickly rendered documentation obsolete for developers. The code became the substitute and source for documentation.

    With thousands of lines of code and few developers tracking changes, features and advances to the OpenACS system went unnoticed or were not well understood except by the code authors. Work was duplicated as a consequence of developers not realizing the significant work completed by others. New developers had to learn the system through experience with working with it and discussion in the forums. Informal sharing of experiential and tacit knowledge has become the OpenACS community's main method of sharing knowledge.

    This document attempts to shape ongoing documentation efforts by using principles of continual improvement to re-engineer documentation production.

    Managing OpenACS Documentation

    Documentation production shares many of the challenges of software development, such as managing contributions, revisions and the (editorial) release cycle. This is yet another experiment in improving documentation --this time by using principles of continual improvement to focus the on-going efforts. These processes are outlined as project management phases:

    1. Requirements phase is about setting goals and specifications, and includes exploration of scenarios, use cases etc. As an example, see the OpenACS Documentation Requirements Template which focuses on systems requirements for developers.

    2. Strategy phase is about creating an approach to doing work. It sets behavioral guidelines and boundaries that help keep perspective on how efforts are directed. OpenACS developers discuss strategy when coordinating efforts such as code revisioning and new features.

    3. Planning phase is about explicitly stating the way to implement the strategy as a set of methods. OpenACS system design requires planning. For example, see OpenACS documentation template planning relating to package design.

    4. Implementation phase is about performing the work according to the plan, where decisions on how to handle unforseen circumstances are guided by the strategy and requirements.

    5. Verification phase measures how well the plan was implemented. Success is measured by A) verifying if the project has met the established goals, and B) reviewing for ongoing problem areas etc. OpenACS follows verification through different means on different projects, but in all cases, the OpenACS community verifies the project as a success through feedback including bug reports, user and administrator comments, and code changes.

    OpenACS forum discussions on documentation requirements and strategies are summarized in the following sections. Production phases are mainly organized and fulfilled by a designated documentation maintainer. Hopefully the following sections will help spur greater direct participation by the OpenACS community.

    OpenACS General Documentation Requirements

    By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003.

    OpenACS documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here.

    • clarity in presentation. Life with qmail is a recommended example of "rated high" online documentation.

    • Avoid requirements that significantly increase the labor required to maintain documentation.

    • Use best practices learned from the print world, web, and other media, about use of gamma, space, writing style etc.

      • Consistency in publishing -Establishing and adhering to publishing standards

      • Use standardized language -Use international English (without slang or colloquial terms) for ESL (English as a second language) readers (and making translation easier for those interested in translating the documentation for internationalization efforts).

      • All jargon used in documentation needs to be defined. Use standardized terms when available, avoiding implicit understanding of specific OpenACS terms.

      • Document titles (for example on html pages) should include whole document title (as in book title): (chapter title) : (section), so that bookmarks etc. indicate location in a manner similar to pages in books (in print publishing world).

      • Organize document according to the needs of the reader (which may be different than the wishes of the writers).

      • Do not make informal exclamations about difficulty/ease for users to complete tasks or understand... for example, "Simply...". Readers come from many different backgrounds --remember that the greater audience is likely as varied as the readers on the internet--- If important, state pre-conditions or knowledge requirements etc. if different than the rest of the context of the document. For example, "requires basic competency with a text-based editor such as vi or emacs via telnet"

    • Show where to find current information instead of writing about current info that becomes obsolete. If the information is not found elsewhere, then create one place for it, where others can refer to it. This structure of information will significantly reduce obsolescence in writing and labor burden to maintain up-to-date documentation. In other words, state facts in appropriately focused, designated areas only, then refer to them by reference (with links).

      Note: Sometimes facts should be stated multiple ways, to accommodate different reading style preferences. The should still be in 1 area, using a common layout of perhaps summary, introduction and discussion requiring increasing expertise, complexity or specificity.

    • Consistency in link descriptions -When link urls refer to whole documents, make the link (anchor wrapped title) that points to a document with the same title and/or heading of the document.

    • Consider OpenACS documentation as a set of books (an encyclopedic set organized like an atlas) that contains volumes (books). Each book contains chapters and sections much like how DocBook examples are shown, where each chapter is a web page. This designation could help create an OpenACs book in print, and help new readers visualize how the documentation is organized.

    • The use licenses between OpenACS and Arsdigita's ACS are not compatible, thereby creating strict limits on how much OpenACS developers should have access to Arsdigita code and resources. The OpenACS documentation has a new legal requirement: to eliminate any dependency on learning about the system from Arsdigita ACS examples to minimize any inference of license noncompliance, while recognizing the important work accomplished by Philip Greenspun, Arsdigita, and the early ACS adopters.

    • Use a consistent general outline for each book.

      • Introduction (includes purpose/goal), Glossary of terms, Credits, License, Copyright, Revision History

      • Table of Contents (TOC)s for each book: the end-users, content and site administrators, marketing, developer tutorial, and developers.

      • Priorities of order and content vary based on each of the different readers mentioned. The developers guide should be organized to be most useful to the priorities of developers, while being consistent with the general documentation requirements including publishing strategy, style etc.

      • Use generic DocBook syntax to maximize reader familiarity with the documents.

                        <book><title><part label="Part 1"><etc...>
                      

    OpenACS Documentation Requirements for End-users

    By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003.

    OpenACS end-user documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here.

    • End-users should not have to read docs to use the system.

    • Include how to get help. How and where to find answers, contact others, what to do if one gets an AOLserver or other error when using the system. Include types of available support (open-source, private commercial etc.) including references.

    • Explain/foster understanding of the overall structure of the system. This would be an overview of the system components, how it works, and how to find out more or dig deeper... To promote the system by presenting the history of the system, and writing about some tacit knowledge re: OpenACS.org and the opensource culture.

    • Introduce and inspire readers about the uses, benefits, and the possibilities this system brings (think customer solution, customer cost, convenience, value). A comprehensive community communications system; How this system is valuable to users; Reasons others use OpenACS (with quotes in their own words) "...the most important thing that the ACS does is manage users, i.e. provide a way to group, view and manipulate members of the web community. -- Talli Somekh, September 19, 2001" using it to communicate, cooperate, collaborate... OpenACS offers directed content functionality with the OpenACS templating system. ... OpenACS is more than a data collection and presentation tool. OpenACS has management facilities that are absent in other portals. ...The beauty of OpenACS is the simplicity (and scalability) of the platform on which it is built and the library of tried and tested community building tools that are waiting to be added. It seems that most portals just add another layer of complexity to the cake. See Slides on OACS features...a set of slides on OACS features that can be used for beginners who want to know OACS is about and what they can do with it. Screen captures that highlight features. Example shows BBoard, calendar, news, file storage, wimpy point, ticket tracking. An OpenACS tour; an abbreviated, interactive set of demo pages.

    • From a marketing perspective,

      • differentiate "product" by highlighting features, performance quality, conformance to standards, durability (handling of technological obsolescence), reliability, repairability, style of use, design (strategy in design, specifications, integrated, well-matched systems etc).

      • differentiate "service" by highlighting software availability (licensing and completeness from mature to early adopters or development versions), community incident support, project collaborative opportunities, and contractor support availability

      • differentiate price (economic considerations of opensource and features)

      • Discussion and details should rely on meeting criteria of design, completeness of implementation, and related system strengths and weaknesses. Marketing should not rely on comparing to other technologies. Competitive analysis involves mapping out strengths, weaknesses, opportunities and threats when compared to other systems for a specific purpose, and thus is inappropriate (and becomes stale quickly) for general documentation.

      • When identifying subsystems, such as tcl, include links to their marketing material if available.

      • create an example/template comparison table that shows versions of OpenACS and other systems (commonly competing against OpenACS) versus a summary feature list and how well each meets the feature criteria. Each system should be marked with a date to indicate time information was gathered, since information is likely volatile.

    • To build awareness about OpenACS, consider product differentiation: form, features, performance quality, conformance quality (to standards and requirements), durability, reliability, repairability, style, design: the deliberate planning of these product attributes.

    • Include jargon definitions, glossary, FAQs, site map/index, including where to find Instructions for using the packages. FAQ should refer like answers to the same place for consistency, brevity and maintainability.

    • Explain/tutorial on how the UI works (links do more than go to places, they are active), Page flow, descriptions of form elements; browser/interface strengths and limitations (cookies, other)

    • Discuss criteria used to decide which features are important, and the quality of the implementation from a users perspective. Each project implementation places a different emphasis on the various criteria, which is why providing a framework to help decide is probably more useful than an actual comparison.

    Package documentation requirements have additional requirements.

    • A list of all packages, their names, their purposes, what they can and cannot do (strengths, limitations), what differentiates them from similar packages, minimal description, current version, implementation status, author/maintainers, link(s) to more info. Current version available at the repository.

    • Include dependencies/requirements, known conflicts, and comments from the real world edited into a longer description to quickly learn if a package is appropriate for specific projects.

    • Create a long bulleted list of features. Feature list should go deeper than high-level feature lists and look at the quality of the implementations (from the user's perspective, not the programmer's). Example issues an end-user may have questions about: Ticket Tracker and Ticket Tracker Lite, why would I want one of them vs the other? And, before I specify to download and install it, what credit card gateways are supported by the current e-commerce module? There are some packages where the name is clear enough, but what are the limitations of the standard package?

    • End-user docs should not be duplicative. The package description information and almost everything about a package for administrators and developers is already described in the package itself through two basic development document templates: a Requirements Template and Detailed Design Document.

    OpenACS Documentation Requirements for Site and Administrators

    By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003.

    OpenACS administrators' documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here.

    • For each requirement below, include links to developer tutorials and other documentation for more detail.

    • Describe a structural overview of a working system and how the components work together. "The Layered Cake view" a general network view of system; a table showing system levels versus roles to help with understanding how the subsystems are interconnected.

    • Provide a comprehensive description of typical administrative processes for operating an OpenACS system responsibly, including reading logs and command line views that describe status of various active processes.

    • Create a list of administrative tools that are useful to administrating OpenACS, including developer support, schema-browser and api browser. Link to AOLserver's config file documentation.

    • Resources on high level subjects such as web services, security guidelines

    • Describe typical skill sets (and perhaps mapped to standardized job titles) for administrating an OpenACS system (human-resources style). For a subsite admin/moderator attributes might include trustworthy, sociable, familiarity with the applications and subsystems, work/group communication skills et cetera

    • Describe how to set up typical site moderation and administration including parameters, permissions, "Hello World" page

    • Show directory structure of a typical package, explanation of the various file types in a package (tcl,adp,xql) and how those relate to the previously described subsystems, when they get refreshed etc.

    • Ways to build a "Hello World" page

    • Show examples of how the OpenACS templating system is used, including portal sections of pages. For example, create a customised auto-refreshing startpage using lars-blogger, a photo gallery, and latest posts from a forum. This should rely heavily on documentation existing elsewhere to keep current. This would essentially be a heavily annotated list of links.

    • Show ways of modifying the look and feel across pages of an OpenACS website. Refer to the skins package tutorial.

    • Describe a methodology for diagnosing problems, finding error statements and interpreting them --for OpenACS and the underlying processes.

    • FAQs: Administration tasks commonly discussed on boards: admin page flow, how to change the looks of a subsite with a new master.adp, options on "user pages" , a quick introduction to the functions and processes. info about the user variables, file locations

    OpenACS Installation Documentation Requirements

    By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003.

    OpenACS installation documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here.

    • state installation prerequisites. For example: "You should read through the installation process to familiarize yourself with the installation process, before beginning an installation."

    • list critical decisions (perhaps as questions) that need to be made before starting: which OS, which DB, which aolserver version, system name, dependencies et cetera. Maybe summarize options as tables or decision-trees. For example, "As you proceed throughout the installation, you will be acting on decisions that have an impact on how the remaining part of the system is installed. Here is a list of questions you should answer before beginning."

    • list pre-installation assumptions

    • Show chronological overview of the process of installing a system to full working status: Install operating system with supporting software, configure with preparations for OpenACS, RDBMS(s) install and configure, Webserver install and configure, OpenACS install and configure, post-install work

    OpenACS Developer Tutorial Documentation Requirements

    By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003.

    OpenACS developer tutorial documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here.

    • list learning prerequisites to customize, fix, and improve OACS modules, and create new ones. You are expected to have read and understand the information [minimum requirements similar to adept at Using OpenACS Administrating Guide] before reading this guide.

    • Refer to development documentation instead of duplicating here

    • List suggestions for installing and setting up a development environment; these can be annotated links to the installation documentation

    • Provide working examples that highlight the various subsystems, tcl environment, OpenACS protocols, aolserver template and ns_* commands, OpenACS templating, sql queries, db triggers, scheduling protocols, how to use the page contract, how to get the accessing user_id etc

    • Show how to construct basic SQL queries using the db API,

    • The life of an http request to a dynamic, templated page

    • General rules to follow for stability, scalability

    • Show the step by step customizing of an existing package that meets current recommended coding styles of OpenACS package development, by referring to developer resources.

    • Use the ArsDigita problem sets and "what Lars produced for ACS Java" as inspiration for a PostgreSQL equivalent tutorial about developing a new OpenACS package including discussion of the significance of the package documentation templates

    • Include a summary of important links used by developers

    • Note any deprecated tools and methods by linking to prior versions instead of describing them in current docs

    OpenACS Developer Documentation Requirements

    By the OpenACS Community. This section is a collection of documentation requirements that have been expressed in the OpenACS forums to 4th July 2003.

    OpenACS developer documentation should meet the following requirements. No significance has been given to the order presented, topic breadth or depth here.

    • list documentation assumptions, such as familiarity with modifying OpenACS packages. All kernel docs are here etc.

    • This documentation should be written for ongoing use by developers, not as a tutorial.

    • List of practical development and diagnostics tools and methodologies.

    • List of OpenACS development resources, api-doc, schema-browser, developer-support package etc.

    • Identify each OpenACS subsystem, explain why it is used (instead of other choices). In the case of subsystems that are developed outside of OpenACS such as tcl, include external references to development and reference areas.

    • Show current engineering standards and indicate where changes to the standards are in the works.

    • Sections should be dedicated to DotLRN standards as well, if they are not available elsewhere.

    • Add overview diagrams showing the core parts of the datamodel including an updated summary of Greenspun's Chapter 4: Data Models and the Object System

    • package design guidelines and development process templates including planning, core functions, testing, usability, and creating case studies

    • Standard package conventions, where to see "model" code, and guidelines (or where to find them) for:

      • programming tcl/sql

      • using the acs-api

      • ad_form

      • coding permissions

      • OpenACS objects

      • scheduled protocols

      • call backs

      • directory structure

      • user interface

      • widgets

      • package_name and type_extension_table

      • adding optional services, including search, general comments, attachments, notifications, workflow, CR and the new CR Tcl API

    • Document kernel coding requirements, strategy and guidelines to help code changers make decisions that meet kernel designers' criteria

    OpenACS Documentation Strategy

    OpenACS documentation development is subject to the constraints of the software project development and release methods and cycles (Using CVS with OpenACS). Essentially, all phases of work may be active to accommodate the asynchronous nature of multiple subprojects evolving by the efforts of a global base of participants with culturally diverse time references and scheduling idiosyncrasies.

    The documentation strategy is to use project methods to involve others by collaborating or obtaining guidance or feedback (peer review) to distribute the workload and increase the overall value of output for the OpenACS project.

    OpenACS Documentation Strategy: Why DocBook?

    OpenACS documentation is taking a dual approach to publishing. Documentation that is subject to rapid change and participation by the OpenACS community is managed through the OpenACS xowiki Documentation Project Formal documents that tend to remain static and require more expressive publishing tools will be marked up to conform to the DocBook XML DTD. The remaining discussion is about publishing using Docbook.

    is a publishing standard based on XML with similar goals to the OpenACS Documentation project. Some specific reasons why we are using DocBook:

    • It is open-source.

    • A growing community surrounds DocBook (has mailing lists)

    • A number of free and commercial tools are available for editing and publishing DocBook documents.

    • It enables us to publish in a variety of formats.

    • XML separates content from presentation: It relieves each contributor of the burden of presentation, freeing each writer to focus on content and sharing knowledge.

    • It is well tested technology. It has been in development since the early 1990's).

    Reasons why we are using Docbook XML instead of Docbook SGML:

    • Consistency and history. We started with a collection of DocBook XML files that ArsDigita wrote. Trying to re-write them to conform to the SGML DTD would be unnecessary work.

    • XML does not require extra effort. Writing in XML is almost identical to SGML, with a couple extra rules. More details in the LDP Author Guide.

    • The tool chain has matured. xsltproc and other XML based tools have improved to the point where they are about as good as the SGML tools. Both can output html and pdf formats.

    Albeit, the road to using DocBook has had some trials. In 2002, Docbook still was not fully capable of representing online books as practiced by book publishers and expected from readers with regards to usability on the web. That meant DocBook did not entirely meet OpenACS publishing requirements at that time.

    In 2004, Docbook released version 4.4, which complies with all the OpenACS publishing requirements. Producing a web friendly book hierarchy arguably remains DocBooks' weakest point. For example, a dynamically built document should be able to extract details of a specific reference from a bibliographic (table) and present a footnote at the point where referenced. DocBook 4.4 allows for this with bibliocoverage, bibliorelation, and bibliosource. DocBook: The Definitive Guide is a good start for learning how to represent paper-based books online.

    The following DocBook primer walks you through the basics, and should cover the needs for 95 percent of the documentation we produce. You are welcome to explore DocBook's list of elements and use more exotic features in your documents. The list is made up of SGML-elements but basically the same elements are valid in the XML DTD as long as you remember to:

    • Always close your tags with corresponding end-tags and to not use other tag minimization

    • Write all elements and attributes in lowercase

    • Quote all attributes

    Tools

    You are going to need the following to work with the OpenACS Docbook XML documentation:

    • Docbook XML DTD - The document type definition for XML. You can find an RPM or DEB package or you can download a zip file from the site linked from here.

    • XSL Stylesheets (docbook-xsl) - The stylesheets to convert to HTML. We have been using a stylesheet based upon NWalsh's chunk.xsl.

    • xsltproc - The processor that will take an XML document and, given a xsl stylesheet, convert it to HTML. It needs libxml2 and libxslt (available in RPM and DEB formats or from xmlsoft.org.

    • Some editing tool. A popular one is Emacs with the psgml and nXML modes. The LDP Author Guide and DocBook Wiki list some alternates.

    Writing New Docs

    After you have the tools mentioned above, you need to define a title for your document. Then start thinking about the possible sections and subsections you will have in your document. Make sure you coordinate with the OpenACS Gatekeepers to make sure you are not writing something that someone else is already writing. Also, if you desire to use the OpenACS CVS repository, please e-mail the gatekeeper in charge of documentation.

    You can look at some templates for documents (in Docbook XML) in the sources for acs-core-docs, especially the Detailed Design Documentation Template and the System/Application Requirements Template.

    Document Structure

    The documentation for each package will make up a little "book" that is structured like this - examples are emphasized:

        book                        : Docs for one package - templating
         |
         +--chapter                 : One section - for developers
             |
    ---------+------------------------------------------------------
             |
             +--sect1               : Single document - requirements
                 |
                 +--sect2           : Sections - functional requirements
                     |
                     +--sect3       : Subsections - Programmer's API
                         |
                        ...         : ...
        

    The actual content is split up into documents that start at a sect1-level. These are then tied together in a top-level document that contains all the information above the line. This will be explained in more detail in a later document, and we will provide a set of templates for documenting an entire package.

    For now you can take a look at the sources of these DocBook documents to get an idea of how they are tied together.

    Headlines, Sections

    Given that your job starts at the sect1-level, all your documents should open with a <sect1>-tag and end with the corresponding </sect1>.

    You need to feed every <sect1> two attributes. The first attribute, id, is standard and can be used with all elements. It comes in very handy when interlinking between documents (more about this when talking about links in Links). The value of id has to be unique throughout the book you're making since the id's in your sect1's will turn into filenames when the book is parsed into HTML.

    The other attribute is xreflabel. The value of this is the text that will appear as the link when referring to this sect1.

    Right after the opening tag you put the title of the document - this is usually the same as xreflabel-attribute. E.g. the top level of the document you're reading right now looks like this:

    <sect1 id="docbook-primer" xreflabel="DocBook Primer">
      <title>DocBook Primer</title>
    
    ...
    
    </sect1>
    

    Inside this container your document will be split up into <sect2>'s, each with the same requirements - id and xreflabel attributes, and a <title>-tag inside. Actually, the xreflabel is never required in sections, but it makes linking to that section a lot easier.

    When it comes to naming your sect2's and below, prefix them with some abbreviation of the id in the sect1 such as requirements-overview.

    Code

    For displaying a snippet of code, a filename or anything else you just want to appear as a part of a sentence, we use <computeroutput> and <code> tags. These replace the HTML-tag <code> tag, depending on whether the tag is describing computer output or computer code.

    For bigger chunks of code such as SQL-blocks, the tag <programlisting> is used. Just wrap your code block in it; mono-spacing, indents and all that stuff is taken care of automatically.

    For expressing user interaction via a terminal window, we wrap the <screen> tag around text that has been wrapped by combinations of <computeroutput> and <userinput>

    Links

    Linking falls into two different categories: inside the book you're making and outside:

    1. Inside linking, cross-referencing other parts of your book

    By having unique id's you can cross-reference any part of your book with a simple tag, regardless of where that part is.

    Check out how I link to a subsection of the Developer's Guide:

    Put this in your XML:

    - Find information about creating a package in
    <xref linkend="packages-making-a-package"></xref>.
    

    And the output is:

    - Find information about creating a package in 
    Making a Package.
    

    Note that even though this is an empty tag, you have to either:

    1. Provide the end-tag, </xref>, or

    2. Put a slash before the ending-bracket: <xref linkend="blahblah"/>

    If the section you link to hasn't a specified xreflabel-attribute, the link is going to look like this:

    Put this in your XML:

    -Find information about what a package looks like in 
    <xref linkend="packages-looks"></xref>.
    

    And the output is:

    - Find information about what a package looks like in 
    What a Package Looks Like.
    

    Note that since I haven't provided an xreflabel for the subsection, packages-looks, the parser will try its best to explain where the link takes you.

    2. Linking outside the documentation

    If you're hyper-linking out of the documentation, it works almost the same way as HTML - the tag is just a little different (<ulink>):

    <ulink url="http://www.oracle.com/">Oracle Corporation</ulink>

    ....will create a hyper-link to Oracle in the HTML-version of the documentation.

    NOTE: Do NOT use ampersands in your hyperlinks. These are reserved for referencing entities. To create an ampersand, use the entity &amp;

    Graphics

    Note: The graphics guidelines are not written in stone. Use another valid approach if it works better for you.

    To insert a graphic we use the elements <mediaobject>, <imageobject>, <imagedata>, and <textobject>. Two versions of all graphics are required. One for the Web (usually a JPEG or GIF), and a brief text description. The description becomes the ALT text. You can also supply a version for print (EPS).

    <mediaobject>
      <imageobject>
        <imagedata fileref="images/rp-flow.gif" format="GIF" align="center"/>
      </imageobject>
      <imageobject>
        <imagedata fileref="images/rp-flow.eps" format="EPS" align="center"/>
      </imageobject>
      <textobject>
        <phrase>This is an image of the flow in the Request Processor</phrase>
      </textobject>
    </mediaobject>
    

    Put your graphics in a separate directory ("images") and link to them only with relative paths.

    Lists

    Here's how you make the DocBook equivalent of the three usual HTML-lists:

    1. How to make an <ul>

    Making an unordered list is pretty much like doing the same thing in HTML - if you close your <li>, that is. The only differences are that each list item has to be wrapped in something more, such as <para>, and that the tags are called <itemizedlist> and <listitem>:

    <itemizedlist>
    
      <listitem><para>Stuff goes here</para></listitem>
      <listitem><para>More stuff goes here</para></listitem>
    
    </itemizedlist>
    
    2. How to make an <ol>

    The ordered list is like the preceding, except that you use <orderedlist> instead:

    <orderedlist>
    
      <listitem><para>Stuff goes here</para></listitem>
      <listitem><para>More stuff goes here</para></listitem>
    
    </orderedlist>
    
    3. How to make a <dl>

    This kind of list is called a variablelist and these are the tags you'll need to make it happen: <variablelist>, <varlistentry>, <term> and <listitem>:

    <variablelist>
    
      <varlistentry>
        <term>Heading (<dt>) goes here</term>
        <listitem><para>And stuff (<dd>)goes here</para></listitem>
      </varlistentry>
    
      <varlistentry>
        <term>Another heading goes here</term>
        <listitem><para>And more stuff goes here</para></listitem>
      </varlistentry>
    
    </variablelist>
    

    Tables

    DocBook supports several types of tables, but in most cases, the <informaltable> is enough:

    <informaltable frame="all">
      <tgroup cols="3">
        <tbody>
    
          <row>
            <entry>a1</entry>
            <entry>b1</entry>
            <entry>c1</entry>
          </row>
    
          <row>
            <entry>a2</entry>
            <entry>b2</entry>
            <entry>c2</entry>
          </row>
    
          <row>
            <entry>a3</entry>
            <entry>b3</entry>
            <entry>c3</entry>
          </row>
    
        </tbody>
      </tgroup>
    </informaltable>
    

    With our current XSL-style-sheet, the output of the markup above will be a simple HTML-table:

    a1b1c1
    a2b2c2
    a3b3c3

    If you want cells to span more than one row or column, it gets a bit more complicated - check out <table> for an example.

    Emphasis

    Our documentation uses two flavors of emphasis - italics and bold type. DocBook uses one - <emphasis>.

    The <emphasis> tag defaults to italics when parsed. If you're looking for emphasizing with bold type, use <emphasis role="strong">.

    Indexing Your DocBook Documents

    Words that are marked as index-words are referenced in an index in the final, parsed document.

    Use <indexterm>, <primary> and <secondary> for this. See these links for an explanation.

    Converting to HTML

    Note

    This section is quoted almost verbatim from the LDP Author Guide.

    Once you have the Docbook Tools installed, you can convert your xml documents to HTML or other formats.

    With the DocBook XSL stylesheets, generation of multiple files is controlled by the stylesheet. If you want to generate a single file, you call one stylesheet. If you want to generate multiple files, you call a different stylesheet.

    To generate a single HTML file from your DocBook XML file, use the command:

    bash$ xsltproc -o outputfilename.xml /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/html/html.xsl filename.xml
    

    Note

    This example uses Daniel Veillard's xsltproc command available as part of libxslt from http://www.xmlsoft.org/XSLT/. If you are using other XML processors such as Xalan or Saxon, you will need to change the command line appropriately.

    To generate a set of linked HTML pages, with a separate page for each <chapter>, <sect1> or <appendix> tag, use the following command:

    bash$ xsltproc /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/html/chunk.xsl filename.xml
    

    You could also look at the acs-core-docs Makefile for examples of how these documents are generated.

    Further Reading

    • Using Xinclude

    • The LDP Author Guide has a lot of good information, a table of docbook elements and their "look" in HTML and lots of good links for tools.

    • James Clark wrote nXML Mode, an alternative to PSGML Mode. nXML Mode can validate a file as it is edited.

    • David Lutterkort wrote an intro to the PSGML Mode in Emacs

    • James Clark's free Java parser XP. Note that this does not validate XML, only parses it.

    • DocBook Tool for Linux: Converts docbook documents to a number of formats. NOTE: I only got these to work with Docbook SGML, NOT with Docbook XML. If you are able to make it work with our XML, please let us know.

    • AptConvert from PIXware is a Java editor that will produce DocBook documents and let you transform them into HTML and PDF for a local preview before you submit.

    • In the process of transforming your HTML into XML, HTML tidy can be a handy tool to make your HTML "regexp'able". Brandoch Calef has made a Perl script with directions (now via archive.org) that gets you most of the way.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/subsites-requirements.html0000644000175000017500000002476011501005400025262 0ustar frankiefrankie Subsites Requirements

    Subsites Requirements

    By Rafael H. Schloming and Dennis Gregorovic

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    The following is a requirements document for OpenACS 4 Subsites, part of the OpenACS 4 Kernel. The Subsites system allows one OpenACS server instance to serve multiple user communities, by enabling the suite of available OpenACS applications to be customized for defined user communities.

    Vision Statement

    Many online communities are also collections of discrete subcommunities, reflecting real-world relationships. For example, a corporate intranet/extranet website serves both units within the company (e.g., offices, departments, teams, projects) and external parties (e.g., customers, partners, vendors). Subsites enable a single OpenACS instance to provide each subcommunity with its own "virtual website," by assembling OpenACS packages that together deliver a feature set tailored to the needs of the subcommunity.

    System Overview

    The OpenACS subsite system allows a single OpenACS installation to serve multiple communities. At an implementation level this is primarily accomplished by having an application "scope" its content to a particular package instance. The request processor then figures out which package_id a particular URL references and then provides this information through the ad_conn api ([ad_conn package_id], [ad_conn package_url]).

    The other piece of the subsite system is a subsite package that provides subsite admins a "control panel" for administering their subsite. This is the same package used to provide all the community core functionality available at the "main" site which is in fact simply another subsite.

    Use-cases and User-scenarios

    The Subsites functionality is intended for use by two different classes of users:

    1. Package programmers (referred to as 'the programmer') must develop subcommunity-aware applications.

    2. Site administrators (referred to as 'the administrator') use subsites to provide tailored "virtual websites" to different subcommunities.

    Joe Programmer is working on the forum package and wants to make it subsite-aware. Using [ad_conn package_id], Joe adds code that only displays forum messages associated with the current package instance. Joe is happy to realize that parameter::get is already smart enough to return configuration parameters for the current package instance, and so he has to do no extra work to tailor configuration parameters to the current subsite.

    Jane Admin maintains www.company.com. She learns of Joe's work and would like to set up individual forums for the Boston and Austin offices of her company. The first thing she does is use the APM to install the new forum package.

    Next, Jane uses the Subsite UI to create subsites for the Boston and Austin offices. Then Jane uses the Subsite UI to create forums for each office.

    Now, the Boston office employees have their own forum at http://www.company.com/offices/boston/forum, and similarly for the Austin office. At this point, the Boston and Austin office admins can customize the configurations for each of their forums, or they can just use the defaults.

    Related Links

    Requirements: Programmer's API

    A subsite API is required for programmers to ensure their packages are subsite-aware. The following functions should be sufficient for this:

    10.10.0 Package creation

    The system must provide an API call to create a package, and it must be possible for the context (to which the package belongs) to be specified.

    10.20.0 Package deletion

    The system must provide an API call to delete a package and all related objects in the subsite's context.

    10.30.0 Object's package information

    Given an object ID, the system must provide an API call to determine the package (ID) to which the object belongs.

    10.40.0 URL from package

    Given a package (ID), the system must provide an API call to return the canonical URL for that package.

    10.50.0 Main subsite's package_id

    The system must provide an API call to return a package ID corresponding to the main subsite's package ID (the degenerate subsite).

    Requirements: The User Interface

    The Programmer's User Interface

    There is no programmer's UI, other than the API described above.

    The Administrator's User Interface

    The UI for administrators is a set of HTML pages that are used to drive the underlying API for package instance management (i.e. adding, removing, or altering packages). It is restricted to administrators of the current subsite such that administrators can only manage their own subsites. Of course, Site-Wide Administrators can manage all subsites.

    • 20.10.0 Package creation

      20.10.1 The administrator should be able to create a package and make it available at a URL underneath the subsite.

    • 20.20.0 Package deactivation

      20.20.1 The administrator should be able to deactivate any package, causing it to be inaccessible to users.

      20.20.5 Deactivating a package makes the package no longer accessible, but it does not remove data created within the context of that package.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation08/18/2000Dennis Gregorovic
    0.2Edited, reviewed08/29/2000Kai Wu
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/acs-admin.html0000644000175000017500000002076711501005377022554 0ustar frankiefrankie Part II. Administrator's Guide

    Part II. Administrator's Guide

    Table of Contents

    2. Installation Overview
    Basic Steps
    Prerequisite Software
    3. Complete Installation
    Install a Unix-like system and supporting software
    Install Oracle 8.1.7
    Install PostgreSQL
    Install AOLserver 4
    Install OpenACS 5.6.0
    OpenACS Installation Guide for Windows2000
    OpenACS Installation Guide for Mac OS X
    4. Configuring a new OpenACS Site
    Installing OpenACS packages
    Mounting OpenACS packages
    Configuring an OpenACS package
    Setting Permissions on an OpenACS package
    How Do I?
    5. Upgrading
    Overview
    Upgrading 4.5 or higher to 4.6.3
    Upgrading OpenACS 4.6.3 to 5.0
    Upgrading an OpenACS 5.0.0 or greater installation
    Upgrading the OpenACS files
    Upgrading Platform components
    6. Production Environments
    Starting and Stopping an OpenACS instance.
    AOLserver keepalive with inittab
    Running multiple services on one machine
    High Availability/High Performance Configurations
    Staged Deployment for Production Networks
    Installing SSL Support for an OpenACS service
    Set up Log Analysis Reports
    External uptime validation
    Diagnosing Performance Problems
    7. Database Management
    Running a PostgreSQL database on another server
    Deleting a tablespace
    Vacuum Postgres nightly
    A. Install Red Hat 8/9
    B. Install additional supporting software
    Unpack the OpenACS tarball
    Initialize CVS (OPTIONAL)
    Add PSGML commands to emacs init file (OPTIONAL)
    Install Daemontools (OPTIONAL)
    Install qmail (OPTIONAL)
    Install Analog web file analyzer
    Install nspam
    Install Full Text Search using Tsearch2
    Install Full Text Search using OpenFTS (deprecated see tsearch2)
    Install nsopenssl
    Install tclwebtest.
    Install PHP for use in AOLserver
    Install Squirrelmail for use as a webmail system for OpenACS
    Install PAM Radius for use as external authentication
    Install LDAP for use as external authentication
    Install AOLserver 3.3oacs1
    C. Credits
    Where did this document come from?
    Linux Install Guides
    Security Information
    Resources
    Section missing
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/eng-standards-filenaming.html0000644000175000017500000004330711501005400025537 0ustar frankiefrankie ACS File Naming and Formatting Standards

    ACS File Naming and Formatting Standards

    By Michael Yoon and Aurelius Prochazka

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    To ensure consistency (and its collateral benefit, maintainability), we define and adhere to standards in the following areas:

    File Nomenclature

    Usually we organize our files so that they mainly serve one of the following three purposes:

    • displaying objects and their properties

    • manipulating or acting on objects in some way (by creating, editing, linking, etc)

    • housing procedures, packages, data models and other prerequisite code Essentially, we want our files named in a fashion that reflects their purpose.

    Under the page root (and the template root if using the Style package):

    • For naming files that enable a specific action on an object, use this format:

      object-verb.extension

      For example, the page to erase a user's portrait from the database is /admin/users/portrait-erase.tcl.

    • However, modules typically deal with only one primary type of object - e.g., the Bookmarks module deals mainly with bookmarks - and so action-type files in modules don't need to be specified by the object they act on. Example: the user pages for the Bookmarks module live in the /bookmarks/ directory, and so there is no need to name the bookmark editing page with a redundant url: /bookmarks/bookmark-edit.tcl. Instead, we omit the object type, and use this convention:

      verb.extension

      Thus, the page to edit a bookmark is /bookmarks/edit.tcl.

    • For naming files that display the properties of a primary object - such as the bookmark object within the bookmark module - use this convention:

      one.extension

      For example, the page to view one bookmark is /bookmarks/one.tcl. Note that no verb is necessary for display-type files.

    • Otherwise, if the object to be displayed is not the primary feature of a module, simply omit the verb and use the object name:

      object.extension

      For example, the page to view the properties of an ecommerce product is /ecommerce/product.tcl.

    • For naming files in a page flow, use the convention:

      • foobar.extension (Step 1)

      • foobar-2.extension (Step 2)

      • ...

      • foobar-N.extension (Step N)

      where foobar is determined by the above rules.

      Typically, we use a three-step page flow when taking user information:

      1. Present a form to the user

      2. Present a confirmation page to the user

      3. Perform the database transaction, then redirect

    • Put data model files in /www/doc/sql, and name them for the modules towards which they are used:

      module.sql

    In the Tcl library directory:

    • For files that contain module-specific procedures, use the convention:

      module-procs.tcl

    • For files that contain procedures that are part of the core ACS, use the convention:

      ad-description-procs.tcl

    URLs

    File names also appear within pages, as linked URLs and form targets. When they do, always use abstract URLs (e.g., user-delete instead of user-delete.tcl), because they enhance maintainability.

    Similarly, when linking to the index page of a directory, do not explicitly name the index file (index.tcl, index.adp, index.html, etc.). Instead, use just the directory name, for both relative links (subdir/) and absolute links (/top-level-dir/). If linking to the directory in which the page is located, use the empty string (""), which browsers will resolve correctly.

    File Headers and Page Input

    Include the appropriate standard header in all scripts. The first line should be a comment specifying the file path relative to the ACS root directory. e.g.

    # /www/index.tcl

    or

    # /tcl/module-defs.tcl

    For static content files (html or adp), include a CVS identification tag as a comment at the top of the file, e.g.

    <!-- file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp -->
    

    In addition, all static HTML files, documentation and other pages should have a visible CVS ID stamp, at least during development. These can be removed at release times. This should take the form of a line like this:

    <p>
    Last Modified: file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp
    </p>
    

    This can be at the top or bottom of the file.

    Using ad_page_contract

    For non-library Tcl files (those not in the private Tcl directory), use ad_page_contract after the file path comment (this supersedes set_the_usual_form_variables and ad_return_complaint). Here is an example of using ad_page_contract, which serves both documentation and page input validation purposes:

    # www/register/user-login-2.tcl
    
    ad_page_contract {
        Verify the user's password and issue the cookie.
        
        @param user_id The user's id in users table.
        @param password_from_from The password the user entered.
        @param return_url What url to return to after successful login.
        @param persistent_cookie_p Specifies whether a cookie should be set to keep the user logged in forever.
        @author John Doe (jdoe@example.com)
        @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp
    } {
        user_id:integer,notnull
        password_from_form:notnull
        {return_url {[ad_pvt_home]}}
        {persistent_cookie_p f}
    }
    

    Salient features of ad_page_contract:

    • A mandatory documentation string is the first argument. This has the standard form with javadoc-style @author, @cvs-id, etc, and should contain a short description of the recieved variables and any necessary explanations.

    • The second argument specifies the page inputs. The syntax for switches/flags (e.g. multiple-list, array, etc.) uses a colon (:) followed by any number of flags separated by commas (,), e.g. foo:integer,multiple,trim. In particular, multiple and array are the flags that correspond to the old ad_page_variables flags.

    • There are new flags: trim, notnull and optional. They do what you'd expect; values will not be trimmed, unless you mark them for it; empty strings are valid input, unless you specify notnull; and a specified variable will be considered required, unless you declare it optional.

    • ad_page_contract can do validation for you: the flags integer and sql_identifier will make sure that the values supplied are integers/sql_identifiers. The integer flag will also trim leading zeros. Note that unless you specify notnull, both will accept the empty string.

    • Note that ad_page_contract does not generate QQvariables, which were automatically created by ad_page_variables and set_the_usual_form_variables. The use of bind variables makes such previous variable syntax obsolete.

    Using ad_library

    For shared Tcl library files, use ad_library after the file path comment. Its only argument is a doc_string in the standard (javadoc-style) format, like ad_page_contract. Don't forget to put the @cvs-id in there. Here is an example of using ad_library:

    # tcl/wp-defs.tcl
    
    ad_library {
        Provides helper routines for the Wimpy Point module.
    
        @author John Doe (jdoe@example.com)
        @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp
    }
    
    Non-Tcl Files

    For SQL and other non-Tcl source files, the following file header structure is recommended:

    -- path relative to the ACS root directory
    --
    -- brief description of the file's purpose
    --
    -- author
    -- created
    --
    -- $Id: eng-standards-filenaming.html,v 1.46 2010/12/11 23:36:32 ryang Exp $
    

    Of course, replace "--" with the comment delimiter appropriate for the language in which you are programming.

    Page Construction

    Construct the page as one Tcl variable (name it page_content), and then send it back to the browser with one call to doc_return, which will call db_release_unused_handles prior to executing ns_return, effectively combining the two operations.

    For example:

    set page_content "[ad_header "Page Title"]
    
    <h2>Page Title</h2>
    
    <hr>
    
    <ul>
    "
    
    db_foreach get_row_info {
        select row_information 
        from bar
    } {
        append page_content "<li>row_information\n"
    }
    
    append page_content "</ul>
    
    [ad_footer]"
    
    doc_return 200 text/html $page_content
    

    The old convention was to call ReturnHeaders and then ns_write for each distinct chunk of the page. This approach has the disadvantage of tying up a scarce and valuable resource (namely, a database handle) for an unpredictable amount of time while sending packets back to the browser, and so it should be avoided in most cases. (On the other hand, for a page that requires an expensive database query, it's better to call ad_return_top_of_page first, so that the user is not left to stare at an empty page while the query is running.)

    Local procedures (i.e., procedures defined and used only within one page) should be prefixed with "module_" and should be used rarely, only when they are exceedingly useful.

    All files that prepare HTML to display should end with [ad_footer] or [module_footer]. If your module requires its own footer, this footer should call ad_footer within it. Why? Because when we adapt the ACS to a new site, it is often the case that the client will want a much fancier display than the ACS standard. We like to be able to edit ad_header (which quite possibly can start a <table>) and ad_footer (which may need to end the table started in ad_footer) to customize the look and feel of the entire site.

    Tcl Library Files

    Further standards for Tcl library files are under discussion; we plan to include naming conventions for procs.

    ($Id: eng-standards-filenaming.html,v 1.46 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/releasing-package.html0000644000175000017500000000711211501005400024232 0ustar frankiefrankie How to package and release an OpenACS Package

    How to package and release an OpenACS Package

    In this example, we are packaging and releasing myfirstpackage as version 1.0.0, which is compatible with OpenACS 5.0.x.

    1. Update the version number, release date, and package maturity of your package in the APM.

    2. Make sure all changes are committed.

    3. Tag the updated work.:

      cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage
      cvs tag myfirstpackages-1-0-0-final
      cvs tag -F openacs-5-0-compat
      

    Done. The package will be added to the repository automatically. If the correct version does not show up within 24 hours, ask for help on the OpenACS.org development forum.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/index.html0000644000175000017500000005004511501005400022002 0ustar frankiefrankie OpenACS Core Documentation

    OpenACS Core Documentation


    Table of Contents

    I. OpenACS For Everyone
    1. High level information: What is OpenACS?
    Overview
    OpenACS Release Notes
    II. Administrator's Guide
    2. Installation Overview
    Basic Steps
    Prerequisite Software
    3. Complete Installation
    Install a Unix-like system and supporting software
    Install Oracle 8.1.7
    Install PostgreSQL
    Install AOLserver 4
    Install OpenACS 5.6.0
    OpenACS Installation Guide for Windows2000
    OpenACS Installation Guide for Mac OS X
    4. Configuring a new OpenACS Site
    Installing OpenACS packages
    Mounting OpenACS packages
    Configuring an OpenACS package
    Setting Permissions on an OpenACS package
    How Do I?
    5. Upgrading
    Overview
    Upgrading 4.5 or higher to 4.6.3
    Upgrading OpenACS 4.6.3 to 5.0
    Upgrading an OpenACS 5.0.0 or greater installation
    Upgrading the OpenACS files
    Upgrading Platform components
    6. Production Environments
    Starting and Stopping an OpenACS instance.
    AOLserver keepalive with inittab
    Running multiple services on one machine
    High Availability/High Performance Configurations
    Staged Deployment for Production Networks
    Installing SSL Support for an OpenACS service
    Set up Log Analysis Reports
    External uptime validation
    Diagnosing Performance Problems
    7. Database Management
    Running a PostgreSQL database on another server
    Deleting a tablespace
    Vacuum Postgres nightly
    A. Install Red Hat 8/9
    B. Install additional supporting software
    Unpack the OpenACS tarball
    Initialize CVS (OPTIONAL)
    Add PSGML commands to emacs init file (OPTIONAL)
    Install Daemontools (OPTIONAL)
    Install qmail (OPTIONAL)
    Install Analog web file analyzer
    Install nspam
    Install Full Text Search using Tsearch2
    Install Full Text Search using OpenFTS (deprecated see tsearch2)
    Install nsopenssl
    Install tclwebtest.
    Install PHP for use in AOLserver
    Install Squirrelmail for use as a webmail system for OpenACS
    Install PAM Radius for use as external authentication
    Install LDAP for use as external authentication
    Install AOLserver 3.3oacs1
    C. Credits
    Where did this document come from?
    Linux Install Guides
    Security Information
    Resources
    III. For OpenACS Package Developers
    8. Development Tutorial
    Creating an Application Package
    Setting Up Database Objects
    Creating Web Pages
    Debugging and Automated Testing
    9. Advanced Topics
    Write the Requirements and Design Specs
    Add the new package to CVS
    OpenACS Edit This Page Templates
    Adding Comments
    Admin Pages
    Categories
    Profile your code
    Prepare the package for distribution.
    Distributing upgrades of your package
    Notifications
    Hierarchical data
    Using .vuh files for pretty urls
    Laying out a page with CSS instead of tables
    Sending HTML email from your application
    Basic Caching
    Scheduled Procedures
    Enabling WYSIWYG
    Adding in parameters for your package
    Writing upgrade scripts
    Connect to a second database
    Future Topics
    10. Development Reference
    OpenACS Packages
    OpenACS Data Models and the Object System
    The Request Processor
    The OpenACS Database Access API
    Using Templates in OpenACS
    Groups, Context, Permissions
    Writing OpenACS Application Pages
    Parties in OpenACS
    Object Identity
    Programming with AOLserver
    Using Form Builder: building html forms dynamically
    11. Engineering Standards
    OpenACS Style Guide
    CVS Guidelines
    Release Version Numbering
    Constraint naming standard
    ACS File Naming and Formatting Standards
    PL/SQL Standards
    Variables
    Automated Testing
    12. Documentation Standards
    OpenACS Documentation Guide
    Using PSGML mode in Emacs
    Using nXML mode in Emacs
    System/Application Requirements Template
    13. Internationalization
    Internationalization and Localization Overview
    How Internationalization/Localization works in OpenACS
    How to Internationalize a Package
    Design Notes
    Translator's Guide
    D. Using CVS with an OpenACS Site
    IV. For OpenACS Platform Developers
    14. Kernel Documentation
    Overview
    Object Model Requirements
    Object Model Design
    Permissions Requirements
    Permissions Design
    Groups Requirements
    Groups Design
    Subsites Requirements
    Subsites Design Document
    Package Manager Requirements
    Package Manager Design
    Database Access API
    OpenACS Internationalization Requirements
    Security Requirements
    Security Design
    Security Notes
    Request Processor Requirements
    Request Processor Design
    Documenting Tcl Files: Page Contracts and Libraries
    Bootstrapping OpenACS
    External Authentication Requirements
    15. Releasing OpenACS
    OpenACS Core and .LRN
    How to Update the OpenACS.org repository
    How to package and release an OpenACS Package
    How to Update the translations
    Index
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-specs.html0000644000175000017500000001505311501005400023651 0ustar frankiefrankie Write the Requirements and Design Specs

    Write the Requirements and Design Specs

    Before you get started you should make yourself familiar with the tags that are used to write your documentation. For tips on editing SGML files in emacs, see OpenACS Documentation Guide.

    It's time to document. For the tutorial we'll use pre-written documentation. When creating a package from scratch, start by copying the documentation template from /var/lib/aolserver/openacs-dev/packages/acs-core-docs/xml/docs/xml/package-documentation-template.xml to myfirstpackage/www/docs/xml/index.xml.

    You then edit that file with emacs to write the requirements and design sections, generate the html, and start coding. Store any supporting files, like page maps or schema diagrams, in the www/doc/xml directory, and store png or jpg versions of supporting files in the www/doc directory.

    For this tutorial, you should instead install the pre-written documentation files for the tutorial app. Log in as $OPENACS_SERVICE_NAME, create the standard directories, and copy the prepared documentation:

    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/
    [$OPENACS_SERVICE_NAME myfirstpackage]$ mkdir -p www/doc/xml
    [$OPENACS_SERVICE_NAME myfirstpackage]$ cd www/doc/xml
    [$OPENACS_SERVICE_NAME xml]$ cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/myfirstpackage/* .
    [$OPENACS_SERVICE_NAME xml]$

    OpenACS uses DocBook for documentation. DocBook is an XML standard for semantic markup of documentation. That means that the tags you use indicate meaning, not intended appearance. The style sheet will determine appearance. You will edit the text in an xml file, and then process the file into html for reading.

    Open the file index.xml in emacs. Examine the file. Find the version history (look for the tag <revhistory>). Add a new record to the document version history. Look for the <authorgroup> tag and add yourself as a second author. Save and exit.

    Process the xml file to create html documentation. The html documentation, including supporting files such as pictures, is stored in the www/docs/ directory. A Makefile is provided to generate html from the xml, and copy all of the supporting files. If Docbook is set up correctly, all you need to do is:

    [$OPENACS_SERVICE_NAME xml]$ make
    cd .. ; /usr/bin/xsltproc ../../../acs-core-docs/www/xml/openacs.xsl xml/index.xml
    Writing requirements-introduction.html for chapter(requirements-introduction)
    Writing requirements-overview.html for chapter(requirements-overview)
    Writing requirements-cases.html for chapter(requirements-cases)
    Writing sample-data.html for chapter(sample-data)
    Writing requirements.html for chapter(requirements)
    Writing design-data-model.html for chapter(design-data-model)
    Writing design-ui.html for chapter(design-ui)
    Writing design-config.html for chapter(design-config)
    Writing design-future.html for chapter(design-future)
    Writing filename.html for chapter(filename)
    Writing user-guide.html for chapter(user-guide)
    Writing admin-guide.html for chapter(admin-guide)
    Writing bi01.html for bibliography
    Writing index.html for book
    [$OPENACS_SERVICE_NAME xml]$

    Verify that the documentation was generated and reflects your changes by browsing to http://yoursite:8000/myfirstpackage/doc

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-ldap-radius.html0000644000175000017500000001535611501005400024552 0ustar frankiefrankie Install LDAP for use as external authentication

    Install LDAP for use as external authentication

    By Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This step by step guide on how to use LDAP for external authentication using the LDAP bind command, which differs from the approach usually taken by auth-ldap. Both will be dealt with in these section

    1. Install openldap. Download and install ns_ldap

      [root aolserver]# cd /usr/local/src/
                [root src]# wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.2.17.tgz
                [root src]# tar xvfz openldap-2.2.17.tgz
                [root src]# cd openldap-2.2.17
                [root src]# ./configure --prefix=/usr/local/openldap
                [root openldap]# make install
                [root openldap]#
      cd /usr/local/src/
      wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.2.17.tgz
      tar xvfz openldap-2.2.17.tgz
      cd openldap-2.2.17
      ./configure --prefix=/usr/local/openldap --disable-slapd
      make install
      
                
    2. Install ns_ldap. Download and install ns_ldap

      [root aolserver]# cd /usr/local/src/aolserver/
                [root aolserver]# wget http://www.sussdorff.de/ressources/nsldap.tgz
                [root aolserver]# tar xfz nsldap.tgz
                [root aolserver]# cd nsldap
                [root ns_pam-0.1]# make install LDAP=/usr/local/openldap INST=/usr/local/aolserver
                [root ns_pam-0.1]#
      cd /usr/local/src/aolserver/
      wget http://www.sussdorff.de/resources/nsldap.tgz
      tar xfz nsldap.tgz
      cd nsldap
      make install LDAP=/usr/local/openldap INST=/usr/local/aolserver
      
                
    3. Configure ns_ldap for traditional use. Traditionally OpenACS has supported ns_ldap for authentification by storing the OpenACS password in an encrypted field within the LDAP server called "userPassword". Furthermore a CN field was used for searching for the username, usually userID or something similar. This field is identical to the usernamestored in OpenACS. Therefore the login will only work if you change login method to make use of the username instead.

      • Change config.tcl. Remove the # in front of ns_param nsldap ${bindir}/nsldap.so to enable the loading of the ns_ldap module.

    4. Configure ns_ldap for use with LDAP bind. LDAP authentication usually is done by trying to bind (aka. login) a user with the LDAP server. The password of the user is not stored in any field of the LDAP server, but kept internally. The latest version of ns_ldap supports this method with the ns_ldap bind command. All you have to do to enable this is to configure auth_ldap to make use of the BIND authentification instead. Alternatively you can write a small script on how to calculate the username out of the given input (e.g. if the OpenACS username is malte.fb03.tu, the LDAP request can be translated into "ou=malte,ou=fb03,o=tu" (this example is encoded in auth_ldap and you just have to comment it out to make use of it).

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-full-text-search-tsearch2.html0000644000175000017500000003570311501005400027243 0ustar frankiefrankie Install Full Text Search using Tsearch2

    Install Full Text Search using Tsearch2

    By Dave Bauer, Joel Aufrecht and Malte Sussdorff with help from Tsearch V2 Introduction by Andrew J. Kopciuch

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Install Tsearch2 module

    If you want full text search, and you are running PostgreSQL, install this module to support FTS. Do this step after you have installed both PostgreSQL and AOLserver. You will need the tseach2 module form PostgreSQL contrib. This is included with the PostgreSQL full source distribution. It is also available with the PostgreSQL contrib package provided by most distribution packages. On debian it is called postgresql-contrib.

    1. For PostgreSQL 7.3 or 7.4, download the http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_7.4.patch.gz tsearch2 patch to correctly restore from a pg_dump backup. If you installed tsearch2 from a package, you can use the http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_update.sql regprocedure script to update the database after tsearch2 is installed into it. TODO link to section decribing how to fix an existing tsearch2 database with this patch.

    2. As of May 9, 2004 there is a source patch available for tsearch2. The patch provides changes to the pg_ts_ configuration tables to allow for easy dump and restore of a database containing tsearch2. The patch is available here : [http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_7.4.patch.gz]

      To apply this patch, download the mentioned file and place it in your postgreSQL source tree ($PGSQL_SRC). This patch makes the backup and restore procedures very simple.

                  [postgres pgsql]$ cd /tmp
                  [postgres tmp]$ wget http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/regprocedure_7.4.patch.gz
                  [postgres pgsql]$ cd /usr/local/src/postgresql-7.4.5/
                  [postgres postgresql-7.4.5] gunzip /tmp/regprocedure_7.4.patch.gz
                  [postgres postgresql-7.4.5] patch -b -p1 < regprocedure_7.4.patch
                    

      If you have a working version of tsearch2 in your database, you do not need to re-install the tsearch2 module. Just apply the patch and run make. This patch only affects the tsearch2.sql file. You can run the SQL script found : [right here] This script will make the modifications found in the patch, and update the fields from the existing data. From this point on, you can dump and restore the database in a normal fashion. Without this patch, you must follow the instructions later in this document for backup and restore.

      This patch is only needed for tsearch2 in PostgreSQL versions 7.3.x and 7.4.x. The patch has been applied to the sources for 8.0.

    3. Install Tsearch2. This is a PostgreSQL module that the tsearch2-driver OpenACS package requires. These instructions assume you are using the latest point release of PostgreSQL 7.4.5.

      [root root]# su - postgres
      [postgres pgsql]$ cd /usr/local/src/postgresql-7.4.5/contrib/tsearch2/
      [postgres tsearch2]$ make
      [postgres tsearch2]$ make install
      mkdir /usr/local/pgsql/share/contrib
      mkdir /usr/local/pgsql/doc/contrib
      (2 lines omitted)
      /bin/sh ../../config/install-sh -c -m 755 libtsearch.so.0.0 /usr/local/pgsql/lib/tsearch.so
      [postgres tsearch]$ exit
      logout
      
      [root root]#
      su - postgres
      cd /usr/local/src/postgresql-7.4.5/contrib/tsearch2
      make
      make install
      exit

    Install Full Text Search Engine Package in OpenACS

    1. Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install.

    2. Click on the Install software link.

    3. Click on the Install new service link.

    4. Click on the Install link next to Tsearch2 Driver. If you have installed tsearch2 into your PostgreSQL database, the installer will automatically enable tsearch in your OpenACS database instance.

    5. Restart the service.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    6. Wait a minute, then browse back to the home page.

    7. Click on Admin on the top of the screen.

    8. Click on Main Site Administration in the "Subsite Administration" section.

    9. Click on Site Map in the "Advanced Features" section.

    10. Mount the Search interface in the site map.

      1. Click the new sub folder link on the Main Site line.

      2. Type search and click New.

      3. Click the new application link on the search line.

      4. Type search where it says untitled, choose search from the drop-down list, and click New.

      5. Click the Parameters link next to the Search package istance.

      6. Type tsearch2-driver where it says openfts-driver in the FtsEngineDriver parameter.

    11. Restart the service.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    12. Wait a minute, then click on Main Site at the top of the page.

    Enable Full Text Search in packages

    Enabling Full Text Search in packages at the moment is not trivial. It involves a couple of steps, which I will illustrate taking lars-blogger as an example package

    1. Install the package.

      1. Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install.

      2. Click on the Install software link.

      3. Click on the Install new application link.

      4. Click on the Install link next to Weblogger.

      5. Install all required packages as well (always say okay until you shall restart the server)

    2. Load the service contracts datamodell and enable the service contract

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd packages/lars-blogger/sql/postgresql
      [$OPENACS_SERVICE_NAME postgresql]$ psql $OPENACS_SERVICE_NAME -f lars-blogger-sc-create.sql

      Note: Usually this script is called package_name-sc-create.sql

    3. Restart the service.

      [$OPENACS_SERVICE_NAME postgresql]$ svc -t /service/$OPENACS_SERVICE_NAME
                      [$OPENACS_SERVICE_NAME postgresl]$

    If you are lucky, Full Text Search is enabled now, if not consult http://openacs.org/forums/message-view?message_id=154759. This link also contains some hints on how to make sure it is enabled.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/permissions-requirements.html0000644000175000017500000003424211501005400025770 0ustar frankiefrankie Permissions Requirements

    Permissions Requirements

    By John McClary Prevost

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    This document records requirements for the OpenACS 4 Permissions system, a component of the OpenACS 4 Kernel. The Permissions system is meant to unify and centralize the handling of access and control on a given OpenACS 4 system.

    Vision Statement

    Any multi-user software system must address the general problem of permissions, or "who can do what, on what." On web services, which typically involve large numbers of users belonging to different groups, permissions handling is a critical need: access to content, services, and information generally must be controlled. The OpenACS 4 Permissions system is meant to serve as a consistent, unified interface for higher-level OpenACS applications to handle permissions. Consolidating access control in such a manner reduces both cost and risk: cost, in that less code has to be written and maintained for dealing with recurring permissions situations; risk, in that we need not rely on any single programmer's diligence to ensure access control is implemented and enforced correctly.

    Historical Motivations

    In earlier versions of the OpenACS, permissions and access control was handled on a module-by-module basis, often even on a page-by-page basis. For example, a typical module might allow any registered user to access its pages read-only, but only allow members of a certain group to make changes. The way this group was determined also varied greatly between modules. Some modules used "roles", while others did not. Other modules did all access control based simply on coded rules regarding who can act on a given database row based on the information in that row.

    Problems resulting from this piecemeal approach to permissions and access control were many, the two major ones being inconsistency, and repeated/redundant code. Thus the drive in OpenACS 4 to provide a unified, consistent permissions system that both programmers and administrators can readily use.

    System Overview

    The OpenACS 4 Permissions system has two main pieces: first, an API for developers to readily handle access control in their applications. The second piece of the system is a UI meant primarily for (subsite) administrators to grant and revoke permissions to system entities under their control.

    Consistency is a key characteristic of the Permissions system - both for a common administrative interface, and easily deployed and maintained access control. The system must be flexible enough to support every access model required in OpenACS applications, but not so flexible that pieces will go unused or fall outside the common administrative interfaces.

    Use Cases and User Scenarios

    Terminology

    The primary question an access control system must answer is a three-way relation, like that between the parts of most simple sentences. A simple sentence generally has three parts, a subject, an object, and a verb - in the context of OpenACS Permissions, our simple sentence is, "Can this party perform this operation on this target?" Definitions:

    The subject of the sentence is "party" - a distinguishable actor whose access may be controlled, this special word is used because one person may be represented by several parties, and one party may represent many users (or no users at all).

    The object of the sentence is "target" - this is an entity, or object, that the party wishes to perform some action on. An entity/object here is anything that can be put under access control.

    The verb of the sentence is "operation" - a behavior on the OpenACS system subject to control, this word is used to represent the fact that a single operation may be part of many larger actions the system wants to perform. If "foo" is an operation, than we sometimes refer to the foo "privilege" to mean that a user has the privilege to perform that operation.

    Examples of the essential question addressed by the Permissions system: Can jane@attacker.com delete the web security forum? Can the Boston office (a party) within the VirtuaCorp intranet/website create its own news instance?

    Functional Requirements

    10.0 Granularity

    The system must support access control down to the level of a single entity (this would imply down to the level of a row in the OpenACS Objects data model).

    20.0 Operations

    The system itself must be able to answer the essential permissions question as well as several derived questions.

    20.10 Basic Access Check

    The system must be able to answer the question, "May party P perform operation O on target T?"

    20.20 Allowed Parties Check

    The system must be able to answer the question, "Which parties may perform operation O on target T?"

    20.30 Allowed Operations Check

    The system must be able to answer the question, "Which operations may party P perform on target T?"

    20.40 Allowed Targets Check

    The system must be able to answer the question, "Upon which targets may party P perform operation O?"

    Behavioral Requirements

    40.0 Scale of Privileges

    Privileges must be designed with appropriate scope for a given OpenACS package. Some privileges are of general utility (e.g. "read" and "write"). Others are of more limited use (e.g. "moderate" - applies mainly to a package like forum, where many users are contributing content simultaneously). A package defining its own privileges should do so with moderation, being careful not to overload a privilege like "read" to mean too many things.

    50.0 Aggregation of Operations (Privileges)

    For user interface purposes, it can be appropriate to group certain privileges under others. For example, anyone with the "admin" privilege may also automatically receive "read", "write", "delete", etc. privileges.

    60.0 Aggregation of Parties (Groups)

    The system must allow aggregation of parties. The exact method used for aggregation will probably be addressed by the OpenACS 4 "Groups" system. Regardless of the exact behavior of aggregate parties, if an aggregate party exists, then access which is granted to the aggregate party should be available to all members of that aggregate.

    70.0 Scope of Access Control

    70.10 Context

    There must be a method for objects to receive default access control from some context. For example, if you do not have read access to a forum, you should not have read access to a message in that forum.

    70.20 Overriding

    It must be possible to override defaults provided by the context of an object (as in 70.10), in both a positive and negative manner.

    70.20.10 Positive Overriding

    It must be possible to allow a party more access to some target than they would get by default. (For example, a user does not have the right to edit any message on a forum. But a user does possibly have the right to edit their own messages.)

    70.20.20 Negative Overriding

    It must be possible to deny a party access to some target that their inherited privileges would have allowed. (For example, a subdirectory in the file-storage might normally have its parent directory as context. It should be possible, however, to make a subdirectory private to some group.)

    100.0 Efficiency

    At least the basic access check (20.10) and the allowed targets check (20.40) must be efficient enough for general use, i.e. scalable under fairly heavy website traffic. It can be expected that almost every page will contain at least one basic access check, and most pages will contain an allowed targets check (20.40).

    In particular, constraining a SELECT to return only rows the current user has access to should not be much slower than the SELECT on its own.

    120.0 Ease of Use

    Since most SQL queries will contain an allowed target check in the where clause, whatever mechanism is used to make checks in SQL should be fairly small and simple.

    In particular, constraining a SELECT to return only rows the current user has access to should not add more than one line to a query.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation8/17/2000John Prevost
    0.2Revised, updated with new terminology8/25/2000John Prevost
    0.3Edited, reformatted to conform to requirements template, pending freeze.8/26/2000Kai Wu
    0.4Edited for ACS 4 Beta release.10/03/2000Kai Wu
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/style-guide.html0000644000175000017500000002161411501005400023126 0ustar frankiefrankie OpenACS Style Guide

    OpenACS Style Guide

    By Jeff Davis

    Motivation

    Why have coding standards for OpenACS? And if the code works why change it to adhere to some arbitrary rules?

    Well, first lets consider the OpenACS code base (all this as of December 2003 and including dotLRN). There are about 390,000 lines of tcl code, about 460,000 lines of sql (in datamodel scripts and .xql files), about 80,000 lines of markup in .adp files, and about 100,000 lines of documentation. All told, just about a million lines of "stuff". In terms of logical units there are about 160 packages, 800 tables, 2,000 stored procedures, about 2,000 functional pages, and about 3,200 tcl procedures.

    When confronted by this much complexity it's important to be able to make sense of it without having to wade through it all. Things should be coherent, things should be named predictably and behave like you would expect, and your guess about what something is called or where it is should be right more often than not because the code follows the rules.

    Unfortunately, like any large software project written over a long period by a lot of different people, OpenACS sometimes lacks this basic guessability and in the interest of bringing it into line we have advanced these guidelines.

    Commandments

    Here is a short list of the basic rules code contributed to OpenACS should follow...

    1. Follow the file naming and the package structure rules.  Some of the file naming rules are requirements for things to function correctly (for example data model creation scripts and tcl library files must be named properly to be used), while some are suggestions (the object-verb naming convention) which if ignored won't break anything, but if you follow the rules people will be able to understand your package much more easily.

    2. Be literate in your programming.  Use ad_proc, ad_library, and ad_page_contract to provide documentation for your code, use comments on your datamodel, explain what things mean and how they should work.

    3. Test.  Write test cases for your API and data model; test negative cases as well as positive; document your tests. Provide tests for bugs which are not yet fixed. Test, Test, Test.

    4. Use namespaces.  For new packages choose a namespace and place all procedures in it and in oracle create packages.

    5. Follow the constraint naming and the PL/SQL and PL/pgSQL rules.  Naming constraints is important for upgradability and for consistency. Also, named constraints can be immensely helpful in developing good error handling. Following the PL/SQL and PL/pgSQL rules ensure that the procedures created can be handled similarly across both Oracle and PostgreSQL databases.

    6. Follow the code formatting guidelines.  The code base is very large and if things are formatted consistently it is easier to read. Also, if it conforms to the standard it won't be reformatted (which can mask the change history and making tracking down bugs much harder). Using spaces rather than tabs makes patches easier to read and manage and does not force other programmers to decipher what tab settings you had in place in your editor.

    7. Use the standard APIs.  Don't reinvent the wheel. Prefer extending an existing core API to creating your own. If something in the core does not meet your particular needs it probably won't meet others as well and fleshing out the core API's makes the toolkit more useful for everyone and more easily extended.

    8. Make sure your datamodel create/drop scripts work.  Break the table creation out from the package/stored procedure creation and use create or replace where possible so that scripts can be sourced more than once. Make sure your drop script works if data has been inserted (and permissioned and notifications have been attached etc).

    9. Practice CVS/Bug Tracker Hygiene.  Commit your work. commit with sensible messages and include patch and bug numbers in your commit messages.

      Create bug tracker tickets for things you are going to work on yourself (just in case you don't get to it and to act as a pointer for others who might encounter the same problem).

    10. Solicit code reviews.  Ask others to look over your code and provide feedback and do the same for others.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation12/2003Jeff Davis
    ($Id: style-guide.html,v 1.26 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/groups-requirements.html0000644000175000017500000007013211501005400024732 0ustar frankiefrankie Groups Requirements

    Groups Requirements

    By Rafael H. Schloming, Mark Thomas

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services for different user communities.

    Vision Statement

    A powerful web service that can meet the needs of large enterprises must be able to model the the real world's very rich organizational structures and many ways of decomposing the same organization. For example, a corporation can be broken into structures (the corporation, its divisions, and their departments) or regions (the Boston office, the LA office); a person who is employed by (is a member of) a specific department is also a member of the division and the corporation, and works at (is a member of, but in a different sense) a particular office. OpenACS's Parties and Groups system will support such complex relations faithfully.

    Historical Motivations

    The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships expensive.

    In addition, the Module Scoping design in OpenACS 3.0 introduced a party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer to:

    • add these three columns to each "scoped" table

    • define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null group_id)

    • perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and group_id values

    In sum, the goal of the Parties and Groups system is to provide OpenACS programmers and site administrators with simple tools that fully describe the complex relationships that exist among groups in the real world.

    User Scenarios

    Pat Developer has a client project and wants to model the company, its offices, its divisions, and its departments as groups and the employees as users.

    System Overview

    We start with Groups, which contain members; the member can be either a person or another group (i.e. a member is a party).

    In addition to membership, the party and groups system defines a composition relationship that may exist between groups: A group can be a component of another group. The child group is called a component group; the parent group is called a composite group.

    A group Gc can be a member and/or a component of another group Gp; the difference is in the way the members of Gc are related to Gp:

    • If a party P is a member (or a component) of Gc and if Gc is a component of Gp, then P is also a member (or a component) of Gp

    • If a party P is a member (or a component) of Gc and if Gc is a member of Gp, then no relationship between P and Gp exists as a result of the relationship between Gp and Gp.

    Consider an example to make this less abstract: Pretend that the Sierra Club is a member of Greenpeace. The Sierra Club has chapters; each chapter is a component of the Sierra Club. If Eddie Environmentalist is a member of the Massachusetts Chapter of the Sierra Club, Eddie is automatically a member of the Sierra Club, but being a Sierra Club member does not make Eddie a member of Greenpeace.

    In the OpenACS, Greenpeace, Sierra Club, and the Sierra Club chapters would be modeled as groups, and Eddie would be a user. There would be a composition relationship between each Sierra Club chapter and the Sierra Club. Membership relationships would exist between Eddie and the Massachusetts Chapter, between Eddie and the Sierra Club (due to Eddie's membership in the Massachusetts chapter), and between the Sierra Club and Greenpeace.

    Membership requirements can vary from group to group. The parties and groups system must provide a base type that specifies the bare minimum necessary to join a group.

    The parties and groups system must support constraints between a composite group GP and any of its component groups, GC. For example, the system should be able to enforce a rule like: Do not allow a party P to become a member of GC unless P is already a member of GP.

    Requirements: Data Model

    The data model for the parties and groups system must provide support for the following types of entities:

    10.0 Parties

    A party is an entity used to represent either a group or a person.

    The data model should enforce these constraints:

    10.10 A party has an email address, which can be empty.

    10.20 A party may have multiple email addresses associated with it.

    10.30 The email address of a party must be unique within an OpenACS system.

    20.0 Groups

    A group is a collection of zero or more parties.

    20.10 The data model should support the subclassing of groups via OpenACS Objects.

    30.0 Persons

    A person represents an actual human being, past or present.

    30.10. A person must have an associated name.

    40.0 Users

    A user is a person who has registered with an OpenACS site. A user may have additional attributes, such as a screen name.

    The data model should enforce these constraints:

    40.10 A user must have a non-empty email address.

    40.20 Two different users may not have the same email address on a single OpenACS installation; i.e., an email address identifies a single user on the system.

    40.30 A user may have multiple email addresses; for example, two or more email addresses may identify a single user.

    40.40 A user must have password field which can be empty.

    The data model for the parties and groups system must provide support for the following types of relationships between entities:

    50.0 Membership

    A party P is considered a member of a group G

    • when a direct membership relationship exists between P and G

    • or when there exists a direct membership relationship between P and some group GC and GC has a composition relationship (c.f., 60.0) with G.

    50.10 A party may be a member of multiple groups.

    50.20 A party may be a member of the same group multiple times only when all the memberships have different types; for example, Jane may be a member of The Company by being both an Employee and an Executive.

    50.30 A party as a member of itself is not supported.

    50.40 The data model must support membership constraints.

    50.50The data model should support the subclassing of membership via OpenACS Relationships.

    60.0 Composition

    A group GC is considered a component of a second group GP

    • when a direct composition relationship exists between GC and GP

    • or when there exists a direct composition relationship between GC and some group Gi and Gi has a composition relationship with GP.

    60.10A group may be a component of multiple groups.

    60.20A group as a component of itself is not supported.

    60.30The data model must support component constraints.

    60.40The data model should support the subclassing of composition via OpenACS Relationships.

    Requirements: API

    The API should let programmers accomplish the following tasks:

    70.10 Create a group

    The parties and groups system provides a well defined API call that creates a new group by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in the data model.

    70.20 Create a person

    The parties and groups system provides a well defined API call that creates a new person by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in the data model.

    70.30 Create a user

    The parties and groups system provides a well defined API call that creates a new user by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in the data model.

    80.10 Refine a person to a user

    The parties and groups system provides a well defined API call that creates a new user by running the appropriate transactions on an existing person entity. This API is subject to the constraints laid out in the data model.

    80.30 Demote a user to a person

    The parties and groups system provides a well defined API call that demotes an existing user entity to a person entity by running the appropriate transactions on the existing user. This API is subject to the constraints laid out in the data model.

    90.10 Update a party

    The programmer should be able to modify, add, and delete attributes on any party. This API is subject to the constraints laid out in the data model.

    95.10 Get the attributes of a party

    The programmer should be able to view the attributes on any party. This API is subject to the constraints laid out in the data model.

    100.10 Delete a party

    The system provides an API for deleting a party. This API is subject to the constraints laid out in the data model.

    100.30 The system may provide a single API call to remove the party from all groups and then delete the party.

    100.40 In the case of a group, the system may provide a single API call to remove all parties from a group and then delete the group.

    110.0 Add a party as a member of a group

    The parties and groups system provides an API for adding a party as a member of a group. This API is subject to the constraints laid out in the data model.

    115.0 Add a group as a component of a second group

    The parties and groups system provides an API for adding a group as a component of a second group. This API is subject to the constraints laid out in the data model.

    120.0 Remove a party as a member of a group

    The parties and groups system provides an API for deleting a party's membership in a group. This API is subject to the constraints laid out in the data model.

    125.0 Remove a group as a component of a second group

    The parties and groups system provides an API for deleting a group's composition in a second group. This API is subject to the constraints laid out in the data model.

    130.0 Membership check

    The parties and groups system provides an API for answering the question: "Is party P a member of group G?"

    135.0 Composition check

    The parties and groups system provides an API for answering the question: "Is group GC a component of group GP?"

    140.0 Get members query

    The parties and groups system provides an API for answering the question: "Which parties are members of group G?"

    145.0 Get components query

    The parties and groups system provides an API for answering the question: "Which groups are components of group G?"

    150.0 Member-of-groups query

    The parties and groups system provides an API for answering the question: "Of which groups is party P a member?"

    155.0 Component-of-groups query

    The parties and groups system provides an API for answering the question: "Of which groups is group G a component?"

    160.0 Allowed membership check

    The parties and groups system provides an API for answering the question: "Is party P allowed to become a member of group G?"

    165.0 Allowed composition check

    The parties and groups system provides an API for answering the question: "Is group GC allowed to become a component of group GP?"

    170.0 Efficiency

    Since many pages at a site may check membership in a group before serving a page (e.g., as part of a general permissions check), the data model must support the efficient storage and retrieval of party attributes and membership.

    180.0 Ease of Use

    Since many SQL queries will check membership in a group as part of the where clause, whatever mechanism is used to check membership in SQL should be fairly small and simple.

    Requirements: User Interface

    The user interface is a set of HTML pages that are used to drive the underlying API. The user interface may provide the following functions:

    • 200.0 Create a party

    • 210.0 View the attributes of a party

    • 220.0 Update the attributes of a party

    • 240.0 Delete a party

    • 250.0 Add a party to a group

    • 260.0 Remove a party from a group

    • 270.0 Perform the membership and composition checks outlined in 130.x to 165.x

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation08/16/2000Rafael Schloming
    0.2Initial revision08/19/2000Mark Thomas
    0.3Edited and reviewed, conforms to requirements template08/23/2000Kai Wu
    0.4Further revised, added UI requirements08/24/2000Mark Thomas
    0.5Final edits, pending freeze08/24/2000Kai Wu
    0.6More revisions, added composition requirements08/30/2000Mark Thomas
    0.7More revisions, added composition requirements09/08/2000Mark Thomas
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/automated-backup.html0000644000175000017500000000704011456662477024156 0ustar frankiefrankie Automated Backup

    Automated Backup

    The recommended backup strategy for a production sit is to use an automated script which first backs up the database to a file in /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup and then backs up all of /var/lib/aolserver/$OPENACS_SERVICE_NAME to a single zip file, and then copies that zip file to another computer.

    1. Make sure that the manual backup process described above works.

    2. Customize the default backup script. Edit /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/backup.sh with your specific parameters.

    3. Make sure the file is executable:

      chmod +x backup.sh
    4. Set this file to run automatically by adding a line to root's crontab. (Typically, with export EDITOR=emacs; crontab -e.) This example runs the backup script at 1:30 am every day.

      30 1 * * *        sh /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/backup.sh
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/configuring-configuring-permissions.html0000644000175000017500000000714011501005400030064 0ustar frankiefrankie Setting Permissions on an OpenACS package

    Setting Permissions on an OpenACS package

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Setting Permission on an OpenACS package

    After you've installed and mounted your package, you can configure each instance to act as you would like.

    This is done from the Applications page. Log in, go to the Admin or Control Panel, click on the subsite the application is in, and click on Applications. If you click on the 'Permissions' link, you will see and be able to set the permissions for that application.

    Each application may have different behavior for what Read Create Write and Admin permissions mean, but generally the permissions are straightforward. If you find the behavior is not what you expect after setting permissions, you can post a bug in the OpenACS bugtracker.

    'The Public' refers to users to the website who are not logged in. 'Registered Users' are people who have registered for the site.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/bootstrap-acs.html0000644000175000017500000002356511501005400023463 0ustar frankiefrankie Bootstrapping OpenACS

    Bootstrapping OpenACS

    By Jon Salz

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    • Tcl code: /tcl/0-acs-init.tcl and /packages/acs-kernel/bootstrap.tcl

    This document describes the startup (bootstrapping) process for an AOLserver running OpenACS.

    The Big Picture

    Before OpenACS 3.3, the OpenACS startup process was extremely simple: after AOLserver performed its internal initialization (reading the configuration file, loading shared libraries and module code, etc.) it scanned through the Tcl library directory (generally /var/lib/aolserver/yourservername/tcl), sourcing each file in sequence.

    While this overall structure for initialization is still intact, package management has thrown a wrench into the works - there are a few extra things to do during initialization, most notably:

    • Examine the OpenACS file tree for files that should not be present in OpenACS (i.e., that were once part of the OpenACS distribution but have since been removed).

    • Scan the /packages directory for new packages.

    • Initialize enabled packages by sourcing their *-procs.tcl and *-init.tcl files.

    This document examines in detail each of the steps involved in AOLserver/OpenACS startup.

    The Startup Process

    As soon as the nsd daemon is executed by the init process (or otherwise), AOLserver reads its configuration file and chroots itself if necessary. It then loads shared libraries indicated in the .ini file (e.g., the Oracle driver and nssock), and sources Tcl module files (generally in /home/aol30/modules/tcl). This step is, and has always been, the same for all AOLservers, regardless of whether they are running OpenACS.

    Next AOLserver sources, in lexicographical order, each file in the /tcl directory. The first such file is 0-acs-init.tcl, which doesn't do much directly except to determine the OpenACS path root (e.g., /var/lib/aolserver/yourservername) by trimming the final component from the path to the Tcl library directory (/var/lib/aolserver/yourservername/tcl). But 0-acs-init.tcl's has an important function, namely sourcing /packages/acs-core/bootstrap.tcl, which does the following:

    1. Initialize some NSVs used by the core. These NSVs are documented in /packages/acs-core/apm-procs.tcl - no need to worry about them unless you're an OpenACS core hacker.

    2. Verify the deletion of obsolete OpenACS files. The /tcl directory has evolved quite a bit over the months and years, and a few files have come and gone. The /www/doc/removed-files.txt file contains a list of files which must be deleted from the AOLserver installation, at the risk of causing weird conflicts, e.g., having several security filters registered. bootstrap.tcl scans through this list, logging error messages to the log if any of these files exist.

    3. Source *-procs.tcl files in the OpenACS core. We source each file matching the *-procs.tcl glob in the /packages/acs-kernel directory, in lexicographical order. These procedure are needed to perform any of the following steps.

    4. Ensure that the database is available by grabbing and releasing a handle. If we can't obtain a handle, we terminate initialization (since OpenACS couldn't possibly start up the server without access to the database).

    5. Register any new packages in the /packages directory. In each directory inside /packages, we look for a .info file; if we find a package that hasn't yet been registered with the package manager (i.e., it's been copied there manually), we insert information about it into the database. (The first time OpenACS starts up, no packages will have been registered in the database yet, so this step will registers every single package in the /packages directory.) Note that packages discovered here are initially disabled; they must be manually enabled in the package manager before they can be used.

    6. Ensure that the acs-kernel package is enabled. If the OpenACS core isn't initialized, the server couldn't possibly be operational, so if there's no enabled version of the OpenACS core we simply mark the latest installed one as enabled.

    7. Load *-procs.tcl files for enabled packages, activating their APIs.

    8. Load *-init.tcl files for enabled packages, giving packages a chance to register filters and procedures, initialize data structures, etc.

    9. Verify that the core has been properly initialized by checking for the existence of an NSV created by the request processor initialization code. If it's not present, the server won't be operational, so we log an error.

    At this point, bootstrap.tcl is done executing. AOLserver proceeds to source the remaining files in the /tcl directory (i.e., unpackaged libraries) and begins listening for connections.

    ($Id: bootstrap-acs.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n-introduction.html0000644000175000017500000004662011501005400024175 0ustar frankiefrankie How Internationalization/Localization works in OpenACS

    How Internationalization/Localization works in OpenACS

    This document describes how to develop internationalized OpenACS packages, including writing new packages with internationalization and converting old packages. Text that users might see is "localizable text"; replacing monolingual text and single-locale date/time/money functions with generic functions is "internationalization"; translating first generation text into a specific language is "localization." At a minimum, all packages should be internationalized. If you do not also localize your package for different locales, volunteers may use a public "localization server" to submit suggested text. Otherwise, your package will not be usable for all locales.

    The main difference between monolingual and internationalized packages is that all user-visible text in the code of an internationalized package are coded as "message keys." The message keys correspond to a message catalog, which contains versions of the text for each available language. Script files (.adp and .tcl and .vuh), database files (.sql), and APM parameters are affected.

    Other differences include: all dates read or written to the database must use internationalized functions. All displayed dates must use internationalized functions. All displayed numbers must use internationalized functions.

    Localizable text must be handled in ADP files, in TCL files, and in APM Parameters. OpenACS provides two approaches, message keys and localized ADP files. For ADP pages which are mostly code, replacing the message text with message key placeholders is simpler. This approach also allows new translation in the database, without affecting the file system. For ADP pages which are static and mostly text, it may be easier to create a new ADP page for each language. In this case, the pages are distinguished by a file naming convention.

    User Content

    OpenACS does not have a general system for supporting multiple, localized versions of user-input content. This document currently refers only to internationalizing the text in the package user interface.

    Separate Templates for each Locale

    If the request processor finds a file named filename.locale.adp, where locale matches the user's locale, it will process that file instead of filename.adp. For example, for a user with locale tl_PH, the file index.tl_PH.adp, if found, will be used instead of index.adp. The locale-specific file should thus contain text in the language appropriate for that locale. The code in the page, however, should still be in English. Message keys are processed normally.

    Message Catalogs

    Message Keys in Template Files (ADP Files)

    Internationalizing templates is about replacing human readable text in a certain language with internal message keys, which can then be dynamically replaced with real human language in the desired locale. Message keys themselves should be in ASCII English, as should all code. Three different syntaxes are possible for message keys.

    "Short" syntax is the recommended syntax and should be used for new development. When internationalizing an existing package, you can use the "temporary" syntax, which the APM can use to auto-generate missing keys and automatically translate to the short syntax. The "verbose" syntax is useful while developing, because it allows default text so that the page is usable before you have done localization.

    • The short: #package_key.message_key#

      The advantage of the short syntax is that it's short. It's as simple as inserting the value of a variable. Example: #forum.title#

    • The verbose: <trn key="package_key.message_key" locale="locale">default text</trn>

      The verbose syntax allows you to specify a default text in a certain language. This syntax is not recommended anymore, but it can be convenient for development, because it still works even if you haven't created the message in the message catalog yet, because what it'll do is create the message key with the default text from the tag as the localized message. Example: <trn key="forum.title" locale="en_US">Title</trn>

    • The temporary: <#message_key original text#>

      This syntax has been designed to make it easy to internationalize existing pages. This is not a syntax that stays in the page. As you'll see later, it'll be replaced with the short syntax by a special feature of the APM. You may leave out the message_key by writing an underscore (_) character instead, in which case a message key will be auto-generated by the APM. Example: <_ Title>

    We recommend the short notation for new package development.

    Message Keys in TCL Files

    In adp files message lookups are typically done with the syntax \#package_key.message_key\#. In Tcl files all message lookups *must* be on either of the following formats:

    • Typical static key lookup: [_ package_key.message_key] - The message key and package key used here must be string literals, they can't result from variable evaluation.

    • Static key lookup with non-default locale: [lang::message::lookup $locale package_key.message_key] - The message key and package key used here must be string literals, they can't result from variable evaluation.

    • Dynamic key lookup: [lang::util::localize $var_with_embedded_message_keys] - In this case the message keys in the variable var_with_embedded_message_keys must appear as string literals \#package_key.message_key\# somewhere in the code. Here is an example of a dynamic lookup: set message_key_array { dynamic_key_1 \#package_key.message_key1\# dynamic_key_2 \#package_key.message_key2\# } set my_text [lang::util::localize $message_key_array([get_dynamic_key])]

    Translatable texts in page TCL scripts are often found in page titles, context bars, and form labels and options. Many times the texts are enclosed in double quotes. The following is an example of grep commands that can be used on Linux to highlight translatable text in TCL files:

    # Find text in double quotes
    find -iname '*.tcl'|xargs egrep -i '"[a-z]'
    
    # Find untranslated text in form labels, options and values
    find -iname '*.tcl'|xargs egrep -i '\-(options|label|value)'|egrep -v '<#'|egrep -v '\-(value|label|options)[[:space:]]+\$[a-zA-Z_]+[[:space:]]*\\?[[:space:]]*$'
    
    # Find text in page titles and context bars
    find -iname '*.tcl'|xargs egrep -i 'set (title|page_title|context_bar) '|egrep -v '<#'
    
    # Find text in error messages
    find -iname '*.tcl'|xargs egrep -i '(ad_complain|ad_return_error)'|egrep -v '<#'
    
          

    You may mark up translatable text in TCL library files and TCL pages with temporary tags on the <#key text#> syntax. If you have a sentence or paragraph of text with variables and or procedure calls in it you should in most cases try to turn the whole text into one message in the catalog (remember that translators is made easier the longer the phrases to translate are). In those cases, follow these steps:

    • For each message call in the text, decide on a variable name and replace the procedure call with a variable lookup on the syntax %var_name%. Remember to initialize a tcl variable with the same name on some line above the text.

    • If the text is in a tcl file you must replace variable lookups (occurences of $var_name or ${var_name}) with %var_name%

    • You are now ready to follow the normal procedure and mark up the text using a tempoarary message tag (<#_ text_with_percentage_vars#>) and run the action replace tags with keys in the APM.

    The variable values in the message are usually fetched with upvar, here is an example from dotlrn: ad_return_complaint 1 "Error: A [parameter::get -parameter classes_pretty_name] must have <em>no</em>[parameter::get -parameter class_instances_pretty_plural] to be deleted" was replaced by: set subject [parameter::get -localize -parameter classes_pretty_name] set class_instances [parameter::get -localize -parameter class_instances_pretty_plural] ad_return_complaint 1 [_ dotlrn.class_may_not_be_deleted]

    This kind of interpolation also works in adp files where adp variable values will be inserted into the message.

    Alternatively, you may pass in an array list of the variable values to be interpolated into the message so that our example becomes:

    set msg_subst_list [list subject [parameter::get -localize -parameter classes_pretty_name] class_instances [parameter::get -localize -parameter class_instances_pretty_plural]]
    
    ad_return_complaint 1 [_ dotlrn.class_may_not_be_deleted $msg_subst_list]
    
    

    When we were done going through the tcl files we ran the following commands to check for mistakes:

    # Message tags should usually not be in curly braces since then the message lookup may not be
    # executed then (you can usually replace curly braces with the list command). Find message tags 
    # in curly braces (should return nothing, or possibly a few lines for inspection)
    find -iname '*.tcl'|xargs egrep -i '\{.*<#'
    
    # Check if you've forgotten space between default key and text in message tags (should return nothing)
    find -iname '*.tcl'|xargs egrep -i '<#_[^ ]'
    
    # Review the list of tcl files with no message lookups
    for tcl_file in $(find -iname '*.tcl'); do egrep -L '(<#|\[_)' $tcl_file; done
    

    When you feel ready you may vist your package in the package manager and run the action "Replace tags with keys and insert into catalog" on the TCL files that you've edited to replace the temporary tags with calls to the message lookup procedure.

    Dates, Times, and Numbers in TCL files

    Most date, time, and number variables are calculated in TCL files. Dates and times must be converted when stored in the database, when retrieved from the database, and when displayed. All dates are stored in the database in the server's timezone, which is an APM Parameter set at /acs-lang/admin/set-system-timezone and readable at lang::system::timezone.. When retrieved from the database and displayed, dates and times must be localized to the user's locale.

    APM Parameters

    Some parameters contain text that need to be localized. In this case, instead of storing the real text in the parameter, you should use message keys using the short notation above, i.e. #package_key.message_key#.

    In order to avoid clashes with other uses of the hash character, you need to tell the APM that the parameter value needs to be localized when retrieving it. You do that by saying: parameter::get -localize.

    Here are a couple of examples. Say we have the following two parameters, taken directly from the dotlrn package.

    Parameter NameParameter Value
    class_instance_pages_csv#dotlrn.class_page_home_title#,Simple 2-Column;#dotlrn.class_page_calendar_title#,Simple 1-Column;#dotlrn.class_page_file_storage_title#,Simple 1-Column
    departments_pretty_name#departments_pretty_name#

    Then, depending on how we retrieve the value, here's what we get:

    Command used to retrieve ValueRetrieved Value
    parameter::get -localize -parameter class_instances_pages_csvKurs Startseite,Simple 2-Column;Kalender,Simple 1-Column;Dateien,Simple 1-Column
    parameter::get -localize -parameter departments_pretty_nameAbteilung
    parameter::get -parameter departments_pretty_name#departments_pretty_name#

    The value in the rightmost column in the table above is the value returned by an invocation of parameter::get. Note that for localization to happen you must use the -localize flag.

    The locale used for the message lookup will be the locale of the current request, i.e. lang::conn::locale or ad_conn locale.

    Developers are responsible for creating the keys in the message catalog, which is available at /acs-lang/admin/

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/subsites.html0000644000175000017500000003564411501005400022544 0ustar frankiefrankie Writing OpenACS Application Pages

    Writing OpenACS Application Pages

    By Rafael H. Schloming and Pete Su

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Overview

    In this document, we'll examine the user interface pages of the Notes application in more detail, covering two separate aspects of page development in OpenACS. First, we'll talk about the code needed to make your pages aware of which application instance they are running in. Second, we'll talk about using the form builder to develop form-based user interfaces in OpenACS. While these seem like unrelated topics, they both come up in the example page that we are going to look at, so it makes sense to address them at the same time.

    Application Instances and Subsites

    As you will recall from the packages tutorial, the Request Processor (RP) and Package Manager (APM) allow site administrators to define an arbitrary mapping from URLs in the site to objects representing content. These objects may represent single files, or entire applications. The APM uses the site map to map application instances to particular URLs within a site. We call creating such a mapping mounting the application instance at a particular URL. The tutorial also showed how a given URL is translated into a physical file to serve using the site map. We'll repeat this description here, assuming that you have mounted an instance of Notes at the URL /notes as we did in the packages-example:

    • AOLserver receives your request for the URL /notes/somepage.

    • This URL is passed to the request processor.

    • The RP looks up the URL in the site map, and sees that the object mounted at that location is an instance of the notes application.

    • The RP asks the package manager where in the file system the Notes package lives. In the standard case, this would be ROOT/packages/notes.

    • The RP translates the URL to serve a page relative to the page root of the application, which is ROOT/packages/notes/www/. Therefore, the page that is finally served is ROOT/packages/notes/www/hello.html, which is what we wanted.

    What is missing from this description is a critical fact for application developers: In addition to working out what file to serve, the RP also stores information about which package instance the file belongs to into the AOLserver connection environment. The following ad_conn interfaces can be used to extract this information:

    [ad_conn package_url]

    If the URL refers to a package instance, this is the URL to the root of the tree where the package is mounted.

    [ad_conn package_id]

    If the URL refers to a package instance, this is the ID of that package instance.

    [ad_conn package_key]

    If the URL refers to a package instance, this is the unique key name of the package.

    [ad_conn extra_url]

    If we found the URL in the site map, this is the tail of the URL following the part that matched a site map entry.

    In the Notes example, we are particularly interested in the package_id field. If you study the data model and code, you'll see why. As we said before in the data modeling tutorial, the Notes application points the context_id of each Note object that it creates to the package instance that created it. That is, the context_id corresponds exactly to the package_id that comes in from the RP. This is convenient because it allows the administrator and the owner of the package to easily define access control policies for all the notes in a particular instance just my setting permissions on the package instance itself.

    The code for adding and editing notes, in notes/www/add-edit.tcl, shows how this works. At the top of the page, we extract the package_id and use it to do permission checks:

    
    set package_id [ad_conn package_id]
    
    if {[info exists note_id]} {
          permission::require_permission -object_id $note_id -privilege write
    
          set context_bar [ad_context_bar "Edit Note"]
    } else {
          permission::require_permission -object_id $note_id -privilege create
    
          set context_bar [ad_context_bar "New Note"]
    }
    
    

    This code figures out whether we are editing an existing note or creating a new one. It then ensures that we have the right privileges for each action.

    Later, when we actually create a note, the SQL that we run ensures that the context_id is set the right way:

    
    db_dml new_note {
      declare
        id integer;
      begin
        id := note.new(
          owner_id => :user_id,
          title => :title,
          body => :body,
          creation_user => :user_id,
          creation_ip => :peeraddr,
          context_id => :package_id
        );
      end;
    }
    
    

    The rest of this page makes calls to the form builder part of the template system. This API allows you to write forms-based pages without generating a lot of duplicated HTML in your pages. It also encapsulates most of the common logic that we use in dealing with forms, which we'll discuss next.

    Using Forms

    The forms API is pretty simple: You use calls in the template::form namespace in your Tcl script to create form elements. The final template page then picks this stuff up and lays the form out for the user. The form is set up to route submit buttons and whatnot back to the same Tcl script that set up the form, so your Tcl script will also contain the logic needed to process these requests.

    So, given this outline, here is a breakdown of how the forms code works in the add-edit.tcl page. First, we create a form object called new_note:

    
    template::form create new_note
    
    

    All the forms related code in this page will refer back to this object. In addition, the adp part of this page does nothing but display the form object:

    
    <master>
    
    @context_bar@
    
    <hr>
    
    <center>
    <formtemplate id="new_note"></formtemplate>
    </center>
    
    

    The next thing that the Tcl page does is populate the form with form elements. This code comes first:

    
    if {[template::form is_request new_note] && [info exists note_id]} {
    
      template::element create new_note note_id \
          -widget hidden \
          -datatype number \
          -value $note_id
    
      db_1row note_select {
        select title, body
        from notes
        where note_id = :note_id
      }
    }
    
    

    The if_request call returns true if we are asking the page to render the form for the first time. That is, we are rendering the form to ask the user for input. The tcl part of a form page can be called in 3 different states: the initial request, the initial submission, and the validated submission. These states reflect the typical logic of a forms based page in OpenACS:

    • First render the input form.

    • Next, control passes to a validation page that checks and confirms the inputs.

    • Finally, control passes to the page that performs the update in the database.

    The rest of the if condition figures out if we are creating a new note or editing an existing note. If note_id is passed to us from the calling page, we assume that we are editing an existing note. In this case, we do a database query to grab the data for the note so we can populate the form with it.

    The next two calls create form elements where the user can insert or edit the title and body of the Note. The interface to template::element is pretty straightforward.

    Finally, the code at the bottom of the page performs the actual database updates when the form is submitted and validated:

    
    if [template::form is_valid new_note] {
      set user_id [ad_conn user_id]
      set peeraddr [ad_conn peeraddr]
    
      if [info exists note_id] {
        db_dml note_update {
          update notes
          set title = :title,
              body = :body
          where note_id = :note_id
        }
      } else {
        db_dml new_note {
          declare
            id integer;
          begin
            id := note.new(
              owner_id => :user_id,
              title => :title,
              body => :body,
              creation_user => :user_id,
              creation_ip => :peeraddr,
              context_id => :package_id
            );
          end;
        }
      }
    
      ad_returnredirect "."
    }
    
    

    In this simple example, we don't do any custom validation. The nice thing about using this API is that the forms library handles all of the HTML rendering, input validation and database transaction logic on your behalf. This means that you can write pages without duplicating all of that code in every set of pages that uses forms.

    How it All Fits

    To watch all of this work, use the installer to update the Notes package with the new code that you grabbed out of CVS or the package repository, mount an instance of Notes somewhere in your server and then try out the user interface pages. It should become clear that in a real site, you would be able to, say, create a custom instance of Notes for every registered user, mount that instance at the user's home page, and set up the permissions so that the instance is only visible to that user. The end result is a site where users can come and write notes to themselves.

    This is a good example of the leverage available in the OpenACS 5.6.0 system. The code that we have written for Notes is not at all more complex than a similar application without access control or site map awareness. By adding a small amount of code, we have taken a small, simple, and special purpose application to something that has the potential to be a very useful, general-purpose tool, complete with multi-user features, access control, and centralized administration.

    Summary

    In OpenACS 5.6.0, application pages and scripts can be aware of the package instance, or subsite in which they are executing. This is a powerful general purpose mechanism that can be used to structure web services in very flexible ways.

    We saw how to use this mechanism in the Notes application and how it makes it possible to easily turn Notes into an application that appears to provide each user in a system with their own private notes database.

    We also saw how to use the templating system's forms API in a simple way, to create forms based pages with minimal duplication of code.

    ($Id: subsites.html,v 1.46 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/remote-postgres.html0000644000175000017500000000700311501005400024026 0ustar frankiefrankie Running a PostgreSQL database on another server

    Running a PostgreSQL database on another server

    To run a database on a different machine than the webserver requires changes to the database configuration file and access control file, and to the OpenACS service's configuration file.

    • Edit the database configuration file, which in a Reference install is located at /usr/local/pgsql/data/postgresql.conf and change

      #tcpip_socket = false

      to

      tcpip_socket = true
    • Change the access control file for the database to permit specific remote clients to access. Access can be controlled ... (add notes from forum post)

    • Change the OpenACS service's configuration file to point to the remote database. Edit /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl and change

      to

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/dev-guide.html0000644000175000017500000000640611501005400022546 0ustar frankiefrankie Chapter 10. Development Reference
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tcl-doc.html0000644000175000017500000004012611501005400022217 0ustar frankiefrankie Documenting Tcl Files: Page Contracts and Libraries

    Documenting Tcl Files: Page Contracts and Libraries

    By Jon Salz on 3 July 2000

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    • Tcl procedures: /packages/acs-kernel/tcl-documentation-procs.tcl

    The Big Picture

    In versions of the OpenACS prior to 3.4, the standard place to document Tcl files (both Tcl pages and Tcl library files) was in a comment at the top of the file:

    #
    # path from server home/filename
    #
    # Brief description of the file's purpose
    #
    # author's email address, file creation date
    #
    # $Id: tcl-doc.html,v 1.47 2010/12/11 23:36:32 ryang Exp $
    #
    

    In addition, the inputs expected by a Tcl page (i.e., form variables) would be enumerated in a call to ad_page_variables, in effect, documenting the page's argument list.

    The problem with these practices is that the documentation is only accessible by reading the source file itself. For this reason, ACS 3.4 introduces a new API for documenting Tcl files and, on top of that, a web-based user interface for browsing the documentation:

    • ad_page_contract: Every Tcl page has a contract that explicitly defines what inputs the page expects (with more precision than ad_page_variables) and incorporates metadata about the page (what used to live in the top-of-page comment). Like ad_page_variables, ad_page_contract also sets the specified variables in the context of the Tcl page.

    • ad_library: To be called at the top of every library file (i.e., all files in the /tcl/ directory under the server root and *-procs.tcl files under /packages/).

    This has the following benefits:

    • Facilitates automatic generation of human-readable documentation.

    • Promotes security, by introducing a standard and automated way to check inputs to scripts for correctness.

    • Allows graphical designers to determine easily how to customize sites' UIs, e.g., what properties are available in templates.

    • Allows the request processor to be intelligent: a script can specify in its contract which type of abstract document it returns, and the request processor can transform it automatically into something useful to a particular user agent. (Don't worry about this for now - it's not complete for ACS 3.4.)

    ad_page_contract

    Currently ad_page_contract serves mostly as a replacement for ad_page_variables. Eventually, it will be integrated closely with the documents API so that each script's contract will document precisely the set of properties available to graphical designers in templates. (Document API integration is subject to change, so we don't decsribe it here yet; for now, you can just consider ad_page_contract a newer, better, documented ad_page_variables.)

    Let's look at an example usage of ad_page_contract:

    
    # /packages/acs-kernel/api-doc/www/package-view.tcl
    ad_page_contract {
        version_id:integer
        public_p:optional
        kind
        { format "html" }
    } {
        Shows APIs for a particular package.
    
        @param version_id the ID of the version whose API to view.
        @param public_p view only public APIs?
        @param kind view the type of API to view. One of <code>procs_files</code>,
            <code>procs</code>, <code>content</code>, <code>types</code>, or
            <code>gd</code>.
        @param format the format for the documentation. One of <code>html</code> or <code>xml</code>.
    
        @author Jon Salz (jsalz@mit.edu)
        @creation-date 3 Jul 2000
        @cvs-id $Id: tcl-doc.html,v 1.47 2010/12/11 23:36:32 ryang Exp $
    }
    
    

    Note that:

    • By convention, ad_page_contract should be preceded by a comment line containing the file's path. The comment is on line 1, and the contract starts on line 2.

    • ad_page_contract's first argument is the list of expected arguments from the HTTP query (version_id, public_p, kind, and format). Like ad_page_variables, ad_page_contract sets the corresponding Tcl variables when the page is executed.

    • Arguments can have defaults, specified using the same syntax as in the Tcl proc (a two-element list where the first element is the parameter name and the second argument is the default value).

    • Arguments can have flags, specified by following the name of the query argument with a colon and one or more of the following strings (separated by commas):

      • optional: the query argument doesn't need to be provided; if it's not, the variable for that argument simply won't be set. For instance, if I call the script above without a public_p in the query, then in the page body [info exists public_p] will return 0.

      • integer: the argument must be an integer (ad_page_contract will fail and display and error if not). This flag, like the next, is intended to prevent clients from fudging query arguments to trick scripts into executing arbitrary SQL.

      • sql_identifier: the argument must be a SQL identifier (i.e., [string is wordchar $the_query_var] must return true).

      • trim: the argument will be [string trim]'ed.

      • multiple: the argument may be specified arbitrarily many times in the query string, and the variable will be set to a list of all those values (or an empty list if it's unspecified). This is analogous to the -multiple-list flag to ad_page_variables, and is useful for handling form input generated by <SELECT MULTIPLE> tags and checkboxes.

        For instance, if dest_user_id:multiple is specified in the contract, and the query string is

        
        ?dest_user_id=913&dest_user_id=891&dest_user_id=9
        
        

        then $dest_user_id is set to [list 913 891 9].

      • array: the argument may be specified arbitrarily many times in the query string, with parameter names with suffixes like _1, _2, _3, etc. The variable is set to a list of all those values (or an empty list if none are specified).

        For instance, if dest_user_id:array is specified in the contract, and the query string is

        
        ?dest_user_id_0=913&dest_user_id_1=891&dest_user_id_2=9
        
        

        then $dest_user_id is set to [list 913 891 9].

    • You can provide structured, HTML-formatted documentation for your contract. Note that format is derived heavily from Javadoc: a general description of the script's functionality, followed optionally by a series of named attributes tagged by at symbols (@). You are encouraged to provide:

      • A description of the functionality of the page. If the description contains more than one sentence, the first sentence should be a brief summary.

      • A @param tag for each allowable query argument. The format is

        
        @param parameter-name description...
        
        
      • An @author tag for each author. Specify the author's name, followed his or her email address in parentheses.

      • A @creation-date tag indicating when the script was first created.

      • A @cvs-id tag containing the page's CVS identification string. Just use $Id: tcl-documentation.html,v 1.2 2000/09/19 07:22:35 ron Exp $ when creating the file, and CVS will substitute an appropriate string when you check the file in.

      These @ tags are optional, but highly recommended!

    ad_library

    ad_library provides a replacement for the informal documentation (described above) found at the beginning of every Tcl page. Instead of:

    
    # /packages/acs-kernel/00-proc-procs.tcl
    #
    # Routines for defining procedures and libraries of procedures (-procs.tcl files).
    #
    # jsalz@mit.edu, 7 Jun 2000
    #
    # $Id: tcl-doc.html,v 1.47 2010/12/11 23:36:32 ryang Exp $
    
    

    you'll now write:

    
    # /packages/acs-kernel/00-proc-procs.tcl
    ad_library {
    
        Routines for defining procedures and libraries of procedures (<code>-procs.tcl</code>
        files).
    
        @creation-date 7 Jun 2000
        @author Jon Salz (jsalz@mit.edu)
        @cvs-id $Id: tcl-doc.html,v 1.47 2010/12/11 23:36:32 ryang Exp $
    
    }
    
    

    Note that format is derived heavily from Javadoc: a general description of the script's functionality, followed optionally by a series of named attributes tagged by at symbols (@). HTML formatting is allowed. You are encouraged to provide:

    • An @author tag for each author. Specify the author's name, followed his or her email address in parentheses.

    • A @creation-date tag indicating when the script was first created.

    • A @cvs-id tag containing the page's CVS identification string. Just use $Id: tcl-documentation.html,v 1.2 2000/09/19 07:22:35 ron Exp $ when creating the file, and CVS will substitute an appropriate string when you check the file in.

    ($Id: tcl-doc.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/security-requirements.html0000644000175000017500000001544711501005400025272 0ustar frankiefrankie Security Requirements

    Security Requirements

    By Richard Li

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    This document lists the requirements for the security system for the OpenACS.

    Vision Statement

    Virtually all web sites support personalized content based on user identity. The level of personalization may be as simple as displaying the name of the user on certain pages or can be as sophisticated as dynamically recommending sections of site that the user may be interested in based on prior browsing history. In any case, the user's identity must be validated and made available to the rest of the system. In addition, sites such as ecommerce vendors require that the user identity be securely validated.

    Security System Overview

    The security system consists of a number of subsystems.

    Signed Cookies

    Cookies play a key role in storing user information. However, since they are stored in plaintext on a user's system, the validity of cookies is an important issue in trusting cookie information. Thus, we want to be able to validate a cookie, but we also want to validate the cookie without a database hit.

    • 10.0 Guaranteed Tamper Detection Any tampering of cookie data should be easily detectable by the web server.

    • 10.1 Performance and Scalability Validation and verification of the cookie should be easily scalable and should not require a database query on every hit.

    Session Properties

    Applications should be able to store session-level properties in a database table.

    • 11.0 Storage API Session-level data should be accessible via an API.

    • 11.1 Purge Mechanism An efficient pruning mechanism should be used to prevent old session level properties from filling up the table.

    Login

    The security system should support the concept of persistent user logins. This persistence takes several forms.

    • 12.0 Permanent Login Users should be able to maintain a permanent user login so that they never need to type their password.

    • 12.1 Session Login The security system should support the concept of a session, with authentication tokens that become invalid after a certain period of time.

    • 12.2 Session Definition A session is a sequence of clicks by one user from one browser in which no two clicks are separated by more than some constant (the session timeout).

    • 12.3 Stateless The security system should not require state that is stored in the server. Required state may reside only in the user request (including cookies), and in the database. A single user should be able to log in to the system even if the user is sent to a different AOLserver for each step of the login process (e.g., by a load balancer).

    • 12.4 Secure The security system should not store passwords in clear text in the database.

    • 13.0 SSL Hardware The system must work when the SSL processing occurs outside of the web server (in specialized hardware, in a firewall, etc.).

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-css-layout.html0000644000175000017500000001131511501005400024634 0ustar frankiefrankie Laying out a page with CSS instead of tables

    Laying out a page with CSS instead of tables

    .LRN home page with table-based layout

    A sample of the HTML code (full source)

    <table border="0" width="100%">
      <tr>
        <td valign="top" width="50%">
          <table class="element" border=0 cellpadding="0" cellspacing="0" width="100%">
            <tr> 
              <td colspan=3 class="element-header-text">
                <bold>Groups</bold>
             </td>
           </tr>
           <tr>
             <td colspan=3 class="dark-line" height="0"><img src="/resources/acs-subsite/spacer.gif"></td></tr>
              <tr>
                <td class="light-line" width="1">
                  <img src="/resources/acs-subsite/spacer.gif" width="1">
                </td>
                <td class="element-text" width="100%">
                <table cellspacing="0" cellpadding="0" class="element-content" width="100%">
                  <tr>
                    <td>
                      <table border="0" bgcolor="white" cellpadding="0" cellspacing="0" width="100%">
                        <tr>
                          <td class=element-text>
                            MBA 101

    .LRN Home with CSS-based layout

    A sample of the HTML code (full source)

    <div class="left">
      <div class="portlet-wrap-shadow">
        <div class="portlet-wrap-bl">
          <div class="portlet-wrap-tr">
            <div class="portlet">
              <h2>Groups</h2>
              <ul>
                <li>
                  <a href="#">Class MBA 101</a>

    If the CSS is removed from the file, it looks somewhat different:

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-database.html0000644000175000017500000002340411501005400024277 0ustar frankiefrankie Setting Up Database Objects

    Setting Up Database Objects

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Code the data model

    We create all database objects with scripts in the myfirstpackage/sql/ directory. All database scripts are database-specific and are thus in either the myfirstpackage/sql/oracle or myfirstpackage/sql/postgresql directory. Packages can support Oracle, PostgreSQL, or both. In this tutorial, we will be working with PostgreSQL

    The first file will be myfirstpackage-create.sql. The package manager requires a file with the name packagekey-create.sql, which it will run automatically when the package in installed. This file should create all tables and views.

    Our package is going to store all of its information in one table. It takes more than just a CREATE TABLE command, however, because we want to integrate our table with the OpenACS system. By making each record in our table an OpenACS object, we gain access to the permissions system and to services that integrate with OpenACS objects, such as general-comments and notification. The cost is that our table creation code must include several functions, stored procedures, and is complicated (even for simple tables).

    There are many kinds of OpenACS objects in the system. (You can see them with the psql code: select object_type from acs_object_types;.) One such object is the content_item, which is part of the content repository system. To use it, we will make our data objects children of the content_revision object, which is a child of content_item. Not only will we gain the benefits of both OpenACS Objects and content objects, we can also use some content repository functions to simplify our database creation. (More information about ACS Objects. More information about the Content Repository.)

    Figure 8.2. Tutorial Data Model

    Tutorial Data Model

    The top of each sql file has some standard comments, including doc tags such as @author which will be picked up by the API browser. The string $Id: tutorial-database.html,v 1.42 2010/12/11 23:36:32 ryang Exp $ will automatically be expanded when the file is checked in to cvs.

    [$OPENACS_SERVICE_NAME ~]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/sql/postgresql
    [$OPENACS_SERVICE_NAME postgresql]$ emacs myfirstpackage-create.sql

    Paste the text below into the file, save, and close.

    Figure 8.3. The Database Creation Script

    -- creation script
    --
    -- @author joel@aufrecht.org
    -- @cvs-id &Id:$
    --
    
    select content_type__create_type(
        'mfp_note',                    -- content_type
        'content_revision',            -- supertype
        'MFP Note',                    -- pretty_name,
        'MFP Notes',                   -- pretty_plural
        'mfp_notes',                   -- table_name
        'note_id',                     -- id_column
        null                           -- name_method
    );
    
    -- necessary to work around limitation of content repository:
    select content_folder__register_content_type(-100,'mfp_note','t');
    

    The creation script calls a function in PL/pgSQL (PL/pgSQL is a procedural language extention to sql), content_type__create_type, which in turn creates the necessary database changes to support our data object. Notice the use of "mfp." This is derived from "My First Package" and ensures that our object is unlikely to conflict with objects from other packages.

    Create a database file to drop everything if the package is uninstalled.

    [$OPENACS_SERVICE_NAME postgresql]$ emacs myfirstpackage-drop.sql

    Figure 8.4. Database Deletion Script

    -- drop script
    --
    -- @author joel@aufrecht.org
    -- @cvs-id &Id:$
    --
    select content_folder__unregister_content_type(-100,'mfp_note','t');
    
    select content_type__drop_type(
    	   'mfp_note',
    	   't',
    	   't'
        );
    

    (like the creation script the drop script calls a PL/pgSQL function: content_type__drop_type

    Run the create script manually to add your tables and functions.

    [$OPENACS_SERVICE_NAME postgresql]$ psql service0 -f myfirstpackage-create.sql
    psql:myfirstpackage-create.sql:15: NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'mfp_notes_pkey' for table 'mfp_notes'
    psql:myfirstpackage-create.sql:15: NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
     content_type__create_type
    ---------------------------
                             0
    (1 row)
    
    [$OPENACS_SERVICE_NAME postgresql]$

    If there are errors, use them to debug the sql file and try again. If there are errors in the database table creation, you may need to run the drop script to drop the table so that you can recreate it. The drop script will probably have errors since some of the things it's trying to drop may be missing. They can be ignored.

    Once you get the same output as shown above, test the drop script:

    [$OPENACS_SERVICE_NAME postgresql]$ psql service0 -f myfirstpackage-drop.sql
    
     content_type__drop_type
    -------------------------
                           0
    (1 row)
    
    [$OPENACS_SERVICE_NAME postgresql]$

    Once both scripts are working without errors, run the create script one last time and proceed.

    [$OPENACS_SERVICE_NAME postgresql]$ psql service0 -f myfirstpackage-create.sql
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/security-notes.html0000644000175000017500000001246611501005400023675 0ustar frankiefrankie Security Notes

    Security Notes

    By Richard Li

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    The security system was designed for security. Thus, decisions requiring trade-offs between ease-of-use and security tend to result in a system that may not be as easy to use but is more secure.

    HTTPS and the sessions system

    If a user switches to HTTPS after logging into the system via HTTP, the user must obtain a secure token. To insure security, the only way to obtain a secure token in the security system is to authenticate yourself via password over an HTTPS connection. Thus, users may need to log on again to a system when switching from HTTP to HTTPS. Note that logging on to a system via HTTPS gives the user both insecure and secure authentication tokens, so switching from HTTPS to HTTP does not require reauthentication.

    This method of authentication is important in order to establish, in as strong a manner as possible, the identity of the owner of the secure token. In order for the security system to offer stronger guarantees of someone who issues a secure token, the method of authentication must be as strong as the method of transmission.

    If a developer truly does not want such a level of protection, this system can be disabled via source code modification only. This can be accomplished by commenting out the following lines in the sec_handler procedure defined in security-procs.tcl:

    
        if { [ad_secure_conn_p] && ![ad_login_page] } {
            set s_token_cookie [ns_urldecode [ad_get_cookie "ad_secure_token"]]
            
            if { [empty_string_p $s_token_cookie] || [string compare $s_token_cookie [lindex [sec_get_session_info $session_id] 2]] != 0 } {
            # token is incorrect or nonexistent, so we force relogin.
            ad_returnredirect "/register/index?return_url=[ns_urlencode [ad_conn url]?[ad_conn query]]"
            }
        }
    
    

    The source code must also be edited if the user login pages have been moved out of an OpenACS system. This information is contained by the ad_login_page procedure in security-procs.tcl:

    
    ad_proc -private ad_login_page {} {
        
        Returns 1 if the page is used for logging in, 0 otherwise. 
    
    } {
    
        set url [ad_conn url]
        if { [string match "*register/*" $url] || [string match "/index*" $url] } {
        return 1
        }
    
        return 0
    }
    
    

    The set of string match expressions in the procedure above should be extended appropriately for other registration pages. This procedure does not use ad_parameter or regular expressions for performance reasons, as it is called by the request processor.

    ($Id: security-notes.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/database-management.html0000644000175000017500000000556711501005400024562 0ustar frankiefrankie Chapter 7. Database Management

    Chapter 7. Database Management

    By Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-next-nightly-vacuum.html0000644000175000017500000000720411501005400026266 0ustar frankiefrankie Vacuum Postgres nightly

    Vacuum Postgres nightly

    The "vacuum" command must be run periodically to reclaim space in versions of PostgreSQL before 7.4. The "vacuum analyze" form additionally collects statistics on the disbursion of columns in the database, which the optimizer uses when it calculates just how to execute queries. The availability of this data can make a tremendous difference in the execution speed of queries. This command can also be run from cron, but it probably makes more sense to run this command as part of your nightly backup procedure - if "vacuum" is going to screw up the database, you'd prefer it to happen immediately after (not before!) you've made a backup! The "vacuum" command is very reliable, but conservatism is the key to good system management. So, if you're using the export procedure described above, you don't need to do this extra step.

    Edit your crontab:

    [joeuser ~]$ crontab -e

    We'll set vacuum up to run nightly at 1 AM. Add the following line:

    0 1 * * * /usr/local/pgsql/bin/vacuumdb $OPENACS_SERVICE_NAME
    ($Id: install-next-nightly-vacuum.html,v 1.21 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-advanced.html0000644000175000017500000001146211501005400024301 0ustar frankiefrankie Chapter 9. Advanced Topics

    Chapter 9. Advanced Topics

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This tutorial covers topics which are not essential to creating a minimal working package. Each section can be used independently of all of the others; all sections assume that you've completed the basic tutorial.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n.html0000644000175000017500000000625511501005400021456 0ustar frankiefrankie Chapter 13. Internationalization

    Chapter 13. Internationalization

    By Peter Marklund and Lars Pind

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/upgrade-5-0-dot.html0000644000175000017500000001046111501005400023403 0ustar frankiefrankie Upgrading an OpenACS 5.0.0 or greater installation

    Upgrading an OpenACS 5.0.0 or greater installation

    • Upgrading a stock site. If you have no custom code, and your site is not in a CVS repository, upgrade with these steps:

      1. Go to /acs-admin/install/ and click "Upgrade Your System" in "Install from OpenACS Repository"

      2. Select all of the packages you want to upgrade and proceed

      3. After upgrade is complete, restart the server as indicated.

      4. If you are using locales other than en_US, go to acs-lang/admin and "Import all Messages" to load the new translated messages. Your local translations, if any, will take precedence over imported translations.

    • Upgrading a Custom or CVS site. If you have custom code, and your site is in a CVS repository, upgrade with these steps:

      1. Upgrade the file system for all packages in use. Upgrading the OpenACS files

      2. Go to /acs-admin/install/ and click "Upgrade Your System" in "Install from local file system"

      3. Select all of the packages you want to upgrade and proceed

      4. After upgrade is complete, restart the server as indicated.

      5. If you are using locales other than en_US, go to acs-lang/admin and "Import all Messages" to load the new translated messages. Your local translations, if any, will take precedence over imported translations.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/eng-standards-versioning.html0000644000175000017500000002711211501005400025605 0ustar frankiefrankie Release Version Numbering

    Release Version Numbering

    ($Id: eng-standards-versioning.html,v 1.49 2010/12/11 23:36:32 ryang Exp $)

    By Ron Henderson, Revised by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    OpenACS version numbers help identify at a high-level what is in a particular release and what has changed since the last release.

    A "version number" is really just a string of the form:

    major.minor.dot[ milestone ]

    • A major number change indicates a fundamental change in the architecture of the system, e.g. OpenACS 3 to ACS 4. A major change is required if core backwards compatibility is broken, if upgrade is non-trivial, or if the platform changes substantially.

    • A minor change represents the addition of new functionality or changed UI.

    • A dot holds only bug fixes and security patches. Dot releases are always recommended and safe.

    • A milestone marker indicates the state of the release:

      • d, for development, means the release is in active development and is not in its intended released form.

      • a, for alpha, means new development is complete and code checkins are frozen. Alpha builds should work well enough to be testable.

      • b, for beta, means most severe bugs are fixed and end users can start trying the release.

      • Release Candidate builds (rc) are believed to meet all of the criteria for release and can be installed on test instances of production systems.

      • Final releases have no milestone marker. (Exception: In CVS, they are tagged with -final to differentiate them from branch tags.)

      Milestone markers are numbered: d1, d2, ..., a1, b1, rc1, etc.

    A complete sequence of milestones between two releases:

    5.0.0
    5.0.0rc2
    5.0.0rc1
    5.0.0b4
    5.0.0b1
    5.0.0a4
    5.0.0a3
    5.0.0a1
    5.0.0d1
    4.6.3

    Version numbers are also recorded in the CVS repository so that the code tree can be restored to the exact state it was in for a particular release. To translate between a distribution tar file (acs-3.2.2.tar.gz) and a CVS tag, just swap '.' for '-'.The entire release history of the toolkit is recorded in the tags for the top-level readme.txt file:

    > cvs log readme.txt
    RCS file: /usr/local/cvsroot/acs/readme.txt,v
    Working file: readme.txt
    head: 3.1
    branch:
    locks: strict
    access list:
    symbolic names:
    	acs-4-0: 3.1.0.8
    	acs-3-2-2-R20000412: 3.1
    	acs-3-2-1-R20000327: 3.1
    	acs-3-2-0-R20000317: 3.1
    	acs-3-2-beta: 3.1
    	acs-3-2: 3.1.0.4
    	acs-3-1-5-R20000304: 1.7.2.2
    	acs-3-1-4-R20000228: 1.7.2.2
    	acs-3-1-3-R20000220: 1.7.2.2
    	acs-3-1-2-R20000213: 1.7.2.1
    	acs-3-1-1-R20000205: 1.7.2.1
    	acs-3-1-0-R20000204: 1.7
    	acs-3-1-beta: 1.7
    	acs-3-1-alpha: 1.7
    	acs-3-1: 1.7.0.2
    	v24: 1.5
    	v23: 1.4
    	start: 1.1.1.1
    	arsdigita: 1.1.1
    keyword substitution: kv
    total revisions: 13;	selected revisions: 13
    description:
    ...
    

    In the future, OpenACS packages should follow this same convention on version numbers.

    Transition Rules

    So what distinguishes an alpha release from a beta release? Or from a production release? We follow a specific set of rules for how OpenACS makes the transition from one state of maturity to the next. These rules are fine-tuned with each release; an example is 5.0.0 Milestones and Milestone Criteria

    Package Maturity

    Each package has a maturity level. Maturity level is recorded in the .info file for each major-minor release of OpenACS, and is set to the appropriate value for that release of the package.

        <version ...>
            <provides .../>
            <requires .../>
            <maturity>1</maturity>
            <callbacks>
                ...
        
    • Level -1: Incompatible. This package is not supported for this platform and should not be expected to work.

    • Level 0: New Submission. This is the default for packages that do not have maturity explicitly set, and for new contributions. The only criterion for level 0 is that at least one person asserts that it works on a given platform.

    • Level 1: Immature. Has no open priority 1 or priority 2 bugs. Has been installed by at least 10? different people, including 1 core developer. Has been available in a stable release for at least 1 month. Has API documentation.

    • Level 2: Mature. Same as Level 1, plus has install guide and user documentation; no serious deviations from general coding practices; no namespace conflicts with existing level 2 packages.

    • Level 3: Mature and Standard. Same as level 2, plus meets published coding standards; is fully internationalized; available on both supported databases.

    Naming Database Upgrade Scripts

    Database upgrade scripts must be named very precisely in order for the Package Manager to run the correct script at the correct time.

    1. Upgrade scripts should be named /packages/myfirstpackage/sql/postgresql/upgrade/upgrade-OLDVERSION-NEWVERSION.sql

    2. If the version you are working on is a later version than the current released version, OLDVERSION should be the current version. The current version is package version in the APM and in /packages/myfirstpackage/myfirstpackage.info. So if forums is at 2.0.1, OLDVERSION should be 2.0.1d1. Note that this means that new version development that includes an upgrade must start at d2, not d1.

    3. If you are working on a pre-release version of a package, use the current package version as OLDVERSION. Increment the package version as appropriate (see above) and use the new version as NEWVERSION. For example, if you are working on 2.0.1d3, make it 2.0.1d4 and use upgrade-2.0.1d3-2.0.1d4.sql.

    4. Database upgrades should be confined to development releases, not alpha or beta releases.

    5. Never use a final release number as a NEWVERSION. If you do, then it is impossible to add any more database upgrades without incrementing the overall package version.

    6. Use only the d, a, and b letters in OLDVERSION and NEWVERSION. rc is not supported by OpenACS APM.

    7. The distance from OLDVERSION to NEWVERSION should never span a release. For example if we had a bug fix in acs-kernel on 5.1.0 you wouldn't want a file upgrade-5.0.4-5.1.0d1.sql since if you subsequently need to provide a 5.0.4-5.0.5 upgrade you will have to rename the 5.0.4-5.1.0 upgrade since you can't have upgrades which overlap like that. Instead, use upgrade-5.1.0d1-5.1.0d2.sql

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-html-email.html0000644000175000017500000000723311501005400024566 0ustar frankiefrankie Sending HTML email from your application

    Sending HTML email from your application

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Sending email is fairly simple using the acs-mail-lite package. Sending HTML email is only slightly more complicated.

        set subject "my subject"
    
        set message "<b>Bold</b> not bold"
    
        set from_addr "me@myemail.com"
    
        set to_addr "me@myemail.com"
    
        # the from to html closes any open tags.
        set message_html [ad_html_text_convert -from html -to html $message]
    
        # some mailers chop off the last few characters.
        append message_html "   "
        set message_text [ad_html_text_convert -from html -to text $message]
            
        set message_data [build_mime_message $message_text $message_html]
        
        set extra_headers [ns_set new]
    
        ns_set put $extra_headers MIME-Version [ns_set get $message_data MIME-Version]
        ns_set put $extra_headers Content-ID [ns_set get $message_data Content-ID]
        ns_set put $extra_headers Content-Type [ns_set get $message_data Content-Type]
        set message [ns_set get $message_data body]
        
        acs_mail_lite::send \
            -to_addr $to_addr \
            -from_addr $from_addr \
            -subject $subject \
            -body $message \
            -extraheaders $extra_headers
        
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-pages.html0000644000175000017500000002456611501005400023644 0ustar frankiefrankie Creating Web Pages

    Creating Web Pages

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Install some API

    As a workaround for missing content-repository functionality, copy a provided file into the directory for tcl files:

        cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/tutorial/note-procs.tcl /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/

    To make this file take effect, go to the APM and choose "Reload changed" for "MyFirstPackage".

    Page Map

    Our package will have two visible pages. The first shows a list of all objects; the second shows a single object in view or edit mode, and can also be used to add an object. The index page will display the list, but since we might reuse the list later, we'll put it in a seperate file and include it on the index page.

    Figure 8.5. Page Map

    Page Map

    Build the "Index" page

    Each user-visible page in your package has, typically, three parts. The tcl file holds the procedural logic for the page, including TCL and database-independent SQL code, and does things like check permissions, invoke the database queries, and modify variables, and the adp page holds html. The -postgres.xql and -oracle.xql files contains database-specific SQL. The default page in any directory is index, so we'll build that first, starting with the tcl file:

    [$OPENACS_SERVICE_NAME postgresql]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackages/www
    [$OPENACS_SERVICE_NAME www]$ emacs index.tcl

    Paste this into the file.

    ad_page_contract {
        This is the main page for the package.  It displays all of the Notes and provides links to edit them and to create new Notes.
    
        @author Your Name (you@example.com)
        @cvs-id $Id: tutorial-pages.html,v 1.42 2010/12/11 23:36:32 ryang Exp $
    }
    
    set page_title [ad_conn instance_name]
    set context [list]

    Now index.adp:

    <master>
      <property name="title">@page_title;noquote@</property>
      <property name="context">@context;noquote@</property>
    <include src="/packages/myfirstpackage/lib/note-list">

    The index page includes the list page, which we put in /lib instead of /www to designate that it's available for reuse by other packages.

    [$OPENACS_SERVICE_NAME www]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/lib
    [$OPENACS_SERVICE_NAME www]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/lib
    [$OPENACS_SERVICE_NAME lib]$ emacs note-list.tcl
    template::list::create \
        -name notes \
        -multirow notes \
        -actions { "Add a Note" note-edit} \
        -elements {
    	edit {
    	    link_url_col edit_url
    	    display_template {
    		<img src="/resources/acs-subsite/Edit16.gif" width="16" height="16" border="0">
    	    }
    	    sub_class narrow
    	}
    	title {
    	    label "Title"
    	}
    	delete {
    	    link_url_col delete_url 
    	    display_template {
    		<img src="/resources/acs-subsite/Delete16.gif" width="16" height="16" border="0">
    	    }
    	    sub_class narrow
    	}
        }
    
    db_multirow \
        -extend {
    	edit_url
    	delete_url
        } notes notes_select {
    	select ci.item_id,
    	       n.title
            from   cr_items ci,
                   mfp_notesx n
            where  n.revision_id = ci.live_revision
        } {
    	set edit_url [export_vars -base "note-edit" {item_id}]
    	set delete_url [export_vars -base "note-delete" {item_id}]
        }
    [$OPENACS_SERVICE_NAME lib]$ emacs note-list.adp
    <listtemplate name="notes"></listtemplate>

    You can test your work by viewing the page.

    Create the add/edit page. If note_id is passed in, it display that note, and can change to edit mode if appropriate. Otherwise, it presents a form for adding notes.

    [$OPENACS_SERVICE_NAME lib]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www
    [$OPENACS_SERVICE_NAME www]$ emacs note-edit.tcl
    ad_page_contract {
        This is the view-edit page for notes.
    
        @author Your Name (you@example.com)
        @cvs-id $Id: tutorial-pages.html,v 1.42 2010/12/11 23:36:32 ryang Exp $
     
        @param item_id If present, assume we are editing that note.  Otherwise, we are creating a new note.
    } {
        item_id:integer,optional
    }
    
    ad_form -name note -form {
        {item_id:key}
        {title:text {label Title}}
    } -new_request {
        auth::require_login
        permission::require_permission -object_id [ad_conn package_id] -privilege create
        set page_title "Add a Note"
        set context [list $page_title]
    } -edit_request {
        auth::require_login
        permission::require_write_permission -object_id $item_id
        mfp::note::get \
    	-item_id $item_id \
    	-array note_array 
    
        set title $note_array(title)
    
        set page_title "Edit a Note"
        set context [list $page_title]
    } -new_data {
        mfp::note::add \
    	-title $title
    } -edit_data {
        mfp::note::edit \
    	-item_id $item_id \
    	-title $title
    } -after_submit {
        ad_returnredirect "."
        ad_script_abort
    }
    [$OPENACS_SERVICE_NAME www]$ emacs note-edit.adp
    <master>
      <property name="title">@page_title;noquote@</property>
      <property name="context">@context;noquote@</property>
      <property name="focus">note.title</property>
      
    <formtemplate id="note"></formtemplate>

    And the delete page. Since it has no UI, there is only a tcl page, and no adp page.

    [$OPENACS_SERVICE_NAME www]$ emacs note-delete.tcl
    ad_page_contract {
        This deletes a note
    
        @author Your Name (you@example.com)
        @cvs-id $Id: tutorial-pages.html,v 1.42 2010/12/11 23:36:32 ryang Exp $
     
        @param item_id The item_id of the note to delete
    } {
        item_id:integer
    }
    
    permission::require_write_permission -object_id $item_id
    set title [item::get_title $item_id]
    mfp::note::delete -item_id $item_id
    
    ad_returnredirect "."
    # stop running this code, since we're redirecting
    abort
    
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/oracle.html0000644000175000017500000020510711501005400022141 0ustar frankiefrankie Install Oracle 8.1.7

    Install Oracle 8.1.7

    By Vinod Kurup

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    If you are installing PostGreSQL instead of Oracle, skip this section.

    OpenACS 5.6.0 will install with Oracle 9i but has not been extensively tested so may still have bugs or tuning issues. See Andrew Piskorski's Oracle 9i notes for guidance.

    This installation guide attempts to present all of the information necessary to complete an OpenACS installation. We try hard to make all of the steps possible in one pass, rather than having a step which amounts to "go away and develop a profound understanding of software X and then come back and, in 99% of all cases, type these two lines." The exception to our rule is Oracle production systems. This page describes a set of steps to get a working Oracle development server, but it is unsuitable for production systems. If you will be using OpenACS on Oracle in a production environment, you will experience many problems unless you develop a basic understanding of Oracle which is outside the scope of this document. T

    This document assumes that you'll be installing Oracle on the same box as AOLserver. For more details on a remote Oracle installation, see Daryl Biberdorf's document.

    Useful links to find help on how to set up Oracle under Linux are:

    Acquire Oracle

    Production Oracle systems should run on certified platforms. Follow the metalink note 223718.1to find certified platforms. If you don't have metalink access, take a look at the Oracle on Linux FAQ: Which Linux Distributions Are Directly Supported By Oracle?. In summary, free and inexpensive Linux distributions are not certified.

    If you don't have an account at OTN get one: you can download the Oracle software from the Oracle Downloads page. It is also get the CDs shipped to you for a nominal fee from the Oracle Store.

    Each Oracle release comes with extensive and usually quite well-written documentation. Your first step should be to thoroughly read the release notes for your operating system and your Oracle version. Find the docs here:

    It is generally useful to run a particular Oracle version with its latest patchset. At the time of writing these were 8.1.7.4 and 9.2.0.5, both of which are considered to be very stable.

    To be able to download a patchset, you need a (to-pay-for) account on Metalink. You may find the appropriate patchset by following Andrew's suggestion.

    Things to Keep in Mind

    Oracle is very well-documented software, the online documentation comes with printable PDFs and full-text search. Altogether there is more than 20.000 pages of documentation, so do not expect to understand Oracle within in a few hours. The best starting pointing into Oracle is the Concepts book. Here's the 8i version and the 9.2 version.

    To give you an idea of how configurable Oracle is and how much thought you may need to put into buying the proper hardware and creating a sane setup, you should thoroughly read Cary Millsap's Configuring Oracle Server for VLDB and the Optimal Flexible Architecture standard.

    Throughout these instructions, we will refer to a number of configurable settings and advise certain defaults. With the exception of passwords, we advise you to follow these defaults unless you know what you are doing. Subsequent documents will expect that you used the defaults, so a change made here will necessitate further changes later. For a guide to the defaults, please see Defaults.

    In order for OpenACS to work properly you need to set the environment appropriately.

    export ORACLE_BASE=/ora8/m01/app/oracle
    export ORACLE_HOME=$ORACLE_BASE/product/8.1.7
    export PATH=$PATH:$ORACLE_HOME/bin
    export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
    export ORACLE_SID=ora8
    export ORACLE_TERM=vt100
    export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
    
    umask 022
    open_cursors = 500
    nls_date_format = "YYYY-MM-DD"

    For additional resources/documentation, please see this thread and Andrew Piskorski's mini-guide.

    Pre-Installation Tasks

    Though Oracle 8.1.7 has an automated installer, we still need to perform several manual, administrative tasks before we can launch it. You must perform all of these steps as the root user. We recommend entering the X window system as a normal user and then doing a su -. This command gives you full root access.

    • Login as a non-root user and start X by typing startx

      [joeuser ~]$ startx

    • Open a terminal window type and login as root

      [joeuser ~]$ su -
      Password: ***********
      [root ~]#

    • Create and setup the oracle group and oracle account

      We need to create a user oracle, which is used to install the product, as well as starting and stopping the database.

      [root ~]# groupadd dba
      [root ~]# groupadd oinstall
      [root ~]# groupadd oracle
      [root ~]# useradd -g dba -G oinstall,oracle -m oracle
      [root ~]# passwd oracle

      You will be prompted for the New Password and Confirmation of that password.

    • Setup the installation location for Oracle. While Oracle can reside in a variety of places in the file system, OpenACS has adopted /ora8 as the base directory.

      Note: the Oracle install needs about 1 GB free on /ora8 to install successfully.

      [root ~]# mkdir /ora8
      root:/ora8# cd /ora8
      root:/ora8# mkdir -p m01 m02 m03/oradata/ora8
      root:/ora8# chown -R oracle.dba /ora8
      root:/ora8# exit
    • Set up the oracle user's environment

      • Log in as the user oracle by typing the following:

        [joeuser ~]$ su - oracle
        Password: ********
      • Use a text editor to edit the .bash_profile file in the oracle account home directory.

        [oracle ~]$ emacs .bash_profile

        You may get this error trying to start emacs:

        Xlib: connection to ":0.0" refused by server
        Xlib: Client is not authorized to connect to Server
        emacs: Cannot connect to X server :0.
        Check the DISPLAY environment variable or use `-d'.
        Also use the `xhost' program to verify that it is set to permit
        connections from your machine.

        If so, open a new terminal window and do the following:

        [joeuser ~]$ xhost +localhost

        Now, back in the oracle terminal:

        [oracle ~]$ export DISPLAY=localhost:0.0
        [oracle ~]$ emacs .bash_profile

        Try this procedure anytime you get an Xlib connection refused error.

      • Add the following lines (substituting your Oracle version number as needed) to .bash_profile:

        export ORACLE_BASE=/ora8/m01/app/oracle
        export ORACLE_HOME=$ORACLE_BASE/product/8.1.7
        export PATH=$PATH:$ORACLE_HOME/bin
        export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib
        export ORACLE_SID=ora8
        export ORACLE_TERM=vt100
        export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
        
        umask 022

        Save the file by typing CTRL-X CTRL-S and then exit by typing CTRL-X CTRL-C. Alternatively, use the menus.

      Make sure that you do not add any lines like the following

      # NLS_LANG=american
      # export NLS_LANG

      These lines will change the Oracle date settings and will break OpenACS since OpenACS depends on the ANSI date format, YYYY-MM-DD dates.

    • Log out as oracle

      [oracle ~]$ exit
    • Log back in as oracle and double check that your environment variables are as intended. The env command lists all of the variables that are set in your environment, and grep shows you just the lines you want (those with ORA in it).

      [joeuser ~]$ su - oracle
      [oracle ~]$ env | grep ORA

      If it worked, you should see:

      ORACLE_SID=ora8
      ORACLE_BASE=/ora8/m01/app/oracle
      ORACLE_TERM=vt100
      ORACLE_HOME=/ora8/m01/app/oracle/product/8.1.7
      ORA_NLS33=/ora8/m01/app/oracle/product/8.1.7/ocommon/nls/admin/data

      If not, try adding the files to ~/.bashrc instead of .bash_profile. Then logout and log back in again. Also, be certain you are doing su - oracle and not just su oracle. The - means that .bashrc and .bash_profile will be evaluated.

      Make sure that /bin, /usr/bin, and /usr/local/bin are in your path by typing:

      [oracle ~]$ echo $PATH
      /bin:/usr/bin:/usr/local/bin:/usr/bin/X11:/usr/X11R6/bin:/home/oracle/bin:/ora8/m01/app/oracle/product/8.1.7/bin

      If they are not, then add them to the .bash_profile by changing the PATH statement above to PATH=$PATH:/usr/local/bin:$ORACLE_HOME/bin

    Installing Oracle 8.1.7 Server

    • Log in as oracle and start X if not already running. Start a new terminal:

      [joeuser ~]$ xhost +localhost
      [joeuser ~]$ su - oracle
      Password: **********
      [oracle ~]$ export DISPLAY=localhost:0.0
    • Find the runInstaller script

      • If you are installing Oracle from a CD-ROM, it is located in the install/linux path from the cd-rom mount point

        [oracle ~]$ su - root
        [root ~]# mount -t iso9660 /dev/cdrom /mnt/cdrom
        [root ~]# exit
        [oracle ~]$ cd /mnt/cdrom
      • If you are installing from the tarball, the install script is located in the Oracle8iR2 directory that was created when you expanded the archive.

        [oracle ~]$ cd /where/oracle/Disk1

      Check to make sure the file is there.

      oracle:/where/oracle/Disk1$ ls
      doc  index.htm  install  runInstaller  stage  starterdb

      If you don't see runInstaller, you are in the wrong directory.

    • Run the installer

      oracle:/where/oracle/Disk1$ ./runInstaller

      A window will open that welcomes you to the 'Oracle Universal Installer' (OUI). Click on "Next"

      Note

      Some people have had trouble with this step on RedHat 7.3 and 8.0. If so, try the following steps before calling ./runInstaller:

      1. Execute the following command: /usr/i386-glibc21-linux/bin/i386-glibc21-linux-env.sh

      2. Type export LD_ASSUME_KERNEL=2.2.5

    • The "File Locations" screen in the OUI:

      • "Source" path should have been prefilled with "(wherever you mounted the CDROM)/stage/products.jar"

      • "destination" path says "/ora8/m01/app/oracle/product/8.1.7"

        If the destination is not correct it is because your environment variables are not set properly. Make sure you logged on as oracle using su - oracle. If so, edit the ~/.bash_profile as you did in Pre-Installation Tasks

      • Click "Next" (a pop up window will display Loading Product information).

    • The "Unix Group Name" screen in the OUI:

      • The Unix Group name needs to be set to 'oinstall' ( we made this Unix group earlier ).

      • Click "Next"

      • A popup window appears instantly, requesting you to run a script as root:

        • Debian users need to link /bin/awk to /usr/bin/awk before running the script below

          [joueser ~]$ su -
          [root ~]# ln -s /usr/bin/awk /bin/awk
      • Open a new terminal window, then type:

        [joeuser ~]$ su -
        [root ~]# cd /ora8/m01/app/oracle/product/8.1.7
        [root ~]# ./orainstRoot.sh  
        ; You should see:
        Creating Oracle Inventory pointer file (/etc/oraInst.loc)
        Changing groupname of /ora8/m01/app/oracle/oraInventory to oinstall.
        [root ~]# mkdir -p /usr/local/java
        [root ~]# exit
        [joeuser ~]$ exit
      • Click "Retry"

    • The "Available Products" screen in the OUI:

      • Select "Oracle 8i Enterprise Edition 8.1.7.1.0"

      • Click "Next"

    • The "Installation Types" screen

      • Select the "Custom" installation type.

      • Click "Next"

    • The "Available Product Components" screen

      • In addition to the defaults, make sure that "Oracle SQLJ 8.1.7.0," "Oracle Protocol Support 8.1.7.0.0," and "Linux Documentation 8.1.7.0.0" are also checked.

      • Click "Next"

      • A progress bar will appear for about 1 minute.

    • The "Component Locations" screen in the OUI

      • Click on the "Java Runtime Environment 1.1.8" It should have the path "/ora8/m01/app/oracle/jre/1.1.8"

      • Click "Next"

      • A progress bar will appear for about 1 minute.

    • The "Privileged Operation System Groups" screen in the OUI

      • Enter "dba" for "Database Administrator (OSDBA) Group"

      • Enter "dba" for the "Database Operator (OSOPER) Group"

      • Click "Next"

      • A progress bar will appear for about 1 minute.

    • The "Authentication Methods" screen

      • Click "Next"

    • The next screen is "Choose JDK home directory"

      • Keep the default path: /usr/local/java

      • Click "Next"

    • The "Create a Database" screen in the OUI

      • Select "No" as we will do this later, after some important configuration changes.

      • Click "Next"

    • The next screen is "Oracle Product Support"

      • TCP should be checked with "Status" listed as Required

      • Click "Next"

    • The "Summary" screen in the OUI

      • Check the "Space Requirements" section to verify you have enough disk space for the install.

      • Check that "(144 products)" is in the "New Installations" section title.

      • Click "Install"

      • A progress bar will appear for about 20 - 30 minutes. Now is a good time to take a break.

      • A "Setup Privileges" window will popup towards the end of the installation asking you to run a script as root

      • Run the script. Switch to the oracle user first to set the environment appropriately and then do su to get root privileges, while keeping the oracle user's enviroment.

        [joeuser ~]$ su - oracle
        Password: *********
        [oracle ~]$ su
        Password: *********
        [root ~]# /ora8/m01/app/oracle/product/8.1.7/root.sh
        ; You should see the following.   
        
        Creating Oracle Inventory pointer file (/etc/oraInst.loc)
        Changing groupname of /ora8/m01/app/oracle/oraInventory to oinstall.
        # /ora8/m01/app/oracle/product/8.1.7/root.sh
        Running Oracle8 root.sh script...
        The following environment variables are set as:
            ORACLE_OWNER= oracle
            ORACLE_HOME=  /ora8/m01/app/oracle/product/8.1.7
            ORACLE_SID=   ora8
        
        Enter the full pathname of the local bin directory: [/usr/local/bin]: 
        
        Press ENTER here to accept default of /usr/local/bin
              
        
        Creating /etc/oratab file...
        Entry will be added to the /etc/oratab file by
        Database Configuration Assistants when a database is created
        Finished running generic part of root.sh script.
        Now product-specific root actions will be performed.
        IMPORTANT NOTE: Please delete any log and trace files previously
                        created by the Oracle Enterprise Manager Intelligent
                        Agent. These files may be found in the directories
                        you use for storing other Net8 log and trace files.
                        If such files exist, the OEM IA may not restart.
      • Do not follow the instructions on deleting trace and log files, it is not necessary.

      [root ~]# exit
      [joeuser ~]$ exit
    • Go back to the pop-up window and click "OK"

    • The "Configuration Tools" screen in the OUI

      • This window displays the config tools that will automatically be launched.

    • The "Welcome" screen in the "net 8 Configuration Assistant"

      • Make sure the "Perform Typical installation" is not selected.

      • Click "Next"

      • The "Directory Service Access" screen in the "Net 8 Configuration Assistant"

      • Select "No"

      • Click "Next"

    • The "Listener Configuration, Listener Name" screen in the "Net 8 Configuration Assistant"

      • Accept the default listener name of "LISTENER"

      • Click "Next"

    • The "Listener Configuration, Select Protocols" screen in the "Net 8 Configuration Assistant"

      • The only choice in "Select protocols:" should be "TCP/IP"

      • Click "Next"

    • The "Listener Configuration TCP/IP Protocol" screen in the "Net 8 Configuration Assistant"

      • Default Port should be 1521 and selected.

      • Click "Next"

    • The "Listener Configuration, More Listeners" screen in the "Net 8 Configuration Assistant"

      • Select "No"

      • Click "Next"

    • The "Listener Configuration Done" screen in the "Net 8 Configuration Assistant"

      • Click "Next"

    • The "Naming Methods Configuration" screen in the "Net 8 Configuration Assistant"

      • Select "No"

      • Click "Next"

    • The "Done" screen in the "Net 8 Configuration Assistant"

      • Click "Finish"

    • The "End of Installation" screen in the OUI

      • Click "Exit"

      • Click "Yes" on the confirmation pop up window.

      • The Oracle Universal Installer window should have disappeared!

    Congratulations, you have just installed Oracle 8.1.7 Server! However, you still need to create a database which can take about an hour of non-interactive time, so don't quit yet.

    Creating the First Database

    This step will take you through the steps of creating a customized database. Be warned that this process takes about an hour on a Pentium II with 128 MB of RAM.

    Note

    RedHat 7.3 and 8.0 users: Before running dbassist, do the following.

    1. Download the glibc patch from Oracle Technet into /var/tmp.

    2. cd $ORACLE_HOME

    3. tar xzf /var/tmp/glibc2.1.3-stubs.tgz

    4. ./setup_stubs

    • Make sure you are running X. Open up a terminal and su to oracle and then run the dbassist program.

      [joeuser ~]$ xhost +localhost
      [joeuser ~]$ su - oracle
      Password: *********
      [oracle ~]$ export DISPLAY=localhost:0.0
      [oracle ~]$ dbassist
    • The "Welcome" screen in the Oracle Database Configuration Agent (ODCA)

      • Select "Create a database"

      • Click "Next"

    • The "Select database type" screen in the ODCA

      • Select "Custom"

      • Click "Next"

    • The "Primary Database Type" window in ODCA

      • Select "Multipurpose"

      • Click "Next"

    • The "concurrent users" screen of the ODCA

      • Select "60" concurrent users.

      • Click "Next"

    • Select "Dedicated Server Mode", click "Next"

    • Accept all of the options, and click Next Oracle Visual Information Retrieval may be grayed out. If so, you can ignore it; just make sure that everything else is checked.

    • For "Global Database Name", enter "ora8"; for "SID", also enter "ora8" (it should do this automatically). Click "Change Character Set and select UTF8. Click "Next".

    • Accept the defaults for the next screen (control file location). Click "Next"

    • Go to the "temporary" and "rollback" tabs, and change the Size (upper-right text box) to 150MB. Click "Next"

    • Increase the redo log sizes to 10000K each. Click "Next"

    • Use the default checkpoint interval & timeout. Click "Next"

    • Increase "Processes" to 100; "Block Size" to 4096 (better for small Linux boxes; use 8192 for a big Solaris machine).

    • Accept the defaults for the Trace File Directory. Click "Next"

    • Finally, select "Save information to a shell script" and click "Finish" (We're going to examine the contents of this file before creating our database.)

    • Click the "Save" button. Oracle will automatically save it to the correct directory and with the correct file name. This will likely be /ora8/m01/app/oracle/product/8.1.7/assistants/dbca/jlib/sqlora8.sh

    • It will alert you that the script has been saved successfully.

    • Now we need to customize the database configuration a bit. While still logged on as oracle, edit the database initialization script (run when the db loads). The scripts are kept in $ORACLE_HOME/dbs and the name of the script is usually initSID.ora where SID is the SID of your database. Assuming your $ORACLE_HOME matches our default of /ora8/m01/app/oracle/product/8.1.7, the following will open the file for editing.

      [oracle ~]$ emacs /ora8/m01/app/oracle/product/8.1.7/dbs/initora8.ora
    • Add the following line to the end:

      nls_date_format = "YYYY-MM-DD"
    • Now find the open_cursors line in the file. If you're using emacs scroll up to the top of the buffer and do CTRL-S and type open_cursors to find the line. The default is 100. Change it to 500.

      open_cursors = 500
    • Save the file. In emacs, do CTRL-X CTRL-S to save followed by CTRL-X CTRL-C to exit or use the menu.

    • At this point, you are ready to initiate database creation. We recommend shutting down X to free up some RAM unless you have 256 MB of RAM or more. You can do this quickly by doing a CRTL-ALT-BACKSPACE, but make sure you have saved any files you were editing. You should now be returned to a text shell prompt. If you get sent to a graphical login screen instead, switch to a virtual console by doing CRTL-ALT-F1. Then login as oracle.

    • Change to the directory where the database creation script is and run it:

      [oracle ~]$ cd /ora8/m01/app/oracle/product/8.1.7/assistants/dbca/jlib
      oracle:/ora8/m01/app/oracle/product/8.1.7/assistants/dbca/jlib$ ./sqlora8.sh

      In some instances, Oracle will save the file to /ora8/m01/app/oracle/product/8.1.7/assistants/dbca Try running the script there if your first attempt does not succeed.

    • Your database will now be built. It will take > 1 hour - no fooling. You will see lots of errors scroll by (like: "ORA-01432: public synonym to be dropped does not exist") Fear not, this is normal.

      Eventually, you'll be returned to your shell prompt. In the meantime, relax, you've earned it.

    Acceptance Test

    For this step, open up a terminal and su to oracle as usual. You should be running X and Netscape (or other web browser) for this phase.

    • You need to download the "Oracle Acceptance Test" file. It's available here and at http://philip.greenspun.com/wtr/oracle/acceptance-sql.txt. Save the file to /var/tmp

    • In the oracle shell, copy the file.

      [oracle ~]$ cp /var/tmp/acceptance-sql.txt /var/tmp/acceptance.sql
    • Once you've got the acceptance test file all set, stay in your term and type the following:

      [oracle ~]$ sqlplus system/manager

      SQL*Plus should startup. If you get an ORA-01034: Oracle not Available error, it is because your Oracle instance is not running. You can manually start it as the oracle user.

      [oracle ~]$ svrmgrl
      SVRMGR> connect internal
      SVRMGR> startup
    • Now that you're into SQL*Plus, change the default passwords for system, sys, and ctxsys to "alexisahunk" (or to something you'll remember):

      SQL> alter user system identified by alexisahunk;
      SQL> alter user sys identified by alexisahunk;
      SQL> alter user ctxsys identified by alexisahunk;
    • Verify that your date settings are correct.

      SQL> select sysdate from dual;

      If you don't see a date that fits the format YYYY-MM-DD, please read Troubleshooting Oracle Dates.

    • At this point we are going to hammer your database with an intense acceptance test. This usually takes around 30 minutes.

      SQL> @ /var/tmp/acceptance.sql
      
      ; A bunch of lines will scroll by.  You'll know if the test worked if
      ; you see this at the end:
      
      SYSDATE
      ----------
      2000-06-10
      
      SQL>

      Many people encounter an error regarding maximum key length:

      ERROR at line 1:
      ORA-01450: maximum key length (758) exceeded

      This error occurs if your database block size is wrong and is usually suffered by people trying to load OpenACS into a pre-existing database. Unfortunately, the only solution is to create a new database with a block size of at least 4096. For instructions on how to do this, see Creating the First Database above. You can set the parameter using the dbassist program or by setting the DB_BLOCK_SIZE parameter in your database's creation script.

      If there were no errors, then consider yourself fortunate. Your Oracle installation is working.

    Automating Startup & Shutdown

    You will want to automate the database startup and shutdown process. It's probably best to have Oracle spring to life when you boot up your machine.

    • Oracle includes a script called dbstart that can be used to automatically start the database. Unfortunately, the script shipped in the Linux distribution does not work out of the box. The fix is simple. Follow these directions to apply it. First, save dbstart to /var/tmp. Then, as oracle, do the following:

      [oracle ~]$ cp /var/tmp/dbstart.txt /ora8/m01/app/oracle/product/8.1.7/bin/dbstart 
      [oracle ~]$ chmod 755 /ora8/m01/app/oracle/product/8.1.7/bin/dbstart
    • While you're logged in as oracle, you should configure the oratab file to load your database at start. Edit the file /etc/oratab:

      • You will see this line.

        ora8:/ora8/m01/app/oracle/product/8.1.7:N

        By the way, if you changed the service name or have multiple databases, the format of this file is:

        service_name:$ORACLE_HOME:Y || N (for autoload)

      • Change the last letter from "N" to "Y". This tells Oracle that you want the database to start when the machine boots. It should look like this.

        ora8:/ora8/m01/app/oracle/product/8.1.7:Y
      • Save the file & quit the terminal.

    • You need a script to automate startup and shutdown. Save oracle8i.txt in /var/tmp. Then login as root and install the script. (Debian users: substitute /etc/init.d for /etc/rc.d/init.d throughout this section)

      [oracle ~]$ su -
      [root ~]# cp /var/tmp/oracle8i.txt /etc/rc.d/init.d/oracle8i
      [root ~]# chown root.root /etc/rc.d/init.d/oracle8i
      [root ~]# chmod 755 /etc/rc.d/init.d/oracle8i
    • Test the script by typing the following commands and checking the output. (Debian Users: as root, do mkdir /var/lock/subsys first)

      [root ~]# /etc/rc.d/init.d/oracle8i stop
      Oracle 8i auto start/stop
      Shutting Oracle8i:
      Oracle Server Manager Release 3.1.7.0.0 - Production
      
      Copyright (c) 1997, 1999, Oracle Corporation.  All
      Rights Reserved.
      
      Oracle8i Enterprise Edition Release 8.1.7.0.1 -
      Production
      With the Partitioning option
      JServer Release 8.1.7.0.1 - Production
      
      SVRMGR> Connected.
      SVRMGR> Database closed.
      Database dismounted.
      ORACLE instance shut down.
      SVRMGR>
      Server Manager complete.
      Database "ora8" shut down.
            
      [root ~]# /etc/rc.d/init.d/oracle8i start
      Oracle 8i auto start/stop
      Starting Oracle8i: 
      SQL*Plus: Release 8.1.7.0.0 - Production on Wed Mar 6 17:56:02 2002
      
      (c) Copyright 2000 Oracle Corporation.  All rights reserved.
      
      SQL> Connected to an idle instance.
      SQL> ORACLE instance started.
      
      Total System Global Area   84713632 bytes
      Fixed Size                    73888 bytes
      Variable Size              76079104 bytes
      Database Buffers            8388608 bytes
      Redo Buffers                 172032 bytes
      Database mounted.
      Database opened.
      SQL> Disconnected
      
      Database "ora8" warm started.
      
      Database "ora8" warm started.
    • If it worked, then run these commands to make the startup and shutdown automatic.

      • Red Hat users:

        [root ~]# cd /etc/rc.d/init.d/                      
        [root ~]# chkconfig --add oracle8i
        [root ~]# chkconfig --list oracle8i
        ; You should see:
        oracle8i        0:off   1:off   2:off   3:on    4:on    5:on    6:off
      • Debian users:

        [root ~]# update-rc.d oracle8i defaults
         Adding system startup for /etc/init.d/oracle8i ...
           /etc/rc0.d/K20oracle8i -> ../init.d/oracle8i
           /etc/rc1.d/K20oracle8i -> ../init.d/oracle8i
           /etc/rc6.d/K20oracle8i -> ../init.d/oracle8i
           /etc/rc2.d/S20oracle8i -> ../init.d/oracle8i
           /etc/rc3.d/S20oracle8i -> ../init.d/oracle8i
           /etc/rc4.d/S20oracle8i -> ../init.d/oracle8i
           /etc/rc5.d/S20oracle8i -> ../init.d/oracle8i
      • SuSE users:

        [root ~]# cd /etc/rc.d/init.d
        root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/oracle8i K20oracle8i
        root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/oracle8i S20oracle8i
        root:/etc/rc.d/init.d# cp K20oracle8i rc0.d
        root:/etc/rc.d/init.d# cp S20oracle8i rc0.d
        root:/etc/rc.d/init.d# cp K20oracle8i rc1.d
        root:/etc/rc.d/init.d# cp S20oracle8i rc1.d 
        root:/etc/rc.d/init.d# cp K20oracle8i rc6.d
        root:/etc/rc.d/init.d# cp S20oracle8i rc6.d
        root:/etc/rc.d/init.d# cp K20oracle8i rc2.d
        root:/etc/rc.d/init.d# cp S20oracle8i rc2.d
        root:/etc/rc.d/init.d# cp K20oracle8i rc3.d
        root:/etc/rc.d/init.d# cp S20oracle8i rc3.d 
        root:/etc/rc.d/init.d# cp K20oracle8i rc4.d  
        root:/etc/rc.d/init.d# cp S20oracle8i rc4.d  
        root:/etc/rc.d/init.d# cp K20oracle8i rc5.d
        root:/etc/rc.d/init.d# cp S20oracle8i rc5.d
        root:/etc/rc.d/init.d# rm K20oracle8i
        root:/etc/rc.d/init.d# rm S20oracle8i
        root:/etc/rc.d/init.d# cd
        [root ~]# SuSEconfig
        Started the SuSE-Configuration Tool.
        Running in full featured mode.
        Reading /etc/rc.config and updating the system...
        Executing /sbin/conf.d/SuSEconfig.gdm...   
        Executing /sbin/conf.d/SuSEconfig.gnprint...
        Executing /sbin/conf.d/SuSEconfig.groff...   
        Executing /sbin/conf.d/SuSEconfig.java...    
        Executing /sbin/conf.d/SuSEconfig.kdm...   
        Executing /sbin/conf.d/SuSEconfig.pcmcia...
        Executing /sbin/conf.d/SuSEconfig.perl...
        Executing /sbin/conf.d/SuSEconfig.postfix...
        Executing /sbin/conf.d/SuSEconfig.sendmail...
        Executing /sbin/conf.d/SuSEconfig.susehilf...
        Executing /sbin/conf.d/SuSEconfig.susehilf.add...
        Executing /sbin/conf.d/SuSEconfig.susewm...
        Executing /sbin/conf.d/SuSEconfig.tetex...
        Executing /sbin/conf.d/SuSEconfig.ypclient...
        Processing index files of all manpages...
        Finished.
    • You also need some scripts to automate startup and shutdown of the Oracle8i listener. The listener is a name server that allows your Oracle programs to talk to local and remote databases using a standard naming convention. It is required for Intermedia Text and full site search.

      Download these three scripts into /var/tmp

      Now issue the following commands (still as root).

      [root ~]# su - oracle
      [oracle ~]$ cp /var/tmp/startlsnr.txt /ora8/m01/app/oracle/product/8.1.7/bin/startlsnr
      [oracle ~]$ cp /var/tmp/stoplsnr.txt /ora8/m01/app/oracle/product/8.1.7/bin/stoplsnr    
      [oracle ~]$ chmod 755 /ora8/m01/app/oracle/product/8.1.7/bin/startlsnr
      [oracle ~]$ chmod 755 /ora8/m01/app/oracle/product/8.1.7/bin/stoplsnr
      [oracle ~]$ exit
      [root ~]# cp /var/tmp/listener8i.txt /etc/rc.d/init.d/listener8i
      [root ~]# cd /etc/rc.d/init.d
      root:/etc/rc.d/init.d# chmod 755 listener8i

      Test the listener automation by running the following commands and checking the output.

      root:/etc/rc.d/init.d# ./listener8i stop
      Oracle 8i listener start/stop
      Shutting down Listener for 8i: 
      LSNRCTL for Linux: Version 8.1.7.0.0 - Production on 06-MAR-2002 18:28:49
      
      (c) Copyright 1998, Oracle Corporation.  All rights reserved.
      
      Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost.localdomain)(PORT=1521)))
      The command completed successfully
      
          
      root:/etc/rc.d/init.d# ./listener8i start
      Oracle 8i listener start/stop
      Starting the Listener for 8i: 
      LSNRCTL for Linux: Version 8.1.7.0.0 - Production on 06-MAR-2002 18:28:52
      
      (c) Copyright 1998, Oracle Corporation.  All rights reserved.
      
      Starting /ora8/m01/app/oracle/product/8.1.7/bin/tnslsnr: please wait...
      
      TNSLSNR for Linux: Version 8.1.7.0.0 - Production
      System parameter file is /ora8/m01/app/oracle/product/8.1.7/network/admin/listener.ora
      Log messages written to /ora8/m01/app/oracle/product/8.1.7/network/log/listener.log
      Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost.localdomain)(PORT=1521)))
      Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC)))
      
      Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost.localdomain)(PORT=1521)))
      STATUS of the LISTENER
      ------------------------
      Alias                     LISTENER
      Version                   TNSLSNR for Linux: Version 8.1.7.0.0 - Production
      Start Date                06-MAR-2002 18:28:53
      Uptime                    0 days 0 hr. 0 min. 0 sec
      Trace Level               off
      Security                  OFF
      SNMP                      OFF
      Listener Parameter File   /ora8/m01/app/oracle/product/8.1.7/network/admin/listener.ora
      Listener Log File         /ora8/m01/app/oracle/product/8.1.7/network/log/listener.log
      Services Summary...
        PLSExtProc        has 1 service handler(s)
        ora8      has 1 service handler(s)
      The command completed successfully

      This test will verify that the listener is operating normally. Login into the database using the listener naming convention.

      sqlplus username/password/@SID

      [root ~]# su - oracle
      [oracle ~]$ sqlplus system/alexisahunk@ora8
      
      SQL> select sysdate from dual;
      
      SYSDATE
      ----------
      2002-02-22
      
      SQL> exit
      [oracle ~]$ exit
      [root ~]#
      • RedHat users:

        Now run chkconfig on the listener8i script.

        [root ~]# cd /etc/rc.d/init.d/
        root:/etc/rc.d/init.d# chkconfig --add listener8i
        root:/etc/rc.d/init.d# chkconfig --list listener8i
        listener8i      0:off   1:off   2:off   3:on    4:on    5:on    6:off
      • Debian users:

        Now run update-rc.d on the listener8i script.

        [root ~]# update-rc.d listener8i defaults 21 19
         Adding system startup for /etc/init.d/listener8i ...
           /etc/rc0.d/K19listener8i -> ../init.d/listener8i
           /etc/rc1.d/K19listener8i -> ../init.d/listener8i
           /etc/rc6.d/K19listener8i -> ../init.d/listener8i
           /etc/rc2.d/S21listener8i -> ../init.d/listener8i
           /etc/rc3.d/S21listener8i -> ../init.d/listener8i
           /etc/rc4.d/S21listener8i -> ../init.d/listener8i
           /etc/rc5.d/S21listener8i -> ../init.d/listener8i
    • Test the automation

      As a final test, reboot your computer and make sure Oracle comes up. You can do this by typing

      [root ~]# /sbin/shutdown -r -t 0 now

      Log back in and ensure that Oracle started automatically.

      [joeuser ~]$ su - oracle
      [oracle ~]$ sqlplus system/alexisahunk@ora8
      
      SQL> exit

    Congratulations, your installation of Oracle 8.1.7 is complete.

    Troubleshooting Oracle Dates

    Oracle has an internal representation for storing the data based on the number of seconds elapsed since some date. However, for the purposes of inputing dates into Oracle and getting them back out, Oracle needs to be told to use a specific date format. By default, it uses an Oracle-specific format which isn't copacetic. You want Oracle to use the ANSI-compliant date format which is of form 'YYYY-MM-DD'.

    To fix this, you should include the following line in $ORACLE_HOME/dbs/initSID.ora or for the default case, $ORACLE_HOME/dbs/initora8.ora

    nls_date_format = "YYYY-MM-DD"

    You test whether this solved the problem by firing up sqlplus and typing:

    SQL> select sysdate from dual;

    You should see back a date like 2000-06-02. If some of the date is chopped off, i.e. like 2000-06-0, everything is still fine. The problem here is that sqlplus is simply truncating the output. You can fix this by typing:

    SQL> column sysdate format a15
    SQL> select sysdate from dual;

    If the date does not conform to this format, double-check that you included the necessary line in the init scripts. If it still isn't working, make sure that you have restarted the database since adding the line:

    [joeuser ~]$ svrmgrl
    SVRMGR> connect internal
    Connected.
    SVRMGR> shutdown
    Database closed.
    Database dismounted.
    ORACLE instance shut down.
    SVRMGR> startup
    ORACLE instance started.

    If you're sure that you have restarted the database since adding the line, check your initialization scripts. Make sure that the following line is not included:

    export nls_lang = american

    Setting this environment variable will override the date setting. Either delete this line and login again or add the following entry to your login scripts after the nls_lang line:

    export nls_date_format = 'YYYY-MM-DD'

    Log back in again. If adding the nls_date_format line doesn't help, you can ask for advice in our OpenACS forums.

    Useful Procedures

    • Dropping a tablespace

      • Run sqlplus as the dba:

        [oracle ~]$ sqlplus system/changeme
      • To drop a user and all of the tables and data owned by that user:

        SQL> drop user oracle_user_name cascade;
      • To drop the tablespace: This will delete everything in the tablespace overriding any referential integrity constraints. Run this command only if you want to clean out your database entirely.

        SQL> drop tablespace table_space_name including contents cascade constraints;

    For more information on Oracle, please consult the documentation.

    Defaults

    We used the following defaults while installing Oracle.

    VariableValueReason
    ORACLE_HOME/ora8/m01/app/oracle/product/8.1.7This is the default Oracle installation directory.
    ORACLE_SERVICEora8The service name is a domain-qualified identifier for your Oracle server.
    ORACLE_SIDora8This is an identifier for your Oracle server.
    ORACLE_OWNERoracleThe user who owns all of the oracle files.
    ORACLE_GROUPdbaThe special oracle group. Users in the dba group are authorized to do a connect internal within svrmgrl to gain full system access to the Oracle system.
    ($Id: oracle.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/doc-standards.html0000644000175000017500000000532411501005400023421 0ustar frankiefrankie Chapter 12. Documentation Standards
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-squirrelmail.html0000644000175000017500000000724211501005400025051 0ustar frankiefrankie Install Squirrelmail for use as a webmail system for OpenACS

    Install Squirrelmail for use as a webmail system for OpenACS

    By Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This section is work in progress. It will detail how you can install Squirrelmail as a webmail frontend for OpenACS, thereby neglecting the need to have a seperate webmail package within OpenACS

    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]# cd www
    [$OPENACS_SERVICE_NAME www]# wget http://cesnet.dl.sourceforge.net/sourceforge/squirrelmail/squirrelmail-1.4.4.tar.gz
    [$OPENACS_SERVICE_NAME www]# tar xfz squirrelmail-1.4.4.tar.gz
    [$OPENACS_SERVICE_NAME www]# mv squirrelmail-1.4.4 mail
    [$OPENACS_SERVICE_NAME www]# cd mail/config
    [$OPENACS_SERVICE_NAME www]# ./conf.pl
          

    Now you are about to configure Squirrelmail. The configuration heavily depends on your setup, so no instructions are given here.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-php.html0000644000175000017500000000752011501005400023126 0ustar frankiefrankie Install PHP for use in AOLserver

    Install PHP for use in AOLserver

    By Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    To be able to use PHP software with AOLserver (and OpenACS), you have to install PHP with AOLserver support. Get the latest version from www.php.net. For convenience we get version 4.3.4 from a mirror

    [root root]# cd /usr/local/src
    [root src]# wget http://de3.php.net/distributions/php-4.3.4.tar.gz
    [root src]# tar xfz php-4.3.4.tar.gz
    [root src]# cd php-4.3.4
    [root php-4.3.4]# cd php-4.3.4
    [root php-4.3.4]#  ./configure --with-aolserver=/usr/local/aolserver/ --with-pgsql=/usr/local/pgsql --without-mysql
    [root php-4.3.4]# make install
          

    Once installed you can enable this by configuring your config file. Make sure your config file supports php (it should have a php section with it). Furthermore add index.php as the last element to your directoryfile directive.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/openacs-overview.html0000644000175000017500000001224211501005400024164 0ustar frankiefrankie Overview

    Overview

    OpenACS (Open Architecture Community System) is an advanced toolkit for building scalable, community-oriented web applications. If you're thinking of building an enterprise-level web application, OpenACS is a solid, scalable framework for building dynamic content driven sites.

    OpenACS is a collection of pre-built applications and services that you can use to build your web site/application. Through a modular architecture, OpenACS has packages for user/groups management, content management, e-commerce, news, FAQs, calendar, forums, bug tracking, full-text searching, and much more.

    OpenACS relies on AOLserver, the free, multithreaded, scalable, Tcl-enabled, web/application server used by America Online for most of its web sites, and a true ACID-compliant Relational Database Management System (RDBMS). Currently OpenACS supports PostgreSQL, an open source RDBMS, and Oracle and is easily extensible to other databases which support a comparable feature set.

    The OpenACS toolkit is derived from the ArsDigita Community System (ACS). ArsDigita (now part of Red Hat, Inc.) kindly made their work available under the GPL, making all of this possible.

    The OpenACS project was born when Don Baccus, Ben Adida, and others decided to port ACS from Oracle to PostgreSQL, thus making it a fully open-source solution. With OpenACS 4, Oracle and PostgreSQL support were combined in one code base and with OpenACS 5, support for internationalization and localization has been added.

    A vibrant and productive community has sprung up around the OpenACS software and there are many volunteer contributors as well as a commercial companies able to provide support, hosting, and custom development. Many of the production users are actively funding and contributing work back to the project. Formal, consensus driven governance has been established (with semi-annual elections) which ensures the project serves the needs of it's constituents.

    The OpenACS community would like to hear your comments and can help you in your endeavors with the system. Visit our web site and feel free to ask questions or provide feedback.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/cvs-tips.html0000644000175000017500000002337211501005400022446 0ustar frankiefrankie Appendix D. Using CVS with an OpenACS Site

    Appendix D. Using CVS with an OpenACS Site

    By Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Add the Service to CVS - OPTIONAL. These steps take an existing OpenACS directory and add it to a CVS repository.

    1. Create and set permissions on a subdirectory in the local cvs repository.

      [root root]# mkdir /cvsroot/$OPENACS_SERVICE_NAME
      [root root]# chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /cvsroot/$OPENACS_SERVICE_NAME
      [root root]#
      mkdir /cvsroot/$OPENACS_SERVICE_NAME
      chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /cvsroot/$OPENACS_SERVICE_NAME
    2. Add the repository location to the user environment. On some systems, you may get better results with .bash_profile instead of .bashrc.

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ emacs .bashrc

      Put this string into /home/$OPENACS_SERVICE_NAME/.bashrc:

      export CVSROOT=/cvsroot
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
      logout
      
      [root root]#
    3. Import all files into cvs. In order to work on files with source control, the files must be checked out from cvs. So we will import, move aside, and then check out all of the files. In the cvs import command, $OPENACS_SERVICE_NAME refers to the cvs repository to use; it uses the CVSROOT plus this string, i.e. /cvsroot/$OPENACS_SERVICE_NAME. "OpenACS" is the vendor tag, and "oacs-5-6-0-final" is the release tag. These tags will be useful in upgrading and branching. -m sets the version comment.

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs import -m "initial install" $OPENACS_SERVICE_NAME OpenACS oacs-5-6-0-final
      N $OPENACS_SERVICE_NAME/license.txt
      N $OPENACS_SERVICE_NAME/readme.txt
      (many lines omitted)
      N $OPENACS_SERVICE_NAME/www/SYSTEM/flush-memoized-statement.tcl
      
      No conflicts created by this import
      
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
      [root root]#
      su - $OPENACS_SERVICE_NAME
      cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
      cvs import -m "initial install" $OPENACS_SERVICE_NAME OpenACS oacs-5-6-0-final
      exit

      Move the original directory to a temporary location, and check out the cvs repository in its place.

      [root root]# mv /var/lib/aolserver/$OPENACS_SERVICE_NAME /var/tmp
      [root root]# mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME
      [root root]# chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /var/lib/aolserver/$OPENACS_SERVICE_NAME
      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver
      [$OPENACS_SERVICE_NAME aolserver]$ cvs checkout $OPENACS_SERVICE_NAME
      cvs checkout: Updating $OPENACS_SERVICE_NAME
      U $OPENACS_SERVICE_NAME/license.txt
      (many lines omitted)
      U $OPENACS_SERVICE_NAME/www/SYSTEM/dbtest.tcl
      U $OPENACS_SERVICE_NAME/www/SYSTEM/flush-memoized-statement.tcl
      [$OPENACS_SERVICE_NAME aolserver]$ exit
      logout
      
      [root root]#
      
      mv /var/lib/aolserver/$OPENACS_SERVICE_NAME /var/tmp
      mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME
      chown $OPENACS_SERVICE_NAME.$OPENACS_SERVICE_NAME /var/lib/aolserver/$OPENACS_SERVICE_NAME
      su - $OPENACS_SERVICE_NAME
      cd /var/lib/aolserver
      cvs checkout $OPENACS_SERVICE_NAME
      exit
    4. If the service starts correctly, come back and remove the temporary copy of the uploaded files.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/releasing-openacs.html0000644000175000017500000000536711501005400024301 0ustar frankiefrankie Chapter 15. Releasing OpenACS
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/os-install.html0000644000175000017500000000605011501005400022755 0ustar frankiefrankie Linux Install Guides

    Linux Install Guides

    Here's a list of some helpful documentation for various OS's

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-future-topics.html0000644000175000017500000000645511501005400025353 0ustar frankiefrankie Future Topics

    Future Topics

    • How to enforce security so that users can't change other users records

    • How to use the content management tables so that ... what?

    • How to change the default stylesheets for Form Builder HTML forms.

    • How to make your package searchable with OpenFTS/Oracle

    • How to prepare pagelets for inclusion in other pages

    • How and when to put procedures in a tcl procedure library

    • More on ad_form - data validation, other stuff. (plan to draw from Jon Griffin's doc)

    • partialquery in xql

    • How to use the html/text entry widget to get the "does this look right" confirm page

    • APM package dependencies

    See also the OpenACS Programming FAQ

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/images/0000755000175000017500000000000011724401447021270 5ustar frankiefrankieopenacs-5.7.0/packages/acs-core-docs/www/images/translation-batch-edit.png0000644000175000017500000013242410015422052026327 0ustar frankiefrankie‰PNG  IHDR\.?ß pHYsaa¨?§itIMEÔ&?r¤ IDATxÚìu|ÇÀç4¹‹»’@‚[p îE Å¡hq-.ZZ¿®!Ñ}¶Ì[÷¥¤¹—Á–ʶlÑŠQEÀ7Ö¤Xj&×B1äûñF1Xú-Sü½>sÌ?_Wáöÿtø¸þŒƒÓ‡¥†€o;ê´rPÄ™üÏ*bMÄZ«ÝÃ)Óé7Œ«Å'æÒ`Ó€UƒªnY8òÒí{B#9E:cÃth“C,)fŸ’¼ó@¿°U vf§7¨ Ø×_ß­3I·.©ªµ®åζªRŸ •úÂ×ÏìuæÑG­ÝAJè¼òçÊ› »ôê‹VŸÅq/7¬ŠfÛÖ}ÿ3vÐÔãC÷&MýçºûÅ®>ýQ" ðWfô=Ð$aåu|oÿÆùrej•ya4U:œ2ýpÊôŸýÒ«-±®ûUû‚³Ã)Ó%OÛvw`»š²åó„ÔžõFDAb ‚ pËxwtÝÔ® '€O Hb žk+ßšø€¼=9éU“µÉ[ejÚ¶Aû†•_Ó7tíŒ>ç¥:£¯†}‚V¾ÜucZ½ ýBÖŒoô¿µi§_*§Í«U&˜Ïb1x®5:GL:ú‹¡òÿ¼oœ„îꢳj¬í¶~Á¨›­™)¥ÝŒýxþ Ûž2˜êøôc#+­XiÓÒ™:rÖОÿýô¸jkVÞ²uój?˜~W&¿šc¶º©Õä…%ÝèxÛ&·H_Þ|ë\½GÃF­œR÷½Tæ9G§>6ùð°ðÕƒªoÛôw‚¡™q;oÌh¼i@èßc[¼£H8|gNÓÍC׌msäAîr‚ÕáAȼúhA«†®^÷¾=Ÿ-¹åñúK“k¯ï¼ò[t&ýõĬ>?¾ÚÚþáþšüŸ¡ž#ÓëIš6é¨DÂqæ×ÙA_e ž—[Ó‰ToÈ$çÊ5‰qñ§ä36¦³ÔÓIÈâŠ"ÚÈKÈ'±þWy¨—ÈÑM<2*gåéc´ªY51#ô ‘ÌÜŒYY-{®©í)±C!mŸ)óqx¢f½•)rYExv©¢R ˆÅêo¯oPV/#b³…åjËŽÄç>Ž,T7‹]Ï+¦‹OÙs÷ÊRæºåá˜Î <X\§ˆ6CK4äŒ~é(×Kòõ¿ö õrqt u)o„l˜V½Œ'›íP®v‡#ñbsEÍö™ýÂ|\8<÷f½g¦ht¹ñ_CÚxò¹ÎÞå†ýuÚhýÉT£5ªkë§Õ ósàðÊTk±õnFÌîù *8rBj¶;– ¡núcôªfÕBy¶WHÍ™›oR$šuBÇ ~nå‘£ü©<%mi(=ß- éEàºÕ×{§$Böî¿ÕO`8Ñ;0J_`x³#÷d*58¦TÜ^v`t¯¸¼Š¹Gÿ—œ¡Òi5Ïvœ\ï²i+Úm˜=åîÓG™2…ÎŒù/ô¼_±t¿›Ÿ2Ô˜B~i殉ãÞ›ŠVϧö5 1¼~Î…%Œ„ëy1k×èþ·ÓU¶`ïÍSç~Ò§¿þãß‘?]û˜¦ÖH$?DßFò?8?¦ß]šÕn-éFÇÛôÝBÄÙW^ñåÒ©_:<"Ó_Íß5fÀt¡V%°ÅÐÌ #ï~JWé´šç»Oõ Ý4iô½Oi¹ú4¸Jsx&‡¯:}#S­Åe©™'g°ä–I~j¾QgÒ׌^Oðý6OŸÿÙȳ#ӟˬTé誤¿ÐHå6Ÿ\ï"…]f?>†‰ÊlñµÇ‡6»N¦à:MŸ2ÄŸ^•¤‡ocR5¡UàûçJ‚Z©õé·§Šý›+ž'ã*±nÓ‰>±_°ò"¦Ð‚ÏØòѳñþ´2ÀI´øtNÃçK‚Ú)âRqßWh1ÁçËG7£H´äœkc«…t]˜(Pʳþè\†TÕ¦R²ô Ë8sbÄ ‚8Õa㊳"KO=\«è¾Ãt’KVæ|šqLÝ'xµiEJ½ìÒ¼6Û‡”[5¬Þε d¨pêâ÷J« µúkL™Ý¯ü.3bµ™³;•+Ûi¶N›õ[—ð²fÛôŸ]1¯ àmÿŠ{õ×s+­~ ÐRøÑ’ ˈ<ÑøT¶§YÝèÖ’n´¼MÛ-QÒÀò;dZ½VÊ_˯y*ÂH'ä) |Ÿ¯»y ëSf ÍáA˜Sqõ¾½ñ)© Šþêõ^¦£ß%Í™ôõ7ôù€JûŒ ±:2å¨U"ÿõ¯¸7.McG dø¯_¹­wRò„à˜ùˆ¾?óÕÒà¾XÝÈUp<ËøcÕÀE0k‹úÍgœêñ‡××Ê=Äÿ{–W¬…›àLn £U`'1Y8Fš¯îkiÎ` ¬V/ˆíFß]ÙŽ!ÿû$5ç–L¿’Ù¤‘«Ãñ,…©Ø× m®bÓÁTf 7‡3ÙÊ\‹Þpœªé¯ºæ¥+³Ïؽ’“íJŒÕ`ñ¨›nàµåè›Ï™ù{ÜL¢%çÔwážä*/ˆ&Uµ©E À¶´>äÓ±“ïôMž²}pÛþƒ[¾騏- ½ŽÊ•:Kß‚svÙ,.ë̬ç:¸ušÕ®Ó,„‘ý>ýζks»i·_lB±d/×½ªö·Ájªù…b&ƒp„a²ñLÞ¹®¦[ŽO8nåtò3úëD™®¶›±¯èøD•ú~Áð7Snðä0ì¨N¡oÓwK⪅`XhÞ‰×=«ÒWý¤wBž®¡ùº›—§€±>:ÌÖá1çHÇ=«ž,^~NæàÑuá½:»›U5܉i__”gÒ×ßÐç˜ü”qæF¦!åXñ2]MW•§LGˆ§fsäéU5ŽçôZ©âéÁk›Þor½™>“¥° âÏÌšÓT·bu"E¾'Àc)êèa\íÜu§©¨;ÌS™ÓÖ8/èÅD/¨„‡þbÞ_šSœû×Ì«~OŠºz‰Ì>gê9çk¢2/· ‹AàÖ«ðyEFB*IÆÅ“‡ÿ°¤ÿË%¡Ì»GL[u+ö­H¡ß3Âá±TÓуgš^™Çε•ÀÍlþÞ“jºzñŒ¶ºBO¤šv9Û¬Žîmm*Uød».Æjè”ÔMŸ»¾gêë:Ì$t¬8mͱ½Â-%ZrÎS™¶µ{®òn­­kV8Pz÷‚ ˆÏ;ô-»rÁÎ,Ó¯žÇϧJ¤Z't©é²‡¥/ßÔë(¦ }‚òUœWiu¼£–3²¡o­Á«º¼ [×|í&—~«´ú¡É·mú~Àä™ km¼§ SÝÈjÃ¥ ³ºÑñ6M·èž‰óœ¬ — æV2T fwÓ¦š'ß‹í¾“Ú-ߨ3iêouÈìÈ4äfÇkbd¶ª¤•¦«°ý‹·{/Œ S‘j‚ Nèôª ŸÙ†®‚%'´™\‡˜ZG®¬4vœÌ²¨êëë*rÅÈtHñEÛÂO8`Už#]÷$7άÞÒ¬n«íFÏj‘‹% ]–œø/S¢Ðá¦N&K2 Ã*]Nf)©Åš"]îIÔæºÃálÞ:ÐYÓå#è·KÞZjštÃëë9ü*‰–œSÏ…{ÞÜ:]-ß0T(xx¿ƒIÓó2JW`„ƒ‡Ïg)¿dš~ľØkr¯³—Ï~ÌÌÖà!ÿ"¼¾*š_ÖøO˜ø90Ÿ§kÉÛ¡£ü׌½›ôI‰ãºì7ÉÆï3›Ôlõã§ð˜y61àG÷mfˆ1Htlìå€Íõéƒú{m}÷óN.¿¾ä˜­~ØÞíÿ¼~í«ñè¸ÑÈj«ºÑ¦[²o\’†5#× ôkýÃT[nHB{yl›øð‹ÓŠÅ''^.º¸ü·Iwß%*t8Îd „j·|£Î¤ÿ™Ú>ñA†ÓŠÄÇ'\ èm¬§Ù‘iHÕé¯%ÙªÛ9`Huí?çÄvw¢V¦x²ó’ƒwE2%vQr¥ÁùÌJ0Äwf¸91¤iº#ò^³Á×Gõ2ÐÊð]³sÒ R>x‹c8bR>x>싯œ¿¬’õYž3NþžÊîÓWù$‰Ðá(9›;@j“á6U·ïy¥–~9»~”“_Ï\·à|g7'iÚË#Úç-”:².§z©ê¸> ^¦Iµ²´]³;ÚbQý>}³çðöŽ’òØÂðFòô:yß("£\fVÓu¨*v ’Þ÷qÐ'®ëÀ˜ÔYâȶ£YvÔ™B¬ƒ'ûìKÙFyEZ„Pý.+›ƒ[Šy\ad¥k7¾M£×¦ê6=¯È?äâWé³ìCw7åºeáÞQ­xlnx£¾éuòN lŸÞ­EOr7'2êöÌjï;Tõw jpßgª-]_ÙD4¸ee×%²ÿ<×n9í6_sëÏ›µ]¼+´ù¹ÁÌw¿ü Ø¥¦×uàLê\Ó‘ëÜfÌÿ–½D‘hÉ9-7Üät%"ÀÅ»BëÄzQ ¦£-¥ün<”n’Öí_~·Ê–Cu¾¢Ñ}¶ÜkÚcñ$?è ¤¡Ì>áY~£Rx\1з÷c…ò·˜Kàpf)ógÉü½-[!Ïb_öÓÿÙ±`ˆ§æóÊ¡­ýûjk+ð Ä@V"¹¯ò“#P¸\[7iÔ_;?ʹ‘]GØ»$ ¿ 1À÷D¾@ 1@i…]b5Ëû¹ãâ:±dÚbñë@ñÀ4 aq=ýC·ëµÿ¶Ý…žRã²Òg|‡¿F1µwXöøÂ,›ÿÌšÝK)%v‡ `ñÃ'ï:ûˆl×j:ÝGz)ÓÐKc/ŠÂPâb œÅëÜ­«p}ÊÅ µiž12›è–;q¦i¬Ç@6ÅÔS²¾¢Wîìž]®Í.ºˆ~ ý \snÛ’^?4 õ÷0<›ÜxÊ%rQ‡ºîó6ç%6«H€Éãr·lœõ)åy9'<þ:vW W¡S§ÑÈ ”‘×R 7Ÿ»Ëv:Ki©Ìÿœ2¼1Ø {óGIˆèèoˆFšyïÔ²Ü%–r4 Ðé>²Æ IiÙq¿µÂPVNoZ-@§û&/h˜ë¥!—žÆpìÓ³ ƒ:ü] @ z7ÞÜ«anQ¾è‹^Õ(·ÊàÝfe®­çköÝøõÃÑ|7ÞÖ5˜Û2-ÿÍ‚ pL2²Ž·Qz_öÒÔÁ‚E…³DGKYõ&]¦îD²îÃuЉüŒß¹¯(€´FÂqt©X«×/3/¾ÌÛÁuòíó†W-ãÅf2Ý+ ùm·71(³ný¡—“ƒiî‹s;‡wo[>ЛÇe9:{×oÛokt\¡ìC%Ý<4i`×êaÎ<.“íàîR¿y§ÉóW^{–³õ¦Ód¬Ÿ9¸ZoËÁ¿l­ KŽhq‚f DaQ¡Ä@VõÿøèüÂ)ÃGTtwrd2ÙÎþµ›uþck4y´ÊjšÝ§ÓfoùmXõoËÁ¿\É+Ž«•I9‡¹þ…¨0? ~ MêA­v „ÜBçŠ>,‡ß.p °HÅý7¸˜&Ðâ¸B”zíК¶÷è³zn þ¾i`°<8,œòiûëÞËk~ÿß4°XäÝ̓v¬ìíÀf²¸üÀ°ª]N8p3  4|Õ‡u ¾C`ˆ €b ˆ €b ˆ €b ˆ €b ˆ b =„öäú¹mëWõtvd±}C«þ8lêñ{‰úLƒñuuÅTïÝ8,ƒÁ⸽Wé ³ ©žáµ)Ï–G2 ¿‹É”w·NðCù@O‹Åsñ¬R·åÔeûä8a(Í}îâ~ #rÅsjÍ-éÃ`-ý+C+ÔM¼\+ ˆTé¯îh&•ó±9ªÒékqsU4,ÜSb$vYcq˵:ûº€BÉâé…oº×BɱÚ?ÆËC\Ì Ú[ÇÕûKƒGèè,jÒ]ñ,ǯH’ ÔAêí"b;ˆÊב.ûfÚ–Y±úÝ Óí¹WÇT-kŠ9BïPɬmù¤=Ø¡¬&â²…~a’©ëµ”}¡­õ§y{~1×p,2XLj|;¡J]÷ŸµûÏ9š•6l!ëüB¬èö†ÌúÖ¬¾«^³ÑˆQŒ½`Û^اèÅå\xµ[ý8uÞâm{?z›iôMÚ½rÏ“÷^+4:YfâºQ5ý­Õg%Ìón~ìþ{•VððD oÞ°cIA¨„—Yl÷ÏjL_ìÝžö^íÿ}«¿U‹n:¸6ÔÑ[,yò{m„Pã¿ã‚ˆ[Ó!Tû'¶® õsB­O‘YZé|Ž[>¨2B¨î„‹¦Ù/×6Ey×\f˜(KYrò^èë@ \ä§`ʼ Â%@¼pV¢&Äiتâ ?kÈÂî•e'ïa !ËÔ­%ök¤ÒgõðŽÛ®ù"!05ÿP3½Ø´E ±FZ¥ßQ8ðDkOkej"å…¦½¿pêåœ>ü|^Î÷“œŠÑ©µDÂCM+_!ÅÚÀ?áö4‹k×~“„õR¦ìí+ê°³¤•,Måä/+¢u ßB¯Ñ\Êü€-ì#ª2TcS¯ß^A˜*ãêñ=K~Ÿ=¼׊¾¼Êm†?«ÉY䨗¼epLùŽÅñÒ_ pž›0eÆNw«¿žäÒçZ2A¡ëåã´ãÅv¾÷Oú§ï»ý­Ãû\¡§'þƒ§#ƒéð@¢&B-¹Ïe2xžqc  Bè£ 3;G’8µ{%79Œ‚«Z¸9 „ -%S}@±‚‹"Úò™j§@§Öqó¦Æc_pƒÞѱ8Býµ[ðXjäe$Ö(wN9á´«yÛVâ÷*'¿œiì×`áÌgy:d=SPÌ‹A‚dµù¬·‡®ÒD¥ÁÌC¥{y¹·¨9¦Ò±óï³n dÉ·Ðktܨÿ眯Oéô@±Æ@ù&}bÿ¬HßzË-Í"dŠ+›™­Í{Œê´ÙL¶[ÎÚɺF~õ¶‘ýbŽgå?‚ø½²çìçYADUöœþšÖÁqâR„wUdʪÞ¡eIb›b 6ƒÒZš¡tšÔw1¿ýŽ hºÞ(3åú0„ß§—ñ)\ƒb08Eiò«ªc³‡HÄlfμÂ`(ªë/Ž•8z‰¯Ø¼Kýì#nZÀ&±^9«vg 2 BG\‹Ș†ÀlG¼9¬p÷”\ÍÈ—×ÎG¸ÿN5Ý⩆1n-²)ë;ì5+ë@8‘öV;£³(¤£Ú¦^øj1A:u“íJ'2|4âÚl²–Jx‰ÅñJQëÖ7ðûåv*A©·ñ­·S}pw “éhˆ<ß;ÌìF^xïó…µD¢?M¾ùE25Ì !Ôå`‚É D®›¯&l;Kw…9 IDATõôN®ŸJt8yš ˆ4V(‡÷•–qþ8_kTÀ&±®lA†Æ¼ n¶Ì¦A‚Ï&+ ±»ä.’ ɸ¥µ£…²è x§4yxm¾·^³‘.Í]å‚u J\ Ôrâ?Êü«*á®sm«1ÐègýÒŽž¬g³É½0‚ Æ9ÿtj·³[dŽp2ÒÍiÇ©îA­ŽÐQÇDá<6‹ëŸaðΚN“áÏe±yåÅN?bå<A„Vþ !ÄáU0L”|X‡âð«di—¤)kBNþÊ!â1"ƒø-ë¹Â¦É˜ •@kºC!–ÍŒÓC…‹ÍG®“‚„³žÓÝUê'ü'ÿÉ’»ëåNÞ’Ë)¸¾’¥ªœüåöuÁ¢JÂÁ—»õó%™G%¥Ußšúç{ë5ú1F†±E6õ@ñÅ@!ïš?/PhujÙëûg®íÝâ÷ûVc ÄÃù~­OÆ$htÚ¤G§[ûñõg¢õÄý݈åȪ·ø)™òtQ=5ø¿t:³TÚ½a¡ VÒ¶ B »—F?ºØµ,B¨éö7†‰[ôßtèRR†Ói¿$>Öÿ} æso–ÙÓ6!TsÖS™¯·D"„Êþx©b _Ê\ªÎ˜­ªï!¤3›Vï,?z)L…ßÚ¯àûÊŒ Pˆmî&XÿPg dü§ô¯.‹~€ÉÔ„FŽ?¾¦Ó%gGòS´œï'=ýH§Õ‰1šÖ~T§k/uµØŸ'øâR™s äN&­uAS±owKÂ~ÒÚ×YOUn.â¨ýšOY8¦#¤YºKû•Uœ…«ŸâV}kêŸïª×¨;%âGùÉÛ˜XAàZ<á©vBkQ‰›z  øb ÄÿNNÞ£j¨—ÅàòÝ«Ôo;óyÜò,b˜riÝ”ˆ²>,˧l­i®æÿ{žÉr~"Ó|#|âêà™–ï/ÂXœ¥¶ÔóE5þ<™±ãB~õ·Ð¾<ƒr –/ˆ¹¼{h×fN ËÙÿn‹nKw_7œŠÕâ»|“Ér~ 1³0©Œ Bhì“Âÿû@fV;>k¶»:˜ah5ɼmZ:³iÜ9UÏæbg®ÀÁIX¿½ì|’ñÔN!öíE¥!“‘oãéÃU÷fb7G›'¬ÙLºñtÞ¢ÃÝ­ŠˆP!‹)ð-'þu­†b6Í|"w/¯0ÔÖô_¢’®¯f—NznÿŸ©L¿¯ÒYä)d3΢&dûÿÓÑéSÿ|W½f¶ïÈô—çU½[Š],®0¬†dÚJµÑY"«½P¤0ˆü¯D•ò?€Ëë¹y>‘i6Œ u)¸@ɇ nå&r]ê D1NLŠ_cø¾üL¯/ˆÆ¢±¯Ü‡ô7XdŸÕÞÕ5"¡‹#A”¦^(R¾¯Çƒé´s^]„Ðï}ÖŠÀõ½ÿBÕ·“",ôcÇŸìY½Õ…Ñ ªF‹ø0•B¯ØöLƒ/ÇÅáe ‹%óW9¿uº tôÄ@¥6  ˆŠØb ˆ €b ˆ €b ˆ €b ˆl…M^%&&‚;0",, œ@)¾Û‡]bbâwû”Ûá`ÕKàJ+°Ä@@ 1% ƒÁ`€sø¾b ˆ¾(åÚPý–›Ë®PkØœM"ŒÐg™nu¦^dGLô*z\Ÿ¶¡¾î¶CHÍV+=&³.lêYÍÕ‘Ãqt©Ú¸ó†èw¦ÊÜÚ2«v˜/—Ë ©Ñ|õÙ×Ûæ©èÁáòÊ×íx8^LÑîËãª6uÄN\¡W¨ä·í™~eƒ²v˜ˆÃú…Ifl šÞߣjSOâÊ:8‹jµ’yI$]Rwo!ñp:8‰ÿ¨x!·Ó ŬÌwk»­u_Sµ¬)vä½C%³¶‡CJ¾†ßD. „[FNÜ{á@ªÖȳ/l‚ª4ä¬>Kg6etkÂW[½9,¾_«ã÷ß©´êÔ×÷~Ø@Ÿ•~çwƒáÛpòë ™<óí´&~ {þí4£ÖÃû¯I—k®ÍÖ߆õ].×¼¿< !ä8ܰ-CÃS¯)øž’½×0¹šÈx«?H¢OO<"ãyKŽÝש´DÂCM oá°cºÜænå¥Çnc25¡ê¶N³y"ï ¹)Ý–‰â€&*;œP Ê€ívÔM¿£pà‰ÖžÖÊÔDÊ M{áÔËE¡Ñc 4h=ìp BˆÃ¯jq YŠÃHVò@Í~žeš5#Ô!´!Yª¿•¦lD¹†Î0~A "B§ÍÖßžÉVAè,ƒÁäZЦ†§>ÂM œ›—ž«p”““ÊÁô¼,L©CHp0#_ ‹+²£oŠA°ÝŽºsÊ §]Õ‘Yâ÷*'?YQ;äki1¥4þt€ZøxÞäßO^{ð)C Ápr ÇñœÍ&¦®Sn?éC³·æöF1Q/.K ÅZ܃m¼›æÁa‰0\„án,BˆÐ‰™lw&Û]§ ×ℾªþVƒ†yÝ ÷à”žlc…Ý8Â$ƒt#8<±Në®ß\ÐÌüÛ¦)áavƒÃÀ &–¹2`;EIKu½¹Âl­‘-Ç=ŠÔ!_KCøEJ1l³©s¶]óNÔ}Ù‘[£;¸ó¡Õ¯XØNÓØ±Wä†å8~UŸaáÚì¡*&]?x”e¾sÛé×Õ(CãáË)¨[òÕ5(e˜úmI#„þÞ3À‡’|Ü”?ž`¸Z˜{DZž±Ÿz™Ç&•sC­Œšf rFý›–snSž¾!ä4¢PÜñK cés3ñYÆŠ×yé‚W*¾/·¨û¦˜•ùžm·‰QAŒmÉDIþT—| Jf7þ­èŽºí†B‹¥Æ]îêbXxLˆ+B¨ï†Ë2 öåݽa5½ŒDUsâ „.¥ÈìÞ¢Ämò`3ÚŠIPcšŒw1Ì=ï¹€Ã`ø6˜ôú‹\‘õvj#?ƒ=ïVÍÃIF·fÎ{IþwSj‰ÌDláÐÜ£¸‡e|?ÉÉFG$=Ò´öËw×ôè†Õºç‚‹X°ÝŽºÿ)ý«Ë¢`25¡‘㯩ÇtµC¾–†p€ïîL´Jðpì‘^N\&Û±lõfí¹o:È>_ìߺ¶›#›íàT±^û¨Ã‹˜UCƒÜM£ ›È~vjÔO­‚½\˜LNPÕ¦KÄYïÎmèÔ¨Š3—Åâ:WnÐqÝ™·ôhSÇ@A¼8¢lQCÄe õ ¶ÃJ0x €ï8 À÷\@børr©Çè-$° öÄ@ðÐÛÁv 4{a@ ð}ï½0pFÀ{a”þàûöÂø1~/ìÙ³gàJ+ú Xà{b €b ò¨U«V­Zµ¾eL…£Í³!ß„ÂFK¸Cb €B~3€ÍÓ§O¿9Éà[€¾_Îo?ê BˆÉvðmԮ׌ñ½]X }®4ñöúÍûn=z™)Vû„Gô1uh‡ª!uÖ“U˶Üzü*S¬à¹Ôlج{ïí딡ӢüóÑ?Ïz)%~š±i~ÿz¡/O¯Ø¼ÿa\¢ c…Wÿqȯ#:U×Öo7Ä>¾¹gùïûÏßÏ”iccëFMÛ°÷Dlü'5â•h:ù¯ýx9FYX‡èÛ5œ SÈÓbo.ïµCUj3Í6gÔ´¥î£c&µäÏw¯ØzðÉ›*äR¹Nß‘3û5 ¡£vÉñ¼UÌŽ:K-.ý¡É¡tyç—×õÑge¿XØfÐ žW×ÿ®þÏ {a@)äÖçÅ›öݺóðÎ¥?W:½sÉ ?îäÌ IǺö™|ú >sÝÿbîí[1Ivs‰>+jÐÄÃWYöïb.Ùòsór×6Ž£ÓœàÅñ¾½¦½Rºýºþ¤>¾ÚÝuäïOuõwœ¹ñðvôàš’ sžö³a­‹ÛŽD œáöýØØÇdâèmïF.Ú~ëîí ¿6|óðüô¡kôétÚ焃Á°ºNðôéS£5ƒ‚¨j©.EsV»ÚL«’³Ÿné1aéK¢ñ¾ wî^:ØŒùzù¤›b³è¨]B‡ „bÙá䂨j©®U(º†™T왳#ˆÑ«Æ—óä9º‡Œ‰Mºýs÷Píâô<ÌŽ:Kø7]PÖ‘-~¿.NŽ!„puÊÊ—ƒ=­kx鴯 JÉ«+6_{ø"=[¢Õá9~uRÎ$š,C s5­ØÅ—,]þÛà® x®eBÊV¯9`ô°ªîm½<±lØ_‡xåسóÏJÎ2ýHš!4£eÃüŠÝ5¼íàáh*°³WΦ“í‰"pŒ¾@û‚B {¾ DUKu­Ç@–»Ïº™”ÿ¢DuöÎQŒçÕ ¡%Ê/Çšb·ÚÅìy:&˜u–`°Ü~ï2ì`âŠS÷ Oÿo¹T‡»•WÓ‰Ïb (‰¬ûyô¾OÒV“£võjîí‬VízAX­8cï߬¨í·câÒ„’ñÏ?Ä?¿~#óîùùÈòÑÑYËŽhpÂÓÃÙcæ ýù‡O¸'9¶¹mN^"ÃV…ãBKSlAT¥®[ÌýN[Õþ*ž·òÄ·±FÕqSY‡&¾Ýö°üìš§¡ÚSºÀC(5À^PÚ8’,C-ÒÖÛÅ!$O;d˜Û?È!´çƒÄ´¢£Oý¹+¶ž¿~÷áÝk;WMF)3¢©Û:ppIŸþà}º® Óû:!„v½–QôšîÖQ;„Í`¸F¢Ë™˜•Ù猌"RÕüÚesÝGm¦UÉ?ùòB§3•9~È:‹âùþTtC±Ð=_pL[tpm:¹¢»Jxñß„{ÿ|’2Ùn³ùÂC€J(½Ê8#„–Ÿ|¢ÖáY ~ûe“aî€Õ\YÌý£gÝx•¬Å1ÁçWÿü1DŸÕcìïgnÅ~‘(Ø|7O„SPOê¶\ÊuØ{tuU®<í¿ñ?ö=“¡O5Ú‰É<=iþý÷™8މ¿|º}`ư®vUÔéáÇG->úP‰áÂÏÏ—[mT=Ì‘…ºŸ;³©ªV›£è>j3­J¼ôg6ƒ±}Ú†$¡J-þ´yú6ƒ5`ñ ¢Š…îù‚›`¶Å®¿ÿ€Ú:yF^3ý¹0k@IeòÞ-}ZF܌ӸAãÁ³¶V¿Å0×5¼Ï™«;Eè–ŽíÛ°^£~“£Øfé³ÖŽhôüÌ–ÁÝÚÕ«S¿ÿÔí ; ؼo²Õ望ï<±±Ž§#¦þ¼lt·%‡#„Ü*ÿ|fïòvUåó†u­W¯a×ãÜþÐfÂF»*ˆ@j‡LýweÇ•ï®×4²ÉÐY›ÃFn1ªþ׸N¾ÎcÚ5¦ù„ h;usÝGm¦UÉ^µÆžX?»*ó¿í#·íw¯2sí‰ñu¼‹n(ºç n‚Ù=ªLoèâ H–#„Zψ„' Pš`mN?{ö œ¼ûw`ï5/ÙŽawîsd2À!À·NDD„þÖ‹àjñûY¡v“—A”2à½0À<{»4["stõï3{çÜ~Á!@)öÂìÇÒaø).(±{a°`?ëÀ· œà{„Q¸Gà›Öø1>ôåËpJqâë x¾°Ä@@ |Ã0ÂÒÔnQ›SXò¿–Û‹A«’iÀW‹üüü*4\`š>¿A??¿oÈ)FÚŠÞœlU¡ü¬÷`¸”Ö‚†€¨ 4—íY— 6L¿_»WÞüÛuPÚÝmmº.¸ëÖòá‘0\¾£DÉ)Å.(=1Ð_ë»mwÐ0åÀøºmøË0åõéuÝ[Ö-T¡ZÃ1îQâ9¤QöñÊø¾*‡…—mضçú“O©Ó¥©±3v¨T68 ¸\ë^“^È´dö-j[¯jp`pµúml¿e¸®c©u³ÄŸZÒaòåÕ7®ŒhH!A%ˆ ï Õå‰ÂµµÊUOPa¶:PòÓYêé$dqEµÚÊc¥yY¯N¨ÚÖ;q…^!’Ù[s$Kµƒ:H½]DlQù:ÒåuV›Èz¬©ê&¿9G‹#ª5ÅŽ¡»ŸxÀLµÏû~½\Q)PÄb õ·ÿíQµ¬%æs„ŽÎ¢&ÝÏ t³$Ä&MWô)äÿúú,;”±d‚©|CM̺ݬ Ôr®lPÖqXB¿0Éô˜¡¶¿÷(ô4¦Âù®‰ÁÄ5x°³ø­³”ÜïsùÈ(¡Œô”.>N›_|Ч|x±ÉɧkJzBHŸòâäd÷ Ýþwñþ§”Ô·±×'· ®1ú¤>«“oøšC¯>§&¸wñàØn5©Ó=Ê·ÜvúVbrjÊÇ7[§F4Ý OÝ?ŒïßjßåGÉ)É.ïkåǧӺ±!'õ/Ódøƒ)†Y–$,ªíÓiG YìɾŽ!]öÐqš‘ÿ½*I߯¤jB«ÀÌ—µVëÓS¯+ø’½×0¹šøò[8T¢Oïá#¿]óEB`j<þ¡fZo1a„ú‹·'•þîâÍ7uúÛ´› Ïʲs1:¥–~ÆævÕž¢%«µUÄÁÉ[÷JÒw1¹šeéÖûGªè1UÆ’¦…É£,»•±TËT>µÛiš@Þ&‘ñ¼%ÇîëÔZ"ᦅ·pèQU­ÌR¤Þ£ÖÓh<˜ _Û@Ô#·¹ëŽV÷uGü¹Îõg×¶ Ôg!„Õ-ý|€?__E«ˆ+W}Jrâe„P¥ €ÃñŸ"œ9Fb-¥‚k!º&¸‹šW+ÜéÐã9•ÜõY¢ø%•š¯µÚº‘!Ñ3Ú ½VëÑÙéŽùWÊ,I¿ÿ;âÇ—‰/·é‹/kT±ì©§ýüøVFñ7q-áè.ÕÈ]BÓCEø1·ÕõFe<9Â˺.VZa0„áqk½¢ç&üøu§fþ9rf—U¼ç6<0çV+×9ûËÕRW}•£™î=½¤„c_ÜòɹÅT¸£«Ó¸[B½ibh£ia2Å(Ëne,Õ2•¯¿µävš&·cE.çÜVÔÊ‘“õTY®!MåSke•B÷µžFãÁT¸(^Ô\'ÍpÒ æW…ßrÀ€¯š”L ?B62¢Æð;Ï롘šMw½x¶Í@d T)8@Š3 ן fzzBèܬÎcN‰»tÿ¡QÝÚš·®èÇÓ‹µ”®Ì¸3ë×E—¼Ê5!RN… €‡S<Ø9Á Ž ‚*[mÝÈø;užûãÆ‹³:–ËY–0«N8gǃEµ½Õ¢+5;ÅÄß›CÇiF1" 7\yö–-ÓÏ4Ç=Ba‚ÒÃÓøÏz£ã¤=ûrš5b7kË®ja¾a0„gfs†F3Ÿ?âróÒ½¸B1®_ÌùG¶È`5¸‡a<¡šN±ÔBLc K6Ú4‹Š2Vå[r;MÈ[7Ž0É@ŽžX§u§ÖÊ,Eê=j=ÍŽ#iãBEœ#nk0TmPc,;žYJ,Eðn<ƒ½p]û>xðçÌë²óOÊ8n&~JMMMKKKOOÏÈÈ CNË£ï\T¯ /öòÿúEV±úuú_‡ÊšM¸ó*5=##í#AäB!òïöÑiÝ÷*½.\YsaR»?ŽÇÓÔÿ׿;™ðBèõ¦%V ·Ïy³"eÒ6OÝ1܃й[ýAÛ›\^_à5.Ëx­îXIÜû/Œœ¢ŒŽ€ÔëÄá'jv_ÉwTGG 8©†yèt8îAú U‡Þxj!·Ñ&lU¦xº©t4Mg<ü¶ƒ³w° !·RÙ}›~Úšöß|ðÜê‘Ôé{SdëFwòra1,u/Y¸Ë{ y+IØB³u#\Ã:Ÿ½¹õþœŽ³ö?¥#! éʪ™[¶}.:ⱬ¡ `Û'b÷nˆƒÅ@ÒÏ2ý—@ÆÒçæ§»²õ8ãg8î8èüö£ó‰E²ÜÀσü§Oñoæðô.O_ɬyÇVG3æžÃ ØÝ¶ ±d£'½WåSfærg3®h”¡–oÉí–L°$§¿#êUžá+߇[¸#¤P¼g‡žFƒZó#2Ôë’ˆÙû›ÂŸàû‹ƒ½5öáÃØ­l“/Žã¶N¸1¡ç–3÷E*L«’¼¼~ÎàVú¬æ§ŸºóL¬Òê4Ò'×ÎsÝQ§wôtœ{à?¦Ë|oJÏyM,ï±­ïØ+q)Ž%¿¸2¶ï6:­›Å)°ÍÉ;ûâ—ö˜¸í¾u L‡¿Õ]ѯ¯ü—Eöúµ»7câNL‰¡Œxì—6yoÔLÛí°©½ìÀ-J‹²?èÿ’ó&OõΊÃ×t"%Ò©‰‡çµT§¦<#¸Ÿ9]/½%g¹húÇKƒ¥«bB%Ò*‰g·µ~”ت3M!䊔%Ôföžªþ($pŒˆ¿¯ÜBNf5vE›cp¼ð”1Â’|Kn·d‚%9³ÖrÖµ—~„c8Jz¤íÓ^Ýk½cáŽBñžz g26/e-øA*›Àw„€N!¿F#ëñÑÕWuu`³]k6í¶rÿM}ú­ýQ]Wuâ°¸NžuÚô;ø8‘:=þƦÈJ,&Ë#°òˆ?6qjÅøjÁ,&Ë;¤Ú¨¿ö3XŽV[§0äsüùVN]æ´*!õs,ã~ëC }§ù_ð\ݲšˆÅx•O\­1|éæÅe‹".Kà*ž»=ç]§¸hUÏæbg®ÀÁYذ£ìœú½0‚ äiÚþÂ>Ks^ØùpEÕ£¹ØÍQÀæ ë´–mƨ_q2›BGymÉFµÓMâå$`²…åjJîÖ’Yov+*ø ™ >¥àÊ¥PÈ7ëvK&Pȹ´NQVÈb|ÊŠ§®×Òt¬)Eí=šzZN¦Òñ¹Â89¼qÀ÷ô^XÉD‘ñ¿*-/}|½»ÚÊøï÷Î[<ú·3ý*ï…À·HÚ-eäjvÒI¸€»TZÕå×Õ‹R=Ô-#þÁâQ k9V ª…ÏF¼ºõþ<»%ÀÏ¥ƒ\i†¿( Ä@ÅÈï µ3ûµˆû(pöû¡ÏïG'U/êýüüX\ß{.Õu¶ÿë/Ìu@\ÂGƒ!d90ÿ8å2¯à[xÒ–ú½°ì…ÀW¾®1À÷ñ^À÷¬ð=bü^œ‰.fàL4|`ˆ €¨4àççW UŠùëE ¡àÂÍJK80«‚¯ “É,†v­Š²¯-³µ¬ÚUò)Ü/:ùE­g)Ü”dž-oÔzµ][htaÄêÖA‘‹c¿È/— àÐjµõøyÜ–cw´%æ ý¯ô0,ó>y‡]ûÇÍDÇKÙ'ù[´ ‚à›“äCãÀ÷ ©ÐªëÏ«÷_3 ^onæèåØlók³u™l®O™Êý&G¥kñBÔ6G8‹ãT±×¸ÅÉMZY²ˆôƒ%‡è/L¸iö°ˆ°6ËÅ3¸uÏQû¯¿ý†º×föýëÙ¶#ã ©;òCãŽüó|i¿LÛ»ûë|‘ÍÈÈÈÈÈHþøþÎùCÓú7yº{Bƒžó$:¢Ú-†*vC`z[(ò‹ÍýÅ=‰f`Ÿ’ RábÕ.à›´@‰<Ah¢W÷/ÎÖòÑæÁám~çŸ –.Œ]-*váR³uujÙ“‹Ûß®oÔsv‚Â' IDAT¡+¦ÓÈŸ_ÛS!uG“î{ PkEm‘Uöôª³-«ò¿WŸÊÔš”·wçö«½°Ë7Ô­)ׯˆk®éäåX°.0ÿ›‰Ž^W׌½žZ y— ˆŒ¢‡ŒòHû4µ¾o½9×È„Û~k\%˜Ëf»z—í1>êCZº>=ááþ^-ky89°8¼²5šÎÛz‘¬r{×Íj”åqXîU&F"ÛÚ7oP¸Ÿ“Á0l!ttɘê!ÞÇ+¤Æä5çÉtÓˆlâÈ’1ÕC¼ÙL¶wHõ±KZ½~fdµPG6“Ë÷¨ÿðk É4½AXÀ´kB÷þ]Ø""ŒÇf:8yEþ8î©DCæ>?¼´yP6ÛÍ7¼ÿŒ-rN-óþö9µËùpXßrµ¦¬»l˜eI”%ÌNZFé<—zb,O%:5ÈÉ/^¡%Û¥¶îÞ?³j—5¯­©uâOFwªïÁç29Nm†<É•ƒº²~j­r¾ǧ\í9ÛïV§°Ú´!£ÏåõSk•óe3Ù¾åjMÛpŰäÙe£*¸3 #!JRøNu³n1ÛGv '[Ç€ž—ÇW¶©Îç°<ËÔ˜µå… Ôr(üLÇi’„èŸÛ×÷rvdqùáµ[/;CÇ^}"„\ø¡YZ]ÞÖd†ò]žËµtª›:ŠYêM ¯püP¸¨°†.õSÎ|¢N9?Ò¿ñ¢§d‚,e³GÅùAŒvÙ’"³TW+cqýÌ6mÇgÖX¸â5‹`˜BS+S‹ ƒqg33 F ­Ãé«ó½õüúÜNÍÿÔU6¯!r` Ü|Eýg¨äÆÝß®¨]NÈa |ˉ§¬Ó $ÈmK ÿßðŸ>+õf/¿û )1PFF“<ïúë''»Wèö¿‹÷?¥¤¾½>¹]pÑ'õY¼xÃ×z•ð95ùý‹Çv«©O~b2Ï½ÎÆã7>$§¼zpqf¿zd[Í'ß{•hÔ4BˆçÓlÏŘä”䘋{šùðGˆ5«y³½£gãç$§$?¼°+ÒӱߎGd·òvŸ½ó!95éÍ£%ƒ«ùÖ_R1{¥'î¾’«1YVÒúÑþ‘ëõYi7çxVî}.æR‹ ??›Û%´ö”›2?ŸŸÈ÷ks*&Q­U'<<ÙÊ—OfQˆ¢PÀÒ"y±¶_£‰dgº—ëyʨ¤%២Ç9v8û8I­U'=>Û!À‰úIáU©ýáÛqR5¦Ud˜ß2¨õ²iubÌ©6~NϦc5uï$Ìón~ìþ{µVðàx oÞУId± ¶sã¿HM%P(iÉ4«[RÕ´ìNvŒÔësø ÷^{.Wk¿¼Y8´±M&·Ô~¦ã´>üñÛ/~‘¨0µ<þá…i½ëб—ìÁu|û]M&¥}¾ÜÇ·î&úÕ)°¤EoZòjÇ%M qèÚ„äã ¾oòöêŠCo¤‘p¨cÅ¡×,Ç@/ÍÆ@ö}fÍÄ@/ÚZ™ZD3jàÂÝù^luR/±ã¼µ»ã%¡Š¼M»©ð¬,;£Sj áglnQí)ÚÜJÎ÷“œŠÑ©µDÂCM+_¡Q dxA¢\tôhû­Æ@iɯ™lýõÄ`—5ϒȬ䤫§œXÇͼdn‰elË苯̶µãõGÓ¦B¯¿!Óßܘä8Š:âç4þêk2ýõÕqN~CÈ2;_åµ’òé>‹ãU1б/мO ò‹ã£¿žêºÃàk‡FËu®C!ó×`—YϲÈô¬g³É, Q X„oñ}{“Qþ¼òî»ReF%- Ÿäò[\6™•7—þ£S§Éäð+‘òYý|¶Kð¯t¬¦nkL€óŒØLò63vºsÀ²ØÑL…Õ¡‘’–ü@³:ýÈŽádǘâ:%æ‹Ý&·Ô~¦ã46󑹕 j{ÉL»=Ä«zYliÏawÓèW§À’b½iÉ«?–4)¢¡kÓ™ÉvÕ_ã˜4Â/R¿©>»W—™®Úê4Éoþ›Ñ94¤ÓnSiö}f „kSß>üí§p¿ú«É\ZZY°ˆf ôvïDw~`·Á¢Öo‹¾ñØìbIçÎ,¦Ì@çY¡Â)¸@Œë,Ρ„³žá3”‚N „ëdL–ó7¥äÅ@î&‹Åb±XL&SŒÁ`ê³v ­çàQ¡ç°‰QvÞ~þ¬îÆfƧ¤™m+9=Ãl ôÚ |zJ<“íF¹°™ñ)é Ç3Ù®–,2kcÁc K)žæ6ÄeÒƒ ‚ ”ÙÑž³úá'SÜØÌ|k³Ú,ê'…<õêx9;äËÓ?¿Õ&ÛÝ«]ÙÌl­Á6Ÿ6›Év#‹iÌ?¦¨”¤3%ØQúÀÍád‡|w63ÛÜ>MÈ[j?ÓqÚñ±½*7kËžc/Såd:µ½dâ˜(œÏ¿/Q¡ßâñ+ê·wiV§À’bvYòjÇ%M qèÚió"†ôû#j/xLfìVvÄýt£}jƒåX±×¸%Éj3^²ï3k´QËu®þX¬&s©µ¢¶ˆf D„"-nߦ¨iãiÛ ֦߯{ßÐ87Š<9KÀb ˜Lƒ!@HÀ`r‡· SkÜhñ¢‹JÊË½ŠŒnmrNèfâ§ÔÔÔ´´´ôôôŒŒŒôô4}V§åÑw.ªW†{ùý"«X}Ïðœ¸YÉKo™ÂQË’rZSG 8© Ã0N‡ã8A8®³¢7aÞ [EÑç·=öþ!·rn÷mãíw´µC²³"{HÛÌ|’øà B§ Ü’ "³š°:ü¨”¤A«îp¢óGј`۰Ǧ{¯/¬m\–ÿ0zGÇJ~½ÿºIÇ^²,· ý§ìz‡z³iZP· ®,ýêv(f‡W 8~èhR¤cÏòÔ]Žô×'&ž‰ý³.ù²U÷ÓÎL/dáöSñS’?¾»vj÷ðUõY•ÚúçØ¥·“S?¿?µyϧKΙèãyõ·œ¼õ)9õÍ£«sÔ·ñ|šï½ô(%-åÑ¥½Í|xC÷眉näÊ]r16ÍôLô¶><Ÿ¦{.Ƥ¤¥Ä\ÜÓÔ‡gx&úëÆ@ÿ-râ—[uä–@¡Õ(DOoß­&…ÌOÑcù~mO?JÒê´‰1§Zûñ鈢P ™›Ãú‡ŸtÖöG^onéV±nÃåϭ|<5Ê)ð‡èØZöÓè­œ‰îëËòÏu…Ks£w¸›a¤ÕIN·ñãþd‡ÕÆg¢æûµ>“H:Óð|¥¥þ¥P’ÎóÅRõ¿øÕ»ñƒ@¡Ó*ÞüwºW«}dÓp²c ¤^›Å÷ŠüßÍ8¥ËJŠ]4<’ÚKrlò³Y§Uë4êÐÕGB…S‰oíŸÎ÷ëi»½xgOÞâ[¿ñ¼»ç=3írÅ(zÓ’W 8~,iRˆC׆H§¤%];±óç¡AÍÆ ´8Ao¶µùá¨Q•£?„´Øþ†þdlßgÖ4k{“€N‡lÐÊœEùNüììíZîÇ“w_É58®‘¿º{²[Y—¾»Þês+4ï·ñÐ¥_ĘN›ùñyÔ¨ºÍþþ†Æù§s=üm5¨tâ‹VÑ „F?½¥ßMœ;CÉù~ÒÓtZ‘£iígæLt37Áú‡:Ãj{cÿ>}1›ëP¶qÛ¿¯;dxj'##ãñÑÕWuu`³]k6í¶rÿM}ú­ýQ]Wuâ°¸NžuÚô;ø8‘¬rsû¼È*ÁË=¸Úä5g¬Æ@G—Œ©âÍb²<‚«MXy–,swÝè0_W&ƒaúnüáÅ£«•ñb1X^eªYr”"â)æˆ ˆW¶õh^ÓÍ‘Íæ¹ÕiÝ{kô j™w·ÎŒõb1Y¾å"~]{™Ž( ÞìžRÁßMï4ŠÈS}âs=âäZ›b ‚ nmž‘§íšh‹Gaàù¾–Õ‚XL–W™êW_4lâÊú©å|YL–WhÄÌ­w «Ó·Ú4ñÒº)e}X –OÙˆ©ë¯Ð™(”¤ó4±T]-~2¦[c/'.“Í+W³ùÂÝw­ö‘MÃÉŽ1@Ä‹#ËZÔå²Xž¡s·ß¡6B}?›uZ\ô–žÍk:sYÎÞ ;½ðAj‡½± ë°Ùõ—=³cðãWyTœF_1ŠÞ´äÕŽ ÖÐ¥8acôwXlŸ ðæúGí¾¨Î]à<÷µñAÿ³w×aQ-}Àg‹îZ@@ÀÀQ_L,Œk]»½**v¡("¢(z‹Ý¨×EA@lPRXº¶Þ?wÁ…]V$¾Ÿç>÷Ù33gfΜA~̉MqV1˜öC o•ø™-›õ-r™ªÑ,Yz%åˆÄj¾ç³ª[3E&ÎT4kÓmõû¢¬×wý5´»¡†ÎÔ1²°Ÿ½!¶€Wç¹äÛÀS,”U®}Ë/UaÁ0ÛLu…t¦"ǺWŽ?¯Ôo¨<ˆ=]Ï,sá΢²1Ðë£yMô9tZñ³ñùi7T”›¤ñ4¢‰MÄÔÔÔúð.6›]/?”BOO¯þ¼ú,)`Ig¯.±—†ÿÔI‡tÛ\Ëûz¯’ƒÚeMÖÉ·.­´0P?…{tt{DÂÝE¿¼æ½N÷ºòt•õß«ˆ1Põ(H í×rÂæwUå~tß.Ó6ìZ5ËÊ\31ê‘óûOãî8[á€ÚHÒ×~Uޤ—GË‚‰“Õ2ãi yýu—C*B<»qgõoþñ›ša“!“=ï¬DP[ýLÔò‹7ÕÏu š£^] ¨9è@ P/ЄB!Fê¬@}$þ\f¸'à·À: @ €¨fa³Ùb*,Y¡(ïÁ–Ã÷ÿdÇö·¸#ò÷F«!•Ô÷ˆ]ž5nÚL¯¨m‡¦J‰œD‰B^Æ·=;´6240·°>mÉùÀTÖÔC[£w:¤q?Ó™˜}Ý´ºí‹© ñ ‚!@ ôSRÊøUÕþ’z’/Ëj±ÁNS^–Âgþ²;žÖØûü½Øø„ˆ§×m}{ë*K^³kóìåÉ?Ó™Mëüïy†­ßôg^ˆª›Í9³mX¯ÿ5l``lÖlÐäQ9\QnÈq7»ö-Œ Zvè½æï€²Ë3¢”œOwG÷kfnbhdjc7ÂûRxI%’ëyâÜiŒ}v¹ó嬧c+]ƒ¡ªed;dÊþ‹OE¹}]l‚<žUz@r÷_S_<ÃrÞÖ%ŸÄ\QzÙõ*Eô •õÔ×µ‡U#%CAE§ËPLjì’C¾³{I[s6‹Áb›·]ºçnéÚü7;Xj2ètI•+©uÈâ—ÄF‚¢$#ý·ù<ü b Ê·óÕÌÍ'^Ç%¼yq{˜^ð˜1¾Tzâ#=_9þ7ösìÍC+Þîš,¥’yLWûseàË÷ñ±1'·ÎMó_Vaý¥ùÅfo&ë7Ùš+0þMÈ•”«Ù|BV¬_¥G#ÈyûŸfBoëêµ*¸ÂòÔ‚ð?Tâ÷ð…{¯}Ë-Jû2V?°*=öÜä!ëC\üžäæ>=µ&dÝà©çãDU9ÜѹÏ$UîÑ<~Ê¥’ò ·æÈõ?ÐT‘‰$¨uªé{ã˽½†ºŒÅf³G¨­@%ò cM LLˆ&„¬¶j¤|:t¥…••ñÆÝÂv§h/± μùl©Â*Û´¤ú¿ k ^%$*Ñi¢½Ê^e%~<·ªÿÒkìhÕ²ióÖ]:¶V¤—,Òy†F­’?Ê22bïHòsÚ6è÷$ñ±Æ/Œ7Õð:í¥2½x1Fìd‰RIJh4ÚùԼẊŇ\ð^A­3¯(•2ÛPUõzì+*ë[ø2³9Ù‰û¨½Î}Í¡£(¥òŒ7ØFd§œ¡bg—&š¦(ã °$‘”ûD !„)oÆç¦QŸOÍ›ÕHM”¥Öh¶”ú·O°ܾçœn¾gýߦä—Î’T¥™Ûo||æÏvF©ïC|\š·±;òí—ŒRjÈ"ºƒ7Š1äwÛæ,|^™¨TB˜ ùܯÔç“_óV´ÒeiµZ™÷µdÉjˆ¶¢ôj5,VMV¸¹(8•R~}/Ý ªß­{H½KwÀfÿÀSníÃnŸÓ¹åt¯'?ÔP[VpVÉM3 tZÿûÆùÙ4FI,¥ g1bÊœu›¶Ÿ½ùôÁÎÞkÆÏeq³Ÿ³T¬+w¼ç] sm'ºÿf蕸«ó.VÛ³dxlÕ¡aÇ&í „¼Úê<ô #~„1Я7JWiÿû,ÑfÖ‡ ^ÞclÕcšã’íN< =uÝkƵ5ÆLíx G´ÙOSáHBvéÙñG4ú—»¯‰í,nNˆh“óú¸šÙØJ///ry$=©/ºÿ†_˜Dµ<2GÑbÑßðE…ó¿^}fÒh|Ùš««ä^ÒÕè-Jºã¤ï"Vyƒ^>–)ÛwŦ­8®½§«~„1Я7g󰃣gßyõ…'à%DÞ™=ú ”¶ã—^~‘YÀåe¿¸wCN£ãµÕey‡  ·D›+\úì´Ÿwóù»|®PÈÍ÷üæ\û}×8Q¹†:¹ü0!-›/ॉٿrŒn{'Ѿw]ŸuXÑ©Çûáä<ÍÞúr%'….§ïÝ]sžßBÈš¶º#û|âä xùož]Ô}º¨X'5¹}Ïãey%‘ÓÎá»úŽºËðbC®Œêëmïí$}ñÊé û6u\Ó¿_ÎÜ xÍ8 ªP%Þ‘Ø ßV¿ÅÍÝ'÷6i`Òoš{cǃ¥¯F‰98µÍ•­ Û6nhÚìëÏ¥¹¹ë‡º§o멳ö6§Ú4{ðŸùÍö-×ÌÔÐдٸåûZ,Å­¢ú_í<áá ðó?SÉV—ºù^_ØFÆòbÏ…Õ IK:{u‰½4??€¨ª ZèµqáäV ÕSÞmœ9-aÄùË ZÕ¥Pëb ‚´Ð~-'l~ÑQU??P{Õô·Û­µá.ÓýÕ§t}óþ£Öž›ß çìw†Ì4C^Ýå@Pë©Õ¢kauRm¼PàÁ@ P?ˆ_ ¨°õ‘øsa¸'ºšážh€ßë@€ ~`bjç•N€:Æ}Óf BÍ„u €ª²jÕj B…u üÅU"7'ƒP“aA#<ãìˆQ@ T¿¤…Lô~V6=xß´×ù<);†øLÈåB¢Ï¥>b ZCA³uÙD!?sÕ*?)ßq"äe,_qB $B~æ¦%Gø6Ä@u¡ÞPž!­SÃ\A•l«Âˆ ª¾…¹8öî²×) b zDN¥×Y{æsK b zD­IW%9íö'}Só!^Ú¥›)ù|w?¹¯@ T e}8×ÅÔhâ<÷÷ùÄ@õFî—×BcºûÉaA1P½¡Ü YÿÍ0åÂU@ €1b Ä@ˆ @ €1b Ä@µ4b³Ù•È*W”÷`ËáûkÈ€în9pG$&@]ŽÞbla<äè»ßxnÚL¯¨m‡¦VØ1öô XXvúËiG"—_‰@]о¡‘…elj 6¾ÊâR¹SmÞéÆ`nÔÙhçÖÈMÖFnÝùkû”’’"{áäÇ˲Zl°Ó”—¥c))))))I qÎï6O>1hòÙJ÷°¸ªøØÇWôÔÞw •%¯ÙǵyöòÀdÌ-€ºå%ÿs[mÖ„–Óǰnø&ç‰ÒÙlömï¥Û45Ð×'„d'†-ßÏÂÔÈÀȬ—ýüÈ®¨ä£Ck{whidhÔ¢ƒûÉ¥k}~{}Ÿ½©‘¡EÛn¾ÏÊvã‰Gp§5v²tL„Æ`4nçäs29Àý'‡Æ`éš4Ÿêr$ëóIQb_› g˜[u3záîÓëdBȬu6û7…•ÎZ uì~XRr2!¤ÃHnów½x÷)þý‹ùâ'N¾$*6q{Ôòƒ7b?ÇÞ<¸ì…ûˆU÷ÅšHyâÞwÑ•1ëÆÄ~~rq‡b膲Ýð‹ÍßLSÆŽ•Qô³ã'à¥%¼=î1C½Ñ Qšfó Y±~˜[5M(–ÞNMM•e7!?··åhÿ—Wé4~QbûVc_?P¢Ó!l6ûP̧AZ å Üt“&ƒâ©bóî¿^Ý¢8|áÄll?®àCØ*‹º¶Îº±àp«•¶”ž˜¼JH¤š®°cÅWÙ¼”¸W‡ÝN|™öê_)•—ìò}¢X K¥éÉ;¶ÿ] ò Z%%~”e$õôôDŸW:BÜ7mƼ¨rs² !Ê*ªŠš‰Y¹Ý¾E¸Ð'¹+Òi„†œá¦Ž¹«Ã¿yYëR¹ý4K ü”ÇN ÝnEqr‹!4ZÉÊÓœ¦ê¢ÏMóRÿGÈw+='Srƒ[iþÂŽ•_XÊÍ®GL«Üá—FBÞ·ø×ÇÜ̾vjæ@®¯¼~‚½­$E7å:ùwrqxA+Iß0pJδwww××Re Ø Kò„²4E“žÝV…œÅí¡!'KǨØEÈ/Lx¼ÑaºËßQ—YýÔøÑ˜:&­æï<±µñ0BŠc nös–Š5æ@MV™ûxù1®1ôÈ„¤’Ç£"é¯]còye û’³Ëa`mUä$+µç]¦èsÆ»=Jzâë(ãØÊ;£Ó¥wfŒ™ÚñÎuŒÆ7nÙm—ÿ‘¨Ó’*z<^B¡@(Ìmr^W3‹¹P×b ¸ Îê]ÜõX%ûÒYzîÕ/Æ•-ü‡–‚³ßÓÿëû'‹Fl)uhÔÌ[ñ</>âÖŒ‘í=çˆí;Û{Ê‘Q“/>}SÈåsâ_íX4¨lý]–wÚp«“SïìÚš·ôFÂÏ   ->j÷‰ìnkDIw]ŸuXÑ s  ®Å@{6GØ»vKìêjá±§lá-ç¶Å˜cnlÜmäJ½iKg[ÔÂcz“&}¦yX:Ýlg(¶/»Ëꛞý|WŽkÔиãÐùyÖ”­_ßÖS-fímNávŒò‡§ý³µ{¤,û{b‰úúFN¥9æ¦ï*«0ãÞêhÏ®ú˜[5Y%Ÿ «Q^í<áá ðó5¡3FX]êæ{}aËã¹0€º Ï…ÕpÌ:p ­æ_ Ÿ_S:3ó|øL„o¦M IDATL+Ä@µB¹ß öC_Ùˆj„;õ Cˆ @ P‹á¹°‡z§T)¬Õ,«V­Æ Tƒºð]µZéïÊ€jƒkaP#Pß•eáû㪮…Ô\¸6 Pu°5HÝ^óÀÝî5 Öj¢Ý0U ë@Õ*9)¾Â2‡ÿƒ¨jXªãh4𨇠KþÚvAÅ„<ÎÞS-Í ä™ U-£^#fž¸ÿ¶>pZÍæ ]b :Ï×Þúà·fÿÜ Ï),úò6ÐyL[ÿõƒêó€x4º2öÄL @ TÇ-ôÿ|{ÿ2+36‹ÁPÓih7röÉÅë@4íîî%mÍÙrL9=skçCA¥wŒ<ëѽ©‹¥Án¯ÜÜ;»—´5g³,¶yÛ¥{îbþb Úª©"óê§I¹CÜ"ÖŸy–Stf]ðªÞóo&PéÉÎ=Ö¼XqøNF~A\賘M]—>’TIÒç²íâל‚×÷+=+y9á÷ð…{¯}Ë-Jû2V?°Ÿ ë—RåÝe·Öv›ç_Þ3ÛVÌÉ> rª6W×v¸T6+öÜä!ëC\üžäæ>=µ&dÝà©çã0…@Fø®ŒßLì»2ÞŸÿ?‡ó¶öûu°lÑÚºG·¶Jô’›š"¾y´Ñ¦6Ó"Wš (ÈŠßNYaªÞôIâ4Ce*‹›®¢ÿWav(µuŠE–6TœïÕ^W|*ÐhçSó†ë*R›¼‚÷ jyE©Òë—R›P( ðž1boê…û~Ýô•IJÄÊSï‰{?PqIAÁxSƒ®wãf7Q/½ûlCUÕë±[¬t¨Âß—™ ÈÉNÜWcÏ5õ~ Ñsa›¶,[æýÛ(òßsaÔ •UTñc€¨îÇ@„üä¨ o„E½Žxðä“òÖ‹ÿÎî¤GýîÿÊåë0‹—î„<SÑœÏåB´å™!Dø.ðË4YŒù\-&½Ü¨¥Ü)õK©íêŠ~Sü›¼ Ùi(Wñr£´ˆN”—ù¨Ô÷‡X´’Du#6Ÿ§Å,޼t–¢9Ÿ›Q[b ²a!¨¸Vã(ê·?{éÖÝßzûòÈ‹N*Éû.D)Ùà É«ìÇçóP(¤)±ïu©¢ú˯­ý€AJO½óùçÇD³åâÝíŒ8ü¦¢‚ÂÚu®EAØg@ Tß™Ù-.Ê~*ÚôŒáˆ>§Çx*ëO¦>Ï4Rq¾/cªlzù퇺!¥~)µéw›¸Íw´•“_ôÏÅ裗Þ-ò2·ä6í±ºJžÑé¢MNô%ÝqµîS¡ Ä@õ]Óîc÷ž¹ýék_Àûö9Òknv'WQîî¾c®†Æñ¼¸Ð«£ûìšà³„J_ê·üÖ¤Þ^çqòyÜü̈G—æþi)©‰%Ggïí;Ô/ ª€ËO‹ ßøW— {%¥~éµiYN Žð½ëø?‡ý%O±Uî?L¥Ö—·¶6å´(Åiçð]}G] ‰å x±!WFõõ¶÷®•_>1«k¾ðÛØ¹©‹¥Ø¼ËÈ ÆÐ'·çŠr¯¬nã2ÒF¥Ð~„K;×Û{SézWE]q~ì=×LKQI»á´u'Û8œÔ„AO ýC|æTW”oÚcJ^ç-öJJýÖ¦f>$ úÚ›õ½G{ÜúÙqêÙÞaóD›f#ÿ¹´ÊrÍH¦‚ÍÈ5V«¯aŠ)2Â=Ñ¿YÙ{¢%žªò§ª3ʽ'ºŽ){O´$¸' `ÔL AmQ‡/„Õ+Ôu.øí°P}6ntà ÔX‚„ºk¸£ns€šë@€øê#<ÿ›Éþl<üBX€úˆ†§ Â:ÔGâÏ…EDD`P ®²´,þÚo¬@}„ @ 5‘•••••:S·Ï#1b €ÊÂ÷ÆT¡Ô`—¾3¯BèLyƒ†ûØ/s©Ê Q¹Ùyï;õ5³P·‘å˜é‹§ôkA)üöb›Çþ€Ð诙yŠmlº 9¾¯µ±,-æÆ?p˜à•-¾l¯ËØö„ÔÐ+[ö~õ1‡ÇhШ՟“NЊ*L]^ }è»yí‰ϾæpÃÂB©ÄSžKv»öæs!QllÙuÁ†5ØŠÅ%¹Â I:dBH|à™->§^¼þT@äMšYž±|L7ÑŽT¯­š²åèå)y:¦-ÇÏwQŽ8ì{ùA|F‘a“öó6mîkªRéòRZ¯p@*wöc®íÛ°ÿìÛÄ,-“ç.ÛWz.üX¨B7U6î=ðäyðã[ë&Y\9ì>qÝãâh öüàQ ®¼,ßå÷ôù“ã[æçä´ðýÃænŠv:~óqà­SÝè1›çÛöM¬†u/t÷ž¿}ißøä÷/¶Ív8Áâеû—öŒ‹ \7ckÙe,/Kë’¤rgÿëóíã]¤h 8ïñå#®9ç—ÞQz.ü*â߆÷DT!Ϫm{¦‚yȳ „Ÿ¡¶ûⲦ}8¿‰ºXAë¶EBâöÏ•?Ú‹ý™"vclxx8•žð÷øÅ{ TZm:º·×+ÞƒºJÈñ|ÔGCžÂ/Œog3X^Ý6èá.Qmï=¨¥ Öĺ;O‡ê(B¼4ëö½itfØ‹+ /w¤òö?ºü“”»òÖ“ÑzJ„¼¯g:÷qW6˜xcQé^í î¬&'àgZ·ëNÙõ0ÈV]ž ­ÛuÒ˜a/ž‹…Œå¥·.}@*wö·÷ïòOr©SOwî»I4tÒsà'‰ÞkaU¥(+zÏ–}÷‚#“Ó²¸|•È/Œ¥>œLÈ!„L1W+»ã =¥óɹ«& ^£¨flbÚʺó8‡©-4䥴uÑcê†ÓŠûûvµPa‰ÒÏ&åB–õ°ù¾c¥7ûi*”­p vñ…:S‹"ðd¯P)‡|!5Ÿ2P§¸QE털ç§^ dÑwÑ¡ª!„Î(¡:«ÉB]^ !·lµ2–—¥uIR¹³ák>!d¨E„l*éÔ\øUT•]ŽÎî¹Àóˆ½­Žª<µ ¶òZ®eÇv0<ÿ~ôüU'+îÍ˸7/ï?øxÃEÊJ€“ÇÙ"PKSS…Å(›{#ø…œÄ ßLZ9‰¬’DÚVXu´Š{þ3å¥> ¿ðì@µÁý@UålB!Äm²Žª¨Ÿ©PÊ!OÚ4I£ý½dw,§ 0óó¾¥i4Ƹ«çLUEëÒÏþ„ ötÍgɾϙ…œ¸}KÈž ˆjºÇöêaùÐsV§ÿušääÓÒqé\µF£®úy °äoš=Ú¦}Ç1 <™¨¬Ó;¾¼ºÒ>í­;Œ]ü·M¿qûŽ/¨°9eCÛÃ÷Xk)ð ã=†¸Ÿ %„¨7›põØæ>-rWOܾ½ÍàqŽ~âzÏÝSéƒú™ ¥²¶Õì‹Þ+ZПŽïÛ¹“ݘǂæËw^t´Ö©ž3U­K?ûºp¡—vmXÏ΃&9+ ó’=~<õˆè¹0¬@}„ê#<PI’¾Ë/3@ P—!Ö¨Õp- ê#Þ[ õÖ >¿(55ƒRôôô0Õë@€1b ¨Åh4N½j·vŒ@­Ølv›5eÓ]þׄÍf×¢AëmÆëK=›4v:üÓ1Pùls|w}È,’ù~ç±\ÛÚ;@I{Þ<þHÀæi1]•oƒ÷Ÿ9§J§ø9²{C锘+»†öhgÜ A“–6³\}óÅ/iÌùtÇqt¿fæ&†F¦6v#¼/…KOÏN [6¾Ÿ…©‘‘Y/ûù‘9\Q!ÇÝìÚ·024jÙ¡÷š¿J¯ëHj½\o.»÷[pÛëÁé] ¥ÔPîß°Q¿l~IUnŠ•Y«¼À¬xÞ¬ÙZʆ\†•]nXvIVôÅ;ëLe9޶IÖ Ÿâš³?r'öËÖQÍ`Êg4¶ÎÞ|Š_aßB‹Z¨g8î+®!òlA÷6™ ,Ž;sÜòÂûü%ñmØý}ŒZ;\¢²h+NÛ~:úC|bBÜ“OÍÒFzºfã¯|LHüòéµÏâÎ]wSéa'¦*é÷<~;$áKBÈíã=ÙJ²´.~ ))ÝÆw™ôéKé,I5¸µÕp蹨؋㘠ò•eÐÄÆ_Û"ûÌ#^v¡›'ðsÉjЫJO¼Ÿ§¤™uì/·P˜úž·~J•>L—ãøwQj–W(x\´dd¦°<„¤SÞ^Ê××ÈÜ÷Om&=ÌÓj–sý9?Ÿ+äÄóœe´]ÄíÒÀ.ïMª@´©a‘}1—[(ÌùÆ÷vÈÔï\ K%e;#éX>žÍQÔÉ:ÿŒ_È~*ê®Ã™rŽ/ªÇÀ674NÀ+\Ù”ÍTÈ0ê™÷â¿Mí–ù?TLzC’³\’ÎWü\%vÖåçüB®ðCpQO=Žh(¤d@uÿ®ŒŸyG"›ÍNIII¼¿`𡞡LJB.M°¾?ýÚΆT!Ä­]csÿ—ãô•¨]¸y¯ÌZ-Jøx›bÑÀà̛ϖ*,±j%¥—&ছ4œHYmÕHùtèJ *+ã»…íÎ [;ÿe}¦Ü³ ¹¶Táû•2I5d¾ßaùgÔǨƒTqŽMM/‡a+U8hRÞ‘(à 4²‹rÕ!KfΫ{µ§‰•Ñbqn§k¶S­ #jxçØ+¸p_¹›~q=+L3š>QŸfX¼ÉÍå«èçf«Q»œûª1B‡&ªá|ªÆpÝâM^@A-‹W¤Qa%B¡¦Xg$Ëlà Õëê[¬ŠÓ¿…ç› f'*QõÜL×ì§I!ü"S>óG³Fñ¦¼JqOd,&½!I‡Y¡Òçk‘q†¼¿ºG›âzÒ^æëXPC!% ªÓ¯ˆ7òõ´Ç/Û“çmº‰Œ8ȤQ dad- •^¢ÑèÉÉI„ëNg]Î4´Çvm;ÚöjÊV¤ª•”žŸòØi¡Û­ (Nn!DTO“ÁŸ¾h2‹ƒcРY…­‹È›{ tþsÏ¿N˜}I®ÁɺëP[[ÂŒ;m<ód¥,ƒ&å%ñæLË¿ö˜—–CED Ð$„h²8ò5µÄ_ëM.ÎÉwF8b4«[Gf7;f š¤èê ÖúË%C¹’tm9N¦€Z,þOÔ"Æ)h²hßEQe㪠+)ûÛ]Ò±¨³8±¥ÒNLNIIú$–Ü„"üþjŸ,­‹ÑhnóÎö›óû¬»ðFÆþ/Ü1àìÜ„˜½î¶M«Üà9uÎÉî-ÿâ£O )äkTø…¶ÃöªÆÜTìdJ ö/üÃ"säžè7·è?*¥ý–ÒÇ¢£w¾»U‡/$¯²5y_S Ð 5©_áM¦>K¯ä—M+©›?ZìW‘t¾„ßÏÂÒ§QJÔòˆÃîÛZÞ]¼ønË­Ý Å²&(»ßI”´£±UiŽK¶8ñ,ôÔu¯ÒÓ}ÉÙå0°¶*ƒFr‰ ÒUÚÿ>K´™õa¿Œ­‹Q3xí¡Ï³•8—¥ƒ®[[|Ýð3Çí¬¦‡M%ßpð³ðè"9]ƒF²ã‹DéÒ6½,ÿ×¥i{–ã2…C§TÞ~R¹è–ó_à§)úJÑï&¨ä;:Ëɯä¾é™F4ç낟<Ý?Z‰¤c«KóŒ.IçD(éÊUÅüü… I:_“Ù4Ϙïš% j} DhLŸ°àà0f™?ÃçøÌ}0wÄþ«Ï2 xÜ‚¬¨g7VNêIeÙŽ_zùqDf—_”ýâÞ 9ŽÒÓÿÐRpö{ZÀã}ÿdш-%Mlvpôì;¯¾ð¼„È;³G”¥õr)ö¾ôøø›MÃæ|Vq tù-«Úm3:÷/7ùÊŽëPڼü|IyÃû«w¾(}ÉQù½}süø\’ÇßøWñH­æ¹ÇÏÈ'üBað ®¼¦´»¦´,å‚#”ï:f;ì/^.Zê§pkR¶×9'Ÿpó…¸sÿÌúÑ>ËX‰hEJÒ±8ídíê›s%DÀØ…öÞ U²xóë’t¾–ÛÝ7÷jhI²d@µúÅÏ…ÉzÎk@§jòL¦‚Z›®C¶žxH¥œðÔ©…2‹!§¬eÝ{Ì©ÐÒÓß<ØÛÙ€Agh6›îzºt—·8¶4ÒdÐ:&-gn8Ac(Tغ”‰s£§¡ò çSÖ¦ÈÒˆû"û ‰úËÂ-3ôtmãÌy^E¥ŸŠ<›ß½u†#]«a¦óßÅ^½ò/a›©"—.¯Â±ù#çfœ@úsaB¡07‰Û]Ÿ3jSµw§`˜m¦ºB:S‘cÝ+ÇÇŸWî#]eŸ]*"K%‹P(¼µ+ÏҔà¥ëšf.öæJj]Ò¦ŒÅdoHÒ£m²œ¯@Ÿ<ˆ=]Ï,sáNY³ V>V3奜lÞãÖ§˜£ÕÐVÊÓµ÷ÿ/䟲ï"å¹0¨:Ì:yTƒzm\8¹UCõ”7Ag®·šu¾-äD8̸ëólu¥kÀ÷FÕïY<€è§­µá.ÓýÕ§t}óþ£Öž›ßªª[d³Ù 9½e¾·ÚI}~ ÖR冧8_µûßö:-¬†Ãµ0€ß‚Ž!Ä@õ‚øµ0€úë@P‰?†{¢«î‰ø-°ˆ ªYØl¶Ø‡ KV(Ê{°åðý?Ù±ýÃ-žA Ñh•È€ê‹Øå©Q!à¦ÍôŠÚvhª”ÈI”(äeq[гCk#Cs «áÓ–œü@eM=´5z§CWð3‰Ù×MA[¡Û¾LP€ÚBRÊøUÕþ’z’/Ëj±ÁNS^–Âgþ²;žÖØûü½Øø„ˆ§×m}{ë*K^³kóìåÉ?Ó™Mëüïy†­ß„ Pëc IØlvÈ™mÃzý¯ac³fƒ&¯ˆÊáŠrCŽ»ÙµoadhÔ²Cï5”]ž¥ä|ºã8º_3sC#S»Þ—ÂK*‘\¿ÈàNkìdì³Ë/g=[™è² U-#Û!Sö_|*Êíëbäñ¬Ò’›¸ÿšúâ–ó¦°.ù$æ–Î :älm®'Ç”c›·]ì}GÆ,¨‰1!dÜÎW37Ÿx—ðæÅíazÁcÆøRé‰wVŒô|åtøßØÏ±7­x»k²”Jæý1]íÏ•/ßÇÇÆœÜ:7ÍY…õ—æ›5¾™¬_n®Àø7!WR®fó Y±~• çí˜EY¼­«×ª`QzÂÍù½V¯;”Sóôôºp·?eÉ€rUÓ÷Æ—{{ u‹ÍfŽþ4P[JäÆš4˜˜MYmÕHùtèJ *+ã»…íNÑ^b,œyóÙR…U¶iIõÖ¼JHT¢ÓD{•½Ê&JüxnUÿ¥×:ØÑªeÓæ­»tl­H/¹Y(È34j•”øQ–‘{G¢ŸÓ¶A¿'‰•è4~a¼©þ€×i/•é4BÈ"c5yÿX6ÚTÉ´—+u,=¨Ó'% ÊU#î(„¦¼Ÿ›F}>ý5oV#5Q–Z£ÙRêß>ÁzpûžsV¸ùžõ›’_:KRý•fn¿ñeð™?Û¥¾ñquhÞÆîhÈ·_2J©!‹èÞT(Æ7Þm›³ðyqTz49wi‹’•*­% ]R²à7Ç@•óÝR†Ô…›ýO¹µ7V »}rLç–Ó½žüPCmUXÁY%÷ )Ði9üïçgÓ%±”‚žÅˆ)sÖmÚ~öæÓ;{¯?W”ÅÍ~ÎR±®Üñ^œw5̵í?C¯Ä]w±d(„匔,¨}1Ð(]¥ýï³D›Y*xy±UiŽK¶8ñ,ôÔu¯?ÔÖ3µã1Ñf?M…# Ù¥ dÇQÐè_î¾&¶³¸9!¢MÎëãjfc+q¼¼¼Èå‘ô¤B¾ð?üÂ$ú«å‘y—Ï ¹ùïžßœk¿³ï'*·ÓP‡#—&¤eó¼ô/1ûWŽÑmï$Ú÷®ë³+:Uâx?œœ§ÙÃ[_®ä¤Ðåô½»kÎóû@Yz`Âî¾c®†Æñ¼Ø+£úî“’¿9ªÄ;ôÛê·¸¹ûäÞ& LúMsoìx°ôÕ(1§¶¹²uaÛÆ M›ýoý¹ô#7,зõT‹Y{›SHmš=øÏüfû–kfjhhÚlÜò}-;0ÆœÊ=¶´ÏË‹;vjÝ AÃ.ƒ¦¿`üáv•U˜qou´ŠgWýJ Ñ–5¡¶÷Kìµ}B¨ËBˆñ€½·]­]F´W`)tµ¦óeQ)YP®jz.ì—ÈK9ټǭO1G«¨þW»Ox8(ü¼ÃÏTr`„Õ¥n¾×¶‘±¼Øsa€ˆB-ôÚ¸pr«†ê)o‚6Μ–0âüå­êÒ @ ð[0kxÿÖÚp—éþêSºŠ¾yÿQkÏÍo…s?¯6] «“°ð[Ð1€ ^ á[¥ Â:ÔGâÏ…ážèj†{¢~ ¬b €ú‰!¨9œW:aê÷M›15֪ʪU«15ÖðT‰Üœl BM†u @ €1b Ä@ˆ @ €1b Ä@ˆ @ € @ €1b Ä@ˆ ¨'1›Í®DV¹¢¼[ß_CtÿpË;"1±êr ôîèc ã!GßýÆpÓfzEm;4µÂޱÿ£oÐÀ²Ó_N;¹üJjìRô ,,;N\°ñU—ÊzhkôN‡4®s  ÎÆ@;·Fnº°6rëÎ_Û§””Ù '?^–Õbƒ¦¼,KIIIIIIJˆ{p~·yò‰A“ÏVº‡ÅUÅÇ>¾z¤§FÈð¾k¨,yÍ>®Í³—&cnÔÍ(/ùŸÛj³&´œ>†uÃ79O”Îf³o{/íܦ©¾>!$;1lÙø~¦FFf½ìçGæpE%ZÛ»CK#C£ìÜO¾(]ƒèóÛëûìílL -Úöpó}V¶O<‚;­±“¥c"4Ë q;'Ÿ“Éî?9|4KפùTrÓÙ IDAT—#YŸOŠûºØy<Ãܨ›1Ð wŸþ['Bf­³Ù¿)¬tÖ²­c÷Ã’’“ !Fzt›¿ëÅ»Oñï_Ìï?qò%Q±‰Û£–¼û9öæÁe/ÜG¬º—(ÖDÊ÷¾‹®ŒY4&öó“‹;C7”í†_lÖøfš2v¬Œ¢Ÿ?/-áíqêfˆÒ4›OÈŠõÃܨÉhB¡°ôvjjª,» ù¹½-Gû¿¼ªH§ñ‹Û·øúFa³Ù‡b> ÒR('`ছ4œH›wÿõêÅá 'fcûqÂ6PYÔå°uÖ‡ƒ\­´¥ôÄÜÐàUB"Õt…+¾Ê&à¥Ä½:ìæpâË´Wÿ:H©¼d—ïÅRX*MO†Ü±ýïzœPghÔ*)ñ£,#©§§'úì¼Ò‰â¾i3æ%@›“MQVQÅPÔLÌÊíö-Â…>É]‘N#„0ä 7uÌ]þÍËZ—Êí§Yå§æî°`öå°S£0Ÿêx t}å­Èðìm%)º)×É¿“‹Ã ZIú†Sr¦í¸»»»¾–*CXÀ6hX’'”¥)šôì¶*¬à,n 9Y:FÅ.B~aÂëàÓ]þŽº¼Èê§ÆÆÔ1i5牭‡Rq³Ÿ³T¬1·j²ÊÜÄËq¡G&$•<•Ií“Ï+[øØ—œ]h«2h$'ñXé¬=ï2EŸ3ÞíQÒ_GÇVÞ.½3cÌÔŽÇp~¨c4†¼qËn»üD휖TÑãñ² Ba¾h“óú¸šÙXÌ-€ºÅ]pVïâ®Ç*Ù—ÎÒsï¬î|1®lá?´œýžðø_ß?Y4bKé¬C£fÞŠˆç xñ·fŒTXò×¶ €*&äqö®˜jin Ïd¨jõ1óÄý·õ9€Ój6O€è Õy¾öÖ¿5ûçnxNaÑ—·ÎcÚú¯TŸģѕ±'>`bb :n¡ÿçÛû—Y™±Y †šNC»‘³O>(^¢Ñhww/ikΖcÊé™[; *½cäYîmLX, vãqË}òB)­D_ÜfgÝXYŽ©mÒf…Ï#QúS_×V”X .C#²¹²Ô/©6‘o¡ÿ´P×pÜP‰™rêLð¼¡oòyåæÞÙ½¤­9›Å`±ÍÛ.ÝsóÕVM™W?åHÊâ±þ̳œ‚œ 3ë‚Wõž3JOpî±æÅŠÃw2ò âB/˜Ålêºô‘¤J’8wøëì”m¿æ¼¾XéYÉË ¸‡/Ü{í[nQÚ§±úýûûTX¿”Ú(ï.»µ¶Û<ÿjôžÙ¶¢`Nö‘Sµ¹ºÞp°Ã¥²Y±ç&Yââ÷$·0÷é©5!ëO=‡)2Âweüfbß•ñîøüÿ9œ·µÞ­ƒe‹ÖÖ=ºµU¢—ÜÔìñÍ£6µ™¹Òl@AVüvBÈ Sõ¦O§*SYÜÜpý¿ ³C©½¨S,ú°´¡ºàü{¯öºâSF;Ÿš7\W‘Úä¼WPëÌ+J•^¿”Ú„Ba€÷Œ{S/Ü÷릯$–%VžzO´ØûŠK Æ›t½7»‰zéÝgªª^Ýb¥Cþ¾Ìl@Nvâ¾{®©÷‰ž kÜ´eÙ2ïßF‘ÿž £^¨¬¢ŠÄ@u?"„ä'G]¸x#,êuÄó€'Ÿ”·^üwv'=êwÿW._‡Y¼t'äq˜Šæ|.‡¢-ÇÈÐ!ÂÿÐht€_n ¤Éb|Èçj1éåF-å¦H©_JmWWô›âßäeÈNC¹Š—¥Å@„p¢¼Ì‡D¥¾?Ä¢•$ª³±ù<-fqŒ(ॳÍù܌ڕ ƒ¨1@õÀµ°GQ¿åøÙK·îþûvÐÛ—GþXŸ/„B! H‰}¨KÕ_~mí RúxúèÏ??&š-ïn÷`Äá7Ö®s- zÄ>b úÎÌnqQöSѦg Gô9=ÆSY2õy¦‘ŠóõxëüËPeÓËo?Ô )õK©M¿ÛÜðÀm¾£­œü¢~(F½ônÙ—¹%·iÕUòŒNmr¢·(鎫u§˜ } ªïšv»÷ÌíO_³øÞ·Ï‘^sû³;¹Šrw÷s54Ž'àÅ…^Ýgן%TúR¿å·&õö:÷ˆ“ÏãægF<º4÷OKIM,9:{oß¡~Q\~Z\øÆ¿ºTØ+)õK¯MËrbp„ï]Çÿ9ì/yŠ­r/øa*µ¾¼µÅ°)§E)N;‡ïê;êJH,OÀ‹ ¹2ª¯·½w­üòy@ˆ€\];ð…߯ÎM X,Åæ]F1†>¹=W”{eu—‘6 ,…ö#\Ú¹ÞÞ;À˜J×ë¸*êŠócï¹fZŠJÚ §­;ÙÆá„¤& zzíâ3w º¢|ÓSò:o©°WR꯰65ó!Ñ×Þ¬ï=ÚãÖψSÏö›'Ú4ùÏ¥U–kFÚ(0lF®±Z}åÈSL!î‰þÍÊÞ-ñT•÷8UQî=ÑuLÙ{¢%Á=ÑÕë@€ ~`bj‹:|!¬^¡®sÀo‡u €ê³q£ †À:Ô Ô]Ãuu›3ÔXÄPáÙøßLögãàÂ:ÔG4.,""ƒu•¥eñ×~cê#Ä@€1@]…ïʨ$+++BHxx8:Sñ ãm;ÿ™ËÐÊ—Ÿ<2–§WÑèɾoU”üÑz0OJÃ:ÔAI7åòLe¦€ŸëˆÄ@P/œÛñ’â°g&!$bÇùªk(<<\ÆeÙKÖ„ÞÔ¸uSj°Kß™W !t¦¼ŽAÃŽ}ì—9ŽTeШÜì¼÷‰úšY¨ÛÈrÌôÅSúµ „~{±Íc@hô×ÌôݼöÄg_s¸aa¡Tâ)Ï%»] {ó¹(6¶ìº`ÚNlÅ⃒\a…$2!$>ðÌŸS/^* ò&ͬGÏX>¦›‰hGªW‡VMÙrôò‡”<Ó–ãç»(Gö½ü >£È°Iûy›6÷5U©ty)­W8 ’f=öMÊUÐì;Ãjæ[ÍÃwÿyœ5««š¼¨@̵}öŸ}›˜¥eÒbøÔ%b»ÿÐ!”¾º$½Ã¥KJ™iT±rk›0Òç¹”zDaPU >Ö~³€›*÷xò<øñ­u“,®vŸ¸îqq4{~ð¨W^–ïò{úüÉñ-ósºSYžç¹<Ù㟧!ÏožÝ?ÁÖìÞž9²4—ya´ý’è|õ…Þ—¨ˆ}tðŒµáü‡®>~ä?©MÖnç .×âKïõïÁ³–ã]n>zFý>£8|7Ãíï€ÀG»Ú¼¾±tÊv*]– %@’9-|ÿ°¹›¢„Žß|xëT7zÌæùÃö†}«aÝ Ý½ço_Ú7>ùý‹mó‡N°8tíþ¥=ãâc×ÍØZ¶EËËÒº¤‘"öänPØtº!dÖô¦B¡`÷ÉXQî×çÛÇ»HÑpþÞãËG\sÎ/.·’=äê°”™& Pʮٔ0Ræ¹”zªtðüfökœvn¥¦Äb*¨w¶_KI¸]üÏ÷ÉE;3x‚qû·öjm,Ç`阵™ë~œÊºš’G£ÑÔå˜t†Š¶qç?F{º*ú³¸´Òm%ü=lªÛWÅ–[Ï\˜ÜÅJ<¾üïBÐiû¼&ºÊLEíáK·Bnyz–Þ‘?j‚UCm±ÂE{WZšh1˜Šÿ¹’’—rAö %‘rȾ+ñ„B‡mŽfZŠ &³<„Bþ çcb5¬\9R[ih=™Ú\îÕ³KÕòuXÊL“öï5í×Ìóª|€Ú× :›Cq›l§£*OÉM:]:wlBˆo\VÙt;8oñ¹q?08ðÞám !ù)þÒÛò;ån®ÄL:9j¨cPrž(}”¡2!äÈûŒ_uP²WXöj”C®§H¹ò5ŸÚÌÿv¢¨7¼zÎÔ/o](ÈñH¢³tî…¼ÿÏ‹{:,zb€G®@H®«HñO5ê_ýSTúL£Ñh??Ï+¬ç÷žzÄ@UÂÞX…²ùÒ‹B¾àÛ‡ Uí-;Îk®ƒ~ÂÁéAtWÀK>°®øža³×^ KÍÊc*©ëj©B”ŒÞ–ªY¿cç¼Z¨Êå&=uüsôéç)TúDOe:ýÊ|—gï¿ ¼ÌÔÏýý–M\éƒú™ ¥ò¤M˜4ÚßKvÇr 3?ï[zFcŒÛ8±zÎÔ/o=í•g|!_Çj™³ä7:Sk™•¿0~Ë«4BÈ„ ötÍgɾϙ…œ¸}KTÿ•>ÓÌ„gÿE'•›çÖó{O=b €*±àØþQ=,zÎêô¿N“œ|Z:î/«ÖhÔU?¯–üM³GÛ´ï8f'³£•µszÇ—W÷OÒ§½u‡±‹ÿ¶é7nßñ6§lh{øâk-^a¼‡Ã÷3¡„õf®ÛܧEîꩃ۷·<ÎÑïQ\ï¹{*}P?S¡”CÖ¶š}Ñ{E úÓñ};w²óXÐ|ù΋ŽÖ:Õs¦~yë<Bz.µK·YÚ“òxóBˆn‡E'\gè¥]Ö³ó IΠüªŠJŸiæ ÐS‘ŸÕ§“ØzÞÍó ëù½§ & ‰]<ŽˆˆÀ @]eiiI}À:ÔGˆ >³ñPûHºQ_†ˆ .C¬?× >¢ýÚ—ŠÔ X€úHü~ ÔÔT JuÒÓÓà T?¬b Ä@ˆ £Ñ8õªÝºqd)_=#Œóˆ*Àf³›Ø¬)›îò¿&l6» ŠXo3^_êÙ¤±Óá'˜.P®˜}Ù Úœnûøu&üEЈ~˜mŽï®™¥S2ßï<–k[{()ð`ïÁ›Ç Ø<­3¦ ”kÓz¾÷=¥°õ¿¶Z¡Pó—”©žžÔ÷hƒ÷Ÿ9§J§ø9²{Ãw4_Ù5´G;ã š´´™åê›/(~IcΧ;Ž£û537142µ±á})\zzvbزñý,L ŒÌzÙÏÌኚ9îf×¾…‘¡Q˽×üPz]GRëåzsٽ߂Û^îLïj(¥†‚tÿ†úeóKªpS¬ÌZ}(àýèfÅóf ÌÖRæ0ä2¬ìròK²¢/ØYg*Ëq´M²Vøלý‘;±_¶ŽjS>£±uöæS/E| -j¡žá¸¯¸†È³ÝÛd*°8ìÌqË ó%+þ›ó, 3tµùÔ· ‡U¦‹£ ’Ñeh^D©¾IªD’r…rgw~[ó ƒÃ6ÏZº‡WzYâþîü¶æò¬ ãVÙ‡ž ÃŽåw´ÈT`q̬sþMþP1é I9Ìrå&^S—Ÿa)?…ÅõIün:Ê·6ÏcrØæY‹½¹•8œ {%*SîL ri4õ_ÙÓZî|+w¯ª:€ßLø½”Ÿ@IIþ2HWy_d•¹WYwð—äB•yiF“!'ÿ}öùKâÛ°û úµv¸De ÐVœ¶ýtô‡øÄ„¸'ÿžš=¤ôtÍÆ=^ ø˜øåÓkŸÅ ºî¦ÒÃNLUÒïyüvH—„ÛÇ{²•di]ü@RR.º5î2-èÓ—ÒY’jpk«;àÐsQ±Çÿ0ä+Ë ‰¿¶Eö™G¼ìB!7Oàç’Õ W!•žx?OI3ëØ=^n¡0õ=oý”,*}˜.Çñï¢Ô,!¯Pð&¸hÉÈLayI§>¼½”¯¯‘¹ï!ŸÚLz˜§Õ,çús~>Wȉç9Êh»ˆ+Ú¥]Þ›ThSÃ"ûb /·P˜óïí©ß¹@–JÊvFÒ±|<›£¨“uþ¿+üTÔ]‡3å_Tmnhœ€W(¸²)›©aÔ3ïÅ›Ú-ó¨˜ô†$¦$w'gNyÀ …Ng7Â¥ÇßÈUbg]~Î/ä ?õÔãˆFCöé°W¢2’f‚Ø);­’æ[Ù½ªbè~/ñïÊø™w$²Ùì”””Äû êz|(!äÒëûÓ¯íìaHeBÜÚ56÷9N_‰Ú…›÷ʬբ„· ! μùl©Â«VRzinºI“Á q„ÕV”O‡®´Ð ²2Þ¸[Øî¬°u±ñ_ÖgÊ=«kK¾_)“TCæû–F}Œ:H÷èØÔôrø¶R…ƒ&剮PA#»(W²´a†à¼ºW{šX-çvºf;Õ Z¡Ñ8B¡f€wÞˆ½‚ ÷•»é׳Â4£éõi†Å›Ü\¾Š~na¶µË¹¯#th¢Χj ×-ÞäÔ²xEVRö2Фc™m˜¡z]}‹Uqú·ð|³ÂìD%ªž›éšý4 !„_$`ÊgÞâhöÑ(Þ”W)Ť7$é0Ëÿ‚/lÛ çI¢ªð ¦ú9¯ÓԔ鄲È8CÞ_Ý£MqUi/óu, ¨ÑýpDå%õJTFÒL;b§UÒ|+»µù ‡à·ûõ1òfX¶žöøe{ò¼M×#‘™4"Š,Œ ²´ÒëO4=99‰rÝià¬Ë™ƒ†öïØ®mGÛ^MÙŠTµÿoïÎãbÎÿ8€¾st_“2•¢bQ,r³[B¹säØE¬Ö‘_lDî$G®ä(6¬+ë&a‰ÅºJTºäª”ÔÐ]sýþ˜Ìdj¦%õz>ü1ßÏçóý|>ßÏ÷ÓÎ{?ßcd¥gßöpó¾Ï),#„ˆëù¡™aDêk£ Èd×àÑ¥%3(Ü»³^éû°Nö’î.QdФb ¢LÞlçâ ·y9¢ï"°!,&çE1KWúµÞäÌìü‰Ç…Žã™}{0úÚ2ÚR²b ÅÌ©¡´Ç‘jFJ’ô&JœÑr`ù?q‹Å)°˜TÕ_¥SäWR9’u,ÚLNr…tOÈTýÀç–Ó „,ªBÓR›âXA‘bò’u˜UÊ/rQùÑjºhó܈<5÷ZÓD‡ù¬˜¥÷±!OHc¾ÿ¬~Vþ@d—‘5*G3O«¬ù&+úŠCðÍÕ³ñcõv»…^áá^‹m_ÍøôKY $7_¾ÊÈÈÈÌÌÌÊÊÊη öBïóîj¢uõ¨S¯3¶Ü•Ÿ¾ÆajAß¹×$ddegg¦ …’›P„Ÿ^íS¤u):íÆ\ÛzyÞÀU§“ì¿Û6ûs÷BwùØov®Ùàyô*È·Q~ôR‡'` ù:Õþ í¨]š‰—U{šR¡¥CÚ|»†'þú©x?!¤«=SíeÙ°OnÕá I\>‹Çcñù,€%²D_"LJ¡>˯ä«M+¹›Ÿ[ìk9ãÊòÊõÈó‚W®dV8}ÂZ™PYÅÓú¹ó 1P5ŒúoîpmÁ‚k6õ7’ÊúÅPÝ',CÖŽ&Vœçü±uÏ‘û]Üò›üôC¯ ¶»84k¢I§HAÆ!qáqújÏóÄ›y/l]Š–¹Ã…›÷— ñ8­H †}6µ°÷Çûk½u ß°÷•ðÀ|¥æú"ùieâôéFÔºÇUA™veÎY¨tLãiªÆï‚KüO”bÐW9úŽÚÁñyÁ’û¦gSž_xº?·YÇ2AŸòM¤sJÔô•jc~~­†xEüE±$³T2ÔüRmZ\ql!„LaS¾‰Ÿ´RÛÌUÎEøŸ?ßdíUgçà{ÅŒŠˆˆ dTúßÛÙsoÌu ¹ÿ¾„Ç-É‹¿iɯ?‰²úMr?w;æC —_–ÿèú%%òÓ‡èªxß+áñß>¿;ßq£¤‰ £öŽŸ÷š'à¥Ç†Í¿W‘Ö«¤ndsööá¤u£\÷Þ¯¾šòÆ¥?nt_8Ý[¹¦ã:RrÝÇ+æ‘ì$Þt›bqú”wÙßâ—pIN íôòGn,ŠŽ_ç¿/&üRaÄ%®2KÞ]Sº–J1ê׿ä»”/¸«\ù5ËI§˜p‹…1ÿqçŽÈûÜ>+X‰xEJÖ±xø1·Ûœð$9’;ήtŒ¿JmLϯÕЋ£E¬ªbšÍ¿?åÌ'„¸ïQÚaWòPÒJ­þ%Ëš =µÈîÁgÎ7Y{ÕÙ9¨ _ù¹0²žÜbß³½–2ƒ¡¢Õ©ÏðMGnŠÒoñÚ³½:“®¤®ÛÅÆéØÃ—òÓ“nìêÕÆN£³ŒÚÎðú»bç6Îé`Ì¢ÓèzÍ;Ì\s„¢«TÛºœIKºô“‘úPÏcÕÖ‘¥ÊÔ¹•òZñA“ÿÜÇ¥:¼§Ór›˜|pÝRVññœØÅý;¾W¢çê¶øàùgùóGq¡%Žý>h(å*kp¬‡\NÈ.L(frûpÆ­+m¦„•Œê÷A[%—¡ÊéòsA`(Oþ“AU¦(RIµÇ" ¯l/²4åЩ\}Ó ü¹²Z—µ©`1Å’õh›ˆ³!Ç3QzÀs‹4 EŸïY¶àÐi¹MÍ>¸ù•}n?e•¯2KÖLxr èÊ•”ªJÖ|“³×W:€†ö\XýT”}´Ý€+©‰ê ­ì{+ºGþå ø.rž €ÚÃhG5ÔmËZ·)-´³“Â×Î\mõû©:h´”ãòÛµÀûËj\~ âJ3 Ä@uh¥5w‘Sÿ¸Ô\ óÁãVžœgQÛ-²ÙlºRÓ…¯ü(÷=Fø¶øNUžâ||ßÿmoð×Âê9\ ø&h@ Ð(H_ h °‘ôsa¸'ºŽážh€oë@€1b ú…ÍfK}¨¶dµâý‡YŽøÂŽŒ¶tØ[7ƒ@QÔW/ÿ¹uÖMϾ׈]•z5nÎÌ-ñ›ƒ¦É‰œÄ‰BÞûýÞÿû©[Gc#Có6V£ÿ8uç…(kZЦ?—®àK:“¸»¯J•¾»ëጩYø‚ i DÉ®äkUûUêɺ½0¯ý[–²"…O·=œÓÊÿÔõä´ô˜{ÜFv¼ºi²(K™5Ы]þ¢;Y_Ò™u«£ü¯ûF­^÷uO"›÷Eá­TЈb YØlväñÍ£~îÞ¢™¡‰Y.‹wIDATÛ¡SÇpŹ‘‡½m»¶762îÐÍfÅŸ·*/ψS RÃæŒÔÖ¼¹‘±©µ­£ÿÙhI%²ë»»>¢ç [û¼<ìõ ß9Íõ™tº¦®q¿áSÎÜçÚ-·_¿ÆR˜pA{Áo–®S™g3 +f…yv1oªÄPb›w^à&N§(êßîÍÙÊLU‹AÞFZÕ£M3¦²Y—¡ÿd‰‹‰?Ü;è5Àª¥“®¢¡×{䜘|®T™ü—Ô]OS•¡¬Þª‹Í†c‘â\ê#ÑçÐ .mŒXt’—ñ»Cw]ueº’†•íÔ¨|®¬½ÄÛñGgs6“Îd›wvßy­âAÉê$@Cˆ!ýâfn8ò$%=éÑÕQM#œœŠÒ3ÂõóØ÷Oò«äËA‹ŸnŸ"§×!3´F,¹óøyZrâÑMssBV[EÁÉy“Ú*ú3àæ*ôÒ eå²ÚMÎK®ñh„{n±çwBÈ‚Í}¶,§§_ž÷óÒˆUÇà J îý½*Ú{DŽ&àý›XTøf×dæïýz ߟ·ûJ\aá»íãJ' ÜV¹{Ÿh·]Þ–å¤FN0¸3xp T)=ÆjóNÌx_šÿöbࢷ§]Äë7ÂD%]ÂôBbÒø!Ä|àr›%û_qŠJ?¤.î•:lä1Y{‰$Ÿœ2|uäòà»…¥…÷Ž­ˆ\5lÚ©Å; Pcuô»ñUÞ^#ºŒÅf³÷%¤:4Q%òJ“›·tÈHO „,³j©þ÷Ã%mtDYï“|Úôóï%õ¡M3ÃãI¯,5˜•›–Uÿ'a‘a\z†ïUù*›8ñåÉ¥ƒÝ/ôæÐêCëv{÷è¨J“,lEFÆ™/©w$ ù› º›q[FñKÓL ìŸä©r/Ñæ,#M͋ɭôDéÙägì–ßI€ïiHÎý@â…ÂP6ãssDŸÿ~[ô{K-q–VËYrêß:¹Ë°®?Í^ì}ðDèÓìâŠY²ê¯1ó1kGñ£ñ›ç‘^.í:Ùˆ|÷UFéMä|š‹¿(£+›ìèWàö ü[ÿ@V¡{{ÉJ•nû…w´ûx']©!ÄVG²Éç¾­Ü8¶ „0TZU.ô›u³N“ç,­æì­x5JzbZ§ó›Ü:·jaÚ¶ûꓹû/^ˆ`ÐÏW+qåUN©hÓ|ÂÞ¿æµÝ½hb[S##Ó¶ínïvh“¹(÷ûÀÇg¶9ôìØ¬Y‹ÞCg<¢ =á,Ê*}}Y‚†oƒ ÑÆ'oýY*ñç­“.ßH1±ßuÕ«ËrÇ®*L•ãVtòGU¬AüùéÅÝcl­MÚtà}ð~ånÜ]Ñs…­"£èLÃV?zͺåó…ÃGÑ™úÍÛM[¾?ïÕQq¢Ýrëðõ÷1·f ôÈ'pð¦)„ßWY¬‹ª˜µð–î¡£2³²!ÝÆ®ï;oû£g©iÏÍë–öË”³âb¿l_´÷Rò«äË{>òq\z=Cª‰ì»>vóÏ;­>˜üêî™mª×TîFprÞ¤¶,;VIÙ—ŽŸ€—“þôðúß´[þ&Ncµ›œ—Œ¹PŸQB¡°âö›7oÙMÈ/´±ú8D•FñË2ºZL¸óä†"„°Ùì ÄÔ¡º*U ÜÜæ? KO¹#*æúï“eíËÃNâÚ®K^D­e‰.‡­êÒJ°/Ü˪‰œž˜Æ¥gˆš®¶cåWټ씸}Þ.G^;Çýã"§rÉ.Ÿ&J¥05Z ë÷ñzœPPddl‘™ñR‘‘lÚ´©ø³çBˆÏº ˜— @aA>!D]CCQ?1j¶Û»˜å´_}Ti!„®d´®Gá²èw[ºè‹r±$Pqöm7ï+áñœÂ2BEIVžf·ÖÖùaNÑ›î„|²Òs4»0‚õ;V1|aª·½ã\³Ã—FBÞ»´'‡|\þ7ë\Ô±q˜O <º¸äJlôöfIŠ~öEòÏ”òð‚’¤¯q˜Zà¼íÚŽþºšta Û°…$O¨HS”üìÎ̈<î%E:&Š]„üÒô'k]f,ÿ3þÜ|«/?Š¡×Übžß‘M­FRqó05º`nÔg5¹ˆWœè•H‹MÏ”<•K{â•XÌ«\øÐë‚í.ÍšhÒ)Rq¨bÖÎgÄŸß?Û©ÖTze"[Ý/!W~gœÌ´'r>«c]Ù¤Cßí¡ûãýœ3«{<^B¡@(,oržÖ2›€¹ÐÐb ”ÓžÚ½}š2%ûÒ˜M}zi{žI©\xˆ®Šgð½ÿíó»ó7VÌ 7óJLOÀK‹¹òÛØ½c|gKí;ËêþqSÎÜK*åò9iqÛæ­\ïEÝÂ×\©AÇ”´{yuä¹_Jÿ²ä¤Åïpû…Ýw…8éš×ýn‹{bn4´h熘1^}¤ûx‰Y¿³rá'7§í™mnbÒwì’¦Î{+fšß~ýŒÁÍ›5è¼ÞÒãÄ[#©}Ù½—]ötpÉÄ–-LzŒœWÔmEåú úùj%®¼Ê)ýÜŽB†øŽ¹¿r§üƒeJ*ÑÀÀ¸—ÃŒ8–ÓåƒN¢¬Ò÷×—%høö1ÀܨÏjø\X½·}Øä›C£O¹Ô‡Îìq´:Û÷àE·N –Çsa ž «ç à,æ…DÏ«/™y*z&¦b ïB•¿ öY?Ùˆ¾?w† @ €à;†çÂêÑ;µ Va¨~Yºt 4„ßÊø®Uü­ ¨3¸õ‚è·Ò 2ü~@-Áµ0€ú ×FjÖ iØk¸Û ^Á:@}´v­7 Va Nee¦U[&hß_(€Ú†u Ž¢(©Õ–üºí ‚ê yœ]‹§Yš*3蚺Æ?;Î<òïÓÆÀé¶u ºÄ@ ÞÁ1]ö¾kû×µè‚Ò²×Oïx:u]=´1Èú–ç'y‰ˆ8·ÐWWZ™±™tº–^ Û±³ŽÞ(_¢(êÚŽ?:›³•JMÍ»x…WÜ1öÄúþLU˜Lv«‰‹‹B9­$œÙlÛ¥•º£IóN‹ÿ§ß;è5Àª¥“®¢¡×{䜘|®"õ˪MìÝÿÚkëÌÙ}«2õØñבIż*sÃvüÑٜͤ3ÙæÝw^ÃüÄ@֪߫ŒÔY¹Ã½cV¿_PR~|UÄR›y—ÓEéY·<¬x´x_Øûâ’”‡§Í×õqÿOV%™7<»M?1uó™·%Oþݧv_òrB{Ÿh·]Þ–å¤FN0¸3xp`µõË©MäÙ9æ…$ìœÕOÌ)> JšÖ!«†¹œ­œ•|rÊðՑ˃ï–Þ;¶"rÕ°i§R0…@Aø­ŒoLê·2žž×ÝåT¿1£ûv³l߱ˀ¾Õh’›š=bÞ­ïÔD´™»Ä̾$/m+!d±©vë»ÎFê¢,na´†ÁôÒü‡¢½D§XüÁ½…¶àÔó-]õ¥§EzS4Z_U´É+y®¢Õ‹WöF~ýrj …·üsÜõæô¿Á} Ô¤²¤Ê‹Þ-õ~ ò’‚’I¦†}®¥ÌúA»â45/&o´Ò~½Ð̾ ?cw½=×¢÷‰Ÿ kÕºCå2ϟƓυ‰^¨®¡‰?Ä@ ?"„gÅŸ>s)*þĨ[wSÕ7ùgVϦ¢ïþ·\¾£|éNÈã0TÍù\!¤‰ýƒ€"„?¢(š@À¯2b1é/йº Z•QK•)rê—S[ÈâASCxég¤Týr£¼ˆNüóáñož1)I¢6“ž\ÌÓe”Lj^.SÕœÏ}ÿ½Ä@•à Q„ nàZX½£jÐaÒ,÷M;þ¼þôñþ! ~•ä}¢H6øB—_Âãñø|¾@  …¢ENìûY]ª®þªkëj?TíåßÂ^}ù˜°:,Øñã Ç}IÕ~_çZôH}Ä@™í‚²ü{âMßDŽøsn¢¯ºÁÑç™ÆžÓ¬sº‘ƺÇï>«rê—S›Aß¹Ñw6oåœðåC1þÀÙg ‡?.”ܦ=A_Í7!W¼ÉIب¦?ñ»;Å¢Ðb Æ®uÿ »Ž_M}›ÇðÞ½ŠÝ2w0»§—8w‡SÈÞ€—ò0düÀí“ÿ¥»/ºò«Í–“ÿqŠyÜâ1ÿ;ÂRV˜µËndð­ø.?'%zíôÞÕöJNýòkÓµü%"æàµ9Ý]$O±Õì? µŽç6µ5õoqЇßèívãÎG&ó¼äÈóãìüÇø—?>1•‚×öjmÈdª¶ë=6œ>òîÕ¹âÜóË:-k­ÂTéê¸üG¯«»ìMDéM{,?ïyÛ®™®ªZ“ΫŽvr9"« ßև œë ­ªÜzÀÔ¢^«í•œú«­MË|ø­„ I«mƯ¿ò¥â´6Q®âM³±]j¹b¬µ CÅzì «eç÷;šb €‚pOô7Vùžh™§ªªÇ©Œ*ï‰n`*ß- XÄ@Cð½hÀÂÑu.øæ°PwÖ®õÆ ÔX‚zDt×p&ºÍê¬âhŒðlü7¦ø³ñða# O@#„u hŒþ(Ç4vº\ÈIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/arsdigita.gif0000644000175000017500000000173607253523116023735 0ustar frankiefrankieGIF89aIAÕÿÿÿ±È㦦¦ØãñÒÒÒúüý¶ËåÅÖê¼¼¼ëñøéééðõúôôôÀÒè»ÏçùùùÈÈÈâêõõøü···ÝçóçîöÍÍÍîîîÊÙìÎÜîØØØÓàï±±±ÂÂÂÝÝݬ¬¬ããã!ù,IAÿ@€pH,HaÉl:—Å#I­Z«‚¬vËåNŒ«xŒìšÏYH˜Ì£ß]M{NÝV aÒíLé€Cvc [tƒd[‹€l[“s•l[šlœlZ¡d£d [ ¨nZ‹ži¯Wª«[еe±‹|Y »u½ZÂI·dZɼYš¹ÐFËd¥Y®ÕD×c—YÜÝÄÇã‚å€ ¦éBÞbíYïñ°Òb ÿ*$O@(jI DÀ` €Ã‡ `ˆP`˜¾I­’ h±£Ç*Áw…ƒ–mE$4øÈ²£#×Ê&å[êtÁšLÿ:4å)°²¥ƒHs~\P„¤šâˆ `i`A"(8øØ éÏ9P‡*}Ø@ä¢+»¸(ì˜ER`l k jr+$CÚ+S=æ ÅÀÄ,øÞ×6…?ó×1Û@…mí8@Ýå™Z¢j:ÌÙ³ÞI4ƒ…" ±³åÓmO¢býÐõ½ÇlLjïÀßÿ6·6}P6•hï,ýºøç!_ÎÒ¶S,_)Ø¥îÑ:î1óL0R@9÷êÄ'…?5´hË€œîÐûó6ÆÂ1ïÐÀ¦T˜gl€€#€DPÀÒs%!`z±eŠu}Ô“6‡Q9puGû†]ªçÎ ÆÆG!.’ŸB aWd,框è&À„€"2wÛ}c4“Å3C$°ã~Íø#mÌ"€héÑcT¨äuF°¢ÅBHÙ‘cvåwUЄL,5V…Ûâ ÀåîATVh¡G#çh‘‰ ~„AƒX¹"„c<‚]m:@Aƒ $éPbÖ†¨…¢E"IT°ÓQH-å©Þ\‡¿ ¢Ëœ×QO^>„×kp¼ñ§ºza¬MFk­]¨#\˜£G¾. ¬)Ìãô=$‘š7%`­µÆ>¡m à8 ?þüS±ö\;openacs-5.7.0/packages/acs-core-docs/www/images/ext-auth.png0000644000175000017500000011747007766174400023556 0ustar frankiefrankie‰PNG  IHDRç8F ÐesBITÛáOà pHYsÐй‹çŸ IDATxœìÝy\Ôvþ?ðO˜2\ÖÂP†aTPWÁhlm­J/¨öØZm+­-­XµÒj=º\®ZÑz-_«"(¨¨Š"‡ °¨€‚ 7“ßÙ΃—™ÀëùÇnÈ$Ÿ¼“IåÅ'Ÿ$P& îîîlWʈÇv=¢ÊüMÓìÖàáᑘ˜Èv ¼Ð×Ü€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔƒP||¼‹‹‹®®®¾¾þìÙ³oݺ¥ÀÆÇïààÐnæÉ“']\\ôôô„B¡‰‰É¢E‹˜ùqqq:::fffß}÷]»)ŠÊÉÉ‘ÿ˜““CQ”«LZ`°9}úô‚ >ûì³ÊÊʲ²277·¼¼<…4ž–––‘‘qûömùÌÇ¿öÚkŸ|òÉÇ?~œœœ!¤]ÇÆÃ‡™ù„ŸþYOOoéÒ¥×®]#„œ9s†Çã.Z´èÈ‘#éééòµ"""FŒ!‹›šš˜9ÑÑÑ^^^ÚÚÚR©T,3‰„B!³‰NëÑÔÔ\¿~}~~þÕ«W[[[=<<š››Û-“-ÿ’I!„’’’;wîÌŸ?Ÿ2oÞ¼¼¼¼ÒÒR‘H4qâDOOÏmÛ¶ÕÕÕõõ`p R *úúúöööGm;óرcÓ§Og¦ÕÔÔ˜ uuuBˆ†††‘‘QXXXXXXdddÛÛy˜äwôÔÕÕÅÆÆ=z”¢(WTTtèС†††áÇ[XX99944ôÒ¥KR©´±±±çM H-0Ø|÷ÝwëÖ­‹‹‹“ÉdMMM»v튉‰ùâ‹/ä Ð4åååEñööÎÏÏOII166‰D «f;¦¥¥Å\—a:Eª««ãââ(Šúú믃ƒƒýõ׺º:š¦ 6oÞL)--ݲeKQQ³Ê©S§ E"QOöÂÄÄÄÒÒòÈ‘#„C‡YXXˆD¢šššŠŠŠéÓ§oÛ¶­  àáÇLÁOŸ>íãAà¤lf̘±ÿþ==½#F;v,11qÔ¨Q̧æææÅÅÅÛ·o'„˜™™8q"44ÔÈÈÈÂÂÂßß¿«f£££ƒ‚‚ø|>󣕕•s‘háÂ…ÿùÏvïÞm`` ¥¥åééY]]M)))S§N …†††›7o>qâD7Á¨-Š¢8&‘HÂÃÃ>>mgúúúž={–¹’) ÍÍÍÓÒÒ˜O#""¤RéäÉ“œœ˜kIÌ’ VVV`Íš5Ì’2™,&&fÁ‚~~~ûöí“Éd„òòòÜÜ\__ߎňÅbWWW—]»v•——w\€¦é€€‘H$‘HÞÿýîë µ¶¶ž3gNXX³ä±cÇfΜÙö Qnn®‡‡‡‰‰É¦M›:m ­ îîî„„„E5J"77—ÒÜÜÜvfff&Çc.£¬X±¢²²2((ÈÙÙ™¦éÔÔT]]Ýòòrš¦ÃÃÃ]]]išf–\¸paYYY\\ŸÏgÚ9wîœ@ xòäÉÕ«W !çÏŸ§i:''§ãåjkkCBB$ ÇóññÉÏÏoûéÝ»w !ÌÖ»¯gíÚµ555‡=z´L&£izÖ¬Y‡f>¥iZ&“ÙØØ·´´Èd²ÚÚÚN[ƒAÿš±‡º‡¾è}}}BH»Ž‡2ó !?ÿü³žžÞÒ¥K¯]»F9sæ Ç \´hÑ‘#GÒÓÓåkEDDŒ1B,7551s¢££½¼¼´µµ¥R©X,f. …BfÖ£©©¹~ýúüüü«W¯¶¶¶zxx477Ë?‰D'Nôôôܶm[]]]÷õ„„„hiiÍ;·¬¬ìÚµkÅÅÅ7nܘ;w®|ÒÒÒ¬¬¬O?ýTEE…¢(MMÍnZ€þƒÑ¸Ð#úúúöööG}÷Ýwå3;6}útfZMM™PWW'„hhhɯ¹´Å, ¿øRWWS#ŸsèСüqøðáüðûªŠ¢(GGÇhii›››Ë‹INNNLLܽ{÷öíÛ³²²º©GUU•"üýý#"" ßxã ùîÈKe®[1ºi úúZ §¾ûî»uëÖÅÅÅÉd²¦¦¦]»vÅÄÄ|ñÅòhšŽŠŠòòò"„x{{çç秤¤‹D"@ÐU³ÇŽÓÒÒb®ãÐ4]]]GQÔ×_ü믿ÖÕÕÑ4]PP°yófBHiié–-[ŠŠŠ˜UN:ehh(‰ämÖÔÔTTTLŸ>}Û¶m>ìI=o¾ùæþýûÿýï¯\¹²í|ccc;;» 6466¶´´”””ô|ï@Z §f̘±ÿþ==½#F;v,11qÔ¨Q̧æææÅÅÅÛ·o'„˜™™8q"44ÔÈÈÈÂÂÂßß¿«f£££ƒ‚‚ø|>󣕕•s‘háÂ…ÿùÏvïÞm`` ¥¥åééY]]M)))S§N …†††›7o>qâDÛèðäÉ“™3gJ$’ &|þùç&&&=©ÇÑÑÑØØØÆÆF,·OQTlllZZšžžžH$Љ‰éùÞ€ý¯Ož¦i…4çáᑘ˜˜ÀŒ¨‚¡ ''ÇÚÚZQ§€’À¿f¬Àa‡î¡¯¸©úÊÌÌìæÍ›lWƒR ô•@ °µµe» üZ€Z€Z€ðl\r®_¿ÞÍóvÓìíí·lÙÂvÐ_Z`È©ªªJLLd» xnH-0DáòA]hCR QB¡ßàŒÆn@jnP–+D¸& Ï´eË{{{¶«Ö(KjÁmðLUUUl—lR–ÔÂÀmЩ?üðúõëlW,S®Ô‚Û: SB¡í€} Ü€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€ÔÜ€Ô08ÕÕÕ%&&²]€"!µôEQ999½[7''‡¢¨nE(…B qãÆ]¹r¥w…ž‹‹‹spp000ÐÑÑ133ûî»ï¾†ñãÇ;88ôbÅââbò<§Y;½^‘“©…MfffÙÙÙ=\8%%¥¢¢¢ªªª¼¼ÜÙÙ9  _kƒšššùó燄„”——WUUÅÇÇ;99 p ÙÙÙiii·oßîu#ÏušBSRRz±bG8i@±ZØ$¬¬¬žw---­•+WfeeõGI WQQQ__?qâDŠ¢(Š’H$nnn\Ctt´···©©iLLL¯yÞÓ¬°°pÒ¤I½X±8i@!ZúEFF†T*•H$R©4##ƒ™1mÚ´Å‹ÛÚÚJ¥RÒ¦ž™HHH°²²kÖ¬é¾ýâââáÇBvìØ1zôhCCÃ×_¦é®6ÄÌ”J¥“'OvrrºuëV?íø`"‹]]]]\\víÚU^^Þö£Nfnn®‡‡‡‰‰É¦M›Ú^^i÷E‡††Z[[wÕŽœL&‹‰‰Y°`ŸŸß¾}ûd2™¼…ÈÈH¡Phnnž––ÖÕL¹¶•´+’tv -[¶Œbaa#_±ã)“XC+ˆ»»;!$!!áyWLHH „¸»»+ª’CÉÎÎn;G&“YZZFFFÒ45räH™L–žž®¥¥UQQAÓttt´££#MÓL÷»|báÂ…eeeqqq|>¿«­444œ?ÞÂÂbíÚµ4Mµ¶¶Þ¿ŸRTTDÓt§JMMÕÕÕ-//§i:<<ÜÕյߋBõú¼êTÏO¶ÚÚÚ‰DÂãñ|||òóóé.¦L&³±± nii‘Édµµµò/—îðE¯]»¶¦¦æ™_ʹsçÁ“'O®^½J9þ¼¼…+VTVV9;;w?³íDÇ"éÎN¡NWìxJ+ÛI«ðC{ÖAá°C÷T" 1%%%wîÜ™?>!dÞ¼yK—.---MJJ5j”¾¾~7+FDD¨««‹Å⦦¦ŽŸ2«ªªŠÅâ7Þxã³Ï>#„…¨¨¨ÂÂBBH}}=!¤Ó 9s†ÇãBÊËËÓÓÓ¶·ƒš¦¦æúõë×­[—žžþå—_zxxtz0KKK³²².]º¤¢¢Â¬ØM³!!!ªªªÏüR¢££½¼¼´µµ¥R©X,މ‰™2e óÑÏ?ÿ¬¦¦¶téÒ_~ùE¾|§3Ûê´ÈާPGžÒÌG8i` !µô¦kéÕ'„èè蔕•Éd2×ÕGuuuùŠegg·dÐÔÔ$•JƒƒƒCBBºÙ†††‘‘QXX˜"ölÈ¡(ÊÑÑñÀZZZÅÅÅÌv_·MÓE566¶©ªªJžõ¥ÔÕÕÅÆÆÖÔÔÈχC‡ýøãÌ´šš3Áœ3ÝÌì¾ÈNO¡®tº8i` a\‹â™˜˜XZZ9r„rèÐ! ‘H4gΜ–––€€€   “'Oòx 8ò¥¥¥ùùùžžž< „TWWB:Ý··w~~~JJб±±H$}ßú WZZºeËæMÓ§N244‰DLccc;;» 6466¶´´”””0¿Î‹ŠŠrssƒ‚‚:¶ßý—rìØ1--­ÆÆFfëÙÙÙÕÕÕqqqòhšŽŠŠòòòj»V§3å:Ùé)ÄTòôéSùŠžÒ½>ª8i ×ZÀÉÉÉàoE8p ,,L"‘„‡‡_&“íÙ³ÇÖÖ–²cÇŽíÛ·———{zzFEEÉ/ÖüòË/ëÖ­ÓÔÔŒŠŠš2eJÛj;m§£ŒŒŒ•+W>zôHOOo÷îÝãÆcÖŽŽ>|øÍ›7ÕÕÕSSSŸ¹ïr„„„„¶Ëwz@ºoùÂ… ï¿ÿþ•+W† Ö·¯Qñz=ô›+ZZZöïßÕÒÒb``óªç7ntüˆ¹D"ŸX¸paYYY\\ŸÏ§iZ&“ÙØØ·´´Èd²ÚÚÚvË·k¤±±Q$ýþûïmg¦¦¦êêê–——Ó4îêêʬUTTÔÚÚzÿþ}BHQQ‘|•wÞy§±±ñ_ÿú—………L&{f;íjÉd–––‘‘‘4MGEE9R&“¥§§kiiUTTÐ4íèèøÌ}—ëê ´[¾ÓÒÍ’ååå‰$##£«oíÕW_%„>|¸ç_4ôPjjêØ±c !E½ûî»Ož_>¿ÓvºÒ®r²²2™LÆãñºÛnß»jªûåÛn–5jÔüñÑG©©©õd ï.]º´|ùòœœ•>ú諯¾RÂks}4˜ï|îž±±±Ý† ZJJJä1¿‰‹ŠŠrssƒ‚‚˜™vvv >>¾¹¹ù«¯¾bfz{{çç秤¤‹D"@@)--ÍÏÏ÷ôô|ðà!¤ºººÝ¦ÿøãÉ“'¿ð ò9¶Ó‘‰‰‰¥¥å‘#G!‡²°°‰DsæÌiii  :yò$‰ú~Úêô€t#44”¢¨   š¦{^ ôÎÓ§OW¯^íêêš““3zôèäääÍ›7#²À 4tS EQ±±±iiizzz"‘(&&Fþ‘©©©ŸŸŸ¥¥å’%KV­ZÅÌÔÕÕݹsçŠ+&L˜`ggÇÌ433;qâDhh¨‘‘‘………¿¿?!D,ûúúš››oݺuÙ²ežžžÍÍÍÌòÓ¦Móññ9wîܾ}ûÚÓi;Ö|àÀ°°0‰D~ðàAŠ¢ôõõ¯]»fmmíææöÞ{ïéèè(ä ´Õé醪ªêâââÂÃÃ{^ ô¹sçÆŒ³mÛ6•àààôôt'''¶‹ègŠ&£T£q‡ˆ¼¼¼œœœæææÂÂB‡õë׳]ѳa4nßUUU­\¹’¹67nܸnÆ>Cï`X(+pØ¡{C·¯eиsçÎÌ™3ù|¾½½ýرc׬YÃvEÐïþûßÿÚÚÚîÞ½›ÏçoܸñêÕ«û CÁ;XÍš5«¨¨ˆí*`€TVV®^½š¹–7iÒ¤½{÷Z[[³]ÀA_ gÄÆÆÚØØÄÄÄ 6ì‡~HJJBd€!}-pÿþý÷ߟ¹}ÌÃÃc÷îÝæææl0ÐÐנ좢¢lllŽ9ò /ìܹ3>>‘†&ôµ(¯’’’·ß~ûÿþïÿ!^^^¿üòËy3@§Ð× Œhšþå—_lmmÿïÿþOOO/222..‘†8ôµ(‚‚‚•+W2/¦~õÕWúé§#F°]ûÐ× DZ[[·lÙ2f̘„„„_|ñСC‡Fd` ¯@Ydgg/_¾üòåË„×^{mëÖ­Ý¿Ê`¨A_ ûZZZ¾ùæ›qãÆ]¾|Y$Û;7H\¿~ý­·ÞÊÈÈ (jåÊ•›6mz®W` H-ƒGYYYvvöíÛ·³³³³²²JJJŠŠŠd2YÏ[hjjjjjªªªêÉÂúúú‰äå—_¶þÛèÑ£AoËŠ¿úê«ï¿ÿ¾¹¹Y"‘ìÞ½{êÔ©l ¼Z¸ª©©éìÙ³ÙËÌ̬­­í¸˜P(”w0%FFFšššò~ù„¦¦fSS“¼ëEÞ SSSS]]-ïªaºmJKK++++++¯]»&ßÇ‹ÅL|±¶¶‹Ånnn<®Bv.%%eùòå·oßæñx«V­Ú¸q£¦¦&ÛE(5¤ÎxôèQZZZêߊ‹‹Û- ££cgg'ïù1bĘ1cž+4MéÜ IDAT@  {²ðÇÿüóÏüü|yO^^ÞÝ»wïÞ½ûßÿþ—Y†Ïç3Fú7UUœr¤®®nýúõÛ¶mkmmµ²²Ú»wïäÉ“Ù. €ð+DyÉd²S§Nݾ}›‰)wïÞ¥iZþ©ªªêŒ3$‰¼oãÅ_Èò†>|øðñãÇËç´¶¶æåå1}?7oÞ¼yófvv6S<³ŸÏwtt”J¥YªRILL\¹re~~¾ªªêgŸ}öÅ_¨««³]7 ’Ôâáá!mƒ£­««ËÈÈ÷¦äå嵕¢¡¡áàà ßÇ‘#G*ÛŦ›G>§¦¦F¾G×®]+((¸|ù2sgïTSS³fÍš;wÒ4=vìØ½{÷:::²]—p>µüãÿ¸sçΣGNŸ>}úôif&ÓÀüvwtt|饗Ø-²+ 7oÞ¼víó{ýöíÛ­­­òO)Š6lX]]óc}}ýŸþiffÖØØÈçó•-²tJ[[{Ê”)S¦La~|üøqÛ‹\ìÖ6ÀN:õöÛoóùüuëÖ}öÙgjjjlÀ1œO-aaaaaa¥¥¥©m<|øð¿ÿý¯|t…AÛû\¬­­E"EQ\jmmmv·oß¾{÷nÛ˜¢¦¦fgg'ïM±³³SSSËÎÎNHHHLL<þ|iiiLLLLL !äå—_vÿ›™™ÙïKïèêêNŸ>}úôéÌm/x b=úè£"## !&LØ»w¯­­-ÛEpçS C$‰D"___æÇ»wïÊLFFFEEERRRRR’|y>Ÿoooïèèøâ‹/¶½¿ÆÀÀ ïÅ477·}J 3XµãøYBˆµµõ„ ˜˜booßqˆÃèÑ£GýþûïÓ4•••˜˜È$˜ââ⨨¨¨¨(Bˆ©©©‡‡“`LMMû¾ càƒãÀûý÷ßß{ï½û÷ïkhh„„„|øá‡***lÀUƒ$µ´#‘H$É‚ ˜ÿúë/&7È;9>|xõêÕ«W¯¶[QEEÅÔÔÔÈȈ¹=¸ãóÖ455;>¢­¦¦¦ªªŠI*=ê´*uuõ‘#G¶íò±´´ìùN(вµµµµµ ¤iúæÍ›L‚¹páŸþA133“÷Á¼üò˽<‚Ðg> úí·ß!S¦LÙ³g¥¥%ÛEpÛàL-í0)D~a‚ÒÐÐššš™™YVVÖö¹±?fîÝíËæTUUE"‘ü))&&&æææÖÖÖŠê] (j̘1cÆŒùàƒd2“`.\¸PXXXXXøïÿ›bnn.O0"‘H!›†žØ·oßêÕ«+**´µµCCCßyçNŒCPrC"µt¤®®îâââââÒn~kkkaaá½{÷¿ã#Ú˜i‰Dblllhh8ûÂãñÆŽ;vìØU«VÉd²7nÈû` öîÝK±°°pww÷ððpss366È ‡”{÷î½óÎ;'Ož$„̘1c×®]ºf ä†hjéŠŠŠŠ……………Û…ôÇ7nܸqã>üðÃÖÖÖ7n0#y“’’òóóóóó÷ìÙC9r¤¼Fio°âš¦÷îÝûÉ'ŸTWWëêênÞ¼ùÍ7ß cw RË ¥¢¢âàààààðñÇ·¶¶fdd0}0IIIyyyyyy»ví"„Œ5ŠÉëææ6bĶ«æªÂ€€€³gÏB|||vìØ8 pH-C‚ŠŠ s›Ò'Ÿ|ÒÒÒ’žžÎ$˜äääÜÜÜÜÜÜ;wReee%ïƒ>|8ÛUsƒL& ®­­544üñÇ-ZÄvQƒRË£ªª:a„ &|úé§---iiiÌHÞ‹/2÷XíØ±ƒ¢¨Ñ£G3ñÅÍÍm€GêpHnnîòåË/^¼HY¼xñ¶mÛp¬úR˦ªª:qâĉ'®Y³¦¹¹955•郹xñbVVVVVÖO?ýDQ” 3’wÊ”) y¤Í ÐÒÒ²yóæ/¿ü²¡¡ÁÈÈhÇŽÞÞÞl0È!µÀÿ¨©©Mš4iÒ¤Ik×®mnn¾zõ*“`.]ºtëÖ­[·n…‡‡Segg'ïƒÑÓÓc»jvdff._¾<55•¢¨·ÞzkóæÍ=|Q6ôR tBMMÍÙÙÙÙÙ988¸©©‰I0 —/_ÎÌÌÌÌÌüñÇy<Þ˜1c˜3eÊ]]]¶«MMMß|óÍ·ß~ÛÔÔ$‹wíÚõüƒí¢† ¤x>ŸÏ<ÛfݺuW®\aú`._¾|ýúõëׯoݺ•yfŒ<Á ÖŽ‡k×®½õÖ[·nÝâñxß~û­––ÛE !H-ðóçÏ?ÿ¼¡¡áÊ•+Ìó`®\¹’‘‘‘‘‘±eË{{{&Á¸ººêèè°]µÔ××ñÅ?üðCkkëÈ‘#÷ìÙãêêÊvQCR ô’ººº›››››!¤¡¡áòåËLÌ•+WÒÒÒÒÒÒ6oÞ¬¢¢2nÜ8æy0.../¼ðÛU÷FRRÒŠ+òòòTTTþùÏnذACCƒí¢†"¤PuuuBH}}ý¥K—˜sõêUæÍÛ›6mRUUupp`ú`\\\´µµÙ®úÙjkk×®]ûóÏ?Ëd2[[Û_ýuüøñl0t!µ€‚ihhL›6mÚ´i„ºº:&Á$$$\»vyÏö÷߯ªª*•J™ãì쬜£CΜ9PTTÄçó×®]û¯ý‹Ïç³]À†ÔýhذaÓ§OgÞ¶ýôéÓ‹/2}0©©©))))))¡¡¡jjjL‚ñðð˜úèwÞ©¨¨ÐÒÒÚ¸qc```»ËFÀ:¤P"/¼ðÂìÙ³gÏžM©®®NJJbžsãÆ .\¸p!$$D]]ÝÉɉI0NNN c;gÏžýõ×_óóó7mÚÔUøØ»wozz:3}éÒ%55µŠŠŠéÓ§ïÚµËÌ̬ÿöz ©””ŽŽÎœ9sæÌ™C©ªªºpáÓsãÆ f‚¢¡¡áääÄ<f„ òÃ|úÃ?ܽ{wß¾}ÇÇTUU­[·®íœÔÔÔÏ>ûì›o¾¡(ªÿwz©8@(z{{3/U~ôè‘<Áܼy3!!!!!¢®®îìììîîîèèx÷î]fÅ£Gº»»?~|ĈmüòË/ËËËÛÎyúôéÕ«Wj‡ 7Z€côôô|}}}}} !•••L‚IHH¸uëV|||||¼³³sÛå¯]»æäätòäI[[[fÎíÛ·þùçŽ-Ÿ;wn÷îݰРo¦¯¯ÿÊ+¯lÛ¶-33óÑ£G±±±ÇêþùçŸ...gΜa~\½zusss§ þóŸÿ,++ëߢ ·Ð×28}øá‡×¯_g» v¤¤¤tœY]]=sæÌ‘#Gª©©Ýºu‹¢(@ ®®Þî¿¿ÿÀ׬ ¶lÙbooÏvÝAjœ®_¿ÎŒH9š¦sssåÓ ì–¤TªªªØ.àZ3üõ =1”{æ€[Z3{{{www¶«e' Ù. G0¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©¸©úÝøñãz¸pqq±»»{ß7š““CQÔ@®ØVÇ]¦(J(…B qãÆ]¹r…™Ÿ““ÓÇÍ H-п²³³ÓÒÒ222nß¾ÝÍb)))„ºººóçÏ÷zsòvÌÌ̲³³`ÅŽºÚå”””ŠŠŠªªªòòrgg瀀€¾l`BjþííímjjÓÍb………“&Mêûæäí++«X±£gî²––ÖÊ•+³²²ú²€!©ú‘L&‹‰‰Y°`ŸŸß¾}ûd2ùÿ/Áȧ—-[F±°°HMM%„$$$XYY ‚5kÖ0KFDDH¥ÒÉ“';99ݺuK¾n»%åíÄÄÄÈ·’››ëááa```bb²iÓ&BÈŽ;Fmhhøúë¯Ó4ÝÕŠR©T"‘H¥ÒŒŒŒ®6úÌ]¸xøðá :ÌC ­ ̈„„„E5½£$_ĹsçÁ“'O®^½J9þ!dÞ¼yK—.---}æF»ÙekkkBˆªªªX,~ã7>û쳞 €þ#“É233Ÿ>}Z]]ÍüeȨ̀(ÊÐÐPGGGSSs̘1<ž²\™AjþRWWS#¿àrèСü‘™¦iš¢¨ÆÆÆN×UWW'„ÈWÔÐÐ022 {æ’1µ½RÓÔÔ$•JƒƒƒCBBºß‹Ž«w³Ñ®v™Y>;;»#fú‚¦éëׯgee¥¤¤¤¤¤Ü»wér~¦#F;99999ÙØØØÛÛ÷ý^ËÞAjþrìØ1--­ŠŠ >ŸOÉÉÉ=zt\\sKpQQQSSSPP³°@ „<}ú´Ó¦¼½½×®]›’’2oÞ<Š¢ÊËË»ÚhÇvŒíìì6lت¢¢RVVÖÜÜœŸŸïééùàÁBHuuu§+š˜˜XZZ9rdÉ’%‡²°°‰D¹¹¹½ØåW_}µgÇ @ñ***þóŸÿ\¹r%66¶]1EQb±ØÐÐP___GG‡ù‹ÒÐÐP]]]YYY^^^TTtÿþýû÷ï§¥¥ýôÓO„>Ÿ?oÞ¼‰'úûûä¾ µ@‰ŽŽ b~B¬¬¬|||bbb^yå???KKK{{ûµk×&%%BLMM½¼¼¬¬¬Ž9Ò±)33³'N¬Y³&((HSSÓÌÌìÌ™3n´c;EÅÆÆ®X±BOOO[[{ÕªUkÖ¬ñõõ577_¼xñ²eË<==>|ØéŠX¾|ùúõëuuu<øÌ¿-ºÚe¤x>ܳgÏüqáÂùL‰Dâìì~ü˜¢®®þÊ+¯¼õÖ[Ó¦MSì0 š¦ãããýõ×ßÿýøñãÇ×ÕÕ]»ví‡~¨ªÚ/©`PinnNOOOMM½~ýú;w îÝ»Gÿ}oHGjjjÖÖÖ‰ÄÌÌÌÕÕU*•š˜˜ dÁÐw»wïÞ¸q#3ºöå—_þøãßxã ~Ý.EQÓ§OŸ>}ú“'O"##7oÞüçŸ~úé§›7o`† *R À`ššzöìÙÓ§O_¼x±ÝˆKUUU}}}]]]ùßܵµµ=ª¨¨xúôifffff&!dË–-„—^ziöìÙ3f̘1cFÿÚƒ¾;~üøÇœŸŸO‘H$ß|óÍ‚ øŸ^x!(((00ðСCk×®½{÷î|°mÛ¶~øÁÛÛ[Bjà°¼¼¼˜˜˜èè袢"fŽŠŠŠ­­-ó,i‰D"‘HÄbq7¿Ãšššnݺ•“““•••ššš’’RVV¶gÏž={öðùüÙ³g/Z´ÈÛÛ[~w (ÊÊÊÅ‹3w'ØØØ|ýõ×>>>lÝ“L¡(Šy2øñãǃƒƒ³²²|||þñìß¿____!›@jàžÖÖÖãLJ‡‡3W !/½ôÒœ9sf̘1sæLmmíž7Åçóäo)§iúúõë§OŸŽ?{öìï¿ÿþû↓X±âwÞ155í—ýçDÓôŽ;Ö¬YS[[«««»aÆwß}·Ÿ†’–™™éîîþÁ<~üØÊÊjß¾}¹¹¹|ðA{Vzhâĉ111yyy+W®TQQÙ¶m›±±ñ÷ßßÕû¿ ŸìرÃÝÝýþýûnnnׯ_wuue»¢qqqÉÈÈ`*÷ððøùçŸ{ÝR (‹ÂÂÂI“&)sËòvÁs½Q¨ÿv †‚æææuëÖ9::ž?^WW7::úöíÛþþþÿB;SSÓ]»våææ¾úê«555kÖ¬±··gn>‚þÖÚÚºzõê÷Þ{¯¥¥eݺuçÎ322b»¨ç`dd¿nݺ–––÷ßÕªU­­­½h©úÝŽ;Fmhhøúë¯3ÃÛ^a‘O/[¶Œbaa‘ššJIHH°²²kÖ¬a–¤(*''§í„¢ZŽˆˆ`n¸prrºuë–|ÝvKÊÛ‰‰‰‘o%77×ÃÃÃÀÀÀÄÄdÓ¦MVÕ¶€ŽÛèFNNÎØ±c7nÜØÚÚº|ùòâââ×^{Ý ”fff‡¾zõª¥¥evv¶T*ݶm[7σ¾knnö÷÷ß¶m›@ ˆŠŠúꫯ”ç%Ì=Çãñ¾úê«èèh@ðã?.^¼¸÷}uŠzÔ.Ƭ$”ê‹(**jmmež}TTTDÓ4sy…ùT>ÝnbáÂ…eeeqqq|>_¾dCCCÛ …´œššª««Ë¼¢=<<ÜÕÕµ«%;6(“Élll‚ƒƒ[ZZd2Ymmm÷Uuº-Ö)ÕÙ¢<”á°ÄÄÄ0®577ONNf±’NÕÕÕ­ZµŠùõ9mÚ4æÄî#e8ìʦ®®nöìÙ„aÆ]ºt‰íràòåË̉=kÖ¬ç}É€r 9†AI(FEEBêëë{¸VDD„ºººX,–‡qùEù„BZ>sæ Ç $„”——§§§wSC;¥¥¥YYY—.]RQQ!„0¯ä親n¶ÐMÓ_ýõçŸNyýõ×÷îÝ«¦¦ÆvQíihhlݺÕ×××ÛÛ;>>ÞÎÎî?þ3f Ûu *MMM¯¾úê©S§ ÿøãqãÆ±]‘899%''Ïœ93..î•W^9~ü¸ü¥³ÏĽ.&à–¦¦&©TJa~U·EÓ4!¤±±±Ó™GZuÿh,…´¬¡¡addÉ\{êa ÌG2™¬'Uu¿-¹úúzŸÏ?ÿœÏçïܹ3**J #‹œ»»{NNΤI“îß¿ïììüǰ]ÑàÑÚÚºdÉ’S§Nikk_¸papDƸqã.\¸ ­­ýÇøûû÷|Œ R ô¯ÒÒÒüü|OOÏBª««Éßi ¨¨(777((ˆY’y]ÅÓ§O»j*''‡ "Ì„¢ZöööÎÏÏOII166‰Dݼ5£c;ÆÆÆvvv6lhlllii)))é´*ùŠ=ß Y?ž2eʉ'´µµ“““ß~ûm¶+z6##£äää¥K—ÖÖÖÎ;766–튉¥K—ÆÆÆ … .<ל`ee•””¤««{øðá×_ýùVVÔÅ*\’TÊóE´¶¶úúú6lùòåË–- …MMM2™ÌÏÏOEEÅÑÑ‘ùŽYÒËËK$]½z•t›BÓ4!$;;[>¡À–Ïž=ëèè8bÄssóéÓ§Ó]Œé´ÜÜ\WW×aƽøâ‹ß|óM§UÉW|òäIÇm±NyÎ¥ÂÊa©ªªrtt$„˜šš2g;‡Èd2fÜ:Ç‹ŒŒì]#8å¶nÝJQUUcYºrùòeæùx[¶léÉòH-ƒ¾è9œ-øÃòäÉæù—^z©´´tÀ¶«X¿üò !DEEåàÁƒ½Xg##!!ÇãQuàÀ¶kéw¤(ŠÇã;wî™ ã ûZZZæÎ{ùòe±X|åÊccc¶+ꥀ€€ÖÖÖ×^{íâÅ‹l—ÃI¥¥¥~~~2™ì‹/¾X¸p!Ûåô» |ùå—2™lÁ‚%%%Ý/ŒÔÀ¾   óçÏkkkÇÇÇ›˜˜°]NŸ¬_¿þí·ßnnnž3g†œ?¯––ÿŠŠ ///æ&²¡`ýúõ³fͪ¨¨ð÷÷oiiéfI¤–mß¾}çÎgΜ‘H$l—£?ÿüó¼y󪪪æÌ™ÓÐÐÀv9\š””dll5tÞwFQTdd¤H$JNNþöÛo»Y©€M©©©Ÿ|ò !$22râĉl—£</&&f̘1¯½öÛåpÆ­[·¾úê+Š¢~ûí7e~'b000øí·ß(Šúúë¯oÞ¼ÙÕbH-¬yòä ó\ó>øÀÏÏírI]]ýèÑ£:::‡îËÛò†š¦ß|óͦ¦¦wÞygòäÉl—ÂI“&½ûî»MMMo¾ù&ÝÅ;"Zz©®®.11‘í*€Û>ùä“üü|‡ï¿ÿžíZÏÌÌl÷îÝ„O>ù¤  €ír”Ý®]»ÒÒÒD"ÑæÍ›Ù®…5›7o611IOOgnFë©”Eqq1sÓã€iûªÅ^(..öððÈ- sþüù={öðùü ÖGúùù-]º´¾¾>  «¿žòøñãuëÖB¶lÙ¢¡¡Áv9¬QWWß²e !dýúõ=ê¸R °¬±±1%%…RWWwþüùÜ´™™ó¹A¼EPZ2™ŒùE¾nÝ:KKK¶ËéG?üðÃðáÃÏ;Év-Êë믿®¨¨ððð˜?>Ûµ°lÞ¼yÓ¦M«¨¨øúë¯;~ŠÔ,+,,dž¬5ðÁ?${à·JkÛ¶myyy#GŽ\»v-Ûµô/}}ý~øò¯ý«›Wv eýõ׎;(Š g»¥°}ûvŠ¢vìØqïÞ½v!µ@Ù±cÇèÑ£ _ýu¦g¸íõùô²eË!©©©„„„+++@À<œBQóÈf‚Y144ÔÚÚš!•J'OžìäätëÖ-f•¼¼oÁÝ´Ù½’’’;wî0W£çÍ›———WZZš””4jÔ(}}ýçÚY žBHrr2ÝÙ zCDbb"Ajéæ(1G ©` \¹r…âììÌv!ì³°°044|øða»'0 µµµ·oßVSS›0aÛµpÀøñãù|~vvvMMÍà×(ô“¢¢¢ÈÈH¶«¢LMMß|óM¶«€ç“••E3f Û…(…qãÆ>}:++K"‘°] ®_¿.“Éìííù|>Ûµp€ššš]ZZÚõëבZ —ŠŠŠ¾üòK¶«¢ÜÝÝ‘Z¸E&“eggSeccÃv-JÁÆÆ†I-òX)„¶ á ‡´´´ôôt¤è±XüÆo°]ÅòçŸvòpkPz%%%uuuFFFx·ÃÚÚš’——Çv!ì`îúÆszŽ9V¹¹¹H-Ð'b±=.)11©…‹þúë/BˆH$b»eÁŠ{÷î±]; !æææl„üü|ŒÆèwLj122ê~1Š¢„B¡P(ÔÐÐ7n3†—1~üøv×(ŠÒÓÓknn–Ïñõõ¥(ª]³qqq:::fffß}÷]ïö"''§cã½Ãв²2…´Æ9ùùùäïßÄÐLÂ+((@jèw>$„Œ1â™K¦¤¤TTTTUU•——;;;0ó³³³ÓÒÒ222nß¾Ývù'Ož0Oß"„TWWŸ9s¦]ƒ555óçÏ )//¯ªªŠwrrêÝ^˜™™1o$í»_|‘òàÁ…´¦„[[[»ú”I±&&&X·½üòË„¿þú © ßÕÕÕB† ÖóU´´´V®\ÉÜyD‰ŽŽööö655‰‰i»ØÔ©Så/–;zô(ó(”¶***êëë'NœHQEQ‰ÄÍÍ­w{!¬¬¬z·n;Ì›¹êëëÒšzðà±±ñO?ýÔ¶'ŒQ[[[__?lØ0¼ž¬ç444´´´Zú]CC!DCCã¹Ö*..>|8!D&“ÅÄÄ,X°ÀÏÏoß¾}2™L¾ŒŸŸßÑ£G›šš!\´hQ»FÄb±«««‹‹Ë®]»ÊËËÛ~!•J'OžìäätëÖ-ò÷5 ÐÐPkkë9sæ„……1K;vlæÌ™m¯åææzxx˜˜˜lÚ´©ÓÖºÁЧOŸ†……mß¾}÷îÝÑÑчª¬¬$„dff^¹r对¹¹EEE÷ï߯ªªª¯¯çÐSéþÿ±wçñP}ÿÀÏŒeȾµ ¬•¥Ý(-¾ñiÓBöTD‹´(ÚTŸvmŠD{$DY³¤ä“í i!Y+EYÃXæþþ¸ßÏ|ýcî ïçŸ3÷œûróáížsϹ7qâÄœœœö£?$éöíÛžžžÇŽ[»v­¡¡á‰'TTTÒÒÒ6oÞœ““#--}öìÙuëÖ=zôoR]]’’’°oß¾-[¶H$FŸ†™™™ß½{—L&×ÕÕuÒ[‡xyyI$Nß¶m[ûwœœ:lE"‘øùù)Š€€€€€@'tþnçððð0ùÏÔ ¼NEåææZYY¹»»»¹¹Íœ9!TSSƒbíÓdÉÉÉjjjuuuAAAóçÏŸ1cþ>¶ˆaØû÷ï544Ú4AÕÖÖîØ±cõêÕoÞ¼aa$–EPµ@¯ÊÍÍõôô¼téB¿#Ò9ü‘`^^^|Y;v „‚‚‚æÎ+""B¥RƒƒƒU ©©iDDDII‰©©i‡³e…„„öìÙ³{÷îW¯^íß¿___?///11‘L&;::"„ÊÊÊ^½zÅ8ÞÕÕ•——×ÐÐpõêÕ)))ƒ~óæ¡¡!þä B¨¤¤$33óÙ³gø/x!!¡NzëPss3~ûaܸqÓ¦M£Ñh <(//3fŒ  `ÿïÒþU]]ýÇ+Ùm|||=¬{***Z÷™––6kÖ¬Ù³g=zŸïB¡PXž|À€>|8|ø0£jÁÇ_¿~|äÈ‘ö­ð±È .°<káW ªè)))îîîQQQ---x1ÁÌ4ެ¬¬6sGêêê"##kjjIDDÄ©S§ðOÍÍÍMMMóòò<==;é™D"iii…††  ÊÊÊ2Æ€ZãååEQ(”%K–ÈÈÈØÚÚòññµî !Ôz ª“Þ:ĸ999‰‰‰ÒÒÒø§úúúIIIÞÞÞzzzí[aÖØØØ¦Žaþ&kjjjjjÂïˆt[‡‹ ß¹sçîÝ»ø^€½Qµà.\èë닌-º¹¹ >üêÕ«‡"“;˜Â‹ÄaæààÏÏÏ?wîܳgÏ"„Μ9ÃÏÏO§Ó/]º4jÔ¨ììluuõ£Gª¨¨èéémݺ!{îܹþù§ó&]Ù U °†a·oßvwwÇ7{à <øëׯøœÜ®Š.//ǘ²³³544âããMMMñtuuùøø¾|ù2a„>´i^RRabb¢  €JHH‘‘‘——722Ú¹sgrr²™™‰Dj3åggg7kÖ,‘6Ã=rrr£G>pà€››Ïׯ_™é­µ_¿~!„(J]]Ý™3g˜\ö‰D"Q(”Þû}kjjêaÝC£Ñ(ÊÛ·oÛwÎÏÏߥIÙÝ %%ÅøNëdl×f,WPPàëë[VV&--ß ìÆxâ›tõëÂke¨Z€5šššBBBÜÝÝÛÏEUSSûúõkiii7º Ú°acNŒššÚÂ… ƒƒƒU //o``   `‡ÃC %99ùôéÓ?~üàãã1bD\\…BQRRŠ‹‹Û¾}û† „„„”””Ú?5­¥¥%''7tèPEEÅÖ¯“H¤ÈÈÈU«VIJJŠˆˆ899íܹ󽵆?ó,''÷éÓ§³gϺ¸¸ôöïræññññññ‰ˆˆô¤“›7o†††¶~E\\|íÚµ7n,..¾qãFëYÌß*++2dþq'c‹ŽEâäåå'Mšd```ccckkËÏÏßñÄ'NtÞ¤«_~Å jÖxñâźuëð»mhkk?xð_¥£>#ßæ•èèè6ÇÏ;ÿ@MM­M'222aaažnÆŒ©©©­_iÓœD"µ®ÀZ¿;bĈ67`Ú÷Ö üR¨ªª8099ùòåËø¯·>ƒ1!$//ïìì¼zõj¼Âï齪%..ŸöÛùØbû±H>>¾'Ož$%%ùúúž>}:33³ã‰lÒUøƒ'Ÿ€5¦M›öòåË#F´ Ÿ¥QRRÂîLœ ¿rrr...!OOÏææf¢C±^µhhhøûûçååmÙ²…qóFXX!ÔŠëëë/^¼´gÏôïØ"FÃ0 𬬬ªªªöEp{555ååå3gÎôööÎËËûþý»‘‘Qnnnrr²œœœ¼¼|‡ƒtvvv!!!þþþööö!fšt ~Å j–ÑÐÐxñâ>Ý’AHHhÆŒ øúõkUUQÙ8 >sĈ .1bD~~~dd$Ñ¡XI^^>666##ÃÎήÍïøº#œúó;:::ÒÿbìJ¦££#%%%''wûöí‡âëßÿnlñ§¨®®ž3g޲²òĉ÷îÝ;tèP|<ÑÍÍMVVVUUuÉ’%í[á㉚ššøx"3Mº¿G#DÀJïÞ½{úôéôéÓ=z„§hiiñóó«««§¥¥effN™2…èŒÄÃ×üÕÔÔ$“É[·n]½zµ»»{û%ò¸W‡Ï@áDDDýúUWW×ÕÙ<Ž!þnñ=fÆ;$''×~í–®Ž'2Ó„yõõõµµµ îµË”””XXXÐh4mm툈|,`Ò¤I!MMM„P‡Ï•ôCéééèßkbcc3xðàW¯^µ_Ôµ¯ÂgË„kàCв²²PµÎUTTÔÉß+œÐ3 ·À}@CCƒ©©é·oßfÍšåææffföüùsUUU¼jÁÿûôéS¢c/77·¬¬làÀJJJ!7"„ðúÆÆDáø.Ù***PµŽC£Ñ’““Buuu>äÀžýtu \FCÐ'­]»6%%EYY944_4vÔ¨Qúúú!]]]„ÐãÇ NÉž!«õ ããåË—#„TUUñi\®ƒot0räÈöo-[¶ ÿ•Ôç¿«ªªÈd2…Bill$: hjj¢P($©²²ž|ì#..~åÊ•üü|ÄÜ6r¸€€EEEÆ~¹ŒAÆ,鹓%«Ûgh£ý¸§êê¹€cÕ××›šš~ÿþÝÀÀàðáü`Á~~þ'Ož”——3ö ìoÂÃÃBÆÆÆíßÚ¶mÛ•+WPï¬ÀÆQDEEGŽ™•••šš £Æ”––F£ÑÔÔÔÄÄÄ`„°Icc#•JEµ_·Ã0ôûõ­ñŧ;yT‡U=3ÖŸöðð ÄÇž˜ÌÐ~ ÜNRu~.À]ð]âTUU¯]»†×¬644lnnöóócOG¿{ :Ǹnj`m\À6%%%¹¹¹ø®iø ¡x5PPPðáÇ 6àGâ ?w¸™ .;;/DðXÕ3óëO·ï‡±.Fknn...î0£!Ë׺„ðòò ŽŽŽ–`¦ÉŠ+B~~~X·ÖÚâvÑÑÑÚÚÚ£Gîð€¡C‡â‡1Ó”K1† ‰Âîß¿þ­ó jl¢¨¨hll¬¢¢âååµ|ùrƒ¦¦& ‹áÇ/]ºÔÉÉ ?RAAaîܹjjj555v¥®®Ž»à°ªgæ×Ÿnß¾nZZ𤤤¼¼|ppðïRá ¥¥¥Y»Ö5`¿û÷ïoÛ¶D"Œ5ŠÉVC† ùøñã;wz5g:}ú4BhåÊ•¿;@\\!TYYéïïϾXD˜1c™L~üøqŸ롚ššG‘Éä3füïUVM™i}‚3gゞƒÙ¸lÓùe)((À'¦üý÷ß]íùرc!}}ýžFä6ø"IÒÒÒ¿~ýúÝ1ŒåUTTš››Ùý¦OŸŽ !:GÃw,ÿÏþƒ ÷Z kêêêLLLÊËËçÍ›wðàÁ®6_³f˜˜ØƒÚoõÒ·á嚣£ã7ß‘——ÏËË»~ý:[rŸ’ÌØt(** µš¾ U t½½}zzúðáï^½J&wù§¨¨¨èºuëB›7oî…têñãÇñññ"""[·nýãÁ–––¨,ðoiiI"‘âââ*++‰Î¡ªªªnܸA"‘ðo U tɉ'®]»&""ƒOÂè†mÛ¶IJJÞ¿ÿöí۬Ǚ0 Û¶mBhëÖ­øº›3gΠAƒRSSñi˜}•¬¬ìŒ3êëëñAÐ^XXX}}½¾¾¾œœþ T-À¬»wïnß¾D"jhht» ‰Ý»w#„œ›››YC]»víÅ‹C† Ù²e 3Çóóóãþ?~¼—£ÌÎÎ!tîÜ9¢ƒp(üÊ૊ã j¦äçç[YYµ´´ìÞ½ÛÄĤ‡½9991"''çèÑ£,‰Ç±~üø…9r„™-¸µk× ß¹s§oÏþ155ûöí³gψÎÂqž?þæÍ111333Æ‹PµÀŸýúõËÄÄädž††û÷ïïy‡d2ÙÇLJD":tèãÇ=ïcmÞ¼ùû÷ïýõ—­­-ó­$%%W­Z…aXßžÝ"((¸~ýz„ÐÉ“'‰ÎÂq¼¼¼Bëׯd¼U ü†a+W®|óæÍÈ‘#ƒ‚‚º1·CÓ§O_µjUcc£••ÕïVpævW®\ÄK´.µÝ´i_xxxaaa/Åãëׯçç玎†ÍÀ[+,,ŒŠŠâççÇ«:¨ZàÜÝÝÃÂÂDEEcbbÄÄÄXس‡‡‡ªªê«W¯\\\XØ-‡ÈÏÏ···Gyxx¨¨¨tµù°aÃ-ZÔÔÔÔ·ïC 2ÄÎή¥¥e×®]Dgá »wïnnn¶µµ•••mý:T-Йþùçï¿ÿ&“ÉAAAŒ ;YETT4$$„ŸŸÿÔ©S¬íœX ÆÆÆUUUfffø“ÞÝ€¯>ìçç÷óçOÖÆã(»ví¢P(¡¡¡999Dgá?~¼ví…BÁ'­·U üÖ—/_–,YÒÒÒ²wï^##£Þ8•Jõðð@ÙÚÚ¾xñ¢7NÁ~t:ÝÚÚúíÛ·***ÁÁÁÝîg̘1sæÌ©­­íÛOÙ 6ÌÞÞžN§3¶é眜œètúªU«† Öæ-¨Zà·öìÙóóçÏ… îÝ»·÷βaÆ5kÖÔ××Ïš5ëÓ§O½w"¶Y·nÝõë×ÅÅÅoÞ¼‰oeÚmøØÙéÓ§ûö~Šûöí“HHHˆ‹‹#: ÁnÞ¼yûömqqñ}ûöµªø­OŸ>©««_¹r¥«3I»êôéÓÓ§O¯©©™1cFqqq¯ž«·•Jýþý{`` Kâq&iié „6nÜØØØHtÂ466nܸ!´ÿ~™öð²=èS Xò(`Rß~˜‚£!„„„„bbbDEE{ût¼¼¼qqqsæÌyþüù¤I“RRR‹rŸ½{÷òððO:•%}º¸¸XZZž8qÂÞÞž‡‡‡%}r õë×ûúú¾{÷nûöí}{r'vîÜ™ŸŸ?jÔ(|™ÁßbÕÞŒ°y,‡`۞π°çso‹Ço®=z”ç­¬¬ÔÒÒB)((dee±óÔ=G§Ó·oߎ"“ÉÝë¤ÃïÆææfü¤ˆˆå`iii|||d2ùåË—Dg!@JJ ™LæååMMMýÝ1p¯t“¢¢b‡ƒŽ\!00°  ÀÖÖVQQ‘è,ÝÁ¥±¹ÅÇ—,Y‚aBHGG‡§KLLœ={vjjêĉïÝ»§­­ÍÎÝF§Ó—/_~åÊ>>¾k×®™››³°sž-[¶¬[·ÎÝݵ=sš &lß¾ýСC–––¯^½’ :ûTVVZZZÒéô;vàµ{gXU(Ámþ!:×§5¸­UWWkjj"„ð1uB.K]]¡¡!BˆŸŸÿÂ… ìÐUŸ?žxðà§OŸÎ™3§7Î"((èèèˆúÁ~ŠüüüaaaâââÑÑÑ}{7ƒÖNœ8%..ÆÏÏßÉ‘PµÀ>|8**JBB"&&†ØYŸ$iÏž=ÁÁÁ  RWWúô)y:T__ïìì|ø`mmÿèœ;w.ÑqþGMMíÍ›7»víâááñóó6lXpp0†aFÊÏÏ733›8qâÇÕÕÕSSSœœz{=ܦM›xyyCCC¹}IfìܹÓÌ̬±±qΜ9YYYDÇéYYYsæÌill455ýûï¿™iU  ¿«®®611©ªª²°°ÀŸÝå(|||‡JKK›>}zEE…††Æµk×èt:›“®^½zäÈ‘QQQ"""ÇŽ{ýúu¯Ž µ¡¨¨hiiÙç÷Sd Y°`AyyùÔ©SûƢɭåççO:µ¬¬lþüù¡¡¡L¶‚ªЯÑéôeË–eee=Úßߟ=÷ ºa̘1III§N’¡æªÀ IDATÈÎÎ^ºtéÈ‘#O:USSƳ¿xñÂÚÚzĈ¾¾¾---NNNŸ?vqqé|âdoÀ÷S¼téREE›OÍ~|||ááázzzºººïß¿':˼ÿ^WW·¢¢búôé|||L6„ªЯvìØ¶mÛº×T-€~‡N§[[[øðaìØ±~~~\÷7k‡¨T*•JݱcGSSÓ«W¯RSS_¿~ýñãǼ¼¼ÏŸ?ûöíÛ·o6äããSWWWVVVRRÒÕÕ¥R©C‡esø®277WVVÎÉɉ‰‰ÁW‚ï'¶nÝ:~üxKKË„„„ñãÇ߸qc„ D‡ú³ôôtCCÃÏŸ?KJJ†‡‡Ï˜1£Û]AÕèwöïßóæM))©èèè‡Åøøø&Mš4iÒ$Æ+MMM?~ü¨¨¨(//g¼($$$!!1hÐ n¼<<<›7ovtt<~üx¿ªZBø2ÄÏž=£R©Ë—/÷ôôäÌ[b¡êêêÍ›7_¾|ðɓ'GFFÊÊÊö¤C¨Zú²ÀÀÀ¤¤$¢Sp¢‚‚„P@@\ôïÕè?¢££:„/VöÇåÃû>>¾Áƒ<˜è ¬´|ùòýû÷¿xñâÑ£GÿùψŽÃV²²²=òôôÜ»wïåË—oݺuäÈ;;;Ž,£Óéÿýwii©€€À¶lÙ²2Xµm#lË!ð˜×Oþ·ÍÌÌÄÙ=qâDçGÂO3Bté²ïß¿!4þü^ʾ|ù2uêTüa*•š˜˜Ht¢ÿJLL¤R©x°)S¦|ùò…U=ý–¾ÉÖÖvúôéD§à\¶¶¶ŠŠŠDgáýáRTVV×ÔÔ,]ºtóæÍDÇ=µ~ýúãÇÇÇÇãÛt‡C† yüøqhh¨‹‹Kjjê¬Y³FuäÈCCC¢"ݼysçÎ!yyùcÇŽ-^¼˜õSÇXUÁ_'€+À7j?ÔÒÒ2oÞ<„ÐøñãýúõÇãᛄ]½ìŽŽŽ![[Û^ÌÄ jkkÝÜÜ$$$ðßéjjj~~~uuul PWWççç§®®Ž?zôhmm-ËOÄAc`Ð{öìÙ/##Ó'gàö[›7oæåå )))!: ‘„„„¶oßþõë×ýû÷ ggg¯\¹rРAöööOŸ>íÕS?{öÌÞÞ~РA+W®ÌÊÊÞ¿iiéŽ;zc±i¨Z}_ddäÑ£GyyyÈŽXFIIÉÜܼ±±ÑËË‹è,Ä£P(ûöí«¨¨ š9sfMMÍ¥K—¦M›&))¹jÕªØØØ¦¦&–œ¨©©)66vÕªU’’’S§N½téRMMÍÌ™3¯\¹RQQ±oß> …Â’µóZ}\FFÆòåË1 óððÐ××':`±mÛ¶…††úúúîÞ½[\\œè8Äãååµ¶¶¶¶¶.,,ôññ ÉÏÏ÷óó×&5jÔÔ©SÇŽ;fÌ•Aƒ1Óç·oßòòòÞ¾}ûæÍ›gÏž½{÷Ã0ü-EEÅÅ‹;88°çï¨Z}YEE…±±qmmí²eËœœœˆŽXo„ 3gμ{÷î… vìØAt¢  pøðáÇ¿{÷...îåË—7oÞ|÷îÝ»wïÇðòòª©©ÉÈÈHII‰‰‰162lhh¨¬¬üñãGYYYvvvsssëžyxx,X0qâDCCÃÑ£G³ó‹‚ªÐgµ´´,^¼8//J¥^¸pè8 ·¸¸¸Ü½{÷Ô©S›6mê½± î5zôh¼¶hiiyþüyfffrrrrrò‡š››ñç}:G"‘FŽ©££££££©©9yòd–­¼ÒEPµú¬]»výóÏ?ŒŠŠbü úžY³f?>===((hÕªUDÇá\<<<Ó¦M›6mšƒƒþÊÏŸ?³²²~ýúUUUUVVF§Óñ×Éd²ŒŒŒ˜˜˜ººº¤¤$q©ÿ¨Z}SXXØñãÇñ=ç8cÐCÛ¶m[²d‰‡‡ÇŠ+8j‰X‡O§%:EÀ?- zóæÍÊ•+1 óôô„û EEÅ>ܸqƒè, AÕèk~üøabbòë×/;;;|2Ðçñòòâë?~œè, AÕèSZZZ¬¬¬òóó'Nœxþüy¢ãöY±b…””ÔóçÏŸBBBëׯGp»¥OƒªÐw\»vÍÃߟ?22R^^žè8€Ý póæÍ÷ïßô x†¨ (,,$:Ç)(( :`½ôôt{{{„——×´iÓˆŽ ##cggwîÜ9Ë—/°T-}\```RRÑ)èuåå妦¦uuu+W®\»v-Ñqa¶lÙrñâÅ«W¯hãÆ±±±>| : è2¨ZœâóçÏ[¶lY²d Ñq@ß4hРeË–ÑétX´AÕà ¦¦¦¥¥¥3gÎtss#:è˶nÝJ&“ƒ‚‚JKK‰ÎºªGX·nÝË—/•””BCCa.èUÇ711ihh8uêÑY@×@Õ ÞÙ³gýýý…„„¢££¥¤¤ˆŽú>|ÿóçÏ×ÔÔtT- ×ikkO˜0Ƀ‹ŠŠôôôz~Òììl‰ÄΆ 7oÞœ6m𤤤¸¸øÐ¡C­¬¬zÒ[ðèÑ£M›6‘H$??¿±cÇô “&Mš>}zee¥¯¯/ÑY@@ÕzWVVVZZZzzúû÷ï;9ŒF£áË'ÔÕÕ=|ø°Û§cô£¤¤”••ņ†m\¿~ÝÚÚzëÖ­ß¿¯¨¨xò䉡¡a—z`$醞´%Jqq±……ESSÓ¶mÛ-ZDtÐ0öSljj": `T- w)((wrX~~þäÉ“{~:F? EMM [Ã0l×®]nnnÆÆÆ¼¼¼$IAAaéÒ¥]ê¤'—‚U—‘mð¸ß¿Ÿ={ö‘#GˆŽú—yóæ5ª¸¸8$$„è,€YPµ€^D§Óƒƒƒ----,,®^½J§ÓÑÿ‚a|¼|ùr„ªªjjj*BèÁƒjjj eûöíø‘T*uÊ”):::Œ¶mŽdôÌ8ˇôõõ¥¥¥‡Š/þüy |µ¦§§S©Teee*•šžžþ»“2”••}øðÁØØ¸Ã«Ádom’¸¹¹©««w˜¹ý—ÆhÛã:6qppHMMUQQ ááá!:è_û)º»»Ã~Š\c|FƒXÕ!è¡ÞøyðàBHOOïGÞ¿ŸB¡TWW¿|ù!ôðáC ÃðñüÆÇm>X´hÑׯ_ãããùùù1 KMM•(++Ã0ìÌ™3ººº¿;²}‡t:]SSs×®]ÍÍÍt:½¶¶ð‚‚‚––ü¡Ç‚‚‚ß5>|x`` †aW®\1bNïð¤ ÙÙÙ¡¦¦¦ö—‚ùÞÚ$Ù¹sgMMM‡™Ûi­¯mÏÿùz›··7BHXXøíÛ·Dgéü4#›/{cc£¼¼)))ÅÅŹ¹¹ÉÊʪªªv²CMû~H$RdddZZ𤤤¼¼|pp°¢¢¢±±±ŠŠŠ——×òåË ššš:lêáᡬ¬|æÌ™°°0fÖqY´hѵk×|}}¥¥¥……… ð ƒùÞ:¼fnÿ¥1Úþ1'ìíí_½z5|øð«W¯’Éð#ÏÉɉB¡DGGüø‘è,€9¬š&ó×8 ±³q"öŸ¿ó$""’‘‘AHæÁO3BuÙíííBl>/è*øCÀ&÷îÝÛ¾};‰D ÐÔÔ$:ÿ³eË2™ˆÂŽU èØïæÉÐ=VVVÍÍÍ»ví255%:ÿÏÈ‘#.\ØÐÐpúôi¢³€Î@Õ:öüùs}}ý¤¤$¢ƒ€¾ ®®ÎÄĤ¼¼|Á‚ :Àø?wî\mm-ÑYÀoAÕ~+))I__jÐs«V­zýúõˆ#‚ƒƒa.àL“'OÖÕÕ­¨¨¸téÑYÀoÁðP»€rww ‰‰#:¿…ßn9yò$ì§È±`mÜ~¡´´´   KM~þüÙúÓ¤¤¤¤¤$==½}ûö±2èëwîÜI"‘®\¹‚o¨ÇZ°`††Æû÷ïì­­‰Ž:UK¿°xñâ®67n\ûñÚECCƒ¡@ß÷éÓ'++«–––}ûö-\¸è8ü¾ŸâŠ+ÜÝÝ—.]ÊÌM€Í jé㬨¨Ø†’’’¾...®­­ýþýûÅýÀ¯_¿LLL~þüidd´wï^¢ãÀ”¥K—îÙ³çíÛ· sçÎ%:h ª–>.$$¤{ “’’îß¿ßúqqq'''ggçׯ_v©·€€€ÂÂÂî%ÌSPP°³³#:Ba¶bÅŠ·oߪ©©Á \À-øùùœœ\\\ÜÝÝ¡já@Pµ€?cÔ+øžÆÝ“yÙ@OOCª–cÇŽ…‡‡‹‰‰ÅÄÄˆŠŠ€.ppp8|øðƒRRR´µµ‰ŽÓS/_¾ÌÍÍÍÍÍ-**úöíÛÏŸ?«ªªx“H$III111QQQ•aÆÉÉÉikk«ªªràT- 3=¯WZ³³³SPPèy? ½Â€€¢SüWBBÂîÝ»ÉdrppðÈ‘#‰Ž@×ˆŠŠ®Y³æØ±cîîîáááDÇéŽÌÌÌG=zôèÍ›7YYY<þË—/í_$“ÉT*U___WWWWW—Cþü€ªtLXXxß¾}›7ofáwª­­-¾É`¹¤¤$©Zrss—,YÒÒÒâêêº`Á¢ãÐ7nôòòŠŠŠÊÍÍUUU%:S0 ûçŸnݺÑz_^^ÞqãÆ3fذa rrrââââââBBBø­ Ã~üøQUUUSS““““]\\üöíÛâââ—/_¾|ùòرc¼¼¼úúú†††¦¦¦rrrÄ}•Pµ€ß R©T*•è€ËÔÖÖš˜˜TTT˜˜˜ìÞ½›è8t“¬¬¬µµµŸŸŸ§§ç¹s爎óÙÙÙ—/_(++Ã_2dÈ_ý¥««;}útf6—••Å?h=•§¢¢âÅ‹ø=›gÏž%&&&&&:;;Ïœ9ÓÞÞÞÔÔ”ùjPµXÃ0;;»ŒŒ ÀÀ@€y[·nõ÷÷Ø¿ÿÀ‰ŽÓ:~ûömooï»wïb†]¹råâÅ‹©TjÏÿ”000000@ÕÖÖÆÄÄܾ};,,ìÎ;wîÜ‘‘‘qppX·nÝ!CXðÅ0 &öXãÈ‘#ׯ_‰‰!:=¢¦¦fhhX__æÌ¢³´…aØõë×ÇŽ»`Á‚ÄÄD{{ûçÏŸWUUyzzjkk³üoaaakkë«W¯VUU]¸pAKK«¬¬ìСCJJJŽŽŽŸ?fíé:U €nݺµwï^2™|õêÕáÇÀø?{öì¯_¿ˆÎò?™™™ãÇ777ÏÈÈ:t¨‡‡ÇÏŸ?}||tttØpv!!!‡ÔÔÔÇÑh´³gÏ*((899ÕÕÕ±!T-€žÊÉɱ¶¶¦Óéœ7oÑq`©S§N:õçÏŸ~~~DgA¡ÂÂBSSÓQ£F½yófèСçÏŸÏÍÍݲe !·6§M››™™iii‰aØ©S§.]ºD§Ó{õ¼Pµz¤¦¦ÆÄĤ²²ÒÜÜ|çÎDÇ€•ðÛ-žžžÍÍÍÆ ÓéÞÞÞÑÑÑBBBnnn?~\³f ???©Baaa¯_¿ž8qbyy¹½½½žžÞÇ{ïŒPµºðeË–½ÿ~Ô¨Qþþþ0ô1†††êêê………aaaDeøôéÓˆ#œëêêV­ZõùóçíÛ·S(¢ò´7zôè/^xzz0àñãÇ£Fòòòê¥sAÕ较ÆÄÄHHHÄÄÄ #“É[¶lAyxxàÏé°YTT”––V^^ž¬¬ì7|}}ÅÄÄØƒ›6m*))Y¶lYccã¦M›Œ+**X~¨ZÝwàÀž¢ãÐ+¬­­eee_¿~}çÎvž—N§oÙ²ÅÌ̬²²ROO/##ÃÐкABB"00ðöíÛ¢¢¢±±±ãÇ/..fí) jtGvv¶ N?|øðœ9sˆŽ@o¡P(NNN!www¶´ººÚÐÐÐÓÓ“ŸŸßÛÛûþýûl;{¼}ûvâĉ………±±±,ìª@—UWW›˜˜TUUYZZº¸¸€Þåàà **zïÞ½´´46œ®²²rÊ”)ñññ222÷îÝÛ¸q#×ÍSPPxüø±­­-¾^ö… XÕ3T-€®¡Óé666ÙÙÙcÆŒ¹|ù2×ý< «ÄÄÄ[n·P©ÔÌÌÌ‘#G¦¥¥M›6­·ÏØKøùùþþûo ÃÖ®]{ðàA–t U  k8pãÆ )))ü!L¢ãÀNNNüüü‘‘‘Ÿ>}ê½³äææŽ;6//O[[ûÙ³gC‡í½s±ÇáÇýýýyxxöîÝ»nݺžwU ÿUWW—””Dt NsðàA|®²²2Ñq`99¹¥K—¶´´xzzöÒ)JJJfÍšU]]=eÊ”û÷ïKJJöÒ‰ØÌÎÎ.66–ŸŸÿüùó‡êaoPµ.F"‘²³³YÕ[QQ‘¾¾~ûS໺‹ŠŠêééݽ{·}Ãììì~2JòþýûeË–aæææ6kÖ,¢ãÀV[·n%‘HþþþŒ­•Y¨¼¼|Ê”)“'OþçŸúØ:óçÏæááÙ³gOPPPOº‚ª€?HNN®¬¬,--]¼xñüùóïÝ»×æ%%¥¬¬,B²±See¥‰‰IMMÍâÅ‹·nÝJtØMCCcÁ‚uuugÏžemϦ¦¦ÅÅÅcÇŽ½uëV+Yp>>>$iùòå7oÞìv?PµÀ”888¬_¿þðáÃmÞ¢P(jjj„¤b:nmm““3nܸK—.bôÒ~Š?–——OHHà¢'œ»jÅŠ®®®---K–,y÷î]÷:ªô5éééT*UYY™J¥¦§§ã/~øðA___ZZzèСøSçÏŸ×ÐБ‘±±±a~ÉË… ¦¤¤ G…ÜÜÜÔÕÕ#D ,ðððÀŒÅW1  R©S¦LÑÑÑÉÈÈhÝ–Õ_z/Ú»wï­[·¤¥¥£££ @tˆ¡««;yòäòòòË—/³ªÏ3gÎ ÅÅÅ <˜UÝr¦]»v-]º´¦¦fáÂ…ÕÕÕÝèªЧ`¶+k?$«IDAThÑ¢7~úôÉÉÉÉÊÊ Ã0 ÃÌÌ̦NúíÛ·¢¢"|û¼yó222222‚ƒƒ‹ŠŠ˜ì_JJªõnìÕÕÕxƒ³³³ó÷÷Çk ‡´´´Í›7'$$<{öÌÆÆ¦õúîýKˆëׯ9r„——7,,LQQ‘è8 ¿ÝròäI–짘––†·FDDŒ7®çr8‰tåÊ--­üüü•+Wv£¨Z@ŸR\\üñãGsss„™™YNNNIIIIIIff¦‹‹ ‰DÂÖ¿råʹsçBõõõLö_VV6dÈƧ®®®­G  ¿~ýš’’RTTôæÍCCÃÄÄD2™ìèèheeõêÕ«ÖmYò%÷¶ÌÌL;;; ÃŽ?þ×_‚-\¸päÈ‘ùùù=쪱±qÑ¢E4ÍÑÑqîܹ,‰ÇùÈdrXX˜˜˜Xddäùóç»Ü¼72@,|¼†N§wø)B¨±±‘J¥"„»Ôs\\ÜÌ™3Ÿòòò¶~—B¡,Y²$ ÀÏÏÏÖÖ–OPPPVVÖÃÃÃÃÃ#00°õOmÚr¦ŠŠ ccãÚÚZkkëM›6â‘ÉdüîHÏWœÛ´iS^^Þ¨Q£zïijΤ¢¢€rqqÉÏÏïR[¨Z@Ÿ2tèÐáÇGEE!„"""TUUååååääF}àÀÖÜÜ\\\\RR’››k``ðíÛ7„PUUÕ{®¯¯¿xñbPPО={:9ÌÎÎ.$$ÄßßßÞÞ!ddd”›››œœ,'''//ÏQ›Ëÿ>i.77w„ >>>DÇ€SØØØ 2$===11±Û$%%?žŸŸÿÚµk|||,ŒÇŒ/^\[[»jÕª.m¦ U àn:::Òÿ  ‘H¡¡¡ÊÊÊgΜ #‘H$)222--MRRR^^>88XQQÑØØXEEÅËËkùòåMMMœBJJJNNîöíÛ>ì|sc---999MMM|þ‡’’R\\œ›››¬¬¬ªªê’%KX~zÏîÝ»ddd¢££‰Ž§ P(7nD=¸ÝÒØØˆÿ¶Þ½{÷èÑ£YšŽkœ:ujàÀ÷ïß ìrcŒEôôôB<`U‡€=xð!¤§§Ç|øÆèmÌÿ£0ydxx8‰Dâããë·ÿjðMKn¹ì"""¡W¯^u£ùñãÇBªªª,ÏÆE‚ƒƒBƒ®ªªb² Ük´õîÝ»åË—cæááÿ´&..¾zõjÔ­Û-߿߿?Bèܹsýpl¨µ%K–L:µ´´”ù•þ¡jü??þ466þõë—­­-~О³³3??DDDWç“:t¨®®náÂ…°-‰D:uê‰D:}úôçÏŸ™iU àZZZ/^üéÓ'mmí .Î%//¿xñâæææ“'O2ߪ¸¸ØÇLJL&·_e»š0a‚¥¥eCCÑ#G˜9ªÀÿìܹóÎ;ƒ º~ýº€€Ñqàhø~Š—/_.//g²ÉÑ£Gi4Ú¢E‹455{5Ù·oÏÅ‹KJJþx0T-€ÿ¿âã㋈ˆ:t(Ñqàt£Fš7oÞ¯_¿˜ÜO±¼¼<00D"qË"“ì¡®®niiÙÒÒrúôé? U !„^¿~½råJ ÃNž<©««Kt¸c?ÅÖ{}üÎÅ‹ëêêæÍ›§ªªÚûÑ¸ÉæÍ›B¾¾¾µµµ U ýøñÃÔÔ´®®nÅŠëׯ':\cúôé“&M*++ó÷÷ïüH:~æÌ„,3Ý•J6mZEEþ,t' j ¿knn^´hQ~~þ¤I“ð™ÌsqqAyzz¶´´trXBBBii©ªª*ìçÕ!|sÙ?PµÐßmß¾ýÞ½{ƒ¾~ý:wí9'0661bħOŸ"##;9 ßygåÊ•øÎh  cccqqñ—/_fffvrT-ôkW¯^õôôäç猌”““#:܇L&oÙ²uºâܯ_¿nܸÁÃÃcggǾd\EPPÐÊÊ !tõêÕNƒª€þëÕ«Wø.ÞÞÞS§N%:ÜjÙ²eƒ JKK»wï^‡ܼy“F£M:uðàÁlÎÆE,--BÑÑÑU ýTYY™©©i}}½½½ýš5kˆŽè|?Ř˜„‰‰ [cq]]]))©ììììììßÃËÎ@ Ÿ LJJ":EßTXXØ¥ã1 [´hQaaáäÉ“™Y#йµk×=zôÎ;oÞ¼;vlë·ZZZâããBÆÆÆ¥ã¼¼¼ , ¼uë–ššZÇǰ9èÏðÉh€äåå•””ÈÊÊ \XBBBÂÞÞþäÉ“îîîmß}õêUuuµªªª¢¢"A鏯¬Y³œè8ôA£G600øõëשS§‚ƒƒÇŽ;wîܲ²2QQQØ{ˆIø-–ßU-0B@±yóæGIKK———Ãêœôgg纺ºK—.}þü™ñâ¸qãà:&?!ôöíÛß…{-ô þþþgΜ¡P(®®®Dg oúöíÛîÝ»/^üðáÃÖ% ‚»›]1bÄ„Pnnn‡ï½ú¾—/_â;“;wNYY™è8ôA‰‰‰óæÍknnîð]bž¬¬¬  à·oßjjjDDDÚ¼ U `Ÿ€€€®.†˜¡  ÐÉSZ¥¥¥fff ëׯ_±b,ô@o˜9sæîÝ»]]]étzûwá¯æ‘ÉdEEŬ¬¬ÂÂÂQ£FµyªÀ>°6n/ÑÓÓû]ÕÒØØhaaQRRòŸÿüçäÉ“ìÍ@?B"‘öíÛ7a›ªªª6ï4ˆT\jРAYYYø£m@ÕØÍÎήõúK ' ;_qØÙÙùÉ“'C‡ çããcW.ú)CCÃääd“6;éÈÈÈtÒŠD"‰‰‰ñððÐh4qqñÝ»w·ÙL[[»¥¥¥õc5x„NŸ0aÂîÝ»gΜÉx+++KMMñþzvv¶ºº:†a¡øøøÝ»w555IJJ®Y³fûöí¬¸¬1pà@„PYYYû· jìfkk «-±JRRR'UË¥K—Ο?/ êÀjjj/^¼°±±¹qããEiiéÎ[%''«©©avãÆ SSSKKKIIIü­¬¬¬´´4 ÃÞ¿¯¡¡Ñ¦I]]]PPÐüùóãããg̘ÁLššssóðððùóç#„òóó‹‹‹»üuö&)))„Ð?Ú¿ÏÐ7%'';::"„.\¸€¯Ú`QQÑèèè}ûö‘Éÿý%+((ÈLC‰4sæL:^SSÃx1((ÈÈÈHAA¡ÍöF¸888¬_¿þðáÃLÆ+//¯¯¯Ÿ4i‰D"‘HÊÊÊœ¶ã ~¹Ú¿U }Ðׯ_ÍÌÌh4ÚÆmmm‰Ž@¿C&“÷ïßÊÌ¥†•––îØ±cÒ¤IÆ Ã_¤ÓéÁÁÁ–––W¯^ípª/BháÂ…)))LfSTTÔÕÕ6mšO‡£0†­^½Z^^^YYyýúõø‹T*uÊ”):::¡ììl‰äææ¦®®¾`ÁüÈØØØ9sæü±I' ñËE£ÑÚ¿U }Mcc£¹¹ù—/_ôôôNœ8Atú/###|q¹?Î*SWW'“ÉC† IIIIHH`,I÷ðáÃïß¿ZZZá[µ'%%UWWÇd*‰tûömkkëcÇŽ <ØØØ8//¯õ¾¾¾¯_¿þôé>‹?--móæÍ Ïž=³±±ÁWRÀUWW§¤¤ØÙÙùûûã“f|||þؤ“„øåêp]>¨Zèk6lØðìÙ³aÆ…‡‡w¸i*€mð_ÀMMM–••…aX\\Ü»wï***¯Í;WDD„J¥***v8H„*++ëpÿv¼ŒÀµ¾O#$$´gÏžÜÜÜ—/_¶´´èëë·N(//?iÒ$ooo¼JLL$“ÉŽŽŽVVVQQQ­ç»ºº ~ýú5%%¥¨¨èÍ›7†††lÒÉÕÀôÏ?ÑèS.^¼èãã#((Ýùc 6 P(4ŸŸÿ/X°`æÌ™ëÖ­‹'‘Huuu‘‘‘555Œ»§NhÓ0..Žñ ƒŒŒ cG„PYYY›EÛH$’––Vhh¨°°pQQ‘ŠŠ þ:ß“'O’’’|}}OŸ>™™)(((++Ëj ÿÓˆB¡,Y²$ @FFÆÖÖ–ïM: u8¬÷Zè;ž>}ºqãF„O‡›¼Ø ¯0êëë™<ÞËË+)))44!+,,L£Ñ0 Ã0,++«ªª*>>¾õñõõõ/^ Ú³gO›®ÌÌÌqâÄܹsB%%%'Ož,((À»MHH‘‘‘——g4¬©©)//Ÿ9s¦··w^^Þ÷ïߌŒrss“““åäääåå;¬'ìììBBBüýýñýä™iò;øåj_œ!¨Zè3>þlaaÑØØ¸iÓ&kkk¢ãú÷!Þòòr&WRRúûᅵœ~þü´aÃÆM55µ… 2‰ttt¤¤¤ääänß¾ýðáCÆUUÕ &HII1bРA>>>! …’œœü×_‰‹‹ËÈÈœ8q"..®uUQ]]=gÎeeå‰'îÝ»wèСJJJqqqnnn²²²ªªªK–,iŸ\KKKNNNSSSQQÿBþØäwðgžñK׌ÐÐh433³¯_¿Î˜1ãøñãDÇü—ŒŒLvvv‡ê0´™À±gÏüÆI›Û*!ÆCIÎùhó–Й3gΜ9Ó>RXXX'yäääÞ¼yÓæÅ3f¤¦¦¶~_`†ñ)‰DÂb¾Éïà«âv8Æ ÷Zè Ö¯_ÿâÅ EEÅÐÐP˜ çÀ—yýöíÑA¸ ~¹ðK×üt€ë}ùò%))iÀ€ÑÑÑ\‚ÀNøpɧOŸˆÂ5ètzAAB¨Ã½_à^ \ïãÇ¡K—.7Žè,€ÿGUU!”››Kt®ñåË—úúúAƒµyâ U \ ,Ç0lëÖ­‹/&: -¼jÁÿ´ÌÈÉÉAÿ^·ö j€[544ìÝ»!$!!áææFt@Fzýú53³PB(==!4f̘ß…ªnµvíÚììl„¦¦&Ñq4hœœ\uu5 1 _E÷w+NAÕ¸‰D—––?~ü‹/ïjkk·ùÖ'‘H’’’­×®666n¿ÛÞ­¸¸¸¨¨¨žžÞÝ»w۟ߌ¥_Mœ>}: _… €“iii!„˜ßݰŸÃ–†ªôYÉÉÉååå•••eeeS§N]½z5þzVVVZZZzzúû÷ï[_]]}ïÞ=ü㪪ªÄÄÄßu[YYYZZºxñâùóç3š0())eee±ú«aÊË—/7oÞL"‘¶oßNHó¦M›†JJJ":øüùsNNލ¨(Œ¾OXXØÞÞ>33ÿ4((ÈÈÈHAA¡Í~cýõWxx8þqLL þåw ààà°~ýúÇ·y‹B¡¨©©±.~¨©©Í›7ÏÅÅEOOæáÿŸ>xð€è \¯ítuuw ªЧá Ñéôàà`KKK ‹«W¯¶ÞìÔÂÂ"&&¦±±!feeõÇn.\ˆßÝÅG…ÜÜÜÔÕÕ#D ,`ì;g΄P@@•J2eŠŽŽ¾^dë¶=ü2EEEcccÛR4aÂQQÑÜÜ\|Ð üæ·¾¾þô4íÑ£G›7o¶³³C=|øðû÷†–––EEEOžuuuf|jhhøõë×”””¢¢¢7oÞ&&&’ÉdGGG++«¨¨(|J|‡mý±±1jµ‹èÐãÇüø¡¦¦ÖÉà;}ZZZ:xð`¢ãp(|Æ¡‰‰I'ÇÀ½ÐÅÆÆ Óh4 Ã0 ËÊʪªªj½{ª®®.ß—/_~÷pC}}ýÅ‹ƒ‚‚ð-XÇÎÎ.$$ÄßßßÞÞ!ddd”›››œœ,'''//ßz x@?$$$dddÔÒÒ@tU__ŠZºti'‡AÕú     6ðóó㟪©©-\¸°õ //o`` ¯¯o'ÃC:::RRRrrr·oß~øð¡ŠŠJ'gÔÒÒ’““ÓÔÔÄwJSRRŠ‹‹sss“••UUU]²d k¾0×§ÜùùùÁ"¹Љ‰©¬¬œ8q¢¦¦f'‡ÁÍjÀÝ:üÿ¿õmc8™qüܹÿ×Þ½†4ÕÇßY2cÕ´°0fiÍ@XÉ" ‡©T–•dEÐm i­RCzQiÑýF±nt¡žš‘Ev¿ß †™•ºdevÁ¨%e)–-lÏ‹ÁóÄót1Ûvö¯ïç¾8ç~/D¾œíœÿp÷/QQQÿ_ä[ÿV¾<øËß%Ir?(ôÄÄD÷»’¾z.€?MRRRhhhuuõ•+WåÇïlÛ¶M¡P¤¥¥}ÿ0îµàuîoè+ ³Ù,÷,~§¼¼¼¸¸¸}ûö“'Oþþ‘T ¾0cÆ µZ}îÜ9ö$ú÷ƒééé?|Ä’jÀBBBŒF£ËårïÖ·û÷ï¶jÕ*33ó‡S-øÈ‚ :ôÏÞ#XºtiSSÓŒ3ÂÂÂ~x0Õ€téÒ%##ãóçϹ¹¹rÏânß¾]XXغuë… 6çxªßÉËËS«Õ'OžüÖ†ó—Ë•••år¹233µZmsN¡ZðN:-Y²D¡PÌš5ëÓ§Or#§\¿~=444//¯™§P-øTvv¶N§«®®^³fÜ³Èæõë×999 …bõêÕ¦™gQ-ø”J¥Ú½{·$I+V¬¸{÷®ÜãÈ#++ëÕ«W F£±ùgQ-øÚàÁƒM&“Óéœ8qâø9щ'<ضm[w½5ÿDª˜ÍfNWYYéþ äÏñøñc÷®LëÖ­ëÖ­ÛOKµ •JuèСÀÀÀ­[·ž?^îq|äóçÏ&Lhhh7nœÉdúÙÓÙ=¾–ŸŸoµZåžâ7áp8ä@ËÅÄĬ_¿>33süøñÅÅÅÑÑÑrOä].—kêÔ©6›­[·nýõW V Zàk‹EîÀ_Ì™3Çf³Y,–Q£F•••…††Ê=‘­\¹²   ]»v'OžlþsC_¢Zà;F£1..Nî)~Cr åvîÜùøñãk×®%%%]½zµ}ûörOä{öìY¼xq«V­8ЫW¯–-BµÀwÜ_¿|I¥R;v¬oß¾v»=99ùÒ¥K?ÜúX8‡ÎÈÈp¹\{÷î9rd‹×áÛ¸È,$$¤¤¤$""âÆÆ kll”{"O:{öìäÉ“›šš–/_>eÊ”_YŠj@~aaa—/_Öh4%%% uuurOä‹%%%ÅétšL¦æ¿¹ÿ[¨üBdd¤Ýn×éteeeƒ ª©©‘{¢_•›››––ÖÔÔ´lÙ²mÛ¶ýú‚T þ"""¢¼¼\¯×?|ø0&&¦¸¸Xî‰ZÈétN›6mÕªU’$mß¾}Ñ¢EY–jÀ—””Œ1¢¶¶611qóæÍ.—Kî¡~ŽÃá0 ùùùmÛ¶=~üøÌ™3=µ2Õ€Ñh4§OŸÎÉÉq:ÙÙÙ õõõrÕ\.\èÝ»wiiixxxUUUJJЧZð;J¥rÆ G ¶Z­={ö<}ú´ÜCý@}}½Ñh>|øÛ·oSRR***ºtéâÙKP-ø©ÔÔT›Í¦Óéž?>zôèôôô††¹‡ú:³Ù¶oß>•Je6›Oœ8á×åQ-ø¯îÝ»?zôhãÆjµz÷îÝZ­víÚµ?~”{®ݽ{wÀ€999>|0 •••sçÎõÒµ¨üšR©ÌÎήªª3fÌû÷ïçϟߣG;v8Ny«ªªš0aBtttiiiHHÈ®]»¬Vk=¼wEª„‡‡;v¬²²²OŸ>555&“)22rÆ ïÞ½óý0ÅÅÅ)))z½¾°°P’¤¬¬,‡Ã1}út¥Ò»]Aµ …¬V«ÅÇÇËý· åôz}EEÅ‘#GzöìYSS3oÞ¼:dddܼyÓWÿþýÎ;ûõëg0N:8{öl‡Ã±iÓ&µZ탨D"IÒØ±cívû™3g† ÒÔÔ´k×®åä䔕•yüý.û÷ïŸ4iRPPÐÌ™3m6[ÇŽóòòžã§ }*÷þË+Õb±X¼±,ø“y¸ZŒFc\\œg×¹DDDÈ=€y¸Z¦M›æÙÜø6.ÕÄ@µ1P-@ T ÕÄ@µ1P-@ T ÕÄ@µ1P-@ T ÕÄ@µ1P-@ T ÕÄ@µ1P-@ î’$É;À÷q¯ˆáoó²¾®¹¿IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/production-configuration.dia0000755000175000017500000000364710017410244027004 0ustar frankiefrankie‹íÝs›8ÀßóW0îËÝŒ+#$>T7é´×¹»‡Nïæš{öÈF±¹`ðŽë{¸¿ýVà|°ró¡dê Dì"´Úß®X5ï?|Ÿ‡ÆHÒ ŽÎ{™=CD“Ø¢éyïïË_ßz½gïý€¿ƒÓ„Ï ¸"JåÑyo–e‹wƒÁjµBá:åYœ 0X¢T þãaÈÐhл83Œ‡|žqyns–gYŒ—™0">ç½1Ÿ\O“xù½¢Õ¦Ý$ãĸááyïÍUþÕlÄ ¶ä쑽àS1N¿Þ-Ú„/Æšˆ^ˆ¤,v¾ˆÓšdëE¥É9òóA›M«EÓ‹7é›â–6'îeÕÝèN%Ùœ'Ó ªêgÂBžeY·Ïáxcõ*Bõ*õ*‚t´ˆ“,áAVU3ŽãPð¨Ð”%KÑ\O:á!˜Ì¾®àæÒ¯‚,‹ÜÿÓÇt 8}7{މÓ$ð÷OÄ­;¤¬?›¾+z\…ôµ"é7AŒCQw÷A”u&~ÝøòèäÞøþò–ÖPHÛéî}OØÂ>ÞÝO—/Òf¶Ýf‡¤Ù¦ÙàÐS/·{ìƒ)N•à›«ùZ$ñŸî±klxãq<…xü˜d›î}ËxäóÄ7Þ_‚HôîÃ"ÿ¼÷‡¹ý|Ê=iàú*hßY‘å!Û²û˜•{]õ»ŒÇeù tGÓPÜé Žéô±l“¸Câ"Çu(E¦Ci3Í“8ŠF"òó¾ÙÃj#yK{ù-:žÕì–¢å|²(ßIÝ|Ý'Tö ŒrZ™Å·¿1f`ÒzÀ ²ÌÀê÷¿•§‡¯Å›kÉöµ¸jþ¥*N†ºËr¿Šl'×`¸ß d…˜°Ævq[Û%¬O±B»%bvŸšð9¤ ÃñúÔEÌ#n3­"óÑ$N¢jÚM·r9ùª]»¥žL»…ô™¦³lŸxFa&5ÓÎâÕ¨&=9«£å* £YœÿÆQÆÃ½ZJÕÑjÀê³`¢NÉ‚ûþvÌY›Ø6i&>ß+c]†p©Í®¡ÍÓ©­v¥Ì본a¼˜ ˜Ÿ?íÈÂö„:»†¹N­Ò:ÃB˜*3<™ö3Äœ!aÒ£{}ì"Ë¥jS¼æýz ù²,âxJág;ž†Ÿ†ßÑðKErL„ùvüÊÈqµjòÝ­b:ðó¡Óä;1ùh[òaÅäÃ@>@DA> Ÿ2ç;ù°&Ÿ&ß+'×äëš|X“ï‰ÏnK>jö‰¥ö­žë€©,ÑG)¢L1åèkÑ1>¾>_Ühø)x±—Ã<›†_Wðûöù €ï’§×5s:HïˆÚìŽÙ}K¾Ï³(r©Cû9¶‹±âÜŽ¨ã7sˆJ¾Á42?"Í·WÌ·u¼L$ãD‚@Å;ÏÔoõ:«Ö@= ü˜)BC®È,0v[“N&å*Qç"FÀ.$òàçP–ûzr-S7MV]\\ê]çõÕ§/)ÆKŠ[”¶7¯õòθÒÂ`ÐA]·‹lì°¡ À‚A)8'l)¶¹šîÉ ÜgYÐŽ[´Û* Ú B‘®ÓLÌÁvåAí²ö›1Ô.}Y®L äÂä lØtû„ Oi‘Ÿ§tÕ f¢ÒŒÀµu:ð¼Òn8„»ÚYù7£Xñ¬vÃR“Çä¼vM“Á¤C¦K½Ól®ªt²¶¥ÛØt¢ÊæfùQ9¨dã+ùÝÐÇDþˆ'I¼*+¸üIKÉ£PDÓ½²­‚CøtÛÚð1QS¿^Ê¥ƒ¿;ð9•›’ç±[2s%xH(‚€"üôWY¾JX‡kCn¤].ò(L¯³(¨ž®˜ßKXb1,±´ñmLE–òˆ¸Æz.þ j&õ8† ¢¹…ÒZÙX}TS3:^ix¹1¥cš&óþpLƒPLC:ð–y‚'T.C&â4¹È³Lgií¹¹fyüôƒœË,žs'ŒípGG: "z£Ôo”,èš?Èwµ®Ä'6ÂÒLˆ‹ˆÒ˜‡`D¥«"r-{(ë¥'½pøô×_bšW‰Â%<5¾ á _;­Î·øì°Fí³ø,5ï@÷–áÖåÓÒ6ÔÆW·•e2A:QeYóNéÊ2ý*é9W–-’`ΓµiçÑ?Óõd§-šÆNl³•³>d›s¶Ùšmšm¯mÃL$$ŒšnªèæhºŠní+¥ÕÒ ßÓ @gˆnX)ÝšnšnÏcO‰5ç:ÿ²™æÜ)9×z‡†Åú”¨­‘ +Ö(½‚t´X¤TšÇ5ï–FFÝËBÞÛý›?R Žæ+–º\áhÔÇù_ä¹8Ûú“=gÿŒíðX¦oopenacs-5.7.0/packages/acs-core-docs/www/images/context-hierarchy.gif0000644000175000017500000001730507525270556025436 0ustar frankiefrankieGIF89a¤”¢žžžîîîwwwÙÙÙ¾¾¾IIIÿÿÿ!ù,¤”ÿxºÜþ0ÊI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ p8 ƒä Àl:•G#qJ­Z¯ã `0aL. æô9옃vN¯Û;ÈB÷‹&³Ý\pqQ„…GJL\ma~`^orw’“”@H]bk€ƒ4Zz^™^œ‘•¨©ª#|šUy˜}¤±«¸¹º —™¶q¨­˜gn»ÇÈX_ÄÆÉ—Ì¿ÉÔÕ9µ§Ö ØÒÛÝÞäå"Ëh¤ÜæصãìòóÙ£Îô®éðúÿìZ #à@ ú<È0ײQvp…/žÄ‹sŽ*€ñÿ6‚;Š¢1âH%Cž\Yc*YfH)³æŒ ,´ùA#Gž@UØ”€Q1‹*Å0PÀRÐü|JõBT;«~8 @«×~1Ô騳a œ%1€€ÙµZÁÀeëv.Õ/véNÍËshVþ:MÊ#)aÁT±l_×8 S¨[¸æPÉtÓÌ É‚S‘äÈ1Ö–#h•ž?ëÉï‚ÕRxÀ›™×jÛ‘Jƒ8ú·²á·¾TptÌÏ£’­Óå@—.ñˆdàqƒ«bsà˜­¼t¢×ÊñKqà „«=Šæ1{]ûôÆà³ozön8 ÝõÑÿ¼@J[¢aÕVA‰…Å |¸æÀFTçßr\ÍF@ƒË èT[ñå·Ýlj=PV+úE†q|Â@ëÜ×Qb ”ˆMlwØyd˜X[Æ$ˆˆ@fÁ`xÎñ²]6 …!†o‡ãpA:0X”ÕÑ&`W?îß|.êCàné\ÅGAÕ1pŽêˆŒ—•)ä^7pdˆm-9I¥€• Ie –åVðµØeC0zàOX˜ðòY]|é×—>>CÊt é† ðègJò˜$w£`Ê'~Ò¦ ªÛ%Jè\*O~€±Äv:9 º¥‘rSŸ…è¡ ßQœ*—Ÿÿ—q(`~È:[‹üž[][^a-c¡·É §¸ÆcÂyÛºçÂŽ‹eCšŠt÷Sw‹éÑ©YœâG®$ “KÖufzÏ LœN àcЏ 9ħ€(¢Ÿ àpÑEÁ1”«}S'Ôâè0œÌD í>2@’+9G¹ÁI¸/Ó3ÈâÞH'9$WдU]“8-OT˜*ÝA?Çæ4=Ló\Ù›$aõÔ»”LtNß,5×úÔ¼õYÑ +ÐdÔ½²"W±Øg·½ NÉZœÚ‚Œm÷A%Íì•F¶B÷ß¹C”]÷Žô u#N=ýDŽÑCÿ…}3Û’¿H9A‚ŸÔŠ6šÓmyçÖäÜ€AQDÐÜ}ûºè[h:Õ®g®9²Ïε“áÆé¸|ÞLé¼ïû<Ÿ€¢¡æØƒD7¹yËW¥ÅÎû±Mê÷x_}J@®|ö 5ï|™'-‰0ÌÀ¢±õ››þ\Û7¡ûÔ;Ó{³x…øæG¿òâ~•9Dô·‡0ÔÂ6ãÜ >¡>°ïÕ£_ýˆ@YE l (ÊðäiÍ…¡ö`A5`€Ü ;´–ïdókC ÕÀÃú°T¤Ð! ÷„ò™ï4T!Œ¨²D Q‡P\D¡8D6±~ÉÃ^ÿï—B#.ðŠW”Ñ ‰Æ“y1‹ZÜ¢¯cˆ3º1:Îx£Xˆ5Ú‘(\âòÈÇ#Üñ/(ΠIȰc…L¤ ÂâE:ò‚4Î#')þQ†’˜\ÁÛÌp¾Lz²Ëè±fôÉR– ,4¥*”ÊUš•®Œ%\%ËZf€–¶Ì%p©Ë^>€—¾ ¦‘n'LW³˜½T2—©Ìe³™Î&­¢)Í‹QÓ–Ó¼f/³©Í\º©›ÞD$8]ùÍqʲœæ$§8ÓYJt²Ó”î|ç'ã)ÏLÒ³ž[T sˆ >ÎøäÚ,h1Â58‚u`J‰VÔsëkÄ#–ÿF |0¡…#nñPªÀï€ ŒŠøµÏ¡Ý…ôH=v¯})½ˆñ~Ò êA ¶¨iL­Àˆ´+…1wJ ×Ug¨’ø눪 ̉ci S+A8©êCqÜœê>‚­Ž<$«Z¥Bq¬ú¢œX3¬?Êj‚7†¡ÕP ÞŠõVÜ ©¹k]uP³¯ ¯{%AYÎò×ÀÒ`WpyŽacà¬4æ—ä¢ÀcS 2åAh±/YU@I é¤fÁ2HŒ³'8•\Á:•âI ‰Fól`o뇺¼ð gt`D‘­{a ±¨E4{‘QÿhKFWéPwn{-E‡®Ïâ€ÜB­—°H­ "Å´–C³‰@±É=Ä@p£hˆ8BÒ»t&ú^h½fútT„Êæ0´9“ºrÌ pH§‹õÓ,UZˆˆÁ{ð™P Ú =(DI²ð`Üô_§¼D 1Ú0YÑÕô–@µxTQ6ºå©¥,L o†ìKÝ ¿FbHâ°‡=œŸ&È¡8=*m­òƒàÀ*˜½!Bóæâí ?ÚY…-â¿ é¿yÚq8[¹,×#nñŸ‰ÉbáãQ-FÓ’Ò<œt D×Âp´Óö€A:¶P‡Ú³dg6ó˜!7@âÿؘ:õ†ð˜† ‹^´£ ‘$RÚ#0«Y 'pÄ…gdºG?å@S8:èÉybQl Òò±Rz_µË\Íܳj¥fQ£uÐ{Ÿ­­È‹õšWØc8‘êšò Ø~æ¾cG,O¹nØNèlVð¹(x ó?=æâØZ${Û±«}\°ýno°£6¹Q øp»˜s\ìÞ­kœáÛåPœî7îuŸr ñûÞÒŒ:¾ë!Ñß& ðBÝÔðí›ßEøH(Jb0|¹`Á No‰³‘â&U‡ªyTbl<‹¿ðVhÒ“Ná£$œ¨ Oxð”ßdåmùFgí‰-Pÿ,âm.„íqoŒ?7è#àq<6O„ bÐ…>t¢SA_ÜgF-i†„J]‡^÷á ­Hõª[6Ìz+v¯?ÐíS¬b ±Xdz§"í7¼¢ÜÍ#w–ñŒ(´;5ºøF•I¥Œ‚cÿ>jD­z£ã›Îx È G|¬<þÊÐqÍ® øöüZø‡]ÑÃe“dè¼éå1=2Àzõ±öÅ%aÏ—ÓÒÞ.¶¿=\r¯{–¾÷cá=ð½rÏáÿõƯJñ“O•å3)Î~Q¢/} P¿ú6¹>öe¢ýí¯¤ûÞ XÃ?ýГŸ%ã??OÒ¯þš°¿ý+ù2üÙZèùËDþöÿýó/:!ó$ö€ˆ(þW€x€h€#·€Õ@€xU ¹ðt,ävnæumÀl5GˆásIç@Bäwû¤1m7BDjh§Q…c EAå=*¸‚)q°pq1@Tƒ6èààfOE%§ª·}èSwÐ g@V?X4Ò@Jw×SÕq„´‡UNèÒ`~˜m&A_…|ÿ×V\x \%†óÇeX j¸€Ñ•8MQ€wb…V`4tXmˆÅR¸I±2§ôfö—‡,~¤+n0hˆwÝ„á!á’8"’V4°ñh Á“ø^¶Â÷|G¦ÎÿAò8…gñ±:0=Æ0Me2 {´]zcЫӀº¡~„ø㵊³ae‹Ó±‹ p&œreXRŒîö#9¦eâ^C¦~(¢b-ܲu‹?O¹ Ê('Ç1AZö/ÅÕ€Èr~_Ò_’*ëÑ\†%–²Ní†%yBL†9Àø_nD ¸+ XyÕX4â¨X&'õ("÷²±Õ+ÇQè²æ‰Ø`9\¡ƒÆ×‹öc!Ò_Û‡±Ø rñ/2"'Ð’&΀ÿ5»â$µ.ä7%° r / ÒÂñ:ÑhêrVø2-ƒˆÿ²0¶ C+EÿùÆsØŠzX1ÃCÑÕjá‡\4pt>F/‘kä7Xñ–¿¦~F3È V›ƒí÷†˜mÙoÛçmés»ÓØ×VYè Ùö‚¦#€íö…ÞÐnòv8hoø –T;2—xzIÁãSw¨\¹ã8™ŒHq$hu€ƒÇCDÉó„˜Ç=ÃÐ ŒÉÑ q'Gs•éy8·?1§•7 :'s¢‰r¤ FçD3(QD—ðt¡ÐuRG‚‰g?»YXçáÀuðu}g‚‹PPÑ) ¶ÐDTQËIŠ=u‹cÄBI÷Cä A¸©1fœhÔxð£vk7?¶0EQ„ Ó‰C.ÿä.šÉžI„w*Äb„xú³WäEÙfkÈŸÀuYBq0VstCgx(dI¿Ç ¤h‰Ø)d`“·I˜2C ¤ züsjízVAB˜!HMñší7‡Èq;Ø!I¢˜1ѱ 'Ê +‰&* &š£]'8:¹1ú£û7¯a­‡£¥ûW=ʤí¤ÑrkØz>*%K‰¥' mf†kX31„Z*¦zFܲ‡(ölnŤёš °Vî8·´¦ ÚW%€_0§á¤ìy_Ú z¢×¶œsxø'j‹ºì!£gç§F¡¢å§xô¨x§*ÿà‘@•ÈF¦¨)ШŽå©xªˆ¨,@¨¦U©Š‚ªù©, §d†§õ 'ü§©ìVf%`ª„â-í'ª.`¬¦« ¬çg^.0©"À¬ÇŠ©‹%«00Š& ¨Œ­Ò§«0@ª`­Z‚¬É'¬,Àª)à­š®½§¬2@«$`®»f\º'­3À«íJ¬/p¥W«㯣j«©5{ž§W6`¯…j…òZyê:RUš ;qÈx Iœº8Y kuúzäÊ#{¯[jp™ìH;ëo/‹ô:ªCŠ1ëjËüʲ˜³®–±;à®™U³+€[Dz;P±"À­vÿe¨&f´?@­Óº³µy³uå³;À´2 µM[§Á†°>P² F´Ó*°h´?°²5Àµ9p©{…´?0³Dµ:²SµD@·3À¶|…«)…µiÕ²«6±;`·•³S ´( ·më·”dCä–Œ ¯E@¸ž`¹;€¶…´š)Š$”*á¶VÀ·5À¸}‹®vš;G—GPR¤V b›p˜Kr”ËœyžÅ¶ŸZ¡o¢<«é0azj»¦›µø ‚aœ›6„#pŒ?d›Ç+R š{S99¼)ƒ¾0„u¾j¥÷€ºy[½/p½Èëà`qÀûU¨|iW/ÿ­ ´™[»i[â+©T˜¨ôp'¬^f¶'[ºç[À9‰})†´NëÙ«Æ8cE‡ŠÁn㸅+l=@ºÆ+g‹×´z+àÕdIÉvs”v%/G ÅC"H›E‹¸< º“Â= ˆ7èºÖٙÑ;ÈÚ0—ZsC¾pÚª^kÁ·+\Ù˜ükQH,?ÉùE&è FØ•á#r‘s_Lf \ºWœ Š»¶®j¥ñ#ÆxP„O|I8 (¥oÒ»Z>¼Ã{œ ì›Zx54î¸:sð°ÐÂBàÑ¥z²ç"´‘cÜ5-Õ¡dòÂg#­Ñ€,ø;·>Ú^äGÞl/|Ð# ‚^}¾2/,"@<"¦Í-J`¸ÿ"9ÆÔ )M†$ÖǾXÈÇ~4퉇ÁH¢ÊÔL=ý4Å`CAÝYT]·`ûm _]E.9öö•7H‚$9! Ìb1í‘•£gaêe”¡oÁÐ}fI < 3bà‘h i<&“Ù⥥Ö?0¼l½Ü‡fRù€k=1Ú&¹ëÝŠ¥ò!nö!iö#wRXÆHà! ‚ûÎV¥¿UÀ"ñ0ÞÑ}4^ 2ºø@Q§ ·€è^A^ÙM.þøŠI†a2îßf½%Þ10àÿ} v8ËÆtÝàÞ!í¡Er-»x& °î«bJþâQžáä@°‘ñ°ã­ýበڪ½fÙ7Ó]©7’nRYr£v‘ͤ`K>ÝGÕ ì²±è'°‘ÒŽã .ìqÏj 5Û6gzîÔKæbÿ "Ÿ~‘rÒÊg2ªmݤxæ6~^àbpNY>éóp]2ÊUé&R$Ü+é] R3½^%Hq#Àî\Ù¢¿(Ä]ÃËΛÓlÝÒÆ A¾,¸:¹Þ;Å{Œü€.ß¾ö²/j^ÏëbÛPÑ|Œ¾æ‰þÈÆ-ôŒrSls^ñ¶î§ÆÛŽDR>í¡•Ÿ¾U=žãùÍ}Ûã™>€3eÕÇåpipÝVlܧàÚW kZ³KrÃÁè&n¼›o-è>xK/Dó™z ÛµYÞc3Ë<ž5‘oF¨Úò![pš¥’5tt,‡‚¸I>4×¢gœaÿÉtLîÒ‘níVñWyƒ·o*ϱI äiÃ(œº‰±N£v–Lžê60ë÷~E8Ö†Ìó˜©ò{mù³vôYŸd—œ$ZÏ.År>n±Ûò.6x€/)ºtÞËFt›õNô…ÿÍ©wÈ©2Ft÷9iáû÷tÉÃ#Œé±3œáã 97Äk vh‚$¯œc ù’?K}r¹»„aë<½öò˜s¥é•ÔY_7ú/Mhéä.ìnÚ.ê_ÿIö]o†lâòëfxK€ÐŒœ`S†Æ ™ s¢‘ŸÞèw?½/£×H0»ÄM[Sƒê°€lc4Zcж«ef¸‚`¸Æ%±.<ªÚéÔÀª4×è“üw™¬™`ix@žúæ ÎÏ…o ¢ ÿ¡„&˜E ‰Ä?²¢©¢ùP€ì«¸¼h= Z¢ v›½L0½8@#bªÖ'&¦‹ŒÙ6·Aˆ$WÖöLðfxT©`GÊ19&|ŒãèÁU`ÈS`%% Å d25˜Â>xF<ª@”pbs°ÅEæêw–ùVŸv¿<2Êºà‘—1-ï-:ãb@¦RRÂì“ «£X|ÆEºé„ÇD& K`Càu4ÕK‘×€ È‚šôšÑ2SÖQÀo—QF¥Ê7|Ó/ö:ç9Š9¥î??ˆ\âÄ ' (’ÒŒ@Øn‡»5Y1§Ê’™ÿÎ^Å•U+ðŸyþ£žFƒŸ¢ƒ {ösvf«šK@ÐNa ™éÄûúB-pA ´Ã§ùR~æ ’Úܧ}lxÆ—ˆE‘(XZRêN„–TöêI¦¥ÒH˜á™¸‹> ¢ÎÚÀ|Ù1et àD ‡˜Ó‰íA©Cý¸Ú-`ÙÉO÷dA²`‰·~ñW¼`«l ªÿÕÓí€k :öUô-@ ªQËJÔ4¶d«R¡MÍh‘§OY—º\¡2¶"ÄÚézœ…ÙÌ΢”|L;){¼2M[ë!7{’Ks±Éí¶•\ó2^M¥"œ•ÚÿV Z€D` ›AìÉQiӍЛÙs%–1è–\ ©eB¶·ýÈh‘K›l0B¡º ±”(,@—*ßEÁ0k5RQ]i¦(Ö©+òã±à]:´Q*Œ 8 òØon_«¼°¢4¾w‚ÙnQ—L€ï) Ýô÷@ÿ•I_¿b —Ã&†AÜü2.•N˜ë€p.üâFa¸î†I‘žÌ‰ WˆÂ€Õd^¨|%‚Ñá…|# ÖU¤kã_)'l©2[¬‡i=Pak¦‘Je©,d#=ñq‰¥\À¨Y¸îú"KÈVÜb™aŽ ­Œ4 Š€ÁmØ­p«Yج0zSvg; =9€ržs¡ý”Oaá¾±mh3eH—•ä]:»öàú¦¬Ö´©!Þôª)ÄkÄŒÍ!ÝSË:I¾…;%Žnô‚ÌO>ó¬ 3ŒxdÇ4éqUÚ ìd/¡Îb.s[~¬ìhÓb-V†2´¥mÚ¨9ÛÜ~t;openacs-5.7.0/packages/acs-core-docs/www/images/rp-flow.gif0000644000175000017500000000474107253523116023353 0ustar frankiefrankieGIF87a…ˆ€ÿÿÿ,…ˆþŒ©Ëí£œ´Ú‹³Þ¼û†âH–扦ª´-¹É»..-5rë—ïî=Oh»eœ"T§ÔªõJ"™3!®ªÅÆX\ñ¦ü Ðö¯á?ÜæºýŽ}×qÜ~½òwf"7Cˆ‚Ö7QFW‘8×H™GYiy)É—)¹gsä'ƒèUdÔ£ *ØDFöâiêÄyJãÚ ;£Dk«J»{+ë1{ÄÛ…*ü |ŠÙìü¬â÷)Xë¸y¢L-ö "5‹ÊZÍ“f*"WÌ|ü®…«F?-zœ¹^-^- ÀIî©2'¯@ ®H¥’‡Î›}ÿ*jiè.]1þN =QŧÄ-ó40q§èc«i | 3f¶üHnZ§P9„žTÞì¹°¾ž}òd¹ï›ÄU-oò¸ˆrdÆ¥Kz!%EŽæÕ{%ezýjé¹|ÈX‰#;B,Æ`Pµ²û" #G ¥èÅÅ”ٱζýé¶ \³}÷“;·ØÅŒçp 92¥¼’+[fLù²æÍ‹2sþ z²çФ7ƒ,:µêÕ¬[»~ ;¶ìÙ´kã)…;·îݼ{ûþ <¸ðáÄ‹?Ž<¹òåÌ›÷¶ ]ÌhhÓëT7s]zôí­³cò~¼ñ`¸›OM~2æõ‹ÓŸ_Éýmö`åï°??öÏøþÑÿÚŸ~fÁß^˜‚.Mí(“‚ NX‚„ãA“…RÈa†Ö‡!LvH¢IâK#–È¢#Äób[L·";)Tc‹:ÎcW0‚Õ07”cG;y@§ydƒ^¡èÕ#ˆN‰d•Ú½è,ßøEÒTùP#•(Šie™SµM;]mÔOeÃ#™if$äÕF\¥³ÔQnºd”‚Žiçœh˜µ9—]\Ù´Œ7€ÂAg@ˆ Y¨¡q*ß"Žp³ `äÀƒJ\h%z`¥Ôe:'KbÃTZ>2Id”„Þš*«*öJ[þœ•1k­dK0!ñ þÒ¥¶>&§‡ÍêêŒVפ&?’ ©ƒÒ©DÑĈŠJªúŒ²±Bk©AzÂyW£AŧJ;Á‰Žš³š+X¸Ïîº/º4Ö9ÀlÖ?¯¯Sï")”˜Å2+U3»a¿µú»ê£¦"¬-²Zvlj¨ÂpÄíZÆÊè\ÊÉIL¯U,sJéäF‹1ƒœJqÌíÕuo²l6Y$.Z,¾5(ž0ˆ3?ãD-/ºð¤í/ÆèŒ«¦G÷$Î9Ða´‰XJ¶´ºìIT¼·Ä1s3aoÍÝÛ²öÂÍ£HÙ­TDE"÷²Zà ø¦š¤6Þ5ÄhÇ[¡úwã?Nëe'=þ4²b”†°^Ç›µ³9Óc;.bÛ CÛ÷Ä]õLц'šŒòg;~mÑ_UŒ¢ÛFW»ŽQWe„ÁH?¦qý뢠¯j9KæM<&w6Tí±f¤ãõìx(G±$ƒ8ySÉÄÉq„f¬«˜!©ˆH!uXM¡ÂX?Šr~•Äá%1É™#ZËM>‚Útè6>¥j[£f¤SÚ© ÇÔp‰E>0‰^ô ½¦Ò§¨ºD/«’14Þn~ˆáöfÊf2•åÊá3鲨$³) K¤6·išr B†‘Ê^³Aï|óœb\ó0ÏQÒóHùZ¥ˆ£}‘›Cv°Vu«a™dÍ’L*m>5¬«¤gESJ6›ö<ê¿HÊR-ivµ¬5^åC-½2Ls3á™±š¸Ç :PX©åvFëØ¶>•°Œ«V'aþ©r¶e‡ã™Ý¦µ<òMƒœ ÷–ù-EB¸Ô¬ìp½»´m%·pð«U¾´=¸Ì6oFémÉ^h°kl©M‚xÅû¸Ú(l®›¦Õâ,‘¸„PBõ²äµ®r9§kÄÏ{sŠš(0/][Äú–bHVN/v»ŠÊ'M?N÷”’¯ŒÝkóNœá©¶rº…mva¶ÔÒ‚{¦Š+\A÷…´ ®Š&W û¦#®•ª:¥Þyy3—6IþoŸˆ(Ëé(LF]P|Òæ ¹¦5 ,ù;1¥‡o±•T¯ö{Ÿ{Böj@üï—`ZÀe v¤Ñ¨šÃÒ<á7—Bƒg„×Lþ\0òÍò«°H §dbŽ® I 6Yi5E'HÍ Õ x0› ÷“Df,£C“gŲëXÖ¡´ùdqLÇ»-Õ$2³çOÏ2RFíwI,ë­JÎԥsí˜X×úÇ>0°åÊëý4ëÎøübgm§i¼@Ö”s£yí-C›Ö݋ᢗ ~pñ›™–-kÅ>8ÿÙl. ""’}%~c<®t»±T”.[’Ø‚¶øÈÊìbšf/grÌ[>sɃÖ\¥7§¹Èe¾s­®.Ø ÇBƒ.ôl³ÜçK×9ÒyZî¨K}êTdÑŸn(y_ýBî>5Ö¥Zò©Ú@ÿziîòºRvífuÏžöj·4ÂÞzyº>w²ÿçzgzÞéþöïØ@GMÝñ®ì½žèºÎ¹à¿x¹Kfìl¿xäK›NÈ}ð—?-æ›þxÅwô}‡»ãÿ=úÌ«žôHÕ|ê[¿ú¸—]¸¯w=ìYïyÙ×þô•¿5í%¿{κô¡Ç}ð| ;openacs-5.7.0/packages/acs-core-docs/www/images/i18n-1.png0000644000175000017500000015320310027550272022713 0ustar frankiefrankie‰PNG  IHDRÈÎËö·a pHYs × °h”ftIMEÔ ¹_E IDATxÚìi@S×Ö÷÷! B@@ € â¯"zDA®RA¥´âðˆE«W+¨ˆ"T¢ "NˆW[G,T[ÇVq¸µhµ(8aµ€„¡ÂB†÷C Æ$çpÀ0º~ŸÌ>묽Ö¯c›‚!„JJJB!SSS„Oii)€vÀØØD »£4Ö5@c 4Ö I¨ Еټy³ÍÚرº=aaaíçðNOP,Èï×/°cæêÄ|;2Ínªm§Hô!IuîãÓ^>6`ÇèlH ‚Ÿ~Þ™%Cb7R©´#ûÅé45{‹i~ ÚvŠD]*Gh¬hG¢# ’^ö%0èÜ®HS³·˜æG¨mW z&†eŸKœ1Á®“n5Ì%êø=Å«3.úŒ² ÒX¶c¦ÿø²R>ž}z›“½K›aíèùíÃ*M–()`òòý¿;)ºyx¦“½.ƒÆÔëã6;ˆE}÷”]‰lÆ1·àvQ­|°ÿ dο- u©4¦ù€­8gUÁÎÿÙi®­E`)ÿ•7†a×oq¶·dÐö.G2ÿù)a­ã@3naï––W­d¯(—ª†j”YbÍ(Ý›‘î`kF§ÒLlF­Kº­è¿øÎ™E^NF½˜4ÇqúÒUB¼4]9ÌK儨.‡¦¥•Îo@ Ê/0ô'ÊŒ?Ü ]µ%(ˆç¤F,ei©?£"’¢òF ‡ª|uðœÈ'ÿþlÿþ”‡Ù7OÅmÍÜ}{ëÿÙÉ.}»>7é…Kƒ—` ?¦#)BdþÆÙ{6JiÒõ';6|^üzò}Æl;Nÿ ½Ç?ñrSªL’ŒYš2è0m „¶XäLó w_ï‘n°ðU¬¥hÕÖj›õ×ÈÊ’y$¥Ò–Ã6Wf½DÊÐÂÚ¼(šiTìX ù£ Š{Õ2HîX¿y°jмÞosÖ!„t©®@$opå–KÍtÍon ¯äç•@d¥-ÝþňbÏ» —ã9ñëÃû€·ÌŒ­É—}Ø}~-Ø6Ì@ŠÆš,¦»HXŠª.L¾²o^Úô-[»«j@£dV û1(ª—äÿÀK!Ä¢hUˆ$tLùÞåæºœkÜo7OàÿiéZVU”€÷ÈÕ¦yÑÝ2ÕÍøÎóÝÏÿ;þÑ6‡Åô¾yɓ˞-Ó”AûiKPxd´­ÌÛ2ÄoP< ~›ò" ¹ŠT£U[«mÓŸ`AÛæ™à1|ûxíì^oŸ=†-îXãÝèoÊyŸô »U‹ YàË@wBõsœúåÞÛZ¡¤±îñ³¦8ÓôWÜ ;.e %â²W·¯ð”Û‡%øìp÷OZ"’ó\]á5T6nE§ Œºúô]úQÏE{3ˆDî÷ßê½î!·B*rŸÜŽ^þîRxì§ î¾—²¸¢†‚G7×ùŽ’Û¸~yüÊ7Õ‰°æÞ…“ºV¾²ñ[Áñ«v¹(f„gÙZ6ŒìíV^/Õó\?0ÓAÕ/A„Ðl#ÖšsE*ëºî®)ó.gˆ$¢‚¬Ëó§lŸ»u‹Á¨¦‰:üû ƒ"„úûÍÏ ûÑz‘“ ÚO[‚Â#£­^¿õ&Ï·l}õ¯…ŸÍT£U[«mÓŸ`A?pee»˜QZÝ Õ?ý_ŠÏ¿müai‹"¨mÐ[T/G~æ=šM×q^°•5>ཷv {Û/bÉ3fÇüJàÄjVBFÌ蘅.L:{œO¨Ä1L‹Ú´­h³ %m}¸·‹¡çº$^ߥi÷4ÐÕìlŒÿ'¶‘Mxªàê½í!±°8$sJ [1µ–m`ùÕËCÆÛ²ØFÖÛ/:‡žSµÁK!{~ǽ5® *UßÄBqÜÒëà•M#">wdÑÞáCÃ/ð´$ŽDmš!£ÑÁR1m½-!Ä6 ´¥Q¦ùXjÊ ]µ%(<2Ú"Œa˧ù‡K¤¶VÛ ?ñ‚~ÈÊ6?5̬Óߌêk¨Í4œ¹êÈÜ“Ù_5hYBðn´ž{ìl€QдáL&Çý«ŽGl«@#ÀQ ó!> BæË[< ÒY4Ö>2²;ÉÏiíy?|(N¸ìkݳ—¾SÒl×I?¼ð>7Ö™“SæmÈü¨*¡}ßçà«%€Æ€Æº›¾•œº$6"dŠ£­¤"ÿàOÞ—éÛ'š¶ÖI`ÿa9Ï-蔞½ô’f»Nú…Wÿæ”ñˆ[ÕÅ>¶J€Æh¬k5$?–}4æøÍ—ýGø¯Ýµh,1ôp$ÉŽÀ9ö{À`Pk ±€®ÒXt0ðáE€Æ ±h¬€Æ4 $º2›7oÖ @û;Ö@·‡ÌW3¶ Ã:=A± ¿_¿ÀŽ™«óíÈ4»©¶Ñv…Bí"hVŠ÷K°c t6¤AO?ïÌ’!±‰ß¹;òû/”¦ÓÔì-¦ù1hÛ%ê˜*€Æ€Ž :¢ ée_ƒÎmP45{‹i~„Úv‰òÀQ g‚aXö¹Äìz1éVÃ\¢ŽßS¼z1ã¢Ï( *e;fú/+åãÙ§·9Ù[±´ÖŽžß8¬Òd‰’&/ßÿ±“¢›‡g:Ùë2hL½>n³ƒXÔwOÙ•øÀÁf³q nÕÊøBæüÛÒP—Jcš±ñ÷׊sVìüߘæÚZ–òß5cvíðg{Kaaïr$óŸŸÖ:4cÐèöniyÕJöŠr©j¨6A™%֌ҽÉá¶ft*ÍÄfÔº¤ÛŠþ‹ïœYäådÔ‹Icq§/}P%ÄKӕüT.@‰êrhZZéü„ üC¢ÌøÃ ÚU[‚Â#Öö cC¼¦Â¨å%ië ª•HÕF‹*¹ý·“.ƒÆÒïãâ½TÑ9Þ*¨­p‚b ™2^a,ºjá=ű‘Ñ™@ ¼ç—@X2‹HàdÌ@c Ó:þÀ]ŸÆ«ªýólì«8'rå—ÂânŸÌl¨}½o!káäµ²Áâ«!N¡'nóëøW–œßñ^S-©ßµÔÍ=‘¸Ì‰À ?gß0ï36~Ï«TfGú9Ö‹›z£üT¿Å—uR3 ¸×w'ÏÚ›%_=ÆU:uí£b~õ[î™]!ü#©ŠóÞX‘°jçD2–2"® ¢Rþ¨©ã§¬²\ä`ó‡Vܹ̚ºÊSÁ½Om•Âj”íàJ›Q´çþ¼tjÔÓ¨Ô»5 u÷Ó¢žE{üç¼t'ZõQ§S¿Ü{[+”4Ö=¾qbÖÔ£gš>žïnÀØq)[(—½z¸}…§Ü>,Ág‡»úÓ‘D˜÷àê ¯¡²q+:aÔÕ§ïÒz.Ú›Aì$r¿ÿVïu¹R±ûävôòw—Âc?Mp÷½”Åm5<º¹Îw”lÜÆõËãWH„5÷.œÔµò•ß Ž_µËE1#<ËÖ²ado¿è´òz‘¨žÿàú™€™ª6x "„f±Öœ{,RY‡ÐýswM™w9«@$d]ž?eûÜý«[ F5M„ÐðÐáßoxè<!Ôßo~fØÖ‹œ4hÐ~Úmõú­7y¾eë«(ül¦mxܬH¯U÷óÊÄâ†ü¬þndVAm…“)bð ›¼*"_¨-êL Þ‹Þ?¯Ò6-Æ 4ÖÐîð!¸ëvòÚ¡æúÚ:F³ÃO/LÉ^io ONOÊó`i3Gx¬h!·ïçsäçÐaÞ£Ùtç[YãÞ{O¥°·ýò'–4üÒOKâHÔ¦‰2,ÓÖÛrBlÓ@[e𥦠ÚU[‚Â#£-Âh¶|š8±DÖs 0 š6œÉä¸Ãñˆ%³ j+œL1ƒWØÄàUùBmQg)ð–€@X’‹Hì¡Å˜èîÀQ ó!> BæË[< ÒY4Ö>2²;ÉÏiíy?|(N¸ìkݳ—¾SÒl×I?¼ð>7Ö™“SæmÈü¨*¡ãu†˜€Æøèëîø6pê’Øˆ)޶’Šüƒk0cã÷¼*AEav¤Ÿc½¸©7ÊOõ[|Y'5³€{}gqòü ½Y²ñÕc\¥S×>*æW¿åžÙÂ?’ª8ï «vN$c)#⺠*åš:~Ê*ËE–1hÅˬ©«<Ü{ñÔØV)¬6AÙ®´E{îÏK§F=J½[ÓPw?-êY´ÇÎsåW½¢ÓÝ‚â^ðªjKÿ ýÜÃm/^š!F‡ž–#„ʲ¶H(ØÎ?JBo³“ í¿Ö”A»jKPxÄÚ†.´Iú®É8÷è!‹i»t´0µÑâÕ±ÎÓ6¥ûFž(©j ëZ\¯¶•GųD;¯D¯MÇyU‚Š¢§;ÜH>’=¤9A•””È^˜šš˜–––‚^@{`llŒwIvºZõŒµ¬«–J¥²3Ö CÕ@±í«.L0uø³†÷½’™T\EÑ6–ˆ¡`‹^½®lÈQõ#ñã×}3võÖñ&LÕ ÄØõ.N~ºg¬‰j$æº_<+›¨GG‰¸LCaÍ„P:5µ¤f‚!CÕ³¸k;h[nþ~ÙK7i–•ü%¥ÆÁK°…ÓÉuyO"¥4éú“N¿>{Ÿ1ÛŽÓ?HïñO¼Ü”*“yÆ,Mt˜¶Š…GB[,r¦ù†»¯_ßÙ`áKÅp%«%b?`½È–G½DÊÐÂÚ¬ @·oTìX ù£ ª]5Éë7V š×ûmÎ:„.•ˆ8TLÉr©™®ù­Âô•ü¼ˆ¬´¥Û¿Qìybׂá²q<'~}Øcð–™±U#ù²»Ï¯Û†HÑX“Å4p KBÕ…‰ÃWöÍK›Þ¢ekwU h”Ìja?Eõ’üx "„X­ ‘„Ž)ß»Ü\—sûÍ঳4ü¿"-]˪Šá¹Ú4/º[¦ºßy¾ûùÇ?Úæ°˜Þ7/yrÙ³eš2h?m Œ¶•y[†ø ŠGÁoS^4W‘j´xµÔªC>dÖ oÇ/SöÈû¼ OØ­R Ç;Ö@wBõsœúåÞÛZ¡¤±îñ³¦8Óô Ü ;.e %â²W·¯ð”Û‡%øìp÷OZ"’ó\]á5T6nE§ Œºúô]úQÏE{3ˆDî÷ßê½î!·B*rŸÜŽ^þîRxì§ î¾—²¸¢†‚G7×ùŽ’Û¸~yüÊ7Õ‰°æÞ…“ºV¾²ñ[Áñ«v¹(f„gÙZ6ŒìíV^/Õó\?0ÓAÕ/A„Ðl#ÖšsE*ëºî®)ó.gˆ$¢‚¬Ëó§lŸ»u‹Á¨¦‰:üû ƒ"„úûÍÏ ûÑz‘“ ÚO[‚Â#£­^¿õ&Ï·l}õ¯…ŸÍT£Å«¥VÑÚõRü¸0^ áq³"½VÝÏ+‹ò³nDø»µJh¬ ÝàCp×íäµCÍõµuŒf‡Ÿ^˜’½ÒÞ@6žœž”æÁÒfŽìñ IDATðXÑ86BnßÏçÈÏ¡¼G³é:Î ¶²Æ¼×UPØÛ~ùKž1;æW'V³2bFÇ,taÒÙã|B%ŽaZÔ¦-p›)iëìýX =×%ñú.M»§®fgcü?áè°lÂSWïmG‰…Å!™S-ØŠ1¨µl˯^ò0ÞÆÅ6²Ø~Ñ9ôœª ^‚¡Øó;î­qeP©ú&Šã–^¯lñ¹#‹Æpð~逧%q$jÓD–Šiëm9!¶i -2ÍÇRSíª-Aá‘Ña´[>Í?œX"¼ZjmX¯S°ž{ìl€QдáL&Çý«ŽGl«”èîÀQ ó!> BæË[< ÒY4Ö>2²;ÉÏiíy?|(N¸ìkݳ—¾SÒl×I?¼ð>7Ö™“SæmÈìa•Ð¥¾Ãkàcl¬»ã»øÀ©Kb#B¦8ÚJ*ò®ñä}™¾}¢ikö–óÜ‚NéÙKß)i¶ë¤XxõoN¸U]| çU4Ö@c 5u«I8~,ûhÌñ›/ úð_»;jÑ8Xâè¿Ô+¼ì¨Ñœc¿ e ±€®ÒXt0ðáE€Æ ±h¬€Æ4 $º2›7oÖ @û;Ö@·‡ÌW3¶ Ã:=A± ¿_¿ÀŽ™«óíÈ4»©¶m§,nWx‚: رºÒ Ç§ŸwfÉØƒÄ½KG~õ†Òtšš½Å4?mIF _¶5m!:¢ ée_ƒÎí±45{‹i~„ÚâE ]5@׎‚= òÏ%Θ`׋I·æuüžâÕ‹}FYPi,Û1Ó|Y)Ï>½ÍÉÞŠ¥Í°vôüöÀa•&K”0yùþ߈Ý<<ÓÉ^—Acêõq›Ä¢¾{Ê®Ä6ã˜[p»¨V>ØÀ2çß–†ºTÓ|Àˆ¿¿Vœ³ª`çÿÆì4×Ö"°”ÿ¶ðk‡·8Û[2h {—#™ÿü”°Öq ƒF·°wKË«V²W”KUCµ Ê,±f”îÍHw°5£Si&6£Ö%ÝVô_|çÌ"/'£^L‹ã8}éƒ*!^𮿥rBHT—CÓÒJç7 „åúeÆnЮÚ±¶_ëâ5F-/I[gP­Dª6ZŨ„-¹ý·“.ƒÆÒïãâ½T1µ¥xlÑÈ  ÞÝž9zé ¼G ¯þñ&%© 4ÖÐ9­3±AàÜeñi¼ªÚ?ÏÆ¾ŠóXp"W~),îFðÉ̆Ú×û²N^+,¾âšqâ6¿Ž%aYÁùï5Õ’ú]K}Ñ܉˜œðsö ó>0cã÷¼*AEav¤Ÿc½¸©7ÊOõ[|Y'5³€{}gqòü ½Y²ñÕc\¥S×>*æW¿åžÙÂ?’ª8ï «vN$c)#⺠*åš:~Ê*ËE–1hÅˬ©«<Ü{ñÔØV)¬6AÙ^©´E{îÏK§F=J½[ÓPw?-êY´ÇÎsåW½¢ÓÝ‚â^ðªjKÿ ýÜÃm/^š!F‡ž–#„ʲ¶H(ØÎ?JBo³“ í¿Ö”A»jKPxÄÚ†.´Iú®É8÷è!‹i»t´0µÑ*‚'lųD;¯D¯MÇyU‚Š¢§;Üä·à•âü¤[¯Ã]÷g–!„ªóS=6”ßÚ?·UåA0)Ieºws‚*))‘½055%0---½€öÀØØï’ìtµêkYW-•Jeg¬ †ªbÛW]˜`êðg ï{%3©¸Š¢m, BÁ½z]+Ø2£êG*âǯûfìê­ãM˜ªA*:‰±ë]œütÏXÕHÍu¿xV6QŽ7p™†š'¡>tjjIÍC†ªgq×vжÜüý²—x–ò)³–4–RVq}³«Bmöpqc9RwBW­µ "ü3Öæº¦· 7ØèËÆ+ÿ޶pù§ªhê-¢út½qbá[µi]óœtxÍËSÎW<ûîœ>ôÙ™¥…é^×?³Žšs5ݧ¿F :L[ÅÂkQÛÚö™9¾ªäÆ"„B-õX× 67‹©-Þz) =Äw$'Áј|)"„*3ÆÙ,^3)iƦíYW†³i->¿Š)LJò‘€Æ:¢±V|‡FÍ[§$k©¸ŠJ7‹ªB¢ú—+æ­|\Âãñx¯K˪ë…2Kòw}£!UKɸ¡$råÑ€ÝkiZ Œz'&têã¡¢¥<ÂIÇ% B(çÔF¯åG,'83r”³Ï,§¾r›Ü“Sƒ(û.Ínêñ,ñz¼—dk¼ ÜêÑ(ùõ"*Ö¬y%•a%nä«›QŠaZò¥4ø×{=[]¼gGgOÞc'k¿ŠòßüMÙ³JýLX1è0m „¶ÒI½öUØ¢³¯**~oÖR9Zü¥|'¬±6õi­Ð¨5¥(ãÍýø~¢ö=Ê]0PïÁÄK`Rez pèV?6Ÿëm퇷¤!Fiê¨v»Oä¾)6îà/¿e–”¿;`*ACjŽ—„ømìÕx)ñü{¿¶ÆsR#–²´ÔŸQIQy£D~ˆBÞÊ žùäåÏ1V…Ù7WϱáØù-ß®ÏMše%I`©qðláÇtDr]Þ“H)Mºþddž“ůÏÞg̶ãôÒ{ü/7¥Êdž1KS¦­bá‘Ћœi¾áîë×w6XøÆR1\‰È[/‘2ZYŠMï 4†VÏ+¶¡<&%£ @·oTìX ù£ ª]5Éë7V š×ûmÎ:„.•ˆ8TLÉr©™®ù­Âô•ü¼ˆ¬´¥Û¿Qìybׂá²q<'~}Øcð–™±U#ù²»Ï¯Û†HÑX“Å4p KBÕ…‰ÃWöÍK›Þ¢ekwU h”Ìja?Eõ’üx "„X­ ‘„Ž)ß»Ü\—sûÍ঳4ü¿"-]˪Šá¹Ú4/º[¦ºßy¾ûùÇ?Úæ°˜Þ7/yrÙ³eš2h?m Œ¶•y[†ø ŠGÁoS^4W‘j´d~ùàoÊyŸôIëJQXuÒððøë«ƒÆ­Ýùüîx}ºZ‰ðR ˜”@€ìXÝ ÕÌpê—{ok…’ƺÇ7NÌšz4âLÓ(p7`츔-”ˆË^=ܾÂSn–à³ÃÝ?ýi‰H"Ì{pu…×PÙ¸‚0êêÓwéG=íÍ v¹ß«÷º‡Ü ©XÈ}r;zù»Kᱟ&¸û^Êâ6Š Ý\ç;J6nãúåñ+wÞT $š{NêZùÊÆoǯÚ墘žekÙ0²·_tZy½HTÏpýLÀLU¼B³XkÎ=©¬Cèþ¹»¦Ì»œU ’ˆ ².ÏŸ²}îþÕ-£š&Bhxèðï74üÒOKâHÔ¦‰2,ÓÖÛrBlÓ@[e𥦠ÚU[‚Â#£-Âh¶|šx‹µˆõÜcgŒ‚¦ g29î_Åp<ÞýݼR<¹l’yì%o+]„þ ù×âûºâü¹=¼&%£ @wŽ‚ñQ2ßXÞâQ΢±ö‘‘ÝI~~LkoÌûáÓ@qÂe_ëž½ô’f»Núá…÷¹±Îœœ2oCf«ø¶H ±†ÆèäÆº;¾‹œº$6"dŠ£­¤"ÿàOÞ—éÛ'š¶ÖI`ÿa9Ï-蔞½ô’f»Nú…Wÿæ”ñˆ[ÕÅz^%@c 4ÖÐXÐX·š„ãDzÆ¿ùÒ ÿÿµ»£ƒ%þˆþKý°ÂËŽÀ9ö{À`Pkè*5@^h¬k€Æh¬@£PA +³yóf š´°c t{È|5c›Á0¬Ó òûõ 옹:1ߎL³›jÛ)uºÂ“Ð"°c t6¤AO?ïÌ’!±‰{ŽŽüê ¥é45{‹i~ ÚvA‰h¬ çQô²/Açv~šš½Å4?Bm»‚Dyà(Ð3Á0,û\⌠v½˜t«a.QÇï)^½˜qÑg”•Ʋ3ýÇ—•òñìÓÛœì­XÚ kGÏoVi²DI“—ïÿØIÑÍÃ3ìu4¦^·ÙA,ê»§ìJ|à`3ŽÙ¸·‹jåƒ ü!sþmi¨K¥1ÍŒØøûkÅ9« vþoÌNsm-KùoÉ1 »vx‹³½%ƒÆ°°w9’ùÏO kš1ht {·´¼j%{E¹T5T› ÌkFéÞŒäp[3:•fb3j]ÒmEÿÅwÎ,òr2êŤ±8ŽÓ—>¨â¥éÊa^* „Du94-­t~BHP~¡?Qfüáíª-Aákû…±Î!^SaÔò’´uÕJ¤j£%LkKŽ 5Uí$¥@•ÜþÎÛÉN—Acé÷qñ^JòÑ€ÆÚØ:þÀ]ŸÆ«ªýólì«8'rå—ÂânŸÌl¨}½o!káäµ²Áâ«!N¡'nóëøW–œßñ^S-©ßµÔÍ=‘¸Ì‰À ?gß0ï36~Ï«TfGú9Ö‹›z£üT¿Å—uR3 ¸×w'ÏÚ›%_=ÆU:uí£b~õ[î™]!ü#©ŠóÞX‘°jçD2–2"® ¢Rþ¨©ã§¬²\ä`ó‡Vܹ̚ºÊSÁ½Om•Âj”íàJ›Q´çþ¼tjÔÓ¨Ô»5 u÷Ó¢žE{üç '\öµîÙKß)i¶ë¤^xŸëÌÉ)ó6dv»Jhsµw°ÂíìX]šÍ›73HÐ¥b8uÉO¿?¯IjÞä&ú~uôë68‰[û"iVß¿¾’fWÖ¶þÍ©+´ÿ“wÕ]¿4RíÐX žÀùN?oúŒÃ` ?§Üéðö‰¦mp²7ï¥Òãµê”4»²¶/’ↅÝ*A#ÕÐc€£ @çCp »;Ö5@c ÐX5h*Hte6oÞ¬A3€öv¬n™¯fl3†uz‚bA~¿~3W'æÛ‘ivSm;E¢.NWxBäÀŽ5Ð Ø=>ý¼3K†Ä$î-:òKž•¦ÓÔì-¦ù1hÛ% ±€žCtDAÒ˾ÛùijöÓüµí ä£ @Ïðìs‰3&ØõbÒ­†¹D¿§xõbÆEŸQTËvÌô_VÊdzOos²·bi3¬=¿=pX¥É%L^¾ÿ7b'E7Ït²×eИz}Üf±¨ïž²+ñƒÍ8fãÜ.ª•6ð„Ìù·¥¡.•Æ40bãï¯ç¬*Øù¿1;͵µ,å¿ Ç0ìÚá-Îö– ÃÂÞåHæ??%¬uhÆ Ñ-ìÝÒòª•ìåRÕPm‚2K¬¥{3’ÃlÍèTš‰Í¨uI·ýß9³ÈËɨ“Æâ8N_ú Jˆ—¦+‡y©\€Õåд´Òù !Aù†þD™ñ‡´«¶…G¬íÆ:‡xM…QËKÒÖT+‘ª–d0­-9‚Rì˜j'ó–ÜþÎÛÉN—Acé÷qñ^Jò‘€ÆZh‰ à.‹OãUÕþy6öUœÇ‚¹òKaq7‚Of6Ô¾Þ·µpòZÙ`ñÕ§ÐŒˆ·ùuü+ Ë Îïx¯©–ÔïZê‹æžH\æDà„Ÿ³o˜÷¿çU * ³#ýëÅM½Q~ªßâË:©™Üë;‹“çíÍ’¯ã*ºöQ1¿ú-÷Ì®þ‘TÅyo¬HXµs"K×Q)ÔÔñSVY.r°ŒùC+î\fM]å©àÞ‹§Æ¶Jaµ Êvp¥Í(Ús^:5êiTêÝš†ºûiQÏ¢=þsž+¿êî÷‚WU[úWÈèçn{ñÒ q0:ô´!T–µEBÁvþQŠz›dhÿµ¦ ÚU[‚Â#Ö6t¡MÒwMƹGYLÛ¥£…©–d0­-9:¦Ú[”¨âY¢W¢×¦ã¼*AEÑÓn$y€jNB%%%²¦¦¦¦¥¥¥ Ðã]’®V=c-몥R©ìŒ5ƒÁP5Plûª Lþ¬á}¯d&WQ´%bB(Ø¢W¯k[rTýHEüøuߌ]½u¼ S5HE'1v½‹“Ÿîk¢I ¹îÏÊ&êÑBâ.ÓÐCXó!Ô‡NM-©™`ÈPõ,nàÚÚ–›¿_öÏR>…bÖ’ÆR*ÃJ"®ovU¨Í.n,GêÎ «õ 6A„Æ:Ð\×ôVá}ÙxåßÑ.ÿTíQ½ETÿ‚®7N,|«6Í¢kž“¯yyÊùŠgßÓ‡>;³´0ÝëúgÖQs®¦ûô׈A‡i«Xx-j[ûÏ>3ÇW•ÜX„P¨¥ëzÁæf1•¢%LkKŽ ; ÚÉÌ=Äw$'ÁѸÅÒÅ{ä ± ±Þ¬ôŠš·NI6ÖRq•n.U#„Dõ/WÌ[ù¸„Çãñ^—–U× e–åïúFCª–’qCIäÊ£»×Ó´ZCõNLèÔÇ5BEKy$…/’(ŽK$„PΩ^ËXNp7fä(gŸYN}å6¹'§Qö]šÝÔ âYâõx/É4Öx ¸Õ£QòëET¬YóJ*ÃJÜÈW7£ôä#Ji6ð¯÷z¶ºxÏ$ŽÎž¼ÇNÖ~å¿ù›²'f•ú™°4bÐaÚ* m¥“ zí-ª°E/8f_UTüÞ¬¥r´$ƒimÉáwLµ+‚7£±6õi­ÐHÝŒÊtpèV?6ŸëmíGʤ!Fiê¨v»Oä¾)6îà/¿e–”¿;ý)ACjŽ—„ømìÕx)ñü{¿VÆsR#–²´ÔŸQIQy£D~ˆBÖg „ω|òò‚ç«Â웫gŒØpì‰ü–o×ç&Ͳ’¿$°Ô8x ¶ðc:"¹.ïI¤”&]²cÃÉâ×gï3fÛqúé=þ‰—›Re2Ϙ¥)ƒÓV±ðHh‹EÎ4ßp÷õë;,|c©®D$imÉáwLµ“‘¨^"ehamV Ý;Ö@gCþ(ˆjWMrÇú̓Uƒæõ~›³!¤K¥p"S²\j¦k~«pã}%?¯"+méö/F{žØµ`¸lω_öؼeflÕH¾ìÃîókÁ¶a†R4Öd1 ÜEÂR„Puaâð•}óÒ¦·hÙÚ]U%³ZØAQ½$ÿ^‚!E«B$¡cÊ÷.7×å\ã~3¸é, ÿ¯HKײª¢D¸G®6͋nÆwžï~þßñ¶9,¦÷ÍKž\öl™¦ ÚO[‚Â#£meÞ–!~ƒâQðÛ”ÍU¤-É`Z[rxãPíJàÍèoÊyŸô »UÊt°c t'T?0GÀ©_î½­Jëß81kêш3M@ÀÝ€±ãR¶P".{õpû O¹}X‚Ïwÿô§%"‰0ïÁÕ^CeãVt ¨«Oߥõ\´7ƒØIä~ÿ­Þër+¤b!÷Éíèåï.…Ç~šàî{)‹Û(j(xtsï(Ù¸ë—ǯÜyS-kî]8©kå+¿¿j—‹bFx–­eÃÈÞ~Ñiåõ"Q=ÿÁõ33TmðDÍ6b­9÷X¤²¡ûçîš2ïrVH"*Ⱥ<Êö¹ûW·Œjš¡á¡Ã¿ßðÐ9x B¨¿ßṵ̈­9iРý´%(<2ÚêÛ ´Ú IDATõ[oò|ËÖWÿ PèVÕJD†Ö–ÞxT;zÿãÈx3†ÇÍŠôZu?¯L,nÈϺáïÖ*å ±$À‡à®ÛÉk‡šëkëÍ?½0%{¥½l<9=)#̃¥Íá±¢ql„ܾŸÏ‘ŸC„yfÓuœlePô†QØÛ~ùKž1;æW'V³2bFÇ,taÒÙã|B%ŽaZÔ¦-p›)iëìýX =×%ñú.M»§®fgcü?áè°lÂSWïmG‰…Å!™S-ØŠ1¨µl˯^ò0ÞÆÅ6²Ø~Ñ9ôœª ^‚¡Øó;î­qeP©ú&Šã–^¯lñ¹#‹Æpð~逧%q$jÓD–Šiëm9!¶i -2ÍÇRSíª-Aá‘Ña´[>Í?¼E‰ÈЪ’#oïj'_~Ös 0 š6œÉä¸Ãñˆm•òí :⣠d¾±¼Å£ Ecí##»“üü˜ÖÞ˜÷çâ„˾Ö={é;%Ívôà ïsc99eÞ†ÌnW m®ö.¢<À‡;Ö@—fóæÍ t©˜N]òÓïÏëD’š7¹ ¾_ýº NâÖ¾HšÕ·Ç¯o§¤Ù•µ­sê íÿä]uׯT;4Ö¨'p¾ÓÏ›>ã0ÆÏ)w:¼}¢iœìÍ{iA§ôx­:%Í®¬í‹¤¸aá_w£JÐHµôà(Ðùè.ÀŽ5@c ÐX4Ö@c … ]™Í›7kÐ  ý€k ÛCæ«Û †až X߯_`ÇÌÕ‰ùvdšÝTÛv¶:ÿçOG[3¨†®aOý¿¢+<Îôl`ÇèlH ‚Ÿ~Þ™%Cb· ùeÎJÓijöÓü´mo‰Önãäÿ³‹¿ñ£×H:ksÖíTÐX ¢# ’^ö%0èÜÞES³·˜æG¨m{K¤˜]R ¥fÖÿÃ4š5tÕ|lÀQ g‚aXö¹Äìz1éVÃ\¢ŽßS¼z1ã¢Ï( *e;fú/+åãÙ§·9Ù[±´ÖŽžß8¬Ò&ˆ’&/ßÿ±“¢›‡g:Ùë2hL½>n³ƒXÔwOÙ•øÀÁf³q nÕÊøBæüÛÒP—Jcš±ñ÷׊sVìüߘæÚZ–ò_pcvíðg{Kaaïr$óŸŸÖ:4cÐèöniyÕJöŠr©j¨6A™%֌ҽÉá¶ft*ÍÄfÔº¤ÛŠþ‹ïœYäådÔ‹Icq§/}P%ÄKӕüT.@‰êrhZZéü„ üC¢ÌøÃ ÚU[‚Â#Öö cC¼¦Â¨å%ië ª•HÕFK¬'Á*à­†au - S¼JðPtLm?džè’Ûßy;Ùé2h,ý>.ÞKIþÿ5ð1¶ÎÄ?p—ŧñªjÿ<û*ÎcÁ‰\ù¥°¸Á'3j_ï[ÈZ8y­l°øjˆShFĉÛü:þ•„eçw¼×TKêw-õEsO$.s"pÂÏÙ7ÌûÀŒßóª…Ù‘~Žõâ¦Þ(?ÕoñeÔÌîõÅÉóƒöfÉÆWq•N]û¨˜_ý–{fWÿHªâ¼7V$¬Ú9‘Œ¥Œˆë‚¨”?jêø)«,9XÆü¡w.³¦®òTpïÅSc[¥°Úe{Òfí¹?/õ4*õnMCÝý´¨gÑÿ9Ï•_õŠNw Š{Á«ª-ý+dôs·½xi†8zZŽ*ËÚ"¡`;ÿ(E½ÍN2´ÿZSíª-AákºÐ&é»&ãÜ£‡,¦íÒÑÂÔFK 'Á*¬Þ%¼‡¢cjƒÌ¢ÄSñ,ÑÎ+ÑkÓq^• ¢èéŽ7’ÿ?´½9A•””È^˜šš˜–––‚^@{`llŒwIvºZõŒµ¬«–J¥²3Ö CÕ@ñ­½º0ÁÔáÏÞ÷JfRqEÛX" „‚-zõºV°e GÕTÄ_÷ÍØÕ[Ç›0UƒTtc×»8ùéž±&ª‘šë~ñ¬l¢!$nà2 =„5OB}èÔÔ’š † UÏâ®í m¹ùûe/ñ,åS(f-i,¥2¬$âúfW…ÚìáâÆr¤îä«ZjDøçhÍuMon°Ñ—WþmáòOUÑÕ[Dõ/èzãÄ·jÓ,ºæ9éðš—§œ¯xöÝ9}è³3K Ó½®f5çjºOt˜¶Š…×¢¶µÿì3s|UÉE…Zê±®lnS)Z= VžVûoµE‡ÕÁ£A&žè!†¼#9 ŽÆ-Ö9ÞÿÐX=¶±V|S”o‘l¬¥â**Ý\,ªF‰ê_®˜·òq Çã½.-«®Ê,94Êßõ†T-%?→ȕGv¯5¦i)¼ý«wbB§>®*ZÊ#áÐ(|‘Dq\"‘ „rNmôZ~Är‚ó¸1#G9ûÌrê+·É=95ˆ²ïÒì¦^ϯ]À{I¦±ÆKÀ­’_/2 bÍšWRVâF¾º¥¦%QJ³½÷гÕÅ{&qtöä=v²ö«(ÿÍß”=1«ÔÏ„¥ƒÓV±ðHh+dÐkoQ…-zÁ1ûª¢â÷f-•£%Г`ÚÐX«}(:¬6 2ñkSŸÖ Ô=ŒËð!ÀQ [ý Ø|v³µŠ’J„¥©£Úí>‘ÿù¦Ø¸ƒ¿ü–YRþ! ©9^â·±Wã¥Äóïý¦ÏIXÊÒRFE$Eåù/Êe]5BhðœÈ'//xޱ*̾¹zƈ ÇžÈoùv}nÒ,+ùKKƒ—` ?¦#’ëòžDJiÒõ';6œ,~}ö>c¶§ÞãŸx¹)U&óŒYš2è0m „¶XäLó w_¿¾³ÁÂ7–ŠáJD gkV¡eÔ>V$/žz‰”¡…µy™ÚÒ¨ ر:òGAT»j’;Öo¬4¯÷Ûœu!]*…+q¨˜’åR3]ó[…è+ùy%YiK·1¢ØóÄ®ÃeãxNüú°Ç>à-3c«FòevŸ_ ¶ #ú#Á5YLw‘°!T]˜8|eß¼´é-Z¶vWÕ€FɬöcPT/Éÿ— BˆEѪIè˜ò½ËÍu9×¸ß n:6Àÿ+ÒÒµ¬ª(î‘«Mó¢»eª›ñ统ÿwü£m‹é}ó’'—=[¦)ƒöÓ– ðÈh[™·eˆß xü6åE@s©FK 'Á*¬Þ¿Õ>Vx‹¢^<þ¦ì‘÷yAŸ°[µLìXÝ ÕEpê—{ok…’ƺÇ7NÌšz4âLÓßp7`츔-”ˆË^=ܾÂSn–à³ÃÝ?ýi‰H"Ì{pu…×PÙ¸‚0êêÓwéG=íÍ v¹ß«÷º‡Ü ©XÈ}r;zù»Kᱟ&¸û^Êâ6Š Ý\ç;J6nãúåñ+wÞT $š{NêZùÊÆoǯÚ墘žekÙ0²·_tZy½HTÏpýLÀLU¼B³XkÎ=©¬Cèþ¹»¦Ì»œU ’ˆ ².ÏŸ²}îþÕ-£š&Bhxèðï7øJH ±>ÂÆº;¾qœº$6"dŠ£­¤"ÿàOÞ—éÛ'š¶ÖI`ÿa9Ï-蔞½ô’f»Nú…Wÿæ”ñˆ[ÕÅ>¶J€Æh¬k5$?–}4æøÍ—ýGø¯Ýµh,1tl$ÉŽÀ9ö{À`Pk ±€®ÒXt0ðáE€Æ ±h¬€Æ4 $º2›7oÖ @û;Ö@·‡ÌW3¶ Ã:=A± ¿_¿ÀŽ™«óíÈ4»©¶d¢í Û5eè`ÇèlH ‚Ÿ~Þ™%Cbw ùmJÓijöÓü´í‚uL@c @GQô²/Aç6(šš½Å4?Bm»‚Dyà(Ð3Á0,û\⌠v½˜t«a.QÇï)^½˜qÑg”•Ʋ3ýÇ—•òñìÓÛœì­XÚ kGÏoVi²DI“—ïÿØIÑÍÃ3ìu4¦^·ÙA,ê»§ìÊÿgïM㚺¶ÿÿ}HB‚( ‚8A¥EôkA*ÈE*X¹´¢ö/m¹‚XAE,â@) (â„xµŽÕBµul‡[ŠU‹‚ŠX­ ah¤‘1„ ¿“s ¸ÞîëfŸuÖ^ë³×iVv6&%l¤Ïbâ¼ÜŠ&å`«ðVäìYëÓlËaNk~{ª:g}YêÿƧZêêX*¿ãÆ0ìâÞõnŽÖ,ËÊÑ}_þß?¦­tnÁb0­=³KÔìUåÒÔ7A…%ÖÚ½y™1ÎöL:ÃÌn쪌\Uÿ•׎/ðs5Àfpx.ÓCnÕ‹‰Òôà±ÏÖŠB’æb†ŽNް!$ª=Í2œ¬0~}ƒnÕ–¤ðȵýÄTo ½0šºz#šdrÜh»oÍ ’5Ñ\䪪VÑÓaXÝ½Ó }'s™t]õ4BU¹ßú»:è³ÃAîþ!ÿã5ð–¶Îäaßó¥d ê›þ8‘ô$ÙgÞáÇÊKÑÉ—#Žä·6=Ý1Ÿ3ÊJÅ`å…Hר¼ØÃ¹Âfáù´Ee§6¿ÔTËZ¶„¢9‡Ó¹’8ïx×׌5õ¢ºò¸ —i{×Rš´ðœ^V~ÿRjeæ§áÛ ãËÇ{ȽWÞ©6<ãß)Ü—¥:ïå%iËR'S±T{Iìzc³ðØ2ëÎÖ‰×u’Oæ76??1p¡wR—ÆMP±ƒ+ï@ÕžÿSˆw|Q|Öï­Í7³ãï'øüç_yÕ/!Ç3<ù¡ ¾©úÏÈq|<·¥él²§¨!TS°^FÃR¯W#„žf;~©-ƒnÕ–¤ðȵšo—ñm»ñãý{¬¦mÑÓÁp£í¾Y^9kܹˆTÕ¬"¢§!4mmN`ÜáªúV‰¸™z¡ÖÝOwðK÷[{HP/ª«(ÚêIñ?¯Õœ „ªªª/ÌÍÍIL«««A/ ;055%º¤8]­yÆZÑUËårÅk‹¥i Úö5”§™;ÿÑ(8 f&—ÖÓtMeRB(ÂjÀ€‹eë‡ó4ýÈ%”U_OX¾a’[3HU'‰+3‹¶M0ÓŒ$ÌRÿ“û5“ ˜!i+Ÿmì#n¼‡ĤgU5¾oÌÒô,måÛØø¸t§â%‘¥r Õ¬emÕt–LÚÒáª\—;FÚV‹ðŽ·âzÀMŸ±³Ô7¿Z¾ÚÎP1þü¯+÷¿ë+¶iÞ"iyÈ4˜(?ÃM³â¢ï{W<:êvÞwpêôÑ÷‡”çø]ú·müì 9CµbÐcÚª^§Ú6ý½ÃÂåÉs~B(ÊÚ€s©l]‡˜jÑvÓ,¸_©dM4Im«ÅIôtté(¶êÔ £ŒûŠÓ\L;-r¢ÿ8@c ôçÆZõ}Q¹éE±±–KëéLK©¤!$iy´dîÒ»U@𴺦¡E¬°ä1hµ´ÓuÔüH[«â–îݺҔ¡£Òâ;1cÒï6ŠU-•‘ð4¡D¦:.“ÉBÅG×ø-Þgý¾ÛÄñïu ˜é:Xióøˆw8mÇÙYí½ ‘%QÇ@ô’JcM” ‰[­´EbDÇ:4NgÙHÛ„x3Ê1LG9¢–f«ðÒÀÑ'*·}ÀÓÛVr×Õ6¨®ö×`sîä‚ê 3ŽV zL[Õ£ ­ü£Û+êìÑCžÅçuu¿uh©mwÌ¢öP—²&š‹¤¶Õ\=6ÖDS›êÒ‹šÄ&xO"‰z¯ úÔÁŽ™]ý“2¹LŒÑÚ;ª­^“…¯MJÞýó¯ùUµ/NsÊÂÎwâ‘Ak´M?õÒ—ÅDN¥rÁë9ªm“)¿þVô ¡‘³ãî=:í;Þ¦¼ðÊòN«ÞSÞòÍW3fÚ(_’Xj¢;ù˜Ž(®ËK©¥É4œâÒz¤ò鉛¬Y¼¡áw<>Vo6×”£-ƒÓVµð(h‹Å}d¹ú÷§O¯­¶ L¢c„uÇ,ò—ÑJµPW•èéxå©[dr–öÊkðŠ ‚k ·¡~D³«¦¸cýÏ­e#æ|V¼ !¤O§ñES³ ±Ð·¼Z¾f˜¡šŸ'"‰®|Ó'N•¾‡·Ì£'r4ˆ;á–`‘W3’ÏqýR¶ñ]c)Ú ØF^q5B¨¡<}ÌÒÁ%ÙÓ;µìꮪƒ–ß ¢i^Rþ¢BšNDÆÄÔï]l©Ï»ÈÿzdûYáŸqÖ5õiˆt7Í3^ÖYž¦×l}ðßIw6:/d.ÉœRs‘¶ ºO[’£¢íó’õ£‚F¤ ˆgdžvT‘f´Ý1 ÑGY*Y“Ì…«ªf=îXMlÎ}ï¦ ün—Öà5k /Ñ¥½´£?ßxÖ$–µ5ß½|x¦÷þØãíÿ,€—kóÙB±LZóäö¦%¾Jûè´€Í^Á9EU™¸äÖ…%~£ã6LÂèË¿û¹ßwÁö‹Á6ä9+œCñ”O iÁ³˜8/·¢I9Ø*¼9û_ÖÆútÛr˜ÓšßžªÎY_–ú¿ñ©–º:$–ʯË1 »¸w½›£5‹Á²rtß—ÿ÷i+]†[°L+GÏì’5{U¹45ÄMPa‰u vo^fŒ³½“Î0³»*#WÕåµã ü\M°žËô[õb¢4=xì³µ"„¤¹˜¡£“#lE‰jO³ '+Œ_ß [µ%)mQÙ©Í/5Õ²–-!hÎáôE®$N„Å;Þõß5cÍA½¨®¼0.È¥EÚÞ•f-<§—•_Æ¿”Z™ùiøöÅøòñrï•w*… ÏøÇ·D ÷e©Î{yIÚ²ÔÉT,Ä^Å»ÞØ,<¶Ìz³uâuä“ùÍÏF \èÔ%…qTlOÊ;Pµçÿâ_Ÿõ{ckóÍìøû >ÿ9ÅW^õKÈñ O~(¨oªþ3rÜÏíDiF:›ì)ªEÕ¬—ѰÔëÕ¡g…ÆŽ_jË [µ%)ˆ^Ri¬‰$qkÀ •¶HŒèX‡æÏé,i›oF9†é(GÔÒl^8úDCå¶xzÛJîºÚÕÕþlÎ\PdÆÑŠAi«Zx´•`4`{E=zȳø¼®î·-Õ£%™¥+«ÐycMÅ•PƒHS]zQ“Øïñ!IàÍŽ‚}êƒ`ǹϮþ½”\&ÆhíÕV¯ÉÂ×&%ïþù×üªÚgeaçxIdКmgÓO½ô½3‘“F©œ£ƒFE"Gµm2å—슮!4rvܽG§}ÇÛ”^Y>ÃiõÁ{Ê[¾ùêqÆLåKK­C”`'ÓÅuyI"µ4™†S\ZT>=q“5Ë74Üàî‚ÇÇêÍæšr´eÐcÚªm±¸,WÿþôéµÕVItŒP"’Yº² Ú]Ó.)Ð"“³t°W ÷;Ö@oCý(ˆfWMqÇúŸ[ËFÌø¬xBHŸNã‹$<:¦fb¡oyµ|Í0C5?OD]ù¦Oœ*}o™7F1Nä$hwÂ-Á" ®f$Ÿ âú¥lã»dÿ6p[cÛÈK"®F5”§Y:¸${z§–]ÝU5bÐòÄCX4ÍKÊÿC” BˆCÓ©“Ș˜ú½‹-õyù_û‘A‚ IDATl?K#ü3ÎÚ£¦¾" ‘n‹â¦yÆË:ËÓôÚƒ­þ;éÎFç…ÌÁ%™Sjî/Ò–A÷iKRxT´}^²~TЈñìØÃÐŽ*ÒŒ–d–.­‚æjª™QñF¥Ô R ØœûÞMAø;Ü. ðæ;Ö@_BóæH8úógMbY[óݡgzï=Þþ/ x±6Ÿ-ˤ5OnoZâ«´N ØìœST%‘‰Kn]Xâ7Z1nä!Œ¾ü»ß™û}lÏ#w·3xƒÿªÛü:¹TÌ¿—›°øÅ¥˜¤Ó¼ÏðÛ$­ew®¬ «·óøìÐùkÿ4ˆdâÆ§èÛ*ƯF¤,Û⮚‘eWYýÞÀ „ìÚ‰¤ExëÒñМ5mˆDÍ2á¬8yW¢±Q;çl™:÷\A™D&)+8÷éÔMsv.ï4Í4Bc¢ÆX}Û-b8BhhЧùÑ?Ø.pÕ¢A÷iKRxT´5ò•Ùƒõžü_¨Êg3\‰ˆféê*­æ+x#7Výkc"b’gÆù-»YR#•¶–\Ž öì’°ÐX@爈!¹+7såhKC]=“Y1ßÍ?V¸ÔÑH1ž™“‘íÃÑe;ù,i›«´°ï§¨aÑþã¸L=·y8“BU½a4îÆŸÿÀ2gÌJü…ĉÍÌ´¼Äq‰óÝÙLîÄ€(™K´½} ÜnÞ±ìUŽ1þΖÇ)†îí»§a'ƒßáéqMìb²DnlBIÅ•‘ùS츪1àZ¾‹/œu;ÅΘÃ5± ÝtÆ-ꤦ Q‚¡¤S›o¬ð`Ñé†fVªãÖ~»Ï¯uŠýØ…Ã`9ûÇŒŽ9»Ëך<Ü4B&ã"äRÆWö<„×<ÌžA›`­-ƒnÕ–¤ð¨h‹0F¬½Ó©DD³tuˆVó¼Q7&RÀvÎÁ¡&áÓÆ°Ù<¯Ïy>I] ×£ @ïC~„Ê/–wz¤·hkºcâpDXšØÕK¾ÿ0Lšv.ж/}¯¤Ù­“¾~á}lª7»¸Æß˜Mí[øc‡ðûŽ@c ¯ÛX÷Å·ááÞ_$ÅFNu±—Õ•î^á+ø,gÓdó®: :,ºø“Ö¿—¾WÒìÖI_³ðZþ9jêtµ¡ry´ÐX@c oEcvè`áþÄCW u ^¹5~ÁDXbèÿ(R?.”wð·Ð‘ÐeBÊ@c oJc ÐÃÀ/4Ö5@c 4Ö Uè ð&³nÝ:-št°c ôy¨ü4ã+ƒaX¯'(•Ö3sõb¾=™fÕ¶W$ê¯U÷&<Úô?`ÇèlH‹D¢~Ÿ~Éñ/F%í&ozò·3Ô¦ÓÖì¦ù6hÛŸ¢}ýÒê—95½IBlYÆ£Á$½ÛghköNÓ| µíÓÑöb-ôpèŸ`Vx2}ÆûØL›wÝãÝP½z&ïLÀX+:ƒc?~úž+Ç ¿ÛèêhÃÑeÙºø~³k¯ÆÛ¾$#tÊâ¿’;©¸²÷#WG}ƒm0ÈsV8‡þâ);Ÿ6Ò‚g1q^nE“r°Ux+rö¿¬õé ¶å0§5¿=U³¾,õãS-uuH,•_jcvqïz7Gkƒeåè¾/ÿïÓVº ·`1˜VŽžÙ% jöªrijˆ› Âë@íÞ¼Ìg{ &af7vUF®ªÿÊkÇø¹š `38<—é!·êÅDizðØgkE!Is1CG'GØŠÕžfNV¿¾A·jKRxäÚ~bª·GÐ^M‚ ]½M2y·FK3IõâV{§-¹[Íò£¨-B¨*÷[W}ƒc8ÈÝ?„â+ ±Þ–Ö™Ü ì{þ¢”lA}Ó'’ž$ûÌ;üXy):ùrÄ‘üÖ¦§;æsæOY©¬¼é•{8WØ,<Ÿ¶¨ìÔæ—šjYË–@4çpú"W'Ââïú怠^TW^äÒ"mïJ³‚žÓËÊ/ã_J­Ìü4|{b|ùx¹÷Ê;•†güã["…û²Tç½¼$mYêd*– b/‰â]ol[f½ÀÙ:ñºNòÉüÆæçG#.ôNê’¸ *öå¨Úó ñŽ/ŠÏú½±µùfvüýŸÿœâ+¯ú%äx†'?Ô7Uÿ9îçv¢4#MöÕ"„j ÖËhXêõj„г cÇ/µeЭڒ¹¶Qóí2¾m7~¼Õ´-z:XÏWу€3Q$DÕN"·$åG®mÝýt¿t¿µ‡õ¢ºŠ¢Í¡žÿ[еæ!TUU¥xannNbZ]] zÝ©©)Ñ%ÅéjÍ3ÖŠ®Z.—+ÎX³X,MÕ÷݆ò4sç?ÔÌäÒzš®©L*BEX p±lýpž¦¹D˜²êë Ë7L2ck©ê$Ña`efѶ fš‘„Yêr¿f²!$må³}Ä÷Bƒ˜ô¬ªÆ÷Yšž¥­|û—îT¼$²TN¡šµ¬­šÎ²‘I[:\•ërÇHÛjÞ)U\¸ "â3Öa–úæWËWÛ*ÆŸÿ•`åþw}Å6Í[$-™¥âg¸iV\ôý`ïŠGGÝÎûN>úþñò¿Kÿ¶Ÿ}!'`¨V zL[ÕÂëTÛ¦¿wX¸¦#Šëò’Dji2 §¸´©|zâ&k–oh¸ÁÝÕ›Í5åhË Ç´U-< ÚbqY®þýéÓk«­“èêîhå/Cò ÅL QµãΨÉ+'Hg‹LÎÒÁ^yɨ6*v¬Þ†úQÍ®šâŽõ?·–˜;ðYñ*„>ÆIxtLÍ2ÄBßòjùša†j~žˆ$6ºòMŸ8UúÞ2oŒbœÈIÐ î„[‚E\ÍH>ÄôKÙÆwI¤hk,`yIÄÕ¡†òô1K—dOïÔ²«û”F Z~ƒx‹¦yIùˆDqh:uS¿w±¥>ï"ÿë‘íG„ÆY{ÔÔW¤!Ò=rÜ4ÏxYgyš^{°õÁ'ÝÙè¼9¸$sJÍýEÚ2è>mI жÏKÖ ‘‚"ž{ÚQEÝ-.¸I̸‘P©öNÕÓt«Y~jÅlÎ}ï¦ ün—–  «ÀŽ5З ßåRãèÏ7ž5‰emÍw/žé½?öxû¿àeÄÚ|¶P,“Ö<¹½i‰¯Ò>:-`³WpNQ•D&.¹ua‰ßhŸ “†0úòï~gî÷]°=ÜIÜÎà þ«nóëäR1ÿ^nÂâ—b’>Ló <[Ào“´–ݹ²*p¬bÜÎã³Cç¯ýÓ ’‰oœ>¢o¨¿‘²l‹»jFD–]eõ{ƒ²k[$’á­KÇC?rÖ´!J!4Ë„³âä]‰Æ:D휳eêÜse™¤¬àܧS7ÍÙ¹¼Ó`4ÓD‰s`õm·ˆá¡¡AŸæGÿ`»ÀU‹ݧ-IáQÑÖ`ÈWfÖoxò¡*ŸÍº5ZMp¢˜‰"!ªvŠ$¨Y~ªÇKˆâŒIžç·ìfITÚZZp96سKK5ÐCrWnæÊÑ–†ºz&³b¾›¬p©£‘b<3'#/Ú‡£ËvòYÒ6!Vi?$`ßOQâýÇq™znó6p&…ªzÃhÜ?ÿeΘ•ø ‰›™iy‰ã绳™Ü‰Q2—hzûΟݼcÙ«cü9,/R ÝÛwOÃ<,N$¿ÃÓãšØÅd‰.ÜØ„’Š+#ó§†YqUcÀµ|_87êvŠ1‡kbºéŒ[ÔIM¢BI§6ßXáÁ¢Ó ͬTÇ­ývŸ_ëû± ‡Árösv—¯5y$¸i"„LÆEÈ¥Œ¯ìy!®y˜=ƒ6-ÀZ[ݪ-IáQÑaŒX{!#8†\"-F« îƒ@3Q$DÕN’‰Ê\[Û9O„š„OÃfó¼>Oäù$uiÉ(GA€Þ‡ü(•_,ïô(HoÑÖtÇÄሰ4±«7–|ÿa˜4í\ mÿ^ú^I³['}ýÂûØTovq¿1û­ª„Þ|„Ÿrkà-i¬ûâ›åpï/’b#§ºØËêJw¯ð|–³i²yW„ ]üÀŠIëßKß+iv뤯Yx-ÿ5uºÚP¹ëm«h¬€Æ ±Æ!íÐÁÂý‰‡®<2ê¼rkü‚‰°ÄÐ¥Q¤0~\(ïào¡#AIh¬€ÆÞ”Æ ‡?^h¬k€Æh¬@«ÐAàMfݺuZ4è>`ÇèóPùiÆWð^OP**2$¬gæêÅ|{2Í>ª­£}Í`º£N^ßç›ð´ð–;Ö@€dCZ$õûôKŽ1*i7y?Ñ“¿p¡6¶fï4Í·A[êѾù?kB1Bø} ± çHˆ-Ëx4˜Ä wûmÍÞišo¡¶o‚D}¥~Þà(Ð?Á0¬ðdúŒ÷°™6ïºÇº¡zõLÞ™€±VtÇ~üô=WŽ~·ÑÕц£Ë²uñýf×^@’:eñÎ_ÉT\Ùû‘«£>‹Á6ä9+œCñ”O iÁ³˜8/·¢I9Ø*¼9û_ÖÆútÛr˜ÓšßžªÎY_–ú¿ñ©–º:$–ÊoÀ1 »¸w½›£5‹Á²rtß—ÿ÷i+]†[°L+GÏì’5{U¹45ÄMPa‰u vo^fŒ³½“Î0³»*#WÕåµã ü\M°žËô[õb¢4=xì³µ"„¤¹˜¡£“#lE‰jO³ '+Œ_ß [µ%)gþ”•ŠÁÊ ‘®Qy±‡s…ÍÂói‹ÊNm~©÷µl Ds§/r%q",Þñ®ÿ®kêEuå…qA.-ÒöÞ¨4+há9½¬ü2þ¥ÔÊÌO÷(Æ—÷{¯¼S)lxÆ?¾%R¸/KuÞËKÒ–¥N¦b© ö’(þØõÆfá±eÖ œ­¯ë$ŸÌol~~4bàBï¤.)Œ› bQÞª=ÿ§ïø¢ø¬ß[›ofÇßOðùÏ)¾òª_BŽgxòCA}SõŸ‘ãøxn'J3ÒÙdOQ-B¨¦`½Œ†¥^¯F=+Ì0vüR[ݪ-Iá‘k5ß.ãÛvãÇû÷XMÛ¢§ƒáF‹» ¸>;ÍK³°5©»Ÿîà—î·ö ^TWQ´9ÔSy‰¨ª©GøÊ¥HÅUÐ~s‚ªªªR¼077'1­®®½€îÀÔÔ”è’âtµækEW-—Ëg¬Y,–¦jÛ×PžfîüG£à€zW!­§éšÊ¤"„P„Õ€ËÖçiú‘K„)«¾ž°|Ã$3¶fªNVfm›`¦I˜¥þ'÷k&0BÒV>ÛØGÜx!4ˆIϪj|ߘ¥éYÚÊ·±ñqéNÅK"KåªYËÚªé,™´¥ÃU¹.wŒ´­ájÅõ€› ">cf©o~µ|µ¡büù_ Vî×WlÓ¼EÒòi0Q*~†›fÅEßö®xtÔí¼ïàÔé£ï)Ïñ»ôoÛøÙr†jÅ Ç´U-¼Nµmú{‡…Ë“çü$„P”µçRÙº1Õ¢E¤G“U}’çE^ØJF ö§¹˜R¯jê’×É$QQ|ü ±ÞÞÆZõ]S¹%F±±–KëéLK©¤!$iy´dîÒ»U@𴺦¡E¬°ä1hµ´ÓuÔüH[«â–îݺҔ¡£Òâ;1cÒï6ŠU-•‘ð4¡D¦:.“ÉBÅG×ø-Þgý¾ÛÄñïu ˜é:Xióøˆw8mÇÙYí½ ‘%Q?Aô’JcM” ‰[­´EbDÇ:4NgÙHÛ„x3Ê1LG9¢–f«ðÒÀÑ'*·}ÀÓÛVr×Õ6¨®ö×`sîä‚ê 3ŽV zL[Õ£ ­ü£Û+êìÑCžÅçuu¿uh©-Þg|Ÿ$yá¶ÚA '¦ºô¢&±IWªšz„6ÖD7’DE² Ý úÔÁŽóš]ýƒ'¹LŒÑÚ;ª­^“…¯MJÞýó¯ùUµ/N…ÊÂÎñ’È 5ÚΦŸzé«d"'R9GÿŒŠDŽjÛdÊ/Ç•ýÇÈÙq÷öoS^xeù §Õï)oùæ«Ç3m”/I,µQ‚|LG×å%‰ÔÒdNqi=RùôÄMÖ,ÞÐpƒ»? «7›kÊÑ–Ai«Zx´Åâ>²\ýûÓ§×V[&Ñ1B‰¨¯I^¸…-Å`‹LÎêbUk¥¢Èo$‰ŠÊ*tK£‚`Çèm¨Ñìª)îXÿskÙˆ¹Ÿ¯BéÓi|‘„GÇÔ,C,ô-¯–¯f¨æç‰Hb£+ßô‰S¥ïá-óÆ(Ɖœ âN¸%XdÁÕŒä³AÜA¿”m|טDжÆ¶‘—D\j(O³tpIöôN-»º«jÄ å7ˆ‡°hš—”ÿ‡(A„‡¦S'‘11õ{[êó.ò¿Ù~–FøgœµGM}E"Ý#ÇMóŒ—u–§éµ[üwÒÎ ™ƒK2§ÔÜ_¤-ƒîÓ–¤ð¨hû¼dý¨ )(âÙ±‡¡U„­Ú*ø$Ê ·°q 6ç¾wSþNתšb„îXÝHÉ*t+°c ô%4ÿ`Ž„£?ßxÖ$–µ5ß½|x¦÷þØãíÿh€—kóÙB±LZóäö¦%¾Jûè´€Í^Á9EU™¸äÖ…%~£ã6LÂèË¿û¹ßwÁöOäù¼ø'Pˆªšz„Bt#ITTV ;€£ @ïC~„Ê/–wz¤·hkºcâpDXšØÕK¾ÿ0Lšv.ж/}¯¤Ù­“¾~á}lª7»¸Æß˜ýVU›¶ ÐXý°±î‹ï¬Ã½¿HŠœêb/«+ݽÂWðYÎ¦Éæ]u6tXtñ+&­/}¯¤Ù­“¾fáµüsÔÔéjCå®·­ ±k€Æ‡´C ÷'ºòÈh¨SðÊ­ñ &ÂCKG‘Âøq¡¼ƒ¿…Ž%¡±kxSk€þx ±h¬k ±­B €7™uëÖiÑ  û€k ÏCå§_ Ãz=A©¨tȰž™«óíÉ4û¨¶ZŒV+ ýjN”wi½ØÞ„§€·رú$Ò"‘¨ß§_rü‹QI»Éû‰žü9 µé´5{§i¾ ÚR~kºLBlYÆ£Á$½Û`iköNÓ| µ}$¨GA€þ †a…'Óg¼ï0€Í´y×=þÐ Õ«gòÎŒµ¢38öã§ÿðè¹r¼ð»®Ž6]–­‹ï7»öj4Y’ŒÐ)‹wþJî¤âÊÞ\õY ¶Á ÏYáú‹§ì|JØH žÅÄy¹MÊÁVá­ÈÙÿ²6Ö§3ؖÜÖüöTuÎú²ÔÿOµÔÕ!±TýnýâÞõnŽÖ,ËÊÑ}_þß?¦­tnÁb0­=³KÔìUåÒÔ7A…%ÖÚ½y™1ÎöL:ÃÌn쪌\Uÿ•׎/ðs5Àfpx.ÓCnÕ‹‰Òôà±ÏÖŠB’æb†ŽNް!$ª=Í2œ¬0~}ƒnÕ–¤ðȵýÄTo ½0šºz#šdrÜh5WÈ'yui6%{ LŸ>q”>K×ÜvÜòô_H*ª“s/?\TäBUå~ëïê Ïbp ¹û‡P|ü ±Ôµ÷i„¾ç/JÉÔ7ýq"éI²Ï¼Ã•—¢“/GÉomzºc>gþ”•ŠÁÊ ‘®Qy±‡s…ÍÂói‹ÊNm~é}_Ö²%$Í9œ¾È•ĉ°xÇ»þ»f¬9 ¨Õ•ƹ´HÛ{£Ò¬ …çô²òËø—R+3? ß^ _>ÞCî½òN¥°áÿø–Há¾,Õy//I[–:™Š¥‚ØK¢øc×›…Ç–Y/p¶N¼®“|2¿±ùùш ½“º¤0n‚Š\yªöüŸB¼ã‹â³~olm¾™?Áç?§øÊ«~ 9žáÉõMÕFŽ{àã¹(ÍHg“=Eµ¡š‚õ2–z½!ô¬0ÃØñKmt«¶$…G®mÔ|»ŒoÛïßc5m‹ž†-î*àúì4/µÂ¦¢ƒ*_fW,Þzòi}󽋻þ;÷ß{¾Â³¬ùpQ‘«î~ºƒ_ºßÚC‚zQ]EÑæPOŠ?@76'¡ªª*Å sssÓêêjÐ èLMM‰.)NWkž±VtÕr¹\qÆšÅbi¨¶} åiæÎ4 ¨¿£Këiº¦2©!a5`ÀŲõÃyš~äaʪ¯',ß0ɌӨ8ItX™Y´m‚™f$a–úŸÜ¯™lÀDI[ùlcqã=„Ð &=«ªñ}c–¦gi+ß~ÄÆÇ¥;/‰,•S¨f-k«¦³ldÒ–WåºÜ1Ò¶Z„w<×n‚ˆøŒu˜¥¾ùÕòÕv†Šñç%X¹ÿ]_±MóIËC¦ÁD©ønš}?Ø»âÑQ·ó¾ƒS§¾<¤<ÇïÒ¿mãg_È ªƒÓVµð:Õ¶éï.Ožó“BQÖœKeë:ÄT‹‘ž±VõIž—fa“T#î‡[õdÇÝh|zˆbQy¸HRKe,ØWœæbÚi=þÐXooc­ú®©Ü´£ØXË¥õt¦¥TÒ€’´àém+¹ëjTWûk°9wrAuG+=¦­jáQÐVþÑ€íuöè!Ïâóººß:´Tï³ ¾O’¼p ›Äþ¥?Ù:ÓB-YòÆ75ˆR3Õ¥5‰Mðž5’UèVà(Ч>vœ(í꟔ÉebŒÖÞQmõš,üxmRòîŸͯª}qÖY††pŽ—D­Ðv6ýÔK_%9i”Ê9:øgT$rTÛ&S~}¯èªB#gÇÝ{tÚw¼Myá•å3œV¼§¼å›¯gÌ´Q¾$±Ô:D vò1÷yë¶ IDATQ\——$RK“i8Å¥õHåÓ7Y³xCà îþ(x|¬Þl®)G[=¦­jáQЋûÈrõïOŸ^[m˜DÇ%¢¾^$yá6‘½üeð“•ã$Kn Sk‘ÉY:Ø+¯@·4*v¬Þ†úQÍ®šâŽõ?·–˜;ðYñ*„>ÆIxtLÍ2ÄBßòjùša†j~žˆ$6ºòMŸ8UúÞ2oŒbœÈIÐ î„[‚E\ÍH>ÄôKÙÆwI¤hk,`yIÄÕ¡†òô1K—dOïÔ²«»ªF Z~ƒx‹¦yIùˆDqh:uS¿w±¥>ï"ÿë‘ígi„ÆY{ÔÔW¤!ÒýKÜ4ÏxYgyš^{°õÁ'ÝÙè¼9¸$sJÍýEÚ2è>mI жÏKÖ ‘‚"ž{ÚQE¸Ñª­‰O¢¼p ›Èžèƒ®ê,ÏŸ5àÙýUkŒJ $©›sß»)‡Û¥UèV`ÇèKì–irôçϚIJ¶æ»—ÏôÞ{¼ý ð2bm>[(–IkžÜÞ´ÄWi°Ù+8§¨J"—ܺ°Äo´b܆IC}ùw¿3÷û.ØžGî$ngðÿU·ùur©˜/7añ‹K1I¦yž-à·IZËî\Y8V1nçñÙ¡ó×þiÉÄ7NÑ· TŒ_HY¶Å]5#"Ë®²ú½A Ùµ-I‹ðÖ¥ã¡9kÚ%ˆšeÂYqò®Dc¢vÎÙ2u2‰LRVpîÓ©›æì\Þi0ši"„ÆD9°ú¶[Äp„ÐРOó£°]àªEƒîÓ–¤ð¨hk0ä+³ë7<ù¿P•Ïf¸©­‘O’¼p »«:<“WÝÐ*“´ýïXÀ¿ö¬ù>„zÅ€^>yB”ZLòÌ8¿e7Kj¤ÒÖ҂˱Áž]Zh¬·1$wåf®mi¨«g2+æ»ùÇ —:)Æ3s2ò¢}8ºl'Ÿ%mb•öCöý5,Ú—©ç6ogR¨ª7ŒÆÝøóXæŒY‰¿8±™™–—8.q¾;›É%s‰Ö¡·oÛÍ;–½Ê1Æß™Ã2ðø"Åн}÷4ÌÃâDbð;<=®‰]L–èÂM!©¸22j˜W5\ËW`ñ…s£n§Øs¸&¶¡›Î¸EÔ´!J!”tjó,:ÝÐÌJuÜÚo÷ùµN±»p,gÿ˜Ñ1gwùZ“G‚›&BÈd\„\ÊøÊž‡⚇Ù3hÓ¬µeЭڒmƈµ2‚c:•Hmˆ|vš—ZawIŒÆ.øî뱃uÙÆ-Û7çHá—£¨×Q å²sðD¨Iø´1l6ÏëóDžOR—V ;€£ @ïC~„Ê/–wz¤·hkºcâpDXšØÕK¾ÿ0Lšv.ж/}¯¤Ù­“¾~á}lª7»¸Æß˜ýVU›¶ ÐXý°±î‹ï¬Ã½¿HŠœêb/«+ݽÂWðYÎ¦Éæ]u6tXtñ+&­/}¯¤Ù­“¾fáµüsÔÔéjCå®·­ ±k€Æ‡´C ÷'ºòÈh¨SðÊ­ñ &ÂCKG‘Âøq¡¼ƒ¿…Ž%¡±kxSk€þx ±h¬k ±­B €7™uëÖiÑ  û€k ÏCå§_ Ãz=A©¨tȰž™«óíÉ4û¨¶ZŒ¶ÇúMx‚z رú$Ò"‘¨ß§_rü‹QI»É{—žü9 µé´5{§i¾ ÚR~kºLBlYÆ£Á$½Û`iköNÓ| µ}$¨GA€þ †a…'Óg¼ï0€Í´y×=þÐ Õ«gòÎŒµ¢38öã§ÿðè¹r¼ð»®Ž6]–­‹ï7»öj4Y’ŒÐ)‹wþJî¤âÊÞ\õY ¶Á ÏYáú‹§ì|JØH žÅÄy¹MÊÁVá­ÈÙÿ²6Ö§3ؖÜÖüöTuÎú²ÔÿOµÔÕ!±T~ÛŽaØÅ½ëÝ­Y –•£û¾ü¿L[é2Ü‚Å`Z9zf—4¨Ù«Ê¥©!n‚ K¬µ{ó2cœí-˜t†™ÝØU¹ªþ+¯_àçj2€Íàð\¦‡Üª¥éÁcŸ­!„$ÍÅ a+BHT{še8Yaüúݪ-Iá‘kû‰©ÞA{a4 2tõF4Éä¸Ñj®‘OòêÒ,lJö¤õ_•û­¿«ƒ>‹Á1äîBñ‘€Æz¹u&7ûž¿(%[Pßôlj¤'É>ó?V^ŠN¾q$¿µééŽùœùSV*+/DºFåÅÎ6 ϧ-*;µù¥ÞCÖ²%$Í9œ¾È•ĉ°xÇ»þ»f¬9 ¨Õ•ƹ´HÛ{£Ò¬ …çô²òËø—R+3? ß^ _>ÞCî½òN¥°áÿø–Há¾,Õy//I[–:™Š¥‚ØK¢øc×›…Ç–Y/p¶N¼®“|2¿±ùùш ½“º¤0n‚Š\yªöüŸB¼ã‹â³~olm¾™?Áç?§øÊ«~ 9žáÉõMÕFŽ{àã¹(ÍHg“=Eµ¡š‚õ2–z½!ô¬0ÃØñKmt«¶$…G®mÔ|»ŒoÛïßc5m‹ž†-î*àúì4/µÂ¦¢Étu÷ÓüÒýÖÔ‹ê*Š6‡zR|$úIs‚ªªªR¼077'1­®®½€îÀÔÔ”è’âtµækEW-—Ëg¬Y,–¦jÛ×PžfîüG£à€zW!­§éšÊ¤"„P„Õ€ËÖçiú‘K„)«¾ž°|Ã$3¶fªNVfm›`¦I˜¥þ'÷k&0BÒV>ÛØGÜx!4ˆIϪj|ߘ¥éYÚÊ·±ñqéNÅK"KåªYËÚªé,™´¥ÃU¹.wŒ´­áÏÅõ€› ">cf©o~µ|µ¡büù_ Vî×WlÓ¼EÒòi0Q*~†›fÅEßö®xtÔí¼ïàÔé£ï)Ïñ»ôoÛøÙr†jÅ Ç´U-¼Nµmú{‡…Ë“çü$„P”µçRÙº1Õ¢E¤g¬U}’ç¥YØ$ÕH„êt £ŒûŠÓ\L;--¢Gkè‰ÆZõulÚQl¬åÒz:ÓR*i@IZ-™»ôn•@ <­®ih+,y Ú_-mÆt5?ÒÖª¸¥ûC·®4e訴†øN̘ô»bUKe$<M(‘©ŽËd2„PñÑ5~‹÷Y¿ï6qü{cÝfºVÚ<>âNÛqvV{/HdIÔ»½¤ÒX%HâÖ€A+m‘ѱÍŸÓY6Ò6!ÞŒr ÓQލ¥Ù*¼4pô‰†Êmðô¶•Üuµ ª«ý5Øœ;¹ :ÈŒ£ƒÓVµð(h+ÿÀhÀöŠ:{ôgñy]ÝoZªG‹÷Yß'I^¸…MRªMgªK/j›àÕ?‰2ý8 ô©‚'J»ú'er™£µwT[½& ?^›”¼ûç_ó«j_œu–!„!œã%‘Ak´M?õÒ×ÖDN¥rŽþ‰Õ¶É”_ß+ºj„ÐÈÙq÷öoS^xeù §Õï)oùæ«Ç3m”/I,µQ‚|LG×å%‰ÔÒdNqi=RùôÄMÖ,ÞÐpƒ»? «7›kÊÑ–Ai«Zx´Åâ>²\ýûÓ§×V[&Ñ1B‰¨¯I^¸…MQ¢éZdr–öÊÊôùFÁŽ5ÐÛP? ¢ÙUSܱþçÖ²s>+^…Ò§Óø" Ž©Y†Xè[^-_3ÌPÍÏ‘ÄFW¾é§JßÃ[æQŒ9 ÄpK°È‚«Égƒ¸ƒ~)Ûø®1‰ml#/‰¸!ÔPž>féà’ìéZvuWÕˆAËoaÑ4/)ÿQ‚!M§N"cbê÷.¶Ôç]ä=²ý,ðÏ8kšúŠ4DºGŽ›æ/ë,OÓk¶>øï¤;2—dN©¹¿H[ݧ-IáQÑöyÉúQA#RPijcC;ª7ZµU ñI”naÙ«A4]°9÷½›‚ðw¸]R ß;Ö@_BóæH8úógMbY[óݡgzï=Þþx±6Ÿ-ˤ5OnoZâ«´N ØìœST%‘‰Kn]Xâ7Z1nä!Œ¾ü»ß™û}lÏ#w·3xƒÿªÛü:¹TÌ¿—›°øÅ¥˜¤Ó¼ÏðÛ$­ew®¬ «·óøìÐùkÿ4ˆdâÆ§èÛ*ƯF¤,Û⮚‘eWYýÞÀ „ìÚ‰¤ExëÒñМ5mˆDÍ2á¬8yW¢±Q;çl™:÷\A™D&)+8÷éÔMsv.ï4Í4Bc¢ÆX}Û-b8BhhЧùÑ?Ø.pÕ¢A÷iKRxT´5ò•Ùƒõžü_¨Êg3\‰ÔVÈ'I^¸…Mb¯úçÂDÓÅ$ÏŒó[v³¤F*m--¸ìÙ%e ±€nGD É]¹™+G[êê™ÌŠùnþ±Â¥ŽFŠñÌœŒ¼hŽ.ÛÉgIÛ„X¥ý€}?E ‹öÇeê¹ÍÛÀ™ªê £q7þü–9cVâ/$Nlf¦å%ŽKœïÎfr'DÉ\¢uèí[àvóŽe¯rŒñwæ° <¾H1toß= ó°8‘üOkb“%ºpcBH*®ŒÌŸfÅU×òX|áܨÛ)vÆ®‰mè¦3nQ'5mˆD%Ú|c…‹N74³R·öÛ}~­SìÇ.ËÙ?ftÌÙ]¾Öä‘উ2!—2¾²ç!„¸æaö Ú´kmt«¶$…GE[„1bí…Œà˜N%R["Ÿæ¥VØu šÎvÎÁ¡&áÓÆ°Ù<¯Ïy>I]R ¯GA€Þ‡ü(•_,ïô(HoÑÖtÇÄሰ4±«7–|ÿa˜4í\ mÿ^ú^I³['}ýÂûØTovq¿1»ŸUüT$ÐXCc ôrcÝßŇ{‘9ÕÅ^VWº{…¯à³œM“Í»ê$lè°èâVLZÿ^ú^I³['}ÍÂkù稩ÓÕ†Ê]ý¯ ±kh¬h¬»LÚ¡ƒ…û]yd4Ô)xåÖøa‰ß¢ÿ¤¾^áÆ åü-t$(5¼)5@¼ÐX4Ö5ÐX€V¡ƒÀ›Ìºuë´hÐ}ÀŽ5Ðç¡òÓŒ¯ †a½ž TT:dHXÏÌÕ‹ùödšo›¶ý€7 رú$Ò"‘¨ß§_rü‹QI»ÉÛ‹žüé µé´5{§i‚¶o~› ?4Ö¼Ñ$Ä–e<Lbл݌¶fï4MÐxã @ÿð“é3ÞwÀfÚ¼ëè†êÕ3ygÆZÑûñÓxô\9^øÝFWGŽ.ËÖÅ÷›]{5ÚIFè”Å;%wRqeïG®Žú,Û`ç¬pýÅSv>%l¤Ïbâ¼ÜŠ&å`«ðVäìYëÓlËaNk~{ª:g}YêÿƧZêêX*¿Ç0ìâÞõnŽÖ,ËÊÑ}_þß?¦­tnÁb0­=³KÔìUåÒÔ7A…%ÖÚ½y™1ÎöL:ÃÌn쪌\Uÿ•׎/ðs5Àfpx.ÓCnÕ‹‰Òôà±ÏÖŠB’æb†ŽNް!$ª=Í2œ¬0~}ƒ·J[Íx¨$B$¹PªÁ<†au÷N/ôdÌeÒu9¸A=\U¹ßú»:è³ÃAîþ!Ÿwh¬ óÖ™Ü ì{þ¢”lA}Ó'’ž$ûÌ;üXy):ùrÄ‘üÖ¦§;æsæOY©¬¼é•{8WØ,<Ÿ¶¨ìÔæ—šjYË–@4çpú"W'Ââïú怠^TW^äÒ"mßt,Í ZxN/+¿Œ)µ2óÓðíŠñåã=äÞ+ïT žño‰îËR÷ò’´e©“©X*ˆ½$Š?v½±Yxl™õgëÄë:É'󛟸Ð;©K ã&¨ØC•w jÏÿ)Ä;¾(>ë÷ÆÖæ›Ùñ÷|þsН¼ê—ãžüPPßTýgä¸>žÛ‰ÒŒt6ÙST‹ª)X/£a©×«BÏ 3Œ¿Ô–Á[¥í+'‚$‘PšÁÃiõÁ{Ê[¾ùêqÆLåKK­C”`'ÓÅuyI"µ4™†S\ZT>=q“5Ë74Üàî‚ÇÇêÍæšr´eð–h+­I](¢‚å©[dr–ÖÕç G;Ö@oCý(ˆfWMqÇúŸ[ËFÌø¬xBHŸNã‹$<:¦fb¡oyµ|Í0C5?OD]ù¦Oœ*}o™7F1Nä$hwÂ-Á" ®f$Ÿ âú¥lã»Æ$R´5°¼$âj„PCyú˜¥ƒK²§wjÙÕ]U#-¿A<„EÓ¼¤ü?D "„84:‰Œ‰©ß»ØRŸw‘ÿõÈö³4Â?ã¬=jê+Òé>.nšg¼¬³ºiÎÎ壙&BhLÔ˜«o»E G ú4?úÛ®Z4xK´}ˆ‚$J-x¢‚'j÷;:&yfœß²›%5RikiÁåØ`O*Ï;4Öð"bHîÊÍ\9ÚÒPWÏdVÌwó.u4RŒgædäEûptÙN>KÚ&Ä*í‡ìû)jX´ÿ8.SÏmÞÎ¤Ð—ÞøiÜ?ÿeΘ•ø ‰›™iy‰ã绳™Ü‰Q2—hzû¸Ý¼cÙ«cü9,/R ÝÛwOÃ<,N$¿ÃÓãšØÅd‰.ÜØ„’Š+#ó§†YqUcÀµ|_87êvŠ1‡kbºéŒ[ÔIM¢BI§6ßXáÁ¢Ó ͬTÇ­ývŸ_ëû± ‡Árösv—¯5y$¸i"„LÆEÈ¥Œ¯ìy!®y˜=ƒ6-ÀZ[o‰¶¯ Q$B©OTð¯<µíœƒ'BM§a³y^Ÿ'ò|’¨<ï= zò£ T~±¼Ó£ ½E[Ó‡#ÂÒÄ®ÞXòý‡aÒ´s¶ý{é{%Í·DÛ·ë ~ôh¬ Óƺ/¾Ñ÷þ")6rª‹½¬®t÷ _Ág9›&›wÕIØÐaÑŬ˜´þ½ô½’æ[¢-4ÖÐXÐX÷ù7Ú´C ÷'ºòÈh¨SðÊ­ñ &Â4Ö@c 5ÐWk€þx ±h¬k ±­B €7™uëÖiÑ  û€k ÏCå§_ Ãz=A©¨tȰž™«óíÉ4_R¥PoB…¼Q€ ¼ÍÀŽ5Ð Ù‰Dý>ý’ã_ŒJÚMÞÊôä¯c¨M§­Ù;M³W´h¬ ÿ[–ñh0‰Aïþ朶fï4Í^ѨGA€þ †a…'Óg¼ï0€Í´y×=þÐ Õ«gòÎŒµ¢38öã§ÿðè¹r¼ð»®Ž6]–­‹ï7»öj´’ŒÐ)‹wþJî¤âÊÞ\õY ¶Á ÏYáú‹§ì|JØH žÅÄy¹MÊÁVá­ÈÙÿ²6Ö§3ؖÜÖüöTuÎú²ÔÿOµÔÕ!±T=–pqïz7Gkƒeåè¾/ÿïÓVº ·`1˜VŽžÙ% jöªrijˆ› Âë@íÞ¼Ìg{ &af7vUF®ªÿÊkÇø¹š `38<—é!·êÅDizðØgkE!Is1CG'GØŠÕžfNV¿¾æ¤Ÿ˜êí´/J“ CWoD“LN²j¸¥O1­Ô°vËÊŒU¹ßú»:è³ÃAîþ!ã€ÆÞ¬Ö™Ü ì{þ¢”lA}Ó'’ž$ûÌ;üXy):ùrÄ‘üÖ¦§;æsæOY©¬¼é•{8WØ,<Ÿ¶¨ìÔæ—šjYË–@4çpú"W'Ââïú怠^TW^äÒ"mïÏJ³‚žÓËÊ/ã_J­Ìü4|{b|ùx¹÷Ê;•†güã["…û²Tç½¼$mYêd*– b/‰â]ol[f½ÀÙ:ñºNòÉüÆæçG#.ôNê’¸ *ö§å¨Úó ñŽ/ŠÏú½±µùfvüýŸÿœâ+¯ú%äx†'?Ô7Uÿ9îçv¢4#MöÕ"„j ÖËhXêõj„г cÇ/µe 9iÔ|»ŒoÛ+äñþ=VÓ¶èé`$«¦ IúãyýÖzùuZu÷ÓüÒýÖÔ‹ê*Š6‡zRŒ 6'¡ªª*Å sssÓêêjÐ èLMM‰.)NWkž±VtÕr¹\qÆšÅbi¨¶} ÿ¯½» ˆ*kã~†™¡¤$ÄBÁ5°ÀBV]AA \Wìì»±kQ×®5ÁØUÄDl‘éfâý€ŽãÄå2 ¼ÿß'æÆ‰çÞsï3—33IA¤ÛLÀËc*êñy%„YÆ „&,m®%YŽ€›³qÑòÎs»é+K6R´ÕV:)ûb·vÖ—l‰§‘ú°™=4”!¼ÒDeíeÏ !”X§R ºks$Kæ•&Z¶XõþÃΊ—²¶V!Úk~y‹cÊç-*IQÍšWžE¤ÍŠ–Z‚ÔÙs¬=Ô î$ùZhV,Ï}·Ò¸çǼ䭒»p‹ß(itá•}–ÚÍäP§^ûç½=fÕÉlÓÀÖ/NLN s¾9Ä|…û0·¦Õ²d¥…wÚÆç&®%„Ì7ÑP¹™`¡IqÔ$#FÑ}:í‘úÖ±ªçpõž~²ˆÖ¸²•vZðË [½JÏ%Yí@b ðkÑ6ùúè”fb-àå±”ŒxÜ|B·øíôßgƤ¦¥¥¥¥gdæ—Ul©Åf¾+.×f)ˆ•Ã+M]6óÀ´- ôØ "©¡ôBô•X1e¢[ [¢Åfæpù¢Ëù|>!äå±%Î^Á&Ýí»tj×ÞÞÍÅÎL¸Íû£ý¼™;.ÿ’{ÉÚRV*#ë%ÄZV)ŠÕ`3?s²_cžËâ˜òÊs¤Õ(`0„KĺYšsS§õÙü”­½´T·ÆÅØ™{dgý;Î@­GT†‡¾Jµl Y)!‚^ lOζ$o´ 'fg߫臬£&1ŠîWÚ±¿H=LtÎáê=ýDɪQO‘[X¦+­FŠöÔW˜ uêà×y½UýÀœ€_Æ`~ɨ¶8öÈê¿vÃîkÿ>IÍú6Ù”OƒH™^2ÛcIƒòËÛ.~÷_lY…ð* Òç¨p$«œ/œDQ‘ÖBZº/{þö’S'Ó¤èÛsÙøþõ\¸ËšÅï÷¸˜ _RlYídu°’·é„æqù.DbÝTÒìm[z4%ýì#Îp+ؤ`Á IDAT­¦Þ1çÓÞ‡äéÿ®§R]HVJcÙ`#߈ôôû¾Æ#Ö~Meµ*u¿Òö¾'÷9\½§ó¡˜/à(0ª:êm¢BðÄ~6úSA$³jšO¬?=ÓâwÏ/BÔYÌÄ®‹!¶ådCu£;IKšiŠ•_Â5U¬f“âtdóhëŠå² ñh¤ÖùiÚTC5É–Œm¤Öèzª¶Ú¡(/ˆRnèÈ-Ë „ä'm³žiwz`¥[Võ‰uC6óI~YSr•ðY$„¨0²¹|%†ø¾^FêZ¡‰Ë[~™K“óz™IŸÌ¼ä BùŒ\j7ÿv49å wÿÕ–Wv{¶ªã%³¸}½3_L­® ¤Vš·´•G‹dÖç7Ó¾AYGM2bݧÓ`©o#«zWãé'FVã ÔÚ=Jón¬FÉöÔWxb u Åó/3>rÝt'áö ƒÜÖ;Ž ‹MåòËâžÞ˜îܺb¹©“0XsG(p¿=œºe;Ǻ.ŠLÌðÊŸß]éõm•ÏÚß‚G\ŽJ,ç–&<»½hDûŠå}ƾzÿS~ ¿¬àᥣê¦#*–ß™µqÎæž¢=’µeUù¶ÓñXy:«˜Ë-ÎyzóÄ´Á%·‘ÕABÈp]•yçb¸ÇaþΑ›ûþ~%*Ëç&D]ÕwÝÈs+mŒd7 !Öó­ùFÚÏjNiê1êÉÂ3æãíªq©•j4Y¬ÿji`|×i"‰©¬£&‰ºû•6¸ZÎáj<ýÈ÷TdÕè³Áe™óœGq™<^釨[~ãè´‰5ÀOS"Å^w÷-hm¤©¨ª;Üçø˜è™mV,ß¶'|áEe›ÓË;û ·oâ|a~³…®Ô”TíGªt›&Zƒ©¶êÚcƾAÃW_§(ÄÔ%(|u‡Õcz*+©uq›Ï·]¨ÀúòÜbtÈéEm|\;ªp4úLÚ¨ÙóËÓJÏ>†gWk¬¥ª¦kásªäÆÃu„^YÊì'}=ÕDÛ uK9xݸÒ*r£…¶Šš®ù´uÛÏ?'¹¬BÖ^\ÿp^‹¥©o,ºÜÄy÷U¿¡¶*lNGWŸÖ>—w9™P·Dj7 !ºf xìÅ–Z„5OK6³¿›Ium «RÂ`ûYæ°Çù|÷fFÆQ“DÝýJ\-çpu~ôÏó‘¦ëÝßZYYËqâj­ké´ ¾ÂTøù¨§‚ÐùÅòJ§‚ü,å…Ït­Žæ|X]ÕãNþæÉ º2¼~úŸÒMŠJ‡ê©º¿ÌtÕV®Wç>‡å>ýjIûê<±†Z- €CC­jsó~“Îß{UÄå|zä9bâr²aÁ›=.fõþøþ”nʪ´øÓ±«ì?jIVýsO?@b P+x޲»à?D‹ÃiÖÍ=Ënÿºr²=î­±³ÞÇê§tSV¥oölhë3§È SAà磘 PWà‰5k$Öõ‹þ¦˜ žXTƒ*<±ŽŽŽF¼ ®³¶¶®‰bñĉ5k$րĉ5ÀÏÆÆÆÆÆ]$Ö5ˆ…Hªx‚%\"ú7º’ðÄ à‰5Ô[G®†‘÷—®ÞŽKÍQl Óª½ÇŒ]U…ðK?†ìÝ{ùöƒ÷IéN8áXøGTT”؃ÞÒ¬˜]›ö†ÞNË*TÖjÔ¶sŸ ³¦ÚèpDw¼íÐÁ}‡®Þ~”š]Ò°‰•Ǭî]Ñl<Ÿ›}rgÐùÐûïS2ˆRƒÖzõîd:Ê}Ì×–§Ûµãï›q3lõ&-: ›4ÏÕ¶Qè@}…'ÖPomô|’¯¿hÛÑ{î_8¶Õ¾áso·!¡iEky¥¼ Yÿ×CçÙnÞ{póü~½„„ {v‹¦˜Q_‰•\–ÿô§qGï–.Úy"âqÄñm ÊîŸàäþ8·Lt³3ÿ|ì=fñ©k·î„ŸÔ±`·ÛÅ”Bš??Ó}Õþ³Æ#–ÜŽxpéXP·F‡¶mÿÚò„郇?Sž³áÐ݈Ç7Ïú­qüò©N»gÖ‰®ÔW BHjjjÅ ŠM£££/¨»øÜ¬û(¸Ü»¼„îç<íb¢ýšKA¿6–ÜXr"²è’°éýçüóqÈ_a~m´+ÖfF8xœ3°[e«ƒÔÝË Ÿvì6N£É„;g½è´¶G‡_r¹ü°ÇOµYâO@,<ùlü{lTÙÂT»½í ŽfŸˆÛj×~:kkëš(SA Þ*ýüöïK×?{™˜’–™ù9/?Ÿ/¦ž!d !dÇÍ„iöòL`Øÿ$“2ÚRS¸D«…!ç2ŸþIˆƒÔ]Ø*m!yñÁ„ÐÊ> ™¹\¾³óˆ®ímš7oaÛñ±ZŪ=7R !cºuïoî­Š?jy×ê+$ÖP?}¼½mÄÜ? ÙÆ.£\=µ056j¤¯gßµ“pƒ×Å\Bˆ¥²<—Á÷ÅÜŠÜW¸„©Ø˜Â+Ž“¹ƒMx4«X9ßyø²3…©on¤¾¹q‘l߸zТ£C-!Ï‹Ê !wžDj0R÷­å]¨¯0Çê§Å¾‡r¹|ÿ3G}<=úÚÛZ6iÜ@EQtƒ¦!$±TžtÐ\™EùXöm_~Y!„©Ü´ºÚßd°_ع‹§OØ·‡¹ž²€_viÃüŠU Ù „§e²ö­å]@b P—Ä•p !ú*²6˜ÚY²ûi¦ÔµúŠLBH!_ uíøö:„Ãïs…KrÞþEÑùe\5vAÝÄzØ8¯Àu[N^þ›Â/ÿÒÔá†j„á©bÛgF߬+]@b PgÌïiHY°ÿzVQ™€_–üêÁÆyî¢t_±¡½ŽrèÏsoJyüÒ¼Œ}^žî=m+ÖŽ6× „l¾ù–/­p»ªì ^‹ï½Iãñy©/ÿ]ä}­b¸Â¾ºÚßc¨çÊM'2 ù|î›Ûû!Z­&U¬rY3QUA!rÍä½ïg”òË‹’^DìZæÙoìœ:Ñ5€ú ß õ“€—"hõÑËÿ&eæ Cðۉ³÷L "ßhÁ+I9¾{ïåÛqÉ\¶zÛ®}{Úü1jZÊ—³J!Ü¢—l…°œRBHIÖ%ŽfÉsX2’U=-+Rj+÷ufCV¥'JécȺØþí!v¾q]кF¯ u=LL_5Äl»ôZjdª:(JsžÎvÿÕD[ÅV6jf³ä^:.ÝH¬þ£YnÎ+ü7¼IË+Ìx=»Ã«Û+–g¿Øfå¼ÍÙÿpZ^IvrìúirBÍïfÉŠE9!sLÆw4Yý@aù'E¹ÇféLè·V¸Ù ·f}RZ˜¾cŒÊ˜Þ ~¤Òª•órG[×]ƒ–JË+ÉNŠ^æa[Ì£õ´RjE¥}8å1áŠê©' ‰77¥ìå½=Jj±Â8ÿù kÇQ{î¤ûôÙù$“’ÿáÔ߬;;GÊ*äÇU¥³¥¿؈eGRóJ¹eEÔ}÷<™8uãé´¼ÂÇgׯo0úÈ{šMM¹1Ûn~¸ß‘»9E9Wƒ¦&\\O?ȳ;êîÍ"„dF-å3›dB>GïÑn3£ÒÃQ¥Ó²"¥¶½ÙÒ}Cú»p¿ Tb£›Á`,ý¿ÓFŸÅbnNÉ_i¡UCÓ¸+­‹¡ :`‚_ø»ô î–›G[S§×R#SÕA1·SA¿ÏRrò?'žØ<;'ø.øu&9!„¤¦¦V¼000 Ø4##ñ‚š §§'kUÅìjÉ9Ö·=@P1ÇšÃáTšvWÜä„ÓÅæAr‹ß(itá•}&„¬l¥ü2ÈVO´4©yE!’»H­š_žÁâ˜òyÅ/y¥IŠjÖ¼ò,ñÆóò˜Šz|^ u¥ÔÍ«RQ«­tRöÅní¬OÝ~šQ”æi¤>ìEf %B¯4QY{@YÁsY h-;–æ†w±˜°øöž=ƒü×E]µVcWz(¥dHô%÷ÙBѱ-ó“‚ :>.H;D'Ô³Œ4MXÚ\‹NEb’CzíŸ÷ö˜ýU'³M[¿819)Ìùæóî7ÂÜšÊ9ÖôOËñý­/&é-òõónÏ’*§Ütí°Øåcĉ—vÛ8>)Ô¥æ.AU¨KÀý'dëòÀ•ÆÎÑWöÓ9Qå”X§R ºkspw¨sðáE¨;ïE;Bcºg•惲”›ñ¿¦³›ßåÆþ¢#Ïp)„&¶ž€ÿíó—L%c>7ûkjòvúï3cRÓÒÒÒÒ32ü2¹+•£¨MosbÚëV5²*¢(íhFÑMÅ;"Y(vTÒèzíò„&¿ Úñì½hV-wûkâl¡ßw5Ã1Å™>4›z ­ð¹†|év˜•æq’û5w?m=´Õn‘!·ÃÓGïhTc[^Îæp8Ž塾ðÀvÙBÈ­¥»mØ[£×–*ÔÅPàp8Ž"—Ë­¹AqëÀbgËf&Ýí»tj×ÞÞÍÅÎ ×$Ö5’[Ë‘4Ó,[øW1_PÉ=ŸF!?n‹cœiçÖš(è›4ÖÓÕQWfË]©Eð*U‚¬Š(Jã HV9_‹U庨wT`sÅiYe5ó8[èö]À/c0Uh6•OCâ” Y‘’foÛÒ¡)é½q†[i5õÖˆ9Ÿö>$OžJ5Ž…ƒ¡/>Ü;0ÖIãž¾^CíÄÚ%æ š°ðù|;Úùèdêpÿ=±-0peŠÁÿ-÷†v3«¹AÑÒ}Ùó_‡ìÜ}û؆À'[îþa…ë?@ÝHT¦‚ÀÏF*ˆä³jŠ© Ôÿާ˜Ï0Î@­Ý£4ïÆjôK“\ÒÍ|’_քì´jY/ÕYÌÄ®0ªêLŒ,Ê£‘Zç§iS ÕªÔ5YQ”6¶‘Z£ë «ÚjWzž¨0²¹|¥¯©ÅŽeyzYûl¼9׻˂M¯"ºi*É*DŒú‘³EVĶüôtN‹ßu>¿\D'Ô“ Õî$-i¦I§"I;šœrлÿjË«?»=[Õq‚’Yܾޙ/¦J6L,’ôOK¡øðSuøøÎøÝ#ò‘ŸÜ÷¾í÷}Ò#3zŠ…K£œ¸€š»þT^¿$ôð–Àk>› ò÷÷wëjV¥UŽA!ª¼ J¹¡#· ÷_€º^„º„â3gÕÈgƒË2ç9â2y¼ÒQ·üÆ9ÈQˆo;•§³Š¹Ü✧7OLܱª%86䬿]ÆçeÆG®›îô#=’£¨e;Ǻ.ŠLÌðÊŸß]éåD§k²*¢(ÍgíoAŽ#.G%–sKžÝ^4¢½¬& ×U™w.†+¨dG/fŸIsnŸ¶mâxýöœ‰=¼rE>v)VÈêGÎо»öðsa¿¼(æÖ—~üNL¦ÙÔ…AnëDžŦrùeqOoLwn]¥ [Ï·>äi?«9!¤©Ç¨' Ϙ·£s8ä`ÖÕíÀõç‘ÁÞ¯ÏÒ7ï*ºêùšÓ-&™B"—ßh=Dåˆ ú/ÅTZWs½ÙG_{ˆŒ¹\iV-9…EŸ±‡¯Þÿ”_Â/+xx騺é\üXBÿÿ5¬úúúµª=Ü’w³Üzš564njY£Ô30ª‰ö—ÈVÕ™üëì4]ïþÖÊÊZŽWk X+G!^7®´ŠÜh¡­¢¦k>mÝßöó«üÛûÂö„/ ¢¨l3`zyg¿é‘E™º…¯î°zLOe%µ.nóù¶ Xš•vMVE¥YŒ9½¨kGŽFŸI5{N•Õ¤µ×?œ×‡ÃbiêSìxtj/£µ—]MÕ !š-F…n4ëóõëö$ ùñ@ýÈÙBÑ÷»û´6ÒTTÕîs|LHôÌ6 i6µ‰[ð…ùͺvPSRµ¨ÒmZ•‚¬Ûa–€Ç^l©EQ3ð´d3û»™Ð9r3í2$øZḺ¹¢ ×IÕV›š2o¨Y^+­kÞ±çÏ®þ9¤‹)ÍÅ"#Ç ðìcxvõ¸ÆZªjº>§Jn<\‡d ®¨©© ¹6u–7™}”uäÑÌ& äËMÓÓëê—wÖ¶Æ_×1¸Ãêý{©²„m«ÆFª Y¾}wiuÝÆæŸ’ß3ÃxÞ˽¸„n:N9„Î/–KNêU^øL×êh·յ°´zx]ÆO÷aˆ@ÝTSO¬ï,:ÔmÅø‘+{Z|›~2*ú²&Ó|F[ÛžCÓ·ñNzÐÄ^ªl… lÉ„æ zõR¾›J”˜ÿìmh?‰7vxµ”À¡#¹&4ï7éü½WE\~Á§÷Až#&˜Q{JÀ€ÿ—ÄšWš°è!s}/ÃFÝ×°.N,å!Ð?Wl©º»§ýp]ýsF©ªp ¼"­‘Kø6GØë:ÏQvü‡hq8ͺ¹gÙí_×àö”€!ÿ/‰uÂù9jkuØ ,­µ}Õæ\H]û9ê¼—{ÿVæ&Í,ûcæÞ#ÇÈׇÁú_‘ï'ÿsØÃ©‡…Ic#‹NGî¦Wéëë§>8íå> ES#SË~£æ>Ë/—Ú*É*¨K¦³{ôÞYÚ67200kfå|»í¸U/âÞÅ„û{t‰:±ž|Ÿþ•hi™O·ô˜p¨÷ÆÇ¯?Ä¿~¼Ñ«Wð¸AQß~Ðk̶ˆ>SVFľ>µ]œ»›ô_Ã’¬¢Ò’©w'„,¸Á_°5äUBòë§7ÇÛ$v–øÜ¿t§WÿXëU»½{~éNäæ&®9ö*>éÉõà†3ö¾Í‘ZcÍu\¼"ÙMòûÕí8÷γwq¯ž®šè˜~HjÊ»bónß,îj@ø¥üî³îìaí?†ÑÿWªÿË©ûÚö½Q¸dF›&m®ÅL0T#„¬ëÒ<ç½e6R~¨Lì³t—+:6+ß`óíX3£–t™Èyûh±ä^Ü’8c‹þ“_Km›ØÆÔ%Wº»/Ï ±UÚÇDá–^ÁƉƒÊ\v/r²n¶ªS³öמ;j) ܺÏñ×÷¤ÔXC—üð"E“¬þù<¾“¦"ÍóIÏÀ(ãcJUÏBŠ/ÔÕÿË‹÷ýöt\"ºd†ï/#üîOØß—²/)ïUÃ*x0µàá÷»4´šUð±3!R’Q§ ¿<§&J––Iî_2ûê‹´ÜìÏ™Ÿ?çää øß~ä–_þy™»CÉä «û_iáæß}}ƒÁ’ZcÍu\¢"™M:½ÉsD‡Žf»vî`Õ²cçnM©‹’#«@b-¿<}Þõä—:ëOûn9Sñ}FùS=¶Bů˜U½`í½5V²¸ã“ûõ›5ª»¾EScm-- ML¾}‹ó’±3 Þ·d‘‹Í>[Ýo_[Á^&lH÷£„5×qB§I͇úÜï1àб«±±÷Ïì\sgÞù ÚaØHªæ9Ö)7æ ~Ù”.aWÆÜÐBÈj›_dIÝ—£À(“ö‰Cµõ1ßí’³AÍÐCŽæ‰UQÕ’Åv÷»’0eÈðÁý{Z577Ðk¨¢ôÝ»”q{xŽñ¿¼Þ~šýÀ3Ï¿=K¡§²æÉ':­­ÆŽS£nG¯Ý¤‹¶ì9|7òÚÑü€tÕüÄzï}—#A’ËíW =bé¿|êîi]†j¾sµS7+¥òÜèûaw¬Ûzæ!!d°¶rÀ•—Ë´d~¿ïäÝ^¶Ã†[l[;ؾ­£èÙ?çx÷>ñ@Žæ‰UQÕ’Åvï§«¼$äÞ¢Á¶ªŒÒ/œ Þ)ºqSe!Ä Û¤ÐN.=·›ùkBˆ×Öq¶#‡ZîØ8¤§ /?öÑ¿v¯ßxì®duÕØqjMêú΍jÉb»¯½| ÿÔ’v&f–6“—6tZ*u/­6ïÜX{ezŸY{ïBu÷¹½wìís;57kÚº³ðÖ§Iݱ;N¢IãzÝØ5§m3Ó&-mÏŸ¸ê_ Ob:?Íøã ®õ[:ÄøB¾ÚK“£Yí;ÖÅë®™ðÿyzÔÔOšÐGý“æ„òtII ‘ö“惖Á`pÔõ:ö²éÀ¦_4ð*ð»pÒƒ³Æ¶.âýý|N³éÚâÜð¢´ÝºVWŠ2ÏÕ\(ê:û ÉÅÖ¸6GNKÄZE¿‘ ƒ£å™y]UAxoà6Òø+µ ¢©÷ aánî_°b×­GϳKH#³Vv·1›0f,µ„œ×惹^‚ ÒoW·{§Í»öçš §żÍÊ/7µé3~˜anÎ:J•¶Šâx•fE lã :åä9¿þåìri’4çþŠîD—§ßóí²É$îÔ$¹cøãq+ŠÁ`˜Üq¢ì.S…±RmuÛ>ûôLŽ““bǺø+÷²ÚüŸõ¥.­æºYÛÂ^ލ§ŸÏËŒ2»wü¯ö«êPË“œßߺ啒«âO®3r\Æ äÝþ½¦®ój´u­ÒÒºÿø³’êâYQ-嘗Ýyì½ðåǽŽçšŠU$¦bù‹?'9ïù0}Ë©¤Ï……ÙéÿœÙÙ¿%çÂ?:k+„ŒÛî¶oÊ”}C‚Ç~ÿ½òüßßZxŸM›¾þè‡Ù…¹ÉG– ‹ ö¶ÔW¯´U”ï¯Âû·vh8ãBEVMQÎÄc¡á¿ÿž\öí§vùe©£G?¹}d¼1¬(³Zâ&V!dü'?ÿŠh„‘š‰º‰|'•Ü;þŽA@<‘Xü„7ó*ZFNS‚³b׋­¸ºÑ³¥¡–a—Ñw“ EßCGŸÛ6¨»Ue%Ó¶=W~(µÐ¿ÃÿvkoÌb«Xvxæm®pyôñUvmLU9æ¶Nkví§¨ˆ:¥¶r_g6dUz¢”ÚCÖÅðoG9°óë‚Ö5;Šº&¦¯b¶ÎÝŠNz-üïAê&ßÞ?Ø®:‡­¬ÑÈa¸· ëË5ª4çél÷_M´ÕYle£f6KîIÿFù>ZÊ—³J!Ü¢—l…°œRBHIÖ%ŽfÑÆÈjUÊýãít(³U´lN~šW&«SÇ–Ú^ó›Ë«¸¥ñ}Fî¼ü8¨þæöײîV¦¶‚’jƒ¦V†O^táa2µ„Òœ°y/[líÚÈ ëVË8¿‹Yß~íõÅŽûóF½¼ôk§ª–’ªNç'îØ4Zþó¤øÓ¿ýZ96^x5d~ïJ7frÌCNôé7í‚pÉå™NN玘(1<†?71óþ>°oðèL._r0Rÿz;A`ÚIDAT»ÆkwÏ´Þ^;ÿ¥¸Â ÓSÝ›öåeaÚEÕ…|ýq$k„2 Š1’z÷ «•:‡­¢Ù¨§ëdê uií”uéÎ~~i‚S7m5%–¢Š¬.ÖŒÐýKíÛ˜pØã6=ƒŸ|<´À¶¹!‡­dÜÆát\>u²ZHÑòª^ôhÞ>èÄSj4Â÷ùt´4Tb±õ-Ú/Ús—⌓zk“u†Ð¿Ú Q´„"8H¬~^i"[íÑ%NyL¸¢zêIBâÍM)ûFyo®ò<™8uãé´¼ÂÇgׯo0úÈ{Én¸5ëè“ÒÂôcTÆô^ð%'»1Ûn~¸ß‘»9E9Wƒ¦&\\O]‘Ô”ÚzôfK÷ éïÂý& ù9^ª–~Èßi£Ïb17§ä¯´Ðª¡ij•ÖÅPP0Á/ü]úwËÍ£­©ÓkáóBÑG¤Rc˜órG[×]ƒ–JË+ÉNŠ^æa[ü%ë"s;õô[ð,%'ÿsâ‰Í³s‚OI­kvGݽ±Y„̨¥|&cÓƒ BÈçè=ÚmfÐi•óÊ0ï oÒò 3^Ïîðj€ÃvYj=ýd3îƒáÁo!é᳎d79åÕŠNl-”Y§ñåZKyà3ÝÊg«"ƒÎö…­çÍ ®Z¿"böáYâ9¬‚òŒàH9³êŒ;¿Z °;4£;Í]ôl¯V^¾ñY!$ûå¶ z›½Ú4¬–þ`ÜÄp´ûõ*èçóäªãŽèòœÎŽ~ñæÉ#ÈÈ#Û¦ÚQ\aæ±Øsð˵ëý½Æý7W\OhŽ#Y#”bŒd¿Øfå¼ÍÙÿpZ^Ivrìúitº,«4Yí¤¸¢ö÷±ìHj^)·¬HÖãw³dEȃ‚¢œ9&ã;š¬~ °áÜ“‚¢Üc³t&ô[K]£¬RD¸ª=ú·Jã)Ä “û­ˆ]q*¢ ´èÑé/V˜r1Qj™Rom²ºCÿj/DÑŠàÔêçys¬ág«¡9Ö€þçÄØ­3'»\Ý7ºÙ·ìÙH}Ø‹ÌJi·²ö€²‚çDbÖW~RAÇÇi‡ˆŒ a^SQÏ+!„Ì2nÐ 4aióï>¼+«"1ãû[_LÒ[äëç=Üž%;UN¹éÚa±ËLj?/ì¶q|R¨KÍ”*Ô%àþ²uyàÊ cçè+ûeeê²îm¢1\m¥“²/vkg}É)±N¥t׿P7;9Ô©×þyoÙ_u2Û4°õ‹““œo1_á~#Ì­)©Êknñ%.¼²Ï²ºó|söKŠR?G,¶høfnø-ïÖÂ(f3§ÝÙhï¼(Yɰ‡Ã—ßzi HÇ-õ¾ô‹z-¿,ÍR»í¥ŒÔÊ,B·(F_o`Ôç8c%&!DƒÍüPÌm(ûªÒ뢴›­¨øÝ¹1£S•Êp³þè4mËýÝ ·][§Ä §E ÅŽÈÄMêqðò]Œ›º?Šn¤*ºA¥aü9·êŠ6ss6.ZÞyn`7}eê+Ládž¶ñ¹‰k !óM4Tn&XhÒG²F(ÅYÙJ;-øe­^¥£^t˜È*MV;i^º+½ìˆ­å—g°8¦|^ñ×g1IŠjÖ¼ò,ŠeµN„i^ôhÞ>èÄSr­§‘ºÁ$_‹/Ÿ—Í}·Ò¸çǼ䭒åK½µÉêý«½h7eµ„"8H¬~Bb-üÛviXÄ’ïþ‘­Åfæˆü˜Á`ðù|ÉA+àå±”ŒxÜ|ÑUÜâ·ÓŸ“š––––ž‘™_\V±\‹Í|W\®ýý?ªdU$ÆÃ¡Uh޹¯¯ßäÁ(þ‹tÂÞè¨oÄ9Gヶ®lˆ<ÞÝ æJUêâ?<·{y``œ–CìƒtkY1ÔWbÅ”é‰üV‘pÇ—Ç–8{›t·ïÒ©]{{7;3©•æÜÔi}6?ek/-Õ­q1væÙYÿŽ3Pë•ᡯBªöáEƒ¡@‘ðË3l´+Œé÷ò`JJÖ#¶‚¬;œx¼Ê2ï\¹ö 2æõë7/bž<~ç¹÷~И•®}{¨ŸãÙÉÎ~{“sò7Ó]®×ÃÆ7¯Èß•ëžè Ó*±v7²êûGÓ !Ì'/NZp˜ôóBH^ÜÁVc–<ûºìô¢ÒJV$wÜd÷ÌÈ•ÍOËxÄü>±¦ãÏJ¬y¥©Ëf˜¶eè‘}…ôjØ`{r¶%y£e81;û^Å;šãHÖ¥#zЬØÂ2]iƒ—f"(Zš¬vÒ¼tW5±¦x)«FY-”µ\Ž‹ÍÛxJ®{)àå²8¦U·pºu ¸ÿžØ¸2Å`€¿ÀÐnf4ïa²b¨Êb¦—rÕ˜ ©;–fEïÜýìnè]÷-wÿ°’Z—ƒŽöÁØ}Ím.|üsIÍö÷ŸŒ4wÌ-x_Ò*}+H¥™Aì–žV3ïôÙñ"tjKÊ;•„[«›9–ú,êûµ|]µs™Åb(kÌϼÈ$dt#5Ó;IË%,ÉÑ*ƒò*gXs{[ǹTŠØ®ÃªÚ½­Òm*a¥…ÐŽÕqviò÷ k§ÆX VÆŸ•XÏ1ÁDíUNÿ?—¹6£s…ùw\‹M£Â¶ ¼ûžœóbW·oo>iŒ#Y#”bŒ¨³˜©¥\uƒ—æ Yéx§yé®ÆÄš"²")u¹=š·šñ[«ÉfÆ—7ü:®)k©·6YÝ¡µnFÑê;k€Ÿ“XB’¯vžõöIT°ð)ÔØFj®'¬ÿª2ñAûé霿ë|~¹ˆâb'\>ÙPÝèNÒ’fß}­¬Šd‰?p!QgïŒß8"Ïrßû¶_Ü÷]HÌè).râjîˆT^¿$ôð–Àk>› ò÷÷wëjF]  S!›ËÎ CFjŸ¦M5T£¾Œ–D)7tä–I¿"ýíhrÊAïþ«-¯þìölUÇ Jfqûzg¾˜*Y X«äH¬ùå+w{ùøTÜ褰§ìügÇTe‘#Ë+KVÖr(+|E½63rŽ…›BÎûubúXj{³©½î‹­½í÷¶Ž ½ÉX ·Œ:0}艆1—„gcõ&Ö²b(ö·Üq£Î0Ê £­Œ‡OŒýE]±ba¥aüY‰u| ×TQ°n˜MŠÓ‘Í£­+½ÂäÆ-måÑb#™õ9äÍ4‘1EgÉ¡cdœZ»GiÞÕª+±–ÚNš—n©\¾ÄšÎ5\V$E—ËqÑ£yû O±hx©k…&.oùå dÎëe&}2ó’¥üÀŸÔ[›¬îÐ¿Ú ÿ h Í;Bmƒ/BýרÑ÷–¿N×A+Ë¿ŽGŸµ¿9ޏ•XÎ-Mxv{шöÂ]{ø¹°Œ_^sëˆK¿~'Ä?ÛîØ³þrtŸ—¹nº“pù ·õŽãÂbS¹ü²¸§7¦;·¦®H*³®n®? ö~ux–¾yWÑUÏלn1Éœ¹üFëù•ÿ¶¼ØDXê—b*­«‹¹Þ죯½DÆ\ ®4«&„ ×U™w.†+¨$†ËvŽ t]™˜-à•%>¿»ÒëÛ*‹>c_½ÿ)¿„_VððÒQuS™°žo}È7Ò~VsBHSQOž1oG§Uò\@ÙzKüýVåƒê;úüÚÓm×é[iy%niBì=ß½~[}²ÒµûǸk†dÓv9·ŸÒÒóâXís]Üÿº‘‘[ÄçssÒnŸ?øƒÃÇfLÐ¥qå=Æïâ×Ìð¤C¹ãF­j}qƒÕ`÷`á:a¬Ò‡†d$Š2Ubkîñ¥Nã·‡Wz)Óh²XÿÕÒÀø®¢Y5Íq$k„RðÙà²ÌyΣ¸L¯ôCÔ-¿q?rVÈjg•®¨?>À)j”ÕBYËå¸èUõöQ¥‹ðü#7÷ýýJT—ÏMˆº2ªïº‘;çJÝQê­â ¡yµ¢h Epj»Ô¯”ÒjÅYçïïïïï_\©ßª+¶äÉ®±¦‡_^Ù<˦‰‹©dnë´zç^á^ÓÜzêk(3Ù*-» Ü{3I²À¬g‡{¶4`2ÙF-»¯8ò@´¢[;æw°4Pb±ŒZÛ/X½¢":îŸ}9H[ùXF‘@ °×P:›Y\éîb ~)¦ÒºNßOTEÆÃ¶æºL¦†^cêÆß:0¬W[%&Û°y—å‡î*°4+–o\±ØµG E¦‚rýC¼e•Ȫ«$;Œ¡ ô¡„+üò*lÿø\©k•dLdE©ÒåR¯´ÂÍŠ3{ê¢Áa2•Ô›wpXþç-ÑB¤®-Ê8ÉQÿ%ŸË—¬”Ï+øE]éDF‘@ ðKÏíðï×ÍZ» “©¤gÚÊéïïÓiu㯬´èýr¨O°*ÅðGâ&µ(ñªùåS,5¿[HF:½«®‘(u3^Yúxa«®Uz…9ÓÕ Ý’§¢KhŽ#Y#”ú@ÿ»×ÇÖÒÍV¶èà¸áä:‡XÖ*ŠvʺtWzÙ‘û¸H­QV e-—ã¢GóöAóèHFãîžEí-ôÙ LÝ&íæïú‡âô“¼µQt‡æÕ^tŠ–P§ÖÂT¨íSAèüb¹äT¹ÿߊ/Û¯=Ê ŸéZÍù°¡ÃP=U÷—™®ÚÊ.zÎSA V àЀ@ÕÍûM:ïU—_ðé}爉f &r(þtì*ûdÕ¸è!8H¬àÿ—ç(» þC´8œfÝܳìö¯ëa€˜ÈáÍž m}¢á¢‡àü×0~>Š© užX ±@b Po°èoЉ°²à‰5k$Öõ«ª;””” jòÁÔcxbýY½z5‚P±äÛ-;;±£o÷îÝ@ý†'ÖH¬X ±þ™²^„.žò»­MkScÓVÖ¶#§,ºñ"KtCCC±]òã¯õki1kÏ]r@bM!ïÎ,ïâì§ÒqØá+ÿ¾‹wïúÑ‘,Ôuù™w²vùu¬Ÿã¼¾ë¯nšÔ‡j«n5·$óÊÀ¹g6Ýüg€™zÅ-}ócõìÓ¡GO§ö‘ýuÄ¿+:ùÖv§©!óßtÿEÇjH{b±p™™ç!aV-¤fÜ÷ ·Ù²…bË_žYÞoέÍaWUëoö†§Mò°ºÊâIiá{E—„ï9lGÚÉŽõ0RÅ‘$Öß<Ì/ï­)ý‡Á5z•ç?¾¼¼wü¸`Å›W¶¶Tcã0kºß¿tüç—bhphŽ1 ±g«®x+·DêªÒÜ[Šê¶Â—,NÓ­WOÅ­¼üÜf@bý Ýôw”þµzïïÕï6At ‹ÓtÛµ3É\}BžãHëo:¯Z¿mô•ø|±å…É7F}X²ª³Ør–²ùöëg?m6çÀl@býG§ÿ¥õ.³úþøç…÷é9å|nnú‡¿®é×Û{к‹’_bMa)7Ûqã|Þžß=wßÇñ$Ö_X¸.¹wniáÃã#»Z˜šwv~ø~ö’³÷–¸ZÈÚ…¥ÜlgØ…’ƒc'l¹…C5U­Ýºïª]})6HMM•È­-÷‡¿Âñ€¢€ ±@b €Ä„äüðâîÝ»;!yžX¯^½Å "_Ng``€ˆÈs¬X ±@b H¬X ±@bMa*ý?Ä…Á`àä€H¬»")…„ÂR!„äPÒuò`€*&Ö^–¤ugò,‹°UIä_¤µñƒðT¨ÊOšÏlCö~aÉ¡dsúC àüšh?±YHö’KwS‘\ÞHö:‘c±Ô‰iIÆ£¹#ûê5à°”T+} Ÿ9¢oã†jLǤu·¥=Ý¥¼àÕòiC›6Tâh šü)-J•Å–&µ YËQu çðFÚJMç9¦Ä‡ãÌ€šI¬7ŘhÒ»1á“^Þ$öÙ~z¾ÃƒºLÛš˜]Ì--$„”æÞµk7ÅhÐÂÇñŸÊ‹³®îžqkvÏY¡)s‹_ÿÖÒþ“å°ëÏK ?ý9»ûƒ·‹x|ùzUÕªû5ïžÚÔõjtBIQæ¡y½bÆàÌ€*©ÊT L6á•W^.ƒQÀã«*|{|nP“3^ÿêÛX¸$3r®¹ 37~ !$l| ÿGïÎûE¬ŠùR'fˆ.û»JUßšÔÒ§é¡ð…eP‰5Ír%Ó ”Nf5á0…Køå™Šª­¸e„®œõIy](VKb]¥ª»krÖ$æu“Q5@íJ¬™ å|)©jÅfŠL…".ŸÅ 5‘XÿHÕtüw¿¼ØŒÃúXÆH¨Xk¦Äz_Â¥HÓ¹‚šªÚT‰ùAvÕµ+±öíª?ëB‚¬µsZk-»›öý²oŸ\´×PŒÈ/ûn¥ ´ºªžÕBkED†¬ªjWbírðå$»ÛÏ|HÏåñ˳ÒÞ] Ù5²§yÅZ÷•ׇ :ö¬˜Ë/ÊI½uf÷ÐÎ&Â}w®ê?vÊæ÷ù÷SbìÉ]Ëû¶m[]U<¾ì¢›Ëá[1Å\AQÎÇ[gv¹ui†3jibÍiØ;âÕ9vÔá~í-8lNãæ]ýv_5uð®XÛ éøè ž§|†é¨(j·¿ý¦ƒïeá¾-§œÝÔ>ypÇ&l&Dz³Ë‰²úFTuU­i9%êäø£ †h+³uÍ~ 89zçœP%5õáÅêi>Au„B€Ä‰ue0X ±$ÖH¬X ±$ÖH¬X ±$ÖH¬Xk€êó?Nܘ&VH»‚IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/i18n-2.png0000644000175000017500000006305510027550273022722 0ustar frankiefrankie‰PNG  IHDR²1§°á pHYs × °h”ftIMEÔ oNõü IDATxÚìg\TG‡Ïv–*½X°  Ænì½E1v]cï]£‰[T,DE_{ï% ‰Š=н£ˆ ¢ Ò;laÛ¼–eËÝB èy~|Ø;wæÌ9sgþwîÜ… ...€ ‚ È· ]€ ‚ ÊAA*¹,à¿ú*ëú:0ÁcÇÉ™¯ÿú ªøÊ Ãæ#H•SºŸ9wq°Ûí‘‹sN/Œð½@á£Ü¥ ëqè`· ÿ{Ì/•(èÍIÁ„訞bBó ‡F£Qg¨Ñh`Y_oªUèµÇäšPr™¦ÊÇ“a[}”Zº,?ö÷‰}=¬ –S–ÉKÍ£B_ŠÍ—KÓ»Ûqu•‰¢îÞÔ†Ë6·qî4`êÓ\±áyt)—¤®×ÃÅÚœcQ¥í ¹ï…Rœä²’é¯?%l¸*&Ê"áoZŸôòu.õ‰§¾Ì7Üš«Ãå´hòǽ©'>ÏÙ:¨!óÕ¯+>«•#’RiyYÔõcoëàkEù¼-Þ¡—ÕÛ 4eJZècÇÞÍŒu 5ÿ.Žþ~­×ãÅoJ¥4½†Qg0!:ª§”¢[L [*/Ï*!eT‹ %—aàÛoÕ¼sQ1ÕÒÿ׳uj»Ù?$Keù1ÏB{0÷¶žÿo9ØSvÍ'²Üµƒ›_ÉéÊðbåÀ­—Îæ$G­ »ü¥iyT Ðæu«Åï’søiQ3½Ÿvì¹ '9Ä !ºäðiÛá5ÁYÊ”´›¬Mä ø*üòqÛˆ#ãjoì±ib›Ã§C2•'*?Dì¿1·éÖ!nƒ=O^ÉÒ¬eTÕ iÑW© uhÍ}ªå r PþB‘ßY÷÷TïÀa^Û×.yš/Ób¹â:/Ÿºq÷ƶ¢üú‡÷æ1‘üÏ(S‚Ûn=—¯ê¹4ÿÔÌÓ“½G~·ïÄéeº!ÕBÄÙŸFxΗJ—x¾Ì.j®b¹¼Û{ušOàHŸ]G.d=ÛrirÝͪáÐ/e†ä+a#<6 vß8¹ãñË÷ó4=6È5 ãÙËiu6oYWÑ<¥°²k+‚'ymZýÏyýƒ_gH ïEº"®L€[ÛæÔ÷°cÐht†Å²àµ™€Bˆìè¯Ã«ÙY˜Y9ûM ÈäÊsì¬aiæTo¼®¢!¹q¡£{~oÏ3£3Ø®ušý~*Z³Š";å’Ýó¹Ys™Kßvƒo¦ )ìÔU¸Z5ç6ç6ëÊÚ°bh;WÃÉEX1é9R¹ò«„ÿšeî­Ù®{[¦Ö¨bÁ«â¹ðćÖŒq·1S5@­X5‡”kó ج~ðÇD]½‘²ÀÃò@¿`üFY×XexHŠyüÛ°&žC³Î¾ÎP¤×3g¥Š  Yþ:Ó† ˆ‘! Ä™F7»¡L9ßakXšD9Žoi¸ïôg¾H& Ÿø{h­ýšÓ̤¡·bâ…„¤Ð°Ášµlð ÜrôC–P®Õµ„/GÎmI‰åâܼ—ç¯ÙhxËˤ.¹t¶WP–DNgÇ÷9GYUoóó, !D.Î[gŸD^¬ä¸Ý'ÖìùÈÏ— “·µßªL7°iQ+ÌõO „D­Ø?eQu;È5`öÌ'¹Òø«WWÝ:wþÓÌ\™j8ôÆK™a„dž¡YD.‹»yXÝ“šä0oék~¾$9RdH)æ–]'OÄ òå²üü×ÇB& Š4¼Qôuå·®óŸÅfB>\XFgXhN*owõ{êa^¾T”“xåèÆžþ•y|§È b^eR5•7ãÐí,¡D"̸4œeá«Y…òóëM~Úw+G$•ŠrnîêÖéµz W›Šdù í<®gˆÊÚ0U(ÎÕæ#vÿ“¬*Õµ®îÈÍ_rD‘!SéL[Ÿñ[sĺ"¨Õ!åÖ|BÈÚ‹qíULáq"i¡ æ³ÌëžlëzŸ-ËÏ{tffu¿ëšçJE• D2‘„=ÿ K“B$¹ cþ£6¦«ŒC’Án4§™'™Í @•Ü7¯7\uë²1—‚DF|þì>!T»BÒE‡ ëbšÕç½(ÅÂóâþ.öCÃò1Ìsµb×`ôãÏÃ"Üø÷vØíóA+¦Þo½þåÅ9õÕ²µ±âa y,Sö<–Kó ¤øUC3*ÏDË‚ blgaÚY€ªù¤‚7–™ß¸ßŸ’#FwK£r;õkŸÒôºxÕ¨àÀ”Á·lTÅ»ì¿-«×Ô&íÚÔ´r±™×j‡æé CvøÒèMª{4©Þ}b^Mìs&ôÓ•WN`ì| “§‰×¥ºs^±]ÎÊ·­àî%BÜϽ'Ëkš¯VkyÔÁl‰÷©‡ây»Í5÷|y…Æ4ªiÿ.Žæv{ L±\üfòõfÅ›®o2,^¶-Ûl ­™’¼:ô7ïßkS—`Hѵy ˆÌ¸^¤–¾Bd2$r[mbG-MkQ¯öŒk·6z΂٣:÷qp¯Y¿¦á¿*".µÂ‰tQ÷y+B£ %bÙf๺¯G–OËî>-»O]Ùï÷º´ú愨eáÜ{HÊ9.ÆR‹ËÌ‘k ˆŒÏ4ó4*Mes£š3ˆ,w±ßÿ«ÁU˜øË4H˦¥[/»ìÍÇž¼aÔŸRü¦mõÒˆ•oæ¸sé Ngš5³jnZþvŽmá5Ç­^Oš¦>t¨ôÿ&6ÌOB™Oñ[Òò¬Ksç.N>àé!Ûþü>_Ícjèê!ZOibËLÉ—»˜Ñ@–Ÿ V9\ ª/}õ¶3{Áw,¾0`ĺÚôCw3DÞæL¦žÖZEQ]UÌbDÒ:\&HE14†…i…kòþÀà{öÕ±.ÃJr®—9ûV–È¥P´ZÕ&Îý­$Ñe^.ç¸Ë{n¤@ò½%¤¢fv½ŒÊs4Y0ÙÕ$‚H¶e³¢‘!÷­ÿ”¥mwniÃ1£µdÇNÏ–þ[uVCµtW3ÆÛi29É|·}ÀUÓ¬™0ÌþØîÈOù)ÉÏÊ}~ì†Sï.jyl˜´ðx±L €3\þ>÷™/’Iþó½î|§"ÔÕl–ããC îS‹t}£iU>ÿTmv-ÍÌ~Ëjž<ýY(&ùiiGÇÜ+ôU»åVù=ÍUdÉ™:×éð–ŠbK‘€úgo¦Éð?¦Ó §mUØC´žÒªË© _„"—ˆß¿Ç¶ªZƒ3‹~56GÊO€_ù~óѳ„R¹8ûâ–‘ö¾K*Ê‹Ë:zõµD.Oˆ¸1¶ý$­U(Yº°ÅòwsÅ2™8÷îñßÍl:™V¸ºpä¿Xùª×ãí½ËͰ’œ»c¼ÏâÀ£/¢ó¥r~FüÅ=³=A Ý?ä#€<õÃÃÅg•s\Œ¥ÿ„Ú ËËäþ“ j bTže~ #Sù²üì›~sü~º"1õá®¶-ôÚtäÇšV8½!¦cø–CBˆ”Ÿ<ÌccdŽT-=óÞÓÅ-ƒ†xlšØöÈ©S Z·°éÚ›¦ºíúºKs› uß0²þÎ KåJäjùŸ¬<7¦Æ†¡ž[›î®¯ ž\/phõ?þt)*[jÄ–Ÿ2¨«à¥Áœ¸ÁnÒ‹vƉ3£»¼Î‘jmþýM—¦ÔÛ<¢Þ®={ãUßУ¨N.ÿâ»/]¬þ…,?{fý#ЇZ‹Õº¿O×–Cê·3²Ÿ¿øµíö¡îƒ=O†fizL­]=Dû)rÙÕå&zmV'hù„«/có ïE`À ŠZÓCøÙ˜1˜\kÅËi{ ö°5gr,wû°p›¡®sÕ¾&Þú³™§ƒÁvõjáà¾Ö*@åE¸s¸Z™q,: ˜r%&Ç´ÂÕ>lýA]K•µaj/(r®êÀ=¿Ž­_Í‘I§óì« ˜.‘QNëç–Y0è4Ó©VóµçÞkžX~Í×}T™"Î}: m}K“ɱjÔeŒr{£!yàΖiÕm¹LŽ¥o‡¡w2 úgsK¶fÐÄ(h€ÿAAA0poA™þ$m©cÈ/åU®!%8‚ b¸Z€ ‚ Høú ‚ ‚ ( AAY€ ‚ ÊAAP ‚ ‚² L¡©P1ù¯,¬PžÑìÔÓ×vå0L6·Š“{eoxU]B‰ã‚ü²€¦ƒ¯þ*Âkþ«ôÌ‹?º Yô<:Q,“Ë$¢Œ”/Ôù?Þ>5{Ô j»Y™s˜l®SÕfm»Ÿ³ìdèc eYs¬«i楾™=ʯ^5g.›Éâp«Õë=bVÈ‹Ôò9]»ÁMÙ¾¹¯“5›É´°²­Û¨õ¤%›ÞåHp0A*†üø±®sMøaÅž^ÎPX[¡¢Õ˜2µ°²xF+=ìŠþ1î¶ðª¬2ÁúÑ-).Ÿ Òð’T]1C)“æ§~~{$`*‡N3Á†ÈC3ÌèZdÎsü})žn ‹tõ¶eý>þà.Rù~üX—N§èî†eÂéå#U)¬-;+WÕà0èbyÍ"9áè¾ }°äû–<¤–•½TÌPjs 4/?뺳C·,©\ëQËþzê—öÖìR9Ý@ïQ,u84Ú”òlÞ "•ì!‚.]¬uRÊ¿|\/gss·~³¶å׆æÚ`Æë+ Ç ð­áÂã²Ì,¬=´š´lû±Lך§05ld§ú\&Ë(3`ÁÔÑ]Z7©êlkÆf2Ù\÷š½ïJÅ•¬f­®¥××—ö ëÝÎÝÁ–ÍdÛ:¸·ë5l÷ÅW˶%·ÓðÅašn*gt¡·¦Ô`F§Zž¾í¹òóæ ÷ÓsEr¹$'#áÉíK›~êëÀÕ»¯Ö¢ßF÷p´6«âî³dßSäEý>ñGW;sç:Ím¿bTõº¢²‡ÒdÂWÎQNêög¼MÉËKy;½¡½"E&I›¹&¼,NçÇÿ;¶Gck.Û©FÓUgß«ây4[´~ï£7ŸbiNrô¶©Mнˆµ8!•ï!‚Q‹]‹ýcò¶kà |ñdç4C‹R±ªùã'‘Tk!íí¹º„ …º,¡Ñ3Î2ÐZ­Þ8=¿›ÖSºÍ?m‚» ´Óð‡ºZÄ`U©tžÑŠ!µõ8ÌB¥C.:qW$/Ñ£œ.*.¥Ï:¶«y3Õ }w½¥.Шç•:”%yj¹´jÑ¿^ø.C‘˜ñvAÑRmYi®j^] VÑ-ƒwA¶EƒÒ:BýÐèfš…ßÚ2N¹þôÝÈÍb9NCÊ鵸Lez”PR¦fL÷°T&ö^u4:1»Ôo¤R7R’¢?a™{•³Úï UØÖ›ª6*UÏè]-0¶£x~v±ÊÐÏ-Y 3ò²ªÔ¡,¡,øÅ£HºÍ}“®HL3×À-‡F®þ¬DåÑ'˼^1i)ãï˜ÞQ¹ñsÀ²“2œ‚”„¶Êª@–´hRÚú½2½ÿ©ÕSdâä™-KÑ Õ÷r¤r¬%ú»HâBøIû |¶]B; •rÉlÝ*‘g´R’ZtÁ¶®1dê/Ά†¿‹Íá‹äDÎÏN¹{!°h‡]¯²“ÖÌ¢p$‰eFu€JJ£df†3}ŠLò™’——9Å·Èòús–Ñéy ;”_mj®Qf¥?×Ê¥pÇbí ÁïpúA*·,0aa_×ÅÜͶè¬ÑG+7»¥‡¯c®­18n+^NÈHøéÿÙÓ«žMé>DðQY$<õéæfc­%Ú7iÏ+Ú¤=bwn~îžÑµ•)óï%•%|[/eJ×Ï4]Y<£•’ÔblÏWÒgÇ›²“CÌ‹^¼÷%öövÃ;@¥¥^ÏS·]”ªª¨46*Y]ΕÅé_øy'&ÕU~íu,ºèʲbÞ"ù¶dÁ“ßÛè*çᎩZ· Ô÷\\¿ø›ÜL¬Õzʉ9µßeîÉ2µÓ@G)èjTeñŒ.L®Å„ɉFgÿ¸èˆÜø(ÞÆç+¾W=dáÖÑðPÙCYY@‰80£ý׋ٓ÷¾.£ÓU±®5,O&7\_âl„|»²€È%§涪_Â͠ÑhfÖÕ¼¾S̉¾½rö˜VßÕ¶å™Ñh4޹UMŸ¦?Mù寰w¥( äÒ¬upä±À¡Îʳ‘&X«ë”!;‡ölíbgÅb°¬ì\Z÷ºóï—em§ AÑÊÊâ L«EŸ]\± o×V5ܸl&ư°²õjØjäÌåW^§RlId\–0©—“%ÇÌÊ¡ÛÈ_£øÃ;@ee e!$éñ¹©C{Ôqwà0ét&ÇѽN¡SÏ>J0°3{:ƒí<¬½/Ãdr­[õ›ž#6jÙ g#¤‚`èÿD@A䫇Ž.@Ae‚ ‚ ( AAY€ ‚ ÊAAP ‚ ‚²AA”‚ ‚ ,@Ae‚ ‚ ( AAY€ ‚ ÊAAP ‚ ‚²AA”‚ ‚ ,@Ae‚ ‚ ( AAY€ ‚ ÊAAP ‚ ‚²AA”•F£Ñ4?Wdƒ+¬m´³ÖSÑ9n¡°Ðpãÿs?W–‰E’Ê‚¤ðk¿ÏÕ¬n5ks6ƒefïæÙ¶çàÕ;N~¿&Ø9JÇKmÿç‚Ê2¶j5£,l£p‹iÕèçJ7•âU‰ åqI@BB‚â‹‹‹ EÖ+³Ûwÿó¶­OÿAþ½Zx“ܸKÇw.X´)N$%„TðA‡ÂB½LÈùß¶·bZH¤™>Mo¤D9³èÿUŒ*YkæR·MÍ-jå«~5°jÃý\A:¤á.­°}»Yˆ ¥¶Z Êø§ïÖ;ëö/žžÒ¾ÏŒiéà9hºïï<ÍYø$ÑOüµÉÒ^ÿ3d®ªÈk©ÛFíª3ÜÏ_«K)) …ÝÜë]½§È£¼Èu%*?¿½°±[‹ú6ƒA‘N‘ c7/Ӥޛ9‡Áµ´kÔ¾ÿîk±j…ç}¾ï?y€—kËÌ÷ý–ËêÔÆ C̦¶ßÛô–¬ÈòìÂÔÁ]=ªX2˜fž ;m .æá×ûçùzºqÙ Ë̹ºÏO³7&‹eÊ£9¯Mî×ÎÙšË4³ë9aÕµ[—eª–þbïÈßÿ6°@qÞ»US{¹Ú±9V=¦ïLNxnΠ+òîÎÒÅÍÖ‚Îàxx·Z~è‘òL’¾}Éø&^î\6ÓÆ©æ )ËŽ:¦ÖØEžÖù†äWmD\Þ3´KS;‡Ã³mÑs̿ɂçç·èÐØ–Ça›Û¶ê;ý@¢y¢®Ò t¯®n£îÞ秇tjdmÆdšY7ê4ôÌ‹tÕœüø+§õ©êÀa0«xøLYû—¦yªnÑ,_­ê”gç'õmëdÍ¥3Íj6ê²åb´Þµvê¶SG‡¢èêäÔ~Pm#EÕº"Baò£y?uq°ä0Øæüä£f¶]eªuË%í­9’øºŒ×s½äF®,¸^¬ýæîÿxWu¬ ¾´¤Âb¨,èkÏ€K¢’Ë‚èSsX*Ï)Ò%‚w?T³ti?íÖ«X±TšønãXí3AµÀÀ'^Æ$‹e²¼ô¸Ý3Ò™Öb²š›Mzm3°êêÍûo?}->#W&æ‡ß8Ô̆^4®5jÕÿÏ#—>$gKe’ÔÏïNïYÍï°â0õ²—uµ?ŽÝLç‹ÙIÿ^Ø3¬m µA6ûÙ1KN«ÖHQ TÕÃÃ~üG¢’²¤RqÒÇ×gw¯W–&ÊºÓØÉwý±k‰Ù™˜qçd{{óÙWãGwôô˜yøzr¶P&&ż:»7 OswÕzùÉG­kÌS~¥Î¯6:6úqçù;éybq^Ê‘_Z±­ìì¿óÛyþNz®Xœ—|pa‹j½O˜& (¼aHiyñ§\-k¬;~+-/??/íÖ±µÕ-ÝNÉSæ¬Y¿ËÊÿŽøœ*–É2â#V©Ù'(‚Â-zeAµfý¶¿›–#•"nŸhegµéU:Eº: uÛ)¢CÝ turj?¨¶ÑðŽa`ÚtqæN¤P*W¤,®i³ü}¦òôŒÈ_,=¦QOá%‰àm'×*S6œø˜š+—I2cBOþOu¬ ¾´¤Ò˃y2yÉeÁ¿·Å¥dIeêy4Ó¯ýìaÙùʉà˜Û÷×Uc~öm°«·ÄXY k]A×g½¶Xµ´xJ­±ö¾›uå—KslÅçã]Ü{¦˜·ø WÆ/8"§ ¿j×Ç{}ÿÇ#]¥ýÕ§úÈ+ŸU¥>›gUm¡â³“ž#¥ªêÚ˜:ÿ.ZJ¡Î¯6æ«d”ð_Ñ\ÕqÞ3–¹—i²€Â†”v K¿31ªGcN÷uisP™ST¼‰¢¬›f6(Ü¢WÈŠóåÖhµÞ¢V ®NBÝvŠèPw]Ѥöƒj ï†@mÈú|uXÕÎ)¿žêæÑãÄÇKU/ݘP·¥îëÅØKA*«,Èô•eØCï×ÛYstìë¡ë:O—‹[Òt¹E¯,P+O"xËäzR¨«“P·":ÔÝ@—°¦öƒjÃ;†i!K³Øx$äË!ÒüÏNæNŸDRŠ+”êz±æ„é¾^ô^ÚRéeAO;.ÜÈ*…‡†’ô“F IDATOÌ\: Ò%r“k,;Y ×6Ód‘Kht–âcÔ±YîF?}ôÜÅ›áo¢S3„â¢I‘E£Iu”)É{=¡ží´Cáj‡ôH§‰å:-dÑik*ÂÔs†wwµfiÕ²÷øUo îWwüMÕb©óSÏ…)FÉjoRS3r Æ2ðtM·+ ˆ\¬ì-Z ÔÕI¨ÛNên`h'×Ý.Ã;†É!¸;˧oH,!äÓy¿ª=NSX®÷z‘è¾^¨/mùdAè Oèy’jÁI£€Ú¥RYPÍŒ ¥ + ,Ðk›i² ?û.ǺµâssKöé®S¼ÍY/u¬9&L»ß»¦Ý”=OUQXÝŒ%”PT—(–ék,!æÍ£7é»{òÜF+SgW³>•*0<¿É²€F£©Õ>S{ÃÀÕ‚põ[Õ—T«ÅµºÅ(Y Îy¨ì-Z ÔÕIô¶]Wt ë¦ËÃ;†É!f\²¯ý!dIM›ßUöë¥Z\æ{ÄpY zi#È× øI'Øtš™m§âknÒß:ùZ² ÞXZÏ‹C%‘ëêÙ@û‘jé wÏ. Ü9L ~`i‚,Ðk›ŠD-åÙÆ6^c¯)ÇäâC°\š¥Û:¿ž¿$² ½ çŽÚº®\¤«4joBÙŒdÊuìƒm\ú2}´·êƒmŠèèr‹Q² â댹FQ ®N¢·íº¢cT7(,ÐÞ14#bB!ë8œ‹>k^¥7µÀ¡öRP#‡Ñ7¾¨ÙK! T/mùd!$xrc°õéüÆó\‘”Ÿ¼{¹7¥¼²?ì³dЛÌÚŸ)Iòž]9¶hÖ’’È‚´›,tÇmåÁЄ,4?7êÉÿ =Xtšá² °±#L>óBZª²@¯mÊ‚I£Fœ ãKåyi±§6ÏppëYx òjû ïgý/:)‡yVÒ‡¿v­hãé¦,0÷ó W^Õu'þÍHòsSïýshDO¢þºWÚR¿Z?m¸iHé¯6ÛØ·=y;B ‘ ²Sî_:<¶‹—ò°0ýúwvn ·IÊ’ÊÄé‰Q—Nìø©}Áƒm}7¼ñ)Y$• 2>ŸXýcu¿½ŠC—ª5Lc§:Eþ’È‚7;úÖúi]trŽ\.I‰}}jÇŠ.õëè*Ú„ßjÙ ÙÿPsõKù9/þ¤ ¯ÚÇn¦ñóóóR¯ZéÎsUÝO1ju‹^Y0kÚÌ=Ÿ ¤r~zܹ ù®î" ¨«“P·":ÔÝ ä²€ºchFÄ„B’îO¶ö¶nNm*µ—2ßí°³k~øF¸@"çg&Ü8»cÀ÷žªcÅ¥ _‰, „DßþeÒÐFµÝxfLiçZ«ó£6ì» ÌðñŸÍm½Ý8 –­S;~{˜À/‰, „dD\Y4aPúÕ-Í94ƒkeïÝ¢Û¯AF¬SoïÜÐ’Í Ñ6ö¥% ôÚf ,¸þjÓ¤n–l–S­þ—¿É)¶Ör#h¾¯‡ƒÎ°s­Óoü’;1¹ÅÞØ~qnd–ŽVæL®Më¾?oݵWËP(Ïß:¡y¿U— )ðchP¦µ¹L:ÓÌڷ퀽עUwæ S/ߝޛ=“NçZ94íøãâ•;«Ú9uP'k.Îrªî;fQb×…LœèiÛ [c©FWþÊBHȆõ«VaÐ6.µN]ñ$Q@Qµ7²£Nt¨çʤ3­=t•öôÔàŽ -9 ǪQ§!§ž¥2êr µ, 3,"3ÒwÏö³f3­ì«ûý¼ìMnAo¡(Pk'¡n;ut(ºAÉeuÕZ#bl!þ:ó0G¬×Têw}gÏfµ¹L†¹µs»'^xžª:VP_ÚRa1âÇ‘oí§RÅÙÿ:6¼šõq•É%|<ëç÷ï/¯·´ÂX—©[ÐÏFñáx÷Vý’ŸLÿf/m¡ê½( P(©ÚjÀâÙ“ûviåjÃŽ÷hÃŒ!Ì_mèìjrS=l~x™ÔÛÎ c]¦nA?ç.w+ÙÙ¨-œP Ê”Tü±ý)wN¼–¼: [Ž›¿~nÿú&äkB|жV`Vö3.öí\Ú‚²AA£Á~ˆ ‚ ÊAAP ‚ ‚²AA”‚ ‚ ,@Ae‚ ‚ ( AAY€ ‚ ÊAAP ‚ ‚²AA”‚ ‚ ,@Ae‚ ‚ ( A)o˜Ù¸Œ‚ ‚h¥OŸ>„oH€ŸŸAAÊ|ˆ€ ‚ HÌJa%FÃP!Ÿàà`ÅúöXŒ ‚”CGýve”úã)uTwÃ`Å"H9tÔR" ‚ ‚²AA”‚ ‚ ,@Aeò_C£Ñpk7Á.„ ,ø:»¸.*{sèL–¥S£v}ϼÀX—º‡ét×Ò®vƒïGÍ\~ó]îÛì Kž¥i=º½³;ΠÊ‚ÊQAWJ¹IìÒDÆËeÒÜô„Ûg·yeß3¨ÑO;ß`¸K³ÛÈåB~VäÃÐ߯vzqt]goç>ó÷ Ü7v#kF§í¼R3=;zëŒ[é\œ@Y€T¤Ë‰Î°°vhÔqÐû௅ãÑ'¥;\q¸–Õ½›š³æiì‹Ážf!ÇõÙ‰û¦ØÓÍ=ëÃ̓5?.wï¾ýƒ ,øj‘‰âmêånaÆ4·ªÒ¸Ã€=×ã‡ø_ÎVa3h4Ú¢ûÉÊü‰·gÓh4&ÛþÜ>¨üÂÅã ]y„)ö«åR…ÃdÛ9×üaä‚»‰£ŒçØt ?ÜÀ)m¸upU÷æÞ¶<.‹kéÕ¢çÎkŸuUxâÜŸ¿MiRËËâØ:Vï:pZhtNñêb·.ø½¯§%—͵qê2dÚæÀµ†XR)`ñ¼öþ»“A£]Y8B\¸bðNaI³‡tq¶1çZ;t:?R ÍÏ|½bR¿ªö– »6fG‹¤F5ÿ`ù”uÝìÍØÜª :l Ó{•)ýöÿÁ ©/$ß›™½f_?ÇKRƒ–ŒoêUÕœÍäZ;´ë7~óÖõzDqΫSz¹Vá°yÞmû¯Ý¾›Ë «ú§$×`Ä‘Yl:½ÉÔzKËx½œF£qxßeJ‹-«iF}›F£ýþ:£,FE­A5‘Ú½_ÁP©`+çIÅ£ j ¼û¡š¥Kûi·^ÅŠ¥ÒìÄwÇúÐèlÿ›êÎErÅ"pžŸƒ9 øßk½…S ʼÝÀŠÍuè|9ü³D&þøôïNö\–E½›é"Ûòh XUax‹åütòý—L‰Dõ(¸›‹a¾=2SkEL3‡~ÓWß{÷E,§Ä¾Ú<¥ Ó¬ê™ØÜÂê"»{ð˜fž;.?ã‹%9IoF5ìÜÀÎÌK*Z¥ˆãdlŽÏÅÀ)+Ú¶?$.ƒ/f_ ô;ßÁ§Žý—!³¯lÕzŸ0ªi;N¼ŒIËdyéq»g6¤3­ÄdS¸±LÇE™-œà—§©©òüÁ.N-ÕìÑÛÀ===`È–Ëyâü/ïï­™1ÐÍŠ­÷Þ ŠsŸ¶qàÒ™ÖóƒÎÇ¥çJÅü˜ð;FFÑWßžœÏ¦Ó\Ú/Q }zK›åi ½ŽE«sºX{Î*ÏQQ5‘½å6@•uGEYPʲàÚÏ^–¯::€¹}ÿÂÙo­œ Ï÷„7;º€k‡•r §6àlïj0ñA’2%ñî8¨ÖëŒÞdQÚ—¨}+k™³·á醷HÓ’Ôç³À¡q!Í‘‰“é4šUõñН—GÕ€Þ'>˜äÛJ# ‚›8@Ÿg)8ÍŠ¤¢8µ™8Xæ^&7-?û6ØÕ[òßÊ‚¬è`Ss¦"ñÃÉA°):Kͽ ´cÑ I,Ó¬ˆâÞ þ5 ´Þø\W3öTžûᯥ\:ͲjßO"©#ùÁlàVñ“ ŽòaN0çar9ŒŠZ)Ü[nÊ‚J& ÚYst¬MÑ‹F¨œGuÍYl‹1YoëpYlÞw/òĆN§©%Þ $*2Ø–M)J(þ šÓaÈìÛ±yFµHÓ©è£ê ®–A¾ký¯ÃûÿмQýª.<3–j†æ–lxVÜ!†û¶²È‚Y€Ó°D¦‘"WÍoBÓˆ<h4æ+ !KêÚ* d’´VV»zK5íÑÛÀÆ<6XUÿnàè)«7íz¥¬ˆâÞ úZ°à߬|]C±× âè§~ç1èLn­ë©Bc:†|”+&ÝITäO _<·Ñò2))Ü[nÊ‚J& ¸t¤KäÔ§¿XÝj®MÖ¼0°pê<\ òåêC!a®·~•f6¹äbœ±-Ò6‹s•f†Oç—Ø±è,‹:“]:äê‹72rEªØtHµUd o+…,˜éf Ûò0pD÷{=ºRLišFâ% RŸ-R,¼h ‹Ÿ¥šÐÀȽ9tšª.·ã•ÞCzƒ¨8Q$'&{^«Ï­˜t Ñ¹ëî$Õ1â¯kÏÙŠ¯›š8À¸kñå3*jM¤po¹ P( *™,¨fÆ€¿Ò„çŠóžûZ°˜ÜZY±xl–¹×ÜüÒZ-x¯¢‹¥ÂhÃuqÞ—Ð&6Çíô§£Z¤eÁ6ç>p¬ÛifhcÍ€ƒÅ«PÍÐÇ€·*­0Ê·•BRCXtš™M)Î$Y`BGBÆ{X*&KKñ¦5’ùþnÐKGòóq³–¹·ÞCzƒXß‚ªëü&¦y®G»ŸÏZÄcЙܚÿ$ð¸¢åâ>ö\X÷>SzŽA£qíûRL»%™4HäTÅêro¹ P( *™,XWÏÚïŒTKO¸{NÙÓW´s€nA„¨C}À©å¯ªªÜ9LÈ‘R©NÍ<ЧhS=uK~8Ũ§hyŸ/6²æp:Eª\Ez[¤Yλ}] Þ”[šª°'“ë²ä|¿0,ô³I¾­²@*ü8Î׆ÿ€3M˜P f¢æTn²àËŸÆü|ã‹i TE&N:ÓVï!½AÜÝÜ æ…§™ìy­>Ë !$.t=‹aáòC´PjxiÏ §ï·^^ýõ±LGÅ¥õì ܰ§ºjî-· eA%“i/6Y2è ŽÛʃ¡ Yi~nÔ“+þz°è4E†×;ú€¹c¾â┋:[@Ÿ pe!`ò™RÝhæeþ[ß’mîØõÒ‹X‰LòñéßÌÙ<Ÿ[Fì¹Íý»¡Û±ÅAáØ¡·EŠræ™ôðKž +!tÿï.lÏ£èâW­èðOè½òDr®H.}xvmޠƪÄyÏÚ»X°yõ÷^y!Èñ«{öhlofˆ%YˆEü„˜W'ƒü›¹˜ÓèÜ~¿œ ¸â–. L(P3Qó *7Y ¸ æÚ÷Q½+5ªU|{L]°ý]b¶L&~vf&8µØ¤÷Þ fGïµfÒ-\{œðN(–ć_Y0zâ = £öyòýU9Lç6 …2CK“Ëøím84ÃŽE7³é(QÝ,•|TÌþ°Ï’Ao2kO|¦@&É{v娢YKŠécÝî-· eA%“„Œˆ+‹& jX·º¥9‡Fcp­ì½[tû5è!$/þœB°ÏKTæOº·è,»3ñ[Æ„©·‡wnhÉfÐè {­µhÍ#Hº·`Ä5mX –cžÃçßMÛ„ÜO!¾<öw“ŽÒ"e9›VÍoïëÁa2mkœ¶:Zå¶Uµ"¹$sÛ‚u\m4ư¯Ñä·½7Õ,‘ðc6/׬nU 6ƒÍ³k7`ÒÆMk ±¤bÊå¶#3ž­§w³Ñ3¿“£þXáÛœ±²À„55¯ ò“„•º›¶o™Ð·­M£³<ê˜äÿ–/Ñ{È ¦<>1¢{ {K.ƒÅ­Þ Ý²ÿƒãf azûjÆ«£u-X '3¼´÷û{(Êéyð=µK>*B>þ³¹­·‡Á²uªÙwÂoøª­ po¹ PeÚQi Y h³‹‹K…úA…???¥PÅ_IªÀ¿àGSôÎoÜ•®ÇbàpÌÑ‹(ý/®}Û:+3Þýú_Ùu¨WÑÙ–M“3Ù0ñ·Ë¶£â¯"‚ E°¸UºŽZ|3"^*'¼»ÿëÐt†åog¦þWöYîÏ3¯@ËUQ”Lt‚ ¢dÁºuÖqw¦vo”kéàÖ°UÏSVðµû¯ìùp|Øì|–¹×ñÉu1:( Ê.·bெ53ÇŒ_´¡¢ØSkDa)?ð!‚ ‚ TšÕ‚ŒR‰À‹D”e.u"• ì±A©¤àCAA ¨«Š·«¤‚¬|™½D²î¨ß®,\ÓC*ªO£±Çb¤:ê·+ AÊ™åË—£o­[âÞA©,^¼¸¬«ÀÕAÿòæ A D$•C-¸Z€ ‚ H¸Z Êµ÷w6!‚ \-@A¤€¯dµ ¢ýstÅ;Ïegþ3x)ÏáE×!“/C¼„”ÿ ÂÎlÞ¶ëü•°Ä\¹SU¯®ýÇ®]=Ó…M§˜Ëµ]ù¢-¹ŸƒÜۼ͎ÝZZíEÊ·­Qg[ÛÊ9lâ¿ÇÔVM|»«{ÇÃï,D'—ªó7NçÈWÏW>at_|¢fÏ7^Çççç½ ;݆Ò¸ãZÝÁŸÖ¯ÿ9W§t ZPŠíE*z_=šu~ç½ÙÃS%reŠ\’Ž.-9N¾…­Äç ã_]i'=ÙvüeEúê6­9ù…<|'HSâÂçõ~²mˆæé±—Ö~×}Ó¼K‘Û¦´5ü,ÁÕByzéà¸ÞÍ9L^‡Sކ>“ªHø iwZRQƒí¤&ððÜ»D $…ÉÒ§—LÐŽÇä4ï=î१ԫªG™fŸ-'ÞjÉ?UsGˆ¥ëȯ³]Êöv¼Ð )åöê„ÂÏ; V&òvX8W9ɈòqµÀäÕBHôÑß%„Ü]ØpÚÕxÕC¢¬;|×»–˜-‰ùwN¶·7Ÿ]˜gGO™‡¯'g eaRÌ«³{ú4wÇ;°’¯[¢Ëgó*>›3èYRíKhÊržœãêÓ?,I ÕG^ù\¼ó̳ª¶PñÙŠIÏÁù¦´eL’ºyî0ïªl­p| +÷°ì¼hgtšHWЯ¬VÀoʇzÏBP ,Poù“‹ÆöjÆfÙv6ëÔW2ת.OIøLNUåå~ãäÌŸºØ°ØÍz=pñ …,â°ì*HeÅŽÊİw tkŠÁ½k±:vXð¸¨ùu¶KÁæÆsž¥R4ÐÔöê„ÂÏÅeOux4¼|”jK;ÆÉB2"6òOó´´ïØ_^Eåˆe8È–Š,85¨fÍþKo¿ŒÎŠ¢M™'/þú¸šñ˜¬ê>MûœºóÌm¥š€µÿà˜×}ž¯V ÅYÊ”Ú[žóñQÀ‚ÑžÖl›š-æ®ÙmÌ4Î`»Bv¯™ÓÂÓ†c]sô‚€G•÷Ä:e‡ ’C~¶öG ÉOèŒb%ð“ljiyQ<¿ÎvBD¡<»îjãB)µWZý¬òa§¹ÃPÅgÓÊÿfeêê—ò³Q²@WÐYtšŽ·l!D˜ú`Îðî®Öl 3­Zöÿo"‡ÚÊSåQe^QË#ç¼qÿØ®€-œkØ¥ZÎóƒs«¸´»ô)WÓ­g!( PP¿‰qqÿº^…;äµ^ºõº;|ñ^R6_&Í‹›×³ª×ȳ„jÍz­Û1Ãà7Ú½†Ûë‹mØ.?¡âŸ˜;¨—0Õ`Y8u~í"„„Íôi³%‚zJ0µ½¡æg—6óß§ò…é·wi·¾`ƒtIÊÿ6eÚ„]Z²ÀÛœ•¨@–óæÑ›ôˆÝ=yn£q¨-¡,°eÒUWh®l¦k¤–ŠbéL+µr>]Zëj]wσd]&©ž… ,@Y`hËuM“oB÷èñ½£—Î`»Ôj4Ñ_žŒbêÒ) ’nÃwîÀä@›ÁÅŽ¾¾ƒ:‚5˜ði'#ÔKˆ:`W:?Õ”ìmåøVå^¤TÛkJw¹¸b„«‡Ãsì3ýÏ|\Û4I¨­”¢,8ÖÅ}è™KIÒéLkŒZ eÁÖ6. &n͈óRþÙ1·VçõÊ<µÛ :ú!1C"—ç¥Å\;ЩÅ*ÍrRï÷²rð?©÷,eÊ‚2l9…,(÷?Ć ¨æw¶âDäÛÜHX²€â‚/I,„é׿³s[¸ílLR–T&NOŒºtbÇOí=G=ZôÝtðBħd‘T&Èø|bõÕýöbÔJ( ÄyÓû¶²á²Ø‡ý'’*ó¼»ytBÿŽn¶t:ÓÞ£ÞkcER­åäÄüý½½åØÍ7¨ÏBP”ƒ,Àÿ X¡ ˜vu~Ø~ôÃWCYÿ»t3»NÞž_µdM?&Å$f°xU|š´êÒe†âèši=ï‡ü0shR®Ô±jÝžC&?=7ƒbDãwOYÞ[ÿº»U[ž:†íê0Ìr,kôºŸš£÷,)PTh¶Æf£¾ôþ¶q ç§eàÐtÕîs«´1r∑ƒ0‚ ,@Êt*Bôbà¿JBAYPf=t‚ ò-ƒÿrAApµA„вÞ(Š  \-@ÑIénEŠ® ‚h7Š"( *.!!!-¤=#ˆ ( Ê |/©\`Å"H%÷ ‚ R@åX- Ñh*¤âìçç‡=#ˆ åÓQ¿]Y¸¦‡TTŸFcÅ"H9tÔoW ‚”3ø&ò vKÜ[€ ‚ •ƒrø! \-@ù/oÎÄ@Êç7qµAApµ "PÙ÷<ãÎ,A¯\-@A¤Êš Ç$ìCè7ä[è±îh=´¿“;ögäk¢2=DP¾F\ñ/Âag6oÛuþJXb®Ü©ªW×þc×®žé¦ët\ÛÀ—;pª% y hïWÕÕr?¹·y›»µýVŠÄý³öÇ©¯>gÊ)‹Ö ܶFmm+ç°‰wþS[5ñí®îwN¼³‡³2¥öóY׳~êlÃQMÌϺ¾0¦/@úÁÕ„Šî‹OÔì9ãÆëøüü¼7a§Û0Bw\«÷¬ôWo¾NŸ\Ð5hAYø­Tè7ÔìáGb¹ü?ü½¯Í:¿óÞì᩹2E.I¶ðùþó3ñ¢+k¶-ó¾èžZâ½EÓ;nGA†|u$B*ÁÁÁ¤ðÖM5]í+!$çã¥Q=Z8Xq,ó:Ízl>û\y(dÝ$/gk–™uë âó¥ŠÄjÍz¯?p)S"7Á*¹$óÒõ½›USXybycOGƒ]½aÏ¿?çi=E&I£3xº]1rÀ IDATë-‡WcFW®Ž!°g¸Û‡GB¢¸ ‘ÿÆõK`°Á»l9¯'¸þ'Ô²&|ÚBhBA¢T?·6 ÿP¬R#ëÕé%Á[G+ïŒÂ†—’ßL‰×õõã«ÛY˜Y9÷µ]µ<óEžXãléÎ9ýœ­Ì¸6?¯¿©Ùñ 채Šs…B¡P(ÔÛœ«3|Û¼T~}¾¶UÓ%a)›1G5 £\x1BiQçÆT³m˜%•«†ûóõÿukìÉa2«xø.Üu_åˆZ1y`]6ƒÎµ´oÚiÐöàp½‡!üÔ·ë&÷´b3yU<ü&¬JË”‡Ò_œÒ±¡%‡iféÔmô²8‘´„– å(A1Ô”œ¯D t4ŸäVz^¾T”ûúî…é}(Ò£ýäÞmñ›Äq^òÞ™kýTPàÎU³›V³âØÔ³pÃãO9Ú“óéñ†…cjZs¬«7½j§Â’Ú]„Î’ˆ²Î¯êdç½JcR’¦}~4¯ƒC“eºë-˜’G:A«µ`îX4C¿ ùÄ„ÔU0=ó8ð$RøøæÖ“Nt˜Q©òÀ¾AAâýÙ¶ÁÓmÅd‘õêô’ˆ-m|f„©F°4üfJ¼\ÛÌ—’ÇO‹ZÐÖ¹Óæ×Ȩ̂~¨ê5ö¤Z o‚º;¶˜õ&)W½°[ERѧFöõ““T]ϹSªÊT wvÌ>ój^x”—/Ix}¥‡ oáDÅ¡åzûŒJÈÊå¹™ aÿ×­žÞC„žsýå‡näˆ%Y ‘c}ëŒú§ ЉçÝyÎË\MÍÍå&_Ùïß ëúZ‚ ,øzd “~/S¤YÂDÞ,Q¡F~DzðQ`Ÿ^>2y@;“Ó¼÷¸ƒ—žRXòôÒÁq½›s˜¼§ }&U±äBš°p¼Žc°´,ðÜ»D $ºë-ÈöOg ÑÁ­]Ñ =Ê às>È$l^ÁôlÁ8ñ¶hÖ§NWý¦YÁçö7²@”ULY¯Nÿ(oØ{ØñB3D¤”ýfJ¼v$¬Lä%ì°p^8ÂþíeåÐÂÖlá•xÕrF9Yl‹Ï-Ìÿ¿Š !ÑG6Z|—rwaÃiW‹,ÊºÓØÉwý±k‰Ù™˜qçd{{óÙ…yvôô˜yøzr¶P&&ż:»7 Oswj —‚Ô3\ë–y29!D.Ëkic–¯î}-»î§,-õÅ<ÛÚ’לAÏ’j_î¢8¤¾~–Ïæ5T|>ÒÁ­û¾wªG#÷t+¡%Ê‚¯GœšÐ‚eáÞcИel<ö÷=åâ°“Î`0ètºb—"FÓ¬%;úb·ê–ÔΫš=Ccr4ÓU¢µ"޼;§‡Gé®·`Œ: Ðf_Ñ mÉ`0 ö$Òh3ñú¶44j‹7@†DOzÆ+èÕxœ¢ŽŠt+&€@DVLY¯Nÿ IÏæ84Þ\~3%^Ù…¢\šMgX*>6qpø]fäN+ž÷ãœ|"—Ðè,Bˆ%ƒ®’?§Œd"³á²€È%?×®ý(éaý–ËÕŽüÕ§úÈ+Ÿ‹;žUµ…ÊË!çƒÈBȆFCþ‰%„Äþ=ĵíµp×·`)ïC!2q2Ó¬ªâóxË΋vF§i¹{¡8$“¤nž;Ì»ª›A+¼xéʺžì%Î}ZBK”_, „|zz}ïöMs' ­eÍ®3p¯"ÑšÅëeá7NÎü©‹ ‹Ý¬×ØŸPXòäâ±½š±Y¶Ý†Í:uã•L‡%º"$áG09Uu׫þ\_ù•ÇÈ“©ßñËİw tkŠ±Â½«žô!ŽË®‚´øô¯¸ûjÈ#ëÕé›;Ìy–Já(SýfJ¼ŠËžâ³=‹‘*‘Bî­êèÔri¾à=Ǻ­BdåÏ* Y |ËÆY@HFÄFž'ï\_-½‰%[õá7!D&Ne°Ÿ§yZ Úwì¯G¯¢rÄ2dMi/ò\ÇBƸòV¾ËT 7Kã%)å­H^üõq?4ã1YÕ}šö9uç™ÛJeLqèÔ š5û/½ý2:G(V(BÕº4—åJh ‚² ²Ês=W÷MO~Ö#:ÓJñy’ ïÏX-·°»×Ìiáiñ®9zAÀ£?«þø(`ÁhOk¶MÍs×ì6fz g°]t׫S w8™ªó‰@òS:CO:‡ ’C~v±ººÛÜÒxˆ`d½:ýCe„ò캫;¥ä7Sâ¥òa§¹ÃPÅçêfÌ‚grñ¬†öMG4¬="”2Rõ!—í¥% ”G•šÀXY Ëi,:M×˽„aêƒ9û»Z³€Î´jÙ{ü¿‰|j’„È:˜O96ÙÂy¤f,êš³Þ=öÒv/"Îyÿâþ±]Z8×°Kï!Så9e^QÖå£eµàY©X‚ ,¨|²`²oüÉçª7;õº;rù~Z^¾T˜ºs¼¥ÇXEzÌ©Q6u†ÞŠLHEï_šÕ÷;Ezµf½Öí¿˜aâÎöŒ‹û×õ*ÜÙ®u¤®×mÜá‹÷’²ù2i~\DؼžU½FžÕ]¯NYðf€çPH@ÚGX1¦ CÃþpù1¥ÿ ÀÜAOú@{€ ×p{}±ºnþ Ðùðl{ñ-‡ÆÕ«Ó?„°™>m¶DPOi¦úÍ”x¹´™ÿ>•/Lÿ°¸½K»õ°CF{9·™ñ46S"L?ÐV~È"„¼ÙÖÍñûÙ‘Éy¢Œ˜Åþô>õA3û[» ºðÉŠ¤¢XåÝ Å![&]uùçáÊfʺŽtpëq ØÞ‚wû»—®%Ê‚J# Òžíl\ÕV±]@‘qi×€v¾l×ʱuŸ‰·Šî®l™ó]uƒ]½açgž•ºû´~}ºoDï­¸tÛ¥V£‰þûÛ”(¢ UÇ–ƒ—+0PÕþ8^øú" êÖ\`rÀ§œŒÐ“žt¾s&Ú .V¸D#Z“u;ÛC`d½TS²·•ã[»–Rò›)ñº¸b„«‡Ãsì3ýÏ|y‘ë&õv±2c[Ti7pÖÉM]œš¯VØ1»¯#͵­:eëQ*²@m eÁ±.îCÏÄX‚L’NgZãPk¬, ˆE^üië:›Ï„¥óÅbAæÓ§'÷öUªÝnhÐñЉ¹´™°îÍ„u%¯ÚÀ•„ †³oxÕ_fôþ!ŸÆ­áÓ|Øï/U Ý‚ ,øf+t‚ ÆÒxà¼ÐóÐHé‚ÿAAApµA„вÞ(Š  \-@ÑIénEŠ® ‚h7Š"( *.!!!-¤=#ˆ ( Ê Þ+Cì±FAŒ÷ ‚ R@åX- Ñh*¤âìçç‡=#ˆ åÓQ¿]Y¸¦‡TTŸFcÅ"H9tÔoW ‚”3ø&ò vKÜ[€ ‚ •ƒrø! \-@ù/oÎÄ@Êç7qµAApµ "ðµîyÆ[‚ • \-@AeA©ÜæãËÍèOäÛè™ ,¶ƒ[£VݦýºùY‚=ƒ|}|…r?¹·y›»õ?´áCØ™ÍÛv¿–˜+wªêÕµÿص«gº°éº:l Y;˜½º×©ÈC$@i½ÔmH¼Œõg)÷ÏÚ§¼úœ)#¤$/²¸m:ÛÚVÎaïü=¦¶jâÛ]Ý;îœxg!geJAôå2~NÆÇwáWÎõ«]}Ä®[ë†{º§ùjW ®N è´à¿µ¡ûâ5{θñ:>??ïMØé6ŒÆ×ê=K&WW}z5€ ÉßJ4$^¦ù³Tè7ÔìáGb¹¼M½¯Í:¿óÞì᩹2E.I¶ðùþó3q,+¯!“aaãP¿Eç¹ì‹|µç̤–‡ãóÐ+È×FB!¤‚L oÑ ›þLÀòeɯèµW-câ¹[FÒ׿3â—´r{ïUAáëûóºÔë¹ö¶l~DЬvv|½ZÆ®ºú8_ËýÉ|uUàØ†&z&öífEÈÖïè>/ái®H{8¨gfAå:ñë§ÉaÝÍÛ.V¿]¥î\ø†ˆHÏ„†’ȈzÿF·~#"êVºÌ“X""óötç%¾¦ÐYï‰Dôi¥gÓˆˆôk¿[¿ï!J=IDä8Fé½ãQæ­w;#ÿQÜŠìg¼ Ñö+$Ó£4w¨R,(_oÚ«2ê³"í¨òÕÛ’xá¹|=#ÚL Þ•’‘# \ñªÏ™¢n–8›÷ûqÇýŒl±Tú&'#îØŽñžMq† T·X õ®Ã;™-P\2<£ôgAF¸QÝQŠØë'~Ÿ2¤+«×¡ßøǯkØ“ëÇwŒï×AËëî=u÷Éx±Âú¼.~{½~ÂѵP1@Ä«ï~§H¤~»Ê­D6TI C¾DDó¨$ˆÈÈ¢t™ÖDDëŸ*õÍšcTy‚Í%†¡1DDOKH"""Òå)½÷•iéÚc‡ˆhïÝ2û£¶Þ4´WeÔgEÚQåyRøühc¾¹KmýÀSéŠëcašþæíò›?g,`æÁnï¯\dæb`›é§•vL{ÁÙ¢åÊ==Ï+’ “.Du33œõv™p/›™»Î¼Ì+–ˆŠ_¤&ü-d@‡ú¸Ô~L,J Ø#ÙôÚæ¦Þ1iŠ¥6m±®4_ö¶í²æ†º«°æXÐ÷ùü7é9º÷>TœcXw¸l:²S=m÷äE™7j;É×ÓcýMÅMd'od1VÝ>rعb)N Ä‚ê}!3~¶¹óÚ2‡—÷öÌ–ŠóØãòïÊ{ëio¬yDÄoèu25¿ü|Åg+‘ŸÞ¹8»·ÓèCê·«ÔÑJb1‡ˆH -íže3†L¸DD¹âˆ*'dëçpJŸ"”wÿ*×£!¬ìBDÄâÐW]iÁ*Ê•Æuõ¦¡½*£>+ÒŽ*Ï“umëÙu/çNŸ×ìj~ #±Ø: ÃsØ Ëçd,-¬},`¤¢o¯¼¸Ü¢Ó’2%‡Øûžzª\É|»@Ù4ŸËÎÇ…¾rcøì~Ã0 ¸‰…"ÅRaA× ‘lº•‘îåü’ŠÅ‚$…ÕJE9åç°¹&²éF:gs ¿./¹ú¶òõ$(ß“3Ù\¾º}˜`cì6?âÁkÎ Ä‚j Ö:›Ï~;d§ærÏSü¥H85s„{-Ýö}Çm½¦aÍ×b·ëÛ^W§¶çHÿ}g%j~ŸÕí§¨0‰«g«~»ªn"Ô"†!ž<H”b¿’blý­Ö£!H„ôÛròt!‹ˆ¨¾Gi,PWoÚ«2ê³"í¨ò<1ÓádŠ$ Ã\ êaÑiQIQŠžIY,È}·|îÇÄùÐ×ĆÉNZÍsàE¿(,3¿­±®ìþ‚⥟£c.›žî`â¹çЕÄûùB .²•páõaýÚî²i‹Uö)©ˆÅâÊ&uÊ—j Ê?‹$U³°N¹¯øÊ¾b ÍVʤŸß§=«cß¼Ý ßi΋) ªW,dŸäÕéUæÄUŽ04/jÛº|¶‹C-=“†~óB®<Òúžô£+!óüLtk5t™³|ë‡tc ]KõÛUêh_^&"²íýî&Â¥ü²7¾³&"Ú˜^¶;—õÊ%R’µŠ£êEe~X,à°ÊΑÿ¼¼®_ÔÖ›†öªŒú¬H;ªT¾K"ÌO¹ùÏž-!C\ê9Ù‚3± ŠÆ•ÏÄÍlîº!©üáYºÎMÉ,,Îz¸ ›eו¥OÒÚµï»b[lvŸ`ώݶ¢ïÛ'ØUþŽ5õ¿+öÒ‹¼B‰¸äIR\€—mc߃ê·û®ë}q—ÙG¿ †¡äP""¯m”¸ˆ¨Whiï›CDdÑ‘îeRqýX:¿‹ ѺºwX«X [¿ÃpÊ,¢×héX­bÁ×|"¢-ñïæ´L'®R±˜Ò㉈ ÍU~á]½ih¯Ê¨ÏŠ´£Êó$Ưq=××ÓrDÅYÑ!DôóÃ\†a’C=ëvœuçe ;uAw‡ Ä‚2veÅ‚f†:Ïß? ÉHM¾’œ•´Õ‹gí‡Km…cAþÃ# Lv½ ˆk››ú{¢¸@ZŒ·üÙ‚ý^¶ÝÖßR¹ÑqõŒßÍVœss}ŠÅ‚m-}Ž<®@,Ðg³Š5ž8bAšüŽ T­X .¾ODæe.ñÍøuï–‹ÉD»t´_OWwÀwëK¤•_}*_&ŸŒÝ»c]¾›£kÙè«I?FH¤š[ˆXlªmI½†Óq…g÷¶Ÿôùä ôÅ·QÇ&¤Ë¡:¶4séÌ{ÉÁŒ8ºôµV±€ahÏjlEÙ¶¤_þÐ*<ÜGíœHŸû®èv,ùô âêQó¯)*IE,в½*£>+ÒŽ*Ï©({Åä~–|}]#Ó®ÞþQkÜ-:,“„Ïú¦.O× ¶íÔÿ²XœŠ*£m¥Ä‚=îõ‡HÕr Q–üž4h ¤Ey¯o_>³æã­êÎßý.Úf^20þ*òäõ|XR’íøÖ<åo"˜„zš]$¥\;9ÇÛYV”9ØØ¶l|j‰Dšÿ*uOÈÔÖÃ#* Ò÷Û˜8­=—U(å\?»J¿–ÚÄ‚¦ËÏ?T Ž]‡‡ýqòáól‘TZðúIT°·…KÎÄ‚ª îïrgëÔùýažr*b×ÿ –—Ϊ‡jèZêÚë‹5ÀGœ'‚]^›~á?fŸ‹³Î´®cz0õE®X"Ìz~ÿøÞðÝd¥6.߬Ùq$éñKXR”ýtï²öýÃ¥VËXð6»sø¦–­;ºM_´úzFÙ[0·÷¯tsnd¨Ãfë6rv[yà¶biAúùCݬj²¹úö­{¬Œz÷LÌjÿ6\›oÑhôüÍiÅbÃ0Ù·¢Gy´«eÀåð[uöö hŽ£hf]›ÍbÉçÜû{÷ÄÁ=¬k±Ù\3›¦Ãf§ Ä8C ªb,˜hÅóÛq·Ì’ßÙò7>ÉG,¨.±@]{U£Xà2fÉ´lQÑë]í¼h Šßçã÷¹øÕÕE9Y›qÙl¾y»ü\úu];#¦ùô´41`±u,ì[Ž–…§È´‹ÿXPýþ'–goÊÏܘ–‡¿VYÔ€öZåZ4ÒÅ.%—íâ5î¯=}+åoFÍ_Ô7o´5:HUÑhßI£}'…áüõ¸5ûðüóø4ç‰ëÄÉWh¿¼–ÿ* ±] J`£ @£šTüw`´@­Ê}P êÃh€jxP ª®˜˜´T#8cÑ‚ˆŸ ¾gÕ ÎX´ @5…g  TU-`±Xh$€ÏÔíQFF†ì…¥¥%jà? 7± ± ± ± ± ± ± à³áVåh¡ÏI__MPZ¨10Z¥‚ƒƒQ ¨%øãVý]ÌÉÉA;}jh‚¬%€£€Xˆ ·º€•••|ZÇ€oçÔz ŸÀð¯«õAI„O¿vžy.!ZŸÍRy°l®_ǦAãö®=GŒõmiaðE+Dzú× õ»b’½àšµêØ}Ä„ï|\Ê÷'##C]Û©+ª‰µ€XðYÈ»aavâ¥As}oåÝ9©iõ=¢Ô?fe&΋{±±«¥êƒ•JŠ rŸ<¸sîÄÁ1_wrðûÁN_ªBn¬ö™{Î!lstG«7é·~]±ÐhŸèïkd- |nºFuÚzŒÜ#l幘&í¯®‡Áˆ¯HØx<<Àg#]Y®z6ÇoÚÄÙµ‰³ëÈQ§<Ýú7éïmiôE*dÁæk×÷väë‘©½óüðmü>(Ïýj  Z¨Ï×!,¸"›¶²²’Š^môsnÚPqÜø^lø°Þ®Žv66vŽ®^Ã6OQ\CñË«K¦lßÂÉÖ¶‹ÇÐM&È‹žÇíÑ«“½­móvnA»¯Ëç‹×.˜Ôµ]K;›úN-¼†NÞqúÎ{‹TÊŒ_œÜp¡—ÇìÚ1aóß¼vžÛ6YpA› ùî‹›)åK÷Ù;Ô-œ}s¯«c“E;.“ÂH¾•••DôbÕ¬­ØÚ;y zünžæV»Z@,ø2Þ<Û£Ëë ùë„IÆž³ãîË?›f'®óòß? 04>åÑã”øÐ¹ýöÎèµáv¶¬T˜w±o·1RçQ‡ãn=z˜´sù„gѳK×ü$ª‡ßF÷€ð䇩gwÿxgÕð +¯dEëö¿iî±óX\ê“§‰×Î,ì~+rÊ{‹TÚ9çˆßÚÁD4xÕà_gý©Í!Ûžþ:>RË ©t#,y‹þ¼§Í’égCÝFDLÙ}n™ŸK™¢-cFJ;N>{#åAÒ¥…ߨÎíç~úµ &Õ@µP£n"ˆŠónÿsbyÀ²Nþïú‰¸ÁëwºÛ).vpæV÷M§Fõ)Œ,é¨IDAT´–}Jlãæû{ع^3£gž@D'§Í2™s`é·Íe 7nï¹l»§l:vú/m–Gëé@D†»nÜíÛyâß_ô'¢MÉ97b½ùñ-Ú»ù´wó‘½KCQyE¯öGä÷JidBD¦-~h’Òü\ÞÐn&ºš\—ï**œ¦e…TºùQ+G é×uGg.ÙÛ6nÕÁÙÑ¢übIû—ŒÞ”¾åüñöæ*þxðß^›÷ —Ýø7ë1òKâGN;î±oP©%Œ|&Vo5jÖ~ÆŠ"÷Lm&/ënUfùmioæ¸*õ[]Þ<.ý¹îò«Å#Tn(âNÎ ¯úò—µ§fü.›da8!x÷ãaùwi(*ïüÿVw_Pú‚Åýq–ÓAZŒl3 KË ©t|‡G¯Ý ™6ÀX’såôƒ;º ˜v=OéxÏoš>ã”ÑéS[Tf"ú~HÅ— }fŇ֤ZÀhÁg¢ùɵF:eæ<-‘4ÒW:pGIIºlúA±¸e¹·È<,û4±WœÃb•v3KF~?o¹GëEu6kÑò«½ïãÂe½§¨ qqÊü‹&q[¬åsù®Îj92}Ùåúº Ç(ÌÓá9kY!Ÿ‹cäâ9ÄÅ“ˆˆ‘E/æ7$üö_þ²Ò°[¡!«Ý\g¦£6†63Tªs£–bÁ•KVßZÀhAU–vr©–E2Œ´8pãÝ}wg({tgWâÊ…BFíF ÒN[~oÁªÎ_ª>½¿ß]"-ûž£¯tS ¹Ï'׸Íq÷ú#þµÊ•,;œ¦øòQô23ç5©– ª¨!&ž:6ê\bP"$ü½ÇwÚ_“7 –•z†­Ë ñ^ºýÄó<#O –ŠŠÄÿà=ÅeÚŠ2‹Õï1ýLÔôM#z¬>¦"uu?:yõ¾ ÙÅ"QQÖ¹¨!?¥oê]“j  Zàþ¹NKÿãkt~X>yáÝ'%¤gÛ¤íèuǧµ¨#+Õ5é|ôÿ"—/YÝ'xzf‘ÔÚ©ßÌY‘a½~gqý´xõŒ¤"2plíê;­ô±¸]s=Ã#C7,¸ñê°V½®½‡ÆFOyo‘¢MóNÛ¾Tå^3,d|øÚ–ÐÛïú³Øž‰™ƒ£‹«ÛŽ‹Ëÿ¬ïç÷oLäŽÝûÂø¾È&=ãÛô÷ ß8ªŠšo=ìøiÓ}ú¤gl[;Qéƒû¤»VÌî¶ht®P·q·à˜3fú5©–ª)<{eiiY¥vN QNNÚéS‹ˆˆ ¢%K–|‘&øÈŽðÅk  ÆÀPÄ@,€ªB±ª–jðMÙs^€&€O­ª£‘ÐðyTé/(Àç„g ± ± ± ± ±  Rý?X€hTIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/i18n-3.png0000644000175000017500000002252710027550273022722 0ustar frankiefrankie‰PNG  IHDRÞçg’„ pHYsttÞfxtIMEÔ7. IDATxÚíÝí«Ç}ÀñÝ=ç*ŽlEvܺ}ÑÐ&…ÐŒ]Ò‡¸­Ó†€û¦W·4ö‹P!\¥ý¬Ú@¡–I‚_4HÁ¯Z®È ƒï¥”º\ ŽÒB‹Ü&v$ûEe'¥Wy:×rlIwûb¥õh~;3;{Îì9߯œ»gÏììÌìÌïÌ™]•u]­¢Bs„æÞJEž™YT³*—3gÎ;v,m>xâzUI?X¹Ð¼tXú‘Œqw)KæÌ™3ŸùÌg¾þõ¯{îÿꫯž>}Z åŸxâ‰ííí .P•C;}út\ö.]º¤ÖÚ±cÇNŸ>}éÒ¥ù|\sáÂ…Ó§O?~¼=—ãÇoooÓ“¼kí6P× q·¨šTþ7› ¹ÍêD¬™4‡c)«cÇŽµqùîîî]wÝ%‡†?ü°ë]õxâ}mUîíí½ôÒK÷Ýw_D^xá…{ï½×úÖ¹sçî¹çžT÷,"Wº¾¾þo|Cn° ¥[­ ‡ã*u¾\ŽŠÎœ9#Äå£;ñUeY–·ß~»—ÅôÇw½{üøñ½½½á>d{{û™gž¡;„…ææØ¬mÑ~oƒÖ~±Õ¦ŽÌߩ͑Ϝ9cŽÙ­½½½'žx¢MÁ3Í[ÍGŽ9uêÔ«¯¾êŸ[×2€ .œ:uª}ëÔ©S沇´ù‚!Ï®µIc)—ΣX3ïJí«_ýjûúüùómœzñâÅ­­­ ¹À]gtäÈ‘^x¡-ð¦©ç;ß ªÁ΢{UF{î¹çÚ£œ8q¢©²'N´ÑðsÏ=7ÄÇ/]ºÔø±cÇÚúmlllœ={v6›5©mnn¶o}á _`ÈÌ–Y§Í„·´xegg§sâ­y÷ܹsÖwyä‘ÎceCȉ~ɹµ–†:âª677#ŠË3Ÿ®ÌÈyV­¯¯®d¬|ŽâßàµÏž=+½³Ì3Z__÷¬}ùì<ôèª2¨š4m]ÅÅ‹ÛoSíÆ6àîÿqí:RÿÜÝÝ m-ØG>¡ùîî®:Œmllø$¢~¤¹Ïž=ÛnÙÚÚ²¦Ðœ¡ÙØØØh”ÐÜZß:þ¼¦¨AŒ+.Ÿòد¦¦c)SÜQä4yä-ö:qâÄÎÎŽöÕȳ´32·ßB#BóñVeÏ6¨”z~\;Mµ×Ò¾«¨f³Y»ÛÉ“'r†æq£ãÉ“'…aOË“d£ÿXn¾¥žB3a¶»»k€ç“O!M5cò âXJ¦çQ|Â}ó§m=â·‹ÐBîtލ*Gšk1·ð dkkË5¿€IB‹¹,µîz’ƒkg×ö#GŽÈ‹Pkøg£yøÃóÏ?ÿÊ+¯hÑ«ýž¹áy,ÏCäSÈüñãÇ¿üå/7¯g³ÙáÇGW2ží³ÿ³k.\¸ð•¯|Åõ¤Å³gÏ~ò“ŸìyFþKÐe5ÞªôìvB?ñ4•ˆ«¬ó(êã_677zè!–P\k7q埥þÙØÝÝÕV…&™PôÏí|òéÚYýÍ][õ;–’ñoŸK}¬vwwwvvNž<©-›îü=gQ³æ£®ÊñΚwE½£FXñÀMcÐbCóè¡Ú3êâõ7謢–žù´nœÍfmĦ­lQÉÌ?4wEWIÎhˆÐ|ÔUÙ34Wïãl—¿«k“üoíüxÐiªëòÕûgÈ.4W×°ž;wÎ $ò\†Û3ŸÖjØa>Ab,%c5ÄZóõõõ­­­óçÏ·½Ó¢´lgÍG]•A¡¹¹ƒº’»í:Ôï*®ÛÊû\¸‹£½ôÖ××­·àšG,2q ¨êzõ.:õëëëmt~þüùfPLš«?ôïî©gnët¯H’OÏJ–²Œ«d¬†xBKç:+׳A“Íj!_¼x1¨Œº*;K^ΤöIý¢•öã® ‹‹¢½š'ÍÕ¡KÛÁõ\óäkÍÕY1yŒrkýHÄ#Ÿ“äÓ³ :¥d\¢ jk’‡æZ!kËÜýgŽÇX•}Bs¹3Ñ~”Køq•ðLBs@F¡y ¨¿«cØl6ÛÚÚÒÞÝÜÜTŸ/–d]M¸43ô¹u}äüùóêþ'Ož4¼NžÏˆJqUåXJF˜;8ŠKs÷ç‰'Ôo5M›ôYÔ34W«£ |ƒÀ¨«²ghÞÔÝææfû}fccCëIÒ~¼yæ½¹°‡ÐÐ_Y{?Ú Àp*Š 4@hš 4Íš„æÍBs„æ¡9Bs€Ð¡9@h€Ð 4@hš 4Í—XY–eYš¯sÎ0Ù]á䓱ü[8- 4B„æz¨ªZŽà{ùÎ+Ï¢®ëz,ã™5CäͳX–£‚R œ-mD§0·3¥W0jS¡_SǼ&ŠÍ$°ºãκvÈùÔ° ªÐH%ç6FûïYY --‡Sàšú¬¹kîY›A7÷Q7š¯›?]ÛÕä#ªû˜;Ž)ò¤»·Âc¾ùÁÁ•yÿCȧ¦ý¬” ðYხñ̆º§«ˆ¬9±þ€#ÿªãÊF³ÝÚ=«À§r­'+”X{î w›gy~6ºvhiž½\ŸžGûlû:ú‚š„ƬcAÐøÝç'©#èÍÓr­ù3·kÑ­uýŒÖ³«jqÿg!çÍ'‘èø©sçþ z&Õçu1ÂþÖ\užxDá«[̯%ý«/ó¥_ © ¸FåY;´´ùô|BKÓ%µ„íæÐhÎcùìà™« Û@=óÖIëýgVÌžÝg/:Aë»ÂÉ xrÆäßjúè™Ng™t–˜5ıN³Y¿p&Ùm±Ô§QyV --mÏw:þ}QÂŒù”CЩõéûç ÀŠpÖ<ô†Ëùô_Ñ“aÃÇ=O_˜”¢}SX‘–º`#ÿKƒÇb 4_°U¾UK^¬—Ç%(ïiÎuN>EG 9ïÒË¡‚’ä––pN&qyÂŒ…6z „æ+­çÂÖˆE }Æxÿ%˜ûg^¼sÈ€çBäT»åYAy ¥-w†‡ÈXô­0g•µÿ²Þ¦É´0,¤pÔ8ŒZX¶Ð\ 7åˆPÝ¡ghhý>É—Tyî ´Þ5¨f@x׺OŸ­¾ùlJë v>þ,a¥t–IÜÎþ)xΫ¹ö4'¶­SÝ w›gõ¹4⊔––¼çºÄæ™±ÎSÖÿ:󖼬š©ŒÊHQwè?q«%h14…„½aÿ¼OZèü³3Ô MP{„!sQkÍ;óW¼Â½ËKù¬âüךûÔ-m žGN­ç)¤Í˜œÉžWÏ?‰3„Í&ÐqÌ£”³Ÿ8I29G[ʹX–¦‚hiKPVËZ‰4NýUÁjØÄåÄå)¹á -«hˆÍ)Õœ‹e™VàЮKŒ)( ,hÍš„æÍBs„æ¡9Bs€Ð¡9@h€Ð 4@hŒÚ4‡LlooSX&GŽ©ëz|¡yQëëëÔV Z€<ÔØÚÚj^P€•ÂH b¹[EhT<ÍídhÜ€Õ¡ÞmÅH bùZE(´Y 4ͬ¤²,˲¤.pPïÐL) OO$¼;ºE‡®Óaõ$°W"øœkÐU°mEPò 4S;V¹/´£O›-…f"„!X`÷R(S’=/F.ð9ôÆížl1:,hÐ=ó3%U¤Î>ê€0k, ;îœnW7¶Ÿ~ö=ô©ûøLù ;wnèÈ!:7'¹Wùr"ä­Ï©ùôÆBe©oQtTòmÆR50ÿÔ\SàòöžC^çàÛ¿x ͬãrõRWûk³×ö·v—®¾¾³—Iò«O²Ú ÇíLMØa – oY‘ Ü̉𑞧æÓûEñ,¢èò‰(ù„ Ì—'i®óòú·¥8,hæ:vsü9É¡;»WW²þÇÕþ!=ëoÚÖa©à×yз¬Þn–îSb©ºÏ܆֣ð/šEZò©Xh»²¦ú-hèA-ÏAŬ90¿ATžh¾p/üÖ3«ÖÌ$£$¸Àóï1äãvæJ<3·âêÌêØ¿}:„æÀ™Yâ`ùÇè\àóìáûT–+Âv½µÀ’_¦……BɇÐÈ+._ÁèÀBÂ\.ð¹õ¢E¢tÂs•ùÂÏ7®iµŸÊíÝœ‹—ÐX@t;ŸÐØaqiŸCá‡^% doÐÓa­90ž×¼bå½]Xf_¬û˜‡Žøêß™kÊž=¶æÐLÙu>9–)÷¼4¸À#zãˆ|>t¯‘O!D¿%—¼OÕ—¹ÔÞ¿]…ZÜ'—€œÚp£¡9òûzÄ»®8;´s÷O*I&û HwÒŽ@+Õ™p÷Ly½qÄiG$¥‘¤ zßdÏ!Ï'‡ÑõÒ ZVŽ6é›Ã oî.˜5XAIDÐÀº{ àµIëZ†Ð|{{›Z¬ F@jÈ+4çÛ`51Rƒ@Ám @F_ònkk+ŸÈ €¹a¤±Ü­"4*În­9°:ÔÕÉŒ€Ô –¯U„â -i<öÔ³Âh*ëèæŠÐ`É>ŒåK·Y`Öý•A–$Bs²÷¡¿ä³ÛkO?JY„æ`XßþÚ_´¯Ë²œL¦Õ{&ÓéôãŸÿšœBY–Ödž¸¶#JqXkNßqE‘m:}I®ÓªšL&ÓÖ¦ÓµOlÿÎdÒ=¿V×µy™„æ«ãæ™9lzç†ùV³E>¯æMõýæOâ½¥lÉÄñÀ‚.ÉJ,¯ªê7Ÿù­¢(Ê’A<÷º£¡ùÂÍ@,dº¢ÿAÍ>¥M³y§}Ÿé˜T¸O­yöõžé GÔÞbŒæÒ3Øãò¢(ªÊëÔ&_¬~©Þâªà{—^°®y1W-¨µtükÍšˆù§+·Úkõ„Übd¡¹ÖJ¬/:› ú§õµûð¹$ÌÄ­ וˆ~<Ï«ç,~Ûw«/B¯¨v½ýºÅœ_—·…”š~´tÌ×>ù÷OÄ×£ÿqô ïßù´›·qy2kÞF箸\ýwÂÍ8Þõ.ú|)ò)vu|·îìúõ[HÜÚÌ„ŸÐ›<%èJS8rÍÍÊkZ†Ù>ä&¨^æk³éûä§³‘©‰·!‘ú®kžÒ??žçåŠm¡WT]_ÿ¯¸1§ÞJÛîÚ_ý 6+ßn7ÓqÅåÖtÚ,•åMóýÖôÕ¬¯ÛDÌü[‹¹­¯ÎzzF¡^üÓï¬÷þí@àhXEqß¿ÜßL™«qùKŸû^’KÏì 䋚Eêiw×ćÿÎi«Æl IÒ¡!ù›Ž¥íQAq‰O¸¬…JG™óyù$â ÈÔ¯Lm¼«F½jT2Htú¶)爳³J‹Ôc‹®ã‹:"¦m‡Z½„¦ßÿ"¥«ÒÓëÃôoÿÓ}7åUY–“É$ô:å"]H c-|sÝÿ”çì9Gt4EÖšL*ME®ãˆ+Ÿ8Û5[Üÿ6VçÚ³,á›æÔ•9ûŽ©îÐv¨ÕKhúý/ú ñ ]Uÿ±þïê–6./Ë*Õ¿øV´‚µæ#Ü3 ]Xв ¡yªÊ:E5²$Ç ZýâŠêæpáËçê_ƒÖ•u^¿ùIÁZDq+¶­·+?q Ô>û¯b ‡æUU½ðÙÿ4ãòªJv]×6®w‰¨"Šw>ý¤|ÇÑÐA…9*å)š'kÇæ¨ïºÇQûZ¯õ)êFë™>+¢´ÛŸïÍíÂ= …ãŽOõ#æMÖr–ÔütÞ]¸ï4õüuL법S¸)*Uo˜÷PºÂYëþêv­¢ÔýÍw]_Ì=]ÙÓò£®’·æ³}×\»bMGù´{üÛa礵gúB;qµ[&ËCóIUUeY}÷Ïþ«( 5.o.GŠhì!»Ú«ËKü­;»â%!.òºä X£9MŸašs“õÜèÿVŸ›ä;/] Zr⟸g–|ÖµËKÆ=ë8ÁR‹eÍh¸3\îÜ?t»çá:‰;®çIù·a¹©x¶™¸*Ž»¤¤§ÓÉdÚÄâß襪š´AyÂ)sa4!T’0Æ3lPŸxá¹sh¿Ý'èê<Ïþ4§‡æÖ[*Ó&N3¢‹ÄœÌ^l:BÊ®©ñ|*…fŒÅÇ?ÿµù ®Ç- ÷$,6²¢B ÍóŠhˆ#ü ‘W:óLÀjzíéGç6öŽ…ÜîÎ…+ýÁê†æ™|›\`Í-? 7C<Î<«ÔÍiÜä'8§4€þx®9fÍ’yì©g)š,:.?ú…€¥ Í···©À b¤¼Bsné¬&F@j(¸ ÈèKÞÂmmm5/¨ÀJa¤±Ü­"4*În­9°:ÔÕÉŒ€Ô –¯U„â -iðäÄ1UV–Ó!4Xò€cùÅm @˜5BIEQ,¹ 4`ä>ôà—|v{íéG)+€Ð ë[®}]–åt:­ªIUM&“ªª&kkî>ú¤œBY–Ödž¸¶#•ˆžÏG@hЭ@¯~²ªªªª¦ÓMP>™Lªj2vâu]›Ý,ožÚJ鬠vê‘Ð<ëž«íƒÒ6ÖˆËÒ¼ÞúdÀ’‚uch"qI ]ƒ\–`Æåídy—WUU–<ËX6㻪˲hçˆ`Ñ•~]¿骯c¿F7¾P\êÄ@D9/ÍWJpŽÓ7âòKY®Çå ¿N¾V»ëŒl©ޢˊîçÕÒ³²õÿÖª±îæªDóèÚÎTPn¦9·ã¦ï0_·-Ië\Ì /zÝú)ó¸A黦ÒÛíu}Ókí#êÚíæ„·õ#®ý]é[ß’ ÐÞ5R ¨…žålv|êO„Ú(¥½Õù%ÁRËé¸~Ò‘Û3ܘ2¿¾¾\Ë›w¼§`®/kqÅåêFõOäªÇ6Œé,=µš¬Uã³HÉZ‰Öd©PBó€NÄs‡¶!ÿ‹¡sFÁÚŽC.¶›"ã²,ÊòúŒµ+®bb×*5ìnÒöw¥/çSÛnîïSžÃ•³ÐC5í'¨GóL?è¸ÚvúD.j\~câü½¸<É”§Ù É]]V\T#”°\ÚýkY®2*”Ð<8:÷l4òºÏÔ„}:[v&K¥øÛ”m ?¸L’”³Ü—¹¾'ôÿê(§C÷ xž®­­­©÷}¶+Ï˲œLqæÆÈ5”*Äbl"4Ï¥qËÁÓüŸ^d.eéÏ3FW¨æA(ϸ‹ž5ïù•@ÞßsÅ<„ÒÖ—«qyªYóÎ9×ú=ôŽø}‰-„æñÁ´Ðh|ÚSÜÄ­ù)aUFª®*ºm– ´ϯ+ò—ó÷¸ Ô‘Y¿QÐc«L[_~s\^%œCõ—Hn P‰„æ}¿Ák³’þ¿ÂD7>õ[|ï #Ž´„­Ö.TŽ’­éÜÈÃõÕÞ®ZúÖý]ékéÓðjþ…‰á3õ/gŸiu·ë¶Ëˆi!á^ë‰kÍI[nî:(]'°â¬ëËÛ¸œÇkŒš0eÞ¾e®ŸtÝ *¬´ì%© Bó°oð}╞ N{ž¿N¬›­·`}$â(ò[}vVÿô,fω™$ªµ é¤Zßy£‚çÙ1â(Šbm퀺¾|2™´AyÚeÇ®©q¦WûG2 üé¹´íòø"ì@µšɾ2QJVÄÝGŸœOoãú嵿¡9?ÅkO?:·Ž%ÕŠzâßø²À¬ù˜`@0fÍ€,0kÌcO=K!€Ð`ÑqùÑ(,Uh¾½½M­V# 5äšó„&Àjb¤‚Û@€Œ¾ä-ÜÖÖVó‚ê¬F@jËÝ*B£âìÖšÓ¸«C]ÌH bùZE(žÐONSeeù8Bs€%ø0–/QÜ dYó!”,K~š€D>ôà—|v{íéG)+€Ð ë[®}]–åt:­ªIUM&“ªª&kkî>ú¤œBY–Ödž¸¶#J˜b$4§ÖK8.”eYUUUUÓé&(ŸL&U5™N»ñº®ÍÓaà#Ì ."4OÓVŠ!:tú¹–jÓw•ò@‰ ùï<îp§<ŸôCËvùIu:þùŒ;©¡Ûä|Ú¼g9 TïÉÏ1ÿö™O\ÞN–7qyUUeɳ€e3Ž«º3h.ËÒ?×WÃþéCµ¨±¶ó¸u=lÞ†N?´lçŸüKl>m2«r¨T“§¹ðö) Aìy\ç8}#.¿±”åz\Þð+äZ=œõK…ð£a\EËåf-^íƒAU`ÝS>Šz 9‡=f~¬¯ãNgŒAÝtmÚü%N ¦Û~ÇÕŸ͈G¤oKÄ2˜©NÚ\Qèġ֮„tÌhî=q¥®ó¬…òòÙytkþÍã …ì*Ï óu¥ïSAí$hj¹Ïù†¶7Ww§¾ežTôu$üfbÝîßÂCÛgŸô}š¨uW9È…&ç¿ç2åo6ƒˆ|¦úžàÙ«·»iûGŒ qãQ—O&•—7ïxº¾¬Å—«Õ?Y ÓûËg-—˜Oá ûÈ ú¤ íәᅄ‚ÚYDšV)9·™¬gÍÛVbݨM˜[ät„™ƒÐô…© mU‡ë¸å \#¢5ÞÒÒi÷ò=q¥¦ ž”ššyÜÐ|úÝÌ¿õ|åŸþ}fÜ…óRPß2 '´x6Ãþçkî/·[óÍ·Ú×¡í¼³Ýºö-7k½í34}WyºÚƒ«¾\åàºüóï—û\×BúÑùL2ªú fÔ=.ÇuÒJ\~câü½¸<ÉäŸõ”…”‰Ë‡ˆÝ­óÜý‹Ú'……WhÛÞÚo…÷¢†¥lŸ™Îš “ r¡kÓSAéûÏŠY‡y"3bÊ*.ÅÕrŽùn €<µïßNB£ÌùŸ¯ç×›Ú‰°hôqj=ëEøøê+ôÛËpå?h»›êö÷âŽ;®­­­©÷}¶+Ï˲œL¦A§À„wž6,´Ÿ HWkoK¶i‰×VešwþáÙÄ…tâz(ï5ˆz@–6dQS6ª9w¼ÍpÛL¡šù ry&9_!.m's>ß…W\èáúgoÎõb]­äZQ“ÿM“Ãå-U9,j\ˆ×´õåj\žjÖ\ŽrÌt‚ûÆE¡;GÏ=/YŒK•y¹[þ»zW—gM'´‡Òà»`÷Mh(g§ÿtcs …ŸïÐéx–g’P/ÉùöŸšís¾ÃM Ç}ÐûÐ9.ýE]ï=Sð\4·vÚY Âx:.„W[_~s\ž,4¯m\ïr'èÂõ¿Ç1·JTÒ‰øygÉÚdî·ªÓ Ú½8®ï…>Ó®ù’èôÍÙmœP'Y ÛêUuÿЛüät¬-¶]'ª~ÄzÜèhU8nD>}Šº3­FŠÀ§.²|‡\ÏvÒî#—OªóuµOs{çzŒÂ¸ Tûˆvc€ëº°¶ÛÎ|z–›µ^\'¥æ3.}Wþ c¾g9XëÝçzôYp"ÜÎë_þqùLu æØ=.¸ŽÛ1f[_ÞÆåDÉ£ Çšæ «ÿ=WÞ¶»–ýSÈyZ:ètÍ Ð…eûûä9Õùú'e-íÎà2US÷ÉgªÕV™ Ë3®ˆ|Ir¹ùw&þçqýöŒÔ£‡žÑ€çÇ×Ö¨ëË'“I”'œ2ÃÂòô$Uì~Xcžˆö櫞+“ó¯tŸœtæp±§°Z¡ù -CŒv€ë›ÿÄLεS üå\õò³w¡Þ}ôÉùœ»kA9kÍÓ]eÚh$y‚>é.$º”ÍA\šÆW;£®ýŽâ¯=ýèÜÎ%î-,°! ]/ËQïc< þ_ Ìšò%"@(fÍ€,0kÌcO=K!€Ð`ÑqùÑ(,Uh¾½½M­V# 5äšó„&Àjb¤‚Û@€Lä2k>·t ÈSÉï/@XК 4Íš„æÍBs„æ¡9Bs€Ð¡9@h WoêIDAT€Ðµi™¸víê;o_¾víJ]×Y•λï¼C6¼ïýÍ‹²,˲ªªÉûÞp2™fRŒs(%Ï 4ïë·/_»úöãßüöé3/¾üõâr×ÿôþ>¾ñÇûטé*£\£Væ0Qýæë?û»ÓßúþÞü«ÿïýµâòâÿì>öÔ³û•Có—b¦«PŒr ŒZ.kÍOŸyñ‹Ÿý½OÝóánûÕ_üâgïÛ<ó=WTºôÅØYã•E|S×û/ÿpö©{~­®÷ëº(ŠšŠqTý»ý%×b•U(F¹Íû*˪(Šk×ö Êå¸ôÊ»ï^y÷ç+\Œ%@hžÆþþ5!¦¼å–ƒÚ–Ÿÿür†zË-µŒÉ9÷?¯º®÷¯]½võjŸb4ØÎ̹kcæ%@hž$4/„°òòå7´€OÛ’Ù‰øæÜó¼êºÞ¯¯íï_íSŒg͹¹1ó©¬þÉ¡ZüOßáòå×<Ôõ©¹þwðà![®äœGœWÊbT¶ËR£”Õc.jùæEës뺾õÖÃo½µ×ü¿(Š[o=ܾÛliX·wîܹÑ~7gÕ•sŸwÕ-´ÅøÖ[{fNÔÂT_Œ¤Í“æµoLyÛm·¿ùæ¬Ùxë­‡›×ÍF5˜nþ´n÷ÙYÞhÍÏ›oδ‚Sõ¼li¯blòÖ¾¶~VË€¯¢Íû‡æûrh~Ûm·«¾ñÆO›h¯ÛÚŸêövÿέ)«­^›…ó2Ó}ë[AÅøÆ?UÛþÙ|öСjpu¶%@hÞ?4ï˜5ýõŸ˜û˯‹®U‡}ÐÜùõ×ÒnojÝØúÀîÔR;tèƒínòœ±p^F`Ú=iÜYŒZyªùlòïY€ÚŸù”¡yÿÐü½ÿ ;t¾¥íÖþiýøÞÞO¬;·Û?ð;Û×Ö®¤¾S>´ü®uÿæ¿>Åxø°%çÚYkgçʧyˆLJ`¤Fü„Ç[…ÏãG¾Ó½ñ½ê>Öí[{{?Örµ·÷cëQŒý‹ð¡¤-F½ˆ”œßôîxJ`”F|¨õ­ÙìG‡ÿB»}6ûQó–u»ÏÎòÆÎ¼5ÛÕ£˜÷\¡Q×ûý´h§¬eF+ÆÙìG®²Í¹Í“„æÎ¨k6»äzW{k6»¤¦*o÷عc£·fû͇°¦é»ž£Þ߯‹ý>Åhœ²Vµ-óíÆz%@hÞ×Õ+Wê¢.Š¢,nüïE²õþµ«WÞ}çê•+‹*Æ«W®Ž¢Íã•ey×ÿû•üú/ß¶_ï—EY–„æ7¦u½¿íê•+/ÿïì®;.¤/2Ï­ÍûšL¦þÁGÿæ¿=|ÿ‡?ñ‘;¨K`ZÔE]¿òoüý?_øó?úùã‹çžsïg™—À¨•9ÜTwõê•ýkïüí?ìüã¿~÷åΨ—»î8øÐ§?v⯬­\Íb”K€Ð@_Eš 4Íš„æÍBs„æÀü?ý8×26ºIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/simple-deploy-1.png0000644000175000017500000006656510014674771024744 0ustar frankiefrankie‰PNG  IHDRÀ"ˆO6ñsBITÛáOà IDATxœìÝy\•eþÿñ÷AÄ]S”£©(jZI2éTæš–“㌣mÚXÙb æVþ,³ÔÌËiŸ–o9e{5YYYäž™–¹R)! ྃ ç÷Ç ‡ãÙ8‡íl¯çƒGÃ}î뺯û¾OøæÃuß·Éb±€gÂ|=  / / / TÖ›&½i øMT£Àm «é£g3  £p_€¿ÊûFÛçëàWC³b®Tû[Õ¢¯‡å%Ûx¡ú-ÙM±CuþßU·‰ï†åÇŒ#v½÷7h2&MÑE ª§ÃjäcD¨@pfïõõí[®3‡e)ÖÉßµû5}ùÇsÖ¹Þ`‰¤äŒNekßrýªO:éÐF_(íú—Žíòõ  fQàÌ–e)‘y˜.š¯&uæ°ò¾Qús¾VeA¿¤P§÷)ï[mLÇv*íj]½]õšûzpÁ¥¤H?üCW.÷õ8 QàÌñtIºô55M’)\õZ(îovÎ:vó/oÏÑÚ›ô^¤>h¡ %© O«GêÝÆúà<ý4C²Ø7):ªïnÑûÍõn­ü³Nf¸XÆúª¯Þ‹ÒÛõôqmž¢3G<Ý©°zj¯óÇꪊꮂ|¥?ãEçÞŽ¶¤PÛÓgê†z§¡>»P;¨¤H’ާë­:z·‘Î:§É™#z·±ÞªSZÄ­Ä!õt/ŽkݽÛH´ÐÓË{°žPcµJ̯¢}_hïÝ­ãæÈ¸rbV×»õ~s}w‹ŠŽÚ¯û•¾ý“Þ‹Ò; õEoå®(ËÕN¹ibåæt»i^|J›§éãóõv„Þ‹ÔוýIù»Þ~†-ÅÚ¹HŸ'ëÝÆz§¡¾ê«¬Ï¤‹³Yá>ºÿ0H:ñ›¾ý“Þm¬÷"õÝ-*:îäSáfwÜ ™x!'>JÐÉ uDïrY£µ›Wj|{µr–•¯sÙÚ:[‡,_Òëu¸Ý]“†m4ô'ED;l¢µ7*ãMûa4í¬AëåÑ ­ö~¨UQó ^ïiç^¶¤P+úkÿûcúêÊå ‹Ðê‘Ê|_=æªëÿ+wÇmž¦6Ãuù]nÑÝ!õx/Ú\«¬ÊWH~Z‰w—¿kËØOæë\³CŸvW³®Ù®: œ´­ðÈ8*<¨Ï.Ô©¬ò%Öcr½Cô7„ÕÕ uŠîYñN9m"O·ÓækFë÷wœmÔûÏpI‘Ò†*÷+w»àêlz¸®šЧÝuz_ù[æaÊþ_ùÖ+Ü—ÇxT 8sÁLIÚ2S´ÐÇ´z”öü§‚¡¡0_Ãvéo'Õù^IZ³ÂêêšuªtÉoÿgßäØN þN£ 5x½'èT–¶ÏwÒó¯/+ãM5NÐåK5òˆFŸÑUÕ¢ŽíÔ¶¹^ï`Ëˤ²B»W{8Ú µ"¢õÇw4ò˜þv\}ÞTD”òÒ´s‘$u™.IéÏ–UËÙÒŠx—©çtåù!õ|/NçjØ/úÛI%Þ#I»—.·†c‚{%²NÓÎJœ “΋'GÆI“Çu*KÛ—ùcÛí׉û›®úA£ 5|¯ÚVIQiµÞÍN¹ibåæt»inäÑä§5ò¨FhÐZµ.Uê3¼ë_ÊýJu›*åýå€F–÷fåêlz¸®šoŸ¯ÓûÔ¤CÙøNGÏ=ìã>4gÎÿ»ú-ó0…7҉ߔù®ÖÕç=UWAÃ^ÿV“D…7T×é’Tt\½þ­¦T§Aé’£Ñç’çÔ¼—Â"Ô^ÑzÞË_¥ÖƒJ_ï_)Iœ¬ÙU‡6êê­ÕPÁ*>©Ÿ–¤Ø!^wîáh›$êÈå|ª¸‘å ©M;•/é:]+‡kÇ¥µð¤)&Wªç™$‹d©ÒHLuÔs‘VôÓÿ°ËÃ#c«q‚Žíträ­Œi»}ÞVìUªÛTEÇõ^¤Ý€ìwªâ&’\Ÿî ›‡7VÛj;B]¦éÃÖ:¸AªÔ jÚI‡TÖÇŠ¿ÞÓ&Vî£+Æaß¿F­ú—.±»ôÓ“Ýqz€ÀÇh{¦Šøz€@­Xž¢_žÓ±*)TÉÚ¤µ×K®#NUlœ ƒTR¤ƒßéû ’ÔÆÙ¬ï’¤´«µç?:µW–b•êxº~}Q_\êцJÎèäïÚó}ž¬#?«~Kuœàuç޶ÝhIúþNe¾«â“*>¡ßßÒÆ ’ÎIBmþ¤È.ÊùT™ï©~+%ÜäÑŽ¸RõC$©^´$å¥ÙßÏ[1Wªí'UñðÈØ2ªòŽGÞêìiIªS_uêëÄmo߃ãNUØÄàêt»oþÍå~Yºw¥s¦Ã¤J ã#ñý]ÚýªÎRÉX¯•ž]Šçá>ºb¾¦tÓ‡6ª¤H‡6êû»ÎY¡ÂÝqu€ÀGZ’¼ŠÅž¬ÌÍðnpR+2ÕQ÷ÙÕ¿­&‰ZžRþmÃ6êrŸ“ÕÎÿ»mVúÓZ7ÖëM8ÞȬQœ.û ü}žwîáh“&)g™ö¯ÑêQç,é«N©6ß›Ôå~­#K±:ýCaõ<ÚWªrˆÊGx¥2ß׊~¥ßz~;GýSÙËTRxÎBOŒm“iÊxSÇ-?ò±WëÄîòZVÖÒòXi$?÷;Uaƒ«Óí¾ù¾Ïµïós–ÄýEªÔ J¼G9Ÿ*w…Ö󴉕‡ûèJ—ûJçO~Ié’Ø«uü™Ê’C…»ãê8/Dt_T¶¸åmÿ50| æ]õƒ:ß«¨îªÓ@auÕЬ¸¿jàʹ UŸ7Õ~œ"š)¼‘Ú\«+Kï³ë(ù)õûRqUC³ÂêªNEvQÇ;4hGªÓ@ Û(v¨.yNWoStre:÷p´aõÔï+õxTQ¨N}Õi ¨îºp¾“[·è#IáÕñNö½*"I=ÿ¥¶QDt•¦p'(i’ýBÏŒU½æ°Rmþ¤ðFŠˆVûqê³äœR^RÛ o¨ˆ(³“ë\wªÂ&W§Û}óþ+Ôf¸"¢e Wãu¹_)/—¾åí ««¾Ÿé¢jÖCuê+¼¡búꊯlÇÃ}t¥Þy¸ªôV<ÆaOþ—TvOvÇÍq\¨‰·lG(c@hÇz³¯FRiA° ¡&Pt0•o‰Ñ$ ´5qâà]!F„¾ˆ0È"¦ÝÅŽ\_àŸ¯m$Ë€¶W‚²Ä¬"uYÛ[Ýùv$°`èP(?[Q‡à¼o´}¾nPÑq54+æJµ¿U-ú”¯àóg§Û©¬¥Ú»T7HFrh“~S¹_éXº,gÕ •ZüQïUtrÍœ ¤RéÙPË»\‰‚wHÀ¯íý¯VÿU–ûå¶!ÕçúÍsÈx2’7ý\2ÕQï7ÔntõŒ ¼0òf2Cµ¨öÃèm‡n ¦lyP–™‡é¢ùjÒQg+ï¥?çëa+²‹âF*n¤–uó´IóK”0V­¨q‚,gu,];(c‰~œN€à+SÁò³$“ÉëTň\k› µS Ô¸·#TR¤¿TD´óK¹ÖpÆúõeþQgO«a[µ®®("꜆#hÓ$í]ª’3j5@=ŸT£xI*>¥Ÿgiïû:•¥: Ô¼—:¥Ê|M£­J-¼ø„Þm¢ð†úÛÉÊ4€* ˜ t2²©c†®åˆ\½ÙŽ<˜…ø…fÌPú³êx—ê5÷¸™EkoTÆ›å Nü¦ •½LƒÖ•ghIknPβÒ×YKuh£†þ¤ˆh}7N¿¿Sº¼¤H¹_)÷«šš%RR¨ã¿içBIjw}l<@ÚOU%%ÄQrºƒ1rÀOí~UëÇI’Lj|¾¢{Ê|µÚ]§°ºåë8Ö}}IÆ«q‚.~R1}U§¡ŽlѩڿFIStÑ‚òVÛ«Ï›jv¡oÖšëtbºLÓ…óõN-PòÓJ£:õth“¶?®Ëÿ[Áh½­@Û–ÏÅ©ýmêrß9»µ(0ncjé¹B·|=:8­©Œ¯F°óÿ®þ_Ën³È$Y$‹Tö jdWÚ¨«·V\3Î_¥ÖƒJ_ï_)IJ¿ o¬¶#Ôv„ºLÓ‡­upC%ìá”è’bI*9SÉ­@•Q†?¢ xmyŠ~yNÇvª¤P%gth“Ö^/IM;•¯S/Z’òÒÊ''Þ%IiWkÏtj¯,Å*)Ôñtýú¢¾¸ôœþ7NÐÁ *)ÒÁïôýIj3L’¾¢Ü/U|RÅ'JgEWï¿,ß VÖG*ȗ嬊Ž*÷K­!I-þX[oÀLSÊ¡Œ³xÊÕû.{_m†—~»z¤2ß/רønü‡ÒŸvÞ§±‚ÑsìPå|ZþVÃ6¥·±sÜnüõê½Ä‹AÊmíÙi“zÍ5`¥"»¸l5Éh“—j„ðFtæcTìªÔù^EuW ««†fÅýUW–§gI=ÿ¥¶QDtùIÉO©ß—Šû«šVWu(²‹:Þ¡AëÎé¿Ï›j?NÍÞHm®Õ€•¥Olé¿Bm†+"Z¦p5NP—û•òruî× 5:ÿf5Š“)\áu’¦hèϤg>TKh¿zö‹õÃÃÇðª<5‚Q ^Dè&4“„à9Ûk ù䟫æí*4“{PÖ àsU Д™R*ÿ7q§Ñ™ÐŒÂí8€Ÿðº혛É4žV ÉÍð9ŠÐÀxT¶MÏÄ„²Š¤b{^Òs@xûí·cbbŒgûUçn Gžkù.ÂÕ²¹Êu÷öÛo÷îÝÛîu ßG™)À¸LTÁ÷ø·@Œ•sXXØÙ³g3hû:ÐâÁÇùŽàK϶L&Ó /¼qñÅoÙ²ÅX^TT4yòä-Z4kÖì‰'ž0ÜvÛm‘‘‘‘‘‘ãÇ/((°v2oÞ¼èèèV­Z-]ºtÞ¼yÍ›7oÕªÕ_|a]ÁýæNŸ>=vìØFµjÕjÁ‚Ž×úø=Û®-Z.iÏž=ÇoÒ¤Iýúõ‡ ’ŸŸ¯²”f4´¾¶’Ó= Áñ›hNtp§gÊ+V¯^}äÈ‘áÇßzë­ÆÂY³fmݺuÓ¦M»wïÎÌÌ4Θ1#''ç—_~IOOÏÈÈxà¬äååíÝ»wîܹ7Þxc^^^ffæÜ¹s'Ožìáæ|ðÁÇgddlÙ²eåÊ•Ž­Œão7õ|Æ ›6m*..–4lذÔÔÔüüüüüü.]ºLš4É®•Ó\í)<áäoâÁ:ÓÔ:Àd28p yóæ’N:YTT$©mÛ¶+V¬HLL´me6›ÓÒÒ:vì(i×®]ýúõËÎÎ6:9xð`tttaaaýúõ­¯5jd¤Û 7צM›o¿ý¶}ûö’~ýõ׎;:=¶ M&SNNNëÖ­÷îÔ©Sñññ¶EhǬ¯î©ÿ ÖO&,ö:ˆ3Šm¢µK¥Æ·áááÆì«ðððÂÂÂ:uêH*..nР+ ©žlζçºuëz m¿]¿~ý´iÓ6mÚtòäIãÝ’’OÆætOý_8@9g GˆO0mݺõîÝ»íÆÄÄìÙ³Çx½{÷˜êÚ\LLLFF†ñÚúÂ+#GŽœ0aBVVVIIÉÑ£G=O–N÷žp2:d+|cÇŽ½çž{²²²Ž9’ššj,¼îºë&Mš´ÿþüüüÔÔÔë®»®º67zôè{ï½÷Àû÷ï7¦/;ŠŠŠÚµk—«NŸ>Ñ AƒŒŒŒñãÇ{¾i§{êçBü·;à?*~Jèx衇’’’zôèqþùç'$$ ç̙ӡC‡Ž;¶iÓföìÙÕµ¹Ù³gGFFÆÅÅuëÖ­wïÞuëÖu\gÊ”)ÉÉÉ®²ã«¯¾:uêÔÆ÷ïßÿŠ+®ð|ÓN÷ÔŸ…Â…­ PØO±ÅvîÜ9tèP¦U¸Â'ø*оôüãСC¹¹¹S§N>|¸¯‡ã§HÏÀ¯œ ­wðÑ`BN§N’’’:vìØ´iÓGyÄ×ÃñG|€¿ ¡ÛØ!à0õø¡z ˆmá™"ð+ö( =¢3ðsN*Т][ìž,Êìæ:sX€ßrwŽ@¼~+Ç\CÜŠôôôAƒ5jÔ¨Q£Fƒ JOO7–[,–iÓ¦5kÖ,::zúôéµbMel’ž€?s ­ †<”FÕ»wïìì쬬¬”””Ñ£GË_|ñÅÕ«Woß¾}ëÖ­iii¯¼òŠç}š*ŶK™êÜU€ê沈ڪm2+((¸í¶Û"#####Ç_PPàØêìÙ³Ó§OoÙ²eÆ ¯¿þú“'OJ4hPZZš±ÂW_}uÍ5×HÚ³gÏðáÛ4iR¿~ý!C†äçç[·;oÞ¼èèèV­Z-]ºtÞ¼yÍ›7oÕªÕ_|a]aþüù11157n\aa¡'cpÜ»^x!>>>""ââ‹/Þ²e‹›¶Ž‡ÂÖÎ;§OŸÕ¬Y³3fìܹÓX¾xñâ9sæ´nÝ:66vîܹ¯½öšg¾JÈÍ °¸›ÂpÚ°m›1cFNNÎ/¿ü’žžž‘‘ñÀ8¶zôÑG7nܸiÓ¦¼¼¼zõêÝwß}’æÏŸŸššZ\\\TT4eÊ”'Ÿ|RÒ°aÃRSSóóóóóó»té2iÒ$k'yyy{÷î;wî7Þ˜———™™9wîÜÉ“'[WX¹rå–-[öìÙ³oß¾™3gz2G+V¬X½zõ‘#G†~ë­·ºiëx(lOâСCüñ£G9rdþüùC† 1–oÛ¶-99ÙxݳgÏmÛ¶yrزx¬Ò›ð‰Š/b ¬{ñÚ]–g6›ÓÒÒ:vì(i×®]ýúõËÎζk¿lÙ²®]»JÊËËëÑ£Gnn®¤o¼199¹¤¤$77÷ñÇ·kuêÔ©øøx£m2™<]XXX¿~}ëëF+üòË/:t”žžÞ¯_¿¬¬,ÛѺƒÝ®8p yóæÆÖ###‹ŠŠÜ´µ;¶ßfgg÷îÝ;33SRBBš5kZ·n-©N:EEEaaa’JJJ"""Œñ{{ ¬¯â3àî@‘È.5†‡‡Ö©SGRqqqƒ ŒÐi«nݺÖzmII‰Éd*))‘ôþûï?ôÐC'OžüüóÏ;wî,iýúõÓ¦MÛ´i“uš„±¦íF¾6™LÅÅŎð®àj nv­Â¶nnñ1xðà””£‚¾pá 6,_¾\RddäÞ½{›6m*éèÑ£ñññ‡öîØ ÏúÚÏ?3þÌ:àŸúöíëë!ÀÜMá°²› (3:$ÅÄÄìÙ³Çx½{÷ÇuZ·n‘‘Q\\|öìY#ƒË-Z4iÒ¤)S¦XËÏ#GŽœ0aBVVVIIÉÑ£G½Ê…¶ÃhÕª•‡cðD%Ú~ûí·3fÌˆŠŠŠŠŠš1cÆ·ß~k,ïÚµëÆ×?üðƒQÕ®W³Gà‰´2¾ ü¸M^f̘xàƒ>°X,3f̸å–[¼ÚGG‹ÅöãoŸÿdûƒ811ÑwT̸lZZ¥èâQÚ–]rz?2oUcU{Ê”)ÉÉÉÖÞæÌ™Ó¡C‡Ž;¶iÓföìÙŽMî¿ÿþË/¿|À€ 6¼ñÆGŒ!é‘G™3gN:uêÔ©óä“ON:UÒ«¯¾:uêÔÆ÷ïßÿŠ+®ðj`—_~ù\ЪU«Y³fy2¹jkw(l-Y²dÕªU±±±±±±«V­Z²d‰±üöÛoïÓ§O—.]ºvízÅWT=@+ÿ|á[‰‰‰¤gðÖ×Ô¡CJ•ž„ç& y~m¢· ‘'…äPà·¸ð+Æ`Ò3£M:tx1…Ñ›I®Þ­ëGcFG…HÏø¿*h+Ç$äIvlE¢ zv3é9ã àx=ÚC•{‚F°¡‰‰v˜ ³Ùìë!€?ª© ¸Ç}`.“˜˜xà 7ìÞ½Û'cpómåäææŽ?>)))!!aøðá_~ùeÕû€Jó—M„ MÔæj—½~ýúîÝ»O˜0Á×Ñãó_+áŽ;îhß¾ýÚµkwíÚ5uêÔÅ‹W½O¨4 ÐâT²  ºDGGOœ8qûöíÆ·f³ù¥—^ºä’Kâââ$N:µsçÎ;wž6mZaa¡±Ú™3gî½÷Þ:\xá…Ï?ÿ¼µ7WEåâââ‡~ø‚ .HJJzñÅ­oUp»•]mÔl6¿þúë)))íÚµø !!AÒo¿ý6räÈM›6IêÙ³ç|/i÷îÝ—]v™‘ƒÍf³m ¶~›œœüî»ïžþ”s IDATùvcpº²«šÍæ­[·6kÖLÒéÓ§;wîüûï¿ÛíWnnî‚ ¾þúë‚‚‚þýû?øàƒ111’RRRþóŸÿ\Ý¿ÿÀüñG»ý}õÕW7nÜøì³ÏJºë®»RRRÆŽëICÀsÜ:ÔTÏmì~ÂÕœcÛPxàÀë…víÚüã[·n=mÚ4cù”)Sš7oÞ«W¯þýû÷éÓǺþ‚ >ÿüóÎ;6¬wïÞÖå“'OîØ±ã€þð‡?Xç~ÜyçC† q¼ý³«zbìØ± ,èܹsïÞ½·mÛöÜsÏËï¾ûî”””Q£Fµoßþž{î:t¨Óæ—_~ù±cÇNžD€Fð C€Z@€F@ru;34Q;˜Íf³ÙìëQBªÒÚX *‡© €9>]Åàê+<Š%˜dggûz€EÁÉ1XSrögÆ|Œ÷ßÿÊ+¯ŒïÝ»÷|`÷naaáC=Ô½{÷¶mÛÊa ‡ñí’%K.½ôÒøøøþýûñÅóçÏ¿øâ‹Ûµk7tèÐmÛ¶Ùnñ£>2š$$$\vÙe?þø™3g\mnèСf³ùã?¶6ÿôÓOÍfó€jö¸üÍM Ù61»JϤj¿òöÛo¿óÎ;ßÿ½ÙlþÇ?þ±bÅ Ûw_ýõ›nºé§Ÿ~Ú»w¯«Ö®]ûÅ_<ûì³;wîüûßÿþûï¿ûí·Ï=÷ÜO?ý4qâDÛ5wíÚõúë¯ÿòË/Û¶m3fÌ¿þõ¯GyÄÕæÆŽ+éÝwßµ¾ûßÿþWÒ_þò—jÙq@`áOØnr°«ivëT÷ˆ*)--MRbb¢¯RS\=ÊÛ¨%úé§=zôôÓO? :´W¯^FN5Þ]±bEçÎíšX'rß®]»¶]»víÛ·—´fÍšøøø’’’¸¸¸°°°ÌÌL§£*))iÛ¶íyç÷ÓO?9Ý\AAAÏž=?þý÷ßÇÄÄ;v¬GÅÅÅßÿ}«V­ªíèžÜŽÐ‘žž.©oß¾¾j h9jÌ$))ÉöÅÏ?ÿlû®'¿W³;êׯo|'),,Ìb±œ={ÖºZ^^Þ½÷Þ›œœÜ®];³Ùl´:xð «ÍÕ¯_Ô¨QgÏž5&–|òÉ'gΜ¹ôÒKIÏšÐU,!²BXXÅ?¯ìÖqÕäŽ;îx÷Ýw¯¿þúŸþ9;;Û¨LÛ}ŠìÚŽ;Öd2½÷Þ{’>üðC1BA‚ ¶oßn¼Ø±c‡¤ .¸ †6´yófI&LhÚ´©¤ü±Â&íÚµëÛ·ozzú§Ÿ~º~ýúúõë:´††ðsh2t ›3gN~~þæÎ+éî»ï®¡ ]xá…’/^\PP°cÇŽÉ“'{Òʸ”pÊ”)‹eàÀMš4©¡áü€¿5jÔ_ÿúמ={fee=õÔSýû÷¯¡ ½ð C† ùç?ÿ™”””šššššêI«þýû·iÓæèÑ£bþ„6îÂ`SÅB²oÿñ»pøÿ³Qžzê©ùóçGGGoÞ¼9<œQU€»p tpŽPCÁ†‰¨!'NœØ´i“¤É“'“ž ”ño‚'÷~¼2jÔ¨Õ«WGGG?úè£Ædh@È"@#D¹ Ù&S›j›ÿOÞxçw|=„:Ûg×WŽÿÿ 4‚“û"´‘ÉÐüYÕs…©Ê!@#h¹ÊǶɘÉüGʼn¹Š¿×;ü´³Û"yð¡Å±®ì*CS„P;Üåæêý!d×›ëR©«t…t‹/Ç š}&u“"¤xÉzÇ¿³Òt©¥ÔPº^:Y¶Ü$-’â$“ÔÁ&.[¤öÒ›ßÉ‹¤ÉR ©™ôDEÝr«ÀKhÀ§lËE¥Ò)é”´BêT¶Ü$-K‡¥Ç*û'ÚÀT:‡;”vÙÇ,3ÈkÙi–t\Z)}_¶ðQi£´IÊ“êI÷Ù¬¿AÚ$Y¤¦Ò7e ¿–šIÝmV›%m•6I»¥ÌŠºåV?€—ÐøNC)[ʓ⤗ʾ"-’ÚHM¤Ç¤÷mÖ_('I'½\¶ðeiܹÝþGzZj+5“UÔ-·ú¼D€à×(BûEèÚó¾´Bê)ÅIKËfK=¤p©ŽÔJÊ·Y¿uÙ‹¤O¥CÒAéséús»Ý'ï°-WÝ·ú1xs« d 6¸”°–]"},í—þ-ÝY¶°µ”!Kg%‹Tâ¬a3i°ôºôº4TŠ:÷ÝÖÒn‡&®ºåV?€—ÐEh¥ë¤íÒ©D:[¶ðé6éW©XÚæP]¶2fq¼â0CÒXé)K:"¥VÔ-·ú¼D€àïýq0‡K kÓµÒ©‘t¿ôFÙÂû¥Ë¥RCéFi„‹¶¥£Ò ©ŸÃ[IIRé|)¡¢n¹Õà%žD€ïŒ–F;, “¦KÓ–[VËt±B]i‘Íåƒî»5nõ³À‹Q!Ž 4€àËK CxêEhpŠ l’§[x3—€kh¡JEèO¤kªu45Ú-OcÿF€j†©ìËîÛý²Ýl-“®‘:J;%I™R˜”#IÚ)u”äú)Ç’æK1R#iœTèЭçiÌ{¤áR©¾4äÜ» ;âRBp ÐxûëA¾”.]& ‘Ò$IŸHõ¤O$IßHC%¹}xòJi‹´GÚ'ÍtèVó4æaRª”/åK]¤I<€#“ÅÂL7À_¤¥¥IJL¬‰yµ~Á(gæääTº³Ù,y9Éá5i™ôžô™´Xz[ºZê&m—þ'’þ.]%ÅKËÊ!‘'õr%I&驃$)]ê'eÛ­¤vÒ$éÏRœÍvÝt˜Sö<¹g¤µÒ›’¤ë¤Ë¤»$SÙ¶•V8L³vÕm©¨¬*R"EHÅnË))¾¢"tÙï*®N™qB]Ýg°ê§;°TæÃ4LRhßq2==]Rß¾}}=Ô*ЂÝ'ÒÕ’¤¾Òé”´Nš.­•NI¤¾’Ü><ÙzÝó¥<‡nåßOc¶á³^º\j,™¤FÒ×ÍšY*B€H¼¾”°HZQ6I£ÔIzVê)EI=¥§¥$©¾$·OÞSöb·ÔÊ¡[ù÷Ó˜-e_’FJ¤,©D:J>€J"@j+¥NR˲o‡Hó¤’¤AÒwÑ¡† ¨ˆE2)666¤æcTš5M–&ikÖ ‚$Mn$q!€åõýì€Z—}NÄ4ò'öÜÁÛïb¨@<@º²~^UgÀ@ * íÉ¥„€¯9ÑòãO¯C±œè X ^ ]öÓ£å—iJÎ@EÐEèÚa ä)¼~Æ Ò”œ 0îg‡€æ² íJãµg¿ÿ›  ãRša_v¥†ÿ@t8wîܹsço­Ü©¯¾úÊd2Mœ8qÁ‚3fÌðpÓ|ü€Êa4€ÀcMÏ9çòí¨<átÀÁQJG¥½ôÒK‡¾öÚk“’’î¾ûî¼¼<§«½õÖ[?üpëÖ­7nüÿþßÿ[¶l™õ­Q‹-Î;ï¼GyäÃ?¬­¡‹ 4€c›ž};’ªËÉÉq¬I#Ô´jÕjáÂ…’òóóŸyæ™Ûo¿}éÒ¥Ž«åææs£-KII‰Éd²¾•ÐBF莋‹;pà€ç›¦ü TpÂö_¦€Äÿ:Azì´lÙòþûïOJJrõîÇܺukÇ·öìWCIRfff‹-jrŒ$¦p€o¿ 0‹#”3fݺu………‡zæ™gºuëf,oÚ´éo¿ýf]í¦›nš:ujFFFqqñ®]»&L˜`}kâë:pàÀfΜ9bÄÏ7ͨ*ЀKv·¨1ªÒþyßDZK ~cÇŽ]°`ÁæÍ›ëÕ«—’’òÜsÏËï¼óÎ!C†œ?¾ÄmìB S8/ / `–%¾z¸ˆü‚ßÞÉÙ`‡ 4À¿Möà+T ÀÇüùŽ"!ò Ä>úhæÌ™¨b¹Ýl6S°wŠ#ƒ C„ÌeGeÜeÌ•9sæ¼òÊ+µ“ðrssÇŸ”””0|øð/¿üÒ:àªt[-(0ŽX»ví.¾øâ;î¸cÛ¶mµ³] à Á);;;;;û‡~èÝ»÷ÝwßífÍ}ûöõìÙ³vFuÇw´oß~íÚµ»víš:uêâÅ‹«¥ÛêJÿÙÙÙ{öìùì³Ïzõê5räÈ-[¶TK·@!@‚Y“&Mî¼óN£}öìÙyóæuïÞ½}ûö&L8uꔌ‘X,mÚ´1Š©f³ù¥—^ºä’Kâââ\5‘ôõ×_÷ëׯ]»v)))o¼ñ†us¯¿þzJJJ»ví¼cÇÇñlÞ¼955µY³f}úô1ÚZ7m-èfffŽ7.111!!áÆolIÏ>ûl=:tè0iÒ¤3gθ_ßéáuu.€ÚÇ“'ªø$ÂôtÝ}·Ö¬‘¤>}ôÌ3JL,m{ß}zé%™Lºýv=úhyŸN—[Ç]áF÷I„üý·–y;ß:pŸ’ht{üøñW^yåË/¿\¶lÙ¢E‹Ö¯_ÿä“O6iÒäÁlذáܹsuî ]³Ù<|øðÙ³gGGGKrÕä‚ .xì±Ç¸ÿþE‹-X°Àh{õÕW?üðÃQQQ/¼ðÂW_}µlÙ2» 6,%%e̘1F@w°¡_¿~sæÌ¹øâ‹‹ŠŠžxâ‰<ýôÓ’yä‘Ý»w/\¸Ðb±Lž<ù«¯¾2ncgº¡ô4¹ƒcCÇÓj7†üüüþýûÿüóÏnÆãá°Ífs¿~ýžxâ “É4qâĤ¤¤3f¸Yßéáuu.üO" 5hÀ‰*è‹.Òµ×jâDY,zâ -[¦M›$éßÿÖâÅúàY,úË_tË-ºõVwË­Û%@£zy£:@[_ÇÄÄ|ôÑGmÛ¶MIIùÏþÓ©S'Iû÷ï8pà?þ(‡½yóæ–-[ߺjÒ«W¯ñãÇ2ÄvCf³yëÖ­Íš5“túôéÎ;ÿþûïvËÍÍ]°`Á×_]PPпÿ|0&&Fn/³;}útJJŠ1›¢gÏž~øa»ví$eddôéÓÇ1@;ƒcà tqqqûöíwÁv<Ûl6¯Y³&>>^ÒîÝ»GŽùÃ?¸Yßéáuu.ü:Ô0…¨~;wjútEE©Y3͘¡;K—/^¬9sÔºµbc5w®^{­‚å¡Ãbá«–¾BJvvvVV–‘ÛvîÜ))77wàÀqqqmÛ¶½ð m'ز¦g7M^|ñÅÕ«W_uÕU—\rÉçŸn]ßH®’4hP\\ìØy«V­.\¸yóæo¿ý6::úöÛow:†M›61¢cÇŽf³¹C‡‡2–ïß¿¿M›6Ækë ;NÇàIC;‡ŠŒŒt?‡-©mÛ¶Æ‹¸¸8ëatµ¾ÓÃëáéj¨Öé’†ÕãëèQ9¢ùó5dHéòmÛ”œ\úºgOY/pwµ@™L¦øøø§Ÿ~zÚ´i'OžlÙ²åwß}—™™¹wï^#^W؃«&^xák¯½öóÏ?ÏŸ?úôé•[Ë–-ï¿ÿþÍ›7;}wüøñ7ß|ó?ü••µsçN럋Ï;ï<ë<¿U%.[¶¬W¯^îÇãá°%íÝ»×x‘™™Ù¢E ÷ë;=¼•8}@ !@Õï©§ôòË¥èÅ‹õÌ3¥ËOœPãÆ¥¯›4Ññã,Æmý@2òIˆÜÝÙÊl6'''ÿ÷¿ÿ½é¦›¦Nš‘‘Q\\¼k×® &TØÖU“»îº+==½¨¨Èb±œ={ÖóÁŒ3fݺu………‡zæ™gºuëf,oÚ´éo¿ýf]­   nݺõë×ß»wï´iӬ˯½öÚ‡zèСCœ5k–çÛõ¼aIII~~þ«¯¾ºpá‰'º‡Ã–dÜiûÀ3gÎ1b„ûõÞJœ> † êa[Ž7NcÇêða>¬nÐÍ7—.oÜX'N”¾>~\MšT°@u¹á†–,Yr÷Ýw§¤¤Œ5ª}ûö÷ÜsÏСC+lèªÉàÁƒo½õÖ:<úè£Æuo;vì‚ :wîÜ»wïmÛ¶=÷ÜsÆò;ï¼ÓvÊï“O>9{öìŽ;Ž5êÒK/µ6Ÿ6mZÓ¦M/¹ä’~ýú%''‡‡{ú@4šÍæøøøÁƒ÷Ýwï½÷ž5ß»‡Ã–ô‡?ü¡ÿþøÃZ´h1yòd÷ë;=¼•8}@ á"BÀ‰*^DX¿¾ŽU½z’TP ¨(HRïÞš3GýúIÒ×_kæL­^ín¹u»n4p/"4ÿúòÓ¨vXš" IDATëýž\J¸†‚_ýõ¦›nú}^¦¤œ¾^œ#£áºuëjlh!‡‹C h zØNBèÚUóæéÈ9¢ÇSYGcÆè´oŸrr4cFyeÚÕr &ð‹J {ðÁ9’ŸŸ?{öìÁƒ×BCvÐ@õ[²D«V)6V±±ZµJK–”.¿ývõé£.]Ôµ«®¸B·ÜRÁr“©ü†Ð¡0K8ö¨ºöíÛ_qÅüã›4i2uêÔZhÀS8'ª8…£öú1‹£ÖŸ gq0…ÃÿŦ™ååT;¦p„*ЀÐü‚ïgLSG¼Ý—P»ŸT 4€`°i“¦ÛÊEv‹EÓ¦©Y3EGkúôªNwa¶ T€¿¨Jú“OtÍ5Õ<žšë¶ráõŵzµ¶o×Ö­JKÓ+¯T÷°ž!@Ë–éškÔ±£vÌL……ɸ@nçNuì(IgÏjútµl©† uýõ:y²¼ùüùЉQ£F7N……öÝJúì3u릈ÅÇëÅKßuաɤE‹'“I:”Çe‹EíÛkË–ò_ŠŠ4y²Z´P³fz≠º]¼Xsæ¨ukÅÆjî\½öšóCáj_…æS  êÐüŽ·Eèü|¥§ë²Ë4dˆÒÒ$é“OT¯ž>ùD’¾ùFÆË}T7jÓ&åå©^=Ýw_y+WjËíÙ£}û4s¦}·’ƌѬY:~\+WêûïKWpÓᆠڴI‹š6Õ7ß”.üúk5k¦îÝËW›5K[·jÓ&íÞ­ÌÌ ºÝ¶MÉÉ¥¯{öÔ¶mΆÓ}T#nc8Ámì|¨÷³{í5-[¦÷ÞÓgŸiñb½ý¶®¾Zݺiûvýï5Jÿ»®ºJññZ¶L]»JR^žzôPn®$™Lúåuè Iééê×OYYçt+©];Mš¤?ÿYqqåÛuÓaNŽZ·–¤gžÑÚµzóMIºî:]v™îº«üé’mÛjÅ ûiÖ®º­SGEE “¤’ED¨¸ØþP¸ÚW*|*!·±óÜÆÎp»PC€œ @ûP%ô_ÿªk®ÑÍ7ëôiuíª­[Õ¦vïVûöÚ»W]»jÇÕ¯¯ºuK»µXTR"“I%%’d2©¸XuêHRq±4PQÑ9ÝJúþ{Íž­uëÔ žzJÇKrסuü‡+!A»wËbQ‡Ú³GQQå+„‡« @ááç쎫n##µw¯š6•¤£G¯Ã‡K7g°X\î‹îoM€öh@€5Láà_¼½”°¨H+V”NÒhÐ@:éÙgÕ³§¢¢Ô³§ž~ZIIª__’Z·VF†Š‹uöli6µÚ³§ôÅîÝjÕʾ[I—\¢?Öþýú÷¿uç¥ ÝthÕ¬™Öë¯ëõ×5t¨¢¢Îy·ukíÞmßÄU·]»jãÆÒ×?üPZ¢–d±”~¹Ú@õ"@.ж~9]è'_Žc +WªS'µlYúí!š7OJÒ Aš7OC†”¾uǺí6ýú«Š‹µm›®¿¾¼“‰•Ÿ¯ü|¥¦ê†œt{ÝuÚ¾]gΨ¤DgÏVÜ¡­qãôòËzågÿÖØ±ºçeeéÈ¥¦VÐí˜1zàíÛ§œ͘QZwä¸/îq)!x‹ ÀïxU„þä]}uù·C†èða  IêèÑò}ÿýºür  † uã1¢¼Õå—ë‚ ” V­4k–“n¯½V#F¨Q#Ý¿Þx£âmÃ8qBýúÙ¿õÐCJJR:ÿ|%$TÐíí·«Ou颮]uźåç›sÜ@õb4àGÒÒÒ$%ÖÄ£;ç3¡õÎ;ºè¢j@ uë·\Í„f´ÿc´?`t¨ ¯xðÛ«ñ\IO¯‘M×P·€ Àþˆ’'Ào \J^ @ðSÞÞÏ€ÚA€H¡Àchþ‹"4À ç  еƒ€'Ðü÷³ø4 —@…Ðü—ü àEhp… P„®M\Jî / ŠÐµƒK À 4€ÀÀýì~‚ x `p)amâRBp… x P„®M¡À©p_*ƒ ð*Ðw¸ÿ Ø¡ Àç¾EðððððððððððððððB¸¯¼›f®paNßìÚЍ@HÇ€ÏQ ¨°CGZZš¯‡Zúöík¼ @`rúf;ÈAnöãÈ÷íÛ— @ð üôlÓsbb¢ïŠÒÓÓ%¥¥¥1€ÀCPq‰‰‰¤çÚg=ìh‚©¨hq9ó7¨=û€`@žj €@Eh|‚ @À#Iµ‰ @#:µû@ÿ¿½;‹²Üÿ?þ™@QÂpE •\:®Õ9iFÚæNuÑ"q9œ H\Ê-Ë¥ÈÒc‹™Ke™~ëûëÍåT*Òrü©YyJ7: *xTBÀ˜ï÷8޳13 ÌÌ=¯çÃ?nî¹ïë¾®™ûö~Ï5×}ßááð\‰ÂB²jçÐÎlÇ*ì‡@ x*HÌFLëL”ñr.ÙÍn”]уüú믙™™ûöíkÕªUzzz\\œò™FEE=÷ÜsIII"2uêÔU«V]¸pAøpë€G2›ŠŠŠ¾&v 3šιÍKØ••µÕ_ED3ÖÌLRµIII‰_·nÝW_}5qâĸ¸¸ìììÑ£GõÕWW¯^ ýÇ?þñàƒ.[¶lÈ!®®¬:i´Z­«ë@‡|ÚH¦wÿÄl>OSÔÊ–Ð\¯YÙvfSµ!öR+”'<ÇÄÄÔ÷†”Óă>˜——`øRjjê]wÝUQQ‘››ûÚk¯mÙ²åõ×_×h4™™™=ôP}WÌ«äççÓ Àè&=‹HQQ‘iŸ4<šõÄì&YÙ,ÓºEj£¦‘§]¨[·nŸ}öÙÈ‘#}}¯¹ŒŒŒ„„„ªªª7ŠÈ!C† ’“““œœœ——çºÊª€GRAz†:xnb®•QåÉÓîcùòåÏ>ûìŒ3‚ƒƒŸxâ‰éÓ§‹HddäwÞéçç×®];¹ö…„„üå/qquÕˆ ®¤tB3ÚãXÊ͘­³1O³'7€Ûn»í³Ï>3¿dÉý4D½"@`+³¹Yš٠ÃV†i’4¼€Z˜æfï Í–˜ Ó$i¨óÈÍпE$i¨€ë¤á,V’´¦ááÐè¥gr³S˜&iÀÓ À-¸í“ɽ¹§PøHÒuAn†ú Öxá-öL{LIÒ0ÍÍÊ»Gž†  ÀÅÜù¡0^þ D’´,åf@MÐÔÂJ’¢…NeÞ¨[™½Îk»¥ÉÍðZhìf=I‹zs¤¥Ìjm/`€+9|ë /›ë0woí¡,=ÑZeÝÒt6†ÐàE”/Äèz¢²ni:›KЀÆÕUpO¹ûçãÃÄF­ÝÒv•àtì¤Ámo'Ÿ@ ÐÔ#ÇžÃç&_uÈÍ€YhÀ"£3‡r>sÏÓ‰iÝÜäì[«ÂÂÂððpÍX7}cÕGû‘hÆJXX£8ží;y¿q*¦Õj-½¤ü¾jeˆm¿B p/¤[ÔE­ùO5Ã]è&WW€·SÆ™yJ—¹jpp=Ðà]”QÔŠ!udK==а ?÷ êm“‘#G6kÖ,  _¿~›7oVæ;1VnÛ¶-&&& à–[n=z´õ›§ẖ}[ÖÞ¾}{Ïž=ýýý£££?øàÛ‹æ)·ÛS eˆ-£8À1h›ÄÅÅuêÔéèÑ£¥¥¥óçÏë­·œ¾‰¬¬¬´´´Ó§Oÿúë¯wÜqÇÈ‘#­,¬½ÆhºîöìÙ“˜˜¸xñâ²²²­[·îÚµË)ŨÚ&{÷î5kVhh¨¿¿ÿ€¶mÛ&×úq {«««gΜٲeËÆ3¦¼¼\™¯Ñh^~ùåV­Z%&&^¾|Ùt;wî|ôÑGCBBš6m:uêÔ~øÁ®ZÚô¶mÛºuëæçç¹råJ³Õ6´hÑ¢E‹=üðÃ~~~QQQk×®Õ¿´bÅŠÈÈH??¿^½zõÔSAAA­[·ÎÊʪõ­3­?ÔÊ /%t«ÊÔ:¡Àh›ôîÝ{îܹ'Nœ0œiجÌY¸páþýû8pæÌÿéÓ§ëÎÉÉ9xðà‰'N:5gÎ+Û*//_ºtéÀ•?m›aiÓ óæÍ+++ËÉÉÙ·oŸÙjúî»ï dv;vìøæ›o.\¸;aÂeæ°aÃÒÒÒŠ‹‹‹‹‹»té’‘‘a}ùÙ³gŸ?¾  ààÁƒ999Ô°ËéôlC[ÇäÝ0Á¥€Ã4\‰i‹ÂÂÂ9sælÛ¶­²²rðàÁYYYJ·FsùeË–®]»ŠÈ™3gºwï~úôie±#GŽtèÐADòóó pòäI³RârË–-¿ýö[ey£M˜.¯¼jiÓíÛ·ÏÈÈxôÑG#""L×2åëë{ùòeÓ ={644TD***n¾ùæ«W¯-SQQ©tB[Z¾mÛ¶»wŠ‘£GvìØÑú×ÕzˆÈk{¾î:eÏŠÇ-VžCëÄ7yþÿ“ òÚެkåñ.Ö‹õ”çÂ(;‰õ'ª(ÿ×yÜŽä0§ï0å¡ÿ;Y—ŸŸ/"111õ½¡ììléÔ©“ÙWu;0wá¨å]²²‹æççÓm“ðððÕ«W>|¸yóæ£F2»Xaaa÷îÝ}}}}||Z·n­Ï "·Þz«2qÛm·9sÆÒ†´Zmiié_ÿú×ÄÄDý[jhiÓŸ~úéŽ;z÷îñ÷¿ÿ½ÖrBBBÎ;gö%% ‹HãÆ«ªª”é={öôïß¿I“&&((èìÙ³Ö—?}útdd¤2­Ÿpbýí°^£KÒPµ-?ÊОÒ1Cr‹DDþó_¹é ):/"’[$3DDªkdæFi9E—1oJ¹Á«—7K«)4^WÊå«ÆÅŠÈ¶Ÿ¤ÛtñKÈ4Y¹SäZ8ÐŒ½Þ‘|¢Db_“¦I0N½"Å¿ëæW^‘§VHÐxiýÉúüúò†+vHdšø%H¯çåàjYÑ^\JŽ!@Û§uëÖ .Ü»w¯ÙWÛ´iSPPPUUU]]­Õjkjjô/é‡?~¼uëÖV6,"òùñ÷•ÏÙuH÷YøÙ\,3o‹¿¯Lÿøz 9¹rp±œX&§.ÈœO‹‘„·eÞãR¶ZræÈ¾ã"×R©ö£ë½˜Ã^•´G¤øm)~[º„KƇºù³?‘óåR°L.–œ\óMØñ³|3W.¬’ØÞ2á];VÔ¤b“¡C‡fffÞ}÷Ý/^\¶lY=”ù!!!yyyÑÑÑÊŸ“'ONNN^¾|yddd^^Þ‚ Ö¯_¯¼ôÌ3ϬY³FDÒÒÒÆŽ5“ž|òÉçž{®cÇŽ%%%¯¾úê=÷ܣ̷>„CÏÒ¦ãããgϞݡC‡šššêêj³Õ64}úô?ÿùÏmÚ´‰‰‰ùí·ß^zé%ÃëMUVVúùùÌœ9³ÖzŽ=:==}Íš5Z­ÖpÀ´]õw>uØ%n¹Œè-ÿ“*Z­¼¶UF¿!ˆˆ¬Ü)ßäÉ¡,Ñjåñ¥²:[&ÜïÈ|Í;×㮼,,,T~‚tŠ­?Êݤ‘ ê.ïçÈä²åGI}X6‰$û°Œï/"²:[¶dJÛ[DD–î3åqº–%H«›ED–=)ÈËñ7+"ý¤ðœœù]"BåÝ æ«ñó˺‰@‘GJdšîÏ ÿ’ݳ¥E°ˆÈëOêb½‘IÚDDdêPyñïv¬h—°°0ë9Pê£ÕÊô òîNÑhdÒ@Y8Jl¼‹iGyÊÀ$ a m2eʔٳgïÝ»×ßß¿ÿþ¬ë¡š:ujŸ>}.^¼¨dÜ3fh4šx ¨¨¨k×®Ï?ÿ¼¾„þýûßqÇ/^5jÔ¼yóL71|øð¸¸¸Ã‡‡††>òÈ#6l°«†–6=bĈÇ{ìØ±c·ß~û‡~h¶Ú†î¹çžU«VM›6íðáófͲ¾Ýµkצ§§5ª]»v™™™7n´¾ü‹/¾8iÒ¤ˆˆˆ¦M›¦§§oß¾Ýîú×߸ çÅèÜ"Ùó‚ø7y>V–\ëÓÿkyi¤´ Y0Jæ|ª Äö·>ÿA7Ð"¦³¤¬•Š+ò¯#òQŠD¥KÅÙ{LÞŸ,"Rx^ºÏÑj¥F{C¹µ…nâ¶–ræwãbEäÓgäÅÏ䥿K Ÿü-Abû˜©Æž£2m½(Ð Ñ—ºT"¯•ÙÜ|”ô,"ý¤êÚWH[V´O%t!Çòh¿W;Œô 7gc‡£Ó6Ç@òÐÀª§ÈÍÍK—î3uºZ-36È_KUµÌ~T2[+öžyòÒHÐUDdç/2çSùÆä@7­§á×$e£'J$}ìøE®VËý]äýɺ]ºòŠL^#Ÿþi(Ï–i›Ù-ßN”Å›¤è¼tk'ïM’?DX[ÑÖE½^D˜——÷ðð¬'†¹¨Á6ª(,,Œ‹‹Û·oßwÞ¹qãF³¿yr!ÜQjjê¹sçNŸ>™™k÷úc´uýgKùuó·§dÕ. I–fÉò~Îõñ/I“ÝtÓ@)»äà|½ð 6@rr%:ìzÌÔ]m’ïyèY´Iu×½4y $¯’£g¤ªZ~9)cÞ¼^È3ë¤øw)þ]ÒÖÉØ¾fŠCÊ•*©©‘êkW=„4–¼S× ©¼"~¾ØH ÎÊÄU×çþ“¤(gˤä÷ë£máðŠfq)¡íL‡¼‹Õ1ô{É¢ýH‚e×!Ý̇¤Y.t*æý¯üü›X Ç—Êþ[K±¿œ”>·é¦{ß*¿˜»¥Cóá˜Ý»w÷ïß_Ý:uê½÷Þ[ZZÚ¯_¿ÌÌL‡ËaZtttçÎ+**†>þ|WWÇ@Ýr³a_Kâ;òT]7Ò’-2n…üs†ˆH“¹xI×£\V)M¯…c{çÛnâĉ¶Ç¥”‘ÐusùùÒãúŸƒºKÚò@7‘ïÌõ2èÚ«3†‹f³<°PŠÎK×¶ò¼Á׺þ·ËÓåâ%õG™÷¸™bGô–Ç^—cÅr{ùð/º™S‡HŸYrñ’®þk'Iú‡2êoÒîÉ*÷è{q¤LZ-©Ò4@ÒÉöŸlmšÃ+¢ŽÌy·2†~ÉXiÞTD$ñ>Y•­ë6^µKﻡؾ–ÏI»P‘¥OÖR¬-ß«Õ14 o÷îÝ ‘~ø!))éàÁƒÕÕÕ¹¹¹÷ßÿ±cÇ+++£¢¢²³³?þøã7ÞxC¹õ–V«Õh4O?ýôŠ+®\¹òý÷ß'&&:t¨K—.ï½÷^Ïž=æôêÕK úÂõ}á… Ë<|øpRRÒþýûo½õÖ5kÖôíÛW¿•ÿûߦUŠŽŽÖjµ†57[ÈW_}õóÏ?¤§§wëÖÍá÷ŠÝ¿a(%%%%%ÅÕµ¸‘ó.TìΕMÏ^’¬›ßµ­ì?®;‰~Bº¶up>l±åGÙøôõ?;¶¾Ç»GÜÍoÒÈÌá2s¸q Ê2Ó†Z+vôŸdôŸŒW|>ö†>¬— ëuýÏ)è&ûɺ)²nŠˆHn‘î.xbðeÌèûƒþOK+:L méRBO¼ÕasçεòÓÙ!ïVÆÐ+0ˆÈؾ2ë9wQ´"Û’·o(öÔ¹­¥ñ¶,ké{µ~†ö#šWÙ½{·r™Ö¸qã'Ožìïï/"wÝu׻ロššºråÊ?þñ:uÊÊÊzóÍ7G­, "½{÷®¬¬‘ñãÇ''''&&®Y³fܸq?ýô“Ñ%p룑~£Fe&$$¤¤¤ìÚµkçÎIII¹¹¹ú­øøø˜VI)ͨ榅œ;w®E‹"Ò¼yóóçÏ;ü^1„ÞÍ6†C »†Ë¢Mr¡B.TÈâMÒíZðM¸Wf}"§.HÑyyþd\ç{º\ß–¿DzF:­&õTlêr¾ ™ëͧ§¯ˆº¸ó6Ùô¬”¬w’dʵµ ‘‚eRµNª?íGRcnPM³ yø²îY÷ î!!oxµMˆ/6^ÅR±Ê÷j…á÷jex†ò-Ël=Œ\&)ÉÉ7¤æC)]uý.™­n–‚ÝtÁYóëšåðŠpÇŽ«©©éر£ˆ:t(99YާM›–••UVV–••¥<*xõêÕ+W® ›={¶²Ìرc•§°>|x„ AAAIII‡2;ÇìFÊüñÇÇ0xð`eˆ¹áVL«¤0ª¹i!Íš5+))‘³gÏ6kÖÌá·‹ oå¼èlê£ù:OÂR$,E¾Î“®u¸O };I—Lé:Mîë,I1Î÷*»ÀÈ’è6Ò9S:>+Á2ÿÏ ±"êÂìw+cè %Þ'«vÉê]’cüÒSýåé÷åä9¹P!iÔR¬-ß«U04 Ïp,r—.]Þ}÷ÝË—u•ºçž{"""† u÷Ýw‹H\\Ü·ß~ûå—_¾úê«Ê2¾¾ºA ·ß~ûûï¿_YY¹víÚ.]º˜ãçç§üÞe¸Q£2{ôèñÞ{ï•——>B¿Ó*™­¹i!<ðÀÒ¥K/]ºôúë¯8Ðá·‹!ð>õ“› m¿=Lv&™ë¥ûLÑjeÎcµ;i€;#]2ED& 4ÿ½š¡ùpÀîÝ»ï»O7<íÚµãÇÏÈȨ©©QÆZL›6-66öóÏ?WPF07oÞü¹çŒÏv«W¯NJJzúé§;wî¬à¶èàè„nŒý[ ¸5•]iP4à:.%€Z ¸;.%¸4À :¡ÀîÂXd¶ËÓûAݹnuTXX®ËUn Ay*!À4€z(ҫ˨0ÃU¸·þŒVˆÐ Cé„öÂQúß:ìlÎ¥c¹»<€gP’«kïB’v ÓAááádèúÀ»Ú`Ð\gAôßÙHÒ0ÍÍÄ;ˆHXv¸ˆÅxöÎ@€à1¸”°!q)¡>’´íÈͰBIÏ*@€ V’´¦-ÜˆÜ #úôìéÝÏB€àYè„nHtB›2MÒâÅÝÒäf8@éYÐ<Á®e=I‹zô¥CÜ ëÔ1ôY °†`dÙ‹EuÝÒt6£.T–ž… Àã¨àœ­¾s *ë–¦³N¡š   À5ˆÑ*Vk·t­ê5j;0ŠÐ ǨéÂAChp%µž] g¶[ºVn2ÊŸÜŒºPñÿohp tH«žía´ºI2F}SqzÎß̸ IDAT44¼¢˜BKƒ‰ÑÒ-<ŸºÓ³ˆÜäê n Öó /¡úô,hp+*>ßðÞž… îCÝçªç%éYÐà¦gÕŸo¨›÷¤g!@€;P.+Tåãx¯JÏB€—3<ß¡xoKÏB€×ÒŸoôdhÄ Ó³ ÀUŠb Î7dhžÅ;Ó³ À­¡x ¯MÏB€wC†àþ¼9= Ü€;óòô,hpOdh¦bbbD$??ß…u = Ü€»!=+|]]€EÊVD$,;ÜËOW ¹¤:¦è~e";l—¸´Üåè·F?4CÊ(l×0={·˜˜z ÀÝÑ À 2ôznbŒ¶Á·íŽè@?4—1HÏ.­‡¡<ƒ’¡Ã²Ã• MW4€zGt¶€hð$tEh ¤gËÐàaÈÐêéÙ*4x24€zDz® <@½ =Û€ žŠ ÀÉH϶á.àÁ¸5ç :ÛƒhðxtE¨Ò³Рdh"=Û ¸åé¬ùùù®®<€ÝHÏ!@€zfhb4kÖkHÏÓhµ¼e€ÉÎÎvu 1E÷+Ùa»\[ÀK(?!z ¢sÝÐ ¸û/îJŸ›õI@ýñ°ÿºIÏuF4¨—þ4)œ)ð‚Ó @íèm üWàL áµÓŸ, ;ŸxÒ³SÑ ÞŸnïı_ÐàMè…¼ ‡|ý`x†sÞƒô\oèïÃOº€ºqŒ×34x+z§UâЮhðbtSjÂÝPÐàõè¯T€¹ t\žŒã·ÁqÀ']nÐxÒ³+Ð 0ÀÉð­®C4À]Ñ€G =»=Ðs8=î‰cÓ  –q]?àV8$Ý`Ý]€;àHt'h€ 8y®ÂÑç~¸ˆ`..\‚ôì–è؃Ó9Ð08ÖÜ`?Ní@ýáør{ áØ@=!={z uÀÉpŽ&ÏA€Ô'~ .8‚< à$„À^5ž‰ p*` ŽOF€8›Ñe…„Àˆç#@ê)0ÂA¡h@}"1 6h@ý#=Àk±ó«ÐPHð*ìðêE€4,RT\íÐW a@•ر½à:¤ ¨;³7!@Ü•€çbïõ>h€Û „ÝÕ‹ n†\7Ç.êõзd”Q„˜WcŸÄ5h€{£·.ÇNˆ ž€Î?4<ö:X@€xúÑØÍ`àèD}`¿‚mÐOFâAݱÁNh€*`/ö8Š PÓH$¤"܈uF€¨! FØ%à<h€ª›¼;êà5ÈR^‚õŒ ð>,UâcEC!@¼˜ÙÈ%¤.ÏÁ'W @ "D1ÏÁ'W#@`‚ˆænøDàNÐXe)º é­>ñ¶Ã °™•T'»ºá½…ç @à(2_]ðîÁc pë‰Pá¹wêB€ ~Ø’jÊŽÞÙjx4 Èö|©çnASMê† €«9IÝY^€ €{s·xMD†×#@v¸ÉÕ< °°°°°°°°°°°°€† Ñh<¨XV °päȑ͚5 è×¯ßæÍ›•ùN̈_|ñÅC=úÄO[_^£Ñh4šF…‡‡ÇÅÅýøãΪ‰¶oßÞ³gOÿèèè>øÀ…5±…ŸZ=í|Ç€Ó î"..®S§NG---?þ[o½åôM,Y²$==ýìÙ³‡¾ùæ›ãããk]E«Õ^¾|yß¾}ýúõ0`À÷ßïôZÙbÏž=‰‰‰‹/.++Ûºuë®]»\RzUO;€V«uJ9ÀuZÜC£F***Œfšž³ªªªf̘ѢE‹ÀÀÀøøø‹/ê—\¼xqË–-7n<~üøK—.Yß\yy¹¿¿¿õeŒN”Ë—/1b„cÕÐUYY9a„ààààààäääÊÊÊsçÎ5oÞ¼¤¤DYàÊ•+-Z´(..6ÜôðáÃß{ï=³5|ûí·Û·oߨQ£ž={þôÓOÊüãÇ1¢I“&þþþ<òÈ™3g¬/_QQ‘иqãV­Z½òÊ+µ¾Û[·níÚµk£FÚ·oÿÎ;ï˜ÖÊèS3mµi[lÜ,5ÍR 'ìj;` =ÐwÑ»wï¹sçž8qÂp¦öÆ$" .Ü¿ÿΜ9ãïï?}útýÂ999ݪU+ýbGŽQ¦óòòÂÃílkÿþýQQQúå-æ_½zÕ×××±jè‹ ËÏÏW¦sssôZíñãÇÛµkwåÊ­V;iÒ¤7ÕÄÇǧªªÊl Ïž=«L———ë«g¨¼¼¼E‹Ö—?zô¨2}äÈ}m-53""béÒ¥¿þú«éæŒÚk¥ÕFlÜ,5ÍR 'ìj;` »Àíœ:u*55µo߾ʟFÆ×××ÇÇÇÇÇ禛nF£_L1 “®©;w¶oß~ÿþýµÖÄhÓEEEú¸fo5ôEFaÃFµnݺêêêèèhÓ¡¡¡Fƒ:ÌÖPÿç¿þõ¯{ï½7((Hé/3¬žÙåj¥Ÿo©™{÷î6lXóæÍÛµk÷ÙgŸÕZ1K­6Ëú`©i–š`:acÛKØEîèâÅ‹5R¦M»ví~ûí7ÓUŒº~Û¶mk¶ä 6„‡‡ÿý÷¶TÃhÓË—/ôÑG«†a´Ù.ê}ûöõéÓç믿NJJ2-ÖÊh³¶mÛvÆ çÏŸ¯©©)--­5D†……™í…µÔL½­[·¶nݺ֊Yjµ%VvKM³Ô‡ÛXÂh€»:tèîÝ»/]ºtöìÙÅ‹÷èÑC™’——§_lòäÉÉÉÉG­ªªúå—_ÆŒ£é™gžQ†Æ¦¥¥;Öt¯½öÚ´iÓ¾üòË^½zη>º¦¦æÔ©So¼ñƼyófÏž]ÇjÄÇÇgdd”””( èïÒ§OŸ   éÓ§?ù䓦u˜>}úÌ™3¿øâ‹+W®;vlüøñV*,"•••~~~'N´¾°ˆŒ=Z¹?III‰á€iKÍŒ?tèЕ+Wjjjª««M 4úÔ,µÚ;€¥¦Yj‚Ãm,ru‚@çóÏ?¿÷Þ{ýýýƒƒƒ‡ªï|饗š4i¢?gUWW/\¸P¹—B=>ùäe¾ˆ¼üòËÊí/Ægö>¦çÁ²²2­Õ1Ð"âããÓ¦M›Q£FéïÛà@5ô›0¼Å„  ë¹yóæöíÛ×ÔÔ˜­Ì–-[ºwïîççסC}o´XèUÝ´iSTT”¯¯ï­·ÞªÜÎúòåååO<ñD```Ë–--Z¤ïýµÔÌ?þ8::Ú××·[·nÿüç?Mkkô©Yiµž;€¥¦Yj‚Ãm,Ñh¹9"@”±°®®EªñÖ[o.X°À¹U²WnnîàÁƒ?îÚjÔ…ÃMPAÛÑ€[(--]¾|yJJŠ«*ššzîܹӧOgffÆÆÆºªuápTÐv4$4®§ÑhBCCSSSÃÂÂ\U‡èèèÎ;wìØ188xþüù®ªF]8Ü´ É-~í<=ЀЀЀþb'40CIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/simple-deploy-2.png0000644000175000017500000006334310014674771024734 0ustar frankiefrankie‰PNG  IHDR ÆrÔþsBITÛáOà IDATxœìÝyxÕâ?þwºÑhi.)¥PZhÙT*|E‹¢EVA¹‚xQ‹¬ò¡‚l¢Wܸ\¯~T„{‘«lZ);²”EYZ–VhK[ÊZèš&¿?¦ Ó¬“4M&ÉûõÜç>ÉdæÌ™™PÏ;眅F£àáè ‘\0Q Æ"""""ªÁx@DDDDD5ˆÈZkX«pú]ØsÕÖÙ5ôÙvŠ«é•$"gãåè ‘\îÀ©¥¸zU%ðW"ô]- ‰O>ðmÀNˆ„¶/»‰ãª%cÂiùMí„ ã§áÞe¶)ІäP""'ÁÞ"2äÒñ[\Þ†ÊëШpç/\ø¿A(LÇ™å0 ²>½{V5Õ5½ Óë%ý”J?в >‹çî î5¸°ºf¹¶é&L,±¢%×´â&áNŽáÓ"åÌØä]”æ¢qÌÝ3ë”î:QÏá±#^äKh=ꪚžeb-—ÛÄæBk;ñc ½‰áå°‘É€UßáÌQð+¼›¢Çx¦Ã+î–¦eìjJðÄýÿ€b½ +61q¹MlÞ¨9î@ærîDH÷šî +¾Ã9ß@÷•ˆ‡F!ððAójJÓ2q5¥£±Í…Ž‚»g »îi7{8ÆÎɧ&‘¡ ôhªq+WöàÔ»¸ñ2¦¢ç7¦¶ êRó¢Q ÃKT·u7~È´è w² ”|óOØÖÝÀG¥MUÉ ŠkàÝÔâÂ%Ö¶ä,D ª³0òI¸UÛe‘0 —·ãÌh3@Íoçñu»`É)•~Ak^ø¶Õ›XÍ']àÐ+8ò†æ ”3£ãv6`èÌkiªqæä¬AIT¥5 Ë LURâ&Æ.·éÍ?Åþ1¸ô\ú4i‡ÞØÑšï°0 E9ØÔ±»šÑØæ·s …è~e-êÞ»Ììá;D$oŒDd’ L@X?lj‡ü-æ×7»Ä:&&JIõ¤ãÊnh× …KÚ!=põwþ¯&(Þ‡¦íkÊbÒO©ô£°ÕE1¦Ýxœý'r7âòö†Ý‘àètœù@w¡ºÒÆ›Hß<òI<‹ËÛqe.þ€’s8ø2ÝcÕ×LÂìpcWSâ1šù2ˆ* ¨[³‡cì<‘¼1‘4ÞA *1·žåŠv#|@Íë+»  Õ;âÚa<þ§ ~}TÝÁo@D’Å…K¬m“8Ü8ü͈zw¡0H¦iû»K:ήdœþGM?Fü4IÍAclsŠ€ÐÔ«& Ot[Ž´¾8òºîGÏŒXã6¸uÆÀ™×†Ë÷úÁ»)ªJðC N…tÊü&Œ_n³›{5F«!h5 3ðŸp\=Xuš¶ÇõcÈÝ„è‘R7Ñ’xŒÆ§ýÊ^„õ«Y¢3¡\Êá<D$oœ{ KaŽ£+HdÛzàì Ü:uÔ•¸–}#ã ¸ú8< WB]…«¿ãÐ$ˆ44”"îïþ8²¿Bé%hTPW $ ç>Ãö$íH]‰;!û+lMÄ?àÛ±“,.\bm[€C¯àâ:¨î@u}‹Ã“ÔiçE>‰ÀäoÆÅà†6ÏK:cêŠ4 €ÂtÝû¥Z*ô´bàiÏŒ˜Ð£¢浪ËÀÓž¾¸ƒtKÐ?(³›Œ]nÓ›ïHBÁ/5GW3WÁ°ê _‰CÇ…U¨¼u%Š`—´ ¾Ñå5»¾vê*\;ŒC¯³‚ÙÃ1vˆHÞØ{5ú¥¬ÌÛÅ’Ó»zÐÀï| OtY`û}5‰Ã¶wßúG"a¦ÕÚ¾ˆkG‘õ1öµxú·¶ ˆÂCîÞ³Uzák?ù?ãÊ^ìVgyh´O½W áMì í_‡G#I‡cL}NÑÝ>‚‹ë‘Ö·æ­ô›ê»÷=äý uE…RÏŒx“ÈY‹’swÏ|Äã¸}áî á‘»ñn£Yhך>(³›Œ]nÓ›_ÞŠË[ë,‰z°êކüÍ(HÃqR7Ñ’xŒÆ$̬™·°õþš%£ä,µ-³‡cì<‘¼¹iŽ7Ý! 1ÉÒò úD ï±#èð‚ºÀÓÞðW"êY<º«AîKØk-bÆÁ§¼ùú調¯¼¾ÄÐ÷D= %<¼áé‡ÀÄNÄ€ý’väéÿHD Âý+ðøI'ZS¸ÄÚz4Bß_Ñu‚:ÃÓž~ê‚{–¸µ‹^àÕ±¯H: ÓêyŠtû­žOp½ ·AüÝ…ÒÏŒV£ôß…È'áŸ`ÄŒC¯5uVèño´/ø¡í fÏë”ÙMÆ.·éÍû¥!2>ÁPx¡q$¼‰Ÿ×|déòðFŸ-¸wšu…§/¼üÚo2¼²‰ÇhL£æxtwÍí˄Ӟø!P{×/)‡câ<‘Œ¹ËcÑL7Óm{ì¹/"çfÝoÒŽÒ@µýë[ì‰ö¯£Û‡6.™È¶.¬Âqhù°îԉȵ¸lïEý¶ÝµéÂÙ¥@DwUÝÄÅõ󒣫B¤g×Ó(>uªn"g 2¦ Däú\mî±–·³ïZ[=…Â]úmˆÈ(팈ˆ¤»÷ž'’ÜÈÝXgI³{ÑÎÂ)ÎDäl\¤÷À`/AÃõXM\v#^}„²I¦úlFø@xÂÃc? ýwÔw=ÉžÓÿ†mpàCjb)qÍ¥ÎDDDDäÚœ8è÷8ª&VsC """"Wâ¬ñÀ•~zgH """"™pÊx mO;cåaH """"‡sâ©É.Ö€Ö™BÍYËDDDDdÎ×{ ´›®ÚqÉî""""’?'ë=p“ßÔÅ7?ulMˆˆˆˆÈ­8Yï;th±ˆ,S¸§–âêAT•À_‰ÐGóZôº»‚ð ¶‘òø“²w8þúPŸµz?”È䈈\‘3=5Ù­²FcçÞ+vç>—ƒHî.ý{ž…F]óöÎ_¸ð%.|)Ó–ô_ßáÒ] ""2Àiâ‡ÙØ„ÍO£¥2N5”oA£†r0î]Š&±¨¼ŽÂÈZáèjR–C“Ðq6þHµ`+yæ""—ã4ƒ‹Ü­ë@ PX|êì¶;w»”D î;¨«ðìUø^ÁÄœopîs\?†ê2ø·B«dtœŸ :½Œ)¸´êJ„õG· ªRü‘ŠKëQš O?„tGû(Ÿ0UÕI(/Äcñ­wj#«1QDD®Îɦ&»¡å­ßþV˜d¶XI–VÒti& ·¨ÎDdžŸ²>EÅUK6Ó`ß(ì{E;QuêJÜ>Óïcû¨¼QgŽ£pþÿPy ªÛÈ݈_Bå5ø}N/Ãíl¨«Pu ¿bç`S;<»…¿á/¡°°ûúíñ/¶÷DÑnË6$""K0È”¸ÑìØ`Cf£‚£*Fä :Ï€s±¡6µÃžaÈþ ꪻ+h}©©ù€sŸ#g-·AïzÃ+ñØa´è…[gpraòoÁÀß1¼ q”æâÔRÈý?ÆÐ›^Žû™l´’·Ïãè4tz A],>À’,¨+P¼¿=ŠëÇ,Þœˆˆ¤qŽxàž#‹LmŽ9ÈÆÚ¾ˆ~¿A9^¸}×aÿXlí†òBS[ÿz}ȧàowC¯ïàÒë¬yÿ „t‡‡Bzàþû?hÔ w s9 w"¤;z×ÝPK£Æþ±hÚß´ìÐZÀg0¼ö¢i¨+t£ ÙŽsÌ=`R•b]<}1¬ ¹›° ªnÖ|Ô¤zoD`GžZŠsñØu2\Ù'\;Œ­÷÷%†˜Œ=DDd-§¹s¹ðÒÕ‹w¨JD‹€е¿ÓvĵÃxüOÿ÷‹íFø€š×Wv@@›š·^ÑjZ A ü'W.A]ifRµ ðma~M""²ŠsÌ= w#ž–À©D’lë³+pë ÔPWâZö€¦íï®Ó( ÓÚ†xÜß ýqd…ÒKШ ®@IÎ}†íÔ)ÿð$\=u®þŽC“ r0ìHBÁ/PÝêvÍlcÿeÑN‰ÏÖ.7fç“(Ú ÕT—ãòöšƒ (ýÄ‘Eœ ÷€Ü–ÆîÏ&rbWøÙ^á‰. î¾ }×#­oÍÛ‘´}׎"ëcìk¦ü&qØÖãî[ÿH$Ì€Ë[qyk5£ž±êŒÈûòþWg‰o(:¿mË]‘ˆzL߶ߊù“ úø5 2ï±#èð‚ºÀÓÞðW"êY<º«ÎmF»}ˆVÏÀ'øîà"‰¡ï/ˆzþJxxÃÓ ˆˆûë”ßk-bÆÁ§¼ùúïªyþZ¿4D&Ã' /4nƒ„7Ñãs[W¿4´zBàá€(´{A@”-wADD"všýYÏæGŸ»3í—‡_"ÇàC‹‰ˆÜI.2 ØÎ#éÄ3•ùÍ!"""jP6ŽÆ"[uTœ„@DDDdõì" """"rÖÖ0  ¨ðDDDDv`qï~*`‹ˆˆˆˆÈ5Hí=`* ‡cQC“Ô{ Îlœ¹*óEßužÙÀ)|÷Ýw¡¡¡Â…¿&""""2ÍÔà"ë4°ó]óm²;ë ‰ŠŠúî»ïzöì©óÚÙŸÀÁEDDDD Íh{ÑõUëŒcëêìááQ]]-\AñkgçŒWˆˆˆÈ¹\äzÙ@L¡P¬\¹2::ÚÇÇç¾ûî;qâ„°¼ªªjêÔ©-Z´hÖ¬Ù?þñaayyùøñã'L˜P^^®-dñâÅÁÁÁaaa7n\¼xqHHHXXØöíÛµ+˜Þ]YYÙØ±c–-[¦ß‚×>*X\ÔòåË£¢¢¼¼¼dgg'''7iÒÄ××7))©¨¨µmhaCíkq• ©SpœCDDD$[âkgAZZÚž={nܸ‘œœüÒK/ SSSÿüóÏŒŒŒ .\¼xQX8{öìüüü³gÏfeeåääÌ™3G[Haaá¥K—.\8zôè‹/.\¸pêÔ©w÷Ö[o]¿~=''çĉ»víÒßJ8ÿ:S><˜‘‘¡R© <8%%¥¨¨¨¨¨(!!aÊ”):[,ÁØ‘­áª#¼µCS EqqqHH€ÒÒÒÀÀÀªª*­ZµJKK‹‹‹o¥T*ÓÓÓcccdfföíÛ7//O(äêÕ«ÁÁÁ¾¾¾Ú×BÛÝìî"##wîÜàܹs±±±¯…x¡B¡ÈÏÏ×?ºÒÒÒèèhq‚~ Ú×Tþ\õ›IDDD$ºñÀ…[`âöºN›[xëååU^^.ŒÛÑòòòª¨¨ðôô R©üüü„ƽÙ&¸”݉Kööö–Äo80cÆŒŒŒŒ;wÕj)u3x¤òçÂ_N""""™¨3¸ÈÍv‡‡‡_¸pAgahhhvv¶ðúÂ… ¡¡¡¶Ú]hhhNNŽðZûÂ"C‡4iRnn®Z­¾yó¦ôv³Á#%""""20÷Àm;vìk¯½–››{ãÆ””aáˆ#¦L™råÊ•¢¢¢”””#FØjwÇã7Š‹‹¯\¹"LД™™i¬„²²2??¿œœœ &HßµÁ#•97Ï®DDDDöaþ±hîcÞ¼yñññ]»vmÛ¶m›6m„…ï¼óNhhh»víbcc###,X`«Ý-X° 000**ªS§N={öôööÖ_gÚ´i‰‰‰ÆZÆ«V­š>}zãÆûõë÷ðÃKßµÁ#•3w˜.ODDD$ºCÛÁ˜#œ9sfРAðc ¿™DDDDöÁÞGzýõׯ]»VPP0}úôäädGWG¦˜ ˆˆˆˆì¦N<ÐÞiÇA•q;íÛ·mÚ´éüùó]9â·‘ˆˆˆÈžÜèÆ¦ät8倈ˆˆÈÎÜè±häDÄü*Ù“=‹\ƒ‘è=;ìEç)ÈîLgŽO ‘C˜ºs‘3Î uÆ:7§"++kÀ€ ÈÊÊ–k4š3f4kÖ,88xÖ¬Yvh£+j‰29Šáx mŸ±µí’† Ö³gϼ¼¼ÜÜÜ=z >\XþÙgŸíÙ³çÔ©Sþùgzzú_|!½L…UÄ%hjÙòP‰ˆˆˆÈF{œ1!U·;ËËËÇ8a„òòrý­ª««gÍšÕ²eKÿ‘#GÞ¹sÀ€ÒÓÓ…~ýõ×'žx@vvvrrr“&M|}}“’’ŠŠŠ´û]¼xqpppXXØÆ/^¶}ûví K—. 7n\EE…”:èÝÊ•+£££}||î»ï¾'N˜ØVÿTˆ9sfÖ¬YAAAÍš5›={ö™3g„å«W¯~çwÂÃÃ#"".\øå—_J;ñõÂT@DDD$¦9]B*,nkΞ=;??ÿìÙ³YYY999sæÌÑßjÑ¢E‡ÎÈÈ(,,lÔ¨ÑÌ™3,]º4%%E¥RUUUM›6íƒ>0xðà”””¢¢¢¢¢¢„„„)S¦h ),,¼téÒÂ… G]XXxñâÅ… N:U»Â®]»Nœ8‘}ùòå¹sçJ©ƒ¾´´´={öܸq#99ù¥—^2±­þ©_ÄAƒ½ûî»7oÞ¼qãÆÒ¥K“’’„å'OžLLL^wëÖíäÉ“RN»AɬÞÙœù©±ÎuïyɾJ¥2===66@fffß¾}óòòt6‰ŽŽþùçŸ;vì °°°k×®F˜˜¨V« Þ}÷]­JKK£££……BqõêÕàààŠŠ ___í뀀•J%¬pöìÙvíÚÈÊÊêÛ·onn®¸¶Æê shÅÅÅ!!!ÂÞ«ªªLl«s*ÄoóòòzöìyñâEmÚ´Ù»woxx8OOϪª*jµÚÇÇG¨¿¥—@ûÚ)¾3DDDD¤%éÎ9NÔàÓi{yyUTTxzzP©T~~~B“ZÌÛÛ[û[»Z­V(jµÀúõëçÍ›wçέ[·vèÐÀf̘‘‘‘¡À#¬)Þ©Á× …B¥RéWC»‚±:˜84³Ûš¸-ÒÀ{ôè!ô~¼ÿþûܶm€ÀÀÀK—.5mÚÀÍ›7£££¯_¿nÙUOûZæß9ÓŽp#""yêÓ§£«@dc¦iéŒQq–±FBCC³³³…×.\ Õ_'<<<''G¥RUWW -laùòå˧L™2mÚ4m×ÁСC'Mš”››«V«oÞ¼iQ«W\°°0‰uŠmwîÜ9{öì      Ù³gïܹSXÞ±cÇÇ ¯9"ôHXÇØ¸&’"½–£+BDDfðÏ5¹ ‹¦ý!2q”™™Ù¾}{áíˆ#¦L™òÅ_h4š”””#Fèo2qâÄñãÇüñÇÑÑÑ™™™ .\»vmZZÚÕ«W_x቉‰üñGçÎËÊÊ|||üüürrrfÍšeQÅ&Ožüÿ÷RRRF%¥ö`cÛêœ qQ;v\¼xñäÉ“,_¾¼S§NÂò1cÆÌ™3gÆ föìÙûÛß,:F}Fü…‘Û·EžÄÿ™‰‹‹s\EˆˆÈ<áæàéééìF —!©÷@L§…gð•–²aÄ´iÓµ¥½óÎ;¡¡¡íÚµ‹ŒŒ\°`þ&o¾ùfïÞ½û÷ïïïï?zôè!C†˜?þ;ï¼ãéééééùÁLŸ>ÀªU«¦OŸÞ¸qã~ýú=üðÃU¬wïÞ;wnÓ¦MXXXjjª”:Hdl[S!¶f͚ݻwGDDDDDìÞ½{Íš5Âò—_~¹W¯^ ;v|øá‡ëàÌ]OŽÇl@D$Ú?×ìC —Q¯§öšhêIŸñlé†ÎHJ'€;m§“¬ÿa6 "r"B;È5X0¸HŸ‰Áå–þH¬…B.ŒcÌb6 """ǪW<ÐÒoçIiëëoÅö¢ËÓ™ÁÂ+NDDD$+Ï=Ⱥça¹jÁ:8È)(•JGWˆˆì­¡â‘i¼ó)QCPÖŠ‹‹5jÔ… Ro­SPP0a„øøø6mÚ$''ÿòË/õ/“ˆˆ ’K<`Ñ=±_…Èæòòòòòò8Ð¥K—I“&9º:ÐV½&Nœ³oß¾ÌÌÌéÓ§¯^½ºþe‘Ar‰6Ýx6ÙJppðäÉ“O:%¼U*•ÿþ÷¿ï¿ÿþ¨¨(Ó§OïСC‡f̘QQQ!¬VYYùÆo´k×îž{îùç?ÿ©-ÍX‡€J¥zûí·;wîÿÙgŸi?z0tV6¶S¥Rùõ×_÷èÑ£uëÖ<}ú´þá=z4%%¥Y³f>>>½zõúæ›o„åÕÕÕ‹/îÒ¥KLL̤I“JKKuŽW©TöìÙSûFÓ³gÏÓ§O›ÝP8QDDnH^ñ€ˆˆlâÚµkË—/OHHÐ.9vìØ¶mÛ.^¼`É’%{öìÙ½{÷¥K—–.]*¬óî»ï^½zõ÷ßÿå—_öîÝkv/ï¿ÿ~ffæ¶mÛ8 ôhÿ_¿ÓÀØNìÞ½{ãÆgΜyì±Ç¦M›¦¿£.]º¼÷Þ{BåÅ>þøããÇoÛ¶íøñã>>> .Ô9Þ¼¼¼&MšìÛ·OX¸wïÞÀÀÀøøx³êÈMÈåÖ1¼Ó¥›ã@À›R=iª÷÷÷OLL\°`A»ví„åGmÙ²¥ðé}÷Ý·aÆ6mÚ8þüСC322tëÖmÃæýk IDAT† ÑÑÑ.\¸ðÐC ­|¥R)nîkß&&&®[·®mÛ¶:u0¸²±*•Ê?ÿü³Y³fÊÊÊ:tèð×_éWAAÁ²eË~ûí·òòò~ýú½õÖ[¡¡¡zôèñÕW_ ‡¿råÊ£>zìØ1ã]µjÕáÇ?ýôSÿûß{ôè1vìX)IÇç+±ÍM‰ˆH&Œõ7y‹‹‹µƒgZ·n}õêUáõ•+WZµj%¼–2º¦¨¨Hú c; d~~~*•JÛ°°°÷ß_Øã'Ÿ|òòË/oܸ@AAÁ£> @£Ñ¨Õjñ0Eíñ2déÒ¥7nÜÐh4;vìX²d‰Ä ‰ˆÜ“\âðÀ,ÞŸˆÈš7o~éÒ%¡—àâŋ͛7–·lÙR¼\»¾——Wyy¹¯¯/€ëׯk—·lÙòâÅ‹:½–îÔ"-[¶|óÍ7ãããµo7mÚnb“ÀÀÀ>}ú¬_¿^£ÑôëׯiÓ¦7$"rOœ{@rÁdHd7ÉÉÉ©©©W¯^-..ž;wnrr²°üé§Ÿž;w®v¹vý„„„þóŸeee3gÎÔ.:tèœ9s._¾|ëÖ-íúM›6=þ¼ôJ1f̘ýû÷WTT\»ví“O>éÔ©“°üù矟>}zNNŽJ¥ÊÌÌ4v§¦áÇûí·ß}÷ÝðáÃ-ÚˆÈ 1\ðæEDv3sæÌ-ZôêÕëÁ Ÿ1c†°|Ú´i!!!Ý»wïׯ_¯^½´ë/[¶lëÖ­:t̶¡Mw)8ö”Š+ ®¡ðš—›ˆˆˆÈ±äØ{ ÷!@f?~;–ô_Ù v)@¯nŸs+q§ìC """r ùƈêÍD‡LCß/Ub0à 2""""‡“u<€^£ÖC‚­Þ蟽 V„@DDDäXrZâ±énu7L;< M–‚”jX]¾Ù•™ˆˆˆˆÅiâ@g«CÆÐÛ£ŽNJ÷‚ÕEY„ ˆˆˆÈΜ,ŒÝåÆeÒ‚ÜÄÎЙsâðÃ'"""rNf‡ÄÈ­‘m–ÓU¸á0!¸‰ˆˆGWD~~¾£«@DDVrâx ÃÒ´`bÛ†#q”[Ã:˜\ SË.1C‘3rx CÊt[‰ŸÚÁZâ0!¸q6`óÑU W9""‚—˜ˆÈé¸l<Ða¢eiçlÀ6®tL.Œ­F×&\߈ˆ&""§ã.ñÀ¶8åŒ ˆˆˆÈž<]"ËÈg$YCÒ‰ˆˆdŽñ€äΆÏa """"ÓÈ 0!Ùã9+&""""›c< ç`pF2‘m1Ó`B """jhŒäL˜HK©T*•JGׂˆˆÈÕ0Q >œŒÎƒÒ|\šÊËËstˆˆˆ\{Èùpˆ‘ëF ­_¿þ‘G‰ŽŽîÙ³ç† t>­¨¨˜7o^—.]Zµj½ÁEÂÛ5kÖ<ðÀÑÑÑýúõÛ¾}ûÒ¥Kï»ï¾Ö­[4èäÉ“â=þøãÂ&mÚ´y衇Þ}÷ÝÊÊJc»4hR©Ü´i“vóÍ›7+•Êþýû7ìy!""²;Ærƒ„l}÷Ýwßÿý¡C‡”Jå믿ž––&þô믿~þùç?~éÒ%c%ìÛ·oûöíŸ~úé™3g^|ñÅ¿þúkçÎ+V¬8~üøäÉ“Åkfff~ýõ×gÏž=yòä˜1c>üðÃùóçÛÝØ±c¬[·Nûéÿû_Ï<óŒMœˆˆH>8$ƒœ•±V¾é¯´v+y~óÓÓÓÄÅÅ9º" %""@~~¾Îr¡`óæÍ]»vpüøñAƒuïÞ]h… Ÿ¦¥¥uèÐAgí#áí¾}ûZ·n]^^`ïÞ½ÑÑÑjµ:**ÊÃÃãâÅ‹k¥V«[µjÕ¼yóãÇÜ]yyy·nÝJJJ:zëÖ­®]»ªTªC‡………Ùìì¸c—›ÈõdeeèÓ§£+Bdì= ge¬}o,6( ñGìC¡øøxñ‹?þøCü©”Ô$Œ;òõõÞFEEðððÐh4ÕÕÕÚÕ ßxãÄÄÄÖ­[+•Ja««W¯Û¯¯ï°aê««…!O?ýôSeeå<Àl@DD®‡ñ€œ˜ô„À0à<<Ìÿ½ÒYÇØ&'N\·nÝÈ‘#ÿøã¼¼<¡WAçë¤³íØ±c Å?üà?ÿù8²ˆˆˆ\ã¹&)Ì rsêÔ)áÅéÓ§tîܹvtôèQ“&MjÚ´)€cÇŽ™Ý¤uëÖ}úôÉÊÊÚ¼yó|}} Ô@Õ#""r Ærn&¦­Ó€ AVÞy碢¢âââ… xõÕWhG÷Üs€Õ«W———Ÿ>}zêÔ©R¶&(O›6M£Ñ<úè£Mš4i ê9ã9=³ œÅ°aÞ}öÙnÝºåææ~ôÑGýúõk ­\¹2))é½÷Þ‹OIIIII‘²U¿~ý"##oÞ¼ Ž,"""×Å;‘+¨g Ï¿7¿s‘üŸtöÑG-]º488øèÑ£^^|¬¤¼s¹Þ¹ˆ\ {ÈÔ³}ÏN’âöíÛ¦NÊl@DD®Šÿ…#¡ÑhêÓÊW(Ø“F¦ 6lÏž=ÁÁÁ‹-&!¹$Æ"r<ù+úþûï]rw¼úÿ?4"’Ærì@ "WRÿ<`¶@"ÒÇx@.… ˆœ—ù„„3À, hÌÎÔ._ ¼„ÀBàËúˆˆÈÆ"°>!ˆ·¼ ÜnK¤Úå'ÄÚ×Ý€“õª*‘ \DdÂ(£zõ!|ôæÚ{k—ß×¾n”Ô£–DDDD&1ÙŒ5óÄóŒÇc)€÷€m€ÆÀm ) h"µì·ß~ÛÙï*cõ´W)câI_CÌsàè|""çÂÁED¶T¯;œîfA@0ØY»¼#p¸öõ cýªHd\DD“•s³®ÿ’·G#"Æ"‡ÿ·¼#°¸Ü–j—æ—|`6ð‚ýkéhþÏ^ÿ#ggÝEÔÞíO øÂ¶u""'Ãx@$k€Ý@ìÖÔ.è$‡¿9²ŽDdÐgŸ}6oÞ Ün}õ>šÄ]¶@sÅòöhD$¢¨×SœˆHO̓“µÿ°„ß¼íóïL¼/ ¿†µÐâ´âѼ5OæŸ+»Q®”pA}ͬ¾ÜNA'L˜0Á­¿¥²üƒcOYYYúôéãèŠÙ{ˆÈ 8r‚²jb‚D&Lptˆˆl†ñ€ˆÜ@ç<ÅZH4À   ̪÷oØîù¸d:]DD®„ñ€ˆœC½:~ž°im´XëšæŸ{€SÀŸ@:ð…mëDwé+rTMˆˆãQÃPÔþOçmƒþO¼/ûxˆÎ.€0$þ  ¨f-`$pG´ùR ÆzÅØt|€h@Ût4V XD  ( h€à„èòUS@3àæŠ] ¼„ÀBàKCç!Hš¾@RÝ»éëãe ˜ ˆÈõ0‘³±4üYÀC@ø hüØ ,@!И)*apÈ.sõŠ0HJ€]À¡ÚLxÈ4@S`GíÂ߀f@Ñj©ÀŸ@p¸h®Ø“@bíënÀIC§b0E@0ÅüÉ#VDD.w."’‘ôôtqq 1ž]ê+knó%ð3ð°X |<tNÿ†/ÑÀϵ„*ºphÈú¹u‹Ð˜< D‰ök¢ÀüÚgß~ìÖFµØ HÓ›Þ`¬XO ªö75à¨Lž–R Ú\Bm3vÉÜíÎE¦‡ñÎE¼sï\D®½Däê~ô¥À~`°(}y@WÀ ðÂê¶›µ·o ê `=t¢€µ M^ûb°¸\¶ê=ýê2ÐVïpŒÛ¸]ûºhRûZ<öìÐh (€ ØøI¸gKW+""WÅx@DÎÄâ ÊU@Zíð!? =ð)Ð ºñ€/ ÈT@5 Ô¢B²k_\ÂôŠp?° ¸ü x¥v¡‰µš¯¯A@PÝOà z›+¶#p¸öõ‘ÚîšÚÿ Lr5p“­ËpX¹ Æ"ri»€ö@ËÚ·IÀbàQÀ`1TûÑD`$ˆ:ñ”J¥›'"—Áx@DÎ'//ïîÏ´D ÆÒl ´ï~9]8$ÔÝÇ`@äJˆˆÈ  @DD„ Œ²m[¹&'h[Ò.˜ ˆÜ§&‘S²ø§DªÿÝŠòòòê4 Îü­[yÝC#"ÂÞ""’ÀÍ:lx'S§qÄ"7Ãx@DΪf‚” ÊDŽf8$@Æß^½Ž"7Áx@DDp‡„†{šî´Ȳ3ÝDîñ€ˆœ;ìCãÌCç%³Ï’娙Àî"Àx@DNw8%§f´3Á˜z†i鎩€ÈÍ1‘d®>AÙ>]út;ŒiàÞ"ã9;NP&[qT6Ð2Ý:·IG™Åx@DDsáÙbËžˆìƒE#"§ÇG¤Ù•‹öÒ8¼ë€ˆH&ˆˆÈÝ1i1‘ a‚}h ""ÂÑõhÌDäæˆÈpX6YM§ë€ˆÈÍ1‘ûâ°"""ŒDä"8AÙ®\q‚2³ˆˆÈmqX‘>Æ"rì@°+'ï@à°"""ƒøX4"rELd f""-ö‘õœôžQVDDd {ˆÈ¥8ik•ì‰ÃŠˆˆL`ï¹/f""ŒDDäF8¬ˆˆÈ4Æ""rVDDdã¹f"")ˆˆˆˆˆ¨ãÙO~~>€ˆˆGW„Ü»ˆˆ$âM‰ˆÈÅÉ6D¤+]ä÷á½€‰¨Æ"rv ¸ ¡¿ÈÍÉ!˜`¢zLDî‰ñ€ˆì*??ŸÙÀMÈ$سëÀÒ$ ‡ö·‰:üHu&¢Åx@Dö&“V#¹ƒÍÀÌÛÓ&ªgðõÊü‰ÈRŒDDD’˜Í.ÖP6x8ú'Ag‰‹"7Äx@DD®©þ]¦ó€{¶ƒõZç,1-9;Æ""rAVgNÕµ”Îi1‘x‰œã¹;c‘€ÍY+˜H Œ DNñ€ˆˆ\”®FûŸOF"§Àx@DD.ÅD6`$p,F"§Àx@DD.Kȼ¿ ™ ¼@DŽÂx@DD®CÜu÷6ÒßÖYNÒ^æ"9`< ""!dƒÔ8Fge°K9ÈΈˆÈD¤+Sãê,akÒ©éw)0'Ùã91ýy©Yó`ÕCÐHž˜ˆìŒñ€ˆˆœ’N0R€ÙÀ%Ë D¶Åx@DDÎD¿» ¿OžxF2³Ëò;ˆã9ƒ©@x¡ó rtDÔ@ˆˆHÖt‚NËOÊ’ɵqБm1‘L™ú˜ ÜœÁAG D–b< ""y‘ž 8¬ˆôét&pÄ‘¥ˆÈ~"""]jùùù6)Ç¢î+"ÓØ™@dÆ"jpL.O¸Äõ –Ž#b6 ‰ˆ,Åx@D Kœ lõ3Ép•#""¬¸Ä–"+0$IÇx@DöÀ`àÚ„ëaQB‹jì: 뜖À@¤ƒñ€ˆˆìÍê`f²qgC‘Æ"j@õ’N.¦>Á€È¶ˆ b< ""{°I0`×ÙC‚M( Fã,ÅÊŠ ÑÃÑ ""‘®ß{žÙ€dHüÍcm(//oèС͚5óõõ}ðÁÿ÷¿ÿ Ë …mw¤Ñh|ðA)Å* …Báíí­T*‡ vìØ1ÛÖÄ"[·n½÷Þ{5jÔ¾}û¯¾úÊ5‘Âê«gÛ2-"e/ŒDDÔPl ˆì£AC°aÃâââÎ;wóæÍùóç¯X±Â†…‹­ZµJ­VK\Y£ÑTTT:tèÁìÛ·ï‘#G¨V¦8p`ܸqK–,)))Ù¼yóŽ;R†öûï¿«T*Ÿýû÷;º.¦0‘íÙ<°ë€ì¦BÂÁƒç̙ҨQ£¾}ûnÙ²µ?å ¿â «UWWÏš5«eË–þþþ#G޼s现\¡P,]º4444 `ܸq÷ríÚµÔÔÔU«VI¯˜‡‡GDDÄk¯½6þü Ô³åååãÇ œ0aByyùõë×[´hQ\\,¬PUUÕ²eË+W®ˆ·Z¼xñâÅ‹èãã#®ÿÊ•+£££}||î»ï¾'N ³³³“““›4iâëë›””TTT¤­žÁõËÊÊÆŽ¶lÙ2³g{Ë–-:uòññ‰ŽŽÖ:»þUÓ?jƒ§zõêÕcÇŽ3fÌêÕ«Í–iâ,_¾<**ÊËËËÄ!œ‘‘QXXبQ£™3gjWÞµk׉'²³³/_¾ñÄ;wî,///..^²dÉ=÷Ü#, ÊÌÌÔ®6qâÄñãÇŸ;wN¥R<Ñ£ÏÑ IDATyräÈ‘Ú&Ož, %OII5j”þ.4"¨hs9A­V_¾|ù“O>IMM}ë­·êY#FL™2åÊ•+ #FŒ–'&&Ìœ9óùçŸ×¯ÃÌ™3gÍšµ}ûöÊÊÊóçÏ¿øâ‹&*  ¬¬ÌÇÇÇÏÏ/''GÊ_†áÇ¿ñÆÅÅÅW®\OT0v˜#FŒ8uêTee¥Z­®®®Ö/Pçª;j­5kÖŒ5J|ÆŒ³víZeš¸R;ERöÂx@DŽ‘™™ùõ×_Ÿ={öäÉ“cÆŒùðÃçÏŸ¯¿šv¦ëàbì 8¬ˆœ…ðo¡æ_‡pWß‘ º …§§çÇ\sûcGhß¾}|||iié“O>ip,+iqî9ÀÑ£GLš4©iÓ¦Ž;fÑæÂ”¾8°>6¯ƒÌ5ô41+"§“±#=bGÍ›µ–Ý/H"9Œ,‚µÕÐh4*•JÊ-€ΤI“ KJJÖ¬YÓ¸qcÖDþˆÈ„¶õêÕ«ËËËOŸ>=uêT+8{ö¬vÉŒ3¼½½ß~ûíS§N©TªË—/oذáé§Ÿn¸úØ¡²¥3ÙÎ{g6 g¢í7X«h @dŒDä+W®LJJzï½÷âããSRRRRRL¬}úho*Ú½{÷ü±}ûöÏ=÷\LLÌã?¾cÇñçm^;ÔAžìÙi à°"rn#5uB‘’Å,x"¸í‹H†¬˜iPÿËÍaEä¤ <5Yœ 8œ §&‘.Ž&Òb6 ç&D!$¬U0!a< "¢»rßR‡‘ ©¹›Ànrœ{@DD5ä“ Øu@®C 8œ{ˆˆpè€"frqhDN…ñ€ˆÈÝ9°Ó€Èp 9 Æ""·æðYÈì: 7Ânrœ{@D侘 ˆ€F ycï‘;â€""Gâ@#’1Æ""·ãðN»È­q É¹f"á@#’Æ""$;dp9ÉÉ ã‘kÒIéJùdvÕ!N ähœ{@D.B©4ü{¹¬äåÙµ]‘®’€|‚˜ ˆ âT’ Æ"rVN‘tè×¹!ƒ¸ß€w("r&â;1!ƒ0‘S2˜ òóóí_‹DDDè,Q*•öéRI6`בLähŒDä|´Ù@þy@‡N……´`·„àpÌD’0!Cqj29çÍúâÌÞ³H&˜ ˆLáíŒÈqØ{@d€Bá"Ž]ø7iÈö§©ì:]Dd†v²2Ÿ¬LöÅÞ""GrŽÝ¦Y;ªʈ¬Än²;ö¥©ûKУ ‘åÏ7úus•þ²Œ‰Ö¿L¦&ƒÙ€ÈRœŠ@öÅx@DäÊä 8¬ˆ¨¾˜ÈŽˆˆ\R€ÃŠˆlƒ ì…ñ€ˆÈuÈ'Äl@T/LdœšL†¹Ì­{ˆÈ8¬ˆÈÆ8S™{ ËËË›|8##£°°°Q£F3gÎÔ®¼k×®'Ndgg_¾|yîܹ÷âããÓ¾}ûÅ‹WWW %ú7¶ë1cƤ¦¦–””ìÚµëСC«-¶oß¾¤¤$ƒ»HKKÛ³gÏ7’““_zé%aáàÁƒSRRŠŠŠŠŠŠ¦L™bzý·Þzëúõë999'NœØµk—õ'"§ÃaEDöÀ„@ Ãf#é]L^^Þܹs·lÙRVV6hРeË–EDD@ottôÏ?ÿܱcG………]»v-((V;{öl»vídeeõíÛ777×àŽª««Ož<9yòä®]»~ðÁú»Ð¡ýÔØ®[·n=eÊ”§Ÿ~:**J+}^^^žžžú;*.. PZZXUU¥³Niiitt´Ð`lýÈÈÈ;wÆÄÄ8wî\ll¬õ·1 O§Bš <mÞ¼y¦7lèv›ð§>?BëƺضL2F¸‚§+§¦¦Š2;ÈÊÊЧOì[› 8l„ñÀŒ‚‚‚Å‹9rdÏž=Ðkg{{{k›W«Õ …B­V «©T*¡Í­R©üüüôÛÖ:{‰¿~ýºÙúh+`lׇZ°`Áþýûýüü>úè£äädýj‹5oÞüôéÓ-Z´0¶#·˜1cFFF†0H|È×Ç•J¥­¶Eõ·1ñ¯,Fþ˜ºF<0› ¤¨gÛŽñÀÙ1IáÈx&²1޹Ȍ°°°E‹5kÖÌà§áááûö틌ŒÔÿ(;;[è=¸páBXX˜é½hÇÒÛõý÷ß¿iÓ&[¶l7nœÙæu¯^½6oÞ÷™'÷s¿ÏsoEEÅáǧN:vìX£½žkj;ô„ rssËÊÊ*++«Ö38 »ºE‹-Y²äƒ>(++;|øpzzzÝÇ--- mÑ¢ÅÑ£Gëó‹üøñóçÏÿî»ïNžÜ«W¯Í›7»vuƒ Z·n݃>øÅ_DFF>ôÐCuwÆ óçÏ7nÜ7Þ¸pá­[·ÖýúÇ|æÌ™‘‘‘­[·ž?þûï¿ßàñ{ì›®ñ* yyúÇ?&I™™zî9³}ãF-[¦®]%é‰'ôÈ#2–p×Ö~•}ôÑ+Î ñ‘3xßOAƒ‹ kšD#>=-äåå5êÈ‘# ÛÍB,“¤®=°X?ºçõë§9sd·kÕ*í߯7ß”¤¶mõí·jÓF’ΜQT”Œõ&µµ×ì¹Öײ4ÙíZU¹Êü`dã:&´“‹øßÅcŒõŸbäöÚJ*^^{PëpÕ8‹măêæÌ™³téÒ²²²3fôèÑãùçŸ÷ò€êÎírkirõ“ø‚ ¤o¾‘¤èhíÞmV®½VååºæIª¬Th¨**êj¯Ùsmš.\QÝùáŠñ@$kPBp#°jAȇâH¸ZL.B“ëÙ³glllIIÉwÞùØcy{8µ»º¯Ñêg·S§jòdK-ž{NS¦è¯•¤V­tîœY%(.VëÖæëkk÷ \$ßÂ,#\–&7 JÕÍž=»¨¨¨¸¸8++«U«VÞŽ+íûºs§23Õ®ÚµSf¦vî4Ûãâ´w¯¹ýÙgŠ‹»B{0®L3'ÞøõÈX©Œ«@<@pk¼`Pýì6.NO=¥Ó§uú´ž~Z}ú˜íiizè!?®ÂBefjÊ”+´MË@P !À]īƮT—•¥?–Õ*«U¬¬,³}æL ¬Þ½§aÃ4mÚÚ-Ç‚áâz0¼GðÜ ZÀ…Àxj²<²4¹nõ_«Êe«çe–&õá[K“°R Dõ p‘ Ð@Ä>Á‹ ”iRSCß ” `$¦¡~ˆANŽbbü¦[÷‰Ý®Tûöºî:-Yrµ±˜Ç#êxÀW\M!;[wÜÑÈãiºnÝ;5_³FŸ|¢Ü\8 ›Më×7ö°0–)£ÞˆÁ¶mºãõ衼§¡„'”Ÿ¯¡C5r¤l6IÊÎVX˜²³%é£4j”$=ù¤öîUNŽŠŠ¦E‹=ìÚ¥ýûõõ×:~\<âÜ­¤´4-]ªâbíÚ¥þÓ|AîÙ£œÙíjÓF}d6þíojß^?þ±ãeK—êÀåäèÈ}óͺ=xP·Þjn'$èàAן†Ë÷ õÂM¸±icqãN—nÜáô•W´m›þô'½÷ž6nÔÿ¨”õé£Ü\½û®RS•ž®Ÿÿ\QQÚ¶Í|(uQ‘âãõŸÿH’Å¢/¿ÔM7IR~¾n»MÇŽ]Ö­¤ýH èî»é8nªkWIzñE}ú©¶l‘¤ 4t¨fÍ’Åb¾ÁoÔŽÎËjëöÚkU^®k®‘¤ÊJ…†ª¢Âù£¨í½Ô¦*‰ÕöwÄMúðé›Öddîh„ZP=à÷²³•’"IIIÚ³G%%úûßµd‰>ýT%%Ú³GƯì‚ÅÇ+$D×^«.]tâ„£‡èhs£[79w+é7´c‡©?ÿÙl¬£C#Hš4Iù‹¾ÿ^ÿý¯Þ_'^6òãÇÕ­›óÛ©­ÛV­t]\¬Ö­Ímã©yU'ú.ßKm|3îhZÜÈu"ð- ] \^®;ÌéC-Z¨gO½ô’Ô®ô ŠUóæ’Ôµ«ŽUE….^”Ý®ÊJG'_mn9¢.]œ»•Ô¿¿ÞyG'OêPF†ÙXG‡UÚ·×Ï~¦M›´i“FR»v—ý´kW9â¼KmÝÆÅiï^sû³ÏÌò‚$»Ýü¯¶÷®‘à ñ¨UÕEÙê—f}俚c »v©gOuêdþqäH=õ”†—¤#ôÔS9Òüѯ­3ôÕWª¨ÐÁƒ—]ÈŸ7O'NèÄ Í«I“\t;a‚rsUV¦ÊJ]¼xå«›:UëÖiýzMêü£É“õ›ßèØ1>­¹s¯ÐmZšzHÇ«°P™™š2Åõáj¾—º±@F,B@íˆ|Nƒ Õ§I9R§N)9Y’†×™3Žx°x±•œ¬ðpÝ{¯ÆŒq았¨¾}­.]´t©‹nïºKcƨeK-^¬Í›¯ÜauÆ0ÎÓm·9ÿè·¿Ul¬âãÕ­›cRPmÝΜ©ÁƒÕ»·ââ4l˜¦Ms}¸šï\ ! ,M|ˆÍf“Óâò·×ªÖrLŒ¶nÕÍ77|pÞèÖga¬æßK“úð³¥ÉÕ±L5„x{P«ª;üÔ!?¿IÝDÝ€o™h׋¶XH¨Âä"¾Èë·d€àÂ#\B<°@b,BÀåˆ|TCïp p3‹P ñ Q@‚ÏJÃ%ľ‹x !è—¡€)!@ñ€_ €à<v,Bñ€ã§àQ,BzÄ€ ”˜HÁŠxÀ×±@<Š)FÁxpÔ˜bĈüOb2Bð! ¦+âBÁ3X  @bŠQ"ðÜἆ„Lˆ¨SŒ‚ñ€ß`²'±@€‰)FA†x€z !âBÁ“( 01Å(˜„x{àxÔD»¶X´ÅBTxTuážQ.ã@Gõ€Ÿál¼Ã( ÐQ=@Cñõà @<@½ñ„@G<`" !( 4âÜBBDÄ4k”ñpˆh8 Šx·°F94¡ÂÂBIV«ÕÛõB<€»( œo@P €$ŒzÀQ=д8_ ü]AŠB`¡z ÉqÖ€¿ z€«C!€˜˜\à—l6›·‡Põ£¤ÂŸj‹ÅfýÈÛCi*IIIÞ‚'ü‰o¥‚`b|òˆ~£z6ˆ‰‰ñÞ@\(Œ)°Ú"’ Z˜Tàí±4‰üü|I6›-°küLLLŒ¯eƒ`Põ±v‡x€ÆaÔ ¬¶oî#øã¢5u4)â G<`" 1Q@ðkÄ&ž{ @DDøÁeª‚‚À¼8¸dµEê3Õþ*ârÞN½DÔàíð?ÿþ÷¿Ç=pàÀ­[·êÒwKbbâûï¿ol¯X±"..΋ß3¤ÿEõ€_rù ¯°°Ðó#i«ÕêÔAI@ƒÌž={„ ›6mÚ¾}û}÷Ý—ššj³ÙÆ¿}ûöòòò믿þí·ß>|øªU«RRR¼=X þ‡xÀÿTeßÏNœl¤€ùüóÏßxã°°°””ãÛ£Gƒ~ýõ×KJJ’““£££W­ZµbÅŠ•+W.\¸pĈ^gaR«“ýñ€ŸñßlPSaaaÍzÔ­OŸ>o½õÖØ±cCB'r ,HKK«¨¨0¦¥¤¤¤¤¤ìÚµkÆŒ‡òÞ`áX{À/@6÷¼ð ¯¿þz÷îÝûöí»|ùr£1**ªÿþÆ »ñÆui5BFFƬY³¼8Tîpꨀ7樿nݺ½õÖ[5ÛŸ{m¾Rà6ªhZüñM…ÛùâñMˆÊþ…xÀÄ‹À'¸|´/àþ' OPö TuñÙÜÀ üÕð2_~Äu€`CõMŽÊþ‚xÀD<`bíor{Ù+sâÝãËë¼Â¤«-‚ûù8ªD¬V+É Pª€ ‹ÅÛChþrÇz{–·G4,“¼=MÆ/nCl|áûþPýåhS ÀC¸Háûˆ@­œ.ißh¾y»æØüåû·   ""Â2ÉG?ØÀcÏ’e’¬V+‹€@e·Ûkû‘Q¯ãPÍ pñ p\ñì–Ó_ԥɼ̘ßé/厀Áe€KT ¸ó‹*&]%ª+Tø ÎYð:âï æûÇy…±œùE€šˆLÄ>Á(ûÔ`š€â€@–sT1÷{ºÛ«Ìž‰%©ÑÏ«õ45Ÿ¢‘¿Ó‰³f{i™&¯VËtu™¥g²¯¯¾±z‡¢æ*4M·djÿ7Wر¡X  ¨‰x4¾üãñ´Z¦«eºF<­üãf»Ý®_Sûºî>-ÙªªO7´=à5VáÄYå×Ð^ÙO¶/$);Ga!ÊÞ'IåjT?Izòmí=¢œ'Tô²ÂB´è5G»ò´ÿi}½JÇOë‘7œ»•”ö²–Þ£âõÚõˆþyDºtÎmÏr~ñ¬æþ\'^Ö‰—Õ;B 6›íÿI§Îëè*íZ»ò\¿…ôÉouzF'húÚì€{ˆ@ãK}Aƒz¨à%{Qºkü‹fûš¿é“CÊ}F–Ë–«õ67ÛXãÞáô/ÿRr5»V#ãeË•¤mÿÒœŸéÝI²}¡‘ñ’´Þ¦•¿Ò שus==^oìqô°*MÛªS­ú•²v;w+)7Ûÿøw­¸WÛ¨S­ø•ë}WOÓ ×)ðÀC‡=sæÌ!C.\è±ãúâÐ8ªOÒ˜úMNÔ©µ:µV“kÊj³½Us»tŠ_\ªÖÍÝlxR@ÈÎQJ?ÇGÆëÔy%÷‘¤á}u¦D#/ýtñJì¥ä'ž®{ÿWcú;öJ쥾‹=W]Újé=.º½+AcV¨åT-þ£6Ï2HÑ­9Æ¿a¦nQ«iºý ‹uìûøXµ WäõY¤A=ÌÅ õáöŽP‡;w6LÒ¾}ûn¹å–‹ÅrèÐ!«ÕZZZ*©´´Ôjµæçç?úè£;v´X,FÀb±Ì~lwIDAT™3'44TÒgŸ}߬Y³øøø}ûöÕl©ÚÅØ¨:¨SŸ_|ñÅ AƒBCC{öì¹{÷îêGq9$c¯ê#wÙÉöíÛçÍ›×¼yóùóçøá‡Þø˜ýñh|;ó”y—Ú…«]¸2Gkç¥{ËÄÝ ½GÌíϾVÜ n¶£>ªî=jèÑEö,Ý%Iñ‘²gé¦Îæ®±hÉ:ºJe¯jß“úåOÌv{–¼CE/ëüm˜iÎDrêvüÿ(ïY•¿ªÏ—kD_³1s´Š×W»sÑ-úêy•¿ª#+•‘ìhÕ¦ •lPÑË}«n¸Îq\§ §?Ö¶£Û( Pµ ùS¦L™ýôéÓÓ§OŸ2eJÍc»ÝnlTÔ©Ï´´´û¸¸xåʕӦM«~—C2^P}ä.;ùþûï;vì(©C‡§NòØgë_,õœª㪃ÓÉ™q1¸¶¥œ–IŽ%dê·hÞHIZùž²÷iï2IZ½C¯~¬7çÉn×=+5-IÓêN»Ë£;Íhñ߉•ÆF`¯óª–ŽQY…f¬S.zþÞ&ß±6Æ?˜ÂÂB§v#3øï?$À3òóó%%%%5õl6›¤ª³a'Æ7g§væo7W/8|øðСC/fÍš9s&<<ÜøÑ§Ÿ~šššš››ûæ›o0`ëÖ­¿ÿýïóòòfÍšõøã[,–òòòcß³g϶hÑ¢¤¤¤mÛ¶ååå5[,óü³úAúlÖ¬YEEEÕ°+++«¥æŒ>F^³“:¥:¾÷<ö×í-T€Æ—5[’u¶¬³õñ!eÍ6ÛgÞ¦Á1ê½PqjX¬¦%¹Ù ‚ä|´gWÅ.TûÕ¦…û¥'v—ª¯èÝ»÷ÚµkøÁ|Hä Aƒ"##SRRºwï>`ÀI©©©»wïþðß}öYã5ÆY»¤^½zmܸ±´´tÆ ½{÷vÙjD‚êuê³_¿~¯¼òŠQ¨¬¬t:JÍ!¹yÍN’““W®\yáÂ…+VÜ~ûíMòQú?ª€ nT¼+𪪺 æ“x@rY@ zÔGT&Ožö(sBITÛáOà IDATxœìÝyxSUâ>ð7Ý  ”.iKËR  (t`ADË¢‡UDD¾RÙå²ÉŽ Š £ã8n¨8"* Z(‹€ˆ¥-H ]è -K×Ðüþ¸m¸Íz“fÏûyxx’›{Ï=÷Ü4ysîɉL©T‚ˆˆˆˆšÀÍÖ """rxLTDDDDMÅDEd6Ë—/3fŒ­kaØöíÛCCCe2™­+bwTm¢µqÌÒblv;‘””´bÅ [ׂœ •º¼¼¼Q£Fùøø<ðÀß|ó°ÜŒ¯ƒ²Æ¤¯,0j_M®¯EØCÅô¿}ëúõë[¶lÙ´i“p× O¤ÌÌÌ!C†øûûûûû2$33Sÿúª]ÏŸ?ÿ«¯¾r‘1”ª¿šæÍ›<øÜ¹s¶®‘võ§áÄøÇ?þñæ›o–••YzGä:˜¨Ô3&..îâÅ‹ååå+V¬Ø²e‹Ùw¡Ù±cÇ´iÓ¤¬¬vÛÑÙÃQ˜·|ðÁÈ‘#ÃÃÃ…»Vx"3¦OŸ>yyy¹¹¹½{÷;v¬þõUÇ›››{ÿý÷›½>vKø«ÉÍÍ0`ÀSO=eëê8›ÿyZ¡ÑÑÑÆ ûè£,½#r!JjÌÓÓ³¢¢Bm¡f‹)Š—_~9$$Ä××wܸq·nÝR­¹víÚÖ­[ûùù=óÌ3UUUúw׫W¯ÜÜ\)3¸ëÝ»wwéÒÅÓÓ³M›6ÿüç?µV[­ÀwÞy§M›6žžž÷Ýwß©S§ô”ß¾}ûóçÏ+•ÊË—/Ëd²¼¼<¥RyþüùöíÛk«µlܸ1**ÊÝÝ]|8V¯^úÕW_­^½:88844tÏž= —.]züñÇ›5kæííý裪 U«VÅÅÅÂòššš¢¢"q­4GUé'W¿Aƒ}ÿý÷ª»Vx"ùøø¨–WVVúúúꯡ®ã¯ ý)¡T*kjjfϞݪU«ÀÀÀ×_]ÿÊZOÖ…f9ãjG-¨ªªòòòškêÔ©-Z´hÑ¢ÅsÏ=WYY©¶²®?­'EW…µ¶ªäãÇËåò7ß|SmjgGWU¥TLíNóÔœ}ºGª»Vx" :týúõåååeeeëÖ­KLL”ROýÏ éO Ë–-;sæLZZÚ¥K—®\¹¢e­§@ëBÓÎxëÖ­õxyyùúõëï½÷^‹-ÊÏÏ¿páBfffvvöâÅ‹¥4tœ]ÖÚ>‚ÿýïÆ ÛºuëÌ™3ÅË5ώĪJù£Ó<5Ý»woÑ¢Åþýû…•÷íÛÔ­[7ÕæÆ6”ž?4£ª*f¹×‡„„„“'Oê?""#X<³9šÜÜÜ)S¦„‡‡Ž?^èŒQj|&kӦ͙3g„Û¡¡¡ªÕ.\¸ ÜÎÈÈËåzöÕ«W¯sçΩîê?ªGuí:::zÓ¦M—/_Öº•ÖKJJ„Û·oßöððÐSþîݻnj£T*‡:þüáÇ+•ÊÑ£G‹{eTÅjmùùùšPZZªT*«ªªÄ·…ªjnß¾¢Yà¥K—¢¢¢jjj”JåóÏ?ÿÙgŸ©m¨¿q$ž\ý<<<„ ¬ðDÊÍÍŽŽþcccÅÍ«•®ã¯ ý)¡T*###322Ô 1êù©u¡˜ô3®ç T"""²²²”JeDDDff¦°BzzzDD„ZËh-MÊIWXkûX¿~½\.ÿí·ßtUX|WWU¥TLíNë©Ù¼yó¸qã„…cÇŽ}ûí·Åu0ØPjw žP»z}P(žžžºªJd,&*®^½:sæÌ¾}û wÕ^A<<<ÜÝÝÝÝÝÝÜÜÈd2Õj …B¸][[«zOÒ´{÷î#FH¯ªºv}üøñ#F´jÕ***Jw¬Ym­J)¿¢¢"66ööíÛAAAׯ_¾}ûvLLŒæ5]- kwâåZo=z´_¿~þþþ›¢¸©ÅŽ=úÃ?¼sçNÇŽ5k¥¿q$ž\ýBBBTWÄ,÷D2dÈ+¯¼rýúõëׯ/^¼Øàõ )‰Jë]]•tww¯­­U+Ĩç§Ö…f9ãjGQWWwáÂ…~ýúíÚµK¨¹þg©®D¥u+]ÖÚ>Ú¶m»hÑ"ýVÑUU)“òd»víZ@@@iiiIII``àõë×Ål(µ»ZO¨ UµÎëCqqqëÖ­5+Id&*}nݺ¥ú£ö÷•““£¹‰Ú'°ÈÈH]…ßÿý‡–^UtíZe÷îÝaaaZ«­µ@‰å?úè£ëׯ«ë•:GâÉÕOm•˜…žHÞÞÞâqTÞÞÞúkhr¢ÒUI­}0F=?µ.4ïouùòåððð›7oFDDèê)Ѻ/ÕB­'EW…uõQåää´oß~ýúõ+¬T*uUUJÅ$>ÙF½iÓ¦7Ž?^mC]{÷ððP ,))Ñl.­gYzU­óú°{÷nŽ£"3â8*uÇ?pà@UUUIIÉÚµk…Q322T«MŸ>ý¹çž»xñ¢B¡8{öìøñãU½ôÒKÂEýääd]_,úé§Ÿd2Yß¾}Å %Ž£ÒµëqãÆ;w®¦¦¦®®îÎ;Z«Ý”ò׬YóðÃ2dÈš5kt Ü‘ÒÒUVVzyyùúúfggëù^dBB‚¿¿ÿ‚ ž~úiÍGµ6ŽŠô“«Ç°aþþúkÕ]+<‘ºté²fÍš²²²²²²µk×víÚUXnöožëªä¤I“^|ñÅÜÜܲ²²äädý+k=ZšvÆ¥uttôý÷ßÿÉ'ŸŒ7nöìÙÅÅÅBóŽ7NbSh=)º*¬µ}DFF8pà½÷Þ[³fæ.Ôž!«*åNש™2eÊ»ï¾ûÞ{ïM™2Em]{ïÞ½û† ***òòò¦OŸ.^_ÏšôªJהׇO?ýtøðáM¬Ñ]¶ŽtvçÛo¿íׯŸ··w‹-†~ñâEaùÊ•+›5k¦j±;wî¬^½ZøVÔ½÷ÞûÅ_ˬ[·Nø&ËäÉ“u]Œèß¿ÿÎ;Õê?wýé§ŸvìØÑÃãk×®ª/¨U[Ïî –/Lw$ þ†sª>kª•£µtí†>ƒîÚµ«]»v±±±Âºšë›o¾iÓ¦ê‹KbZGU‚Ä“«_iiiHHˆj膞HçÏŸ8p ¯¯¯¯¯ïÀÓÓÓuµŒÚrƒ+¨ÝÕUÉšššäääààà   7ê_Yë)кд3.ñ ~øá‡ž={Š¿Â6uêTéßõÓzRtUXkû¨½zõjçÎW¬X¡¶µgˆ®ªJ©˜ÚQè:5wîÜ‰ŠŠŠ‰‰QýíÜ{ZZÚ}÷ÝçááõÖ[o©Ö×zBM¨ª^._¾tíÚ5ÍJ™F¦T*ÍÓ\˜pßÖµ0‡OdoÊØ°¶lÙ’——·jÕ*›ìÀòåËÏŸ?¿}ûö¦Õ”ftž'¡!6?ãvÂθý¼>$%%õèÑCÿ×±‰Œâ0‡ŽÂ^Ú øDÀ„Pe«(//ÿë_ÿš’’aý½›ó<‘,ÆÉÎxS8г…¯äÄ"""—ÅDEDDDÔTLTÔ;¨ˆˆˆŒÇDEDDDÔTLT$Â*"""“0QQG›1ˆˆÈ~0QQcì """2`Q“0Q‘;¨ˆˆˆLÂDEì """j*&*jÀ*"""S1Q¹<Θ@DDÔdLTDDDDMÅDåÚØAEDDdLTDDDDMÅDåÂØAEDDd<®Š3&™•kc‘90Q¹$vP™• c‘™0Q¹vP™•«b‘ù0Q¹Θ@DDdLTDDDDMÅDåJØAEDDdLTDDDDMÅDå2ØAEDDd1LT®3&Y•+a‘e0Q¹vPY•Ë`‘Å0Q9;vPY•k`‘%1Q95Θ@DDdLTDDDDMÅD弨AEDDd-LTDDDDMÅD夨AEDDdELTΈ3&Y•ób‘µ0Q9vPY•“b‘1Q9vP‘5}"³øSÎ »0#Ǫ­£³tk;ÄÙtˆJº [W€,€Td…ûqnJ£ö&üä}í¦"¤¯­«e$ñû›|BÐCÑöx6·]µì˜Éß6ì<÷m0Ofdu gÇ>*'— 2£œ¯°o0®îAÍu(¸}—þƒh´Îx¥ƒ=ßêjP‘‡«{ð[2¾íˆk'l]!g”ñ&ndغD6À>*"Òæô+PÖA>÷­C󨹎ÂýÈÜbëj™JH~uÕ¨¼ŠÂ8·7Ò‘: ÃÎÁ»¥­+ç\êjñÛL<´ÇÖõ ²6öQ9 vP‘yÝÌ€ûÿƒ!ó€w¢Gcpj£uÔÆpwkÊpäi|€/Cpþu¨*ÄáQø¼¾l…S‹¥ú&µåøåYìh‰Ï›ãอ¯bÙá§ø"Û½±«=~Ÿ‹š2©åæ ÿ´„GO °ªŠù–…[Ûºjœ[‹ïïÅg~øÌßß‹óPW 73ñ©;>÷G͵F›Ô”áóføÔ½¾›Ç„&•z7qt">÷Ç—!8¹ðn ª*¬fˆD\Ý‹œ¯ô­£§et¹•…ƒIø¼v´Ä/Ï¢¶\}…‚Ÿpà1|ˆÏü°· Rî>¤ë ôl¢¢çtëÙ\QßçcW[l÷ÂØ÷0ò¾½û¨±Ïa¥é›ðC>o†ÏüðÓäîj\IgÓà1ê2¸õ'<†Ï›á‹üò,jojyVè9ýíàtdJ%߃™××±¸n+Ðáï:{qÔžuÂ݈aÈÿîî:ý¾Ä™WqýäÝ%½¶¢ýóú6ñ‹ÄÐSð ÖØ…G& ûõj´è„!Gá(©’*9ÿá'Ѳ79&µp£j[W”A(þY½ÀÐxhܼpx®ì@÷Uèòÿî>z~~ŸÈ$ôÿJçõ5©ä£ˆ|¹_ß]!a3âþïî£bÂáHy…Ö~»»ÁWŽáçàî«e[ƒ-£©ºßß‹ŠÜ»KTm2^# Ü<1ä(‚{>(­›@òéÖºùÏcqù3m;5þ9\W‹Ô¡(øIß!è:›Q׿Õ%ØÝ •Wï>$¼oîîÝàáèlçÄ>*§À8EfwÏ8½_†`W{ƒ¬ÿèETaDFßF§Ypl2Ü<1<c*ê—üùoõMn¤ã‘_0¶C³XTäâÜ:-%_|ÙŸ Y,úïĨ2Œ­Á£'Ò7Òqv•ÑغÐÐgTák{þuÿ ¯`<ðFÝÀè›èû ¼Q˜ŠôM¿2ß¾ÛªÊ;õ}fñó%½I¥EeF\ÀèÛˆ{.}P¿\õ2" ’3áU¥E'ÄÍÀílíÍ"¥e´l²¹hÖînËß8§¾Nôh<úÆV#)mÆ¢®¶¾?OÏAéÙDEÏéÖ³¹P6cT9ÆVaÈD&&=‡3ÞDÁOðlÞïáÉŒ­¾[šŠ®³)ñum~n*¯¢yû†øå›Ýàáèj'ÅDå€4/µ™]Ûg0hä#àá[âÊç8: ?ôDU¡ {ýÍãàá‡.  ö&zý-:ÂÝ·~I¹Æ{á_¶ e/¸y¡eoüe ä~£¥ä?߀¾Ÿ!òqxÀÍÁ=Ñ÷3®1iåT_=c —XÛËÛ ×VD†gsx4C›qHx.Á=>•ù¸üiý&9ÿÃí+é‹V}%½I¥E¯­hÞ~èºnœ7Ð\F¥«®KáÝ çÖi¿$j°e4 ¹4[^ìÏÜn^ð‹Ä_Þ€n06ÑsºõlîÝ ÷#c  e¯úNGžÃÙ@¯­h7Þ-áæ…V÷×—¦¢çlJ9F]› ÝQw[ —z³<]íà¤82Ýa©õK±ƒŠÌ.ô!„>åÜÈ@ñaœ[²?6}>Ò·U`·úÞ!Ú—(n©o"t BúÀí,-%—Ÿ€=½´7:Æââê^¤oDìDõ=4wPÁ˜&•~÷Ôßði ŠÛZ61™W º½Š__Ào³´¼ƒJi5·²m-¯¢¼ƒôÈþ73¡¨¨_XY ¯’7Ñuºõožð6ŽNDÎÿó?hÞýw" ‹)ÏaaD|„¾cÑu6%£®Íoe@ˆè¾!¿íkðptµƒ“b¢rpì "K“¹# ñ„]í‘ÿ½áõ .1žAŸR.Gª)>-â,R¸D¡в7JAá>x4GÉ´èXŸ-Ĥ7©ô£0×IÑ¥ýs¸ðrwâê^ËîHðû<¤oT_XWcæM¤oùžÈÅÕ½(>Œ+_àæE6éi&áE^×Ù”xŒž ¢ ÈWÆàáèj'ÅDEDÒx€â¦¡õŒWtáCêoÿX-«tÁµvÆ Ÿq·ñÇrˆH4ºp‰µm‡²ÓÈßèQw W¯Zt¼»¤ËBLÂù7ê{Ë:Ï•ôª‹yšH(e“j"sGÏMHˆßfª?$±eÄšÅâFº––W†þôÝŽˆGáÙµ7ñE€Z…ÔÊð&tŸnƒ›{4CÔHDDü|ü/¥Ç“NP‹Ž¸~¹»3^ê&*Q¡Ù‹FØ ú%jß'r8ZÛÁIq•³àoyíé [p#uÕ¨«Áµ4è~ÏkŠ3Pzuµ(ý¿Î€Hm×8âþ©Ãõ_Tä@©@]5nfââ6ì½_ÒŽêjpû2²þ‹Pö|Z£Ã £ —XÛ6cà×pås(nCq —?ʼn½5F>†€xäïÆ•/à†Ø§%ˆ.Mo"ÞÁP˜ª>)ƒ±BBÔH-³}Jl1¡ßN³åUîT€»Ü}p+ ǧ©— yP7è:Ýú7ߟˆ‚ë®~Ü•`Ò ž¿þ—ÞGÍ5ÔÕ äJß-ñu‘¯ßõµ¨«ÅµøõïV0x8ºÚÁI±JLf —Øõ|ŸÈ8 ŠÌ£ô¸–O“2wt{Õüûj‡=½ïÞõ‹Dü-«µ}×~Gæfdô.4?oøG£ß—w'†^¸ÄÚvžüïPü3i´Tÿ…_¡ÙÞ¾'+åpô´ƒ3r­>%fýmbl`2 k½ºÇ,EŽÈ±¦R³Pm/ŠŸÇ£ãLô|ÓÌ%™×¥÷ql Z?¨þó À‰û¨$v)µÑ_²ÖMôlnî+GyC""5µå¸²ÚMµuUˆ4|%ÇPWÚrdŒ´Ù€“_¹k 'G¥'µX§CNm/jõîš­&ÌRDŽKÕß‘xwN "û‘»¹;- ºíáî2œªJ­ÈØÎ' ÑZóôW1N9:™BrîÁ%äÀìFø#ð €›šµCç¹¼¿©ßŸp^N2ŽJ-ØÿA5©ÂüB‘qøDåpYJL­G͆5!""¢¦pàDåÐYJŒ¹ŠˆˆÈÑ9j¢r¾¢:"ç8"""—â‰ÊYÇóÅD"""áx‰ÊY㔊Ó ‘óq°Ù\!m¨Í–¿fCDDDÆp°>*3OiÇ\!;‘™îǹu(=ŽÚ›ð“#ô!´›Zÿ»{øÙŸë'qf%Š¢öZ& ~ä# l’û52ßµßP{ž/ފȺ)Q¹ZÈpµã%¢&Éù ‡ÿeúrq~²y¢ÊÝ…ÃC]m£…úë“ñü–¬eyÂ[ˆ›aκ5ƒ]õƒ+Å ë©ÖCÔÏÊ5$"N¿eä#0üÆÕâÉ"<ðZ?hëj‰TàèDÔÕ"b†ÅØ*<ú¢ ýHܹµ÷"’r1N¤œú uvµÅ+Ld ‡é£rͳ_å´yr©ÓGdUÛ½PW‹¿•Â+Xû Ÿhüù«:‡²?ÂÅwqý$îTÂ/ QIè²^6U†´ÙÈÙ‰º„ FÏðEþX†œ¨È…»/ZöBÇdȇk©Àé¥8³ñH< 7O©Çõ¹?Swßú%Š |%µ"Ës°>*|?6ö›Ø¥¤ùcˆú{8ìÜ"²_9d¾êRc6SâÈS8ò4Š ¶u5¸õ'Î¿Ž½÷£¦¬ÑŠ??…?ÿškPÜBîNüØ5×à—)8¿·²PW‹Ú(ø tŒpºúÄÍ0"Nh3Ný?TæCY‡Š<œZ1Os˜Dç`}TŽR[³ÐÕ-×Ä8bÃ6ÔUs—:­D–ré}›¡Y[÷„|ÚŒk_4ÇQ]üŽOC³Xô؈Ðp÷CÙiü–ŒâŸÑy.îÛpw«fíÐ÷Ý‹ë¿ãçq¸•…øù¸w>óÅ*$lFìD¸{ãZέGÿ¯´ÔpGjÊðè üùodýZöÂ=ËкŸ¾ãª«ÁÙÕ¸ø/Tæ×/ñ@‡ç¿Ð¸dFdaÖGå:ÄáüýL–¬µ/gÇ‘´}ƒöA>þ¸õ'®|Ž£“ðCOTêÛêÏw ïgˆ|žpóDpOôý r§¢¿lAË^póBËÞøËÈý¼[@á~dlBá´ì¥=N¨½ ç7àÂ(nAq …û2Eô˜UE¨.¹» º•W1øD6åaë Hâ‚Tú9AShvË5GË™MèC}Ê;¸‘âÃ8·e mú|¤s“ò3°§—–‡*®4º+îI é·³ ámˆœÿ!çм=úïD@-ºûBq µ·0"ÍÚâV~{ ù»qz)§#½„¾´ßçãÂ;ˆŠž›Ð,·.áD2.l…›7znÒßDÖÄ>*;e·ýLf§«×ÊVõ!rx2wÄ£ý4 Üùßë[YÏë‰ÚºD>†'rÑïKtš¿HܼˆãÏk_Ó/îÍã ó@óøëûpíW}åg}}Í;@ææq¸ÿ?­;&Ù‚côQ‘+Pëµ’Éf‘ò ÅMÑ" ”@Ç–€.¸vÃÎhïU+:„ð!õ·‹€lý]fˆ‰¨‘ˆŸÿ…£ô¸öZý7Òµe¸†Êh˜Jq}Ê’Ý]Nd7 Š—ü\8Z±³ŠHª=½qa n¤£®u5¸–†#ã EÇ»ëx@a*ÐðŠ÷wH†¬ÿ¢"Jêªq3·aïýÊ?1¥ÇQW‹Ò_ðë ˆûQð#·¡¸U?²J×;KìD8ö n^€òn^À±g4šÕ]SP78ö,n^l´U`7iíBd%Ð ÀDå²8¬ŠÈšÓM¹£ßD&Õß=< WvÜ}Tè:1™›µ—)¬ ”1ù»ï>䉡§à¬e¿1ãÑçc투-ñðÇÇtŸöõäÃ/nአIDATÕç‚—¹cÀwDçVDVç}T䲤ˆŒðèoè4 Ýàî 7OøÉý7<|ðnœÐóMD= ¯à»Ú$üDôßà'‡›'Ü}Ó1äh£òû~‚vSàD>ŽÁë§”‚È$xCæf±ˆ½ßÕYÉ¿þ÷®C‹Žpó‚W0¢žÄ#¿è‹S"1h"†Â+2wx#bígœ"{cƒ>*Ó®ãðÍÕe±“’ÈÆlþk€DŽÀJ#ÓwRJ²¨NDDöÌ‚‰JOŠâ[#I§T*ùí?""²sfNTü™²U¨"""²OMýÐÏŽ(²ަ"""{fz•Ö,Å7<"""rAF'*Í ÅEDDD.NêU?)²9^ø#""»%©J§ø~FDDD¤ÆÀœéâVS*•ŒSaûöí¡¡¡Â‰ß&""" ÑyÕÏùú¥¬<›‘YvgZ!ÑÑÑÛ·oïÓ§ÚmGŸÏ‰WýˆˆÈni‹uÊ_¨uÄ}úàÁƒš[ §@møÚñãÇÓÒÒ €#F$''ÅÇÇÏž=[m+­%è:R"""2™–Ë(Κ¨T׌d2YIIIË–-TTTÔÖÖˆŠŠJII‰‹‹o%—ËSSS;tè ##càÀyyyB!¥¥¥ÁÁÁÕÕÕ>>>ªÛþþþBÜ1¸»ÈÈÈ´k×ÀÅ‹;tè õ\ˆÊd²üüüððpÍ£«¨¨ˆ‰‰wSi– º­õHퟳ>3‰ˆÈ ¨'*'~ÓGµ˜"Üõð𨪪.¨©xxxTWW»»»P(¾¾¾B2˜Z¤ìN\²§§§”D%¾{ìØ±ùóç§¥¥Ý¾}[x´®®NJÝ´©ýsâ''9ºFWý\|Jxxø¥K—Ô†††fee ·/]ºj®Ý…††fgg ·U7Œ2jÔ¨3fäææÖÕÕ•——KZ”ˆˆˆL¦e•ËöLš4éÅ_ÌÍÍ-++KNNŽ7nöìÙÅÅÅEEEÉÉÉãÆ3×îÆŽ;kÖ¬’’’ââba”¦ÀÀÀŒŒ ]%TVVzyyùúúfggO›6Mú®µ©sñ¸ODDvÎÀ Ÿ.eéÒ¥;wîÞ½{Û¶mccc……+W® mß¾}‡"##_}õUsíîÕW_ ˆŽŽîÚµkŸ>}<==5×™;wnBB‚®0ñþûïÏ›7¯Y³fƒ zðÁ¥ïZë‘Ú3§œÎƒˆˆœ‰ú0ðMËÒÓÓ‡Ê+qºð™IDDvŽ}T¶4sæÌk׮̛7/))ÉÖÕ±SŒSDDdÿ%*ÕwÓlT—Ó±cÇÎ;wèСE‹+V¬°uuìŸDDä\hör8>EDDŽÂ…fø$â|?ÔMDDÎÍÁæx$§Ç,EDDŽHKØMe-js »2µñRl""r,ú¾ë爃‚±Î¢§)233‡ âïïïïï?dÈÌÌLa¹R©œ?~PPPppðÂ… ­kd Ä §ˆˆÈáhOTâ_‚³beÈJƌӧOŸ¼¼¼ÜÜÜÞ½{;VX¾m۶ÇŸ;wîÌ™3©©©ï½÷žô2e&— l`ÎC%""² }TŽª„ªŠßª«ªªž{î¹€€€€€€iÓ¦UUUinuçÎ… ¶nÝÚÏÏoüøñ¯2$55UXá§Ÿ~>|8€¬¬¬¤¤¤æÍ›ûøø$&&©ö»fÍšààà°°°;w®Y³¦eË–aaa{÷îU­°nݺÐÐPÿ)S¦TWWK©ƒæÑmݺ5&&ÆËË«G§OŸÖ³­fSˆ¥§§/\¸0000((hÑ¢EéééÂò>ø`åÊ•ááá«V­úÏþ#­á›„AŠˆˆœ€¾«~ª„ ‹ßž-Z”ŸŸáÂ…ÌÌÌìììÅ‹knµzõê'N¤¥¥z{{/X°Àºuë’““ Emmíܹs7nÜ`ĈÉÉÉEEEEEEñññâã+,,ÌÉÉYµjÕ„  ¯\¹²jÕª9sæ¨V8xðàéÓ§³²²®^½ºdÉ)uД’’røðá²²²¤¤¤©S§êÙV³)Ä'qèСëׯ////++[·n]bb¢°üìÙ³ Âíž={ž={VJ³k¥”Ìä]ÙÃ#£kN µ±Þr¹<55µC‡222˜——§¶ILLÌwß}×¥K………Ý»w/((0a„„„„ººº‚‚‚õë׫mUQQ#tSÉd²ÒÒÒàààêêjÕm…B!¬páÂ…öíÛÈÌÌ8p`nn®¸¶ºê vh%%%-[¶öP[[«g[µ¦ßÍËËëÓ§Ï•+WÄÆÆþüóÏáááÜÝÝkkkÝÜÜÔÕÕyyy õ7ö¨n;ÄsÆž©:J‰ˆÈ> 0@¸!é»fô©#<<<ª««ÝÝÝ( ___!…ˆyzzªztêêêd2Y]]€;v,]ºôöíÛ?üðC§N;vlþüùiiiª+kšâj½-“É …f5T+誃žC3¸­ž/>òÈ#½{÷úØ^ýõãÇïÙ³@@@@NNN‹-”——ÇÄÄ\¿~ݸ ªžê¶?g샑c0`€ßÞwˆ÷HÍ>ªhv‰EGG9r$22Rmù<ðÌ3ÏTVV¦¥¥ýûßÿõÚk¯=òÈ#7oÞ P&ƒ‰JÜG5hРœœñ ºê çÐ n«'Qùøø”——{{{¨ªª F˜õéÓgåÊ•°oß¾%K–>|XO• r¬N;!ŽSqqq¶«¦ú¾¼¿”¬6(GרgÛ ÌÈÈPÝ7nÜìÙ³‹‹‹‹ŠŠ’““ǧ¹ÉôéÓŸ{/*гgÏŽ?@JJJiiéäÉ“_xá…ßÿý?þPYYéåååëë›=mÚ4£*öÒK/ °’““Ÿzê))u€´lº¶Uk qQ]ºtY³fMYYYYYÙÚµk»ví*,Ÿ8qââÅ‹¯^½šŸŸ¿hѢɓ'uŒšÔž0M,Í¥ÄÅÅ1NÙ?Õ˵‰J ù;€M³ÔõuzÌ;7!!AUÎÊ•+CCCÛ·oß¡C‡ÈÈÈW_}Us“—_~¹ÿþƒöóó›0aÂÈ‘#¬X±båÊ•îîîîîî7nœ7o€÷ßÞ¼yÍš54hЃ>hTÅú÷ïÏ=÷ÄÆÆ†……-[¶LJ$Òµ­ZSˆ}üñLJŠˆˆˆˆˆ8tèÐÇ,,þùçûöíߥK—|ðÙgŸ5êµÒ âM/“ˆˆÈÞ4iÎn=ïŽÒ¼»¡#ÒsÎ¥ð" AÂ%?öN9–ÌÌÌ&ý®ŸžéŒíŠP*•ŒNO8ËàÏ‘Ó1úªŸV¦M2¤¹>/ 9=žn""—Ëm]"‡ažD¥‰S;йÔÁJÁ‘UD"o÷ÔSO]ºtÉ&uÐs×4Ó¦MëܹslllRRÒ?þØô2‰ÌËR‰ŠH?vVYH^^^^^Þ±cǺuë6cÆ [Wšó*›`úôéíÚµ;räHFFƼyó>øàƒ¦—Id^ö’¨øžêšØ{Gd!ÁÁÁ/½ôÒ¹sç„»r¹ü_ÿú×_þò—èèhÕÕÕóæÍëÔ©S§NæÏŸ¯ú±ÑšššY³fµoßþÞ{ï}çwT¥éêvR(Ë—/¿çž{:wî¼mÛ6ÕCB?™Úʺv*—Ë?üðÃÞ½{·iÓæ‘G9þ¼æáüþûïÉÉÉAAA^^^}ûöý裄åwîÜY³fM·nÝÚµk7cÆŒŠŠ µã•Ëå}úôQ½Ô(•Ê>}úœ?Þà†BCIg/‰JÀ÷W¤šÕÖ!r*×®]Û´iS||¼jÉÉ“'÷ìÙ#üüÔÚµk >|èСœœœuëÖ ë¬_¿¾´´ô—_~ùñÇþùgƒ{yýõ×322öìÙsìØ1¡/Jõ¿f×”®8tèÐÎ;ÓÓÓ}ôѹsçjî¨[·n¯½öšPy±Í›7Ÿ:ujÏž=§NòòòZµj•Úñæåå5oÞüÈ‘#Ÿþ9  sçÎ7ÔÜ‘~öòõ:~ùË•qVΞ@M¤êòóóKHHxõÕW…_kËå¿ÿþ{ëÖ­…G{ôèñå—_ÆÆÆøóÏ?G•–– gÏž_~ùeLL €K—.õë×OFr¹\œTw>ÿüó¶mÛªÕAëʺv*—ËÏœ9 ²²²S§N—/_V;®‚‚‚ 6ìÛ·¯ªªjРA¯¼òJhh(€Þ½{ÿ÷¿ÿíØ±#€âââ‡~øäÉ“jÇûþûïŸ8qâí·ßð÷¿ÿ½wïÞ“&M’²!‘tM=È,T³*QÓé·$N %%%ª«ZmÚ´)--nGEE ·¥\ö***’~uL×Nq €¯¯¯Öh {ýõ×…=¾õÖ[Ï?ÿüÎ;<üðÃý°©æñŽ9rݺueeeJ¥rÿþýk×®•¸!‘Qì%Q 臭’ŠˆÈ Zµj•““#ôE]¹r¥U«VÂòÖ­[‹—«Ö÷ð𨪪òññ þõÖ­[_¹rE­ÊØ¥uëÖ/¿ürçÎUwwíÚ®g“€€€ìرC©T4Hø1x)žÆQ‘$%%-[¶¬´´´¤¤dÉ’%IIIÂò'žxbÉ’%ªåªõãããßyçÊÊÊ‚‚‚ ¨–5Jø1Ð7n¨ÖoѢşþ)}§RLœ8ñèÑ£ÕÕÕ×®]{ë­·T¿FúôÓOÏ›7/;;[¡PdddèúnãØ±c?ýôÓíÛ·;Ö¨ ‰¤c¢"Ûã(:"+[°`AHHHß¾}xàðððùóç ËçÎÛ²eË^½z 4¨oß¾ªõ7lØðÃ?têÔiĈ}úôQ-Ÿ3gN‡ü׿þUu¹ð…^HLLÔœ†J×N¥˜4iÒ† :uêÔ§OŸ³gÏnÙ²EXþÿ÷½{÷3fL»ví^|ñÅ¡C‡jݼÿþ7nܸ}û¶ê $nH$}]eã;«Ëâ©pd:‘#ÊÌÌdÙ‡¥‘£³—‘ébŸ®‹fòp²†â©'""e_}TüYcÉغ"¦S]ïãTŸDDä¸ì+Q¡JÍŸš–‰ØªV&ÐZ[Ç:"""Øa¢C•nj)J)"^îÑJ\CñOn©µMµˆˆˆLb㨠šD›k4imñBUç»jF=?;ÃSODDŽÈû¨âî öXˆl ýW¶mL­]SjØSEDDÇNû¨âŸ{c… ´v\A#©X§aMÛ)Ï;9»NThxßU]‚]½²²¦ôÙèéø±ô¤ &d)†i""r,öž¨ÌUf¥¹¹”ŒeFÕœ¡Šˆˆˆc$*kæ*+Œ.×qeÑòMÃPEDDöÌ‘•@­ëBí![ÔÈRlõM=ûiFñ¹CÙ1ÇKThÜY%æ4Ëi¤éªœ[DD„­«@‘ŸŸoë*Y›C&*ÁkU—K®ÂÖÁPå|¤œžpŠ™«È¥8p¢RclÀÒ³­åH¢ÄÄ C•CÇ)¾ã:+á,GDDð“ëpžD¥Æ¨ÑÖö3“$ƒ‚VjÝT`¨r||£unÂùˆˆ`¨"×á´‰Jžw_+Ç)æÓ0T‘=s•D¥ß•C•Ãáð"rVöû»~Dj´†'û¹bKDD®Œ‰Š CÙ'&*r0 UDDd‡˜¨ˆˆˆˆšŠ‰Š»©ˆˆÈÞ0Q‘Cb¨"""»ÂDENEb¨bör,r¹\.—ëºköP"²+LTä¨tÍDe0- +0T‘1Q‘36TÉd2µ]¶HµˆˆÈõ0Q‘c“ª˜ŸìÜ×_-\J‹íׯßúõëkjj4WS]kS»îöË/¿Œ;¶cÇŽ±±±‰‰‰ß~û­x¹\^]]½téÒnݺEEE©~÷Ýw=öXÛ¶m;tè0~üø¬¬,)õ1¡Däô˜¨ÈiIéŽb̲~øá… Ξ=;qâÄ7ß|sÅŠš«ååå©n¨n=ztôèÑ …bÿþýüñG—.]žþù;vˆ7üðß~úéS§Nåää¨nÙ²å7ÞHOOŸ5kÖþïÿþOJ}L®91þ,9=ÁHó'–µ®cî™(55@\\œ­+b)ׯ®®.**ªU«V§NBCŸ*»¨Ýðä“O;v,%%¥S§NÊÊʺtéÒ¶mÛC‡©ÖW=*.äÇŒPQQÑ¡Cww÷+W®¬ upMüGr™™™ü¥drzb{¡BaaáÚµk:T\\¬P(„…¥¥¥7‚ΠAƒÄ /_¾,¾«5§vìØQ¸áççàÎ;&×GJˆÈ‰1QA&cg­MŸ>ýøñãsæÌ™:uj‹-îܹmìIIOOoÞ¼¹®GÝÜ´ rpww7o}ô׈œÇQ‘“hb$bW–mýþûïf̘ѢE 'Ož4jó{ï½À±cÇlX³×ˆ 9†*Ç%Ä‘>ø ªªêüùósæÌѳrpp0€ .¨–ÌŸ?ßÓÓsùòåçÎS(W¯^ýòË/Ÿxâ ËÕÇ u "ÇÂDED¶·uëÖÄÄÄ×^{­sçÎÉÉÉÉÉÉzVž3gN@@À€T3ôêÕëë¯¿îØ±ãèÑ£Ûµk7lذýû÷/X°Àrõ±BˆÈ±pø9›&v5Ùö/‚ßõ#gÂÓM®#33“}Tälx툈¬‰ŠœCYgO %eæO""û!þÉ#“‰§¥%ób¢"ç¤?0 XúçåC"²-³D(ýe2`™9-]I•ªˆÈ~ŽPM|MÒxµcÀ2#&*r-š!‰—ÿˆÈ¶ô)ó~¬S+MwÀb´293qZÒÓá¤+T±›Šˆ,G{²æKŽî€Åhe&*rrBZ2ŒªˆÈ lŸ¢ôW£áåP\a¦+ý˜¨ÈùIŒD UDd9Z²”=¿®¨ê¦ÑqÅ\¥ Ñ]SEDf§ž¥ì9HiÒˆVÌUº0Q5¢5T±›ŠˆLàØYJPyæ*ݘ¨ˆÔ1TQS8URӸˊØÅ˜¨ˆ´`¨""8s–RÃ.+ ü]?"히È(â”ҩ㔊‹¦4LTD:i†*Ž['"IdZæÏtB.r˜Ò0QéÃPEDÆQ›ÕÉY_0œøÐLÅqTD;¥‚]E.Ö %~’V+ž— 6ã€Lc¹ãR{yÓ6m•Ëb¢"2L-Tqˆº#²ZfÒÏ`5¹œJãáÛõ7ôÅCW–¢LTD’ªÔ>ºYçÕG¼/—ÿÈhl„ÊÏÏ·PMÄ"""ô¯ Vm,gà蹊YJ&*"©ØSå(te)ëd&ýô×A3oñKéÎCk®‚ÍOev[UûÀDEdþLýÇ){ˆPFQ«°Á-r<šì°ËŠR&áwýˆŒ#î—bº²[ùùù§49Á!NJmß ´í+Šf8Ý”1˜¨ˆŒÆPEV#„*;VOæ§Ô­´þk"‰…kÖŠ$àU?"Sˆ/ÿq@5•Ä/”Xú_Éš€‰ŠÈDSEDf¦?Иåõ†™Éb˜¨ˆL§ Uì¦""‹ãkŒ}ã8*¢&Q)öW¹2&*¢¦bïñª‘—ÿxí,Çn¿îÇÙG‰ì£"2!K5éÚ_&0ðü!@¦ªh`> 9–‚ì‹ÝF="+ãGj"sº›¨Lø]¿û€Ç—%ððø'ðð% žž¦êÚ½h_2,]ºÔ¤ƒ€iÓ¦‰ïn۶ͨ…º,[¶ ž¸RxƒçܘÖ!Ìꮫ›JxT8é.bùòå.ú™G¸v‡eff&û¨ˆÌ©IQÒ…@ ,Ò–¬Â`ð3Ô“ˆˆÌ‹‰ŠÈ¦Ä ‡ër  X$6,? $4Üî œµj‰ˆH ŽL'²ÿúK±ÀÏ ËoÍn7nÚ jDD¤ÇQ™YýP*ÆQ=ôf^Ž{@ÐPÄ×uí[´¯¦ kˆH½;Ü8€ÙÆFk¤râ¨g+3vü™”qT®3¦­þéêšoªG•™É>*"»qØx Ë»'€€ß€.–Ú¿8E‘krµ DdFLTD6%}¢í¬^lº6,Ÿ,nø®ß"àY³í\J„2c•é\óC¿MpæG'3éïE ,þÈ€çÕ|&˜‚#Ó‰ìÆÇÀ! ˆ7,è Ä]€HTK—.ݶm›žé ì"-9…mÛ¶5e¾³1íãÇ6à0p8¤ï™·N®‚‰ŠÈ¦Ä/€ ¨R€Ž ËeÀà:pX+õ³£Äwý¡Êæ‘«~X?.[h¸öGÒ©>·,]ºté2#sÕ÷@WÀ ˆTî Ö€0¸Ý°\l¢Ð^ô¢Ú§E,µÀ Þ0T,§h1&*"WgóØDäÒ&Ë€›ÀAà׆…«@Px DëÒ%ÐØß°pt­¶ 8¤—€+†Šå-æÀDEäüôÏcûU즲 vSI§ö÷µ|Ùrã¶÷ò€B øWÃÂ÷€M@$ÐX ì­ÿ:Ð 0x·aá»À”ÆÅþØ DAÀ&CÅrŠs`¢"rNË—ñ²‘*× Uö³È‚ø=c¨Ç)cþîêíR€ž@4°³aaÐðÜ0 H´~xç€ÝÀ5 ø߸ث@[}é*¶p«áöM ¹ÑA`¢""áZC•}a79¥¿»€bàŸÀ Ãl@Ü”@¶ ƒ€G€¡¢ùVT%\ÒØDW±Â-KNÑâܘ¨ˆ\‚® ª „8¥ Uv•®\yÚ@ÛàøtiÌÐA`p¨ê€; §ÏpV£ÿIE¸ð÷žÆ%?“€\  H6T¬0EËU XL6å8ˆ‰ŠÈié}H•«Å)ÍÛD¤‹Zœš6mš‰=Œü—¾ ô~À`¤ŽmÊ[ 3‹-:ݶ@¬¡bM¢…Ä8Ã'‘+Òš¥Tì0TåååÉårg/l"›ìÔ>DDDpþt)LSÆc5º …Ë•«]ѱ‚'°I4&]±Â-Œ¨5ib‘«P}¤Ö§œSç8Åš6bL Ì‚€``a“S «†H‰ ~–\‘3Óüèì¸qªIÓ(| 7km,Z,§½¶of»ÞGÎ…‰ŠÈ…8nœjªï€á@ pp„ËYé@º§“°ü)@µF±pœi¯³€$ 9à$6þN¾&ŽO—€qŠT˜¨ˆ,CÖðOí®Eÿ‰÷Õ@õŠ¿,®~ ºÃÇ)c»©Š€L ¤¾¼oû¡ôÎR}8 dW%ÅÂq¦½$E@Ì6Üx¤†×ûH™RÉ«åDæ$“ÙѼI•2U×Բ̥¶ýH-tx4e°³\.Œ¼.öà;à à{à`;0 è œ¾ÆÏ1Àw 3ñÝ€ ¸´dÜÆÅhÌž¢EûÕS`~Ã&×^€Bo³T1†º©žËºN™pBuMoÑôÓmoô_ï3åÉé4d€kOt’™™Éïú™YS>¥¤¦¦ˆ‹3çhgqœ2c±ŽD5Úi0¨Ží€ à8ð€†é¤Ñ0ó¡8«¾|Þ(Ô(ÀàU`%à üH2T xÚëÅÀ5@ ü¼Ó¸æz¦½Ö,V˜öº€ÆÓ^«VPÇ€ù@ZõBƒá_ɉUuâõ>Rë~DÎL3N9ú5 £Ç§×) ×õ|ŽÀÛ@O è l:>ôÎRÕpã¦Q,ì{ÚkeÃ?£€@.P”»joŠ©ýo‡,‰ŠÈi¹î8t±ƒ@G uÃÝD` ð0`°HlxHÏ,Õ/5Œ=JžÒV¬£L{] x¾@6 ±‡…ãÓðû}$‘sÒ§ý£¶qÝTßÃDwëÀ` óM«•žYªû÷±@°L[±Ž2íõûÀ< 0x*‘Âm IDATPG}ÈÆ)ÒŠ#Ó‰ìˆYÆQ©²Ç)q²Õ[‚¹†*18ø ¸¯‰;´V±vKh;q.22]bG¦sd:9׺Ò'å÷a2-³k KöGúõ¾»¿•ËU.§¼êGä<¤Ç)'¹ðGda¦Ÿ’¹Æ×$E‡YßE瘨ˆœ„Á8ÅÁd:ŽO—&//¯QÜwâ\ÕøÐÔÜ%ñª‘3p­‹}ÄWX\êò Y‘ÉTªlQßm#žÌÑ5ˆLQbì£"rx¦Å)G¿ðGÖæbÝTf™.Á©º¬Ø)e‘‹H•§œìŸѳ}Ù‚ö\å(Ï[Ú2Ké«~DŽÊ¯ô‘=ˆˆˆp‚ ô³Ä|žB i4|Ûž¯j | Rú1Q9$³Ä©mÛ¶9I¯GSY‡küÌŸE§G‡’»éJܪ6|&3E5 ¯ú9ž¦Ä)'‰P ørOŽ+¯A£¥²Æÿ,J÷¾´×ôb‘ƒáÅ>²%% sæ 6ùý>õ…ª&ö`ŠhŒPMÁDEäḨœà§Q s±ùÏ!«ÃËÜ{¤¦`¢"r fÌRÓ¦MãÔ ÔDNÜMe? ¬&—IfÄDEäx¥O?vSY•“ŽO·y•A CvŽ#Ó‰ì¥ãû«ˆì?N‘ýc¢"²kŠSNû†áŒ}'öÈ©çOwÚ¿²0&*"ûÅ‹}Òñ‚™ŒÝ´dLTDöÈØŸ—i"¾£Ëâõ>2&*"»#ÎR–‹SÎ÷ÎÁŸù³*gü€óýQ51QÙ—ù 7x¥ÈÒØ;KfÄDEdG¬§ÄŸÈã­…ÝTVåàÝT¼ÞGæÅù¨ˆìÆ'õA€½SfÀPEÆ`œ¢¦c‘}hˆS©ûm["£8è·,£S–ìŠL©tð~["G÷ÉÝî!NÅÅÅYsÿâ·KRf0⯗¸»=ݼÞGf—™™É>*"›RÅ©ñJŒçÇ"kcœ"sa¢"²qœ²¼BNOr²&*"±›8ÅÏèä:x½,‡‰Ê82¿AdF5¬3œ»‰SD®ƒqŠ,ʲ‰*//oÔ¨QAAA>>><ðÀ7ß|#,7ï;â©S§}ôÑfÍšÉåòÿûßúW–i0cM슚ŠuŽÑü{±ï8Åk"DD&°l¢3fL\\ÜÅ‹ËËËW¬X±e˳ï"33ó±Ç›6mZQQÑÑ£G:dpecf¯’pâCs`ŸÈêã”C·Ú‡uák_ÂWÀˆ¬‰Tdi–MTÇ_¼xqË–-½½½øý÷ߣῸèÎ; .lݺµŸŸßøñãoß¾-,—ÉdëÖ­ õ÷÷Ÿ2eJuuµæ.–-[¶téÒ‘#GúùùEGG¿ÿþû&ÔsÈ!©©©ÂíŸ~úiøðájkkçÌ™ôÆo¨VÞºukLLŒ——W=NŸ>-,ÌÊÊJJJjÞ¼¹ObbbQQ‘ê´®_YY9iÒ$ÿ°°° 6l 1]Í"“É6mÚíááQÏŠL&[³fMpppXXØÎ;׬YÓ²e˰°°½{÷¬¼P L& )))–×ÖÖ¶nݺ¸¸X\+c[ ººú™gžQµ€Öó¢«LUÉüDRké'Qú^ ³ï®)"'Æ8EV`Ù9Ó{öì¹téÒ^x!66VµP©TÊdæÁZ½zõ‰'ÒÒÒfΜ¹`Á‚·ÞzKxèàÁƒ§OŸ–Éd“&MZ²dɺuëÔv±oß¾®]»FDD”——6ìŸÿügPPµ]è·nݺɓ'ÿöÛoJ¥rîܹ_|ñ€eË–9s&--­Y³fË—/W­œ’’røðáààà×^{mêÔ©Ç0bĈ͛7úé§µµµË—/Ÿ={öG}¤gýW^yåúõëÙÙÙJ¥òÙgŸ•Òbºšåøñãiii­ZµR[¿°°0''gûöí&L˜:uê•+W¶oß>gΜ?þøCåUΜ9sëÖ­‹/Ú¼wïÞ!!!â]˜ÐÅÅÅÙÙÙuuu“'OÖz^ô” #ŸHj-#ý$µ}*NmÛ¶Í:S‘Ó³Ãɨˆ,IJ3|æåå-Y²äû￯¬¬:tè† „—Qµ·¨˜˜˜ï¾û®K—. »wï^PP ¬váÂ…öíÛÈÌÌ8p`nn®Ú.<<<žzê©7ÞxÃÍÍmÖ¬YUUUÛ·o×Ü…Šæ˜aµ &$$$ÔÕÕ¬_¿@TTTJJŠÚ\‹2™¬¤¤¤eË–***jkkÕ ¬¨¨ˆ‰‰Qõph]?22òÀíÚµpñâÅ:ÕÐÕjuÐÚ,2™,???<<\µšP¦L&+-- ®®®öññQÝö÷÷W(ú+¯*0++ëÁüóÏ?===§OŸ>pàÀÑ£Gk6¯Q-ššª:ŠŽ;ê*ª•©:4‰O$µ–1ö$JÙ‹>’ã”ÐWjå>U¬6Õ'㔋°“8Å*²‚ÌÌL+Í™^PP°fÍšß~ûíðáÃÐx‹òôôî*•ʺº:™LVWW'¬¦P(ÜÝÝ( ___Íw¾€€€¬¬¬àà`×®]kÓ¦ÍÍ›7õÔDWÒÚ±cÇÒ¥Koß¾ýÃ?têÔ €‡‡GUU•pH׿ª»ÇŽ›?~ZZšp H|Z×÷ð𨮮Všªt5…Z´6‹®}‰—k½-±òcÆŒ1bÄøñããããOž<éãã#®•¹ZÀ¨2¥?‘´ÖÁ´vrŽ1¦wÊE‘Õ0N‘uXoÎô°°°Õ«W ×V4…‡‡ggg+Š;wîïRª‡²²²„—.] Óܶk×®ân'“¿–µiÓ¦Ù³gÏ;Wè juéÒ%‰›5jÆŒ¹¹¹uuuåååsjhhhvv¶p[uz›BÌ`³EbåçÍ›÷æ›o9räP‹SÒ Q ES*&.SJëé"qwFìE5Žq±OŒßø#"2ŠeÕðáÃ8PUUURR²víÚ{ï½WX˜‘‘¡ZmúôéÏ=÷ÜÅ‹ ÅÙ³gǯz襗^******JNN~ê©§4w1yòäY³f]»v­¬¬lÞ¼y r­RRRJKK'Ožü /üþûïÂè¢I“&½øâ‹¹¹¹eeeÉÉÉúK¨¬¬ôòòòõõÍÎΖòhìØ±³fÍ*)))..ž={¶j¹ž¦3Ø,F‘Xù„„ÿ <ýôÓ&¢2~üø—^z©¸¸X8 Ó*&ý‰$…®Ý™¸üy~|''Ã*²&Ë&ª^xá•W^ l×®ÝÉ“'?ýôSaùܹsT¡çå—_îß¿ÿàÁƒýüü&L˜0räHU ýû÷¿çž{bccÖ-[¦¹‹©S§FFFÆÅÅÉåò7n¼ýöÛk¥9ÕŠ+V®\éîîîîî¾qãÆyóæXºtiçλwïÞ¶m[ñÈz­Þÿýyóæ5kÖlРA>ø Á:¼úê«ÑÑÑ]»víÓ§§§§Á¦3Ø,F‘^ù¹sçæååõïß¿)…–/_Ò¦M›{î¹gàÀ¦ULúI ]»3e/Û5Eä4§Èʬ4ŽÊ4F}_Ïq¥§§:TúF6Ë–-[òòòV­Ze“½;’O´u‘Úý8*ðMˆœŸÌdMÖGEšfΜyíÚµ‚‚‚yóæ%%%Ùº:†•——oÞ¼yÆŒ¶®ˆÃ†U‰ÿÙ¾ës`œ"ë³ì|T¤GÇŽ;wî\QQñØc­X±ÂÖÕ1@&“¹»»oÞ¼™ß{—Dkw”f„Ò\±ß"õ!r%ŒSd.qYÈNIè¦Êg…Šˆñ݈ç!ëËÌÌd‘íhveid¬ˆT¹Ú3f,¡pµ§M›Æ©ÈqñÙK¶ÂDEdGR#ö£ñÈtÍDeöŒ¥5W9"ö°’ 1QÙ5Í c¡Œ‘*׺•~ãÈø¼%+c¢"r0–ËXªÎ*^ø#GÄ'-Ù‘Ã3-c颫³ŠÈžñzÙç£"rBùòÔþµyDª|YÜrÕ]~ô'ÇÂ8E6Á>*"— ¥KͲ¸åË2—Z¬FDfÃÐOö€‰ŠˆÔ ñ‹ïRäx½ì¯úQ=µK„âw&¦+rŒSdCì£"ru‡NŽ‹YŸì‘‹26H™eb*þ.¤³ÊÏÏ·þNy½ì ¯ú‘Næz‹Šh`–ÒÈYÿü2N‘½aY–øÖ&=dÂYŽˆˆà)&—Å>*"’ª)cVòóóù^ëÄTç×:=Uì ";ÄDEDúð½Šì ãÙ'&*"² ¡Ç‚½SDäô˜¨ˆÈü²:Ù;¨Èn1Q‘|Ó";Á8EöŒ‰Šˆˆˆ¨©˜¨ˆÈ8¼ðG6Á*²sLTDd߽ȶ§Èþ1Q5Í&þär¹\.·þ~ÉæØAE‰Šˆ$áÛÙã9 þ®9†¼¼<[WlŒqŠìû¨ˆÈM¼ð'\ÂÛ±cÇC=Ó§OŸ/¿üRíÑêêê¥K—vëÖ-** Wý„»üñý÷ß3hР½{÷®[·®GmÚ´:tèÙ³gÅ{üú믅Mbccûõë·~ýúšš]»:t¨\.ßµk—jóÝ»wËåòÁƒ7å¨ÉXüb)9&*"’Êì=Û·oÿì³Ï~ýõW¹\>sæÌ””ñ£~øáÓO?}êÔ©œœ]%9rdïÞ½o¿ývzzú3Ï}ú\sÍ5ÁÏ1Cœ‚½P£1'þ¬ìĉ’æÏŸŸžÎߟ1—Äï%¤þ€ ŠŠŠvïÞݧOŸ¥K—zT!¦˜ïƒÝ‘¨µfÍšH¯Ö¿IßÖ­[=„BœB`Ö@4¸æ@  ‘(P!9¨˜€5ňq IƒD J\ü ‰ ¨LHTÌÁÄ"BœB’!QˆWAð"Qâ’;|0M[}ÆMnnn|^Èú›—&q I‰DÀ;î¸Ã"+¨â–™:Öé0ˆ\@R"Q°«H#”ÛíŽÑH9ÎŽŸÐfØ©°(P!Y‘¨˜)>¡²T|2SÇ:Cû¼å=—ÉUÄ)$1£â<ñ§¬¡"ÒfÀ´’q I†Dáp8=s$qåÃvY*(·Û:¡Ê"ëí€a÷&ãÂo4´È²úØa¾ID„äñœó´Ñ"_íÇg\ >Þ-HJ$*@lQ¶D* Q0WP´b¾)‚DÀ\)Ñ)Þ$Hb$*@¬P­Dê`÷¦ ܘÊÊ÷ø³&Ë~Ü/ê=8˜ïCJ¡Fèˆ)Q8…¤G ÌÊ»•F½)ó}H5Ô¨˜)°Á55e1߇D¢˜‰8…ÔD¢0ŠuT€ù\.ÝsÞ}W’®¼R«ViÈIòx´`Ö®•á¹sµt©¼wdÕÞz¿æøßUƈÀOüu*êUÏ©sƒasÅzÍViiià·¨:¨Qæ+*Ò˜1ª­UM~þsÝr‹¯}ÍíÞ­ÊJíÝ«òr­_ßI{BîЇäæt:cF‰SHe$*À|UUZ¸PYYÊÎÖ¢EªªòµoܨŋկŸœN-Y¢ :iO ¿Õtê|ˆ`ŽÖ:I'êÉ'ÕØ¨†­X¡ÂB_û¾}=Ú÷¸ @ûöuÒn_'RS`Š÷R ë¨ó­\©1côØc’”—ç[P%éÄ õèá{ܳ§Žï¤=ÔÖÖæææ:”OâÄã‘Ã!§Ó£U¥¥¥VÞ^ ˆjT€9Á¬Yš>]õõª¯Wq±fÌðµ÷è¡'|WÏž´' 6¦ôHT€ùÞ~[‹)+KYYZ´Ho¿íkÏÏ×ÇûÿýïÊÏï¤ÝÖŸôñÞ6.pÚqÀ‡%s‘¨s‚ü|-[¦†54hùr îkŸ6M>ªÃ‡åvkÑ"í*T; L°±@¢Ì·e‹ÞyGN§œN½ó޶lñµÏ«+¯Ô¥—*?_W_­Ù³;iw8üSÙº„f½ÊÖç Å9<üµ´ãp8ÔîOùÖÝ8-¨ýؼ-Þ µòN-…³TÙ»Õ§5ÿy“’÷Ò靯û óþ¯H2.—‹€Q$*–ÀõéÉ4Ûé¹°>0 ‰ @2¨¨ðÝ<ÑÝF—á<=ü°²³Õ§.4:CÊ+`.«0R¦*+ÓäÉ&'vÝF—fBÝÿ€¨$ƒ;4y²öÝEñÐ!¥¥É»BºªJƒKRs³.Tß¾ÊÌÔÔ©úî;ÿá+Vè ս»fÍÒ?´íVÒohøpué¢AƒÔº_i¨=ý´ áK.ñç'G_¬={ü©ñÌÍŸ¯ .Pv¶þô§Nº óþ¡Î¥=ïÀ˜øLA¢`9‘–©êêär骫TX¨òrI*+S×®*+“¤·ÞÒĉ’´t©>þX:rD]»jÁ»viÏ8 Ã‡}· ìVÒ´i*-ÕñãÚµK}ä{B~ø¡**äñ¨W/½õ–¯ñÍ7•­ŸþÔÿ´ÒRíÝ«Š UWëСNº óþAÏ@¬±{»'˜%ŠÓG±Â† Ú±CÛ¶é7´q£^zI“&iøpUVêµ×TT¤™3õË_jÐ íØáÛ’þÈ©¯¿–$‡CŸ®K.‘$—K×^«ššsº•4p x@¿þµ ð¿nºÝê×O’V­Ò{ïéÅ%éÖ[uÕUºûnµÞÇðÇ?ÖÎm—j…êö¼ótæŒÒÒ$©¥E]º¨©©í?E¨s ¥5¼†ú±{—ËE¢‚ Q™%>‰êæ›5y²fÌÐ÷ß+?_{÷ªUWëâ‹õÕWÊÏ×þýÊÈÐùçûºõxÔÒ"‡C--’äp¨©Iç'IMMêÖMgΜӭ¤>ÒOèý÷Õ­›V®Ô7Jê¨ÃÖñ××+/OÕÕòxtÉ%:p@YYþ'¤§ëÔ)¥Ÿ{ÏúPÝöî­¯¾R¯^’ÔØ¨AƒT_ï{9/ï]ƒžK:Þ˜ŠD„ƒý¨XN¤ëÓÏœÑξy½nÝ4t¨ž{NÊÊRAž}VÆ)#C’úõÓÁƒjjRs³/¬´:pÀ÷ ºZ99m»•tùåÚ¾]ß|£^Ð]wù;è°Uv¶~ñ mÚ¤M›4q¢²²Îùi¿~ª®n{H¨nCÝÿÑãñ}…:q@¢`o»vièPõíëû¶°PË–iÂIºþz-[¦ÂBßî¼Ssæè‹/ÔÔ¤}û4uª¿“ûîS]êêTR¢ââ ÝÞz«*+uú´ZZÔÜÜy‡fÍÒºuZ¿^³fµýÑôéúÝïTS£†•”tÒm˜÷l.c}:` ’÷nz­_A-òÕ~l¶Q™ª¬L“&ù¿-,T}½Æ—¤ ÔØèOT<¢±c5~¼23uÛmºé&ÿQcÇjÄåå)'G¥¥Aº½áÝt“ºw×#hóæÎ; äƉºöÚ¶?züq ¦‘#uÑEÊËë¤ÛP÷l£ý¹ˆÖQA8ìIβã:*¯ðWS ¢­[uÙe‘.ÝZV¨ÕT¬£Âár¹Ò;zõ—Fyy¹¤!±Ø¥Ûž—x‡ârÅä¥cÔ-€dŬ+Jxu "B¢°>0ŠDÀ¢ŒÜæâŒD(SƨXe*vA¢œƒ2 LlPDDÀÒØF€-¨~¬O¢C¢`u¬O`}$*@”©€ˆ¨Øeªxb}:€Q$*vB™*>XŸDŠDÀØF€•‘¨Œ"Q° Ö§ÇëÓˆ¨Œ"Q°ÊTñD™ _z¢Ñ T°jT€Žð)K אָ xD À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*1äv»%9ÎDb‹D`wJ”©R„·* ¤ jTb‹KlêàwTF @Ìq¡ô¨QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(î” %äææÆç…jkkãóB,…D IÄ-3u¬Óa¹€¤D¢`W‘F(·Û£‘r:?¡Í° X@r Q°ŸPY*>™©c¡}Þòž ¹ °;› ŒSVˆPi3àN Zì‚Ïú°%·Ûm»8Õ^œ/$’7TYdY=€¨‘¨Œ"QE¢0ŠD`‰ À(ö£K°ìÇýØ}5*@G,õK¡F få}>ÙÕ5*£HTF‘¨Œb€DŠzÕ3ë{¢cå5[€­Q£€ât: £@,P£‚p8‰‚9첓gK¢G2ʼn¤¨QE ©MáÄûǽ5«)íÇf—RDmmmnn®£Ø¢ÿ°ÉdzEŽb9NTæ¢F`‰ @‚y{Ù¥¨–4XŸ˜‹D©… V HT¬‚2û"QH<»ìò4¼e*&þ‘¨Œ"Q° ®O·Ô`b„2`€dVqPCæÇ»[ƒQ,>IŽõ逹HT¬"eª² M¾ÌÌcÚ­Y°#€d¶ãSM¾LƒP•[’}«´Ûä®—¤*·? IÍ-Z¸U}ïRæLM}Nßýà?|Åkºð.uŸ©YkôÙ¶ÝJzã5|ºLÓ ­yS:›ÅþhxàÝø'õœ­Œ*|RuÇ|íߟÖôÕê>S9wëeþç>X½SƒJÔeš~¶H{ur`¤XŸ˜ˆD˜ÏuX×/W÷™ê>S×/—ë°¯ÝãÑÃUöõ¹C ·Ê㉲=é™U¦ª;&×a]õŽRù~I*«P×t•}"IoUjâ(IZúßú¸ZKtäyuMׂ¿ú{ØU¥=ËuànÐc¯´íVÒ´çUú_¯]é£jélLñlñ—šþõ)•üRuÏ«îy]š«6ûÚÿ}›ê¿ÓÁg´g¹vU?…{µûq5¬ÓúíÚg$*À|EÏjÌ`Õ>§šUúùźe•¯}Í›ÚýUþA{W¨¼RëË£lObæn£ðú§?\矧‘*¯”¤ŸêÞ_èµ I*߯‘’´¾\Oß®þ}Ô3CËoÑ+ú{xfš.ì­¾½ôÌíÚònÛn%evQí?uä˜üHk|{WèšKÕ­‹zuÓSô·Ï|í/½¯?ߦ z©o/ýùöàÇ®ž­þ}”ÙENÖ'ÿÁ¡LG¢ÌWåÖÂ_)+SÙݵèFß|“¤ïhñõË’3[KþMvEÙŽ0•}¢I—IÒ¸aúðK<­÷?×ÂôÞç:yZ~©q—JRm½F.Túí:ï6åÜퟕ“”wïÁE}uäXÛn%½rŸvîSÁ" ¸Wÿõqða|ð…Æþ^=fÉQ¬î3uô¸¯ýëF :Ûÿ  ~ìzødvQSs†‰5[€YHT€9'ª&ŽÒ“ej<©†“Zñš¯"i_F_ä{\§}5Q¶'7³Ö§ŸiÖν¾y½nô¹€ ŒIDAT]4Ô©çþ¦‚_᪙ ³u×_‚dÊ3šw½jV©e³×ùgo/ì­ƒgû?x4‚S‹ú@±C¢Ì·rºÖ½¥¬9Êž£»´j†¯ýÄ)õÈð=îÙMÇOEÙŽpìªÒP§úöò}[8R˶kÂIº~„–m÷'Ý;¯Óœuú√šµ¯FSŸówrß&ÕSÝ1•lRñ•Aº½u•*kuºI--jnñ5feê‡ý|Z]ÒÕí|<ª;ÖùÛo¹B÷oÖÑãúæ˜qU8¢>0(Ö§¦ Qæœ=™õ‚¦UýZÕ¯Uñ•š±Ú×Þ#C'Φ¢ãß«gF”íIÏ”2UY…&ò[8RõßiüpIš0B'Uxö§üJc¢ñK•9S·ý‡nºÜÔØŸhÄå•(§·J¤Û tÓŸÕ}–yI›ïö5>8I£õÿ/sõЋê1[×-ÑÕÃüÇ>1E½35à^ _ 1ƒ} ³ÂõbÇáIas8j·ÄÄ{ gÝIÆ 5®U×ó%éÔeÍÑ© ’4¦T‹§èÚ|IzsŸ{E»¦=È€ÛÍÛbßûååææÊØ*Ÿ!óµõwºlY#Šm·UnM|RÕOÇïÀ6¼o·ÛݦÝ[»²ï ˆ—ËE 0G`A%?W˶«á¤Njùv ïïkŸv•ݦà r×kÑËš16ÊöÔa¤Låú£ù¹ÇônïýOýó„¾nÐC/êÆÑñ8@Œ¤'z@Ú2Oó6èÉ2Iºb°¶ÌóµÏ½V_Ñ¥IÒÜë4{\”í© ¶¶Ö[¦JnCûiØC:yZ¿ú™~s<#ÌúAœõ‹¿ä›õ“ˆHЉ?fý€p0ëÀºbq›?ˆ@bÀë¢LÀ.HT€sP¦¢@¢`”©âƒÏQ#Q°4>eÀHT?Ö§Ñ!Q°:Ö§°> ÊT@DHTl€2U<±>ˆ÷õB zý¶òEÝÊc€äF €ãƒõé@¤¨QA$êâååå’† ’W·¸ÚÚZsÀ‚¨QE¢`¬O'Ö§!QE¢`'”©â‰2>V¦°%BK¡Fè7«ÂA €Íp`AÔ¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*ÀBÆ'Éår%z €È¨ŒJOôA™ ì…`-Þ‰?€Œ7îÿöÀÀ,VÕIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/complex-deploy-1.png0000644000175000017500000007523610014674771025115 0ustar frankiefrankie‰PNG  IHDRÀ1 FÄsBITÛáOà IDATxœìÝy\”ÕâðgAV•mAEÜ® ”ärÅ Ì+Yþ\Óò–KZ˜ŠéÕÔR22Ë›¶\ËÌʲ²®y³²²p75ÌÐÙÄ…M`æ÷Ç Ã0ûÀÀlÏ÷ã§ÏÌ™÷œ÷¼ïLðpæ¼çI¥R‘nlŒÝ"""""sÂMDDDD¤h"""""=0@隈LÕg"|&2v' ÇÂǰt999-ý.˜Å»l$2mvÆî›´™;qmnÁýØØ£} : Fà t|ÀØkaò1ÂÆàÚ ¾±èú$Ú8¯[&L8cS[xù¦ÖÙ‹¹tƒˆL4‘u«¸ŽCq(>ÙP"©Fé”^À•w­+:Hî£<åy¸¾—^Åнðˆ0vŸ¬†U}ÒˆÈü1@Y1I5ŽCÉpôC¯•ðvbHkP–…¢#ÈøÈØýk-Bz“T¡â: âÒ«¸“Šä±{ m;»sDDdr ‰¬XÆG(ùNý;<ëKÛÀ%.¡~ºaKIRßĵ]¸“.!˜†î aÓ¦náËîÇnáô³ÈÛ {ô\†ÐŨ,ÄéÈÿ¶žƒ¾ëQ£*K‘²9{ ¹ïNj;œõ)®~€[¢¶ŽÑ9a+aïG'ãÚpë…Øsõ»âû>(½€€©´SûÙ°i §t €ÿcøiJÏ!} z¯ÖiïM8 §ôn:¾ …­âr`ïÑPå~)öø¡¶c/Á¥{Sι®Gq§ç#çkØ:"è)ô{¥®…Ï¿wP3r\[‰¯\!­ÁÄÛ°k?ôí³p3P}»Ý jƒ‰¥°uhhPhMó^ªïªî›J÷2‘ò< ~M[tŽCÿ77(øio¡è$÷áÞ}ÖÂ;Zqï ÝÐP¥¡“·Õ~ 4T¯)Çù5ÈÙò\ضC‡èñÃu¯j~ã”Ik¶YŸâN*¤tˆ‹à÷ΤæcÔü!pï/üñ< …Èþ¡ÿ&|åÒpµŽæó@dD¼!‘õ:Â_ñàÇ|\Óf’*ˆÆ£Šå^Ãð÷ý°±ê§úŽEþ¾†  kqëφ’ï!xNÝc•Uý{¶.56š*űéÈúL±.=0ê8ìÝp¿ûz£"QŸ£Ëd¸öŽN†“?bÏ¡«êCS7É5ç~"1ú„N{×÷p´žÒ#‘½}ö¯†W/oÀ™¥ð‹ÃÿªÝ£¦s®óQøGî· DlFÈ‚†Wå©›zñóC¸qÑ¿Ákî—`wG@ ‘ +AWþ†ÃÑé!Œ<\·½Ê­°Í}SVUŒú¡<·¡Dv®dÝVØ—MŒ:píÝPY: TVþT±SÞ8’j$Ç¢àM‡ áLêrŒêªWÝÄ÷}Pq½á%ñ8äý¯aïZGíy 2!\…ƒÈŠ•žŸQZ6»¼7ŽÂÞ}‰wðwõìÝP˜ŒÔM¶¬*¸4ü_z<'ž€M<œŠIåu%}¨ØøTŒþ“«0úÚ¢<—’TôáêÈú í1d&–bò}Œ9NQ¸“Š‹‰`ï¶Àù5ÖB*Áù— ²ÁƒŸ¨MÏx€»éºî]ßÃÑzJ{.€ô·!©®«"­Eúè™Ð¨)ÝϹîGQQ€qWðey2vÔ•ËBÌTiÝ?µ'p€º¹õE‡)œ •àÆ‘†raeš÷¢®oÊ.¿†ò\´jxGî\RÜÆÿÿ0æL®B\ºL†¤—7j醆*2>ª y4b3&ÞÆäJŒ:¿8@Ÿ7N&íß(øm\¹ ÞÄ䪆Öt9“º£ºê—’PqÎÁõgàwÜn|ÚµŽºó@dJ ‰¬ØýÛ´Oó½¶ ¾ÿÿCgصG—)ˆx®5Fø8‡ÀÎaË ú.þ.ÝaÛ®®ä¶R‚ð: „=:DbÀ;û?}øëˆú~ãÑÆ6màލ/ ç¿uÛøŒA·y¸“†ÌOqmî\FèRµ)M3{÷ºþë¾w½Gë)õèŸQ¨ÈǵÏëªä|ƒ²ltŠBÇAšÒýœë~߃s0ìÑk%ܹ¬ó‰«×i0 Рï:@Ó@ñ) þ¯}é޷ܽ€ªwDÞC_À£?lìáè‡ïÀM¥¯šPEÃÇ@Cõ¶ ð7¤mBáAtX÷UƒîoœLÖ§0ð=ÍBÛ°±GÇëZ“Ñp&u9FuÕ…Áæ†30Pñ´k=uçÈ”p4‘³wEU1ªŠáà¥i³»WÀ7¶Q¡0™òNz£B·>uÚvR]RsO±qùÕi”eªèÃí ° Š—ʳÿíu\ÿ ^†M¸÷EŸ—Ul¯‹ªhã¢ßÞ¡óáèrJ{.ÇõŸú&g¨™m<ü }ιîGáÖ»î03¾¦LEÍ:EAd[  “ÑÎS‘²… ø$D¶è¥w³zõí^& ê‘‘Ö"õMdíÄÝtÔ”×VhÚ»ŽUÔ} 4WxÇg çä|ÎÁ²®az¼q2wÒ@÷¿á^&~ÇÕ­(»I5j+p'}€Ÿê¿aµ85Ù_¢¦ 5÷písœž )¿žœžâ“T£øwœš~ª¾wy’Ç"óc”ç@ZIî¦ãêVüô`Ý6×>Gî·pë€i豎b\û¼î[`]Hî£ì2?Æ(=Ot›¯ÇÞõ:O©ß?àÚùß#û+8xkY,E+ÝBƒ¶P˜ h[AˆÈ™Ÿ"xï€¨î¢ÆN´î{Ñ@­W~Gdj+ÀÖ¶¸—‰“³µwCkºæê¿Å àçºÏCÝœi IoœðQ9õ 2¶ã~ $÷qóév)žŽÇ¨Ž°ÞÜ©gPr’j”œÆ©gm õpÔ"SÂhÐ+ë²1$ó`c¡ÿáñ(ùCÓ—¤¡‹¿7ŽâȤFå^ÃÐ=¾¹}pÁþȆ§Ž~èù‚ŠÍº>‰’3Hߌã3U·SY„ÓÏ@ßW ²#ú$âÄ85žCê.KRGyÁ2' þºáòJ­{×÷pt=¥"ô\†ã3 ­A÷ç`ÓVËÞ5Óý(4ðú;²wãÀ𺧚â ’ûpï[7ÉÞÁn½Qz<R[Q¯½hºYŸáîÕ†wÄw,îe4là3¹{b¥òJÃÊÝÐZE îc ¹úõqýÇF%þMzãBžEþ÷(8€³t­"£ã1ªÓó…ºùÓ?¨+ñ‹»W ªÏZGÝy 2%VúWæAe©Fú¶ßÝ'2G1FÇÂg¿8Ø{@d‡öè¹ ‘Ô½¤ïgÓÃ~Àß6À½/l`ç¯aºW§ó¦ã1ªÓ¶#F†x\Ãiø7P¿².‡£á<™ k¹‘Šæ kؓКû"2cênbb¦Zèp®}Ž£SÑý9„ÿÛÀ-µŽŒí81 žC1"ÙØ]!2‹ÖkŒÙ°»ÖÜ8‡¥‰HWÕ·‘½‚ž2vWˆtvèÜ<Iªo#k'Rœ†A–ÆÒæ@«Ë¦F÷•ßµ¬{"‘µŒýQÉffûÆ4¬¹Kdúr÷ wO£÷¿!XÏ‹‰L›…Œ@«in¹1æ&“ï ‡¢‰H ‘¼þÎ  df†}ŸÑhã {´BèŒø­¹—À™³U9=Ã(=Ñ—|ÏÍ¥ÏDDDDdÆZy¼ÙX=i2 8""""kc®Ú’†o£‰ˆˆˆÌˆYhYâ4ÇΫÃMDDDdÌø"B ‹˜ ;òúB""""Ód~#ÐB²4»nëÅ"‡Ø‰ˆˆˆ,ƒ™@[ɸ¬üRwÆí )0³hk~–á845Káo¸”„ⓨ¾ G1¼þŽ §Ð)ªa£ßMýN*r÷ gŠOÒ¦ôäèd\û° {‘90§;ZUz •J[yº »³ž·ƒÈÌäüGƒTR÷´ì2>BÆG¦4¿ mVõk»óºBD¤³™ÂÁÉ !ÒÈà dDÔç^„Tñ8<| SªñhúžCÝ­Æ\{¢÷jŒ½Ð”ºù85a+ Ý'""íÌf ‡µ ? D"½ß f†ÔVÛµ½•D­m—=$Õx¬öª7øLé^ÙàtÖ§¸úný‰Ú 8vFç8„­„½[£ŠK‘²9{ ¹ïNPSŽók³å¹°m‡Ñ=⇵ô¶ “I~‹Ae!ÆœÄçmô®KDÔ<æ4…ÃÚÙT9C·rD6`kò=·¤[ᙢvb”e!ýmt{m;è\MŠcÓ‘õYCÁ½¿py#òöaÔñ† àè4äï«{œ»%§{öø}Vݤd’jü‚‚_ Ÿn¯¼‡Â_1æDü-FDF`6S8¬BÖÔk„T£–쵓/ç"Ãë½ Î­Â×°7G&!ócHª6…Ú©Òº®~€¬ÏÐ>Cö`b)&ßǘÓè…;©¸˜Ø¨ý;©ý;&Waô ´Dy..%@î·±ocr%Fƒ_œíÞ_8³½^„[·LD¤óÐÖ9C“Ⱥc’&jY]ŸDô¯ƒîý…ì/q|&~ Ge¡¦Z}Q_Ào<ڸ¦ <Âõäü·Ñ–ÞA‡°±G‡H xrÿm;@áoHۄƒè0CWl&©ÇgÂ¥–²Y""}ðË/e.9¸ùT.zÝ„ÉßD¤Èëïðú;¤µ¸“†Gpé5”žGÊb úTm•Û`ÿ@/•g7zê9¸áq§!P– oãø ä|S·>†s0†ìkXSú¯0K[#¿¼ŧ0æNÞ "#â 2 IššÈ0D¶pí מðŽÆÞ`äÿ ic ÿÓÉOÿÐÀïx$×Â#Èþ w¯âäŒ<¢_Ÿ58· ’ûø¾·b¹Ñ×´&"kbšó7¬ll¾õD†ÔÆ jîʉ) êÇz]ÃPrc/h3.: ŸQuo§Àº§víÑy:O@Ï¥øÆÅ'›Øa•iXr¿‰­ŽyÌ&k#?=šS¢‰šb$®¼ƒ;©TAr%)86\º7lÓÖ “ú¨ò $EæÇ(Ï´’*ÜMÇÕ­øéÁFퟞâ“T£øwœš~ãà·üŒš2ÔÜ«›mØ_4²Kå¯}”•µ 3&«Õú÷b$²Å'U ýŠlÑgmÃS¯¿#{7 ¯{:UŠ®O¢ä Ò7ãøL-í;‡`dÃSG?ô|®ÿˆë?6ÚÒÿQµ(Ìr–=e&"Óf„hÞ»Žt'ŒCóc@¤·1 ÇópëÛv°iG1üÃÈC• ÿ7:? {†)"ÞÂðŸáÿŰiÛvpí‰ns1êx£ö£>CÐ,Ø»ÃÎ ~ã1âPÝ[¢À/öÙ¡} z.Cä­rÀDD­§•®Ó2©{y‘}xø1 2 ¼\ˆ¬^ NáК™„Hwò×ò“CDDDFgà­.43÷Psp24™Žæh3‘Uiúwâ*£3C3µ® MDDD&BïhåÜÌLCDDDDÖC×hæf2:B‘)ÐiZ>=3¾‘5Ó~#ùUx™žÍ®]»¼¼¼„7Nþ15Ÿ¦)6ðÜÊ«dwMkÄßß×®]ƒ Rxlîë(s ™µ‰ÊònÿfŽñ±i}¶±±©­­ÞAùÇæÎßA"""²<ª§pX^z–'‰Þ{ï½€€{{ûþýûŸ;wN(¯®®^¼xq§NÜÝÝßxã ¡°²²òé§Ÿvuuuuu={vee¥¬‘õë×{xxx{{ïÙ³gýúõ:tðööþé§ŸdhÞ]EEÅÌ™3œœ¼½½7lØ œqe·ß“ojÓ¦Mþþþvvv233ãââœbbbŠŠŠPŸ2mll„вÇò]Ry¤fÁ2þ """³¦"@[vz8pàÈ‘#¥¥¥qqqO=õ”P¸fÍš .¤¤¤ddddgg …+V¬ÈÏÏ¿råJzzzVVÖÊ•+eæää$&&NŸ>½°°0;;;11qñâÅ:îîÅ_¼uëVVVÖ¹sç:¤\K8ÿ SÏOž<™’’RSS`ܸqñññEEEEEE={ö\´h‘B-•-¨;R""""Ò…ŠïÄ-u¦©l€H$ºyóf‡”——»ººVWWèܹóBBBäk‰ÅâääänݺHKK>|x^^žÐHqq±‡‡GUU•ƒƒƒì±“““nµîÎÏÏïàÁƒAAA®^½Ú­[7•ï…|¡H$ÊÏÏ÷ññQ>ºòòò€€ùAhådU©é³ÔO&™ÅmÁE>Ñ*¤Rá©]ee¥0;BÆÎήªªÊÖÖ@MMM»ví„ø«5¤ê²;ù–Û´i£K€–zâĉ¥K—¦¤¤”•• ¯J$]ú¦òHMŸ8‰ˆˆÈŒ4šÂaåL}||222 ½¼¼233…Ç^^^†Ú——WVV–ðXö@/'Nœ?~nn®D"¹}û¶îÉRå‘‘.T̶Ú¾™3g>ûì³¹¹¹¥¥¥ñññBá”)S-ZtãÆ¢¢¢øøø)S¦jw“'O~þùçoÞ¼yãÆ aú²277·´´4u-TTTØÛÛ·k×.++köìÙºïZ呚8+ÿ뎈ˆˆL‡ö©XÕ«W‡††öíÛ·k×®Báºuë¼¼¼‚ƒƒ»uëæçç·víZCíníÚµ®®®þþþ½zõ4hP›6m”·Y²dIDD„ºì¸}ûö„„„öíÛGGG:T÷]«(Ý{ï½`ooß¿ÿsçÎi¨«|*䥦¦._¾ÜÍÍÍÝÝ}ÅŠ©©©BùŽ;Ö­[çãããë뛘˜øÑGévâ›…¹™ˆˆˆÌ‹¦)f—¡…˧±+Väçç_¹r%===++kåʕʵ^yå•Ó§O§¤¤¶mÛö…^””_SSS]]½dÉ’7ß|À¸qãâãã‹ŠŠŠŠŠzöì¹hÑ"Y#………999‰‰‰Ó§O/,,ÌÎÎNLL\¼x±lƒC‡;w.33óúõë«V­Ò¥Ê8päÈ‘ÒÒÒ¸¸¸§žzJC]åS!ÿ&ÆÆÆ¾öÚk·oß.--MJJЉ‰Ê/^¼!<¿xñ¢.§]%©Îš¼ """"£Ð~›y­Å«pYžX,NNNîÖ­€´´´áÇçåå)T Ø·o_XX€Â¾}û˜>}zDD„D")((xíµ×j•——ƒÐ"‘¨¸¸ØÃ㪪ÊÁÁAöØÉÉ©¦¦FØàÊ•+ÁÁÁÒÓÓ‡ž››+ß[u}P8´›7ovèÐAØ»««kuuµ†º §Bþi^^Þ Aƒ²³³=zÔÇÇ€­­muuµ ‰Dboo/ô_ß·@öØ,>3DDDDzÑi3ŠD ©ÑÎήªªÊÖÖ@MMM»ví„Ð)¯M›6²ñZ‰D"‰$ €Ý»w¯^½º¬¬ìÇìÑ£€'N,]º4%%E6MBØR~§*‹D¢ššånÈ6P× ‡¦µ®†%>F)Œ oܸñäÉ“û÷ïàêêš““ãââàöíÛ·nÝÒï ëžì±‰fL™l™¦aÆ» dš¦pÈ(Ì0—¼¼¼233…Ç^^^ÊÛøøødeeÕÔÔÔÖÖ T(ß´iÓ¢E‹–,Y"~ž8qâüùósss%ÉíÛ·õÊ…òÝðööÖ±ºhB݃®X±ÂÍÍÍÍÍmÅŠÊÃÂÂNŸ>-<þã?„Qí¦Q7{„t‘\ÏØ!""-øãÚ:éq#Ù`*Lx^‡››[ZZZ÷îÝ…§S¦LY´hѶmÛ¤Ri||ü”)S”«Ì;÷é§ŸÞ¼ys@@@ZZZbbâgŸ}vàÀâââ'žx@DDÄùóç{÷î]QQaooß®]»¬¬¬åË—ëÕ±… ~øá‡âãã§M›¦K ÛBÑêê*œ ù¦ÂÂÂÖ¯_¿páB›6mêÕ«—P>cÆŒ•+W~ýõ×R©tÅŠÿüç?õ:FeR©TþcjŸÓ$ÿƒ8$$Äx!""í„¥`“““9mUt–§T®G¦/Žj/Y²$""BÖÚºuë¼¼¼‚ƒƒ»uëæçç·víZå*Ë–-2dȈ#§OŸ>aÂ/¿üòºuëlmmmmmß|óÍ„„Û·oOHHhß¾}ttôСCõêØ!Cz÷îèíí½fÍ]ú #uuN…¼;w>|Ø×××××÷ðáÃ;wîÊç̙ճgϰ°°¡C‡6?@Ü¿¾0®¦g""Ó'ûqÍqh«Ò¬;áiCº_›¨oEs¤Ë@²50Ù/.LŠð#˜é™ˆÈŒãЄ¶zLáP¦a’«¾²ïúÉ‚qF‡VLÏDDD¦¯YZF9 é’†•k1QY<…™ô|ljˆˆÈìè=ZGM»ƒ†¥B3&*à¬h"³ ‹Ý""SÔRšH3®sGÔÄõBBB¦M›–‘‘a”>hxÚ4³gÏ Œ‹‹ûù矛ß&Q“™J€f„²N›'2¸¼¼¼¼¼¼'NôéÓgþüùÆî”ïÿÚsçÎ :vìXZZZBBÂŽ;šß&Q“™J€0NY!ùYÑDd( .¼té’ðT,¿ÿþû ð÷÷PUU•УG=z,]º´ªªJØìþýûÏ?ÿ|ppp¿~ýÞ}÷]Ykê•kjj^zé¥Þ½{‡††nݺUö’0 ®°±ºŠÅâO>ù$22²K—.£G¾|ù²òáœ9s&>>ÞÝÝÝÞÞ>**êÓO?Êkkkׯ_ß§OŸ   ùóç———+¯X,4hì—‹T*4hÐåË—µVN‘J¦ ‰ˆÈ JJJ6mÚÔ³gOYÉŸþ¹ÿþììl¯¾újAAÁ‘#ÒÚN IDATG>œ“““””$lóÚk¯ÿþûï?ÿüóÑ£GµîeãÆiiiû÷ï?qâ„0Ò,û¯òÀ³º8|øðž={RSSÇŒ³dÉåõéÓçõ×_:/oóæÍgϞݿÿÙ³gíííŽ7//ÏÙÙùرcBáÑ£G]]]CCCµVTÞ‘Œ©,ƒÀuͬ?.cGÍ$îuttŒˆˆX»vmpp°P~æÌOOOáÕþýûýõ×þú믉'¦¤¤ÿúë¯ddd ËžFDD|ùå—]»vUèƒÊÕíT,_¸pÁÝÝ@EEE=®]»¦p\6løõ×_+++£££_|ñE///‘‘‘ü±pËÕ7nŒ9òÏ?ÿT8ÞíÛ·Ÿ>}úí·ßðÌ3ÏDFFΜ9S—ŠDºã:ÐÖÆ0ËØ‘‰P7çX>Þ¼yS6E¡K—.ÅÅÅÂã7ntîÜYx¬Ë†¢¢"ݧ:¨Û)!=h×®]MMr]ooï7 {ܲeËœ9söìÙ   `äÈ‘¤R©D"‘Ÿ &;Þ &$%%•––J¥Òß~ûíÕW_Õ±"‘:¦ …[lpa`"¢VбcÇœœa¤9;;»cÇŽB¹§§§|¹l{;;»ÊÊJ·nÝ’•{zzfgg+Œ@ë»S½xzz.[¶,44TötïÞ½>>>ª¸ºº6l÷îÝR©4::ÚÅÅEÇŠDDêp4™ þíDÔjâââÖ¬YS\\|óæÍU«VÅÅÅ å<òȪU«då²í{öìùî»ïVTT¼ð ²ò‰'®\¹òúõëwîÜ‘mïââò×_é¾S]̘1ãøñãUUU%%%[¶léÕ«—Pþøã'$$deeÕÔÔ¤¥¥©[udòäÉŸþù®]»&Ož¬WE""• ÉøäïïMD­à…^èÔ©STTÔC=äãã³téR¡|É’%:t8p`tttTT”lû 6üøã=zô7nÜ Aƒdå‹/îÖ­Ûˆ#xàÙÜyóæÅÄÄ(/ÿ¬n§º˜9sæ† zôè1hР‹/¾óÎ;Bù‚ "##'Mšôì³ÏÆÆÆª¬>dÈ;w•ÉJÇŠDD*™Ö” ^IfµøÖ x!‘9âE„ÖÆTæ@“.”Çh-#qr왈ˆˆÌˆ)Ná`œÒ¨ž±;Òtò7ë!"""+aZZ6žÊ ¥™T*U{É1V¯š@Ö[Ù™Wÿ‰ˆˆÈ ™V€3´F ¡Y*G¾Ü,’´|åï² ¾õDDDdÚLq´°&4. ­;ù%  òIԤΤrtVÞÀ¤:LDDD$cr#ÐŽCk 5Yj–6î)U9ð,o=™8SÈCÃÄPK÷ÑY•ÃÒPʦ­snuß)¿‚ """SfºrA ŒÑͦad·¥WÇkN^g†&"""ScÒJ±Ïšc´¡¦4(Ÿ½ŠÔÍiDáo'ë|ljˆˆÈ4™z€–‘_ŸAë%h–¤nž¢<[Z—n4¹}Ýk1C‘ 2›-PXæÌ(sy[±ŽN—!ê&7¥oufh"""25f êV ¶˜;w†ÒáéÎ;|ðÁ€€€èèèŸ~ú)))©ÿþ]ºt‰½xñ¢ü¿ýö[¡J``ààÁƒ_{íµû÷ï«Û]ll¬X,Þ»w¯¬ú÷ß/‹GŒѲ煈ˆL4™7 CÈò‰Y]zfª6)»víúâ‹/N:%‹Ÿ{î¹È¿úÉ'Ÿ<þøãgÏžÍÉÉQ×±cÇ~úé§·ß~;55õÉ'Ÿ¼víÚÁƒßyç³gÏ.\¸P~Ë´´´O>ùäÊ•+/^œ1cÆ¿ÿýï—_~YÝîfΜ àË/¿”½úßÿþÀ£>j'""ó¯°ÉhÈÁê¦y(lcè5Qrr2€cw¤¥¨»•·0–üý÷ß÷íÛÀÙ³gccc(äTáÕôèÑC¡Šl"‡ðôرc]ºt©¬¬ pôèÑ€€‰Dâïïocc“­²W‰¤sçÎ;v<{ö¬ÊÝUVV†‡‡ß½{÷Ô©S^^^wîÜéÛ·oMMÍ©S§¼½½ vv,ïÜNÖ#==À°aÃŒÝj%& Ç1f3*ÿàüùóò¯êòw…0»ÃÁÁAxêïïÀÆÆF*•ÖÖÖÊ6+,,|þùç#""ºté"‹…ZÅÅÅêvçàà0iÒ¤ÚÚZabÉwß}wÿþý|陈È:1@“%hæ2C¶Y°±ÑþóJauUæÎûå—_N:õüùóyyyÂȴ§H¡îÌ™3E"ÑW_}à›o¾çoY1h²ÌÐàÒ¥Kƒ˗/èÝ»w íèÌ™3æÏŸïââàÏ?ÿÔZ¥K—.Æ KOOÿþûïOœ8áààÛBÝ#""ÇM–ƒÚÜ­[·®¨¨èæÍ›‰‰‰,XÐB;êׯ€;vTVV^¾|yñâźÔ.%\²d‰T*9r¤³³s uˆˆL4™ŠI“&=öØcááá¹¹¹o½õVttt íè½÷Þ‹‰‰yýõ×CCCããããããu©íççwûömpþ‘uã*diš9lÜÿ#¬|Ó¿7Ê[o½•””äááqæÌ;;ÞˆJ ®ÂAÖƒ«pXŽ@“¥áDj!÷îÝKII°xñb¦g""kÆßdtYû™H/“&M:r䈇‡Ç+¯¼"L†&""«ÅMVJCȉ8µ©µ™þä/¾øÂØ] k'ïú¦1ýÿшÌ4Y&̓ÐB>f†&"SÖüĬµAFj¢¦a€&‹¥.Ë'cNö "Ó¡=17óïz¥Ÿv {dž&Ò4YåqeušƒÐDÔ:4åfÃþRhM}žf’&ÒŒš,™|8Ö†™¡‰¨õ©ÎÍ­ù#G}žf’&ÒŒš,œ޵æ`fh"jÆÍÈw£þÇ¡|‡¦‰d Éò阀9šˆZŽŠèl"¹Y%Yß”†¥£‰ÀM$Oe†æ 45‡bt6¯'JIš1š ÐD ˜¡‰ÈPÌ;:+:ÏM€šˆˆÈ°,*7+h< Ík Éj1@)â 45%Gg&ëfcì™"•Y™—‘Ò³Ô¢Ó³Œ•&‘h"Õ˜¡‰¨éD*nSb¬ä0‰”0@©Å9D¤7…Õ”-5_Zð¡é€šHå ÍAh"ÒBÚxnƒÈ‚â¦Â±H9‹ƒ¬/"$ÒBùšBÍšTÂæ5=2ªïgbø~YšÆWÚÕ=0Ó¸©ðƒÍL‚È@ ‰´ãM Í‘Y$fÊ}f¤¶æ£‰”0@éD!Ck_ÕNáö]­ó+G~_ÖøU¦çüüüÖï‰^|}}JÄb13´…P£aÂyTùgˆÉv•¨Õ1@éJï MF"KϦŸ˜(tXÈÓÌÐEéÎØ¦8 Í!g"mx!‘3çu˜ óMÏÊ,àH-©ªõ:ŒûE¹¼@H Ž@é‡ó¡Í£'™uÒZ·ot14iÃh"½ÉC3LS‹þ0Ç "I?:ŽõŠš÷ÏPÝ ²z&j ùqhN†&"ÃÐüƒÄ ­óg‘!0@5çrQ«bö%2œÂAÔt²g&i"""ëÁMÔ,ÌÐDDDÖ†š¨¹˜¡‰ˆˆ¬ ç@çCSK3Ù…8x“"²B&2 aºY1:8NÀ( ]Ö4°p<€å¼ˆL‹É&{"¢–Ãh"ƒiî8ô$`<ð% Þ&)€­Àà ¶OéÔÞêÕ«·nÝÚôþ´€5kÖ» æÇ”o #Ül\3Sû¶œÕ«W¿ôÒKÆîµŽ@R³„N–n€;°H­/߬|_ øÈý$""¢&c€&2*ùëXà5à6P $1õåˆúÇáÀÅVí )à"“ñ0XŽÖ—ßÚ×?vî¡kDDD$ÃMdTò3>f3E€ÀÀ~@{àภ8ëÚöK/½dî+$4ù5]ææ’²–˜o={ölƒ·išx=%‘õà"“qX¸nÀ à`}ypºþñ@˜qzGÖÀ××—{˜·¦]ÆÌ¥~ˆôÄMdTò¿í€õ@)P ¼ ôª/Ÿ¬®ùÀ à‰Ö辰Iù¯µþ‘¹kÚ›([êç l3lŸˆ,4‘ÉØ |_à0°³¾|ô€¡À?ÙG"2°€^€=ÈVü«–ž€#0(«/›@ËÅe)œ“û›¼X tÜ7´5Ë¥~ˆôÄMdTòÃE=€@9Pº×—‹€ À-àðjS¿¢5Ous¸­éL py+›¬î‡€Sõ…¯§ h ¼ ·ýI .Àoõ…¿î@¹ÍÖ€ ÈÖÖ,—ú!Ò4‘ñ8y@!à¼__¸ ØøÎÀ«Àn¹í7³€ê ?f5nöc`3Ðp6ik–Ký鉚ˆL¡‚ƒÐ­g7pü=õ…y@_À°¼"¹í}êL¾J€bàG`jãf¯]•ö¥®Ya©>KýY-h""’ÃK [Ù`/pø0¯¾ÐÈj€Z@ HTUtFŸŸ±€[ãW}€ ¥*êšåR?Dzb€&"3ÁAh²HS€KÀ}@ÔÖΞ®5ÀE¥ÑeaÇ6¥ùfϹ@)¯­Y.õC¤'h"2uæ~;óÃK [Óx`à,>­/\ FŽÀt`‚šº#ÛÀ=`¸ÒK«P /ÐÔÖ,—ú!ÒïDHDDd<“ÉJ…6Àr`¹R¹Ti³l5´6É]>¨¹Ya©Ÿ zôšÈÊqšˆÌ€1/%´â©#„&"R‰šˆ¬@ b>ÍšÂݘy)!‘z ÐDdš5ýð°A{Ó¢ÍònÌDD¦š¨eˆêÿ)Éfñ?QK`€&"seŽ¿¼•ûÌHMwæÌ™]»v988ˆŠŠŠŠŠBýgOø¯ð©«­­}íµ×>ÿüó²²²1cÆlذÁÑÑQØæ_ÿú×Ö­[ËÊÊþñ¼úê«öööÆ<"ÓÃMDfIezÎÏÏoýžèÅ××W¡D,3C“aõéÓçõ×_Ÿ1c†¿¿¿¬0//Oáöyóæ³gÏîß¿ßÙÙùÅ_LLLLLL^:qâÄ/¿ü"‰.\¸aÆ+Vè¸k~žÉJp4™YzÎo̸½Ò…Ê›ãP:™²÷ßÿÖ­[ãÇ ]°`Aaa¡ÊÍ>ÿüó—^zÉÇǧ}ûöÿú׿öíÛ'{iíÚµ:uêØ±ãË/¿üÍ7ß´VljÌG ‰ÈÌȧgãö¤ùòóó•Ǥ‰šÉÛÛ{ãÆŠŠŠ¶lÙ2gΜ={ö(oVPP Ì–J¥‰D$É^êܹ³ðÀßßÿæÍ›ºïšÃÏd% ‰TÿEbÖ,ø—™¤g¢–æéé¹lÙ²ÐÐPu¯îÝ»×ÇÇGù¥œœœ€€ÙÙÙ:ujÑN™#Ná "2&á/Îâ š1cÆñãÇ«ªªJJJ¶lÙÒ«W/¡ÜÅÅ寿þ’möøã'$$deeÕÔÔ¤¥¥ÍŸ?_öÒªU«nÞ¼yóæÍU«VM˜0A÷]ó“LV‚#ÐDjI¥ž £Ò …&B¹o–2†NDz›9sæ† Μ9Ó¶mÛÈÈÈwÞyG(Ÿ7o^LLLYY™ðÝÔ‚ Þ~ûíI“&tïÞ=>>^ÖÂ<]VV6nܸŋ+ïB”å—õ ²"©iÆ"£¦pX@€¶ÈßjÂ/lKšÂ!Lƒ¶È7‹Zo²@þ0ƒ}~¸’F¤§§6l˜±;B­„S8ˆˆˆˆˆôÀMDDDD¤h"""jÀùDZñ"B""“`²Ë0N)à4ib²ÉžˆÈX8MDdd¦¼¢o”hñ¾ýö[aÕçf~ÕÀµ;Ô‰¸â™â4‘E× ™4i’°Âš:ëÖ­Û¶m[ëdß‚‚‚Ù³g‡††ÆÅÅýüóϲ7§Yƒ|I"œ±.]ºôïßîܹ/^lý’™b€&""²4yyyyyyüñÇ Aƒ,X aËëׯ‡‡‡·N¯æÎtìØ±´´´„„„;v¤YC¥ÿ¼¼¼ÌÌÌ~øaàÀ'NAAAóçÏ/// ‹¥R©ŸŸŸ0˜*‹ßÿýøûû««à×_>|x—.]"##?ýôSÙî>ùä“ÈÈÈ.]ºŒ=úòåËÊý9sæL||¼»»»½½}TT”PW¶kÙ€nvvö¬Y³BBB§OŸ~óæM¡¼²²2>>>88¸_¿~ï¾û®ÂÝ…*û ®¢2//¯Y³f%$$lÚ´IC”»}ýúõ¸¸8ggg‡˜˜˜¢¢"Y³III^^^NNN³fͪªª 333UnÿÃ?ôêÕËÞÞ> `ëÖ­BammíòåË===§NZVV¦þm§ÖÀy9D*4óN„ééX°G@T¶lAHH]Ý^ÀûïC$œ9x商6U–ËnÇ­u§æ{'B~ÚÊôoÍ»$š>å;ʦ#ß½{wÛ¶m?ÿüó¾}û6mÚtâĉ7ß|ÓÙÙùÅ_tttLLLDã¹Ëb±8..níÚµÔUéÝ»÷«¯¾:räÈ7nlÚ´iÆ BݱcǾôÒKnnnï½÷Þ/¿ü²oß>…®Ž7.22rÆŒB@Wî°`øðáëÖ­ëß¿uuõo¼qóæÍÍ›7xùå—3226nÜ(•J/^üË/¿µdÕÕõA]E }(**ŠŽŽ>þ¼†þÈWIOOòÉ'?üðÃx ººú¥—^*,,þB‰D±±±~ø¡H$š9sfŸ>}’’’ôêÕkóæÍÊÛwêÔéÝwß7n\aaáÚµkßÿ}k×®=tèÐöíÛ]]]Ÿ{î9''§-[¶èýY!Ãa€&R¡™úoÃøñX¸R)Þxûö!%þóìØ¯¿†TŠGÅ?ÿ‰§žÒT.Û/4–î1šÚô© вÇ^^^ß~ûmçÎ###?þøãîÝ»¸qãÆÈ‘#ÿüóO(è3gÎxzz OÕU8pàìÙ³cbbäw$‹/\¸àîî ¢¢¢G×®]SèjAAÁ† ~ýõ×ÊÊÊèèè_|ÑËË /@¬¨¨ˆŒŒfS„‡‡óÍ7]ºt••¥ UöA]Ey }¨©© R>ùþ(hÈÝÊ»¼¼< @T‰DW®\ 6>|xnn®B³òÛwéÒeÑ¢E<òˆüŸûöí PXXØ·oß‚‚•gŒZ§p^j*–/‡›ÜݱbRSëÊwìÀºuðñ¯/ñÑGZÊ­‡TÊ­ô¬D^^^nnîÑ£GRSSŒ9Òßß¿sçÎýúõ“Í‹P KϪlݺõÈ‘#cÆŒ0`À?þ(Û^H®ÚµkWSS£Ü¸··÷ÆÏœ9sðàA9sæ¨ìCJJÊ„ ºuë&‹ƒƒƒKJJ„ò7nøùù e¨ìƒ.”””¸ººjî‚K—. 2¤}ûö"‘ÈÉÉIþ  ºvíZXX(<>qâ„ÊíwïÞ}àÀððpÿ={ö…yyy}ûöµ³³³µµõöö–ŸBFÁMd²ébcñÚk¸}¥¥HJBLL]ùÅ‹ˆˆ¨{ÙEÞêʉˆšL$lÞ¼yéÒ¥eeežžž¿ÿþ{vvvNNޝµ¶ ®J¿~ý>úè£óçÏ'%%-_¾¼ }óôô\d d¶ IDAT¶lÙ™3gT¾:{öì'žxâ?þÈÍÍMMM•}UÞ±cGYté¿L*îÛ·oàÀšû£`Íš5óçÏÏÍÍ•H$·oß–ß,33Sx‘‘áíí-<ž8q¢Êí °wïÞ7nüç?ÿ™7ožPèãã“••USSS[[+•J%‰î‡O-šÈðÞz |P7½cdÕîÝCûöuq÷®–rk |*ÿçµ(áw4Ww¶b±8""â¿ÿýïã?ž „°´´´ùóçk­«®Ê3Ï<“žž^]]-•JkkkuïÌŒ3Ž?^UUURR²eË–^½z å...ýõ—l³ÊÊÊ6mÚ888äää,]ºTV>~üøÕ«W—””¯Y³F÷ýê^Q"‘mß¾}ãÆ .ÔÜ…nWUUÙÛÛ·k×.++köìÙòÍ.\¸°¨¨¨¨¨(>>~Ú´iBaEE…Êí§L™réÒ¥û÷ïK$Ùé;wîÓO?}õêÕššš‹/N:U÷ç–ÀMdòC³faæLܺ…[·0mžx¢®¼}{Ü»W÷øî]8;k)'"j¾iÓ¦íܹsÁ‚‘‘‘“&M zöÙgcccµVTWeôèÑO=õTppð+¯¼"\N§£™3gnذ¡Gƒ ºxñâ;ï¼#”Ï›7O~Fõ›o¾¹víÚnݺMš4éÁ”U_ºt©‹‹Ë€†ag§ëÍàt¬(‹Fýûï¿õÕW²|¯®? Ý~á…Ú·o=tèPù–‡ Ò»wïÀÀ@oooY‚ß¾}»ÊíÇ?aÂ''§eË–É9Y¶lÙ!CFŒáèè8}úô &èxìÔBx!‘ ͼˆÐÁ·o£m[¨¬„›*+`Ð ¬[‡áÃà×_±jŽÑT.Û¯ÖšïE„á7µÙx¿.—ò"BÓ§|¡5¸zõêã?~üøñV«¨™ÂE„dñ8Mdò“°~=JKQZŠW_Eý(fÌÀÊ•¸~ùùX±¢adZ]9QKà*d¾^|ñÅÒÒÒ¢¢¢µk׎=º*©ÄMdx;wâðaøúÂׇcçκò9s…ž=†¡CñÏj)‰„¶†YÂÖpŒDÔAAAC‡}衇œZ¡"‘JœÂA¤B3§p´>sŸÂÎâhuÂ'Dë,Ná0}Ö9…ÃÔp ‡µá4‘ ‰È$q=;Kš:¢ï±p=;"¢&`€&"K’‚³i¶i‘]*ÅÒ¥pw‡‡–/oîtΖ!"j2h"2Í„þî;<ü°ûÓrÍ6-¼nÝŠ#Gpé.\@r2¶m3t·ˆˆH7 ÐDd öíÃã[7¤¦@v6ll \ —šŠnÝ ¶Ë—ÃÓŽŽ˜:ee Õ“’àå''Ìš…ª*Åfüðzõ‚½=°ukݫꉰiüý!!8¸!.K¥ ¹s $TWcñbtêww¼ñ†–fwìÀºuðñ¯/ñÑGªO…ºcQÆ»5 4™}¡‹ŠžŽÁƒƒädøî;´m‹ï¾€ß~ƒpµW^ÁéÓHIAa!Ú¶Å /4´pèÎCf&®_ǪUŠÍ˜1kÖàî]:„S§ê6ÐÐàÉ“HIT üö[]᯿ÂÝ}ú4l¶f .\@J 22­¥Ù‹Q÷8</ª>*…ˆˆ ˆËØ©Àe쌨 ëÙ}ôöíÃW_ᇰcvíÂØ±èÕ —.áÿäIxòIŒƒ€ìÛ‡°0(,Dß¾((‘W® 8ÒÓ1|8rs5  K,Z„G¿Ã~54˜ŸزÇŽá³Ï`Ê Œgži¸»dçÎ8p@qšµºfmmQ] H`ošÅS¡îXÔÑzWB.cgú¸Œ)à2vÖ†šHh#jB€~ì1<ü0žx Ã… ðóCF‚‚“ƒ°0\¾ ´iS׬T ‰"$‰PS[[¨©A»v¨®nÔ,€S§°v-ŽG»vxë-ÄÅÐÔ ¬ÿ·n!0JŒÌL¸¹5l`g‡ÊJØÙ5:uͺº"'..pû6pëVÝîR©ÚcÑ@ó‚РЦÚ0@[Ná "Ӣ籠ÕÕ8p n’F»vèÞo¿ðp¸¹!<›7#4àレ,ÔÔ ¶¶.›ÊdfÖ=ÈÈ€··b³ ÀÞ½¸qÿùæÍ«+ÔРŒ»;FÆ'Ÿà“O 7·F¯úø #C±ŠºfÃÂpútÝã?þ¨¢ •ÖýSw,DDdX ÐDj 7ЖýSYh"ÿ”ûf=B÷îðô¬{ƒõë1r$Œ…õëS÷Òܹxúi\½Šš\¼ˆ©SY¸EE(*B|<¦MSÑì”)¸t ÷ïC"Am­öåÍš…>À¶m˜5Kñ¥™3ñì³ÈÍEi)âãµ4;cV®ÄõëÈÏÇŠuCãÊ”E3^JHD¤/h"29z B÷ÆŽmxƒ[·0bŒ‰Û·ô²e2#FÀÑÓ§c„†ZC† woÂÛkÖ¨hvüxL˜'',[†O?ÕÞ <¡÷îaøpÅ—V¯Fh(úöE×® ÔÒìœ9ˆŠBÏž ÃСøç?UïNùXˆˆÈ°8šÈ„$''i‰[w˜ÝgB‡„à‹/𷿸-Ô¬ÉR7šs Mç@›ζ6vÚ7!"2ù«ñÔùÿöî;>ª*ÿÿøgHH!ÂÒJ”) ˆ®¿•²E¥­¸.%¡I(¢¬  Q@D¤Èª°`¥‹R,ë.HY±à%«„W’¥I(Iæ÷Ç —qZf’É̽w^Ï\nnùœ›;sß9sîÌÌjÙu5m` á Ety4‹ àVBp€F¹û<;¼ƒ ¡\F€ ]tB4ˆ ø :¡À94 Ú;øbp€¦ñ<;€Ö 7p+!Tˆ @븕 )h€tB€#h:@'´7q+!8G€Ü@€ 'tB{·€húÀóìA€Ü@€ ÜJèMÜJŽ 7 è ÐÞD'4Øèë 2ÈÐ_¡à Ï?+ô@ÐòÀ·èÜ@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Ü@€Üèë€"S¢*œ™›í­rD4zB8|Žh …„í?RRR|]‚‰U&ÐèLNl¶Ýðäf_QŽ|ll,ã ûÙð,ÓsÛ¶m}Wˆ?ÊÌÌ‘””Æ@ ?e?×¶m[Ò³÷©‡ €Aªï @ KÄe?¤Œß ïÙçÐyð4zEh|‚ €î‘¤o"@ cDgÀûx4ƒˆŠÒÁ÷Jdg“uP±JÌn¬ÂyT€^é"1[±­™(ãç|rÛÝ)§¢ŽüüóÏÉÉÉû÷ïoܸñäÉ“‡ ¢üN[µjõì³ÏŽ3FDž~úé+Vœ?^øåV4]²›rrr¼_‰["##­æDEEqmóneeóûÕWˆ˜†Ù™IªÖ‘‰'ÆÅÅ­[·î‹/¾?~ü!CRRR†úÅ_\»v­~ýúÿú׿z÷î½dÉ’~ýúùºXc2™Íf_× øt‘z¥×~bvNÍÓÄ£r%4WkVvÝTm‰³Ô åžccc«{GÊe¢wïÞ!!!–?JLLüýï_TT”žžþꫯnݺõµ×^3™LÉÉÉ÷ßuæW233é 3†IÏ"’““cÛ' ]sž˜5’•í²­Í*R[5<íC;vüä“O x#ÈM™2eäÈ‘%%%›6m‘~ýúõë×/55uܸq¾+Ö˜ÐtÉ鯠ßÄ\!«âÉÓÚ±téÒ§žzê™gž >|ø´iÓD$::úÎ;ï jÞ¼¹\ÿEDD<ñÄ>.׈ÐàKJ'4#¡uÇQnÖubvÎÅ<Í™ì7ß|ó'Ÿ|b;ÿ•W^Q§ùET+4®²›› š°lµe˜&I਀mnöÏÐìˆÝ0M’† °Ü\ ê!"IÃÀÐÜÀ Oq’¤…0 #@PÎ*=“›=Â6IzG€MÐì7“ûsO¡øˆÑUGt†Á Îøá#ö”Ĭf>u‚$í.ÛÜl~Ÿ0 # @€iùKaüù‹mÐ!í:«”ÌAƒÁ p†i×ÙírŒ‡ @ÅuH ‘Ü ÿC€À N’´øSp´;”Ùš?G€àK•~ô„?Í­ -·Ö«¡ ýu~óŸ‘Z Tˆ ~DùÃíAVÁÑHyšÄ 8B€ì0™L¾.Á3ôòô1®Ä^ÃĪ›[yÚî*¾Rṡ‘:á„f'¯GÎ/ hª‹eèt”PµüW ¡°‹ 8d·'I›—ÛÚ´|I¶”e¦Ñk<Ê×XDFF2ŠÃûìžäÚy©ò4 ³ÙìèGÊç«N€¸ö)4Ÿ!¶Âã*̆¦èC5|]§Œ3ÓN?œŸà1&Piô@€QFq0*†pT‘+=ôô@Ã%|Ü/ Õtí’ìììAƒÕ«W/$$¤{÷î[¶lQæ{eý‘ŠîÆ+ßCëÁƒ<çr¾H^^™u|½‹óÍêå{a”“Äù7ª(ïuº;‘*Íãg léôÝɹÌÌL‰­î¥¤¤ˆHÛ¶míþ´üæ)U£%'§hff&=Ð.‰ŠŠZ¹reNNΑ#G4h0xð`»‹eggwêÔ)000  I“&êx¹é¦›”‰›o¾9//ÏvÝI“&­\¹Ò6¹ºx–;ÚõG}´sçή]»¶hÑâŸÿüg…Û‰ˆˆ8{ö¬Ý)iXDjÕªURR¢Lûí·={ö¬]»¶Éd +((p¾üéÓ§£££•iuƒõ»a½©²Þ¬ˆŒ|Sf?"WJê,ÙBäz*5¿£sÀß$éAÉSòß”öQ2å½òù3?”s…’µDÒHjºý&ìüQ¾z^ί]eìr7VT¾HÅ%ýû÷ONN¾ë®».]º´dÉ’Î;+ó#""222ÔQË&L7nÜÒ¥K£££322^zé¥õë×+?š4iÒªU«D$))iØ0;éÀ2zº>„Cåh×qqq3gÎlݺuYYYii©Ý²-M›6í/ùKÓ¦Mcccùå—¹sç:¿©±¸¸8(((444++kúôéÖ9tèÐÉ“'¯ZµÊl6[˜v«~ÏsaP‡[†,•‡ºÊ‰b6Ë«Ûdè29ø’ˆÈ;»ä« 9¼HÌfyd±¬L‘±÷Tf~åèâ.ÌçŸ^™˜)"2»í UÙÚ¶侎R3@út’µ©2á^Ùúƒ$> [Êø^’rDF÷Y™"[“¥ÙïDD •NÓeÙ£å[X2R×Y2Bz½$ ã~³Y©$Ùg%ïWiQ_–µ_Æ Ë'BE^$ÑIåÿݸWöÌ”†á""¯(õVÞ#õk‹ˆ<Ý_^ü§+º%22Òù@€%´Küñ™3gîÛ·/88¸gÏž6”÷P=ýôÓwÜqÇ¥K—”ŒûÌ3ϘL¦ûî»/''§C‡Ï=÷œº…ž={Þzë­—.]ýµ_ÊÜAÒ4BDä¥Á2ë£ò@ìî|¸èÓïËZĶ“‰«¥èªì=*ïO”V“¥èªì;.k'ˆˆdŸ“NÓEDÌf)3‹åÇ?75,Ÿ¸¹‘äýj½Yùh’¼ø‰Ìý§„ÉßGÊÀ;ì”ñí1™º^f•Q·ú‚D_ß~tûMPÒ³ˆÔ ’’ëBº²¢‹øVBªÜXy³Y¦m”å»Äd’Çî•yƒÅÅ,«84_/#ûá·\ìpôØîHî^þ¥êEzzzß¾}Oœ8áÞj^¸l÷~Aç7Z^]Y,[JâbY²CÒþ+O©;V~Y*á¡""Š$:IÎ-¯Ì|W ¶½MG=ж*Ý }­TMŒW¤Q¸ˆHŸ—¥W{ùì?òùt¹ÜÛAö‘mSEDZ$Ê7³Ë{ -™†ÉÑW¥uc‘Ì\¹wžü²Ôz³ªí‡$áÉ}½|EËßEó'åoÃäÛ¤n¨\¼,uÇ–ÿ4ꯒ:SZ59–'m¦”ÏWW·ÚŽú_G+VŽó[ ¹‰PkÞÞ)k¿”'•05&ÖÕ¿«µ“€¹‰°*ªõ&ÂŒŒŒxÀr€e5±ÌE^Û©";;{È!û÷ï¿óÎ;7mÚ¤1Ûò„›¡5‰‰‰gÏž=}útrròÀÝ^?Þ\Õ®l¿jþ>JVì–ˆqRoœ¬M½1àÒe©R>]'T.^®äüÊ?~|•Ö×›Ôt‰‰¼sût’ù›¥÷­""÷ß*ó7KŸNå?šp¯Œ[!Çò¤¤T~:%ñ¯ßØÈ¤u’ÿ«äÿ*IëdX7;›[&‡³åj‰”•Iéõ»"jIFî_• @ ­)Y2~ÅùCÿ “ß“‚‹ræ×£]QéíâVB×ÙÞ3*ŽoB5 “Å;¤E¢˜†Ië)¿¹·¡ÕdIûï¾ÿk¥òÔûÒp‚Ô'¯n«`³êS‘õä¥Á²æÆã@Õ©£{[áC{öìéÙ³§±wúôÓO÷èÑãÂ… Ý»wONN®ôvÂo‹‰‰i×®]QQÑŸþô§9sæøº UËÍ–]; o˨ž2¥¯ˆÈ+[åÑ·äßψˆÔ‘K—Ë{”/KëáØÝù•¦£ ]õŽÀOJ¿Î7þÛ§“$½+÷ué}«$¯—>×úÌŸÄ´Eî›'9ç¤C3yÎâϺž·È­ÓäÒeüÿdö#v6ûPWùókr<_ni*ï=Q>óé~rÇ ¹t¹¼þÕÉä÷dðߥùï$¹¿lú¶|±Éc+¥E¢Ô ‘É}dÇ!W›VéQE#ß”7d@ÉûU^üDÆ÷±¸ µn-I\+Ó6Üø›yßq9ø’4¨#·?'»K¯""»K½0¹ÍâÉœ³?–‘ƒ/Iíyáå3mö§SrÇÍåËt½I~²~&ªý:•±:–/¨“¥£dÃ_åZ©¼ð™ò^ù ¬Þ¢jãàS+åÞÖßÕ–¿}*c—˾]]·gÏž^½z‰È÷ß?f̘´´´ÒÒÒôôô{î¹çøñã¡¡¡ÅÅÅ­ZµJIIÙ°aòeË”Go™Íf“Éôä“O¾õÖ[W¯^ýî»ï>ܾ}û5kÖtéÒÅjÎí·ß.}áêN_xáËm9rd̘1¸é¦›V­ZÕ­[7u/ÿùÏlKЉ‰1›Í–•ÛÝÈ_|ñã?†„„Lž<¹cÇŽ•>V -€ÿ±b«øèGåÂòò1З¯IÄ8¹¼FDäîÙ2wÐõ‹èO2ë#ùêùÊÌ·e˜ç@«ª Û>%›ž”.Ñžª¨z7›ž#}_–‹½·¢G9"##Õ;;ýÄ /¼àèÄk™(SúÊÃwJ‹ú7fF'ÉÖdéÐLD$ï‚tš.§ß1 “œ×ËïaXö™|sTÖO‰[&=bä‰Þ7mó'eç³Ò¶éoöåh³ÃåÚ:©a)3KÐH)YçRN†p]•è$ÉSD¤Ù_eOE#‹ Þ._tUꎕkï:[Ñ–Þßì2ÆŽfÍšíÞ½»M›6:uJHH˜0aBpp°ˆ 8°W¯^‰‰‰K–,Ù³gÏ?þñÚµk¿þúëC‡U0™LkÖ¬>|x@@Àm·Ý6nܸ„„„U«V­X±âСC¶s,‡p¨;µÚæwÞ9qâĸ¸¸]»vMž<9==Ýr/¶%)Û´ªÜv#×®]«Q£Fiiipp°ú˜]Û£ÄÀ1O ØPX~^Ù!Jæo–óEr¾Hl–ŽÍÊçì!3>”Üó’sNžû@íYÉùþ£*Ÿg¾âù˜ëñÍ&¾+g/Ééó’¼Þþ ˆ_UñÑ$Ùù“t}NZ$Ê?”ÏTnB !Ã¥É7ÆBˆ”§gÖM¶ý g/Éÿ.ÉŽCßí7›Í=/77²Þ—£Í*L),?˜R†g(/»uZùö˜ôœ#µÄ4LÂFKÁÅòùZ¸·>qüøñ²²²6mÚˆÈáÇǧdP™:uê¢E‹.^¼¸hÑ"å«‚W®\ùÎ;ïDFFΜ9SYfذaÊwY9rdìØ±aaacÆŒ9|ø°Ý9vwjµÍ~øaôèÑ!!!}ûöUþ>±Ü‹mI «Êm7R¯^½3gΈHAAA½zõ*}¸ÐðWž‹Î¶ÞŸ(_fHäD‰œ(_fÈûËç?ÖKºµ•öÉÒaªü±Œ‰­ä|`°Þ)GbšJ»di󔄇ʜ¿xcETÅ7Ëæ§äÌ[òöyüú>›FHÖ)Y'¥ï‰ù})³7*½^˜U`]»*½"4Âr,rûöí—/_~åJùÐû»ï¾»E‹ýúõkÕªÕ]wÝ%"C† ùúë¯?ÿüó¿ýíoÊ2壂o¹å–µkׯ^½º}ûövç)ŸwYîÔj›;w^³fMaa¡å·C¨{±-Énå¶¹ï¾û/^|ùòå×^{íÞ{ï­ôá"@ÃÿTOt¶ü°ò–HÙù¬­–¢Õ²óY‰¹þɬÉ$‹âåÜr9·\ ½ñð)wçÃ0&ö–¼7åâJyâF«uEG¸•Ðvïurª¥„?ʊݲr·$ÄZÿhTOyr­œ:+ç‹$éÝ 6ë¦Ö‹2IDATÊS¸·Þ·gÏž?þñÊôêÕ«W­ZU«V-õkݦNúå—_N:Uù¯ò½o<ðÀ³Ï>kµ•+W¾þúëáááo¿ý¶ò ¶s&NœØºuk“Éd¹S«m®_¿~ݺuõë×W¿cΊUIv+·ÝÈ¢E‹öìÙþå—_ªé¿ ØQÅ1ÐÞg¼1Ð í?SÌHìƒæ1v–6î•Ù—ß3úÊp¹ÿV‘2³,Ü"oï¼qê_~/b3æ¸Ì,ÑIPCN¼VþǰºÀµRI^/ë¾³YfýY&=èl³Ê”®Ø-"òؽ2ˆ?­íÖùÒ?eÁ–÷¶n9(“ß“Ÿ Êïm}buùü¢«òØJùx_ù-ª³>’«ïþ¦ZGOWt´¢-c¼;Y1Àèèèè­[·vèÐÁ#uºÈ';­+c  Ѐh @{™m†&@û³jº·ÕïNV  ¡â&Bú¦¼ñ@YÀ›¸·¨ðŒ„ösÜÛ Tˆ/R ÚùbcS¾n~nbo™ØÛ«+ºC4M3Ø@I€ 7ð<;¨€Öq+!@SÐ;è„G¸‰pÈn—§–ûAµ\[eggGEEq+¡wp+!8G€0»_|íÖ¨°ÃWßÒäü+¦ <ÏÎ[”NhFq€]hú Œâðu08u°‚¿Ö’´ëÈÍp‘’žuŠ @Oè„ö&¿í„¶å$I aÚÁ34ÉÍp…»Ÿ… @§vð Û$-þ¦½ÉÍp…~o(Ї”8˜ãë24Èn’›Xi¤<íü¯Vr3\§ëÁ 41ÞuZËw çˆD¦Di¹BŸ³:!”§ĮVº~W!@€ïéýÓL¨ÜÊÓ ¤ê ‡E‘˜áÆx»#@€Vh¹£W˵i™Ý‡âYñ~ªvýB3<˃7hÐ öÍäÄfæšç[vè[©ºZ‘•á5šz‹«4hݽþíT]Ýûª•;* Z¤©+Ò M¬÷Ò-ŒÇ`dÕðu‡ vÉÇ)Øøº  êYj˜? Р]Ú¹Ø(•Õ4…_ôE;ohUG€2ÒÅGz†^hj@š§ @‹4x±¡Z#¶1ê¹J€@7ŒG`HÆú¬"@€VäÄf+ÿD«9I˵ùŽ<ôÈxéYР–×íçT-×fTsè‹!‡>«Ðàcj¯³- f&£^µŒAÏÐß±hÐ"5§jð:¤ýrƒ±ÛhŸ‡>«РQÚ¿ö¡½Œ 1ö¹J€íÒl_¯±/ÚÇñ÷[±±±"’™™éëB2öÐgt@³Zƒ…›å‡ã†Ï(ÐÿyCôugrb³•kRdJ”6“f 3Ût‘÷[섎͹G™H‰Ü-Ú+ϳè­Óì …š-ÌüáÆ,¸BÅ¡5¿IÏFK4è€Ú­5š-̨HÏmfèõ""oŽõmÞB4èƒfÇk¶0#ñ“³ WëM""ñf_×á=hÐÍFUͦwXhš’žý tC³cŽ5[˜0ôš¦¦gê~4è‹f£ªf Ó5Ò34Í_Ó³ @w4U5[˜N‘ž¡i~œž… z¤Ù¨ªÙÂt‡ô Móïô,hÐ)Íæ*2tÕ‘ž¡þšž… ú¥ÙçÇ‘¡«‚ô ­ó¿‡ÖÙ"@€Ž‘¡ †ô ­#=‹ŒAƒ9• í.Ò3´Î/ùlÐåÛY333}]ôDË9U˵i éZç÷7Z"@€îi9§ZÖ¦Áò´ÀòÈž¡Q¤çß2™Í@CRRR|]ô*6çe"%r·o+±Kãåù ‡Å0”‰ôlƒh@[ŒüŒj¦&05“iŠÆËó Ò³aù­›ôl=Ð`,¿ÚYÞ„¤Í ½ƒã]Ðøû‰ï Àp´ÍÓ~…ÕÊÏ›½àDuŒ F¤ý+ŸvÁúg«¡GÚñ)4”.®º(ÒSüª±Ð5ÎÕŠ À¸tqô‡NYh# Cï¾F€CÓ˵ШÓ¨í‚QéåÃ×Ð`t:º")n©-ð:z¯ð54ø}]-£§è¤f•®‹‡?Ó×»„¯ À?èî꨻$ª»‚•îÞ| ~C×H«T*Ú+^ûÎéñÁ×ÐàOô{¥ÔZNÕZ=@åè÷=Á§Ðàgt}½´­ ï´Å·{E€ÿcŒ«¦£8+žk—vøŠ1Þ|„ þÊH—O'I׃ p 1ÖkßGÐàÇŒzõTž6Øaĸ¯zï"@€ãj ø^ïRÃ×|J½Žzg_!={ü0<Ò³G dhÀÐHÏžÆhÀu–é™ ­™Lš¸¬k¤ ˆð¢®.ô@®‹7ë¨+:;;{РAõêÕ éÞ½û–-[”ù&“Ç*ß¾}{lllHHÈï~÷»¡C‡fgg;_Þv×,ÆãL&“ÉdªY³fTTÔ!C~øáWVñBaUQ‰ Ûµk×¶m[«(êÔ©óàƒfffªó—/_n¹äöíÛ5}L,;žIÏE€ü–N2ô!CÚ¶m{ìØ± .Ì™3ç7Þðø.-Z”””túôéŸþùÖ[o4hÇwá[f³ùÊ•+û÷ïïÞ½{¯^½¾ûî;_WTUîö|ÿßÿý_IIIPPÐÞ½{­¶c6›Ož<Ùµk×øøxuþòåËKKKÕÿ¾üòËU,¸1l£: 6ô¡÷íÛ7cÆŒúõë÷êÕkûöír½Ré>T+-->}z£FjÕª_XX¨Ì7™L .lܸqXXXBB•+Wlw±k×®‡~8""¢N:O?ýô÷ß_éjí®¸¸xÔ¨QaaaMš4Y´h‘Z¶ÉdZ¼xq‹-EääÉ“¬S§NHHHŸ>}òóó•Å®\¹2zôhuuuwŽZm«F‘‘‘O>ùäœ9s^|ñEe¦ÝÝÙ[GU‰ˆÝÆ:Z~ûöí;v ŠŽŽ~çw\i¡C‡Z·n­Æe³ÙܪU«´´4Wj³´víÚQ£F9ríÚµ¶?mРÁÌ™3ÓÒÒÔ9={öܸq£2½yóæ:8:°>Fz®fh€=–Z“1ºk×®Ï?ÿüÉ“'-g*‰Jé>TæÌ›7ïÀÌËË ž6mšºpjjjZZÚÉ“'sssgÍšåd_………‹/¾÷Þ{•ÿVîS{»»›9sæ¹sç²²²ÒÒÒRSS-—ß·oßÁƒKJJDdÀ€IIIùùùùùùíÛ·Ÿ2eŠºú™3g²²²:´k×.u]'­vä‘Gùú믕i»»³=¶ŽªrÔXGË9röìÙ/^LMMÝ¿¿+MèÔ©SxxøîÝ»•ÿîÚµ«^½z·Ýv›º€“ÚTW®\ùàƒFŒ1|øð>úÈö¨‚‚‚¹sçZnvâĉ .T /¼””Táõ6Ë,é¹ú˜pâ})ÿ§1§NJHHhÚ´iDDD|||vv¶2ßêÒÖ²eËüQ™>}útãÆÕÅŽ=ªLgddDEE9Ú‘r¹lÔ¨‘º¼£«§í|±HœvwuìØ1eúèÑ£–ËçääØÝKaaaÆ ÕÕ-7«®î¨ÕNª½víZ`` óÝ9‰ V‹Uxl-—oÑ¢ÅâÅ‹þùgË*lÂÒ¥Kãââ”é¡C‡¾þúëŽ*´Ü—¥?üðž{îQ¦{÷îýÁ¨õ+ÂÂÂz÷î}äÈËæ÷ïßÿã?þøãûõëçü˜ø€V_­ÆÃ!TDÛWåÜÜÜÄÄÄnݺ)ÿµ 45jÔëˆP+))Q¦eG•2̺GÎ+1™L¥¥¥êKJJjÔ¨á|w–ó-´å–÷îÝÛ£G°°0%Ø©­p´º£V[²ÚENNŽš2íÎŪ5ÖÑòûöí0`@ƒ š7oþÉ'Ÿ¸Ø„³gÏÖ­[÷ÿû_AAADDĹsç,+t´/Kýû÷_³f2ýÞ{ï)ض™VGlÇŽ·ß~ûm·ÝöùçŸ;YØ´ý:5Ž2ÀÚ¾6_ºt©f͚ʴU iÞ¼ù/¿üb»ŠU/i³f͜¨(88Øù2QQQêÓÓÓÕÍ:Ú]dd¤£hË-7kÖlãÆçÎ+++»pá‚úÓfÍšÙívÔjKV»XºtéÃ?ì|w.V危ޖWmÛ¶­I“&®7aðàÁ‹/~íµ×âãã­*¬p_yyyÊørU``àéÓ§m›iuÄÊÊÊÚ¶mÛ±cG»ÇÄ7Ô—§V_¡ÆÃh€ ÔÇ`ifHtÿþý÷ìÙsùòå‚‚‚ tîÜY™¡DIÅ„ ÆwìØ±’’’Ÿ~úÉò‰ “&MRÆÈ&%% 6Ìv#FŒ8räHIIInnîŒ3î¾ûne¾£1ÐÆ ›4iÒ‰'JKKOœ8‘””4bÄç»:tèäÉ“ Μ9cwœ®¢¸¸8(((444++küøñêüøøøI“&9sFÙ¬+­¶RVV–››»lٲٳgÏœ9Óù­£Å5ÖÑòqqq‡¾zõjYY™úŒ Wš°bÅŠ•+W&$$¸xÄTï¿ÿþ°aÃ,#ÑÈ‘#ׯ_ïè@©L&SFFÆþóŸ —ôžUç¾Jî]ÒLG×§Ÿ~Ú£Gàààðððþýû«ý¸sçέ]»¶z+--7o^Ë–-kÖ¬Ù¹sç?üP™/" .Tòðè£Ûîâƒ>¸õÖ[7nv«Ú¹sçW_}uþüùŽ;V™9`À€¤¤¤üüüüüüöíÛO™2Åùò3gÎzôh'‹HqqqPPPhhhVVÖøñã/,"C‡UžOræÌËÓŽšwøðá«W¯–•••––ÚnÐê·æ¨Õ–\<5ÍQ*Ývœ¯<ðé§ŸöèÑ#888<<¼ÿþj§àܹsk×®­^ïJKKçÍ›§·¡e¨»°|ÅØ±c-ëܲeKË–-ËÊÊì³uëÖN:µnÝZí½ª›7onÕªU``àM7ݤ<Îùò………Ç mÔ¨ÑüùóÕÞ_GÍܰaCLLL```ÇŽÿýïÛVkõ[sÒj•‹'€£¦9jB¥Ûc3™yÀ!Àï)ca}]E•Êxã7²³³_zé%Ï–ä®ôôô¾}ûž8q·eTE¥›`€¶ÃE á@÷.\¸°téÒ‰'úª€ÄÄijgÏž>}:99yàÀ¾*£**Ý´î"@ o&“©~ýú‰‰‰‘‘‘¾ª!&&¦]»vmÚ´ Ÿ3gŽ¯Ê¨ŠJ7Ám‡»4ñ‰ ô@n @n @nøÿªÖF²ôþÈÊIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/complex-deploy-2.png0000644000175000017500000010427510014674771025112 0ustar frankiefrankie‰PNG  IHDR> šj­sBITÛáOà IDATxœìÝy\Tåþðϰ ¢lŠ,£,!*®åZn‘[ŠyãVäViþLíša(–Y©¹eVZ.í·[YYi×k‹©Y¸›й È& ¨ìÃÌïÃ0ë™a™íó~õêuxæœçù>çÆóå9Ï9…B""""""Ëæ`ˆˆˆˆ cêBDDDDDV€© Y¦.DDDDDd˜º‘¥úZ‚¯%æ¢éØXwš–˜Ó$;°¹‚Ue«’ˆH's@Dæ¦!í+\Û†›§QU´ …ï0„>…ö÷š;¸f¦zçàW_xöD`îzÎmÍ–öØ”f~4eË´b-aQ¦.Dö­ü:F£ðD}‰¼ÅçP|—ß·¯‹6yʲQ–ë{pá Ü¿ >ýÍ“ݰ«3ˆˆLÅÔ…ÈŽÉ«q`ŠþBëŽèù „› JÓ‘©ÿ1w|-E¸n–W¢ü:òà¸u ã1þZµ3wpDDDT‹© ‘KýŠþ‚{ü®êJát~¦~My%.­Çµm¸•]2]çÃÁ¹váÖšÇnâÔ©o5y%öÄ#êå~‘x`\€º«™ÀñÈù¹~…a;pnnž©/ø:Ï®]ÖºI뎈Jª½^o0Ó@£O ýkõ<ºaÌ1¸x¡ª?÷By†|ƒàIpí[™÷ D…³§ö®éšÌù=ŠvƒðàqQ­Ûƒ»ôp 2¶£Ï*ôx¹þÓ‹ëpz:Fcøu¶¨oŸ‹îELJ‘õ¿úúoD—çê?U¥ëF¯}CqãFþ¿HTa{{@‰+‚³'òþÀþðŠÑ‡j×ךº¨µ¢?6M•…Ø}7ʲêK”ûJ¶Z[Îs >ý ‡¡uˆ> ´n.¤ßZqàÔÈ«‘…ÜßôuAÏžÓG]›Wà—Þ(¿^ÿ‘t²¬oÝ`wtî"">aŒÈž'@À«]|7ŽÀÅC¿EÌ-<~C¾†‹òpiCƒ5+ó1!—¢Û p|:œñÐ%L,«-¹úoõÊo]ƒbR%<Ž6¡(ËÂ…µZb¸ò Ò¿F›P ߉˜bLªÂØSð‚[—p~¸øàÞOàïePÔ@!ÇßË!qÀ}_êÌ[ôè0 n§ˆmÝØîÜ¥Ý@ÊfÈ«k7QÔ etoP•ø}.¾幘p—¢Ë<Hý¼¶\yù8EQûŸÎ8@íªüƒ€î!PÈqãp}¹°Ž&ý­èŠMÓÅ7Q–…6aõGäÖõu‚ÇØ¿0©Ñ™žy5.¾m =›(é9 ôl.dý7"¦“*0æ(:FÆ8¥äw‘ûœ=0èSÖÏÅ»6~ñ­Õƒ»Ô§/Æ <×¾©Ý$ó”fÀwÚnP•ø}.¾?@ÛÎpjž¯À­‹¢w\ßa€2u9}VBžêòCc‰-k íˆ¨ú-|úÂÁ­;bÀûP 1fÂ&zN=›·jy yò ÝÀÚá5ñN)}+ üa3Ъ\Ðþ¾ÚÚ”ôìI1}Ôµ¹0ÀR¿ªïvƒÝѵˆˆ8×…È®¹x¢²•…põÓ·ÚíËÕ P¸iþVJƒB¯Þµ ­|µ—Èî¨W®zýê;JÓ´ÄPrö ÔòQYFýò=oáú^œ{ÎðîƒÞ¯kY_ŒÊ"pö0®uˆîŽ˜]Ú}1®ïÅ¥õ} @íhLDÃ!³ÏÅ÷«Wí‚0JVªeý|‡@âX›ºä%À-!S¸y ð$Žh?ÄèjŠíN íˆ()jpi=Ò¿ÂíÈÊj Ësõµ.r]§þÍûoƱ§ù2€¶1|'<{qà”n%€t‚¾¾èÚ“"û¨kó;éà;´~MÕeˆ8uí""ŽºÙ5á÷úÞ&«Pâh¸Ä4zfå)o© »…ª"(d(ËByd·un¥ßCàÑŸ֛–_$Ú ÂÍ3Èû…'Qp]L³ˆßçâ{Ñø£æìï>(ËÄ­‹(> ÿÑ€£q3wRQ– ï>&¾9§©Î(§ãq:7ÏÔ_ W5ñ&â7ïøü3 Ãv Û hÝ·¯àÄlÀ´ÓOÄ'uíI‘}4p T4 Æ`wtí""ŽºÙµàIÈû/EàØú¿ÙkjÛÅg‘ó ‚bê …»q<º66†üCõ“mn÷P-«yö@Ñ)Œ?gà¯'æ ê&ú½‹Ò4œ]Š“ÏaˆÆl`ƒd¥ø{9Ž3®uˆîŽÈ]Úc1Fãâ;µã? E]’ê"¾úH 0‰ï0%ââ[PÈk÷IÀ¤}‰äwÝ]ŒmE6¡¸uIËQ¦g Ù†À±pö@õm|¯6-J# ÛÐ}ÜÜ© :=‚N û"üP;leÂó芛gµ !SÄn¢$²º»ýÆ‘ú‡’©=ŽBLw´î""Žºh’bÎ]Óá}î¤aw?\ù¥× ¯FM9n]ÂÕO°·î~á]'ŸEÆw•Bv×¾Á©¹L¹0Rsj. O@^Â?qr.tÔv—K—@Âx¤}²L(dWâv ®|„½÷Õ®sídý^½2Ý¢µ×¾©½çD yJ¯!í üÚÅõÂçѺQݹK;þžÝ‘ó 2¾‡«¿Á$¾z´ò€¼ÀП„ä$m+ ÿ(ðHjà«7uߊ•æQª)GW8ºâNNÌ2†ÁMºNý›ÿ1¹ûjχڹ1€IN8UNþ ©Ÿ¡ªò*ÇAq“ÝEöQá)Æ'ÿ…¢SW£èNþ«Á »£k?qÔE`TB"fe>rš¬ƒƒ îÿFÑ_únɈˆCÎϸq‡'6(÷‹D×ØÆÆÐ¶ ö ªÿ±uGtQËjw=¢ÓHÙˆcÓ´×S‘SÏ@ŸÕ8À©5z¯Âñé8ù,: ¯ø«‹æcp݃0lGý ¶nlwÄîR º¿„cOA!C×çáÐÊ@ëú‰ï…~ c;ö¨ýQßCƆ€¼ Þ}j'S¹úëŠÏ@‡¡:74ª="!ýkܾRDÇãNjý "kgý½æ›C4Ã0¸‰@×i óë¿âú¯ J‚L:p]æ!çäîÇñb7QÙG]º¿X;Oæ×µ%ãqû2$u×»£k?Ùí_2ô¤(ô2¶þfŸ¨é´–bÌ1ÜûoŒkHœà䯞cŽÕ®ãÐ #~CŸÕðêGW8ºÁ«7î^[ÿR—Æò5ÂfÀÅNîèø0FlðFUýßÈ}z ­¥pp†£<»#|Nmœ§æ¢²¾C꯴BŸ„÷=¨ÈWÿ£¯.ŽnhÝQ°ãÏç¿­Ûñ»Ôw8µAø³¢z¡ŸÈ^èÑï]tz.>†oåjå nà¯òômá6*}7(ÕŠ¾ÚaÔAtüœÜá⃰Òðͤƒ>F§GàÔ.^¸k:o5†ÁMºNý›ÜŽÑpñÄ mBÑý% ú¤ö#cœƒ3"wãžuðîGW8µ†_$îß%j¿‰ì£.­Úcô!H'ÔïöþïuOíÓ=ûˆìž½¼’R Ñ´;¡%Û"²bº^i¥š©;×¾Á‘)èú<ú½ÛÄ5µŒÔÏp|:ÜQ æ…ˆ¬žÍŽº5®Ò´M믜C1D$Vu 2¶@ØLs‡B$ÚÁ¢à8䕨.AúWHŒxÓ5 [›ë¢++0ãX‡jÓÊð${ï"")gàŽ«‡‘åËÚ‰¬ J¼ïAg#§ûic#£.ZGWšo\ÅdªÁpø…ˆ 8ÁïÞèOV&ò<gO8¸ M"bÔ}Șë¢õf0³Db,ÕÈ­%f"""""s±âÔEsŒÅ\‘˜Ìº@DDDDÔ2¬5u±¥! &0DDDDDYeꢼַÆàuaCDDDD¤‡OÓ·±‹{µÇ p?‘*ëu®é­.l£Øä°QcXÙ¨‹ŒE¨>@Ù¼‘Y+u±‡!%޽Q£äý kQxÕ·ÑZ ¿6¾CêWÞz9Å|ß0_küuFL0%çqv)ò úÚ„"ìÿÐíHlí ËDD¤ÉšR»Ê[-ÜeyìêpY“ÌÿâðcPÈÕËUskL]nžÆ¾a•6(¼k:îý¬)#""‹d5¦â­SM¢Éw£±2Õ!j!g_…BéܳmÃQuy e‹¹ÃÒÆ¨ÜéÌK•"`,ú¿‹6wáöUœš‡Ôÿà®éèp³…HDDÁjF]ìpÈ€DbôjdrÒbÍÙÛ¡$jiÛ\ ¯Æc…pñѾ‚žô­¸ò nžAM9ZwB§hôx.^ 6Œ)Fb2wB^ÿQè·î! +Ãß˹eYptC»è éCúb0*uù® d¥x$®jK*òðƒ?îz÷þÛˆzˆˆÈ YÙ4}»"dš¹D/ƒÕ*ô26Hýµé©Ü¨˜‰ÈhnRHÙŒÊBc6SàèT}ùP]yî\ÅÅ·±÷>T7XñÈT\ý7ªŠ »ƒ¬Ø7 UEðç \\‡;iW£úrà Úü±+¶¹bï`ä |oH ðO#zIDDÖ‰©‹…R½ 7orÒ„ ¦1æ ŒÈõz ξ†¾ØÕ‡'"í È«ëWPŽuLQÔþàÊ'HÿmB1|'bŠ1© cOÁwn]ÂùU ê¿u þ‰I•xð8Ú„¢, Ö@Öÿ ÿFÄ”`RÆEÇh¡ÞN¼ÇðûhÜïÓÃb“ñ˜Ã5¯»žÆÈß!'wÜ¹ŠŒïpl~퇊<}[]ý†|‹ŽÃÙÎðé‡!ß@æ¬9` Ú „ƒ Ú Â€-õ#´jy yò Ý@ o¸¡ªàÉxè&UbÌxtƒ¼R=AÒÔk$ŽÈù?†ã'üØNî +3°!Y?ë˜ëÂÔŨe,<ÜDMCQƒ[ɸqÞÄ«™ŠÁ[k?Òœjò»ÎÀÁ“ªê·šXG·ÚdeøÎŽ®˜Xެ]8öªKj?jÛÃw³‡á8‹Ná×pí€Gê’+µÙ8Ê8ópn9 O„LEØ ì/ýôÓîîîþþþëÖ­SÖ¦k ¥ººzÁ‚¾¾¾ÞÞÞï¼óŽÖð” º•H$|ðAHHˆ‹‹Kß¾}•1«Ú½{wÏž=]\\BBB>úè#ÕšÅ;µ.¨î]›¤¥¥EGG·mÛÖÕÕuܸqùùùúw”*ú{óæM__ß‚‚åîíСÃ7DV«Ú#ƒçÍ›÷ú믯X±BOåááá—.]‘‘áàà““àÒ¥Káááú»£ L¡P888È´ø‡¾mÛ6ay×®]=zÔßâ«ë©žšõ+¯µƒzÚÕº¾æ/‹žFÐÿ˜Ý¦¢ûT¥e‚$ËÄӀȲ|ÅWü}´÷Þ{o|||jjªZ¹Ú·î믿>jÔ¨ÌÌÌ[·nMŸ>}îܹÊÕ¢¢¢rssóòòÆŽ»hÑ"Í&øøø8;;wéÒeõêÕ2™LkCÒƒ®Þ)?ºqãÆ’%Kúõë§,Ÿ>~üøñùùù¹¹¹cÇŽ…ÊýÌZ[yùå—ÇŒ“‘‘QTT«e]xì±Ç233KKK—/_>`ÀÍ~µoßþû￯¨¨¸víÚÌ™3ÕjyìÔ¢RÝ!º6éÑ£Çï¿ÿ^VVVRR7uêTý;J•±ý*™7oÞŠ+„’_ýõ¡‡_­jôP‹6''§}ûöz*Ÿ7oÞû￯P(6oÞìêêúá‡*Š-[¶<ÿüózº£«EâššÚ«W/¹\.—Ëûöí+Ü )|ªë©žzv¸’ž_7­›ëiWëúZYD«šEM…©5ž9D„©‹mÉÊÊš1cF@@€——×”)S²³³…rµ¯ÜàààsçΠ˹¹¹~~~ÊÕ._¾,,'''K¥R] Éd²¤¤¤x`þüùZ›0’žt5ªüçÃÝÝ}ôèÑ/^T–çää(W LII–/]º(,K¥RÕÞL]:v옜œ¬ƒÖu5    @X.--urrÒìWPPІ ®]»¦µf‘ÇNm[Õ"f“ÒÒR___aY׎Rel…JRSS;uêTUU¥P(fÏžýí·ßНVµGz¨E[]]­ŒAkå¿üòËĉ ETTÔ¢E‹„lêñÇß½{·žîèjÑ„ø…Ízè¡;vìØ±cüøñš½P ÕBâ>úõ×_ûöíÛ»wï}ûö©®¯ë<{ÅÿÊkÝÜ`»j?jýes®6v®‹žy)j‘Åò÷÷_½zõ‰Úfžž.“Éjjj …\.W~”––&,¤¦¦úûûëoE"‘¨nkTHzbh$???Õ^øùù)[T-W®ïääT^^.,*ËTW3­Q1 °k×®7n|øá‡Ï>û¬þ•MØoº6‰‰‰™;wnVV–\./))Q^àéÚQª×&÷7>>þÝwß=zôèСC]]]Õ>mÌnÔjÇŽC‡ÕS¹››[×®]7oÞܯ_?//¯~ýúmܸ1""B361LŽ̘1wîÜ‘Ëå£FR-×uŒŒeìicl»ZYÄ4jzê¢uJÓ""7E!ê+d%zè¡TTT¼ñÆwß}·Pîåå%Üù#˜3gÎ3ÏëÖ­+++ËÎΞ3§þÁÜÓ¦M›7o^VVVqq±r}]áéjTdÀ.\¨ªª’Ëå555jŸŠ?vºèÚ¤¼¼ÜÅÅÅÍÍ-==}Ö¬YÊõuí¨&éoÿþýÝÝÝ_|ñÅ'Ÿ|² «U#—˯_¿¾iÓ¦eË–½úê«ú+7nÜš5kF `̘1kÖ¬7nœiíš¿D"INNþûï¿ÕÊu#ƒyÚÛ®Ö_QjÄè×øˆLÀ“ˆ¨9üôÓOÆ kÕª•‡‡ÇC=tåÊ¡|åÊ•mÚ´Q~ñÖÔÔ¬^½:88ØÙÙùî»ïþþûï…rk×®ž4}útÍûy Å·ß~Û³gO'''©TWVV¦ÜÖ¨tÅ ª*]M¨•———Ïœ9ÓÃÃÃÃÃcæÌ™Ê^”——OŸ>ÝÍÍ­C‡o¾ù¦r«ÄÄÄ{î¹ÇÉÉ©S§N›6mR–WUUÅÆÆúøøx{{¯_¿^kxÊ]BÄGß|óM×®]œœzöì¹gϵ5E;=­èÚd×®]aaaNNN¡¡¡[¶lQí‹Ö%f'ëê¯jù?þ,—ËM®VáÃÑÑ1 àñÇOJJ2X¹0-þ¯¿þR(Â{`”S}Ä>ÕBâ×_§®c¤uÇ*Œ?mtmn°]µµþ²ˆ9WÅ>ÂY님 ‰šŠ„ïx!"²0–ü.²[¶lÉÎÎ^µj•¹!óõ£š·ðŠÌ…© ‘¥aêBÍ­¤¤äÞ{ïÝ¿`` ¹c!ó3<×E™·(zÈÂmÛ¶ÍÏÏO8pªËDDDDVD"‘´k×îùçŸgÞB},±±Á–þËP“4gZ%AAAÛ¶mmÚ4wwwÿuëÖifB‰êC¨%Ɇ ‚‚‚œœœ¤¥¥EGG·mÛÖÕÕuܸqùùù¨»¾wpp6T.«†¤µ§VÁ6r0""³ùšß¢DdÅ´¤.¶·öïßøðáâââèèè™3g …Ë–-;wî\bbbjjjFF†P¸dÉ’œœœË—/§¤¤¤§§¿òÊ+ÊJòòò233W­ZõÄOäå嘲 IDATedd¬ZµjÁ‚"›{õÕWoÞ¼™žž~öìÙƒjn¥ö$;Á‰'e2€ &ÄÆÆ OÓïÞ½{\\œÚVZkÐÕS""²qBÞÂì…ˆ¬––;pluFòv#‰DRPPЮ];eeežžžÕÕÕ:uê´ÿþ.]º¨n%•JÂÃÃ$''1";;[¨¤°°ÐÇǧ²²ÒÕÕU¹ìîî.ä›ëرãÂÂÂ\¹r%<<\ë±P-”H$999š½+++ QxѬA¹¬µ§–ÏVÏL"¢– ÌXøFQ"²Zê©‹ _ªæjù€ð£““SEE…p/–’““See¥££#™Læææ&$Ó1Í©Öììì,&uQýñøñã‹-JLL,-->•ËåbbÓÚSËgÃ''QóbÞBD6¡Á cv>‘ 55U­ÐÏÏ/--MXNMMõóókªæüüüÒÓÓ…eå‚QbbbæÎ›••%—ËKJJÄ_Ókí)Ù8æ-Ddå´Ìu±Û¿jO›6mÞ¼yYYYÅÅű±±BáäÉ“ãâânܸ‘ŸŸ;yòä¦jnÒ¤I/¼ðBAAÁ7„i*š¼¼¼’““uÕP^^îâââææ–žž>kÖ,ñMkí©…³ó¼šˆÈt ó"²~†_Ii?–.]ѧOŸ»îº+44T(\¹r¥ŸŸ_çÎÃÃÃ;vì¸bÅŠ¦jnÅŠžžžAAA={öû,>>¾M›6#G޼ÿþûÅ7­µ§–ÌADÔ,˜·‘ QŸJ^šÃ¥K—¢¢¢x—.<3‰ˆLÁ¼…ˆl G]ÌéùçŸ/**ÊÍÍŽŽ6w8Šy ‘)ød"²9 Rå±ÌŒÝéÚµkDDDxx¸‡‡Ç믿nîp,ÏF""Sð‘bDd‹ìèáÈdu8Å…ˆÈÌ[ˆÈFÙÑ+)ÉŠ¨¶ðT$"2ó"²]VöRB²yLZˆˆLǼ…ˆlš–Qp॥¨¾êÞΩÍián!"2ó"²uúž0f3¤­1æf¢gW¤¤¤Œ3ÆÝÝÝÝÝ}̘1)))B¹B¡X´h‘···ÏâÅ‹[ ÔQ-dÞBDd4æ-Dd´§.ÊkGf6iâĉƒÎÎÎÎÊÊ4hФI“„ò>úèðáÃ.\8wî\BB§Ÿ~*¾N‰ITkPÔiÊ®Ùæ-DdtŽºXcö"„ªzM\QQñÌ3ÏxzzzzzΚ5«¢¢Bs«šššÅ‹wèСuëÖS¦L)--0f̘„„a…ß~ûí¡‡––ݶm[WW×qãÆåçç+Û]³f¿¿ÿÎ;׬YÓ®];ÿ½{÷*WX»v­ŸŸŸ»»ûŒ3*++ÅÄ Ù»>ø $$ÄÅÅ¥oß¾gÏžÕ³­æ®Puéҥŋ{yyy{{/Y²äÒ¥KBù矾råÊ€€€ÀÀÀU«Výç?ÿ·ã… QÓ`ÞBD¶Nß cV—½«^/Y²$''çòåË)))éé鯼òŠæV«W¯>uêTbbb^^^«V­^|ñEk×®•ÉdÕÕÕ .\¿~=€ &ÄÆÆæçççççwïÞ=..NYI^^^ffæªU«žx≼¼¼ŒŒŒU«V-X°@¹ÂÁƒÏž=›––výúõ×^{ML šöïßøðáâââèèè™3gêÙVsW¨Ĩ¨¨7ß|³¤¤¤¸¸xíÚµãÆÊÏŸ?ß¿a¹_¿~çÏŸ³ÛµRˆfrDDÔ ¹0o!";`xš¸u½[Cmâ»T*MHHœœ>>•••®®®Êewww™L&¬pùòåÎ;HII1bDVV–j´ºbPëZAAA»ví„Ö===«««õl«¶+TÌÎÎjÔ¨Ö­[?ñÄ<ò€×_}åÊ•ŽŽŽŽŽŽëׯðÙgŸÅÇÇ·iÓfäÈ‘÷ß¿Q >¼W¯^¡¡¡þþþË–-ƒHº¶UÛª¾úê«C‡:t諯¾ÊgÏž=dÈîÝ»÷èÑãþûïo|êk²3¯.]º0o!"­TóóFBPùºæØ Q hÔÛÜõ\†ŠŸýoì†ÖHÌà‰=°ØÁ:‹"üãǼ…ˆ´bÞb™„±¼57#nÓ¤g2ƒ±\WÞYD6Œ÷ļ…ˆô`ÞBDv®Q©‹’æ5¨˜ûìÔ©S›7oð¯ýkРAÓ¦M³¡Ùqj¾á{]ˆZFÓ<™ˆˆ,„®¹%ª—ãÊ¢‚ƒƒ …å7ntêÔIXsÇT~~¾ø«t5 @È[¸¹¹Éd2Ímýýýß~ûm¡ÅM›6Íž={çÎrssG @¡PÈårÕ[O•ý}ä‘GÖ®][\\¬P(þøã7ÞxC䆿ż…ˆH“¥¤.ÂË ù¢"¢о}ûÌÌLat%##£}ûöBy‡TË•ë;99UTT¸ºº¸y󦲼C‡j£.Æ6j”:¼ôÒKÊwíÚ gOOÏÈÈÈíÛ·+Š‘#GzxxˆÜÐŒ˜·iŹ.d)˜µµ˜èèèeË–¼öÚkÑÑÑBù?ÿùÏ×^{MY®\¿{÷îï¿ÿ~yyynnî‹/¾¨,‰‰yå•W®_¿~ëÖ-åúW¯^ߨO=õÔ±cÇ*++‹ŠŠ6mÚÔ³gO¡üÉ'ŸŒOOO—ÉdÉÉɺž¨6iÒ¤o¾ùfÛ¶m“&M2jC³`ÞBD¤ S2?áV >dŒ¨Å¼øâ‹¾¾¾C† :th@@À¢E‹„ò… ¶k×nàÀ#GŽ2dˆrýuëÖýúë¯Ýºu›0aÂàÁƒ•å ,5jÔ½÷Þ«¼ÓìÙgŸ7nœæë\t5*Æ´iÓÖ­[×­[·ÁƒŸ?~Ë–-BùsÏ=7hР‰'†……Í›7/**JëæÃ‡¿uëVii©²S"7lyÌ[ˆˆô°¬´8WÛnñÐ 8MŸÈž1o±^œ¦OÔ2,e® ‰¡9.a×úo!"bÞBDd%Þ0Æ Yñ$üéTƒ·êŽ5ó""=,+uQŽ!ðV?…B¡6Þ"Qa®¨L ŒVÙ#늟ˆ¨IC.Ì[ˆˆô³¬ÔÌ^ôRKW*TË­"‡QP3~sDDDdÌ[ˆˆD²Ä¹.Â;^ð5/â©î(奿j`Q{RWÒÂCODö†y ‘x7ê"àØ‹¯éõŘw—êlQ+ä¡'"›§œšODDbX⨋@õð°°Aó?"¡u(YAËì[åØ Ù0>RŒˆÈX–›º@%{˜FÓ3šÑÜÏ\66iQ;î<èDd{˜·™À¢Sh\pÛsÓT7Piî½fJfš*#böBD6†y ‘i,=uQR}r®þÉ6¦^C)æ_IœLXuà…ˆÈ–0o!"2™Õ¤.µW˜eÎF‹1WïÄ Ë˜\•QÛò¶1"²1Ì[ˆˆÃÊR®wÚL&ci1{`öBDÖy Q#Yeê"0x›“¥%Y]ÀÍMí¶1f/¶'00ÐÜ!P³ÈÉÉ1w–‹y ‘ɬ8uQcl&£gÛæ#òÎ+^ +1{±IÌXlžpˆ™À¨â«'‰ˆÏvR5b¦ž‹ü´%ñºÜ f/ÖN5oᥭ­Žr`` ±€y Q“°ÙÔEž‹ÝÎ[xÙm,ͧ1{±¼¢µmÂñ döæ-DDMÇ^R=xlù˜½‘•RNÍ'"¢Æs0wD&²œÛüHÿüóû÷ïWýôË/¿|òÉ'“’’233uÕpôèѽ{÷nÞ¼ùÒ¥KO?ýôµk×8°eË–¤¤¤ùóç«®™œœüå—_^¾|ùüùóO=õÔ»ï¾ûúë¯ëjnÚ´i¾ûî;å§ÿýï<úè£MÒq²jÊ).DDÔÜ$z®ÿˆ,Ÿž ÄàMexò'$$èÒ¥‹¹i.rrrÔÊ…ñ“_~ù¥OŸ>’’’¢¢¢(d§û÷ïïÖ­›Ú&ÊÛÆ„=\QQàÈ‘#!!!r¹<((ÈÁÁ!##CkTr¹¼S§NíÛ·OJJÒÚ\EEE¿~ýnß¾}òäI??¿[·nõéÓG&“>>§OŸvrâ+} °½'Œ1o!]ø„1¢–ÁQ"€/$Â;w,X°€y‹=cÞBDd.ü×—l‡Á¹™lâĉ‡öññY½zµ0é…ì0ä¼…ˆÈŒ˜ºMóJ]+H$¼Òl,ÿV±o¿ýÖÜ!9YBÞ"ÜWÙ–ÿ‹FD¤S²#BfÂì…ˆŒ¢œâÒŸ«¬É Y¦.dkte&ª9 o-#"‘Zrj¾á\¥‘ZÑøÚSk‘™ Y8¦.dƒ43ñc)x!"¥–É[ôe,Mûm¤V›îL†9 Y&¦.dãtå!¼mŒˆôkî¼E{ÆÒ’ß=º3æ0Dd™˜ºm2ýo#"]š)o1º¢‡ju_ª3!"³cêB6KÌȉ®ì…/Dö¬9ò-I‹%Ç(cÓŠaCDfÄÔ…ì³"RÕäy‹zÒb]ß+9 "2#¦.D¼sŒˆj5mÞbÝI‹!x&0DdVL]ˆÙ ^ˆìS#ó›ÊXÔ4„ál~"jaL]ˆj1{!²sÂKcò[NZÔp†ˆÌÁÁÜYf)Dv«‰ó…Mç-JvÒM"²L]ˆÐÌ^8 †Èæ5>oQ'ÑòÂGd'Ý$"‹ÁÔ…HÇ^ˆlX`‚T9_YÒ” ¨½ÅV¯ìm¸kDdÁ˜ºÆ"£LWšåՓІwRIlèB_­/ Þ3FD-ŠÓô‰´Ðœ²/~¾¾Eå9œ5«¤ý-æ†Ç«%©¶4eÞ¢ªá\öÚ+½ÐWûb³Ò^‘•cêB¤_öbí¬"WQ£3“™¦¥õÞ°æÊ[”¬=aÒBDƒ© ‘NjÙ‹qJV{uËüc¯Ú–}§]Z󖜜œ–Ä(j%R©”ًКÀÀ‚3Íï‹ •ˆìS"}•½™(óËÏUÔ¨,d2Ì^š[`‚´Ù^”Ôþ¨‹„á0 Y*NÓ'2€¹Šu±Þ¼E“ tÁ¢èy’X?dL …¶g‘™w°T3NÁ'" ÃÔ…È0Õì…`¬/úÉXfÈ^ í ]½ÿ5’ÈÊùÜ0"²TL]ˆDaöBf!ä`ÖøÈë’™Ýr÷Œi%2UП{ü¯©Â "2Îu!‹Ï#²^æy¶˜±ô§ MòõÃÌ„ˆ¬S"#(³Î×'²j—´ˆÁ¯"²{L]ˆLÄì…ÈêXeÆBDDu˜º‡·Y#&-DD6€Óô‰Œ¦laCDDDÔb8êBd Nz¡f±ãë2‰ˆ¨ÅpÔ…ÈDMŸ±¤cwÀ¤([Þ€°˜SuɲXlNEDD¶‡£.D¦Æ^šlàe"ð0ð Þ&‰€€ÃÀ@< | ÌUßÒ¥K?úè£&¬é,[¶ÌÜ!XK~½f`` ¹C "";ÂÔ…¨QšrÖþ%à8Ð °x»®üs`%X¼&6u!²ÉŸgÍš¥Y•øÂntéÒ¥° Ë—-7¹u""Òƒ7Œ5V£†\T³ž(àM (ÖãêÊÏýë–ûçMoˆˆˆÈzqÔ…Èb¼ ^„GêÊïmê–Û·ÍQ˳®!e£r!"j>L]ˆÌJuÀf0 ˆ¼ LöÚwÀm ­Øº—/_níO2y 8ç`˜Æ’çÕñ¹®DM¬vê‹òK¸%LÌï™+PR7×¥ð*ƒ•ÀÀïÀkÀa]m«´%,ïÁµBF!þú˜O¯2 ñH8 ºN3c·µ«=]ÍûªÄ¤À‹ÀÇ€˜ ¬nx/«Èv-ï §%¥¤¤ˆŒŒ4w D6Žs]ˆÌJõú °(Š7€žuåO¯×` 0½å£47ÿk©ÿÈÚ™v•1<$Ÿ6mLDDM†© ‘Åø 8À!ૺòÙÀ ;иø?sÆHDMl7ÐpBå$`1Ðh LJëÊ%À UœUùkH5°ð¼w U«|Œa ° øOsö—ˆ¨˜º™•êŸH»û2  Øt­+—뀛ÀMà ãoä°fµ÷ŸØS—ÍLp¦P { XÜ'ë W§€D h¼¨²þ PÀu…¿Þ@o•Õ–ç€D È0T-cHDV‚© ‘ù´²< ø¸®ðS`Ðh ¼lWYÿm =`ðI]á'ÀŒ†Õ~l:ÞÀCÕò1†Dd%˜º‘EãÀ‹Ypà¥ålöý€ `g]a6Ðp _eý€º…©À/@Pü LiXíuà.¶tU+<ÆP`Ìc ‰ˆZS""RÁÉú-l° ¸|<[W¤2 Prmz__Q€WÃO€TMtUÛ8U·üУÑ""jL]ˆÈJpà…lÒdàPÈšºÂ9À3À@œ×QQîûTãn1Ó€y@P Ī–1$"+ÁÔ…ˆ,=¿,Â<8Y¿%= <¸/[ë _†£€ÖÀÀ#:¶ ”wêÞû¤j)ôîB UËÇ‘•p2wDDDvl0I£ÐX ,Ö(Wh¬–¡cg`ƒÊ}ýÕ 1\gDÔDDfÁQ"²本oÇ7ªqà…ˆˆ, S"²‰@ë©Ö´dI,¼`q£gÛs²>Y¦.Dd5ðòðP“FÓ¬Õš–6|.ç€àÓ¦‰ˆˆÈü˜º5IÝj?6ëªm‘ªŸ‡€pà pr—€p@ °è´¦¥*›¯üw`P©Q-€Ý@OÀ>ªûTW…`H€Î*‰ŠΪ¾j`à xïªös`%«€ÿhÛi@4ÐpÆ5|[ˆ&NÖ'"" ÃÔ…ˆ¬±‰Y> Æ €Ÿ€VÀO€?€(Àjàä­€Uj8œÒ€ëÀkÕx XÜ'ëVÐSá PÀu…¿Þ@o•Õ–ç€D Ue6¶®jÏýë–ûçµíŠ @,äÝ8Ã;ˆˆÈrH ÞÑLd)téÒó',‚ð'üœœ“kJ¥€‘·TýøøØ |lÆ= ÀÀDài`,ü\÷2¾<  —΀`Õ°ZÁ@ðO H¥]=æÔ½}pø0ü Ôu°°_c:®j꺿GÉ@¦w·”!†^ê²D]‡L8 ºž^ÝøÃm]L99m†°ï瘧¤¤ˆŒŒ4w D6Ž£.Ddë~Æ"@p X Ê€@$ è8Ž€Ãkzåk1îò4ª°Øô‚€u…z* ¨[˜ ü…À¯o¼Ü¥Ñ]Õ¶îÔ-ßÚÖ-«ÞOx´$€;P {§ ìó*œˆˆ,S"²&FOÖ¯ö×Ýæt6ý/ °ˆ\!í{· IDAT@: j W©$­n!ðרÀ`pøx¶®PO…JÞÀƒÀ—À—@àÕðÓ Uc]ÕöNÕ-ÿU7,@Q÷€`.Èf&DDde˜º‘M;t:Ôý8XŒŒÖãê>š<\dÀù† óëæ‡ÄSµU;¸Tr FD…ªfŸŸ34>šÌ²€b ÖPµO¯×` 0][[å€ à¤³tÄ£†“õ‰ˆÈb0u!"+cÜÀ‹êm]Æ7Q€Ñ@‰Jêò0´žQÙj8Ð üeÚª}xp^¶Š¨P•Æ`„ÆGK p—ÊMkºª º=€ûÿÓÖÖg@<Ð ܯ#"""KÅiúD„ÓôE2b>tà[àžF6ØRÕZ,  íÀqš¾šÚ3vv3žÝÏѧéµ's@Dd*‰ˆ Ä”æiº™ª%›!Œ Ú|£2ø)•Jí<{!¢ÀÔ…ˆ¬OvvvýŸ·‰,†pí^rÚpÓðŽM&-DÔ2˜º‘! @‚ÀÀ@»ºûËdÊëøÚFy•o9 3"2+NÓ'"«dôS’‰Z\vvvƒ‹{‰5Ÿ± ƒWïQ‹à¨ ‰ÀSYý]di!"‹ÁÔ…ˆ¬UíŒ1“õ‰ÌM{ >{5ˆ˜´‘Ù1u!""#pà¥1Ô§ÁÀ"a8ÌBD–Š© Y?¼´ …5OÕ°0–8Ãa"²xL]ˆÈŠñ)ÉdÕtÂèÒÈÄF\æÉŒ…ˆ,S""“õ›‡ú Œ.Í<êŤ…ˆ,S"²nœ¬O6CæÐ$ŒLNˆÈª1u!""£qà¥å™–u&HäD2c!"[ÀWR‘Õãë)[G·ˆˆÈL˜º‘`êBD6„/-C掃ˆˆì S"²œ|LDDd󘺑`êBD6‚“õ['ëQ‹cêBDDDDDV€© Ù¼´(¼QËâ+)‰È1{!""²9u!""ÓñÙnDDÔb8êBD6…WÒDDD¶Š£.DDDDDd˜º‘`êBDDDDDV€© Y¦.DDDDDd˜ºQËÉÉÉhî@ˆˆˆÈú0u!"""""+À÷º‘pàÅNãlDDDM‚£.DÔ¢x-k?x¬‰ˆ¨iqÔ…ˆZ¯h‰ˆˆÈu!"""""+ÀÔ…ˆˆˆˆˆ¬S"""""²L]ˆˆˆˆˆÈ 0u!""²#¹¹¹³fÍŠˆˆ ŽŽÞ·oŸP.•J›°• .L:5<<¼oß¾Û¶mkš‰Èž1u!""²#sæÌ ;zôhrrr||üçŸÞäM¤¦¦NŸ>}êÔ©gÏžýñÇÿüóÏ&o‚ˆìS""";rúô騨Xooo—!C†lݺuC.R©T9öRSS³fÍšÞ½{‡……Í;·¬¬L(—J¥›7oîÓ§OçÎãâ⪪ª4›xûí·ãâ⢢¢ÜÜܤRéúõë[ªsDd㘺Ù‘Þ½{¿õÖ[ª…ÙÙÙÂÿ…7nLJJÚ³gORR’‹‹ËªU«”+?~ü·ß~;~üx~~þºuë4›8räH~~þ=÷ÜÓ¹sçÙ³g—””åM{OÙ!¦.DDDväã?¾yóæÃ?ñÜsÏåååi]í›o¾Y¾|y@@@›6m^~ùåŸþYùÑŠ+|}}Û·oÿúë¯ÿðÚÛ]½zõ÷ßÿ믿ÜÜÜ^z饿ê Ù's@DDD-Çßßÿí·ßŸŸ¿iÓ¦Ù³gïܹSsµÜÜÜÑ£GP(r¹\"‘(?êÔ©“°TPP ¹mëÖ­—/_îåå`Ù²eÊ•C:DD¦aêBDDd:tèðÒK/EDDèút×®]šeff†„„ÈÈÈðõõÕ\¡k×®ª©Žê2Qcð†1""";òÔSO;v¬²²²¨¨hÓ¦M={öÊ=<<®^½ª\íÉ'ŸŒOOO—ÉdÉÉÉsçÎU~ôÚk¯¼öÚk<òˆf?þøÒ¥K‹‹‹oݺµbÅŠQ£F åœëBDÄÔ…ˆˆÈŽL›6mݺuݺu™ˆZN`` ¹C f‘““cÈö1u!¢fÇŒÅæ ‡˜ 5+¦.DÔ¼Tó^ÚÚ*á(òSsã#ΈìçºQKÈÉÉáE­ S_ްY…?þøc̘1!!!Æ Û¾}{s4!•J¥Ripppß¾}çÌ™sþüy1›4G$DdK˜ºÙ‘ÄÄĸ¸¸—_~ùòåË[·n=räH35”––¶{÷îÆÄÄœ={¶™""ûÁÔ…ˆš§@Yš7¾üòË‘‘‘ÎÎÎÁÁÁëׯÊ+++ããã»uëÖ­[·E‹UVV åR©tóæÍ}úôéܹs\\\UUUIII¯^½ŠŠŠ„d2YïÞ½ 5Ûrppðóó›1cF||ü† „ÂŒŒŒ3ftéÒ%44ô‰'ž(((@Ý‹0V£g5Z<ú×ÿý÷ßGŒtèPffæÚµk•?~ü·ß~;~üx~~þºuë<==£££¿üòKáÓÇßsÏ=íÚµÓÓèøñãOž<),OŸ>}æÌ™gÏž={ölxxøòåËQ÷Ìåììlå<­«iGÿú±±± ,¸|ùò?ü””$nܸ1))iÏž=III...«V­2z?‘9H …¹c ¢Z ºtébî@š G]ì · Lȉ¬Ÿ×”––æè訶fß¾}wìØ àêÕ«111‰‰‰¤Ré‘#GBBB¤¦¦ÆÄÄüõ×_>úè±cÇœœœ^|ñÅ¡C‡N˜0Aµ6µÉô2™,,,ìÚµkj–——4H¸—LÏü{µÕ4ãѳþÀgÍš5nÜ8Õ¹4ƒ úâ‹/ºví àÆ£G>sæŒþ=©_JJ €ÈÈÈÆTBDqÔ…ˆˆÈŽxxxk– ËÁÁÁª7€ý{wÓ½ÿqü3DBTBí  ‚h£µÖšKÕµ´U[,[JQb)ê¡H©­ªåR×OÛ‹*-Õ{«¥ºXbßiÕ¡¤H©„,óû㤓1[f’ÉÌ™™×óáÉwΜïçÌŒä¼çûýž©Zµªr#((H™ˆÔ Aƒ 6dggïÛ·ïÅ_´Üé7üýý•ÛGíÚµkÍš5kÔ¨¡›xfÀÂfÆõXØ~Ù²e»wïþç?ÿÙ¨Q£üQi¼zõj»ví‚‚‚ªV­Z¿~}ýÙhÔŒè€iԨѶmÛŒÛË•+wéÒ%åöŋ˕+§»K¿½|ùòÊíaÆ}öÙg‡nܸ±åN7mÚÔ¸qcåö!C päȑ˗/ÇÇÇ››ýaa3“õ˜Û¾~ýú+V¬øý÷ßçÎ;iÒ$¥±B… ¸xñâ¥K—’’’._¾l¹~*AtÀƒŒ1bÖ¬Y;vìÈÈÈøóÏ?ÇŒ£´wéÒ%66ö¯¿þJMM:uj—.]t™:ujjjªÒÞµkW¥1<<Ü××wæÌ™Ýºu3×WvvvJJÊòåËçÏŸ?zôh¥1==½X±bÅ‹¿téÒ„ tûùùýñǺÍmf®sÛ>œ6mÚ3Ï<£\ŒHiÜ´iÓË/¿üÔSO)Se.\¸`M=ù¨poaaaƒ®X±¢³kàAˆ.œãÌ™3«V­:{öìÉ“'£¢¢.\8}útãÍt3Uô¿«nß¾}={öÌÌÌܾ}ûï¿ÿ6tèÐõë×ë?pÕªUýúõûí·ßt#‘%K–|øá‡ñññcƌٱcÇ›o¾iM=ù®p&g‹%%%]¼x1**Êñõðd¬uTÄc׺dggW­Zµ\¹rÊw]ç¹Ö¥[·nû÷ïߺukíÚµEäÖ­[aaaO=õÔ®]»tÛëîÕßÉ/¿üR·n]yðàAÍš5‹-zñâÅ<ëÉG ž‰µ.*Tðµ.°k]Ç`­ '¸víÚœ9svíÚuýúõÌÌL¥Qÿ+ð,SEÛ¶mõ ¾¨ÛdT¾<[D|}}EDw¥Ô|ÔcM ÀŽˆ.œà7Þ8xðà¸q㢣£ýüü²²²‚‚‚lŽ/Uª”¹{‹11!¶hÑ¢ö­Çr €ã)Ã,–„à¢XëÀ Ž;&"#FŒðóó‘_ýÕ¦‡×¯__DöïßïÄzì^`ÄnŒèÀ ”óþ•+W¦§§Ÿ>}ZÿKîŒ=ùä“"röìY]Ë„ Š+öî»ïž:u*33óÊ•+ß|óÍ«¯¾Zxõ8 À1È6\Ñ€,]º´C‡|ðA:ubbbbbb,l}ú’%KìÞŰaÃJ–,yùòåøøøóçÏ/_¾ÜÂÆÚ¿Ü.¸ýû÷4hΜ9wïÞýᇶoßn—ÝpªÍT*gò‚¿Ícÿ܉åCãòÇì‚èbÚÁƒßyç²eËúøø´iÓfóæÍò÷ЇF£ÑdeeMš4©B… ¾¾¾}úô¹ÿ¾Ò®ÑhæÎ[±bÅ’%K4èáÇÆ]lÚ´éÃ?,S¦LÙ²e,XðŸÿüǦ Íu½yóæzõêy{{/[¶ÌdÙúfÏž={öìöíÛ{{{‡„„è'¨¥K—{{{?÷ÜsÇW/\¸Ð¥K—R¥J/^¼C‡)))ºC6¹}ZZZÿþýK–,Y©R¥yóæåùÔ׸½dsösãòt_Zâ~IÆš¬Âw¶°/¢‹i 4˜6mÚ… ôõ=”–Y³f>|øèÑ£×®]óññ™8q¢nã;w?~üÂ… W®\™:uªqÃ&'NœPnXù=îæºŽŠŠŠ½{÷îÎ;:d²l}{÷îíСƒÉ.¶nݺ{÷î[·nuéÒ%::Zi|饗bbbRRRRRRêÖ­;vìXËÛO™2åæÍ›‰‰‰Çß¹sg>ê·aS’QUžÉ³0² `)¶iIIIS§NݼysZZZÇŽçÍ› F‹F‚ƒƒ7mÚ&"×®] ¿zõª²ÙÙ³gkÔ¨!" mÚ´¹|ù²AÝ»w÷÷÷Ÿ?~vvö[o½µjÕªŒŒ ã. èî5×uµjÕÆŽûꫯ?ʘ——×Ç‹-jÜQjjjÙ²eEäÁƒþþþJyúsæÌÌ™3׬Y£Ü5zôheå}LLLß¾}»ˆŽŽŽ-[¶ì/¿üûã?*íV^Ù\×½{÷ž2eJ5²³³³²²L–­oâĉݻw¯\¹rDDÄ¥K—Þ{ï=Ë×:KKKóöö.Q¢Dbbâ¤I“ò¬³W¯^cÆŒùÏþ£ÕjõÆØT¡³b ™M"#å•WdÝ:ÑjåÃ¥W/9zTDdÙ2Ù½[N­Vºu“Ï>eM¹vƒ¯º³Õ´iÓÔp©Ëþ†ƒ¹}º¸1¢‹iÆ ›2eÊÁƒ}||Zµjõå—_*ío½õVÆ ïÝ»§¤‹·ß~[£Ñ¼ð ÉÉÉaaa“'OÖí¡U«VO?ýô½{÷zöìiòÔ­qãÆ5ºsçNóæÍÿûßÿšÌ˜ëZEùã?j×®ýÅ_˜,[_³fÍ>ýôÓ &œ>}:((èwÞ±ÜïòåËnjӳgϪU«Ž?~íÚµ–·Ÿ1cÆÐ¡Cƒ‚‚J•*5fÌ]B³©þÇÞ,/û˜øxÙ¿_||DD&O–ùósÚW®”÷Þ“Ê•EDfΔ©Ss"йvÏÁÇØã€ÌC† qdw'bÂX¡à«èMŠïرãùóç ´‡,PÑô±q˜F“{W·nR¿¾Œ%Z­,\(ÇË7߈ˆøûË¥Kâç'"rû¶ËÍ›–Ú÷l¶`SƦM›fűºØØØ<'ŒñßÅa”·Šõ£.¶Nó„A¶ØØw]‚;c uA¡5jTllì£GÆߥK—‚î®à£"–òÿ¾ Hÿú—4k&Ê5±«WÏYô""÷îÉOäÜ.UJîÞÍ£Ý$%%ZÏ`Z­h4Àœ1€Ë!º Ð…††Ö©SçÁƒ/¿üòôéÓ]Žy EúgÞƒIÿþ¢,í™?_ Ÿ~yâ ¹w/gtåî])U*g{síôî»ï:ý“Kå3{Àm¼ûî»0°*Et)ÌÓ7bĈ#F8» ‹ì·@_±c‡|÷]îZ—Ò¥sÚÃÂäðaiÓFDäÈ Ë£ÝC0ðâ…4ðby~`aPõ(ŽAtg³_hÑ?ó “Ù³eôh‘ ¤^½œö¨(yçùæÑjeòd<8v 0(sÆÜ†#—és-op.¾’žªÖîƒ-:«WË®] ²k—è¾°gèPiÞ\êÖ•°0iÝ:7¢˜k×hr¿àÅÎ5Íñ„cùÆ…° ø•”Žçº_I©Ã¥ÆÌÊKñ•”úx—:€J~wÙŠ+ŒŽÁ¨ @t  ʇ¬N™3æNÕl=.›¸Ó®ˆèÀ=*µj¹Ìnówþ§ÕÊ„ R¦Œ<ù¤LšTÐiKÌzrcjxƒ@a ºP‹‚ ¼lÜ(;Û¹žÂÛmþN —-“Ý»åÔ)9qBââä³Ïì]Üo0îŠèÀlÚ$;KÍš/"rñ¢)"Êrñøx©YSD$+K&M’ Ä×Wúô‘û÷s>w®T¬(%KÊ Aòð¡ánEdóf©WO¼½%8Xtß#bn‡,X AA¢ÑH¹ç‘Z­„„Èñã¹ñ,#CÆ“òå¥LùðÃ-Å‹K±b9»Õj%;[4ÉÎÑh$3SŠÉÌ”%$#ã±ÝŠÈ¡C2c†ìÛ'%JÈ¿þ%]ºˆˆ¥êê¿ySªW—óçE«•5äÂ)]:w//IO/¯ÇÇÜnýýåÒ%ñó¹}[‚ƒåæÍœîZ­Ùc±Àò¼]ô^tqã7˜­Tò»ËVDÀ1˜0@]l]¬Ÿ‘![·æL +QBBCåã¥A)]Z4E‹¤N)^\D¤reIL”ÌLÉÊÊ9iÓ¹p!çÆùóR©’ánE¤Q#ùî;¹~]þïÿdذœF ;Ô)SFÚ·—U«dÕ*éØQJ—~ìÞÊ•åüyǘÛmX˜>œsûÈ‘œOÍED«ÍùgîX ~¼ÁÀDÀ,æ±&Uòϸ6ϱs§„†J… 9?vè ³gK»v""/¾(³gK‡9w½ñ†¼þºœ;'™™rò¤ôé“»“Ñ£%%ERR$&Fúö5±ÛÞ½åÔ)yôH²³%++ïê4H>ýT>ûL 2¼«9R._–[·$&&ÝFEÉ;ïÈ•+’œ,“'ç 3>ËX¬¯nü;"ºP›^6n”NrìÐAnÞ”^i×NnßÎ.o¿-­ZÉ /ˆ¯¯¼öštíšû¨V­äé§¥zu©TIbcMìö•W¤kW)YRÞ~[¾ø"ïêSʸwOÚ´1¼kÚ4©SGÂÃå©§¤zõ,`"¢ õRV¼X³Xfœat\qM¿ñQ¸Ü!€' ºcyàÅ€É £ÛE3sá@…XëÀ°âÅ1 2º¥‹(&—Ĩ|aŒ5ùÊE3¸F]¨WIvEW$3yÛxK5s•:À½]¹¬Y¬os1Æ\‹8$'Ø4Dn• ºP;ë» ã `2B¨jj™~ͺ·¢‚7¤}éžXåÂè`Œè0ÁŽ/˜Ðp@t±²_Ëã-d»0^ÉHz`Ñ€ `àÅ‘”9cN¤’ Z&ËÐ?¥Ö­Â"Ãäƒñ{Œ¸ ODDD’#’t/ÖÄ'Ý©6Æz$AtàJxq Ýb}gâ¶ûXÈ0BŒ1sqs €| ºp \%PÀ¹jÆF<5Ƙ›sHbPDìÌd†£zwJ2–×G‘XØÑ€Ë`±¾#9}±¾{08ew§$CVàxDÀãÖˆˆH'Wá–lJ2 •ä™ÏXÿ¢W8Ñ€K┺ðhWÿ}k3Ëð4&c€My¦P‘R¨Ñ`–vµZ¾ Ò3Ù”g »_p:¢ ÃIU¡‹{ìÌ8 .ô¢*üొ8»€ÚÄñ:ç#ºr™K)¤€Ó]V!½œ‹è°éàD,Óä•ú§#º,!´T‚ cCÉIÊ?a’@5uäbŒ ZŒºòÀÀ @ ˆ.³„¨Ñ@!JNN‘€€g‚‚bààtD€% ¼T‚eú×ÖG+"Ö¼„Ê8…Q…‹sYÏÁk (TŒº(tœÑºe­ “ÇNĨ o|=%Àéˆ.\Æ6ˆ dÚ qqqÎ.Á³DDD8»OGtX%9"‰ c€XœEyæ 0NDt؆À‰ôsK­ZµœWˆ'JHH‘¸¸8Ò‹³°Ö`-  µjÕ"·8žîigàËYˆ.›1s àxD€ xœHù°Ÿñx,¢ ?x8Ñ`^NAtä/G"ºlÆÀ Àñø^n"0ÐF’’Ü팟ïx8 £.\Uàãœ]ŽU8»¢ü#±¨JÞB*)ÃsüùçŸ={ö¬^½zÓ¦M×®]+ÿniÕªÕ?þ¨Üþè£ÂÂÂ\ý÷ `€Q.ÉäãäädÇWb“€€ƒ–ÀÀ@׊IŽH ˆ tØÀËÕ«W§Nºk×®ôôôððð#F´k×Nìúž?~òäɇ‘FÍœ9ó©§ž²°½q×j~A•ÿ5^^^eË–mܸñÈ‘#ÃÂÂò|ˆjG‘ [·n••µ{÷ný(7J–,Ù¨Q£3f(¯{``àûï¿ß·o_Ý–Û¶mëׯŸÓŸ“#FôîÝ{ÕªU[¶l2dHddd\\\¯^½¶lÙ’‘‘Q¶lÙ 6´k×náÂ…:urn©€}1êÀõèÎ3’çܪ¬a²`>µÒo¼²wïÞ3gÎŒ?~åÊ•…ÑEÆ =zäÈ‘gŸ}vذavï¹’’’.\¸°yóæÆ÷èÑãøñãή¨ lMÇŽËÌÌôöö>räˆÁ~’’’öïßÿÌ3ÏŒ1B×¾fÍš¬¬,ÝK–,)`Ávñûï¿wëÖÍÇǧS§NÊ3P³fÍæÍ›¯[·nõêÕ/¼ðBõêÕ.\øÑGµk×îçŸvv½€Ý]¸ýÜâÜJ Î!"Iu©±cÇŽÅÄÄ”)SÆÛÛ»yóæ_|ñ…üý~П“••5{öìgžy&$$dĈrV>2WZ-ZôÛo¿ýôÓO¿ýö›··÷Ì™3uï߿˖-û÷ïOII™7ožqmÛ¶]²dÉÝ»wïܹóñÇ·iÓFiÏßȘÉîÞÿýÛ·o8p@¹Kû_ýõ§Ÿ~RpÀ€ÑÑÑÇ?~üxÍš5ß}÷]ÝÃÿúë¯üòË/{öìÑ=ÖÂQ›Ó©S'ejœ¹îŒŸ[sU™;XsÛÇÄÄŒ7îìÙ³ÿýïûí7k¡nݺ¥J•Ú»w¯òãž={üýýëÔ©£ÛÀBm:=úþûï»uëÖ­[·M›6Ç×7n,X° nݺú»ýøãµZ­V«ýð㣣ó|b`Ñ¢EëÖ­ yúé§çΫ47jÔ¨uëÖU«V•¿3ç°aÆîÔb{Òè>Ààtqqq"R«V-g¢jÊI¤;EeŒÓgÏ„2êRØ+^®^½:oÞ¼mÛ¶¥§§·mÛvÊ”)+V£ÕMš4ùüóÏ•Oǯ_¿Þ®]»_ýUÙlÏž=ÁÁÁ"rþüù=zLRºxùå—•½mذ¡B… Æ]èXXëb®» ü÷¿ÿ­V­šˆ$&&6oÞ\·ý±cÇ”î ¤¥¥5iÒD™ÜÕ Aƒo¾ùF·Û–-[*7wÔªÍÌÌ ùóÏ?-tga%‰Áfy>·úÛ7nÜxÈ!:tÐÏ„yÂòåË>üñÇ‹ÈðáÛ4iÒ¿“ê÷¥oÓ¦M+V¬øúë¯E¤wïÞ}ûöíܹ³èES__߆ Θ1£FºÃïß¿dd¤ˆ|õÕWŸþ¹ÉD$""ÂäseGü™P‡½Ü0Æ2}€}özýJ•*ÍŸ?_DRRR/^Xj4šììì"Er¦0deeén›ëîúõëUªTQnën(ôsËÑ£Gß{ï½ßÿ]™7¥;ŠëׯëïÖš£6çÆþþþ–»3`a3“knûeË–-X°`áÂ…Å‹Ÿ1cÆ?ÿùOk¡k×®sçνuë–V«Ý¾}ûœ9s¬¬MG™-¦ÜîѣǺuë”è"?;8pàœ9s233§M›fnŽÁ„1@A9øBÉ*Txûí·;fîÞ\¼xñÒ¥KIII—/_ÖÝuéÒ%åÆÅ‹Ë—/oüØ}ûöÅÄÄøùùùùùÅÄÄìÛ·Ïr%+VLLLÔý˜˜˜¨ Yè®\¹rº’ôk30dÈ9räòåËñññº)*TÐß­5GmΦM›7nl¹;+«2w°æ¶¯_¿þŠ+~ÿý÷¹sçNš4ÉÊCð÷÷ˆˆX¿~ýúõëÛ¶mëççgemŠÔÔÔ¸¸¸Ñ£G+3©F޹cÇŽëׯçùDµnÝúþýûZ­¶eË–yn  P]vS¨ëõ£¢¢öíÛ÷ðáÃ7n,^¼¸^½zJ»ŸŸßü¡Û¬_¿~ãÇOLLÌÌÌûì/^l¹¤ &Ô®]»k×®Õ«WïÚµk½zõÞzë-ËÝM˜0ÁÏϯQ£FmÚ´iذ¡——é™Û}ôÑŒ3jÖ¬ùüóÏëÚßzë-å[YÚ¶mÛ¼ys]»…£Öܾ}û|ýõ׺øg®;ƒçÖÜfæÖÜöíÛ·ŽŽ®Q£Æ¬Y³-Zdý!´jÕêÎ;÷ïß×?ö\å[µ«]ÇÐôuB§*¼Úà–TûõP®ÈUþ€zF]……İ#F]³ †”«Õ9>`\›S>\χ¤¤¤ÀÀ@M_•>±îG»Z4}% ÀÁ‹^xF«Õš»K™S`aˆͼpKD€#^ÇÈóÌ›Ss¸.&Œp2e>±« ¹ G^¢Ä° ¢ x§ÌÍãjc€ÃhÍËsh™M§nDjÁÀ‹' ½òèÀù¸¥ƒ)/þZOÝ´1Ò ˆ.aÑ   ˆ.TA…‹õUUL!qðÀ‹°èPDîìh¢ÔçèÝ0ó8&29ý‹tH/[]¨Ea ¼l<*Ÿµç u· §‡ŠÂÆ¢@þ]¸³M¿Jçg¥æX‰O¹ø—yM’oŠˆÄ'Kͱ""YÙ2i­T&¾¥ÏÇrÿaîÃç~/‡IÉ2h™<Ì0Ü­ˆlþMêMï( Ž‘eÛDþŽ^š¾¹ìÂuéò¡”,ÅH‡÷%åNN{Ú#é¿TJ”JÃeÞÆÜíõo,Ý*Á1â%ÏM–ãóx ­œ²X_Á¢@>]ûK¸"/Α’¥ä@yqŽ$\Éi×je—RæuyrˆLZ+ºkÇÛÚîöì5ð’rG®HËÚÒ¡¾ÄÙxT|¼dã1‘í§¤c}‘Yäðy9:S®ý[|¼dâ—¹{Ø/ÇçÈ……rå–L]o¸[‰ú·Äv“»ŸÉΩrè¼Èßy@»:wðä¥$柒òoIù·Ô ”±_ä´OùZnÞ—Ä…r|ŽìŒ7}[OÈîirëSéÒ@¢?±áêÇ¢€­ˆ.€ýE.’f5%éc¹¼Xš„H¯Å9í˶Éî3rjžœ˜+q§ä³¸|¶»1û^%ù‡_å…zR¬¨t—¸S""›~•Qíåû£""q§¥C¸ˆÈgq² ŸTyRJ—9½dýÁÜ=,Œ’ŠþRÁOö“Õ{ w+"¾Þ’tC®Ý‘ ²òI´é2N̕ԕÞâWBfôŸÏiÿjŸ|ôš”÷“ ~òQ?Ó]:Xª<)¾ÞòVg9ö§ ´‰S^r{'½¬Ctì/>Y&½,¥}¥LI™Ü%gª’ˆ¬Ü%ïõÊ¥% ŒÌì)+væ³VÚxL:=+"QGþ!ɾ³2éÙ{V<’ƒHD]‘¤›>I¼úIÑפÒðÜ ]"R½|Χ*ȵ;†»‘õ£eëIi0Y‚FÉ·‡M—±ÿœ´š.O M_)9PRïæ´_½-Áï?¸œéÇ–}"熯·dfÙð@+9w] ‹^Ø‹F£qv p¢ `úsœ:Ö—÷7ÊírëÌý>ç£}9yY>•s»Au9y9ŸíîÍ^‹õ3²d뉜)a%¼%4@>þYT—Ò¾Ò º,úIêHñb""•KKâBÉ\%Y_ˆvµd‘»“ ×snœO‘Jþ†»‘FOÉwãäúRù¿Á2l¹éJz,”/ÊåÅ’ý…Üþ4wâ_EIü{ÿ‰©6Z¾¨B,zÔãÌ™3ÁÁÁèH?fØ«S­u“ª“’’Z´háããÓ¢E ¾ Ù]ûûWùt»”~]ʼ.+wÊâ9í÷Òå‰â9·K•»éùl‡5vÆKh€TðËù±C¸ÌþNÚ=-"òâÓ2û»ÜHùF[yýS9wM2³ääeéóqîNF¯’”;’rGbVIßæ&vÛ{±œJ’G™’-YÙ9¥}å̕ܤ=o/)QLSeȧ¹í½ž—1_Hê]¹~'wŒ5òý@“œ¸X_Á¢@%vìØÑªU+÷îô­·ÞjÙ²åíÛ·[´h1~üx‡õ {!ºö¡?ñfÐÿIÿVró¹ù‰ôm.–æ´?Q\îý?î¦I©âùlw{vxÙxT:ÕÏý±C¸Ü¼//Ôi÷´Ü~ þ¾÷í—¥Umya–ø”×–H×F¹jU[žž(Õc¤’¿Äv3±ÛWHפä yû+ùbxNã[¤á;¹õ/*ã×ȃ¥íLi]'÷±3zˆ¿¯’z¥YÍœÅ3ÖÈ÷UŽô8׎;Z·n-"ÇŽ{î¹ç¼¼¼4Í™3gÒÒÒD$--- !!áÝwß-_¾¼F£QÆO4ͨQ£¼½½EäÈ‘#áááÅŠ ?vì˜q‹î!Ê ]§û<}út³fͼ½½CCC÷ì٣ߋɒ”GéWnr'[¶l=ztñâÅÇŒóË/¿8ãiF]ûÛ/“_‘Ò¾RÚW&w‘_*¬Š>ŸsûÈ «’ÏvXCwýbEÍJ¢]-Ï‹ˆ„‰vµÔ¨˜sWLzYÊ£ÏåØ,éÞ8§]»Z&t–kÿ–ûËeùМÙe»íõ¼Ä ŸËïsåŧs'w‘»Ÿé]aì99÷¡d|.çȰrÛ}½eÕ0y°\®ý[º4”*OæökpÃàGsÌ7• ¼ép*ÝÈ€ú÷ïÿþ}­VÚ¸qãO>ùDD–-[Ö´iÓZµjÍ›7ïƒ>HOO×MÓjР’%}ëÖ­èèè·(ÑjµÊ ]§ûŒŠŠ2dÈÝ»w,X0xð`ý^L–¤l _¹Éܸq£|ùò"R®\¹›7o:ì¹…½h¬œxåÓƒGåCtsËš5}sïj0Y^zNFwY°Y6“Ã,Ý*Ÿï’oF‹V+ÝÈà‰þG~ÚMönP›ÒâºysNaÝûûG}.±]åQ¦¼þ©Ô¬$¾Vè4GyÃ$''´+yÆ1o$]na \NBB‚ˆDDDvGqqq"¢;S7 üæ´pj—ó×ÍÔüñGË–-•_ÅŠ»}û¶¯¯¯r×Þ½{###O:U§No¾ù¦I“&k×®ý׿þ?|øð3fh4šŒŒ ///å±wîÜ)Q¢Äƒüýý322Œ[4šœóOýN öY¬X±ÌÌL]ÙÙÙÙú½—¤ìÓ rã”+WîäÉ“+V¼víZ½zõ®_¿.F”gÉÂï=‡½Ü0ƨ `«GÈ®30BFÈ®3²zDNûÐ6Ò¼–Ô/a¤u‘ÏvOມË&¡•¥Îx©9NüJÈôîŽx š1ö8‘þš“ºuë~òÉ'æ|Ao³fÍ‚‚‚:uêÒ¤I‰ŒŒÜ³gÏ/¿üòÁ(Û(‰BDj×®½råÊ´´´åË—×­[×d‹···Wô;5ØgýúõW¬X¡ŒŸdggôb\’ÉÊwò /,X° ==ý£>jÛ¶m¡<•(LŒº&äcÔŹÜoÔEtªò wK&^9ê’Óc\ 0ðWã£.ýû÷oÚ´é°aÃDäèѣϞ=;lذ={ö¤§§+5ë÷b²$­VkP¹ñN.]ºyøðáF­]»¶JS±uQ3¢ `ÑE%H/ޤ’è"¤¸ 7ˆ.ÁÁÁ›6m ³KVrJ§y"º¨Æ"*X¬o€ic€#%&&:>Bä§Ó5Y÷Oz.¢ õ²××Sµ°è€i„Gt㉋‹‘Zµj9¥w—ÀÀ‹c(/ªš3¦`ìðÊïyÿÂéˆ.\ƒ2gÌÙUÀùH/€9îq5yed59Â=ŽvÆ„1€‹aæà®t¹ÅÙ…@¥ˆ.\WIv$•OÌ#½î‡Ü‚<].‰ô¸r ¬AtàJxq$•¼ép Êê5!·À ,Óà’H/PèVí ç=€ Ò}ôÀÿ_XƒQ€%ê¿ÊáÀµ[`+F]¸õŸIÃñ”±á¢É€« · u¸Æ^BnAþ]n‚ô¸r òèp¤@åÈ-(¢ À­^Õ"· €ˆ.wCzTˆÜ‚‚#ºÜ~z!ÀÎ¥ÿßÜ‚‚ ºÜSrDÃ/€Óé‡r ˆèpg¤À‰l}]nŽô8¹vGt¸?Ò à`ä¢ À#°pp å£ð]ž‚…û@acQ> ÑàYH/@!a°…èð8Lì‹Ibp ¢ À1y °&‰Áaˆ.ÏEzk‰ˆˆ‘„„g’‹Á8Ñàј<ä“Äàx^Î.'Sκ”“°€¸@N ~Nx‰Hþ‡r#.`»ˆˆ³ëq0eø ŽÇ¨ "Lƒ‹PÃI³anñ0jx <£.äHŽHÒ½s` VÎZé£uj)ðPD ±vxÌÍc¹p¢ &0üä`°ªAtÀ,†_àÑlÊ]°„áx([ >DòÆð <ƒ-P+.Ž €U ¾¹R¸z2ÜÏã×>v^€iŒº`ý¸Âð Ü ¹ªÇ¨ ¶aøî†ÐAt ?0p„¸&Œ*!" Î.€µ˜?Fn«aÔ€aø®‡ÐפÑjy¿*çìä_Dò?t·ã¶;±8˜2lî-peD@uH/€«#Àx×È-„¸>¢ …ƒ3E¨oE¸ ¢ …Fÿ”Q8k„Ãñ„{!ºPÈ8}„ãñ®ƒ;"ºàœJÂ1x§Á}]p N+QxxwÁÝ]p8N1a_¼£àˆ.8 §›(8ÞEð$Dœ³OØŠ÷ <ÑuàdÖà}Ft@M81…9¼7àñˆ.¨ÁIªpžêÁH,À߈.¨§­žŒWxÑÕcÆ£ðrf]pœÔº1^\ /D\§¹nƒ—°ÑWƉ¯‹â…lGtÀ-p*ìx™€ ºà^ŒOŽ…óc§âì„耛âŒÙ¹xþ{#ºàîLžC §Ñ…€§(LD< çÖvÇS 8 ÑOeîœ[8í¶ˆç p¢ °x:.FΓ¨Ñ<Îò™ºxÀÉ:Ï JD`Qžçñ =›wï£Ü ÑØÈÊÓ}§Ÿ÷»\ÁL!º{°5¨)pDPÈœžjÈ'€[ ºpEœ]äèÀ]¸¢ @tàˆ.\Ñ€ ºpD.€è¨ÈEIDATÀ]¸¢ @tàˆ.\Ñ€ ºpD.€èÀ]¸¢ @t94 íVU<á§#º`ƒ¤¤¤=z”)S¦xñâ-Z´øþûï•v;ž¹jçïïoÍöÅŠ ŒŒŒüõ×_íUI>üøãÏ>û¬OhhèçŸîÄJ¬‘ïW­N:µjÕ²ï>mBR‚g"º`ƒÈÈÈZµj;wîöíÛÓ§O_²d‰Ý»ÐêY¿~ý!C¬yÈÇ:Ô¢E‹6mÚ9rÄîUYcÿþýƒ š3gÎÝ»wøá‡íÛ·;¥ŒÂvàÀÌÌLooï}ûö9»À³]°ÁÁƒßyç²eËúøø´iÓfóæÍò÷GàÊ臲YVVÖ¤I“*T¨àëëÛ§OŸû÷ï+ífîܹ+V,Y²ä Aƒ>|h¹»÷ßôèÑÖV¤H‘€€€‘#GNŸ>}ÆŒ,#==ýõ×_÷÷÷÷÷÷2dHzzúÍ›7Ë—/Ÿššªl‘‘Q¡B…ëׯë?jöìÙ³gÏnß¾½··wHHÈòåËuw-]º488ØÛÛû¹çž;~ü¸ÒxáÂ….]º”*Uªxñâ:tHIIÑ•grû´´´þýû—,Y²R¥JóæÍËóÙÞ¼ys½zõ¼½½ƒƒƒ—-[fpŒÆ¯šñQ›|ªW®\Ù¿ÿ¨¨¨•+Wæ¹O /Á‚ ‚‚‚¼¼¼,²É§Èú^7CtÀ 4˜6mÚ… ôµZ­ü=Z¢´Ìš5ëðáÃG½víšÏĉuïܹóøñã.\¸råÊÔ©S-ôõÝwß………*?Z9G¨[·n{öì)`“'ONNN>{ölBBBbbâ;ï¼S¦L™Þ½{/]ºTÙ`Û¶mMš4)_¾¼þ£öîÝÛ¡C“Umݺu÷îÝ·nÝêÒ¥Ktt´ÒøÒK/ÅÄĤ¤¤¤¤¤Ô­[wìØ±–·Ÿ2eÊÍ›7?¾sçNÝÆæ3***66öîÝ»;wî}’’’”vƒ?©ÕªU;qâ„rûêÕ«+VÔmvöìYåö™3g-ôÕ¸qãS§Né~4÷WÛ =##ÃËË+eèv ÜŽÐjµçÏŸ¯Zµê£G´ZíСC×®]kPIÑ¢E333MV˜ššªÜ¾ÿ¾®<}÷ïß/_¾¼åíÏ;§Ü>{ö¬®Zs‡´`Á‚?ÿüÓ¸;ƒãµpÔ¾þúëüãÊívíÚ­[·Î`WÖ¿’““õ+±õ)²¦ÀÍ]È+W®Œ5ªyóæÊ§’^^^E‹-Z´h‘"EDD£Ñè6ÓÜëg c?üðÃK/½dM%]'''ëNpm-C·+ý¢¿AÏž=W­Z•••š––fPIÙ²eSRRò¬P÷ã¾}ûZ¶lY²dIåãTýòLnoP•®ÝÜaÝ»w¯X±bÊmƒSɪU«^ºtÉø!ÃUªT1·óçŸ~÷îÝÖ”aÐõ¢E‹^}õÕü•¡?êbrXæÐ¡C 6ܵk×àÁƒwûòË/ëNë-T¨û±J•*_}õÕÍ›7³³³oß¾mîì_¿*“£.æSç‡~¨T©Rž…™;jk×®)KSt¼¼¼®^½ª5],¼ÖühåS”ç3¸Öº`ƒÎ;ïØ±#===55uΜ9õë×WÚK—.}æÌÝfo¼ñÆë¯¿~îܹÌÌÌ“'OöéÓGw×èÑ£•¥ 111}ûö5ÙË–-[4MóæÍõ-¯uÉÎξråÊâÅ‹ccc§L™RÀ2z÷î=vìØëׯ+ôîÝ[ioذaÉ’%'NœØ¯_?ã&Nœ8iÒ¤ŸþùÑ£GüñÇÀ-,"iiiÞÞÞ%J”HLL´æBj½zõ3fLjjêõë×õƘ;ÌÞ½{Ÿ:uêÑ£GÙÙÙYYYÆ;4xÕ̵ÎêÕ«ûöí«"µfÍ û´ðXÃÜSdß^—á¬Ì€+Ú¸qcË–-}||üüü:wî¬xï½÷žxâ ÝÖ¬¬¬Y³fU«V­X±bõë×ÿú믕v™;w®r%¨ϹR´jÕêÛo¿5h4÷W[ùƒ^´hÑÊ•+÷ìÙó·ß~ÓÝekº.ÒÒÒ¢££ýüüüüü¢££õëüþûï«U«–m²˜M›6…‡‡{{{רQC7#f†¾ûî»//¯êÕ«+—™¶¼ýýû÷_{íµ%JT¨PaöìÙº!/s‡ùå—_†††zyyÕ«Wï§Ÿ~2®ÖàU³pÔŠðððíÛ·ë·ÄÅÅ…‡‡ëiý;Áä1ZùYÙ àf4Ú¿å€Â¦,Bpv*cÉ’%III3gδoI¶Šïرãùóç[Gb°ÖíÛ·-Z4bÄg0jÔ¨7n\½zuüøñ]ºtqVœ‚謢ÑhÊ–-;jÔ¨€€gÕZ§Nš5kúùùMŸ>ÝYep U [€eŒºpD.€èÀü?*_!Y^áÐ=IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/complex-deploy-3.png0000644000175000017500000006316110014674771025111 0ustar frankiefrankie‰PNG  IHDRýý>ö(sBITÛáOà IDATxœìÝw|uþ?ðצ‘i^Hè…J ÅËéQE@“(U~ M:*p(r|õ<φw¨ØP@ # % H)¤BBIÝìþþ˜d3Ù:[²õõ|øð±;;ó™÷|fØ}çóùÌgdJ¥DDDDd7[@DDDäð˜Q™‹Q3Z±bŸqãl…évîÜ&“ÉlˆÝQÕ‰ÖʱH±ÚíDrròÊ•+m9ͨòòòÆŒäííÝ¿ÿ¯¿þZXnÁ¯0Y‰Ëõ"fT FDlEö˜þ_D‹¸yóæ¶mÛ6oÞ,¼µáU·oß¾áÇûøø´nÝzÒ¤IEEEË^,X°à‹/¾p‘Ñ–ªÚkÕªÕ°aÃ.\¸`ëˆ °«GNÀ?þñ-[¶”••5÷ŽÈѹhF5nܸN:]¾|¹¼¼|åʕ۶m³ø.”J¥Öß!]Ëõ"¬/~íèìá(¬Ãûï¿ÿÄODDDomxÕ½þúë/½ôRIIÉÅ‹&L˜`°áEnnîC=dñ8í–P¹¹¹ƒ~ê©§lްù¿e+;räÈ?ü°¹wDOé’<==+**ÔjV‹\.ùå—CBB|||&L˜pçÎÕšëÖ­ õõõ}æ™gªªªtíHW [óCÚ³gO·nÝ<==Û¶mûÏþSëá¨øöÛo·mÛÖÓÓóþûï?s挞ò;tèpñâE¥RyõêU™L–——§T*/^¼Ø¡CÍbµÖ €M›6ÅÄĸ»»‹Àš5k‚‚‚¾øâ‹5kÖ‡……íÝ»WXáÊ•+úÓŸZ¶lÙ¢E‹Ç{¬°°P­@mÚ´)..–×ÔÔ„„„‰£Ò¬U ÒOº †úÝwß©ÞÚüªܽ{·E‹ú#×U9â¤_?J¥²¦¦fΜ9mÚ´ |ýõ×õ¯¬õ|i]h‘ËCk½UUUyyy)•ÊÊÊÊéÓ§ûûûûûû?û쳕••j+ëú÷¥õdé Xký¨J>yòdTTÔ–-[Ôv¡vvt…*%0µ¡š§æôéÓíÛ·W(Âú …¢]»vgΜ1¸wµúQ½ÕzBMÕ:_&ß}÷ÝðáÃ5ƒ$sÑ6ª^½z-[¶,++K¼PÙô'€5kÖœ:u*--­°°°E‹ .T­|äÈ‘³gÏfee]¿~}éÒ¥æ‡$±íZWH“'O^¾|ùíÛ·9òË/¿h=58vìXYYYrròôéÓõ”Ÿ”””šš à›o¾iÑ¢Å7ß|àСC#FŒÐ,VWÍœ=ztJJJQQQQQQBBœ9sÔ T*•&Lؾ}»°ðàÁƒ}úô ïB³rTŒ:éÆ:{ölÏž=UoíäªÛ¿¿Äf'ý—ôëÀòåËÏ;—––våÊ•k×®é_YëùҺдË#44Tÿ———oذá¾ûî°xñâüüüK—.efffgg/Y²DJÕAÇÉÒ°Öú|þùç#GŽÜ¾}ûìÙ³ÅË5ÏŽÄP¥ü Õ<5=zôð÷÷?tè°òÁƒƒ‚‚ºwï®ÚÜØŠÒó¯Ò¨PÅšïË$11ñôéÓúˆÈEÛ¨rss§M›8qâD¡ÑE©ñçTÛ¶mÏ;'¼.(( S­véÒ%áuFFFTT”®éªaÍåúÏ…êS]!ÅÆÆnÞ¼ùêÕ«ËPRR"¼¾{÷®‡‡‡žò÷ìÙ3nÜ8¥R9bĈ Œ5J©TŽ;VÜ£*VkÍÈÏÏ× @ii©R©¬ªª¿þúTs÷îÝͯ\¹SSS£T*Ÿ{î¹O?ýTmCý•#ñ¤›ÀÃÃCˆJ`ó«N©Tž:uª}ûöªr – ç–~ý(•Êèè茌 µBŒº˜µ.“~yè9(•ÈÈȬ¬,¥R™™™)¬žž©V3ZK“r²Äk­6lˆŠŠúõ×_u,~«+T)©ý Õzj¶nÝ:aÂaáøñãßzë-q +Jí­ÁjW_&r¹ÜÓÓSW¨DͨT®_¿>{öì~ýú oÕþñ{xx¸»»»»»»¹¹ÉdªÕär¹ðº¶¶Võs¢IzF¥Ÿj}]!¨««ëܹ³fTú+GâI7AHHˆªgAÌVWÝÁƒÛ¶m{êÔ)ƒ‘Kɨ´¾Õ¼»»{mm­Z!F]ÌZZäòP; …BqéÒ¥|õÕWBäú/i]•Ö­t¬µ~´k×nñâÅúVѪ”À¤\„7nÜ(---)) ¼yó¦xCƒ¥öVë 5!Të|™‡††jI$æê•R©¼sçŽêµZ111999š›¨ýñ­«p‹gTºBRÙ³gOxx¸Á½èúVÒUþc=¶aÆaÆ)•ÊGydݺuIIIZ‹ÕZ3& FGGïܹóæÍ› …¢¼¼\×ÏØ/¿ü’˜˜xôèÑ¿þõ¯ºY©£r$žt¨£³þU·sçN=­ºJ06£Ò¼Ö6£.f­ -{yˆ·ºzõjDDÄíÛ·###uµ”hÝ—j¡Ö“¥+`]mT999:tذaƒÁ€•J¥®P¥&ñ";vìæÍ›7mÚ4qâDµ uíÝÃÃC5|°¤¤D³º´žeé¡ZçËdÏž=GE¹è8ªQ£F>|¸ªªª¤¤dݺu€ ªÕfΜùì³Ï^¾|Y.—Ÿ?~âĉª^|ñE¡?>%%Å"÷IG¥+¤ &\¸p¡¦¦F¡PÔÕÕi=sÊOJJZ»ví#<`øðák×®MJJÒZ‚ek¦²²ÒËËËÇÇ';;{ÆŒºVKLLôóó[¸páÓO?­ù©ÖÊQ‘~Ò5räÈ/¿üRõÖ†WÝo¼±`Á‚ýû÷‹Çu¡î<×ü”)S^xá…ÜÜܲ²²””ý+k=_ZšvyH9êØØØ‡zèã?ž0aœ9sŠ‹‹…j7x›¤ŠÖ“¥+`­õ ::úðáÃï¾ûîÚµk5w¡våH UÊU¤ëÔL›6íwÞy÷Ýw§M›¦¶‰®½÷èÑcãÆyyy3gί¯ç_¥ôP¥3çËä“O>5j”™ó³uJgß|óÍ€Z´háïï?jԨ˗/ ËW­ZÕ²eKUµÔÕÕ­Y³F¸¡é¾ûîûßÿþ',°~ýzá&”©S§êº§Fk=ëY®'`ƒ!}òÉ';wöðð¸çž{T÷¶¨ŽÖ%–Ÿ™™ @háFhj‹£«ftíNW ¨^õÕWíÛ·÷ððˆ¦ÐU]_ýuÛ¶mU÷"‰i­U Oº JKKCBBTC4ìçªpûöm¥î«NO=k]n0øššš”””ààà   M›6é_YëùҺдËCâA}ÿý÷½zõßÂ6}úté÷úi=YºÖZ?ªO¯_¿Þµkו+WªíEíÊѪ”ÀÔŽBש©««‹‰‰‰‹‹SýC3¸÷´´´ûï¿ßÃÃ#&&æÍ7ßT­¯õ„šª¾L®^½tãÆ Í ‰ÄdJmß¶¤ŸÐoë(šÙÇ2L4úmX3Û¶mËËË[½zµMö®ËŠ+.^¼¸sçNó‹jŽºu‰+€½^Öç@gÜ~¾L’““{öìi‘{ºÉ¹9Ì¿.»â@ßJ¦ûXÀؤÊV5S^^þàƒ8p 22Òú{·—¸êš‡+\9ÐUÄ/r8¶€ìÒǶº…t2™ÌÝÝ}ëÖ­ü$M¼Ü<ƒ ûôÔÞÆ®@È<1¦ îÞ ¥éßKímí±iu' i/¡à¸µ@L2z¾¡¾BÁÈøŠŽ@Qƒ ûÐýU„Uß»Zz6i ²\çe gsy~_Žœ]¨È…»Z÷FçDªÿTÿ‰Ó¤”#ãMdˆ[éP*к7ºÌAôã’jRÿ1ê¿HÜù¿¾„ƒ¹#ö/è¹ÿóo¬@ƒ‡£¿ì˜L©äo°S`FE&80…ñÐÿ´¾ÕÕ80Å?ª/Œ‡÷ÂÍ h¸#G"ÿÛÆ|†s¯âæéÆ%½·£Ãsõ¯µnâgêÓˆ&WµÇ'!ûcõü»`øOð DÍ |{/*óÑï´W?Åãá‹gá ýÐtýÃÉùGŸDë>xô„¤½{8«ôØ\Û…«Ñíÿ5~zq#~[€èd üBçõչ䣈þr¿l\!q+:ý½ñS1]ß9ûû£øG =„°Á¨¹]m%dnøË x ð AHÖ¸\XG“þ½èŠMÓÅ ¨ÈEËögäÖõubÇâ±_1¾É9h;ŠZ\|Ý@z6QÑsèÙ\HP·bL9ÆWaøqD'Æœ8•Œ-(øžþèó.ž,ÁøêÆÒ¤Ô¤”cÔµù…õ¨¼ŽVjàg”7­vƒ‡£«ì3*¤vã+o‚%“Õ”0x`ä~­%†?Þ€~Ÿ"úOð €›'‚{¡ß§óEý:¡ã󸕬qu'n]D×:¶õó ª_úÞ:ƒUÜÃQ™«ŸÔo’ó9î^CH?´éÛ¤(éu.ý(zoG«ððÅ=KàÖEÉ× d Ê¨@U€]¥¿ i«±¤Ç–û íŒˆõÿÁ=áæßh<ð6”h4š°‰žË@Ïæ-Ú@á!dlFáa´î]ß)ýÄ©d½·£ý4´h 7/´y¨¾4=5)åum.4G5Ö@oõj7x8ºêÁîq•ÃRk—b™À+Õ¥¨.…w˜¾Õn_€ÈM 2ne6YؽþE‹íKäwÔ ÿ¬† €»YZb(?{{kù¨âZãëû_Ãõ}8·nžêî+µ¬/Eõ ðô7nï|8Rª4a®ïCú&ÄOPßvÕµiŒ©séGxoý atü®–Mô é™{}FU˜ ŸÄMDÚ<€Ò“¹£M?£‹5*¶;Y€¶3¢¢¬Cú&d„Û™WÔ/¬,зw‰›èº ôožø~šŒœÏ‘ó9´ê€»Ð͈§r+¢Fë;]5)ñum~'Bú7®)~ ס®z°{l£rpl "s?½×÷Y¬@™»á%¦Ñ3âSÕ/@~ 57 ”£"•…ßÖ¹•~ÅGÀ¿“q{·¬°ÁhÝ7O£ð JAÉqøwn2²X ½Î¥…ùgÍÓA=P‘ƒ[Qvá2D<‚›i¸s9êaâŒ_–º¢ü6¿ÍÇÍÓyE…7‘¾yôãøs.|†./Á7·/ãäs€i—Ÿ„Ÿ]5)ñ œQ²¦Á<]õ`÷ØFEäÂÚŽGá!ü¾ ‘5¶phjÕ eg‘¿±c ]*þÍ¡èhã@®â#à¯eµ€n¸q #ÏøSõäLÔÜD¯-¸›…³ËðËßÑOc¬Aò»ø}D&·wH>‰UÚmŽ$ãâõ­e]çIú¥ÔEúQè#”€Òp$!p# _ƒRQ_'Ñõ2¶ºQ»=ZÆãVº–3¢" ýé·‘ÁÓµ·ñ?µ!waÞ€îËÀàæ-óbž@Â|QßÈg‰ó§‘ûâ&JÝDEâ1ê"T{ñ·ªÝ!åp´ÖƒÝc•³àSÈí¦"è~ÜÉÂw½pyî^…¢u•¸•Ž?ÞÁ¾†NáÖ¹_žÇµÿB~ò;¸ú NÍ`Ê÷µšS³PzŠZ”þŒ_f@´¶®ŠN€Ô‘Èú*r ”CQÛ™¸¼ûª_çê'Èý÷"î)t™ß(\ý¤¾ã@ E î^EÖð}"Ê~‡w(:Î2bïFŽÄ*~ È߃kÿƒw¸[2 ’~z´€ÂTÀÐH!gÊú!|„dõ#åCôfTÒ÷¢‡Ðž§yFTê*ÀÝîÞ¸“…“3 ‡ap®Ë@ÿ懒P°¿þz¨wå˜tâ„Kå—¿áÊ{¨¹E JNàˆ´ñÝQašƒ_þ†§ ¨ÅSøåoMV0x8ºêÁî±JLf /±ëù&>–q@ÁÍ ƒ¾Æ‘?áÆ¯úÚÕ»ÎAþ·(þÇÆ5Y6SÌ¡U'ìíÓøÖ7 µ¬ÖîÜø ™[ñÓíåTáÔlè±27xø¢ûjœ˜Š_žGèÀú±®ºhþ5⋟5ŽÙ7¸wcGj•Êð2~š ¥gí…½ë'ý(ô{×váÀú·ún÷Šõ¨¨çŽÀ{QvBûëÜШ½èÑu²?ÆíËg$r$î\i\!âQäînÌ34g<Ò Ãà&]—þͯëß7Yû$`Ò‰ëôò÷ àNL“º‰ŠÄcÔ%aaý¬ï¨_9·/AÖo<]õ`÷#ïk>2 &lbB!Í…éË7 ÃÿBÄpx‡Bæ?ÞƒŽÏcøOõ븵ÀÐc ï…»7Ü}Ø÷­oœŒÊý>Fûi𠂇¢ÿ„aGšÌi)–ø ÙØ¿À7 nžp÷A@:άóÔ,T— ¤_ã@üÓºUEê"ëâîßhDŽÀÛ0ò¼ú#hôïÝØÃ‘^¥!ýÀ£%:>/é(ô“xzôÚ‚˜'ál¸?®Eü»@¸hz¡/Ì¿«¾^f£ö¢/€ÖvÑÃÃ^Áh? ýšNôÚçÿó<|áˆvSÑ÷CÃaÜD ë2пùЈN†W0dh„—ÑçúŒ=qnžüî߈ p÷†‡/ÂcÐW’êMâ1êÒ¢ 9ЍÑÕž¸h¸VÊáè©ûæZ3|JÌuô׉± “åkXkïs)r8N6Z3ÎÕOðãDtž^[,\2‘u\y'¦!t†¥Ú:”æå´mT›Ž”Úè/Yë&z6·Fó•Óü&‘Xm9®í€öÓm ‘dGþŒ’PT£¶Ù!mà0=wæpÂqTz²ë4È©íE-á­Å"a.Eä¬T­Ñ‘IsÿÙ¿ÜÝÈÝÝdIÐýè`äwäTmTj@Æ6>5­X¦½Šé‘s“y ìaGDBToðD< ϸy¡e{t‡a‡Ì½¯Â8É8*µìÄþʬ€yC‘qøŒÊár)1µ5FBDDDæpàŒÊ¡s)1æUDDDŽÎQ3*çËBTGä‡CDDäR2£rÖäÃùÒD"""áx•³¦S*N€DDDÎÇÁfOp…lCuh¶|š ÃÁÚ¨,<=¦s…Ü‘ˆÌRxÖ£ô$joÃ7 a£ýôúç lþœŸ[éÈÝœÝ(= (µD¢¨ÆùµÈú*òà…øÉèöÿ ?,R±¥'ñÇ¿Pð*®Á£ÚôAÂB„²äqiãH•«%®v¼Dd„œ/pì/P*Ô—‹Ó ›gTj!ÕŒäè“Èù¼É’˜'1`—YÅj>ùTæ†þÿCÌŠ%2ƒõúÁ•Ò ë©Ö‡!êg剨ÞÙW T j4F]À„Z¢f´Ó ŠZü¥^ÁÚWÐlªQµådˆËïàæiÔUÂ71Éè¶^M6S†´9ÈÙ E ‡¡×&øÅ€¼¿/GÎ.TäÂÝ­{£s ¢FˆVkkÙñ§‘ý!î[‹„—ë—\X‡Ó‹ÿ4úáÐU¬šŠ<쎆Ìj%•Id*k£rÁßccÙÌ&%͇!êgìá°q‹È2|¢ ó-T—³™ÇŸÂñ§QtµåPÔàθø:ö=„š²&+þøþøjn@~¹»±jnÀÏÓpq#îdAQ‹Ú[(ø‡G›x7~€È‘K„×¥¿˜X Vî^àîmÉ2‰´q°ŒÊ¥i‡fòѬ9“±Ašœ~±ëÈ,÷.€³KñY¾ê€cãõ(DÍ0ª–›‰Êúÿ\~Ù£e<îÆ˜2Œ¯Ác§Ò·Òq~u“òo¥ãÑŸ1¾ž@ËxTäâÂzÈý·bL9ÆWaøqD'›xyв]ãáuež‰juñuhhÉ2‰´aFe§Äy†ms& 2˜]Ù*0"ÇÓî =ˆ¨ÑððÃ?pí¿øi ¾ï…ªB}[ýñôûÑ‚gÜ<Ü ý>€œ/š¬ùÀ6´î 7/´îƒ¶@î×Т BÆfFëÞØtCéê*Àݧq‰ðZ^abš²?Æ… póDµ+“H[ ‰Å‡9:'¨ ¥¶i·\s´‘‰ÂFØÃPÖáVŠá”ýŽ´¹èû¡ÎMÊÏÀÞÞZ>ª¸Öämè€Æ×!àn$¾…Ÿ&#çóú{ôZuÀÀÝèfJüî¾ßA]%<üê—ÔU€‡oý[ƒ· ê—ý~šþm4%B"c°ÊNÙm;“Åéjµ²UY\?¬ž¨y8@¹,&RD:=ö+º¼„Àîp÷›'|£ûûl@@@@@ÀŒ3ªªªT…¬]»6888<<|÷îÝk×®mݺuxxø¾}ûT+èß]eeå”)SüüüÂÃÃ7nܨ™ô¨& µy󿨨XYYYÉÉÉ­ZµòööNJJ***BCÚáææ&l¨z-Ië‘:çH ‰ˆÈùhɨ\¡oåÀÇŽ+++KNNž>}º°pùòåçÎKKK»råʵkׄ…‹/ÎÏÏ¿téRfffvvö’%KT…æää¬^½zÒ¤I………×®][½zõܹs%îî•W^¹yófvvöÙ³g9¢¹•p Ô†¯LüѲ…ôôô#F°'N^™DDdçØFeK³gϾqãFAAÁüùó“““mŽb:EDDö¯IF¥º7ÍFÁ¸œÎ;wíÚµcÇŽþþþ+W®´u8öˆW#9š=‡O‘£p¡>É8߃º‰ˆÈ¹9Øäô˜K‘#ÒÒF6SY‹Úè®Lm¼«…ˆˆ‹¾{ýqP°#ÆÜLôTEffæðáÃýüüüüü†ž™™),W*• , ^´h‘ÒYñB¦SDDäp´gTâ'ÁY1²’qãÆõíÛ7///77·OŸ>ãÇ–ïØ±ãØ±c.\8wî\jjê»ï¾+½L™IÄ%(XòP‰ˆˆ¬Bg•#&UB¨âŸêªªªgŸ}6 `ÆŒUUUš[ÕÕÕ-Z´(44Ô××wâĉÂS‡‡žšš*¬ðÃ?Œ5 @VVVrrr«V­¼½½“’’ŠŠŠTû]»vmpppxxøîÝ»×®]Ûºuëððð}ûö©VX¿~}XX˜ŸŸß´iÓª««¥Ä ytÛ·o‹‹óòòêÙ³çÙ³gõl«Ybééé‹- Z¼xqzzº°üý÷ß_µjUDDDddäêÕ«ÿýïK«x³0‘"""' ¯×Ïá’*!`ñÏóâÅ‹óóó/]º”™™™½dÉÍ­Ö¬YsêÔ©´´´ÂÂÂ-Z,\¸ÀúõëSRRärymmí¼yó6mÚ`ôèÑ)))EEEEEE â‡ñæää¬^½zÒ¤I………×®][½zõܹsU+9räìÙ³YYYׯ__ºt©”48pàØ±ceeeÉÉÉÓ§O׳­fUˆOâˆ#6lØP^^^VV¶~ýú¤¤$aùùóç…×½zõ:þ¼”j×J)™É» ""²†GF;Öœ@jc½£¢¢RSS;vì ##cÈ!yyyj›ÄÅÅ}ûí·ÝºuPXXØ£G‚‚“&MJLLT(6lPÛª¢¢"..Nh¦’Éd¥¥¥ÁÁÁÕÕÕÞÞÞª×~~~r¹\XáÒ¥K:t™™9dÈÜÜ\q´ºbP;´’’’Ö­[ {¨­­Õ³­ZUˆßæååõíÛ÷ÚµkâããüñLjˆîîîµµµnnn …———¿±§@õÚ!®{¦j(%""û4xð`á…¤{Íè7R-ðð𨮮vww —Ë}||„,DÌÓÓSÕ¢£P(d2™B¡°k×®e˖ݽ{÷ûï¿ïÒ¥ €'N,X° --MÕ³&¬)Þ©Ö×2™L.—k†¡ZAW zÍà¶zn$|ôÑGûôé#´±½þúë'OžÜ»w/€€€€œœåååqqq7oÞ4îˆÂS½¶ókÆ1‘""r,ƒ6âî}‡øÔl£:|ø°fãXllìñãÇ£££Õ–÷ïßÿ™gž©¬¬LKKû׿þ &&æµ×^{ôÑGnß¾ J˜ fTâ6ª¡C‡æääˆWЃžC3¸­žŒÊÛÛ»¼¼¼E‹ªªª…f}ûö]µjÕ!Cÿüó¿ýöÛï¿ÿ ²²ÒËËËÇÇ';;{ÆŒFöâ‹/ °RRRžzê))1@Ú6]ÛªU…¸¨nݺ­]»¶¬¬¬¬¬lݺu÷Üs°|òäÉK–,¹~ýz~~þâÅ‹§NjÔ1jR»`Ì,Í¥têÔ‰é‘ýS}]‘Q 4Ÿhþ¥®ÛéM0oÞ¼ÄÄDU9«V­ ëСCÇŽ£££_}õUÍM^~ùå6Ì××wÒ¤IO<ñ€•+W®ZµÊÝÝÝÝÝ}Ó¦MóçÏðÞ{ïÍŸ?¿eË–C‡4hQ 8ðÞ{ï_¾|¹”$Òµ­ZUˆ}ôÑGGŒŒŒŒŒ>>99yÿþýæ—IdYÍ•QéÇÆ*¢f’—————wâĉîݻϚ5ËÖá@s^eÌœ9³}ûöÇÏÈȘ?þûï¿o~™D–e/S][Ippð‹/¾xáÂámTTÔÿýßÿ=ðÀ±±±ª««çϟߥK—.]º,X°@õ°Ñššš—^z©C‡÷ÝwßÛo¿­*MW³“\._±bŽ÷ÞÛµk×;v¨>ÚÉÔVÖµÓ¨¨¨>ø OŸ>mÛ¶}ôÑG/^¼¨y8¿ýö[JJJPP——W¿~ý>üðCay]]ÝÚµk»wïÞ¾}ûY³fUTT¨oTTTß¾}U_5J¥²oß¾/^4¸¡PQDÒÙKF%àï« RM‚jë@ˆœÊ76oÞœ Zrúôé½{÷ ŸZ·n]AAÁ±cÇŽ=š““³~ýza 6”––þüóÏû÷ïÿñÇ îåõ×_ÏÈÈØ»wï‰'„¶(Õÿ5›¦tíÀÑ£GwïÞžžþØcÍ›7OsGÝ»wíµ×„àŶnÝzæÌ™½{÷ž9sÆËËkõêÕjÇ›——תU«ãÇ üñÇ€€€®]»ÜPs_DúÙËíu¼ùË•qVΞ@fR5ùúú&&&¾úê«ÂÓ¢¢¢~ûí·ÐÐPáÓž={~öÙgñññþøã1cƤ¥¥èÕ«×gŸ}àÊ•+ £¨¨(q†¤z›˜˜øßÿþ·]»vj1h]Y×N£¢¢Î; ²²²K—.W¯^U;®‚‚‚7}úüç?ÿéܹ3€âââGyäôéÓjÇûÞ{ï:uê­·Þð·¿ý­OŸ>S¦L‘²!‘tæÎž@dªYˆÈ|ºÆ-‰³„’’U¯VÛ¶mKKK…×ÅÅÅ111Âk)Ý^EEEÒ{Çtí€NðññÑú€öððð×_]Øã›o¾ùÜsÏíÞ½@AAÁ#<уM5÷‰'žX¿~}YY™R©fÌáa ·nÝR­ïïïÿÇHß©“'Oþé§Ÿª««oܸñæ›oªžFúôÓOÏŸ??;;[.—gdd躷qüøñŸ|òÉÎ;ÇoÔ†DÒ1£"Ûã(:"+[¸paHHH¿~ýú÷ï±`Áaù¼yóZ·nÝ»wï¡C‡öë×OµþÆ¿ÿþû.]ºŒ=ºoß¾ªåsçÎíØ±ã°aÃ|ðAUwáóÏ?Ÿ””¤9 •®J1eÊ”7véÒ¥oß¾çÏŸß¶m›°üïÿ{Ÿ>}Æ×¾}û^xaĈZ78pà­[·îÞ½«:(‰Ig_½lüeuY<õŽL'"rD™™™l£"Ûã°t""rtö22]ŒãÓuÑÌ<œ¬¢xꉈÈAÙWKb,Y[b:U§ú$""Çe_˜TI£ù¨i™ˆ­¢2Öh눈ˆ`‡˜T首E)EÄË"µG(~ä–êSÛ„EDDd{GÑ$ÚX£Ik…ˆªÒq^bWÕ¨ç±3<õDDäˆì±J n®`‹…˜ÁÚÐßpeÛÊÔÚ4¥†-UDDäpì´J ~Ü[,L µá ™Šu*Ö´ò¼‘C°ëŒ ¿»ªn ØYï••™Óf£§á§¹'e0!—b2MDDŽÅÞ3*ó* ŽˆÒÜ\JŽeFEÎ¤ŠˆˆˆcdT×Ì«¬0º\sÄU³–o&UDDdÏ)£¨5]¨}d‹ˆš‹­îÔ³ŸjŸk0©""";æxš6V‰9M‚å4b>&UÎ-22ÒÖ!P³ÈÏÏ·uDÖæ•À`_•Ãå%°u0©r>L¤œžpŠ™W‘KqàŒJ± –žm›Ä!JÌôcRåÐÄéq•p–###yŠÉu8OF¥Æ¨ÑÖö3“$­Ôš©À¤Êññ‡Ö¹ ç722’I¹§Í¨Ôèùõµr:Å<À4LªˆˆÈž¹JF¥•“*‡Ãá5Dä¬ì÷¹~Dj´&OöÓcKDD®Œ9&UDDdŸ˜Q‘ƒaREDDvˆ‘¹˜Q‘ãa3ÙfTä˜T‘]aFENEbRÅÜ˱DEEEEEézköÙfTä¨tÍDe0[V`REDDÄŒŠ˜±I•L&S{èr³„EDD®‡96éIó';÷å—_ ]iñññ ذaCMMæjª¾6µ~·Ÿþyüøñ;wŽOJJúæ›oÄ›DEEUWW/[¶¬{÷î111ª…ß~ûíã?Þ®]»Ž;Nœ81++KJ<&Ä@DN9-)ÍQL³ìGFFÆ|péÒ¥óçÏOžyâĉtéÒ@YYY·nÝÚµkwôèQÕúªOÅ…ìß¿?!!@EEEÇŽÝÝݯ]»f0bpM|Œ#¹ŽÌÌL>)™œž´‰­P¡°°pݺuG-..–ËåÂÂÒÒR‰› ‰ÎСCÅ ¯^½*~«5Oíܹ³ðÂ××@]]ÉñH‰ˆœ3*"Èdl¬µ±™3gž}Ú¨Íï»ï>'Nœ°a<ˆ 3*rLª—޼ÿþûUUU/^œ;w®ž•ƒƒƒ\ºtIµdÁ‚žžž+V¬¸pá‚\.¿~ýúgŸ}öç?ÿ¹ùâ±B DäX˜Q‘ímß¾=))éµ×^ëÚµkJJJJJŠž•çÎ0xð`Õ̽{÷þòË/;wîȉ£ž­ÌØñgRÆQ¹Î˜¶úËÕ5Tíò Çš233ÙFEd7_-‹À†åÝ€SÀÀ¯@7ÛDG®ÀÕr " â8*"›£ê¬Ê€2`pOÃòÉÀà:,¦Z?J[Sò?kýGŽÎ´ù[”œ¢Å˜QÙ€£@$ >jXþÐHºƒ€¿J-oÙ²e;vìÐ?9Ó’¡À1àpHÞµlL®‚‘M‰¿þº€  8tnX.67›À:©ƒš3•ý¨–ÁG&Zhèû#+ù¸ðâÕŸ?uÀ" ð&w–Ë€Í@, :ˆ¾@”@{à¬èK-0‚€7 Ë)Z,陥öŸ­#"r.“åÀmàðKÃÂ5À) (Z EëŸÒ%àjXxº‹V[œÒ€+À5CÅrŠKàÈt"ç·cǵ™Íµ’’-å¶ö½À?€dCЧ½^Ü”À÷ÀÛM#×3íµf±Â´×þšN{­ZA œi }…[û”œX•H*¶Q9?ÍŽ?ÇM§ŒŸ^ hè×ó:o½€@ °è xÐ;KuVË+@¸F±°ïi¯• ÿÌrPÎúˆ,‰‘˱ó{ú,ìÐmx›¬ Ö6tùAï,Õ/6Œ=JžÒV¬£L{] x>@6 ñ6PŽO'’†‘ YÞiÅòNõV¯Õ IDAT©;n.e\3Õ7ÀHÑÛ$à&0 @Ã|ÓªŒJÏ,Õ{x X®­XG™öú=`>Ð Ò™DfΘ"²¬fG¥jšZž¹Ì¨yª,Cd$ó§áŽŠŠ¤uZu>î7s‡Ö*ÖnÉm'N8¡ºî°ÔévF\–ÎG¸ö#833392È%ˆÓ)ÛFbIRž“Ù<»n¦bÉ‘5>+ .–W¹|:%`¯‘“O7¥J§¤<‘Æžñ»›ìÌ5n“f} cFEäÌ\k:5ŽO—&//¯IºïÄyUÓCS?p—Ä^?"çä¸ó#HÔØÃâRÝ+äT¹E}³xJ0G×4Ad%Æ6*"'$¥iÊÑ;þÈÚØLe<§j²b£”!̨ˆœ®‡ô¡éTŸNÀèÙ>‰lA{^å(×­F´Ì¥ta¯‘ópúž>²‘‘‘®3!‚ YH“áÛöܨ-ác"¥3*"'¡§iJ—;v8I«GSYóg6qRÒ˜]‰kÕ†W2³(ó°×ÈHO§œ$…jÀ¯{r\y š,•5ý¯YéÞ—öØH/¶Q96öô‘U);þ,LýÞ@1µ¤ÊÌ,C)S(s0£"r`&ôô©q‚Ž?N£@NC-¡1œ`YzdfTDÉœ¦©3fpê2›©¬Àp‚ev™dĄˆùMSN†ÍTVÅñé6ÂdÈÎqd:‘ƒ±x:Åö*""ó1£"râg›™N9úØ)Øvbœ?H{ýˆ{úô«ïø#"²¶QÙ; 6MéÂŽ?""31£"²kRžylçëøãcþ¬Š75ÅŒŠÈ~±§ˆÈQ0£"²GVèéCÓf*çèøc3•U±™ŠH„#Ӊ웦,€IYÛ¨ˆìËàü‡…L§È!pÚI"L©d»-‘}ø¸±]Ś锸¿¯¹‡« 3ñé%.‚§›\Gff&{ýˆìCC:•y¨S§N¶…ˆˆŒÅ^?"[ûX&N§l‹sŒO'"²>fTD6¥ê雨ÄDÛtÁ;ßÄTDDÖÇŒÊ82ï jFU¬óœq:EDDŽÌ2U^^Þ˜1c‚‚‚¼½½û÷ïÿõ×_ Ë-øË'k ¶\©T.X° (((88xÑ¢EÚË4X*B{ãć¦bcl–½ˆzúì-bÇ‘ ,“Q7®S§N—/_.//_¹rå¶mÛ,R¬˜R©Ôš-íØ±ãØ±c.\8wî\jjê»ï¾+±(‹‡j'œøÐžôô©±ZÇŸpÛ—p ‘3±LFuòäÉ%K–´nݺE‹C† ùî»ïÐ𗽸¨®®nÑ¢E¡¡¡¾¾¾'N¼{÷®°\&“­_¿>,,ÌÏÏoÚ´iÕÕÕÒwýþûï¯Zµ*"""22rõêÕÿþ÷¿Mˆøðá©©©Âë~øaÔ¨QjkkçÎôÆo¨VÞ¾}{\\œ——WÏž=Ïž=+,ÌÊÊJNNnÕª•··wRRRQQ‘êд®_YY9eÊ??¿ððð7¬"1]Õ%“É6oÞëááQËŠL&[»vmpppxxøîÝ»×®]Ûºuëððð}ûö ^(P&“…„„”””ËkkkCCC‹‹‹ÅQ[ÕÕÕÏ<󌪴ž]eªJ†ä L­f¤ŸDé{‘ÄŽ›¦ˆˆÈ–™=¡W¯^Ë–-{þùçãããU •J¥LÖd¾«5kÖœ:u*--- `öìÙ .|óÍ7…Ž9röìY™L6eÊ”¥K—®_¿^â®ÏŸ?Ÿ˜˜¨ ãüùóÂkµ]ë·~ýú©S§þúë¯J¥rÞ¼yÿûßÿ,_¾üܹsiii-[¶\±b…jå;v,88øµ×^›>}úÉ“'Œ=zëÖ­Ÿ|òImmíŠ+æÌ™óá‡êYÿ•W^¹yófvv¶R©üë_ÿ*¥ŠÄtU×É“'ÓÒÒÚ´i£¶~aaaNNÎÎ;'Mš4}úôk×®íܹsîܹ¿ÿþ»þàUΞ={ûöíK–,pðàÁ>}ú„„„ˆwaB ggg+Š©S§j=/zÊ„‘˜ZÍH?‰FíÅÑtSvžNíØ±Ã:S‘ÓãdTä:,3Ãg^^ÞÒ¥K¿ûî»ÊÊÊ#FlܸQøºTû)Š‹‹ûöÛo»uë °°°GÂj—.]êС€ÌÌÌ!C†äææjW#Orww¯­­uss P(¼¼¼är¹Ö5U%¨-V›4iRbb¢B¡(((ذa€˜˜˜¨Í $“ÉJJJZ·n  ¢¢"  ¶¶V­ÀŠŠŠ¸¸8U ‡Öõ£££>ܾ}{—/_îØ±£†®*R‹AkuÉd²üüüˆˆµº’Éd¥¥¥ÁÁÁÕÕÕÞÞÞª×~~~B]é ^U`VVÖ AƒþøãOOÏ™3g2dìØ±ZÏ‘ôHMMUEçÎõ_ŠjeªMâ¦V3ÆžD){1@ZÓ”ÐVj«ù¨¬6Õ'Ó)ÁtŠ\Gff¦…çL/((X»ví¯¿þzìØ1hüyzz o•J¥B¡Éd …BXM.—»»»Ëå>>>š¿pÍ<) ''Çßß@yyy\\ÜÍ›7õD¨+ÓÚµkײeËîÞ½ûý÷ßwéÒ€‡‡GUU•ÐO¤ksÕÛ'N,X° --MèšÖõ=<<ª««U‡¬ª]U¤ƒÖêÒµ/ñr­¯%?nܸѣGOœ81!!áôéÓÞÞÞâ¨,UF•)ýÓƒiõ å5aLÓ”‹dTDDN&33Ó³'„‡‡¯Y³FèCÑ‘-—Ëëêê„_#ÕGYYY‹+W®„‡‡Kßc·nÝN:%¼þõ×_…–lÞ¼yΜ9óæÍ¨„h¯\¹"qó1cÆÌš5+77W¡P”——ÌSò³³…תÐ[Eb&W—9ÁÏŸ?Ë–-Çïß¿¿Z:%½•ˆˆñQ˜˜¸L)µ§‹ÄÝ·û„.ïø#"2Še2ªQ£F>|¸ªªª¤¤dݺu÷ÝwŸ°<000##CµÚÌ™3Ÿ}öÙË—/ËåòóçÏOœ8QõÑ‹/¾XTTTTT”’’òÔSOIßõäÉ“—,YrýúõüüüÅ‹«FäuÇûJKK§NúüóÏÿöÛoÂè¢)S¦¼ð ¹¹¹eee)))úK¨¬¬ôòòòññÉÎΖòÇýøñã_z饒’’âââ9s樖ë©"1“«Ëœàýüü.\øôÓO›\ˆÊĉ_|ñÅââbá(L Lú&…®Ý™¾G„Îv)""“Y&£zþùç_yå•ÀÀÀöíÛŸ>}ú“O>–Ï›7/11Q•ܼüòË6l˜¯¯ï¤I“žxâ U ¼÷Þ{ãããÃÃ×/_®¹ ÕÍVj“H=÷ÜsýúõKHHèÖ­Û AƒÄ£¼uÑœjåÊ•«V­rwwwwwß´iÓüùó,[¶¬k×®=zôh×®xĽVï½÷Þüùó[¶l9tèÐAƒŒáÕW_ ˆ½çž{úöíëééi°ŠÄ V—Q¤?oÞ¼¼¼¼šSˆ`ÅŠ!!!mÛ¶½÷Þ{‡ bZ`Ò/0)tíΔ½ðž>""cáqT&aÌ}yÎ'==}ĈÒ{mX]Û¶mËËË[½zµMöîH>ÖÖD*!µ²í8*htö±ÕŠˆH Ë£"éfÏž}ãÆ‚‚‚ùóç'''Û:ÃÊËË·nÝ:kÖ,[â°„†+ñö‡)‘i,3™ sçÎ]»v­¨¨xüñÇW®\iëp Édîîî[·nå}ï’hmŽÒL¡4—Dj–xˆˆ¨™¹tw‘Ih¦Êœg…@ÄØñGDd,ËÏGEDf±nŽ™¥µ@NLEDd”ÌÌLöúÙ‘ÔÈCh:2]HzÄ4—˜™céÊ«ˆˆH:fTDvM3Ñi¦+25JëVVxÆ‘`FEä`š/ÇR5V͘1ƒs¦…‘Ã3-ÇÒEWcéÁ‘éDv¤ùfø”žQ©,Ï\¦zÍŽ?""=82ÈUHiÇR³¼Ó qREDDz0£""uBúÅ¡TDDÒñ)4DT/pžðŸðVÜÓÇ슈H?¶Q¹:ŽC'"23*"el"e‘‰©ø\Hg•ŸŸoëˆlŒ½~D¤“¥nñ‹l`‘ÒÈñü±Šˆš—ø‡–-ÎJ8Ë‘‘‘<Å䲨FEDR™3>=??Ÿ¿µNLu~ÙRE.‹éù=‰ˆ¤`FEDÍHh±`ë9=fTDdNLED¤3*"2€DD1£""""23*"2;þˆˆ41£""ÃØñGD¤3*""""s1£""£Ù¤ã/*****Êúû%"’‚IÂŽ?""=ø\?"r yyy¶ˆH'¶Q‘)ÌìøºðvíÚõðÃÇÅÅõíÛ÷³Ï>Sû´ººzÙ²eÝ»w‰‰F¯Ÿðö£>z衇ââ↺oß¾õë×÷ìÙ³mÛ¶#FŒ8þ¼x_~ù¥°I||ü€6lØPSS£kw#FŒˆŠŠúꫯT›ïÙ³'**jذaæ591fTD$•Å;þvîÜùé§ŸþòË/QQQ³gÏ>pà€øÓ>øàé§Ÿ>sæLNNŽ®Ž?¾oß¾·Þz+==ý™gž¹zõêáÇ·mÛvæÌ™_|Q¼fFFÆ|péÒ¥óçÏOžØ¾}{äßöêÕ+i Á¢¢¢À»ví*©Y³f~¿¿±±1ô´ººº|pРAݺu+-- lõå—_Æ{¹¢¢¢±cÇ666æ"«ªªNŸ>=xðàN:eò>€4äòŒ¿fÍ’AE='Þ&wß}÷«¯¾:nܸíÛ·{½ÞHòûý ¶8q¢Ëåzíµ×$ýñS~"QÈ›]»vìÞ½[Rÿþý³ôB[·n•4cÆŒvíÚIúðÓnÒ­[·¡C‡z<ž7ÞxãÝwß-**9rd–†ÀHTÒY¦28ñ÷ôÓO×××>|xîܹ’î»ï>£ƒ‹càÀ’V¯^}êÔ©Ý»wÏœ93•­ëÓ~øa¿ß?bĈ¶mÛfix€D oÆŽ{óÍ7—••Û»wïŠŠŠŠŠŠT¶ºîºëºtérôèQ1å WÔJyT]]­ÔVdçWdi*ñÊ*·Û-ÉçóEµ®,eý‹v.^¼xÁ‚:tغukóæ\9‰x¿nÀñ<5*i3qâÏÊNœ8Q[[+iæÌ™Ä)‰ñ1Œ;vË–-:t˜7o^`A$@¢`Ô²eËÒ½ª‚õçûÖ¯_Ÿï!°fýd"—¦ë#QE¢`¯O€T¨dˆ‰?ae:v¸œ[VYÿÜ "Q0GgüH,á)Å×%c%E¢¹»îº‹T€)Ò OY½Ý‰Ë£1æðˆY‘HTäG*)*÷÷Š‹ùŠIcéŠDÀ4VžøËÙì Ç$x?´òv›Ž-*cE½µü‡@¢`ˆu&þòµâ$JÒaà‘¦Ù7B%5x‰ €]¥¡|>_–FÉív'~Bi P¼ÓÖ*±–ƒwx3åfâ/Þá*7™)±Ächš·ïÅÁ‡™‚sÏtpŠJ ò]G¦+G+£r<ñyвB„JKÔ€“´` MƒTa¦¨xb¦+çE+ƒ+æi-6䘯ª¦l—¥bòù|„*û"He ô9/Zq&³ÈBu»DC‹,«GR¥B~ð©kú¡Åülm„DÄúùÏ>ªÑ"?MÇ–c–½h`¢¨#=AÊŽù™õ ¡y+¤Ð°a’ô÷¿«oß$í¶–úÄeª¼ÈR™ª²²Ò¬n­ÄŸ|òIS'6á$*À‘ o_ÍŸ¯¤çžS¿~Áö ôØcúÃä÷kÎMš¤ȆÀÄŸõ™¸òÉšá C¢Ì·nfÌÐÂ…’4x°Ö­ ¶OŸ®O?UŸ>ÁÇ¡ä¯=tØ ]¶Ê¦R<4R¦B–˜θi4pùùšp¹\j’`¬kšŽ-Ðâõzó3 ó—>Je(p¬²æÇëH=$é¯&ðLqGJý×mSì¥9`‘ï®ty<V¦E¢` ÿ’æe}-¥(Ý÷ÂõÓ‘'ýc1‰ €ÔÖožh‹n3;,ùýúÅ/Ô¾½:tÐìÙF瞘ºr0+ì`ˆDÀ*Œ”©ªª4z´ÉãÉ^·™«âÝÿˆÂ–$*N°i“FVÏžÚ³G’P³f ¬Þ³G={JRc£fÏVÇŽ*.Ö¸qúê«ðæ è’KÔºµ¦LÑ7ßDw+éÍ7Õ¯ŸZ´P÷î ‰¯C—KÏ=§®]åréòËÇ7¿_—]¦mÛ©ñÌÍœ©‹/VûöúÍo’tºÿ£Û­¹sµjUì"Þ{i*00&þ¬À‘;X¡!Q°œtËTõõòxtíµ*/Wuµ$UU©eKUUIÒÛokäHIš7O| ÚZÕÕ©eKÍšFÛ¶iß>:¼}Pd·’&LPe¥ŽWMÞ?ø„¾÷žjkå÷«];½ýv°ñ­·Ô¾½¾ÿýðÓ*+µc‡jkµw¯HÒmŠ÷Œù^`qì`ÀÕ€¸z‚Y28>ƒÔW­Ò¦Mzí5½ù¦V¯Ö+¯hÔ(õë§]»´q£ÆŽÕäÉúÉOÔ½»6m ^’¾®NèóÏ%ÉåÒÇëòË%ÉãѰa:xð[ÝJêÖM=¤oT×®á×MСϧÎ%iÉýíozùeIºí6]{­î½7|å­ï~W›7G/ÕŠ×íèÌ5k&IçΩE =ýQÄ{/ñ„Âk¼ßWOˆ”½«'8uË€E¾»ÒåñxHT@ $*³ä&QÝ|³FÖ¤Iúúkõí«;Ô¥‹öîÕe—é³ÏÔ·¯vïVQ‘.¼0ح߯sçäréÜ9Ir¹tö¬.¸@’ΞU«V:sæ[ÝJzÿ}=õ”ÞyG­ZiñbÝpƒ¤D†ÆßР=´w¯ü~]~¹öíSIIø Í›ëÔ)5ÿöµ–ãu{ÑEúì3µk'IGª{w54_. p1ô˜ï%Ħ"QEÊ^¢rð–.‹|w¥‹ëQ°œt×§Ÿ9£Í›ƒóz­ZéŠ+ô *+SI‰ÊÊôüóêÝ[EE’Ô¹³öï×Ù³jl KBöí >Ø»W:Ew+骫´aƒ¾øB/½¤{î 6&è0¤}{ýøÇZ³FkÖhäÈðMC=ìݽI¼n÷ ˆ¼ÿ£ßü‰÷^`}ì`@¢`o55ºâ uìücy¹æÏ׈’týõš?_ååÁ¿ºûnM›¦O>ÑÙ³Ú¹SãÆ…;yàÕ׫¾^?>F··Ý¦]»tú´ÎSccò#M™¢+´r¥¦L‰þ«‰õóŸëàA9¢ŠŠ$Ýîÿxè|>Í™,ž5Õô½$Æút+pðV8HT@\.×·~b6Zä§éØl-­2UU•F ÿ±¼\ >\’FŒÐÑ£áDõè£2DÇ«¸X·ß®›n o5dˆú÷WêÔI••1º3F7ݤ֭õè£Z»6y‡‘Ã8qBÆEÿÕO¨wo  K/UIº>]×\£>}Ô·¯~ô£¸wÔnú^`}ì`À:* —Ý#Éyy_‹ñšÔ¬ôê¥õëuå•é.ÝZV¼ÕT¬£ŠÄ}ýrÀ¾ë¨š'Pxòõ?êêjI½²q•n{Š\Ç“•—ÎR·œŠY?Vd»ÿ¡(p$*ëÓ£HT,ÊÈmþ ÇHT‰2` ‰ €uQ¦`$*À·P¦2@¢`”©rƒ+-#Q°4.£ÀHT€0Ö§™!Q°:Ö§°> ÊTM…½îGnA¡OÕ¦sý$*6@™*—XŸž"¢•)š~Œ;RÛwJ U‘å“Ð?”£©kšDmZš !Q°—‹ƒV.øýr¹˜øK"”ˆV©s^ !Q°¯×kÓ¹8^‚h%ÒUœùzÇ©æh­T¨é*Þò2ç©Û”©˜øËÀÄ23Z©IÎpÒžœxoqp !Q-QIÂI‹…DÀN(Såe*Ó¥°,²«'Ý 0BE!Q°%Žôp€˜×bˆbå]‰DH„£fnÄüœ­s~+»AR$*6Ã7; {»p£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨d‘Ïç“äv»ó=È.€QÜ)@.P¦*ª$P€¨QÈ.±…ƒß5 5*YÇ€ãQ£0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€QÜ)@A(--ÍÍ y½ÞܼK!Qpˆœe¦Ä’ƒÈ8‰ €]¥¡|>_–FÉív'~BÔ° X€3¨ØO¼,•›Ì”Xâ14Í[÷B®ìŽDÀf"ã”"TZ¢œ´ À.8×€-ù|>ÛÅ©¦ð¨ Ÿ¡Ê"ËêdŒD`‰ À(€Q$*£HTFq=*°ËžîÇÕGTP£$bÙ¨X 5*È3+_ç“«º)¢F`‰ À(€Q¬£O¯zf}Of¬¼f °5jTP@Ün7aÈjT@ .—+ßC0‡]®$ä_—ï ×ø|p(jTFQ£âŠ*œþsoÍjJÓ±Ù¥áõzKKK]ã-úÁ:\ãåv»YP˜‹€Q$*yXìe—¢šc°>0‰ ¬@6¨Xe*öE¢v¹ÊƒcÊTLü&"QE¢` \Ÿn©Ád e*À,$*NV»_½fæº[ƒQ,7IŽõ逹HT¬"eªªZ¾Ò̳ÚmY°#'Ûô¡F_©žiO’|©f·Ë× I{|êù$5žÓìõêxŠ'kÜ úê›ðæ 6ê’{Ôz²¦,Ó7g¢»•ôæÿªß,µ˜ îZö–t>ºÆ‡£á¾/tÃoÔvªŠ&©|¡êÛ¿>­‰KÕz²:Ý«_U…Ÿù`éfu¯P‹ úÁm;dÃt±>0‰ 0Ÿç®F­'«õd]ÿŒ<‡‚í~¿~ñ{µŸ¦wiözùý¶;žYeªúcòÒµßSù@Uï–¤ªZµl®ª­’ôö.(IóþKìUí\Õ½¨–Í5ë÷ájöhÛ3Ú·H‡Žèñ×£»•4áEUþLÇWªæq½¿W:SüëÂ¥¦yV?Qý‹ªQ}JõÐÚ`û¿½¦†¯´‘¶=£š=±ßÂæÚò„Ž¬Ð eºsyÈ1`¾±Ïëêžò¾ ƒKôÃËtë’`|K4IDATû²·´å#íú•v,Põ.­¬Î°ÝÁ̽ŒÂjx?]xʨz—$múP÷ÿXk%©z·ÊHÒÊj=w‡ºtPÛ"=s«^/Üâ ºä"ul§EwhÝ_£»•TÜBި~GËïŒ=Œ ôÏ}Ôª…ÚµÒS·èOÛƒí¯¼£ßÞ®‹Û©c;ýöŽØÛ.ª.TÜBÖÖÿKcôP¦Œ#QæÛãÓ쟪¤Xí[kÎ Áù&I«ÿGOߢÎ%r·×ÜÕªš Û‘¢ª­u¥$ í­÷>ÕÉÓzçcÍ£¿}¬“§õÞ§ÚG’¼ 0[Íïз«Ó½áY9I=.>¸´£êŽEw+éõ´y§Êæ¨ëýúÏbãÝO4ä—j3E®ñj=Y‡Û??ªîçûïþO±·ýN›àƒâ:ۘƆ)bÍ``ŽÈ‰ª‘µ°JGOêÈI-Ø,„HÚyPƒ. >.ë¡3lw6³Ö§ŸiÔæÁy½V-t…[/üIe=TR¬²zþ¿ÕÛ­¢ %©s‰ö/ÒÙ5j\+ÿ:[îdßÁ{ëÕé¢èn%]u©6ÌÔKõÒTÝó»Ø#¹e‘f\¯ƒKtn­Ž®ÏÞ^r‘öŸïÿá4ÞZÆÈ`¾Åµâm•LSûiZ]£%“‚í'N©MQðqÛV:~*Ãv¤¢f®p«c»àËhþè/I×÷×ü á¤{÷uš¶BŸÔél£vÔ¸Â<°FõÇTLk4þšÝÞ¶D»¼:}VçΩñ\°±¤X wòõiµh®Vjÿaݵ"Ü~ë`=¸V‡ë‹cáÅU©ÈxØXŸ˜‚D˜#rödÊKš8D ËÕ°\ã¯Ñ¤¥Áö6E:q>ÿZm‹2lwu‹.*V×ûÕo–®î\˜•ŠŒ7=.áœ>¤Ìår©É“À2•u'E“tt¹Z^(I§Î¨dšN­’¤«+õô-ÖW’ÞÚ©Ç_×–'2i1à&c ´Ø÷~y¥¥¥2¶Ê§×L­ÿ¹®ìnÖˆ²ÛíŸF.ÔÞçr·a”Àãóù¢Úµ+ûîH@nx<jT€9" *}K5ƒŽœÔ‘“zfƒúu ¶O¸V½¦CGäkМW5iH†í…ÃH™ÊókóséÝÞÿúÇ }~D¼¬åbCYÒ<ßhÝ ÍX¥…U’4¸§ÖͶO¦OëÔçIš~¦Ͱ½x½Þ@™ÊÙ®è¬Þèäiýôúå͹Ø@–0ëÄ`pÖ/÷œ7ë'3&þ–˜Ìú©`Ö€ueã6%$*€ÄecHT¬‹2» Q¾…2 L•œdŒDÀÒ8Ë €-¨a¬O2C¢`u¬O`}$*@ ”©€´¨Øeª\b}:îëÄóøm僺•ÇÎF €sƒõé@º¨Q1äëâÕÕÕ’zõê•—W·8¯×¸w2X5*£HTlƒõé¹Äút -$*£HTì„2U.Q¦RÇÊt¶D¨`)Ô¨‰p³j אָ xD À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢0ŠD`‰ À(€Q$*£HTF‘¨Œ"QE¢,dèС’<O¾H‰ À¨æù€(S€½P£¬%0ñ°‘¡C‡þ?QÀî¯(¶IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/tutorial-data-model.png0000644000175000017500000000431410010213367025635 0ustar frankiefrankie‰PNG  IHDRŒuœ] ïbKGDÿÿÿ ½§“ pHYs  šœtIMEÔ (;îtEXtCommentCreated with The GIMPïd%n0IDATxÚíKLSOÆ¿K/ T@^myk\˜®0`ꆅqA"îŠâÆÔFcˆ‘׺2ÆwF\²1AÒ…A#`x¨y(i(Ðrþ‹¸¡XÚ"òhý~›f˜ÇÞûqæÌÜ9SED„„I o¡`C(BÁhGÀY H  4- Ùj05‘tØQú0„N/¡`C(˜ƒæˆ fßEaþ#‚á²À> fdd.\@RR:„óçÏÃåriù«««¨««Cff&RSSÑÑÑ¡å½{÷………ˆ‹‹ÃÑ£GñäÉ“ñx<¨®®FJJ RRRPSSÇãW¦½½F£z½×®]Ãòòr@ËàóùÐÐЃÁ€ÄÄDTTTÀív‡ìûzŠ¢ÐÒlW0eee°Z­p¹\p¹\8yò$jkkµü¦¦&ô÷÷Ãn·cxxãããZ^ee%ššš°¸¸ˆžž|üø1dG155…¡¡! btt÷îÝó+ÓÓÓƒOŸ>addN§÷ïߨVKK úúú`·Û1==øøxܾ};dß×­”ˆÐb³æÿߣà¸ÝnÉÌÌÔÒ¹¹¹200°l~~¾Øl6“pÉÎΖÁÁA-ýõëWÉÎÎÖÒdhhHK HNNŽ_þ:Òß߯¥¿ÿ.F£1¬¾‡s/¢`šØR0>|³Ù,z½^k@Q-_§ÓÉêêjÀF{{{¥¬¬L222$//O^¿~²“:N¼^¯–^]]UUý¾D¨üuTUN':Nbbb¶Õw æ“››+/_¾”ùùyY[[“Ÿ?ú• ö_º‘·oߊÉd Ë„² ›ósss>è¼¼_ÈqÑb± ¶¶333p¹\°Z­°X,~enÞ¼©ùTV«—.] ØÖõë×Q]]oß¾ÁëõâóçϨ¨¨«ïGŽÁÀÀ•íú0]]]rüøqQUUŽ;&=ò+·²²"V«UÒÒÒ$55U:;;µ¼/^ȉ'DUU),,”îîîª^ZZ’ªª*INN–ääd©ªª’¥¥%?Õ···‹Á`ÄÄD¹zõêoùëø|>iii‘‚‚‰•S§NÉ«W¯ÂêûÇåðáÃÿ´¥ fa´ T‘<+¨ª–%#á/^Fí*»Ý“ÉÄ'½¨aù~§ÖíÌ™3hkkãÓÜ‹g CáD"íÕ! Ù;§—oo#›¿å£ÒÂÝVs6™3ú0„N/¡`C(B"M0½y®ùP0œ®S0ÿ,>IQØl6äççCUÕ°,ÌV±A¡bEAkk+ÒÒÒ`2™ðæÍ´¶¶"==&“ ïß¿çÓ>‚ Ÿ½½½°Ûíðz½Û²4›cƒBÅÀôô4š››qùòeLOOc||ÍÍͨ««ãÓþ[£ÂØ¿Š ÑÁvàOMM…½4ØÎýP±FdvvVDD<ÏoiNÇý¹{¹§w«M5ªªÂãñrE Û7ÙX6P½ØØX?ë³¶¶EQ°¶¶°N¨ô¿B°ÍPRgÇCRVV†‡‡wý‹geeatt^¯>ŸO ‰0&XŒÏŸ(6(T¬‰&XŒÏvÆÎeÅ…Š5Ú|­Piú0ûäÃú0„lITÄ%‘( …ÁY¡`¡`C¢Öé冨è™@ÐÂN«£™ý¶Ö´0„‚! ¡`C(B(BÁ †P0„‚!L¤ñôéS$%%ñ­ø°'a&»¢’““ƒîînîÿ ÝåÜíÞË¿f‚‰‰‰90a³Ñ.˜ˆ’EÑhD]]Ìf³öóÄëgȈÈoçÉ(Š‚ÆÆF$&&¢¸¸N§3ìk=~ü0 èêêÒò&''a6›³Ùì׿Æëoî˯_¿pñâE$$$ ¨¨ôav› ££‹ÏŸ?×þ‚ýÖ´×ëÅìì,Ξ=‹;wî„}­±±1Œ£­­Í¯^}}=Š‹‹±°°€¢¢"ܺuKË Ö—††FÌÍÍ¡¼¼õõõíÇì(¶z·â{7×w»ÝÚglllȸiât:EDÄétŠÁ`ûZsss""²¼¼ìw®LzzºÖæÔÔ”ßïxë‹Éd’ÉÉI™ŸŸ—ôôô=‹•F$ÆVïÔ‡Ù8ìlü æ7(ŠŸÏ‡˜˜ø|>ÄÇLJu V°¶u:VWWƒ¶¨/ëgç:׆>ÌbffðãǤ¥¥í¸½´´4­M—˵e››otNNÜnwTœkÕ‚±Ùlðx<°Ùl8wîÜŽÛ+--Egg'<:::PZZPT}}}~+//ÇÝ»w±¸¸ˆ±±1TVVÒ‡Ùm&Ðg(¦¡¡AäôéÓ211±ísj6§‡”””Hll¬”””ˆÃáø­~{{»èõz¿zn·[*++E¯×K^^ž<{öŒ>Ì~®ÃìÇzÈ~.1Ї!ƒú¯}ažQCÁlKgI„‚! ¡`CC(BÁ †DâèxB Chaþ¾¿¡…! ! ¡`C¢w–ĵZBþ¾…áZ ¡…! ¡`C(BÁBÁ †P0䀢­ôò¡…!ßÂð¡…! 9üñ\8¼aâî°IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/apm-upgrade.png0000644000175000017500000010057510014674771024213 0ustar frankiefrankie‰PNG  IHDR­P8£sBITÛáOà IDATxœìÝwX×úðwé ˆ ‚€ ö‚% 6ì"&D¯±ÄhŒM¼Š±{Mò‹1¹^cŒMlQc‰%(vlXQAED@A±P—Ýß#sÇÙ²;»ûý–iè÷XL °:H¬Ò«ƒ{@˜ô`€a°w#U>¤ ¡'õîݽ3‚{À`”J¥©C­`4t þ•¿L&3Z$PH@[ZþvH&X¤Vi耽7@›,¤Vi€ÕA`uX¤Vi€ÕA`uX¤ ™L&3òŽP¡dJ¥ÒÔ1€Ô1½ù½{÷ê´ûs¸Ƥ£ L&[³f~ûê½#T(;Sfƒýv_KL°fÍ™ ƒNÒ‚þˆ)ÏPkôèÑ„©AR‚IA ÈP7øbj€Ô`4ö9?¸Ò¤i€ÕÁ¤ «ƒ4Àê °:Ht`Ø[fLi€¨¤úe ñññõë×ç/8p iÓ¦ŽŽŽÁÁÁûöí+g¨B5jÄ‘uðàÁ-Z8::6hÐ`ãÆÌÊôôôþýû{xx899uèÐaïÞ½·Œ†=qÈ÷Àâ! Š}ûöõêÕKe9..näÈ‘ßÿýóçÏW­Zõé§Ÿž;wÎà‡>wîœ\.wpp8{ö,»2..î“O>Y²dÉ‹/8pìØ1fý€êׯ÷îݼ¼¼yóæýøã‡Þl £ÁS³ÀŠ(AkDôÓO?Õ¬YÓÞÞ¾E‹W¯^U¾ÙqäÿɬY²d‰···‹‹Ëðáà ÕÞºu똘•å>}úüòË/ì6ëÖ­‹ŠŠ/V.—OŸ>½ZµjÎÎ΃ zùò¥HðŒÏ>ûlþüùK—.=z4»ò½÷Þûõ×_ùqÚÛÛççç‹7TAAÁÈ‘#+W®\¹råQ£F°1|ûí·¶¶¶J¥2??èС...>>>Ë–-ã^l ¨ì"R;µ­!É‚ƒƒíííkÖ¬¹fͶ¥º3¨±:DäååõäÉf}qqqµjÕÄ›À´0 ›˜˜˜S§N={ö,**jäÈ‘TÖqdZ“ÿ'ãĉ×®]»ÿþ£GfϞͬäÎ<ÉÊÊJJJêØ±£ÊòéÓ§ß}÷]v³wß}÷ôéÓâÅ.Z´èâÅ‹ñññ™™™ŽŽŽÓ¦M žˆŠŠŠ¶mÛöÑG 2dÇŽEEEÌú3gÎôìÙ“ß!!!sæÌ¹ÿ¾H+Íœ93##ãÎ;III)))³fÍb_:þ|||¼\.'¢¯¾ú*777%%åÚµk'NœPÛ*»ˆÔNmkE2tèйsç¾xñâĉ.\àÏ?ƒ«£T* ôŸÿü‡YyôèÑ6mÚˆ´€é?ó0_D”Í,¿zõÊÎÎŽ]¯²™ÊŸwîÜa–ýýýù›­_¿þ_ÿúÙÖÖV.—³›ÉårîAÕ[³fÍ7n0Ë?öññ~ûöí]»ve–#""¶mÛ¦öЬ´´´O>ùÄ××·J•*ƒNOOçoãçç—””Ä,ß¾}ÛÏÏ!##ƒÝÌßßÿîÝ»Ìò;wØá¶€Ê."µSÛB‘~÷Ýw<à†Mo¦s:U'999  ¸¸X©TŽ=zëÖ­üf¤:êîkLØþtII ÛÿæêׯßúõëùË^^^™™™ìf™™™ìl¡bíììlmmmmmmllˆH&“‰Ù«W/vòÏo¿ýöî»ï2ËU«VÍÊÊRÛŒG?¾}ûöü—¸)76•T6c_å¶€Ê."µS{D¡HΟ?ß»wo//¯€€€]»v©K|¸¸¸øÞ½{ÇgvéÕ«×ñãÇ ³³³—,YòÖ[o©T‡ˆ 4qâÄ'Ož0± 4HíÑøÅ_dgg?yòdâĉüÖà©ÚÖŠdРA7oÞ,..V(¥¥¥*GQ9ƒZV'44´R¥JÓ¦Mûè£Ôn !¦„0O$0¯fÁ‚®®®BÑÒ¥K™‡Ø|üñÇÜçÌ0 &L˜7o™ñ×_1Ï´iԨў={¸GW[liié¢E‹˜'½õÖ[Û·o ¾yóæÇŽã®mÞ¼9³¼ÿþæÍ›;88Ô­[—8´oß¾Ž;:::V®\¹W¯^ìä~nùÜGëŒ9’_eÆ«W¯† âìììíí½xñb{{{~ ¨ì"R;µ­!Éï¿ÿÞ A;;»&Mš:tHåX*gPËê(•ʽ{÷Ö¬YS¡P(¤M¦Ä³Ò+3]dƒúõëoݺµE‹*Ëå,ּܾ};22299Yûà’Hküøãééé .4u H¢ódÙ*¨‡*‘Žo9?~îܹÅÅÅ£FªW¯Þ7ß|£_9Rh¼¼¼¶mÛÆÄÄøùù™6po˜Rƒ 5jT¯^½Ê•+Ï›7ÏÔáèO&“U­ZuüøñÈÀ,˜þ;T02ŒX¤`2[‚ƒM€•²3u`-¸þÁ *+Ù5`¸7ŒAû/þ‘Ò06¤&‡4LL›¬ù€a! ©@>`4H@ŠT(¤ uSäºBfù€¡ ³$ž ‡4̆ô€4,òí! „)Câ€%C> Ò° ˜2À…4¬~• €4¬ò°rHÀª! ²7{©«üiÁ̽¦ÚÄoîu€ŠcgêLI¥ßÃ]ϮᾄJA#¡^zcåÁ}Ú¹¸x6jÔxÄ¿ÎM’öSïêÚ•ˆÞ?vÌÆÁAí±jÏ»A›yóêôëÇ®tæÌ±Q£˜e¼LËÆÔHÂà„î?Hì?`*ÿJm fþ3jpÆ¥òvy~~Ö¥K±Ÿžv옩c1± =S©‡={VôìYê‘#â[Šœ;gçû{öp×ÜÛ±ÃÎÙÙÀ±€^üóo*?àÿ[‹|Àø˜wbß“'ƒz÷&¢›kך:"KvgëVfánÙŸÆ3‘ÿ2-ù³(77íèÑ€=*&dÐ &¨¡2YHep€Ûû7Ј¹xúÇÅÅ/[ö0&FQRR½]»iÓ*ùû3¼|øðÒ’%™çÎÉlm{ôh9}úöÖ­‰w}ö?wîòŠcbŠóò]»FDÏžMüí·¬K—%% 67®zÛ¶ìq_¦¥Å/]úøìY‡€ðð–S§ª Lõ(çÏ_\°àááöÎÎuúõ{kÂ’É´Œ“OÞë­·%%Y—.=ON®\»¶ög„U;*êþ_%ïÞÝìßÿ&¢û{÷*JJjGE© €I £ößWµÓ‡€~NO›–qü8³œóôÆÈ]»ÜÝ‹rs|ôQÁ“'ÌK÷þü³ðéSõ%LÊ–À8:r$»œ}åJìèÑ=¶lñ &¢¢gÏþ:4?3“ˆ¨ àÞŸäähçÙéÓÓŽ%"yaáÍŸvññ©?x0i§–jåÍ.¬Hi ¹¼õë¯éÇ÷øýwµ™€­£cÕ&Mž\¾œ“àÓªUq^^nR=KJ*yñÂÞÍíiB‚R¡ðjÒ„Ét"tú„Üݶˆê¼ÿ¾ÌÖ6nÖ¬;Û¶…LŸ.v¤Â§uëJ¾¾÷ÿú«Ùر$“ÝÛ¹³’ŸŸO«VºÆ“‚̃LSháø3…ØAjça¾hïyròÛü1ðÊ•·ÿݵFüÌÌ›ëÖÑÍuë ž8pàdt´M§~|çm‚ÔXë{;vQû•+ktëfïæfcgçÜ~åJ"zøÏ?B¬BeÝý¬‹‰¨ùøñD”ué»Þ;$DcCñ >µSHíCH1eÈŠÈd¤T* ™Íÿ¾gQ*¯_âñnÙ’]®JD¯ÒÓ‰èez:Uã¾ÊYæªöæ×ÃÊÒÒÛ7¦ìÛ÷"%E^ö nAv6³ÀË?¨FUêÕcœ<=‰H^PÀ-P›8µŒP#;gg† ÁÌï/íyJ ùwé"Rà™iÓì\\ºüô7rmšQ¤ÖywîÑ¡ø‡ËôH(’j-ZÈlm™î~æùóÎÕª½ûnüòå™.QÎõë2[[¯-Dê"Dèô©ÅÜ\ûý÷™?ë p{Ó¦»[·ÖîÓGíö*gD…[``µ-R&™¬ZË–®zÄi€)•§ß¯ëÆÜc!0ñÛˆù¨,#°Tö®®%/^åæ:U­Ê®,zú”ˆ\]u.ŽûÎØÄÎɉûçå+noܨ²¢¤DçC«bk+ú²æ8YzG¨ö]£¡4-¾"Q*¥EEE¹¹:)\k‘ÏV…\.ô’½««GƒOoÞ|žœü,))¨wo’É|ÃÂ8ð2--ÿñcÏÆí+UÒPu4œ>ŽÜÄDfVRÌÇs×g_½ú,)IeÚ–Ÿcµ£¢ÎÍ™C L 2*ñY:Ê7öÐj‹Å|!ƒ™)ÄݵîuêÑã3g¸+3NŸ&¢Êuêð·ÏŠg—Ÿ\¼HDÌ“‚\ýý‰è gªÌ-¦Í3=£ýŠýãâ߸ÑÿÜ9î«L±üƒêM8Å#Ô•xi•ƒ‚¨lž•–Ó¦)JJN~ñ÷Ž^mšQ¤ÖÌeðîž=ìÛŸûŸH0̼ [ë×+ ß°0"ò SÈ剛6‘ð¯1æåû烹9X­;Â/‰ |ç;'';''îœ+09¤Æ`’~¿‘|À8X*ÉqòÜRlÁj¾óÅ/[–+/,”¦;vyÅ "ªÙ³'û‹óçç\¿®Ës®]»0>13+˜y,æÏš ËŸ&$0¯jTZTDD¶ŽŽ¶ŽŽ/ÓÓÏÏË}µF·njª7=âPWâ¥Õzï=&¼ä]»Šóò%%ÙW¯ž7Ž»MáC[Nª,-=;}:3§_c±k]Ð "Šýì³û{öä?~¬,-U¿HI¹»}ûaÑGô0ýû{÷’LV½];"ªÞ®Éd÷þü“Ê’!ŽîîD”yá‚Þ™€™MTL ÷ó**&Ffc“²w¯øl"!ö®®\ºôÁ¥Kú e@Á¤  ¤¶c-y8l$lœÌ‚t"4G0ª²%c¡íÁ\Ô8ðÁÁƒÙW®;–»¾Z‹õäoïtˆ³ÞÅLJ¹Ï²ñˆÌÄôƒ|À¼ä×¹ó‹4Îîðmß>-&†íéúwîÌ}µÑ'Ÿ¤ìÛ÷"5•=¨_çÎì¯;éA8Å#Ô•xiõ?ü0ãĉÇqqq³f‰ÒpØ0¥RyyùòssçÊ |ô‘x±k]ûý÷ŸÞº•´yóÙ/¿Ô©:ÌmŠ’ ˜yeN^^UêÕ{–”DoÞÔÁçÓºuêáÃ1Ç3êñI’rà@ÉË—¾:¸T¯Î]ïR½zõví>ý`ÿþ:ÿú—®Å€4a4 ¢¨äFþÊ_'*±a¦Pùi32 ²1Æ,†½}øºuÍÆ«R¯ó]r•zõš×í矹óaµ_¶¬Nß¾•+Û9;×èÖ­ûÆîîDäèá±i“—.vÎÎîîuúö 1ƒˆ˜WE´ùúë€îÝ휜ÜÜjGE…-]Ê}Õ±J•î7ÖèÚ•-¶ý›èJ8Å#Ô•xi6vv]Ö¬i1y²Gƒ¶ŽŽvNN>­Zu^½š_N£?n1y2)•—–,Iøï54£µýòËn?ÿØ£‡‹­““{:õ è±e‹Hu==+תEDÕÛ·gWú¶oOD•k×vôôÙ7dÆŒ€ˆww½ŸÈùúçúöå¿T§_?*Ǽ ™4;¦fÛ6Çæå'0¦ŠÄbp;ôÚ|?§6Àå,R+y×®¸Y³¼[µê®õ#öMÂ\â4,ë¬5˜5Œ÷!„4 œ¬- (O_ß,ZImM¹a‡ÔkðÂ@âèÏ g‰§–ÔÌ*( äV i€þ¬m(À:©ä&?Ý— ~’ Àš ÐÒ«"©ÁŸ Mù€@ 'Iu Á8¤vÒ+: ä– i€ž0`¬0àÈ8G€ …4@OH¬–Ô22b2@È,Ò€×ô{&ZÏ:I3 4f2@ÈÌœU§æû‹W`rÈÔÔøGýؘ:c“q¨¼¤Ô‘IâI)g&ipƒØþ÷–à`µô :¨J¿Ÿ9ºq-±§Ã„çŪ. ]+[qcvÍn€8ðgÇŽ*˜¼M€cB]ŒÀ\ªii€P×ÝzÐ{ÁH- ^2`äãšQ>Ÿ™yê‹/v´mûG‹G† IeÖ0ÚGgÎ5jkË–;ÂÂÎL›Vøô©øöúZšÍ  ‘RS—W®ì´jó9&¨ÌšËø4¶¹Æ ,3 ½‰ûúý`(¿„Œ?,À=´Yä§'Mr ê}ðàçÎ57.é÷ß ~ˆÛë×7:´ßéÓ½öí³ws;=y²Á`¾$8{0?3Ó«ysfY‚áp•ÿµ´4@ãl“D`&™#Ä@²ù@ÎõëMFv¬RÅÆÁÁ§M›®kÖPÙw'Ü•¥¥W¾ývgÇŽ[CBNO™"/(`Öo ¾¹nÝŸ;n ‰›5KQ\Ì?D×µký:v´svvòôl1yò“Ë—µŒmKpð­[÷DDüѼùßÿú׳¤$f}ÆÉ“ûûôù£yó=w·oWðË´´ãÆmkÕê-Ž-2!RµÛ7îÿ½Y3~`Ü—ôn¡ ryü²e;;tØÑ¶íí Äãä·?Zµ …WZXxöË/·…„üÙ©Ó­_~ánÏ­µ`ðÅÅq3g²»klg¡íUbVªN Èʹqcw·n‰¿ý&R‚P#èwööìùüþ}"zõèÑ–&M ²²ˆèùýû{{ö$ÎÕK¼Ï(µ×¿J˨ÝFmœâapË$¥rK“&ÜÀ¸ô¾…Z[¨Z^ÜËRäj×òÃD…P jë¢Ó‘N—´Ú8…N„Úà7ˆÞþ\jë¨ö½,tÒÕVŠRø²4€ÿÅ?ºþ SÍâÇ µ|À38øÚêÕ/ÓÒ¸+™ ¹Ñ&¬]û4!¡çŽ}Oœ°up¸²r%»qÖÅ‹‘»w¿wäHÁ“'×~øAüpÏœ©Vö-£6µÎŒ‹‹øí·;~˜•ggÌh:vì.t߸1çÆ µ;¶ÁGõ;y²ßÉ“îuêÄ/]*t‘ªå\¿ÞsÇŽA×®ñ÷⾤wãy}õê¼;wzîØñÞáï=“ßÚSÞµU«Šóòú9¹{wÖÅ‹Bµ þêªU…¹¹}މܵëñ¹sÛYh{mBÕ©ÿù'ö³ÏZÍ™Ó`È‘„A¿³àÛ±cæùóD”këà~ü8ež;çש» ÿ&ë_…ÚmÔÆ©MB‘pé})м+ÕÖBËkCä}ª±¡4Æ,ƒÚºèôA¤Ó%­6N‘OmHáíÏ¥¶ŽBïe¡“ίÿ¤¨9®÷ÅJ ¿)MXóºð67nÌþgêXÞÆTQ½zü8nÖ¬?;wÞÞ¦Íé)Sò33ÙØ¸›íîÞýÙ;ÌrAvöÎŽÙÍž?xÀ,?¿W×®"ÇʹqcÏÛo³Û U–]¿¹qãÂÜ\f¹¤ `KÓ¦¯ƒ ¿½qãËŒ µ{ñ•ìèÐ_¸Æªåge EÈ}IׯQ*7È]]»>¿_e¡£¨m •hÕþ)Þ®®]_¤¦¾^ÿàw{¡Q žS¬ÆvÚ^%f—™ÆÜܸñÍuëvuíš“ M-Ô6‚~g!ýĉS“&)•ÊccÆ\^¹2ö³Ï”Jåɉ3NžTª»&Ù?Õ^ÿÚl£6Nñ0TŠå/—³T¨¼+ÕÖBËkƒ{YŠ\íÚ˜piƒÚO›étI«SèDpIüíÿFuÔÕQ转ö¤kù‘Ë?ÆœI²T¾û7a$`µ”J¥o½émKp°i§½ª `–˜‹O›ùó‰¨0;;aíÚS'Füö³üÌÌ}û)•J…‚8gÜÕßÿõB@@Av¶Ð2ÏŸ›9³ãwß¹2k´®ò O IDAT©£c•*Ì‚““²´”YîðÝw7~úéÆš5¶ŽŽ¡_~Y#<œ¿cöÕ«WV®|zóæëÑgáKT¤jÎÕª íÅ}IïÆ ² ;Û5 @Ë8µi !jÃ+Èήäç§²¿ÖbÁsŠÕ¿ÐöÚ„ªSÑ­[kEEy6n¬M-Ô6‚~gÁ§U«‹ È ³¯\ [¶ì¯·ß–æ\¿ÞnÑ"¡ú2Ô^ÿÚl£6N½ÃP¡÷¥(ò®T[ -¯ ‘÷)—~&B1hù #²™N—´Ú8E>y´!…·?—Ú: ½—…Nº6ÿñd®i€ÉÄýñÇÑÑÑYYYJ¥’»l긬Îà„î´W“ßÇÏØ£ÅæäåÕ|„mÛª}Õ¹Zµ[¶¸øøð_z™žÎôì_>|èìå¥v÷ÿ}yùòN?üÀíé­j“&W¯&¢Œ“'ãfÍRÛñ=õÅ-¦LñíÐÁÁÕµäÕ«ímÚ•&R5-éÝ8BA:{y½|øÐ-(H›£hl ™­mia¡­“={¦1<§ªU_ed0ÿô¾LOªµXðœb5Æ/´½ µ¡êÔ€DÔ}ãÆ˜?vpumôÉ'â%5‚~gÁÖÉÉ-(èΖ-žÁÁnnžÁÁI›7»×®mëè(TßrR§¡ÂÐûRÔþ]ùú@Ú]\"W»ZcŠA˺ˆl¦Ó%­6Nm>»$þöçR_G÷²mþ=âÈüî àÞ`H#—lÃéWÈÔ©SwíÚÅœ2î²}›n1¤p·ÿþоy öóϳ.\(-**ÊͽùóÏ 2ëÜܘ» õ 87{ö‹ÔTeiiÞÝ»§§La_º´dIáÓ§…OŸ^\¼8¨W/þ!noØpeåÊn?ÿ¬’è]©ÓS¦äÝ»§()!…B©P¨ ¸´¨ÈÆÞÞÎÑñezúù¹sEJ©š–ôn¡ kEE]\¸0?3³øÅ‹K‹‹Emkpy4lxkýzyaa~fæ…¯¿æ¾¤6¼š={^Z²¤(7·èéS‘{*„‚êÕëÒ’%EeÅjl%¡íU¨ U§$"Ÿî6ÜûóÏ„µkÅKj½Ï‚_ÇŽ k×Vo׎ˆ|ÃÂÖ®õëØQe•k¸<„âÔ& ½ רÚ¿+Z^\"W»ZcŠA¨.ÚétI«S›Ï.‰¿ý¹ÔÖQè½,Dm¥TN ÿ@f6`I €I˜°ÝÒÒÒÚµkÇ_¶€Si¦UÚ°Ëhãõ ¸¶jUöõë¶Þ!!íW¬`Ö7>üàÈóó™Ã59’d²£#Fde¹×­}äùùï¼ÓtìXþ!â—-#¢}½{³k>¸pÁÎÅEï˜ktíz2:úEjª{íÚaeÿP©ÜváÂKK–œš8±’¯o£áÃüý·Pi"UÓ’Þ#dÓÏ?¿¼bÅ÷ß'¥²ÉgŸ‰Emkpµùú븯¾ºþÓOÎÕª592õðañðš~îÜÝݻۻ¸46ìÑ©Sjk-üرæÍÛaïâÒhøpvw¡ø…¶W¡6TáìíÝý×_ÿ>\YZÚdÌ¡„Aï³à×±ã¥Å‹™þwõ°°Ë+Vøòúß*×pyÅ©Mz®±´W2´¼6¸D®vµ4Æ,ƒP]´ÿ Òé’V§6Ÿ]ûk<"ïeµÔVJ夨9ÿNÉb«jê@ ‰­ýôÓO5kÖ´··oÑ¢ÅÕ«W™õÅÅÅ'NôòòªR¥ÊÊ•+™•#Gެ\¹råÊ•GUPPÀ²hÑ"Ÿ]»v-Z´ÈÓÓÓÇÇçСCZ.??èС...>>>Ë–-ã·6÷šc×|ûí·¶¶¶J¥299¹OŸ>®®®ŽŽŽï¼óNff¦R¸—Ì ImM¥Ï®IéÜ7,Ää7«%‘0¤Iâ£MxyÉÉ{zô0B0âLÛ’i2£·¿öôþ 0›IAÖ0sêÔ©gÏžEEE9’Y9wîÜ7nÄÇÇ'''§¦¦2+gΜ™‘‘qçΤ¤¤”””Y³f±…dff>|øpáÂ…C† ÉÌÌLMM]¸pá¤I“´<ÜW_}•›››’’ríÚµ'Nð÷R¾™K0Ο?/—ˉ¨wïÞ̼ÿ¬¬¬ÆOœ8Qe/µ%ÕŒÀ´¿-  ãÏ«uqѢ⼼ÂììËË—×èÖÍÔᘬ“^ù2séU3i€¹D«=™ìõ)ÉdÙÙÙU«V%¢üü|ww÷’’" ˆ‰‰©_¿>w/ÿØØØzõêQbbb·nÝÒÓÓ™Brrr<==‹ŠŠœœœØåJ•*1}t‡«Q£ÆñãÇëÔ©CDwïÞ­W¯¿ÍÙBØ?322|}}ùµËÏÏ ÊÊÊRÙKí²ÚšJŸ%]™Æ¿7WoüÀø1›üiKR&ñÆ /é÷ßoüø£¼°°F×®­çÎ-Ï .ƒ0IKJ­ ÈŒÞþÚÓûƒÂ<ÒKêi©àöËUúÖÌŸvvv………vvoÜÅaggWTTdkkKDr¹ÜÙÙ™éÄkìjks8nÉöööÚ¤Ü?ãââ¦NÿêÕ+æU…B¡Mljk*}vqr»×RîÆ±¤˜#3˜dåO’ñõõMNNVYéããs¿ìÖïäädŸr<ï_rJJ ³Ì.è¤ÿþcÇŽMKKS(yyyÚ÷ÕÖŒLšùBú1ƒ4€a1ß¶êjذaãÆKKK{öìYtt4³rРA'N|òäIVVVttô Aƒ u¸~ñÅÙÙÙOžÌn°téRŸJ•*}òÉ'EEEÚÄÀ¯ÝþóŸ   ‡–-[^»vMd_~Spݾ}{ÆŒUªTñðð˜9sæíÛ·™õ6lX°`¯¯¯ŸŸßÂ… ýõWí¾\”eŒp,sg¦?6¬+Œ€…1³4€Ì0`æö)gΜ™‘‘qçΤ¤¤”””Y³fñ÷Z´hÑÅ‹ããã333§M›FDK—.ŽŽ–Ëå%%%“'OþöÛo‰¨wïÞÑÑÑYYYYYY7ž8q"[HffæÃ‡.\8dÈÌÌÌÔÔÔ… Nš4‰Ýàĉ×®]»ÿþ£GfÏž­M |111§NzöìYTTû=½Ú}ùMÁ=‰‘‘‘Ë–-ËËË{öìÙÒ¥K{öìɬOHH e–CBBÊñ¬RkzÂ:Yö!*ÉYG­Àò˜Ód.óš¤2Æßß?66¶^½zD”˜˜Ø­[·ôôt•]‚‚‚öïßLD™™™Í›7üø1 2$44T¡P<~üxÙ²e*{åçç12™,''ÇÓÓ³¨¨ÈÉɉ]®T©’\.g6¸sçNݺu‰())©[·niiiÜh…bP©ZvvvÕªU™£»»»—””ˆì«ÒÜ?ÓÓÓÃÂÂRSS‰¨V­Z§OŸöõõ%"[[Û’’"R(LüºžvÙ,®3e%„¸0YÌ”¹¦dV;•¾¯]QQ‘­­-Éårggg¦ëÌeooÏ~w®P(d2™B¡ ¢;vÌ™3çÕ«Wlذ!ÅÅÅM:5>>žxÃlÉ=¨Úe™L&—Ëùa°Å R5ûŠÜðöÛo·iÓ†ÍX¹råùóç:DDîîî>¬\¹2ååååææêv8á±Ë¿f¤Œ™¦VÆØ±Ì‚ßêÕÆˆF2ØŠ³¬­@:ºtébêÀ ˜qÀ0‹Ž4àøñãü¯á¹Ïœ9S£F •õ:t>|xAAA||ü/¿üBD+V¬xûí·ÝÝÝ_¼xáîîÎöò5¦ÜÑ€ððð‡r7ŠA¤j÷Iœœœòòò‰¨°°°J•*Ì]aaa ,èÖ­=ztöìÙ§N I#óJ’ñÞ?—Õf ä H@œ©(/¶GKîÞU©R%11±AƒÌŸƒ š8qâºuë”Jettô Aƒø»Œ3fÔ¨Q«V­ JLL\¸pá–-[bbbrrr>þøc" ½~ýzÓ¦M œSRRf̘¡S`&L`r‰èèè?üP›H»G í«ÒÜ¢‚ƒƒ/^ýî»ï7nÌ®¹råÊ¡C‡RSS‰hÉ’%?>uêÔÉ“'>|¸téRf›eË–åääœ;wîÈ‘#§OŸÖx”•+W&&&:t(..ŽùÖŸý?@è DtòäÉÝ»wß¾}ûwÞ™}ÚÝݽQ£Fwä @o¸EX î¶r¸†ºEXMɸiXGfz31ûÕ»‹‹Khhèüùóë֭ˬ¿|ù²··7ójË–-wîÜY«V-"ºwï^ÿþýããã‰($$dçÎAAAD”œœÜ±cG¦7¯r¯0ûghhè¶mÛj×®­ƒÚ…êïïãÆ "*((hذáƒTêõøñãåË—=z´°°0<<ü«¯¾òññ!¢6mÚlܸ‘ù¹ô'OžDDD\¹rE¥¾ëׯ¿xñâêÕ«‰èóÏ?oӦͰaôÙ@{¸EÄÙ™:°^]Žaúµ±fÑ59þ@й¤RBsñ¹]ÛììlvÒKÍš5srr˜å'Ož0ËÚÌŠÉÊÊÒ~òŒÐA‰ˆÉˆÈÙÙY.—ó÷­^½úÊ•+™#þðãGÞ½{7=~ü8""‚ˆ”J¥B¡àN/dëÛ·oߥK—>{öL©T;vlÉ’%Zî`(HÄ0?†çëTdúÊ̺ ½¼¼>|È|럚šêååŬ÷ööæ®g··³³+,,trr"¢ÜÜ\v½··wjjªÊh€®Õ‰··÷ôéÓ5jÄþù×_ùúúŠìâîîÞ¥K—;v(•ÊðððÊ•+k¹#€¡àÞ1È· ”‡%Ý<5wîÜœœœìììÙ³gGEE1ëßÿýÙ³g³ëÙí7nüÓO?<~üxÚ´iìúþýûÏš5ëÑ£GÏŸ?g·¯\¹ò½{÷´?¨6†zöìÙ¢¢¢§OŸþðÃMš4aÖôÑGS¦LIII‘Ë剉‰BOF8pàï¿ÿþÇ 8P§ i€<,È8 ”“eÜL4ö­MùûÊÆ"Ðþ$"0y@ÈLù€¹Câ” F¨&JUhJÀ/\c±˜ &…4€ ˜n0SH@Ò°ÚÁ#dA÷ã:l噀DÒB&`R0;H@Òƒ‘à¯ÇøÃ Ìô Øš3餄L@˜ ¤ i€iì­šuƒ[í¸Ãj3I¥„L@2HÒ‡4 bY@V`U£â¬6 ’Z@œ øùù¼L ¶%8XeÍà„“D¢QFF†©C0*¤ i€Qé4³ÅT§F$H\-Ö™ H0   ÈÐû/'sÉ €õ@â˜RÅÝÿjX¸H¸¬0f@͸9º‰å$ÙÉBìYÆ)+4Ä! (Óf¸*DèñÈQs'Ù4€ — 0Dô KšOŹë4ÄÙ˜:POiR¦®½¤ñÛÇ\Fu,Û³ä &×åÈn×?6"‚ùÏ„! £ú°ª1)0Ê9&€¯‡C"“…pºÁz`4Äa4@Œ ˜fp€?>`¬ÒƒA&`BÈÌ& HÒ=©„LÀ„ ˜¡Áœ>ã@ ?dRƒLÀa²€I 0&&†ûê¦M›>ú裫W¯>|øP¨„3gÎ>|xõêÕ·oß>|øƒŽ?þã?^½zu„ Ü-7mÚtç΄„„¡C‡þßÿýß¼yó„7lØ0"Ú¶mûê®]»ˆ¨_¿~ÚÔË|a²€AÈDú. +‘Þ¼6O•æû166–ˆêׯoê@ôÄvù·3küüüˆ(##CeGæ{ý4oÞœˆ®^½Ùºuk¦·Í¼Ó°aC•]ØyAÌŸgΜ©Y³faaa:uˆèôéÓAAA …"00ÐÆÆ&55UmØ …" ÀËËëêÕ«jWXXòâÅ‹ .øøø<þ¼yóær¹üÂ… Õ«W/O‹™~ ~gˆÐé°ä £æ ý~0&Ÿ1ÇÛÍ‘ÆÁ~ž`"_·Ë*ò?"€rÀh€㎠`@À² plL€KåsÅs„ðI`HÌ2«ÂÌ¨Š É¸ð`)0)Àìq»þ¸]ÀJ¨Ìâ2ðì °PH,€ ™h„4ÀB°™€ €&¸7Àr°÷ à&0É>,ÈJ~ÚLcG™ˆÀh€E1|ï?‰¨Q%¢JD=ˆ’Ø#M%ò ò$š»AZ$›ŸHF, 3&`°D}ˆ¶)‰¾!HODDÿ%:Et“HIÔhÑH­Ê›3gÎÿû_f8sçÎ5uæGÊ?…æçç§q©]„zêß_ã&sˆ¾þúk#Äf£ˆI s“Àm¢DUˆ<ˆfÝ.[¿h‘/‘ÑB¢_ p(0¤–©\CÜô!’hQÑ3¢¥D=ËÖ'…–-‡%è40>L °X†™ô=QÑl""ªEtºlýK"ײe7¢8 Òàᦟ #šHDD+‰>&:DDD®D/‰*Ñ "7mËþúë¯Íý).zß~ªÍœuૈû>ýôSƒ—)M¸[„`Rˆ:N4“¨ Q¢™DÇËÖ],[¾DlšèÀøùù!ƒ2oúݦ„Ç‘T0¤ÀÃý7;˜h1Ñ3¢gDKˆš”­J4‹èQÑL¢¥©)ñŸ±þs§ßIdGvƒ(–hac¤ViK°ßÜ>8pàÏŽuÚ,Êf¢“D~D~D'‰6—­MÔž¨1Q0Qg¢¦Œ ìo¢&DDADì³UK‰fy¹ &zU¶^FôQ ‘Œ¨.§Ó¯$ªCtóÍB Ñ$¢jDDßh*#¨`6D”Ÿ™yê‹/v´mûG‹G† Ie^3`ÏoKp0óŸöÛk\£Ÿ}½zíŒTÛ¶V­Ž}úé‹”výÝ;¸[fœ<©6 Ëî"_^¹²ÓªUƒ*êA0Üö?:bDÞ½{t îU@÷«»†D1DùDùD1D ÊÖˈ–åå-ÑwÐß<½¾·ÁšªlbJ"ÜYadC‰æ½ :At¡lå"¢‹DñD™DŽDÓ8ÛŸ'Š'RU&:V¶ò(‘Q3Îfs‰nÅ%¥j*#¨`6DtzÒ$·  Þ~pî\³qã’~ÿÝà‡œPqýHíå\»¦,-µ±·Ï¾r…»ž ¯ÏáÞÁÁ§§Ne×ßÛ¾]YZÊþyk5Iægfz5o^¡‡`Úÿý£G½[µ:ÃiÿŠ;\EÂÈtʱ4s!J'Ê$ $Z[¶rÑwD5ˆÜˆ–q¿([IäEDDŸý\¶òg¢OÞ,v#Ñ*¢"¢ï4‹Ç‘T0"ʹ~½ÉèÑŽUªØ88ø´iÓuÍ*û¢”Û½P––^ùöÛ;n 9=eм €Y¿%8øæºuvì¸-$$nÖ,Eqq…Fœqòäþ>}þhÞ|ODÄÝíÛÅcS‘¼gO­>}j½÷^òž=üW=<šŒó,1‘]ãúàï¿™å´cÇÜëÖåïÅo¨Ò¢¢ssæloÓf{›6ççÌ)-*Ú‹ÿ§Pc–žýòËm!!vêtë—_¸ÛßÞ¸qwxøïÍšÑË´´ãÆmkÕê-Ž]øô)³™¢¸8næLvwö¸ÛmKp0)•[š4a«É=œPM·'¬]»£]»?;uJ‹‰IX»vGXØŸ:=:s†ß,{7·ÆŸ|ÂŒèz± E¢öjaë¢å‰ck½%8xg‡E¹¹¯[U.ßÙ±£HŒ €©`@À$0 `<;ˆbˆBˆ‰v—­L'jNdGdKT(‹³½oÙ‡Dˆžå$üf±ˆjóŽ%T,ó82†.#-Ù‘gpðµÕ«_¦¥q_`¾1å~‹Ÿ°víÓ„„ž;vô=qÂÖÁáÊÊ•ìÆY/FîÞýÞ‘#Ož\ûáí¯GæìŒMÇŽýàÂ…î7æÜ¸¡16–¢¸8õàÁZï½W«wóÓ•¢ÜÜkÖTiÀNz zƒÝ\·Ž”JR*oüøcƒ>âËo¨«ÿ÷YY½ÿþ»÷/32®}ÿ½NTÛ˜×V­*ÎËësäHäîÝY/r·Ï¹~½çŽƒ®]#¢ãcÇ6øè£~'Oö;yÒ½Nø¥K_‡´jUannŸ#G"wíz|Ævã׎{8‘šæäD=Ú<:úÌ´i…99Q11Í££//[&Rñ’/nþò‹GÆâ©m¡HÔ^-BU©SëÁ 5##ïlÝÊ¬ÌøûïéÓ<=ªV ýòË”tª ÚÆdÊtôôtòôl9}:wû–S§:zx0ËïîÙãÓºµ­““½«k³ñãÙoßìßÿz÷ªUCgÌ`÷Õ¦ÝTp'RÓ¦Ÿ}fçì\«woyA»œ—Ìÿø'*kÿímÛÞÙºµÃʕ≴?µW‹‘ê°µn8tèÝíÛr9=üçŸZï½§±Å ½ÉÁ€X¤AD7‰Š‰DìÜØ1D£ˆîɉxßô³˜yAëx3‚ˆhÑ8¢4¢gDÑšŠÅãÈ*˜¹øø´™?Ÿˆ ³³Ö®=5qbÄo¿ñ7ÍÏÌ<з/‘R©T(Hö¿ý\Ë~Ä5   ;[ûà ÎÒ–É” …ÌæõƒŒ”¥¥ìr‡ï¾»ñÓO7Ö¬±ut ýòËááâ±±îïÞ]+*ŠY®Ý§Oòž=o¿­! ¢ú~xõ»ïryK­ç¬æä¸Ö¨Á,»æäh¹#CmcdgW* w}ó·`œ«Uc—³¯^½²råÓ›7_Ï¢)k‡‚ìln±ìöÚ´› îáDjêàîND6Üeî\ƒH©|ñðá¹Y³žÝ¹SÉß_׋M(µW‹‘ê°µv­QÃë­·Rÿþ»æ»ïf]¸òfJVqÐõ— ôôtü0“Q)‰däççW¿&ªúõ%ºGÔˆíL'’u'Ê &š)°oQ‘-Q7ÞKsˆ¦5'R–ý6¹H±£‰î5.[ÆãÈ í_vòòj>aÂŽ¶mÕnê\­Z-[\||ø/½LOw $¢—:{y•?,oï—©©nAAÌŸ/RSÙ~XÕ&M:¯^MD'OÆÍšÅtìDbc>}šqêTúñãq_~ɬ‘ÙÚæä8U­*‰oXØÅE‹líí«·k§eðNU«jl™­mia¡­“={Æ}Ií¾NU«¾ÊÈ`zð/…õÔ_´˜2Å·CW×’W¯¶·iìwöòâËn¯±ÝÊ_SmÉdní–.=o™šŽëäá±;"â@Ÿ>ÕˆH‹v§MMuU÷ƒînß®ëÅ&‰Ú«…¥Ç‰cw,ÈÊâ¶°Ñ »oQâ‰ê›O±ú%J¢©DDžD3Ê}§/n0™RYÞÕ-ÁÁ蚊6ùüþýØ1cÞ;tÈ8!IŠD.¶;¿ÿžŸ•Õ<:Zó¦@m"­±YdÌýìÛéÒ§SÅ=–Œˆý]2˜o—õžqþú=sÑ3Îo©êD&|Äòkpkˆ6í$Rõ#A4²|ʈ4,æ„ ]få<ÝfGÿëÓHòǘ’’’ˆ¨K—.¦$ÊÆÔ€¶..ZTœ—W˜}yùòÝø7^‘”¼x‘¸ysýAƒLrt6Ð3’•ý§òg…þÇ=pí'êETè6¥Ù1½ÓÛDõˆˆ¨”h‘7‘ Ñ`¢WœÝ—ùU"ú„¨ˆW,ýMÔ„È(ˆè¿e¯ (#úŽ(HFT—ÓkTÕ!ºÆ9}%D“ˆªyp’ ¡b7- ò%ò#ZHô«ºv¸OEäFäDÔóͧÑóá… i€Ù¨\«Ö¾^½þêÙÓÞÕÕ Óo@[‚ƒw´oß`Ègoo“Y`ôÀø1€ ]“œ,¢$¢ŽD=‰b‰ˆh‘#óÜcDÌÍ)‹ˆ.Åe9Mã”p‚èÑ}¢Gœ‡®°ÅÑP¢¹D/ˆN](Û@¤ÀóDñDJ¢ÊDì•y5ãl6—èQçLC ŠáÝ~ T¬-QIÙ7N ""¹h³äi(˸„N&qaR&aRQ§)H‡øD Œ ˜«}eSwº%Ê':K´™¨Q>Ñy¢ DD”NÔœˆÊ~]•;æP«l¡6Q&¯X"ÚA4Ÿþ¿½;ª:Ü8þŽd! ;A ,1A6¡EÙ«€bhUZÄ­@ذ€X6ñ‡P[•Š«°âRQiA@´E‚!,¢˜ ‹@–ùýq“É83ÙgÉÌý~Ÿ›“{Ï9s“'œ÷ž{îÕ_¤0i±tgY6-Ú¸_z\:-Y¥Ò‹¿ìù1éj§SRµµ¤óRIR–T»¨Ü¶ƒUú¯4MÚ]t+Q™ó*Vn07ঠøÓ¾:×þƒ3ܯÎ*üäÐ\éã¢Û~¤6Ò RœTOŠ“ž—ÚJ5%IM¥#Rž”_4¶±=íö°ÔÄ©ZI×K륓ÒRi\Qa)ÚÔ—n•VK«¥Û¥z¿ünSÉù…à%UÛ^ÚY´½«hº@’µè?IC¤ ÒRt֬׭À눨îlã`³%Rn‚ßÛ*µ‘l LJOKÆsqHOK‹¾õ4F:(åI)Ò}v•L.ºŸ~’t¿«jï•öI—¥)¿Ú)½,-—F:}k¸ôGéGéŒd{\VIÕ“—ŽIÒ,i„«¶²¥)L:"-¡?X( UF @ug¼îÍØ6É´€Ã$À/TlB`ƒo÷å@)Sê'Iê/µ‹3¤ÞR?)\z@lwTo©£ÔJj"ÍqUíÒ`)Bš!­)G…öŒnœ—œKö„ÔVê$]mwcRIÕ>(õÚIí¥>Ò(Wm­¦Jµ¤[¤>%ôàn,†? ø äÕó²D¸œ*°3VZ'ýªŠ z«Új«„w°DØAáo¦LvÕé׋%Â( K„áOîKIq¸G¨úŒ•«Èa–#`>—•òb/›4Ï4í¡j0¼ùÞ@²›”kÖ¬™É“P büŒ1>¤0@éééÅ—]jÃÿrpøå]y tÄø¥À J¬’EQQQ¦ºÃ§ÒlcâÂ<`ÿÌVÇè¨bü˜ÿ†@ *œ(Ï}A€Ôä¨büžË0 j9¶fô¸•å÷a€T1Âþ¡¢>m;?äÔç]‚ç0!?â: ¨ÿö:=“—T1¦”< /Ž¿]¾ß€Ñ?à!LT…ã²UËÉ.ÿîF @ÀrÎòäm9¥¼×ŒÑ¿I1!àÖr¿µ e©Ž“\þ<†€Àg? w¬{îÄ ýÍŒ'‡Â¯•89`ãÑTPB¨cô¸1æâ0:wc `Üø …=ÃqrÀÆ»Ó/ÀCˆ05Æîð #`8ŒÂ½0ÓŸðb @0!àŒÑ€q…¯;©p´ÄêUï`Ö*ˆ˜1<Œ ï°JRTT”¯ûþžÂ]Ô€j‹˜1<ˆ…Â^ÅBa(7b`:Äð,&¼Š (^ÞBTÌ Ïh€21ǨPÝ0˜10n ²lÙ2_wÁgÆŽëë.@à @udæá~IJ9'$¨(bT/e€|Ð;=©n–.]ZÒ·Œ“F€ò³X­¼j@i’““%ÅÆÆúº#%)##Ã×ùE0íp¿¢ìãA™I úü¬OKKK“Ô·o__wÕ³P]Ø2 BŒÓUÊ\À1 ׉}Ž Påù!2â¡ Æ…fÂÏ Ì€Äè0Pðs€r"‡©´Ê“‘T7@µ`ªñ«'˜pM¿3ª‚Ù¨FL8–u#S=žŒ Š˜ L‡Ù¨<·ß•Á%ÞÀfªù Õ³xÉÒ¥KIzª fÀ æÌ™ãë.À¿'K—.eZ€Ï1•g{b#1åaû=aN€Ï JH¨’€j‚UE@…TÄp’*„$Àçˆà¶$àM‹Åïj®4OwéÉ'Ÿ ©h+åÙßå>$F¾E ·1’@¥‡wû÷®bÜR‰$«ÕZžÝÒÓÓ{öìÚ³gÏôôô2÷wW÷Üž?‹/>tèP9?¸[ØäµÀ†îT•$°eË–Þ½{W±n©¤üþô§?õêÕëìÙ³={öœ:uj™û{¹{e²ïÏ©S§Z´háåø< $÷ï_þòÿùÏgC†8|«¤XÕ?²[Nš§ÏükíÛ{´~ø1<¢I`Ë–-}úô‘Ô´iÓŒŒŒÍ›7[,–Í›7gdd4nÜXÒ·ß~Û½{÷6mÚlß¾Ý8jÚ´iááá111ÿûßÿì+™;wn£F,‹qGŠó±‹eâĉ!!!û÷ÊÎΖ”•––fµgÏž.]º•TÉæÍ›'Ož\³fÍGydÓ¦MÎÊè@óæÍßÿ}ûîY,‡ž;ïìкaóæÍMš4Y¾|¹óþŸþyLLLDDÄôéÓKê°Ãi±ïíÿ»víêÔ©Sppp§NöìÙã²Ä^™ľç%ýô=NïØ±sìØ-~1zôÏEý¬¨CIIæÎí»i“L9ú/]Ÿ·äÊUBñ(b¸Y¥— Û®LwéÒåàÁƒ .œ1cFbbâ:vì(iذacÇŽÍÊÊJLL5j”qTttô©S§&Nœ8fÌûJž}öÙùóççääw¹¸<6...;;»M›67ÜpCRR’¤eË–Ýxã±±±Æ#FŒ>|ø… JªäôéÓ5’™™™éü¡¬Vk~~þêÕ«'Mš¤_^}wè¹óέKZ½zõÃ?üÑG­;ì?vìØG}ôäÉ“W]u•±¿s‡N‹­?Æ—ÆÿF}æÌ™Ñ£G1Âe‰½2?ˆ}ÏO‘– ŸûöÛÔçž»f„Þë×Ç<üðþ ²RS+QÏ¥S§ê´mkl÷u•úÌ,€OÈ}))&lÚ ,Þ¼ €?JNN–d¢œ–-[fl”3 :t¨W¯^’fÏž““óî»ï¦¦¦ÆÆÆ<877wáÂ…ÁÁÁyyyÆþ‹¥  Àb±\¼x1,,ìâÅ‹uëÖMMMµU²nݺŋ§¦¦Ž?þÉ'ŸtylnnnPP¤Ï>ûlèСûöíkÛ¶íÛo¿Ý­[7‹ÅbµZƒƒƒÏž=nè\IdddJJJãÆ?Þ¡C‡“'OÚ®Ü[­ÖçŸþÙgŸMOO7š;pà€­{=ÏÍÍuع  À¡u‹Åüî»ïÞ~ûí’œ÷ ÊÊÊ2ꌈˆ0úïÐaûÓ2bÄ[ŒŒƒƒƒÏ;gß7çÛ®<Ä¡ç.Ù~OÊù‚a#3”saúÞ'žˆì޽ɭ·_Û¸ñçÿþ·Ãœ9’’û÷7ƯÖÜÜý‰‰'·l©Þâ÷¿?””ä0®µ¿ÚÝwÓ&ÛÅ5äç·rå±ó³³#»wo3eJš5%ý¼cÇᤤ‹G†FF¶¼÷Þ¨øx‡îe;v襗2÷ì)È˫߹óµÓ¦…Ô«gÔÜú¡‡~|ûí˧O÷Ù¸±¤úí¹l˹þ˧Oï3çÆU«düºZ­ÿ>¼Ãܹá-[ºl¢Ì“c’û÷4é‡×_¿têTD«Vm§M‹hÕÊyç«Gþñ­·ò³³õíÛfÒ$Kpp)§ÂšŸ()éøæÍÖ¼¼è?ü¡ùï~gßâ¹ýûSæÌiq÷ÝÍïºËV()---cÂc$ýZûö§LI]¹2ïâÅ–Þ0{ö!!½*¸|yÇܹ?lÜÑvĈ=Ï=g;Ö¶ÑeúôÔU«²Ož¼÷믭ùù_-^|èŸÿÌ»x±ùÍ7wûóŸƒÂÂ$äå}¹`Áwë×[óò:Œwíðáöõªò/]ÚùÔS?lÜ(éªÛn‹{챡¡ÎMØš.©­ŒmÛöÌŸŸuäHØ•W¶;öš!C„rc6<¢¢sö—É»té²hÑ¢‘#G^qÅ ‹-2f:wî¼råJãêxAA±óªU«²³³W¬XѶm[ûJ†º}ûöM›6ÍŸ?¿¤c ©{÷î-[¶Œoݺu·nÝl½j×®]RRÒ¥K—Œ/+éׯ_bbbNNÎÂ… o¹åIÖ"’¦M›¶|ùòóçϯ_¿Þjµ:, °ï¹óÎέKZ¿~}BBÂ?ÿùO—û·mÛÖ¨såÊ•%uØþ´”´PáÚk¯µõ­]»v.Kì•ùAzî’GçΦ¤4°û±6ìÖí¬ÓEÖÃ+W^>{öÆ5kº.]šùå—ΕƒË¾›6•tÙû‡×_ÏJKëúâ‹ÝßxãŠààÃIIFyêßþ=lXï÷ßï¼`AVZšó{gÏn>xp7ßìñæ›á-[zé%Û·²öïïúâ‹}6n,¥~{.Ûr®¿ÖÕWEDœùê+c‡Ì/¿ ª];¢U«’š(óä8ÈܽûW‰‰=ß{¯QûŸ{Îå>g¾þºë²eÝÖ¬¹|úôw«V•~*޼úêÅ#Gº¾øâkÖäœ8a_ÏÉO?ýæñÇc'On~×]¥÷êÄη¿ûîo7mÊ>yòë%Kœwøêùçs23ïØ´éöwÞù©„;Ç~þæ›o½uï×_KJIJ:’2ð­·oÝZ#$äË¢OúÍ /œ=p`à[oýößÿ¾p옊†þ÷¥¤Ø®îµhQö‰¿ùè£ß|øáùŒŒ¯/vÙ„MIm}>sfÇ îþâ‹~¯¾úóÞ½¥Ÿ8 €§T( ØnR—gµZ$%$$äççwèÐAÒk¯½¶zõê† Únm—tðàÁ† &&&&%%ÙWbìsë­·>öØc%koÚ´iÛ¶m›6mš}áŠ+^yå•ððpãçJž}öÙ-[¶Ô©S°"û= IDATgÛ¶mFÞp¨sÈ!QQQ»wïvøŒ=wÞÙ¹uI·ÝvÛ¿þõ¯I“&-Z´ÈyÿeË–ÍŸ??22rÿþý!!!.;lZúc³|ùò^x¡N:K—.}å•W\–ØŸÃ2?ˆ}Ï›³ñ\È;>¸vmÛ—Áuêäee9ìsâ“ObÆ®W/¤~ý˜ñã+Ñʱ>ºfܸÐÈÈ ðð«G>¹m›Q^#4ôÒÉ“—23k^ye›Gq>ðú¤¤z:]Ñ*!áô®]¶o]óÐCÁuë–^¿=—m¹¬¿ém·e|ø¡­æ¦·ÞZJ=9±“'‡FFÖ m>dHÖÁƒ.÷‰™0!¤~ýzõbÆ?þñÇ¥ŸŠŸþýmÔ(¨V­kƳUrô7¾ðÂuO=ÕÐ.æ•$næÌš ÖlРëÌ™G6lpÞáû>ˆ›1#´Aƒš v9Óe%]¦M ­_ߨ>ôöÛq3f„7nÑyÊ”þýo£ü»÷Þë:kVx“&!uêÄ͘Პï?ú(nÆŒšF[=v¤ègáЄMImÕ¬™}üxöÏ?G4mÚmîÜ2OìùºÈÆŽkÜ4gΜÒÃÀ–-[lCð-Z\¾|ÙØŽŠŠ²ÝÖ³yófû£Œ‹Í¶ñ÷СCm•8ÜóYÒ±6wÜq‡}‰±Ý¥K—¯Š®˜º¬¤E‹Ÿ}öYIjîܹs‹þa~â‰'¢££ícÆüùó퓃ÃÎέ]êܹóÑ£Gm‡ØïÓM7ô$Y­Ö‚%¥v³g¿fÍ÷¯½vEHHÌ„ ‘=z8xîÛo'%e8Ÿ“#Iv+¤Aƒ2ë·ç²-—õ7¾å–Ã+VäeeY­ÖÓ;vÄNšTJ=9Áuê5BC­ùù.÷±¯ðrѺš’NÅåÌL—íflØÐxÀ€Ú11evIR­fÍ 7Z´È>uÊy‡ìS§ì÷qYIX£F¶í‹Ç8x°äxº²O*ép›œŸ®Õ¼¹±]»eËœŸvÙD™mõLLÜûâ‹{—.­Úõ±ÇšßrKéíÂ1<«œIàÈ‘#UoË-•xŽºg\ì¿æškVÝeáÛþT‚'’@ÝvíNïØÑdÀãËÓÿû_]§[›Bê×Ï9~<,*JRαc•h%¤Aƒ.‹‡FF:”×iÓ¦ã“OJúyÇŽýÏ=çRþüçÖ>ØàúëƒÂÃó.^üôÎ;+T™m¹¬?¨V­]»þ´i“ÕjmØ­[PDD)MTýä8³¯0¤èâwI§"¤~ýœcÇŠÆÍ6,øòÑGƒ#"ZÜ}·Qb©Q£àÒ¥+BC%\¸`¿óùôôÚ-[J:ôh˜«Ói¿O™!¬Q£¯½^”g~QÏÑ£µK}CH͆ ËìOyÚjØ¡CŸ^”±mÛœP!ÜWég0= ÂX––vÓM7y¢~ïpûÝA-ï¹çðòåg¾úÊš—w櫯¿òJË¡Cöi|Ë-þþ÷Ü3g.Ÿ9sàï¯D+Qƒí_° ;#ÚŸáÈ‘}O=e”ï{ê© ßoÍ˳×q\¾l ª’ýÓOi‰‰­ßžË¶Jª¿ém·ý´qãñý«Ém·•ÞDÕO޳ÿûå¢  ^Kêjã,YréÔ©¼ Úu 42òW Û¸ñûüÃ(©ÕºõÑ7ßÌ¿téÒ©Sg‹ »žy&çôéœÓ§w>ýtô AÎ]Š4h×3Ï\*Ú§Ì3tèÿfÏÎúák~þÙƒ·½9¤Õwîüë_/?~9+kWQ=!µkŸûî»â¶n¿}÷¼y¶¶®*yõ|émmŸ:õì¡C¹¹*(pùÛ…RÀH¨÷&:íÚµyä‘K–l4(mñâØÉ“ë8ÍDR·îç<°s̘ú;W¢•–÷ÜS·cǯ¦MÛÿí3Ï4êÕË(¼é¦”¹s·txùò¶®î¿vêÔCË–mýÍo¾ž>½Þu×U´~{.Û*©þú]ºäž?Ÿ—mû¼%5Qõ“ã¬^ÇŽ;ÇŒù߄ԯ=lXé]m5lXøUW}1vìx ô—WÄC6ì<þñÍ›¿_»VR›G9¹}û§wܱ{âÄ_>áíʸ¸ï¸c}ÿþa‘‘'LpîRÇ jÖ¯ÿnÿþÞqG“r,6h7zô•]»~2jÔº.]>›>½Eѳ¤:Ž_§uëïºký€EwµMHØx÷ݶG]7qbÍÈÈõ¾?p`x“&×ýñ•k«ù¯½mÒ¤uqq_.\Ø}Þ¼2û {<0@x`¨Uô)¢0¹Rž"Z¡†ÂœÒÒÒ$õíÛWvýl˜ ïaNâ…7‹0-bx—oQ!$FB o3’Ã;”“íÁA¾îüwÁ1|€$€ ! p;bøIBà.Äð – £BX. À½ˆà3$TI€À—H¨~O¸K¯;f7vìXãµbŒð^Ãlø/@%ðk *˜ €j!À›˜ L‡˜10b`:ÄÀtˆ€éÓ!¦C L‡˜10b`:ÄÀtˆ€éÓ!¦C L'È×€@Ö¬Y3_w¡lééé¾îÀÛˆàN~1îwàÜg‚¿Çl`:ÄÀtˆ€éÓa‰0 DÕöaAüØYðfþ§ÚæðÌ\¨Î¯B‹ŠŠòuÀï1˜10b`:¬ Ì"-M?¬íÛ%©G-Y¢ØXI²Z5}º’’d±èÁõÔS²XJ+7þoì¨*½ü”{Ö+§:¯C€@Ål`C‡ª{w¥§ëÇÕ­›î¹§°|Ù2}ú©öíÓÞ½JNÖòåe”[­àQQQ$(ð2‹•Ï?a±Xät Þvå¾Laa:sF¡¡’”“£ tñ¢$u﮿üE7ß,IŸ|¢Ù³õé§¥•ÛÚ-³Qç¾%Õÿ‰ïÆl½ÆøÅ(ÿœ€‘ªÿ/à[iii’úöíë뎠šb6d¶x$Ý~»þö7=«3g4ož,,OIQ×®…ÛqqJI)£b`‹ëå—U¯žê×תUZ²¤°üüyÕªU¸]»¶²²Ê(7ã2³}ˆ‚G/ÜÞD ™ým-#Gjøpef*3S÷߯# ËkÕÒùó…ÛYYª]»Œrˆ€YlÙ¢Y³T¯žêÕÓ¬YÚ²¥°¼}{íÜY¸½k—Ú·/£Ü$˜ð &Àkˆ@ ³Ŷo¯§ŸÖ™3:sFÏ<£ ˇ ÓãëØ1edhÖ¬âY‚’ÊO`A6x10‹µkµm›¢¢¥mÛ´vmaùƒªGµk§öíÕ§F*£Üb)~€.–›á3Lˆ†~£Š õ>ÿ}`¨ Oõ²r>9”†åÁCQ:fÓ!@‰|¸P8nFªèga¡0x1ªFT¿¾,(£ÚU«ô—¿¨iSEEé¯ÕÊ•®OEIŸÅoï @¹TtBàÄ ¥¥©W/ ¨ädIÚ°A¡¡Ú°A’þóÝ~»$=õ”vîÔîÝ:~\¡¡š>½¸†­[õõ×úî;;¦Ù³«•4l˜æÌQV–¶nÕ_îPJ…;vh÷nY­ªSGÿùOaá'Ÿ¨~}]w]ñnsæhï^íޭÇõÃeT›’¢®] ·ãâ”’âúl¸ü,â¡€ßà¡>T‰'‡®\©>Лoꣴj•^]ññêÐAûöéý÷5t¨tÛmŠŽÖ¾¤ùøquꤟ~’$‹Eèšk$)-M7߬üEµ’®ºJS¦è®»Ô²eq»¥T˜‘¡¦M%iÉ}ö™^{M’î½W½ziüxY,…°E }ü±ãòƒ’ª­QC¹¹ºâ I*(PHˆòòOEIŸ¥$¶ÄUÒ“Cy`(P<0¥#~ƒàC•ˆ¿ÿ½ ÒˆÊÎVûöÚ»WÍ›ëðaµn­£GÕ¾½¾ýV5k*8¸°Z«U²XTP I‹òòT£†$åå),L¹¹¿¨VÒ_èÉ'õùç ÓâźóNI¥Uhëf¦ZµÒáòZuÍ5úî;Õ«W¼CPrrô‹SRµuëêèQÕ©#IgÏ*:Z™™…ͬÖ?K)J1(bJÇMAP¶Š.ÎÍÕÇÞö¦6môÂ Š‹S½zŠ‹ÓóÏ«m[Õ¬)IM›êÈåå)?¿p„móÝw…‡«IÇj%]½Ö¯×É“ZºTãÆ–R¡MýúºõV­^­Õ«uûíªWïßmÚT‡;RRµíÛkçÎÂí]» § $Y­…ÿ•ôY¾E üŒÅò‹ÿ\V“ÿœûf[·ªM]yeá—êé§Õ¿¿$  §ŸÖÀ…ßzè!£ƒ•—§”Ýw_q%“'ëÄ 8¡I“tÿý.ª½÷^íÛ§Ë—UP üü²+´7r¤^~YË—käHÇo ®?þQ?þ¨3g4iRÕ¦Ç×±cÊÈЬY…ÓΜ?KéX( žF €r©Ð„À† Š/þrà@efª_?Iêß_gÏÇ€3Ô»·úõSx¸x@ƒÕ»·:vT«VjÒDs渨öŽ;4x°""4c†Ö¬)»B{F7Ο×Í7;~ë‰'Ô¶­:uÒÕW«U«2ª}ðAõè¡víÔ¾½úôѨQ®›sþ,ßbm€2$''KŠõÄ «üMùWÄÆjÝ:ýêWnª­¶JZ!ÀÚ }Z´h¡¢ÕãÆ?~¼O; ‰Ù€3cB€û‚”ßÕW_ýÎ;ï8—?÷Üs¶mþ¤T+̦C L‡˜10b`:<)P"—ïE®xÞT³ÿSmó ø f.TçW¡ñ’c¨:fÓ!¦C L‡µà¨ÒËO¹g½rªó:TÌ|,**Š^Ælà7,‹¯»àþòÄwëZ_÷À4,÷ûº<†Çûº‘{ÿe60f?ãp‰Ú¸ŒZ=¯[;÷Í_.ú¦§§7kÖÌr5=±ÇºV–ûÅ" PY­Ö’¾eÌu—²ä™;ˆð¬2G±sã«ᦠpÁ¸ÿÒ_¦/ …Àk˜ øžq_€@ÅMAUä‰Ùf 4ŒM‰®ù˃M†± ›û‚À;ˆ€é DÕp¡pµêŒ‡0!^@ oÛ}D±z»Ú*æïÄ^Ô^C €ÒxbB`Ãn ú•;+ôhµè`ˆàm|©A¿RÌ¥fHÒ?는‘)I©Š™"Iùš¹NWŽSx‚î{A.>ï}5§ˆ\¦K¹ŽÕJúè+u˜®aŠž¤eŸHE1Ærqžùî¤î\ Ú£Ts„þM'Ζg_Öð—‘ &ãõì†âýí7^úXÑ“2L]féëÊ8°¢X( ÞA Ì"í˜<£ˆE$hÀ3J;VXnµjÚ?TŒŒÕÌu²=¸¹¢åÏ]'Î)í˜z]«•ü­$mØ­Ð mØ#IÿÙ§Û;KÒSïiçaíþ«Ž¿¨Ð MÿGq [Sõõ3ún‘ŽÑì·«•4ìEÍù²–kël}qX*[[×_ÔÿÍ|MºM'^Ô‰Õ®™¦¬),ÿ¿7•yAGéëg´5ÕõGøx¯>}Bg^ÖqTÕ10‹¡Ï«{ŒÒ_ÐKÔ­µîYRX¾ì}º_ûžÕÞyJÞ§åÉ•,`î}rè‡_ª_×ÐÀNJÞ'I|©‰·êýÝ’”ü­v’¤åÉJüƒš7Píšzæ½µ£¸†EÃÔ¸®®¬£EÐÚíŽÕJ Qúi?§– •4Úu7öÎÓ¯Û),DuÂôäýû›Âò×?×ÂÔ¨Ž®¬£…p}ìK£Ô¼ÂCô§AÚó}¬&À£ˆ€Y¤fhæoU/\õ#4ëÎÂÛQ$­Ú¦¿ QÓzŠª¯¿Þ­•[+YŽrÚ°Gñ¿’¤¾mµã.^Öç4ó}v@/kÇ!õm'Ié™ê4SAPÔd|ñM;’Z5*ܸúJ?çX­¤·&ëãÅÍRˉzw§ënü÷ zÿYµFÊr¿"t*«°ü§³Š.ª?:Òõ± kn„‡(/¿–ëO¼ú׈@ ³¿åöÎúÛ½¨35ïýÂKÎ’R~T׫ ·ãZ)åÇJ–6w-ÎÍ×Ç{ oû Q›(½ðoŵR½pŵÒóÿRÛ(Õ –¤¦õtd‘òV+¬kU°¦¸’ïNn>¡&u«•týÕZÿ¨N¾¤¥£4n…ëž Y¤ ôã¬ÑÙ—‹oîj\WGŠê?rª­Ò@)öïßí…†ì‡ìîjÔZ¾gÓÓÓ{öìÚ³gOo¾¹’˜Åâázù?ª7FõÇhÕV-QX~>Gµjn×SVN%ËQ[SÕ&JWÖ)ür`'=½^ý;JÒ€Žzz}q<{èyY+/_)?꾊+™¼Z'ÎéÄ9MZ­û{¸¨öÞ%Ú—®Ëy*(P~Aaa½pí?V\Iöe…),XGNiìËÅå÷ܤGÖèT–Nž+^0P•>Ð% 0lÙ²¥wïÞÝèŸþô§^½z={¶gÏžS§NõZ»Ä Ùß\1r©†÷Vf’2“tx©°¼VM/Êge«vÍJ–<·LlØ­øÎÅ_ì¤Ì ê×A’úwÔÙ‹XôÝ¿UïkÕï)…'è¿kðõÅGõ¾V§«Õ$5©«9¿sQíq¼P#5ãu­_Xø§xu}¼¸ÿ+ÔÔ×Tk”nù«ú´->öÉ!ª®–ÕaººÇ.6(J¥Ø²eKŸ>}$íÙ³§K—.AAA‹eÿþýQQQÙÙÙ’²³³£¢¢ÒÒÒæÎÛ¨Q#‹Åb\×·X,'N ‘´k×®N:wêÔiÏž=Î%¶CŒ [£u~ûí·Ý»w iÓ¦ÍöíÛí[qÙ%ã(ûž»¬dóæÍ“'O®Y³æ#<²iÓ&¯[b`[R5ëÕ W½pͺS[ŠžåÒ¾¹v.ÜÞõÚ7¯d9ÊÃöLOCLYתK´$uj)ëZ]Ó¸ð[WX4ó·:²H—_Õž§ôû Ë­k5mŽ¿¨ +´âÁÂ;ˆª½ç&¥ÎWî«úfžt,,œu§²–Û=)¨‹.Pî«:œ¨qýŠËÃC´zœ.®ÐñugW5oPܮÆ×%XiLÝ…ù#F >üÂ… V«µM›67ÜpCRR’¤eË–Ýxã±±±Ï>ûìüùósrrl·âÄÅÅãò„„„Ñ£GŸ9sfôèÑ#FŒp.1±Z­Æ†­Q‡:‡ 6vìØ¬¬¬ÄÄÄQ£FÙ·â²KÆö=wYÉéÓ§5j$)22233ÓkçÖRΛ–øœqÁaf\Ü-iI¥åþâoÅÍÒoºhò@IJüHöhç_$é¥õê6½=YV«~—¨Q}5úו)wÙºCߌoÞøè^Íš536{ ëÄW5g°.çiÌËŠi¢xüÀ’¿0åF6ðß_$À;ÒÒÒ$õíÛ×Ó %''K²z9Kpþëæj‡C‡õêÕËø#|öìÙððpã[Ÿ}öÙСC÷íÛ×¶mÛ·ß~»[·nëÖ­[¼xqjjêøñãŸ|òI‹Å’››d{îܹ°°°‹/Ö­[777×¹Äb)Û7êPgppp^^ž­Ûö­8wɨӡçΕDFF¦¤¤4nÜøøñã:t8yò¤œg©”¿{•øq3˜ÅÚ Ú¶_Q5AÛökí„ÂòoVXµ›ªöÓÔ§­Fõ­d¹˜dÜÙ¦©ÚNUÌ£ª¦?ÿÞ€Kö÷è·k×.))éҥ—)vïÞ½eË–ñññ­[·îÖ­›¤¡C‡nß¾}Ó¦MóçÏ7ö1Fç’®½öÚU«Vegg¯X±¢]»v.KBBBŒ¡¿}£uvîÜyåÊ•Æuý‚‚‡Vœ»ä²çΕôë×/111''gáÂ…·Ür‹GN¥+Ì~£³¾x³²]Öª–'< ¹œ`6(˜ >|ø7Þ8nÜ8I»wïNHHØ»woAA±ó{ï½wçwnذ!>>ÞVOddäĉÿïÿþÏvu_ÒŽ;F•ššÚ¶mÛ+VÄÅÅ9—L™2套^ÊÎÎ6l˜­Q‡:80nܸíÛ·çää}¶oÅe—¬V«CÏ+9zôèСCwîÜyýõׯ[·®ys·Ûzb6€ø b@5Að&bPi¢££?øàƒöíÛ»¥Ÿåä“FËä‰Tå^à)Öµ²Ü¯¨¨(çÞ‘#GLÒ¨O°6*Æ]¯À‡ˆ?À“CÀ½ˆPILxË0ÀˆPa,Nø;b ºãÂàvĨ  ü1à7˜wá½€Ÿqyù¹:_“®Î}«¢ôôôfÍšYîg «7/¸ 1že¼·*;À툀ß(åMìUú[â!‰ ï°½QØ×€@@ €Ê3î òu/ úâ ËÕK„Ó!@•ðäPoâæ+pb`:Ĩ*&¼‰ p –€Ûþ‚Ù€ÿáÙ#PEÌ€0*øfÓ!¦C L‡˜1¨ý.IDAT0b`:ÄÀtˆ€éÓ!¦C L‡˜10b`:ÄÀtˆ¨¼¾}ûJJKKóuGP1ÄÀt‚|Ý&|˘–)?fP%€Âí*ñ#`6UEð;̦C L‡˜10b`:ÄÀtˆ€éÓ!¦C L‡  ÆûáÓÒÒ|Ýà6ÄÀt‚|Ý~ƒ ð/Æt.àÒÿÀð~+8IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/translations.png0000644000175000017500000010125610015422052024507 0ustar frankiefrankie‰PNG  IHDR³Na pHYsaa¨?§itIMEÔ2‹¿Ð! IDATxÚìw\ÉÀgÓ¨ %!ôbEl*zÊÙ è‰b={Á³7Ä;=Ë©œŠž»žþP¬çéYïì *¢`/€„Þ ¤'ûûc!Æ”%T)ïûáÃgwöÍ›™·/»oÞÎ&XPPЦM›B0u)2ÀJi°ªïÜ5„“»£¿#†a–-–ÔÝ!,ia‰a˜cÿàÒPC‘Võï~4À  a’ýlõ¼+<„Ðèà 5ò®ŽQÚmÌU‰U (4†…µSWŸÑ»Î¿¨òà Ã0 …fjÆmө߯ÛÏÊð/2‡F#„xWæÇæÀ9ÈPqÖ E1L=C;r5܎˜µ§Lm¸\šŸ™|ÿò‰¹þí&ùPå½ÅqyqaV|ôÕõó‡~ÿk”²ÜÚ+ÔÓ” ¾Î)ÔDd€« òÕRõŒúíäE¼Û> „ìû…04&í¬¿C>(w >†ü%$5”œŸ•¸a'b÷ÔÂÅÕp.d/λ1»ƒT Œ~ö¡ü¡»SŠÀo ¶ä ”?…,{ÃÌÁ–&Ê aÜF¯Òd ÕÄœëÞuÀÚð[šq9Ël[ #c3[ŸÉ«³¤ B@&ü2œGsg¦±ÍÀرEû±³—ÿ¤«'e6§Ù4±«å\ؽ} s¦ÍÀØ®©û˜ùk_HT•ó?]ž< ³%Óeå8rÁö"9®¿epYÞºŸ|¹,CŽƒÛÜB‚Ô[“|<ÍfV†Ï-TÑVfgÈÍR¦ÑÈ­„â'^ ø[e¤š‰ßJvR+rQÒ¶¥S;µra3FLç–^K·&‰äú;ŒÖS ë¤—Nvµ«R.ïpTºZ´#p”“ËiÙyÀäË |ý=¶ªÎ…&ñëJÒv×<úpÉJ"$òBܘW.yH~¹0å8O^wŠØå]®†+µµßš’s!x­z í¢ÄÆ®õñpá€ê%((¨ÌœÚ¡mÕÄÂÛZij¶÷µZÅ}#›ª ¸ýtnoE2ŸÓ쒞ͩ©’ ßq5×›¨µ¸{°ËW]úß…Žfª%îóïUôé ¹YÈ–i%Qî-Wã2FZùNj")zÑÛÎDSÞÔ¾o\±TO‡!9j}(SUy­ª«]5ýtc×[¹¢>š,°gbÿd ÔÉ¥ÙMŒh!³®B™°+Ë!D3j’-•“_d¢’8‰aÚ×ýmHô+îBIªÀÄz‚ª˜ «$"a:âT'‰ Øí¦Ü}›&S98}T|B±H&“ ?>9Kˆs†ªUl4rKF±äåùù%5VgB€E+I]œ~“©PÈrSßý{(tx×&ººDÞœ®Q\žÐœ( Øõoz¡H&,¼wºdvbëý?Bæô%A‹ÿÚ„\ 7a¿‹þ—¶¦c·eK>^ÿEYÒdÔ–ôbɇ+‹J†lÖUÿΛ…üh™V:ãW2.Ç+?ä9~óuTiå;©É¥Ñ%wÐFÃCr‹…y‰ë†6*±Þ˜=Fÿ;P™ªÔj•w8ÊêN~ÁŸr¾Žó 35|.4idH#dÒ$rµCIÿ #uø=ÇñØßKfäÃþKÒmUEQvÒÿ‚:%-ºRµ‘ÁWÙ ký´¯BIqˆfØ.ÜPë"ƒÃéÅªå ¹àèúÝš0(%ÍIꇺ°Bªñc¾Çq ÿ±1•‚b¹,,ó¶QÝǯʑʫ/2@Y»ûÝÊRI‡(¤ÊÖá µ.2|}•¹0Ù|y—r·ôò$WÈ{f¨·í«GÅ”¡c´v©Ìæt‚NÁÊ\‰fD-‘+ǨéiS^5m¥¼%èßr³-ÓJZF*ªÉT¾“š˜P)º,L¡šèé0ˆ t©ªäp”bÚ†c\ÃçBg9ƒ¢´ƒ$Ú¦•tùqe¡LQ OpA^Ê?üKÒ“m‚µå Á…j]d VÞ¸ôê³ãæk±\¡œ–‘,ЪJRûèÎÑíóKŸbzh.³9]ú½Jg]‘*€Õ¨dÎ@ÿ}:Cnò£eZÉKc¤šóÔªê¤ÖœÁ5=rúß]ÊŒ t•”ËËL}3èðMÎ…*sìLµ®3¸<¶)IdÐtìe­æRHÏ/oçЩ%‹fæUñÓ„/ÙY¾ò™‚²PõOÉ:ûùpá€ÚØ2J®aOx⢬CK¾/odàÚküþ37?gʲÄÇGJ§\L­Âe6‡ã¸%½dbzî]¶²ðZ€+QÈõšzãE¢H&å¿}vïÀ–•>í ™8•¬3º.1O(ÌK\[žuú—èÓr³-ÓJçJK–Œ4÷㪎UÞIMT×$æ EùI!Ãt®3(Wd õ¤—72(ïp”Õ]üת Çù‡Ó5|.4‰šÚ‚¨5òaºêäÛÉ $X9¨òd°8½$‘@3pRæ4 øtCŸÒÌÁθœêÈœ \,vUŠ¥?Y²¾aæ¸p@m Ž rVp8ún/od uâbÓå­Âe6‡ãøj7KÍt«L”8º-›<+Ì¾ÚØˆ¦ZÞxØŸÕèÓ=Í¢õh™VåÝV[ßdÄŸUÞI-Ù…ò¼›P®È@ëI/odPÞáèz7fÔäzް†Ï…&…I›JÝøËüþÓéJùÏR“ŸåPò.ç?é´¼BTú‡»×g‘LÏÈ \.D0tÛs¥ž+Ã…Û“ùpá€ÚÈÄÉËÇ÷áššYõ¸"C"/odðéþ™ )þ-ÙÒ)tcÇfãnT^qÔ/‘e5‡ãxqê•1½=-L«‹NíømÀ÷ž\s&B5f²ÝÚ?5è÷ȧŸ•u Þ_œÐ¿£¹1Ý”m?tö晢:"}:Cnò£úX©ðÓåɾ^ÄH‡ÏÛš/ø\òF9ݪª:©™ !ô×)[:™Òh†&Žn&/ MÊÊe=M´žôòFåŽÊ— ð·ÍáÀ6¥›wì7þâûý? Uu.´2Ó……b0Û+1Ì,½ý÷?þAMøÃñþ¥AÃLˋ󣚖Їï«ÚÈ€Æ0äØ7éî7nÏ…ç*ሸ=“2k  ÚÁàW˜‚ìØ +-ÄsÜBÞV0ˆ>`* Kkç¹Èzº‚Ûa Bhö£Œ^Ü:jçÌè9Öv!„VÆd­òà€ã@µ¿›Ðpi=`ú‰ksŠÄrIqü¿Gô+ù¾¼nkfƒqê͹°jÿ{h„Ðñ‰¡u×>¡#„úm‡°jbÎ9˜ïªÒbðêg£ÃÖlÎ îž ’QÄá'Wr@Ýâõ•ƒð¶³4¥Rèfl»ïúÛ|ôÆ«sÀ¹r3r@dD@dD@dD@dD@dD@dD@dD@dD@dD@dP>°R”%“=ìì<§”·Õ L€Ö;±®C8ŽWF3ŽãjÊå …ÉË[KŸþW²«U¨ 2 n£¼«Ý«cÖ~øy:ø&o…c¾Év—1ŸÔ˜õÒ>ð4(Çg Ò¹q%U:óƒËÚ5âÐ \ÜûIà+Åž_ëÝÆÙ˜Á°´w›³õ6‰ó¨*ú|õ§!Ý­ÌhTŠÖZºZÔzÝW«þ1rŸw3cÍÀ´y‡>ÿ‰C56¢+Úñ™GlX6ÛM¢¨ä5D+5ïÆåê¶Z¡\¡PÈåõöTá@Õ¡4¬¡e¯4±\íhüöžª®YGGg¹A9³ê®æÑ.KOˆ¤ï.ÿŒ2k¼˜8Ä»ˆa˜ëä)"a~òÖ ®šªt펶1A­»+Ê ÒÞk¤¾šµ’Ža7ý›+Š‹³Ï­÷Á0Êâ[© yÑH{S„ÐàÝq8Ž?Ù1‚í>[ W€ÏW‡Géé]µêjÖ}"ƒjq¸ŽLB¨å´sªå2Q’›©Iv2¸J6Ì0Wk8K”DìÔµ5ˈNe˜4kßûS/ȺLG×ôlÇcŽ­éÚÚɈN·°k1;ô–ZE]} ¿Ú´4"vûF~&Ñ£ú¡ºž'Âq|,×®¶õ&g ×&lI§ „ŠK§Ý¸Bªd°¨¹EÉ“Nº‰SÓÖ?Î ~‘/.³E}"s𖇧T†5qô¿™­ˆ’•÷Ó!þ†Ó ¢Ü}ðZ_’ó?ÕëÛo/¥rIÌéù![ï=ú¤¯ÊLA©*!×OÒÿ´»¿Ñ1¬ùä)ùB1?íÏinFÿínZr]ÔóŒÙ±±ÍBÆV¾ÄERôÜÞØòv¾XÕŸt¥7IšÜѵz6yj—¤¤fÅ_?÷1k>ôy¡¤ = q C„Ðô¨’ω0缩û—ÛP7SD$ww6ZáÈ@”óhöÐîNÖ”Ò'»æÍ–YKÿÈ P¦Ýñ^lïKTù~ÍCˆ ¾ydp2K ³¦B‚¢2lôI_•™‚Ò_?Iÿ‰tÔÅÒ$™07!Är^T\Dõ<2‰>w37D¹Ï‹Àqüò´-g]ÓêOZÓ›ºšÄÑuy6yj—¤:?Ì éÞé^ìvÞ eú¤jßìë…2oZò9yÔ¦å¬(ð“z9}u¡åßÒ?2@ÝÈá8.)L¿{>!D¡WIdèÈBý™Z¤,d1bÿ€ã¸(ÿ޽1çÈí-†ŒB3;›V ‘Á· Ä_ÇoÅ)7¦ üŽË2R] ¨OúªÌ”þúIúOʵ) ¹!D¡™W בA= pÏŒ^GÅ0ŒBßrÿ´…±ÓËb©VÒšÞÔåкÊI<›<µKžbÕúaØ0ºBÈú»erýRµrqjc#B(ôS®{1'2à'uôÚMþ˜¶4MµÃ0×É»R Å¢ÞÎÉnåŠ úÿÇËWÈEÏ/… „Œ­GT 2p5¦#„îe sÞž¢·Äq<åú/T ãvžó41[¡&ÇßšäÁ~àŽãºÙz¯‰ÆqüÎo]B–­Ètëj 2P+œíÂBÛsµP,/Ó*‚*—~="ƒb„…fQ¿…È þG8ŽŸÖ!„Q0¯Uuù“Öô¦.‡ÖUNâÙä©]ò«ÖäÇKN>à‹åâ¢Ìã˺"„zý f´æÊ,ϸ·«s3k*…Êuñøuß]ýÓWz¦ HôkÍiöóÝÅ:¹™2¨T†©[ç»">è“!ƒÈ Áy¼žŸ­éM}Z­œÜ³IR»$} é¼B^d ñÚ$¹ž¢Ôƒ†9<NÒ >4C“¦íº-Ýï¢@] Ú´i|mgÃA&|G7ve0½Ä…j¸iosÃO3–61ƒ³PkßMh`ö멇E…¤8ëÔÚ)!ï_vÖœ“Qi§>ä‰òÞóX#~…° v¿µØPX?ò»õÑ M\Z´_º;bÍÌŽ5Ö´o'×I-¹Æv!ÿEÂÒ@d|{ðoúëòï¿„SPW€§ @dDCCº‘ †AΈ Ð !4 # ‚œ‘@ƒ…Ëšس4ÿ?‰Šxû<ÊÃÍ¡›—Û¡?7Y1!2€“ÉLIIÁq\õ?ŸÏ÷õõåóùL&ó|ÈÚ°°0>Ÿ‘P‹Á%a‹Ž•·ÎÉë‰-aæåUIÕÔ\Þ˰½©EúHæ¿ߑ¯`—ªâö¿w_ԥȤðCoÝÎÄ0ìÙ3ð… žYËd2 ™úpY—U¾õÞ¶_íé tæÕÁ›šÙ˜QÊk¨º;d ÞœSðÞNZôÒÈ$=ïêoc_#„rã6ÿr<!„+„ûFLHʪ£9\^°jÈü<™BÉeƒædKëRæ ø|¾¥……X$¶²âȤ’›7Ó<<0¢<ñSøãµûˆíúd–û—… ©j`Q±X„ø³67pïøý¡Ç™î¿jg*Ð}„Ç-Þz‡—^ ¨€­ª$t«’!ÕR7ïôǼ±‡ž’E)›¦Ÿ¾2uéB”`£®žìjj£šµ3aè)ÙÁ”Qá.UmÎ@,s8©TÌf[ʤ’g1E,+"²ó”-1‹Ó⣣£E¨^ä *À™ø›•E2 ñÌB<™—¼qªÓŠÓj¸3Ê>è#Ìɾ³cÖûUR7ïmààrA•ë” ß]~À¶¿u´vYQ ú@ä¸V™TÄa³å2©×J*åGÚ÷S{”P©È æDpw®³Çãžä‰”å)·÷ïÛª±ÝÉÎÊgÈØ£×_!„Š?GÎñïèjkhomÑ×ïÇ#×^i*Ô*£6ÃМpä=?<¬‹‹ƒ£eÛöë=ÑS±A”x½FÆý½ÚÇÓÎÁ‚îÖÚ}ù®òá3L¹}§î•\+Ó&úŒK«ÑôŸ„å=?4´“£½£]§žg>hŽ‘(‰ý‹ AÏÎOĨjÈ ÚÙÑ®4sK¼95ê{GŽi§ž~ÿ~(ÈyâGïFŽlCÏ®ý/%ñÉG­iaµ!“tFëp€êàÛº1xoÃ!/nÓ¯áï~éÖ3WVÅ÷J*î]ÛÎÎ_ûVC“ðc§u³oìöÝ\Qí4>qã—ˆE6G&•p8l©X4a’wØ'ñzûñO¯ðx¼,>ªšÈÀgÚÊ[ï&gäl™Èï·ƒ(ÌÝØoþ•Ÿ¶F¾Í¿y»À×x¡+„P`ïámæ†Å~$&~ žÐ4hh+M…ZeÔ¦š³)ó®/‹JÈ.ºrlÝ«u½WÜLÑG•ê´)æL„PÚÍ ÑûÒƒÿ~š˜#¼wéÉ™³Î&yCqöµÿM7s[P¦MÊìŒ.£é? ›ò~ÝÙø¤ô¬?FÓ~ñ_§9F„PêõùÃCâ–y”]tùèšWëz¶"ŽîËßyõc|ôQÕºAkãƒO>OHIYã/ÓÒìà¸U'cR36ŒÂæÞ@>jM «™¼3Z‡TËE훺1xoÃÁ¢Í¢IÍþ¹É”Vñ³!Œjúlט¿2‹¿ÕÐŽûù¼ê°îÎ¥mOþMÖ’3À¿½ñ‰Ü€‡#“I¬¬8±ÈÜÜŒ”ÿÕ­´xå¦Êeˆd6ëôœ„PH[sÃóIÌÔD\ÙÔí·“û·¶#Q£K†ËÂT?–ª»\¶ñ ¢)±[ð!ØÃ/ÿÓ«-ú¨RS»¢%«ÇýÌÞæ†Ä®´ø±kû£ŸÞlÓÔðe¾Ål²8ìì\Ÿ6ä6)³3ºŒF2ÓR3Hx¢`€¥BH&úà`×1=7OSr…ËòR²²•‚Ok<~Èùô*”;,úÞÌ@­•ÉBKC„B’fñ;˜(hi„’KRìmÚ¤çæ’ŒZ³Ÿª%äÑ5 ªø†n ÞÛ`)x}ÓºÕ[l\ÜNçÍDc,çYøúô^Áî¶é™ô!~)‰ÌF_'„‹ïÍl»Áýðl ÿ~óv»?E= l¹súÝðú>ÚfÓÚAQâÅ©#'?È`ÎÞyí—A¶³L¿ø« !´µµùåy÷"¦iƒ÷¹[¤œO\íbV.UáçÇñ¨»élKK¡PÀb±zôrŠˆìœ0Ó\aP©œA1/rÆ vM¹ . ãšÑÒ’Ù²#KSþÔö¡cZµõò^²ýi‚ö ›>2šŒ¶5ý¹Ì¤¬˜ª¿Ò‹G;)WHÙÛz ³ŽéšèdâyâÇ· ÿ:2ä>¹MÊìŒ.£éO? #bƒfØD!Ë×>ÀŒbÕVXN³éáÊÝ.__X úX”ÄI†-B¨i+T†½B–G>ê2¬MÚ}†T’ÚãÆà½ Âßî{vþáñ•h9¦sýibdÈOÿ%!„ßßü^ ÕW300¢–«3¦ºÊ(þwV§h¾¤tVY¨*sxl¯–M­ »/‰&fþ?z3›°cë«]ó«iw`Ù»ý?ËÒZ·¤ Jr6[$2M™ÙÙ9ªÙµ•Š –÷)ëü0¯L÷•¤ t¢íØU‘/rÏíYn¯x¿ ‡ãÜ}±èë5ÒºdJ‚Ä/[êî‚éÝ\))„>ä)ˆái9Ù¤),†mS¯…{/ÝÛ:‰Ü&ev«´÷Ð0r{hiÿZ˜Z†Z-»ä£.ÓÚ$Ñg8@eb¿½ƒ÷6bï2ëujž=“¸çàò¢ÖO^‘X€’ ^íyüñÛ³¥r„0.‹®V]ýé´äÆDk‡q'½˜ „ËþÛ4©Û¸Ê£2a|?ßÙÝ–?4¾ ^’¥?æK¦Mòï3ÚW.NQÓÆñúùRˆWPŸ–Ç_äu½—=8¶1®vóúv·¡P`bb’™39 ›ê ÍG  N¥m™9ˆcb€B ¡²|¢óÀg]st¬q{ŸYËv\‰>zz¹¿rÖòõgR]!dF£|ɉmQîy5¥ç³¿,vå'î4¶™B¢Š„±6¦‡yü ˜B9ÿÐe“2;Cj´*c´ÉÁÏ_âbþç]&6“+¯–tÔ5Ý ÂÔr7ï­ë´Y1wó¦î!Œ‚!„0Œúêð¾LŠÞ1þrjBTŽî©¿>2e’ûè±aÝ”òèâLDÇšäˆU–ä½^YÀùyzŸvF´’û#F1 >lÛê­wî}F¸XMmÖ£#~½6ïà½1mÙDÝ™ý_FhûúÞ7àÆÀù­•͵íu–Ï[mkA¸ç¥²î˜?NÞøKßþ£%EO¹,li’ø¡Ÿ3—…ÙZÐÚô›—!*Ú>±¥9µU3…É%ußîéÂea!ÙôÎ,ƒokü)…ª_Ìd2}}òx¼€€­Ë+GC—¶µ3háÞíg9*]Ódåµòbˆ÷Ž=±i®­;ì`zòÆF„Ðí¿wÅl›êîhèèà°h÷«ƒ×ÿÔÔ©K&ðÜÉ‘Ÿšs º ž×ly8Ry§!tlUÛµc:8±zZÜbÉÕ5=íu©R­…Ú¶Àr‹–]fŒZ}!dÝíóÜà݈Mkٮ˱8›37BB ®P(”GTúÄÚÒ¤ç  oÙ/þ@n“2;£ËhZQÉ®Ú{_¶½¶þ³¸Õš±ÙÆ| IDATýÆþê¶ôúï=í55”·]£Ö´°j-=;£µo@%ù†n ÞÛÀ•Q OÏɽ™(HÏ—'eSs¥™…xF¾,-O–V PnœÖÄÈjlF<-OýªŒBò -*âwÌ2g3„PÒéCFÜ®%QOÐʦÚz»àg%Ú¾þKÍ-Þ<¶Ù—æò%Š;ë½T5Hø± –wf!ž–W|>6/³OË“¥(2 iy²ô|yf!žYXR7£@–Yˆ'¥fú”.yÑìR‘ÅG"Ä$þóù|â5Ee‰– ¼›úñ|U÷û£Îõ¼èdóuK:[W*ç%ÏìÒ×Ò§·³Ÿ÷"lïáV{ßí*½ÿ4.%ßpÌ8?Z•f{ÚoÍ]ôæA`y+ S_WS—ª ˆ €šC!–S ¨U¥-/>lb@pÌ;žŒbÔÌkÈ©ó‡mUÿݾ⬸=¿ÏØvÍèÄÿ:q ëý9¢›ÖN´&!¿ÉÈT!U „,Z\xPqLѳk‡v¾n×qÒÃØkFƒøIˆ j)|s0†iû³ÃÎnXÑœxÐ4È%¤‘‘úBC]zœ † $2˜Ø‹†ÁÓ 2" 2€ †a,KóDDDTT”ƒƒƒ››Û¦M› 2€“ÉLIIÁq\õ?ŸÏ÷õõåóùL&ó|ÈÚ°°0>Ÿ‘P·Àÿ²žØd\þ9¡,¢ÄíᄄK‘Iá‡ߺ‰aسg8†a .<²–Éd2õ!2À0 +ç]ômÒ¯Z»TÝú 7j'ÙÏ7Ï:ÂÂm?Lø(”MôÌðù|K ±HleÅ‘I%7o¦yx`Dyâ§ðÇk÷Ûõ!2ÀñrÿN±\!U ,*‹h¢U¹Ô‚ï5RƒuV£.%ÎF1êÑ )WÎ@,s8©TÌf[ʤ’g1E,+"²ó”-1‹Ó⣣£ëIΠÜH¸YùXÿš*Ô5Rƒ@ƒÊp­82©ˆÃfËeR+®•T""Ê´ï§ö(¡R‘Á£#Á^M¹tC¦{¯qrEÊòäûýº¶bÒYVûýßåW¡¢Äȉ>9LC†±E‡>?î|¥©P«ŒÚlFó BγÃ}Ü] h ë&íW„?ÑS±A”8û^# Ÿ]ÝÙÕ΀Fç6r_QÞÔ…š~ òŸ†÷jãH§Pˆr]½Ò쉮y^γC½Z;2h ÇÖ=ÿzW@~.ˆ*ù¯Nùxº˜6ëä÷Ï»‚¼¸¾Œ†.íúŸMø’;Ò:v}ÎPŸÂ…jrcð^ rÞ)¾Y 3T2g ‹8lŽL*ápØR±hÂ$ï°NâõöãŸ^áñxêu‚‚‚ð  ¹úF&?<6ÓÊã¢0ëÉÖM‡_}ñY"—åðÎmŸJ\tFÙ˜„^~^,‘KŠsoÿµLsÊB"£&¬º‹êÑaÂõød‰Lœ9Ø™µà*OOUjjyWÚtžõ&U*—f%<[6ÈyìÉOZG­ç.BhÈäÐäqÖ«cäFÐj ­Mÿà·,Ž—/åÿ»¡Y£_ÈÏQ>bØo/Sò¥¢üÿ6ús‡ ´”Ðð߯þæM—‘]Ÿ³ÔEjÞÁ{ sdš»ÿËlÇÅ÷L¸c‰Âû3܈B L˜Lfaaáƒû9·o¥ÆÇ‰žDç¾+···7ì|Ïá-Z´(,,TÿÀV82ø‚BJ¡[›Ë›­ù¯)bI§\xžB®F— ùek¯ÜÍ{»šé¨§*5µ ™—r…Ê] ?ši?O«ÍÉ–.ý×òD ɵõL¶€Ø– ßShæä炨r.»dPrq*Bèt©™˜G¡Y]Ÿ³ÔÑÈ †Ý¼Ð÷~"Wà8žùøàô I8Žã Ñ͉Í!2¨üLàî´Wñâ§óÊ *ð“"F÷r73¤«]YÌi”\©BSþéÁ•^ÍíZv·rÛm¡‰ ùeK¤Òš\šC\qôQ¥¦ÖŒ¦þ`…JgWr²%«ÐIήŠiÊZºÎ…F-»äc×ç¬õ>gP%n Þ ¨"áÇÍâmgÉ4wüYµüÿëFœNÀqÅ)ÿFÝO|P  2¨LÎàõKIÌ“üw¯eîe¶hÑâÞý~7ü&ÛÛÛk­RÁu ºŽ” ~—ÅW›‚`i}aÀsÒªGso\î¤x?ÕËqÒÎXôõi]2%‹/[ꫦ)z7G†P¾ì«˜F&)ûÇ©qÒ÷#¨•î•4Lµ¿eœ *ZvÉÇ^ùuk‘Aµº1x/ ä—®=>t ¼ü__9ó¿Ú•üþší™R9B˜¬Tµë „B‰‰IfvÎä€nª+ T_V¬ì: öåÓ((ã÷_]Ì‚ßç‘×-N;O3tÑ_ÆœFù(,™·²N©Í*Ždý4a!‰*’œÁ"'Ö†Oåléÿ´BÏ^U`ž§ë\è?5Ôgìúœ5 Žæ jÀÁ{%â‚{ª©PŽç¼ÍtX„ãøÍ`O"CÙÞظ;©¹ŽœÁ8ÈT g@¼¡@ü'%ØÛÛ‡††j}”PñœÁx;Ó œÉȤř¯®,ŸQ”²ðž¿ÅÜãJ£ÑÞN%6zzçIBÒB©‚’?§؃Ë qûW~52“ÉôõyÈãñԾਲ9ƒÂü:57 RX6® ÷ÜW}@øæÜæÞíP)†Lî÷CfFçŠpqa×ï6LCÃØ¢Cßq‘‰|MºdòßïÙÚF¡Úµêu$6G-ÿ™zkç÷nö4*ÍÊÅcYØ#Uj2o¯Á1f0m§n‹!Jâþñníd@¥›Ûö[(Æq||[kë¶4SZgEš¹Y}¨Ùråj»ºÎIÍ]­c×ç¬u1aPÃn Þ |•ÂÉ—ÿ"jø‹ˆÿ-œ³¢Ýï×·û8èY'ùÒÊ×Ö Îoè æƒÈ t  Þ!ÌI¥?½™H]wã½—3SÏZ’üw|»¢Ó¹`@ˆ €z…!ÛÆˆ=p~«òÕb˜7o×­ù‰n`¿š†&ªX)‘‘õ BèÐl0%‘Á€Ž0ž&‘‘4X¸,¬‰=Kóÿ“¨ˆ·Ï£<ܺy¹ús“"h0™Ì””ÇUÿóù|___>ŸÏd2χ¬ ãóùÊ*ð» @$ÿuøÖ°¹öL„0óòaçUÎf`5ˆÛÿÞ}QæBͶôÄzö Ç0¬E‹çCÖ2™LBFįû9. ã²Ê÷mÜÃÛö/¨»Ü_Òþd–!„Ë – š“-U „p…p߈ ‰BØGk΀Ïç[ZXˆEb++ŽL*¹y3ÍÃ#Ê?…?^»ØVV©Ã‘Afa¹°X¡ª‹E*PQ«*ðWà†ÔàÆ@å-eúp+c„F5ë`Ê 1ŠQWO6‡$g –ˆ9ŽT*f³-eRɳ˜"‹ÙyÊ–˜ÅiñÑÑÑ"Ĭ‘A8³ò±H"¨m!5¸1PÃRõ zˆË r¤ ]2çWŽhekàèà8S„æÑ¢äC—=ЬH^â½ 0«Þ9®G&qØl¹Ljŵ’JDDù‘öýˆÐAµJÅ#ƒ˜ÁýݹvVÌ?Œ{’'R–§ÜÞ?¾o«ÆVt';+Ÿ!c^…*þ9Ç¿£«­¡½µE_¿\{¥©P«ŒÚäFs®“÷üð°..Œ–mÛ¯?öDOUÄQâ9ôQ÷÷jO; º[k÷å»"ªÄ ºz¢Ùº®¹]ÞóCC;9Ú[0ÚuêyæCysD•‚7§F}ïâÈ1íÔÓïßù/OüèÝÈ‘mèÙµÿ¥¤/ù¢Jލ—T•ƒ÷j俎_¹¬Ýõ)]O¥k(âm¶õ´ûˆy¹ü}`d®HMÃ÷­ò\1÷ÂÚòç $b‡Í‘I%[*M˜ävÀI¼Þ~üÓ+</‹ª&2ð™¶ràÖ»É9[&²Æûí sc7ö›å§­‘o3Äo^Æ.ð5^èß !Ø{x›¹a±Ÿ‰‰Ÿ‚'4 ÚJS¡Vµ™æDgʼë ¢²‹®[÷j]ï7SôQ¥œ6eâ1gú „ÒnÞ—ü÷ÓÄá½K‡LîÌœu6¡ò!é‰jë$s»¹!ï×OJÏúc4íÿuäÍU‚ÖÆŸ|ž’²Æ_:§ÿ¤ÙÁq«NÆ&¤fl…ͼ¬üxzIU¹1x/ †]ï®–†=v?áÈÔ*À;ÿ—]¯cÇ·o\³çÊÞîöû£ÒÔLœúrè”­—ÂÍi%s<ôÏXq82™ÄÊŠ#‹ÌÍ͈pAù_= Z¼rS¥šÅe6ëôœ„PH[sÃóIÔW‡º²©Ûo'÷omG¢F— —…©ÞÔUw¹,lãþD;Sb·àC°‡_þ§W[ôQ¥¦vEKVû™½Í ‰]iñc×öG?½ÙFÞ™2 ¢ç HÒቂ–F!™èƒƒ]ÇôÜ<’æˆ*‡…>–†!…$͆cw0Q0ÐÒ!$—¤ØÛ´IÏÍÕ¼@½¤fܼPCRü˽5{gk=Ò~Rüú'Çúæ=ßݵ÷qµ‹BèI`ËÓ€ÕZ>‰8ŽGÝMg[Z …‹Õ£—SDdç„y˜æ ƒJå Šy‘3µkÊepY׌®æåxüÉŽ,MùSÛW„ŽiÕÖË{YÈö§ Zuê#£Éh[Ó/‘‘ËAúÁŠ©ú+½x´“‘rq–½­—0ëXå R±A©Òψؠ6QÈòÉ›#ècQrŤ0lBýK5Pö Y^•Œ¨—T¹ƒ÷JÄÙwF´ïuöŸù²…j‡oé½ÿ]~£ñ3³®Í¸{Í¿ q·þy/CÔ–$E†Lý/!tóïR„¤ ôÏpØl‘HÈ4efgç¨f ÔVT*2XÞw¤¬ðÃ>‘Kü’‚ÐqªÚŽ]ù"÷ÜžåöŠ÷ z8ÎÝ‹TÖH,µÊ”Ì+¾lIÕ“z7G†Ð‡<1â/-'»ò©@OÔ aZƪ«9*Zv«d¼@½¤Êݼ(Í åNÿ~ ÍÒ›:ÙlÝóÕ:3™ðÓ­wi›Æ‡™8L½ºwÂ’~¾IfÃïž:ç¤xy:K€’Çí~’‰"zãöl©!dÅ¢«ßÝ·¡P`bb’™39 ›ê ÍG  N¥m™9ˆcb€BŠ/àD;æÏº¦Xãö>³–í¸}ôôrTú„ò뫃º BÈŒFù,’Û¢ÜójJÏg ¾Œ?q§±ÍU$Œµ1=ÌãW,QCb ô¤2öן ¨—Ô¤ƒ÷6@’ιo4÷ÏÉî~ýîcø–¯‚?£Æ³WÍç¾F5òkw3ƒÖ+VQé \-_æ!„n »ž!@ˆÂ1¤jDƒ7gõÈ`Ö½§£«Ýw@S"PÿôÊ¢E‹ª8g0ÒÖtÎÖ3¹B™Tynãpeù´û†L¹ÿYªÀ¹Éÿî˜ÐÌsqÝÙv)š/–ãRÁûØ— ó.Z¯MZeÆÙ1‡]-’È‹Ò_†Î:¬VkïèÀGïÓe YêË«óo³k¡žÍ¹Ñd /Ø[»!„fî¾mðÔ;/“¥ ¼8'ñÌ–1®^A¡¹Þ¶m¼'WØ ºz¢ÖzUÙ_thÈÔŒƒ÷6@òŸ§1›y!„8í—åüu=ÿ«÷Ò®fä²0®™ù{Lš'Fu˜é=»%—…M:ñ!j\S[ Ú˜¨Ô®¶´!½8ÕËÂB²éY`^r>¦ª~52“ÉôõyÈãñ´.?¬xdq ]\ÚÖΠ…{·gœåÊ9‡•×Ê‹!Þ;fôlĦ¹¶î°ÿéÉB·ÿÞ³mª»£¡£ƒÃ¢Ý¯^ÿSS§.™Às{$G~jÎ5è2x^³åáHåu)„бUm׎éàÄ6ê=jq‹%W×ô´×¥JµBhÛÿÉm,Zv™1jõq„u·?þýÍsc€w#6­e».ÇâlÎÜA)¸B¡PW©>QjÓe]ƒRkd§ù¦%Is$UÔvuh éêvcð^@·?ÎîÞ·Ï„ ‡ÌÙÚÞôËí\&x9ýç{ý÷¼É,Ä3 [×z?_Õ{ü8ÿñ‹£íúü™Yˆ§å+2òdiy²´EF¾,-O––¯HÏ“dâI©™>¥ SøŸxMQY¢)_ï&@ùyyeߊÀE²~¡çCˆWoþÉw×Ùûœö£_8ØÌ¨ì›½0õõý§q)ù†cÆùÑàáBU‘PÓÈ墧6žz˜Ói`À˜¾mÀ µ Ƚ|{´~ù<|y-õ*ÕÐûÇÞ?‚% 2´AP{ € €Èˆ €Èˆ (74„Ð¥Çðc$”F{qÀ xšD@dDÐ`Á0ŒÅbiþˆˆˆŠŠrpppssÛ´iDÐ `2™)))8Ž«þçóù¾¾¾|>ŸÉdžYÆçó!2ê3y/Ã7ðøÅøá_Ö[‚ŒË?'TGsU«¹’·ÿ½û¢.E&…z|ëv&†aÏžá†-\¸ð|ÈZ&“IÈÔ‡ÈÃ0 ÃÊU¥o“~µ|PÊV`tn 44¤ü7¿Oâêâܼ…[ W×fM›¸8;l¹‚Ë æ÷ž“)Q¨Ég?ß<ëP9LC†±E‡>?î|¥©P«ŒZ6R39™óìpwúIûáOôTEl%ξ׈ÂgGWwvµ3 Ñ¹Ü„F”ë:«Ô–ÿê”§‹‘i³N~ÿ¼+È‹;áëÑȈaèÒ®ÿÙ>¹õ õ |Ûpܨsô=®ÍÚø2·,ß,7L7~‰XÄasdR ‡Ã–ŠE&y‡p¯·ÿô ÇS¯„W„PÈÕ72¹øá±™V…YOþ°n:üê‹Ï¹¼(‡wnûTâ¢3ÊÆ$ôòób‰\Rœ{û¯ešS5aÕ]„P®Ç'Kdâ¤ØÈÁάWyzªRSË»ºÐ¦óŒ¨7©R¹4+áÙ²AÎcO~Ò:jòÝÃ~{™’/åÿ·Ñǘ;dà ¥q¸ŸsûVj|œèItîû·r{{ûqÃÎ÷Þ¢E‹ÂÂBõKD…#ƒ/(¤º%±¹¬±Ùšùš"–tÊ…ç)äjtÉG{x|ånÞÛÕLÇ@=U©©]àȼ”+TîJøÑLûyZ5hN¶TžË.Q"§"„Ng ˆ]™˜G¡Y[.©@EàÆ@íA\p'ðïÊÝœçÇ»81ÍìÛî~œ¥)üüblQÊŽ ‘É_â iVg–ÁäKŸÕ$·61/¹U+D7'6×?2È÷WïéË;Š/ÍղȀø Þ½“ö*^üôq^™aŽã|šPô9rLïvæF Ã0 ]!-ÉäìúÌŸåÌÒ”¿ºoÅÿVö­¼ç¯Úþð£öw9ô‘Ñd²é—¥%秬˜ªƒiÅ,°RL/Aæ1]yW’+ì@KÃ’ç4 [„Ÿ¥±KeØ+dyäÖ€š||n Ԭ﷌lœ˜/A)¤éßužhä3Ûß:uÙèªb÷×÷Þþ&¿íw»Ù#:X}y(NãÛ7è¯q?+¾ræ/;˜U߆œjÇ–û‡ŸÉ¨”JÒ¥ ÍÎho®V®3à°Ù"‘iÊÌÎÎQ¾¦¨¹Â Rë t)ü.‹¯veÁtXÇsÒªGso\î¤x?ÕËqÒÎXåóHåSI­2êÇ¥ú €D•.0„òe ÕË¥LRöSk^UiÙ.¹õàÛ.27¾ 2Á‡%CÛL{”’Ç}”[^ý3$x‡LøNEæÓÕ7iÁÃÃd‚Kü[OJSÕÐxä1?ƒ¨ßWþVQ™S·ÞžÔ˜1{èå…Íc=.æ5;#¥ì[1ytDrmŽ ˆÛ¿P(011ÉÌΙÐMu…êËŠ• ަíŸ?ˆkj€BŠ/öšáÀÜ•¨kŽŽ5óò Þýò豟ýuÌZÔeBæ4J‚HNl sΫ)ý;ëKXWøi§‰íU$Lµ3ýó3¿fΓ.ë@ܨ âüëÍ,lÜzKàS ¬sKrQ fç¾Î’1+÷¾É²/“ršqãE!sE9¯©ÖN9y·ÆöÓ3¯/•®ú8Ò±¶¬²£­—7å=üyÍó„\’ýèZâW±rig(t–ìöåL‰œ´¹oŸ3À0¬{OGW7ºï€¦D 0þé•E‹éÊTpÁT¦ßº²Š¥’¢ŒÁ”·ùôû«,û_~ž$‘+в?ŸÚ4Þ¼ù\âÆ¿îü£‘L!)~úß:Û1ZŸ…h•ùÙÅÌgKD¡XV˜¿lÐ ôõ#LÏï¦Ý}“&•K“_\âÌš…G¢Jµn#ÚíôâüçéÆ-pO½ñ³yÓW_|–Èü¬„ã!£-[.Äq|b;Ûv“Hš"ÝTuíê²< ¾É Dpc º)æ¥i¬-¸Ë¡SdžðolŽ20kq2½XUà]Äc«‘ª%oôİ’Ù,F)y:@U!D¡Ñèt:ƒÁ@!d|>G(Ê•à8~{LÓ)osq/JÝÍr\L¶@.8·=¨‘ ]Ù •J5k>€'–—ÕÆùa-\g@@¬'(,,lÑ¢…½½½j‰–KDÅ"ƒÂü:57 RX6® ÷ÜWæ$qsnsïv ¨C&÷û!3£sE8Ž¿¸°kˆw¦!alÑ¡ï¸ÈD¾¦N]2ùo÷lí@£PíZõ:›£–ÿL½µó{7{•fåâ±,ì‰*ÕÜ)Žã·WŽà3 ˜¶S·Å%q‡x·v2 RŒÍm{ Œ-ã8>¾­µuÛ äùRµ£eî겞Öì.\S€ê^~n T7Òâ—Û/|P+<æÆn5÷¡®*™Ï~b:,ú¢¡(ÞÓ”áþ®üËŸón]Úø[ºDŽãø‹-û\"Et^œðÕ’ù¢Ï·Çv°±uó^{ôŽ¢dqmÞ‹\®©>l.³3šškDX@¤ö#KPµÄï¼èqÓº´676 Q±”—7C6èñ×û†5Ò©.kÇ=îr<á\_„ÐóKûg-’ù†ÞÞPÞ„=®ÀWôõ)èØ¥±­Yaò‹Û¹ÅÛæœw;:.9ÏpÊd?©Æ§¿v¿=îua÷.§Ÿv4¥«uÉ‹FýõÄùJyAÊk=5×f 2jžEãBO]OLËE ‡&-û›±}ÅÍÛ§ =.tiÀšs”Koov³Äîßxä^Ž÷à€)¾m*Ö°¤06tížû/y2Š‘[g¿ K'Põï´XN1 ¾}_àÚÌL.U¾3*L8<íRÇííOm±Ìû…î IDAT˜»ÞÕB—XABôÞm·ÿݦï¨?¶¯ikΨ’Ö?žü{ê‚ð…=áDè LT+’,ƒÍ?520fÜy&‰˜Y#¯Å[O-ÞZ¥Mç¿ãÛ †ïÛ€œ‚&" 2"ô„†:t# @Id0 # ‚§ @dD@d . kbÏÒüÿ$*âíó(7‡n^n‡þÜdÅ„ÈL&3%%ÇqÕÿ|>ß××—Ïç3™Ìó!kÃÂÂø|>D@-—„-:V¦Tþëð)%·1aæåUIUÕ¾´(æ÷;©ǫ̃ÄíᄄK‘Iá‡ߺ‰aسg8†a .<²–Éd2õ!2à²0. +W•ámûÁG VqIû“Y„PZôÒÈ$r\^°lМl©!„+„ûFLHʪ(.‘ž1<–/©9>Ÿoia!‰­¬82©äæÍ4Œ(Oüþxí>b»>D™…xy«(RÕÀ¢¼Õe·!³uhjnkNwus›4ç—Èljð©êàÆ@mã-eúp+c„yc2e0ªYSQˆQŒºz²«¬Í£+·þ™—Ȉ%b‡#•ŠÙlK™Tò,¦ˆÅbEDvž²%fqZ|tt´Õ‹œA8³2Õ·õû>Ævø¹G¼”Áíÿ7NùkBïFð©êàÆÀ·— ÔJŠ’ ]ödÜ_’‰!3< Y‘¼d6¨S–?gÀµâȤ"›-—I­¸VR‰ˆ(?Ò¾ŸÚ£„JE1'‚û»sí¬˜=~÷$O¤,O¹½|ßV­èNvV>Cƽþ !Tü9rŽGW[C{k‹¾~?¹öJS¡VµGšOòžÖÅÅÁ‚ѲmûõÇžè©ŠØ J<‡^# ãþ^íãiç`Awkí¾|W„f·ÇçX:ÁmJ¡Òmšt\rø/Õ£ZN4‘>´³£EÙ]mi-'”ä=?4´“£½£]§žg>=W#—×zâˆ*oNúÞÅ‘cÚ©§ß¿ ò_žøÑ»‘#ÛгkÿKI|òNu…ZîÆà½õ’¼¸M¿†¿û¥[Ï\ÙW·u wÜ·Ês^ÿ€|™ÎÛ=!³bî!†¬xÎ@"qØ™TÂá°¥bÑ„IÞaœÄëíÇ?½Âãñ²ø¨j"Ÿi+n½›œ‘³e"k¼ß¢07vc¿ùW~Úù6Cüæeì_ã…þ­B½‡·™ûY˜ø)xBÓ ¡­4j•Q{d ùaʼë ¢²‹®[÷j]ï7SôQElgâ™…xÌ™>¡´›A£÷¥ÿý41GxïÒ!“;3gMPk«»™Áž{<å.ƒé­Ô©kà„@à¾üW?ÆG%„uµ¥«œP27äýº³ñIéYŒ¦ý⿎äÔËk=qD• µñÁ'Ÿ'¤¤¬ñ—Îé?ivpܪ“± ©Faóo ï8ØuLÏÍ#O”-¯râˆ*‡…>–†!…$͆cw0Q0ÐÒ!$—¤ØÛ´IÏÍÕÓP@m¦ö»1xo½¤àýõMëV?n±=rq»¯Î¤Ç(XNÌÁué½×t¼Û¦gÒ‡ø¥ê•QPnÌÁµ½7û:ís·H9Ÿ¸ÚÅ !ô$°åÎéwÃ[TdµAIÓÏÂ×§÷Úèë„z»§óR§§ºÔ'ËsYŽãQwÓÙ––B¡€ÅbõèåÙ9a¦¹Â R9ƒb^äŒAíšr\Æ5£+¤¹Dù²#KSþÔö¡cZµõò^²ýi‚öL¸>2šŒ¶5ý¹Ì¤¬˜ª¿Ò‹G;iI. ³·õf©¿Ê$8A•ë)I[ä}ègaDlÐ ›(dùeŽH«¼®GÐÇ¢äŠIaØ"„ú—j 2ì²<ý Ôfꄃ÷Ö32ï{vþáñ•h9öÕãàÄÈŸþKB¿¿ù÷B©ÖºI‘!SÿKDÝßüûG!T®”´8~Ù˜ïÛ:³šµüE{Ó›‚ß ¤õ>gÀa³E"!Ó”™£š-P[aP©È`yß‘²þÁøDBþK BÇ9k;vUä‹Üs{–Û+Þ/èá8w_,*}:¨|ü¯U¦$²û²¥~þ0½›#CèCž‚ñ—–£ýÇ©¹Í;›zôöƒ“£×þ8ƒ|à%×&ýÚ"ï #´:Zåu8*ZvËk( VO#j·ƒ÷Ö3bï2ëujž=“¸çH¯ö<È@HþøíÙR9B—E׸£Çí~’‰"z#!ƒ¬JeÊ÷í‘Ð!ð䩾r׳ézqû &&&™Ù9“º©®0Ð|”PñÈàTZÑ–™ƒ8&!¤*Ë'Ú1|Ö5GÇ·÷™µlǕ裧—û£ÒÇü_ÈÕeBf4Êg‘œØåžWSz>ûËbW~âNc›)$ªHkcz˜Ç/3'óJ%´´é²H’MëÛ–>}¨$ºNœþÔ@'êN-ÖQ7ï­»´Y1wó¦î!Œ‚!„¢wŒ¿œZ„•cDÕUåFаë„(C aú½u.áßßÿZ|pÁPk󒌗>M׿œ†aÝ{:ººÑ}4%…ñO¯,Z´¨Šs#mMçl=“+”I™ç6W–O;¸oÈ”[ñŸ¥ \›üïŽ Í<ç£m—¢ùb9.¼}É0ï¢õ‚¥UfœsqØÕ"‰¼(ýeè¬ÃjµöŽ|ô>]¦¥¾¼:oðæ1»êÙœ‹íA¦ 0ñ‚½µBhæÞéÛO½ó2YªÀ‹sÏlãꄚëmÛÆ{²²ÖäÙ^ór8^”õéX°¿eÛeä׊®¶t•W!ºNœþÔ@'ꦎº1xoÝžÿòžÎL„ÐóÕ\æ¿6æA€«­mLT*±1äøû’ ^ò [ š­mÒ‰Qãš~%ó×û‡Sݸ,,$›Þ™e O»2AœB^䦵ìt¢8u3yÓ!¼>.nü˜R¨úÕÈL&Ó×ç!Ç кü°â‘ApÄ1tqi[;ƒîÝžq–£Ò÷­¼V^ ñÞ1£g#6͵u‡ýLOÞØˆºý÷®˜mSÝ í~uðúŸš:uÉžÛ#9òSs®A—Áóš-G*ï"„Ž­j»vL'¶QïQ‹[,¹º¦§½.UªµBÛøOncѲˌQ«#„¬»ýñïož¼±i-Ûu9gsæFBH¡ÀŠ’×iîÿ{¤«øúïFvæôv{]LÿîlÄB⮫5J «-]åjJ´êT‹±tÉë:qäM¨îêê$PW¨ån Þ[•Q 'òÄù²´ñš¢²D‹ÝªàݨY„©¯ï?KÉ73Φc¢”øoè¸×÷Æ•©M’÷áÉ£ËóûÌÿÑlKu#;·Þvn$RÁ«ónúþŸ>ÚM o0÷ †Eð[‹uÕ—;TßòhØà¯®îÿ±s¯Ö+®¯ëã O…ô›{n˜ô~ÁÛAΠnSß”¨ßˆrÓEO£’¨Ë.¾÷tdêY˦çÌE=ÁxõKCËÓÜÀž&õx¤ ‘‘Õ !té1ü¦¥‘ÁÄ^0ž&‘‘ "2À0 ÃÊ÷mW}›ôƒSЀÀ0„Á÷"–:ü» 8Ž—72+¤ªŽãåt0LÙ4y!ÔæÜø·gÝ—òê¾Uè`ç¯9ƒ p#áf%cÍK§ÖB¨Í!5¸1ðM<¯äOm¨O‘Á£#Á^M¹tC¦{¯qrEÊòäûýº¶bÒYVûýßåW¡¢Äȉ>9LC†±E‡>?î|¥©P«ŒÚ#Í'9Ï÷qw1 1¬›´_þDOUÄQâì{(|vtugW;ÛÈ}AhD…-óä0¡ÇÀεóê#1ª=ÏuÊÇÓÅÈÀ´Y'¿ÞäÅðõhdÄ0ti×ÿl_©AÿžjÓnïîÞÚIÍ$çèQØRÏÆ\ÍÀ©MÏ?£2T-SUFê:5àÆà½À—ù:†¡§á¨#¢P¾Lñ£¦\dÈD½Æ!¥Âϡ֎ˆÆ@­{¢w%‡#‘OGÄ4DƨÏHÛF§N¥æÒ;:º¹Ú!5rG Í‚‚þßÞyÇEq´|®Ñ¯Ð» ¢‚ öcKl1»±Çò‹Í«˜¨XH¬1jL|c,XcbÄä{‹Š"‚ " Gïw”ëóûcáX÷n—ãDîù~N?·³Ï<óÌ3ÏÌ>7»wD`£@E'>T©å7…8öØ@ßÞàì;115[¡VW•ŠO~?Ÿø 2ÅÅzë™{Õ µ¢ºìÒ‘H¢ E˜|ˆÔ{Ö¹û9 •üYJü^‚°D±ª(jʼn‹]úzõažR­,κì5ý×'z{Í\˜*ô™˜š­P)rÒÇûÃÄZ±I¾NÏ­PÊ*þÚ8ÒÊiìèàåibâp„È7²I–[ïÞÿãËÿäRœ@7F9ñ íÇ%¤f+TŠÜ.Ü¿‡Öþ¦6 ´RZNCôšfüé/œ³WÊñƒC áćX-LJBp} Ô•‰Äâ ,«Àß¾‹Û/­+w±Ægîa…W—á#‘Ïé!×¥ÓI&q1îÿ)~˜‡ÕJœu{aS 'ã3ƒ4J6ÏŽxé#\û¸BWÄŽÇ>u/—Y sf°K,Õ–?ZÍ÷ 7PEm˜'ÿtY­öP!½ÅwÕ«n‡¶NŸìòŒ5|Ï0mÝ“%uM¨åy¡ßKjˆC•\ÌæÚ6ɲI «u@7Faü5åÚ3Õ…1Zû›Ú4Ðz3ƒÆ½4–Ë®2¸>ê„ë£×f`®¨î=õ^hô¶¨«“Œ'“ KoaS '#3鳸©Cº -x”5EÄe—)5ºòwö®ìë#rëòfèÊmëKd˜3©5µ²”Í¨Š¢VÈ¥ÞXáðìø°%|Þšz“1²ot›d ­èÆHÈe—’+hF7 ´Õ=ƒWƽÐ>‹ÃCºa F¨îE&…gé½+±wy¯Ü†É­³N2\vƒ ñ2¥p2ò9ƒ°7'«FGý[,¥|a!¤÷óHÏVÝÌ,»¸wE;MÆü¾žíHÑÞeÔÞ&Ô+S·(4¼Sò ƒ*Úû\U¨žËiT cþП®¬îóOÈrYÍc‰ 7mŒžÿœ¨jv'­þ¶ï+ cˆ^@?oNF££P±Tÿ³Š,}AñÑ*”Y†ö®@š Ô×é®üÌ:©¡©ixRcdRádÜž9›Õ0 Õ5Ú´}™·0Š´×§—êüX®…·á2".;³VE¼¯)>NùÜCÝŠ\Ì ŠaÏà‹v‚oŸT¾ø‡­pOþš ò6l” Þ$†Íò¡–0ÞRYÌ0Fážü¨ÆH*þÁ覶ºgðÊ¢ö h Ù,LЦÏ÷zæÇbí…F+`¸ÎvlÂáddf0߃?fýoÅÕJEUáѨ÷´“³àú*;Ÿqgî=S¨5U%ÙÇ7ÍuZHÌÿõ±7+e*¢úÎ_ë­]§é]#ôÊ,ñŽÜ'‘«$y÷#ƒƒ)W÷žo,¸ò0_©Væ¤&Œõ,J3¨"×í`ɽTP]‘˳òÃç_"ò”˜š­Pk¤ÅY‡£§ÚuYŒ1žÝÝŵûG†/©â3‹„&œMËQª•9igÇ·’Ÿ¨2dI¥³„amÔwÎ¥¹'ÐQN|¨°ýø³ib¥Z™›~qNß!F7 ´ÕÌà•…1D/d´…|¼þ7\­ÄU…8ê=ƒ2„pìM,SaE5þk=Ö^h´ :-¹¸ gÆb+?Œ1>¿ûN©ÙX­ÁÅY8z*6¥p223džÓ¯“9‡-pé¼x×uòÀ‡'7íîcÎa[ðÞr«L†1N=µsìÀ®| ®™•mïa3âŸJuuÒÉT<:<8ÐƒËæ¸ ‰I)Õ¶E¼É»¸ã-w.‡ëèÝ#rÏMU”–—VNr°23ç»Îß–L”¤‹ØÎœÃ¶¹™ž"‘cŒg9;Í¢liR–6JaÒ¾¯ûttáqx.û|½ÿ¶^1æC½–0¬ò%Éû†µã=ï†1ºñóòîÞöŽ™w÷a1)E,[«­IM­4-h9a ÑkŠiå?]aæ)ܯæ°±Kg¼ëzƒE˜|xj'Ø[p±•-6²NŒñÊIØÊ ó]qý‹Æí0‡E®xJ86¥pbEDDlÚ´ niµæo7ùÇÉ($WùárIx€èµê_G^d9Ž<‘Ü I²\4ÏoöOà¢x™£VÞz±-d@ËZ õ…)Öþ˜c“>x%ùféêÉv“ŸqEž#¦†^Ýúxx]Q Ñk ˜Î5µÌM¸›€6¸È €ÌF¸¡ýçá7D¨Ï ÞëãŽÁÝ 32 3“ÅIÀêà.ÐýÿöÕ¸G÷®öð÷x»¯ÿþŸ69ò!3€ÏççææbŒÉÿK¥ÒQ£FI¥R>Ÿ½nÏž=R©T[þn´YˆËÿ»¯ÚÚŠjkjíííÆ îÞÅ,ËÏÏ/6zŸÏ'ddÒÖ¿gà$`9 XMª21hx‹²ÚÀ´ …ïH¥R;[[¹Lîèè R*.\ÈïуE”?}²/iÝnâ½¶J+Î Š$Mþ³î’¼Û2žÝÞªû˜Ã/nO£k´!‹¸“€u¥RŽR˲´%0€Æ½¦wêý³ºW'^ñž\!wppP*åööv*¥ânr•@ ˆ‹ï?wKò—ù÷oݺ%Cü¶Á‰û^\Ieæš h˜òæçµª×©— ö^}¥ø-¡9BˆcÑþ~ÜjÏᛚ}qÚ¯=Œ!zMçÍ!ÎßÎO¼â='G•Ræ`o¯V)• QÓk8‘:«Ÿ$ÑÍÉÍ‘?èý·ËeÚòÜKÿ9,ÀÇ‘×ÎÍqäØéÏ=@UgÇ>®OgW wgÛac>Œ9û@W¡^ÊgÝå÷LàíakÖ%¨×7‡n¨ŠxC”ô–(L;¶zdO7[ž`·;ãè:~1âçÞ«7n|GðőǺgõÚƒJ9B(7ïÚ³ÿÆ£Éz»Ó¨…:°K˜:‘XÜÒ›Óæ_9q0ÌèFÓ¡„1D¯i!¯ˆÛ÷gB•ûÌ8ê”ñ{aµ^1…4eÁÛî>þo\.“ÓšqÏ@!—9Ø;¨” {¥\6ë£{~i'ÿÆ}æ±X\,EÍ“Œ\°rôwWr K·Ì̳(,KÙ8|QÂÇßÅ?*”?LO eµx\B(|èÄ® ÷¤d×<}ú$j–oÄø]…ze( t?OÌ =¶çjVIU¡õÖýêB®!ªˆ÷E\$ÁÉ'ÞEå_ˆ˜º» êØ§¥µ×Nï·¾òÙYºFªe¿ü»fÓ$Ÿ·6}ž²ö+]½öä[41:myÌͬ’ª3×>X?„(gè®…záZúýrlÂô©›5ùšÑ“fœøÕË‚Cœ2¢QÀDh!a ÑkR¨äyO&¯ZþÕCÿ‡¯û¬Yp¼î„¦vÁ³´b‡ÇŒ|Ð{ýåÓÛnÿ™NkÆ=G•Jáèè ËD"!‘.hÿ§îìDDD|¹rÓ 5‹U.Î¥¥¡è ‘Eì³ðöBŠHg{Î÷—rFº1¨¡“q°ÈóŸ|è$`m|(ífCV>Žê1¦âɃ-†¨¢¨ýª‹`Ðõ¢¡" âPYÔ¹×Á'·Q4d:ñø‚»'§ „B|m:'憑:KgÏWþ»Ó9Z·T>YÛãýÒ'¶6Ú;¾Û›‡-¿“#ì³ÿxx¿†Õ(` ´¨0†è5â·­O—©‘¦Êï“U£ø•ï´ë°ü~É({K…ôÊÚD·¨ñ±ïEgB¯Å-5NÆøê•{;»ÚÚ@0hH»¸øþY¡,Ý' ^(3¨ÇG„üçìÍ™’œ¼w´ã$©D\êþ^ê¡UK¿Ý–gö!1ÂÙeŠvvæ¡’[ûo[wZGðR³ÐÁ]››››cQ[[ccmSZV6gÞÛ ·ÑwV ›¬u#KJì6$é£AÓWŧ–ܵÂ]“6ÈsáîDz8™¸S¨W¦n]hx§¤¦67Ç ¡Çå¢;ÄK7-¨w¼¨ú›î¶„Íoüß…üË!Y2U£öPÜ‚ŸdèÁpêþ½ÒFVIË cˆ^SÄï³c¼K .VÈUµ×L ÿ;Ÿ(wè»ätt߈w»N-/5 Ä-ƒÚÚkk뢒RJZ {+ÁøÌàx~Õ–`ks„ÒÔjËg»ñÉ®¤»øúôùYäö„[_1Õß}|>· Ê „„\v¶LM¼—•ÅR”Æ–Ô4ôÿé+—¹ ª˜îbs@,e–¹¶ôû>ÓÉfïhqüI£öLu±Þ›-i(ÏÞií2ÇÞ½¯¥Q åÓ*¢·Q|‰úØÇÜó§E—†ÇsÌœ=ÊÊ$oìÜ¢}צكߚ>ŸÏb±ÞìÙÙŸ7ê=_"Q˜y'á‹/¾ÐýV e“]m>ÿîDY­JYStrãDmù‚_Âw{ñ~¶RƒkÊrþÜ>«cÏPb{`Ûé[R¹+k2RÒÍDtuÒÉÌpã¹'±J¡®*HßúÙJ­§†ßÌ(PiTy鉡lž¶s±Íy[rÿ.ª‘<=åîì ùñ“mÌ¿œž£ÔàêÒ§'¶LëÜ7!´p k×sBjEî’s¥fv$+²eAòªUÚ²cîãæ]y ViTyÎ…Õ—3÷ŽbaS1®Q mÓZ¢·ñìd°«-—òµáγãœm_^Ï¿:½#±‰0láŒ})ÿ îNk.2s%äŸFæóù£FÞ‹ÅóæÍÓûø¡ñ™ATÜ!ô¿åAnæ~ÝÞ¾ë°Õ=ɱïÊÿEÜþéàööÜνÿû·Í¯ç7"„.Û™¼m~7O O/~x°÷ÜOº:édÂOîRÄ|ÜÉÉ|À¡WìC¤¯B!„­ Z7­w;{Ë¡S¾ôûOâÚÁîtªÈµBÛÂÆÍéjÛeÀ§SVF9¿½áϯ{nœ7°½=·K÷‡Ò\NœFi4X£Ñ „\< j%£»…h ®¯íØã«šâ#Úã:ä»ß¾ X;½—½ÕðéËü—Ÿ[3عwº2@éqm›Æ½¦@ï­÷óËU:/MaeÝ=Ü ¥vké¨öà±fÞ³‘"âÿK¥RâÙm‰®|s|7€¶ü­E€¿µØ:л_ _Ö 30Q ^ p7È €ÌÈ €Ì€¦ÃEN*GP—ÌâŽÁÝ 32 3“…Åb Ýÿãââ®^½êáááïï¿iÓ&È À$àóù¹¹¹còÿR©tÔ¨QR©”ÏçÇF¯Û³gT*ÕV¿¨´5ÊÒöì·›în® .ÿ?î¾jk+ª­©µ··,¸{³X,??¿Øèu|>Ÿi {,‹Åb5©Ê°Ã[šI@k pãÒZÀêÊ/†/*UjˆC"÷»ˆé]}=ÛyµoïíåîæêääôAäQù ¶Ä…ßÎÖV.“;::¨”Š ò{ô`åOŸìKZ·›xß2Œ›<¬j’<ÍŒjVsvߺQovµXñ,mÚô½hUül£MjíëÁiÅÇ IDATϦC··¾Ü«n»ÁÓ¶0Ñ0† 5•Õ‰#ìmcF¼WU•Mõï²)Å|ÃÉÙϲ²ž>ËÍË/**Š]÷a“®ʪäþïüÑz÷ ä ¹ƒƒƒR)···S)w“«A\|ÿ¹[’¿Ì¿ëÖ­6²g`ç³.¼ØÔT};¹Û÷éüègóË¥•ù™ÖüäȆQ½½L1+ǘøcuEAæá Ÿfý2÷Åç`Ujñ#gºa AÛ·j˜¸6váÓ:©åGuu|‘†jŠN…ü4a•LÓÊR4b?ÀÉÑA¥”9ØÛ«UJG'G¥BF”ÇôN¹•€BØ(nXݧƒ#×Ü&hðô륵Úòìs»ƒtá›s-ùý†Oûo|:ÆXš7kDo{sž¥¨×Ð)»ãÒuê•ÑÎgÝÃ’äýCƒ¼Ì8<'Ÿž+ö&¨Šìv#‰Âä˜Uý:¹šq¸ŽÞA‹¶œÖµðß}c:Í9A)¬ÌúQǤ}ƒaÓë­gîU+ÔŠê²KG"õÆ7 E˜²~ ê=ëÜý…Jþ,%þ/AX¢Ø@UµâÄÅ.ý?½ú0O©VgÝ öšþ늅ŸºÚìi, Bï‰LW¨ä’¸-#…í—2{Œ\E)«øóÛwµUrâ ÚKHÍV¨¹ÿ\þ¸­Í†XK±jÒ„¯Ós+”²Š¿6Ž´r;:x9Ñâ_Gˆ|#1ÆX#mg¹7·ª®ŽFhm~±BÖ”Ìà×¢sõn¡FYîfÎÙ_X1–<[ }PŠ1VÉž -òjŒqN|¨ÐgBbj¶B¥ÈIKï# Kk›;gkN¥¼øÁ!¢ ²3sÕ{ˆÉ.²­.Œ›7z!hÛi¹ÕŠsf€1~¸{¤µó™æ…ÚÚÖÍÑ?dß³Ç7×ìþ·¹ˆÏçK$’¿¯—^º˜w?MvûVYÆ#µ»»{jÚ„ØÁýüü$I³e h”lžñ6ÒG¸öq…®ˆ}ê^.³:æÌ`—Xª=,´šïn *ŠÚ0Oþ鲆…ôß=”R]ÈeW¨4.©'JjêÕÚÇl®ˆÙc”*ÊÚ m•0þšŒr­XuaŒÖfC¬¥Xu²¤N^-ÏCý®5R.fsm‰÷™ÇÆzŽ8PïÌe|E†¤¢kj* o%žÜ;whsõÞ˜®}·¤aŒo}ÑÕ?´W§Y—0ƹ&9õÚ­õ9ØÊ3Öð=ô†-îª@q¦TüƒÉ.²­.Œ›7z!h[Ò§±¼lƒÞ[.7àR­Qk0ÆEI{?9õŒrªüáÙ°)oõºÛhf QW°³{0ãEÌŽn/ê¿ý~«ó66W.ç?¸/¿“TÞhZ`|f }7uH7¡|Ø7+Sêê;{Wöõ¹uy3tå¶¿õ¥ 2Ì™9T+K‰õÈUµB.õ‘ Ïžb¡ˆË.W6¾¤’D4ÚVè<ÆPEÈe—’›Ó(ȧµ–Þ*=‡u-¨$D‚ÄrÆøÌ$Ÿ7¶§7ÚÙºÇUxVíß\²õ­Zºþê½…¹—¦¼–;çrnÙ8ŒÁïëç2.!Gër°iêGŸ0L¥s9|ΙêZ“Í Z]7oôBж>÷: :Òÿ“û%äòkÑC¶ýSN.yüçúI¿ga¬9>®ý;G“Oå_Z-àYô˜÷Z“‚1.ºµt?¡•y×°›º™Æ8;n®¿w¡BݨyºfÔoŠo³³rß“TÔº¼Mìü“®H¾]ñï?ª¿¯1ßJ0>3˜çÁŸ´9¶P*£LN[J(?Ÿùý{3nÓWŸØñgo¿‹Ÿ¿ÙO'Cˆiô-+Ä)…¾Ì€A]f 2àƒÔW›ÝùU†}Œ¦ÒyŒ¡Šˆº.ÔO5j­û.”Ã~Òé£3X#²1‹/“5I­!B74º…*Y¶€g‘ZpÅÊnáüÿŠ],økUzý£V–j?>ê&¢¿>™­.Œ›7z!h[#l-ÞÚ†±:!¿áÆ–²:sÕlû€McEUúæ+«ôs!‚+u¢d'»;yþóD‡^ëR”ÕiÞV6›ÿwçlˆ Mf€±z¾·`@ô]½&)k3>ù3Å J³ú£°Ì†—é?ãðöÜ-iu{É·+ý£¼z¥’4çž9›Õ0¥IS}™·0*£œ¹nu~,ù‘ŸFeD\vfý¼ª)>NYŒb «Ÿ¿›°˜AÃBöE;Á·O*™­zôËû¾ÓR³È;ëø ]¶è<ÆP%Ü“õ¯þ½DC¬5nmU+ „.WR–Ú¸~ÚTµ†DH£‘@.Ühß;<ÈgâYŒñÏ"ÙùoÒJ†{ò×d7f£õ£¯ÛÅ™ä=mS£Õ…qóF/íkò9ýÆÊ!,¶åÂÝSĪò~°v™‡1¾Õ“Èâ¹ÓeÙ­‰"9ÑÅ¡wô½‚[ã…^«1Æ7Ãé3\|w×ÂûQR׳sG¬›ÕO¢ÒhÍÈMü³àòW êq§)¸ö½³ʼnG­nÏ€ø†ñ?q+ÁÝÝ}ëÖ­zÓã3ƒùü1ë+®V*ª F½§×‚ë«ì|ƹ÷L¡ÖT•dß4SÔi!ôëcoVÊTEõ¿Ö[»NÓ;cõÊ,ñŽÜ'‘«$y÷#ƒƒ)‹QÏ7\y˜¯T+sRÆz %ˆT‘ëv°ä^*¨®ÈŒåYùaŒóÎ/ùNJLÍV¨5Òâ¬ÃÑSíº,ÆÏîîâÚý#íÞßÚ: ݘô(O¦R×”ç%üÖŸ/Ü|§¸Ñe‹Îc UrâC…íÇŸM+ÕÊÜô‹sú6<Dg틯­ã»kûZ»[õÝ”ö"™]õ Ýxeý1!ôÑ"Œqù¿KB#~kxBM|f‘°Ã„³i9Jµ2'íìøöBâùS½†‘™÷Ï•oô2݇¹Z[7oôBоJRnPJþüv‹ÅúòVÑóië`«î‹Íáp8Kû†’üû˦E3?p@H[¥NžÅAq8VoûŠê I „º.º káï“ç­Y>šxÔƒl 6‡cõõ©'­tˆ$@"‘øùù‘w šsÏ@’yjL¿Næ¶À¥óâ]×ÉwžÜ<´»9‡mÁwzklÈ­2Æ8õÔα»ò-¸fV¶½‡Íˆ*ÕÕI'Sñèðà@.›ã0$&¥”ò£yw¼åïÎåp½{Dî¹É ŠrçâÒÊIVfæ|×ùÛ’‰’´cÑÛ™sØV"×!SÂS$rŒñÌ gç YäUõÔÎåow÷±1çš[Ûõ2iÿ•<ò¢£÷»‘ c¨‚1¾ñóòîÞöŽ™w÷a1)E,[Û–^ké–B†&to«j[°Y±%µ¦ _k¤ë¯Þ¡¡zEUŠ×ò©L…1Ö(ËÌÌïV)È­$íûºOG‡çÒ±Ï×ûo3VïLžgÀ;”ïΙ`rÐZ¸y£‚öu¡’‹—®Z]Cô¶Xr¿ì4ý÷ÞÝ|ùæ\„Ô“.eJݯ¦÷ç›!„îÞþÙªQ[/íš÷šlFò²w.Í8|ã‹~ë×¼élRƒQ©EÃb±"O$E÷B’ìÍó›ýÓ+øI±‹+¶û-üœ´Â0†èm±hjº­¾w´GLüÜ ×R0pøäÑNíÊ7S«e—oŒ¹V:c×µ¹£º¾.ûtÍè±ê|/s سƇ«~Ïxi$ùfp·ö\¶ƒ×„…›%Œrë_)›BˆÅây÷šøô„΋« Œ c£Ñ½@ áÉoçÍÌþ_èêgðFËî&/ùyMÇÊ&æíño%÷6ç€Càn`Òp¬lB3/ŸW´ Øà 32 3À@¸¡ýçKÀÔeïõqG€àn™`™“€å$hÚŸëœ4¼¥™Ô2õòtRÑå-Óó¦3³LmN­GËBÈt2ƒ" njFI^qŒjVsùк‡uíìfåædÓ«oßÏ—®:Ÿ’m´I-ÓQ/O§!PÞ2=ß‚i5a #Û–.Ïz_/»ébÃB²‡6’Á‰û^¨>VmŸÝí¿ÿðWì>›–#ÍÌÈܹòãg¿møðm/ˆ$ Õa ¼Š%˜xQÞm*3H>5¢›“›#Ðû3n—Ë´å¹—þ;sX€#¯›ãȱÓž{€ªÎŽÿ|\ŸÎ®îÎ¶ÃÆ|sö®B½2”½DÝ­Åò{& ðö°5ëÔë›C· TE¼!JzŽ?K¦[=²§›‡-Ï?°ÛŠqº>92á°uTÌÚÐÀöÎfŽ¥Ð¹ÿè_ÜJ+¿·|?Ow[³îýŸx\Éì1ÂÚ*–íêänkÞ£ÿàý’»Ð¨µt¤!*šwíÙãÑdæch2Fà\ïȾH[@ãflym¡‹Ì—1%bó€²OÔßÓQÈÖ~|ç²íæäèÈ·}¯~ê„ïíõót´5³ï7ؼ~¸YÙñüq}ì]-mmÇ|h¡ïBC§S«Ù¾þŠÀ=¶ZÔÓÍÑ–gØÍÆÄÔøÌ`ä‚•£¿»’SXºe¶`æ˜íDaYÊÆá‹>þ.þQ¡üazJØ(«ÅãBáC'v]¸'%»æéÓ'Q³|#Æè*Ô+CÙKÔÝZœz.lÏÕ¬’ª„Cë¬úÕ…\CTï‹$¸H‚“O¼‹Ê¿1uwAÔ±;OKk¯Þo}9ä³?²(míZu~᪔B~»O(V-ŒÎXÿÇýìÂÒ-³,–Ž[Ïì1¢.QåYAñ†©\m•¼s¡“6>üúè§%Uq¢RWŒÒÊb­^òÎ-š¶<æfVIÕ™ƒk¬BxŒnàèÌ&c´1ÌÊõŽì‹´´0nÆÖ™×½ ½Œ)i: åÄÿ6»+$‰™¥·jÏŠ¬”w¥¸°´j¶@P? „0?:£êûÅÅÒ©\~ýpó‡NT-ÜS–]SüôIÕ,_¾¾ ƒNb£ôÄ»!ö…áî‚êcwŠKkËOïÇ—C¦4 ¬ˆˆˆ/WnzÁÍIç‚ÒR„PtÈ"öYx{!E¤³=çûK9#ÝÔÐÉ8 XäIK>t°6>”Îv³!+GõSñäÁCTQÔ~ÕE0èzÑP‘q¨¬NêÜëà“‡ÛÈÕ}í8ÉÅ*‡év”“€µïiÍ{v–!µ,ÓÝ­wAY9ƒÇ(UT²Çn}ˆ*_ù lÿ—½ØGDˆÕôê0“°Ùkõvü+ÝéíU>YÛãýÒ'¶Ò ³Ù/h ³r½#ËЖ~µ€­.Œ ˜¦¶Î¼¶èm¨§¤‰ïè& ŽVeŽL!4§[|œ‹ë‡ÛQÀ’<­‘ÛY"„ì±£[Ÿâ²r„ƒ=Gr)G¡³òëmQW'YƦ‹@q½HQ? ¨:É¡×Á“P#3ƒjq|DÈÎÞ| ‘)ÉwG;NR‘JÄ¥.:©‡V-ýv[žE@ð¸Éã?œÝK߈N†93Wb³úÖ4ª27§e冨¢¨õµãHT²=ž}~ésQ¢£çv‘JÈmdIÍ«Äõ"ØIÀ&Z¡óC_;NR‘ÊVÛV: Í´§µVïÚêkǹM ¬*suêPPVN7pÌf¿ 1ÌÊõŽ,C[H« c¦©­3¬-t 5㔄̠ÑB–8žò³›Xõ£ p°Š+1ªnG›8Å=´Šÿí6¶E€|Üdù‡³•õ+¿Vy#:I8ØqXÏ(âٛ̀y7aŰɪQ7²¤Ä†|ÃX"¤wmš¾*>µìä®°Až w§ ú{ÚuzeêF¾á’šÚÜ\#)BË5Dwˆ—î¬þÀÁêTiM£ªHK.«Q1Taéd¸M²–®›ä¶q};tÇlö ìœÕ¬mm Œ›·u†µ…a}kö) Ða3l2U–%Õÿ¬¢¾AVM_UžZV±k…Z“a3È“¯³ò7¢óyJÊ5Ú'%‹%¸Ø”ÔÈÌàx~Õ–`ks„ÒÔjËg»ñÉ®¤»*ùôùYäö„[_1Õßæ~îQeBB.;[¦&ÞËÊb)JcKÖ8éÓV.sT10ÝÅæ€XÊ,òõ ‘Q Ëî­÷ñÿÄh10ÕÅú—g ά.Ø×$kétîÍ–4x,{§µË†3Äl£aV®wdn haܼ­3¬-t ½Œ) Ðaž_% Ö4e¸‰•_ÝkdmäöŠ[-tV~ÃuÖºØXšð€™Lvµùü»eµ*eMÑɵå ~ ß=vîÅûÙJ ®)Ëùsû¬Ž=C‰ím§oIåj¬¬ÉHI7 л©Wf†ÿË=‰U uUAúÖÏPjý85üfFJ£ÊKO ý`ó´‹ lÎÛ’ûwQäé)wg„PÈŸlû`þåô¥W—>=±eZ羡…]»œCTé0ý«¿ž¼tSÊã|…Z#«Ì¿ôë†1£6,9ºÎh1ðéö9»ÆÎ»ò W¥Q<¼´|úo ‹;µ_vÌýaܼ+Ä**ïÁ¹°zÑ œ!fm ³r½#kt[€–ÖÆÍÛ:ÃÚB×Ð˘’rWÁw'ص*TSdnØp; XV§o±äj¤¬á¤¤c•ŸA§Ú’Ë+ªa==åèìªýñ«曥ç f•>5ß2ÍÁ¤4""‚üÙÝÀדÔS#{w2ã°ùÎC¶^'T§®ÙüV‡mnãÔÿý3Ù²" ¾tlç¨7ºÚXpÍ,m»žq,]ª«“Næqòá]<¸lŽ‹ÿ®•jÛ"Þ¤ÞÑ¿³;—õo×#|çMUÚ.2±Ë&ÙYš™Ù¸ÎØL”\ÞݯK;3ÛRèúÖ„ð yò" žèì8«ÁÎJeÌæåoùX›sͬì‚Þ™´ãLžÎÎÒ=¤óC•" Žß±<°=‡cæ4ì‡kE,[Û–^kõ¾(:~üºG‡çÔ¡Ï?ÝÖŠé8Í6ÎfåzG–®-Š=ðjäÕzÂø¥¶N·¶0¬oÍ2%Mù…"^§ž’÷î¤á°5Îk¶^× P„ɇeÇvÊÞ誱àbK[åàéRŠÎ" ._6Imi¦±q­­¿"”í‹Vti§á°5BWÅ„ð2SÐæønðJPH¯útç%+ã–Ð:LI ­Â´dœ¬ðCIá£z!iö¾¥ó|§ý> Œ_cë0%õ[yèE‘Ä2àõ“ðË7QßLî8ûWè9xbè_߼üfé eüš‚d Њ¸…·þzû×TàÕwh€ .2 3€.BètüŠ'õ™Áì!àÜM2 32L"3`±X,«IU†uCÞ!\êî°N.B›MŒ~óŽ)DAÛÖ`±P¯@+Î 0nòð«5Jrba\.ÂwŸ©Ñ9µÈWdD¦Ðù™aà‚íüùŽX­Ñ@>Õ¼ µa÷BCоžË³Þ×Ë¿Tj! uFDDĦM›Zïl4"?x‘º,kIgÛÊ]÷ì¦-,¾ý¥ÿóÒûkŒ60|h^dÐ_žªVçacÚWhͦ{ÿjZÓ!""Å«ûtpäšÛ ž~½´V[ž}nwð€.|s®%ß¡ßðiÿOÇK³âfèmocγõ:ew\º®B½2ÚíÝÃ’äýCƒ¼Ì8<'Ÿž+ö&¨Šìv#‰Âä˜Uý:¹šq¸ŽÞA‹¶œÖÛk„Piêjk×i*Raˆ·`Ó£r²atþ!Z,IÞ78ÀƒÇáy :ü¨¢Q—ÞøyYöŽ<Ž™gà ¯;bˆÍäþ,¬ÆÏs±&+IÚO(1síÔoÕ;t®¦x¯øöÞÁ\‹ÒqÝvéúËÐ.yhèN×H½±Ç<t 1›§·G†y ¡u…ñ+Ž^“ Ú—sLïÂáÛ{q f±¬Æ±¹ <kc‰NÞ‡<0‡‡aíeÅá½±9¶á¡S°v’[dÐI¼ê¯8fîäŠ9\ì„éW×6‰ñ™B(:ñ¡J-¿q(ıÇ¢°øög߉‰©Ù µºªT|òûùDÔNq±Þzæ^µB­¨.»t$R﵄N†"L™ðƒzÏ:w?G¡’?K‰ÿÀK–(6PE­8q±KÿO¯>ÌSª•ÅYw#ƒ½¦ÿúDo¯1ÆËºØÍ?+&J o,vìµ^¯ºþ!Êß™&®PÊ*þüö]aû¥ÌUrâ ÚKHÍV¨¹ÿ\þ¸mCÚŒ1Æùh;˽¹UÚÃ@kó‹2ŒqN|¨ÐgBbj¶B¥ÈIKï# Kâù±s¶æTÊ‹bÈ úkx»Ì§=¤‹=æ± kˆÙ<½=2$È[NfÐšÂø•G¯ií«Œ?ý…s¶âJ9~p¨A!œø«åøP&9#„ÇDbq–UàoßÅÚðs±Ægîa…W—á#‘Ïé!×¥ÓI&q1îÿ)~˜‡ÕJœu{aºÕ2š«Ž’Í³#ÞFú×>®Ð±ã±OÝËeVC'Ã<Ãw‰¥ÚÃòG«ùžáª¢¨ óäŸ.kø|£Þ⻇Òi(K_kíò¡ cŒ5 ¼;ŸT걺þ!ÄN”Ôl®ˆ¹J˜MF¹öLuaŒ¶!m&È<6ÖsÄzG-ã{,Òê'Yyƾg˜!ž?[.3ð"¤·¿†·kà"K{ÌcA׳yz{dH·¨Ì …ñ+Ž^Úד0 ŠF‰INÀáúîàÚ ¬ ?ëíŽÞuu’ñäcRXbé-L¿ºBfPï¥gqS‡tZðÈ»dc—]¦ÔèÊßÙ»²¯È­Ë›¡+·ýM3èd˜g¸ŒÔšZYJD¼!ª(j…\êØž=Cn±"Ð~^¢¸àÚ"—7¶ê*¤ó!FòF{Š®ŠË.%»T£ Ÿ2Äæºz*É‘ ±\†1>3ÉçíéZ%ä!ÓÔû°QÏ« ¾éí¯áí¸ÈÒÅóXÐ5ÄlžÞä-*3hEaüŠ£×4ƒöõgžÅá!ݰ¯aŸŸ,LêNé½+±wy¯Ü†ÉsP+À¬“ —ýÜ-„0ýê ™Aó<ø“6ÇJe”д¥Ìÿçg÷¿7ã6}õy€öö»Xçö›^BL£oA!N)ôe ªè&˜ˆË®Pi _RËþùÆÚeÊöf¥L¥QTßùk½µë4½³Q¯ÌoáÈ-q¹J’w?28˜2Iz¾±àÊÃ|¥Z™“š0ÖK°(AÌ Š\·ƒ%÷RAuEf,ÏÊcœw~‰ÈwRbj¶B­‘gŽžj×e1Æxvw×î2£È§èüÃ0Eéªäć Û?›&Vª•¹éçô¢=Eg3w×öµv·ê»)M[">³HØaÂÙ´¥Z™“vv|{!ñg£žÁÌ€¡]ÊиÈÒÅÃX04Ä`†y Ì ZQ¿²è5Í m‰{ëÃÕJ\Uˆ£Þ3(3@ÇÞÄ2VTã¿Öcí$ïÐé´äâ‚jœ‹ Çž_‚}'áÔl¬Öàâ,=7¶ºBf€%™§ÆôëdÎa \:/Þu|GàáÉÍC»û˜sØ|–¼ÝiIDAT§·Æ†Ü*“aŒSOí;°+ß‚kfeÛ{ØŒø§R]t2ôà²9nCbRJ)_þÉ»¸ã-w.‡ëèÝ#rÏMU”;—VNr°23ç»Îß–L”¤‹ØÎœÃ¶¹™ž"‘cŒg9;ÍÒÎ"Ê=?òL#Ÿ¢óEŒ|ÈàÒ?/ïîmÏá˜yw“RÄb±µíêµ™Uíc 6+¶¤–\˜´ïë>]xžKÇ>_ï¿­-gö¼!ÉCÚ¥ î7¾è,Ñ{ ŽehˆÎ<†ä-$-h¥aüj¢×dƒöÕ¥”üt…™§p¿N˜ÃÆ.ñ®ë aòá©x`WlÁÅV¶xØ LÌA²NŒñÊIØÊ ó]qý‹Æí0‡E®xJ8nlumK´î_:2A’«|p¹$ɸêU¹;\zÝ®*ØžZ]CôÀ« .h?¯y")2¸’dÿ¸hžß쟌Մ/®Øî·ðWp)Рâ·U~yèƶ-…¤#ß,]=Ùnò3®ÈsÄÔЫ[ßa^õ4f±X,Ï«çñ?¼ŒE_o£0v€qa¬`//z¸¦ÔwЙÀ!´ÿ| 8€ºÌà½>àÜM2ôóÿ̶ÌìmÆ¥IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/group-initial.png0000644000175000017500000012247510032262136024563 0ustar frankiefrankie‰PNG  IHDRbׯÊo pHYs  šœtIMEÔ ×xy IDATxÚìÝ{\ç¡ÿñga‘kpA‚—¨1æähH(5h´mA õzlñµ^ÀF%ÆsR›œ¦jN›ksië‰Ç‰¼ÅD‹†Œ€B1‚ÜaÙýý1¿ÎÙ.»Ë.×½|Þø‡ÙÙgžyžï<3³«Ðétøgƒ(@L1°} …B¡PP Î\Í Þºç[Â!CLl½µ5RºTWW—žžáååååå‘––V[[;PÛÓÚÚzÇwÜqÇ­­­F_ ÑhÞ~ûí3f)•J//¯ðððû·;wîœüš'NÄÅÅùûû»¹¹…„„<óÌ3_|ñ…µMJ—›zåÊ•—^zé_ÿõ_ ÔÏ N?7q´¨ýÝÁñ¤3Ðóf«Ë×HšôJº5è¾ù書¸¸²²2ƒù#GŽüôÓO'NœØÿ›ô§?ýiÁ‚ÒDRR’Á_+++²³³ÍòüñSO=¥ÕjþÕò&¥Ë:o°H#Ý8* ±j 4ýŒÑD §tÿÌÌLF555ÅÇÇ—••EFF~úé§ G޹÷Þ{ËÊÊâã㛚šú«öìÙc0!kooŸ={vvvöˆ#öìÙSRRÒÖÖÖÔÔtùòå}ûöM›6MzÙæÍ›µZíìÙ³/_¾ÜÞÞ^]]ýÑGEGG[Û°tùâ»ï¾;---//º„¾íáô™#KúÓíÛ·þóŸ{zzÞqÇëׯ×jµú¯y÷Ýw£££}||”Jå˜1cV¯^}ëÖ-«ÞNNccãÚµkCCCÝÜܼ½½cccÿö·¿Yø^Òzêêê–.]èââÒå ;vlöìÙ>>>S§Nýì³Ï¬*âââøøx•Jåïœ,_|4SW¯^={¶J¥òööNNN¾}û¶Á"F?”N§kiiÉÈȈˆˆððððððˆˆˆxùå—ÛÚÚ,,gù¿µµµÉÉÉþþþ^^^ %%%–ìóûÔ’jcUÉ÷zÍlnnV*•ƒ ª¯¯—æDDD!"##¥ÿÞ¾}{РAîîîÍÍÍF7`÷îÝBˆ‰'ÊkÔ××O˜0AñÛßþÖ¢¶¼n›ÿ¼ùùùBˆ©S§N™2Eqùòeý¿îÛ·ORUUe¦`ÝÜÜ„7oÞì­6¤—µªš™ªÀ¦B…%Ǿ©ÿšYÖÔÛ¬ÁÂÃÙªcÊy{4Šè瘯ß̽öÚkÒ_µZmç [Bˆ &˜IŠæãËOúS£ «%ï%ÍyüñÇõ4µB3Û&sss»pá‚…¥QSS3bÄý?É[bêínܸ¬¿ÈìÙ³vHª¥¥åÁìü¹yä‘ÖÖV«b¢þš…#FŒ"B7ÊÍ‚êFÉ÷EÍ” ðĉ:îæÍ›Ò•ÁAƒÕÖÖêtºãÇ !zè!S%„øðÃ;ÿéƒ>BDGG[XÔ–×móEúÜsÏ !Þxã?þñBˆ””ý¿ÆÄÄ!Þyçó­AHHˆâ׿þuMMµmÈ]wÝåîî>uêÔÓ§O÷[L4U&¦*°ùÜfþØ7ÿ_£ËZ-?œÍTÆÑˆ‰À€ÅÄx ¨¨¨±±ñÙgŸBL™2E|"44ôÀµµµmmm.\Ú»5kÖt/&_&&&^¹r¥µµõ‹/¾„§žzªb¢©21S»|GSǾ%kèrÙÎ3-?œ»}LôaL4ÕÂzzzšº‡ØÍÍ­{1ñþç|||äõŒ;6//ÏÂ÷’þ󯯬¿rS+ìL£ÑìÚµ+22Rÿ½”J¥…¥áîî.=Ù ÿµ±±Ñ|‡dÉ"F?”4RÒÐР?³¾¾^áááaULìüªÜL­ÙòŽ¹Ë’ï‹šYWWçâârçwêtºÈÈÈàà`­VôÀètº;ï¼ÓÅÅåöíÛÝM¼~ýºÑÑDSEmyÝ6S¤<ð€| ]§Ó(Šý×µv4Q§äççïÝ»Wáž?¾… ž?^1tèÐþ‰‰¦ÊÄLîüŽûFÿkí²¦.¡Xr8[v‰‰ú)&ššãááÑ§Í þªÑh æÔ××ïß¿ÿù矗Æ|ðA ßËÔû]agÒŒ™b¾4ºõ’5¿wº;—³ùìby¹Y2Öb¾º,ù>ª™“'O–õ4h4÷óŸÿÜÍÍíÛo¿BLž<ÙÌ<üðÃBˆ>ú¨óŸ>üðC£÷&š*êîÕmý9ÿû¿ÿkjñ‹/J¯yôÑG-¹7±³«W¯J—D-|½ô•úƒ©}ͼÀTî¼ µÇ¾þ»Ñnt;&v¯Üˆ‰&&JTšd2J:ç–‡arrrLm€t—4 bÉ{uÙnê¯ÐÔøÐ‡~X[[«Õjëêê¬ê–ºqÑYZDÿ¹ÈcÇŽYÒÇÜsÏ=¦®RÉÏêvYÎæ¯„Z^n=‰]–|ÕÌ””!Drr²tÅY§Ó½ûî»BéYÔÔT3Ëþæ7¿BLš4É` ·¡¡áî»ï6ú¤³©¢î^ÝÖŸ³bÅ S1ñßþíߤ×ìÝ»Wº²ººÚª¶¦¦ÆüÞ7pöìY!Dppð€ÇDSXz\Iÿ1ak}ýÿv¹lç·3Xƒ%‡31‘˜Ø_L”îv5jÔÛo¿]VVÖÞÞÞÒÒRPP°wï^ý«]¤!œgŸ}¶©©éêÕ«ÒÅ2yqqqGmhh¨¯¯—níwww·ð½Œ~S+ìLÔ9pà@KKË·ß~+?)iaiH°HÏ£´µµ;wnôèÑ–<Âr×]w?¾­­íüùóãÆ³$&îØ±Cº¬ùÑGIM¾çýå—_¶¤œå5wÞ`éæ<ËË­ç1±Ë’¹ÿ~éú B¡®ÆVVV* é¶¼ÿþïÿ6³õõõRqÝwß}RA544;vì¾ûîBŒ7N?>š/êîÕmyN}}½··÷ AƒÊÊÊô_PVV6hÐ oooi˜ªµµõÞ{ïBÜyç{÷î---•¾7ñ›o¾yã7¦M›&-õ/ÿò/¿ûÝï¾ùæ›–––ÖÖÖ¯¾újúôéBˆ°°0SE1{öì“'O6444779rDz:gÑ¢EÍT`éúûñãÇåèfí±ßyèÚ̲ßÎ` –ÎÄDb"`1Q§ÓIÜYuÅPúÂ9ÙO~ò3_K!„HJJ²ð½,üžpy…ô_6kÖ,«º¥^ùBi‘ÎO?,hÉ7h˜/gyÍ3gÎ4ú--–—[Ïcb—%ßG5³ººZš#?( í!ºuËËË3Øã’;ï¼Óà; Íu÷ê¶°ÀÀÀ.÷NssóŽ;ÂÃÃìááqÏ=÷ìܹSîTº,gÝ?糟ŸŸJ¥Š/..¶¶Üz»,ù¾«™Òuÿµk× ñv¾ònÔ?ü°yóæððpOOOOOϰ°°Í›7wþÒPóEݽº-Ï‘’ŸÁ%KÉŸÿügi¼SžÓÖÖöÇ?þqúôéC‡uuuU©Taaa+V¬ß諯¾zþùçï¹ç77·áÇ?õÔS_|ñ…™BÈÊÊzâ‰'ÜÜÜF޹lÙ²òòr ÷WßÅD3øÚµkO>ù¤¿¿¿ü3zÖûúÿírÙÎo×y…]ÎÄDËñ›ÎÖ›o¾™œœ}òäɾ~/~j¶ßPÔ@¿á78Ž'žxâܹs­­­uuuúÓŸV­Z%„¾´`õY'd§ES( æÜ{ï½gÏž•¾+§Þšµßö2E ôF8ŽÃ‡?öØc>>>J¥r̘1kÖ¬9qâD?dDp̳2NÈУ‰ &€˜b"ˆ‰ &€˜b"ˆ‰ &€˜b"ˆ‰ &ÄD@L1ÄDôWŠÎ#==B`jÊb44p`7:ŠF0šš9°w@å% #M1ÄD@L1ÄD@L1ÄDAñ`›t:ÝC=¤êtº^xÁÏÏÏß߯ :Îàpæ 1@ïô@rÀ½ùæ›Z­Vξ}ûΜ9sùòå¼¼¼“'Oþá08¢9®ALÀÁýðÃéééo¾ù¦þÌ·ß~{Û¶mÁÁÁÆ Û¾}û[o½EA˜€sÙ°aÃ/ùËñãÇëÏÌÏÏŸ2eŠ4}ß}÷åççË P*•ãÇÏÈÈèèè a \)zWvvöÅ‹_ýuƒù ^^^Òô!Cêëë¥iéBsGGG~~~jjjuuõo~óŠŽÑDÀžp‡;`RSSÿð‡?¸¸¸Ì÷òòjhh¦ëëë‡ ¢ÿW—{î¹çý÷ßçb4ˆ‰¬Æî€]8{ölXX˜|R'ŸÚMš4éÂ… ÒôW_}5iÒ$£gƒ¾ÄDíŒN:©“Oíž~úéM›6UVVVTTlܸqÑ¢EÒüÄÄļ¼üðCiúàÁƒú¿Å\RR’0dÈÁƒϘ1£ººÚàÈR(Fw}ÙÙÙ›6m pww‰‰ÉÌÌÔ_Içß[²ª­ˆ‰€ÉÊÊ:sæLmmmBBÂâÅ‹¥™;vì¸páBNNNUU•»»ûºuë̬¡¦¦fÛ¶m÷ÜsO—ïuúôéÜÜÜ’’’ÊÊÊ-[¶˜zYzzz^^^NNNqqqYYû­\¹rçÎÒ@þÖ­[SRRä?Íž=;%%¥ºººººúî»ï^µj•…Ç»¾ûî»/--­¤¤Äè»ë_‘èF[tŸpiiiiiiõîÇšò¤éÆÆFWWWizÔ¨QyyyÒôõë×ÕjµÑUIT*Õüão¾ùÆÔ[ÈEEEÒtAAÁðáÃ;¿@š1bDAAÓî#ph›?~gÍšµÿþýû÷?þøã8ùp ì|ˆ=Þõ•——'''ûúú&%%]»vÍÔqjy[Á቞ã7 Mxzzj4iúÚµkR ÕjMÝ´nííJ¡¡¡ÒÄèÑ£«ªªL½¬²²rôèÑìÀ¨_þò—¿úÕ¯4ÍüÇèÏ?wîÜ /¼““#]ù5zØ=Þõ >üøƒâúõëóæÍ;s挙±°­zˆ‹Î€ .--Õh4Rëoù²®®®ÍÍÍÒôÍ›7õÿ$_É*.. 2óîÅÅÅìÀ¨éÓ§744hµÚØØXýùsçÎ]¹reyy¹V«­««ëáC'AAA;vìÈÎÎî»¶ &viùòåK–,¹zõªF£ÉÏÏ·ê)戈ˆ]»v555]»vmùòåúJMM•nœJII™?¾©5,\¸ðÙgŸ-//¯­­Õ¿õ €B¡P\ºtÉ`~ss³R©ôðð(--]ºti÷V>kÖ¬S§Nµ´´ÔÔÔ¼ôÒK‘‘‘/ðõõ-((è•¶ &viýúõQQQ±±±žžž ,˜3gŽå˾ñÆðññ™:uê#<¢ÿ§¨¨¨ðððÐÐР  ôôtSkHKK›8qbDDÄèÑ£åëÔÌ{óÍ7×®]ëååõ£ý(::º{+Y±bÅæÍ›}}}ÇŒó¿ÿû¿|ðÁ Ö¬Y3eÊùârOÚ Àг#¾“ NBŠGfBØG Ú€r†>F@L1ÄD@L1˜Äïò˜ŒàÛŽALœNssóÂ… U*UPPЮ]»ä…B±{÷î‘#Gººº !ZZZ–,Yâããããã³téÒ––ùeúkÓ_|çÎjµZ¥R%''·¶¶RÔ€%%% C† }ZÿOÙÙÙ999F±qãÆŠŠŠ¢¢¢ÂÂÂÒÒÒM›6u¹æÓ§Oçææ–””TVVnÙ²…¢̘={vJJŠôèwß}÷ªU«¤ùéééyyy999ÅÅÅeeeÒ̧Ÿ~:==½¾¾þôéÓçÏŸ7µN£/Û±cÇ… rrrªªªÜÝÝ×­[gpÈët:ooï'NH3?îççwÏ=÷È/3ºIfV t‡piiiiii6»yÇ¿zõª4]TT$›BˆŠŠ ùeÆ +,,”¦¯\¹2lØ0ùeúkÓ_¼¨¨Hš.((>|8ûÚjll ”¦GŒQPP`ð‚‘#GîÞ½û»ï¾3¿£/5jT^^ž4}ýúuµZÝùíµ×¥éŸýìg¿ûÝïôn£›djµžèF›pýúõiZžËÓUUU£G–¦ÇŒ#_3#44Tš=ztUUE ˜qîܹ¨¨(///…B¡R©jjj¤ù•••ò¡'ûë_ÿš••uß}÷9òÀ¦Öiôe×®]‹ˆˆpuuuqq Ò?–åC~þüù‡þá‡nÞ¼ùé§Ÿ&%%é¯Öè&™Y-Ð ÄDÀ&¨ÕêÒÒRiZž0ú²’’iº¸¸X­VKÓ®®®ÍÍÍÒôÍ›7õÑ}PPE ˜1wîÜ•+W–——kµÚºº:ùÖÀàààââbƒßÿý¼qãÆÞ½{W¬XajF_\ZZªÑh:::t:V«í¼ ŸŸßc=öî»ï¾ûî»3gÎôõõ58ì¼I–¬ &væg?ûÙóÏ?_SSsãÆ ùv¨ÎW­ZuãÆêêê”””ÄÄDi~DDÄ®]»ššš®]»¶|ùrýERSS¥­RRRæÏŸOQf477+•JÒÒÒ¥K—Êó.\øì³Ï–——×ÖÖ¦¤¤ÈÇãåË—ÛÚÚ´ZmGG‡™Ã¶óË–/_¾dÉ’«W¯j4šüü|ƒ‘BYrròý×ýáHNN6ø“ÑM²pµ1°'/¾ø¢ÏÈ‘#æM›æææfôeÛ¶mS«ÕcÇŽ7n܈#^|ñEiþo¼qàÀŸ©S§>òÈ#ú‹DEE…‡‡‡††¥§§SÔ€o¾ùæÚµk½¼¼~ô£EGGËóÓÒÒ&Nœ1zôhùFŽøøø9sæ¨Tªõë׿÷Þ{¦Öiôeë×¯ŠŠŠõôô\°`Áœ9sŒ.ûãÿ¸®®®¡¡!&&ÆàOF7ÉÂÕRð LpRB²‹œtåÊ•™3gv¾œÔ#\aOǸí#Pm(g8F[ñÜsÏýðÃׯ__»vmBB &BˆñãÇOœ8qܸqÞÞÞ¿þõ¯)Àî(:¡L`×\)ÀF¬\¹råÊ•½»Nî*úG £‰ &€˜b"ˆ‰ & ÿñ…8p.ü„À¡ ÀBŒ&‚^ì&Pg@QÃ~Ó°ïözëÖ­Å€=¿¤.Ø>F{M‡éééòéo{<b"€^î`Šÿ» Óé™ìñ@昅íã¢3`݉ü¯B¡~7V¡P¤¥¥Ñåv¹»À“΀M÷%q°sF”æ( ùõô:€ÝÝ€mâ¢3`£½ˆAb*#ê'EÊ °¯£°q\tl«ÿп%O›Ïˆòk8œ»Ë‹¤FØ2F[ì9ô',Ɉ⟹¤Øþ1Ø>îMl¢Ï0u?»…Q?)2¦ØEF$/Âö1šØhbmF4X׳Û?Æ9Haãx¬·0ß=t{\P^oÜì"5r„Âf1š pÑ»Q^œ°‹£ž#¶ŒÑD ¿{ˆ.{…žß_ÈŠ€ý¶€íàÀÆNÝz#á<ËBçØNL$;‚˜ÀHÐãˆF×FèîMú/&ögF4º*ò"0à­A癘°YÜÀ p:싌htµ<ø ØBFä„á¢30ÐçjÝýrÄnôRŒ[{~V ô.:}ÒXÈú:#êÿ‚Ÿ`<°Ã glîûmQ?)Ò!Õ2˜:ô8$a³¸è ôN.ìÆÍˆý“ é“û ‘Àb4èͰhkÑTR¤gl-r0Â1šô´Ñ·¶qï猨ÿ¾|³àç™@ÿut@Ošu{ɈÄDÀîš `ÀqÑèþI72¢N§¨¬Æ¥gÀ–CÇè^F¤ R `/è·€þhîm'#’Vb4°.ÚuF¦/= <€>·ä1p.ö5zG/pôÿ×…qù 0ßj÷¤í¶ÙŒh~ÃV¤Áḃ­a4˜(f ›g&óR€˜ØGcÝí“{…BaãÑüP"uèÅöÄòcŠE;Ȉ=¼Ð,è ´­MŠ (ÌõhÜ›œÇ÷ä„Þ^2¢¼µ¦6µ'Ov£‰€ar’Œ(,P$#1 &ö4Ù]F´0)¶-Ü›b"`÷-¸3Ü8 pòóO«b"…b"àPì=#šP¤ßzëD”¤»ìàx„èaFt€ƒÈ’¤Ëå0 ’%a¶ƒÑD8éù}¯´ÂŽ‘…C¡t]@·[ÊÄDÀéNÖ&#ÊI±ËKÏtxÉN…‹Î ý%#:ò‡t£‰pº¤Hœ2Åü€b¯Gme &¶ {¥ñuì!7 “"• í˜8HFäZs_dnj@¾„cãV$Ðæ’­þ¤„EpŒ&‘ÓaoE…Bálãˆæ/=óà3`ûg¶@/ôŒ&‚ŒhI`r¶#…Ëë@Ï› Òì+E‡<ïÅ›0#Š<ËÂ¥gpf €3x2b÷?>WÇÛoÊ€nãÞD8`ÛJFì–|vº1päñFá0‘ŒØ'm„7)2òpPÀ!1šZdãÁˆŒpö‘úB8LRäËûª™°¸L¸U°Í³_ {M„#´¤‚kîû¤hù¾8HãO§2"±· ‡ÑD@0áþb IDATb"àœ1ˆ"¢€~‹‰œwaÀñõÚàLÔ›Åwn½Rù9‚` ¸7NÚ“­eùS,ôp€ ¶u@wºH:HØW£IFà&ƒ8S‚Ó`4ÎØø*þa`%“éNŒb"Ðßçè3b÷r[—K9RÔétŽn²ðý×àlÍn¯ÿ_·G%íô.¿dN‚ÑDØAFÝDliiY²d‰ÏÒ¥K[ZZä‘°;wªÕj•J•œœÜÚÚª€„6l:t¨§§gRRRcc£4¿½½}õêÕ~~~¯¼òмˆt Û|®B´¶¶>óÌ3*•*((h×®]Vm¹¼ª={ö„„„(•ÊÉ“'çææšßà¾`U@ddœÖÄDÀcâÆ+**ŠŠŠ KKK=<<ä”súôéÜÜÜ’’’ÊÊÊ-[¶,¸cÇŽ .äääTUU¹»»¯[·NÞ˜¼¼¼œœœâââ²²2ymþôæÍ›oܸQZZzñâÅãÇ[¾å›6m’ÿ”••uæÌ™ÚÚÚ„„„Å‹›ßà¾KŠ\zHœp|:ÀV¥¥¥õp Æ +,,ÔÏpòtQQ‘4]PP0|øpy¾41jÔ¨¼¼|¸þûšYP˯\¹2lØ0yU555Òtcc£«««ù î;4 @?´=ožàÞD8æ8¢ÄÕÕµµµÕÅÅE¡P´··{xx´·· ! …F£qqqBh4ýùÒáææ&Ç;­V«P(´Z­´Â––W×ú^ú.o1”_ oô¾ò»˜ÙrS[h°fSܧ¬º·’q°;\t†#_pQ«Õ%%%Rš)..V«ÕòŸJJJ¤‰âââ   ƒƒƒƒKKK5MGG‡¼äùÅÅÅÝÞžàà`ý÷írËåWêo¹©5Ý྾aá¥g¾I´Z=ûlyyymmmJJŠ4Ó××Wº‚Ü¥¤¤¤ÔÔÔ7nHïk~ËW­Z%¿RË2µÁ6µOéí2"ì ×ÝáÀ·ã!/^ìííííí½xñâææfyþÎ;¥ç‚-Z¤?_šèèèØ±cǨQ£ÜÜÜ"##ÿò—¿HóÛÚÚRRRüýýýüü~ó›ßH3·mÛæååeæh’ÿÔÜܼhÑ"¡C‡¾üòËfinn6µåF×ljƒûUÍ7Z÷&ÏÚo%Ôét®®®]ß5WŸÀžšwb"lêÚJoˆn|sõW_}õ“ŸüäÚµkì‹~(m€vŒ3+Ø>îM©åÿ{ðÁ×®]Ûó·6Ћؕ_£HŸöÑŸ22"z¥Ø…Å?РØF1ðzñB3q X[ìdD°ƒ!úTØHFìan°j4 }Õ Óáô­Y}o"gV®l$&’éS¶uòOÏ {O dDÛjS¬ùr2"Ø2îM„݇2¢M±öüp°ÀfqÑvÜð‘¦Ð ‚ÊLF„ b4ýÝBõÖ¥Féâ&ÑYû5ŠMe?´™1‘–¨û ÚW3ĵv±èáT3•އ‹Îèï˜Ø+ךɈ6®{¿ËB p€€˜è¤:::>û쳋/jµÚèèè©S§ !4ÍáÇóóó…aaa3fÌpuu•šƒY³f9s¦¾¾~èС jµZ¿¥þÕjµÇÿúë¯ÛÚÚ&L˜0{öl¥Rùî»ï>üðÃ!!!BˆâââsçÎvÙÐÈçÁæÐ¡CùùùîîîÒFöîÙ6Ñ©’"; $9€˜ˆ®}ºô§âââääd/¿üòàÁƒK–,é|QãóÏ?¯¨¨X¶l™»»{ffægŸ}6sæÌØØØ,[¶L§Ó=ztîܹIII–G´'N455¥¦¦êtºôzÚ“f”ØáØ],ØîMì?/^œ9s¦‡‡G\\œ43///..N¥Ryyy͘1ãÒ¥KòëgÍšåíííææ6mÚ´ÊÊJ£ëüúë¯ãââ¼½½ÝÝÝccc/_¾,„V«ÕÙÙÙÙÙÙcÆŒ °j;/]º¤¿I½ØÌ‘»ü€¶Ýx–…îö›ä¨½p<Œ&öŸ††???ƒ™òLÿÆÆFùOžžžÒ„›››V«5ºÎÛ·oïÙ³Gêõ»ä &œ8q¢½½}Á‚ÝØN___iºówû<¸ç¿Åç´ãˆÝûì].Õ?EjÕ¥ç^r2ƒrb¢ƒóòòºuë–ÁØžJ¥ª­­õ÷÷BܺuËËË˪u2ä¿ø…···ÁüsçÎM:U£Ñ|ñÅñññÖn§þ&ÙoNr}ôÙm°HéA’l ûOddäáÇoß¾ÝÒÒ’™™)Í ?räHccccccfffXX˜ù• <¸¦¦Fþï”)S<øÃ?hµÚêêêýû÷ !Š‹‹›šš"##§L™RYYYUUÕyA3ÂÃÃ?ýôSy“z¥õìvÓ©P(/#¶´´,Y²ÄÇÇÇÇÇgéÒ¥---òŸvîÜ©V«U*Urrrkk«\ÒDGGdž †êéé™””$=···¯^½:00ÐÏÏï•W^‘‘JÏLÙJ­­­Ï<óŒJ¥ ÚµkW7¶\¡PìÙ³'$$D©TNž<977Wƒ …þ“~kEb¢}ˆŽŽ üýïÿÛßþV¾˜£R©^}õÕW_}ÕÛÛ;&&ÆüJ¦M›¶oß>¹½x衇FõÎ;ïlß¾ý¿ÿû¿'Nœ(„8uêTLLÌ Aƒ wìØ±Î šñè£zzzîÞ½ûõ×_ íùéu·9ê¬lܸ±¢¢¢¨¨¨°°°´´tÓ¦MòŸNŸ>››[RRRYY¹e˃wìØqáÂ…œœœªª*ww÷uëÖÉ圗——““S\\\VV&š…_?¾yóæ7n”––^¼xñøñãÝÛò¬¬¬3gÎÔÖÖ&$$,^¼Ø`ƒ…|ð¼ÁdDäHа <7Š>lÔzÒë;ðñ >üäÉ“ãÆBÄÄÄ\»vMúÈEEEcÇŽBÆÄÄ”—— ½kî!!!Ÿ|òɤI“„UUUׯ_BÜyçYYYwÝu—AZxoâˆ#Nž<)¿ïøñãM-hfËkjj¤*ššš|||ÚÛÛ 6X¡P¨Õjiƒt¯E%)‚˜N¯üÇš]]][[[]\\„ÆÃÃC U …B£Ñ/…›››œŸŸ/„ ›1c†«««ô޳fÍ:sæL}}ýСCÔjµþÆHÿjµÚãÇýõ×mmm&L˜={¶R©|÷Ýw~øá!Dqqñ¹sç »ü,rÑh4‡ÊÏÏwww—6œŸÄDØq;Å£ °\7¾F±Wœ}ºô§âââääd/¿üòàÁƒK–,IÿyŸþyEEŲeËÜÝÝ333?ûì³™3gÆÆÆ8p`Ù²e:îèÑ£sçÎMJJ²| êĉMMM©©©:îÀT»;gìÑWȈ軤؋—ù.^¼8sæL¸¸8if^^^\\œJ¥òòòš1cÆ¥K—ä×Ïš5ËÛÛÛÍÍmÚ´i•••F×ùõ×_ÇÅÅy{{»»»ÇÆÆ^¾|Y¬V«³³³³³³ÇŒ`Õv^ºtI“¨-ΙG‰¤ègŒ&¢OΛɈ° ~~~3å™þþþòŸ<==¥ 777­Vkt·oßÞ³g|õ³ï„ Nœ8ÑÞÞ¾`Á‚nl§¯¯¯4Ýyƒ1°Mb¿¥7®;ƒ˜»o Ɉè6)TõçŠ^^^·nÝ2ÛS©TµµµþþþBˆ[·nyyyYµÎ!C†üâ¿ðöö6˜îܹ©S§j4š/¾ø">>ÞÚíÔß$ª €~ÀEgô22"z%)ZuöÒ‘‘‘‡¾}ûvKKKff¦43<<üÈ‘#™™™aaaæW2xðàššù¿S¦L9xðà?ü Õj«««÷ïß/„(..njjŠŒŒœ2eJeeeUUUçÍÿôÓOåM¢žØÎùsŽíqÝýŒÑDXÑ<‘awu²KÑÑÑÇŽûýï/MK3cbb>üꫯ !&Mšc~%Ó¦MÛ·o_[[›´I=ôâwÞ©¯¯ ŒŠŠBœ:u*&&fРABˆ¸¸¸cÇŽ-X°À`A3}ôÑC‡íÞ½[©TN›6íêÕ«T}N½vþJFDo¶Mñå8@÷ÎU¸7ŽŠ‹Î°¢m2Ó£“ÑI‘B€l‡éÚaIF4ùmô]LtªzÕù(cÐ1öÝ‘“a I‘[û ×qÑÝïzɈ°Š*{ƒí5’öþvO:£‹®—Œˆdá×(Òq@_à¢3ºUoȈèßúFe€þÇEgǵfØc¥eXTr€˜ˆþȈF#i\‡Œˆþdáï²Ð}‚Üô..åÀжk°¦Š1lØÛI5@L„sõÓÔØ~ ¤Û€ÞÂEgéeG„ ²ðÒ3à„M4ÐGøB6@¢ÓH ¶£ËÚHŠm0b"¼Õ##Â61 Jѯgæ$è·>Œ#š-‹¿p›z‚{a¼[U(dD8@•þ|ž£ÄDôkLäËG`Ë,¹ôLo[ß…¶.ätܛÛŒ»`á³,tWpȆšD?µ´¤èw¨dD8LL$)›ëÍ›7öÙg/^ÔjµÑÑÑS§NBh4šÃ‡ççç !ÂÂÂf̘áêê*-2kÖ¬3gÎÔ××:4!!A­VëÒ´V«=~üø×_ÝÖÖ6a„ٳg+•Êwß}÷ᇠBŸ;w®°°°Ë8(³j4šC‡åçç»»»O:õرcö…ÑDa—¤KÏ|9œÓÉ“'«««—-[¦T*O:%ÍÌÊʪ¯¯î¹çt:ÝÇ|üøñéÓ§K*..NNNöððøòË/<¸dÉ’ô×ùùçŸWTT,[¶ÌÝÝ=33ó³Ï>›9sfllì–-[¦ÓéŽ=:wîܤ¤$˯¶Ÿ8q¢©©)55U§Ó8p€gw¸7ÿÿ´Œ{Äo=;Éy¬mnÆ€l›Ôb_¼xqæÌ™>>>qqqÒŸòòòâââT*•——׌3.]º$/5kÖ,ooo77·iÓ¦UVV]ó×_çíííîî{ùòe!Dpp°Z­ÎÎÎÎÎÎ3fL@@€U[{éÒ%ýM¢>a—M0öÈòßîú(•Tkhhðóó3˜ÙØØ(Ïô÷÷oll”ÿäéé)M¸¹¹iµZ£ë¼}ûöž={~ýë_oݺõßÿýßåÅ'L˜ðÕW_ýýï¿÷Þ{»±¾¾¾Òtç †íã¢3 ¢HOO' Â~“¢ùKÏÄDô]ì'¥wôöö¾uë–ÁØžJ¥ª­­õ÷÷BܺuËËË˪52ä¿ø…···ÁüsçÎM:U£Ñ|ñÅñññV­ÓËËK“¨`ÄDØYƒÈσè»&66öìÙ³mmmaaa?þ¸ôDÅ­[·Ž9R\\¬ÕjCBBžxâ •J%„èèèèüX†ìÚµk}ôу>øÀ˜ZC{{û¡C‡._¾lðÀ„ч3Ì'?ƒg/lí<$22òðáÃñññJ¥òĉÒõÜððð#GŽüä'?Bdff†……™_ÉàÁƒkjjî¸ãé¿S¦L9xðàÌ™3}}}kjj>ÿüó'Ÿ|²¸¸¸©©)22R±oß¾ªª*µZm° áááŸ~ú©.3339(ˆ‰Nté¶nÝš––æ Ÿš(ìÀ,–…jÐÿ¾ûî»+V(Š?þøÄ‰?þñ…|ðÁŒ3ž|òI­V{òäÉ#GŽÌ™3G˜x,CòÍ7ß:t(>>þ®»î2³†'N´´´¤¦¦ !þçþG^ÜèÃæ·ÜfŸ½ªqGGDZcÇ~ÿûß !¢££¥?ÅÄÄ>|øÕW_BLš4)&&Æüª¦M›¶oß¾¶¶6i=ôâwÞ©¯¯ ŒŠŠBœ:u*&&fРABˆ¸¸¸cÇŽ-X°À`A3}ôÑC‡íÞ½[©TN›6íêÕ«ö…/Ä!I°‹aÿ YW7×êˆ{î¹ç¤ Ž7oÞ|ûí·W­ZeðšöööÝ»w¯]»VñÊ+¯,\¸ÐàBjzzúüã¿ÿý‰ÁÁÁßÅ` ‹-’Þñ‡~xõÕW¥¾{÷¤¡C‡ !öìÙ³fÍSÛ,-¢¿ª›7o¾öÚkëõ ÑDÃôÀïÀ»˜6ÝQuù»,ìô¢ÿøBCCƒ4]^^~ìØ±ÊÊʶ¶6¡÷¸ºÑÇ2„.\ˆŒŒÔψfÖ ¿£vìXww÷¶¶¶ŒŒ i¾——WçÇ2„Ï<óÌ[o½åîîþàƒš_ƒþ3µµµòL=œa†%Ï^PŒÅBL$#Â^w7ÊŽÍLRä$a@è?¾pÏ=÷H35‹‹‹««kmmmVV–üb£e!¼½½Ÿyæ™·ß~[«Õ>üðÃfÖväÈ‘øøxNwäÈy¾Ñ‡3Ìo¹Í>{ak˜Š˜èø'@ÔrgÛï$‡dþb"ûz@Œ5êõ×_okk›4iÒ#<"ÍŒ?räÈ_þòŸiÓ¦åååIó£££;?–!2dÈ¢E‹¤¤mj 111ûÛß~ó›ß(•Ê©S§ÊL}8Ã&fff>òÈ# xì±ÇØ@·9×EgbL%.@; Kže øÏÿüÏöööñãÇ?úè£öô €ñoçiLDçNÔ´‘Ñ¿§šŽý¦pZƒÈˆ€þP"5ÄÙN &O¹á„›ªŠ3¶n|9¥NéøA…qÚ˜(Ìþ‚À©c"]¾©¾SF'JµqìÚN G_·Ü›æêØG/Ç’Qtœ¶Â4ÇPÕM%Ev.t}²í‰Œhn—3¾BE¢ÂÀ9c"]{—½¦¿¿}}}hhè¢E‹^xኅêÄ©À€£}!z—t:ÝÍ›7›››ÿò—¿;vlÍš5” 5Êá뼩ßzf·¢‡íCÿW!~ ÄÄ^ëÚaŠ‹‹Ë=÷Üóþûï¿õÖ[”Õ‰ý MÎêZ 7Y«ªªê®»îª««£(,LÔ.;nì¸ô VrœÑDúo %&&æååi4šo¿ý699yîܹ” µËy’"…hŽh‘@Lìf/ÎÁÓ¥'žx"11ÑÃÃ#::z„ ¯½öeby£‚Ù/3¿ÈÂn‰ 0ÊÕÁŽXöh—æÍ›7oÞ<ÊŽÁ9“"—žAOXÎZL†y@eƒ¥M1,f÷é°A­ƒåL}9ûvÔþP]AL¤Û5 $EØ€äJ1öRg¨¨èOƒ(Φó€"]/mN_|‘[ÿ9_G8ú¸€kñc} &âÿz”7ÞxCNff¦}Å#«¶VñC† ‰½|ùr/¾u¯”›âŸQEažw€.qo¢Þxãäädé¿/¿ü²c÷‹Òëëêê^{íµùóçýõ×¶ÖCÓÓ£‡õGÿûq¡µ¸7ÑD+DEE}øá‡ÒôÁƒ'Mš$ÿ©££cÆ C‡õôôLJJjll”æ+ŠŒŒ ÿ   ddd=zT^vçÎjµZ¥R%''·¶¶v¹ÂÝ»w9ÒÕÕU‘™™¦T*CBBöíÛ'¯sÏž=!!!J¥ròäɹ¹¹ò²ò„Ñ75ÊÇÇgíÚµÒh¢©­’•””$$$ 2dðàÁ3f̨®®–ßWÌOžhiiY²d‰ÏÒ¥K[ZZäý@¯c(ˆ‰½`åÊ•;wîÔét:nëÖ­)))òŸvìØqáÂ…œœœªª*ww÷uëÖɪªªúþûï·oß¾`Á‚ªªª²²²íÛ·¯^½Z~ÁéÓ§sssKJJ*++·lÙÒå ³³³srr4âé§ŸNOO¯¯¯?}úôùóçå×dee9s¦¶¶6!!añâÅ?‹Ñ75ª®®îå—_ŽŒŒ4¿U’Ù³g§¤¤TWWWWWß}÷Ý«V­ÿó“ÊÍàõ7n¬¨¨(***,,,--Ý´i“åA T*ÇŸ‘‘ÑÑÑA…µ êdú?P2°÷&Â)ZI»––––––Öo$•Õ¬Y³öïß¿ÿþÇ\?ýŒ5*//Oš¾~ýºZ­–—ºyó¦N§“ÆÉäiùEEEÒtAAÁðáû\aEE…¼U#GŽÜ½{÷wß}g°©555Òtcc£«««þG0ó¦+‘ 6¬¤¤ÄüVu^Cccc`` ÑÈÿ6lXaa¡4}åÊ•aÆ™ÿi4š‹/>ú裩©©ýVåtp,úõ“ý ì€üMá´ìþw«úíÇÓ¤{˜Ž9ò«_ýJ£ÑüÇüGll¬|c“›››ÜÙhµZ…B¡ÕjÅ?ÿ2˜Ñi…B¡Ñh¤û5‡‡G{{»…+Bœ?þÅ_<{ö¬‡‡Ç«¯¾šÐù5úïeþM;^N÷í·ß&''¯]»vöìÙ]nÕ¹sç^xá…œœéz´©Í–ÿëêêÚÚÚÚyKL½Þ”ëׯOœ8ñÖ­[ŽTåÐoø?0Š‹ÎÖ™>}zCCƒV«ÕŸ\ZZªÑh:::¤eù:KJJ¤‰âââ   «Vxÿý÷ø-\a||üœ9s¾ýöÛ &¼÷Þ{=|S3–.]ºqãÆììló[õæ›o>ÿüóóæÍ»óÎ;×®]ûÑGIó׬Y3eÊ”††ƒñÅmÛ¶=ûì³cÇŽBÌ›7ïÅ_´ü#<ñĉ‰‰W®\Q«Õ?ýéO·mÛF=D·é(ÒÃòÄF!ÀÁÏŸ¹7Ñ÷:wbQ퀈 IDATåÀ¡]á¢3üSR\׃Å'ÔÀ)ð‹, ›ú¸7Ñ©ûBéÒ3=1,IlÛ ŽU€šv7ì¨ZR3AL¤µƒ§žAb$& ž<í›ï{ëÿï³ýo­£?p¶¤HÙÄD‡:xØ£„9ªÐ;¾Ã<Í «NxÐöÅ—½õÿÈÙøWÖ1híœ'EiiiìwNËqFm¿W(þþþAAAÈÈÈ :zô¨ô‚ŽŽŽ 6 :ÔÓÓ3))©±±ÑÂ…;wîT«Õ*•*99¹µµµËîÞ½{äÈ‘®®®BˆÌḬ̀°0¥R²oß>y{öì Q*•“'OÎÍÍ•—•'Œ¾©Ñ®ÿv¦¶ŠÚÀîúí,)ÚòA[UUõý÷ßoß¾}Á‚UUUeeeÛ·o_½zµô×;v\¸p!''§ªªÊÝÝ}ݺu.(„8}útnnnIIIeeå–-[º\avvvNNŽF£B<ýôÓéééõõõ§OŸ>þ¼ü𬬬3gÎÔÖÖ&$$,^¼¸óÇ1ú¦Fé¿™­",¦ètº­[·²ßaSÍÙýÉÑ~™Ê–/=+Š›7oúûû·¶¶›>DÄDtÛ âõùìçÑD*ˆ‰èc@e b"öœÛú'ºqc"ˆ‰° ®ô¾ˆÊñôÛC‰èŒ&èeŸ~úé½÷Þëîî>~üøwÞyÇF™Á„Ñÿv{å’!C†ÄÆÆ^¾|¹W6µ·°°°púôé*•J¥RMŸ>½°°°?c á &€Bœ;w.99ù¥—^ª¯¯?|øð‰'la«L àõÖÀžN§Óétååå<òÈüùóûaË­òÓŸþtÚ´i×®]+//à~ö³ŸQQ{7 ÷Û½‰”6ˆ‰ìXFFFFFÆc=¦T*ÇŒóæ›oJó[ZZ–,Yâããããã³téÒ––i¾B¡ÈÈÈð÷÷ :pà@FFF@@@PPÐÑ£GåìܹS­V«TªäääÖÖVó+ÌÌÌ S*•!!!ûöí“W¢ÿoçÁE3›·gÏž¥R9yòäÜÜ\3ŸÝÇÇgíÚµÒhbGGdž †êéé™””ÔØØhðâ’’’„„„!C† ýôÓéééõõõ§OŸ>þ¼þ6H#sÒÈŸå›—••uæÌ™ÚÚÚ„„„Å‹›ùìuuu/¿ürdd¤bÇŽ.\ÈÉÉ©ªªrww_·nÁ‹gÏž’’R]]]]]}÷Ýw¯Zµªï¶pæÌ™/¿ür]]]mmíÎ;î #tpVì}§’–––––Öoäââ¢Ñh:Ï6lXaa¡4}åÊ•aÆÉõðæÍ›:N“§]\\äIÓÇ7¿Â‘#GîÞ½û»ï¾3ZÛ ª½ü_3›WSS#M766ººº=”dÆ +))Ñét£FÊËË“^pýúuµZmæ¸kll ì»-,//9r¤´…¡¡¡ýYñ8¸ûÅh"€ÞäëëûÃ?tž_UU5zôhiz̘1Ò5V‰¿¿¿ÂÝÝ]º££C~Ahh¨41zô說*ó+üë_ÿš••uß}÷9òÀn¶™Í &<==5©óm­V[TT4f̘K—. !®]»áêêêâ⤿Bɹs碢¢¼¼¼ …J¥ª©©é»-LNN^¸pá­[·nݺ5þüE‹9ä`€^GLЛ|ðÁÇwž¯V«KJJ¤éââbµZmù:õ 2¿Âûï¿ÿàÁƒ7nÜØ»wïŠ+,|‹žlžD¡PŒ;ö½÷Þ[¶lYCCCpppii©F£éèèB¤ÁëçλråÊòòr­V[WW×å£*=ÙÂS§NmܸÑ×××××wãÆ§N¢¢önæëµAL€®­[·nÆ GmkkûöÛoŸyæi~bbâªU«nܸQ]]’’’˜˜hù:SSS¥{øRRRäçˆM­011ñòåËmmmZ­VHRâëë[PPÐù-z²yúFŽ9uêÔ÷ßùòåK–,¹zõªF£ÉÏÏOJJ2xess³R©ôðð(--]ºtiŸná¤I“222jkkkkk_z饰°0**‹pÝ{Á½‰½ë“O>‰ˆˆP*•cÇŽ}ë­·¤™ÍÍÍ‹/öööööö^¼xqsssçzhtZ±sçNé‘áE‹É šZá|0~üxWW×°°°#GެmÛ¶m^^^¢Ó­Š–lž©£Æ`æ§Ÿ~zß}÷uttìØ±cÔ¨Qnnn‘‘‘ùË_ ^|ðàÁ1cƸºº†††¾þúë}º…ß|óMLLŒ‡‡‡‡‡GLLÌ•+W¸o X‚ßp^ü„S±ß/:¦¢Rëø¤‚+Î \tÀ21ÄDØWŠ€-ãŠ3l_ÿ\t¦œÑÿMœ®3¨l|^€˜€> TïÉèiìB¡ 6ÙàçåÈ1€ãäEt/œ¤4»mÔ4’(ÐͦÛùÛcï;sÏM—c§Ží¹Œ[ƒÑDÀIc¢-koo_½zu`` ŸŸß+¯¼"ÍliiY²d‰ÏÒ¥K[ZZ䨔‘‘áïïtàÀŒŒŒ€€€   £GÊ/عs§Z­V©TÉÉÉ­­­æW˜™™¦T*CBBöíÛ'¯Dÿß΃‹f6oÏž=!!!J¥ròäɹ¹¹fòßîÝ»GŽéêê*„èèèØ°aƒôó3IIIT0g>l)Xô_Gn˽Nzzz^^^NNNqqqYY™4sãÆEEE………¥¥¥›6m’__UUõý÷ßoß¾}Á‚UUUeeeÛ·o_½zµü‚Ó§Oçææ–””TVVnÙ²Åü Ÿ~úéôôôúúúÓ§OŸ?^à ~EPŸ™ÍËÊÊ:sæLmmmBBÂâÅ‹Í|ðìì윜F#„رcÇ… rrrªªªÜÝÝ×­[ÇÙIèg\vtâ}ÏEg§OŠ6ÛßyçYYYwÝu—þÌáÇŸ™4i’”ƒ#""®_¿nãG®3ßÒÀ¥vALI±?¸ºº¶´´H×^õg¶¶¶º¸¸!4‡‡‡”·ôk²Ñi…B¡Ñh:/hj…çÏŸñÅÏž=ëááñꫯ&$$X-Ù<óÇÁŸÜÜÜäÁK­V«P(´Z­-¹Üö 8.:ÄD›ëÔƒƒƒ‹‹‹ fªÕê’’iº¸¸X­V[¾Býƒ‚‚̯ðþûï?xðà7öîÝ»bŠߢ'›gªJKK5MGG‡”©NÎ|´R° & kBˆ… >ûì³åååµµµ)))ÒÌÄÄÄU«Vݸq£ºº:%%%11Ñò¦¦¦VWWK Ο?ßü /_¾ÜÖÖ¦Õj;:: Våëë[PPÐù-z²yF-_¾|É’%W¯^Õh4ùùùIIIT$’@Làì|ZZÚĉ#""F*Íܶm›Z­;vì¸qãFŒñâ‹/Z¾Â¨¨¨ðððÐÐР  ù“šZa||üœ9sT*Õúõëß{ï=ƒU­Y³fÊ”)¿.±'›gÔúõ룢¢bcc===,X0gΪ½MdP8 îNsâ}Ͻ‰pŽžžªNÍ@L}'èï©êÔG+ ʈ‹ÎèŠ ¹ Â8Ìd§ëŒ7Vœd;sGÅÞ}?¨'ˆ‰ &º@Õ &ˆ‰€É4@Ѫ"ê£{)s îMÐEL¤pNŒ'9ñ¾g4VæEJƒ€HÄD‚ûý ÄDÀšÐ@b #Â|¹õb‰qc"ˆ‰ &Âþ¢Øã°ÇÜ ALÑ¡7mݺU‘––Æ^@L„³ÇDIYØÚ!#MP-a>^²á0øBt§›ìÝ¥º±Z{üq3Ø;Ý?Øï/ìÁs'¡È•"€Uݤ­èÓANŠT`è§: Ž„ÑD§ÖÒÒ²dÉŸ¥K—¶´´ÈÚ¹s§Z­V©TÉÉÉ­­­ÒLyø¤££cÆ C‡õôôLJJjll”æ···¯^½:00ÐÏÏï•W^‘1?ô"ÿ©µµõ™gžQ©TAAA»ví2ÿzyãÆ»r劢¬¬lРABˆ+W®Œ7Îügz\D?äN¢'ˆ‰7n¬¨¨(***,,,--Ý´i“ü§Ó§Oçææ–””TVVnÙ²Å`Á;v\¸p!''§ªªÊÝÝ}ݺur‹–———““S\\\VV&þ1Ð"õ¦]nÏæÍ›oܸQZZzñâÅãÇ›éžõ×9cÆŒ“'O !:äîî~èÐ!!ĉ'fΜiþ3äEì‹88!İaà ¥ÿ^¹råÿ±wçaQ\‰þÿ«C³6¸u³ˆ¸4`p4&ט„o0q hÄxÁå…€ëuã‚èÄ0f™Dcïd™I&™<Ž 1>.A3h¸ƒ†m‘MŤ—ßõúõ4ÝMƒÐôò~ýáS]U§N®óéSUÝÒŸÊÊÊÄé’’’   i¾81|øð¢¢"qº¶¶V©TŠÓÁÁÁ%%%7ÔeIĉ   ýíšYPÿO_}õÕÌ™3u:Ý´iÓV¬Xñä“Oêtº3fäååét:Sûô雋¬ÓÊÌÌÌÌÌ´µU=Ó¤ÎK&“¹¸¸´··»¸¸‚ V«===;::Ä?©Õj£óÅãêê*e5­V+“É´Z­ r¹¼­­M.—lÈ|3“^ —ËõË#mÅÌ"‚ ´¶¶FDDWTTŒ5êâÅ‹¿üò‹‡‡‡Á:¥}¬ó.Óº;0)p¿#úšR©¬¬¬§+**”J¥ô'ýù*•Ê`Á€€€ªª*µZ­ÑhĤ(ͯ¨¨èqyô·káRžžžáááo½õÖĉýüü&NœøÆoŒ;ÖÃÃÃü>Ö¹\#tu{.2ÞõÊzȈ &¢ß$$$¤§§744Ô××§¦¦&$$HJKK«¯¯çÏš5Ë`Á… ¦¤¤”——«Õê³gÏ&&&Šó“’’–,YR]]ÝÔÔ”šš*Îôóó¯ w)111--M*™W¬3...;;û±ÇaêÔ©ÙÙÙqqq]î#`ͰÈÍ‹dDÀŽÏ_pÂÛ§Z[[“““ 0`À€äääÖÖVéO999âƒÌsçÎÕŸ/Nh4š-[¶ >ÜÕÕuüøñŸ~ú©8ÿÖ­[©©©ô÷÷ýõ×Å™›6mòöö,¸Ñ°µµuîܹžžžC‡ݶm›™E ÖYZZ*Â?þ¨Óéþþ÷¿ z÷VšÚG€›á<·9Ü›ˆîéîoœèt:¹\®Ñh¨: ߆Òû‹Ú€ÑI†'ÑŸç(ÎMÄD ýøãO?ýô¥K—¨:€¼âœ¿ÂKM™2eëÖ­½ÕJºì{°`wtü² üËÉÈy½Œ£ØîÛ“ENŽ!IØFÀæHé¼ ??²rêqÞcÏh"`WoXò¢½` ƒÑD°Œ/臨œhœ÷Ø3šØóû—°èÀ„`4샋ä<€˜ /:iÊú—øØsÑpз6y@¯`4 ã‹€kÖ°wPà¨yÑàÇ]`ÍœGȃಣ{.:Nö–—â#µa¤(0"b"ˆ‰È‹÷&€sé—›mäs©]|Ú– ö,&.a;Mü¿huûƒ‹mmm)))¾¾¾¾¾¾óçÏokk“þ”““£T* żyóÚÛÛÅ™ÒV4ÍêÕ«‡êå啘˜ØÒÒ"ÎïèèÈÈÈ2dˆ¿¿ÿŽ;¤EÌ—PúS{{ûK/½¤P(T*ÕöíÛÍ¿^ZgXXXqq± .\¸ãŽ;jjjA(.. 3¿¤=äEãÖ¬YSSSSVVVZZZUUµvíZéOùùùgΜ©¬¬¼|ùòúõë ܲeËéÓ§ ëêêÜÝÝW®\)…­¢¢¢ÂÂÂŠŠŠ .ÿ)”¾îǼuëÖ544TUUýôÓOGŽ1³Ëú댋‹;vì˜ pww?pà€ G6mšù}윻¹T =ÀÙpôX~º°°Ë ,--§‹‹‹¥5”••‰Ó%%%AAA'¢áljӵµµJ¥Rœ.))éîéKzAPPþvÍ,¨ÿ§¯¾újæÌ™:nÚ´i+V¬xòÉ'u:ÝŒ3òòòÌìcg™™™™™™Ýªê,ô¾Åyñ…8zpÞÐ~ëL.—···»¸¸‚ V«===;::ÄÕjµÑùâª\]]¥¬¦Õje2™V«WØÖÖ&—Ë»uú’^`Pi+æO‰­­­EEEÁÁÁ£FºxñbDDÄ/¿üâááajÇÃEg@·/@™º­T*+++Å銊 ¥R)ýI¾J¥2X0  ªªJ­Vk41)Jó+**z\à€€ýíZ¸”§§gxxø[o½5qâD??¿‰'¾ñÆcÇŽõðð0¿1@^4~óbBBBzzzCCC}}}jjjBB‚ô§´´´úúzqþ¬Y³ V¸pá”””òòrµZ}öìÙÄÄDq~RRÒ’%Kª««›ššRSSÅ™~~~âä.%&&¦¥¥Iå1óJƒuÆÅÅegg?öØc‚ L:5;;;..®Ë}4À½‰ &œ:,êçÅM›6)•ÊÑ£G‡……oܸQzqttô¸qãFŒ¡R©:'¡U«VEGGÇÆÆzyyÍž={úôéâüÌÌ̱cÇFEE9rĈâÌeË–ÝsÏ=–<[³aÆ!C† >|ܸq111f^i°Î¸¸¸k×®ÅÆÆ ‚ðØc]¿~]Љfö±sæëA­a;¸;͉=÷&胋” -I™r¹\£ÑPo€mb4Ðkºõe:………oRt<ŒÂ~ñ+,€>ɋℙ_v™2eÊÖ­[osC“h—™=XÄ:‘_s1àtyÑèÅhS¿_Ò³<Ú§‹X'&¶†»ÓœøØso"€þ8óX?«èîMXO¯ür´}±ð;nw1'Í‹$EØîMôs^'õz4áö‹»ÓœøØso"›<59dXì6Ä!/Fwy{"#Ž &à¤y±Ë HR„ â²£{.:°·³–” oï,|  &‚˜Ž“ùyØ).:ìŒx1ZÌ‹|“ЇÉOræã}Žq6“â£=–Ÿ±FØ,FöÍÞv! Âv?ƒ1žäÌŸ¿9úõü&%H›Ê‚$BØFŽÆ¾ÆÉްÝO\Œ'9ó§mŽ>'9ÝIñÑf3"a6ˆÑD€ƒ³ÁÅÎY‹Ñ°erªàö\tÀ™°¿¯Góã+°e\t8/[¸ML„í~Žb<É™?CsôÀàÄ(ÅǾK„äBØ îM@0H‡öþË.@ï|pâ àÌš9úÐ婲ïò"7&ÂÆqo"&õõÍ‹ÄDØôÇ$Æ“œù#2Gzpò”ds!éÄD€°Ø+a Ûnÿa†AL€¼H:„]âz'/Zþ° Ï8Ã.pwš{îM€>>ÍJ ’Ú€=b4€>!.ŠyÑ`p‘ÑDØÇG§úˆÃ{R߆ 2339ÊxçZí¬+N8ä¹—ãKL¤‚à €7,ŸÒ9ÊÎBN3‡o^ö”ýEgÜ›ÎJ€˜" &ÂÉ“"yb"ˆ‰€P€˜t1 @LÈ‹"ÄD 7“"yb"º ÓéV¬Xáïï?pàÀÕ«W;Ïz€øæ›o¦Nêéé9hРٳg×××S' &Â&ìÚµëĉçÎ+**:vìØž={~—P`S^{íµW^y¥±±ñ—_~ñõõMHH N@L„MØ·oߦM›7oÞüûßÿÞyö¤ÀåÄDGû ûÎ;†º¹¹M˜0áÌ™3ÒüÜÜܹ\.‚F£Y½zõСC½¼¼[ZZÄ—µ¶¶&%%) •Jµ}ûöÎÃoyyy‘‘‘nnn¡¡¡»ví’þ¤ÿëò¦VnaÚÛÛ_zé%© ;èáá±hÑ¢ÜÜ\ý™¿ýííÀw IDATo.\èááa¦œúE5(p[[[JJН¯¯¯¯ïüùóÛÚÚŒ¸ò"‡äëë»|ùrq4Ñ~O¹]2z²µ°HF—ˆ‰}ëðáÃ'NœhjjŠONN–æªÕjA¶lÙrúô麺:ww÷•+WНY·nݵkתªªÎœ9“ŸŸßyåsæÌÉÊʺqãF~~þ©S§¤O½ú¿.ojå–—¡¡¡¡ªªê§Ÿ~:räHç2ü÷ÿ÷ÇÜÔÔ$þ÷úõëüñÿ÷›/§ÁÇtý¯Y³¦¦¦¦¬¬¬´´´ªªjíÚµF L@`¹ëׯoÛ¶müøñö~Ê5ÏèÉÖÂ"™9QééœFffffff¯¯¶sêŸ5Åé––¹\.ͯ©©‘^?|øð¢¢"qº¶¶V©TŠÓAAAåååâtYY™þjʼnÜÜÜóçÏ›)©•[^†²²2qº¤¤ÄhƒY¼xqvv¶8½}ûöE‹u«œë ,--§‹‹‹¸×Û†€#žŸ%•••pÊ5Óé-¡…E2º¬_X1ñvÉd2F#ýW­VßqÇFß̦‚‘\.wqqqqq¹ãŽ;Ä â|µZ-Nwttt^¼  à©§žøàþýûà”k¦Ó1ZB ‹dtYαà¢óí ,//—þ[^^Ø­5TUU©Õjñ¯ÕjÅùJ¥Rz:Äà1ѤI“öïßßÐÐðî»ï.Z´¨[+·ðe•••âtEE…ÑeGŽyß}÷}ôÑGŸ~úé¯~õ«Ñ£G÷ œ¥R©¿E¥RÙ×G‹Î€c“Éd£Gþàƒ,XÐÜÜlï§\3ŽÑZX¤n¨á<ˆ‰·kÖ¬Yiii¦¢¢"55õÅ_ìÖ.\˜’’R^^®V«Ïž=›˜˜(Îá…^yå•ÆÆÆ†††ôôôÎ &$$œ;wîÖ­[Z­V£Ñˆ3ýüüÄKæWnaÓÒÒêëëSSSMí²eË^{íµ;v,[¶ÌÂrJ œžž.m1!!Á:Ç‘°8¶É“'ôÑGö~Ê5Óé-¡…E2¢†óâ¢Æmjoo_±bEPP‹‹KPPЪU«nݺխ‹ÎfË–-Çwuu?~ü§Ÿ~*Îoii™={¶§§çСC³³³]]] ÿøãÃÃÃåryddäÁƒÅ™›6mòöö–^cjå–¡µµuîܹb¶mÛf¦Á<øàƒ“'O6º¿FË)ýÕ À­­­ÉÉÉ 0`@rrrkkkŸ^tæRàð%_ýõĉíý”k¦Ó1ZB ‹dtY뫎Ͼ¡ìúòŠ‹‹§M›fꜳU¼9år|ѧ¸èlÓ–.]zõêÕÚÚÚåË—ÇÇÇS!œ¹pʈ‰A;vlXXØ€^}õU*¤×3"pÊL‘S¶lñâÅ‹/¦‹8åÖÇh"H‡€˜ &fÒ!€y2™ŒJ1ôr^4XŠÐ b"`ëJÐ]½òÃÎó-Å &ž>øJÿÍËË‹ŒŒtss ݵk—8S£Ñ¬^½zèС^^^‰‰‰---ÒR¹¹¹!!!r¹ã<O:œAeee||¼‡‡G\\\}}½tZËÉÉQ*• …bÞ¼yíííæçw>‹vttddd 2ÄßßÇŽf6'."“ɤe¥‰¶¶¶””_____ßùóç·µµI/xçwBCCÝÜÜ&L˜pæÌS;ØÚÚš””¤P(T*ÕöíÛõ7¡Þ6³!£{×e=€˜G6gΜ¬¬¬7näççŸ:uJœ¹eË–Ó§OÖÕÕ¹»»¯\¹Rz}AAAaa¡Z­v°z ,Ží©§žJMM­¯¯¯¯¯¿ë®»ô 9??ÿÌ™3•••—/_^¿~}—ó;Ÿ=ŠŠŠ +**.\¸`fs?ЪoÍš5555eee¥¥¥UUUk×®•þtøðá'N455ÅÇÇ'''›*ƺuë®]»VUUuæÌ™üü|ý?韷ÍlÈ ëN„ß u<‚‰ß’ ÉÍÍ=þ¼þ_‡^TT$N×ÖÖ*•Ji©ššÇkü®(àTçç–––!C†H§µ²²2qº¤¤$((¨ËùÁÁÁ%%%–oÎè©800°´´Tœ... ”^ÐØØ(­G.—›ÚJPPPyy¹8]VV¦_Nýó¶™ -˜©z ÿufŒ&:‘?ÿùχž8qbHHÈ_|!μtéRTT”\.wqqQ©TÒÕA¯JÞ?üííí-“É Ecc£ô§#Fˆ#Gެ««ër¾Ë—/9ÒòÍUWW'­dÔ¨QúgÝAƒ‰^^^f®äÔÖÖ†††ŠÓÒDçó¶™ ™ba=Ày\.omm§¯\¹"ÍŸ4iÒþýûÞ}÷ÝE‹I甪ª*µZ­Ñht:V«uÈ:!ÎãùçŸ_¼xquuµV«½~ýºþeßÊÊJq¢¢¢B¥Ru9ß@@@@EE…å›3J©TêoN©Tvw•JeUU•8-MX¾!S}„åõb"ìXTTÔöíÛoÞ¼yéÒ¥… JóÎ;wëÖ-­V«ÑhÄ™ .LII)//W«ÕgÏžMLLtàš!,ΠµµÕÍÍÍÓÓ³ªªjþüùúJKKo"LMM5kV—ó $%%-Y²¤ººº©©)55ÕüæüüüJJJ:¯$!!!==½¡¡AÜ\BBBwwð…^xå•Wôï¼´pC¦úËëÄDرݻwñž¾¾“'O~øá‡¥ùÏ<óÌôéÓ ŪU«>øàqæªU«¢££ccc½¼¼fÏž=}útGM‡dDÀIìÝ»wùòåÞÞÞ>úèC=¤ÿ§èèèqãÆ1B¥RéŸLÍ7™™9vìØ¨¨¨‘#GJ×gMmnÙ²e÷ÜsOç¯KÜ´i“R©=ztXXXppðÆ»»ƒ7nôõõ ‰ŒŒ¼ÿþû]]]¾ÌÔ†Lõ–ל‡Ìy¾É‰¬à´8ôoRAd2ã]ž©ùv¡¸¸xÚ´i/…÷býpvfŒ&‚îìÌÒ¥K¯^½Z[[»|ùòøøx*ÄD ‡씬q~xxøØ±càðꫯRQè#rª„EÎÀÔU[¾âlªl‹/^¼x±u¶gÆh"H‡€˜Â" &‚tHF€˜b"`C‰ãÜ&§ûB2o[–p¢ÑDN@ÀùÙFlذC Û'ãë4°vï+“effž`ã¸7+ÑÏ…dDÀÿŸ Ò!aÄDˆ‰YFs!I6‹{èó€he2ú_ØFèÛŒ(X0dȘ"ˆ‰{%b"Ž‹‡‰‰ &àtIÑÂWv¾‹èGrª€þ͈€mâI+z?šÏˆ<é »ÀEgl4ký‹O3X½÷5;šhù³/@Ÿb4€^ЋOŸðà3ˆ‰À\R$,¢qÑ€ÛtÝ s>ÂBXDÿâ q¸­Œh§+ºþ<Ãh"Öî}»ù…8|í6ú÷&ÐVÎmÄDX #FpÑ«÷¾=ý®>Ú¸è €}¤4¾OÄD@LDÿã¢3E´^Ìg=¾èÜGåŒb4€®3™`KÃx +Â:MÀ¢dfS£‰€0š€¹th0a›Åˆ‰X;„ÙlãÒ3ˆ‰Ãˆ‰ &`3 ÌöC˜½”ÄD'#ÚQðbXÄDH]ÄDXä`í¼ÅâÀ.0š€ãÄ\ÆÑ›Ÿgø4€µ{_FaM8;Ç„cLÄD`<#’qûôÀê½o_tæ&Eô FNʳ_» b"è",’Ñc\t8c~êßðdµ'¹ú b"ÝHNb"ÝKŠN2š(pŸ"n÷&œ(:a`âE -‘AL€˜H €˜ÀíÇ#1ÝÅ#,2¢Õ{_žt†=`4àø1‘!4ƒ:¡B@L†ÈˆÆ£3@LÆ“"yæqoVï}màÞDžìA—M8n¼ëVL¤®@L8]‚åEÁ(.:`õÞ×–¾‡°SM8®5ßfL¤ö@L8xÜU‡ÞÂEg€Ýç»K9¶ù+, +£‰0öy†ÑD¬ÝûÚöo:s£'DŒ&ì9¦OëVàÒ3ˆ‰€˜S¸è °­Œâ ÅÆ/:"Fý ‘Dv赘HÕÙø1‚#aМQGGÇÎ;çîî>yòäC‡Iw¤=þøã'Ož¼qãÆúõëÕjõW_}uöìYA"##ãââär¹ÐiœIúoVVVllìÉ“'oݺùÄOˆ¯7AÄEÔjõΞ=kPS¯wÞ—‹Î}pɸ½‚ÑDpFGmkkKKK[´hÑùóçõÿtéÒ¥ ¬_¿^„Ç߸qcéÒ¥K–,ijj:räH—k>þü¢E‹ÒÒÒnܸqôèQKJróæÍ´´´… VVVšêõ·H]&ˆ‰€ÞTTTôŸÿùŸ …B¡P<þøãúš:uª———ô²Ç\¡Px{{ÇÅÅýüóÏ]®9..ÎÛÛ[¡PXøúŸþYÄD›MŠ”Ê É©pBÍÍÍ~~~â´4!òññ‘¦[ZZüýýÅé¶´´t¹fimþþþÍÍÍÝ*‰´-ý@F´4f0¬h³·.pÈz £‰àŒ ESS“8-M˜Ùµk×¼½½ÿ_çqÇâôÍ›7õ1úz3¼½½õéœNˆ6õ‡}ݺb"À"‘‘‘¼yófKKËÁƒM½lܸqliiiiiÉËË‹ŒŒç«Tªï¿ÿ¾££ãŸÿüçôùú믥×ß}÷Ý]–dܸqú‹í(&Ú×­ &,ãîîþú믿ýöÛÆ sqq1õ2…B±sçÎ;w0 &&FœÿÔSOgggïÙ³'44T‘áÇ¿ýöÛ¹¹¹ÞÞÞ?üp—%yä‘G¼¼¼rssß~ûí#Fè'2¢m&E‰½Üº€ãÞDpF®®®Ó§O§üñG£9@.—?ýôÓO?ý´Áâ ,þ{ï½÷JÓS¦L™2eŠåC.—ÇÇÇÇÇÇK‹K/ #ÚrXÌÊÊïI8p `Á­ âË:ߺàêê*»u¡óëÍo]áõFÀIåååµ¶¶677óÍ7cÆŒ±µ BF´}vqën£‰à¤ ôæ›ovtt„‡‡?òÈ#}šùºœ£?Ÿ€hã¤ó׿þõõ×_wss›>>S¦L9wˆxë­[·""",¼uáÀ¹¹¹nnn÷ß¿©’ »øx€mågˆ‰ð+,÷666~øá‡©©©½²f>*ØF6—<`+++ë¾ûîkmmÕh46x눉I‡dD{8.:èå£Ì!vÏ3Œ&ȈÖî}¹è {Àh"Àz1‘ŒèTGœÃML ë€HFì?Öúðãì÷F`õÞ×™îMä~ûÅEg@_…’`׸è èäH%€f`¿MôI& À aÐ$ˆ‰gψ¤˜ùü;Â#,€^N‚®{_¾^ö€ÑD@ï¤Cƒ €ÄDˆ€bЫ÷¾\t†=`4Ðs\@‡˜ç 7Vï}¹è {Àh" Û¸\Ú1NŠAo@70öÓ;½/aMt## |?"øBL€˜83½DÒaoö¾\t†=`4ÐuFD„uÛˆ‰b"@R´Q zÌõÖtØ}ÒûrÑö€ÑD€ÉŒ(0®>¢ &ÐÇ 7€€hõÞ—‹Î°Œ&›þÐÂ'–þ"§ ;f*ƒÞ€K‡dDkô¾\t†=à¢3°›1°&.:è†Aã„ zpݰµ{_.:ÃpÑØÓ§>ÒÖèqéw˜Â 78uF¸ÜÜ/½/aM§Ž‰dDØûç½ß¿ÒÑ‚¤b"€ž4ft÷F`õÞ—{{5)’û£‰à\*Xˆ_a2"@Æ z`õÞ—‹Î}“I½‹ÑDpü¾“î@O>Ïði>)’m®÷e4ö€GXÀaÓ¡ÁàT-ÄD€Éž’þ´|t–-¿—qo8Z7Ii½/÷&’í£‰@ׯ>Ïði,)í ÷e4ö€ÑDp¨tHF ÞT1€¤Ø›ôÀê½/aM;ƈ€åo*˜`$#’»‹Ao¬ÞûrÑö€ÑD°?\kxïXœ*kvQ¶¶6ºL[c#ŒwBà¢3Øl 4¿!kn‹#kÍfêO=Ëm].Õ»›1ÐÃðdƒ‘ËavÄácb¯o¨´£·0͘˜V RÖñ8ó¾÷uLlmm]²dÉ'Ÿ|"ÂÌ™3wîÜéáá!þiëÖ­;vìhnnž9sæï~÷;wwwýܦÑhÖ®]»gÏžæææøøøÝ»w+ A:::V­Zõ¿ÿû¿jµzݺuééé2™LÚb—©´½½}áÂ…Ÿ|ò‰OFFÆŠ+L-ÒÖÖfªä¿ûÝï¶nÝZSSùûßÿþî»ï6S`[hØ4Zb"ô~6ròÞ…*ºý˜˜žž^\\¼wï^N÷â‹/Þ}÷Ý¿ùÍoÄ?M›6íý÷ß—ÉdIIIwß}wNNŽ~žÛ¸qc~~þÞ½{}}}—.]ªP(Þ|óMAÖ¬Ysúôé÷Þ{ÏÛÛ{Æ ¹¹¹Bw.:¯X±âܹs{÷îÕjµsçÎýúë¯M-˜‘‘aªäÏ=÷Ü믿>pàÀßüæ7(((0Sà~oÃ$1zhèH¨Ã^‰ÇŽ ¡¤¤$&&æÒ¥KâŸÊÊÊF-BiiiLLLuuµ~ž ýòË/#""A¨««‹ŠŠª­­aذa‡¾óÎ;¦À.cbppð±cǤ톇‡›Z0((ÈTÉ $ÂÍ›7}}};::ÌØÊŸ[úåÃ1-Öh¨a+ÄD—öövAÔjµ§§§ªd2™Z­6:_ì²]]]Å N§Õje2™V«A.—·µµÉåòžÅD¹\®_i+¼²s ÖlªÀ¶Ëúh4ÑaZ81Á…ÔBå÷CL üöÛoŽê&>úè£/^ÔO]!!!ßÿ}pp°Á:os4qذaGµp4ÑTÉÆDSîŤeû£‰vÚΉ‰H'à ôCLÌÈÈ(--ݳgN§KJJŠŒŒÜ¾}»ø§'žxâý÷ß!)))**jëÖ­ú©kË–-Çã7BCCKJJ6oÞüÑG ‚°víÚS§NíÙ³ÇÛÛ;33ó·¿ý­ þþþ?üðCxxx—1qåÊ•gÏžï8LJJ2soâ²eËL•ÜhL4Uà}»h!Žtç.1€¢!GÊvb¢þ“Î3fÌxã7¤ç…srr^{íµæææ3füîw¿“æ‹]¶V«ÍÉÉy÷Ýwkjj"""Ö¬YóÜsÏ ‚ÐÑѱ|ùò?üá:nýúõiii‚ lÞ¼yëÖ­ÍÍÍ]>éÜÖÖ¶hÑ¢?ýéO>>>Ë–-³ðIgƒ’‰¦ ,8Ó vº§ÄDpû!&v«ÿÕétr¹\£Ñ8p`rª·ª½T1€cžsI‡PGЉ?þøãÓO?->PL*"2€0‡=Ä݉[·n¯#ßÎF ætY†,ÒåÁâMjG5FL@tÝÖc"Y‡ß/uHL`ǧN:Ú€½~ψƒÆD>Â9X• @« &’©db"¢h!ÄDÞ¡Ô91§BÐZˆ‰T8Íž˜€sh9vÓrì7&òötª#BL@Z1‘·'Íž˜€´(b"oOš=1€=žÚèà MËŽb"oOgnöÄDô@ ™y{Ò쉉lò,Fgko6 ˆ„Eb":!Ððˆ‰¼=iöÄD¶w΢‚Ó¶@›‰¼=iöÄDtBv@§Ó=øàƒß}÷t¢ÎËËËÉÉùᇼ¼¼¦NúÚk¯‰™Ã`AjÏÆÛ¡ ÆD§Ù[~ˆ‰‰Èˆ6êý÷ßï½÷Nž<)¨cbb–,YòÈ#¸¸¸ìܹóË/¿üþûï‡û`gh¶vÈxoÒò‰‰è‡ìÆÕ«WÇèС1cÆ=Q···ûùùµ¶¶í±MÚÔ!ã½IË'&èÿ³å,X0jÔ¨+VÍ---o¾ùæñãÇ8 fŽÞ¸qcĈsçÎ]±b…‹‹ uhËÓvb"‘¤HL@F´'K—.ýî»ï\\\:ç ñNÄ¡C‡~÷Ýw£G–æk4š³gϦ¥¥EEE½þúëT£-7Q‰‰dDš½ù£OL@F´9÷ßÿîÝ»#""Lå‰þóŸ¿ýío:”ŸŸoð§ÚÚÚ±cÇ^»vj´å†j 1ÑyÞ›–? fêõNÛòïàÔÀ ŸVÑ-'OžŒŒŒ”ÉdâÀ¡ÁƒÌ‚ 0`Ù²eFó‡V«¥i±dDÉÞ½{ ÞÛ·oOMM­­­=þü¸qãžþyó¯'&@_õ¸„ÅîÒéô¾àæÅ_üå—_ÔjõåË—×®]{ÿý÷‹óŠŠŠÔjõ?þñyóæôy ¹:óç·«W¯feeíÝ»Wæ‘#Gž}öY???ŸeË–ýßÿýŸù×;íg$b":]»ñôÓOÏœ9ÓÓÓóW¿úÕ•+WþøÇ?ŠóŸ}öÙ„„OOχzh̘1o¼ñuE£å½)Z½zõË/¿nô¯---¹¹¹>ú¨…¯w¶&Á½‰úð¼CFMרþº7ÑÙ2bwŸ3ÿz' ‹Œ&èÃÓ @fïúQZZÚž={L}?”N§»~ýúË/¿±xñ✜ñ‹-6lØšš*ýé©§žJMM­¯¯¯¯¯¿ë®»ÒÓÓ;/~øðá'N455ÅÇÇ'''w~Áĉ333+++n]ú6 i¸nË–-§OŸ.,,¬««sww_¹reç¥ÚÛÛ?ùä“_|qöìÙþóŸÛÛÛÅùëÖ­khh¨ªªúé§ŸŽ9¢¿H]]ÝÅ‹7oÞ<{ö캺º .lÞ¼9##£»{4gΜ¬¬¬7näççŸ:uÊè.ˆá¸°°P­V›ªÆÎK­Y³¦¦¦¦¬¬¬´´´ªªjíÚµF×Ö¹è\qÆí´œûŠ ¸™™™™™™¶Pñäöä“O~öÙgŸ}öÙO<¡_ôµ´´ 2D)q¢±±Qz\.ï¼`uuõ¼yóüüü/]ºÔy%ú¯>|xQQ‘8][[«T*…<ãû IDAT;¯óÓO?}ä‘GÄéÇ{ì“O>§ƒ‚‚ÊÊÊÄé’’ýM\¹rE§Ó‰CtÒ´‹‹‹…{$½ $$$77÷üùó«Qÿ¿555F+Üh5ŠKKKÅéâââÀÀ@£k3ZnÏVëmç]éœì:heff2šÀaÇ-^~ùåÍ›7oذ!--Mþ?üííí-“É Ecccçe $Nxyy‰Ã]‚‚‚öìÙSSSóË/¿ ;}€¬gÅvxÄDkêÔ©ÍÍÍZ­666VþóÏ?¿xñâêêj­V{ýúõÛ|ŒC¥RmÙ²¥  Àü˪ªªÔjµF£ÑétZ­Öàõõõ_ýõܹsÅûfÏž}ðàÁºº:qYéêvEEE_ÔÕ¤I“öïßßÐÐðî»ï.Z´È’E,¬F¥R©_x¥RÙ[€Í²ÓÈzPlb"Øñ¨FIIÉÏ?ÿl0¿µµÕÍÍÍÓÓ³ªªjþüù=[ù“O>ùí·ß¶µµ566nݺuüøñ/ðóó/‹.\˜’’R^^®V«Ïž=›˜˜hðú?üpÖ¬YúW|æÌ™óÑG ‚˜˜˜––ÖÐÐP__¯“e/JHH8wîÜ­[·´Z­ÔSì‚…Õh°TBBBzzºTø„„Ë ;e§™)¶©5tù™ 999J¥R¡PÌ›7OºáØÌ mëÑ.îàx7B=¹I3÷ïß?jÔ(¹\>bÄqÂüm…F×vàÀ|ÐÝÝ}À€O>ùdyy¹Á‹7mÚäíí-ýW£ÑlÙ²eøðá®®®ãÇÿôÓO VuôèQý9ÇŽ‹ŠŠÒét­­­sçÎõôô:t¨8Âѹ`F§»Ü#iâã?—Ëå‘‘‘4º +1UKµ¶¶&''0`À€ÉÉÉ­­­F×f´Ü›hoIqØxܸqZ­V«ÕN˜0¡´´TÚ߈ˆˆ#GŽÜ¼yóúõëéééÒG#ýföÜsÏ]¼x±¥¥eÆ “&M꼉ÿøÿX¾|yEE…©Z5¨ÞW_}566öâÅ‹ÿüç?çλxñâîÛÔAHMMmnn~ï½÷ …4)½`Ú´iµµµuuu?þøŠ+º\aBBBCCƒøßÁƒúé§mmmçÏŸONN¶þ[€˜€ûåÇŒ‰ýò~ìó2óÅ6µÁ‚ÇÈôŸ? êr…¶óhWff&¿é  7ñ›Î %[xG„uú_ë?X&îÚÁƒÿçþG­V¿öÚk±±±ÒþþðÃ+V¬(,,/³Êd2ñ>]é5c¾¢jkk³³³üñÇ'N˜Y‰«««”ù´Z­´QË‹mj ú2:-“ÉÔjµ‹‹‹ jµÚÓÓ³££Ã ‚pêÔ©7žé\Ú³3³¯Ⱥ,¶åkèLÿ.•JÕ­öû£]ÄDÐËìë².‹mù:KKK¿…>55uÖ¬YÝZa¿?ÚELÐËøÕІaÊÞ½{—/_îííýè£>ôÐC=[É¢E‹Ö­[ççç7jÔ¨¿ÿýïü±Á –-[vÏ=÷HO:¯Zµ*:::66ÖËËköìÙÓ§Oïîog ÑÑÑãÆ1b„J¥’•…+|æ™g¦OŸ®P(V­ZõÁôCÜçÞD}ÔËÒÑ‚Ök²÷uÜ{áHïFôaG‹Îá€J  ö‚˜€¾äZ‡m±Œ&âvZ1@ßv·ôO ÑvŠ˜€N·üÄ–…?¦Ïè¯r™ZOkkkRR’B¡P©TÛ·o×ÿ¡3ó?fæ'Â:ÿBZç=£¹ÄDèå®×ªÕjA¶lÙrúô麺:ww÷•+Wv¹øœ9s²²²nܸ‘ŸŸêÔ)q¦©õ¬[·îÚµkUUUgΜÉÏÏ×_O]]ÝÅ‹7oÞ<{ö캺º .lÞ¼9##Ãü A8|øð‰'šššâãã“““A0øY Z¬]ïñ=h3<é €^ªÈd²ššš€€ñ¿¡¡¡_~ùeDD„˜Û¢¢¢jkk³Ï·><==ýÙgŸ ‘fšZOppð·ß~;jÔ(AÊËËäŸ|¸råÊÀÛÛÛ=<<¤i…B!æW3kll4h 7oÞôõõ+Âjä:[µrÅ:Ø{ÐIš%1IÑqb¢%?f¦{3ú«\¦Ö#—ËÛÛÛ¥_“^ÖåO‡YX0S?zFã´ß ãHïA»k–öU`ý¦ÂEgV=ï8É•¯ü´—Ñ_å2µ¥RYUU%NK}T0Çn–ÎvA–KÏèV !&°öÙÇ:ªü´—Ñ_å2µž^xá•W^illlhhHOOﻂüè ’€Ø§xÌÖZ 1sïëÁO{ýU.SëÙ¸q£¯¯oHHHddäý÷ßïêêÚG3øÑ3š¢ìµï2‚ÙT áÞDôÐö­¸¸xÚ´iT…µÀþºYÍÆß}< fkï b"€þ<{léÒ¥YYY·nÝJII Û±cubG ¯sƒ-'E³µÏN\tÐ?§$gS”uÒƒ•„‡‡;6,,lÀ€¯¾ú*ª[¡38±£·‚õ{“ & Û¶6]'=XÉâÅ‹ëêênܸñá‡z{{ÓœøXÒƒ·žãQ°~orÞ-úýÄÔù_ ×{>šVçèlãŸÐV­Z%“Ébcckjj"""Ö¬YÓå"â£`ÿøÇ?ÆŒ£ÿ(˜ÑõlܸqÁ‚!!!>>>¯¼òÊ×_ÝGknn¶ÁKÏæO¼Ü›À?Èңñ[”Ü¬Æ «Ä ³äèеƒVä¤1‘¤è´‚Yx܉‰èæAËqÞ˜h¿I±ó³_=¨Ò·ÞzëÕW_½yóæÓO?ýî»ï:Ém¾–qb"º|ÐZœ:& \}vÊ7‹%Çš˜€î´g‰û8Ù›ÅÂCLL@­‚˜hX¼ËõýÒ­#KL@2m€˜h¼Jy‹9Ø[¦»”˜ÀHRD_Jb"¢8ÄÄDÂ"‘˜€0(1‘°H@$& [бq‰‰½~\xO9Ï‘"& p€#EL$,‰‰H!trb"a‘€HLÒ •OL$,‰‰Ð;©…>&&’©sb"Xzž¥ó£‰‰Ý:¸nǨdb"ô$Ð8y/HÉ‹ÎP¥ÄDè͸ã`¢3ï;1±w› ÍÃë˜}žŸl¹§t˜!&’u¨1b"8Zvd§ˆ‰NûÖ uÙxåÀ©#ý41‘TD% &Úͧç¹Í×–÷”f 1Ѧƒ”}eGGúš)ÄD» [ý›ºœá{h¦-8RTb"ÄDØÁh"1á8î  @L1ÄD@L1ÄD@L1ÄD@Lˆ‰ &€˜b"ˆ‰ &€˜b"ˆ‰ &€˜b"ˆ‰ &ÄD@L1ÄD@L1ÄD@L1ÄD€˜b"ˆ‰ &€˜b"ˆ‰ &€˜b"ˆ‰ &€˜b"@L1ÄD@L1ÄD@L1ŽCN¬ ++‹J B¨ û"ÓétÔ€ ˆ‰€þéûÉ ‘ø·.Ÿ¾´b"†==½>h6ÄDèéAr|!€´"Áh"€®4*}ÙÓ—ƒÖELÀ°ç¦ÍŒ˜À¿uØôÜ ½0ì§é³AÃ#&ðoÝ3ý4hŽ/Ät£{¦‡¶œN§{àd2Y—ó¯]»6cÆ …B1dÈ*¶[1‘ê"&l¨o&#ZhïÞ½Z­Ö’ù‹-R(ÕÕÕÅÅÅ{÷î¥öh¶€‹Î€nôÊtɺzõêøñã:4fÌý®Öè|Ÿ .øûû‹/xæ™gŽ?NÒ2‰‰ûè†é‰»eÁ‚£FZ±b…Löo]­ÑùÞÞÞ/^”bâ¨Q£®]»FÒD‰‰;è€é}»¥  `éÒ¥ß}÷‹‹‹~45ÿ¹çžóõõ}íµ×´Zí²eËþð‡?tttP´Õ~ǽ‰K;`X(--mÏž=...Îçw®]»x×]w5jðàÁÔ!­Ô0š0×ïÒûö¤s5öt³™ùúöíÛ÷Í7ß|øá‡T#¶ß1š0ÙÝ¢gtzô³ ©ùÉÉÉÕÕÕ­­­û÷ïÏÊÊZ¿~=uHë%&lº—¥»µŽ{ï½wÒ¤Iƒ~óÍ7?ÿüóððpꄦk ¸è 0Þ×ÒÑ‚ìäMÐÅ‚6 b"À‚þ =ƒ˜ smÄD@LÀ¤Î_jm›ë´µ-ÄD€ å¹Ý»wëÏÉË˳¯xÔ­ÒÊþÅÇÇ'66öܹs½¸é^¬7N÷Àý ƒù×®]›1c†B¡2dwèM»wïÖh4Ò·mÛf_åïî·‹¿ÈR]]ýðÃÏš5«KbÆÞ½{µZ­%ó-Z¤P(ª««‹‹‹+**öîÝK“&&Ð;¢££ÿøÇ?ŠÓû÷þ¤ÑhV¯^=tèP//¯ÄÄÄ––q¾L&ËÎÎ8p J¥úâ‹/²³³ ¤R©¾ùæiÙœœ¥R©P(æÍ›×ÞÞÞå sssCBBär¹ yyy‘‘‘nnn¡¡¡»ví’ÖùÎ;†º¹¹M˜0áÌ™3Ò²Ò„Ñåëë»|ùrq4ÑT©$•••ñññ>>>qqqõõõÒvűIƒ’´µµ¥¤¤øúúúúúΟ?¿­­MzÑ]0põêÕ¬¬¬ÎÏèü/¿ürÇŽþþþƒ ÊÍÍ}ÿý÷iÒÄDzÇâÅ‹srrÄ1¶ 6¤¦¦JÚ²eËéÓ§ ëêêÜÝÝW®\)ý©®®îâÅ‹›7ož={v]]Ý… 6oÞœ‘‘!½ ??ÿÌ™3•••—/_–~1ÙÌ Õjµ sæÌÉÊʺqãF~~þ©S§¤×>|øÄ‰MMMñññÉÉÉ÷ÅèFº~ýú¶mÛÆo¾T¢§žz*55µ¾¾¾¾¾þ®»îJOOþ5v(ýZ´¾5kÖÔÔÔ”•••––VUU­]»Öò]aõêÕ/¿ürçß4:ß`ëEEE4iû¦à_233333ûkëb¯ôä“O~öÙgŸ}öÙO<¡Ÿ~†^TT$N×ÖÖ*•Ji©+W®èt:qœLšvqq‘^PVV&N—””u¹Âšš©T!!!¹¹¹çÏŸ7(jcc£8ÝÒÒ"—ËõwÁÌF V" ¬¬¬4_ªÎkhii2dˆÑHÿ ,--§‹‹‹Í¿ýío÷ÝwŸZ­6X¿©ù¿þõ¯çÍ›wíÚµ+W®¼ôÒKF×iÍÆÌ;úvß’TÀ¦bâ×_=a„»ï¾ûСCú)D.—»¸¸¸¸¸ÜqÇâ5ÓÎñÈè´ b ÑétRv±d…:®  à©§ž¨P(¤kÇæ‹äââb´$¦^¯oòäÉRfÕ©ù Ï>û¬§§§R©Ü´i“J¥rÚÆì¸è °-S§NmnnÖjµ±±±ú󪪪ÔjµF£Ó•å묬¬'***T*U·V8iÒ¤ýû÷744¼û-ºÍv&“ÉFýÁ,X° ¹¹¹ËR=ÿüó‹/®®®Öjµ×¯_×uõ¨ŠR©Ô/‰R©´|Nž<)Ýò(ÝïhjþàÁƒ?ÿüó›7oÖÖÖÇÄÄОí1`[d2YIIÉÏ?ÿl0áÂ…)))åååjµúìÙ³‰‰‰–¯3--M¼™/55Uz ØÂ&$$œ;wîÖ­[Z­Vÿ)ìžmԔɓ'ôÑG]–ªµµÕÍÍÍÓÓ³ªªjþüùÒ|??¿’’£åOOOohhK’`ù.tn4??99¹ºººµµuÿþýYYYæïÈ1€Þ±jÕªèèèØØX//¯Ù³gOŸ>Ýòe£££Ç7bÄ•J%}ŸŸ…+|æ™g¦OŸ®P(V­ZõÁÜæF͘?þ®]»º,ÕÞ½{—/_îííýè£>ôÐCÒüeË–ÝsÏ=¿ÝpÓ¦MJ¥rôèÑaaaÁÁÁ7nì»ctï½÷Nš4iðàÁo¾ùæçŸÞùÁØÙg6]ï}¯ÀÞ‰i†/Fî…þUFKc¶{Œ&€˜b"ý…+Î &·s6 b"€Î´g÷¬ô¯–èüí3¶¹N[Û"m˜˜p„¾Ii· &zØÑÒãÚž‰¡é¶ÕÝ:™L–=pà@•JõÅ_dgg4H¥R}óÍ7â 4ÍêÕ«‡êå啘˜ØÒÒbá‚‚ äää(•J…B1oÞ¼ööö.W˜››"—ËAÈËË‹ŒŒtss ݵk—´ÎwÞy'44ÔÍÍm„ gΜ‘–•&ŒnÔèŽëoÎT©h½ &zÒ×:F[WWwñâÅÍ›7Ïž=»®®îÂ… ›7oÎÈÈÿºeË–Ó§OÖÕÕ¹»»¯\¹ÒÂAÈÏÏ?sæLeeååË—¥Ÿ06³Â‚‚‚ÂÂBµZ-œ9s²²²nܸ‘ŸŸêÔ)é5‡>qâDSSS|||rrrçÝ1ºQ£ô7g¦T´Xÿ¤Á 6À|¿kï]¯L&»råÊÀÛÛÛ=<<¤i…B!æ§ÐÐÐ/¿ü2""BÌ…QQQµµµ–,(“ÉÊÊÊF-BiiiLLLuuµùÖÔÔˆ>|xzzú³Ï>¢_ÚÆÆÆAƒ ‚póæM__ߎŽAï×ÿLmÔèŽëoÎL© p¹™˜ ÷íIL”:;£Ó®®®â„N§Ójµ2™L«ÕZ² L&S«Õ...‚ ¨ÕjOOO1ÒY²BAN:µqãÆ“'Ozzzîܹ3>>¾ókô·e~£æwÜòRÑJALt»¶Ón¸Ë´òý÷ßwwAƒ½G}ôâÅ‹®P_^^Þ¼yó._¾laL4ºÑ.cbwKEã÷&ºî‰{´fáÂ…)))åååjµúìÙ³‰‰‰–/›––V_____Ÿšš:kÖ¬n­0!!áܹs·nÝÒjµæ67Ú§»iãQ¿‰‚˜èÏ.ÙÁvmÕªUÑÑѱ±±^^^³gÏž>}ºåËFGG7nĈ*•Jª WøÌ3ÏLŸ>]¡P¬Zµêƒ>¸ÍöénÒ ôÍvÕsËè»i‡ÄD€m÷ÐtÒÄDš1“½5]µ-ÄÄÎ?åçý;­Ž˜°³>›n46‡Ä#,znÐÒ`£‰zqд@LУƒæb" »vzwЊˆ‰˜ìæéãAã!&@ 1€î÷ý ƾð…8z}kÛ°a•@k±}Œ&`õÞ—ße†=`4ÄD@L1ÄD@L1ÄD@L}G&“Q @ßæ¶.—êÁjIÄD`Ct:­ÄDÐCmmm)))¾¾¾¾¾¾óçÏokk“þ”““£T* żyóÚÛÛřҞF£Y½zõСC½¼¼[ZZÄùC† ñ÷÷ß±c‡´ˆL&33þ'ý©½½ý¥—^R(*•jûöíæ_/­3,,¬¸¸X„ .ÜqÇ555‚ ‡……™ßG€qkÖ¬©©©)+++--­ªªZ»v­ô§üüü3gÎTVV^¾|yýúõ nÙ²åôéÓ………uuuîîî+W®çgeeVTT\¸pAø×H¡N§³dÈpݺu UUU?ýôÓ‘#GL½Ì`qqqÇŽáÀîîîáèÑ£Ó¦M3¿° 2F›°vï+“;vLu+))‰‰‰¹té’ø§²²²Ñ£G ‚PZZS]]-λìÐÐÐ/¿ü2""B„ººº¨¨¨ÚÚZA† vøðá;ï¼Ó`Cæ;zéÁÁÁÇŽ“¶njAýuæååíÛ·ïüãO<yîܹ¿þõ¯3gÎ|饗üñ   £ûb"0Î\\\ÚÛÛ]\\AP«ÕžžžâŸÔjµÑùb—íêê* éiµZ™L¦ÕjAËåmmmr¹¼g1Q.—ë—GÚŠù˜ØÚÚQTT\QQ1jÔ¨‹/FDDüòË/ë”öö‚‹Îô¥RYYY)NWTT(•JéOúóU*•Á‚UUUjµZ£ÑˆIQš_QQÑãòèo×Â¥<==ÃÃÃßzë­‰'úùùMœ8ñ7Þ;v¬‡‡‡ù}1—žžÞÐÐP__Ÿššš ý)--­¾¾^œ?kÖ,ƒ.\˜’’R^^®V«Ïž=›˜˜(ÎOJJZ²dIuuuSSSjjª8ÓÏϯ¤¤Ä’ò$&&¦¥¥Iå1óJƒuÆÅÅegg?öØc‚ L:5;;;..®Ë}1·iÓ&¥R9zôè°°°ààà7JŠŽŽ7n܈#T*UVV–Á‚«V­ŠŽŽŽõòòš={öôéÓÅù™™™cÇŽŠŠ9räˆ#ę˖-»çž{,ù¦Ã 6 2døðáãÆ‹‰‰1óJƒuÆÅÅ]»v-66V„Ç{ìúõëRL4³° Ü›€Õ{_Y÷ú_N'—Ë5 Ukb4[WXXØù&E ¯É©lÜ”)S¶nÝz›+é|é¹ËÍ,GÂEg¬ÞûÊèa¸è b"ˆ‰ &€˜b"ˆ‰ &€˜b"ˆ‰ &€˜b"@L1ÄDÐäTÀÖdee±ýN¦Óé¨q`4@GFpo" ,‚˜ˆ &€˜ú–8 È°"1ÄD 0 HL1Àb (@L°ŠÄDÐs:îÉd]Î/--:uªB¡P(S§N---¥ö@LÀaíÝ»W«ÕZ2æÌ™÷ßÿ¥K—ª««ï»ï¾^xÁ^ö‘EÇ&ÓétÔÀÖ’‡½ç«W¯Ž?þСCcÆŒÑïjÎ÷ôôljjrww¡­­màÀ7oÞäH¡ß1š@ï[½zõË/¿nÉüiÓ¦mÛ¶íúõëMMM999qqqvëAL]+((øé§Ÿ222,œ¿sçÎ÷Þ{ÏÏÏÏßßß¾}o¾ù&ÄDPZZÚž={\\\,œ?oÞ¼¤¤¤k×®]»vmÖ¬Ysçε¯ý%/:*îMØbæ°ëäaôéf3ó=<<®_¿.Ý›èçç×ÖÖÆñB¿c4€^¦Ó#eA3ó#""²³³›ššššš¶nÝi§áÄDЛ>üðÃãÇ?~üÃ?$ ÂÈ©úŽ©›»ôç3æðáÃÔl £‰à¶p{"1ÄD‹1 HL1Àb (p¿ìÚñ¶èÂØ±cï¼óÎ>Mof6á$’Eb"væoû›Z­vss;yòdç¿öÊïÖšßDwñSº &` ûöíKJJš3gξ}û:ÿUºëèèÈÈÈ2dˆ¿¿ÿŽ;Ä™fõêÕC‡õòòJLLliiùÿÚ»6þ?Žã9r$PíŸ •3u+X*.b‹-ÙLÓh¡BJ L‡;¨…PÈX  ¶ƒÍ\l é TZTŠMmÓzI‚¨Ü%ßáà诿¯å«éó1}îÍçî“Ïà‹÷a´¿D©Tºuë–×ë•$)ï]qtt´¾¾^’¤t:=::ÚÐÐ IÒÛ·o«>’ OŸ>õûý.—ëòåË?~¬šPu8==ÝÒÒâr¹ü~ÿøøøï· B"‘eYøßmÐP$&p”J¥ÉÉÉ›7o†B¡T*U*•~nTU]]]][[3‹###g@Ê IDATóóóªªjšæv»í/ñðáÃB¡Íf?|øðîÝ»½§hšöõë×áááP(¤iÚÚÚÚðððýû÷÷_<“ɼÿ~ccãúõë·oßþýfÃáðÐÐÐæææÌÌÌÜÜÜ¡[˜UUU×u"Pà8‰Åb±Xì/øêÕ«+W®˜ãk×®MNNšcë— 5hll\^^®:½©©iaaÁ¯¯¯Ÿ;wÎþçÏŸÿôé“9^^^Þ»b±X¬T*¿~ýÚ;v:û?ÛÏŸ?ÍñÖÖ–(ŠUªeYN$_¾|±³‡Ãñýû÷?ñù1® t5Î|lŽ{{{|ïlúñãGsssU1—Ë)Š"Š¢Óé”$)ŸÏÛ_b}}ýÂ… æ¸êÊõõõ‡Ãívÿâ æÀãñÚöK¥R™L¦µµU–åt:}è|>ߟ¸çôk1PËòùüëׯûúúA! ½yóFÓ´'û|¾ÕÕÕýÅl6«ëºa•J¥\.Û_Âçó}þüÙœ¶ÿÊÿ†(Š;;;æ¸X,Zõ¶¶¶©©©B¡066600`s D/^ܸqcï{´p8üòåË'÷ööÞ¹sçÛ·owïÞ5‹‘H¤¿¿eeE×õÅÅÅ`0h‰`0xïÞ½B¡Ïç­  EQâñøööv.—‹D"V½§§giiiww·\.[½ÉC·@X1ð×yþüy__ßÞÊÿú{g‡Ã‹Å.^¼¨(Jss³õ²8vtttuuy<žP(ì/ñèÑ£3gÎ455]ºtéêÕ«G¸¯d2™N§ëêêÚÛÛ;;;­zwww ðz½ÑhtbbÂæ€ |3àXá+šyv8&è&€˜þ Z‰ÄDl •HL1ÀZ‰ÄDl ‰HL‡áÀÃééé––—Ëå÷ûÇÇÇÍ¢a<8{ö¬Çã ƒ[[[ÖY‰DB–eQ ‹ &PËÂáðÐÐÐæææÌÌÌÜÜœY™ŸŸWUUÓ4·Û=88hÍŸUUU×uÒ!ˆ‰Ô2Ç“Ëå4M“e9™LšÅgÏž%‰ÆÆÆS§N=~ü8•JYóŸoÍ÷ù|¤C¨¢(îìì˜ãb±hÕÛÚÚ¦¦¦ …ÂØØØÀÀ€•³Ù¬®ë†aT*•r¹|·LX$&€Ã)ŠÇ···s¹\$±ê===KKK»»»årÙ0 ³‰DúûûWVVt]_\\ ƒ¤C¨MÉd2N×ÕÕµ··wvvZõîîî@ àõz£ÑèÄÄ„YŒF£]]]' ·_Âbm*• wpÜ’ùƒÇ„ÿÝD@F1ÄDpäh%@L°V"1ÄDh%b"°&â_Hä%à¹`?º‰‚€ü{áxÂì^º,IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/openacs-best-practice.png0000644000175000017500000005476010012372366026161 0ustar frankiefrankie‰PNG  IHDR3óe¥f sBITÛáOà IDATxœìwX×úÇß™í}—Þ;ˆŠ(Ø{Wìh,1jÔô«InL½iÞÜ››ûK5ñƨ11&šbo±7T°¢"½ƒ´…e{ßòûc " Ru>Ïìì™sÞYæ;ï)ï9¡( º¼·ïJg›ñ¸@QÔÇ3t¶ÂÎkÅgó«:ÛŠÇŠúfþP„¢(ô…mËc¹þ¹Î6áAxù”ÿÎèl+ÈõÏ¡mC0Êd`芴™21Ú/ÀM!ä=Àµ¡žRAšüJ)äõö–b(,éàæ&z"¤GzÊ>†Ö󟙦ô¸¯KÞ™Þ·ÉóÑ>òŸ rãc0>ÚïÙá=~+ásúy´¾”N‹¿_Ã:ÖêÕ«ÿy0ÛÐÇõgètÎ4LLd!èº'‡¹2½R×|ú»¿zsJŸ¤ìJòöW ‘ ¹§_ÌvÚRÊô‚ü{Fÿ³ùUf^ŸA­ËƜέtàdÃÌë¿mÒ†¡a^_<1ø‡äœ»Klo>œ×Á%¶ ‡3Ë.—Ô€\À]1ºW)¥1>r“Z*ãUm+Æô.Tûø¹ ÷BæöSÊ$þ2>ÁbÏëí!48ˆìZËœ¸ÐX/I©Æ´lX´§R:.‹$©©}M&³§&Ä„Œ ÷²ÙlbpgZ¹æo£zr‚ÉQÞ:ƒYgÇ@m²¿“8lf¸âhv¥ÑóÙ¬µqDÏ IQ^6›md”ÿÇ3äTëŸè*æ¸(‘$J,Ñ#€ÇFyÁ}ƒäl Ös#¢Y|~¬œÏÁxlHÅODû•ÕZ»À`ŇSã°úE;d`ئ=Ü"ƒìKJ…eI_o°ÒsŠìÁ³Ã¢×{zHd_·oN¥¯™;ä`ve_·ì½òâÈ(Òéð0p“Ë^€TTÕ¤ÕXþ“8èë%Ý/çÝòôðcÍ’Š&÷ õ–ˆyìW²í,n_wE~\4¢Ü`Ó[]¾ôËãiåfT¬'KóF÷ þï|qA¡Boq“Ë—â`huumj•iJï€[Zó‰Õ{“{­úãdxTo“Á!”qQçÞìÚeñ~8 yEeUNäéq?^)ŠóUn:›"…ô“ýò2o}µÈNv?Hw@gsR"Y R_iæTª*Ö.ÿÙ/GG è;‡MƸÈ./®5þkFüØ/[1iÌgûXþ7O|}ã¡¿aº÷ç »œ|Í"ö||¤x¥¦x+oÏÑ­ßëƒ?3=ØT‘Þùû3#ûü÷pbßàì¹<-&0¿8%³†zojìÒ­AmÉY8W¸cùˆ·ö]€>=‚WÄû~w¥|ë’¡K~»ZPc8—¯¡Ó (·íÌ7•é-ëŽ\¹ùÄ{sFn=sééÁIëþ,` BÜÄž i¢‡ä§Sij¢«<wÔf÷gTl.ÎEq’:›Yò¯¹ÏÝ(úòdÞ·‹‡^.©ì€¤•kzû* ÕF ¿êVÕê}—†ÄD Y_žÊ*Öðì„«ÆðÙ‰¬å£{묶HOé…Œb•Ñå.Ýv!wéØ~‚:qü–Ö$ð—êyýVm?7¤Ro8ßœH òRöiPÉ/¯NÜ|vÎè G€ç&ÆôPðoi­¯M޵»›óëSIù•ˆ\éÆâN ð^<"Díp]È,zgV|F^ù—'sÿóÄ€ÔRõÏ«iŸ½<ç¥=3Ò Ö3²¼/(j[röœa½ã=ø5¶@·PïÐJ¥„`‚ u¯{£‹ÈÑYrª´ž"v¥Å©Õ LÉËÕ;ôƒ›B ¹F§ÃiÍ7á‡ÅâMë#·Ù,¾¸a™WkmV›…ÅÜ6"IrýÑËßÝÔn^< •<³ ·Ø,_ž/®OsèFÉäþÑvK ¢ ˆ‘$EqÙh­ÍeµÙ$b\V[2+Ô"ç óñ;è7lw(Ón³ýpµü•)ñž`+3ã^Bvµ ·ÚmB((®OŸkrÕ-JKã p‚°9ìà)dרp§ÓÉb¡‹UvÇUÇ(Êö÷¾“зZcÈ©¬ÅØwüE—‹ ’¬ÿëÒ—UÍüþô˜Á±³{û€—]¤Ò_*ªzy×u Ó$qøfÙâa1™·´yì4µ¾›ÝÎãq‚¢òÌN•Þ "Œr°Yñ!2îe1´HuúŒšÔhÔ.Šúòxî?bûÈ÷_.þ=«æ™¡ ú‡HxœÞ¨$õcrñÛcbž²/e?3Ÿ’~¾8v"?øƒ>¿éÊ’F¼Y—þø§fûí™L8‘š [.äÖçÐïã]t‚Ÿ/äÑY•º¶Š"·Ÿ»AŸ\¾%©>«'Ö¦&~±ÎüV÷Õš#—ëÓD}XgÞK¿ž£ö¥¤Þ×ïЮÜià&âE*%zû¬9rS‡“‚¹l«ÃEPÀÁX< Å ’±ì.‚Çf9qÂêÄ€ÇasYIQˆÙáâs06ŠØœ8 ˆ€ƒ9\CÀI\Œeuâ,å°†YÑÿ“eq¸Ä<N’f» 8KÀÁŒ6'IQ‚°1–Ó…#Âã`±»pNr9l ±:]8‰ˆy˜Éîb³YAºAÃPÄêp±X(Ù\¸ÃE8cYœ8c±PÄhw’U¡}" üb”ÄKõ¶Î5é†\ÿÜ>ÓER±¡ž®èp(Š27ð$îp€»ë¯R»Óeoµ.–Ûí6'}a»ýu}Võê­Ž†—Ó9Ðö8]8}`s¸êŸ ‡ÓuûÊhs€³® (ÊrÛIØ]uYY8ýNqÝΜ¡õ”iMm£ÏÊ4XßžJï,Sº8 G˜(Šjô±>MÃ㆗×_B4ú¿ÉK]{÷%õéÙÓèLÃi|I£[üæh¤L†{ñ·ÁÁÓC%mÅc-N ÂÜDmÌcC·sç&ä°‚ζâ1€#Ëu¶ Ý}µMæyÏñ@‹ÎÁ±1vÛDƒÔ6±’‡¢¿…;I‡Ê8mb TVVúøøÜ}ü00í ÷Aê¡Ò«Ç«Ài²îøà*P$E‘:•…¢€"©ú^nÒ_ÙSxaWáõce&ÃjpÞ8^F‘DÓ3öÏýZ{]†rýá¯ÓëÒÜNyôû¬ »‹2’* 56§è¢) H‚ R•’·#xŽÿ}awá™_ ŒFètN$E’`ÖÚËst@‘@KD‘ÔÇ÷讯)¸ù/¾©»G’$âĉ@Aô1PIõ/¾óêë•F'ìÙ³‚ IvíÚE'#‚ Éúô­jgj+- áçyª««e2—Ë}È|*++½½½;>JöÃiäÅb§ Ϩ$‘2m¥µèzIçì31XUhÌNVI=„Í:,Ð7ˆo5¹(.;v„_„e¯Ò”›ó.U‹<§Þj4“V+5lv0›ƒÀÅ‹ ,6e*×»zK SµwÎùíEÃç…dœ, èï+‘blëÆá±Š®× $œã[òO ,¾ªº =EùWj‚ê3Ö+ÀDrîàÄâ«*]™©°Âä0;8Jih v=EÃ á·„é ’ã’V°âÌ ôG&ìå}ùF\Ï.}ú™¥óæÏ¨Èω‹‹›1cƉ¤ËEQ@Ùt•tú:ŸI”LâÊ»ªë=@Z’ap`,Êšs¾Òjt† 1iív³ëàš4·@1I!qÓC¥2e‡=É’p‘åYÚ¢êôÓf­#PUXXv»]ŠV§ç”ÆGy¦å«tVÍÏ[w-zj¶E“ú†qÚØ8»Ý>bĈ1cÆÀmE½óÖ;Á¡Áãöþ3ùcÇÇÇ:tH£ÑÌž=ÛÃÃC¯×/Z´H.“~óÍ»}ØÞÝ;u:OÔ i#zîÛ±Ce°õ‰¥'Q×ÎüYd•{òÒ®_³áhâ¼§,·R»îÂA(â/]8ó§-;œ$é?ml·\¤y‰¹9–°x壿ª<ƒW´› »’îÙbÝžÔCtº(‚Ç,¹°§D,#8íî"•Þ‚#|]z+í0 ¦¦ÆÃ£.RÚ=Ê­úHe¯‰Ê+{ ƒü|›?3‚N'’sƒb”Pž£6àÙÇKÌ'ó/Vcf.a€€›Ÿhpb–j*}G{\?^îî).É2xJØì A^†\µ6HTQ`é5Þ/yKºÒ]gÂìlK­­Gœ[-ð#ÂÎÛñõ–fõè34.&Ø®;Ì ®gp­"muUßñ¯ç eømPReœ1iСcg꺨Ø{÷ì5Û]Ñ^ÂŒÜR¢òªÜ/N{£Übµ…yKÂË16§®õËZ½zµN§Ã¤Aë$LNžµ‡´ØÃãÝ-Z»ËA¨‹M¸÷‹”WUÛÇ>ÁaSFµ]á#ÊlËH®®,4»…ÉKo¨£‡zc´ß¤€‹¿å»xl‹ªÌ5„ŹÑ%åççûùù€Z­¹å¥5ˆ]' ìe¨®’FqXïÔ#'âDZQµZ½}ûöÂÂBFc±X|||nßúûŠ¿]>}œí1ąРÿêêš_|Q(@FFÆÕ«W33Ò-¤xØ X‡Eg0šÓR¯ºË <ÅüYÓ}¼<Ò32ªrnZaSG䱉jUMiI‘B&¿võÚËžÐËãjjº¹¬<ËäR 9Î%Mš4¡­é:äò®™y_Øl6‡Ã¡WYq'Éc6£ÓaÃ%”*;p"EÆa‘8eÖ9\6Âå ,[Eº:ëBoO$IP•éV®!°‡üæñ2Tx xB Ìf3ý³hÊÍNñå‹Öî°á$AÕVXÝ}fݤ±;l8‰S&ÝaÁ)ŠÂ¤ËA¨skóÓ Þ=d•zøÆeYÎú”&r8òÒMO¡Ô[T•V]vËÁã³Hñ ¦Ö*½87“ª¤þ2¡»À\ªÍÏÐÛlˆO´R—_›sU#P^ü†ÚmDdl/…Xäãï.‘ûK]ÊÚ§ßÀÞñ ¥™\Ú»W¥Br!R¨²ÇÄöswS€X,V(Ý|Ü”nnо—d]Cd!Ãâ"”Bôêô “*óÓËj­Áal •Ëåµ3Q6+$Zti{ùˆÑšBMYj Áåö›(»t ™… €rØ`« ¹ î8ˆtèÌWÿ,køWDyìØ‰"ÊÂþš'Y_M¶@&ÆOœÎxîïCÓS`úì wöbžü:{hŸ¹{÷nðpXL˜óTNfÚ‘}¿÷ˆÛè¹™2eŠR©äñùF­öòõ¼ùógé¶ltáŸÇAQåp€ËvUk­,Žïû³×¸inJEØq 8lŒ‹±:ð‰3æôsŸ˜ËtŒ5[€ˆpÖUAÝýE5¬®R áER•zð)’ñëåæ×àò€~^ôAôH_¨oõ××ÝüÅÔí~wѵ£åÃ}ª®WÆÝ_D«ô—Q$å©ôŒ¤-ÆŽÒ6Ô§·…[]öØÏ“>àðXÐC 1"ú*ÜIÚ­dÏáÞàÛËÝÅÐFú×Ⱦà¦yûî↎nø[EôîÑà#ƒÔÃKêáÃÆÔ½ú"ûDö€ÃÇ4¼ü¶2@Y¨{¤û”7Ü€…¡r/~ö±ÊÊë&ÀØ\”N õ½Õ÷[NÒá Z–ZÎå¡Õ¹Ú«N²×p·«» 8|Ì+T5Ø H’ܺuëâÅ‹EQ‹5`ä˜#'†aX’$IÇAá8ND“ï:=Žã¾}úôqPÿzkåO»O@tttdd$ÝFQŽã8^7…„ ˆ”””””ÇogKà8NÝx€‡ñ™ ­¥Ñs’zùÂÛo½ã-ãÿ±éƒƒUqú¤a}—¼òþŸ»¯»„°ÿ{Õ³ý†Oü~Ã:‹©±»³˜Í+^{ó‡MëG î»äå÷Ìv¼Q‚mÛ~ðâã/-]ðÛ‘Kõ'uª¢¥s&?·êƒ'>½â=‹‹8qâ„Á`0›7o6™L)Gþ=vâç_­™8vĶƒg»éÃݸ¼¦¦fË–-  {röL  ¨=›¾)Ð;`ÆŒwåóûöíËËËktòµ×^³¨Kþ8xnƼ…bv“¶³ÙüÝwßÕäò…Ñ}ÜkÝ$Z—Ë5eÊ”+W®lذaîÜNlxd qçõ<ÕK¯ÎŸ?mØW¿'Ÿ»–5up¯ß¾ýßñ 7³÷'U¤ùjÝ÷P˜zéËï~~þ_Ÿ=ÿÜ¢üïF™p¹œYSƘM6_ÿmë×¼»rydDpÃ!½†lÿíûéO,{éé¹î§OnýúËŸ÷˪ù½<õЄÉO=åéÙe2I’Ï>û,Iþ%YüØU¯¿–•vöµ¿ÿcê¨SRQ›M’î0{xxôïßÿo¿õ¢gS2êÆ9Õ9§—ýë—·ÞzËÇǧyYÀŒ3Î;÷æ›oŽ5ê7Þxã7Øl6Žã›¾Ýôâ /Ù¤5f]¼xAY³f5:/‰æÌ™óæ›oîÙ³ç•/º#µOL”øü‡6g«ê-l6;&&F¯×33Â’Ú¢+i…š ßþOàJ9M¿ü¼ƒÈ©6€'‡…rê¢V* ³÷ä°LŠ ßÈ׎íš;{nV­Ã/ ŒÄ-y÷¸Òtâ/ßý—2×,[0¯¤¢2ÊuEyrX,¶;EQºò;f,R•U©¯..ÜðíºðÈþONŠ!]q· évæSã{Q.í·kr’lþãô³GÐ_¡¥ÑI§C«ÕÚl÷\zÔn·¿úê«\.7qþ¬ÿ|òÉè £ëspØmzÎb±€ÓnÓét:Þjµ»pœnè;N­VK’M«ŽÃÍáUÿà?Zk2è(’4›ŒZ­Vo06\«Òn³êt:Ng±X6p—ƒ6ƒ  H‹Ù¤ÓjõzƒÓU¿"&i6t:½Él¥SÒÕ9§Ý¦×éôzƒó1[³ás²÷Ð¥5_´bÅŠ÷ßÿïĸ }Û­Ò[§ïÁa¡—Ê4ºòº]Ìc#|B¼¤WÊu†šl—ÓÜ(ÃŒÜR½ÉÊ"t÷.7÷¥_ÖþK{+½¦¢æNÀç°éRøbE¿1ÓÀËÂIê|ò‰]ûOÍŸØßÌ‘%.\úü¢ùeU$Ò-C#êf ¯n.vIIIP ÿõË®\ËJ˜3_lÏ¿RÁ%ô)))‰‰‰~~~ §Ž{îå×.£sFZ+ò–®x£Gt”·w}¦¿ýö[^^^BB‡Ãùî»ïFŽIQÔüEË7¬_×324((hìØ±¯½öšÕh*É»tàÏ#ñ‘¾sfÍÊ×:j+Jÿܵ͊#ÉçÏ;wN$‰Å⨨(ç¯Úˆ^¯ÿúë¯ýýý—-}ºàÆùM›6ËǽôÌS‡÷ïøýÐÙÒÌK¯¬xáäµâÑcÇ ¹ÈÉÝ›—?¿âf‘ʨ­ùmó:³ ­(+½páBbb¢©}î圚rö̆ßö«Ër_}qéÞS7FO˜,á!;6~:oéJ3‰ý¾á«'—,½víÚ‚ Šn$-Z´$­TrûúÍ{“&>ìz Ýz˜T*EQ´¸¸øôù…‡§Ÿ§‡673OëòUjôú'Ÿ~.È[~ój:p<” ©››ÛØ)‰ƒô-ÉÎÕY0¡@à'×íY^krɤJ//¯€€z/èõú <"b» =Ââããƒzôíß;"5å¢VOüýíQÁžV fǰ1gÏIä9MW¯ß(­Ò?½l¹¿W÷e¡ç4ëõzê6§OŸ>wöì¿WÌAdÑë_|ûÉ?‹uÖU«V!²uëVŠ¢ÎíÛ(d³¢‡LÕ˜ÙI;·¿AÝÉ´iÓà£>Úºuë»ï¾KŸ¤sØ´iS}‚/wŸ¦HGFúÍ­_ÁBÑU«ÿïð‰3i7¯—\¸pfΜIÝKðÏߟ3sÊ¢ç^¹žSJQTÚõÔŒ‚¬¬ôÄY“PLpèh²º -Ò[ÖsÌt½§(ÊX‘ºaÆU«VÀú¯ÿï­Wž;ŸUFç™›y=;;;;ûÙåó”ýÓÖƒºòÂq¯¡#t.bëæÿÀ+¯¼BQÔŒ¾…²ÒA¤_;„ è‹ÿüén Ijkk ].Wgò¸pèdYüì …pçOß–^wî‘4pô´‘q9—NJ¹ùçùœiC£›Ê™4iÒÂ… Ÿ~úé{”€ öÂéÙ«÷¤é'ÞóÓ·³§N=nÖÖƒ—š¼¤!¾¾¾¬þhÇžƒ?oX'ÿX7~è ßŽ^2[H·Nm~…®¸ÚåΗpY öé÷ÜsÏÑEýùg_¬ÿõè©dºß=åÀ–飇ûÇaƒ‰ Çí*µÉ™§2+Ù,)†bü¿º%NÞ,Çí¶?ÿ¿_wœ4h ¦+hÑT†àžã™þ1ÃæO‚[ÍsÎnô5[ìõìÒùeÿúý){R¿ IDATßX1¿¹¾ÖúúÉݰnçkeI¾ßqàlÒ™Cû·‡zqlý`! RUæç·æN¾úöwƒÙúÆÊ¥þ~žô¸‰|ä‚R£Ëâ"`óºï;q(Š1¼¿”ƒ³úÍc2àÛ;Ë«5o®\êOç¦`A ¾'ME8*ëKêÆâò½òÆþóÉ·Ÿ½¥ð om̸wGÒØg †äääsçΖ·¿Ú|ñâ¹¾ÊÜÜÜ‚‚HMM­¬¬€q3ŸŒðÍ-wΘ0¤QW®\Q©T””D÷îEQtyyyƒNP?¸réÂù~üÕ¥Ô*µÎÓ/lö²ç‚=åƒz”W~ôÏ7^ük*ŒÝn?vìètºäää†åΟ:(ꇭ;Kò2(ŠÊËËóíóÿù¯*ùòëulÝ|æjù€þ´2Йƒ{jo­\¹òÔùKs&äsÙ?ü~ çÆ%Ú0¥_àëo¾l¨®ù~ÓÏgŽž«(?]¿®G ÷êwÿ¹sÇ[~?6fÜÐ6ø#00ÜEÝ,0¥RIÇÍÚíöüü|¯ïª©©©®®¦è”þõRŠ!ô‡ÏVaw¾IoݺUBYßy“žž'00.B"‘EàÕÕ*Þ@RˆX*÷ññÂP¨®,¯ÕØj………III‡ƒËå±X,‰DÒ·oßmÛ¶-\¸ðŽ q\8V˜GDQœ&bTèsfíÐÇiú߃ºlÙ2‡³lÙ²øøx›Í¶nݺíÛ·ÛívÒiÙ¿óŸÙVQkD[Ëß²Y°ö[,«¤ oçÑ£q;“$I«Õêt:Û¶ñ0`Æf?ødë{Áb±øü{î‘Üx09Ý«šÚ(·¨ÍÚív’$ 4wîÜ~ø!åð´Jc ÐµïŸyH ï‹XÌp;z„¡I×f)Šr¹\&“ÉݽӖloDMMM{ŒètÁÖuÛjì!i¾¨õ—Ûø¨ “ûøHèe'H/o——·kPŠ}i–¦{€X,–@ è {š ;vw)µžz³›´¤Å?„p8¥R‰k¶oßîãã3zôàßÝYÈbÇÇ÷ïÕS ôæîŒ,[âþ~ Ôdp†€º}Ù`Õ*Xµ ||€¢`Éøù禯JKƒkðôB°YaëV?‚¬örý:ôíû`ÆwÝTcÌÃX>yòdÉd„mßôÔ²gÞ°ÇûP¦Ã¿ü ¡ý`år0ÔƒÀ‘Žƒªœ¹Ï_)oåÀ‰ 0n¸„‡Ãg€à¥PZ >>à°Âáý`eCT(|øL™Ï>Gö€ƒ³¦r§JJÚæVŠÙƒ­ûjìè 7;tÈ.ØÐ¸_þî#Ò ûŒššT¸¥‡c[`ðPòÀÆMðÒ*H[õWÊô[0f,lÛ ï¼ @ô@$áx*ˆDÀåÂïßAÈPØaÿ0–.€”퀇€·öœ‚Ä;vø„  @­öŽubLc2¡wÝ|€|Ú_?¿9öÎ6äaA[·˜c3´6Ò€pÂ[À½'¨+Àz.ñŸP” xÖ¥¬)ƒäpã TUýu9‚À”ðÝçPPPe„„Rà<, d”Cy>ð˜<¥‰ÒI±‘Æ:††Ï †amÛAÇÅÄôiÃ<»5­­Í=1¬ýتáµWaÜ8øïÇPU b)ôô…Oþ Yyš qq€a àH Ú,ÐjA¡€‹áÚ5@1Xö¿0¾þ€„qsàâxåmø÷ øö7 qÀÁ(%%¥Éã2 ²»Àáp.›ÆÐæ4ž9M„Ñh´X,~~wÌð:y._ÏïÍÒÒvQ&S›½/îžk‚»\8Ñ¡K¹šL&wwŽ,±i­Ï;ÆŽmWKº:Z=$IjÔÕ.—³cJ×jµ%¥å‰³çtLqNÓÊÄq¼¼¼¼ƒM¹ ;¨èã†H£3 «±;· #½[LÙé$A´ÚmÚ,ÆÊ*µDéæ.—êõz™LF¸ì:£ÝM)kÍå.ÜÕuâÒ:€¦ûf›¹áp8Ng½)q·¢¡?¢(Š¢(½3T“ º´yp‹æ×?EGG^I9ßgôÔ«IGÌž¶wG´R™}¦Ó餗Znoo着.ý<ñù|.—«×ë›I#‰"##;̤FtGA>@0V)ïƒêàæµŒcÇö ôé²}ÿeÜjܾóðøéSÝ¥Âv°ôQ€Ù¥¯sè•ÕFÜ×s’FÊëe \6j³»wØŒËâòå"È-è*-¦.H'ÏK½xÙîø«bœ––vôèÑN´§+éÝ5uÛJŸY¯ÉzY@¾±Y)gvïÞ·mûñ!Ãã{òÌD»*#érV»ÙÛ½éÐÀâüAäääàà`AæÌ™S­ªŽÄÉûwØl¶Å‹+Š?üpâĉiUg‘éݽê´-úÌ4R YÊ/Z¼Ðîpbl‡-˜?l\B¢ï–[èuºÐĉ}}}sssGŒÑ»wïÊÊÊÿmü.nð€K—.Y,–ØØXooo pÛöm›Õv¶Y§š<ÿù>AìÖÝâ¬?ÓÝæ½žZpMÖƒ²0 ÎÔ Š"§fÞ>tè:@¾¾-Ù*“Éd2ŸÏ§(*&&Æf³ÅÄĨÕj(/)Û·çÈØ³jíŽ#»÷Yµ¤cÌë Ô µË곞ƒ%Z€ ø@Ý$£Ví?ó à8Úž%t-ºÄ49’¢¬·WId±P‰›ûì' Hãìêε­½iä6ë¥HŸÜ[ÕÕÄYomb¤wÝãß_»ãLݦ£•i6›Fc^^ÞðáÃoݺÅçó333ã#7ï=òý/»ûDù 'ŒúÓ†!ÈøilaÇÓdƒ“>y/Ýv0·mà]/T7´CghÇÍÚl¶¬¬ºË˜ñÌ6ç^u×»ÅYO{«´Q¡#Ý8×ho8í ÕPÕ¼ëk1ÁcB—¨Í24#³ú m#õ¶¡\[“•F£ù«?¢ªŠËáäa˜:úÞßÛíèÑ£ýúõóðhºW¯´´4333!!á¾ò|$¹§2Æ—Ö¿Ãõ!Òd‚†ç[Ÿ€~Y¶U‚&l2AW¦¡Ã¤ë…Ú¤l¦•zþË•qØpþ¤¦Á”ùô‰“'Oæddzûû÷ TMN“yÎbú•{¯å•ÞzýõWÔjuß¾}÷íÛ'—ËNç»o½å4/qâïìsoÞÓK]Õ9ûŽœ«V뎀[xôhã©(%ßfµìúý7‡·™M¢Ž¼©.Ë=ãf9òÇmt:ÝáÇíön¼:KRRRaaag[ñ€Ü­À†-Ï£™V@`` ]™>qôέ[vì;bw¸Æ ìýý÷ßçU€Ÿ¿ËP½ióV‰{¸¿¿¿X, €ÑÓ¦g<°ió/•jäIc÷oû)9­–Ž6ahÜ7ër¹è%6lØð$AÂÞ=¿ËåoŠä‡Œ9¤Riý~ïÀ™3g­™Ð¶4ô™ëÖ­“J¥ÕÕÕ‡ÇñáÇ5 ¸\®——WûÙж4é$;Òs>ðþ™›6mzæfUËûæžÑy<Ï`äP+<|ÐþýoF³}fiaQ‹Å²bÅŠøøxP«Õ«W¯¦·C¤7¤H’@QT¡Päææøøø Š PŸ†¢(ú½\]Uùå7ëý}mNrÙòeʇ›(ÄåráóùN§³¬¬¬OŸn¹Ô½Æ<¡£¬çŒ‘åƒÑ\tžD,DŽQ*~bp Z×3<<Üáp4“—P(Œ‹‹[¶l™J¥âp8.‹zÓ¿(Êw™7&jÝ{ø|¶oô€HÉÉC‡r²³žòé%ó×}õ_—ÝkÈŽ£b׎Þîßà^‹ž]ê©Üwà Íj‡‡SfTT”··wQQÑåË—¥Ri`` Ñh|˜ » »ˆÚf˜±#in˜T"’ˆ¹yÛÌù0jþœæeIc4wîܹsçNµZ}ýrZÿISW¬X‰kK÷m?´øµ×V¾ü’*/ bÇOþÛŠ•¡¾ü²¼Ì ? d^<Þ7îÍ÷>Y¸paO_åÉ#{+ª"1ÓPG3sS:fÚJ7mz¸§2-Kmmå¹óG½‘2§wLxxxk²“J¥‹-zã7bccù\¶Él#I'I©«5Xp§ƒDP0Yl$I8Ž‹I”aýž]¾„Þ9[ÌB ²²2éfÑÔÙ‹£BÜôšÚ‡¿IzåØÉ¸:@œŒÏìHîÙšïß¿¿ªúz~Á•ó–-oÍâH‹¥°°pûöísç΀žñq{vìÞpé\PÏãûmݺ-‰DbÊÌL³Þ*Þ¸¡Bá>1¡ïöýGËò<Š‹K®]»V\\ |–zæDÖÕKb¹»»§çCÞ¡H$JMMµÛíR©ôXâ©ùÁÌv­Ö2>³#¹gß,Muuµ——W£?ÉCöÍvÆ3ù|~ýûÞår¹\.èn}³õ´¨½vç÷Í2<-¬6âééù¼)m6›õ6´,aºÝR M‚Ó~xä`ÄùpOŸ‰ H£%˜›˜˜Ø\~¥×Db CM&‚ "Q ïfò•Á !!!B¡z÷îÅápbbcg,X0iòÔàpï¥Ï­´Õæ€_tôâ%K^zyé¡ßvüyô¬¦¶VUYá2¢ûÄÌ]ô -˪¼ÔÝgKäPQQ¡Õjg=±`Ú¼%3Ç÷ݱó@Ûü :Œ8»÷T¦F£Éɹ±ÿÀ/>H ·çª‡#”͘0äÔá“ôG‡ÃåÂ]†ê`!ˆEÁÄ,´¾èZÉæpÕ–H<üãYñò+/ÿíÅèá\Án÷Ô<÷i“«T*ƒÁ`³ÙnffáÂå I¢U=l6›Ãá´Øè}äaÄÙ¸gmvΜ9v»Ý™YÉ š4+aAkF™-Kyyy~~~xxìÂéñ2©ú÷ð]÷Ý&ž{trrryyyFFFVV–V«-)))//ONNÀ/›ÖG¾pÑüâÔ3Öý'q0pPyy¹J¥¢C[ý|ýý?ÿüs Ãt:]ˆ§tÛ÷߉IJ„©Ó[´J¡PܸqÃét*•ÊG{˜¤y·Ù½@(Š*..V(tG I’&Ó_ã:N&“5fàñx]|M Fã™,«þH’¤ÇQ0 £kÚÝŽ‡éÎé‚Û104I ír¹üý#¿ -ËÇÆsv ˜=§»éô‡Ù]èä=§:¦ÁÙ-h< ¬5þ³ëûXz=¾ÓtŒ1 @k´7¹…VÃí@ºÝšMÂårÛq”[ná¹gtÞ–-[èØT‹Å²páƒû÷ÏLLìŽíF£‘ ˆƒ†„„DGGóù|×ÙF= L-ôñ¡¹væôÏM™ú›íöÍ×ßÄ8©©©-fgÔkŠŠŠT5ò>ëŠ:N:uéÒ¥ú“×’¯ÝW&M²qãÆÝ»wëtºÓ§OòÉ'çÏŸø<;‘¶rtLk³‹Óœ2µZ§^Oöë7Ö…§;u’^|½l&Ão[·egeýúÃ×¹yù¤ËY\˜_R¦¢²³³5ÕE¥«)?/Og²€QS“““«7Y5Íš5kr +{ö왟“‘—›«5YÍf³“rêõúв’¢‚¼JµìCnnN™ª–^e¯5øûû»¹¹ ³ÙLoÀÀÐÅin ‰X(—еšÊÄž~‘CǺ¹¹Ý3LÇ „à êùäò|½½ÎÝ“–[|ýÜÁäô²Ÿ~ÚrñFNÚ¥ã_­ßY~«`ë¯{Ì5¥ެ®®Ú¹ïO½Éb³Ù F+\Ë,*/+غu—ËåJJNr:}òeiyÕÆõßS¾ý·me•ªý¿n:{öl+ïÐ××7,,ÌÃÃÃn· …B…Bqÿ¿R— Í[†ŒÛìÊ47ž) …¾ªúÜ+Ž×V¿çççKŸ—ËeM¦Ëå ãG–äeìÙ}ÐâBóni¦Lž0sîé)güÇŽ;lÌ?oÁèq“Q\ŸWš•••‘‘YQTàãé8 oÄô3.Eår¹H$òððˆŒŽ5j¤»Bàpº¶xÜèQ#Çñ÷÷°>]Ó¥£—hîé3+++“Ïûé篼½ûð‰­ÉK«Õýy1kôÄ„Á•eBÔèͪ’,±G0ðP@ù( à)ÄýüóÏ/˜7›Ãa$UTõ êá"ôgc!6«Ùît©Š²ïë&¹\.Ç“Éê^(©ö.½-o“´“scÜf—åžíÏ<ó ‚ :C,pÞ“O.kM^b‘ЋmÿñûMJŸÀþ=Bƒ=¹‡öýÜgLOX÷uò7t:V«­­­Õëõ˜Ì#X«ûñ‡|Âz…F„ɸIW ‚<ùõ .]ºTÿ¿Íf3›Íiéã‡ôݺå'œÍ‹´vÇh´´4‚ ¼½½•Jåh^7u›Ì ÇcE k´Ûl6@@QT£æeIIiG[ Gì)­5QËøé C}$÷JÖh<³á²â$I^±b0DŠt—5ÚÛ{ŸLfl³ ÒÂJø|>Ÿn…6”"ÝÔ)âœ0Íf³³Ø÷>j¤ÖàŒã9»]…–QÎãÆƒ¬Ñ®Óé ™NÚöeaB‘è¾dÙ$q5Yñé¢ÐÐÁ……EmaUÇcƒè X¶­³Í`dÉt¤ÁÚCmæë^ž2¾ù³[:OßРŠÂ’ö-ƒ¢VNiÎgv®,™—Bס(*¿¦-(ˆð”@^u—^ôà^¤ë¬Ð[.h§ü)ŠŠðlz>@{ú´F™]¤=–á;„ºéhJ§(¤+Èev%ÚE™ÐÍÅ (•.¢Iš.eÌcN{)³.w¤Û‹ÚíImïü ÆmvZˆhHè¡În*NúÝ[Õæž¤kj’¡KѾʄn.Nh ž‡—#H†ÖÓîÊ„î/NšF.´áÉfhXÃh’¡•´o;óŽ’ºyŸP“´ÑÖ¥È45»á3ihÏù8φ0O0C;Ñ¡;Ýž8Ö‘e20tK:z/0Fœ ­¡vécÄÉÀÐ"³&EuïY íMgîlˈ“á^tòžÓŒ8» Ìú]Îß ž'ÃÝt¾2¡ÁP'M—P&0¶ wÒU” Œ8Ð…” Œ8nÓµ” ÌP'tAeÒ0âdxÌé¢ÊFœ 7]W™Àˆ“á1¦K+q2<®tue‡ÀðXÒ ” Ìh ÃãG÷P&ÜCœŒVUº2ñœ ÝI™pgBÃÿ1º™2i˜[†Gžn©L¦µÉðÈÓqëͶ Œ;f%è®@7ó™t;ónÅ2;þêÔúó ]–úfb‚Þ×ó•N>=mЧGo¾0,\cu"VóÍZëòa=æn<¾eéè_/ŒòU¹:;µ1%ïÕa¡¹5FŒ…²0ö+ãú°)—E¤—®_<ú‡”‚1!ò“ê¡AÊ×w]Œ ññzÈ6¿<>Ú‡ÇÆž`q—Øw³¬¿Ÿìý}—*L.(Ó™/Jd¿.òä/)y5†Z³}pϰ‰þBŸ¿óüÍÙý‚¢?3*?Lˆœ÷ýé/—Œß¸çê‚Q‘ïÎ|sTXR••‹Š‘‘Þ×+L§³Jl.œ/~9opRrÖïÙ•ò#34 ‚tÜ–çÝŽ|摬Šr‘+Åùå•a¾R6q4-qPD±Æä#@¹Î"à`%SUµþígãÃܪԆµg²-<ÈC<À_öå±›žr„…ˆyìMIéa>î;¯|…DHalo)D¯µQ)俍tN¾1)ÅØ¾nòz3>Ý{~o¹s×òžB6|œØ×à$8:ª·_f¥n×õâÓyåZ’70"È ñþ'oä?1(8½Xýé¡oΈϯ1ØÍö\L)T¡òÑÌYùä0[wÜÈ<Àå­,B"‘¼ûî»dã#E Ê$\Î)Å«Ÿq1£´Êäô°E|žÝár$ˆ”ƒ)duúÑ“¥zg€˜# 1 396‚ˆ¹l6†Ùì ÀEQऀž%ò¯™qû.ç¥U™aÕ—h#)ò.3H’üîÈå éºYq¡Pªw\É,þìTn~•ÞE‚“%ºwâÞ8š³4Æ?½RW¢wJ82‰X§7€ àöKzû…ÜÃûô÷µÅøHÑÌFCEÑþ­þ !- ¯•¾‘¢¨'N|ñÅ­IühÓ‚2QIÉ(Vݪ¸\ëÈ.ªÜ’Y½h@л{.—k-ÿ=ž¹pPØüb>›E”ÇàRzÑ‘JËÌh·_R²=xØ'§³ç ÿåÜM eïL-á}ðfi¿·´r¯Løîî«bƒËªÕ8AòÙX­Ùî-fUéd|N‘Úè.â×AA”§Œ$ˆ_“n¼°3^ßšÔ»GÐä0YJ‰öÛ”ü>21‹Ü{>kãõ’›E·ÊÏãIDATVžÈÊÑ:Ž^ÊM·óûx.ßzAÌcW­ì&Þ‘Zäp¿\)Ù3¨]ÙnJ+»uÔŸùñÇ•J¥B¡øñÇé“+V¬àñx Óóx¼+VÜ+ÛqãÆ­ZµêîÄk×® …Ë—/§³Ú¹s§···X,~ûí·é”+W®kÖ¬Y²d‰P(|ï½÷îÎAÅ‹‹D¢õë×?ØïÓa4]ѯ4ð‘‹^ÕëXZî‰"]ÇöÑu" Z옭o6:¨ÿ¨P(Ž;&LÐjµ‚8p !!ÅbQõᇮY³Æh4bær¹µ3}l”ØÍÍíØ±c$Iöïߟ¢(µZ (Š ȹsç¼¼¼"##OŸ>íããk6›ï.ñÊ•+0yòdúò.K =@•:ó›{.vŒ) Ý¡P˜ŸŸ_SSCDÄn·óx¼»SN:µþøÓO?MNNv:ƒn±ˆæ“$¹oß¾)S¦°XuM¡aÆÑçGŒ‹å~KìRtû¸Y†¶â¾F2_yå•ØØØ¥K—ÒI’Ÿþù„ àóÏ?¿ûªeË– :tñâÅ­)¢Qâ>ø`ذa³fÍb³Ù°qãÆ•+WΘ1šmÄÞ]âš5köìÙóÙgŸµòN;‹¦k³}VÿÞñ¦<¶¤­žßÙ&t“ƒ½{÷¾óÎ;ÙÙÙvy7§iÚgîY< ƒí``hAD"Ñ÷ßßÙ†tLm– ›8̇wwÝÅaBó£&U…fúÀ®µ›uŽúó%75¸³ñ #EÕ…†Ê#ŽSù—kLZ´D}þæj«Ý‚7üÊi#J3´¥Z«Á™¹æîkëów9ˆÒ mY¶Þn#š,¥ÉË[Iyyùµk×®]»V[[KŸ)+++**:wî\3={EÅeNÒtñÎ@†.kõêÕwŸÕétðç/‰"½eRÖ…:µ]¦`g%WcbéĹvEFmIºø‘„ Iåv„…’é"].2yG¡Eñu¥†ÂtƒÌKˆ±FïZ}Á'ÞO(@o̰šœJ? ÆFkJMBWUdÔ”›¥î|„c5:WU¶†/f\®©­vâüøYÓ?ÞK•Za©4ðPSíô“ÜlµZéã ¾n7Õúµ(‹M¸2.kìµ–ê ;ýme¡$McÖ;T…ÆìË5_yYªu¹{`ržo„,°·‚NÉ—pDr.…SÚ‡ÀCh¬0ªŠ¬—–öuçNФn¥ªn•91\([.ƒô³š›Ço¹E*M…UµåæKûKÜ‚%ÙgÊŽºŠÀÞ½{é»Ý~åÊ•+W®¨ÕêCûwõŠc›r °°°gÏž †@A¥1:*äàžCôUîþ¡HM~µÙ™ç©Pw?‘ùXr}IVÊñRWÁ6ì=v¥Mþ„O+«²ü1‡Óô| †6§9e¢Ë?XpåtmD9hò4ª³Ýh¢¿ ’ˆd\¾¤®¥:Â?¢§T[¤ÉH©ŒrXmµÓewéu® ¨ºP¸É“' ú˜+å 9äÍTsÏ>b¡ŸÜ¡2T}{Ô9˜Ñ¾ƒg‡¸ù‰€Ëe BxZn鳯j Å8,6·n «ºÈXUl‰ŸèÒZʲõ&­•t8P&Ur¥¾Ò…—dèƒû((‡«"C­×8]F“Ã…¸{ó½{¹@Ê®«²z…ˆ1¬Î«Ïœ9“>J¥‹/^¼xqxx¸É‰†øûDÇ A¸\®P(¤“§_Ê/*5ë‹è‚L˜žpòàa‚¢rËôÃöŽŠhRÑ—d×8mFåù0¹ŽgÍš5………­IYZZ:dÈ.—;tèÐ[·nÝoA*•ŠÃáTVÖ½Íu:Ý‚ $‰‡‡ÇÚµk`ýúõ>>>wGðÞ+²÷ĉ^^^^^^§OŸnÍù®@ ÑyÞ½Üÿ¿½3 ‹êH÷ø{útKÓÝ@·ì›(qCLˆ ŽÁјq‚×…Ü„¨AcM&s½ÏÄÜg¢ó˜ñzÑháÆ¸`XQT‚€ qßQQ j¢@w³ôzΩûáHOßf±Ù¨ßŸ>ÕuªÞÂúwUzO½o¹YZr€¡‘R¡Q)¨vs>ºÓp÷Ò³†gj¡„#¹E™¿Û¹ñA¥S*t¥ŽÍ–››«R©ôwyMs qe?Oz]òϺ‘’JÉdZŠB”†¦tLSuÓë/–mžSíÆÏpYs ÔJ]ãS5ˆøp)ë÷Ê›u¤/p‘ÇœÊÆFZ«¦åÕJppq1£âúI)ŒhÝ$Ó(Zh}:Í~hjjJIIIII©¨¨ë&9tðPzꋯ$<æð/ÉEEQ²úº&…Ro*iaãëa]þðñìé¾~ØŸ¸ÿàøiÓÙ[fϘR_%•ËåjÕ¿ò êêêÜÝÝMɬP(‚ƒƒ£££»ZQrr2EQÉÉÉúÒAEEEYYÙ£G 66öرc ô}¢ƒZ1LüüóÏ÷íÛ·o߾͛7›’n´¿½SQQ!¯U•ž«æp@€4A€p‚aЋ<148$1ˆ €¦’ËA1 pH"p¡'w‡a‡O+˯=×—¯SÓJ™R |çÐú ýåc1Tk4ƒH’ƒÒ»q"šÍÀ!€¦‡$‡C0 C[k½â™J¥Ô ÅkÛ4…<§Ø¹¾"½‘4M3 $Ir8J§‚C’„@Ñ4»ë†¢‡`ýQZoG4Í$IS‚Ë%ð·Ð4Å0Àå½£½¼¼úôÿ¸sLœÊêG!„Pbbâ¦M›B;v숌Œ$"::zÿþýjõ‹•ˆP(”J¥‰D&“¹¹¹µ´´‘žž¾cÇŽ5kÖ¤¦¦®[·®¹¹9::zÛ¶mADEE8p`ãÆ_ýõôéÓ§OŸ^TTtéÒ%‰DR©T,ë™7oÞÓ§OCCC£¢¢<<< ‰D‰d×®]ï½÷ž>Ïç+ °±±ÑÙIº9С2ûÙŽf™¦á¹v”O?=„`´ôãÒþH“‡°jì„A¡L0ئïÈ9–ý9¡PXUU%‹ •iè°Ú®×«£££ŸŸ_III``à“'O<<<Š‹‹½¼¼Ú*“¦é .¤¤¤äçç—––IQTvvöêÕ«õžƒ08•i.ç‰$ý&KàŒ GûÙ›ƒ,–ÞÚÆ ÓËÞxão¿ýV£ÑìܹsΜ9mó³^¯EÑô‹½®Y³f;¶¥¥%))éùóç|>¿¶¶öèÑ£ðÎ;ïÄÆÆÖÕÕÉåò¸¸8 I2((è£>ª¬¬4*™ g4ÞLœ81'''''Ç×××”ts ÃE]M³¶°¿_Òç @Ð1³tî ß}÷ݲe˶oßþꫯ&%%±‰†«x½&%%]¸p!**êË/¿Ü»wïÚµkGmii¹eËhZK$’­[·Þ˦5êûᅢA~ûöí+V¬€#GŽt’nVt8›NNNýo¦ßèO¿ŸAä°j&˜ËlƒÁ‚•9LégGY<`v¬L Æyù»&•••ÇŽÓjµ|>ŸÝ¯£(jíÚµ¬£–R©\°`AYYYyy9h[ŽM}ë+\GZªT*öüí`k±´¶ÿàƒ¥ )))R©4,,lìØ±mó+•J’$-,,ºÐVL+ƒâÍ’aÎËÇLOOO­VûÅ_ÄÄÄÄÄÄŒ3F§{áÓ#Äb±T*€;7omXÿinN>øøø¼öZ^òôôô$bíêÈÍ_íÒR ¼ÿþû<¯]Y€P(\²d‰éåcz|Žv?ÐåÙìÇÄB¡VÝRðë©“gÎ6«^¨´Y§[»~ý”)ÞçÎS©T …"%%ÅСt·¯]ÌHO?“W¨P¿&ÆáoNöØû÷ÿøë®ƒF_IÞ=žyìLÞ¹ §OŸ€êêê´´4`(ÍÕâsÇ2¯ß)ÃË™—2€æ‹óø]\öìÙÓI†Ž. ÓÙ ›®þF`ä7ktÉfvvv>xиCö¨=ÊËËkjjô—Û¶m€ 6ÄÇÇGGG#„Jý—5ïyL ¾qëZà$7Ðh4©©©_WWçìì<~üx©TJÓ´¾œkW¯þíûÃ÷K¯O÷÷y=4’¢ÃJãããŸ<¸>ÕÛ•g)Ú}4—A(>>!tþx¢‡Çè_ò.nüxþ –7¨©ÚÚZ˜7o^UU­k‰[õ§€Ðð›—ÏúOòþïÃÙí¶Ã’v¯:í^u é¨Û˜Ã0&Þn]àääÄžÁÕüýý322222¦M›Öö’Íœ——gccÓÕZzNÆÌÅ‹ÇÄİ“Éëå ÿ›5Ã×kÊd?—1SÙ úw/lmmI’är¹®®®†®!Þîöüú‡ÓÏ(iËK§~¦iQncüÒ3’¼„›?Yz$§ˆÿ¾ýæ;µV³08p|à¼ó'3._¸áàà|>ßÅÅåÉÃÊÄ>ö–!@\Áß¿úGW›†Ý0÷íÛ' ?üðCöÒèhÙ„„±Xl8ˆùùùäççûùùéÙMooïî7üýý ^CcÚ­·]JKKCCCCCCKJJÚ^B«G‘««k­í]>m$<<ôâ¨õÖ€ì&ÿÍßþs×WJïܸ|ëÖ­vóxúÎN>øCÈ»K×}ñYÌJ`´ÖÓB Öé”*í®];ó ®wµEÇÎc·lÙRXX€¸¸8½÷lddä¦M›NŸ>¨Ï™˜˜ˆŠŒŒÔ'æää¬Y³æøñãÝo¬_¿>""BihÌW_}Õ¶ÞîÀ¾îwèСZÛ ^>fêt:v­ØØØ(“Éd2ÙO?ýÄÁY±,¤¸ôÑý²»5å7@­Vk4`ÿä`¥ÔQ{ö|³ëÇL}QB>ÉáµµU 5÷Ù[ kQ*•à;{áÑÄ=¤ª†¦´°!n%‡Cž¹TòàjîksæO›é¾VõJÍm½öàùÒ÷CJ*êœGy©kÔ!A¯þ}†DFèP›%þòå˳³³Oœ8±|ùr6%>>~ÕªU™™™“'Oîau!!!¶¶¶í~Õ¶^=FùͶu£¥iúĉ+W®ì¡µÝ¡Ý9®á:S*•&µA§Ói”My§²³NœÉ9“Ÿ””tï޽¤¤¤ììl„PÍã²´Ô”ìœ_›5Z}±ªfùɬc'ÏäŸÊ=ËÞ¢ÿŠ­%''GŸrå|^II ûùqÙô´Ôœ3ùÍjŠM©,»š’œ“[¨c­U]@ìÉŽ½ˆ¡Ë¦À²Ô˜¤L™L¦?ã¬W°±±±°°xøðÁÐxnnmmãèhF®ãåå` £ôýr4É×·§^ZB( `Ú@[ñ/°,‡=Ufcc£µµ5P¥Õjõ1KLA ,|wQ÷ê•Ëåú£ ?÷? ÃP:ã—f ,Ë!Cw”™••UUU%—˽¼¼Äb1Ã0÷îÝ›;w®aNò±”WzGà"1#h'ŒÔ½ëÅ—nqGð.\à`ogJíÙÙÙaaa‡Љ‰aSΟ?¿`Á‚n4dˆe9”0Éo¶¾¾ÞhùìÙ³âââE‹¥¤¤Èåòúúú)S¦ðx<žîæƒ*†#ø`Å¿YŽàpK¯Y}±Uûîå¿/A…3G ô‰DX–CŒž>#mllœ0aÂâÅ‹ÙgR³~%9œ§ï·4É¡:b…ú­„JÛîíï¿~8ñÇý?'5´P7Éc7~ædEÕÕ>˜=3ö‹-VÖÜO7n’>¸š~4SÍãY-*n_ Љ‰±¶µ‰Ý¸yó•Â,…B¡T©ÖÆÅÅ}þçÛ¿.¸p3jcìÚ¨Åì;ïÃ,Ë¡G/<â ÔÑ––Înn‹—,£›ë¬­E@MGM×ɽ´µ[ä*ÿëçOÞ½SF«›ZTj™¼‘äYX‘RDr8€7;qA³|›eG~ÉÐ1ˆGŸ3 €ˆ$¸€h!Ÿ¨~.“=¼0,–`YI:ŒÏãñD¢áhU*UÛI/—˵··gÆwܘâs4nnnÓ&žÊ9U#Wñö";Þ´äóù\.÷âoÅcݳŽ×ñFÏôq³KË8þÊÔY|FÎÎÎ4M»»»Ó4=+xÎý‹g‹®–xúLt0éÇsØXŽ Ã899¹¸¸°—4MϘùúÙ™ªd#íFóñì­¿TG „†!¹ð”;ý~ÍÝúf,Ë!I7×™=D¿Îülc\/ËR[û4--­¥Y½â“uÎ6}½| Ö™ØËgh3û™!šj?‚uO°³µûdõ'ìç¾(ßõ²ƒ”)`YyR™óÃôºß߀@rÉ—gê=ðÂr8`’2E"QïºÑ±AÔ_y¥³‡C˜¶à¡rø`’2qøsËrXaêlVÙÒÜŸÞç …B(²²±±é·Í¬Éaˆ©ÊÔé´uÏŸö©)†œ;_ôVÈÛX™€e9\é£'@Ì­«WžÊÕÓ­ø¼êêww·Êû¥·±baŸoc °&‡3}òóùœ,ˆ¦NðL9š&kR]¹råú…³ÿ¬RZ·çÔŽi,ËaNŸŒ™OTáoOäàêlÓ¬PÜ¿rÁbÞòùsüM/ÁffØåpë ã̬I ô‘2yˆRk)‘WÕ¢âð,FŸX_qûñ„1£¬M,AQ”ýVÈÛí·öb:¡O”ùÆ›3’â‘àä5Þ~¤ÈÎÑ}G¤„,Zbocj|xhí£Ã¡¿‡6bº„©qMò†þ6ëææ®Oª}w¨¶ ÓCÒ;¯K ½ñs(µÓ똪ÌòòŠü‚ü>5ÅÄ0$ÙŽm†ú„ÁÙ­µñ˜~cpGéD½|™Š1Íl¶]ô½Ülû½Ù†1sLS¦\Ý:6²óó&{ñ4ʶ…ƒ9Ø€옠Ìâ"HNƒÐw`Úë`+êRéEEEóçÏïè[Ó){ C‰ö§BŒÂû`Abzˆ ÊT5Cu5<’BëAäqŸÅòò‡ù¹¿ªhrÒësƒ}í¾ýŸŸ¾@`k72""B¥Reffêtº„„„ú:™ÀT¢¹êFy½•ýè—ÎO>ðã³&Mх˽®L=FÚh70V÷ôÓ‹Ea0a‚2ÿ0œÜ`âD}‚ØcTÌú˜ÒËK~¯ïír%ÿdÓÝ‘KÖ}ê!Pïù.Q¡PÃ0MMM†X+æ,‹xmF`ÉÅ_«gù16.Vþ‘ þÜw 3¢]åt/Ž!¦0mi Ks9±•ePȼ?…ÕÕ<~tóòýr©@Ò¢V)í¬,jJEÅE63@Ì% ÐÿãUŸ(j·X*d2µª¹æñï½Üš.‚5†1[L:ÕÒö°I;{ªþÉñSy|±sàìÙ÷‹so–7´(ÕË–¼›•žQ§æOxÅÛð¼I/»ŒcÇž5£É“'ñ©¦g \¼§MñЧÍÃ`)½¼Ÿ™””´téÒÞ0 ƒÖ nO f¨‚c?c0æV&cŽ`eb0æV&cŽ`eb0æV&cŽ`eb0æV&cŽtèiРA·e}|ƒúx&މ†1¦Cv‰1Ó~pŸx0(@Ðqœ0ƒˆöµwñ±¬ŸíÆ qcÚŒùѾ2ýÇy÷³ÖþŒ}ˆDü ‘œ¾é ãIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/grant-perm-463.png0000644000175000017500000002517310024102556024363 0ustar frankiefrankie‰PNG  IHDRጜY?¨ pHYs  ÒÝ~ütIMEÔ  ¥Ss IDATxœíÝy| çðg²GöÈæ’‰ûˆ«Žˆ›q¥%ˆû.Õ¢uTK‰ŸºŠº*nJªAwUw‰£Ž*¡JäB!wö¾~lL&›Éî&’¥Ÿ÷ËËk÷™gžçû<;3ûÍìì,e4 8 §² @ŽàX£8äèŽ9:€cAŽàX£8äèŽ9:€cAŽàX£8¾5•Œúœ³ûv8râêÍ;‰Éϳåjg·r^4mÖ²mÇ>ýû5ô“¾é@KEQl‹„b™{¹ õ5éÜ£ß'£ûVòJ30x{qlTÆ7 8²¢Ï£ÇXÖ¬r…΃>ßrúiñ ÎÞŒÍVª³_&ß¼phúð ÔóëWvkòá'{¢ãK!ÜÒd4Í2$£Ñ¨Vd'ýsíǹcݳýñÛÞo¿X£bãå¿%•QŒvJ:8׿¼‹Ô«öœ_ß½î™ÅŠMY eŽâNŽÎî2ÿ0!Äó½Q]¨&²pÂøF丣79rVÁozÜ÷Òó}m*”bT%ìM\ëB1h_ð„yÓ–ש_#Føy«/y«ƒx[°žGÿmq ý¸m7[Û¥ Ñ)—32À¿²Ä™o*1Õ|ü׉ùSÇtlÕ¤¢§›3߉/{U¬Ú²cÈ´Å›“º"›M9[ ¶ÊÌË›óéÇnµ&3éUÉÛ—OïÑ¡YEog>_âæÝ¨MðŒð¨t]œÆÊY*\-ãîÑ/‡|è_É[âÌŠdÕê7;;"KoÌŽûcÆ'½ëV)ï,à‰ežMÚ…¬>ü/wÌ¥9qççNѦI]ow>'’ºVñoÜ÷ãïÂ7_‹Mµ£&ww„âÑ–ÅS>l×ħœ»Ï—º{¿×²óäùrµf5m}é‹T†]sãØbM„.˜úyKͦ×îͯDö&ë·"`ÅvO‰æ2!]'I¥ã¸û„•7¦è]Ý5ø›ˆ„´\uÎó?oH÷¸Uí±ÿâ?Ù*F™ýÏ¥Ãêå}ùRäÙôxŠœ»YïŠÝNÝ}¦QeF}`*¡(§°³ÏØêgÌrUúÎÞbS¹O²ö^:½(-fGK !D m¸óÒC¥V{)ª¡T@q«ÝýZ¦ÚŽY2u…ÎÇo'kTÙ{ÿHú´ ñ«ôÛíd*{ÿ·ÍéÙ˜væ©5ƒzqy©?ïo¶€Ï~ˆIJÕéõÙ¯Þ4³¼g_Mî9|usK`9!D(k¶÷ÊC¥VxýP[w!ÄÙ­Áæ/¹_k^z6eØ5Ç„ÐKÍJ†UÈ¿·iÓÙ^eZM÷/®¾0=.ÎæWü½ÉÖm,b}Ë”ðòO±k ö¶ÎP±írº\+¿C9zÄãæZò”môZå›­ánvðy ¨*ó,]èV-Œ­~q†`4µÊÜGÿ\ûyÉÔÚ.yÈ<,;–H××äܨ'˜uÜK—Çné`*ô¨÷¹Ž½ ¶Y2«6úÒsS¡2í³|Tt^:¥L?NºVÎ=(“O*ºÐ…)=³~ì¶îöÕäèN“}Õ_œ7Q]vÇÓå‰?2 ĵ¯fk8𲿥·¨ ».Ü”EfõãvÓ‹„²ær}2÷Y¤³{{µÁh,öæWü½ÉÖm,*VŽ^dnÁ\4énšµAò/6à9ûr÷{)ëõyA½"-¡[}kc`#!D ’zùÖlÿa¿ù뢞ü!zl=ºÚÎT].±•.{%…­ ŽYbV{ Ðæ Zû’Yþ¯¥r³Ù`›1/ÿr…÷3˜õµò{öÕäèîÂguéÂ(ÆD)^î¡Ëë~v£)k^z‹Ê°kŽ a.5+Ñ«ŸUvÎÿ¹±‘ø`äØÀš-–Ęsó+þÞdë¶±¾e¶°úZŽ÷l梹Öâêšìصs&µlèãáÂw²p8wÌsŠlkq·ÆÍÖuC½Ätý§êüóˆ:U]îÛn[l³dVq~RgM¹5ƒêè.¢ yBŸ¾ŸM]÷ó® 7þUèÍÿD³¾&Gw½õ˜±éTér±W(GSÖ¼ô•a×Ö¬b±ðäðÚô*þ³1'U»ßÎÍ;ë_Ìͯø{“­ÛXÄšU¬®ãI¿×2Ï5Zh‚ý=›¹Hmé=ZþüX·¼»:ºTê~"æ‰ÖPD›KíË*¸Ùº®Œñùƒ–9dƒŠ.—ëÁÖ…ÅYâŽÄŽQ[\t?b(±D ­Ðmðă7žÛQ“£;ÆDµAM—;ñdÅœ‹Ê°k»W‘¿ˆ¢¿—IQÔÎyßÓxÙ©Rçtµbn~ů­ÛXÄš"<ü¥ýþÍõe8Ž÷ì"s‘ÕÍÊÓfþ“fåŠ%›Up³u]fþÇÆ‰ïaG%8j¶Ew­éÞ²VữB('Á¤=‰vÔdë9ºM«ÆÙuòȶö°¦ˆû{K–ÄgZ+7?»ÇkÓ¶±Þ]¯InèQã_…–R)(êÉ™Aloùûý’9™ø:óŸkô¦Ç/5z/“5+²-µµÜ¶®ÛÓKr$Mizœ«7H-]½c_%8jîsŸÇ^¾úWÌÛÏ?zþŽþu‘G7eúïvÔ´Ø]¨·äૼ‰z¬ÒUvÎû[½ú _TÅôXìªxy 8“`Qvm÷*„çFù¶ßbzÌsö{”ýH’0¿rÇÄÜçùך—àæWÌñZ¿€ù{Òþ ¦:N|×ÓiJ¶j­Ù‘?ÿ´_îë+V ºLîÙ–²•ó f6±r®hçFÕ¡ëÿ–n>iªôㄉ÷;º°uÔ¶¾.„è,óó%Ìÿ-U'žÄÖšÝ1¿Ý¸ƒùÅÍÔ]ty½qÑÅœ‹Ê°k»W1½¼ã["]·=Üü~ÅvÅ3ë”àæÇVν7· °¨ˆáܲ¡¦·dÏ#”¾9švk7GÂQd.2†q§¶]¯³¥Ì¸ï¹W´5« ïFGIÓêF£Ný„"Ôå¾5C0£ÎºXM”w ޶+cÌ–þ:¦.!¤ïŽ8;º°uÔ¶¾.„†“™ÕÔ«“éš.~cl­ÉÑ&çšÅ &ìϻϠ@RçF× ­laeصM«^zcV½¢È£³LRõyÁû–àæÇVν7Ùºm€EEgq'Ö¿_Ó"ñi>gÝ®˜øg*­A#Ï|xãìÒÉýM'Âx.íL³,ƒ€·M \._3ø—Q5Ã×X6èØõ*zÑ¿øý JN\Úý§¡ÕV}rðÆ2éáâàˆ¡UWLüè×;/ušz¿vÈöQ5Ã×\3}ÀÑ«÷U…z³_ù–"eš–~šù¯vD·lI†P’Ù´“|ÿüë(*ƒ¢2äOt£»çx¹d˜žÒå¹´½Zf‰3ý[çN2fÇi{f‰…µšçžyaÞýTùR7¦gŽ·,C(Íl,<¥·f‘Y#„Ì{Úa]³=$qf³.òƒÿ˜÷¨JÓë•SN–!’e¶ UÜ•k:2CQz#áQ•Qÿs•]ž1+ѧÒM+RTÆ·IFBÈËÛ¹tI^ E½jÃg¾ˆ•Q#TgÓœp»6ÔsñvF‚žÏ»Ùÿè«P(Š¢(JþäÌèî­¼\D¦§¦E·®iS_*ä˼*wÿdÎ#5s3 (ŠR¥]׫M9™H$ón:þ®\ˬ@W£(ªFè9ûFŽÂÈ®¿ï²"ËÕ/ãÆ×ùéè±ä\¥^§PÞ;rmBM×S5ÌÊ«ûŸŽ¢Ô©T——ìÑüDxßSñO”:•òâÂíŸÿÅh*~¼ÿú½{eÉu:¥*öÄÍ)õ7ÝÎÐrDÈt³’ççRŸ\ÓcÅ MuYæ¼mÚÔ\£Va¸rHÕÐ3ódš¹z—€ÜßÿÖ«uÆøhÝ!éÂä7’ Z¥aÏ·Ù®UäýÛç=šž]>PÅ×µ2&m×f«Œ¹/õK†dY¹È¬Å Mu·¬ðýÚt…Q#7œß£¬ášy(¥@ØÃšæì½¨ShŒ9©úåóü‚ÔVvÄ=ÖtmqƸ›5¯f0¶õÌŒSæhrtRqfŠæu E½j÷Ðs¡¯—äHš²èzF#!¤KÀÀßÿNRëtñÑkè}2ugt¶Z§H´îó€ÊÁ¿˜­5¬iÈÞ‹ÿ(4ºœÔøåÃýý‚¶˜U°/rp@Eäèlÿè:úmXv4“¹VÊácûÝc6røI^ž¤S¼,ðTž:¨ú&ºftÿ¿ÛžÆl*-úø„1‰lálR±bÀ(Ö½N¶”¹†Ø[Ú¿“Wg,ŒÖ› wevÞ¤cÖO>[£¿†¹ú²Dƒ±BÒHÊ+×Êu̧š\_”iV™~,vJO{ýç†iEk™5²½cfè>=siüjfå°˜ü°U¾8?$îŽ ”ùÔš®-ÎXáfÍþ™U¸úMV—íùÝ Ï®9(ïu±æUã~áAmœŽMNÆsÊÔ=|£ÑHY–˜Å]G§N拪™­óŠ~ªÊ8É×2«`MïðV(îyô¯k-¬(ºéä/ÕŠdVÎeœ /øÔ0ÀïfS ¹šÒ«³‡ÖßÏÞðF>>F°-¥S@'~º§ofðùFööž4ýfNú:•^ì™Ã\½`,ùåÌ3ûfO)Š5½žìŸø‰òæ# iÇ"³FHÓïÈ ,ÕäêÒ,få—Ì Bâ_+»¶8cÜÍΉ•i×Jù=õ*—±ñi^ÀÖ¼j÷ØMs±ɹðœÒ´ÿ¨3ÿÀŠ’«·æ¢+øô¥–1¿5E9™Õ/²Mx[÷;£Ï”?q‹ÚybOƒ*Y"-Ø ãi»Å=S¦û‡›µOñ„l]o»ÂÇ C(HS™ùÓN¼wf”²\«ïÎg}Êqï»%×dߎWöj¢2Vàuî!˜ó¨š¨èEfb¤^Á›¬$<²À%Ô^Ìð¨!Yß‘}]³Í‡Â¯‘ÈS0ÁY™"UÊŠW úæ½.Ö¼j÷Ȧ9áØä:{8ŸÉTõ÷›•›¶pú¢s©“ù=@Õ7¦›¾ÿôµçrún›¼‚u¼øŒù¥„Fc©Þ¤JSq¿3ê'vJVÈôÊtž¨œMU–ð"MÝó´À¿Ý'3B‹HI†Öü€zû›èËDèÆ[ºÝåqšûÉŸD²ûêæ­•Ö,2SWBî) ”hz˜ÇR݆ŠTÌ®m2v%ÉL=!äÌ$õûáù)ó›xÕŠ3'L_‡V ßgw3Zuyà?ü»O´†¼Sìv7ï€âæè¡’=gs˜%iç.º´´£©>-¥ïÈ”n ot¤Xñ±˜ù¾Ó¢;Ò ìµ´¼œ­~ñQTF¬’ŠÔk#X¹_–~GmÍ"33Z:Í9^à/¢äß•Þ-­=n}G%Þu‘1ŸVê*QPd( .M½ò7Ñâ¿jT¡ß°*Μ0µ\™¶0ôØ#;öǸ¬s>®UÑÝ4Z£Áæ?¨Âc€·Vqsôæë»$MÙwì·§ Ñ V?øí¯…S^~¶®¦M® ¾õñÁ³gSj£A£IŒ¾·¤çùËÛ³ÕPÑ·éhûÂÙ!=’»ù¸>KEôjãß§5=[+Gn6¿P¡d š¦~šE Zã[U®Õ…V.bê%¹5:gÅ]–šèUÆKTÝFë7ì”H ÜŠßµõœ„N«?0öž•+ê"ñcÄXüW­±”ìþ×h4’„?ÕβlS¡õs屃 e­.ÿfZ`ÀäÅ‘×ï?‘«tz*õq쩽? m#«ÖŽ;°ñþî}¦ÿû<Ó`4¤'ß[ûU7ëõzh‚Ýÿ¦ú„?#œe¶®…5Gà÷ý?G¹Ð«æ’Cíã·ý¼îŠ!u7þ¼õùЃÃ½+s?¸U™°mÜös®\{ýò¹1 gÝÅ•-BƒÁhÐë,.¢ï„Ͷ®³ÿâEñµŠZÞBYV߯ՖËÖ…8™­nÖ‚Y³6=9,©rK]¯B†Ø#kæ!rôr~fɱȬqyÁ_—$76(ª¸g8»gM\¯_rÑ5ćbµõ1°M ­]sßÝìåf÷>gê°ÂùB¸~òª×þ[ùª± Ÿ²c•ó¬ ,/£Å@uX¤‹MsB879BHùVco>øµÒ«è }ÚùzJD®^ Û…,Û]¿ßìçñ^‡”#sæº ®œlôh÷u}q@ð8y›µ„qjœ^‹14ó’«¾˜äÏã9·¸6,r/Ç(ÀñQ¸òÀ¡”ÀïŒ@ ²|ïÅ—¸”­=O§Z_Ù¦_¡°ˆãÆo®up,¸ÖÀ± Gp,ÈÑ rtÇ‚À± Gp,ÈÑ rtÇbùwFÃÃÃK90±œ£BK30¡ŒFcYÇùp=:€cAŽàX£8äèŽ9:€cAŽàX£8Öß0z»Ì;·¬C°6à7s PæÌÅ*•ªŒy ˆD"ÓœG(caaaeÀ›‚·9ë-^¼˜~üŽœG7Á 3(s87à˜pp(%ø6—‘‘QRM½6nÜÈ|Šóèe†ùç2À;osÅñNGpÖœ0ûsàm·¹R€ó莥ˆ]§|üóÂÉ]Z½çí!ð=ÊWiÙ¡Ç×sÃÏßyö¦#£(êMwá°½”,Š]©P†«[lÐÄÉÉI"ó¨ß¼ó¼ŸÎ”TË%ÒNÉb‹Š#ZÇ€ÝÒïþ߸¡-›4¨Z¹jýÆ-‡Œ›qê^:³‚¯¯¯Ù*9I'‚ëÕújÓÅR 3WŽžq7*(`hrùVï=û$5K!O»ýë=ü÷-žÞ¡‘_©…X¶ðFï£ÑhúßLYÇU–L3`0ÒŸ?Ü:øÅ¹½BVß-®qT(eqæ·î9KÒ|ÀöãÑqIq—NîÒÊu^¯6óı­’v+*¸ë7]~ø}Řv¥*õzt­üv§Î+#î_tw~]æR¥NàÇu?êàU¾ùÌÒ‰¯¬üÇÓ€ÿ‘‹Wóà\VùL#“~+fk8t8Õ«ã=¦XqöÂGÕd¦Ÿš=FÎèЩYû!Í>øûC/‘Ù*ÉçÖ…|¾{Ú®³ƒ›z•z¼yXÏ£_ê¹x;#AÏçÝìôûéóbù“3£»·òr1?=¿}puH›úR!_æU¹û's©õt ¦jª´ëãzµ)'‰dÞíBÇß•k™ãóè¡çl˜Ä;”ùV©WÅWðl¥40«C½%¿¼PPeФ|?¶g%O)<3 zÍä³»Ö ^UMøÓÖØ¬‘yïð°®Í<$ؽY—¡ÿÉÿ‚N‘{•ÌvdŠ¢¾MÊ&„¼¼ÝÓl³Ïü÷ȈnÍ=$¡Ä½i§AûïØŒÅÝYùòÒ˜žm¼e"¡Ô³eð°ÈS÷Ù‚d;pÌ\* SeýÁ,áØÍÓoïà*ˆ]+t9ç‰Zovè „è”qó?ï_¯Jyg>OâêݼӀ GîN‘ÝY<@q‡—yïа.Í<\œÅ®‚GÍ}ªÑ“b`ˆas7ð†üö]µñÛèæR¹ËÖ‰Õ¾ 3Oäþ=0?xʹ•gŽ—a‚N8rôð]‰“{V.r}Ó{|h¯ˆ w?Ë’ÇG¯¡5 ý²îÄM)¹êÔ‡—º‹Ž¼ß;Êl­ÏºÎï<í§ätù«„«}d§ƒ{î4«@"ŸðkG[6JtfA\&ý4ñÀçÙ☯®¿ K2Î?ç2~¸„²ªo·ž³¤ä˜3 ÃT˜Ù0dQ÷9»ÒäÊ;Ç—ÇÌé2ýbŠ­ápS¦iÚæ›Àq«Ò”Š´„ð1SÚ4=üBaZZäT$³Ë-Œu[OŸ8¥nA5WBˆwãÚœëRq•ž¢L=Ö´åØZÃǾ”+Ò’Öùþ¼ÍN¥«¬ Æâî<£MñÀ% ¯ä®÷-wý“®õØBµ¸:÷üØ!÷év¡´1ý”c7W¤jÜnB½—%¼’g>‹™Úê^¸Á…íÚ\ó 9rõB«K}³rJkN‘ÝK(®ð^nÒâ³êƒƦäd>‹™ÜVÓ5d…ÝÓÂ1;Âæh à͉¸œ2æãZÕ>&år³ärÄäëSö^ˆjï'-•èXQlŸÌºòyOÔ:7^Ñ×MRµ,1kj5WŽ:zÍS‘[;­2‘¹VXÌ«E Ë™žª3O¹ø~¡U`ö7„of½÷Õ²»„„¨±}6z½þ#)ÀE`M›&º wýÏúèÕO¬_þk˜G+ë\± ]=I¯t $õtÊÌ;ö Zá½XäÙc‚ó®È!$+þû³â‘c|ó>æ{ Ð5• )¾¨Š:ëBq‚Yrí\:ºWŸÊõ[Žšž¤²íšikæ‡Ûë¿VôЬÔó{—ÊR"GÊ?(sìæºFÒG ´QáöW^9XõÎOM*Ȫ¿×¼Ïˆñ›öGëØÿ á>ª>@qÔ¿¯Ð56 Ï¥)[¿|ŠÒXŒÊ¨¡(A‘±5l›æÞö½Í•¦–2á¹, 9-!DuN(kI?å‹j¬ù}_¢ÞóÆ–Vt¬Xsô¯C«†oa½M‘f´êòÀøwŸh †²ºË[—Õ£®†-0䢒W ¯E©5<<~íDµ‘,˜quæÒÖtM›>Ϩ)æÇ*´ÌS’ƒ ¹ü™ŽY6¹êJø÷:f‰Vñ¯@ÌzÑv‰»²Ã’™×!g&E¼>•.o dh f÷mÔ벋ӗЭÉÒí¿?NË>ùÓ·²ûš·žkÓê%7?NbWïú}sqÇÐÝŸN¦ÿPàØÍý%ü˜‚_ÏÕÊ-|ñQê´ùص,EÚÉkú¿_ýä²õûG®VdwÄÒŠ£~] ÿ¶yx·Øúm \ÉÖ.Wg_H9[öiNà-bÇÛ\iú´­ÏÆ­–sÚøí>m?e–ðE5Öž8¼¼ÏÌÝ¥tC^6¬ÙiËå‘i C=ʵ¯Ýã²vÎù¸VEwSFƒÒÖ _>k+:sÞ×î±÷“gÕæ4sB.ÍgW޽oÆ!ñØ>k9Qª‚øô¯™§ž36ø¯±õÈ5£eù9Ç |>“üûlï–a%”ù^V©ëå Š'.è6õÊ¿†aæûÝIcÖÌNX/-o÷ý ïÎEÅ*u„â×k²rÿÅô;¾vɱz‰ÏOµ¾‘C$gÆœL6=åØÍg4/ÿ¿}‰Ì’Ä}3ØšuÈj7n5ø³©»Ï_?”÷gOñ*õÃZ”‹Šg–<ÜÁ:-a­Ëû“…7¡»ß–o]`-‹±ï`h±)xÛ9l‚NiµhvÒÚÇ“rÌÊåɧF¬Nœ½¨•Y9_\sÝÉ__®0eË_¥£¬9ºPÖêâño¦L^yýþ¹J§×¨RÇžÚûÓØÐ6²jEÜÎ}¼¿{Ÿé?Æ>Ï4 éÉ÷Ö~ÕÍÖÈK»ÿM5õ F8ËM…#*ú6muNK¦¾·tÈÞN+ÑEƒVtÚ9hI§Õ“¬l¢›‡hÅ¥æûiÿÝ«ÿÑuåþKé ­V™yóܾÏC,|Ò P½£6ÜÝmÅKYjƒ^•yéÀŠn£omØÙëvê$¬°úyïY¡¢.ü„ùצ…ìˆ<Ò{óñY*½^ó÷éí=[3ró2ë[¶¸;šöóÓ,µA›óÇÖ™®ÕÇØ´ú˜§…QŸì>ÉtíÇnºsÍ?‚l?›®Ðjä¯Îü2àŽ ÂÍù·¼~×É„” Ñ(O{²åïÀi¦EÅ?ªpÔïµ>öëó¶ž~¥Ðjä/OFθ?˜­ÞQ?gÍïôéüˆ¿cŸª4z½Fõ4öïMóGw^¹«W‘±5lަÞ‘ׇGýªK·?Ž‘©5è²^$Ûº$8hb¯eG ßÂ×^êPö¦¡ã7^)ý€M¸®ò(ßjìÍ¿Vz=¡O;_O‰ÈÕ«a»e;£ë÷›ý<>ïRTæ½~™ë.¸r²Ñ£ÝÔõÄÁãämÖÆÉ0Šq÷q¶’«¾˜äÏã9·¸6,r¯©Ð`0ô>àæVwü*‘ÐwMûü/û¶_SÉ¥úÆ`k¿$º*bêöÁÍNNtlR¿~·/,¾±qrM/‰¤\ÕQsv6³Ãú¬!.ò×¥¥76Lªâîìì^uâúëK.Þ yýá5{“Ù=¹-~óۤÊ1Âÿš¼ª³ÐÙ#èâÅy×6~UË["”ùôý:¢ÓòóëBªXLáÝ9æðº*·ÖÔ«à"ö¨>óuô²…¯]r¬Î=?öñi³b˜øÌÈ#çn.©z+zÅŸ¾ªê!–U¨¿è„ò×Ããx.f­rkïâêWvæ «t;ð´Ùµóyg¦‹Tá ϧçí?ŒýezM/©¬Bƒeg ¿ùŠ­Q¹.×âÎT~qzT÷^®"‘«W‹î£Î¼¨r&îzgOQ‘±5lŽ¦Þ¨Z}f_:8O~m×®mjU­ÙªëÀíW2fÿzivË÷d$„ðŵ7œ9¬Ú:êÓU6ÿJO‰`½ñÖÛÅâíÕJŸõ÷“â¾÷"””R88d'®ôm}37eÛ›ëÀA”ÈÛ\)ß{ñmaí½À¢&¡_ûó_¹Æ Seý}&ªßû³z,]ÖAÀ;…_t`øyh•{Œ‰WSâê Z ™wtîÖOK쀠ä™>®‚wUÓ~SNô›RÖQ”¼Í•\ëPÂ/.ÖÏ:82¼Í•Žwê<ºé+eËôýp(88””’z›ÃÉxnïÎyt$F`Ž'ã‹ôŽÜ{àñîœGx7 Gp,ÈÑ rtÇ‚À± Gp,ÈÑ rtÇ‚À± Gp,ÈÑ rtÇ‚À± Gp,ÈÑ ßbixxx)Ç&–stBH```iÆ&”Ñh,ë ®Gp,ÈÑ rtÇò^;aeÞÀWFIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/grant-perm-50.png0000644000175000017500000004226210024102556024271 0ustar frankiefrankie‰PNG  IHDRŠTP@ pHYs  ÒÝ~ütIMEÔ %sõÇo IDATxœíÝw\×Úð3[€]:Ho Š"`ï½bïBÔØkÔäI¼¯F$åÆÜØbK,׻ƈ{AcïDD¤Ã.ÛæýcuY¶ÌÎ.mÄß÷?»gΜóÆ`J/ëîßeÒÌe^yžÜm÷žmi:O·]ü©Û*æ£|°ŸE%ËÝõÍÞÏë/ýÄoÑ„V-¼+WéŽ3µÛ>öZ ûJ\”Ï‚?®0ôaŸ”ÉžÌ,HV{³¿¬°Y@“4‘[–B¥/‚ª$¾À.zbeeB†ƒÍêCQTé'Õ,Ç9¸µî7õn¼ôÃêLQ»”†yåùíݤ”±od´¦…–,úoÚ­»yÌ;î|5“ý,Ç>ÝšÛ¼ñϦl1}y\dÁ9߿ЧPA  œ™õ¤ÅüÚWfÝ/“ÑL¦ÏÜÁ‚dµw1kñËJ/ A•¾úh- {¾Z4¨Ç+tŽBeVš.›¦z‰T*evʽ_Fztëµ¾L†Õ¿v( ³On÷k»6.Ws7óü Û!-5w¥)I+Fl¼äÿÅ“ÚnÞ} [Ý®}t鯚.â»àÿßvËÑŸbëå‚aýýìm¡¬m›Lìš¼ù¸ö8šßKÇÿ÷àÔÐß>­óû/³¯ËL¿Ÿ˜ Ï}¾û•ãçÃzz¾ºp;W©i§•²]ÓvOýmdƒõ;v§jÚ£|<^wüó°ßF†­Ù²/çÆ²#“C–hgg2}M‡ôcçGø/üÄoÑäNÛã.è'å³ ëÆíÏk/™Ð!ŽYpý]Þ' :ñÃþÏê,ZcéÌAûïe)˜£*óŒòYðtã‰)!K†¯üiúù·rš¹]{Çw($Û¿Ø1&hñ„Ö[ß’¨Ëuô‘²Ø7æÖî?˜bí×Q¾Nb¡C½öŸœ~+U7«äs†wp[{Ôjµúj†ºQçHNs—¢¨–M ¬fg_-èÛÏý<ÆÏYTò0]µõ»áÕ]íDŽ^}?ÿM¢¢5;žY1#ÜßUÀãiú«‡UÈBò_ݳ¥›½ˆ/°ö©Ýìû]Oõûf$ƒ1°¶so3pÖë sLÆŸziu ƒÈ³î6ë ‰3q´€Ïã[ù‡µ_q6¡ÑâÔ ŽÀJÊ{´)‘޿ʲžŽjzRÓ²·Ã²ø y¤÷¯ê»K.Y·ëET©Jnl80¤æzÍŽš“†œ~öRBÓtZ\|”ßýY„/Yºåi¶De04M¿Ú¼gåþ©L%ËË¿µçʤê︬§ÿ瓵o0HøaÌ蚦¾_?ó‡âeI^³ý?k ŠT…©¯—·_¦Ì—ÿºš™§xyìX”ÿ²3¯eå)µ³3™¾¦Ãp¿Ûã²i•2ùÔ?ÃêìÐO6Òûׯfß-(’¿~ ¥Y,¸öíäÕ;–lO.,R)‹ŠînÝ?)òsTe¾€‘Þ¿Ži±÷ñ ©²HzýŸOxb²]çÆãï7l<–.S(“ǺGÝX®‹`ð±leHÉ£gÆ»‹: ]w:WªPHsO­âÓi»ºýâÌú3öß’*äw|'ríkp(Í]BH‹_åJìŸÂ8‡Ž_šš+{;—Ç·Uwx¸º÷˜—ò‹ÒÜÔ£[öˆ¾¢ÙѧëÌëÏ3išÖî¯=Ñpo»/6Í–Èå’ÌÃ+>Ú†ë÷1™Ž±‰J)KØø›Œ?üó ÙÒÂgw²Ø¬ƒf [>ï»Ø§´J~÷È6N-NÍàh&™]žiš^Ûè·ø 9MÓò¼”Ñ Ò%ß‹)åQ> ´wT߸š%×PGÞý»³-‰ò_6wôá}›Ü»œ®ß_{Ç• –¤ij¹jxˆ÷PyÁ†n ïÈ57Œå¨Rʾ ^t%SNÓ´,ëɰàMEÊ≞¼»Søü¢v0·r4M«ÒHï_Ÿæ+Ek,}ͯj.\º?C'$2s;Ga8tC ®}{I½%)’w±)$o‡ÕÞ•¶2YÀHï_·'HÞŸ6¬ö6“í:7~ [üVfàÿmå·mìW†¹<u?*|·¯¼ðµCKõíÕD/‹tq†ò|4KJÓ´J‘M¹š'Óé0ÆÓ6IªM!vî¬é°ÿ­Äà€†“QRO¿ÉtŒMd,»¢ü·'þ74pð.“ñÏ’jÀ¼šá¶Âá;ïë`°ÑâÔ Ž`’%WnwŸVí¯…¯ !¯ÿ:í9¡™ÎÖôË {œý}jì¬khC­ià(`ß.$ôç«_,ØÓ»U»§Gnü2xÓÏk2ú_ÌTL­±P}3Êg¡,ï¥~8,vCë^‘hn-çÚÉôjM›8 !B§ ¾nÙë®h&ò½[1ïzÚ{Õ±ãB(¾5!¤†-Óª2§?{S³øÏÖOê´í¿Ü0öçºö|í»&\ãZ–ÂÝú]l|k'EA:˨H- !¤guëwˆ«) ÒL¶ë¸£t¸B§üÁä#Â~e˜í+ ´y€À¦¦,ÿ¦úö±¬"O+¾ñýtµq°&„P|GBH#;¡ÎÖ¿2$Õmï/½HrÎj6us¶19xbüžùÑߎ6°IÝ@šfú3’±tXN¤¹4¬Zõ† ÏÙ2Àdüí­µG`^¸ßlý$Ô'¬ÍÔ9+4Õl´85æÑŒ1ñ¦lÇ€öéMNÈ~¹oIzÔi'íMÉ[D/Ïî5¥q»6A^N_µú]w>›ë)ž_ãê~«w›J ŸÝ™Ø÷™0ÀX_MÖ?ŸikI*œ™õ¤ IåsQÓb?ëþg'šBx„ÇN•˜ÏJ«"3çÇœ¾sË6Kã‚ÒÓ ®ü÷]¡ÝÏ1µ˜G`³àFЄ.þ«0«…†$„Šÿ€Gk¯”±v´¡å-×E`󈔡eïo™xFºÄUÍ"Ƨ¢’&™r•³ÀÀ†þÛSµcÛÍ2ýë/GvîëæÄþ[ŒŠÓa31~Cü:mÌë áÕáÇÇ×û&¦¥Æ~;®M¾÷å%Œ5a:5sF(fIMØûôrÉY¼õê}~Øä’?;÷Ãýé¾"!Döö‘e1M Z4ïátç÷ÏtQõE~¼Ní+c; ’$ÊP{¦# EáÝ~£ÏLZ¬¹a°›<÷ùî—’§ŠßF+ŠþúûíÜFõø­]¯¤*R”qϲìLòõò%~Š1ícIÌLR2YÆÜà.éE*/!DY”CøF)ô•ÉBξ‘wóB…oxÖÅÿ·3Ö®#ÔžŸ« K¾—÷"è?"ÚX®ŒA‰û£y|[õíÞ®6ϤŠ`‘€¢>£Þ·wt´~#Wyž’‘fa?co››²Ž%4h_ƒÖýóMç3¥uÅBˆäÍ.ƒ}Š'2’N)™?A šÒ¤ºÄ9d YB34¾‹ÁüÔF0ÆÂ¯%éøµÇõÙgü§5Ði÷¶áŸ;›¡TÑY’W:fÙà†UÛºæARb\AeçÝØzÒ£w>NêöK™²°2è ¯{^HU´¼èÆÿë|NÌ?"{µÞ&hnœúùÒÓ5fökzJ`=e†ÇŸKÓ !}æíØõB"£‹22¶Œ¾`YvÌ~ [òש %M ßRï+‡v²:Œ-¸Á]NñÚûJ"§UrÙ£½¬üÙV& HÙ5æÌ‹ ¹JVtkãY»àâ?k×10Ò9îb–ЦSÎ]Q/¶Áà#bÁÊèKÜ]oТ9{n«ïÎþ¦ù¼íçódJ¥,ïü¶§NïÚGÕZy6AI«Ÿoë>HÝhËçEïO$Dõæé¥Yƒ§±œ‘2çß-o9“-Q¨d9‡–ލ>›¹¿§wìy®¢à5!¤¶H¸åØ]¹J•rïä˜ö“ öÑ0–N)™¿Iý«‰ÈUè´g]¸6«åŠOüMl»yç΃×F°¥üÄ/‡g4[1ÄwÁˆ°U f_Γ«tú_ýaÏè †.¥išV)Oü°ï³%CªÿöÍÐà Ʈœ2E¥”ý;|þ•GÊ¢œ…mV_ßôϢÓCY½ö/ &eð¶Éô57rnÜœÓvåß_£ü–ìˆËÖOVgc nx•òؼ؉µ ^1o±[Ï‹˜£2—ÉŒôþõñþ¾ _2Ë}·zò73û7 ^!í6Ý~«n|;×–Ï£(GÍfó÷<&†®ä2|[%_ûu”Ÿ³X`mß(bÌ¥÷—S#ךíÿº“ _ r¤i:õôoMÝø|+ïÚÍ£7üc°öDÓ16‘ÉFËâ7v[s#ýÒ­k{ x”öÃa°ÑâÔ Ž`Eð“PQ¢|üzcí-3Ê3¾‘=ËÞî?¬ËÐüO*Žž¡âàè€%”gÎùPP  Cyà”gÎAyàœ2ú¢j¨XÚ_£HãWâ )§%ÂÊ@Å0ãè™*‰/´rtõ oÞaâÌÿœy”U~!~ ´×ª²F(:Og-v¨Q·Ùøo=Ê•™ÞX0ãƒU E‚âY2w˶èAeÜ­ô‡Y #Tâ1ÃÓÀÚ¹ñ¡„øN®¦.°àè>heó·gZU´}ÞàÎóN—Éh`’ö÷²Vv,ÅŠ²®¸µ²£x§œ–ˆ›+U…噦i…\’|ï¼Q-4§~è¾%µ@»ÛÝÃk‡õnçëæl%°rvóm×kØšCwôGK<½mrd·ZÞÕl„B{ïV݇.Ù~F³Uÿ¯±³¾Ú튂Çßêîîhãêúë®Bäù 1ûy»ˆ=ƒ›}»ò¨~™w~3vPx /;‘ÐÆÖ1°^«IsW¾’)¦˜7¶—§“Xìä3`Úò"ºD7ƒ{©ï~=eT—Öý=m¬+‘›oPÇ~£ÖMÐÙ…ac+ÀfÁY¦ÀMÓriÎÉ5c4-é—Ðî`î’JÞÄè& †jÖjp‰¤onþ4cTÓÐ@[•‹gõæ{½˜}‡ŠYy“aÀGå/Viï¢Ý¾ª_€¦½ÆÀ#šö]3# N1s—öîæôæ:_Ê0¯±H´Û;xÿpEñ¦m]ݬäI×þ«jï{uÕT;¾ÿ¬8õK’* NÑÑ»ÄoõÛäqÃVŠâ±7É‚Ì]p–)£?µJ‘­iá J³¤í«‰Œ¥iîªgæµÕE†¯…dÙ¡bVžMPåRêòœ÷j…¦]äÚ[ݘv¾ø+”kŽX›'Í]5¼¦¦åëÒÔÝÞ\.Þ×­Ëñûi²ü”ÕÓ;2¿!‹D»ýøä”KÑ:-©W¾×ܵõ©Ù1;a…ïÝZÏÙ™%‘Ưê£é>ý‚Á)VO~õÏ,Í]±û6ËEÓ´sˆe»NgÈ Þ¾Ø4§£VH#XŽ ¿‰å‚›•‚A:SdZ¥Ÿ‚eKºåÄ­­ß£ÔÞdÖjp‰&øØiZ~Ø{¹@&Ï~ýôঅ!Î,;TÌʳ ªÔåEzúÑùß *ðØÝ¢¢Éí§IŽ_>j¨ €‹Ê¬<ËrÏ-yás÷Ùu{þ»2H+rûÔkz.wL[«~®¢'RE‘€R˜Q|Q·±vcŠrNkß ¨Û  .©ç' ï4‘D?'„tv²¾/‘·Ä2|ÈÊìäöýå?…}µHS› !”ÀaÁô0õbfwZ¸ûb¾L)yûxþ¸Åš>ÆÚµ‰ù¼EÇ_¢zûüÆüÏæïÛ ö²Ó4ÉI|Âã‹Õ_Li¸öR…Jžwjý— "~-«*LÙ”gZ%‰Þ-_>2H§½Ö¨¥Ò]ÑRÐoù€Ì½]›ÔmØq ¼ZÓÁX»¶¸U_¬™Ø®zõZ#ç¹ùSÓ>ÃÜÓ1ÃkVo7qÍ«âÔµÇýñrG·faµê6_pR¸a÷´2I "Q„””õ///½)ªjÿb~P¸ß¹ À9(Ïœƒò À9f° ?*PÞÌ+ϸr  àä6ç <pÊ3ç <pÊ3ç <pÊ3ç <pÊ3ç <pÊ3ç <pÊ3ç <pÊ3ç <pÊ3€ EQUÙQ€iU鑲,—ª´ í5/ÛõGy6Š¢(>×öûôÛ+%ÐA•de-ö¬¿èzFeÇU®ï_=²o{7'_`ïâÕ¨mïè¥ÛÊ|§ý3‚¢(—Ú µÚT}ª‰ùBÇû… MÓ¢:®Eø'͘ÜÉNÛŽîþEù÷ØYÙ”»ª÷ò¬œÇ.å=´BvŽ©ÃãÛn|–£Ó^Y!6õ³W}[)/JK¼9L8ßÊc溛å7Q¹SÉ~J¶(6#O¢,Ê¿|pM{/Ûò Bób¤>·ãóxç ¹RÝ’qëkuxmWÞW·¨ÙÕ„|ß.Yª`3&w²Ó>tð!<óÃB9sgÆo– {yV †ÇN;Ó²}ÔPž"„(‹R:¹Šì|£r*ívÍí /{±¢Dn-zŒ:þª@Ó‡òôèÝ× mj4éµ?)/íÒöÁm눅Öþõºîy–«äþžÚø"'¯ˆ‘³Y¾û€þ+A!M&„ð­<4- kkì±£i:åÜÆAêÛÛl<: œX‘o”Öõ"„Fþ©Ý¸p@C[!O}[Lú}S";ûW³çñêvs3ÕÿoºÉqÊÕ/Á΄i2Õw—7ó»ÒÖÑZ\m º%ûé¿ !ÎÁ¿0¬ƒ&®e÷nö•í!.\!í~ ³•áYÇþýD¯ñ[‡wmìh#°²umÙwòõœ¢ŠI¶4/O³Þ?í_Ú£Eˆµ@`m_·EÏåÔíiGBþ­é9¿¦!dôÅ4æÙ bxìPž+z•3n,PTã¯é´kSÊrÿ6â8]Ó‡²öàU‰\vïà BˆKƒ¯Êe÷Ï$„8Õš­î™?W@Q5‡¯Ì.’ž]Ù‡Rcà® ÉÿJ(Ê9G»Uße³¶ú]ÖÃßíø<±{§½—ŸHŠ7I7+²<æeGY‘’o¬ƒ:k^ñi[ÚÒLõóªÄgã£õí!uÆŸ§iZš}ÒŠGu^ÿèæOM!?&dÓ4}ù«pBHû µƒ×Yæ7ÊÊ~­)û¹Š(Š›xLHQ¢jýUZÛ˜ŸuìßOô÷Z¶ýXjŽDQ”·´7!ĽɂŠÉ¶4/Oöù¦ž# (ïNs3 3ætõ¡(áÜø4𦕲4!âY=(”Ó4­’g¹y|¡ëk™’yvC˜;”çJ YåSëQ<«å÷2uÚµ©¹<Š¢x6š>šn*E¶þ]žÀI}÷ßÕ !—r‹è÷ÿ»ˆË-§*E{U¥Ù÷/ÛÜÝÚ)lý­·êF–k«óØýêJùêÆƒ•7õ ´·ïÏñêSsêêƒìB™¦Ñ²LõóªÄg£4ó!Dì>Œ¦é‹3ÃùVî‰R…,滛Ïóë¶“¦éi>ö„#™RíàuÖù²r_k™¾#„8ÕšKÓôÏ!.„¹ïOЦžuìßOV@^øˆÂ8—W†%•æåÉ>ß™„?Þÿw¶ m!ıú·ê»«ºBzEÓtö“Y„÷ÆkLήù±Cy®šUVÊ3úxÚŠÝ{¦Ë”%Ú‹^ÎÕµCË:¾b+†‰á®‹ÐÀÕy] ¿nö£^i¡bX[†ÇÎMÈ'„¤É”:ULRŽïʳÊXƒÁX–©þP•ûlâ&¦(ê|æ›p[a±êÆum½yB—‡™­x”Ø}ˆ¦³ÁظœÝÆöÞ„žÓ4ýâX!Ä»ýFÍVægN¨ wW@Y‘)ë/5û—'û|ÕÿÕüñQ¥È%ZÿI>Ü—ø« IDATâÝn'MÓW¾­Gé÷Âäìú˜;æg]i‚òl„ö*g=øÝšG…}«Ý¾²»!¤GôÒcn¤dXöô²çó!©2£GK`Œö2Ê öð¶%„|þW¢¦ÃÚ2C0–eª~Ó)R±§ä$ý¨ÏÞ÷3­feÿj"uûOIÅŸ¡0¸œÍî΂„ßÎ[5-;»ùBZ,¼£¾Ëü¬cÿ~Â\**ò™\š—'û|gø;BÖ¿ÿïlaúBˆCÀLMçk:Bæ=º'âS.µÑ´³2˜|ì˜×¼4Ay6Bg•UŠÜOüímœÛkÚº‰ !‹Î&*åg6gÙËéåÑ™|ŠrŒ<÷øu~ʅߎõyÿF Ìô_ oo¯©&äÛD½‘+iƵexìžlJñ˜ó0-¯ õê„Ý*òM¦éÅëQ5zÅ‘‰L)/¼}j[Ÿ`Gæ×¿e™Î¨î@ùjß‹q*‚ª(D,$„ôÑ:Æ¢iúÁªö„¡8D»Öš,ÏÊN%ïêlCùN«d=žG±qŽP‡Çü¬«å™6çåÉ>ß”Sÿǧ(ßîó’²$’ÌĘž~%˜s6UÓùñ¦„ïM!]¶=Ñ´³}2°xìPž+þ*ç&nRÿ—\}7óîÖ.á~Šâ í{~±Â²—MÓb—önæ( ÅNí¾jÝšòJ©j1øJHÚ7KHQµ‡¯Wß5¶¶ MÓ‡}êë"ˆv»åÀÉ .Ï4M?>³}bdßjŽ|Š;y¶è2è§U{Ô›ŒcA¦9OöômQG,äQ<¾“ó8ãï.¾›€×%O9Ê% ®B¾o—¿µM–gîd—qk&!DäÒ£ä‰TeO!dæ­ õ}†g]Õ(Ï4ë—§YïŸc—toVÇΊϷ²«Ó¬ÇÒýµg,Ê9Ç£(BEñ/åÊ´7±y2°yìʯïjBJ›Ú>”þ6-ꊥ}š÷xï©$۾ÿt´V=»²çœ¨}Ûž÷M;Ø¥Å`>!„´kæwöEõˆêMEo/oß{«uï]}=x*iFJâî'×4;^JV´ê5ÁÃÙ&ýÁþ=›{ÔiÕªß$'›×÷÷úë|àØŽæ¦|~Ë&^‹¨O"ª T’7¯îÞ'ÞM fGÙÿOb‹VÛ÷sâ½_ƒkn`ežØ)¿{¿ñ>Õì 2žÅïÝrÆnJû@GƒÃ ,VŽ—†Q<»ˆ6~)§÷©èËoz¶$â•( CúDx:ÛR|+ßú}åù7õGˆìß»–¿µ€ÇÚ6í#}sÖàD]úuJ>¶~õï¿8xèÞÃûOÜÏ*T°‰ðÆé]ûtr¶µæ DAͺß;»Ç`7Z™ò^A§úï¾xܹa_éÃØ|%­¾{wÿéàAÃêx øO(r¨«½ï ž½\íxN&§Ö`¿æ åÃl4w­›) ÒÃ`çÒ„•oy¦x¶ÝÚúm;õاóT›’‡Î·ÿZ/k0¤•=%²w‰Äk–þPª‰øbŸ pŸ põÝüñ›ÿÞÙ6t ó^*šŒû2ÚÚÄú™çy’§+•h姥ÆR„(i§˜O«—%çÚ‡Ô½sënÆ›¤„«gÓ;mâÎr_3ל&„U^¥ *÷¯%qªÙTz-<ÜU§ýJJÁÈHS¥‘•ÝǯèÜ„¯UJl½ëbàÌ-Ÿ"*­úA"Á·’ŒŸ’’¦{eÕlÊä®:í—Öýr!½°µ»8H,x˜/ ··*]fàÙxÔoîAQÉÓV­ØØ<äku»NvúÖ\gß`±ðvvQ3—wÐEÙâú„–)÷¯%¡x¶M[¶Ó9t&„øÙn&¦)iZš›vóä¶ÒLÑÎ_¶oçÎ{ I…2Q)óß¾¸tpc@»(ýžµDÂóOÒUïï6n|û¯ÝÏÓsT*eþ›¤‹Wëïò îVõ®ÍõÛú?Š»NiÒ>äJìÑôœBšVæ¥']ŽÛTš\LÚ¼;öqÒK©\A+eéOïX9„i6éd§aÍuömØ9üÖî¿’ÓsT´*?ýÉñÝ‚»´² $°L¥}©gÇÈ>GlY½¯PììÖ"‚Ü|lñPîÁ­úú§ž;ôÏáWrZèXÍ7¸AŸ¡ί¶qàÀÆUû%B‘ýøÏ¦;Öܽ(îâ¾5‡ó¤vA¡¡Mtú+%÷/g;ŽõsÐÊÖ¯·}ö/O%-‚ê è!?yvÏ9{·€Ð¦]É=e¾¬„ûÙ?»{êÕ["{„öù4ÂXvúû2¬¹Î¾öA½ûž8w`Í¡œB+{柶|Ù¶Y!qÇú½æúHÒ$ÈôT½…¢!)))ê;^^^;½É«¸€ÊÖŠ…óØ|Ÿ_žÜÆd.ûHÒ$ÈTOÈ´”ªÀB¹ÙhDy¨LË3~€sPž8å€sPž8å€sX}îùЕŒòŽàã4ª“_ˆ`õÁ*¨H8¹ À9(Ïœƒò À9(Ïœƒò À9•öƒ’cÞ¼yeس>’4 2µ´[VU GÏ•/&&¦²CøØ±ù5º*à#I“ SÐó!.Ty=ÇÄÄl¿ùf„Ò´Ñ/š;Oͼ#sƒ²o;w5éUºDAìœÜkû{:5jÐ@g@Ë·8à†ÿ8W¥_qÿHÒ$È”Rå2-¥ª·PåxrÛY™ô×ÝÌ!á.ê»ùɇîJ yü—ïÍý»ŸÚöê5 š¥”åfe¤¼H¼}夺<—Iµ,Ë”cyÜÑwõÁØ¢°1Ö!„>ñ×mßNã’ã~×tHx‘pãð‡¯ =kt4(ÄÅšhàÆÄÄÌ7øÔ¹Ë’R¤*WÐ^ƒzxYóõ'ÚzèæøϱåQ„³vv÷qv÷ mÜF½U{@¢u&YÝøäŸCqîH‚##{û;-ÎÅà8111#úv8sñú«ŒÛj¾û%_;vmùiG¡«oÓväòc‹‡ò®ÛjDÔ£±‡Žïy%£….¾õšöù¤S»]‡ElݽñÇ+±ý¬™Ó]êŽ’ÆØ±f{ŽÔÑ;¨qƒ&–PÚq(AÚݳ'þ~žWD;{´4¹‘›ÈÜ‘›Õ°»/ù-e%ö 1!²\ªªô{ Ìõ‘¤I)è©z EBRRRÔw¼¼¼*5€²7oÞ<6ßçgccSÁ”Ÿ$M‚LõTLK©ª.Ê3çà'18å€sPž8å€sPž8‡Õçž7žÌ(ï8>N£:ø…Vå¹gS¿-e'·8å€sPž8å€sPž8§Ò~P b¬X8M·©_±êÆYIš™ê©™–RU]¨J8z^¹(†S“VJ<À)l~® øHÒ$Èô|ˆ U.GÏ oÊŒè2Ÿâ lƒ{ àj[‰¬\S&áÍ›7ÏØ¦ªô+îIš™Bª\¦¥Tõª\ʳv‘+§š§S¥”å½}yïØZ:xp뺥ýîÔfàˆÊùÛsAê½Ë—.'¾H‘Ñ7¿Ðv½z¸YñÕ›’¯:õN‘Cp·Þ½½ì…ÌãðøVŽî-z^½rkëºÿÒÿ¯€vËÛ§—/^¾’’ž)´ónܹUƒ ÑJt~öòÕôÌ|[÷ ÐÐ: ë7,ƒ´Ø©œò|èRbƒF­z{ hIâÕ]v]ói BHÞã½§’lûÿÒÑZõìÊžs¢ömxšN•OQÖ&{{œÛ¨ãnnÎÊ‚´‹û¶Œíæj°gArÜžs™Ýûõvç§'Þüç(Ay€ T9¬Šìß»–¿µ€ÇÚ6í#}sVÝ~ãôƒ®}:9ÛZó¢ fÝïÝÃ<ŽR!}ûòÁ‰;Úô79iÿ]ü=]|žµƒw«~í’ãÏëy3îzƒÁüÜø<£g­ö¦š•@)Uþ«xWZ%QßN(”ß]þ#›½ÔW‡ñ…"'w¿ÚÍG4ö0kR¡]C¥ä¤±­ äÃMŽ”“Ê/ÏÚT4÷e´5‹CúR^ÆEÓJÂ3ú‡mššP¥ 4¸õ­aA"Á·‹w·æQy šMOYækÇƶÖ ïä~â@ÕÀ­òܸ]ðí¿v?OÏQ©”ùo’.\mÞînâã—ïK*•Bú&ùÞ™Ø5Ú['¾È•´J‘õòÞ‘¿®5éÓØØ8:Ö½¹;öÕÛ<­ÌMvnïJ ó°·Nn;Öܽ(îâ¾5‡ó¤vA¡¡MÌÚ=<òÓœC·¬Ü#'ÖÕ|ƒë·rïé¢wÛ(AÆÃ³?/Ñn {N®ë*26Ž}p¿ž’ãÿì[‘S(rö ®Û´4I| ßK`®$M‚LAOÕ[(Š’’’¢¾ãååe°Ó›¼Š  l­X8Í÷ùåÉm* ˜òó‘¤I©ž*i)U…r³7Јò P™ –gnýíÊ3¡<pÊ3ç <p«Ï=º’QÞq|œFuª¦ßÈêƒUP‘pr€sPž8å€sPž8å€s¸õƒ’enÞ¼yeس>’4 2µ´[VU åÙ<111ÑÑÑ•˜‡ÍÍ} >žu@¦ ãC\¨ò*Ï111ï&°¶õ©Q·[ÿn^ÖüRh².Vbí485j9wØØý©×yóXýXìáø ŠýX=2%U.ÓRªz UŽGÏêÊ$—æ=»½óúø¯?k_úÑ>å~r[hcܤŸäÈRBJ”ç'ÿŠ»pGêÙÛßA¨iÏMºqèÔÅÄW*ȯfè‹û—gÏ&ZG¢Jiêñƒ'î?}‘W¤²srmØDG?[òþx]sÔ®îlp–˜˜˜o'=z"þabŠTIÍýn6CBöYÍᲺ6ãÐ8«Ü/ +|uåm§S[ú{Y_¹­¢É·ßEÛèºËTDh꘦ZXÇ)Au¯\½›––t÷ÂÙ”c;Õs7ØÓØ,ì{*h"`wŒeãd4±ÒîKË(žˆ9fö²Ï˜išQ›€ËÊý[ÃÄ>MÇÚ¶vªøÝ°®XpþD¿s]±àv¾Ìä˜|‘G‹¶ûGû|úèøØšvE”%G38‹Áy Çc+¸™g:BH˜Xx-»H»¥(ûšÐ6Œ9föÌ¢)ɨÍÀqñ¥žAíF·ÿoÛ9Õû–¶]ƒ/ý¹;!-G¥Ræ¼N:±{µº½cï†gwœHË‘Z™“ž|îÐ6ýÑ–nнýäe¡LA+e¯ß±v*.abáчé&gÑg¬g»ˆ3ÛŽ¦dÒ´2;-éTì&c#´îvzý®ûÏÓåJšVÊß¼x°kýéðž­™cf!CÖ`š¦Q›€û*è[Ã\B#"¥±ëŽÜß=”âRp”4îÄŽ5Ûs¤ŽÞA4Qws¬ÓcœÍ­c{7<|þFìâݤ]u-Yg¨f5ìÆÇîK~KY‰}CGLˆÐlê:,bëî?î”X‰ígÍœnláéé>àùÉC[þHÍ’8y4iÝ•Ü4\ABúŒ”Ÿ;~dûÞôl8¹û4ì:ºmGæ˜ÙGÈ5°ñÁ}ŸŸe>Я_°2Uo¡(BHJJŠúŽ——c犦’¿þïÊ;³¦u©ì@àÆòKÁ¾Vìƒð‘¤I©ž*i)UÕ…â\y^¾y×ö-}\iiöµ£[óŽê`WÙAT(Îý$FÓzNíÜ•ôVäìÙ°M?Ôføqîè*âÊm0 Ê3ç <p«KÃ6žÌ(ï8>N£:UÓoÄÑ3ç <p>XÀ98zà”gÎAyà”gÎAyà”gÎAyà”gÎAyà”gÎAyà”gÎAyà”gΰé$•JË;0ÉÆÆ¦²C€ ‚£çÃüùó+;¨8¬ŽžÕ²²²Ê/`°jÕªÊ*Žž8å€sPž8§ ˳êØÚï{·oZÃ߯f†GOßÿ´ì·œ··we‡`ž2+Ï7FÎÜ—7ë=ž%]:ò¿æ¢Ó¢Ú–Õà3®Üf6ë««®moá $„¸VoôíïG*«Á>*evôœ Q„Ú–(ö]¦oÔ¾+É|ºrÖðÚþµB›Œúú· ¹ª(+®NÃÏä´ÞX´ü³5=Ì&„¤Æÿ9´[Ëêþþ¡M:ÿ¸åC’×WæMÖ4,Øß¿Fó®Q+÷Ý.O%ÙöËô¶ ëøùÔoÙuîªc̩۽½½™w̾ð³È®ÁÕýk×úå‚™RûDº±ÈҤų&¶kàçÖ#jÒÆcò€P™•ç¡^v³÷=bèP¯ÓI“Éמ<»vr{ žþ3OY;wû.ðÒ´¸—:=_ù×iñðuœò’wtµ¬ËW¿ßúìä–è †üx9Ýàಜó½ÚT5útoü­Ä§÷6ýgü«=Ó5[·|Þ÷º]›MG.'&&ÄþñͳÕSÆíHdŒÍŽ’ô¸Îýf׊œ{ñÞÓG7NLnIYüéd†Èë×ç¦[×MãŸ%¿¸sõÄ÷“ºÜZ÷«%€EIIIQßñòò2ØIý¥žÌ_K’û,vè ¯òZwmÛ¬fuÿÚõš5ªåa¬³JžV£îˆç Çò_m ï|àνv|J½‰VæºýJtƒj;ú4ø{øžíŸª7eÞÿ¾õÇç§é¸ÿÓ¦ëÚoø{b¨þ&ooïÖ?ß5®®¦%'á¿§>¹µ˜!0“;îÜhwäî­ïc#„<Ù6´ÝWgÔ‹ÉyŸï¤ïóeCýµ$óæÍc¿ |ÐÊìèÙ!°ß«·~Ò×^™uùØî/¶hÞwʵ™z«J‘¹&fj‡¦á~>ÞÞÞ¾…!v>#§ùÜ›¸ý™fœgÛ'Þ´0·A5BȪY_ôðÕlrª5¥ e³ÁÙ—\JŸ;,ØXlß­¥}×¾úxiÖ!æÀL‰‹9IDATüæÛÿëã§½5 ïÿin3D>ÀC<~þ–¤,™±hÊìÒ0BÅ·m1¨y!„ЪÂ=ÿùdÔ ßïŸF98µ÷ze¿Å›ö‡úØY ­ðöñWï5jùèÅ}'¥GuòTò×£Ï÷ÿó²úÐò©DY§z‰)(ÃO$Šp[¡±ÀBÄ%6ñ„.*Ežú6C`Ì;>•(t¶ Å!šÛ ‘`Ýœ¯ÿÓµþl— ºaá ;vë7¤gsÇÒPõ•eyÖFñľýß´Um™F‰‰{¹ýáW5mÞM'Ë» ééòõ§µãVÞÛ?-üÞŠñI¶Ý¶|wV<ÀF°ñÞÓ6¦ƒ¬%Ü)7´3Z¡aŒY Hð P¦U¡å…5·"{¶Yôç¡òüç nݸ|ð÷I¿ïýúüšOͪ°2;¹=xΖ"U‰…ä1ߦ†úvJe¥uà{o]‰ß_š±´ï­%cf=ûÛ­î çòß·O s™6Íì_6wÿqÇ ÂfŒÁ \>ðB»åÅÿhn›Œœ'´«Q·qÿO'ÿ±çàó¸ïÍ ª¾2+ÏÖ}ݸë˜'®çH*yá“ëÇ¿üYó)¿¨·~ÓÈmÌw›^åHå…oOlŠ™z¡·ö¾-~îdû¶ÿÀ6mwöÑ´÷Yõõ YsðJ¶D.—æÞ9`Ö¨ÎgX±$ë×Áßo8’š#¥ÒÄÛgb&vc6s` z¬øéÑìÁKþŠÏ–Èå…™ñ»OÚÓ†Mä­NÞ{æyzŽ‚¦ ³R®‰q­7…å¤ð‘(³ò|qÿºOêS¿ÏU¯V@Fã¿[[}Ôï;§7Po¾uG‹Œ¿;7¬]³^‡U—¬vožTbgJðýÏrå¶ÿåg+­¿ÂŠ={Ÿø{ö­?ç¶ ªÛôË×¾ÜàìVŽ­œ^'»¸®góP¿À!3–»õþ•MØ&3NäÑãøÞ˜‡[£›Ö ¬Y¿ýÒÓÒuGóø¶&#ÿsfĽýË´o\Ý/ Yס‡RëÚó9ËIà#Qf¬‚¼ä5 ûÜyrki™ŒV|lð‹U–ë2ö»ã× å*EQîÝø½úÿ·Ëœ•TåuåöÇ`ñ@ŸÿÌóÙýç2ÊÆ¯vÃ_oú*²zeUʳåÂ{¶­7¾ÊNnpŽGÏê ” ¼±=zž?Ÿí÷u@)±ú`T$üí€sPž8å€sPž8å€sPž8å€sPž8å€sPž8å€sPž8å€sPž8å€sPž8å€sPž8å€sþY¶®xX ÑŠIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/hpha.png0000644000175000017500000012735310014674771022734 0ustar frankiefrankie‰PNG  IHDRækmõsBITÛáOà IDATxœìÝ{\”uþÿÿ×$’'D,@$0Ã~¦¢X.чÖÛ¢»æiÓÍ5òP‹‰¨Ý22µÌè`塵í[fûÙ2mýhîæ–J¦†a(¤)˜¨èššT`~\q}Æ91À0sÍð¸ßö¶·kÞs½×531OßïëÑh´ç6wë|Ü=PYYYîЉ‰‰î¤ca0ÚGR…w ¸¨/"+ZgšW£££Ý7 á • R+€z!² uJd%¬Â (Á•Ô ÀqÜ~  QDV4)V@sFdh‘ QDV€FYåãî€[˜þ «JýMK@³¸I€¦@d@¬&UÀƒ(ÿ°Bpà\DVÜÏ4¯òJ‰¬………¼‡8ײ ÑÑÑ|ׇçRßÀ¬càDDV€FYp3eU0ó«X"²4ŠÈ €Òëõõ*wýH<«‹&åéã€&EdÀóüæ7¿yàÓ‚“Ìò’k⓾Vttôĉ‹ŠŠ\ЩåìmÚ´ÈÈȽ{÷¤§§¯]»¶‘£OAdÀì_¿þá‡þÃþ°~ýzµðÆO=õTTTÔ}÷Ý·zõê:Ë•IEõÿ-']¯_¿žžž3wîÜëׯ«;¬[·.>>>,,lèСGŽQÊ‹‹‹§L™ñÇ?þ±¢¢Â‘c騱ã¬Y³~øáµñwÞy§OŸ>]»vµ3ûeù°ªªêù矿÷Þ{ccc׬YãÜW%''oÙ²E™YÍÉÉiÙ²eNNŽÒû–-[’““«««—.]9sæÌ«W¯ªuW®\Ù³gϨ¨¨Ù³g߸qÃòD8p 555 À××wÀ€~ø¡Rn«MõLêõú„„£Ñ¨”Æ„„„#GŽÔYQy vìØ1hР°°°øøxµSp%"+žäÆ[¶lùýïÿûßÿ~ëÖ­j¼yùå—Ï;·oß¾/¾øbÏž=êþ¶ÊÊÔ¢2áiöÔK/½TZZº{÷þúôéÓË–-SŸúúë¯7mÚtôèÑaÆ͙3G)üÓŸþ4uêÔüüüüüünݺ=ÿüóŽÎùóç—/_Þ½{wµäàÁƒÛ¶m+..¶3ûeéÕW_-((ضm[vv¶zÈÎ:pU—.]ÂÂÂvíÚ%"999ãÆÛ¿¿ˆdeeEDDtîÜù­·ÞÊËËÛ¶m[^^ž¯¯ï /¼ ÖÍÎÎþòË/³³³ËÊÊ233-!..î•W^QN‹);m*gÒ`0øùùíÝ»W)ܳg¿¿lll•¾RSSÓÒÒŽ;öé§ŸæååÕyªÀét꿺·¨×Ülݺõý÷ßÿä“ODdüøñ'Nüío+"÷ßÿÆÃÃÃE¤¨¨èÁT˜­r½^o¶¡PöêÕkãÆ"rüøñ1cÆäææ*;:t( @D®]»sêÔ)³A^»v->>>??ß²}µe£M›6½{÷^¼xqTT”R~àÀ   åY[c¨ó ÌŽ¥wïÞëׯ¿ë®»ÌÆàô_»ví¾}ûV­ZÕ«W¯Ï>ûlÔ¨Qûöí›>}zÿþý'MšÿÁÜ}÷Ý"R^^>dÈåÚW½^¿gÏõpÆŒc¹ä»´´433sÇŽ•••IIIÏ>ûlpp°ˆØiS=“ï½÷ÞþýûW®\)"3f̈Ÿ|xYY™R~óæÍ´´´ÀÀÀ€€€×^{MÝÿí·ß÷õõíÕ«W~~¾eƒ:nÙ²eÁÁÁmÛ¶2eÊõë×ÕòåË—wíÚÕÇÇGD*++{ì1ÿ”””ÊÊJe·ëׯ?úè£mÛ¶íÔ©Sff¦i³f½Ø§ò”éL²ºa«SNWçqýûßÿîÑ£‡¯¯oxxøš5k”Âêêê§Ÿ~:((¨M›6&L¸råŠÙÁêtº¨¨(53ÆÈÈÈüüü:+*gÉ”ÕWÄÎY=]*[çÙŒÕÓb«Óz5nëçÈka«®éÁš¾<Û¶º¶Úã½h‘`äÈ‘©©©eeeeeeÝ»wŸ={¶R¾páÂC‡åææ«ûoß¾}÷îÝ.\HNNž:uªÕ6wíÚ•ŸŸâĉŸ~ú)##C-ÿöÛosss«ªªDä™gž)))9vìXaaáÉ“',X ìóì³Ï–——Ÿ4–“«¶:uä¸&Mš´páÂ_~ùe×®]999Já‹/¾¸ÿþÜÜܳgÏÞ~ûíóæÍ3;X£Ñؾ}û;w*…;v숋‹«³¢r–ì©ý#²ÏÁólõ´ÔÙ©#ÛzãÙêÔÁºbí àøÙ¶ÚµÕîêÕ‹FÍpäûê•+W•íÎ;X6RQQ¡îìããcµ£cÇŽ)Ûz½^-/))Qw -,,T¶=ªlëõzÓêb’ Ìz±?N«muêÈquíÚuùòå§N2- ;tè²]ZZly°o½õÖøñã•íqãÆ­\¹ÒÁŠf¬©#²zÔ [çÙ¬–ÕÓRg§Ž4nÊôçÈka§®Ù†ÂÁ³íH×V»³ß‹f錬˜€fètÖ¿ fggÏ;777WYǨÓéjjjDÄÇǧ²²ÒlyªY#VÛÔétUUU-Z´‘ªªªÖ­[ß¼yÓrgŸëׯ[îfVÞ²eK¥–­®ë5N[:r\999‹/þæ›oZ·nýæ›o&''‹ˆ:<£ÑXSS£ž=Ó~þù爈ˆ¢¢"£Ñuâĉ:8RÑŒÕ#­ïÙ:êxœriÜÖϑעκfµ<Û¶:8T[½h ƒàÆŒ3sæÌ3gÎÔÔÔ\¼xQý RTTÔ°6Oœ8¡luêÔÉê>ÁÁÁ¦»«ýš–«ûûøø\»vMÙ>wîœZ^¯qÚêÔ}úôÙ¼ysyyù_ÿú×éÓ§«½ŸüðC¥ÜV›ê™Ôëõ ê7Z£Ñ˜päÈ‘:+*/ר¬¬|ì±ÇüýýýýýSRR*++•rN·|ùò®]»úøø˜UÑétË–- nÛ¶í”)SÔw‚Y[-_¿~ýÑGmÛ¶m§N233M›5ëEÙ¸yófZZZ```@@Àk¯½¦>¥ÓéÔ}Ô ;‡óöÛo‡‡‡ûúúöêÕ+??ßòTüûßÿîÑ£‡¯¯oxx¸òq‘êêê§Ÿ~:((¨M›6&L¸råŠÙÁêtº¨¨(Ó7Rddd~~~•³dµSS–‡/"'NœHNNöóókÕªÕðáÃËÊÊ?L±úòÙ°Ù+bzÚm C•““Ó¹sç7ß|Óþ™¬sÌV_Våg“n»í6eHê¶å˜íôâÈQ›¶Ü°Ï‹­!Y}!®]»6yòdõbº¿i¶N¾­Ï—­#µ|Y€CΟ?¿|ùòîÝ»«%ܶm[qq±ˆ¼ôÒK¥¥¥»wïþúë¯OŸ>½lÙ2eŸ—_~ùܹsûöíûâ‹/öìÙSg/¯¾újAAÁ¶mÛ²³³•ÙTõÿ-'Wmu*"_ýõ¦M›Ž=:lذ9sæ˜UìÒ¥KXXØ®]»D$''gܸqû÷¬¬ˆˆˆÎ;¿õÖ[yyyÛ¶mËËËóõõ}á…ÔºÙÙÙ_~ùevvvYY™é×/U\\Ü+¯¼¢œSvÚTΤÁ`ðóóÛ»w¯R¸gÏÿØØØ:+ZöåÑžyæ™’’’cÇŽž½ÿþ“&MŠÿàƒî¾ûn)//2dˆrí«^¯ß³gz8cÆŒùî»ïÌZ.--ÍÌÌܱcGeeeRRÒ³Ï>,"vÚTÏä{ï½·ÿþ•+WŠÈŒ3âãã'OžìHEí(,,‘ÄÄÄ· ×ë³²²ºuë&"ƒ R^nNWRRbYE§Ó;vLyg4èÌ™3–UlµÜ¹s第,µúÝwß­|CV¦³L{QvéÒeûöífŸY[;Û9œŠŠŠ;î¸CD®^½êïïóæM³ã ›={ö¨Q£L'ÒÃÃ÷nÝzÏ=÷ˆÈÙ³g{öìYZZjv°+V¬Ø»wïÿüÏÿˆÈøñã|ðÁ3f8RÑV§¦¬¾©«W¯†‡‡+“lަ­—ÏÖ€íœv;Ãxùå—ßxãÍ›7÷êÕ«Î3Yç˜í¼¬êx¬n›nXí¥¾GݰϋÕ÷ª­¢sçÎ_}õUdd¤ˆüøãݺuS÷·Õ…éÉ·õù²u¤–ï@"+n¦ýÈjõÚQ³ò®]»ž8q¢E‹"RUU©¤D³ò°°0û‘µk×®EEEf+ÙììlµS[û›:þ|BB† æÍ›·uëÖáÇ¿þúëÉÉÉ{÷îíØ±cXX˜:•QSS£Ó锯nz½¾¸¸Ø²G«ÊÊÊV¬X‘ŸŸ¿iÓ&±Ó¦:¼‹/ÆÇÇggg+«‚÷íÛ×¾}{G*jGã#«Ïõë×Փܺuk嫼p¢Ó骪ªê¬b«e³ò–-[Ú¬>>>•••fïR;;;r8V.''gñâÅß|óMëÖ­ß|óÍäädQ‡§¾jjjÌZøùçŸ#""ŠŠŠŒFcTTÔ‰':tèàHE[š½@–‡Ÿ=wîÜÜÜ\ey§­Æ­¦­—ÏÖ€íœv;ø뮻Æ¿dÉugOˆÕ1;ò²ÖY­öRߣnØçÅVdµúB8ø±uòmU·u¤–ï@'¸óÎ;OŸ>­lßyçÊvPPi¹º¿ò­WÙþùçŸÕò   Ç—¹ÚêÔ;vìÓ§Ï¢E‹D¤ÿþ‹-êÓ§OÇŽ•aìÛ·¯¸¸øôéÓƒA‰ˆ Óít4þü¨mµ©ò÷÷OLLܰaÆ ’’’Ú·oï`Eo|âÄ e»¨¨H™£®“i•N:Õ«åÓruŸk×®)ÛçÎSËCBB¿uvÃGѧOŸÍ›7———ÿõ¯>}ºÚûÉ“'«ªªª««•ïú–†ºnݺuëÖ1¢C‡V´Õ©)«‡?f̘™3gž9s¦¦¦æâÅ‹õ³úò98`‡ñÕW_}üñǦ‹ùоª1/«}õUFbë-6^ˆààà“'O*Ûê†%['ßÖçËÖ‘Z¾‰¬À ’““.\xîÜ¹ŠŠŠŒŒ uffÔ¨Qj¹º÷îÝW¯^}íÚµÒÒRÓ‹µÆŒ³`Á‚Ÿ~úéÒ¥KêþíÛ·?~ü¸ã:>æ={ö(‘5!!᫯¾RïüÈ#¤§§+_§ L‘‘QQQ¡ô8zôhËf'MšôÍ7ß\¿~ýüùó+V¬èÑ£Gmš7nÜ?þñ>úhܸqõªè5Æ?{öìòòò²²²ÔÔÔñãÇ;RkÖ¬YÊEt©©©'N¬WË&L˜5k–Z®îß³gÏÌÌÌ«W¯ †iÓ¦©å“'O~òÉ'Ïœ9sáÂuÿ:8ëpÔº?üðÃ7jjjª««•ÂiÓ¦=öØc?þøcUUÕáÇ'L˜`µî”)Sþö·¿½ûî»S¦L©WE«š²zø×®]óõõmݺõÉ“'SRR?F…Õ—Ï‘›v;ÃPV·¾ûî»K—.­× ±ª1/«}õUFbë-6^ˆqãÆ=õÔSåååf—›²uòm}¾l©å;È œ`Þ¼y xàBBBæÎ«”Ï™3çŽ;îèÛ·oRRÒ€Ôý333?ÿü󘘘‘#G*¡Q‘––Ö­[·Áƒ÷ëׯK—.JáôéÓ‡nùs¬¶:uаaÃüüüúöí+"ñññíÚµ6l˜òÔO<?vìØÈÈÈ'Ÿ|rĈj­~ýú%%%õë×/000--ͲÙÉ“'gffÆÄÄ$$$>|xÕªUu¶ijàÀ—.]ºråŠzº¬è5–,YÕ­[·Î;/^¼Ø‘Z¼÷Þ{#"":uê´páÂzµüüóφ……Ý{c R÷çw6mÚäïï߿ӥÎÏ=÷\lllÏž=ïºë.åRj™3gNïÞ½-u³a‡£øÝï~7zôè¶mÛΟ?_½õôüùó8xðà6mÚüñ´úï&"2dÈ‹/^¾|Y="+ZíÔ”ÕÃï½÷ÒÓÓÛµk—””ô›ßüÆñcTX}ù°Ùi·?ŒÐÐЬ¬¬uëÖ)¯‚ƒ'ĪƼ¬öÕwT ‰­7¶Øx!/^ìïïßµk×=z$$$´lÙÒj³¶N¾­Ï—­#µ|r-+n¦ñkYziüµ¬ `ç²=rästôèÑ#F8¾0Þ)˜eØô—¿üåüùó¥¥¥éééõ½£ñˆ¬›î¾ûîØØØnݺµoß~Ñ¢E.îE¸ ƒáMܲ0€c– QDV€FYEdh‘ QDV€FYEdh‘ QDV€FYEdh‘ QDV€Fù¸{Ç>®B IDATÀã…††º{h%%%î€æŽÈ ˆ¤êõ”—˜à Àˆ¬ !Ló*‘Æ[)¯rhh(/1wáZVÐp%%%„/¦¾¾Ì¨p"+@£ˆ¬ Þ¸ÄàDV€FYEdh‘ QDV€FY€;éõz½^ïîQ4ŠÈ Ð(w4kƒÁÝCh³¬Ài”U¾6lø¯ÿú¯ððð„„„7š={ýúõçž{...®K—.b±0Xyø÷¿ÿ½ÿþáááIIIÿùÏ–-[Ö«W¯°°°#F>|Ø´ÇÿýßÿUªDDD<øàƒ/¿üò7lu7bĽ^¿yófµú¿þõ/½^?xðà¦=/€†"²'ûè£>þøãœœ½^ÿ—¿üeûöí¦Ï®[·î‘GÉËË;}ú´­öîÝûŸÿügåÊ•G}ôÑGO:õÕW_­Zµ*//oÖ¬Y¦{¬[·îرc‡ž4iÒo¼±hÑ"[ÝMžûÏþSD~ÿûß;åÀN§3îÍZVV–ˆDGG»{ õ*"%%%fåÊ|é¿þõ¯ž={ŠH^^Þˆ#úöí«$CåÙíÛ·ÇÄĘUQ—+÷îÝVYY)"{öì ¯©©éÚµëm·ÝV\\luT555]ºt¹óÎ;óòò¬vWYYyÿý÷ÿòË/999ÁÁÁ—.]êÙ³gUUUNNN§Nœvv¼Ž­—ÛªÂÂBILLlÒ!h>˜eNkºñý÷ß›>ëH8WÖ ·jÕJyصkW¹í¶ÛŒFcuuµºÛÙ³gŸzê©Þ½{‡……éõz¥Ö¹sçluתU«±cÇVWW+Ë•?ûì³7nôïߟ¼ šEd.uÛmuý0ÛÇV•iÓ¦­_¿~„ ßÿ½Á`Pf_ÍV™Õü•W^‰MMMMMMu¤VRRRçÎ/^¼(¬ ÍãŽÁ¸™÷Ý1X½ý¯f½ùæ›Ë–-ëØ±ã|||Ü=­ãŽÁ܈YVм\¾|977WDÒÒÒÈ« qüg4#cǎݽ{wÇŽ_|ñEå¢V€–Y€ÓhIðÇìî!ê…Á"²4ŠÈ Ð("+@£ˆ¬"²4ŠÈ Ð("+@£ˆ¬òq÷ìÑëõîBÝ ƒ»‡Þ‰È ´Å#2ªË1bÀ)ˆ¬@C¬æÕ’’פ^BCCÍJôz=©È ´BÍ«ÚϨf̬$XR+4·_šà¹yÕ’h³¬8N§s÷þGÏìö€ÆËÊÊr÷à¨ÄÄDwA눬ÎWRRÊÚ`¸IÕ)¯ÁÕ"+Îc¬ÝÐÝú°I™ö¥¡¹^.ešW£££Ý7ÔOaa¡ˆdee‘ZmáZVÀKDGG“W=‹ú’1In ‘ QDVÀ³)t̯Â+YÅí—šú{³ZíŒázÜC À,+@s¤Ù, ·Óëõz½>,,¬W¯^Ó¦M;|ø°#U\00Ç•––¦¤¤ÄÆÆFDD$''ñÅîŽYV€&QRRâî!Øêî!@Ó CMMMyyùÖ­[ÇŒóÑGÅÅŹ{Põ0mÚ´þýû/[¶¬mÛ¶999«W¯2dˆ»…b–€¹Ûn»-88xÊ”)éééË—/W ‹‹‹§L™ñÇ?þ±¢¢Bj§X•¹Y;»)V®\Ù³gϨ¨¨Ù³g߸qÃþþ;vì4hPXXX||ü‡~¨VWW/]º4...22ræÌ™W¯^µüRSS|}} Pg]½^ÿÎ;ïôéÓG¯×'$$¿þ¬¶ÑhLHH8räH»víê”ÓKDV6=ôÐC999ÊöŸþô§©S§æçççççwëÖíù矗Úë¢ ƒzªÕÝÙÙÙ_~ùevvvYYYff¦ýýSSSÓÒÒŽ;öé§Ÿæåå)…o½õV^^Þ¶mÛòòò|}}_xáË1ÇÅŽòÊ+ÅÅÅfåvê|¸éµ²ñññ|ðÁÝwß-"åååC† 9xð Y#¥¥¥™™™;v쨬¬LJJzöÙgƒƒƒíÔÕëõ ‘÷Þ{oÿþý+W®‘3fÄÇÇOž<Ù‘ŠÁÇ®eÀ­ EžÙ#""DVˆ(ß9"óDÞщ<.òbm4õ ¾ ×X6 QMçüùóþþþÊvnnî’%K¾ÿþ{eeì¯ÿZgÁÎn]ºtQ6ºvíª.¶µÿš5k–/_þÆo´jÕjñâÅÆ ‘ÒÒRåÂT£ÑXSScu :uzõÕWE¤¬¬lÅŠ?þø¦M›ì×UcçèÑ£—-[vá£ѸsçΗ^zÉÁŠh"DVÜj¬ÈïDÖ‹E^'’+""kDv‹ü bù½È»"SÝ((hþüù±±±êÃ:ëúûû'&&nذÁh4&%%µoß¾¾Â¹ˆ¬¸ÕQ‘l‘ÛEDä‘WkË׊,Q¾½ ’áhd}î¹çÖ¬YÓ5·páºwâò#—iúIxõ}•’’ÒäAjjj***¶nÝúꫯ~ôÑGJaeeeË–-[µjuúôé¥K—ª;·oßþøñã‘‘‘öw‘ŒŒŒ×^{MÙ=z´ýýg̘1kÖ¬ˆˆ£ÑX]]­>òÈ#éééK–,éܹóñãÇß|óMe¯©I“&MŸ>½W¯^W®\ùÛßþÖ£GÇëŠÈ¸qã/^,"êUµVDSàöK¸œiº!ò²ÈE‘ "ËD†×–é]»}¿HÝ?‹4!Ó¡XSË}ÃA“ÓëõáááC‡Ý·oß'Ÿ|¢F¾×_}ñâÅݺu;vlÿþýÕý§OŸnzÅ©­ÝD¤_¿~IIIýúõ LKK³¿ÿСC§Nõâ‹/¾õÖ[JáO<?vìØÈÈÈ'Ÿ|rĈ–ãŸ"›EDäß"Sj#«U"CEÖ‰EFˆt¸õÙ‘"‹YV[ÍÞ#²_dˆˆ|W; +·ž¨1"¯ˆ ñùEÄßîØ¼·k DV€+Õ+£Š'ÆT݇®ìÚ ì¹[$¨öáp‘…"óEDä¿E–ˆ,®}jšÈc"o‰„‹ˆ¼P»^WDf‰ü?I™h­Ùñ"ÏŠD‰ÔˆT;Р©)"sDDd¹ÅS“EžyW¤Ès"oØmv’È‘"F‘gDþl­¯k"¾"­ENŠùÿêÛƒ›šÕ,ˆµWJË·_ª/ÇC©ÇWOüÏLqû%;˜e4  áÈDkaÓtÝDÍÂ}¸äðnDV@ý4,£ 1"¢® š—¼^‰È ¨1ðT^t¦zá’WÀkYV48£ 1u©÷¯ÝÀ¯¼žŽÈ i\Fb* eÍu¢Õ —¼ŠÈ ÍT#3ªSÑL´Â¸äð,DVh.ŸQ…˜ x2&Z-qÉ+ }DVðfÄTh­®aüõZa —¼šEd¯â”Œ*ÄT4=~íÚÄ%¯€ÖYÀ³9+£ 1ðnÜ„©ž¸äÐ"+x'fT!¦Â­¸ <—¼nDd­snFb*м1ÑÚ\òê^N¹šÀ`04¾¸‘4ÇéUˆ©Ð*&Z]Š›09—¼6\ân¿ ­Y@ˆ©à‰¸äÕY «üËV×[eWM!²€{4EFb*<­®Q{&wÃ;qÉkXIªMúŸû×þeVGEvÕ"+¸HeT!¦ÂÃñk7ð>\òêó¾þ”©c¸5»\Ý‹È M…Œ Í—¼Zrõ´jÃ(CbÒUˆ¬à4M—Q…˜ ¯ÆM˜\Š›0¹—¼Š6§UícÒUˆ¬Ð(ÄT@½4ÃK^=/¬š±6éJpu"+ÔO“fT!¦¢¹b¢Õ¥˜hÕ†æpɫLJUSW7!²@š:£ 10E”Bóã}—¼zUR5sëja.su"+˜sAFb*wã¶yÁ%¯ÞVÍ0éê*DVpQFb*`_õSõ]6œ˜˜Ø¤ãqÄ-yµ™üÅ»5¸¢)Y4G.˨BL4ŽƒÙ5+++++KÙNIIiÚ19BùKëõ «MÈ  ¹ ¦<šã‹×¬Y£l¸'»šÞßË‹ƒ+aÕUˆ¬¼–+3ªS®âø%¯nË®f¿hª³(÷\f_.,~»NGdà=\œQ…˜ p7%²š® ¶ÊÍÙÕ;&]m…U41"+æúŒ*ÄT€&%&&FGG‹I:µÊôY×ÅW«ÁU<$õY~×ðˆa{"+Oâ–Œ*ÄT€çPƒ¨ýì*®Ÿzµ¼¹®–³«Õog3@d iîʨBLx8fWÓ¿®–ó®âÖXHLÕ$"+Í!¦àD¦AÔÁeÃ.wS¯fû4;ß8øF DVîçÆŒª"¬š§^]}É«ûîºø;_´‡È Àm´TU:ŽÔ h><`Ù°¸$¯òÇ_󈬠ÞJJJBCCCCCKJJÜ=¢Ñìª O‚È @´|É+š7"+·1šZ  BCCÝ=¸ÓéÍF/yE³Dd€_q9+P/ÊÚ`w®@^mΰlp."+h ’ Ð|8ž]ç"²À¯˜b NŽ_ò 8Åmî€fM#)Ñh4jd$x®_… 0Ë  9" Ðx̲ˆ¬ÜÆÅ· &¦à,„U¸ ƒ¸”ÎDS÷e¼USw@3a5¯²HM„YVMÎe³©äRx£G>ôÐCß}÷]‡”’>øà¯ýë™3gôz}JJÊŸþô'ÑëõʳƒÁ]CÐ Váz̲h®™MeÞçý÷ßoÑ¢ÅǬ<\·nݦM›Þÿýãǯ]»vÓ¦Mï½÷žÔ&Uò*—Y³fgäÕ†}ï0ŠÌ é(ò´ß)´„È Ài\Sɨðn—/_Þ¼yó›o¾¹víZåþöÛo¿üòËݺuóññéÖ­[ffæ;ï¼c«ú믿~Ï=÷èõzeöèÑ£C‡ {衇N:%"ÊS¿ýío•”‡üüóÏ•í:«hžl…UÍåUihÚ\#²[ä‘C"Y"ï:wLh"+€Fiê˜JFE³²aÆx`ذa;wî‘3g΄‡‡«;DDDØ™Y]¹råË/¿l0”}fÍš5kÖ¬ü1--mÁ‚R;+»hÑ"eÿ¬¬¬N:}ùå—>øàwܱ{÷î:«hn\1¹úo‘"¾"á"jWÕ"O‹‰´™ r¥¶\'²\¤«ˆN$Ê$ E"EòMfYoФ‰Šˆ¼VW³kE–ˆ„ˆ„м ò¾Óǵ¬êÇ5·Mjê.múàƒ ”ù̵k×4H¯×Ÿ:u*22RÙáĉvf;ßxã×_}ùòåéééÿýßÿ}äÈ‘©S§*OµmÛVÝ­W¯^JíÖ­Û€Ö¯_õêÕÁƒGDDÔY@³â¢•À“DV‹Œ9+²XDiþE‘ý"¹"þ"™'²¢vÿoErEîé%²Sdˆˆì ‰3iv¡È!‘\‘v"Ï×Újö°HïÚ}î9ìäCDcYÔ­©c*Í\bbbVVÖ'Ÿ|b4•dXYYÙ·oßÓ§OO›6mÞ¼yË–- ;uêÔ¼yó¦M›fÙ‚^¯7 =ôÐC=´k×®Ç{¬   {÷îÏ<óLÿþý[´ha«ëÙ³gOš4©ªªJ¹zÖ‘*š[¿aÓ$+ÛˆDΊtQ/}xWd«HgyI¤§Id}UäN™"ò·ÚÈú7‘)·6ûÈv‘.""²¼®f/‹´«ÝÇOäg‰È Àº¦¾mRÓ5x¨Y³f‰È?þµtéÒsçÎõë×Ï`0ÔÔÔ<òÈ#ƒA¯×?þøã“&M’Ú;›Í¸*;tè0cÆ Y¾|ùìÙ³:Ô¡C‡‰'Î;W­¥N™†‡‡÷éÓÇ××·K—.Vàõ\}›¥ "‹E–ˆ´yS$YDD "=EDÄ(RsëM•Bj7&Š,9/bù\dõ­Íþ$r—E_¶šm'rY¤½ˆˆü"âçœ#ƒSèøâ@Õ¤·Mj¢–ï••åî!N“˜˜èî!4;ÊC¢££ÙN#Ãê¯ÿŽÖà¿ùÿ™"ò“ˆˆtÙ[;jJwkûcEDŒ"9"¿u‡."ÛEÌN‰­fD–˜¬1ÎÙ]ÏÁëDq#÷ÂÂBá³c·_š»&º·Mê…¯)ð¼™=”;Ãf¼È"7DjDªk §‰<&ò£H•Èa‘ 6ê*kƒßµX,"“Ež9#rA$µ®f'‰,ùI¤Dä‘?9ñðÐX, š£¦˜M%—Ä}îâæ\ýÈh‘ã"1"ÖÎщ )¹Gäu‡ˆ\iQ;Ajê9‘t‘ž"F‘Œºš}\ä¸H÷Úí?;íàÐx, š b*ÞªÁ ƒ{›¥Æ. öh, n2̲^‹Œ ìpóä*à"+àUœSɨx—þ† Ð8DVÀã9ý¶INl h “«ð,DVÀ#91¦’Qh&«ðDDVÀcS@ðž‹È hš³b*€f‹ÉUx4"+ 9N‰©dTÀä*¼‘p?2*p:&Wሬ€{4>¦’Q€UL®Â›Y×idL%£€:1¹ /Cdš1¸a^‰È 8_cb*@VV–»‡4Dbb¢»‡Ð|ÙúóªÁ`Ðëõ¢|jVßht""ƒÁÝãðNDVÀ9Sɨ$Ux:å=Lpu½… Zºrµ™W“/€z½žÔÚˆ¬@‘Q8‘i^ŽŽvß@€†+,,‘¬¬,R«ËX «âÖ¼ªd6½^ÿëc/®·~$¬6"+P ‹©dT"¬Â£)oàÂÂBR«khtrUDLòÛ¯ÙUýå߉Hª.Gdê@Lš¢ÁÉU[¼jÒ•°ê&DVÀŠÄT2*€SV3Å ÀVóªÆ§µ­Wñìjñ­°êbDVàWõ©dTàJVêRè÷o3®¢íìjí‹!aÕ-ˆ¬hÖêSɨÐxž~GMO?<”­•À¶ÊµÌôdeÞUÜ_‰©št›»¸šÎ„ý=·rÍð@kôµ¢££'NœXTTä–1ØyØIIIT¶oÞ¼Ù½{÷ªª*åáÁƒ“’’ÓxiiiJJJlllDDDrrò_|ÑÈÑ¢™³5¹ê‰yÕŒ¡Ö-¥º[ÿפl÷e}lp"+¼ŸîVvö$£€UÊ÷¶ìì츸¸™3gº{8N˜ôHNNÞ¸q£²ýý÷ß_¼xñСCÊà 6Œ5ª1O›6-22rïÞ½ééék×®mähÑlÙÊ¥^VÍØË‡º¦ü_½F7!²Â;5l*Õ5cÕ±cÇY³fýðÃÊC½^ÿÎ;ïôéÓ§k×®"rýúõôôô˜˜˜˜˜˜¹sç^¿~]ÙíÆO=õTTTÔ}÷Ý·zõjµ5[§UUUÏ?ÿü½÷Þ»fÍõ)e¦×lg[êõúuëÖÅÇLJ…… :ôÈ‘#fÇ’œœ¼eËef5''§eË–999Jï[¶lINN®®®^ºti\\\ddäÌ™3¯^½ªÖ]¹reÏž=£¢¢fÏž}ãÆ ËuàÀÔÔÔ€€__ß|øá‡J¹­6Õ3©×ëÔ¿GF£1!!áÈ‘#uVT^x/ž\µÃp+¯ìõEd…÷`*šÔùóç—/_Þ½{wµäàÁƒÛ¶m+..‘—^z©´´t÷îÝ_ýõéÓ§—-[¦ìóòË/Ÿ;wnß¾}_|ñÅž={êìåÕW_-((ضm[vv¶òõQýËo“¶:‘¯¿þzÓ¦MG6lØœ9sÖ H IDATÌ*véÒ%,,l×®]"’““3nܸýû÷‹HVVVDDDçÎßzë­¼¼¼mÛ¶åååùúú¾ð jÝììì/¿ü2;;»¬¬,33Óòâââ^yåå´˜²Ó¦r& ƒŸŸßÞ½{•Â={öøûûÇÆÆÖYѲ/x´æ3¹Z'CÓs÷!¢n:¾²Ã£9rÿ$Þä4Nã?r£Ni¶iÓ¦wïÞ‹/ŽŠŠRÊ8¤<Û«W¯7FDDˆÈñãÇÇŒ“››+"÷ßÿÆÃÃÃE¤¨¨èÁ4ÔÞ5Ôpë]X”‡½{÷^¿~ý]wÝe6«;ÛêT¯×:t( @D®]»sêÔ)³ãZ»ví¾}ûV­ZÕ«W¯Ï>ûlÔ¨Qûöí›>}zÿþý'MšÿÁÜ}÷Ý"R^^>dÈåÚW½^¿gÏõpÆŒóÝwß™µ\ZZš™™¹cÇŽÊÊʤ¤¤gŸ}688XDì´©žÉ÷Þ{oÿþý+W®‘3fÄÇÇOž<Ù‘ŠÚQXX(šÿÍ-kXXÕøFP'>8vpÇ`xGÖúºf$ÐLØšˆ0 KêòÔ°°°sçÎ)Ûååå]ºtQ¶Y¿ZVVæø2W[Šˆ’WE¤uëÖê­•L9réÒ¥‡ íØ±ãÑ£GwîÜ©Ìa–––2DDŒFcMMéŸÓ騨°l¹S§N¯¾úªr,+V¬xüñÇ7mÚd¿MõLŽ=zÙ²e.\0;wî|饗¬/àM·œˆÈ ÏPçZ_—`ÕwÞyúôieú±¸¸øÎ;ïTʃ‚‚LËÕý}||*++[µj%"?ÿü³ZT\\l6ËZßNѱcÇ>}ú,Z´(!!ADú÷ï¿hÑ¢>}útìØQÆæÍ›CBB,+šöh§‹   ùóçÇÆÆªmµ©ò÷÷OLLܰaƒÑhLJJjß¾½ƒáéX ØÂµ¬Ð.ûצr=*hJrròÂ… Ï;WQQ‘‘‘‘œœ¬”5*##C-W÷ïÞ½ûêÕ«¯]»VZZ:oÞ<µ|̘1 ,øé§Ÿ.]º¤îß¾}ûãÇ;Þ©ãcÞ³gY¾úê+õ^Á<òHzzúÉ“'«ªª L‘‘QQQ¡ô8zôhËf'MšôÍ7ß\¿~ýüùó+V¬èÑ£Gmš7nÜ?þñ>úhܸqõªeõÊU¯¿Íà8"«—Ói@ƒGkö,·M-›7o^``à€xà¹sç*åsæÌ¹ãŽ;úöí›””4`ÀuÿÌÌÌÏ?ÿ<&&fäÈ‘JhT¤¥¥uëÖmðàÁýúõS—àNŸ>}øðá–?Çj«S 6ÌÏϯoß¾"ß®]»aÆ)O=ñÄñññcÇŽŒŒ|òÉ'GŒ¡Öêׯ_RRR¿~ýÓÒÒ,›\9¥ jp‚µº³Wž"¼ž'N®ÞȪi® ‡jÜòõõíӧϪU«ââ⚺SíkL‚µµ?9€×àGx%&W "²z?Gb’²ÏÕ«WW¬X1a„C‡5ý¸¼¬¬LMG>úhÛ¶m;uê”™™i¿ñ6mÚ̘1ãÇ´Õ¦Ùþ¶vÐéto¿ývxx¸¯¯o¯^½òóó•ò›7o¦¥¥¼öÚkJauuõÓO?Ô¦M› &\¹rEmdùòå]»võñÑâ?¬oÕàvtÖ8qœ N¶&WÉ«€Y=Ì3Ïzô8óá|>Ÿ÷ùœæ=ŸÏ9'<ÜxÛûúúNœ8qÿþýÛ4O´êÜÁDxx¸y áááùùùz½¾ººÚ`0ÔÔÔØnÄ=4y« ‰àŠ""""""œ<…µ¼”dÐ,RV“œœœ––VRRR\\œšššœœ¬”WTTx{{ûúúæçç©û§¤¤Ì˜1CÝßvão¼ñ†:jÜæäÉ“-îo{ãÇæ™g ÊÊÊÔ`¦L™2iÒ¤Ó§Oëõúãǧ¤¤Ø3n¦™2Xqå$Öåh“«€+"eÕ:“dcÙ²e¡¡¡±±±qqq‘‘‘K—.UvÛ´iÓìÙ³† f\ýùçŸoß¾}çÎûô铘˜h»—6mÚ¼÷Þ{ï¼óŽy›C† 1¯Uç&/^Ü£Gøøø®]»ªË•çÍ›7xðàáÇûùù;vôèÑö Œ;k¾ V\pE± …  a ÍïË4-&W×Åí—Üú±ž“ë–“¶9ýÍcça:=N I¸Óí—”%¾k×®}ýõ×óòò:vì8sæÌ?üáÆ?ÍÍÍ]±bÅ?þñË—/Ÿ;wN)T³VååêÕ«_{íµ .ÄÄÄÌ;÷ðáÃ|ðÁ¥K—zõꕞž®Ü´OñÏþsêÔ©"âíí9jÔ¨3fx{{[ì®OŸ>GŽùë_ÿúÀ(Õ?ûì³I“&õèÑ㫯¾j¾áru®~û%’UÀ¥1Ëên˜†r{Mû@kœ;k_®5c xŽmÛ¶}ðÁŒˆˆ˜>}zFF†ñO·lÙòøã9räܹsÖZØ·oß—_~ùú믟>^¯×‘ýë_7nܸóÎ;ÉWÝ ·YÜ )«[aŠæ™ÁгW×I³¥E‹º?~˜ìc­Ê”)S>üðÔ””ÿþ÷¿………Êì«Éï:“ºãÇ×ét}ô‘ˆüýïV»n³¸/gÀ¡L>É9&m3ïÅFòìÄ‹fù¢h*'Nœ¸í¶ÛDäÇ‘>}ú4SG‡‘iÓ¦µnÝZD~øá‡:«tîÜyèС»víúì³Ïöïßïãã3räÈf F² ¸%fYæà9X•6gb5࢖-[V\\\ZZº|ùrùÿïÿ5SGJb¼yóæÊÊÊüqæÌ™öÔRnÂ4kÖ,ƒÁp÷Ýw6Sxp&W7FÊê>ø„ÆsÌíˆ-Ò`¢¨Í¼p <òÈÃ?Ü¿ÿ‚‚‚uëÖ™<3¼ ­_¿~ĈþóŸ{ôè‘šššššjO­aÆEFF^¹rEXì¸rpoÜ1Ø}p!+€´ÍÿÐÐTÜïŽÁêí5kݺu«V­jÛ¶íáǽ¼¸Nªš½c0·<¿£ÔƒS.…Õ,.…\Ôµkײ²²DdæÌ™ä«®‹•À€‡à×´›ððÌÎBkŒ p <òÈÞ½{Û¶m»bÅ å¢V¸’UÀ£²h2d°ÆÈ`á™´¿$øƒ>pvh8Vˆ”ÕðÉÚDkŒ§ÐHL®ž‰”€ƒÁ#ƒû1¹ x2RVÎaž¤i'‰UcsXHæ‘Ä€‚ÉUÀѲº<í|ÊIƒÓ°NÌ«™†&W)«ûás-܆³2XÛÿˆœ•Ä’Áð4L®P²p œƒUXÌ›;<2XnŒd€1RVצO퀃i6ƒU8x2– €{`%0s¤¬n…Ï©ðXÏ`űI,,WÄä*‹HY¸¡燎Ìî¶¢˜ÛÐ8&WØ@ÊêÂ48h–ö§aŽ™Œe®%""ÂÙ!Ô­°°ÐÙ!¸*&WØFÊ À¹J+™Œ%ƒ…Ö¸DŽjÂäЈFNÆ’Án 33Ó¼d@ƒ‘²ºVp-IbÉ`ײaËå䫃”àP ^QÌíˆá¢ÔçÍjMÓÞÊØb¾J²  ñHYÎ×°ÉX¦aÆhªð0¹  Y‘²º‹àøˆÀ-5 ‰%ƒ…Öœ?ÞÙ!XÕ±cÇ&iÇb¾:tèСC‡6Iû@Ê p õ]QL 4+k“«$«š)+À…Ù?K 4!‹ùêäÉ“E$''Çáápg¤¬.ƒ{€=ìLbÉ`†±‘¬@s eum|Æ€:Ù³¢Ø™·#Îù"߈ˆÈ ‘×Dº)ˆÌySD'ò”È —úê²Á·Émªk,=®›µ¶˜|@³"ex¢:'c7 ûˆÈƒ"ŠD^yT$KDD6ˆì9!bùƒÈF‘‰ÍÜ€’ê7_âjñö¿$«€”Õ5°*š›íÉØfÌ`OŠìi-"" D^ª-ß,²L$\DD–‹"".’/¢©1ˆÔ5’W»‘+fÖ¬ˆÜ.²C¤Dä ‘§k m4¨ ¹Wd‹È‘‘"Á¿þi¸H®YkÍö9T»ý½H¯ÚmCí"2FdšHHÈ2R„”U‹Xâ ®ÊxZÌøe³þgÜ—;Ù#Ò]¤CíË"+Eî‘{DVÖ® ‘)"“DN‹èEŽÿzÂsFíõŸ©"Yj6Yä„È ‘‘j;4¦¬ Þh¶*XDÆ‹<#R R&’ZW³ãDŠ\9/²@äO–úªññÉ™l%Ü„ €[ eu¬ h_ý&Z—ïŠÈ‘Ë"ÃEDän‘+F)ë<‘Á"ÃEüDÆŠŒ6ª5X¤H‘0‘%–š}Pd´ˆ¿È<‘­v4hL ãšH¢Ù‹ô‰éj´8ÙZ³O‰ é)ÒKdˆÈ“–úÚ$2[$@d˜È+ñ€;Ò‘êhMæX9àº233E¤[·nΤ”¹»óçÏ×·bDD„ˆ}ëZ»‰| ò›úöà¤f5K'béL)gÐÎÛbÕëtçääˆÈСCë$Xçåì€çÑÙ‘µæ4O×ÍÔ, y°0Ø0Å p |Ú ÀS‘²j 7^M‰›0pq¤¬.)V€k©÷ÓnŒ”À­1Ñ À•‘²j«‚‚‰V€HY]«‚€˜hàŠHY5Ä`0‚< ­ŽÁç .‹”Us Fœ Í…§ÝìAʪi¶WrZ`/nÂÀ5‘²j÷d¸+n¨)+€a¢€k!euU¬ ¸&ZŠÏ\)+@£HY5 Yž‚¿xŽÁM˜¸RV—Ī`€Ûài7HYEÊ œŒ›09Kµ¸RVí²v!+«‚xRVà|L´:ß~p^ÎõÃ+ÀÍ‘µŒ0Ë à‰¸W3—À,«FñDV€§!ƒ˜c–Õ•°*€G!eh)+@£HYµÈâ…¬¬ àiHYEÊ Ð(RV×Àª`ˆ”Usx"+(HYEÊêX À3‘²€z;þ¼ˆtìØÑÙÜ)«¶˜_ÈÊ+ååì€ c¢ÕC(óêàx̲€† ‡ñœkNÄ,«¦±* ed2€æÆ,«†ðDV0FÊ Ð(RVíbU0GÊ Ð(RV­àBV0AʪQ¬ Ïtòäɘ˜˜²²2µäwÞ4hPçÎøöÛo+…µœ%ŽBÊ €†¼ýöÛ-[¶üàƒ”—[¶lÙ¾}ûÛo¿}æÌ™Í›7oß¾}Ó¦M"RXX¨þ7Fʪ ¬ ˆÈµk×vìØ±nݺ͛7+ËmÖ¯_¿zõ길8//¯¸¸¸ôôô7ß|ÓZõW^y¥W¯^êìëÉ“'ï½÷ÞÎ;ßwß}?ýô“ÔÎÍÞÿýÊÊËÁƒÿûßÿV¶ë¬€ƒ‘²j«‚À3}üñÇÿó?ÿóûßÿ>$$d×®]"RPP­îÐ¥K3«¯¿þúêÕ« •}f̘1cƌӧOÏœ9sáÂ…R;+û /(ûgff†……}õÕWwÝuW»víöîÝ[gÌËÙ€ÿóÎ;ïdgg+ó™›7oNLLŒˆˆøé§Ÿbbb”òòòlÌv®]»ö•W^Y³fÍìÙ³ï¹çžüqâĉÊüýýÕÝúõë§$¢qqqƒ úðÃËˡÞ¥K—:«à`̲àdC‡‘>úÈ`0(s¤gΜ9|øð¹sç¦L™2wîÜ3gÎèõú3gÎÌ;wÊ”)æ-(yì}÷Ý÷ÕW_-Z´è™gž‘ž={~ðÁgÏž-,,ÌÉɱØuZZÚ† Þ~ûígŸ}ÖÎ*8³¬Îgr!+«‚À3͘1CDNŸ>»råÊK—.ýö·¿-,,¬©©yüñÇ #""žzê©qãÆImŽj2㪼 ž:uªˆ¬Y³&--íØ±cÁÁÁ=öØœ9sÔZê”ittôí·ßîííÝ©S';«àH:$§#edff:; É(  I°0X[ÈWÀ3ñnƒ73€¦Å,«óϲr:@Å,«“ñDV°†”UC˜bc¤¬"eh)«3qã%°” Q¤¬"eÕV€9RV§á‰¬`)+@£HYUÁ`)+@£HYC½•)V°†” Q¤¬"eu&V€ ¤¬NÀYÀ¤¬"euV€m¤¬"eu4.d;‘²:«‚ N¤¬"eh)«C)²²*¨NW¯‹Àë»󩨨˜3gNttt«V­4’ö¹îéV™„T¯ëÜÙvã ‰”€sXûlí”ÏÜ:#ƒþôÓOßìœ9s øÔ IDATÒÓÓúé'½^ßøÖ\KVV–N§ëÚµ«òRS§[QUUuË-·ÜrË-UUUN ÀÈ`n€”€Ö G®M¸víÚ×_}ÿý÷ïØ±£‘M}ôÑG"²}ûö›7ozÚòŠŒŒ 6lX}+:ìtüñÇ—.]ºtéÒ'Ÿ|Ò´-7ë!ØnÜÁÿXpRVGãàYÊÇý¢¢¢±cÇŠÈÊ•+Ù`qq±ˆ<ðÀ^^^MŸKQRÖÄÄDgbÕúõëM6€‘²:«³€†1YÜxæÌ™x ((èÉ'Ÿ¼zõªÅÕW¯^7nœ¿¿ûöíçÏŸoÿ·E:tX»v­ˆ9rD-ܺuëСCƒƒƒ[·n;kÖ¬²²2“ùå—§žzªC‡^^^J‰Òi‹-Ô«ªª^|ñÅÛn»ÍÏÏÏÏÏï¶ÛnKOO¿y󦦌ËËÊÊüñ   öíÛ¿ôÒK"RTT4f̘€€€[n¹eÁ‚ƇùÕW_=ðÀÁÁÁ~~~TrH“ŽlŒ’^¯_³fMBBB@@€ŸŸßСC§mÈ7¾þúkiPÊê˜Ó}âĉ½{÷Þyç _ýõ?þ¨”—––úøøxyy]¸pÁxÿòòòàààÐÐPådÙ3¶Öº¶]WqåÊ•'Ÿ|²]»v=ôP~~¾ÿÔxC‘““Ó²eKÿŸþÙ¸VYYY@@@Ë–-­5 €3à(Œ6`ÌÚ¯ órã’’’’ððpã_b£F2©¢¼|ðÁw{õÕWíFù@ïëëk0jjjRRRÌyÞzë­—/_6®~ß}÷Ùþ}[YY9hÐ óò¡C‡VUUYkÊFŸ|òÉm·Ýf\²~ýz“ƒRµjÕêСCvŽÒ7†nª²{÷néÝ»·6O·Á`˜>}ºˆ¼ùæ›ûÛßD$55UýÑ£>*"/½ô’ñþ7n‘™3gÚ?¶¶_Ú®kr¢###/]ºdã;RÊ~øaY¾|¹ñÑ­^½ZD’’’lNAå8?®Ëüó´Égk“=•íY³f‰Hllìwß}WUUõÝwßÅÄÄXüÔ>`À€S§N]¿~ý™gž‘„„„:ƒQ¶‹‹‹Ç¯´`06lØ "]ºtÙ¾}{YYÙ7:¤dž³fÍ2®µsçÎ7nXlÖ`0,_¾\DÚ¶mûÁüòË/W¯^}ï½÷‚ƒƒEdÕªUö4uûí·ggg_¿~ýÙgŸ‘ÀÀÀÛo¿ýäÉ“åååJÉwÜ¡Vùãÿøý÷ßWUU;wNIÃ’““í¥ôôtiÓ¦ÍÆKKK«ªªöíÛ§¤4ö È¢E‹DdúôéÚ<ÝÊ”©ŸŸß/¿üR^^R^^®ütçÎ"ò›ßüƸÊwÜ!"'Nœ°l­½´§nLLŒrÈû÷ïïÒ¥‹ˆÌ™3ÇžÆm¿4 ßÿ½ˆtìØQ}wéõú¨¨(ùæ›ol ÎBeÊöç*;YkÖñ‡h–ýÿˆŒKºwï."_~ù¥úÓ/¾øÂâÇôÇ+/‹ŠŠDÄßß¿¾Áüýï7Ôæ*0Þ¿  @DbbbŒ«þùç›U_öéÓGD>üðCã}Þ}÷]‰·§©¬¬,å¥r•¬yI@@€Å¼|ù²ˆDEEÙ9Jñññ"òÞ{ï™7eÏ€ 8PDþùÏšt§‘Ó½iÓ&7nœòRÉöß~ûmu‡¸¸89~ü¸òòðáÃ"òÛßþÖbkÖÆÖÚK{ê~ñÅjÉçŸ."=zô°§q{º¾çž{DdóæÍÊË?üPD d1BœÎÓ“(ÛŸ¢ϸ#'& AÖ>Ç›——´nÝZDÔ 1ƒÁpýúu‹Óõz}}™ì ð÷÷4hšnùùùYûÞªU+ãêׯ_·},>>>"ríÚ5ã}®^½*µ‹ëlÊü ¬¦^¯OOOW.šUööö¶³ºêÕ«WÍǪÎùå—_¼¼¼Z¶lYVVfm(l”;àt0@DvíÚ¥¼ÌÎÎÖétÆ©²PvÞ¼yÊË)S¦ˆÈ† ”—vŽ­Å—vÖ5?dŸ:¯ó¥b×®]"rÛm·)/•ï¶oßncÄp¢ÿ»;ˆ‡°óHk½xÔPuRþ¥˜ÿ»0/7.ñññ©ªªª¨¨Pr*©¨¨P>ý«Ul·P¯`DÄÏϯ¢¢ÂZE¥ŠÇâëë[YYyíÚ5uŸk×®úúú–——ÛßT%iii¯¼òе€ë¬®õÕ«Wê; Ÿ~úéý÷ßÇw|÷Ýw6¢µ'Œæ8ÝGŽ1¹ØøG}ûö‘’’’ÈÈȰ°°üüüëׯwìØ±¦¦æÂ… Rÿ±mÀy)//÷õõUJÊËËýýý}||”a·Ñx/U¿ýío¿ûŒŒÀÀÀ;{÷î?þø#÷h“ÛÞ1Xg‰ùnóøFvm­é4žr]ß7ß|£–o7‡^½z‰È±cÇÿë¢[·n"òÙgŸ*·áUVÀ6¡Í›7‹È¶mÛÊÊÊjjj®\¹R¯êJ<ŸL[ç€4ø‰¬æšãt¿ñÆuþ¨}ûöIIIgϞݳgÏûï¿õêÕ‡~XÉW¥qckg]å~ËŠ={öHíPÔ—µ”uþüù"òòË/+ùó¬Y³øóÐ,wKYmd§b}MZ3±Ø ‰+Ð÷ß¿ˆL:õСC7oÞùä“j#[;ëN›6íÀ7oÞüî»ï”wˆz«äziÛ¶­ˆdffšü%zàzöìùÙgŸ}ôÑGaaaÊé@£,~Mîr\åд!à0Öþ˜——˜?õDyˆ———-Ô+…rZ¿gì<ûrSßa1/QÒK•’û‰ÙWi֪߸qÃbÎYç€étºÖ­[WTTØ3¶ÃhòÓ­Üîø÷¿ÿ½ùî½÷^yóÍ7•—555±±±ÊÅ´qqqÆ{Öwlp^FŽi¼[Ãrc¨}¤ÉéS¼óÎ;JáŠ+,ŽáY“É&g‡cWŒhZÖÞüuf §OŸ5j”¿¿Û¶m'L˜púôiiß¾½ý-ØŒê?ÿùÏÃ?ѪU+__ßž={N™2åÛo¿­ï±TTT¬X±¢OŸ>>>>¾¾¾}ûö]µj•š¯Ö«)Û%%%%£Göóó þÓŸþTVVf;·1/¹qãFzzz||¼ŸŸßСCwìØQ瀼ÿþû"ò»ßý®Îøí £iOwÿþýÅì¦Í 对ýû÷WK^|ñE‹I]}Ƕ祬¬l„ !!!þþþ>ø`nn®=›¿,,,üÃþжm[u…°êÌ™3" >MmríÛ/¯°uÅ1Y!슇8ݦM›&L˜0dÈÌÌLgÇ™4iÒ[o½µlÙ² 4Gûœî¦òþû理¤LŸ>}íڵΎ[\øZV5ßS’oçÓ0&‘s™+`‡zhÿþýUUUW®\y÷ÝwÓÒÒDäøƒ³ã‚Hí½—›ªANws¸råÊÇ,"'Ntv,ÔÁUgYóUçFÒT˜qìdþÍÎo~ó›o¿ýV¹ìn†ÓÝäÔ!1b„Éý«Ð —œeu¿|U,͸:1@Ë>ûì³{ï½7((ÈÛÛ;&&fÖ¬Y»ví"qWœîæàååõ»ßýî­·Þrv ÔÍõfYÝ2_5aíIzàQ\l–ÕòU©=:&Zx8KYî¯#kàÉ\ia°‡L±ª¼ È=ä\p /gPož“# †&ŸeuXƒžsš4—IYY"k§FT}SMkÝ‘Êh<—IY˜ð˜²ƒ“Ò†µV¯TÖO+{¸Ìµ¬žöÜ—Æä¥š%Û¥Ù°8‹k̲²*Ø„‹fwÃVO®§}+ N®1ËJ2ãöL¾•à\}.+ÜÁ`0NS™W .‘²’½xãÄ•óÀRV+E=‡qÖJâ x2—IYáQ˜n N¹c0ìd0x·žÌAw ndâÁª`OÆý¢ÕŒ³¬6ÒTÒÔ—NçdЄš8 °–¦’l 1Ô÷o$À£4v–•©T8µž©á)«Å‚4ÐT겚gª¤©€æ`oÊJ¦ -à&L€G±+e5ÎWIà\Î x uîa|³VòU—°mÛ¶ÐÐPåÄo€k±µÌÒÍ&W¼¦´IºkX#QQQÛ¶m8p É¶«¯ªUÞ.}êÅjã~OÂtÅ„­a1·hÑ¢ººZ9ƒÆÛ®ÎÏ €Æ°¼0ØýòUc:nýúõÑÑÑÞÞÞýúõ;zô¨R~óæÍ™3g¶oß>$$äå—_V +++'Mš4yòäÊÊJµ‘•+W¶mÛ6,,lûöí+W®l×®]XXØ—_~©î`»»ŠŠŠñãÇûûû‡……¥§§›g•J‰N§3njÍš5QQQ^^^"’———””èãã3bĈââb©ÍëZ´h¡TT·C²x¤.Á=rov²²ºw¾ªÈÈÈØ»woYYYRRÒĉ•Â%K–;v,+++77÷ìÙ³Já‚ Ο?êÔ©œœœüüü… ª;wnùòåcÇŽ-**:{öìòåËgΜigw‹-º|ùr~~þÑ£G÷ìÙc^K“Kˆ8••¥×ëEdÔ¨Q©©©ÅÅÅÅÅÅ={öLKK3©e±kG Zca¥¥»^1¨.+Õét¥¥¥íÚµ‘òòò   ›7oŠH§N222ºuëf\+"""333..ND²³³ •F.]ºÔ¶mÛªª*uÛßß_É'ëì.22r÷îÝ111"rúô鸸8‹ç¸P§Ó?><<ÜüèÊËË£££'ZÍ[P·-©ö¹ë;€5¦)«gÆ9¤I¨¼ôòòª¬¬TÖܪ¼¼¼ªªªZ¶l)"z½Þ××WI8ëL íéθåV­ZÙ“²¿Ü¿ÿœ9s²²²®_¿®ü´¦¦ÆžØ,©ö¹ñ›€E¿Zìá †‡‡çææš†††æåå)Û¹¹¹¡¡¡MÕ]hhh~~¾²­nÔ˘1c¦M›VPPPSSsåÊûs9‹G ZcáZVÅ?~ü3Ïúè³Ï>[ZZZRR¢\†j.888;;ÛZ ÞÞÞ¾¾¾ùùù“'O¶¿k‹Gªqþ} à™,ß1Ø3-^¼¸Gñññ]»víÒ¥‹R¸lÙ²ÐÐÐØØØ¸¸¸ÈÈÈ¥K—6UwK—. ŠŠŠêÝ»÷À[µje¾Ï¬Y³¬ek›6mš={v@@À°aÆ b×TË<á–`Ì™^*)dÎpòäÉ‘#G²X×Þ™€gb–Õ™¦OŸþóÏ?_¼xqöìÙIIIÎG£ÈWEÊêLÝ»wïÑ£G\\\›6m^xág‡£E\ x2zÈ \—°ÎÅžÌ a<¹J¾ x,ÓYVa¢NE² @Å,«3ét¾2ðX$«LX¸ý’’-¸èmo\4ìæ`c(rrrî¹çÿ{î¹'''G)7 sæÌ iÛ¶íüùó–7êt:òUælÝ1˜ôÏ]=òÈ#,,,,((0`À£>ª”oذaïÞ½'Nœ8vìXffæÆíoS×j#ƒ|€Êrʪ¦ ®•µ*ÑgA•••“&M šsæLu‡={ö=z4//ïÂ… Ï=÷œ=1˜ËÈÈØ»woYYYRRÒĉmÔ5 ãó8räÈÕ«W_¹r¥¬¬lÕªU#FŒPÊ?ž l÷ïßÿøñãö »E†zjpGÜX·ÿq¹cšÜÐ("""333..ND²³³ MªDGGúé§½zõ‘¢¢¢øøø‹/ŠÈرcjjj.^¼¸zõj“ZåååÑÑÑÊD«N§»téRÛ¶m«ªª|||Ôm½^¯ìpêÔ©ØØXÉÉÉILL,((0ŽÖZ &‡VZZÚ®];¥÷   ›7oÚ¨k2Æ/ xöìYéÒ¥Ë7ß|."-[¶¼yóf‹-D¤¦¦ÆÛÛ[‰¿¾§@Ýv•· mªû޵®•µšäi^^^UUU-[¶½^ïë뫤yÆZµj¥ÎIÖÔÔètºššùøã/^|ýúõÿûß·Þz«ˆìß¿Μ9YYYêâ[eOãN-nët:½^o†ºƒµlZumÜŽøÞ{ï0`€2KüÒK/8pà‹/¾‘   sçεiÓFD®\¹}ùòåú£ðÔm—xçh“º: MC‡uvàælÝ~Iaœ€¹Ð"aEhhh^^ž²››j¾Oxxx~~¾^¯¯®®V²>¥|Íš5iii³fÍR§XÇŒ3mÚ´‚‚‚ššš+W®Ô+3#,,ÌÎìÑ€º»wï^°`Apppppð‚ vïÞ­”÷êÕëСCÊö÷߯ÌÜ6Œµ5ɰGf-g¨¿® ¹Ùõ\VãÇÞ(ÿ×ì¼Ypppvvv÷îÝ•—ÉÉÉiii7n4 ©©©ÉÉÉæU¦L™2iÒ¤W_}5:::;;{ùòåï½÷^FFÆ¥K—þô§?‰HBBÂÿûß>}úTTTx{{ûúúæççÏŸ?¿^͘1ãoû›ˆ¤¦¦>öØcöÄ ö=¸ÕZ]“¡0nªW¯^+W®œ1c†ˆ¬Y³¦wïÞJù¸qã.\øÉ'Ÿ † <ùä“õ:FsƒÁ%Þ6šbüѧ[·nÎ P7åAq™™™L·@3©{–Ue2oÖ„“®MØÔ¬Y³ÔÖ–-[¹téRó*óæÍéÒ¥‹ˆœ9sf̘1YYY"Ò¿ÿO>ù$::ZDrssïºë.%󌈈0NAÕ— ~øa×®]Mb°¸³µN#""Ž;""·ÞzëO?ýdr\/^LOOß¹sgeeå°aÃ-Z*" xçwºwï."%%%wß}÷?ü`r¼›6m:tèÐ믿."S§N0`Àøñãí©دɟËZ¯›ê›ìl­®ƒoÔµmÛ¶: k;G@³í×Ùcv¨WE5É 4hкuëóQ¤a±5Ç Θ1㫯¾ª¨¨HHH˜;wî¨Q£Ù&œ¢Q¹hµkGÓ°ÒÒRuákçÎ/]º¤l—””têÔIÙ¶gelqq±ý h­u*"J¾*"¾¾¾z½Þ¼nXXØK/½¤ôøÚk¯=õÔSÛ·o‘‹/Þ}÷Ý"b0jjjŒ¿ÚWwôèÑ«V­*++3 »vízñÅí¬¸/\PPpçw:¥k7ø¼ÎChòcT,--}å•WRRR:Ô´í7,žFzä‘G† ²~ýú€€€o¾ù&==”ÕEiea04€ÃÜrË-çÎS¶Ïž={Ë-·(Û:t0.W÷÷òòª¬¬T¶/_¾¬–wèÐÁþ´Ö:­—:Ì›7ïðáÃêËï¾ûîìÙ³çÎ+,,,((0¯4tèÐ?þøã?6lX›6mì¬hN§[¿~}tt´··w¿~ýŽ=j¾ƒ˜=4Îbu‡Ï?ÿ¼wïÞÞÞÞÑÑÑÊUè&nÞ¼9sæÌöíÛ‡„„¼üòËJaeeå¤I“‚‚‚‚‚‚&Ož¬þN°¡2EÖ¢E 5>>#FŒ(..¶8êF½b¶q ìáêêêùóçwèÐÁÏÏ/%%åúõëæ­ÙÉøHí1kÇbq¬êtË-·,Z´Èø=c•µà«ªªžxâ 5H“¡3iþk¦“xàÀ… ¶k×®uëÖ‰‰‰Ÿþ¹RníL©Ç«ÓébccïƒsôèÑ:+*…&§•”pƒïDW‘””´dÉ’K—.•––>÷ÜsIIIJùC=ôÜsÏ©åêþ={öüë_ÿZQQqñâŹsçªåcÆŒY¸pá… ~ùåuÿ6mÚœ9sÆþNí1nܸo¿ý¶ªªêçŸ~íµ×z÷î­”?þøã³gÏÎÏÏ×ëõÙÙÙÖîü裾ÿþûÛ¶m{ôÑGëUЂŒŒŒ½{÷–••%%%Mœ8Ñä§Ê_O“gÝÛ®2nܸ%K–\½zuÏž=4ïqÉ’%ÇŽËÊÊÊÍÍU¿–Z°`ÁùóçO:•“““ŸŸ¿páBÝYŒJD-Ztùòåüüü£GîٳǞÃ?pà@VV–²þbÔ¨Q©©©ÅÅÅÅÅÅ={öLKK³ÑW}c¶Æþ^±bÅ¡C‡²²²ŠŠŠZ·nmüÛÒžŒ´^#f1‹cU§ÒÒÒeË–õíÛ×bTÖ‚_´hQIII~~þ‘#GvîÜYg/æo°f:‰ýû÷_¼xq^^žI¹3¥¯Á`hӦͮ]»”Â;w†„„ôí۷Ί ¡ñ´r-«p5£gãì+¸–dr©µòªªª… þïÿþ¯ˆŒ5jÙ²e­[·VÊçÍ›·cÇŽ€€€)S¦,[¶L©uìØ±™3gž§¦Åëu:ÝùóçÃÃÃ̓,//ŽŽV'Z-V¯oÌužÛ#ýé§ŸöêÕKDŠŠŠâãã/^¼hÒ”ŒÔþ³çXlŒ•Ú²áïï?pàÀuëÖÝzë­æQY >22233S¹uBNNN÷îÝmŸV‹o°æ8‰………Ï=÷ÜçŸ^QQ1räÈôôôŽ;Ú8SÆÇûÚk¯íÛ·ï½÷Þ‘äää»îºkêÔ©öTDsÐPÊ*ä-ŒS¯ eWÔ¬)k÷¤±½yS\ºté·ß~ëëë»nÝ:ó%ʵ&K½¼¼ªªªZ¶l)"z½Þ×××<5µ¹ºmÒH«V­êLYË÷ïß?gΜ¬¬,eA¦N§«©©±Q½¾1[c竇£^$¯„טa¬sĬU´s¬l€I¹µàë{Z-¾Ášõ$^¼xqåÊ•ßÿýÞ½{Åú™2näòåË]ºtÉÍÍ5 ±±±yyyÁÁÁöTDs`a°+q×k}Ýõ¸Ð Ûo¿}ÇŽ%%%o¼ñÆÓO?m¾Cxxxnn®Iahh¨ºÀ277W¹kw}…††æçç+ÛꆈxyyUTT(ÛÆ÷f31f̘iÓ¦ÔÔÔ\¹r¥Î$¡Ib¶_xx¸r¹Auuµ’Ò4>$k#V§úŽ•=¬n\®îoí´Z|ƒÕ·Óz [±bÅÔê­×ë?ž’’Òø¬X¬UcX >%%eÆŒj¹º¿µÓjñ ÖT'ÑØý÷ß¿{÷îÊÊÊÒÒÒ_|ñ¶ÛnSÊí9S"2a„·ÞzkãÆ&L¨WE49m¥¬Æ Hœ‰«pƒô•%Á4ƬY³ìÿ$ðàƒŽ=ÚßßÞ¼y[·n5ßañâÅ=zôˆïÚµk—.]”ÂeË–…††ÆÆÆÆÅÅEFF.]º´¡.]º4(((**ªwïÞlÕª•Rþæ›onß¾=((èÎ;ï´±¾zÓ¦M³gÏ6lØ!CÔrk#Ð$1Ûhßļyó<|øp??¿±cÇŽ=Ú|Ÿú†dmÄêdm¬ÃZðÏ?ÿ|ûöí;wîܧOŸÄÄDuk§Õâ¬9NâÓO?½hÑ¢ààà˜˜˜~øáý÷ßWÊí9S"r÷Ýw_¹råÚµkêAÙYMN‹ ¯Õ7«cs:ãÏö¯NížqüÚÖ1¸–\Q“_Ëê Nž<9räHûˆ:€Æ¯HÔàˆŽ¡­YVs­v2üšÉOµ<k•–ÿ<€&4}úôŸþùâÅ‹³gÏ®×î@›H´µ3}uúš$«ÚüóšC÷îÝ{ôèצM›^xÁÙá¸F Ðôú&âÌ5ìÊOkiªƒG•Z'€+ba04¯ºwqƒÁ &9ܤ§1Lž[eq»¹Ç–K”Ô—¦SV1[!ìá‰k“¬éuXúj1Z=w@£×²š3¾èQ#×d:’ññ6aÖgíòW]S°Ø]SEš‰Å?âÛ¶m õ¨O_ö°8 M2J µs1þšâ2)«Â$¹ò„ÜÕ$Ym¾¬ÏÚ­›š¤Mn³€ý4øÙfΜ9ÿøÇ?šö¯y#Sƒ£ÔÜÜã9ï¨/­/ ¶Èü©¤îw_“Ž<(÷@\—ÿÜyçÎŽâW48JÍÍ—›e5fÏ¢VgÅÖ0Ö"ç×Eý$ðùçŸ÷îÝÛÛÛ;::zÆ 6ö´§buuõüùó;tèàçç—’’rýúu¥¼ªªê‰'žð÷÷ KOO·Ø‹Á`hÑ¢…Ò~eeå¤I“‚‚‚‚‚‚&Ož\YY©î¶fÍš¨¨(//ÓIóxtµ·)QcÎËËKJJ ôññ1bDqq±R^QQ1~üx5Suð5î}:P'žË ®¨ÉŸËªÌjŠHçÎÓÒÒz表¨(Û{ÚS1::úÓO?íÕ«—ˆÅÇÇ_¼xQD"##333ccc•céÞ½»ùãŽ"""233ãââD$;;;11±°°PÙçüùóáááæqZŒÇ$xcåååÑÑÑÊÌXddäîÝ»cbbDäôéÓqqqê5bêFiii»v픊AAA7oÞ´QÑãNm´iÏX:uJÝ'11±  ÀF_:uÊÈÈ0ùë¯ÓéV¯^½víÚ;vôë×ÏdÄsÈÖÞ3ö„m1Tï‹Aš`ímigu{4Õ™…³¸yÊªÒæ,«£â×HYÀ5_ÊzðàÁ¥K—~ûí·¾¾¾ëÖ­KJJ²¶§=[µj¥NRÕÔÔètºššñòòªªªjÙ²¥ˆèõzu7k™ìïëë[g.a1“ý÷ïß?gΜ¬¬,eiháçZÁžã²ÖicÚÔétz½Þ||l`ee¥ÉjjN×µk×äääeË–™‡ÑÈ𬥬Ã6f1T;ßÖ‚·ö¶´³º5Íqfá,n²0¸N†q@$ÍÑp·ß~ûŽ;JJJÞxã§Ÿ~Ú|//¯ŠŠ eûÒ¥K¶+†‡‡çççëõúêêj%=PËóòò”íÜÜÜ:£ 5Þ?44´ñ""cÆŒ™6mZAAAMMÍ•+WÔI¡¡¡ùùùʶºa{*ZëÔ;ÇÊxŸ°°0Û}…‡‡[lj÷îÝ|ðA½®«´ç­½g¬…mÌb¨ x?˜´iñmÙHÍtfáž’²6LÃ]ǧÁÀ-%''Ÿ8qâÆ555ÕÕÕæ;ÄÇǧ§§———N™2ÅvÅ)S¦Lš4éôéÓz½þøñã)))JyJJÊŒ3JJJŠ‹‹SSSí‰*--MÝ?99¹aœ­îSQQáíííë뛟Ÿ?yòdµüÑG}öÙgKKKKJJŒ¯H¬“=­ujc5cÆ å*ÊÔÔÔÇ{Ìv_ãÇæ™g ÊÊÊŒÛTVùnܸqåÊ•MxÈÖÞ3ÖÂ6f1Ôú¾Lλµ·¥Õ­-¥l¦3 § eШ|pôèÑþþþóæÍÛºu«ùo¾ùæöíÛƒ‚‚î¼óNã•É+Λ7oðàÁÇ÷óó;vìèÑ£•ò矾}ûö;wîÓ§ObbbQ-[¶,444666...22réÒ¥ ;Y³f%$$¨)ǦM›fÏž0lذ!C†¨u—.]Õ»wï¶jÕªÎîì¯h­Skì«Áƒ÷éÓ§K—.aaaK–,±Ý×âÅ‹{ôèßµk×.]º·Ó±cÇÌÌÌ-[¶Ø3Èv²µ÷Œµ°Y µ¾ï“ónímigukšéÌÂ)<åZVÀ%p-+¸¢&¿–̲֜4Š” Q¤¬šVçó<4¨YcvÅSðVq¤¬°K€&ÉH<¬‘Cg£:'CÊ €æÂ>ÝgCÊ  -UUUO<ñ„¿¿XXXzzºZ^YY9iÒ¤      É“'WVV*åÕÕÕóçÏïСƒŸŸ_JJÊõëוòÏ?ÿ¼wïÞÞÞÞÑÑÑ6l0ïH§Ó­_¿>::ÚÛÛ»_¿~GµÑ‘2«¦Óé,N¯Y‹YÝY§Ó­Y³&**ÊËËËFÌ7oÞœ9sfûöíCBB^~ùeký^¾|¹}ûö¥¥¥j­:”””‡dñð­õ«†§ÓébccÕ|Ì`0ÄÄÄ=zÔZEcyyyIII>>>#FŒ(..¶6ÎöÄo>ÖNµSi>t6ßžêÆŒÏ¬Åw‘ÉÎö¿ÓÄìÝ¢ÓéV®\Ù¶mÛ°°°íÛ·¯\¹²]»vaaa_~ù¥í‘‡{ eЖE‹•””äçç9rdçÎjù‚ Ο?êÔ©œœœüüü… *å+V¬8tèPVVVQQQëÖ­çΫ”7nÉ’%W¯^ݳgÏÁƒ-ö•‘‘±wïÞ²²²¤¤¤‰'ÚèHÉâ ƒÅé5k1;pà@VV–^¯·ó’%KŽ;–•••››{öìYký†„„$''¯_¿^y¹sçδoßÞ¸;‹‡o­_5<ƒÁЦM›]»v©-‡„„ôíÛ×FEÕ¨Q£RSS‹‹‹‹‹‹{öì™––fmœí‰ß|(¬‹]X:GaOuk,¾‹ìÙÇÆá¿[D¤¨¨èܹsË—/;vlQQÑÙ³g—/_>sæÌ:Gn€ç²ÂsYÀ5ùsY###333ccc•Æ»wï®|`‹ˆˆÈÌÌŒ‹‹‘ìììÄÄÄÂÂB‰ŽŽþôÓO{õê%"EEEñññ/^‘Î;§¥¥=ôÐCQQQ;Òét¥¥¥íÚµ‘òòò   ›7oÚèH§³úÑÑZÌjNwþüùððpek1wêÔ)##ÃäO¡I¿Ê˼¼¼!C†œ9s¦U«VS¦LILLüãÿh\Ëâá[ë×8¼×^{mß¾}ï½÷žˆ$''ßu×]S§NµVÑšòòòèèheºÏâ8׿š°qj,žJ“¡³qøöT·xR¬Õ5Ù¹¾ï4ãw‹N§»téRÛ¶m«ªª|||Ôm5§µ6ò$;n€³h)+¸¢&OY½¼¼ªªªZ¶l)"z½¾U«VÊ6“r___ås¿ºƒÁ`¨©©Ñét555"rðàÁ¥K—~ûí·¾¾¾ëÖ­KJJ2éÈb*h£# €µ˜ãºÖböòòª¬¬T–ƒÖç#<2jÔ¨”””ž={þðÃ>>>Ƶ,¾µ~»¸|ùr—.]rss Clll^^^pp°µŠÆöïß?gΜ¬¬,eÁ­ÅÆíßâPØyjê;ìvV·xR¬Õµ¸³ÉËú޵m;G.Š…ÁÚž——§lçææªå¡¡¡Æå¡¡¡êþùùùz½¾ººZIE”òÛo¿}ÇŽ%%%o¼ñÆÓO?mÖ:j@Ì6ö·sxx¸=Õ³gÏ^»ví¾}ûþçþÇ$ß+‡o­_c!!!÷Þ{ï–-[¶lÙ2räÈàà`;+Ž3fÚ´i555W®\©3Y²¿Å¡hÀ©1i³Î£p¤FŽª¾#×BÊ  -)))3fÌ()))..NMMUË“““ÓÒÒÔòääd¥|Ê”)“&M:}ú´^¯?~üxJJŠºÿ‰'nܸQSSS]]mÖ: ÎÎήWÌÖX‹yüøñÏ<óLAAAYY™Ú޵~üýýçÎûøã[< ó÷֯‰ &¼õÖ[7nœ0a‚ý+**¼½½}}}óóó'Ož\ç ØŽßâPX;5Ö˜ ‡o­z“«ïáXSß‘‡k!eЖ矾}ûö;wîÓ§Obb¢Z¾lÙ²ÐÐÐØØØ¸¸¸ÈÈÈ¥K—*åóæÍò‘®ÅÒŽŽŽ¦¦¦ŽŽŽôhÑG}ô’K.YºtiåÌáµÝ­ëÝuLÃvM@¿qb0lþà çlá>6lذ•+WVn?ÿüóÆ ëúPíñ]wݵr{øðá/¼ðB{{ûûï¿_©Ö^‡ýâ¿8cÆŒ—_~¹££ãÍ7ß\og®cýF²Àf0XbµÖ y™õ0yòäÙ³g¿þú믽öÚÌ™3'OžÜõ¡Y³fU.F9sæ©§žZ98}úôsÏ=wÅŠíííO?ýô”)SzöüãV[mµÍ6Û¼ð çw^×ñ¡C‡>ûì³5 €~#Y`skê~êlc$/³®ºêªaÆ3fìØ±#FŒøÚ×¾Öõ¡‰'~âŸ=zô®»î:þüÊÁyóæMœ8ñè£ÞvÛmO;í´SN9¥×ao¾ùæ9sæl¿ýöŸþô§8∮ã_|ñеQð†L ß¸ö âZV¸>XeíìQq ù¿ÙÞJu0_Ѻٯe]WƒPs½'¦çO©ëh0ÙÍ€¸ÐÎßWƒè Цš?Óíº¶/èŸ=dÓ€hÔnzÎYÄl•¢ëʹ¦šƒÎ`X: H’úF·Å‡þùö®ö¹÷¢G¯½ºjÕªþŸÉFiiiév¤µµUµx½†kHõõü—d@L»q9+„$+ÐhºzµüFí¦Û„+«ZDÏŸ%•Ü®½þÌ«Ày0Ø1h(·W{j€—@w5o]šjÞê¨×iô:aèGVY$özÝ»¨?/]G! TŠa• \•öˆ[I±Ö±ŒÙÔ—o5¨«¬P†n­Øç «SŠ'Y Hzœ @±$+…’¬ʵ¬@±›·µµÕ{ @#³Ê ÅXž“l—l—“,¯ïL.IvJvN.µ# e)¶¥€Æ`•Šñ—ÉIÉÿN:“o$_N–&I¾“üKòLÒ™ü÷darNgJªüjÖ2µ´´Ô{ @ƒ³Ê ÅX–\š MvJ.K–Uÿ ¹*ž´$“ÜRÇ)@¿’¬PWM5·OH®MÞLÞH®Iޝ:9 z{ÿäé~ Ô‘ƒ¡ßLK®L’ŒNþ_õøÛÉöÕÛ;$oÕajP’êªv/¥³’3“ÙI’ë“©ÉÿM’lŸ¼ì˜$y+Ù¡Ÿ§XO›¼µk,7MÉ×̓“ƒ¡%—%C“¡ÉeÉCÕã’Ç«·ŸH&Ôgv ---j`kZÿ]za[r &Y¡®j¿¿œ\¼‘¼‘|=Ù·züŒäòä•dUrY2µÿgYoÞúënÓþ»¶%*y0Y¸yçŠd…büCòpÒ’´$'ÿP=~~rx²O2!9"9»žs6³'û&[%»'ß©|?¹4ùx²m2%ùÏêñ¦dA22iJÆÔjg²gòdÍOÁÞK.Jþ,Ù)ùÆú†µ-9“¬PWµK"ã’û’ÕÉêä¾dïêñ¦äºä÷Éoê‰S[[[2¸^ru&®îgg$ó“·’ÅÉ¿Uþmòx²4y5Ù:™[sÿ%ÉÒ¤3Ù1y zðþd§äÏkî6?y*Yš<Ÿ¼´¾amK@Á$+Ô϶I[òj22ùnõàÂdA2"Ù!ùzrWÍý¯O>–$9+ù^õà÷’³Öö‡Éß%»%;% Ö7¬mÉ(˜dŠf¡µ.,´öŸ»’û’ý“‘É=ÕƒmÉ~Is²e²kòZÍý‡WoœšüSòÉ¿'ÿœLYsØW’=z<×Ú†­lK^1ȶ% |’€6aêg&ÿ˜¼žü}òWՃÓ’öäý¤3éèí;%Ç&·&·&'$C×üèðäùYÛ°¶% `’ ,´Ò&'Ï$ï&ÉûÕƒÓ“s“I{òtÔ.•sƒö8+8É™ÉÉËÉÉÌõ k[r &YÒ}pn0ýÆ&Lýé¤ä”d»d^r[õà¼dbrt²mrZrÊZû™äÍäíäS=>ô×Éød¿ddôú†µ-9kêìtlNMMMIÍÙ••µÁþùï¬ö¹š’нÖÖÖÄ9«ý¨)IV­Zµî{U²¶a¾Ì>¤AýUÚXÿàl‚åË—'9òÈ#ë=€d•ê¹ Ó >!ÙB+Pw’–&{ œa7-’;“K’’“K?ôZßà\*Ê#YáC-´.JNܬ³éÓa7-¿“üKòLòTò`²póÎ  >$+ô¦ê[·wûô­ö¹¨uorb26Y–$y)Ù"©\§¹,›$y?¹4ùx²m2%ùÏš‡_“ K¶KÎJþÔcØ$?NöM¶JvO¾SýèÚlJ$#“¦dLM v&{&OÖüõ½—\”üY²Sòõ ûƒäªdxÒ’üMrKoŸ‡•Éç“’!Éñkþ¶ÏžlÂ@²ÍÆùkÉòä/’ã““$‹’­“EI’’’$›<ž,M^M¶NæÖŒ°8y2Y™¼’\ÙcØ$g$ó“·’ÅÉ¿Uï°Ž—$K“ÎdÇäêÁû“’?¯¹Ûüä©diò|òÒú†}:9 z{ÿäéÞ>ŸMf&¯%¯%û$³×ÿɨ/;CA|ðÁ${íÕ×G6ˆMÙ”õ–äÞäÎäÇÉ’ÿ•LJöMžIþOò—É´ä¸d÷äÞdB’äÕd¿ä·I’¦ä×ɘ$ÉòäSÉËk›dT2;99Yó¼ëpU2y»zû­d‡êíÚóÆM&&Û'MÉvÉïÖþI«œõ”D²ÉFoÂô^r_õÔßm’½Nö™™gIDAT“o%û'C“ý“¿KÆ'C’$Ó’öäý¤3é¨deõÆóÉ®=†Mr`òÉëÉß'U=¸Ž»ì”›ÜšÜšœ ]ó£Ã“ç{“$9&¹:9¾ú¡éɹɊ¤=yzÍÏYÕë?g&§ö6ìää™äݤ#y¬uVò½darV™\¼œ¼‘Ì\ß°g$—'¯$«’Ë’©½=ד­’m’’óÖ2ŸnlÂÔ•d˜[h­=}7ÉñÉï“£“$ŸIÞ¬IÖyÉÄäèdÛä´ä”šGML>‘ŒNvMæ÷6ìIÉ)ÉvÉ¼ä¶ °Veo'Ÿêñ¡¿NÆ'û%{Ôœœ¼¶aÏOOöI&$G$g÷ö\7's’í“O'G¬e>%±ýÄöKh#ö¹Ù+¹#ùo›{}4l±š’Þ6a²ýR-Û/ æ¯Û/ôæzO`S5m@,ï›§î£aÈÚÚÚZ[[?XÿTá:è{€>åÄ``àñÍ1¥kÚø_ <ռ̙`s³Ê Àút&MiiiYÛ/h¥¢òÔÿŠ·^q]3Èý €¾#Yé¿NÂlÈ` ëê·Úµ«îàkU©Ðï$+ÀBëÆk¨EW± @HV` ²ÐÊ€Ð{¸f€|Ýö¸"W¬ÐÏ$+ÁBë¦é®)»]{Û;J¬P’ø,´öÎÁ± n_ª­¾^Ö]Sׯd™ @‘$+0€}pn0 @ÝwiªèÖ}Z°kÿ„R ’€ f¦>Ð{»Vôï²¶R @’ØlÂDÃèVŒýpF |’€f¡µèIH²E½'ða}ð½ú‡Õl IV %Yb¡µt&IKKK½ç4>É 4Wý4$É @¡$+Ð lÂÔ¯lÂô É @¡$+Ð8,´ö+ ­@ßk®÷ú€jhVYØtöjú”UV ¡((€Fb•€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d P’€BIV %Y(”d ÕÚÚÚÚÚZïYPO’ÊrÔQGURm·Ýv›8qââÅ‹7ðµuwï½÷~ö³Ÿ3fÌ^{íuúé§?ôÐC2¢E‹;ì°Q£FMš4é'?ùIåàøÃÃ?|Ô¨Q‡vØ÷¿ÿý®çêµ'Ÿ}öÙƒ>¸Û£n¹å– | Ý´µµmÚhÍõž°†xਣŽjkk{÷ÝwúÓŸ^xá…¿øÅ/6j„;ï¼ó¶Ûn»îºëÆŒó‡?üáöÛoŸ2eʆäßÅ_|óÍ7pÀ<ðÀ´iÓÚÚÚn½õÖ{î¹ç–[n=zôÊ•+çÌ™ÓÑÑqÎ9ç´µµµ¶¶öóÑG=äCz>ª³³sÚ´iõ* VY¡XMMMMMM•ÛË–-;î¸ãFuÜqÇ-[¶,É 7Ü0a„®¥Î®?—,Yrã7^ýõãÆknnÞyçg̘QiËÊO<ñÄÊ—-[vì±ÇVÖT_|ñÅ$»ì²ËÏþóÕ«WsÌ1•‡ÜtÓM×^{íØ±c›››ÇŽ{Ýu×-\¸ps~ôÑG=ôОúîw¿ÛsIN<ñă>øG?úQ’_|ñK_úÒèÑ£9ä;vØžS`¬P¢ÖÖÖÑ£G_}õÕ7ÜpC’™3gžyæ™Ï>ûìÔ©SgΜ™ä[ßúÖµ×^ÛÖÖViË®?:è ßüæ7»ï¾{Ï1+÷ùêW¿ZywÖ¬Y³fÍZ±bÅE]tùå—'Y¸páOùä!C†|þóŸŸ;wn’o¼ñ†nX°`Áœ9sŽ9æ˜Ú;1â¹çžÛ{ï½+ïV–4»üä'?Y¹ý«_ýêœsΩÜn»í’Œ7náÂ…ï¼ó΢E‹Î;ï¼%K–´´´¼øâ‹{î¹gån+W®9räÚæ¼råÊ-¶ØbÔ¨Q­­­ÝU{Õk×*k¶o½õVåø/ùË»îºkë­·ž4iR·—ßsª VYa?~üÝwßýÎ;ïÜ}÷ÝãÇO2iÒ¤ŸýìgW\qÅ\P¹Ï!C~ýë_7nÆŒ³gÏ~òÉ'ÛÛÛÛÛÛyä‘®Œkí³Ï>wÜqÇK/½ÔÖÖ¶|ùò$#FŒX¼xqsssKKËÛo¿äœsΙ;wîsÏ=×ÞÞþÜsÏÍ;wÆŒ=‡ªé#}z·GMŸ>½ç£nºé¦;ï¼óñǯ¼»ï¾ûÞ}÷Ýííí2U «¬P–£Ž:*I·Í,X0kÖ¬yóæ?~Á‚©VâСC¿ò•¯Tîóå/ù„N8÷Üs§L™²õÖ[_|ñÅË—/2dÈX¹X´ëz×ÊÈ ,˜={öSO=5tèÐSO=õ’K.ùö·¿=þü+V´¶¶^sÍ5IÎ>ûìæææ©S§VVM/¼ð“O>¹v¨Ú™?öØc‡rH’3Î8£££ãôÓO¯ìÒtþùçŸqÆ='0uêÔ“O>ù _øBåàÃ?|ÑEÍ›7oÇw<í´ÓæÎÛuÿûï¿¿ÛTûöï€b4uvvÖ{À|ðÁ${íµW½'ÒÝK/½4oÞ¼o~ó›ûØÇÖvŸƒ:èöÛoï:`ð¨œrä‘GÖ{" ȉÁÀú9rÚ´iŸûÜçº.=íiÉ’%z€ÍË*+”¥Ø…VÖÆ*+@ß±Ê @¡l¿%²/.ÀÀb‰ Xe…²ø¦`ÀñO7@ßq-+…úÿ~ð€}ª¿+IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/site-templates.png0000644000175000017500000006033010010213367024725 0ustar frankiefrankie‰PNG  IHDR›¯›ó‰ pHYsaa¨?§itIMEÔ "ÁßM IDATxÚìw|eþÇŸ™­Ùlz%…„$4éU@P)ží°{*zêyzÈéï<ûyŠ‚wêyÖ;{/§`CTš‚ ½HM Ùô¶}§þþ\×-³³»³É&ù¼_¼Â³³3Ï<Ï÷)Ÿçû<ÏÌ€žåûAEåWZ,–¹ î¸ùæÛ`D ÛÑJÿíܹ“¢¨={öÐ4MQ”ô×úQºpרHE§"GrèuFì ,Ž£Fa„NØ0EEqÏž=ar¿‚ Ì]pÇÔ™7D-)ý ÿpyi¿íþo},bó¯G§Ýr×ú¾#®ÞüvYÆ–GŽÓÒŸ|v­ö=®0ì›àH¯Ea„FX>|ÒGW"áŠNx.j8û²;_zûŠ/~p±ìè Ç"9;~xsô„Kz·ÿûñ™7-ýÆ/¿1fÜ7N9?TE"Hß}÷m鎾ÇŽGð;îö&Xæ„Fa„£ ûϺ_rŃ„ß~ÐoŽý¼ßÜIùrå ïéBAø•¢÷;}â=óÒ«VmZþ=¬œL4ÓW¯ÞœR6k ÙäOÆðÜŠÙ7.YÝüÜŠÙŒ½á÷íöÙpH]ÿÀÌqfM »qÉê=Û?9î¿ü*4Ýs+fûÅgPU©ºT”ˆÞ;V”ˆ‡ª)ïqo<~Ç„RVÌÊžƒ0Â#Œp4á_ùè’œB.XtïÇï=ìuÇ%9'„Ì™¿dÍgÿôÝÇó¼ZQÎNûè‘5óo+<öщâ¬yIÖP 7ȨÿU$Ñ4’=Û?6za7Šú§ŽôYÜÞ/¨S${¥ v SGHÿè6lôBo6a™2}±_l~qÊPqr$H!ŠXoØ{|Øè…Aû… !‡ªùsFa„Ž"ü+Ý·_xñÝ+?xÄWÎý¼ù@Ñ\4¬Üsü¶uÿK¾ùÉkL¯FH'ýç©ù×ÞºÒ{šôñ?OÍ'„l\ûQ´îÜKÆÍ›m"ìíUÏ¿wÄ%œL›o2(Z¿àòñ3Gej÷¶õûN;gb`Tò¼ü÷­ïÜ9öå{[óLBÈœË ¶¼øìô;o•L'“ ßH¤›ú™Ñ×GOÊȸè’*R“4b]¥å¿/í>gèÈó|cðÆ)oÿÕkÚù³§~ÆÕ×\wñÄtpxgåí¯¦þóÔüG–r¸šúÏSç=µêøågd˜$ꮼ~ÂøA' è›òŠþâaïèa„Fá˜Ã¿RôÞzàÂKïóöøó/ü??=øúó'ýÝg}Ò¢¢½¯¿ä¢ ¿y¯ùž;¿þ¨3Ǩ—¾:°çÓÁÃæxÏ<°çÓknæ^~æ7>^ãüó?>pûÑŸŽ×²7ûÎGæ6ßÛ«ûê:æüþ¶ÛÏ÷Üõ¥¥¨¿9ãÜ¢¦{ÿøŸ} ιW]U߸//;‹r×HçŠÿ{j籺‘s¯øû ßü¥æš›?òß÷î„¡MŸž~béõÏTÛÄ+î]rÇì½÷~ªÑŠ⛌=>ÅPsë5ÿ˜”?¡yï6Ç5 wþ«Y_ôˬ¸ð«©]ïÇŠ¡gIûžø¦R_^P6U§Ñ\<=ý…ß?¾³9¥ pìþÕÛó—Ÿ^³ü£’œ‹OK}á†e;›“ Gîþj«Ž­ä…tBÈÒG¿°ô+šÐ~°*){Añ¯LC}ã÷»ûEÌ/\÷ÊŽŒÂ‚ß¾¶cÑßO­yñËþy™~ɸp‚ùùë_;Ü‘UXPºñí¿›430ª0ˆÂ›ï4Þsgé'Ë<³¯.ßûú+­\†×2ɨzVZÅà¿]•ù·£M.óÞ4hà¦û7TWîÈ)Ò?/¹êû=žQWûViÿ¿´H3Wþþ}¿²kÿ3'eBè³ÝBÑä C×¾±cÑÓkÿ»fúø´ ñ )¥O–òüâW¶gLž8`í›Û¯?“RZÈ>ös,Fa„V%äyô•<"ïõÑKÏ¥7¤¼õÙÓÞKn¹”»ã3&égOÑÏ;ôu1¥ÀA_XX !¢Àsô¯<âîEÂÙŽ|Æýu]{VÉp-%ŠD›’=Jºü¸G(..ÖR„çŠÒ œEà†òJ !ý ô7õÖìÒQ"²ÎfqÛqDÈç—Œ½Î"&°®Ö ¾ñÂ")pùâ·ƒjzÓöÍ-—/œeZ{A®íÒUûLyc½ñÈ$ØYt÷ÅOÞñß½ LaiE ¹|©Êž\röþ)&=ME‘wU |®ü:zÙ ¾Q…±¿ãÈ‘c„­6vøÅuu„P-Ú¤éŒõБcãN®¯²ÞxõŽK ôZ‹uøi#ëêDB4à‘c¼wDyä…0Â#Œ°*áàO¯}þñãç,\êíú¿ùâ©PÜ2ŠÖ_wšùËîX]g•Žȩ̈|õÁž7?Ôg¤1I¦)éL>5”¯IÑ!¤Òͯ¸ðÖ½Öwí›ø*7?Ƥ=FÄ@G™þùZÉ3æ^z§mP—ú¸G•¬=A‰¼Àë’ûñž6Q°ý2ßðsTÇ=“Ö"fÊ:Ù°èº7ŽÝ …K*μǹŸÿ¸uÙ3zëå:·¡¿Ië'T24†ôÛÿoÂgË^ýæP]véhJx‘ÈøèºmüÏ¿ûðú]ÍV«@§~·æ1Qp͸o £ kBÈÄ݉:B¯KÎç™V‘ÿÅn‡,€Áż4r¬vó#MZïù¾·Ãha„FXÝpÈwÆ}¹rÅœùK‚zç>zöð©æ†¿±ØsJ&é“_½Û˜vÇàæg,¦o;Ø¿žÊ‹»8mJÚœEÓCùš¾áWV·üí¾ù¾×jiã2 rΞ7áíç>xîõ w<0ÿþWÛ<ú©óO_÷þšP+ÄÏ5²ÂÄlc½Ïñw_¾ú’k^!„¼¹Å¶ôî9÷¼ÒêÔ˜.žX¿ésŠNLÒ›?Xÿü—Ù}­Í¥1Ï»vb(§¿xÀ™ùçj¾úâÂö5´Ù ™£ÅŸ7– <*×ÝuVý»¾ñýs¿1zQðª÷Ñ“4TkÝÆÐ¿txáÜKfÈ'Fæ`Pû›=dÂDÉþ„;îž+%øê[&Z6|N(sàå^/üÛ=Ö¥wÏþë+mNùª›1`Yñ/£K„Fa„U ˽ö«OÿáõÝC*ºÀBæ]QðÝ㯠º"=á…ŸÕgý«ž¾mƃ·ì{ÙÆ?.¾â•[2<Öu«¾%§.$!§ö†|üÙ«³†Þòç©ý³–Æ/þ÷UGÓîÔìaß^ùñ…ãî{xFº†Y÷ñ·Ÿ¶í7¥ŒGúøì5¾ùTƒæ¢«^ò¯­ÞTX2qï«+¿¹tâ²'æ&SìO[wÿiÅ:©,0I{_ûtýÕ“ÿùä ãüá«âÈ™Dñóß~™Ò˜‡šý÷¨‡JÆÌbY|é¬Å—ž\õ÷I`"{øßÛÿø§?Ý”ov´wløl™²0T:åÊÛôèa„'~Êzè±Ù9Fqÿ–·?¹A—\VZÀ§¬ˆ|ýüª”+&ÿãÉrçøþóudй„ÒîèñŸgþ‹Â#Œ0ª„O¾¶¦¦&ÒwƵµµÍ]pGùàiRtÖ†TÖðîWRÁÖ6·Šyùý¶­³­ŽáB“Ìý‡ó‹ÆBNl—~a —õ¸ÃÙÎs"­3™R‹““L„"òÎÎc§•'Ú¤”’´”ÔÀk½kU‡½CÄÀ»ˆ„w´U9]6hõ¦œôŒ|šPQ‰"çh«t¸í†´ _¾yÖôóÍ/£\Î3¥<¾çû™+0À»::›XŽ£5FcJ‘³ãHà}ƒ&&0ª ö/*-ò¸’¥Ó†e±tð"­OÊ3"ïx-Ÿ2ilÕ JЧ¬H¬:! û8»²®Õ.Rz£¹¿ËzÔ{ŸsFa„Ž5|RÑkkk#UôÖÖÖ¹ î0ð4Ò«¹ÿ²aÿúè ]k^xãÂÓÛ>¹øáí¹ùå¤1 ˆTŸ@a„F8¡Ã'½®®.REonnž»àŽ’²S{·˜œ;ý¦ß Í3жízèo¯[Ä‚ŒÔdÈ9Â#Œ0‰>©è‹%REojjš»àŽ¢Òñ½^Ò8W£ÃÙ)ˆD«ÏHNÉ¡)Ò7PHªëFa„NÐ0EY²d @Oæ¤^__/}^±bÅòåËa g¡ zÔ+ðèÐ0EPt@Ñ(:z¥¢øº˜.K@we°GWã$¸å»=y¨™mì‡Åb±X,]ÖOÉßËûmAAAÔ© z­t0~9UnÕÓ×È{â(¤ÛXc©Ï(zxÕìБùõæñèÜU õDúlÆPôȜڸªrPïJJ‰ô•÷„Hï.ÅTD}Í ß ± Fà…~ ë2#Gt__‹ùVal¾E)ã°ÆÏ±ä½[ %ÐnEïne`üò’Üýæ4rà°†(˜";Ä ›ÌòG¼Í®VÞ»¥Ð»ÆD€Þ è]¼ì¨Ö‰lPï`"𯊦ˆëRz<&l¢6fü"Opb)H8Pt•û µD¢[º'_¥"]¿»8p[ݘcWÍè®U˜£  ‰6½¬V’]ÿn¬x€^«èpà ) E7‘« ‘'àôr¼“„ŠJ½a¦'>©,é‡ÂN9pÿ—tUìSî¾>_õžyOÖÄÝG÷ëyc‘´ ëè~s›A[ë|¬ŠŒú^q2rØøÃÞ7¢qL¤"í· §"ˆ:ïñ®J ½/¿`€¾ EE±¾¾^ú¼bÅŠåË—{?zœ×>zÄîr¼€P®[¼;¬îº¯ò”¨˜˜ÄÉlwé_¢å½ Eï+o‹Kœ~³ RÒÇE"³c’ úôYðÛkPt@ÑEzÁ÷º¯Y³¦z¼¢_yå•0 ÐãïŒzXG è€¢Š€_Рvð¸#@ÑA/᪫®‚ G*:Ïóõ–Ú†úº¶ÖV‡Ó)¢NkHËÌ*.î_RÒ_£Ñte6DQ´Z­6›Íår±,+‚V«5iiiéééEÅé¾vÒá –xXÂpËQ„¢hŠ&ÍóÄîd'æÓÌG˲¬ø3ÒŠ¢¤\¸\.ƒÁ`0bÏÔŽ½Ç×noëŸC&Œ,,-ÎU¥Т ‡)zC}í‘»“““óóòU”hµ:–ãívgskûO?íߺuû„ ãÊËtM¬Vkss³N§3›Í4M ‚À0ŒËåjjjª««+((ÈÌ̌ǭ›ÚE­1¥¼Ä`2Ò eÐQ:%ŠÄÊ4%~°º¦®#ÓÅ8ò#¼9Ã0iiiFr𦽒IQÇqG§ÓÅ2l:TY¿õ(Õ¿|°^¯ÛpбzÓ®òÝi&õhÐ']Å#wZۛƎ•™‘¡ÑÒ¡8žgÎhЙLI¹9YÍ-›·l«³4N=ýÔøùÇn·;???))Iº—(Š‚ h4Ng2™\.—Åb±Ûíýû÷WýîÙâñ¦ 'Y‰Hdž‘h4„&TGGG~^î¡§ÛYVúÒ4MÓ´V«õó})Š2™LUUUÙÙÙ‡#999:Q¯µ´~»Ã™[P Ñh’’S)Z'pùÕmܯïÍOe&):¨(vã¬x«5H…Óy§›Ë h{ÐÍŠ~äàNÎm¼~ãÓϘ¿Ô755qWTT$9¬’¢ÛíöŽŽŽŒŒ é£ÑhÌÏÏojj:~üxII‰º 0'ÑÍ­.^È ( D‰ A ¢H4I3‹[÷¶hµºŸ*]uuõCJ“.˜Õ/É^ƒµZ­ËåÒét¾r.ôz½Óé´Z­‚ Øl¶¼¼<¯ð+¤µÍ¶jcs~ñŠ"IÉ©·»½¥‘çÎh6§Ôw´¿ñi¥«sÃ’çö‹ibƒe<º¼Àïàò×N|±‰›39µ¼( ÍT$²§×ê-Ç­íM£FIKO1˜“iCj­Ç:öÓY‹·ß1~åÙÛ:·›“IIzƒAgÐÑcF¯¬ª;t¸*NI·Z­.—+??ß`0èt:­V«Õj[[[¿þúë;w®]»–ã8­V«ÑhhšÎËËëììlmmƒ=­VžáÃN ‚HDB.â`È)ƒûñöŸŒÂ‘ÒœÎÔôÌÏvæ]yß‘ŸªlJÝét ‚à;5"Š"Ïó‚ dddØívžç)Šr¹\¥Öîp¿óeu¿’rЦ–aÛ[Y–¥5z»­Ãfm'Dã謷ÚìþcÕæí‡bRtÖÃñÄï_KsÝ虯k9Zã@ó€îQtžçŽÜ;ô”áf³Ik4R´ù¸³yÆúÙCû—]3颉ƒG½Võ¡ÉdH2ê z­V«ÑШѣ¿]¿…çyÕÓ-Bsssvv¶äK²MÓôñãÇóóóKKKM&ÓÆ†ñúîyyy555êîÞbXa÷žC5‡$ç,OBÙ„åDŽ'Ùyž?kú´q3¦Ž^‘–š–‘ÖoÜÿª·4…‘ai±Ü+äR€eY†ajkk³³³‡ VQQQRR²,!Äét8pÀwŠW?ÞWXvŠ(ò†$3Ï í- ŒÇ£Ñœv«µ£M©ŽÖÆEçºáÒ±IZçS/®~ýýõQ[Œa<œ@üþ57ZÚ\º¢²¼w×4>n“7B4¿»x?F}÷®IvWÞ½{sÔ½ô弃^®èõuµÉæäÌŒt½AGÑÆjGÝôM3Îpê%ó3õÇ:j‡ç ×tz½V§ÕhµŠéiæä”ÌÕwÓm6›^¯OJJ’´Ü»<==Ýn·kµÚ¬¬¬¤¤¤7ºÝnig™´E¼¥¥E­4ð¼xד‡×li«m°sqºˆ R,G4: T£•úâ{ëïþºùƇ¾¹êPzšÑÕYEQtvÁˆg߯ _04Ͳ,ÏóÞMï<Ï744ètºÚÚZ§Ó) ­ ^9ß³gOXQ/Êâý´Ë`0Iâív¹hÞå´w¶·¼h·ÙgML›qÆø3§O¾ýúc'üÅÖ{}ÛfwEa–a}ôæÆÏ,úågžßøíç¯~R­¢«K_Þ·ïgÒn1EØb¥|ˆÇqz»¢×ŸÈËÍ×hiJ£©´ÕÌØpæœâ©×”ÿ6CŸþêOŒË˜ô§1K(F«¡Oj,!DJJÊ>EONNlƒ JOO¯­­•ÔÝh4~ÿý÷Þ©éôôô¶¶6µÒðîjË {‰1¥èhu Ë·G°Û·Gd9Reá÷W»ßúxÏð‰N=òÇ}íÞP”ÚÞÑÖ¨Óv ¹N§“d›çyŽãX–mhhHJJ2™L999ÕÕÕv»Ýív3 sðàÁœœ³Ù¬ÑhvîÜ)mÿ<½íØg{\×ÚTïtØiÞívw¶·ðïaùá%ÜÈá¾ëžßßt»N§½åºs/:»ÿÕ7ÝùìÑꆈ ⣿öì¼ÿÜnO·K—¯\ù}‰<æ}ðYQå8êè¡D°©ª­µuÈ 2ŠPÇíµ3Ö,œ\>zfÞiNÎùÀÎ'v7ý´ÛùÓû{ß'B„rR£RF''GòÔ¥Ü566–––æåå)Z†ùaËöŽŽŽi§ß½ïè¾ã­zCÒm¿›T6 ?ϱF£~ìèa‚È;ìvÆãv¹œ%F÷Ô;Ç0ò>:ç3d «‚é±’ã‰6åöîÒ«¢ÑÔJdœ®õ»Üo†<YÆôrE×ê v‡ËhÐýqè ç}uéí®Q¥§Pùt×7µõ„!ÄMˆ›!.rJÊÐE£/§hƒÇÙLáŸ<–D]¡œK.,˲¦¼¼¼µµuÿþýÞ I ƒÁ••ÅqœÝnE±¢¢‚¦ižç•<½-‰º¼œB.š™þʷǨè?ð4sº&#úßû›Î9+˜Œì¼ŽNB(ã˜Éc=nÁãìV—åxMž©é™?è—mT’Gisœ÷…qÒ¸Äd2™L¦¦¦¦ŒŒ IÎ[ZZ²³³Ê9!„ñx¬Vk}CK}CË„1ƒs³NlþqÛ°¡—Qže=ŒËn³Ô·«M®(æDãB¢éÚb÷ÑœˆöR%æÆ+™©ûÄ4cbŽÆèyŠžžžÙÒÒfJ2¦%g|<ëõ_^ÁºÙÁÅåSŒ[oÝ25Ò¿g<îr±v‡Ûát»<¡S´zs­¥¡ ?[IüÊåœb4N§V«Õétgœq†N§“v㉢¸iÓ¦¦¦&IέV+˲§žzªÉdÒjµv»ÝlVôšõyóæÉË9!äÜ3òÚ¬µ+·n/Úß`0»§§J¤YfË–†¼‚|‡Cl8ÑT}¸:Å(ægè& &¿YTkTZ6Z­Ëå2™L^Ew:.—«µµ577×;E‘ššj±X²²²RSS•Dëa<ƒ*¢†¢hžçJŠû>Zc4êže÷þ—Þl­¬v{†eÇÜ~5­×‘—–ÿ#…eyEgÃùè ŽrQ8/ݽ¹è.]„ ìu/*.:Q×är{ìw:Éü`æ+MÕí»þdu؇• úú؆‡×>iw¸.ÇÃÊ@i“õÆô½ûö ªþ ÞÓÒÒìv»´ œaiÕœa˜Ý»w744ddd°,ÛÑÑÁ0Ìĉ¥·¥êõzIéULÆç¿ôç¢ÙZ«6lvUµ,¾hì„ ²`î¸Ý[-›7üär iY†¤äA%æE F .˱:"Ð0Nçr¹¼ 6›Íf³ÕÔÔdggKÛÚÚ¤ÇÛ²³³wìØÑÙÙ6΂‚‚-[v <`ØÐVk§ÀsÆCQ£¡hšJNN²56Krîá8žç(J¤(1:’vÆÉüS²3.N¾ êN^P‘îN|Œvˆ4S2çw¥}àôƒÞ¯è¥¥¥V›³¹¥Óît[í®T1ý3_è¬vzD…êéNOOgYVú¥5¯¢»ÝîÆÆFƒÁÀ0ŒWÎM&“$ç.—«³³SZVslaÖ5)wä ã×;ä IDATÜ3šMG<¥H¼èœSδeýV§ƒ))tÐbZ³ñ(EkíŽ4L§Ó1 #Š"Çqííív»ÝWÎ-‹ôWz=;;{ëÖ­òqæææþîº_yí½òÒ~%Ź‚À{²è÷‘üú ãØûeßø}# u\I$A{jP7ýò© ›µH#4ÁJÌ{¡¨Rˆô*E×jµ&Œß÷S¥ÓÅ9n«ÍeÓ_˜ñ/æ8h{å‰}õ3 ¦»<‚@%QÚT½1[kHþàƒÏ?÷4Ný_a§iº_¿~­­­ÒãÚÌÏäååµµµ577{½s­V«×ëµZíÊË˽ËÒ*ê–ã)^ Xžð5rañ%%ýœ²mÓ¶öÖN­ÖÈp¢N¯wº#óÑ}·»×ÖÖ¦¦¦z弸¸xРAùùùuuuÒ[ùÒÒÒvìØ6Ú¡C‡þöÒ«^ëY™iv»Ýåt o³ZêÛÛÚRŠ‹K§NµZ†e‰(Øí¶ææNöP0¬‡å‰Ì?ùut™`~?5ê£Â­dJT'T„Çe¡Îu$TT2•-ìA¿TEy¨BŒ4aA‹5êB‰â8=‘È´¶¢bÀ KÃÎ=‡GÆ Å0©TÆK³_ØTóCajñ)y#ON¶'ei Éo¼ùÎÀ’¬q£Æ)é™™™6›­©©)//OÚúNÉËË›0a‚ÓéÌËËÓëõ’w®Õj÷îÝ›ššª|ûXä½>Ãñ"/RÒÆ~·GHÒR—ž²£x|íñ#”™L3Èé°‰‘¬k4ÉG§iÚl6—””=z4++«½½}À€ÒdCnnnggg]]]FFFggçÔ©S•ÄrJœ¼ ôAŸPtBÈ´©“Ö­ßôÝæ£GNKMEÁd4Ÿ5ø7„ÒR´A«7ëémï¿úÖ Y‹~3=®©/))9vìX]]]^^žÁpò:³²²²³³¥_#•&Û÷ìÙ“šš:xðà8ÚQ#:]<­Ñj4´ÇÃsOóBQ£Æ étx::ÚêûgrÍCHow—z™ÌÌÌ#FìÛ·¯´´4''‡¢(–e9Ž3 ååå•••S§N5•n»3f Ë^õæë/œ>y4˱<Ï:—Ëéá8†eÝ,kq8Þ[¹1¯°tæœEÆ ‹JÑ=YúhWh%}±B¨kv䀄StŠ¢fL?­ß¡Êµ¶šS2KJËrsû™Li´Vïa¸ZKþ}ëOÔ;ÿÜÓâçûRZZÚÚÚZSSc0ÒÓÓÍf³^¯§iZÚJÖÔÔÔÙÙY^^Gï\ò§)ârsÆ$Ýájnjéììp8l6k§AÃõ|j2—m>uˆ¹¬iDÑ ‚ Í2 ãt:¥_‚·ÙlV«•¢Õj“’’òóóÓÓÓËÊÊ"Móĉ9Ž{ãÕgÓÒ3œ.gSSÓ†ï~p3l¿qãÊF޼lâD…Ï„býÿîB€ÄUt‰!ƒË+ÊKª:p°êÇm[mV''ˆ¦$CA~îøe×.:=kç¡ÈÊÊÊÈÈhkkkmmµX,,ËŠ¢¨ÑhRRR²³³‡§µs_ zú‡ Ÿ™Œtfš>/Û{îEe7—¡U@RtÉA1lЈaƒ!4MgggK¯Gí.™?6ÑNœ81Þ)Ÿ>}úôéÓU‰*ìüQÑð«E=ž³Î: :t/4L@ÑE^‚ïŒ[³f LôxE¿òÊ+a Ç+:žDzXG è€¢Š€_Pô^÷Mß|“ñî»Fš¶.X0jîÜÀGõþýý‡ IMMí•fª¬¬lnn¶ÛmN»Ãj·BQ4MZ¤hŠÒäääØluç/¼´ätõ·»=¬0ö˜¾Ü*œNgM£=;7W—dÔÌî¶¶‡µUÃt\j2™Ðq¨‚ÅbÙðÑ2Íg½`ÆŒ½/ƒl~ì(`]T¨Ÿ1¢(¢KGhv_>+¯GçtíÖ¶ºF¯ÕhtN—¤×iuº&«±(Ã1a§×ëQÛCÁóü]oÝxçÜGü~;ô¿¯¾ÅQ)<ËÔÖÖüýþÛÕTô´>8sÜb6»6oÚAiÊæœíûí‘#G¬?\Á0ßÙl§<ýtiii/³øÊ•+gŸs~ÿÒ!fsªÙ¬×جÝ*^ñ ÛÖo6›~¿ä´nüQרI+žú‡íóg÷ÝVeiŸ4zpy¹†"òÒ›Nœ2sPÅ0Àæ ‡,õlûþ‰c†¡'Š‘–––ëŸJÒºÒr’=G_\GQjýªoâðÊ7ÎfJþW )ŠÚauù¬†ž-Kºü¥×fù;B5íGë³÷7‘²”ê´´4Ôù |ùå—ÏþùÉ¿=þÂm—ßæ{œaù;î\ÜÞêüàÃTöÑ4MR’ ’fL™²mçvšž}RÔ=*.[v^¿~Äé,Òj?Y½ºô†z™Å³súõ/έ¬´X,= ãv9†q»ÝZ­ÆétÚöÜ£-wÜA§=z¤qùCo<údOµÀš5ß žváÞZ݆ ŸL˜0_8þ*ƒÁЇdÆm˜2v¨›PuM‚^GçeÅ—_øÏ7Ì›“fk³;=¬Ád´¹¯Ý´oÆ”á茢¦½½}ÃkÞüø´ßYv~UYXÔïÄþÿ‘^§èÇ~:ÔöÝFÂBDâvŠúõ?’6¦€Q={º¥z/!Ó !'xŠ¢ˆNCÊûg\~û»W\uÉѺò3J÷çå塿rgÚõ«>ÿüóIV|ùå—}§iíÜ{txiFM‡pì›d¤S“ Mˆ(мlÇZFCÓD` z±•Ëüþ‡­ÑUà¸ÖUu›[œ°Ùl«ž{ðæÇ'’;õô¤â¤öÇœÀÅ)Ëݘ÷6­AôÌù߈ü¥¢p•(\+ ¿ùËDîÑ}.Û9ËV?E´ŽíÔšzzq̨#„Oi(‘ˆ¤µC „LÎíÚðŠØúÝæ½!dûן7m}`ËÚoãW¬‘æ½{›ÆŽ;š¬5Oý÷ÙsgõÙgŸù~•’šu×Ý·ó<£dÍ› E>úè3gü(ŠS·ýH-8‹è4Ôeóƽö¿Ï-–a•ŽEšiƒþ`½eÏØ±çœwžŒ±,KÐp‚C‰‚†Š vlÛòÔ“ÿxì±åãÆËËÍŸÿÄãé³fÖÞzÆî5¢ ² ¯Ó¶ÈÔ•DÏ5ëÊL3 D<¼sÅœÁÛšO¼»áýBnÿO{dœ¼vÕªë¦Ný×gŸ]pÁÞ<öÐ’õ>©ÒÂé´´H ¼è¾2Rº,B‘‘‰H gÐê;|K¹wX Þx<ž—þv×#/ŸJH ±íhÝb©l²9n,~cYY™L·ÛsÍKiýÌ9ÄDEx‘§išòƒ¦‰ØãûLš¦-'ªÔÖ&dæÐ¹Ytcá ©ªæÓ²é‚êé×-;û‰ì¿=LÈLJö·”NEk 'NœØÝøÃ=“ŸÑh4Ï}öà°³+öìÚ3räȓݑ£ã¿¯¼ÙÑÞT>x¢ò8µÊO-™yæVB&¾ú5&©oÊœz*©o!„j¬­ÛÜ¿ÿŒ;ï¤(*ì¨Ê[A}kjÐÁ¸Ì]Þ%Šthžç¥“Ñd6™LÉæT­ÑDë’ÊËʯ¼òÊY3gÜrûR­†ï—WЯßü°Fɯd¯¡üì´µ«˜Ó£—²Ö—--Ôóã&™o.¼5-7/» —OÒNcÝ‚ÀVoÞ,Âi4M¾ÿÞøÕWägE—Ï]D)å (9?v ´5µ ‹D"pÓRv†Òè !‚È–'û’EƒFt Oo¡¦o\tç4ÂoÙñæ¦A³5[QÞ)o±„jŸìzkâìQO|÷g"’Ô‚´Œ¼ŒO¾ëUôÌìÂß]}!äý¿ k.o@Q úÏ<󳺺É/5}2ik# SìØ§{®9e®ÌÏèAÃa‡öAK]Iñ¸=œ‹!¢¨×jÉÉ©¦äT½!Õœšc·;”U¬úbÝðÁEÏ<ûÒ¸1ã£È¯Lvä³ÊnQg³³­süÙ£mã¹WßIH=Ë:X‹g<‚Û!ŒÛår»]„¯>ù¤2)ióÆç*˜ •;ùJé—‘°•X5 ´ËëW@ÑÍ ÄE <¥M%„P/0Â2<Çó‚HXž¯«­Xœª°”½Ób2eu5jL™9…÷U¥áø"ÂcK—>ýÎ8BÊ%9¯jqüø“vÂÂÛ o¾Qè-DT.qê4$Rt)Ù¸äé{n=Μ8}Æô¶Ïy-ϲ,Çq<ÏŸ”v^ˆ¥ßÏuD *ÆüdòÍ IN¦?ßA>YñèRæþ«.ýӇ⶟èÏßýþÉ‹Wf:©9´¾å‚ßž5 Òµ™l†ê7¼iØl¶úÜ%«/¸¨d.!¤ò`å¡âÝԘΖ–éi©öö¦ÿ¼ôŸk¯»–ñ0L–DÔlªªªFìߟ5êÒØBì.b³÷KK/klüáóÏ»l¦"ê!Rà… £b9ÖåEJoÐ'š²9Ü99ý’Œ$=+söœóN\ÔÔÆÙíÎPµÍKü²¦J69ž³vXy–'ÄAˆNÇ»vïØðÉÇï½ôê½·ÞW¹g·F«#„8íöäü|‹Ç“°sYQ[ 8SÓØÜb³»žw±¬ÃÍY„ÁÃx\nÁÃq‚ r¼päÐ!Wlj ÌŽSQv×,k¨ûFmO/¢(>¸déÓ¯$d$çÇZœë¶k&_x—*r?ÛÆ˜w'͘fNFd2Y‡‹sp)Æ"?Q'¿vÒ}; µ*CÔ‹ÓÊ0¸Ì°k¿‡åˆÞ@rt•ÆÁ©>Öï¡«}´‡L³ž>èÌRBªø§ù·‹õ¸éñx4÷×½•JežwÞy#FŒ1bÄÂ… ¿û¢ºâŒAo¬~C:!;·øÚë®%„8Ýî¸ÌºWWW§?õTɨa¤­ƒPT}õñ~ié¢Õ6sàÀOž~ƒ œ1o^ԃ배ÕÝHï%Ëå±Ùl¼(°?{ÖtÁÓöÄò¿ÿýoÍJ3g¤™hB8ŽµÙ¬]Ü;Ëä%ºlŠ<ÇxœÉ)†-ß®ºõÆ»ÿŸ¡D7”ØìØR¼ÕùÅf2ÿú¿fee%¾ £Ë{eeå§µŸ¶”4>¹ïÍ+¦Î7 BÄÛ^ü“†ÕüþÂòóòN§¤ë,Ëúͺ‡r¾#m2r®z~ !%%%ŸÿÐ:°¸`öpòתK>™W1aàoƼ{Ç=[^úª˜Ø±ø“å6¡Ù´fÍá­ä… zì;‘›ÆóÛ—åôËLÉ~ÿÑe[…³Åܤ§öÍv:ï[tËMÏ<ñï }ÂùRkcÍ›o½{¢¶6#·\yÌŠfÝ«««-÷Þ{FzºØÙAœ.KUõw9yç>ù¤ýÊ+?Ù³Ç(6Û5¹¹ >úåÊ•±ÏüÄ{èiœn—ÍjeYF¯ÓTkœ;gº˜<ù({ÎUKáó,ºùUµK»çzÄLQhgÜNB‰­mŽS'”:­ÉÈê˾>QcélnÕh5„¢ÕrÇF2¤îàZyËŒ®²Ÿuú°qe:­ÇÒXµ+]ßÐÚiEº¾±‰u4üî²…}ö-°ÑÙóÐŽ•w´Šmë…ý-Çšï¯~û‡‡äåÜoK ‰pÏD"t¢&ÇÖ’k…o¹Ž¶µÛ;œvФ$I!ß}ûQQÉKcóÓQtF³B;Dšq…{ Ô*kÎӦё†f¾ˆ"%Wí¾ýÎÊå1ÒZËáš«—Ÿ|ŽL6UQ‡îz¸<Ò”?vñ K§>zçi½uͧ]üÙÃûÏ¿ü !‡4Ô_˜?í¹Yo™L¦´¬üË.½äæ[ïhmmSn.E>úæ\b6{l6ƒÁPÙаµ¢bÚŸ—R5iΜ ‚ðòòå×ä嵨lKÓÓï¼çQ«{Î9AM¬|kºÂªtì©ú6N·ÃiµZ;;;ÇO˜’››?íôñ×Þð‘G+*òEAüŸç¶7¶ØZš-ÊË^•ªžMZCÆÝieï½¶0GÛô¯§¾»¸iìét&ï±Í=wJùÈÁmGª!<ËR å 2TáúÍ_ “8ï×õÍ”7þ]'tnFô°|J²I¦,"ê’Ôª ×"î]»Î¹nÎÝ·}R\¨;aë÷»%&''Çb%õ$¢|ÅÃ&ÿ÷ü§Ï|z æØG«?ºnÕq¼;m1 %\¦Žvÿóî¾*ƒ")Eé ¦¿,<Öÿ‹ºž¿:àvZµ:"ˆ¤¡EX~;=û²Oæ|¾`ö42íòâÁÇ^ö{BÊb¬ØQ÷‰Ö4N °V{°©ù·[¾<îl4v°š“;%ÛZjÿùô³—_~=ÃFà>Q„Qëëë¥Ï+V¬X¾|¹÷£ÄË3fü¥¬ŒPÔÍ#FÌ¿÷^ßí߬\Y¿lÙÒÔÔ:‡£PÎ÷xþýã½É5¹ïþ‡Î™wIuuUFFFff–9‰<òº}þo¦õ|s ³ní9η®»îº!C†ôèl~óò_ó{{öÂÅWoYõ¿Š!SÒÓiJhm©o¨ªimhf˜¤óþX¿zõ(“é‰å˯\µª+ç“»‘ÍÛöÖ»ú1œ§éØž[¯™K€b.»ì²×—-4r5+7uŒ‰g}ŽF£éSXñÒŠÃç~ßiwOøræ’?,éÝ™}üÙ¯÷û+šN¤x`.Ô¼ñèòΪ¯®â«ÌTòÁ‡;n¹¸…/kß~ûÒTî_Ÿ}?ý¡‡wìØqeÍþUÇšÆ?ôwBÈëï¬Zzû⃕ͯ¾þÆoø­Ò!‚’“’,xï“OÌÍá©S/þµœBfΟÿ¥ Üyß}ËRRˆÇãŽö1¶„…'ZŽ ‹ŠAÜ»gç±Ê}B³nëeå…Mõv]Ç÷ËŸZÞ ²9ø¬k¿Y‘7¸œjÀ Ššƒ›V»F“œ›QzÚ ³K}ñŸ|R]Zºñøñ+ã£â]nà‰›÷Ú«ëÚ‡ „¢+›õùæ›ë®»öì³Ïî›Z.qÞôóÞyúMžç-™×ë3››“ò؃ïð®ú4WR’^ZZ8y\Iff&!#Ñ‚rÆüùÏß{ÏhÞ3¹æÄêÁCÖWW‰ôƒ6ãFŸrÏý²¬ÛÉoe)šu@‚CÃPt¨DÈqkÖ¬u€ží£C΀ï£××ןuÖY0 гôzúõëW__߯_Ÿ{ÛË@ÑAo“ó¾)o‰ófYè EOœ-îZ[[ûZ–û&Òî>X½Ñ¨QÐ(è>’å Š¾iÓ¦>e 3f¬]»¶ïäwúôéò'¼µVxPC‹§c ³{|öû`õ¶X,hÔ(ht_Èr_Ÿuß¼y3œW?XÆó§Ëý…pùk'~8 =u_”ƒw z#×È2rˆYV¤èÛ-#Ò”0 ýXz’£W®fùEg=ï°¥¹nÚ”±ë·5œ1\(ÎSm ÝZ£¬‘ëH™>}:ˆüV§û%¼nÝ:4²ÜCë¶¢®9”ÓVK‰bM†ÉÕwüÔ^œe/ ãáÿƒÍ–6שÅeyk¶ÕÌ'”äëcWhéänߪÖ7˺OåzúôéëׯŸ2ešôqÓ¦_Â^Ö¯_?mÚ4BEQ¢(¢ ‘åžX·Í JN›ß¿–溱£²¶ä·ÙýÖÛŒ3zœŸc–{l{`óÞÜxâ™åO¿üÌó×~±rCGèke×\÷¬ÆNaY2eÊ´õëׯ_¿,Çx7 E>ºŒÓÖ¿¢ßþýÌÐü¦ì60éêîYðµE¼wCD—åPé j ïÁ°ù ¬qÍ>ËÉûkÏþÁ^öÜò>wAAïsb¾¾¸ï9Wù|þøyó}³¬cÏuÚ‘ä«Ó~ºNG¼3–ÒqîWï]Üú¤ «±ºý¹ŸUÕ5iY*´=¢ ýê¶ÂYw&paUrÚ¤°sÂÔÙ£ãë·ùÕ§xoqŒ:Ë‘¦Sáù]Y·X&È:ºß ±ßÅO¹ý†A‡qzš¼o–u"4ê.fÓ¦õ^ÙöʹŸ¨¥Gï¦NØ‚Ž_E–½wï¡›ç½u[™¢Gî´ICïÀÇ×^A‹3¬ãâw<¢Ë»ÌO •εk×& r‡áË»ß ñ»{×/«÷ͲŽz&Æw¾!T3 šw¿p¨Î4h¡¾r¾iÓÉ…sBȦM¦M;ƒ0ÒvÊÐ7 25ÁïÚ¸f9ꂎ.ïòauWQJÕÍr¨ÌÊ—`Tæ u[éθH¶ %´˜ct¾ãä»wŸš˜pÁF¸~'tez|½öž;'‘x®›š¹V¢îJü³H•@!Ó¦MóÝ=¤ÓŠ¢!Ҹŋ¿øúë÷»Ý÷‰¢ï¦÷躅Ɏw–ãW½»xº´{³,“Ùˆ†2ñ³’_ÝV¶Ž®ÈiÓD4͒ਕe%6Q2ÇÐ¥{¢òÑýÖʼnz¯\·×Þ7Ë:º\ûIuØ~Ê;²TçÔöS‰ïFwIË (iû /¼ð /xO|z-¢I´^.êêé.¿²Ž¨Ü{h‹N„šàW·)º2§-)ê4%àÎXÕ³ì[¹ýjyâ­£3òí í£ûí†SÝY÷Û^'FYÇ)×¾>JÔ-·‹›|ÍñªòŠ2iF}Ê”i’™£‹Í IDAT¨ß'Š w¶÷èuôØ :a{é®iÑ žq¿º­¢½¢'`ƒ‰w–է鼻ߣðÎ}/Œ×^÷>YÖQç:ö.Ò)úØÉÈÈX¿~Ô)gxxŸ>_¼x1!DòÑY–(œuï ,÷ˆñœ_ÝVö<:Ãp‘ùǪ·°ê)‚À龈¢ V7Ëò锾U±;‹%ƒa=LÞ=AÕ×Wqƒ~ô¢ä’À ƒž)aDs}­¬£Èµ”?ø`RìS¯1fÏÞÝÒÆ7‰±£O÷†_|ñÅ_|‘JJ"$¾riI©Uâ]Ù{û–uDå.ÓR¢È{ü²¬îèS•"ö«ÛñÚGïáT¸¸ê4…—w™Ÿizâ”þG¸,v„‹9‰ž]ÖêÎÄø5vù.)–éúXð>‰n4i¼núõ×_ïõщâWÀFÑkuW®UŸrS«ǯ-¨˜åX2Û•Ý[·+ºe—*K2_E:û¡äx¤·‹:Ëa‡/QÌêÄ#ƒaG¸ò'ô6Eï{eE®ås¤°±+7Ž’,+ÏþºuëüÞ—Iyà.»ì²uëÖIêTÎ#êväsÖVêf9–ê­0#õùÊBŒyW·E‡-èˆR"ö­ÛJ×Ñû”ÓÖ7³ì[Ýÿ²ôQÒgè›eÝs-u|RXzæçþG½ÿþû !ÓD±—ý@ zï¾Y·¿3®/9m}3Ë^Þù÷U¤/Ñ7˺oæZ’m©ïEqÝ—_®›>ôºß[CïÝíYîú55©+uïSN[ßÌrŸ¥o–u_®á^ýîM¿±†‚FÝVªèüqR_³KÌrŸ¥o–5j¸Ä´žü¬9 YöƒF“ èHNþ\A}}½ôyÅŠK–,]€žEuô5kÖÀ.@ÏCEï‹6—,Y"Š¢´ñññ{Êß ³îË—/Ç(èYÙGQìôxEï o]à£>:à£>:ðÑW´A}ô ¢.㻋¢èýÖ÷Z¿ƒaÏ z믊=µJF<'ËÄ,OtFLF`.F«üÛPÙ Z: K$¨åÍ‹ŠªzE •_½ ,e…–Œî…Í!ljÃV!¿ÓÚ§‹Ë4l‹‹½öúN£7+ºL¶}•ÃOE‚¶¿ƒçƪä"½*©UžHŠ¢ÂF‘¨­¾Ñ*9¢°U(ÔΠ >TéDZ"2r(oOTT+ª_TÞ„)ÑK%õVù9]¢$µ¡t%°"5uW–i¨j´7ˆ®ö…N£wÐëè¡j[<®R …·‹:Ua…*ÒÒQR‰ƒF+¡ÌDŽŠ¥£®)PQ£;-°O T£(*Xìö’¨Sµ}º¾LãZÍ"m€è4QÑeü¹xWèè¢ zU¤6Þ*¢ºuK:}ÝŽ®)TÔ®Ùô¾Ô½$º¡F7Z©;ðžÛiÀGW§æI“~]pU«ltRê½J•afDið‹VáX;T÷§Öp¤{+¨¨*öÝå¦÷ˆ‘w,7Š_5‹´¼Ði$‘­£«^¿eö¹¨~Ut©(Gê¶«¨ë_àÚaW:C±”Ž’5NU騨ñˆ*ñ»KURÛÚÑÔªf¤»—\¼Ó詊Ë@&¢­¼WEêVƘ`%©U¾§Æ/I‘¦*èŽ6™¡qØ}aawVG=\P’ÎËT¦,Th£¢ÊTÔ(¢R¾]Cþ´H÷Fz‰*U("ûtK™ªÒ«¨î½£Óè$ÖóèÑÍ¡uÙÌ[D•,º]l¾Ä˜åPû½„:_ÉL¬ÂtÆR:±ìÏGEU«¢ª¾Óª—ͽwﶸ¸ZCá®@t‰®èݾ2” óB]‰wS®ŸâƘYÕëqØtv™bue5@Eí‰Ý¢Z#ƒwï¿Dúf§ÑG}ôÀG]¾ƒ¥›œòi1ž d~RÝzÅœ' ÷zKG~éµ ** xÆ7èê è¦G—Z¿Ý^‰¯ßq­f F‚Í:zÐi%Ïñ3±ÌKˆ"½JÅÔ*Ú 'û½!ì·Aky`ÿ"óž ßKsjéNþ-2Å4aKGÞøA­-kù·P¡¢ÆXQI°G´CåK&m¡ÌÑ9Ê£U’ÚPJ#ÿÎ8åzÓ5eªš…m°Ê`ßé4z¡¢Gô†ˆýéí^¥zjcô§£ø6Š·[]èÖ2¯zPžÎ(ò«ú%¨¨ªWÔ(*ƒ’Ó¢8'Þ\Ç5uËT¦šE”‹Xо7u=üöÐK¯ã࣠ˆ`¾ñØ €€.Tt¬£ðÑÐ ¨üÛk@Ÿâ¹± ¬è}çgj€Ø¹óxN"$ëè@oëè@o áÖÑ…çÿ2܈ÏðÒ-ðx=øèaôÒW•£ÓZéŠÄuȈ\ö‡Ï—¢c=Æq è2Sr/:³(¹$–¤¢}>"Õj©µ’€Ê>º·•¢¹Eó‘f§To>QÌxa’ €Øu7ãîÿeÜý?ÕE=ãîÿ=ÞuëèAW¯}ú|úàįã ìƒäOµf8.‘éÝdn¡<ñÞNݨ¼ÆHšç«GÂÖº Å´øôÕÚPŪð¾j9µ S嵌ßù2‰ô3làùÒAß{MŒLåWrf¨<Ð ô>Ô Àû•¤Ü~½§ž¯æóè~ؽ*é¯CµØPó«¾}ßåOð û~T®¯aÓ <ñ¨ßqryƒ*}Ð:xr`ò+²PÕIþ¾aÔo¤4%‘¦J&*ùD†:?0‘¡Ué {m¤‰ 1t¯û~ôûÖOÝ}¿’Ž y¨õŒutïl¤wÇ\ âÊ8úÞÏzmÔ³AãQžx9÷¢ÉhOP –wgÃŽÔš?—×3%©Šè„X.üVáí"²<½FìñûJæÌÀTóÑe¦cÏ¿ÌÄ`â:#ué7Ùx¤Û«G/›q‰qIóOt*¯£«î@,A«QÜ×o]YݱZ9ŠB×e èÝ^8 X)—wÍã¥è±¼×-µÆ‰Öš¢Ø@Ÿ%è‚wÜ©*>ºß›a׌{xH=At%èškàr²ßö± ñÖáP›Î"J^Ðû†ª<¡îâ;Ý­$žøUû.ˆ'vË8zP_Ü»)Ýïy6•¾ë~{Mj±¡‰‰=6òëYÁP·S±›ˆúêš( yÉ$!Œ¢«-ñxÔÊ/ή¬02›Ô"µpÐ'6ýÚ¬ºv a=xßgÒÔuJrÊëëë¥Ï+V¬X¾|y¨†ÖG{\þ!ìPç+ß'¿7Jf90lRå/ šå‰Çóè}øôJž›(¿¦DÑW¬XÔGGgïîF†œ èQƒ÷ºw[ÿt–é­ pñ¦ëÖÑ_ÿî'êèñ¨¬ès8m”³¬¤>:г¹qGÂ8ŠðÑ€^€Ê¿øèˆ’ÖÑñ^3>:ÃG—Y_EÑû­ïµ~ÞôÖ1^{j•ŒxOsب|ÏôÍZ¤–Œî%—(Im(BE¥Ð>]Y¦òª$ÙÝ+Šj/_4aÍ¥¤\~ªÐƒ6R……¨Ð¤p?£è2Äû•o3–šYÐÝï`à9ñ„jç‘^Ô*O$EQ‘FåM˜½ Ú÷E}ND—(Im¨Î=°"5u—•iÐZç—eùØ"ª?aS®<; Í¥PJ•t ¡F$¡îi!ʘÚàKwîu÷k [ftW©…ÂÛ)9-°c ì¾ÃÆ ¤#Ž´@Ã^uj£¶O‚”iŒÊ§ÜAï‚æN>y2óy*6Rù! žÍ@NÑCµŸHǯoUrU¤6N#›Þ—Ú —D7Ôèv+ÅOBT¶+Í¥| Óƒª:ðÑ#î£ó »e`®ü¦ÊW”»@`âá¦'Ž©êFJ–‚Ö“ÄtÓ:衆kªØVÉtúq$T~¯{t^—üÖµ®Š.µå(Ò]áɉßg©’Ú.€DPñÞªOAgÚ£k¤ÊM 9 Œ¢ÇÒ­D´ç<ðªˆnÝU‘¦Vùæ/¿$ÝÖiTJ²¦d“¹’sb¹DyjGÔ¢«z™Æ˜l™o%°- +L|ŒM[ƤðÎ$±žG®Së²®0¢.I>Uê¹÷ͽ'Ú¶8Ub :Úð%zo¡+Y9Ržø¨ë’̺;öÄ^Ñ| ³÷5ãžÕ7©52è¡>–ZÉö>/àKO©Þaße#lˆ: ä£ËÏCª{UD"ZÐ º“(¢Þª+ÝôèRë·å*Ñ$JÉ9ÑÕϨýÑ@ã+I€*ëQ´©°¯[ˆÇˆ:¾D³ŽtRNÉÁÀsü¤Ì+«"½JÅÔ*ñ=ÙïíòQºh ÓÊ,£¸P¯Rñµ¿|U—¯uÊÍ+BØV41a©|yEdÒÀ—ÿEWê£+þ[þ%$ ŸÛ‰î*ÕSÅ]¢ˆJáÓºJN‹âœx¿Š ®ñ¨[¦±¿GɫܢÎWDÙ‰¢E«RI¢°ê—ЧÀTÑ1æà£ ˆ`¾ñØ è1ŠjËëÑ?Ï‚½€Äëè@/Ut¬£ðÑðÑ(:|t oûèåååÑùÝ1ö˜€>꣗——WVV*”RéäÊÊJØP—h~{M¡rU}é¯ôÑ{P:ÙwXàwyàÁÀã~ñ˸ïÞoeÒàM!ª€žªèʦÚW&Ãê_ Fú~ õU¨sÃ2¬ð¾~aT=ˆX×Ñ% ŒÎ—ô*ßóÕòžCÅï@òÑÕn1 ¦¢G4åÑÄ»º.;ÔñÑCmU@å:zPw<èclÑÉ|ЫºrÄ€Ñ €>ä£Ëøî~Et‰¯÷ï•B%öÛ'*òØ“ $”ä”×××KŸW¬X±|ùò §VUUõ)Óàyt=¼×Ýß¿z"qyg\Eáä<Ð3½»žGOQGÐÁTÑñûè|ttQ®£W<ö5l$´¢+ñÑ…çÃv@â€ut —*:ÖÑøè€øè>:ðÑðÑ€^Aþ}ôÀ¹„îM¶oz0*ÐýŠ®–ÅUq{ÁÒFT¤G®£c¥è"=¨èÆc>Þ-@°×€®¡V”Ž6¼G¼Ê\å—µˆVúƒtäm¥$_¡r‘Ñd®Uh ¿ØDQÄ2?ôxE}n\FEºx#}¨ùùãa…?¬­‚jvü¶Ê$>:k`žz}ñyôˆäJEmS%ª°‘Dzˆ7ÀGïçÞå“6#AçêCY@¹ï4Ú¨s¡$wJ„Y¹5 ô=¸P%ŽT„ÒQ…“ç~†ŠH#ã—ø¨-ŒÅr€ÞˆhlÁÐÃ=éòÓH™­XH>º:`T ×€ß^z©¢G½s-ð-%~(¹K¼÷Íùí ú(¶’w°„º\-(B%>”Ý¢“as;ôhâõθPO)‘.––èv†Ç) ?öôø•D࣫/ÿ r»ø¥-ögÐU‰‹,Ðk=ö9[™ä_Ûîû1®J#¿òÄĘȨE=ÔˆZ£È<ô8TÛë®üåêŽÆžuãèR«–/®îiz¿z(¡¶Â2ÐG}tÐÓuî;ÀG½TèÁŠŽW@â¿9€ºÄëyt/|tĬèpÚøè€øè>:ðÑðÑøè€øèðAµß^“ˆ¢HQTÐh½ÇýNð‹-T’¢¸*ötÊ\®ð^Þ3•Çæ{fàWAmË aÏT’°°õD&*…¦è–Œ(=ÊóÊ챫òÚ%Sv¥J¦†-¸(Ìè×ü£èC¢î=ÚP:{Þ£Ž"××]¾y+©:ÑÅ /J¤’«bOgD—„ …*¨0ÙÿßÞ½#Çnc}®šØ*¯@*…Nõ¢Ù‡—à%Ì*,­ÀK˜}8’Ó UO‘Â)yoN±hñádŸS ÔÝlD“¸¸ Ù½¸Eé›\Ðæ¹k/ŸR·>ÁÜj§Ê•ÇNqCe "U†‹õ)hƬ¡gÖ¨eñ™¬UÔo{MáÜŽæÎ£Ïíîñseï:Dn­&ãG$틞¾ö‚6¿%wùf´Úͼ«¹ÕHY>eïÝKa9¢·¹ß”3Î>\q¾]¹‹,/¨7»Ek%|†‰Ùüxù‹í½ÈÑ[ï+Othm=-¶gšÎê{Eûm©ê±•ï««!MçX«GOé vÜô𔽫 ž)WKEN¹®ª²ýOǦŸ¯]÷Ìîn!gÅO°x§› >ëâkŠÂfLÉžwþ Ê™Äm?ãñÈÁ}£Ý%ërÜñõ±Y×LÕ̹׸æ–Y¥\UwH-®ØâhÿO°x«o׉Fe‡áºÍ¸Jo°£Á9rôúÞ!+_op[êGÙ‘›sŽMÓÓ+v›ýÚb¢´ÛQûmÿYÇ/}O¬êê‡aÙEÝû÷›fÒÒt"|gÜe9¡~®kHUS´¼O:¡N+ýØ}¥líWÝ¿çÝÃé¹kvCŠ÷RßcÃøÍå«DÇátý•ö^ä臊”Yßíî½96Œ7-k¾q»4=·b5ráp¾x3ôÎûvÊ÷î5UÕúÞ eù‚½WšÎþZ<><6z׊‰Hâ¥_}lZå€`» žò_›^¡vÈ'˜[àGD;WÞÕ†Í87þÈ­FÊò{oúÁU¼íb ½¾/HÿŽÃá-¤u({׊õÌ-¿¸©S®é-®üx”ï›\«Íkv¼Ã?ÁúO9±©+Û-«së«Z³#¥ï“«ï™5ŸBÊ–®¸íÎÜ8¿½èFy Gäè€Dt9:ÈÑ9:PiÛïŒÛúKÜ‚ßI\÷g»ÒÎõ›ŒÀ…U~9`e'6~{ÐI"G?Í‘ÐZ§t`O¥“¼¹}g›VÛ@h0|îù»ï>ˆóEôÕ§Üû_ö¼ÉŸlÊZ ²ÆÉ#añ76‚Ùû/ƒi¥ÅÂS*»cH«ãŸƒ –‰t›s/E:¥¹>mîenùÔkâZ÷ñΑ»@âÀ6þ°²ð/iÓbýÃÖæÐ€ÓE÷ÎZ]n}§ïuzDôCFLñÌ5eøŽ2?öãÊñ!ü’éâl¦T>þ«MF©@b·ÖÛ®Ë]ì”&;Éa?,¡ |ÚÊу)ÈG;^¦`”}7($¾Ã•¾¸ëGÚªx¸ ÜB:>Ý·èµ¶î”tzÙð Xê¾&§µ7 ºuû:½3åè§pì-æãÁ©óI@J¿±Qj»u§¤Ó;eŽÿ¼;n¸êF¾1&wŸ÷ÖAàéG}§”r^§w¾ýûßÅwÖø —5¾}õ!aq±ÃË[ìÐ@V¿±Øçô¨«wJAUuz§ÌÑ+Óú¬kËãã‰ñ­b¹§Òçv¾ÉÂËZϼÞ›-öØé§±kJw’﩯!Mäè‘Ø™ò“qqÈaXNÁ7G6° n§€Sõ¬¾1ñœ¬î· +.Ÿ&rôô»³Vš²+äî.ñ·¯[xýÔ‹s˜ÄÔ¨²O+4š£MDtc(£8òZ÷²sç€n&¢ËŒ@ŽÈÑ9:ˆèrt£rt@ŽÈÑ@ŽÈÑ€Õüc2G¯ êþù§–¥óôô¤ Òå;Õ§§'CŽÌDtçÑ@ŽÈÑ9:ˆèrtXÍׯ_¿~ý*GoýóØùCÐ}-noÊ6Fšeÿ,G?xGÐ}}“¯Ú,ÿ£Ç½¾¾v·×××”=£_¬{¾{ûð¥àád9sëÐ}¥¤æ‘­Nð“Û•Û8‰/e­b®åèIGEä#/ÖíUýKÁÃàC+@÷µi›ÌÅÚÊÆ/™µŠ¹…‡Á^޾÷®UõŸ“æt_eáy˜àfÕ'rµA¤œ”Æ ^ ¦LrW‘òê&ßë~É={nòj­©¼Ð}•­=7œm’xVb£Ê—-ŸÑ…óô£"dÕ|ürt@÷UÞ&ÏÔÔ¶+}ÁLûäØÅytnq”sºljxÑÃ$÷£gï«ÏÃÅ^àžH@÷µÛF ãÜbÌ;p»‚ɃÜU¤TÀyôì9¸`•O:(Ç < ûÚ-Mßt»"·œe­büñM„ï.)ÿøøè¿¼¼z¶‡Ñt\ƒ(;^8…P Ð !ü‚9zq#ø·?~'î)ƒ†É¼?x²É8u˜Œç»ýôx< gÑ#™tðÌ\áñÒºWÇï›r0&h1G/˜ëî‚zYÐ ÞØ?¬)àDA=q¢{§Sbç\á‹¥MVxïÓ‹ºA®u—‹7'ˆ]M"ä.)>ºÇ///ÏÏÏ“‹¾½½õÿ?>>F }ײtîïï5TÒ©rš½Ù9p9:'ŽèûO¹ œPÉo¯ÀE#ºßG9:p€MΣ»¼`E:U #zýµîŸŸŸZ–ÎÝÝFØóèpшî<:ÈÑ9: G]Ž'ÖÄ÷ºýúóïýÿ¿ÿç×S4â¯?ÿ~–ªpCý¨ßGïbù04Š”pÊ=ˆßÁÃ>}Gýà¥ñ’‰‹ÅÇ“óÝ“sEÀmåè‹éøp`áà¥q /[,²–áÃ.Ò äë׺!s.]ŽgÉ)‹ W_ ÈÑ›6Œâpâˆ~ã÷£ËÅ8£VîG¦¸€Úˆ~`Žõáä×¶»m¼"»§ÐÐyôàŽ²/Ÿß{¶ÃlAâŠv«Ìù¡KÊ?>>ºÇ///ÏÏÏ“‹¾½½õÿ?>>F ýüüÔ²tîîî4À­äèWšÜ–£Ççj?üwøðû÷Ÿ´É¸‰r›¥à-ÇGôý§ÜEA€íbÕꡨýض…á&·Ù~{ àâ©ç÷ï?Y;—ä~t€+‡ó ¿ì–éüðÉq¼Ô¿Ú=“^Âx½ãÅÆÏÛ8WÕ”râõ™,ª¬މè7þqí…êÿ_ÅÜÿ³bà>L‰£]`N,an½)ÿOÆ×‚JyKz#ôs-pÊÝåÍ+êby—nõÿT”6®†±*12EJˆ¬wñíA9¹K©yMµËZà”9úûû»#Îýý½F€s#~ÊÊ’9œóè7—¦)æâKÃóÇY%TVàKò„vpõ_MŠ\PT##çÑN`ÝSés¹ø\(-+¡²ñ@»8©PÔ³ŠjäN¶sü>:51/=‰¬O77MÙO2ü:fÜp}2¨§OVǯT¯,!÷íãKÌ"%^?÷0˜Û¯H]íZwVM¾¿§÷Ïã 0s·‰O'q«_>r£ynD,Ž…s'¿ƒÂç¶(¾á‘ñÁ*-°aD?éyô‡‡¿}ûË‘ *Y7hïÞ[>÷LsüaäùÜMGëá?éë+'½n(Gxø1x&1<òâ5V®È°€‹çèA¨ëábü« ã5®nÇešK¶à–ñÖ쟵·{ýÛ·¿ÆitÿLCfM¯.+HO>?9p¯bn½“- õüd*MŸGïØdðÞ!Ó[]¤V«¬"Rxd0!õ¸qgº=1b Ùxœ{xøqø‰Á„Aÿ0^~·X÷·˜ÁOæñzçJ˜œÒ@ŽÞbP_=bÕœá2õÅULN¤7Ø&\'¢7Î'Ï4¯à·›»Þè|™v:Mg\qðë§»· xÁujhš‹èäè‘p¸Q¤Œœ–ž;ËêãWã«X\o¼|€[ÖÐyôø7±7n­½²Ö8eãsõñKÛ&W1·ÞÅòÍÀˆèÇçè)Ñh|eøä?‰eæ®1òdÍŠiýK…SIDATW)G  •}»YôüDxý°}‡ï^€k»æï£ çˆè~äèÀ69~¯eààˆ^­ûçç§–¥sww§vð?réÖ©IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/backup.png0000644000175000017500000012423210014674771023252 0ustar frankiefrankie‰PNG  IHDR0>@ÔÊsBITÛáOà IDATxœìÝwxTUþÇñÏ$!…’Ф %1CU‘fPDTÔu±!`AdE¤êDQeŵ.Š4]Eeeuݵ‹".Ò¤„@ ¤…’:™ùýqÉ0L&“ $Óò~=>>wNî=÷Ü;!L>|Ϲ&»Ý.ÀWÂü=T/Rð))ø|Š@ >E Ÿ"€OHÀ§¤àSRð))øT„¿ 2-_¾ÜßCW½{÷ö÷XLv»Ýßcp¾È¡>b)8HAÏ9JJJòß@À½´´4cƒL ) èQ€gÄRdR‹šÀǤ€àFy èHÀ§¤ Ú1›Íþ€j@ *Ùl¾å–[\Z*«gCRRÒ Aƒ222*¥ÛŠŽÁÃËs“=|øð¶mÛ&$$ 0à믿>ÿ>>)¨L5kÖüÏþS=[,‹Å²zõêN:9²*NQÑñœ'#FŒHLL\µjÕöíÛÇ¿páÂóï@à#€Ê4eÊ”3fX­V—öâââéÓ§wêÔ)11qäÈ‘¹¹¹’zöì¹sçNI‹¥yóæ´sçΞ={–ÕýúõG½uëVã¥Ùl~ë­·ºvíÚ²eKIãÇONNNNNž0aBAA±[aaáã?ÞºuëK.¹ä7ÞpôVVÑ“Õj:ujÇŽÛ¶m;wî\Ç—Œ*-—Ë:©Ùl^¼xq÷îÝ[µjuÝu×mÛ¶­ôå¬_¿~Ô¨QõêÕ‹ŒŒìÙ³ç»ï¾ëáv9_¯ÙlNII±ÛíF»ÝnOIIÙ¶m[¹7 €H@ejÛ¶m×®]/^ìÒþÊ+¯lܸñË/¿Ü¸qcddä´iÓ$]sÍ5?ÿü³¤o¾ù&22Ò˜°¶jÕª>}ú”Õÿ‘#GæÌ™Ó®];Gˆ ¾üòˬ¬,I/¾øbvvöO?ý´bÅŠ={ö̘1ÃØgæÌ™‡^³fÍ×_½råÊr¯böìÙÛ·oÿòË/W¯^mTB9þ_º0ª¬“JZ±bŲeËRSS¯¿þúqãÆ•>Q§Nþò—¿ƒ/÷v9_¯Åb©S§ÎªU«ŒÆ•+WÆÅŵmÛ¶ÜKŸ €ï™q2€`´|ùrIIIIþ$Él6[,–ƒÞrË-_}õU:uŒIÝ»w_´hÑE]$é÷ßïÛ·ï† ¾ûî»>úè7Þ|ØØþý÷ß[´hal{3gíàÁƒÞOm+뤒Œ4JRLLLéiŒ’š4i2{öl㌯¾úêÃ?¼lÙ2•q»\®÷¶Ûn›1cƱcÇìvû÷ßÿâ‹/zy ¿#€Ê7bĈ¾}û:ÔÑÒ¨Q£O?ý´iӦλEGG'&&.X° S§N±±±:uzçwÚ´iunçmذáž={ŒJ¨¬¬¬† :ÎîÜîØ?"""???::ZÒÑ£GG›••åR!UÑ“VH£Fžx≶mÛ:^–¾].âââz÷îýñÇÛíö>}úÄÆÆzy ¿c )¨|111£Fš9s¦£eðàÁãÇßµk—Õjݾ}»ã1yW_}õ+¯¼Ò«W/IW]uÕ+¯¼â2Y¯B ðÌ3Ï>|øÐ¡CS¦L0`€Ñ~ë­·N™2ÅÑîØ¿]»vo¼ñF^^^vv¶s=×À'Ož¼ÿþãÇ;öMOO÷þ¤Þ2dÈÏ?ÿ\PPpäÈ‘W_}µC‡F{Y·ËÅ]wÝõþûïðÁwÝuW…à_RP%n¿ýöÔÔTÇËG}´{÷îwÞygbbâc=Ö¿£ýšk®ÉÉɹòÊ+%õêÕëĉ×\sÍ9Ÿtâĉ\pAÏž=¯¸âЦM›N˜0Áh7n\ƒ ºuëÖ§OçGøÍš5ë‹/¾HNN¾ùæ›SRRícÇŽmӦ͵×^Û£GÇ\¿?ýéO7ÜpƒËƒù<œÔC‡5kVrrrJJÊ–-[^ýu£½¬Ûå¢W¯^Ç?uê”㢼<€±¨9ÜXÔ@°`Qs8P!Ÿ"€OHÀ§¤àSRð))ø|Š@ >E Ÿ"€OHÀ§¤àSþT&³Ùìï!”Ïb±ø{àOR‚[P$P.J™ˆ @µB  ˆ¹M£öíÛçû‘TH³fÍ\ZÌf3™€êƒ@ @°r¤QŸ@¹p°‘O‘I¨>XÔ@P Þ4ª´¸¨*¤€€c2™ü=„3¼f‡(‚RàF²Œ ´À9 B Tö’ ÓÙ/«”ó¹¨N R¨€OHÀ§¤àS¬!@…UÊ ôþK êH@ ØíUÃèÄï…çSTÃ{Žêƒ@ P>³Ù\}òo£¨ó|öey²4†Q}n;ª)ûöíó÷ÊÔ¬Y3ÁÜäPç9yæ¹ó’¸Ê1*’)„)@uçEUiå%ÇÎN¦ˆ¥¤Õ”¯K¢Î1$ ¦Z¤ÕN –DyFÁB BÒ¤G¥•’¤žÒ«R’$É.M”Þ’LÒÃÒ å¯¦ìcçü8³j²¶Q¥ äõªªZðEQ.ÜLK!è„ù{*ÏRŠd‘öJÝ¥»JÚçJ?I[¥ÍÒriž‡ˆ€Ð¬Y³j˜å™Íæ³Ò({¦QgÞõÒ€€G…BR¥ÕR”$i’4»¤}¡ô¼ÔT’4Mš" óÏ˼é@Ð °¹*ô%Qœ=å¥D¤€ grú¥´¿4Sú³d—^–n(iß"u)Ù¾LÚRîçÎ+iøðá•3ZÀ‡B9ŠrÁ<>“ÝÂ"€à`2¹«WqYø¬OîΔEJ‘²$I ÒÊ’ª¨p©¨dÅ›)YËîMg~¹}úé§]¾^uÉÔéì€_P|Æ$y½˜”1¿/¸×ÙyÕGÉ“|¿ÒÒÒ$õîÝÛßÿ±†PUL^“dwR±Ó8ïþ€4T:*•I÷•´×–N–lŸêœûEÍ;ר™‚‰©zÌR¬&—‰À”= ÂÜ4y䣩 ?HŸ:­!U·¤½½´VºF’ô«Ôþ|ÏãȤ*±`Êb±˜Íæ³ ¾Põš5kâOܳ;e4ž‹ ƒ9‚ pÚ9ÄLÎü¶†s‚Ó^š.–$Í‘:”´‘&KK%»4IzÐÛ¾§NjÌú)«*Ц‚˜½Ú¤.³_M¥Úƒ—Ë;h/£<R}ç™4‚cõÕ÷¤‘ÒLIÒåÒ{%íKéR»’m¯)#ròK©²’)ФPEÎ^ù;¸ ¦ÊŠ¢€ Á¢æV•39ÔãÓ—æå¢æ•|n§s™$wë"—»†ÔùÄR,mîkÞ-mÄ‹š{x€‹ ø®órØeüáõ;5‡R,•39TÞìyóøÄ\ª¥ØSùÜþ\ Àq^£B >REI“C(}² ð )•^0å·"©ê9U°äÏ¥ç"©¬*-ÐBŸóRxTHà¼TuÌäJySˆ ¬‚©uÒ]RZt{n˜]š(½%™¤‡¥Îoëê³´y¹Ü®îË¥š<¼üüCÈ!€{>Kš äM! ²>·X,f³ùÚK7Uü(u{nßõs¥Ÿ¤­’]º]š' «äqUwžUçãðŽŸ‹]aþ|ÊäµÊ=¯½<•{:øÑðeí0wîÜrgù»Ï¥›¤6Rª$)K “Œ¹h©RIR±ô¤ÔHª)Ý#r:|†ÔXª%= ”êVÒ¥R¤/9.¢¬MÒ©¥d’Z;… v)QÚä”nIc¥ ¤zÒ_Ëëv¡ô¼ÔTj&M“¸»™Ò©Ž-Ý ôxÓìRɤ<œÅ~ö!yFÀO¤B„_b&gäMpáM,UN2UÑo؃Ršt¥tƒ´\’ôo)Jú·$é{©¿$éi­´N: EIzøQÚ$eJû¥)¥º•4DzF:!ý(ý¯dþ"­“ìR¬ô}IãwR=©“ÓnÏH›¥uR†”U^·[¤.%Û—I[ÜÝŠ›¥QÒAé ÔNSþÍCùìUÿPm°¨9@@óñ¼9øÜèKÁµ¨¹—” ¤ Þ?’ï\Ò„?J7I÷IyR{i³Ô\Ê¥=R{i›-Õ(éÖ.Ù$“d“$™$«.I²J1RÑÙÝJúŸôœô³#ýM Éc‡Žñ•¤ É.µ–2¥ºN;DHù¥Öø-«Û8i+Iʑ⥣%§SÉþ«¥ Òº’‰~Žc=0IR!ƒ@ ){•É_+4•‹%œ <Ïã“Ó S§—öþÏJ‘ômɤ¼é"é5é2©®t™ôŠÔVŠ–$5•vIV©¸$ëqÈ,ÙÈš”êVRWéSéwéïÒŸJ=tèPOºNZ,-–úKuÏþjS)£Ô!euÛ^Z[²ýkI •Ξö5P)í•lRNu e0)¯fÌ䌼)™JþsyY¥ÿ9Ÿ«ÊTÉÂç?JIJ^Þ M—úJ’úIÓ¥J¾4BzHÚ)Y¥-Ò=NŒ.Ywi”4È]·wK[¥BÉ&{Ñ¡³¤·¥yÒ¥¾4TzLÚ+“F•×íi²´_Ú'M*)Ýr‘'EJ1Ò.©œ§–`is>Ä”=P­Ú¼9øØV­Ôw¦fý”›=M}fjù½<.Õ—ž*y¹CJ’~•:K¥KœÖ‡²I3¤¿Kû¤öÒ$é’$“4Cš-”îÞ¢KuûôŒ”.%K³¥~åuèü×&ÅKáRFIÞçØ¡H/-–ìÒi´ÇníÒémIÒÃÒtwéágÒãÒn©…4^zÄ»")“$=ýôÓ^ì*¹[ù+ 0e){dR Ô/ó^âSÎÙòåË%%%%•·c(+™ò*J’–H—VòªªÛ@õô3Þ¦Qâ—èŠ@Š@ ,¢ü]F0&Mò&ÀFláKM:US½ˆÒªfLUÔm5ãý̯ºPY¤€ÿoÌäŒÈ ¨,ŽH¢ÂËH!ø]ÕSö@ ¤ÉÀ§&¬Pš²çVµžxå&IÚ·oŸs›±Ø¹ó° Š ½šòb˜²‡€G…¨°PŠ™È›€€e±XÌf³ëáð7ï ”‚(ºà3RàŒLš äMà-»dR³fÍ\Š¤Î™£+?—G[j—&JoI&éaéwR‚¡/„c&gDN@£HªšÁª«sûŽ+ý$m•ìÒíÒöL»þ¯4^J“šIÿ'ç)–&Kó¤“Òé-©–$É$½$ýUÚ#%J;JJ™ìRkééâ’LªHzBZ$Y¥§¤1»](=/5•$M“¦H!…ù{À•Ékþie²—ÇßBê'_«Î?t‡HÏH'¤¥ÿ•4¾ ­•ÖI¤(i¢Óþ¿Hë$»+}_ÒøTOêä´Û3Òfi”!e•×í©KÉöeҖʾF Hà;Õ0fr opžðyaM5%‹t@j)½UÒ8Oš#5—êH/J;í?[j(Iz@z»¤ñmé³»]$½"µêIsÊëö¤T»d»Žt¢2¯Rœ¯êYÐTy„»$5kÖÌßãð¹¥o¥Ë¤–Ò²’F‹t±!…KM¤ƒNû7-Ù$ýG:"–¾î9»ÛýÒ…¥ÎUV·µ¥“%Û'¤:•se@@! LÄLÎ(qàw§‹¤ªËÏ]øIWéSéwéïÒŸJ›J»$«T,Ù%›»ëI×I‹¥ÅR©îÙ_m*e”:¤¬nÛKkK¶•ÚŸ÷E‡@ PíPÐäyÀ­jW$u·´U*”lRqIãé!i§d•¶”ª~r0fíÍ+5_OÒPé1i¯tLU^·C¤ÉÒ~iŸ4Iº¯/b6›%)_1IÒ¾}ûŒ:©àZZ¾Z«˜¤€|¿ÒÒÒ$õîÝÛßÿQ!ðb¦Š"o€³P$åvÉTýfí¨z¬!¨d,ÏtnX ¼€E€Š¢B à"¤óD¢8P!pEAÓ¹¡¾ |æt‘;ù‰¨THàB% ²P!€{”8@ £Hʧøk@e£B @0#“€ D… |<ß@%¢B àÊn·³Š¹$“ÉÄL=dä#¼¨€ªòuÏZ_÷¬åïQ@À¡B ª–#“ê»ò”G‚@ IÌÑÀH¦|Éb±˜ÍæÓËÞW«Yø&‰9­xLÙ€jÁT0±€àü•<Sù˜Íç;¦êñ@F§Ë4›Í~ P*¤ D*'â'€ïQ'UÕŒ*¡3ÑLWKýIò(>)äM熘 °H£|ƑΜN¦ŸªBàc9‚ò¦Š"i‹¾+O•žšGå!U0E… G ¾@Þä%b&@5ñuÏZdRþâ>–R$S¥>TE!H±¨9T– ÷Ìî€*çÈ¡XÑÜ¿,‹k”c àµÏÝÍÍ%Áƒ )ð ¡’[DHxÃ1kÏH£/©“ò;ç@ÇMÍ”üZ6åîã' BHäMg#f *8gOdRÈuísƒË‡Ä*ý”TöRr(„)Õy“¤ ):‘I,÷É”Á·*ɡ¤„ˆê93¤È¤œKä&Ÿªâ3!Œ@ @p¨žyI!L*ˆ•ˆ§ìžQbi”—Ï›# šà¹{¡Š7ð€@ €/T“¼‰˜ ¿3›Í>˜WUéȤBo%à€ÊÂyM€ÀwõÕWAL‹-zõêõã?zy svóùçŸß|óÍ­[·NJJÊyŽHú÷¿ÿ½fÍš)S¦H9rä-·Ü’ššúÔSO3ƹÛÒC dRAw ð"‚7o¢  €Êb±XöîÝ»bÅŠ«¯¾ZRjjê­·Þ=`À£Bêå—_~饗úöíëXìÉ¡yóæéé鎗.‹=uîÜÙ†¶mÛ6lذøøøÁƒ¯Y³FRrrò¼yó6nÜxûí·>\R³fÍœ+’233[¶lYÖ˜333ÃÂÂZµje6›]Žr;€Y³f%''›ÍæcÇŽIúí·ßn¿ýö¨¨¨o¼Ñe2`é¡2© åöýâMÜ"‚C0–83à_mÛ¶ýä“Oòóó?ùä“¶mÛJºñÆ¿ùæ›§žzê±Ç3ö‰ŽŽÞ±cGrròÈ‘#ÇŒ³iÓ&«ÕjµZþùg·0Úµk·dÉ’¬¬,‹Å’––&©yóæ?þøcDDD³fÍNž<)iذa'NLOO·Z­ÆšV#GŽ,Ý•‘7ýüóÏ—_~¹¤#F¸5bĈÒG½ùæ›}ôÑÚµk—:tøä“O¬V«7C .dRB[„¿@’3Qr‹ €d”D™Ífç*¡9sæŒ=ú‰'žhÛ¶íœ9sT’Õ­[÷‘G1ö¹ë®»ú÷ïÿÐCÝsÏ=QQQãÆKKK‹ŽŽîÚµ«±H“c)£ç9sæŒ3fóæÍuëÖ4hЄ ^ýõgžyfçÎf³yÆŒ’|ðÁˆˆˆûî»o÷î݉‰‰þóŸo½õV箜G¾fÍš=zH2dˆÍf­Ý¨KxNºmÓ«òx·¾UppmqT]ÓU¯Ö¼gsì -±½^®kÊ^mÝúN$ãN¦/+rFÚ? %µ¹#Ò›³;Mµ]÷ZƒwÄIbÇG¢$¥..´•eöb¥.,”Ô~x”ÀçRSS;æhY´hQÏž=[µj•’’²`Á£Ñ\Â?£De`î€`G åªÜdÄþ¾ˆ€SÕwŒšà{¶"í_eÝýùYÇU¯ÖlÐ!<¬†j6 ëñ|Œ$GÙNÆ'E’.ŸÓæŽÈ¨z¦°º søÕ?+ÏÊü¬èû¹¦pÓ5oÕŠ¿±bõ5=ž‹ixqxX 5¼$¼Çs1’ö|[TÖÎÆépù´˜:­Â"bL‹–”“~:uÚóM‘ÛÓyÈó>è||Ç’Â . ïöô™w|Ph ¬Eß‘uLajÐ1üªWjJÊúªHo`ægE’zL‹‰¿±FZ¦ˆš¦„?ÔèþlŒ¤ÌIjryDl|Ø‘-ÅŽììÈÖâC‹/¸4<®u˜7g?s[^ˆiryDXI’Ö Cx³+#rØ2?=Øíþ²èÔ>[£.á.;«â |cÁ‚áááK–,1^.^¼xÙ²e ,HOO_¸pá²eËæÏŸ/Éb±8þàE&˜Œw„â5 \Õ}Ê^…GŽn«OREw²úÜ@ £.Æ^¬ã»lëf寞’W\ho÷`”Ѹõ‚ŒeEÇ3mÖ¼Óߺy¿ŸN@r2Š%µ¸ÖÓOÝ£s#jš®_³Q— ÿpnÜõLüѸ[¸¤“{Ü.y§C½‹NwÝÀ$ɱZ–ÑméÓUHDMS§G£c.8ósãXšMÒç·œ,½ó)‹Moàñ]Å’š÷>ëK-ûFH2–”’ÔæîÈ_§çg|RØyB´JÊ£ZßéåÙJ_lÇG¢ö­°nW˜x[¤¤mïHê@y8yòä§Ÿ~ú·¿ýíÙgŸ>|¸ÉdzóÍ7.\غukImÚ´™5kÖСCï¿ÿ~·‡¿ôÒKo¿ý¶Q]e±XRSSG•ššÚ¡C‡×_½U«VFEÕ¥—^º~ýz‹Åb¼LLLü¿ÿû¿|PÒ·ß~ëùŸÝŠêƒ¹{‚Wõªò²0Çûr›rkpB¦fªrKœ(hB°3…+.1,ezŒ¤-oŸ.Y;=í ùG¶;RI6GyLì6Øóxúη»V2UX9ã,aª‚úž¡™q÷n»úÍš’¾øÔáßÎ\Œ‡?î§gÃßÒÖŒ «¡ŒÉ.k®=cYQDMSÂÍ5¼={‰ˆ×a4éÑð’ð#[‹÷¯²ÚT|ð×⸠ÃÜ®UUíã?¾âŠ+®¿þúzõê}ÿý÷’öîÝïØ!!!ÁC*ôÚk¯Íœ9Ób±ûŒ=zôèÑ;wî;vìäÉ“URQõì³Ïû/_¾¼I“&ß|óÍ•W^Ù AƒŸ~ú©ÜCP¨“¤B¶BÊˈ¤*"GŸÎcðš©J‰ÌóÒ€ªVpätMúÒBIW½R³ÙU‘µME§ìÿèxܱ[Ü…aG¶g}m½ð–2£Š®“£ÿ÷|þòGr¯˜]Ó±[DŒÉšgÏ?l7*•ަºO¤ü¯¸Ù•§¤ø¥XRíîÿÉÁó8ËU»EXNº­ô鼩–×Õèò„}õ”¼Ÿ'åÝô¯ÚÆÃûê¶ ;ü[ñ-_Ö®›ä> ópc¦ï]nïæKY_[£Œ—ÑõM-ûÕØõyÑ_¬9™¶¢SöÄÛ#kÔ:ý£¯Ü³{Ö鑨ï†çnWP£¶IÆêQAÿςҢE‹¶oßn%-\¸ðšk®1›Í»wïNLL4vÈÌÌô°nÔË/¿üÒK/Í™3güøñýúõÛ¶mÛ°aÃŒ/Õªu&ìèܹ³3µiÓ¦gÏž~øannîµ×^›Pî!¨"Ž:)1S @ðµ ©Š–>Ué`<ÔLUéyK;Ïú&ª™öbådØV=™'ÉaXó%)]…$ÝY7)üðoÅÛß=}™Éƒ#%}û@nú? Oí·Ù‹U\¨ã™¶´÷ ÿsÛIy¼F¡ÓêÉy»>/²æÚ­¹öÌO‹ŒQ%8¥W§—6ÿ¤èôræwžùR¹g/÷žÔm¶÷{ë®Ï‹b.0]xkV£€Ê²qãF»ÝnÔ7¥§§¯_¿~Ïž=#FŒ˜8qbzzºÕjMOOŸ8qâˆ#Jk¤T7Þxã7ß|óÔSO=öØc’Úµk·dÉ’¬¬,‹Å’––æö¤cÆŒ™;wî‚ üq/AqäP”J!R!å6R œˆ¤tÍ”±Q‰#<‡+pîD&ä8¿ ‹Pç‰Ñƶ¹WDÖWEŽŒ©ù5gý€M¾/jïrëþ•Ö•ò¤2œvâìv­}!Õ“yÖ\{Ûû£o«qxsñ¶……Ûêtä¦")î°Ïœ‰Nj6 ë0Âý2FžÇY®Geü«èÄn›ãtͯ‰8‘U±í™ÂÕíéè¯úuf~‹~5‡µydKñ¶……?us<ÜÀvâö~_tpmñžð5éÑîþ37¡iJDVaŸ*6>¬q×3^îÙË»uøSôOcríÅj{_T8y=z´¤;w¶nÝzúôé‡îÑ£‡Åb±Ùlƒ6–|zøá‡‡ ¢’Ê¥ZÊxY·nÝGyDÒœ9sÆŒ³yóæºuë4h„ Ž£åNñññ]»vŒŒlÑ¢…—‡ êuR’XR @P0…@*á’ÅÅUtÌÊ›‚âAÇ9Š2…+º©q—ˆ#¢t<]!UpÔþóÿåY~°†ÕPË~5ºN‰~¿Óq•¬ƒ.ÉfÕ¶ùŸåd›ÂL /o7,Ò¨c2:wì¹å­‚µ/äKê<.ºÃŸ¢ÖÍÈßñQ¡­P-ûEt6ƘaçØÙ8öîM±kŸÏßýe‘­HM{Ft{*º¬){åŽÓe0¥[Nî±ýòlþþUÖðHµìW£Ëd×ʺ{.;,$w÷‹Z^WÃXUJÒþ•Öíïþ¾¾8ÿÍaªÓÂÔ¸[Dâí‘\îùh뼂ÌO‹Žï*–Évá€íˆ ;»Jló›¿ÎÈ—Ôy|tÇG\;Ïgw{ '²lÿ¼êDDMÓÀŸëDÆ2a€¯-_¾\RRR’¿ÿsTH‘Iù'Ëe”OöîÝÛßÿw åÓã…”KxÁ€€â9(od~Zôã¨Ü¶÷Ev{:ÆßcPHÁ™”H•‹@ A¼†”ó2áAÖ¸ŒÜ±œ+4@)‘“n“tjŸmá…9¹l’rÒmÿì}Â¥ÛÒwØÃµ8nõ„œö>!Ç%ÚõÏ«NM-.÷ÀE­sÊ ¤(Œ:O~¼i{÷î½üòËKo‡Àû—2)ÿjÐ1|ÃK'÷œU¼d¼)F™’Ѳéõ‚C›Šoþ¼ökë„Gš~‘ïØùÀ/Ö?|QçöuòÚ6ü5_™Ÿ<42î³R‚rßñÂöÍ/¨ß.ÜÃ6ÌÉ?¶½øæÏkßþc“ûNÿN·î/ùym·-¯së÷uNîµ­Ÿ}fTûWZoø¸ÖÝ›b[ö«±jbžÑ¸bLî%££îÙwý‡µm,v{$ÚX|ó絇ìôT»Tz|x~~¾£“éӧׯ_¿I“&Ë–-›>}zƒ š4iòÕW_9vð|º¼¼¼¡C‡ÖªU«I“&³fÍ*]¾d´8ש™L¦9sæ´lÙ2""BRffæ€êÔ©}à 7ÝÞa×â¸ÕmîˆÜ±ätEÕŽ%…mFzy ›@*´Ó(÷ß~ûÓO?;vlÀ€Æ 3Ÿyæ™Í›7¯[·.###++Ëhœ4iÒ¾}ûvìØ‘––¶k׮ɓ';:9pàÀž={¦M›vï½÷8p ++kÚ´icÇŽõòtO=õÔÑ£GwíÚµiÓ¦ü±ôQÆýw©Pûå—_Ö­[gµZ%Ý|óÍ£F:xðàÁƒÛµk7fÌ—£ÜöPÖ•€dRþR³IXÊŒ˜;ÖÄø¦NT=Óº_°éT¶íÓþ'µÎY”˜óa×ãy‡ÏüX»ùéßýë´ ËûÝMžò˳y=gĘÂ]Û=,“443nhFÜmËëÔivt{±‡äýn«ÓÒ5|È;d«Óâtcl«°¼CgFåH”"bLö’@¦÷5÷¯,þ즓§œÈúÊMÄcˆiT~ƒÛñxàåýwððFœC/ß…Û}Üž·IðC‹­yöƒëŠ;>õûºbkžýÐÆâ&=\+¤ÜÞa×â¸ÕÞRÃò½µà˜½à¨Ýòƒ5á–^x&¹py|^éö`'§hæÐ¡CÆö©S§"""ŒíæÍ›oß¾Ýå¨fÍš¥¥¥Û©©©Íš5strøða»ÝnÔL9¶ÃÃý<ÙlÞ¹s§±½cÇŽ²Þ ——ûöís{u§Nºà‚ JåvÛ핾Pý΂ȂøcÆþH@ðý­(:e[Ôú˜ãìÎ_úèòã§ö—>dAü±ã»N·çdØã¸Û}\þó< çNZŠ—tË):e+kö8ž“áÚþa÷ãnGårêÒ#Ùû}Ñ’®9Þì¼0ñ˜5Ïflç±9¾êv<^¾nï¿—o„³s¾|û”uÞ¯‡žüíïù_:i·Û¿º÷äooä}ßIcs¾Ã¾©œ_.yjë;ù[æåÿ8ê”÷º†‚Fy”=tk£ 406jÖ¬iTIÚ¿ÿ…^è²ç‰‰‰Æ´8Cýúõ%EEE9o» 0Ýž.;;;>>ÞØvl”«iÓ¦ŽíÕ«W÷êÕ«víÚ&“©V­Z‡ò²·W å¢NÊÁ7Ø“ô탧¬±¨à¨ý·7N/Ø$)2Ö”“q¦²æ¢A‘«žÈ;±Ûf/Ö±´âG)äùåÙ¼üÃöüÃö_¦æ]8Àu®–J–@r,„T¡w¹V³°F#2þUTÖZÿ±Æš§ór³m…Çí¿L=½àQÂjüï¹üü#§G•p³›Q9ûñϹÇvØlE²Ûä¨ r¹.ê· ß<·ÐšgÏͶý<éÌbLnÇã¡«²î¿ƒ÷o„CE/ße×Ü»Æo¯4»2BR³^¿½^Pz¾žÊ¸ÃÞ\‹¤6wD¦}P´cIQë‘ÞxVV5_ §iÓ¦IIIÎ7ÎÌÌlݺµ¤ŒŒŒÆWÖé7n¼k×®ÄÄDI»ví:‡ø—¿üåºë®‹‹‹;qâD\œ·?Ý^)xchfœãÉb>ˆcpÑ ¨õ³ m<ijÜ-¼×ßN?¯ýCQÿ¾ù¤5×n¼ þ%“¾t*÷€­nRx§GÏ,Õ¸[Ä¿®;aÍUü5.]þªI•tw亿ä߸¬¶Û\<*zí ùŸÞpÒn×Å>ÝxéØè5Oçýóª’âo¬qéØrFÕ¢oå#Nßm‹K ¿rŽû;à"ezÌʉyÿ–_³QX‡Q»ÿ[äa<º*ëþ;xÿF8Tôò½QÖyͽ#~™joÚ3BRÓ+"־߼·ë|=•q‡½¹£Û¢vS¸š¦Dx É¹*´Ë£Œ¾7\Ú'Ožü¿ÿýoÞ¼yµk×~úé§_~ùeIãÆKKK›7ožÝn:th‡fÍšåÒ‰ÛírO7vìØ;v¼óÎ;v»ýÁüì³ÏJßùzõê­^½ú¢‹.*}"I 6|ë­·ú÷ï¿oß¾'Ÿ|rÉ’%¥ÏèvÛ핸갴\|V"˜‚åòÉ ˜*°ŽWÈ{úé§Û¶m{ñÅ_xá… FãóÏ?߸qãÖ­[·iÓ¦yóæÏ=÷\eî¹çž‹‹‹kÙ²e‡RRRjÔpS27nܸ.]º”U¹6þüñãÇ×®]»OŸ>W]u•÷§v{¥Œ4 @FÌÁÜ=ç UH²ÔÔÔþýûgddø{ ŠïL `K¡P¥ – §B ‰ )úóŸÿ|äÈ‘ìììñãÇ0Àßà P¤Q@ «žuRAt½¤QLRþtÑEµmÛ¶M›6±±±Ï>û¬¿‡ˆªùBû@P¨ž™”Èz€ó`r)<¡ƒ¥£€ ,SØ*EµºX *P!…@d2™H£€à⨓ª†¥R*Ê52~ùgžüÅ%Š"‚ˆ£bˆL €gTHùÁŸ3¢( Ið†›@*¨‹¤‚tØUÁíHKKëׯ_­ZµjÕªÕ¯_¿´´4£Ýn·O˜0¡^½zõë×òÉ'} 9GQbŽäB>“b)àüyª"Ü UwÞygJJŠÅbÙ»wo÷îÝïºë.£}îܹ?ýôÓÖ­[7oÞ¼|ùòyóæyß§é<8:¡0  !ŸI8Oî)G(\™”1ZçŒ#??ÿ¡‡Š‹‹‹‹‹>|x~~~飊‹‹Ÿ|òÉFÕ¬Yóž{î9uꔤ~ýú-_¾ÜØá›o¾¹é¦›$eff0 N:ÑÑÑ7ÜpÃÁƒç>}zýúõ›4i²lÙ²éÓ§7hРI“&_}õ•c‡3f4nܸV­Z<ð@AA7c(}uo¾ùf|||dddçÎ7mÚäáØÒ·ÂYjjê“O>Y·nÝzõêMš4)55Õh_¸páóÏ?ß´iÓfÍšM›6mÁ‚ÞÝøJ@„2)”Y!Œ™”1fçhcÒ¤IûöíÛ±cGZZÚ®]»&Ož\ú¨^xaíÚµëÖ­;pà@TTÔĉ%͘1cÔ¨QV«µ¨¨hܸq/½ô’¤›o¾yÔ¨Q>þóÏ?oß¾½¤\|ñÅÙÙÙ’î½÷Þ.]ºØl¶ììì™3gº•››oI™L¦Ã‡ׯ_¿   ::Ú±]«V-«Õjì°cÇŽÖ­[KJKK»æšköîÝë<Ú²Æàri‡jРqö¸¸¸¢¢"ÇºÜ ç—‹%%%%++KRBBÂÊ•+›6m*)<<¼¨¨(,,L’Íf‹ŒŒ4Æ_Ñ·À±,ß6ªŽ# ™E—XC 8åR ¶LÊ%…‰ˆˆ(((—dµZcbbŒÇY5õD6›Íd2Ùl6IüñÓO?}êÔ©/¾ø"99YÒêÕ«'L˜°nÝ:Ç´8cO瓺Ý6™LV«µô0;”5—Vî±.û;»îºëºwïnTxÍž=û—_~ùòË/%ÅÅÅíÙ³'66VRNNN||üÑ£G+ö8 ϱß9É1o˜z÷îíï!@p±LŠ@ 8ž578Ç+A4}ÏиqãÌÌLc;##£qãÆ¥÷iÚ´é®]»¬Vkqq±‘éísæÌ3f̸qãåQ9räÞ½{m6[NNN…rça4iÒÄË1xãŽýá‡&MšT·nݺuëNš4é‡~0ÚÛ·o¿víZcû×_5ª®ÎMY³áå%ü=@9øq ^ ¥¹{¤Q@¥ˆðf'G™ãÿ[óR·nÝíÛ·_tÑEÆË»ï¾{̘1óæÍ³Ûí£Fºûî»K2bĈ‡zè•W^‰ß¾}û´iÓþñ|ûí·‡¾ï¾û$uéÒå·ß~ëØ±c^^^dddLLÌ®]»ž|òÉ lôèÑï¼óޤQ£F 4È›1Èc•S¹ÇºÜ ç®Ú·o?}úôÑ£GKš3gN‡Œö!C†Lžø`…®±4»Ýß6Åù›¤¤$ÿ P¾´´4IËEâ8§ IDAT—/§T Ê543Έr&äæ(¿BÊÁ¥æ¥ ¦*±«qãÆuéÒÅÑÛóÏ?߸qãÖ­[·iÓ¦yóæÏ=÷\éCžxâ‰^½z]{íµ5kÖ¼÷Þ{o»í6IÏ>ûìóÏ?þÒK/?^ÒüùóÇ_»ví>}ú\uÕUX¯^½:vì˜Ð¤I“gžyÆ›1x©¬c]n…³÷Þ{oÅŠÍš5kÖ¬ÙŠ+Þ{ï=£ýá‡îÙ³g»víÚ·oÕUW %wß6çßgu””DÏñãš:)ðF(ÕI8Oåà¸9Æ]¦pnÅ/¥» É"o ªƒàZÌ_Œ_iH£ ˆuRI€—‚}=)¦ì•«){.Ü® tž•/޹]aÌà+i8”ì!Àµš¯Ý÷_*iaBN«ùëý=œsp©øƒVqüË \œK åP)«V;§$!Ïe=2Þq€Ê¯Ç"­æ¯72©Ý÷_\™”1lœãg±Î+r¨¬X!Tм¨óA©Ìf³Åbñ÷(^á¹(:I+O}ݳ–¤Ý÷_Úwå)Ç[»%I}Wž’øƒV1< .*°¨9P‰\;÷ï`€a.‘””4hРŒŒ ¿ŒÁÃËs“=|øð¶mÛ&$$ 0à믿>ÿ> $ñ\Ge$Sm< .%"’¨ž¨*Åb±X,«W¯îÔ©ÓÈ‘#ý=UJÕˆ#W­Zµ}ûöñãÇ/\¸ðüû€L ¨¶%2OTCΫJ¨,õë×=zôÖ­[—f³ù­·ÞêÚµkË–-%Œ?>99999y„ Æn………?þxëÖ­/¹ä’7ÞxÃÑ[YEOV«uêÔ©;vlÛ¶íܹs_2ª´\v.ë¤f³yñâÅÝ»woÕªÕu×]·mÛ¶Ò—³~ýúQ£FÕ«W/22²gÏžï¾û®Ñ^\\<}úôN:%&&Ž9277×åzÍfsJJŠã/»Ýž’’²mÛ¶r4n ž‹‚ F&TOH*Å‘#GæÌ™Ó®];Gˆ ¾üòˬ¬,I/¾øbvvöO?ý´bÅŠ={ö̘1ÃØgæÌ™‡^³fÍ×_½råÊrÏ2{öìíÛ·ùå—«W¯6*¡ÿ/]UÖI%­X±bÙ²e©©©×_ý¸qãJŸ¨S§NùË_ŒÁ;{å•W6nÜøå—_nܸ122rÚ´i.×k±XêÔ©³jÕ*£qåÊ•qqqmÛ¶-÷ÀÒçU‡L ¨†eq·®æø0ðÏ›8OŽr¤š5kvéÒå¹çžkݺµÑ¾~ýúF_íܹóÒ¥K$¥§§8pݺu’.»ì²¥K—ÆÇÇKÊÈȸòÊ+\ÉeusÇË.]º|øá‡^x¡ËÜî\ÖIÍfóæÍ›ëÕ«')///99y÷îÝ.ו=kÖ¬ï¾û.??¿OŸ>O=õTãÆ%uïÞ}Ñ¢E]t‘¤ßÿ½oß¾6lp¹Þùóç¯]»öµ×^“ôÈ#tïÞ}èСÞxÏX¥•%ZáG|„¨ªÃÃFiTÀ®qnŒ0`‡øK•ó”=@€(룪sÈrèÐ!Ç”´V­Z>|ØØþý÷ß[´hal{3gíàÁƒÞOm+뤒Œ4JRLLŒÕj-}l“&MfÏžmœñÕW_}øá‡—-[&);;»oß¾’ìv»Ífsžüë¸ÞÛn»mƌǎ³Ûíßÿý‹/¾èåTǿըQã’K.™>}zÛ¶mý;$IÙÙÙS¦LY±bE~~þÅ_3qâÄ .¸ gÏžW\qEÓ¦M'L˜`´7®AƒݺuëÓ§OÏž=ûÏš5ë‹/¾HNN¾ùæ›SRRícÇŽmӦ͵×^Û£GÇ\¿?ýéO7ÜpƒËçc'õÆÐ¡CgÍš•œœœ’’²eË–×_ÝhôÑG»wï~çw&&&>öØcýû÷w{x¯^½Ž?~êÔ)ÇEyy •+//oÑ¢E—\r‰ñò¾ûî6lئM›6mÚÔ¦M›©S§í¥âðŸÿügÈ!3fÌxðÁ=ŸkõêÕß|óÍêÕ«<8kÖ¬Ò;ò3CȤ€ê P57°²uµÅ[o`ERF¬Ï ¿ã#D€sþwšZµj-]º´cÇŽ.ûäååuïÞ}Ó¦M*û±!“'O~ûí·,Xà8¼¬g‰˜Íæ•+W:T2pàÀ_ýÕåŒÿÌ\ãœEÍÏiÂE̓‰ÉXbe¡6 ¡Íȉòóóß}÷Ý©S§~üñÇ’Ö­[÷üóÏÿöÛoÆì6ǧâ²²xñâ;t˜å–óƒJ“þ3CmsÒ( râ”=â Lgó÷p*SHfm€Cttô=÷ü?{wU}ïü}f&3YØDM¢‚UA)WEËbmmoµØªÅ­u­m­R¬Ú«¸õQq¹.Tp«¶ÚÛŸ¶E4ZÑ•*›d‘’ ÊÈ2ûùý1 “ÉÌd’Ìž×ó‘É™s¾ç{NÂÌÉ{>ßï™.VºòÊ+/½ôÒ>úhçÎ7n _Ç»mÈ+¯¼òꫯ>öØcá%ñn<")ò^"}úôIЫ\¾gc÷€–[Tø%¸À¢–ô)€pŠÁzè$RG}tøÛ¢¢¢âââÿüç?‘³+Ƽmˆ¤þýûÿùÏþÃþ°`Á‚À’x7‘tÛm·íÙ³'p/‘óÏ?¿egòåž!dR@¡Ê­@JdR EÞÉ¢e‚“wÅSùÒO ƒ******FŒñÿ÷óçÏ,|ðÁï¼óÎaÆ]pÁ§žzjx嘷 èׯßË/¿üÊ+¯Ì›7Oño<"é”SN9óÌ3O9å”>}úüüç?oÙ¥<ºg™PrtN¢pN‘›ÝË¢õD Â\;Q]͵îe3’@>b~Vd—ˆ5ÙyaÈúçÌ!•¼i",ç*¤¨“J ^|cFˆz*§Š§";³·%»uRg)—£”šgRYÏPrJ2gÃl®e Y9«‘;%ŠÐ&Y»GyB¹H©y)±TGÄ §2Y6EdFá× Ëz& Ur:RD’ø¶“ÇR)9öŒ…S1Ç E@¡Ê¯? ò«·€HdR@a°e»É \£¦Qó.¥ªÙ¨´˜S¨óü¼ Àõ•±qž}߇V¿KÝŽõú§ÏDŸ¤åËRUóßÖ^ëVÙ{š=Žó ¾ØÓu˜¿ÕMrj„Bø ›Ù}”ÿØ_¸»ÓÊ! Ì”• ·ƒ\{“¼\¯ŠUד#³t§UÆæ]Š7áTJÚd˜€ÎiÍm޲£ÍÓþØô_Ë›Ž¹Ü³óÏE)ßÅ”• m½Ÿ²²á̪†“6õëÿðºâƒóìb@¡£þ¯¿5ö9Í·öŽâlwÔIù.o*¤"EVK¤©€(‹¢R¶LTaœ@Èuë-ãæ9-Iê5Î×k\°ð;×µå)ûªû]FŸ ¾a׸GÄxy¯}Ívüo›}LICâþ×%%#æ<5òF£—)iÄOÝ^W<ìjwj{XÔÃï­¾úlcàÅ¡¡W¸ßýNiÌM¬³·ñÖ·Ëù¥ÜûTÜÏu‹+°0Á©ˆþ)[K4þ‘¦Ä«]f¿ÀYÜ×”4âW¸‘í/íøcÑ 8»h} ªtÿ í®fe>) ¿H )µu§6jµäP:§T}ª.ÝïøÞSrEëècŽší’äÚkl¶hͯ'=æl¹šó+㟗–J’)Ó/E¼WÌJJÊýî}mx#K²ÿž–¢®Á·žºõÖÍØV[|„'ÎÞ¬³·ñÖ?n®sÛÓö­‹ìV‡FÜèê;ɧ„§¢åÑù]ÚùÿlÕ ãnJ°#÷>£¤Òßð¹±íû˜;‚#Ë6Î+ý+·¤MóìýÏñ&P‰/ÇM¿<û-»«¬[›,Úò»eØL‹CM»ŒÍÿ{xò¦¨ÞÆ[-^oã­¿övÇàK=eL™†éS«§¢%¿K5ÿ¯¨¤ÂL¼£òižØGÿÊe-Ñ–§ŠFü48ÚÎÑÇ<éQçG×›^ ¾Ø#©ë0ÿöìGßí=dlœ×ú¡r ™G:K Õ>„GÐ B¨Ü¿LŒêa‚|*Á± ø¶oË“Žº †Ånôëó›`¶2h¦÷_³J|MÁmýгý9}t}±ó+ub¹ôðÛ=÷¿ÿÃ_“Ñï ï1—Řx;Ü“äo´|b™aUQϱþñ œ]Ž &M£ç¸6Í·¯ùµ¥¸Ÿ9h¦g÷ Åìm¼Õâõ6Þú}N÷­ù•£±ÆRv´Yy{èÌÄ?-Ú°ªë0å¯]‰wtÌeÞê‡-ï_\bšò£fs?9Ž0Ç=ìüèúbÓo ¹Ô=êf×ú{[Ÿ.sô6ýÀóeU+‡ÈA)Ϥ¸Å&™ ;ªªª$ ><Û:$^U0Wr;@>àÍ­þ ª««%Mž<9CZàˆ’Â‰@*µxÓDR€ÔHßÔà¹&ò ":ü¸ €<ÂØ= ÷HÚ¯ó„PñÄ §H¦Èºp&%Þ‘œD h–Q—zá3ªdŠSš#øA@ž dRb<“¤ 'äòMè"‘C%#åÉhŸfR‰¯ÐtdY2:¹gDõ“`%ñ’)ÎÓñ:)Þ¸t €ìh™C]²­{¼•®‹Ü*“WEäP)•LåBÂ@çÁØ= H@¦EE< r¨¨u2KE¥Cà4R0@†‘I¹†@ 2*2åI&ŠŠ”±XŠ(*݈¥È<2) §H@†t$ŠŠ”ÖX*²“\¨¥[Ìq|œvÒ‡L ÈRv©Š¢"¥<–"ŠÊ¢È‚)b)Ò*ùLŠ7e ­¤ ÒEEJI,E•#ˆ¥È ꤀\`Év `¥;Šl¢T €4‰™Iqƒ ݤ sRR*E%H£ˆ- #øH꤀̳e»йò£@¢•I%ˆ–Z¦Wi½mrYàŠ™›UZSV6ðö ddÁ%Ûº·Ì˜’¯™J&Jðù—Y ò¢Y (‡\cœÙîm’œïtë-꤀Œ €ìˆ •ZM£R[E&•w***b._4èÀ¥Û{(ö“ÑjjjRÙ'h;r(ä¸I÷2)éF 9!åyS [CfÄ‹œ»t{T킸 @ºE¦Q޵ÅYì À¤1dR@&H@§@=T.K6Š2;¶#©nKH7¢(ä8ÇÚâ)jå§üºéB ˆø)/ÄÈ¡:9%–¸ñP\îÉÒ‡@ €L‹Ž¢ÒšC%)܇æÉ±€T Ô›P  C2]Õ>.Q0€t" ír±$*1 ¦N–lw€BVQQÑ,2ó!ŠÔ¼ÃчHƒBº[îoØÞžQšøˆÂÏÒhR¤EþUE%kÕR:nï*ëç/íÿÄb-Ö§ú†_ç¶÷4%ÉÔæGí;_µÉЀoy‡^å¾Å[®à³\]|`5öÍ=âlAݤ#ÛæƒåËÚs‰’¤ÍØÇÞãê1Æ—é¾ÈyTH@ñûý~¿?j¡×ëÍJgÐ>!ÁïÍ<¬ŠŠ§ù±D)´Ýç(xgò²Æ /4YË̵·;Ëk^-Ú¿Æ2ñç„çšö­¶Ô,±%^|v©ÍŒ~x6ζSV6´šwtdۼо£Hüãp~eô¨l €H@ìÙ³gýúõ’öîÝûÉ'ŸlÞ¼YR]]Ýk¯½¶råʦ¦&§ÓÙØØøÉ'Ÿ<õÔSË–-“tèС͛7ïÝ»wݺuYî=âÈûÑyÉc€9ñAç§ú¬%²÷4‡_ã>°&øçIÍ2ëÐ+=öÞ~ÇæÐ«<µËl‰—Kò4¶.´žãŽ·¯Û¶ªÝÛ¾û½’†Ï-’œ»å§•¹ö’>·¼û½I¦OŸý¯ýíé¥+Î([{‡Ã×txÃíϽ=£ôÍ3ËÖßíð{ZÔI{Þ·¾ÿÃÒ7&•¾ûÒÿ/ØŸx .ŸXöùK¶|»tùIJw¿Wrø5ÜÔÊï•Öo±„K½LŸ±i½jZé[ç”îx±(q³­ž–åËdjùieö£Fä%3@/¼axå¦Zãã[Šß<«lÅäÒÿ¼Ø½ßˆ:Æ7&5kÖïÒº;ožYöι¥Û_(Šl0üÕj7¤dÁÓO?}àÀ•+W.Z´hÙ²eëÖ­Û²eËþð‡¦¦¦¥K—nÚ´é³Ï>{î¹çŽ8â¯×»k×.IÏ?ÿüºuën»í¶;vlܸ1ÛG€h%ŠŠÔI@¦ìûÀÚ½2XàÔ°ÍÚmd°¬¦ÛHýVKâå’>û_û€ïzÊÆ-‘J°m«Ú½mŸS}ûÿm•´g¥ÍRd~µÒ*iÿjkŸ >IÛžµ×}j9eQÓ×—4XŠ´ù1{xÃý[Ny¦é´—Ý{-OµlyÝŽc.sŸ±¢iü£M?µ&hðà§ÖS5MYÙ`+Ó¾ÕÁõ÷}dµu5»sø¤mYXÔ°ÕrÊ¢¦Ó_njÚmIÜl«§%PxÕ‘:²–-||sÉÑßóL^Úðõ¥¥ƒüÕ ¢ñ¬wšíë³'íÞCÆi¯4žòLÓþ[Â;FÝâ*ŸF):R>Ÿ¯ººº{÷îýúõëÓ§OMMMYY™ÅbÙ¹s§Ëåzûí·%Y,–õë×ñÅ’l6[MMÍàÁƒ‡ R__Ÿí#@B†ZN¢Q€:ÉaȈƒ-›ØGÏÖ7ùšd- >e-1}MFâå?µÜl}¡'Á.âm›ŒvoÛûß¾ÕI_½gøßÞ¯ÞµJÚ·ÚÒûŸ¤Ú×l#np9ú˜¶R ý‰ûË·W¼ÑãèeÚ{š#~êÞõ÷YÖb9¿”{ŸŠû™£nq&hpÄuž¢î¦¤ŠÞš×Bg¯Ù*¦7‹cj—ÙFþÌ]Ü×´u5GÜÐJ³9¥ívê³=OôY²•ièî½ÿ²†Ÿ c¤/Þ°¸ÁmïaÚ{š#Úì7¤nu×ëEÇþ2nU€´bRsÈ‚ÊÊÊsÎ9§¨¨¨²²R’Çã)**ºòÊ+½^¯Õjõù|6›­²²Òår9ÁÙ4.¿üòÀjYí8ZcFd4¡ùw 9€”Ú¿Úº~®ã¸¹Î’Š`©ŽµD¾&ÙÊ$É×dXKÌÄË7Î+=ÛeX£[Žœt<Þ¶ñ¤dÛ3ßlØø€ÃçÔuÖ1w4½ûß%>§~j­üµ[’ó+㟗–J’)ÓßìÕµøÈà©()÷»÷QÍNYÙpÜ\ç¶§í[Ù­¸ÑÕw’/qƒöÞÁûŸíýìñÏAC¦öüÓzìMÍâ÷>£¤<ºÊ,^³ñNKZçz¯[oÝüˆý`µ%8r0Ö1Frï3Â'3ü@’kñéïì'Üï´ä[5¤€3ŒúC{`…ee‚›EƒÄ{jÆŒ‘߆c&›ÍþWR8ŠZ 9-|YkDü«‚H¦¢^ÞÌ8Ë -v¯°mZ`?þ>g·‡Ã‚²Á¾ƒ­½Æù$Ühé2ÄŸxyÝ:ëû?, o¾/[d oÛxR¶í@ÿþ\Ôm„ßÖÅì6ÂÿŸ—‹Êù-vS’£·ùµ'š}b¼C8¿°⹦Z‹½—Ù²ÙîÇú¿ß)iÏûÖ ÷8úNjLÜ`˜­«Ùûdß®¿ZMS}&øl]š­lïe6ÕZJ4;ÀxÍÆ;-ñr(Ã*¿K‡$yêÚùæñÉLjëܽOöÙÊLo£Þ:»• ì=ÍðÉt~!ä÷ko+y£;ñ¹V ÙP˜*šËvwÐ)EM±”×Ü¢:ÏìQRdÇ‹EÕØÇÍk–FI*Ÿêûì‰"÷^‹kñÙãEáY~â-O Ô2‡jµÍdtdÛÞ§ø¶=SÔûk>I½Oöm{¦(0^OÒQßòl¸×ÑTc1}ªßj¬½ãðQç¹÷îýƦyöþçÄØÝÚÛõÛ,¦×i˜¡»Ø%h0RÅ oÍköÚ%öòéÑ-—Oól|ÀîúÊðÖ›æÙ7ÛÖÓÒu˜û vŸS®¯Œ ÷Û¬9Ѹ­‹Ù°ãðß­~· ›iq¨i—±á¾Ø¹y¿³¼›æÛ=u†û€±i~p§ŸÞoÇqÜþÈ&*¤€ôˆ*ÈÌ_n‘ûÊß¿{S!fU[[›ánü}B†wˆœõ_2¿ ¦Z¾’äE·äM ì’Þ»¨$¼äŒ7¬%:ê]æèmúç˪ī šéý׬_SðôŽžãÚ4ß¾æ×–â~æ ™žÝ+ZÙ|èîOïw¼óíR[©9ðÏžZ$Õ.³Õ.S8KÇÐB­2L“KK •‚Cör#êœCöÂiTæ¨(ŸP*é’mÝ3¶ÇŃëÄEU–ñÿg™çàûp[ûÙ‰_pª««%Mž<9ÛAçUUU%iøðáÙîH"®1NI޵ÅÙî:¯†Ï-ÿþEñijLfe~cÓ„7M„1d@AÉ4 ˆÁŒø 3"¾²(f7bv€¼²éA»ç áÚkT?\Ôçô6TÕH+†ì(@¤QÈ1g7kx:$È¿ˆŸ¤t ùÞÌŸÓè{ºwèîÖ7RdU‚{Õe¸fŠ Pˆ|Ç3à;±§ÓER䆨<(i ²U!pÿ IDAT„9¤ ]Î~¯Q¡‰Æ3†Í ‡™þ/ K¨€´ dRi½Ý^8öZ>±ŒL @Ž#€4 Iý}B©¤ÅƒëÒ‘IEV`EÈ Rvg¿×Τ”ÒR©pE H@&¤¼T*²0êÒí=TÑÁöÚ©¦¦&;;ϘÔÈÕÒÙR™T&-U‡–›Ò/¥žR/i6óç·@,%iñàºvOv¹í¥Û{\º½Gj:×.YJÂä3*¤€œqtžôGÉ”.”VK’žÞ•6H¦ôi¡ty–{ŠŽˆ*•ê`;µªMUÇÚ¡¼¼<‹{¿¨rÆFi¶ÔCê)Í‘6†–/–î’úKåÒ\iQ»ˆ” —JeesÈ.*¤€¬2"†àM“î—®—Li¾45´|½4>ôxœ´>Ó}Dš*$°|bY⸩ פ€œñ4AºM’4XZZ^/u =î*ÊB×€Œi5ŠŠZd ÈGR@VEÎP>KºDú™$éwÒ¥Òß$I]¤z©›$éÔ5Ã]̦vO˜ÍÜFíS[›Í©¢¢¨Ä7&OÇØŠX È/R@Îx[zUrH’æHá;§–>”Î$}$ÎNïЂ#­H’æµÖ,·òdVÔ½”·9·K9‹ )9"©¬ H*s^–VHã¤Ò_B k¤±’M²JGJ_F¬ß?ôà"i™´OÚ+ýUšÙ¼Ù]ÒûŠ×làVžìVž€ÌKw•™ÆtR€&ñ_f$½*Iz]š%}K’Ô_z/TÊOOééYÉ”¦EÜ—S¡¶JÃ[,ŒÙ,·òPè***²Ý…Ö?„ëd®K_l¾û€ÜD…€µ©`Š4 È/ ÙÒÃ}E}›Ö¯È}!ÒRi†4LÚ(IÚ!Y¤À§§¥a’$Ÿ4[ê+•J3¥†ˆÍï“úIeÒ,ÉÕ¢YI¯K•’]$=z6^ƒ†4O(ÒЈøÉ”Ž‘ÖDüø<ÒÏ¥>ROéÖš],Ý%õ—Ê¥¹Ò¢Xça›ô-©«T,M•¾LxÒL‰Q{ ³.ÙÖ=ü•Žõä*¤ä›¶I})UK§KS¥*i¤´DrHK¤+¥·¤i’¤»¥¥ÕRwézéféáP ï„r¢K¤Û¤ûš7+ébé1é\i·t§tek ®’VKGH'Jo…n‘ö¦ÔS:.¢çwHë¤ÕRé7¡…ñš]/­3NZëTœ+-þ y¤ßH?‹¸­@Ž!c b¦Ù¾W’TUU%iøðá)ëMa ŽÚk«eÒYR‘4UZ,ýXZ*]/½&])UI?’$-”–JGI’î•ÆFäGó¥~¡g„©p³’J¥i·4Pz2´U‚'!Iš%= ¤ž’f5ïù3Ò i€¤ˆÛ¥Åk¶^êZ§«t(Ö©XzP"Ý) JxÞBÊËË™Œ@j1d@¡["M—$M–VIÒûÒlé=©QZ%M–$ÕHc%›d•Žl>œmpèÁiw‹f%½,­ÆI¥¿„&h°èÁEÒ2iŸ´Wú«4³yÏwICZN¼f»Hõ¡Ç‡¤®¡Ç‘#:ÿ)M’ºH†T&í‰ÒÚ®@"RòIpRÏä'ÉòH+BƒòJ¤Ò#Ò8©‡4NZ +K’úKÛ%¯ä“LÉÑȶЃ­Ò‘-š•t’ôªô•ô¸ô“Р†õ”Αž•ž•¦I=š?Û_ÚÚb“xÍŽ–> =þHzl†¾$ý·t´SòKu©É› :°|bYø+-è²  ½#ú†¾*Ý!Ý"I:[ºKº3ôÔ¥+¤Ò i“4Wz!ôÔO¥ßK’n.ŠÕì÷¥_KC%¿äK¢ÁH³¤_HŠ”v‰t´Pê"Ý.ÍOØìÅÒ­Ò+’)Í‘.‹µ¯&É.•HÛ¥ÙñOZ$S2Ú0j/œIMYÙxM¤öLYçöÒ@ @ž Î$•äÔæ‘ë$M•nÎ’$M‘n’¦†žºE2¤³¤Zi´4'b«IÒ©^úžtG¬fϓΗ¶H##¦ OÐ`¤)Rd Í$évé&i¬dJ·µÖìUÒiTèqÌ@êiéFé{Òé&é¥8]j‹K·÷_ŒFVHE>&œ  UTTIh7)mióØeXDŒ5¶y¤e‘fǪ ¬óË„Í^(]ØbÃÄ F®¶#Î EÒ¼•Sñš5¤ßJ¿m±<Ò¹Ò¹ßþ$îŠÑýI®H*2xŠN‰| ŸC¤I.ßW¤¼¼<Û]ߤä­dФªÓ³ë45[@â…S*Ü?Z×î©“ÍoHŒÚ¡P_ç©E  ÿÿòGžè„áTg‰¥"n/À¨ ä¦Åƒë.ÙÖ=Û½èÔ"_ç'əŞ ¯ùý~IK³[ry½^›¿g<Æ`@kÚ8µy…N™ÃiiÇRÍïtI•a_øWýs×J¯Ïiö>ÎZùcÇ€3‹”Òð¥öÞõO¸vൕ“m'ÝZRÜ;ÑýM[íR;ú¶xp]à¥HGŒµžrgIÏ‘Öö²oÊÊטlw9oÏž=»wï=zôÞ½{wîÜYZZ:lذºººªªª^½z?Þ0 ¿ß¿yóæ>ø oß¾ßüæ7:ôÅ_ôêÕk×®]•••Ù>m@  /µmjs䤨ԩ`¦ §3Ád*üW|ü®’C冷¯kìw²íÔ¹]meÆ—z×?á ¤?)´þIרËÿõx©·IÏw¾s}ãÙÏ—%X?^—:6÷6™Ÿq¿sCÓyëÒ‘ÖVSV6D½tG=ÛŽ6Û] ÍÜFí“ óU=ýôÓ&LX¹rå?ÿùO·Û=räH‹Å²|ùò=z,]º´k×®6›í½÷Þ›>}º×ëݵk—¤çŸ¾_¿~o¼ñÆôéÓm6ÛÈ‘#³}’E HBꊤâ)¼â©‚*˜"ŠÊ%{>öýl™µØÔ‚­ÿ›BõD9ŽéÓ¿çÜü’ÛÓ¨gÛ&ÜSb+5댻¹xýS.o£Í(:宫=zSž þ§³•jüìâ?ØŽ.)T•|ßb²•#hÿøàh¯úÿøWÝéܵÒkzÍ#Oµö»Ò@õ–ß«îsnyÅmú4ö:ǨËÍz¸Æ÷ÖU•W9޽ÔU®YÆÕê™A¤ T¤óÌ3-Ëúõë‹‹‹?ÿüsI6›­¦¦fðàÁC† ©¯¯Ïbç´€|E‘TK2œR>ü;–RžüÞ¶ˆˆ¢rAï1Ötø½Ë€ÃÓ©rŸÈœeÍ£®=k|ç.íRÔÕXu‡ó£ûœ'ÿ¦$ðÔîUÞoþµ«aèÝŸ7~ü€sÜ-Å v·ë]oŸ›LIv©}}kÉÛdn|ÎÝû¸`V\ÞxòÅ_¨ÄïÕÇó]ÜÕtúƒ¥’>žç<°ÉwîÒ.E¥ÆÇó]‘-|þWÏ?ç4MüméQg´réÛ¦3Ó %™@EJÁ«t^¼Z†Ds3¤²²òœsÎ)** ¾óxŸÏf³UVVº\.‡#:_~ùåÕ²ÚqíA hƒ´IÅ”`dŸò§x*:–Rn'S±þ&!ŠÊ“-ýøAײïÖûœ:ê¿lãf—ö‹}ö’ûÌß—–i‘tâÍůM=}¾v{IÉFàÁßf6$ˆ]ö®õ}0×9eq+1D’]J¦o‘ÂÓHÙJo¼ìCxàžU:ágŽWN;øvË+žs^(+ëo‘ôµÛѺ'\Ÿ>í>kqYïÊÖ§ JþÌtÉÄk¹f.¿,#7͘1#òÛp̘¼<<…y8ŠZ @~!ÿ(’Ê 3'>;Íëâ©ÈL'FÍ”²ú›L•?J´L¸¯D*iúÊ\û¨óík§þ)ÆäJ _ø_V/I¦L³q—£‚iQ×–¦¯üñvôÅûÞ•75M~¬´ëÑÁõãÍ •d—’é[¤Àî|N³úîîr~ãÅ2I_ýÛ÷Ñ=νë}ÞFS:¼mÓWþ®c¤`ÕÏ»‡~·(™4JIŸ™Â–¸ *ÁKkÔ4R¦:ÓÒ?<"HÈcÁKUtVÉOµ\9ë¢ç>ˆú³<­ƒÅÉ¡òEIãÄ›Šÿ06öO¥}-Óþ\¨BŠR¿ÓȘíð—ô‰]Ê´}‰çƒ¹Î3ž,M2ÊI¦KÉô­%k±1ìûG÷窺ºñ¤9Åå“lö®†§Á|aÌÁЮ-‡vø» Žnó/•ýõ†¢®Få•Á’ Ã*ŸÓ ÌxåÚßì¿Y2g¦ð´;JùV€N…@ ´Üþì4Oó©ØÉT@fKÒÈ¡òÅŠË*¯tq¼ÍÛhnø½«×¨``dïfÔmõwŒQF\dï–¦“SÒå(KÝßšG\“æ—žZõ?Mï/•´ê7MC¾c¨Ë†§\žvŸýlY÷¡ÍB™xsHÅëRXò}kÉç4«_pw U?ù\¦¥HÖb£~§ÿ£ûáÕ†~·è_·7M¼¿ÄVj|ü ók·Ç–iùÆKeŸÙ`z5æj‡¤^£¬ëžp¾Âî®3Wý3r_­ž™ÂŽ*µ-„Q$•9ûF ÀHÈo\ª"ž¼Ë§¢ò  Tÿ‘@å©9þý;מO,v£ß׬“ F9£¯p,9·ÞÛh2£ÊŸ8dèï54îö÷n=îÚÃS®ôûšíÿsÈÛ¨AÓ‹ŽÿiŒi’>˜ë”ô—)‡ÂK.Zß-Áðâu),ù¾E Ì!eXÕk”õô‚mNümÉw:«®i,+·T^騾ÄX>ö†âïv¾:µÞ45öúf –ö³œób—¿Í¬÷û4ö:Ç„{JVÞÜôÉCÎÒ¾–Ê;>Ý“ü™ÉSéN ÒѲ#7†çè$ Óäo8 WTUUI>|x¶;’g‚·ób–¡ëÔÚÚÚÀý¡ó4ÔÈØŸgè ª««%Mž<9ÛIJ¼*'äõ™‰º„ÈÍ—8×§$ÇÚ¶%}‡ÓyÞè3äd*¤Ú}øýÌØ·@´ÝŽ_ûöýÆ¢Uùõ¦‰´¢B @Þ£H*£ å³Ó6ÕOµ\rÇâÁuÒ ’>³B^¿‚1_d¦åöð|…„@ €Öo^žƒCütZŠxä>)„"©Ì}vší~¤Q[ó©–›9+G¥¥[Ξ™Vã'IG?ýoî¨ÿÜ*…Αn¤_úФ¦¬lX>±,“ƒdyr€B@=?Òªå…,€4I&~jùg|UUZ:S°VKJÕyÒlû"0SºYzR2¤«¤»Û2â>SÃó¿íé‹¥Âÿ›–O,ãMÈAR´€”h_üÔ ¥¸Hj‰4#íd¦ÙöòÒ»ÒÉ”¾#-”.Oq¿:"ð†x£LS©Tø?o¾@Î"P r«ž¿àÊÔæ)DD UÄO¹b©t4LzM)íI;¥ri£t®´YòI·J ¥zé[Ò“Rø%ü>é©^º@zLr4oVÒëÒMRµT.ýJºRRü éAéé?Ò1ÒæÐ;¬) •þOº¶ñH·HÏH^é×ÒÏ6»XºKê/Iš+ÝÖÆ@*#S›Æî)Õ¥R‘ÿÑxŸriѾˆ*æ†òN2Ù“ˆŸÚ¡ãŸ<})UK§KS¥*i¤´DrHK¤+¥·¤i’¤»¥¥ÕRwézéféáP ïHk$CºDºMº¯y³’.–“ΕvKw†© ®’VKGH'JoIgH’Þ”zJÇEôüi´Zê"ý&´0^³ë¥ñ¡uÆIë;vÒÒ&å¥RFyÄ0Mj €\QUU¥Â‘43‚3Iñ–†$ÕÔÔd»y,f Ö¹¬ººZÒäÉ“³ÝdG’Ù“Ò?åÅ%„kŒS’cmq»[HÍ»ü"i©ô'éui±ô¢4]ª”6H¯IH?’¾! ’–J£%I»¥±Ò’$CÚ, •$UKgH;›7+éhégÒ·¥ûMÐ`m¨”éaé=éIÒ÷¥Ó¥«#2¸Ò )ꇯY«ä‘,’$¿d—¼m€D(’Ê S2²Ý…Å’í@›ÕÔÔd» €ö#´Æ”¤òòòl÷@ —‚ER %€)ù*/¨(-ûLD "—b¦Qµµµ™ïI›”——G-©¨¨ “‰}ñ†mÓ<»{¿1eeC¼u–O, <~¹Œ@ @þ §Q¹Ÿ@E‰êp Ÿ"“tN{WY?¡hÿ'k±Ž8Õ7ü:·½§)I¦6?jßùªM†|Ë;ô*· %Z®à³\]|`5vgÛåËÏ'Jp:²mŠl~Ä>öW1¾v·@J ×0©9€<“¿iTKp´Ûç(xgò²Æ /4YË̵·;Ëk^-Ú¿Æ2ñç„çšö­¶Ô,±%^|v©ÍôÇÝW¼m§¬lh5¦éȶ©âüÊèQÙþ4 rR@ †a´¾R>(ຢò݉:¬%æðkÜUß( |[³Ì:ôJ½·_ÒЫ<[ž*ª8×›`¹$ÏAcëBû‰óï}¿$æ¾lÛªŽlkúŒêG‹v½n3}:æGžžã}ŸüÊqÚKMᚯ•”޽ÇéüÒØü¨£ás÷Ñ ‹ÝG׬ý@)ÖòÓÊ$MYÙUë”LéS°…‰Á$5Õ›rìûÐjzÍ^ãü£ouÊÓ–O,~½kÇ‹v×^ã¬w7ëwiÃýŽ/«l¶Rsà÷=›±z¹*°´ dSmmmyy9£öܾ¬Ý+ƒN Û¬ÝF³ªn#ýõ[-‰—Kúìí¾ë)·D*Á¶­êȶ[5lµœ²¨ÉV¢-¿·걕ißjk¯q>Iû>²Úºš]Žñx]é¨_º˜èsïÓÖ§íjHµ ¡Úªe ß\2òF×q¿qú½Úò{{õ{åm®ÀS?µž²¨©¨»ÙÂgOÚ½‡ŒÓ^i”©õwÛÃÍÔ¼f;°ÆÚîî蜲ÄešÍ¾b.Ì‘¯–}È7Z6-°ží|ëk’5Tçd-1}MFâå?µÜl}¡'Á.âm›ŒŽl[»Ì6ògî⾦­«9â—¤ŠÞš×Bƒ_³UL÷J²Ëù¥ÜûTÜÏu‹+ùöÛíÔg{žè³8d+ÓÐ+Ü{ÿu8Nq'*’ôŶ7¸í=L{OsäO›êºuÖ]¯ûKwº  P! kö¯¶®Ÿë8n®³¤"Xßd-‘¯I¶2Iò5Ö3ñòóŠFÏv- t"'·m<©ÚÖ½Ï()oV·Õÿlïg—x2µçŸÖcorK:n®sÛÓö­‹ìV‡FÜèê;ɧ4Oš^·ÞºùûÁj‹¯I’"§‡ NŒâÞg\~ ÉµÇøôwöîwZŠøD@ÛHÈŽÝ+l›Ø¿ÏÙmÄጣl°ïàÆà ¶ƒ-]†ø/¯[g}ÿ‡¥áÍÃcÓ"sœxÛÆ“ªmí½Ì¦ZKé€Ã›Øºš½Oöíú«Õ4Õg‚ÏÖÅ”ÔýXÿñ÷;%íyw^×· IDATߺáGßIŠŸCVù]²8$ÉS×ΙO?™ãq»÷É>[™émÔ[g—%^ßÞÓt~a „†Î/‚ãlücímÅ#ot;úFh3†ìÈ‚/U?b7¯Y%©|ªï³'ŠÜ{-®=Æg•Oó&^¸Û]øžw1sœxÛ&£CÛNól|ÀîúÊðÖ›æ§^ª˜á­yÍ^»Ä^>=ØÔÚÛõÛ,¦×i˜­ÝL¯ë0ÿöì>§\_î·'X3rÒq[³aÇá¿þün6ÓâPÓ.cÃ}ŽV7ïw–wÓ|»§Îp06ÍîôÓûíýÏñö8ŽÛÿh*¤dÁ¦vIï]tø¾xg¼Ñ`-ÑQçyw+gK:ê[ÞŠÁÔ&ÞòdÄÛ6œ¹DÞ.…Ûs™·úaËû—˜¦†ü(8ËR¯“|ÞzVª®$õ9Ý·æWŽÆKÙÑfåí­Ì!5êf×ú{[Ÿ.sô6ýÀóeURg`ÐLï¿f•øš‚ý=ǵi¾}ͯ-ÅýÌA3=»W´²ùÐ+ÜŸÞïxçÛ¥¶Rsàž=ÿ´Hª]f«]¦p(Æ]ö´‰a2û1ЂaRôÔà†¡– sD˾–äÛ***$ÕÖÖf»#)S^^ží.$R¿E@jUWWKšR@jDæ)£Gëž{tà€н÷ª²2¸üâ‹uë­ÚµKµµš3çpåT¼å@:0:P¨2ŸFEíŽL ’G ¤ÞóÏëÿPy¹ÊËõèùçƒË¯ºJ'jÔ(­¯]—]ÖÊrÃæ\á…­3#H“l¥QQ;%“€$1©9‘W>#GjÅŠë†~û[ýö·É.ï<•,©Í³Ý‹N„©Í…*+iTxׯ@Ҩߟle1 t€Ù RrB§6/¤Ï2Ûz,Lm(9å`— ×H(«Wkøð¼i¶}˜iê—¿TÏžêÕK³gwtDg¶?B Ų^#Ý€ÜG  Wt¤HjÉ͘‘âþ¤¯Ùö]©>ñ„Þ}W6hÝ:UUiáÂTw €<”#ƒõ"1p’A  ,]ª34l˜6n”¤;d±(0a÷Æ6L’|>Íž­¾}UZª™3ÕÐpxóûîS¿~*+Ó¬Yr¹¢›•ôú몬”Ý®AƒôÄÁgã5hš7OÊ04tèáøÉ4uÌ1Z³æpèæñèç?WŸ>êÙS<ÐJ³‹ë®»Ô¿¿ÊË5w®-Š}*âKKŽ1j@æHÈ9m-’úòKUWëôÓ5uªªª$iÉ9Z²D’ÞzKÓ¦IÒÝwëõzµvï–á›o>ÜÂ;ïhÍmÛ¦]»tÛmÑÍJºøbÝq‡Ò;ï胂+$hpÕ*­^-ÓT·nzë­àÂ7ßTÏž:î¸Ã«Ýq‡Ö­ÓêÕÚºU;v´Òìúõ?>øxÜ8­_ûlÄ< R–GP$­"C£öÚjÙ2u–ŠŠRK—êúëõÚk’TU¥©S%iáBÍ›§£ŽR×®º÷^½üòáæÏW¿~êÛWóçëù磛•TZªšíÞ­õä“Á4ø»ßéˆ#$iÖ,=õTpáSOiÖ¬f=æ-X Ô³§æÍk¥Ùúzué|ܵ«Š}6bKbIÈ0)yoÉMŸ.I“'kÕ*56êý÷5{¶Þ{OZµJ“'KRMÆŽ•Í&«UG©/¿<ÜÂàÁÁC†h÷îèf%½ü²V¬Ð¸q8PùKpa‚û÷>¸è"-[¦}û´w¯þúW͜٬ç»viÈèÉ×l—.ª¯>>tH]»Fð+Á±Ä“{Ÿ(¬¼¨?Ê‹N@VHÈ-mÚÜãÑŠÁAy%%1B<¢qãÔ£‡ÆÓ‚:öXKRÿþÚ¾]^¯|>™¦üþÃlÛ|°u«Ž<2ºYI'¤W_ÕW_éñÇõ“Ÿ&h0¬gOsŽž}VÏ>«iÓÔ£G³gû÷×Ö­Ñ›Äkvôh}øaðñGiôèàcÓ ~Å; XŽ× ÈÙŽ@Ž â žD–ŸD-Ì‘¯–}ë<ÞyG#F¨oßà·S§êž{4eŠ$}¶î¹'8^OÒ¬+®ÐgŸÉëÕúõÍŠ•~úS}ù¥¾üR7Ü ‹.ŠÑì÷¿¯ ävËï—Ï×zƒ‘£ö.Œ¯'é’KtÝuÚ¹Sè†Ziöâ‹uë­ÚµKµµš3G—^{w-%1¦6yRrN›Š¤"ÖIš:Uû÷묳$iÊÕÕ¤n¹E“&鬳TZªü@çŸx«I“4fŒÖ‘GêŽ;b4{Þy:ÿ|••é–[ôÜs­7)ÐúzqFôS·ß®cÕØ±2äðP»xÍ^u•&NÔ¨Q=Z_ÿº.»,öîZ …'†ÂåQW “ JIÜQUU%iøðáÙîHö…nšÓúšÃ‡ë¥—t )î@ššÍYø¯¶¶6jy rª}“ÍGuuµ¤Éùê€lÈ‹K×§$ÇÚâ”´–³÷׋b†:å;ijÜ($¼i"Ì–í@\†Ñz&U]–]§©Y€² 7u ó 0µ9€Œ"£Ú4µ9@«^}õÕñãÇ<øé§ŸÞ·o_ïÞ½÷ìٹξ}ûúôé³oß¾O?ýtÚ´iÝ»ww8ãÆ{ñųÕm(HR‰")@¡[ºté5×\sï½÷ÖÕÕýío{ã7zõêuþùç?þøã‘«=þøãßþö·OMŸ>ý?ÿùÏ¡C‡{ì±W^y%[=€‚D  wQ$Reîܹ=öØYgåp8†þüóÏKºþúë}ôQÇXÇëõ>úè£×_½¤íÛ·ŸwÞyݺu³Ûí_ûÚ×þô§?e³÷Pp¤ÍP$Èq’ÌVïÅÛÜÇ|ÆgD-3fÌðáÃÿøÇ?¾ýÓŸþ4|øðÊÊJI?ùÉOÆwõÕW/Z´hÇŽ©è8à0)y€"©Ìhã…=Ùª¡NÍõÁõ×_?þüÀãyóæÝpà Ç<ðÀ믿>xðà×_ýøãŸ;wnJv°e»HMMMàSP›–O,KfµIr¦»'‰p o½õÖôéÓ£–ó›ß¼ñÆß{ï=I{öì™1cFø©O<ñÄO”´mÛ¶ÊÊÊ9sæd²ÃPبÆÔ怶š²²!%ë¤Ûœ9s®¾úê7ß|ÓívöÙg_|q`¹Õj½æškæÍ›7oÞ¼k¯½Öb þ‰4}úô·Þz«±±±¾¾þ7Þ§Ùû8kåÎ,’´xpÝ%Ûº§d5UÞµÿëÚóo¯µÄ(?ÝvÒœâÒ#[ùдæmïêû6ûºe9îZ‡Ï¥]+½_¸4jµ·¯mì?ÑvÔÙbB¤p–d)Òc­§üÿöî<>ªòÞãøw²Ìd!aMAJ€$âˆéQŒZ^. Ò-`APD˵­u¯  V)`# jZ½^,¶µb°±·lAÙã(‰*$!Éd›¹œa&N&a&³åóþëä™9ÏùÍ!¯!ùæ÷<ó@l×Á‘>yua È£¨ l’¢= ¼A‡šµéçU‰DÜXpë®ÎÃÄx¹Öç—Ø½²&5Çü£­‰7&tY0·ªåç/j(¼»*cqÌä=ÇåÅõï†7šn­?uÄÖøi§ŽØŽn­p£ÙË—0í`çi;ßúaâyã¢7ϯöÙË qAžF5$Ÿj$e@ð#@³¾ÞÙ~»ÅÒÕiÖ¹£¢Æ½¯ÓýDkú—9‹ì Úñ[k~FùÚ!å›çWÕW9zUÖô/Û½¢&ÿ¢òu©å…wW7xÊ‚®~%¾ïÕÑæDSt¼iè,Ë·{Z.i×s5wÇ$ŠˆVÂù£´hÐËÞ?|gö}yµƒ&["-ž_Bs¢bMƒo3WrÔpê Û?fU­Z¾vPÙÆé•Öo¯ËV¯­Y_QþjzùÞÕ5î7í£†?]V±ïÅZ5YÇçüÒ›;X!´L/{‘‚°$6RhV÷a‘;—Öœúâ;ÍGÆb=£¥Èù蹚¯?j¸þíNÙÛ"ͦíYO>º¥þ†¿%Üô~Bõ1ÛΧ¬j^}•}ßjÎíØS¢¹-™Žm¯OÎt_s7xŠùà[µµåŽÀ¨¶Â~ð­ÚÁ·™›{ ÍÖPmß¿¶¶û÷5¼7£*5ÇèèœÚ¹Ìzò@Ãõowºis©Òï¬;ü·º÷r*/{(vÈtsË×òþÎø_ã(*ÈÓ(ƒ¼;‰Åzà=ö@³2Ÿ‹Û¹´æ/7Ÿj°ªÏ¢2î‰ëíá/šŸä×^ù‡8cï§‹cþ<¡â’ûc‡.þUll“qðÎ+3î‰ñx!#~ŠénºöN-—T[n·tqÏ,]Mý²¢¬«6Û"éã×jû^méjòþ%8ó¯¨8Ó5ùŽ8æ‡ï8Љ”.\hycL…ñå§oÔ]ýJ|ü¹’.þ¥ëí^Y³/¯vÜšøîigÞ‚ÊË;ãgÎ(JAßåQ7“ x¡…@ ÍŠ;'bÔc±Rlõqû®ç¬›n¯šð'QåW¶·®=%IvÙmR£_Ì;õq¤? }#ª7Û¦4í`çºSö½yµ…‹ª¯ùc¼N÷a5eN4Õ”Ùcº¹ÿòŸškygRåЙ“Iû_ª¿6¾U/Á¸\ƒÕ^üjíÖ­×¼/éxQÃöG¬ßìip,B<}Íêã¶„¾R­âuµß»9Ú›4J^ß •5z»›+@™”3¢= ¼D €3‹íi±(æÕôrÆõЏöâ=~:Þ©#¶„ó#$U|n‹íÙÒ~ÑLi3Í»ž=Ãâµ^Q%ÿ¬p“û‚¸„¾=†G\_mê64Ò¸¨÷/Ác˜mÞþ¨£†‚9U#—Ä$2'˜ê*í¯ +?=UDÅç¶Äþî—¸&?þo“*£Li³,ƈ)R V{dŒIR͉ï¤$Þß?õÆ(C 2)Ò(hö@³ÞË­<úŸú†Õœ°ïz¾¦[ª£÷Çœh*ûÌÕÔ3h²ùƒ{ª+Ûì :Yܰy¾ë“ò¶ü¦ÚúÝú}ËýÕLtßûIÒû ªÊ>±ÙT}̾ãÉšžgØC*íg–í¿µ–¾_o«SÅa[á"×'â¥Í²ìYU»guÍЙ–3¾¬öâWj;î~j¨±GD+2Ætêˆíƒ{]úÞÍÑÿùUuÕW¶Úrû–û]ãqçD\“ÿI~í®ç;wKܽ²¶¾Ú^õ•íßK¾óá}g¼3~r;FµÀ ùmi´ RhÖ É–¢'k¾þ°2Âlê}q䨧ãŒñ¡3-®?U_e7Vº¥Í¶È¤¿O®¬:jë’ùýÛ]yPï‹£Ö_]Q_¥~YÑÃïð°MÒyWEoº½êä' 1]MIWD_ñL\Ë%õʈõhÜöG¬'?iˆOŠHÿ¹ëZ=†GšM¶{¯ WêÔÜKpcä_¦HuK¼ü)ÇsF?»õkÁܪø¤ˆ´Y–CêŒñôù1Û¶¾5á”Ý®ôy–ÆóÄõޏúµNïüø”­Aé?·Œz$¶pqõ‡O[ãzE¤ýÌrø¯uÞßÿéez5î“’Ô~­R3/Ò(h­€íù ©‚‚I))).Ð ÅÅÅ’233]H0ZÓ¿¬¹­ :8ßÞ™¶ýáçez5ì’,»ü½±”Ú'“¢1ªeþÿçF¨à?M8Ñ!t8á×ÕT;µJÑ>A t á±¹—ŒÀÈW±QøÚ ëõš¨;Ó£šr¶J©Q¨ä}2ÕttÒ(8{R@øëPQM9#¤¦ÉT8'iÕ¥Ha®c6FyÔ4™ÎH£<¢q ‹@ O|™ ˜HaˆÆ(@0#I.¡cÉÌÌ t Þ¢1 ü¤B 9T w>øc)£!@ d4N£RRRWHGT\\,©   h3)£!$"РuRRRH£üÏyÛƒ³IípÎ…ÎcÒ(@ð£C mÎ4Š( *¤BƒÑ˜Co[Ó¿ÌyL!R@Hr¦QççI’+!ƒ@ 1£¦ì”»ZÐ) ”8Ó¨i;¶ÚŒ@  nQ¬€³D  L$''º„3+)) t €PE'RBUH$PnšÖLD µ>¼hÑ¢­[·öîÝ{Á‚ÙÙÙÆ{Ë€~ñ‹_äææJºë®»V¯^}òäIñ>.X¦3RB’Ç4ª´´Ôÿ•´JRR’ÛHrr2¿+h•¹sçÞzë­/¿üòÆgÍš•]PP0iÒ¤7ÖÕÕuïÞ}ýúõW]uÕòå˳²²],|€Æ(@X"zœiTð'PnÜ 6ò)2)­²k×®×_Ýb±deeï=zôÿøÇªªªqãÆõïßùòåK—.]¶lÙ¢E‹Æè’Ñv4F€ºiTS¥¥¥M{¦ eiiio¾ùæ-·ÜåúAnáÂ…S§N­¯¯ÏÏÏ—”•••••µyóæ™3g8p pÅ¢íhŒ„7)!) Ò(h›gžyæÎ;ï¼çž{§L™²xñbIýúõ9r¤Ùl>ï¼ót:»ïҥ˜9s\.Ú„Æ(@Ø#€@2š¤XµÀ{\pÁ›o¾ÙtüÉ'Ÿtó–ºhŒt.€DèHè/ì—éYvÅÔ ³Ö ³Zvź@àHDc "&죚ªf t ðZá´Œ@ €Øe¬Ú tðÒ(gD AÁøŒö Ägu@{è€Qr €OÙ´$h“2]6À‰)°ÒÒÒ@—Ь¤¤¤@—a¥.ÓÀ#)ÀhŒÀ‰@ h_4Fà†@ hG4FЀ@jó†ÙìmÔ6Á¼_„£ht FG,~@c- <0™L.Á7JJJ]‚Wìë]A‡ašè ´›6÷œ¢©³ÿ”4 €–H>Ã2=¼A 4Ë­mÇh- Î^ž¦µ…J#LIIIrr²irÞØðc_'Ód%%%±jWv»½¹‡Œþßžu—4Qx‰@ |œ1O ›eéÁ†Æ(Z%"ÐèèŒ}:B¥¥+lð1…àC£H£ðRб«ö„+–ì¥ÖvÑ@ÛHì$-ì@›±d@àý§k£UŒàU{p6H£8tH­p8çÂ5"à¬Ð! (áÖæAUL;¡I ZëpÎ…Æû—p6¤„³‡”r§¿§=Ë$Ë?AÛu@k½;:þÝÑñÆ1Qg‰@ @°h&© ;tÝ…¾œ°]§5@rFQççŸWØbRÂÙÛ;uÝ…¸PûK%éóo1E¥'$i©.”¤›îÍW¯ÙŠËѧÊ×éýY½g+>G?Y©š:÷i%ýõC¥-–yªúÍ×ÊH§5ÓdW²vð¸&>¥„\ÅLׄßêX¹c¼ºVÓV(>GçÌÑã\Ïo|°â=õ›/óTX¢>?É­ÅÖæàÆQWV¶Âà{Å_jü£ŠÏQ|ŽÆ?ªâ/ãv»î~U]gªÛ,Ý›/»½ãaÏWMRÇÊUü¥.¬ ÃU°O’6ì%JŠ$éŸ{uípIzx½¶}¦éèó²Diñ«®6ï×Gêàr}yR¿|Ý}ZISŸ×¯oRÅ ÚüKmýL:òØ×¹®Bó¯Ñ±çuìy¥&káZÇø}Ò‰JZ®Õæýž_Â{»õ¯_éäjMÌÐŒU­8àÎ(J¤Qøà{ÙÏhÔ@•üNGžÕ%4éYÇøÊè_´÷qí~L{õBAÇØ±jÏWþ²SãÒ© é*Ø+IoïÔ¼«õç’T°OÒ%é…-»M}º)!FNÒë[\3,ŸªÞÕ+QËoÓºB÷i%Å™Uò­Ž–«ow­šá¹ŒÝ驊5+1VÜ¢¿ïrŒ¿öo-¢ž‰ê•¨¥·y>wE®útSœYw]§¢Ã­8±Uh’7F‘Fà[R€ïí/Õ½7¨KœºÆkÉDÇb1IkÞ׃·èÜ.Jꪇ~¤7·q^ÚP¤¬ %)sˆ¶|ªªZýûcÝûC}ð±ªjµåSe¦JRÉ ¥ß«¨Û9EçÌq-©“Ô¿§ãà‚^:Zî>­¤×ïÐ{{”±D}çé·y.ãÿ>ÑØß¨ÓOdš¬ø}]áÿªLýNÏ߯‡çs»wrÄ™UßЊ½Ä~UƒÉdòí„,Ó ½H¾Ñx•ÙµÃõÛ *«ÒÉ*=ögGޤ=GtÑŽãŒþÚs¤ãáÍW[›×5è½ÝŽEy±f JÒïþ®Œþê§Œþzæ IRL´$ÛE‡–«þe5¬•}lk]“<î8øì˜Îéì>­¤‘è­;u|…~Ÿ«Ùyž+¹e¹æŽ×‘ge[«²Õ®¥—½;ëÐéù}ÝŠ—Öæ èׯŸ.Ô8<òÕEíÞ-k/))3fŒÅb3fŒ7=¹4FÐ~¤ß{zšVÿS]fªëL­Ù¬g§;ÆOYÕ)Æqœ« kÇáÍû5(I½_NH×#oéªa’4~˜yËþìJÍ\­OŽª¾A{ŽèÇ¿sMrÇË:V®cåšÿ²&ö0í­Ïjo‰jëe³©Áæì§_º&©®•9J±Ñ:ôµf­vOºL Öêë /wm,å6Ÿè[›0lÚ´iìØ±á}Ñ»îºëòË//++3fÌ¢E‹Zx&Qí@ ðÆKŸ~ò{M««tb•& Ÿ=ŸIDATÖôŽñN1:u:Tª¨VBLÇÞOš¤6ìPÖp×—Òu¢RãÒ$éªa*«Ò„ÓÞsƒÆÖ¸‡—£)Ï鯑®³ÆÖ°Åê?_çtÖ¯oò0í3tãRÅÿD÷¼¦µsƒweé¢ÿvÕŸ÷S-zEruåCºbˆëÜnQç8õ§´Å5б)•7Ú|"´`Ó¦MW\q…¤¢¢¢#FDEE™L¦$%%UWWKª®®NJJ*..¾ÿþû{öìi2™Œ^'“É4oÞ<³Ù,iûöíéééÑÑÑéééEEEMGœ§΋ºÍ¹oß¾Q£F™ÍæAƒ6¾ŠÇ’Œ³Wîq’7ÞqÇ111 ,x÷Ýwq›ÛKff¦¤âââ@€·¤ßÛ´_K~¨.qê§%µéôç  í£mŸ9Ž·ÔÐ>m‡7ÞÞ©ë.t}9ðÙ×iD?IJï+û:}¯·ã¡“î½A‡–«ö%=¬›/vŒÛ×éîëtôyUæ)ï§Žõ}nÓNºLûŸPÝKÚõ˜Æs .™¨Š}ÊÞ}ò”ê^ÒgË4{œk<ά—g«*OGŸ×ċԧ›ëºnn_6wb›Ñ$@š•¦OŸ>mÚ´ÊÊJ»Ý>hР‹/¾xÕªU’V®\y饗¦¤¤<þøãO<ñ„Õju.”ËÈÈ0¢œœœ3fœÈÎÎÞ»wï!CÞxãK.¹$??ÿé§ŸÞ¿ÿœ9sxà“ÉTWWeœ[^^UÕ¹s纺º¦#&“ãçÏÆu›3::º¾¾ÞY¶Ífk|•¦%sºUÞt’=zìÙ³§wïÞGMKK;~ü¸š0îR ï{~ûçn-ãÛ‚_¾…" è|oÝ\½@Is•4Wïк¹ŽñŸþ—F§(u‘†Þ­+†(7³ãAI@«!‹4ðN%Æê77ûãDð¨ñ^N©©©«V­ª©©1¾5jTß¾}³²² pÉ%—HÊÎÎ.,,|÷ÝwŸxâ ã9FN$iðàÁkÖ¬©®®ÎËËKMMõ8b6›ªñEÝæ>|ø‹/¾hô:Ùl6·«4-ÉcåM'7nܲeˬVëÒ¥K¯¼òÊv¹•Ã/xBoVp¢C ð  R~Rrþ©?(oxXòØ$E‡à0èš6mÚ¥—^:{ölI;vìÈÉÉÙ½{·Íf3ž¼~ýú‰'nذ!++Ë9O=æÍ›wß}÷9;ž$mÙ²%77wÿþýC† ÉËËËÈÈh:²páÂ+VTWWO:ÕyQ·9?þøãÙ³gZ­V£æÆWñX’Ýnw«¼é$_|ñEvvö¶mÛFŽ™ŸŸß§‡Åð¡Û!@h!< dRþD ´YRýúõ{ûí·‡ê“:½‹žþèAÁ¾N¦ÉJJJjº“€°wèСrQ$ØC @ð2þ@mtîÂà;ŒezÐ~¤„š¤üƒíºø€ ÆvÚ~¤.F“«ö´+)ÁŽ­Í ÌH< I @û‰ t@ðòØ’Ì}:Á\ÛY*))INN6Mf×m°¯ çï%Á€@ |˜L¦³|€HØíö€\·  @RJJJ@®h’ò£IŠU{Ú €Ð`¬Ú t¼Œ€ lj¿"2Œ?þ³ß¶°4@û!€_H%4IùMRÚ ›šIdRºè´„ÏíàstH1ä#êè€_HÀ¯¤àWRð+)øüŠ@ ~E ¿"€_HÀ¯¤àWRð+)øüŠ@ ~E 233%º€³E ¿Š thš¤ËhUgƒ)€ApüàtH„è€_HÀ¯¤àWRð+)øüŠ@ ~E ¿"€_HÀ¯¤€ ’™™)©¸¸8Ð…ÐŽ¤àWQ.€4I@h1Z\à%:¤€à¯4rxëh­ÿg,@Uì+ÿIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/upgrade-apm.png0000644000175000017500000010057510014674771024213 0ustar frankiefrankie‰PNG  IHDR­P8£sBITÛáOà IDATxœìÝwX×úðwé ˆ ‚€ ö‚% 6ì"&D¯±ÄhŒM¼Š±{Mò‹1¹^cŒMlQc‰%(vlXQAED@A±P—Ýß#sÇÙ²;»ûý–iè÷XL °:H¬Ò«ƒ{@˜ô`€a°w#U>¤ ¡'õîݽ3‚{À`”J¥©C­`4t þ•¿L&3Z$PH@[ZþvH&X¤Vi耽7@›,¤Vi€ÕA`uX¤Vi€ÕA`uX¤ ™L&3òŽP¡dJ¥ÒÔ1€Ô1½ù½{÷ê´ûs¸Ƥ£ L&[³f~ûê½#T(;Sfƒýv_KL°fÍ™ ƒNÒ‚þˆ)ÏPkôèÑ„©AR‚IA ÈP7øbj€Ô`4ö9?¸Ò¤i€ÕÁ¤ «ƒ4Àê °:Ht`Ø[fLi€¨¤úe ñññõë×ç/8p iÓ¦ŽŽŽÁÁÁûöí+g¨B5jÄ‘uðàÁ-Z8::6hÐ`ãÆÌÊôôôþýû{xx899uèÐaïÞ½·Œ†=qÈ÷Àâ! Š}ûöõêÕKe9..näÈ‘ßÿýóçÏW­Zõé§Ÿž;wÎà‡>wîœ\.wpp8{ö,»2..î“O>Y²dÉ‹/8pìØ1fý€êׯ÷îݼ¼¼yóæýøã‡Þl £ÁS³ÀŠ(AkDôÓO?Õ¬YÓÞÞ¾E‹W¯^U¾ÙqäÿɬY²d‰···‹‹Ëðáà ÕÞºu똘•å>}úüòË/ì6ëÖ­‹ŠŠ/V.—OŸ>½ZµjÎÎ΃ zùò¥HðŒÏ>ûlþüùK—.=z4»ò½÷Þûõ×_ùqÚÛÛççç‹7TAAÁÈ‘#+W®\¹råQ£F°1|ûí·¶¶¶J¥2??èС...>>>Ë–-ã^l ¨ì"R;µ­!É‚ƒƒíííkÖ¬¹fͶ¥º3¨±:DäååõäÉf}qqqµjÕÄ›À´0 ›˜˜˜S§N={ö,**jäÈ‘TÖqdZ“ÿ'ãĉ×®]»ÿþ£GfϞͬäÎ<ÉÊÊJJJêØ±£ÊòéÓ§ß}÷]v³wß}÷ôéÓâÅ.Z´èâÅ‹ñññ™™™ŽŽŽÓ¦M žˆŠŠŠ¶mÛöÑG 2dÇŽEEEÌú3gÎôìÙ“ß!!!sæÌ¹ÿ¾H+Íœ93##ãÎ;III)))³fÍb_:þ|||¼\.'¢¯¾ú*777%%åÚµk'NœPÛ*»ˆÔNmkE2tèйsç¾xñâĉ.\àÏ?ƒ«£T* ôŸÿü‡YyôèÑ6mÚˆ´€é?ó0_D”Í,¿zõÊÎÎŽ]¯²™ÊŸwîÜa–ýýýù›­_¿þ_ÿúÙÖÖV.—³›ÉårîAÕ[³fÍ7n0Ë?öññ~ûöí]»ve–#""¶mÛ¦öЬ´´´O>ùÄ××·J•*ƒNOOçoãçç—””Ä,ß¾}ÛÏÏ!##ƒÝÌßßÿîÝ»Ìò;wØá¶€Ê."µSÛB‘~÷Ýw<à†Mo¦s:U'999  ¸¸X©TŽ=zëÖ­üf¤:êîkLØþtII ÛÿæêׯßúõëùË^^^™™™ìf™™™ìl¡bíììlmmmmmmllˆH&“‰Ù«W/vòÏo¿ýöî»ï2ËU«VÍÊÊRÛŒG?¾}ûöü—¸)76•T6c_å¶€Ê."µS{D¡HΟ?ß»wo//¯€€€]»v©K|¸¸¸øÞ½{ÇgvéÕ«×ñãÇ ³³³—,YòÖ[o©T‡ˆ 4qâÄ'Ož0± 4HíÑøÅ_dgg?yòdâĉüÖà©ÚÖŠdРA7oÞ,..V(¥¥¥*GQ9ƒZV'44´R¥JÓ¦Mûè£Ôn !¦„0O$0¯fÁ‚®®®BÑÒ¥K™‡Ø|üñÇÜçÌ0 &L˜7o™ñ×_1Ï´iԨў={¸GW[liié¢E‹˜'½õÖ[Û·o ¾yóæÇŽã®mÞ¼9³¼ÿþæÍ›;88Ô­[—8´oß¾Ž;:::V®\¹W¯^ìä~nùÜGëŒ9’_eÆ«W¯† âìììíí½xñb{{{~ ¨ì"R;µ­!Éï¿ÿÞ A;;»&Mš:tHåX*gPËê(•ʽ{÷Ö¬YS¡P(¤M¦Ä³Ò+3]dƒúõëoݺµE‹*Ëå,ּܾ};22299Yûà’Hküøãééé .4u H¢ódÙ*¨‡*‘Žo9?~îܹÅÅÅ£FªW¯Þ7ß|£_9Rh¼¼¼¶mÛÆÄÄøùù™6po˜Rƒ 5jT¯^½Ê•+Ï›7ÏÔáèO&“U­ZuüøñÈÀ,˜þ;T02ŒX¤`2[‚ƒM€•²3u`-¸þÁ *+Ù5`¸7ŒAû/þ‘Ò06¤&‡4LL›¬ù€a! ©@>`4H@ŠT(¤ uSäºBfù€¡ ³$ž ‡4̆ô€4,òí! „)Câ€%C> Ò° ˜2À…4¬~• €4¬ò°rHÀª! ²7{©«üiÁ̽¦ÚÄoîu€ŠcgêLI¥ßÃ]ϮᾄJA#¡^zcåÁ}Ú¹¸x6jÔxÄ¿ÎM’öSïêÚ•ˆÞ?vÌÆÁAí±jÏ»A›yóêôëÇ®tæÌ±Q£˜e¼LËÆÔHÂà„î?Hì?`*ÿJm fþ3jpÆ¥òvy~~Ö¥K±Ÿžv옩c1± =S©‡={VôìYê‘#â[Šœ;gçû{öp×ÜÛ±ÃÎÙÙÀ±€^üóo*?àÿ[‹|Àø˜wbß“'ƒz÷&¢›kך:"KvgëVfánÙŸÆ3‘ÿ2-ù³(77íèÑ€=*&dÐ &¨¡2YHep€Ûû7Ј¹xúÇÅÅ/[ö0&FQRR½]»iÓ*ùû3¼|øðÒ’%™çÎÉlm{ôh9}úöÖ­‰w}ö?wîòŠcbŠóò]»FDÏžMüí·¬K—%% 67®zÛ¶ìq_¦¥Å/]úøìY‡€ðð–S§ª Lõ(çÏ_\°àááöÎÎuúõ{kÂ’É´Œ“OÞë­·%%Y—.=ON®\»¶ög„U;*êþ_%ïÞÝìßÿ&¢û{÷*JJjGE© €I £ößWµÓ‡€~NO›–qü8³œóôÆÈ]»ÜÝ‹rs|ôQÁ“'ÌK÷þü³ðéSõ%LÊ–À8:r$»œ}åJìèÑ=¶lñ &¢¢gÏþ:4?3“ˆ¨ àÞŸäähçÙéÓÓŽ%"yaáÍŸvññ©?x0i§–jåÍ.¬Hi ¹¼õë¯éÇ÷øýwµ™€­£cÕ&Mž\¾œ“àÓªUq^^nR=KJ*yñÂÞÍíiB‚R¡ðjÒ„Ét"tú„Üݶˆê¼ÿ¾ÌÖ6nÖ¬;Û¶…LŸ.v¤Â§uëJ¾¾÷ÿú«Ùر$“ÝÛ¹³’ŸŸO«VºÆ“‚̃LSháø3…ØAjça¾hïyròÛü1ðÊ•·ÿݵFüÌÌ›ëÖÑÍuë ž8pàdt´M§~|çm‚ÔXë{;vQû•+ktëfïæfcgçÜ~åJ"zøÏ?B¬BeÝý¬‹‰¨ùøñD”ué»Þ;$DcCñ >µSHíCH1eÈŠÈd¤T* ™Íÿ¾gQ*¯_âñnÙ’]®JD¯ÒÓ‰èez:Uã¾ÊYæªöæ×ÃÊÒÒÛ7¦ìÛ÷"%E^ö nAv6³ÀË?¨FUêÕcœ<=‰H^PÀ-P›8µŒP#;gg† ÁÌï/íyJ ùwé"Rà™iÓì\\ºüô7rmšQ¤ÖywîÑ¡ø‡ËôH(’j-ZÈlm™î~æùóÎÕª½ûnüòå™.QÎõë2[[¯-Dê"Dèô©ÅÜ\ûý÷™?ë p{Ó¦»[·ÖîÓGíö*gD…[``µ-R&™¬ZË–®zÄi€)•§ß¯ëÆÜc!0ñÛˆù¨,#°Tö®®%/^åæ:U­Ê®,zú”ˆ\]u.ŽûÎØÄÎɉûçå+noܨ²¢¤DçC«bk+ú²æ8YzG¨ö]£¡4-¾"Q*¥EEE¹¹:)\k‘ÏV…\.ô’½««GƒOoÞ|žœü,))¨wo’É|ÃÂ8ð2--ÿñcÏÆí+UÒPu4œ>ŽÜÄDfVRÌÇs×g_½ú,)IeÚ–Ÿcµ£¢ÎÍ™C L 2*ñY:Ê7öÐj‹Å|!ƒ™)ÄݵîuêÑã3g¸+3NŸ&¢Êuêð·ÏŠg—Ÿ\¼HDÌ“‚\ýý‰è gªÌ-¦Í3=£ýŠýãâ߸ÑÿÜ9î«L±üƒêM8Å#Ô•xi•ƒ‚¨lž•–Ó¦)JJN~ñ÷Ž^mšQ¤ÖÌeðîž=ìÛŸûŸH0̼ [ë×+ ß°0"ò SÈ剛6‘ð¯1æåû烹9X­;Â/‰ |ç;'';''îœ+09¤Æ`’~¿‘|À8X*ÉqòÜRlÁj¾óÅ/[–+/,”¦;vyÅ "ªÙ³'û‹óçç\¿®Ës®]»0>13+˜y,æÏš ËŸ&$0¯jTZTDD¶ŽŽ¶ŽŽ/ÓÓÏÏË}µF·njª7=âPWâ¥Õzï=&¼ä]»Šóò%%ÙW¯ž7Ž»MáC[Nª,-=;}:3§_c±k]Ð "Šýì³û{öä?~¬,-U¿HI¹»}ûaÑGô0ýû{÷’LV½];"ªÞ®Éd÷þü“Ê’!ŽîîD”yá‚Þ™€™MTL ÷ó**&Ffc“²w¯øl"!ö®®\ºôÁ¥Kú e@Á¤  ¤¶c-y8l$lœÌ‚t"4G0ª²%c¡íÁ\Ô8ðÁÁƒÙW®;–»¾Z‹õäoïtˆ³ÞÅLJ¹Ï²ñˆÌÄôƒ|À¼ä×¹ó‹4Îîðmß>-&†íéúwîÌ}µÑ'Ÿ¤ìÛ÷"5•=¨_çÎì¯;éA8Å#Ô•xiõ?ü0ãĉÇqqq³f‰ÒpØ0¥RyyùòssçÊ |ô‘x±k]ûý÷ŸÞº•´yóÙ/¿Ô©:ÌmŠ’ ˜yeN^^UêÕ{–”DoÞÔÁçÓºuêáÃ1Ç3êñI’rà@ÉË—¾:¸T¯Î]ïR½zõví>ý`ÿþ:ÿú—®Å€4a4 ¢¨äFþÊ_'*±a¦Pùi32 ²1Æ,†½}øºuÍÆ«R¯ó]r•zõš×í矹óaµ_¶¬Nß¾•+Û9;×èÖ­ûÆîîDäèá±i“—.vÎÎîîuúö 1ƒˆ˜WE´ùúë€îÝ휜ÜÜjGE…-]Ê}Õ±J•î7ÖèÚ•-¶ý›èJ8Å#Ô•xi6vv]Ö¬i1y²Gƒ¶ŽŽvNN>­Zu^½š_N£?n1y2)•—–,Iøï54£µýòËn?ÿØ£‡‹­““{:õ è±e‹Hu==+תEDÕÛ·gWú¶oOD•k×vôôÙ7dÆŒ€ˆww½ŸÈùúçúöå¿T§_?*Ǽ ™4;¦fÛ6Çæå'0¦ŠÄbp;ôÚ|?§6Àå,R+y×®¸Y³¼[µê®õ#öMÂ\â4,ë¬5˜5Œ÷!„4 œ¬- (O_ß,ZImM¹a‡ÔkðÂ@âèÏ g‰§–ÔÌ*( äV i€þ¬m(À:©ä&?Ý— ~’ Àš ÐÒ«"©ÁŸ Mù€@ 'Iu Á8¤vÒ+: ä– i€ž0`¬0àÈ8G€ …4@OH¬–Ô22b2@È,Ò€×ô{&ZÏ:I3 4f2@ÈÌœU§æû‹W`rÈÔÔøGýؘ:c“q¨¼¤Ô‘IâI)g&ipƒØþ÷–à`µô :¨J¿Ÿ9ºq-±§Ã„çŪ. ]+[qcvÍn€8ðgÇŽ*˜¼M€cB]ŒÀ\ªii€P×ÝzÐ{ÁH- ^2`äãšQ>Ÿ™yê‹/v´mûG‹G† IeÖ0ÚGgÎ5jkË–;ÂÂÎL›Vøô©øöúZšÍ  ‘RS—W®ì´jó9&¨ÌšËø4¶¹Æ ,3 ½‰ûúý`(¿„Œ?,À=´Yä§'Mr ê}ðàçÎ57.é÷ß ~ˆÛë×7:´ßéÓ½öí³ws;=y²Á`¾$8{0?3Ó«ysfY‚áp•ÿµ´4@ãl“D`&™#Ä@²ù@ÎõëMFv¬RÅÆÁÁ§M›®kÖPÙw'Ü•¥¥W¾ývgÇŽ[CBNO™"/(`Öo ¾¹nÝŸ;n ‰›5KQ\Ì?D×µký:v´svvòôl1yò“Ë—µŒmKpð­[÷DDüѼùßÿú׳¤$f}ÆÉ“ûûôù£yó=w·oWðË´´ãÆmkÕê-Ž-2!RµÛ7îÿ½Y3~`Ü—ôn¡ ryü²e;;tØÑ¶íí Äãä·?Zµ …WZXxöË/·…„üÙ©Ó­_~ánÏ­µ`ðÅÅq3g²»klg¡íUbVªN Èʹqcw·n‰¿ý&R‚P#èwööìùüþ}"zõèÑ–&M ²²ˆèùýû{{ö$ÎÕK¼Ï(µ×¿J˨ÝFmœâapË$¥rK“&ÜÀ¸ô¾…Z[¨Z^ÜËRäj×òÃD…P jë¢Ó‘N—´Ú8…N„Úà7ˆÞþ\jë¨ö½,tÒÕVŠRø²4€ÿÅ?ºþ SÍâÇ µ|À38øÚêÕ/ÓÒ¸+™ ¹Ñ&¬]û4!¡çŽ}Oœ°up¸²r%»qÖÅ‹‘»w¿wäHÁ“'×~øAüpÏœ©Vö-£6µÎŒ‹‹øí·;~˜•ggÌh:vì.t߸1çÆ µ;¶ÁGõ;y²ßÉ“îuêÄ/]*t‘ªå\¿ÞsÇŽA×®ñ÷⾤wãy}õê¼;wzîØñÞáï=“ßÚSÞµU«Šóòú9¹{wÖÅ‹Bµ þêªU…¹¹}މܵëñ¹sÛYh{mBÕ©ÿù'ö³ÏZÍ™Ó`È‘„A¿³àÛ±cæùóD”këà~ü8ež;çש» ÿ&ë_…ÚmÔÆ©MB‘pé})м+ÕÖBËkCä}ª±¡4Æ,ƒÚºèôA¤Ó%­6N‘OmHáíÏ¥¶ŽBïe¡“ίÿ¤¨9®÷ÅJ ¿)MXóºð67nÌþgêXÞÆTQ½zü8nÖ¬?;wÞÞ¦Íé)Sò33ÙØ¸›íîÞýÙ;ÌrAvöÎŽÙÍž?xÀ,?¿W×®"ÇʹqcÏÛo³Û U–]¿¹qãÂÜ\f¹¤ `KÓ¦¯ƒ ¿½qãËŒ µ{ñ•ìèÐ_¸Æªåge EÈ}IׯQ*7È]]»>¿_e¡£¨m •hÕþ)Þ®®]_¤¦¾^ÿàw{¡Q žS¬ÆvÚ^%f—™ÆÜܸñÍuëvuíš“ M-Ô6‚~g!ýĉS“&)•ÊccÆ\^¹2ö³Ï”Jåɉ3NžTª»&Ù?Õ^ÿÚl£6Nñ0TŠå/—³T¨¼+ÕÖBËkƒ{YŠ\íÚ˜piƒÚO›étI«SèDpIüíÿFuÔÕQ转ö¤kù‘Ë?ÆœI²T¾û7a$`µ”J¥o½émKp°i§½ª `–˜‹O›ùó‰¨0;;aíÚS'Füö³üÌÌ}û)•J…‚8gÜÕßÿõB@@Av¶Ð2ÏŸ›9³ãwß¹2k´®ò O IDAT©£c•*Ì‚““²´”YîðÝw7~úéÆš5¶ŽŽ¡_~Y#<œ¿cöÕ«WV®|zóæëÑgáKT¤jÎÕª íÅ}IïÆ ² ;Û5 @Ë8µi !jÃ+Èήäç§²¿ÖbÁsŠÕ¿ÐöÚ„ªSÑ­[kEEy6n¬M-Ô6‚~gÁ§U«‹ È ³¯\ [¶ì¯·ß–æ\¿ÞnÑ"¡ú2Ô^ÿÚl£6N½ÃP¡÷¥(ò®T[ -¯ ‘÷)—~&B1hù #²™N—´Ú8E>y´!…·?—Ú: ½—…Nº6ÿñd®i€ÉÄýñÇÑÑÑYYYJ¥’»l긬Îà„î´W“ßÇÏØ£ÅæäåÕ|„mÛª}Õ¹Zµ[¶¸øøð_z™žÎôì_>|èìå¥v÷ÿ}yùòN?üÀíé­j“&W¯&¢Œ“'ãfÍRÛñ=õÅ-¦LñíÐÁÁÕµäÕ«ímÚ•&R5-éÝ8BA:{y½|øÐ-(H›£hl ™­mia¡­“={¦1<§ªU_ed0ÿô¾LOªµXðœb5Æ/´½ µ¡êÔ€DÔ}ãÆ˜?vpumôÉ'â%5‚~gÁÖÉÉ-(èΖ-žÁÁnnžÁÁI›7»×®mëè(TßrR§¡ÂÐûRÔþ]ùú@Ú]\"W»ZcŠA˺ˆl¦Ó%­6Nm>»$þöçR_G÷²mþ=âÈüî àÞ`H#—lÃéWÈÔ©SwíÚÅœ2î²}›n1¤p·ÿþоy öóϳ.\(-**ÊͽùóÏ 2ëÜܘ» õ 87{ö‹ÔTeiiÞÝ»§§La_º´dIáÓ§…OŸ^\¼8¨W/þ!noØpeåÊn?ÿ¬’è]©ÓS¦äÝ»§()!…B©P¨ ¸´¨ÈÆÞÞÎÑñezúù¹sEJ©š–ôn¡ kEE]\¸0?3³øÅ‹K‹‹Emkpy4lxkýzyaa~fæ…¯¿æ¾¤6¼š={^Z²¤(7·èéS‘{*„‚êÕëÒ’%EeÅjl%¡íU¨ U§$"Ÿî6ÜûóÏ„µkÅKj½Ï‚_ÇŽ k×Vo׎ˆ|ÃÂÖ®õëØQe•k¸<„âÔ& ½ רÚ¿+Z^\"W»ZcŠA¨.ÚétI«S›Ï.‰¿ý¹ÔÖQè½,Dm¥TN ÿ@f6`I €I˜°ÝÒÒÒÚµkÇ_¶€Si¦UÚ°Ëhãõ ¸¶jUöõë¶Þ!!íW¬`Ö7>üàÈóó™Ã59’d²£#Fde¹×­}äùùï¼ÓtìXþ!â—-#¢}½{³k>¸pÁÎÅEï˜ktíz2:úEjª{íÚaeÿP©ÜváÂKK–œš8±’¯o£áÃüý·Pi"UÓ’Þ#dÓÏ?¿¼bÅ÷ß'¥²ÉgŸ‰Emkpµùú븯¾ºþÓOÎÕª592õðañðš~îÜÝݻۻ¸46ìÑ©Sjk-üرæÍÛaïâÒhøpvw¡ø…¶W¡6TáìíÝý×_ÿ>\YZÚdÌ¡„Aï³à×±ã¥Å‹™þwõ°°Ë+Vøòúß*×pyÅ©Mz®±´W2´¼6¸D®vµ4Æ,ƒP]´ÿ Òé’V§6Ÿ]ûk<"ïeµÔVJ夨9ÿNÉb«jê@ ‰­ýôÓO5kÖ´··oÑ¢ÅÕ«W™õÅÅÅ'NôòòªR¥ÊÊ•+™•#Gެ\¹råÊ•GUPPÀ²hÑ"Ÿ]»v-Z´ÈÓÓÓÇÇçСCZ.??èС...>>>Ë–-ã·6÷šc×|ûí·¶¶¶J¥299¹OŸ>®®®ŽŽŽï¼óNff¦R¸—Ì ImM¥Ï®IéÜ7,Ää7«%‘0¤Iâ£MxyÉÉ{zô0B0âLÛ’i2£·¿öôþ 0›IAÖ0sêÔ©gÏžEEE9’Y9wîÜ7nÄÇÇ'''§¦¦2+gΜ™‘‘qçΤ¤¤”””Y³f±…dff>|øpáÂ…C† ÉÌÌLMM]¸pá¤I“´<ÜW_}•›››’’ríÚµ'Nð÷R¾™K0Ο?/—ˉ¨wïÞ̼ÿ¬¬¬ÆOœ8Qe/µ%ÕŒÀ´¿-  ãÏ«uqѢ⼼ÂììËË—×èÖÍÔᘬ“^ù2séU3i€¹D«=™ìõ)ÉdÙÙÙU«V%¢üü|ww÷’’" ˆ‰‰©_¿>w/ÿØØØzõêQbbb·nÝÒÓÓ™Brrr<==‹ŠŠœœœØåJ•*1}t‡«Q£ÆñãÇëÔ©CDwïÞ­W¯¿ÍÙBØ?322|}}ùµËÏÏ ÊÊÊRÙKí²ÚšJŸ%]™Æ¿7WoüÀø1›üiKR&ñÆ /é÷ßoüø£¼°°F×®­çÎ-Ï .ƒ0IKJ­ ÈŒÞþÚÓûƒÂ<ÒKêi©àöËUúÖÌŸvvv………vvoÜÅaggWTTdkkKDr¹ÜÙÙ™éÄkìjks8nÉöööÚ¤Ü?ãââ¦NÿêÕ+æU…B¡Mljk*}vqr»×RîÆ±¤˜#3˜dåO’ñõõMNNVYéããs¿ìÖïäädŸr<ï_rJJ ³Ì.è¤ÿþcÇŽMKKS(yyyÚ÷ÕÖŒLšùBú1ƒ4€a1ß¶êjذaãÆKKK{öìYtt4³rРA'N|òäIVVVttô Aƒ u¸~ñÅÙÙÙOžÌn°téRŸJ•*}òÉ'EEEÚÄÀ¯ÝþóŸ   ‡–-[^»vMd_~Spݾ}{ÆŒUªTñðð˜9sæíÛ·™õ6lX°`¯¯¯ŸŸßÂ… ýõWí¾\”eŒp,sg¦?6¬+Œ€…1³4€Ì0`æö)gΜ™‘‘qçΤ¤¤”””Y³fñ÷Z´hÑÅ‹ããã333§M›FDK—.ŽŽ–Ëå%%%“'OþöÛo‰¨wïÞÑÑÑYYYYYY7ž8q"[HffæÃ‡.\8dÈÌÌÌÔÔÔ… Nš4‰Ýàĉ×®]»ÿþ£GfÏž­M |111§NzöìYTTû=½Ú}ùMÁ=‰‘‘‘Ë–-ËËË{öìÙÒ¥K{öìɬOHH e–CBBÊñ¬RkzÂ:Yö!*ÉYG­Àò˜Ód.óš¤2Æßß?66¶^½zD”˜˜Ø­[·ôôt•]‚‚‚öïßLD™™™Í›7üø1 2$44T¡P<~üxÙ²e*{åçç12™,''ÇÓÓ³¨¨ÈÉɉ]®T©’\.g6¸sçNݺu‰())©[·niiiÜh…bP©ZvvvÕªU™£»»»—””ˆì«ÒÜ?ÓÓÓÃÂÂRSS‰¨V­Z§OŸöõõ%"[[Û’’"R(LüºžvÙ,®3e%„¸0YÌ”¹¦dV;•¾¯]QQ‘­­-Éårggg¦ëÌeooÏ~w®P(d2™B¡ ¢;vÌ™3çÕ«Wlذ!ÅÅÅM:5>>žxÃlÉ=¨Úe™L&—Ëùa°Å R5ûŠÜðöÛo·iÓ†ÍX¹råùóç:DDîîî>¬\¹2ååååææêv8á±Ë¿f¤Œ™¦VÆØ±Ì‚ßêÕÆˆF2ØŠ³¬­@:ºtébêÀ ˜qÀ0‹Ž4àøñãü¯á¹Ïœ9S£F •õ:t>|xAAA||ü/¿üBD+V¬xûí·ÝÝÝ_¼xáîîÎöò5¦ÜÑ€ððð‡r7ŠA¤j÷Iœœœòòò‰¨°°°J•*Ì]aaa ,èÖ­=ztöìÙ§N I#óJ’ñÞ?—Õf ä H@œ©(/¶GKîÞU©R%11±AƒÌŸƒ š8qâºuë”Jettô Aƒø»Œ3fÔ¨Q«V­ JLL\¸pá–-[bbbrrr>þøc" ½~ýzÓ¦M œSRRf̘¡S`&L`r‰èèè?üP›H»G í«ÒÜ¢‚ƒƒ/^ýî»ï7nÌ®¹råÊ¡C‡RSS‰hÉ’%?>uêÔÉ“'>|¸téRf›eË–åääœ;wîÈ‘#§OŸÖx”•+W&&&:t(..ŽùÖŸý?@è DtòäÉÝ»wß¾}ûwÞ™}ÚÝݽQ£Fwä @o¸EX î¶r¸†ºEXMɸiXGfz31ûÕ»‹‹Khhèüùóë֭ˬ¿|ù²··7ójË–-wîÜY«V-"ºwï^ÿþýããã‰($$dçÎAAAD”œœÜ±cG¦7¯r¯0ûghhè¶mÛj×®­ƒÚ…êïïãÆ "*((hذáƒTêõøñãåË—=z´°°0<<ü«¯¾òññ!¢6mÚlܸ‘ù¹ô'OžDDD\¹rE¥¾ëׯ¿xñâêÕ«‰èóÏ?oӦͰaôÙ@{¸EÄÙ™:°^]Žaúµ±fÑ59þ@й¤RBsñ¹]ÛììlvÒKÍš5srr˜å'Ož0ËÚÌŠÉÊÊÒ~òŒÐA‰ˆÉˆÈÙÙY.—ó÷­^½úÊ•+™#þðãGÞ½{7=~ü8""‚ˆ”J¥B¡àN/dëÛ·oߥK—>{öL©T;vlÉ’%Zî`(HÄ0?†çëTdúÊ̺ ½¼¼>|È|럚šêååŬ÷ööæ®g··³³+,,trr"¢ÜÜ\v½··wjjªÊh€®Õ‰··÷ôéÓ5jÄþù×_ùúúŠìâîîÞ¥K—;v(•ÊðððÊ•+k¹#€¡àÞ1È· ”‡%Ý<5wîÜœœœìììÙ³gGEE1ëßÿýÙ³g³ëÙí7nüÓO?<~üxÚ´iìúþýûÏš5ëÑ£GÏŸ?g·¯\¹ò½{÷´?¨6†zöìÙ¢¢¢§OŸþðÃMš4aÖôÑGS¦LIII‘Ë剉‰BOF8pàï¿ÿþÇ 8P§ i€<,È8 ”“eÜL4ö­MùûÊÆ"Ðþ$"0y@ÈLù€¹Câ” F¨&JUhJÀ/\c±˜ &…4€ ˜n0SH@Ò°ÚÁ#dA÷ã:l噀DÒB&`R0;H@Òƒ‘à¯ÇøÃ Ìô Øš3餄L@˜ ¤ i€iì­šuƒ[í¸Ãj3I¥„L@2HÒ‡4 bY@V`U£â¬6 ’Z@œ øùù¼L ¶%8XeÍà„“D¢QFF†©C0*¤ i€Qé4³ÅT§F$H\-Ö™ H0   ÈÐû/'sÉ €õ@â˜RÅÝÿjX¸H¸¬0f@͸9º‰å$ÙÉBìYÆ)+4Ä! (Óf¸*DèñÈQs'Ù4€ — 0Dô KšOŹë4ÄÙ˜:POiR¦®½¤ñÛÇ\Fu,Û³ä &×åÈn×?6"‚ùÏ„! £ú°ª1)0Ê9&€¯‡C"“…pºÁz`4Äa4@Œ ˜fp€?>`¬ÒƒA&`BÈÌ& HÒ=©„LÀ„ ˜¡Áœ>ã@ ?dRƒLÀa²€I 0&&†ûê¦M›>ú裫W¯>|øP¨„3gÎ>|xõêÕ·oß>|øƒŽ?þã?^½zu„ Ü-7mÚtç΄„„¡C‡þßÿýß¼yó„7lØ0"Ú¶mûê®]»ˆ¨_¿~ÚÔË|a²€AÈDú. +‘Þ¼6O•æû166–ˆêׯoê@ôÄvù·3küüüˆ(##CeGæ{ý4oÞœˆ®^½Ùºuk¦·Í¼Ó°aC•]ØyAÌŸgΜ©Y³faaa:uˆèôéÓAAA …"00ÐÆÆ&55UmØ …" ÀËËëêÕ«jWXXòâÅ‹ .øøø<þ¼yóær¹üÂ… Õ«W/O‹™~ ~gˆÐé°ä £æ ý~0&Ÿ1ÇÛÍ‘ÆÁ~ž`"_·Ë*ò?"€rÀh€㎠`@À² plL€KåsÅs„ðI`HÌ2«ÂÌ¨Š É¸ð`)0)Àìq»þ¸]ÀJ¨Ìâ2ðì °PH,€ ™h„4ÀB°™€ €&¸7Àr°÷ à&0É>,ÈJ~ÚLcG™ˆÀh€E1|ï?‰¨Q%¢JD=ˆ’Ø#M%ò ò$š»AZ$›ŸHF, 3&`°D}ˆ¶)‰¾!HODDÿ%:Et“HIÔhÑH­Ê›3gÎÿû_f8sçÎ5uæGÊ?…æçç§q©]„zêß_ã&sˆ¾þúk#Äf£ˆI s“Àm¢DUˆ<ˆfÝ.[¿h‘/‘ÑB¢_ p(0¤–©\CÜô!’hQÑ3¢¥D=ËÖ'…–-‡%è40>L °X†™ô=QÑl""ªEtºlýK"ײe7¢8 Òàᦟ #šHDD+‰>&:DDD®D/‰*Ñ "7mËþúë¯Íý).zß~ªÍœuૈû>ýôSƒ—)M¸[„`Rˆ:N4“¨ Q¢™DÇËÖ],[¾DlšèÀøùù!ƒ2oúݦ„Ç‘T0¤ÀÃý7;˜h1Ñ3¢gDKˆš”­J4‹èQÑL¢¥©)ñŸ±þs§ßIdGvƒ(–hac¤ViK°ßÜ>8pàÏŽuÚ,Êf¢“D~D~D'‰6—­MÔž¨1Q0Qg¢¦Œ ìo¢&DDADì³UK‰fy¹ &zU¶^FôQ ‘Œ¨.§Ó¯$ªCtóÍB Ñ$¢jDDßh*#¨`6D”Ÿ™yê‹/v´mûG‹G† Ie^3`ÏoKp0óŸöÛk\£Ÿ}½zíŒTÛ¶V­Ž}úé‹”výÝ;¸[fœ<©6 Ëî"_^¹²ÓªUƒ*êA0Üö?:bDÞ½{t îU@÷«»†D1DùDùD1D ÊÖˈ–åå-ÑwÐß<½¾·ÁšªlbJ"ÜYadC‰æ½ :At¡lå"¢‹DñD™DŽDÓ8ÛŸ'Š'RU&:V¶ò(‘Q3Îfs‰nÅ%¥j*#¨`6DtzÒ$·  Þ~pî\³qã’~ÿÝà‡œPqýHíå\»¦,-µ±·Ï¾r…»ž ¯ÏáÞÁÁ§§Ne×ßÛ¾]YZÊþyk5Iægfz5o^¡‡`Úÿý£G½[µ:ÃiÿŠ;\EÂÈtʱ4s!J'Ê$ $Z[¶rÑwD5ˆÜˆ–q¿([IäEDDŸý\¶òg¢OÞ,v#Ñ*¢"¢ï4‹Ç‘T0"ʹ~½ÉèÑŽUªØ88ø´iÓuÍ*û¢”Û½P––^ùöÛ;n 9=eм €Y¿%8øæºuvì¸-$$nÖ,Eqq…Fœqòäþ>}þhÞ|ODÄÝíÛÅcS‘¼gO­>}j½÷^òž=üW=<šŒó,1‘]ãúàï¿™å´cÇÜëÖåïÅo¨Ò¢¢ssæloÓf{›6ççÌ)-*Ú‹ÿ§Pc–žýòËm!!vêtë—_¸ÛßÞ¸qwxøïÍšÑË´´ãÆmkÕê-Ž]øô)³™¢¸8næLvwö¸ÛmKp0)•[š4a«É=œPM·'¬]»£]»?;uJ‹‰IX»vGXØŸ:=:s†ß,{7·ÆŸ|ÂŒèz± E¢öjaë¢å‰ck½%8xg‡E¹¹¯[U.ßÙ±£HŒ €©`@À$0 `<;ˆbˆBˆ‰v—­L'jNdGdKT(‹³½oÙ‡Dˆžå$üf±ˆjóŽ%T,ó82†.#-Ù‘gpðµÕ«_¦¥q_`¾1å~‹Ÿ°víÓ„„ž;vô=qÂÖÁáÊÊ•ìÆY/FîÞýÞ‘#Ož\ûáí¯GæìŒMÇŽýàÂ…î7æÜ¸¡16–¢¸8õàÁZï½W«wóÓ•¢ÜÜkÖTiÀNz zƒÝ\·Ž”JR*oüøcƒ>âËo¨«ÿ÷YY½ÿþ»÷/32®}ÿ½NTÛ˜×V­*ÎËësäHäîÝY/r·Ï¹~½çŽƒ®]#¢ãcÇ6øè£~'Oö;yÒ½Nø¥K_‡´jUannŸ#G"wíz|Ævã׎{8‘šæäD=Ú<:úÌ´i…99Q11Í££//[&Rñ’/nþò‹GÆâ©m¡HÔ^-BU©SëÁ 5##ïlÝÊ¬ÌøûïéÓ<=ªV ýòË”tª ÚÆdÊtôôtòôl9}:wû–S§:zx0ËïîÙãÓºµ­““½«k³ñãÙoßìßÿz÷ªUCgÌ`÷Õ¦ÝTp'RÓ¦Ÿ}fçì\«woyA»œ—Ìÿø'*kÿímÛÞÙºµÃʕ≴?µW‹‘ê°µn8tèÝíÛr9=üçŸZï½§±Å ½ÉÁ€X¤AD7‰Š‰DìÜØ1D£ˆîɉxßô³˜yAëx3‚ˆhÑ8¢4¢gDÑšŠÅãÈ*˜¹øø´™?Ÿˆ ³³Ö®=5qbÄo¿ñ7ÍÏÌ<з/‘R©T(Hö¿ý\Ë~Ä5   ;[ûà ÎÒ–É” …ÌæõƒŒ”¥¥ìr‡ï¾»ñÓO7Ö¬±ut ýòËááâ±±îïÞ]+*ŠY®Ý§Oòž=o¿­! ¢ú~xõ»ïryK­ç¬æä¸Ö¨Á,»æäh¹#CmcdgW* w}ó·`œ«Uc—³¯^½²råÓ›7_Ï¢)k‡‚ìln±ìöÚ´› îáDjêàîND6Üeî\ƒH©|ñðá¹Y³žÝ¹SÉß_׋M(µW‹‘ê°µv­QÃë­·Rÿþ»æ»ïf]¸òfJVqÐõ— ôôtü0“Q)‰däççW¿&ªúõ%ºGÔˆíL'’u'Ê &š)°oQ‘-Q7ÞKsˆ¦5'R–ý6¹H±£‰î5.[ÆãÈ í_vòòj>aÂŽ¶mÕnê\­Z-[\||ø/½LOw $¢—:{y•?,oï—©©nAAÌŸ/RSÙ~XÕ&M:¯^MD'OÆÍšÅtìDbc>}šqêTúñãq_~ɬ‘ÙÚæä8U­*‰oXØÅE‹líí«·k§eðNU«jl™­mia¡­“={Æ}Ií¾NU«¾ÊÈ`zð/…õÔ_´˜2Å·CW×’W¯¶·iìwöòâËn¯±ÝÊ_SmÉdní–.=o™šŽëäá±;"â@Ÿ>ÕˆH‹v§MMuU÷ƒînß®ëÅ&‰Ú«…¥Ç‰cw,ÈÊâ¶°Ñ »oQâ‰ê›O±ú%J¢©DDžD3Ê}§/n0™RYÞÕ-ÁÁ蚊6ùüþýØ1cÞ;tÈ8!IŠD.¶;¿ÿžŸ•Õ<:Zó¦@m"­±YdÌýìÛéÒ§SÅ=–Œˆý]2˜o—õžqþú=sÑ3Îo©êD&|Äòkpkˆ6í$Rõ#A4²|ʈ4,æ„ ]få<ÝfGÿëÓHòǘ’’’ˆ¨K—.¦$ÊÆÔ€¶..ZTœ—W˜}yùòÝø7^‘”¼x‘¸ysýAƒLrt6Ð3’•ý§òg…þÇ=pí'êETè6¥Ù1½ÓÛDõˆˆ¨”h‘7‘ Ñ`¢WœÝ—ùU"ú„¨ˆW,ýMÔ„È(ˆè¿e¯ (#úŽ(HFT—ÓkTÕ!ºÆ9}%D“ˆªyp’ ¡b7- ò%ò#ZHô«ºv¸OEäFäDÔóͧÑóá… i€Ù¨\«Ö¾^½þêÙÓÞÕÕ Óo@[‚ƒw´oß`Ègoo“Y`ôÀø1€ ]“œ,¢$¢ŽD=‰b‰ˆh‘#óÜcDÌÍ)‹ˆ.Åe9Mã”p‚èÑ}¢Gœ‡®°ÅÑP¢¹D/ˆN](Û@¤ÀóDñDJ¢ÊDì•y5ãl6—èQçLC ŠáÝ~ T¬-QIÙ7N ""¹h³äi(˸„N&qaR&aRQ§)H‡øD Œ ˜«}eSwº%Ê':K´™¨Q>Ñy¢ DD”NÔœˆÊ~]•;æP«l¡6Q&¯X"ÚA4Ÿþ¿½;ª:Ü8þŽd! ;A ,1A6¡EÙ«€bhUZÄ­@ذ€X6ñ‡P[•Š«°âRQiA@´E‚!,¢˜ ‹@–ùýq“É83ÙgÉÌý~Ÿ›“{Ï9s“'œ÷ž{îÕ_¤0i±tgY6-Ú¸_z\:-Y¥Ò‹¿ìù1éj§SRµµ¤óRIR–T»¨Ü¶ƒUú¯4MÚ]t+Q™ó*Vn07ঠøÓ¾:×þƒ3ܯÎ*üäÐ\éã¢Û~¤6Ò RœTOŠ“ž—ÚJ5%IM¥#Rž”_4¶±=íö°ÔÄ©ZI×K륓ÒRi\Qa)ÚÔ—n•VK«¥Û¥z¿ünSÉù…à%UÛ^ÚY´½«hº@’µè?IC¤ ÒRt֬׭À눨îlã`³%Rn‚ßÛ*µ‘l LJOKÆsqHOK‹¾õ4F:(åI)Ò}v•L.ºŸ~’t¿«jï•öI—¥)¿Ú)½,-—F:}k¸ôGéGéŒd{\VIÕ“—ŽIÒ,i„«¶²¥)L:"-¡?X( UF @ug¼îÍØ6É´€Ã$À/TlB`ƒo÷å@)Sê'Iê/µ‹3¤ÞR?)\z@lwTo©£ÔJj"ÍqUíÒ`)Bš!­)G…öŒnœ—œKö„ÔVê$]mwcRIÕ>(õÚIí¥>Ò(Wm­¦Jµ¤[¤>%ôàn,†? ø äÕó²D¸œ*°3VZ'ýªŠ z«Új«„w°DØAáo¦LvÕé׋%Â( K„áOîKIq¸G¨úŒ•«Èa–#`>—•òb/›4Ï4í¡j0¼ùÞ@²›”kÖ¬™É“P büŒ1>¤0@éééÅ—]jÃÿrpøå]y tÄø¥À J¬’EQQQ¦ºÃ§ÒlcâÂ<`ÿÌVÇè¨bü˜ÿ†@ *œ(Ï}A€Ôä¨büžË0 j9¶fô¸•å÷a€T1Âþ¡¢>m;?äÔç]‚ç0!?â: ¨ÿö:=“—T1¦”< /Ž¿]¾ß€Ñ?à!LT…ã²UËÉ.ÿîF @ÀrÎòäm9¥¼×ŒÑ¿I1!àÖr¿µ e©Ž“\þ<†€Àg? w¬{îÄ ýÍŒ'‡Â¯•89`ãÑTPB¨cô¸1æâ0:wc `Üø …=ÃqrÀÆ»Ó/ÀCˆ05Æîð #`8ŒÂ½0ÓŸðb @0!àŒÑ€q…¯;©p´ÄêUï`Ö*ˆ˜1<Œ ï°JRTT”¯ûþžÂ]Ô€j‹˜1<ˆ…Â^ÅBa(7b`:Äð,&¼Š (^ÞBTÌ Ïh€21ǨPÝ0˜10n ²lÙ2_wÁgÆŽëë.@à @udæá~IJ9'$¨(bT/e€|Ð;=©n–.]ZÒ·Œ“F€ò³X­¼j@i’““%ÅÆÆúº#%)##Ã×ùE0íp¿¢ìãA™I úü¬OKKK“Ô·o__wÕ³P]Ø2 BŒÓUÊ\À1 ׉}Ž Påù!2â¡ Æ…fÂÏ Ì€Äè0Pðs€r"‡©´Ê“‘T7@µ`ªñ«'˜pM¿3ª‚Ù¨FL8–u#S=žŒ Š˜ L‡Ù¨<·ß•Á%ÞÀfªù Õ³xÉÒ¥KIzª fÀ æÌ™ãë.À¿'K—.eZ€Ï1•g{b#1åaû=aN€Ï JH¨’€j‚UE@…TÄp’*„$Àçˆà¶$àM‹Åïj®4OwéÉ'Ÿ ©h+åÙßå>$F¾E ·1’@¥‡wû÷®bÜR‰$«ÕZžÝÒÓÓ{öìÚ³gÏôôô2÷wW÷Üž?‹/>tèP9?¸[ØäµÀ†îT•$°eË–Þ½{W±n©¤üþô§?õêÕëìÙ³={öœ:uj™û{¹{e²ïÏ©S§Z´háåø< $÷ï_þòÿùÏgC†8|«¤XÕ?²[Nš§ÏükíÛ{´~ø1<¢I`Ë–-}úô‘Ô´iÓŒŒŒÍ›7[,–Í›7gdd4nÜXÒ·ß~Û½{÷6mÚlß¾Ý8jÚ´iááá111ÿûßÿì+™;wn£F,‹qGŠó±‹eâĉ!!!û÷ÊÎΖ”•––fµgÏž.]º•TÉæÍ›'Ož\³fÍGydÓ¦MÎÊè@óæÍßÿ}ûîY,‡ž;ïìкaóæÍMš4Y¾|¹óþŸþyLLLDDÄôéÓKê°Ãi±ïíÿ»víêÔ©Sppp§NöìÙã²Ä^™ľç%ýô=NïØ±sìØ-~1zôÏEý¬¨CIIæÎí»i“L9ú/]Ÿ·äÊUBñ(b¸Y¥— Û®LwéÒåàÁƒ .œ1cFbbâ:vì(iذacÇŽÍÊÊJLL5j”qTttô©S§&Nœ8fÌûJž}öÙùóççääw¹¸<6...;;»M›67ÜpCRR’¤eË–Ýxã±±±Æ#FŒ>|ø… JªäôéÓ5’™™™éü¡¬Vk~~þêÕ«'Mš¤_^}wè¹óέKZ½zõÃ?üÑG­;ì?vìØG}ôäÉ“W]u•±¿s‡N‹­?Æ—ÆÿF}æÌ™Ñ£G1Âe‰½2?ˆ}ÏO‘– ŸûöÛÔçž»f„Þë×Ç<üðþ ²RS+QÏ¥S§ê´mkl÷u•úÌ,€OÈ}))&lÚ ,Þ¼ €?JNN–d¢œ–-[fl”3 :t¨W¯^’fÏž““óî»ï¦¦¦ÆÆÆ<877wáÂ…ÁÁÁyyyÆþ‹¥  Àb±\¼x1,,ìâÅ‹uëÖMMMµU²nݺŋ§¦¦Ž?þÉ'ŸtylnnnPP¤Ï>ûlèСûöíkÛ¶íÛo¿Ý­[7‹ÅbµZƒƒƒÏž=nè\IdddJJJãÆ?Þ¡C‡“'OÚ®Ü[­ÖçŸþÙgŸMOO7š;pà€­{=ÏÍÍuع  À¡u‹Åüî»ïÞ~ûí’œ÷ ÊÊÊ2ꌈˆ0úïÐaûÓ2bÄ[ŒŒƒƒƒÏ;gß7çÛ®<Ä¡ç.Ù~OÊù‚a#3”saúÞ'žˆì޽ɭ·_Û¸ñçÿþ·Ãœ9’’û÷7ƯÖÜÜý‰‰'·l©Þâ÷¿?””ä0®µ¿ÚÝwÓ&ÛÅ5äç·rå±ó³³#»wo3eJš5%ý¼cÇᤤ‹G†FF¶¼÷Þ¨øx‡îe;v襗2÷ì)È˫߹óµÓ¦…Ô«gÔÜú¡‡~|ûí˧O÷Ù¸±¤úí¹l˹þ˧Oï3çÆU«düºZ­ÿ>¼Ãܹá-[ºl¢Ì“c’û÷4é‡×_¿têTD«Vm§M‹hÕÊyç«Gþñ­·ò³³õíÛfÒ$Kpp)§ÂšŸ()éøæÍÖ¼¼è?ü¡ùï~gßâ¹ýûSæÌiq÷ÝÍïºËV()---cÂc$ýZûö§LI]¹2ïâÅ–Þ0{ö!!½*¸|yÇܹ?lÜÑvĈ=Ï=g;Ö¶ÑeúôÔU«²Ož¼÷믭ùù_-^|èŸÿÌ»x±ùÍ7wûóŸƒÂÂ$äå}¹`Áwë×[óò:Œwíðáöõªò/]ÚùÔS?lÜ(éªÛn‹{챡¡ÎMØš.©­ŒmÛöÌŸŸuäHØ•W¶;öš!C„rc6<¢¢sö—É»té²hÑ¢‘#G^qÅ ‹-2f:wî¼råJãêxAA±óªU«²³³W¬XѶm[ûJ†º}ûöM›6ÍŸ?¿¤c ©{÷î-[¶Œoݺu·nÝl½j×®]RRÒ¥K—Œ/+éׯ_bbbNNÎÂ… o¹åIÖ"’¦M›¶|ùòóçϯ_¿Þjµ:, °ï¹óÎέKZ¿~}BBÂ?ÿùO—û·mÛÖ¨såÊ•%uØþ´”´PáÚk¯µõ­]»v.Kì•ùAzî’GçΦ¤4°û±6ìÖí¬ÓEÖÃ+W^>{öÆ5kº.]šùå—ΕƒË¾›6•tÙû‡×_ÏJKëúâ‹ÝßxãŠààÃIIFyêßþ=lXï÷ßï¼`AVZšó{gÏn>xp7ßìñæ›á-[zé%Û·²öïïúâ‹}6n,¥~{.Ûr®¿ÖÕWEDœùê+c‡Ì/¿ ª];¢U«’š(óä8ÈܽûW‰‰=ß{¯QûŸ{Îå>g¾þºë²eÝÖ¬¹|úôw«V•~*޼úêÅ#Gº¾øâkÖäœ8a_ÏÉO?ýæñÇc'On~×]¥÷êÄη¿ûîo7mÊ>yòë%Kœwøêùçs23ïØ´éöwÞù©„;Ç~þæ›o½uï×_KJIJ:’2ð­·oÝZ#$äË¢OúÍ /œ=p`à[oýößÿ¾p옊†þ÷¥¤Ø®îµhQö‰¿ùè£ß|øáùŒŒ¯/vÙ„MIm}>sfÇ îþâ‹~¯¾úóÞ½¥Ÿ8 €§T( ØnR—gµZ$%$$äççwèÐAÒk¯½¶zõê† Únm—tðàÁ† &&&&%%ÙWbìsë­·>öØc%koÚ´iÛ¶m›6mš}áŠ+^yå•ððpãçJž}öÙ-[¶Ô©S°"û= IDATgÛ¶mFÞp¨sÈ!QQQ»wïvøŒ=wÞÙ¹uI·ÝvÛ¿þõ¯I“&-Z´ÈyÿeË–ÍŸ??22rÿþý!!!.;lZúc³|ùò^x¡N:K—.}å•W\–ØŸÃ2?ˆ}Ï›³ñ\È;>¸vmÛ—Áuêäee9ìsâ“ObÆ®W/¤~ý˜ñã+Ñʱ>ºfܸÐÈÈ ðð«G>¹m›Q^#4ôÒÉ“—23k^ye›Gq>ðú¤¤z:]Ñ*!áô®]¶o]óÐCÁuë–^¿=—m¹¬¿ém·e|ø¡­æ¦·ÞZJ=9±“'‡FFÖ m>dHÖÁƒ.÷‰™0!¤~ýzõbÆ?þñÇ¥ŸŠŸþýmÔ(¨V­kƳUrô7¾ðÂuO=ÕÐ.æ•$næÌš ÖlРëÌ™G6lpÞáû>ˆ›1#´Aƒš v9Óe%]¦M ­_ߨ>ôöÛq3f„7nÑyÊ”þýo£ü»÷Þë:kVx“&!uêÄ͘Პï?ú(nÆŒšF[=v¤ègáЄMImÕ¬™}üxöÏ?G4mÚmîÜ2OìùºÈÆŽkÜ4gΜÒÃÀ–-[lCð-Z\¾|ÙØŽŠŠ²ÝÖ³yófû£Œ‹Í¶ñ÷СCm•8ÜóYÒ±6wÜq‡}‰±Ý¥K—¯Š®˜º¬¤E‹Ÿ}öYIjîܹs‹þa~â‰'¢££ícÆüùó퓃ÃÎέ]êܹóÑ£Gm‡ØïÓM7ô$Y­Ö‚%¥v³g¿fÍ÷¯½vEHHÌ„ ‘=z8xîÛo'%e8Ÿ“#Iv+¤Aƒ2ë·ç²-—õ7¾å–Ã+VäeeY­ÖÓ;vÄNšTJ=9Áuê5BC­ùù.÷±¯ðrѺš’NÅåÌL—íflØÐxÀ€Ú11evIR­fÍ 7Z´È>uÊy‡ìS§ì÷qYIX£F¶í‹Ç8x°äxº²O*ép›œŸ®Õ¼¹±]»eËœŸvÙD™mõLLÜûâ‹{—.­Úõ±ÇšßrKéíÂ1<«œIàÈ‘#UoË-•xŽºg\ì¿æškVÝeáÛþT‚'’@ÝvíNïØÑdÀãËÓÿû_]§[›Bê×Ï9~<,*JRαc•h%¤Aƒ.‹‡FF:”×iÓ¦ã“OJúyÇŽýÏ=çRþüçÖ>ØàúëƒÂÃó.^üôÎ;+T™m¹¬?¨V­]»þ´i“ÕjmØ­[PDD)MTýä8³¯0¤èâwI§"¤~ýœcÇŠÆÍ6,øòÑGƒ#"ZÜ}·Qb©Q£àÒ¥+BC%\¸`¿óùôôÚ-[J:ôh˜«Ói¿O™!¬Q£¯½^”g~QÏÑ£µK}CH͆ ËìOyÚjØ¡CŸ^”±mÛœP!ÜWég0= ÂX––vÓM7y¢~ïpûÝA-ï¹çðòåg¾úÊš—w櫯¿òJË¡Cöi|Ë-þþ÷Ü3g.Ÿ9sàï¯D+Qƒí_° ;#ÚŸáÈ‘}O=e”ï{ê© ßoÍ˳×q\¾l ª’ýÓOi‰‰­ßžË¶Jª¿ém·ý´qãñý«Ém·•ÞDÕO޳ÿûå¢  ^Kêjã,YréÔ©¼ Úu 42òW Û¸ñûüÃ(©ÕºõÑ7ßÌ¿téÒ©Sg‹ »žy&çôéœÓ§w>ýtô AÎ]Š4h×3Ï\*Ú§Ì3tèÿfÏÎúák~þÙƒ·½9¤Õwîüë_/?~9+kWQ=!µkŸûî»â¶n¿}÷¼y¶¶®*yõ|émmŸ:õì¡C¹¹*(pùÛ…RÀH¨÷&:íÚµyä‘K–l4(mñâØÉ“ë8ÍDR·îç<°s̘ú;W¢•–÷ÜS·cǯ¦MÛÿí3Ï4êÕË(¼é¦”¹s·txùò¶®î¿vêÔCË–mýÍo¾ž>½Þu×U´~{.Û*©þú]ºäž?Ÿ—mû¼%5Qõ“ã¬^ÇŽ;ÇŒù߄ԯ=lXé]m5lXøUW}1vìx ô—WÄC6ì<þñÍ›¿_»VR›G9¹}û§wܱ{âÄ_>áíʸ¸ï¸c}ÿþa‘‘'LpîRÇ jÖ¯ÿnÿþÞqG“r,6h7zô•]»~2jÔº.]>›>½Eѳ¤:Ž_§uëïºký€EwµMHØx÷ݶG]7qbÍÈÈõ¾?p`x“&×ýñ•k«ù¯½mÒ¤uqq_.\Ø}Þ¼2û {<0@x`¨Uô)¢0¹Rž"Z¡†ÂœÒÒÒ$õíÛWvýl˜ ïaNâ…7‹0-bx—oQ!$FB o3’Ã;”“íÁA¾îüwÁ1|€$€ ! p;bøIBà.Äð – £BX. À½ˆà3$TI€À—H¨~O¸K¯;f7vìXãµbŒð^Ãlø/@%ðk *˜ €j!À›˜ L‡˜10b`:ÄÀtˆ€éÓ!¦C L‡˜10b`:ÄÀtˆ€éÓ!¦C L'È×€@Ö¬Y3_w¡lééé¾îÀÛˆàN~1îwàÜg‚¿Çl`:ÄÀtˆ€éÓa‰0 DÕöaAüØYðfþ§ÚæðÌ\¨Î¯B‹ŠŠòuÀï1˜10b`:¬ Ì"-M?¬íÛ%©G-Y¢ØXI²Z5}º’’d±èÁõÔS²XJ+7þoì¨*½ü”{Ö+§:¯C€@Ål`C‡ª{w¥§ëÇÕ­›î¹§°|Ù2}ú©öíÓÞ½JNÖòåe”[­àQQQ$(ð2‹•Ï?a±Xät Þvå¾Laa:sF¡¡’”“£ tñ¢$u﮿üE7ß,IŸ|¢Ù³õé§¥•ÛÚ-³Qç¾%Õÿ‰ïÆl½ÆøÅ(ÿœ€‘ªÿ/à[iii’úöíë뎠šb6d¶x$Ý~»þö7=«3g4ož,,OIQ×®…ÛqqJI)£b`‹ëå—U¯žê×תUZ²¤°üüyÕªU¸]»¶²²Ê(7ã2³}ˆ‚G/ÜÞD ™ým-#Gjøpef*3S÷߯# ËkÕÒùó…ÛYYª]»Œrˆ€YlÙ¢Y³T¯žêÕÓ¬YÚ²¥°¼}{íÜY¸½k—Ú·/£Ü$˜ð &Àkˆ@ ³Ŷo¯§ŸÖ™3:sFÏ<£ ˇ ÓãëØ1edhÖ¬âY‚’ÊO`A6x10‹µkµm›¢¢¥mÛ´vmaùƒªGµk§öíÕ§F*£Üb)~€.–›á3Lˆ†~£Š õ>ÿ}`¨ Oõ²r>9”†åÁCQ:fÓ!@‰|¸P8nFªèga¡0x1ªFT¿¾,(£ÚU«ô—¿¨iSEEé¯ÕÊ•®OEIŸÅoï @¹TtBàÄ ¥¥©W/ ¨ädIÚ°A¡¡Ú°A’þóÝ~»$=õ”vîÔîÝ:~\¡¡š>½¸†­[õõ×úî;;¦Ù³«•4l˜æÌQV–¶nÕ_îPJ…;vh÷nY­ªSGÿùOaá'Ÿ¨~}]w]ñnsæhï^íޭÇõÃeT›’¢®] ·ãâ”’âúl¸ü,â¡€ßà¡>T‰'‡®\©>Лoꣴj•^]ññêÐAûöéý÷5t¨tÛmŠŽÖ¾¤ùøquꤟ~’$‹Eèšk$)-M7߬üEµ’®ºJS¦è®»Ô²eq»¥T˜‘¡¦M%iÉ}ö™^{M’î½W½ziüxY,…°E }ü±ãòƒ’ª­QC¹¹ºâ I*(PHˆòòOEIŸ¥$¶ÄUÒ“Cy`(P<0¥#~ƒàC•ˆ¿ÿ½ ÒˆÊÎVûöÚ»WÍ›ëðaµn­£GÕ¾½¾ýV5k*8¸°Z«U²XTP I‹òòT£†$åå),L¹¹¿¨VÒ_èÉ'õùç ÓâźóNI¥Uhëf¦ZµÒáòZuÍ5úî;Õ«W¼CPrrô‹SRµuëêèQÕ©#IgÏ*:Z™™…ͬÖ?K)J1(bJÇMAP¶Š.ÎÍÕÇÞö¦6môÂ Š‹S½zŠ‹ÓóÏ«m[Õ¬)IM›êÈåå)?¿p„móÝw…‡«IÇj%]½Ö¯×É“ZºTãÆ–R¡MýúºõV­^­Õ«uûíªWïßmÚT‡;RRµíÛkçÎÂí]» § $Y­…ÿ•ôY¾E üŒÅò‹ÿ\V“ÿœûf[·ªM]yeá—êé§Õ¿¿$  §ŸÖÀ…ßzè!£ƒ•—§”Ýw_q%“'ëÄ 8¡I“tÿý.ª½÷^íÛ§Ë—UP üü²+´7r¤^~YË—käHÇo ®?þQ?þ¨3g4iRÕ¦Ç×±cÊÈЬY…ÓΜ?KéX( žF €r©Ð„À† Š/þrà@efª_?Iêß_gÏÇ€3Ô»·úõSx¸x@ƒÕ»·:vT«VjÒDs渨öŽ;4x°""4c†Ö¬)»B{F7Ο×Í7;~ë‰'Ô¶­:uÒÕW«U«2ª}ðAõè¡víÔ¾½úôѨQ®›sþ,ßbm€2$''KŠõÄ «üMùWÄÆjÝ:ýêWnª­¶JZ!ÀÚ }Z´h¡¢ÕãÆ?~¼O; ‰Ù€3cB€û‚”ßÕW_ýÎ;ï8—?÷Üs¶mþ¤T+̦C L‡˜10b`:<)P"—ïE®xÞT³ÿSmó ø f.TçW¡ñ’c¨:fÓ!¦C L‡µà¨ÒËO¹g½rªó:TÌ|,**Š^Ælà7,‹¯»àþòÄwëZ_÷À4,÷ûº<†Çûº‘{ÿe60f?ãp‰Ú¸ŒZ=¯[;÷Í_.ú¦§§7kÖÌr5=±ÇºV–ûÅ" PY­Ö’¾eÌu—²ä™;ˆð¬2G±sã«ᦠpÁ¸ÿÒ_¦/ …Àk˜ øžq_€@ÅMAUä‰Ùf 4ŒM‰®ù˃M†± ›û‚À;ˆ€é DÕp¡pµêŒ‡0!^@ oÛ}D±z»Ú*æïÄ^Ô^C €ÒxbB`Ãn ú•;+ôhµè`ˆàm|©A¿RÌ¥fHÒ?는‘)I©Š™"Iùš¹NWŽSx‚î{A.>ï}5§ˆ\¦K¹ŽÕJúè+u˜®aŠž¤eŸHE1Ærqžùî¤î\ Ú£Ts„þM'Ζg_Öð—‘ &ãõì†âýí7^úXÑ“2L]féëÊ8°¢X( ÞA Ì"í˜<£ˆE$hÀ3J;VXnµjÚ?TŒŒÕÌu²=¸¹¢åÏ]'Î)í˜z]«•ü­$mØ­Ð mØ#IÿÙ§Û;KÒSïiçaíþ«Ž¿¨Ð MÿGq [Sõõ3ún‘ŽÑì·«•4ìEÍù²–kël}qX*[[×_ÔÿÍ|MºM'^Ô‰Õ®™¦¬),ÿ¿7•yAGéëg´5ÕõGøx¯>}Bg^ÖqTÕ10‹¡Ï«{ŒÒ_ÐKÔ­µîYRX¾ì}º_ûžÕÞyJÞ§åÉ•,`î}rè‡_ª_×ÐÀNJÞ'I|©‰·êýÝ’”ü­v’¤åÉJüƒš7Píšzæ½µ£¸†EÃÔ¸®®¬£EÐÚíŽÕJ Qúi?§– •4Úu7öÎÓ¯Û),DuÂôäýû›Âò×?×ÂÔ¨Ž®¬£…p}ìK£Ô¼ÂCô§AÚó}¬&À£ˆ€Y¤fhæoU/\õ#4ëÎÂÛQ$­Ú¦¿ QÓzŠª¯¿Þ­•[+YŽrÚ°Gñ¿’¤¾mµã.^Öç4ó}v@/kÇ!õm'Ié™ê4SAPÔd|ñM;’Z5*ܸúJ?çX­¤·&ëãÅÍRˉzw§ënü÷ zÿYµFÊr¿"t*«°ü§³Š.ª?:Òõ± kn„‡(/¿–ëO¼ú׈@ ³¿åöÎúÛ½¨35ïýÂKÎ’R~T׫ ·ãZ)åÇJ–6w-ÎÍ×Ç{ oû Q›(½ðoŵR½pŵÒóÿRÛ(Õ –¤¦õtd‘òV+¬kU°¦¸’ïNn>¡&u«•týÕZÿ¨N¾¤¥£4n…ëž Y¤ ôã¬ÑÙ—‹oîj\WGŠê?rª­Ò@)öïßí…†ì‡ìîjÔZ¾gÓÓÓ{öìÚ³gOo¾¹’˜Åâázù?ª7FõÇhÕV-QX~>Gµjn×SVN%ËQ[SÕ&JWÖ)ür`'=½^ý;JÒ€Žzz}q<{èyY+/_)?꾊+™¼Z'ÎéÄ9MZ­û{¸¨öÞ%Ú—®Ëy*(P~Aaa½pí?V\Iöe…),XGNiìËÅå÷ܤGÖèT–Nž+^0P•>Ð% 0lÙ²¥wïÞÝèŸþô§^½z={¶gÏžS§NõZ»Ä Ùß\1r©†÷Vf’2“tx©°¼VM/Êge«vÍJ–<·LlØ­øÎÅ_ì¤Ì ê×A’úwÔÙ‹XôÝ¿UïkÕï)…'è¿kðõÅGõ¾V§«Õ$5©«9¿sQíq¼P#5ãu­_Xø§xu}¼¸ÿ+ÔÔ×Tk”nù«ú´->öÉ!ª®–ÕaººÇ.6(J¥Ø²eKŸ>}$íÙ³§K—.AAA‹eÿþýQQQÙÙÙ’²³³£¢¢ÒÒÒæÎÛ¨Q#‹Åb\×·X,'N ‘´k×®N:wêÔiÏž=Î%¶CŒ [£u~ûí·Ý»w iÓ¦ÍöíÛí[qÙ%ã(ûž»¬dóæÍ“'O®Y³æ#<²iÓ&¯[b`[R5ëÕ W½pͺS[ŠžåÒ¾¹v.ÜÞõÚ7¯d9ÊÃöLOCLYתK´$uj)ëZ]Ó¸ð[WX4ó·:²H—_Õž§ôû Ë­k5mŽ¿¨ +´âÁÂ;ˆª½ç&¥ÎWî«úfžt,,œu§²–Û=)¨‹.Pî«:œ¨qýŠËÃC´zœ.®ÐñugW5oPܮÆ×%XiLÝ…ù#F >üÂ… V«µM›67ÜpCRR’¤eË–Ýxã±±±Ï>ûìüùósrrl·âÄÅÅãò„„„Ñ£GŸ9sfôèÑ#FŒp.1±Z­Æ†­Q‡:‡ 6vìØ¬¬¬ÄÄÄQ£FÙ·â²KÆö=wYÉéÓ§5j$)22233ÓkçÖRΛ–øœqÁaf\Ü-iI¥åþâoÅÍÒoºhò@IJüHöhç_$é¥õê6½=YV«~—¨Q}5úו)wÙºCߌoÞøè^Íš536{ ëÄW5g°.çiÌËŠi¢xüÀ’¿0åF6ðß_$À;ÒÒÒ$õíÛ×Ó %''K²z9Kpþëæj‡C‡õêÕËø#|öìÙððpã[Ÿ}öÙСC÷íÛ×¶mÛ·ß~»[·nëÖ­[¼xqjjêøñãŸ|òI‹Å’››d{îܹ°°°‹/Ö­[777×¹Äb)Û7êPgppp^^ž­Ûö­8wɨӡçΕDFF¦¤¤4nÜøøñã:t8yò¤œg©”¿{•øq3˜ÅÚ Ú¶_Q5AÛökí„ÂòoVXµ›ªöÓÔ§­Fõ­d¹˜dÜÙ¦©ÚNUÌ£ª¦?ÿÞ€Kö÷è·k×.))éҥ—)vïÞ½eË–ñññ­[·îÖ­›¤¡C‡nß¾}Ó¦MóçÏ7ö1Fç’®½öÚU«Vegg¯X±¢]»v.KBBBŒ¡¿}£uvîÜyåÊ•Æuý‚‚‡Vœ»ä²çΕôë×/111''gáÂ…·Ür‹GN¥+Ì~£³¾x³²]Öª–'< ¹œ`6(˜ >|ø7Þ8nÜ8I»wïNHHØ»woAA±ó{ï½wçwnذ!>>ÞVOddäĉÿïÿþÏvu_ÒŽ;F•ššÚ¶mÛ+VÄÅÅ9—L™2套^ÊÎÎ6l˜­Q‡:80nܸíÛ·çää}¶oÅe—¬V«CÏ+9zôèСCwîÜyýõׯ[·®ys·Ûzb6€ø b@5Að&bPi¢££?øàƒöíÛ»¥Ÿåä“FËä‰Tå^à)Öµ²Ü¯¨¨(çÞ‘#GLÒ¨O°6*Æ]¯À‡ˆ?À“CÀ½ˆPILxË0ÀˆPa,Nø;b ºãÂàvĨ  ü1à7˜wá½€Ÿqyù¹:_“®Î}«¢ôôôfÍšYîg «7/¸ 1že¼·*;À툀ß(åMìUú[â!‰ ï°½QØ×€@@ €Ê3î òu/ úâ ËÕK„Ó!@•ðäPoâæ+pb`:Ĩ*&¼‰ p –€Ûþ‚Ù€ÿáÙ#PEÌ€0*øfÓ!¦C L‡˜1¨ý.IDAT0b`:ÄÀtˆ€éÓ!¦C L‡˜10b`:ÄÀtˆ¨¼¾}ûJJKKóuGP1ÄÀt‚|Ý&|˘–)?fP%€Âí*ñ#`6UEð;̦C L‡˜10b`:ÄÀtˆ€éÓ!¦C L‡  ÆûáÓÒÒ|Ýà6ÄÀt‚|Ý~ƒ ð/Æt.àÒÿÀð~+8IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/query-duration.png0000644000175000017500000006422110004234423024757 0ustar frankiefrankie‰PNG  IHDR;ŸÞdN* pHYs  ÒÝ~ütIMEÔ;ƒùp= IDATxÚìÝw|õÿÀñK𦋦{Ñ‘½‘%Ã""KDPd ².DEDd© èÜ V¦ BA–¬2[F)Ý-Íþý1Í]ÓЖ+}=ùÜ'ŸÏû>¹Þ;w—(ccc%! [d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ùR9,ýr{*¡PB^lìdMÇK—&ÁN0”Y\@¾ÈXÈ ù"c _d,Àm¡E¨FQp¹X”ç0¤q£Þu;–ÚZ`[„ûE&;Ãuʼ}Þ²šœd,Àm)Yf‡ËÅÒ`)pr·"Ñ«{oáÁ`2éKm-°-‚­Ò<<º÷]™þRÈ6Û)ëóö–¹]GF¨ë4j¹xsâ½4uôëñ1þeæxÛùc¡b ‘3ÈXà?~8¶£ÔÖÛ‚ €7¯ÜæmNÒʸ!«-ÜyþFö†%£¿©ñ×—³]kj×Çý»MIÈ7=hŸôcˆœDÆ‚r-aÕ¤uB#<µêøý±4»gÓÿYÕ«Eå¨õ#u}ðÕ‚k5hÞî˽×mO›J7x·…µïvªZ1Ä·m×ç¤ç[Ë“w}þB\­Ø÷˜Š!»÷_³í„ ¹—¶¼Ò£IÏȰ€¸n}Wo=Q°AK,=iØs«Dkbî½…W¨Fq}Ïâ§›ÅÜG×MëܰbT€{ÍÚõ&/Úl»JÚá•=›GWôSÚŽ+óä·Ï¶®\¡Y»n?ŸÍÌ8¾¶o«*ÑAž [vÚt1Ûvu˲Ã:,´;u~ø–ŽyÔiØ|ÎÚÛ–Óÿù²g³èÈuýfí~8›)ñB·Âáźáòæ('ÛBZy‚ôØÅꋵ/Ö¥‚{!‡ÄvMEÚÝÙÏ;î¡Ã­éäN^ìÝ$Ö¦-±:‡àdĘ·ÎÏ[‹#Þn²èÇ^Í««UUšö]±¨åì‘[œéXÁýð¹?ˆë˜3ûmKÍPbw¦V0ëZF†§L‚ TtsxÕ– k\8’Q‰HLL4’Å?þ=øÿÿ8Ú·Ro÷^JN×Þ·­Oƒö‚ XŸ¡eƒßﻜœ®MøcKçhÍðõIvk9ðû MX×’nÐöŸ “ן¼š¡Ý²|DP½Ù–“¿Ï‰íýÝÞKÉÆ “VÍjY½{˜Ï{?ýsñ¦1ùzÚú/Þ’hÓö¡Xkko %1®ÚM^Úp ÙnCü³~Bh“—7¼r%CòØ¡ñOTêýå9ë*O<ÿÑádíÉ¿¿²ís·§ßÙ}*ãÊŒ¯¦wö é÷ĤßOZvò‹}«`öP¬Û6Ó`Œ¦r¯ï,Óà¯ßž¬ìgé°¥NÇ.oY^tÍ»k*½&ñB·Âáźq/›£4¹îhÚ˜9oï§m®íîÓþ­¸¿¿äü[ÏñÌtéXH"DEâëlM2”_ÕÝþN1¨îœQ5å‡ú{Ù¾K“2Íj듆´Š¡U¯¥¥Û¯eÖ‡ú©-kI7h•›´eâˆ7¶î;‘•ûCKên§üUögx|5õµY_ñ¬õT>=û¾ØHäï´ÝQ¬5Á錥¨-”ܸ®dšUŽ6D–Ád[ÓÍ=èêÍTË*W³Ìn’í|h»é-Ë{(ÖmëZÕÝØŒ×lH‹­jùkñß5‡j”/ä|(Y¬÷²9Êöùhø.EÇ㮲bóÛ¯låüÄ›™. I„¨HœÏX¸å—ý¾_áVH‡…fƒó ZLŽëcèôî_ç³­§\­«;ÜéÖí?uË‘´Ÿ–LŽ4×6zôg‡› [ž(F¬µ"ŧH-”ܸŒfÇÝ;›n²=¹lù+ká0ôvîU…}ÅŽÃ:,”ˆ›ù¿SÃæEÅ ‡CëF‘6GAü¶X¼÷šíŒÝÃr Æ"îV¶/Ý%—wMEÝI÷ÐáÖtr'ïp£HÏB_÷ÞoÜfÞÚqøî¶hè£>˜£³>ÔçìWù4q¦cnEÜ(Nî·CÏ®}ôoÊžtm:E6éå¾}ëä÷ŽåN}4¢H[lfJÏjECTBÈXP~=îóÅÅ»wìÝJ]gWa}jžu9ûÂBïðÁ×ʽ¶Òù-¾½š3oÄSÁ>‚ ¦[Öò+ú~qIìBEl£Î#ßú$~ÿšï'÷þ{E¬Ã$[sJQ[(¹q­½–SpCô¯°*©NÛ÷P¼ðî4Xq)ën‡/-ò ä 9 ±éí°EÚ•mQˆòçg ô¾÷^º$6‡]Ú9&¶5ÜÉ;Ü(Î̱:÷¾?gÞiÞi²d×UëÃë»æ7x¥D÷*Ò»yD¿QÝgìG£B›(B¿n•¦Í^_iJeO·¢¿ˆ}Ø];’Q !cAùõò'ƒ–t²ûD²Ád¸~zÏÛÏÍ·«°ô¹ñûÎ\3˜ WŽÿ6æé¹ýM°[ëÚÉ]“úçLƒ£[EÔiu{§Ö'¢Â+óH»eÐç¥ü4§·µÎ°/ÆÖ}ðÎc—ô&s^ÚåŸ?P½áAB5Š7íÏÖÍú¼3‡«ý[8Ne/ÕÞ”¼¬ "ÃjJ´f˶W÷ÞB K„ŸúÙ{êŠÝ†±tøÇOýýøe½Éœ{óÂóúÕh:±xgˆÃÚí /î1d÷‰$ƒÉpåĶqw:\Ôr>‰u£H›Ãn†”‡mñJËð:­‰=,'Aàü ” Ñ%»½Cbs¸¨» ©ŠlM'wò7Š33D¬ŽÄœ‰óÖáØ¾»-Ú-~oÿˆ^?í?«3ê/üýíà»_[Ü©$:æü¨;OnrxÑ‘G'Ö¡êˆ.§>ÙYrÏbÙ® I„¨¤ð]aü+Ïÿ¶,œT;&ÈÍÍ=²æcs~½fySX?Ò>ºiaó‘*7UPLƒñ‹öXK]7nñ7›ÃÅ|¦vXHí–:çŽlèÜø!µ›Ò7¬Æˆþ´ÖIÉ2ÿù¿¹­ëƪݔB›wñë¥ü”,ó®u‹žx´NO•Ú+ ~»ç×Ïv8–õo>è¥VWˆx~v‚DkÖ÷¾]¯î½…— §v¯l];ƽÀ†ø}åÌfĨݔ^~­{ßqEk×½‚ç( }h»ì°‡ íŒ_úNƒªáînî¡U›üß§ }Ñ{ …Ã!‹u£H›Ãn†”‡mÑ»VhH­½µ{XN‚ ñKbcwXY¢}±ÉYp/äðŸÃ9\Ô]tnM'wòbïhgfˆØë:‚ócÞ{Áw·í¿ýëæ4©¡RªÂª=:eí™Bw­b=±;ê f¡ûíäk‡Õ*¯„†”,óõ´ô@µÇökº¢¾õÄf¦kÇB!â»Â9ròÆGÞ² ¶E9€mÇØQ¼¸óÀƒ€s,À=±~áÞ;l‹r‡_?˜’e»Xý’ëI9ßã¶cì¸ïø=òÅUad,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ—Š(ÓB5 ËBJ–™hðàá €²-%ËL®ÀŒŒ±q²²åq ä±€‹8½@) c /i k?Ù°F„WD wÓÖq‹¾?xû ³î«)ýWÑD†ú?ùüÄd­±†ÄëïZöf—¦•¢U=Rïý/ÿ°ZÏ–pæY!c /ÏvÒð•Oÿ>—•t5eõ‡c®|?ÄRž0£í‡Çb¿þ+ùÂ…Óý+îì1|£t;bõO.}ê¥ÏοúùŽÄÝß¿­ñ9ðº¥ÜzÂIJÀÉdB‘˜˜kWz#›È¸?ºDzVeN·ÖÍjT¯¤ºsªã©(ÏÉÿf5óU ‚`¸uºRåÉ×[× Õ(ìr ±ú½¢½ž;x³w¨·ÃW/ØN¡\X„ø:[“Œ€¼džÚ8kîò„§ÏŸ9ã1hÖæé/Ô!Ò_©7ÝM  ÅõL“õaÁ´A¬~”¿ò\ºI-rÍ ¥ÃùŒ…ßc /~5ºÎø¬« ‚)?aó']u›þB¢  }½?OÌ W;¾–ÕËM™k4û¸ÝMDÄê7óõؘš×3Äñ9¥Bana@>¸€¼´î5ü§2néz!?Cén)wD½gFÍ>u%ÝhÔ^ø'þíþ l×êæ=釓M‰Xýéo´{³Û°]G.èŒÆÌ«ÿ~új{Ûvñv_òg¢‰Í€l”ÉŒåì®Õãûµ«ãèY§^ƒ ï/Ï5–ÉK2.l™Ûµqdd€ºN£–‹7'ÞKSG¿ãOþ‰ÁçÃêÿ8cPý(Ϙ˜Ê¯/?µ`ÓKyƒ7wŽ®rfpûjQÁšž#gUìó…íZ“ÖÍ=>%.ÂOiýŽ/±ú5GmZ<¨âÌÁ­cƒÕÛ?{£ö»¶í,~ÿ¥Ï7°mG‚Ý׋±í( eò>–P"¬ÍØ•ó_¯’yéð'ãºÇüç²^e+ô9I+4›ÿÁ÷ß>Õ8&9áÇ¡=G Ù{©_´¯ Míú¸ÿÀ…I¹×çbz” ÎßÇRV?•ÿôëYªE¨”ª Ê'­ùþüO£ Ö±|ê™yòÛg[WŽ®Ð¬]·ŸÏff_Û·U•è φ-;mºx;3˽´å•MjDxF†Äuë»zë‰RÂŽo7Yôc¯æÕÕ**Mû®XÔröÈ-ÖgÿoZ熣<ê4l>gm‚íˆÒ¯ìÙ<º¢ÍgÀCVäþx ^,ëlÜú»3µ‚Y×22<Ý`¡z à>*“KJ–¹…ÆÃúPåQY© uXM„‰ï{÷›Î''Oï¡¥ÓÀQïúÍáóW®ÏzV1öéY–šã;ô®3zùáKy.œ{w@µ‰=k•Â(–º1²}EëÃðvS-²,_Ù6¶÷Ì£“Vï;Ÿšóëšé'f´{G²uDã?ËXø[â±ýk¬ëþ¶÷»ú~b°«ï°ñëiéán s[ûyä$Ï=“}ýÃÄ AN^=§ñ >vÓ(÷ÃðíÆÉ[ôÝlá(]‘`W_¬ñVSÛœYüµ «Ö{{ì’kñsAØ5ewÓiOðŽÀýR¶3–›‡¾îÞzÔÐ ?Äxº‰ÕQ)¤ZÔí?uË‘´Ÿ–LŽ4×6zôg‡K¡ó }ÔstÖ‡úœý*Ÿ&–e… Øž+1ß.»Í­ˆ/dW_¬ñÆs„ký›²ç]›N‘Mz¹oßz#ù½c¹Sà}€û¥Ìf,fæyƒŸx#~úï ½«ùG‹ŠØFG¾õIüþ5ßOîQ #Ò0dÉ®«Ö‡×wÍ nðŠeù¹pŸ—²¬Oe_Zä>¨¸^W¬q7è7ªûŒýhTècAè×­Ò´ùÏë+M©ìé&2À7@°5ËϬxâsì£Võžúˆ©^¦'X±ÌŸ%]#»~ô1Ç=*“‹.ãðkÝk­Ïï°gËÊÆa^÷þ¦ Õ(>Þ´?[k4ëóÎ>®öoQ £h·ø½ý#zý´ÿ¬Î¨¿ð÷·ƒGì~mq'ËS#^ÜcÈîI“áʉmãžžÛoÑ„âz]‰Æ;OnrxÑ‘G'Ö¡êˆ.§>ÙYrOÞ$Š]q}ûƒú•îe=>&}ʰYÿÌýrSy8xÕ§Çf={SÏó➔Ɍ¥Ý#ÍVî8ýãÏGù)$¾{×úËn…>ܵnQÂÇCëE{FGEýßâ+¶}Z £¨5ð·ÏŸû|D›ÊAÞO ÿ¨ûg¬?ÆÑ~þw¯×šÞ¿I¥ ïŽý߬9iÛ{í" Áv¤ÆÎa}±ÆAoÿZåõÚ h*M T{¼Å›Ä?)j9P\ÝùrV­¹zú¾0j/ÏÕµAeßu­º ÞZø‹µ¦Ý?KùÙ«Æ=×¶Nt…ðÏ:uë²0ÕæP¸DÏMå\ÜþÖàΪT P×mÒê£oöKôS¬¼úy9ìG`×i53þï÷dÞ¸Âw…(~Þ}õ¢–åÁ·…ÿ:óв…¾/ÖöŒ™ï7tù»#kDúg\<¼ôg’ŸÛ¾¤{±wPÓŽ½оM‹Ê·nœýnÞàu?²éÕâ}ßlçÖõ m¼ÜmÚŸîìuýÔþ/çN|sÙ>×ö%×Ï’^ѵf¯íéÝar÷ã;Ÿç­;åè»Â¸]0udXpÁ“®éLÖúŽçOÑ·;ñ‘Šƒ ‚ð¿s™/Ô t&žïý~eÍâIµ¢ƒUJUp•Æo¬ü%~Ògõ÷Ç÷r¿nE«ÝÜüÂk š±áƾY¥ð¦ûyàˆš ~û¥ž1¡~nJuÅš­Þ\¶Ož{Q‡û“áæ‡#:ÖŒð¬\©ÊصݎEš‡®½kËJ\Q®þ–¡Ø‘±‘WºÆ¬q¸]_µ“ñ´;¹uã+ËBãjþ~n•"C;<Ñ}ñw:\÷Êö©Áß+…]Ó'‡n ¾éÒ(²¢¿ªZµª'̼~'Ùë§3ý/ ÷{&´^—×á·“ÿÞ^åÐî/*ÒÂcÚɬ»ýøÿ’®ÞþÌØáüqa‹‰8XT p;–jðq+üÄãwÏVžï7bùÔaÕÂ5—úÖ 7ž¼žy÷«ÿu·ÒÏ&ìX8iøõN?}?©¥íº§6¼×sÔ·ËŽþý¨¿‡PÂ*ú)«?ùúü÷Çש˜}åßïô^“ûvºç í§DÿKsÿðx„Ç”»Û}kTtœebuºö>2³#‚+^Kçàöœ¿*ŒŒ€Œ˜M¹Öèó×éšG]WÄœ¾r¢oõkNŸôR*ìþvZFú+õ¦»å …âz¦É®Ž-‰ú.(ýŒ%íàªq“>Ü{øTæ-mÿ£ü•çÒMꇈ™§6Κ»<áÄéógNç¸E šµyú µ¤G””i¾ÝŽYæ_ÁrøXÔ8[ .8\E¬ŸÒý/ØNE?å… SÁþ‹Í¶8ñ‘ˆƒE¯h¯QG3Ú;‘H˜t×>ycäêõÛ’RsCª6E‰D,}§Õ¾·v¦‘'†½sàԽɔ“zaó²7Ÿw|ÎÊ^‚ <ÖgĆߦçjM†ü‹G¶¿Ó·ËÃ>áÐ7SZ6è¤ìºôoæT¾sÆ£P÷þÝ/NïÒoàÛ‡/¤MÆŒäã‹Ç<Ñv–D?ÅÊKºŸbû‡·ž­~g»_ütÌðRÞ«oy{OÓ·ÛÀ= c /¡-ß½ò§~F›Šá­?6üu}RóBŽÀ¼¹st•3ƒÛW‹ Öô9«bŸ/Š·¾´Åï¿´âù~ÊRû®°oVÍX7ºmL€{“Çûå´½ûõ;5GmZ<¨âÌÁ­cƒÕÛ?{£ö»–òχÕÿqÆ úQž11•__~jÁ¦ …¾ÄÌZÇŸ|Ä?ö¡úÛTý6Ìk_¼qûý(±~Š•‹µÓaÉŽ'ŒÚV¯På¡z¿{ü°¸s±oâ#‹ˆ6Kþðë¿÷Ï¡÷Û«&?×0&P]¿Y»•æ-Ù{¨S¨·  žýzê b}+†öú–ªÃ¼-v¡ÓÐw“óµ?¼ß;Üæœä¥|©oü3æŸÁ38î^6z¥žÿ{¿Eθ®µ£Üë·è¼Ï£ïÏ_=/ÑO±ò’î§Øþ¡ÕœßŸõŒïð¦Z­Ö‰õ–¸<]Ÿº~ê©€ÛD–??1îcÜÅ/ÉŸb‰Ãñù­Ÿû­Ç‘_&Ü÷®ž_÷èÈ„…Ï÷®¬¹ïyúYT‹»DnŠûeãøú¼kPwÞ\Á9ñyÀâ0±†¯nêOž«A?¹q>cQ=Èa%!£à IDAT8âð2rx .âó Í“¹§ÊƧ°e¥ŸÀ}AÆåŽÄAg¹:.,ñ!d…;ïÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _*‡¥›þN%4Jȋ탬©ºÇõ äpUù"c _d,䋌€|‘±·) …BQp¹X¼c‘s›åa. ‚WµcQcxä³q…û¹)•e(æÌ²œbßï@I cn3›Í—‹¥Áû89·Y¦IÛÙÅÊhÒ5†O]´ì`’Ñdr-ì÷å¸ógȃ}¬,Ûà8¿ßKÜ8·UÍHµJ]ñá–þœÈ@i"c€’µýüŽ¢®r)ßÐ&Ò—ÐA&²/­lÜõÈe;³ó³_1úëq1›°(5d,(×ö-ŸÔ06T­ò¨Ò ã×GÒìž½yhÕãõ*{¨ÔaU½½ò@Áµbê´ûtÏuÛK)¤¼ÛÂêw›V u÷ô­×þù½iùÖòËÛ?ïÖ²–ÆÓÝ[Ò¼Sÿe¿ž!ç–;7 öõT{4~¼ïç[Nu,‡ÖLk^£¢‡Ê=´J½qmî\þ¡P(&žËÔç²>«_ÐU–:k4Ÿ¶:ÁRhiäê®ÅÕŽ)7‡ÍZVI=¸²}hw‘‹ FÀî –‚·8ì†t%e×Cëÿ …¢Ò[%æXÁ+mÄæ•í*v+:ì˜D‡ ö͵à‹Í=gfˆX‡“ÜÉxJlô"uÕáÀ|£É-8–ò›‡¾l_;Z­RG×n÷¿Ó™Ò=ta¿÷ë ·[,ÿ±_Ëê*jöý~yË)ƒ·ð@éILL4åÒå-£5UzŤ3è.Û6 q{A¬Ï ‚жñ€mÇ.ë Ú‹‡·<]I3î·$»µ’ÿýý¥æ ¬kI7hK„™¿4µ}5"¤ÁlKá³ÃªõþíÈ%јs3é§C-«?îóѯÿäꌺܴ]ÿ{Ëa›/ôÛ„ðæ/ï9yEoÔß8è­§*õÿæœ!ÿRˆ§ætžÞRG—sÈÛ+æ†Î(VßÚí;/7Æ/¶×o–—;ú[ÏX¿qñIÖ:õ›¿ôû¿Évq“n¶û .gjoœøÊáèÄ"`WÙnó9ì†ÄSÒƒ*ØC±ë°3…Î+‰ÕÅ:&ÝaÛÖ\¾ÃÈ;3CÄêˆMòBãé02¶]èªÝÀy£É38‚ tíöÖѤ }~ÆÏ³÷«òšD]ÛïµñóØž‘o­–Ÿ±ÝÃï1þˆ(5d,(¿ÆEù¾w&Ýú0;i±Ý_î%IÙև駦ùF/¸VîõÕÖµ¤t̤WºZߊõ›~6£`•@w冒]˸hßMi·¬Oé²÷ûFŽ1›Ík;Duùá¼¥ðô—í+?ý³t}³ÍaÓ¸(_Û®¦ŸyÏ7zœµÎšë¹â&ÙìÖô|‰Ñ‰E@:cqØ ©Jª`]ÎXÎ+‰ÕÅ:&ÝáÿLWƒï0òNÍ‘:b“Ü|Ï‹ ]µ¸ÃÖ¯7@æÁá‡Ô<˲þÖ¥Ê_ª‡.í÷¼Ü9FÓÝý–1GéæÍ¥†Œå—ŸJyS÷o°ÙxËî/w¾í“ú›–ãûµL:ëZÒ Ze_Üü\ûz~žîÖS–r•2Ívõ;®˜Ò4Ö¿â#-ÇLùx¯ÈÄKû©ì/þts2›Í7þ_ÀCÓ-u^«¤™ž˜!]ßlsØä÷ß®šîÇRG/7‰f ’[J,Ò‹ÃnH÷PbP{èrÆ’/Ò1±ÕÅ:&Ýa»éáZðFÞÉâ°ŽØ$7ßsÆâBW N öù:aau_ypþ;¥M…ÆÄ…ýž—›"÷?K. €ÒÄ},(¿ì¯ÙW¸Ù(YËlp¾A‹q-ûž|÷ôÛdÚ®îð›zœº/1mçŠÉ1¦3C›F\xX°¹åö5îâ/­„ à ºTAkͨq}æ½6cû¢ì–“bý¤ëÛÁ¶«æÿŽÞ`v7‰fí"e7:‡°yiË’Þî âß{$ÖC‰A¹ßÄ+ênW¬cÒv9ø…Ï=çfˆÃ:b“¼HntºêæÄ`W¹víŸUòŽJá`?$ÖCö{M+¨÷eë¬uÙûÝ+4á€ÒÃ9”[ã£}ß=íøú.K"±ÚþÚ¡ ײ½¦BºA+¥âîñŠ1ÏZçÍÊ~ïÚ\­áPîÕõ*ÏÊEËÿÅhfËtØÚÞ±µûâÔ±š5|÷µP¢¾íHß;c{=Ò»šè Ö:®*™àd³Î°€¿J™xëöåy7¾ ¹¸¥Jª¨ÝÄϱ8œW«‹uÌùKð­‘w¦5±:“ÜÉžHlt׺Z¤7š<ƒ#ˆŸl,ØC×ö{ßvˆzòÎE¤f³ùü]£ÚûÀÿ d,(¿.oãW¥çÖ£Iz£þÊ¿»‡=ÚÈî/wÃG‡í>yUoÔ_>ß½’f¬õvç;k%ß9¨éÝûV%|±~xDý–å¡Q¾Ýf|w#W¯Ë¹¾öÝ.Ö:×þœÛã×.ꌦœÔKß~ø‚ÿC£-=™±~_f¾Á¤Ë=¸q†OD¿"åÊöWý«=óÛ‘K:£)ûÆù¯g>øÈíãÚ¼”ÿib& ŽÐØ^Ð/QßÚfÒ¯cýªöÚzô²Þ¨¿|tkÏ*~¶÷µ·m:h׉d»¸9Ó¬è~J$¯Vöëºnf«Ú1nJoÿˆöÏŽ?œ¥µ®5*JðÐT»¦Ö·ž˜µÔù{å;Mª‡»»¹‡WoòΗîîS!5ae‡º1îâæL³‰E ãÔ×íjG©”nkµ_}ø¦m;ÝxÊá Äz¸kÊ3ÁÞj߈¡'ØmbÛU .;œWW/4Úbåv}+Rðm{"ygZ›u'¹Ã>;$¶Ñ參ƒ}¾NhX½‹4-K98v-Û>ë¡kû½³æ´¨¡Rª"ztöú3üùPš‰‰‰±±±\¸L¡P˜ù=x™EC¢l/Êî¼ _*BÜ ëÏQó±½|¢!Ñ ¶WšHvØdPn‘±÷„£(FC¢l/& Ìáª0òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2òEÆ@¾ÈXÈ ù"c _d,䋌€|‘±/2e›âB!¥{¬ÀýBÆ l3›Íf³™8%‚(£ÈXà.N5 7d,䋌€¼¤þ½¦w»†Á¾^*wïjâæ¬;xû ³nùýbC4j/ÿ–½&^Ö iH¼þoKÞlQ«’—»*0¦Þ¤eX ­7Ã8ycŒ]—ë»0^…BñóÌá5£ÕžAgÇúº‡c2Ü|wPÇP_Ï AUÏø•‰-2òҹæ>MLÉÒæ¤¬ÿdLÒÚ!–òýSÚN;ûËÑäÜÔÓC¢v¶°Qº±úÇ<õìÂóSÖìȸ¥;÷çš û^·”[ï‡1ß!çñ¾òg𺽉9©‡ü6•n_l,ÛG¶þ2·ÃË)g¶W;0‚‰-Ebbbll, -ü<ž0ç™¶Í©Q52,HuçÜ@kÏ™—²ZiÔ‚ nöî¡Ë=n]K¡PØ—‹Õïà5øäÍþaÞ_½`;bìjº¢X}Æ«P(þÈԶШjÁî5òõ˜s9«½¿‡ ÚŒ­žqÜ'2ò’ñïÆwf.ßwôôÙS§³U#çož?¸– j7¥ÞôŸ#~“ÉdûÐî€[¬¾‡›2Û`R‹\ÃUú‹ ãu¾“RñQ*sŒwâ`Ö*”žd,yâª0òâ_³ë‚U?î;tüfNöžÕ£êf)o¦ñNÖ­—lÙ¦+‚ x»)sŒÿ9à«ßJãñý<±WW*N¶{»)3ï¼¢>÷Ëõ]ï½kPÁý,­eY›¹‡‰-2òR»ËðuÛ¤çéz>?ÃMn)Ÿ7¦^ÜÙÇ“ÓFmbBüøž l×î=f]‚íA½Xýùï´{åña¿¾ 33®ü;L{Ûvêú¸ÏÛèLr00ÂgТø½)'åì¼áíž-x³»X}ׯ{ïfö¯>lĤLm~ÆÅùÆÚî2ò²vTýµSEû{zVµäÔŠ,åM¦î|=öLïfÕ<<4ÏŠîÿ…íZÓžûÏ›q*¥Òzœ-V¿ÎøMk†U|û¹Öu•fÏ^¯û®m;«?|iq¯¶íˆ™¾yáÍ¥C<Õ±ÍûæwýºÐq‰Õwm¼Î³û4ky»O~Ñ3¾a¤& rëÓ —Ø®bÌ?+‚WH³ ÜÇø³kâj NXuò|ÿX ÑÜw*B°5ûõ¿^Xv€t d,Pæ9¼†Íåïþú,9›䃌Ê<¾˜ðãÎ{òEÆ@¾ÈXàþ»üËäh?‚·£ð£(Òq[|äÓOÅL2¸ÿ¦ ?qÏ•‚·£pƒ \c6›™<d,pÿýzkx­ ’kŸÏÚ]‹q#䀌î¿tƒÉ‹ý1Žð\¡P(â?R%¨‚§oHÇAï¥î\cÖ-£_lˆFíåß²×ÄËZc¡íX>À¶»ë@â>…BñóÌá5£ÕžAgÇ[ Sÿ^Ó»]Ã`_/•»wµFqsÖtØ~¡–+Š£_MiT5L¥RG×n·æxºõ©ý_MoV=Ì]íýHë>Û®åYë¿Öµž‡Ú§ãØÕšWñð è;;A"býDñÎ+ ·cY™?Å5.ö€”ÄÄD3 ˆAˆí=ó|Zî­ô‹<[ëåm–ò}o?ýÄ['®fér®/Ó°jŸŸœlÍùrAbºNúçRš6ûâ˜ÖÑ–ÂF¾êYögäé ùÙÇþØ0¦{=gÚwØx~œ¾žmÐfm™ßÝ7j¤õ©æÞùëôu½.wÛ¢^¿c­¿àŸ”ÔãKA˜èZÚ©åžþí%â ÝÏb‰ í”tý"Å¿¤ç•ÃíXVæÆ%«þzo’±€ AØšžoYÎOߦömjYnåç±;SkYÖçr÷~ÄÉÖœ/á;/aõ¨ÆcÐÔ›vî»p5Uor¶}‡ÊÑY–M† ¥›OÁ:&C†›{°µ~ŽÑd2æÞYȳ¬"é~K|îטּÇ~–μ*¸ËÊüq†óã’gÿ8xo’±€ AÐZ€LZ…Âݲè®TØ]dâdkΗ;,L?ñóèº7­ÿH —ÊÝ7zìòcδ_hãÖ‡7ö}ùt«:þÞj»q 6_Ke» é~K|îטּÇ~–ô¼ÛŽeeþˆqm\òé?€BÞ›d,àA¶Y? ÏØ®®ÐвÜÊß'Ykt¡5çË 9|4ÞÚ÷Ól•g¬m™R¡0¹ÔëÃG5SÖo6› Ú$±5ëBáqpÔÏb‰Ïý÷ØÏâWÞnÊlö¼Øv,{óç¿\—|ú@wÞ€‹†¿¼àRF¾63iáˆaUûβÎS/nÈìãÉéF£61!~|϶«”ÜúÕî2|ݶéyz£^§ÏÏpS‡Û>[×Ç}ÞîDÓ=´Ÿf0…†…ùy»g]=9d÷Bë‹ÅAºŸ(Þy5 Ü{̺“Û±¬ÌŸ¢¶_\ó­xûÏ{EÆ9p ›ß1Rã¡ö êðÂ;7tw>O5é¾|gðÑnnêJõÚÏý.Án-Á¹Ó&vûjéÊf³ùèÆÅÝ[ÖöqWº{Ô{¬×× ©ÿyv鍨_ËAR¡ãrøðâÆ9M«…»)”Á•¼óõQ¡°Ï˜Åâ ÝO'{Uhù}œ÷ØÏâW© Ÿ6Œ °ÝîbÛ±¬Ì1®ë¾ôßpëŒ ^!qìEç)cccÉÜ H,¦‡ûm¹m…{ï'óêwvM\Á «Nžï«!€“T„ tÌ~ý¯– ]Š„ŒÊ‡×ÐËù£}±¾É­Ïe¥ŸåmþÈÊgÉÙ(*2pE™>>ãà’MÃüP†ð]a䋌€|‘±Àƒ£à Š; Œ"c€‡Yä‡\ˆ  ì"c _d,䋌\¡P(â?R%¨‚§oHÇAï¥î^yµÿ«éͪ‡¹«½iÝgÛµ¼B2ë–¿Ñ/6D£öòoÙkâe­ÑÚþk]ëy¨}:Ž]= y¯€¾³$Úç~ÀƒŠŒ\4â`õgS2.컲ÍèÖò±ñú›ŽÞÊM]øœ©O»YÒìŸÒvÚ‘Ø_Ž&禞µ³Ý€Ö§¢gl½rxÞo 4Zú×µ殟ùªDûܯxP)ccc ‰B¡ØšžßÁßCmÆvM̛ڬ}vuÌÆLw¯jÝ ‰vZû{μ”ÕJ£Ápë´wp]îqKû9F“·pKéæ“c4y ù*uˆÑ#ݾB¡p˜·ˆ• œcµöó°,xøµÒç²,§î_Õ½uÝ…B¡Tù› 7¥Ù—­kíça¹ ËÝ»†áÖ¿Ö§|” …Òû΂—ɘëBû”ud,à¢=™ZË‚6ëwŸ:–ånqÃ꿲ðÌõ,³ÙlÐ&zf£™Æ;Yk4ßa2™¤ëµ} o7eŽ‘s,€2‰Œ\4üå—2òµ™I G «Ú÷öý$iShX˜Ÿ·{ÖÕ“óGv·[¥àÍñóÆÔ‹2ûxrºÑ¨MLˆß³ô‹J·/f@¸÷˜u &¶  "c}R÷x‹JþšÈú›Uý~_ÜÞRÿÍŒ/_jë¥r¯Ú¢_V‡…6ÒdêÎ×cÏônVÍÃCÓað¬èþ_H×kßš 9üưé?ÏýçÍ8•RÉ—‰Êî¼Wp/;¥ƒs,䋌€|‘±€+¸$ €ÒAÆ@¾ÈXÈ 9ºüËäh?¾Š±£iCçOÜs…{E 9ú!õÖðZAı£tƒÉ‹ý c 7 …ÂrûŠuÁö©Ÿg¯¨ö 8;ÞRhÒ%¿ù\»`µÚ'¸]¿IWt&kå׺ÖóPût»z@ó*^}g'o?>Lý{Mïv ƒ}½TîÞÕÅÍYwðv ³nùýbC4j/ÿ–½&^Ö¥Ç%ÚNû@YGÆ@^Ìf³åöë‚­Wþ ^·71'õ߯¡–’̓Û~c윜•‘t°³amÛ![¬•£gl½rxÞo 4Zú×µ殟ùj)ô¿s‡!M'|š˜’¥ÍIYÿɘ¤µC,åû§´v$ö—£É¹©§‡Díl7`£ô¸ÄÚ ¼Q$&&ÆÆÆ²¢P( ¦+ …âLm Ú¶°¯ÇÜËYíý=AÐfl×DÿŸ6;ÁR9Çhòn)Ý|rŒ&o!_¥1rJ¨‡Ö‡-ü<ž0ç™¶Í©Q52,HuçTGkÏ™—²ZiÔ‚ nöî¡Ë=.1.±vŠÚÊ:α(KìëA8–«oåçaYöðk¥Ï=f}ÊG©P(½ï,x™Œ¹¥ÐÃM}W!qûÔqƒƆ{ûÅŒûâvZ²/[×ÚÏÃr©›»w í¥Ç%Öå çXÈ‘Ø9–‚…õ}=>JÊjçç!‚6s‡&j‚6ûmå‚ ÅÂGåvEkðsS‚ Ï=¤®ÐоqSþþŸ?iÙw©þV¢ ­*¬»žUQ­tr°bí¸ÞÊ&α” oA`1ý©èa#&ejó3./1,¦ÛôÒyÝ>ƒÅçèM9)gç h-¯ÝeøºmÒóôF½NŸŸá¦·”ÏS/nÈìãÉéF£61!~|ÏÒ틵SÔþ°”ue5c1äžž6¼gµˆ•ʳj£Nó8ü`o§{ü¬”#<ÀžX±£»aC݈ ¾ëm0ôØþEçÒyÝé›Þ\:$ÀSÛ¼o~ׯ­åkGÕ_;eP´¿§W`åQKN­Ø¹ÁRÞdêÎ×cÏônVÍÃCÓað¬èþ_H·/ÖNQû#‚1ÿ¬ ^!qÌ@YT&¯ 3é®Ñ Š—Ú³rýN?žÏ¶Ô̹°åÅÎM‚}=ÕÞïûù–¥0 ±=´fZó=Tî¡Uêûh³ÃuÅê\Þþy·–µ4žîÞšæú/ûõ„pç‹%•žØÊ¤ʛٯÿõ²?IWeT™ÌX-þ÷eå¯Åz¹{„T®;~Q²ÑÑ ËY…aï›·ñŸì¬äùÏè_l=ð…·ŽÎÙx8;ûú¢çƒ;βÔúhï–_JËËM=7ohµaOÔ*…Q8|Ñä­»,º6wÃÁ\Ý­;¾¬°cÄóßž·[Q¬NêÁ9M†ÇYºåfžöÆ…Ãovõ~©s-k,?mqqóãLz ¼ù,9{å€ÄPF•É«ÂBÕªðG_^úùä¦Õ‚RNí}«_ÏKÏnÝöF}ÃS(~J½õt§ &ÝU7Šß§æõ òÁ¨KVûÔ1êÓAR»­³ãЭG/ëMæœÔ ÿû _P­‰v+ŠÕûõøùǹ¤7™so^þnc,«TõRý~=/óܵOM&=Ê2™±7˜ü넘‰O5ôr÷ªÓq˜[%ñ¯9¾í^°ùñD‰‡G6,Ú?gh”¿§§ÔðO|¿÷ÓR…Ãh7{÷û §õkå«V…Uo±ìpøö¿fÚõV¬NØ£Sþœ×jö‹í|Õªà*ì©ÿ×Ëk}ñZ^±aõ_~qæ×Lz”!eòª0åD™<Ç÷B¡ˆÿ`H•  ž¾!½—f¸s«˜Y·ü~±!µ—Ë^/k¶«üî‚ ˜™*H£!G¢bì?÷ ¸B¡PhMfµ%10ë”nL& j7¥ÞôŸoQ7™î^ÐUð{Æ3þÝøÎÌåûŽž>{êt¶*bäüÍó×Á]©Ì5š ¶/ö-íbícÿ¸/¸* \´'SkYÐfýáîSDzÜLã¬5ZàµÐÃ}ÿš]¬úqß¡ã7s²÷¬½hT7Ky-÷?²lÛ¯åZ;%ÝJ ¸høË .eäk3“ŽVµï,Ká¼1õâ†Ì>žœn4jâÇ÷l ÝHí.Ã×m;ž§7êuúü 7u¸¥|úSÑÃF,LÊÔæg\^8bXL·é®µS¼ýW(Öt±€‹>©{¼E%Mdýͪ~¿/no)l2uçë±gz7«æá¡é0xVtÿ/¤Y;ªþÚ)ƒ¢ý=½+ZrjÅÎ –ò'VìènØP7¢‚oÅz =¶ÑÙµvбÿÆü³‚ x…ı饉ûXÀoJy°ûvM\Á «Nžï«aJŠœ1ûõ¿^Xv€tPÊÈXNù,9› J÷±€+Êô%a@ÿå ù"c _d, _üø d, _Üm ÜœK@  ù"cW(Šø†T ªàéÒqÐ{i†»—oíÿjz³êaîjïGZ÷Ùv-Ïv•Ÿg¯¨ö 8;ÞZh9Á¢¸Ã¶ÜÁ¹³nùýbC4j/ÿ–½&^Ö-Å©¯éÝ®a°¯—ÊÝ»Z£¸9ë{ÿ¸/ÈXÀE#Vßq6%ãòÁ¹+ÛŒÞa-¯_°éè­ÜÔ…Ï™ú´›e»Ê+¯Û›˜“zÈoãPK‰Ùl¶Ü¬b¾Ã®ÜÎþ)m§‰ýåhrnêé!Q;Û Øh)ïÜaHÓ Ÿ&¦disRÖ2&ií’è?¥O‘˜˜K  H ÅÖôüþ‚ h3¶kbÞÔfí³«c6fº{U3ènXWù#SÛB£vØšÃü¤`ykÏ™—²ZiÔ‚ nöî¡Ë=.B ?χ'Ìy¦m³GjT R)Š¿ÿÜœcµöó°,xøµÒç²,§î_Õ½uÝ…B¡Tù› 7mWq˜®ɾl]k?ËcîÞ5 ·þµ”oúë» ‰Û§ŽÔ06ÜÛ/fÜÇK¢ÿ”>2pÑžL­eA›õ‡»OËr·¸aõ_Yxæz–Ùl6h“œüzb¥Báä×7Óx'kÖKÈL&“¥Ü¿f׫~ÜwèøÍœì=«G/Õ­4û@É!c yÁ¥Œ|mfÒÂêö½}¿GšÁæçížuõäü‘Ýlª®û¼Ý‰&'jÎS/nÈìãÉéF£61!~|Ï–òÚ]†¯Ûv =OoÔëôùnêðÒì?%‡Œ\ôIÝã-*ùk"ëoVõû}q{Kaü73¾|©­—ʽj‹~YV8ÙÔê_ZÜ«J©´û®0Û‹&Sw¾{¦w³jšƒgE÷ÿÂR¾vTýµSEû{zVµäÔŠJ³ÿ”î¼WˆÝ+Oÿ(^œc _d,䋌\QÖ/©â’0@YAÆ@¾ÈXÈ €²Áö~qߣ]Î7ñ€ÒDưÇ].Ä䃌|´xð±/22òt°÷ú›ù¶%ù7ôînY>úÕ”FUÃT*utívkާ߮aÖ-£_lˆFíåß²×ÄËZ£u]…BñóÌá5£ÕžAgÇZ¿H EüCªUðô é8è½4ÃÝË„ö5½Yõ0wµ÷#­ûl»–Wìí8—B¡°œ`QÜa)åûú±´ÛC7dTññ=š«—îíêV&ÃÍwu õõ¬TeðŒ_‹}ÓÛ½bQo±>Lý{Mïv ƒ}½TîÞÕÅÍYwÐÅy"³ø@yFÆ@F^ë³t_ŠmÉõ?—Vêùªe¹ÿ&ïµ{µy7—½ä?²ódKáþ)m§‰ýåhrnêé!Q;Û Øh»ú+¯Û›˜“zÈoãPgêɈƒÕwœMɸ|°CîÊ6£wXËÇÆël:z+7uás¦>íf•D;Çe6›-7W˜ï¸Ò9-WX;˜ûÇçT¿Ž»Dgl×µµ}dë/s;¸œ‘rf{µ# ”‘R˜B; i:áÓÄ”,mNÊúOÆ$­âÚ<)éøŠ 11Ñ ò~úõèÇ6›ÍÿkÙö;³Ùüãc‘“Φ›ÍfAåè,ÕL† ¥›e¹•ŸÇîL­eYŸwÊÝûkk‚ üqç)+‰úE"ÂÖô|Ër~ú6µoÓ‚uL† 7÷àboÇḬOÙ•ò/†yúÉÑ™ÍæÏ›†=·=ÙÉÑÙ•4¬ Þv·Ÿ¿¬pì,´}±új<M]°iç¾ WSõ&§¶»D<å(ω‰‰±±±dnäÀlÊ­Ùçô•ò ºªˆIË:Ñ9¢ÆÏWNz+ …ÂlóÙ¶õ¡ÚM©7ý§Üd2ÙÕ±%Q¿H …ÖdV[N˜uJ· &“N„Ôý«†NüpW©Œ<3í»ÐŽÃqI<õS·ÊÆmÚõ’GHPÛӃݕΌήµR™c4Ýé§V¡ô4ë÷e‰mߢÖÏøwã;3—ï;zúì©ÓÙªˆ‘ó7Ï\Ë…y"·ø@yÆUadD¡ô™s0þøŒ´ÊӦĤ|pì§«NñVJ]MÔLã¬5Z?†)4ý(j} {2µ–mÖî>u,ËÝâ†Õeá™ëYf³Ù Mræ°µ¸ÚA©P¬×þãQ Ó&]Ú<Æ·ÍÇΤ+5¨àþGÖ~fî)|Sñª0o7e¦ñvßõ¹‡ m_¬¾Í® Vý¸ïÐñ›9Ù{V^4ª[±o÷b‰Àyd,ä¥ÝÔ¦#Ç}ÖæÃ>ÏÎm³hìØfÓÚHן7¦^ÜÙÇ“ÓFmbBüøž Š·¾„á//¸”‘¯ÍLZ8bXÕ¾·ï3I3˜BÃÂü¼Ý³®žœ?²»Ý*Ü]hGL]÷y»íÆ5U^}ZùÛÓC¶=ùA—;³õa#&ejó3.Î6¼ÐúOëKÔá3hQ|ŽÞ”“rvÞð…ÆM¬~í.Ã×m;ž§7êuúü 7ux±o÷b‰ ¸€¬èr©ÕA—µCþ¥ µÇñ\½¥\»ÏÁ¤ûòÁGº¹©+Õk?÷»ul‰×/A6¿ÿb¤ÆCíÔá…wnèn~q㜦ÕÂÝÊàÊ ÞùúhÁn,)j;‚ø=G—ŽŠ ñµÜÛ–Ÿüì17÷›z£3ã²u7lú›ï êâ£öô‹<3^(îû4ÒŽ~Ù¦f¤JéR¥ÑÔÿ+4nbõn\ܽemw¥»w@½Çz}êâ<‘Y| <ã>p… 7?”h;Ò’·?ÓðՎ׾Ć”9\8³!룑ÛZÏ|‚PÊ"!€››: r‹Á‡;DZKÞoæ»­ˆÈ ¸¢¸Ž_Ká8Ød2–þ‹²qÅ…«ÂÈ ù"cð@‘þ™B”txËyü‰”2€³¸Áƒø@é#c _d,䋌€ììÿÿöî=ΦªàøÚç6—3WseŒÌDrË­(„1I…ˆBÑ ·BEêé¢B‘„®Å/=JåV„<¨¹6ø‰f0Æeî×3sn¿?Ç4sΞ3cfÚsæó~õÇÙk¯½öZßµLû{ö>笞ݩi˜VçÝâÞ!Û/Ø %IŠ_ýz‡[Ã4]d«˜¯ŽgÚÊ-¦ô™q½C}=}‚¢F½ýsuR’¤­sGGùxú†ôŽ›•aºþ8µxùKâCüt^]M=_d®òv$IÚ0g\ó†õtžAOÎÛj+Lûã«GbÚûzi´ÞM:ôš¿öàµø§ü{hL°^§ÓÇ {ùb±E>ž2ý´)U^Ýñ/uÆŠ~Pľé,>³Òâu Å™²Õ¸xs|a~Ú’¡–!1ïØË‡oöþú÷Ä¢‚ôÏž ˜ØçU[ᎉ÷®Ì=p>ëÊéML¨É~N8Øtg•¬ócó¿è6i§­pÿë=Þü3zS|J~Ú©Ñ ±±:Úyæ·àµ¿'æ¥öß8ÆVÒ'vtÇç?N¼’S”wå‡&_øz´­|˨ߘûJÉɺp°é룒§3V«Õá‡4*É‘˜,gñ©hœ«;>­ HS–Zl{-„8œWl/W©õ¶×í}tÛ3 ¶×†ÌmâúµcuBürã¼Ûu¾m¯»ú{ìÎ.²½6ü¥õnQåí!ö^ßewŸGÜ‹7ÿº/)5Íh¹QÞöoñÙ®ói'Ïr{[ª¤ºã_ªÁrÛwVßY|*g¥Åê)111::šÌ €B¤í_5fê»»ý•UP,„$Éb±Ø^XK¼‡mßÔ©Tyf‹Îö6½µHRyZkäûš$I*²X¯Ÿ·X¥ö±XŠ…:µÊhù[?mý¯ÂvJ…Â&ëÿ6Θ³|_ü©„¿NåjêO\´eѨ–B­J•#>7ÚwÏrG]ªZuÇ¿¢ýtVßY|*g¥Åêž  ,ýzmûÌ’Ó—s¬V«©èB¹—wí|´{sŠl¯‹²÷ÔdW÷d_?oÎ^­¾µíu'?ï”"³ým!ùt¥ Û hþàâUë÷>žž—»çËIKŸîg+o©/Ÿœ½Z}˪ BEã_ѧ¼ժlóµ5`Ì?\nûÎê;‹O%æ«Zã(‹Œ€²d˜,¡aaþÞڜԓ‹&(·þœáMÇNXr!»È•¼h츚ìê¸ñ‹Ïeв/,™0öÖÇ®}Þfáä6½FÏ;ž’i6%ÚúÜÀv%qx^‰vÊjÕwÜÚí2 Œfc±Ñ¥Ö…ÛÊg?y=>ç—LÛ¨ßìª BEãïðv¿Lý'ëëã–nÍ3Zò®$,÷d©½eã鬾³øT4ÎÕ€|Ž€¢$oœß±I¸ZR7n7cM¼(ñ™æ’Õì›cú¬¸Þ!z§ä¨9[E ~ŽeË[##ü½¥xåŒQ·GÔS«u·´é¹`Ý¡RG•HEÛq8ÆøËti¥×ª´ÞmºZs(ÍVn2œ›6¸[ —FãØmð ç &ùxÊŒ·${yuÇ?#~e·æ•:$ªÃÿs¬l·K•8«ï,>³ÒâuŸc€Ê¨Ä‡ªµÜO…P. !Ø8ü<·€ˆü³ÈX 2ªê:UQ×»\|P ž  \d,”‹Œ€[‘ÿ9BžÈ•_Q¬VGÞéÚ0ö½jjüü¦W#ý=ÊŽîoÍ[Ø3¢ë;GY'Ê—Âç€ ßn À­ÔØ—Wí‰þ©ï8¶¯´¼uaòÕ¾AžÕÑþ˜ú>­¶&?Û:¨.¯ICúÆà[¦Í<¢½Ùw Ýu¸åw|Wá¼à_Ô])¿ŒÏn½ š.C…ߥŽkYéJ­xoÞ3èÁ-³ÆïHaT7E­7˜w@9ÈX îúuÆo÷Î{¨úÚÏ4Y¼øÿŒÍëº÷µ]¬æ@åðÊb)Nù÷И`½N§ŽöòÅb‹}—$IæŒkÞ°žÎ3èÉy[¯Õ7¥ÏŒëêëé5êíŸo4d-^þÒ°è?W@—ASÏ™åÛ©„­sGGùxú†ôzòÍ4Óµ~Žkèûⱌk]0eEé}ãóU‡þÁÞ?¤JV3¤¯÷Péñ®HÈ~ªu½’%’$ÙÇÕ;nV†ÉZn<²8¡Ô§d>·à°Ÿi|õHLû`_/Ö»I‡^ó×tØ~¹o®K’¿úõ·†i4ºÈV1_Ï´ïÚ¿zv§¦aZw‹{‡l¿T`¯?ýÁ6:}ï)_ޏ;ÊÃ+ð±y‡dâଟ6AwŒÍ>½¢Æþ½Ô¢u"Ãá¼Ô–õPÝóÔ9‰‰‰VPŒÃ›Dž›œY˜Ÿ‘4wpTÓÇ7Ùw !=øòÑsE¹É“ï´n{ªùµúégÞz8Ja+ß÷Ú=‘÷¿r"5§8ïòòÉíoò½|;%„ˆ~dÎÙŒüÂÌ乃£›Ùf+OXs_ý®ŸÛ^§î}2¸Íû.¶æJöŒnÖgSrÉjI?ö¾ý©=•¯^­Ê3[dÆÕrüörãY¡qÉ”;ìg_Ý;?îÏ*(6ríýqò€6®´ï°ñÖÃæžºœk*ÊùiÑ߆í»î1ãO]6ço_:¨Þí3ìõ½’vü#!Ģ×2þZîÐS&òý´˜óTjŸ›ÿ×Q§Ö‰Ãy©-ë¡jç eië£Ûži°½6dn×ù´³ïBìÍ.*U¿ýßêo³_²tõ÷Ø}½²±à/­w ùv*JñËßúÙÞöÚdHóôÿ3¯Øjµ~Ú1lèŽ[s%™§^Œü׫Õú?]êGôXgµZ×wx9!³ÒãõQ«rM¹qùv,7ž—L¹Ã~Þãç÷ÆâÍ¿îKJM3Z\mßaã‡óŠm¯-¦,•Z_¶ŽÅ”¥ÖÛëç™-sþõ¶CœÅA¾ŸSN5e,î½NÊÎKmYU;ïÈX(‹F’Šì"–"IÒÚw9¼Ñþ­¾Á^G«’J="ßNE !œõsýC·tY|ÜT˜èÝðj±ÙÅÖ\‰ƒÅœ×4¼¯Õbhª×ûø4/¶X{†Ý–o¶Tz¼=<·d\—Lû—L¹ÃÂÌ&=1 cÛõ¼4ZßÈ)˹Ò~¹Û7¯î[Ù¿këo]©qÙ+”zá,òý,ÌØì[%«®Ž¬góR[ÖCÕÎ;2ÊÒÆG·#ëú{·Y;t>mí»^Žtô-Q?ó—÷Xô)E޳…ªÊXn¼·µÃþ³ÕjÍ>3Ï+¨ÿ™ïú6êó­‹­y—yÛYVv û9~FPËwç·šùçúúWßÌx¿¼3lЯ)rãº~ïH¦}ù(¹^^μ˜ ÷}?Oã]²L%I–JõľyŸÇë_ﺚk°Z­¦¢ Î.Lí/ʃ£~^Ø10쮯n~Õ¹ë:);.góR»ÖCUÍ;>y@Yf?9vÂ’ ÙE†¬óK&ŒmÔo¶|ý9Û^¯Ÿ¼hì8{ùÂÉmzžw<%Ól.J<´õ¹íª¼«ãÆ/>—e(ʾ°dÂØ¦Ïµ—ûE½Ð_µ­ÿèíÌíæbS#½'¯=dq!1otœøì'ÝÞòè‚nK§Léôf·›o÷Ù]÷Lß 3®[{Ç•ö«ïG[õ·vûÌ£ÙXl4d©uá%÷Þ¡×.Üh¹‰ö3L–а0omNêÉE”[ßYäûùÃô=]f9X ›»®“²ãr6/µe=ÈÏ;€ ã E1ÎMÜ-ÐK£ñ ì6ø…s“}—pô°Å˜>+®wˆ^çé9jÎÖu,Å+gŒº=¢žZ­»¥MÏëÉ·SQBˆ­sFÝRÏ[§é7+ýïÏÔŸü¤»Z’ntõÍæ´C·oh»˜“CqÞa.è|‘Éd8¤ó8žo¼™ñš‹¯6×{ÿ˜VX²ò–·FFøyèôA±O̸ñT›óö­×ûÏa”Ê–”$_ÙjµÆo\6 K+½V¥õlÓ}КCiÛûÑÓÑ!¾%ã&3_7“7ÎïØ$\-©‚·›±&^”÷žº³8Èô³àÊ÷ÞúfWÊ<h*<-„ð éåúªs×uRv\Îæ¥¶¬™yP üæ=T½”ƒÛ¿ÐûòÁ§”ßÕ£óîí»åá”ÏÛ6Ýò×ÇÿY zD¬¿ÓžÛ–*OøªW³Q‡V<;<ÚuRwæ@%±@³šr^hÕ8iñŸëz7¬uçJ´ÆŒð-žsà‹ÍjcçY'j’†@ÕRëwu$6‚PÔ0‡Ÿ‘Pì…õ')¹Lë€+ÈX ŠY,æÚÛùZ}=ÇÅ(¡f=n‰ï  \d,”‹Œ€r‘±P.2ÊEÆ@¹ÈX( å"c \d,”‹Œ€r‘±P.2ÊEÆ@¹ÈX( å"c \d,”‹Œ€r‘±P.2ÊEÆ@¹ÈX( å"c \d,”‹Œ€r‘±P.2ÊEÆ@¹ÈX( å"c \d,”‹Œ€ri–®Ü‘FhT“‘=ƒ]¬é8cé{W°û@­ÅSa”‹Œ€r‘±P.2ÊEÆR;„úI¡~Rm?QÉÆklDLB¦ VÏ>øÕâŒ%~ÍsêJÆu%Çê'*Ùxˆ)Pȸ~ꤟ~ Ó ?:™e]9°SdD ®m§˜ï²åÛ· Äé!«^ŽmèÑ¡kïoe8‹†+£f þÙ)9‹³ÊŸ:óèªA7 Ôµ¸£ÃÜÕl…;'¼v×ÒõƒînªÓxDu|lÅÒ.ó&þÄ_jê²Úš±lû}][ù:¶'O¦¾ulæ7GϦ¤Ì~ØøÌ}O>=3þoŽœ½xùG¥)ýß±Õ|.ö‘Ö“–9W”tfæˆ&S¶¬!غ÷Ü'YK¶%Ûÿ•­0uçÔ¡Ÿ\š¹ö`RzáÞÍ+õÿ0qýÙRÊÔé3öõí>9}áH¿'ú} 3:ùMšsúíõÇÎ]N_8ÂsúÃoÛ˶oˆíäKWç ÕØ¹¸}òàù'g|}0)-oç/í|z°ÃP¸2j¦àŸ™³8`¹§5yû³Ë÷œMËÛºúíoǾ¶3EñÙá«{6°× ™švx)©¨Ë¤ÄÄÄèèèR¥WkÉS¡~’üñ¡~Òª¤Â>õ<…–âÔðà+’ ¨ç%„0§D„·¾”‘!„h¤^¼ëü}­Ô|ÿ¿=o¸·DêõZ ¿¿]‰ ð´móÿhÖá«3'ß/9X™:7XMáÁa—ÒÓNþD_$ôµEÉÑàÎK™¥»^¢ýR‡˜ Üe;䵿~›Î=`«–ñèÛ'Ú§¬b#b 0ÎÎâx€åzþÉÜ‘ |l›Ù 3ÛõË:sba£@ÕÉt³·êÚý.«%¿~Pè¥Ì|þXàfB|]­éþËÅl«Frºi;üÏÕoLçý‹ž-zxÈÀÇFvˆò¯±þ§æXÕ%JšÔSç˜,%먵A©éi%{ë¬Nþ…Ÿ¦Nxé—}'r F[¹ÌèäOT"JÖP?•­gíËÒ¤žú+¦@{Ä-†Ð¯²—Ë2a 5ÎÎâl€ò§¾mÕÙwš2„Þz)#³Q ê¯t³×Œ¥ ~P îÇõŒÅý¿kK#ÉmÚÜ1üŸþÌøþÃW#,§Ÿí9é“#5Ö=õß7%!2-Wr¬öÿÊ^5:«ój¯!¦ûfþïÙ\[¡üèäOT"J7^9k_æÒÁ–Ôƒàʨ™…Ló8 ü©~½q{½î`^±}Ó˜·_£¿ËíÿLü‹Ý¡ÏÄW>غÿ«o_}øŸêÄðpŸUr+Wç?©y '<¬÷BK¡üè\9QEÚwlh¸þóä/L[[éQ3ŠŸ‚Ò,÷Ô?¤Ø_ç&-ñ%„Ý>äÃ]©öòË»·{†?OÔed,Bê'½¿yn‘Ùj,8}ä¸. ó?Õ“ {¿ÿ˜ÿ?o´XóÓ“¾[8¬YÇ©.ÖRßç™EßešŒW¾Ÿÿˆüè\9Q)ÎÚ—1þƒ¸ŒÞ}"Åd1]>µçµ¡‹*=j¦@ÉSàp€åžú£¡Ïí;}Éd1]<¾mrÿÖ>/„ˆY6kÿ„AßïO(6“þøÏ¨ »§/»¿QÔeµ5c±ÿf¶ÌgÛ+”»¹kíÒCïiéÙ°á´e'Vlÿ¸f†P²?6aÝæm˜Ñ~þè®QAšm;¯ŽÿnÇœR•Õ™¹eµØôò åíSù&–E!ÉrñpWW©ÕêzO´Þanë=hÌòMGk ¥ Í‹Ål®òs]ýcYó÷{ [QµÍ®êy‹æþq•õ €»r‡Œ¥÷íQ+.¶6Zä®— ê#=µ¾lyX牿ý•j4¯&~mPðêůÜ}×4–EÝa½ÎáfMvãF,ÆŒK V¼u[ñïcl{çˆEæší̪£—.]Yµmš OÅÆ<+:/ýhLçªm¹óS/í,¦ÄÄž*ä½Ü“[d,óvï[3S¦Â™µq3NtÞ1¯WÙ]«6.¼ç¶pJÞtÌìuBˆìÓ+Ü &pÅ‹/¾XÍKèÜÒÏS«õôkÙùÁ¥›låö[oÜ©TjŸzÿzìùãùÆ wKÒø6è;xɆc‹ú6:øåsWœež+s¶™´iAבU©]e»äpeo1ÉDÀæðŠWÚF…zh=·éýÝYÇh_0<>ßxÿ{ÿ6Ð뎬z­]T¨N£‹hÞõÓ}W®|íÎ[Ã=´žQmï[—c«œwnÛSºG†økÔªRø^c~üð…ÇYÒ¸§ÄÄD«[° §l¹!sWc}½5ɹ2u¬V«ÅT°û‹ÑBˆ[XæÁͯŸÔÝ3´’t[Ü)Y…E¹©m.IÚ»SeBÌØrÜh.>ôí!Dý®–»Deöæ¦| „ð©?VæFP©Í6ýߺ[|ñÐgö]íRÉBW"Ðùåo² ÆS?¿ „ð~Ñáè¦Dø !~Í28ž>·4m=âåŸÿÌ*²í’4~BsñEV,nÉÍ3–˜i?§yO«rðÄ©š’Ƨ߿W !Î|;•e'l÷"œ~?Øô.>ßô{ïw~Ì6˜¬Uññý‚+k„Þ!ƒí´8ÿ9ùR†!;u÷ï !r?²í*Î?*„ð ÄŠÀ-Õõl üÊÁ³i‹ùÊÙC³FÜ/„húè2–lž_ý¬V’¦N[žš[T”›º|Úó’JûÜêçl{›yk…¿¥2N­Óé[ !úÔóBÌýå´ÅlØõùØJžÕjÎϺôÇŽu“û·ž¼é\Û¡ó¾u›mÏøF¾Bˆ{“ÌÅ9?¼=Ñ•Æä»TvŠ€ëâÆ7B¬N¾©·F<úæ±”l>ÀOkBx?`+ÏM^#„h6>Ž €{rƒï +;(ë$ìY÷ì4mPO#Iú€æwÆL_ðM¡™ïc¨sdÏ©MôíÔÜG§Vë|šßÝwé–û®ýïŽjâ+I’oHÔø%G¬Vëå½Kïn¦V©C·û÷'»K¶Y¡õ©Òx„DÜ; î㔬–¸î_wDjÕÚ ÈVÓ?=àJû2]r8„²í8‹@©šò4œl©×6ŒýL&ì.nJ’Ú?$²û€1?ŸÍµµóYlC­¾åÉ#+·ä>ß@É®üþA›ÏXößGßS…Íþ¾|B·‰ß/üõè¤{B 2n‰¯ñPBï™t2þÇÜU#ª¶Ù«rŒ?Iº€ã åâ å"c \d,”‹Œ€ri–®Ü‘FhT“‘=ƒ]¬É=ÊEÆ@¹?æú=¨>Üc \ÿï³\ó IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/README.TXT0000644000175000017500000000101007525303736022624 0ustar frankiefrankieALL the files in this directory are *generated*. Do not edit them. Instead, edit the files in /packages/acs-core-docs/www/xml/images/ and then run 'make' from /packages/acs-core-docs/www/xml It's done this way so that everything under /packages/acs-core-docs/www/xml/ is a self-contained version of the most up-to-date docs, able to regenerate the latest HTML and files. Bottom line, if you want to edit docs, make sure you're editing files underneath the 'xml' directory. -- Vinod Kurup (vinod@kurup.com) 2002-08-10 openacs-5.7.0/packages/acs-core-docs/www/images/tutorial-page-map.png0000644000175000017500000003332610010221046025313 0ustar frankiefrankie‰PNG  IHDRMCE\• pHYs  šœtIMEÔ'xᩉ IDATxÚíÝ{\TuâÿñÏ a@¼qD]³Öò‘¦¦id²h¥>T ôk˜º™«k©e7wÓo·ýÖ~£UÛµÖ õ¡¥¢¹þÒ]¬o™‰x3T’›\?¿?Ž{f†af^χ3ç|Î9Ÿóùœ9ïùœ93h¤”;åDÈ9È9È9È9mD£Ñh4Úä€W¦S§N={ö|ä‘GÍYÐÌ›®m* f4ãhá{€=E”²®®®  àرck×®íß¿bb¢“““9 ¶¼Lï)=Æs€C¾ªœ|}}§NúÍ7ßäååýíoSg%&&4ÈÕÕµÿþ F7ZF?)ãÅùó盿¶Ï>ûì7¿ùMçÎyä‘«W¯66 =~üxXX˜››[hhè©S§Ô¹[¶l¹ë®»\]] ¤O-® ”`/ _ÑGŽ6l˜òx÷îÝ£F:wî\uuuVVÖäÉ“7oÞ¬· 9eš,©W¥/¾ø¢¢¢"!!!22²±jÇÆÆ^¹r¥¼¼üå—_5j”2ý‹/¾2dÈÉ“'«ªªNž<9xðà={ö´¤2pÐ×MØqΕ••yxx(xà .¨³rssGŒ¡· 9eš,iTuuµZÃj««*,,tssS1âèÑ£j±”””‘#GZ¥2p(\ãZQJJŠÅËŽ7®åŸZ•••ùúú–•• !ÜÝÝoß¾­;W«Õ–––ê.hN…‰’ª‹/þþ÷¿ÿæ›o***Ô HF«][[«~ˆ¨[™¢¢¢Î;+Ó+**zôèQ^^nYeà°œiÀ¦âÍp%žêûï¿¿ûî»Õü¸}û¶›››é¤l²Œù%£££§OŸþÅ_téÒE˜¼IÒè2†å[ƒùÕ9ÀÊñfYJé®ÊâÀ«ªªzùå—çÍ›§< ;qâĨQ£L,bNóK¦§§óÍ7JüÔÔÔ4·BCC?>fÌåéwß}ÚÂjÃqéh¡díµ~å][[{íÚµÏ?ÿü¾ûî‹ŠŠª­­UæîÝ»744ôäÉ“ÕÕÕ¹¹¹«W¯~ðÁõ>î2Q¦k×®—.]úñÇ{ôèaº¤jذa«W¯.**ºyóæÊ•+;áèMWŸêÞ‡’––¦{Š•÷¡hiµïæt/âuïÞýá‡Þ²e‹^™;v <ØÙÙ¹[·nO>ùd~~¾î‚&ÊH)×­[çéééíí½~ýzÓ%UgΜ9r¤‹‹KïÞ½?úè#£ï­õ¶®÷tóæÍtqq8p îîXPp Ë/Q¶ä#´´i #"ç€%M{ÅŒ-Ô çŽ´È9 £…œ­%ŠÍV ç†q ìr`´ÄÀ°¯°ŸäP+i•dÈ9€#êr äˆ:€œ9¢ çBލÈ9ÀáCލÈ9À¬„`Gr°·Áœeƒ²; é@΄\ ;s€³Ë }\½90˜K±ï<àê%È9ÀÑCŽÈ9ÀžÙýÅ=®^‚œw0ç ÀÕKssƒ9†t@ÁßY…£‡€Ö{GÅx ä^b­Ë™Îï:öĘp„÷‘ŒçöŒœxÓ s€rØ w\±999Ø>—|aää6ï‰Ã^£Ó›Â]ˆ9ØIÂp\·„C0g Æ` ç;:ä`ŸQG ääЇt ær°ó¨@ÎÄr Ûs€Ds£:ä6‰ß·„Õh4¡µI)9ºÐ’ãGiI‡:È9Xó4ä°gá¶lgldÇÜëV:‡jR®[‚¡ÀK•œ`w”¿UÄÍ8 ç ç çØþÀ:È9öç@Î@ÎèP¸h r€ýã¢%È9È9 _99€Á@ΰµÈ9öŒÁÈ9v;˜#ä@ÎÙƒ1cÆÐ¯€aÈä\šF˜³Rký…{Ýíº»»‡……%$$4ùkjjÚ²’@GÁ`ŽÉ¹±ÊßV× •6εuuuÅÅÅß~ûíË/¿œ››ûÆo˜XêÛo¿¥_½Á!ÆsæîHëøñãaaannn¡¡¡§NÒÍB¥ÀüùóÕÇßÿ}XX˜‹‹‹î(íÌ™3BˆÐÐPÓƒE''§îÝ»Oš4iÏž=ëׯW&nٲ宻îruu4hPbb¢nÅ,¨$`Ç!sfÑÍ!%ðþö·¿%%%?þøã‹-Ò%¥”RþýïW§|öÙg‡þ÷¿ÿ-„¨©©0`ÀÉ“',„8qℯ¯ïO?ýd~ÖîÚµëí·ßÞ¾}{YYÙ¶mÛÖ­[—””¤›ÄÍ­$`Ç!Ç`-99999Yc4ctç^¸pAy\XXèææ¦;ËpU—/_Ö²qãÆ'Ÿ|Ry|èСûï¿¿±:(×- ¿üò˰°°•+WJ)GŒqôèQµXJJÊÈ‘# ·Þ¬J¢%hO[kçäÿàèBÛ7©M{šäääÆÞîé}>gø´¶¶ÖÉÉÉp®ÑöêêêtG„UUULNNîׯ_|||HHÈ /¼`bÙ¹sçAƒÍŸ?Ñ¢EÊm)EEE;wVæVTTôèÑ£¼¼Ü°&æW-A{ÚT;ÛÙHŽ£«Ã5©M}*ìl~QÃFQó£¹—=…®®®K–,y÷Ýwßÿý]»v™¸yÄhg~˜×ØÇ{ͪ$ÀåJÀδg,X° ))içÎ!!!ÍZ644ôøñãêÓï¾û.44”îìpø²#!ØVΙù½‚®]»fee½¹õ~þùçŸ}öÙ´´´êêêS§N-^¼xÅŠÍZƒ™•„ÞU[WWgÝcÏ„´´´Q£F¹¹¹™ÿMÐÖxur6{46·@×–.³˜³éfm¬qÕ¹ÊEE½§+V¬ íÔ©Ó›o¾i8W׳Ï>ûúë¯7–s&œ:ujiiiTTTNNN¿~ý^yå•Ç\o‘fUm@íÕ±cÇÚlë³gÏþóŸÿÖ¶øÓï–lîääT[[Ûzg®¶¹WÂèV:î0ÎÌš·RÛ6¹ZÛ¹ÿÅê5q¨ûPÚùO>ùÄ‚‹–h—ó‘Õ¿q¬w]èÊ•+O<ñD—.]´Zíï~÷»¯¾úÊpd¯ˆ7ºÂ3gÎDFFzyyyyyEFFž>}ZïUíää¤Ñh–/_ÞXe®^½:eÊ//¯.]ºL›6íÆæ¯ßh Ïœ93iÒ$///OOω'ê¾¥3±¿–õK‡ÆYåÛ³gÏèÑ£ÝÜÜ|}}Ÿyæ™[·néÎ={öldd¤§§§··÷´iÓ~þùg½Å›,Ь͵ïÑ…Úë[BˆN:5ª  €ï²Ø¾d-ù:Ž0ø¦úxÔ¨Q eee×®]‹ŠŠ2QÒ¨ŒŒŒ>}úlÛ¶­¤¤äÖ­[[¶léÝ»wff¦ùkBLž<ùÈ‘#•••ùùùÑÑÑQQQ-Yfff@@À'Ÿ|rëÖ­’’’;v„„„¨_$5½¿M6`“=ÒáŽ+»c~ãlذ¡¬¬¬  àé§Ÿž;w®:ëÒ¥KÁÁÁJ÷)}1jÔ(ÝÕ6Y Y›k÷£‹ïÏ™ûý9Àðú’J캥îS77·ÂÂBOOO!Äõë×ýüüL|}ÓPLL̸qãâââÔ)ëׯOMMݲe‹ù©¾úê+õ£»œœœaÆݼyÓâõÏž={øðáÏ=÷œ:%11ñرc Mî¯ùa¯t0 .²•””«Ý7gΜ±cÇêvßÖ­[£££ÕÕ6Y Y›k÷£ËF$Ir¢%¯ õÈiyÎ;6((è7ÞèÛ·¯'øùù¥§§ûùù©SòóóÃÂÂòòòÌϹòòrwwwåimm­³³³ºˆë÷÷÷OKKó÷÷W§1ââÅ‹Mî/9§{€Yöa’îRþþþ§NÒí¾_ýµk×®æhî±Ý¾G9g$ç€?~| s.//oÅŠ_~ù¥ŸŸßc=¶jÕª®]»šŸs...·oßîÔ©“:¥¦¦ÆÝݽººÚüœ3üuŠëwqq1ü+Q;w®¨¨hrMT299¹5Nírã€é³m³ÞEåææ._¾üàÁƒ………jaÝ×dÿšÞ®é͵ûÑÕÂTî ‡ScœÉÁ*Zþ†©W¯^›7o¾qãÆÆO:¥|de¾ž={èN)((ðññ±ÖZ°~Ÿòòr½ ÔÓÅûë¯ÙqãÆ5w7gΜ˜––VSScø ½†ÝWVVÖ¬ÍÚ\»]Ðå,¸h‰–½ï7nœU®h4šÂÂÂîÝ»?øàƒÛ·o×½ cŽððð¤¤$ÝO8’’’ÂÃíÕ¬âĉÉÉÉ‘‘‘ê”ÔÔÔ œ;w®åûkÇ gÙ‚Ç?xð zaP ©}¡×}‡jVfm®Ý.4À„hù}qæß[%¿‹RñÌ3Ïܼy³´´ôwÞ=z´nI__ß~ø¡ººúÀþþþ†kÎÌÌ Úºu«r¿\bbbPPPsï·41¥ÉõÖðòåËC† IJJ*--­¨¨8pà@ïÞ½·mÛfÎþ¶ýmrírƒœ™wš³×cÇŽ]¸paNNNeeeVV–’êÜììì~ýúmß¾½´´´´´t÷îÝÊ/š_ Y›k÷£‹û-ì,gpXs–Ózï®ôžîÝ»w̘1;wöôô|üñÇúé'Ýe7oÞèääÔ·oßÏ?ÿÜèúÓÓÓ#""´Z­V«ˆˆHOO7Ütc/où†SL¬¿±fffNŸ>ÝÛÛÛÅÅeèС‰‰‰jyÓûëP9g•½þå—_f̘¡6õÎ;õºïܹs‘‘‘Z­Vù¶Ùùóç›[ Y›kߣ‹œkð½É_»@s®[½¬dSŸ9Û·Ö»}À–;‘¿ËÓáš´£þ]ð© t8üm69999€5p¿%¬`ܸqÜù €ñää䀜€œ€œ€œ€œ€œ€œsssssssrr0 Ñhh€—ª­q¦ËaRJFCÔµA;;ìÑEï[±%ê@"çÀ)]´¤=ãº%€œ€œ€œ€œ€œ€œsssssssrrrrrrrà8œi¶O£ÑÐ-'¥TZRJI΀ …œC—Û êªI¹n uµ¿ä€œ€œ€œ€œ€œ€œsssssssrrrrrrr@Î@Î@΀í3f @΀Ðh4FwJ]]^[«0½F΀¹¤”zSŽ;F³s`M))))))´È9¤]ÓΜ93iÒ$///OOω'¦§§ëÎ={öldd¤§§§··÷´iÓ~þùgݹz—1•Çšÿˆ7ºÅ={öŒ=ÚÍÍÍ××÷™gž¹uëVcuSÖsõêÕ)S¦xyyuéÒeÚ´i7nÜЫdd¤—————WddäéÓ§›¬é]9À~ÒîÒ¥K'Nœ9sfnnn~~~\\ÜÔ©Súé'enVVÖ¤I“æÎ›ŸŸÿË/¿DGGÏš5Kwq½Ë˜ÊSùëׯ7ºÑ)S¦Ì;·¨¨èüùóµµµÏ=÷\cÕSV¸páÂeË–fffº»»/^¼X-™™©Ô0///777&&&22òÒ¥K&êcz—Qÿ.Áð"5ÇŒ!ĸqãÚ~£†ôª¡Ñ4}¦š={öðáÃu“&11ñرc Bˆ9sæŒ;6..N»uëÖèèhÝÕêmÅœê*)) ¾yó¦‰!ÝW_}5aÂåiNNΰaÃÔò111ãÆÓ­áúõëSSS·lÙÒX}Lïr§~MëžüÛåp"çX9íH=KšsRö÷÷OKKó÷÷W§1ââÅ‹ÊÜS§Nùùù©sýõ×®]»Z1çš\D£Ñ”——»»»+OkkkÕò~~~éééº5ÌÏÏ ËËËklå¦wÙº›œ@Ô™u¢4'r\\\jjjô&vîܹ¢¢B™{ûöíN:™ˆ¥ææ\nnîòåË>>YYYêhIOÏž= tGKeee-¬üÌ™3GŽ™––Ö«W/'''Ѳ¯¸Ö°  ÀÇÇÇâ]6müøñŽ3Èá>6·$îĉ“““u§¤¦¦ÞsÏ=êܤ¤$ݹ‡ja=?¾fÍšÀÀ@%äÔ—eÂÃÃõj˜””nñ.£ž€v’ÜPcÅÌ9S]¾|yÈ!III¥¥¥èÝ»÷¶mÛ”¹ÙÙÙýúõÛ¾}{iiiiiéîÝ»CCCõV«÷Ô××÷‡~¨®®>pà€¿¿¿áÇŽ»p᜜œÊÊʬ¬,å54œ«;%333((hëÖ­%%%%%%‰‰‰AAA™™™&êcz—Ms¨“?9 ýsÎ*'åÌÌÌéÓ§{{{»¸¸ :411Qwî¹sç"##µZ­òU³óçÏë¾×7|ë¿yófe¬Ö·oßÏ?ÿÜps¿üòËŒ3ÔÍíܹÓÄàÁpý†SÒÓÓ#""´Z­V«ˆˆHOO×]ƒÑú˜ÞerNÁ}(l]kßO“òùääää䀜€œ€œ€œ€œ€œ€œsssssssrrrrr€æÑH)iã9h§÷ã @“’s8/ƒÆ4¶¿\·À©ÙAH)•–t¨3?9°g\·ssssssrr°–1cØ)äœÃÓhîü3_Zš5J¸¹5{ÁVÝ Cuu­¾ÝŠ Ñµ«xè!kö…iz;eÝöçw¯rÎ)?ÊÖ¬Ÿf›=[¼ð‚(-Úô®;Öê›Ø¹SŒ!.^—.Y­/Ú}§4û="¿oiûCºfu‘““¨­µ­÷þÍÝk7N,Y"¾ùF¸¸ˆµkÛaG¬»ãíÕŒã9´i`h4âêU1eŠðò]ºˆiÓÄú§B''¡ÑˆåËïL-†;‹ÙÙ *¶g=Z¸¹ __ñÌ3âÖ­›:`ããëŸêj²’&öÚ¨K—Ä… bòdñôÓâŸÿµµFZÒpÇ…'OŠ „V+ºtâ_ÿj° éÆ×Ý)£;®ìé¤IÂËKxzЉEzzƒõ7¶u3›Ñ°í¦éjvE¶éu‘ròdy䈬¬”ùù2:ZFE™*Ÿ‘!ûô‘Û¶É’yë–ܲEöî-33”Œ”?ü ++åþýõ‹ !gÏ–ÙÙ²¬Lþñrøp9k–ÌÊ’eeò“'ëotÃYV& äÓO˹sMUÉp¢9•4½×†V®”Ë—ßy“‹™»uËrÎp7MW°3|>×Á>ŸÓhDy¹pw¿ó´¶V8;ëÐ}êç'ÒÓ…Ÿ_ý”ü|&òòêËWU #Û½}[¸¹)ƒ~áä¤ÿÔÄcXgúÍ©¤é½Ö³w¯xóM‘šzçii© .4Ø„Ñ÷óçΉ=ݯf5¾áŽûû‹´4áï_?¥¸øÎÍ2ælÝt36VÃÝ4] ÀÞ΢ä\‡Ë¹&ÏkºO]\ÄíÛ¢S§ú)55ÂÝ]TW7qwƒéÕê>ÍÍË—‹ƒEaaýÄf圕4}SÆOˆ)SDllý”§Ÿƒ‰çŸob Î΢²²AMš*¦wÜÅEÔÔ诶sgQQaÉÖ-¨’9Õì ÷¡Ø¹ž=EAAƒ)ÂÇÇš›˜9SŠ´4QS#¤´äž@ëV2?_ìß/æÍ«¿kC£›6‰M›š^¶GQ\ÜŠÝáã#ÊËï´’úOM˶®{‹MY™ªsèHÂÃERRƒ)II"<Üš›8~\¬Y#…““¢~Ö^•üç?El¬þI\J¡Ñ4ýý¶qãDrrýÓsçÄ€Öl«‰¬_‘š*î¹Çò­wë&®\©úï[¡€½á#ÊwJ³ dfÊ  ¹u«,)‘%%21QéßÊhÁvuŸŽ+.”99²²Rfeɸ8ý¾¾ò‡duµ9999 ç ç ç ç ç ç çäääää䀜€œ€œ€œ€œ€œ€œsssssssrrrrrrr@Î@Î@Î@Î@Î@Î@ÎÈ9È9È9È9È9È99999999 ç ç ç ç ç ç çääääää䀜€œ€œ€œ€œ€œ€œssssX‡3M`E†F°WRJzߦºCið&ûÐp”X1áhLÇìbzŸ—l×-Ûîý>ì¸é}^w çìü%/69¥^œ¤÷m³_r@Î@Î@Î@Î@Ρ¹¸ W çÀùà€9‡vuöìÙþýû ¾ëÀ]o› ¤È9´ÈÁƒ}ôQÚ®@ε³œ={Vy¼yófåÁ™3g `Ù,õd7aÂÝwÍfýúõ}ûöuuu½ï¾ûÒÓÓ•é•••±±±Z­Ößßÿí·ßV+V[[»jÕ*___Y³f•””!-Z´iÓ&µÌ?þñE‹щ6ÛõF{üöíÛqqqÞÞÞÞÞÞñññ•••êq¢ÑhÔÆè`¨±bWê†ô6svkâĉGB\¹reñâÅåååBˆ#GŽDDDX6KQUU•ššúðÃëmë믿NMM-**š2eÊüù󕉯¼òÊ7._¾œžžž’’¢^»ví‰'~üñÇk×®¹»»¯X±BñþûïoÞ¼yÛ¶mBˆ­[·~úé§ï¿ÿ>h³]o´ÇW¯^›››™™™‘‘‘ýÊ+¯ˆÿ\N”Rª×†+ÖØq¥0Ü`$Z̰÷ìÙ%¥\·nÏ'Ÿ|"¥œ1cFRR’e³¤”)))#FŒÐÛ¢¢  @y\VVæìì¬< ÌÌÌTgdd¨åƒƒƒÏŸ?¯<ÎÏÏ÷óóS_»v-$$äùçŸ ¹ví}j~_ëMiƒ®7ÚãÊã .­^c€žÆŠ5v\>h÷~êš 5^c%%%}úô‘RŸëšõáèzõoƒxÄ{IØòx¼Áxr@Î@Î@Î`œi‚6ÆŸ,±Yܰs°BÂq2¥ƒ´%®[2b½s°ÆXÓh‡ˆ:.,ää6€ûP’››k—û ìZ@@½ rpÜ„ËÈȰלÓÝ5Òm‰ë–€­°×s´}9‡; ïë³;ý¸ç°ísŽözyä:^¨xÈ9´”9ß«;{ölÿþýÛ>¨Lׄ™RRRhs0åàÁƒ>ú(íä\Ç£;*zóÍ7ýüü´Zí¼yó*++usn„ Jáõë×÷íÛ×ÕÕõ¾ûîKOOW ܾ};..ÎÛÛÛÛÛ;>>^YVY³F£Q7Q[[»jÕ*___Y³f•””˜Y·ýë_ƒvuuíÛ·ïÆ®È94áèÑ£§OŸÎÎÎÎËË{õÕW•‰UUU©©©?ü°òô믿NMM-**š2eÊüù󕉫W¯ÎÍÍÍÌÌÌÈÈÈÎÎ~å•WÄ®:J)ÕËk×®=qâÄ?þxíÚ5ww÷+V˜Y±ÿú¯ÿzýõ×KJJŽ=züøq£+[Kp’²Ê€¬Éf4,£NÑ}™™9`À!DFFFxxøÏ?ÿ,„8räÈŠ+þïÿþO)SPPУG!Dyy¹··wuuµ"000%%å7¿ùââÅ‹áááW¯^5Ünß¾}80hÐ !ĵk׆šŸŸo¢¶êƒ>}ú<ÿüóO<ñDŸ>}šµãvÖ›&ú±%ê~K!ÄÀ­û:~?Œç:Œ~ýú)BBBÔR/Z*”BxxxÔÔÔ(¯]»¢<îß¿ÿµk׌®ÿ—_~¹û‹þþþׯ_WO¦¯@~þùç6lXŸ>}vïÞMO ç`‰œœõ¿¿¿Ñœ3ÊÏÏO]6;;ÛÏÏÏh±^½z]½zUþG]]2]ÒØúï¿ÿþ¤¤¤7nlذaáÂ…ôr–Xºté7®_¿þ‡?ü!&&FQTTtñâÅ‘#Gš^0**jÙ²eʲK–,yòÉ'•éݺu»pá‚Z,>>~Á‚YYY555§OŸž5k–™‹‰‰¹xñbUUU]]:ˆÔ[9lÇøñãMÌMKK‹ŠŠ2] çÐ*ÆŒ3xðà~ýúùúú¾öÚkBˆÃ‡?øàƒ...¦|ã7|||ú÷ï?`À€Þ½{ÿéOR¦¿ð ÷ß¿zAråÊ•>ø`xx¸‡‡GLLÌ´iÓ̬ؤI“{ì1­V»bÅŠ-[¶]9:Š 6,^¼899™¦€#àÃ[k4¢E÷¡˜)>>þî»ï^²d íl ½ÙQîC?~¼‰›8qâ—_~éìÜn?ãÎ}(`<‡zæ|84KUUU;†ÐÆ8Öm]VVU^^Þ|pòäÉššš¡C‡®Zµª{÷îBˆêêê¿üå/ÉÉÉ3gÎ4=ÔSÿONN®ªªúë_ÿª þÂÃÃ/^¬\$?~ü¢E‹vìØQPPpøðáñãÇÿáؾ}û7z÷î½téÒüüüO?ý4??¿oß¾«V­Ro÷ϰ܋/¾8}úô]»víÚµ+888!!A™¾iÓ¦âââmÛ¶mÚ´)--ÍÄ”HKNNVüãÿ(((øì³Ï¶lÙ’——·iÓ&µäÅ‹?úè£Ã‡+OOœ8ñÞ{ïíÛ·/<<|åÊ•ß~ûí»ï¾»oß¾1cƼóÎ;t È9VðñLJ……¹¹¹iµÚ¸¸¸'N(Ó:ôì³ÏvíÚµk×®Ï>û¬ù+üú믕»uëöÜsÏ:tHµpáBoooõéòåË}}}ÝÜÜf̘QQQ±téRåiTTU¶Œë–@Grîܹ 6dddܾ}[èüéÍ›7{õê¥qâÄ{ï½·oß¾ððð•+W~ûí·ï¾ûî¾}ûÆŒóÎ;ï¨ÅN:õñÇoݺµ°°ðã?ÖÛâ‹/¾8}úô]»víÚµ+888!!¡¹Õ0Óºuëbcc÷ïßÿ׿þõÂ… F·Òî§ZŽ@ZäÚÚþýû/^ìãããáá±`Á‚£Gª³–/_îëëëææ6cÆŒŠŠŠ¥K—*O£¢¢t8ñâÅ]»víÖ­ÛâÅ‹:¤·þ?þ8,,ÌÍÍM«ÕÆÅÅ8q¢¹ÕÐM)‰åææVPPPTTäëë»|ùr[kg)¥2ªC›QNÉ1˜ƒiüŠ=+((˜;w®Ñw¾]ºtQ#Dïimm­Z¬W¯^ê岤®sçÎmذ!##ãöíÛ&ÞY›¨†™^ýõO?ýtóæÍnnn‹/~ðÁm°µ9ÛÒà çÐÖzôè‘гgO‹×——¨<èÞ½»ÞÜ×^{má…Ç÷ð𨨨˜4iR+UcРAo¼ñ†â»ï¾{ë­·l3çØ&®[Ú//¯+W®¨OüñwÞy'77·¶¶6;;{Íš5Í]aBBBqqqqqñ|ðÈ#èÍ­¬¬tuuuuuÍÏÏûí·-¨†éûPTþóŸþùçšš)¥:ÜÔÛ 0ž³³fÍŠ¯¨¨P>늎ŽNLL\¶lYaaaŸ>}æÌ™ÓÜ2$66¶¢¢büøñO=õ”ÞÜ+V$$$¼ú꫾¾¾QQQꌶz5FŽùâ‹/æåå½ôÒKF·Fq?®5ьۚ-¸õ977W÷–¶7~üx{êÓtOq ;ÐápÝ`ϸn XmXO#´õëù ¯AÎÁr|îÕ¬„ã„ÛöQGãÃ\·¬vÎ-r°ÃÁ§Úv:.ƒœssss:‚&ïòà6ssqöìÙþýû·ÆPÌFF„9çˆH;X‰q¶Y|ôÑGé;€œ³Ï“2ÐÚsÀ€gÏžUoÞ¼YypæÌ™X6K͹ &(£õë×÷íÛ×ÕÕõ¾ûîKOOW ܾ};..ÎÛÛÛÛÛ;>>¾²²REi4u8U[[»jÕ*___Y³f•””Ý‹ÊÊÊØØX­Vëïï¯û—›\Üh‹«Xçr?å`…Fl¿Ë£ÊÍÍ¥‘­8JnIOÎÕ›òûßÿ~ðàÁ .¼råʽ÷Þ›——çáá‘pþüy)¥³>øàƒªª*ŸŸ~ú©k×®fúôéÿó?ÿÓ­[·wß}wß¾}ßÿ½bùòåçÏŸÿøã¥”sæÌ {óÍ7 «÷§?ýéßÿþ÷¦M›¼½½Ÿ{î9ww÷?üÐp7W¬XqöìYem±±±û÷ïWVÒØâêVš,ЬjX÷5Ç%Ñbæ4#Mm½i8WoÊž={¢¢¢¤”ëÖ­óññùä“O¤”3fÌHJJ²l–”2%%eĈêæ ”ÇeeeÎÎÎÊ €ŒŒ åñ… V/88X‰U)e~~¾ŸŸŸÑÝ ÌÌÌT+ÑôâæhV5¬û„㾨irV̹’’’>}ú(ã³½{÷>ôÐCRÊ   ÒÒRËfI)_zé¥Õ«WÝœú´S§N555Êãêêj5ÿôÊ;;;ƒtGBFצN7±¸™L#çÐø|°&OOÏ;vxyyMž<¹´´tß¾} Ðjµ–ÍÒýpÎ??¿œœåqvv¶ŸŸŸÑb½zõºzõªúú¯««Ó»®£<õ÷÷W×vùòå&7¿@³ŠVAÎV±lÙ²˜˜!Dttô³Ï>añ¬¢¢¢‹/Ž9ÒôF£¢¢–-[vãÆëׯ/Y²äÉ'ŸT¦wëÖíÂ… j±øøø deeÕÔÔœ>}zÖ¬YF׳lÙ²‚‚‚7n,]ºÔüÅ+`Y5>Ÿãº%l”òäÉ“ÎÎÎׯ_—RææævêÔ)--ÍâY;wîœ4iRc›SŸ–——Ï›7ÏËËËËËkþüùÊôuëÖyzzªÅjkk×®]ìâârï½÷nß¾ÝènVTT<õÔSîîî~~~o½õV“‹7YÀ²jpÝVÁMJVÐÚ÷[Âvz³Éû-­.>>þî»ï^²d ]Ãë \·ì9Î0õ6ˆ7AŒç`Ëã90žã9È9999‡†¤”ü .ÛÇí 9‡–žFiz@[r¦ ÚrHÇÉÔö;9N¦ÐapÝ@Î@Î@Î@Î@Î@ÎÈ9´¿éå Œþ*½o›ýs­òb£¶é}^w°Ýƒ„÷A¼ä`æ¨Þ·©îPœ3È9€Cãº%€œ€œ€œ€œ€œ€œsssssssrrrrrUV–X°@ôí+ÜÜD×®bÔ(±zµHO·pmÐhZ´ì=÷ˆº:ã¦OoÑúsp8ÿïÿ‰§žS§ŠôtQV&ÒÓEl¬Ø¸Q já ¥´¼2ʲ½{‹-[ŒÌýá‘›ÛÒM°AÉË­ãçŸÅÔ©"9Yxy5˜žš*ÆŒ±}ä¶m²¤DÞº%·l‘½{ËÌÌ;s/]’ÁÁwæ–”È;ä¨QR÷˜ÍÌ”ò“Oä­[w „„ÈË—Ýœ²lZš ’õÓGŒÇŽÕÐ-¿aƒ,+“òé§åܹúsCCåîÝwª÷Ùg28XæäÐó€máº%Z‹‡‡(.®®¦ÊÄĈqãD\\ý”õëEjêÐæÌcÇ6˜»u«ˆŽ®Ξ-†Ï=W_ 1Q;&š¸æ9s¦9R,]*„»v‰>û÷7qQ´¤D‹›7¬-)I<öXƒÊû­øç?é|À†shÅœ+*nn¦Êøù‰ôtáçW?%?_„…‰¼ÿÜHÜ\±|¹8xPÖOÔË9½WnåØîCAk‰ˆ6Q¦gOQPÐ`JAðñitnYYƒ§>>¢¼\HÙà_c!§çÕWÅûï‹×_kÖ/0s¦ ii¢¦æÎš éÞ™¢Wyäìܲe"!AëOß·O<ðÀÇáá")©Áܤ¤úû'NÔŸ{èPƒ§'ŠääSRSÅ=÷˜U½1eŠ=Züö·Æ ?.Ö¬ÂÉIa|”ö¯5xº{·xôQz°1ÜŠƒÖ³w¯6LîÞ-‹ŠdMÌÉ‘o½%ýýå?Öß0$·n½sËbb¢ ª¿ß2;[öë'·o—¥¥²´TîÞ-CCÜyù²2D&%ÉÒRYQ!½{ËmÛš¸ßRUQ!ËË-0v¬\¸PæäÈÊJ™•%ãâŒÜ9z´Ü¹S––Þ©<÷[6ˆœCë:wNFGK__Ù©“ìÕKΞ-/^lP =]FDH­Vjµ2"B¦§ë/)µZéé)'N”çÏK!ô¿Z0}ºôö–..rèP™˜h*äô–5]à—_äŒõkÞ¹Sq!dNŽœ:¨"Atž°èU?ðê ¨eÚg<.æ÷»ò·Õ'é|RyT³º®;©êu•Nh¤çïõa×=©”¹€ÃÃmý¯SEØ™«ÇÌÇIÜÿ]çŠuö’Ãv&ü%ãïÆKöF/=¨ëž‡TŠ]·á½42vJŽeÁQ儇nþGܺÃv&oüçó)ó‹tÔó‡úíyH¥÷QœI±üíyÿú··O¸áάsòº?ÆÉ·e=:ª…6lèyH%áµzøC ‡¿@¼YçúmC`þu¿åðf϶sUÖ±\fËÕ"ÓÏpÏåèœ#7¯7»®æ›¿ß!Κ´yoÈý »»ºèÞߜ¬ý6ŽÑóЬeœ®¯ÿõ@XjàÏì{æ0F®‚k9=Ço3òÉò„uUŒy;û¹Ó×Iù 4#ð’ŸO¸êZtÎ1À"Çíá;Äφ­ß Çè´ò•¶ÃÉ’ÃÎYÞÖ-Ù¿d?ÓuÏCûbBðáGßC‡³Ñûíw´højý  YwŦ*>‰¡ùˆ³4S±o´»ÿ5ÁLÖõýç¿^­ êÈHŸà¾5êyx5fnp]/d”~ ¹Ôá·³{ ¸}vO¸äæ×s›ª@“¨û­ÖøÀ·þëz®ú+ð´U…·ßΖ>ÏÐ(ྣsL¥¸Wµ ÷êe:¡„ozrxÿk³¾y³¨`ý’À¸Þüy³å÷J¸»ZowËšÙˇèÝåz—£D.#üp×ëo ¸ô5Á×ßOüûRRñË(-lyß9›o´VÝm1.¼ ,Åë¨ç!­T×jùk>²ê>ÜEÝâ~»ùý®È῞½v(¿¯£’~É¥nT?!^Íÿ .~½ŒêÜíì¥ÊÓ3ô%É[ì²?œËȱërò6´pPaí·šrçk‚¹¿Rpï6ÓÙ× 7çBrïΗ9éºÓ×XÞ/ÑÎz,‡Z½½é·êïS{]‡Ðˆûc¦ÌÊ|ûJ«d Ûï’ôýzžǸþËEä^.§ùþ¡å4Æõ…=6Iæ ª•!Iû«¬8ÔóÏ7Õݾ’«á½_ž¹ñªÛ"w7C T?á¶4ëí^SŽÀê^½µL{à ¬‹IÊTêìädòÇç’}¶ž§î·v¤­µ'ŸyŽ”™ |7uhM5¦ ¡’(·^¹wíWû-¼gÔã‚°¿W@ûG1| TB!­B?”ÑãˆÍýò|ô< ¦£AÝéøí¨‡c v8Дr? ºy¤ÁÁÜiÅÓó0˜¦~ଋ sU§¹³ÓfCwª}¸nõoê½§0=ãùùk÷FY¦Ív¤ÙÏÍ6 †×ÖOðû­¥¦ŽºzÆvoŒ°{žÌô?,Û£­è|ÃðßðhÓ ¿{ “0œSÉ1áÔ@k©˜JIzc¢$%º6ÎVŒÊÐÏ0*£» ½j +I¹éa›é笔PÀhÃXaÊGßÂ$ öô*ŒaÀ‘¬<å Wa*¦ŸÓRBacfE*-ý s2ö“Ð0’adzR•Šž„™™~~H …ÁŒ<¤¬çô!ðR îÒo0žÁGµ²õ„Þ¦Ÿ¯RBaHãlÅëýì© ‘tŒjб­„]¥Ç€3¦ŸRBa`³ o…,ž¾~R(ÎèÛD#ÜLI Eˆ¤\ìéÞtƒ\] Ð9À%¦$Ö”P˜ÁŒã\u;¤[€{T—N€iL:ÔÕ¸ <1ùô³ ó˜w´«t_“¿á ÍYWçÐŽk¬* |©§†)”Ã0’ŽJSGMrSB(—0ª. Tdß›6 gy*Â]Í®OãÖåÛeÆm/ÞPEiÄRr7äÙãä£(üÖiéì´Ù´oŸuÔnj³^µÙ*fùñR.F]ˆÒ]í®Á´/¦.7>ƒHËZ»xTQ꺅[Jãi¥4lÖî0žF®4®ºQ¾M~tJž!Ù¾TõSÎçŸÚ ø³;0oÉ=º=u±¼DíîŽ350u¸qig‹Õá|ŠÎ@ ÖÙMíV¸6rG[u89Ñx½2—ïï6M~|•¯‡êp*¢3Ì®ØT„ˆugÕáçDg˜Tźé"0›Ö¢ª:|›è siª|»Œ­ýú¦_%:Ã,šZpO³%÷:Ot†ÁuTÝ@z×QÉ=¤ÿ$:غ.ßn }¯^©ÃgDgÍ0Sn í¦äR‡÷DgÄÀuÍ D 5—ÜCêðBt†¾MU¾Ý@êRÔaÑz5íG7ò¦-¹‡f®Ã¢3tfÂ:uÆ D 7%7lÂ:,:C”ï7´Ô“«æ©Ã¢3´nžòÍ|HEÉ}b†:,:C£®;¹MxxHÉMkà:,:C[”ï„æ¹Ü£>ä6^¡ã}4oÄ 7«”Ü’FªÃ¢3T6@éÅÀ7HJn]ÔaÑêP¾+ï"f¼·¦ß:,:Ciý~ÔÌH73JnËz¬Ã¢3ÒQ]˜Mû7›m¼Z½>•ܾ´_‡¢3jjà)ßé÷"ðeüö®ý:,:C.M%xâ5rñý~Ÿí7ðOPFƒ×§’;’Fêð!Ñ™A´SÇçÜSýâþÒ]®.¨®‘ëSÉ[õ:¼':3Žºu\ùX•ˆŸÏçý~/ïB3M©~}*¹³ig!‡èÌ *Öñv> “UùˆË[E ï°QëúTrgÖÂBÑ™q®ãÒÌ´jÝ@´Ä™–å¾>•Ü'ªT¬;­¸CtfX™­òɽóU7Mf½¸¾sò½‘²¾âò£®b×gï×üϵ~BùoætÚ«kårˆÎ ¢@oö.aË¥9«$ËržwHÖˆûw‹žiGÖë³Ù’{ÉÏöWÿð?†’ 9Dg†’£Ž·?çÑriΪµ™öâÙËG=›ô%ßõÙ~É¥erˆÎ "yW¾ i |­o‚C/Š—Í-Êýƒ¯ÝÇòÀ/ŸþÜÔë¤ ¬on¿ñÃ-Ç´ópƒ›]‡ww¸£ÀΞóú›h ,†Îq]‰Î°õü£êœ¥90¨³›Å$ûí _üLs¸£öÇòó½!r¿g ~rQÉßIDŽî1– ”ô¼`–ìíÍè>[ÒÓ¤õ×Ó_¾ yëì°4V°@›÷Ó±g»^¶³ÙZ *þìÃZws,äÛõðÓØä¥ÿƧýlª4‡+æë×[Û¿dßo™’p“^¿:ê°…¯×ÃóˆÓäFL^Nº×3µnË„‡ÿ¾bDVé˜2{8epèp×û]¤º2c¶yŒñÛ)¦Ÿ×á…è<¬ø«|<—†DŽò­4GîîžLo´á©è¨D±ò"û|?Ù6m9M®úõ¿ÔÆð9=œ³HÕ€{/üüýï 6)Fd¿ÅoíUéx^‡Eç†d]ôÃ^¾¡«4#Ç9Êqb´ð îÕþs‰ÂæÏÉ?5]Y7i_…Ÿö¼UûíDÞº<ìß»«âIž7:ŸuÖÙ"žýƒ-on+îkóàúþEàiávÞxþ„rç¥9~w7¶óðµËöZ˜©Ð'¼Ø‹|…7üüMA>«Ì‡O»w 1—/Ë-ÄÖº“DëÙ¥1›/ÍJÎl Gî/Ã'Ÿ]¢gþlêá]µŸ»ÛwÑfõáÙNcZÛ²V¦9 ¥ðeº¹ ö—HxËß?¬ßk÷/?Üæ¦³?„³!úsw%Uÿ|¹‘»6Ç»ŸŽ/Í1…2py¬ŸxaxZ ©?/¿³8 á7p«ÎÞ ÷>9GI42F²fîÂ>¡kgZ;=l|øå¯“!P«,×ͬkņUnUº´ü'®ª_O.ÂygϬ;qÿ1ñçÛÛºâþÎá¾|ù vxòÎ^»ßì{7eØ]ø2ij„ç.Üá³~Ú^zBà ­ÞÔ¿]¦d®¶óðÏáv^mäÕ&½0Õ¾îi*CTŒï ïëïe¶”ÄÏÑ”Mò8ÜxüN øá~Ïž_±,×röÑ¥YgIá6,Ñâ¬Ig·ÖÃ/ø$%wÒè¾òÖÏùZ†w’ëï½Z›‘DLåM{½ ÌhÖÒB½ë·47ؤ°v.¼’ŠÞ«at?õ~òëè(Âãåð_•åÃIúµÐ°ýU9GÓ”Zç:í~'Î1wôËõšöþBÉë&Ó!   ÝÂyé·47ؤCÕ/³ºZ(¼]}U`;1kŠ”åE;uøªøO\©vWfGùt˜“Fç×Å~\j}¿5n€CȪÙÚ­4 µ‹ª¢f oªÛ€—ε²¼Ñlh¿…Ê}ýü/ÇF.‘ëiƒÍ¶Tç`3é²ìèÒΖ>n ¾ òŸ½ÿU»EÎZÇÖ‹n'?% ï½$ù’³¾^}±ÞTøùñûJƒu˜ö-WKî’ÛÊ'ÝŸ¹wÓÖÿ´¿±ø³‘ëj¸yáúfexG뿞-;kÕá¡]:„ºžSñÇU^3¹Çi¿ÙÍ67Ç~XÃ[4ãù&¡3¤ò×F+©ë!ÍOcœ_µ›°Þ¯~Çi -¯~ÑQ½Uk-ôÒs½2R©x%Ì»Öù‰ÀÍ#ƒy`=®Ã£×C]ܵßä9uxr-œwÑùurj7/g¿¸@?7R7_;qad¥O¥©³,:Ã}j÷„œëÖ4’›—ï´-­Ûžy¨ÃkóœŠÎ€Ú=sf:v–’¥çÌ:@Ñ`&›³!7ç&:@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè Qþ©Ý¦ó~¿_¯×çó©Ý¶|»h™è õù ]°`€Sªf[^ˆÎ²Èï÷[n:":PÂwAÂ7+[œtÊZg Y§çõ#½0ë @–jÝ1ë @ ë üù|¾Ë6L?}1ë @9ŸÏGbúeÖ€ÎR²ô tĬ3D¨Àd3Ð#Ñ€Òäf S¢3D Šÿ •¾ù/f LõÂOÎÃóãttÏ›ôØ|:jß>1ËÐÀ¨Dgîäc•è À5ß@“†7Z€z':åÉò÷%&¡Þ‰Î„$Ì»r½8–o•……@§Dgþ(9%l!Ðр׫j~µè…è 0»vVMXÈ4Nt˜TËS¼rmæÒQµhè 0‹~WAXÈ4BtÜHS¶ru‰Îc8_ZÈÔ":ŒfžU r…‰Îƒ˜y ÖB  Ñ oòâÂB 7Ñ WV)œ±ÈDtèŒ)Õxri‰Î}ÿn³HEthU©XÈ<$:4Êi>r÷ˆÎm‘犱¸Jth…UµXÈD*3åÙ 9€0Ñ ù¬YrgDg` M݈oª1XÈlˆÎ…˜Âì—…À—è ëý~ŸEœÀ?åhÆ÷òVï,äDg`dûˆ¼„ž2{IW#²¦%:Ãú|>ï÷{ 7ÅB³)ÉyXȳ‘-ɦ@¸‘Ÿ¦e!ÌCt†A¸q#ÓgÏ—…0<ѺáÍøªõ ï‚õ²ç=iŠñ’KŸ[J~3 9`T¢3t#¼Z×{ó™}ˆy¸èYºçRwÑ·rÀxDg˜]ïÓ{gÇuûxMüs…0 Ñ9›LÚ,<øsËï_?rø´ý†×îíüR;gÐË”áþÄmæ×73î½Þ?ççƒË~[Ûo*|1ïí¬‘M±z':Ã}먺ùóëïo;, m_Ñic¿…ÍŽö¶mý´pÃö/¼Þ%M»SzÌ7ëswv}ÆÎá5¶8ÜÚÏápvÏY?ùç´Ÿ˜7,ä€~ý¯v`Lë7ÂÍ›bÌ{ä>ìßb#§¯O ·d°÷òK‡³DƯ|­Jký;ÖûZþ|öœÀ«–ø›°Oö͈oإͶléϾš 33ë ÷ÅÌÎî'Òn$³o¶=¾^†Ӱ×÷•“è} 0æŽAx:¹˜}3’4¬‘£»ÁBè…Yg¸o=7ùóÉW—‡>÷ù+þUß?Ì3öþWwÓÌkQû?ßøðös_7„×l$Ül/6“ÐóŒAèˆYgxäÒ›t/Sb­µ³L€háHŸØÜô_²o&2#ç5ŸxpÙøá¢äõ“ÏšqøÈ2!}¶ë³L?ÆÙ¬Ý à@ï‹p[Ål·N ¯]hxýM*Ÿ¿ßÆ‹iöáó7/ üõ¬ á†í·¢bm&u=×ÂyŸ–ë§>Ò·ºïñûi¡ÃÕûå§1m>|þfû)·Ã9ÂȆÝkgnåOñæCÑÀ èg8ü¦HÌÐ õ‘¾y_²7jÔÌQfÈ ©M3_fÐ)k¡šŸ?ƒ@E5¸Ã3ñ\À<77`0¢3T“ê]SÊÉjÎ =Ã1V1ÕUCaf° ˜3C“„k†!:C÷¼&CÉãn’¡9äz€‰ÎOÉмœ}˜ƒè Œ =!ç¦":¤'CÏ™…9‰ÎÉЃqar¢3@ 2tל5àKt(J†îˆslˆÎuÈÐÍrF€3¢3@e2t#ô?ð“è Ð º ½ Äš#C oDg€vÉÐÉéIà Ñ 2ôCú HBtèÉ&C ‚a3–è Ð¥o é Ñ crl˜Œ²F0y†žó¨òDg€¡L•¡g8F )¢3À˜ÎÐãÐ Ñ`pÃdèÞÛ @t˜E§º¯Öc¦ÓE†n¹mÀ´Dg€y5˜¡Ûi Àžè @ý -1]øOá -1}85CKÌ@§DgBfh‰èè @”ÛZb†!:pMd†–˜ñˆÎÜt˜¡%f``¢3Ý[Þ§ZÖZb&:Ó7oÒ@1ÿ«Ýèƒè QDgˆ":PÚûýö_ G¢3D(!0Ílè…è @!ûˆlåÐÑ€¾¿ÂþÍÊ~‘è”ÿ€BÖéyý@/Ì:P‡¥@wÌ:PÂ:(>Ÿï² ÓÏ@_Ì:PÎçó‘˜~™u „³”,=1ë QDg*0Ù ôHt 4¹è”è QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(ïÏçS» cz¿ßµ›@vÞFa*ÿÔnÀÈ䪱ùt³±`¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":Åûý~¿ßµ[’è Qþ©ÝÆôù|j7 1³Î¤ay0<³Îü±NÀËÌñòàf.ùûøçóùþaùëò¯‘[8ü'€ÖˆÎü¿uð]'ÚM^‚òæ ë§máûÝÁ}¶6c tÁ‚ þ³„Úp¢ýþëg%°©ýƒûÍšoº`Ö€cËìòÉáõZ޳=ËßMø!I€>›„^‚µè ´Ï‚ ~Ë—k—ùfËö‰Î;üFà ›d¼þ_Ï~v MnäÒÝ"„MJÞÿ®Ü¡³ŸŸ;ûëÙ–ûꫯîN1ðµÎü'þ·2~>-ü×K[h„Et€(¢3¯—¸ˆ :ðzù‘8€¢3øêÀÑ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Ê?µ0²÷û]» $óþ|>µÛ°`¢ˆÎEt€(¢3D Šè QDgˆ":@Ñ¢ˆÎEt€(¢3D Šè QþÃEÈŒ©FgIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/code-model.png0000644000175000017500000102263307752161573024026 0ustar frankiefrankie‰PNG  IHDR„»Û pHYs``zxEtIMEÓ 1.2D IDATxœìÝy|LWÿðÏ}&û"²IDd!‘„b‹5©P¥¨Ú«Z][mý©zªªj+Uª”¨jKk«½¶ ±•HD$!²ï“Ì>óûãÔ<ÓˆUC}߯yyeî=sî¹gî˜ïœírƒ„B!„˜ÏÜ „B!Ï/ F !„BˆÙP0J!„B̆‚QB!„b6ŒB!„³¡`”B!„˜ £„B!Äl(%„B!fCÁ(!„B1 F !„BˆÙÌ]€?½^_WW§ÕjÍ]Bþ.Žã$‰X,6wA!„ü{P0úO©¬¬,..–Ëåuuu"‘H(š»D„ü]z½^¡Pðù|KKK;;;€þ!„ò·pƒÁÜeø·ÑjµÙÙÙeeeÎÎÎ666VVV‰’ ÖÒ/—Ë‹ŠŠ´Zm‹-ìììÌ](B!Ï0 F³šššŒŒ ±Xìãã#•JÍ]Bþ)z½¾°°077×ÅÅÅÓÓ“ã8s—ˆBÈ3‰‚ÑÇI£Ñüþûïvvvîîî<M#ÿ~µµµéééÍ›7wvv6wY!„<“(`zœnß¾Íçó›7oN‘(yNXXXxxxäää( s—…BÈ3‰b¦Ç†ÍXòööæóùæ. !OŽ£££­­í7¨›…BÈ# `ô±©¨¨°³³³´´4wAž1:î¿ÿýï_|ÁžVVV*•J󉩨¨¨ªª2w)žÇ5kÖL¡P¨T*s—…Bȳ‡‚ÑÇF.—[YY™»ÏŽãlmm/^ @¯×:týúõ'ÃO>ù䱬ꚜœœ––ö÷óyˆD">ŸOÁ(!„G@Áèã¡V«Õj55‹>mü{ݺuÆ û;Μ9S­VÿÍRݺu«¸¸¸M›63Ÿç„@ ‹Åuuuæ.!„g-Xýxèt:Žãhðg0öìÙ³hÑ"[[[cÌ·oß¾O>ùäå—_~ñÅGUXXÿÕW_ ‚íÛ·gee-X°@¯×{{{/\¸-o¹råÊï¾ûN 4oÞü½÷Þ[°`Z­NHHàóù?üðCMMͼyó®\¹Âãñ¦L™·zõêü±k×®¿þúë­[·ÜÝÝY3ê²eË222V¬X7iÒ¤}ûö…„„X[[›³ŽžÇYXXÈårs„Bȳ‡‚§Ç†ã8ZjñÁ•””Œ=zýúõ;w~÷ÝwÙÆîÝ»>|øÆÇ­X±ÂÒÒ²E‹?üðüyó †ºeË–ÐÐÐ3fL›6mõêÕ)))Ë—/ß¿¿L&‹‰‰¹|ùòÒ¥K7mÚôÍ7ßH¥R±XüÆoètº;w¦§§'&&¶lÙò•W^¹téÒÖ­[7nܘšš*‘HÖ¯_ëãã#“É„BáK/½`ÿþý/¼ðýºxp|>_£Ñ˜»„Bž=ÔMOÌãèÑ£½{÷¶°°:t(Û( w«’Éd^{í5WW×åË—ß¼yS­VŸ>}zÕªUJ¥r÷îÝ:nÇŽlÖ¬™½½ý† ÂÃÃÙ«,,,,--õzý7ß|óÊ+¯XYYEDDïÞ½[, …ÂÁƒ=zèСcÆŒùöÛo•Jå®]»z÷îmkk[TT”––Ö­[7sU!„òü †bJ¥R&“±¶äFÆÚŠÅb@¡PØÛÛ{{{sçííݧO>Ÿ_SSc|mPPP½×* NgaaÁžòxŒ>£>üÝwß †¶mÛŽ3€N§Ójµl¬*ypŒBy4ÔMOžkÞÞÞÆ.{>ŸÏçóÍ[*B!äùAÁ(y®yxxL˜0ÁÜ¥ „Bž_4›žB!„˜ £„B!Äl(%„B!fCcFŸ„C‡]¹rÅÜ¥ äñðññéÛ·¯¹KA!ä_‚‚Ñ'!%%eÍš5æ.!Ç Aƒ(%„ò¸P0úätíÚ500ÐÜ¥ äÑ]¿~}ß¾}æ.!„ FŸœ!C†Œ7ÎÜ¥ äÑmÛ¶‚QB!M`"„B!fCÁ(!„B1 F !„BˆÙИQBEyyy]]½½½L& Ñh.]º 88X(š»t„BÈ3ƒ‚QBÚáÇß{ï=__ß‚‚‚-ZDDD 0`Û¶m»wï>pà€³³³¹ H!„<3(%ä¡mÙ²%>>~òäɧNª««srr²¶¶~ã7~ùåƒÁ`îÒB!Ï F y8gΜ9þ¼J¥Ú¾}{PPPff¦¥¥e½4J¥r×®]iiiÎÎÎ/¾ø¢i[i]]ÝŽ;„B¡““ÓÁƒÝÝ݇.•J«««÷íÛwáÂ++«øøøÖ­[îÞ½ÛÖÖV¯×Ÿ?¾gÏž¾¾¾_ýµH$9r¤ƒƒ€[·n¥¤¤TTTDDDôíÛW$=Ѻ „Bþ6šÀDÈÉDb±X&“Éd2¡PxàÀ7ÖK³lÙ² 6ôêÕ«´´tâĉr¹Ü¸‹ÇãUTT¼ýöÛ_~ùeóæÍ?û쳯¾ú ÀåË—W­Zåèè8bĈ¼¼<—žž>bĈ3gÎÈd²ñãÇO™2ÅÎÎî§Ÿ~Z´h€òòò#F(ŠÎ;/]ºtíÚµO²!„Ç‚‚QBNÛ¶m›5k‘””àïï_/AMMÍçŸÞ·o_™LÖ£GÔÔÔ«W¯÷J$’.]ºˆD¢™3gŽ7.))‰Í| š3gÇsvv–ËåW®\qrrŠŠŠòññy÷Ýw§M›&“ÉúôéÃBÒôôtG-..ŽŒŒ´³³‹‰‰Ùºu«iÔK!„<¨›žÇ¬¤¤D.—Ÿ?þæÍ›âââîHêââbgg@*•–––Ø·oß‚ mmmR©d)e2™X,æóù<ÏÖÖ€@ `Þ¹sG.—ÿüóÏ<O«ÕvíÚU£Ñ<É3%„Bþ> F yÌœœœlllØ¿½^?wîÜfÍšÕKÃqÇq¦[¾ýöÛ®]»Îž=ÀŽ;ä@Í›7wpp˜5k–ƒƒÃõë×wîÜieeõ¸Î‚By2(%äáœ={6;;ûرc-Z´pvv>þ|EEÅñãÇ/^¼XVV¶{÷î—^ziÒ¤I~øammíµk×nܸammm|¹B¡Ø·o_QQÑO?ýÔ¾}û3gÎäææž9s&""âË/¿Ü²eË;w222~ùå??¿#GŽ>|X&“•––Ñ„Bž1ôÕEÈÓ&MbðùüAƒ±¿›4i2þ|;;;Žã&L˜xùòeÿÉ“'›6Xrçíí=kÖ,[[[>Ÿ€ÇãMž<ÙÏÏ/+++00pýúõ%%%</<<<$$ÄÒÒ’ã¸ùóç³”íÚµ ¶¶¶7nÜ¿aaáÛo¿f¦*!„B£„<œãSöG‡L“õèÑ£G÷¾\"‘¼ð Ƨ­Zµ2þW/±éÞ7:99 6ì!JO!„?ŸZCÉ?ǃ’S*9e%¯2[®NÏWæwÓuë(íÈßÜ¥#„òÜ¡`Ôü´mª"u·g›l›’Sš»8ä9¢…6M”v‡G_«wâ;ù‰üÌ]"B!Ï FÍ/K“uLìg‹Ÿ)%Ož†~ÁO’Ÿš+›»\lx6æ.!„ç 3³Z}í)Õ©ÝâÝe¼2s—…<¿.Š.9¯ô«[@ p˜uÿê*¾®ŽÀ )Pl.Í€×î¶Ë¶ÀÚ$ÝìÀP »Cû6 ÐÂdË^ 3p¸„ÞÝ8pÖïn|hœâ€\ pºk€‡o %„Bþ¨eôiR \†6ÀI@!pèð°ø€#¤¹€?Ì!nƒè¬¾j%€Ø¤EÀ6@,Ñ€Ý'à  è£€ @ Ø@Øßížæ ðÏ}ô¿ïn@0 ¨ôÀ(àw ø˜}ÿ‘€L` ²ó€ï€ÞÀ`" r€Á@ =°`­~;×€V@0Èl´ÆÎ­M*YìíÝN)ú¹@ÕŸ·×:“ ¾=põÁZ— !„経>M®r =Ðø Ô5÷„›€ËÀ`&Ð øð|àCl,€è|ô$@/àШ.xÀÀ p8 h(ÃHÀ¸H$@S`âÝd¼»­ùuÆ`pp7€æ€°ýþ'r (~,€>€Ð€í@O %Ð(v^À»€Ƚ;ˆv„<ÀøhäÆC×LZ:\².€Ø ¼ùçÄ€Û€ ðÊÝ:‰šßMÓ ¨äwÃtb>UUU§OŸ¾pá‚V«åñxíÛ· ³¶~*ÞFsêÔ)NתU+WW×û%+..>yòdzzº^¯wrròòò µ··7MSXXxôèÑììl½^oeeåëëØ´iSï¾¹¹¹ÙÙÙÆ§"‘ÈÎÎÎÃÃÃÂÂⱜ݃;wîÜK/½4vìØ·Þzë úA”••%&&zyymܸñ=PFFF|||§NÖ­[÷xsž9sæöíÛ÷ìÙãííýש“o¿ývÖ¬Y .8pà;(yšQ0ú4Ù}·Óü&ðp Ö€öÏÉlÿïéÀ `°êq(´w;ÍE€#€Øu!à.@qC¹€ ÀJ °T?,Õêîq èïÆm-{r@à!pPÜÐÐE@àv÷2÷®rj`@}7“t àBàPp7îd€pî‹î€'à´½§Ðº‡ºJ+ƒÁpðàÁwÞyçÚµkJå «Éd²ÀÀÀ ôìÙÓ¼ÅpüøñªÕêI“&}øá‡÷Žz½~Íš5K—.½yó¦ZýÇê°R©´E‹“'O9r¤H$’’2sæÌœœîÑÀb±ØÁÁaÙ²eIII÷;ú¶mÛæÎk|Êçó%‰­­m÷îÝGŽÑH Û  ÈåòwÞy§^ ü— EfffiiéC½ê‰ÑjµÙÙÙÁ?þMªV«333==={ÎEEE™™™ÆKèɨªªÊÌ̬ªªúë¤äù@ÁèS£8„  9 \¢àÔÝYðµ€àà¸}_æ(ÍV€ñ7<¨¸†Ækh€;PØÝM/½ÛÙÍvm¦Ã°çÏ9<ÂL€äÀ•FSº¥€Ödä¥ Ø}¬XÉ›nÀo€à™w‹ä$£ïmüCà Ü4yº t@ÀØ$šì=8öwƒÑa …Ô€ œÎNž˜]»v½üòË …bèСÆ kÖ¬YAAÁºuë¶lÙ’œœ¼mÛ6³Ç£[·n­¬¬äóù)))3f̰µµ­—`îܹ}ô‘T*7n\RR’‹‹K]]ݾ}û¾þúë  8ÐÑÑñÒ¥Ko¼ñFEEŨQ£^|ñŦM›VTT=zôû￯¬¬lä覮®nÈ!:u P(222NŸ>½víÚíÛ·OŸ>}Ê”)íÚµ«¸¸x„ ŒBžŒ>5®ÅÀ: зÝ@,0ø¨Àqàsà𠨀¯€¡s”$à`5и4bî“R,ìs€únWµÖ p¾;£¿°ëÏA› ð-à¸Ñ@>p8)€3е¡ƒ6ú£€AöÑ耷Ào@ fÓ€M@WÀè,–Àz ð*°pl€_á@«û( 8 ¨p 8¤Ü-¼ Ø ô¬Ê€£ÀtÀȽ†g »MÂÄŠ‹‹ßxã ¹\>þü·ß~›µ úùùuèÐÁÝÝýƒ>xíµ×Μ9so½Z­®¨¨àìì|¿Ì+**Ôj5ŸÏwttl¼ ƒÁÉɉã˜=WVVöý÷ß{xxDDD|ûí·xá…LìW&ÇqŽŽŽÓ§O3fŒ\._¶lYmí³ð.^¼8qâÄÐÐPV9íÚµ›={6ûnfe>|xFFFQQѨQ£ú÷ïß¿ÿo¾ù€B¡øê«¯zõêe¬´Þ½{ïÝ»×8¢ÀH©T~þùç‘‘‘ì-:thVV–q¯V«Ý»wï AƒBBB"""ÂÃÃ;vì¸zõj…BaL£Óé~üñÇnݺ±c…‡‡·oß~Õªÿp2 ©©©C† a'6|øðk×®=Håèõúýû÷ÇÄÄtèÐ!22²OŸ>ÇŽ3Mpþüù‰'²â±*š5k–±ŠŒ222Æß¶m[–,<<üƒ>¸ßAårùÔ©Sccc?ûì3¶¥¬¬lîܹwuèÐÕ³©´´´¸¸8VÎÈÈÈÍ›7 R*•ÉÉÉ£G6öã_½z511±ÿþyyyl‹F£6lبQ£X @¥R}ñÅÑÑÑì:ˆˆxÿý÷ïmŒW(üqDDDÇŽÛµk7aÂcž÷3vìØñãÇïÛ·oÀ€aaa]ºtÙ¹s§é5sãÆwÞy',,Œ½]»v“'O¾7ç#GŽôêÕ‹¥éÖ­ÛO?ý´hÑ¢_|ñÖ­[¦•¼|ùò¨¨(v‘‘‘Ÿ}ö™ñ4”––NŸ>ÝøÎ†„„ÄÆÆ^¿~½ñ³ 0Ç¡®®.--M¡P4¸wìØ±V¯^}ï®j~ðWûÀ§ëQD§Íqè=À¯ÀEà= §¹ë=>>ô#«½Àë€ÊÜgtŸGrmò%å¥F®ó””ƒ ºwW^^^ffæ£}|ž$µZÇqÜG}tï^½^ÏÆJ¾øâ‹lKzz:™LšœœÜ¶m[®®®¦ç{æÌÉÉɽzõ‹ÅÎÎΗ.ý¯>Åb±‹‹‹¿¿RRRß¾}%‰•••i¦{÷î|>ÿôéÓ*•ÊßßßÒÒòÆƽÅÅÅŽŽŽ<ïÊ•+Ÿì§Ÿ~Êq\Ë–-ÓÒÒôzýƒ×Ò‚ ,[¶ìÞ]gÏžµ··wrr2iÊ”)ÎÎÎ=zôHNN0`€‡‡Ç>|¸\.7 yyyIIIÖÖÖ2™,222:::::ú«¯¾2 YYYÞÞÞ HNNîÚµ«D"qppصk—ñp,ªóõõµ±±éرã€üüü8ŽëСí[·XšªªªŽ;¶hÑ"...99¹wïÞ666b±øÃ?4æsðàA;;;›>}ú$''ÇÆÆúùù%&&8p iÓ¦B¡022299¹K—.‰$000##£‘Š*,,tsssqqqrr JJJêСÇsuu=qâ„1Ù¤I“\]]cbbX±ÙcÉÉÉjµÚ˜æâÅ‹-Z´à8Îßß?!!aàÀ!!!¡¡¡lï¥K—ôêÕ‹=-**Šåóù£Fªªªb•Ãqœ——×€¥Ré§Ÿ~j?<<|À€mÛ¶uqqñññqpp0~¬jjj^}õU@àââ7pà@ooo‘HôöÛok4ƒÁ R©&NœÈçó[µj•””4hРèèh;;»ýû÷7r ¤AŒ>ÿ¶`´x ¸jŽC¯q@®¹ë=@Õã«ØsŸÎýÏC0Z[[ëïï/‰>Ü`‚;vfOY0ÊqÜØ±cËÊÊ Ciiirr2€ádz4Z­¶]»v-ZÄzý ÅêÕ«y<Þ /¼ ÓéX2Ö™˜””TPP ÓéT*Õûï¿Ïãñ&NœhLc0._¾laa^WWg0æÍ›ÇqÜ¢E‹ŒÑdjjª……EóæÍÙ±‘““ãëë ÀÉÉ)66vÁ‚())ùËZj$­¨¨ðññá8.--m9uêTff&+­N§»qãFÏž=%ÉñãÇÙ–ÚÚÚððp//¯k×®Éår¹\΂°òòò£G–””hµZƒÁ —Ë¿ùæ›^½zÿ/eÁ¨@ ˜={vUU•V«½q㋺Þ}÷]–F¡P:tèÎ;,[¥RyìØ1www__ß‚‚–fòäÉ"‘hýúõ,R«Õ………ÆŸÅÅÅ!!!,tc±]MMÍÇÌçó_yå•F*Š£Ç%&&êtºòòò)S¦°ÀÑø¶?~<;;›”V«ÍÊÊŠŽŽ–Éd¿þú+KPWWÍãñÆŒ“ŸŸ¯Ñht:]YYÙo¿ýƘ£7nÜèСƒP(œ6m«v½^?oÞ<ýû÷ÏÍÍÕjµZ­öÒ¥KŽŽŽ¶¶¶lð€Á`>|8»Ù5PVV6vìXÖ3ÞH0:{ölŽã6mÚÄž&$$888…ÂaƱ7nÕªU<oñâÅ,Áž={d2Y‹-Μ9£R©ôzýíÛ·»ví*öíÛÇÒ°`T ¬^½Z.—kµÚk×®………q÷ÙgŸ5Rá-[¶d1kVV–N§«®®^°`X, 1^ØçÏŸ¿råJmm­^¯×ét·oß~ñÅù|þÖ­[Y¥R`Ê”)eeeZ­¶¸¸xäÈ‘LƒÑuëÖ ‚öíÛ_¾|Y­Vëtºôôô;;»3gÎ †›7ozzzæääèõz½^/—˯^½j¬pòà(}<þmÁ¨PÜôýä @þ˜Z"éñ0ç!•Ëåîîîb±øØ±c &`ýï~~~ì) FmmmMc¸ììl‰D"•JÙGþìÙ³<¯]»vƆƒÁ V«CCC-,,Xpc0Äb1ŸÏ¿yó¦1ÍÍ›7%I=L[ÈÞ{ï=Žã>üðC}^ºtÉÂÂ"$$„54 †C‡I$’¶mÛÖÔÔüåùž?~À€Æ¬,Jøè£jkkyU#Á¨Á` `Ú~ÉTVV²îoctb0Ú·oïåå•››Û`†¦¸¸¸°°0//¯]»vžžžÆv8ŒÓ:tH*•›¶u NWZZZXXXPP0zôh 㻟_¯±|ÆŒX«¡B¡J¥‰$++˘ ¤¤„èh$=pà€P(1b„V«U(®®®±±±ÑÑÑ>>>ìšdË2¤¦¦²ôC† aí¦¦ñ?ýô“D"1þîbÁhTT”é5¼yóf‘HÔ£GF.NÖÈúóÏ?·TWW‡††òùüC‡ÕK\]]Íjû»ï¾“Édo¾ù&Û~åÊggg///Óãï¿ÿîêêj FÕju=„B¡é± ÃçŸ`Á‚ƒ!==ÝÙÙ9 ??ÿ~&ˆ&0‘†p¹àÑãeÆC“ç^yy9€zócM'$yxxxzzfdddee²NpK—.5}k,,,4Î…ruu5]4´yóæ|>¿¦¦Æ8lT©T¦¤¤H¥ÒAƒ±&«€€€ˆˆˆ£G^ºt)22€H$âñxjµúÞÁ¦÷jÛ¶íæÍ› O:uöìÙÓ§OŸ;wnÆŒ555ï½÷Þ#¬IÄíGVWW¯_¿~×®]999Z­¬YTt¿[eüOZZÚ_|qâĉêêjƒÁÀ^eaaÁ¦à…††:99Ÿúøø¸¹¹••••––²iFYYYëÖ­ûå—_ÊËËYµTUUÕÖÖÇeÆÅÅ¥¤¤L:õçŸŽŽŽŽˆˆ 2¥eï V«5}Õj5›r”——çïïâÄ Ó3 7.´dggÇo0mÚ´9tèPnnn«V­Xa¾üòË;wÞºu‹U‹zoß¾Í^råʽ^ß¾}ûÆWÈÊÊJHHÐëõ7nLLL4N÷¹sçN^^žL&Û¹sç®]»Œésrr°T7oÞT*•~~~^^^ÆŽŽŽÇoä lñÝ“'OªÕê³gÏ–••õìÙ³¦¦fΜ9™™™­[·NMMõðððóûcÆÀ… Ø¿ÆLXÕåååi4ã|£¨¨(KËÿ-,amm““S[[ÛÈ/''§àà`ãS++«°°°´´´«W¯vëÖ @mmí·ß~›’’’••Å[«T*¥R™›ûÇÄÒÜÜÜ’’’=z4kÖ̘¯¯¯››«1V¥ÙÙÙR©ôðá×/_6­RÇ’¹»»‡……íÙ³§gÏž½{÷îܹsHH¦ÒH}’Q0JyŽðù|77·üüü;wî4˜àæÍ›š4ibº±Þ Žã²/Ýk×®-Y²¤^nNNN¦ßLÀt¾ð½“>|óæM›>øÀ)VUUéõú¯¾ú*""‚ÏçÛÛÛóùü¼¼<…Bñ KôK¥R/////¯¡C‡VUU­X±bîܹk×®?~|#ËéßÏ­[·ªªªØb¥êêêÆŽûý÷ß·hÑ"88˜µ:߸qã»ï¾3?Ô ãÇ>¼¬¬,,,¬M›6¬0[¶l‘Ëåõâìzo‡………µµuuu5[#öæÍ›ƒ¾zõjpppûöí›5kÆãñN:õë¯ÿ[÷.11qÕªUk׮ݻwïwß}gccÓªU«yóæõêÕ YΜ9óûï¿×+$;M•J5þüƒ·oذÁŒÖ{—…B¡ƒƒƒV«e!µB¡?~üöíÛ}}}U”——ÇzÙKØO 6ì¸J¥²uëÖ‘‘‘¦ë¬W*•Ÿ|òI½—899±)ùì*upp¨7cý/Û²±±iß¾ýž={²²²~ýõWFÓ¹sg¹\. ?^[[[ZZgœ/Ï…Ý´iS½Y[[[[[›n¬7‹N&“ñùüººº{g°Õ˧ÞôyVo,Ê×jµ3gÎ\µjUóæÍýýý===e2YqqqJJ K@§Óéõz‘HdúcL$™N¨W«Õjµº¶¶vÆ õ‚KGGGv²2™lùòåüñîÝ»?ûì³+V4iÒ$66vîܹðÉzÎQ0JyŽˆD¢víÚ>}zïÞ½ƒ®·W§Ó:t@‡L·×ÔÔ˜>5 ¬É} ²x%..náÂ…÷±iÓ¦^¼M›6i4½^oÚ¾@ ìܹóý÷ßoÒ¤‰¯¯oóæÍ¯^½züøñF®oͤI“V­Z•ŸŸ_PPð_™'Nœ(..öóócâÙ³gwíÚÕ·oß+V¸ºº²¯íÍ›7—#hÄÊ•+‹ŠŠÖ¬Y3pà@Ö¦T*=š™Yÿ½ÅźëFmmmuuµH$baÖöíÛ/\¸ðŸÿüçÝwßµ±±aáÎĉMƒQ‘HôÊ+¯¼ð ùùù©©©{÷îýùçŸÇ·wï^ãj#FŒxûí·ëšÇ㹸¸ðùü÷ßÿõ×_7n 1-ž^¯7†,¦¬¬L °`+--mûöí½{÷þòË/ÙÌ37nܺu«1V™………×XxxxttôÂ… ããã7mÚÄPâî%›ÔÔÔ{_Å:âÝÜܰqƦa½ºmP×®]÷ìÙsôèÑC‡yxx´lÙ’ÇãÙÚÚ8p ªªJ¥RõìÙÓØÙÚÚ–––nÞ¼™W6%•JM¾zóëkkkµZ­­­m#Ë{`G4ÝÂêå|íÚµo¾ù&((hëÖ­žžž¬TGŽaCŒ+++©TZYYY[[kŒ¡«ªªär¹1P(ŽŽŽ,Ÿze06èzzz.]ºtúôéׯ_?~üø·ß~»víZ½^ÿùçŸSûèC¡`ÔÜ8H ‘¡. =ôJ(Ÿ|‰È¿|qý;ÌþAу¯ó÷Œâñx/½ôÒš5k~üñÇ´´´ÐÐPÓ½©©©?þø£D"aS=Œ.]ºdºegggeeYXX°h€eráÂGGGÓnLJ•ŸŸ¿wï^WW×ýû÷×Ëgúôé[·nÝ»wïðáÃÁСCgÏž½xñâèèè{4={öl`` T*U*•b±¸Á÷´^Dò€®^½ºhÑ"F3pà@cÛp]]]ûöí1·N§;pàÀƒä–——çèèØ±cGcŸlFF†±ŸÔTZZZaa¡±á0333??ßÏÏõÝçææŠD¢Þ½{o PVVvoXÆqœMëÖ­_zé¥)S¦¬Y³æêÕ«~~~¡¡¡<ïòåË÷[“’‘hPYYÙÙ³gÛ·oo|zþüy‰DÂfˆgggkµÚèèhãH­VË~ó …“'O5²Š­T*5kÇq|ðÁÀwìØÁ®@WWWÛ·oß¹s§cÇŽ ¾ÖÛÛÛÂÂ"+++;;ÛÇLJm,((¸zõêýgÔ¥K¡P¸cÇŽ³gÏÆÇÇK¥R>Ÿß±cÇS§N•””p×¹óÿnš‘••uþüù=z4;v¬¦¦ÆXál´FHHHã¢âââ .{Ø+++SSSA@@€ŠŠ …Bf}ºººúÞUFPänfbNl¯·×B{ïC÷(·0"ä/è¡oðz`¯··àžôÍÇŸ¼ððð#FTTTŒ9òرc¬G˜Åì¶LãÇg_lF …bÚ´i¬!§¤¤dêÔ©jµ:))‰-SÊ–„¼víÚ;ï¼cV¨Óé~ûí·¯¿þúAFv2ìÆH½{÷fÝ‹¦ $ SRRX›ÐرcÛ¶m›ššúꫯ^¾|ÙxˆÛ·o/\¸ðÕW_e‹€Îœ9sêÔ©/^4~/X° ¨¨¨eË–¦æTWWW\\\\\œŸŸŸ––öé§Ÿ&&&^½zµgÏž'Ndq†£££D"9pà@~~>•JµaÆï¿ÿ¾^VM›6---½~ýºÁdUK''§ââ⃲^òœœœ9sæ48Ò433sñâÅl}Çììì9sæ¨Tª°¦G777¥R¹cÇ– ªªjÁ‚lÆiݦ¥¥[Ôªªªnß¾-•JY'u‡BCCO:õÿ÷¬Ç€R©>>lo½uFµZíÊ•+%I³fÍNž>Þ´*ºtéÂqœµµuÓ¦M---£¢¢‚‚‚UQ[[ËV³µµe·±`—Ÿqa¸‹/:99¹»»‡‡‡'$$ôêÕ‹ ']»vmã•IîÅg+<“¿I«Õ–––6iÒ¤ÁÙ©?ýôÓo¿ýVÿ…Ð^Õ\=+:«ç´ù„B]“Xml˜8LÀÝwôΕ+W¶oß0hРz»ª««µZ-ëº}úI¥Ò>}úÊåò›7o–––*Šˆˆˆùóç¿ñƦ·.,--]±bE\\ܬY³.]ºtãÆ í­]»–M”fÜÜÜù|~AAAIIIii©T*íÚµëØ±c[¶lÉ:Ä/_¾Ø¿Ó¾Ëßÿ½M›6=zô(--MMM zíµ×î½½¡D"Ñëõ‰ÄËË˸th||¼««kMMÍ;wØj¾¾¾Ó¦M›1c›cÞ¦M???•JUWWWXXXQQaee³xñâ¾}û622¯¸¸˜­äââââââééóÊ+¯Ì™3gèС¦÷É”J¥QQQr¹üÎ;ÅÅÅ–––“'O5jTMMMçΣ Zµj"“ÉØZèááá>>>ÞÞÞUUUÁÁÁŸ|ò‰‹‹Kß¾}Y/gmmmAAÁ¨Q£bcc¯\¹’ŸŸ/‹ °xñbÖ ÀÑÑ1,,¬¨¨¨   ¬¬ÌÕÕuΜ9ÑÑÑ:®oß¾¬a’Ïç+ŠÊÊÊ’’’²²2{{û1cÆÌ™3ÇxÅzxxôèу5n•–––••YZZvïÞý•W^iÞ¼ùý*J«ÕÞ¼y³sçÎÓ§O¿víû}¹lÙ²ððpã{Çfü‰ÅâW_}õõ×_/..fó¯Y²&Mšôë×ã8V€ÊÊJOOÏ &°…´Ødðˆˆˆèèh</44ÔËË«¦¦&77722’­çïââRQQÁrP«Õ­Zµzýõ×%±µµek¿—––ººº.Y²„…‰‰‰‰O† …jµºk×®ƒfWŽ““Svv¶——׈#L‡‡òx¼N:UWW•””ÔÔÔ¸¹¹5*>>ž5f———³;H………]¼x±¨¨ÈÒÒòÅ_üè£L—M¸×òåË­¬¬V­ZURR’‘‘¡Ñh‚‚‚–,YÒ§Oö± …ÑÑÑz½¾   °°ã¸áÇÿç?ÿ‘ËåmÚ´1'°µµíׯ‹,===‡ ööÛo³ÎcÆŒa…dYyyyUVV–––×ÕÕùúúŽ=ºW¯^2™ŒÇ㱫ÒÚÚÚ÷ßРA{%÷â Þ Œ< …BqíÚ5ÿo%£ÜÂÂâ/¿¼ÿr¡œÇŽu7’€­4ô–A(6Þ u?ÇYYYÝoÎP=§”J¥5dQì_–ç‘ëJ,7r- …Âz T=ö02™¬ñ‹B¡ðÉ,<$ ÿr±*¦ íN$5’9ŸÏo¼óòò6nÜØ±cG'''½^åÊ•yóæÉåò¤¤¤{C[‰DÒȯ‚¿¼ðȃ `ÔÌ8pâ€hmt–*kŸdMZ"Ož•Á*^ßIÜÉEð×ß„ò¬S©T«W¯^¸p¡………Á``7‚>|øˆ#Ì]´ç£æ'á$QÒ¨’Ú ½Å~Éþ*^•¹KDž8­Gœ2®+¯k(ˆÃ¿|]§G`ii™`zBˆ¹ôìÙ“Çã5>œãAxxx¤¤¤=z”XH$]ºtéܹó?:n4‚‚ѧ‚ß)É"ÉEáâYë¹O²/ŸWͫփ¦4‘ŠCM›uL´(:P(âh¨Sš5köÃ?˜»„X±bÅcÉG$EEEEEE=–ÜÈßGÁèSçÈwìkÑ×SíÙZÙ:ß_•Üáß)ã•é8ê¸'“Ø vÖ9»è]œ Î^<¯ö²ön7j%„b.Œ>EDœ(Xì'ò«Ó×Uê+Ëu嵆ZÎ@QyœxàY ¬ùŽ–ß˜àÎ;éééjµšÇãyzzúøø˜î%„<« äq¨««KKKS( î;v,€Õ«W?áRòx¥¤¤4hн»òòò233Ÿ|‘Ùùóçù|~—.]”JeTT”D"ùí·ßŒ{,XàààÀÊÊÊÕÕÕÕÕµyóæ÷ËêÔ©S666ì?U@àíí½aý^ßHRRRø|þÊ•+[ª««'L˜àììÌq¡Pèïï¿eËNÇœ;wÎÛÛ{È!¯½ö+Çq...Ë—/×h4Æ|ÊËËGŽimmÍÊãââ²téÒîÝ»WVV6R¤o¾ùÆo¿ƒÐ IDATÏÏ…wR©´GS§Nuuuýâ‹/X‚Ë—/7iÒdàÀÆ—lÚ´)((H&“±c‰ÅâÐÐИfÛ¯_?ÿE‹µjÕŠenii9dÈ‚‚‚zÕØ£Gc±‡‡Gjj*Û«R©Ö¯_ߪU+¡P€Ç㹺ºÎ˜1C.—7rF„gµŒBž;z½~óæÍ† &‹‡ ròäÉ­[·†††²:tˆ‹‹Û°aC‡¢££4Ò ˜““#‘HÞyç–-[ …Â'N|õÕW“&M  {ðRÍ;÷óÏ?wssûïÿëìì|êÔ©/¿ürܸqÍš5ëÔ©µZ]XX¸k×.kkëñãÇ·mÛ6''ç£>š1cF—.]‚‚‚X>³gÏÞ¸q£——׬Y³š7o~äÈ‘ùóçWUUµnÝZ¯×ßïègΜyóÍ7+++‡ Ö½{÷’’’/¾øâôéÓµµµr¹ü~¯úý÷ß=<<^~ùeOOO•JuøðámÛ¶MžÓI¨&Õ''˜S%Æ}å­O‡§ÞmÖÛÊPÑÖµ~ D"™9sfVVÖ˜1cú÷ïïêêJ§ÓïÞ½ûùçŸ?ÓUôz=Žã,‹õ”_Tªmkkd\N½4 N¼¡ 5=o,/_Äã=pv†Ny`†„BÄbi 6[Zv Gš:¢Wˆ$Éääd¹\Þ¡CGGGã·,--³³³:4wîܶŸP¥Rýõ×_:tØ·oŸ¡ƒ;//ïY³±±Á0ìÑ£GAÒM…BQQQÁáplllÚx[[[ƒñðáCNgh-..V*•Ôü‰D">ŸÿèÑ£êêjÃc!¢õ¹wï^VVÖÈ‘#·nÝjÈ# ¨Äºí,---,,Œ›f Äb1F³±±Ù¸q£qË1àí=Á&F’xuõ½þ¬½=d¢À”,,­­¼¼|±FSdêX^!FsðàA‹õóÏ?Ÿú¿víÚ…¢–dBQ“rþu·!©TªÕj9ŽaBè—_~yÖÆÈîÝ»³Ùì£GVTT ÷îÝ«P(BCC iî¿ gÏžMKK#I!¤ÓévîÜÙØØØÊQL&³W¯^:nË–-†[¾uëÖ… Z9J©Tj4¡PhÈz•Jå¾}û¨ë¶££c@@@uuõÞ½{ûú :tèàì윕•uíÚµfoétºgº ‚ÿbš˜V[\_¿ÙÅEÏ|Ë»FÁ@,FRin]ÝGÇŦŽåUÉÈȸsçN‡ºvíÚì­Ž;vêÔ)+++--­[·nžžž,ëèÑ£433Ã0,$$äÉÚÛÛ»ººfggoܸqàÀz½þСCÔ¢ÂÏX```ÿþýSRR&Mš”  ÓÓÓB³fÍj{2êéé»aƱcÇN™2ÅËËëôéÓÇÿ×yT3fÌ8vì•þ8°®®nÛ¶m­O¥wss‹Å‡îÞ½{XX˜T*ݲeË… Ú¸€€ƒÁ˜5kÖÅ‹7lØ€9r¤……E}}ý‰'>üðÃÀÀ@—©S§&$$̘1ã›o¾éܹ3‹ÅR(—/_~üø1uàÍɨ‰i4EVÁåš:¢Ñ•YWw™$q { 7¶Áq|ïÞ½AP«5{—ÉdŽ1"33sÿþýݺusss›5kÖŽ;"##9ƒÁ¨­­mñ´?üðÃܹs?ûì3[[[ÇgΜ¹qãÆgŠÁ`¬[·N.—Ÿ?þÖ­[T6Æf³ããã?üðÃgJï–,Y¢T*“““¿ûî;„³³ó‚ ~úé§Ö Ù´iÓ·ß~›œœüûï¿s8œ÷Þ{¯gÏž¿üòËÓ øøøLž¢6Gx&ýû÷_µjÕÒ¥K—/_¾yófsss¹\NÄ AƒB4mîܹ‰ä—_~™6mš@  ’Q*o~ÖkÚHFM¬©)Ã!`â22Ò° ŸÏ_±bŨQ£N:UQQa˜µµuHHH—.]Z¹#À›Á”Û?½Ež{;ÐÇã*+IÂ|½æ/~‹å ÊÊ*éOþ¬’o×v o±ÆÆFãm?›ššæÎK£Ñ¾úê«Öw(-//×ëõ†——.]²³³svv.--}…áÞyÐ2jbz}=5ìÖ-´eËÿy«K4{6ÒhÐèèQ¤T¢#Ðĉ¨±­[‡fÎDNN& ¼ZÞà‘ÉD † ÇaáÆ7Ø­[·zöìéîîÞØØxåʕӧO;::N˜0¡õîþØØX›.]ºXXXŸÿ*.¤×ëËÊʨmÖY,–““—Ë}zz½^¡P`Æår[Ù¶T§Ó•––655!„8ŽX,ÍÏW*•åååjµ!Ä`0lmm…Baë ì«T*FÓ¬F£YZZ¶ …$ÉÊÊʺº:„ŸÏwvvþ×C(¦¤¤D©T2 ‡¶,wx ¼sÎ;«T*y<‡Ã™ï߯*óÍ7—.]R(L&ÓÓÓóÛo¿6lXëI3à5€dðnÑét›7onhhØ·o_pp0F{Ž%9ÿÕéÓ§cccëêêºuë6fÌwÿþý”””™3g¦§§¯]»ÖÜÜü¥_´ípß¹sç;wBûöí mÖ¸¨×ë׬Y³bÅ ­VÛ­[·°°0¡PXUUuõêÕÅ‹?|øpÇŽ¡k×®7®¾¾¾K—.Ý»w·²²*//¿yóæ±cÇæÍ›×J2ZQQ‘‘‘áâââââb(´°°h=5$IrÇŽ ,°±±‰‹‹c³Ù)))+V¬hjjúñÇ™O±$•JgΜyúôéîÝ»GEEåçç=ztêÔ©¿ýö[ÿþýÛþܝīܸþ¢T*ïܹ£R©Z|wúôé¡­[·>ùV^Þ`‰‘$|ÁW{ùºI¥§ZüI>pàBhÔ¨QO¾URRòðáÃùGôÚ(•Ê   .—‹ãø+ºDii©““FKHHÉd†ò«W¯º¹¹!„V¯^ýê®ÞwïÞ …ÖÖÖÞÞÞ•••Í*:tÈÂÂB$íÝ»×ø7[}}ý† fÍšE½?~pàÀðáÃÙl6UáÞ½{¹¹¹...cÆŒyrn†a† !”““£ÓéZé%‰D’žžN„H$rppø×¡´·oß&¢_¿~ÆQõêÕ Ã°ŒŒŒ§U__Ÿ››+‹“N++«Î;gggC2 €ÉÁ¢÷¦G’¦Ž¼‹Zþ(I"’¤cý5GóÚÌž=ûĉ¶¶¶.\¸pá§Ÿ~J’äo¿ý¶aêWúâÅ‹gΜ9rdVVÖ”)Sôz½áp‚ Ξ=»yóæ‹/^¸páÃ?|òUUU¥¥¥,«wïÞO¾Ë`0¨òfÉSJJÊàÁƒÏœ9sñâÅŸþÙÒÒréÒ¥/^¤Þ•H$Ó¦M{ôèѧŸ~zöìÙ‹/?~<00pÕªU'Ož4>ÏÕ«W]\\RRR.^¼xìØ1OOÏܾ}Û¸Õ¬Û¯_?''§=zx{{_¸p¡°°ÐPáÁƒ …ÂÏÏÏÆÆ¦õçùþûï3™Ìÿþ÷¿qqqû÷ïÏÍÍ•J¥­bl×®]½zõêÕ«×{ï½7nܸ»wï¶^?//!äééi\hggÇçó  E‹G)•J©TÊårÓh4___‚ JKKÛ0àU€dÔÄX,•ÊÔA€w‘e‹¥:"“ùò'ô´ÖÖÖžžž ƒF£y{{{{{[[[ëtºíÛ·c¶råÊ‘#Gº¹¹…„„lÛ¶ÍÉÉéÖ­[iiiÆgøä“O&MšäáááééÙ±cÇ'/Q^^N’¤½½½……E‹1¸»»#„JJJ‚0úøølܸ188ØÍÍm„ ³gÏÖh4»ví¢Raªw~È!Ë–- tppˆˆˆX±bNÿí·ßtF;³9::&&&vïÞÝÑѱ{÷îÓ§O×jµÍ’ѨÕêÑ£G³Ùl.—;räH©TzôèQòŸÿSÕù|¾¡­ôi¦L™2g·³ÿþ>ú¨wïÞQQQK–,1Nm[dnn2vìØùóçOŸ>ÝÒÒòÏ?ÿ7nÜýû÷[9J¥R™™™5[‹Á`0™L­V«6,¿üéõzµZÍápšÍ¸§î®ºººõP¯$£&fn[σöC«E$)f2LÈk¥Óénß¾Íáp>øàC¡@ >|8Žã7oÞ4Òh´¡C‡¶~6­VKÕl½ŽãÆ/ d<²3&&†Ãᤧ§S‹q^¼xÇqÿ»wïÞøFc³ÙyyyÆIXXX˜ƒÃÿÿøüýýY,VQQ‘¡¤¤¤äìÙ³žžž½zõ¢J¢££Áü!“ÉZùI<oÕªU§OŸ^½zõСC­­­³³³bbbrrrZ9púôéçÎÛºukBB† Nž<9xðàÜÜÜ7çèOÂ0ìYcÂq¼ÙÓ6F}^‚1£&fnTSÃÀq=ý­ío• ±Ù¾ †•©y­*++µZ­«««ñÀJ Ã|||BµµµÆ•ÿµçÚÕÕðªª*FÓâúM%%%!jº½¡ÐÃÃÃ8Dz³³c0 …‚ÊÌB+W®\¹re³³q¹\ãb±Øxì&•ºÉårCɱcÇjjjøøñcªýÇq[[ÛŒŒŒ¬¬¬ž={"„¬¬¬0 S(Z­Ö0Aêi Fhhhhhh|||mmí­[·¾üòË{÷î­^½zÇŽô§üj³··7~éââòõ×__½zõÚµkR©ÔʪåŸ@&“©T*›%Í8Žëõz&“ù´v\‹eff¦Õj•J¥ñ'B¥¡Æ¹;À$ 516Ûü¥Òû"‘©Cï<½Õ×Ó‚^¦äu£š$36Jcc#BèY¨wpp‹ÅÕÕÕ7oÞìׯ_³w ‚¸~ý:B( À¸¼ÙxG­VK’d³æÕ„„„nݺ5;!‡Ã±´lyÐÅ“ôzýþýûqOIIIIIiöî¾}ûÂÃÃétzÇŽ-,,=z$‘HÚ¾+5÷+::Z«ÕŽ7îÎ; Ôìõ¶°³³ãñxR©´•dÔËË ý“Í444Èd²°°°§ínenn.äryuu55F!D’dQQ†a­¯±x 51ËÁÖö‹ŠŠÙêv°' xw‘$ª©A$.O0u,¯›¥¥¥D"yüø±ar A†Ò—6¢Ñh111[·nݼysïÞ½ŒÿóköÒ¥KÙÙÙ 22Ò¸üîÝ»z½ÞPùþýûZ­–jEyxxPåQQQ/²cÕüéïï?cÆ ãT•JµråÊ“'OVUU9::y{{ß»wïï¿ÿžûL üùçŸ7nTMQÌÊÊš9s¦N§›;wn³&ÃS§Nݾ}›šB$—Ë·lÙ¢Õj DµË>ÜÌÌlË–-¤ÑµµµÏ4ÿ&99Y.—;ö“O>™e$>>~РAEEEçÏŸGñx¼O>ù„Åb-^¼øï¿ÿ6ÐÔÔ”œœüÃ?P/7mÚ”žžn<ìR©T;vL©T:;;?mówµZ]QQa<޳®®nãÆ‰$ À°oS~~þìÙ³—-[FmFŠŠˆˆpvv>yòdjj*UòðáÃ}ûö ‚èèhÃÙ:4{öìƒR/Y,ÖðáõZíÏ?ÿLŠ ˆãÇgffúúúvêÔ©íð*@˨éÑhæNNK n9:&Ý#¼‹pÕÔ š¾µõ\î;×G¢Óé_|ñEJJÊŽ;"##‹ŠŠ~ùå­V;þüçSHMŸ3gÎW_}uöìÙ!C†XYY¥¥¥:t¨¼¼<::ú‹/¾hÖaØèÑ£§L™bccsôèÑÓ§O»¹¹M™2…j•ìÝ»÷ĉ“’’ÞÿýÑ£GwèÐÁ`äääœ9s&666>>¾-QI$’?ÿü“Åb :ôÉÆÎ˜˜˜ääääää?üÐÌÌlìØ±999›6mŠ}¨å“Ξ={ãÆ ÃšV;vìøî»ïzõêìîî.‘HÎ;wöìY‡3yòä§­'PZZ:qâD//¯°°0++«²²²ãÇß¼yÓÝÝÝøÉTTT$&&Ìœ9“:•»»û´iÓ¾ÿþûÉ“'O:ÕÒÒr×®]yyy“'Oîܹ³áüW®\ILLd0£F2ÜÝž={Nž<;bĈÇoÙ²…Ãá,X°àY‡a^>ÓlüôÖyîí@ ´ÚŠ’’ù™™üŠ ÔÔ„4D¦ß¾ÞÞ/N‡T*$‘ ‡iÙÙ¥Ò“¡kýçüíØ´©©),,ÌÛÛÛ¸ ˆ3g΄††R\h4š³³óÂ… år9UÇñèèhGGÇâââ6^èäÉ“‘‘‘†v>333ooïeË–Õ××Wûé§ŸB ,:t(5ê‘Åb………?ž C5¹\¾lÙ2ooojF‹Å‰DÁÁÁþù'U!##ÃËËë‹/¾0>ùùóçÝÜܨµT©wРAOF[UUêããSPP@•¨Tª={ö„……‰ÅbF£Ñ„B¡››ÛçŸþàÁªÎê¤O%O IDATÕ«ÃÃÃíìì¨ç†aŸÏ ݽ{·F£yÚ“)))éׯŸ 5åˆF£Y[[÷ïßÿâŋƷ|ãÆ {{û¾}ûJ$CaSSÓÂ… ét:uàÔ©S«««Ï¿páB{{û… fee–,`2™¾¾¾Û·o×ëõO ðÚ`$ K®¿*•*//Ïßß¿ÅÿdϘ1#))iëÖ­3fÌhå$$©—ÉÎUWoÑj`X .e³‰ÀS„™ZM⸈F³çñØÙÍkËÚ¢ÉÉÉcÆŒ5jµÃ±ÒÒRµZíííýjâ}™‚(,,$âÉh%INNŽL&c0Ôtƒ’’•JåááÑö­†4̓¨•G---}||ìììšÕY³fÍ_|±iÓ¦‰'fffJ¥R‡Ôâ$žŠŠ j-'‡ceeåééi˜µ£V«KKK¹\®ñ%šššÊËËy<5(¶¦¦ÆÒÒÒÁÁ¡Å§………Z­ÖÉÉɸE³±±±¨¨¨ªª !$‹­­­›­ V« ëëëe2F‰D>>>­Œ(¥Èåò’’’ÚÚZ¥RI§Ó<==›-> T*KKKÙl¶³³³ñ¬|Ç ¨ÑÑÑÑ××·Ù”ÿêêj©T* ›-}ÐÔÔ”““SWWÇf³}}}œœZðz@7};‚a > Ÿ¥×7hµÅM™V[òï‡ðìètXìÄb9²XÎ4Ú»ÕMI£Ñšmác  ©µZäââò¬×b³Ùm©laaÞz‡§ àp8O¦×ÔU!¡Pø´Aœ”§jñùü   V6Ìäp8þþþ­‡ý$.—Ûâ–ÆÌÍÍ}}}Ÿ,§ÓéÔ†O;ÐÖÖ¶ÅE,,,ž¶=À„ m‡0CÄ`ˆÌÍCM À«³éÀ”„B¡@ 0u `Ð2 ¦4vìØ÷ßÿiÏà­É(˜’™™™ñ6¤ð®nz`2Œ“d˜ $£Àd ¤Óéär¹V«5u ðÎÙô€þþûïŸ~úiÖ¬YãÆ3u,¨±±Q&“UUU•——óùüÞ½{o†Ùv¥¥¥<ÈÎή¨¨àóùvvv½zõòòò2ÞÌ!¤R©¤RiAANïÛ·oÛg÷«Tªœœœ7nh4„££cxxx³Ý;_"‚ ª««ïÝ»—žž.—Ëœœ‚‚‚ž ÇñÜÜÜK—.Q[§¾÷Þ{þþþOFUSSsáÂ…ÒÒRæçç׫W/Ãöª!’$«ªªrrrrrrªªªÌÍÍííí{õêåííÝì^$£í A’ µ¶Q¥nP(keJ=Ž›:"ðv¢Óiæ,¦ÈÒ\Ä5çrØæ»þ« ººúúõëÇ7u èØ±cË–-£2Q½^ß¹sçË—/7Û´½fΜ™’’Âf³¹\®V«•ËåÖÖÖñññóæÍ3læž™™ùÕW_=|ø°²²R¥RÙÙÙ¥¦¦:;;·åüyyy .b³Ù%%%Û¶m{‘{\³fñËnݺ±X¬Ï>ûìäÉ“ÑÑÑÔ½„……]»vºô_ý%“ÉÚrf½^ÿÃ?¤¥¥ }º¬¬ÌÍÍ !¤ÓéU*ÕêÕ«§NŠ ¦Ñhüñ¦M›z÷îMùòåËçÏŸˆˆX¿~=Õ5ïîîyðàÁ™3g"„8Î?þh@×®]™Læœ9sŽ?É(/ ŒziJëÏå¨iL¾HÄ`² ¯ F3çò,„V÷«%—óŠô8aêˆ^‡ÚÚÚY³fõîÝ»{÷îýúõ[¼x1•Ójµ{öì8p`DDDxxxddäüùóŒë¨Õê}ûö <¸gÏžááá½{÷މ‰IKKkñ¢W®\:tèÊ•+ âÿ<äôôôèèèE‹éõz„¹¹y³lõ%¢FsÊd2’$©‹õcîß¿üøq@°téÒf©|TTT\\œR©LJJ¢’"„H’ÌÉÉ™9sæ{ï½Þ£G,[¶L£Ñœ` &‹keU&U<¨¬3u,¯œ\.Ÿ2eʶmÛt:]TT”ÝÚµk›uˆ±f͚ɓ'çääøùùEFFÖÖÖ®Y³æ?ÿùÕŒ‡Âqüë¯¿Ž‹‹»{÷®››ÛÈ‘#ýüü²²²rss[¼npppfffbb¢\.7.ß¹sçÅ‹}|| ½Ì¯Žã¥¥¥{÷îÅqÜÐ:øÜ®_¿^WW×¥K—Ž;6{‹F£1‚ËåfffÖÖÖR…©©©#FŒØ±cI’}úôéÓ§†a§OŸV©Tl6›ÏçcÆb±D"‘H$²²²jû£hhh¨««³°°àñxTIMMMee¥“““£££¡šH$ruumll,//G©Tªû÷ï›››ûûûGJDFFF‹×Âq¼¼¼|Ïž=L&sÀ€mŒð¯Þ•.¹v‹ É{Å•2Áµu°?¯Î0çñî–TÚ ¸V–oóVé|X(q¾tß}÷]NNŽV«ÍÍÍ­­­7oÞøñã_ðœÙÙÙ$IvèСÅ1 ®®®b±¸¢¢¢¾¾ÞÉÉI¡P|óÍ7S§N]¶l™X,F)ŠÇ[XXDEEY[[÷ë×oÀ€Û·o¦0t:]RRRqqñèÑ£]]]©Â’’Ngoooœp››› …B¹\^SSC]½ººÚÌÌL(ŸÐÎÎ!D%¬fåÊ•YYYZ­–šé5cÆŒØØØg Ð h‡31™Jó¸FbÉçC›(09›££1ò*kMÈ+¤Óé>L§Ó?ùä///„F‹íÙ³§qµ#GŽ(•ÊáÇæ×{yyÍŸ?Ÿ$ÉP%»wïÆq|Μ9†L!äîîn<­»™¸¸8ƒ±gϪG!tüøñÚÚÚaÃ†ÙØØ¼Ü;5xøðáíÛ·oܸQRRbffÖ±cÇŸIõ¿f7Ãf³ †J¥¢ÖmÍÎξ}û¶§§çâÅ‹©L!diiÔÆN-"bß¾}7ntssûæ›o §Âq!dh(5°±±!I’#ã¸N§{òœÆ©$I>zôˆz†?¶´´ìСËDh kTªµbÀï5Ð`›Ã©•5¾}t:ÝÇY,V= …L&³_¿~†—AäææÒh´fóoˆÊÉÉA‘$Iuæ6¬íWïÓ§‡‡ÇÅ‹KKK©’}ûö1~üøW·tFbbâ7Ο?¿cÇ7sæÌýû÷¿àGL¥bO›íDI’t:š#•››+“ɺtéÒbª÷|‚8qâÄ×_mff¶nݺ€€€fžl-†aO›‹öd!›ÍÞ´iõ ·mÛÆãñ>ûì³={ö¼ðMþ’Q«W(™,˜±Ú :ƒÙ¤Õ5iZh4z;$©Ñhh4ŸÏ7.7´ØQ´Z-†aÍæÊPuêêþ7¬V­V£:vÛˆÉdŽ;V£Ñ8p€$É¢¢¢ .øúúFDD<ßí´…P(´··ˆÝ¼y3‹ÅÚºuk³q«ÏŠjÇ-((h6‹ÒÐÐ —Ë­¬¬¨¹A*• !$^äŠÆ¨LtêÔ©:î¿ÿýïСCߥ=h–VÑÔÔÄf³---BfffàÉöÑÊÊJ„ñº÷! Ãõ 'NœøóÏ?ã8¾~ýzÖà%dÔÄêäM ÖÿoÕiµ õ²†züŸ^<„ªIÑX_§U«©—$IjÕj²¥¿´ÑÓšÅhtšŽ •oﮘ†±Ùl‚ ¤R©qyEE…ñK‹E•š4«cÈ>©] mœmôŸÿü‡Ãáìß¿_£Ñ$''+•Ê>øàùÖ´;v´´´¬¨¨ ÄçÖ­[76›žž^UUõä»·oß®­­uww§rV Ãêêê^J‹;I’§Nš:uªR©\³f͸qãšMÆrtt …………ÆM¡õõõEEE<Z`aaáàà P( “ë)yyy!??¿Vðõõµ³³«¯¯7ü·ð‚ 51ž ýÓ=W]V’øíç?Κ´rÖÄ]+—hTJ„Pö­ë?ΞüãœÉ뿚[UR„’ÖÕ&%,¨©(kå´´N÷”%œh4ºžDÝ[ÛäÃd2;tè ÕjÏŸ?o(Ôh4—.]2¼¤fU“$yôèQãcOœ8êСBð.]º „Ž;öLøùùõèÑ#33óÆûöí£ÚJ[ì2n]]]]MMM‹[QZZªR©,,,^pæ~·nÝ:uꔟŸOMÏ7~«¢¢bãÆ$IŽ5ŠšÀçóÓÓÓ‹ŠŠZ<“Éd0ÔÔ¢Ö‘$yëÖ­Y³fÉåòE‹}ôÑGO. ààààççWVVf<)þÑ£Gùùùîîîžžž!:Þ»woNwâÄ Cã®R©¼xñ"›ÍîÖ­[+1ÔÕÕÕÕÕ±Ù춬Òh HFÛ ×ï_÷c“¬qÒ7 ¾\ìâí‡ã¸BÖ¸ýÞA!“¿ùžÀñÃII’ÔiÔùY÷4ÿ¬/h;&“9zôh’$ׯ_Ÿ––¦Ñh¤RéöíÛ¯]»f\-&&†Çã}¨¬-º{÷îîÝ»ËÊÊÔj5µ®~nnî¢E‹d2Yß¾}G)Ô×××ÔÔÔÔÔà8N„á¥Þ¨¦¡P¸`ÁKKË+Vlݺµººš •J•——÷ñǧ¥¥uïÞÝ0g¿cÇŽ=zôxüøñ‚ òóóÕjµF£¡ö_¥&Bq¹\.—[TTTPP P(”Je‹½ÿ¡ôôô &”——Ïž={ìØ±‰¤æÚšóy<Þ¨Q£ ÅòåËKJJp/..^ºt©N§?~¼aûaƹ¸¸:t(%%…ÚÈtß¾}—.] §êdee%&&–——žáƒ¾üòKFóÞ{ï5éxn°´S{¡U««ËJz æŒa˜_h„PQ^n}Ue¿˜1önQcb·ÿm“¬ÑÔ‘ðf‹‰‰=zôÞÿý†††ÌÌLŸû÷ï길¸,[¶ìË/¿œ2eJHHŸÏ¿}û¶D"ùàƒFMÕyï½÷¾úê«Õ«W?>00ÐÙÙ¹ºº:''gýúõÞÞÞ­meeEµÛÅÆÆ6›—••5yòdFC„R©|øðáÀ1 ëØ±ã¯¿þJåRAý½C-ùü†êJ“i)"„Äöz®±¾ŽÉb™:XÞ`fff‰‰‰üñGNNŽX,^±b…³³óŽ; †a³gÏvvvÞ´iS~~~EE…‡‡ÇÈ‘#?ýôS–Ñ?ÀÅ‹‡„„lÛ¶-77·ººšÃáLš4©oß¾­ >ýôÓk×®q8œ'—e³ÙnnnT–I->Eqpp0ôæh4š:Wh&444!!áĉ………Ã0ÿaÆÅÅÅ5›tEmË„j–z¶¾zƒÁ˜>}zPPÐîÝ»¯^½zûöm:îëë;þüqãÆ5[©*888%%%111%%åþýût:ÝÓÓsÚ´i!:þÃ?SƒPY,ÖÓÖä÷÷÷7^H˘ñ¸[‘H´{÷îuëÖ;v,==ÇãÅÇÇÇÇǯ*J£Ñ¦N*‹þùçû÷ïc6pàÀ¹sç|!!!+V¬8}útAAZ­¦Ñh~~~ÑÑѱ±±Ï4q Ð:ì-^Ãåu¢ú§üýý[E4cÆŒ¤¤¤­[·Î˜1£Ù[Ç3ÈhL6Ç !¤njºqúï›§Oäf:yúÌûqÃÃ{wöþwùSÌ,,+‹ –}<áË;8ffË?Žûü¿[\|ZeÀó‘ÔÖDù»9‹Zè‚LNN3f̨Q£’““›½UZZªV«[olo”J¥\.‹Å­/«ÔÐРÓéZ¯&‘H´Z­P(d½–ÿ+8p`„ ›6mš:u꿎7¥†"0 ++«çœÚz½^"‘0™Ì2¯Õj% ‹Åj¶Úü+BÝ»@ he‡U‚ $ Fk%$*l:ÞlÕÀK-£íÇ¢o̘¾1cJæ­þdêÝë—œ<¼õZ­J¡0³°l’ËÔÊ&hàe177oË4v++«­ózR+ƒ‚‚‚>}úŒ5ª-É%›Í¶µµ}¥ñ0ŒfË`= ‹ÅzÕÁk˽Óh4‘HÔz×6ï˜ÀÔŽT=–K%ZµšÉbÑ ’ …Ö6l3³ÂûÙZµ*ãÊk'k'„I’MòF™¤A&iP4JI–yàòõ×_Ÿ>}ú%®Ü &-£íÈ‘m›Ë òùV¢†ê* ? {„ÐÆ®Ç ÷w¯Z*²µ/y”÷Õw &ÃhzvÛÒo©}›„Ö6sW®·äß%¼y mG&Ì_Töø®ÓÑèt?*¿Œ™>' ¼gÖ+E‘!Ä‹ç¬X‡ÿ3‹–ÉfsÌ-L7Àó‚d´á „þ»6+d0™~¡]|‚BÜ=u:-BˆÅæYØÔÔ$Àf žÖzch»ÌÌL;;;SÀë¦Óé²³³ÝÝÝ!ð¬ [í¥±´´”Éd¦ŽÐét8Žs8SàÍÉèK# %‰R©4u ¼V$IVWW³Ùl6›mêX¼y }iÇ+(( ÂÔ±ðúH$’ššwww ÃL €7$£/ †annn¦¢¢Fâ‚w„J¥*,,ttt´´´4u,ÞH0é%“H$<îîîÐk ÞbAÔ×× OOO:nꈼ‘ }ùÔjõãÇU*•Ç377§ÑhЃ Þ$I’$©×ëårymm­L&sss³±±oÏ ’ÑW‚$ÉÚÚÚšš…B233c0`IWðÆ#B­Vët:‡Ãçóa=€Éè«E’¤Z­V«Õ8Ž›:^†a,ËÜÜ:å¼,Œ“ÙôÀd` #o’$ssse2ƒÁðððpqqÈÞÐM@{‡ãø;wΟ?¯R©¨ ü½½‡ {ÁxÓA2 @»F’äõë×Ï;÷äÎ^ÿùÏx<žI^ 3 @»V^^~õêÕ÷˜­¨¨¸|ù2l? àc΀ièt:È¢Ú"##ÃÐ;ÿ¤ôèÑÃÊÊêu†¼DŒ b÷îÝeee¦ä'—Ë $£Þ\ŒÓ`2™,ËÔQ¼ôz}ëMȰ'€7$£Àh4Z\\œ©£x3œ9sæÚµkO{—Ïçs¹Ü×ðrÁ&Úµààà§¥›†ðùü×ðA2 @»fmmÉf³›•cæááѳgOè¦ðFƒuFxäææž9s¦±±‘  ØLf```ÿþýÍÌÌLðB í‹^¯'I’Éd¾”³ã8N§ÑÞøN­V[XXX__Ïf³]\\Äb1´‰x ¼ñ¡A;ãø±cÇ _ä$AÄÆÆöéÓçeEuðàÁ¾}û>|¸í‡œ;w.77÷eð±X,__ß=z„†† C&zòäÉö0ÐŒ‚—C¯×9räáÇ/r¶wïÞ[·n½¬¨ÆŒTSSÓöCþú믌ŒŒ—À«pï޽ɓ'+ êå©S§ ðæ‚¥ÀËA§Ó©îuFƒÂ0,??ŸÏç;88$©ÕjBL&“F£Q¨I9UUU‰ÄÊÊÊÖÖÖ¸ßY¯×ëõzª†a:îÑ£G ÃÃÃÁ`P=zD’¤‹‹‹……E³>k¹\žíââbˆb¸(AZ­–Á`0 N‡ã8ƒÁ(..Öh4ÎÎΫV­¢Óé!­VæFH IDATKƒÁ(((`³ÙÎÎÎT_¿^¯/((`±XÔ}Ñh´fƒ šššJKK †‹‹ ‹Å¢.aƒÁ !Pw¤T*KKKétº³³3õ(H’”H$UUUÇÉɉ :?õ4¨§'—Ë+++U*‹Å¢Ñh+V¬ u¥¥¥$I:99™™™QÃ0•JU^^nkk+‰^ŧœ$Éýû÷{xx$''WVVN˜0ÁÑÑ1..nùòå)))!!!?üðI’ÕÕÕƒ 9r䨱c#"">|X\\üá‡:99EFFvéÒÅËË‹J߀ö’QðÒÌ›7oíÚµ$I666²Ùì«W¯±xñâ™3g’$yìØ1­V«Ó颣£‹‹‹+**A^^I’¹¹¹–––õõõT2Z__?tèÐ 6Pgž?þ¤I“t:N§ëß¿ÿöíÛ ---sssõzýúõë+**Œ#™6mÚÔ©Sq'I2,,ŒJF‹‹‹ýýý I’ëÖ­£’QªÂòåËqÏÌÌ,**Ч’Q’$mmm÷íÛG’äúõëGŽ©ÕjÿøãÐÐP©TJ’ä‚  ¤R©Œ/=eÊ”¹sçj4FÓ³gÏýû÷“$ùûï¿»»»¯[·nüøñTóæÍ›>}:U­ÿþ;wî”J¥‡&I²¨¨hÞ¼y …âÈ‘#T2J’ä‡~˜œœL’äÍ›7 ÐØØH•þùçT2ºbÅŠaÆ©Õj’$gÏž=qâD’$Ïž=ëææVXX¨Ñhz÷îýÛo¿½ÄOxq0f¼L&388Ã0[[[ªdÀ€t:ýï¿ÿÎÈÈàóù...™™™t:Ý××!äíímaaq÷î]„I’QQQ………3fÌ Ž½qãÆ•+W"#####óóóïܹãêê×½{÷ÈÈH±Xlccc|õ¬¬¬Î;S½ê]»vý×hÃÂÂh4Z@@€««k³·z÷îòôô$I’ ˆ´´4*T„Phh¨¡Ü ##ãìÙ³QQQQQQ%%%÷îÝC3&::zÉ’%óçϧŽMMM½téUíñãÇ™™™%%%jµ: !äêêºnÝ:ªfÛedd„††R=þ!!!¹¹¹Ô¸R777jÀ€§§§Z­~¦s¯Œ¯Fk–K±ÙìiÓ¦mÛ¶ÍÍÍmÒ¤I!'—Ëu:“ÉÔjµr¹œÇãQ•×®]»hÑ¢øøø 6`Æãñ¢££¿üòK„УGBz½þÛo¿]²dÉŸþ9gÎ++«Aƒ®Åãñ”J%õ½L&3”+ jŸ÷ÆÆFãØÁÓn¤YºÉçóe2™^¯g0jµúÉ]ãy<ÞäÉ“gÏžM…J­ª×ëÄbñ/¿ü²zõj&“)‰>øàƒøøx„PAAaô*5²V«Õfff`¦Õjõz=N7¾ ŽãÆKVßµJ¥233c±XÔgñ¬làm¢ÀËã8µ¨'AÔ4Ng(Áq!{ëÖ­¬¬¬~ýú!„BBBüüü¶lÙ¢Óé¶oßîåå¬×ë1 ß½{÷öîÝ‹ãøèÑ£wïÞ]]]]SS'•JËÊÊbbb Ƙ1c<==u:q0111û÷ﯪªÊÏÏ?þ<ƒH$ÒjµÇŽKMMýý÷ß©¨¨Põz=•V¦îý³î)ÕããøÀ>|˜••ÕØØ¸gÏž'“ÑÑ£G:t¨ººº¼¼üã?®ªª"bݺuŽŽŽÇŽ;räu阘˜¿þú«¢¢¢²²rÖ¬Y¥¥¥nnn;vìP©T‡þñÇõz½P(,((¸téÒÒÒҨؘL¦F£©­­‹‹+,,4Ä\£Ñ¬Y³æ¯¿þŠ‹‹8p Nïß¿ÿùóçËÊÊ–-[fkkkkkÛÐаwï^‚ ¢¢¢ÒÒÒœœœüýýý$6›Ò½{w×bàÝô´wµµµÆÝô†4”Ïçkà -£àÿ±wßñQTëÿÀ?³}“l6uÓ©@º@ H 6¼Š¢ˆŠ/"vìÂÅ~Q¸P¤JiB 5ÔÒÛf“ì&ÛûÎï¹Ù_B3ÉJxÞðÚìœ9çì²3óÌiCn†Bi{(%ä6 ‹SRR( %„ÒöP7=!ÿt6›Ín·{yyQJ!¤í¡`”´Z­öìÙ³2™¬k×®-·eeeétº>}úˆÅâk§,)))))ILL m‰šB!m-zOÚFóõ×_¿òÊ+‡£…Š8vìØ¸qã¸%¥¶nÝúì³ÏšÍ櫦,((xõÕW7mÚÔB5!„BÚ FIÛóÐCqK8µçŸÞËË‹ëOHII?~¼{=¦Ë 4¨k×®-ZB!¤   L¤ Z½zõÑ£G‡ 2vìØ½{÷fee}:''§sçÎÏ>ûlVV–B¡øóÏ?:äëëëíí½bÅŠ   ¨¨¨÷Þ{oéÒ¥=ôPMMÍĉÍf³^¯ðÁNç„ ~øá‡¯¾úŠeY??¿yóæ-X° G7näž·@ °,ûí·ßšÍ怀€mÛ¶½ôÒK"‘Èn·Oš4I­V»ëãt:ùå—ÊÊÊÆkÝB!„C-£¤­INN~çwÄbñúõë³³³Ÿxâ‰3fÌž=;<<¼¨¨(99yðàÁB¡P(Μ9³G:uнxñ¢R©¬¯¯ïÕ«—Ëå>|øªU«^xá…{î¹G(~þù牉‰ãÆ“H$\)‰¤OŸ>«V­””Þ³gÏW^y¥²²ò÷ß×ëõÜ““ª««§L™òÄO<ÿüó×óD!„Ü(%mX,æžçÉãñt:€!C†0 ³cÇŽãÇ?ñÄB¡K€[¹³¤¤¤¦¦F«ÕîÚµK(²,;nÜ8àˆL& •J¯Q®Ã0<Ïétº‡Š~÷Ýw‰¤sçÎî¬!„Ò] IÛ'‰&Mš´téRƒÁ0wî\÷û/^LMMU©T,ËvèÐÁÇÇÇÏÏïwÞñõõ-..^¾|¹û!õ·lÚ´i÷Ýwߘ1czôèñÀüÍÜ!„¶‡ÆŒ’¶£¼¼|ûöí•••Û·oß½{wIIÉÞ½{ <üðÃ'Nœ:t¨···;ýÂ… ׬YóüóÏß{ï½ñññ ˆŸ9sæš5k^xá…èèh±Xü믿Z,–¥K—Fk×®5 ÿý﫪ªþøãÊÊÊmÛ¶eddäää9räüùókÖ¬1kÖ¬Ù³gÏÅ‹Oœ8a4»uë6mÚ´%K–4µ!„rÇ¢EïIÛQ[[{àÀ–e£¢¢„Baaa!€~ýú………0`À?üÇ%ö÷÷ß³gω'$Éøñã}||ÆÍ›7×ÕÕuëÖ­W¯^|>ëÖ­‹À¨Q£$ɾ}û¸ÉIƒ :tèÕj •Ëå¹¹¹zôè‘““c4%Ixx8WN:šÍf__ß4µ!„rg¢`”´quuu«V­jß¾ýÊ•+—/_ÎÝÌÊÊJKKÛ°aÀø|¾§ëH!„ܹ¨›ž´}GŽùí·ßÞ|óM÷,¢<ûì³™™™-÷¬&B!„Üj%mŸÃá`†Z@ !„ F !„BˆÇP7=!„Bñ F !„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!CÁ(!„Bñ F !„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!#¸ê»,ËšÍf›Íær¹Z¹B„B!¤Íàñx"‘H*•2 sÕ—£555*•Êh4‹ÅÁÕ£UB!„B®ËápØl6–e½½½ƒƒƒ ÅeQ)ò,÷Êjµêtºððp¹\.‘Hø|~S1,!„B!×Ų¬Ëå²Z­Z­¶²²ÒËË+>>^,»ü/Õét999¾¾¾1117B!„Ò,l6[qq±F£éСƒ¿¿?÷&ò¬Ãá8uêTxxxxx8GSš!„BH‹`Y¶ººº¨¨¨{÷î"‘Ülú¢¢"‰DA‘(!„Bi9 Ã( __ߢ¢"îžN§«©©IHH á¡„B!¤¥1 ¯Ñh4 þ”)SD"Qhh¨§+Fiû\.—F£ …|>ÿ–3Ù°aƒÁ`oÆŠ]‰eÙšš‰Drk]Füå—_ªªªjkk/]º×ì5¼)•••kÖ¬IJJ …Wn-,,ܺukRR÷ÿb0ŒF£T*mõjBî|>ßn·›L¦€€ž^¯—Ëåž®!äŽPQQ1~üøêê꿓ɶmÛNŸ>Ý\UjJYYYZZÚ­­µ\WW÷È#H$…B‘———}#{Mž<9??Ÿ{½~ýúÅ‹_;ýƒ>XWWwƒUÒjµ´ÛíWÝZ\\¼fÍ÷Ö·ß~{íÚµ7˜3!„Ü™L¦×ët:]»ví<]BÈ!##ÃÇÇ'444??ßßß¿¼¼œeÙ:ppjµº´´ÔårÉd²ÄÄDn–e+**T*Ç‹‰‰ñóósçæt:óòòÄbqddä¥K—, ŸÏïÔ©“»ñO¥R•——ûùùqc䣢¢Øíöììl»ÝÂqñâE‹Å"¹ÊìÙ³'%%E œ?>666//a˜¤¤$–e¹à²sçÎ|>?77W&“qÍ´N§3+++11qË–- 䦦FDD´k×ÎápÐh4Z­V(–••ÅÅÅùùù?žeY‰D’˜˜XUU•‘‘1dÈ­V}ôèÑòòò¾}û*ŠÐÐм¼¼Ž;r ÜëK—.íÛ·ïøñã]ºt …UUUb±ØÝÀ™››«P(*** C‡^yå///—ËURRÂuµk×.((è²ÿ£úúúÝ»wÿë_ÿjÉ!„À×××h4²,+àãããéúBÚ>§Ó¹cÇŽÑ£G[­ÖÙ³g«Tªššš   åË—ûúú.X° ''ÇÛÛûÂ… S§N|X¥RýðÃr¹|Ò¤Iû÷ﯯ¯ÿì³Ïî»ï¾aÆ=ûì³»ví’ÉdÕÕÕÏ=÷ÜŽ;~þùg“É´xñb‰D²téÒ'N̘1#11±¤¤¤_¿~óçÏ‹Å3gÎ4™L~~~'Nüä“OV¯^mµZ§M›æëëk0ÊËËW®\Ù±cÇÆÿMgÏž jß¾}ëÿB!w±X,‰l6ÒÓÓYBiy•••={öÌÊÊ2÷Þ{ï+¯¼b0 ’““þùg–eëêêôz}yyùêÕ«“’’,KEEEûöíW­ZeµZõz½N§cYvòäÉ .œ>}zjjê… X–5 uuuæôéÓ½zõÚ±c‡Íf{ä‘Gž|òI£ÑXUUÕ­[·iÓ¦¹\®Ï>û¬_¿~Æb±|ÿý÷Ç7›Í:tعs§Ýn×jµ\uuu¡¡¡J¥Òf³ÅÆÆ~üñÇ‹%''G ,X°Àb±œ>}ÚÇLJeÙ¬¬,///®‰÷‰'ž˜9s&sÇÆÆêõz»ÝþÑG½ñÆ,Ë®Zµ*""¢¤¤„Ë*<<¼¸¸Øn·k4›Íf³ÙºtérôèQ“Éäp8æÏŸÿÒK/™L&›ÍVZZÚ©S'­V˲lYYYJJJ]]ÅbQ(ÅÅÅ\ú^½z½ÿþû&“éܹsááá;wîdYvÀ€Ó¦M3 ƒáرcýû÷×h4‡C­Vsßü“O>9wî\–e÷ìÙ3zôh®‰â7Þxíµ×\.—‡~&„;ÈÑ£GÍf3=í“ÒJÎ;'‘H:uêd³Ù$É}÷ÝçííÓ¥K—“'O>úè£ëÖ­[¶lÇ …z½^£Ñ\¼xÑápŒ7N$q]íœÏ?ÿ¼}ûöëÖ­‹ˆˆP^^>sæÌªª*__ß²²²¢¢"«Õš››ûÖ[oyyyI¥Ò¾}ûp8ƒaÚ´iÌfó±cÇAZZÚ³Ï>›––6räÈ1cÆØ¿rrrhh¨ÝnçñxC† ‹Åñññ!!!cÆŒ‹Å]ºtá›Ü¥K—~ýúýøã“'OÞ²eËÁƒ¹ú3 #•J/›§Õµk׈ˆ>Ÿß®]»öíÛ1"--mܸqÇçñx<O,sƒ„B¡@ ¸Æ"±XÌ0ŒD"‘J¥J¥²°°ðJ¥)))ÉÉÉçÎ:t(îKàž†U__ÿæ›o?~œkg½l«ÕºwïÞO>ù„ÖW!„´ F !­eÙmÛ¶ 2D p)ææq7Ç ªªê“O>Y¶lYJJJyyùèÑ£Y–‹Å.—‹sÙX¯^½ÎŸ?¿wïÞ‰':Îùóç'$$,[¶Œa˜§žzÊét2 #‰Ìf3W„Õjx<^—.]ž~úi.Ÿ—_~Y |ùå—gΜٷoß§Ÿ~záÂ…>ø`Ó¦M#GŽäÒ0 ãX)•J¹|܆yá…Þyç±XÜ­[·äääk| ~~~\'‘H¶lÙrôèÑýû÷¿øâ‹ ,x衇8ÎkÜWwٛܣ›ÝÓL&“;ô”H$—%^»vmAAÁÚµkårù—_~Y\\ÜxëÅ‹y<^§N®] BiF´Ê=!¤5h4šS§N <˜ûÓjµ®^½Úl6çäädeeõíÛ×ét:ÎÈÈH??¿5kÖp¡jbb¢¯¯ï¯¿þêr¹ CYY·û¨Q£-Zôá‡þøã.—K¯×‡„„„……•––ž8q€D"IMM]¶lY~~þñãÇ·mÛ@(>üäÉ“ñññƒîÑ£‡D"q:çÏŸïѣǜ9s{챜œ‹Å²ÿþQ£FÝàG»ÿþûÍfóüùóŸ~úé\J¥R]ºtiøðá~øa¯^½¸•Ÿ¥Ré‰'¸˜R(*•Jnž©··w]]]~~>7’Õd2q™ðùü¢¢"—Ë”””´råJ»Ý~äÈ‘âââž={6U´ÃáðööŽŒŒ´Ùl;vì¸lkzzzRRR``à ~vBùû¨e”Ò M&S·nݸ?Åbquuõ½÷Þ[[[;tèÐ#Fðx¼|pâĉÞÞÞ …¢C‡|>_¡PÌŸ?ÿóÏ?ß¼ys}}ý“O>ù /ÈårŸ‘#GŠÅâ9sæðx¼gŸ}vΜ9{öìq¹\;vôööæóù³gÏž9sæ¿þõ/…B‘”” à©§žÊËË{ì±Ç|}}M&SZZZ·nÝæÍ›WWWçïï¯ÕjçÏŸúôi///n:?Ã0ÁÁÁîÞöƯÃÂÂÜŸåÑG]ºté<À½#‰¸âøøøp­¡R©Ô½ŽžR©|ùå—¥R)וÿðØ:uêwß}·bÅŠüqÀ€7n;vì˜1c¦OŸþâ‹/>öØc …"22244” yŸ{î¹7ÞxÃáplذá‹/¾xíµ×†®×ë§L™Ò»woî±  00a˜Q£Fmܸqøðá:tèÀ­N ‰üýýY–ݱcÇ”)SþÎ*°„r³˜ôôôzº„6nÑ¢EŸ~ú)“É4a„—_~¹S§N.—K¡Pp½ÉV«•[rH.—Æ€€>ŸÏ²¬V«5™L ÃÈår///n$///–ekkk† ¬­­µÛí\>b±ØÛÛÛl6s3rL&Óã?>}út.æs:jµÚápðù|nÕ'n>Ã0b±Øßßÿ³Ï>³Ùlï¼óWóêêêÀÀ@.>küZ©TºãѧŸ~Z&“-Z´ˆûÓjµjµwÅè IDATZ…BÀ`0°,+“ÉÌf³Åbñ÷÷çê Ñh¸FP___nI—ËU__oµZƒ‚‚¸Q³f³Y,Ëår»Ý®R©\.W`` 7AžÇãÙív½^oµZCBBx<÷-ñx¼ÀÀ@n,Z­–Éd\<ÊMÏ àRFî;´Ûí~~~V«Õh4êtºgŸ}ö§Ÿ~âÖÀ"„––™™ÙµkW F !­A«Õòù|.êâ‚Ñ3f 4¨åJÌÎÎ~ê©§¢££ :vìøßÿþ÷—±«««‰DܼŸëª©©™2eÊñãÇ÷îÝÿ÷ªìa6›M§Óq«§ëB¹#P0Jñ §ÓyöìÙvíÚ´\)‡£¼¼Üáp0 ÞB·4›ÍÉÉÉ‘‘‘-‘?!„´a\0JcF !­Ïç»¶@Ð +·K¥ÒaƵt)„Ò†Q_ !„Bñ F !„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!s‹Þ³,k0Ìf3÷Äd–e[®Z„¿a‘Häëë+•J}||¸'ªß,—ËÅ=ä|Òf0 Ããñ$‰······———Gž€êr¹ ƒÉd2 ‹….rûb†a±XìããÃS7uŹÑ`Ôd2X­V®¤àà`€žÞDÈ?šÓé4™LjµÚb±ðùü˜˜¹\~S9X,–ââbƒÁÀ=«=((H 0 ÓB&¤Õ8N£ÑX]]m³Ù¼¼¼ÚµkçååÕšÐëõN§“»ª*Š[»]$äÂétšÍæêêj»Ý. ccc}||npßë”,ËVUU•––úûû'&& …BÜABn ˲v»]¥Råææ*ŠÈÈȹ“t¹\µµµ¥¥¥2™,99Y"‘ÐOÚ—Ëe³ÙÊÊÊ.\¸Ò ÷Z.—«¢¢¢²²288822R(Ò i3\.—Ýn///?þ|TTTXXØ\;®MR*•åååñññtÀrÛá:ë###åryAAÃላ‹»î±\[[[\\Ü®]»àà` CI[ÅuÖÇÅÅÕÖÖ–”” mÑY–---U«Õ:tËåtU%m Njű±±þþþ………‡£]»v×ßëÚ›ÍfsIIIBBB`` 3„ܾ†ñõõMHH¨««S«Õ×Nl6›KKKÛµkB‘(ióx<žB¡ˆ‰‰)++3™L-Z–^¯W©T‰‰‰~~~tU%mÃ0 z½þºé¯u™aYöÒ¥KÁÁÁþþþÍWCBˆÇøøøDFF–––Z­Ö¦Ò¸\.®w>88¸5ëFˆgúùùº\®*Âápäç燅…Éd²*‚¹\™ŸŸït:¯òZÁ¨N§3›ÍíÛ·oΪB<*$$D(^£qÔl6ëtº¨¨(jmQ%%%çÏŸ¿ì®@©Tž?^§ÓyªVw2†a¢¢¢,Ë4äÜFòlddd åO®«ªªŠ±Öát:µZíµ“]ëbc0|}}iÖ<¹ŒÙl~ï½÷*++=]r+x<ž¯¯ï5.·F£Q$I¥ÒÖ¬ÕhãÆãÆ+,,™™9wî\»Ý~àÀÇüÀW¦/++›5k–ÙlnõšÞAÄb±T*m¹žzƒÁàïïO·y-J§Ó•––6µõÀ'NÜ·oŸû ìÙ³§5jvGâóùr¹üºÑÿuZF©+\)77÷·ß~ òtEÈ-’Éd&“©©¾H½^/“Éh4[K›6mš———ÃáàååÅÍ0aBTTÔUQ¤§§«Õj¡PØê5½ƒ0 ãããÓBÍf.—Ëh4Þøb7äÖddd¼ûî»Mm}ä‘G, ÷§F£Ù°a]ÎZ”L&»noõ‚Q³ÙìííݬU"­jíÚµ«W¯=sæÌÂÂB–eøá‡]»v:tè믿 V«_}õÕ#GŽØ¾}û÷ßéÒ¥·ß~ÛápÆ·ÞzkÓ¦M²²²>ÿüs.ÛÍ›70@$yî“‘¿E"‘°ÙlWÝj6›ézÙÊŠ‹‹;wîì¾P«Õ+W®üöÛo‹ŠŠÜi¶mÛ6dÈêªji2™¬…šŸ¹e¤¨Ï¡EUVV8p ''ç?þÈÌÌ ÑhÖ®]ûÍ7ßlݺµ¦¦æ²ôgΜ‘Édñññž¨ìâFŽ©k£Üb¼ÍZ%Òªl6ÛâÅ‹].×æÍ›-Z´cÇN÷ã?F@ðå—_jµÚÇ/Y²díÚµv»ý‡~¨­­õòòúùçŸóòòJJJ.\¸téR–e׬Y“ Àl68pàþûï÷ô‡#·ŽÇã1 ÓÔã^\.5¿µ²³gϾüòËîÑ~øÁh4Ž?žSWW—••5xð`VóŽ ‘Hìv{ eβ,ÝÆ·(£Ñ¨R©¸ÃG¥RÕ××Ož}¨Ý­EI¥ÒkL™å\g6}³Ö‡´¶>}ú(•Ê‹/fffŽ?>##C¥R•––véÒ%..N&“>}zïÞ½<ðÀþýû5Mnnnjjj@@@bbâñãÇ÷íÛ7pàÀüüü²²²cÇŽ :@UUU~~~ß¾}=ýáÈßrí£›ŽýVöä“O6nò>|øäÉ“?þøc™L¶nÝ:‡JHHð\ï -÷û§#«¥%$$Œ3&!!aÖ¬YcÆŒIOO/,,|÷ÝwŸzê©>ú販cƒáðáÃ#GŽôTmï×]¡‚†Q·e!!!QQQéééEEEÏ?ÿü… ¶nÝÛ¾}{¹\žœœü矞;wnâĉ`óæÍƒ¡sçΉ¤wïÞÛ·o?tèÐøñããããwïÞ““Ó«W/;vìèÓ§ŸŸŸ§?!mVbb"Ã0 ]»vÜ §-[¶Üwß}ÔUEÈM).. 0pàÀx ñÖœœ†aâââ}ºK—.4ö÷Ÿ@¥RåååõïߟžAÐÒ\.WFFÆ€®º533³k×®Ô2Jn%¤õ¹ÇÏBšKHHHHHˆ§kAþ‡n!„BˆÇP0J!„B<†‚QB!„â1ŒB!„¡`”B!„x £„B!Äc(%„B!CÁ(!„Bñ F !„BˆÇÜʘNŸ>=mÚ4‡ÃÑìµ!„4¯·ß~»¹ßZZZúüóÏkµÚfÉÏ’J¥ .¼ë®»>>z½Þ³up:§OŸ.++ól5i|>_­VßÚ¾·þlúäää%K–…Â[ÎÒræÍ›·cÇŽfÏ6**ê»ï¾óóóköœ if³yæÌ™ž®Èÿxyy­\¹’ž“Nn_.—ëwÞÙ¿ÿ-çpëÁ¨ÏÝwß-‰n9BHË n‰l¥Ri¯^½‚‚‚Z"sBZÁ`Édž®ÅÿÇçó{ôèåéŠr‹œNg``àßÉ&0B!„¡`”B!„x £„B!Äc(%·Ï?ÿ\£ÑÜHÊ~ø!''§…ªñí·ß·Pæ„Ü.222æÌ™³uëV6›-77×jµ6WæJ¥òý÷ß_ºtiseHH+«¯¯ÿî»ïny^ù‰‚Qr8xð Édº‘”«V­ºtéR UcåÊ•´ i«6mÚ´dÉ’I›———žž ªªê¥—^*--½jÊ%K–=zô¦ªáëë«P(~ýõ×›Ú‹´a³fÍ:v옧kñŸ~úé²eËšÚªÕjþùg FoʭϦ'¤ÕÌ;—›©wéÒ%ÿÒÒR“É”””äž¾———WYYÛx¯úúúââb–e#"" Emm­J¥JJJâñxZ­¶¨¨¨S§N×&S«ÕÅÅÅZ­688¸cÇŽÜ&—ËuáÂF“˜˜èNY\\,‘HÔjµÍf mo[åt:u:D"‘J¥î7µZ-˲¾¾¾<ÀÙ³g/^¼øâ‹/ºèõz§ÓéNàƽ_¶lYDD÷§N§s8¾¾¾Àþýûýýýï¾ûî+«tYJ,Ëêõz†a’’’.K¬×빪þÍïüs\ºtI&“UUUéõú„„÷Y´¼¼¼ººZ ÄÇÇ{yyUUU>|8..N(ÆÅÅùúúêõú¢¢"§Ó©P(ÂÃÆiœmYYŸÏ7 F£Q¡Pp¿Ìêêj«Õj·Û«««¹Ó~~~¾ÕjU(‘‘‘\‹%??ßn·K¥ÒØØX‘HTQQÁ=Àßß?::Ú}¨Õê£GõìÙ3:::00Ðjµ^ºtÉn·K$’Ë.CäQ0JnS§N]¿~}LLÌôéÓ-K@@@mm­P(ܸq£T*ݼyóìÙ³ãââ¬V«{íÀ¼¼¼)S¦Èd2±X¬R©V¬Xa³Ùüñ?þxذa¯¿þz]]ÝO?ýÔ8]µjÕ¶mÛ|}} ~øáY³fñùüï¾ûnñâű±±,Ë–””p)?øàƒââb???£Ñh±XV¬Xíï…kª««{ýõ×U*ULL w±ü¿ÿû¿øøx‹Å2þü3gÎðùüÈÈÈ·Þz+;;û÷߯««›8qâ˜1cÆÿý÷ßïܹS$ùøø¼ûî»îpó2ß|óÍæÍ›—,YûÓO?ýùçŸÀn·/\¸ðÀ™™™J¥rëÖ­S§NíÛ·¯{¯?þøðáÃ.—ë7ÞèÔ©“Ífûæ›oöíÛçççç:?ùä“ôôôîÝ»+•ʺººAƒ½ôÒK´¸uÛ0}útîÎ_§ÓX½zuppðž={æÎ¥T*“’’¾ú꫌ŒŒÂÂÂU«VíÙ³ç­·Þ xõÕWm6›\.///ÿꫯºwïÞ8Û/¾øâÔ©S6›M©TþôÓO)))ëÖ­ûå—_ù|þ[o½õÓO?9s&88¸¤¤ä£>1b„Z­ž3gNIIItt´F£™?¾V«1cFtt´ÃáðññY¸p¡{9°¬¬¬¬¬,©TZWW7uêÔnݺ͞=»¨¨(66¶ººúÓO?õòòòÀz»KOOg›™™i4¯|ß¾}B¡°wïÞV«µ©} iFqqqùùù,˦¥¥Íœ9Óf³éõúøøø}ûö±,›°`Á—ËuñâE™L¶iÓ&–ezè¡)S¦˜L&«Õ:sæÌÙ³g»\®+V$''üñÇ yyy—•¢V«ÕjuaaáêÕ«5MUUU»víÖ¬Yãt:wíÚåããsàÀ–e'L˜0lØ0F£Óé†:gΗËÕêßÊuLœ8Àòå˯Üd6›O:e2™®ºã™3gÔjõ•ïçää%&&ÖÔÔ4s]IËp8[·nõ÷÷_²dI~~þ<ðÑG±,»råʾ}ûæææVVVÞÿý~ø¡N§{íµ×ÆŒSXX¨Ñh>|×]weÊ”½{÷j4šO?ýô©§žbY6###%%åèÑ£\‰ `YV©TöíÛ÷™gžQ©T‡êҥˑ#Gþþ×¢×ëSSS݇óeŒFcffæß/åJv»ýرc‹ÅýŽV«ŠŠ’Éd¥¥¥-Qâ?YZZÚ¤I“ŒF£Á`èÓ§ÏúõëNg¿~ýæÎk·Û³³³cbb6oÞ̲ì°aÃþüóOn¯—_~y„ õõõv»ý£>zæ™gGãl§L™Ò·oߪª*“ÉôØc½ð N§sáÂ…‰‰‰¹¹¹6›mÓ¦M‰‰‰çÏŸ·Ûío¿ýö½÷Þ«Óé/^|÷Ýw—••±,«Ñh,ËgŸ}6zôh®s@¥R]VʤI“Þ|óMîõ·ß~Û½{÷¢¢"–eÕjµÉd*..îß¿nnnË‹ÿ‡ãá‡æóùkÖ¬¹r«Óéä.ÖWuôèQ³ÙL-£ä63dÈ¡P( ###KKK«ªªŠ‹‹GŒÁõîuíÚ•K–‘‘‘œœ}º\.÷ööމ‰°ÿ~ƒÁ°víZ>Ÿ¯Ñh ׬Yc4Û·oÿ¯ýË]DHH÷è™Lÿæ›oŽ9òÁŒ‹‹‹ÅÞÞÞAAA\žn,ËŽ?~óæÍ[¶l)--­««päÈ‘ààà^½zñx¼ûï¿Ñ¢EBCC¥Réý÷߯P(xðàÈÈH܉½OŸ>Ë—/3fLZZÚøñã¯ñ ‘S§N¥¥¥µoß@@@@‹}[m£ä6ÓxøšÍf“H$\.÷wÞ ú÷ï?dÈîO™LÆçókjjòòò Å… \.ŸÏwg¥ÓéfÏž½xñâ=zÔÖÖ¦¥¥qeY­V›Í€»3v§w—hµZ/QGÈ? ŸÏw«s8\.—@ àÞäzÕNgã]X– >|8ÇKKKs82™,&&Æb±„„„\6J#‰¾øâ‹“'OnÚ´éé§Ÿþúë¯ï»ï¾«Ö§°°pæÌ™S¦L¹çž{233׬YÃUŒa.çËîë¸cœÇãñx<®þ¤MâN¤î•ìv»{ýôÓ¿ÿþ;n^µÚ͸šÄ‹.¢äöæçç×§OŸ_~ù¥¾¾>==ݽ®ÓÈ‘#OŸ>Ó½{÷ððp¹\îp8^ýõ„„„µk×®ZµjÆ ,ËjµÚ>ø ¢¢ÂápX­Öàà`Ÿ7r'¦¤¤$¹\¾nݺººº 6hµZw¹6l(,,,--ݰaCÿþýÿÉÏÅu8*•êÂ… §OŸ¾téR}}}㨚ÜRSS9R[[k6›÷ìÙÓ·o_™LƲ,7ÀºS§Nƒ!:::--­¬¬ìôéÓÁÁÁ=öØ3Ï<3räÈ«ŽÚ,))ùðÃSSS—,YÒ«W¯ .‹Åz½þüùó¿ÿþ»F£Ù¸q£Á`ÐëõV«µG)))î ¸gÏž*•Š›AÂÍÓwÛ½{·Ãá(,,äF´Â÷C<"00°k×®?þøcMMÍrss{õê@$åääTWWÛíö#F\¼x144´{÷îQQQ>>> …‚ûeŽ?ž›Ÿ·{÷îìììÊÊÊ7öë×ﲜ={ö,((8tèPmmíêÕ«Û·oœ––¶oß¾¬¬,“ÉTTTd2™.\¸àt:ÇŒóÆoðx<½^Ï%åV÷ ©®®V©T6›---mÿþýÇ7 %%%—µäQË(¹ „……q·È!!!îéÀ!!!ÞÞÞ>ýôÓW_}5;;Ûn·ß}÷Ý\‚÷ßÿõ×_î¹ç|||¸¡è999yyy¿þúkûöíß{ッ¿þ:55Õét®ZµjìØ±]ºt™ÿüsnÀh=¸F®ôiÓ¦i4šöíÛOš4éªmEÇ0ŒZ­þí·ßJKKÍf3÷ŽŸŸ_Ïž=Ý„´aõõõ\÷‚ œžžn±XþøãÇüÂ… ¯¼ò ŸÏ·ÛíÓ§Oçñx©©©Û·oŸ3gNttô믿~úôé™3gFFFªTª?þ¸ñ/|ûöí§Nâñx;vìÈË˳Ùl_~ùå+¯¼RYY9mÚ4…Ba±XFŽ `РAëÖ­Ûµk׸qãrssß}÷Ý:ÄÇÇ4hÞ¼y eee555Ÿ}öÙ´iÓÆŽûïÿ›Û]£Ñ,[¶lòäÉŠ‹‹_~ù劊 ®ÏÔS_&i^ …ÂÇLJ{Ƚþä“Oþýï?ýôÓõõõ“'Oîß¿?€'žxbÙ²eþùç|0cÆ N7uêT¹\®ÕjŸxâ‰+×^ˆŠŠzýõ×µZ­Ï”)Sx<žL&ã:ßôïßÿ™gžy÷Ýw½½½- 7ß衇ÊÏÏŸ5kV@@€Ífûâ‹/ÒÓÓ×®]l4‡ – R©Ö¯_ÏõÈ5êý÷ßî¹ç¦M›6f̘¼¼¼×^{-((Èn·þùç2™,44”fÚÝ&==}àÀWÝvìØ±”””+ç…íß¿èСݺuËÈÈø'7‘6£´´4<<\ (•J???.ÜT*•ÞÞÞÜÄÛšš½^ïççgµZår9÷£åfS:N©TªV«ív{hh(Ã0‡£¬¬L¡PˆÅâ²²²ððp±Xìp8ÊËË].WDDDUUUdd$×_QQÁ-¢Õj%É£>:lذaÆéõúèèh.&þ§yê©§öíÛ÷øã_w ‚Î;6¬ñB?ngÏžŒŒ¼rðSnnnjjj@@À¡C‡‚‚‚ZªÞ¤ù8Îòòr§Ó)‰d2·ð¡¿¿¿¿¿¿Íf«¬¬t¹\aaaÜÏÀårUVVÚívîpp:\APPÐek*iµZ.«ÀÀ@³Ùl2™x<^DD„ÝnW©T,Ëøùù°Ûí•••</,,ÌårUWW‡„„…B«ÕªT*¹Ê¨Õj©TƽÉãñüýýkjj¸F¯ÁƒÏž=;11Ñét¶k×®Y.ðƒá¾ûîËÊÊÚ¶mÛ=÷ÜsÙV“ÉtþüùÞ½{ÿý‚.ãp8NŸ>Ý¥K÷8N—’’R__áÂ…¨¨¨f/ñŸ¬²²Ò××—‹A«««¥R)7(Ÿûu ‚ˆˆ÷H*­V[WWÇ5F8¥Ri·ÛÅbqXXØe£¤^|ñÅ„„„G}´¾¾ž›Æíîp8ÜK:Ϊª*«Õêþ¡p¹\J¥ÒjµJ$’®CÉápîêãp8*++ wF5uuur¹\&“9NîØ‹Å¡¡¡,ËVWWß9ñ¨Óé|ì±Ç~ÿý÷_ýõ‘G¹l«ËåÊÈÈ0`ÀU÷ÍÌÌìÚµ+µŒ’Û€{á$÷ꆗ½¾r€¹H$j×®ûÏÆñ“@ pOªp¿îQAwt/jã¾À0 7ÚýK,4èª- \§§Ùl¾j0JÚ >Ÿßø—,—ËݯE"Ñecàx<^ãŸ4ŸÏojÁ2¹\îΪqžB¡ð²¹JB¡°qÜù‹Åbwéî¿ÉÅ?þøcaaáºuëæÍ›×øx'm@xx¸ûµB¡p¿nüëºê›àÚ;Ã0áááó¿,C>ŸåReÜ Uã4—ýþAãw¼½½ÝÍ|>ÿ²*5.܈V FÏuy IDATm¬ÍÂZZ³DBZ«o¾ séZ§8Œˆ‰ƒ› pÁ:®ªªªuæ~ÚY»•µºàj…²H[Û%ö‹e_——ëÊÃ;.Ä ­bAþ¿éÓ§Ó2Ÿ·£F¬CéTV;ª+•Z—V4’ÜæÚZkœ:áùÁÏñ 准òCÃa7r¾v«'7U%99¹ùªù.¸T•Ò©¬rVÕ;ëkQK>¹i O=ËCÞ•‡<ÆßŸñæ‡óÃÃa"††Ýé:tèàé*[ѲÁh«î¨ùh¦33[­(+øFÆèdœ×ß“Ò@ ©Ø%v‡;Ããìq½˜^ý%ýC¡×n(基ƲSîÕ©šÎ¥;a9qÄq$—Ÿ[&(«Uj-ø¤y‰!–¹dþNÿ(gT¬=¶7Ó»Ÿ´_?ÄÓõ"„Ü´– FY°ö‚½æ½ûûwøìÐð4-T!mž¼!‹Žýâý½½{:{ð[cå2BÈß×üÁ¨Æ©©fª«yÕÍž3!¤±:^’§Ô¸4M£Ÿ„„„ÆïX,÷¦´´´¤¤¤#GŽ\¼x‘{tXXØ-,0nfÍJV©ä+ovGBšW=¯¾‚©Ðº´Œr»hþ`TíTWð* ­)HHËrÁUÎ/¯uÔ&®Ÿº Ã(ŠÑ£G'''gddTTTTWWëõú´´´ÈÈÈk¬ uƒËPÃÔкÄã,Œ¥‚_¡qjb„1×O}Ûr¹ ,KS2HK`ø|ŸšSÔ”– Fùן·ôðpù¹®©X 8€` ×}; ßLAÍË ”A@-\å錄\‹ަFaVð+4öfˆÿø|~BBBTTÔ¹sç222òóóËËËïºë®Þ½{ûûûßÈ@RµS]Å«jòÀ¯¾/þu“X<ø\e?Or×9˜êáºü]  T@»V|ôž¨‚54듺]p55-¡Š_Uëhrnßm‹µÙÊÌæl“éŒÑxÊéT²ìU¦'ò7±,Ãç+¤Ò®ÞÞÝ¥Ò$‰¤ôøðëæ?'9àÐò´×O·r“Á¨ûñ7\÷ €ŸGƒQ0˜ ,Þºz®&äödC“3Ó ŒÁÁ6[/„D"éÕ«—Ëå*///((8zôh^^^ïÞ½odù''ë43æ&7ó@à<°òŠ`Ôì&^/Ý œæ\ï3YÀ‡@ÐõR^Wç*`Ñ£÷Ûp3OlmEµÀ$`.ð°P\¿øˆÆÝ|¹¥ å.¾"o>‡¦Ùaoj“–§mc ¹¸\&µzuUÕG SèåÆÛÛ‹Çk­§À‘; ËÂbѸµª G ŸßÓaa³…›=kÜœV|6½PQ@=P,hx¦"îÚ½€RÀHÄÿ&A²@ PˆX x?7ÊÖ”‘€Ðú†·($øËùªPB ñš-”z °þ@LÃÝ|1àÔz àÆÔÕ倛ȴ€ÐˆHþù¤RéÀ{÷î}ðàÁ‚‚‚;wfgg§¦¦:·tu7J xØìýëÖJ@|Ƚi b>Pœc!µ‚X ¨öçP ²!ÀU¥$Þ€¨´@ Pø± mx P  €?ð"¬ýkAu@`ä@"À*-ð' 0@xÃÇÑ% $6j›% ª€ `;P Ô" ðô€¨‚z@Ä<À m:v5œ…êñ¿Fv    ðoøžÔÅ€ˆd€ (U@À ˆx€ (ô §>¦á{.@0 ðʵÚ†rË9Ðä£ÈUX,—ÊËß¶XÖEF:år4ŒiÅË7¹Ãøø (, “I]^¾ðÒ¥ýÉåÃZ®Ä–ÿ5»€r`°èü8 üp ØôÔa€8 | Œ,~¢€J`&ðÐÕòWÏ?aÀn`°¸<°¸< ؼµÀ àmàªÏ÷Ö/Õ€°K‚æ)€¨,ÀX`p˜ð | Tÿ5ö €¼à Zi„܆‰ŠŠz衇rrr>\ZZºvíZ¹\îççw£k?±€Ø¬„ÀïM$[ ìªÝ÷G0(d€øæg€Zà5 Xqµ¬œÀÀA  øðÞîί6Ä €o€}ÀL ¨"%¨€Q@8à” M|®7€l Èž¦«€½ ü0dS_@„+š8áœ&ñ€Èþ:G€÷bP?`9px ª€8 8ÿN~€ø? P¿ô]{¯á,$kó€§`€ä«€^@0`|”ï'€óÀ ð>ÀoÇ9P | ô”ÀdHÅ€à>€ðnö p ÚÓ)ñúŽšüü Réé lÖq„\ÃÀÛ luõ‰¢¢Çãâ6Êdý[¨¬F3€•À ˜ „À(`Ú¨™Ð”÷o›‘À%`ð_`P4µNÛè^ß èß2`5`†LÀÀx`P Œ®úðšBà,°è ¨ÝÁsí(¿¾ %¾Ä_|  0s€üFYÅ‹`>|Dýo“V% ;wîÃ-ÿT[[;zôèsçÎ]g7'pX |G€AM'þ7ð0ÿL¬Ø ¬z@ HÀÀN`UÓY €w€zà`yC° ˜ô>´Àà`"Ÿ€d dr Xô¯¹Mô*àØÃÀl`:0 ˜ð€ÍýϺ_` p¨‰ïÁ¨-@"ðt:?|ÀŒ2+à,îv—€Là °ˆ>¾¦³€Æ# GoÀ·@ð=ÀM1wµÀR ;0 Ø ô~¼€µ€¤cõÀ @2ðjCž›€À: øXôΕÀ@; ðDK ¦alÀ `?°Xtžú7óXÒ¶„e•• §cbpÓ iN<BBàr©ËÊfuè°‹Ïo‘~FŸXà#` àuÍ”~@O€bàØð¦ÿM–{ÔÐ/Æ-›X›}€b ¨‰`”ë‚èŒmh£åŒo ê€à? Ýý±€xí¯—/À àÜ£é|oòSòàãã3`À€¤¤¤lݺµ¶özóBê—Rà}à¡¿ö¿ß9Ð ˜ t6R¼¨à—&ÒX3@)0p@x~D ¡p$p7à^`6 m¢ò‡Õ¯a|QS‘ÀX@uÃI骂€vŠeÀ{€@ ˆ€pÀ`/ ¨ÎUÀ€T7tÅ|‚¿Œ– ˆNw~6Eíp‹}]îd€ ˆÎ7Ôÿ2Ç€j`À4ÔÍÄRà ;ðp@¤htW£€?wL`WÓcœîx:Ý^µú»Ž)%žÄ0 V{\©œ9¯%Šhá`ô`5°XŒ†aMŒjº² ›\¸Ê\IÁ ¸µŒrxš]¹~s®ç艆¶É—€îMÔ9ø8ì^ü ›÷²±2瘀E@Q£wÚÿ¡ÑQ¤-àžÛ4cÆ /¯kßVr`1ð° XŒ†Ü;7Ò&þ œvs `T)…À½€ñz7ºàஆ?“€SM¤´.€×̹Ï3W2¨þ ¬’€ ýŠÜg 0¦a$€¸kVò2ïIÀÀ¸¯ÑqŸ<¹RX x¹á}_ ˜4žH6˜ÕD)ü«Ý·Óοžñ  x©aw@ Äë€ÀV`"°»á&ü2J X(4`BC¸L®À²ŽššïBC-×›=HH‹ãóíÊËû.<|w½«ÀÍká`ônàn Øüdó `œ@ PÞ0èJ°Ô‚†82¨ ¸¡åà"àìh89ÞìžÌÀ`  ÄÕÀƒ¯a6ÒU©  Ð84µlŽ?ÐXô„@9Ð xùŠ–Q:‰f³Úìb»°åG“¹\.‹Årý`Ttº5À^`° ؈lÀ@„, ªP0@(`r®@'à$Pß­ (ŠqÃIC{¯93sfµ×þ/ˆ‘3S‹ä¬ƒæ°Ê·‘'À*Ê~jp€Uö‡{Ã&¨ ž ƒ§à:4 \¼ÃàŸ*€'샳Åwkk ‚!Ì“‹ŠŒÞ&-`#\ƒ›pÂåvw8WÀ | üþPR![Þ€•O@-ØnïÛ2Bè•Vñ‡I2dg¸óÁ=ÁÑ•*='ç˜N׬Ì¿/Ûñ*Àó0âAŸÀð…¹ % †92êç0~yÃÐÂ8¨3ÀÁù·Í*þ=öÁp°€ø€|a7(@ ßã^‡ÑàF¨,/6Yí±]g·¦ð¿σ *Â×P·ìOž@Pš$Í…µöTÛÓªU«Û¨¿OøBèc³–ýàu†Ù`†ñòîõIrFc2¼  OQ¶Ö°^„ b60YÑÁ@øÜa´€á5x$0À2p…  „j €`9¶ê 3Áâ`¦< Œ‚×@+!À0p—·ÉçóLWá}xž¤ÁOÅ,’8C¨ì“ùË—äÑðl€\h ®  YI@Aà ‘p^wH†1PšÜÞ»ã(ox¼åEž¡°†Cô´É+oÂKP>‚¶0ÞwH‡þ§á-„ˆ”/Å…y ¼Å]úma2%WEXTð TâèhÈÉ9ñÈ:£ùSY.ß·W8²fe-–]½§m–¥úB{Hµ”æAš¼Ox†€ üå€üWÁ <åå¶ð;Ä‚ŠŒÖß TZ¹ýëBÐ*°®É ྣJSéoè·Çm÷ññ /ý€ûZ^£aºì´~ñçÚ¬ÿZ£ ð$ƒ‚m$ØàOù‹_òt“`XäKJ(,‡«`†Š ƒvÐt°´0œá4Á/^6JœJø’e;0. ™6SO„‘`‘¯-!òõÁAŧŒ×‡Ÿåñq²WÚ êC&øZ> ÍÀÖ|ZPÃ{0ÒÁí¯B5`¾lÕórÞQEø®É‚ü߇F°²@ €ñ0ÒÁEú>Ah!¸øß–2•-ßdgst´i'µ¶w/ß{³î[¶P»6¾6Qü­[‰hÛûÕŒðô¤êå½”;’“Ù³Ú´¹“*8;[²³OÝ‹Á„P™GQùéíä?½¡pÙmµ}£º(ÝAg¨Y¨QgÉ(øµ–W¤ÙŽÅH ÷…Üʹººœ9ëׯ÷òòò÷/aúá@)ïæ¶R¸x¸üŠQe×Üž”½¢Ð°ößS­|“i½Œ¸Ë†¹sÁ)`§Êæ2âX|7ë¼¥þdjl®~¶wÈ…6[›mƒ¬%ˆ—€Úf{–mæ…®¨+'²¬A>ÊBóªî°ˆ‰ 4,–\U±ÒW’íÅÂܹtíÊ A÷Ų²æÃ™2…öíoµ?ιsüñ Ò±£]ç¥K©[÷Þ:£³gÓ³'¡÷·š¬^Ï¢EtêTú¼F#o¿Í™3 x_Q@­F¯Ï½'#ß‹AÁ}BIH³)C:yòäÚµkûöíëâò°UÕ|D…¯´  …ÒVÕ7;›„L&üüp•ïFÒӉǭD©³™„t:nÜÀÓùŽ.5¥“‰œœñôHJ"9||ÈŸ=3“´4OOJMÏÇ` %ñðÀÛ…‚¬,ŒF<<pwG«0‰‰A’¨P†Ñ£Nž´Ðh$1‘Áƒ °k7™HHÀbÁÑ//Š”BÎÌD¯Çb!=Ýî&%‘’‚«+~~(¤§“‘AT¡¡hµ¸¹åõ4‰Çd"0‡"ƒ‹''‡¸8­9—¸»çÙ“˜ˆVK@J%™™\¿Î/¿€V‹‹K^·âNìµk¼÷^A7ý~qOòÁ„3*<ÚhµÚ¶‘m“’’bbb¶mÛ©V‹ïõã õ´ A1äæòì³èõZ-óæQ¹2çÏó HZ-ׯӵkÑÇ^¿N¯^™‰ÁÀÇóÔS3fËÕ«(•„„ðí·lÝÊ”)(˜ÍLšD÷î(;ÆÄ‰hµdgÓ­cÇ=KaNžäÕWqs#'“‰É“éÔ‰U«8z”iÓÆŽåõ׉ˆÈ3F¡ -'ŸäÃq,ªDâÕ«LšÄÅ‹¼þ:ƒç5fd0c{÷¢ÓáìÌW_áUx½~ûo¾Á×—›7©\™ÿþOOvîäÝw‘$ôzFfÈ~ý•å˹pO?ÅÓ“!C4ˆäd>ücǰX cÆŒ§4›³!2l2é-rKV¡Î’\+¿gá>…ÑË~ß²R·•‡ç³a”m.œZc„ì¢Ôsÿ5!!!mÛ¶6oÞ|¥„ߥ‡Šü7×Pè)cQgïa ›‚{†Å•+¼ü2£F±o§Na6³};}ûâîNƒÔ+1®¯Ó1h®®ôëlj·œ¹gŸ¥];BBhÚ”Œ Ž¥gO<=éÝ›sçˆ%!ýûyé%t:‚‚¨_¿¤Y¾úŠÏ?gÁ‚¼.àãCïÞ¸»Ó»7.’Rì±]»âëKDÕª±kWÑ}Ôj¼½ ÖDÝ´‰nݨ]gg7.)‹ ,Œºu E§#&†ÄDΣwo<=‰Œ$7—7ÐéðõE­ÆÃ_ß¼ÑÖ¯G§ã·ßøñGŒF¢£ó å·ß ž“Áƒ‰Š"(ÀlfÛ6ºw§R%jצuk€øxNž$7—ï¾cËÒÒ¸x''||Ðjóæ-!ÙjÙ2 @£!¬HßG–ûèŒþ Ûÿõ ?_jå^°ÖÜùQ»` ƒ­6ïÀỲ!nj¼a¿·8Òàú]M a*ì+¾ƒÞ‡aÐò3{b` ÑEõ·­ærE®d]$üÑð' ƒ>ðc¡>›a†c÷3|_ü€ 0ÒŠïP$I6:—·ÏNÏÂg…žÚ oÃiN(4ïyø.[ä]¡P4lذQ£FÙÙÙk×®M)áªÿÀÉÅp–Ëoî’B}þ.êì@‚8H/­ q¥÷º-J°¹Èy¯•Ѽ‚;AQîôK7nä‹/=šiÓèÖ £IÊË’´Rò¢­Z—Iiõärå;=W×[–¹¹HÖ-SZ- &&P’od˵k\¹Bll^äP©nÍ+I˜íò"¯V´²pƒƒ]7£‘’1› º§Å¡TÚ¥“šÍHRÞyÓhP(n™]x ggÔjÔjºt¡›\†ÃÙ™¦M &wVªD“&X¹,L¦¼)$)ovë¤:j5ŽŽ¼ôÒ­U~ë{Z2ôïONNIžý£HÙ;£jÔ–B;Ïca¬}¤ðî¸z/î±0¾xéæøÁ4{Á¿'ŠÙ \*K`R¡Æw •~)’ßaÜ]M (¡…¬ùZ$x&CŠCÓ`8)Ô_½mþÍèB}ò9ãÀž„iP£¨º‹Áaóo,Ä?àBø½ÐÞçRùê®n~À4h ç =U Ú*6V˜™°ôÖ8¨OªY'a‘]GWÉU)‹Õju»víBBBnܸ±qãFƒá¾Æî” ¥NÒÝV×]0 ÔЦAµ¢ÞÜPû7·HŒð–,§_2aüm™V:V›«–X4Ÿàå <‚2CƒF{K{Ïw‹»ò‘[÷+‘ØXjÖ¤C*TàÈ•Šðp¶nÅl&)‰³%G€´4öîص _ß‚€¬øùÀ¾}Hû÷ãéIp0„†ò믘Í ·VØ‹äÓO™;—©SÉ×F½y“$vîÄ×ww4âãÉÍåÒ%Ο¿uìÞ½ÄÆrö,µåJÝ~~œ8AzzžKš›KFFž%y±m‰‰H7oæyÏ·ƒ•*åÀãÇQ(n%›ªÕܸAFFž»Ü¤  #G2v,ä8Ë—2„cÇì†ýùg^xë×4""X»–ë×9s†;<=ñ÷§jU^{1cèÓ‡ ò&•$.\ #ãVh¹0Uª0dîî\½KУCÙgÀú¨|**¨P™m¯ÁK¡*´`%X ÌÐꃶÈ厚@OYj$þ€Sàƒ ŠÍ4—`=t‚Ø ;!U®&ï fØÿ@ øÊ€6ÁNð€~@,‡ à=l*Ž+Àž‚ø de# ‡°údÁ¯Ð2`X ‘à'a-`ï›fÀ€ Á(¨gàOH‚ê0L𬇋ð¸Ã`8›á˜á,Ô‡p¶ÊÕhV/Ô‚(Ø Gá ÐÁPÐA"ü— €Õy8Ñà[¡¼ I° TPK6X‚£° *ôOì~¡VQ+˜[á@¡›–ÂAƒ6º6Ì…²¸¬/øÚW#¾ƒTû÷Ëún~©Ð:Úø|ið=| pV;€ºÐÀ`8 ¨ aìGÐCè*¸ Ëá´€.ýSèpNØ·)rí†üWº ¶@4€>¿Ãn8 9}PiUR¥ý›ð´$Ð7ÐOsë.ÇÙÙ¹sçÎ?ÿüóÉ“'Fãý”Á÷RyùéýÔ¨M¶¹F8Ñ0PnÑÃwÐU~sý ©5eÁeóÙL° 6ƒÚB78 «à(è!jÀÓE™e€E°Gþ"8ÀÒ`œ€*ògo \ƒh ;àihÛ! CDB;YvªpY£•pr t Ì‚Cpf^dÂr8!0<áh ÕïüNé±G‰²83Ðè­*R£ëQ¥}{¾ü’!CÈÌ$6–jÕP©˜4‰#ˆ%9?¿’’u:Æ'8˜#GøôÓ¼J÷®±Ešî IDAT®èìï§Nå³ÏØ´‰ãÇyóͼmãŸ|Âûïsè™™4nÌÛoßÙZ-“'óÝwœ:Ř1xxм9³f1t(z=ÞÞyQöìaȉˆÈÛ_ ̇²s'¯¼B§N|÷7rñ"çα};#GÒ¥ ÇsàÏ=G` ™™Ìk§Wš“Ó­¦—ŽŽ891n|@t4/Ò¯!!yºvå³ÏˆŠbÀž}–W^aÔ(ÆÍ+W˜5‹Æ²³Ù¿?Og Ÿk×8xðVìyäHfð`4L&t:¼½yë->ù„M›°XHKcÞ<ªTÁɉ®]™;—+èÜ™—^*鬺¸”C}´({gÔ[åh TKj³BvF“àk˜);s‹`/¼ ±ð ¬‡j0Z@XWa<áHApŽØ8£Çàeˆ”ãv ¡ÔƒÿÁ9x6ÃH ð>Œ‚'à+øFÀ ?‚'L t†SpÔÆ¹I„E0 <à,L‡>ð< ÇÁêÂ4¨ á0|nS«‰¢jÜ}õdHÀž„Tˆ-Œ‚vPÎA2¸ƒÂf(…Í’tñOÂç²3ºê@­BÇxb ,„ø€½ð–|þËkÙfˆ‚ê²P¢ ¢ÀÃï°·`ˆ®`„)`»ó ü½`œ…ÏåvëbtÉ¡_†CÐÙæeþ ÿ>ð<ü"åöÿ'tà"¼ Ï@[˜ >ÐÖÃHx ÎÀ3°Iž¢ÀMö è ¡L‡,x‡õ £aµì¬'a Œ€8)¿…Í{—?¸„Ê ÖÀ—\¬ñü€ó5šÖðôÌ« èСÊ+ªW¯^£F©²ºe†›ÒÍ_/‹×MåM$H€ð œ„66Îè!Ø+Jî ¶©±ÆÀxÈ…ƒ6ÕêÍ·qþ ŸO=Œ…0VÀ1˜ ÿƒLPÀ/0ރͰ¾†1ààOhYÌ,ó ¸Â{`‚¾63æ[(ÁÿÁÁ˜Ga„Â`h ~¢Bæ¿ÅAr0xkÊ•3Zµ*ÿÍ•+88P©Rž¯ÁêÕ\»†‹ >>=K[üýY¼˜sç º•]:aBÁÅýaÃhÔˆ´4\\¨W/oY¹G5âÊ$ÉnÛøíàíÍüù$'@x8J%aa,_ÎÍ› PäÅhgÍÂÑ‘˜ j×¾•Ð¥ áádeå¥`öîm·ƒÊZ(ÕúÒNÊón‹ÜJôíKùz²`Až¾U„…‘”„‹ áá·–ûßz‹>}0ðóòbçNa2áíM5Y´¸Jþú‹J•ì&6Œ§Ÿ¦¢¬\±"?þHBj5o½•wlÏž4lHl,@¥J·:C÷îèõž +Ö{‰ƒ©Q#/ªZ({gÔSå øYü®ªä òOàkãCàuöÁJ à<Ü„f°ÆÀ Ødg(‰ÿ,‡ð†\¶d\€ÐvC,®`½;@,„÷àIˆ„§á 4‡SÐ šB{é¿@=äýà¹ÞýJ8ý¡.¬€†ð;4‡Ê ‚:° úA¾~o-¨u²Þ…^ !êC3è'¿´W ”ð¦|ˆµê÷nè}Š\aHjsìUX¿@ …Wá-¹‹ ,?Ù%Œ…½6j`\‚«Ð>.~ê"iM`ª}£ ¾?†~ð©ËœmKÓÙŽ…2z›Ã †ˆ‚ „\Xä00à_‚€íÐ~„¾ð`†ú°Âëp|lNà_ò{á FXÏ€#¤€5}'°Ä:‡#À ¾µiI4‚šà-{¨¯Ái¨b3/ÐÚÐøAÍùhÎ×ʯGŽ9tèPkßðððøøø;vtìØÑÕÕöc}qV8)ƒüÍþ7õ7™Ë@}à#áw#| OÚG=  ƒQ ²O¹ŽWh r$µT…mÐ^¶é™ 7poÐÂKà‰6çó,ü [ÀêÃSð ( 7˜Á lÒ3ZÃG Á ø±xgô;8)ÐÖ@Kጓ?ØgáØ• ZÃç0 ®À?°¾„ÎðŽüIÜžÏ Re‘uJa*U*è÷!!·ây’ÄéÓv‰˜:Ý-qøªU ÅU+¡N"+V¼å0Ý)¡¡4jd×R½zA§Ö*óXT ±Ê•o= *ÚfŽ&¥UÁõöÆ[¾=©"¶¬ÎqaÔꂺ¹Ñ¬P LGÇ"÷õµ Íž=Ë;ïPµ* ddð¤\b78¸ˆrYjõ-O·œœ5Š ¸y“ÏJÍ­D({gT…ª¦¶f÷œîßë¾×+ô¤Ãa¢}‘Zr¶ª?\†dx2¡\ƒ$0ÂUûj(ùWçÍ I¶=FB"Ô’„€ëÐUžÂ=‡tø¢ä_kšã;ð ,ƒ˜MÈ€ÿÁ@ûD-h@+ÿ®¨a°1Ý3n#°žòO²5vRÂÐBm˜y·9¦%&°~Â!dg´Š<¢˜ÀL6¼ ¡!ä–Q\ ]àe¨Ýà0$Ÿà‹ämþp, A"x€'èàh(c½Ruƒp¦Ãly‡ìÈ€¾¥½ÎV`†9àt›-JÅÞ…Ñp ÆÀ:°ºÎ…Ò%­ØºƒZä×k›¯©°Wr%$Bˆmñõ² s 6Âið†-6!I…¼o‹Ò@*mÁ1 rÀ ’@ >r¶hhmßS{{×®‚T #üÆØ‡½ ã‰ò9¼aÿ‘³=P¾–}µœçÚ_„(ãf)í$¸Ã<¸»áU P”¦”‰f±æÌgâRã";D._¾¼ž½²‹ƒƒÃÅ‹M&“B¡°*᫊/,XVÔÑÖialqÆéÌš¨5–ý–Á0†AÐÌðœ R€R÷Â2ˆƒí0Ê)§>á@kXJEµý¾‚ ,ÃØ ›Â˜Ê¶ÊdIo³ŸOm/w°ªÁ¯Œ·Ù¹¯¶÷ÁæÙ|ï¼`%ü !| -Dòè¿¢¾±~;S»f.ÍTwxäQ*Y° ˆvwwF– ]rÏ dĈ0ïC…‹ :+>ÅrüëãÒKRA§g)´†ëp>$ÁP×rÌ£øÁ4x΃?Xk°ºAx &BUð„ 80[ޤ‚ÿƒÙ`€­P  3̇I`†­0üás¨>`’:³á[èåžý 3|ÙT—.Ì.H€Ø ÙТ˜çuX*;¸¶¿Žµ`®œêÐFþ¥¬KÁ*C}¨zø”°ò×DjÀEX>м¡Ì…‘ð ´)j`} ×aX )¸‚ƒ¼²9ݦ³ªÃMä¨R0(ák¨ÝÀ«Af9ÿÁzK— S¡¯`Ö@,.*µ9Œ…å à‚ƒp V@%ù%o†•àËàsPÁ*H‡>¥¹Å½á}h—!Þ&ÅÂÖAu¨M¡3|k 9œgyÓL‘µÔ+À ø *C3H=p`5T&°ö@p7›%þš°ªA 4/ø5U¢ º°?`äÈ‘}:ôñÎ_|²'55uÇŽýúõ;xð ŸŸ_£FE–É+;´ mk§ÖqYqIŽIž8`|ÂÈ5Ø›¡?œ‡°°PP³&Ì !¢áÜ€¿ä7wœ‚f Îò‰²~öÖ@ T}\w{ÏÒJ…¥à]¡Ô…Yð"ÄÁ9˜Z$ëa%8ÂJ˜)76ƒ °ª@C…a\ƒŸå+ò¦ûŸAOC-¨ 3åløƒ0VB[˜Á"[ô_¡BUÃX£GnÖŽ­=•%\‘ÁCǽª'UI]©›S·SQ§bsbÍýÌi#`6HðÔŒ…oÀ^‚LЂ,†9ð!8ÉÊ,ù1•Q'¡Œo@ /‚4 _À?à -Á”ð1|Ÿƒ"lÒ€Âä4Ö ýl¬õ€Þà ½ÀZØÄN:@”Mj©•`›S¼Î@ ˆƒ8¨~à ½í#pˆ•ó&_†ü{©f0¶4—§¶fÙþ O@}¨a1T„W¡±|l+˜;ÀZ€|³a:„À[r·pûÈ8Ç¡$Â::0¢@‚>6 jøæÁßPQvF]á;øNC70Ë)³ÃáoÐ@wð„q`¡ª¼fºBà) Ò^… Ð ÁuY  ÖASh a<ü©0zƒ >‡—m’=€@ ‡6[Éqµ>ó@_ËQ7àyÈ€õPC-XßÃ*ð‚Q…ì,`óë°  $Á?`„Ö°Ò¡ 8ÃQØZøÈf‹Þ`È„MPšÚ}Mu’®¥¾e¿.O,x¢Cµ¢¤¯ðåË—­ÑÍ›7ûúúÎQ*küT~Ýœº¹ä¸T5V]ç´.±R¢ôœÄsrX´^Q9—Ï@¬‡Ð®ÉŸ–êð7D@#p’ãñ:˜ þ€œ¿kýì5**àšO3˜ÛÁ º‚~€¹ðh¡( T…,p/xQ>6–Á ùCe¥Œ‚ ÐÂÓp¦+|hãS6€we}eë®5ë5í}p€n „oþÝàfqk§oiˆláØ¢†öþíÛeÂ=,nZS[3èjЈ7F¸¨]ÎdŸ¹ªºzU}5S‘™A†ö)­výbØKP@ÈÀ•a–}KWùÖ&˜ñ¼`w¨ñš1Ó=S5N%%J¬Äµ±«Ò¢ÄÞ(4Å›…ZNÂ(±Y÷‘Õ:­Þ[e‹Á’}#Ûø—ѹ©³C5»•ô±òPVþ¯Ð©±€»hRÈó #t´o¼ð¼¼+ËJ(| ÓÇÆÂ±ö;ý­xÁûöÍì³BK×PÂ0ȯêVfÛw°@mûýLùzØÅê-Ž’ƒÙ§‚¹BuSõED+çVꢲýí‘$©jÕªþþþüûï¿ûõë—¿éþ¡@ª õQùTÊ­T3³æIõÉëªëWTWÒÓÒ¥‰q ,tÒòå– ´5à°ill/2Ÿ?B Í^ºÞ •̓µ[øÔ¾Ïpûÿ²¥lEm…ÓÛ6Yo–¼×yk×”õr4ÙþpIÎÐ(ð¬Pèc_¾ôYî'Z´:Içkö­hªXÍ\­©¢iK]Ëu ÚÈ; ²²¸ëK§ŸR¯]»ñÔ /ðå—¸Ý~˜à±ç:£À‡ïhÆkŠ3Å%šõ‰ŠŒ?¼þ¨¡©ž^úñwKâÍÄuÓÖådç¨ÕêÃÔmZW•uÛùCÖÒAÙ¥ôJ‹Mûó?¹ŠÎS;ûüDmÀ²Áªît;eBo‡¹&SY øàp‘\|”>¾j_GÿŠêŠZEÑZß…Ñh4íÛ·OHHˆ‰‰Ù¸qc=´ÚÛ=ö®qUº¶wnf ‹7Åß0ÝHÒ'¥kÓÍ3Ìðˆ½Û\¶i´Í³š?hCE @á‚‹—ÂË_íï§ñ»£ï…8|˜9søñGîNØ`(XQ)Ÿ•+ùäጠî€{ëŒ*TÁêà`u0`’L ýfösppÐ:ÞË«FcÞþûmÉ")÷ª,œ¥šåŨ]Ý\•ªrUçCð¢@¡F­QÜåkN—¯„ïïïߪU«²5¯H”(+¨+TPW̘ ’¡ nÿ£À ±ƒ …“îñÞü°ò/¿åIb÷n¼½Ù»†îݱj»¥¤ð÷ߤ¤Ð®µjlÞ̾};ƪU(•tíŠR‰Éıc8@ÅŠ´m[l÷”vï¦Q£[¥’€ìl6o&&†V­Ê›»à>pÏQ»Éj5jgb>àeÎ=ÝL©ÆÅëöêõ šÀÀÀÈÈÈ¿þúkçÎ~~~÷!yÔ*'Å#éÏ9»Þ¯‹•@PHãÇ“•ÅSO±q#ÑÑ̘ÁÀ³Ïb±Ð 3f°l-Z°q#ÇŽ‘œÌÊ•(tîŒRÉìÙ,YB‡,Y† |öEŠp$'³z5k×òúëüßÿåÍ;y26ж-‹,J$”Ê}uFÁƒ",,,>>~ûöíëׯïÑ£Gé‚G…‚W^áå—Y»– ˜1ƒ½{9x+Wpq!7—¹siÞœ?fÓ&¦LaÁ‚<óÆ ¦Oç?hÒ„„""˜2åV M[ªVeÞ<ž¶ÙöÇ?°z5Í›óÏ?ôìYÄQA gT x,P*•-[¶¼yóæ©S§þùçŸ:EZ>ÖêAÕ«““pî5kæÕØŒˆ`þ|$‰Â:o.•ÅìÙy)¤Z-ׯíŒæòetº¼rDµjåµnጠ ‘‘‘III±±±uëÖ}Ð ‚{Ž£#yÓÒpt¼å‰J6‰Ü®®8:2~ü­Òð¡ªx“YYèõÙÙvà ·ƒØ|#ÌéÓH5jÎÆxzâäÄÑ£¨‹‰VÅÇsú4™™yRR¨U‹-âÊ-"ë‘Í< gT x¼¨R¥ÊOË{ïñÞ{Ûµ£]»;µW ÈC8£Ác‡Z­®Q£†^¯Ý°aC=4!Ö(ì¸t‰~°S¶úiš5+þànΨ@ð8âääÔ¡C‡+Vœ8qÂßß¿eË–Ê»+Ã"Ê):ááv ö÷¸œ°àñåîÑ .<÷ÜsâL x8Ù½{wÉ‚‚‚:vì¸bÅŠíÛ·ûúúÖ¬Yóv†‹‹5j”ƒÐn<²˜L¦3gÎàß!.pA9äêÕ«V ÑË—/Ÿ>}ºäÎ^^^]ºtqrr:xð`tt´Xô¸ÿlݺ5))©È§öìÙsŸíZ-ï¿O… ”ÞY¡`áBΟÇÁáÞ[&”ÂÊ'UªTyæ™gJÞ©]‹Å_B‡„„ƒÁ \¥{JNNŽ$I",*°¢TÒ¸ñôW©ŠÝä$<„gT (ŸxxxÜÝÆI’J¦Z,“É$œÑ{„ƒƒÃ]ijàÑEäŒ ;¬ëû%tpvvvtt¼oöÿ£‘s碣9s†_~Áߟ˜îP³NðP#v!å“þýû÷îÝ[T6…iÕŠ  œé×Í›±Xøûoú÷ÇÏ Y3T*€°0\]ñõÅÅ…¸8Ìf*W&;›^`ΔʼnEâëË3Ï TòÌ3\¸@zz^ûÓOÓ®*AF/2h O>IB ܼɉŒ‰ƒ..4làåEb"/¿Ì—_’]Ò¼‚Gጠ@ð`2Q8‹X¯§€ô‚Å£æ¥ IDAT‚^O©Ê`jyeT£É!'§ØZöÞÞ(• HU«²f mÛ²v-O=E\\±Säû‹Z-J%ùeÝ*W¾•îi6#IyÿªÕ( yöˆ¹†‡ó×_tìÈúõtéBLLI¯Îdʳ6IÂ`Àd²ëfm*jœ»Y¦7›ÍÙÙÙenŠ@ðð Ñhõ= f³ÙºýE­V«Õ"!G x´±Xøâ ®\aÞ¼[F#}û2lýúÝj¹5iFãÇÓ¸1/½t«Û¹sLžÌèÑ´iSÒ¹Ükîæ'êÈ‘#/¿ü²©Àý…@PŽxöÙg'Mšô ­øWìܹ3::Z’¤fÍš5oÞüA›#(·$%%FoooF#I’ÅbQ•ݪÉdJNNV«Õ^E:2’ĉœ>m×h±°y3mÛÚ5&%±e ))%¦Õb2ñÌ3¸¹qìÓ§£P0f Ï<Àqþ66vôèÑiiiÛ·oÿ7/§ T2e YYvZ-6P©’]cÓ¦lØ@xxI£ ÌÀ$%‘›K•*yy¢þþlÚÄñãøû£Õòúë89¡VS·.¬^NGd$ÁÁyY›õêQÂgÄË‹¨(®]cÊÂÂòÖâ_|‘E3$"‚„<<¨Q#ïÙ§žbóf.\Àb¡F €ˆ~øŒ 4êÔ)i^`ìXžoï[-üïѰ0þú‹*UJJp¸ûÅ»Zµjý÷¿ÿË‚rÆòåËgΜù ­0­[·ž9sf·nÝJíùî»ï®^½ÚúØÓÓ388¸H­þ .Œ1béÒ¥ÁÁÁ¶í—.]êÓ§OTTTݺu 2qâÄwÞyç®^D¹B¡ Zµ" /{¸»SªN€µÈZ/pp@ÖϨ\9ïÕ«kÚÈóAo“àà‚Ù…'ªV-"ÂêímçM:8P»öíΛoy>juy ..y/Jð`¹{WÒÉÉ)""B[œ¨ƒ@ðhr¨¼ÔÈsppÐ í /^ܳgOÅŠ“’’®]»Ö¾}ûÚµk+ “É´k×®£GzzzvêÔÉÇÇgóæÍééé;vìHKKëÖ­›‹‹Ë‘#GvíÚåììܵk×€€€"ÇOOO‰‰ ²J8vìØ®]»t:]óæÍCBBvìØ‘’’²bÅŠààà:8;;ƒaÇŽééékÖ¬9sæL‡\\\8pàÀN׬Y³°°°ûzŽeGh(|P´©@P±›^ (ŸtíÚuüøñãÇoß¾ýƒ¶EðP`0–,YÒ¿ÿÍ›7ŸÉÉÉÙ¿ÿ‹/¾èééyñâÅ1cƤ§§gddèõúÔÔÔôôt³¼ý[’¤ÌÌL£Ñ˜‘‘‘––f2™¾ûî» &¸ººž}I’æÌ™³sçÎ;M§Ó…††þþûïÂ-‹Årâĉ}ûöíÛ·ïteBÁãÊ¥K—Μ9sùòåãÇoÞ¼933sÇŽjµú¹çžûì³Ï6mÚôÅ_(ŠŽ;5kÖl?11qÏž=æ¬ ‚{X¦¼°$ÔjµÉd2›ÍNNNùâ\z½^¯×«ÕjgggkôbÆ ýû÷¯X±¢£££B¡0 ¹¹¹*•ÊÙÙ¹°t‹ÅbÉÎΖ$©ð˜•*UÊ/Þ¦M› 6ƒaïÞ½^^^7Öjµ¶aÖ¡,‹V«Íײµ65¬Šs ×ëÍf³V«ÍÍÍ•$I§Ó)•âæ*½^o0T*•ðÚùäææ¶jÕ ÈÎÎNKK{÷Ýw³ÙP(ûöí›:u*`0FÝ¡C‡)S¦ÄÆÆNœ81((è믿ÎÈȘ0aBvv¶Ñhìׯߋ/¾hë †™3gnÙ²E¥R~ñÅžžž×®]3fŒÁ`pww‹‹ŒFãK/½téÒ¥;wFEEíØ±ãäÉ“K—.8qâ“O>iJ’¤éÓ§ÿóÏ?>>>YYYÿùÏÂÂÂ$Iš1cƪU«üüüü¬êÌ0yòäíÛ··jÕêâÅ‹ñññݺu›8qb–~yÔQ©TÖP“ɤ×ëoG½\P¾ /F }À€ °m©]»ö'Ÿ|’ÿoçÎ;wî\ܱù_xá…üÇ#GŽ,Ð322222ÒúØ6Ó´M›6mlª1öíÛ·¯MIœÂã‚r†pF/†ºaÆcÇŽ­X±âÂ… V·ÒÃÃã7Þ2dȨQ£víÚ5hР7Θ1cÇŽ³gÏnÖ¬™Á`7n\5¦M›vúôéîÝ»·k×κãÁÊ–-[–.]ºuëVww÷¡C‡ÎŸ?âĉï½÷žŸŸßüùó¯]»h4šo¿ýÖÛÛ>|ø¦M›ºwï>pàÀF^¾|yþüù5jÔX¸pá»ï¾»|ùòƒ~þùç‡ 9r¤5Ú÷ÙgŸ=ùä“7oÞüí·ß®^½Ù¤I“ûx:^zö왞žn.kl«ï @ð0!œÑÇ‘:x{{›L&ggçøøx£ÑxîÜ9kØ£víÚ¾¾¾ÑÑÑíÚµËoß>Ãÿ³wßáQm‡gKʦW’@H$ôÐ{ïH ŠTi" ¢ øêûZ>±#Š"v±bCPP‘ÔÐ$BzßdÛÙïÝM6•baîËËkwöœ3s–’‡93Ï£×?öØcƒA–常¸äää7*ŠéÓ§ÿúë¯&“iÙ²e@VVÖž={ôzýáÇŸþy¥R}c“$iÖ¬Y+V¬Ðétiii–ô1üñGëÖ­-û*ÆŒsòäÉâãcbb EHHHÛ¶mwìØ!‚Q …BPYròÚa6ëeY§×'hµGÆ,³ÙP‡ƒ.³Ré¡Ñ´srj¡P8I’H%7Œ ˜L&û•…²,—Ùän6›Ífs¿~ý,ùY†¥Óézõê%I’^¯oѢŘ1c€#FÏï½ö•‹™™™Ã‡ã7¼oß¾·Þz $©²õ Å}ɲ\aB¡.È&%=SX+ËWœqrBüâ5ÁlF¯') ðÕhº=áâÒM’ÄrA¸™ˆ`ôÖbÙ·d4F£^¯7›Íz½ÞÏϯyóæ»ví :sæLVVVçΕJ¥«««Á`ذaƒO»víRRR:w—wçw¾ûî»á¶JÉýû÷ß¾}{TT”‹‹Ëk¯½¦×ë»uë½uëÖ!C†dff9rÄ2¥ªÓéÌf³N§S«Õ™™™qqqÇŽ‹‰‰Y»ví¤I“òóó‹ŠŠºt阕•%˲^¯ïÑ£Ç /¼œœìëë»{÷nY– ƒeäöíÛ‡ ’}òäÉ%K–Ôå—[Ÿ˜L¦ŒŒ Y–Ífsaaappp­=©7™òRSßJIyÅ×7+8X„¡Bm0›)*JÏÊÚræÌ.?¿Å‹T*¯º” ×J£·–¯¾újÿþýqqq:uúñÇsss_|ñÅÏ>ûlùòå‹-Ú°aÃåË——,Yf4ûôéóÌ3Ï~òÉ'Ï?ÿüüùóÿúë/­VaÙ‘#GîÝ»wèСM›6U(ï½÷žJ¥zâ‰'&OžgΜáÇ·jÕÊ`0\¾|ùµ×^ûïÿ œ?~Ò¤IñññóæÍëÝ»w}¯õNNNÎ_|aÉëèè8sæÌâ„5ÊhÌ:þnîûæÍqs«…@’pvÆÙw÷‚„„góóÿ_§Ry×õ¸A¸&"½µLŸ>}úôé–×ãÇ/nïÙ³ç¾}û._¾ìëëëìì ¨Tª×_ÝþÜß~ûíÊ•+¾¾¾å ô©Õê—_~9++ ðò²NHDDDXÝÛûú믋_—Ù3{îÜ9ooo`ùòåEEE–­N/¾øâ‹/¾XþŽæÏŸß»woƒÁ`°`áää$˲Éd*.^ÃÌ©©ïëõßGF¢µuÁÕ•ÈHΜÙqåÊëMš<#ri ÂMAüA¬”Jepp°%­B¡ ª¢T´——Wq$z,‘¨…‹‹ËUƒËU«V%&&®^½Z§Ó‰H´ ƒÁ`4-¯-k3j¡Óüü©©Ëš4‘¨P—”J‚ƒÍ™™oåå]_M AêJ]þÐ0c–ͲŒlFäå®[§îÞÿä}ÀÁÅAoÖ—ùTBRH  ‰[qÅ¢““Stt´ƒƒƒ,ËF£±ŠcTYÖ]¾¼ÔÇ'Ë㦻„«pqÁÏ/;)陈ˆŸ%IüÛH껺ùSš#ç\0\H3¥]1]É’³ Í…u2 áæ Á‡õ‡)‹¢Qh¼$/¥*¨©ª©›âÖZÀèááa)êXkŒÆ ƒáxéÒ<‚Pg¼¼ÈÈøG¯¿èèV×cá*j;•‘êŽî.Ú§ŒKT%&©“U‰y’¨ó&T³9ÄÙäÜÔÔ4DÒ¡°C_ç¾QQJD—šb4f˜L‰¢Ì“PO¨T(éz}‚F¡þ«Õ`4_Îß®Ýþ—ü×7.ßœQOç…š“£ÈIP$œRŸ"‘IÚ¤†œ¸(\êzhµÁl6›L&KâU³Ù¬T*k: «V{ØÁÁ RU¸ ÝÌ¿øÃn2QX I¸Ô⯞,£Õ(h4e?ÍÏÇÕµö#TI¢Üj• ‡¢ÂÂÜÜú×ÅA¸µŒš0m×nÿNñÝ.?HµÖ¯ œRZá¶â’ö’Akã2Fy $ľxñâúõë›6mêêêzâĉ &4®á'èFcº““8YÞjµ:D÷î8:fЂñÆ®üçŸÌ™CA:/^å`ƒß§W/œœn¬·.ƒN‡$aWó @–ñöF_nqH/’@¯^õ"Ó꟢Ñy}g]¾ÌÇ3w.þþ53¬j — 7ã:;ë Õþ€A¸^µ·›þ¨îèAóÁõÎëE$*Ô>­¤ýVóm¬{LKüp2ÙÙÙùùùZ­6;;Û’u«F™Íè rd9'99çÑGs23sL¦³9·85™(ÞÙo6#˘LÖ–*]ů-í@—.ÄÅñÑGtj9½¸^˜,“›ËÂ…¤¤”œ^Üoé²bW׬qqüðCÊ2«W—m·ÜZq/&»vñØc ÜX2ƒ2wg¹fq{™ÃìoÖòíŸhy»|9ß|Sö‚åÏ-ÃÏmÛX½ºªcêš y–ßxeþS(Šêzl‚ \“ZšÍ2eí)Ú³Îe]¡$ö* uC+i×kÖ†¨C<µ‘¾Î¹»»[^§yªo¼ÁŽÄÇsß}xzòè£DEQXȧŸ²oJ%wßMïÞlßΦMdgÓ¬—.Ѭ>Ê©S¬^RÉÅ‹„…ñè£Øn¢YfãF~ø£??x€¦MY±‚ýû¹t‰ÄÝ… éÜŽ/¾à·ßpp`Ú4 ²^áÊbc4ˆâLf3‡“›ËÀUÝÝwß±~=f3“&•4îÙÃûïc6ãèÈÒ¥øú2cçÎqîÓ§#I|þ¹5ãUR‡3`@©¢ ×Ó«ÅUoÿù‡+ÈÍÅÑ‘çŸ'0`Þ<¦NåóÏÑj™;—ùûoÞ{ü|Z·fáB4yë-._F¥âŽ;9’£Gyí5àèQN¢];/ÆÁ¸8Þ{¼<:vdþü –"j5÷ßÏK/1m×ðk/‚pýjifô¬áì~ÕþóªóµÓ Tè”êÔAÕÁxC|]¤ÆI’äéééàààîîÞ¨Q£ZHíd¯[7†ÅË‹‘#=__d™—^âóÏ™5‹þý¹÷^.^äìY~ÿ>}X¹’ŽY³†Ó§IIaåJ4æÌáÐ!žzªâ.L&.^äöÛY°Ibî\ ºwç¶ÛpwgøpÆŽ%(Yæ•Wxë-æÌaØ0k¿{÷2q"©©%×´üàƒW¹»¨(ÆcݺRwÜÁС,ZDß¾ÖIıcéÜOOÆ#&¦$ÊüãbbHH(uú’%,^ŒÁ`}›šÊ!øøðÀtîl]º lØÀ#УC†PXH|<#GÒ¶-÷ÞËÖ­|ø!@ZÍšqÿýÄİ`§NѨcÆDT11ôì‰RI|<ãÇÓ¢óæ±y3ï½WéýŽƒ6\åkA¸aµ43šfJ;«>+sÏÉ¡ºWO3¦™Í ;ÿhXXØ¢E‹,¯V=ÑWzö$(ˆÏ?gìXëZô46mâî»ñóÃË bc""8†þýùüs22xøa\])(`þ|^|±‚}Kj5'òóÏüõùù;†BAïÞ´iÃòåŒM“&¬[ÇÌ™Ö~›6å÷ß™: Mžû* S§’ž~•»kÓ†V­˜2¥TcA—.Ѧ 'Z–É2a‡3aJ»UÊíÛ³tiÙYƻ聆°¤XÀÏ?ãïÏããìL·n¥Ž|î9FŽ´¾~á""èÙµšÛogëVæÎ¥C²²8p€ÔT”Jöïgöln¿ï¿§eKî¼Ózî÷ßHÿþ880a›6qï½Tøo†{îáÙ0oQ_S„PKÁèã•+NWj§/A¨BŠ2åŠîŠÉlR‰Tص¨°Œ ¾þš”J<=IN.Ùî쌿¿ujÐÃÃÚ‚ÑHnnÁhv6£F€x{[/[žÉDn.k×òÓO EI¼Õ²%-[–:X’3æopÝ:>ø€×_G£á§ŸªÚ'YÁ§veq23 ®¸U»v%¯328{–dz¾mÞ¼dzòdÚ´aëÖJ‡qáçÎñßÿZ߆„`0TŒ&ðÖ[lÚÄŒ•^Pá†ÕÆÏã|9?GÊÑ)tžT°PO^‹ ¾€d ýÿu¯2˜©ž´’ûa#˜¡Œ»ÚÁfÿE¿Áz•kσ/!Urâ%p‡\pƒë-cÓ5ü^È…\p‡k¶ùúL¢ÂßoùÊü 2n©Iz³Ù Ôtj§òL&ŠlH45â‘Gˆ‰±~¤P”Ý¢^,=ÔTüý9yWW,¥^-+GeÙú¼;>žK—Ø·•Šo¿-uºe ”…JE£F<ü0&”ôkqþ<;v0aBÉÚM³™_%+Ëz°…$¡Õ–ô[™Áƒ6Œ¢"†gãFk¸éì\Á¾Ÿøx~ûÛo/5˸e :cÆXçP9}š¢"ÔjdI*ÙoŸ% $„ŽY»GGÌfÌf ¶oç™g˜4 ­–^(u#öƒ‰Œ¤}{Ö¯·R–KMß–áéÉ=÷ðÁŒ‡¨°%Bµ«¥É¡"вÈ*¢Ê½¯ÀI¸³òxëºì€ï`9üûÅr>Ð~­×ŒþÂ;7Ú×q®(͇/ Oå_ÎbßÃ8˜TÉ1•ù–ÀUׄýßÂX ß_gµ.“Ì Û³¥lƒlhð9n/\¸pöìÙfÍš9::þõ×_aaa­[·®Í¸»ãàÀ“OÒ·/£FÈÌ™<ñW®àèÈîÝ<úh¥ç¦§óØcôíËŠÜuM›âîÎÃÓ¥ S§Š›K—âçÇòå%çªÕxxðŸÿ0p ÇӴ)sçòĤ¦¢Ñðë¯,[FPÀ_ñÀ TŒÊ2«Vqüx©`´ys4|˜3³™U«¬‘ß IÜsÀèÑŒ‡³3 %“—­ZqâO?MÓ¦Ü}·5Ú‹eþ|zô(Œ¾ù&Œi=fÄ–-ã¾û˜0_~aÞ<*üÕ›0wßeñbzõ".ŽˆfÍ¢K>ýIâ»ï¸t©äàÞ½yûm4Z·fèPÆçãyäz÷&.Žî½·ª_Ð;îàí·Ù¶­Ô—#‚P-êôI¥ © \£Ð:€Ÿí€ ˆhjŒpá8@ȆH„Öp Úƒ+œ‡88'À Â@ fHƒ8h €K ƒdh'¡-ø@ ˜ Ò¡+¸C hYpÄnðfȇcÑà2$ÀQˆ…“ †[¿©p ²ò=c…pÆ•7e8 ‰p½9"eH8t éÐülc>á$( œÀ ™p¼¡m%c6B2UÓô³P­Îœ9³gÏ•Jåææk6›k9õöæóÏÙ·ôt,[ùçϧuköïG’7ް0 ÅLJÿýoo¦O'<œ³géÚ•Þ½9p€… ™6ÍzA6mbûv²³­×_·ŽŸ~"7—O>áÏ?­‡¹¸ðÕWìÙCRz=’ÄÌ™DD°{7ùùŒcgÚ´áÙgË®2…´´R7¢R±u+[·’™ `6[_¼ø¢õ…Ř1Ö·ï¼ÃðáÖÆˆ¶mãèÑR×l׎_¤QéUΚUjͨ»;¿üÂW_qâáá% LŸ|²Ôž÷  ~ûuëHH 8˜þýž~š¯¿æüyÆŽeÂ""Jº åÌòò¬çþô“õܦM¹jíØ€fÎä½÷1Bdû¡šÕQ0j„=° ¶Ãf¸¯ÃIH€Ÿán˜Ça „ÃEèoƒÒ „A>Àc°ö dð‡0xþŽA2ü¼á-€àè'`< á˜íÁz4‚¯á%øZÒáhYÑ-$ÀDpO8 ïCgX ‡á,x ásXà$ÌÅ•|'‰°ÎÀ#`ÙÏ+Ã2X ]á¤-Q£RO˜%Pƒ*PØþÁ=pBá8Œ‡W „Ðâà;h K!²ahàUˆ€`1t‚8K»ë«l]Œ‚ÆpŒ×ò5P„ºWûOç‹5oNóæ%o•Jú÷·L;Z_,X¶u“gÏúTS£ IDATâäÄÝws÷Ýe/جóæY_KíÛÓ¾½õm/»‡ !!„„”¼U(èÕ«Ô-[²¸ôFIbìØ n¤iSëô§åjÅë,íÍŸ_A#е+]»–j‰Š"*ªìaÅûŠŠyyqÿýe.,ÛT¶Ñ͹s+‰ƒÆ1lXIK£FÖoþ͘«ëÕSý ‚ \¯ZF“á øLp<¡Üa$/_á]H‚ }m ‡ÇÐÂ^¸a3<ƒ¾†µðlËÖ‡xX AøØžeßn°^€À²‘¶l L‚÷Áî!`‰Fð3¸‚^ƒ5Ð>€°~µ–ËàmÇ`.ÜYÉ‚Ëøì®$Â'ð!Œ„`ùi7 ì³p‡Àà+@ý¡xâÄ·ÃÓðÌWàü; ‚å°Ö6æévc΄Ça)ÜI0æC(Œ†A ¸Â.Ø«àp'Ì„Z}*%I’$IÎÎÎuÞoo:t¨ëA ¨ >Aø÷j=}VÀðxT9—væ B NØ£m†-‹½Tà .àTùã¡Þ…O !ÇöQ ¨mU -+ »Ùöõ„ŸÁXÑ÷¤‡Ça8‚FUÒïeH‚UðA*¤^óîŸ,(²…w­Á²Âì«rU¾-c³¬m°ßtì°Íª7°<¶ëh›ï,/ÎÃ7° Œ ƒs .¶ë÷â3` | ™ҲPwºuëîíí­V«g̘ázóÐ *M¶õ Å/Àv€~ƺ;üiØf÷ßç¶ðúZt=ì-l…î¶vo(‚Û˜A[¸} '(+ vsávÛZ‚8X`·óLAáÚÔz0Z¬9¼gl’@°/Bý0B[¸îË’%4+=KÚ<ÀÁ‚mó¬= A?¸ þð¼­ >'¸@íÜâ9ב¶ýæÅûFC tËV†`€HP\O¥5t…A0.‚?,ƒ÷¡%´„·m3å½m`¼màsð‡àˆ€5Ð l›´Šÿ ®d^Y‚ƶõ£@ x¦B\†â}-` …®p\á ØÐ–U2`WØÙµBý`4M&“N§;wîÜÅ‹eùJ­Z½Êç ½áë˜LÕs)A„†¤®‹ÐØOO®(ýQ ì*w¼?üQº¥xáãm|m{ë_”>²_¹YØ7m/•>w,Ø/´ó†ÕvoàçrÃ<á£Ò-½a_EG–ñ$ù„ØXþù‡¢"Þz ΜaÕ*ºuãÌNžÈÎfÆ ^z‰'X³¦¤„æ+¯Ë‘#œ:U¶º’½^½ˆŽæý÷Åä¨ B‰º^3*BuóððèׯŸåµ%0­ÛñT!7—÷ß'?oï’JBM›Òª@P:€^ÏSOqö,W®‘Az:€Ÿnn8:Ò¤ ’D~>[¶ ÑXƒË´4ÎW¾ÞZ­¦o_€€k­ÎèÒÅZºiìXvî¬øÄ¸8ÒÓ‰‹#.àâEÒÒðó#"‚‘#6ŒáÃéÓ§ª[^¸yóX´¨T%RA„[ÙÍŒZ¦ê[™â‰ú60A¸yHJ%J%öó¶e¢´ÂB-",Œ?Æ``Μ²Q*‘e 0™ $< <ß S’UÂh—æB¥*õ¶ÌannÖ.€Õ«±ì ûýw6ofçNfÓ¦RU7Ë5Šà`ÞŸÇ㦪%‚PSê_0ú+¤Á[Æ¢`%Â.hò¯/žj[u¥i"`Í5ä@MÇÒ‰«A77~ø*Ç äærÛmDFò矕Îw*téÂêÕÜy'ŽŽdf^ÇH,õ³³qsc÷nÚµ+ù(/¯äuûöÒ¾½õ€ÄD,µ ™6iÓÈÎæð᪂Qà‘GxôQ,àæ)Œ%‚Pƒj#UH 'œ¼ð*¤°ü§zôZ´Ö7:xþc‹DóàX ÑÕ4”§ \í‡ß5Y @(º†ƒŸ„N0·:ú®/¾ÆŠrººš]NRƒžÐÞ¼yó‘#Gbbb"##‹ŠŠÖ­[wåÊ•éÓ§7ªb1c=æêÊØ±ÌKÛ¶œ?§g¥GΚÅÞ½tè@³f?ÎÓO3kÖµö2r$;Òµ+$'³Â–i®GrrhÓ__vîÄ×—7Þ`Ⱥv%9IâÐ!€ÐPzöÄÝãÇYZY¡]›±cyúi>ý” ®ux‚  Xm£I㉧«É5YUzi.l†>vSžëÀw°òákØ Á²ác8 Ñp­ÜåyØÎpœ`*lËFZ/H„Åë ÎCDÚjW^‚Ï †Àm`€Ïá (Á.Â"‚À ~O˜áT, ¾ƒ¿À ¦B´­@ÑaH†d†Ù¤À§púÃÈ„Í0ü«éK¿å1f“]¾=Àà…—¢AoÝ+,,Ôét–K:îfÙJôêÅj[BßeËprB¡`ñb¦MC«Å×—ÂBÜÜe†ÇLJýûqqaýz<<Ðhøüs’“ÑéððÀǧâ.4~ù€aÃèÒ@­fËbc),¤kWŠS²zyqú4/–<¸Ÿ3‡ñãÉÎJ2†¦¤•ˆs™2¼å¨Tüï<û,sæ r¿ ‚ ÔÒcúe@ )ðŒêŒõýßð>¬ƒ¶võ{t°æÛJ¢ûA°­0’‡m¤s!ÀJÛEÔpAk Çà¼÷À*è ð>Üaà>f‹ùÎÁ(¸ zÂó ‡AðL¡Ȱ ž†! ž€?a2l©¤ôå^8 # ¦Ázð‚0p³õk9ë2Œ‚>ÐÞ€< Û`1 „90 t•)¡ú™‚”JéfJ½y½rrr$Irvv …R©Ôétz½¾®ÇuMœK‚9?ÛŸ2I"ÀVäÌݶÜÅòŒÛ²å((ÈÚ¨PиñUº$š6µ¾ÖhÐhJÚ»T´äÆþx oo¼½Kµxy]߆¤‰éу›$à Bͪ¥`ÔWéÛÜØ|ãÓvO@&L…=ÐÒnÐVȂɶ·}!>…‰¶Ø1vÂOÐ |a>¤C ÞðX~ ¥€/Üûa(\†Té°ZÀt[k ^58Àg0|a2œ„Û NÚþÌ‚qÐvÁÝçXˆ‚¿mŽ…©0ö@'»~ׂ,5¸À ˜_ÂX OB.<wUÇW/”f óSù5àÇôƒÁÛÛ[–e-ÈrssóòòR©êßñ[˜J%ê0 ‚ XÕÒϧ‡ˆ®y]œH8A<ô‚hhj‰šà˜ •†W œGiðô«é¶Ùc’vRwU÷H‡Èº‹ ‚ %juýü Í ;w,Î[­V(´‡7 5ì„cpo¹á¸Á°m/@ ŸCSX íàup &Ú=UwÙà¡ô„Ûm-‚8 I´†oá"|g¡9h`&xÃxha¸íÜáð)œ‡¡x7ÃÿÁ8 ¹,ƒ@øü`™]Fª»aœƒ"`\á$DASx‰H´Ft4t|8ïáÛ·Ð hØûèäää5kÖìÝ»·¸åÏ?ÿܰaCFe•ÚoN_~IÿþôïÏ\ý`“‰gžá÷ßk~XµëôiNœ•Eo …… ÀÂ…¤¤ÔõP¡Ôjìã,9Ñ 5„jéŽ]T^LP%¤*Só.å™6+ƒ””É?ã–ÒÏÅíð2˜mOó-í¡j÷VcËè9€vyÂý¶KYZÚÂr[‹åšw¥÷'Éäšs5£4ªgUÖÊÇãÚ]ЖÚ]ª¸x tK+xÍîHK£ø¡R}Ìá¦ð&¦&aư(9j f`3u³¼o©Xnnî©S§”Ê’t‰‰‰ÿýw‡|*Ëut1‚.]XµŠøøRíÙÙôïÏ?Ò¤t oï«g\ª÷ÝGt4÷ÜS —:q‚GeïÞ’´BCåèÈk¯ñØc|ü1ÿû_]Fª[mOÄIH-Õ-»7N6&'“ÓõéÙr¶-Av6'OâäÄÉ“4ib­zœ:Å¡C¸¸0x0îpâÉÉ8;³cþþ´j…$QPÀÎääM”m_ãùó8€,NçÎ'=šgžaýzæÍ«¦_¡¾R(ˆŽ¦C+Û+7³ºy*ì"¹„«ÃÃÕáfÌæ›a>pú÷Ó Å-0­Ö HH·ÂTh999@q^§bÆÊª­×':>JQZ-iitéÂúõ¬[Ç«¯ÈsÏ‘“ÃìÙ|öY AM&¶oçÀ23ùúkÜÜxàüüHOçÃ9p€W_eܸ’Žîº Z¶¤°”æÌ¡š5#8˜dëVà?øæë)ýŬY\¸PÁ°fìXúô¡}{íÛéÜ™ýû6Œ38{–%K8xóçùäŽ'9™ÔTºu#*ŠÜ\FŒ 0-xê)V¯¦W/ΞeÄÆG©dçNÚµ«87¾JÅÃóê«Lš„GµT9ê7•J¬Ê¦:^¢x³„ e_h(4}ûöíСƒ£cÉLðàÁƒ{÷îíævsä0›™=›Œ þü“'ž`ÄkcñÏ`Y®øç±JÅC‘MŸ>¼þ:ÁÁXR„…ñÉ'L›Vö,Y桇˜=ÛúvÍ Ö­C©$7—>`æL^yYæ³Ï8ØX:t¨tÌj5ëÖáêÊÅ‹Ö`tÅ ¦LaÅ ŠŠ cÛ6F¦[7æÏ':Ú:—)I|ó *_~‰“Í›óæ›tëÆ‘#øùñÈ#øù!ËUåÆ¿óN–-㇘1ã:¾dá&Õ²%|@J 7ge_A¨”ˆ±¡AQ«Õ>>>®®%YÊ\]]}}}íÃÓú#%…¾}‰Šbذ’FIÂ9—›Þ½ I²þ§P`ŸÌªÂÄV €Baý/>žP*éÖ„ºt¡¨ˆ¸8,àË/9tˆÁƒ+íÚÛËʈˆ´Z€³g­×5Z·æòeëØìÇ ÄÅqì˜õý /pþ>|ôF#UVCÕ£Ôv…-|})²Ѹr''T*¢£yûmmÛÈÍeþü«_³8ðuu¥ Àú:'‡r‹x­<<ˆ‰áí·­'*¨Õ89±};))lØÀþÃС„…U|:p×]¼õÛ¶1~üÕ‡'ÜÔ6o¦kW¾ÿ¾¦þDB]3£‚ÐpÆ'Nœ>}Ú¾}zzúÉ“'³²²êp`•Q©hÑ‚¨¨’}BŠŠâàAÒÓùö[._.i÷õeï^Nœ -ÍÚ¢P Ëüø# hµ˜Í¤¦’@A©©\¸P –ѳ'‡óË/üó?üÀðá(•ôèÁêÕL™‚$qá;^Ç­ ʇ’”Ä–-üó½lɉ]]Ù½»dÌ11lÙÂîÝ <ÈöíGް};..ô쉃ÃUJØ{z2mï½Gae%ß„†">ž&MP«+žì„›—F¡á(**úí·ß¶lÙR`s:thíÚµ u8°k¤P…¯/´h£#ÑÑ&àèHß¾ìÛÇÀ/4‰ž=yè!Þ|ÓÚâêÊsϱa³fqø0&+W2{6ÙÙ|ñ³gkí¨}{ìW.´iòe<òãÇ3t¨5õÒˆôëG÷îL™Â]w•šIµçéY²œ´qc‚ƒ.¤W/† ãÿþU«J¦6x…‚ùóyûmd™.]xã –.¥Kž{ÎdñòËtïÎ}÷±|¹õ‚U˜;—S§Ø½û:¾jáfd6‹9Q¡a¿¯¡áÐétz½^©T*ì&ÓÌ7É\K2EK@6r$ ëÖ4nÌ?`2¡R!Ë'QuqaéRL¦’‰"…‚ñã;³¥Iâ™gJm]²œëäÄ_”ú¹®Trï½Üsõç½åûëÚ•Ÿ~B¥âÚÅÜ©ß|cÃÌ™%c{ûmŒF$©TʧŸ"ËÖµ­Àw2~¼u£’eH]º°}»õ•êêÓ`ñŸÿ°cŠ`¥a2xå¾ý–ÿû¿ºŠ Ôñ÷– 4ƒÁ`0¸¸¸ÔÏíJ×Â.[?Ø­U*­•yfm ת¸H™ –¿²ý¥ÊÌ}_¼êåöc°?R¡¨x-¬eËTƒ©ð¦ªvÿýȲˆD2__V¬`øð«)7ñW— 4îîîÆ 3›ÍvAPHHˆ,Ëþþþu80¡¦•p…†D­fîܺ„ ÔŒ BáÑh:”K†^'ãA„«ºñ`ôìÙ³·Ýv›$6õ ËÅ‹ëz‚ ‚p ¹ñ`433s»% ‰PcœœœZ·nݼys•J•’’räÈ‘´â6‚PNQQ‘ÑhtqqiHÿJ,*"%@©¤I“ºÍÕ$%Ѩ‘X»)‚pnä¯Ì6mÚ|ûí·²,Wûh{—/_¾té’Z­¶-Z´èÞ½»F£‰ŒŒTˆÕa5,¬Š$ãõØ®]»bccGŒÑÑ.%æÎ;÷îÝÛ»wï¾}ûÖáØnØ©S,\ˆVKv6gÎÔ`G&“5Ãhe ê«–”dM;µaW÷àA® F}||ÆŒSíCì]ºtiÍš5¥÷âªT*Y–5jÔ«8ƒ¶ Ø)((0 NNNö&“I¯×›ª¨)Y¿µkÇöíüþ;³fÕlG:Ó§sâÄ £üAP[¶PúëA®Bù„ƒÑéxê)<<˜9“NeV®dëV$‰ÎyöÙªFn0Ф NN¢:Ž ÂõO{ë£ÔÔÔ .Tö©V«=~üx-G¸9˜Íæ&Mš„‡‡»”žÙóöönܸ±»»{] ìºìÙÃŒŒÍÿ˺u|ùeŇåå1u*/¼€›÷ßÉÄ–-H~~üô11¼ù&²ÌË/óùçüç?̘Á½÷’˜ˆÁÀgŸqàÏ>‹‹ K– I´mË€(ôëÇÀ4j°};ï¾Ë’%<ûìU –BIi{AẈ`´>ÊÌÌ4U ¶1 åI’4pàÀÉ“'{yyÙ·wèÐaÖ¬YіšõŒNÇìÞm­Ò ¬[G›6„†ôèÁO?U|â_qâ#FPP@¯^üý7mÛÒª3`§OSXȺuÜv’„‡MšXkfªÕ<ðÑÑÜv'N Itíʘ1( DLŒu§”Á€VK|óh}Ö¢Û¶±i'OÒ­ÅI̼½ùñGvíÂ’¢ÊÙ™U«øáŽÇË‹ùóQ*¹çBC1‰ˆÀÅ…—^˜8‘vˆÉ“ñ÷G’xòIš5h׎ÿþ×Ú…ZÍš5üú+Z­uv³[7._æï¿ b÷n4šªF®TrùrÍ|)‚  šFë)F³gÏžC‡ét:@¡P4kÖlÈ!þþþu=:¡>ÊÈÈ|||êz ÿŠ$Ñ´)÷ß_A{h¨uc“…‹ S§–:fôhë Ëf­{îP*éÕ‹2™y§O·¾hÞ¼Ô6ùfÏ.yÛ¬‹_ëÈ{ödÉ:t`Ó&Ä:A„k'‚ÑúËÙÙyàÀÑÑÑß|óMfffLLLDDD½Ý‰"Ô¹¢¢"¥Ry³£7¯Æ`°.oA®‘ˆlê5…Báæææèè¨P(ÜÝÝE$*TaðàÁ}úô)Sµ ˆŒŒ ÐTýŒY¨®®u=A„›n¡P©TþsE£ÑˆHTA¨·DÒ{AA¡Îˆ`T‚ÔÔÔmÛ¶:uªüGZ­öôéÓW®\©ýQÕ­–?.yû×_lÙrƒ—2›ùãÞßšT_A¨"„† !!aïÞ½çÏŸ/ÿQJJÊÚµkc‹ n68¹¹<þxÉÛC‡X¿¾Ô{÷òâ‹×t©ƒ™4‰„‘1T¡öˆ5£‚Ф§§ž–b—å˜L&£ÑX»#ªf²LZ’„}f³Œ òò(SwÆ ¦M+Õréû÷_S/GŽÐ±#/¼ ª( ‚ ÔŒ BC••x{{Wv@nnnµt¤V«óòò|}}³Ù|øðáøøø‚‚‚£Cƒg IDATüüÌAƒ| £Zz)ãÜ9æÍC«¥¨ˆAƒX¶ “‰•+Y¹’à`t:ëayyÜy'gÏÒ³'Ÿ}PPÀ„ œ:Ef&;âæÆ®]Uu$ËŠHT¡V‰`T‚aÆEGG—ÿÈÛÛ{ذaå+3UA«ÕF­Vëîîn póòòöîÝ;sæLµZ½cÇŽ°°0@’¤„„„“'O*•l0hj"Õéxâ Z´àå—IKcÊÄLJ+xçúöåõ×yçWW¾ù†7ߤxI‚FÚ5¬_Ï7ßðõ×W‰2ÍfÒÒùÓAj™ø{WŸÊÒÝ{xxôèѣ²²²rrròóó [¶léáádffnÞ¼Ùl6˲ܽ{÷Áƒ’$iµZF£ÓéÔjµN§sttºtééááQTô…RY#Õ0óóùóOZ·æ™ge239yOO †G©dÜ8k0*I¸»ãäTr®¥E£A­¦’% V:cÇrø0«W×ÄM‚ •Á¨ 4|&“éìÙ³ééé999 …¢86=pà€,Ëf³ÙÇÇÇŒªÕjGGGgggWWW[5!FÓ¥K—;î¸ÃÃÃcáÂ…–Hhj+|™œ¬ÖéL51x³…‚èhkÝÎÎéÚ•cÇ$”J zæ2ÕjžzŠÿû?bc1¢.(‚ \#Œ ÂÍÍl6_¹r%//ÏÏÏÏËË+77wÿþý!!!C† dYþý÷ß“’’OOÏöíÛ[Îõññ quuuwwwµ•ruu}ú¸»»{xx¸¹¹YÒŽ¶oß¾]»vJ¥R²[M)I’££cñÜgsvæé§Y°€;P*ÑéøðCÂÙ>É“iÑ‚ädë‘[·òÌ3\¾L~>={2i>н;f3;ãïÏÖ­Uõ¥TRPPãw$‚ ØÁ¨ \+“É$I’BQƒÙyM&SZZZ~~~AAZ­ŽŠŠ²„‰ß}÷]||¼Édrttœ9s¦ey¨^¯¿té’%”4™L–¼NîîîÆ sppððð°´(•J½^ïçç7hÐ K/EEE–Ê*¦ ë“Nؾ¤$ôz‚ƒqwG©ä¹ç˜=›ìl""Ðëúõ+•aÔÅÅú"(ˆ­[Ñj¯Þ‘¿?G²omÚàæVw"‚ ”#‚QA¸&iii?ýôS=Z´hQ-ÌËË‹ÏÍÍÍÍÍmÙ²eË–-üüüuëÖåää˜L¦&Mš4oÞÜ2Céèèèàà Ñh\]]‹g1#""æÏŸïêêºfÍš¤¤$Kº%ggçâ§ðJ¥²FèZ I¸¹YªÑÁˆˆR-NNT|WWl˪2h¿ÿΛoòÔSDEÝèpA„ë!‚QA¸ ƒÁpàÀ½{÷jµÚV­Z]Ë)²,9;;[Ç'Nœ;w.777??üøñ–¨1%%åÇ´ä¢wtt´£NNN–¥ŸnnnÅqç°aìP(ì×q:99Ȳܵk×ÔÔÔÊ’ŒªTªFU‘‚T(æîÎòå eé ‚ 5G£‚P•‹/þöÛo ²,v+ M&SAAA~~¾J¥ò·ÕÚ°aCJJJ^^ž§§ç”)SœK—.WãÌÎζ£ÑÑÑÆÝݽQ£F–Oo¿ývI’ʬã´,­B¡h×®]·àãã3uêTIdr¿6 õf¹¬ Â-A£‚P±¢¢¢½{÷2yî9¦OŸJO/*b̶m«žÁ$'3y²µÒýW_U•ßô­_ÏŠ11<ôÐ_'#ƒÇãå—±”ëÚ¶Ÿ~béÒ’• :ùùx{_¥têµøî;Þx`üx-ú·W¡»ñÇôÁÁÁsçνYRÃ4}ªøA*TŸýû÷oÚ´Éh4Nœ8ñøñãñññZ»œ@………–ùiI’,ëAë\jjªV«u)ÎcTNQQÑÉ“'==={÷îÝ€ƒQ''^z‰ìl¼¼RIAAWÙMo2±gOµ ÆÏ/¿$1‘éÓ)÷/š1t(]»òÙgÄÇÿ«ëèõüù§5àîN“&¥âÎC‡xç>üæ_u F·n|ögÏþÛK ‚аÝx0øè£ŠµhBóÎ;ïlܸQ’¤ÈÈÈ-ZäççŸ9sæÄ‰‰‰‰F£±   ^-P1™LYYYJ¥Ò³êÊë·IÂßßZ†Þ^N{÷JPµÅwº¹qø0..Œ‡ý?+ÌföïG©¤Â‰f³™Ý»é܆ôtާ_?€ôtΞE£aß>Ü݉‰¡qã’˜ïªöïçÄ  úô±V==|˜?ÿD£aÈüý­©©<=K2üWáìYk`=`–r­yyüò ©©4n\ïÚ…VKŸ>%·¿ÿξ}Ädzmîîô쉓S×ÏËãøq¢£qtäüyt:kÖ-Ë-$&rþ<ôéscáVvsg„¥T*=<<:wîò/½Db"Ï?OzºõÈß~ã7X²¤$hÞ±ƒ}ûHI᧟ؾÊ~§_¼Èã“•°ilmÿè#&MâÕWÙ³‡¯¾ªôtA„2ÄnzA¸:µZíïïïïïߣGzõ¤ÛÁÁaذaF£±ŠQùùùÝwß} …¢þTø¬M!!¬\ÉÔ©oÿ3›1™xäÈHV®´¶Ë2Ë–ñÙg¬]KÛ¶•^P§³N.ÊrI'Ë\¹Âöí4kFAAÅŠÊÏgéR>ý”áÑet:€wÞaÔ(–/G§£U+víb̘k½à«¯2~aðeXXØO?ýtïÞ½²Xšˆ*?ÿŒ‡Ó§SüwÓ¸Cç4"¬W{¤Ra3=kkòª+ÄÆ>‚Ÿ°²âÝw9p€8uŠ‘#±¶F¯ÃññÉZ<Èwhk[°LV0ŸLDDD¤¢1*Rz½þرcÁÁÁO>TBB—_~¹nÝ: --­Q£F!!!@HHÈéÂ2™£¢¢:TÔh±±±‹-:jtÕTNœ8ñÕW_………Ó&77÷öíÛ·oß® rlJ%NNìÝËÅ‹$%a0pë/’’­[\¸ Ø‘…"•âëËš5üü³)ò¿xyñÝw„†²aC ‹±µ%9™~àÂ…"sêÝÜhßžùó åÒ%Œß÷®]Ùµ‹+Wع“{÷hÛÖÔøÏ?9y’[·Špð`¾ü’ÈHøá¢¢¨_kk6l 4”õëIIHIáâEÂÃIOçòeÂÃ…îj5üú+W®i¶Z[ÏÙ³\¸ÀÁƒ%Ü??._æ—_ )¡¥ˆˆHE4FEJ@«Õ~üñÇÇò¡7nܱcG£Idff¶xñb777àäÉ“_öð¿~ýúûï¿_Ôh­[·ö÷÷¯R¹íOtttXXXñ7!--íÀßÿýõLŸV”J, %…•+ A¯gÿ~V­B¡àôi>ø€ÿE&£m[Á‡çìL›62:øúòé§?N¡ª¾R)óæñûïL˜€¯¯ÉL´·'(¨`cÖ®åÀ–//èF}xÀ±´dâDfÎ$>`ôh^x·ßæóÏùøc!WèÒ…>}øüsöî-Òw;y2]º0w.'rò$r9––¬YÃÅ‹¼ù&2]º RÁêÕ\¼ˆ½=}d²)›7gÌvìàÓO³õ¿xx0a̲eôê…ŸŸpÞß_Tx˜6m1‚Í›ùöÛÂGcFk(ááá[¶lquuÕëõgÏžmÙ²åøñã¥RinnîÎ;ùå ‹¡C‡>óÌ3‡ Öëõ±±±ƒ òññ9tèÐ$I¿~ýºwï^`䈈ˆuëÖEEE5nÜxÔ¨Q¶¶¶z½þûï¿ÿî»ïììì,--ƒÁ°ÿþëׯ7mÚ4**êÀwîÜ™7o^Ó¦MŒ€[·nmß¾ýÞ½{óæÍóôô5jTXXØgŸ}ëêêúÚk¯Tô]«bäää$%%)•ÊâCB ƒV«•H$ÿÕð* dò³Q(ɘ4Éd·I$ÂÉu먠 š703c×.¡MïÞtëFQ¸mÛòý÷èõXX˜LÌÆ (D(~Àúö%7· àÔÃxx°f F5[£(‚…+W’šŠL†……iX†Ù³‡eQQÌšEFz=Ь];š7''½¥6n4¹WóÔ &Oæ­·Ðë)*áM"á­·xõU ”JÓ £GrÌ̘2¥Œcjƒ®ØŸ¬ŠxÅ)  \@¢1ZC±±±ÉÎΞ5kÖüùó»uë6oÞ¼-Z´nÝzýúõ;wî\·n]XXؘ1cvìØQ¯^={{{ŸvíÚ988œ8qböìÙ6lÐétãÆ³±±icô,––öꫯöéÓg̘1‹-Z¸pá‡~xêÔ©·ß~{Ë–-jµzäÈ‘Fõ~??¿¥K—>÷Üs5òóóËÍÍmß¾½[ž$ØÚÚ6jÔèÊ•+íÛ··±±IMMíß¿ÿøñã'L˜0o޼ݻw/X° n\U";;ÛXŒ´ ¦UU.‰)βP›2ÏÌ’ÉLvX^‰•Šuë8sÆÔE&cËás^P^_©´Hã5oŠ™3‰Š2 bÜ8¤R¹œ/2EIÇ–(î,“’¥dnž/©èá[T̳fñpT¶Ÿ#J…TеuÁ^ÅÜ¢ õc P¸Õ CæP„ïZD¤|ÈÊB¥r-‘Ec´†bkkëãããïï?qâÄœœœ­[·îÙ³gôèÑ5 ؽ{÷Ž;-Zäàààïïß¡CN·}ûv__ßôôtƒÁàéé¹wïÞ€€€sçεjÕŠ‰‰¹víÚìÙ³ÃÃÃ[´h±`Á‚•+WîÙ³ç¹çž{þùç C¯^½’’’$Iƒ ŒEƒìííýýý^xá…‡Whgghaaa<äÈ‘¤¤¤#FÈåò¥K—Þ$!ǧ ‹ÁƒkµÚbÊ/jµú™gž1~¨¨¥= øûç³®¤OÓÔ¢II¦ÃºuË äfyÓ¼¹ ÂoÄÅ¥ îƒH)17o Ó™çädaÊWùoÈÓ…^OV–ÂÖ¶aÉMѭј››Ëd2‰D"•Ju:]nnnrr²³³3 “É,--cógùêtºøøx½^éÒ%à™gžñññILLÜ»w/СC¹\®V«ÿþûo@¯×O:5==ýÁƒuëÖ$‰³³sÒÃäRçàà`,?ëáááááñÄW_í)eIRµZݺuë XÏÓ„DBÇŽtìX–cX–£U ÕqÍO R©ÚÌ,03óœèW© èõde©ÔêÆå1¸hŒŠ˜P«ÕîîîW¯^íÑ£Gvvö½{÷:wî,‘HŒ»À ‘‘‘õêÕ‹Ÿ1c†Á`ؼy³R©¬]»öúõë#\¾|Y¯×¿öÚkÎÎÎwïÞ]¶l™µµu@@À™3g½^õêÕB¥×333 éS§Úµkæêêú°™uúôézõê…‡‡§¦¦ZYY8qâÂ… S§N­»""""R H$ +«¢£ÏYYU'ºÈSO|< …¿JåYƒ‹Æh %""âСCûöíBCC:Ô¾}ûwÞygòäÉÙÙÙqqq)))C‡U(‡¾p႟Ÿß¸qã 4cÆ ›ãÇoÚ´éáa4h0pàÀ×^{­W¯^‡8p 0bĈ¯¾újæÌ™*•êêÕ«R©ôÔ©SÑÑÑÑÑÑ;wîlÚ´iýúõ—-[¶jÕªß~ûíÙgŸ}þùç,X0räH77·;wî|òÉ'û÷ï?zôhŸ>}^yå•îÝ»ïܹsÅŠ§Nºxñb\\\Ó¦M›5kV9÷±R9þ|FFF`` íÕÂ`0m}µZ-­1›¬±±äæ JïØÚ…Y(YYܸ RÑ A¹,ò Òž|}Miÿ1Ðj…Lc±‘ Aêì<9!áÛØØñ¶‹T.DGk¼½W—“ Se£¹¹÷³³oggß2ô%·)Srs °0 ÝŸ‰dáÂg¤R©N÷c@€ÝÆýoÞ¼Ù zâÄÉOqq¼òн¿¿½D¢kÕÊR£ùcëÖ!×®]“J¼ôRsó“y¥®ÌšÕøòeÒÒþœ:µ~@qqÛÌÌ ;wŽ677ïÞ½WDD„JuÜÁ!mñâ¶IvZÚ·ÞÞÊ?ìššzmٲ綯YÓ£^½„¸¸mNN†µk_JN¾ðÁ’’vΛtáÂ…ÌÌsK–´­W/4<<üw™ìh\Ü?…^¦\n£P¸š™ùÈdO[ "ƒÁpíÚµÈÈH//¯âÑÌÌÌÝ»wçææ4Èú¿Y'O){öpïK–èt,\Hÿþ¼øâ#ŒÏÒ¥¤§ÇŸ–ÙÂÎÃΟ2ꫯø÷_ΟgçÎB„¥ pú4VVÅ•9-žI“8žqã1â1Gy  §Úµ×„‡÷±°È*ï÷ ‘¢ÈÍåöm©½ýDK˶%·~,*ÁÕë3bc?OHø677B¡H“ËSe²¡8S¥JiÕÊt˜™’‚Ï<#&' Œò7ZíæädÔjSß¼“çFÊ+´hmmêâä`g‡§'@vöÖìlê×7 ذ¡iä< CãaÞ£49;»–èõÙÙrÎJ¥ªïèøšÝ ‰DVxÓêFFFFZZš¹¹¹yI…³³³½¾½õee‘™)|–ɘ2—GÁÍ­[ù÷_† )Ë…}ù%Íš•1:w.:/¼PB½(#ëÖáëû˜Æh|<'NðÅ´hñ8ÝEž+«œœæ„„,vqÉrrÈD*š”"#¥Je7·wË/m®¢ÑŒŒKwîüO§;æâ’«Ñ¢'b4ŒH9¡×Ëuº$­6)--ò޽ߒ’yx,V©jWöºÊ€ŒŒŒììlµZ]h îà ƒÁ ©?³Ü\6mâàAÌÍ1„·ˆ,@&ã­·„!àöm–,áöm”J&O¦S'îÝcùr$‚ƒñòâ½÷psÃܼ þ‘ÁÀÞ½ìÜIj*nnÌš…Ÿß~ËÝ»L™"L·lŸ|Rˆ˜Ñ¹slØÀ¹süý7gÏÒªcÇ"•râëד˜È³Ï2m ãÆ‘Mf&®®„†²d ²p!R)ü™ãÆÑ±£ PUÀ:‰ŒdÅ BCQ«2„~ý¸qƒ5køóOþù‡ðp˜<…‚'øòKbbhÕŠéÓ ‘jÊC«ÅÒw÷"•GEʉDîê:Ãܼé;襤üã舙™ ®%"R~de‘“CR‰‰NÎγœFI¥å7]…£‰‰û"#ÇÙÛǸ¸ø€Y³˜9“¯¿.|–°0Þx//vîdìXNœÀñc=KK¶nåÎÂ7==<˜˜êÕ£G\\HøçFŒ`Ñ"š4aÆ ¾úŠ7ßdÇÖ®eéRœ©U‹Ý»iØ~@£aåJNžæ­U«YhÖŒñ㉊bÜ8ê×ÇÕ•‰ˆÀÕ•Áƒqp@&ãÆ Þz‹iÓhÙ’… Y¿ž3Šô ää”Êù*RNH$ ›MóèèU11ç´Ú0­ö®™YfÉ=EDƒ­ƒÁZ¡ðS©øøL17,o)±Š3 sr"##§zxÄØÙ‰®P‘J@¥¢n]¢¢Boßžèë{°ºG‘Êåò‡kƒ……EŸ>} ƒü©~4øþ{ºt¡{w “&‘•;›ôê-³²¸wà`üüL;æÖÖüï¨TÌœIÏžètü×z—H6ŒøóOâãUü  œùî;†eÛ6ÁÃú_\]queï^4 kWáäþý¸¸à⃴lÉáÃŒ Эß|C«Vþ˜å˹}›Ù³yóMGGÁKjgGN‰‰88웕EïÞøúòÌ3H$äæH¥¼þ:_~‰›99ü§DnqÜ»GzºP‰T¯§ñÿKøåUfâ℺£Æ·¹kk!·ý¿¬^Íwß1dJ%J¥©`iîÞ%9™½{…y›6¥¨Ê“QQDE!‘bš‹T<2™…Lf¡P”êETD¤ºPA¨ääcûýý ¢%*R¹ÈdÔ®m Ymg7X­®_r‡*Innnpp°•••››[M04KƒL†—W®hµ\¹‚½}‘==ùðCRRøòK¾þZ0FïÞ%.""°´º+•¤¥™¼¤FêÉ“˜™qø°iÀaÃX¼˜¥K2„ <\¨ÝߟðpÖ­vösr ÙâÏ3oÜ }{22ˆ‰T«µšÄDSãcǘ<™¡CIIá“OLç•JN`óñ¡^=Ö¬V[¨ØHŸ>2h‰‰k–Šˆˆˆ” ôKJúÑÆ&K,#!R°°@­NËȸP}Ѥ¤¤#GŽXXX¼úê«%•§§§ÿñÇ …âÙgŸUS>¼ú3|8]»2o ?þÈðáèõìÛÇܸÁÞ½Ó§>>Ì™ƒÁ@` ?þÈ³Ï Ýssyýuzô`ýzÆŒöpÜݱ¶fìXêÕcÖ,Üݱ³céRذÁ4µ‹ =zðí·¬YSÂ"6dýz’“  OdÓ&&O¦eK.\ÀÝwß-²ïªUääpî66´o/œìÚ•ùó¹p~ýhØ–-Ù²…ÌLâÁSß  Á6õócà@úõcûv¦L¡U+®\Á×—ñ㋜×¹¼HשˆˆˆÈRAÆhFÆUQ³W¤ê ÑšzÎÞþ•jZß9111##ÃÉÉ©4å@³³³¯]»fnnÞºuë§Ûõña÷nF¥bÓ&a“]£ÁÖ–±c!›M*¥gONžäÆ Þxƒž=…î^^ Î¥KLŸNß¾ÂI•ŠÃ‡ùãa[ÜÌŒC‡øî;RRX¿ž«WM³7i½{&‘²¢5Šºu‰ˆÀ(ÉåêÊ¡CìßÏ­[4nL·n+W¢VóÖ[øù‘žŽà¶œ6ØXY¸íH$´lIË–ùNÁÙ¶-mÿ#Þ,—3`<_«/¿l:¬_ßdq¶k˜È_±e sæ”üÉÜÜdþqwg„|gÆŒèÑC8lôÿÚM›æ“ΰS':u-,xýõBæU«éÜ™Îó]—ÑF/[[ºveÂ^]i)C*ÂÕj”J”Jë"¼P9‘wpà—.±|y‘£%&2e áá´iÂ5Q÷.'‡ë×˲ ÁÀ7ß°f ööÌ›WðY^Vde1|811,XÀóÏ—Ë…a€BJ@ªÕ:½>´P-¿@ÞÞÞ‰¤víÒ ¦ÄÖ’°¶¼’At4;v0l˜É]¾œ#GòµùùçÂõžJOçÎØÙ=ÑTÊ’%ÄÅQRHˆˆˆˆÈãP1Ûô½>RJÓ4-­È,Q#gÎÁÆ8:"+]HLdÆ >úˆ€€²0-™4‰NÊQ½åß9s†S§*¸¶uᥙd2´Ú´êk¢¹¹¹•R× ppp3fŒT*-Q¿&ãéÉʕٷAƒ|ÒQÀèÑë6=yš™±´ieaffªÓ&"""R¶TBîÉ“|ÿ=))x{3|¸ ÅòóÏ8 „sEZ[¶ðûï$%±w/uê0`r9þÉÎdfÒ±#}úî‡#GË9ž°0Z·&(ˆ£G‰ˆ NîßÇÑ‘ñãa³ø«¯P«ùýw”JÞx__23Ù·Ó§ÑëiÕŠ—_F&c÷nnÝB¯ÇÑ‘ˆ&NÄË‹ädvîäòe\\xýõÂuª³g çÖ-¢¢èÙSØÈKJbÓ&‚ƒ©U‹Ñ£quå×_9~œðp¾üGG:t (­–'8tˆÜ\ú÷4¿ã¡Cüõ‘‘œ=˽{ôí‹·7IIlÞ̸¹1z´ðŠŠb÷n||øñG,-™8‘_åÞ=bciÔˆ¿þbÂS!Ðÿ‰ ¥ö剔r¹Ü¾˜Är‘rÀÞ¾¸\~‘ÇÅ“•“‘™yC««ìň< Èdæff~ff>Je-‰¤"2 *Á=too<<Ø¿ŸY³øâ .]bìXÆÃÜœ÷ß/r³L"ÁÌLÏ376èÃÂ9’—_¦Iþ÷?$a§lß>ާ[7|}…¢Ÿ~Ê«¯²d Ó¦±q#={âï_Ú5¯[‡¹9cDz?óçóõ×$&ráAA˜›óÉ'df2t(Ÿ|B÷îìÝK` 72w.Ó§óàÆqü83g²iSáÊ/dzf 3fàåÅÌ™øúâåżyüý7cưk&°c ffH¥¨T˜› î–~àÿcâDôzfÌ`óæGpš*•¦Õj£ËE‹8uŠiÓØµ‹7ÞÞ"#™>矧G‰Žæ³ÏhÛ–?þàß©S‡>âóÏ‹œH¯ÒmJ#III™™™¶¶¶f•{+""RA22.ß¹ó¿ìì¿åò$¹<ÍÌL)‘dWöªDžB 23‰Wétv‰››Û»vv}Ë[ú¾ŒÑwÞ᯿HMÅ×—-[HOgß>Z´àí·Q(¸r%ŸÞÃh4ŒR‰D¤IÂÉ?þÀ‚I“°±áÒ%öï§_?Á½Ú¦ «V ²Ïß}‡‡Ý»³gƒqð ·oiŒFGàí-d¼ãÇÓ¯NNÌ™Cz:..LšÄÕ«dgãëË•+ Š…J‡Èdüþ;¡¡üöK–àë‹¥%³g7oÛ¶LšDJ GއF￲|9=zàçGÿþ„…Ñ®>>>Ì!dg³y3Ï?ϳϢ×sü8ÇŽiŒæä `k+ø;;u¢E dà@!Z4)‰cǘ?Ÿ¾}iÚ”gžáæMa.ss>üPøœšŠBAß¾dgS§µkóÕW…Oª×sæ »v ÅEžsçÎ]¾|ù…^hÑ¢EiÚgeeEDD˜™™Õs¡‹F«Í dnŽ¥¥éÐWݶ­PbÔ``åJf̨èEŠÔLôú̘˜511+íìâj×F.G&“H$f £"å…V›­ÓE§¦Fß½ûZrò!w÷…J¥{ÉÝ—Š6FÓÒ9’œ5âÁrs1ˆŒÄÍMp›ùûóÏ?0`d$vv‚¯ÑÕ•k×ÈÊ,ÈfÍ„ R¹‰[[“eéìLFF#ž=BA”/¾0¥Í#ô,-Q©Ð뇥îîDE™¨ssd2AŠ%)‰ØX¶nE¥Â`Àݽ¸d[WW¡–ºÑß™‘V‹‹ €•Ri>ië<ÒÒ¸s‡ØXæÏHO/Òšââxë-€nݘ3§ð6¹¹¤¤Wdoi^336>/P*E&+!xW§cÏ~ÿÙ³‹k&Rôzýýû÷³²²ló¤}J"))é»ï¾suuÑb¸u‹îÝqtûôɧ÷©×³v-..&ctË–‚ÆhïÞ|÷¨ï!RÆ ¹ã22¶yyi­¬Ä/˜H!—#—£Raa‘~çÎæàà?ýü+•å9^ÑÆèܺÅÑ£¸¹qä§NxzŽV‹\Nxø£ èîNBYY¨TÄÄàà`Š-~*“•ögÚôt Sv‘NGžV¹9ÎÎté"ÈÁ@q»áÎÎBÀb6xe2Ôjbb’’HNÆæÿóÑ%’ÇùS¨P°z5Mš°e‹¨ 󤤥¥%%%™››—ÞÕëõÕ7U«ÂÈÉáþ}~ýU8Ìs‹&$ÅÃ7;=ÝTÀÓHJ YYú//öïgáÂâR J‰¥e¾ºBqr"$„C‡ˆŽfçNºt)¼™Íš±|9¯¿Nr2—/3kVi3Ö bÅ rrز…Fýj++ìíùøc^z‰† ñóãµ×xÿ}œœppàÌúô¡I“ÂÇ”ÉJNf·¶¦kW>ü•Š;ðõ-YÇ»DŒžé81àþ‰‘Éd™™™šR+{eggç<\€R¤$’‚¢î.0jnn¤¦rë–prï^vì $ÄtæóÏ9v ƒ#¦N-ò‚ˆÈ#‘•zïÞ¬ÚµEKT¤2‘ɨUËpóæÞøø^ööƒËcŠŠ6F=<øì3vïF§ãí·¹s33ZµbÍöïÇÌŒùó)ÞãoSØßŸM›Ø±ƒÐPæÎeà@á|çÎBž¾__^z FŽÄÆF( Xz^yEÍÙ™AƒP©èÚ•¨(öíÃÚšE‹ÐhP©<''ºu£vm¤RÌÍ13cõj¶mc×.ÌÌxî¹"]&AA¤¥(• €›J%‹³aÛ·ãëËonnÎpàgÏbg'„“ZXpð ™™4jôÈ ,*C†ñ€LÆìÙ¬[ÇÖ­8;³i“àjuueÜ8S/¹œ!Cps£cGìí±´4­){{23‹+-R4MÇŽu:]iäîØÙÙuéÒ¥4µšj8YY&yù·ßæµ×˜7Ö­Y¶Œ“HE¿~tê”OcÌ^}776oF")G}4‘…Á ‹ŽþÀÊêM!ZÉ""ŠJ…§gvdä;»þå‘__ L É£woz÷.U÷æÍóåÁH$<÷Ï=W°YžUj$0PH»™6 `øðGY1¦ú(¦š%cǬ_b܃Λژ^âì,LZ<; ÌÌLî..Ì›WHcÿ|YP /¾XBA¿bP« –¥vtdîÜ‚Íj×η¥Rè•çLjܸ¸Yê×G©¤[7æÍ+¤øÈ#QzK°¶¶nÓ¦Mù-æ©A¡`Ñ"ásƒèt\½*$G6kfŠ–¶°0EŸ±¶ Pgç2Ø™1b0äfdœ«UKŒ©XY÷³²n©Õ¥–"*5•`Œ–†U«„pR#vv¬Z…øvX­±µåèQâã…‘Ç@¯×§¤¤XXXÈŸ\B]ä?Èdù^‰srÐëMŽüÒØÿz½hŒŠ”:]jVÖ?Þ|DD* ‰•*+3ór 2FÌWCY.ËÐU{$ÜÝóɈ<*ÉÉÉ»ví²´´ìÛ·¯y©ŸQ:.++K.—‹˜ŠÇ` 6Vø¬RaaA£Füü3/¼@ddÉ* W¯Ò¬Yy/S¤¦‘qE©Ì-úÅ3_Vâ½{h4ÕÕeŽ“S¾×¤§Ô©S°ðuTju á|Õ½ž;wptÌ·Ù’•Ž{x{—Ð1"™¬BëÈH¥¨ÕºŒŒ¿Ë£.q}‹÷ô¤Q#Ó ”A1=‘êNbbb\\\NNŽòQÒ¢¢¢6nÜxêὑÿ —ce%Ä õîÍœ9ÈdÌŸÏ¡CtîÌ«¯boB^OçÎt튃;çKT?žñãéÜ™Ÿ®¼ËyŠÐé’‹þ¡ Ít``É“DµcêT._ÎwfËÞ{~ý8¾`ã•+Ù¿¿|×sòd‘ 9eKF3fpýz¾“aaŒU\/½žÕ«:´HmïòC¥B§+Ui÷GE4ñDDª ÷ïß×jµ®®®´M¯ÕjÓ~‘"ðöæôiÓ¡1Ý«U+&>KK”Jìí‘JY¿¾ð.$* '§ŠX°ÈS¤„XQ“ ´Á è‹US’’( ø1s&Z-½{< VîàY³øàžy¦|g ’’ÐjóÔjK0…³²8~œ)Sxé¥r]]Q”KsU7F32øçrsiÑ¢B‹Iž?«k!{Êii\ºDóæ3ŒDFrçÏ>û83FE‚»;õê=Nw‘š€B¡ðððð|Ĩ[NWNëyšP* ßóð((OQÔö™RYPJD¤¬ÈÍeñb®_G­¦V-fÎÄÚš¤$ÞŸS§ðô$*ªÈ¾11Ìžwî`aÁ¢E‚8ÌgŸ‘“Ch(÷ïÓ¨ï½ÇÝ»,X@r2 3gÒ @|ÂÛ`—îðpæÏ'-Ñ£©[W8©ÕòÃìÙƒ^—³f®Ìxð ?ý$¬éÞ©SQ©ˆŠâà G£aâDZ´`ëV¾ÿžà`fÏÆÞžAƒxùe²³Ù»—ÇÑjyî9FŽª‘§¤pê­Záà`š(8˜ˆž}Vˆ-Œ‰aÅ îÝC¡ (ˆQ£P« eÙ2nÞ¤ARRôzŽaíZ22hÚ´„k0 ‘àäôTéWÑmú<>ü 8tȤñ^J.^ä“O y©*%ŸÎ_r>:šwßåÁƒÂ{;VdY£‰Šâ³Ï6Ì$^("R€–-[6Ì××÷‘z †ZµjÙ•G˜ˆˆH… ×“›Ë¬Y̘ÁåË|ñkÖðë¯|ú)/¾È™3EöMOgˤRþ÷?²³;cŒ‹Y²OO†ÇÉ ƒÉ“IKã½÷P*yûmá±;cgÎðöÛLœøhÂ| ìØ^ϬYhµ¼ó™™DDpé’Ðà·ßLâÓ—/³h¯¼ÂÔ©BÍêÿââÂôéèõ„…™N=Ê»ïÒ«3gR·.E½zߺÅ7ßо=³g³e ÁÁètÌ›Gp0ヒS¦O§NÌ™ƒ‡#F0gŽ Ôsð +VðÊ+ŒËW_qò¤0fD¯¾ÊÕ«ù&Ú¹“Q£ˆŽÓÒpueÖ,Þ|“íÛ9z”ÌLæÌ!-O>ÁÞ^¸Ø°0¦O§[7–.åÊ•nlv6))O[ìbU¿šÓ§yí5á-*„Š|o?ÉÉhµØÚšRYCCÙ·Q£ò‰’êt$%an^òûÄÂ…S¦ÒÓÉÊ*èN/%Z-Éɘ™ Ä~˜-ذ_$"¢„Èe‘šÌc$!y{{{zz>’”ˆˆH•B©¤~ú‰û÷ÉÌäÔ)&OæàAÞ|“¦MiÔˆU«ŠënT¶¶fútZ¶$#CxõèÁŒ‚tTv6?ÿÌ/¿Ð¸1o¿MË–$'£Rñí·üúk>EÅ¢øë/´Z”Jš4ÌV++fÌÀ÷ߦsg’“‹ìûê«´nM«V¬]ˉ‚S¶j5+#îÙCçÎ ˆTZ‚¼`«V €L†…·náæÆï¿³jÍ›£Ñðý÷ܹC“&¸»£ÑàëkòPnÛF` ÆZ¬^^;&$X»º2~ÁÍÌ.]pv6ùJkÕ¢I¾ûŽ„ÒÓù÷_5âÚ56l Y3ìì8xP¸u‰à7}ýu–-+ò*NŸfï^rsñò*îb«UÝ3š™™ÏšìÕ‹±cyå:wæÈ­–•+éуþýyýuââHLdØ0–.åêUz÷fð`¡²å™3ôêÅ+¯Ð«—éÍæ¿Ü¼I¿~ôëǘN~ÿ=Ý»3x0S§æ+j¿m+V™™oƒ“'éÓ‡'.\ _?† ¡woŽz-xm¯^¥_?îÝÉÐé Ž&"bD«Õêõú’Ûý©TªR©D5(‘êËùó Lz:­Záë+ˆNH0+)¾j`ž®:ññÂyOO“ˆi|œ÷ß')©ðIëÔaåJlmILÎܿϼyôëǦM4ož¯ãÑ£ìÜ)5Í[óþýLžÌ!´kGBӦѺ5›61z4K–ðàqú´ ³g üA13ÃÂ"Ÿ±+"’ÇÙ³g·lÙRÙ ©h.^¤iS–,aèPáŒTŠ»;7nhµ¦}áB‰‹#2 <µÚdÂ>Œ³3 w¢Ráá‹ &×Lññr›7³gë×›r*bcWË­[˜™acƒTJF:iiÂ’Œ„„`0•EX˜É¼³°ÈצP¼¼¸rEpîèt”þ…ÝÖkkBCÁcõ°Aÿð•z{óì³|ý5Û¶±s§©a\ë× w,sçØ´Éd'œ9ÃàÁÌ™CïÞ俢×caR)ôJI!5U˜"&F°Â ìû gOÖ¬A&þ×?5T]gÉÙ³¬YCJJÁ2ë/¿Œ§'Ï<Ãùóhµ\¾L­Z´nFC—.üñ‡ÅìêŠZ··ðZöÏ?Ü»Gj*ûö‘’Bh(ž‘gf†·w¾/eXÙÙôî§'ýúqèéŸÆ'%%ßæûß3no½%l„‡B۶¼11Ü»Gƒ°?9¬YÂŽ†RÉ‹/²`7o2mZq{ú"5Û·oGFF>F6RXXØ… ¼½½›=í˜ J½z¼÷^¾—X‘êNƬXÁ'ŸÅ?r‡£F1w.J%ׯ æTQ(¼õ={²mo¼Qx6°L& ž= ŒFƒLÆôéÌžMd$©©¨TL™Rä,ÿ•7Æ¡öéÃ×_Ó·/¶¶øû³t)+V‘ϳóÕWÈdܾ™™©FcÇŽlÜȃôìI` ÇŽqý:ÁÁ¤§£ÕÒ¡1r$#G2c\»Æœ9ùÒ‰ŠÁÊŠAƒXµŠ˜~ü‘FLàÀ@æÎ¥K:u"(ˆ1c˜8‘÷ÞÃͳg™Íôé•%&RuÉÊÊÒh4666¥/¼TéSóG«härZ·¦aC1ðZäiC*¥GzôÈwR¥¢OŸ|gòíS+Bl¢LÆ€ ¯q÷îg±´ä•W žT* ™ºôË~é%^{ÍtF.§o߂͌±ÿB­¦kWºv5-ø¿k–Hð÷/ÎH0Ò¢-ZŸGŒ0_àžqtÌ·H©”À@ 6srâí· ž|æ™|¥j5C†lccSÈ}®]›‰‹¿33:t`Íþþ›Å‹KÕ¥êSuQ#2Åkuw耧'¯¿Ž³3W®°u«ðÒа!99 ˆ—‹S¯¯¼Âĉ´jEL ŽŽ¬ZU¸VèGqæ gÎɾ}LšDP={2iÍšqñb>m‹ŸæÚ5FΗž¯Ñ°`/¿ÌÊ•Ì˨Q̘AP‰‰H$lØ€µ5ÎÎtíÊúõùþ”èthµ¢OT¤lmm‡ ¢ÓéÌ=j]*•>F¯jMJ¹”©ÒèõL›–o¿>0åË17§C‡JX Ï?_¡á5©”I“<˜ª"T+ªºáãêJd$xz"•òÝw‚}«V¬Z…™æælÛÆùódf²p¡)æÃLJ={ˆªüI¥LŸÎ‹/‚FCÆEª;õê•OµÞÛ¹œE‹¸p¸8¦LA*|¥Àüùdd˜L_zIx%òòâÛoIKC&cÂ:u"4¥’€¡±D‚…-[š"bSS¹vœìíËòŠ<H¥ÒÇö‰úùù¹»»×{ÔߟᆪwoêÖ}ÚNEDŠA*eéÒ|B›Æ}B6n¬„õøû³aC%Ì[P* ã¨îTucôµ×øä’“Y¼ !ΰ²(ºu+¤¯§g>Í…"Ÿ§=3“»wóíh¸¹ai‰·w!2Ÿ íÛ2EÁ S¤HíÚ¦ó Ò°¡é0!íÛÙ¾yóLÂUW®°|9AA%o7ˆˆ<jµZý4Uê(‰¶mY´ˆwÞaõjSt—ˆHM ÏQ""R½¨êÆh×®´m‹ÁPö©å,\˜/¶lÆŒŠ¨E èõhµ,Y’/ü%(ˆíÛ…ìE‘‡III9~ü¸³³sóæÍâ¦WI:Äóϳv­IêODDDD¤*SÕQ(/…#__6lª¢yÜ]ÐGÆÁ¡u …BŒ­)œÄÄÄ¿ÿþ;>>þñ´™âããmmmíkFHT­[—VÞEDDDD¤Òyúl‹B&ÃÊJ¨KaüO´Eª&ÑÑѹ¹¹ÎÎÎʇˑ•šË—/oÛ¶íÚµke¾°*ˆÁ€VË£×L©4ªgTD¤†“––&—Ë]Ÿ,̲ørOiiÌ™Ã/¿¢ÿ""RC¸s++"#‘J©__СLK#* ÀÑQ_ þÉÜœÄD¼½…±¸8P«ñðxª’µEª8UÝ eÛ6d2¦N­®‰¾þš›70€¦M+{)"Õ“6mÚøûû?¡j½¬#Ëå´jEïÞ´iSÙK© ôz&N$'¹œ[·˜<™7ÞèÑkkÔjbcY³†À@†G£áöm¼½‰eút âèQæÏÇÅ…˜ÆŒaøpÑ© ªú6ýòå\¿N³fº‡þÇLŸþ˜}/]büø|g|}IKãwò•°)=ÆÃÃã±¥¼½½;tèð„ŽÕj™C‡Ò¡ƒ¨è$Rsyð€&Møæ¦M3):-[Æ–-¬^M`  ·Â8;Óº5C‡rä¼ù&£G³u+Ë–ñÞ{ddTâuˆÔ,ªºg4"‚ÁƒéÙS8´½¥ IDAT¼v þý•Š-03C¯çÖ-nߨ[//´ZBBÕkµšÄDZ¶D£A§ãŸˆ‰ÁÚšÆMšJ©© XZ"‘ Õró&ýÅÙ³\¸€\ŽŸffèt…•Mš Tr÷.ééøú"‘C\ÞÞ„…™ú*øù¡R„ZÍ[o‘ž.†²‰TuêÔ©S§Ne¯BDD¤"HèØ†Ö­Yº ;›ßgÎT*îß§aC!s×Ö//\]17';›k׈ŒäÒ%nÜHJâî]QM¤‚¨êƨV›Ï'úê«ØÛãíÍ™3ŒÉÔ©$$0{6R)ffܸÁêÕøú2duëò×_Ô¯O\“'3|8kÖ°s' ÌÀLš$D̼÷ðùçh4ddðÅ\¼HXË—ciÉÂ…¸¹ñÙgì܉Ÿ¡¡tïάYDF2m«VÀ›oÒ¬“&±y3çÏsçË—coϼy¸¸H¥¢`“Ècœ””äããSŠË‹ˆˆ<9ÆG[žÃåøq¾ü’¯¾Âɉ;ù矂-èõXXЬ™PpíZœ+lÉ"5ªkŒfgEll>aùÔTÆŒaÜ8¾ù†o¾aüx¬¬øè#rsÉÉaõjvíbδZ–/gÂúö%!7¸u‹ X»–çŸçüy¦McÈá—–MV–ð¦heÅÇóã¬]Ëîݤ·n±q#|@çÎ\¼Èĉ FPC†ðî»øú¢Õ2nÖÖ¬\ɉÌŸoêkD¡ ,µlYqR"Oƒáüùó!!!–––mŒ¦¥¥åääh4Uµõ̧¦ƒ³35 KD¤Œ‰‰¡vmš5#3“_~)Rßßkkúô!7—à`Se‘ò¦ê£'O2k* ä;ÿ H¥8;#•¢×“šÊ»ï…FCD„ÐX£ÁÌ • wwRR¸{—Û·yð€÷ßçÃÉÍ%:šädÁ]¸®812’»wùà>ý”Ü\RSIOG&ã78r„øá‡jxº»S«cÇ2k#F<ñ­©1¤¤¤ÄÆÆš››;?âôéÓׯ_ïÚµk@@@®­"ùóO–-Â;ÅX‘â°²\›266;óÙg¼ú*IIdg ©À66Èdh4¨T(•XX`mÍdzl;v–†FÃŽ<–šœˆÈ#SuÑ6mظ‘¹qƒ¶mMç <Šöí#6–/¾ÀÖ–¥K¹s'ß¿÷ rrP*qvföl“v^¥Pµ½¾`Π^^oÚìpqaæLÁx•Ëgmp0ÑÑXYqò$Í›·ÿ>wï²zµ˜ä+òh$''gffº¹¹Y="333%%E«Õ–áÂ*˜vípw§o_nÞ¤qãÊ^ˆHUE*åÓOqrpwç›oÜÜøábc‘Ëqp + ‰„íÛñð`æLÌÍ‘J B*¥‚‚HNÆ`ÀÕU´DE*ŽªkŒZXд)µjqëV>cô¿((•DFräE¹~üüÐh& €”îÝ3ÅÊcF7l0IG™›Åùó8:â/66ܼI` ))ܾM:ÄÇ3s&}ûÒ®'Ò¸1;(•ÄÅñçŸ89áî.¼feaaAPXŸPäÑpqq2dˆN§{ò* ÕZgT©ÄÕ{{rr*{)""U›ºu…J%>>Âg''ÁBÍÃøOîµðÁÃr_¤ˆHª®1jD*åa‡N@€àµ´¤n]¤RzõâØ1^ (!^©¤n]¬­qvÆË ggV¯fÙ2$;›fÍhÕJS.65òhÑ‚ŽY°[[–-ÃÃåËY¾œÃ‡ÉΦIÚ´á‡prbâD¬­™0;iÙ6¤S'æÏÇÕ•%K„&Nlyd”J¥×ÃAÓ…£££‡‡‡Z­.“%U"¹¹•½‘²¦ª£ÞÞ<ˆ /¾ˆJÅöíXX4oNƨT¸¹±e qq¨ÕX[£ÕbnÎÚµh4,Y‚JE«V‚9Û¶-»v\Ž‹‹É3:>z}¾˜QKKV­"5¦k׎¦MIH@¡ÀÉ ™Œ~ý8Pè5f C‡ ŽU++V¯&-ÍÔ÷÷ßÙ¶ ‹ê*Ú/RÝyöÙg[µjUÝEïÍÌðõeÅ FæÅ+{5"""""eGU7Fß{o¾!&Æ”ínäaw¦Fc²óòü¦ü¿-ÈCa¦·Ì£PQ*5m[±°0 ˜7…c™û‡û>|˜@­ZLœ(&^ˆ< ÞÞÞÖ¾‹Î“ïòW:R©SÙK)Sªº1Z«3fTö"žŒÞ½éÝ»²!R ¹téÒ•+WzõêÕ¼yóÊ^Kå“‘Áõë¼ÿ>íÚUöRDDDDDÊ”ª^TD¤f’™™yïÞ=¥Réž—bð¸œ:uêÀñññe²°ÊE¬ó)R3ÉÊ¢wo&M"2²Tí¿ù†ùä“r^–ˆH!£""U‘„„„´´4{{û'ߣ ¹téRš1¹z’“CTññb¬‹H E©dî\BCÙ¹³äÆz=3fУ}û–ÿÊDDÊ‚ª»MŸMF––SÝŸŽŒ 4!‡)7—ìì|ñ Oƺ …Xù©šaooß»woNW&Yð‰DRÕNždùr6+e‹ÔP¤R!m7,¬äÆQQ "î$ˆTª®gôäI bÜ8ÊÜ¡Á¤I$$‡§O3gN¾))„‡—ñ¤eˆVKh(YY¥j¹jðÅå¿,‘2ÅÌ̬~ýú 6|ò¡”J¥µµµYu~.ñùçlÞ,zFEj4¤B_ñ"5ŽªkŒ¶nÍŠüðƒÉj,+²² 1 Ö­KÏžùœ=Ë»ï–ñ¤eHB'–êý8%…ýûyã †-ÿe‰TUºwï>tèÐÇ.m_°´ÄËë©Ý¾)%\¼ÈõëÅ9#bbøöÛ*T‹ˆT5ªî6½¥%M›¢P¢NDv6‡ñë¯Èd LP ÿþËöíÜ¿³³IHÝ:¢£ñ÷32ظ‘3g¸p¹s17gÔ( Ÿ%,Œ_~ÁÁŸ~ÂÁ)S°´äçŸ9z½žAƒhÛ‰„ØX6o&$„ P«éÝ…‚ï¿gèPÔj~ÿŒ ºv%'‡_~á§ŸÈÍåå—i׉„ÄD¾úŠk×P(8Ž9r„£G¹y“O?ÅÁ.]Š+Oe¬hZ¯^‘— R5¹ÿ~|||­Zµž¤ hÕÚ É£IÂÙ8‘O>¡Ð]ƒ¯¾bÝ:¡" ˆHu¡êzFH¥ãݾE‹hÓÆ'<œ´4ÆŒ!"‚nÝ8{–ÄD¡¥‹ ìÚešÎÕGGÔj<=ñð }ư0Þy‡/¿¤At:Ù³‡ÿý¦M©_ŸéÓ¹y­–… 9tˆž=ùçæÍ#:šز…Œ €“'ùùg€ýû™=›¦MiØwÞ៾ü’_eà@Ú¶%.ÀÖÌÌpuÅÓ“âmެ,“¼¿HuáÒ¥K{öìùÇø%àäIZ´`×.“¥ ãÆ±oTìÊDDžŒªë5Ò¼9ŸΨQ4iRd&Sz:èõ89áìŒNÇgŸÑ½; ìÛÇÉ“øùË–-xyamÍôéBß¾}‘ÉØ´I843ê*ݺÅèÑ%/ÏÆ†Õ«ññÁ` '‡±céÒ…æÍÑëùþ{~û Nœà£èÔ‰Æ9w®ðq²³Ù¼™víhÖ ƒŸæ×_ àþ}”JllhÜgg€  j×fï^úô!0°¸µsð z=O, $R¡hµÚÛ·oK$77·'M§Ó…††æææÖ«W¯Z‡V Z-Çsÿ>]º¿8‘ªCx8µk—°Ó¥ÑHffE­ID¤,¨êÆhƒlߎ¥%õëiŒ^¿Îĉde1z4'’œLB¿ýÆßH¥h4$&"—cÌKvv.³ÔrwwjÕHÈÈ .Ž3gø÷_­©”´4rs1n“Z[SÔ~iz:”ÄíÛ‚;säH-â­·Þz‹1camÇŽñÍ7xx”à=©jÄÇǧ¤¤ØÚÚÚÚÚ>ùh999¿üòKjjêˆ#Dc´DÎcÔ(† +.úED¤²ÈÉ)m“TJl,NNå¼ ‘2¢ª£»w³f Ý»SŒ.MÆìØÁ€ñÙmmµ5ãÇ3d „œž;'ìY”üÖ˜•UªŸ½ZmÊX47ÇÆ†‘#1@¯¸{…‚¤$€ädSx€NGn® Àaf†Fƒƒ æf^˜¬¯/Û¶Ëþý¬[ÇÈ‘ÈåH$¦k)†ñãéܙ޽ ¥Aƒ‹T¬­­»uë–­)´Rm$.‰„äd²²ðòÞ*³³‰Œ$'kk<<0xð€ìlRSqrâÁ<<„²½))DG#‘àåU\à pó&-Z°dIE\”ˆHéÉÉañbŽaöì’K$4nÌÔ© @Ÿ>å¿8‘'¦ª£™™Ô¯_œ% ˜›ãím:”É3†?F&ÃÚš~`Ú4°³cÉú÷gÍA.êÎNœàâEîÜáë¯ñð CWW¢¢øøcjצkׂEê‹B¥bØ0Ö¬A¥ÂÚšcÇxå7¦];–,!3“~àþ}[[²³Ù¶ WW~þ™—^B¥bøp>þKKll8}šÁƒ àÿØ»ïøïþñ㯳³ÇÉI„$Æm×UóFkÖwµ”¢µŠ~[”jq¥ªTÝf'¥jµÔ¦¡µ7‘Ùë¬ß¹~ŽÄIbdû<}ô‘s庮ÏçœDÎû|ÆûýÙghµ €½=|õ/¿LýúÔ¬™o—´Z´Z²²ž¨ÿBaeeU§N¢½gyÏ3:>ÇcgGb"uë²d F#̱cØÙ‘œÌ˜1ôèÁôé\¿Nb"NN4hÀâÅ„‡3nF#éé4hÀüùÒ¿#‹ôz1˜$”E2UªðÅOTW.çûï9s'§âï™ …2Œ¦¦J“ÝO+g üÞ½ètÔ­‹‹ öö¬\ɺuüð/¿L§NØÙÉ… ¨Õ´oÏ…  Òåµkóßÿrìéé´i“o+U«òú빎 ŒVËMH¾¾(•̘ÁÊ•üø#þþRÐìéÉìÙlÞLL Ó¦IKÓúöÅёݻÉÈ V-¼¼BBؽ›ÐPüüX²D ÊmlX°€Ÿ~âÂ|| y)L&±xè…¦V«[´h‘’’bŸ3HX>ÅÇccÃÆÜ¹C×®LŠ·7ýû3jvvüö³góÚkÄÆÒ½;™™8ÀÌ™¼ó:³fáíÍÂ…ÄÇÓ«'Nд©åVL&nÝ*ú*‚ðüTª§[¦H``±õFŠZÙý»»oóæÀ3¼‡ZYÑ·/}ûæ:ÂgŸå:R³&óæY¸\¥âßÿΛ|ôqÕªQ­Z®# ={Ò³g®ƒžž|ô@b"‡ÈdtéB—.y¯íÞîÝs|ün9ùàƒBºØÙÄ´iôí˘1…Ÿ/”ºøøø„„///»"Jª©P(Š|œµT4h€“z= ÷îáíÍ… l܈\NVqqÒi93øvvEf&¡¡T«Æ¤I$&rñ¢å`4+‹>}8q‚U«JîI ‚ ”å`´NæÎ¥R%ŠbdzKI᣸sÇ|¤N¼›žRIÍš”ä:@++.äæÍR~ …'wþüùC‡µnݺuë֥ݗ2íÎ&NdéRj׿êU ¹/pÊå¼ü²”z¢wï| ŠªTL™Âܹœ?O×®ÅÖoAá1e7uuÅÕµ´;ÖÖŒ‘k·Ð3oN·³cÉ’"éÔSpr¢^½’nTx6F£ñÖ­[&“É+g•FÝ3-- °µµ•W ”³ÉÉ ´nµ5k׿{šFC­ZÄÇÓªr9ù¦Å‘ËiÑ‚®]9w®˜º,‚ XVvƒÑ2"g8SJÀƒâââ<Š.ÅeJJʦM›d2YïÞ½‹¤žS©pr’>Êåxx VãçGëÖôï•2žžÈd¸¸`k‹B‹‹TÀB­fÖ,ÆŽ•rk¤¦²aCA™Ý iw£ ‚PbD0*e…­­mÛ¶mÓÓÓ‹0©“Á`HJJ’Ë冇ôÊ¡)S¤iwGGÖ®ÅË †Õ«¹~ÀÏû÷Q*ùäll0™èÞGG¶n aÓ&¢¢Ðé¨T©TöÞÞœ:ÅÑ£Ô®-ô ‚ ”Œ ááØÛ[˜ÁÔë¹t‰  ‚R®&'£×ç›Ï¿øÜ¹ƒÑ(ÈãÜ9ªU³<–šú¤Y£Kž••Uƒ J»eÑÃR¡ jUék[[êÖ•¾ÎÉ¿–§dÕÃŒoÎÎOºlºukºveÑ"¦O§~ýçê³ ‚ð„*β'ñûïœ8Q íîØÁéÓÅÛDX_ýì—/[ÆÞ½Ž''3h±±ù^h2±{7ëÖ‘ýÔÆÇ?WŸ7ofãFËß8ðpËßš7 ¤’/¥Réåååéé©)‹ž€ƒóç³i“ˆDAJN¹Ò륤îàäÄÃ|8ÙÙÄÅ¡Tâæ†\ŽNGF›6@PJ¥4lf2‘˜HZ..RR˜'g0‹L†“&“t¹^Ïýû˜L¸»£P`0–ƦMÔ­K@ ÅSì¦7™HOG©äÁärÜܤ<£&ññdfJ}6™HKãôi-bÀd2ll¤´Þwë–·šNb"))=Y m[ bðàBžZÉKMM}ðàV«-ÚÂKýsÖK ‚ B™TîƒÑÓ§™;W*¹icòeTªÄ½{L™Â; ôéÃÈ‘üý7óçsñ"ÿMh(Mš0u*ÙÙ|ó Û¶a2áéÉgŸIÓ|©©,ZDãÆtìhnèòe–-câDüü23ùïù㬬pv¦N>ø€øxæÌáâE ÚµcâDnÜ`útΞåìYöï'((o®Ódd0~<:ññþ˜S§¸w!CP(X¾ww®_gútÒÒHOgìXzõ²ÜîýûŒEr2½zñöÛÒÁ¿þbútT*ìí¥PØ¢V­¨QƒÕ«éÑã‰~ %æâÅ‹üñG³fÍÚµkWÚ}A„’Sî§é““9vŒY½šعà믉Šbùr¦NåóϹt‰Úµ™7ÆéÒ…yó¤±#GX¶Œ÷ßgõj ¾úJºgf&7ròd®†"#Y¶Lªç ÒÜôœ9ÒÁ›7/æêU¾ü’Ï?gÛ6ŽÅÏOj·gOæÍcôè§xj—.!—³b°d &×®1>ãÆñÍ7dd°x1vvLœÈðḻ3o3fàåERï¾Kõê¬ZŸq̘ALŒåVœœ˜7sÚðœÔªmÛò¿ÿÑ®IIùö0;½½ggš7' @êab"+VðöÛ|ü1@\S§òÎ;|û-J%sæ —3f 'âæÆ¼yÌ‹³3F##Gâã÷ßòñÇL˜Àƒ–ÛuvæÓO©]›Û·ÍÇ£IÖ¬¡]»|Ÿ, T2y2k×°–<“Én0\ËB>3AA(Aå>||hޜʕ©V¨(€£Gù÷¿©QƒprâÄ ìí©Q\]©QƒJ•vïF¡ 4”õëÑé •>:8°bEÞRŸõë³cAAÒãGiÔˆ–- ”ðRSÙµ GG6of×.t:NœÀÚš5prÂÝ5 ©ÞùÇ|ú)Ÿ~JX˜ù`÷îTªD‹ÄÅ‘˜ÈéÓh4¼ú*þþtèÀÁƒ(øùáíZMT«†FCt4gÎÍúõüó©©R¸ü8•Š5¤ý9âã gÀ¼½4¨ mÛÒ´)_ÍÊ•Lž,--U(xýuªT¡cGîÞ8}¹œ>}ðñ¡_?þú ™ |}¥>רJEB “±f Gb0pñbA}~4l‹‰áÜ9†ÅÛ›áà ٢ԡ®®ìÙcSAç• ´´´˜˜++«Ê•+í*'}MZš´0Q¡ÀÞ^ZTú¸ìlœ±·ÇÎŽ—^bäHé¸ZMëÖæ­¸9ÜÜèÒÅ™ét¨ÕÒ"Μ•‹Z-vvØÙ1lÖÐy’3wïræ gÎäŒ|¸æÒ`@§#- ¹\JsãàïSÓë1™pvÆÎ77Æ—âï'‘“gQ£P*¥/,rtdùr¦O§m[nÜ`î\éxN,˜ó#23ÍKB­¬ÈȰ|·´4)adÎ øþûæ}Ó…Ê ´r²h4ÒÏ%?J%ï¾Ë¦MóéJ‰S©TMš4iРAQU}(++ëÆ·nÝ2VôM[*0r$7nä;¦žÃ`ààÁ‡ƵZƧW/,¼õÇY¶ŒÍ›ùòK)}ï=^}Uú„6{6ßÿ„Ï#_ññLšÄíÛLžLZÚóÞM¡ì(÷kF- áÌt:îÝãöms@¹œ”ŒF)0ªY“sçèßWWRSÉΖ¢¨ÔT¾ø‚FèÐÁ|Ï+WX¾œwߕ֌֭˒%„…áéÉŸJ{§ªVÅɉ‘#Q©¸ßœZH¥âÆ s»ù6Œaà jii\»F@'N"÷òÂ` #CÚGåâB•*Ô¯O—.ÄÄðä5}<=±·çìY*WæÂóôýãnÝB.—Fƒ‚ µ|ZժܹCXüý·ytY©”våìØ©\//ªUãµ×¤›?ù(¡§'ÎÎ8@¯^üóz}!çwëÆœ9i[·þöÆoU*±µ•F¬¬¤a¼‘#yã † ãÞ=êÖ¥qcéä¦Mùüs._楗xï=z÷fÿ~†§R%"#é×!C²²øå¬¬r£wî°f Jof={òçŸ ‚›4j„BÁ´iL˜À°aØÙqý:óçÓ¨@ÇŽ|ø!QQ1sæS<;[[iT.ÇΙŒzõhÞœáà àìYs}ÑÊ•ñöæõ×ñòbútªTaÌfÍbÛ61ùé'ËM¬\ÉÁƒœ=˵kìÛLj´jŰaLÊöíœ>ƒC¾1ôÑ£¬ZEf&ØÛóÉ'ÖÖÒP±L†½=@­Z¼öÆÄ¡C¹ú@Ÿ>¸¸°p¡´kæLvï&#ƒ78rÄr»[·òóÏ\¿ŽÁ@DÝ»óúëLŸÎŒìÝ˹shµ…ÄýVVôè¡^±byß¾}íszYAÉår+++u™Í­ZüvïfËê×çòe–/gß>4t:¾ø‚ÁƒÙ¿Ÿ-[ضøxzõÂߟêÕ:”•+iÕê)Zqq¡jU¼¼rM ÷èÁÚµ¼óŽùȼyÈdñí·=ÊÂ…¬ZÅùó¨Õ,[F»vŒÇŽ9¸q¼ú*ÉÉ À–-¸¹¡VS³&VV„„Hé2A*†rŒÖ­ËÒ¥R­” ¤¡ÍÆùùgnÜ@£¡aCóØFÿþ4lHb¢”¡ÝÙ™+8{VJ õ0¶ƒß~›7|ƒüþ;ÁÁÒÜBóáá(lÚ$M 6nÌ?réÙÙTªd>¹sgILä©Â-’¦×X³''T*–-ãÄ ²²˜6Í<2êîÎ?JC•®®Èå¼ù&­Z˜Ç†×®uê˜úû£P0u*íÚ‘˜È[o¡Pä›e©š7ç»ïHH`Ò$<<0™øà)¹’µ5¿þ  Tòõ×üý7iiŒgn.ç„ëבɤŸàë¯S·.7nT¯žoŸ5ÂÓÓü0'Â;ïШññŒÑXø·n®?ÿ³cÇŽ~ýúrj1KOOOIIqpp°~ÚìbO@«Õöë×O&“½°ñè¿ÿMÓ¦$&’žÎpò$Íš!—3e ÿù÷ïS¯Çsü8:Ÿ~*}ŒyÚ`´KºtÉ{°ys.]Ê5Ë?{6ññ¤§ãíÍÔ©Ì›л7Z-›73q"¯½†^ÏܹtëÆèÑÈdôïÏþýô틇?þHÿA¨0Ê}0êèHíÚÒ×®ò 2O?¤Pä=hoO‹yOS©ÌéCNN<:ÍGáãCVþ) •*YX©TZèL¡ jÕ’¾¶±¡^=ék^y‚·›ª IDATÅÂù¹JÊå›bN L=ßÁ€€¼«cÆÂËò8™ __êÖ%.NjZ�ÐÜÿœaÀÎŽ¶m-ÜÁÅ%oZМýLùõY«ÅÅÅò‹,—Ó´iá}~ÈÖVùÃTªç›…- aaaÛ·o¯W¯^§Nd/w}zJ¥ÒóÑÈýc2±gsæàå…µ5ññRª2¥RúEµ·§reÂùx‘¤…ãøúAë #G²|¹´dÜhä“O8tt:¢¢¤5î*ÖÖXY¡RI“</’–&íyÊÎ&=½:#‚Pf•û`´´hµôéÃÕ«h4üïÏk–°û÷sM'æZ‡ðÌ^~¹¸ =Þ祥E¢nÝz Eoz7oÞÌÎÎvrr*òHô…eúÿi²²X¶ŒwÞaÄRSÍWL&23 ’’ptD«¥iS.”Nx8Ž,“=×ÖõÞ½™9SÚÌÃÆœ8ŸdzgO¾W¹¸ðæ›RÞ_ ¨wµ ‚ ”-"}FVVtì˜++~çåÅï¿Ë ØnÿœŠ¯ÏeGfffTT”R©ôËYŒ\Ô’’’¢¢¢\\\¼ž| [y¦VS¹2¿ý† ~~XYaoÏÝ»\¿Î¶mæ¤iÙÙ,[†ÇŽ‘’B‹¸»3p ÿüC` —/ãà eÃðö&9™mÛðñ±0aR(GGz÷fñbµšë×ÉÊbÞ¼‚¶Ù ÀwßQ·.¶¶=JÇŽO±™O¡ÜÁ¨ ”&™LV§N„„Ççܶ›7onݺµAƒݺu+Žû—5j53g2>Ÿ~ʤI4jÄìÙLÊ‘#x{óŸÿP©J¥Tìw0Y¾WW´Zþû_¾ü…‚éÓ¥ÚÙñÕW|÷&ÓÓ-ÖìØQZ¸üÖ[ܹC­ZhµÌ™#-KmÖ ¥¥’ºuñõÅÁƱµ¥}{”JÆŽE©äƒÈ̤jU «QA*Œ BiÒh4­žj§ÌS2 €¼àäKP«W›þë_ìÚ•÷œ‡åÖ’ËéÕËBZ™ŒÞ½éÝû©»ñ0kDp°9—Åðá žë´·Þ’¾ÈYBðÅ ï¿Ïûï?u£‚ åÑ ôUNeeQÑKçÅ('µÉ“{SAÊ Œ–u+W²eKiwB(©©©qqqÅZ¨ÓÓÓ³cÇŽÕªU+¾&Aáy¼ÐÓôz=·osé&5jàï/¥¼{“‰ØXnÝ’2 ™LDD`oÏ… deÑ ..ܾÍåËèõáïpãnn89ÄÅ‘’"Ï#3SÊêrí¾¾Ôª…BÉDd$. ÑP·.®®ddpý:'NàéIp0Ò´œ L9•¥ó-}™À•+ÄÆâåE:Re¦ìlnÜÀÑ‘3g°¶––©ÅÆ¢Óñà7nH©š¹r…èhÜÝ©[bbHM•’@ \¹‚¿?ÅóÅròäÉcÇŽµjÕªyóæÅÔ„(à#‚ ”a/t0ɘ18:bkËɓ̟/¥:Z°€ƒQ«±³ÃÖ– ÈÎfÀ¬¬0ÉÎfà@zô`Ü8¬­Ñh¸p hÕŠ)S¨Y“9s¤Üï K—Zh7<œN ¤R%BCY¹’6m¸r…Aƒðó#!•ŠINfÆ ÎŸÇÆ†°0š4áý÷IJb®^¥F ÎcÞ<^~Ùò³[¼˜ÐPªUãêUêÕcþ|ärnßæ¥—xé%L&âãY¼˜Ö­ùæ~ý™ ­–ÔTfÅ öïÇߟóç©WÅ‹9z”É“9y''Nœ woNÁèsÑëõW¯^ÍÎÎvËS_AA^$/P0j2‘‘!ˆ·¶F&ÃÓ“¯¿F¡@§cÑ"~ýÕœwÓÚš_~ÁÍ»w±¶&;›”^y…3’’¤ Lr9z=+V°i/¿Ì AÌËøñdfj9ÍakË‚ԫǨQìÙC›6¬^¯/ßO\;³?}ú°e &P¹2&HþñÇŽ±};îî¬]Ë’%ù£o½ÅÛo“™Ix8cÆ0i’TµÈhäí·éÙ“ÄDs:Æ´4þübb†eÈ23‰ŒdÈ>ø€¶m±¶fÏzõâ»ïèÒ%W‚}áDGG'$$hµZïœRÅ#===;;ÛÖÖV•S¤µ|JI!>gçç­/‚ ”A/P0š˜È¨QÜ»G•*,Y‚‹ ii̘Ax8*•4ëýPÇŽR°õ0½Ÿ½=}ûJ©°Ý܈gî\.^ÄÊŠ»wiÖ  E L&Ž“ê‹6hog\\¨R™ .]¢eKT*¼½ñõåêUËž;GZ“'¤¤H‰»g0°g«W£T¢×“˜HLŒŒººÒµ+ -'ÈÑ¡ƒô]OO ¶mcà ŒFt:t:ÜÝéÙ“~ M~ÿ•+ ~±…ÂÙÛÛ7hÐ@£ÑØÚÚ_+û÷ï¿råJß¾}«T©R|­·#G˜;gg~üQŒÇ ‚ T4/P0jcÃðᤥI“ïÀܾ֭͆ T©Âܹ?n>ùñQ$µ:×Á]»¸|™ï¾ÃLJyó¸~ÀÃöíY»–´4zô(¨nŠLFžd;j5IIz=ÙÙüÒÒ:Ô\nûQ®® ÌGao½=Iñ·ZM``Þ“ÝÜrM÷;91j3f`g'í¸Ïé¡FCÏžù¿¦Â“‰ŠŠ²±±qrrRäü›*UªÈåòb] P’D0*‚Pñ¼ÐÁ¨»;6ðàÖÖØÛ›?^øÄɉuërñò’®ÕhppfgIB&P@Œ`¾ÛÃú+®®¬YÃÒ®ö‡‚ƒÙ¾ÝüP¥bøp 1{{òËe®T2~äP(xçF§ÃÅEºÖd"%…3ghÓFÊ0%<³ìììß~û---mèСîîîÅÚV ¬(ÖÖT«Æ§Ÿ2t¨ø8$‚P¡¼ÐÁ( RñÌÁ€RIžœ<›7³r%!!´lù,7”Ëqqy¢35ófö£G9yÒü-++zöÄÕ™ gçgé “åÚÞ$'3t(,_þŒ÷ºsçNbb¢££c…°,2vv„…‘˜XÚ]AŠÔ‹Œ­—_¦N|} ÚºTät:ÒÓÍM&Šc³Š­-ŒVkN/ <³7ndggW¯^½¸ƒQ“Éd2™*FaúôtNbþ|Z´(í®‚ EJ£EÉã²o¶iC›6ÅÞŠRI:ÅÞÊ "000%%¥fÍšÅÝPjjêŸþ©V«Û´iSÊÓËåù¦AÊ/Œ BIóõõõõõ-†t:]xx¸UÎæµòL§ãî]âãEA„ ¨ìÎßefGVVi÷#7ƒÄÄb™Ïa2‘”DBB16!¼8t:^¯—Ëåå}¦þÐ!FŽ$(ˆààÒîŠ ‚PÔÊî[ÔÁƒôí˘1æ<—eÁíÛŒKtt¾'¤§ùì÷ß¿Ÿ×^câIJõ¬…¢’••uýúõäädÓÃJ¬ÅL£ÑXYY•÷<£õë³n?ü ¦éA* ²Œ¶jÅòåìØÁƒ¥Ý•Gdgsó&:]¾'œ8Á!Ï~ÿíÛù׿˜7/Wª)¡ÂˆŠŠúé§Ÿ¶mÛ¦+àw¨èhµÚþýûwïÞ]ýxÑ­rÅÙ™ªUE$*‚P1•Ý5£ÖÖ¡Vó CHrãׯK¯^tê„\NBë×sá•*ñæ›ìØÁ Aæïë×l.}ô¨7øæîß§re©8gz:›7sì/½D¿~Èå|û-Çsó&ÿ÷8:òÆhµüó›6K•* Š¿A=7xölSBwíÚ5NW¥J•’‰U*Uqç1A„çTvGFs(ùV¼,À±c|ø!~~2m11dg3f н;·o3m©©,_ν{Ò%‰‰Ì›g¹¾KZo¿ÍÝ»tëÆáÃRYθ8Μ¡U+ºwç»ïX½…‚€ªVÅÖ–ªW—JÀ?N•*ôëGJ cÇ’‘‘o·M&¢£Q–ÝÂsÉÊʺyó¦R©¬^½zi÷EAÊŠ²øÔ«ÇÒ¥ŒÁK/廑6=»w1™ÐjÍIã»taÄ’“Y½šˆŠâÄ V¬À×&L@¥ÂÁk×8uŠ»wyùelm©RÅÂý/_&2’/¿¤zuœ3ÀLJqã %* ooΞE­¦sg¬­9|˜Ì—Ìñã„…áäDd$wîP­š…V¢£Ù»—óç5ê¹^1¡Ì’Ëå­ZµŠÕæ©6[lâââ"""ÜÜܪV”ªY{öÌãÙt:~ý•¸8”Jºw/ö$kW¯²oYžKAž\YFkÕbü½©_?ß`ôôi† ##ƒqã˜2E:èêŠ\Ž““4Ñÿ> |ò‰´ìÌË ¥’† 9vŒ«W¹y++ÜÜðô´pÿÄD ©¶»‡‡TüóâE&8˜5HNÎ[Šé¡”Þz‹;whÝZÍoÕAd$ëÖa0ˆ¬ò–J¥ª]»vI¶¹cÇŽ T˜`T¯gåJFŒ°ŒšL$&rï?þH­Z…£F#_}EãÆ4nü,Ý0éÚ•W^¡øsÅ ‚ T|e=ýñG–-£S§‚ÎiÔˆ#G0™( œ§'U«²z5~~ M›òÙgT«FP›7Ó²¥åx×Ù¥’´4€˜’’ŽÃߟµkQ(xÿý\»¬ éþÀíÛ\¿Î?ÈÁƒ¹ªÌçѸ1;vн;‡XÐó„'”³gßÚÚº´;ò¼L&âãIL̵ˆ<çCfr266xz¢V3b©©ìÛ—÷òÔTîßG&ÃË µšŒ ââØ³µšÊ•Ñh¤Ž˜23qsÃѱ.…‡óå—Ò?sAáy”õ`4#£ðÌ‚juáSr!!ðþû BB‘‘LœHp0·oÓ­!! Ìûï[¾68˜ªU™=›^½X³FàôöæÆ ¶n%:šï¿7‡ËZ-11|ú)~~të†V‹µ5?þHÍš,]jyMêC*¤¦ò\„ò(:::99ÙÇǧ$SЧ¤¤Šò1;ÆØ±Rä—óÁÏhäçŸY´†”>þ˜®]-_{íï¾KR´kǧŸrü8ÿ÷\»Æµk¬_OãÆ|þ9™™L›ÆXYamÍÚµ–íäÈÙÅXþ_WA„2¡ì£9éßFž!CbË–ælùcÆà+V°v-[¶ Rѽ;j5̘A»v89±`uëZ¾› Ë–±r%;vСÝ»ãäÄ+¯Ï®]8;³`yK~p0‹sêqq xx0>ë×É›o’•e^Õj‘RIz::¨4SÑ„††ž9s¦[·n 4(±Fƒ‚‚ìììÜò[DRN¤§3gmÛ²`§Nѹ3ÀíÛL™ÂÒ¥tëÆŸ2i;[ˆu:fÎ$ €… IH cG^{6m8p€Aƒèݛ޽¥3û;8|77&MâË/™7Ïr²²8¾ yAá©”Ý`ôÈæÎ¥J•gù£ß¢…ùë·ß–¾pqa„\§)Òn$`üx½>×9VVÈdøûóÙgy[:”¡CóT©èÒ….]ÌGš5£Y³'íy:|ñqqÌšep…ò.---""B­Vûøø”d»^^^^^^%ÙbqHKãÖ-¦NE.'0€€3gHH 4”M›ÈÊ"6–ØX®™™œá78¥’{÷ض ++  bÜ8Ž¥qc>ù„ž=9|˜=¨\™¨(Fbذ‚º˜Lϲ¢]AÈC£‚Paeff¦¥¥rö~—g­ZñÇܽ‹§'66ØØ P0d:qû6 5jHgÊdôéCûödfâì ÄÞ½„…¡× å Ú·çøqÒÒ¤ÜÃVV|õ×®‘šŠV+å€+€£#ßO—.89Ó“AxQˆ`´¸œ>‡G®•™™\ºDp0§}4IMÅÚZl¢¯€Î;çààP¥J•ž+7™L&“I£Ñ”ðÚ€bâå•w’L†‡‡…´n2™†>dmÅjæØ4ç‡AmÁär–.eçNôz† y¢KA„ü”õÚôEkçNBCK¨­‰Ù¹3ב˜Æãöm 'ge1q¢4Ï(T$ÉÉÉ{öìùñÇ“““K¸iNçæææççW’™M_²aƒˆDAŠ@¹ÕëÉÈ@&#=s:¤ÌL’“Q(pvF.G§#-_~Áߟ  T*)c”Ñ(mV°·çiß²³²HIÁdÂÎÎ<Ø™žnžøËa2‘œLV–”-ß"kk)w ÔÔJRDDDZZš¿¿¿]‰gêR«ÕÝ»w/áFAái•û`ôäIfÌ@­æÞ=œY³oonßfòdÂÂ0™:”Q£ eÖ,°±aß>Z´`æLôzV¬àçŸÉÊ"0Ï>“fÕÓÓY»–Úµså+ ç»ï6Lªôi\¹‚É„ŸsçRµ*7o2i‘‘89qåŠtáÖ­,\ˆN‡ƒ))ù>‘ŽY²„ß~cĈâ{µ„’võêU£ÑX½zuU…^a0 J¥² ?[AQî§éSS9uŠÑ£Ù½Nʺ|9ÑÑüú+sæðùçœ?OƬ[ÇË/Ó¿?ëÖ1nÀ¾},]Êdzcj5_|!Ý3#ƒåË9v,WC7nðÉ'æIv•Š×_ç§Ÿ¤k—-Ãdbî\är~û÷ß— ÆÄ0g}ú°gM›’ïqvfȾý6W™{¡¼kÑ¢E»ví‚J#_—Éd2 %³{)&&fË–¬ÐÐ:]iÆÜÙÙdf’™™+hŽB_‰ÌÌ"ë‰É$õ$«ˆ‚sƒAºa9§WÀ³.àµ*a&YYÒke2•rgA(å>|}iØüý‰ˆ åÕWñö¦C\\8ykk¼½Ñh°µÅÛ[J¤¿w/66>Ìòådeqò¤ôÎaoϲeôê•«•zõزŜÔÞž¸8¦Oçí·¹t‰HIáäIzöÄÓ“¶m¥3#"HJ¢KìíéÝ»·={¢Ó±kW¿>B)òòòjÙ²¥Ã£ÛdJJjj꯿þºk×®¬¢ ˆòwýúõìlƒ•U†Jõ4±R‘ÊÌä£2„¹z5×· ,àøñB.ïׯÈ:ǰa ÂÈ‘…ÁObφ¥¾ùæ)®Z¸?ÿ´ü­yó:”>}8s¦ðû¤¤´Êè9ÅÆòÞ{ ̨QÄÄW+‚ ”e!}\Fr9€L†ƒC¾YYR-øôt||èÓG:®VÓ²¥Tuð!WW:u2G“{öðÉ'tî̤I´o`4b4J‹Vår©9ecrfhÕêBê*¹»Ó§«V‘žþ OZrÉÈÈ »s玩˜‡›²²²®_¿.—ë}}/kCS«2„±c¹u‹ÄÄ\ßÊ©è[põ+ƒ={Ь3NNLšÄ!=Z4£}õë3i\zš×øìYË;&¾}™4‰¸8îß/ü>sæ°qãS´ûTœœ5ŠAƒ¸|¹C^Aʲr¿fÔ¢  Ο';›»w‰ˆ0§k‘ËÉÈ 3…•ŠZµ8wŽwßÅÕ•ôtL&iãQj*Ÿ}F³f¹JÌ_¼È¢EL›&©wïR§}ú•ŧŸ¢ÕboGÒ¥ ‘‘ܹàîŽJEDUªHå^ 6p 7òûïôèQô/‹P’’’’.^¼X­Z5777YiäF7 Æ™‚•ÉdÕ«W—ËÜî”@sù‘Ë !55ïNÄøx~û ™Ì¼»Q¯ç×_ñò"4úöÍ•àÉ`ààAôz:t°ÐŠÉÄ/¿Ð±#vvÜ»ÇÑ£ôî ÍéÓhµ:„“ƒѰ¡T,ªPÙÙ9¹sÈå´oOp0F#'Npð vvôè·7îsâ—/r7½ž¿þâØ1ªV5¬ÍÊâÐ!N¢reºuÃÁAú«˜gÈÞhäÚ5"3“nݨZ•˜öîåäIîÝC©ÄÃöíQ*¹Ÿ={¸s‡zõhÝe>ï$Û·Ó¤ ®®Ü¿Ï±c´k‡­-÷ïó÷߸¹qè66¼þ:uê`k›ïMA¨ðÊýȨR‰TÅÊJŠ&GæÐ!þó†ç_ÿ¢iSéäæÍùá––‡ö쉗ƒ3f ½{›?úge±kWÞ?úÑÑüôññÒúu¹|™#4ˆ ¤š.&°};o¼Á›oJ…¿?¯½ÆÄ‰ŒÉìÙ89I#¦ù©\™=XµªÈ–š ¥%,,lÏž=ûöí+™ˆðqr¹ÜÆÆÆÎή¸óŒªÕêV­Zuîì¢V—Å!ýÌL®\aÁN’ŽädR=૯˜=Û|²NÇÒ¥Œ‡»»å»™L¼ÿ>qq.0uªtüÂÞz‹Q£ˆŒdÃîÝ{Š.\È;ï Óqó&›68À«¯’žÎÞ½téòtëÈ·laÀ23ùùgöí“ú|¸^¯—ü¨¢«T‰Ù³¥è!¥’?¦{w||øüsé ÑÈâŬ[Ç÷ß[N’_°ädNœÀËëé‰&%1>ßOÇŽ€ô)ô›oxýufÌ +‹ZµØ¿Ÿž=Ÿô†+V0v,“'“šJƒaaüï¬_OƒôèA¯^ÄÅY®{¼p!ݺ1u*2ƒ³};£F1s&÷îÂøñÒi[·’”ÄêÕ89áîκu¼új!kòËùúk5B¯%UA(ÿÁ¨ƒƒ9@¬ZÕ|Üßÿ¼'ËåT¯žëˆ•× W*-¼9:Ò¸q®#~~jV¯ž· µ:ï… `õêBÖ· e\LLL||¼³³s@ž¥Ç%H¡PØÛÛw+IIIYYYÚœ-å‡\.}"U(rÍe/Y‚V›ï°hÁBBðô”îùänÝ"=æÍ¥‡9s;wîд)r9ÖÖù7¼r…ñã‘ɤ…CÀíÛdd0c†´x=1Qúðü¸°0¢£9qàî]š4±|ÚÕ«DF2|8@z:..dg?]0Z¥Šô÷YLÍ ‚@F+™ìé‚W¡ òððèÛ·ozzºmNq…Šëرc'Ožìܹó£•oK‘L†LöŒéЬ¬ eð`&NäÿË·6¯LÆýûøùåͲd1-´'îî(•ÄÆòhU;;’’L&bcsU7-ô†Z­4n0š `o‹ ‹I±2˜+kÈd¹ÆqµZ 0Â>úYæÑÓ\\ø×¿øæ)”T«Éï×\.—–4èõ¹6r)^.“I¤v„Ô ÍÍ;Ä IDAT='ÅD.—ûøø•ÊÖ¥ÑÑÑÿüóÏíüvS…´´´›7o* 2S7L­¦R%6mâØ1âã1™¸|™cǸŸ+W¤ƒù‘ɨT‰U«¤toùFìÜIddáõ{]]ÉÈ`ËŽÍ7ˆôôä•WøðCnÞäÌ~û  C6oæÜ96oæÞ=ó¸©ÿÍŸrùr¾ÝëÚ•¹vï¿—¶Þ‡„àãÃÆèõÄÆ²k—yIzµjüô‡ л7?þH\z=»v™óøú²kû÷sþ<íÛsû6‡!—sáÇç;ÕÌîÝ„‡³~}A%?ggd2¶m#4”´´‚ΡâÁ¨ ±’É3_¨;wîlß¾ýr¡»¯ŸÃ½{÷îß¿ïââRv‚Q•ŠY³HIaéRÂÃ1Ù¾/¿ÄÅ…S§X²„°0”J:uÂÍ  re)5›R)¥°ð÷ç›o8wŽäd ÷—Ëùè#fÈjÔ S'鸧'/¿œ÷d{{V­bÓ&/.h!éò帹1dï¾+­9’®]3†åËY²Ä¼â¨cGzödÅ ~û-ßN™Bp0o¼ÁÖ­¼õþþØØ°j©©Ò ob¢yr|útllX²„óç¥v_}•wßeà@Ž1‡˜Ã‡ÌW_ñóÏètԯϒ%lÛFŸ>|ùe¾CÈÀرDDðÆØÚòÚkØØ89ѺuÞi}­–¹s9uŠ+ž(Û” ‰˜¦„¢¤×ë·mÛæííÝ AƒÒ-šžžk6lèææV¦ŠÖ¨ÁªU懓'[8gÉé‹FhÔ@£aÃé`‡–ó:åhÖŒ½{ó¬U‹Zµ,œÜ¥K® qyy±xq®#ÖÖÌ™cáLµšiÓ ¹›““ùÙ=Tµ*+WZ8¹R%–-3?´³còd ¯˜—WÞ{¾ò ¯¼RHO€úõ¥±ÞGðÑGNnÕŠV­ ¿§ FKÈÎ4mškí—P!ݺuëòåËwïÞ­S§Né†h%PxÉÍÍ­K¡¡Vùd2±n9 —³hÑsÝóÓO¥Ùðõê1dH!¹ÞÊ‹M›8|ØüÐÖ–wß}Æ}`‚ ¼€D0Zì ¢£Y¾œìlš5ÃÍM¤2©°L&ÓÙ³gu:]íÚµmr¦$KOHHˆ““S•*UJ·åWíÚ¸¸˜>ÿ?Û¦M¥E9¼¼*Ο‚  \µ ØÒ$‚ð¸:MI!* ™Œsç¦V-ärt:®]ãÒ%lmiÒ­–ÄDnÜ :__bc±¶¦qc ÒÒ8wNªAâç—ïÇÆ,ZDb"‹±b?ü€ZMXj5§OS­õê¡PÍœ? Íš¡Õ’–&U½×jINÆÎކ ¥"RçÏNݺT¯^AFV*†ìììøøx[[ÛZ§lK–···w±mq7Z­ÖÁÁ¡Bæ1•ɨ_Ÿúõ‹òžmÚåÝÊ”üV)‚ <‰:=žðñÁLJɓùî;Z´àÈ&O¦^=ââX´ˆ 8}šyé%BCiÒ„°0~ýOOFæÖ-ùè#¾þÚòj'£‘5k˜6]»˜>//ll¸r…®]ñóÃ×—ƒY³†6møã¦O§IââX¸õ뉥}{Ú¶eÿ~š7çæM¾û??ÆçʪWç“OXº´"¿Ã•;fذa9FK»/Å+%%eÛ¶mr¹|ðàÁþÉ ‚ ÅêÅ Fu:L&d2”Ji‚L­æÛo dð`Ž¥E 7æ?0É̤{wNžD.§fM>ûŒÁƒùüsFŒàþ}NœàÚ5vì@«åÿcÙ2ËÁ¨\NP«V‘ML >>Ò@¦µ5 R¿>cÆðÇ´iCëÖ8€ÑHVJU¤}}ùüsúôaölfÌàæM®\áŸØ»­–uëøâ Œ–-*•Êóa:ÇR•™™i0¬¬¬Š£TTTTbb¢ŸŸŸcY-ÏžŽÑhNÞ™œŒF#¥”Bz= J%e3©ÿƒR®Sgç‚¶´‰¬,RR°²Ê•U¡HTÀùµü$%I)Kr’›ä¨TI*ûùðÍæŸèу–-éÝ›ˆ)õ´­-VVØÚbm Á©S$$ðÞ{ ʦMÜ»—on¼Ù³iÓ†7èÕ‹‘#¥|1nnøúx{K9ÿ®\¡woš7§W/iöP(°²ÂÚFz³¹r…äd©Ý­[‰Š*Ž—Jx:NŸ_e›ÒðÝwß-X°àNÎoR‘2—.]‚‚‚Êìý×_›·lëtŒÅîÝOw‡¨(ºw§CsšÏ"ñ÷ß\¿^4·š2…îÝ àï¿ ?94” ž±!“‰÷Þ£Y³ÂS« ‚ <ƒhdÔÊŠ=HO7Ç”€F“·Ýܹtî̤IÈdyß„äró†;;jÕbìXéHN´j‘VËôé\¿Îðá¼÷ÿüƒÅ³ hÙ’?Ä` KòÛ ­Rhn·´7ɓɴuëÖ¬¬¬öíÛ—‘¤›&“I©T*‹§Þbýúõííí«U«V7&™™¹6™L¼óŽôñï!ƒÌL 4d2L&©NzV–ôgÁÏÐP®\‘ò>*;µZúˆ˜“ò3g:ç>ç^e4b0°r%õêQµª4Eóð†z=VVÒÌIÎŽÉ„B!ôzär23‘Ë¥#ß|Xˆ• ²²Ì§å´»t)Ô¨‘«]¦¦ññ:ĦMÔ©SÐi‚ Ïæ F5š'JŒ§R¡ÑšÊŽ/ü•WøõWär‚ƒ¹{—´4ËÍÓÒX»–—^"3“{÷ w…½G™Lh4¤¥±o'OÒ½»åÓZ·fýz²²¨_Ÿèh©ÔžPêâââÂÃÃår¹æ©f‚‹Mvv¶N§S©TÅŒÊåòjÕª•ÁHT¯çÛoùùgi2!§2ûÍ›|ð&P©’tfTsæpívvŒK‡DF2kj5—/KËcr²âça2±a[·OåÊ|ø!5j°nÑÑRÐ7øðC¾ýÖÂÅÐP¾ü’¿ÿæìY¦IéSå|õ 4oÎÔ©ØØ0t(@RÕªqõ*‹,}믿P(xï=Ú··¼yñæMæÏçêU4äõ×¹t‰Ï?çøqΟçêUêÔaâDT*båJ¢£©_ŸéÓ J>xyLžÌ† ´hÁÆüû߸¸àèHõêXYŒFCp0®®´lÉøñŒC›6 DD„å&”Jôz>ø€½{ùúk&O¦A¬­ –'¼¼ÈɽóÞ{üò -[²bmÚàá 5k¢RŒµ5ÕªáìL“&LŸÎûïÓº5}úV"¯”P˜‹/fdd:”™wl__߀€€2•޾¸8À¬YLžÌ„ œ<)ôð`ôh’’¤Oƒ€ÑÈìÙØÛ³z5S¦HAXr2ëÖQ¹2‹“‘Á„ ù¶ÏÛo³jAA¼ñ@PóçKKz6l ;Û<÷ò¨êÕ;–:uhÛ–±céÜ™ŒK—èÛ—W_eÉþùG*Cºs'Ý»s÷.&þþ¬[pèþÉ'ŸÐ³'ÿù‘‘–»—šJ«V,]Êĉ̜Éùóøú2z4Õ«Ká﫯¢Trñ"ÇӶ-‹qõ*_~YP]øÌÌ‚*H ‚ <§hdôquê˜ËŠLœ(}Ѻµùm졦MáÿOŠ=,îò曼ùf!Mh4ŒǸq Îôéøù™«¡üç?ÒÍšñÏ?y/_¿ÞÜîüùÒÁ!C2¤Ð''”(¹\îààP§N2²†R­Vwîܹ8î¬×ëoÞ¼ikkkm1à*U[·Òµ+;b2ѧ9+xsr´=ºÏ*gâþüyΜ¡n]iÐj™<† xùeÖ®µ0ô(“ѧ¿üÂŽ$'sü8@Ó¦øø°y3C‡²v-‹YN êê*ýçïO³fÒÁ~ V-ªU#=6mØ»—±c:ubãFš6%.ŽK—¤Hñwhܘ Xº”#G¨ZÕB+Õ«så ëÖ¡Óa0pæ õëKYê*W6·»s'•*BVíÚñûïddX^ö³w/7âä„“S¡?A„gñB£%©CQ~©"kݺu“&M^„aH­V»cÇŽ»wï¾úꫥݗ\ Èɬ*“ááA~{· fÎä‹/øï¹x‘9sxç77i»½ƒF#ÑÑ<ž§5#ƒ¶miÝš6mHIáÿ“ŽΚ5Ò2€§*J•@d$Ÿ~*=¬U+W ›3#Ö•+Ký·³#6Öò gÏf÷nÞxOOʷݨ(""˜7Oz@~»ïr288²®Tᙉ`´„ôï_Ú=ŠYY-šÃd2 ¹\^´#µ*•*$$D.—ûûûám‹„B¿?.`0`2qútAå(ÝÝ¥©†eËøá) '&ÂÃqr’"Q¹œ¤$iOpç |ý5 [·šo8`Ó§3gýú¡VÔO™ŒŒ óÀùñG¬¬00 JÒtò$-ZšJ\~~ÒA†˜ó9GŽ0apÿ>))æãr9z½”Û¨]›kר¸;;©ÝüºÝ¥ !!ôìI||¾KÞAž‡FṤ¦¦F;;»22AŸ#))iÇŽZ­ö•W^)ÂñZGGGŸ‡sÛeÉÀ´oϤIh4ìÜÉo`0°~=çÎqáëÖñ×_ LH3gb4âáÁöíæ™k½ž#hÛ–åË?^:èï»;C‡R©óçãニ g·7kÖ˜·¥»»Ó»77J‹j P§Ë–I½z È!üðcÇR«çÏ„ R<ªP “!—›‡$—.%#CŠ³Û·—¶kÇüù9Bÿþ4lH«V¬XAt4þIr²y¥A›6ÌŸOr2!! N¬]ËØ±Ô­ËµkÔ¬ÉèÑùöÙÚºØó˜ ‚ð"Á¨ <—ÇŸ;w®cÇŽuëÖ-í¾˜eddDEE¥¦¦ †" FSSSÿþûï3f”Í\÷AAìÙþ}(•üú+NNÈdáèHË–2..ÈåôèÁÿcï<㪶üž)™L*é!„„ÐB % UD¤))"+"XðZðzQ¯èUD)^D¼RT@Š銂té% IHBz2©S¾s¾ I&•„öûÌ“gfÏ.kNæÌYgíUŽE¯gêTx@Þ¶-“'sþ<}ÄCÉ*{ö°¿¥LÆöílÙ‚$ñÓODG[V¦_?Úµ«DÈ矧];²²hÑIÂÝ;ùå238PÎøñÝwØÛ󿛸úRP@Ïž²>:kII ăZ’Ï¿õ}ú•%[‚ßxƒvíHIáÅqq±xLžL` ééxz¢PàáÁæÍìØAJ ½{3xpE2«Õää”D‹B+µOÃUF‹Š(,´dò«EÌUŽlmå«‹^oÉäW3ŠŠ0«WÜ¥Z˜"ªTu¸„ fäææFDDº›k'40j=Ïh~~~BBB§†Z†\’èÐJ4öéc¥g¯^ôêUºQ¡`Ü8Æ+Ýîî^"Õh` Ånj¾ÉÎæàA–.å£ä_•‚¹6R1ź£RÉ!%ÞrqáÉ'K´Ü?üÜ$кµü¤sg9~ÿfJMèàÀ£–îcîVªZ›››õžequeÈ&Oæå—™:µJC ê4 ÅRlÝÊ]w1m¹¹µž•+¹x†Ç£bbX²„ǹz•K—ð÷gÚ4òòøùg /»îâñÇ-[xe1Q©ps«öAÜ|}}}ÍE ’$9Tð­ª>ùùùçÏŸ=zôñ²ép@ ¸î6½…¢&ÜË—3{6wßM×®LJt4ùù<ý4©©LœÈ–9;wF¥bófù¥JE×®´kG³fôî-WK²ÊÙ³<÷íÛÓ¯ŸÅ(rú4:>JLÊùó8:Ò»7žžл7;ddpîC‡òøãlØÀâÅ}£Q.™-Ô#ÉÉÉIIIéé鉉‰õ-‹@ š Ú2 tíÊ×_óÈ# Pn$“Á û•ÚØ Ñ`2±h3fÈ©§÷îåÏ?i׎øx¾ýœœxåyì!èt–ô Æ¡×sú4cÇV$ØúõóꫨTDFÊ•‡ ÃË‹'ä ¨Ó§éÜ™±cÙµ‹îÝ-z{óòËìßOd$œE@ hè7ò«V±`ÆUÔgРH<=qqaæLÀhD’8|˜ÂBÙò‘’RI„¾$‘ŸOAAE©”Ü܈Œ¤°µšØX¹qíZ>úˆñãÉÈ`Õªý32,Ïwï¦C~øIâí·‰‰)w•éÓ9’‡":šöí+’Yp;1 §N2™LíÚµS6È"‰999µ;¡‹‹‹ŸŸŸN§k˜–àZA«µl’ëäæréÍ›[ºRXH\œ¥%?½žŸ&;…F$ã‚jÐЕÑüüš(aÏ?/×ú³³cÏÞ|“®]ññá½÷xðA¾úJÖJ££Ù¾³g¹z•Å‹iÕJÞÙ÷ö&.Ž?ÆßŸ°0š5³²ÄÈ‘üïÌŸ»;Ë—3|8@§Nüðj5»vqþ¼¥sÇŽ¬\‰­--[òÐCtèÀÿ˪Udgóý÷¥“ÿ•B«ÅÑ‘i}»s‰½q㆛›[ëâ I’ …]} Ò˜$‹Òi¾Å8s†ÄÅ…ìlK Ïo¾aéR¹î¨™ÿ›­[1™äÔú|À˜1·Yv@ hÄ4\eÔd"'G¶kV—çž#0íÛ),$$wwììX¹’eËØ»—I“°³ÃÉ ŽÜ\Z·¦ukrs)(‡wëÆW_qæ ¹¹r~¨²ôèÁ·ß²iÉÉ|ü±qÿþû,\È®]³d‰%«ö“Oâà@Zš¼qÏ=¼û.àâÂÿ[ÉN½$É;þFc%=· ŸQ£Féõzí­;|Ô ;wöñññöö¾õ©òòòNŸ>Ý0ëÖ.ùùÜsü|êT&NäÝwyðA>ÿœK—èÜY~kÚ4¦N-aûœ3‡9sP(8yRœ¤@Pm®2ú矼ó¥=*¥’aÃJoîûúòþû%Z‚‚J{†™Q(¸ï>î»O~YTTÂL¡]Eï¾»´QÓÕÕzö{''¦L±¼T«™4‰I“ªôY\]ñóã™g˜>½Ä$‚zD£ÑtíÚµ¾¥¨/////¯Z™*66vçÎ>>>}‹‹¸7Qlløè#ùy@Ç3}ºü²!U{‚&EÃUFÛµcÁ‚ƒo©Pç­“•ÅK/•pëìÕë¶CÒhXµŠÈHQ ´¡`2™j7™|'""Âd2µoß¾ÉsR(J”–(,D¡°X:«bòL@PîÕÅÛ›ÚØc¼UøÏJÄòß~åX¥"8øv/*°Š^¯ÿã?‚‚‚üüü²Jšžž®P(œœœnQÈœœœ¸¸8­V”••U[â5XŠC•JT*:wfóf :šS§ä·Ì¹2ÌOÀr—hoÏÉ“rêâÕ& ”†«Œ6 ||ê[Aƒ!::úСCS¦L±­_£}…lذ!!!á©§žjiNŒYSìííÇŸ˜˜èééÙ´•Q…“É’Ðwð`¶mãý÷7Ž“'IKÃÓ¥ƒL&4BB.\‡¼ü2#GâîΜ9„…Õϧ‚ƈPF‚jð÷ßëõú®]»6dM4??¿°°ÐÆÆÆÆÆæ§’$ÉÃÃÃÃãVkÈtìh%ã[¯^„‡“”„‹‹%×o±öYŠ?äÃëPB@ hªˆÈϺâÐ!®]“ŸçåqèP%ÉMËb2•ŽÔ/ÙÙÙñññ¶¶¶Íu]*z½^¯×«Õê[ôò4‰/hµ´j%ªNArg)£›6qàÀmZëwعS~žœÌ¬Y$$XÞÍÈ`Á‚y³ËÃСœ9S‡B ª…££ã³Ï>æXœ½A"IRPPP«V­n1A}ddäþýû3n.Ø AmÓè·éM&9õ´Á ǘ1Ðë‘$Ôj9U§ÁÀöí´iCïÞH’ÜÓdB¯ÇdB©¬vÌÕ±æuo¼5ðôdÅ K<–Á@j*Ë—Ó«^^(•Öu}|hÞœo¿åË/k’lUP899999Õ·•`oo?bĈ[œÄh4ž8q"""B£Ñ„††ÖŠ`@ ”¥Ñ[FbÐ † #(ˆ»ï–wÆ?ž–-i׎yó(*b÷n:wfíZæÎ¥sg^y@¯gáBºu£m[¸~]žS§ãóÏÙ·¯ÄBQQÌše©üi0°lÝ»ȨQrûåË Ž}úXË/¦[7~˜øx¹åùï>ÂÙ8‘ÎùñGëÍÆ†éÓùõWK‰BA=b4ï¨m댌Œ„„GGÇ[eJ MƒF¯ŒæåÉ;ï…½½¼3¾`YYDG³lóçsú4ÆÉÊß›oÎÂ…{öðõ׬\ID~~Ìk™sÙ2.±Pt4Ÿ~jQ(ÿü“Ï>cùr®\¡cGæÍø÷¿±·'&†/¾@¯—{NŸÎÎ(–üP³góûïtèÀÏ?Σ–ûéºw'8˜Õ«kçX jŒ^¯_µjÕÎ;‹nÎòÕP1™L·®:_»vM§Óùøø¸ººÖ–`·ƒ¡Üªi@ h˜4úmz U+ºt‘+¿GG=JX ‚ÿMÏžVîÙƒ³3'OÊEüNŸ¦ gg¾ûÎR¥ÚLÏžìÞmÉ÷¹gœ9Ù3rÀ”NŸæwpp _?:uª…fkËôé¼ø"Ï=‡¿-L(¨.\¸zõjAAA£0ŽFFFþñÇÁÁÁýû÷¯ñ$;wvww—$©!§S-Ez:cÆÄG5ˆ,Å@ ¨ Þ2jÎòÜÞ^®_–‚$‰¤$’’ðöæ‰'ävµšÐP|}Ktvuåî»-Aµ:J¥<ÖÅ…É“)*ÂhÄÞ(Q¸åéߟ¶mY±¢vfÔ½^ðàA£ÑrëÉ’nÙÙÙ 999·2‰B¡hÑ¢…O£Ê²ëäIJeÄÅñË/õ-Š@ ªLS°Œ–¥ukΜA¯'1‘èhÚµ“Û%‰ÂByO¡ KNbêTš5Ãh”Í¢@v6ï¿ÏÀŒm™óÌ>ù„÷Þ£M€îÝ9qBk2‘—‡VK` û÷3lqq–¼NF£¼¢ù‰YIµµÅÆF.å"IÅ'iµL™Â?ÿÉÓO‹ôûõC^^ž‡‡G§Z1w×=™™™@C΄ZG(•´mK›6'@ 4|½eT’J6?ÿÇ?س‡°0ÆŒ!$„~ý䃳hòî»&àæÆ¨QL™BïÞ|óÜ­ €_-Ú:1‘5kHI‘_Žƒ··<¶o_¾ü…‚3X½šñãyøa$™8‘I“ç‰'?^NçäêJh(?ΠAlÚTÉg://V­ºÕc%¨ŽŽŽO<ñÄäÉ“‹zg2™Ìµ@k6Ü`0ìÝ»÷رcæz— I"-­¾…A•iô–Ñ»îbãFÌ!,+£!!:ÄÅ‹h4ôèa)=~<÷ÜCVvvÎά[Çùó¤¥áæfñòtue×.J¥’0€¨(‹mÒÙ™~àÂRRpq¡sg€Áƒ9p€¨(<=qqÁÉ ­–yó,v• //ùÉüù¼ù&EE¸¹Uòœxáþóž}—[9Z‚š `Ù  IDATãààPß"T•{ï½÷Þ{ï­ñð¼¼¼ˆˆˆ„„„víÚÝb¦Òz¡];Ö¬aÂüýi$·@pGÓè•Q­­V~^\Wðö¶ÁàæVBùS«éÖ­t…‚²½µZJ´¨TtéRº›¯oigÓR/o^õ²ácÆàç'²ÖÑÑÑ~~~Êê&¡m̤¥¥éõzÿ†ŸQÕ*wßÍìÙ„…±jÝ»×·4@ ¨ŒF¿M‡ ÕÒ·/ÍšÕ·wÑÑÑ«W¯^½zu£ÈèT+èõúÔÔT…BÑ¡C‡ú–¥†¬YÃðá\¸ 4Q@ h4z˨@Pw8p@¯×ûúúªÕêú–¥ªÌâÅ• ß²…7êB®ŠÈÉáÍ7¹rÅÊ[‡óÞ{·[žÛF£éÓ§OïÞ½Q " °°°°°P­V×Àµ >>~Íš5±±±u!Øm@©¤GÖ®-‘!X hJÜ1îë‚; ¡ŒV•×^㫯j8V¯'!ÁúHt4û÷W461‘eËØµ‹ÌÌj¯;~Íe6¹v «;½ÑÑlß^Ãiu««ëĉï»ï¾‹:þüÅ‹“““ëB°Û€­->Jhh}Ë!Ô ~~¤§×·ApGoÓgdƒ§NÑ®%OS\Ь`oOj*'Oræ YYìÙƒ›!!z=G’˜HHHé¬O7ÍåË<òH‰”R:¿ý†ÉDÅ%W®ä£ÐëY²„¯¾bóf9w77NžÄÏ^½äž©©üþ;Z-ƒáà Ë|â {öàê*Gëõ;Fl,½zXîºW¯réÏ>K‹–Ƽ>>‰‰‰Þ°À¹F£iÕªU æææ^¾|Y­V{xxÔ¶P =š> W/–-£k×ú–F ¨=îheôÂ&N$0  fÌ`Ý:ú÷çèQÂÂèÛ—øxlmÙ°øxV¬àÊ22(,¤S'BBHKã‰'HK£}{Þz‹¥K¹ûn뫜:ÅêÕ\¼È¦Mr)Ñ7;µww~ÿ!C¬,*bõjfÏæ÷ß™1ƒà`$‰èhÂÂhÞœÎÙµ‹o¾aÄ¢¢>œ22øè#¶l‘e>sF®€Ú©Ý»£Óñâ‹\¸@×®¼ý6‹3|¸õ¥ÏcåJöícófz÷ÈÉÁœF=0íÛiÛö}ƒ¦OŸ>z½þèÑ£÷ß¿Bq§ìäääèt:wwwOOÏú–E Xaÿ~Z¶ä¿ÿµÔ¸šw´2 h4|û-­[óÔSÛ‰$$ðàƒ ÄÂ…ÄÅ‘›[UIbciÓggŠJüÛæÌaÂâã?ž°0YmupkŠ’^OD½{#I¸ºÄ¥KÖg;ž”Yæùó¹p¡ªW®"Ë\¶îTSÂÅÅE¥R6RáÑ£G—/_~äÈ‘ŒÕh4 óSÿù'Çӷo5Î2 éQ\YZ hbÜA–Q;;¦M#7{{ŠËŒÛØP*Nñ[F#YY”WÜÑ‘¾}ùøcù¥FSÔ†¶¶äçËϳ³+êéäÄ+¯pá“'óæ›üõÁÁ–wÍAÞ*Z­ì{ª×“Ÿ_®Ì¶¶tïn iªV°µ­­Å½µiÿ ^ºtiÑ¢EÏ=÷ܤI“ê[–šPXXh2™šÕCµ.½ùv®.1‚ž=2„ˆÙc[ ¨£“ÉXßRÔ“ÉP|N üþ;gÏÒ¿½Ê$¸ã1™ u1ídµ±aÀ† £*ˆ3î×-[ÈÌ䯿HMµD5oNd$QQ˜÷0ﻋIM¥MŠŠHJÂꎮ^ϵkÄÇËõ×®QTÄÀœ:ÅñãddðóÏåJ’ŸÏ7ßð×_ètDD“ƒ««õžC†ðË/\¿Î‰œ=k‘Y«åøq.]’e4ˆ‹IH M$‰Ë—­Ïf4Ol,z=IIÄÄ`0p÷Ýœ8Áñãdgóý÷åÊÜ4HOOÏj´QZæ\÷¦Z£víÚµaÆ”””¯«R¹×]ÒIB£ÁÙ¹‰ß j—ü|´Úöõ-EÍQ*›áõz¾ÿžöí™2ÅÜ s½I&¸S),D©´¯‹™ï ËhY4¼¼d%ÒÕgg€gŸ%*ŠÐPT*¦O·˜až}–7ßdìXºwçÿ£_?Þz‹—^"7­–Y³,*àÍ$&òØcÄÇc2ñôÓx{³j0e “'£PàçGyû¢J%’ćrú4ׯóî»ôéC\>>²5×ÉIö1˜8‘¿ÿfÐ Ôjž|’å{Œ' £gO¾ûŽ>ûŒ™3e™§Nµ¾nn./¼ÀÅ‹¼öÍš±u+:ñöÛLžŒÁ@@>>5<æ ™‚‚‚Æè$Z ___I’ªŸ™™ž——×·o߯ko’˜¨2ôw^®}ACD¯§ ÀÆÃ£+£vv]óó•ƒA©D£aÅ øÿ 1àöc2‘—§ôð¨“<w´2Ú½;ß}'+£ï¾+Ÿäžž|÷F#€Ba9óÛµcÃL&¹E©äñÇ)ÞÈ-O‡iÙ²t¬ùR=ko½þ²¨Õ<ó S¦ð ̘A§N¾¾üü³¼Ü“OÊ~®NN|ýµ™ýüX»¶„ÌãÇóÐC•ÈìàÀ¦MVd~í5^y¥™5GŽ9~üø¥ò\n ½zõêÙ³gµõ_»v---ÍßßßÝݽÆëªT’Ô¢  ÆÎ®ÆsT„VK›6̚ŋ/V'Kšz=F£§FS~»Ré¨Ñ´ÉÍ 7×€kª?¼‚Æ‚ÑH~¾ÆÖ¶s]L~G+£’d9½oÖÌ$©´#iÙ>fnî¶oZ^::òØc¸¸XŸª¼%¬.:rd ëi±7Ë_3™àÏ?-/ml˜4Éby­±Ì‘ÜÜÜcÇŽeggkµÚú–åV©nɨÌÌLµZÝ¡C•ªæ?*•‡ZÝ.+«®”QÀÞžÂBRSëj~AS";Iò±±iYß‚ÔI²±·MOoT‰M–œŒFW­¶C]L~G+£µKq»{ûZSÝ|°væ)K)™ÕêêE55%Μ9“““YƒRWœ¾}ûvéÒ¥åCoF¡°mÞüèèCNNÙu¡æåqò$sçr ®‚;…¼<ìýüfIRµë5$IÙ¼ù?.^Üäâ’%ôQAý¢×£jÑâ_’T'z£PFkž=éÙ³¾…¨&ݺѭ[} Ñ0pww÷ññ0`ÀŽ;ê[–š“ššºfÍWW×1cÆTÝÄ+I’cm\뜜»¹½tíÚÇmÚ”ër+HÒ{³$¨:æRÆNN4k6ª¾e¹U´ÚŽ>>ÿŠŽ~½cǦ¼1%hà˜LÄÅak;ÜÓó™:Z¢Ñ‡kµBPPÐÓO?XAÔÆ@AAAVVVVVVuwêk …·÷L£q`T”%yYm¡Ó‘’RQ ((àÒ%ŠŠz¶lùa™pn/’§çKͰˆˆÚ?§‚ª ×sõ*¾þþ  ®®,Bdš@(}QQQQQ‘V«­bù¥ÔÔÔo¾ùfïÞ½………µ"€JåÖ¦ÍÏÍÔ‹UÉÉrPÝ­³~=½{Óµ«¨‚((£‘7¸pA¥T>Þ¶í6µÚ«ò1…BÓ¦Ízgç]¸ ¾~C$y¬`2‘žÎ¹s ½>¬C‡ýM@Ý­Õn³fñüóøû×·‚2DGG›L¦€€€z²&Ö&’$999999U±ÿ•+WâããnÑaôfT*ÿ..£cc߈‰9«Õbg‡£ã-mÜÀ‘#¨Tètètµ%© )`4¢Ó‘›K^ždcÓÁß¶‹ËXIjR[Ú …}‹³›5{ &fz\Üa;;´Z ÄÆ½ .0™ÈÍ5ŸV’Jåß²å{nnÕõ9%”Ñ:'3“Õ«ùå>œ1c¨f>rAb0vìØqãÆ &´o߈Sšñõõ}饗ª¨U †ˆˆI’‚ƒƒkW—$•³óðN†]ÏÍ=››{R§‹1*¬6&Ô•­mëæÍ{ØÛ‡¨ÕÞ’ÔTÝŠöö=;tØ¯×§ææžÑéþÎͽ,Î)AÝ Ðh¼¼ºÙÛw·±ñ½=Q€w´2zù2ëףѰw/={òê«8:Dze\¿ŽZÍĉôïÏùóü拉áï/çœÿÇ?°·çüy–/''‡nÝxê©r˾ñééx{Ó®‘‘–Æ·ßboÏŸÒ¥ 3gâäD\ß~KBj5£Gsß}ÄÆòé§äæÒ¼9™™88ðÎ;8:Á²edeѵ+S¦T£ © ,7nÜpqq ¨Ã ˆÛ†$IÊ*[K T*•‹‹‹ÝXì%Imcãgcã׬Ù(hÄU žFï`SE$I¥V{9;uv*Î)A]r»Ï©;å¶JRÿùññ¼ð?ýÄ–- ØÚòðÃôìÉóÏεküü3ÁÁ,YBp0›6Î¥KL˜@³f<ôk×ò¿ÿY_Âh$*Šñãñó㡇x眜HOgáBâãyöY6oæ—_®\?žþý™9“£GIMå—_èÕ‹o¾Á×—½{9vŒ˜ÆÃÖ–Ñ£Ùº•E‹nÓ±jªœ8qÂh4Þu×]Õ­ŸÙ°³³›0aÂ3Ïý”.]P©èÚ•M›ðõÅ͉1kìÓ‡»ï˜=›!C8|˜=øì3ºwÇÓ“ÇÇÁGÁÝ1chÓ†-زooþú IbĈÛr¤šqqþ‰‰gÏžk¹E‹Q*•ãÇŸ8qb¥yF322²²²ÜÜÜZ¶ly{d <îh»H«V<û¬üüÁå'¼ùféžf¼iÓ^zIn dÖ¬J–$‚‚ âÏ?yè!š7ðò’§† ‘Ÿ¸º2sfé᯾jYwòd¹ÑÇGXCo›øvíÛÛÛ×·,µ†B¡psssss«´gAA]@@ÀmøøFŒi†´BS¡ á¢*¨4’ÆEé¢äÎIoÊË» ×§Üáæ$AaR(´ZmG…âö…·ÞÑÊèíäƒðj"Õéšžž‰wÝõ{pð—MÉ2ZuZ´h1pàÀ:Mò_`*8]púº>!IŸ¨–ÒéeTPQæ›òž*U‹.š.ZI[ßBÕ F£.)iIfæžÜÜ“’”¥Ñ(@_ßB š &ƒTX¨±·ïjoêí=ÃÆ¦Îc¥…2z›ðõ­o %‘$S(F3ùùù×®]srròªì¾G’$…BQGß„éš>vîŠClŽô×^wR¤)$‘ [P7˜0¡È19§|" {þœÝ¿¿vP+u+‰&uŸ™›{":z*÷ò2jµhµ8Bn}Ë%h²ètûÓÓ÷Ÿ?¿Ú×÷w÷'êt9¡Œ M„ëׯÿôÓO–þ@NNNÕ«4U†£ùG/ìïm»©½Íq•TTG 2@3éF3ÅõùˆÂ³ûr“múô×öo*÷Ƥ¤¯ããßôöÎñöæ¦[È&¥m   ..dd$ÆÆ>›•õ[@À%©®ªÃeT h" †Š“ØëtºÕ«W«Tªªä"­WŠ.Gîíð_we‚$öå·%ú6Ǽ”×vææDzt° ®o‰jîX|ü̶mó­æ±êIÂÅ{ûÂÈÈU A-Zü³Žj¸Û”W¯²e ±±µœiÓhÞww.´¾nf&O¥’´4*Ì“SšŒ Úµ£{wy„±cIN¦eK\\ähý ,ß¹¤$ÂÃiޜӧQ©ªwj©T $%ѹsEÝúôÁߟ­[‰‰¡Y³jÌ/hŒéõz•µû6“ÉžŸŸïìì|„1™8uŠ­[qr*ñ3š”ÄÂ…¤¥1j=zX¨×³m©©@d$ýúÂÞ½ØÛÓ§yy¬_ÏСxy¡Õ¢ÕZöL ¶oçâEbcY¾77†'0ädÖ®E¡àæä8z=kÖЩb42r$DG³ctïÎÀìÛ‡ }ûÊCòòX¾œgž±ò›pß}4kÆêÕ<ÿ|­CàfŒF~ûðp€  †0™Ø¾hÓ¦"K^V›6áì̵kxx0v¬lÜÙ»†ë×IJ"0#(,dËââpw硇(ÎY¼g¼ôÀån –%1‘={pv&&°³ãüy’’d§¸ èÝ›-¢¢8tÆŒ¡MJåüHIaãF èÔ©D{L ;wRXHË– nÝ3íÔ).]Âh$9™nÝè×I¢°]»ˆŠÂÑ#qu寿8y’Ë—Y³†cÇ %4Tï·ß0¹ë.ºu“ç,*"9w÷¿ YYääàéi± EEñûï ôï/_µsseÂà`‹ÕsÛ6¢£ñó³L¾y3ÿÍõë,[†‹ < +«èõ¨ÕôêUñÿ¤áÒÐ-£&Õ5q"ï¿Ï#ðÄ•X]]éÛ—±c5Šƒ‘$Þ{_å cÀ®\©Æº;vÂĉ<ù$Í›ˆ$1b³f1~< XN½ž—_&,Œ·ßfÆ <=­Ì––Æ‹/òôÓDEñÊ+Lž,›Z]\<˜çŸgäH6n¬Hµ{û*Yø“ÉäæææééiÕ2š––cooߪU«Û ÌÉ“Œ‹NG\ß|ciÿþ{ââÈÊbüx놇¢"-bãFÖ¬aæLΜáÝw~ø­[t:>ü˜r¢9 ŠŠ0™Ðëå'€ÉD~>ß~kÙ  y÷]&MâÔ)Žeß>23yàNœ ;›ñãÙ· øüsËÓ§ùüsëŽ1J%ï¼Ã§ŸZ¶>‚Ú¥ €O?%'•Š7ÞàÇV¬àÅñð௿ؾ½Ü±))L™ÂÒ¥˜L|öo½%Ÿ?üÀŠ”š IDATC±jl܈ÑȬY|ú)’Ä×_óò˲»ËܹL›FQ©©üþ{5d¾z•_äóÏ1˜77ßD¯çàA~úIîðå—–´ƒŒÉÄ¥K„…•›¸ÐhD¯gÕ*öï·4ž?ϨQœ;‡BÁ®]åæLÜ·'ŸäèQâãyöY¢£,à_ÿÂdâ»ïxî9òò,¿!æ'æ#pè£GÍ<ù$gÏÊsšï–K9,^Ì!–ߨcÇxðA.]âÆ žx‚S§0™øàæÍÃÍ•+-¿„11|ò‰e*ó- ×£×S±IòöøÔ ×2ªÓqîEE5 ¨Ÿ6{ïE§ÃË‹¼<Š“´ \Úš(IÌ›Ç?ÿI|<Ý»³kW¯¢×ãë+«‰ÎÎ,]J¥×ñ±c !;†Ö­eKÌôéÜuyytêDz:ÎÎØÙ±c$%áêJ@+WâïÏk¯ak‹ZMHŽŽ¼ð‚åò¦VË›øJ%ï½Ç+¯@ÅEÈ L&ΣU«:Ü£4'L˜XµŒªÕê   £Ñèææv„ùázödÎ âã-í<Àœ9èõÄÆòý÷C)ÆŽ%%…“'™9“#ªº¨Rɘ1 Ä?òì³´l)·{yñòË=Zº¿$ñ0y2F#?ÿ °d W®ð¿ÿ1cÿùF#óç3bGŽÐ»w¹7·&ð¯±~}%1…AͰµå§ŸˆŠ"1‘Þ½Ù²…ñãY¾œiÓxõUòó+Q /–FŽä“Oä,+ݺ±f ¶¶äç£T²|9?þÈðáôéÃС|þ9vvÌ˲eŒÉ$ãV¥’… 騑®]yôQùÞÒ*“'3k„†²s'O>i¥§'S§–ö.]¶Œ.]øì3ll(,,mL½™ž=ùàÔjvì <V®äÿà±Ç0€‡æòedà@Ö­ãá‡-»"ß|ÃС̙ƒBAz:7ÊŠ„½=ýû—Þx  o_‹QyéRæã‘$23Y·¶mã?ÿaÔ(† ã䞣GãïO±#•ZÍ„ ³v-Ï=WѵÞd"&†~°XU# WýóO>ûŒgž©‰eT¥²î*êâbE'Óhðöææ¬Â®®¥ÝCU*:t°¼ÌÌäÂ…‚‚ðð@£)Ñ­xþ~ýäçæUŠÅó÷—Û•J¹¥x'Ñ,@y"66xzZ·§ÞL³fLÊO?qý:o¼QIgA£Æ&_Þ»NNN<ð€Ñh¬»ªô7sõ*ݺ¡T¢Tâç'§3Ú·—Û´©¨ƒB³3’„­mÚõml4I’Eºr…-äµÐP6l 8ƒ£Gù÷¿ÉÈ *Š»ï.w6•ŠW_åã™0¡¢Ë¡@P3ââ=ooüüˆŽF’0IH] ÕjËÝ—U¼¼äËM@ùùÄÄг§¼_gkKl,¹¹²BHQ×®áèHNƒHRE!³@»v¤¥Ñ¢þ‰“€‡>>­[“Ÿ_‘ïc‡ò)P:Ü¢b®\aÀY°ŠÅ3[‚¥’œÒÒÈÌÄœsÙϵºÜøŠË—‰ŽæÀŽ”Ûýýùî»Ò-ãÆñÐCrcQ—/ÉÁƒ¹¹Œ!¯b6~9;sëžS……,XÀš5¼òÊ­NU4\etèP ÂÖ¶†©Fë”ØX,(Ñò òéÚ P(xôQÆ9“(ŠºÈèd''9®Èd*±kfvž6™ÈȨž©¾Ø%Ëh¬¶m¦nÖÌ=<äP ³™ÁεšnÝøòKžzŠ}ûHOgæÌŠf{ê)æÎeófÆŽ­5 3Û·ãïÏ?¢ÑðÁüõ—œ"&!AîPqI¿”t:ìíIOÇd’7Ù ÄåÕË I’Ï‚ÔTŒFš5ÃÁI"2²JΈfl…BöørsÉÍÅÅ…Œ ù&00™0IJ²ŒMûÿ Å7nXŒAMå±;..ÄÄ`2Uû2gg‡F#ß*gdPTT®.ëàÀ´i¼ð‚ü²¸[^çÏÓ¶m …21‘¤$‚ƒ±µE¥¢Y3ž~š×^“ßU«IL¤°P^W¯¯¤0¸RYQô¶†>¢_?Þ{ü£’Î –†«ŒªT•ÿꋎùþû- VT󽦠ÉsåÊ•cÇŽw.×–’’bkkëp‹[?ôÓ§³u+ [·ÊÁÀúõrà®]Ì›W ÛµãçŸ9y’_~)Q{Ì×—µkÙ³Ú´ÿwMY±‚!ChÓ¢¢HN&#ƒÈHŽ‘#ËÒ¿?o¿ÍêÕøù±no¿RIß¾|ø!¿ÿNDtï^‘vvLʼy„…5Ä[hA£ÆÓ“èhÂÉçÛoiß•а0.¤kWΜ±82ZÅ`à£7Ž :Ô¢,ÞŒFÃðá,X€ZÍÒ¥ €‡j5ãÆñÎ;Ì+—ô=ºÜUÊžY|þ9“&±p!Ý»ãâ‚»;ÇsègÎkéùÝwtéÂ¥K\»ÆàÁrc»v¬_OË–´m‹§'W®œLj*±±>L@^^L˜ÀŒ¬_O§N;ÆT5`×ÍÐP/–}7ÝÜðõ•ßrrbõj iÑ‚‰ùôSºuÃÓ“¿ÿfÀ¹&â•+„…±zu SÔŠ,_Îöí!I<òï½Gh(>>œ8A¯^´oO,X€kÖÈ÷í:gÏ…NÇáÃØÙÉû¢¨Õ¬[Gh(íÛËöæ²ØÚÒ¥KE0>â'³&˜sˆÞü×Aý’ššzñâÅëe<ÿ ÃÎ;¿þúë«W¯Þ6aî½—×_gÅ Ö®eÊy'±C~˜Ÿ~⇘9“‘#­ T*éÓ‡–-ñ÷§{w´Zî½àÑG â7ÈÏgüx‹UõÁ™4‰•+Ù¶Mnqtdñbâãùê+®\ÁhdË.ÄÁãÇY°@N¯¡T2x07×¶ æûïÙ²…E‹xúižx`øpÂÂèÕ‹É“yþùÊ‹™½ðW¯²cGÍ@`•áÃ3†¹sY·Ž3¸ë.$‰W_eÐ æÎeÿ~¦O¯(ÔºE xùe Y¾\6"víJûö%º}ñZ-óæ‘—Ç_È'_}Å]wñé§|ùe%f¼²xz’—ÇÌ™±p!Z-Ç3|8³gsù2S¦Èúkß¾ Î’%lßÎüù–ò×o¼A›6,Y"GîÞÍ_ÈN5_|!‡þ ÆÜ¹lÚćrþ|¹×âÀ@‹qwà@||P(øøc‚‚˜7ôt–,±Œ?û †ÿþ—Çy„·ßfåJæÎåÄ ‹}ÇÁKoòп¿ÅgtÌfÏæÇ™;—ãÇqpÀƆ?ÄÙ™¹sÉÏçÉ'å”;_|ÁÖ­tìÈ_°j•<ÜLJ?äÂ/.Æ®fÏZÜ8ºÝüþûï¦r8räˆN§+Û¾oß>µZZPPPÞØ›)(ˆ=}ÚÉ &âÑœ>í§×g—ýº.Z´˜:ujU¾Û ‡Ý»wÏž={ß¾}¥Ú“’’>ùä“ùóç§§§7æåå8q"77×êT§OŸNMM-ÛîîîÞ¶mÛ7n”}÷_Ó+>ÂF#ZÛÍ¡……`4–û¯1G°šCYF -í:……¥‡ÉK”ú›w‹Š((°<Ì&“•yÌ7‹W,@qŒm¥… ùôÓŠ> xܶÇñ¼{öéö•wÊDGG{zz¶jÕ*11ñævNwäÈ‘ εSTTtôèQs¥43™™™¾¾¾ŽŽŽ±±±eû§¥­·|ƒ‚ù)þ67šÛ­‡Ë— D¯';ÛrB™Lr^íRÍçK©o»ùt.(¨Þñ?tˆ¶m¹qƒœœëêõètò¯ùL),”Oí²g¥ù¬ø\6ýÿ™[šQüCT¼\q{ÙÏ[Üíæ ÍKܼ¨ù°”:ì7® Ä3¯k–Êh´aóãæÃUÞB¥IItèÀ„ ?^'g“ùqý:W¯Î(û]ÕëõãÇW*•kÖ¬)û®Á`({m*æðáÃyyy uw¹öøøc†­$SiÃ'=Ï?ç¹çä}„ãÇÙ³‡·Þº­2¤¦’–†›©©ò–¨UŒFΞ¥m[Σk×J<ʵEQQPv/>22277·uëÖ·'Ãh1ecÌfÅbãbj*o¾)W33x0Ó¦Y<^ÌŽâ` b¿²–«N2Å«—çBc5̨T£$É- EUw?^x£Qxi jŸ›«úon4™:UöÌ6Ì TâíRI©Ÿ«§†ÕÆJC—¬bcƒ··œaðf”JK ‘™â³ÌêÒ7ÿ”G¥Qƒ7okÜÜÙ¿X•9Ë.aõ°X°ìزÝ*8ÂU9þlßΩS•Wçi˜4}eôÐ¡Ò rkÆ´iñꫵ0U 0gî˜8Q~i¾3®-dútþþ»’n{÷²iaalØ g¹+OÔ)SX¹’‘#9qÂâ…#¨Sî¹çžÐÐPíÍÏx{{wëÖMj`ú‘£#Ï?_âk\ivˆFA×6 N‘$žy¦D¾Ió¨¯o­”ˆ¬6]º°ys¹nŽ‚ÚE’är唦 ŒFDpù2F#mÛÒ¦l“8s†'hÓ¦¥-)‰K—pwçòe´Zîº [[ââ8{I¢gOÜݹqƒ#G8ž¬,¶nÅÃ޽ÉÌäâEzô@­&<I’Ý\ΜA©$7—¤$|} æða¼¼¸rI¢Où×!= hÑ‚ °±¡OHHÐ{ôW 8|¸DU½ž£GIM•}éŠ1Ë Ó‘€§'¡¡˜L„‡sù2Î΄†ÊñÈæ-›ðp Ú·Ç×—C‡8xØX¶nE¥¢OŸr½¿õzòóå¿`2‘—‡ÑHn®È·ûÐh4kå‚‚‚š& ØØ4âb!AD’¬6+c¿Í¨Tõ³® 1Òè•ÑädfΤU+”JÞ}—/¾`Ð 6làwè×5k8p€_,wøÑ£¼ð͛Ӳ%:ÿý/ׯóÒKôìIn®ìGœ’®]$&RPÀ®]´oOïÞ\¹ÂìÙ¬Y#—T©˜=`Ñ"ÄÉ wwœœøê+^Ž{î‘k‹}ù%@d$?LëÖ4kFn.Ÿ|‚ÑÈÓOÓ½;Ÿ|Â?àáÁ{ï±s'}ú°h‘¼ùb0pì¿ý†JÅúõ–²z5»wc2áãCQ[¶ðõ×|ó N@K–¬[Çpï½äå±w/~ÈÁƒ;F~>»vÉyRËSFµZ\]å¿ Ixy¡Vãã#LD ‚Û“[T ‚šÑè•QwwV­"+‹ÄD²²øá9ºpÊfÎ$.Žþý+n4’—ÇW_ѽ;……ØÙñ꫌Éûï£×Æo¿1a ð裴oo) aº©…Á`qÓëqvfýzœe/æ¢"^|‘©SÙ½›·ß&'L&rsù׿è×½•Š'ŸdäHþýoôzžx‚;4ˆY´ˆ{îaçNž}@£áå— àÛoK|³gô¦M¸º’ŸOb" 2w.#F˸qDFâéÉüù¼ü2O?-Û/µZÞz‹}û8v¬tæÔ²Œɽ÷bcÃ!uÓjÙ¸GGŽ©jŠ Á-¢×ë###Õjµ¿¿¿Íÿû%$$xzz–Ý»c0pòdå>åqq¤¦Êi…£c‰z1Åœ8Aç΢úƒ 4úŒDׯ3i&ðñÇœ;GVii$&Ò¹3 ¾¾´n]É mÛŒFƒ£#™™DD°~=ƒ3t(gÎȉ`ªEÿþxyakkñ•iÛIÂÇ­ÖâÐ@¿~ØÚâà@n.QQlÚ$¯û×_\¸@F´k‡$ѦMåûƒѼ9 ÎΤ¦rù2ï½ÇÀLœHl,ׯ£Ó‘”DH …göJ1"óß $š5C©ÄÕUd¼ºMètºÝ»wïØ±#ï¦DsIIIkÖ¬Y³fM~­˜n0°c/ÞÒ$yyÜ%}ÌÅ—-»¥…‚†FB›7cª°âyÌšÅÆÖß;¶Dl¢@P)Þ2º~=*›7ãèÈGqé’\:Å|Q6*?%nŽ“µµÅƆ×_·xdV x™Ð%¢üÊ‹ø“¤Ê™%]™ZFÃÔ©–ä‹ööÄÄò1Ñë+ù 7g;Óhðô䫯äø!IÂÕ•ôt4šJ<>«‹ÉDJ 66Â7¨>Ñëõz½^£ÑÜ\céÂ… ¹¹¹¶M´ì^ÏÂ…<ð€•¼Õ¢¼€fŒFvì`Æ ¦L¹¥U‚†Fx8Ÿ~ʨQ5ô§zÿýr÷¾tºšë¸‚;“Fo¹2דÕë9ž5klm¹ë.¹°Á/¿påJ5f³³cäH6lSû>,×Füü¸pˆ¹:™¹®ÚÉ“DFòûï·ú)9’uëÐéP*9wŽœZ´ÀÛ›uëHJâûïe­:?ŸøxRS-O¬âåE›6lÚ„ZMA¢ÑЬ]º°t)ÿÇÞ}‡7U¶ÿž“Ý$MÓ¦{è –BËZö”¡P6È.[†"‚( ¢¢"*äÙ  ²÷^e´´¥{ï4;'¿?’_[JÚ2;ŸÏõ^×Ûœ>9çI-Íç<÷}ge!%'N˜;8@«Å©SHK{á$}• C‡âë¯_áůL­VkµZ.—[Òž^©TÆÅűÙlÿWŒÔªN‡={У:wÆ_ ¨ ¦M3õ<ËËÈ8rG¢sg\¼ˆo¿Ex¸iÿŒ^½{ѳ':u§Ÿš>w­Z…9sг':t(]ݼx]º (‹W1c?‰æÒâvaL™‚?D·nèÜgΘŽïÚ…N†™3MŸ¾†ǬY¸w: <Üô—?- ãÇ£S'ôêUY}•;wй3&M2µ\7ºq}û"0sç>•ÑOϣΣpsÃûïcáBôîmªk°d ØlŒ…mÛЦMe¥%,-ѨÑS –sæÀÛ&àý÷±m[ézäèÑàr1k–)ðòòBDæÎŬYð÷‡££i˜‹Ké×X,4nlZ^åóáímZ7µ°€Oé0ŠÂÔ©hÖ S¦`ÄlÝ µ66øüsœ<‰#‹°0ðù¸q£FaófäåaÔ(|ÿ½é ŽŽ°·êu­Z…„ †ÈHœ?ošÀ·ß‚ÃÁ°a=7n˜{x`út|ÿ=&N|±ØÝ8s;;²7´†YYYuíÚµuëÖ%FY,V‹-š7oîXö×±.8wóçcî\¬[‡+W°}; €¥Kqþ<>û Ú·Góæøüsøú¢_?,]ŠaÃàòeÌ›‡9s°nnݯ¿@l,ŽÅŠøè#|ö —‡qãЧzª(c%Jú©D-wû6’“±aÂÂðù県 0q"6nÄ?ÿ`Ø9&ÀË K—béR°XÐë1lX,lÝŠþýYa¿%Ó™SSMG4LŠ&Mp䈩?A¼:›ÞÖk×B¥‹.×;º¹aÓ&¨Tàp`0T¶¤Ñ®Z¶|êF&ÊP(LO,¹Ãéë‹¡V›r•8|ò ¦M‡§4é㟠mE"lÜh:‰‡~úÉt­&MLéí%¤R,[fº»Áç›æÜµ«)Éǃ^nnO%Ñ—l ˆŒ,_g;0[¶@¥E•ÖvuÅš5P*AQ¥½ù||ü±© E¹êÄUâñ°~}eµˆ‰j`aaòtM.—¢×ëky*½J…  VÃÂÂÔßyß>xyA­FL ¼¼pâ&NDûö˜5 ƒÁÞÀÂh×ÖÖhÔáá`0`ϸ¸@£ÁãÇðóÑ#˜4 ºwGP¼¼`i‰‚ÄÆ"9‘‘0y2þø£Âé=|ˆ‘–†ààjùqÄ+£(Œ ww¼û.~ÿ.\€³3 E!2`Æ ´h¢"Ó¿#ã‰û÷qá&LÀ½{pp@l,RSááaæ––h×î©­YâáCìßDF–ϯ%ˆ*Õ‡ ‚Ç+ 7Kº”=X\Œ~@^^éS0|8S(Y›m~1µÜ`6ÛL‘£r‰ËUš'Äb•†zfó‡X¬ò×-GUT1Îì¶À²?„\®™^4  üäŸGÙHÔ6µ<P\ŒmÛ—´o†AVòóqèèõ¦Z¤4ÐP E T´ÔË0ÈÌ46>lÕÊô­’Î Æl¹¹¦"e¨ªÒ¾Jƒ……dQ—ß§Œe[Èå°±1ýòÛÚB.‡Á`¦IXNx<œ=kZO8ðÒáårXZšþM‰Å$u•xaõ!­‹wwØØ”©k·. ¢2r¹\¯× ãmúœœœ‚‚n­oÆjm5kJßiÐé°z5h cÊLKÃìÙøðC9‚Õ«1{6ðÿ}°X@Q~þxºøZ¹·F??äæ"!îî¸}»²é£Iœ;‡7àéù_7ATWWýÎÎøätíŠ1cŒNÀå"<?þˆÇѲ%† ÁèÑ8p#G" ·n¡GŒcæ¢>>èÒ£F¡[7ìÝ[Å il6IÈ ê°öíáîŽAƒÐ²%¶oÇîݦ`4(5Ê´ÔÑ|€‘#¬,ܾ¿þ2¿Éíï¿qñ"?†FƒÌLôê…6m ðî»8vŒ£Ä kÁ(AÔoJ¥R¡PXXX(,,|òä MÓ...5=¯—áá?ÿÄÿA£A` Ú·‡Fƒ.]о=x<¼ý6Ö­+Ý£663ÆÌ†.#xyá£L%PV®ÄHJÂW_!.Ž´¤'^LýFssaaa~Kå«S( T>µà52“‘èMMž¨7ŒeíõDSSSóóóÝÜÜì*ßY[Q1bÄS‡5}AÓèÔ©ô¸@€°0„…•>×ÖÖ´¼DëÖ¦/8 `úÚÊÊÔÒ 0mK­Mcøp|þ9®^ÅÎ/ür¢:QTi±j±¸ô– ­-¦N53ÞÇ空.<:vDÇŽ¦‡ rržÚ0-‘@(DëÖ¥ÿ¬J…¥ÿôÞ~û_ÑàÔÿ`tæLŒnÝÞÈÉÿøT}§ïþ}XZâEªŠ‹1z4¦MC/9½ÇAQU÷ "ê:KKK///©T ÀÁÁ¡cÇŽR©”Cšñ½&}ú mÛšžAT»GðÑG¥Û²L›†~ýjnBDýUÿƒQcSÍ7¤E 3 õÏúå4k†qã^ìärs_iòÛ·ƒÃÁüù/¢NèÔ©Ã0l6€••UXX˜¤¿>õ¦î~Dmæï;ž:B îoHFÕjlÚ„Ë—Á0xûmŒ EEX»/ÂÇ•=ýÊlÚ…R)>ùðè6l@F¬¬0>œœ —ãûï„Ç¡Raôh´l‰¥K‘œŒ€€ÒÛ"ûö!>ÉÉÈËCÛ¶1IIXº—/ãÖ-œ:…F°h‘ù™$%aÃÄǃÃÁ{ïáwLÇÿý;w‚ÍÆøñ¦BŒ×¯cÃ( Ř1¦Šú»vA«E|<¢£€wÞÁ7ßàömp¹¸˜7ïuü¸‰Z‰Åb•«âD=[¸… âE°ÙOu™&ˆ7§ÎWS(“ƒáÃ1z4víÂo¿ÀŠøóODFB$½{>7;Ó§£qcLž __SÁüädŒ'ÂÃÃÔIB­ÆÞ½XºþþF^Øl„†‚ÃÁñã¥'¼yß|ôí‹ï¿Ç_A"Ax8M¥¹+)˜£F¡S',ZTÚéÒ% Ž·Þ”)ˆEBÆŽ…£#ú÷ǦMضÍ4ìÖ-,X€ìl„…A§ƒµ5ÂÃáîww„‡ã­·^ågLÔ ÃÜ»w/%%…a˜šž AA<¯:¿2je…¾}qû6àìYŒ‹ðñÇèÑíÚ•¿ËP–Á…j5ø|Œcºqæ X,|ô¬¬žÚ(¦×cþ|¼÷( 𯀦j…eµm‹É“AÓ¸~{ö`ÈL˜€k×Rš0a–1Ãñþ}$'C.Gl,|}`âDôî°08€³g!•B¥Â¬Y°´DTöíÃäɦ34mjêöiœÞ„ HL—[Åu‰º.--í¿ÿþsqq øçŸ8ÎÈ‘#¥ iAC.ÇÚµ˜3ÇôðÂ$%aðà7r­'Lý¾;v4Ý© ˆj Ñ૯àïÞ½Ÿ«;Ƀø÷_S&‚¨ýêüÊè¹s6 .ÀÒÐ韹¶¶ ÁÙ¹ÂçÊdXº—.aÌ´kgZC}ò66¦f„S;d IDATëÆjF |}KKsWD*‹e*óœm¯Ö­ÃŒˆ‡ƒ,,JwkÖˆÅÉ“ƒ´4ðx¦ªHO/=ƒq¥¶òéõ\.MKKKNN–Ëåvvv– ¬ªŠ\Žo¿-}‹Ÿpú4.|=׋áä„k×púôë9!A<Š‚TŠ%KL>+Ç09QQ¦72‚¨ýêüÊè¹shÖ ?ÿ  ÷ÖÖ°´DJ ÈåHN®ð¹…~ýн;rs1iþýðôÄ '§|ÊM›éŸö¬ÌLhµàpcÚjT¶©YÇcÆ Œ‚lÞ\ZM#) ž{{XYA©D^¤RÄÆ>•¡o6yºl"$Q/ ±XüðáCƒÁàëë[û»€¾„ÂBÓŽêFL¿ê ƒGPPPº­aöíMF ÈÊÂãǸv ii iÓ§»gétÈË3}ˆ-**ís›ŸÈ˃£#Z´@‹•ýU!ˆ7ÃÁôéHHÀ­[U6pû6þù‡$ÞuFFýýñÛoؾ øûo´kšÆ¨Qøùgp8¸|¹ümô²bbðí·hÝ,ââ0z4tìˆ5kðñÇx÷]œ:…ѣѤ‰™ç¦¥á¿ÿpéÒÓ±m||Lu×.]ÂW_A*ÅÁƒX¹Ò48 ›7C(D£FèÞÝüd5ÂÎàñð߸¿ôø?B À½{P©Ð±£©ý¢E ¶m¥e‡ÍòòÂwßÁÊ o½UúöLÔ3F ˆD¢fÍš¹¸¸x×ÇR^QQ˜0ÖÖP«á鉵kÁ0X¾ü77Ó'O fÎÄ£GƦM TbÖ,  |÷©Óî³d2„„ !4åËMa¢ƒ¶mÃàÖ-X[›VJŒmúÚH¡@L \\˜SJ;€Þ½¡ÕâÖ-¬XQše?f œœoZæ4kþ|ìÚ…‡ѪBC.cÇ‚ÇÃåËàp°e œa0à·ß°u+._ÆâÅ¥E¼;w6Ó-cÐ ˆDˆ-}·&êŸÀÀ@‡#œ+Ù•Rg©Tøì3„…™âÂ!Cpé’©©ý¾} Â/¿˜>ø …øùgüôSiþŸ@€Ÿ~ÂؽÛ¶UvsC«-ÝWSTTÚä)7QQ8xB! ßÜ«$ˆªyxàèQèõ¨üæÇ“'6O"ˆÚ©Î£<† 1s02‘‘UuÄ¢|•Poo|þ¹™ç:;ã‹/Ê´´,í„Q™ÌL‡Œñã`äÈÒ#…€¬XQ~d—.fÎ)V}]¢®ãñx<³ ¤ë ¹·n¡ |ƒééxôÈ´®U+Ð4zö4£Æ}ueK!…àp^~¡("nnÈRQúvÅÂ… ÅÖ­ 23À`À²eøåôï_í“#ˆWPçƒÑç‘—‡‰ŸÊõ òe¯ÿBÏsƒôÞ=L™òÔ‘™3Éâ•äää<~üØÇÇǦž†K<úô1Õ—:Mš”®}¾väòÒ}¨3Ã4š75‚¨È;ðñÁ¦M¾×PƇ‡éuBÔ1 "•HðãO¥ò¼¡nïåj›Õ¸qùjSÉ™ ѨTªÛ·o'%%EEEµhÑ¢WÉÖzD$B@1q"ØlÜ¿pâ:vľ}UœËEr²™¬Ä²df"'…S§žºÁ~æÏ¤»;ví‚Rù\Evâu¹qÁÁ ¬lŒƒƨQÕ5'‚xD0JÓO%¶¿9ÏÓ œË­¬ÚA¼¹\~îܹ¢¢"š¦}||jz:oŸÅ‹1ozõ‡šÆªUðò‚˜1B!,-agÇŽaéRäåA©Dûö8Ó¦@x8œœÐ¯$üý·ù«¸¹!<;ÂÁvv MÇ­¬Ì|víÛ»w£W/tíŠO>yC¯› ÊÓjŸ«¨‹±ºŸ\nªAµ_ƒF ¢¾R«Õ€T*utt¬éé¼)Mš`Ç€…¤RP&NDŸ>Ðh “A©€¶mŸªÂXòNlm;«H?âr±y322`a S‚McÉ3Á¨­-öíCa᛺ÇBåèõ8y—.=מ.Š‚£#Ö¯GÏžð÷ó“#ˆWVÁè±c0ТizK¯J©Tj4{{û¶mÛŠêõ2ˆX\Z³ÂˆÍ6å¦|&ci–HdŠMu:> …¢ô[èÐÁü%X[WqB‚¨:vîD›6ÏÕZŒ¦±nþüVV$%ê†F££±k‚ƒñý÷UÔ§ ¢rŽŽŽäóù^^^5=—ºÁX*??¿ôˆJUs³!ˆçÃãaãÆÿÎ;xç76‚xÝj :žžøòK(•di ^‰P( 0æòχ˭¢UAQÍjfÏhEw¾‚x!ׯ_§(Êßß_@òº ‚ ˆº©f‚QšFq1)ÔG¯D¥R]¹r%''ÇÎÎÎÅÅ¥¦§CA/ƒ®‘«úú‚ÍFÿþ8r¤F®OõAjjjnn.EQìg+aÖS >øgΘù–R‰ÈHtè€V­pëVç1˜hJÏÒÒÐ¥ Ú·G·nOU8&‚ žU3Áhn. 1p`…]ã ‚¨R||¼V«åñxÜÓˆÚ`@r2är3ßâóñùçX³€©ÒS%K–˜j_ [[lÞŒ/¿D|< †7u‚ ˆú¡:ThšÏ0¬²‘32`m÷ß7SH… ^+!PüìQµ4-¦¨šù0öºøúúÞ¸qƒÏçsž§ÝB]¦Õ⯿píüü V›Êå8t pqAŸ>°´„£#Äâò½'/âÒ%°ÙèÛžžHNÆùó¸––P©àà€°0HMÅþý(.Fp0ºu3?ƒG"<B!22pãzö€ÌLDEÁ`ÀÕ«‹1z4ÜÜÈš(AÄs©Ž7c6[FÓve×*´ZÐôsu’ ˆWc>JS(ÀçûSTÝ^P”H$Íš5óóóã×ëÚëÖ­Ã_@&ÃÑ£¸pÔj̘͛ÁåbÇ|þy…Oß½‘‘P«‘œŒÁƒQP€¼<\¿Ž¼<ÄÆâÚ5DG@r2ºwÇ£G`³ññÇøçŸ '3}:23àÎLŸn:~çÄ¢EÈÍÅÑ£ÈÎ~?‚ ˆú­z¶šQÁÅŌ렱±8s)2JÔ˜âbXX4£¨º½ÕR,wéÒ¥¦gñÆbëVÌœ‰1c’‚k×àþ}<ˆƒá鉶m1d/6s§E©ÄO?aôhŒ• ׯãÄ ¼÷¾ü‰‰ˆˆ@D„iäöíJññÇ`±@Qض Ý»¿Ø<µZìÙGG(•h0û&‚ ^ƒjz3‰ZÉå» EaÃû 4 ¯z®Låed€Ín)¶ªé‰¼¼ÄÄÄ+W®¤¦¦º¹¹Õû`”Ã@€¬,ÐéL-æ!bÍSäGÓÉJŸÂ0¦/X,H$˜9ÓÔð€¥¥é ƒ¡tû)MÃÑ¡¡XµÊt¤’?P4œxz–O“2{«§d&ADEª)ƒÇórrú,1‘£Ñ@ ‘(Qc ddÝܾg±êjöœÁ`ˆŠŠÒëõEEE›6mЉ‰©é½Y––ÇÏ?ãÊlÚ„øxxë-4j„õë‘’‚»wñÛo iàráæ†­[qþz=23‘™)•ɦ98Ì©© »¯…@ 4hPVVÖ±cÇX,–……EMÏèstÄêÕÆ´3”ÄÞaõjS¶PÙ­ žžøòËÒ‡b1fÎÄÔ©ÐëŸÚ§î₯¿.}HQèÙÝ»C¡€HTÙdZ´Àž=ÐëŸÚ„  3ƒ»tAÈ1#‚x%պیñ÷ðX—×%9y~VVœP¡<I«'Þ­V§VC.Gq1hº¥—×·"ÑÛU·áhš–J¥¶¶¶\.·~×u*AQfbDŠÂs†âNùú£fÑ´é*¾ÿçΕ~‹Åž=¦¯I²½Z+Ö»¡¶mûòEL—.E»v°²ªbX^._Æ–- }É AT‚£Qg°Ùl;;;ã×*• €D"©Ñ½*š†½}Õ±Ôš5xüOž ;Ç#2nÜÀâÅP( “áóÏáí•+qñ"1iÄbÌž-—‡•+qù2h£GcèPxø‹¡° ƒY³Ð³§ùënߎ¨(Ü¿œ¼û.fÏ€›7±hÔjˆDX±á§Ÿpæ   ŠÂ”)èÐøá\¼†ÁС=…ØXÌ›‡¢"èt?Þ4™g©ÕXº/‚¦Ñ´)–-—‹˜|ý5’’ à³Ïlþ¹r9~ùÇŽ¦ñî»?T*l܈ƒ¡×# Ë—cËœ9ƒŒ |ðD"Œ‡îÝ+üùët akKŠCñF`” ê½^Ï*³×¹sç–-[ÚVÔ)¨îàp”î©Âõå\»†+Wðë¯xò}„þýÁçcöl„„`üx¬Xùó±o @«V¸wS¦ÀÁ^^Ðëñí·¸v +W";|€ÐPxyá»ïШF‚\^ÙuïÞÅ`Çdgcð`Œ‘S§¢ukLš„Õ«1~'bâD´lYá°=77p¹HL„L†{÷°~=7ÆÄ‰è×¹¹ðñLAApq€âb:„^½˜½––¸t ÞÞàóqáš4A@+›^ÏžhÞ:¤Rää@¥ÂÕ«øõW4nŒqã• ¦4$¤´AÔÎx÷]$%€£#Nž„·7„B\½Šà`4iRÙ‹¥i¤¦âÈ´iƒfÍÀfãêUDE!2ÃÞ7o"?ß|0ºcZ¶DZX[ãòe´j…ýû1p ÂÃAQ0&¼çÌã!0>>•ýŽÇÆÉPÇWá ‚¨½H0Ju@zzúÇE"QHHH=k¹Ä0P© B«­l˜± ªñ6±N‡¼< ÀÖ:”J3ÏÒëQT„ØX@h(\]AÓX°6`ëVÄÆ"2sçVxÝ’ ZÆUé¢"0 ll@,à /ŽŽfž˜•…ØXÓ¬‚‚àäÀtÝíÛñø1ÆŒÁ'Ÿ”¯eµno¿Åر¶¶8p……`±pþ¼©ìÀðá.Ufe!#ÿþ ¦Ð³¨öö/y“Ýx!†!÷è ‚xSH0JuÀãÇÕjuÓ¦MKr¹<99Y"‘888PuæÌÁ¯¿bëVÌk¾¦•Fƒþý„#!îîðÁ€¢"S €ÇCÙš þþhÝs怦¡R™"Hoo\¼ˆqãÀá@¡xª s%»Œºw‡Ÿ @AAÕ©NA/áåƒÑ¨¨¨¶mÛÖõ7B‚('33³¦§PžÁ`(,,äóù~~~Æq™™™»wïöññZQ LÝ¡ÕÂÉéÅ"QÖÖ0}„nÝðçŸ?ÞÕñxðò”)Æûï#0³faÁÄǃÅÂÝ»X·¶¶X¸EEÀÁƒ•%î<‹ÇÃøñ˜9b×.̘Qº´Ùµ+FŽDóæ2-[báBL›†¸8…8{7ÂË 3g‚¦ˆ¿þBûönW=së×#$))xë-¸¸ÀÒC†`Ü8ôì‰ìläçcíZÓmúþýñå—8}ï¿Ì™ƒ?Df&,-qî–/GH&NÄØ±˜=..¸«V™ÂÊ–-1c‚ƒ1hÚ´©ðUóù`±ª»pA ÇË£ÅÅÅ×®]{S!Â,Š¢zôèѦM©TjÞü­ê²&N„@b1¾û>>àp°t)þùOž`Étíj)`Ó&\»¹R)( }úÀÓ/B¥Â¼yÉÀbaüx?¥óç£]» ¯;t¨)^d±ðý÷°³EaÙ2üó>Ä’%èÖ­tð–-¸qyyÉ [7ìÞK— P`Ñ"8;ÀŒ8˜?mÛVøÂ[·FAâãѺ5>ýÔ8~ñÎÃíÛ°³Cx8J6kŒ‡Ö­oÚ<Ð¥ vìÀ¥K(*‚ð÷€æÍ±oΜAf&F.­{õã¸u ÙÙ¨<ŽÃ\ޏ8ØÚ–®ÈA¼./Œ6oÞüüùóò1™¨¿J*(Õ<¯ì” ëx\ Ñ`Å \¸€Q£ªY’ëÃã¡W/Ó×R)† 13ØÎ®t šFP‚‚žÓ¤ š4©z†%Ï2¦Ÿ …èßßÌ`[Ûò‹¬ÁÁå 0•;¢T")é©GggˆDæ_Ÿ.]Ð¥KùãBCK+€R”ùWçí oïòe23'|–TŠAƒ°d FŽÄرU'‚x!/ŒŠÅâ-Z¼ö©ñ,†aÐO¯¡yxxtèÐÁµdbÝÄåbæLÌœiZÒk€âã±páS©HŒÖ­knB (,X€ ÌçïA¼"’ÀDµZBBÂÙ³gƒ‚‚š6mZrSÞÍÍÍ­òÊuE¡–-@W7__lÙòÔÊh­öØlSA‚ ˆ×Ž£Q«Ý¿?..ÎÙÙ¹No%Ìb±`iYÓ“ ‚¨iU%Qs E||<—Ëõ7æ¡ôz}^^ž\.'û¶ ‚ ˆz€¬ŒDí%—Ëy<ž³³³M™m•{öìáóùu=‡éua ìÜbÏüb¹wÂM®ªó]R‰²Ø´F,HµÅÙˆK,’ÄüôªŸCDÝA‚Q‚¨½ìì솮ÑhxÆDµZŸŸ/•J˶ªoÈ ®×âÇ%çµÓAÆárÙ‹Gþ²Õ+ Ú„ £SZ°šºokäp”M«kz^A¼äO6AÔjOgµ¨T*F#¸f»÷4$+.«ý•Ø)jø ¥–,6 ;kë'.ÀÀ0j•õÅX—Ô¼f¡ž›$I5=/‚ ^²g” j)•Je¬ëT‡Ãquuuqq¡«,_ÏQ±™N?\là7K­Yl‰Dë=Цùbk礢'î¦ÔX×ôŒ‚x ø›AÔRƒáرc;wîÌÎÎ.÷-—÷ß?,,¬F&V{*¯ÄMâ‹øBRj Aa±Ùb‰4OÝüVÂpÆ@6«DG‚Q‚¨ bbb’““Í~—¦ivE}Í=ù?^ƒÆ| AMÏ…¨M‹,­eôOÉ ­z4Aµ F ¢6JHHËåNNNVÆÆäÄÓŠTq™=„+rk¾Ábs¹,¾ãýä÷jz"A¼*ŒDm¤R©¤R©¿¿¹PƒÁð×_íÞ½ÛØž¾ÁÊ,lB±-H=ŽËãç+Ÿ/•JŸ]4m8ô G¡‘Ñl6 0ó?s†IxøàþµK[W|‘ú$î%.Ê0ÌŽU_¿Ò¼Ÿ–ýàü‘¿^º§ë…#£>{¼¸¨`÷Ï+•ŠâW›]ícî¿5 `‘„z‚¨ëîâ AÔNÙÙÙpuuíܹó³eí­­­‡j0r0 À``1®þÿW@µunF:EQO`ê (*,ÊÏJ$"K ›Ã‰˜2S¥P<ºu½Ü©´u~v6MSÖvÔÿ—nÕëtùÙY:­ÖJfËÔJ…Z©Ü¿~uŸ1„BËüO…¼ˆËãåef°8\k;{Ól&'#]¯ÓZÛ;p¸<Å…q÷î\;uì­ÖíØl¶…H Š ”Ë ós-Db±•´¢×ÎèõÊbyïÑ‘åÖwó³2Õ*å þ ëh½Áü/<ÃH” ê<ŒDퟖ–&“ÉÌÞˆg³ÙRi…aJÔ“ž¶ùË…*…€½‹käâsýÔ·¬ãòµjØÌy¾ÍÌÊLIúß7KTÅÅZµ:èíð“>P˜›ó¿o–ægg2 ãäá5îÓ¥ÿìü߽ˆY=†Î˜çîëoö„«>š& •ÅÅ9éÃfÎkÞÉÀ0ÿûviô­l6ÛÒÚfâ_‹,%¿,œ“•œ”Ÿ“õÓü™ÙÄÅ_±9Ü›gOüu=‡ÃU ˜øAp»f/‘žødû+r3Ó#&ÏlÞÉxðÔŸ{Žþþ«P"a±Ø•êÕªAÕ†£Q‹èõú¨¨(¾¾¾ ¾ÁÒóº}þTQ~އ߯3 ò‚|9Ù›—-:s^Ó¶í¯;ò¿¯—,Ûñç³OÔëu;W}m![°´¸0ù¤Q­ºötöôÞ¿á県´éË h:+%‰¢¨öý"B;v»yöäØO¾(©]E“I‰{ܶgßÞ£&ü³óÿîú­Y»n_?}`ï¢Í;Dé×ÓÆþ·w{¿1“F}´èúéã·ÏŸ5o›Ãe±9Eùyë?Ÿ?pÊÌ–{Ü<{rïÚU-Z{`–cëìúþG ×>ßøbäf¤í\õõ°™7mÛþ¯-kÝM?Z‚ ˆê@‚Q‚¨E4Á`puu5;àÑ£Gyyy~~~¤þh ™£sfrâÎÕßø·k úÖÂüܤÇÑɱ1j¥"1桼 _$)ÿÓi´÷®\x«UÛ£Û5 /%.ÆÁÝ#êêÅÞ£&XÛ;ÚÚXËD–V(ûg†žõv¯¾b©uãà›gO€è›×Ý}ýÜùÑ,VHÇ®¯_í3*ÒÎÅUb#ã ö.n4‹àÉèâ‚üԸ؃Iëõ:í“÷´Ù`”ÃåÚ¹¸òø¥ßJzÍæp›‡wYYµéÞûê‰_á›J•¥ IDATÇIQÝH0Jµˆ@ èÛ·oqq±P(4;àÎ;QQQVVV$-تí_ÿtçâÙã{~?±oǢͻôzPliïâf0náR³u  ƒV­¶uvµurÐgÌ$¿@ U«ÙÎKÏÇAÒÔÿo?Õë¸| ã–P‡«Q›¿‡®U«-Ä–¶.®l6À˜ù_” 7«Äáò(š@³Xi@DB‚Q‚¨](ЉD}·°°¢(KKRå»TQA¾[#߀ÐVmº¿³tÂp…¼ÈÙÓÇÀ¼›zøè´š‚œlcV͢ũ£'6n>tÆÜ-Ë?{|ï¶^§SÈ §/_%µ³8eæÚ…}?{‡Ëã “¾øMÓ­ºöüù“Ùb+«Sg»76ŸÀd!7ûÒl¶@(дm¸‹wão¦çYXd§¥Žýt©ñ¿oãà­ZõݬIÖöŽã|áäéÝgÔ„K8yzË ò%6² ‹–›]Ð=°ñ—˜;7cæçd]>vä‘ãüC[vè7pýç»x5JON”ùzpãÊõSÇûOœþf~öA¯ÁË£wîÜ6lXoC4ûöí ©žk]¹råîÝ»:t 4;€Ãá¼óÎ;r¹œ¬Œ–Õ²KOgïÆ¥’/º5ò5nÁ|wÂ´ÐŽÝ r²¹|¾“‡—q$EQ=‡j¦Óhl]\ø5o1wõÆÌ”$FÏȬd¶\}|çý¼%5!N«V—¬ƒR4=éó¯3““ôz]%‹£|ý£q³©§“± –Ð4Íåñg·&!ú!£×;yzYÛ9GZÉllØ–“žÎæ°Yl6€¾c'…vê–›™ÁárÝ=9\ó[ÚtïÝ´mxÉC['Š¢Mû°eçîj•ÒÖÙU§ÑXˆM¿!qQwÂz¿'“_‚ j¯— F•Jebb"MÓ2™¬¢%‚¨ë2335Zm¦ÇÏ› V«år¹ÞÞÞdïQ_ñ_$—ùÕñx|øM_èµ+..Þµk׎; +éêêhkk[=#‚ ˆj@nÓ¥~øá??¿=z<ÿS¸\îÈ‘#;wîlö»,kÈ!›7oÎËË3;À`0|ýõ×-[¶ìرãË̸ŒÖ­[oÛ¶-99ùÏSýsrrž§º~«V­Zµzdj¢úÅ?ˆ…q÷ïòø‚&-Ûð-„Œ^Ÿú$öÉÃûƒÁÃ/ÀÅ»1EQ1wnªÅŒ^/‰ò³²‚ÛuàòùzöÉÃûi ñ6N>M9ÕÕm ¢f‘`´žÓét©©©|>ŸÃádddÈd2™LfüVqqqjj*MÓNNN °°ðòåË& ÀÚÚZ$©Õꤤ$ƒÁàââ"Ê™a˜¤¤$µZmggWöxVVVvv¶X,vqq¡(ÊÅÅ¥ì>H¹\ž’’ÂápÜÝÝY,V~~þ•+W,,,¼½½mll„B¡J¥JJJàææölpVTT”žžÀÑѱ$£¼°°055U"‘”IJJb±X‰$))I(gòÚ~¦¯Û£Gôz½ŸŸ_µµz"Þœ•3#ÅRk¿f-nœù¯Ã»ƒÞ›05?'{ã’nž<¾`×êo§.ûÎ?´ÕgïG¼Ý³Ïµ“LJd&'iÔêvïôÛµzåÍs'›„¶9üÛ¦ÐNÝÞ?•&õA ‚hH0ZÏeggOžŸÏ§(êÇ”J¥%§eæ÷ßß°aƒŸŸ_Ù^\Ç_¾|¹ñü#FŒ>|xÙɤ¤¤LžŸéææÆ0Ltt´OÙip8œwÞy§oß¾ƒ!!!¡Üwp¹Ü6mÚ¯’™™Y® æîÝ»·mÛöÏ?ÿXYY£dãEKö ”­¯Õj/óÕomß¿ÿÖ­[f;$éõz…B¡Ñh†áp8‰äyv(•Ê¢¢"‰Dò<»E³³³ØØ”o˜NÔrl6›Ñëò¢Ô'qçôiiv˜»_‡Ç‹½w»YXGZýäÁ={WwA4ä/]=§ÓérrrÔjuVVVaaaqqqQQÃ0Ý»wÿóÏ?ÓÓÓ?~üßÿõéÓ€µµullìÕ«W¿úê«^½zݼy“ÃáX[[ïØ±#::Z$µlÙ²eË–5òõõuppØ»wo^^Þž={†IMMµ²²jÓ¦ÍÕ«WmmmÕjõÒ¥K-,,²²²ôz}NNEQ]ºt¹té’µµµX,þê«¯ŠŠŠ(Š …±±±'Ožüæ›oz÷î}åÊ¡P(•J×®]kÌU:{öìo¿ýÀ`0°Ùl¡Ph0’’’Œ/§K—.{÷îMOO?þ|^^ž±§J¥:tèP^^Þþýû}}}]\\^åǨV«Ï;wéÒ%†a†),,4®1äääüþûï›7oÞ´iÓ±cÇJbú'N8pàØ±c111ÏvWzðàÁæÍ›O:e0ªœEQ666%ùgDíäÞØŸÃåˆD.Þ>ðvϾ¡hÝgóv®úºéÛá®îàÕ$ˆ¦i'/¡¥¥•­ÌÑYl%öå÷WÿûgígóÖ}6/õI\M¿‚ ˆjBVFë¹ìììÝ»wX¿~½¯¯onnnqqñ7"##ÓÓÓ§NÊ0LçÎß{ï=ýúõ[¼xñãLJÚ³gϨ¨¨éÓ§K$OOÏAƒ•=­µµõêÕ«W¬XqôèQOOO??¿… nÚ´iåÊ•Ÿ~úé½{÷ôzýòå˹\îºuëwîÜ6wîÜyóæM›6¦éAƒïª2dÉ’%W¯^0aB÷îݿ䜿þúk¹ƒ <ï›o¾).. …e¿„ÂÂBã‚(µZ}öìY½^/Ê‘VVVÆ ãp8|>¿ì–Á^½zfdd0 SrÿìÙ³>>>©©©"‘ÈËËëy¦AÓ´l"¬›hš[Y?ÏHЦÅVÒªÇAÔ#$m¸(Šz6Ê,—rn\É«HÙ˜²›Í®äV2EQÖÖåß•ÅbqÙ‡åÚ]““Jš=y¹ƒ‹/Öét .üòË/_})ñâÅ‹e{#ét:77·=zÈd2.—k}îß¿óæM™LÖ­[·çI¥ÏÌ̼xñ¢‡‡GPPP­-˜JA/¡&ƒQ­A¯OÒ%å09é†t9%ž4‚¨š«éÿ)%Å5pm)[[ÚÖžeߘÛXL¿À2$EQQQQ%eJhµÚ'N899™] ­òœ2™,<<<((È`073h4šøúúV´£ 33óæÍ›z½¾¤TAAÔ5Œæès.¨.œcÎÝåÜMà$äÑylšóÌ âåP ø¾cå¬wöÖz·Ñ´i/hïÅñ¢Ÿ¯Ž„››[qq1—Ë¥(ŠÇãq¹\'‹%‰T*-I™ ©©©§¤©UTTÔßÿýðáÃîÝ»›-eJê:½.ƒ¡(?W§ÕZˆÄ¤¿ADmP3Áè̓“ª“Ç9ÇONÐƃV°’C^#ó!ê±"ª(‹ÎŠaǜ㻧¹—ªLm§k×–ß–Kq«|®““S£Füýý¥R©H$B¡ðÕ;Èëõú#GŽäää 2ĸ©ÔÒÒR,?xð °°0""¢lçU#¥RÉårßPÉýåæÙ“¬_Í·v8¼Uמ5=òÒ,D"Kkò©ƒ ˆ¤‚Ñt]ú1ձ͂Íw9w~wD5ÑAw™{9–›[œ+T [ð[P¨bóåÅ‹¿ýöÛÖ­[¿Þ™dfffgg[XX”äry{{<ØØÕlƒ¥·ß~»I“&쩀 aôúÓímÙ¹{‡~kç²è¦eŸ6ëØsÄØšžADõ©î`TcМRž:Ì=L"Q¢FdÓÙXüá"wqa»8±_&éÕÅÄÄ(•Ê€€€²¥š¬ÓéÌîC•H$/±?•(ëÁµË—ŽŽ‹º«*.ÎÍHoѹ{“m sæà"‰Õͳ'r2ÒC;tí14+5ùÏMk órí]Üzš`imsöà©ñ±i ñ¾Í[<¸~¥Ûàoµn§V)Ïÿýçýk—(Šê1̯y ³×MKˆ¿rü¨F­J~íìåóÞ„iO£VÛµ-úÖu._ÐmÈHŸ·‚£œþsoJlŒF¥ÊHNtoìßþÝ4M?¼qõüá? ór[½Ý¡ß@§ÓiÏüµïîÅszηYh÷¡£Ø¤ú,AuYuw`º­¾}WÎòÎ’H”¨)‰¬ÄyÿžQžÑt52ooï·Þz«\^¼H$*¹Ÿœœœ””DRú^#k{ÿV–RWŸÆ-ZÛØ;0 ×NÛ´ìSçV{æåêuºµ‹æªÅ]"†>¾{sÛÊenœ=Q›CQÔ‰};}ƒCvþø €#Û6ù}K»wÞ lÕvÕÜé9Ùf¯›“ž¶kõ·,»Ó€!Ç÷î¸wå€ûvù}Kxß6ŽŽ?Ì™Z”Ÿ'–Úø‡´I¬Ý<Z´vñiLQTbôÃçNwòôîÔð©{.?àÁµËGÿµ}ß]à[X_‚ êºê^ÑÆüÇÿOA)ªùºQÖiÞévêvL «6ç9;;;;;W2 33sÏž=E <ØÑѱ   ..ÎÑÑÑÁÁ¡Ú&YÿØ»ºË/ùËç­f-;÷(ý†mº÷~oÂT㣜ô´ûW/}ð„ƒ›Íb­˜:vòÒo)P-Z«Šå,'¤C—£Û5 ÿîü­Û÷­d¶V2[‰ìÁõ+­»õ2{i‰¬ÏèHôvXvZ €ËÇŽtŽÒ¡Kp»§öï¹õRën½¬;wÿw÷6w_ÿ’é;|ÀÖÉ¥qp‹ÅnÞéòñ#mº÷V+•j•R¥Tzøyú6åp«ÞýLQ›Uk0ª0(ò˜¼DVbu^” ž¥¦Ô)¬”L}f£U’H$...÷ïß?|øpDDDRRÒŸþX¶VƒÇ¼®AЦ½Þ*y¨°sq`ek§Q«”rSb%‹Í¡Ë…ÍJK¹}þtô­ë¬míE’ Óˬÿ½û“ª¼8þ™Ù¾Ë.,m)KGª€"ˆ±÷Ž¿Ø5Æk¢QSŒ1ÑăÆh4¶¨±ÅAÅ "ÒwY¶°mf~ì,°K‡¼ß‡‡çÎ;o9÷ÎìÜsÏ{JNË„ÄD$&Vï§ä-ËnÚ ‰‰™Y+ó—×:pé‚ùùK?û—{ª^¶êÐ1î¹ßýüC÷––wÝ»ßy7þ*9e«jŒíÒĈł̻»6;TÍä//XZµ# ¨•y óGw×}G.ZVVöÝwßåää4jÔh¹ëSRRFŒQPP°|ùòüüü ¯Ó:$&”e¥Í_ZQa«3 ¯Q135…B ç|׺cç¥óç¥7ÈLϬ½Y‹6íFžræ€CG¤²r³Šd7m¾tá±XEEÅÊy›WÛ¼Ãᄚ)ÃZwìF/ûÍŸª”àÊŠòĤäP…ã~rù˜±—Ìšúå¯Î?õ”˯ýÑ*£±h4¬41¡¼¾ Ø*v¨2Z-\’°$#”‘&^Cr6:V.øA©oŠˆ±Ñ¬ðäÓ|ëÖú;錩í­O?aðÆæÙ˜Ì™2ÔRâ¨(¡¨ ¢ *º‰9G· ,xöÙgsssO:é¤ §ˆÊÊÊ:ꨣJKKÛ¶m;iÒ$ëUIý1U6n0û‡ÅåiÛ! >+»qßÁÃÿݯ:rÌKã<úøZ»…B¡#ÏûÌŸï.),LHLœ<þýS®¸¶ÊuS8è¨cŸùóÝš6ŸýõW ²ºîµOU{ç^}&¼þr$iÕ¾ã>ƒ‡xøÑwþä¬Þû»öÝz~÷õ”=öÜĨ‰o¿9㋉{ôé»pÎì&-[ý˜·é£ÑHR(/#eI} °UìPe´âNàu~W7¿æM–òßázÔ¡ŒVðŸQÊ#$Ó‰F<ÅõÉxöã>µÛ?e #ã“\FŒ§¸ƒáLç ­cìlŽc2¹–ÿ’À_™A%å4g(Q.g:½ù€ë8±Ž w8ápxèС‹/^mòÜ ÿõ¯4lذU«úIŒº’ž¼|ŸöòÝÏ“[ÖZ& `·§lUIZèëž¹ÏÖ· [Ký)£•ü›‹hÁU¬¤qü­ þICV0‡Çyœ½˜ÎXίÍfædîâ òù˜«Èã1~ÏѼÀÍœº9~È`®¡±'EmÂó4e˸ŸÛÎ7\Ä<Ú¯7$‘S¸‚…D™ÀXÆ£\Å™¼Ãùœ¿iÒ&r YÉóŒâЀ?PF1Ù<Î  %£ŒÃ™Â0^ävЏ½îUR¹›Å‹ñÆUÜÇ•\Æ å§tZol”ûÎC”²?¨äjng ÅìËìÚÆâ:ò¸œq\ÇóëÉ<ž—ø€¼ÅoÃÎáS—””Ô£G=zlÖ¨ää䌌Œ… ~ôÑGG}tBÂNcé­WB¡h÷Öÿž·|¿¥#l0,`·¤²¢¢¬hñA]ÎJû¡¾e ØZêOÆlZÎ|Á°ø[C⸘H ¿&™Jò¨kCf(7ñ³èJ7¾­± ߉BuxÖÁh®ç}öàgì½ÁÎÑ4e&‹yˆÇ©¤„•uŒÚ—†¼O%™ôg ÅñÝÿ¤°”MŒ¢ÞGø˜ËIa§SȵL'•Â[d÷ IDATV‡w¥j{³›6]T°€~`1¯6…2 NÉñÏe?ðO^$F*?Ô¡Œ~Ig‚ïI'V›Éó b\MˆRJ7áAbçföìÙ³fÍ …B³fÍZ¶lYNNN}K´³.=`{^ÿªea^ÏŒ† ƒ*D? b±XÙªUeE‹»ä<Û¾Ù{õ-N@@À6 þ”Ñ7ˆqU\Š×98®[Ô fJ£ WÕ°›Öu/nÎ1ŒcN T%’ª$‰DÂ54˜Ê ÚÌF±/_ò0×ð(«nåqe®Ššæªšq UyÍÃt¬c‰ÆÉ#¤p< È#Qu^²¸Øª’邺nG:p$Ï‘OWÞâ ^£÷³=v´B¤R Ê)¡Öàœ¬±xÿ$Õ¸VÖ¾V‘Ç©ŒŒë²hTãs¬©L7¤7į[ÒÎbýá‡V¬XÑ¡C‡´´Z½žëdùòå±X¬}ûöp@Ó¦M·“x»(2æ±×åŸÍ9{Ö’Q)Í“SSCáP8ÞY<3¶±X,F++W¦š>pG:6;!¼•OÒ;õ¤ŒÆxƒ ¹÷ó7Ô°Û­¦i|ÉhJù”Nu«Çs8 ¨Š(hG;å2þIKš¡”i,âFÔ-äË´¥ò2!²XÎDry‡£ëØ6|Æž”2•uôıÜO¿MéÀÓtàYÑ‘BÊ™HGÞ`¯:¦jDS>ç Ρ­âsSyŒ §ÂÉd<ÓÉ®[éG b|HrHc?ž /Ò°Ž˜°FÆý–óû’ÅpþÃÕDx‡ÕÙÇ;óƒiLCŽå/œNcfÔÐw›ófЀV äæ²/+˜Íf mG>þøãÉ“'uÔQ}ûöݬùùùèÝ»÷f…=ýxhºxP×ß¶Îþlêü1E­*cÙQY I;Ç#HÀ6"F#«¬H/ï”ýYŸvÿÈJ[PßBl3êI]BGÅíƒyŒedÑzíŒ?y_ñ2% dtÝÓö¡{Ræ‘ʯ¹ž“Hçv’Á(®£)]7¨rMæv²)çFÒèÄñÜH ºÑ,Þ³ùÚ–Ñl~Ímñý÷þTy;ћ̸ΔÎÍñ°›nË| 7Ђ=âÖ'•äЗAqã``,aö¡$.a•%2DÄg8†Ï¸ˆžü±n™[ñ3~Iˆß±'¿àBN"½udý q6_p.aÑ„îã*Î¥œÖœï?–+8›³8‹3Èã'dRÉÝñnGñ!—Ò˜ÇiÏCüš)áôÂF¶råÊ9s椤¤´iÓfsǶjÕª¨¨¨eËMM`ù#$ŠtÎy³sÎKʳW®j]PÒ¦¤,0!ïV$„货 uQVú‚ v> `÷£ž”Ñœµ³Tvg|üø®õ:ïÃs›0g3YÆi5TÃýy4ŽŸk"w²‚;ûë¹~í–náR2ã»ÀU\¾Þؾ›,ówüÀ/¬É¼Þ×ȧa|•D®â|Ò6¶é|IüàÁøAþ¼^·ã¨ª+™ÂŸj´çò·M;‰k¸¦FKþÃ®í½°xl½Æöü«¶Î-x²ÆËd®æêõº5çѵ[‰›Æw,XPTTÔ®]»Fê¬YýúõëׯJJJ¦M›–œœÜ«W¯ŽúQKOÎKOÎkÑð«ú–$ `3¨×ÔNÛ–ó;†ÓíöäÚ¢ï7[%¨AãwÙTþÍÝôbèÚí ñp¨šìä™­C43ÿ¸ÉÍÍ9rdvvvRÒ–Ù,Z´èµ×^kÖ¬Ù{쑺9É5vfv#et=Øc—:§At£Ó­‰»>™™™ýû÷ßx¿õˆD"åååÉÉÉ -Z´hذá²eËòóóƒ]û€€€€€Ý†Ý(YtsºïRš(šÓ3ÐDêä»ï¾7nÜ„ žžž››‰D–,ÙM*qÇbŠŠ¬ZµCÊÊm7êƒÝH ØùˆÅbŸ|òɬY³"‘ÈÆ{¯Ç?ü°hÑ¢²²êˆœxâ‰íÛ·ß–"Öee~ùK'Ÿì?ÿÙ¤þÿý¯OtË-ÛWª€€€€€ÌN¦Œlf^ú€€›åË—¿ûî»/¼ðBqqñ _±b6¬önÙ²e—.]V¿ÜÕINvÁúöõ—õËÛ®GE…л· .Øþ’ì@êU-åíµ+*Ý·iÑÜ[I9Å“m.1VðK·giŸòCüâTò c9ƒqñ”ø»³fÍZµjUnnnFƆS¼ÖN$ÉÊÊÚ¬Zö»á°Nì·ŸòMøJG"*+í¿¿=öØþ’ì@êÕÅrÇñu’K…„ˆÕ¨<´MX§nä ®àïu”Ü•<Ãc”PÁ%œ´ÒX~ͯ˜G„½¹¦/®£%‡nëE¶³gÏFÏž=·¬¦üèÑ£‹‹‹Wmª¬¬ÌÏÏ///oÙ²e8¼“mkl)¡•+Åb6\^>SY¹£d ØÔŸ2ú$ŸPÊohÀ˜xa¡Y\Å\Î`añóiÌÿÑ®Ž ßã¾e £8†0sx€Å4á2ry‰÷˜ÇÈæ$zPÆ‹¼MŒÑŒ¨Ãdü.ðkzñ¿bS˜Á<–r§“À»ô7î`ðsfÔ6„û¸œ Æò8y,çmn£ûs³Á öåTR¸Œ•¼Â—¤ó½¸‡•üƒ›9ˆ!ü’/yvÍ/¹Œ>'‰ J¹0ƒ·é°=iѢŀ6·}]$'''&&VTTlY8ÔÎINŽ-\yå†Â˜ÆwÕUÂá`> `7¤þ”у8†dŽå´xíJŒäDÆRA_ð5çÓž1|Îòºç<¤ÆØ•Ìa"×r(×0‘…ì˱4åhN£-þÊqôe y«¶É—RF'~ÉHưZ8˜3C"‹À d2‘,¢*O7ö£G‘ÀBžàhúӟμÍdFð(¥ü”$V'²yžðWÚnÝ•ØE˜?þË/¿<}úôÕ-‘H$†B¡Ð†·´w)¦O·h‘ œvZ}FŽôî»ÒÒ|öÙ”, `‡°ó¥ålKˆ¤¸/fÅÜw!m»vøuhI˜Ôøi“¯ ŸNIVÕ¬àÞ‹·ÔºXH"«Hå²økü­ B„‰a%çS̾$Õ&p"a )àuVß_ÓYJc¾æ\öcóâï~Æ ‚J»Ë–-ûú믻víš“³…•©fÏžýé§Ÿ¦¥¥uëÖ­ª%55µ_¿~±XlwªÀTT¤S§:7èW“‘!7WEÅ‘) `R¯Êh"!6|wiB3þw-%e“çϦŒt`TyÙU-ZQ£[cÎæüø[µÚ‹³© ‘rÞ§sêXwßòOºò6¯ÔÑ-&ÎÅ„âvÖïXD^¦ïÖˆ²:‚ €c×᫯¾zï½÷ Fµe†Ìuò:!##cðàÝÍK£´Ô¦w…Bb1[” + `§¦^•Ñtã`këÓ›^\Îñ,å[~UÃÁtôf(·pcßx‘ú†4â— â0Ús¿¡‚†¼ËÕtYo¶Æ4f:?ã·”Ó;îrºMÉâ :0®nm;™ÿãçTÒŒ/8—>¼Ìo¹‘3èZC’XÅ!›vîõJeeåŒ3B¡PÏž=·xK}ÕªUIIIM›6ݶ²í<”—»÷^Ï>kSJ¥&%éÙÓ]w™3ÇUWmávõ½Mÿ7^e!Uá$Çߺœ†$ñ0Oñ MzS ª¡ö]DSÂüž¿ò'nUMæ^c1U¥O¡²”ÔZ÷;ÌO¸–_ò‰q€áqáSù?ÚÓŒ?òæq)+hÌ(Òhι4äš0І¼O=hMkžæ ~K¡ç; °Œî2,[¶¬¸¸¸iÓ¦-Z´Øxï:6lX¿~ýjÎPVVF“’’ëû/w[`ð`ýûëÓgãÃa7Ü`ÄéuýìšÔ÷-mj†Ç«q|eü çmÂTÕ8¾8~ÍOkë܉‹j¼ s0ol‰¸˜›ãáíWpp ™ÓøIüx¯x¦ªÕ?è Ή¿µ{þš›ù7MéÍ­ñö/`§¡Y³f'œpªU«¶&޾iÓ¦ë˜E?üðï¿þzàÀ{íµW]£v!ì³ÏfôOKsÐAï°kQßÊè®E˜“8†oˆÑuû¬Òð=ùAàü®JBBB›6m¶íœÑhô‡~X¾|ùî½(£›OÊöiO ¶ó*Û‡X,¶õ©—òóó,XЪU«Æñ8ó¼¼¼E‹effnÍÖ@@@@@ÀÎÆnRQ0 `çá£>úàƒŠ·.ð{Ú´iÿú׿¾øâ‹š999íÛ·ÏÌÌÜ:6BQ‘å5ò/Z´£ø.4w®¹s•—o¼sa¡¹s-\(Û^òìÌTVþxs{ÅbæÎõÃv£zk”Ñ€€mIiiéĉßyçüüü­™'//ÏÚyš6mzúé§yä‘[VæþGBy¹çžÛZÝñÿðóŸWG"Î8cÝêPï¿ïÛo·j‰ÕÜx£³ÎÒ³§iÓ6Þù±Çx ›oVZW!ºíÃøñ¾þz‡®X+o¼áª«””Ô·õAY™3Ï4p ·j­É°‹óãSFóïxý–QÎçüƒIu÷‰RD…D7mÚ7©ënôå¯ÌÝla·1å<Å_ù{<‡À¨ 8þ½PUˆkÇÚæÍ›·råÊÖ­[7kÖlkæ©Òe×Ïë”””´5ÓîºTV*(PP°–m¬¼ÜŠk4³Š ùùn¼ÑÂ…JK7bCZg,b1+W*,\Ó*/÷ÛßZÝ5µj•ûï÷ÁJK7d¨«¬TOQV¶Æ–YZ*SX¨ @4êᇽóŽÎµ&¶«Ñ£=ø šqq%%V¬X#IYÙš¯¨¨n//¯¾€EEk$‰Å)(X#gÕÊJeeÕ'UZêÑG½úªÒÒ:Í·±ØZëF"Õ=c±jñjjUW5YKžhÔÊ• 6d!îÑÃÿëƒ6éBíf¤¦zçGåÍ7ë[”€€íÀÏgt&¿ ?[åü~ÇálÀso!×sá÷T…²”2…i4æ ÖÙký#é^Ûl‹˜Í¿ÈŽ'ÿßϑ̨Í8¡Í Ê÷,⯠Ž@Œy|Ä*Š{»~À³Ç3üyûȳaþÁ[</ßµC˜;wn(êÒ¥KJʦ—g¨…~ýúµiÓfµ2ZXX˜––¶;Ýt Ü|³)SÄbößßm·‰ÅLêöÛ-Z¤I7ݤ{wwßm ¸â ™™®¸¢Î ¦S§ºóN?ü +Ë­·ÚsO~û[o¾)9YZšª²Y“'»ã¥¥®¸BóæðÕW~õ+'š=Ûk¯<Ø…Ö¾Ä3Ï(/wæ™pÉ%n¼QUHÛ‰'<ØK/)/wË-ÙŠÌÁѨÿÛ£Z¹R¯^~ñ ÙÙî¼SÆ.¹ÄªU~úS£F9òH7Þ¨¸XUeÙ3Îpê©ÂaãÆùÇ?TTØsO7߬ê»vß}òóÍœiî\ûíç´ÓÜ}·?6i’O>Ñ­›ë®³~],æ† âˆ#ࡇTT¸äO<áé§kÐÀر?\(dÖ,þ³ôtÿûŸÄD÷ݧC÷ÜãÍ7Åb:vô«_©õQ®m[#Gºÿ~C†Øº?¯]’PHr²•+ë[Ž€€íÀΡŒVÙPN”2*É$•’x…Ï Œ-ŽkE+ãõ“nìÌŠYHFüù¥„(£ŒT2‰QD)Id¦’bÞãd.Þ Tå|ËJ¾¡ äs ³Ù‹É<ÏŸI¦˜BR×6౪ƺ§‚õ·ÉV[þ²H&J!ãIg‰ñË¥€ÊøyÕE É$Æ?Žª+£d Óˆ«YV£jÕü/r3â·çÙ³­ŠïÀ|ð¢¢êã7ß´l™[n ÉȨkô&ñùç.»Ìï¯W/7ÝäpóÍŽ=ÖqÇéÐÁÿþgþüêdX'JIñ§?™4ÉÕWëÛWR’[nqûíöÜÓùçûÓŸªEúê+/½äÖ[õêeáBmÚ¸ürwÜ¡}{'œ 3Srr-’„Ã22üýïFŒP\ìᇫý’’\u•¼÷žÛnÓ¿¿æÍ­\é‰'wœÛo÷ý÷RR|ñ…'Ÿôàƒš6õí·µ(»«W9ÿ|£GûðCo4ßîHóæky3ì6Ô·2ZÂLþÁ4ã1ވףïÉ=<ÉœÂÐxûÕ¬bO°€û˜ÂÏ)'Ä n©a·[‡e\À|Zòp¼òÓù),c/þÌ'üЏ–£™Äµ|Íg¼Ã™œJñÚñÉñdõÉ„I¦Ê’õ«xšrq 3IãBæÐœY>æFVÄÅœŸa–rSˆp ·±”s˜MãéÇTò¡wÓ£¶ÙʹžcÈ2N¥j3h9G±'“ÊõeXÄ-kÀ€êÔ¤ŸnæLMšxÿ}fδ|¹Î5m*5U¯^rsëœmÒ$3fÈÉñÎ;RRLžlÙ2/¿lăÁ˜1Õ·ü† õë·ÖžxV–~ý4j¤C‡M*U+¿þµ·plM^yE³fV¬0~¼œãÇ++«6s^t‘´4/½dµ×ñyçéÞ]×®þøG&ÈÈЪ•Q£de9ùd/¿lÕªê‚Gíüó…ã?¶M›jÜXnîFÎ÷È#½ø¢ùóÍž-sÀ°ß~žxÂSOY¹Ò¢Eòòª ̹¹®½VÛ¶< ¬\éé§ ®o_ˆÐëÒÅ¡‡zäƒoRÙÝŒÝs[nqöÙÚmt—, `סþ”Ñ¥¼Â3|Ç®'“…ÌáU28Œ‡8“âN†q=)àuþÉ· ãR²Èå^º°„Ã8šº~îK¹šÁÇË\ðÒ•y¬àÎæ<^çw@/Æqq,Y,äRטü®£9·Ó»iI¯rOð(I,¢„ûHc"S9,ç§Í¼Ç5 ¦Õz§ãæòœÈkÉ8~C*—Æm„Ÿr³/·r'ÕvM¢Ì¡Ê[®¢†¶’‰ áEV’SÛØ—8„$FÂ|ŽhEÛxE«$~ÆÓœ@gNå0²hË£ôc.Ïr3¹Œ9€»ø9Ïó-Ï0…f|7TOå ^§qü‰Eü~Í¥ñúU™ÜBoJ8ž—8NÆy=þÑavÀþœ~úéûî»oúV×ö‰D"Û$º¨¬¬¬¼¼<%%%99¹¼¼|„ ‘HdÀ€YY›X wwãÐCýâ^}ÕèÚÕ /ÈË“’âûï«;Œ[§9m}òò4h`Μꗗ_.¶bÅšÚN-ZlcûStmÇñìì÷ÙòóE£fÍ‚Œ G]­Aö飢BçÎZÖ(&W¥•†ÃÒÓ…¤¥©z kÒDqñÏÑæÍ×h¢›N¯^23½ý¶/¿tÀrr¬\éœs´kç˜c,^lâÄ5îªÙÙj~—{÷öç?{úi—\¢IÏﳜ‰u_–ºÈæÚþ ë3‡¾Œãx®ä†¸RÛ"îV[uB d ‹y‚ 9”2–c¹§LGþF2ïñùŒÍIe,0‚_0ˆ!ÜËÀµíǯ²‚Óâ¼ÎïÁ|æÑ@ÓÑMo<üÆNßwºïO÷9òÞ{ï=ï¼M©ôU'+W®|ã7:wîÜ«W¯­TI?ûì³·ß~{ðàÁƒ ‡ÃýúõËÊÊÚsÏ=·fÎ]šhÔñÇ;í43f8ì0sæèÚU8ì¼ótì(UT´F¹©ŠËÙ={ª¬\3¶°Pƺuóî»Õá>}´!ãÂayy‘9¶t©XL~¾yó6Ò9;ÛwßÙ{ït[‡nÝ|ù¥k¯••Ux”’¢ À…:ç'úÍoüâÕçgŸ6L~¾ùóµk'=Ý‚–/—šjÒ$­[Û@±°„K–ˆÅlÀc99Ù±Ç7Îòåî½W(dÑ"®½Ö{xã eeuŽD dÄ 8ä³goȰݫ—!C<ø þý·DiÞ¥ùðCC†¸úêú–# `[SÊè<Âý|ʉ ˆ«;)q"…JʘËóü‡"n¦k¼êæÃ|Ycìµ$r)IÌØd1jÆÛ6Z»=&TÙ0®®Ã(¸‚©iD9˜.ëu«$_«!Yd!ÿÂq„ªu[Ä×½¦Žˆ¥å4§ÊeíTºÕ}‚ÍâÝš®]4ubqƒuÂÏjÓDkÞ*I¤€¾„éÈä:–(`<ÿd"‡Å?ÇýhÎó<Ám ô2W5fó¯òwò1{p Oq‡qmH"Âï9¯†Øæmn%…ß‘GDÙ¢²W^|¥àÂâ¢âK/½tèС¶Ž9sæ|ýõ×¥¥¥={öÜJe4//¯²²²**11q¯½öÚ=ên1/½ä‰'ìµ—9stë¦];á°Np晆 ³t©¢"ãÆAJжm]z©=œsŽÞ½k™­}{çŸï´Óv˜¥K-Yâ©§œ~º‡rÁÒÒ¼ÿ¾£‹7ÎĉæÏ÷øã>úÈÅëÒE(äÀÝu—™3í»¯ÓO¯]æý÷÷§?iÕÊ_HO_£Æ%'×¢Ò}´;îðöÛÎ;ϦÔ'žèŸÿtÁzô0}ºƒvöÙ~ýkYYn¸Á‚F¶ß~F‚”—gÊÍ›>\8¬iS—\¢sgÏ=çþûUåiHL´¾ÓÊAùÅ/,_®[7?ùIÁCÇûýïåæêÓrsµjåúëuëæ•WD£Õ' IJZë"|ö™otÀ–,‘•µ‘ è„gœáÜsMª×ö®?²“‘—ØDvOv´2J¨òõ;„C˜Å¿ø©X›Xì©XLÌ','‰ìÍSÜÁþñ ëªg÷a cÏr y˜¹\̦¯½o¾e´¦}B%+Ö6ß®&““×¶ŒÖú@ŸMˆ¹ü’L&Ó€v¼ÇQ,bhNKº3’ù4ŽO’Ä÷ñ€ªLz‘Êi$QÀêÛC"óYE"Iôâ1£«êβ”@Ó9” »8I´`!ÍI&—iÂ,äa×6ªœ“XÌéÜBûŸÍ­TĽfûQÌäPFUôhÙü$nýŽÎ\Ë•¼Çãü…{8Š·˜ÅÓÕO5 b?ÄbÇ„c±è”h¨u(4!4û¼Ù Û5<þÐã‹ ‹zöìÙ¶íV•^ÅbÓ§OF£]»vÝúìKUy²³³ËËË“ƒ›ƒW§þÙsOÇWïÈßu—>0k–.]ì»ouÏ´4?îóÏUVV!­Ob¢;îðÁfÎÔ¡ƒý÷‡6m¼õ–wß•”ä쳫õ­>}4o^!Žx1,cÇêÞ]a¡Ö­k[ â¯5ož#”•­1õ=õ”õ+Å^r‰äçÛhu­… Mš¤W/ ²³½ø¢wÞ±d‰>}p€òrC‡ºðBºtñÄ**ª7Ço¸z÷6|xµŸÀ³ÏzçÅÅž{®Z}ÄEÕâðp :u²t©ìì yjvïîï× AõüééyÄÿ«´Ôý÷¯¹:ùÅ/ÔtŠéÑÃEYºTçή»ÎFÿû÷×·¯‡ö‡?lÈX»[ªzôÅ,_]¾<–“Žl¢;:q]ÀˆÚÿÎC¡íõ•Û¡ÊhZ8­Ie“L™‘ÕÉN\#vY¬|jyJjJ¡Bßq˜Ç)å-ÚÕÄÓžŸr1ÓHã~Ík|KZÝg–@z ãëê}Íã*Á®àgìXëN©‘*(ƒM êÌ¢'/sÏSÁèÈeŒå$ŠXJ­¹’›ø«È癸Éöt®çÎäH®â„=¹?næ¼´FûÅë)Ig1ŒH¤SC×Õ–Wh£\Ê)q2 iBcšñShArÜzƒXDk¬5ŠÌ‹»váU¦¡)«³ØÈûÌ¥HãN¦QBZyL«8™äÑ»†+mcžY¯g7sËhEÇr×s¥µ9* ÷£]ŸRY½ÝâNÎd%‰T¹JàŸqËnŸÚòjµ“øŒ?­yz)Vì^S<µXÒ”‡ÊµÕºYëÆ¡ÆÍš69räK/½T\\F·x{===ýœsÎY¾|ù6‰1:ôÐC§OŸþüóÏG"‘%K–ÊèÎÌ矻øâµZnºÉ‘Gn—µFެ]—Ý('´qsã&2eŠË.[+‰ý¥—Öé«°ýèÖM·º|“vÒÓ{¯ZU‹VE›M¬öø/g"ü‘†3lbµî¢ÆbJJB n—ô‚;TmnÜ<Ö<#–±®2Z“„¸…o èU[â¡uȤgü¸¦gR­¿ÔmâùêkRGòÂЊ¿ó0Wã6­k­¦]®¢ÍÖVÐ3è· Ý×¾,ó¨N‘@O@ßxcóøAµZ†Âtˆ'·Ç5tàA–2„[kR+1^æ!³ŽIf½9%®•n˜æ¼^›³Äz—´Me›œÔôìÙ³Q£F-[¶ o]4DZZZîÂ.6‡‚‚‚7ß|³¢¢bàÀÝvû[î.΀«µ„—±c·ÙT{íå½÷¶Ùl 1±YBBnIɼ­ÌG°MˆÅ”–¦´lYÛîÉV³C•ѤPR³„f+;/O®#oÊèÚöpwr¹¥¾eÀž®ñ2[âfÔ-&‘S8e‹Æ¦s,Gm«iU[òõÈŠeµŒ¶ÌI¨¶Ÿ·Ž»þE"‘¢¢¢šá7…h4‹Å¶UÉøH$’œœ¼×^{åçç80¨Dðã$JJKë]T(£;ee**ÒÓÓ·K4íŽv·Ù3yÏÃKŸž8½ \[î¥_Þ¸zàN¨oVS•ÃkÇ>lÕa½{g„×úÅbo½õÖÔ©S;î¸6ëǘÔÍäÉ“gÍš5`À€Íµ>±X,Nž<ù‹/¾ØgŸ}<ðÀ­4Ö캄BIÍ›3çììŠ Ž1 ~‰FÍ›nÒä”px+mWµ³£ou]’»ôOèDé‰õ^ü)àÇÊž{­:0m`xíï$YºtéÊ•+Ÿ~úéÙ³gÇb›6‹Å&Ož¸ÚõÌÒ¥ÊÊöÌͽm;Í¿£ïv!¡Aiƒ†UZ:45¶É%S¶ ºUv;¶äØ!iC2Ãë¦5OLL3fL÷îÝ‹‹‹?ùä“H$Rë$ë°xñâE‹eeeµÛŠò|~øá /¼ð駟Μ9?ÚÊŸÛœ_ô¿ÿm÷UžyÆÅ»ë._¼%zÃ駯)d¿ yòÉ5þ¬¥¥Þzk]óâ‹-Z´VË)§xûm§žê­·êœö¹ç nÙ²m-nÀz„B ­[ßZRÒmþ|›öƒ°‰F-_náÂÌvíþ°y>l›N=˜^„‘qĨбc‹Ç¶‰´ L¤;€°pf,stÉèËJ.;&õ˜=’÷¨µ[ZZÚ˜1c>øàC=´ª`}•?èfÎËË ‡Ã;vLÛ@›1eÊ”wß}7tÐA5ÊÌÌlÔh R6ÔNE…éÓMœ¸¦2SI‰iÓ|ü±¹s×ÜãËÊ̘áãÍ™³¦6fa¡)S|ýµÒº£.k¥¤DA™3}úéšu£QsæøøcóæU¯[Xhɯ¼báBK–¬Q‹Š|õ•¯¾Úˆ’ZQaî\lùòj%8³x±O>1gΚ£ÅÅ¢QwÝeõ×jåJK–xã óæY²dóTáÃSQáÕW7cHÀ“””Ó¹óÓEEƒ§OO(*Ú’²±[F,¦¬ÌìÙ¡ :µmûHVÖÖ–†Ùõ£æ$äÝàè6em:uü&᛹ sç%Î[™°²2T¹ñÁ›L8nmÙº²uëHëΑν½†6Ú(¼!=/11qàÀ«_N:µ²²rŸ}öɬ£@d=Ú´iF7wW½ÊC´*>©[·n³fÍêÑ£G÷îÝ\RR’ºé¥Ö6Æ_þâ_ÿŠÅ<ÿ¼-Üt“7Þб£3\|±‹.RYé²Ë|ñ…V­ÌœéÑGõï﫯œy¦FëÔÉã×™ò=9YzºÔÔ5¹Üï¾Û¸qZ¶TZ*3Ók¯ILôä“®»NïÞ¾üÒÍ7;çù‹çžSZêÄ%$¸ãC‡š6Í™gJIQV¦kW<°VŠøÕ”–ºòJ￯uk xòI½zùøcgœ!7W^ž¼<‡ ÿ»´|¹>ªÎ«÷Ý^}Õ¢EÆŽ•šêg?s챑!1±úÿºhÖÌùç{à£F­)°ýHOïÕ­Ûë Þ5sæïÒÓW¦§GÒÓedD‚àÆ€íA,¦¤¤ê_¸¸8-#cT·n¿KNÞ6¹bê¢Þ¬’I¡¤©º$uYY´¸rq^YÞŠèŠÊh Œlc$4hnš“˜Ó4¥i‹Ä u–¨•ôôô¹sç.\¸ð‹/¾Øÿýû÷ï_kl{]zêXµjÕäÉ“óòòªL°iiiÇw\Íu7w€*¢Ñj£fBÂűyso½%uÄzÈÍ7»øb7Ý$3a‚ .pÑEÊË=õ”Ï>Ó¾½Š ¡HÄ-·4Èo«¼Ü!>üÐAuÔ5Ê!‡HLTY¹¦&PëÖ^]i©Ü\?ü uk×]çŽ;œzªÇsãN=ÕÕW»új™™Þ~ÛêïÑ-·Øk/÷Ü#1|¸wßuøáÄ]<«Êiâ•W¼û®W_Õ²¥ßýÎ]wyøa·ßnÄwßmÑ"ýâ©ß.¸À‘GV×­âæ›Ý|³Îýë_jjøóŸefÚ{o 6¥pÜqî½×ûïo^²ú€-&JiÕêºÆ+.žX\¥¥¥ßÿý×_Ý·oß*e4‰TTTT$&&nnݦ‰'~òÉ'K—.MMMíÛ·o‹% c±ØW Àÿþç÷¿‡£ŽrÎ9ÕT—<ؤIb1¯¿î‰'ŠDäåAb¢}÷uÔQúöuè¡N:I$büx=z8óLX¹ÒÔ©u*£ÖÏ¿3`€ädÉÉZ·V\lÞ<‹>¼Z’Å‹ååiU[&²>Ò±cµüfÏ®n?ç……š4ñÇ?ÊÈ0a‚âb×\#²x±PHY™É“}¶ÄD¹¹[Rº½ªÀÂFíò-Z8ûl÷ÞkØ0›ÿ,°e„RS»¤¦viÒäÔú–$ `øklˆ6mÚì¿ÿþÓ§OÏÈȨ*_QQñÒK/5kÖ,77÷ƒ>hÒ¤ÉðáÃSªê?®G4F£‘H$//¯Y³fU~¨yyyyyy­[·8p`óæÍköÿæ›oæÌ™Ó­[·­ ‡ú1Ó¢Eµ¶×¥¶2`åå,XàÚkýûß8ÀôéöÛ’“½ø¢ñãï§?•”dÌÉÉÆŒÑ7^ bs3w­³Ó]åÇQ剅ÖêPÓ39rÌ1k*p®þ. bÕ* ¬اK/­¶ÅfdHM•˜X›‹­ñ|Ýœ~ºGõÁÕVÛ€€€€-&PF6B(êÞ}ñ~þüù3fÌøòË/«^F£QLš4)!!!999##£U«VU.¤&L˜>}zAAAEEÅØ±c³³³Ñ¯_¿öíÛwêÔ)q=¿¼Y³f}òÉ'ÙÙÙ2ºetéR‹úßÿZ´HB‚÷ßwÜq*+…Ã:wV\ì‘GªûD"¾üÒ€ú÷7a‚åË%&:Ô¤IÎ8C(dÎÙÙ[%[Û¶:wö Î=×sÏéØÑêê ™™&NÔ¿¿´4II† óÅÎ8CR’ï¾[ã0zî¹kM8l˜W_Õ´©Ü\…… «kÜ¿þº‘#}÷É“~ºXLQ‘¢"‘ˆ¢"……4¨Ö_LŸ®ys©©67“e«VŽ9ÆC:ÔVïÊh@ÀfÒªU«1cÆ|ûí·Ó¦M+**êØ±cjjj,{÷ÝwW¬Xœœœ³Î:«*¸>//oáÂ…áp¸qãÆ«V­ªRF›4iRWæ¦üü|A^§mJF†¬,£F)+Ó¦³Ï–‘áÔS)=]Ë–Õ!8ååŽ=VëÖ’’ÄbF»õVcÇ:ø`‰‰JJ¼ùf-{ñuQS?kÔ¨ÚõŽ;\y¥çž3ož?þÑj{úÏ~æÿþOF†»î2l˜Ûn3v¬C‘œ¬¸Ø3Ϩ5¹Â¡‡:ùdcÆhÖÌÂ…n¸AçÎnºÉÉ'1By¹N¤¤X¶ÌI'YºÔҥƌ‘“ãÉ'5m —^êg?“’âç?wÂæ×Â8÷\‡n¼ÙcV(£›GJJJ×®]»víZ^^>cƌ޽{‡B¡²²²>}úäçç—••eff®Ž¬?ðÀûôé“™™Ù°aÆÛW#MMMÝÜz¤àŽ;Äb–/WV&^öÕ=÷X²D,fµ¿nZšï¾³h‘PHn¼#o4OžÌ/¿””­ù“NÇÆœ£ØÛÛç’èäääääTdúLlܸqÅŠy” }lRRR222r Ì„”ÞŸC‡¨_?Ûxp0€$am pó&Z­l úû£Ñpÿ¾…Ù ®_çë¯iÒ„¦M¹ŸA™ë×å&O*YSÝÜܨX‘ ؾý‘NNðÒa4j32.æh¯%ÖÖØØ¨ÓÓ %_EÄŒ>£XYYÕ©SçöíÛ­…BQ¯^=Õ#µÊ<1 wïÞÕëõO}عsghhh¯^½žz’þ˃«+û÷3y2›6Ѷ­y<7 œÞ9—$ìíÕa¹pžˆmúg++«Ž;6lØÐÚÚÜüÀÚÚºAƒ]ºtnÑ¢G©T–(Q¢J•*O½Âkrrrzzº“““­¨ÝòÄ8;c0Ù”£Iy›ÞÊŠÞ½qrÂÆ†+$¦LÁˋŋeI~ø¨(vì 2IbìX† áë¯ùøc22È-µ,"‚;HO§bEvìàìYŒF¦N¥m[>þ˜°0¦L¡lY£GGQdT?’$)•ZHÌåaΧ3Ù¾ÐÐbTö‰X¿>gIµŠ©]›;¸u+§ðùóŸ.#GrþüÓŸvÏöîµü–é6$„ãÇóŸgÓ&fÏ~L´Z&L $$ïÊwFH¶øW§P¤Rþ¥0hži¬­­Û·o_«V­K—.ùûûwèСT©RÅ­×KJ­ZµjÖ¬Y½X%I*_¾< ŒÑ''8˜3:”3([–7ÞÇmløøcùyÙ²,_náØ† ÉÚýÊÚš#1Â%JàíR‰V‹VËùóÄÆ’–†••¼‰¡Õrë:~~æ›RÓ½eª©[ÖÁ”.]ÂÍ ½“Éh$%…»w±µÅÏ¥’5¨Qƒuërª­Ñpû6Z-¾¾8:b0‘ÁíÛ\¹BZ …\zÖ` 6–èh¼¼ððÈë^7=;w˜>6mr•)„1úàéééããséÒ¥’%K K´x‘$éé¶5áêêúÚk¯=õi_N4 $„{÷xê[ Æ'&Æ<Ò´)Æ= ¦€Úµ…1*x4ÒÓ ÆÏkk®\aýzêÕãüy:w& €¨(’“éÔÉò±ááÔ¨AÙ²øùqäK–ЫÀˆ\¸@d$NNxx°{7¿ÿÎûïLh(“'3j’$¨T¬HJ -[òÅÕùØ1ºt¡dI¼½¹x‘?fØ0V¬àøq~ü ];>ûL¶;GÆÛ›èhêÕcÑ"ËÞ+W<˜ÐP>ÿœQ£äÁØX† ãÆ J—&5• ðô´pì‚|þ9hµHü§'ýňøûΰaL™Âüùüü3áá ‚#G2r$÷ïóöÛ$%ae…£#«Vaú¾~#˜9“ºuÍ ­\É–-,\ˆ© WXo¼F#·nÑ·/ÀÞ½Œ—ññ´mË·ßZ6cb4Hþ*S(X·ŽŒ ºv%!ôtNœÀߟmÛÐjùæ–,! €[·˜7ÎsýO1y6[¹ cT ȣјššjoo/º <ûH•+Si`’Ä›o’‘ayÔ{Ã-žªB‚—öì¡tiôzæÌá§Ÿ¨]›iÓèуyóHHÈX™ƒ”V¬ ^=Ö­ã½÷èÑC¾ŠçÔ)J” * ¥’I“øê+ bËFŽdð`lm3†1c;I"22¯U2³m3¿&ÓÓùþ{Z·fÝ:¦O7oS¦ wÕªe+”abʦL‘Ÿëtò¹ØØ`c#{˜Öýã@¯çÞ=Ë&¾)n!:š¡CnÜ0¸98wޤ$9((5•øxbb,»‡W¯fÚ4üýyóŸ…1*äϵk×ÒÒÒ¬¬¬žzê ÑhÖ­[geeÕ­[7Ñ T <̦M;FHžž|ÿ=[·"IXYÉqŸ`n9kS¬³$Éb™·½YcÔ­­‘$9öT£‘åM’¹™A9èе{{s±£QžP§3·FË oÍZ¸7óD4šl!¡iiù,ªP<æ¾³$!Iòºz=’”kðŒBAË–æ®™y¾1£ Je¶S³µE©ÄÙ™^½ð÷6ŒjÕÌ*eUO¡ iS2¸L–´EõJ—æÝwå—66æâtë†#FpõªyÑgá‰ò',, ¨Zµja8/“““£££ãââ #5ê…!"‚ÐP ~àeÀ`ÀÛ7Þ‡v IDAT7ââX½@©¤^=6oF«åÆ ÎœÉëð”þø­–mÛ°¼KëâB¥JlߎFömx{S¦ žž³d j5éé\¾œ×*¯½Æ›oÒµ«ÙŠbï^´ZþþÜݱµ%<œädÎãæMó±;všÊ•+\¸`.PU¶,Ç›Ûóêõhµr­ Ó I~ÿÛ·Ñé¸z5[MÞxxP¾<[·¢Vóï¿X[Ë]*…‚ë×Ñhd3·U+Μ¡Z5^y…²eÍWïòeêÕãðálÓ.X@Ó¦ò©)4lÈîÝ$%qý:”,‰—‘‘4lH£F¸¸˜àjÕ—×U©hÕŠsçäuýýÍYkkîÝ#%S7ÀzõHOG’xåêÔÁhÌ™à•‰«+uëâîn¹ÍGñ"ŒQÀ:N«Õš¬CFãëëëëëëmª–þ´ILLT«Õ..."•>Ö¬¡KÆ/n=‚â sgbb¨Y“ °¶–“Ð?úˆ'¨S‡®]ñ÷';eww¦M£AæÌáûïeI•*§/ð›oX´ˆ:uøê+¾ùFö›.[ÆŸÒ´)uê°aã©íìÌçŸS¯³góÕW¸¸Ð¦ ‰‰4nÌÈ‘”(!kbeEx8¯¼BëÖôêe®h1|8»vQ½:ë×LŸNp0Û¶1{6ÁÁ¬YЯ-[ÒªMš0hPÎÎL 2Ë!š®ž 3fð¿ÿQ·.Ó¦1y2~~²ÀèÑ|ú)rÝ·‘#ññ¡aC4 ];îÞ•Å´Z¢¢ÌŽO))DG›µ#G¢PP·.;£T¢RáäÄܹlÝJݺԪń ¤¦ÊÂpþ<Õ«óùçï¾K•*r±ŽvíÌåŠ;t@«%0PNT ä‹/2„F¨^ßÏç?ÅäÐ}ÖÛô’’’V¯^]¦L™jÕª•/_¾}ûö…‘DoB£ÑX[[—,YRԎ̓ Ðh8w®¸õŠƒ%8|˜ÈHœÍ™æ•*qé·nQªyßɺºrú4wïf“\²$§XÛ¶\»Æ½{x{›½›ÕªåãvÍ''öì!- //¹&TéÒ:DDeʘ­Ã¿ÿˆÌíЀ:u8zÔüò«¯øê«œK8;3oóæå£É{ïñÞ{òóL_fÓ¦œ?Od$žžÙJV½ù&o¾i~鿯²eæ æáÎÐS§2uªù¥—Û¶…££9¹ªvm²0a@ûö™_:9±p¡1??vï6¿T(èÓ‡>},H>ŒÞÞlÝŠ›è¢Aüø pvvÖjµ/^¼xñ¢££cÅŠ«V­êïï_öb•*U‚‚‚49î¯ ’$gå4…F#6d Äôò’g&¿`¦d¨Trƒ†'Ç…©Tš=Ž&¬­-/‘Õ -2¬¬äL…‡)¦óÁÚš/¿déRþýW£Á3•••³³sjj*’’rúôéÓ§O;;;ÕªUë©W{•$ɦ൤à!ŒF¹¨{&¦ØAooV­*}ªTaùò¼j- Š…*UøöÛâVâ!„1*XÆÅÅ%"ûLrrò•+WêÔ©ót2… ^ FŽ´0nk[<>0'§lýÌ‚< Le\\\rŒ¸¹¹õéÓÇÓb·Ç%..nëÖ­'NœÐ?›m1@ (d„1*X¦Döªnnnn}ûö}º–({öìÙËyWL‚g SíÒÜÞ aŒ –qvvÎ,qo²DKBµ˜˜ƒÁàååUåô 7ÒÓÍUŠƒ!CX¹Òò[õë÷ø3 ^B„1*XÆÑÑÑd z{{¿óÎ;…a‰111’$•È­·†à?.^äÚµâVB x8|˜7ß|ÌöE@Û¶¹ö ½}ûñ§¼œ¦V«Å5/2ŒF㯿þ:jÔ¨âVD  Š$ññǼþ:ôï°c:?üÁ?Э›lq^½Ê´i²Åy÷.?þHh(åÊÑ«>>ÄÆšÛµgÅÏ)S²õd¿v]»8uŠ ¦Y³"8QÁ Åã£õë×ß¿¿µ©¨®@ðÂѸqãÃY¿n ÈÈÈû÷ïûùùyKï@ð"âæåž@¹ròóJ•øûoŒFvk\»†$Ѧü–«+‰‰–ч‰Ž¦dIyEOODccÁ£"þd‚bãÒ¥Kÿþûo«V­š O‚@ (œœÌ-Ô#"pt´`‰¥JamÍ©S¸º>òÎÎÄÅ‘’‚‹ II"fTðÈcT (67“CPh4|ó }dá­˜-ðð Øƒ5Ž㯿êÕ£cÇ|„ïÝcõjÔjÆã%LS«‰Šz†º;mÚÀüù4lÈÂ…Lš$£¥KsáëÖQª­ZHýú¼÷ãÆþ}|ò VV&¼r…Û·IHàÊvï¦R% bÊFfÑ"RRŠøÏ=¢´“@P<èõúˆˆ¥RéUÀ0AHIáí·‰‰)¨¼FÃW_Y~ËÊ llX° @S5k–k ð'ÇÙ®_çÏ?ó¾ŸE‹(QÂröIáqáãÇ“–V¤‹>L\;³uk1«Q,H:Pª€³3Ý»¸¹ñ÷ßìÞÍäɌŻïÊÂAA,]Êþý¬Z%û27o¦|y&MbÑ"Päb =ʪU”/Or2«VŠJÅúõ¨TLœH•* Œ­mœ®àÅAxF‚bãÕW_MHHu Bz:gΠÑP»¶¹ LTaa”-‹¿?F#ÑÑDFrô(W®’‚§'–g3¹|™ˆs.°iðÊîÝ£~}queÀÂÂ,TöމáÒ%üüäP¼˜<àÀnÜ@’(YRÖ0#ƒóç1¨_ßòƨI&&$I®nª9‡JERW¯L` ¤¤Z ËeoOïÞÙN?!sçðö¦B$I¶×MA~ééÄÆRº4)) Ü¿OBµjáè({÷.W®P®œ9ô0#ƒÄD\\8u GG‚‚ˆŠâòeŽãúuœñö¶ìT‹Ç`À#­VË)2*qq\º„Õ«cÊD0ˆˆÀÕ•›7‰§vmùtnÞäúu¼½©\Ù²µäíM,[ÆŒvð’µ’$¦M“Ÿ{zòõ×òóºueë<ÇßaÏžôìi~éäÄ'ŸÈ÷TyäÊöï/§FeÅÏeË,G£ ù"<£‚§ƒ^¯Ÿ>}z«V­ö™ Ü=ÄâÅ‹›7o¾víÚ"PfÀ€Í›7/‚µ¥RP·n][áCÈ+Wfξúо}ôz, A¾ûŽ–-Y·Žyó>œ{÷˜0Aƒ8uÊòlz=ӦѦ sçÒ¦<¨Õòæ›tíÊwßQ»6ׯçªÌ²eÔª%¯»t)À?2`F#ï¼Ã€ìßpó&Õª1y2cÆÐµk®5À§M22>ùÄì¦ýì3:w¦aCƧk×'u7®^MíÚÌKÇŽ,^ŒÑÈÙ³4n,Û÷ýúñÅèt,\Hp0ƒñÑGÔªÅÕ«k×R¿>sçÒ¨‘ÙI|ò$íÛS¯cÆÐº5‡1q"ŸNh(Ç3j”9H1›6Ñ«ééýE÷î$'sð uê0g|@›6ò±IItéBëÖôèÁÀ|õ'Ò¥ K–л7»wçz¾pý:ûBDè¢I*¨™˜)yî­[Ó¼¹ù±iSþÇ ðŒ ,°yóæß~ûmݺu?D©T~ôÑG­[·ŽË¥ Ü!CöîÝ{7÷ös¿ÿþûñãÇgÍšUå>úè£:uêôÌzSŸ…+V899¥ˆÀ¥…ƒ –MŽoÞdÖ,6o¦n]Žã­·xã fÎ$1‘fÍX¿_ß\ïÝcñböî%8˜Ÿ~b€å˹x‘Ó§±µå«¯˜;W.…“ƒØXÞŸêÔ!,Œ¦My÷]¦LaÊ”JBB̾º÷ß§cG¾ûI¢vmöì¡]; æl£1ÛFÿƒœ;‡»;QQØØ<Îu3Áôéüø#mÛréo½Åë¯Ó¦ Æ1f -Zpÿ>?ý$ï«–,ÉŸâêJß¾|ÿ=3g2{6Ÿ}ÆàÁlÙ”)tïŽF#÷ï³t)]º˜ˆ­-Í›sø0Ÿ|† 8;çzñ[·æÿþÐPj×fÃ:vÄÝà`ÎÃÉ ­–®] ¡Où‚±x1*))$&rð Ьz}^vO¹rtïΆ%÷ê·öèãS©K–dû›,œ>t0F_> CDD„½½}Ö¼™ØØØ´´´2eʘ`>xð ‡Õ˜”””˜˜èããc±…ºF£¹ÿ¾kö$L£Ñx÷î]{{{S¯KI’rI‰‰Q«Õ>>>™KDGGgHHHHLL,—¹5˜…èèèäää¬#‘‘‘Z­ÖÇÇG’$En±Nϱ±±€»»ûs¡mñR³&S§R»6uëòî»4hÀ¹s$$È F÷JD„¼Ù (yY*gÎ`oO€ÜÒÉhääIt:FÆhäôé\tÏžE£‘׎&.Ž;wðõ•ßÍê|:r†wß%%…ØX.^´lŒæAÏžòvöæâ\»FZ+Vðë¯DGsù²ìg;–}ûX¼˜Ý»qw—…ƒƒåE[¶ä·ß¸z•èh5B’¨R…HJÂô‘ ¤I ó±¦ÓÏÛW®AAlߎ»;çÏ3v,À½{|ð'NàêJTo¼a–ïß_¶’]]Ñé¦gOêÖ¥];Î+=kÀÖv¾~,¼e«–{å^vlm©P¡¸•¼côe!99yĈ!!!-[¶¼|ùò;w–/_Þ±cÇŒŒŒñãÇ?~¼téÒ‘‘‘+V¬Ðét³gϾwï^³fÍZ¶l9}úô9sæüöÛoAAA—.]Z¹reÍš5³Î|ðàÁÔ®];666æ¿Ì‘Û·o÷ìÙÓÛÛ;!!!00pÉ’%YÑëõC‡ sssKLLܲeË7fÏžššÚ¬Y³Ž;Nž!;wî¼víZ¿~ýŠ[—gZµ¸x‘Çٲ…Þ½9q[[œœèÝ[°²zŸ¼-æÝs¥’jÕd3¨wor+üªRáìl¶–FÎUÒÆ†fͨU `Ð Ê—/¨z™<­Xb…''ºwÇÅ`ôh9Áåþ}nÞÄÖ–#G¨QC¶ 3/ˆZ•VVfËR¯G©4»~y¼2Ó}û2g%KâîNÕªsæàçdž ØÙ‘Ën€JÅÂ…Œþ},ZDF†å2&éðªbËâ-ƒZ‰Î]Á³Žpɼ,8;;Ï™3ÇÊÊêÕW_=zôèèÑ£M»ð;vì ùûï¿7mÚÔ±cÇI“&øá‡ÕªU ùä“O._¾¼páÂíÛ·¯]»vôèÑãÇÏ:mFFÆŒ3† ²~ýú5kÖFM¿—›7II¡cG&ND¥"9™jÕ°³#5•hÞggy#ÛÔØ0·€EÁÁH;wb0°aƒ|T»vœ9Cõêtè@­ZfCÐÕ•{÷ÈÜ'¨Q´Z:t M°³“ßrsãßÍ«´nÍÕ«´jE‡”.-ÛS¦ ‰‰$%‘šÊÁƒù\''®]C­ÎG,•+Ëöw»v´j%gÙ§§3lÍ›³r%³fqè,|èW®‘ÁÎÔ®MùòøúòÇ>Œ»{®Æ7 TÊç’7õê‘–Æœ9t=@ZåÊáèÈ‘#fM&5•³g©\™áÃiÓ†¨¨¼VQ(èøvÙS'O9s&…žôzBBò9å¬ètœ>]Ðt7 ØÆèK„B¡prrª]»¶B¡(UªÔýû÷Ô¨QÃÕÕU©T¶hÑâäÉ“ééé …Â´Ù-IÒáÇSRRúõëתU«¥K—ž;w.>>þ7ÞhÙ²e·nÝÔjõåË—›4i"I’««kùòåFsèСþù§uëÖ:uŠ?qâD¦F£ñäÉ“±±±­[·nÓ¦ÍáÇ÷ïß/ý‡iÑ£GÝ»woÕªÕ¯¿þzäÈc–À¥LI“ðþýûëÖ­kee¥P(V®\Ù¹sç"¿´Lrr²Z­vrr²y’`À—†Ó§©U‹ hÑ‚>}(_æÏgÚ4*T bEV­’%èÓ‡þý©Z•={,ÏVª3g2`AA8@Ù²]º0` R¹²`ÂÓ“ hÙ’*U\]ùõW>úˆÀ@X¼Ø<í´iŒA¥Jrlë_”DÅŠøû3`XV& €¶m©^F(Q¼åíînÁ3Úµ+NNT¯ÎðárìlAðð`áB¾ûŽÊ• `áB´Z–/ÇÚš/¾ uk>ø€¯¿–H:v”3îÇŽÅÎŽÙ³ùåÊ—çÓO™:Uö@ÛÚâå•3™=0à`Ú´¡aCòÈôö¦MœœèÔI5ŠeË(WŽáé^]®E Pàím¶õ;*Tàðas‰¢Üð©æU®q¹ï¿ÿ¾ WêF§ãÛo©^mÛò6éÞ¾}å\:àÙGlÓ¿\X[[gºâLæ]VcH­V[YYåhñêèèX¾|ù¿ÿþÐh4§OŸvqq™9s¦N§S*•’$YYY©Õj 3$T’$GGÇ¡C‡öéÓ¸~ýº‹iƒð?lllZµjõÓO?ñññ¦èÉ+V4-š‘‘*å†fcc£ÿosñæÍ›666eÊ”yôkS¤XYY™¢D*}AèÞÌ[ S§AI¢kW:v”³+2#™U*¦LaÒ¤lƒ9P(<˜äç¦T*¦McòdyòÌc ¦OgÊóáM›rö¬œu”u‰±c3Æý”´4ä‘-8sF.Ù“Ùæ±N–-Ë©ƒ³3?þháÊ<ÌìÙÌše¶e›5#4T^B’äq¶nÍfï–*ÅÞ½òüy_R ¥¢Ç° .¼páBµjÕò‘~¶±±aË>ø€þ!ßÛmƒÝ» Åß¿(tžá}ÙéÒ¥Ëáǯ_¿®V«×¬YÓ­[7•JåêêªÓé’““‡ V¯^½ìß¿_¥R­_¿þ§Ÿ~2Õ$ª\¹r… ììì^yå•-[¶/^¼xñ"`mmݱcÇõë×k4š´´´!C†˜¼°&$IêÚµë?ÿü­T*?þøãƒŽŽŽiii={ölß¾ýÕ«W/_¾leeµ|ùò•+W7oÞœ;wnzz: R©RRRNž<9wîÜ.]ºìر#!!!##£ÿþ1¯x^|¸¸¸´mÛ¶M›6*ÑŹH’¿˜5„P©äÁ¬&‹ÉfR©òJ£ÉœP©4X™ƒ9ŽÍœ0¥²@ë*æU€?ÿdÝ:óãàAÙ6‰©TÙ"2 ËE4 Y2*UbÕ*úö•7Á-ê¬Tš'ÉjÚšÎÂÙ9Û¦ëœõ äf ›Ô3]„;³oHH61¥ÒÂ¥éÔ2ÇsÈd=‹Öó¯U§VhhhUShêsŽBµuA‹|iµ”+' - žÄáËBrrò”)SlmmGŽ9jÔ¨•+W †/¿ürÒ¤Iüqÿþý%IªY³æÔ©SÆ—.]ºS§NmÛ¶-_¾üÂ… ?ûì³™3g–)S&Gé%++«¹sçŽ=ºY³f*TèܹóÂ… +UªôþûïGFFvèÐÁÎÎnРAµk×^²dɽ{÷"##ëÖ­Û¢E‹‰'öèÑÃÓÓ³råÊï¼óвeËeË–uìØ±]»v¾¾¾Ë—/:t¨‹‹‹——×wß}DEE­^½zàÀvvvýúõ›þøãf͚ݽ{·K—.¶¶¶}úô©^½ú;ï¼S£FÑ£GïØ±Ã.ë>ß3Fî^Á‹ÇÕ«ÙZCÞ¾‹Ë#gî›xóMtº§¦ÆÜ»g~©Ñ<µ™ Ž„de±øþó‰‡Ù+ŽX&3?O xnØ»w¯1Ž=šššúðxHHˆ••UýúõÕjunÇ žAt:V«ÕétƒA«ÕjµZ½^o4M/5ée¦pÖ‘‡rÌlz×´„Á`0z½^£ÑhµZ“Œ^¯7-jz7SÓˬódŽäXÔtH¦°éð¬oeÎfR#«ðcШQ#ààÁƒO2Inïg'==ýÔ©Siiiß={öl\\ÜÃãaaa•*UЉ‰yøÝ“é'ÿIíiª”)âñ,>þ÷°°lgtô(¾¾ŒÇ­[–OÙ`àÿ£m[Ú·/þë//Þ#"‚›7ß{øoU§ÓõêÕK©T®_¿þáwõz}HHHnŸ‹#Gޤ§§ ÏèKDÖ¡Yw‡%Izx³X©Tæ&oqæ‡ëšŒr{ù‹æ8$S°X õÙ!##ã§Ÿ~²±±éÓ§SfkK@ È“ôt$‰€rû>–$œœðóãäÉ¢ÕL x2žcT¯OÐë“Fcþ¢Á#"I’Ba¯R=+ÍCÓÒÒT*Õ3n4 ‚gŠýûéÐQ£ò’iÙ’† 7¹‚ç‹â4FFMlìšää=©©'4šÛÖÖJ£±8¢Š/: …F£U©JÛÛ×rrjV²ä ¥²8¿ª“’’Ôjµ«««H¥/¾úвeyë­Â]åâEÂÃqs#!!ÿd燹}ËKdÃþù‡ùó-¢ß¼YÎÍïÖ/¿ÌgžŒ ’“)Y2ŸÖ+W¸xîÜ¡GË2QQlÝÊ믛ëU žää…[[#;‚ç‹b3F32®†‡Öé•(¡÷ðÀÞ•ÊD3qAa`k4jÒÒÂÓÒÂãâ6ÇÄ,ñ÷ÿÁÉ©)OþÑhôòò*S¦ŒhZDFâèX諜:Å®]T¨ÀÕ«têôÈÉIµkþDÞ¬„îܱl‚tíJ‡¬^W=ùLŽå»ïX³&[&þÃ\¼ÈêÕ4iÂþý¹£vvüø#J%ƒD ¤§^Ï;°_›ƒ'NP·n!ë$<%ŠÇ‰Y~÷î‡ñÞÞ­Ð!< ’„£#ŽŽ”,iŒŠ ½v­}É’ãË”ùD’Šá#P¹råŠ+ŠTú"ãþ}>ûŒøxºw§E ŒFΞå?¸ŸJ•Ì-ί]ã—_ˆŠ¢Bú÷ÇÓ£‘vîÄhdð`*Uz„E&.Ž ¸{—·ß¦~}€ÔT–.%,Œ*U4víâôiRRøî;llèÞ]^åÀvì@«eà@s]åìYÖ®E¡ =Ýý”S§øì³Â×L xµ[H¯pûöOÏÙ;òEŠ­-eËnÞœìäÔÜÆ¦|q«#(\:t`âD ΟççŸiÒ„‰9{–;w¨[W£Ôë¹y“À@Úµãõ×ῌ3f0hzJâé IDAT=Gްk={Z^¢}{Ú¶E’0Í{ô:1|8’Ä…ܺEéÒ¬Yî]¼ò åËÓ©j5M›Ò´)~È Aæmúï¿g† Ãhäôivîäw,,ºi*0mööܹÅ ‹1nœœãrö,ÿÍàÁŽÝ°’%™3ììX³†>}xóM¼¼¸r…Áƒqp eÏ6o¦Z5:t }{îÞ¥Bš5£I zõÊëÊ»¹1`K—Ò­â;ÿ y¤ÎÁ Å£É ÅKQûf"#¿Q*O”.]ÄË 9qsÃÅ%úÎ)Fc›|? L¥û÷ïߟÙÂTðùí79ã£Ìƒ¾¾rÇ ªU‰ŒD­¦gO>ø€¸vM.ÆnkËìÙ|ú)ÞÞtìHd$wîðùçT­Jõêœ?OTT®ëf6FÊZsÇ”“$I¸»c4’€^O­ZeÊ‘AnÍÂ.\à믩Z•jÕÌm<²eqt¤reÙG{ç*ÈÁåÊÉ2×®ñÍ7T«Fµj?žkýók×8~œúõ©Z•iÓÈÈȶџIL ññ¼þ:U«Ò²%IIæ§*•üoÞôéCB;vä#&^fŠÚ3ÿ»¯¯AìO ž¼½ ýÛ`HS*‹ÎisãÆ ;;;±M_ôèAÇŽ@¶ɸ8£‘7ððàÚ5Nž$<;;`õj@n×>p wîðöÛüþ;ÆQªŸ|«¯ÊóIQ॥HµÚ(îži÷G (vlm‘¤„ôôËE¹htt´Ñhôôô L…J%{F³£[¶°n›7ó×_¼ù&¥Ja4òûïìÚÅ„ ²ŒZÍØ±8ÀÍ›¤¥áé‰JÅ[oñé§ìÛÇñã|ù¥lÔ>6nn4iÂ石oS¦Ð¾=™¥½üý™3‡¹{`ð`æÌaÏŽaæLnÞ”ÅptÄÞ^6s{öäØ1V®dË–-“eÞ}—y󨳇£G™9“Ëÿýu{yqø0?ÿÌ¿ÿ¢×óÚk„…±|9'N°a[¶Èsººrõ*+WòǤ¥Q¥ +òÅ9ÂÞ½|ûm^³¹Ñ¿?·n±oßã^8@ð¢S¤žÑôôKÖÖéÂ$xvpp =ý¢£cý"[1==]’$wQz±¨hÕŠªUÙ½›Œ ¾ü’ví$~ù…U«$&OæøqøÏ‹¹|9’Äðá¼þ:’ÄàåÅš5 =Zé¥ Ðþ’™„þóÏÌžÍ?ÀG™÷¸W¯æ×_9~œÀ@||96nD«¥R¥\SÑ«TaáB6mB©dìXœœP*26mB­& €’ÿµzh׎38ŽF¨P øé'ŽÃݾ}e±5øòKN">ž¦M±·gùr~ü‘åËQ(hÞüq¼›eËÒ»7 Òª•d(Rc4#㊭­:«1úçŸ\¿Î˜1¦WrÈÒž=,]JR+Wš¿I&9™¯¿æÔ)~üoï¼Ö]³†žZm‘¨(fÏ&,Œ~ýÌßàß~Kõê´iót–(GòÅ4oÎèÑä[:=#ƒ 8|˜iÓäµ—ŒŒÜ²æííIK;[”ª´oß¾yóæ6â7¹¨èÞ`ÈŒFsùŽvíhÝ@©äµ×¬­ùî;ôz9ºÔ„•ï¼Cÿþ²ä#‘õÛ`âDù‰óçc0 TfÛįY“š5Í/•JÞ~›·Þ’uÎ͇.IôèA·n9ÕëÓ‡7ÞÈy¬R™³òõê²2 …¹Þ¾BAïÞæ]~ÀÝI“ä¸ÕǮҿ?qqÄÄàãó˜3‚˜"5FFRiÌúŪReÝMS £G3u*Õªå“}ùï¿lÙÂwßåcež>ÍÊ•h44mJ@À#£~˜Ÿ~âî]¾ø‚2ẽ66E]¦*(ˆ1c˜4‰W^¡Q£|„CCùæÖ®¥B…"Qî™#×Î^J%:!·w •JåXEØÙyxCæá¬$YNÇyºí¬–_Þp]‹b<¶€Êd5ЀæÏ¢Sà¦8ÛnßNz:uê˜GŽåüyÒÒÐj¹~J•,jÎ$1‘à`Z¶Ì˾œ7õëIIaûvdþ|¹^ÉéÓܸ!gךêä]ºÄ¥K¨T¼òŠìŽÝ»—R¥8y…‚.]pr"*Šؽ›  ÂñµÅË‹ÄDöïÇÓóº GŽàïÏÙ³ètT¯Nr2‘‘Ü»G½zœ:E­ZÙ!™hµ8€³3wî Pа!žž–OÍÙ™Æqu%22×ÓÏ$6VN†‚¢çÉÍY@ðSœÆèÉ“:Dùòæ–eW¯rò$ééœ<‰­[çŸ$Iùx:W¯æË/ùýw>úÙ´ýá.äõ׉Œäüy¦Ogß>æÕW¹}›9sزOO¦NE­¦];öîåèQæÏ')‰#Gˆ‰ÁÁ#Gpr¢JÒÒ8~œÿý>0WWIKcêTâã©X¥’ºu¹s‡Ã‡qsã“OhÕŠeËØ½ÛÂözz:Ó§sçݺqã³g³eK^± :]žWù?„OâYàæÍ›7nÜ ôÎ;²D ‚—†â4FgÌ`ÉNŸ6ôëGË–>ÌÇçeéõܿϞ=ù‡6kÆgŸ¡×ŠŸ’DDß~Ëܹtíj¶äV®¤];æÏ'.ŽfÍØ»—Þ½Ñé8Q£Ø³‡O?%9™J•˜;—ÈHÚµ“ÃÈoo>ûŒ;w̵£‘”Þz‹?0xï=Ú¶¥Z5/fÚ4Þy‡èhüü,ŸÝ ALŸNT¯¾JHH®e¥ííñöæÐ!^y//ËŽƒˆvî§Ÿ ._¾|øðaaŒ @`â¹t—ÅÇÓ·/7Ò©S>’_|Á AcÜ8\]-ËôïOß¾ Ê”)ȃþþ,^,‡m™¬WWæÌA£¹E$À’%ò»AAÌ›g.25}z¶T¡?dÜ8óK“˜£#óçgë ýá‡rÌh«VX[³`A^U«¤m[;»\]žáá,ZDxx¶r§¹Q¶,ׯ3}:C‡š{L /$ju¶t½Û·Ù¿Ÿ­[¹}›ž=:GGÆŽ¥CÞŸ37Ž]»˜6Ñ£©PU«ðõÅÑ£‘Ï?çÒ%þþ›¸8:w¦uk-/ºb¿þÊÁƒògvâD$‰3g8p€×_7K:9¡ÑcT Ì›1ªRYvšò{ B“&¬ZÅ©Sùˆ)•ôé“37ÿáÕ•ÊlŽL0«¡Pd3Žs‘ÖÖÌJIÊiOgʘ YvíâÏ?ÍÎÎŒ%/ªPäïï4([–5k¨^=I B¶mãìYñXœÜºuK§Óùúú Ïh!‘’ÂG±};sçfïØ‘²e)QwwÒÒÐh¸t‰5k(Q‚hÕŠ„ÜÜäq9[«eûvºvåÈŒF|}9p WcÔÕ•Á!!|ÿ=îîtéBp°y¼Z5\]é×èÒåiž¾@ <§gi§'ÄT þ•Wò—,Ê.ÇÇ'[<¨vv8:²cGN³Ø"Œ]е êÖ5×s ÿüóÏÝ»wè#Z"*AAìÝ›3t»tiù‰Ég™”„Ñ(ß.zx`0šŠ›[ÎÙŒFbc¹qCÞ3©UËr-¶ÜHL”ï<%)[¢)Ô»uk±G!2ϱ1ú¼DP…qQô…$###))ÉÊÊJd/¶¶ŒɃ<Ȉ¹Š•)ƒááøùqînn˜ª¾š¬FͽcM5àš7gÔ(îÑš W®LX¯¾Jr2aaæñ°0lløòËÝs ÁË€0F‚¢ !!!##ÃÅÅEìÑ6*U>éz °atèÀÖ­Œ+oÐ[YÑ¢o½…¯/ãÆÑ´)3f0lçÎáàÀ?ÿ°}»åí½{ù¿ÿãÎâãéуæÍyÿ}¦Laà@nÜàܹlú¤¥=B{zÀDz:ÍšááÁ¼y¹ÆŠÏ/ÂÍŽ„ÜÝ-´8Ò鈉A¯G©ÄÓS4_䊳³s‹-”J¥Íc—ŸŒR¥ˆ‰!>^ý?^Þ‘·³ã×_)U ¥’O>¡m[¢¢èÙ“ äU*~þ™ $9ß±ysvíâèQt:ú÷7o÷ç 8˜É“Í/=<$:wfÇ®]£GJ–Äš¡×sý:Â<¶¶üõcÆðÛo̘QÜÚO›Ê½w[·hÐà)…7o2z4K—òp¤_t4|À­[dd°e eËæ5VˉT©òÈñ{öÊÈ‘âì9ÆÁÁ¡a5cO-X³†®]Y¸5ÌŸJ¥ÒœígcC«VŽup0Û¦€$áç—-T4""[99{{ÜÝñðÀÃ#çT õêå,Í6j'N0rdª× ™HøúQܪ…À õxàË–±eKJoƒ”ËSJ•bùrΜaĈü[ª¤¥ñé§|õµk?š|÷uêШѣ(¼„”)æMh4Où{0?>[c§öí™4éføúkŒÆ¼ºTyààðøÂ‚g™çÀ>œ5øë/ll˜65¶oç—_ÐhhØÑ£Q«™8‘³g¹u‹·ÞÂÍÙ³)Y’ˆ, ,Œ%7Μ0tâj5 ˜ý àåEÕªòHh(sæpû6Õª™sbÙ2©Y“±cqrÂÞ{ûœ?-11Ì›ÇåËxx0~<•*ñÃìØÁÙ³|ø!®® Jûöh4lØÀ`4Ò½;½{[ö}V­J›6üðƒ0FŸcbccm X·LðdØÚ´BÜ#¡PðÓOÙê£e­%\DöšàI¨Z•_e÷n4È«S´@ðÜñìûîØÁ¾}L›F‰Ìœ‰VKXcÆÐº5#G²l›6áàÀ°atêD™2¼÷#GâìLz:ƒÃÔ©øø0eŠ9`ΦNÍÖ¡>9™1cÌ TRR1''fÍ""‚¸8€ :”:u˜<™'X²Ä²ÂiiŒÉ;LžŒŸãÇ“šJ»vŒE™2ôëÇ„ Ô¬ ðË/Ì™ÃÀ¼ý6ß~˱c–'T©4ˆƒ9þi\PA‘óàÁƒuëÖ­X±"%%¥¸u<8:š"XP”T«FRóæq÷nq«"ŒÑÙñeË’˜ˆZ—.áé)[{¦ØÍ̈®Ò¥ñôdÖ,Ù–%KOοÿ&=ŽÍ!_¦tx??7pwÇ`CÅïÞ%1ÀÏÿgï®ã«ªÿ?€¿n÷vW÷®“±Ñ=J HIJKH)NA)t(¡ Cé”Pº$FëÞîòvþþ¸ç»À»ÁÆêó|ðÇîىϹìÞû¾Ÿx¿½½±s'¤ÒéÔá,V©©cb1¤R|÷5½•F+þ­ÉT¼Î‰Ï‡úôÁŒ–oó%­Z¡E ìÙƒ•+_á)#j.—Û¨Q#OOOY·òº\\pø0H0J4\z=‚šnATƒºŒ¾¤G,]Š%Kàæ†ãDZkµîÇÛññX¸mÛbèP4k†Nðå—øè#ää 9+WR¯äíÛ‘™‰÷Þ+ ±x1úõ£‚ÑfÍв%fÏÆðáØ½›š]úá‡8tsçâwðð!|}1u*¸¹ÁÎË–á½÷0h|}ñþû˜?Œ¼AAÐé°nŽ…H½?ÿ GG|û-ž?GJ Ƈ•Ö¯‡—®]Ãܹ°µEZfÌÀäÉ–¯›•…ñã‘”„O?ży`2áØ1,\Èå(,|“g(véÒ¥üüüwÞyÇÞ¾ºº k &ÙšÓ+3Ú–‘QÓÍ!´<£Ã}uÿöÜv ²¨Ž ê‚z>t(“¡m[=Š9spàT*ܽ‹?þÀ?àèQ0™Ø¾VVزóæ¡Q#„†b÷n89!3 `âD:„ÿû?#-Íò%¼¼°gÚ¶-âOLÄÊ•˜;Çcôèò;>99HH—‹Æac“ ¹¹hÙGŽ`Ù2ìÝ µááøåãða8;#8b16mBp0ÜÜpø0v;rs±p!>ù`Û6lÛ†ÄDËוHpø0Úµ+”óò°lfÌÀñã˜1£‚I®Ä+2ááá=Òét5Ý–·ÁƒåáÎzç†j`õÍ%ˆ éM¬;ê>Rf'_¶oM·… ˆWR¯zFOžÄýû0fLq}¦^½ S|?†³3š7‡@€^½pö,´ZXYA(ƒkkªtgt422ðì6l€B”dgÃâb1Ø%>|ÓÒ Ñ b1ñË/e6øƒðô)~ÿ™™xðË—SWï=ˆÅðõEa! ñìxåDyòòò”J¥•••PØ –™ÓAoÇéð§"õ¢JÝ…{ZDÏ«é ŽÂhõ¯ºo¶¾÷agz}ïm!ˆz£^£45o²dñEÛÒ‹) ÐéÔt:ŒF˜LNe4‚É„«+5«²IH¥¯Ú £±¸ ,VyÓFE"|ÿ=||‰˜„„`Ñ"ªa%éõ Ñ¨²Ù0ÊþþHMEb"¼½qëüüÀ函Z-µ›§'D"4o޾}¡×#)éå ¶ŽŽ`0ðü9||pï^y9’""@£Ë…DBõeZä燂<} ??\¾Œ-¨í44äæR£66psƒ£#ÆŒÑˆØØòÖ0½ÄÚöö¸rcÇâöí –ÿ¯ÈÙÙù³Ï>ÓëõLf½z¡•ÏŠnõ‘ßHïƒfLœ¾æ¬Ë€ îRf¢˜NR…ÕÂZÑ6SïžktdÑÜZs;û±ü˜´ôŠ#ˆz Á½b»tA@>þb1òó±x1µ½U+H¥èß..ؼ®®˜3K–`óf¨TðòÂÖ­°Q¬]‹óçŽ;w°oæÌAŸ>˜9sçbÛ6dd€Ã)³1Ïžaófdd@«EË–X³Æòn­[cØ0L˜kkÈdؽ›Úî䄿ÍÑ»7ÜÝ©L `åJ8…"öîµ|õ_Eh(ÂÃÁåâÖ-ªÍæû=t©©åµ™xu CüR‚†ÍdwöîÜ£mO\И=*Ûª×L¤‹”¨\:ׇm'eHt—Æ¥¡ÞŒì0Ê£|@ñ6[Cz=h´jYXσÑs稌K:`÷nðù Ó±};²²`4Âʪ¸ïP*Åþý(,„^©4ÆŒAß¾ËA§C,ŸoùŸ~ŠáË:8€NÇôéøðCèt`0”™,iÈôèÇ‘›‹Y³ ÂhıcÔ8{Ó¦¸x¶¶`0°|922`0@$BѲlìÝ‹‚èõpr†!CðÎ;Ë©I¥eB k×—Ûüé§èÛZ-x<*ïAÄFÿ® IDAT¼ 6‹mE·jÊnZÓ !ˆ:‰Ïo©RÁh|yâÖÿÔóo¢¶1™ TÒmlü«ãäõü¯ÙÕ•úË-^”#@ °°³yIP:IqLVP€°°R©é›5ƒ“,ÄšL&ÜÜ*n;;4i‚ü|˜—¸Ðé(*Éោ˅‡‡…3ˆD‰ŠÒh¥Ú¬TâæÍRû{{ÃÛ66ÅËžŠ0ÅOñæòòò>|èâââããSï3Þ[$‘HN:Õ®]»Ž;6%\Q…X,)‹å¥VÇ•ÕBo“ɆÍãµªŽ“×ó`´ åæâĉR%š„BËëë+«[7Ë‹¨Þœ\Ž#GJm0ÞÞÕr-â%×®]óñññn¨ÏxÓ¦Mׯ_¿cÇŒDeÑhl.·yA F‰ZA­†NÇçñªe°‹£¯ÊÛ6U˙Ֆ•Y"ÁŽÕur¢|)))ƒÁÑÑ‘Q}ÿÁµÛµk×FµlÙ2®y‘ A•A£1¥ÒÏãâΊÅ:ò"j–ш¤$ºƒÃg †¨â½+¯!ŽÄ[ @úê)ÁêƒÁ •Jù|~Ü¥@oÎʪ§XüYBBužÄ+ÊÌ„N×ÒÙy~5Ÿ|HDµèÕ«×°aÃì½ÉdJIIi°½ÂQ%h4–‹ËbÆ7!¡ÔŠ‚xkL&de!-Mèá±™Á¨®ô½u>½x±ÌŒH•¢Ñ@&«ÉoŸ‹ãäIêçìl|ýu™Å<+ËhDNNÅod:îÜ\Ž;w Ñ”·gT’’ðø1’“«¦…õ’­­m‹-Nºû’’““G}çÎŽ;Öt[¢nc±$¾¾'4š~¤P3ñ¶©Õˆ‰AFF/¯C"Ñ;Õw¡:?g4- WÁy®^ÅÖ­Ø·5µÐâþýâUùæÂ¤UÕ©”ŸÉ“±t)š7¯`·Y³ðÓO˜5 Ç/êÿ¯íÛáík×г'¦M«šFuEffæW_}Å*§° R©ž={æââòÓO?í.Ê‹Kµ‰\./,,ä×…ÅA<^ÓFegï‰ý?KfNÃåêÉÀQL&h4P( P@­æŠÅ“<=°XU±^»lu GX4ˆÅx÷]*ßg\.\“ ™¬¼cÕjœ?¦MñèôzÀË 99¸v J%¼½Ñ¾=ôzœ?«Wñü9†XŒÞ½!áÜ9´o;;ääàáCtë ééxôvvˆ‰ŸÀ@ÄÄ 'J% ЬZ¶­×®ÁË A£A»vðõE~>®^…\ŽFЮèt xð7oÂË«¸üRx8=BË–¥Ââ¼<ܺoo<| °¶Ft4>€€€âÄO©©¸u Z-¤RtïŽçÏqëÂÃqêžê*%//ï·ß~«éVDÃÂ`ˆ¤ÒÏÅâA Åm¥òqnîcƒ!ÕdR×t»ˆz‰F§;òxþöö|~k¯ V^ïC•¨Áhp04¸¹áæM\¼ˆ•+‘œŒ#Ц Ølœ8wß-óXsoŸÜÝa4B­†H„ ÀfÃÏ6`Õ*t숋†Ü\üõlmѹ3D",Z„­[ag‡/°r%Žƒµ5?ÆÈ‘hÖ nnP©àïƒñóÏ1*BBðûïpr‚BE‹ ÑÀÕ 220f ¦L€&M°u+fÏÆÐ¡8w_}…>À­[¸sC‡@L ³gøãX[S7’€Q£±j5ÜÜ`4bÚ4tí :[·bï^xx * £G£U+¸¹áôi´l‰ˆœ;‡œ\¹‚'OÀf—Œ2ðò— oo”ÛíGGØÙÁÍÍB²RÂìêÕ«‰‰‰£Göòòªé¶T©Tºzõjµš|þõ‡••••U]©bOãp<8[Û‘&“Ö`eh"ˆ7@£Óùtú[íI©Áè’%ÈÎFNÄbüôæÎÅÑ£ ±aø|¨Õ¥rZ4~<¦O­{ö@©Äo¿ÁÚ>>øùgbãFœ:…•+±k*|_b³Œ€(•`³ 6 ?}û"!J>ªRaøp|ó èt¨Õøýw¤¤à¯¿`cƒ°kÄ?bÐ ¬Yƒ¬,DDPç4íÚaäÈ—¯K£aþ|tïF#¦LA` ֬шI“pú4fÎÄÎpuÅ?‚ÍFa!ø||ôÞ{ƒcÕ*´iSÞ}‰Åؽ"vï.‚- ƒ?¬ fm°ÔjµL&£Óéõ¬¨X,ž4iRM·‚ Ðhl&Ó¶¦[AU¦¶£z=-£Gpv†V‹ü|èõˆˆ€ŸUy¨ukܺUÁIzô Â& xþ~r9\\ RY.ÈTWW4n ­ø(ggp¹0×m+ê6 Ñ«­ …xú±±Tß§ùŠ™™ÈÌÄgŸQ¥žÊ™£Yt•ÎA§ƒÇC~>bcñàîÝ€¬,xx@§Cd$¨‹Š*™ ŒN§z:+ìï4Ïh+s^‰L&S«Õ¶¶¶$¿&AAT¨¶£QQ¸xG¢Q#ܹƒÉ“@,FZU±73³â“”œå-¡KlØ@md³Ë ª´ZËK­.§ÓA£U|Q&NñC±íÛcûvªÊ0“ ¡,ÒÒ@§C…ƒŸ%OÈbQ½ž#FP[0™°¶F^ž…cM&èt·Ù¢äd ))0þÊlllpJþAaImOíÄáÀ`@r2¢¢…zõ½{¸|wïâĉʰ<ް0hµxþwîPÑ¡½= \»†gϨÐÓÙ§O#2¿üRq¤X¡^½œŒ;w V#2OŸB(DÏžøõWܿߧ–"™{7#" V#* áá–³,ñù8ú—Ëq÷.rr@£að`œ:…Ë—‘˜ˆ#G¨< ¸\œ=‹‡‘‘Qé–oÚ„áÃßìæ>Ÿ@’½AD…j{Ϩ—fÏÆÎ`0àá.l61~<¶l‹…îÝáèXæál6:u*5 ß±#V¬À8r:ÆŒ¡¶·nqã°?Øl¬XggÌ‹¥KñÍ7ðóƒ­-˜L°±AÛ¶ÔÏfÞÞ°µ&íÛÃ}zžÅ(Q×Ðh4ÿ×]bRO‚Q‚¨%\\\ …««kM7äõ ‚s"‚hx …¨²Yš_—Ë?þÛ¹AÔf5Œêtˆ…D±ø•Òv–Gåxòô,µbýÍed@©„‡HNâõ´k×®M›6u·[€H$JOO×ëõÌ×XïFu™Á`P*•ööö5Ý‚hXj,æ*(À÷ߣGª†P¥„†bñb|ðÁë[ŽßÇ€ضÍrjO‚xEt:½N£<Á`d¾J= ‚¨_²³³õz½°j;9‚¨H£¶¶Ø¾-[âêÕJ;oöî‹EUHª*ÇŽaÀ,YRæZ{‚(ŸR©T¿y„šÆf³ÝÜÜ’““åryM·… Þ•J•””äááAò`Ä[VcÃp4¬­áì ƒ¡‚=‚ÄDØÙáë¯Ñ¸1µRþ¥¾'µ»váÊèõhݳgC @b"¶lA\?¿ò.¤ÕÂß¿ruê ¢¤K—.ÅÆÆöíÛ×××·¦ÛòFìììòòòbccýüüHQS¢!Ðjµqqq"‘ˆŒÑÄÛWóS#33©¤ñ)•˜4 Z-¾ûŽŽX¸*•å=oÝž=˜9ß}//˜LP(0s&T*,X©óç£üŽ­–L%^ŸÑhLJJÊÉÉ©c|4ÍÝÝÅb=}ú4;;ÛTÎK” ê8“É”““óìÙ3“ÉäååU§çØDUÃÁWçÎ8Û¶A&³¼ÃÓ§ˆŠBÏžP*Ѫ<@NŽå=Õjäå!&t:†…PˆçÏŽnÝ T¢ukDF–Y™==«W#* ÞÞUs_D”ŸŸ_PP ‰ÞÚRÜjÅf³7nìì왑‘QPP ­Ú™1Qst:]aaaFFFTTÔ‹/$‰¿¿? 'ˆQëe­¬PXˆÇѯìì,ì› ‡Q…ŽZ´(³ eøâ ?Žà`´hŸ~‚L¹G‚Ë…É”•ßÓÓÓd2ét:òÑHÔ ƒÁ`°X¬Ú3.¯Óé’““³³³9ŽP(”J¥²ˆ¨e´ZmAAANNNjj*‡Ãñööæ[¬º^I5Œêõpw/o¦fÓ¦èÕ 3gbèPdg#:›6ÁÚú÷Gp0¢¢Ð§Z¶Äùó8~]º "nn°±­-:wÆ_`èPäå!5«VY.U€É„•Uy³W ¢B,«žE¢Eh4Á$ˆêSPPðâÅ &“éïï/ kOˆL/±µµ5™LZ­611ñéÓ§îîîR©ô ÿbk25‘•‡òöa±°v-NBr2¸\LZœåþë¯Ñª^¼ "È-™ ÎÎØ³ Ñ°~=þú `2ñÉ'älâpðü9ŒF²Œ‰¨4“Éd4IUw‚ ^ƒR©|þü¹³³³³³3y!j?Æáp5j$“Ébcc8::¾É k,ÍÎÆgŸ!9S¦T°§PˆO>±¼}ðàâ‡nn zy‘#F¼j“úõCH²³±zu™¨aQnnîüáææÖ½{÷úÚ9JDu0 111vvvnnn5Ý‚¨fN…#‹¹o¤½Æ‚Q±ëÖA €TZSMxÙˆx÷]$é=Qi2™,99™Éd’Á5‚ *%==]«Õ6%눺ÉÎÎ.'''&&¦Y³f¯ý XcÒL&||àèXéÂôՇɄ‹ ÜÜÈ0=Qi©©©z½ÞÙÙ™Ôs'âÕ †ŒŒ OOOòÖAÔQ4ÍÓÓÓœâµOBÂ.‚¨F HkO??AuÁ`P©TÖæe¹Äk‘Édááá•Jô‘žžYrËÁƒW¯^]ÕMk(X,ŸÏW(¯}ŒDèÞ½ûĉëzP‚ Þ2…BÁãñÈDó7qõêÕÙ³g«Kæz¬È‰'-ZTôÐ`0>|Ø›”½y]4M$¼öȸ@ƒ”„û÷ñá‡~õÏ?pr*/»ªN‡'OжmõµÎ²¤$\º„qã,üêŸ  S' ¿R© Õâí÷2p¹Ü7™»]›™L&µZ­Ñh Eaa¡Ñh¬éD¡Óé\.W(òx<.—ûæ+ßåry•¤il°rrrîß¿Ÿœœ|öìY//¯¶mÛfggŸ;w.''ÇÇÇ'00ÃáÈåò3gÎdffÚÚÚ¾÷Þ{ ãáÇñññgΜñôôlÖ¬™9½k‡júnê0‘H”œœüڇ׫`ôæMüý7æÍÃ[®€óìŽG‰oYU/7k×bÂøù½Îá øýwËÁè¾}xç2ƒQ“ ‰‰X¸»vA*­ÜlZË—ããѤÉë´91¿üb9Ý·ÎΖƒÑ°0ÌŸ“'acó:%^¢Õj“““srr —ˇ,Ò",½^¯R©’““ܼͩ¼¼¬¬¬Þä„4Ì}z½^­V ¹\®R© ÅôéÓ{õêµqãÆÈÈÈ   õë×'$$|òÉ'»wïÎÊÊ1b„Z­Öëõr¹ÜÜŸzûöm‰DB²¼ ‡£Óé^ûð:ðÈ͇ƒ”°Xps£ª(éõHH€^WW0‘ŸgÏpþ<>ýÄb*r’É “A(„“SåK™LHJ‚J©4D"Ðé0–…NNT’üü|DGãüyLŸÖÖ•ˆØT* ÈχBgçâªÈ˃PP(–†³gÑ­ìì PeK5¤¤Àh„›[™ñ·É„ÂBxy½+çç#) å¿‹ øé'üú+âã1v,Ú·ÇêÕÐh Ñ@©D~>‹û e2dgƒÇƒ»;Õæü|\¸€ŽáàPÜf­II0àáQÞw†ü|xzâ‡Jm”˛۷‡Býû1cÆÛ[&“ÉZ´hñ†‰Öj“É”›››Àb±üüüx<ùÈ$3£Ñ¨Õj322"""ÉÊÅ$‘H:vìx÷îÝaÆ …ÂK—.={öì‹/¾J¥Ã‡ß³gϸqã …Bá²eËŒF£³³³¹uäÈ‘æ“\¸páý÷ß'ÿ‰o‚N§¿I?ExꇇD¥Éɘ3 ­ àßÁçƒNÇŽ‰„ǩĥvvØ´ øë/¬_‘2‚‚0t( #?óçgq*(À’%hÓ¦¸+î矱cœœPP‘?ý¬^Ë—!B¯ÇÆps¸11? V­Â«$¡¡8u T*¸¸àÇ!áâE,X[[dgcútL˜€ýûqø0°|9ll0i†Ej*æÍCV øø`Ý:ˆD.¡ÕbÍüû/<<°kµ16–JïJ§#* ï¼c¹yùù ÁÊ• EH à￱q#¸\h4 Ñpü8„Bܼ‰Ï?‡‹ ÒÒ0y2¦MÃ8v 11X¹ÖÖ˜8Æ!7AAHK±¿üBE¨/1™°|9ÂÂÀ`àüyjcFÌït:âã1j”å6s8˜1›7c¼µBzÏž={ñâ…››[} FssscbbœœœœœœÈ{4A”d¬www‹Å±±±jµÚ××—ŒÔ™™™¹¹¹»víb2™:Î××W¯×Ï›7oݺuŸþ¹@ Xºt©_鯴´´ˆˆˆÙ³g×T› Ô‰L/^À×{ö`Â87nàøq„„à·ß`2a÷nXYaÕ*Lš„Æ±y3Ö®… ÒÓñí·;¡¡˜;ÁÁÈÊ¢Îùèî݃^_|7o""‚z˜˜ˆM›„_ŰaˆŠ‚N‡þÁ±cذ{÷¢uklÙ>‹!(~~ؾ+VÀÞ¾·&“!%?ü€Í›ñü9¢¢ŸeËðÁøõWL›†à`ddࣰz5\]1g¶oGïÞ0±y3 Š]»‡sç,_‚ÍFP&MBRµÅhÄÖ­ q𠂃Ëë>¤ÑÀ` &Z-¤R4oˆÇÖ­øé'¤¥áÁh4X¶ Ý»cï^Ì‹ï¿Gv6†ÇÖ­ðòÂ×_cûvôé“ ;v .¡¡ EAŽ-óºß|ƒÉ“[¼qÇ8t»v¡üY‹Ÿ|Ç—·OÒét2™ŒÅbÕ§¥ô&>>ÞÕÕÕÍÍD¢aF³¶¶ö÷÷ÏÏÏÏÎήéæ4\ ƒN§ˆŒŒ´²²²··_µjÕ®]»V®\Ù£G±XœššºvíÚ“'OvìØqݺuZ­Ö¼bL¯×GEE………ÙØØxzzÖðm4luãcfà@ØØÀÏ@­Æóçðð€Ÿôì‰K— ÓÁÙvvàpàâBu‰ED ;·oãéS¨TˆGn.$X±C©2Kb1öï/(‹ƒÉ„îÝ!#0ÀõëP©°?h4$$ 5 !‘€ÃA…³MÌ1€6m0z4µ±];xz¢ ¶¶Ðë‘›‹Œ ÂÖÝ»cíZ$%¡}{8;ƒÅ‚DB]¥°ׯƒÇúu›‹°0 ná¢4J…ÈJ%îÜÁøñpp€ Ê™±mmU«Œ‡Ñ·/fÏÆÀЬ<=¡ÕÂÛ24DD`î\ØØ o_0™ˆŒD×®àñÀbÁÁj³N‡ `0`ÃÈÏÇ;;Öò¥%’—Ãú+W0x0U"¡[·òžg>_~‰­[ñÑGo£~Ann®Á`°µµåYìæ­ƒL&SRR‡Ã©Oá5ATçææ'‰êë*ÆZÎÉÉI¡P>|øÄ‰[¶lñòòZ·n]ß¾}<جY36›½sçNOOÏ>}úäååy{{3™LooïìììÐÐпÿþ[ tëÖ­Þ¼×Qu#5GôzÐjA§S]zlv™G™L Ѧ 5~ݵkqµ'W×—wf0àãSüÐ<ïÓ\õÞd*þÁÕíÚ@Û¶°µE¥VR2™‹”>6o)Ùfóµ,>|‰¿?µÈ½m[4jôªÍ0ŸÓÜrsßgYèt ˆví0i†Çœ9èÞÚn>¶ä¤OóF: ÊJ÷f2¡iÓ×i3ƒE=t>í#GbÍüù'†­Ä%^ÍØ±c5 »œ¿Å:E¥Rååå5iÒ„ÔÈ®Íòóóõz½µµ5麮q‰D&“¥§§“ÞµѶmÛ   ÄÄĹs纻»ïܹóäÉ“<4hPß¾}i4Ú‚ Ξ={÷îÝN: :”N§wëÖmêÔ©YYY“'Oþ¿ÿû¿™3gÖôM4tuò]¬iSlÛ†äd¸ºâÊøùQQ‘½=ÔjäåQÑžØl¸»ãý÷¡Õ"9¹xVå·ß"77wŽæåá³Ïй3¾ú ¼½Á`àìY ŽÓ§!“@ÇŽ¸t ]ºÀÓ99P(¨P˜ÅBn.Õžr¸ºbá nÍÆvv¸{:áþ}Ô T\.RR`0€Á€@€–-!—cð`ðxHN®`YOI<Z¶ÄßcìX$%áÞ=ôécyO• 7nÀÝš6¥¾ ü‡__\»†wßÅ¿ÿB£9Û¦9ÒG×® ÓÁd" áá<µ"íÕµiƒ?ÿÄ”)P«qû¶ånà"¶¶˜9ÁÁ0 ¼¯+U‚ÅbIо-Õ …‚Éd’t3µ\HHȱcÇBCC[·nmÞ2þü©S§’xèí£ÓévvvYEóÀˆ·‹ÃáŒ*±ŒÀÑÑqêÔ©%whÞ¼ysó<³ÿáóùŸ~ú)€ÂÂÂÅ‹û½^ž¢êÔ`´h]<› ++Ðhx÷]´oÑ£ÁçC£ÁŠT/ióæ°±ÁèÑpsCp0ÜÝ1gV¬ÀöíP«áム¨3iiÈÊ*Z ˆ/î«sqÁüù Á¡C`2©˜µO\¿Žqã`oÜ\ŒÉ“ÀÏžž3ÞÞX¹² ˜x<êÌæÕúæ®Ó/¾À²e8}éé˜9“ pÅb ŒŠÉ“1t(¾ù_!C¨µD«W£M — Ã’%ÈËCj*D«VX¾_~‰‰Ñ·/t:ÐheŽe«Õظ‘šQXˆ… ac6»8¦ ÁfƒÃÁ¼y˜=×®!#sæÀÉ ˜LŒû »wãÝwQ}Ø*•êáÇR©ÔÃÃ£Þ j+•J;;»šnEƒõâÅ ‹åëëëîîN£ÑÒÓÓ>|ÈãñÜÝÝsrrÜÝÝKÆ=—.]jÑ¢©*YS8“ÉT«ÕU5¤ Õj§OŸþðáÃ*9AT>Ÿùòeggçª=mF‹*, (*Ö%ácS¥XY• ­h4¸»GEþ1/Oa\»ÑÑJqÿ>FޤÖÓ°ÙÅÁVIbñ˳?_…ƒõâ–øø”šÀjÆdâ¥ñ7++´hAýl0àÞ=äæÿÖÎmÛB(´œÐÞɉê¿,//tíZÜÝkmM 4Zñ´ Å·P„Á€—W©-æ f&îÜA~~ñoù|tí 6Ûr›ŠŸ±WñÕWÈȨܼÞÊÊÉɹ|ù²ÝøñãëM0j0êÍü׺(22òÓO?íß¿RRRJJÊ‘#G ÅСC[´háââò矪ÕêÅ‹»—~_;sæÌèÑ£ÉüÑšB£Ñ F¥Ê£—Ïd2eff¦¦¦:99‘×#Q˜L¦””.—«/™Š¨Šw®2}öRR`2aêTøûW®øÐÛ§×ãêUDEoiÖ¬jjxŠDOu}=&.]B\\ñ‰]»VÙù_úfR233µZ­½½}}ú´0™L¦rÖÍÕ,&&F.—÷îÝ»iÓ¦'Nœ`0d2™ÁÁÁ °°0**jÀ€%IKK‹ŒŒìÒ¥KMµ™P¯&“BÊTµB¡èÝ»÷› / FËd±«¯Öâpðõ×5݈J¢Ó1o^M7âͤ¥¥™L&2Ã’¨*;wîҥ˔)Sììì¦NJ§Ócbbš6mjÿõôôŒ*ù¥píÚµV­Z‘ÉõF3Ϫé†äryõ½`” ^_‡ìíí}þ;©‚ ^—^¯Ÿ?¾^¯¿páÂÌ™3»tébmm§×ëY,–Å-§OŸîÙ³g}êž'¢A©ÝcÏQ»988)¢ ]¿~ýÛo¿U©TÍš5ãóùl6»ÿþ=:sæÌ½{÷Žÿ¯¶XTT”N§‹ŠŠ’Éd÷ïßïÝ»wÍ6› ⵑžÑ¦V#;»‚¥A4;v ;xð Á`øå—_¤RéúõëÿýwGGÇöíÛ'$$¸páÂðáÃ=z$‰ÜÝÝI¹,‚ ê.ŒÖ°ˆ,Z„S§jºDåeffªÕjRGލB...Ë—/iã°aÆ ¦ÕjCBB¢££•JeQ͘7n|õÕWä¨q………7nÔh44mðàÁz½¾S§N¯2Ÿ>//ÏÊÊê S´FDD,]ºÔÇÇgÙ²eorž'—ËÙl¶ÅY7K—.ŽŽÞ°aC£JÕ0¬õêy0‹;w —ÃÙ]»R9‰òó½OŸB(Dÿþàñ “ ññHL„ŸºtARîÜAAѵ+ll•ŠÊ¦$—ãÙ3´ha9ûúƒ Ñðä ètRy‘ÒÒpñ"T*4kFU„øwî &—.ÍF›6àó¡ÕâÎDDÀÞ=z”™1J.ÇíÛˆ‡ƒŽѸ1ètxô"=‚B®]Ѹ1T*<|;;ܼ .}û‚ÍÆíÛˆ‹…€4i• ÷ï£uk…0ñô)Äb )±ˆ’nܸñìÙ³?üð¥ÚQMž>}zýúu¥Ryâĉ &˜7v­Â ñN:u÷îÝõë×oß¾ýúõëyyy;v|•`täÈ‘{öìqz•tƒeóôôìÞ½ûßÿý&'© -Z4`À€@KõZÁÈ‘#ÇŽ«P(Þ~êU=F·o§ÁÃéÓØ¸ž<Á˜1pv†¯/ärtèlÝŠþ‹ qý:Ú¶ÅîÝHM…³3ŽÇéÓØ¼wî`Ãüõ$üù'6lÀ™3–ƒÑÙ³¡P Güû/®]ömÈÉÁ§Ÿ‚Å‚·7Ö¬ÁÆ ÄÙ³¸{2ö탵5¼½Áfcóf=ŠÀ@œ:…sç°y³å²™!$-["?›6á×_Ñ´)òò0it:ªDªV‹Æ‘’BeªwsC^\]Áç#$ÍšA¡ÀÆ8p >ÿß}‡#—‡qãðý÷$-ÉdÊÈÈÐëõâ×H0K¯¥E‹¡¡¡&“‰c®€LÕC.—gff ­V›——çééÉ`0bbbø|¾F£IMM5™LB¡P"‘$$$ [[Û¨¨(&“¹bÅŠ””6›M£Ñ222är¹½½}zzºJ¥òööO§ÓœœìììRSSŸ>}£T*²³³…B¡J¥ÊÍÍ•J¥ŽŽŽ4Í`0$&&æççs¹\ooï¢^Ãääd™LÆd2=<<„B¡Ãÿ2Q'''k4çèè¨ÕjT*•‹‹‹¹ÿU­VÇÅÅ —¼¼<.—ëääd4òóóíìì\]]K†Ñ*•*55•Çã™L¦¬¬,£Ñ˜ššj4­­­“’’ †¹·2!!A¡PH$’¢ðZ.—ÇÇÇF©Tj.’’’Íçó=<ÅÝ»;âÀ Žëסӑ*š(,,,((‰D6665Ý¢¡`±XäËñ<{öléÒ¥æ.;;ÛÙÙÙÁÁ!>>>::zûö펎ŽsæÌ‰4iÒ_|1kÖ,F3}úô¿þú+??éÒ¥AAAË–-³µµÝ¶mÛ‘#GvìØáëë **ꫯ¾ºpá‚H$œœ|àÀÐÐÐüüüM›6 … &lذA©TúúúÒéôçÏŸ‡„„´jÕêï¿ÿ^´hQ§N›7o¾hÑ"‡óÇüðÃMš4‰ŒŒtqqÙ²eKQûçÎ9xðà¹sç.^¼øÉ“'~~~ÑÑÑ'N6l˜Z­^´hQdd¤——WFFFttôˆ#æÎ»eË–sçÎ5nÜøùóçÓ¦M2dHÑ ãââ¾ýöÛ´´´6mÚÐéô'Ož¬\¹²C‡!!!W®\ñññQ*•YYY»wï>xð`XX˜§§gDDÄܹs{õê•””dmm­×ëcccwìØ‘’’ìïïX²Šïùóç#"">|ûöí/¾øÂÙÙyÖ¬YB¡F£EFFþøã¶•*óXwÔ«`tëVüù'¬^N ÕbåJܽ {{ÈåÈÊ¢BUÞÞðóþWjÒ¬{wjLÜÚ:‚ƒqõ* P@©„Ñ©}ûâÐ!x{#:K–”×󸹽=ø|ªð½ÜÝA§£eK\¾ ­ÿ’“ƒädìØ={`0Àh„Riùü7n`Ñ"ØÚ‚ÃAL Š p¹xï=ªfQ¯­­-ºwó°Ë—ñÝw°±‡ƒ/ ×ƒFÈ ÅÓ§8tƒ ',b2™;w6 ¤Š ˆz¦cÇŽãÇ_µjÕ¡C‡´Zm“&MÖ®]»aÆٳgŸ:ujíÚµ+W®ìׯßG}Ä`0¦M›Ö¡C‡ää䈈ˆ­[·øôÓOͽøŸþù\]]×®]{ëÖ­¸¸¸ððð}ûö5nÜxÇŽ cþüùÛ·o6§SMLL\³fͯ¿þêää4wîÜ5kÖìÙ³ÇÚÚ:((¨oß¾III#GŽœ4i’­­í’%K¾ûî»áÇGDDü\Ô£ܾ}[¥R­[·®Gt:ÝÛÛ{Ô¨Q§OŸÞ½{wÿþýïÝ»wæÌ™ãÇûùù­_¿>..nÚ´iqqq{÷îݼys×®]ÿøãõë×wëÖÍþNM›6 úì³ÏæÍ›çéé¹jÕªõë×;vlÆŒ'Ož4hаaÃNœ8ñäÉ“#GŽœ8qÂÇÇççŸ^¶lY§N¶mÛÆçó·mÛf2™,X`4/\¸ ‘H–,Y’––öøñã’Ïü'Ÿ|räÈ‘1cÆ :À’%K ÆöíÛétúwß}W¥j‰zŒ~ò ÞU‚26—.a÷n´iƒ[·0aŠ d0øï<–’É\pþ<~ø¸wÓ¦QÛ?ú'bËøøXî°,‹@………°¶Fn.øüâY“ &Õ æÍ£nN/®Ãù’ÐP ˆÙ³a2aРâítº…˜tzñå üü3ÞóçÃhćRÛ}}Ѻ5ví­[˜;··Ö0ñùünݺÕt+‚ ªK“&Mlmm †Édêܹ3ƒÁpwwONNЬY³–-[îÛ·oÔ¨QÙÙÙ-Š*S—¡C‡\.·gÏžmÛ¶½pá˜1cüýý'L˜`qá]“&M¤R)Nçw–/_.—Ëœ:uêÏ?ÿ¤ÓéiiiZ­6))I©T¶oßžF£ùûû/]º”Ëåxüøñ”)S»uëF§Ó ƒ@ X¶lŸÏ—Éd …B§Ó…‡‡ÛØØ˜â;vìxæÌqqqñññ›6mÚ±c‡B¡Ðh4ùùùÁÁÁB¡Ð¼¦ÐÕÕÕËË‹N§wéÒå×_ÍÎÎ`gg×¶m[6›=bĈàà`[[ÛFÑh´Î;oÚ´)!!áÖ­[C‡5w[,_¾œÅb}ðÁóæÍëß¿=&NœXÖ“¦Ñhn߾ݳgOó­-_¾œÉd¦¦¦¾îÿg­V¯‚Q7·REç9 HI‹…Daa%NÅdÂ`@z:ž=ÃÎÅõÓ[´€³3ÄO?Yè×,GûöÐëqâZ´À±cèуŠ>y<äæâÔ)4j¸º¢qcœ>iÓ TâÁ|ô¸\ 'ä󑚊„\»†ÿÅäɯÚ VVHME|}”Jåo¿ýÖ¯_?2™¬   ##C­VgffªTªÌÌÌŒŒ F#“ÉÌœ‹/–H$“&M²³³3W³³³ 6wR>yò$,,,))éÈ‘#VVV\.W£Ñ †Gåå奥¥yxx´k×îСCééé'Ož\³f\.ÏÊÊrqqéÝ»÷ǼhÑ¢{÷îFsتÓéÂÂÂòóóÓÓÓÛµkWXXxùò夤¤'N˜ƒQ???©T.îß¿ðàA&“Ù¨Q£V­Z5oÞÜmGGG_ºt)))éàÁƒï¼óŽX,ÎÌÌÔjµ©©©æ±[·njµúï¿ÿNJJúõ×_;wîìéé9pàÀ3gÎÄÄÄ<{öì믿NMMݶmÛŋ۷o?bĈ‚‚ó}}ÿý÷………x<^zzúï¿ÿ¾cÇŽ~ýúýóÏ?ÑÑÑááá_|ñErrrFF†N§ËÌÌ4MΫêUÏèKh4LžŒQ£`0@(,—oÑëÖ½¼ó¬Y/;f † £Ž53“ƒk×0hœË»ô¦MÔÞÞØ¼™úyÄ VVÅáp0kV©«ûúbÇÈå`2-÷‰šùûãÐ!@$*ž` cçΗ÷tqÁþý¥¶x{ãàAêØ¢ ¼°7o‚ÃA¿~åÝ //oÿþýb±xĈ¯Þ%@Q'<}úôÊ•+:îÂ… Ož<éСÃÞ½{ù|~xx¸V«={öìèÑ£y<ÞСCsrrÌÝuÿþûïƒôzýþýû?øàƒ‹/šL¦Ã‡Óh4[[ÛëׯwèСk×®R©”Ãá,]ºÔh4Ž?ÞÜ-:mÚ´#GŽ †¡C‡^¹rÅßßÿÈ‘#IIIR©tÖ¬Yt:}ùòå«W¯þꫯÜÝÝ;uêtàÀ-Z¬]»výúõK–,ÑëõóæÍËÌ̼ví€ .ðù|[[Û 6¬Y³fáÂ…‡:wîœD"Ù·oŸyUÓ®]»Ž;fŽtH$’uëÖmÞ¼9,,ŒF£-^¼ø¿S$Éùóçþùg±X¼páBNwâÄ ›ÐÐP777OOÏ&Mš,]ºtß¾}L&ÓÊÊêûï¿g±XcÇŽÍËË[¶l‹Å=z´¿¿›6m//Ï`0mÿï–W§Õj Kn1Ëå?üðÇ~ø*ïäÿüóOÏž= C~~¾^¯/ç×kg-WXXèîî. þû[¹\~÷î]‹ †Ë—/—uZó‚³úÜ3ZåÜܰ~=ììð6¿ˆÅøøãR[|}«þ*L&¦NÅäÉôøfiiiz½^*•2™äDDƒ3oÞ<'''ƒÑ²eË*<íÓ§O9’™™¹{÷î)S¦”üƒÁxíŽ@óüÎ’[îÞ½{ãÆ ‰DµhÑ¢ ßÉÃÃÃCBB²³³÷ìÙSÎ’£"oXMª"¥•ÀáÀÛûm_T$z)?i4¼Yñ‹†ÅÚÚÚËËËœˆ„0™Lz½^§Ó™{ jº9ñ¦ÌKRØlv )ŒF¥V›úÿìw\UõÿÇŸw°÷^‚¨€PÜšÛiZnùº·©¸pf®rÔÌQæÖL3ÓrfnMs‡(Ê‘½á.îýýqÏO„±\Ø}>üãrøœÏçsŽ—{ßç=^o•*M£Q¼Ò…–. ÊÊʪR¥ŠBqUñò–²³Ë[° ‡F£133ËÎ>ÿÒæýË–ýïÑ£GùùùNN-ííyîZ¶¶ùsætÌÍÍ_éÆÞDR©¥Tj§§gûÚ*‹tƨ/ŒŸŸßs¥Lþ hË233•J¥H$‰D:cTÇ;€6z(‘HLLLlmm---ËÓÓò ¢VË32~ÎÈøU&»§VljDÉ"Ñ«5F¥R¬­ÉÌ,”šyYhej ââ^òÌÅ02Âȹ¼¼ i‹˜Ë?¾â¢ÑˆÀõô:EÿF£T¦*©2Yhzúáðð=.._XZv|¥‹¾SoØèhNœàíéP°u+ññÿäÄ«W¹wïeïæ¥’“ÀDD¼ªùÕjú÷'<üUÍÿoÈÏÏ*üößD¥REDDDGG»¸¸øøø8::š™™è,Qïzzz¦¦¦¶¶¶>>>999¡¡¡Ze¢·ÌÌ“÷ï·†Ýի˱°ÀÈHg‰êøWˆDèëcjŠ­-žž‡»õ‰§V翺Eß©÷ì¥K,\ÈÛ`'$&2>ß|Ãĉ|ù%ùeþj˺ŸeçNŽ{¥ü·= àïÿªæ××§}{–,yUóÿΜ9³uëÖÈÈÈ7½‘7ƒF£IHHÈÊÊòõõuttü{ˆu¼ó˜™™Õ¨QÃÜÜ<""âmkƨT>ŽŽæèåéùbMXtè('b1vvxyååæ~“”´áÕ-TBÈ‘‘¬^-¸û÷§sg4Nžd×.²²¨[—qãP«Y¸?ÿäþ}‚ƒ±¶fêT¬­K˜-"‚Í›Q«yðWWfÏÆÊŠ¨(–/çÉ$ºv¥{wîßçÛoINÆÚš¼<Œ™?33Îc˲²`ìØRËêçÏG&£^=7F©¤ €ÇùæT*îÞÅÎŽyó„®÷ë×sþÿÀԬɲeÅ5üß,jµ:"""%%å?Û’>'''!!ÁËËËÄÄäMïE‡Ž×T*uss {Ê5elìSÓh{û7½ï:FF¸ºªÂ–:8HÓÒ^ÉÀ«±t)„„0r$ææ×¯3nMš0i.°m´oO` vvtîL‡—<[B_¹9&pá?ÿ •E­Z„„Ä‚üõ±±>L“&ìßOÓ¦œ9Ãýû„†L` “&qý:ë×—ºçˆêÔÁɉ–-5 SSÒÓY¿©”à`nÝbß>€Ã‡ùæ† £}{fÍâöm¬¬èÖ OOjÕ¢[7Z¶xøQ£ðócÂÂÃY·®ÔuSRøøcBB¨S‡ñãÉÊÈÌdåJNbÔ(Ú¶EÛµáÏ?™=KKÆ:0%'óÑG„„а!£F‘Ÿ­-ë× pèÇ£mE&—óð!Õª ‹ªÕ=Ê?2z4õê1eŠp0;›±c™2…ÔTæÍC­æ§Ÿ°³#'‡k× dÃÔjBBøóOBBhÙ’ Ûîîèëó×_χ¼NÒÓÓsrrÌÍÍ­^Q¶ìÛZ­Ž‰‰±±±ùo^¾Žÿ,R©´J•*‰‰‰oO°>#ãhvö·W^X¢C€™ÎÎY}û¾S´B£ áá$$àêJÓ¦bo·7b1 pì"Í›S»6ÖÖ´nM‹eõ.ru¥š4¡~}!5³Z5œœ8q‚[·P*yðÀɉF°±¡aC¬¬ˆ‹ãÐ!ôõ©]±˜F8~¼ÔüÔAƒØ´‰]»Xº”?ÿ¢ðNNôïOÓ¦´iƒ6ÆûË/´iCÇŽô뇣#§OcnN»vT®Œ·7íÚ ®Í£G‰ð÷G$¢U+*õÒÚ·''‡£G‰'9™˜ḥ% й3ÇS³¦p00Ù³éØ‘€6mÈÎæèQbcÉÈ &†*UhЀD&ãûïéÓGˆ¥¤”„‹Káºb1ÿûM›2|¸pizz|ø!7npì þ) kÞœ€4 €ÔTòòرƒ®]Q«ñõ¥ €ë× §õò"6¶Ô‹}#¨T*;;»*Uªü7=£Úª''']zhE'22rÑ¢E;wî|zÎÍÍ‹‹{¶E¸Žg133355MOOÓÑ¢NO?`g§~[«ªt¼kˆD8: ø¤^: L?}:+VÂê IDAT0>3z4‘œÌ×_ 4(žsY6Ria~·Ö·t)¿üB¯^fÞ˜™ñ´˜‹ r9Éɤ¥:D6D./¹X¾G™;™ŒÁƒùþ{Á³«§'d‘&' ㆆ“˜Xò†ÉÊ*\Wë.ý;ÙÙŒXLË–Â>m]kjJ•*ÅÇk­y-yyŒƒJEëÖPP@V1c:ñ×_…YCC¤Ò"¹¹Ú´þ_üˆŽ¦sg>ú//ÌÍ‹ –H {¦¤ Trì§NÔ«‡™Y‘+zÛ´ú÷ï/—Ë%O¯á¿„L&‹Åï’§ãe±iÓ¦÷Þ{¯ú«’°°°‹Å»víêÖ­›VñûðáÃgΜY³fÍ«^º‚"‰ÌÌÌrssßôF4š™,ô™:t”ˆD‚¹9žž¯dò·ì«¾$llXµ ™Œ¯¿æàA¤zuÒÓÙ¼4òóÈеšð`â£G3`Ož°re©ÃªUÃÃo¾Áȵ¥’Ò¼cé鸻ãéÉG1r$QQ”˜h俯ƒBD;5µÐ^”Hx6-ÃÓ“J•„uµ×["™™DE±{7>>\ºTV4_˳Թ¹Ü»Ç¾}x{óçŸ,Z$oÞ==&O&0wwá ™NNÄÇãë[êä·oãàÀòåh4,XPê0GG¬¬¦qcaOU*bbðö~ÎU¼~¤Ré¶ñRvv¶‰‰‰Î-ZÔjuvv¶™™Ù³5^¹¹¹"‘Èø™,¢üü|FóôȺu묭­Ÿ£jµ:''ÇÈÈèïºB999b±X{¢B¡Ë妦¦Oÿk òóóŸýÏR©Tyyy¦¦¦ÚýØØØÔ©SçüùBùîƒvêÔé¿ù”UNLMMŸ`ï^Æ£^=ÂÂðócàÀ’GÎKNÑÑܼ‰©)µk—¬ ܳ'ÇóÙgdd Pж­pÜߟ… Q©ðð`ÈÚ·gÇÆŒ¡qcBCqqaòäf37ÇÅ…åË©U‹}ûx¡®FF¸»³t)þþüðCáqKK:vdÕ*öî-ú33ºtaË*UÂɉ „?×èÖ  E ¾ù†‚ììØ²¥Ð3Ú£«WS©¦¦ÎÎìØAÆCF§åT6•+Wؽ{÷ûï¿¿lÙ²ôôô… j4šýû÷oݺuΜ9óçÏß»wïÞ½{,X0iÒ¤/¾ø">>^©TvïÞÝÞÞ¾k×®!!!ŽŽŽëÖ­ [´hQ=öíÛ§Õ¼üä“O.]º7gΜªU«ÆÄÄ÷ïßÉ’%*•jñâÅ*•jáÂ…¾¾¾K–,ñöö¾}û60kÖ,‰D²dÉÿ~ø¡M›6–EU*._¾\¥J—g3Áuü7î} È!£”¯ÉŒñôä¹þôC‡(úøóV#•²e «Vý“@ë;²þþ¾‰2Œ^Õ©žÑ-hÑ¢øAWWÆŒ)~P,¦^=êÕ+k6''zö^7k&¼°°`Èâ#µõÞ½Úµ+\wôèçïÙÃîß§E ¡VÝÚZ0@À@á…DBË–%µ††´iC›6…Gœ>¼ðÇŒ Á|:zzxx0ujñÙ,, *~ðïwÉÍiÓŠQ*ùãÖ¯gÀÁ,~ŠŸÍ›JƈŅÏúú‚—Z,æ½÷xï½"giMggáGí–JéÔ‰NŠŒÌÏ'=½È%¿ ÄÆÆFGG»¹¹½MßI:Þ.Œœœ|}}[¶l)‹ûöí;mÚ´/¾øb÷îÝ|ðеk×}ûöuîÜÙÜÜ|ÆŒ={öœ?¾‘‘‘‰‰‰£££6LÿóÏ?÷ë×ÏÓÓÓÓÓ³nݺvvvffffff‰dÔ¨Qß~ûíŽ;²³³/\¸põêÕ¼¼¼?þø#77×ÕÕu×®]*•ªmÛ¶Õ«WÏÌÌyy¬XÁŠ…e¾ÅhÞ¶m{±òhÿ˜ à­¸¼ºRÇÞ½‹ëÅâWb·YZ²gÏËŸ¶‚"—ËÕjµ………½NcZÇ󈊊ÊÌÌ´²²ºpáBíÚµ%I½zõN:5tèP‰DrùòåfÍš¥¥¥mÛ¶múôéC‡mӦͭ[·´~€Û·ogffÖªUëܹs½{÷–Ëå-þ!‚5jäççûûûW©RåäÉ“çÏŸÿè£V®\9tèÐîÝ»/Z´èĉƒvss»téR```llì£GŠMróæMGGÇJÿÕü¸ŠŽDÂúõdf’“ƒHÄÎãäÄæÍ¤¥ ¶à‘#B&UiLŸÎ V£P0s&¬XDBV{öàëË—_²r%=z_˜Ê?dˆPóú””?¦wo|}™6Mß/XÀ† \¿Îа˗9q‚~ÀË‹&M˜9“„ŒR•Šñò"'‡Òt;V¯¦cGæÎE,&7CCÜÜX»–ÔTd2>ääIZµâÞ=Œ ÂÉ CC$®_çèQ6o¦F ZµbêT. Ö=‹¡!C‡2s&C‡¢s} èŒÑ ‰‰I©%A:^ýúõÓ–“¿é½èxÛÑh4ÁÁÁVVV—/_^·nX,;vì!CÆŽ«ÑhrrrÆŽ«V«>œ˜˜hdddllܤI iÓ¦»wïÎÏÏ1bÄ”)S† 6nÜ8…BñTk}„ FFF“'O^»v­¹¹yƒ :uêìããsóæÍO?ýTOO/22rüøñ^^^·oßîß¿¿¡¡áœ9s,Xžž®Åß½{wãÆ±±±Û·oŠŠjÔ¨‘Ù³²j:*r9&‹½=¹¹B±ìÝ»Œ‰Tг3憕FëÖb1††„†òèƒ$%áçGb"éé‚|Š‹‹{V"•+Ó¹3cÆ`bB³fÌœ)#"‚ìl>û ‰¥µºÐCY«–`üý̓/ Pp÷.ƒ ¹ÚÏã‡?…{{ÂÃqphтݻéÓ33‚‚0€„’’øüs¤R”JŠBŸîßiÕ víbêTt™Y¯1ªCGy144Ô%Õé(sçÎMLL qvv´…ð¦zõêÚXù/¿ü#‰fΜ©mj5kÖ¬»wïøúú>~üø³Ï>355µµµŠŠrppF=bÄ@+k ‹—.]zïÞ½¼¼¼ñãÇ;::_ýuDDDnnîèÑ£]]]:øøø$&&VªT©ÿþ@åÊ•çÏŸ¯ÑhÌÌÌ&Nœ8õïÉæ:*W®pó&/bcþ}̘FÃúõÔ®ÍÚµèéѯßó'y¶ÉƆʕ ,033lm10 % ;›2„ÿ¥R¾úŠØXnÝbìXš4¡KáWJ%0§¹9vv|ú©`ªJ$…mŸ­¬([«@_ ‹âº7ûöaoÏ7ß`lÌÈ‘ÂÁ*Uøùg"#ùõW–/§MŒŒprbútll„uˈ˜™1|8‹1p`Yö·Ž—ÂÚ}ð€;w„ªšb\¿Î‰…ÕKoŠšBuëö|‰¯78~kk¡è¿Fv62¶¶/ÿAV­Vë Éu<—ØØØÃ‡'$$ܹsçƒ>x¶ÖÍÜܼNÑB;;;»¢B)FFFuëÖÕ¾¾}ûöìÙ³ÇwêÔ©œœm˜¾jÕªÅV”J¥5ŸöUÀØØ¸V­Zņ¹»»»»»ïÞ½;66vÿþýÚ2)µZ½aÃóýW:*Ú®"11ÄÆ²v-€H„ƒ·oɃ?ÎßÞ5eÑ£Ÿ}Fr2NNܹƒ£#..ôèÁ‚H¥üü3Zá…‚ÐPîßG.çÆ ìì¨^˜Σ~}<<°´,ìZbgÇœ> ¾¾4lˆDÂÅ‹tè@f&‘‘…:ÖåÜá7ßP»6¦¦Ü¿O§N˜š’–Fd$±±üú+½zœ?OFU«R­ææH$Ô®¥%çÎÑ­„‡ãêZÖBíÚ±zµÐìZÇ+å2FÏžåØ1fÏ.¯Ph(Û¶•lŒJ$rîqqÏ7FoßæûïùüóÞp9Ñ×ÇÐÍ›©VíùÆèÅ‹:ôêÐ"!áÍ׿߹ÃäÉüòËK´“Ëå‡vpphذáVñ^Gy066îׯ_ß¾}]\\þ¥êB³fÍæÌ™igg·gÏçSÛ^ww÷+VO•2Åbq1™'‹Úµ6ŒI“JùàââFfÌ>ùSS&M*«kމ \¤¾KÒÒøâ CCfÍX°€+øòKjÖÄÎNH']¹’ü|ê×gÍ<<˜7‘ˆýûÙ±•Š?,TÂiÓ†+WX·–.ÅÎŽM›X½š£GÑhèÞ]Ø@åÊÏÑÃÑ2r$j5Ÿ~ŠZM£FtêÄÿþǽ{ciIP>>yy¬\‰D‚¾>Ó§ãä„Dºu¬XÁر¨ÕtìXª ¤++†gíZºwGW,ðJ©_«ZJ‰{{!D©$1‘ü|lm±²B­&)‰¿þâÌââ05þZJ$/Ç‹‹ÈÂçæòä "..à營R)Å*\•J’’ÈËÃÆkkÔjRR¸wÓ§‰G*ÅÖ‰†”2312ÂѱÔää VcnŽFCZffèë ¯ŒHJ¢ {{AôÌ™òÞ®êÕéß¿ðÇ‚ž•* ÷J¥"533á®Vª„ž2ññ¨Õ—*SP¯*;w2fÌËtŽ&&&Þ»w/--­~ýú/mRï"¶¶¶<+áû/033{YS=¥Q£F/wBo±˜™3™9³ÈA{û"íKÊÀÞ¾x¡ªXÌàÁ \ä`v6ƒcl̽{lÞŒ«+VVlÛV|6ww,asóÂÆ~Z4`çÎâÃJTr,q¶iÓŠhÚÛ³iSñaíÚ•àKª]›-[ž¿ÄSÚ·ç矹wOgŒ¾Z*€1zäK—"•¢RÄàÁÈå̛Dž H¥B†Šµ5!!ܾM|0dHɆÑöídf2m¹¹LšÄ„ øù‘›ËĉH$„…¡TÒ³'!!ÿüî)•|ý5?ü ´]¼öìáÒ%6m"#ƒáà ¢[7¦O'&FHè®S‡eËJY½š={05E­fÍ´¡¿½{9yR0pµšöãÇC~>ññxx¡¢b¨ÕÌŸ‡ãÇ£ÑÔŸÎöílÝŠ2íÛ3}:ÀãÇQ¥ ÷î¡T²nuë2|¸`›æçóûï%›øzzŒÍŠ ÀK¬ÇˆW©TŽŽŽÿåöK:t訸¬^MTTá66̘ñ¿à³üñëÖaf†\ÎêÕ¯IwoçÎ"¥ú‚¯÷uâàÀþý¯uÅÿ&Àݾ–-™1ƒÜ\!UåÐ!f÷n¼¼˜1ƒ5kX¾œ•+Ù¿ŸmÛØ¸SSJ‹;>ÌpàVVôé#üüs$D&ã£8¾PÅýYNb×.¶m£F >ûŒeËØ¸‘Ï?çôiV¬`ëV$,,xü˜Y³1‚Áƒ9s†Y³èرdñˆ´4¡½ZÍãÇBYŸZMx8nnìØQÜ}û¸t‰µkÙµ –/gÉöì¡wodÁRS15¥kW4bc15eóf?¦sgÚ·§zu–.eçNš4aìX¾ø‚Ý»22øí7¾ÿ__¢¢¨R…­[Ù´‰¨(¾ø‚Ò‚Ø M›2>Ÿ|‚BÁ®]¬\ Ф -Z`kKd$Íš1|866(\¼H§N,\HFvvDFrìý…ááe}†öìÉÒ¥ìÛ'Tƒ¾233õôô\]]ur÷:t計ԩS$/ÓØøÅbG}úо=*¦¦¥*.½t|}‹øLMŸSÛ¤£âRŒÑ€6oæÁ7ò;ÏžE.gÓ&D"""P(P*±±Âܶ¶eÉ]¹BÍšT©‚HDË–\ºDN.àêÊgŸdgó×_%£.ŸÏöí±±‚ùhe……zz<­CxôˆG¸|™{÷ÈË#%…¤¤’ÑÒ04dðಲ|ÊÏåËäç³k»v‘˜ÈÍ›¶¶¬XA‡X[s솆ÈdˆÅt숹9††øøpãr9 -Z Ó¼9sçNÛ®LѺŸíì05ÅØ˜²»Ö¶m˸qܼIn.YY ©©,[VØu-+«°Îqüx …[§ýŸíÕ‹¦Miݺ¬||ccFŒ`ýzz÷~išÍš5óõõµ{EMyuèСãÓ´é¿áõw– àu/ªãPŒÑ±c äâEÖ®åÆ ¾ú ¥//š7G$¢yslm)ì´  pð³ÞµúõÑÖ°6o.ä>ÿ†*UhÞ\øÑ¢Р¨ÑŠVh“›4Dï»t)l:ÿw”ÊÂÓŸ¢¯_²6Û?  €Ê• ÷ù„U«Ë˾=:tèÐñ_G¥"6ö…û^¦¤AD„ð òË…šÔ·¬¬âR¦o'©©DE &J…¦£_|A¯^±q#={bdÄÇS£ƒÓ¯½{sø°0²fMLM6Œ±cIM-y¶®]qwgà@úô!!AÈž5‹ðp‚‚è׈·l‰JÅÀ,[о=3lAAôíËÏ? Ã|}ñð`øp&N$9BBX¾\˜ðÓOK}£´nMv6½z1k‚i+ciY‚¯wð`ŽaÀŽy»×¢ݺ1x0AAôêÅ–-(¬Z…—£G‚¡!ëÖH¥ÜºEß¾ DÍš´l‰—ƒ3~<}úpá' s•BÞ¬ħŸ>g?VV8: }í¥RFb‚‚X»–ªU…ç ‰¤°x_˃tïNß¾akKQ¹Æèׇ9}º|·©L._¾|åÊ•ììì—0—:t¼e<~LÏžEb_åáûï9’.]øþû玊’Äžåî]FŒàíüd=p€%Kþùéqq/ €SŒ„._.×Ș>üQ£¸wï®õöPÂôË–‡L†³3îîˆD˜š²~=‘ ^^ÂHggLÉÒ ˜´jZÁ&wwÁL¬^={ˆŠB&£R¥ÂüN77öîåÉÁ445eÙ2>$- këÂummÙ½[X×Ú {w5âÑ#ôõñð(µð°Z5~ø¸8\\Ðh„Ø·±1K–”|Ùª$%='/ ã»ï„òCCæÍãáCRS±° Z5Äb†ÇÉ }}ôõùî;Áp—J™;77$||oîçŸÓ§yyxz Ö€=JøØª][з*»E‘¡!Â-‰øôSºvE.§jURS·´‹‹›û”zõؽ›äd ðñy~7TGGFbëVZ·.µ¦ª<¨Õê«W¯fddT®\Y×/Q‡ï¶¶ÌŸ_\ŸD&Ê JûH3†1c.ÁÛ"—£Ñ9ñøq®_gÆ"ÃÜÝ ÁظøºMñp¢BAAÁK«P(„T4©´0'—£V.!“•j%Ëdèë?GˆàìY¾úŠ‹K8WO¯TµG-üÁÖ­ÂeÙüù' ?ýôœ¯Ý A0FííKÈPÔ×§Fãíýœ MMKˆ8››ãçWòà§F' •–<¿¡aq9z—B-ÌÔTÎ+ò[??!bîêZ¼„XLåÊ%,!am-»eФ ùùE.ßsõê…¯ml°± ù‹ß©ÿâKhsaÿŽ¥¥ð  Rº«µÔ¬)ÜF‘¨øÕI¥…)êO½¡úúÅï§ž^¹4ÿŸ%8X”ý7¤¦¦æååYYYY¼-“ЉR©ŒŒŒ”ë²"t¼CˆÅbwwwÓ׬$ô*ÉÉaÞ<22P(¨QƒÉ“‰X´ˆÐPLMiÕJ6w. ÄÄP§wï2|8:°i•*Ñ¡Àÿþdž ÅH-ÉɬZÅǨT4mÊÈ‘äç3k7n–Æ€XY±`¦¦¬[ÇÅ‹88P·®à›P«ùá¾ÿ•ŠÎ0}}Ö¬!'‡»wIMåÿ£W¯øHÏÉaõj""((À×—ñã¹}›/¿D¥ÂƆœœ™5 CCöìáÇQ©hÙ’áË\ÚíÛ¬[Ç A4h@D„ÐìÔÊŠ‰K./IIaáB®\ááC ÀÒ’éÓqt$2’¯¾"&KK&NÄ×µšcÇ£S,fÚ4,-ùä2 IDATâ ®^%"BP'œ6­¬†¥‰‰BÍñ;@0Fß’’Š«ìŽQVUÓ¿Áß¿óñ¹èë3uêKÛ’BQüz,bÓ¿LM_Ìx-‘ÔÔTFãää¤S-ƒ”””Î;?Ðv­Õ¡ãÀØØøÐ¡C­žÚhŸï¿Äþòòˆ‰vê„§'3f V »óçiÒ„¤$.\ KÖ¬¡MnÞ,,W8t¨d1i 5¡}p0®®tîLÿþ˜˜ΰaèë -[µB_Ÿo¿ªx›7™>yó°µå“Opt¤sg®]ãÆ –-#<œ%KhÝúÊgçÀ¾üàñc4žøàƒ?þøãMoä%Ó£‰‰lÚÄôé´oφ e…¼Åâ’SUª²lÓ_eêTzõ¢^=îÝ{±*ïÌLìí_£¡¡B›XL^^¡µ<´oOB;w2g-[–êÍ}òcca]îߎÇÇS£çÎ1z466df’’—_ IÚŒr’šJZ«V ¢ýÞÞˆÅØÛ³p![·2t(††lÚ$èK–“„²³ß€øë+¢TÓÿòò^‡l„Z-t‡*çZ*•£ù–#“‘“Cnnñr%¥’œœwAKB‡:þ;H¥L›Æ™3ìÜÉÎ/öå( _[ááE,B©”¬¬BóôìY>üÏ>£k×"óK$¤¥=Ç”tqT ¸W×U{ªÝÛèÑ?Îöí\¿NbbÉêT!5•ÌLÔjîß/¬jèÔ‰mÛÈÉaéR ¨\™/¿äàA~ú‰o¾)+±M*¥ @0¦77\]Y¾\8wÓ&ªVE­¦iS¶oçìY\\ «ï%’“ Ï-33æÏgð`ޱ{òÖòŽ{FGbîÜ"=Ð^Lš„¹9 ”k­ßçòåçH ½q”JV¬àÚ5d2fΤqãÂ_9ÂæÍ88/|–ÈH=â½÷^ÃN_!NNN‰‰‰YYYæ/« :t¼!vìàî]ªV%,Œúõ‹IKcéR22HIaÆ lm™<¹äsýüøòKD".^,¢uݪ3g’™É{ïÑ¥ ,[†ÑÑ\¼H¯^°jÕX²„)S°·'8˜ÔT6m"&†˜æÌ¡reFŽäý÷Y»–™311áòår)F•;}œ=KíÚ*yس9%÷jöó+®±øTmÐÐ>@­&%¥H€††Å»@YX``€§'Ÿ|R丳³ #®½¨Ö­…ã¾¾ÅûK?­‰ ƒ¦¦En—RIzz‘³,-…¬P©” hРðWÆÆÅ/ÙĤÐsü, ‚)\6µk#1p _|A­ZÏÿ6óîÞ}ú):qó&»v±k™™|ö¾¾èé1bŸ}F·nÜ»ÇÀ´m‹±1‡ˆ‘ŸαctêÄ¡C\ºÄâÅ/¿²y3ÑÑT­Êž==Êúõ>"—ÿØz!ôô˜<™Þ½;¶,™´·kkk###ûòK‰è¨àh4š;vìÝ»W&“ 4(<<|ìØ±6ź•Dnn®L&+ÏȲY»ví¾}ûvíÚåS¢†á[CAAArr²­­myŒæüüüÌÌL{{{qI.\˜;wn¯^½>)f8èÐñ723 .Ò¨ó½÷hÖŒÏ?/2lÎ5z囹w¯xVâE…²Ù¯*U8r„„„ÂN=—wÊÍΪjž>#FðÉ'$'Ó¨W¯Ò¶-ß|#¨Näå±?ݺXÌÀTª$ˆ\„‡óý÷¬\I½z´oÏøñÄŽ@ÄyÜ8ÒÓÉϧV-fÏæñcŽA$bÓ&¡‘fBB©çn܈·7ë×£§‡\Žž§NÆéÓTª„ß~+¨9Ô¬É×_““ÃGI:¨T À¤I\¿NÏžÈå%¨ •Z͇²`"Q‘¬ Fƒøø°u+3gþÛ©Þ*•êðáÃóçÏ7x¡›¨£"£P(.\¸k×.™LöäÉ“¨¨¨ÜÜÜò˜˜GŽ9}úôÚÒêuËÍÌ™3÷ïß/{ëÁÒÓÓ‡ ²nݺòÄ .]º´dÉ’½{÷–˜{ݦM›ß~û-¹B4×ñ¦±°`Õª"Å=Ú ø¶mE†•–úr©^½øº¯¿¶ÝÌŒw£3à;eŒ®[Ç¡CK—>i}×vv88ðà5j0f ÉÉØØðè‘`_âáAÏžX[Ó£ÇOj*Ë–¡¯/Ëçä”wr9K–ðë¯ØÛ£Pµ‘‘x{ ošÚµK5F §];A=ºsçŽF£©Zµª———H$RSSoܸ¡P(\\\¼½½Ÿ>ùdggÇÇÇÎÎÎFFF>ŒŽŽ‹ÅZW}AAAXXX\\\¥J•,--sss+W®ldd{÷î]©TZ»ví¿;õóòònܸ‘™™ieeåãã#‰ŒÓÓÓãããÝÜÜjÔ¨ùàÁ???kkk !!!44T¡PT®\¹zõê"‘(***>>><<\{P,ß¿?&&ÆÒÒÒÏÏïÙ€»L&‹ŠŠzüøñýû÷]]]e2ÙíÛ·SRR,,,|||¬ŸÛVN‡ŽÿG,.¹àQ7Ö×/ì’­ã_òN£ýúѾ=<“í$%(•deamÍ/¿ RqâffÌËööìÞMD¿ÿÎâÅ´n©©PFçæ&ÌSþ̘~ù…õëiØë×…ñÖÖÜ¿OAÁsrF%,-yü¸ÈA rs11!1±¬¶ìRiyÿ&µÆ«RY<Õ¦""Q©-zŸK»v¸¹±e “&ýÃtèøg9räÓO?õ÷÷wss;{ölëÖ­322222òóóûí· .Lš4©yóæ .Œïի׺uëó<ªP(&L˜‘‘Q¯^½={öôìÙ³cÇŽÁÁÁ>lذazzº½½ýðáÃCBB:vìµjÕªï¾ûÎÚÚ:((¨J•*Õ«WŸ7oÞÔ©SßÿýÓ§O§¥¥;v¬R¥J 8|øð×_ݱcÇ[·n999-Y²äi´´+W®¤§§:tÈ××÷ã?ž={vXXX‹-~þùçúõë/]ºô ¼?tèÐñ6ñN£•*•ž¸e ¾¾\¼ˆJEÆ\¾L^‘”Ä?=*CC¹{—zõ¨V CCD"¡vççŸ4ˆìlþú‹nÝ(g?H}}Äbbc±´díZ22ZµbûvŽÅÅ…½{)CF½{wfϦsg*WæêUÞŸÚµ)(`×.7æÀ:uúg·§GGnÜ 4”°0ÂÂÊ©§‡·7?ýDíÚ¸¸¼pìC_Ÿ‘#™3‡áÃ+X(A.—;88XXXˆŠu&ÑQAÐÓÓëׯ߲eËFŒÑ£Gùóç=zôìÙ³uëÖMLLìÞ½ûÕ«WÓÓÓ]]]?~Ü®]»N:åååM›6môèÑîîî*•jùòå€ÍÇ|àÀM›6ÙØØœ8qbëÖ­ÕªUûè£Úµk—””äîîÞ¹sç'N̘1C»ú¼yóúöíÛ¯_¿¬¬,+W®4iÒdèСíÚµ‰DÛ·ooÒ¤ÉöíÛ W®\©§§çììlüÿ%ÊIIIÛ¶m 7nœT*Ÿ1cF³fÍD"Q¯^½Î;×µk×U«V 8pâĉùùù¿ÿþ{ÇŽ+Uª4oÞ¼zõêMœ8èÛ·ï?ü0bĈ¬¬,FchhxãÆ3gΜ:uÊÙÙ¹qãÆqqq5kÖ|ï½÷ ¾ýö[­ sÖ¬YmÚ´9r¤L&ëܹóÙ³g»víú¿ÿý¯Aƒ¦¦¦‰dï޽ݺu0`À?þ8jÔ(OOÏŒŒŒ+VL˜0¡C‡?îÝ»÷ýû÷ýþ¿ÅÙÙ¹k×®7nܘ4i’……Åõë×>¼ÿ~ŸÖ­[¿{Âò‹‚‚B±##!‹ì…xò„“'éÙ³05îíG¥âÏ?¹y[[ºt)kçqqœ\h«E©dÖ/Ç‚3ðòBO¯¾bñb¡-X—.ÏÑMÐhÉP«‹©\™)Søê+”J7¦KŒ dòd,@,Æß¿,c´sgÒÒX°€ü|||hßž*UøüsÖ¬aÓ&êÔàʕ…-I$‚\…ö…öÆÄ„–-K µ·hAóæ DÕªô쉀TJ£FÂ마DŒÍ’%L›ÆÈ‘‚¬T¾€¶Y·n,[ÆöíŒ]ÞSÞ?~\·n]333]Œ¾B#•J]\\sssooo‰Dbhhhll¬V«ÅbqÿþýÛµk÷èÑ£;v•=•­­-Ю];KKË)S¦tèСfÍš³gÏ.q¼¶•¹¹¹‡‡GxxxíÚµO:õóÏ?{{{?|øPô¿~ýz­Zµôôô€!C†<=7$$$))iêÔ©Úò äääÍ›7{xxxffæÈ‘#ÜÜÜÌÌÌÛ·oÏ™3G©T¶mÛÖÁÁÁÎÎÎÌÌ hüŒt°‹‹‹¶˜ÝØØøáǹ¹¹ýõ—öî%%%åææ^»vmÇŽµk׎yÚÑüžôéS|Ø!<óuS* ÎðáEvï^\€ã©H„¡!óæ ¯çÎ^¸¸°}{©K˜™•pgLLJ¸3€³sñãG²f å”76fÊ®_/×à·‡øøx•J•’’RðR>„t¼˜þÍíãíí]¯^=mt¾iÙ­ ÿÆñãÇþüòËÉ“'>|ж2OKKÓ&Aj 2µZ˜˜hccsöìÙß~ûíþýû–––ß}÷ÝñãÇ77·øøx­e|åÊ333m}HHHhhèˆ#>lcc³yófKKË;wêééݽ{W»{{{mÑZ­Nÿ›víÚMŸ>]$]¾|ÙÈÈÈÛÛûÛo¿Õh4FFFçÎËÏÏW*•@TTTTTTK­ÂÍÿcdddii9dÈ'Ožôôô¼uëÖÑ£G:äííýÃ?ìÙ³çÙSrss MLL¾øâ‹† ªÕêÇkML…B!•JÅb±X,ÖF²²²LLL”J¥¶,ìÉ“'·nÝz¿Ø—³Ž×ˆBAX—.!•²v-Ó§sü¸Ð-)3{û VF†P;af&h¦¤`cÃÚµÅå0““‘ˉ°µ-Ù'’›Kz:GŽ`jЧ'&&BéBARr9vv…_1YYde˜šbaA~>ii;†£#vv•å³LO'%œœÐÓC©$%…sçptdÔ( J x¦¥FZ³gãjµ è©­-ÎÊÂιœôt¤R2317ÇÖm,­ €ädT*¤RlmQ(HKãÌ<=©Qcc¬­™ªêÕ )²´¶ž‚¹œšŠžiiH$8; Â> … r%‘`k[ÞÈí[Ë;nŒ¾´R½À I>Ío¿þhjÊàÁÅ“o' àêZ(zü\úö¥oßW¹¡WÀ£G€ØØXMÎ:ÞbÔjõ£G E|||zzzrrrFFFbbbFF†B¡ˆŽŽvvvÖÓÓ0`@PPТE‹$‰F£‰‰‰Ñh4ÑÑÑöööiii2™,>>>777>>^{–»»»F£™2eJïÞ½Û·o_µjÕ¼¼<ÀÞÞ>::úÖ­[³gÏÖ:·lÙâîî~þüy##£fÍšEEE©Õê‹/zyyíÛ·HIIéÑ£GÏž=Ož<éèè8a„õë×ÇÇÇËår“ààà#GŽL›6í³Ï>suu½páÂÝ»w³²²n߾ݼys™LÖ·oßí۷׫W/44ôÁƒÚ«îׯßâÅ‹[µj%•J'Nœ¸víZ‡ÿ/²hРT*Ý·o_‹-V¬Xáç瘚ššýäÉmvéàÁƒwîÜY§Näää%K–lܸÑÌÌL£Ñ\¼xQ$ýôÓO999  …B›WÔ¹sçµk×ZXXÜ»woëÖ­Mš4‘Éd'NlÛ¶m·nݬ­­E"Ñ7¶oß>eÊggç;vôìÙsãÆ666ÚtU©Tªkuö¦¨úìu\TYÇwº`fèn´ ÛUQ±»cí^]׎5×\EQ1ÖÕ×XŒU±[QD@énf˜ºï3Râ(÷ûñ³{çpÎ=Ͻ0sŸyÎs~=ètXZj²¶RRп¿¦Àµ‘þøúúˆŒÄˆ‹‘“,[:«W#4$‰Ë—‹—øOžÄ¯¿ÂÈ))˜7¯ü˜ßåËXµ ááØ¾'O¢S'üü3òò0oÂÂ@’ÐÕÅÀÄoÞ`âD°ÙÈ˃£#V­BX/ÆóçHIÁ®]hÝ‹•]áá;™™P©Ð¯¦OGB&OƳgÈÌÄ€pvÆš5åoÃøýwœ>ˆL™}}lÜbùr89áþ}¬^<|ˆAƒ`e…ÌL0™Ø·ööɰ~=N‚¾>rr°q#’“±x1Þ¼—‹ 46K¥X¸·o£aCìÚ¥™7* Æ!=*Ú¶ÅêÕË1n²² •".óçcÈ(X±/ÂЙ™øõ×bAÖïÊý p¹Ÿ¢7«§‡’J‚j}Šïƒê¹Ýß#uëÖ½víZ¹‹’ßJ¥2,,løðáÑÑÑÇÞÞþÞ½{ÉÉÉC† «W¯žP(lÛ¶­‘‘Q¿~ýÔC.]º4þü›7oZ[[?xð {÷îïÞ½KJJJJJ6lØÙ³gÇŽKÄüùóCBBÂÃõ´´Ö®]  Y³f;vì>|¸ZMÓÇÇgÙ²eL&388X,‹Åâ-[¶?~\$ 4(22òÙ³gmÚ´ÙºukHHˆR©œ5k–‹‹Kpp°¿¿ÿ³gÏ\]]ûôéSt………Û¶m300˜9sfzzzzzz`` A«V­rvvvttT/èwïÞ]¡PìÛ·À¢E‹Ê,‚ëëëïÙ³g×®]¸röö ÃÎøóOxzâí[hkÃÕmÚ`ÂÔ©S¬ÃÏãaëV?Ž  ây·n…¶6ΜADúõÃO?¡~}$'£U+ÌŸ]»ðÇ2©©8~kÖ ];¤¤|÷aQPÎè7ÄÕ®®ßÚŠ pvv~ôèQÞÇ zQÔ0˜LfÉ,LÏRábbb^¼x‘íë뫎2Œ &u°´´ìñ>fÞ¼y%ǶmÛ¶mÛ¶%[Áš÷rsrrT*•››Û!CJæ÷éÓ§OQ¢ú{Ú´iÓ¦¨  v‹ÕÌž=»è¸Œ¸\îÆwíÚ¥vãh4Z¹³áää´¦D%_777·ÒߤY,Ö°aÆ•.¶Ó½{wµ«Z’~ýú•´vÒ¤I%Êf³‹²iy<Þ¬Y³Š~dcc³bÅŠ¢— 4hð5…Â)>`âDâÀìßž=!—ãÀ<~ ‚@t4Þ½[[¬Yƒáå…ž=QÑÆÎðp$:uªPƒ©®\€; ;@¡€“¢£€ÆñÓO(¯lB…Ü»‡qãÀåÂÃB!ž?GÆÕ3éc04D:àr5q\wîÀÁAª¬Vý>©û¤ÚX IDAT¢Cpp€‘ž>EýúàrѪètxyi²æ´µao ð÷ßhݺlê÷åŒRPPÔF"""æÏŸoddTÒ1ú,¨…–,Y²cÇ“/V…Ãáœ:uêöíÛéééS§NuppøBQüðøø€Å‚£#\]‡Ã‡ñè~ùææÅ%K|}qô(n߯±c8~—/W(#H£U¶+¨ ˜šj*ÿÕ©##¼½qä®_Ç©S ÁùóÅ¢Uæó“¤f›¯Ú…ýïùÿ*•F±d=ÒQ(@§Wè¯WAh¬¥ÑÀ`hl.j,Ú%ÆçcçN\½ŠÐPŒ5k4ÛTÔ{©Õäß?š3ªP =J% «ØÿNAQ)))\.—Êýr€\¡”+•¹RYޤPþ-v‰™:×_»û‡Í!¹œçñ)ŸñÌþc&ú™ “Dæg=sIX¦›ÎÊÌâpØ.÷UrFÕcj4‚Ðâ°µ8,6“ÁbÐi”L[$&‚ÉÄåËš*©©pqAݺÈÊš‚II07‡‹ <<àë ™ ,²²“• P© ­:u T"4~~H PTÕÕEj*ÒÓÁfC €·7NŸFëÖ‹‘ ‚ޏ8cøp4mŠÁƒ5EðxxùM›‚ŪP7ÐÍ ¡¡èѯ_#?¿lõùêÂfC.GDìíqýze=Ýݱw/?†³322 hji4$&"=]c³º&N^d²âF„…!7ïÞ!!¡ÂåS©h×íÚ!+K½‘±cѹ3 úOûõùќѠ ¬[''lÙò• ‚Qü`¨Tªƒ’$YXXø­mù1)ÉŸÆ&ÇgääÊdJƒÉü¦b®2 çÛÍþ9È•ŸZ—âGG¥TJ•‡¥Ã纘 ”KZu™__°X(,ÄêÕ00€¿?FŽÄСHH€©©f§üéÓØ½66ˆ‹Óh#¦¥aà@dd /þþpvÆæÍ06ƲeX¾!!HKØ1ø ¿£˜^½°jΜAÇŽ˜=âöm@O11˜>½{ãØ19ss$&Âǧ8,êï¥Kqæ Z¶,Ö“)Ä 1"%ݺ¡(!™Í®¬vLÉ›£¥UœÀçkÊe#=]ã_2šâ¸\ͽòöFÏž=HLÄêÕš©}}1g®_ר|ó&æÍÓ t놖-±|9F°aè×ÙÙhÒ^^P*!+9ª÷øed`ð`èè€ÉDJJq[.ÇãÇ_$áKó£9£§N¡o_Ìœù‰r Šääd‰DBÉÝ T$Ÿ‘sëMl®\Åå x<€Î î3Å‚F¹B¡”+ $±O^»šÔ57b3´ß'cd„ @’ ‹UœÜÝqö,’’ ƒÇƒBƒ¡IÈåàóáà‚€XŒß~+^ûæó5‹È¢m[M´µEm¼/š˜˜¨™W$ÂîÝxýR)ÄbM¶e` ÚµCa!¸\ØÛkTôì‰V­”TVUª$ãÒ%ÄÅÅ‚½}ñÊuÏž(ò]>¦¦Ø¸±TIí©Sáç’„±1Ôrjuëb×.ƒ8uªÆ<Ë–áÝ;dfB (¾ ;ÂÓ³Øæúõ±qcñÉÕá3ggœ?7oÀbÁÁAS|Å MÝQ ìÙFFFr2––Å"uuqôè÷!ËS†í=YP>ŸòD)>ÄÄD¹\nllÌüî’nj6*’|›ô &‰Íµù”Jñu Ñè46Éf˹Ü'ñiÉÙy­]ly,êÝ ,Vùºñ&&(“íÌá”a2Q‘ø‘Q)®tuK©„2™eÓ¹\¸¸”?VG§ê2Ýzzåä èë”»ÆfÃÞ¾T ‹U¼n®>­@P¬ŠST<kk¼/FQ¾Í"Qù!L¡°T;[[Í1‡£¹?4LMajZv,“ù)Ú>5êìL«ñ¨TË5Ú¹Ÿ†X,vvv¶±±¡Ukß&EU$fæ>z›Ä‹¹å‰R|}˜,¶HO?U"¿¯¢2Â)(j?NdôÍ>ŒÈHÔ­û­M¡øž±¶¶¶þðû,ÅC"“ߎŠcðøLÖw¢¦Kñ#BÐh|madJº©Ž¶­AUQ5 НÅû)(@LLq1EÍáE|J–TÎå—-ÈIAñ•a0™làALB¡‚ªôKAQSøqœQ77lßÜ¿ÿ­M¡øn‘J¥ùùùªÊEä(ª‰R¥JÌÊåð©ÕyŠ›Ã-+³ ¤ßÚÏFa¡f›ÑG"—C&ûbÖPPTŸÇ@£ÇCjê·¶ƒâ»%44tçÎE•¾)> R¹2G*c0~œ¤ Šï¦‘#ùAœQ¥S§bÐ ÁžšA n]´k‡¸¸ê OOMÕM ŠÂæŒàÒ%¬X¡¡¥ øxär¹•••­­-¥0úù©fÆÙ£É„_7zµïœšÿiÞøÛÑß?.Rô©¤ÆÇÍØãÓÆ¦''.Ü[ñ‰{¿ŒüöUø§ÍRsHŽ}ûÛ„‘)IŸ06=)á· #S>ÎÕ*‰ –ÈHòÁÕ˜4˜™™}‚=5öGËT$¨”ŠšÆø'IEµ(> ===•JE)Œ~Qb¢®œ<šŸ%‰Û÷¨kd¢R©žÝºñøæ5¥BîÙ®£SC6‡ËæpËî¾'É´Ä„«§e¤$[Ø×iÝËŸÉbÈÉH¿rêXÒ»ž@Ë·ÿ`~ùDð›gitúñmņ­{ö­È˜¼ì¬+'&ÄDq¸\ßþC Ì, %’Рw¯´Ä:üé«Tª“»¶˜ÚØ=¾qM[G§û°±lï|ÐþäØ˜¼ì¬ãÛ6ðí?˜¯-”Ë ÃΟyýø!‡Çkßo¾‰€;7›ÚØ?¾qU¬oÐeÈ(6—w1ø`âۨܬÌ»¶Ð錶?õê–SÀ;òé£Ç7®e¦&‡†~týª­kÝúÞ­®ý¢c`äêÙ@\Ôëð»·[õøéþ•ä²ÂèÏd…¯ö]<š‘‘’tý̉ä¸X+Ÿž}y‚ x—‡B!|ýêó;arYa}ïVZµþ¼PRñø¾‰•­oÿ!tãÎ¥sá÷ïrø<Ÿî}L¬m< û÷ñÍky¹¦Öv-ºöÒ‰/Ÿ8òöUxFrâ¹?÷ð´´[õøI×ÐX!“Ý¿zéÅÝ[ ˧G_3[ûr-ù÷¯èðçɉçƒö „âæ~ݵÄ:×ÏœtkâmdaàÁÕH’tjìyóÜi’ÄÛˆp.׺g?c+’$ßE„‡]ø;?;ÛÙÝË£¯:W$/'ûÚ_!#ÆŽÿ‘ÞéB!Þ½ÃÓ§°µW~Ÿœ<{†ÌÌ eä)(¾?Î[‘‚â³ð#=Ÿj ’üü=¿,P)ZµÕëäçæ¸wùâÎ¥s ÍÌM¬mw,šYîØìŒôÕ“Ge¥§ÖmÒüÖ…¿Ïí ÉÏÛ0s›g¶hÍRâcL¦HOŸÍå²¹<‘ž¾–PT‘12©tíÔÑá÷o7lÙš§¥ý†$É»¶\ >T¯YË´„¸Í?OR©T*¥òຕÿž9ѰEë»ÿ\=q„´Å:Zb:.ÒÓééÓètG_ÿ÷þ?ܼ¼ }ãÌ ¹Àá¿]=u´AsŸ»¡.=@K$ÖëÒè ‘®žHO¿¢lZ6—+ÒÓg0˜¡X¤§ÏhÈHI Þ²V&•8÷çž×OÒèŒëŸÜ»r‘‘¥•Xßpã¬I 1Q’ü¼õÓÇ%ÄDÕkÚüñÍk§þø½ZWOÛ»r‘©CýFñïï^¿Ú±xÖãW-ë8g¥¥J%göí<½{›}Ýúlwëüé9™î„^00³hؼõó;aAëU)•¡XK¤Cg0´ttÔWD’ä¹C{ŽoßdW·—/ؾhVVjJ¹–ð…"-±ÁÐëˆôôL‹Íyrë_õ,ÈÍ9¾mcNFº$/7dÇæŽrn왟“³uþôüÜœw/×MÇ 3ë4h²}Ó½Ë5Héi™)ÉzF&åÎøâä…¾¾8¾Â>»w£GØØ”S”ˆ‚âÛòFF)(>•J%“ÉX,åŒ~QrYnv_[hn_ÇÙÝ‹ÃãËe…ÿ;Ô¸UÛF­Ú‘¤*üþ×þ)7NöèÆÕB‰¤ËàQt³e·Ÿþ´ÏoðÈ×OƼ|±ñìU¾¶°±O;uÏ6½ý£ÃŸ1˜Ì6½ý+1&âñƒ¨çO¿x‹§¥Õ¸U;r™ìæÙS¦Îñl×ѱ¡{ {bÌCs+:6xæ}³ä¸wÑ/ž‚ švì’ô.æŸcAESÈ ÿÚ³mÚúÖN®¶®õþý+$îM„•£ €¡?/Ö31Mxò€T©¼ÚwJMˆ =äÓ£/³âåUs»:ævuÎÞïѦƒ­«¦ð¢w§îgözm`j~ÿê¥)«§Óé|zôi×g A/îÞºûÏy ‡:™)É#æ-çk I'wýÞuèh¾¶ðc~G¤Juáðþ΃F|x÷ Í-G-Z)Šäfe††î>|¬‹GSG¥âöÅso_½póòî;~ZäÓG™©)f¶ö/îÝ–J Ü[·7µ¶}p-Ô»S7=cSõØŽù éÜØË±¡ûƒk¡Ñ/Ÿ7Ð7øÐ˜†-Z›ÙÚß»|±©ou(@ ¿žAWu2*îÍë‚ü\·&Í0˜Ìž£Æ{´íX§~ã%ÃûE={òøæ5Cs‹V=~"ZJ\ì­ g=Ûu–@»ÊR’ß@[7ojê¼—ËäÉð÷‡³3Þ½«¢j<ÅW†rF¿YYøë/øù•Sžôùs¼yƒ®]¿…YsáÂgggoooÊýr„¢^£&„ìÜ|îÏ=ÆV6#æ/×10ÌHINŽ}ùô±º›g³rǦ'Æg§§múy²ú¥Ž!€ÌÔC3ót³Ê™š¬chÄ+ñô&UªÌÔµ³%Š´ÅâÌÔTCs+4õš;¯bÝþÌ´¹Lvrׂ Ð36•ª$Ò× ­£«ÞPó_61ë›8»7¹qö”¥ƒ“XÏÀ²Ž¦0¶¡™¥ZÆUd`˜ø6ZK$ÊÉÌØ±øgµ1bÃÙ,¥&/';;#ÝÀÔüØZÞGšs33¤ùùçƒö]> €ÃãÓh´œŒô5“é †µ³kVZ*Pþ¤yÙY…Ʌîž:€N¯Þ“¨NƒÆ 3üþ§aÿ:6ôÐ36IOJ`±9b#\€'ÐÊJOM}¾aÆõ(gw/õA£«ÿ_­Ik82ôô*óDÕBG¯_SÎ(EÍ‚rF+#8:uú”±99 Aóæå8£áìYÊ­Y¼{÷.))ÉÆÆ†fÿ¢Ñا]ãÖíÓ“þX6ÿê©c}ÆOéé7ðnÕ)`8d‘ÛD£ÑJî¡Öë˜ÙÙ/Ü}D½®­Þš-ÒÓOOJ,ÈËUçD’*•zÛ>“ÍV)«Ø-ÒÓÏJK-”°¹<*•Š ÑÄúù¹Ùòr²r23ÊÍæ,B¥T’$©þ›êê1˜Ì±ËÖ¨S'UJ¥zí¾Â±*ÕÇ8ˆ4M’ŸW²¥Moÿ=+¾|p·©oW“˜ÿŽ$IÈḚ̈q­§%›ÚØÍÞºOí¦WiLIÚBž@«h³IªÔmÙnB‡Ï4s‹Gêkyq÷–¬P:gÃ~-±Îõ³§ÎîßUÔŸ,ñ›åiiñ´´NŸ[·Isõ­¨â}G’d‰4mÝ-Zÿ½§$?oÈÏ‹Õ ¹,73€´ _*)êêš[²¸Ü±ËÖQòïJߨ„F§çd¤ä ù.ÈÈÀGþ†ét|’ªÅ¤Ö9£ òó¡RA"— ‘H³Í77¹¹ Ñ £ 2rsqå Äbxz‚ÉÔlÏW(™ ¹Aeö Àçc÷îR}¤Rde J_ÔDbccXZZRÎè¥ 7÷ï˜ÙÚóµµ%ùybC›Óª[ï£[×óµ…"}ƒ×4öi§^ݶrr9¶uý…Ãû Ì,ê{·jТõ¹ƒ{oú­AsŸ¸7¯eR©ßà‘v®õôL̬^Ö¬c·äw1Žöõ°vr=¹kË•“GµDbõþ›±¯×ÐÀÌ|÷/ šûõL|mfcçØÈã­ïñmØ\Þͳ§m\êšZÛV”m©­£›Ÿ›sj×ï"}¯ö8<~û¾ÛÍê9j‚\&»z>pѯ¹€<–´ àÌþ:Fî­ÛWÙ5±¶½pø@Zb‚©}Ý\Ü›Ðh´·¯Â'®ÚT$Spí¯öNy9QáÏúNœa`j²cóá¿yµï”û673Ãoð(ÆÇÉD4Z»¾ÏíˆÄl/#9¡Mïþå^~“ƒ·¬éZ0ñúñýþƒµute…Ò;¡çÚÂÓl-J‡åk rÙùCûÌì¶h-ÔÑójßéÈÆß %:ƒñêÁݶ}¨cÏÂáòT¤êâуöŽõš¶hÖ±ëùÃû-­íÜê«»Ée²»¶€ ž†ýËbs¬\Ú¢³&ü½—•£säÓÇæöuµlMÌ['-éGÐu Raûvüù'Ú´ù¨þžžØ¸ii ¤F)j µÎ}øcÇ‚ÇC^är9''¼{‡¡C‘’©ݺaéRÙ‹»·ÕÁN=#“ië¶…†9÷çmÝ]zàk §­ÛváÈóAû´ut]½4Kü^í:J%qo^ëWd ‡Ë›¾~祣Ïíãk ]<šÑkô$‡s)ø Xß`ÒªMjo²ûˆ1ê!Žœ÷5x­év<¹ùo^N¶z¯Ò€isBV/[»x6U›ÝmøXÀÔÆ€úÛ_[8eÍïn\‰{óº¾wËJîXÿÉ?_=},îÍë"‡•ÁdÚ¹Ö7¶´Ñ5,¾4Ïvß¼ªR*G/^eíèBÐhÓ7ì¸tôÐùÃx­f»~|d@û¾B]½{¡ä2YQ&®©µ­:粈^£'Ý8{úúÙS I§Æž\¾@¬oØoâ̰ÿýE£Óý†Œ’ª„ºzÃç.}øïå¸7¯]<šè6lŒž±iØù3*¥Ò±‘‡ â}fÚ:ºÃç.½åRÜ›×u4V7ꛚ7õíÂy¿uœÍåÙºÔ½öW—ϵh¥–H,ŠÆÿ²þÊ©àWï雚™[ª{j‰ušúv¹ò÷éiÃý99"fÌøXgtÍ\¹ë ÛDAQj3ZXˆÄD9OOøûãüy89iǰ0ÄÆ¢Ktî ܹƒiÓ £ƒ¹s5c/\À±c8zvvX²+V`Ïžòg=:  x5äâEܸ `d„€€¯q¥ÕbàÀùùù¼Š4Q(>,6§ó K7ÒéôÆ>튜ž"htzÃm¶(~ÆšÚØLŸ[¦›Ž¡Q¿‰3ÊNÄá´ûi@•öè›”Ëå úŒ›VÆŒþ“VÛºÖ+ÚK n“æê…f5l·ã€¡ -9¼ÿäYê+Gg+Gç¢v&ênJ…¢dü•  ³ÈÂ^‹~$/,Lˆ‰zzëú¨E+KF:m]ê¶ìÖ»ô¥™–¼4•J%/½(Ã`2TJU©y B}N:ƒÑÔ·KSß.%û[88Z88–la±9>=úøôèS²Ñ½u{÷Öíñu4.r%°8¥Æ’$©ËKæ-Ðh´¢Àª[ý¢(€‚ÜÜ'a×$yy}Ú–ì߬S7uð¸èrìêÖ·«[<°¯÷ß¹cóýçNÒhð¯lŸ^YôôлwÕÝ((¾&µÎ`h004Ä»wpëÚ·‡@''˜›ãáCøø”3ðÖ-äåaófˆGZšf­ÿcxøõêÁÚ:tÀ•+Ÿéb(>TPŠoÅé=ۢß½4²°ê3nZ¹«ê‘Ïmøµe×Þn^ÞE¦Ö¶Ú:U,‡ß»}þð¾’-½GO¾zþmD±¢¾®¡IŸñSËÊ»~r2Òƒ·¬ÍÍÊ(jqqoÚÁP¹/=xÿꥣÆ[j\I“eåäÂýè·°PGoþú­?€'JAñcPÑ)Jè&ID…ÉÝ2ììÐþýw~¡°zu,ŠVɪ³\Fñ5P(t:Ê¥øVx¶ëèêQ¬!ÀáóèŒò?&œy,Ù¼L£ÿûàk%˜Û9tX²EÏÄÔ«}çºMZµ°¸‡S »?<-í¶? (Y’ª饮ÃFw6ºd‹PWoü/_¶àÅ—ƒrFÀÕaaÈÊBr2bcѨ‘¦FCz:rrÀd‚ËE³f¸v ÎÎ01AA$”»@½;J½M*?ùùàrQ·.Nœ@Tôõú5/Ž¢  epp°¶¶v‡¨B ß+Û/=…¶Žî‡ÑÓj•eú¢0Y,k'ª.òò TBX±V›J…ôtˆÅß²¨©BìlˆDThé³ñ#änW ÚÚPç¬óxšEö±c‘œŒÞ½€V­àé©éìë‹ÿý~~X¼Ú·GÓ¦èÝþþhß'N”?EJ FŒÀ˜1HHÀ¸q>IIðõEýúèß½zááCP Â5‡””äèèèwïÞ}¼#Å—`íZLZª%:7n¿LIA£Fˆ,¿L[Ybcqõêç4OÍóçhÓ11Ÿù´ V­ú"×|j]d´A9¢©_?gަÑÖ¡¡› '§âï[mÚàî]dfB½rÅãaÍÄÆ"1FF°°( }}¬[‡"yD:úú`0°oÂáRÁÊ Õ©ÌGñeIHHU(¦¦¦TX´¦A’¤L*e²ÙUny–JãÞD*å2c+›Jöe %‡Ce}PÔ@ ¨T ˆRËzêä•¿Ï ÐhP© Ri:Ëdš]ùEê‚€T §üÀ!IB.“Y,,¥E§C¡@x_,$ …×®áüy¸»—2›$!‘€FCE%ÌÔco߯hÒC3£R ¥tz±yj“€RV©¯—$¡Tß™ Ê.är¤f¬B‚(uf… ”JÍ#ˆ mær!‘`åJxyUØçG¥Ö9£l6 Þל•xfñùhܸœþ|~©(&KKXjB‹øøR'wv› #£rNÅdRŠN5‘‚‹Å²°° ¼‡šF^vÖ¶ù3ü'Ï*·:hJ…"hý¯ÏïÞ24³è6|LÉmן ’$oœ=U§»¾IÕâ_ë§>o™ºî%EÍáî]lÞ¬ ” ¦‘‚Ú¸7o‚N‡Pˆ9s`V¾Ø+,_SS\½Š‚´l‰ñã1dvì€@€;wpõ*¦MÃýû L†GЬæÍÇIÈR)ÆŒÁ¢EÝCAAÈÌÄ€˜=iiðöÖ<޳³1g>Db" ‚™.Ô Ù½/^€ÁÀòåpu-ÇÚøx,]Š/Aƒ`lŒ ãͬ_ôthiaæLØÚ"+ ›6!<$ 77Œ«ñ 6m‚H„{÷”wwüü3°v-23am­¹*ŽGHT*4nŒ1c…ÆïŚ5˜<»wƒÃÁ; ,Z„ú|J (¡¡èرü?*µn™þóríV­*þ·m›FÖžâ;¢E ËQ£F9;;WÝ•âë¢R*âÞDJ$ê— ¹\&•äå*d²‚¼\µ´§\&ËÍÊ|õð^À´¹ãV¬³qv —*ärI^ž$?¯"ÉzJ…BVXX(•äæ¨Ï¦F.+ÌÏÍ‘ä« ¹\šŸwöÏݱ‘¯¤E=U*¥$?¯ 7WUzÏcläk¹¬5ŒÄDtíŠY³Ð½;üý‘ ¹¹7³fÅÂŒ•­ÚݾE‹Ð²%„P’Ĺsš€bRîßI") [·¢n],_ŽýûVÎy¸\ÄÆâÖ-(•H@’A@ ÀÈ‘ÐÑÁÇšž|>†G‡ptÄäÉ(–¯IIÁâÅ ±iSÙ8¥]]Œ??ØÚbòd  ÙÙŸ3 £ƒ9sPP€‚`Ò$L™‚ÐP:¤9ÃÇX¼ŽŽ8ººHJ˜1°³ÃŠÈÉAN<ŽÙ³Ñ¡þÔ IDATFŒÀž=†  Í֥ϟãæMðx¸p÷îaÁ˜šbÉ’ o²µ5zõ¦Mµ®JV­‹Œ~^ À€ª¥ )j:ººUÈâP|#:ƒY°¾zúصÓÇs33 -,Óº›»ô‡öÞùç 1Q®ý…¯-ì;~š[ý õ«2R’ßF“*•{›½FO*w¡ÿöų×Μf¤$ÙºÔ»l5N{±wåâÌÔ›Ýwü´úÍ}®ž:zí¯„è7‡7þÆå Z÷êײk/…\¼yí“°r¹›—wÀô¹Eªò &ã«{NñcàãƒcÇpø0$H¥HN†Pˆþýqæ Þ¼A|<ÂÃ5«É1q"FŒ¨b–úõÑ·/x<¸»#¡‚*WãömcÓ&lÚ„/°|9˜L4jcãâ\LuËË—ˆŒ„—W©3LŠzõ4~›ºäa¸\4j¤ñz‹ÆÞ¿ôt4o™ îî¸xÉɰ°€›._FR¤R<}Z|’=0a‚æøÊH$3˜<Àµk00@ÿþ`±Ð½;þþ‹!3/^`Ù2 Š;wàé ,ÆC£FJ1yr…w 0p ŽEX¼½+ìöãAEF)j5$IPÛ–j,<-í¡s–¾/œ“–jdaÕeh`lÄˉ¿n¼wùbnV¦OϾ£—üfliÓgÜÔq¿¬µvv%I2ámTFJòÏ[öŒ\¸â|оWî–{þœÌŒˆG÷‡Í]úóï{_Ü ‹zþT¥TZ÷«¶Xgù¡S>=úþ>ºTRФC—ñ+Ö[Úô9~â¯ÒÒàùsbýzøûC$ªÂý ðúuõ–•œ‡;w0y2¶n…µµÆQ+‚@AAñžàê¢Þ³¥F_FFX»'N $;vÀÄW¯¢M,\ˆž=QºHY)¯ÚÐHJ€¸8ä瀽=²²•• qq°·‡®.¬­±{7úôÁãLj…›[õ ¦Ó1|8<(NW¨ PÎheH¥ÅÛú¾!6`Ð ôë‡;>R)>‘øx«gÏ”’÷Y‰?4MSŒ‡ƒÁ|Ì(•JI’dAn®º”¤ù|m!ƒÁd0˜[µkتm¹Ý((jžžX¼»vaÀ›eoäd,[†U«°vmµÑ&MðóÏØ°»wWo  ˜šÂÏ11hÔL&^¼Àºu¸}ááX··ni:[Yáùs̘½{QÝjSSDD`Ò$üñòòP¿>êÖÅĉؼ `òdäç£Y3„…aÍL›†ÿ­ðT..ppÀ”)ظsæhœã–-A˜=Ë–áâEôëÍš!:=zÀÂry…Â;•P§Z¶Ä¶mµ(EåŒVƪU‹‹SF¾;£IÌžÄÄolÉGÛ¶AII£Ê•? ønQ*•¯ÝoÚ±«4??9.¶Y§n9F£[ÙÄF¾rv÷Šz--È7¶Ò¬Û!—* ‚F£ÑhVN®*¥²}¿:^(•”[º³ˆ¨çO.Ÿ<Ú+p¢HOÿ¿^ŧ²gއD‚%KˆD8y7n€NÇþýˆŠªl…}ôh¸”®K°s'þø*¶oGAèt¸¹aØ0ÍI†‡mÅÅV¬€P¬]‹&MhÔ—:wÖt(J]mÚ 2Rã+kkcÉ€FÖ¬’—‹»;@D„¦¼"›]»pîâãanŽž=ÁãÁ×,^½‚»;zõ*ñÀܼøT|>öîÅéÓÈÏÇòåÈÍ…ž„BãÒ%(8p@“œÚ¥ ´´àà€iÓ ¡2ÆÓèðXX`úô VÃdbÌøûãåKÔ’½µµÑMMÅ‹pó&tuÑ­¸\DDàÚ5èØææHLÄ¿ÿâþ}hiÁÐFFhÑxòÍšÉÄÓ§ Ó5%ÏžA.G\Þ¼³3Ú´Á¿ÿ‚Ïǃ Óѽ;ôôÊ·$<2êÕƒ\Ž›7áê ]](¸qFF¸~R)Ú´£#P{l¾b1³JKŠšÎ 34Ád“ÅRo"0Y¬’¿D‚ nž;]()ÈHJds¹}ÚUpB:ƒ©yŽ1™,Æ`2» ܳrQldÄ«G÷[÷ì«Îþ$©‘ûÁu+®œ:ÖÔ·‹g»ŽÝ†þmÒ¨ 3Ç‹ô "Ÿ<0u¶‹G“Š,ñò|Ð>¿AUmý  ø’èè`äȲ  AÍq³fË5 ÐEðù¿°kײc1o^©›â´ËN@")µÂNàóAèÐAÓ2p æÀÉ NNå[îáâ—C†hLMaj …¹¹¥ús¹Å^u™±\.zö,Õ™FCûöÅ…¾‹h÷Ádžž^±fS¶¶e}n33ÍEÝ[õö&5èÛ·œk,ƒ›–-«v¬úû¥6:£¯^að`èê¢qc$'ÃË ‘‘;½zA"ÁîÝ AVnÞDb"23qó&œœÐ¢¢¢°lއPˆƒÁá`Ñ"8tGŽÀÆÖÖ¸rX²‰‰è×7nàÎlߎr%,CB‘5k ‘`ùr,] ]]`ÁddÀÉ 4RS5³PPÔršûu'I’¯-:{W 5zÉoÚb],wØÜ¥¦Å‰t:#`ú5ÐPÌž]juøèQØW¦ó[óæáŸŠ_ 8¸”È÷'43g–jY·>>ŸsН‡£Yô¯%ÔFg‹…}ûàêªyË…þý5kýû㟀õë1mtt0wnÕ'´¶ÆÉ“àó!“i¾MžŒÀ@üû/¦LAnneÙÙ"—Ãß_S ª&$­RPÔtLÔNŠJ™Óh4 û:e:óµ´¶l£>&I2?7§äOÙ“ÅëŠõ aáà¨þAÖN®ÖNèh„Uéâé<-­zÍZ|Œål.¯÷˜òå¥((j:Ç,? kÖ|γ•K¹qMŠï‹ZêŒZYirŠi4de!>àÔ)ÈÊÒl3¬M›jtΊ’W@$Ÿ_ím€|>Z¶Ô×¶š`ÿÞºg_S›bI~Þ’¡¥ƺ Õ¼Kφ~)N›Su' ŠÚJ-uFéôâus>\.–,ÁO?U1J]oWªüd™‰2'T×ÀP*KF+_v¸öl¬£ ødh4ZQLT O µêøÿ¾•=•C-ÉDÏžøýw<}Š„ì܉·o5?ÒÒÂ;¸}‘‘ £ƒ‚Ü¿‡qæÌg˜ÚÞ÷ï#* ÿׯ«èle…Ó§qïRR>ÃÔŸ—;5E•Š4˜’’°m6mBPP)Ï={—÷‰³üõWq•¦Š IÔº¢šß/µÑ‹áî^JÀbÊøúbôht놰°â¥öaÃ`nŽ¥K±?XZ"0 bÞ<øú¢Îû,5GÇâc5žžšÍïZZðòªPx¢}{¸»£O\¼ˆ®]59ÝL&<< —íO E’dZB<“ÍŽ}ýŠ$IÇFî,6'#9)=%1úų˜Wá$IêiëèäåE¿|&ÉÏwlèÎ×ÒšÏd±Þ¾ 'I•sc/‡“™š’•šýâÙÛW/ètºHß@¤[a!¥¤w1Z"qldDvzš‹GP¤R*b¢â£ßX:8š[‘%ÔÕSO——•—ehnY—›š×ö§þbâ³)•ÊØ×¯’ãÞ uôìÜê1˜,¥BiëR·d7’$Sãcß¾ êêY;»1Y,¥B‘û–¯­ýúÉ#‘®žµK]:þå~/µ„¸8çÎ!8gÏÂÞ11ÅΤ$ôïsslÞ¬‘²ù †mÛàç¡ð¿^;Å…rF¿zzèÝû[AAñýA0Ù‚V¼,÷4ìúÖùÓê7*,(¸!:5~Åú´ÄøECú蛚K ò ‚˜³m?‡Çß½bÁÛWáõ¾}îêÑdø¼å÷._¼}é\J|ì… ý\V»><ÛuLMˆ[5~¸¶Ž.›Ë=¼aÕ‚?‚øBÑÕË^?yP§~㘗Ïy.þõÑõ+7ΞJ‰½|ˆ§¥Ýª{oïÎÝ+²xËÜ© ¹\)—ә̻—/Œ]¶zïÊEn\«Ó Ñ¾_˜·¼aË6'wýÎáñ†Î^LÄ¡õ¿9ù»ˆ—'vn¿w{ÉãE*§Ç¶®»}ñŽ ÝßE¼ì2d”g»Ž¹9Á›×Ƽ|Þ¾o@×a£Õݞܼöû¼iŽ Ü£ÃŸ»x6>giNVÆÒ‘„:ºf¶ö®]:{Qs¿êÎt“@yE8((Þóè„J…^½Ð´D2ȨQš:œNN¸~,||@èØ‡C*­ž3Ú§èt´n ’ijgðñÁ¾}¸qYYHIÑ(퇅¡aCM‰#+«â±óçƒFömz¢ESlߎk×Ð¥K5 £øúPÎ(E EK,ž»ý€–XGýR’ŸwxÓo~ƒGv4‚$Éüœl—Ž24³˜»ãOI~Þ‚A½ï]¾èݹ;I’Þ»õŸüsÔ‹§+F>oyû~­zü´xh¿€ész UªS»·šÚØÿeJ¥Ú~ƒFriAþø_Ö¹x49³oçÃk¡Þ» Ó€¡Ÿç×CñãÂåÂØ$YÖÕ+_T©@šz•EE|XÇòÃ2„Äûr¾:ûöáÖ-lÚGG,XP|žrë„DZ`vî¬Ì55ÅàÁØ´ >>*ìFñÍ©½Î¨T …<^ùŠžŸ™ 2h4p¹š·“B¹\î—š±”JÐhå¿«ÕB¡‹&ó+šEAQ14½äbt¡D’ž”P§AcA„"¥BiåäB£Ó¹|™­}Ü›× ¦½[ú&f² Š˜)ЍgO²3Ò— ÷‘š¬c`€F#¬ÜX9¹H òË[9M;uS»}B]½ëŸT)•ë¦%@(•мì,’$]<šªTª7Oççf󵄶—õlëûûÜ©æöŽöõt¨.ú!ñQ‘=FAX9:3X¬äØ·VN.<–‰µ-ž–VvFº\&c±ÙxZÕ)GQ+©S§¬Ḋ88@*ÅÝ»hÑ¡¡°µ-‹êëãî]´o&SóÐÑÕ…TŠ‚p8Åò2'N`Êܽ ’D:¸u nnprBNBCáç^^8u ÑѰ´DRtu5ÐæÍˆöí±};&MB%I(þþسwî uëÿvS(¾$µÔŽFïÞÈËéSptü"S¤¦bèP¼~ ìÙ£ùBŒmÛpíÚ™±\T*„…áüy¼}‹iÓP·âÚ+V`Ï´k‡]»¾žyAt:C!—·Ðh,GÝB’¤B.cT¤£VÞÙØ<~»¶¾Í:uS·pùŸ'rR2;“Ãã™XÛŽ_±^] ”N§Ó ‚ Ü[·¿öWˆ¬PêÕ¾³b›{NlÞ¥g䓇!;·€$LC”÷…’ÁdÊ¥…r9©"Y\.ÿ‘y¢ê[G£ÑéŒZúD øX¬R>Ÿ‘æÍÃðá°µÅë×8xE¢S¦`˜›cÛ68;€»;œÑ®°{7„B°ÙÆÅ‹xó°¶ÆO?¡o_tîŒìlÈåùÅÎqãºw‡ƒ>ÄÅ‹°µÕXbe…Õ«1e <<àí]¡ÙVVèÞ›7£iS|&YŠÏO-ýèyô::¸y³Š’„R ’^@U(@’`04_øHRóO¥*nT©Ž´4pnìu`õ/Y©)6ÎnyÙY)ñïÄFZté¹zÒÈüœœ%†¨?5d…RR¥"U*Y¡´PRÀbsíÙí›ÖN.}ÚG¿ü‚¨(ØÚ¢aÃâYöìAv6"#ñä š4Á˜1X¸YY04D~>¸\¬]«Ã/ùs¸~QQHJ‚·7~þ¹ü„kÖ !W¯~Ô=Q(•E9£5&‹5hƼ½¿.žÙËW!—7íØÕ¡~£v}¢ÃŸÏõï I‡Îõ›µ$IRÏØ„+Ð@§ÓÍm4ÃÙì®Cþ¾þÜÁ=݇mÙ­wçÁ#3RSf÷ó#‡Ç\ü«¡©¹®‘‰zŸ;AÐÌí4K•4­ÛðÑG6­>{pwÇCÛ÷­ð‹¡©‡Wüþ1¶² \üëÖùÓI’,”H:îP¿1[×zÆV¶|-m3{uÏ3'ÆGGض`&€ië¶›ÙÚ_Ÿ§¥=î—µ4í¯=Û¯œ:ªòïß'º ôéÙ·ï„¿Ï›6½G{¥\>`ÚC㜌tcKk@ -205/7¤ªF’Ÿ—ËbSQ#ŠÊ(WF¿a  eE¢âÇ™™˜›—ê ”ÿ 34,õ²¤%&&\„£#BC©çZ¦–:£ÙÙ•eOª9zK—býz˜šâñc(•ˆŒÄäɘ9uê`Ü8ˆD˜4 OžàðalÝŠÂBÌ‹¶mamþýqç’“1r$ø|×Û³'NÂÅ‹¥4í>Ä¡C˜1=zàÍddàúu¬\‰éÓ±d öìÁ­[ðõ-ǼˆlÙ‚ `g‡1c``€‰ÿëm¡ÓÁç—“xNAQC00³˜¹é¥RY´Íæp'¬Ü’T©T´÷C~^¤>àii/;t²h¸{ëî­;½d±9Ãç.>w©J©,0}žú€Ádþr¾¨sÃm¶(Uò¾\Ư\_¦¥I‡ÎM:t.i³š•|9}Ã0€)k·(9¶Ûð1݆)ÓÍÌÖþ— Ó*¥’ ÑŠÒU‹NèÑÖ×£my"ïIz#ÒÓoÒ¡s•WGAñblü­- ¨”ZçŒfd $;v OŸ*z9‚>}С¸ºÀ½{àñУtt0`þúKãÿµnN™ 6©©pr‚§' !¢eËâ6lˆ/pñbÙ‰ºtÁìÙЮî݃®.¼½ai //œ<‰ v_€—† €AƒpòägpFµµaoE‹Ð·/Úµû¯g£ øB”“ I´ÿ £Yݱ 1QÏoß,ÙÒ¬s7ž@«¢þ(׿æ#Ç~ò0²°š°bƒPWïÓ†SPPPüGj3ªR!- ùù¥\Ê%9––¥Z²³‹3c„Bäå!?(‘Ö©Rir@«…Þ§>ŠV.„B$'âIJB‰€‚‚Ïp6 Š…L–—“]²…T}Ç †æ–Uw¢   øbÔ:gTO?ÿ ¡çÎaÔ¨Êzººâþ}  :]³»ÈÜ))HM…‘ââ`høuË""4"Ã11MàrQorÂ{_¹)«œÜ»‡«WËÉõ¡  (ÂÂÁÑÂáËÈpPPP|4E[x?m A|AmGŠjQKFFU÷9/bÖ,l؀ɓ‘ OOp¹˜>‹aÏŒ ¼ìUSRȳÌ_ùÛ·˜;ÇŽ!.sç"8¸¸[ÉìÕ¢QEÿ­$·õùsŒ‡¥KT™c½u+&NDZV­Â´i•]²B¼¼OycSPPPPüØ(•(¡«Ví± Ågµ…qã™Y½Q$‰mÛе+‚‚ªîLñu¨u‘Q5¼<äåϯÐÛóôĹs¸xYYðóŸý…'›‹Ã‡5EÒúö…L|>V¬€““f¸£#æÏ/>Ÿ77¸¹¡_? ÄÂ!CJ`m¥K!cÁ˜˜`êTØØTxÝ»£Y3¤¥aïÞRÉ©ehÐ::šÙJ¶*•ÈÉ“  ûPPPPPÔN6lÀÍ›8|¸BÁÁJص `ûöÏlR~>ž=«¶‹ƒ­[±p!Ú¶ýÌöP|2µÔ­[99psÃÙ³Åîã‡ØÚ–]þ62˜Ò;YëÕÓ°X¥¶½ëëãÿìÝw\SWðßÙ@ÂÞ .@Ž÷ÞVëª{´ÎÚº·Vmmõmµ¶U[­¶Vk«ÕZµî=pï²÷Þ!û¾$DÀð|?þ‘œœ{îITxrï9ÏÓ±ÐÖ[SZD‘´gr¹iË”ñ?I۶ยÿÓò³ŠJ$;¶ÄÉçkÙ-[¾¼Û’%øùgôïožQñ"•2÷äÞ]­º÷‘Û;èõºóïÏNOë=fEQ·ÏŸ}x¯ÇÈq¹Y™Ç÷ü’HÝ&ÍýÛ´»p诘ПoëäR¿u€Â¾˜´œÁpñÈÁ”ø¸~ã?2¨Õjšu,q×yr|¬ÔZ.¾ü¿ÇßÛ7·ï÷^~S‚¨êrrðçŸ BD¶mƒTŠAƒÀ²P«qü8áæ†LAj\އN¹½zA«Åþý¸t ‘‘øñGH$èß¿Ääó.\À³gàñ77p®\Áƒ‹Ñ£‡éZIf&@RÒs+Ê’“qêrrФ 4(í¦¢J©Í›?WÝ”0¯wô6½—‚‚ðø1¼ë)Ñð IDAT½Í=•—yò~~ÏýÙ¾üüJ«9ñfÏFl,6m*Ë1 âm¨ó”'öþšžœÀ ×_:zpï¦õÏîßQçåýµuÓ?;¶ªrsSãÿÙ¹5+=ÕøG­Tô†+Ç?¼~%51þ⑃Ÿôíôìþç8.èÄÑ=Ö>¸zÀý Kw.œ-üjá΃áëO¦„ܹUÜ0E·.ßóKNVÆÛ¿}‚¨$4\»†ÈH¤¦"(·n™ÊÁŒƒõë‘šŠ¹s±a df¢{w\¿nº˜“7n , II¸z·n•x¿žã0>fÌ@J ®^5•*üë/¼ÿ>¢¢ðÇ>YYP«1t(öî…FƒÅ‹‘–‘‘èÒÿüƒèh¼ÿ>‚‚*îÃ!ÊDiWF†Q«Õb±¸ÂfSÁªDe°ºuñôi1íe~¡ØÔúDµ¤×ë9Ž+% z¥eçìtâËãe¦¥XÙ˜2_‹-¤®ü*¿±:hÛ^ý»£Õ¨WMyõÄïzþÅ(·s8½ÿ÷z-Ûæ·hTªc»w„=~ ·³ï=z’•íÝËç]N‰‹9µÏý ‹õZ¶õkÖ @胻çþÞ§R*zðkÞªß6AT,cQ@4 š†\Žï¾Ãúõ¸|›7›®€^¼ˆK—põ*lmѹ3&LÀĉHLDj*ÆG½z˜9Ótyò›o°yóËoÓã×_qôèse«·nÅĉX´‰‰hÒ·neŽ'àâ//¬^ [¶ÀÍ ›7C €L†­[Ñ¢EñgÉÊ¿ÿB§#÷+—Ò®ŒŠD¢\cî"‚ ªF€ÿÊeÜÍ…ayÞõŠ %­hÒ¡ëí‹g/Úß¼S÷ü´š:úöù3·ÏŸ¹sñlfjŠ©+g,¹®ËËÍay%VïlÓ«ÿ£A© q¦ƒ8î÷o¿:{ð¶=û¥&Ä­:àdrïZ‘ÈÎÉÅ¥F-©µÀ“[×WNîQÛÇ¿u» s¦Å„†äY³ACþ+ÜÍ'ˆJëèQøú¢n]üþ{‰}žÿ¦p‹ÜÞÁÎÙõÜßûçmÚvãìIc£*Où×›0,;dÚ'Þ~þÎüãÑ«aï8.°ï{%žB*mԮé}{ŒOuZíµ“ÿŸµ Q»Ž^¾õ'6Ž ~êQÇÇ­Vc»wÖkÑÆ¯EkÇý³cK×!#[vëžœØ0 Ãù¿÷ ûxžqk7–ÇA§];üû/(%ö±·‡ÎC‘»§ë×ã³Ïpí&ND@4µëtà¸Ò–rZZ"#*Õsr9’’@­†Á¹4Ó¾áÌLS]¹ãÇcíÚ—¿µ}ûpâæÏÇÔ©¤,S%RZ0*‘Hbbb Cåÿ¥ , çΡAøû“ÌaQ"ƒÁ‘‘aóƵÌŠÇãõ1¶†o}wÏüF ™õŠæ?5Þ¦wõ®åß:°Ë‘5ê5(¥6E3ýúÓüÛ´À )ñq–VÖ,dV2…MVFZ±¦''=¾yýò¿‡ŒO›vìZl7‚¨Š$xzmtwÇÏ?ãòe¸ºÂÝ­[#5?þˆƒÐP ‚ðpœ;‡`g‘¨ Nµ³Ãõë8}žžpw/>`½zððÀŠXµ aaà8´höí±cڵùsà8øûƒÏ‡J…½{Ñ¿?¶l1¯ýúaÚ4 iS\½ ™ %¾;…¦uD%ñ’+£ ""«”ôB•F^nÞIJe8¾hå$‚ ò%&&j4E)W<*·z-ÚÔkÑ&;ã%©kø5hÓ«ß« èY××ÞÕýöùÓ Z·£hÚÖÉ97+€2;+35Ef]ðAÞ©d!³ê5ªKÿ S^åéɉ‘OŸÔmÜT ª¶Kð‰j¯[7<|ˆo¾Ã`ÇÈå8rË–aÿ~1( ÿþ‹_~€>(H)Óµ+>Ä÷ßÀO?¿]$®]X±ï½†ÁÂ…0w.”J lÜwwP¾ýkÖàÇðxèÖ _~‰o¿…JÌ™SQ†J F)Šª]»ö­[· …¬Ò§@ðõÅ·ßâäIäå™{*QY)•ʨ¨(///@`î¹T Ëk×÷½ofOm°<^ó.=önZÏ />P÷¾kÍÚ(@*—Ÿúó·”øXϺ~u|zŽ·qþL+[û‡×/·èܳ†_ý’NñðÚ•¯gOýúЗ5+ðDY’H°dÉs-uê`ÏžçZjÔÀs¬XŒE‹ žIA‘ïÞÕ[·>÷’\Ž/,{éÚÕ”±°~ýÐ~B¡@N-¸qhÛöåý‰ ð’<£"‘ÈÃÃãÑ£G>>>•?%¢999!!!r¹¼*Þ£§¶]ŸAùÁœ@(ê6l”ÈÂÂÖÑ¹ßøžïÉ´íÕßÞå%5m)šjÝ£1i‹Î=R>žïQLJ¢¨ÁSf‰-¤Zˇ¬ÿá¿Îô„Å«/ü³?%>ÖÁÕ@ýV3¿ÚtõØá¼Ü'϶NÎ¥œ+>2ÜÑÍÃÎÙµ”>ñŽHOÇ¢EÏí1 Àøñ7;;üó.]"{˜*‘—'½wvv¦(êÁƒöööžžžLå.)áÆ Ô®]Ú*i‚x× †˜˜˜ØØX'''—ª˜Ô‰a˜¶½úç?å …]†Œ ’Xôý\1\š¦[wïóÒ)ŠnÙµWþh&M3>æñÅÞ|—Û;ô÷\ÔëÛ´¥oÓW¨'„Ü»ýþô9ü*‘LŽ Ê™XŒ!Cž+æRñ‰\\0dHEŸ”(Å+U`rrr’ËåÁÁÁAAAqqq/æy®$>ø³fáèQlÚDge ;;;ýu+W:.///+++''‡Çã‘ûæ²à‡æžATÌ= ¢’yÕr B¡°~ýú¹¹¹ÙÙÙ>,×9½'0x0¦O‡e‰Ûg â5$$$DDD˜{oˆ¦i@ P(ÜÝÝ-,,ªâQ‚ ¢Ú{½Úô‰D"‘899UÚßjaaX¾µj™{DuQ³f͆ š{AÄ+ÉÌ„NW4CjL ¬­Mò«±±pt¬¥"ß^5LÈI®‰AD匫W+è\[·âóÏ‹6öécJã_©9bª€úë¯z=fφ&N,¾xI4¬]‹3gðõ×xð Ì'[¾^ïÊhe–€ “S|6]‚ ‚ ÌâÌܺUb½øwÖƒˆ‰«+¢¢L‰Z$'ãòeìÛ‡ ^o4½'NÀÊ gÎÀ×~~e>ßrT}®Œ>x€½{±p!Ü^’Ñ… ˆª!;=må¸aQÁh5šïÎZ4¼_^nÇölX;gP÷Œ”ä°‡÷¦ti•ÿç¯-õ:Ýæ¥s§ti5£gàÒQïúó7CqµV zý+Î}¯‡2; À_[7íÙðeI3á8îôþß“b£ßìß½µþãÉÅNƒ ª®>ÂÚµ D¯^75nߎö퀡Ó!=S¦`Çœ=‹Ñ£ññÇÈÉ€Œ…€Œ˜˜‚1OžÄɓϕGJKÃÞ½Ï]#ܹ;# #GšÎ«×côhÎqþ¼©[r2¦LAÆ7©©¯÷ÖöîÅgŸ¡_?â§Ÿ ÎÛ­0t(=€mÛ0a:uÂìÙ Ķm TbÝ:tìˆÎ±oßëwãFLŠ'O°|9&M2½ë°0 Š€ ŽgÏ€ãpð ºvE` –,©éÕ«Ï•ÑNб#ÉèDÕ‡Á O‰ÑjŒ9`¸´äÄðG]¿R»aÓ‹‡ªò”½^£QçdfÌZÿ½ñ[gWŽãÒS’¶mß´C—ʨ_¬Š%­{ô}q|c,tòßöýgg¤©rsKš Çq§þÜmçäòf¹B5*Ujb‡Jš„„ ÞÌîÝ:Û¶aÁ¬[‡ pó&.ÄO?ÁÊ ýûÃÃ]º`Ð °,ž=ða  #}ûbèP,X€;1o¶mŸŸšFëÖ‰Lg‰ŒÄäÉXµ µk›Z8K–ÀÕÛ¶aÆ ìÝ‹S§ðÍ7øö[…5ÊÔsöl¤¥á—_pò$~ûíõÞÚÍ›øë/ìØ°0|þ9:v„‡T*,^ GGìÙƒ3pè._†Hooœ>?ƦM2ë×ãØ1lØ€¤$Ì›‡ZµP¯^ñgiÕ YYÉàãcjiÛ2nÝBðô„T*Ìœ [[|ÿ=¾ü&àØ1„‡cÚ4,^ Œ[[L›–ňðõ……ªBÝÌçTŸ` ‘(ATs~Í[ÿ{?M36ŽÎY馪ñ,ß u»ü>ÆÚôÎ^Þ Z·Óë´·/œ ¾{«Ø`€_óÖGwmkßp~KlسoæLMЉ–Hec¬hØéÐöÍÇöìLMŒß0o:_ ì5jB·a£õ:Ýž _^<|@£V5ïÜ}âÒϤ''mZðqlØ3•2·Û°Ñƒ§~Ri÷zD™øäxyaÐ üþ;ôz;†úõÑ¡ôí‹C‡Ð«Ú·Gp0T*téb:êâEhµ¨_11¨S‡#+ ÆZ³gƒ¢L©‘›¾ý´´o}ûðçŸ Et4²²pèºvE÷î0p ¤¦âÒ%|÷üüàæ†Í›K{©©¸sœQ§Ž©±O´l //|÷)E8pûö!4‰‰HK€ Àã!/þþàñ‹}ûЯÒÓÁãA.Ç%£mÚmñ÷‡T ±-Z˜î³GD $K–Àן~Š®]K—`k‹±cÁ0>ÇŽaÚ4ðx5 š4)íÍVNÕ*%¢:YXûx¾­³K~KÆÍ.>xt×Ï-»ö<¶çc£2'kÓ‚Ð ÛmØhWoS6 Fóäöõ°÷üÛ–t ßf­.9ðøfñ©A¯ßùåJϺõ>ÿýð©?w¿øÓo]ê5zb÷c—Ž4dÚ§~Í[Q àÄÞ_o?½vßQž@¸rÜЋ‡´éÙïÌ_{åö 6ï4èôq‘aù‘¨³W“¦Ñ4YÏNT7r9°¬ébPz:\]M¡¤TŠˆètàñŠ•žŽÜ\üþ;X‡¶m ú¼XçS¡À°aOÑ»7Z¶D³fÉiiðô4u°³CZrs¡VÃÎÎ4“üë¬Å ÁҥЯ_A0jÜ Íãe !ýû£aC´l ++s\©D^‚‚ÎÎp}»Êkj5rr`¬ßli KKäå!/öö¦2r9’’Þê• F ‚¨¤øaóÎÝ ·XȬk7lrýô±1 –ç£,çÓ¤Ц-­Lþ~Zµxûê¥2…M“ÛõXò)í 9³¯…•½Nñøáôµ“i† ìÿÞÏ_,‹ yZ«A#šaЦhc@Éq\ÐÉ£n5kß¹p€•Â6øî­6=ûYÙØÞ¹u×ú5u6-|±ÖÚÖÞº}Ù~8Q ¹¸àÀ¨T‰ Wׂ(3;z½)~ru…L†uëàà`z5ÿ¯¿‚¦1x°)€_EûöhÜž>……V­‚B;¡Ñ€£#¢£¡Óeqë<< P@&ý{hÐqqÈÈ(mÚÍ››Vš–r'#!|>V¬€ƒöî…JU|7¹¶¶4cÇ}koÆÂ––HH@½zˆŠBn.llàèˆ'O•KK<{V¶Ê˜-MIÁ˜1°²ÂÚµf(FDUDÓÔ gt8ÔBVP`/µPPÚÏx›~ìüå]‡¢@Q4]Ú½rŠ èÕîàu7[Xràò”9ÿ½BñBM ¿s4*•J©Œ {ÀÅ»–G_íû–É·/œùù‹å®Þµæ~»¢«Ï&Q‚x©¾}±nf΄TŠ'pꔩ½A¬XiÓP§&L@›6ðóðaè×QQÈÊÂÆ¦„šÛ·ƒaпA0Õ«!‘˜‚Ñ5‘Õ«!•bÛ6H¥0y2úôÁÂ…P«qü8&N„D‚±cñÙgˆˆÀ•+ˆ.uó!E½ ߣb'C¼ªÜ¬ÌM fÅ…‡–ÞM£Vÿüù2Ÿß( ƒLaS31 æL ¹{ëÍü`Ûª%ƒ¡lgEæµ};Z´ÀرèÖ [¶@v6FŽD»vxÿ}"9‰‰hÑË–aï^øø }û+sž< ??´k‡Ñ´)¢¢àÞ=4k†¡CѺ5-‚Fƒ#Gàãƒóç1y2||L9M³³1q"ÚµÃ!èÐ11%Î9&]»¢{w¼ÿ>úôANrs1f ºtAÿþèØÑtì¢EX½ÒÓÑ¥ >Dz:ÚµC@† AӦر–,A—.¸}ݺÁÇW®”á§ûn©Ð5£"‘Z-2Ô4 ‰ƒWäÉ ¢¹¹°³ó1÷,ˆ’p½.ÿrHr\lVZjzr¢[ÍÚQ!O<ëú)œâ#££Òšvè*¶°dX–ã¸Ø°g|¡0:ä)EQu›4I,Š=-1!'3C§Ó&FEÖòo¤pp2¶Ç„†D?±¶³¯Û¸€¤˜è¤Øè¨'!÷ïh5[gW['gZµúáõ«ZÚ§i ‰¥ô¿IÆ„=¼Çã Ükûäç¢â8N¯×äÊ(Q­lߎeËðÞ{0L—þ8w2¦MÃ?bÞ<œ;‡ÄíÛØ´ …’Rë ÈÍÅÁƒpuEÏž8#F`ýz4k†ñð!úöÅÀèÚ;¢_?Lš„îÝMe9ÿwïâìYX[cî\lÞŒ•+‹?Ëš5P(°oø|ÄÄ@(Äß#(GŽÀƃaûv,^ ­Öt•”ã VÃ`Ç!=“&aÂìÞ]»0j–,Áðá;[·¢FßñRŒòùN ã Tf5De VC¯‹Å _Þ•¨.þëÔŸ»åvÑ¡Á¾ÍZþñÝ×köztóÚÝKg3R“¯>öäöõžŒI,÷lXûäæußæ-³ÒRüøÝüv^?}|ÏÆ/køÖŠ%?±lÝ“2«sïÛñù²¦º>¸v¹iûΣç/vÿöµSÇ2R’ož=|÷V«®½lœSâ–yßɳ†P,ÞùåÊÏ÷–XJ]¿úÝ¢OvÊÉ̸téƒÙ‹É–y¢kÝsæàÐ!bäH8sÙÙX²?FVôz`Y0Ì˳‰×® ðùpt4E·×®aþ|ˆDhÜ ‚ƒÑ¨4 >¿`À³g¡VcÙ2 …¥eñã«Õ¸t ³gÀ©ŒÓãÇðô„§'( ­Z•¶U"A³fàóáînZ À²àóAQÏM†x¼›ž’ɺ$$<µ°àh3o"$%A"iCÓsO„(žTnóåþãìÉ89ƒ¡i‡®¾ÍZîývÝøE«‘šÜaÀà–]z¬šôÁ É3j6hHQ´^§ÓétÍ:u¿xUž2wѰ¾×Oè=àÅñ9Π°w˜ÿý½N»xäÀ°‡÷|š¶<´}óiŸv22ôá½EÃû÷÷aËn½›uê¾tÔ{}Ç}è×¼EÑþô½—o½i_|CQÔ÷‹fŸúã·>c'?¼~¥N£¦£ç-ã8Ž3èó#QŸ¦-–nßÃ0fÎ^BekåJô郳gñÕWxú_}eZ€g,éÙ­ðZ¿ë‚¢ýiÚ´TÔøŸ©ð:Ô"Ýj×.(%êèX|7ã EÖËèõ ¨‚—ŠL@§ƒNW0=q–“Š œäåy¥¦Vði ¢¨ìl¤¤X¹º®¥iòÓ¥’¢(Š/Ò…~9ðø|±¥T 1,ËÀ¢hŠfP4MÓŒ1þcÆ·YKša„"‘ƒ›g\D‰«N­lì–¥–aÙœ¬LƒAŸãR£EÓµ}Ä––ñáEËÇÓ”éÇ…=ºüxõ¤VMùèÆÕ˜°þ­ÛÝ»|aZ·6ç͈xR°•ЦicÝQ‚¨N<@³f˜?}„øx @T:t@ß¾hÓ¦ØN,FDòò^ûõêáôi¨Õ ‚R __S»D‚»w ¶4µh¸8´je:¯½}ñ£ñùhÞšf ­  4¡¡ÈÎÆ¥K¦šò¢£a0àÑ£—ì”gYäæ>·¥éµLŸ^´î|L Ú·ÇÏ??×xîZ´Àox–ʯ¢¿©óxöÃÃJ$yb²a‰0­‘‘prZ.×7÷\ˆ²ÇqœF£6>Ði5áKêÔç£@ñBƒA@¯×ååæ–Tãžåñ[tîÑ¢KOãS‰L fƒFß9þèÁé}{¾™3íëCgŒQ,ATKsç", nnˆŠÂÆ`YŒ‡;wи1ìí‹~@—.€Í›áãooüñ¬¬^õóçcøp´näd  ŸÿVøŠ9sðë¯èÑ_~‰#pÿ>Z¶„£#±|9ÜÝ‹pÁL˜€æÍ!•B.Ço¿¡cG4nŒnÝ @¡Àĉп?D«VàñPz¡4''ô쉑#aa­[Ѣū¾5£ÈHDG?×¢ÑàÑ£¢¹²³ñàr_žY¤ª2Ãm#™¬›Ýâ§OW:8ä98<£DEKOGT,-ÇÙÚN,i—=Q¥ †sþlѹGRLTÄ“G'ÏxÅi–õòñ»xø€O“—Žü-µ¶v­YÛøÏ ~lïæ!±”Š--v:h_ç!#ävOoß[Zü@ ù4m¡Vçݹ|r9Õl IDAT®ôs}1e¬2;kñO»Y²ë¨šDb"T*¸¸ÀxuI"Á–-ÈÌDj*œœÉÉݧNA«E¡¤ëP;¢m[¿ýmÙã÷¸úõqõ*"" —ÃÖì1K¿~èÖ z½©E*ÅÆÈÈ@J œœ )yí•»;þùÉÉÈÉ«+D"Pvì@|<òòàæfš€¿?®_Gb"\]Á0 AQ8zÔt›¾m[=ja°|9æÏ‡ÁPâ[ËwëvíÂðá-{ö HÎ7„…Ý Õ­PÂWãêÀ,k˜(GÇ9––-ÃÃ'gd<µ³ƒHdúAåG¥B^ÒÒmïêº^.DQ$µmUbek¯U«EÎ^Þ Ã¸Õ¬m ãh†võ®%*ôû‡¦ƒ^?{@WŽãº¼?²vÃ&Å(“Û8{y (ʵF- ©Ã0£æ.ý~ñìOûwfyüñ‹W¯ªÒ4ÝoüGmÝtâh‡ACûê:tTzrâêIŠÅ“W¬ùôñ¡Ÿ·ôz†eÇ.XQúeѬôT…ƒ#M–ÏU–PXÌH–…B…¢hûK\2LA°U¸.£DRpw>EÌX66°ù/·Û•+ˆ-xÕÂíÚ™áóáìüܱ<ÜÜŠŽÿâ»È?c᩟–þæëÚ2YÑë¬/Æ—ÆtCE°¬iÓUuežõÅXZúø\LLü>%åB^Þmƒ!U,Î#ñ(Q(J›ËqœD$j 7õñ™Å绽ü0¢’ ì;ˆhš¿x5Ëc§®ùšeY¡hüâU [ðÓŒ¦éžŒ÷oÓ xAI[Ú›wîÞ¬SW ËNXºÆ;:yÖXºmÞ §(ªðBOÿ6~Í[qg܇ÄF|²P7MãišÇè= U·Þ8Š¢ø¥þâUçåņ==w)¹O¼;tAF®{jNÍä¬:YyN\yÞ˜ºóÉIOEb(­`æ•Û ýhQlVK…‚ìÕ+GEQ”ØRªïÄLÉÊs ¬»†¢ªL br¿’ ‚ ˆrñ$¾wlF LnK"ÑŠÁòùR¹]xJ·ðäsÏå5`” ‚ ˆ²—•çt=l¢DfG6êU$†e…–ŽA¡S”j›—÷®H0JD%•—›³󆔄R럔 1:2)6úåýŠ£ÓjçêžûâK÷¯\\=ùƒü§·/œ¹}áÌ›… ª½G± ¬[é™%ˆò ‰T\­§ñÝÍ=‘WE‚Q‚ *)*ïÜÁ?3‹”"y5G~Ývìùô¯Žf˜î#ÆJ,¥/¾¤×éT…ª ß¹r÷Ö›… ª½”ìš|É"nEñøÂÄ,?sOäU½ù&½^Ã#«@ˆjJ£©’ÙÚª±Ü쬃?}ïV³ö3'ìÝÜûŽýPlaiÐëƒN½zü_ hÛ{@ý–m“ãbþÙ±õAÐ%𦷝YjãàÔ{Ì$I±Ñ§÷íŽ ©Ó¨Y—!#ø%Ô}zûÆåÑ Ó¤}çüÆÈ§ïüI•§tpó¨˜7KUÎ HÉ®)Q Áo ª<^ÀQ|½AlàŠYXlù¥ÜÌŒÇ7¯%FGj5êO¾Þ̼v0ú è²*7§I‡.o2ã·úàn\DXÛ^ý‹´Þù£V­6£zŽã ·ÎŸÎLMí8è}ÎÀëÆE…<ùgÇ–é_l Þ¨8°ãqúbb9ƒÁÀA ÕUzöoŒ6iÒäÎ2­fE••äUJå¦p‘O<ÐÎÉÍ0Êì,N—‘’ääá€åóöNé…+’“‘š¼iÁ,½^l)+¶[±c¢ercù"LIey‚(¯\öÓɳÆÈOÞ½|þè¯ÛÀ½ÉéBÜÍLKyã`Ô ×¿ÙÆÿègÁ÷¯^,Œ&ÇF_?}lòòµùsÛ·y£½«›F¥ ¾s£a@‡VÝzhÐ*àØî!÷n×òoüF³¦Šì9àÕ?y³{“`”eY©´˜¥ýA劢PøâËãYÛÚg¦¦ÐiµiI u}/ D"}¡»76NÎö.nó6m§ãá¯ñ3ÚÖÉ9'3Ãø8)æå;ôoœ>îèáåìåýê§ ˆjïúé㻿ùB ©ò”Ì^ܰm{Z½ÿ‡o‚Nþk0è}š´=oi~ ߢǞ:¶oóƒ^/KÆ/YåV³€ûW/þ±éy¹9µêýi³=}ü¶®X¢×i]¿jãèuÍÿr²2·,›—©ÌÉž7¸§½«û¤å_ˆ-,ܺÄòøuL?”¼ë7ì=zÂw‹>Ufg[¸²yçÆvk;{Ú>WO}Ó`´: ˜‚¨ÂšwêöÝÂONþñ›2;+úYð„%«ín5ëîÛü­³«ÜÖ¾e·^ Û¶?ðãwû6S·I‹Ä¨†Çëúþ/ŽfÐë/üóWNVfnvÖ¹ƒJ­}4j×ñ×õ«wý…§ßßÛ¿WØ;•2ƒ^¿îãI&Íxåò† ¢jÚ¿ecÿ S›vRæä¿ žýë÷[çOÏÝ´M(‘l˜3íÊ¿ÿöüâqa;¿úìƒÙ‹}›µ<ñû/{¿]7ý‹ê<å¶ÕKzŽײk¯Ì´TFcçì:ó«MG~Ý–ž6xê,šfŠMˆ #%iÛê%íûn×gPvFºñRè_[¿[H—íøæÉÍ _¾ZU§Q3©µ<&4D£RPæddž…Pæä<{p÷“¯7;ºy|1uÜÃëWšvèúñúï/>ðøFÐø%«hšI,Œ'Šwö¬‘{'øÎÍc»w6ì¤Óhî]â -ºô@Q”­³Ë“[×Ëü3¯BH0JDÕ ¶”¾÷áÇÆÇõZ´qõ®m|0yÅÚ[Î0 3ký÷Nž^Æ-»õ¸¬´TV@j­X´e×™¿~¿wù<_ (¥.¼V£1ètýÇO Õ¨9޳´²žûí¶ ÿx|óÚÐs¨RëÚG>}l0·ëPVïš ªG§#¿ü”éÛ¬•ñàí gd ›;ψÄOïÜ,6 ¹w[«VÇG„¥&ÄegdƇ*s²£CžhØI"•I¤¦U7–VÖB‘X§”Z+J™I|D¸N£iÖ±[þ±ê¼¼°‡÷z™,“+ê6iΰlbt¤´„«ªŽîžu6ay|÷Zus23i†±´²I,xA‘óÆ…‡Ú¹¸å?õ®ï?uÍ×÷¯^ÌJOmÛkÇÔê´wq¿üï?œÁðfËF«ŒQ5ˆ$‡Œ0>ö®ço|@3LÀ Š|°]ßA…[Žƒ>|ÉÕJša:½7ìÅvïzþùg,]Ø£{MÚwö¬[eÒûDŘ´ì‹k'ÿ½õâñ=¿ô›0¥Çˆ±•Jdai¼ôX·Q3ךµ‹=P«V±<ž^§Õ¨ µ–w6Z iµšfÞl}§V«1 …¿UêuZN'‹0 KÓLÞóÙTÔyyùy<>Ëã è—¬öQ88ªU²,eyþm9Žã=¿56=%ÉÒÊúDA‚Q‚ ÞMWþ{ÛùOYÿãõß[ÛÚ½å°mzöoݣ߻üK… Š¥Ój; Øï½}›7„?~Àqœ[­ºYi)=FŽcy<­Z­Q«Œ=išV)só×|;yÖ`X¶e·ÞÆ,¿Yi©"‰…ƒ«»2;+.,T&·Ñët*e®ñ'Ëç'ÇÆ †R6Ú88éuº¸ˆ0…ƒ£^¯Óiµ" K;g×»·šuì–«V)ÜÜh5jen€Ðw_ús³²Š\Ú´wu¿qæD‘nlqÙÙ“b¢\½k½ôÕ F ‚x5 èð|ò?ÊÒÚú퇈ªF"‚¨`ËÇ ±sqµ²±{tãêè¹K(Šê>bÌÆy3ÖLþ@nïùôñÀÉÓ{z<ëúq·rüК 1»væ:¬›9É£ŽOZb‚‹w­1ó—;zxõ1vËòy>MZ$DE4ïÒ³Ëê4lòï®íËÇ v«Yçýé³óïàæèîÙmØè-Ëçù5o•Óiðð{ô9î‡%sâ"£#}š´põ®Íòxžuý~Z¹ÐÑÃ+6,Ęu¸$Þõü÷mÞ°xä€~ †Î˜#KÔmÜìä¿%D…;¸y–rlnVfÄ“‡½GOz«Ï·Š#Á(Aï"¾PTR&‚ ÊÜ‚Í;Ó“9pƒ&ÏP8:°sv]¸ù—˜Ð½^g)³¶s1åM³YÍûnGZb¼V£á  à ÿdA|D¸2'‹/Ú»º (ªçã›vè’™žÊòøÆün¼|ë¯ÚýwRl4Ã0qñ{ó)šî1bl“ö3ÓR–çâU@½–m—nÿ=ìá}+[;/ŸzÆÛè#g/ ¾s“åñÜ<órsxùÖ¿d•qœ§åïUröò^µë@R\ ˲<ÀØè^Û§†_ƒë§Ž‹À•äÑõ« ËkЦÝ[}¾U F ‚ ‚(_¶N.¶N.E…bI±«±EIáäh,Ë{ñ.6Í0îžîÏ]t¤(Jj-/iïÑsǺy®îKÓt‘b Kÿ6EZÄÞ¦µ­…;S%•+¤òç601,Ûoü‡w.+}2*eîà)³ïöwcŒQUé´ÚÇ7‚4jËãÕmÒœ/HKLü€•m ¿æž#Aï.—µ\j¼d1hÛÞ*f2• F ‚¨ªô:ÝÃëWÒ“oœ=ñå¾cr{é)Iw.žMˆŠˆDŸ~³ÅÜs$‚ ^‚£AT^jUžA¯Ï_˜U„@$zú쌔¤«'sÿU¬á[¿†oý‹G."OATZ$%¢ÒÑjÔ?,™£R*3’“2ÓR}8#°ßàô¤Ä5ŽZ»ï_Gwm ~2iùæž)Añ¶H0JD¥Ãq\FJ’•Ýüï¾yþô7öl0è3R“TÊÜüzñAT3·ÎŸ¾}þ´N«>kAé9•ÊÖƒ K7ΜPfg™ö‰Â¡´Â¿DÙ"™™ ‚¨Œ†mÒ¾³…•uÝÆÍ”ÙÙæžA$%>î—¯>ó¨ëÛaÀûÂÒ3•‡´Ä„]ë?wôðêôÞ0 Yd~Qbtäò1C¢"Êcð*\%¢2¢YVla  p%ÎÀétZ–-¦„ AÕ@äÓG‘ÁO†µsreù€ Q©¢"$2Y̳`Š¢jù7Š%Yi©¡ïð¬ëkec§Q«’¢£²ÒÓ"Çq•ªfƒ†<¾àÅSD? ÎËÍQ+•r{‡äØO?™Â&&4$üу¼Ü'_@Q”A¯ #ŠjøÕ/)3qRL4ÍЉё:­ÖË·¾¥•5Vöð^VFšÂÞÑ£¶EÓqaQO'ÇÅD<~˜“™áèî%‘J¤&Ädž…P4]³^C¡DR~ŸmeF‚Q‚ ªšf(šN‰‹µur‰ {–ßβ<©ÜF­TîÌãñs²2J¯ HDesbﮄ¨ˆôäÄ£¿m—Ê#f-´Éâ#Ã×}u|É>'‚¨xÅÑÐòè¬b¿r µzËÛGÍ]þøÁŽ/–OX²ÆBfe¬än0²ÒÓ}8³Eçz½ŽåñOïÛÍãó§¬þŸ@$^5iÄ¥#µë(±°³`ùªI#{žxõØáذgÅ£ê“YìQ<>ŸeyÅãó59¤Vrߦ-ùB¡ñiÄÓGîžÆ½M®QÏž6jבáñwØ­lli†1”üŸaY…½cBT„H,aXÇq,ÇòøEñxçµÊjÖoDÑ´½«;/HŒ‰.6àV«ð|aXŽãr234µ£EÓîµ}²ÒÓÒ““Ý=YÅòøÆõ9™IÑQgüqíô1Ñ!O¢"^7ÕsB½^øb»N«¥8¥TûZ£™ F ‚¨t(šv­iª¹Çã j5hd|laeíÛ´å‹ýùá‹¥ü$R™§TVÎ3%¢x6ÛZ™§õ.6}]Mƒ*xʈr238ƒ¢iƒ¡ÄTÄ/ðetZ­V£`Ðëõz])g)²Ö“fš¦ z=­FM3L±«W–[Xœ<£fƒ†ÆIÙýÈÒi4VâH–Q•Հ劬¦"‚ ¢ì),ƒÁ\™«Ó¨Iø£aîG?{úôö:š–ÇYTyÊsÿÌLM¹}á Í0Žîž¯x ÂÁQ"•ÝbX€•íøÅ«ŒÛá›tèâÛ¼•V­ˆDÂÿfΰl÷ác;ô_¯×ß ÂÞqü’Uy99à8X̳úóu efrSm,Ÿ½¼wå@‚Q‚ ‚ Êçïþ[LZ‹¬Ì–©”¦™—Ð #za ¦1ëpa ËJ­å}hÚx”ÈŸ)1AR‘¥Ÿù‘"Í0/® åñøùWXÃÝ¿vê߯vè?ÄÎÅ-?õßP%¶°Ä Ó¦(ªÈS–åS“– ƒ^Ÿ“™aoy¹®óA€+«aËY3JD…ÊJKݵ~u^n޹'BD¹ã1ʾËì„G3S5ªª±™ÆHl)õ¿=¼ò[„b±ƒsá?ÅnK2#µ*/3%ÞÉâP@µlqùž*-re” ˆ ÅŠ¢‚ŸÜ¾p¦U·Þæž AåN&Šéì·èQ\ßÛc”ÙŽ<Ÿåñ8ž^oИ{j/a)³Çé4¦yÚ9¹Úõu-Ò'ÿUsáƒN§Õjt ŸŠnå½¥¦Ãñª‰‚£A”7–¡i |Æt†oiÑ®÷€{v¶îÜÇçë œ«2÷’ˆ*„¢(]ü"?-8AYä"^˨ê¹îuW\ŠÏôOÉ®–SCkÿ·C¼z›©°zfcùÔÑêŽT_…îÎç#ÿ ‚(_ß Ó«4Úüí±5ê7üåk¢#Ã]¼j[r³2ÿ÷ÉG®5kš³Ä|3%ª ÐsœÞPÌ/f•J-%9h+N&Ž‘‰càøN/Ôø$-ÇPÚª’O´$$%¢| y¬…§×ëòƒQ¡X,KRããòƒQŠ¢xïuò¿Ä›á8N¯Ó*,Å/ïJ”–QUõà‰([$%¢|ñYF*à§j´ù‹ý)šá@ååææ÷YXN[ó5ÍŸHD¹3ô< 2qäÐ!¢LÝôA”/š¢¼ìäªÜƒÁTM^§ÑtZcéù|:Îð_¹y‚(7\^NŽÂB$‘`” * ŒQî<íä®Ö–9™Æ§™©)j•ÊÖÉ%¿ƒ2;kÝÇ“ölüÒL$ÞµšÒ¨›y¹0%ìm"¢â‘`” ˆrÇcè¦^άA——“c0®ž8Ò°m µ­m~­Fe,ßLåD§Õ(33¸;Ø£Q™`” ˆŠ`%µ­íÎjU1¡!÷.Ÿï6ltáò€)ñq<¾ Ã€÷Í8C¢ã8N™““–V×QáãD¾óDåB¶ Q(ÀÝÆJn! Ž;¹ÜÎA¥T²,ËðXŠ¢Å–Ò‰K×È6æž&Qpz­^£Õjµ­JeÉg|½\äRº„ ãA˜ F ‚¨8–BA Ÿw-g»˜´¬ÔevNn¶V¯7p|ÈÁÍ+%>ÞÜ$ªš¦D,#æ³vb¡½ƒµ‡­µDÀ3÷¤‚( F ‚¨P,M»)¬ÜV:ƒA£ÓkõzR€‰(À24ax,C®…DeF‚Q‚ ̃¥i–OäbATIII5 11ؽ~~æž Q•‘ LAA¼6…[·‚¦¡"Õ”ˆ·C‚Q‚ ‚ ^ÃÀÅ|RÄ—xk$%‚ ‚ ̆£AA„Ù`” ‚ ‚0²›ž ˆ²¡Õjoܸ‘ššjî‰Ä[Q©TæžA¼CH0JDÙÈÈÈøè£hšÜo!ª6ŽãT*•@ 0÷Dâ]A‚Q‚ ÞŸÏoÚ´©ƒƒƒ¹'BeF(ZYY™{ñN Á(AoK.—oݺÕ`0˜{"Qf(Š …æžE¥–”„q㜠–„ÄÛ!ÿ‚‚x[E‰ÅbsÏ‚ ˆ %—ãÛoa0ÀÉÉÜS!ª8ŒAñÚXîîæžQ-­AA„Ù`” ‚ ‚0ŒAAfCÖŒñ¶t:]DD„F£1÷D¢ÌPåææ&‘HÌ=‘jkï^øúÂ×·OñÉ'˜6 7bêTxz¾Þ±÷î!$–ÏÌ998|;C.ícEh(¼½ñì¦N-¾Ox8V­ÂÊ•pt|Ë™–;Œñ¶RSS?øàƒÐÐPsO„ ÊŒX,þå—_Ú´icî‰T[›6aôèò FOÂÈ‘8}#F¼ö±W®àÏ?Ë7ÍÌÄ·Ù IDATƨWïM‚Ѱ0ܾ šÆ­[%ö±µET¶oÇ‚o3ÍŠ@‚Q‚ Þ–Á`HIIIKKsqqáñxæžA¼ŽãâããsrrÈÅþÒýï8|4 ™ _|//ÄÇcåJÿ.àéSÌœ ©sæÀ×+V sgtê;w") Ÿ~úf9`aiÓðÉ'?¾øùW$%¢lXYYmß¾½V­ZæžA¼•¼¼¼Q£Fݾ}ÛÜ©ì¤R¬Ykküü3-ÂÏ?C¥BÓ¦˜:¦OÇ?ÿ`èÐblØ "<={¢o_(¦öÈH|ù%fÍ·ßâÉ0 nÞ„ñë­J…#Gðé§HMŇbÀ,Z„={°b¶mCIiŽg΄“f΄³3¨Õ8v :à믱y36lÀޏ}Ÿ}†¥Káå…?„‡†Åô騳'ObáBðù(©×åËX´+V vm¬X_~A¯^8ssæ`Ý:øø€ÏÇÁƒøøc;|õ.^Ä‚ðóÃàÁhØóæaÒ$xyÁË b1( ßö푟~ÂèÑ%~ø­[ÃÛðò*íï¨];ØÙaÏLŸ^Z7³#Á(Aeƒ¦i[[['’ÿš¨â”J%ŸÏ7÷,ª€æÿoï>㣪¶>ÿÏ™ÞgR&½BJB“^TA¢à¬Ø@±\l€¨ˆ¯×‚€ ˆ…"J‘b ”Þ'}z=!@’L€õüòafÏ9{¯™$d±klØ€òr#;ÂÂP“• 8r¤þdÔÛÞÞˆÎ/z)&3f@©DÏžõ7úÏ?(.†¿?΃Ÿ6mByyƒÉ¨;™›2å¢ÂÉ“‡ÁƒñÁ0™°?‚ƒ1v,„B ŒíÛñè£èÐ!!P(. ïÛ¶A£@€ÌL„„`ûvŒ¥Ý»C«EÏžHNFQ°,{ :!$_ãÇ1f D"Èdˆ‹»Ð¹;~<ÆŽEJ t:””àž{lºS§š WŠP©ÄÓOcáBLšt!éo…h5=!„B®Ma!ÆŽ…Ó‰~ý–€ñÒKFÿþð÷‡ÕzÍÕFDàÊkƪª`·ãÈìÚ…ÔTŒu•ë/'ËÂfƒÃÒRˆÅpÿïC«EEÅ5TU^»»wc×.¸\5Ãë@M`åå B£B!tºú+ŒEûöزë×cèЦYxtï½ËñóÏMPUó¡žQB!„\›ädH$˜3R)–-ƒÃGŽ`äH<÷ìv|ñÅUj‹átÖSÈã]ô4' C­ÆK/!2ª«!—ßЉŠÂލ¨€Z3gjªàí ‡ø 'J‘‘(,Ä¢EHàrÁh¬I=/g±àÌôïŠ TU]hÅá@Ý™Éb1zsçB*ÅgŸÝÐûª¥VcêT,_Žqãnô³j>”ŒB!äÚÄÆÂlÆë¯ƒÏÇo¿Õ ”÷éƒ×_‡J…Ó§qüø…”«^ýúáÓO‘”„Þ½ëÍ0x0æÏ‡\ŽÃ‡¡×@×®èÓO=…{îÁùóp¹°t)$’ë#C‡â‹/0}:üüpèV®¬)‰AAžxááxöÙú¼‡­[ñÄèØIIèÞ÷ß_+<>ýyy8u ÁÁ5“4„„àå—Ñ¡¦NEÇŽ0p h4èÞýúßT] ƒÀŠøåLœØ4u69JF !¤~Ç­ZµjË–-‹åÙgŸÍÈȘ:ujc¶ 0™L¤ Mdk´9sæìÚµë?þP*•7XÕœ>}ú¿ÿý¯¯¯ïâÅ‹ÅbñWèp8 ƒR©dÙzf‚þ*u_Ú­;hôïî߀ª*0 Úµ«§³S«Åðážž=‹ŸFy9FnÜ[j†Áþ±F#%£„â!.—+33Óétzyyeddh4šÈÈȳgÏšL¦víÚI¥Òœœ³Ù̲l›6m*++ËÊÊ|||’’’ŒF#Ç1b„Ñhlß¾½H$2™L999î^Ï¢¢"¥RÙ¶mÛS§NY­V‰Dk6›SSS­VkJJŠ···^¯·Ùl~~~iiiB¡°C‡|>@AAA^^€€ÿ*–——Ÿ?žã8­Væçççî\¬¨¨(... ÓÓÓ+++ù|~\\œäßþ“ÔÔÔªªªÀÀ@§Ói6›£¢¢ø|~aaa^^ŸÏ‰‰¹¼§V¯×Ÿ>}Z(Êår†aÜ免²ÒÇǧ¤¤Ä`0„††úûûgffêt:±X'òòò ƒV«ÍÌÌd&66¶nÍ6›íüùóiiiî!$$„a˜óçÏ——— ‚ˆˆ•J¥R©šû;NZ‰O>Áþýžz{cùr4gGk$aÔ(øù]ýÊÔT””à“OÖÄ1øøà¹çš¸Î&DÉ(!äÖçp86oÞ¼lÙ²ž={HII5jTjjjQQQttô_|ñǼ÷Þ{#GŽ|ýõ×çÍ›·téÒ-[¶¸\®M›6õïß?==ýý÷ßß¾}»Ãáxçw’““£¢¢ôz=Çqƒ :|øpï޽ׯ_?oÞ¼¨¨¨ääd»Ý¾iÓ¦Þ½{§¦¦.X°`ذaþþþÇŽë۷﫯¾Ê²ìðáà  P(öïßÿõ×_·iÓ¦¨¨è‘G‰°uëÖM›6Åý;fyâĉéÓ§:töìÙiii³fÍ>|xvv6€åË—K$’üqéÒ¥¬¬¬}.\˜––6sæÌäåå±,»lÙ²º‡[Æÿüç?</22òäÉ“N§À?ÿü³téR@ V«³²²¦L™âëë»|ùr÷ [°`ÁáÇßzë­N:gffúúú¾÷Þ{µùhuuõÁƒ+++·mÛ;a„U«VmÚ´©W¯^‡ üꫯZø»O<èÉ'ñÈ#žòx­w Mó‹<±ó÷ßßà¬Ó[ÜîÝ»9BùWRRRYYY½/¥¥¥ååå]^^PP­ÕjOŸ>ÝÌÑ]¿ŠŠ ‘H´uëV‡Ã1iÒ¤aÆ™Íæ””µZÍqœÝn5jÔûï¿ÏqܶmÛfΜÉq\rr²P(tßîp8¢¢¢2228Žûæ›o‚‚‚ÊÊÊ ßþÙ»wïE‹éõú;w>|˜ã¸·ß~{Þ¼yµM …ÂM›6qwæÌµZ““ÃqÜ»ï¾[PP Óé&Ožüî»ïr7gΜqãÆY­V§ÓùÒK/={–ã8//¯sçÎMž<ùÃ?´Z­ÇܹsçÜÜ\Žã²²²:tèðǸ#w,Ÿþù“O>Ùôßã&b4 $•JwîÜY·Üjµ;vÌý]¸„ÝnOLL¬®®¾Bµv»ýèÑ£‹¥nannnZZÚå›Íæ;î¸C(îÝ»÷òWM¦ÓIIà8ú¢¯ý*,Äë¯Ë³³³/ÿ™4 ÿýw½?ùN§ó’"ê:|ø°Ùl¦žQBÈíB ´oßžÇãiµÚÈÈH±Xäž‘Éçóüñ™3gNŸ>ýû￟9sæ•«Šˆˆðòò0xðࢢ¢Å‹oܸñÞ{ï}®‘°h×®˲gΜ‘ÉdgÏž}öÙgƒ‚‚²²²|}}œ8qbèСîíÖ,XP;9uÚ´iùùùï¼óŽû%‹Å²jÕªß~ûÍÇÇG¯× †ÒÒÒœœœ=z0 ä>møûï¿‹ŠŠ~øa.—«¸¸xçÎK–,0qâĬ¬¬ÐÐP†aºvízäÈ‘Úh»wï.‘H"##“““u:]·n݆ >uêÔÀÝïˆeÙ°°0¥R™””ä~ƒ—+..fY6::@ûöíç͛׸ï!ä6BÉ(!ävtù´ÅAƒ‰ÅâU«V•••uto²Ò8:uÚºukbbâ»ï¾k0>üðÃ˯)--õòò²Z­6›M¥RmÞ¼ùèÑ£¿ÿþ{PPТE‹***ˆÅ⊊ Žã†9w¿¿V«0}úôõë׿öÚk+V¬H$üq@@À‡~¨R©:侑Ïç»+q÷ƒºU«Õ£F3f €¤¤¤¶mÛúùù-^¼€Ïwß}g0ìv»@ 0 Î:[>Ö®‚—J¥,ËFv»½¼¼\þï «»9›Íf·Û½êÝöÀãñìv»Ýn`2™RSS®|b ¹ù½ñŒFLšt•㋚œ^œ´oߢ¶r‡¢"äçÃßÁÁ5…™™X¾R)^~¹µÌߥ˜!·>—Ë•••år¹rss+*****t:]YYYff¦ËåJOO ‘HÆ?wîÜñãdz,Ëqœ{<ýܹsv»=77×n·ggg›L¦ââb«Õê^~à‘GINNîØ±cß¾}­V+µZ}þüùC‡=ÿüóî%ê«W¯NKK[¹reTTT||¼———ÉdÒétéééþùgEEEeeåäÉ“·nÝš””túôé'Ÿ|²ºº:;;ÛétFEE½ýöÛ{öìùâ‹/JJJD"QQQ‘N§Û»wïùóçóóóårùСC¿ýöÛÔÔÔ~ø¡¬¬Ìؘ1cvïÞm2™ -Zät:U*Ulllll¬ÏwÞ™““³k×®ÔÔÔ7Z,–âââââb½^_ZZZYY 88xРA+W®LKKÛ´iþíâ°aÆäää_~ù@=¼ûî»ßÿ=¥RÉãñ²³³Ÿyæ±XܦM›U«Veffþïÿûúë¯Ýo¼ªªª¼¡ýÁÉMnÅŠšs†Z’ÝŽ°`²².ÚF¾1 ñÖ[ø÷÷ÆÃŽÃÒ¥MVÛ¡C>Ó§cÄìÜYSÈçC(Äš55[·¶¼G}4ü’­!·±ââb¥R)©o;÷‚èË÷¼4 +W®´Z­S¦Lqwæµ6v»}Æ ¡¡¡ÕÕÕ*•*++‹eYFsèСÂÂÂ>}ú¸G¢W¯^ýÉ'ŸˆD"§Ó¹nݺ˜˜˜¼¼¼„„„ßÿ]©T–••µiÓæðáÃf³ÙÝÉÇqÜæÍ›Ýó¥^yå•Jåçç·oß¾ÄÄÄ‘#GÆÄÄ,X°`„ «W¯.,,\¸pahhhXX˜ÉdÚ¶m[rrr÷îÝNg@@@¿~ýx<Þ† >üØcõêÕkÓ¦MZ­Ö`0„‡‡;Îêêj‰Dòàƒ&&&}8°k×.“ÉôòË/Æ£GÊd2FÖäk†›‚Ýn_»vm~~þĉÛÔî 8Î’’???^Ý3‚.—«¤¤ÄËËKÔð¦—.—«¨¨ÈÏÏ_çHŸêêj‡ÃqyײÃáøæ›oŠ‹‹'Ož|ù§äpèÊË?kÌêløà¬^:ŸJKqît:h4àñ ×£° Xf3²³!“ÁjEi)JJ‘— EÍ¡šyyp:‘›‹ÌL°lýëŸÌfÌ™ƒ5k’‚ ¡cGèt0™›‹Ü\Èå5{…:ÈÈ@Fìv¨T`âÔ)|þ9:w†Õ ¡°æÊŠ ¤¤ ¤jõ•aŸôtA*­Ù8©¸©©(+ƒJ>.òó!‚χł‚¨T5 œ;‡*ää`ï^üò zöDe%är\ö³— yy‹¯«³f¡}{|ú)Ê˱a&LËB¥BB֭äI×Ö3j0àØ1a—.Ó/Y²Ûí¥¥¥—ßåþ}C©f~~¾¿¿?-`"„\äV]Àte999¹¹¹7n|õÕW›¼r¡Ph±Xl6[“×\kóæÍßÿ½Åb9{ölDD„»O· ¹\.—ËUû4>>þĉv»Ýét6mC­-`ºÁ/___xzì À¨Q¸óNÌ «ÙÙè׿þ §#ñãQU…={Эú÷Ç}÷!!»vÕÜ>a†Gß¾èÛ3gÖßâ¡CèÕ ›7ã±Ç—‡¢"pæÎE¿~¸ÿ~ôë‡iÓ`6ƒãðùçèÖ #F !›7ƒãðÁ2Z-î¾#GbÏpNœÀàÁ¸ï> „éÓa04øf·lAïÞ=ƒcÉpNŸFŸ>¸çôî3`6£ºãÇ#1±¦æaÃÀq8y119#G¢[7$%¡¼O?=€‘#ñÈ#Èή§E“ O<{îÁš5ÈË»Ò7¢¸±±øóOpáë{ázññW¹0BH‹Ú»wïºuë„Báûï¿ß´5¿üòËÁÁÁ>úèªU«š¶æº„Bá’%K8=kÖ¬zû'n„{R·%K–8ÎÅ‹øá‡­³#œ´*¯¼‚Aƒ0{6*+1t(ÆŒAçΘ>óç#?kÖ`íZ(•°Z‘—‡_~A|<ÞxK– GH¥(+ƒÑˆ/¿„·7ªªêoB©„ÁPs”‘R …*+¡VãÛoqþ<{ …… ±læÏÇèÑX¶ ‹£<ó  ÂsÏaÉA*…Ãÿþ X°åå?ÿüS³‰ý%ŠŠðæ›xôQ<þ8 TWÀŠð÷ÇÊ•HKÄ xàtìˆÒRØí`·C§› ee˜5 wÜÉ“±w/¦OÇ{ïá—_ðý÷Xµ S7°XŒ×^ÃŽøþ{|ü1zôÀĉ¸ãŽzúP-”–¢°Çãµ×À磸ÿ®ol](%„xXí£Õfµ;œ.ÎÓá Kßáí:Š%¡Ú'·¬¿x×e씩£'MPTm˜«^}ÚßÑóÃϾ°Ù¬B¡ÐÏϯ ÒÐL xïȃ†°,ÏÈñšö³jZ,Ã<1Ÿ/ Y¶¹>yre:’’ÀãáñÇ ¼¼æÏ1c°?fÌÀ'Ÿ\8å(&11‰0d~ùz}Í‘÷cÆ 6|}ëo%&¯¿ŽO?ÅÙ³1  _?èÕ J%‚ƒ!‘ÀéDA\.tï±ýûãë¯Q^ŽÈHÈå5܃ÏîûŠ <ñäåáäÉú“ÑÂBèõ2¤æ4y6NÂØ±Ë¤¤ ¡õþþèÒ"‚‚`³a P@&ƒ@€+œ Á0 ÁÔ©xè!lÞŒ7ÞÀ®]Ø»—/#d°,d2t艦µþP2JiQ6‡3µ°4§¬Ò`±Y].'Ǹ8Ï'£5Œ&”f5SÝ)g³›©æ‹­¨Èi‰†àHÖçµHC׉e˰à$¾V)‹ ðõQ\zinîìgÚ´š¥ÜO?¨(0™•çÏÃé¬9 ´ö_wÚT›9]õKcÆ m[¼÷ڵâEèÒÀ¥‹¨Üº[¹¤ ÷0t-–Ÿq5YòÓO#$¤ÁwÇq¸ä]wamµº Íæ W …¸ìX4¨³³E=ÜÃåûöᇟ{îÁĉõ'¯"¼½¡Vã½÷pâœÎF唌BZÇA§7IÏÕ™¬"©T SJy<–e[ïÿÖÉÍŒep.›ÝaqØÓË ™ºÊ„PÿØ@_¶‘i9>>èÜ'OÖœÀ~ò$ ¸\øàX,X·O?0~<¤¤àÔ)t[]3ÚÞyy5I-Ÿ_³FªÞT‚‚ÀãáàAaçNÀÛ$ HKƒB¹¾¾HHÀùó˜4 ÒÓì§ „Z­[½:bcÑ©vîÄäÉHMEi)ââ ‚ãpö,°eËUÞ‹TŠŒ ää@¡€RYÿàûë¯#;cÇâ®»Öà¿ *Ú·ÇúõˆÅš5èÜ™’QBÈí㸳ºc™Š•Þ>u—uÒL–å |@$–X-æ£YE•ú~±ábýík9~ˆÙ³ñàƒ`µâÇqêvîÄŠˆÇÛoã³ÏjFÕU*Ì ‘øè#¸·ôðó»zVj6ã“OPZŠìlèõxí5H¥ðö®I"y<øûƒÏG@^yË—ã»ïP^Žÿþ·æ‚  Œ —ãå—1p Þx¯½†qãÀ0°tiý«ÎµZ¼ó.ÄîÝ0™pÿýˆÅÓOã¹çðàƒ0™ðàƒèÚ"xË–áÇÁ0‘¨ææB¾Ûµ+:tÀ´iðõÅÂ…õR/aÞ<øùÕß«zÉ•3gâùçñÀ°Ù°xq=©m+A¿„– Ó›þÎ,*”"q=›FÒ¼F$‘òÂÜʊĬ‚^Q! õÇ7§ 0u*Üç$$`ýz€¿MÏåÆ5½tîµäîʸ8|ø!¬Vøú¢viÜ\=늎ÆwßáàA¬\‰+j®ñÅšÍÔj,_xä ½^^rAóçcÚ485ÓR۵÷ߢ N'´Úšðê5x0 ÓÕLåƒ~@Aø|„…ÕlõÄ:N'a2@Û¶øâ‹šJ¦O¿°O“·7¾ù%%`Yøû×Ó"Ë^´mÖ•õê…ß~Ci)Ôê K—²²ðÑG5Ë­Z JF !ÍÎjwIÏeEbÊD‰ñø|™Ru®¨,ÄKâÝð rc>ùËE]‰*ÕE#ÝÍ…Ç<ÞE32Ý‹êjäȲH„¶m1tè…̵vAË^È;Y¶ž¾Fwµ¹)ˆ‰©yl·#1†:ËWóØÇ§&Ó­¥VC­¾¨D @Û¶5Ý…PˆÚM/.Y{$‘Ôäõñó»ô3”Jѹ3zõºèáY”ŒBš]jai‰Ñ¢öi`),!-E Ú%²c™ù~*¹ßZÇ,or=t=wÝq-BÇ\]P~øúo¿› Û¶!?ÿBIŸ>’Ñ›ŽV‹)S<ÄÅ(%„4/§Ë•[^%‘Éš'JZ±Tª¯(Ó[¬ÞrZ\ߊ¸·Fjd2¼ù¦§ƒ¸¥ÑßBHó²:œz‹'x:B€aY‡J“ÅÓBjP2Ji^f›Ý`µóhH”´ Ãð‚’ªf<€rM(%„4/“Í.ÄÇ^þÅÖ·¨9éàÞ÷ŸúΓlXñÑõ5ª¯(×WVÜXàWát8J ó¯~]½÷:¥…\#vû/+.´Ûl××ÊËJ9óù믪›å˜%³ÑP]^Ö´už:´Íâ….— ŽÇ0õþÔ‰Ä"£ÍÞ´Mß2JJ0f }ååž…Ü6(%„4/—‹srœÍéª÷«Þã—"Úu|è¹—¢;vÊËH¿¾F·¬þrûÚ•7÷Õ”—}ôòôë»·²´ä“ÙÏ;ìWχþïٙ篯•gÒë3Μt6"Îëpl÷¿|óMX¡Íjù}ݪàÈh÷.¶‡†ê»ãЧÜÜÆÔjÌŸ_³(!-ƒ0BZTiaÁÑÛ«ÊJ5>Ú>ÃG)ÔŽse=“tp/Çq]úßÓN¡Ö(ÔšôSIÙ™uï­,Õ%þµ³¤ /"®C׃y|cuÕñý{rÓRj¯~#îgXæØ“B¾L IDATî?Sñx¼]›Ö+5šnƒîj(³Áp|ÿîìÔ³2¥jà¨1J/o›Õšø×Î̳§5>Ú¾#Ԝ˵çç ~Á!I÷yùù5V$Ú±¥('» +cצõzÝ=\"“;ŽS‡öŸKJ”)UýFŒVj¼ìÙü£o`ð©Ãû5¾~ƒ'‰ü¹­('+?3}Ïæx|A÷!÷È•õl3”›~.íäñÜôÔC;~;ædpdtÛ„.IþRh¼"ÚuP’—“•’ÜeÀà”ãs..#ù¤Ýjí:pHxl{†aŒÕUÇöüQ”Ý}ð=‚kY¥\ZXpxÇ³Ñ Kj»oKòs ³2v{ÚÉãþ¡á}î §ŽìO;yB®Tõ¼k¸·€ÝfM:¸—eØôS'd*UÏ¡÷zû^^¿Ù`HÜ·ëÄþ=º‚¼]›Ö+ÔšÎýUèŠ3ΜìÜïN¡Xl³ZOìßÑ®#_ LI<êr¹²SφFÇÜqçÝB±Øépœ;ñÏÙŽò‚îCîñ wW›yötQNfç~ƒÿNÉå„B$$ !eMÜmMHƒ¨g”Òr¬fóÊ÷ÞÌ8sÒ' HW˜¯+Èü÷ág?o2,&ã'¯¾ØPG ¾²âãÙÏŸ8°G¥ñúùë{~ÞÀb2}ñÖœ=?ýàåç_˜‘›žj·ÚŠr2M†j³ÉX”“YZXÐP0v›õó7^Ù½i½·_@I~Nú©Çýþý·ß-Y¨öñ=öןŸ¿>‹s¹œNçò¹3¶¬þÊËÏ˪/÷oÙ̺ü¼ò’B§ÃQ”“Y”“ét8l]õÕÚ¥ï*Ôê¼ôÔåsg¸ WÌùç¯Wh´~;Ö¯Ú÷ÛOJ òËŠ vGQNvQN¦£Qx“¾Úýj¥®¤('Ó=¢}.)qݲÜ÷¿¯[}xdža¶·ò“ÙÏ[M¦ªòÒ%3žÒäY-æó_>üûV…ÆkÇú5ÛÖ~Ã]r~vÃLý§s_<:I,•íÚ¸Îf­YèsþôÉf=»míJ›Õ’|ì°Ù`8°íç•ï¾%‰Sûâ­Wúj³Ñ¸úƒ?|¶T"“'íÿ뫯YÜ|_Ìá°ëòó U•fƒÁý=r¹\“é»%‹²Ï›žºvé»V³¹ +cÙ+ÏÞ±U*—oü¿_· ÀÞ_7ýïíy Ë”~þú¬ª²RwµçŽÿ£ôòQyû\Þ"¹VBá¥G®Ò|¨g”ÒrlVKyQ᱓â{÷×øjy|¾Ãnß¾öÛvÝz3Áét楧%ÜØ&òò{OÜ«ËÏ}töb©T(‘ìÞ´~ðƒ²RÎ$ÿ}èý¿k|µÇ9ìvP8ñÅWMz=_ ˜øâ«W&#ùtÒ¿>ÞºWéåÍqœÍjq:ì»6®{àÉç×eÀàîí_RçíÀ°ìÃ/Í kc6èÓN&3aäcOåd%þµ«¶ ‡Ýö㊦Î{;®k÷N}½ùèØ¢œ¬ ˆ(Î~#°M¤ÝjMþûð£>yš® ïľÝãŸ{ù –1»Åtîvbÿ_CÇ=Ù!Á]ØëîÛ×~[”“åxø÷ߦ½¾Ççè1tؘgfp.çÛi©Gvl ‰ËNMyî½ejo¥ÆkÛšo™(SÔw áeÎÿ§ª´ô…÷>Ñhý¤rÅoßþ¯ö%µ·ïÓoàíà°ÛXÿÏ×=îþiÏçf¿õØC™çýBÂ\.ט§^è6hhçw.|â‘‚Ìôˆöñ—4¡PkîŸöŒL©<údíÚ6öï];¢ã;Ûµ#$ªm@X›ªò2µ·ï¤™sü‚CÕ>Úß¾ý_Ï»îýcýê~#F÷vŸÕbY>wFFò)wohaNfÀ¿½¤ä…„`ûvôì‰N@{²‘æFÉ(!¤åÈÊ£ÆlýîëíkWjƒC'Íœ£ôò.ÉÏ-ÊÉúrÁ|&CuCÇÖ—äçšÆ5Kp:ì‘@aV†· ÆW €aPØø`Jòr4Z?¥—·û^‘Xb³ZÊŠ µA!¼ýüeJ•.?ÏÛ/€aXÿ0*/Ÿü¦±VèJLúêý[6Øö+•·oí *mp¯6ý”ƒnäÊàÈ趺ØúsXL;‰\ÛùwyHT ˲`YÂìL™Re¨ªøqù†å9v±TÊ9;E²BW¬Pk$r€€°6u?Rÿ°p/­?¾@h6ªËËÃ#†ñö Ke¥…ù~!aR¹Â=n®Òxó]AþåÉh½x|þ€Qcøtq¿£ïÛýà“ϳ<•·»ÑÀ𣾺87»º¢üØž?ÎþsXÍ5¯fƒA¦T_¡ Òx]»âã1w.6o†XìéhÈ­Ž’QBHËay¼»ÇOîuÏ}ŹÙk—¾»kã÷cŸ™)W©;õ0htͱ-Âÿô1,ãr8jï•)UÁQÑϽû‘ûTq÷ú*ŸÊRÕb¾ä Q~#¶5U¨5úŠ »Í*ÖtO2 «P«m ‹ÉdÒëå*õ¿ÁÔ“"×û–«Ô<>âŒW}kN”ÈäWhÝÕèAP›ÕZ÷éÀQc7¬Xš~êD»†‰e2waei Çq Ã*+|bÚI ¿°'ßzO,•¹ƒ—ÊlNªPšŒz»Í*–J ÕUÎ:Y,ËòjtI¤"‰ÄdÐ0ªíV«û³²˜Œ†ªJwØN§Ó=q¶!ö‹ßZl—;x|þÖÕ_q.WÛN]Ý…f“ÑlÐ ¼¼«+ÊB¡ÊËG"“ß7åñ=úÔFâ~qæd#ß&¹²mÛ0e ,ÀµüÿŽëDï„–c2è·­]Y™Îãñ"‘T¡ŠD½î±ï·ŸÎŸNÒåçÞ±¥(;Ë}qPDTæÙÓ‰{w¹ç&ôî_^\´ï·ŸÊŠ “ÞÿÛfQ:©¼½\¾4;5ùï];2’O¹ï ‰j›züŸ3Gf=ÓP0mºzùùÿðé’ìÔä£nOKJäóùúúmÕ™gOÿúÍÿEDGF5t»L¥ÒWUîûí§³ÿµY­™¼Ï½£6¬ø¨8/'?#}óWŸ1lƒ} b‰Ôl0¸ï­íØ«—68dÏæ“)ÊÍv—$ô`µXROë3lTmj¸ËæÓGùc[ÖÙ3ûŠëÚÃn³íûuSYQÁ¹ÿìýyƒÓÑØñÑñ]NçÞ_6¦Ÿ:±í»¯í6k½—±,ÛeÀàÖýç螟~Keî9 .—këê¯ÒOÿ}Ý*…ZÑPC^~i'íþ#óìiwÊ«Pkº²û§õú ªúY’—»sã÷i'·®ù:¾wÿ€ðˆ.ýïüóǵ¹éç ³2voZ_»ÁV›¸öÅyÙîü˜Ü «”‰’B=£„–Ããñ*JŠíÚ!‹£:v:îa0Ì€Qc\Nçöµß:ÿÐð„>ÜG¶O¸ÚôCÛ k§ }váÒß×­J:ðÏ¿óñ¯g~´uÍ×ß-}W$‘Œ}úE÷½Ý‡ ++*ܵi½_phx\ûzƒ‘*/~¸üç¯>ûné»|>Ì33–7}æÚÞ[»ô]‘DúÌ‚Å|Ðåtù ûÿÐðÚžB…J3mþ;'öï!‰›ûßß¾ýßúO>t:mº0` ù »WU×µ‡;}Th¼›÷ßãûvŸùûЄf×öí]nâ ³w¬[½sÃÚø^ýÜSÄilç;ª+˵ÿvÁˆNè²uÍ×›mü󳢺òx¼g.ù}ݪï—} ßˆûY¶±‡xùùÿgÎ[Û¾ûæäÁ}mâ:¶ïâžØêÜ¡{¯ºWŽ˜2Ía³mü|™H"ylî[_?}e…L¡Ke?®øH =úêj߆êн×Ї9¼c«O@``x$O"бgß?Ö¯é>äžÚË|ƒÊ‹‹Ö²8 ¬ÍèÇŸå £¦=³cݪ_¾ùÜép´‰m_;6¦s7…Æëì±#]iä›% ))ŸÒRègÒrDéÄ—.*…wä®ñ\RΙ0xÌ÷S†aÚvêZ;z[[óä[ï]r¯B­÷ìKW'0<âé·?¬[¢òöyúíê–°<Þô…KÜãºõˆëÖ£ö¥#¬ÍSÈUêñÏϺ¤‰gÞ©¹7:¡KtB—Úò>÷Žês飼GØ&òÑ9oÖ>µZ̺ü¼³‰GÇ?÷2¿N·U|¯~F©{c›vŸúïEo¤ñ:öìÛ±gßK £:&DuL¨[¢P{=2ëµK.cy¼ûŸØp‡h-‘DzߣOÔ>å\®ÊRÝß»v´i×!4:¶¶\©ñžúÚ‚º7JåŠû§Õ³Ã«\¥:vÒñ}»» ÌÔw˜iŒ²2Ì‹ãÇ1{¶§C!· JF !Äö®þ*7ý\íSßÀàQSŸrï¢z‰œÔ³ë?ý°ý½º Z[è(«o§ÒºRÛ³ùǺ%Ã'OK:°7ïü…v5¾Ú‘ÿyªvêuàñx~Á¡Á…,9'-uÛš¯ë^sÿ´güBÂ.¿×j1oü¿ó3Ò'¼ðJíª)‘Dâ^þÕH=† ‹írÇuÅNjH¥7?Ž®]¯~1!M‚’QBñ°Ø®Ýƒ"¢kŸJå ¦Qõ6í:¾øág¹‚Ç»pÁøçg]uÁ–oPHÏ»†×-QyûÄuíy¡]±TÊ¿±I‚R…òñ7‰¥fh||/iW®ÖÔ{¯H"øâ«,W÷öð˜vϧñð…Âz·Ù''‘`ð`OAn3”ŒBˆ‡¹OTj ¾@P»À¿–{Éü•yiý¼´~—*È ¯Ã0—,ÛWh¼úôo콊K—üóø|I£÷ „ܤh5=!„Bñê%„ÜôœGq^6çâ¼ýndÊ#!7ŽÃùóà8„‡£»ëÒQÏ(!¤•2VW­˜?«0+óÊ—¹œÎ_¾ùüÓ93Ö,^˜[g9Nâ8îäÁ}µg _Ùgóf–5G„\Îå¢E?_~ééP¹^”ŒBZ)‡Ý–òÏ‘º{˜sg19—Ëb6¹\5û}Ú¬–c»ÿÿü¬ÙË¿ŽŽï\{±Õb¶ZÌWmÅép˜ zŽãjK\.—É ·ÛluÛ]ÿéâÜ´ÔKîµÛ¬f£á’ÂäcG­–+ícOHâñðÕW˜6 ?ÿìéP¹^4LO¹9ØúóÑ¿ë++üCÃuyQ;=ôìKþ¸öø¾Ý™çúßòÝ›Öß÷èa±í~úâS“ÁŸ‘ær:»¹gÈØIõî:yl÷‰í´ZÌ•eºˆ¸^˜Íòx¥…ß/{Ï}¬üO<ÛåŽý[>úǶ‚Ìó?®øhÇkz»¯çÐ{vûŽõ«OÜë°Û;öì3ò?OÕ{^(!-#<ÖúÊ"ä&@ÿzBZ)‰L>晾Aî§Å¹ÙN§£cÏ>ÿìùã¾GŸøkóÆêê„Þýî}ø1/?ÿ~#F˜ò¸_H8çâÒO'¥$ûÌŒ!c'®ÿdñùÓIõÖ_Z˜pû¯F>øÐô—ölÞw>Íår­ûø}CeåÃ/ÍëÚý³y/Ùm¶¸.Ýï{ô /?ÿÞ÷Ü7ò?O¶Mè àðŽ-ÛÖ|=úñg'¾8{ï¯?:¼¿¶ÚqÏÎPyù´ÀçCng.×EOYæ«rCê 51JF !­”P,é7b´ÒË»¶$0,¢mBWmPH›¸b™Üj6ù…D´KeÁ‘Ñ‘dJ%†aú¿?ªc§.†„µM>v¤¡&"ÚÇÇ÷îÑ>Þ7(¸87Ûé°Ÿ9zèî “C£cïž0EW˜—“–âíÙ±“X* jÕ±“—Ö㸽¿n ‰ŽÕædgjƒ‚ïßS[gÿû”þ{@%!ÍÏ÷u8ئ€¸8ääà•Wpú´çÂ"·:«ÕÕÍR3 ÓBn& gYžÆG €eY¡DRUÞàÂ#¶Nmv»ã8“Aï>)^(Idr«©þÙŸÆê*©\‘~ò8¿°ÆoJÈãóÕ"QŒÉt¶vcVކ¡õ¤¹¸\Ðë‘y•¥×‰’QBÈ­Æét¤Ÿ:ÑëžV³©¼¸¨ûà{y#Ëò|ƒ‚ ²3Úwï¥ËÏ3 >ÿN`³ZÜ 0ÿ®qoþß§•º’“‡öõ:Lâ®0¢]ÇŸ/;¾O׃;õ8bÊÏ~nå¢7U>Ú´¤Æ<3#²}|CÕfœ9ùýÇï÷v%£¤‰°*Õ]%%ëµZ¸;÷].ˆDžŠÜÒÊÊ“ƒüüf©œ’QBÈÍ¡÷=÷9]N•—ÏÃ/Í“ÈäÓæ/pçvB±xò¬×‚ÚDÖ^Éãñ‡?2U(„µyè¹—ëÎ:­«ë€!‘ðx¼É³æû…„2 3xÌDŸÀà¢ìÌ»'LéÜw ûJ†a&¾8;íd¢Ýfó 7ûÓ¯Ï&5VU 31¸ÎÉò—Ë<{ºCÞ¾ÁMôI/¯q:Ý—‡‚‚P\ŒS§pÙYª„4³99‚•+ÅNg³,b¢d”rsðkã~Ó¹€vÝzºŸòxðPݱTúÜ{_T"‘¶lP„4Æßÿy©´CNÎLî$Ÿ‘|>¨ žÜ ŽƒÃ»••Ðé4ÞÞÏøûÏ´X„Í×"%£„[Ã0J õ‘[£TމÙQTôQvöo,[Î0¥"‘OÛÉõâ8X,ŒËååtjD¢ömÚ¼ T\zôq¢XB!ä&&ø…„, zÃf˵Z³m¶,§³órkcV¥ ‰Â‚ À·e¥d”ÒJ¹œÎò’"•·@x•MkªËËøB¡TNˉÉí‹eÅbq´X|¥iè8PBH+e¨ª\:ó™üŒôÚ«ÙüÝ’E…Ù—ž²ù«ÏŽü±­e£#„Ò4¨g”ÒJqœËPUátÔœÀm¬®Òä%Ü߉eY¥Æ["—»_²6‹Ås‘B¹~”ŒBZ)†aåj ïßµÇ÷íþã‡5E9Y?}ñ©T®1åñ.ÿ­$–É„b±ç"%„rý(%„´R2•êÙEyûºŸö~—þƒßyò‘ÿÌy3ªc§ºWÞ7å †H!7'JF !­Çø÷Ô¥+Óhýš;B!Í„’QBÈ-ˆã8«Ù$ y|§c!äú•——y: B`4Ng3UNÉ(!ä¦Á° €¼ói>AR¹\(–4t¥Ù _øÔ”S¦õ¼kx Hȵa†a˜†^µÛí/¼ð‚˜æC“VÀår•””ˆ˜ÅqÜ~’¯Š’QBÈMC,‘ö¿oôÖÕ_íûí§á“§uégCW««SO»{Âä– kÅ0ŒÝn¯·\£Ñøøø˜L&“ÉÔòr9µZ-•Jyõ8k2™„Âë?/”’QBÈMƒaÙ»'Lî;b´Ãf«Ýש^é§“Ã#ºÒb±r¤RiAAÁååB¡ð³Ï>£4”´6,ËjµÚËËõz½L&»îj)%„Ü\™ByÕ‹¼üüŸ|ë}:“‰´rR©Ôf³Ùl¶Kz•†‰ŒŒôTT„\Žãôz}``àu×@É(!äÓ©«§C äêø|¾X,®¨¨ðó£!ÈÍÊf³™ÍfùG«®ŒŽ%„B<ƒeÙ€€€¬¬,›ÍæéX¹.—+==]£ÑH$ ®(½*JF !„ñóóS*•Çy:B®™N§3 7²šž’QB!ÄcX–mÓ¦^¯ÏÈȨwe=!­“Ëå*..ÎÊÊŠŒŒ¼‘¥ô d”ÒjY-潿nª./«-á8WU™Îa¿t@óôу9çRZ6:BšŒX,n×®Ñh2åÕ7%ăX–‰D‹åÊ;àˆÅb±X¬ÑhZ,0BšUuuõU÷çd”ÒJ)Ôšy_¬©}ÛåŽÐèØS‡ ¼lTÇNu¯|è¹—[<:B® ˲R©T¯×ßø;Bn"ƒAyµÎZÀD!„´…BQ]]M#ïäöár¹ª««Š«†GÉ(!äæÂ¹\.OÇ@ÈõP«Õv»½¤¤ÄÓÒBŠŠŠÇU§P2J¹ið|‰Tö×ÏNìßSVTèép¹6"‘(<<<++Ëd2y:BšÉdÊÎÎŽŽŽ¾ê&JF !7 ‘X2qÆ«öoù¹('ËÓárͼ½½½¼¼Î;g4= !ÍÈh4¦¤¤hµÚƬƣL„›IDûøˆöñžŽ‚ëÄ0L›6m²²²Îœ9¢Õjy<ž§ƒ"¤)9Ž’’’œœ__ß°°°ÆÜBÉ(!„Òrø|~dd¤——WFFFqq±L&“Ëå …‚²RrSs:ƒA¯× —ËÓøÊ(%„BZÃ0^^^ …¢ªªÊh4–••8OÇEÈõãóùb±X&“…††ªTª«Î½èÞæ ‹B! >>>´í(!´€‰B!„x %£„åt8ÊŠ ißoB!n”ŒBZTuEùûÏNÍMKõt „BZJF !-Jíí“лÿöï¿uŽB¡d”Ò–íy÷ðÄ¿vV••ÖÚm¶#lK>văBñJF !-Míí#‹‹órjK,&ã÷¿¿óǵŒŠBˆGÐÖN„–ÆŠø|A¹®¸¶D,•Mxá…Ú˃QBñJF !Í‹eÃx,óo Ã@.— y¬ÃŹ8N ö2Ì“Q’[Ã@ÀÖ?úgg8^/BZ%£„æ% ‡Õî`ÿýó¯7LF£Z`sºÜ%6‹å¯Ÿ7¨}µwÜy—ç"%·Œ“㜮zÖÉY-6•¢åC"„Ô‹þkHi^"_&ä;ëu˜vò¸ÚÇ×/$¬¶Äj6ý¶êËûw{"@r{á8Îa·ûÈ¥ž„Rƒ’QBHó øJ‰Èé°»ŸZ-æ[:n’@(¬½Æ¨¯6TUô6ÊC1’ÛçrñN%{:BH JF !Í‹e˜ Òl0p.‹ÉÑë®áu¯©()îu÷ˆØ®Ý=#¹XLF•X¨¦d”VƒæŒBš]\ oNie…¾Z®R«¼¼'¿2ÿÒ ºõˆëÖÃ#±‘ÛŠÝfs˜MÝ:DòyÔCHkA¿„f'äóºGsV‹Õlöt,äöåt:U•í}ƒ4JOÇB¹€’QBHKÐ*å="ƒí†jCU¥Ëåòt8ä6ÃqV³¹ºT¬’%„ú{:BÈEh˜žÒ±¾¾JÙsÙºRX&ã <¾€a˜«ßLȵãpœÓá´Ûlv«…uØ{G·õ÷©³ã-!¤U d”Òr¼åÒa 1çŠJsJ+˪+MNŽáó(%ÍÅéÇ©¤be\¯JB‹–i(%„´(m¤m¤uq\•Éb´ÚêÝ–œÄ0 j©XÈçy:BÈ•P2Jñ –a42‰F&ñt „B<‰0B!„¡d”B!„x %£„B!Äc(%„B!CÉ(!„BñZMOi.—«¢¢¢´´ÔÓrCL&“Ýn÷t„ÜF(%„\ƒ+œäYZZÚ¯_¿– †æ#•J/)á8ŽãhO\Bš%£„Æâóù6›íòr†a4··wˇDH3‘J¥ n‰Ãáp:<m¡OH£d”ÒX2™¬  àòrÿ#GŽ´|<„´$ƒÁ •J)%¤ÉÑ&BHcI¥R»Ý^oç(!·<½^/“É<!· JF !%X–­¬¬ôt „´4»Ý^]]­R©<!· JF !% srr,‹§c!¤åp—™™Éçó5§c!äDÉ(!ähµZ¹\ž••u…eõ„ÜbÊÊÊÊËË£¢¢X–þhÒôè÷Šr X– ×ëõ©©©V«ÕÓáÒ¼œNgAAAzzzXXØå›=Bš%¢ò_»®IDAT£„k#‹ãããœþ¼X,–ÉdR©”aO‡FȲZ­F£Ñb±Øl6­V{Ɇ£„¦EÉ(!ä",Ë6æ,D†a´Z­V«µZ­z½Þb±X­Vê"%·¡Pèçç'•J¥Ri#'‰rçr¹h RB®%£„‹H¥RƒÁàçç×ÈëE"‘H$jÖiål6›Íf‹Åž„›Í%„\D¡P OGAÈÍÄ`0( ZkOÈõ¡ßBÈE¤R©Íf3™Lž„›ƒËå*++£Ã™¹n”ŒB."•J•J%í$JH#•••UWWÓr{B®%£„‹0 Ó¦M“ÉT\\ìéXií¬VkVVVDDM%äºÑ&BÈ¥„Baxxxzz:Çqþþþ4Žz †ôôt¹\îëëëéX¹‰Q2J©‡Ã0çÏŸwŸ‚(‰hQBÜÜ9äåå„„„Ðo!7‚’QBHý¼½½•Jefffbb¢{[{¹\. éï.¹m9N“ɤ×ëÍf3Çkß¾½R©ôtP„Üô(%„4H ´mÛ6,,Ìh4êõúŠŠ §Óéé ñ–e¥R©ŸŸŸ\.§#Çi*”ŒB®Â½­½———§!„r ¢u „B!Äc(%„B!CÉ(!„BñJF !„BˆÇP2J!„B<†’QB!„â1”ŒB!„Ïà8Žàr¹< !„B¹½X­V†aX©Tj0< !„B¹ '‹Y™L¦×ë=!„B¹F…B€U©TUUUžŽ‡B!„ÜFªªª”J%ÖÛÛ»¼¼¼ººÚÓ!B!„Û‚Éd*))ÑjµX‰Dž’’B˘!„BHsã8.%%%$$D*•½µSpp°H$:wî壄B!¤ùp—žžÎq\hh¨»„á8€Íf;{ö¬ÕjußB!„Ò„ CJJ Ç‹‹‹‹ÅîšdÔ-///++ËËËK¥R) ¹\β´+>!„B¹N.—Ë`0èõúêêêÒÒÒÐÐÐÐÐP†aj/¸(`6›ËÊʪªªŒF£Édjñ€ !„BÈ-E"‘Èår•Jååååž'Z×ÿ–ÜÕ襻q˜IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/development-with-cvs.png0000644000175000017500000003506210014674771026073 0ustar frankiefrankie‰PNG  IHDR2ci©sBITÛáOà IDATxœíÝyxSUâÿñO ´, eJƒ´²Š,² SuDYÑYTPEÙý ŠŒR*ˆê (ŽŠÛðs@Ü[‘}PÚ ”Å@AT”­@áþþ¸iš¦Iš–¶¹MÞ¯§ÏíÉÉ9'L>œsr¯Í0  Ø*{ˆeA,°b€%Ë,X` Ä2K –X± Àˆe–@,°„ˆ`XKZZZ°‡^’’’Ì·*"[RR± ÈdÍš5 Þ@ÂQff¦yÀ"&p"…yÚ333Ùò` Ä2¹‚ÉTYÐË,X` Ä2K –X± Àˆe@’öíÛwûí·'$$téÒeÙ²e’ìv»ÝnïÑ£ÇG}dÏ;·U«Væq°Ç‚ˆe@’FuóÍ7§§§O›6mܸq’ÒÒÒbbb>û쳫¯¾ºnݺk×®]°`ÁìÙ³‡ÃáöxC7_ Ü™×-»þúë322ªV­êþÐèÑ£;uêtêÔ©ôôôþóŸ+W®œ;w®Íf›8qbÏž=ƒ3Ü•™™I, Ü™±ìᇾóÎ;û÷ï‘oƽ{÷2$77wÙ²e—_~¹Y¸fÍš#Fddde´¡Š›/§ùóç¿ýöÛ‰‰‰­[·ž5k–Yß±cÇ?ÿùÏf&3w•=ðÀ>ø`Pš˜- Üqó%+`¶ À*ˆe–@,°b€%Ë,X` Ä2K –X± Àˆe–@,°b€%Ë,!"Ø–f·Ûƒ=„Ðáp8ü<Êl€%0[Šf†¯‡l6›ÿ PÞYòXŠVdª$vÀ?1,Ù2P41/R ³‰Ì–X± €åÙlbÏ €0@,à™„ÌŸ¨(5j¤oÔ¼y:~<Ø#«°—ŠB,P”³gåpèã5fŒš7ׯÁ„&bß C†¡œeeiɵh¡C‡Ô§~þ9Ø#€D,P”¨(ÅÇkèPmܨ6mt䈞¾@…×_WR’¢£¥&M4a‚Ž“¤£GUµª""tèPú§N):Z èܹ"ZðêÌ=ý´ÚµSõêª^]íÚiΜü¦”·\øÛoº÷^Õ­«K/Õ-·hï^Ï ÇŽé®»T«–.»LÏ>+I‡«]r‰êÕÓ£Êãkeþi¶yü¸† Qºì2=òH~ ®åK×Ò0bã물0sCá÷‡÷ß×ßþ¦Îµ~½³Âwê7<«µh¡¯¿Vt´ Ò[oéÙg5n\þ£¯¼¢{ïÕøñz晢[ðÌ™3ºî:­[çY?)I¬ÈÈüú}úhåÊü iÛ6Õ©ã³Â{ïéÿÐÖ­ù% êþûz™®6o¾YÿïÿåW˜?_ÿ{þ£îxï…•¤¥¥IjÖ¬™×GÍ{brŒ‹dž%?÷ÄÌÌÌd¶ @q\}µ$ef:ý׿ôÆJHÐòå:vLgÏjãFuë¦ôt=õ”$ÝwŸ$½þzF^|Q’î½7 <<û¬Ö­S:Z¶L¿ÿ®ãÇõÆŠŽVZšRR ÔLO×7ßèÌ­_¯„ýø£fÍ*PáÈedèäI=ü°$Ý}·ªTQzºNr–¼òJ /Ó%;[?ü “'õÐC’ôê«Îr×Ç•¹.̧o˜-à¯Ù²Ü\U©¢ˆç¢açÎÚ°A6¨cÇü:‡5Rb¢ví’¤fÍôÃúî;]q…$mݪ?þQ]ºèë¯mÁ}0mÚèÿÓÛo«ÿüúo¼¡;îP۶ι.³þÇ«gOg…>R¯^jÙRߟ_aófýñ’ôÓOª_ßKÉ%—8¿yø ·lQ»v’täˆ4P:q¢ˆS X³eå€Ù2¥í—_$©fMç¯;vHR§N.¨Ñ¨‘$íßï¬3b„$-]êüÕœ*6¬-¸ûáIêÝ»@á_ÿ*¹Íá™Ì‰=S’”•U B›6΃Ë.ó^âJT²ukç™óNžôòTå|£Ob€âøòKIrý“ÚÏ?Ž]{ðï¾[‘‘zã †NœÐ¿ÿ­54p`1Z(#•+]b |¾ZÂXFFF|||9tä¡J«Ó§G÷îÝ£¢¢ºwïîg>¬HÄ2;yRO}ôÚk:p@¹¹:sF™™zé%ýéOù-¸6þ»oö/V .æ4Ûèí·uò¤NœÐ›o:Ç3xpš£FiÃ;§o¾qV¸é¦žâÒ+óK ii$3„›Õ«WÿùÏ–´eË–öíÛGDDØl¶ŒŒŒØØØÓ§OK:}útlllffæOr¯|öÙgcÇŽ­ZµêÃ?üé§Ÿ–üdP˜äý§qcãÛo Ô|è!Ÿ•].\0š41¢¢ ÉhÚÔ³¯"[p?ÎÉ1ºuóR3)É8s¦@ýÞ½ ThÔÈøùg/ XR¬Az-¹í6ï'°€ÔÔÔÔÔT‡Eÿìv{ff¦amÚ´IIIÉÉÉ1Ëo¾ùæçž{Î0Œ”””[n¹Å0Œ5j,Y²ÄUAÒ’%Krss Ãhݺõ¼yóNœ81oÞ¼6mÚx-qƒ«S6¯ºêªÅ‹çää|øá‡Í›7÷è¥ðÌ6=F^¸‘J•*?Þ0ŒÜÜÜÊ•+û9K¾N²ÃáHMMå­€7î¢Z5£Q#£woã…ŒãǽTþôSã¶Û »Ý¨RŨV͸â cäHãë¯ Ôyúigk3g»sú´1s¦ÑºµQµªQ­šÑ¦1kV~&sÕ?vÌ6̨]Û¨QøùfcÏÏ …_¯ÿ’b ²p‰ÃaüíoF:†ÍF,ƒÕ”],ÛµkWÆ Í㈈ˆ“'OºZ·n]£F~ÿýw»Ý¾~ýzÃ0Þzë­®]»Ö©SgêÔ©f³çÎs=÷Ô©S†aœyë­·$µmÛvذa#GŽŒŠŠ2íÖ­[åÊ•m6ÛêÕ«]OÙ¼ys·nÝNŸ>íŠM’Z·n=jÔ¨¡C‡¾òÊ+/½ôÒ¶mÛ —DEEeeeÅÆÆºwêÑfÇŽÿþ÷¿÷ïß¿zõê®Á»ÜcHæ£#/ÜÈÀüñéÓ§ïÝ»×½k³Ä2@p¸öxIZ¼xñ+¯¼R½zu×W&'Mšôå—_Nš4ÉüÕÜvà 7üßÿýŸG;‹-Z°`AÍš5_|ñÅW^yÅkɨQ£š4ib&*W§m¾ñÆK—.­[·®k·™!yyáFæÌ™³zõêš5k~ùå—Ï<óL‰O³eB³e@1•ÝlY||üÊ•+[™_g./Aé´HÌ–Eøz à"íÝ»7L:-Ä2!‡y2{Ë,X` Ä2K –X± Àˆe–@,°®[ŠæõVEŪ€"1[` Ì–üÜÆ¥‹Ù2K –X‹˜ ¢ŠµÛ̓ƒ!±ÒJ,Œ+…b¨|¥±Ð˜*± XY¨NŒyÅ–`]Ž™ +± XŸdJ¡X*€PŠ_¾Ë,X*¯{ÿCl X¬Îý²±!ÅÜË€¥¾”¨&3®[,ÊϽ•B2™1[¬(Äîwb°œ0Ìd"–« ÏL&b°”°Íd"–ëçL&¾‰ ¬Àýj±á™ÉD,Aæ“d.,b€`"“¹ËwIII’233Ë¿k2™;b2™ö–§r›0Kºæ×qZjª‚1QgA6Ã0‚=|iiiåÓ‘+“¥¥¦–OBRR± ”#›Íy@)„½e ¼Éü"–€rA&+ [þ@s2‘Éü!–€²Ä$YÀXÄe†LVÄ2P6ÈdÅÄ"&(ml&+b(UL’•‹˜ ôÉ.³e 4°pyшeà¢1IVXćLVJ˜-%ÅÂe©"–€a’¬´±ˆ ŠLV˜-ÅÁÂe™!–€€1IV–XÄ!“•1fË@QX¸,Ä2à“då…ELà™¬1[¼aá²ÜË@!L’± ¸a’,xØ[òÉ‚ŠÙ2 ‰…Ëà#–ö˜$³báI2Ë –®˜$³ba‰I2ë!–f˜$³*bá„I2 #–˜$³<.' @YrCAä>IF&³*bX›Ã¡þýU»¶ªVU÷îúï奸a¿j•’’TµªêÔÑÀr8Š~ÊGéTT”š7×k¯•ÚH|q½X‹DœŠÅfcá²¢ –€µ  fÍ´k—~ûM3fè…J¿‹9s4fŒ²³µoŸZ·VÿþEÔ_¿^Æéé§uü¸>üP©©¥?$„‰c’¬B!–€µmØ ©SU·®¢¢tíµZµJÊû¬uŸ9^<¢úõU½ºÖÉ“Îr›M³f©AÕ¨¡aÃt挗.¾øB·Ü¢èh]z©&LЖ-E )9YÉɺáEF*1Q‹;Ësr4b„jÕR­Zºï>åää!9Yuê(&FË—+9Yuë*&FŸ|RŒ ^_µ;›M *>^‘‘jß^Û·û;3M›*=]’öïW¥J:xP’ÒÓÕ´i6ýWóózSRÔ¸±" nàþö[5j¤yóŠ8½¥…I² ˆXÖÖ¡ƒ\YY ÍOY÷ù™3µq£6oÖáÊŠÒäÉù•׬ÑöíÊÊÒ¡Czì1}<©”]wóW_+†_}¥^½¼”?ú¨Ô?(3S{÷jêÔü‡Özê)Ýy§Öþýzê)_Œ ^_µ‡Ï?×Úµ:vLýúiøpg¡×3Ó«—ÒÒ$iÅ EEiÅ IJMUïÞô_ÍÏëݰA›7+77¿äý÷Õ§.ÔèÑÞ_º˜$«  €•ýø£1l˜Ñ°¡m l8Îr7ð¸8cÇçqv¶Ñ A~µ~pgdv»ÏŽ$C2ê×ϯïë3¢re#7×Kyl¬‘™éyÒˆˆp{=3~h `†Ñ»·1i’Ñ·¯aÆí·«VhÓ5?¯÷àÁ›=Û°ÛM›|¾™Žæ*›Aˆ€ !;[ÉÉÚ´Ik×J’ÍV`¤J•üɤ d³éÂgµÜ\U®,I¹¹ªVMçÎùìâ÷ßõÜsúôS­Yão$õêiçN]v™gyD„ΜñÒ—ûP½^ÁãU»óxÈõ«×3sú´ZµÒŽjÔH{ö(1Q¨U+íÜ©ªUóñ_-×kþú‡?hÐ =ù¤¿³Z*Xµ¬àXÄ€ "&F3gjÃï6l¨½{•›«óçùÃŵºgbbüuQ³¦&LðÙ…K·núðC/å è«Aƒ"Ú)^ÏLµjjÞ\ ¨CEG«CÍŸ¯–- d²"«þzW¯Ö²eš3§Œ^¢ÄN²A,këÛW«W+'GGêé§Õ®³<:ZùÕFŽÔˆÚµK¹¹úî; œÿÐØ±:rDGŽhÌÝq‡—.îºK;w*7W‡iêTuíê,÷µ·lòd=òˆ>ùDgÏj÷nÝs³|Ð §Ÿ~rö5hÐŽro<^u |™^½”œ¬ë¯—¤ž=•œì}ÜŸj¿ÞF´zµ-Rrrñ@F&«Ð‚½Š ðkÅ ãꫨ(£fM£o_c×.gù“O—\’¿èüycæL#.ΨRÅh×Îxçg¹dÌšeÔ¯oT¯nÜ}·qú´—.Þ~ÛhÝÚˆˆ040†5ή/+WmÛ‘‘F“&Æ’%ÎÂÓ§áÚ5š5áÃóûroÇëqà<^µ;Â"ÏLf¦!9÷{mÝZ`ž;?Õy½î¿:d´li̘ᥗc'Yhao„4?›±P¡q'¥PÄ=1¨hØF¢ˆeTL’…4b„4>¹C, ðML,L˜-ÀÂdá„X€%È‹˜X™,,1[€•ȱ k …=bÁF ƒ$ö–dd2äa¶ € !¡ båŽ@oˆe”#|coå…L¿˜- ìÈbe‰@†€Ë(2± €ÒF C‰Ë(=2\b¥Á=‰L†’ –pqd(%Ä2JŠ@†Re3ø;~ÒÒÒ‚=¨Ø’®¹Æý×´ÔÔRn?)©tD…@, #¤1(ÔYŽga†X.Ü3Y³fÍ‚7¨Àbív×ñA‡£ì:ÊÌÌ4Hfa…X.ÌXF €pOc*ã@æÎ g$³ðÁ–| V Cx"–…¦Ê ¸d(Ä2 !XˆeÊÝnwð  #!¸*{¬Ån·Ûíö¸¸¸öíÛ9ò»ï¾ öˆÊ„½à§¯»ìììûeË– ýúõûôÓOËs`–X»Ýã[–d2”?bO‡#++kÕªU:uêß¿ÿöíÛƒ=¢r5räÈÄÄį¾ú*##câĉ¯¾új°G„²E ƒuËxQ©R¥  6lâĉ)))fáùóç“““Û´i“˜˜8jÔ¨S§N}ÿý÷]»vu]gÇ0Œ®]»îܹ³pMöÏœ93qâÄ-Z´hÑbÒ¤IgΜ1Ëívû‚ Ú¶mÛ¤I“qãÆ={ÖU>þü+®¸¢]»v}ôÑüùó[µjÕ®]»Õ«Wû›ë‰K—.íܹs\\Ü 7ܰsçNåM•™ó‚…_û–-[ÆŒS»víÈÈÈnݺ½þúëEvñòË/wìØÑn·ël¸žØ¸qã‹ø³BÉÈ`5Ä2þôéÓçÛo¿5çÏŸ¿mÛ¶?þxÛ¶m‘‘‘O=õÔW\q饗~õÕWf…uëÖÕªU«eË–…kz4ûôÓOggg¯]»öË/¿[¿~ý‘#GæÌ™ã*?zôèÆ'OžüÐC=zôÛo¿öØcýúõs=ôØc=zÔ,¿õÖ[p‘=z¨Y³æîÝ»½>4dȯ¿þúÌ™3¿üòËóÏ?å•W«‹œ ”vô£Âa¶ €'»Ý^¹råºuëvîÜùwÞqMýýï_°`Á€²³³›7o>f̳¼G¿ÿþ{åÊ•»uëæ¿¦ËäÉ“§Njֿ馛&Mšäz¨K—.×]wÝÉ“'oºé¦ñãÇ8æ"{ôðÀôêÕëäÉ“…w˜ :tΜ9[¶l‰ŠŠêܹó /¼P¬.Jp6Pº˜CÅÅ–ÿ°À–TÜ#ô[þà ³e€Š-¶ÐõçB !<ËUèM!ÌËX+˜ !‰X¨0HcmÄ2@@ C8 –¬‹íü+Ä2€1=†0D,XÓcgÄ2@ð‘ÆËÁÅb%àB,Óc@aÄ2@ù!~ËeŽ4‚X(+¤1 Xˆe€RV8‰@€X(5LƒX¸X¤1 TË%ÁJ%Pêˆe€b e‡X(i (Ä2€O¤1 <ËÅ€`!–†ÝÛ‡e9øœ-¤1 èˆe@`µ@frŠ|V¡‘Æë ––æÈ<¬‘k˜ƒ$œU D1Àšˆe€u¹g2K2“9$÷pF2³2¯QL¤1ÀJˆe€ÕY0¹óg°&Æ€ „XX”5÷“ùÇ„™E01TPÄ2ÀÒ,>UærðàA&Ì‚‹(„b`Eqª å(„b`]eª åÆWQ  Ä2°4¢>ˆe`-~r˜ˆb@H#–@ð1%@Ä2 ¦ÄF,€2ç?„‰@± @é²Â¥=¬pI[r€ –(Ö¹¢lùßl È&r€Ë”+\h­¢!! @!–€O$0”bH'0”b€ðxü2”b€TÜì%â –姸°È­ÀãË }Ÿ£È¦ˆ_~•ú%N¬p½ ¢ –¨üä0¯È^^åªrEvJn\ˆe@y+r:E:äûJæ#ŸóŠÈJñ¯¨-€:æØg€ˆe*óÓÝ ×E«X §±rþWA‘ݹr›k¨ä3„3b„š §±À¹F>D,Ê“Ãá°Ûí6 FZ–!Ù¤ØØX&Ìü¨@i¬0ò b„@VÒXa¾òá á€XU…ž+’ùZ˜¬ù·,PFBi±²¸<7™ùD={ªZ5Õ­«;ïÔ‘#þ*Ûl^~çQ¹¢MA¼Zä§ðØÖ1K,<×1Ãd±²¸8I•$iÀ5k¦]»ôÛoš1C/¼Púý<û¬~XGjçNÕª¥AƒüU6 çÇqÉ\ÌsÀJly?àT $U’¤ 4uªêÖUT”®½V«VIy“Lî3UçÏë‘GT¿¾ªW×àÁ:yÒYn³iÖ,5h 54l˜ÎœñÒÏÇ«W/Õ¨¡úõ5gŽÖ­+Þ0}u½j•®¼R‘‘Š×K/y¶ûÁÂ…ŠWd¤Ú·×öíÎòÓ§5t¨jÔPLŒæÌ©p³kÂÇÌP8'×ο¼J*IR‡züqeexÄ}²Ê4s¦6nÔæÍ:|XQQš<9¿òš5Ú¾]YY:tH=VDŸŸ~ª?ýÉy`òÕõ!š>]ÇkÍ}û­÷a»ûüs­]«cÇÔ¯Ÿ†wN›¦_ÕÞ½Ú¾]kÖ4 4”ÛÇjè}~‡Û:¦‹ÇÊ]XÍy¼X1’l†aÈáÐciÕ*>­Þ½5gŽÌ·<›­@¸‰×Ê•jÕJ’VÛ¶ÊÎvVûá5i"I™™ºöZýø£Ï7mÒ€úè#g}.ÐO?éÅõÀÅnÖÔ öîu»‹Y)õ•šJé’¤ýR%Éœ/J—šJ’ÎKHõ¥êÒ`é¤ÛÓgI ¤Ò0éL¡f%­’®”"¥x饼G}5h“R¤Æ’MjRðk¹‰Òv·OÓsÒxé2©¶ôÏ¢š}UzRj(ÅJOIK.•ÂyÅV#š¯1“Æ>*IRß¾Z½Z99:zTO?­víœFG+##¿îÈ‘1B»v)7Wß}§Áƒó;VGŽèÈ£;îðÒÏ?ÿ©I“ôé§jß¾@y€{Ë|u=h¾ÿ^gÏêÂ?ï}ØE8Ðù-ÑŸ~Ò¸qÅx"pŠu™Œ#R¦tµÔKJ“$­¢¤’¤T©·$i¦´QÚ,–¢$·íŸZ#m—²¤CÒc…š•4Dš.—ÖHßæUðÓài³dH5¥Ô¼Â/¤ÚR·jÓ¥Òfi´¿¨f¿“®Ê;î }çãl„çe2áëj5VŽhþ£ ᦒ$=ð€¦MSt´µu«Þ|Óùà„ ºêªüä4eŠzôÐ_þ¢êÕuçºõÖüfzôPëÖJHPLŒ¦O÷ÒÏøñÚ¿_W\‘²'Š1L_]ß|³n½U5jhʽþº÷aéÿP­ZjÜXW^©®]U¥J1”‹¥¿HUÜbÙJi´d^c0Mê%IZ$¥H¤K¥§¥wÝZxNj Õ—ž“þ]¨YIÕ%‡tXj,½œWÁOƒÏJõ$IäåþKVpä¯Ió¥Ë¥ÚRJQÍž.É;¾T:^̳wD´ 5?½Å›qñÛÛýoÛ¯XÒÓÕ»·öì Jçlù7ïú¿Mê+Ý-–ZI;¤FÒ)Q: µ’vJU¥*y­ÒÉ&™ëý6)Wª,IÊ•ªIç 6+é[éÒ×R5ižÔO’ß]ÃþUJöH†ÔDÊ’¢Ý*DH9…n'â«ÙZÒ©¦$é7)^úÕÇ ñ³ë?¬¶ü—gËT/-„ßyØòn¸U¹$iôhýò‹²³5q¢úõ+“.Š{¯„×1ÏIŸç-SV“šK ¤R´ÔAš/µ”ªJ’J{¥\é|^âqq]ÿfS¨YI¥¤Ÿ¤%×>M? ºÔ–n–JK¥ÞRtÁGJ…ÿ•ã«ÙVÒÆ¼ãMR+ßç„uÌ’ñu¯Žp`YÄ2IRóæjÙRM›ªfM͘Q†•e8Ë”zJ5¤RO·KÒ$©¶TGz¤àîìb•#XÖHÍ¥úy¿ö’’¥ë%I=¥ä¼LI#¥Ò.)WúNrÛþ©±Òéˆ4FºÃ[³ƒ¤ï¥³Òé| º3×1ZÁ”4TzHúQ:&)ªÙ!ÒTétPz4oeªpH*ë~”F, ÌQ£tø°Ž׿ÿ­K.)ºþE*›p6@ê*9¤¥ÎÒÀ¼r_(n9‚e…ÔÇí×^Ò¯Ò_$I×K¿¹Å²)Ré/RuéNÉmû§zH­¥)Fšî­Ù›¥[¥Òéõtgã„tm¡‡—ZJm¥?Hy×ÑñÙìýR7é ©•ôgéÞ@Î„ÒØ[†@øÊançÿ"÷–U“ŽIQ’¤©ŽtJ’ÔUz2ïóò é1im‰Ê½¼¦Bc³I?þxƒEO<ñ„Ÿ?âfÒ2é¥Ýi5[n\ÿG•ÿ_¹û<»+Že¡Š½eEW¾G‰[.i8vßyÝ[š-– é9·_(n9‚¥Ô/Á_¦Í–#xÿ x饗ЮTzœ¯ñ‰'ʳSAA,³†Òˆ}ó¤®y—¤J\wƒ÷uÑâ–€2Å–ÿÀ˜÷>¿˜Ÿ@Ú/Á¸ÜއIC¥_¥_¥;ܶK_"¹®w\º´¤å(S|M~<ÁT˜- ¶ÒÛÛ·Zú ooÙ£n×)0/:`îs¿è@qËôÄO„ä2ŇnÉ’í‰'Tðfåpݲr^Ä>ˆeÁSÌ}oY+)Y+IJ‘®Ì+7/:ðždHº}»­¸åLAÙò °ˆ %]²ôïßÒ—R¬+}évƒ_(n9(S\ £¼ðKn¾θB‰y܈‰›/…¡~çáá†EÌòBü€‚lÄM  1”ì{ÁÜ· ¸xÄ2À¼m9 ã¶å¥®d‰Šû¶XÞ*éJ)RŠ—\Wï8/="Õ—ªKƒ¥“yå6)Ej,Ù¤&n!Ì¥ínÿ<8'—.“jKÿ,ªÙW¥'¥†R¬ô”´ÄÛ8ÏH÷H5¤iŽ[yá6·yòˆePá ‘¦KÇ¥5Ò·y…3¥Òfé°%Mv«¿AÚ,RM)5¯ð ©¶ÔÆ­Úti‡´YÚ#í/ªÙ@îÛ6MúIÚ+m“¾p+/Üf[ocBßÄ´¾‰æ\—§²æ·•¹fw<žßÄŒ“ÆI·HÝ ã¥•yW„>,µ•²%I6é ÔP’ô¼ô•ô†$itµô ÛNü˥ϥfûòÕleé\Þ¿õ/H‘Rn¡q6’Ò¤&’¤L©y^G^Ûô:6¯Bø‡ob†f˫ɕòA}Wú\ê 5––ç:¤¶R„TYБޏÕo˜wp‡ô¡ô‹ô³ô‘4¸`³‡¤?êËW³¾îÛfËû‘”-%ä•»·ìµMÿcB± *¼ŽÒÒOÒ‹Òy… ¥½R®t^2¤ ÞžX[ºAZ*-•z»Ý´ÍÕžBOñÕ¬yß6“û}ÛŒ¼ó¹Yyåî-{mÓÿØ€D,€ oô½tVº Ï+)vI¹Òw¾g›†Iÿ’Ià =4TzHúQ:&)ªYó¾m‡¤ƒÒ£ÒÝÞú,•~’ޏ5è§M?cB±Ìrl¼Zä§ðØp‘¸LF‰…ùe2n–n•jHS¤×ó §H=¤¿HÕ¥;¥[}<÷zé7é„tm¡‡—ZJm¥?¸->új6û¶=!]&ÅI­ vç«M?cB[þ-ÄÜòØ#u1¸ÓN‰¹ÿÿJ ù+Q$¶ü#dpó% )»ˆœ––&©Y³fEUAÃ"&`-¬c–óI*:b€%Ë,XXë˜%Æ:&€ X` |°.&Ì ¬0[ Ô„äõ«„fË+"X@b¶ Àˆe–@,Ks]0…¯€xÂ7ÄD"–@…a#Ÿåñ8æ ÝŠŽ-ÿ`u®© Wø0ãHx^>×#•2O†PB,CØ1?Øx+P¬Ý~seùÌPÂ!Ÿ‘ÆXÄ ×\sÝn·Ûí—_~y=Ö¬YàÝ—V®\yÓM75iÒ¤Y³fwÝu×êÕ«iaÅŠ]»v‹‹ëÓ§Ï'Ÿ|b¾öÚkݺu‹‹‹ëÚµë+¯¼âêËäÑBFFFçÎ=žµdÉ’_‚ÞÍËÂU9÷¿É!¼¸Yø¥y¼v ”0[.RSS¯¹æ‡ÃqöìÙO?ýtôèÑ[·n-V ï¼óÎ믿>gΜ&Mšüþûïo¾ùæàÁƒysœ0aÂâÅ‹¯ºêªÔÔÔ{î¹Çáp,]ºtùòåK–,IHHÈÊÊš8qâ… †îp8ìv{á6ׯ_ߥK—ÂÏ2 ãž{î)Ö«@ 0afY¾7UñçÏ GL¢Â³eaÇf³ÙlÎw¼ôôôo¼1..îÆoLOO—4wîÜV­Z¹¦¬\ÿݰaÃsÏ=÷ì³Ï¶hÑ"""¢N:£F2ß%ÍÊ}ûö5+§§§ßpà æÜؾ}û$Õ­[wË–-§NêÙ³§ù”… Ξ=»iÓ¦M›63g΢E‹üŒyýúõúÓŸ ?ëå—_.<I}ûöíܹó{ï½'iß¾}·ß~{BBB—.]–-[æÞlá¡ÂSeHá $[œBó5f¦Ç>ˆeáÅn·'$$$''Ï;WÒ˜1c†š‘‘q÷Ýw3FÒ‚ fÏžíztý·S§Nˆ/ܦYgÆŒæ¯cÇŽ;vì®]»Æ?uêTI‹-Ú´iS§N dNÑýøãîM%$$}ú|öÙgÓ¦M{衇Ì:U«Výá‡Z´h1jÔ¨qãÆmß¾=77777÷믿v-†º»âŠ+–-[¶ÿ~‡Ã‘™™)©Q£FkÖ¬‰ˆˆˆ=qℤáÇOž%%eìØ±S¦LiÙ²eJJŠò’Pttôƒ>hÖ8p`ïÞ½GŒ1xðਨ¨ &dffV­ZµcÇŽææ-×þ3³å”””qãÆíر#::úŽ;î˜4iÒ /¼0}úô]»vÙíöY³fIº÷Þ{#""î¾ûnsökôèÑ·Ür‹{Sî#ÿæ›oºté"iÈ!.\¸ë®»ÌoÜÿýC† )<€»ï¾û–[n¹í¶ÛÌÂ/¿ürüøñS¦L©Y³æwÞ9yòdWý/¾øÂc¨eûgPqÀBUáèSþWa%~~Ø £¢_EKKK“Ô¬Y³`ÄÓþýû§L™2oÞ¼zõêùªÓ©S§7ß|Óµv‰rà'–ñ•L <™ùIIIÁÊ ‹˜¦ÆßsÏ=ýë_][Á Û°a™¬<1UÁB,C]ýõ_}õÕ¥—^ì „6(;ì-P€û2¥ÂX¸€òÁl€%Ë,X` IJ𒞞ž˜˜xìØ1WÉk¯½Ö­[·¸¸¸®]».Y²Ä,´ç Î(KIJð²dÉ’Ê•+»îؽtéÒåË—/Y²d÷îݯ¾úêòåË/^,·[as¬„bY9qâÄ|0oÞ¼W_}Õ¼ŒðÂ… gϞݴiÓˆˆˆ¦M›Î™3çå—_öõô¹sç¶jÕÊ5‹–žž~à 7ÄÅÅõéÓgß¾}Ê›cëÛ·¯ë2úv»½G}ô‘y\äSgIJ0òî»ïvïÞýÆo¬]»vjjª¤ü1>>ÞU!!!ÁÏ Ù‚ fÏžíºuÝØ±cÇŽ»k×®ñãÇO:Uy³k3fÌ0ë§¥¥ÅÄÄ|öÙgW_}uݺu×®][äSg\·,Œ¼öÚkæ¼Ô«¯¾zíµ×Úívó®”f…¬¬,?³VÏ=÷ÜܹsSRR&NœØ³gÏ;w>Ü|¨F®jíÛ·7ÃVÓ¦M»uëööÛoŸ:uê/ùKBBB‘O œ1[’’’¶mÛ–““cÎuíÞ½{Ë–-9rääÉ“wïÞ››»{÷îÉ“'9²ðÓ֧ͬOŸÏ>ûlÚ´i=ô¤+®¸bÙ²eû÷ïw8æ]Û 7nÜK/½´dÉ’‡~8À§¶˜- cÇŽ•´k×®&Mš$''ÿüóÏ]ºtq8.\¸ë®»‡Ýn¿ÿþû‡ ¢¼æ1sfþýàƒJJII7nÜŽ;¢££ï¸ãŽI“&¹žåšúŠïرcddäå—_àS[6së7B^ZZZ°‡€Š'éšk$¥¥¦{ @øJJJ öP~XÄ ü oÝá†Ù2¾Ùl’Ä»” fË,X` Ä2K –X± Àˆe–@,°b€%Ë,X` Ä2K –X± Àˆe–@,°b€%Ë,X` Ä2K –X± Àˆe–@,°b‰Íì”—ðy¥ÀÅ!–(&‡Cýû«vmU­ªîÝõßÿ:ËKñ£×fsþ^¿[7Ï’RI•*²Û5`€¶n-f­Æ×éjÝZ68ÏžU::wÎùë† jÓ¦<Æ„b€b0@Íši×.ýö›fÌÐ /”~†!Ã(ÞSjÔÐûï—þHÌÁœ9£o¿U÷îºöZmÚT&½XÓàÁzýuçñæÍúõWmÙâüuéR ¬q¡ŠX ˜6lÐÔ©ª[WQQºöZ­Z%åM·¸Oq?¯GQýúª^]ƒëäIg¹Í¦Y³Ô jÔаa:s¦tFõÌ3zôÑü¹¯ÃhÚTéé’´¿*UÒÁƒ’”ž®¦M½7^©’bcõÐCš1Cÿø‡Ï–·mS“&ùÒ0”˜¨íÛ}ž —œ¡ZµT«–î»O99Îr_çÊfSr²êÔQLŒ–/Wr²êÖULŒ>ùÄß«6Ÿ¸p¡âã©öíµ}»³Pò>=9hÞ~[¹¹’´n"#õÕW’”›«·ßÖ AþFž’¢ÆQ Áo¿U£Fš7Ïûy± @1uè ÇWVVB3‹¸ÏrÍœ©µy³VT”&Oί¼f¶oWV–Òc£k?K“mÚ¨[7½ø¢g¹×aôꥴ4IZ±BQQZ±B’RSÕ»wøÛß´nÏ–Û¶UÍšJMuVøâ Õ®­6mü Ó£êàAýðƒ23µw¯¦NÍÈ×¹:|Xè©§tç:|Xû÷ë©§4~¼¿Wmúüs­]«cÇÔ¯Ÿ†—¼ýÙ¹ÄÇ+1Ñ™öÖ­Ó°aÎXöÑGjÚTqqþF¾aƒ6ovF:Óûï«O-\¨Ñ£‹8Ï@Ø2ÀÉ(ü.ñãÆ°aFÆFt´1x°ápäWvgìØá<ÎÎ64ȯöÃÎ㌠Ãn÷×{‘%îå Æo¿¨éu~h `†Ñ»·1i’Ñ·¯aÆí·«VÑã¹sFD„¿–çÏ7 rh,X೦{ã±±Ff¦ó8=݈ͯàõ\IÆÏ?†aää8®\ÙߨÌ'=ê<>y2ÿµøù,X°À8Ð9Èýû¸8Ã0ŒŒ^(bäæ7"³gv»±i“ÏŽ†Í(îáÜòõ.‘­ädmÚ¤µk•ÝkV©’? sá‚l6]¸à¬–›«Ê•%)7WÕªyYytõà”«æŒ:sFO=•_âu§O«U+íØ¡F´guà€ZµÒΪZÕßRÛ¶:rÄgË¿þª„íÙ#ÃP“&ÊÊRt´¿Sa–GDèÌ/çÄ×¹r•×ã"{ô¨ïçT=ªÄD¥¥iäH}ó®ºJK–¨[7íÞ­zõüÜ££?üAƒéÉ'ýþAáŽEL%£™3ó¿©ç¡aCíÝ«Ü\?ï .®Ð={SšCš0Aï¼#‡£ˆaT«¦æÍµ`:tPt´:tÐüùjÙÒ3“öÞ{êÞÝ_˵k놴t©–.UïÞŠŽöYÓ]ƒÎIƒù•ì\ÙcàêÕS·nš0AII’””¤ñãÕ½»êÕ+bäV¯Ö²eš3§ä#± @1õí«Õ«•“££GõôÓj×ÎY­ŒŒüj#GjÄíÚ¥Ü\}÷]oí«#GtäˆÆŒÑw£ë"/{Q½º}TÓ¦=Œ^½”œ¬ë¯—¤ž=•œ¬^½|6{á‚ÒóÏkúôüÆ}µÉoÐÏÈ=4j¤Õ«µh‘’“}@ ö** óº·lÅ ãꫨ(£fM£o_c×.gù“O—\’_ÿüycæL#.ΨRÅh×Îxçü6gÍ2ê×7ªW7î¾Û8}Úg¿®÷r_ãt9޸ꪢ‡‘™iHέN[·ØÅUx$•+ ·ßnlÛV #¯-Ÿ?o\~¹o\¸Pô©0>m nÔ¬iÔ¬i žN|+_ç$“ïõ¼yüÙy8~ܨUË8~Ü0 ãØ1ãÒK'Š¹×Ž2Z¶4fÌðÞöØ[ |¾c œ+ ̰ˆ ` Ä2K`À˜-°b€%Ë,áÿ$“‘bŽ1ÉIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/alex.jpg0000644000175000017500000002112407363366176022740 0ustar frankiefrankieÿØÿàJFIFddÿìDuckyPÿîAdobedÀÿÛ„      ÿÀP¸ÿÄ   !1AQ"aq2B#¡Rr3SÓ$•‘±Ñ‚’tW b¢“³”´ÔuÕ6V–7  !1AQq"a‘¡±ÁÑ2Rbr’²“TðáÒ3CScsÓ45ñÿÚ ?¿Í- Üå¬}ø÷­TÅ*úºlšºZI‘ž‚¶óX|¢ ÁyðFÞi_uµ!lQ\=7Òˆ°¬/9Šä¸µ%¯*:Aƒ`ÓÏ5Œz΂wÙ¾†k-¸ì.äQÑIÒTFÁÅBõ†h‹?þò1ø,㜗g8°µ‹ÈõP’¹-LOY%Õ‰º1_îÝEpÛ4êž™~ÏJ"Éc(ÎuÌ ¸#pæÁì%䞯5 7FÞ 7aBŒª£Š O!¶¿²#pHDX%r~?UE Eä ©²v‹$ŒÀUAd_32f{>£ÄÓQ7Al\qÆûPpÔEЙ½ÆˆÜÍä±—’Zã®ÊrEž1C4›Ÿ¤0äxMµmA³FTIâÜÁW»æDÒˆ‹ú„C,ó—0¾=z%u¼Çì2+-’§©d¦ÙÊUðôã·Õ|”ÔSí×wIåËÍLÆcoµ#Ï méqó •ÀÖ9–ÏK!’’é]ìÆÁÅ#º=4 ³0æëñI4œYWŒÂ4Uar«… DžJq Ç‘éýÊ{ëyúnlxeº|ŽÛÝGVõ9îm|KAšž·sچё·g{%ÖÖ5Ôè%},ç: YÜ[K”Eîy1›²I‰â¢ÄøÌ#‹ö!ï£4ýàÒ;§Æ‹gëFçSÄŽÔµËaYm# N×Õ‘­¯@)Á‚sŸM™IæRe•‚¥k‡]G(vL ª"’´[¡Šn@‰>;o­=[–îôÖ6Wð¾'{20ñ0õì>ÝÑùšÓRy‰œL™¾Ôo/[z‰Z®Räë¼÷Ʊìf6GmŸK—Ëš°šhâ¶|ÆŒ½¿rùykc@Ð¡Ô ¸žiLl„4š7Œž"FUnå¯Ì:üútöðA‘ó—WpÂÎŽÞº¿µìÞæ|QÈñeœ™DËø*pºõî!À]È:aõ=xÿ!®ŒMœg¢l|±Ñ}Äy®®ó*<'Ǭ° õ)±û_MÆå´(¤¥S$M¼›"¯M¼mö]£Qåy-í½ò 5½h^Ê‚ÓóÚqoçÂ7šâ¸º÷+ˆÝÅ*úáó0vߦE5p^Yå^F¡L›ãŠÊœ—&#K2ùÖRŒâ´J 0 uNuÐÕ¹wLÒçî'¹“Ž€á#´+Ÿ\Ý#™5]Vþ Xø*GjRdÓ.ì§çüçþÎqýÆÿþ®o¹è¿‰—î‡õSßußÂÃ÷Çúk]Êœ³}Åá®Gs•ðÌÕÚ‘¤;¤´µÀò¾ôî“[úоý»øk±ÌÚ ÑïjÇ­)˜®U+‹ÊúáÖ¬[tYÁÄ\)Zû$Œè<Éß•åU¸uHÛÚ52C/M‡],ÎJ}év‹¡ÑP}Gî5÷2ÝuÀV¥‡Ua:þÃ#±vʶÈUÍVPç@£½ä“äë1Ÿ8ÿµG[EÙIW·æðMz¢3,CFB4X€-Å`@E;Qð×¾¡vî¿J%©D»¶N¥²yõé¥.©ÓÃã¨E©¿‹a>ŽÆ%YC"l\¯;RŽ4bàv¢¨¨¨¢‰l]¥±v–Ý«åÁ;¸WÅ’À§Èà:ë /ÊrÇäI¶'#«¤Jû’|Õ&ûÃbÛ°‡´E>TËg¼ODÓ‰Áµé4Z××ïo$ W®u7ð‚P×Û?Ó k–îÄ-óüþDÉvÙâ†ø2œvã2K¿¦Ø‹IòŽßM]9òñðÝ:.ͼ!¡¬@âã½Ä»3éTž@²dÖcRš¸œ¸¹ç:†Í£r¥¨Kè hŠ.{«¡f?=É4î .oʉ.›$ŽˆÜ´mÇŇ#ú©²¨;¿jî‹·‡UÕ÷áýÙuø±—·ÁÁÌ8¶ qSxáÏ5ó–ú#Á<%¥¯:„ð–×wj´ËƘœ“™;:ßÚVu6®lÉ "Î]Ulr‘$Ü‘1˜°È®åÔ·DO-uô=0G¯h×´Ñ¡Î4m÷{NÙ—qõÝTÉ.xö8—Uå­N«šÂx[·?9—61²ú\]ȯ9ú&<è©/øÌE?ÕLr³¶Ý[üÑèVÓÍÙitOò¤€†ñp¬ó”ùwå·^?Æ0\þÏÑÊ}§­&¼}ËÞú0¤ ŽêŠ¢¤«ÓoÖUNÜš¥–‘¥Mao/,Äq¸#hÜÞ,\|4Ûà¢âG¥_k´:…Ì]ÄPŽÃIGîáÁ¢»+²›jš¾Ûy1Î1f­pœºñZ¸´?Ì)êŽ\Rï”k°º&ˆªž ›t]t9ßE7Z‘“¿…†`÷†»Ù(¹¼‹® M0GÜNþÛñdeÍö·Õÿ¾&ÿÙ—!P9üæª?óGñVßz=JáÿP? s÷GÖƒ~ïç%ŸÓX¤IPmõ[É kj̆»Ûy{mUTI7ÙSÉueøou¬½•¤oi«N#v…Xø›7}¢1ü%¼R0ÑÂŽÀ‡z7g¼SQœ[˜3¤â9Õk=´™ÍRúSYùvôTÛÖewù›>Ÿ µVÒ9‚]<˜žÑ,=¨Ÿ‹O„|—np몶ë» ¬qŠá£³+0pð”Ýí=TLÌ;•2\w ‡Ç× šœŽYXÆq;*/P|IvF_TñmvÝ|7D^ž¥ [Ý@ot·F1|Gõ‘~“>vÍ»W/Læ›YÅŽªÐÙ ”~®_ÑÍÚwTiËÿòžQÿtMÿ˜=V4ßî¢úmó…iÔÿ´›è;ì”ö{ÿÁ×úÝýiÍ[þ$ÿ»—¡Ÿd*wÃ/ôqý'ý¢ŠœƒP.Ô`oFz~G™7&V=DÛi´©6vc’»TúSq§QUÂ_âÛ4í¢ ×NšÙNÍn\ƒu]oêŒ#/jÀˆžI÷ùënhÄd6˜Ó•ä¬ç ZlÜ4%MÔE7%ûÅWËXÀ©¢•ÅŸQ[w£®'y‡ªõíO»ÃGR¸d‹·ìó_ B/†¨ àî&*„+抛.€í°ÈeÆútI­6?ļ}®¦ÉÑö^ïó“·YkkàËų©BÒË›8©o,eãònb”nÆ1ˆÂÚ¿ ;\Ù6ÑwBÝQWuDùQWdY¹kF´Ôí>„mSoŽá;kù–@ß#ž_ŠØ´åtLA‚feu{ì¼c,\›$²zHžìº/>"ª?NÙ"íª×F#š8‚„•psonvV5õ˜äÜç„gIre{B²-±óy{AW¹ö;·^Šªž;¢î…ô9峿ˆÚù$l7Àx»1ÍLMå–_8·†÷•ds#‰ÓX¸Ôpö¤†¹ŽÜßý­kS-5ñNJÊ9]Ô²÷ƒµÓä m’x‰Ç”­8Š‹ÓôuY¼å}NÔÑð<ím=mG•Z,ù¯J»eÃÜâáÒ×Pùe÷4qN6שiŸS!ª~Î$YA2A¯’•Ç WËaÔZrƧti»úH-o[AåSyÍZU ¬—ô;©­©ò ¥ì|«Ü¤¸4.ã–XW Â’ÔëkKFÖ-•é2]Í1:ª,¯Š™&þ ãÓV‹GÛr«0‘²ÞZÖ´ñ2æç;';À<تµÛ.¹±í„ÄèlAsž8_52k[›[·‹¯<עĮåkÕðš°áÛÙG‡:4ÔF@Sà(ˆšÃË’:]/T{Ic ;Éq©Y¹–&EªiL`£Z÷€7Ö€¥N¾~¾†¸—è—ܺ‘š‚¡¯¶>Gãìw‹#ÕäÍ%“w¦å|ûÑÞ9F¢JÛŽ "*uNšúg=è—÷Z™’${x‹Xçdm|»uÝ>ÓKÏqÆüö´âì0%H?ÿÚ†)ýq ùÝSæu_ÂÍ÷nõ+§ýN“ø¸~ñžµ}ÞÝÓ_p}]½´;Š©y,¥³„ø?ÎÄØëjB»ª.Ë⚸ü8µšßYtr±Íx‰Õk{'qT¿‰—pÜ茖µì2¶ŽiÕ¡aE1Ùþ)¯àøµóWfWÔMÜ¿ÆóÊ)xÞWVݵDÎÕr9© ‚î6à*¯ ¢þÜÓu;:q=»Ë^6ú8à+KSÓ-µ(  aÙéb„(Ñ•¹É<)Qq\™|ÃÏ×IˆÝDrò€\hÁµxÓoª`UQ׿ñÛošó§?^•Žh^A„SP‚iòwdON=IÚ/Âö¸›‹"Ò+œ°Ô8¾[üÀÝLwÞÏvþâ1­•i–)ÓýmÍj|Iÿw/ÑgÙ sá—ú8þ“þÑD̆¹âϱÉäI¾~bv9E&Zµ’+ >elÔfÛì}ã}Zeþâë»$Ú¨TVÓhWõ‘ ÅÚ§$'Աܢë+¸î¢»wET_Ã]©ar+4O&Û2!}òq}îÀO$_TñU×0‘J —µ˜Û}ëðñ]cq¢•ÎÌɌ̦öo‚ïã×É~íD­,qiØs}Èí£c!ÐkÖ4mžòAî5ßaüUv^‰¯ÑM®´Ô ŠEØã£ÞÇwD=—¨Šø)'ÃYÚÒ[Űf¡3ù› X6M­ò‰a"/§ǼŸ„¤›J|[ùœe»Ým}@ENÒ]crœøå= %S1ñÊÚÊÚéJ³*#µ+ÎÈùÜ|Ÿ•}U^í÷U_5_cE½Ñj{Ñæ©8ŽaG†bÕnY³,rK[:¨VFC ˆ#Ç”ˈ; )ª§^£öëvßQº·ŠW³è¸·ÌVΙirk4LyùÍó…ê}Îòå ú´Rñêg•ƒŽTÇ/ô›Œ+¥Æ¥ur),¯xùÎ'ÎRÛK³¶5†0üÖµ¾`¦´syß#çVØ?#ZG·v}qNÇ&·ˆ¤Û±U=v;YCClûÑWªv/ÇZKyXcðaIz4‰0Ø‘")Ã}ÆÄÍ¢$ÙU²TUTñÛY+Ø ZH1\úw¬o‰!Îh$dHË£rãcc¢ËKIm@®¯däNšù 6ÓM¢‘™’ôDDM×XÖEYœ•þð «.uobñÖj­ÆÊnûÈÛ¢¸Ô PíEý_P÷øŠxhŠÚóÿ,Û¾ãïdìÃõUYW[´Ýwٸȿá]þÝm{ýÏï_õëZã­sÔo©eS{ˆåŠcÊûfÇÆ=¥=l $ø*”d4ü 5#P¹µÖw­AÓmìcúõ)ñí«Ü¼žbÈã ³¨£ ò,cϯшwÞ ¢à‰¸«¸Ÿ—]xs™8ÝÄvÔ×ÇšÊlà,ð7„l §‹$W÷)îf³SOQU"Ì®Ú9 W>ñ6Ä8¢½£"Gb)î (©¾ÅÕ6ë®¶fä^ì9û"”rO$Ò4ªªÜvYˆÈ'Áœ_óWD[,cÝÿ;ã²Y¹[y}r®Òê/"²ûo‚ô W[ÝÓ§BüR £5¡Â‡%eþÙyæ§š¨¯‡‰eŠ9lë¢#Iž©6ärmSuh»„‡§Åw×¹e|®ây$ï&¥xŠ&DÞ44nƒÈ·Y yX?!ØÞtå|¹-Ç¢àù,ÉŒóuQXiу)µ&+1ÁQÂ7Å × ¶Ü5_dFÔŒÛS$ÌAþ‘%L—õDEaûÕ7ßYøË˜°(¦+ªd¦áFvS¢F-íòŠ©.É×É7óר£284(&Š<ûš¦÷-“`Pb{Uä «,Y‘tíÔFd±2Œ9»,»&$æÛ/Q@ú³ó"mÞ­­4n##^œÄf!Ô®&´ðû8ã¿nÆ¡ùÀ÷\ƒmÇìrÅTzžE¦~«#ú0F£O*éÏà Hí"¯¦Ôáe$y!ôù{uèµü!ÎÌú?5 ›‘d"3VÐŽ¢HÇø¡_¼jÌû²Ã°¼.Vq;ƒdŸ›ÛM†ßÔˆG_2ñÁƒ1kÕ4ˆ/¦Š{"ï²ásI …ê # sdi Ó#ÂjÑÝí¦$ ÊCÓaô¸–Žá”âðRáU0«(VC¤ûàÅ[ÄuqÓU#.ÆÑ•w.¿l[8ÆàGRÁ3ûÇ*IYVLÖÐLÈ%GJyèì=9[EûÑ–\q}Õ<7ðñש[ÂâÝÅx¦ßb°ÒgPã“Øc"ðBWe¦%™:RkæÍŽÐHuÂG½³ý A "À¥²Œ’«Ç.ò›Çþš§„ôéîôÝd•Sr-¶Dó^š"óÏÈyµŸ#æÙ.ooÜ32)§$cª÷z 'ÈÿšÃDX!‰ÞþtqÈ×DôÞ¿,ÇY">l ž?š"îÁòû<0Ç3:r_Ì1¹íMi½öG@WgY/ø.¶¤ ö.ˆ½ âMNo‹ÐåÔozÕ9 &gB5Û¹ÑEP4Mö ]Ä“ÉQtEYÞúy®e…ØðÍ “SPŒËÍl¶ú©.»*ª/PhI ‘|IG÷º"®¥TDUUÙª®ˆ¦û#ä\þŠ«'ºº„Ô\6 Å’Ó’§œgVA@ tB=öñDÑB×ýÝ·-²…GÊPåÈón}[ŒúmHuâè‹gíÇÛï$ðÇ?Ds*­je$º áäõ¤oA7YThÈ„ ³TETßõwÑI÷Ik>ߟ¹1Û"86A_Kõ#Æa°hGìTù¾õßDL~%Âêù‘1Œ.ç! ZºúA²õÁ ’Š‹d`Ð!ª{¤(¿NåO XYþïJC¯3Á³éñ­[ÙǼi§£:_r86mïñA/»DN/e\s˜q~E̸ÆiPå]‹_’wN<¦§"=äù\û:¢ô$Eé¢)»•Á¬ŸZ…¶4™„XÑÜ”˜â3÷%¸À+€Ó!(ÛkÕ%MLÅ•7!Nº"kqì‰Ïc¬1mõn™¤Ycr\ú—)SbãU…+mß&nã"%%^äTlÛQ=œm·›u‡SvŸì_?ÃY‹H#0¡1™9Õ2Ÿi“VŸÙº=¨BbEv_³ªk¬àÉš ÉcÉk%dtøtI9NI{¡©ë‹‹984j‰±8á"w*íÚž*[""ëÑo©KsMÝ—òNfÞˆæË;$šá·JÃÐ'EfÅZŽR]X¾À6ç`oó"¯jöî›*ñ–Dp[¸Ó\Èkë;¦O VãÏlS` /²2ŽõÙ;ý'5O$1øë$@ š ¨)­™eUü}ŠÉÉ%¹¾‡‡ëŠÁÌۨ¨jÛM›Ä‡²ú@Ä›ön» û•åÇNýèÎÀ1ü£¨›U“dqrA ÇN47¢”*× ¨/8ô©E$˜>ñ—±U¯LHTÄœs•½ûò»piiøŽ¢Z}uÙ·k–kÕ¸L–ñ™=¿•t{Õ>žE¢*³7 i²u×I¦7""]„E<ÕUvM]-g·6ÃÚ«œG"3a“Ϭ+i®Ê£~j’ƒæßo‘ÁwýêhŠ—eøÏ=S%Tg ™1Í6&ÜmTL <”IDV‰ì•[•UyÄVÒö™Vgo‰ªîq]_él†ÿÉ:¨hŸ_†ˆ G7ΑcÌœ§2R¯¬æSfÚ¡xˆ³ Úü4EªâÚ87&qö;k²Ö]äU°ìº!2ì€Cþ|¿Žˆ½` ¶ÛmŠ mŠ"Š&Ȉ‰à‰¢.Z"Z"¬¯z>ݲ kßïk¦‘uõ‘3z¨‚†óe´æ¶Ú/q¢¶=® ¢ªv¡y®ÄU—ã÷¢þ(¨¿ãEÑÁáŸxü‹Ç@§ÊŸs;ÃQlãK.ë(¬¦É¼iD»Ÿjxª©ä„:"¶¾;äÌ/•h$Â.Bڽіßi6üg»P•—Ú4BD$ûÅS®ˆŸº"Q©W‹r :»ûSg.ä2-Lâ=3ì<é‰ÈyégY]pÞxAƒb(¨„(;jADXÆîÛÉ*BѨË–TèoB'[xÊùoCwçiHU;Ù_Ö@T-VaF6±žÜ‘,æ—gÅ^×⺠„̆ËÈ€HUzn›.è»krÝÁÌ,Û˜^NuQ’ª"óßçžÞ-òªìšd@cdÄõÀܬ–ÓñîëcIFÒd”A&Tþ]ôípv\¸¼í—åëS–*ð—µnHá¼ûæq\YC‹p¡L”í¥TÑ_í<ÛD80 øM)ƒ6Ûm¢z¯8BÛm9Ó\´Œ×¡ÚŒ‚¶ì&“4g2â¼êî²9ó-ì«Ý6Üy„’é,v6”€˜ÈÓEÚD;†ÈD›.¥»Ñ2 gµ97)À§Â›k7¯¤a <É" ;_ÍŒDÛLý•³˜n#Œ¿¢'NÓ{ÑD{É5De:d)–V[‡½—$Í–é ¶ÓM ™™ø Š*ªêyèåìðù7’óã´‚5äòZÆw †À£1…~ßHU>*º"kb¹ئKE“ÇÎN?9›°'‰g`»ÛG@… vBO Lÿ@9ÿMâ?ôYßöÝCÜÇ&‘™å7ÙlÈë&äSŸ60Œ;ÕÅl\3$B-ÉQIzªè‰ÉÄÚñŸ&a¹º¡Z;[FÃôŠâ¬IDø¯¤á*'ÅDDoux‰ã|Ë‘[ÆÚF;Ÿúy67jßV$³8ÝVÍ:k½Ûí䢾i¢(÷tʹЬëßXÖ²—Hø¶óŽ6I÷¢èŠôxÜ×r^9_*VQ]Ždí°ØÞãöo· Æäö§¨¬úÄ(ëj[¨ªôñÙzhˆ­7’øæµ“‘?>Ça²¤N;gSdûÜë¢!V+îo3ÞQ…Æx;®ädì s¦äí"· µŠ€¾“]â„ê—wRDíO%]mh}Æñ…¾c—`VWŒâ¹6#fýsñ.n3RýQõb¾D€h¾bª„Ÿ ºèˆMî+Û—gx½ö{]"· ÉâErpå1Ü Ì&ÅK¶` #gêm·¨?>ë¾åú*EL½Â%¶Û¦ûhŠnû Èì+yŠÇeÓZÌšŠIοÉêÁ6ÜeÝ¿|(f;ü DW¢%¢!ŒÞ8¯¨¢¹7‡]Še/ΗyWhãN8ÁÚÊìÇ~µÅ×#ÈyçÖÄÇä2ôû µD‰©ã|Ù\P+øòïY$Rç3ʾ¶Gå³Z!Ú]u$u•õá7èœÈàȶÒ÷=óÍQiy]•–pÆM-ælfq¤‹evÞK`ÛÒ·¦v¾G¦-‚ÈVÌ€vß艮£;×mÚ·tÆ“pÜOˆ‚´7Xk™EMÖ=Kr¸uÕÜ YdHŒH~ ˆRáÎaÀiñ&ϵƑ;K§U׿voÔÃrð­z¹|öàë¿TGÁy§œ!ç.c«g ¨²“‰¹>L*K)rã° `qþ±¸’\{éÐĽFÜP4ØK\pTtKű\oǪ1,BŽ5ŒÐÇ”ÔuÌ‹£2>Û`ˆ‰ÕUU|UUUz®¡3÷ÙÊI‹ñü.;­“ÙsŸšþd‚¿3uQ‰ÝüÓÖsµ´øzhŠ wOŽˆ¬ŸÛ—´L ‘8²£4ämÂÒþD‡ëÕŽßÐ úl‚õ5-üÑSDG_þˆp?òyõ¡7¢ W¸ßh˜ñe¾i€3nv”#?d&¬€ú?Mò@PN ¦%¿’"芶7OŽˆ¬sƒih}Íð,î"Ȧ LÓ‹^W0ËÅD'X‹% cª§‰4„„˃ûÔý$A\ëó4»Íèߣ±eWÒ7xòdr;éò8 ñûeé¢&bˆ’lB„ŸMôEÅh:£`?j"&ˆ¦±è629Þ¦Ê%t©Uêì›±²i£(ñÕÖ?g꺈¢=Ä›"*õ]}òmsŸ+„–I¥w%œã`è¨÷âB„‰º*uEM•Ǥa]5Ž+¸°¤ª©æƒ¾ß¹¢.µ!·TMú&ú"´ßc%yŽ•¯,eUîÕ¹qòìJºH(6ˆÉoÜ­Ç—9†ÿäÛ#·Ù¶ˆžø§pö &c> stream H‰­WëŽ\5~‚~ÿÄœñÝÇh…4a†UV —L#~ U†MØ…]íÛ¯]WûôéF4I—«ê«r¹ªl?9¼[ŸLÉi)ɘãíÁšþ÷ëæpý¹5À5Çׇ+»xkK?»¸T|¾7Ü=qóÕ³_Ü}k®®Ìí›ÿüûñåÿœ¹6{öòÍÏæþ·ïß¾zø¯¹ùõÕËO?4Ç·‡f°Yº*1vs¦áÚ´&µ.!¬ûØ8ÓPÚ·jÈÎbí'v57ÏÌǦ^ûöÏZ wǃ3ý¯{íV½I%›âÛ:^™×Û-¾o,óþóÖÐ"ŸÿÝRô}‰n­]èÝ0‘Í£9Ü÷ ;±ã"â,Œ«¹0ì<Æ©aÙæ¡ ºE™à è1E‚DºÀjvÄ´‚9L '¤î'søþ£Ã/ãºMrÝBˆ¥O´€ýd¾5?›ƒùVÚþÿ³ÅʘÎÆ*äÐCQS‡)äÎÄ}Ý„kÛ¢ Fºê #—ë"qÜHC¤÷%ŠÚ‰bYä™÷‹LÀzMè]oª±ñVÔƒ!lGÛ"ñ3µ-â1D¼Bè˜éT †,Ã.Šx°²`‘!dFUŠ‚…»÷õ°”.ŒW’]]Ò¨lÓ¨Á'Ù­{E\}ˆ|³±ƒ2Qt{bà1 T’&n+^TêL ¢±®¹Q]ÜÈËÌ_)3‘ ÂÕþp€€@DgÙ£h»ç}ÔƒÞ :(2VwH¦QW"ž‡dØ@·åD\ÜÑ Þ‰³¬TíâÂtÛ6û–b6Éû¹h“ÖÌ>Û-¿'áÇØ%’HtÊîD?ÅÖo|XH¬˜3qe§RkD8¦–¡¢€‘U< ɰ7"î‡û(茪âuÀš#šØ"ÚC­¥U,4×Væ°"%ƒ'{…E°Ûí ΄ "’«SWà%îg@ÙÓ¨†(8„Å…€`½§ÐÛ Ž!»>1*¡3$ÓÆ¸Ù,î,'Xd™Q•¢`al!®^̳™íÊr‰[ç •äsyÌÍ~Æé™U)7%%è”ÄtbÊ<§‡j™á$ùš,Ž*BCbÌ?fWRª#–& F¾¨Îç¹ÁïÍšCÙfN >¤±›çÒýÚ6|×ó<þB·r[¾ƒC^E¼ –èJå¤ÀÍì ׃õ H|àŒNNšÓ+.ò!Têíµí¢L6±uÃ’…]D­0‰uÒˆxÑ‚¢‘1d£KfpMSát£w·¤X>('×ONb¦Ó£=|x,¯§„±6w%üPžûuÃX¤,<ÔéÐÏVGÊ\´4 ×þKÎ¥2DA¥•ªÌuPÿ¤tÕcPòëˆèµvÑ ±Å73»90CÃÇ¥1Úg‹8;´SéŠn`ùª«{ùÉý4ÙŠÁ@°Á+ÓjnEIyq Rš“"¢AbGUŠÄóçÏÞÞTÞ4°¥§à 9@̲“q…§U¦ LNHÚà#騆B­Š*¬¹)\ä^Ö:8ðÙ8Rq7Z·Ôe%‰ µû¡Ëö´ÞZñ ÙŽ=€ÅãJü!¢D’‘’ä[!6û¢#ÝëmÈ}@dZ´Ú<éØÀÑûªî¢†ÁµžÒó‚:*’ÉÂ%Å9–¬ëCøv¯_¹Ú4]¹P„9¢a3H©Q€Õ¿ˆå0Oû´Åý„ÅYoçÅœýáª`üv’¼Sk+ܼÅvÙ«áîôÁá›ðœHÜud¢…>­ý !Ô!Ü6¦3açAGúZ¡‰Ž”²"fE\z€J£&’)ðU¿¯ˆ´âÓlCZÕÉ Y—B–9’AÂâ)¦¸>?ÇÒM±´¢d·±´C,ÝK?Ç’Ì3 jaùK‚£å£Z¤¼aÅüL *s/Ä5À}2F~ÊD1mØ¿`/Ÿ(ˆl²°£*Å%i²‚Ôℵ(³Œjeƒú‡3Õe>‰ûj;… ƒ§y¯æ§uœo™ÉF²ÀtëZkÅv=·Q<„V·â…™E”ŠÂ¡ Nô\%¯ˆ^É2É P]üS‰ê´Öà‚Ò½‡â…B'æÊÜp1žx ÅR9 4±Úvã |óvÞã•ÙÊú½[’²­*Ù%i¦Ÿ¤¤VʈZŠ¢e†Q-lPÿpPÁ.~$\ļ[ŸZÞIh‘µj{8¤\ŒÑ´e`½4æ9õ÷θwJÃ3#§¦¡rò0¯å[,“½œòªl0Œ8t¢.QêTF9ÐDzè –Èt`[àU ¯À[Ä`B6·¥=j8è^‹Ü5OŽÄïæx{¸þÜš&[R'_®ìâV߆}ãŽïÍ7ŸÝ¿¸9Ÿ?}òÍñîÅíÝýgÏŸ~u|úå÷šãÛÃÝq4C·¹ÙâÌaGZc ÃF_eކõ¡©\¿yçÌí¿ÿ¡û|« endstream endobj 9 0 obj 2258 endobj 10 0 obj << /Type /XObject /Subtype /Image /Name /im1 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 11 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 11 0 obj 456 endobj 14 0 obj << /Length 15 0 R /Filter /FlateDecode >> stream H‰5Ž» Â@D¿àþÔI‘ÍÍêÝ]ìòD´Ð„%",XE…(Úøû&‚L3bN zÄhqÈDiÁûŒ+x€ ÿ•ÀW”6Œ¥²Væx¡„•f“M~«…usýA´+6uéOþ¸¯Wèó®\çQÆb„¨Ù†8†¿Sí©ý1ð¤Ä@ŒS2=Ú™dAémÔ¨žô\ú%9 endstream endobj 15 0 obj 151 endobj 12 0 obj << /Type /XObject /Subtype /Image /Name /im2 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 13 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 13 0 obj 456 endobj 18 0 obj << /Length 19 0 R /Filter /FlateDecode >> stream H‰5Ž1‚@DOðï0%,þ.±[£…&U ¢Q4Úx}3Í›Lñ¦½@â,Œè ¢Œà}ÆG<@uøÊ ÊWŒR9's½PÆÊì"`Ur¡#~øúM½íiç·íß/×¾7C¢™‡4E¸S¨ûù-8&³[)‰6=¿'P~› 4Oú¿@$> endstream endobj 19 0 obj 149 endobj 16 0 obj << /Type /XObject /Subtype /Image /Name /im3 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 17 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 17 0 obj 456 endobj 22 0 obj << /Length 23 0 R /Filter /FlateDecode >> stream H‰}QaOÂ0ýý÷LÝÚÞm|ÛŒ¨abB²D¢¢|ñïÛ[·AÉÒõÞõúÞëÝ ÄC‘Fc0Ad`ÿ x€cÛdl.†—t@d¾ˆ "e”‹× -‰\ø ½¼XdóÉ”Óê¦xÁ}:Ï®Òy´ê…R®ú}°ï¢°bv0 èŒEg H£Š(þc`Ùm9^õ´<¡Œš‰Qˆ–ŽLp¬ûW¨@$wºk[ŠH’ÿ ›ÖL\;ö‰-cdz[UÇÐ…Ô]lżmÄ-6œlU<âëµ ·Œjצ=‹ãöÒÄÓůŽ`›oʉ¡4Uþ½ÿŒ%‰ýXüDÒlQ•ãë"³UVNm±´ÕdšËÓ1ú /9<Èw%æh5p/^@C„NWÂ»Ž¹f¯]õðm§!ÿ?ãñžJ endstream endobj 23 0 obj 340 endobj 20 0 obj << /Type /XObject /Subtype /Image /Name /im4 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 21 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 21 0 obj 456 endobj 26 0 obj << /Length 27 0 R /Filter /FlateDecode >> stream H‰EN½ Â0|‚ïnl‡¦IÛ/ǘTT*).‡¢¨PE_ߤ‹ÜÜu 7ˆM- CëY*)*'ú\pà O ÿV#ŽÊV¢ÆpŠW*¤Pfa¢!EÍJEûEv°¿ çµ[bßï¬?bÈÚíçòºùƒ†Œ(4Xë4Ï`œ@å}b¸ýÔf$: endstream endobj 27 0 obj 145 endobj 24 0 obj << /Type /XObject /Subtype /Image /Name /im5 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 25 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 25 0 obj 456 endobj 30 0 obj << /Length 31 0 R /Filter /FlateDecode >> stream H‰‘mKÃ0Ç?A¾Ã½Ü„uéÚ˃ïÖ-“ùÐ=4" `Q§lŠ{ã×7—4Ý èÝÿz¹üòÏ Ø0”Y"J #žŒ>‡gØÂ|+ì±K%`§l8ã'R"É6pû8f.o€'™”Ò¥ßЗSÙźžO/¡¼¿+Ì6½ÙͦßûÎŒe«3Š\ý‡"×S¤z)t*EY_™Ò¬Çv¾(«Èq­Ã«ãPÂN%]sßIÅÅÔ)TYsh\÷´¡°–k‡ s-ÃOÞ¥~6mŒÔÔ¿;)( q ñ” ü¹#v¤Í;̉BÇ[`Odg—¶vr E>üö¼ƒ±íËNªzQ\›‰­íãÒÔv\Üš*šG qf¤—޵ò.üq᮪[›×;|Û ˜~²hlŠž endstream endobj 31 0 obj 323 endobj 28 0 obj << /Type /XObject /Subtype /Image /Name /im6 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 29 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 29 0 obj 456 endobj 34 0 obj << /Length 35 0 R /Filter /FlateDecode >> stream H‰Œ½ Â0FŸà¾Ã7&C¯7±I¬["¢ƒZ.‚pè¤PÄÉ×·å,‡3œ¨S Ù¸8:P%ì%ºÅ'oÓnÍ?˜Kwʽ>õqÍ{ÜÛ±?¶£/Ɖ‹bçb-ôMYé Š…*¢n^÷5¦´yÍ Ã‡þŒãX endstream endobj 35 0 obj 123 endobj 32 0 obj << /Type /XObject /Subtype /Image /Name /im7 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 33 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 33 0 obj 456 endobj 38 0 obj << /Length 39 0 R /Filter /FlateDecode >> stream H‰mPÍj„0|‚¼ÃwÜ-hóí-«BuínÚÓ‚PýÁ¥´—¾~ó%©R(¹ÌL2Ãd€QTç\Óe®\M2ê¹ÖÏ@sÉK¾açì¡k¦ÁöÍ<ÙSuoOü²ô²ßƒ{'2|XÚ ¦~íJF{[OÕ±{ì‡Ý ð|½i‘Tø*вÜ(¸ÂÊö””{(ñJRô@`"¸A˜”…ð·$.ãuZÛì1¶ÄØeãE )H&G§‰:4Æ"‘/Hy"±9$¢Ñò äùç_k¨4?<8…_’Áâ’qE;ö“Ç®­¬kÃ9Œ×¸­ºú³Yâ¾ÓÈ'²3 ë0aŠÙnß®Ôä¶l¬ endstream endobj 39 0 obj 279 endobj 36 0 obj << /Type /XObject /Subtype /Image /Name /im8 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 37 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 37 0 obj 456 endobj 42 0 obj << /Length 43 0 R /Filter /FlateDecode >> stream H‰U‘MnÂ0…O0wxK¨„kÇvBØ’V¸;$$²hAEU»éõëqìT•%{>Ëo~ž÷ ¥#­µ(,L9箦™ªÈr÷B¾ýÁ¤êº—vU¹v·=·õÛ×Ͳ9à4yZŸ¦S¸)ðú~5ެQÂÂjë÷;F,`ôç<Ðߎd¬ùƒQG06‰SdGI`¥’d@‰ –ƒ8d•©J¬*c•ÐN€Ø¢§HEÉ;èòÀf¥ò¥È¯$xñÈÞµLÉbp-9¶9wÕj]=7Ç`P3fÈʶôÍA_ <$å< ÞûÇ×{‰ú“~hX endstream endobj 43 0 obj 245 endobj 40 0 obj << /Type /XObject /Subtype /Image /Name /im9 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 41 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 41 0 obj 456 endobj 46 0 obj << /Length 47 0 R /Filter /FlateDecode >> stream H‰]‘ÍJÄ0…Ÿ ïp—ajþÛÎ.ÓF-µ¡v¢ ºTq6¾¾¹éŽÒ4§ç»‡Ó {O¤f)W O€¯È–¦¬áxš ­ñøIgÊÆÜÚ±®vàÛ½íaHnša³ÿA(l tCps®ùb/r}ioìóžL_Þ™ž £tØüé´r¤sŒÚ¼q¥ií_’@RDø«É\°Å-™šÜÖ™ý½­Ænh ógõ„®ó‘åi¦ ãy†»PØÒù^Q^µ<”&4Þb›QS5ì’.db"™M¦,¦kÇ¥•ÊvÖUÖ•µ=,y"JÆá'¿I‡Qóû'0üÐ˜È ”ULy ß_¿Ÿ…ê‹üjk: endstream endobj 47 0 obj 288 endobj 44 0 obj << /Type /XObject /Subtype /Image /Name /im10 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 45 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 45 0 obj 456 endobj 50 0 obj << /Length 51 0 R /Filter /FlateDecode >> stream H‰e‘]kƒ0†Aþù´³|š¤wVÓMº:§V(^”ml¬Œõf‰šÒ®9¯Ãóž÷$/€V-âZ’+ Ðæ(&˜i¢Ýþ É™ÛþB”ÛÊ–¹-³ýPäK(wÛ•­Ð~"±ñ(8”j#g”'ÔLhgë¦x./8è£õ¦_< 8S,vã¦p»¯ìº´ÎÓšõ#³F{7Ò‰ægœ¨ olÝ™vuq‰RIþÁBç‚&æž;¸8ó¶E|œÞ “` Š ÿžJ3˜I8½Â›KÉñ2äü̉Ï5ãG„¼xú >¼ªYÃææ&kiµª4Û¤vXO¶ ^‚ ÷FŽ€¤8¿¹Z?€’Q:–Þœ0Ê/Jp¿rÿq¤òoô½ƒz endstream endobj 51 0 obj 300 endobj 48 0 obj << /Type /XObject /Subtype /Image /Name /im11 /Filter /DCTDecode /Width 8 /Height 7 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 49 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?ôWÖ£ÔhwR»>ƒï¹„ êÞ×k6½Ž’=ÅÚ7øAÇÐ:5_XzQ¡ÝJìú?¾æ+«{\=¬Øö:H÷hßá©ìþÚ½k냛õ–üÜ:ÿÑ0UU®†Ô ~›N¤™´#tŸÿÙ endstream endobj 49 0 obj 452 endobj 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream H‰¥RMOÂ@ýûæ&ÔýþàV A –‚!!é¨ÑHŒ\üûîl·Mk¢³‡ÝÉì{3óÞ<™”DQ™FX¼ œ‘M˜sþyšä~Á`¾¼Ïªål ù~=ÉŠ!”o„ÂÈ&<ÀaÖ©§™«q‡¬Ø-7y §Á|u6 ºsíd„KÉl ߦåb ‡´˜.Ò‚ŸLQ±åM(Ú©iº½–ÇmÖE*ë–ÎJÂÏõw1Ô„Ë‚‰‚ë<n]ÒÉ LBáÛgwAÃøCЍ…Ÿ òâXœéºÃº¹t»®¶ét•ÞeÕæ1÷ò4íD¡àDè -Fï@b!gñw­QÿTÙÅU„‡žª}±üSvn(k¡aìš§ëžðü'”é¶ikcÕݦ(«UvìíWÏ")ƒEÂp´Àj o\’µk’”èYT§%×Í–÷-¢Tþf®QëP¤ai¼IʶqmÓ'¸½Ì~1!9.ÓÙÿ¿}½0³ò ÒñÄä endstream endobj 55 0 obj 388 endobj 52 0 obj << /Type /XObject /Subtype /Image /Name /im12 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 53 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 53 0 obj 456 endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream H‰}’]o‚0†Aÿùœ&²~¼C픈Ƞš˜˜Ì‹}D³l7ûûkKÁa¶… úú>çô¥€fqžDT§À,Ð[Eˆ]ŸGœ2a—_pW¦óuºÔÍZ¦°O«ù*­èñŽ`|À¼! “Ø,<«+„H¥94EºÑBdOP˜uNÕ€Pæ»*Íg˜±wKÆ;7Éð»*xÅ­™Å}k‚ÕÐlå`zvkX^OÞzëRÏ›‡,×M™šÕ¿½I"â`g2¦·þÉ\xÅn3ÓU—™ø<æ´ó+)ƒ?+–¹6Û¢)§à:ÛÆ¡+÷|>Òö2(éPR%‘€ ô:&À”[Rû‰+ÖÖ€ fw´êl…··’©ØÛýÛ×ýv«„xîwÄÖ*uŸ4,)4 •³+ø‘B!Ì@½ýÐÓØÝøv$2³ù¹ÇàÓ‹“6½6¸´Ü4ÝßëªÎ¶EícÓcg$åµ­ôHz¶½Ó]$Nvóýë…0X¼£oÆ/Äf endstream endobj 59 0 obj 398 endobj 56 0 obj << /Type /XObject /Subtype /Image /Name /im13 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 57 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 57 0 obj 456 endobj 60 0 obj << /Length 61 0 R /Filter /FlateDecode >> stream H‰…•ÛŽ›0†Ÿ€wðåf¥M}À6ä΀7EáµH•"!5=¨«ª½éëׯÆI»+$Ä€¿f~Oœ&!Œ³5ÀTÉ\£,wÏgׄ¡Ü>þG©tÝwC]m@wh ©ÀéáywZ­€ù™@ðäÖUÀâ3<áyÆ<¾åNlå°“_6à(TùY(|z@žV3!ºÆ4jQÆ‚VŠg•t¢•wZ“»(äÙ¤@0¾•8¨úFF ó8ÂÍ'˜fÄÃúжBÝ´AàD,Z˜…º+©KUïKüÜ«V˜åêƒBŠÐ”z'qͦwéaÌÎyêY%)´*a¬mî¾hx†£]”F»ºªW×é²×»Å®Ñfyì6E¡[Ù‰¢‘Õ°ßÇYì–!qo MÖ6¢yоà€±Ý¾³r7¢¥Ý÷Ê,AwãËÉe|yØDaÄÐö•l†¦Õ2S1}Bf°<êÁW1(©ÑV¢é‹…Y@Æ ˆÒÔG1Žâl”Æ$xš½¡<ºËÒànUk£êâ0RF¨ÂîÎË¥b> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 63 0 obj 456 endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream H‰­—ëjÝ8ǟ༃>¦…Ým•eÁÉq²&ç’ú8ÒCš’²œîÂnð¾þê6²|χ6hìÑߣ™‘ôë'´¹¬7Œ‰„ $ORP½Ý|À QJéñ7„–R¦‡ÿ¡‹SQ=”WESn?¢Ãýþ²¨ÐãÅõíã»w¨þsCùùçmÐl¤Þðë+¡çMQo¨‰@’ýû' &CT˜¿\[T°ÆèÚHf4œ}Ö&5ëp¦Äî #“¬-°]í¹³™l%&nŽ{c 3Õ}ß?8;X.\¯‡‰?Ðæé½É5c3nR‘ù1IÓI§LJ—t—ïün߇ürWl›»üê6¿)š‡¢:•ÇÃɦ\µÒ× ™ºeLBÝ„t20õ¶øüÍVS®Iäeµ±UŠ% Ý dï«ò ²ÚËÊÖï}˜AP„8«¢®?7‡|_, v^'dÓ*‹Ð·Œp'æot;§Ñò‰¢D%}Ñ•pc·(ÛMå2ÊÓ¾ärF#¯ž Nƒ #~ÃÞï÷yµTuï—Fv¥ -´-NWUyW›y×ÇjŸ× šcçX^tqRˆ3šñ6Ý©ÊSLH—_¥ªØù©h¶y½T¥Øm\þT‰Ð¬DA­ÛcµX&ãW Î1å±Èj½Á)#‚CLYš9¹pV,¨Ÿ¸&*œ2󡕇SïÖÔ"¯^ á®…¨o¡:¿¹YQ—žT§>´ýݱª×" N“½¢ÿ¬‚í§‹Ÿ7ûã¶Ø5»c¾]ùÀ„÷¸sxªD±¯R~U—¹Ý+]9ðìí¢.-ŒÂ&z»òÈ·× !f)9¯ºÔunvÅá¦þc±„±c¬šòpàq /OuU^Þ×ë§Þе— ö'ÍÔ„ôZ6†¾¿‚gDjïeΕé;M4ð@`¤‡æ¯Å‹Ôö¥· ,ŽÁÔŒ!˜ŠÞ –%^œºæX9w65(âE¸eû¨"à€56:ï ‹°*`0øfàˆËBÖk—|ˆ5×å®°Éÿ©&™ L*ÇŽ`§Z5s‹KÍ4u¸çXÐÄëLK‚~,ìbôl7°²6SÆ4ÇÐ9Œ±eMĘBVÌ Œ«ÿ”1ÏÆ²QËÇæfƒÒ™…¸ÆÙÌ<™_Ìõ³CÃÞ&²°÷2:A…íþ…ù©Ì·ÛöuŽó$íÎ)1y¯#žói™*9æ¸vlpx…s}†ÔÚY$#$Äš ÈÑ.²¡×ðV!Ý­’Á­¬íÁVÿš\t«Ì#W»ÂV$d›NÈ æ÷à1 P–2…N협Âe‚—=ÐQ;A2…ÊrŽ)P;$ža–9Ä焱ú´Æé“|‡r)àDL:íÒhà ýÈÔiÚIv1G”U‰1¼´CJPT$,@§à¤¥hˆT…¨1›áv 4XG„d³¤ÑÎ ÅðgªÃV Ø:„‹ßžŸ~þÛœÿ~J^¾¿ž¿ÿõòúãñâ9I’ßÇõœ8_ÆPÑ.ÒëÀO‚IXá$&Øû¥’º›é«Ò]£§È4׿²×füº÷¨s1Z=‡N¼{õ?P5ü endstream endobj 65 0 obj 1178 endobj 4 0 obj << /Type /Page /Parent 5 0 R /Resources << /Font << /F0 6 0 R >> /XObject 66 0 R /ProcSet 2 0 R >> /Contents 67 0 R >> endobj 66 0 obj << /im1 10 0 R /im2 12 0 R /im3 16 0 R /im4 20 0 R /im5 24 0 R /im6 28 0 R /im7 32 0 R /im8 36 0 R /im9 40 0 R /im10 44 0 R /im11 48 0 R /im12 52 0 R /im13 56 0 R /im14 62 0 R >> endobj 67 0 obj [ 8 0 R 14 0 R 18 0 R 22 0 R 26 0 R 30 0 R 34 0 R 38 0 R 42 0 R 46 0 R 50 0 R 54 0 R 58 0 R 60 0 R 64 0 R ] endobj 69 0 obj << /Length 70 0 R /Filter /FlateDecode >> stream H‰­WëŽ\9~‚~ÿÜEÛg|¿¬Ò„Ì"‚HÒ(?вCBÍvE¼=v]ì²Ow(»=.×WŸËUv¹Î³ÓÁš¼Ù R [ Jž´jÿ~þ«:Üü hÕéÃá¨7«uªã{¥7’­Ã¯ê›»WooÿðâíïïÞ¨ãQ=ÿô¿?¼û·Q7ê—/Þ}ú¢^ÿëÇÏïïÿ©n~ÿîWߪÓçC]°®tLÞ·åTåÕ!âÕ& ­ùNÕnþ­ÌÆ~¯õ÷:«Ûê;UnlýOk ”w§ƒQí_óÚdå­ )ªdë>Þ«ÝVüZUêwíç³¢M¾ú:ødTȾmó±I¾aiâA^3"nh‚Zg…ECØR%çU„½®ög–`XžÜ OU‡ì‘w 'IÝ7œÛ„Ú#é"i¦°™Xí`Ê ÍÂÂúQ~üÅAýÉW­©ÿÿ¹æE©¿¬y f“i™½ÃŒƒ;y ɇ8 &8e’o¤Æ—fÝ$d@]¤5Q2¤sE«àXçrnþx}^[,Äã¢ZK]Nà¬P;–È­~¶]088¤Cõ·² ±b‹²Ë°UV¢÷hFcϩ몹Áè:#/GJÃFÒÅk ‰hÔ”á÷šUT…}J]ÊKSœ³³d½$hOVs1M©Ìi"â=­T¥)M)É4á6È,.iâ ÕÜ`iâåHYºQ9—¦Ÿ ~š\”‹-YÎw óGõF}Qgòx¬Ô•£ÚÐniÂE EfiŠÛË)É 8“ç·ÊÝV!A ¢¨»20’4všrÔ:Iß6yEM² eàõdDµ™bÅrKFYMëµä@.X©…‰tä …&6 >æºÊu·pá‰8t«7ØÚäçz][Î\XkqN|‘\Áj "ÊF€8WzZaï— ¶Jy»¬OèQ–x['Š6¢‰5­6x„;ÚSŸðjZlZ«ë‚7âéo¿Ä(Ú 7’Í 61Ñ}@CéáH¯sŸîÔ=·s6f×,÷ íÞÙÜîP4†_Ól†Lñ#ˆÛ¢Î"ÑtäGðxN©Úaœ]³¹‡Ð„À´+ NXìÒí zÑÓÍ5uÎôlNËB~ðÖ’š÷âÇp¤œg ydf&Ö‘uX’”F˜MnŽœ¯©aÆž›Ùñ]Ê»vw¯=2—ùjó„ïqvµ9—€$,FE#_q×Ñ^«’&„êÄàÝCîñÖCKô(dhŒªVb5xr=\ PØ ni@2Ë©óÕ!Âx:Lð0³Ñ}¾”‚H)Îî,^Ü]ï³Ç65R(XNV\hß^í z˜¬¡¥æ;Ä$Zñ*A/ásç™Ömû¬]'#–F"üA£ ùBçÃÅPY&£"åå ¥ÌuMkQ(ÎBBIOCÊ®:j#«c%éê´0$ô£vbNºT%ÂnsÀ&‚”¾ ‡(&È*{eÄâ`5V%i”fÊ‹_Ž–ãh˜’W©GêL䯉feÞ÷ %‹¾†ÙL–ÈJ£ÍÜM§cîàÚÌ7a…ä'ô η0\¹K.É»Ô%H±Xɸ°Ü%7T~2òÓ]b¯…ë×…ùú]¢ÅP™&£´¿Kû£p&+ôúÀì«,C"2OºÔ³>R4ZîØá‹•Däa¿ï$×O#Ô”=¿ ¡m8úpI _Ñ“ÜõHÇêúyAšxè_¢ã//½†³$–‰G-ö!¢7¨ Ã$ 2À‘¬ÈŸ”Æ…#Àà2¤Êlg&ÌööÆÔƒ>\\3É;Ñû;LŒ:Òþ1‘(N‰Ô!–G?‚¯n5F*Võ5›8,-EBÖ<ò£Ín’ rjF.[C*#LŒ O¨Ñ}×È%.DJß üÂ5%³‡žØzì'O×”Ò–ÎdÔÕ¢6ðDšÎ“Ún¾+‹¦Ž,Ç$×Öœ™%¨bº ÒºVD°$ÁöhŒEf6KVÛÃ;ÏoJø(zŒà”‰V4F&z±Ã3j½]ÓÚIGÍY†"Z’’£RË“ Ax`”l`[ºê®vÝÌ1ÁÀ7’m„ž#u$£(¹.öO ü`DHÖ*S|vѯ «Ì™Îoˆ‰‰ozf ê×=Ƴþ§Ö§4¹Ó:âþ¨Þ¨/Ó‰n¸ŒížbïÒÁá‹1š¸=P…n#°« ƒ%2 -³}oäÊÈÇ˱“†´©‡ˆ¶±ÆÉi§á ¥²¹ìk×Ý$Ï-˜Ë[Ä¡N,Ñq.°Yë<ŸèÒ¤§v{àÅa6^,è¹³ÚÌl}¢½³U`st“Bd ´ ÒD_š¬ÉEÄòŒb37±:fÅ%Iɾ©ÙMña¹ËƈDëȧ¸ˆ›3ÜYK=TTî±Q ¸±IêáöË ¬¦ö«ªµndoA8{]¢àúÂ<°¢ÒŠœ> BY/ÚQ¥G²UŸVeiÔ%‚‘ˆoG32Ið€ 85Œ†‹â¡9“Ó«£p|ß^#¶œi¯õÓ— ŠÓ·µø1Ð!iiä±’[k¿†ªà[M%ñìÖÒ<ÖÚ2$,'HéŠÅb”ã\¢öoʱös®8ªWmô£PãÈ áŠD/Ù‚·„ªZ¨tð832ž+®ù‘zï‚"ÄÜÁã0›Îñ¨åÔY¤G•&fŽdEx¸×èVhRy6ð3ž"Œ,aëH?Ô)H¦l=FNëåèÖUêïÃ8IŒHÛÔÞ‹³†ÎaÇŸð¢Íî­‹ºløq:bû0&Ð×Ö¡FÏoJ²ÚP?<™%FTuÔüÒ8h‘£ß.éÁô`Õ¢YbD»b¿U»\?>+—°ë`ÅÁVºnäq"CiB#ü¶F"—cefqæä*¶ }p½ˆ…y›²†¡§kù/¶mGÓCú8Ä€/ ¼k¾v¦uáMµX­`:JxìTˆCÙás@Fޏah‰6]$¼L\Ü}\ÿé·Ðâ#V¬Èn_óB ÛnÖàá|8Ó‹W1A+á3$ö xž’©£,zc’à @ÏÊjì[ÉŒ…ØÏKŸQl&ÖÐYaIRšn4¹ù¿DÔjQK«Gñ¥AÒ| Yu=˜X¦Še®¬ö½P3´N0l[È­;D…`#„ — à9w(Ñtà$XþÛXUâva7Ên™y;k”Úü´¨” ÃoAÆ’§•Ä*Q€£Ø ¸g€C$§¨ÒãtàòP¡¶ _>z˜ÄfÖH‘êz°œoOaýžÂ#4~çl€Õ™·^•u©g'ÄÚý¨Ós±øÍZÕc•B ÎéÃá¨7“¼¯ãû¶«ÓWõÍí¯_¿½=^ýöÙOw¯¿U§Ï‡»Aˆ—¦nØc7Aý)°Ò1ÖNÄ ¼¾¯7ŸëGäó¿þ$…ÄÙ endstream endobj 70 0 obj 2619 endobj 71 0 obj << /Type /XObject /Subtype /Image /Name /im15 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 72 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 72 0 obj 456 endobj 73 0 obj << /Length 74 0 R /Filter /FlateDecode >> stream H‰¥U]oÓ0ýù÷q›´âo'{KÓ mÓ¥î`R¥HLˆ6{áïcûÚNÝuUj}œœs¯Ïõ½½‚bj .ʉ– Ÿ0 `fÅ9™Ð’s»¾2áRj»ü 'µ1ý|º5í0Ÿ]Àj»œ¶ý)˜ïóÊ1Á2Q42u)‘ÙMß·Ìͺ½€ëºoÞÕ=ÛPBv§°;¹ü°;B2dáµXµ¡AËÔÓE;¬êe&ÅŸ*©$ÉN2œæPÊgåEÌ™§Ë‘Î"}Ý·ÆÜ¼ÎÕ$ú(Ów½ØöõâE¶P,²i©½éz3tý¬í³a*¹ ›Õ¦>t^¾b¼–Éx‘tÚËz»0Ãu½Øfb‚¤¼3ÛUUŽgg(²œ¯†JlŽå¯ÅÈÑ‘Sz‘Ãht‰W<ºdº¾~›×†çæRZEZ)x¤ÕfÞ ëŒ—Ó*’j¢XˆÖt‹íruôRzjkŠ_PР8pâZîñ ÜÁGøaŸ€û<~…¢t÷ ˜¢î…‡ûæÔ¾S™îGk|âÜBaèÞ=Ims¿¢‰`בà€ò/y*GªŠ+G!y òA2Et¤ÞAñù¬¸‚èf&¤ûö7o4ÃÎ$Ÿ§œì£àyèÝf3Œý;k7M?_›y·ÚD·Ç@¶²Öð¿¾à¹Åˆí©6°G—%XÃŽåè%ísBLó¿f_–µd +òÙ¸l?Ü)НÆ*‹)Ód#ZÇ‘J1|hoþ"(× È þ†ý•"ù«Ë'1/ YtÓl a°±¿˜*m4…51ÅÎÒvɱ¯¤ßÇ?E{i%Ü2ìÜ» _‚°A+нPBd¤ãŽb‰6P ‹c!rônÜ;¬# '@X$bßY;SJ»IÀ}œ#~²òùþÂÁÝLyW{öY€c«ª¼²´â£µ·öå7ߨ‚ÙÏâÎ6Ø% endstream endobj 74 0 obj 725 endobj 75 0 obj << /Type /XObject /Subtype /Image /Name /im16 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 76 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 76 0 obj 456 endobj 79 0 obj << /Length 80 0 R /Filter /FlateDecode >> stream H‰Œ± Â@¿`ÿá•I‘õ6a³jyÞ **ÊÚ,R)±ò÷½cŠ™jn èÔ‡À½b4«‚'ê‹­­ôŒÀƒŠ”ü¡¹ÆcÞùó¶¸<Î1ß15ûÓÔ¶ð7e§/hD(tZW²¸~•M1/ ÕkCúÐô& endstream endobj 80 0 obj 117 endobj 77 0 obj << /Type /XObject /Subtype /Image /Name /im17 /Filter /DCTDecode /Width 8 /Height 7 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 78 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?ôWÖ£ÔhwR»>ƒï¹„ êÞ×k6½Ž’=ÅÚ7øAÇÐ:5_XzQ¡ÝJìú?¾æ+«{\=¬Øö:H÷hßá©ìþÚ½k냛õ–üÜ:ÿÑ0UU®†Ô ~›N¤™´#tŸÿÙ endstream endobj 78 0 obj 452 endobj 83 0 obj << /Length 84 0 R /Filter /FlateDecode >> stream H‰EÍjÃ0„Ÿ@ï0Gç`UÖÏÊÎMŽ]úCkË‚Á‡”–†Ò\úúÕº6e³»ƒ>;@ÔQh¥¤v _° 6"W² S¦þ%!Úd!Æn_±öÍOÃcÝv³Ûûq³Aü y¹0šˆ†5Õ?b:„‡¡ÝâºÝ]èô˜Y¥ÔÂh£(Àu}ƒ°ÞIç DÒ;%®'œÓÞò8^òžÇdõóE«]ÍÂ)p1’s©ÂþåZ2íú© 1Ä×ç¶_C¬ŒÒ±\ œÕ|Û²ø„H}CÐLÎ ÖÓìW†å˜^ܼ_RàæKüwoM› endstream endobj 84 0 obj 238 endobj 81 0 obj << /Type /XObject /Subtype /Image /Name /im18 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 82 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 82 0 obj 456 endobj 87 0 obj << /Length 88 0 R /Filter /FlateDecode >> stream H‰MPÉjÃ0üýÓ‚]-¶Ÿ”› zhB+¡…€¡>t¡¡´—þ~µÙÞŒôæ-ó¶õ¬Ñª¦­Ö1À÷¬âµ”DOàuùð«ÞzëŸÜg{ÜÝÙ£¼¬Z~Y¯á?Ge¢QMžÕ ɬÞÛ§ñ0žíýÉ Nû­;&¥@#å…H£Ó‡Z(’Ì;CY2ÓQÜ™Ô#UÍ8u¡™Åi˜’LÒ©¤¿½ÜDkçÖm-³³ñÄUƒKŠK‘]ÊÙÝ0ºàKñ(yã–"Üüó$‘0Ëö Ö¥ªUÞ ®<…¼Û÷«0è¿Ø$¥có endstream endobj 88 0 obj 272 endobj 85 0 obj << /Type /XObject /Subtype /Image /Name /im19 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 86 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 86 0 obj 456 endobj 91 0 obj << /Length 92 0 R /Filter /FlateDecode >> stream H‰ Œ± ƒ@¿`ÿá•ZxY]r'vw‚H‘µRX)ˆXå÷³ SÍ•„ƒ{"Ô­š¨bW{i­7°ñåE¯:qÑüS‡÷òŠyÆZ ÓZ–Ѓ²Ò ò`£òf›l'豟 #]ôˆ endstream endobj 92 0 obj 113 endobj 89 0 obj << /Type /XObject /Subtype /Image /Name /im20 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 90 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 90 0 obj 456 endobj 95 0 obj << /Length 96 0 R /Filter /FlateDecode >> stream H‰]ËjÃ0E¿`þa–ÉÂîH²%+;?¥4q++@À‹Ð–†„Òlúûɉ E0 ó8÷Ž^šŠL^¢’#†2Ê‘äüˆ”FjNpá6Ûõ¸«Ÿ·n…»Ú·µ—‡… ¢Ãr‰á„™d‚,ÉÜ R‰‰ðâ]ûqS¯ÿ#þ%¯ÎBÏ6Du³1ô>Œ½ïœ_!;jœO«.€Àø®VFJiV_¥ ×7|+ò[ÝÆ Ô¸3¤ŸH]­Òì%¾H‹N¨(&'“‰ºƾyrmîêÓ²LÜ ‚¨(7sáŒÀß:Q3V±’Ž#Gž~ø¼HÝü†Wd endstream endobj 96 0 obj 255 endobj 93 0 obj << /Type /XObject /Subtype /Image /Name /im21 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 94 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 94 0 obj 456 endobj 97 0 obj << /Length 98 0 R /Filter /FlateDecode >> stream H‰TÛnÛ0 ýÿ›I%Y’­¼9±Úz[ÖV¶``Ŷnh7¬/ûý‘ºÄNÛ C‡²|xŽIÝ@¶rgl¡@çb!€«³9[¦4Æ÷ÀyQbôN6«wv톦^B»½ZÙnîGÆ`n¥ùˆR0wwm—ð±êÖ—U'v'Ⱥ›Áîäüýn–锈—û<*—!ÏzÓ:{;åVQ¿WÂË"e0œ‡ ½]o»ÆÝ M{i1®—@jPÌ„Ìó˜BrUD­\³i‡mo»Ü©^ä&ñJ¿Õ•Cè91Zmʈæzê™bQg$ËLHÎM€~¨z7\mêæ¼±õk2&ƺÆùïšöâ行ؗCËW¨#­Ë~CÆK ˆT ¤ íù <À'ø‰{@¿ço¡SZ¸ùcšSS¾5Y à²yIeëG\J–sÎý¢÷a‘`ñ…,éûÇÉ‹‚þbš 3R„I@X!0 KÒø¨L€È>Ÿf7Ð>}MGp“”pÆ4€¾Ðó`wµî‡8IûAhk{›¬¹”$– ÑcäJDJVûÕÃToîõ’yoÉ%´Åòbœ6•¦íÕu1×CÅ…W,‰é*§Þ¨|ßÄEœÌª]ÛÞmºÿ! …’ìÇ“f‡0^&:ðµÃ…mmçÇ´?š@56w`㹯ˆ‰á+n¦x 'A½ƒÛ‚qßV¨…ý(§ŸJ%tݵ}ÒB ¨ËÍ%™H‹PotCûŒxéùórCÏ{üôìû“PÿÊþC¦VÒ endstream endobj 98 0 obj 616 endobj 99 0 obj << /Type /XObject /Subtype /Image /Name /im22 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 100 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 100 0 obj 456 endobj 101 0 obj << /Length 102 0 R /Filter /FlateDecode >> stream H‰…“ÏNã0ÆŸÀï0Ç‚DÖvì8ææ¦Þ¥¶!qH•,ÑÃ.´Z.¼>þ›¶€r°Çö÷›ÏÏ5 ¹A\‘À,Ð.(µ›ï cꦯ0ÛÌ/uc¬¹ëô9ܨ¾¹P=ÝÍÆ»“0ÙôIFá‘0l;ÝÕÃnöójÂT†ò„)%“£æƒé•³Òƒ‡8Æ$åEPD5Ç"› %‰ê®×ÆÜÙµZ}~)¿Àe&0*ÞºvÛ«ö8ÜÆüU5æOæš·ú¿ìåaMòµgQ¸\ØfÓnWë¯tœ:Z¥Œj®Ô¯ïsr™¥%I9½Ä®´¹Ø,Ž*?Ö›°|ß²NÅò¿Ûê[£×Ãr³¶áúGYü÷ò6ˆHæ¹ÔñžaŠDÁÝ3¥…ðtS×ó½;†ë¼óä#‘7 æq#èsP%Q i8ýt°†L¡ÁAΣ O⊗'{Iœ'XŽD–ÿtêûot%ýàÛƒÿ|=|eqÚ)µ@3ØÁ(³l¬2¦·7ªÝê!ÔQO°’VÏEÎßè *ÀÝ;«äK³w§<<ÓÑmŠæ endstream endobj 102 0 obj 436 endobj 103 0 obj << /Type /XObject /Subtype /Image /Name /im23 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 104 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 104 0 obj 456 endobj 107 0 obj << /Length 108 0 R /Filter /FlateDecode >> stream H‰Ì» 1Fá'˜wøË¤Ø8“ÍEìö&¢…º ‚°ØJa+_ßÈi¾ê\A½’Hp9‡Бvž“T/`׿m¬üœûã4èCï—i‡[7‡nöÅs±(f*ÖB_4)}@ \k„³óÿ»¸ˆemž«ßôÅ8¢ endstream endobj 108 0 obj 124 endobj 105 0 obj << /Type /XObject /Subtype /Image /Name /im24 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 106 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 106 0 obj 456 endobj 111 0 obj << /Length 112 0 R /Filter /FlateDecode >> stream H‰EÁjÃ0 †ŸÀïðÛC<ÇNm§7§q·Ðv¤©Sr(ÛØXëe¯?)¤ ‘,ÿŸ~ùQ%‘ç…t+hã€T‹LÉÜOùJc5¥¿X„”º¦êS›zçþPÅÃb»–K¤O¡• ´µv¦ü×ç°ïãçÐmžB§‡E¡”𑬀ãöA*§œgk¹“z…Û+Þ„ñœN­RRÇóõiÚcn™I›(p0wò~¶4Ûic6»ðÇm³cziãénä>¦ÄôAŽ‘\}Aа;±3‹BIjé¼ÐÛ‡+ ëoñV!L endstream endobj 112 0 obj 241 endobj 109 0 obj << /Type /XObject /Subtype /Image /Name /im25 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 110 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 110 0 obj 456 endobj 115 0 obj << /Length 116 0 R /Filter /FlateDecode >> stream H‰UËjÃ0D¿@ÿ0ˤ`W’m=ºsõ™¦©# †€¡^ôABi7ýýêJrhÐfFÒœ{™g°…gµ®$àW¬à¥”"ȼ¬lUù‹ÙõÝÚ ¾ßºáÁõWxi»åmÛÉý¬áûùþ“q– BÃuFÔ² ±íœ÷ý°iÝ€äA€ÎϘóLh eT@áˆìt©Ý”M0–ž„®'‰Ì6¤òÅ!øŠÙ[™#e2êMÊLÑìUü8*âód(—Hö@.î—|Ü;1’4Sèìõ‚ºÏƒ,õsС¨F¡Lª15xã6®k×ÃÓâÞ-ý.–æNÃÏÊâyŸØ7˜ŠÜBÁÖå©„1|¾ü8J…Õû;9ká endstream endobj 116 0 obj 281 endobj 113 0 obj << /Type /XObject /Subtype /Image /Name /im26 /Filter /DCTDecode /Width 8 /Height 8 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 114 0 R >> stream ÿØÿîAdobed€ÿÛC    !"(($#$% '+++,.3332-3333333333ÿÀÿÄÒ  a!1AQa"q2‘¡±B#$Rb34Ár‚C%’SÑðcs5á¢ñ²ƒ&D“TdE£t6ÒUâeò³„ÃÓuãóF'”¤…´•ÄÔäô¥µÅÕåõVfv†–¦¶ÆÖæö7GWgw‡—§·Ç×ç÷(8HXhxˆ˜¨¸ÈØèø )9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêúÿÝÿÚ ?î:.oSëýS×ÎÈ¥ØÄÛ‘XôÚËæËKNèÒNÓ0Cš»Ž‹›Õ:ÿTÅõó²)v16äcÖ=6²Æ9²ÃKNèÒNÓ0Cš­ýLúÇõûë‡×±õ<«:n?Ks²®«Žc]¶À/u2w!¦²?ÿÙ endstream endobj 114 0 obj 456 endobj 117 0 obj << /Length 118 0 R /Filter /FlateDecode >> stream H‰ÕUMoÔ0ýùsÜVjäÏØî-› ìÍ.‰ E,ŠD‘@h¹páïãÛÉnW­8ôP)žÏ{žÌ<%ï¡Xú‚3••¥Ð~U\±’kB|¬”šóþÅvù¦mü¸Y]Cw{³l{Ø/^½Ý_\€ÿY0¸rȆÀZÚÄV¢‰Ý×›f=úzù®½†u߬ë^ì’ÍÕ¤!´È8SiÔÇ%^¿¿CŸYi4üÃí 0øV´¾Ì””Rð & Ã]²*D&¬Šž…–ÜCÁ5 <¤ö W&n w*’.’2”DY:„HJçt@PQ˜ $jŽ¥ÿ€âë%Í3ŸM Ž”^Ø!®Ói<±«u3Œi¶Í¶óí¨­.Œ# àD¸¶Užˆ<·Ä¹Ê¸éVí]9åœÍ˜[5»Ì$ɺkÚÁoû§E²²¬Nþ%eÇ&å*Û¯Û®ík¿ÙvÃÚ'yÏb0)A9…õ¡ÃiÌ }Äù9ƒ[R²’cŒž÷Ð3FeÄ -ÒÈ@ÍDz`l™x¢©&mº“ÑðhBh´XAª5PãjSúl´t¶=7™àÜ=b²]í×ÿŸÃüåË3—,GSňü É 'Ã¥,SˆsSÅP‘§"9Ç1€!—fh茨gfçÑq£ób%c&/4óc#¥s§_Ð+Uê+ùO»vnwmOÑM½£¶bkB‘á׃­±á ™Þa8‚aK;?½óöÉ£9µNfñyë/y•“b endstream endobj 118 0 obj 587 endobj 68 0 obj << /Type /Page /Parent 5 0 R /Resources << /Font << /F0 6 0 R >> /XObject 119 0 R /ProcSet 2 0 R >> /Contents 120 0 R >> endobj 119 0 obj << /im15 71 0 R /im16 75 0 R /im17 77 0 R /im18 81 0 R /im19 85 0 R /im20 89 0 R /im21 93 0 R /im22 99 0 R /im23 103 0 R /im24 105 0 R /im25 109 0 R /im26 113 0 R >> endobj 6 0 obj << /Type /Font /Subtype /TrueType /Name /F0 /BaseFont /Arial /FirstChar 32 /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 750 556 750 222 556 333 1000 556 556 333 1000 667 333 1000 750 611 750 750 222 222 333 333 350 556 1000 333 1000 500 333 944 750 500 667 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 552 400 549 333 333 333 576 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 549 611 556 556 556 556 500 556 500 ] /Encoding /WinAnsiEncoding /FontDescriptor 7 0 R >> endobj 7 0 obj << /Type /FontDescriptor /FontName /Arial /Flags 32 /FontBBox [ -250 -212 1217 1000 ] /MissingWidth 278 /StemV 80 /StemH 80 /ItalicAngle 0 /CapHeight 905 /XHeight 453 /Ascent 905 /Descent -212 /Leading 150 /MaxWidth 1014 /AvgWidth 441 >> endobj 120 0 obj [ 69 0 R 73 0 R 79 0 R 83 0 R 87 0 R 91 0 R 95 0 R 97 0 R 101 0 R 107 0 R 111 0 R 115 0 R 117 0 R ] endobj 2 0 obj [ /PDF /Text /ImageC ] endobj 5 0 obj << /Kids [4 0 R 68 0 R ] /Count 2 /Type /Pages /MediaBox [ 0 0 612 792 ] >> endobj 1 0 obj << /Creator /CreationDate (D:20000928234927) /Title /Author /Producer (Acrobat PDFWriter 4.0 for Windows NT) >> endobj 3 0 obj << /Pages 5 0 R /Type /Catalog >> endobj xref 0 121 0000000000 65535 f 0000036019 00000 n 0000035889 00000 n 0000036523 00000 n 0000017847 00000 n 0000035928 00000 n 0000034432 00000 n 0000035517 00000 n 0000000019 00000 n 0000002353 00000 n 0000002373 00000 n 0000003009 00000 n 0000003278 00000 n 0000003914 00000 n 0000003029 00000 n 0000003258 00000 n 0000004181 00000 n 0000004817 00000 n 0000003934 00000 n 0000004161 00000 n 0000005275 00000 n 0000005911 00000 n 0000004837 00000 n 0000005255 00000 n 0000006174 00000 n 0000006810 00000 n 0000005931 00000 n 0000006154 00000 n 0000007251 00000 n 0000007887 00000 n 0000006830 00000 n 0000007231 00000 n 0000008128 00000 n 0000008764 00000 n 0000007907 00000 n 0000008108 00000 n 0000009161 00000 n 0000009797 00000 n 0000008784 00000 n 0000009141 00000 n 0000010160 00000 n 0000010796 00000 n 0000009817 00000 n 0000010140 00000 n 0000011202 00000 n 0000011839 00000 n 0000010816 00000 n 0000011182 00000 n 0000012257 00000 n 0000012890 00000 n 0000011859 00000 n 0000012237 00000 n 0000013396 00000 n 0000014033 00000 n 0000012910 00000 n 0000013376 00000 n 0000014549 00000 n 0000015186 00000 n 0000014053 00000 n 0000014529 00000 n 0000015206 00000 n 0000015893 00000 n 0000015913 00000 n 0000016550 00000 n 0000016570 00000 n 0000017826 00000 n 0000017982 00000 n 0000018177 00000 n 0000034111 00000 n 0000018303 00000 n 0000021000 00000 n 0000021021 00000 n 0000021658 00000 n 0000021678 00000 n 0000022481 00000 n 0000022501 00000 n 0000023138 00000 n 0000023373 00000 n 0000024006 00000 n 0000023158 00000 n 0000023353 00000 n 0000024362 00000 n 0000024999 00000 n 0000024026 00000 n 0000024342 00000 n 0000025389 00000 n 0000026026 00000 n 0000025019 00000 n 0000025369 00000 n 0000026257 00000 n 0000026894 00000 n 0000026046 00000 n 0000026237 00000 n 0000027267 00000 n 0000027904 00000 n 0000026914 00000 n 0000027247 00000 n 0000027924 00000 n 0000028618 00000 n 0000028638 00000 n 0000029276 00000 n 0000029297 00000 n 0000029813 00000 n 0000029834 00000 n 0000030473 00000 n 0000030719 00000 n 0000031358 00000 n 0000030494 00000 n 0000030698 00000 n 0000031721 00000 n 0000032360 00000 n 0000031379 00000 n 0000031700 00000 n 0000032763 00000 n 0000033402 00000 n 0000032381 00000 n 0000032742 00000 n 0000033423 00000 n 0000034090 00000 n 0000034249 00000 n 0000035770 00000 n trailer << /Size 121 /Root 3 0 R /Info 1 0 R /ID [<002b8f19347118ab218c3c3dd24e70e8><002b8f19347118ab218c3c3dd24e70e8>] >> startxref 36572 %%EOF openacs-5.7.0/packages/acs-core-docs/www/images/acs-without-apm-vs-with-apm.png0000644000175000017500000001445407543434717027214 0ustar frankiefrankie‰PNG  IHDR‘’­×k®sBITÛáOàäIDATxœíݽ«ÅÀñ=× Ú¢’(v^5ì ˆŒ`ì‹«i#Xˆ‰Å‚Ú&¢(ZØ ;!&¾€E ƒ…bÀ9¿â˜u2¯Ï¼íîì~?ÕÉœÙÙ97{ž3;;ûìj½^wЈ­±;€Ú³gÏjµºvíÚØÁ ³´„˜ %Ä,-!fh 1 @KˆYZBÌÐ’mõ«Õʬ1ƒE§›ÏUûƒX÷"ù“»§Uæã`:üÿã Eºº¬±Z­†ù¶÷ü»‹ªÜ °ä•åý1[^¯×«Õj€ÿ—Ù«zà¡’ÿÎ ûÿ’µb€˜ßIÏ÷?ªr7vÀŠú“Z‰ …ˆRõÀC=ú8kà_3¦aekýª\ߨ_oOã’}A¨êW'†šð¹¡u¯êB}K+‘ë8S;ßÙºûAŠüOXc¿äírE’ƒ0í«”pT{¾##~ ßuÃà)OÿO³D¸{ítÉ¿aTeOWs>HÚÞƒ5§ýg©Þ'9Šü¡[×N= &·9ü‘ØÖZ´Îøš›™Ã+ë€K.*$+û¿ðÖ®¦}ÏŽbÿ¤EÙÏ|×u<K5¨Ìò ‹ ß¹¡ü’|Á/aTS #gá¡Õ¦œðOª ¼‰q(uày¾¥É¡2+¡A¡âû-r$ß³b[t %´³\'ê ç•ý•…±ÕüUIûƒ?\˜ÆRÁo#8¬.~{b~=]•£zRãÛ$7oµÌQ€çÔ¯ˆeþU[§ @¦ðó3¿©@̲N ÿ ÃŸ"ù÷XãXì/zö+ì<êxÂ3&¹„Ã,íÀn•y¼•ý¾l ;$¬Û9Ï…†ÌÊæ†þkº®y¬ Âö…uLõÔ;ð´ù,×?­%ÖÊRß̯§ðTÎz°à‰U`œ•Dû9/ÉßÑ_¹aãµC ƒ¬ªjx™cŠä±UÏz'¿'É“ÝÅeåu0'3/¾H.ÇH*ÇÊü hK¥O-ÏŸJ¶àÙJ~Tûwù½.þUÚ6*ü´±¢šMÞ—ä°“7.9¾Óþ¤’ÿlYET:ðü!#ØlÔ·]r°%ÏNdñªak†ù³ÔAþ̰€Z× Q ¥ŸÒ ÇY݇Z,×èá4ÛqV£ÿ.3û8WÓ‡Ó<ÇY折 %Ä,-!fh 1 @KˆYZBÌÐb€–³´„˜ %Ä,-!fh 1 @KˆYZ²}áÂ…÷Þ{oìn ®£Gø mЮ}ûöýöÛoÃìë»ï¾Ëÿ1xùå—Ož°«Ô®çôÌ1Ì›çXþ0®´Ç­ª­óÆs'‡Ç¹!PØõë×Ïž=ûÜsÏÝ‘yŬ•ÂZöo ›– ;_d Háqýúõ?üð¡‡zöÙgúé§±ºá9†ÞZÝL-ïnþFûÛ/%üé•2úÝôF}²¼ù”yWùæŸý(ÚÓ¬:Ò–;ìy°úè£ëéß½ù©îÝ®“_7Ô^¤•{š n’/Êöœ°«½{÷^¼xñìÙ³fäBqá˜{}ÍsÝÍÕlgÌ[õ‚åÁÎ[wáÚµµÜlP²k,ÊÖÖÖ3Ï<³‰\<ð€p«Ç’Ú¦y]Ïú–vT{¾_ž›Ä÷]d«ßŸ§’:2T‡ˆZ¹«¾k®1gl¹§ÛZgÒvaÖ‘ì ´‰\ßÿý™3gä‘«,õ×ÝÿüóN~tÔÊRkýœv´Î¨õ]åÁöͰ [èÆÈEÓu݉'{ì±!÷Ø¢­­­õzw¿¡¶p46GMr¹¤? ý”ì À¤dÍg•ºfW»k¹'g–Œ÷ĥǬ„5.¥k;ž~ºræ`Q´C—Ã`â²ÆY­üïûÉMüKÖÊaŒò¹hÄ&™‘ôÇœžïlsöÚ"ƒ7“À¸®ÐÅŠM2ãÉcmÇs%q¥àÇe]»víÕW_»3$ÍŸµ¾A{«/T_˜›{ÊÕvÌä¯/iÇÕOO} ǯ¿þº»»»ÿþwß}wì¾ÌP3ëàéûá‡Nž|øðm6·ÞzëæÅüáiÙœ´uÝÈÑ¿åÙ¤‹y6¨°¦|wi6‰žfÝ~˜ykfÇ1}®CôêÕ«üñèݘ¬´3Îríìì>|ø­·ÞºråŠZþàƒ?~ü^_~ùep¨U¹û¹ò{Õ1 ȵ½½}üøñ—^zé7Þxûí·ÿþûïMù=÷ÜóôÓOû·=tè?ÍôGOù=ŒjAš[¹_Ç$)W×=ËW7ž<¾ºyEèô^ÕÞ½{_ýõŸþùèÑ£·ÜrKWh^ãù^Lä+#¦¿é:ø~“nÌòþƒ°ÜÚÎæŸù?äî½÷Þ÷ßÿÂ… O>ùd~ÌÒ¾Úô¶õ-Ï&5ÈwWªÃqÏ7\;r!HÊÍKf}³@Yþ¯Gη}ggç³Ï>ûý÷ßS»ö×—Èó–g“ä»+ÒáAç³@ Ñÿ~ŽÝ‘0ÏeqÉææIƒêî»ïÎé›¶—¨·¬åþå Z‘o(Ü]B‡­†‹Yæ²´Áv `6}¾a?¼Xëü«§ióŸR%Ml¹pwž‹ÆUÞŸá{Ê=³f5è…ç³\ó©žyVÉ4›ë(W5 í7~,'ŽuðÀøÎ;翃=b0¾cÇŽÝ…f³g^”:tè®»îr­KÏE«êÑÀuâĉ±»Ð˜A×g“5Ê ˆYX®Ø;T0Òù,댮ûœ=÷?÷úuXýBd-¯ƒ¿5sC³qIO´E³Ô£­•—›­™«[³Žä=ù3 ]¯½H+ïlÿ‚t½^÷âiÜ_@s†ÎE“8„wZ£!ç†ÀÌ ×!ö¶g5m©<˜ZØoÈ×À }Ý0!lÉÇGžÆdó0h.𨰕šFmœ0?é¹h$9g:ÇG¶„l¬÷Ý&³ 0é¹h\…ÂÊf³Q¯…«‰SÀ̰@KˆYZBÌÐ’ò1«ÔÕ:®ú01ÎÐb€–Hó:ô¯csΘÔ42®ÍTþvXÓ,Dxœ¥Þñ׫Ò=wóy*l§A­²¤K‹Æõ:¸aryT:ó–•‹&xikˆÊJYÚD’ëvèäö£v`!¢¯Ž’Es@UrÑX+HÆGÉ;°á˜%É9c½t(IJãªoærˆJG`®DóY’œ3®K~ÁÖJ¥£°¬ƒÐb€–³´$=f1`xƒŽ³s2qn %Y¹hÔ·‚9j6…¤Ž#=M'H)ÓAÔ1r¤ç¢éÜëHYö  ’¬\4.̵¨¤|Ì"u €z²rѸpJ ’¬\4¥ê€Pz.I}óÒ¡0‘X¥ç¢IH)ãj 3£®Å›·%|Æ©a<€–³´„˜ %rÑä?åpàIæ €v9Î"vˆU fq)À`rsÑt7²;Hjª•ÍËáfZ›Meu]˜+Ë– ÇìϦkÂb.Ь\4±5Õ¨¡¥¦±¦µ±–KzböÇ|È«¼Ó‘•‹&ª¦6Ìñlh-÷WKn–AЖæàý hÇöŠYæÙ$¨’‹ÆZ“° _á\4þšùaËÕ~l9€F•ÌE#©©†­ØÔ4®öÍì7þrí*‹Æ“yÆZ(¯o¾ë =ÂL8Áþ˜¸9ß#­â87æaÎ1+6Ã*€é«ò¬°é N33çq€ù4fåL*1! cœ -Y¹h<™a¬‰e:%×Bl›ê¶ž~Zs×$÷YòÙµ,7Áö™br¤ç¢ñd†±fzQ“ÏĶ©%®ñ÷¶ß…ú:­Ï’~š)À‚íH–•‹&9Ó‹ÚŽgÛ„o¸A©p¿Éõ%årŒ¶Ö!yNÝu'c¥ýÖ® Ê81K›Ù‰úžç Xb÷›ÐOÆS@UsÑøI¾Û5Æ,±1…LJV.šœ»ùÆÊÛ~NöÎâÒsѸÊýM©™a´×þ6ב‰k‚ŸÅ¼´'¯o–›õ;Æh@é¹h\åþëe®ËsÁ}ùß’·uÝ3¡Ÿ’¿ €d¬ƒO¡Žø8†DÌJÁ9 0–™ç¢©‡8Œ‚qV§~À¤‹f» Ä8+€s@`R¦•‹F¸m©®z>‚ú–õÞ`Ÿ=;lZ¹h$Ûú»ºVD¥” î.¶Ï®ÎÈ1N.šÌm…b»*_³šóyä˜U.×)gÎî’y: Ùh1+ù;ìßPfRo%d¸: Ùh¹hjKõ>Ñ (e¹hJ O;®ÝE}„´Ê Ÿ®oN£žmY˃Måo¬#쪧敾Ø>3ŸÔ0‰\4±Û–꪿Mó­Ø>§€âX %Ä,-!fh 1 @KÈEƒòúÛÆîfˆq€–L+§Mu[IŸÌÒ´rѸò·¨ÛøÐš5¹\4Ö:°1­\4ÜïÀor¹hÈßÀcº¹hˆVLÓÊEÃ",~ÓÊEã™Ï’ä¢0{ÓÊEã)÷¿`!X %Ä,-!fhÉÐ1«ìc , ã,-:fqí@éšÒžZ¨ÕQ_ô•­ÿLh6v¿Úkó^Ÿ¥®äÞ¨Õ±n’Ь¤«jr›þ5ƒ;`6âÖ” ¿üÂçÆ6µ_â0KÌÁh 1 @K¦’‹†Ér£å¢Éi–Ü5Àb…c–zi¯3&Γ/ù%7[öR#€¶ËE|ž…g“ØfÓ*˜æà´„˜ %Ä,-I_ëÀ5;ÛÄ8‹ð@(=fq=ÀðDk¬S“(hòr=ïËZ®æ¨q=+LÛ…¹2‹µZÀB„ÇY}¤ÐŠVgSA«ßó_fùæŸjûfmKtnûPÂàúROô‘¬MÕ¢'ƒ,`9D熱˜SPI•˜5À¨Ç:«`öF[ëPj,Fä%+¤¾õùžväûò\0Wq¹h$#I’™Î6§®.ž0ëøw`!¢sј×ǫ̃!¼¼h}Ë“3 &qïNN j5fÉOÌI•µ ZË4B.Îé$kõÜÀ2‘‹@K ä¢én>ݳ&é1γ¡V  “Ä,Wb,µ‚'–y–¤j-˜•ÉEc­ÜPÍHCªÖ:¸’‹Jp Mã×txe®®oèbš•ÔÌðG8`*¼Ö!ög'XŸCª¹hrËx*0Ô` Ïgõ‰b:GñÌgù×:˜-›£*YTrÑtÞÈâÏT#l6¦{ï'†LY¤š`U1MNÄ!Z°JÏESVÁÇðiÀ4MôܬˆYZ’ž‹¦d’1_''¨‘”3 Ì^xœ¥Þh>`5í6CÏV®f%åLf³—•‹&*G|+ײղÝТòkú@µ°È­Î £4ó¬0m•)ñ X¦Š× µéö|œúÈÊEã*WO­§Šew—ÿÈE­Ç,×3&Ôò®Ü ÈÕ¬Ù ,Pz.šÎ§„›De¶‘´IØæuðZBÌÐb€–L% H0ÎÐb€–H×”ö ¦ÔÂàk(+¼>K[ºY½Gà–•‹–>Ÿe½ÿ™hTÅ<€–ˆYÅs΀KV.šÌœ3+= /+ÿ-(Ž9x-!fh 1 @KˆYZBÌÐb€–ˆÖ:¨KIÕ Qåêryóa_’ ±-Ë;  áqV ´p[ÞÝ.›ø¢¾V´œÖ1­ÈÊE£–[—Æ.@•Wð´œÐ1­ˆ>7WfO¦óA¤‰¾wg\™=™Î¦ØuÃÉa&Û1 ¢sÑXWáz¼EñxáꉧZÂæ&+.MgLcËËó [¾c“5ŸUîº&h½–'yí)Œí0ÊÚü*,g$»œO:¬ƒÐb€–³´¤µÌؘô8‹P@3é˜Õãz€2¹h´B×?cs×XwLGÓã€ù*“‹Fr›"f}ãQ¯ft¦£0?ÅrÑĶãz=Xg´h¹h?™a¹Þ¾´n´ë†¤f`Ð\4Er×ÔKt`úÊä¢1S/øËýí¨—µ(I>`áŠå¢IÎ$ã¯#Ì3Ü À<´±6ˆYZBÌÐb€–L"f±j€Ð$b¥ç¢‰Í9ãJ£æœÑRD°d€&=MB}kº5çL_AžâÀ¢d墉­ŸÜl¤ç¢é‡Eí<1­7œð«’‹&'Ö¨ó\Z(€é^7$Z0eå¢éó.hñÅU_¾#° Ÿj a‚ߨú2Å|¿Üù,Ifk!O `ºóY`"fh 1 @K¤1+ö Ô ]ÏÔ8€)àÜ@KÂã¬>WŒgñ”öt/e*‘>ßP]ö©%“QË™óPUĹa­:V„‰h¾Ç0 À¸"b–ö¸yâ€áÅ]7äÔÀ¸âb–6ï,€²âæà»›Ó‡ªg‹¤0€¸\4jHr½€zX %Ä,-)³8OPOJ..‹ô¹;Œž…3³œ÷r>éD¯u€Eä¢éla+áÑ^ÖM´½¸ê¨é%<{wåÆáAd@ë"rјo¹²Óxl"HO{ ¢Zhm¶ßܳwWnœ„Þ˜šÜ놙Yh\[“ÞtI¹qÈ™´..É:Z±j¹Õ²{/XÀÔäÆ,ùs¤Íw3oQLÈÃð hݘëàó#1XšÜ˜¥Î| çàc›M¨&)ç<¥p, )ëÜp39¥]û“l¢þÓ|KجZ­Ý_.4—M$ôÀÔDä¢ f¤òlâ¿®gÆæÆ!N­›a^nfl†1KÍ›Ú1¶æ%w­Ã4§€¹šá8 ÀŒ³´„˜ %Ä,-!fh 1 @KˆYZBÌÐb€–„c–yï7ñ ã,-‘>wÇúÆ8 @KˆYZBÌÐb€–³´džyJ±d—/_f áŒý³.\¸ðâ‹/ŽÛÔpþüù±»”ôo̺téÒéÓ§Çí iß¾},œ½í¼óÎ;cw¾–¬Ñ`x+~—PÜž={þú믫W¯Þ~ûíc÷sÃuC-!fh 1 @KˆYZBÌÐb€–³´„˜ %Ä,-!fh 1 @KˆYZBÌÐb€–³P ŽPù³´äÿ$—œRˆ¥IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/prod-normal.png0000644000175000017500000003507010014674771024240 0ustar frankiefrankie‹í}ÛrÉ±í»¾¡ýbG€¥º_„mŸgìmGxf´G¾<*šd“Â0Pùá|û©¬)hˆÍ®ÎšÌ‘-Š„D•÷•+ÿûÿüv5}*—«ébþ‡—‚ñ—£r~¶8ŸÎ/ÿðòŸÿøË‰ùþøâ¿Ï§ÅëøÿËeq5Šÿb¾‚ïþðòÃz}ýúÕ«ÏŸ?³Ù—U±^,ÙlzÃVå«ÿWÌfÅ«ø W/ÿøb4úö ΋u?Ûü´X¯—ÓÓ›u9šWå^žg/—‹›ùùËêQ›Ç-f‹åèS1ûÃËÿºHÿ½|µyšW÷žç;Ï}]\–§Ë²ø¸ÿ©K¿Ú<õu¹Ü~Ú«ëÅj²þr½ó=Ï¿ó˜Í£VñAóË?þ×ý_ÕKÚüàësսнBÖWÅòr:ߕߛYõFˆÛ·àñÏ~Šúì3Ôg_¢>ûtõþz±\/‹ézWÂéb1+‹y%䢘­Êö‚VgÅ,Þ¤c\L×ëEG¨~|§*U»ËåôüûZwï{žåóô|ýáýoß{»8“¦ý;V ø‚'àÓt5=•ug˜Îו™ÿô_ºyúíÏ(à¯ÿ<óNT϶ןûvþòfz^®¸l÷³ç™>löê¡w}ûqMߘêG[þ6‰˜_ÊåæéÿôÕÓŽ6pt Ë›[ÿ“þÁâôÿ–gëÍñþ2[|>ûP,×£“ÑŸ¿½ü9ĸazþ‡—¿ðûïÏö‰â³E ¸ó]/în‘°ÌŒùö‘wÍÆ¾g?=Ý~òe|ýÅürVÞ Ðf|Â73!þÞNb9+¯ÞŸ-–ó]ÇÞÑ™’„d>vÏuk:¤f9¯ÿC9½ü°Þÿô"´{òÓÅò¼\¾¿¯Ž5 yz¿ÚɘÎçMDÜê'bõañù}MTZçõ’ö´’R]¢÷Ëâ|z³ÚÿYD/Ñîù¯‹óóûÁÎ3·|Öåoë—ø­Çì{§SP{ïq[ñïžè÷;þf_³˜¯ëÁÏGÅÕtö%¾žb¾z9Z­¿€aŒ®ú§-gŸÊõô¬øÖ~?þìh]ígâó„Ü·µu¶IzæÌ8Äßò$m«`­òô_ž Ø^ίÊú¯œß\Õ„·ß‹Gê\ê¾°àÕW¸ÏE¾‹¾æ¼XžGù¸ô».RäºÈê#Ãô‘Ò0Ÿ|¤5%âïcÁÄÌËÑÛåâüælßðÑ»rß{²8ƒ“¹xÈ\Ü(Æ(éJ®vÔàöoF¢ÕØÜ™õ"ÅÑ£¯{/·º}[OÚÄ6}¾¿]–çåÅt^žƒÎœ•«U©’ÙѼ‰‘¯jY4‹ç Äó*þ6ŽyîÃØDcå„@ é³Ö(¨gÒxï1ãzfyë·©aàÍùÅçÇx_̦×ï?,–ÓÿDC^̾+e«¨õh1QÁÀ   iä+£ŒQÇïÊ_{N®»k×-,³2è±f®¹ð."þ¿LgåêËj]^E·ú—Åì<:Ž]Wª²£~ìH%gAnÚÿUß'`ã0Ç“b¶.—ób]®¾Aº±…ÿ¼ŽšsÍôÍ1uܲ4CkYXˆ1Vy-F/MË­®Cçi„T­ŸŸ—Ô¸¤Å‘{^eD+% ³Ô½ì~ì³I1ÎvPŒs ’ê‹q. ™ÏLôŸØì¹ÙÇjä?3ŸþAÿ)Z??ážqŽjn×Ü “P±,Iyfç®nOv˜Íi`=2u öšlE b&Î3þ Óš®Fþ3!‡¼=±0²öà'/O);¤ì²Ã-ú>ÅDJ¥†[ÿ<‹ñª6!Ì&/ˆ|j w¡ HZš‰K´@JƒÅtšÙ'kâ39ê ÏyðÅ s¹#€eör¼˜e)dEP2Ý~ж Åàq Eÿúç7?öë6¯óÅêº8+w}ç‹›å4ªž3 {ÎÝ{‡æ8·òi;οOçu^Sò®L…Æ4ÉC‚ÿ Éi øÆ´M4+ú¾œŸ§C<òhß¹²­ÒxMή·_ÆW:¬vO:‹Ÿw·ib;ிܵ=ÍHÑA4˜‚ø*(:U4,³çX°ðgz~pq]΋³[,/_ßá7?¤´+­Üº‘ä Ì–;Ìh”Ì @‡‡ÚÑ,K71Ñf©4­9€I¨ Ñ›,Þ.§ŸŠø/ø×»Ñ¯e¶X~yfK|[õDêmßE2U¨±|ö|’‹Zm„+Óqë1#úhD¼T É— \8!¾ÕÒaöûÎYëtC|¥©v攤ÛUJ}ßUºw³æ‹=éïÚÏî¯Kݶ¤ÌOàÖ‹E‚ÝŠª`,XÔ‰^/Î=Õ‹²^¼Ïq˜ŽŠ@m ÷cŠ@€DùZR­Ñt­Iפ ÔºÃò”]„2{‹@w¢¯TÌvàÜQ‰©@« Î!ªD5 Ô~p¢×Ò‘aüÅŸ–Åüì±S`ÔŠvï%_øÁooåm×]ðê«Û®#'·"åH½¢}büTŒžc›·ëTsùž‚’Gn T ¶ïÈFIÝC‚…Ü%ØÒô”`·?%ØG™`GBWÚàñuÁk£ ÖCô¡ ž4áYh‚â]iò¢±2fÝmå•d±eÀÝ6Fúp,P]%ºJä0××Ú ºñVjs—ÆñA`uSGYfÇ)…ÃLáGNáö™&ÙYÄŠŒ ÜX'ÇÜä«H; Û$É6!Ú¦­«Gæ ¡ÂÍÓž¦µRõç ÃÅÍ"Tu«ØIoˆ&ñ!N»‡Ûÿ°öùÆ“Æ6…ŒÆõ¶ß})†îªqÍqýöF3@Ì­bâÈô£[§Ûÿ8AއƒÒGiÆvSBô×”P¦£)qiñ§Ä£Œ¯Sâ1¼ígJ\ZjJ<ÔŸ²]ÁÅ¥î ..õ}¸x¼«=ÂÅwι.JDpñºÊgÀÅ·„¼¯Rˆë®•ÝÜFê¯pi†··Á.†h‚Û`CüŠ!¾«bˆê%ç1wÅÝ[ηuºýÓ”óÕä|9Õé—óu½‘½äWÀT}$žà@ó®<…ÁkHæíXĶ2Ö"h¬}¬…èOú cmOa¬] ¢Jä0v3‹*!Œ­FQ¥íoU>Æng)Œ}¸ˆÔ×@©î O£zÓÈo ~…šÔ¨‚„YART>B…ú¡`i^7¡ó7›[ÖW"H©vMŸXQ—MdŸªÑ® ÁhÕ­š UÄ Úb¡¬bÚ4Ñ5ÉÞ¾(>]·ùÈÐ}¥cH…ó~b³N¨Ä+¬‡°ÑüÅÙ§++®®g%›—ë¯ô°©|zVr²%H¶„è…ÑãüoãÒ ïo†iÓýª˜×PÍ—I]0#œ™˜Í®ÅnuNRu»:ç«s{l“å]ó H |¬O“øC+üëŸßüøMR@7I÷ï!ŽÚáßòu¼½™Ÿ}(ÏG?DsQg'²Á@–³ªó»¢+JIB&ÖB3@,켘‰iöÑšd¦ff&}Ó^‡›@º øõÌ9<.fÓë÷Ëé¢ý.fß•rQÌV9b¢&ÃÜ8š|!Ê(cÔñûì xø$áòغX²Ëÿ<»á‹í¿­b&¸T£ÒY¢é˜NäÍò¬Îg£åÀŸÊèO£› [Lnã Q.-Ä@ (Erãš·j\\Û{Èz¦ºà%¼0˜àlùÂn–ŸÊ÷çÓU< Ü¿G礰9õ·kÇ\·ô™ÑR®ßËåâóöÓU •ýÜïgåüòû'è@ȃï’Bl[ÅÏ÷~Rä¬4]—öX–.°‡6Í@‹Œèƽ\ï“z[ÉcŽ?O!ÓÀ€p¿¥[Ìï$í-m±<ÃeÔkjºN8óNÛ†n]LÖÅô8I/c\¶M“ë«>©óëc%±‹iÔøÏ¬‹iºP‰9eügïÖåõH¼ý->ýr=š—ŸG/~‰‰Ð›ÞÅü<žpZŒ^Ä;|ZÌf#©üá_ïFåoéÑ¿›/Ö#È™ç¿'–´Î¥‹KÌ ©;\&j—VÆ­ÖÕZaŸZµBóÄxæ,GbêÎøÝXǶNŽŽ&„qÌZo$0‡ `¶ñ*ñÝ[c;š¢öè<@ ÅAã&60'E2*v8aŒ|=ú©\^–)йÄ|ž®?ŒÖË›ùGŠSf­=…*½qCÛ|œ°kŽiNìXÁ‚°%ž°%šíÞPl‰z=z»\œ•åyô£ËëÙâ \™ê§«Ù‘ÎíÈý+IÕ‚d£«µdž{;*}ÅÌx¾JŠhŬï5ó¦­ä¾9扂 Ád콃O¡—|lU±•~ñGgPÕ÷³âK¹LßÞ}·ycþy}¹,b´þoˆÖß¼ý)Ú­éjz /¢B¨dØ»l >°V˜ñ îd•¬ÖŽž(¦ÕD&LüF0¯ßÈU^ü㨽-Î>—›´+~Ï,XLb[¾ºÛHPXÌy4—”e[ljB,f"zÿ¨°GÒêVseSS[‘Ì"µÚ |#çÞœD.}îÓÑÏEW`f«ôEIfûP—šSí>(¾R–•…ïQßÓfT— Ьì+.Ù*Ȉ"tt.@‚1v­÷Ã4›¬ÈÅrô»,>—Ëß×Ù—lìg*¬Ÿ8Ü h {Ep:É Ãß   §¨¼¹§kRÞ‰Jàƒvˆ sìm×ÉáÄ3&œø°^_¿~õjƒTf‹åå«%9D4‡ècФÁÎÅhJh!©(ÔË`•Ë+ >6¸.0° ã+æC2.¡|ŒžX0ÚcU휯.éº_ÆäUËD9¾…HóSwÏÜ`zÊæŠx°­i»Mz÷hc6ð7DŠ¨Šž%¤+Í­w`,–ÃJ¦…âØÕû§Ûב”Ì»¡kcÌyàŠt² àrLO#‰. ËÇ'µ5¨Wë¬àŒÇ?ŒOÀ ¸"þm5p6+—£ÔÏŠ³ru[û:]WÙU……qÅ‹é,~?ºÑòf¾ëâ´X•wå²ÕÙrz½¦±#„VϽ»LE2ÄàÃgchC‚=kÔT@x«ªðC9:mDŒ¾w;øØ>Ý^\ fø¼PÒÙhÒ)é1)Øøl¨nº—ÈIFÅP`&ÚTqÁP ~™ß:ùetçŧLç#¨ýÞ\ΧpÖÅrZ’‹ïÜÅ×ÜMró´ñp‹¿¬ÖåU4(YÌÎËeIÉ4 &œ·c‹K¨Åp+ˆ™(ÁDzÀ„y mÎ>]£öWô AyÔöoÿVõAO-¶gÜb{õ¹<}µ*—Ÿ¦g%?)^Ý&Þ¯. vZ4%ÿcù©œ-®Ó‹m: ÿðü‘ÏFn ËÒ6DTg…èJÊD X¹(=CuÓ¹§j⤥FÝ:мÒåô~¡®t) ü:f÷O#N4âtêµO  8õ5âäuSíßSJS9.1Q2­¯Â<Ó7±Íè]ŒÚË%™ $“!úÙé:p›‘3×Cê} :¢x»,ÏË‹é¼<¿¥¥¬3XÙS."y\Úv©G)áaö.Œc"¸¨Á}ÖÁš„ö‰²Ð{Ôµ6¾Ky¥â}%¦ò•ßyô×>Þrá]»pkê‚©¸¢Š}¶µ²gº¤'¦ÌØ?†ûJê$g"aaˆ³céÚ.ÈkØÐÊ:W£ȈnTµ­Ÿ %Ú[‹\i÷í*H‚¤\¸'úMvúSq9‡‹2úqºúXçJ]' 3©qi¢+)嘎É4¸Ð¨³Ñ¹GkâO?¿uêØÐ«Êø>QrJžõ=ë,ä¼üD޵sÐ¥Ž^Õ[ÈQ=Ušûb)÷Ù〲Uù•…¹×%JÆ«*þÒø÷´3鯣öÐõ¾sÖe¶‰GI|Ì=ó1û­­#‚?f룷{WF¢RŸû.ÖX™Úm7§7e?7²’ãaª8йLw]áñ™Ðk¹/Žêçƒ"ýëWÿ¶4HˆGéŸ;ÌÖÕÀ»i‹¼| íÎFE ³ÎƒÄ Ž?vþ¨AË}p[w-nÞΟŸ%ª+d@ê¤Ês©j%B„˜aOnŵ^WB¸Ï!g×»·˜©1óê?ÍhÇŠ3ä`BC—¶³XV‰Cße´}ªú‹cÃË›sêÊÄNЩsÎß*±ºþ%!20/½Ÿ(¨ Bý ¸º.?ßÃaÿ{±üHaLrçF>…ÿˆ]xþ®•µ&®˜>•Ä´‘ ˆH¹…ytèFc×ãvX™Îi G¶„‡Ûµ|ÛW50"u©Pa&–õJ 5ŠÁðCðex-DzørµŽ? x¡sÈ÷Î | Ñ‚<Þ‚`6Î[WLÁ¸9€Ó "˜R”hrP)‡z »T®¦ëăú™² ŒraÍ]$ûÈt\ H™ ·ý/¼ÐkÒŠÛ‰ŽY©w2‰µ&à·ÿwŽXswíX8D²Óœ¬ ñæf­R¾S½0†¾Rß ­’ÇåT2©o „œHÁ´ðʘÜnýíbµþŸeùîÿþê—eq6+_¼ùåï«CpG”ËéÅn ñéU¹:ùuqUÌŸ¿ÛÎ}¤Æc7¼nï¦W×Q%,¯g‹/©ò.Zñ»=4v²±‰JÄ+ 42Ù³€±c7ÆnDüŠ=v“y´&c7°Tê)ŒÝ†Ænhì¦ýØM š/©Vˆ3z£Z:ºjE£7}õÏ W?1ƒ}Ǭö0Ç^kÛÕ¼–îŠàè€ÿÝÖnXsZx…A[MxÿGãý»ºÏÙ˜XÀ}ácèS!$ä¼ÐÁŽÞr.“õ3{Œ¬îˆûÂJ›&ÎèB÷2ÀrÛtŽéÎAšÎ‚çCFýøD"ói{fa »bÖCžCHØ´çÀº“/¿ý¼øº8/¦ÃóËrõzL«‘8Q4§ÒýœÊöýDì)ÝÏ6ŸåŠàù@Ø´bN*d—\I‘°ª«jKKhK«¬êº³T¦eôCeI¢;½£”É”ÔÝKª,ãÆ÷Ù€X¥cX‹™­*żóz ©`ðn¢>ÎA…Vñ¶yrãØ~ûxß©´´¯Û¾„KMéîSÙ[jb:Ð|íƒ Þ~m3 ƒ˜6 *ÞtÝG½¨îœu:r”÷\2’üP%#Ó 3”@.³5TüªE6ªN*©êN{ïû¡†Þ7%$Òžž+HÛÚãûB®Š|ZFÅô¸º³‘!&F²`Ɖ MtÝÐ˛ٺ\΋5áT»çeܽŒ{c"O„ëybзÂynÇ–y«‚NàË“X˜W|ð‰y¨ÓiÁ5}bRDc|Ò#˜toXì;“âGÅQˆNR„¹Ås‹ð5GÛéd2I¨î£Au‹0EŒ.2 t7€º ¬Kˆº8 u †`Ýè°î³IÀî¶Ö£ÂCæ/^æcT²ã¹‹¿º#š ÕzIbStGÛ󰃀ìxÎÀ5pA¸ŽžpRt€ëà®ð9àŠ¦¸Ž$ÉA ßøI¼-éûƒ(éÖQA]ùÉ;ê¯!—{h†ñ¾ša’&‡aRŸb˜$†ÉcšÍ€Êlt«,h¡Ç<}i»‡¢™uÙS¡~ Ó‰]˜ß{ÒÚ!ÑüWv£¢RÓ¨(Š÷g„û“fp£¢ýhLÓYQR˜Ã@ýì†E¥¥aQ¥žõ¨§@âÃm*8¥aQ¥žBNÔÝǰ¨êrXTú®JDØ")=¤¹N‚½¾p'0~í©Vd”ôb/AÜë¾óá°0M1vÈu¸Iö-UÌˆÒ 5vCÚ·d_þü[ÕR»õá£øéJà©âckn&ácQ;'*Ÿd3€N n×Þ1זּ Ç ÏÅ$ŠU"uc…²Ý3Ör÷ažix˜dÚÑú%ziï商ZÂÓOl¼öB¦4~>JUÆ ÅÑ»ÍØË¼ü|çèAù÷Îý{½¥r¦%ÉÇä©>,IûÝ™% eÃ1%¿K¶ÄGÓ‹hIÎÊÕ*Ú‘×£_³Ùú7@\q½,?M7«[3ó{21W™˜ÞsÕAI½"‘ànJF1B˜–Œ ©Ç>îÑaX»'¬yg°ÊÑÄ<ín}<Ìõ¯4¡þõoO<¡þ õÌE¨24µOSû„°#„%Ä4µ?´Š›âÔ¾ô ¦ö£S ¦ö-'|ÍìÓÌ~Oøºñâfï{‹wŽè߉þ}à3aÛÚÓÍLX³ñtåiEñs]Q¬ÍÓÜùMfí“§Ð4»Ò®¡ÅFÚ5§íÇ9í¤‰‡^¶Õ¥·v-h Ú©ÜNåv*·Ó@û`ëíZy ]W?Ð@;ÑäÒHûS(¹oÇݽ•Üõ`ð²2˜h™œA^VK¯à[òã€Ë†aæ«•=0TVl2‹€Ùüí[6 јÍâÛÔý§ârîmôãtõ±Ö˜d£oìüÈE/%Òžº(з†;13—{°&©¼aÁ¸¶|²yÕúõOçófÙ|{sô˜l~½¼i™Ì_̦×ï?,–ÓÿÄ€°˜aÕ ’˜¨aM¢ iP8PF£Ž?X•ËOÓ³’Ÿ¬ÖÅeü UºN”fÚAB`™ O-!8â‰6?>~h¸-]¼„ÕÈ^k7‘‚ñ ÜÁ…ÇÏ6“ AxyA[M-%lº¨½79Œê вÈ=јU† ÓõÕAÂø·åÜ'Ãç±É]êN¸/šŒòBÒ}î—$?&9÷6Û×l£îÙÃx£¼›nŒöCn¬I”?O×ö7ŠMãÝ7Ö\QšpÄmZe£FUÂ)HY´©D(¦¤÷¯¢r -«0Gùzc[nךË;JX‘ÖKI­+Üø>¬tŒk1SU¥˜w^! ÞM”aÜy•YÅÛ&Ƀûíã}§ÈBÍ$j&åç&²¯ÜÄðT_û `®Iàv6‚ÓF93Ñ’Áa*™)1v·QŠ%ÄëыѯåŲ\}¸!F?n2 &0ªßuדB 4L8ÆäSÝ&²yÜr{Ål ·&Õ-ú Ýö©j£YûƒSÐBLÓQýäÔϲÔJR2¦ H¦SOt0e½!™Þ!(Xèœ[ºÆ\Òæˆ Ç›åY­Ýȱj›­f[Q3’©°:Ä´#š Î-T4¹Ö Ùv\nm{(o±<Ãu·g7ËOåûóé*¾¯gå~‡‹9¬wœ:¶SoFKa4ÑRÂ×$à‡@ß]p"¢%áVBPI®Z#Ñ›€Ûç«¥Êw2:zMÕ5òë­UQdÈ<ÆÛ |B{ãÒ¨yREÁ¹8–qs“^ â­Ÿhè|Ï“§$[ßÛu œÆ˜go¢™Š(Sˆ2e”)Û:ãúâ€pš8 ˆ‚8 ˆ‚ $Ä1Ø gˆ‚8 ˆ‚°’9™*ï ÛílWå\ÜTõNJBš‰±!Ó¼©Î9ózô®\Þ.ç7ÕMH¢¢ZŸŸ,æ³/£¨ /\|ž.âŸ~*â›\ÎS§•b£Î‘àu÷–Œ[ûà¨IŽïòƒ£1fD$øøä÷j,Tt¸ùýØSjO©=¥öä¾›Ú ¨ ÊìûÊì}™=‡ôÚç¤×M3û$ÉU=ÍI¼-éûSSè7±/Ž€3áɦöõ×¢_ŒÔÞh Ò…nšÐèc© ¥ØÔ†ðGßOúÁ1Èžsrè]hw ÅžwC½†­4QŠHÓ QmâW@U .Ó8q06àãªdíQ²Òe-IúÝä±­?~çcz ÓH7Ú×lu©ƒZ]*hw©<¢å¥-(©UcJê&v\v…ÀÃ}¤ô€»sú¯1ü‘.Í‘Âמ xF@‚Ì÷£ÍwGEŸ$M†{/ G-P­mÌ¢À±c‡3¸%øëÑŸ«x_oA£øñEâ©r*Ô\MâT@ñù›á«Ù*ƒb9æÕäø˜”‰I«„¾`¡l@wu‡Ü}˜gºâ0ÖNQrµwó&_-ÑuÒ05>±ñʦna<; Uƒ@àT^^lx’æåç;/ÂȹwîÜù®ý¤þ$¦k·¤ è™B”¡µ’ÀѪ0Æ…ÔcÍÇ/ûïž°æA>&ƒ¬–|úóeiöò@H^ïhiÌ1-üDHZCkcŽ<²hÛõž`»Û%Ø.Áv)+&ØîÀ`»> ¶ýl—æq ´;|ÐnŒx²øf¨À…€:"ÔáŸÊ´~*.ç`šF?NWëÜV¬ê ¨è%`«6Q†6PÈáÜ Óö˜yWΙšd^&žÈµÅ;5J¾Të:Ï›&_m+ÀI¾ÖË›œ÷Ëé¢Ç[rŸÄDÅ‚MHƒt±ñ& ÒÄÄ×Ûêâû"½–Hï‰ôž 6±¡,ŒH nˆ¤÷ΫDzï‹R@z/8qã̆hï{ƒÙlÇݽqã?”Y9ÅE´LÁ[`VÎj#OŽbV.TÕ#š”£é÷‡YŸþ“Ž›ëÆzW.ãÿõQd8p¢_þä8OÅÑÕ–ÃýÚ²ìÓ1•«/«uy-Õ_³GÕڪ칳ásÇ ¹£…J­ÒsK¦/êü^DÝszµfÄ9îÑè^ ÿýêsyúêv~|v×>;†tèí-ùìÎKVwƒðÿ(®ËZWª:p¥Õ®/dWšÆõ´™Äëb•7ø,d¹kÔça^ys|.•üÝ3öwgŸVÏYÝÇ9&lPÀàA©iÝIg& —´Rg& ,Ñ…FNóŽôàÿÔ™¡Î %kû’5 ÓCäÇú›Â–<{ìS§»-ð«‘‹"¬çHx´óaýŒ÷ÊÛ`‘á´»ÜãùÄðèU .ùai¶uâHÜyï7˳Z½Ïž_U= ‹dTp§lauAM@¦X½‘JcÃèkX3vba­]|XÒ´|EÅò WSÏn–ŸÊ÷çÓU|oÏÊïÀž˜’N58˜5ê¾5}-¡‘<{Ððä&nF«5³"ÂÂÚ ˆ„}µQè€֪ףþõnÜ 4¢ó4¢î¢eÛf1‹GŒðÊžÊÓ2uê0-G’`¢‹ƒU×1¨ÑÜŽ-Sa0–C¾½ƒ§&Óc:v.áS0üˆÍFȧJOÆ7 ¹Â]²› C21œ˜C¼ýx»íެUtÍ]$‚j@D'óQ°E2ÏqéK¾J@P s „Š…¡¬’œë.àŸËÓ“;Þù‹›ÙŒ­‹%»ü™•Îó™}7”lK÷às˜¸<È`)DG€d<Œwzx‚`³f`†ëìÓŠì¶½º ÉPõ³zJŠì᫘ðxu­Q2ñå¦Q;áÇ–«¥À'å­ÑÜ8óÞrÌ-T’IÑúj RÊé5¼÷Ã{¯—‹ó›=;¿ªÐçO«Ä1k ÂJHõï]ó—â€ËKLÀ„N„ßÁL˜à!_b;Ö¬S‘W%¯J^•¼ê¡¼ªŒùGPcÅyÕ> ÷:ÛÌøDâ.ÏÉøD1Ö:º(0z¢Âl(aâ‡0úµ<[ÄwÿËsºcÝplß¿§På:â;aºá > ØlÁ'qSñÇ"ñù‚ÛéàlÁ¶5nƒø‚i úÁ˜Ëx‰l±¿ÈÚvC¶ˆë'=à'mjéñ‰c~äŸËÏ£·wéø†u‘,’åd5PÁ.1¦Æ`Zü&˜»,ÏË‹é¼<µýæµ6+øH€ ÁåÒà,¢&FÁ®©®ÍénˆŸs²fDQÒxï1·‚0ËDÁHÕõãsê¯=/v“LÈ;ËD°šÂÿnÊdÍ8Œ…Ï'^§ƒŒ$ ²’’À¤â=`«Â¥]Ì81“û$÷ù}ã“‚\)-V*¢Yò¡ýC¾²T-¸L,µÞd¥<ºQ ^tZÖd£¢©ÛŸ«‰#ÕL¶Ï›¹ÓÈ9Urª˜N•6 U–\YÈ5¼3\“Sí‰hRò|WÊ‚ºQmϸV.I°J¤µ–B ì‚ÄæÛ{Î}±á—¸ñäa¨æö:ë{ö]¢:¿ET'ûš“–ùË}Âur\Ò˜Áb)ÍÄs¦ 6†æC¡Ñ¯‚tx?¤D>¯Ã¼üõ)³ÁOL¼ØÖõÕ"hluÚÒÚaZUxJcHzV'·Ÿ˜¹E¸¬:QÆŸËõçÅòcÔÅ¿ùôñÛ¶¸ÓÇìQ+ôI+§€;µÖXïvgwê`WYæç¡™fTñ­Ûj{³ýf8Ež(É{•ü N¬cŽ«Tå±ÖO‘ç®d©˜ó­Û:Të¡ZOËZÏÖ>v¡{«õØŽfþ—ÜI‰ñ#,Θûë³Äóv±Zÿϲ|÷¿õ˲8›•/Þüò÷ƒÔuÊåôb·°óéU¹:ùuqUÌû(í8t$GÝe| m§#(íìYs$]<×zHC`ÆšùŒ$ÂWãÆ€é 9Ù9ÞBÇÖ‹1h¹‘•:( C·ëŒçî:«¾Ÿ_Êeúöî»ÍI^,¯âa~¹.—K¿‡Ke¢*+pãRžˆiut0ñ›”Ü¢’Òæ©ÉŒ‚Ï›Êh@¡uÆÝ”ë"ý‡?é'æ*b®:/fÑ*§”)õÅ[¥dnLÁB5û²P[Ç·’8sí&Z³ v¹ >]n×ËéUqPbX* ºéØw ©ÑÓCÔÍ{V©l £cä)„„‰0ñVrHX¹öJc—v¶ÏUó.^P&ƪ+Ï• °–éyä_â˜õBNdLÅ„wãh­¸Â8Êw° /¬€àÇêî$¹°f†ä¡6å_ã'*Ш•µžqÿ˜Ùj‘-Ùî­°¥EÞ,ñãFËoƒÐ¸.m#J0­…žÄ+â~˜ˆ¢%+<ßq…ý÷ÀžÕ-Í1æîÕÙ#VÊÝ[ÊŽaªÒVÐëÌbøÍ+¾ã€Ûµn(Ú J¥+*]í¸kÚ Šô§_PÄßEÄÿuÞï¯7§µž3{Ô/TÛ€nõÊ3”ð• 0v¥Õü©“Ú9L/š}Àf-!¡¬²ˆ•³ Éã‘Ç{¤Çûû¢8ý©˜è™ÐÝ#Æ› ¼LYªކ%zkÛènÀÎRà7oÐÎQŒº; …ܸÉ=¡ íLm!j aâyʾZB¦¬3º§¬ÀÎQL¸Å:KÎAÉt|ï’õÀèéãÀ:kÛ ÖY8ÖÖ¤˜¯hg š–= ÛŸŽÐÎT@£¡†vÕ*Srç}•Í\GhçÀú;‡ÄÐÎBa£-2Fpg‚;S]ëÙÞ’ÜY_µ-ßÜ9$ rpg(k…oáÎÂ¥Ûw&¸óî=$¸3FË; ‡>p˜ ÏQŽ¿ƒ< Í6ä9ã`{¦Õ°ö|Ø3ü)öïøü½E'&{vÆÛCjÖ¦œW˜k.îDÙDñ0Ù4or7_|²÷œ{›JÕ«<Èþ“¼ÐNí]Û`¹¬¶÷ÿµíqoÉÞâ쎻±å1›k ¬Õè«™kÏ·ï g½¦\ᯎÃ/aö,¦KŸ‘ÄÍNÜíEk6 Ìdz¤6¾ƒuÇ«›:Ù¼¢,û~ÈK¸mGE_k¶Êß?Šp.Ã4Ë’5³Æ œ\q5‰i³å D{­ÚR4¾ŒûOº¯ÁåiÿvÏû··Œ¹à Hø¶ÝÝ™fÅ’SÃ(Ê›¯Zݘ€¾VpÿA÷¶™mkGEšØ:3°yšè5q_—˘.fRwA£¯ ¾eª•àŠiïl”-‡±ƒøn#íoÄÁ~í¹‹Ôéê¶ZˆÞÌ–íÌl •lHf+ŠŠ—Ò~5[B²`ÚÊ&³õäÌÖÎ]$³ÕÃJfËuµ5ÛáoÍöL|»5[&†¹5›lâªlG«²ûØß/…î”B'6Ê•BÊøM´š–]+¡÷ ½Œ£å’yÂïô„Ý7¡#^ 侂•«´Õ$šÛÜ“!ìà{$HQ‘j)*VdH M´â–b˜LP±'¾·ÙCL¤è” 喑¦ªM>˜ñ}ö¹÷æülû¦,ùäSä¾ÙVÑozÚHÔ[˜o³AÍ› Ù_Jæ’ûò°kÛx&7ÃÜÃX¶ýc±.N‹UIÜs¸¶ÃÑp?rdo9Fdßïh³ïZW°ÅíüE1VQaE ’ks­VÑŽõǬQ]±öîéØ3Òq ôãt´ú@c«:RA¬~B„4 ϵ¯ÔOy‘ ÿV´]oÿXõó¤zÇ©züøTïÛºÖOÅå²ÑÓÕÇZ%ÌÆý§ÛgpG ÐÁ%1*EëÆ‰4kZû¿†U®¼³5©qNº5j3š &…–D¸JdG˜ÌÞòTPÛykaF±‚° âPﯖ=¿£„{,0£Ú$!Z é]UÿrB£w r°¿ÍGëÓ„NÓË›eÒ8þ¬Eû~9Ýê€WE²ñܬÊóÑE¼¯«uv9Šæ<üùæžp¯Þ8ýüÅù¢\æ‹õè| oßìË(îã_~¹}äh:X^³‹ë²z!/^-ëœqg[#׊kò‡y´íc‹Ì” …œØ˜%8!å&7CÆÿ¹8û0ºþjªª‰žh]nf磋ø[Œ‹Ùº\΋u9½ˆ÷tçáÑÆGÆ×V|,ç£ÅÅ$ÆÉÎÝ\_.‹ó’?Ý[$ûD·Óôa•ªïgÅ—rùÇÕ7ñÿñª^ýñÅÿæ$Z~FÙopenacs-5.7.0/packages/acs-core-docs/www/images/dotlrn-style-1.png0000755000175000017500000011717310066530231024601 0ustar frankiefrankie‰PNG  IHDR X' pHYsaa¨?§itIMEÔ <úH IDATxÚìÝuXÛðw¶Y:$±;°%ìöÚ×Ûk×µ» [¯­Øb¶‚ba¡‚”4,lÎïÅu%–ãg|?Ïî™3çœyçìλ3³ SµÊ€o‡ƒ Á@‚€ ` Á@‚õã=x¸åÁÃ-N¿T¾ÇdF Öïùþ~7`ó©enxëÐßê«ë[Z>?gx'n®2ç1š¡yÍÛWGýNil¾wý…3óÖ,èÙ¤ªÕO››â ~'Û®oD‚õV­êÀjUlÝÑ{ßnô÷èf_ùþ‹½Ž7º4¶Ô<5´iâ 6â(Ö”Øy4ˆ¹uîwz‡q©6¸žÇ¸~#·]~­ºvÞê‘.˜ßOdX§cß*F<$X¿°»«–_‹“õX9¢ˆ±ÐË›­OŠõ®¦yZ¤cÍ@ïZ}í5%uúØÝÙñ{m4+ËH~{lûn­–˜v4®ª)fÀwrïöj¯é®?:«ËmiÉNW6—%ÕõX¡úT¸üÊúf‚íǬ N%¢"® & jPµŒ­ˆd¡/_Ü´ïàuMõ9íó@Ú%êÇnm–ñlÞ N ;3Au—!DdY¹Î¤MëT²çËSoÜÏ2¤<»kÞgã°ÁMÜ«3òþ«fí}mäX·øøë4EŽCmÑoÓˆAM\«3Ò÷üMß÷üS;Yß5•i3ºx¸ÇúyuÚL¼™slKWûgx³zU‹˜‹9‘¯_ÿ·rûÁ»ñÚ¢ý qO¿‹{ÜS?œtou\]â¶háÐ÷Þ=¼BÔOGŸ]÷·èHÏæ¥è¥ìa×fV®Áñ]=âÎîè0ý&^“ðc$‡TX/²æûÆÈY"jÕÚbA•;|Z½""†c0 0§KHš¦¾}½†S‡5®RÒJ‘uØkËÚaÙÛ4/Wcìð&u+1æÊƒî>ïÔ^®eŠ%¼{³aƦ”ªMt­SÂÞ0áÝëeÿx] ÏÈ×0ô!Kz;iràþé5—w¼gËù¡î͉ãèéÕ*feÈy}ÿÑ­ïÖn>§{´nñè°jÔÈVj3᫪׆©ÿ/Út<Ü’åú•¦¤/\ϲ$½>r#I&0)7ÜÙP]b`U¿™@šøÀ+8•ˆ,«¶õYÓ£Tƃ®MF¸6s%½È¤5s=«˜è¿Á¾ÇÆ÷jUÑÞ€Ãᑉsƒc[û»:§ýÛš»ûø©kohWÖ§»ú…%^S–7nøÏˆe+¹»m8<©aYî ¼š7;lñãòõÜÖx7ÔTnÛjB}×a5\¹6š²üD¢[››¶·Êm¨î…RVO\Ò¨þ˜Qk‚+zx¬ÛÔX×ÑâÝ•ÑûÃí›ôá’ÃGRcG·c»‡VJ~ЯÍ?õÎò7pœè5»Ua‘ö$ O—)«U˜ðâP”LehÛÌFÀ!"®ÈaN#«½Yò"â ¬»*eq«^è»S²„]›Ø¶ÊÎmÝ9‘÷úͼ…$ü¸“9Ê4ï0¥g #"â m[Óà„SŠò5ŒxDddߊå¯`Õ•-*´Ú9¶ä¾ù«ÔñlÙÃ+±Z¿NâlŸù¬oþpÿÞ¶ ‡»5ž¶êðËò­ÿ""‹Š­.õ¸¹cgkáu<&ÍÝñ´ó²ÙýÊk¯ëéÂ]=nn½Ú#§ìIœ¹gi¿Šìбs]kœ²'e†W M5}†¡¿¸§ íëëÙ²¾#Ôccõ7nÏxùµ“›Œ¬ç1qñÞG–Õ=ôíº‘¯lÙÖÜm(²+øÕà% ã2–jå†P"j5¥¢úyé!ˆèÑjõ ­^óófãTßÉ2iR̶©'†ÛsASý‡;¶÷¿îu<57ËáLðÊ5·cUéËŽÀÓÙˆJõëg̤§q­´µ!"³2m&Öÿ@ªŠÕ3JY®Á7t\»pa&~bŸIJ/'ø‘nm‹¨1¨™—myì.?Ó·†9õ¨ônw ¦f÷…Íçôßv#(F¦T¥ÅEï]¸qðʬ¯ÜnËÚž¾êÈõT™Jš–xãÖô“ˆ¨çÂæG«¿†6«7Þ¤¨ãyýö¬!Sõíßc÷Ý Š•©ð~¿¼¼tÝðvlgÒø¹VU{: ï…ÈhL‹B*YâLßXõÒÖ""º ÏLSîõ6°v':¬çpžGi?íá`@D;‚Ór¬œ¯îTŠ”K8<#õS†#ô\5±ž™BÅZXšš™Š9 CŒ Ï1+e±DÄáæñQU¥Lýw°ÏÅCÝ6Ì©õ×äÛ_lf":|{Ó—§µšùäzÒrU ÕièÒÏž35|No‡Ø€­+æŽé-<º¬ì DtyÕ+ý£”%왉6ß|ÎÞñUMïo¿ Ãk ~°˜›g MmCTvPñ3³£‰(ìнRËJÑ•í›XÚüùÂV'[ါ¾øªˆŽ~‘`6h÷"5{/lE½ü¢<ñÅi±Í|¢#9½$1þç§ò$í¾>ÃÐWh£”Çå·å¼F˜Uä’±*eæi³ÙçÖ^ðòÁ“÷Á^¸ý=âðÓ*ÀK@W‚¥”FÍ»¿ÔÍrj ëqjW2ä½÷Ý-Så–T|åè…†ˆ$ú6óUÝ5™5m[a¿å›|ß§†„ÅFE'\½©ç·7õý(–üæÒØn«»öv hýäÏ'ІˆZÖ%Ów’‚}ÞKëÛÔj^¸©ª¸wë§·•…'ÚϬg^¸ª©"#jÝ›´¯ŒÒÈÓ›5«XÇ£:œxèu^Nð#É’ŸÞT ka!ìRZ2(VJDiÑ’ŠÌ64 o! ›ÿ9éç1Lú^‰æ»XŸaèϪr«´Èkߣe=…JUvNä—oJ¥RšyysÚ§ÝÛU)UªT‹ÞmkmX2oÿ»ÿ×h¾&—Ã|^y|ÓíΠDT~D«*cj³,»~ÙkÍ¢c±DÔØ<óó“Ь*¥Ç\W?MQ²DdÉÏÇûܹ50ãç¸Twwù5­¥ÍØwÿüµ Wïb“%Šï±Ÿn-_v+AÞgÍ0;­ …#Ó‰h`¹/î„°«úù+TKDÚ‘cUÒew⦖N/'K~¶!D’úþô…Y£…#+ò¢oÈøôé³ÀQêSÕÄwùÒcO¦³‚ñÛÇ–3äáe?Ø×âûvmcv:óŠUx G6ìpZ»Ú‰Ò¡•ò¸×óHtFÿRFÙËGe *ûE¹YÙÖ’¨«­>ÃГÀØqÞ’ªW–Üÿ¶-çkc÷‡H†ÕÎúã2…ª·MyEóT÷nïÖ£³&­éÐ|~»qc¾yþï’•lQa®yQ~_y$Xi‘ÄdXÖYàn™râœÖÅ£]Ó.+Yvè‚V¦±U¿YVµoúyõÒ­/S‰hjûÒbS¨d¥é ûæ¹aÛ–Ѩù­œ,Eb+§É+Gh/ÕÝ]~]•QG‡1¶-ÒgÜÀﱫTŠÔéžG¹†ÎgÖø|"Eɶ^3¼yµÂB.cl[dÀŒ §¶ý|lˆÊ ¢‘îÚûæñš"*-æï<¤þŒ¹Áëß°[ûæë£ä3þôÝ/#®è4ÂG",êµ½›á8  åíŽÇ%6{¶9øó´ßô®ÓôÒ·|ñí¼3®üµv\×úÅM„بBšÿzÍËš«M>×~ÃÈ¿ê: 8|±Q%×:s6-$¢=SζÝ0¶³‡³‰ˆËŠ+xÔ_·¾ÞöÉ 0ZÃ`Þò^ì¢ûÇð¾@dëèØªgÇ=§'ËNþ7çv‚þ¨|mìÙ‰‡j/š<¸]E;3.‡chfY¯më-K+yM¼«®pÜ»˺Îfb‡/,ëZ+-òη-ÀÏ`ëËÔ™\L…®P\¶f©«þÕ,*ÀK ïÛ—¼è°¬Š!—92ÛO»<îÁÑNc’' j°ÿB ÉÃ^¾Z:fÙþ™×Âö YUd^Ï&ÿŒñ¯~øxdžCšçñç6·JÛ»þ¡sM^ß½»mç©.õ«èÙ]~-ì½V5«s÷S 9Ò”ø³»Õþ{+éõ…±‡\WuþœÀ%½¼øW÷Øa _2y®¹)dQïü&ÍÖTð²Õa~ÇNËföä°i’zîcˆ()䨛ôÆÎBvéÌ;¨ÞŸÚ•2ežHúÞ;TòõQZà¢~}çl§!ò}»nÿ7¸Ëì;x½Á“v2^ÙxÓ£äÏóùñq¯ÂÆW_ÜH{ϧËÄøqz[dgÀJŸÞypîâÙ,MÅ?9Õy\ü?ƒz^boÂgƒ=½äwŽˆâŸœî:!u’gßQKl yHЋ½ãgy–R€Ñê†Ð¬Zq¡jÜ“äÜÖUW\¥'Æ%¼ ò>õâ“„|m >òµ±iá·:ôN=¼ù¶1E­Œ…)I¯Ÿ.ÿ{êÕOo/îÄ»õî3s­½*=åéûC{ú¶£ø®²üRn¿%¾Ȫ¢ó{¿6Ф/ÿÛ´®“ÇÒ¿˜ªUè–Ȳޭ‹ýd©¯ÝÜËq@';±&»·>PüÉòþµñ ÃZÑ«-{]ä©to»wÿù#H°t.æÏlm­RJæø€`ä©g)ã=ç?"¸¼/@¾à Á@‚€ ŽaYüúÀ·„3XH°` Á$X¿P‚5´ÉÁCÿ…g) ÚuknoÝ+v±_–¯¡D\~´¤ÝŽ>NË{–^?£ÿùÀ`iö¦"|ïü˜¸0 £»Âó#óò¬Ì|‰/4´/Q¹ßôMéªÏ:ÿœß®à'—÷Ï4t±_VËÚ°ï]OKAæ_%KRý\R\ÈÁˆñßjo7\}ßlĤ*ÅŠ3JYä“÷>“/[ÿÓ¥{KSíj]–ÿ#âÂä.‡£T©tWÎR®RÊScï?!°ßÃuMÔšÛWZþ* œ˜§×ð“Óëá_­D»üÓ4Oï_1lTûÛŽcÅ¢×3×»–,aÌãW pp)>ì`ÓÿœÌRíçI]ÅS_øËwÄ9FDŸ×²­·pTìÄUA ˜‹V‚e`_ÃôÍõD9KD¬"R_ÂcY6×òXeZòÇ·6ÏX¢ûZí%ž>{¼ÚŒJWa6üI 1œîÕy»Jˆ(Ñÿ*¯¢›@k½F÷í`o äpE¢Ê½›ª2â³70`}½bö"†È¦i=V)Ï^¡äèN+N÷¿¨^©"¼'‡nOk°qP“£Ï:u|qh+W+!axüŠC‡íºž½ŽØºýî¶A6½Ð<È­µuþy”3àqL쫬>5QS>ɽ¥ÛYð¸Bc׳_yç+¾ŸoqçðŒÍ¬«Õï|,¬ìÍM͵ëLÝl»î ¦#Àï§g½½§‡Ð‰òóÂÊÎleiôÝ×·ü>D…$†<ŽÈñ¤NÓ¼;r¨bë@T¾~‰–£Ý½¼qñé².[/ÔÊ­þíxÅe§åZ©LÎÉ¢Çü%íKM"Ïš9V ’ÈÅœÌ+wF‰¦¨ŸŽÏØaœyºŽ'*.—<ËW|ÕÑK>Y1¼Ï¢ç·"ªò³W«4æ¤U‰Ê·û=­c,À¤øS,“rnÊ IéN»Ÿ+Uk/ Û}fƆ¤ÖC]Ü]‹·´m0ÁuSöÕ¹ù¼Uɼré–elv¯ù(×KÅÒöÐñ†ymÁåI.:¦ý G ‘œ%õ%Žè‹$I»O•´Qæ‹­ºN?`!õhÓiÙß)‚lÑ`8ëNxVí¼%ôì0LJ€_¾?4ÊðÄ]T[O_dêú2AXðoм‹]:õ*Y¾ŽƒIdÁÆ1®äŠûñ_\äpE\‘EÖahõ\ÍŒ’®Ôݬ$Ú§o…ÃýKkäV³˜ˆ÷ U¦~œµCSÞÚBt7%3©R¤¿ÑI¾ooo2çR÷+›¯Ìq©E…± M—ÿ{'“àOI°ˆ¨êxÛ»ã‚G—ÌRn+â\÷û¨T*?> ÙÐéBÁÆ1t¸ƒW›ׯF¦¤)‰U%…ÆœšîSq\Ó,ÕLyÌ£™<1‘ˆ: ·ó=ž–¡båÒ‡[}û7Èá¬Õm‡9ê%â|~›þeÍ'­=“˜¡”Ä<ßfަ|ê¤Z“–KW(e)7÷Ïá”P—Ûð9çÃ’¥ñoò±‘ oîÅ#asZ_O’帼Ëö':À¤øÕñô¯jáæÊ(ßujjœ¥|Ì6Åã$5+fÓddG½§ã(1¦Ë?V7Ž->³åUb†Œ±(ní>ÀuJïBYª è¼Êmm#Ø÷fd‘Á\æûޝv,1)Z§Ôä£u³7;åNT–¹}õJâè‰ìº%0¶}g¥‡®êòŠcÏß­’íßUÆ5¶Ùw#ó§ä7nÙµ´E*c$—$RN'´r¼Mhêzaks·NÞáFæ°3Äå}æ Kþi ðkÆ|cøcÏßX—óû›ÿï¾áŸG(\"øÖ ¹ Fòäï=ØÅÅqø®d„â'‰?aÀ×À=XH°` Á$XH°`,$X¿^~W`ý½‰ˆU)ªyŒ LWf¶"²Kö›iÀaˆˆ©>DϦ*x4Z6Àõd!!+ ?râü¤½ªß%²C† !"†áM[½¦ˆ«.TÉ"Gž-W±Däíí­wcª'~'ÎûÝ‹JPr Š—oôWçNÆú ?½Ðnðç ²º,ÔëjoõO¯Ÿ'ß{ïd—&Ú Ã0®¡i%ö·®ÁüÀ1|o<ƒÅpxËXjž:ºwUgWú«Ò}Гå]š•³1äsx¡s‰âãǽ>¼Äo_–UŒÓ<{|@}àÏW—¶Ì]·çÌ«÷3äJyFê»gw·.žvöm ¦ï· òï†ï1Ob^Ýߺ|ÆwÛq¬J©HKŽ»}rËŠÓ¡˜Éð;álµ`©Êų.ùS?ý{˜£BÃZëßÂÁU‰ÈsøÜÝ"¤Œ°VýV74­Ñ½yÍúâkÍç„¿EµÚ©ŸÞ>Êá[«ä1ú·ðl×ÁûxÂÂ݆ô«YÚ^ûÊgã¦ûQß>Í—ôÅ þ&AVËñ<ǯròã;Í“—o!¢ßaÀÞÞÞIJriê3¿Ý|ßž?@­&b2ÀŸž`My’|Ð¥™‡Ñ©k© añ)öQ÷w9ÔôT/½py]c~ÓÃ/¤(„&å2.ÎH~nÐp•v |†!¢Z¥íO~ˆfÜ<ïÜ÷ùüÑÖß›ˆÜ–_ÝÚ¯vQ~ÚVï#ö¿T/2´.·m^ÇæìŒ8ʰwoçÎݼ-(U½¨n‡Ž›»•4R]»p¡ýܳ©ŸNc¸´l½~ {£a!ë6î^xñËo{g“M¯Î½Jo]Ê€§Èxsæcºié> /6ª—®úgÄs‰|ÌJ¯²bžB4üŸÕ|qÙu+Çh·pÿ@ U:Ú­¬ íÊö×3tó£6mZª+Hƒvmõyú.RªâZØ9·ê=¨ž“Qö‘„Þ9µ××/<6ÕÈÚ©þ_½Z¸V—«¯¡ÌÖqÇÑK¡1if¥Ú÷XÝV¬^tqßß[©s×¶ý´[Ë­SukS{7\wðºÀ®úü)}‰ ë ãSn!M~°mû±—ïcå$°u*Ûq`¿ æÂï„<ç …ß÷ÝsòZhlª‰cö}šVµÕ=4×ò4AÈqÿæÖlÞ†/2®Ü¸/ùŒQJCõ™Z¹MÔÜöÀÿK/^÷zÁ0œ- Qñy siýÍÒOSˆh|US"²«Ò„ˆ¢]ÈzÜ:öˆúêryáÞ±Í\¬Ù{¹:Ö£”…Hdl9|üØ-Ÿ®H®Ø:¤K5—Ã8•,³vuuyQ÷ž7§6-geÀ6nÓîâu¹C®÷g·®YÔTÀáv*>áôI% X|K´+òªcwc‰(ö®ŠeË´+®YÚØÙ˜ˆÎ¿N"¢¤×ˆÈ¤D“,-܈—Q‹&šIõ¹ãÔ,•y¾ðÐoÿWár%«”Å…¿Ø¿noN§7,Üq*$:I¡R&F½9¾yÞ¹ð4í ³6y™¨PÊ?†>ûoUæ‰ÉØ{[Wºú1M–‘}iÏbíúº;]´ûJ²TžžQôW ²&ÐÐãŒQ®!ݽlÇãwÑR…J¥Èøüpó’C? yΓä7Çæo=ñ6:Q©R$D¾9â=çÔ—Wsœ9ÒÞ¿y6«›<=ùá¹mDÄ3(©ÏÔÊqyNo€_&ÁŠ}q4QÉVê׈FpP)%“_|~W}´3”ˆ*öu&¢Ú}í‰èÞÎð,-œ_¶hðÎû J–'4ëޣýSËÏLoiÇÿâF®àcÛ kèîED]'5Ï< ¶ÍTÂT÷´í´ŽˆD¦Õå'×$¢•#¦[uÞND•»wT—ÿ3½.Ã03FÍÖV~„ÃpÇÍvùañ5.Ú^ÌaÂÏ\&¢+¾á GÜ¡è盎š9QÄÙ·Dôöl95sÈÒBœBEDV¼\÷T¯«½½½½½7.=‚ˆäiO²×¹øß-–eÿ9ÓkÃúY£;²¬òÂŽí 6®=—¯õš9¼ I“î© ÏzDDvî×­_7ÀÍFÿNmë^çµf¼g_%È #¤OSeDä9w•·····÷ê…½~@òœ'—·]U±¬½[÷kWôp³gYåÅ­—tÏÍy;õ†ä¸ólVÇ©Á!C†Œ3ÁûØc"*Õª³>S+ljšçôøñ x‰P%Oü÷]ÚÚî]‹¾ZHûjo”âómÅŸŸ'ªjU²%— ˜^ÒˆeÙ/S³7±yí–];OôêÒdV?W¡ y»¶·-ãþ¹£©2rM€D¡8æu:Ž›×$Ú“y²ªR•+zÔ(ODN橯^–B"šyïcŠ*–©þ¹‘~VB"š³fæœO%fEêùý˜ø2<³¿ì ÷GøùÇ”¾–(5vèaÂýœDmJô05ÂWźøF¤2 Ó¢HÖ«{<&FÎÆÊUv‚\ñoo—W¥]ò[¯g§íÛTäóø…íèW ²&пS!íZÙjçÃXïl‹—._¥QskÁwÿ=”<çɵø "òìênÈç¸uº÷úôŒøkDítÏiïß<›ÍãO`ba[ͽU—ÆöúL­™çôøeÎ`Ñ)ïP"Ú°¨'ÝÛøT{‘LòöX¢œoPxDÉå ¸’„{štÈBš³uËžâÍfyn¸IDµ;i/-ÄS&Õ_¿Ïü‡=¾ÛêY,#zÖÌ¥_eÕ c¶ï2æP"²ý‘!®ÔÆ‘ˆöxï!"§¶¾‰s#¾RúáJø•R¥À¨¦æ·4ꚉˆèì»äÏAKð›±|ëýW™7q‡\Ü2u鯛6ý&äšg/‘Ei?ur‰ˆáˆ²‡Ô0óû¡_LÝ–0àýàyü•A.ÈgŒÜCZgð´-ÝK;V&¾»zzÿ¢…Ç~@òœ'Fû•À}Q’óÈ‘öþͳÙܨϊmðZ»xî´®Mª0úM­™çôø•¬ˆ»Ç,k^J̪”Sî'fYºîAM›Ð‚ˆ"n_Ͼº¿Ÿëï½æ¯2æBŽ<#Áÿu ©”_œèš3¾¶—9f IDAT×zH{"J‹»­.<9Ò…Ã0»|ü"­êjoÞxÍ®eié\õ÷–úý«^ºë£Œˆ¦gPÓ“©>„©>„ScØ ±Y¹¶†‘„K†Û¾´Y–¥ JšÑ™gˆÈ¬¼[öÕku)ODþë×ßyùA¡R$|x¾s™Oô«{»·eÞÖæu4€eÙ:·´Žr_¨m" ¢¶Ã§¯Û°Q}`Û¸q}ö\*ÛZB"òÞ}W®”þâF"Ýæ÷7;þïA.!e8m{þ3qê¿ÓF‘$êʈ@žóD=à®§É%7x‘¹Gžs€a"Š“ÉSR9îß<›Í/ÝS‹Éç¾ø)ø™¹$te´t‚­(9êÜ“l'¨žþ÷ŽZªjLD×÷Df_}äÁð[}FÎøg¤Öì_¿U»ŽcÓž)Í2ï_Ù9/ó8ñ8]Ù„Ï9z5ÉRRÆÆ•Å܇åâÅ÷‡.s¹fþH""zw鈺þ’…w†¯ô˜·bú¼OÍÆ¶és⇅˜+tll.<Ÿ!²hfŸíÜIá¦ÅèáÇ”×)DT¢IÕ,* hW9ôØ£Ðí+fo×f8¿†g^…±p“ªU“GOl¬¤„K•YNÒ4ëYûª×µã^óŽ*1vlµlê_ºGÞ´gÍ+^~1÷vޏ·“a¾ÈÅuwÊüðyü•A.!Ý3mŒßÇÏ—Ø yü€ä9O÷®sqÍ•ˆë{Ç^ßKD Ãm2¨ažÍâ11rvêÈÆEþ^6½nöý[°fuÐg>ë¿/~½3XD´sO$=Ûy7û¢øà3J–%"•J67D’½Âm¯¥=¼®Ü{Ÿ®d• Ùë çã'Îí¼÷½vê³Î½NJc–/X<òV‚º°×胷B“äJù“{·vÛ@DÛ<+QèÕÿê/¹ô:A*ËH»ìëë1?H]?ìúÞzs}ï†&ÊT¬$9ñœï™zOýà(×ilGD…›×ʾÈо…ú" ôúôó,'Z 9¸Scg;s>—Ã+_kÀ„yŠd~rÀÈ.ÅmL¹¾}™ºcg %¢'žd;úö˜Ø§e13ÃÄfåk·˜8¡µÇìžã»7´ó…ÆÖnÇi/Ò§Ó_*ÈHhr i—ÉÃë”só¹žÐ¡LÍaÚþä1OÌËw›Úï¯R…-ø\ž™]ñCf¶ÔãGÞvpµ22žˆó"Ç kV‡L­‚Mo€ïû¦L.ƒ¿SÓήñ´&„³èp&¿ëªKÿ¿ºó½ù{vqù^ß=Ü3q”_’TlÝnåÜò\ @@(@Ÿøv|ïõå&؆Ç!¢{›üe2ä’¥ŠˆŠµ©Žh Èð{ø^ßöŠô[ÁÉH:uâF¯óe&ŒË L+Õsí_Ý Ñ@ –.†µ=¿fõŸçâà÷¶výFÌB~3„ ,$X€ ,Ðò,¢ð á ,$XH° ,$X€ ,@‚€ Öw·iÓ¦M›6ýäÝ©×:ó4¾`­%E_>uà7‹$,øÂïø~) °â“—ƒ?$!€¿"B§Áƒx]V%¹tæQï¶ÕF$Xº¨ »vVpL{õí,â0Ÿ2‰ŒC;v'©øûö6ãqdÉïoß ùðQÁ vªîZ·°af_êkRÚY‹v‰úq·f.§®}¹×*eÀã˜ØUQ?u­[VÌç˜ÚW#"V)QþÕwÀ ½‹RÜû7.^ºAD¬*#·á¹5®ambÀáð‹Tp#"•2UǶu­mo˜òîꃘô,‹ž$J‰è¾ïá-›·<}›ˆdIAÙ[YUcˆ¤qDô6à#™–2#¢„GÁDôècSÕR¤g4´c«vøâCËrENU ‹ñ’ø¿%XDLíÊDôüZ0_{NDvu33õå0¡úÞ&â ˆH¥HÐ^ÿóùV‘½uÁç¥)UÚ%\¡vM}ú²Tß ÅÉL)¬ù\"b8"íH"ïß¹çÔù+ŸGÆ¥êÞøÂ‚Ìî®a–­ÉQ…¦ÍLxœÀ3—3T_ÔLÎvÝP¥HÌa'ñ,J𔲘wiqRdDœµp’¥Ʀ¾‘«x%-x=£¡[5%KB£H¾•-€(øÝ6fåëqïK½’lx;&Ã5rw2V/2çq>ÊUáR¥£KDJi8qx–™I K”¦d¸ )åÑÙ~ºwžˆLxœD…*R¦´¨[‹Ô®©»¯Ì<#Ë639lÎ þ) •S¥š% [[X˜ØûŸ®¨}nÑ+å[µtwÞ9øôír#'Y¡ê6` 7vÊ5zõ2ñþÃ+J–F­ U3ø'Ë®ú‘‘cý£¡ÛÌŒ³Bã†V¯÷_ }uéAÝîõðªøJÿ,ߺ¶¥±ªË'/«ˆŒÝÅŸŽÜ• Ñõ‹I EFbÀ¥ëDdèà¢^jÌãÑ­ p…ŠÍHýøàò5Ýêd.$¢kW%KŠŒä‡Wü´kêîKáR9—,åXØ29잺PõímR¢¡‹µAܳsÚ…LDté^°L©J|°iÓ¦mÿ]ÊL "¢x™"=CIDf• QbP<™W.ED%\¬ˆ(>(‘ˆ W4Ó?ÙwyÛºÎ&%;ðd)Ïî}ÌÀ«à+}Õ÷Ŝ݊Ý<¤HS‘Km[M¹SÃz†û.¤EØø)³lèá ~\ÍÆàjDZÈí3Ûn1œ<îªvnTýö©!þûCü‰ˆa¾³î¾ôWÉ\ô >ã²ÏîË긊iRe!÷[źJËFÏÿ;-ÑúJ_‰•îøÜ‹}reÇ“+™%nµÔ¬ùÜH™òðŽm"K>K M«ò˜ KDTµ„ 9ÕdèKD ¯ª©ðk¢ÁÃum\:ää³ç—kv­À×øª_r7°ªcÍç‘À¤j ­ïöóÄN;6+]ÔFÈãpxB[Dz­º¶ÕÜúS¢YëJÎv"‡ÃXØumÙYw/“²]ZÖ³³0äp¸†æ65štü"CÔÙ—þª¶iQ¦H!—ÈËÔèÔ± ݺýöÆš+(ܺ®£v‰È²JÇÆ5mÍ8 #04¯P·¥æç²<\+š‰ Ãp>Ã1¬`( "žA õ¯aqøÖ•D$0¬`øéÜá×DClW¯¢™PšôøA‚/ €¯Á°,[°5•,)R??䛨PkÑ£I#D€¾æáÖÍ™¿6Îá[»Û#»øêK,à¥+Xc ;FBüÍh€O ~‰r„SOH°` Á$XH°`,$XH° ,$XH° ,$X€ ,@‚€  Á@‚€  Á@‚€ ` Á@‚H°` Á5Þé&è–߬Ý7¯}ˆ“(ÍÌ*W.3¢_ûNåŒÕK™êC45†áñ…¬ 5mÞÐ{H=£Y¢:uðĪ“!ñéŒÀÙÙ©{ÇfÓÛ”Ñ,W7Âú{k÷«]¨é…a.—kbjÚ¦cûmƒkhŗ×.ßzíÆëX)Ã/ZÔ¡Ã_M÷¨‚  LûÇáòÌ-,Úvn·©¿ W«NFò#ƒ†ë‰ˆa8÷®­«.æQbØ%‹Ž‡âb.O´à2D¤R¦Õm8ñžD¹ÂgŘ¢â,é8„éy|d8¼×ÖT1Èš"#ÒÄ}vºŠÍoµÜ¶(ÏÃ}~7ù'÷#ò‡Óë×–µçн˜T™R¥LŒ»våf×¾Ó>NÎ^™eY¹Lú!<|Ç–] 6¼Ó”o˜1¯Í’3—žÇ$¦+¤Éó§A3f¯t™uµãaYV¡PÄÇÅíÜ´¥Ñ–Puaà¾ÍÇ<&W)dÒ·Áo–­ØàæŒwø&TJE\l̶õ›Ê?-c?—‡^9ÿéð¤šv'Aýجh£uÕM¥io;ûDežª8°ñnš¢°K·ì©Æ79„±*Ÿ+qŸGåw@6 ZŽ[”çá>_›Œ‹â^Ÿn³ý‡#þÏÀàó«ä÷¼^nólj-T©¤óÇþ"ÖþÞ¬¿·êþFÅí5&Õ$¢€Ô‹ÞßÚ5Ì7‚Ë3ž1ct´ŸW†ß² ³ÛØò9Oíx71Èß›½¿QrmÙÑQUˆèö™]tY÷ˆ6zý›z{£üÖê šÑý}»ñŽ_I}èI÷[yíßµLø¯®žh*F³ôØÎDä>¼l|¤)ï·°§˜Ã\_»9JÎ*eñÖ¿ápÕËÞþ79„•r6ÞÒ<ݹ>”'´.XµÜ¶(Ïýþ›Œ‹|f]aY¶Á„‰ëzÖ(naÀãðJUªzxkç’ÕjnZØ:{}†a¸|aÃ݈H–®.üoéC"j4uÂì¿ÊY‹yB±qãV­ý¦—#¢#‹ïæ{L c`hܶW_"’¥gžÁ’³,Ý}‘¨byQ½¦YoÙYx_€o€aDbqõ:u¯ªCD76ÞT+e óÂÓ9áö.}M¹LBè‰÷2•z‘Y¥Cm¬åé÷„lÛø2CY¢õà6füìm“CØÂŠ&ɑ箥*ˆH–öfaDºm娦c‹ò<Üë¿ÉH°hu¨„ˆ–¶¶Õ.4¶s{µi@ëœò|6C’vîÐ"20©¨.Û“AD [iWtjÐŽˆR¢o`Té©ÉGvn#"¡QIu‰w»ÂD´}Í6§†Sz¬8#û|s–eš‘$á¾úéÇWÇRU¬YÑÖΆ–󊪔“‚R4•›Nð,"àÜÛ¼±Ã®÷\Ù¡ årló›Â܆—aYÕTßX"zsÆGÁ²†/@5Ý[¤ûp¯ÿ&#Á¢72•~¾ÁMûßɬº°†§ûؖˈ¨óØÌ¤8LÆQ훉/²%"¥,.!ªaªןÐÉë1y 윹GÇOÞôw s.£&îÛ{¤fëq-æùFÊY¼À7Äã[‘R‘¤~zÏûUT•ˆÚ s"¢k^¯>W>>¨˜Bú1B¦ª9pX¥/ƒŸ“’oq+T¦½—y¼ý2­ÝÎን1.@5Ý[¤ûp¯ÿ&#Á¢2".Ý‘(òµ–±]¹õËgìhYHý´0Ÿ!¢Gé_4"Ë'"®ÀBýÔ„Ë‘T{:©äDÄprø¦$O °/RtÔ˜¡¾=ì?E‚?häÀÈ s¶xº;9*•ìì±ãu&ÞÅ{|CJy"qy¦DD¬jz`2]ž6©>ÄiìS"Šyv$Eë¶ñÊ}†©ëS4÷ƒ¹®C˜žÇGßln1ÃÔX¿aþb¥–ÅÛÙò˜œºÒYM-Òq¸ÏÇ&#ÁúÇYLD“†eFÞß[ý/{MÖß[zcåõÅ+ñR£^œ¸ÿVñiwô/$"¢)§c´ëŸ=FDÆÖ™÷¾9 ¸Dt_+““K£ˆˆË7ÏÒ ëï-¿µ6üè´Õ½²þ ƒÐÄzÀÀžoÎÍÚ8´…ß9Œ÷ø†ß_#"±yM"J½ü8=ë …,~fˆäóqšk¤~`Sº£Ï!LÏã#µâHDC'ï!¢šžrëHG5}¶HÇá>¿›üG'Xmf4bæþÆwÜ}“¡R*Bß¼Y±v[Ž•"±k£Æþ'§¸sÏîß]gÕ3uùßã*ÑÕeK'y#QÈ$)gs_òŠˆÚL¨­®ÓÅB@D=¦÷OV±lr\ôê%ÛˆHlQ]ŸqVwÎT2êÄ‹©Š/2¯^ÒZ{|%V©xûüéÀ1~DäÒ¿6½<|›ˆê/œ¯9ûðvIi":î–¯–uÂô?>Ú×jËc˜„W†Ã]XÃ,·îtTÓs‹r;ÜÿN¾ûZ87?3ðMóÍ·®Û¶uÝçr¾Õ°AmsN³Œ­ke÷÷ñ€½ë¶u_ÙßVäèÞI£÷/E.^°vñ‚Ï5+4í¼£nf>`fýÙžgÞß:_£ÝyM†aL«¯Ï8×vq¨»#d휕kç|.l;lÞà+e¹çجh Ÿv6D´éD,•.ýùGž,J!z~û˜ŠÊê D÷!Lÿã#_ìøpiT†‰m³Š¹ßü¤£šî-Êópÿ;íôñC£Í† ¹¶OϺÎv&BOàèXtøž/ÎÍYÕ§fn«*×â`[[–UMI=&,žqzjëFålLE<¾PT²\™ÓF=ZÐXsöжZÛWëzu¬^´‘€Ã0qÅÊ•V-›±¢¶™>ƒ¬3|ÂÞá j³0à2\ž d¹²Ë–ü{¨G¼/À·I³8ÜB6vƒ<û¾94ÀœËÈ$o·ÄɈ¨±ÉçŸ!™V&"™$dUL†þ-ë>„åëøøwO;"*ÿw-Ý=æX­[”ípÿín–Åå¾%ü©=$XH°þ(ß÷[„1ü„\\\¾w8þɾïMîY¾˜ ð“Èñ'¯q„_#ÁzûQb!æ!ÊðS‰—(œ­Äß»ÿd¸ ,$X€ ,@‚€  Á@‚€ à†¿ò ð}™»Dþ4?â –¹¡Pý/_«|e"’&ž·uh£=Í?K‹…¾!ÿÏÀ³ŠKÛur«\ÜÆØÖ¦pÃ6}ŽÜÉ×ÖýTþIßÑ>…ñÕñ…ùZ1Ôw޽‰f¶X™Ù{ߎù‘ÃÎïëþÄ‹ˆÒ¤ iÒoÛ`žu¢®®´«?V{šûÆxõpùÿåX*¯ÞUljð\yèéûÄÐàÀiÝJOkQqã?ë<ùåüÅ$©Ósv¾²«z=Vؤ™-×7t›ÙªÆö€¿è‹~<†eÙï×úÛ 1ÏÜP˜ßFVÉn¯«ÃÍu½ªʱµÓs\º¯ŠKŽÿñAÿpq°ë$ã ûËEZùmèÑ>®“Äï_müV›ÿ#ü“ËW<íM Fì šÒª˜vaÐÞQM¦'F¼ÝõsŽò+^¢p¶ï^ÔAÂ%Â?ÒO“;+Û1¥{9;³B–5=Ú MÑ~4þ÷¯[Y{+#ÑþXé’—é“ËZäÖ°S«*eš¦‘;ÛÇ—±6)]ÕSw§ÛÆUv0³µ)ÒiðŒ×EöfÓÞ_ðlçVÂÆÔÒĸl•z‹}‚³×98öD»m“E_ƾhÛGOÏÓ³5Í5,k+–=O¼HÔ]®gH¿B¾œ{›/|–4w)fkfR¦Šûêsá»g5¬TÄÚø‹¥µ,)ˆî9 ® ùßÜPhïØM¥Õ‚JWËÆþuúûQ¢TeÉ®ˆ¨\÷eÏ·çw¶ä6Ú‡^çŸÆ¦f쳬[5uajÄšxË¡E„\=;û´ò½°È[æëî´Ãòð­·BÂC{Ø\hÝfkövÆ5èfÞ}ÑÃиèè°uÃJ.÷옽ÎÎ)CK™g)d8âê%­ôl­n·…Ã÷%¤I#Þ¿œßËÞ³é Ýåz†T;ù°Ž6Û®~;{ÿ÷±‘[F™ÓµFï}É‹ŽÜûüÅÎÒ¿Znrœjêó@êën#̯N«Y~zHZ­•% ôøª#(¤5—ôœ-¹ÉsÀ¯îg¿D8ÀѼÿ“¨z&B"R¤¿²wê}G»‚¹¡p_xRssQ–/¨5Š6]Z™r¿Ú¢ÝÈáˆäFf™çtt:áaÔÔRæD$M¾V´äøèèûºÎ¾©$–&–ñ©éYÊmŒEÉ<&ïÍÏ­µÚ…ŒÜvÜZÚªR–:¹•kÓ±uÚAÈ×€u´¹ñ]BWk1±Ê$ ëc’=L…Ùã¯g5í°ä9²?ˆ¾9¤ÎHû·f¨k/nYòÂÛ1Φ:‚¯}"*¿³%·Ñê3‹p‰à»Â%BøÞ~öŸi8—±Þ(óHÆ9Ë%AÙë42e/<ºëm»‹Îúwän*Ô§Ó!Å2ÆB£ZrÉë› ¹yìèå»oÞ¾yúð6˪²W(&â½MW”ëü[;vpL¹65ýšzÎêç‘–nÝ©K=Ýåz†T;ù°Ž6[[dæò\S"rË¥ =«å&Ç9C¦XgUñ6;#Æþmo”¼ø¨²Õ‡/³«ì4YŽv¦¥çlÉ>³~i?é%B†ù|,×:æbU9|¦çg;³¢”†m޳jo¬YÉ­S!çS=†C9Ñ Ú:Àcè:yáZÝúò:|3Ǿú5Ùô&‡»£.?®gk¶ æÝõ»0®•³ßÙ£ËÇt½ç¾îò¬'ÃrÙ:~.ç¨ôpnmr}&œžÕ´¶A®{ä2ß –.·tØ)":5|Cyÿl~ê9[rmž³`}Õ¬¢d*MzÄ—Q?nf.òOÍçòûdiÂ["âU[VÛøï‘̯wåðˆ›û¦dù´‚Í£Ís¬ocòùƒª#ËØÛ;UÜð¸ÒñÝíÕååFúöÊ8\¯˜eá"eço¹x]ŸÖÖ^‹QßN»$Ë/¹Wë¶jøÿìßÆÏ³ÓÕmË*RÜeËãJ¾¾žÙ×Ýv`Á•É­ìÌ-›þ=·Ìø¹ ;åøÓñ5 4-^È´RÍÆ»î¥¯¸yÅÕ\¨gkË/î Ý:º¢ƒ™z[4ÇþÜÊõܺÜå1à‚í¦üº¹oʺne-ŒŒ]ÛµzZÿWkÞ¿Š­CÉÚê§-Öy†¶¬AŽ•luð© IDATZ͸±gôºne¿r¶èmž³~u?é·Nøb×ïAš|ͱ̼¨~æY„Éð]á[„ð½á=ß%M.»½zR¹A+ øå,õWÜñ‰þïÊÛZZTëqÁ·ÖO;Bü™g$Xzùmò*$ˆ¿¸”Ÿ|ašü8,$X’ÿ×·ÙÈW_¿KHNS13+ûR•k±Êüsrwï ¢.½úb÷,}½ºq<0Dó·í2â"ß܉ MkÖ©Œ•»~3 ~k$Xß]zäÍÀDß¼ª›«“­¹4%êѵkï“¥A×üËttÅ.$Xùz?ŒˆŠx4)n+&"±iášMk'^_¾R¥ì••’÷nÞú˜¤`9b«ru곑<9äέ‡1ñÉ,Ã3²,\¥ž«­!_G9%¼ |ðäeBŠT`lUªrÝ2ŽfêòÜVÁ•J(˜ÿÃMîï$r"*§u5+*Ö¢‰{Q“ì•Ï]} WªX•"-1êÁå;êrÿó7"?&)U¬J)OŽ ½uþ¾îòôÈ»nÆ%§«XUFrÌãë'ž'fè^ `þg°Ò”*"2äé•Û¹´ïáBDÄf$Gœ8qQ% W—GÉ”DT¯m{cvýÜÊ_Ý &¢ Û–±3Mz~öÒýW7Cʶ*£cœ»€_&Ás9© UªBe¢_Ž%‰ {AD,«PVq0º–róÄc‹B6…K•/mÄãè(—® ¢§—?ýÔ¬<å%Q«Ìÿ!“p6àÑó¸ÏD!yqæ‚_XtröÊñÏýNŸ»œÆ5-_¯¥vy1·6.ËX[™³’¸à'w/žy »\ÅfmY¥HÒ½ @ÁüÎ`­îðøÊÛð«më»:2•¥D^}’"ó¿Å/Ú¾N–Ê7¾c‰K–4Hz¦.a‰"bÅ+×.^™”éÑ>>gäÉ/ˆªSîåN¼`‰¼bý6¥í-9Ì—}äÖÀ¯’`‰íÝ*9Ä>»{áø]M’Ãð+Ö¯š½²%SúÝKD¾H%ÏH”«Ìùœ€c{ߤÊ>o†qiõƒÜÊËÔ*|åÅ“«'Ÿ|Z$²¬üW‹ª:VÁ· `þ/71eê·¯ãRÎÂÄËa8<‘¥s­fKšçð+£5Ö°41àpx¦¶%ê·nHD÷‡Q•æœì¬ø<Ãá›Ù8»6ËLÎr+Û×nT»’¥‰‡a¸±m±Š ›VÖ½ @s–e¿_ëo?J,ÄFhê$¤I?åCÒøè° ÛF4þ»pàÞnš §'žo²¨Ù¥‰ÇéÆ}ßðBBºvÉ›]Ýî¸Î|ºÝM Lº´©W»³Þ,ÐQ~?‰ü‡ø³.ŽloþïÝhÍÓ˜;L›OÎ9.<¡•}É®“v¾÷ýGS¨<ŸõÊ`Ó í¢—Ó_I¹õ²jxÛ¤fs²^\ý¤K;±€Ã30oÐoRâËU«£>üº~É3Xæ†BõÍ '=•Ýýf¯sä×Oýôü´ëmvnX±;×ú*e ß ŒæiØÉ±f+ÌD–‹ÜÍ& ;ÚÅ9ǵ^z,ßмĄ/ OÆHV›‰2ƒnP–e•ŒÎúðûyöþWj©¢E°¿¾Æ¯wK“]ey¬ã"c­^ψ‘©ˆH%û0ïµÉ„b¦¹äVòØG+<;uZä­)Û>Ó¿ïw"r]Ò?`æ¦ÜzÙÐ¥Dö ‰ÜáÓ¥IÏ”ˆ„FG}øuýbg°²gTæ†Â|œÇbøÿÖNóÙ\×6æîD~Õ¹"££}†áölž™IÎlMsp6%"“â“ë¥ZœO˜ÕÔ\¤gÏ©Jös_ Ÿa|àwõÇå]f6ö›~‘ˆ.N¿VwF½,KÒ¤êñ)i¡!ÁûVöô™4M½èåúYå'ÌѤHÿޝ0à ýû5â2JöÓVIŒ“àwÅûÓ6زÂ\å—XI“YO3®¸Ê­Ãá™*Ò´ÿ²Œ±EÕ%ó7¼ôO¨f>ås‘ù,šzLÏ~+ˆùÉJ•CD*e"Ã5Ää€| 9·aÎÊ]/ÂãÍ‹Tìò?öî3,Š«‹ø™-,uiR,X@¥ˆ¢XÀ†1Öh,I욘5–ØK±T£±D_[{ì5Ø V"*HPQ-°uÞ‹ë ,¢‹eáÿ{öÃΙ{ïÌ^ÆgwîÞ™ôóÐÎnDäçYÂ<“ØÄä²Ô-%2²¬âwßtž;‡ï0ËU5mÿxµËL—“¢ôQ+²ùæžD$N‹8Ïï¥ßÊ‘Èr$ÝyÑ+ÓDeÐ`F¯Ò“«ÜGIÛç|ÝpÔr"Š Y°,ôÕÌOK6ÎŽ+ãAÛ÷ŠØùD®VËÅ1;– ì:á′‹]%W³uú.:}íꌞµXµ|ch,Å&&k^¯k`iÂáÙŒ\~ ŒuõÅ¡2&X¤3SêíªWm?‡Q²Ýjߥ]ÉÝ^híßiÐ%ó‘GB[²jIP”`eÏZE ×꽞{bªv9«ÒÕ¸ÎþЬÕ„Õ\êíb–î™…‹ÊîÀÍgDô㔞«î3gQNÂ.݇&ÿ¯Xþeľï»zi"~žu57õÕ}m›ðÖ*Ñ,mBÆ·ôÍëÍØ‹óiWKHNù—Òã_{¸ÂŽ6u‹üëBdN ¸ëb5¶4!"¾•)Ä/¿ƒÄ¶,ú;êΨij”½ném,€ N¤R‘9—!"Í/¥XUžvï‘©¿²,Ûaá·ºU´SÝõÕ-½M0c0–\†ˆ T,±* 1\¡f—B|9òß§<³z“Ù¿QÝRÚ$X_ >]ËéÅ<¾U3Í®G'•j¶ŠßtÁ««g¿¶n)m,€Š¯G=k"Š\r@*—D­#"Û†}5»®oN&¢†£¼ß´n)m‚–eß]ë)ÙR;sLó€Ë3©ÒµŠù»>Jñ/ACö,úoS·ÏÈ_ütáf¼Ô³šýØ¢Áe‘,"öß–ÂWø¦ù alb²¾º¥´‰‡=#XFÀªÎ·¬läæÈçpíjúŒ^~P“ Ñ-©‚ˆ[˜¼iÝRÚaëkàßõëá?ÍÞV7xá·yK6lÜ“btçÍž® ðQ2Ƭ÷ #XÂÖ;—qóLâÂ!e*mD%K6?6úæCt,xKã¾° Ž}¬ÝÌŠ™fÝuº ¼|ΛVtŸ0ðBÐqíæ‰ŸÎõô&¢ü';«× Ö)©V>õsªž”¯,rÜ«[ƒÛzV¯bij/´[t$õÅö¯ùÃ|\ìœ\LZ‘¯f‰¨{UáÅ<¹fwAö.[ Á²”çšMYÞYçjEŸxÿÈÜêB3[ c§vݸ«=h‘sо¿°qv‡†Õ«V«Õû›É:§ªþ3h°‡³uµõ',?©-ok!ˆÙ8ÕÃQèÞd+ß4s WU;ûízº/*ýp¶‚kÿ›âSÃÆÙÉ¥ÏÈ$©×! ÁªPÙ•öˆošcY¹L®’’%W‘Zž1?I8­Ž5™9ôûÑöï +O´%Óÿ ñ[^Ϭèĵov)WHx".ˆß6qé_M0yKßë~“bRžd¤ßQåÏî¡—ˆh”·ÝÚŸi ÄÏžçú…ë¦)§4›9×±k4¾HË­,»íVŽDö0í΂!ÕGuñÚ38òþÒc·¦Þ ù’†-º¡ ¦l°ÇñëK©Ïî\ÚQ°eˆnùÉ >—<:°~ÝZÑ}«àËó)Ù™RÇYM´ãµ‡ûrYú†‹©é©×9ü¼Ç\Š€«BeWÚÍ7α~°Ÿà§¸,"ÊŠ ä7™gúb-¸a«zm¾Z[ðçÉg†Gt)ÞÀ’ͳ¹Ø2Dµ»‡¨UMpEèé1í˜ñ¹¾yÀ„_n­!¢†cÜoüz‡ˆXÕóI{žm_ù—øÜø4™Šˆn¯¼î1ΧHË.n‰ˆˆofÓfPXƃ×?æsÒ¾Mª[sL,|ºMMù}&¸6øtȰBS®Uµ&K÷NÓ-?/¸ŸÐÔ½©=- ›;¹§+°òïü?¸Äêü’~ b)õyöÆå3±˜ˆÌ:ŠvÿW Ú4éÄ剨ÓòA±?-SJoÍwíioV¤çöócÏžœÒÝõì±½Ë&öŸóÇåŽÄ*J¾hX–˜Â-%K/ü`˜RN^g]5«–½öp/ŸüÀpˆÁ¥P&òç§ü<ëúyÖõ÷rOÔ™ÀZlàuWg¾¯ª 9À»žfº ÖûSäžà[¬Åá;ÌrUMÛ?^í2ÓEÀÕÝå9î×ܳ?^˾9+N¹¢kÙÛìbkzS*/exãjZ,ßüK¶ßôz6Ddë1§‰ä÷ˆ³s…õ&—˜ŸÔómÛïûñ‹Vm9½"bd›âd¹Çu7weI ÿAÊ3L¬ZjÞ÷u0¿#)LŒ¤™¿—rÎqâ®Sæ—¼ X‘Ãm,yQ>‰gZW#@Y<ŠúíÅÿ…U«ÏgýŸ¬ZyòåjAÎÌ—©Xt¬–ci^o·ÒfÇ ßƒ£4˜Ñ«Hœoé»Ôßjè¸>6­eÊ-{ƒÓ¦4_½óüó|¥Zþüä¯ß¹6 ÒÄ[~ëºgàD¯i 8/R®c=~zÐmt‹âŒt³ Úv6Wª ¢œ¤·p _s.gÑ‘T"õ“{—BMÑ­²¨ÿOw³¥*™èʰj gÍ[ØiÞ–¿Erµ4ëVH¿…úÎyÊ”æ¡Ë>ËWªä¢ØÝ xfn¯=ÜÏýfÝ~"UËE·Ï³õú—"@YDÿ–DDM&ùÑí_NÙ[Ô{{ÅËI·G"npMk¡Ó`}°Kóz»êUÛÏa”l`·Åw}¶rÔƒ©c–¶£=Çéú߯ÖuœœÝæãíˆ*¼½X£wyö½»¶¤û¸0’¨úv¬V¼‘eQ[îo˜Ð°†­…Àw@ÄÔmñšø…m3Wð´³´jóÅd§Ñ‡u«lÀöõ©æ\Í-ðwÅ–Uí4Á:ý·õy¼Å¿¶»ÿþàÍ®U‰çì5îȂݭëØWsñœÈ|}Ô¹×.²²——ƒ‹[Óõ792 ×!Àk©åþ—.âp̓…Yr9¢ÿ"ËUºÆúT‘düvE¤ "…8~SšÈ¾q ú­áQ9Y^t-ù™'+ÆÇQ¤Tw™qÜð¦ðdx*ü£ržÝ˜úYÿ}B×'ßÕ«ùÒ»9¿8¯©#½xôÑí½?°¯Qð±ßÕMÝÖ¿ÿÜøî;b÷÷'¢ØÄd£r †¬O¢Ÿ‹œî5b®QŠfU,—½V b rþµ|R>³ð—øPþýåÕÓ™ˆÚNhDDW–_Ò-`ãhÅå$­ÝBD;×$r¸Öc½ìÐoH°*”Îög}vùõ§Ø÷Ç¿CûÕ¶3¯ãÕú¯Gmކà/ ða°ª5ñOˆ(nê§~žu{&¢œ„0©Î4vßñ7ëü¬?OÞ?¼'Kj]o²=)AyÂý»/õ©¨|Š]Æì2¾Ü›ÅýA€7•ÿxsr¾¢HP%ËX—ú|¢›6Òfœ÷Òqç~žBD^ã?A¿•/¤«Êýí{‰È7üLlb²æµw…?ý%A·˜C«)\†Ý~ÎpxcýÐoH°@¯½Ý'¢Z^BmDèáEDYçÃÕ:ÅxæÞ-ˆÈ¢êH73ÜÑB‚z($×dçQ áËõ±Ml:‘Brc{¦D·p÷o݈Èux/ô[¹Ã2 YÒ‰u³ÃVŸ¿£4±kòI¯©óv¨o]z•w´,V[€J…_¦ÁpX¦Á@Áª°®­4pSúä_¥dKÒ$FLþlÛ7ÍçîOEϼk^ª°¾³ÿè#QU×ÊÝïóUG85=…ôºˆÎx§0‚õQÓ>ýPû*{]¾ïŠnD`×íñã‹Ú–‹HûþÂÆÙV¯Z­Vïo&'éj¿Nýdýw­k{5ÿ~Ìä_7n¿“QÆŠƒ#ï/=vëaê­/iØ¢%–i5`ÑØm·r$²‡iw ©>ªóˆri bÀ$÷Zñ!«7š*~'.îInFB|Ì™“‡¢bîVñî¾ñÈ­ìL©Ø¬sí¦­… ôß'j ‰H%Ϩéú0e]ñ–ý,Ûnº¸¤{£â'lH³ïLJšäH°pmU„K×ã+{vÝq°MrL`é™Ðý¼!—!""•½ÐñiÞÓâ­ež òê±´^çQ¡ßµ“ä;öé×úµ VYš@‚þð•…“ïW£¼ÏkIXtûÊ^Þ6fYb8Eò_€¿—!ð=Waµt´<ò4_7ÂåÙòLë/)Ë=®»¹+Kªy£’g˜XµÔ$UÚ—¶X=ß¶ý¾¿hÕ–ãÑ+"F¶y‹f`Á ›ÙÉo^kåäÖ£ÛÜuù©XN¬2ë¿ë«¦ôl÷ÓjÍ^s.gÑ‘T"õ“{—BMÑ­¸¨ÿOw³¥*™èʰjK~~óH7» mgs¥ "ÊIJàp-Ê¥Y€Š·+¬¦3Žot6õöbSµ^“þcæìÞP³÷¶™­x.Qs\›Œž˜Î6ÐVÜ<€íëS-£ÀÄ»Í[þlWbãË¢¶Œ1¡áØ»b™’õ˜º-¾\š¨0É*5ÉÝÀ9Xw÷/?wíÔ§öuš Y=¡gá¬;þ4lÞï)™y–N®_Œ‹ Û¦ìuõÅ1 @ÅO°Äi›<|&ÈÕ…ßÚ G°äZÊ75­ò37n88G¡.Œ3ܧ’&ùV)K]}q$X†Ã,#paR˜\ͺ]y/3}ÉWV-‹˜tŽˆ¦wû!G¡ž¿ÿòÃgÏ.ZʲªÈËXW_`T \yJDÁ¡ý¬L…. ¢ì«[‰H"RÏcˆˆÔDDŒ‰¦Š£ÐÑFXJ]}q0îßX‘œˆü…"2±nKD Q …ü5wè¤ÝšÌ ""[O—ÿYƺú† RÈSª‰È’Ëõ$"µ2—ˆ¸æUDD ú57á™¶¸„ˆDéËXW_`T ƒMvU–ºúâ`8Œ`@¥c¤ÊyŸ0‚e Œ` Á@‚€ ` Á@‚FC–sÄÑFèh#t²µ½&Qhã…A;‡éË 2ÿvM{kÍ.t,(YÚ¡HÍ–U-<•Qd/«–Í>˜¦ÝL?:½@Å¢Ó`@iŽF$Q˶Dt}áá"{ë˜ò®/تÝÜ1ï ÏÔ† ôRÉÒÃSó8\‹#ÖyœçÉ ÊTº‚š;ŠÒ".æÉ‰H.ЉLÍsô›‹~« ûèî•¿ìÙ»}ËžÛO:—–]ðñwÖÎß7íü}Ó›îxϞݜ+Q©­ÝfÖ²r™YßV­Í»úD·€H˪ìH!¢Ô!J–mì~3úëîùýç.ÝÈz&R(Õ*EÁÓG÷bŽï¾m 9––èqJÌÉ¿pÀGèÊ¢óDä؃ˆºûÑÅ9çu Øû̱æqn-[KDë—Üäðl‚}ª ßÊÑxsþ£ ×Rs9|Û&mÛÔv¶•‰2¯GG§åÉnEÇy|Õæcî¬~C¾Õ¾?zò,ù—´ àCb•‹þÉ"¢sÃ}‡Ʋ¯†ˆU_YrÍ&ǤêŒú¶3omØw¯Í¦L‰½w¸#³†Œ<Áºù¹´ëäælNDæÖÕZtöÏ=—Ö Q#m™ÜÔñ7sDr°J=ŸV5­5qÍm¸O›{Ä^OVðm›wîl–qåâ•»*ï¶Üª˜¾QmV¤»©yÿY»æ—¯þ›#–™Ù8{·iWSh¢[L{7°HDÛ`Î׮ܼ“#’™XU©ïÓÊ£–&®ÈK¹x5ëYËð,í«5nÝÆÙ‚_ü|ÞšäÑš[Ry‘ ² =,)w®‡­6ÒyVã™CNDD¾A]Ðoå뤫ÿIDäUÅTášÖù¬S@M§Âµ7 ²®œ<åi^¾šUå?|ãìþ[¯Þ=<}ù¶D®”Kž\ŠŠ>})QªPÉ$O¯ý}ùMË”âøÙËÙyR•Z%~ö0.êÊ}ÀüG±'/\{š—¯fÕyY7ÎHÌ-<ÿ¸çe?W©YµJ‘—uÿâ‰Ë¸ |%oØFD­7ÞÈÊÍÓ¼â¶ÑÑE×t‹9·ŸÍc˜Ü„\†Ã pF¿•¯0‚%Q©‰È‚§7·Kºx›%²®ëÿI³:éqÇâ“sîœÿ׫wSmZ­{úVÉÝ»ÿ¬B”^³MÏ&vÙû\TËè6R–2¥°ªÛò“¦õdãùWU¢s3¨¤!+]wc’‰ÈûÓ^U­Å™‰ÇN]¾{!Õ³»eÊUDԺנêV&Eĵåbë)DT·‘6bÓ°ÑÙG§æ¨©½6È·hüCuËUé"«=Íùè·òõF°Ì¹"+ÕzSo©‚ˆZ7¯/à \›JDJé]Ý>µlùVµ ß×´X¹Ë*Þ´Ì %œI ßzGX­1±jù}Àÿò•D”pzÿî?¶;u™ˆ¢;š]kXÑ…;Ž=våzb)ðäâË¿?–Q€@4µëFDrñ•µbÝÂ~t'"÷‰ýÑoåîŒ`¹šñnˆä‰Oe~NfšˆRzûä…¬kî¾Hú"*qYYS£ÙKDf†ˆûve”,ñR+Ÿße£™ëǼMF¯.vÒÚCÔiÛC}ãJZf¶Tü4ùf惒Þ=šá*€òbbÙ<3§è÷š‰°MVnžæýèoˆÈ}Ôé¬Q/‹eéìãK°j6«qãLJúßQΟ´©á`-=¾ö÷‘Hw‘_ó‹–DTÛŒG"¿pùNûfuÒâOÏ£|ÏÏaj61óy'³×Î/À¼®†ˆ%’(U\™ ^ÉÞj›ñ’¥Š†Ÿôp¯nÏ)ÒcâæãïæCªüÇ{öUäÝ&B‚€Ë`æÕÛ6ªñäFúÓØ“ûcµ‰ÃoøIÍûúþnwN%>OŽÙ—CDÄpÜ[{–ï9¸šóïˆå‰§ö&ó6÷I-x±R}xûVS»Ö=»ÕÓÝåáç–|æöÍ¿Þ|1µ÷éùY"Šß÷ç=ñËŽ<+wÍüŠ "ù ‹^0Ÿ|Ѳ©—ЂËa8]ËéÅ<¾U3"âðì¿ùõ@ÌÍ‹Wã#gwû¯@%¶)c]}q@‚P)ô¨gMD‘KHå’¨aDdÛ°/MïõiG_¯mñéjEÞ±åÔ,ëÔ¡ëꋃá°T:Ƹ–è¿MÝ>_ ³f•`ÖÉK=«Y\ î2n÷ËBy¦®kÎnhÁ'"ÍOc“õÕÕ'¬ƒe0Œ`«:ßþ±"°‘›#ŸÃµ«é3zùAM&Ôlöö½ÛØšó¹KÖ½—ìÿK“]•¥®¾8#XPéãÖ{†,a ,$XVÒ‰uƒ:6©akîìTã³þcOÝ}þANÃÖBPüU^-ãšøà*Ñ ôk+ ©»æ×C›Üªq”â{×¢—|ÓüÂÌ!½j¿ÿ“É‘Èpñ Á2zßÎÙô‘¨ª ‡ˆˆkåî÷ùª#œšžƒBz]ÄuåÈ(o¾Ým5¾ïŠnD`×íñã‹Ú6¯ýoŠO g'—>#C’¤JM\’vrTï¶u¬í…Vž[ÿ¼'ùEmõîEc[Ô­ê`kתëSé’qö¯ùÃ|\ìœ\LZ‘¯fßô£Ålœêá(to2ª”ÖôŸÕKg~þòË9‡ˆèþ‘¹Õ…f¶Ç*Níº >p;×=@…'~Êϳ®Ÿg]/÷Ä_jDTlàu7ÿePUà]O³ ]WI,ݼêr¬_§~²þ»Öµ½š?fò¯·ÇßÉ(RàËeé.¦¦§^ätòó4Á)íØ\|õþÓǬSoÙ¨¯4ñ¤ßzßðü&êæƒÇYÂÛm?AOÞÒ÷ºß¤˜”'éwFTù³{è¥7ý€“|.=xt`ý‚RZÓwVZ#-Íô×ìω¨Õ€Ec·ÝʑȦÝY0¤ú¨Î#pÝTx¢~+ü?«Z}>³È^V-<ùðeá3óe*VŽŒl¡Ñ3ª²Ïgº÷$7#!>æÌÉCQ1w«xwßxäVv¦š–§]ÍœUß–ˆdyÑ5ëM}üør±ËQj/´&Î'¢]íBîd;ò‹f¨ã]í~ºídÂ!"…ø²Ký ÌŒã¯ýÚ`k!Øý0¯ƒ ì­éž•­… G"‹[3lÆO£–Ñðw°l»éâ’îp¹hT†…F·tmºêþó&“ü®.µ®ûÓ‰ƒßiâš1ª¦Ü\û§¢¦j‚ëºønʲUÜ'¢ØÄdÂB£«\ˬ»7kæNÔ¦cÏQÓ>¾²g×ÑÍßt[‘¨ÙûCkÍ¥ŸB𤭕zaßÞÓ±÷Rî%\ý‡eÕšàÁ§ù+ø%Œÿí{š¿ÕÖìeËðK<“R’ÂkAYZ+ñ¬ˆèƦ1ßo;Qã‹ /Ù9Ñ«G‹³G…~×N’ïØ§_k\÷›Zþèé"×Ó¶ˆ9ø}ï6mÛ¸Ù¼œPÕÅÎT\R’ÕÅÖô¦T^^ŸW_kúΊˆ¢Ö61­¹qqƒ¡iƒõ|Ûöû~ü¢U[ŽG¯ˆÙ×=@Åöï/—ˆ¨þ˜ÎDÔvB#"º²ü•/ ¯@+.'ií"Ú¹&‘õëe‡~«¼ V‘ŒêV“Z9¹õèöwF]~*–«Ìúïúª)=Ûý´Z[àç~³n?‘ªå¢‹ÛçÙz}¯ ºšòvžþW¡’§ßˆÛåGmáiÓü7F'ä+Ôj…8fçt—úà ãSš¯Þyþy¾R-~ò×ï\›òaõµ¦ï¬ˆÈ„!"rü§Ïß#÷fJˆh¤›]ж³¹Rå$%p¸xR:@…ƪÖÄ?!¢¸©ŸúyÖí56šˆr¤:ã¾ãnÖùYž¼xO–ÔºÞd{îR¹,M^¥y½Q­¦3ŽoœÐø÷ÐaMjÛÙ mÛ5îYÃ9;Ç7Ôˆì£ìååàâÖtýFGŽhVI ÿíXxfF÷ª¶ö‡Îó˜z@[Øcì!Çè¥~uìœjn~üGô MÜsÜ‘®ÿml]×ÁÉÙmþ1ÞŽ¨`C>©¾ÖôÕKŒ`ñ¶‘3ú¯$¢eQ[îo˜Ð°†­…Àw@ÄÔmñ¸î*°üÇ›“óE‚*YƺÔWž_Òfœ7ý<1„ˆ¼Æ‚~+_Fö+ÂwGóû;\•AÅþáíˆC×&ú†ŸYýYá/3Nùb|Lõ.›þŠh£ùalb²RšÐì Ë2Þq nf<í.¯ †ñ@€ eï_÷‰¨–—PzxQÖùpµN1ž¹÷@g "²¨:ÒÍŒ‡~C‚%SH®ÈÎ'¢—‹þ˜Øt$"…äÆöL‰náîߺ‘ëð^è·r‡[„PéT†…F „[„Â,$XH°àía:À{‚™ã•F°ÊF°Þ…ÂhÂç ð÷2F°` Á@‚)UAJsg;G›—Ïr¾»iצõªÙÛ5lÖ!òÀÝké+S–ºðð,B¨t>Ô³ ŸäΪò~îë~ú!eåæ‘8m“‡Ï¹ºðÛœá–\Kù¦¦•n-}eJ©‹Iî€qHÛÿ]@£å?Ñ ^˜&W³îCWÞËL_2À•UË"&+RQ_™²Ô$X™oǯ&Š/;¥üãÊS" íge*°pe_ݪÙåh#ÔÜIÔW¦”º€  R¨îÓ)|ïµðï|tƒ±"9ù DdbÝ–ˆ¢˜"õ•)K]x;˜ `®Fï)ÌSª‰È’Ëõ$"µ2W³K3I«”2¥Ôa Àˆ y IU,±*1qx6e,S–º€  ÒibiBDÿäɈHžCD|aË2–)K]@‚Pé ò´%¢ÙÁ;Å2ñþ…!DTÅ÷ë2–)K]x;X *ã]KCóÛ@Í«çI«øÍÐYËÊ4üzÊ`KÝbúÊ”Rë`#XF̺Þèè­s›»W5áp\›ÎÚtA“!•¥LYêÂÛÁT:Æ>‚õ`Ë@Á@‚€  Áøh¼óŸø=“*ÑË€«ÜäÜODÀǨJÓŠýùd9G\ê "†áOÏjlÁ×Ä5«2Á©ô oó 2ÿ¶k ¿K:ˆ†7ÁjÚ´)ºàýK;©yòª…§2vö¬¥»—UËfLÛÓßU³™~tº&»‚ò‚9XÐшD"jÒ–ˆ®/<\doSÞõ[µ›;æ]ᙺ¢Ó`€^*Yzxj‡k±bÄ!óÑ-àÀ²ª;Rˆ(ugˆ’eÛû£ß`€^W'"ïÀDÔ%Ø—ˆ.Î9¯[ÀÞgŽ5skÙZ"Z¿ä&‡gìSý† ô`•‹þÉ"¢sÃ}m„¾OQöÕ±Î4vŽIÕõm%™öÝÛ³)SbëâÈGJ€ ôÊpL¶ÄݨoVT$·oö™LÅRIë—Â[À@ô(ê7Í–U­>ŸYd/«–Gž|ø²ð™ùšì ÊË;ÁbšýP<ÈÆ­}ñV}h爃ññ©ÏòW×Ú¿êÔÃ)©:Ã0<¾‰ƒ£C箟®ý¡µ ó²€NƒEƒš÷ ‡w%zEc3®¦€²à‘0`N¾šÕ­›}jê†èóIOd ¿fÍ_öìüó ÆÈ@ÀEÿ–DDM&ù]]{û—“Ôù;ݽ5L¹·W좞S5›G"npMk© î£ßÊËÎV‡ÌïvôTbVn¾R&•&&Ü ™³¼ièß%fYV!—e¤§oZ¿¥ýêÿÞè@¬Z9åÌSíæý³;òÕ¯¤ê×¶ýÖpÊÎã·Kj¥\–’|oiøê¶«0L ÆG-ô¿t‡k<(Ì’ËýùX®Ò-0Ö§Š$ã·+")Äñ›ÒDöÑoÆ—`±qku_š`ÚÅ-cŽ<äò¬BB&<>»ªàìÒ“sz8ó9Wm›[¼ºúòå?+NNoADñ;v¼Ñ Ôpâ×\Ônnþõ>Oà¨[ ßÊ«D´fU°øŸ5Š‹‘çv&¢ËÛ~Ç%F'÷ö²|•Ú²Öøê–ÕG¹Y«Uâ•7Ÿêh<©%˪V¼OD†©X¶ù¤¦è7ãK°J´uÉU"ê0kÚœž^Žæ<¹UÇ ò"¢¿~Ž-^ža._ðé—ˆHžŸþFÇZÔP˜÷èx´XIDrɽEó}¾Ô- `Y"нó0WÍòLL[wþŠ[+?ŠKŒÎ¿¿\"¢úc:QÛ ˆèÊòKºl¼­¸œ¤µ[ˆhçšD×z¬—úÍø,¦ÙÚ—6ø¿¬"ZرŠnÉÚí{‘èñùZaÙ©äø®?ˆÈLØðN íX–UÏ:ò„ˆîÝ£dÙcÜt ¬í]ˆ6®ø_íOg ?Ÿ%ÇÅF‰U­‰BDqS?õó¬Ûkl4å$„Iu¦±søŽ?¸Yçgýyòþá=YRëz“íy˜ul„ V‰ÈY"ò~1ñ\ƒoêLD*ùÓò³æ£Ì&w[OD}'ùFÇrðøÂ†ËÜØxšˆ~ÙÎáš/ö°Ò-ÐyêŒuC›Ûr¥,wÛŸµø|Êg󶈬[ÉÏdç—Ÿû¹oCKž8óöË)ÊUm.]–¾ÌÒ²L"âòm‹îójÑèQ‹QÞ%ž’@èøýðÁ÷އ®ÝšˆÒcvãã²÷¯ûDTËK¨=¼ˆ(ë|¸Z§ÏÜ{ ³YTéf†…Ç+P‚5tŠ7ý½tÉŒ¿²¤J¹Ttlÿ¾€°»DÔcš‘Â&¦æm:tŒ;83ÀŠ{lûï-#þÕÄûٙѠ™ûãÒóÔ,›÷ôqdØÿˆÈÜ®Y‘ªûõâ1LÎ])Ãá.jnSdo³€±L³Æ¸#SóMm›Õs$"×—…äÚì|"j!¼üµéHD Éí™ÝÂÝ¿u#"×á½ÐoåŽaÙw;ͨą@_`—LŸxêQ‘¨wç¾7vdôTrëhÕ¡ûÕĬ?¸|˜³iæ•ý5GU¼º¨Ã0YîoS¤…ÀÏ',É,°®Ö-÷@¯"»þY¹¨Õ¦Ô"gÒgrЮA.¸Jà-¤dKíÌ_ºû ÍXN¾~M|ýäÃþd€™ösÈáYŸwðr²6åñ¦õ¼âããÑÅðjÚÏ6†wèÝNr×}ò ÀÇCÏúA婸$w…Bf,ýÃç p‘âÝŽ`Ý;¶¼ÈµðÁ=“*Ñ ðNa’;,$XP^T)Íím^>ËùÊöEÝZxÔ°·­ëÞxtȆ|u ³«ïî_Úµi½jöv ›uˆÂ÷^ ÿÎG7¸5êâ¿÷»¸D”yn6ÙxN-R1V$'"¡€ˆL¬Û‘BSJ ‡ RÆájôžRö>¿³ûó›8\ó­_k"šIZD”§T‘%—!"†kIDjen)q0F°Œ^NÂöÎíF¦ËØ!+N¬eUd¯Ç‘TÅ«‡gSJ`TvÏïììÐqLªŒ´4jé`¯âšXšÑ?y2"’çÅ_ز”8 Á¨ÔÒ›}:ŒI/PÌ>²üû’Ÿ`=ÈÓ–ˆfïËÄû†Q߯K‰ƒá°T:Æ»–†æ·š)VÑ£}ûnK.R@³K[ìyÒê~3tÖ»2 ¿ž2ØÅR_œ°–Á0‚`ÄæxðÚ2ÖõFGoÛܽª ‡ëàÚtÖ¦ š,J_ ‡,¨tŒ}ë=À–ÞÇVÿ®‹×]öÂoózû»jÞÛZ´/;¡¥[=ï閭g+Ôºå_fk!}1³ôc±*q¿¯üB­|<øSWËjÕjõ6ýFž¼ôòF`eÜ<“¸pÈC™JQÉ҇;ùPÉ‘È4¯ìgOcÿÞÛÙúxÇ¡;u9x¢Óâ.§÷—~¬ÝS?=™“¯¹·e@L›Ù óÜ»6Â'¡wûÐÒËA‚EDã¾° Ž}¬ÝÌŠ™fÝuFÉ'ÄT©^¯ÿôÍiG&iƒJibè]³u#6šÞ º+Uê;JÄØ^Ï»Ì-ŒŠ¼Ù¯wSsÏ̶ýwÓsïDH_Ìæ+±<€q$Xî^:®Ý<ñÓ¹Þ¥”W«D|3íæƒƒ“mÚ…Û˜Ú/°™~Hïl¾;í– ïÚµHð`–ôSÍ{ž™'˪˜RËG‚eå2¹JRH–\MDjyÆü$á´:Özr+Å“Ôëá£úôY¼VÛ8;îÛ°"j6,~ö:}GYݯnñà-©¢†€[øiyÖD$à0¥”0Ðûú‰Ãöü—õ[+ç¬Ø@~“y¦Fw¿­Å+¿V`îà®…Y‘,çèIÀCWk"ºÍh-¶;‘ÚÙÖ´ŒG«Ø—Çbø Ã`i x§Þ_²ÑtvdzAQDÝ*¤u‘½ÚIîÏD’û©ÉÛ–Þ3ý'Í®;¿†6˜6W›"Oõ^°úvÙkÉeTÚ•(X1&ø«@æh#Ô¼œl­«98¸»{[¼[ýê^';‡©B[E™»¦½µf:ÐÈ,{ïyª›³žH‡&Ìnê ¯Ãá \:[ZsTY°úNÜL_í:­g]ºûkhÙëmÎÏS^WjU.õÀ_*–e• YÎã;û*ìê+»Ô²ÙÓ´›éG§¨Xô˜Q&X¾Ã,WÕ´ýãÕ.3]^LŠÒG­Èæ›{‘8-â<¿—v|+G"Ë‘tçE¯L•ñ¸½-R x¨,HæòñW€ /+7/+'÷AÚ½Ís?'¢Ë¿êî­cÊ»¾`«vsǼ+#æÿ¹mLƒW¾þMªÎ¨o+ÉܰïÞžM™[G>R‚ríyt@Å£ˆ*EçYg98tùuA•/¤«•‘sûÙ<†ÉMÈe8ü gt,0ߢñÕ-‰ÈªÆDOs>: ”ƒ?º‘ûÄþèŠr‡_@¥S±EX.ð+Ba ,$Xðö0à=ÁÌñÊ#Xå #XïÉÝiÆrªõkºàïeŒ` Á@‚€ >:©ÇWëÚ²•·{÷Ïúl>q¯È^µìþ—Ýý<ë¾QÝÒÛ„·†g@¥ó¡žEhÈ$wiÆŽ.‚äêÂom†c2ãÄ¥ÞÕ-5›¬J´î‡Ïþw!“ˆb“ËX·”61ÉÝ@Á0ñ¡«äj¶NßE§¯]ѳ«–o ÕìʼqlÆWí7þÊsþ“êIDATóôMë–Ò& Á¨øÜ|FD?Néi!°ê>s&å$ìÒìêÕÿÇè$qÏ=EªøyÖÕÜ1ÔW·”6 @Åw]¬ ¢Æ–&DÄ·ò#"…8^³Ëɫݬ §fõ÷zÓº¥´ H°Êª×ÅëÏ ^øm^oWÍ{[ öe'´t«çýÝÔðl…Z·üã Ãl-£/f–~,V%îWÃF7¢V> ü©«ƒeµjµú ›~#O^zy]º'¦}áÚ¨TD*5™s"b¸DĪò4»ìÙÐÓ¿zñ*±‰ÉšùXúê–Ò& Á*«Œ›gy(Si#*Yú°ù±Ñ7j#9™æ•ýìiìß{;[ï8t§n#‡OtZÜåTàþÒµ{ê§'sòu#÷¶ ˆi3;áaÞƒ{×Fø$ônZzù"´'¦}áÚ¨T,¹ ¨X"bU"b¸BëÒ& ÁziܶÁ±µ›Y1Ó¬»Î(¹_x‚*ÕëõŸ¾9íÈ$mP)M ½k¶nÄFÓ;Aw¥J}G‰Ûëy—¹E‚Q‘7ûõnjnÂá™Ù¶ÿnzîé‹_m”X@W >]ËéÅ<¾U3ëÒ&TÀë­o“¹Ox!è¸vóÄOçzz—R^­ñÍ<´›N¶incj¿8Àfú¡újÝi·lx×®E‚³¤ŸØ˜jÞóÌ‹×jcgÇ}@Dm†ÅÏ^§ï(«û•°ÈÛ-©¢†€[Øé>sþ¼ËpßÏö+½ŠöW„úê¾E›P1¬âÕ›åX ?ØOðS\eÅò›Ì3å0EZ+|YYÖoÐbñž$Ƥ0+’åÝ ˜äjMDB·­ÅkOä”ýÈbûòX ŸaÎ~ðg¸/ ›;¹§+°òïüߢõ·¿ªÏVÿ¹¨Eݪ<†jwQ«$øð‘°ªóí+¹9ò9\»š>£—ìYÍÂÀº†´ ¯É8Œk%÷Ó©2Îø¶µäHdO®Žj3¥ÍÓC~oçò÷¢Ëë[9kâښ¬Z)zúèŸ}s¿›'Êx°ˆn,ð›bõ¿“ãh ÜŠl;ZòKô¬Æ¥N»YÛÚ,97Ÿ§I±X¥Ðî™(¯”òeÜUChv/7_À)Ú¬­… K,ã3%· û‘Óó ,¸Œ6þT"ã”á¸FÍWrϰ’»*Ýslì½ç©n6}"íšPp¦©ƒÞÄ“Ã:¸t¶´`rMMdÁê;q9¾¶3_–1µ ¥YûÊx\os~žJmÇã‘Z•«ù5l¹ÐIÕ¬úe>ÄgôUPèni³+ ,Œ`8#û>-> ò¦C,¾Ã,WÕ´ýãÕ.3]^LŠÒG­Èæ›{‘8-â<¿×« %tçE¯L•ñ¸½-R x¨,HæòË¥CºØšÆ‰ {@™ŸR–*²Üã¸î`éͨÞîVÇ ßƒ£4˜Ñ«ôä*÷QÒö9_7µœˆâBÖ, }µóÓ’€³ãÊxÐvã½"vþ#‘«ÕrqÌŽ¥»NåÒS¦4]~ðY¾R%Åî^À3s+±˜9—³èH*‘úɽK¡ƒ¦àº@‚UBŽeÈb›UÛÏa”l`·Åwig‘Û ­ý; ºd>òHhKV- ЬìY«HáZ½×sOLÕ.gUº:×ÙšÕ š°šKÝ ]ÌÒ=³Ê¥+¼ÆR°»uûj.žó™¯:Wb± Ûf®àigiÕæ‹ÉN£ãºx§Œl’;€á0Éýµ0ÉÝ@˜Ó PÎ0¼P¡h%"†a8\¾…cÛSƒÆ~ÎÑÙËpL¶ÄݨoV˜¨ ’Û7ûL¦b‰Hó|h0F°*&–eUJy^vúá•Ç®¾ùÊ.µ<òäCíæ£3ó5Ù Á½b“coÝ={96lj'"Jøß<ݽ5L¹·WìÒn‰¸Á5­…NC‚¯Ãp–ö߆‘Bš »g¬OIÆoWD "Rˆã7¥‰ì¢Ã`ÀëÉDÙo˜BD|ËæºñÆ“Z²¬jõÁûDôð`˜Še›OjŠî*G˜äPi§ºkøŽyeýE¯@+[hÐÜk9\ë±^vX&±a  Â⚘9ÔlÐ?põò¡î¯|ýóp³ÎÏúóäýÃ{²¤Öõ&Ûó”'Œ`T@¯]m¡Í8ï¥ãÎý<1„ˆ¼Æ‚+_HW*#‡VS¸ #ºýœáðÆú;¡C`€¡xæÞ-ˆÈ¢êH73ÜÑB‚å¡û·nDä:¼º¢ÜáaÏPéàaϯ…‡=#XH°` Á€·‡èï fŽWÁ(gÁxO ™±œ*Ÿ/ÀßËÁ@‚€ |tîî_Úµi½jöv ›uˆä/’'†#Xr-囚V§§6þrnIÏa{£Ã;”¥®¾8a’»Á0‚`.L “«Y÷¡+ïe¦/àʪe“ÎѦ‰Û‰¨íìݲ³£6"¢¤?'”±®¾8 Á¨þ¸ò”ˆ‚CûY™ ,\@DÙW·Q¢cMk³ˆ1Ly& {«’jª8Úm„¥ÔÕÃáþ€ˆɉÈ_( "ë¶D¤ÅÑÖ¨‹Ú2™çf‘çÔ2ÖÕ$X•BžRMD–\†ˆ®%©•¹ºžßÙýù€M®yÈÖ¯5‘¬Ü¼Òë¾¶Mxk¸E`„<†ˆ¤*–ˆX•˜ˆ8<íÞœ„íÛL—±CVœX˪ŒuKo ñÎG°žI•èe5±49SðOž¬“­©H»·yîçDtù—@ݽuLy×lÕnî˜w…gêŠNC‚¯ÃpL­ºŽ]CD É5Ý=AÍEióäD$ÅD¦æ9úÍE‡!Á€×+ÈË:9‚ˆL„­tãþ!,«Z°#…ˆRw†(Y¶m°?º«ñÐO‘éê­ênÚû̱æí¼µl-X¾~ÉMÏ&اÊôZùÁ@…ŘUuõ1ÿÏmc¼òõoRuF}[Iæ†}÷ölÊ”Øz„8ò‘”kÏ£ *ž¬Ü¼Ò tžÕxæSC'‘oPôXùBº P9·ŸÍc˜Ü„\†Ã pF‡ ÁCñ-ÿPÝ’ˆ¬jLô4ç£C`@9ð£;¹Oì®(w ËbåV€ò—’-µ3e®³B!3–“çóø #XH°` Á€·‡…FÞ̯<0‚PÎ0‚ðžÜ}f,§Z¿¦ þ^†À,$XH°à£“z|õ°®-[y»wÿ¬Ïæ÷ £¬*jýœ¯;û·jàÞ±]ç9ËwÊÔlYëêƒð,B€w¢ø³ ™ä.ÍØÑ¥SüEòÄpLfœ¸Ô»ºå¿+û[¯[²v¯•;w-K]}qÂ$wƒa Àć®’«Ù:}¾vuFÏZ¬Z¾1ôÿíÝ{\LéðÏ™i¦šL7ÊeWÔ²l[,ŠðÛ¤°…EËÞX—µiY×–Rm I.¹¯u[í¶…,‹¬íºIBkÉ-¥V55ÓÌœßCF™é¤”ô}¿ææyÎsæû<ßéÌ3çœ9'@ä©"#ÝIk¢3.Gí^àFÜbŽm5•š`B!ÍBì…¾šçf +¾h€ÂŒHþû$¤]ôÒMÈ(J‹ Åöª&}ÞêÔç­NZÚj*'uG×Á"„Bš€s%Þi! ÷PQòÔ‘Á¥Ž½â Ê„âNó¶rl[ã: M°!„WY±B @Äg0|¬â¡úJ+È¥E÷HU%É—®jo[ã:És£C„„BHЂÏ(W°XE)†o¨¾Àæ?/ìYû¹R–¿ËkǶ5®“ЋBy•½m p¶D†Çòb;>Ǹöëv¥Ln¬'°8€´è7Žm5•š`B!Í‚kg#kVÄJd¥¿…0±ÀêÞõ¼BIÀº£R…ìܯ~„âþÛj*'uG×Á"„B^ˆú½Vñ?;†X¦vÍ*]ï£)ní /„ÿpBíÓ|XÐñoÝ,¨~B˜|骦¶šÊA×Áª³~’;c7½z!›Q¥ŠaÐÌÜlÈPçˆéý…ŒÆ¶•ÍÊÿƭŒNMË)@hõ†åÇcß[<¢K•WW[¾j¡ö—PÕŽô]=²Ís7¯òêŠn3)YÞ>îeÊg(¥ýœ½R$ŠU¿¬šm!ª²|ùÃsúÎë0 /åd¸ˆ_Y•qòØü­'O_¹/e¯à6$è£wxúž¹£Op’®ØòÐÏsL\‚WáñuLLMG޵ir/¾ÆT¿Ø\pé,çD(î =ž~ýA#´²ê8aÌ{‹]»2OG¥%ïÚƒ©âþ¥óOãM-‡DŽÔòï =Ñ5¯–|Ýçä”.‹\ím)¢M!M—ØrÒî°ŠïVo¿ôOøu›ñóV¨fB&¶_íZÅ_¶3ëF‘q{ëQ_øMs³àØVS9i,ŽX–­Ioçæîز3[Ùî–\­ôþn~ÂíÇOåY}3.8?1Ù»_=Æ´öìà¥=DüúZ¡±…K¸]‚gjθ_îso ó§É¥ò×ì&TŸ]ø÷÷„Ç£¤ôI*<âÜJõôï½›{¬L{¼”4çêµUÎ.øÃ³Sõ•œ‹ÝÝ78I(jóÓ'SA­V*ä÷ó¶­ßt:ÓíŠáB¦rQ«Îj·Á/`Fü­ÊP/edúedþš>á/'Žy¯U0AÞ'L p©10M‰æ2¼ZBš½|@ÀøøPß3Þ»Ñ&&ÍÂeÚf—iÕË­†zlêQ½¼òW„ZÚj*'Mc‚U}/N•*–e•rÙïÑ»¥¤ÿôf,¬±íÄíónóuÄ>Þ“=½i„²SÇN|º<>%ê‡#mW¼-®—ðÈeù£']_Õ_KCM;«4ù<ðãCÖ'®Ý|w´¯[8vý5O¸áûþÏ\8ú‡Û=ß<µ.;}ã98?ú¨v? `ã:ßOz¾¦ËJ“OÄýÏ;!uï.xúWYCÖ‘Hû€Dž^Ûýûæ1rï;›–-/+Ë8÷÷W>{’OÄŽ>hçjÞð¹ÐÞYyfçŒø[ê¡&þ~òÓ€¸³÷N}ÿ-}Œ¹äûÈ—œYyS¢ohó}—5öQS¢¹ ¯–Zv9Æø·¨ËQ'Kœ´ +³BHCxYNrg†/Ðuþ`<YY.—&?®¼`÷‚%nÖæ"]‘x°«kâbk;ÏÕclŸ·Ó»‘øcÀ¥’z\§¾q·HWóв[cvç¦oÛx¹\ÑiÄ®ÆÏر¤ä–ñxºÛÝ'ñ™ÂcoÊ”ªª –|ùV‘’Õêõ2†M‹®úŸs"º‡ï1V`¶k·—[[ÝçÈžHd×·_Lh_§7þÑ(¹àØÙšß6+ÎpQ uÐð§[ˆ Jæ˜wîÁdí; óh·ÿÓ´$šËðjÉǽ5Ë*Åß§M!„¼R,ÆnzåCÃŽ ¶\Rz$r7}C[MmÕ×°-¯@à Vê wt èÆ©ç¯z«×Õaøõÿ)ëóC|Ù^ÈKÙ¼ñƒ7ùBãÈÖÏ\,?;ºDÉ[Œ°2h`i T”“Y¬ªŠÕÀö°m}´êHzžìY;lâ»{.W²–.º[è×¶ïêZv @R˜Z½ªrÁ¥³\¨B]^%Ô£ß;Í1ï܃9t¤ÀÐÌküwÐ’h.ë=$«6²öeÒ&BšË¬GŸ4ö_ê;Î’`Üܸ4Ì•³ÞÖê^[å·ê1B£öïþìÚZòàü°­×ëqµ:zíb¦YÊ¥ù·dÊÞSgtÓö9^)Ùޙր댎N®Ë~4E›¿pÓD{>#—íÝÕ{ļ÷âïT<5è6'¶Œ/n-à];y_Z§€¦òÿ%\:ËÅ  À¦j¨m(dóÎ=˜¨¢ î&ÂÓ’h.ë=$‘qO¥ùtWBi –:q[ë ùc=˜qiÛAÀ»"U\.Wت}ð(*ŠðxvÕò™‡ VÊB·ò¼le†§S«ð†3«çQ¿¤-a‡Æ×ã°tÿlÖÍý™…†S.þû!€ã>‹ŸGey£Š•vbž`ÚÌ©ŸMtÛµÿ¨ÿöÓ¹RÙá蘾¦×W;T®à!ôW¬óuÎÜÚ#4ËcÖÁ±{Ç0Ï•ŠŠ"|£ÆÉ‡ÎrÑNÀü+cÏ•É{«ývZVž €/4åšwÎÁd•+Xëñkè£ÖDs^í!=žÝ¦M!„4—=XlZ„ôôêÄ q¶-tJîfŦæÈ¹í•˜d¦ `iÚVz,xèšDvhßú&.DÛQÈ*‘W¶ªÞÀ˜Ô*H¾°å¯}• ɤY‡ësôùN|6×až¹@ÉýãçËäU å²ß^—T>Õ54Ÿ2õãkGü7zô›ô³úÂKCýæö4ìþ‘çØVºW&/xîh‹nž 2é݈¹ÐÞY.&›éX—§^xõp4±yÿZåK0ª¼ò˜¢Òžh.ÃË%$†áÓ&BšË €POô?—Ai9Šù‡÷íêz‘K«OæÙˆY¶=õ¶Ó„þ©bßtþÚ5ì<€>ST˸› |´(&-÷¡’eÜ[¼ €È´Ö·°püÄÏZœ—y°!GæòÏp \ƦE¨9Á]ÄDÜ`çèÉØMŸ›U(U ôLì:›«OÚT|úš`xÂk‡ófŸÿúŸ:]‹I°Bžs)cêìSzMvh”\pé,çÙ8²baTFžD.“މv ÎàºÀcÞ¹£:ò›Q¦¨K¢¹ ¯öTG" ÚäÒôy«“êá`ݹŸ­õàw–®;¨|ºÖámëlµïuŠò«Ž6UU4€õâ%úͶPüzdøð¶cÒ÷„o›°zr½G_»«v­:ÂbñîäÐawfÇßœì±D½¶UWǘѭUOùÖiÉ—‡nžI°• ö=ž™âãôÔ7{ /QÅÂ5Æ®+RÔ*+ç~HÀ¦Øûºtyrq,Ó.í˹F+ñÖZ÷×ûí¸¾véêµKŸ49cÊ3WÕ²ó{Ûžšx<÷ý  Y¾Ý9ö½J­±…ý/£Z?còâsQ«ÎjÑÁqr°ËM¯cw‚–¯ Zþ¤Üfȸýž½/­zÞ¹ãn*L*•ÿT(ë%ÒîDs^í!•ÜO`вmòiVX–UÈeósãÂgßáuØàñä7d¬R¶æè­unTOïü UÐ]^¹=X•̬ßß?² Ë*Î?ÆeêòõRŸ3îãzw0 Ú¶oïí3ÓÃVÌ*‹ãÏç«–hÓsdvø'cì,ÌZy #ÔÙvïâ·ÊÁø9ÂÓ7±=4ŪÁFC&ÉÙR 0ÈðÉåôŒºI®‡æ•÷õ\°Çs`oKS}>Ã×v¶~+$Ø7ò#77˜°ÄÃJ——} bË­òÚÍy|³Öm§}9éZä>Ó(¹¨mgµôfA_œ÷ëÖFz:]½ÎÖ]ý|f[>ˆáœwîÁ8»š8{¿.‰æ2¼ÚC:¿=@§QoÒ&æ#ùÒÕäÌìS©ÉÁóÈØözíëzü¬°Èʧñ¡çùzhÐêÑ«v/B¥¼ØÇwC¼¾ã9?Ê.å¢ÑI S o™ö.M˜Òxëì7`查ò}GÃ?4Ð;“S¿÷"ä®ò„ª§¬¢ØÁ¦Ã&]̬¬ ìÓÚ;%}rFO± ¢$}@ïñ-û„ç%yV6¤{ÖïUëŽ80ЋfW”‹—„Ȥ·—…Hò e™Úïxxäø³TnbñÍ®i†¤Åù'¶Î ha¯^þΜ¾,«Øpà_·+XÖ~E@,BšŽËX½ðXcæs ÀÌÀ!” BšÕ뎽®> ç oõZck/1Ÿw%b'€ý/ñøFžÖ¦4hõˆnLFȋժ«›æÖˆøï]éOi ¤¹â õMÛX9ÿjöÄ.êå<ùô7ŒB²÷ý·Ï/y“®KZêÐ>—¦3ÁJOO§!&„òêÕë?"Vy–&ÿ›i231h¶ëYNô–hJ,»é›hˆ !„¼„juÑœW’Y¿y|ætqÖ OÇÓ¡5½%šÒëÚáÕU~@A!„4º9 ‚ŽÈfBƒ]wJ Ú~ñ†>}X×3:àJ!„4SÃ'½ÀjêHŠz÷b¯ƒUý „BH£{ ‘[µ½èWi¬ë`Õ ºVÑ,B!„š`B!„ЋB!„&X„B!äùÑè„BH¡3ǛڃE!„RÏh!„Ò@**¤M%T@—òU´‹B!„&X„B!4Á"„B¡ !„B^:Ù1!C{un×ÒÔÖÎeMlv•ÚŠÒ¿{¶1576¬U[íë$ÏîEH!¤Ùi¬{Öå$÷’›;ºvÿZ¦|ô©ÍðtWüó™…¸r=Þž}è&€¼¢‡ÛjY'ä^G°ËÄ@÷™F|uõîý1ÙÄ@×ãÌÝêmS#Ã?bߥI»×, °-ö,½!„4Œ?æË”l—‰á×îæ®oÅ*¥¡sŸLχÌ9œ[Û¶Ú×IšØ @a©´ú£_]½6Î+að÷ïóŠ©Ò*j®ã‡!‰#¾YŸ|å^NfúÊ™ƒú¿ïº(†ÞC„BÀî¿ øú»‹õ Ç/_ ÿìª*VQ:glˆ®±K•&æÆ†ª#†šÚjY'i’¬—–\rÉ?[Ó´íz—gKä•åùgý¾>Ô1õôÞ]ì „zFfvÃ'ïJúËxÿçÁ4n„B^´äbC]B£wT'©ªÎ¯{(OâVÛ¶ZÖIêèÿ¡ÍÚ+®Û›IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/production.dia0000644000175000017500000003506310027550273024141 0ustar frankiefrankie‹í}]sÛØ‘ö½Ê{“TQðùþ7ÙòŒ“Mª23Þñdsé‚$HækŠT”=ÎÅþö÷ô%[$hA8hˆzœX–L³yÈÓßO?ýŸÿõûå<ûTV«Ùrñ§—þœÏ¿¬Šõ²Êç³ë|U¾ú¿b>/^…½zùçYöíœë~¶ùi±^W³“ëu™-ŠËòO/OŠÓÕòzqö²~Ôæq§Ëù²Ê>ó?½üóøßËW›§yuçy¾óÜWÅEyR•ÅÇýO]jøÕ婯Êjûi/¯–«YxÈúËÕÎCö<üþÍc6Z…-.þü¯ÕÔ/ióƒ¯ÏÕôB÷ Y_ÕÅl±+'¼7óúà7oÁßýõÙç¨Ï^¡>ûlõþjY­«b¶Þ•p²\ÎËbQ 9/櫲» Õi1÷éç³õzÙÓêߪÊCÕ}_ëî6häÉ9üê&c¶X´q7¬{˜ˆÕ‡åç÷ ai“Û[W×e7)õ%z_g³ëÕþÏ"¸‰nÏUœÝ vž¹ãû³._¿¼ÇÂo=fß;£Ú;Û €÷„¿ßq8ûb˜åbÝ$~ž—³ù—ðzŠÅêe¶ZË,\ýOÿVÎ?•ëÙiñ­ø+ØÑºÆÏÄ¥ ¹kk›l“p¹Õ~K“´­‚jÈâi‚Bd{±¸,›?¾rq}Ùß~/ iò©ûâ‚W_=â>ù.øš³¢: ò7¸ô».’§ºÈú#Ãô‘Bç.úH£§’‡ß'<ç#0/²·ÕòìútÞðì]Y…÷ž,ŽÅ`d.î3·' 1J¼’«5¸ù›ìC°›;³^Æ8:ûú·w’«›W°õ¤mlÓ·áûÛª<+Ïg‹ò tæ´\­L•HŽæuˆ|e×È¢]<¯!ž—á·)·¹cÎOt0V–sÔ>é`­‚ú\hçf\ŸÖùmjx3v~ÎØ!ÞçóÙÕûËjöï`È‹ùw¥lUµ,&(¸4!-‚|©¥Öòð]ù±cäºûvÝÜäFx5Qy¸Ú ï#âÿël^®¾¬Öåep«]ÎÏ‚ãØu¥29êçÈŽT°Ü‹' 1 Až ÷Ó‹¦œ©µˆÞS’ß$¿yx~óÕçòäÕ*¤¾³Ó’äC{Oƒó †"çÙ‹óü&%ý©¸XÀ=ÉÞÌV\¨Ju¡R„NÜ)uöîEƒ …L¥ ’,N”q%P³Ñăµq¥*,-§¾×¡æ¢ûûDn•Ü*¦[½ñ¨äOûö§Rå†IrRg•§œ´·ús¹þ¼¬>§úã|y}ÖàLuri7Éâ‘ĬìÖ¦\æœ5á¹3Œ;Ô²nʡڸQ¡Bt£*å]"÷Œ}Üßá™ÃŸ²uUœŸÏN_¬—Yù{qy5/ó˜SEÁûÙ<ø<&c¯]*! …ñ`ÿW‘÷àŠùº¬ź\u‚<¶ê™šdÇ ®ïàû÷­ ÒTrÛ5å&÷!ÅCu¯‰Gkãaå“蛞ŸšUrâ]ú¦Œü4Fç”Cç4|•![%/Ýwñ·•oµýøV†îX}î¿Â‘8 (‡p¬Œ¼ê}^•Ê¿äU»yUNNÍ©Â9Õ!áH.ŽÄòí± D’QÊTØ\ÛàâDŽZÿM<ÕÓÆ$‘÷$ïÙ&é„iÿ˜¤:É :œõ½xи‰\(ˆ¹õ¡6—è>4á\O݉Ra—œhg'º..ÂwäA1<¨¹3ãL´Ÿöëÿû®G~žL0£';á7u)QÈTù\N¸Ãõ¹É‡jãt *ËLg¢™!š¢™9pÿª øWAþu(’™d–øÄ°dÁ§ðUåœìÂó´ ’È§Ùd8 L +$zˆÖsñ’ÀW܈ýF’ÐÎL•ÌvÑ29ÝUò äW§ŸV¨²šïZ¨ßf—åêè×åe±ÂFYtµï>SÅÜT±Þ™¯þ¾ˆ ðyön½¬Š‹²Én%³u(°"è(nRƒ¸² AÜVÔZCêÑÚÔ€ÔKH…‹7³JªÄS%þ¡•øàh«årýêÙã»\“ å\„[[NÉAßEùð¬ðBÛAµˆõ“é9PN$Ãe¹ŠB„AýT†€n"!¾?|£ónvy5Ÿ¡O6[dë³U¶aù?ÿò%´ç±X­Ëâ,[ž‡Ÿ|*ªWóÙÉ«b9_E>Ü—ñ ¶çÁáoáa‹å:+æó,|›­‹‹U^oñÍ_¬–çëÏEUÞþÕGzïK6è¥ýÁ^Í9 vaVdóeˆ}²»½Ê¸%´*õØZ•–bL¤E^‡1H³RØ´üä¾ôAÈÎÏO KjXRcâÀ¯†Ì#Š:7ÔµìÜsËL&OplÂ1¥…ÉNè x=õ,çኄ×_&œ©%Q8†óþ¨B‹BØ£/,äVä'ÉO’Ÿ¼kœtÎ TTuñûG÷üe>Ÿ]­[TÉ\á“ïÅq[TAŠ©Å_9u!ªñ;'p}fêáÚxN† ˆe‰€Ø{_<×à—{š$Ï3;3‘ÈÔÐáN ¢ÄÊó0o/þö—×o†õ›—ËÅruUœ–»ÎóÇåu5+«!\§Gw;WÍkn«âÓöšÿ˜-]¦ïÃHpt#á£ã²`$ +;§—•y_.Îâ v®æÇtl·»qzµ-þ+ H·'‡¹ßܰ^ÉÞÅ+™ •‚õÿÅȵ^âBÂél¬˜Èàö|î ª¶5jw°®oyU.ŠÓU¾¬.ŽoQ›R*‰•Jròˆ¸Kó8hp‘>“âµÊóšKcªM^§¾ªÙÀÜý¶š}*¿üñße¿–QزúòÌLÿ¶Æ‰„OÛ¾ˆd§0#w‘غǓÇò¾F\ eðÉhp>L$²6ì¯#IÕÏ·Pƒ q1ß q‡ïâŠz ϯ'uo(o1Ê[ÜEy‡Ë:$Ê[´Fyà #”w“ï° (ïm, ªÒaúiKãƒeø XFŒ,à ,ƒYí–A®wØGªwØž’;ŽžÜ±¯É*¹ã-’;AÉ]Þ>©Ôa/¹ë/à °; >H€HàY€|OnA 3x"¾ž5’ÁNƒ'èƒ'DÔ5tàj \ëcL”¡ÏˆrÃÖ8$ Õœ†DÙ=¢ ¥Ù§±î« 5ä©x?ç€<¶äñqò8òðJBŒyÈ®U¢``îßç Ò÷?›¸+È"ïQ5° @ÂÚEÓÕ½¶Ü€”zªV{xNkh­­u .Îë6åK+z¦¸Û»'cã6º¯´9_3Õ67AžËÕªd§ŸVyù{qy5/óE¹>¦%ÎCÙ­ I¥³þãûgã2úîïr)Ճݲ‘æÕliQï¡‘¨e½‡FbC“GÝ®1AU2„QK¸-Y|¼“ôÒ]¿bb÷\Í¡rò®uWÔIjkô)ásfÈ1Ž…°45^Áu“¾ë4gû{ÝpĦ›ÜŽqñ5 ·éŽÛ϶‚ þØtDà¯á Rø×5|@áC¬áK>…?£ \áÇ}"tüHôVúÖ¡öGÔJßõ ZõèëÃûqNêÆ8ò›z“¹A)ïÅËÍ ®—/>õ —ñÅ áßЪx.ÕðŒ€Q•f=+›BÓÞ6€µ·ŽÛ殎^GЛ̈ΠÓ6íܼ§`›ØÛ&5\‚­y? ¶pùùuƒ4›üZxìAšÔ³Qz=¦Y-úqÕá¾X|_¤ˆ«†-_#ñÔDt‡è©·.¹j„‚ GvÕ{JZöRó×.)½ÙßÒY¶¶s¬ý)6ï¿Ï+>Þô·î ƒ;~‹©Ào`1èà©g£¸uLm!­ûñ ß7ˆ¯¾²*=ˆs÷:‡îÞ“ö &Á7l;–!}ƒé©¦!©iˆ;5 9PMCox¾Áö2PÙm lÏp÷T͘F^¡Á°?R×_»žªsbêœøZ“#©ÎÑ>nuNPu»:g«sûl“\ˆ@’àc]œÀùÖßþòúÍs4IÝ$ݽo„8ê„ËÓñözqú¡<Ë~ æ¢ÁN˜d0èíEËc@¤Lmì·{ˆ„…ã3-M;X›¤ÔÀ¸¬ÇdìÈ•ãÜâæŽö~=sÚŽóùìêý‡e5ûw0ÝÅü»R΋ù*ELPbGÒ‚"Dj©µ<|w½Á EH^¾.ªüâßÏnîß`»n«s©lÜœd…5Ä Ò3ƒÈëê´Éu'å‚3Ÿ›ò s f$Œ¨×l1‰§™¯qBÖqìÒÚÞs6’¿2+ë*º.”9½®>•ïÏf«ð„°ý{$N^p“R}»·rÌ:rµ„×^­ßUµü¼ýô_uC&?÷ûy¹¸øþ zrï»$›V!ľ[žä)«ûtß„=Æ¥䡉ÐgF©X¶Ô.öa¹bb"]n Ø!JÓ¿Ét_¦y01ŠÍqZP„ò¸Ê68C¦À¹‹PtO#Ò䤄«>5>· ÏŒ$BÇÙOeuQÆèäNpòy¶þ­«ëÅGŠMæ§Ý“#heËól’±¿Jæz¢0÷ E ÒCÆc†‰ñ(tzcÉxäqö¶Zž–åYpÙ›òj¾üצþéjE¶¤o[²s-ÉŽ Ú‘dÜ´¹cÎL¸Œ_1íÉWI!Ý1ÓpUŒ†ïUî´3ã`'r) £±ï>…Vñ¡O¹¾›>±FÃM20ÞÔød›>”(dþä&ÂàOy4lïÃÌS÷h…bœÍËÕ—Õº¼ 7í¯ËùYY5ݵd ³a)k-Ûåé¾Þº­àªY˜§€êƱ´SµA/ZDà¢$8!Á /,|õ¹†­«²$ÃÒ»aa4ë8`WÞ&#“MÈ|ŒˆÎ9b¸R1Ï|„% î 8fÆa炇l^™m;›ØÖ˜>ž['-a‘Ÿ4y?šøáPd9 ÙŽ Š,¬©ƒXáåÔ°\3'">ÃÇù´‡"‡¦¤M1°F&¨OŸ`ädãR?/¾”Uüöö»ÍûôÏ«‹ªáö¿_òúíOÁÔÌV³xuu#!JF4w²žáò{ ÷óÉ\M¥*ü™aLýÑA~Tdo‹ÓÅÅ&>Æg–-ñ»±"F¶Ôt‰Ž“Í&Ø9$ä6ûßUÎõT@Ñ6üQb7ÌšÖpeWpüGì—¥Ð'´K»"÷š5ÈÝ}£{ð¸è ÛAj}‘"7C¨Kév^ )Ë€ÊÂö(‹ëEY¾eûùaù{“²$CPkûŠ»ð d*8 bžØÎ;ÊÛuÈÏÔ¦EîÒð÷uÉuŽL {ÿÃo”'t—ëù=¤׫»C÷zm(j)õž$©˜K«œzÕCõªm^LFðip/N;\_%1@¹j72d1á{`“î,yPtvUÍ.‹êË#Z÷(õtñï?âîýs¹¼F0Uÿzý3d¨¿1WüÆ\%ƒ y‡1«9áé§\‡ÛÈ IÞI…]̹s¢†¿ïãÕÜ“óA67ÚdXò¬›`&\µ(JL¹€Êžs ©:Îþ¹*¡þã~×›ÖÎyµ¼Ì~-£Øå£ú®'õî\JÂQu·"_ÝÈ—!‡ ãá¹ÃSTÙ~[~.«?6—NØ õ#‹[ù ñ.÷VE9~ÊCÜk¼…Σ7 ™¶9ñxmê:A œW˜" K3 4£ð@÷øa½¾:~õjƒ0ΗÕÅ«Š<"šGt¹ – ºGñ;¦ªAˆc— 1æl‚<^ês¯Â˜ÈÜy/äZ\:³½V ¸s¾¦tënýr”ð¿Ž)rx ‘@·ÏÜògREÜÛÏ4ý¦»{´1¢ëƒETE—{É…+ÍŒ³ ð+†Á>ð\qɰëwO·¯)rgÇ®!AdžIÒÉ$ôÈÑQæ¹t,›qÔž  ]žj;=Âç ÇC–÷÷EP½ù¼¬²ÍÏ‹ÓruSõ:Ë®jHìªÆÄ€á9p'dá3˪ëÅ*;+ÖÅI±*o e«Ójvµ&R,„îÎKLå1̨#5ë#ÐY¡æÜYÇÒ Ð*ÍCØm™õØQÇöéö"¹ÐãÖf)ò0Ø $ƒsã½D&Ï2€:WiˆFAûËüìÆ·WÁ‹Ÿ‚÷Ÿ-2¨õ^_eg38Ⲛ•äÙ{÷ì W’¼;6»—KG.óœ[g&—£$ˆaFp3•<÷ÎùpYsΡb˜“Oת݇—µÝź¿UC,*¥–Ús§ýZ•Õ§ÙiÉŽŠW7ùö«óå2?)žO=:M,0_ þ–iå5Õêrï†S~*çË«øbÛÎÁß?hä’!ÚÜÇuÖAˆª¥L‡Ø_¸ÕM§žª“*Çœ5B^"~r¿PY?K ¿ÙýÓ,Í2=JÑÚmH©i–i Y&çz_·øžîáS؉-ÆÀó"û&¶ÉÞ…¨½¬Èd ™ > ©æÈmFÊ“ÛOªÕgÀÛª<+Ïg‹òìfWR“ÁJžgáøû¸Ê}-eÊLÙyà·óÌrÔà>é`mBû¸EÇaÖßxn»đY÷ï*1•ߨüÖÊ£»poÈ…÷í¹Éð L¤dÒ®­å“‡¸„œDNÌØ?„ûR¨(g*`µ5èkkÒÎÕÆ™̵5]ë'äBÉ…ÖÁ"WÚ» R/(îlj~“þT\,à¢dof«M®”÷‚5 ×™!ª–2•6W!Ù‚¦ã u:õhmü)¬tíœ:¶ôª"¼O”œ’g=@Ïz 9+?‘cít©‚WurTG•æ¡èÈ}ò8' l]~eZb®’¸† I)L{ÊjS¯TèCÖûÎÙ”Ùæ›…+Œˆ—&^v[ËE8{ÈjÏ÷íSÃ>¶ŠÄcA7<.͹µÌt$;gõb3îÑר5r_0ÔÏyIú7¨þmkçÒ?޼c`Hë~@Ü oˆËâ;QÃìA-ÑÉõ Pƒ¶øà 4¶îZܼ??KT—Ož{TQ•C´µîÁZ܈ï'e×}›ˆÝÛFÔ¨yuú4£™H–# º¼°†Åäµ8ô¥EÛ§jî°Ø||ysJ]™H zuÎéë# –B׿(DøÀOeÔ 7"NîŸËÏwà×ÿZVÉo#LGî\ħÙ°çN_æ £^£–Âeν‹•0¥…¾Qf 4ü¸VØe¸Ý6C¥S:äÈŸ-¯áv ß UL|ˆÍ)Tt‰ƒe¼AŸò¨î|<¼†¿•«uø ½Ã»w®ÝSÄÁÿ8Ku«š7Á$”ÿB~q+o4)†<†)—³ud9ýLÙFU°á’é@ä1åŒ÷ÐhéépÛüÜ)=%%™™ª†:+¢X£=~›çˆ —×L¸Eä2MIZo4È‘ÜS®1t®±®0P®Á™è‡?Éá’'雇^ï¼§}Èðáírµþïª|÷?ÿxõKUœÎ˯ùÇê1Ø!Êjv¾Cü6»,WG¿./‹Å“`pÛ¹ˆÔZ쇹íÝìò*èâ›òj¾ü‹ì¼ƒÛ}ƒ5œ%Ã%w€+dg“5 &k4LÖðð{²&ñhm&k`OÔS˜¬)4MÖÐdM÷Éš/_P‰gºF{tðÕ’¦k†ê%r–Œ+æ¶Ævb†ù67Ê €;¥ ,LsJx¸+œ¡cúwظ4Í*ÎázeAú éïë>'Ã^Ú…“·¹ôÞŬ¼¨¼aLDë§=Ç._5q_XiâP]èAfTnÌïËAÎÒÁ®q{œÈ>¹–"` W0ï ÏŒ»R[”ìÇÚ€7’½£TÉ‚4]G*)ãÆõÉ W©B8‹™¥J™;ëôR@ïìTêœYg¡2+Y×ü¸uL¿}¼ïTXºWŠóÚ½tK}h„”D –’øT_9/'œuß.Û΄¸yà}™Ê¦D±!ªµ#ÈM²›É™Ù¯åyU®>ÜÄÙ›M‚BÁFÝ»énRÝ», Dwlˆ=‡ód<.øeö *ØjBkØQËî©£ò…Æmƒúñ¨ŸÉù†8çFØ(¨0n°ð0Õ"÷zâGÃÒªš&]^Ï×eµ(ÖOퟀq÷2Rì <¼à‰FßòæBìjrg¤W{bX+a‚{¢ïktÆÀzôà#MØ“1¤ûÂb!zÀâGÅAˆŠR¸¾qóà GÛ‡äe2I`îƒs 9 E .²ÖÃi-Ž&ÆÖæFs7XK‚sw5-p"}2› R{HÄmø 0rÂeç]‡m1]ÏCp‚sœã9Ã98”¾9¡9BsÝšƒ¦Â¥`*Ú¢9¢$ {@s¨ú{Ÿ‚#ÍQ@9ùÉâ9š¯!Õ”è±Áz`D"y8$’êH‰$‘HrÔnòS$cZ9ϽâjÂâ—®»&ÚY—-Q0 ªà*~Øõø½'m Me‡1 * ˆÒ€è(á~’=ÜOøÑ ˆ£1m'DIaá·­0ƒˆJF#¢4"J=ê)POFDGÛTœFDiD”FD©¥t1"*û•¢¯ vHY®ÖÇáPaE†¯•Šô}c¡œr^ì=‡{½w:f(&¹l7Éäfz#m,•Ìqö—ßëFÚë·rØ€§ŠŠm¸„ŠEí—ÈtBÍXö9Ò¸½z›;k”9Ž;ƧA¬ä±Ë¥ñè±é»s¹‚‡‰\YZ°D. Î]C-áé'G¦^b£<5ÿn73.‹òó­YäÖ{wëÍÆ“j{˜$€'‡0 uÈ-ˆä#° ˆ&ÄM²Ùy0 §åjÌÇqöër>Ï GœWUùi¶¼^ÝX—?’eé½ô'ɲ ž1Øêèe‡i“"ˆáÊà ¼Ïjâr©™C‡Zíž°áA.ä4ð0†§]¬‹‰GBöKGÈþƒAö›#GÈ~BörDÑNçi2Ÿ&ó EG(:Jˆi2d…6ÅF<™ü×d>èh.ÿ €è¬$Í–Ólù#›ÌÆ'¡ir;¥['BéG[WŠö§L­“&>Fð²­.ƒ ­+MCë4´Nåv*·S¹†ÖÇ[o7#ZWõ÷#Z'&\[ ÷í°{¸Šûhà²Âë`™¬áž\V § S(Øa eý8ÓUBÊ>2RVIlŠ—Ùüý[Æ Þš±âÛÌý§âbî-{3[}l4&Éà[ Û<9rÍKò¸.Hð­f–O¸E†Ì¥¬M&¯s¯mW΋Vɼìüúg‹E»d¾»9zH2¿®®;æòçóÙÕûËjöïs¬’A4 ¢I4!-êRK­åá§«²ú4;-ÙÑj]\„ŸP1¡ï„@ª\YHL.ýSKx M%ÃϹ nG×y'`é±SÊLÏ™n gÜa‡çwOטÉzÏ9¼<¯Œ¢Ž6%Ô¾›¬Ó±¨¢(ƒÜ Y¥÷"^_å ~Æ\4|›É¥é„û¢Éð(ÇÝçayðC’s'a3C6êžÀ‘L7ŠÛáÆúÏã˜mlH”?ÏÖöM7ò#EÓýO76\QpDíYédШŒ0¡0‹6µ2Ò© q"ºc•'sÇ£r³²XÞQ¦Š”©îÜFêYáöÉÈc©B@‹™£J™;ëôr@ïìTêœYg¡$+Y×ì¸uT¿}¼ïTW¨‹D]¤ô¤D –”¨T_9/až‰ã¶}6‚|дCˆÜE±!–°#ˆ#²HðãìEöky^•«7Döf“ŸP$Qónº›O ``´|$ ŒNg³4ò¸Eö JØ‘ÊVÇêŸAœÛ>UÃcTÞýà±™tP?3õ3yl I=½6žêƒÚPIoj&ôÎ Ý`(i-D&ãuuÚh1’A«ÊĹ*‹ÙFT¹Ð1øiåC¾ c*˜L)‰ìºwÏ×8·¶;t·¨Nqíéuõ©|6[…÷õ´Üïª`ë†qÖ“;ÇvçíX(´#ЧÎB±Ï4û~0ã¡”‹ç™Ê:§ò¹õ^ ñ¸o à¶ ló±›g‘K+YçÃ)s5T}ذôÞòD0Ô¡þ !h¾ 1àT@šKj'³^]TÅYy[Î>ÍŠìõÛŸ(Í뿯¼u© ŒÚV6œ­ˆÐj” Q#‰uÊb"Ö©±±Nm«Ë`¬SFë±Në±NQšD¬S£Eð5bÖ)R™q±NÑ–âœ?ÞÎ<óŒÀaž1É>)`Ï .ëŒ×>ŽS‘,²ÎˆÜ¡’Î$œéÙΜŸá Ît'œ9¡ vïcï›çFÕÌpi„!†CbÐGžˆaà ÛCx.ftžŸGn äBŒÞo›È^1öSNî^EªMà‚@Ò9e‘™ ÜídÍ,‰´u>.­•Æb ÜO+#iŸ©¡F bÑD*`|¤·-n"òU ŸJŸ{þìr?6l?.¯¾…j-c÷&RЀÑÐpD `YOÌè3OÀ!Àw·!à@U›Ž¶H û@ q Mä=h"¾"êÜE!|Z‹ã9I±Á—:—@ƒµ$6¼‘U› ™W6gNo‘ÇV™Ó †gÜLƒ`.¥…±$e5v±aß1G\@,rb çÞ›žÊ~FËynÑGËm$”Þq˜paF€2HÎ2ÐtÂÆõu]Œ\=Y.µZ’zBìBö1UTÈ z#…ÃÀw$ÕKôíhÜ{À9†¦ÛH…;ÔnŸMÇñêïà諎xˆ†ƒg‡ŽŸ ¦X•ôZ wü¶Ï×H€oEðïŠJiäÎ;«¢É$yˆ²Aù¸rÚÆyò¨Šœ1~(3å:¾@É:7Ñdùž'H²¾wk7Y‡1´ÞF3-ñ¢/Ê(yQ¶uÆEô`=Ñ=ÑHˆèa´ƒÖÑ=Ñá"U6ŽÛ±¾ª¹¸™ê­?Õân' ˆ[gïÊuö¶Zž]× Š Ú|v´\Ì¿dA^¾Y~^dçáO?á½-±­JQï`ï¦ëJ6­{HÔ"³w<=$š`ÆAÜñ‹ ¿AV/'\ƒ›ÕO%ô”ÐSBOîë¡ =‡z §|~ |Þ‰òyYµKÉªÛæóQ’­;™Óp[â÷>¥’0l>_+“Í蛯!E¿}ˆygÒÑÉ~ZÏ蓎±÷¤˜Ø|æðG7LóùÞIÇžsÎqä½çm¥l'‡SýЪa+MÂãäBP›ð°Tœ‰81ìµñøh*ÑB{¤¨uY ÒŸa—tlëÛù˜B&ÒöµÛGêô¨ö‘ŠZH*h#iºiÙšnº7}áî°C! í¬°>†?ÂÆ™Qø:ïÞˆ“ù~°ùî«èކ{G/`FMn¦7ÒÌH¦´8;Îþò{Måz!ȧr凧J›Ðp#‰6u@Ä¥oy¯©4ndesg2 ÇqÇø4ˆ•Ü0—Æ£{ĦCî>Ì媦%VVÍmu÷î>]-ÑuRçrrdrŒ5r‘²ŸçF=µèí{¢†f7hvcô³ÛéÈÃf7¼FžœÚ[zIF*GÒ1t8¯YƒÐTÇ´ã@4ý¡†4‰I6;ÏÂX®VEõå8ûu9ŸgÅÁ&ù«ªü4[^¯n 3$çÞ{i¦é’’cÇuìŽH´‰D›8íïxzìÂãÌH{?’mªVFØ31„.¶Þ1Aš8|X½£.n :{LtöDgOÈBÖPFtö#…ÖÆGLg¯êïGDgOôwDhÿÀ5;a÷Pôw‚‰±LÈIƃeòÎhrFi @î?ˆ 9_h>Ž&Ýï'vú!ä×W­©œÚäÏɘ^Í¡HÊp5„€Œ©å¹›p“KÌô9õHmògÁ³gnp“ç“sø… ¾*5ü:dð¥ç”ž?Fzn¢ur”5µ)X2Ž\‡o‚<d¨(djLHÅÕI¦©äiìG¯1ŸqqvJ5frbäĶXìPÐgÈsòŒ$ÕhÁËÕÔhØW0üà‹¬Î̳weÞø¯"Ãý²'ÇoÊ®¶,ïÖ–E?ŽÙ¼\}Y­ËË`©þºœ‡8ªÑV%Oè e;nÈ,T씆˜[ä2ï¢Ní¥žªMÔm1göPkFŒÑÀ ìuð߯>—'¯n¦öÈg÷í³CHg#ƒ=ùìÞKV·ãï¿WÍ­ZÛƒ+­×y!»Ò8¤§ô4\#ÆçK=X«>Oî¤Ó‡çRÉß=cwúiõÜø4Ñ}œÍ¹ñx;(5®3ãzéÌxä’VìÌ!%º WÈIbÚ‘žúŸ:3Ô™¡dm_²f`xˆüØpCØ‚%O}ª˜cw~µrcA„qLõ޲ÎOƒŸqNZ€ã1ã 2œv÷€{<©JÁ;',í£íš€8wÜûuuÚ¤÷–ݸÇÙ››Uvd4x ® Ù \»Ñˬ^5unËm#‰`ÉMMRâÇBR"SGŒÃÿ>—'G·¤òç×óy¾.ªüâßdVzO_öÝP²-sõ8+~×=áa0Åé4À"NÍè‘®ÓO+²WØöêî5$C5Ì^)Á“gTŒÌ¹Àž‹hE@ˆ‘7NÔq71¹6JpL RêÑZ‡çΆ¹bJä!èíúFµÅ"¥´”ÅûŒQ¼WÕòì:GÏίJô1Óz»pÈ=7‚pPÃ{×ô7àò&¡"­·×SÀ8àÁØŽ5éTäUÉ«’W%¯úX^U„üÃˉÌ%yÕ! ÷.}§ÌäHà®ÈÄÈäHÂæ¸ØÚ9 Žõð­Å†÷%|Ù¯åé2¼÷_žÛd].ÐÍÆöí{ 5®žªã¾Rà#M |äs¦kRàpC>)p×#=:%°é Ö R`šÚ£©½QТiØÜCqõ@qµ`ý0*âúI—sð“&¶ÔäÈænmäŸËÏÙÛÛd|C­H–Érx²¨P—ScÐ)~Ì¿­Ê³ò|¶(Ï@m`‡y£ÍJŸ0â`Cp 3XÜos9ÕJypmÚ çqCü”“µcƒÚ9‡¹ú#7ÌrN<‹T[?<§~ìˆ]±˜È¹ð!°39÷F)rä½”ÉÚ ‘ήNGêE-%BIÄ{@I…Ë­˜p,¢)&÷Iîóû4ÅG¹Rî«XD3äC|‰ä©T.I­6Y) nø-‡†µ•Ú¢¦¥ çjãHU.ºgŒíÜi à‹œ*9UL§J´ÿh•e›s& äÎjF‰éPl’B¥»ÒÜ+®†Ôv9SÒÃ%ñFò¸»’ ’­Øär{Ϲ/6ã¦vb—|>¹½cÎjçž}Nˆ-6:1Ô”´Hßè"ª“á2Ål¤ð\Ml‰ëG£Ž#pt~x>›H4nÁ¢üœ­¨ã—4]J›Æ ILP ÄäÐÆ H °ÜË@·¦Šh¡t׿mû¤ùœ± ª}i˜—[\bÏáW‚„{½ºÀôê;~™÷í—÷*SúJ/˜¶T…É•2 µû$s.\lOjk¼›êp±ƒk«¸WYöŸ´q˜’5ŒRkR§Õ‰ï']î%Ë^”ñçrýyY} ºø¯×?ƒ>~[ºæ·ú˜<_…>^ån` (§ÎÂZëÝîÈNÚ*ÉüÜ7ÈŒI¾}[Í`¶ß§¶$9'ãTŸ—žÛ©±¹eR€hcôáÔvn+•2·®s7‡J…nÓ”vö¬0’¼rk=„ ¡€×•;ïµ™F–Wm'å9Ù9ÞÇÎK/hq‘ÊK Co™JÝcV?/¾”Uüöö»ÍI^V—á0¿\•UOLÂl5;WQãIR‚‘nJrÎT”õª5®’펈Jú'*Ù¹~uAí+ÉdÔ(·2*Ü$1 „ë©hãb×?šÖpe4C»Ÿ Þ]}u¸¸;G÷êŒêÅÍ"«L¡j NÖ ¡0 §jÜ;Cêòý¡muq½ÐïaÃ’É(¨ÚÆrܨ”E.ZL¸Æ:¦¶¨<´igj3˜àÒFñï›Jèœo·%Ä:ÿá$$àø‰®Šèª‚rhƒSÊ”†"«’¦7&a‡‡Y¨ãI,¶n­Ÿ r™¸¾e}ÛU5»,• Ö=J•Ýtì»…Ôæ êfªd2Ì‘‹ òèÁF”ëp+$¬L9©°K;ÛçjxH/(aÕ—çJ†×qûór/ ±¹Š‡M¸Ï% pÿM$ÇÕÎ|Üךü[ø„³·euÞº'Ù¦ú“Œ·”jr$jñGÊÈLRôT™$‡oDg{» PÚ¹Z­"¨D‰žøÐ‰ LO²À¤X0N2u£•—ZéŠ`ÇËå·£ayÈ(P;·Q  w§å«øƒ×ŸŠÙ¼8™ÍgkZ84â…CÏŒnO­’1Ä!žÀ³ÕFJ³aHŸG5õ`g;в)ʦ(ûIFÙÒƒqzzÕ¬C޳“1òõ‡†í*uî@ŠŸ‚ßÃ7¼3†oØÖí7[‡þUžÐæ!TëÁ)ÐÆnâ*~»‡T2X?¢oƒÃAíéÂPO”â¦RÅGÒgìíC©g£ýCÄõL\Ï´hp7.s÷ÙÜø-†-ræ˜U³ä9ib†Œ‘ RT-ÆM•Ê#õêªîäcÑtM'PYë7sS/L£eÚötÞ,âËosaÏAŽ»…=s•[lØsÂÁúL5,ªaôùq ÏPð§Ø¿gðó÷Ö›èäñ}˜p÷±YÃsiÄ\nq+ÊD–‡é¦y“"¸ýº“½çÜÛTª_å£l=Ië]Ú½Ka[¬”Õìî¿6nëÑÉó»œßÞq÷´|#fs!ƒ5 }!sãùö]á¤×ôWøö*ùˆ—0yÓÆÏHàf'öæ"€5›ú\sË’¤¶¾ƒMÇkš<Ù¼¢$ûþ¨—pËŽò¡–kk›¾/vúD Ð.KV¹ÑÚëg’ÉiH› “ Ú)©òeÜÒ} .G[·‡Ýº½mÌ9{P@²=œ?ØŽ{ízSäXòajD9ýU ¡ãÑ— î?èÞ6³éì¨H;}Y’&n׌{׼].ßǬSì.(ôÅ÷¢tpˆA¨bÜ6d 6ŠÍô¿ûµç.R§kæj·2[†õf¶¸Œ6d³D…Ki¾š-.r¯»Ê&³õäÌÖÎ]$³5ÀÊ€f‹÷µ+ÛâïÊv¹¸Ý•ÍG¸+›Lâ†lK²‡ÂÕÑ…€‹BE"ÚŒBˆðÍlŠv\ö ´ˆå"wÛ²odOtÈí.jWiê4»¹'cؾ÷:;È‹‚"52S¬È dÅ­ „0™—b_|ŸŒ4Ô@BŠÎDRnˆ(´Ïe½Ã3¾O>W+Ì~Ž96Û½KA>ùä¸oÖ:¯Y7í".ÌOÆ2o>6d)rÝ—ƒ-ÛÚåb3Ã=Ž5ÛoŠuqR¬J¢œÃµ–fú±#{…Ù·€9šd¼»Rulp~AŒš×G«üTC‘BùèÚlg`Ukcó1TFÕd=œY8 pÜÂú¸á{$¤±±=© CV?Î}gʹ¨~Òñˆô7¼ëbû‡ªŸ#Õ;L”¿:<Õû¶®õSq±€°,{3[}lTÂd¸¼}wòP \#c´®-#V¾³ÿkYåJ;[›À£;³ ¶c§ÈW‚xV‰£â“Ùz Êa{Ïa Œ&ÖÈUNÔéÕÀ’ÇvpoO8fT%€•¨Ýé†2ßXü}‘­?ÌV3Ï.®«"£IøY™Ã~1Ûj}×Õ±á\¯Ê³ì<\ÔÕº»È§˜Ë?__Á®Ã›ÄŸ¿8[–«l±\gg3xßæ_²°ùåæ‘ÙlQ]óË«²~!/ȆõN°³­ „gEµ]6yvG™!–ÆÜJñSS§ãØó—âôCvõÕBÕƒ;Á¨\ÏϲËð[ˆ‹ùº¬źœd/ÂýÜyx°áQ'áµËE¶^y'ãúåõgw;v[ÒÞu·eµ÷íæÏ?ž,Ëò¹±KgmÜ<ìµ+²,ÇŸÜüj›ã¾ŒÇP»ör~Õ¶×{ïI°:ø ?dù)Âà:OÖŒ³ûvƒæEÔç?:[zhgçú-Ñ–9èÜkVklŒúBˆ¦>^3«”núl×ë¼’iSo~Ekñ«kÑ—ÝÕI= I „¨woQ¡ ”m)®jÖø›_½½gÿo7 ñV?/èjY© ‘mf°óªçßl°öhÛ×ꆫ<Žô—G>q_#©ü„x:ÓFj-µvÖ-±¼ÜþmÆžcŸ˜0v‡—>¹Zùù>2Cítæó3¿ X¸í 57à?¼<¦Az飲“Þ¾Ô|i…¯v&½ôqˆ—iƌ˩w6ÉŽŒµÞ·—²}Û÷ÜRò¶è²êÙµ×;<5齎E û)$!|øà^VMe3¦ÅÇÍ­üÖ‹»ooéQ´ìÊßžŒòhó”×6:lEwËU_ò×·ñ»|Ídÿî”!óý}™L‡rÑŸAå㿳΋-ƒø ?xK3á­Ú†ìßvúôÞ[þ5jß»k»MIÍ÷Ý«%žÞ¯/Y׵诒n›Sßé-†óÙöàÉ"ê-Qi‡ÌwϺ—f»;ßýzÅýRï³|a4Á‹Æn:º/ å#Bˆú]ƒ×ì;U¸Qq?Å}ŽÌÌ/ë×Ngß\õóŸÉüð –¤Ô z£Ð‡}–”ö¶Ýnq“=¿ßµû–É";,–‹»N}ÔëTçÅõ\Z×|±â²É*›nÇ|?æt¶=h?½ÆO=·œú;ÉîpÎG¯xå{i¶»ó]›ò~3¦»qÛ,ËrҘ͓¾Ëב}jî‹¶ùëÒé'µè±åÄ_‰v‡û÷ÕÏ^ØQóÍ]¥Åü§o[W.ô¨¸Ô¹æÑ7‹®sºZ¿P!DÑ®ŽŽÞW~tåû•$Ô!%ÞÙÖáààÕÛOšø ÏI²×Û‘æøÞ?yâ¡i3[1ûN.ýø°óé%êD´«åSM]¥ÉþšñÚî¿"“ƒ+–ê5ÿ¹y­æ‰{pŸ’sj@ä׿}>ûÄÕëæÐŠ%;ÐáóÎ Ü+xÙÇ£Ò½/Zn~5f÷{n$åBŠ>=¼å·Ã¿ôq[ïÏdϪ4áøÏîù&*måå .ùôøù IÚð&}ðF×$äß³þxndŠÒïñ1¿VTa7Þî]uÕìóoÖH²ÝòZ…yÿ;5¢b€Ò—"Ó¡V~Öm³Cñõù—{T\æ\¹êÚnÆà¬”G^k{ëËcm)esíâô‡GK¾Ò€að]æW°À÷â¡€à x@ ¹ÆíÍ, , , , €€ €€+K1'¬#z%U)§S‚ãj7I:6eÇqGéž$$Éà½ÔùŸZW¡Vâ[³­ö´Kà¿°Ž~nl4ÜòÄ«º?Ï'›B/œÜ_½cŽ©eø¼Ê"÷Ù‚,‡f[*Ë¡²w+èëÚ«+’›Œ´æë yïx$Y– T‡âÏ›+w°_<­÷OŸýbO¦„Õ2åIŒ$Ãý·ã½Rk¢M_$Ùj Îß×2/Ž Ü¿wKºÇ{µõ/¥tþJ矡_…jú¹§‡è=–NÍ‚uµ.®V³¤e{î9C’ ±'-­jÅ«U†ˆZ‰ßFÊ:eÚZ]?ß=diQ3^­H›h󲋜òȰÇ7˜;<–à¯1„Å·ígº”"|ì¼âÐÊ”ÆUâµ*Cá² #fY9ƒøï,÷\å=cÍ<åxý‘lBXÌÑ”š]ÌÇù_5„š ÁKǪuN˜u,5ˆ8sØËìŸn 2%‡,è% l“aÜçï®lR»ÖôŸ/¯Ü|ã´¿/»ð)A>¸ÍÒ§YRz×Ê:ŒÕGèo&…Æ\ XÓѬ£Ù£{Yu>j‹±Ã"Ǭ“-¡íòÜeìùƒ“€‚æALfš¨²Ú¯FiH°†úy ~+Æ™ÖO¯—ÖìæÊÝ…!Rwo†õwC:…IB[ŠC˜`·†¸õÇs*M’ ¿B[†älÞ§S¬Z*SEÙ¥¿ß#ÔªLs£,T~ñ6s°û¶Yu~dé¸v'CZÝë§5ÉV¨Š%1ZïK—À7`Uó7|w'´šÞ[ƒaC¤1´*mÃ&«õñvKˆ+jX¡®@ã‘<2 X69T™Ã]ø~–;³ÁöÖ Óº_í7 ²CvFºîeÕùPµ!Ζ®5…JrÅ/DûáÈjÒœ3yùTRÎê+Ô¾Ý(éïJÚ]§‚-öPçLeŽ:o°¦nåüÏýÊø¬Œ«¼\6ëú¥n]OSb†ÇFÝØm ©htþ<$Bšv"] 1ÇR‚"´yØçüÛÅâ òêIšŠÅ%¥$„iW±|п„´àJZýä}x'1ÿŀ周¼OJ†TÕþò†¨ñDò×Ûl1‰²ìw®ØWÍ25ho™¿5õþ§ký–¶IZ¾Õžhv³|x‹¥Ã3æñký|ìLEØyCŽ¿hÕø'dUç>wáÅÐÊRç·ÍçnÈYÄFÙçÌABµLûqkã¶›CDŸ¶õÊøô4'1ÿÑ€åÌUNÙÖl8D¿ÿõŽÏLuÊǫՆʓV‘¿<Ô«|êÌYx]¿ßi6¼Ÿ\2ØàßoŠeÀº ÑuSK]bÈtQ±|¬æÅŠqEë{OõéÜઓ£]xð^:e_`­+–fUãÕjC6Ƹ†z/½õX,ÑB·kŠrr÷D½ÚP½•1°—þ‡J_v ¤÷ Q€;¾ì © To˜áÊ<¬€8Ò0E·˜" `°Xÿçè$ɰ1VBo[\kd7"W$J’aî5îN¹Š4í&÷‘ÕâîL úêùÔä—tÕòH'ûµÃôyå/Kx^qì®îÂZuAýø‚gXÙJ¼b)QÇ|åN`!•²V=¾ùö ®Å¥Ö¤(sáÚVÃe¿ð¢É⃋ìˆEÀ zpS„Ò=Þ«–Ѭèàxn–]ñ÷²¤=­ôîé*z¥S³„`A­‹«Õ,iÙ‡{ÔpŸIÌtñî!K‹šñj…·9ÇßF§ÔzKç¨ú¸†¸ÙáQzm‡¹cÓ„ ?ƒ>(®q›äÏ7Ù})ºÏnÇž´´ª¯V"j%~)»—ºê”ikål  ˆíÔšl«wä–µrá„(sÚú»GL¡á K7ÛâL²Õä8¸)¥Q˜aæQ‡Û^bÓïÔs±c¿”kñò3f"»ÅQFgØ— ˲|ë`rp9£{é탦"··›mò­ ¶áMã\íx)ʃn?g<å°¦8~ú0Ñ£KYø=ˆ)ÂL¯Zyßï_ “ê¿oëñYÐ’Žiר&VŒ3­ ž^/­µ;‡M•» C¤ÎuEÇ}¾,ã⯆Ж!ÞºzucRƒñêÛG´B!‹FÁ†QBºNÝ㸠q~[‚'TL]L‰µêÂ’œ»ðRtÿÝ^7¤S˜$„°¥8´ vkHV•@AP@–pÈ’2Î!‡ºo¦1DC ¹}»Ã&«õñvKˆIÅ&‡*½vu\Ÿ;_-nœšê¼•Ð/Qæ³Ô]RΛÒuÀÅKÑýwÛêUI—ʠ PÐ~)$!D.îl—][e–ß¼§+SŒõƒ‹²Ü$þs·•jcâ¼ @eVMЬ÷–gÝVIœ¨ü›<ˆ›Ü3½+í ‰¦H·a̱” ­k1D%.¥¸Ò’%§ílª1*P–CÝÿ›áþGê=éKI .§uÀtÇ¢Kʶ(¿» þ‹Ë#QåzRrÄZ¿¥m’–oµ'š…Ý,ÞbéðŒyüZ?W…×JICX-"ñ†}Ú«9K*²CºÌ>e¬çE®W¨’ÚÔÈUÚOŸ1þzÒauˆ[‘¶ámŒO½¯Ë¶(_»]Q'vÞã/Z5þ œÍóÞ{!bÿy¬¿¶+å¹Çãµ±*­¡Æã‰KvÙÝK gÍOVS*bKTKXyÌáÞ‚«Á¬>vç*½hJ[wÁè±ÕùŸSZÕÓkb Çõhvß½—¢ûïvVÃòûûIáúXm`Ü+ŸØøÈÿ¡Oü§ðeÏy¬`}Šð©óC†ç5PP" S„y‹)B à?¥À}UŽë>wnÙÿRî –3WÀtÅ'À¿5`°|%ÝsŸíDï±tj–¬3¨uqµš%-Ûãp/Ý¿ÄT¯|œFeˆ¨™¸èw‡$ܯÞn B„ª M¡¡®RYHŠ´¦¼oKÀyåa»É]Nâr¿9_  rÀÊx±*§—Í\÷›‰¦H·m̱” ­óç~Å¥—ÓJ“nXÜkzßV¢—RR6ÅX89@Á X‰ê~&%G¬õ[Ú&iùV{¢YØÍòá-–Ϙǯõs–Žþ\3ããŽÓ›C\?cñ‚Õ÷m…¯•’†,°&ZDâ û´W=VEØyCŽ¿hÕø'pÞ€>`9s•“÷jîDpýç* ¯ëwâ;͆÷“Kü‚ãûM± X4ºnê=^¥Úè·¼£Ý>ÁOchÚ+¥åb÷»¿¼o+„»Yo^j Õª>m¬<Ù_¤¸èò±š+Æ­cì=ÕŸóxË3à&÷Š%ÁXÊhNâeÒÃv“»$Æ­·™lÂë˜;$¹j_=¯1xФ@]Áú·|ßÏkÿš€ðàËžX,X,X,X, , ¬£V’X‘eF?¥áánI2HRºãrÈ2g!Û;¾\ðÞà·MOî4Ó‘|Ë&Ë¡eÆz( ¸Ä+X]Ë»ÎòÚV6¤{²­yèD@ƒÛL7ãæ±˜iíÙ*!,À ñkôLòŠ_íi»X™Ò¸J¼Ve(\6aÄ,«G wYZÔŒW+<§ó\¢÷X:5KÖÔº¸ZÍ’–íqx´{ÒÒªV¼Zeˆ¨•øm¤œ£þ{Ù6«n€ÿbÀrÏUÙf¬Š:_›õ˜kóXìÕ$¹ìý•ØÐ¸«A] ÙúµJp®Úbì°È1ëÇÀdKè_»üw{~ãpo¡ÿ|yåÞà§ý3ÝiÌÑ”š]ÌÇù_5„š ÁKǪuN˜uLvoáå öO7™’Cô’¶IÉQÿ³ÚÖK·@ò îÁÊ4Qe»_ïUò¨æ¾XLk˜{4¤k5IaM¶kœE#Kǵ;ÒêÞE2k’­PKb´ÞÕ¯†Ð–Y_B›X1δ&xz½´ƒºsØT¹»0Dê\-¬¿Ò)LBØRÚÀ»5Ä—{ßÖ{·ëA¬?g%·~ÛÑHݼ‘²~3u¿çTÎëu¡jCœ-]# •äÊ1’d°É¡Ê¬÷¦1DC ©ÒÖ8l²Zo·¤µ`u„ª$_•ÇbVÛzï6(8†ç`É™ü$„Gùß¾<ûšÒjyö€¤:}-®"ƒ5T–Óþóˆ)Êûî’JÊ—m½wü‡VÆ‹UyxÙ,D%.Ý»OÉcq/’$Ct ¢e{Íÿ>ÔºxzµÑ¹¾ iÁ•´$ß°èÃsð´Ï!Ò´éús,%(B›ßÃxŸÝUÀòHTy;)ùZ)iÈk¢E$Þ°O{ÕâQÚímst¼pXåƒ?[´!©³z£–i?nmÜvÂasˆèÓ¶þOŸž¦ó}#Öú-m“´|«=Ñ,ìfùðK‡gÌã×úå÷Þg·Àðœ¹Ê)Ûš®‡d|îyFc7ëÍK¡:CÕ§•'û;·røA_êˆù‘b]HüëKkö¥~*°D Ý®)ÊÉÝõjCõVÆÀ^ú(]»Îv¿áuýN|§Ùð~rÉ`ƒ_p|¿)–ë‚Fו0´\Æ/ ›üÛù„‚Ó±lW€°dÙ^?P³)6%D•úæ½e†:Ð>éL¬s1¸üLSÌšÀ†vYö¾9» г·²,;¶»×/m\þñ£!ÑÝk—ñùáÒ±lW€°„PLiQbÚ÷—]ËÛ><9tyû=žt­9¿bJég§=¼SŒ }`È# š˜²øÜÙovj6ûl§ ¸Ÿ€%L~æäk?ËöÄ)—ƒÞo33fÇ,W…Å3ÿê2©žkñÐÊÉ«”ЪԅËÖ1k£—]^ÛñyǦՃüÔú ÂÛôú|ÓWQôžešÕ Ö©ÕºàZÍ:-Ûí*rÎ…Åÿ½¾]ýr:m@¥F¿;o8ýmÛzåt¿²uÚ|)Ñ}/¾÷'[þ¥[mXÞrZïµÙ6žÓNz9Þ\Hˆü©g«úa~ÿBžé½â׳>vøî¡å-j–V+Ì67ä,Ø­1E´þ‘&«,ˆȷ‹Ô[&Ëò;A[ )²,§ÄíÒè*ígåk›_/öØà½g¯[íÖ;—ŽŽëP¦Ç×\M¹ïåöÁ‹Tè¼åø³ÍzëÂÁáM‹ºJï™ÞxéæÃq&«ÕwpÓ’Fa¡3Þuo§k§ñ'£âlæøŸ§?£/Ú¹c§ §£ã¬)q?L{:¤â8WMïýñ.Ó1±$Qëññ`}ìd¶ÇëKÇÜW¶Ó½³f_¢Ù–|÷ÂG=*¹Š²ípÇ~Ÿ\‹7ß9³ÊËù|çí õózE^Ø%Ëò¾!ÕZ¬¹ ËòÑ÷êµZQ–å³_ãË…ÜX{nIƒ"Κ¡jeœÍ‘nêQj·Æºæ¡\{)¤Vž7Ù ©2™Š Ó(#銶Xµ¾’ÝãjÇê]å]{ñÞïÜÛq±&ö/Ö×’tÊ—ƒõ±“Ù¯•Bav8”é.?ÚJ?‡Ãæ\úsV¿Öo¯ŽhÔªy£ºõ›uè÷\#…o¯ŽM–•\Ë ïx»I½ø“S GÞ‰Û÷¥É³…ü„%G„œŸš”phÆuíGµÃÝ+¬÷à–UšÉáÞ<«{3UÖ· ùØ]Û8©Põ‘>6î{'s4<%5ÊH“Í}-å¼RSµØxÔòÛ×OÏþ_¿Ò껳v˜tÀƒ XjÿÚÃ‹Ä Z:ªØ“o¥®’4ã+Åù|XHíÂÕiÛö/°àJÚâ’o¬Ô‡wÈ´Í¥\N«iº³Fö¬óç!AÓNÜu¯slZPÄÐ\•ïýñEòµmúï÷e—¼m<§ÇÛ­ˆþÓ“é‚QìÉOu…»º%IŠ,ß²}×ÿ}¸ðÐ…½§WÎÑÙó>ƒxrVCI’^ÚÓµæòm$…ÔyÛ5÷jÑÛß .ßeëñ«V»-êÔönUB:,:›é}B7÷¾V¡Ë¶W,vûÍsô¯ÞnþgÑ#3BÃ/Ûr8!ÅfKI8´yi£°ÐGîfu’—EoýqXêB>܃å0&Æ=´{΄%õ…†/>”‹ƒõ¾˜íñz¸ðuw]xóÕ;Ž%¦X­)‰Çv~Ó<\×ye¤{ãõ__—b·$îýzŒ.¼c.: î_6o®ÆÛ«%…&Òds­I‰Û¡PêÝ×8]=¥é#¥Ô epñʯ¾÷­ÃíýÛ#ÉÿyN«úõe@áò}'®²»5rmג篨U©´5nÉ®kríx_ôÒsüïþEûyIW.~þAeª=ÚsÈ»»ÎÅçî`³í¤—ãÍÔ–¹ÿ{¬f9?•Jë_¦zãѳ~tŸù;ñüç¯è§ÒèCê?Ýó§Èxß;LÌ y»Éý¡ô÷’§_ŠšqðÝ:\¼ùDõ_;àEËŠý´£/<È?ÿ¹+XùMÁ°X,°X,°X,°X,X,X¬üÖªBÒ¿®e@ÀÊc’d$C@‰d›œIé òqÎ >¶æåÜuCvÈ_N36©ègPiã*ÔJ|íÍ”mG÷ß2 `=h²*„x£µÿ&‡GQÔ6ã÷a~®:¾Ø~10wÝø¾_⬠Š?Æ&‡šâƒþÜϼ=¥u½ø¬Zö=󀇞$¼+1’dˆ=£+ÙÌs+@w/ʹcÑøç¿V&Î÷€•kÅ´†SI¡áê´5)«®PRV»–$ÃèøWxpW°¤{|©úˆß[%l/­M»ˆuþËäcut¯Fxn~|ƒ¹Ãc þC@X|Û~¦K)éBû…%çbìIK«Zñj•!¢Vâ·‘Y†Ë¥øóvºR¿Pµ+BelÙµ²L[«så¡•)«ÄkU†ÂeF̲rª@ÀÊût•éÏ^¼±Öï—É v!„pX=^·ÍY­ÉX­N'cõú›I¡1W‚Öt4ëhvy\Rr.¾<Áþé¦ SrÈ‚^ÒÀ6)Yíý›iÚW*Å?Ñ!yòLóövSúéÊL[–åPY½²I-„ˆÚbì°È1ëÇÀdKè_»üwèåC IDAT{~ãÈtGí'oôøüÛ=ˆ)ÂL•—ýº¦Û¦Ôû}Hàæ×”G¦&v=¡½ð­FxŸŒ“…Ê/ÞfÎØ”kqýÝNa’–âÐ&Ø­!YuÖìøõë®Ý¶ß~³¹"º òûlš6P™eËî‹#Kǵ;Òê^ÛÖ$[¡*–Äh}ƽü2©ýgÒŸßmçú“V>¬øóæ"uÍ—¢ü+™¸2:¤Y°g”1lo 2­ûÕ~à ;dWË¡^–Õª’2/õ")Êþñˆ¤u¡úÓ_¨} X¡jCœ-] •”U˜#cð)ÐÏÁ ®¨\ÅñhëD}ÿfÁ™Tx»QÒß•´»N[ì¡ÎºlÛTI¹éI@)å„çV}ßÄ`Mí’ó?/—Ê$IYvÿ°²‘ñb•ï—͆¬Ñ%EJßÎPgZºø‚¼z’¦bqI) !DÚU¬û&I†ãÉéÖ(5’pøºyÿÒ‚+iI¾aчgþ`Ò“Û/ÿ<éYל”°rœ±r4)T^\SŸyéÐÊRç·ÍçnÈYÄFÙçÌ˧«wxÁ´ç„Ãd²CDµ½×/©bw}V•+êÄÎrüE«Æ?A1j™öãÖÆm'6‡ˆ>mëÿ”ñéiºL7t…*Ò¬Üd,'ïÕ\<ð¥tʾÀZW,ͪƫՆ:mŒq õ½/z¸¸/ GiÇð.‰azƒZ÷xgÓíª~‡–ª³ÚvùXÍ‹ãŠÖ1öžê/„(ÑB·kŠrr÷D½ÚP½•1°—þ‡ÊLwä U¤+ñA£ÿj † o© Toúoôãëtø/`Š 1E@À `° I’2ý*ÃmžU ’…B\¤Üs§D[‚«N²úÞ, `h9½ß#ô87ϪW©,ËSÜá-K+^[Ü´Ë* GîÐ~ºïÍ€ÿ¸Á§%)ÌXÙûæ¥6ãI¿Ð66óõtìÆ×)ašxà«^•r×+ðŸòà®`ù>­¶ÉØzå‹hÔ~åë·ûö´ç“±¢÷,ëÔ¬V°N­Ö×jÖiÙžh÷]¸vT¦í¯¹è¤, I‘á‹¥ºÙ{¾Ü>¨õnƒ™3”€åž«¼g¬¨Í¯·žvnúG’S÷¬³ñånî¥1GgÕ첸ã¸åW &“áêÒ±u®9ëX̽x”6åweÓÓ9ê¡Ý’|áØ®·_x¶ZïùKõEÛoŸYïÅÖ“œ2 Ûäóæ¹2MTYíwdé ð]ׯUv.&E-,=ÔUybÅPÓšÈéõÂ]õï]¹»¿!ò=×¾r:E˜ö³Â¯Ûû«W¾ÓI-eº¹ünÓÇ{ÿºaPuÁ!ø¬Pµò¢Éªº·‰#ERê\•Ã4ÊH£­*­A‡-V­¯d·Ää:`9KVãÉí_´{ñÓÅN?[X—éæ–ÄuJ??ãÜ…vEt,•‚ø)ÂôùH™£ê¹µ¾ö3¯ÿ2±ØÐW6gUGØpó—]z·xÓB²ÿlÀÊx¥Ç˵Ÿ~Åý\Np-oã^:$"hÚ‰»îkbŽM Šš£þx¹ ¬Æ/â·¾j¶gU!¢ÃÜ«n|vÆaNðO,Då}fmôç/Ïx¦ÿŽÓÑ6‡íÆÙßG>ÿ‰{鈵㗶é¸|ë‘D³ÝnN<¼eY‡g–_;ÂU¡¢Nµó†1þâÿª¹è§J_íÓÊë/{©óÊWÛ͵åÔÿpÀ÷>Ü—í}K¥ÚÌÞòN•Ñíkûiô^_ïãMÂíšSxÝÑ'¾{mÃû}Kûù—ì7å‡ëNŒ®æÚ|ùØ^¬Z´ÎÀÞSW‹ônÈøœW©{:,xiKÏŠ*m‰¬*(ýÊ­ÛÙ2£kˆ$IR*•AÁÁºtZ:àQÅì oùú7\R¨f>æZ,Ó¬›3]ù®N×NÎ|±Mµ¢þj…J£-_±Â˜QƒZ± Œ‚ì°ÞãZ¼²ç[g†ÈQŸŽ}¿ý›vý}7Ál7%'íß·¿×Ëã><™ø¯>?òbdþ±¾çÇ+yä`¯ó«Ç²l³ÙbcbV,þ¢åWøóÀ:ovÔô˜k±ï26óííiͰºBˆACßh2Hý؈ÇÇnB<Ú㥂0 µŠÃ ÿp-®XpE¥-’£¢ö­¹õºF_bÑœqIû\]óF÷²z‡Ã<õÍuÿêóãþG&5:ZäþŸûÊ|êy>½"•|±úð­|IW‡ÉwÏøþõ:Bˆ}_~ËŸ'xøÖ;'‚Š·i Bhü+¼SRwóøzWé¶óäC‹Zª„Ú jò¡E¦ox´ –$!D£*%C’Í’²wë:©Á@Íã“ÜßkïÑãï­³M;§Íë^ŵ¡‘jß.žÿÇûŸs/}=ò•j®¢Ç:w9½ùSËï³¶½Û6ÀíŠZýví÷¯ÿØ|`Aôwo½ót‰lA 7¶ìN² !,É>ˆ6«ÝÙUÚªÅ0©ÁÀm‰6!„9áŒÔ` ®Å§-|=ý˜¢ÛŒ‹ðW+K—dÉâ^•ê5\4µ³Bòí3ݼüØeãáåz|²ôLR¦=9¼ñçFßÒ6Rò…?øõºk½Ô` Ô``äî­w}Û¯ñ° ½ç|{Ùè*ݺúë -‡µž8jý%÷Ö²Ú©³µÃ¾-ÞlXù>Ëóud¼pv#GãåH‡~š V?6¢Æ« 7Ý2gÕx¶¯ˆâøÖuy[Óphé?ž¾ãf¶£6—w¯ç™ŽdVÍú0"’Î?ð¹—ú !,¦+¾¼ˆYY  `¬ß柕$Å´v……ÚvQIÒö\¥³N% !ÆÔ B¯ÓJqëø6n¸.„xùõW.ïø`õ¨6õ‹h2îe×¨æ• ùù† 3ê‹{3’³– |±^© R¡Ò”­TuîìžÎõÍzíÛºZ¸Níçÿt‡çí_ʹ¾T“n'·o¬Q(K”­0õƒñoWò÷~tO ­*ËŽ±ï!.lZg“å–C*¸JGÕBÌ8/„¸ql›¢híV-|qË,„[;ȵF_¨Á¹Åý{ÖO½Þ3ªÿ¢5G¢,v‡Ír9òìð«3»èòí£ïþ|àj¼Åa¿~ù¸w¦|™ì^¡ú›ë÷^Š3Û¬ÿ:ýÚ Î•6/i3k×ÅxKbì­O?øÈ½¾÷6šºó¦ÑoŒÈבqO^•ã0àµå?Ÿº•luØ,)§íÖmVdûŠÜ<¾¡þ¸÷]‰³:lQ/¼ýö{寧=Ìt´3å>’Ù6ë))aýŠ¥Bm@%_^ÄL;™í‰((ëÎÙïãìr­—[!†÷/å°ÿw6ímãøŠ+BˆšýÊ !÷+)„8°"Ê£…­3>°â Á.«´!=zv>ðóÌMãÛW§»‘ëü†eþ‡õXwSÑíígR“Y‡RƒRƒAÅ^˜'„ð ®é\ÿÖÿ !>6>¼ë2!Dí]œëGŽL’¤‰¯OÖ6R}Ø:IRŽž\ßûÑ®Ú)D)X¶C1wI”B©ÿ°jڭеû–Bœ\~Qñçòh!Dþ¥™ò‡,ËïÍy×|`Áéy]dÙ>óÝÃîª<ßëÎïóO}ÒJ‘sÀ¹rÚ'Ç…tyÕøç¼U‹ú¾Óª]˜öÍÙ=½I¾ŽL.x‡Íñ!Äúï?u^òLø9Ë)æl_‘¹vÙe¹f§wŸµ SIY¶Ï·Ýûhg5¹é>’Ù6ëýzžþÉ7_˜BÑüÕ®¾¼ˆ™žÙžH€‚°Ö¸ —’ 7ëÑ`pamÌ… 7mi7;ßýk«"¼R;¥¤_)@–åi'elâó¹_o5ñÕ…{¢Ì…BóÌóÏíû¸‘{•ásmÖ ó×!ô¡ ]ë#jÕyoÔKk>è%„P(R/}½¦B¼{ànÌ¥?Ý'§^× !\ï.BˆÒOf3 ê÷Ëù'ÝÙóíÕCŸÝ1‡Ux¾˜*-ù…?ÒZq7r£]vL‰L’$il•"Ô’â¼ÙÛg"¯ž86qÖW/¾³JápX2VXv×,„pEC!Dܵ]îV¾ñX¸ŸªZÓöB‡Ýä\¹Ö`BÌ^W§RwÚÙ÷~8¨¦ŸZ[£œ._GÆ=‘øxÓ•—qø´y¸¢K—7«õùdØÂçS²ðl_‘·R„ëßlæç?àÍÁBˆÄ[»³íL¹d¶Íz§ÒhJ–ŽxýÁ{–ôåEÌ´“ÙžH€‚°„?/º"„øìÃ^Bˆ O¹YŒ7ÄYÕºÃ*=U]§4¸èàÁœp{É«*´™4è³½BˆR_Hw½$õÍÛùP€Ô·ÆG{¾ziÉ r)·&½;=Ý¿øoH>˘É¿bÙ]ûe„ƒÿ·JÑpP ÷"¾üó!j«éú¼È§Mv}hC×c \^)ì'„øðT‚kMÒí=U.ùúHêG®þ¢\ÿ…—üŠNšüfV}°eø|ž-%Ý<µõJ!„¤ðK÷JBQH)e|A½ïôq•/¯û}ŽL.x‡~Ž[пÙS5JXï\šÿÅ7úd9s—í+¢’ÒNYÈB!IÙŽv¦ÜG2Ûf³âLŸÖ?æF}?nöKu¾½ˆ™v2Û P€Vôþl²ZY/;ìïŒó(w$^1îͶBˆè}¿eÜüОùò¡Es:V Õ*¬)†C‘·…{º ]ïi TµØI‘³Ï¹ò§áõ’´rÝžá¹wzU¬E1¹QXXù¦ò¡Eæ=RÿM×"„?jŠ®á ç´‹âÑ!Ù]ÉFÏ©$ÉpÎ()”<âQ:¬^°bêôMBˆ’MžÈ¸y¯ÑÕ…kF/øòÐu³Ýuñ¯W^[wîðRïEë0÷°C–ûtiVünê‡ò2^Zé®BL™5Þt`¡óíÖqpA¶¯VŸ0­¢ëÔý&›uí§éîIò¾Ó`¥Ooü÷92¹àe$…nðà^Û—Ž=þÕp!DÜåY5’í+Ò'L#„è<ý·X³ñ‹‹„AE›g;Ú IB\N±Þ6Ø2Él›Í)ï/¢"‡(pËj¼òÉ-³"áæ–“.Púò’¢pÝ@!Äo«ndÜ|øš(!Äð‰#c÷~æøsî¡Y„?,Xâ^§Lë^‰ûç¯íVB±bJêá “]±õ—ÙÍioILtý«ý£ !†Ï™zwM!Ä¥í©Ÿjüøƒ?=Þ]n­ì˜íÑ©õeFÕ !‚е©™á2LÞå„wŽ& !žèU<ãæOôŸÖ¬ˆ9ùJŸA“ý -ýâ§k£S íûŸ<ï¬PK§B´~vÄ#¯ÿ¬ B7zŽá[ï4öˆ†Eûü˜mÏǼÓP¹y…¾ñ°¾?Ýq/ò¾SŸcvŸ#“ ^ÆapÇ7œküÛÌB•Ê2»dûŠŒßDqòûÕaMG^%)”£§µÈ¶oå5’¢ÜãÃj;éHæ®Y/|9sòäDü3K±bÕ !Äéû3Åžßd—e!„Ãayßíãâ.ûæOï9çK±&»l·Y"Ïü5æ­÷»®¾æ^§Á¤-‘³1îöÌi ÿÃà\ùÒˆ5\‰·Ú­'üÑ¢ûgBˆ¥ƒj !®ìúòÉ·GÌ–”ä76ŸzÆYÿêo«›¾¿qÿ•8‹C6&ÄmÙ¸©é«?ûrt}{BTïÛ(cQ¡Šm•’$„P(4Êê3ÛZzgæ»kÞxºq¹PJá§lÔ¤ÑWK¦Œ¨œúƯf¿øX™`µR]³ác;¾,„xeáÉ ™ çÞ í• Ñ($}PH›vm÷~Ñ>ÛnG<ÑkÏ[-ʪB‹ 9ڽȗæÿÈ䘗q˜µ|h߯eB´J¥Z[ûц?,y.ëf²yEJ5é~ð½ŽÍËòS©J–«ðÑGïŽ÷á!ïß ¼\ˆV¡P*ÏfZ!wÍz‘‹1w' I²œÉƒ¹}ÿöwŸmž3(\k¸º¡PçM9ÝÖýûRò[în9ø™×Þ5‡F<»¾-ç #€yöugA}Q•Bq`ñ¡‡o˜,Æ[6‡¢á€œ4Œ Þ©òª¡{f)Râþñ÷—¶Þ}ø†©x³Q¿àöÿªu8' #€wy9Eøo‘ß òpŠ, €€ àá–ùs°k\Á `°X `°X `°X `°X,°X,°X,°X,°Xÿ*† S’$e\)Ë2#Nr@¶¸‚O)w~ï÷d­`]PÍæ}~»czÀoùŠ6z=Þ.çh'^GÀ?ùXþÁêû?ñÿ#cõV•BÓÏœ?‡Tc87ýŸp§ ]füýÝheN6\‰á$ï=J J™dw8V(ì¶Ä|䛌\÷Ǭξl’·¯Ñá `@~`Šž^+äú9¨ìk¡Kû>éÒ}Î^ ÿVS÷nèõDõ@m@µ¦=¾ß;µ€ôjÍÿï‡Ë¼:€¦½Ž³'cäSÿ5  ÷ç¹ÁõýlÂ!ÇW°PpmQÂ}Ña3Œx¢é/QÉŒ à_°¤¬…?òµ{ÍjþšL?~ïßxå©FµŠ‡‡hÕ*•ZR¸D­FOõcâ{Ïû¸Ç<©`K¾8â'êT ñ÷S(7Lˆüíý7ú6®Y!Xï§T©C‹F4ïÐwÉ–¿|ļ:Ø„È_ßèݾr©ÂZµR«®X«éà‰Ÿ]·8îõsÛ˜¾ÏU-ST«VêC«>ÚbÌŒU‰Y<ÂàÖßû¿˜9¹_×v jV)ä§Q)Uš€à°rUj¶~®×äÙ_FÆYòðUH¹}lêȾkV Щ”êÀBÅ}êù—ÿj¿¿³óý͇{W u_c5ëZ÷Ùc‰Öœ6e7ßX³àýníšW(]D§U«4~á%Ê5k×ý㥿d:†™>ë!ãgõkRmð>÷ û p®/\gŽûzùþ^F;¯Î«l²r`dÍŒ o²‘¿›=93^ê‡U]í^ó½Ú£µ¤k»ú4¯à}§å›õÞy5)Û=Þ…„‹ëë…úyÙð§i}tÊÌßlÚMÜšíXåáÁžýfL 2“¼\©óÕÛþƒ‚T™”m4$ÉîÈÑ+è¤Ôùù~_¶Ê¶Âù&Vgþ…ÊÏOµ:ä\píÚ’tâé¢zfCªôºn¶gµIFÿðÑ#!Ú¬†"¸RëM—s:€ÂëlÚ#ƒþp5•|kEZRêN&[]E±¿’éhçáy•í¯€——{ÿ52nX¬ñ/2 Û7²¬ l)W+ëÒ…§ /®ÏXíöÁ7„~!-ÌY–å¸s«+¹E®:=þ·ýไd³Õ˜pþÈ®q/Õw©õ•VŸ‹óþ®–mnȶB«p]‘&}6ˆL¶Xc¯|÷ù²îîÿ¸½{åÎÿ[tòê‹Í|ûÒ±9#ÛJ’Òûîòö`õšÐwWü“lIйôÁóeÜ‹J´n¡R§•~ع¬{i‹Åg³IR¿2uÅßѱV»5þÖ¥+¦º¿¦’¤˜°ïÖý²N©ì1qÉ™¨‹Í|ýìïý넹—vùöÂý,Y–“ol­ ñØi‰ïÓ'ˬz{iýhõ½ 6 Uð¤•Ûî&šM ··®x7ø^fÕÖþ#Μ‹¡e9zgÏtÉUSü–%]øÛ7¼zº×kedºŒý™Bí_Ý”óö¼òþ+í1žý~j ­RV§ûÁ˜þbÀý,Y–Nk’n6Qé¿ÍàùöýêaBˆæóÏȲl·ÜlîöoåÂõ&e¼x1µaW¿Ðæ7Ó¿åyÀÒ…?ë¾ sÂ~׆)±›Ü®E´]áÑÔÒg#¼ì.϶ñô£ioº×ç{-]à^Túí¬Æ¡æ¨ë¯ïè¾mhå)÷?È•ûýà^špuFºëCeÆßgÀ’eÙpfEqgÞ­Þoq¶Ë’x¤´6íû êŒKwÑîÏwj»ŠŠ?13wËa)ë—î+§^Ørͽ¸iPº‹gA£Ü7ßùr!Då~;òé¼òò+Ý1Ú×Nꪔ$!DÝ^Scrw)X™\Ä2GUI?X¾ë:÷ É7VJ’¤Ô–¼œb“eù¯EOºW~éϛۼu°{'ý•¯«íº‹Yݾaé®+ 9ãQÁùŽ—ÝåùÁn‰M ¯6ÓEßKU~e³‡M±žØn¹‘~¢°äýǫ̀Äô»¸•®{ÚÒ÷°dYŽÞ>UŸa õé‰[¼¬#ëº×ŸnN-1j¦û L_ÝJÎEÀ’eù—ÎåÜ«z䃴³èïñï”ú)Æ”š¾ìÆšþj!Ä‚èÄ|:¯¼ü x9F»ùú¸ç« !$…ºÏGÌ @ž,Y–}èqK¿Õí"ÖúNå„U^Ýî\_&(«Là’bHwcSP™ ù°~‰5euh‹¸×Üa†Èš|ÚËîòü`î—!ì&ßK%I™é&\Ú7kü°6OÔ(ZÈO£òý&¼œV¸f¶y© IŠ< X²,ŸY9H‘á¦ûW—žô²Éˆ’îõ/¥¤ëªÕø·{iñ‡s°â/~¾WêßãSO§;”Í8æõ&¥^¼}x¨B_¤{þW^~²:Æäè]«„8GýÉ_IÈû€e7GUõ¸ˆõÂwÎ"KÒ‰•BR¨7Þû ^.ýDÉ«=“­wÒ]ÞЕÏ×€gËr^£¤6Ý”SlƇÙËîòû`ï§T–å-õõWúô Žûd{Î[È]À’ey×´öž„º)¿FgµI„6ÝËdñx‘íÆt÷ΗŸžÛq<[Hç^³ÑÌ“²,;¬1eüT’$M›T'Ý´]XçfË›B4™}*ÿÎ+/¿™Çåó*û§ýÊ—l9ÁÌÜ äyÀ’eùøÇMÓ½Ÿ)u›cSdY>2¹¾¢X“®šjEº« ™ß³á°¦wÔäkÀòr\j)ûÞzi-¿ö~J£¶ w/UûW›³î÷»Iæ6Èù°dYþrp}ÏODjŠù—!ÓMÔ¾=ÀIüx®䨔t½Òî*Ëòõßú!K0ÇïõèÉ'×l¦ó!*…¤ÐìK0?È_"ïÇè§ð±zƒWó‡ò>`ÙÍ׫¥¿ˆU®ó‡-¾N€F1å¬ÁU³¼/ÿø¶ÜÏ,{¾µßç¬ü>Øû)ý_Ù`÷Ò»®?àü”¯KvX§uôœwÓÖÎt“RZ•ïK¡ Éõ¤ÄíP¦P³¯&|V¿ˆâ©çdYžR%ݽ*÷ÙqaÍ3Bˆ°ê?Èó*Û«|›þ?OðÂìü­€<X²,Ÿñ¸Ç¤ÌgËžB–|Õ½šÇí#›3½}$vsú˜¥»}Äãcú7[Êå<|k÷¸kOü}݃•‹ƒÍ¿€åñT*GFýë–,;¬†! û2ã9¤D@ŽæË<(2|Œ“+§‹Pe;Ï P*$…îD’E–åË?vLY±æˆ2ABˆnÛ¢äy•í‹e“åk›'jÒ_Ç’ê ›¯ñçò8`ÙÍ7ªû«3¾™uûåŠ{µ¿=•í nþÙÛË3œJ§¿ÞpÚ푌²,'\ý8ßÚ=žN4ôLN?Ex¿›Ë㑤 n©Ân½û,Y–m¦ÈçËf°Œ©é^º"Ã猷¿Bè ¿è±¾húk9®GU9‡Q¥-å^ùÊ/2ö'¼öì{ÿ<¸RHíyWœJ[êNú‡,ä÷yåã‹uhn· ó°Å¾ú;Ž¿˜—K–å“3ŸÈ0)Ó 1ýõ»åÖ“…Üá39ã¬Û{õÓ.<øzÒ㑌ãʤ›Ûšx!Ýô ½+åá[»Çs°Ê´ÿʣŠŽe¼>ë~6ÿVǰt7\Ϲ–ö…›û^8–,Ë)±{ex>»Gsüoî×ó*¿²6³@'6/.„xröi’.áé"ïúl`7«Va IDAT•éBˆ€âƒÒÿ;äz± “k=vD»*¬|¢„Gi™ö?xö%ŸÏ+ß_¬o†5ÈpÚ£xÖ(äiÀ²[nÖHëÑ©Ç2V‹ûÛã!Ôïì8t.Ñh±š’ÎÙ5®W=ðMg÷]n0øÏs7­v›áúÙ¥“zª”ú¼}kßÿQ{÷üw÷ùék1V»õî•óÆtÈþIî÷w°ù°~Kÿˆ¯ðº]бYÇ]^/HóÐ,Y–.­óøØ]Æ:g–½ê>Ó÷Tÿ‰[öŸ4$™ì[ü«»¾_ÒµQ1!DpùîïÃÛüBy÷Æ›øs¢ÅwíØàú……µÞ:èQÿ»g"Ò?f¬Äm·ôsûð`‘™iÈó_¢¼ X²Ã2©u)ϯªÐ-Êlçï&äYÀ’eùä'ÍÒnVò˜¿sIº¶«w³òÞï&®Ð¼Ï®kI™lì°¾ÿ\¥Ì¿;O]ø½Ÿ.z¹í&§#púqjמּ‹°í„-Ù6•»ƒÍÝ×ÛùRêd3E¶)ÉMÜJÿÁóvån óªBŽÞì}ÙööŸsBܦD3­stõ»Ô^úV¼QŸ#™}UŽñΦˆ,n“׆4:™áW öì8÷:Ϥ{0¯ÃžäþÝ~!-²Š*y~^ù’ƒÓ݉eº˜»_(@Ž–Ýr«æ½‹Xå»þà½ò¹ß6Lx½_óGk R+ ¥:8¼x͆Í_1aÃïÞ]hÛºtZÇæõŠ„ø+$I£ *[íÑ—†¿wä–IöúmĹ~?ˆ?·{òë½V/¤Ó(ª Â¥š¶í¹ð§“²_~œ»ƒÍï€%˲ÕxaƘ>õ*•Ðk•Zÿ2Uô6qï¥Ä\a X²,_üþ-×C²ªc5^]=wò‹m›U,]ÔO­’$ÉÏ?¸lÕ:Ͻ4äóïÿðò50 v¾3 [½ªeƒôZI’Ô~•ëö:éðLàikœ6kùV†¯ØÖ£¢«´öØCyûK”‡K–åP•‚€¹&eûw9Ý]çsž¬1b·$)VÝLìQD/qÖ(GµU:IVs*é 7K¡P¨Tªs&›kÍþÏÎ!ú-•ÈMÀ’eÙn·÷÷Õ­$«Íÿç÷Ó‡¸XºÏGuÃ8€¬x»KÊð=n u¡Å'/ô¯ÂÀdE9iÒ¤¬Êê” òWKɉñ‰É)Ú "õžê4kÕÏ/Õ*Ĩx‘³O [ †€€@À `€€@À `€€@À `€€@À `°@À `°@À `°@À `°@À `°XÈ *ëùcϤ¯öî>s=Æh ©]»ê°—;½P-ÐY*5èª)I’J­)\¤pëgZ,ØT#¹J?¯ùñÓŸ¾k’4åË—íÑ¥ÍøU]åÎFäC‹Ü÷ë¾ÒµI’”JePpp‡.–xÔOíÞ>fÉîß#ï˜%uDD©Î[Ô³ðpsT(U¡… =×õùůÔWºÕII8®k±@!IŠ»ç5Ð+…qW·ê²V£/w}Ç[…”’ÂaO~¬Å[ŒöYëf½¡÷Ø‘—·?ß[%…êÈî9ut©]³¥Üj6ÙäsZ-«#Ê6*äô >ŸâÇ/ æV}ÕÚ—o'Yì{\lÌî{»õ÷Á‰„Œ•eY¶ZÌ×£¢–±ò©Ï.¹Ö6qJ‡7mÿëvœÉf6ÿ:ufâäOêOÚ•‹N˲l³ÙbcbV,þ¢åWœ+}ýyÍÑk¶œ¹•luØ,æ‹ç/̘õÙóÏóøÇ9춘;·—.X\mÌ/9mý•[ï½µ9ÆýipþÑr^ƒ`sòÅ®ën¦^æøváþd[‰úÝ3FhckôèWÉûš”dÄã/O™VJ>sqõ?D´he/›^F‘ŽdÏ(p¨ü)竌„ODÇMŽ4å«(Pnñœñkçq-2DtÁ앉ÍGD|Q¸k1”Ï‘Õó–`íDÄðü|ÕQ *1ppß¿:zy*žz<Þ÷ÝŠ>u ‹y,kÛ³½Öˆø}€,Âi×_FDıcÏëˆèŸè±LµÞņ^&¢ø+[õÃÆßíÜÏõ!¦sDÊOò@¿ Ÿ­<¡rrq¹áÙá÷OÿôÌš«DËüÆß¡& ⌄ i8åœ` ‰”ѨM÷kïôR×Oò”Üé¥Ö#óþÑ®bˆÀðäÚŽS·/«´[ Þï™þÖî"RäM¿VLÄ'¢S‘œÝú„ˆøB•ÏQ¸ÓKíÇÅm‹^ð¥ï, âмÝ{tŠÝ3qIß÷‰(îøü>@¡ypˆˆdªDdxöÏE³oã…Ö0á®)é!Íq}Èë/Ü æñ䳕ˆšö.JD}GýJD5úTHé@’sFB…´žr¶°š¯Ë0Ì©%s{¬9«¶°NÇ½ØØ¹‹VùM,’È>¨[ïô£ë(ø»[Wkþ×ú.Ã*ÑÁÙ³Fm½orØLúÝÛcê̼AD͆×t¥i."¢Ž£·ŸŽÓ±§{ñtÁÌUD$ ¯Ì™T«ÓŸ©Ö{àŽkj++”¨ª•ÊëyÞ Îé¸}õrÁ‡‰¨j·šDt}ËDôñ÷SÝ-·g–&¢íKï§)çÀ¿àŸ­…¢ZF}ÃÄðøßWW¦t¸É‚<£”B…&õ‰FÃ#?ÛÕ#ö³åWþ°jåIë…ÒÜýz¶ðf) oþ¡I.ÛϬÿaÕóºå—­ÓmfÝ#ö?ž1mÑŒiI)+4h·¦vbÝ}ÂÇ“úìzploõ–{Ý †éýq0g²¨}áÚkî.únÞ¢ï’V¶è׿ÕðùŒWVFTÿ½e>"Z¶ã•.4ÉSxé"D×ãþ‹a©lð³d~üÿlÊŠÉ'žõÄš¿aÅ”?HøŒR rØuê 6ìÝÿú¢ÎjG ¢¢E#ú÷îtmÏwó;×Hi—<åmj‘ŸãØQßîw]Íá3ÆïÓ´n¹|aP,)U®Ìøè¦Õs·æ¯ÒâÆ_¶©‘'DÄc‘TVñÝJógŸ[SL!kõ¾¾ÿ'5ЇKù _ *U®ìì™ã6w,‚ßmxóaŸ'_ž}ºÆnî®â36Óí/lDT/4iIØ»Dd3Ýo >çÀ¿4=[»t*@Då»D>¢ßdé8£d¡Bκâ‡ïÙd$¼©,XIn?7¡ŽRåóÄÄ䈫~ j²Ü–yóRÊ ÔîŸ ̦qzˆ§Çò¼FÏcñxj™BS¼‚þËo,ÿÞÊê“M¼¸hÔÉPº°F*T‡„iÞ­¥ï?ÆòÏÖ³³×­øŒ²)6ãf-‰?kô¥¡lL¬–…jÊW×÷aùû|–¨Ÿª qàßhÈŒ‹ˆ8Ž 0cÇ©8Nåúd†ûo+ÒTÐC£%»J܇à8˪ž? ûk´º’íð®vÐrg–­åsËMQlö¿f4«î\QLê.üg¡¹î{Zwf¯û&Õ3ʦ|nËtG½Ç™ÞÿÖþA7é‘+a“*îZèô~£KÌõ+g‰ú9£·b<€×*•‰Fo?7Eæ–1LPó‘2Œú5 œ“+¢y[Ù¯ã÷@ÆöÚåŒÝN… *“åþ(×Þ²¾ÓÌyûŠLîÍ&\²äªdvŸÈ뫽7uF9á×#]E}ÍR¦{ï‚Lâ]?êÿYÂËg¡ú ò÷‚äzb¦´o›×8ëáa[«:º0©Z(ÕTªcX}˜õ|ny¶ ¸.ÙêWÒ êˆJú7½þßO¸j~*ô-bð$/"ŒY#˜ö•Í3Ãç§mŸVÔ yIÇJµHY?ª  Ôy#uãV;œÝ…k³Ú:¹H’KÛ¨«ùNÊo5Øú¥¥õ:©GDmóhRêØÝò•¥ý:©$Yý¨ÊI<ãéôÝ¢ƒ¿ óÿ`{CA²ò“×Q6ÆCfžË¿öjýi‘\ ¾PR¸t!s¶¥4àcR­ü‰eãŠ}ftýË(ÁýùùY³*·nÕn‡ÆÌÙÍì©]–¨\ê9çX¿‰]‹Í[˜.DZv ûÇt}Xq“çÖ¿ZhJmOi_›Á!”i½2ìjy åžýÏêJL‘Þ­n<ô?§ÍÁ=¸do[B=h¯3ÀÉŽüÍ®³r=»m¶¡p}KJ)ËËþgL[íοi.õèMv½•3>wÎøBãÞ1¥õ>‚©ŸªKÇs”v­L—âX‡•ýs–^–Oß¼•éÊCÖna·OÓ+Kš|j#M‰/¸Óï]F=øÔËS`¹ ò„ƒ?ç^V–pÕÔOÇ-¸´ÁßÀÁÿ^@\OÌ”Szx½º×”mV.[æÿ÷ED>ôßõ‡v§ýñõ#Ý«åy?úhòdw~ÿ:´XWñ^W€5®„úÛ3¬çÖøÓ&ÏaògÃÖç‰éíf'O NÚÆrå cÙT.Ë1¼Ï4«½¶S¤ŸŸ$%ÐÜ2+Š˜‚ªx–ã‹4)mòÌÎW» ½óÏ'JØt…u‡•îSZï#˜zð©ºtœQ0Gq_q§ÕI”órÑañ¾Òž8ðbŠwZjû>=i /gv}V_7) û3…L°W<·hàÒ¦éF€€ VðGüG“ÔÒa~¾U(¯è“Ænü_ù•±Ú×`… ^ؽ¶:í,O¨ðl°³þ³ÒÄš…r­Må‚Ùô¡Ü«Ëá ˜"y…µ³>O_7K‚}`{]¡p5I JüI©ZÊÊ®¤±+pþÿÍ1( åß×÷jZcw¦¶žK{=85˜3 æ(>WÜÎrÁß^L÷¾ǵϫ^óˆå8nO;M­EŽ”êç’ÑÏõõ¹Žé»E—6ÈÀ› °^\°6¨¬ ò׎]åõ ~›¥i-­L˜ ×|ÖÅtÛìµïýý–fµµ q‚T¡Žj`Xö—Ã翇ÙéþfÖ6yñâY[~¨ •$$êŠêWrúüõ⢵^E€ŸP¤¢î·^9œZkŽzG#â'ä.ª8Ç ޝ0U.® ŠWÑÿv™õùo*¥st—|ò=–ã¸6¹Õ¬žÿ}%ŽÕ¸øââ¯õ*ð…E*~úÛ ÷©MŒz§€ˆ/È]´âÀ9;ƒ¼Ö¬ÓÄ„ù¬\Û¶ø»ƒö¸‹—…¬”­-Ö–jD»QŸ¯†%@š`ŠäÙðàù4¨”ºa´õæ#ÖÁ¦¤/«¦î}ŠMSí¥š¿9Þù÷ÖïG+åUWìlMuý«<ÅÓwFx¤c‘õhüËÀœ9Ž»³M_¬¹•c¹J! »S¨§Ÿª¨¿>êLõ*§ï |jAÞÀ°ÞT€õiuÃþËþûñŒ ‰?eÎ[B¿ç‚ÓêàžÆ:¼¯ñûŸÉåõ¦ˆ(ãM-×A IaøÄƒÝÆüµG¯9íNîÙGt3Íüÿ÷`—14Òð÷%§ÍÁ=¸lï\]üè— Ç`øýï+ÕÅæ-¢/ÇiìÍÓë…áqjó×î{ôÚ#»ÓþìιèfE¿Ø̵6>Y­,9ÞsMü‰IÒðOŸÚœ¯=À[B=̧³ã”IY" îÏ)^b?ö ÷m•BÔ ¯êF ¦H?ÅÕÃ"åy=Y' (Q_µä.eÔ%kìxtÐVÂè·Àó'J¸eNj·s?DSZŸŽz|¡ƒ9£ ¼Òº¨$ľ¬Ó3kÆX¬ƒR©ÿ9k )b#Þó‹æÐC¼-ÍVª•–ê©y#ÀxSÖâ I½G†Œ‰Tw3iGó [òÿLN-7–jbzf÷Ÿ_š†mø Ÿ\X½×ãybÓÛC úÿppaõ”[IGÑ?°?ú%È1é °¶>7½<µ›<Ò£Àнj‹Ç© )Ø/˜k½¦uñA‡'ý1l{V?—tܱ'žx]Ö³³fUnÝê=…sXØÓ»­Q¹Ô³Ï¦a¸nbäôÈ"h|žåî­&={í´}á8c!™zÀ2GàGc0Eªe8ô?§ÝÉ=¸lo[B=hÿ ýÛ2ê†Z®?b,÷âcá@]à äÄÆˆZ†õ{íÏu,ëäâï:ÖÍ1 ѬKa`Yàü‰ª´Äi8§=ºÁ$Í­¼>õêµNõŒ2êHÇâðbê†sl:+§{äÛBÿ*Y•”&üóˆÕÄÚ<¿?qiŽNVH]cv ~ÔýÓ ¹+è—ÅØãX‡“3jØKÇm‹&E!šW¹ES=µ o`Xo*ÀJ©™9ðÈ•À·yÛ'Ûƒs ¹+šŒþLǰ Ï?íÜErý¤ô¼RàyïÖTG×3#}–Ç©±ž[•ßï{óªT/ôÙå_®?ÓsÍßC+k±Â§`±N–Ç÷ªñ-->Ð*Ä ±ºÂú•}»{Ý5`ñÔpm¡­>w’ûG"W-§ëØÏtð›Rš ‹äÚëù9kÝJ?!w1môÊog‹Ú1 ._¨šÇO(RN÷Ý:GàÞbŽã·öh¥+œ[Íç%(óku2î¿Í¦T!ó¿¸ÝÒâ­B’ ’©«Ö3üñòÏš”ÖûiÅ âÒ¤f>£ŒºÒºÈqœúšõãò>/¡`9ÝÏçÙWÉêÈdCnY‚X¡é6/éWÝavJx ÛŸ§ÒIzçµk ]‘Ãï×vyÔ_sfÎïFVþ"dúy>C,XZo`X™`¥ôUßÀ#CFSOöø›Ùo•†ë=³µ²œå…ýÓ‚š9‡ü?1_eØÆ°õTŽ?Ã#«4—ÿÇýà"^å4>±?ú… n †ßÿ¾”^¬9ñÏ`Ó³-ÁXÃ"B§ÞÒxœÚZi®¦)Ôi}<¡}¥JŸOt ´JµxÁX)EcD íVÙmvvûD]©/mÙúwcGgMÕ)Žl}W ó÷dx€õ^Mã¿×üôãòä¨)W þ‹N›“{rÃÞ½²ºñŽä¿ûæx{šegü4ɼʰ‡ûMa‘†½œv'wÙþyiu³¥þÿ|°ÛV°ÿ²Óîä]µ÷ª© ~ô‹K0c0’ÇLË…5œó—ÎêÐ=º2¶Eóଇû‡‡E¶Ù{á¾Ý鈻¼ÿóÒÊfK¯ùÿÓúî¾&ïäé2ã`þFum êU9Ynþ°—SôdY9éåEYYàW叿4t@öyËñëlX~ïq²)Ý®­VsxÓ¦}ÎgF®PiAÏ1²ñ_ê<cwZûN°½ÄòÂxmúJWM¹FEJÕ®W}Ø¡B¹Î•ØìT%™DÜ!ë7c­ÿœrš‰)S]0dЬÛG<ϲ¹ç³HDç7X¾™l=y•åã·ë+Y6N”Ò4ê'VšûL±^zÀ,#ˆþIÞ§ŽÖOªçHDN "×nŒW6Ï•âDíkˆò:÷Íõ_[µùïÕ'ùÊ|0}ýÖÎïåJlC"rOøîw‘ˆÎo˜úÍä%'¯?–å+Ñ®ïäeãÚû=pQ‰ð¾Õ‘¼0ùDóIŸ_1À»3‚!Κ¿šÃðDž|Ã0OlÎ|BžM{8¬øsÂÞ,~.<\NÈ D[Ê ¤´uÀºSv‡i÷üQEš Ïúç"Àåx­²ìû˜³$36ñ“gïá¿ËFöŽn íKÕ|õצO³ÁEG!À«C!xB!,X°,X€ ,@€€ ,@€e ‚NÉîü}Çì­§ÎÞUÛÒJ•ÊîÓ®Cy…kS­7q§—¢B‚ °¸ùc&Ùû(qÉj8ñ߉N'Îß]9uTE*ÀSP]„qÿý¥]˜j½]•YèFªÐ1øYÏ0jTQ¹ÐÇØ|û¹)2·¬ôûýnXWþTFì? óƒÕ»Ù e-îM2UUã¾^Dôyƒ›’‚'Eþu~`}Ü#paøß¯Ÿ5²”<À. oŠë‰™Ò¢O,õïAûƒÂG%>ë9N…šÌ‚ƒu×ÎQ¤(¨æ®¥,XJDÄ=½{9Û,ÚK®õ»µ6"Úºm~«"RÏô)­Ÿ7åÇqß-œ0²f¾['÷—ÿæ÷9ÎŒ\_'À.­ [ø`|H“ Ú/­ë„¯óçLA]×!CD·¬l™Þ¿x~üÜuíGÿJD,ks­œÿQn"jÓfx¹Îó¾Yrà–… ¼~õs+8I\£_ùo~'"̓ƒwÈ&_fÁaùþ>úC)w >(,á1~‹—RV™,Mc°Üc­&¼¯½ðUHL¾Ïúñ%5æMa³ª$=þž1¿ÓÔ7¥¨êl!¨1XvŸVçÞ˜Ã÷:÷™ÔùåJOw³’ך\ïJt÷iÅ"R IDAT´D°²‡ ÇÖ1£çLØ4¸^Íâ*©€'‘)¢jE­[9eÐ;òäI×-h_»h˜/¬X£ö?¿õ%¢nK.ÑÜ5ý»Ô,ªóùBñ»Õkl_Ù•>¥õv<:®qTQ¥ˆÇÈB• 7:º¢ià]²‘B°ûáWŸšmèýËY‚ê"D5–¾.B—åmµ›¢Bþ¡s¯WRcÞ6Û³‹ð´ù¤¾…¬ìßxú­SXgè=× Ú,YÕаf¯So%§•;³ÇÖì3ëØÍÔ,ðåš«ÝgÆv¾„÷ûn ßcÌUîÊ’‹[D1“…ÂÔ’0m×)¶^¿‡«Ì ³ ª Ó¤4W{žjëÕ@Uø#qÌ¿bÔX6…,X°`,Xà£~ *!gÀ4 ™Ägú+O®éXoÌA€iäžËó…9îÀkÿmª(g@!,€ì)¥iÜ]ëFíÙ‡èZÔ^·7®ª•Š5¥¢ [npê+¶FU´R‘ºØ{†mw¼úOÿl©YZ+¨óÓ škGm#Àßð˵Øs´cæŽPƒ>l~;êRÇØuœsΟ¡z½ráçÔ­Å8n©ÙRvî…ѦºzP®8hêø‹*}ƒ.àxºÛÏM‘¹e¨&€À|ž˜©>@=Ç`¥´’aÔ[Ÿ+[åbˆˆµ±|±6æ¹²E.†ˆœVV¢sÚ•®”CŠh_RÖO\"»Á^Ú¦ˆ'øƒAîYW³pÆõ'âQ“—‹|1u$5‘¬yÂÍWy}E‘'`ˆ`!À€äÏi&Т'µ]¥ÄS=ËÀ,€l¯{Afñ½¤-ãc›,7æ,E€¯`èjñ̦}YK¯8ºbª7MŠjA€ðqMÇà3±»ÏÊ4-üTzp R½L¨._ߤè$ÛÞ‹z~“—ß"xuiý!älYºË5ÇZHA£Ã_Ø'Rã9'›ë³ûG$ÓTod<îï¥O7×êF½èAPï{:»Ú$áûu”é±£g3}.¹Z$×Ôjj:ô ~_@€õf¸ænï¾Ëw¶´¸}¦m¹$ä1-›ëÇ©8NÅ:T÷.)š)ÍëZ’g;m”³uþü¡ŽT °o–±Îh§ÕßTmN [¿¢AÙLr-^eŒßœiYÉpËÔ¾³eõ.B†Q'üOZ¨ŽãÅÓéËhc¹æù´-΄õ,ªñ™ÍsÑavJÂô›Ò3CCœ5Ï»võ]Iî|ÆXmX>a £+Kþ>R]åg.¸suµ²Kó’¾{`n¸J~z"?Õ} çA!xz3-XÌKÁ$V••Œ(èørsR[Э_Œçß“öˆbwžoš‡Y*J‚™¨÷îTÚ—N_ ©¦ô¿iÅr¶ß¯ñƒ5F‰¯/·³/ ÀÊøèÊïço–ììmÔ9‰ˆX;ûÅ@ÇÂõ¢@;°ôôŽsfOcdK¯/©²v®ïÜ‚~|"j»Xxp5ðqK¦üט\«Ü^…—æš_؃Ù`½®è*øKùŽdlqgûUN":?Ó¨þLÖ*“Bþj†Q3|uþHÝ÷ÿ2úzMj·Ïh*#­© "Ê[UVú¹eã3.}'òÔFy½»y"kÃ+È>¯Ê°Y:¹²ñQ{yëï??L±ùÊ=àÉjän_v,«ßpDþgtâi.èh¹îe8C‹úð»Žw~þSz*!Ÿˆâí”ß#Æbm¬ëEQɼ›MK^£L \¾`…•O*m®Þ@ÖY^',õôb9S6J87&DžÇHÑ¡Dd~aÿþ6ÇÕÒ.÷H&”›ô?„*Ò>[Ë\LÌs®O¤†4ó »4—·dv‹Kò/-þ£§~›¤†›ÌÆÙi bX61ÿs“̆*\ó8¸ÆG°Ž¥§_¯GÞâÙNÏ5§gYKõã–€7ЂÅqœ{ÜUðÑ…Fе ÁF063wçŠã§hSD)q,×µsÊ=ߦªn‹…•úÙè’$­gQqtHHaݨròá…aÄýý«¥ãZæDÞKo¨‹0ȸÊý¢%¿SIùlõ|+ÃHÂ*Á¯×Rrf‚ˆˆx| µÈ¥¹mVMio› }b#"†18„ûƒg„÷÷Å=Í% ÄTùX´õbH)iPûÀÛÌòL8w¼ôÀq¾‰¨L”­ÿ$c•|‰›¢Ê†û>‰xÜñ+êtd•êVÈVÐq˜*ø­iJì)å8iº +(X±S±"]ûÀÛ‰µò4©8İi®CAÌÉ?$#Z„®9¤/,Nlz8q5Áøéá. éË*ÕÁk…o½dž›Ë寿†íí*)'²µÛ›f4g¢—'Ž07Íè™xëTá'léË*ðVxݲn –»‹-‡AËÀÛlÇf~›-^RåzZïµÑ7"jÚ*il«Z¸þ…s6}YÞ oo€…@ržƒ¦›Ê«“N¬´Z5aD&Ÿ”×É":|&XœÜJuœ±íÜjL5«àoW€ó$ØIåýìå 9ÎîûzÎÉ̈á8èôYïäèåìC©dä@¶.$µƒry<~Y;Ã}ž¿8'{VÐ\+Ôw÷‰1ê ³ ò@ðš`;@æùXÉR{5#Y5"±Òw$ûÎIÂ÷ÇY_%« °2ëÑ!~ŸH+AÎ;e\z€×­y[ç–U^_建RÑÖ+î±é+r뱯’U0X™Ê5¾~p¸½û.ß›;nŸi[. å¸1øøJ@æ(ÙË(‹Qüø»PkaœÞ[d#b¸©=½ÆZÝZ&/ØÌ$÷7£ÂäVª&mB‚É*˜¬7`ØfÉæ.&³GˆÅ±\ߎ¶©¿ã…ƒN|±ó‡íÍ^i›ZÊk…-ßÇ›¹]_DâÑcÂ1³7ðz ²ûÿ{˜ˆ{9Ê=pV©`eæ¥`«ÊJFt|¹9)ºõ‹ñü{ÒŒG†j×Ï”ûµÍ“bï¡k}Â%[ýJZ¡@QI¿ñ¦×]~úgKÍÒZ±@§˜nÐ\»ç^!LDä´°"žú¸ž8ç>nòénÚ;Ö×å Q‹äš¨ÏŒkÿvzfåSŸ}.ÚVÑJ„꼑ºq«½&J9±Ò\%R#¨#*ê—a=ww}~~ÚöiE­—´þáa[«:º0©Z(ÕTªcX}˜Méè~²~TA+ø) @¶&Ék^ªûûœúØ9õª¥†*ù¼ƒ†[uZ]?Üÿ¾ã·©ÿÚf 2«T°2*ºâ^ 2ƼY²³·Qç$"bíì ׋¼þ’àTÑe˜Á§”c#"Ú¯¬ §ƒ?Ým®>¸¯Ç9çï 5•‹;1½ZÜ[ãö˜š-eçîPmª«劃¦Ž¿±Dä´+óI˜k÷dD¤¹ea”4÷˧5L)aÛü¨S-c±^²{ *ÍýÐ6Ꭾõužð)v=ì#Qè-ª³;dצïK ‰âv›Lcgí5ZUÿm’žjðÌÁõ¡ûÜÏGÃ_‘»V¾8g©ØÆÚŠm ý4@Ÿkl0Ò%ü(Š_µŽ°k /å ÆgÑìTI^¦æœ@ªu•A%Tß6«’&¬ãˆáùîëàTž§K¤¾iR…{οâà„2­Ó¦ ²06V%dü ûXÙôÔ`¥¹§"¬¤xRi¶z½¬³Ü]%7c©`b;q4|;¡S ÷h Rî™TÛU—ôã&ò¿/Õ±8íÜÏœ(2„é'±_1Ñw¹uü_»šCåñÂŒr zÞëâõ\Îϧ$ü”‹ç•Ü_`šŽ×‡.ŒCVç3î*pó•~›¤†›ÌÆÙ”m&Ï÷¯éÀyóm…¸aº¦;è^Y|/©<ÆÇ6YnCbà"æEp.Evíên©:Q ·ÏGZj‰µs§þ´‰•I½t= 3ýÛõ6Ò?vNëá'¦™ÛÒ|ä:ë`)GCK·‰§3l¹hög¦®°–ýÏ1¨­=Õ3´Y²ª¡aÍ^§ÞJN+wf­ÙgÖ±›%ÁfKÓá«~ €+ËÅX.“¹¦ Hifs¿[Ëö“³¹è®¼ óôY,ø©ôàþ¤z™P]¾¾IÑI¶½WRŸ[á†RËMnt)†ˆEÄ! ÜÔ&)èâvYá³Ö²ùÕR¥vàJvÓr÷¦1»eÖU&•T]¦žéIòäåùë{þ˜Öz™H]¹©©ô˜ù x/ Û3š7¬©N"R¿ßÉRw™Üó[˜îsñ¬“Ü•%·ˆb& …©%aÚ®Sl½~V™ ¦0.—¿ë —'+ @Îð FU6|ÓßÁQeãʆ\'ÄïH‰éõU®¨À,îmäþºâ¬ù«9 OäoÃÉÚtEa“UúïKï1ïY_Z¹OþPe¬ÇÝP·Î·'±¾.É>®›PÇk†šøcòÎóXõeiZ¿øŠ0È=Ð*1D[Ê ääHœQGou˜dJ`õ3–é‚° ýÌO${íŽï¾Õ'’'ø›J¹Ó|ËþQr«×ÛDhÆ·¢¾ -¨½lA€*HI¤wW36'×Ì´6úiIKzæ‡7p!Ь9ù™âR= "¹ó›RÌ÷ÿòf}â;—²¢„嫼’ {øÓ%¾#n‡âFÓœÜ4T¬ìpx­XoÆþÔÉ,Õoýiˆ„>1%OÖa¾¥q{™±^Î'ÖÁŒ*¶GÚË.ÐE©âɬÅMä©Ê›‹ªÅûü ©R³|]ˆ?f+ˆn®Pè?4~Œ¡í°À¯mS…M°&.0ܰìŠEþ;”Ú/°œ™ò\ϱŒ7n’U— ‹ óX5¢µ®ƒ*Æóa,•›ÆjeÉÞ‰aéY\Ò¥‡"¤¥¡²/¸ÈNЂ•…p,÷Ë4S­ Z…D-kJTÒ÷nÙwŽ f_Ÿi¨^‡L8@ŽwýGidW퉫 ž?Ý òfŸ÷ÿ¶²¶ó,æ»4m„U‡ Òi[WýÜXÞ⊣ʬ ûs¹ÄºßÒ Š6¨àìõÍÇð€WþCšfmåõíí-5o;2Éÿû*äE,ÿœÐ” ù ¤W¿Î}K$•#yB> %LÙ(á²ýrT @ŽQ³|ø ómÍðGÖ¤•†²&]ÄÚ›2×üìžÿ&x+ Àz[0ÉH§ãñ^£HTBw»‘Oß»„‹¶†U´¡:o¤nÜjGJÒÝ´w¬¯Ë¢É5QŸ×þíÌðC@rî>Á‚ÍU!ELîõžiç€ÊD€Áúmš¸[)í‡ÍŒ“æX÷Ÿtš½_ùôÐùí°k×Ã>ò…Þ¢:»Cvmªað>ÿã·:Õ2ë%»— ÒÜmîèZ_—á‡x›á]„¯¹~“5Y®p‡‘ý{§ýà!Ç¿ÿ:ÎÞ£6}$?M+øîܼÞЗ|qqœ²o¡Ä#jc-E>át÷¥É’_¬^tNÙ®CDv£S¢ól'ËC¼m‚yaÆvíeZ;ÞE˜˜¦!‹]9ï³öâÏÚ‹‰Èçœ9ÈP³7ïÊ a»] )ž -*6>ÖIÉûµ3§Šù^Ôà]ͤ(áGQüªu„δŒ^OéuB"xãÐE˜u…æ[rc½×û8?Ÿ’ðSâÅq*÷Õ*¶`”¨ˆ[ÐËð^Û«ÜЂ•…0Œú¼Aõ®Çù"†<Æ8)tÇB‘""ó [ò~‹ç¾Ê—éîYåÄ)è–YU·©¨nSѰ±b‰JOkE{ðŽ¶· Z°^/.™À雵5¾ÈšıwÍñ]WCÉI]ø= 3ýÛõ6Ò?vNëá'ú™ÛÒ|ä:ë`)GCK·)F?Ÿ´>ÔkçNýi+¯ão-´`e!·ÿ Y²Ê6 þæ=ÖÆ0…Kðwœ›4kÌnY«6&Õp6_Áôõ!´]ã„îeõ×÷üÏ[ë_gÊð{ ™ÒÀ}q»lÜ,kÙü&+©X[¸é?y†|<Óê³iÉó„)pùÒ ß"Ȉ?’Sû!¬· š2º³Šlýe¼¦bxcÌO¸èÁìÎCœ¨RÞ¸ù¼ÚÜŠYè\ºûßm²ˆdš|ÁŒÈ1iÏ*µ­ðZ¡‹ ó8-Ô¶¶3ô3Þ±XÁÝXÁ·¨KmçKâÖ½ƒÑ1Cò¯<Ê¿r”LV·,€œ£‘Šv½ðZcIà$ªÄ¸gÐ"î·­¼ºÕ¹˜b*Y•™þ;ïÄ"6YÞ °rŽ/»ÐªE^ýtçr‘]ãëg;˦'«À[@ÎQvˆ@¾Á9ùNm!‡…þù™íº–IŒ{¦5§í؃çÈl'ÖN·ÏsÑí٢͓¢¢:+~Ä“Uà­€ çHè÷cü„?ØÅÅ3ÿ ÕÇø‘’Ä­Í— F}HS{:ß)à(XÐÙº‡“û€Ù¿4éaÍqı\0YÞ ¯&ÈAN4ša¢Ñt@ @ÃXÜü1“›~¿ëàõç:«Ól4œøïD§¯£§_ÊNs¦Ý<{ªSïñ¸äðƱÛlÌ’ïxÏö°Ïì~ô]ËÛÑ—µx¼…c¹=Ø1¿ ë)XqÿýŸ=¨Wí¹_$²ìÊeJU©±tjcwš {ÿªÝf¤¨Fÿ"ígÎúç‰{½«'îè¦ß"?«ÙŒ˜§ÖÓ[7F|òMžfÓ_Ö§5O¶žŸoÚûA»‘’šß”øjáÆ»&Ÿd>‰“gxæ¯?£Z×èW¨íÌïÿ~ä^¯½w¶Y×ñ!µú kªÐcÉ®§V¿åk§á»hj†ˆšÍaŽdý&ëµ–·o°SïtíÂõÁM[W5ç¬kÅS+y7Ô½F^íÆ²î«æu->¹S5zÇ÷4vÖw;väÈï¾óî=üpÖÁ;:[ÂãÛ]z¯xúzûóÇ÷F Ý’Ö4”¾õèÕa¿}õJÏ~1iª…¸ÿ6VŸðçÉûZë|t76zô”7‰÷wÏ5^~j´³›åÊùsŸwߌ›^Å£Nó;üª!DD¹ßã•|ÁÆ<÷3 =¬$ohQ®Ç:Žˆ./`5õxs#ÀÊYÖ];KD‘¢/wÐÉq[}ñüÈÜÅ­ qœsn´W‹ç—S¢ÕÛ»‘.îb»IÑÏ·|EDf͹´¦  tËNÏŽüxy^}"2¾8é³ÕÝè·gpÞ”cÇ}·p‚õäâ+?´á8çœ g\›vkmD´uÛ|׎º?¿ @ª~É5žór¡iݘÙÓü§ì±–tŒó‰Žë:—[¸£¯r\€!dˆè–•M)Áâ§"Ú:¼N.‰¼×ð¾D¤zÈ3ÁŒO + Vu}ž^¯P®ˆ("bYkZÓ¼ —ü”äçÁµsKåÞoJD¬Óœ¦ZXýÜJDãN×èWþ›ß‰Hóà kÓürQ›6ÃËuž÷Í’·,,nH7K·à.ýRßéšm!¯ÒñÙBîÎo¬Áé'qh$3¢5hå”}Á«ŠÊËqV·<"š~Yç^cˆ?\º÷Ê gã]‹&©Ñ’#ŽˆˆñjÆÌ/dˆIüNi!!xÂäG &žåˆÈa}œ|Ó»2>1ì>­Î½1‡ïuî3©³;^á‰'Ïkéú×¶õDÄðøÃ¦}š±í‘O2û‘yÚ€ Óˆ^z&X‹1·¬\ñ¾É[ºËÓ_k{n1ºæC:eìË5yË5yúss"êÛ|ð’GIŽ¡…G×W1 ‚—/ÜAD‹;O?D¼ìqÑÝe+5券¼J6^#pÍÒžWéð;›hà­uÙäÈŒž3aÓàz5‹«¤žD¦ˆªµnå”AïÈ]› ×êpê»æE†K‚BÅK̘1alyEÆtÜâ. ßÉ%äñ D7qt:rømÀÅ•bO à_KAv<:®qTQ¥ˆÇÈB• 7:º¢©kÓÜ5ý»Ô,ªóùBñ»Õkl_Ù7 ¤»O0ÂcÓê³é©å Sàú¦B`€L’±/iF;,@HôÁ×>2Bi€Ì€‘Lo´`d0´`d†“×b³iÉk”)Ë—VhÁ@€€ ¼.–gÂi}CëWV½_YÕ½üìS¯­×þ’ höq¥ð*«¾î)?zIwV·,€‚µò4 ùÄ¼é˜æÐ1m÷O¹-B㬉QTÜyß9Â# V>¡‰îaßÒKqÁÀ¤#«À[@Îqs¹ÜØÜ0°½]%åR¶v{ÓŒæLôr¾këœiâ!¿êÕpÊDOÄ•Œ²M]e›™œ8rkèjñ̦}YK¯8ºbª7MšQç óÀv1$ìÒúPK¬;õ§M¬Ä»²s3Å¥z˜Drç7¥˜ïÿõó,V”°|•—?aORGHÜÅ2¦ð®Xc,—ÀÉnÿòEv@}.™Z(Õ|ÐÚ_Frz•Ð3ÍÆ%Âï:èå"u妦ÒcBæ7H<£)ÿ)*ݳÕ)£ Õï54ijÈÈcLz¾ÚÒ 3¿Ö+¥ê’ïÍdôK¼‰ ~*=8…?©ƒ^&T—¯oRt’mïÅ÷[`¸ªχ±Tn«•%aéY\Ò¥‡"¤¥¡²£¯`!JðçúÒÈ®Úõ#¼Þl¶ª©jöyf|U?!TÛy–µm% ×âMhÙ º2 ÇÒ¬­¼¾½}£¥æãmG&‰ýî"/bù焦„ÍW°ÀŸšåÃo˜˜ok†?òø: á¬I±ö¦Ì5‡»ç¿ÉÞ Y¦MÈ$~¿ýRÄtâª)pš ·BÖ,€ †,€L’±]{hÍB€‰Þ"è"È`hÁÈ xáÌ[-X -X™á™VŸMKž'LË—VhÁ@€€ ¼FuwøÝd~ íà,]ÀQ¨€£Ñçì±Çò œ8MY,€lìÐBgóIdcýlrZ¨mmgèg¼c±‚»±‚oQ—ÚÎ;ÿùNœ¦¬ Ã1Ç¡2Öíç¦ÈÜ2Ï5îo–¬âÜr€ß ¨#^ãû]þKÓýµüÃß3î5GF9')yûF1É8qš² ß"D€Õ¬;*.¡¼J?ÖÈ2޲]ó'­1=aËLw®ùéq œ8MY!ÀÊpè"ÈTÅ%)nÚ¥¦Æ¹¼ÖH‹:©)dà‡ÎŠuœÁ$N5+x­0Ñ(@VñÌF¹…^kx"†µ%EE–Øà§š Àx+äÑs;åõŒXÇ%šZ|”dâT³‚× ]„YE#ízáµÆ’ÀITL:§)+@€c}Ù…V-òêÅ;¿‹ì¤#q𲂠‡.B€¬¢ì¼œcrþ7íÑáMlŸ ´ûjRT4ðCçsé/ÕÄ©f¯Z°2U^¥#¯ÒáùÁM ¡ßñþ`ksDsÌüƒVãGz|ëãˆc¹`§š¼V˜ ã˜+ÛÁƒ< ÀȮټ=ÐE€ ,x½nopæU:V<ô]ïš«X§Ãß4JÃßu$Ÿ= `Ñü‰\“nÌÒ1¾a”k |o%7xŸï¦GØá<Â`yXœñ»ÍÆ,ùŽ÷lûÌî'Aßµ¼}Y ›´†c¹=Ø1¿àÁ ü9͖ć0ÊѰý~(KóäçúÆ$­¹³‘½\‘÷eaT^ö€Wåd¼¯ÊaíT­ˆcù-AÕz~Ž­Ù•n]ðjïÈ«tÄkÚ[lùO¹«wø >±v®a¤sÈ9~ãÜŒkkfž ^•“©_!¦Zïä+¹ÓK_~dÿÜ´cþgÎÜM03¢ÈÈb_´i8¶YÆßî Ä¢³2ˆˆÂ­›7˜Ññ=´Ñ@–òè€Óü¿jQî÷x%_8bž3-s3>ÉÂJò†uôXÇmìÂ\^Àjêñ'KYÖ«†?ŸÒlæ®ýWã5f‡Õdºzùã'Í«:ñ ßÄÇÙmÖGqqkVüüÉOwÒt Žu ;ð½xïðF3ëÕöv~ÃòŠÃ6íùßS£uج·oÅΞûÓ‡?ÞÂ5€,åç‘\ã9îšÖ™=ÍÊkùGÇ8Ÿè¸®s¹… ÐbÛÆèÓÂäòàØÏýþzÈ(¢Çtë_ï02ÿ{àÐWSvžûsCFï­ˆRúìÎqë°ˆYWÆÉ37R¿QÁ´¤˜wfÉ1jÜÒµ¸vñ=8¯ÃïNÐþ‡sD´äÇq_V)$æ¬'îü`ÌÞSÖQÿ‰¸ÌEX¸w‰«ïüÅc¥PÆfñCø¾‰C#™¥¨A+gè¼Z¡¨¼ìä•Âá_f#¢ºc†Oj^.¯L –)ê5izxl9"Ú:ãDòô Ãð…âO[w "›9.MÇú¾b¨îñžCÙŒ±ß?4ç·µg;Çщë5,'IÞoІ;½ÔvÑd!—f°eúóã5ÏŸaE¸Ñ'ý‰þz ßK˧ ù*‡XLµÞî÷ÊUñ"šV/·gÊbŸ´$"ýÓ#~rá8‹É¸gó¯D$ ­˜¦‚~Ø¿ DZcþzFD±»~wp\Ý~%<,mYˆV/\UìÓÑçî9oÃÕ€,…ciä:nô0ßõç0{‡ú°Řػ‚²RT^ °üºo㈨‚Ô«MS(ÉODNÛ ?ñYõ>Ò:CÏ>CD톶NÓ±ò”i¥ä3WÿCD‹VÆñø²ée¼¾ÔÐàÛQ˺TWñ‡U³aýÖM‡5šò×c;¾# YE¾pÇe#u.î¼oIZ©»ËVjÊ©¯²®ùÙ=ÿM.ðVÈ:^i VA!sÏÆ]0;jÈ’ò±Y∈/ O)+Er3¾mÛ÷£<®ÅP>£srVŽÄîïF°v"bx^eã •“‹ËÜ:¼ñ~韞Yó¼Ó1¿Àû˳™÷ïŒvC†'×vœºí~ÅR1ŸˆN™’‚q»õ ñ…*ŸÃ5í]”ˆúŽú•ˆjô©à·HâмÝ{tŠÝ3qIß÷‰(îø\cÈNV—aˆèàìY£¶^Ž79l&ýîí1ufÞ ¢fÃ}ÛDÙuëþct÷oëjÍ¿âZß>\DDGo?§c9N÷âé‚™«ˆH^Í'‡BQ- £¾abxüï«+}¶V«ÓŸ©Ö{àŽkj++”¨ª•ÊKD<~®1d®÷4gÔê3+{¥–Æ¢uºÍ¬û`ÄþÇ3¦-šá1‡G…íÖÔVùÝE¤(¼ù‡&ºl?³þ‡U_Ìë–_Ò}ÂÇ“úìzploõ–{ÝɆéý±Ï¾BYÑ!ùijžXBó7¬(õý2ë¢ö…k¯¹»è»y‹¾KZÙ¢_w\cÈ"ÐÁ÷öxů}2ÃgŒß9¦iÝrùÂ$¡XRª\™ñÑ/L«`®Ù<åmj‘ŸãØQßî'¢üUZÜøáË6Õ"ò„ˆx #’Ê*¾[iþìñsk*“ïÛ¥S"*ß%*ù¦Zý‡¯ïÿIâáR>ÈJ•+;{æ¸Í‹à@&û2^òwÂ[—d°ÿ¨Æ øEœD¦IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/dotlrn-style-3.png0000755000175000017500000003330610066530231024576 0ustar frankiefrankie‰PNG  IHDR X' pHYsaa¨?§itIMEÔ 1ÄÊä IDATxÚíÝk¬]Wa'ðcs¯‡øÚN±Ûq§”iZµ•†(J¡AQB§ ÕHDJ‹‚†vL§1ùbb¢‰T>Âd&£ éh>X»QÛ¨LkÁP¨’Bª¡ˆÄÄ$˜ä:ØyÛIl_û:g>ºÙÙuÖ~œ÷ï§««{öcíµ×9Éþ{­µ÷YÑív;´g¥&°,  `\ÌUØô¦›—쯷¶pûÞ•övëÄrr.‰Â½ª6Ñ0O3¿09µÌ@›«ÝËyrµÎ¼œPéúÏÝtsÃ8’ß=ò%7O?´¨ÚaaWG`yÌå|Ì/í5N9Ð}Õ·¡zá¬pßä'½Aáö Ž@l~¨z¹-ì\I®úek#¯â™’é*¼êW]^#a„Oy&¾äªÛ×È—…fms˜t#˜äÞ‹&ž¡^?Mú‚ #6\ž9Ð@û~ cÊ€bYøÐí1ÐæeÝl0k*ÏÁÊôèdz8ÂkÓ›uJf_%/˺²2ïôö}ˉ¬C¥SNÇŽüÑG.ò4+Õ¿oÛvô` `ùµ¿0ô?±¸í+Õ!&säCX8ƒŽIS×»4C,¨°’ˆPªˆÈ©ß܇•OdÉõN¹­´7À·¹Õ[5ËÊI¿A뀀5¨‹z‹ƒŠÙ¥RÉÃ|üƒ¯i€J'¹Ÿ8¹¨uj0D `X€€ ` `XYsñ›nþè'}é3õÖöJ¿¬QÀ¬@ŠÊä¤Ú¥ÕKicedC„…YêØ—>S/«Œj=X½TØíÔ F-vJ¥‹íäFÃc‹}÷ÒOŒKÀjQaVËDŸôeÇo. --fÆøÂ9¦·q`L0½o 7«,i¥÷*[кÊ=X™ž§†]A½}ŽÜ…£’ž*`ÜV|‹Ï^5âZ:TEvGé²&5`E ÜEØ7cÕë6Ó• G9X{ÓhLΰ¬&:´€1 X1 ¬Ó¯Ç¨p\/“Ø"çˆ “½*;h¢æa¥)Vñ+S`Ùƒ™“»óYªÆ}ˆ ­èv»…+Nœ\¬]h+ýC:™€ µR´«å»{cpzž«5¢À@æ`Ì2s°,€ñÖò¬o>ùØ£Ï<»xò̉WWhÜAûo7 f³Å—ž8qêØž=¬ÅÂ~çWÛsRÎz6ß±mg`xë¡£ÿÝüòé×ÞºfiËÅKïÙxVãÔß<ùÎgŽ=³jÕªK.¹dÕêU…Û<óò~ôüÎ,^wÑe¿±õƒ-ôoƒÇÿzÛsRÎz6ßñlg Ò›>ýéO®xméT|)¿ûí¯yê­o~ñç׿üÖ7/­™_Ö²ƒöäK—^ô“§Ïœ9sñÅoY{ÑÚü‡ÿ¿#Ç¿Ù[6¾kÃÖuk.ÓbaO½ðÃãžšµöœ”³žÍwg Ûˆ×BÖÁï~û{Ï<½}ýɵóç5è0;ö“N§så»®(¼Þòv*i:Éý¡£ÿÃ_±Nº#ϼü£§ž?²å­WºÞhÏ©?kŸv`:Öß~âmŸ’®ÆÊO|Ó¥ow½Ñž³pÖ>íÀxj4DøÍ';}niÛú×Ê6øÃ}?èt:Ÿ½m[¥UáÒÒ*íÞ¢|åkœÎ€,¾ôĹås›.þ¹² >ýÕÃNçÓØ^iUXoÇŸ½ìWBí ¡´¶g¦Ó™.j ç[é¬ «:œFÖ³öGtpÊ'ܤC¨0Fëáýø²5KÃyC’®z!¦÷ò÷ý`2ÍXyúÅ'×]tY§3¤Çd¤¯ ŸþÀöŸþ¿û«‡§æßCnÏ1¹òEžu6Q ý}©ç >¢ƒË(#oR -†Ÿ}uù’ÕKñÙ(°$R§äª2§Î¼tñêu5:K ÿUøiçÊ?ÿ¡=›´g …Çê¬G ãë9qQ¹ &]£¬—ÏÎ_¶¦éó®* ·¥»¬ w)Ü7çÊVåKk˜ä%§ëÙz^9óò¥k×7ýŸ{îè…ÿd/ìÈí¾fn“ž¬-˜ô’²xQXN8fõÖf LïU˜Ê6ˆIQÉOYº* IùÓÁE%ÜíTò/õGiøïædX§ôÒ•Y²ðÞWÞñ+ç7¾ë¹3«žþÞæcÿø¾W_ôúÒO·X¡ý+:kýŸ ¿vá_ÿ§÷ýÒ5—¬]»âMs§;+Ÿ{éÅ£Çÿç?zÿ?Þ·ãì±Àî[î_ît:‹ž‹\Î[lêߟ4Èá_m¾þÝ»þLJ®½þíë/[wÑE«Î¼Üùó?}ËsO¼}ó–÷^ÓßýÖÞï­y{`÷Þ…­w‘sͬÎ#k®|ËïÞñîË/S§»v~þâµkÞ|ö•׿ögó?9277¿¢ûúÛ¯ºúпø÷§V®ÑúÀTj¹CèðªËÿéªßúí+ßuþüù5kÞ<ÿ¦7Íw;®üÅõŸyèåsË+Ïžít;×»oÞ¾óï¿úƒ§þ±¬œÅÏm¹yËýËéÞ¬L÷UÒÅ•^žÙ2ý2ù;PZxmÙáb–Ö¤¬Âe'U¶q_bã—Ç”YµØÌ©ŽX¯©Ë>}kM´ÜƒõƒK·­¹zçŠÎŠó.,¿þú¹nçÅïëØŸþ‡Sÿ{Ï…óK:+_ït—/,¯^óæ'6üB“•]2ã£FÙÚ|™É±2«2™ ïò†'U{Ì49©|%ãOª,Wj«üò@ a.²Ø@ jî Œ]ÀZ¼ôç×¼uÓkçÏ9þµ¥¥WÎ.¹xÓ«ßzàìËÏ]³néÜÙsËÎ/_x½Ó9þÖwõ)êŸ/ቪ!¦wq-»Ž–Ø>½Kf›²å1éªð¤Ò5ÏoÜ·%óÕ«qR}ÛªæÇ¦â‰$[Ö°,„Uj|h¢åkI·ûúÙåå×––^¿páB÷õ3+æ»Oîœ?s~Ç¿:uvéµ¥¥3KKg—ÏŸ»páBþ¹c¬0@$ã˜éëzÙòÌ ç8ôšT:©æ%7ÉaZÕ(ÓP °6¿üÄñOŸ|ÛÛ–Þt~éÂ…ù«W÷Ðüüª—ÞùÞWO|å̹×Î;sþükg—6½ðDäeuä ‘»ôÂtx*[>n‘±ÒIUÊC•–Ç—™©U`rU`®•>*­å!«O=þú‘G^|õÕ—NŸyáô™žûI÷ûß<·áÊ¥?zò¹c/Ÿ[zeiéôùó¯¼úʶ›šFŒÌIè lù¤Ÿñ¬X¥Z¥;½`‚Öö¥ãï{êБ§~|òìÙç_}õùS/Ÿ™[³¼|î…s¯?×Yuòôk¯,}õܹ7=ñÝ_{¥~ÀÊtftJn«=xTVf~jvá%¼lyÓ o\OüIUm«²Âëåžp­ WezÃÕ´§”ÀèV§Ó¹æôÞùûŸ{þåÓgž_ZþÎþó·nü¯G7l;ùê+§Î.½r~ùÔ3OÝøÄý—¼~¦yOFþêž¾­Éü¡Â2;Ág+ä¯èUû¨Ϥl\ï4«žTa áöo¥M"‹íT¹í1ð.çx.gE·[<ÙüÄÉÅôË£ÇJÙñØwNþÙ§’—ÝNç¯.Ûùí÷üîE—ož[õæîÊ–ÏŸ;wþôéÓsG¿÷ï~øåŸ~UÎ8}¡»ô€¶ $O¬ètþÍ‹ÿËo=þ÷ë~ñÉõÛ_¸äm+ÏŸû¹—ŸÜù⣿þêÖ&_ö `õIUo´yù¥ûÂ7:/|£ï–Ö28´e¥&°ÆZkãb¼¶YktÚzL C„€€ ` `X€€0æQè¯ê- ÀLùó?úùÕók/Z»j~ÞÕ“|UÎ#‹_ײ̔ÓGV­»tÝ;®Üré¥ëê•àê9Mæ44÷ü³/t:óK›4s°,€q7ì!ÂO|ápúåç>¾½pyfmY ™ z« û%¿Aa`8WÌüEªpIà×wUø1—ÈÈëo ØJ›Å,¬TÕð¡Ç=`e‚Qïå'¾p8}2™óϬMJHÞ†zÍQv”|ùù:ÀØ \°b®e1éjR.‘e×ú^) ížËÊáŸpr†õ>ɪæ QXB‹åÀ¤ˆ  /‘ù¾¥ÂÞ¦ª›®­”,aåhß¶øÓ.,!ÐùÙ°ª™8Ãï’(Œ™?Z¹NE5n—Èzu(lØÖÏeL'¹·›™"’îNN`Ðy¢•tÕÖ%2½o œ¾›eF5L£yVÙDõ²Ä3œ\ÕÉ -w 09¸æWØæ—ÈüdüÂéù‘›ÕnŠNj&ÖàòÆhVÙÐ^æ£0 Ùs}Ë4É€qNNeצړ›ã¯¹ãp‰ÌÄ»Âú'QxVý£½µu©ª:§¹ÉqÓ}`M6ëŦÚC–ƒ¾§må0?"MÆA KhwÏÔ+ÆP¾Ã¦3€©EábÛºD–u2ÕØ¬7#mloG[9üOIdt Î:å#Œù™q•š>©ž9XŒ\ÃG[µ˜±—Ȫ×ßÈ ˜Þ>„§ LLÀJgÌø ïM¿µeM\#!å+/]0AÒ£fù1Ÿ˜1µ¾“¤Ë.‘ñ×ßäq˜1åV.Ä#‰_+ºÝnáŠ'Ó/?_è#‹_÷)`¦<õ­W6®ß¾cë†M õJpõœ&&¹X€€@}y’»§I0kþø½›]=lÀZ>°_Ë0SvïÝåêIÂ!€€ `XX€€€€ `L9MãàÄÉE05ô`X€€€€ `XD™¤ç`ÍÝtsúåòýéåÉË·°üôªLõ2•Œ) ÞuC§Ó¹ñŽ"Wå–•(™iXéì²|`ïåÜM7aLÉľڕ,ÌaI;ÈmÔpã¼ë†ƒwÝ“ºÂ)-]¦†Í›¤!Âåû{"ùcT!¯lIaÒ*Ü%°ïÜM7®-ë-+Û€©”É7…KÒ ×F(p¬$WÕ._À±²¾™²ŒÕ ùØQuù cb¥ ÒÉX#‰›Œ¿ïx ß½Ô[’‰_…½P…»§ Ñw5¾kß¡=ûíDˤÌàZßåÂóGæÂ|°óù †t§Q¸û*° S°’hÕbÆ wç”0ÆŒKUU–Ÿb†óÒÛÔþKú·ŒP[:âæ¡'?í;¡j¬V:TÒU&Q%ýL}g£—Ý*X¸e¥¬¹q`|0û¦L¼è§·gBU»£„á 0ú€Õ‹V1é*ÝåxØf§¨“)G çBŧ–ôƒÙ.\Éz O€Ù4ª%d&Èw<¬¡ÄŠn·[¸âÄÉÅôË£ÇĺsÛµZ€™²{ï®…ë·ïغaÓB½®¸ü*Í85|Ù3€€ `5‘žÖíwüo`„ÌÁ€˜ƒEš!B @À°¨oNÀ8Ø´n‹F˜³ØƒUéû=õ¨6f-Zuªÿà8ŸŽ/%€14s=XùoƒžÐh¥k ¬qÏ[™¼’™Ï4é…ɪäezI~÷²Ã¥wD¨åûõ]€€5p1:Ëö×èûéÄõM& õ–çÓRfûüîU .*´>4´rjš¬0ëf¬ª1+é+Êtõ]Þ¬êá€I1 +=×;&cÕ‹YÀtþKZ8Ê,7qd€‘»çök —ìîGz«>v÷#™{KòkËR˜ºÒJÉÌŸ²?’í§!`õÎ*™´Yó\&T†š21.Ú¦#–¥ó@aWK:6åÃCaX’±zOɬ²&ÒN¿[ùj//;b»ÅÀ€ÒÕÇî~$ÝûÕ)ê›èÌ^’~Lfá=g½‰Fù?½¡¯kj>1]S™fÊ4M2%+3t˜ï÷ o_˜üâw/< G¾ƒ*®z#’÷Ü~áŰYœƒU–Z ŸAšÏ¤árúæâðá*å*ñ €E«Iï¦ê€RƒzÖx½1’žC¾AD¢ií¦Â`‘€Õè½1–À˜h«ÿiš&³÷É@ý¦÷¤o¬Zø }UNú;mZù=l«Ìzû@s³“®S€:o¡ª×‡²¢Ûí®8qr1ýòèñ#ñ…îÜv­Ï(3e÷Þ] ×oß±uæ…z%D^=ÃO½Ê/‰VYºÊlìZ1Vj˜bùg+„R~yºé*’9X0ý«÷l…@ŠÊį̖餫† C"¤žd¢óp~ X `Ñ2s°¬Æz·ˆ|º‡ •ÃÆ¬E«NîÉU“øŒÐÌwú€€5Jù/xžÄtõ†ïë~ãK`äf}V¦7+Z2/ó£Šé…ɪäezI~÷²Ã¥w7: ÖˆÅ$’ÌÆ—¼|`æ{“áÅ|7X~ûüîUW ;º¯@Àhº*Ì:…é¤jÌJL&Êô]Þ¬êáÊÎÚ‡"ÓÂÐF‡VNG{¥CILÛÕˆYã|ÖÀXµ™žƒ5¹Eº€±¾ROGNJG8yLG.‘® õkk:W®*›]ø¨)éÁJÆûbæ-þo²ÚËËŽØn±@‹éªð³üßéYI¡>©i˜NLÃ埉•I£éU™]Û&¿øÝ ˆ‰Ï€A¯Â‹oŸ}g°½ÊâH&o¥ÿ(Ü%ra¥ÃÅ&q §ÚºþÎiÐæ©ÖXLºvû/VjÐ&oCz˜O›À«ÔŸ²rÖÚ¥Åß™Ñöʬ·/ÐJNÈß6Xöà«üødÉŠn·[x˜'Ó/?_ÅÛ®õ>0Svïݵ°qýö[7lZ¨W‚«çp"TF~¶Oø1 é…ùùï?ë(ÑÜÀ,Ì空*pwZïos°Z&`Xµ~¯[ø·IîГÜyCž›¸ì™ÈLÝÜ“¨å÷}Üh~/ÏÍkì¢UúIQcSòŪWɸS4阙±#&Ú$ÍÁJ¾¶:üýÕCyeKúd—À¾á§™ezËÒ‘Ë÷öÀ˜˜€¬²1µ²ŒUö¬°ªËÃ1¨pƒt#ôúðÒ}cz­`¬Œ¸kß¡=ûíD ôôÄ,ïÝúvåsaafj×ò‘Fk”=XI´ÚwhÏm×ÝÙJ™á¾œÌ·ö]žÙ&?Û)­²t•tƒ%™,fwVj˜ñ4V¸PÇUsš¦LdÿS~’m÷¬ô)¿ã0Åá)ù)[•ÏO‘ôZµeE·Û-\‘ùNï£ÇĺsÛµZ€™²{ï®…ë·ïغaÓB½®¸üª¾Ñª,åWe–ôÝ·p­Iîµ™ƒ³«Iw ] XÀPHWƒà.B˜ÎØ”~®U@øY£Ôc’;´`“Ü™ “у•ôÀ¨ž`^ø„v¿¹ÙÃÙ@À^¦É|#჈ LÌ$÷ô×3{Û€q61“ÜÓ]V錕 «ޝ¥GôÊVåK«—ä kRV`ßeN§IÅ€!qÖ¾C{öÚÞ&2ʾ&‰_é ’ŒR¶*ów`ûª1+\`ß•¥«&†f”=XI´ÚwhÏm×ÝÙ7c¥¿k/Ó‹Ó{Ùë=JÂVYOO s¨FŠ*¬IddŒ©^þ}j@Àê“®"3V§Ö$÷˜ðU¬—bêP)Õ%Á±ÆÑ€ Xµ%“œ"“MÕaµÖãK¾ÀpÅ2ýpµÃ%0së¶ëîLwbº¯ýt¨ Ê+ñဉ³iÝ05F9É= U};©Î›ÀÝ‚e«2¡$é *œ5Ÿ9P+®°ÀÀ!ò“â[¬0Í«­"§^uJ¬É1ùaµÂÈR¸Yæ@Í»µÊ T¬R9Àxšøï"”9Í¿‹Ð7ùN“•š@À°HÏ^/ü™Ÿ4;¿€±5ñs°`˜ƒEÚœ&€IqÏí×d–|ìîG ·I/ÏïU¶/Ìhºê£ÞË{n¿¦oNJ6Èg¯@zËì%–Ub’;L’$ß$ •õZŤ·L€+\Ž€Ó#o’ГI`µ;™ÊvÔk%`ÀtJÙv#eVêjJDz² §ï*ÞÌÁ*|*AÃG·žÿž^å1ñŒaÆJÞ ®oIoÖ”¬A'*˜è˜•~™ž¡Õë誔‡2óèû.gâÖ$¦:hÌÊÙ5Å“®¬Ô ¤3Ou_>°?3¼˜ïÇJ6ˆ.,Û%½<ÿˆy‰ €†bÆc%] Áˆ'¹ï;´gß¡= ÓÕòýé OÉ–É…1(|ÄÂ]òQ¬°¾å€VbV2Ͻp|0‰ªNu¯´œÒÀ0Út•üqÛuwÆd©D/¯„;„úv%…ÄçžÂ]Ò骰´˜Ú@ßô“6Õ Ò[>WyÖèĬLÇUߌU–NƼO¨—·Â‘Ÿ±š,#}Wíšìç`e†Ç6cUˆ¬:2ýU}‡'¾+°†š±¦«ô\ÌÆ O½’óí+U°ZÈX‘é*I*eSšÂ·é%kÔ“Tvôü“#|æ`ê­èv»…+Nœ\L¿èq À¬ôÌñqþÝÉ=M´ïöÀ´2 ZÐ|Ö—_¥§†!B @À°°, €(sš&ÅÁ»nÈ,¹ñŽÒ«’—ù…}7˜z›?úÉN§sìKŸ©´JÀ€™HWéÀtð®*Å£Èí3I.ãòËÉ0D“$É4ƒ 7é$— sé…¢µñ×ë¬ /°`¶¤3M:ëÄç³ÈT.yêû®6ô“½ŸüÂÀÉöL†t¿Qî£ðîe}T5òÜØ†§Â¿3 {S²bz¼6ô“Éü­ÞZ &)c5Y5BRz—Þq'wv|~&{fI:]f¬c_úLï'SBz‰€“³êÒwDzÕ;zznyLjÌܾ™;§O2qJÀ€™Ö|êU&c••V–®Ú­ÀåG÷,˜õ˜Õ)¿ËÙ5œ&Þq ’VY÷UzÞUízÐ(©kê½÷½á"zë-Ówv“{RIŸSYSoƒÌ}1ÆD¨Þ¼«Jå³c_úLúֿµMï¾¢Ûí®8qr1ýòèñ#ñ…îÜv­ÿILn´:xë-Éˉˆ#‘Éi k÷Þ] ×oß±uæ…z%\qùU>‡SCt´Jÿ‘éÐ,b•uí$K’ 2[vtn“Nlùrµ*,¼0æ”ß=æùU7Þ{ß”–2h&¹P-‡©J}]I^ ì•^•P™¸–$¡ÌòðQõ¯}jŒ­ô¤õ!ü6 ` }ñO~yÇΛv¼ïÃ6_ŸœòýR\ÏSx—Â#W…ëÞ&ÐV¶YóJf˜ƒEš!B€)ô›¿w÷ÿô7_ùìG6l¾zÇûnz÷{®_½æ’øÝÇ­ç¦lˆ°od €Ö¼û=׿û=ןzñØcÝÿЃŸèÁÏè÷¿Ù›5Î"Gî ð1ræ`L­Å#=}äá¥3§6l¹:܃5æYDHBÀ`ô~ðs÷íyÿC~þíWíüÈî¿øÐ­_¼ä²Í‘Q¦—fúfšt&+œ¥('°W¦ð¤>…• G±ÀfáúçWAU&¹L¡¯|ö#;ÞwÓŽ®ºcþq£áYäe9È<ã SÒIÖä1 …%>?"ðlˆ˜Ç4ÄTµÓÆ$wWOËG€:&ñËj†v¡«ç41DÙD•yòXÐHzXz XÄJÏæôïNj.Ô8ÿNBUáÃW¡/s° æ`‘¦ @Ào¾*&Ã=·_Óét>v÷#‘«z { WÅ,DÀÞ­ziéžÛ¯)KT1q*Ô Xæpt À„†§À’LÜi’{Òá)‰k1G°€iK`™PU˜>v÷#‘ñ¨,¢U°`ª"Tþïæ¥F«$?ö]IWL¼| iqjì›î “®, Xßn°²iòX0m‘¨• æ}3Sà&Á^ðJ60á]À€I•:e#†•æKf»—¥«Þܬä'2« XÀX‹׋ܲR¤#†Àäéõ9z¤:©‰S1 )üȆ¾Ï%cE·Û-\qâäbúåÑãGâ õ}àÌšÝ{w-l\¿}ÇÖ ›ê•àê9M ´l C„ù/~ôñçŸ}AûV;æWϯ»tÆ`¦¬»tÝüêyíÀ ÖÚ‹Ö¾ãÊ-ç—6i_fÇüêùµ­Õ *`­šŸ_¥ ˜U&¹XÀLñ$w ™G|3Ñô`X€€€€06rá¯ê- ÀLùó?úÞW嬚÷u„ &`}îãÛµ,3å𣯻tÝ;®ÜâËâèx´âùg_èt:ç—6 ¨üƒwÝP¸üÆ;è­ºñŽòÛ÷î›Ù fN’‡ ãT¥"3\æˆÂ™€T“¤¨¤Óëà]7¤ƒ”P5Žë_8Ü ÎÍÊoÐ[’÷¹o/\•ì›_Û[(°oUÓ ËŽ^v eKÊê £’OQµ;̬1• LùðQG’Ô’1ŸøÂáÏ}|{ß3å„7h†õô¡`´Ñ*?&˜éßb2V’6ÚJI!eÝ]ã"ǼžL²)VáÈ•™‰•7d¬V§ß(^Ä–Î.õêS5íõvIöʧÆÂÆõ€H1Á(ÐSU67‹B£’{&T5ÌXéqÀæq­yeÊbS»õ€æŒ¶h‚ï"Ìä’LWP2«©Ó¬«êÑ«fÁæõ€Á¥+“ÜëqV&XT(ìõ%?…k ÃP“yôøn¹¶ê ÀÌÊ?M´õge%°„­Hã5ɽu 'WݽïöCé €&«7;*•b&¹ç·Iž/]M^ÀŠyüU¥¬ÖâX[è“ï–ËO´2&@í,Uiyd*j¸;£", ­ÜN˜Ll~Ž «l$q$õg¨=X펂N3O:œ2Oòl˜™ò5o8É}õÆÄŠn·[¸âÄÉÅôË£ÇÄúÈâ×µ,3å©o½²°qýö[7lZ¨W—_¥§ÆJM `Xµ ä.BÏÌ`Öüñ{7k°–ìײ̔Ý{w5,aÓº-šqj"°,  @À°°,  @À˜,s#9ê=·_ó±»é»öžÛ¯É¬*Ü+\ÀL¬xéätÏí×4ÌRùÝÓ._²èLRÀ*Ë.ù^«tʯí•Ó7 ›Ù+ý2P €°‘ÍÁ ¤¥®RÉU·}ÀjEÈ ãÀHŒrVfh¯°û*›ô*V !,“·ÊYÌL,€éXI*ª— VûùLÞÆÍè'¹×ë¾*ÜÅTw`Œ{Ö@'¹g™ù[@+Vt»ÝÂ'N.¦_=~$¾Ðۮղ̔Ý{w-l\¿}ÇÖ ›ê•àê9M|Ù3€€ `XX€€€€ `XX€€ ` `X€€ ` `XYs7Ý¥M_}@ÀB’ç@ÀªeùÀ~´enÎ!Õe’D¥ÞÂåû“?ʶ̤«Âm2kÓ¥åÿΔS¸0_¥²ÂÇ ×¶ð¼bê®F¸qò…:æM¬QC#îÁÚwhϾC{š§«åûó ó2¼ea¨=Ú5wÓÍùxQXtΫbΨj}š®ð\ÊòYL³W­!ŒKïÏhÓUòÇm×Ýsu¯ª^¯Fo¯&="I ñ=L_ŸÞ6I kØ9”Þ=SrL³¡†0U+ÓqÕ7c• U_á-“‹wÙ¾0%Ä_ã+ÅÄÈc5éש±ï º‘Í®× kdâ;0ún™î t·ÔN3­vµÒ½”éÙ tt ¨¯¨°ÙëÕFnds°2ýU}‡Ç'±%×ûÞÜ Q óXùø5üÞ£J§æ‘X¡ŒÕ<]%=‘3µË¶ì-èe;P~½ãÆŸ{|}Ên±Œ?\¾ó)ÃÍ^µ†0Ó«­¦«Â»Õjo_Z“ªvJ¸Põp k[VŸæ ˜>—˜©èe%W­!Œ‰Ýn·pʼn“‹é—G‰/tç¶kµ,ƒæþA`¬ìÞ»kaãúí;¶nØ´P¯WÏiâIîHWÐöuJ0¡é `Êüå7¾|øÑÇŸöM1ƽ+=?Úo¿óÏÊÊ,˜\ó«ç×]ºnaãz?Sðc´ ù¬sçÏŸ~íôù¥ós "€±°j~~Õ¥ë´Ãt0É@À°,¦:`Ýxï}™Ÿ!=ra+%aßÛ9ÙfÈoJÕyõ˜5“qáÁ[oÉä€ô’J—áz;Έ¶Úy*¥SZ¾YÂmU¶oÕå™ ¼;V›!` :$z×ãqN0×ÎeÙVwc&%/û–_¶oÕåùÿXÃîWÈ/ï-IÿÓ¿ï¾áô“Ù¬ìBX/xÅתð,Òå„O¶a;7yG"÷ ´I>öÍ"…Œ&o\¾yG’#+“7É=±b¦ä¸ùÞ«Fòõï{²3gÄ=XûíÙwhOÿXª2K óG:Xä³K¦g¨°¤„@¼ T¸p¯92FùÍÊN¼£ f'`%Ñ*&cÅ„’ÂîœôªpÐ),¤ïqÙ%)0¾ÌøÚ‚—,3°2¡*±ò1¡ÏĪ:U<©ä€æ˜÷-VÆ€š˜9X£Û^#¯¤ƒ`zðqTõ†fd=X·]wgàea¤˜Äñ¯QÕÖ£`V:TÒUáío‘£„™>¤N¿{ýúæ•øñ¾ðà`ºJUp–¯OßAI‘ f"`õ¢Uß¾«&Ò+W’å}{˜T¨±WzyaQç>ô­Oáßñg ´eE·Û-\qâäbúåÑãGâ ݹíZ-Û"O±»÷îZظ~ûŽ­6-h |Ùód¤+@À¢eº¯@ÀjMzÒ÷lþî¤&fµR0hæ`@ ÌÁ"Í!€€ `XXV¼ï½/ó3ä£G.l¥ä!ìÛb;'Û ùM©Ú #¯³fn"jyðÖ[29 ½¤Òe¸ÞŽ3¢­vžb™6ÉG·ÂKoV¶{ÌòÌÞ«Í0½ëô8'˜‰kç²Ælë, Ëɱ¬¿3žz/«.Ïxüÿ @Ààe5² ·$ýOÿ¾û†ÓOf³² a½à_«Â³H—>Ù†íÜä‰Ü7Ð&ùDØ7‹~0bÞ¸|3F&¼áäHÆÊäMrÏ_,ÞzKæâ×»%?霑ٸpßdyß«iß‹nøYxˆÂ’ËjUvùrò Ò¼ËöŠ|G"÷mØÚ‘‡œpwÖ(CUzæuú•ü¸nú< 7¨Tfú|&hr=ެUßåñ Ò°ÓÙeøïHÌ[PX½VÞ¸˜½š§+ù `RLÞ$÷Èí«H 3,f‚KëfÌYD6H+ï²¹J Ç([lÿQWº°&^zOÙ•©õËUdZj÷y1 ÒV|IkÈHÞ‚ÂC”U¯aÌí»o[ç›ùäˆ\Ö(“Öð;-ÂW¾˜[Ï&·Aú^òG{Üp’Ð Êl~ C3ñOr/|Öeäõ;½oáî}gsç·‰™_/p”±ì,ÚÍpñÏmëi˜ ûŽ Wz㆜ɘt“݃ջ(æoà/›ñ“¾£0¼o²YÙE7üà€ >ækUvá WoN[ÌÓ+òõLnì[ø£´ØŒù)qýg@ú(}?¥­µ¢Ûí®8qr1ýòèñ#ñ…îÜví,·©. o0ƒvïݵ°qýö[7lZÐø²çö/ÒÁ€€EËi½ Þ8fÜœ&h‘+´7:z°, @À@À°,, @À@À°,  @À°°,íÆ{ï»ñÞûËË6ZM†Y°,ÆÏÁ[oét:™þ¡ÞËÞªƒ·ÞÒûhÑœ&˜eé°•‰bépþ»°Ì²µùÍË3;xë-…ÇͬÍlPï¤ «‘ô`ÌP Äšt¼(ì÷ª‘ØbŽU©á*Ýxï}ù¤Xï¤2AÍ1,€)÷Å?ùåÿ{ÿyîØc‘Ûö¾ ¨K&3øXMò›ÅŸK`L³F1Mg `úýæïݽtæÔW>û‘¯|ö#>|ÿÒ™S­‡¤²1µÂ„4  Ön§QÕ“J6p‡#õ˜ƒ0aÞýžëßýžëO½x챇îèÁÏ?ôàç?ôû_ܰùêÀ.½ÉI‘S£Æ¡·¦õ:Ô(0ÂÒƒCÀDZ<òÐÓG^:sjÖ«W¯¹dq§2ʦ™OœÈ“’«°fÂÃ~î¾=ïèÁÏ¿ýªÙýºõ‹—\¶92OÄ$†& Íôút‚3ÀÒ›µX‡VNÊà ÀlyúÈÃïûíÿxË_ßùÛŸˆ‰VUãQ§Ù«¾qÈl–Ù¦•:4/°õj0kVt»ÝÂ'N.¦_=~$¾Ðۮղ̔Ý{w-l\¿}ÇÖ ›´z°, €QIO$÷»ùoˆd´À,Òô`X€€€€ `XX€€€€ `XÀØšD¡ù/~ôñçŸ}AûV;æWϯ»tÆ`¦¬»tÝüêyíÀ ÖÚ‹Ö¾ãÊ-ç—6i_fÇüêùµ­Õ *`­šŸ_¥ ˜U&¹X€€€€ `XX€€€€ `X€€ ` `X€€ ` `X€€€€ `XX€€@À\ävßyúk †, @À°¨/v’ûßþè cE·Û-\qâä¢Ö¨Á!€€ `XÔ÷ÿ‰²»| gò|IEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/upgrade-cvs.png0000644000175000017500000010545710027550273024227 0ustar frankiefrankie‰PNG  IHDRÏ?Æ |9sBITÛáOà IDATxœìÝy\TUÇñÃ6ì²( ‚(*¤’+¢† ˜€kf%jdnYZf™e«f©O‹mî–K™î–¥æ˜n †.à"È"Èóüqqš˜a@äŸ÷‹×ó\Î=sîï^¿νc T*Öt@EÚäBÚäR‹Óvˆ§gˆ§gYŸê}® Zñ%UÂXú?)XGE•Ú]V{ý¤¿Œ-,ìÛ¶m÷ M}}k¤Œ*ù¢(‹Šâ¶o¿ºsgÚ… ù†&&V..^^nC‡6êØñÏáÃÓ.\èõõ×®ýû—záµÝ»MŸn߮݀M›„IÇŸ_µêιs÷îY899uëÖjøp‡ÎË= ‰±¹¹»{›çŸo>hÐß”øTŽqMPeª9 fgß>uêö©S}–,qéÛWwgýLi9ÉɧN½s¥¸°0ýâÅô‹/®_Õzøðsç^ÞºU3m_Þ²EÑjøp!Äõ}û½ñ†²¸XÚu/!áÊo¿]ùí·ŠŸuaNγgϘQ\Xè6thœÛCÓÏ/¨uêNÚ®6RËMM==~üœ_¹²Ü´­‡Š æLIвprztòä&={š;9) ï%$Ü>}úʯ¿ !Z ñÅ·ŽÉNJ²prR½6ûÖ­[G›™µ^ñØ'Ÿ(ll„¦öö®¸P‘Ë(1µ³ëüÖ[—7oΈ‹+µK÷I•ûÝXœŸ½víÕ;ï^½*„hмy‹!C3ÆÐØXºìç–.½¾gOö­[Fff Û·äùç}}ſʺæºÚ¾†üþûö'ž0R(†8 ].I~fæo}ûåå=«ö§PTrnûð;ï$„…IÛ7öïOýçŸA¿þª°±ÉKKÛûüó9ÉÉÒ®Ë[·æ¦¦jáí·U#HLœ¨ÚN‰Œ 4)0$ÄÞÓS‘—ž¾o̘ì¤$!„Èɹ¼ukÎ;©óè»ïÞ8p@Q˜›{~Õ* ''à`!DÅëÔå~p/÷ÔTLíìšùû_ݹóêÎmÆŽUµ_ݹ³ 3³õ¸qRPÓq)´S*¼óNüŽª†¬ë×/¬Ys3,,pÝ:­ûêÎBˆ¯¾úoÔÖ¦uPPIÚž4©ä|•Jiæ[JäBs'§{7oÆ®[ç>j”©­­ŽÑtQ*…F E%Nª¬ïÆâüüý&$GD¨z¦ÅĤÅÄ$<ØwåJC“ð™3¯þù§´«8+ëÖÑ£·Ž­à¯[åþoyjßÖ-Z4ó÷¿¶gÏÅ <_zIÕçò¦M…99.ýúUäР©ä3Iî^¹ÒýúQ‘‘ý×­³rqÉNJ:¿zµâüêÕ9ÉÉÖ®®%{ׯϸ|Yë±±ý~øaÔ™3ªpã:`À€M›FEF;p ù AÅ……Ö¬‘v]øþûì¤$«fÍT½[ư¥ä¤¤<ñçŸ#Nòxî9!Ä•ß~“Ú+^gYòRSOö™ÂÖãÜSS×:(H÷Çê—6nB´zæéS—B5fpT”ô!„¸´eKüŽV..}/:vlÔ™36ntèÜùn\\Ôwßi­?=&FѤgOݧ٨S'›V­²nÜH:qBjI:~<ëÆ ›Ö­uê$µ´ùe!ÄÙÅ‹·ôêõû€‡Þ|3nÛ¶âÂBÝ#«ËKK‹øê+!D“^½þ½&>©²¾/¬Y“¡°±éõÕWAÇ8q¢ç_(¬­“Nœˆ^»V!ý&Öõƒ‚ÂÃGEDþò‹Ö¼«õš—;¸J©ï‡v/¾(„ˆ]·Nu‰”EE±!!Bˆv&Tü¢€Z¡’iÛûöoohbÒ°CïY³„7þúKq34Tá=kVÉÞöí½?üPëÝ>úÈ©[7ÕßÜ…½¾úʾ];C ''éU)÷'¥T¤yÐru›=ÛÚÕÕØÌLZq÷Ê©½âuj’ž ·¥wï+Û¶ !Ú½ðB¹§¦Î©[7ëæÍÓ.\Påû´èè;çÎ5êØ±AË–å^ ­.oÞ,„èùÕW.?nbmmhllïéÙ󫯄×÷íÓú’üÌL!DE¦¢¥[!/oÝZr¬­[…ÚĶ¢åSOõûág??csó¬ëׯíÚuôý÷wåVàï%³W¯Ë›77êØ±ë{ïUâ¤Êún”死͞í:`€‰¥¥±…EóAƒºÎš%„¸ºc‡êô“ÂÃc~ú)éäɆíÛ÷Y´¨Üš%å®RêûÁ¾]»&>>9·o«º]ß·ï^b¢CçΪ_`@q?¥RY\l`øoþ.yÊ„¶õŽ]º¨¶ºvBÜ»yS‘uó¦ÂA}¯Ú¶:éUÿ«¨(zíÚøíÛ3ãã ss¥Æœ”iCVó å²uw—6¤õ…99êV¤Î²››ÛµiÓö…4o‘,·¶ÖÇG|õUÜï¿wzã qb»åÓOK{u_ ­2.^Bì9RsWvb¢Ö—(¬­óÒÓóÒÓÍ6Ô]­ÛС‘ß|s}ïÞ‚>B\ß·ÏP¡(u/£S·nNݺ)‹ŠîÆÇ'Ÿ>}~õêôØØÓóçû|þ¹îÁUŒ-,<'M2kÔ¨'UÖwcæÕ«Bˆ¦}ú¨w–¾^ÒJ뮳f}ï½ëûöIñÝÚÕµÏâÅ6­[W¤àr/U’ºv/½”xäHôÚµnO>)„æÂÛ2± @]T’­¥ÛÝòÒÒÔ÷奦 !VV<ªZ@×¾´Yc33õO#¾ü2âË/Ó¢£UùRQ\PðÀ‡.Uˆ‘‘ÎÝåשIZK0âäÉ€ŸÖú4’R§¦©å°a†&&WwìJeavvüöíÆææÍ”öVâR(ËÞUÖŠiLâáúKB˜ÚÚ6ó÷/ÊÍß¹3~ÇŽ¢Ü\×€õ;üT ŒŒlZµjôøÊ•Bˆ„¿ÿ.wðਨQ½.BüýÚk©jko*qRÊ¥oß§è½pa›1c,œœ2¯];þÑGU2²:Íï'oï†:¤EG'…‡ßù矔ÈÈnnµñÉ6 \%iÛ¦U+!Ä­#GÔ÷%>,„hЪ•æËnŸ>­ÚN>yR!=ÂÊÙY¡~ëX²Î%*ÒªŒž_~tìXð?ÿ…‡«ï•†ÕþÒ¦M{‚ƒµÐrØ0»¶m³nÜø3(èÒ¦M÷Š ‹rsïÆÅ]Þ¼yÏsÏ©wvòö¶vuMŠJвnÞÜÉÛ[}ïîQ£.®[w7.®8?¿¸  õüù#3f!¸¹=À1¦uëÔ¨¨‹÷Ô]ñ“*ë»QúâÄœ9×ví*ÌÉ)Ìξºsçɹs…Ò“Âÿš4éÖ‘#Ò®¡¡Ba¨ýNÍk^îູôíkÓªUÂÁƒ×vï6kÔˆ§ŒPW•¬Ûv5êê®])‘‘aS¦¨ïvèÜÙ}Ô(Í—Y·h±[­ÝÂÉIºY°Ý /H Žw!íjêë›yõj9+:„hÒ³çýûN*}êüß·Co;aBüöí™×®©ÚÔ×7ëÆŠŸg)•®³ª4îÞÝÚÕ5î÷ß‹óó­›7wôòRíÒ})„Nݺ]Û³gÿøñÒ§ÁQQ-Ÿz*õÂ…Ø_~9úþû,ÀÐÄÄwéÒƒS§¦FE•¿|ÂÀ Õðá‘_-Ôœ¢rçÜ9Í)a#£÷O¡" ŒŒº¾ÿþþ ",pé×ÏÜѱâ'UÖwcÛ±cÂÂ’#"½ù¦z'oïGž^‘xèPâ¡Cê»\´Bóš—;xy'lÐnâģァ,*zdôhCõG€:¤d&ÏÐĤßêÕ¦Nµuw—fUmÝÝ;LúøªUZŸ­ÑsþüVO?­hÐÀØÜÜåñÇý×®-yg;»€Ÿ~’O¡°±iõôÓÒS&´.óU×ýã›ùû›™)¬­[Vêî:S[[ÿµk]úöU ۳·ßiUé:«ŒA«áËóó…-ŸzJ}îK!„ðzï½fÒÊiµµ]ßÿñU«\-œœ ÌÌlZµr920$¤¬,œœCBzÌ›×ÄÇÇÌÞÞÀÈÈØÜÜÖÝÝ}Ô(ÍWµ6ÌÐØØÐظå°a¥v Ø´©Í˜1¶Fff†ÆÆNN®k×>èÓ£ºww ,ÈÊ:ù¿ÿ=ÐI•õÝh¨P<¾zuÇiÓl=<ŒLMÌÌl=<:MŸ®zv¿ï¿wé×Oacc`ddåâÒnâÄîsæh­Móš—;x¹¤s-,´þB ê¥RÇÝhZ”zËÆr]ùõ×c3g:z{ûßb´~ª-uB݃~7ê•«;wž1ã‘Ñ£½Ôž{ê˜J>o[‡ƒ¯½–ræLq~~Affüöí§?ÿ\”ýúT[êDT™ym÷n¡me¨K*ùÎí:ÜØ¿ÿÆþýê-vmÛ¶.ï)Õ¯¶Ô‰ºGš’B4íÝ[ó½H@]RõsÛ~ß~Û¤gOkkC«fÍÚŽïÿÃzxXm©u’‘‘S·ne-uƯÛPAU?· @BÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäb,ëè¡¡¡²Ž¨üüüjº¨$¥RY僲UŽÌ  6ªú´­µ=<<ªvp@=+m¸Ô:r¥mr6 jI™›À  vá.I@.Uœ¶™ØT˜ÛäBÚäBÚäBÚäBÚä"KÚ¾zõêˆ#ÜÜÜzôè±aÃ!„³³³³³sŸ>}víÚ%móÍ7žžžÒ¶55N–´=eÊ”'Ÿ|2::zÖ¬YÓ§OB„††6nÜxß¾}½{÷nذá¡C‡–.]:þü›7oÞ¼ySŽ€'KÚ>wîÜ3Ͼ¥Zô¡ªÊ!mà_ ‡:û;2bé·Zo½yäh§—_Ò,Æ©«×ßïͺ1D!„Rù{г}>ÿ$ûv²fy‡Ö^¡Övib[ú_U…ªªj×—F0·  éÌw+sRRžØòĆ_²n%]±Jµëvä™A?­ºucÎ;gW}/5F­ý%5:fàšUOïøÍÈÄ$ré·ªþI'O|·døÞÍúôÿäs©1lÆ{ŒþÌÎmÏìØfÓ¢ÅéEK¤ös«ȸ7pͪ¡[Öß»•$5û¿öÇØ·Ëù¢;¢¨Ú;ç/ \³êÙ¿!ήX÷î“[7úiÍíÈ3ª>êË6rÓÒ3¯]wèØA³»Ö­L,-“NGH=o:­hÐÀ¶U˲ÊS?tYjm—vð‘0UÔV¯ªv}ii@ÓÕ}¼^Ÿjfgkfo×õ×â÷îWíòšö𙽙m×i¯ÅïÞ+5^þc‡×´W-L,,:½2ùÚ_¡ªþÞo¿iáà`ljÚæ¹Q©±¥ÆÁ¿¬qêÒÙÈÔÔÄҲ䉉ÇOHíq;wwþº…££ÂÚÚkÚT©ÑØÔ,'99'-ÕÒÉ©û»3¨Ú.S§˜ÚÚüÛmÚTS;[3;Û.¯OÕzâ G5öö246ÖZL«!ƒ.ý¾]uÊ­ÔQ^éCk«PGåeUU»¾4‚•$šrÓÒ¬š6‘¶­]œsÓÒT»¬š4.Ùpnš“š*mg''ïó‚B(•Êââ’µB!LmJ§±©©²¨HÚNù'*ré·©1±…¹¹BUÿœÔT+禥ŠéõÉœ¾ÿñŸ5k¦]§¿æÒ§wÅ«5oÔPµ“šjÙØ©ÔYˆÿ>nüæ¡Ãνz–UL‹þgV¬Î¿{W©T& ÷ž1]Gyê‡.«B•«S¯ªv}ii@“™]Vâ-kg!DÖÍs{{Õ.­íæ ®\fáàPÁñ}0»óÔWšô覰´,ÈÎÞ0¨d{û¬› Ö®ÍÔ;7lÛÆ÷‹O… GÃ}ò™f¤ÓQm©n÷n%I‘1+ñ–f‡â¤“§½g¼YV1 kë&ݽãvíQ*•M}z(¬¬*RžŽ +Ry©ªj×—F°’@S‹€~§.ÉKKÏMK?¹`Qó€~ª]§.νßÞ¢€ÔèþÔ“áŸÎϼqSYT”wxöÝãåçš+L³oÿüKU»Ûà'¿^˜œœŸ•ujÁ"©ñðì9qñÅ¢¸XY\,5ª/¶ÖQ­ºæþŸZ°8/=#/-ýôÂ%ªvÕP·#ÏX7w•n ,«˜VC_þ}Ç•?v¶2HGy¼žeµ+¬¬î^½¦µ*ýÿÒ”ÂÜ6@i^šxò›…¿B¸öëÛáÅT»;vØ9zlavŽk¿¾í_/5¶{>Xˆ¯MÏII±qká9nŒîñ{Ì|÷ԂŇf~déäØ6xÔÕ}¤ööÆE,Y¾óù B©|tÂX©Ñ¥WϿߟ•yã¦Móæ>³g>Pµÿé6iâñÏ¿üí©  ó6£F$†/Õ¡ÔSö´ÓØÛ+?+ËÀȰ±W— –§£Â²ÚÛÚ5á¥Âœœà#a¥ªª]_!„R©Ô}È*„ððð¨Â1BÄÆÆ !üüüjºÔ)!žžâ¿ —Ëéïã[ñÎúìîÕk¡o¾=tózõÆ?F>×kîGvî5U•V¬J?¿4!>¾ÌmÔ'¿YØá…ñÅ…K–¹ôîUjï~©‘ªtÓϪ*Ž´ P_4puÝþìó…¹y.½{vxIû‚T-Ò6@EéáZ…âñÌSϾnjwIr!m?i ÛЊ´ È…´2I·Ù ÒHÛ¨º£|jLì#Ÿ«¶b´Ò¬P¦ª*ù[R±ôÛ̓7÷¹|…P*«º.PHÛÐG ‡:û#7-]êâãµöçÍý‡l2ìÆÁ¿£Öþ¼yÀ[‡ K<~BÕáüÏ![?¹±oà±ÿ}Vœ_P‘J ññ½øë¶mO\ߧߟã&¦_¾¢ãµÒlnˆoYÓº7uîåó—1ÄÇ7zæ߆­ëý¸¢(/?ü³/6 Ú0èøg_ååKÝ´¶k­PU•ÖÕu•Te„øøj-^uˆR'«{Ø+îîøÒ æš7jÔqÒÄ+;ÿÔz%@Í"mËåÜê2®Ä \³jè–õ÷n%Ùµnebi™t:BÚ{ëÔiEƒ¶­Zû¿öÇØ·Ëù¢;¢5ljZûKjtÌÀ5«žÞñ›‘‰IäÒo…_™têë…Ê¢¢âˆÅ˼^{U6ã½GFfç¶gvl³iÑâô¢%ªArSÓ†mÛÜqÒ‹G>š—›š6ì·M'½±h™ªÃíÈ3ƒ~Z3tëÆœ;wήú¾"5hJ:y*à»%Ã÷îlÖ§wø'Ÿëx­4›|$L5­«jsÓÒ3¯]wèØáá/ãó®Yõìß„g¾[™“’òÄÆ'6ü’u+éìŠUR­íšªW¥õp:®’TFð‘0­Å«º•:YÝÃf\‰³oóˆ´mÿˆGÆ•x­_P³HÛr‰Û¹»ëô×-ÖÖ^Ó¦ !Z té÷íÒÞËìh5x ÂØÔ,'99'-ÕÒÉ©û»34ǹüǯi¯Z88˜XXtzeòµ¿B…vî¶­[ÅlÞ»ykãîݬ›¹!ÿ²Æ©Kg#SSKË“&ª¦®…í'Œ563sëX˜›«ÚθzUÕÁkÚkfövfv¶]§½¿»ô;¡h­A“÷ÛoZ88›š¶ynTjìÅz­º„£Ç{{?üeì2uŠ©­´}u߯קšÙÙšÙÛu}ãµø½ûu·ë¨Jëátœ©ª ­Å«hž¬Ža srŒÍÍ¥mc ‹‚œœr/,¨~¼—¤\rRS­œ›ª·´èpfÅêü»w•JeâÑpïÓ…½>™óÏ÷?þ³f­‘´ëô×\úô.5NvròÎ1/!„R©,.R»KŸÞçV}_˜“Û÷›/¤–”¢"—~›[²Øà~O!„¢A!„¡ÂD}[YT¤ê`Õ¤qɆsÓœÔÔ ÖPŠ©MI®565U ^Áת¯]¾yè°s¯žÒöC^FóF U/ÌMK³jÚDÚ¶vqÎMKÓÝ^ŠzUZ§ãLUeh-^Eódu kln^˜“cbi)„(ÌÎ6¹Ÿ¼€^!mËÅÜÞ>ëf‚µk3U‹ÂÚºIwï¸]{”JeSŸ ++!Döm|¿øT‘p4üØ'Ÿi¦mó† W.³pp(Õ³ac›Q#ŠòòÎÿÒãƒw…‡>˜Ýyê+MztSXZdgo Tñj³oY»8 !²n&˜ÛÛW°†ŠxÐ×&<í=ãÍ’—WÑeÌ’2ö IDATB˜ÙÙi=ͲÚuT¥õp9S­Å«hž¬ŽamZº¥FÇ8yuB¤ÆÄÚ´l¡ã¸ ¦°’D.nƒœüzavrr~VÖ©‹¤ÆVC_þ}Ç•?v¶R…Ïž“_\P Š‹•ÅÅR£ú"f÷§ž ÿt~æ›Ê¢¢Œ¸¸Ã³ç!n<•—q·å îO=™{Qº%±(?ßÐÄØXaš•xëøç_>Pµ§.ÎMKÏMK?¹`Q‹þ¥öj­ATìÑue½Vaeu÷ê5U7ÕP·#ÏX7w5³³•>}˜ËXJ‹€~§.É»šÍúénW¯°TUZWÖ™–¢Y¼ŠÖ“-kX·gV¬ÎI¹““’ræ»U- @ÿ0·-—öÆE,Y¾óù B©|tÂX©±±·W~V–‘ac¯.R‹K¯ž¿?+óÆM›æÍ}fÏÔ§ÝóÁÂ@xmzNJŠ[ Ïqc„ÿ|ÿcÇI/ !ºL›±dYßo¾ì1óÝS šù‘¥“cÛàQW÷¨xµŽ;ì=¶0;ǵ_ßö/Œ¯H TÖkÛÚ5á¥ÂœœRÏ¿+õ”½ªºŒBˆ/M<ùÍÂßG !\ûõíðâ ºÛÕ+,U•ÖÃUð*i¯ûdËÖ}ØÐ¬› ;‚Ç!ZÚê‰ÁZj–²Jß#44TáááQ…cê³Ð€QÙç%ë_ý9…?F>×kîGvî5]ÈègU!ýÑÀooé;_Ú(66VáççWÓ… N ñôµÿŸrè­_æ¶¡_žØðKM— …~Vôë¶¹¶ÁŸÏäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚäBÚ€¼B||C||kºŠšAÚäBÚäBÚäBÚäBÚäBÚäBÚäb\ÓÔê”>¦»OY„÷’’8'5:ƾG¯y[88Tm¨NÌmT™à#a҇X´ÔÉ«sОŽ:E,^VîAëíÇÔ ÌmT™Mƒ•Ž]:y¿5ݲIãÊ ’t:Òû­éF¦Š6#ƒvŒ[V7õ]‘)sÔæ¶ªFð‘° =;žÜºÑ¶uëóçTzœüÌL…Mƒ½“_5µiŸ™¥µÏV­DEim‡> mT%S;ÛöÆ¥ÆÄVz…µu~ÆÝ€o—äeÜUX[ivøw&;*JŠÚª AàÖ3¤m€ªT}!d½‡{¥GpìÜ1fó–âü‚˜Í[œ¼º”ÕM}J»¬Ô8ÖmT iRÙPaâØ¡CÏf©Õ×R«&ž¥ iW©>]¦N9ôáÇç ±oۦ眫­~È´ P5´Þ¡Xª±"},›4î¿ryYG)‰éLc׬$¨MJ¦Ã==kºTi i VÒœÞfÂ[±n – >&­ÞÖ¯yƒ½ÂÜ6@íSV¤&jëæ¶j%ÕÓ![1· È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´ È…´Ú'ÄÇ7ÄÇ·¦«(i i &ñۺ͸¦ ¨Ô3qð‘0Ý}Êê „¸—”tøÃ9©Ñ1ömÿÌž}õ矫±(µÛ¦ÀÁû†¾ùö½Ä[•$étd› áF¦Š6#ƒn<%5žùv冾۟}þÎù Jý±Ò6‹Rôi€\òRR¢æÌ94lXØ AÓ¦Ý9vLj/+ûVBh@€ôQª½0++á÷ßÝ_yE÷Ë[O™r}ëÖÂ{÷Ê=ÊCUYaÕv •|$,hÏŽ'·n´mÝúðì9•'?3SaÓ`ïäWMmägfI–M› ßõG›gG†2¿‚ãügeKT”ÖvèÒ6¹œŸ7Ï¢Y³îk×öÙ¶Ímܸ›¿ÿ^å‡ðÛ»×oï^ÍöÄÝ»õꥰ·×ýr3GÇF=z$íÛWå…¨«LílÛO—[éÖÖùw¾]’—qWam%5ºõ025mÑ?àîµkäß…ÝQQRÔVm·žá.I ZUçM65înttÇÏ?745BØvêdÛ©“¸?}+ý¯”•EEqkÖ$îÚU”“ÓÈÇç‘éÓÌ̤>-'N¼±ysQNŽƒŸß#¯¿n`bRÁC§†‡7 Ro¹¶aƒÖ¡ûö½±e‹ó“OVdØÐ€· ®oÜhhbâñúë÷®]»¾i“¡±q›wÞ±÷òÒQsq~þÅ¥K“Ä޾¾­§L1T(¤þ­&O¾±eK~jª²¨¨Ô•)uh×_¿¶~}^JŠ¥›[Û·ß¶ts+ëê…Û~Þ<‹fÍroß>6z´ÏºuІ ³¯_?7sf÷¬à5 UAvv̆Ívî•Á±sǘÍ[;&fó'¯.Rcüž}-ýãwïmàêZñ¡Ô§´U-!žž•® r`n¨2œK¨¶›ljœµ‡GÜÚµ9‰‰êRŽTŸ“¾¶~}fll×åË}6n441¹²r¥ªsúÙ³]W¬èþóÏù©©q³ââ¬ÜÿóoaYCY{xd]¾,mWd!GAzúcëÖ¹á³Ï ÒÓ q?þÊwßé>Еï¿ÏKIé¶fM·~ÈIJŠûáUÿ̘˜®Ë—ûîÚ¥yeJI;}ºó‚½¶msèÙ3櫯¤F­WϾ[·ô3g„©ÇŽš˜¤;&„HŒlؽ{¹' ,Òªè-ƒ†ÞŽˆìùÑ,U£f¡±¢Z½O—©SŸÜè? éTDçW_–ï^»¾yÀèuº½ûVYã –bnxXê?+2-½)p°² À±K'ï·¦[6i\¹ƒ&Žô~kºt“ÍŽÑc+7ˆÜeŠÂÎNáþÊ+‘3f´œ8±‚‡.ÌÌ4±¶Vo)k(c+«‚ÌÌŠŸT‹Ñ£ÌÌûûÇ|ýµj;váBݺÚù«¯¶¶R‡È3ZMš$õo=y²‰MEí1mšIƒB—  øû7wj½zöÞÞI{÷62$%<Üå©§î=Útðà´3gšôï_ñ3PŠÖì¥+ÒDzIãþ+—kvè›qþ|Q^^fLŒmÇŽ<}&eqVŒÔÌm•§~“Šú†ô0ÄÇ·¬É é&›Mƒ*}hÕM6¹©iª›lô–ÂÞÞm„CÆ•µ·Ë¢EÒìl)¹IIæM› !r¥ ã ²rs˺xÑÞۻܡîÆÄXµjUñ‘Ë¥õ@&¶¶•>Ý´^=CSSs—„mÛ¬=<Œ--­=þü'Ÿ¨v]\¶,?==?=ýâ²eNýúUüÐ {ôH9rD½¥¬¡’CCöè!mWÉø´È©oßKË—ÜowìÛWëkK]™Š(ëêÙ{{_]·Î®K!„½—×ÕuëÔ÷P7hNo3á­‡˜Ûª•4n¨0qìÐAý&õYðR7Ö”üÅð¿}ºLrèÃÏÿbß¶MÏ9V[ýÄå‰'âü1#:ÚH¡°yôÑv| µ»ŽqjÊ”¢œiå†ë¨Q×6l8óöÛy))–-Z4î9Õ¶íÛŸ|ñÅ¢œ_ßcÆhB•K=Ê£q@@ø„ -ž^µNCëP¹·o§=Úº¼Çr?­r?þâÒ¥áãÆ !|}ÝÆÓúÚRW¦"ʺz »u»´l™”¶í¼¼.¯Xaß­ÛÃ=|$¬ä6JâµÞ3P*•U8\hh¨ÂÃã ÇÔgÒ?ð¼·j5SÏ 5_FÓØÒ?=)²âÑM¯„~üq5T2Ñ^U¬‡Wß°n ®Q…lžØ]ãHÛÀÃâ&™ÔÆ%µ±fu•ú{¥¸k+I€ÊÓ}“ ¼Ô¸ÿ©ª¯+§ksÛÀC)ëÇ?Îz‚IîšEÚ–úO1i›¨]oUÉ»«MíªÀCb%wM!mQêñã'_z)làÀ'Þ —é(Ç'L×x‚uê‰''O80|üø¤ûË©óRR¢æÌ94lXØ AÓ¦Ý9vL¦’*Gâo•Ô 'ÔURVV}”Ú{uïþÍž(ëµZßÛrcÝ6¹Ü½p!ú«¯Ú½ÿ¾M»vQQç?ý´ýÇ[·iSµGÉŒŽV*wÏŸoЮݿ‡þòË63fØuê”—œÿóÏNBˆóóæÙvìè1mš±¹yFTÔµUo$©ôá&K}¨€n:þ‚zî‡óïÞ-÷µ<°:1· @.×Ö¯o9a‚mÇŽ&&¶:¹uýziWh@Àµ Žý=dHô—_* ¤veQѕի2äü'Ÿåæªú'lß~lôè°N¾üò½¸8ÕQ÷ìièägÏ¿‡^·®åĉö]»›5iÒfÆ ©ýnttóà`“ ¤’:¨½K¼Š²¨èÒ·ß>üаa7¶l‘‹óóc¾ùæÐ°a‡† ‹ýæ›âüü’ÎÑ_|ñ÷!GFŒ¸¾q£ú ZOD’uåʱ1c„êÍÅ”Êð1cîÅÅ©¦„sÿ™=ûï¡Cà :ûþûùé饊 ;Vz÷ÜÛ·CóïÜBd_¿>v¬ŽjC®oÙr488lÀõÑîÆÄ}öÙ¿þ*þûöœZ¯yq^Þ…ùóU§¬9-µ„¨¥~ܲ.Žî‹@å¯é3Ö÷é·û…IéW®”Ú5hÍꊌÀª’êDÚ —Œ¨(ûîÝUŸ6ìÞ=Cí€ÒÏžíºbE÷ŸÎOMûñG©ñÚúõ™±±]—/÷Ù¸ÑÐÄäÊÊ•ªþi§Ow^° ×¶m={Æ|õ•Ô¨,(H sò÷oìïŸò÷ߪԞqþ¼½··fIÖqk׿$&ê(;~íÚìøø®Ë—÷øùçÜÛ·¥Æ+ߟ—’ÒmÍšn?ü“”÷Ã%íkÖägdôøùç®ß}—©Dlj!¬Z¶4¶´L?s¦äÔ"#­­-ÝÜTþùðC—§Ÿî¹iSÏM›,\]/ûm©"í»u“^žz옡‰IʱcBˆôÈȆݻë¨V‘Óuùrß]»T-ɇ›9ÓcÚ4—§ž*u­×ù¤¡ÚïEº¯¹4¸‰­­ÂÖ¶µÚ)ë¦~ܲ.N¹ €Š¡Â¤Õ“Od\‰+¿«NLrWÖm‹±•UAf¦ÂÖVú´ 3ÓX-›99•l4i’Ÿ–&m祤œœ¬$ ×Q£®¬^~挲°0ýÌ™+ßï:r¤jïÅeËòÓÓóÓÓ/.[æÔ¯ŸÔØtȘ¯¿ÎIHPÝ‹?¯í.F•Û8=þ¸´>Xúhpû¯¿J½jUê©SÊÂÂÜÄÄè/¾^rvæÌô3gŠóó 22®­_oݺµæ°N—,ÉKI)¼wïÒ²e%}û^Z¾¼à~ÁŽ}û–´÷ëwqÙ2U»jŠœH“níÚ•´{wãÿÞ³(„(ÎÏ7066R(rnÝŠÕ˜}—Ø{{_]·Î®K!„½—×ÕuëTKÕ˪V“i£F¿þ:q×®«ëÖ•Õ§G?¿‹Ë–dd¤§_Z¾\kcKKé&N­Êº8ôÕê­ý†nZ7*l_àwËlÜZHRÔ÷¶¬ä– sÛäÒ ]»GÞxãâ’%Ùׯ›;;{L›Ö@mnÛ¶}û“/¾X”“ãàëÛbÌ©ÑuÔ¨k6œyûí¼”Ë-š?÷œŽñoíÞÝzÊõ'ÿKË–¹<ýtƒvíÚ¼ùæ•+î]»fæèØ|ôh©ƒËOÄÿøcFt´‘Baóè£í>ø@sX·1c.¯Xq⥗„R©z¡Ûøñ—.•žêíàëëvÿñÞ-ÆŒ‰]¸ðèèÑÆææÍ‚‚ROœ¨ø‰ØuéR•e`ddשS©]mf̸¸lÙùyóÌ›Ý Õ|yÃnÝ.-[&¥m;/¯Ë+VØw릻Z­ vúòËÈ3Dq±î ®O°¬‹ó@_}2a’»Ê(U ª ¡¡¡B*SŸIϷⱚéçÿú\•>A94 @«ÂƒÊ¾~ýÜt_»¶z+„ðóó«žÃ¡žñôú÷Ó[¨¦·«äâèç¿’Õ ÄÇ—•$€sqéÒÂÌÌüÔÔËß}×ð±Çjº²àq%U…´ x0ÍšŸ0!|Ü8cKKÝËTÔj¬ä®¬ÛPXFR«9ꦵϽ¤¤ÃÎIޱoãÑkÞÇZn·ˆß³ïÜ÷kî%$Ú´tëòÚ§.åªòãyÛj“ÓgÎzxu¯-ÖÅÀÖAýCk¥Rùö‡Û5omßÂý½çU<ŽTóoÎjnª©ÎP•õ´ï𮫠 “>Êê±h©“Wç =;;uŠX¼LkŸa{ÿoΈ}»Ú:4sv¹UOùÐ7Ìm]NooßµgHÿÀ*©ª†Õ¡ÜK±bÍÚCÇÂχV å3Ï_ýÓ/ÇŒ®žÚÊÅ6ªV›óÞ8XYPàØ¥“÷[Ó-›4Öìt:Òû­éF¦Š6#ƒvŒ«u^ÿ›#m8vꟙU”—gdjªÙM=d«¶u}Ôæ¶Ô&;öì2 нK·èØ‹Bˆk7nÚ9&ܺ%„ˆŽ½èÞ¥›¢¨¨è½ç9¶ncѸYðÄI÷²³U/ÿ|Á"'÷¶–M\'Ly-//¿Ô°BˆÜܼ_{æYK›f-_z}znnžÔ!îêµaÁc¬[˜99>òvrŠÔ^PPðæ:´zÄ®y믗.—ÿÜ»ÿѽM[´ï²bÍÚÊéë6Ì›ù^“ÆNM7þ߬÷ׄ¬«økåx_Iæ°Q=jûœwð‘° =;žÜºÑ¶uëóçh퓟™©°i°wò«¦6 ò3³tŒ–—žqðÝ™Ï +7jGEim‡> m¨>ù4èÛÉ)±—.÷~¬ÇÀ€~¡‡ !¶ïÚcjªØ¾k⯿ ôB|òÕ‚“‘§HºtÁT¡xGí¼ƒGŽž=|0îìéĤ¤?ù¬Ô°Bˆæþ/áÖ­‹§Çž ¿v}æ¼O¤>OŒ|Ï¿þ† IDATîõ—_º}9úö¥èv<2ýƒYRûGŸÍÿçBô郮œ9yíú ©qÌäW>zïíÌñÿüýÄé­çÒÐÍCáÐô‘®=>ýzAQQ‘f‡¨ Ñ];w’¶½:uŒºó0—®ÒHبAZ“wMU!¦v¶í'ŒK‰ÕºWamŸq7àÛ%ywÖVe ’»{â¤ÆÞ]»¼öªæÞg²£¢¤¨­Ún=CÚPª$¢íÜ»Ï߯‰‰É@)mïØ³÷µI/ý±k·"ôÐáþþBˆÕ?ý²à³y.M›Z[Y}öч›·ý®aágŸ89:8:4ZøÙ'¿lÜ\jX!Äú-¿.øôŽœÏÿtÝæ­RŸŽýÝ·w/s3³ÖÖsg¾·çÀ_RûÚuÏÿ´™³³­í‚Ïþ'5Z˜[ÜLLLJ¾íêâ²rÑ7š'¢LO¾›sëú¦¿ßûWØ[ÚefÝ»gei)m[[Yeféš+K妷µNcWb  Õ® ï‚ìì !ëí<ܵîuìÜ1fó–âü‚˜Í[œ¼ºhísùÇ?ÿÒgöÌN/¿d`XfZSŸÒ.«5Ž´  Öؾk÷àþB¿Þ=Ÿ:“sôøÉ÷¦¿~$üDvNÎñS§ýzõBÜLLìØÓϸac#{§ÆíT«>„nÍ]¥–-š'%'—V‘”œÜ²Esi»•[‹Û)%¯=vâdŸOX5mn`ë`ÙÄ5åNªÔž˜”¤ê¯²yí÷ûCzùösõìôÛŽR£æ=‘FFF<Û…¬únMÈzÍ>V––Y÷îIí™YYÖVeN€iU‰%òLc£VÐó ïßß-ƒ†ÞŽˆìùÑ,U£zŸ.S§$?¹Ñ@Ò©ˆÎ¯¾¬µOø§óS£cöLš" X˜“S=õCÜ%  š<ä½’ûÃþ^öÕBs3³GÜ[/]¹Ú«SG[¯N·²í#ff¦Bˆ&NNGöîtÑ6­wõZë–nBˆ+ñW;:–Váäà ÞÇéþ“¹‚ƾðå¼û÷ëkÓ AfV–M³–R{'§+ñW=Z·R?Šw—ο¯ÿYñçÞý^}mØàA¢ìøk``P\\,m«÷ñlÛædDäã}z !NEžñlûH%.š&Í'ªny$[£ÖQÝF© Ü5~c¥Ö;K5Z6iÜårÝ}tßé(Es¦±k æ¶Ô}Ľµ£C#éÓþþŸ~½0 ¯¯"ðq¿O¿^(-#BLž0îÅ×Þ¸t%®°°0*::xâ$Õ ÓÞûàvrÊíä”×ß}ÿ¹Ã5‡}vøÓÓߟ•œrGêóìð§¥öœÜ\…ÂÄÜÌ<þÚõ—^Ÿ®plðÈ©o¿w#!!=#ãõwß/ä…—ÎGÇäççk]“ýì /ýsáBaaá司 ¯¾4l¨fŸ1£FÌœ÷iâ­¤„[·>˜ûɸàgôŠiÞ+©ÚVm°VuCíZgòð¤,âéYÓ… BHÛªé*w¯äö]{¨>Ð/-=ÝßÏWÐ×/ãîÝý¤]ï¾ñZŸÇüŸ|Æ¢‰ëè_~ú‰!ªWõñy¬½Oo·];:~ôîÛšÃΛù¾“£CëÎÞî]º¹4m:÷ƒ÷¤ö–-š1ë#+çæý†>åÛÓGÕö;3Úz¸wìéײcW·æ%KJž4ðéçÇY6mþîGs^QzKñÔÁÏN˜dÞ¸™ï ¡mÜÝñ™fŸIãÇöìÞ­]÷žžÝ{ùöôyáùç*qÑÔi]ÃMÈF£ŠÝBˆú»Q+Tíß\BCC…U8¦> <زڕüMÏ.»>Wå·woMò/iÝB%“xxußðêÎÚWm=2 «?´þn“ …ïÚ•¶ccc…~~~5]j“rà-ÍëÛOïr©?“ä?í÷'¼õíŒôó_Éjâã˺mÕê—víž;¾«·cO…ËQLÃÐêk»¥ä]ãk»«Dð‘0)¿j]ORC­>#m¨Ò‚$Rà®Ábê¡RwFõÞRùT[³½ú‹¤m2RÙ¿½{Õß÷rS¦'Ø:h>Ѝ·4c÷/íÚÕ\9¥ävÉúºH£¶ mE©œ­¾vü!UBŠÝ!žžÏ?ÿœ­ƒ¨Ô-%@¹HÛª˜ŽœÁô6 Û/íÚIÃdnÈ€´  jgK‹Iª®"SÝxH¤m†u#µ÷J‰©nTiÀPÚŸ³¹W@­ÃT7i@…TmÎF bz¨êSÝdnè@ÚPYs6ÓÛÕ‰{%*Çò”‹´  LÌg@E°¼:ÖtôT5Gmæ\«‡š6mZÓ…u“2=Yú#?Ó ÂÜ6€Òª9gó(@u Kº¡Ž´ à?TQ›¥#ð0Èܶ”¨ÁUÚÜ+Y¸W¨NÜF Ò6!˜Ò9©27SÝõi¨ïôäÁ#LoW'¦·A殟HÛ@½¦‡SÚ¤@u™»¾á €@ý¥‡QÕéæÍ›5]PIÏ j±usÛ@}¤'«GJ!ü¨o˜ç®HÛ@½Ã”6è2wÝFÚê¢6È'ÄÇWµ|$LkŸ{II‡?œ“c߯£×¼-þóp@)sgÅü£µj#Ò6P_èçê¨cÊ Ù*‹–:yuî·è›s߯‰X¼¬çœÙê{ÕŸÏ]˜tSkÔ.¤m ^`JªÇ¦ÀÁÊ‚Ç.¼ßšnÙ¤±f‡¤Ó‘ÞoM72U´´côX­ƒl~ì±!!kœ…›}+ëXêSéªírã>ªÏ$ê>¢6Tà#aA{v<¹u£mëÖ‡gÏÑÚ'?3SaÓ`ïäWMmägféè³gÔÈâ;·†9ªõ¡%ÿYµ¥µú€´ ÔDm¨¦v¶í'ŒK‰ÕºWamŸq7àÛ%ywÖVåöÙìó˜ôŽTê™ûß™ì¨()j«6[϶z¨ Õ¦ ;ûBÈz;w­{;wŒÙ¼¥8¿ fó'¯.ì#=Ÿ»TæVŸÒ.«5Ž´ ÔYª¹ ¢6Tßß-ƒ†ÞŽˆìùÑ,U£zŸ.S§$?¹Ñ@Ò©ˆÎ¯¾\ñ>â¿÷P¢¶à.IàÿíÝy\Mið§íÞ´—’TÒ¤¤“‰TC¶± cceD Ã0ƒPv†aì&;“Ã;c+f¢P¶lE¡¥´—öºï'Ç™»u«»ßß÷ã3sîsžsÎsŸS÷þzîsÏQBø @&ø~C‘«P·u«~a;›P‡Â)|îåóMr2‡Ãi^cAJ0¶  lðµtå6öú•?œœÂeÝ Ò6€RAÔ+HÛÊQ@¥ðocÀ[aÞ6€’@ÔPß$'BÍ'Á\ÁØ6€2@ÔPÔ5I¨ë“ð¼ÁØ6€ÂCÔP\9›zÙ§Þð ·¶¢6€*>ž ò 3I¢6€*@ÔVhÛPTˆÚJ9[ m(6Dm¥„œ­4¶¾ ¬³• Ò6€âAÔPJÈÙJ i@ªèÉÖDp\~Ÿ}méòü')&Ž=W†ê˜™ñÝÃ_cƽÏÌ2´³uÿ>Ƚ‹äÚ ’†œ­Ä¶¤­Á1éÄ-Û-<ºôÞ²éᾉ[wôX¾Œ^EGmk?ŸN“&´m›s%.xÙˆsÿ“`‹@b³•Ò6@s1‡«E¹Nȉ¾_pª«ÍÝݺý8W·u+Þ Ùwïuûq®›å8zäÙq„ïÜÜ­sUIime¥›ÝÌ'Ò„œ­"p½m€fùÏ̤$¾åLc¯_uvè©ãFöö×–-ç[§ª¤„eh8“mhPURʵCfÔ®,,ºús°ÃˆaˆÚ DÍÈLÍÈŒSøQ[ m4ÝÇœ”DEmzÜ„¶±‘ˤ‰ù)©|ײôõ«ŠŠýwm«,*féë1W1£v~JêÅ)ÓZuëêþýÌf>äl„´ Ð\Ì!mA%\ªËʇG;tà»Ö¼‹kJäɺªê”È“î„ßEHžÿuöæº ^˂ݦ§¦Ž_d¹F…lälÕ„yÛREåfu––yçÎ=B–Ð…Ì$í>+(nihòáp“ŽŽ=–/å;Fž°f=!$jZõpÔå š-ZH¼õ THHˆ¬› œºc©ÉÙó³UÒ6@Õ774ŒÍ…ï·'¹ u[·ê¶“yÞ:¸Ø6€œPè ¨(BBB±Ÿñ%H  m4ÑØëW½|¸›v,ID'$ù…ü€ïQˆYȦm²nBã`0¸ mÈ/Ü3@N ^Cƒ²A¤m€æâÞwvÃn_Ò¤‰7j#ar6‡´ ÐtÔd" ^7gLZ”»ä€4!a„l.Ð,‚Ò°XR2¢6€¼áº–¢64cÛÍEeb1αÆtmyƒ‘lh2ŒmÈL×ô0¶¤G²ñʯÜ0¶ 0° +‚†±™™XЫôûììkK—ç?I1qtè¹2TÇ̬iuðíe‚±m9‚9$2!â0öØëW¨‚ö“¸e»…G—‘QçÌÝÜ·îhráGÅ‚±myOAáÄøûûFG˺M¤¦¦F/‹8EäDß/8ÕÕæînÝ~œ«Ûºo…ì»÷ºý8WƒÍr=òì¸ |w·Îý]aOŽÐmeñÙ’E-:Šø˜o—[HÛò¯’Ð41þþ*rÜpB¤pWPJÌxMáp8¤1wH ^Ÿ+ G¿¶lyßßù KW•”° ¢göÙþ[UI)ßýð­£kÙú« ¥_ŒNX½~à‘ý¢´ç?3[’’è'î僷¹‚´ 0‡¸È*=7Šot´LÚÙØH!+555*(‹R“ùPÄ­„c¹Lšx¢ï@¾kYúúUEÅþ»¶Uä°ôõD¯cÛÏ_ƒÍ¶éç{Ã&Qšñq$ûÃ7µ@ýv pˤmÙÕ"¡x*«ÒÓ¹ØGÏ^Œž4ó{BÈþí[öíCQ32?fôŸŸÝ·}ËWCBþ¹;!pæû²²°-›F DÕ™ùÝ”=‡/ž77xþ\jWjFfÚÚìõ¡!³¦M!„$>x8)èûIÉuuuTö ]û˶°=¹yù¢Gá„ÛwíßCùþ§E"®¢FÊ©ÿRâj˜š‘Ù¬iSví;Xõ.“Úähä©ïfÏ1dðÁ£ô&ôElmhhhhh(³DÒÁš/¾‘—«P·u«~a;[‡ªÐ%(Pø±hõ\?QJHÛrãò©i©yZA Ê.!!!MÛᜅ‹÷mÛB-Pi›2êË¡£¾úã’eTÚž9ÿçC»·ëëéœ0‰JÛ„~ŸûMþö¿AÃè´Í)|—ôä‰ÿ°¯¨P;qú̉ß|=cò$6›EUXÿÛÖ¿®ÿvô(Þf¶µ3Ð×ß²~õ—ƒ¾`–èës8œâ’®M­â¾ãÛæj!¤k·ò·+é ËÖ¬;~`/!äàÑzBÈνûãâDëH²lÙ2ê,ŸI¢:Æ^¿îåîìŒÀ­¶d ʉƦjäiEúË ?‡¤¿Ì  ?”¼¤¦>{î?쫺º:æ†_ôóWSS+,*¢.[³nóŽÝÅ%%tÖLNI0ŽÚ„]›6l Ûûë¶ÿüõgKzø™Sø®¦¦æï‹QS¿ÿ+mèëSaÚ@_Ÿ«åBV1ñ6Œ2ö«ôׯ^÷öñæ‰>vêôžCGb/ü-dç|ÉdH ™¶@µ4*X#UCsض³¾|%–bcÝ–.üPRÿM8ûöëC— ìÛG]ýãýæ¸Fp×ÿ¶õÚÅs•=úÕ_Ã釰ƒ‡§OšÈbÕîoÇŒ;r„ïC/Å\=|søY]]ÍbóÆTÏ®ÿ;wò)Ï—ù„¬b±X™oßZ¶jÅ·a„MÍÿD‹vm­¨§L‹úçß9 _:¯Ó¢w› ‘x‡·ñI9„´ 3Ø–4у5R5H¯«WL˜D¡æ“PÂ#OžþûÜÞm¿QÃ~Û4kð˜oˆàI̾ӣßÀ€oÆÒ%ûwl ˜1뇅Á‡9ºG÷O{ûôbnK•·mÓfצ t µÉª%‹†O9~HôU“&Ø»u+¯¨à¾ãmó¸Týe?Í5qòýé>|ÜÄ÷eev®Bž24ˆšLB¯¨W¬QLL !ÄÁÁAŒû”gÔ{9Ò’”ÉgHml«¤sÓ/ê(*%EÌÖ*ÒJ‰¾ ”KÍÇ5IdxAÙ:}öÜÏ!+žÜºÑ„mC6m#͘=ß *­ÊÛ{Šˆüž½üê]ƒÜ2‡´ mØæÕ`¼F¶h rËÒ6€l¨øëâ5€Ô`[¶¶¤Je¶…ÇkdkIà ·¬ mÈ€*¼Æ!^Hר ó ¥"¿ nIHî£$Sg§ž+CµMŒ¹¶¥7Á ·!mHÒl I؈×â"(%'nßiÚÉÙï×_îÝŸ¸}×gK Ú³J¤ i@Ú”é¥ ñTuyðïÜùÙ·ïw°÷\ü“‘]žŸðÅál–ã˜Qç¾(d˜U"MHÛÐ8HØ jBBB$w#CúŸ‰JÆuUÕOOŸ¹±|õ€{èUUEÅl#CBÛР²¸D”ý`[ ¶¤Dqǯö@Þ¨³´Úœ¸m'³ehPYX¤mb\YTÌ6Ðe?ä–¤mà @>…{ùønXgááž~î‚Q{;æªÖžŸ>9vÂeÒÄ'Ç[w÷q‡ä–4¤miPˆ1$lùçµ,øö¦ßÊrÞ™8:|¶t1U8Ó×6÷ éqKBNø0íäÜsEH£v‹AnÉAÚPi‚6â5€|²éçoÓû¥Û×6BˆvK“>;¶4yÏä–¤mP$Ì+èÑËòÿr oþCÂnЋÇ߿|é,¤Î£eËô;th7nœÔZ ä;¤mPÌÌ:6))ÜÙ™.Wˆ×Ù6Rávenî³; îÞ­­ª2pp°3¦e÷î„qµ™î®Ö”–fþï]wï¾¹}PÐíÀÀ6_~©©«+ü(Òéd©”¹Å iäBƒÕ+$%1¨Ì×Ḣ¶Bd²ä•+\]æÌÑlÑ¢())ãøq*m‹Õ¼‡d]¼hÚ³'ËÄDøæÚææ¦Ý»g_ºÔfèPñ6 @`[\¶A¾ÿ•¦£6³„ä–OÒ‘4qE!B6­øÉ×uëÔÙlBˆ‘››‘›ùŒ©ÿRO‡S[›~à@Ö… µåå¦^^ŸÌ«¡­MÕ±›2åuddmy¹™¯ï'³g«ii‰xèü„„¶#GÒ˳²žïÚU˜XWScìææ¸`ËȈZeîç÷úäIÓvŒ¿¿í¤I¯ŽW×Òr˜=û}FÆ«'Ô55úÉÄÃCH›ëªªžnßþîÊBˆ¹}P:‹EÕoøúäɪü|Nm-WÏpÚaö쌈ˆÊÜ\][ÛŽ èÚÚ ê½„ \V®ÔiÛ¶"''~Ü8¯£GY-[–½zõ08ØóàAû”¹ÅB]Ö à#ܡú'ë†( ºÇøvšot´bEmBˆ¾ƒCú¡CåYYÌBêY0ŸNFDDIjj×;½ŽW×ÒJ £+>xÐõ÷ß=©ÊÏOoLL,MO×ëÐ~øhéR«áÃ{œ8ÑãÄ këç»v1Yúü9µ,äŠ.´êÂÂÏŽµ x¼vmuaágáá¶iŒ)+|Ûœ¶o_enî§|ºyvvúþýtý’””®;wú\¸ÀÛ3\ îÞí²ysÏ3gÌzôHÙ¸‘*äÛ{&Ÿ~Zxÿ>!$?>^]K+7>žRxï^KOQ¯&J†Ùxkn¤mkÌÉ;° |öØëWè²jXó9/]ZS\œ8gNܰa׬©ÊËã[-ëüyûéÓÙ¦¦š::vS¦¼‹¥Wu b³ŒŒ:̘‘}ù²è‡®))ÑÒÿxWˆnaaF®®êl¶¦®®m@@þ;ô*M=½ê’îÖÆd3nœ†¶v«>}j+*èå÷ÂÛœÓaÆ –‘ËØ¸CPPö¿ÿÒõíµ E9´Ãœ9lSS 6ÛjäÈ’gϨB¾½gÒ­•¶s¬¾ü2ïÆ BHÁýû&ݺ‰þL@5'+3ßS¸ 3I@fDüu¥?Æ wvV”ÀÍ%·s EæØ¦¦ŸÌ›G©ÊÏψˆHZ±¢ËæÍ¼Õ*ssoB‡Ã©«#jjô*m ‹ú…Ö­« D?´¦¾~uI =]¤øñã´°°’§Ok+*!ÌCÔ”–Ò¹\”O4õõ !Ôüz™š"¤ÍÕ……Ú­ZQË-,-« éú N.§iP l6}D¾½gìêúlÛ¶ÚÊÊâäd§E‹â¿ý¶¶²²$%¥ã‚" š‰ù:Ï62ìgFŒN;{žÞ³N“a&w£`l$‹÷—°ÁŒÈ·ÂÇO¯øÅk…ÈôSh°µ*;ŒÍd5xð‹ƒ‹ž<Ñ`± ;urZ\wbëQ£îÕ–—S37¬ÇŒÉ8vìþ‚•¹¹º66í¾ù†Þƒ‘‹Ëí©SkËËÍ||lÆç=¹.åÑÊß?aÒ$›o¿¥æi8ΟÿtÇŽä•+µÍÍÛŽ™CU«ÈÉɽqÃ~Æ 1>k¾m¶ xº}{Âĉ„3Û‰ùnËÕ3¢Ô{-?ýôÙŽTÚ6öðxþûï&Ÿ~Ú¼gF½héèx¯^N>¼‰xÌžõ]ýËN¿°„Èþƒmú÷¥ÖZ¸»µõë59ÐmÆ´k!+ÚþÂwúÌñ±‹–Ø}1€ÚŠY§9ÍcÎKÁ ·pjGŒ»‹‰‰!„888ˆqŸòŒz“ÆO_š»¬1”ùøþ!ú5Ź6l~«î‚$Í×Ì[½¼8|¸,#ƒŽø|‰ý^’¸=MƒRSS !¾¾¾²n(jGNÞJhõ3IêêÞ=|¿bõÈòßPû loʉSÕ¥¥„ñÖ3öZ QS£ªEôê=2úœ›Í½[Fq5•Z˽ò ÷òÁØ6ˆYÓ¾ بjòÿËõM®‡\¯qòü'„ʲùöÛët •BK@•©©©§²°ˆwÕãðcþ»¶i›ŸúszѸƒý‹¨Kvû«ihpíT¼ÄW'„´ b#Ñ q(.AßoÂPÃ«šš¶‰q—Y3˜…Ô›…È//δØŸ0ÞPèµá^>ƒ#ŽÄ¯^wë—_µôtí‡v6•kbÞÆW'…CÚñàÊ•aKäŠ(Q›·»Þgg_[º<ÿIЉ£CÏ•¡:ff¼{¥Ž*SÄ)ŠØfAß_b>ì2sz—™Ó !ÝæÏTÓ×6A{Ä;5¹Á5I ¹˜ßGVú e4Šð+› ¹®Hâ–í]FF3wsKܺƒïæ¢Ô&܇/ŒmCÓÇÓ– IDATa<›Â5'›Zhð&1ótûq®nëV¼«²ïÞëöã\ 6Ëqôȳã&ðÝ\”:ÒÇ5ÈÍ$–P(ŒmCS`<›öŸ?9·ºlðoúÌ ×–-绪ª¤„eh8“mhPURÚä: XÄrÅn‰jl ¹®±ªƒÿÍ4ó.©L0¶ †!mÚÇ?9>¼‚P ôEÁ…_{$?%•ïnYúúUEÅþ»¶Uä°ôõš\GÑåß¼™¶gÏûW¯tÚ´±›:µ¥§§$ŽrsÒ$N]çÿ9ô­[i{÷¾ùR»U+›±c-üý !•¹¹Ïvì(¸{·¶ªÊÀÁÁzÌúÖ6ò QÄÕ@šø¾KªÎ÷)‘¶¡qTó3 ᘬÓ%¼wáaöXuYYʱÈ7×oðÝ¡yהȓ&ŒO‰JiZÚ£îÖ_4—ÃI˜0¡Shè­ï¾£wyVÖó]» ëjjŒÝÜ,`1IÍë`ÞASÐ&1þþí_ŸxÐõ÷ß=©ÊÏO?x*̈ˆ(IMíºs§×ñãêZZiaatý‚»w»lÞÜó̳=R6n¤ 9ÕÕï®\±èÓ§UŸ>¹±±œêêúC''›tëÆÛ$}‡ôC‡Ê³²„4ûÅ¡Ce/^tݹ³û‘#99TaÚ¾}•¹¹Ÿ8ðéþýåÙÙéû÷×—8PUTÔýÈ‘®»wÜ»GïDÈ!„èÙÙiêêÞ¿_ÿÔîÝÓÔ×§ÿ~ „äÔVþþYQQf½zB4uukJJ´xæB°MM?™7R•ŸŸ‘´bE—Í›¹êTh·nÍUX]X¨ÝªþR-,-« ?Vf<º¾'B±èÝ;mÿþ𒇓ó¦ÃìÙ̵ŧ……•<}Z[QAˆHwi² ËÄ„Y“oÏ7ሪi¶ˆÂ¹>)ßòÍgèä”óf«¾}©‡ù †æUB*²³[XZB*²²XÆÆT!ËÄÄ}˶©©(û¯*,Ì¿};/!áÉúõT‰š†FUAËØØÐÙ9ïÖ­V‚/ZÇ21±4)nØ0>«Œ+²²ZXY1 µŒŒø7ØØ˜YÎÜ¿ð'¢©§gÒµëÛèh‡ÓÒÓSSW—¹6iùòöÓ¦™t릩£SSVÆ·\Dß„ïiÂ@uà]3I€?DmQ|¼c–³3óŸl[¥¬ÇŒIÛ»·ðþ}NMMáýûiûöYM¯}ºcGUaaUaáÓ;,z÷¦ - Jùõ×òÌLNmíû/’W¯²ÿœþ±øüsjî2õ¯•¿οÿÖzÏžü;w855YYO~ù…ÚäAppáýûuUUÕEEúöö¼»µèÛ÷é¶m•¹¹5ïß?ÛQO ?¿g;wVh°¹Ÿ_}yïÞOwì ËéˆòDZ÷ïÿöÂ…ì‹[õïϵª®ªJMSSƒÅ*û6•gô¢©«[öêU£6¡ðíyÑ7•"ü]RuÒ6ð¨-:á]¤RWï/'§O~øáé¶mW JݲÅaÎÆØ¶‘‹Ëí©SÆcÛŒOZcèârÁ‚«_|ñxíZ3oo!ûË“S-úôy{ñ"uhÇyóÒ~ÿýêàÁ÷þ™¾öˆÕàÁ/Œ6,a„ÒgÏœ/æÝ­íøñ:íÚÝúî»øqãØ&]ذLL&N¼9q"ÛÌÌvâDªÜfüx–¡áqãnOj̸‰(OÄØÝ½º´´¦¼Ü˜çÒ(Žóç?ÿý÷«ƒ?øé'£Îù>}ëQ£îÑ7e ßž}sP5‚Þ%U*`¨q81î.&&†âàà Æ}Ê3ê½JÉ~bä?j×ÍYnš'hv»<ô$Õ%»3îÌ¢²RSS !¾¾¾²n(j¨U~ÞS”•¼½wKM¸—ƶá?ä! *!×Füø F¸TÒ6|„¨Ý(á^> ö7€ŠCÚ†zˆÚ"úí~¸ÅÓH@ m!ˆÚ!Ê6n•…´ ˆÚÐä;Ø#p¨&¤mU‡¨-¢& isAàPAHÛ@¢vCš<¤Íý  j¶UšÊ^üRtÍÒæBíÃÛ*i[u!ð5H\CÚÂwJ i[Eaº¶pbÒfÂnÕ´­Òµù’è6½gIìä Ò¶*ÂtmA$:¤Í¸TÒ¶ÊA¼„Ù3ÒüSg@‰!m«L׿‹kH[jƒ ÜJi[!j3ÉjH[VGiÒ”u@z0€ÊE¶9›K¸—ÌÛb‡±m•ƒHG‘Ÿ¨3 Ä¶U®CÂ$“YÚBàú$Ê 3I@µÈÏ6¨Œm« lS iSå²Z¦‡·1  L0¶­üÞ†´@F¶U…*GÌF]e¼ðyZüÊ5…ÏÓŒÚÛu^hÔÞŽÚÜaė颺ÿÜÖ§Wáó´+V¥¥w°ï±|™^KªŽËä€Çuøj¸ÛŒi„‹S§Wäå»~7Ù¦ßÒ7™ ky÷ða‹–-]&M´ûbÀ£}Ÿ¬*.±a ˆ0“DÉ©øÀ¶ˆwb§VQÿ½±bu‡áÃFFŸë0âË+VÓåíüûx¯ ½¿{!$~åšNãG]¾à2eÒí_7Óu,ÜÝúîÙ™zâ$µÛ~a;‡ž:v{óVBȵíü{¼xÎ}VPüªµ„äÃxþ<Ÿ9§7»P>ÛV ª9tÚ´g>O³éÛGƒÍ¶ñï}kýFºÜ´“§¶¶43“RðìyìÂ%T¹f‹ts7W¢¦VSYIy¶7åÄ©êÒRjUAJªí¶ÍlV[ß^T{>[üpïþGû¸|7Ùªgº©ˆÚ |T3ŠP¶A 5g–¶±}ûQ—lúöyuɨ½]žû(©¶¢BÏÒ’bÜÁÞmÆ4‹.njÿÙXM^|~Ì×6mãÓC¿¢6yuÉn`z“¶¾½Úúöz{óV좥#/oô“E€´­ÌTóR$MÒ¦u^¿rÍÍõíÛw^H—¿ú÷Êó¿ÎR%Ÿ-Y¿j]~J*Û@ß~ØÎS'ÓW5¡/-Òqì˜K3mö§Ž8¿zÝ­_~ÕÒÓµ:ØuÚTj–AÇo¾f6€ÞÆ­%”Ò6(±\xĨ½]ÿýa¼åî³gºÏžI-ÚÚöÛ³‹¹–y8z¹ËÌé„nóçRýwm´ (+¤m¥¥jÛÍÒnpÏÒlÆð6(Þ·*ª„ïwèšÏÿ:›°f½çÂíAoEÑ`³uÌL-ºz8«gÙZÂm—¤mP$Ìß^á¿Éb„È ÐXBÞ=__³ôêþ&ö¶©úµ•UeïÞ½Ž‹œÙ{ë&ƒvÖRi©Äá €ÊI)¯kñŸ‰"II\k¹n©”ò<€*«©¬Ì¹w¿ëÜ9Ù‰÷¨«xÑ4Ø,}«6¿í2yâƒ=ûdÕB±CÚVfÊ”>?NIJ¢¢6½ ””éÜÐÞÞ¼Õ²££žekÇOÞÞ¼Å·Ž•wÏœ»‰Rn˜ä`& (>CÚIIáÎÎ2i ú–·œHz}5ÎÊ»'!ÄÊ»ç›ØkÔ2¶¡Aeq‰¸[*3HÛJÓdK¼ßOÅw%@žñ~K’o9…SW—yý†Ë䉄+ïIqêêÔÔ¹§ZT³ ô%ÑZ™ÀL¥¥L­>¿*ȼqõ¼2ABHî£äŠ‚Â3ÃG‡{ùœ1º¢ 0÷Q2oµ7q×Ì»¸I¿y‚´  þ–1˜1 È^ÇÆuš4º°ÁØëW:Mšð&î½¶®ººôMæ“c'ìÙï29@†í/Ì$àƒM7hgí6ý»«?BÞcÅꢴtãö=–/ÓkcIÕq™ðø£_ w›1-ãß+ «ÖÚ Hí¤ðyZüÊ5…ÏÓŒÚÛu^hÔÞŽÚ¤¥³S^R2†®@‰ñ·ý:6®GȺĪgë¡+ÝfL£ê«³´tÌÌ,<ÜýwnÕkc)ÕæJÒ¶²Qî›Ú„;;sÍ'‘Ѐ÷ ðCÿÌž7ðྺÚ¶±Qß]Û¯- í0¾×gooß½ýëfßë©«÷[¸»µõë59ÐmÆ´¿ïñ^³Bƒ­r<’rcÅj‡_Úôíó"úò«ØCmâ1{fÔw3DinsòŒ÷í‰*ô¶58âó¡‰ã'ƒŽR_9 mƒb oLÅ7^‹ý·ÔÀ¦¹G—´sçk**Úx}¦ßÖªàÙóØ…õŽk¶hA×4ws%jjÔCK3³ÌÝ\éo{>O³éÛGƒÍ¶ñï}kýFzÓNÎÊý²4¤mP Þ V¼\&M¼2ÿ纚šÞ[6BŒ;ػ͘fÑÅMMCã?õÔÔèE=ËÖ9‰÷4´ë³¸±}ûQ—lúöyuɨ½$ riIý×%¥2[Fߪ™K'uK·u+BÈgKƯZ—Ÿ’Ê6з6¤óÔÉõcí¦y„{ùô\»h©Í€~ÔÇ÷ǯ\ssýFcûö݃Ò-ÇÌefhJŠréGjGŒ;‰‰!„888ˆqŸò,ÆßŸÈÓd#åž´MS‘§IkÎó¥¶õŽs›d!55•âëë+놀²¡æ(ªÎÛ H#m‡{ùà €’‚™$¸3H ƶ@¥)ʽŠAQ0¢Æ&%alT7ˆó' cÛÊCÕ¾;¨:˜WbÅ‚´ ÀuGùß'È3¤mþ$ñ)>yP5HÛ’‚´ ÌÍ[Oø|uå*ù0äâÔéôl‹S§Ÿ>úÅ…(zíýŽÞïÞŽÝ„Ò7™—gýáÛç̈ÑigÏÓûdÖ冴 Œõç¾Þ«BïïÞC>Ìñ˜=“^Û/lçÐSÇnoÞJ¯µpwë»ggꉓ„k!+Úù÷yñœû¬ øUké­˜u@¹á €Â˜vræÔÖ–ff2K¨`ý loʉSÕ¥¥Ìúæn®DM­¦²’R’j»m³›ÕÖ·sÆ6³(7Œm“û(9'ñžž¥%ïªÇáÇzoÝ4ìLäJÕÔèEãö/¢.qjk¹·dÔ冴 À59ûeô¥ØEK]¿›B—Г¶F|y)pfÒÄqi?zm¸—ײളçùõ=9pÈýÝa¼{ÀÕ”f’ðGÏýè:oW ¥ËÌé]fN'„t›?Wжþ»¶ñ-çÝ(%ŒmH Ò6€¤ m+ j0&'Ȥm%Aål|ë@® mH Ò6€¤ mH Ò6€¤àî6 xpéPÛ¤mIAÚ¤mIAÚ¤mIAÚVÔuñ½|dÝ3êœâº‡Ši@Rpwá^>\÷T ßÑzºæó¿Î&¬Yï¹pAûÁ_Ð[B4Øl3S‹®NãÆêY¶–pÛøCÚ dÅë«q–^ÝßÄ^£Ó6U¿¶²ªìÝ»×±qÑ3{oÝdÐÎZ*-øÌ$VSY™sï~×¹s²ïÕTV2Wi°YúVm:~=ÚeòÄ{öɪ… â¶•Šª}QòíÍ[-;:êY¶6qüäíÍ[|ëXy÷̹›(冉¾"  Ð0“䈠¿xË©ôùújœ•wOBˆ•wÏ7±×¨e.lCƒÊâq·@$HÛ Gx¿%É·œÂ©«Ë¼~ÃeòDBˆ•w¤ƒ‡8uujêÜ×T³ ô%ÑZ€!mƒ¢Ê}”\QPxføhf‰YçN\ÕÞÄ]3ïâ&ݦÔüme£:S·_ÇÆuš4aìõ+Ô¿N“&¼‰»F¯­«®.}“ù䨉{ö»La;›“¶ƶAð·ý:6®GȺĪgë¡+ÝfL£ê«³´tÌÌ,<ÜýwnÕkc)Õæ|€´ ò‚w—*4²;8âó¡‰ã'ƒŽR@ú0“Di©Âdå†3 ¶•w• Î&€BCÚ¤ífñŽ&rü‰¿Ü6 „s ¶•¦(œGE‡k’ˆ‡ÜŽDÊmÃ@b9}Ô'0 Ûn.Dgøù-Œm‹Üš"ÇÍApâ”ƶ•רèŠQ@™ mH Ò¶JÀð¶¢À™P2HÛJ΀Ò@ÚV4•8GÊi[ùa T±à|(¤m•€‹“È?\Š@)!mH Ò¶ªÀð¶<ÃÀ6€²BÚV9Üòg@‰‰9mûúúBRSSÅ»[ Ê3œ¥„±mU„ÁTùs ÜÔ8Žx÷#Þ‚xeQ –۷˶%€sÐXÔ'¨ DücÛx)”svòg@DxE$þ±mPáÎ΄±II²nˆêÂ)P˜·­Ò¨ÀÒ‡žPHÛ*ŠREì“>ºÏ1°  ô¶U¢žl¡ÿTÒ¶J£†·¥ ÓµT Ò6‚À--ègUƒ´­ê0[j0]@!m·4 j¨&¤m [µTÒ6ÔCà–DmU†´ !p‹¢6€ŠCÚ†ÿ@à#Dm@ÚnÜb¨ iøBàn&Dm  mÜM†¨ Ò!éßMéÿîãÕ”Ò6Ä Üx³£¨Þ+ËÎŽûá‡ÈîÝ#ºt‰7îML ]S\ͺ~ýŸ©S¹»Gzy]ÿé§Šüüù,2’Y’«ç7óêÕsÆE¸¹2äÍ•+:Ê߃ý5p WaV\Üù#"ÜÜþúâ‹ô3g¨BAg_ÞÐg¿ ?Êñ“ QHÛ ÌØ¤$ r‹ˆ™³éN»6ož¾Íà F%$tž5+õèQ±÷ÉþýŽãǸvmÐßkéë_ûñÇ7y~â§¶–~øxï^±·JúrïßOXºÔcÑ¢Q7ov]¼øæ²eyˆý(ypjkÕµ´rïÝc:>8ØmîÜQ·nùíÚ•}ó&U.…³/ø@¢¶¡aÜ 4{$ïáÃNÓ¦±ŒÔY, OO¿Ý»éÊÌpNmí½M›Nz{óð¸6~My9½Ûä½{Oy{÷ðˆ®«ªâ=´_X˜¥··f‹Ú&&]~üñ]bbƒ­5ïÚõåùóÔòëÿ5´·§W iÉ“C‡N÷î}´sgBHmEÅE‹Ž{xœêÕëñ¾} >®¾zzìØÿW×ó_}U˜š*dÛ¿ (NO'„¼ÏÊ ïÔ©<'‡Rœžþ×€\»MÞ³Çuöl‹O?¥ººó÷ß'íÙ#¼…sû¶(›3eÇÇû9òUBBÛÞ½–,²mkooj¨83&FƒÅ¢æ‡d'$XöêŵÏw‰‰–>>ôÃ6>>Ì?<øv£Öòma]UUÆ… ¶C†Øü**ŠNíïîݳôöæ}š|Ï>—‡Û·=}: 2rHTÔû¬,ªðþo¿•çä >~ð¹s¥™™¶l©/ߺµ¢ `htôÀ?ÿ|› z·‹Ò¼?–‚úAø&ÌŸ!„ìùÕ¥K1Ó§w[¶ì“qã„ï@1pã''꟬"ì÷o߯Ÿòñ9áéymþü²ìlzCfµÓ}ú>}J-—çæžôö¦«¿|I-§§ÿéç'¤1yé×®/¨UTyÌôéÑÑÑÑÿNŸÎ¬,¤%e99ôNþôó+ÉȨoØË— nÎՀЂj¹º¼<ÜÅEȶo®^›7Ãáü˜¸qcÌôé'vîÜÌØX®Ý†»¸ÔÕÔÐëjjè= êF!O–o _^¼xiâDjùò”)//\à{hš ³Ïô§Ÿ_qz:Wá)_ßâ/¨å¢´´S¾¾+3žˆèÝ.¼éýpýÌê®:\™?'¼k…ïù'§ä½{ÿôóËKJâ=€‚Ò”uÚ36)‰ù¹³ÊÎødŽ é Ï+!¹¹Iaaqsçúóûp¼,;ûÜðá„Âápêꈚ½J¯M›ú…¶mËss(ûæÍøÅ‹½7oÖ·¶n°U„‡o¾¹¿ys]Mû‚"¶¤…™½\ž›«kiÉÕBá›3±Œ¨Mmmz9ßm-ºu»½reMEEî½{^ë×ÿ¯_¿šŠŠ¼‡?[½škŸ,ƒÊ¢"mêaeQËÐ^Ë·…´–o ÓOŸ¶6ŒZ¶:4íÌë~ý!,}ýª¢"ö‡CÓD9ûå¹¹zmÛrVäåéYYQËúÖÖyy+3ž]¿Án½¹ðíá˜?'MØóÓcÇl‡ 3qre' iÜ„pgg Ü"Fm&mSS×9s"»wç»¶…™Yßðp ÞU¥oÞPºôÕ«¦¦|7yþ|â/¿ôÚ¶MôŒÒÚËëöêÕZZ­>ûLÄ–0i·lù>3“ |¥oÞ4vs¾øn«¡­­ocó4<ÜÄÙ™¥¯oâìœúdžvvl6׿fnn™W¯Ú}HÙW®˜¹¹Ñkùvc£Z[‘ŸŸ÷æÊ•øE‹¨5 м<í–-ͺtyk7t¨ m…œý¦¦¥¯^éÛØü§~Ë–üljÊ,ÿ¸“†žˆèÝ(^jµÚÚ„ÊÂBQ6ésèÐå‰Yzz'M’hÛ¤ó¶¡)¸®U¢:3¹¹fi7µcfÌȹu«¶²²²  yÏcGGªœ¥¯O}kÒaôè„¥KK228µµEÏž]›?Ÿ^ugíÚŠüüŠüüÛkÖØ Ä{ˆ'ÞÛ¸ñó={¸¢v'EMmðÙ³OŸæ*Ò¦vÜY»¶²  2?ÿîºuÝœ/AÛZz{'……Q´öòJ ã;IÚiÊ”{›6eß¼YW]}óæ½Í›&O¦×òíÆFµöÅßÛDtêŸÝС/Ξ¥}Ó¦¬ë×몫K_½Š_¼˜ÚDÐÙg²6ìöªUeÙÙU%%wÖ¬¡ m¼»n]åÅ&· ·IDAT‡·ûpÁA›Aƒî¬]K—7ØuL¢t#×¥(„obìèøxÿþšŠŠ²ìì[¡¡¢ìPÇ¢ÏÁƒÏOJ kTKäƶ¡é¨¬©"Kš0žMq=úÁÖ­¹j°Xæ=6l Ê;\5ª¦¬ŒÚ•Ó”)DMíŸÉ“Ësr íí§M£÷`îáqnèК²2ëþý]‚‚xqwýzBÈ߃Ó%£nÝÒÔÑiüS$Â[ÂÔùûïo†„œîÓGKGÇq„¬¸¸FmÞ¨C[z{ßY³†Š‰­¼¼7lhÍ/m›º¹y††Þ^µªäÅ =këOCBLcÛ|»±Q­M?}Ú}áBf‰í!wÖ¬q?ÞÔÍÍsùò{6¥¥é¶níHUtö™\fÌHܰáÜ—_§ÓôéTaçï¿¿½zõÿ „X÷ïßyÖ¬úÊAA·–/?íﯥ£Ó1  QÝ.J7rýXŠBø&ž¡¡ñK–<ܹ³…™™Ó”)QQ¢ì³…¹yŸ.pjk;}èLÅ¥ÆápdÝPM £ A†OM!&ꧧǹxQÖ H!º”f’€x0ÓŒÒÌ-áz"HlL·W¯®**ªÈÍMüå«Ï?—usäf’€Ø0'–Ÿ[Âõׂ‚> ‰2°µý{РšŠ +??zªpÁLE ¬ŠØfgHÛ Y¼SJä0Â*D#@!mƒ4ðÆ-óD+Ÿ­e‚´ R%èÛ“R˸2o¨¤m!×-cö•ÎQøBÚ¹ µ+"a€4!mƒ<cøF¼BÚÜK@R¶$i@R¶$i@R¶$i@R¶$i@R¶$i@R¶$i@R¶$i[1„;;˺ Üä°IòFSÖ eÙÙw×®}{ãFMeeKgg§)SÚøúBÂÇ&%‰å™±±É{÷æÞ¿¯©­ÝºG.óçëXX©OçHM³.]º.Z¤oc#––ˆWºˆzjjÚ-[š¹»;Ojìè(™ÖIƒP”“ÊMöcÛ׿ÍÓ·±|ᨄ„γf¥=*öC<Þ·ï“qã†_½:ôÒ%£âæÎmp“±IIc“’†FE™8;_[°@ìM’¡±IIcîÝë옹»û倀|1ýI#‡”ø$€¢}ÚÎ{ø°Ó´il##uËÂÓÓo÷nòa`2ÜÙ™¡äÔÖÞ۴餷÷1kóç×”—SåáÎÎÉ{÷žòö>îá\WUÅ{ˆÞû÷·íÓ‡¥¯¯¥«Û1  àñcÛÆ66îX˜’BëÉ¡C§{÷>Ú¹3!¤¶²2aÙ²žž'<=o.[V[YIU««©¹»~ýÉž=#»wrð ðö *¯«ªŠ_¼ø¸‡Ç©^½ïÛÇÛ6Þ.Ô^jêê-Ì;ù¦ó¬Yvíjf󷪸ødÏž•t‡œôö®ÌÏwvN ‹üì³S½z½¾|9),,ÒËëT¯^Yׯ7؆§ÇŽñ÷pu=ÿÕW…©©|{@V'136öìС®®güýŸ8!¤TìÓ¶‰³óƒíÛK_¿fRÓ¨±Iª$),,?)i@däð«W5X¬{7Ò•snßxúôèèòwïlÛ&äX5ååO¶èÞzØàÌãÊ‚‚G»w}ò ]’÷ðá€Èȯ< „Üÿí·òœœÁçÏ>w®43óÁ–-T‡Û·=}: 2rHTÔû¬,áíT~ëÖŠ‚‚¡ÑÑÿüómBoÛx»HP{„hëïÿ.1QxKHC=Ì{\–A»Ÿ;FUÈNH0uqa›˜B*òò†ýóëìÙ×ú©"/oØåË®³g'®_ß`²ããýù*!¡mïÞ K–ðí¾¤po,\è4êÖ­>‡å=z$¤TGÖÞ¿}|ÊÇç„§çµùó˲³©ò?œœ˜ÕN÷éSøô)µ\ž›{ÒÛ›®Vüò%µ\œžþ§ŸŸ ýáäô‡“ÓÉž=éú\‡àªù‡“Ó1ËS¦¥¥Ñåe99tµS¾¾Å/^PËEii§|}©å?ýüŠÓÓ¹ö)¨ý‚Êÿôóc>/¾Må*Ô!›ÔÕÔ„»¸o‰ ¦wÅ÷¸%¯^ýùùçµÕÕ'!$äåùóÔ&•……§¶²’¹,J* ¨åêòrº¾ 3È‘òIìÝûÉ¡C¥™™ÿ©Ì¯Tì¿%©caá¹b!¤"77),,nî\ÿ#Gx«•egŸ>œB8N]QS£WéµiS¿Ð¶myn® MJª.-M9r$!8¸Ï¡CäÃਠÊ|Ë[˜™ÑËyyzVVÔ²¾µuE^µ\ž›«×¶­ˆíT^ž›Ë|^‚ÚÉ$¨=Â6ÉÏg o i¨‡ùWÏÊÊÔÍ-ãüùv_|‘së–ÇÏ?S¨Ã©³XÌeNmmƒm`Q šÚÚt}á¤v{nÞühçÎG»wk°Ù]-²êÝ[P!¨Ù§mš¶©©ëœ9‘¦ypiafÖ7<œïµDJ߼ѷ¶&„”¾zÕÂÔTÈ!´ôô:Nœøh÷nñ4¸eK¾‡najZúê×0µ_`¹©)sçÍi¯¢£ÍÝÝ…·„4ÔÂŽë4iÒÍÐPÝ6mÌÜÝ5ØlQž‚6HˆXNbËN|¶o'„dÆÆÆSÁšo!¨ÙÏÛŽ™1#çÖ­ÚÊÊÊ‚‚ä={è Ò±ôõ‹ÓÓéjFNXº´$#ƒS[[ôìÙµùóéUwÖ®­ÈϯÈÏ¿½fÍ A¼‡¸þóÏÅiiœÚÚòwïîoÙbææF•7óŠÑ6Þ]·®òÃ¡Û H•Ûv{Õª²ì쪒’;kÖo¿ r›Aƒî¬]Kïœo¸ºHP{xqêêÊß½K ¸}{§À@á-! õ° ãš8;kêè$nÜh;x°h=*¬ ¢ô@ˆå$^›?¿èùóºêjRWÇ©«RªFöcÛ£G?غ5÷áC ËÜãdž TyÇ€€ £FÕ”•Qóœ¦L!jjÿLž\ž“choïƒÁ·`Á‚ýèG§OŸ–ßóÛßþöÞ{2™L?üáÿûß{ßGM™2%))éÞ{ï}þù绺º_wò–¼ôÒKöÓßÿ}:L вÍf£i1Èã{¤v!½“6âe‘FNAòóNxÙºÜlÕgŸ}vï½÷6448L7¿ùÍon¸á†Àö×^{mùòåÒ‹üü|‡¿¶´´äääœ9sF¡ùõ¯ýÐCŒŒ¸üëhû¨ÄÄÄ'N,Z´(;´­V{óÍ7WTTÈÓyä‘wß}·»»ÛW«ð~!ô̈XŒµ#âØ¾Na"€ÀèééYºtiCCÃ7Þø›ßüæêÕ«W¯^}ï½÷nºé¦†††¥K—öôô~«<èðB688˜}æÌ™¤¤¤ƒÖ×× ôôô\ºtéðá÷ß~»ô¶;vŒŒŒdgg_ºtipp°­­í­·ÞZ¼x±÷=U___}}ýÏþó믿¾¥¥å»ßýîåË—_¹¹¹}ôQ]]ôßŽŽŽ·ß~û{ßû».0‘ ˆ4 AúÓW_}õƒü@£Ñ\sÍ5%%%###öïùÅ/~±xñbNššºiÓ¦/¿ürT«³ŸÒÝÝ]\\œœœ5mÚ´%K–üÏÿü—ë’–ÓÙÙ¹zõêY³fMž<ÙÝ6|ðÁÙÙÙ:.66ö¶ÛnûßÿýßQ}꺺º¥K—jµÚøøøU«VÉ0(|êÚÚÚììl­V;mÚ´U«V}õÕW³¸Ûø¾¾¾§žzÊl6ÇÆÆÆÆÆšÍæŸþô§^–§üß+W®¬Zµ*>>>...''§¾¾^ak½\©Â2·J¹îŸ}öÙ… jµÚØØØÅ‹¿ýöÛ.Ï=î$Êû›7»´ò髟šÆ„7ÜpCWW—ýô®®®ë¯¿^ñÜsϪN½i,ÊÛñâE!Äm·Ý&m_ºtÉþ¯‡B˜L&«Õª°/EEE !._¾<þNéêÕ«ßüæ7…¥¥¥Þ´ewu§ÜüÝmLyy¹bçÎÒÄgžyFñá‡:oªÇæãMâMõqðB$&ФvåÔ¾téRû#ß /¼ ýuddÄùKs!Äõ×_¯N”Sæ÷¿ÿ}—ÇZoÖ%Mùîw¿ëñœÜa!QQQçÎóòSwtt$%%ÙÿI^£»Õµ··'&&ÚÏ’í2M:l|__ßwÜáü©ï¼óÎþþþQ¥vû% !’’’Ü)ïWª°LûmðXwK–,qYï.'ºÛI¼Oíî*w´©Ý‡M#33Sñæ›o:ÿé7ÞB,^¼ØË:õ¾±(—Ãã?.„8räÈË/¿,„(,,´ÿkVV–â¿þë¿”»“É$„xòÉ';::Æß)ýêW¿BÜzë­Þ´eåºs×üÝmÌÈȈÑh4™LÒ¹ÍüùóçÎ+_ùã}óñØx_}¼@jH펺õÖ[kjjº»»×¯_/„X´h‘ý`[rròñãǯ\¹200pîÜ9鈵yóæ±¥ö˜˜)=tvvöõõ}üñÇ999^®KZŽÑhüðÃíG¶œ=òÈ#üãûûû¿øâ‹G}T‘——çå§~â‰'„©©©øÃúûûOŸ>œœ¬|ݼy³"--MšåøCjjªË4é°ñ{öìBÄÇÇ¿õÖ[_}õUWW×믿>}út!ľ}ûF•Ú7ø‰'žp¹µÞ¯Ta™öÛà±îöïß/„˜6mÚK/½ÔÑÑÑßß/×»Ëèn'ñ>µ»«\ïˆÏ›F||¼Âå¸uKK‹bæÌ™^Ö©÷E¡zzz¦OŸ®Ñh¾ú꫞žž3f̘1£§§G~ÃÌ™3…­­­ÊÝ‹”ø…*•*55õ‘Gyå•W”›§B§ÔÖÖ&„˜1cƨÚò¨š¿ÂÆlß¾]ñÛßþöã?–.þq^…Çæã±ñ¾ú8xÔÚÿôé§ŸJÿµZ­B­V+ý÷[ßú–âÌ™3ö³466JǤ±¥vi*77÷Ç?þñ{ï½744äýº¤åœµ{¹ÿ{Lí>lÿüÏÿ,„xë­·œÿôæ›oº¼®Ý]ù­±ØOùÓŸþänö?ÿùÏÒ{¾óïxs]»³ÚÚZûä=ªN騱cBùäa mÙã,ÊsäÈé¿ÿùŸÿé§Ôîþ µ¤öÿ›"=YBa˜Ó%i$IS¬¬¬t·Òå¼Òð’7ëòòH& j¾ùæ›W®\éììU°Ã2Ò,öªøàƒ¼IíÒ3\~Û~ã7zYž£½BÆ›•Žê uwã7 !^{í5—•Míî1/ö;‰ŸR»Ë ðyÓxöÙg…óçÏwø¾åêÕ«óæÍsù wå?¶Æb?eíÚµîRã~ô#é=‡’.¿nkkUÐÑÑ¡\e6÷Ï‘®?ùñìe[v®;³(oLgg§F£‘.÷w¹©›Çć}@jHíÿ7EºÏlîܹ¯¼òJCCÃàà`___UUÕ¡C‡ì¿IwpóÍ7 !Ö¯_ßÓÓS[[+}//óÞ{ï}ÿý÷¯^½ÚÕÕ%Ý•5eÊ/×åå‘LÊ:~üx__ß_ÿúWù$^~jéf2éÖÒÓ§O§¤¤xs7êu×]wöìÙ³gϦ§§{“Ú÷îÝ+]ñÖ[oIe"ßÙöÓŸþÔ›ò”—ì¼ÁîîFõf¥—9ªýäé§ŸBètº—_~ùòåËýýýŸ|òÉÒ¥K¥Ù¥+1>üðC9{¹ÛIü”Ú7ÀM£««K*Ã… JŸîêÕ«|ðÁÂ… …éééöi^¹üÇÖXä)]]]Ó¦M›4iRCCƒý&Mš4mÚ4i ¹¿¿ÿ¦›nBÌ™3çСC‹Ez^ûgŸ}väÈ‘Ûo¿]šë[ßúÖÏ~ö³Ï>û¬¯¯¯¿¿ÿüãÝwß-„ÈÈÈð²Sêïï·X,¯¼òŠ”wäÇÑxlËÎuçq–ÑFd‡¿zl>;öu© µÿÿ)Ò£'Fõ³ô\jÙ< ðP6!D~~¾—ëòòH–““c?ï¿üË¿Œ*ØùäÉÒ,Î÷:ÌèÍC•ËS^òý÷ßïó'?*,sTûÉÀÀÀ]wÝå®Zzè!ƒ”w¤vç ðSÓ¸pá‚î%™3gŽÃ³Ò=–ÿ‹ìëR;@jÿÚ”>øà¡‡š={vTTTllì¼yóÖ¬YóÉ'Ÿ¸[ÝððpqqñÌ™3§NúƒüÀáêòòòœœœøøxµZœœ\RRb¨òº¼<’µ··çææj4šéÓ§ÿë¿þ«óOœxüÔuuu<ðÀØ~eIšEº´wÖ¬Yk¡··wïÞ½ ,ˆ‰‰‰ýæ7¿¹oß>9={,OÛבgÆŒZ­véÒ¥uuu [ëq¥—9Úýd```ÿþýf³9&&F£ÑÜyç'NœþÔÔÔô½ï}/>>^þwåÄç©ÝyüÔ4l6Ûßÿþ÷;v,X°@º ###cÇŽÎx÷¦NGÛXä)Rw¸ÆCòË_þRú6@ž200ðòË/ß}÷Ý jµZ«Õfdd¬]»V^ÑÿøÇ7~ó›ßŒŠŠš={öC=ôûßÿÞ›NI›””tÿý÷¿øâ‹7?xlËÎuçq–q¦voš7ˆOú: ü¨lüx;€À:zôèªU«/^|êÔ)¯KÎ+ûtÝÝÝqqq111½½½ÔuxÔ)ƒI{ðÁOŸ>ÝßßßÙÙùÚk¯ !¾÷½ï…ß'íïï—îS”¯ÖÀ'kàÿŽF¥r˜rÓM7}òÉ'Òcà°ê€utò'}òÉ'wìØAÕ‡A@`¬€ß½ûî»÷ÜsN§‹ŽŽNMMݼyóoûÛDö ”z½~ãÆ%%%Ô;À—‡†+€ ÇX;@j@jHíHíHí©© µ µ µ¤v¤v¤v€Ô€ÔÚÚÚR;R;R;@j@jHíHíHí©© µ µ µ¤v¤v®©)!­´´”B œ ì1Ö€( Š‚cí” „ Ø1ÖÚÚR;R;R;@j@jHíHíHí©©©‚†J¥¢Ð{€Ôt<æ(D›ÍF“'µ&þxL! £©ܪ¯¯ÏÉÉ™:ujLLÌ}÷Ý×ÖÖ&MÜ´iÓ¬Y³f̘ñÌ3ÏHOž<™‘‘m2™>ìn™}}}:N§Ó­^½º¯¯OþÓ¾}ûôz½V«]µjU¿4QBÞºukBB‚F£ÉÏÏïîîv·1Ò,*•Šá7 ¢ÐäIí¡²³³ ÛÚÚÚÚÚæÍ›WTT$M/--½páBeee]]]CCƒ4qÅŠ¥¥¥]]]gÏžu·ÌmÛ¶577×ÔÔTWW[,–í۷˪¨¨8þ|}}}KKËÎ;fÜ»wï¹sç*++­Vë”)S¶lÙânc¤Q7›ÍÆð@pGxV4ý;€ÐUZZ*ÿë===&“InŸ3gNyyùu×]gÿ†¹sç=øàƒF£Qa9³gÏ>uêTzzº¢ªª*++«©©I:ÖÖÔÔ¤¥¥ !ª««³²²¥éRçl2™Þyçùóç !¬V«Ùlnmmu·1ò\!WÎï@IÒ|‚±vøšÓ§OgffÆÅÅ©T*­VÛÑÑ!MoiiIIIqxó±cÇÊËË.\h4?în™V«Už755U¾êF‘œœ,½HII±Z­3655™ÍfµZ=yòdƒÁ Ïèrc€ ÄM“½ªªŠDp"¸àìˆB µ@9zôhqqq\\Ü]wݵxñbyú®]»n¸á³Ùœ’’"_Ö²téÒÜÜ\­V[RRòꫯº[æîÝ»õz}ZZZzzzRRRYY™ü§ÌÌÌ $'' ç ÇKJJ233—,Y¢Ñh–/_ž››«°1›7o^´hÙA(Ù99;¸*—33¡+,ï’´ÙljµZaäžrFHJ‚GÊ™BKŒµ@p©¬¬t¾À3RÁ`p Ê¤v€•“Ñ.áŽ;î(..¦$A Ä8û" !̨)ªPbÿË©@X¶.áXpõrfW±ÇX;˜€àN9ø»É»¤v‚{h œIí÷ÔÛÛ»råJ­Vk0öïß/W„J¥:pà€ÑhT«ÕBˆ¾¾¾‚‚N§ÓéV¯^-_¿çPqö³ïÛ·O¯×kµÚU«Võ÷÷+œKدhxxxëÖ­ &??¿»»›:"µ€ BpÀÙ‘óÄ;v|ùå—‹åüùóö:sæLeeåÐÐbÛ¶mÍÍÍ555ÕÕÕ‹eûöíWWQQqþüùúúú–––;w*¼Ó~E{÷î=wî\ee¥Õj2eÊ–-[¨8…kž„.ž#N9#y¬wpppÓ¦M³fÍš1cÆ3Ï<#MºqãÆŽŽŽööö¢¢"woÎËË+**joookk+,,ÌËË“¦›Íæýû÷÷ôô455­Y³Æ~– 6´µµIï_¶l™—[µfÍš‚‚‚ÚÚÚ¡¡¡‹/æççÓ(Hí Hƒ»óp{vvvaa¡”çÍ›'çËÒÒÒ .TVVÖÕÕ544HW¬XQZZÚÕÕUQQqöìY…uEø}*•ª¬¬L§ÓÆŒŒŒÛo¿=**Êå;wïÞ­×ëÓÒÒÒÓÓ“’’ÊÊʤéGŽ9~ü¸N§»í¶Ûî¼óNûY233,Xœœl0¼¿¦¤¤$33sÉ’%fùòå¹¹¹´ÇedBwIRο@é.™ôôô˜L&i¸}Μ9ååå×]wýæÎ[TTôàƒFåUp¤½Ï?ÿüþûﯫ«ókõÔ€4 JaÜOŸ>ýÄOTVVJ®¨T*éŠgµZÝ××']â";{ölYYÙ'Ÿ|ûüóÏçääx“,£¢¢¤ÿÊ÷AJ«ûªR©._¾<00PPPžž._hDj'µQ’rFþæÌ™óïÿþï÷ÜsN§ëêêÒétòtç±vÙÉ“'W­ZÕÒÒâM²4üqRRR¤P•J•ÐÓÓóÀ:t(..ÎO©ÝùÂ'ÂçØðäG¤É`ÜR2î6›­··7:::66Öb±lݺUþëÊ•+ׯ_ÿÒK/ÅÅÅíÚµë¹çžBäååíØ±#--mdddxxØËI÷A¾ð &“©ªªjÏž=¯¿þz$”°?¢³Ëe’ÑIí½´´ÔáÍ.çužèÍ Œ¥ô÷'Nlܸñ‘G™3gNqqñ[o½%½a×®]ÅÅÅf³Ùf³É?À¹téÒÜÜÜ¿þõ¯×_ý«¯¾êåºJJJT*Õ’%Kš››çÏŸ¿mÛ¶<;b— Ê¢ªÀW]yʨb·Ç7â R0RKp©|ÐÞà«xMŽÁ µÝ7QØy}ÌFŽGx÷1gîƒ L9ƒÔAÐ'*¯“ãA „? ™³R;„[@¶¼>æIˆÁ µ@t…%‡D&ǃàÊ™ÔaÐà ¯¹ÄÈñ PRÈ µÀÓáDEɰÉëäx„h \{ R;Ð#9¯¹ü ñ ¸‡e9SȤvôË›×Ç\GäxÜ î µ‡€*©Ž¼NŽÁ µ  “×#t÷ <á“àN†¡œIíA]áS.Éñ PRÈ‚¯5Híèäuö4r<NŽÁ”3©¼Ž Úo©/()dR;zdùP”‚k¯Aj@@'¯#D›õKpHí‚.“QÈëT1m„àN°©¼ŽpkSì w€Ô€€N^Gèµ;v’0îdÚø7 Èë ǃàÚ:yoÛd@jèðY¥Pì Ç µ³9x“×ÁÎFW€ÔÐA^9Hí¼LT÷ €ÔÐ#«6©2ãÚ:ÈëÀÄôTìáH투tÎÁ¼ãÚ:ÈëÀt}4€ÔÐA^B¯{¤™¤v`":Ç!ò:eãR;©t׈èliS©  Ãg{û@Ž@jäu€æF ÚA@Èë9©t×LÔQ€6 ÚA@GdírìW9©t×LÌ…6ÚáËŽ’^äuäx€Ô:ØEÙ š?G%€ÔN÷GWò:€°8ŠÑQ¤ö° ètp ¯ ǤvÐò:€`9&Ò«€ÔNj' >Û½ÙãR; ¯ ÃáÀ R;èy9 µÐò:LÔÁš^ ¤v:Yí‚9 µÐò:LÌqŸ^‘ÚÙуÿôÔ e€öK9#¢S;»íT%€fK±ÃÔ>ß-Ø?&¤A–––Ròô­”€ào¶´â@–¹(R;T¢ äõ`,y²;©ÝóΉj–×Av'µ{Õ21Q}"äuÝÃÕ$_5Nª¢ºEJ„‘®‚­jø¼HOíÔ}ðôÃ!‰¼Ù:ЬÔΗ,Û3Rò€ Œì”•P¿Ê1Q " Æ\kòÐ;u&ÑDéà¨Dõ!þ¼4ýäÉ“ÑÑÑ&“éðáÃâ#â*•JwØÔúúúœœœ©S§ÆÄÄÜwß}mmmòÛÖå¼Xfw&C³Ô)‚:µ¿:Ïœ9SYY944$„Ø»wï¹sç*++­Vë”)S¶lÙâÍ\¸p¡²²²®®®¡¡Aš¸mÛ¶æææšššêêj‹Å²}ûvùýååå}ôÑ•+Wrrr{ì1iâŠ+JKK»ºº***Ξ=+þ1dn³ÙìÇÎí75;;»°°°­­­­­mÞ¼yEEEÎÛæ¼.—‹¥!Â#Þ…„‰½Y.DoÕ#oïþìe¦ÿ*•ª¹¹911Qú¯ÉdzçwæÏŸ/„°Z­f³¹µµUz›»Mš3gNyyùu×]g?qöìÙ§NJOOBTUUeee555IËéèè˜9s¦¢§§G§Ó  !æÎ[TTôàƒFûm³_©Ã¦Úëéé1™LÒp»<—»u)|–14Z#Ar äµaœÄtY~í²œ€»8wK›ðŽ”>6DMò¾ Ç_‹ö9¸©©Él6«ÕêÉ“' ù²---)))­V«<155Õ~9RŒBh4iÔ\qìØ±òòò… ÆãÇ{³©§OŸÎÌÌŒ‹‹S©TZNVÞ IDAT­¶££Ãùý.×åÃó]Úþ˜0´‘áÚý-ËÐÐÐðð°Ífñf–ºº:‡‰z½¾¾¾^z]WW§×ë•rË-·œ8q¢½½ýСCk×®õfS~øáuëÖ566ŽŒŒtvv¾±ÙáC*•jß¾}z½^«Õ®Zµª¿¿_š®pÿ†|›‡ýÝ_~ùå¬Y³ä“ØÁÁÁ„„Š@Àº²QÝ,粋syc›ôbüwÍI\¾Ù~u.;d`Œ©ÝOß•¬Y³¦   ¶¶vhhèâÅ‹ùùùgY¹råúõë¯\¹RXX(MÌËË+**joookk+,,ÌËËS^H^^Þ¥K—FFF†‡‡¥‰Ó§O¯ªªr7Koootttll¬ÅbY½zµ÷ŸQy±Uò@EEÅùóçëëë[ZZvîÜ)MT¸C¾ÍÃþn3fäååöØcÓ¦M›6mÚc=ÖÛÛër9òßxão|ãjµ:##ã½÷Þ“&îÞ½;..ξéÚÏ{âĉÔÔTµZœœüâ‹/:¿Íݺ;*>,y¿@Öµ¢¦¦Fz]UU5{ölç÷twwÏš5K~ss³Ë†\WW7gΜ›Íöoÿöoo½õV˜•€ m†]Óܹs/\¸ ½nmmÕëõ ¡Â¡‹sy¿öÚk«««¥×Ÿþùµ×^+¿¡££C^ŽZ­–^ÆüíosXšË7Ûçrà+—=ýÄOTVVJß,«T*éº5å[µ¾ÿýïgggçççÏ›7ïOúSLLL8•€ m†}QTT”œ†GFFœ{°Ñvqjµº¿¿ß¹«t÷þ³gÏ–••}òÉ'±±±Ï?ÿ|NNŽÂ›í_¸ì#¼rᎷWÈ`³;à[ö·‚ éõØîß(..~î¹ç>þøãoûÛˆìà’Ç›åFÛÅà®9…]jŸØ“-•Æ0_Ù°aƒtqgaaá²eˤ‰^Þ¿áp·Æ¢E‹´Zí–-[~ðƒP°&ŠÇ›åÜuqîî@óÉ]scîQ¤ö Œ.¯`‹œÈøUffæ‚ ’““ ƒ¼Ë=z´¸¸8..î®»îZ¼x±»y7oÞ¼hÑ"ûéÍ›7755effR°&JIIIffæ’%K4ÍòåËsssÞ஋sîÓ$»wïÖëõiiiéééIIIeeeʰtéÒÜÜ\­V[RRòê«¯Ž³C\rq];UOxd§ä#³êv]»oOƒ_|ñŦ¦¦={ö„_YàhZ25Þ&y¬9LT›‚_ggç /¼°nÝ:Šà8êMíŒcMl#¡äBT*ÕÌ™3üñk¯½–Ò8f:…_©9»â¼Ň߯ò£Ü@/Š€™äIÙ)y@h¼8rQ›˜€ÔNp ’ìÇ/Pƒp v¨0jŽ€—/yŒ–Y¨'j0øM¢™êCSS[`œÉÏ~Ü2!¯Ãk¤@* ¤vaY8´uDd'µBa©Ë€ˆ ÊëDö¥¦€oƒ»Ã€.1HN¥¨ R;Ù¼?Rñkº@°u¬ Ä,¨ÚºTÊ -—b©@¸÷ìDlHR;€`92Ù_êñaÀ„k—hÿÓQ\#Ž ÇݨIÝ«#»G†ñè_aÖ1ºì͸¿¤vÁ›Ô=.Ðc”€ê½¿pù$@j0ñIÝãÒHðÂ5¬»[Ù¤vÁ›ÔÇœà9¤ªNrüÙ¤v¡‘Ô=nð‚°ŸôÇ·Ž^ÞÁÚ’z0'¸„@¸†u…ì.z©àüI}Ì žÃô–ì[Èî µ{B2©{ü\ Àð_‡9Q= Ù¤v€¤Î– ¤Ã:Ù¤v€¤q…À%4FÛsgAv© ©GDá0Àc'üÙ¤v€¤A%F‚è Bºçä§UAjHê$xŠˆ”^4 Z:?ÏR;ìI®Ùç%Ì<9i˜µk²;Hí@Ð…u:âÀ”9  ¬‡Av§×© ©Gz‚§R€êN#ð!ZÜ® R;@RÜ:b¹5b›'Ù¤v€¤NÅ‘àÂ:Ù¤v€¤Ž°HðÔ,ø®•vGv© ©ÃsE3LTïJ+#»ƒÔÔ1–Ú'Á„u²;Hí@h$uºBö …×ìÀ˜»Yš¯Ê“G¼“Úˆët|P>@*¿ Ð4h,þ(a²;© ©n÷<@X'»ƒÔÔò ž ô·´‚‰ÍîT© ©®÷+àA—Ë><Ù]0ôNjHê€ÇÂ:Èî µ$u„|‚g/EØô½ìÌdwÚ’:Âj§eaÖý²ë’ÝAj¼=0Ðõ D÷d<ë »ƒÔŽ0ët4ˆ„Ï~Ž`ë„Ù'Éî µ$u°Û{å é‡ÙøÃ!»“Ú’:0®¶@‚a¨q²;© ©þMð4ø©Cf×"»S,¤vÐ5Ôqµàá×>™‰ìÎЩHê€ „uø/» †Þƒ•Êf³Q ©mѲCiPDPÞ%ØCÆgÙ[@j‘(¢»úDJŒsff¯` µ“ÝIí ÷üß2ý´XŽ  ¬Hð ¬ÓçÝ#×µ“Ñ}|\ÏìÞG :À˦ÄShÈX€¯NZ7!µcbbz¶º1§vzÀc³âÖˆêð©VÝIíÕ¤Ò­kT©~aÊ¢« ò¶f]GÐ~ºè° »“Úá³0¼’—©Þ„­`ûh!ô-üêm™ìNjÇ3Ü.#¸Šdw>”/Îÿ˜ÔN™“ÝAj c9Ä›O|@^¶¨GÚ ËìN…’ÚÁ1f\…Ɔö(£/eg g¦BAj'¯ƒ})=s˜ïÀlpn6©=dv:2–'×áÛßîèNC(»SAáÃ#*ÚÁ&ˆdw ¼óºàrÛì–©)—{,Åøî"¨ÊœÔN^ç Av"èŒ8¯#¸“׃![< µst¡Ì¿–Ú)y ±,0m5¤ûäˆL!¯“ÝÝ™DÅÛMtÂÏ—( Ì5¥Aõ…\àxDÚ‰ŒàÄ ®~Ì*Q8]Ë®ÌÙÔNÇÄÑ…êð¯ÞÞÞ•+WjµZƒÁ°ÿ~•J%MW©T0jµZÑ××WPP Óét:ÝêÕ«ûúúä·Ù/Í~ö}ûöéõz­V»jÕªþþ~ö"L`^Ÿôᡇý6ø³ûDÕ©¾ ‘R;vìøòË/-Ëùóç+**ìÿtæÌ™ÊÊÊ¡¡!!ĶmÛš››kjjª««-ËöíÛ=.¹¢¢âüùóõõõ---;wîdB04a:Uj3#;5Ne‘Úé”8Œ¡"\o¾ùæ³Ï>;kÖ¬„„„gŸ}ÖþOO?ýô5×\#¿íÀ z½þ…^xã7<.ù¹çžÓëõ Ï=÷Ük¯½Æþ¢àeCàYÔ©=ÄÎØ´§áTG­­­&“Iz-¿$&&ʯ­VkJJŠô:55µ­­Íã’“““¥)))V«•]œ€:õþøÂîJõ‘ÚÉî ^¾F¯×[,éµüÂåÛêëë¥×uuuz½^z­V«{{{¥×—/_¶ŸÅþýƒÕÐB´Ùúc$"ð_¢`áÔ-Ù©DR;ûPû» ‡‡‡·nÝš Ñhòóó»»»=.áäÉ“ÑÑÑ&“éðáÃÒDwËQ¸Ùñ©§žŠ7 Çê©§fΜi0Þÿ}åªTªƒšL¦èèè›o¾ùüùóòA¥RqaÏh=úè£7nìèèhoo/**r÷¶¼¼¼¢¢¢ööö¶¶¶Â¼¼…Sáë,û¯ã\~·¦ð$Pç¯ÂÂÞ˜¿6TžÑçMyÿÌÖq~m‹Ð=YEpÕ© g×®]»víòßòêwΜ9_|ñ…Ç·¹ôî»ï åå\{íµµµµÒëššaw‹Ëuɯ½Ü0— é üŠþã?þ#!!!...??¿««Ë»YØ”U(v BˆššéuUUÕìÙ³¥×sçνpá‚ôºµµU¯×Ëïonn–g7øÛßþæÐ®«««¥×Ÿþùµ×^+ÏÛÑÑ!½îîîV«Õcþ¼¡²{!._¾l³Ù¤/äד'OöXÎÊ3ú£âÜU}Gêr¥.?¸ýê¶ÊßM# ŽÔ»þx~ÝES³ŒµG5kÖÔÖÖ ]¼x1??ßã,yyy—.]‘‡ÆÝ-DzǿaÓ§O¯ªª¢BÇ`ݺuV«µ««ëµ×^‹‹‹óÕ™?<\>…Sáë,û¯ã\~·¦ð$P_}BƒŽcþÚPyFTœ7äý3[Çùµ­oG4Ãfh6BØ_”år:uê=R{µÞ’’’ÌÌÌ%K–h4šåË—çææzœeéÒ¥¹¹¹Z­¶¤¤äÕW_U^Ž—7;ŽÃ6oÞ¼hÑ"7x¾¾D(rùÎÄÄD‹Å2444<iw·,»[ Ë£åç5‹¯?µY~1þ[Þ#ç†iR{P÷°9h…ÍÍŽÜ-„åò)œ^~åò»5wO…³1|Ÿé¿ŠóJýú1€ƒ×… *++ëê꤉ ÷”í>iw twc´P|j³Ony¦U|C$qÂ3¢ó'cØ7~ö³Ÿ=ùä“===<ðÀ¡C‡|uåtØ×' ”•O> JJ]º?¿7ÉÞä}Ž¿{°9sæ”——_wÝuögÏž}êÔ©ôôt!DUUUVVVSS“´\¾|9>>¾¿¿?&&F~­Õj¥ø«R©jjjÒÒÒ„ÕÕÕYYY œ;wnQQу>h4÷4‡]Nþ¯ÂæuttH·gôôôètºÁÁAw;sss³|÷…ÉdzçwæÏŸ/–˜ÍæÖÖÖìó¥¥¥þÞ?k'µÿÿŒî|·õhùãfÇȬ Ò:À \Â{o K---òíã2…{ÊÇvŸ´»º»1Z™Ony¦IíA—é•&°ˆì@xt§4á±Q9¡NCKbbb]]ÃÄñÜSîò–ew ÛÑ>¿å=Œo˜&µÁ‰ÂDÈ]ð@[ ¶½Å'_ºb­\¹rýúõW®\),,”&Žçžr—·,»[ òÑîžÚìó[ÞÃø†i5»xpfwiÏë^àT7àÃŽ”3ðpꢩJ/íÚµ«¸¸Øl6Ûl6ùæÑÝ»w¯_¿^º<ý‘GÕ=åÒ-ËW¯^}ä‘GäZp·@éÆè¿þõ¯×_½óÑÒS›¯^½êp68žÍs©¤¤D¥R-Y²¤¹¹yþüùÛ¶m ›úånT¢$……L-SV‘“Qð½"_]²«g“ ­=3´nYŽ„}•±ö8r3Ò 'EAX¿ìxÝ}Þþ{KöabPP}(vHº5R{¤dwR”›% „w{'¸ÙƒvÏd·Ÿ<¥Ú¯iÔNçå"µÓÚÉë@thYÝ&yc„—ÇDø;œ¦Éë£Âóó#´‹ ÎIÆB´> ¥Íþ6=!÷LÙIí“ý©¶É§£ÀÙ»'äÙ!´ÇNT‘ÚD=)ý©T7¨²ˆ-g. ‰\4õÂuí :tgœ˜‘×Iídw„L^'µ„LvÇ„ÇwR;þ¼»mP©T0jµZ1<<¼uëÖ„„F“ŸŸßÝÝÍÎ ÚˆhÙÙÙ………mmmmmmóæÍ+**’¦ïر£½½Ýb±üùÏþðÃíg±Z­_|ñÅž={–/_nµZöìÙ³iÓ&ç…———ôÑGW®\ÉÉÉyì±Ç6ãÌ™3•••CCCBˆ½{÷ž;w®²²ÒjµN™2eË–-T@jÀQD ·_¸pá;ßùNllì´iÓÊÊÊä!ó×_ýÀ³fÍÒëõÏ=÷œý,;wîÔjµË—/ïîî–_öÙgÎ ?xð`RR’F£Ù¼yó§Ÿ~ª°O?ýô5×\#½~饗8””4uêÔŸüä'ÇŽcŸHíDtö:}útfff\\œJ¥ÒjµÒôÖÖÖäädéuJJŠý,ñññBˆ)S¦Ø¿v^øÌ™3¥FGw'11Q~ÝÔÔd6›ÕjõäÉ“ ƒ|Ñ{@j B=üðÃëÖ­klléìì”ï%MLL¬¯¯—^×ÕÕr“-ËÐÐÐðð°Íf¡šR;_i÷¤öööFGGÇÆÆZ,–Õ«WËÓóóó7lØÐÞÞÞÖÖVXXÈMZ³fMAAAmmíÐÐÐÅ‹óóóÙ-R;íèÑ£ÅÅÅqqqwÝu×âÅ‹åé?þñgÍš5wîÜ deer“JJJ233—,Y¢Ñh–/_ž››K5¤v\óÇp{ággg×ÖÖÖÕÕ­]»V¾B&&&æèÑ£===V«µ¸¸Xžnÿ8v—¯]¾S(>ÇÝáO“&MÚºu«ÅbøôÓOzè!K³ý µ¨`þùq€¼ê µðA|w˜‹s„G°‹ðx§rB¤vÁÂ'ßkó3é‘pF'ÿ÷äÉ“ÑÑÑ&“éðáÃÒDw?™éðËš¤± ï P&©À¹û…s•Jµoß>½^¯ÕjW­ZÕß߯<Ý9Š nÚ´iÖ¬Y3fÌxæ™gV'Íb?'¿èëë+((Ðét:nõêÕ}}}ò¼üùôÞÞÞ•+WÊ?Õn¿ ûð§°"—ŸÎc9À{+V¬(--íêꪨ¨8{ö¬4Qá'3íY3˜q2N¨M€ÔL0w¿p.„¨¨¨8þ|}}}KKËÎ;=Nw>È]¸p¡²²²®®®¡¡AauҜˡ¸mÛ¶577×ÔÔTWW[,–íÛ·ËòòçÓwìØñå—_Z,–óçÏWTTØÿÉ>ü)¬È/Ëi4š¦¦&«Õj49"MTøÉLû_Öôy,ó_àC¨Gv_œ£:~øã(ÒÓÓc2™äñïššš´´4!DuuuVVVcc£òt©Ë/æÌ™S^^~Ýu×y¹:ûN@þïìÙ³O:•žž.„¨ªªÊÊÊjjj’ÞÐÑÑ!ýcOON§t¹–¤¤¤ßýîw©©©BˆÚÚÚôôty;›››åßhTX‘Ë sWÁ\¿¾î óìÙ³eeeŸ|òIllìóÏ?Ÿ““#„ˆŠŠ’OçFFFT*•ôû; þf%/“äê‘}bkÁ~ÆÚ‰áîÎ…ö¿pnµZ=NwÐÒÒâðÓèÊ«sÉjµÊ IMMµÿµs/>½µµÕd2I¯åûŸUWX‘;^–djµº··Wz}ùòeyú-·ÜrâĉöööC‡­]»V®ðøÉLR;‘ µðw¿p.„°ÿ…sƒÁàqºƒÄÄDçŸFWXKz½Þ~uz½~´P¯×[,éµüÂû¹ šÞ—df³yÿþý===MMMkÖ¬‘§çåå]ºti```dddxxXšÈŸÌô÷(fii©¼ Â_åuj µAÄÝ/œ !6lØ ]€^XX¸lÙ2Ó¬\¹rýúõW®\‘#ÝÝê¦OŸ^UUå¼¼¼¼¢¢"ù‡ÖóòòFû}ôÑ7vtt´··Û_µïåŠÜMï˲#GŽ?~\§ÓÝvÛmwÞy§<}éÒ¥¹¹¹Z­¶¤¤äÕW_•&†ßOf2jKe¤vcçîÎ…™™™ ,HNN6 ö‡.wÓìÚµë†n0›Í)))òÅ$îV·yóæE‹9?Îy÷îÝz½>---===))©¬¬l´°¬¬L§ÓÆŒŒŒÛo¿=**ÊåÛÜ­È]Ðô¾ »é¦›*++Ö­['Óòè£~þù烃ƒùË_î¾ûîÿ;*ê'3YwöY}&hó:‘PÆÝ¨Àèüþ>œ¸»çÏO÷ÆçŸ~ÿý÷;_·ãÃò •ú •ÍËOê°.¢aPí A[/܊ࡦøÉã?^ZZ:00P\\,=ŸžøE#¯¤v‘Åùi8üßøÆ 7ÜÐÓÓóÀ<ùä“Üh²;y2Hí@ˆqwùG0_ãnÛÖ­[·nݺÀ¬ vÇ„Çw¤vAÍCvy µÔÙ‚O~Híü¥© µ0 ±À˜q7*@ìhDìkˆ ŠÁޱv€T®ùЈ€ÔœÂWÈyìk‚; Ø1ÖÚÚR;R;R;@j@jHíHíHí©@à©l6¥ ´´”B œAjäHPì¤v€ñGr$eR; ;‚ò'µ© ÚÔ Hí Ñ\HÔ‚7©)ø¿²‚T‚cí€HÝ!Ø1Öˆ}THí€Ì*¤v0á±Ô Hí £Ú©©Œ C³Ô)Hí â&J¥¢~Iíd;_Æey.¿¦mê”Ô€±ã-AjcsZšÊIDATaÂaZþïÉ“'322¢££M&ÓáÇ¥‰ÃÃÃ[·nMHHÐh4ùùùÝÝÝò\0jµÚÝZöíÛ§×ëµZíªU«úûû¥é}}}:N§Ó­^½º¯¯ÏyÒ&©T*û±sûÕÕ××çääL:5&&æ¾ûîkkk³ÿ,γ»Ü<ûºû˜ µ—+V”––vuuUTTœ={Vš¸wïÞsçÎUVVZ­Ö)S¦lÙ²E~ÿ™3g*++‡††Ü-°¢¢âüùóõõõ---;wî”&nÛ¶­¹¹¹¦¦¦ººÚb±lß¾ÝyÒ¹Íf³;·_]vvvaaa[[[[[Û¼yóŠŠŠì×ërvgö Tø˜ˆÄ3[¾µÞóÓÃFTª¯eù¿sçÎ-**zðÁF£üW“ÉôÎ;ïÌŸ?_aµZÍfskk«4Wsssbb¢ÂZjjjÒÒÒ„ÕÕÕYYYBˆÙ³gŸ:u*==]QUU•••ÕÔÔä¼@çt·ºžž“É$ ·Ës9Ìîróì¨ð1ý”ßJKK¹º=h1Ö‚×±cÇÊËË.\h4?.Mljj2›ÍjµzòäɃA¾E¡Ù%ÉÉÉÒ‹””«Õ*½¶Z­)))ÒëÔÔTïhÿ×Ó§OgffÆÅÅ©T*­VÛÑÑ1†Ïk¿@…éï³2Ú\P«Õ½½½ÒëË—/ËÓo¹å–'N´··:thíÚµr´µX,CCCÃÃÃ6›mddÄûÕ××K/êêê ƒôZ¯×ÛO×ëõcø?üðºuëGFF:;;Ç?>ž R;€ï™Íæýû÷÷ôô455­Y³Fžž——wéÒ¥‘‘‘ááaiâš5k jkk‡††.^¼˜ŸŸïýŠ6lØ ]z^XX¸lÙ2y-EEEíííÒô¼¼<—óNŸ>½ªªÊÝ’{{{£££ccc-ËêÕ«G;»³ñ|LÚ|ïÈ‘#Ç×ét·ÝvÛwÞ)O_ºtinn®V«-))yõÕW¥‰%%%™™™K–,Ñh4Ë—/ÏÍÍõ~E™™™ ,HNN6 òÕ »wïÖëõiiiéééIIIeee.çݼyó¢E‹Ü=æèÑ£ÅÅÅqqqwÝu×âÅ‹G;»³ñ|L„îF£ 'ÝP¼Ú÷qR³ð7ÆÚÀX²¨_ôœ“3N0¶lÌ ÏùB›ÍŽƒ$B*¤v¹hH½€ÔȈ .HíäEʤvÙTHí€àŠÔ`"ð¼v€Ô€ÔÚÚÚR;R;@j@j@jHíHíHí©© µ µ µ¤v¤v¤v€Ô€ÔÚÚÚR;R;@j@j@jHíHíHí©© µ µ µ¤v¤v¤v€Ô€ÔÚÚÚR;R;R;@j@jHíHíHí©© µ µ µ¤v¤v¤v€Ô€ÔÚ—ÿÏÃ#©¹ÖVIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/images/translator-mode.png0000644000175000017500000030342010015422052025076 0ustar frankiefrankie‰PNG  IHDREgx°«sBITÛáOà IDATxœì}w`Uúö{æö´›J:©@½÷PEQD±+讫ëò[ ~®uu×UA±­®AQDº‚B¯¡$¤'¤÷ä&·—9ß“L&Ór“Üî óü“3ï<ÏsÎ{æÎ™3 aŒA‚ $HðrÈ`ì˜Ç®µ $Hà,ÎÿâZ[ðD Œñ¥K…c„kóÔ^K"„èµÔª.è`šŽ¡XZB NÊ1iÅ—û·aÞ`—$Ôë óʹ)¡^gÜ–P¯3Ì즄öÈ01bD"HàaŒéö"I’ n磀1&‚ŠNפ¶¢¨`Þ\Ò BrT¾™r¼½ŠÉÀ+Ç2L’$µ-SŽÞfu¦~iØU õ:Ã×6¡^gXÚeú ¡=0Lm+‹Žvá¶ÿíià®ê.ƒóÁ¼p‰œ3åz0쾄zaÞ`^ô{ÃÒ.#.w KàE§ó3xGL¼C-f¹ÌŠ"d®»‰ËqážÎExµaÞ`—$Ôë óʹ)¡^g˜×˜´Ëp]¹6¡=0,á„ÐéüŒj8¡qµÀŠa¶µ8LÇ0ÿ—c18)Ç2Ì+'R~cØ} õ:Ã}™P¯3ÌÚDÚeÄ »/¡Î–À‹NÇyª¥„ÎÇy×ò%xgé`šw0âB9ƒÈØG\ÎÛ »/¡^g¸/êu†AÚe<£:cX/ïu6Í,ç-ìVpïúXN2,¾¶r’aÉ07X²W_}c,2öa­â*cÙO¡Ñþ¡ÑþÎ3ðÊÑ… •­«oÞ0ÿá1n2ÜqÃ.—s“a÷Éyáþ‘Pɰ» »O®Kéx&Ù«¯¾Ê-¥Úë³g;¸µB㯉Œ÷c”ãôw3vy®IgI‹ ö¢öQ²˜yåÚ@Úê‹jNn¾ôû†‹Ì:¾·(?«Qg•ŸÊßO.WÈ¢“ƒ#‚`ÇO×–êↆ±H˜l]Ëñ•³6¿°r{Sh@pH„¿즦êCÿzâýªiããý|U¼r]zp&X—·?}ó{ϯûù¬bìÜ!Ú0ðº¤}vîܹaÆٳg»¤…ûÀp/å\’PÉp2ì>¹ž1HÖõ3²O”ÕË-È©+irÐ…–ÊâÌó-g2ªËóºdOâÃ*OFÅñ’Ì_ó ë!25bØô¸”qýpí¥’Ê‹e TËÇÌi{ðê•úªâæ.=t+÷¼ÁQIòô» s ÈV]ó7ÿ ò^ʉzÀ—Îf<˜a lÝüß $ÿx®{û†ó ]âêÕ«§OŸv•\ö¹Þ3x‚œdØ… ÒÑËyðü"31l$¡¯×åf6ÇÏ¡Jr·_¶ÅG¥­@Íí’¤ÝhÊ;^^[k²Ú±ÂG–?<ÄWŽ ckvÊʰ˜€ÒœúʜڄDÿÂ<ÁèPøk¢†…GÅø©Ø©Ê;]]˜Ý4øþ)cG‡hv³¹¹BW™[çã/C[,[¯ÜôÐè»òª õM¦}ßdjC5“\Ÿ_[QÐÔØd¥Ê?<`Äô(êtžN¶ÿz,oö˜x?µ"·¬Ao²ŽÙv Á<Áãî¸/y×»Eù…£'(êŠÿœ÷þ“ü•€meùÙy9¹Wkší„::yĬ©#|rpéÒ¥’’’E‹Ñ„û÷ï˜8qbmmí/Û¶Þ4aèÙœ’†VÓä)SGŒIËQÿÚZó.Ô›‡=x×mï.}ûHýªñAJŒ²I[›óΟ¸TPat(¢=,)&Ì!°[sÏ»˜WfpÈÂã‡68!R €´žMÿýJI•Á†Âb‡¦M«@ÿûßÿ-ZNUY§ÓmذáÉ'Ÿ¤ #³.$ÀçraE«Åá=zúôİ€³'Žfdd”••}üñÇ¡G}T¥R±M¼-,¾‰3 ΠåzÏà íãu ½N KàEdzÁó–ä[jNV6N V!‡©åÈÖæ„gÆ6TT!@c«Ùžq5'ãjuµÉl%A„¦Deš #|`ËÚã¿>',& çdÅÞ/NϹ5¹¤P§78€€ðrËĹ ÃRüXŠ-fl'ˆ¨h9@¡Q‡%«Ã’éD¶6™¾ziÿMÎ9UÑPÕªo6“ŽÂˆÄ@êxf.¯½°¿  »±EoÇH¦ ôàÀÑ)jyÛa £g|ñÕâÁ;§ŒJ>—yéBîUùí7HŒ1Ž­Ì~£™z׌¨Íee'²*B®^<ø³vþŸÓBÕãÖ’K÷ìúãØ…&£Ùþ§ÀoõôÔp­Fž‘‘±cÇæñlýúõIII'N,++ûÛßV½ñO\.*oh1ˆˆ9j«›V_Ü_e0iF,Y0hRùè–OË_³h°Æ_ Ö–ú’ó‡¿ùv{i½ÎŠ”1ƒ+µ¾·ÆaÕ7V\>òÍ×›¯Öë,X‘TªV ‘ãì¦Ö–¢“_|µ¡F§·H© 3íF³üÖI‰ZX½zõˆ#ÂÃÛZ¸¡¡á©§ž¢Žgëׯo¨(ž8fdNq¹Îd“ɉ¬få£ 'eee]¾|¹¶¶vçÎpÿý÷ÓdzìÛ=î=C·p·%´÷ }lØ} íËî÷h;ž!„¨ÇX÷†jb’¢êÊòëkÎWž/×^Îr„΋÷¯aÀÐÚbûj]ÞoL¿yˆV#·WÎ=º·æÀ†ª o'3y0Æ&â‚1øÑN $J÷ŸúicE®R3|è V†(¯XwÿT0{NôÀd­Z&S29AÈ€y*÷ðësZ›LáqÚ»ÿ>ÚûDÅŽ“™Ù>ƒn³tv˜£¢êü¦ë?,¶&IáKPµ£ÏÜnüÏ«Ÿ¾_Qs¾ìðoï¶¢µÏÞæ¯@MyäΟßUvôhV’b×öò¿ì˜O­Êýõ' ª±÷|¼r®Ÿáêº'—¼üÙ ß¼xÈøV½PûýKÔ‚•Dj?}íù‘q¡…Œ}±;2÷d™íÁÃîœé«…eÏLïÅÝúéÑØ_ 7œ?ñýGt³úüÿ|[ýôQ°­ãá-e9§¾ý÷öªY߯{oh(yzçZk.Bãµå'ßÿÛÃ=_¾ýððøÈÆ÷Zrqó«˜ó„?¥¥ž}ê¯{ŠþûVÓDûèïŒð¥Ön% cÖÚ÷šÜG£úbퟆidj‚GΦ?³­Üœúç±a ÇÎ]|Wô©†EAQ¡ âRqË®+¶oaXˆcÿ½Em[TeüöHã{é/ R)ºá¾—¨òÊ&ó«› ×”<;6@é+C } „ܼé—ÏЋSh?tût¤!tç-S^üó­QJ€ßìÇ>Ak&;,`ÖŽ¹3IXËt0o ‹00 ŃYºB$,‘HÖOS…»ËpI¼Î0¯/t'¡^g˜ÅÀkØ… í®a BCûÈw~ &´| Ž4£#§dY·•ú¿1- ÔŸ 1ÆÔv6»!·à›ÿd´è 6’»ŒJ†Î.Œ±’€0UûH ÉÉvQÔyô䪈ԸE/F/$tÍe Y{3}s©*Çtç£ñídcL¶oE;/1ÚOÿm×O a€1i¶ÑÕ#Ú_3JÉ`“˜´;€;î‹eîctáèûïÝ÷^Õü¿÷o¤ ¯šì3äÄP9I’!Wjo°Ÿ$` ¦0Ã'½ C0ÊG.Ì+—»þ³ês{Ú²õÓ^£ŒêŒæÿ|–ÿ·ÈД &;Ye±ÏÒªX†[ìd‰É~ƒV¥h«c[•ò²Á6K«T#ÀË5CYˆÍøÓëUrt—–£pEû X ?’´aL ÕŽÙÂÐyt‰ïfja¡ÈË@ïä" t›‹Ë¹Ê0KÎë »OÎë cÏq mè¸~FågL!—Jõ3 'v¾–9`yšÖ_.'€him4mxñxè]S§>æãë+'À~ñpñÙeL‚¶4 Œ›0ºBç_RÉe2¹ŒúS©à4¡äˆÊJ€xÌ8ã&ˆö“µöͨˆ ÏL<.ÊOÞ~ö öU@çòBo?¾ìˆeÌãOÜ¡¬»øÍúæÔå_®¼›¶J«0»‘Oð0¹:.„(žÖqÇf¸’hu¥Ç°Ýf8'SÇRaŒeŒÒGFi«ÒÀla9J‡Y) í­_í¿:fÙÓ+ÒæD)Ú’bÓŸzüÿýØPg<Á_†B•²Lƒmz€’i؇@‘*Ù9½mª¿BŽ:ª&ˆDµ)ÜgJ¬üã¶V4›­¦æK‡6U䟀èõüaþ¼¿¹¨Fg1·^9öKñÅ ñS<4-üƒ~-¬Ö M™öäÕZHÉM×*œ/É®l2› ¹gþð)«îÐ~Ç,×HŽ!«ÑÄL¨È[ïh‘Á,‘ý™%Ç qÃNʱ s©¼Î0s­kêu†¯mtư^tœŸ‰|é@®õÕúOÖ1M¶7±J#Ÿ² ¦üPξ³2¹ HYÝÐÅØ"!1à‰”;¬ÆŠú åu™290¶´èBOŽfE&'øä7îüèDLŒßìeÃ`øâáõ‡ê ÿÈ­´pÚeêÈÑÑIC§ˆ…Îc.Ã|=oÊÍ ‹÷œ¼´÷‡÷/í#즲\ÇÃ. €a©‰“ÆÜ·ñ³ŠCAr¬†ÖzCw“RÈø~kÀ˜b’üåÓë2eäí·&}t9?b@Òã‡Ì¼eá…Ý|¼&W£ ðMó¢Ä œ{ײ3[}ýQžF%'€œ‘––vûŸž:òÃÞo?ºà«„æêJEØÐ»ç΢˜xháÖ ‡?/¾ê§Ò^W¥¦EEv¤Á‘I¾¶ßùW„Fþì³Ïj4ç?~!ÒÂÎ ^믫¾ªàâ弊FKâÔÅZ6-Ô_E ðÒøÈ®^ȼ˜_oÀñãúhTc†9r¤Á`(**ºûî»Y Ny8¶õ˜E‹Ç ‹Qɘkµ¦Ü\2&dÀ˜ ©~Õº‚“§ÏWµ„¥Ì>rTdˆŸÜÇß?:Ù·¥àlæ¥âŠÆÀÄÉÃF ó“«4AƒG9ÊÎggç—×+#†Îšw㢴ÁJ!„¢“ƒkŠ ró¯VÔaßÈä‰ ‘±æ¾ûî€üüüŽ9’övþüù´´´èèh?dAÆú“g.–”.Y²D©Trû δ°·2'd¸ ¬€îÊuiøv.¡·î±\ÿ3ì •ÀEÛ…GæñcLDm©Ž;( ûY—…ÀH[o\"î«PÊD˜úÎÈõ’îq•»+ǽX2ìZÃ\9¯3ì>9¯3ìá=PäŒö:ÿ“ ¡¥ÑïpOr‘@!t'¸÷ Ý“ûçŽåƒÆDvuóˆèdtU°'0H†=JN2,æKàBðŠÎO÷ä\öFN‚ $ô?t<Æ]GŸº1‡B‡W1ðcÎ E’a×vŸœ×î • »Û°ûäºdÎÏ„Ðõ}fØ} õ:üÁ.I¨×¦Wyæ.#Ÿ ¡íí™@AGw¿2?%((((((bàœŸ~?e éǤµréÈÁ±¡!ÁÁÁ±#o~â­½ˆŠâEÂhn à.³bDä€4=°-%"”ªHÈ€A_ý´Ó„y̰Dü¸Õ°\Ï '&&¿ýöÛ"~Xr¼Z}c˜ÕÂ}iØ} õ:ür¼žûß.s {` ƒ´pû»/&NYòò›)> °ê/¼ñÉÞ]‡‹¨µ6“ñ—g¯iÔ;H™2jÁ‚Ù«WÍ¥7ÇŒ·gÒ ô€…¹ÀŠaF ­e1t)×zõpùÉOk,ª’¤­þ»óe{ t=“ëî•c&˜ î’Ž¹V†YrnØ9¯3ìB9o7ìá=P‚:}Pc,W&¥Œýç ó°½ìäûO¤Ÿ©1‘–¦ÚìŸÞÚ™Ûju`€‘‹îœ¾hq|€ŠÙ¾ˆqƒ³œ^f憎aeˆw-‹¡K¹‚K5‡wäH¦Ò¦MÕúúËPáþÓe'²z&׆Ý!Ç î’Ž¹&†Y1žoØ9¯3ìB9o7ì-=P œ÷ƒ ¹6,aîò¿ÝñCƾÂCCÑ¡í¿$G†L ß´æËóå à?ëÖù æMHÑt|[_½|òò•œ¼¢òú¦‹+Õ>áÑq)£&ŒžÐöÁ°†††7ß|0ÆË—/?~<-û·¿ýÊÓí·ßž––f³ùÅ_¤‚o_|KBTèÉÇ/”¬xíšwEªd7g•\>p¥‘+ã=|4¿»7¯´àÈ•‚ÉW ‡ú²«lni,Ï¿t:3«¤¼Zg0’H© L:rÔ¨‘Ccƒ ½cµTåd]¾”SXU×Ðj4Üw@L°1GMˆ¢¿ˆ†K.=s!ëjyMC³ÞF‚Rã7 2fô¤™c†Dø¶½º¾¬¬lÍš5íÊ•+‡Úæ„Qeº}˜¶råÊPâÂécg.6è­>A†M˜6npDˆ?äää|öÙg!£ÑHîÛ·O§ÓQUX»v-os±v¼ [ ¼Á½gè TÆÏ<žÑå ÔñÌjµÒ…*CeRLØÆmû2óÊõVRüxÖ”sºàâ‰b“CåëwÇCsçá’¯Îþ¯¸¾,3'oÿ¹Ú¡3¢±¸¶$çlÆþßþ8|ò|VqY¥NoÀ2µ642iè¨Ûn[4ôÏÆdѹôCö:zêâ•‚ªÚúƒ ¾á±‰ÃÇNzj僳&`‡Ýš¹ëOÛvœ<¹¤¼º¡¹Õê•XdÌØÓ—fÝ0oÁ¬ Ñ! ¦¦fݺu”ƒyóæQÇ3„³ÊãÆ?~<êÜh#¢}”àØ²ã÷Ó— Z-ê #&fU?´rÑÌ1 ¡ê²²2š–©S§N:E- ÏxG—΀wtÙ%op·vW×vŸ\ï<¡}¼.¡×‰a ¼|cÚÊgd\j>p®²¹þÔ±½ç2å&“bÆÌ}øÞY©É¨–Åv‹±úÂGo½¸íl¥Á¡‰ˆŽ1a¸¯™[ó.^Þ—wáôÅ"]öð]óâ49BD—W5™i;‘~´82Ú¦89-ñ}5±™íÒÑ‹—Ž\&ä~~ÁÃ: š¼HĮ‚꼳¹Çw|úU;¥±èäo?~úÙ7û2+d Ÿ¤¡))! lfcsùùˇðçÀTsyÛ7ë¾Ü–žWeð ‰N6<(@H£¾¹ðÄöÊ9£`ÖdÒjl*>õÑ[/þx²ÜNDÇF2B#ÇF]CaÖå­¹ŽÏ3Ëþ¾ìæiÑ Ôq œ ¯÷bŒY8»Ù;ßz˜2rxCyÞ¥¢Šc»×7ÈF„…'ÎL ž7oñà- ADuîÉ7ÿ´òçKÕuW|¿sDpü°§çÆwh B)9 0(дv IDATdH¥ pçáRÛŸYÛ+§" pûD" YÛݎεsP½”j%ìhe6ÍOÊ‘¯ !êÄÑgɘeX¼1©`z’þ“®»H s-ñŠxàma&ƒ[ óÊñ&Tܰ3r^gXÄ/êu†û2¡=3 øÐñ :´¿…ÙW¡B¨ý>Œ}[S…Ðÿ¶ËQ—Z¬y­ŠÁá°k#F©âdª8@J&­F»Ãhwv˜Œ5»Y¶X#Äù° Ë0µP¸õçò’R£¶ëšjOŸ:Ù†S§+ëêmcÒªkªúú›lŠd¨F£’@£É¾=¯8û …q¾ ?Ùõ¦ÓUFÞvô•¡±~m uªÙRj²·U„4k£–åêD¤ˆ„èv°v ‰Àa­7ÖüÆäd¤Õã>^#»¾P¥˜@:¡‡¦ÒÓÓ©eV ³Àbáö.¦¡(n¸K9^ˆvRŽ·zµap[B½ÎðµíΖÀ‹Žó3’ñ:2Pc :ØW#_vcüÍ9pxÿÉäØÔðY£‚5¨¥ºpçßèu­‘W}ñÔïV«£¦`ÜÐ8_™£®¢ðܱ?–,,nÐðÀ°ùÝ=ìÔ9ÕúÌm[~644å ÓÕ…þü0ø„%ÎZ0sÔ¸Áä«X4&"ûHìÚ½Y #È* rîhª¸ýµ_%iŸ±ÁªæfBg#Ï]¼ôÕw‡ûÀ=÷ÜÃÛÂÌ„ROþÀÌ™3YTªµ©“6:Œ`¼5•^7,2:&Y1Üßñ‚%Ç –oŒ¸œ×·%Ôë ÷eì™a ¼`ŸŸ!„H’éˆT&è‘…L}ã³Yzþëß/”Ö4žÞÿý‘Ýß’™L­ñ ŽŽ:ý®‡nI»1E ~þšžX´½b[IUCåé=_þí{߀Иä´_‡ã˜*B§êÌ®Ï4ŒmÖËÛÖÖémk£'%%N¢‘37!”ñcº11àëìFÒÖ¸ö—ËãºxîB¢©ÑòãÁ‹ Í?}ú¯v B¡ÒøiƒÌ¿‰Ú6lâã/kt '²®6\=·þý_Ú€d*¿ÀàÐÙK ó7÷ÿþ²4û“Ýg«ë«3v|µÿg;‰A&—«Ô>1 SgÞóð‚ Sý (D{ï£7o)ÙVÛ +ËØöÉÑ?mlêä‘·üN¥Ó¶Ev<ñö¹gú°R³5»ªùÜ=gö·Í岎gt–Y å¶ðÌ™3yå¨c}äãe`ò3åXk™ B=ÐyÃ"}˜WŽ÷÷Tܰ3r^g˜µ‰ êu†û2¡=0,ÔÚî×ÇŒG”¨W>Ó¬e*Œ1 ‘!$bíæQ¿|¹}×oŽ+,­6XIM@ðà‘æß~ÿ‹g&F‡PJÿ°¤e¼Q£ùô‡§¯”YeÚ” 7,¼ëÁ—»á»ç;ÙâviØdulxÿ|k³¢gŠ™=–ާ §N Ÿ¹8ñëìF8¿vƒeq Ò ›¹xÕà‘iû·}·e÷±³—ªš2ßÈ„aióo¿kéTS„ì†G^2>mߎíÛ;|9¯¸¦I‡•ƒFO]´ìá 3§AÈ”ík7§Nþøû­»Of^)©¨5ÚÁ/0,iؘ»zêžùã£B¨vЄƥ,{÷?5ò7í¹XPMªB†O½ùÞZvCʯtÔ—®·ÄÛgÑÛ¯f¿²Æ¾ûH~E½Ñjçæ‘ÏI(¢#éú*÷Ì™3¹ºAPs’ÔZ&+¡ˆ3f§‚YX=°7†¹$Nʱ 3%x{ WÎë Óñ"†…ä®ÃîKhw sAþ'õèþÄŽžs>¸÷ },'îRŽy<£–gÍšåɆ½KN2,æKàB¢S[àôÙ®«xƒ¹ó’a×î¥uE cÌœ„¤ÿ¤¯·yŽáîÊy]B%Ãî6ì>¹.¤ã™Ä.ØRè}Ûu‹AhJÁMr½gè†]%—––Æœžžî9†¯¹\ï('î9 \tܯ1¦F¸ý1FzìÀ\KÇSmÊ:kf2P ÌÞ`f¡œ8CËya/M(Í@MH2_¸@ÅP7IRk=Á0KÎó[¸Ïä¼Î0öì]†÷§\PçgÌÜ0ãz-++ôª.è`VV0gš˜ÉÃËओV|¹æ vIB¯­aê\---^æ¾¾ä&TÚe¼×0o°›Úüӡºú^ ,}üÂk »/¡×Ö0ëY7j™$Iê^*˜÷†É¾I¨´Ëx¯ákûèŒa ¼è4ÃqpÁ<¹GˆŒtèšAHŽÉÀñæ•c¦KXa,¹ëÁ03¾7 õÃÔ™óP‡ÚOÚhÐǶ¾I¨¸ašDÚe¼Â03Þµ í™a ¼pê¼Uh_I|o‚{Ï ¾¹\®÷ }lØ} õÃ̯ÞÐ…¬‡¸yÐÍI9¡àÞ3ôãØ{OîÝ’ëËî÷s‹0çlšJ£MEZ–—^v&+%çí†=?¡î3Ì}A ô '»eX(¸÷†™%ô²·÷@¯3ìu •@¡í{1Ì"¡S`hoYn¼P0W¯» ž çí†=?¡}l˜÷«7Ðùa€ÞËyT ÷±œ·öð]F‚xÎÏ$H¸~À=¶Q ¿zÓ§n$HÐ Hß‹‘ »W΋ ÓwHÒÁÔ®ÁýêKä¼½öठîìY³ÚÎϨÞL=²ÊêµÌ}›:ùe>iÈŠ¤˜{w¿¢„äPç{x¶`æ•c10§Xf˜rÜ©†þg˜W® õ:ÃNÊ!„ÒÒÒèßzæZúz[Úov™n}îG‚„¾Á¡C‡:æyû."½÷ BÁ¼p‰«PèE|ýÞ°ûêu†¹Áô+HX`^oËÈÈšºì¯»Œ4+Á£pèÐ¡Ž®O}’ŠbŽ1…Þ×I3ˆìT4ƒÈ®Å’ãE—r,Ã";§¸œ·v_B½Î0¯/„ §¥¥1[Ô2uÒF?îFýé!†»%çLB©ÚI3 öù=Š£ © zìÆœµgÆlÍ€îÞaɱœ”cnÂk˜¹VDÎÛ »/¡^gص 1cõçŒ3è`úªI’ô¼ÜÌ™3=Á°K*A‚Ç¢ÓýTǸñ®eut:†w JhÞK).”c1]¹a2°fÃú‡a÷%Ôë ÷ABéÛFè é Ihq‰Gæ]Û¥œ ˆ¶çÏX×y{0=6„Γ't0s+¡Ý€Ë I³˜q…¼»r¼lL9O?0 }›P¯3쾄R·pßô…7O3Ì+é ÁÓ Ý¯/–î×ï:¸÷ ¥?ÉÍ*g= à9†…‚%HðXtý†›*2v?öûå¶5¤¥ðôæ_Ê+‹ÌvÃÎÈa‡µ¶è쑳ö6šEj'Ä`i­?²uKaæ…Ά»nÒnk­+Ûöá{]3¶7W]9{ùЦ:“¸an1쪄 •\‡†‘s¡aæ±þ*7u±yl£ŸãtN&ÁKá®ïÅ`Ònª:µò™µñ/Ä ˜BÇ8ÏÐÎc=òésßî%’gß»!LZíú‹.~.åëa“"cé0^’.å,Myß}ûÃöÂÖ¥ëQµæ b¸¼ùï~›{×c1#g¡nµ±áê‘Ïžùë×57xX@X¤ª=XAÚ©Œ1CŽI⼜2(E0P€;¯uŽÁ> Õ¦ à_ËbèÜ>¤\ãˆÛ6µˆ1ÆŽ0äS´ÿÙeût)ÇŠqIB{ÖÂýÕ°3r}i8--mÆŒôZ Þ9™žžžžžîr9 <÷7ROr‡ÆTf¾2o•ÅŒ¡‹+€:ö1Üþòf0æ<ûâ0·¶ÖT–´ŒQÊ¡`ZBJ­¿/õj9QÃ"þ;NerŠ u®s† •@çw(ð2tnB.“©}oÎT+Õµ±[˜ËÐf»+9–aW%´-ìi†ìÝL¨gæ>èFùe€^&T‚Ï÷{1P[Z¼õÃ÷—¼õA€Í¦PÊ‘¬ãŽÚ'EÞüÆü…Pîüñ ÖZ]AÞÕ+YÙÅFeIº|JIB:g€ä2b”£×ÒrÜÝ’9y ŸaD0~XíÃý5éd€©‚ê8M$¢²ñ¹ŠS—ê‹* »M©ðà705bÒØð!C0åº4,Óû„:ÓÂ,†kk˜WN(¦ å“óÃÜ;J(æ—x͈$´Ç ¨¸-)¡õygc¿˜´ÖÖTŸüþpÙsáwß»aÁìø¤Xæâ¿\Îô~ñ]c;(ƒ§Ì j’‹~ü{Ü×L0i­Ý¿mGNµ14iì¸1#Gù1W;Ý>8³èçù{2*2 tåuFÉa—Ë}‚}"CމI[8覢‡ î"Xú^ ˆö@ï2Ì|'2ܯ•öø`&On…f̘áÌ7ÕèSÕîB|C'ÕûX´Ç•í¸*.o VÞ{É/>[Àžo$±IéG¤Þö°¦åÜ™œ¢1Ó&ÅcJó½U–É|ó'\CB{odtiiQêyKå<*4ãã¼rãuãô2?UW_31Üλåøöï?ùèÇ™_Tr8!rš‚á‹Ñ>ÀÛ<Ô´gKcƦón*:Sn‘ûDMˆŸ<@­1Yj.•Ÿ9S\p±.·Êb ˆàë¤a¡ÃLïêL ³rtm óÊñ‚%Ç#.çɆ…>ÕÆ|i2õE·îþ¤ÒñÌÊ.‹×ö¡×DÝc¿‰êncnåï˜"o@)"’ozçù[ÆÖ;þô@ðÀ6;êj6´wS¡_% t0/h^¹ÆÇ¤«¼˜¾)£Ù "ƒƒ˰ %Œ1£vÝ5ÜFà°™Z«ß}ö•S­snY8,°ÅZvÒHbf ð€Œ ?oÍ®Òó¥F£¯&a\âòÎÿdýß}2ïÕÛc‡*•­­Ù%¿}YXä¼aêÂ> .I¨3-Ìb¸¶†yåxyXr"ZBrÞb˜~€%Œ/ºÑ ⪳|Û¶mááá زe -G÷н{÷¦¦¦*•Ê1cÆüüóÏ,Wtðc=v»ý¯ýkPPP``àÓO?íp8¨µÓ§OÏÉÉA °6dÑ:£NGrýÀºuë’’’”JeRRÒºuëxÝ ‰òÒ:SYæ¶¾¾¾ÌMxMnܸ199Y­Vßxãååå¼*¬q·^Ý•è²â4  TM‹Åòè£úùùÅÇÇïÚµ‹KKƒ`ñ„Z© ƒWLÕ¶äæVT™Bm÷M0ê/:˜7^œÁ¦+9yêćÛsܹþ¬Æ`Êq!.×F%Z;Q†¶u€ ÆæŒ¥­×¾}ߟÿüÿÞ|qÉCK„l1?”Èv‚Ðús™µ =ô¦esž™¥$Ña3_^pjD, hl,ÌÉÞî¼aÞöéqB»”g膑ó:á™3gΚ5‹b ÎáhÎôôtz¹7ÈËË+))Y»ví /¼@•0v>øà_|¡×ëÿñÜyçÌ 1ãNË/¾ø^ýõŠŠŠ‚‚‚’’ƒÁðÞ{ïÙíöY³f-Y²$%%åÃ?\¾|9=`nÈ¥íR޼rå Ëÿ|°mÛ¶={öÆ;wnÙ²eݺu΋òÒ:SY:,''çÀâ&à¾ûî{çwš››ï¸ãŽ'žx‚W…iŒ·^Ý•©8-]\\þÓO? Uóå—_6 ¥¥¥gϞݻw/—–ÍH2`·´«N>wßœp­Oò²6­¦W±"éBŒ±ÝZç°I’´è*/ØüÔ²—0Ƴ‡§Üûõæô&3—ÁakvØZI’´[ Íy¿=vëß«Ëk©U·lº}ÚäUMTpÉΕ+—>ô/ýJ3ܬytÛ:3˯7jÁf´ØÍV¦ajùƒ¾>㎥kÊZÄšóÿø×_n:p@Dò¸»žúOÕ1®=ÿØüÓÖ}ò#I’»±¾ê´F†?ð}fa#·}˜%–ÖÜÜýó•~cóòK¨’ÿûtÉ‚ùT•ãþ*{àUøû4;-loX°áFxÐ«Š ÿ›Õe•Å=¸0Øú·œç>ØÜ ó!]ØÜÜŒ16›Íô]0Ìà˜˜˜>úÈh4:ÃRB-×ÕÕ9c\[[·jÕªéÓ§›Íf3ÝU§"ëêêXþrrrè˜+W®$&&:/*DëLe™Ûг1a³Ù|}}yU˜%Bõê®·²ÌHƒÁ0zôè÷ß_¤šÑÑÑtaee¥PÃfð9Épß`ìØ±{öì)**;vì-·Ü"¥Óéèc­Éd‹ÅòÎ;ï|þùçÏ?ÿ<ï%W©ÓˆÍÏϧÿÌÏωïx+ë<–.]úÜsÏ555Q›;³IwëÕ‰5kÖäää|þùçt o5###éTÖÕÕ‰²g«Áfj´$/]0ÕÏGi76W}õ­.5Í$¶›ªÏÞ³ù»Mu6d¸¨Î`2Z@ $—sîK¶6]:òÕŸTÛˆÀ-ææV+ €\ιqˉ;£.=3ê&—¼ñÖÉ AÁ¡Ã¦M:bh<8ì–†âSo­ý"£°Ng¥_Òá0ëÿóé÷ÃæN[xû‚I©É!#;Ba²aKÁb!|‚BB d®5ˆ b|•PWRRSU­·Xl¤­©©ê?Ÿ~¯Ÿ°xö¢Ûo7(>z ˆØÏÇ’äøµ .”_øåÒîƒÎÉf}îÏg7U4W€Ÿ\ÌÀy"í#ýøºA:ü÷%B»wïöóó7nœ^¯g­ÕjµÅÅÅ™™™ÔÉÁ#<òüC§Óéõú5kÖL˜0V®\yï½÷®X±bÕªUË–-³ÛíÜ {¦.„§žzjÅŠW®\±ÛíÙÙÙ+V¬xê©§œ‚3•í, ÆX¯×ûí·B*ÎÔ«»B8xðà;ï¼³mÛ6Fí½Ž·š÷ßÿóÏ?ßØØØÔÔôÚk¯‰pvzž4a 3çߪ ˆ÷•+rXZËK /(+eÈêÐç}ûëñ•OUæškí•û9v¦0fÁÁ¾  ¸¥¥¥¦¦F_ßÔ¬·Ó„]siQq˜¼)ëÜ™?ì‰_þ\ˆ¯Üè°; úšš›¾®^geûj¿òŒ1FûÐÛ~›µ©¦Ô`'mr5øªêj}C6SCYÉá#W"n²QwÍÛ­–ÆÊ«g[Ïm;]qÓ“ÆEú•É€1¾ðKœ=i‚Îj1]É+0ÔÖ’¤ÃÚÒpáÂET«·X­•eWróü´Z9i»z~ïþÓùqC'ÅùËl¥%¹9ç÷m;]±ðÙ´±!äE9&íÍÍuWròMVîQªÎ´¡·®mh¨,ª¬½pèâú0²v°¿VךµõÒ±ŠÖf•jÀÈqó§Û‡›TìÄ :N Ûƒ¹TN’0åº$¹¶†yåÄy0ã ÝÒò:Ãà\Bj¿-…¹9³PhyãÆ«V­*,,4hÐúõëY´/¼ðÂÈ‘#e2ÙÛo¿ /½ôÒêÕ«“’’ôzý´iÓ6mÚDQÕÔÔ¬X±bÇŽGU(cÖ†BVÅÕ…P}Ç?ßï¯4ŸÞ~ðTyµ"~Îdm¤Î{›"Îý"1> v~ùÙ·Û~æ^?¹ IDATMøð‡wµ$iÙ~ú•o³÷žm¨h±Mv‹0äJ¹&@6céÈþ2|¶’ï¡Wª}¨¡V±Ú‡ í¯„ yèrªcˆ0Ð=[„£®­a'åX†™ŽaÆ[<ú™a'J=MÝ)A‚çàСC¾O1&•Z¥Šùûû×^Ù{æ œ@€0`­V{âãwñàÑ_¹}kå¶m[·mÛŠ"äAa1jðõó¿²csÙñàÑo¼LkUd;z„ú3 LCê­‹ËÁf7Š(A4féì¦$¥v@ &­$–@´ð™oHRhu¿ÿ±eÃî\æp€i˜úS›é_)Q3÷äí8X~>§±¬ÙfQ+ƒãC‡ÏHZ¼0aÚ”ˆDÔ.ÇzJ·Ýp§7ïñ>‡K7k-÷tŠÕ¼k™Š3\[ürÜ0—Èyap.¡$x,Ú¾ƒ;¿;!2õٳ瀺ÏN’v’PR/µ'1ÆH&—„Œh;y9ÇOq …fBH{sù•ãç.\<–]7}éŠH?*x×Ù†ÚØ#'@aÒfi)É4+Òj’|Ü×+„ŽùËGßÿå#'ä¨ò'þþÜN<˜*¤´êlŽL2(yÙ7¹ßN ’ã ¶›ê«õFP.àÓ^ˆ†Æ.»`•0Ueî¯Ë0Ó×€x0s+¡ßµ.å˜lžiX$’æÖˆ»Ëð¼Ë0¯¤C‚Oƒ7ÓO0§,g¾ÿáØ¾còÖ?Vùû»_Ë™«Euš©ç2P ÀØCxƒ;~Öv[Q6ÿ‰sgLš @CCÕÞÚ’›?cÆ­³¡¶$3;»¤Ú€H??&%RKW×y9f f¼Â•Ãb°6œÉ.ܵ³Õ’::%ç$«}¬-¥¹YùWkZ‡¦½yó##|®5Ì›P^ú0ã„^o†Yr^gØI9 <]/ÆTÝ””0`ɘ)V‹ã³OÎùÏ£þ>2Öž#Î@ïÌ}ƒ¦dš€¨i‹¯Üwðç¿-(kj1Xí 8.mÅœ‰³iå~šÑ±v©ýÔ BÖ•óOÖ 3€ÉÀÚo;í̶º?¶ïÛüM†O@äÊ[b˜ü]2µÜg@â°€èÁ)ÕɦŸûÝܶ[4©å¡¡C¿ºí+qÃâé`6Hß‹áÜOѳ„zµaÿ¬x <Ç3fŸfv_uØà­=90Z¦€´{î£õxM0«Ph ‡“ìr™\1xô$B£M¬ª×›,$j_mLòØáCb5r9ÈåZUÛkʸ \9z?ç•ã­5ýÛÁiiÌÎíæáÓnö ÃB žŸP¯3쌜×î–œ ˆ¶ûõ™EÔ:+޹«pã…‚¹zÝe¸ÆrÈÛ óz~B½Î°3r^g¸[r$x ľx+A‚ $x :ž?cÁxg„èHà›‘šráJÒ Ì?™ ÌUBóÎÈ!ÆmZ´!ýØ0¸-¡^g˜WÎM õ:Ãà\B%HðXt¼q¨/ÙíQôZ‘É:Fè+>Lñq9–a^*ƒxŒxݽڰûêu†yå„bz™P¯3 Î%T‚EÇ|#ëE±‚´¿ó”»ª» ÎóÂ%r¬B¡7ö{ÃîK¨×æ æE¿7,]6“à]èÆ“°t!k"‚þ“Ûû¹ÌÜ«ÍB„̵¼NÄ óãN¤pg`úŸaÞ`—$Ôë óʹ)¡^g˜×oBÓÓÓ…%H¸†èt~FõW‘‰hïÓ¬?a ƒéæŸâr,'åX†yåDªÓo »/¡^g¸/êu†Y›ˆ'T‚DÇùÕÅ™“¬!sÔÆœ‹`]÷¦ß$˽Œ¡"-çÌè•w°É4ì¤õ'S3^}˽Þ? Ó«ú ¡^gØ} õ:üÁÒ.à ó]FdJù:ÿ£—¼|÷hõ ¸÷ },'– _[9ɰd˜,‹Žûõ¹ëèC³ùx#…Ê{ÀÀÌ*t¡œdØÝr^g¸$T2ìnÃî“ë’A:ž ¡ëóÖÞ·]·xƒ{ÏÐ-\‡†Ý'×{O“ »¡vŸœ›®t{¶÷¤þ±§I†]Èà ¿Džl¸$Ôë KàE·gÌ3âžeEè\»äºdà – ó¢vŸ\ï<¡}¼.¡×‰a ¼pêx&4¢q¾t+¸÷ BÁ’a:¸÷ ýðóè÷†¥]F<¸÷ ×¼…û=:Þw…1¦.9r3ǺIsÃDèe&ƒP/aÉ'ë]æ•ãj±„P^m¸/êu†Ý—P¯3Ì+ÇÕ’vOØe$ðBº__2|íå¼ÎpËI†%ÃÜ` \´(PO>bÆÓ|À%Ññ1‡]̱ƒ8ƒP0kôÁ+'ÎÐÇr^g¸$T2ìnÃî“ó:ÞPéx&„Žã·pçdf!sÔ@,Äè`n^Yc&/ƒ“rLZñåþm˜7Ø% õ:ürnJ¨×·%Ôë ó»)¡=0,½DÒ÷b¤ïÅô<¡^g˜WN(¦— õ:à í2žÑ1,Ò÷b7ø:4쾄zaÞ`^ô{ÃÒ.#.w Kà…œú;!`µZ™gÓ¼§ØÜ3e&„‚E¦œdèc91,—Ë…&(XŠëÒÁ,6®´È/WHÄÏ51ì¤\—†³Ë8Ó>^g˜+ä¤\ÿ3쾄ö̰^ȹETÚš››¹}‹7ßÜB:ØÉ#ƒÊ]+ÃÁÁÁ2™ŒÉŒ.ÎÜDèwY"ÎÀ/ƒœ8Cÿ0쌜×v¡œ·öº„J  ¾qýÓÌ,„΃Ö*Þ`®^wÇã‡~°X,]î2¡¿ýö[ii)¯ŸkÒÂý£zaèÛ]Æ“ _ÛèŒa ¼èô<5Õp"¬C{ã²þt†¦c˜ŠË±œ”cæ•©N· Û­-­Õ'8Qi±;0v\=y*çØ)»Ï°Ñh\¾|¹^¯ïÒp— }å•W222¸-p­Z¸ô@¯3ÌÚÄÝ»Œ'¾¶ uư^tAˆ;xײÆt o£SÁÌ—lr\(Çbà•c1ðÊ9cX®ôÑ )¢øD‡©é`’´šíFƒMßjmmµêͤÕêpôÒ0hµZg »/¡njáþѽÎ0ôí.ãɆ¯mtư^´=†ïrmæœ/+˜µ Ä@k1D"yg´é™å. óÊñ²1åX<Î`ÐBû”B¡Òòÿ½²óPuVµÙ¤RG¤F̼#õÏ Lè–áv²6­VËzæÝÉ*3 ™-ÌÍcÏÊÝ%×e ;cØ+z ×æ•ãeƒî$Ôë ³x »0¡Ý5,Amó³˜ñîKê,˜]Œ“e:†ÞœÅÀ,§—Y Ì?ÅåX },'Ê`»j¶˜ì$ã¸Ò;-uÕënùý=º°&}úû²ŸM~x€nï[ÜõAu]“ÝÞcÃ---!!!MMMTayÖ‰/_Y9mÔàð°ð!£g<ùæÆÌ¼jf²²~yÿ¡E3†&ÅÅ%¤¤-|øõÿþj"Ûy[ï¶pÿè^gØ…rÞnØÃ{ !t¼ïŠw íMIX1¸óS¬`&ÌŒa1ɱúXN„!{ßwÇ}ã´)Sƒ:„AÛÁ¬ÁhÑï:·­Ñf¼mðœ Ñ#úø…D¯7OÛybï/çvÝ‘v{  766R¾¥ðý»ví΂»ž~5)Ü¿µ*ÿÎ7(ªSú’æF]Ñ®g¿ºœ6ïÁ›S¹<73ÿܶ—Ö'½÷Ð0OH(‹¡ô@¯3쾄zaoéXày£8èöí1ºÅà rm…ÝÔ¤k(?fŒ»uˆÀa)½R,·'““»šÁnßZUˆf†Æ%ú* B6ËAþZXµÕfŸ àßKÃuäLnIcìü»/šêk¨/õ³ånºpñBDâ”c[jëÿðËð¹«æÎŸ8(:T–ê!ázkÆ÷újŸÛqR‘׃kZØ r½gèc¹Þ3x‚œdØ… ½—»~Ðíã³e{–•n寵r¢ ˜´5Ÿ=zª²®É`Jœ2q\Í`¬-(0ùúkC‚›KóŽîÞrÿ­C´à¤Q„4-ƒ!à› bä2‚‚ð#d1¤Í–Àó€Zª|.§Ö¾Kn›ªFù‡ÅßpÇ[Žÿ\_x`lC“aã¶³ %‡öVG¤C_zµªáÒQ€õa ƒPð5ìî“ë=ƒ'´×%ô:1,NÏú͈F„tØ NîÛ¶óxmuv^EÌ7-0&Úæ°Ô‘þòÊ{÷XS†Œœ0YWSqúxÝœ{@FÈ Ô~Í»}: Ý`,)“éìdIš1V „±“H&‹õØ0sÇ(µ8° RÑkÕ¡1ÚHZ+À@ÂQeøÁ}µ2„[ÍœžÂl1w·°“ Î{]ô:Ãà¶„öž¡ßô@éDÍ…ü^ «„.tfDÃË@/;“•>—#-Æ–ÿ®~ßÿÞ²…{v™HÀ›¾¾6sYÜŸ&—§Ÿ¨‹ò‹>^!#42^´^[ øÄma¹õ•ÇZ›’ƒL)*•ÕZÞÐz„@ʰÀÛd„oO c:TŒ vì/ko4»A°¯Œø÷ÛFk•j‚=éOÏ7^IJúGô:Ã.”óvÃ^—P h›Ó žZ*䯋ó¢[ }#‡°Ù¬Ïú±È¶úÎi“Eø¨dH_]xá—µõ&;&2¥ŒR6# ˆh[Ó¾Ú„ý5þ÷M_&´óâŽÓÕ9M¶¦œªÓÛ/ìPÊÕwO¿Ï_Ð3ÃÌ7 „Fø)ev¼§Ê@3Ê·öWú¤ „B”²{"|Þ=TÝlr°˜$]Ê ¡÷ eöèu†](çí†=<¡n=$x5:Þ¯1¦žàc.@ûè€.ᡊ8ƒP0ê<úà•g轜Ãa²™ H‡qöô©€Í&3Iâ-?|E8lf‹|þÄÕih5££›?{ûul—ùjMÁÖf«ÌOn7Ú•~¤Ãa²› dŠð~ÀX& ðôÎ}¾Í?øõÑkì6¥<(.xÞêq>8 T‰º®«n:…ã´…Ãr×ïøî¹7“^{zZJxUVú»ÏkvϹ“1Æ¡Þüü©ÑËñÏ×–ÌŸ–æÛZ{5ûÜ‘ƒ»·¾öùnšÄ­-܃„Š3x~ô:Ãî“ó:ÃØ³{ Ø/úõŽùF*Üã?ÕˆÜçç™ í tÎ Œ;Ÿ˜SÒ%Ì4wWNÈ?+!D2$óÕ/øô¿úú¨hD"0` èÿ³wÝñQ[Y÷>IÓǽaccÀ›Þ{1  d“ìRRI/$Ù”m„-©›Ý|»Ù$K²Iv“l²!z‡Ð‚é½™nãnc\ÇžOÑHïûC¶,KyÆã13fÎþ¥«sŽî}’žÚÜÉIR•˜®š Ø}c{÷‰Ò2ÖÊÊC{õ)÷`D€ÃB«m®X1 B›™rß+±w˜]6šÅ©tª°h}‚–¿Œà‰aQ~¢ûßyç=:fíÆ¿½ü°ÉâЄE¥fÞ³àž;&ôBiÂÇ>÷Í›ªí—ÿæ‡Zœ¬.<&¹Wƨ)/€`òk†• *j]£aÿ>4è wfAÛgBCÓñŒK˲|A'ì/_kgPãgqÁîb„r¢æ+5,+ÇÏåå¤ëÅŸlÖ†¼³šè1C† ×òr\«â} óÃ:£o_wµÞ]VNïÝ~°èRöæœs³ÕùeµÅdbBÏ»+ÿÅ=ÿ­jÝÏZ8dဘÞÆ˜ÅØ…57‘ÒÇô>ùþ¨Äa…åf;­Ò…'÷îŸÙ;)Bƒ¥2&Ýþóãú]«¨©·9•Î×-µW:gé7ÞÈÈÈ-DGeXXPÙÖ%Ͱ4&¸Z`п4è wf lŸádÑr~&›Y)”Ëà#ƒ»`YtˆB³ÎÚʲ-k ˜v/¥VäŒ^–PEÆöL(¾V\˜{áÊy»¥Ál޹`ZwÞa³éº E,ÃzHO}„Ç3=¥÷Ö0°.›ÃtE¥€7Ýß7*¾ïðó"C·ô1 iB*¾“8sæLw°vH†EÁÒ=W;šD×hAgüVР3ì¿‚zb8Yˆ¯7‚›ë³üù/·SVh wº-Ï `K$'Ó¦Ñ|¹ÿò‚³±¾¢èÊñ#‡OT¥Þ÷|_•JÆ•¼aý‡Åä™-vÊ©Q«(MX·ÔÌÝ 뻇E'5 ÅþnÔï”Sá­a„PQQÑ¡{¬õ׆M{¤Tmö_A=4,’»‰†eådá{ :Ãà·‚áÎlí3‚,ÄçgHpyM~"W ¾g!l‹Ê |°I®­Ëʉ<”."5ŒËØ+Krfï=v¾l£¿›? Jtš¢`3Žº‚£¶~#&O˜2<¹åš¤ß ós¯\¹²ä“¯¢’ú>ÿ‡W4u›†ýWP dçvšáÎlAgX´H4è wfAÛaØ]B$!TYY)Ûqp×›ð<Øw†‘³×W;jóÎ_«¨ £ •¯óŠ®¿–Ÿ{rõfjÌ„¡S§õêÃÑÑÑ$Iz º&°r!Ã!ÃÒà¤ðz¼«.uxŒ&iŠ &·~^ø¤)ÿP)·çE­Ÿ4ŠqÁBÙ`áDþUy‘ {4V$Ç9T0,+'ºwhD¯tHe ŒC MŸÖDHÝ»{XZwý͵§€=Ùg¿\wáÝ,ËŠfþFllìÖ­[;S1„B¸Ep«|/†6çl:j)4Å¿üóD è")™o¥sÁg¶,]½qëñkµÆî¦ÞóÈ s†‹"1Óh¯Þ³hUús£¢Ãâ4N†UÀ0ÆXÞ ÆPZ¾fŵ=G«òªvµ&6-vôŒô‡îMJö6?î.bx›áJ'sÁ3{FÊr*´)Ç(3°’qÅ” w2ÜÅ ûO®M†Ðéš;´Œß’±…³ 9¡X2œ 0’gPÈ>ÏàNŽSÉIµ„ ²rBGí¸0ÂÅÖ_¹©âŽçfÆj…fx{Ýþ {vž»n1ÄDBCÞk¿œ4ó£~:BÕÊ0Â.Õ¬‰ §ö ¢»÷ Aq-®Y”àטemVóOoœø²„é6"iÖ]a‘õæ«§Ëw}ÕPHéÿ6%Ì` wfÝ"‡1Æ,c¯/^³lEεÒj³SÑmà¨q?ûÅÌd-…1þóŸÿùäƒ>è«&Ã!È¢e|}ÙÌJ¡PßÜËÂ+R—œÙ[ÓÃN:rºÅª[8E õwäÕúŒœpû˜žõ¹§lß±%¿¡Oÿ(•PŽP©Ã2oKŠ:VÖÇh0ò#Pqmµ6ì -/~»½üÌøA¯OM›=62ÚÔpLÃä½s~Dz‹w6Ù _–TÎ?Ñá¤?øÏj ÀÓMá²[j.ß[OöZ|ß‚ ¶oßÞ»wïñãÇ —ݰaÃm·ÝZÚ»wo„EQÛ·o߯2dHTbJdDXŠö|½rWƒ“ÕG'¦í çv.û2¼×ƒ“"ô”£6÷Höî­{rˆÈÈä©,ËÞQÛÛÐ#a4Xl-Ý©‹ŠO2b–n4Ým­uD?}gzïÞ½I’ìÖ­[¯^½B‰‰‰ž¬²çù äØ5 ƒd“‘îýoÃþ+¨'†CEËñŒoUîRÌMç: mB, žAÁ–HN6¦M9ᘞú„~:ÖÑP[_ÚmÌÈpµPHÈPùŠ:ì¶Qcfκ-:Oc½øãν{J^H×é¨9‚REôTaÈšå²T–U×bu˜š ´˜±ÒöÕW2€§¥ÝÝH’ºÈþ#zNcr½ºÚ1p8ŽgBà À¦¿ˆ(®a\p_¿žI‘:TuíØú ;¿^ºeñ}¸¥ø•%gÖ¬YùùùUUUo½õ/QÑ;yÒ½Ü1,Z¯€“?|vÆ:læôÛgŒ«G5E9;VþΧëïôh„>¢øôÁCGN”G {å±{‡§'ÚkKŽïÝch:ѤÊÕôúó£ôMŽSãÆ¢œÝß­Ú³áûÍ/Íùý›o¾ù¯ý롇š5k–Ð’¨Itt†ÁˈZ|W3Ü™-°}†CEKƒã†#ÅWÖApÿCø¯' |0#üWYNÄ࡜pÆe«.»ztïÎË6›\¬h®Ëi·V\ÅäÐ IDATT;B¬Ãfo(ÍÏ9|ü§E¶ÒÇXÚÕÊ0Ë8*‹LN‹ë®ÞsúÜÞb ‹1æ…êvp8`€JƘ$c(jÆá8€±Ýawùáçê´êÏÞ}!Uïª,¼r>çb¹™ÂÆøúüMÂ<+䇧å~Ü1cä¬#¢õjîßo?ú±ÏðôèTQpõü…+eõLÊÈÉ%»ÿã²ÕÀñ}—L6ݜ盙¬¦Hcl©ó™œ6[6"*lÑÛ/ŽìÛ=L§Òè#ÒGNË>ÔR²S¡ ¢Uî-0è ‹i³*È»á›[PO ‡ ‹VßóTèUñ}ÍõA„=Ù+´þ$B·Ëw9¶™®mýaùßnvŒ»ªžš›¨Ä€½®äìª7ÏL^òàí³É]«¯ž3—³íÞx4rðÀâ#+œÌ}´ØÅb„l·”î_ú.Ü÷ΔnEûöæCßèØH…Xî¬HlTÛ$‡b"Tî »Íò´©(ûï¯}|äìÕ²ªz‡‹e&!!Ašaw7'„s3ôTº¶ååõUì+Ï~†þð̲¬AM"pÀy í¢ÐŒî©aБÄmQš!" FÌZdWG¶Itt†ÁË({šÒ5 ßÜè‰ádA€ Å¢“e! õ4AÒe!•PÎ]€ô·(Æs9ÌX¿ûð?òÉüé‰Ôð“'ôŒ™Æú†²}—¯ÿëÅÕ„ñηž›£ºv|å²)#Yú××SØÜuu.Ó7N—•í-6;-æSŸ.­aX Â@éø»qošRf$Èùz=ìwØËX– —«ÔnÏFH¥×ÏGD˜r~d“Ì8¬¶7ïx¸zÐCï®Ø}µ¸¢¶®zÍêÂMH,$—þ !J Æ`øaßáÂÊêÚf˜L¦ººÚ´´4ÑâRârÈ^QXå.Ӄΰ¬œ¬g‘\×3Ü™m‡aÁ n‰çõ«NüçR&cФ‡îŠ/JH*þd^<¸…ÐÅuï;÷ñ»¿|²c&nðíýÓŽå;ëSfÏŒV©é¶ëxõØÈȪìÕéU£æŽ×¡H5nÊRñóúþqó?ßùÕæ³›ú ðÈ„¤ë•Ç7œÙ¬&uóÆ=`Ô¹Å=Ìp–“aW–[·Þ?%½{7½ŠtY¯ÚjöòaFÕ3¬ÉÅFMÌöÚ¬Ë ÍW9„õ•’ß×M¿êdµ1*elR«ÇU¸˜Áêx£ss‰ùþÔ0‘a§Ô<€bX–ð­I¸ öÁ-0d¸ëöŸ\› ¡Cš;PmFøž;¯dƒ}d0ç—8Q¼!¦{|·Ä†wØËÿ~Öúv†ŽÔ4E" léEGÝÉgž.¢(.Íw$ '(Ö@úY÷Ï¿zý7«5P}­Ò¥"6ì9¨aë/›ò?ùíËßkèòËì âǽGH‡ÙL<¦WMý©&i’ KM~òï#];+ŠÖžyg#A°¬ ýŒ¸óñäÔpJf|A¨¿žÚvªh®!þ‡y¯¬ølKýÏtwMéÛ= ÛÊò/îÞ¼êç_ˆŽ3u`ÞÆìÕÿü"ùéyc2’íµE‡~\•9rjjæð6‹’¡W]ªhȬ·÷ŠÔy¸Ú] z‹á”ó¡“åüÄp+ íã™(0FõJ.¢ïˆ¸SçÎÛð¹9ÓõGЈh~ ³Žªe+Wç¤ß5?kP”š¤ˆrý¹Âë9¿þ®<®4§Îéì5bxÿ¤¸Û[\œ~Gsgé6^G£3Œ S«»l ådÂ)„¥ÖôžñHjlAic­•q‘¤>Zß==fpšF-»j®²Z­úå+~¿ù›‚=ZƒštÑpC5à,Çpç‚yõ?Û±ôã£k´BÃX†8Ç/ÎKpë!Rtï‡o¬,¼và«%G„Ij´úðˆ^,R@Òà‰“ëhËÎ+ÿóþ‚ (•Á‘8DîÁó?~ï¸c‡¶½{ò ‘"222.\èù*{•ŸŽbèd9ßA.d¸|—»uàõñL˜ÙöUÅ«Útˆ\dÿ¬I“‰+…5,aá‰?9>ECQ€­¡¦$ïÜÁN˜ú>ñ«'ï­&‘¥8C¿fuîÆË®ªmÃŒGzlÞˆ”8ƒ\vEB.k}µ©¾’ŒŠNd úëó+EÁ ÓXeέ2çAc<=uzrX²»ü(¬2©VÏ|jaåw[ +êiBߣÿÀ!“g—_>Ä1ô™v÷LuÔ±ã9¥Õ ¡ é6æö»µFUjj* 4hÞ¼y|†çÌ™“‘‘!”ÓwõÐòè‰3§/]«25"•.®{ÚØ¬;t#¨#{ Ÿ@…Âö;_tÃDéâú™˜ =zôX°`ÈjŸ>}x¹»y5ŸDa6…ÁÍÎ]™AéC‡È±,k5U]=ôàÁ³Wo$M¸ÿÕG&Œ]ù9Çwl\w,¯:,uÄK¿~<%\¯FbYfGmyAéõêz&6¡›-²îoÇÞE¼:êÕ¡ñC=1Ì}ŸÚ—UØ‚áöÉávËu=ÃUPÙÇ/CÙãƘ áñ šïFÊ&]:‘ö°l þ“c絓{N]¸VÅÆ1.kHЇr7˰ðxæ­!ys3À t†¥rAgØrAg8À[`èxæò§Û¨õù™pzûzËÐÉrbXùü, ]†V.d8dX‚M}Œ1w3ƒûà'Bsº…1üâ"átþ·ˆAø¯²œˆ¡“å‚Ýpà4è {"t†;P.Ø x ÁZ®7ŠŽù¢ó3~.7QØkà{Ò^ƒ4ûü‚BBQßDÈ#Ë࡜VùwPæÎÏÚaX6¸C ê§ ûϰ¬œŸ t†Áo :òÁ~*h; ‡®7ºC«ñ7…=„ý…³]Q÷D<ƒrŒ²œÈ°ÂxkÊrÒþT×3ì¿‚aY9w1>4è Ch“ Œè‰ádÑjÃ!È¢ÕûÔ\â^Y‡æäŠþõ„æc„ÿ*ˉ<”–•SX.cØ :ÃYР3,Z$´É(ö_A=1‚,Z]oä2åîýyÙ¹²] Ù7 ù`ž‹‘íÑ´C³41+7×å¤qSÓÁ¬ƒÅ² îä<3ŒXÆélym…e0Kcïò#ò +×Ãþ+hÐök vÃà·‚á›Û=1‚,ܾ\ß‹Á,Ý·v½~Ê”¸ØT ÙšÝýÕªôQCRe°ÎÚJÓåσÞèÞ±†{mmñO?„Í|*A¯%mÉ;nv䓽Ž×wT~Bß‹¹eåB†C†¥Á!H4ß‹aœõç÷üãÕgfÞ6eƬ;gÍš5ãŽéÓ§MÿÄËŸl8i·TÿåÑ·ó˪ +’«Ïýî?ÛO-®ì*=~åÿ¯ØîjSÎ;Ã,]–—ûçþ^C3€eÇV®Ûµ|]•“ñ_~pLL]]]Û mtÆ ó?Ø;¹ õyôúÿ³ëSÛ´Õ׬qNÚÐᆽÍÏMßdn¢\°Ì} ?7w߈rwò+ú—O1¯ÌÀ ¹¥7‡E7K‡åÀö­+~X×ÐmÐS¯=“™ ŽcJ£‰' W*ãªÁ€r4Ñ©N|™Åˆ4hU½âÈ3­›„TÎkÃ¥%´ÉœŒ¡Š'ã\¨ÑËü¸K¸(žcÀ×Öb–ÅüI¶;Ãm´¡Ót+9Ìâ3?Ñ0'Ï3¥UàˆŽCÃǫÌL"Œêöeøø v× öñ÷ôc‘ÑØv~µ;ˆríy¢ù`¯jÓÔ†Hu¯ÌŒÑcŸ;–wÃÅÄËÙÆ^ìÄPçÂÝÔ$´2ì‘\; c^ã„0vÚmÿ—óߣ¦Fƒ62F£µ[K.Þ8zº¦ˆþt­FÓ,+§œaJK [t•=—ËÔ[‘Ú©äà ".²e…kò˜c9®ëÕ˜ÆK¤¦‘#*$–³6°ûV:·ž`ÓG’#‡“ƒ2ÉnÑ@a¨¯e/œfwm§÷mv’”êŽÉT¼a;­ìÑ®ÂrÖê%÷¦†"bÔË–9'M¢RS[ÝÍþâ ûôéªâbvÛ^Wn Þ¶ÌzòIõ¦MÎÄpÄ2p­Œ5F¢yó4`*bÎ^d‹®³vhÃPr™5š"›ëìhÀåìéKLM=z”6€ìßq«ìrಋ̉ól•‰e0£ˆ´~ä€þ$¶²Ë–9ív¼f }â}úwÜ¡%¶Ñ„‹¯0g®0¦ædöO'cB¨¾ž]¶Ìy×8òL.SiÂC†’£FS´ Wæ1‡Î²uLjQB‚¡ÁÙÀΛ§öª "ø²Ét”\› íÞdB†}1‚,<:ž)ôh&£&¾–Þ_£Ö(È)x°Ùð‹/6Þ¿J£A´™½tœÙ°Áyé:¶9J 1I¬i®jÒh2Þ˜§™Ý¸Úyì2SQ‹]ôDjÆ¥ÕLÊঀrÙØŠ+®–Ð^×=7ƒ°×Ⲧà¨õ(¦áTã—_RþýÄA“LÍì‡].عËu,›Î-aë  ©S§ÒÎà϶ÿóŸ:Ññì÷¿·uïN±çϳ••ÌæÍ4Z°@õÁŽ^±¨["*ªÄÝSˆyó4Ž:v×VúðY¦¸Ûi¤ÖAB2CFãÓAE‚ËÊæžeÜêpÀ•“ƒ +‹Ïh3›w†Y·ŠÎ)gíMÉœ:[5u2Õ͈kjð‹/66þNs¥Œ­ªÇZ=>ßÈgÖ|ë<œ‡-L¨ "Ž,*`íÍdzö5*ß÷\"2¬ȆoMÈ<–*M™ðÔµ¾ª+ ñ,Öqöè¹+öð Øe¯¯©¼^^~£ºÎJ˼¨a¯»qeÓ§ûk®oÛyÍd²ú´žiNOßô_TÛ—ä™{Á(?hÿ¦ÿîæä®§R;hbp5V›ìNZüMXw D lë`ny«ÃöÃÉ-.À3ûM–©ŽL‹:­ß,šql=ùƒÕaðJN\™Coßâü°Úr9¶ÍþÉXøŽþ»ÕÆÿþS71;si¾oÓžMÆç&qså‚ÝpÇïýœŸ8´Ü½äA’€Ÿ(WæÀº*5}¢#fÌâKýûíçþìîç^ÿçyf)eHŒôË{ÈÝ : 7ј”Ñ÷îWzÕoùËáÊr+#–Œš¼±–ŽrÑÜBË€Ì Øe-Ùù»^ȯÍõh•BÐt¥‘ׄ¯·7Àx­¦;E!„(*I«€n´¯ÇØ*¥ò<Ãܱ!tx®¡‰ûÞÖe ÔJHýñïÍ öZ6‹ª)C_ÿ–þýrýÌ,ª[$2FcïÒüüI]þZ‡(?׋açFüðßÕ¡=oØö^€¬õ{ö‡/O—xÉÁƒÆ×jd-gBaFâÔ.ÜÉdb$¡Ñ4ÃnS×]¤ëÒʰHNðÐϨ#¸à¯K?ðªöÞ{U=ã C‘6Býì;úÜïíŒ#„²¿gjÌhþ;ºÃI½ŤRÿÑ9BÅÑ&§Sï,Õß1‚ŠCúpbì=ÚA£)síI†ïÀù׉‡þ¡Ÿ6˜ä“™ˆñ¥m oûõ´£‡aZ„Ê?‡nƒG¿Ðß>ŒÐ£ø^Ô#/«ç>ªâ…Wu¯A.Ø wø>PYN™AìçƒB£3¾CjRÇež?*îºÙ,]ý«Wþo…>s`õå󟽶C\¼ïë«ßÛ^ÏdÞ6Xßí‰Yƒ£ôÍE‘*.>ñ³÷g¬}þ××ó ]­;+‚ûg$AQ”Ú›UÃ,m«ÛôßÏö/{vÇÅ“…6W +¦«i–h9*4ç‹ÜúzÁ™eë»wr ^¸ñ'-˜UÃ}=[zxo5˜nd Ú _”ãgz˜btuUG’u*­iÜD 7WˆëNüS=^˜Œàƒc8kõì/¨øH”<€|æ}=C¨À w¯»^˜géÓݤSבTÝÌYÆ.¦õÃŒ(Cßòïåø¥‰ ½Âê(ªŽ¢ê(•)®»™¶2\*³ë°S¦ÉoÛQúYlË,‚Bˆ@¬g¾NZp¦µJ&¡ANKËòwÇ ¨æVY`‡ð|zK¼.žÒÅ{}g:„Bð-ß‹öq3ø)¨ù)8þ!ÑÉ/–Ç|¹pQí0‹ñw{ÂUX…šò€"I^ –€1ÆÀ /à6ÝÄØ^ãÂ,¦ô$ÆØÙÿzª±n0õ§ûÕ= GÐ}ìàýˆŽãÍSøüca$)è^aŒYŒß_ªØ“м€°0ÑsŒm·@^B¸`kW-?¤9çyxÛ$Waá&#Ãl+Ývl2"´j«âY² ʵÙ…Z]Ø0È5_ö rí0:Es‡æ]BÐf [Ή’»S`*MtÚSÏ»vðǼËWlŒð¥EnE„žùÕiY;YÃc dLÊ€Ç~yÑpúpΩK&'`—ÍRslûZ›“mf@ˆÒ…Ež1¡8çx¾N&kFX·†›nØaè©AÇjZŠå¨f#BFá)Ñ貊ì7„=š=š3†=š>œßœš ‡S¨í©Ã0³ºtŽÝ}Ìe¶A]¹ëÀJX«™Mÿ£i ÊœL€ÃÅ.Ýïšw5cšjü8jØ@èÔbUO‚™…†æû‘,Ã:Í fÝmÞ° N‰F²{f“çÑ£ÉQ£ˆ1c(’Ä¡L¢X8Rå6? #þqW†±› ÷Ô †ý•- ÞQÍ`ZBÀвÉĪ §ï(o9{s6°ÎzÆ«MFÙ°r“àc”åDÛ¸rëò¤*ï.‚Ú°ïû@_ ê‰ádÑrU„eYOûÜ;€-Á»¬”ÑÐz"ã´U®_³&aê/`Ûº‹?Õ×®Ö»¨þ1 4ÝæÌ¿¿žŠ4ꊫ1ëàÉ¡ÔRDU鵋Z}>ßT´eÙÿ.DEkZ½¥h-7ž¹¸žjÌ;•¦! Œ1m·Ÿ©gÆQ„Ú…1ƒ1ƒÍrÂc¦ €RØf0Ë8 Î;Ÿ£ºâjåε–š‚^d³˜N5ÄLת5jZ;DQ”>ÉÈ8MGÿû_¶öì±kêâ¼¢òZÒ|µÁ5EC‘­[Ó¨ŒÃÒ}¼ÆzÁ’³åbíi½¡Ñv½¤Au{ú#¦ WiÚΰ¼aþ_FB%Ùõ«éÞs©žñÈ\ ;WÐ.$ô£ &=ò0õæ§Ž!ÏRcQä´âÊr6ï¢ë޹ZNŽ;:v‹†ÉƒÐŠ•Ìܨ{Q}wȵm›³Ó¥UáÆzDªÐÊ.Â…†!'Œ$™A §…¹|ØupkËà ããáôy6:OÈŠÅ5åÌÞµ4í”ó \»G¦>Úèì©RiÆ’ ‘Ó¸ú:“s‚žös ¡†qc î¬ûNK¥%!ºçwöÈ RÄŸ<•"EC\«ÞV6Nß"÷öÛö^PGG£‘ƒP• ¯þÎÙç*=¸dš1ô,¾„ÈÕ¨g 5-ÿ’õ<‘.3{r'}j?Ã÷ ÚÎ΃`Ytˆœh¢»±+»¼aÿÔÃ!ÈB<>¸9™å%\ÏBðn<Ë8LEH‰Õ©©fB¥RÇe¨H¢×Ð0¦ÜTz½žK24+QT·ßs4”ì(8{¹é$0k»zîJÞÕ]·øÂ’ ã¨éCÁT[RW#P!ÂÒ.™)ïAPb¸}¡f×ÛŽœlÚRÊÄ„!`‘µ—2Yw±*51hªºÄNoÚO¯#Øä‚±ã²Bæg±d·M {É»FÇ»j*ˆ8=¤ö Æ#àÍ7m< ŠŽF™ã©ë×ù®5*He¸d&ާÆNrÝÒÈq3Õ»?w­^åLŒÆŠ/d/—ŽDu·Áö% a“pÑ*Ó¦œ—-P|¹¬Ëöjè•a©\û ‡ ñùBˆeYiCä'r•ô,XÊÈœØuÖ‘Ñ=Ò¨Ó¨),ër4h&„«÷X’¦>1gT嶺jü%iŽÁiw8ˆ44]¢rXL7Ê.ì8X”çìÿЫ¿]86×^ç½I cŒGEEîå¼’›!}6ß(¯9¹u¯*îQU˜Þnµ4XN=Ä(8‚b̺l5¥WölZ}Þž8ó‰_M•‘æ²T×6˜JÉ„Tk±F£BX–eh{CMÉ•óÇþ·Óq÷»ï¾J÷k‰ IDAT4>ÖenÐétáFÞã´Y´Ù¡2Rj=Ùx¶2 ª_âí™ !0‹[~¶ª0ôŠèÖúª£(â­Ÿ ÍïÔ c*uûlDsÕ6ǺjÂgkçO'ú% OWýó-üÕôÎ5t•Œ±DŸ䌻µa¿~DTm,‘š¥¾}©íã¥ôósˆ´ÑäÈi*­˺ht÷m­'%ÜðT Ö¢gþ¬)}Ǿá[—K3Gªß«Öurs'<¯¹ñ­s÷^zén  œØ‹šù¸îR% >õéCàæá8üÚž®zý7xõFWö6úz-F:H þÙ<-×ÿÑ&Óf©"5ôòMÎM¥HOÜ1W­ŠAãèh”™)nèB¹'ª–|ϬýÉÑè@3fªÆŽ%B#GR €1•š0“Ä.û÷Ûn—Ì{¦’CS¨ÕxäHJØ5ÑDæê÷ðÑwÎÍÕXú¢zŽU•^qµYPåŽ2ðÿ*o¡"å¼j rÁnØ«} m‡awy¡ån*w­–¯h|}Q£ž)#„r—/üWNLL\·î±ZÅÒ7®YúݶQo,ÿõÌ!ýcµBÌ:öý˾X½ñLÍÀVþe$C;.Ú¼ü«¥ùD߉³ç¾0wŒðF”È ïZwÐ0Æ€á§eË?É$§D‡©­7òV­úqÔ›Ÿ=:²WtÃõ‚ò:„Ïš5jƒ?@òkÇM¯=³órα+ýîCŸ¼2ô½e1‘j†¾‘Ÿ³wóêMÛã_\þÖ\Ì4~þÉš~úfMÃ3Ø+ /ä”W;»¥ô´ÆU>³ãÉæËNÀÝ:âFåj’ÃðùŸg%g¹[;¾§Íãës†Ê˘žiæk¹áQQÍü¸w ‘;ñâÓ(Ø.w,äƒBf61OÜi-K¡fÌ gN¢úô U*Š˜Ÿ¶ÒkÀŸþ¨3ŠËXÓK B9þ^cÜì—ky<ÇwÃB9ŽY('dp'',=ߨ[nò¬h¸EÎiv}ý­kýNضNѪûÕÄÞúÉqn iƒµÕÖ ÷~“Q”¶@åM¦+ægy¾„ö´†•O|oeÈ÷‚¼þ^ »þ£76ì:pâJq½Vé"{¤M˜ù௟eDG]áî5_.ÝpõœüÛ·5,‚8²ö“mgMI'ß>~XFJt[rò'éÜDÆq=çøÁ-[ö]-­e¶÷ÐÛžzpVJ·hä1pÇ»ŠK¬½R®Üã;ö9[ÁÆsÛ=ÒÛdðܰ‡ ÂïÅœ8ÁŒÝ싇»™~ †@”‹ˆ@&S”ÿšD'·Àဒ AЦó3…ã™°K"M.fmUûþïP¿ùÑ›OPéaá½F„«AP”J« דDK§3tcUÞæµ«¶íÏqjcGM™~ûí“3»ÇhId·Ô[ ©Öé4jµŠɉ<€báM—×Ì)*$ÆÎØR©õáa:ŠlõQ4e¡œË…) `Ún³Ù. 5ZQ×2.Ÿl~¼2¬œaž?žmÙB¿ô+›•…Çß2<<i(щ6vÁ^K¦ß†@“Ll%×XÇžÝîüÇ×®k×Ò@ôIΣ¾k ¥&!-lÇÎËÃ&ÑÉ-P4}ß¾}Bƒ)S¦´ýÖ§r_³@×Ú§ˆi\Q>ixrßÞ=µ¿ ný:"Hmdòøs{˜4†øÄÄøØh Ö©1H÷2y‚uÔÙAkiŒfê„„Ù³MåT*îîRiõ*­^9¸†½ €áÃÉO?Ö©t¨×@25 D_ÆÎfÐ3NÔ=A“–¥±ØXD¡ð(”œL$Å·¿í{ûñk ÉB@ìÝ»×ëQ D[8"ÕÚø!#bŒ¦qÓT=Rjŧ¥AéÂ{¤HIóôãí ‘š°nƒ†²7:ÂÚÁàùÐ+¯Ð&Cb"‘˜Øôx¼n·\Ç2E†½ &Õ(¦9!U>2 wÔ)S|Q !„ŽE{Žg­fAiãz€>k‚ò‚‹í–ksYDé ‘ú¾‘òrm2ÈûÕ°²\Ȱ¿ ûOÎw†@È”;9 ÌB@xôœŒ» ØgTæƒ}gè†=G—7ìcACᦣåí?Œ1¼¶,„èv1, S`à Ümö"9lWm–•“j‰ø]Épg4è û¯ AgXVNªB šºðÙÏ·rhý„tWåŽ×^¤ʉ˜Àòr²lB9OàFÍðְȬá,¨ìê²aÿ4è ËÊ›r„B ¡e|}®¹ó?bbb@ÐÍî†ø F´o‚÷…Áþfèd¹›e˜ÿWX,©~¢¨ "Z/¤ÀÀwØ•å„ÝÉuIÃ"¹ 3ì¡\!,Äã7ò½6á[ý è¬áæëÂí$½?a0÷[¸1 û†X²C½Ÿ/eMw,Œä‹D$nXÉOäg ÷>¢‚ E¡uAA0æ©´èîEñcXVNdXZn)ƒ'rAgXÁ¿´éú ¢¦B £c‹Õ!l-ïŠ`°D„PCCƒ´•!ULä59&ê-ŠLó B9!Ï ¿‘—ã ,'2ÌO#”õX¥#^ŽaƒÁ ävŸEIæû"âžAaø‘œ»¹"à 7×°¬œ»¡œlKV– :ÃàYA}„!çÊ]À¤I“öïßï ûö‰Ê z¨îId»z©Šç«à!DÅò‘¿CºM-w}Eƒ‡JÇ»nîÆ.ã”7*©¸9<ðÒÊ ‡òr"’À1Ìâ»aóÓfA;-ÃeØC¹NkAg|~^_¸Ÿ•ýíãîÞOdzÄÍ:ž¾Šl{÷î_R¥C­Okpëë¢0¾QJgñZÊrB.XJ(b•v—‘Ü­`¸£ t†=”óSAƒÎ°TÈw¸Ûa §¯[·.!!!>>~õêÕ¼=ÞÏöíÛû÷ï¯V«‡ ¶fÍÙµ@=õÔSàr¹^~ù娨¨ÈÈÈ—^z‰anîĉ/_¾Œ-(¢õD]Éý­‹'…Ë á"ÒÌÀòåËÓÓÓµZí´iÓJKKeUDÍï£>JKKS«Õiii}ô‘‚awm®8øøxw«ép8ž|òI£ÑسgÏ-[¶Hi½…ü ¤S¤»!…©,ÿÛ“í$ ä‚Ýpà4è {"t†½’ó+®^½ZXXøá‡.^¼˜›"´÷è£~ùå—‹åµ×^›;w®pAÜ|cüå—_ÀÛo¿]VV–——WXXhµZßÿ}—Ë5eÊ”9sædff~üñÇ=ô_,á‚RÚ6ÕE‘ÜïK—. ×Ň|ØåË—wïÞ­ÀÆáá‡~ï½÷L&Ó/~ñ‹… ʪ-Y²dݺuÛ¶mkllܼyóêÕ«¹CšW +ÎK$$$¬\¹ÒÝj¾þúëV«µ¸¸øäɓ۷o—Òz ù'—×ãëËl!î‚}gèd¹1,_?( ]†V.  gggCâNËd2EDD8½^Ïuä…Á)))‹/~â‰'t:]›œ=zôØ¿jj*TWWO:õìÙ³UUU£Fš3gαcÇvíÚ¥ÑhÜ™‘Ò*«‹xBUUU±±±ÂuñÄ¡pY!³”M—Ëi±XdW‡ŸÒ»wïmÛ¶eddpÓ/_¾<{öìk×®y+!]Y¡bccã„ {ì±—_~ÙÝj&''TyíÇ:[‡v9*ΔnÊ5µ›Á+ønØr¾3‚\È0ßw:>bøðáÛ¶mËÏÏ>|øìÙ³•ƒ“’’êëëyó6› Ç{ï½÷ù矿úꫲwƒ:JÝÈ:ôóçÏ_´hQ]]çÕIIIÉÍÍåÿÍÍÍMIIéX‰>øàòåËŸþ9?Ev5ùüWUUy¬Œ¶ÏÏ|¿˜îƒl°tbáö»x²ÈÁ8ÍEù6-ý©Ø]ðÕ•9RTPI³€éòÜÜ–,-v0˜>¾jÍá=Êâ~“φق»ìúñª™n/ƒwð=Ãþ“ó!äB†¡­[·Æ#Fð¾xDDDœ9s†;Ïxâ‰'^{íµúúz‹ÅòÁŒ5 žyæ™|ðé§Ÿþõ¯}ÿý÷»\.é‚íS÷ž8ô ‡cl±X¾ùæw*B¼øâ‹O?ýô¥K—\.×Å‹Ÿ~úé_|±îðÓO?½÷Þ{ëÖ­ã.Ér­Kv5,XðꫯÖÖÖÖÕÕ½õÖ[Þ®¸­ÆoŖ͸»Ð,dP8Œ 6E¡œ4¦¬”f­ŒŽ@¹œŒ¥°ÆîÎOaSíÂeµ[¯Ò,nZ÷º Ú\Gc±yŸ à¨qÚª™V÷ØÛÌO›–•k‡a庞aå=lK˜;üofó×÷%Ù~vè—_VT40.a°ˆAáüÆ+Ãþ+hÐö½ žËað¬ !„°ÄïŨÂÓúO{mäN_­U‘#¢Y‚Ò’'ž|÷:ŠÐ’ˆ{ABJBi£ŒÝÇ…!ôúÞÊó÷DK¹ëùzbXšŸ¦„,ë×Ùÿ£Ï9R÷! “<á¢påÖ/¾Éþúá{^ˆ‹V–㋚á­ap³KòSA¥ ¸a *’ ¨M¦£ ËÊ›r„B ¡åy}îm,yx—ŸÍý5a ¿¸ˆA8ÿ-bþ+ ¦íæÚ+Ù«Þ}ê±/ÏæVÚD ,ÃF¨ºìø¶£ÇV^¨ƒÖ$­‚ y?-?xvO0À ’±ï cÀ,¦­µç6¾¾§ÜF³Í1[1»²±&ª5Ý H2I£ž„nl\‰Ysûòã•á@(h3ì‰\ÐöDŽ{™:„­º`Øýõ"~®( ®Z„Óùß"á¿Â`º¡ôÒ¿ùÃ{Žœ©kt2¸%Æå°Þ8½ñãÕ•tù‰£WΞ©t0"î·Ó\UzjóÇ'ªm4[°wW^^~­“Á¢‹,²fD†]ö²­ß}öÖ¢W>÷Ηßj™®ÙvòÜù vSíÅ«¯Yi¦5‹±c M* `ÀØÙ¾ü´iXsÓ Úõ {"t†•å¸#ÙäÉ“!„^âû•‡6,EŹ[öçÔf ¦$w©„±”›ê.VÚh«ùÊêGnØÌ4Ë4Ô8ê,Þc]¦kµ¦|“Ãz£üòúÕ‡o42®ÚöF ÷˜>v§êÞÛžÿ}~0¯– ¯7› /^©Ì0ΪCE»‹)=˜}æÔùÜz'vÑôÒF†…Ö „F¨ÕG»êXXÖäråjõ2cx•aw—Œ|dð · aÿÉùÎà¹ÐiYA¯g¢îžç ÊöOå%Xl0DO¹wþƒŠ$Êrr.ž>Ê?Âxæ<`Àaìú?^p”Œt­š¤]´ñâ˜ÅöïŰŠ]ÿáÛ¸‰7.fÿ¸ RÓ~kT7¹b01!0,^;ìr9KŸö™ZMb çþé­€ˆÿ¾Ëb(Ó‡a–Ôê(!̲´“Á VSA"£ç/ßåí9R¸lLJF›;ã…¾ü":Rù&‡”Ë!½;rs Úõ {"t†¹ü}²É“'ïÛ·/¨o˜IWSyzG ùéKÍíîâ0 “––6tèÐõë×w ðÃ7¯}DÓóúÂI¨¢‰ÐœPÙY²ÁR=σñ¶•;§xÔ·xô蓞÷ˆy9G=­£Øp5É=š,ã Ò ‹¾û«OŸ<0™ÓÅE!7ý>Œ±­¾º,¯†u™Ý \&{$ß÷j÷ùîlx˜aQ”Ë!š(­f› 2ì¹\ÐöD.è K¸Ó2åȤ¨]<¬Y³&!!áðáÃyyyéééÈhk Ïëûûác[ŵ£Ù»r“oï?túŒH­;9Æn­<´^–‰(=AE’BÇ"~º¡4ïò⸠©£ sœÈü:3㫌Œ¯22¿ÊÌøoFæ×™ünzvIv‡çGø :ÞÈ‘áììlîr=·SÈÊÊR–ëdÈ~™ëôH?¦ÜŽOË~¬cüî»ï¦¤¤h4šÑ£G¯]»VÁŒ¢~§¾|©Yة忠-ë\Š?üðÕW_}æ™g–,Y"ò)ü¶òÚmÞ¼955Õh4>õÔSü(Žü‚îÒÕÉh¹ÞÈŸ£ˆúb\ –ŽàÀ7t>^™J»“¸õ—é…Û§·rîü#„ÔÑIý‡F§ÄZNG"9ÌÚ«+ Þýàøˆ_ 3xh˜ÔÇQWi¨Áúˆâ‡,¿s9j>¡”vr1Æé‘éž´™Q†ýWР3Ü™-0ˆ sØ·o_VVw0Å‚v2~øáµk×Κ5뫯¾Z¸páæÍ›yWÜÇ”×®]»xñbîkÑü'1Æo¾ùf›äK–,Y¿~ý¶mÛz÷î››ûì³ÏÀK/½ôÞ{ï:uêôéÓz½~Ù²esæÌáÒ"kFiu °°pìØ±Ü ¼ü—šI’üÍo~óþûï/Z´¨MÛ– ì\´àáÇ+++ï½÷ÞñãÇ0àÏþsdd$OÈ}{ܸq ©æ°k×®3gÎ`ŒŸþù7ß|ó¯ý«pMÝ¥«“„}.nT7Î¥ôûÔc‚ „ÃÄ5Qö×<,]%$;N('"äø!ÿ[YNd˜N(Ç/Èss­µ×¯œ>´gÏþ«ÉO¾üäàäH½Šðİéê¡C»¶_±è3rÊìIñh˜Øa¯2ÜQõ%Ã7ۇr~je˜{ÜZ¿RæIAoâxÄÒ#K?¦ìá'ùcƒ»5÷ìÙ3;;›ãñÐŒ¨|dG}©YD«ð™i!æÍ›7iÒ$î8÷øã÷ë×oÑ¢E¢z²vׯ_ïÖ­Mœ8‘û(o©ÍtuöîÝÛr<vêîxÆýî•ø¶Ž›û‰Ê§AØÙ”Ý8yie…½‰‚aY9—ÃÎØëJ‹òÏæ\­¨£ÓÇÝyÛÐ$IxhØZ’“{ÝTeNLJÐ7¼ sÇ3©a‰'¶/Ã7Ѱ‡rÖoŠaî)Œ1wóCz˜þ«,'bðPNdXVNº:”V¯IíÕoøØá“"ÔoX:WÄà¿‚áÎle˜{ Ÿñ¥ ¯>Žìí'Ý}¬ùé§Ÿ~õÕWkjj¬Vë’%KÆŽÛ3û¥fÑ'§ÛüÌ´Ùl^ºtiII `Ó¦M~ø¡;à k÷öÛo›L¦ÚÚÚÅ‹/X°@4W6]&L˜4iR›Yê@4ÝAwŒû!Ñ|'™ûÁǃ… y¶‡2ÈÊ DT|°ˆAV®Mòr·‚aÔA :ÃYÐÀ1Ì̲³³¹s²¬¬,_ êÛÇkxûqdO>y,Œw÷±æßÿþ÷}ûö0`@TTÔš5k¾ûî»v˜éØ/5‹>9íÎ9ðððššš‘#G '~ùå—Ç–ÛÃTO˜0aàÀ)))F£ñõ×_Í•MtzgHþÕK$wÿ Ü_Õ•2(ûÎÐÉrb˜¿,†ƒ.Ã+×>î0–••…Ú»w/ÿ2™ríMy$„Ðô}jîTUç_E !ÀíñL­V{¸kö}ç®À˜rbXÄó®´WÁ¾3t Ãþ“ó‘!++Ë÷o»øn8„n ÜÏl6[›ûäþU!…àvŸÁø.Ô†5´- –ÕR€,ƒ'•k“!Ð ûOÎwÏ sOás'dÂÓ²N(h!šŽg!þmMî‡Ùl¶cÜü¢%7vÿ®%¼$‹›_•ˆ $2È#¹D6@ðz©;9Ρ‚aY9Ñ„À1¬R©ø÷©… ¼a¾¼maAE…ææø‘aƒÐ¡,ƒ4?7×°‡r"Ã|A…r¢MFVÎ߆…ãßOš4IXŽöö° !„˜hj¯ÐüJ ßÊEÏ7 OÀý`<ƒôTC,”Ã’3þ_áf¯À๿aóœÂŽÈFÇFÈʲ p ÆŒ@1) –5,ïÊ+Ãü¬N(h‡d¸3 û¯úÛ0«¬£ ËË4ÐFU!¡çõ;Épdä,•êTëé€1˜LËΩž0„ž×¿e儳³³¹Gðo¢aßoÑ…‚?Ðò¼>n=n,ßyä¯9¸»ˆ!œ¨Àà.X8Ñœ2C'˵—X0Œ[~p»åøÛ‘eÃXР3,’ó“ah>¤ÝÄM†þ‘?“Éñ… üD‘a°\“èd9ƒ° l˜A„[ô{1€6å:Î0'¢Öèoý¢¿h IDATÃþ+hÐîÌ؆ù7£AîM².½ÉtýØ>šÊ%ˆ|ÁO,ø¾ŸB6¹˜¢¢¢ßüæ7Ò¹555¿üå/­V«PNmʉ +  Ç3(Ç(¯{Gæä~d™üdØ÷‚vr†ýgXVÎ]Œ-° ‹‚ýdn“¹i†on ôÄp²Ÿ>+ä ®–àÖçÎ< 7·®®nãÆÒÅ­VëêÕ«].—²œ\#ê⠤͋ïàð†¥&!?,Z_Cû g>èàB€í€X€3[*o‚aa¼'•Î RÃÊuH ôÑð¾}û„Ÿ(ã.ñÝZ›L Æwl lŸádáöý3!dk¬Pxi‘„Áü»¹®ª¢¼¢Æds2*­!&¡Gr·H½Ff³ù̙ӃӒóË*­vQš¨øÄ¸˜(Êz£°¼Êb£)mXRÏÔø˜H‰0k­.+(½Qo±1@êÃ"cãRcD_ãÁÛíö£Gé“R|½ÊÜèÄ¥IHìÞ=ÖÀŰ´­ªâúÊê†F;‹(CxLzfZ˜Šûh ÐvkCUyQyµÕá"ÔÚ¨¸$›Ù¤S£þýûs‹7V——Wš,.–Pi 1ñ‰i© ì¨P`ÈXÐð@¤Ûd*lZž—ÃÃ`ß  {ŽN6ìû›Ñ\PߺL ìÌ wyÈϰälšïJ€ § ™•ÎNáxX§%ÿÌÁí›7í;›Wi²éc’†ŒÿÙs§LKÔR(??ÿÑ –üî‰U{Ž•T™±ÊÐwômãlj.É^µëHA…IÕ}êOülúä ÌºèÆºÛW­Þuørq¥ƒUÇ¥ô7eú¼_ÌLÖ‰Aeeåý÷ßÿé«Ol^òÌÅC¦Î~éE#3Í[¿zæåÞ”ÑwNñ¹jÏl{ÿž·O<õçÇŸ8ohûôÚÿ€8€|€?\ TOz?ÈûŠÒU] 0 ‘Z/Æápüøã¢˜3gÎ\ýõ|ð^§×‘hžž#ì—{ ç{ŠuÀø|0!4)Þlâ‰Q,BŽDkâã‘)cæ\ã–[rªÖsÍœ×@Î}íN§ÏM94þÏ[òñæŽQ¼96?&}ª«þiŒŸÀ{›®Z±bÅÊ’C'«n××Vsœc|Äémà¸ùÙ±BÍØÒf˜?áFÆØÃ᥵ힹ×þËlb:lp¬×íkoÀã€GÜpà=€/>¼ðdàÒÅ“lÉÕ05Mæ(¸„ö ƒä”o'WTTDθHÞSÒ¦aÝÕ°N[ _c¸&‡®ùA2÷ ¹ :+Kæ?$#…yáB¢~z žÇÍáx„æ®É%ƒ€íPÄ8–M€BvFÈ(%æB€‹±üöÁÿM5#s×id6w\­ÉÜŒ‰f†éÁŒÉŠL±ÛÊÿ¹ñËe;Ž×¥O˜3í²d«ÅÄûÈ£O èðìä°t5&ƇB^ÀÍ,wÏ=÷öKˆ7î¬Ì+¡ÙËf `+à€n¨È•­a…i ùk›p/BúE 0„%¡‚œ2ƒö «”CÝŸv“Nu’SFMýH jÖpäª;ÃT¹°´Àà  ¢ë~#µf¥PHƒJ>&Ë´{ñ±Vïè _îi܃PŸÛÙR}òèí%¤aÒÒ¢oJŽW6¸¼¬×Ýzêðî;6œzÜäá¬11i‰ñVn­=µiå"Öëá†ç%eÄ¡oVo«jjÇ»Zj÷n\UyüoÆj1]7{Ô÷+Öî9t¢¾¥õù¼ng]UÅîMk;ë8н@=…E5¬ÐÖEé Öp*ëÝ0UŽ eÃjätg"–PÝî٨ư*Äã3$³–×}½¡gAv05 ;süþ/×ïX¶4Ý;kxNRCÅÞ¯¾<ÜÿÊ9£‘BQ–ü“@|zòœy¿\ôûÏV'»FIO°¹[N?tâHéè‰3E†yœø|áz›³np¶ÅÛp`Ëæmûœ¿xàbžsâÀ¬í•Uß­Ý0y@|}ÅÁoîu»YþèOvülù†¯¾Xí`Gæ&¶Týqé¾C‡›Çg"ŽãÌ6ëeÜöÕÃ_;ÜMç ÏIÃîÖª“e{¶þ4vÊlà8@ê˜ÈQ 5Ln%Ó!ÚJ2„%¡T=¦ÊQIʆÕÈ …Ò×¢ÉííÆ„êÎp4[`†åêÁ@·çùŠ“ëwP·Šš)c2™âââ¨$ ‹€ç¡Ž#Çv¹ääägžy& 9²0#3söìÙÉYÇêZ\æ˜øÌœ‚QÃå¤Ûýž`ñ`Êóú¡×OÏÖpÁº3,‚ð>õ¦AÑ–3 ‡‘!t¹¾ƒ€¯gdÍ—•€r^9„P||ü]wÝYhOî?zÊ€s¦‚âÍ©a·û*–ÛÝ!` —«lXùýö‹°×°¾ GN.t-ÔîÚG  ""ëŨda‘ëAÃNç½ Q6¹„êΰzˆ„‰ð…ýʧLzM 4ja„ìz1&“‰¬;LÑK¨î Så€xpQà =¡Æ)£_ÃÑlÁ6@…$õ…:!*™ŽŒ´º…`©^  ZÓˆa2)–f3:†ÕËõ¬aþbÆ—#³Ðå4UÃQ–Ó»aŸ2ä`Œ[ ôQc2¹ŸÇ 0 /ô¹õbtm˜š¦°– ÖCä䊊ŠD¯”É-Ð059¿ ÆpMþÇg¡×]@ r#ôÉ€oY³ö›O75ºýkð&äBg£\qq1ùS™Ütø!zÐBý†ÃÈ »S¦Ï¢Ï­D°PhbkNÞ{ ~øÔßœC}ÃæŸªöm©jñzÍæøÌ„Ác³¦OLN´á ‚N «\Ÿ,Êõ:ƒä Ãad]®ï ÛûÔ „a/µM¨‘ô;ôm•k~…Ÿ¤yej»ñyÎV5#.!97?&îØ~8uóø\»‰JÂy›îÞ[ÙàŽÏÊ:|P‚ÉçvûêàgÅu5˜±ÆZ,^oÛþš‡ZçÜ4Èfµtÿ:,†¥·n¤KBuaX4¾ôöµÀ¾|Êèݰ‚„;¡Á6@E·÷©ùŠ“{V•ÿ Š!ëZ™AbÈ?•åD *åD†©r ‡#üéiݳy÷öÝ‡Ž¶ÅÉ.žë\³l_µÒp¶¡¶²V`¨)Ýðßßý÷[ï~½úç#un/Ûr¬âƒ¿îþü8xÕèß??ãù?Œ¹¶Ž¾û¹÷+Ž5³ÞH1D.¡º0Ì_Éø«Z4[`_>eôn¸gªÆ°*Ä3ô€üûóÔ­Ô®uö!X`àc¨=š°È‰¨r"ªën¬­<¾rùwk¶ìMËϼí²ïÿýG–ä<«¾Z³ì£†5Ïü­Ô4þòßÜ{Åù“ª7·¹‹¶,a_>úòó²‡%[’‡fwÕØ+½>××[µºZ#aXĹ„jÙpQQ‘ðSÙŒ3ø«Z4[`_>eôn¸g¿Õ6@EÇûg¸ûTc!i­ñ…Ò*"É]¨ ‚É )‹˜@aª•”ñ „¶~Wǵ¸3b9ιrÆ ¸ô~Ç?¯]ÝxóŒ«ÍSî˜2ʄӆ–zmBAÚÀ1ÓG%À©–ŠÅíN˜a·õ·X†É±ÙfbxÍÙ¾ãù¥Šää £Nø5¬|ÈÔcBƒ¨á0.**"Ÿ¿§6㨵À>{ÊèÝ0ÐZD,¡6 ‡®çõq÷™yùÐYû˜˜3”ÿu~É’… rÁd¡œœ2C¤å çÞ1ã0`Æl1™L>.óŸ¿þÐWúëÌÜŒÁE­n®ªÙ“•`Å_ýÌo¾öb¦¾ÒõãúÅ`ŽŸt€ðÉ—û=:QaÐõ£|ÈLh†…›ŠcþªMâúÑ~ GMNw†±¶O™/sÄýF>!ÑðÓFô¢?Õ0H!Id0É@_Ã<üÊ™­V›Ýk³XÌ c‰KyÓŸ¼?¿´¿¾®ÑÕ¸í‡>Zøöge-ü.©c¯ÿ¿ë‡{J—øÁÇ;*Ûí€.±ÇÀ§cำ^ï6æû%ÅD°¨†#—P½­‘Ø—O½ŽfBƒ3l€Š®JǤqdGdêw‡œ¤À ¬å·3âWNdدg©f¹Ö²a Å™¬±Ùãnë\[tìÌY—§òL]ÙÑJgÇò:ž†ŠÝ+=ö¬ü‚Áqæ8‹íêç›­/ß¶¿þT‹·åT}é–²õ&Æ:mÄÕv‹#¼†yˆj8r ÕŽaþ’†1ž1c† UNÁ³œaé¡IyÂRÃÑ4 K¨î +ð@¸œaTüþ™iÏK¢1uÈùe³®¶³¿ÞP„X ¹“c‹–-±Õ D'ö®nqYpÐj­Ø²«9mô´‹/½`j^¢•ó9& ¿íºÚ–cõ;~<ÔvÔßÜZ~¨Þ=mÀ/=|R¼Õ^ú«á  áó 5¬RNÄúÔ)cŽŽaT¨ºžQ+1¸D°ÈÊ€±×ç:°¾¤ªÝ+}úvpARí‘ýµÅ%ÆÙôã᎘Y·>4{Òè¡™±cÄÄÄ'\ôøyÜŠŠM»ënjòX,Éù9×NpÕœ„xÁO¸ ‡Ü#5950j¡ö…SF­¹´Ðµl¸oI‡Æc†aDëŸaŒBÔ¶´P¦¶€€4(§žÁźζŸ¥0`ÔÑ:3b2ìf»9~ý³àê‡üq;8†('”j¸¤¤„ÿ,šÚC †¥r¯amž21¬ñSFôãœÆz1þå‚fØ\µù¦7I]‘øôòO/ì¡92)–fÓ/ƒ\°Ô$jXj˜ æÌ™äÚ.=hXœ¦j8Êrz7¬ñSÆ€þýÌ€zÌÊ›Uuo¢õ°À¸{ ä ³fÍ2*Í€Tt½Fvp'„áK™/”~K;"²ˆþˆ#| 7É}y©‘C¯qþålèÂ05M~ %aOh„j˜/s¡zÐ~ 4NýJ¢Ð Ã59t½À3†É%@تP›BŒÂ|kƒrŒ²œÈ°Â|kÊr"¹c×µáÈ%4r†ù1™0•0ÿ¾¾Z î ƒqÊhã;PaTt›XÍeŸÿ)R. 1¨¦",r¢Bª\_0¹„d¸¤¤„¿’ñ,R—tÑo ¡·@ÝîÙSÆ]¿Ÿ µ&WÅÂè!$LÄB‚dPHªÀ `K$Gñ+'<¡$ÈÉÜI¹Þg8r ¨aÑ+eºkº3 Æ)ÓßÁ6@E·ñ_qÆâ½ÌpäÃEEEü}E>fæÌ™½£êΰhã”Q6¹„ª1l€ ¥iʺÅ‹_èÖpä.ÃÐùcaaaD G3¡º3 Æ)£ï@•§Œ)èÓ½ „DïS åÔB)ƒBpè Q–Óˆaò}j]V&gÖ…áž•3 †¥Á¤èz^_´!%%E¸Ô Õ\&b ‹ Ã(§#ÃÔŸ”ªtpØø§ð ùÉ>¨Ý©ž5L Æ’ßx"T?†a½Žœœ_ãz&Ù÷©M&“–û&FßM ¡Ÿ A3Ã2„õÙÅðÊÇ@ Ör †ƒ€–å"ÄÐð“ ½»%õŽ3Mk†ùÇ=xPçÖšá” A r†á02W2õøzFŽ‚ËŠÂ8#Òr~¨Á†a*Tæ/f¢å]´c8rr¡3h¡~zA T#§;èð3#Çùøû¶|’wÃÈBðw?Ê@FÄ F€JP%ä Ç 1DÙ°ú[Ê …ü­E~j-V>hŒSF1Xˆû&:®g!þuѳ¡ÇDzÐY•Bï€|³]¸ÀðuM¾á(wé‚η+øgD—(áOåî ù~F|B"©"烥½Ü}aÁ³õ¡ Ò¿¨6Ȳ†E[#j$õQ@æuQB{¥áÈ%Tw†©rÆ)#hê”1@…ìóú|¡ËÕÎ_Ï„òàFWáe ƒ÷ïß¿mÛÖßÝwääÂk8 r=eX˜ªJ/†õ"g6 Kƒ HÑõ¼>ß)>åàlkmnn ßă'rEe"%Ô`Ñ Œ€Ö3öï/ݱsWZZ:é– ®Ö¤y 'å„òH3¢`˜š™Ð  ë“éÅpDª;ÃÆ)ƒuÒÁ€ Äó7"„Dõ…1Æ€¡ûÌÓ¨óV= ²Pnfh2+|ŒpëRFÄ`œÊ Èy¼¯×Ë0bÃÒ?EWG¡èš*0ÍH¨ÿ§2ƒßލaªœtBòÌ È°ha-ŽfBugXÁ¿qÊ@Äœa0@C·ù7–'Às_­J„ΘŽ`*Å?rä%‹_(–OhH‹_ …üÅLã†åääbBL¨î ƒqÊh£ª1l€Šnó«¹ìóƒ!ꥈ㰚~ƒÀ°mûö\;ñ¯7›ššä‚©à8Œ@áP—fPf Ëî=‹_H_)Ó¸áå¨èõ†SFY®  ¢ã~£Ð_ öPÇmbÿP¹}ûŽv—K´ÆxÔÈ‘ÉÉId°À°yóÖ²²²‹.º¼ö¯+¯¼<11±¬ì¸×ë6l()'° äãî~Ä£uÑ)422€*G ˆ$5ܳ†©r"Ã"þsqq1ÿü=ù&™– ‹TÊE(¡º3,R)×û G.¡Á6@åý3éhcŒqÇõL¨SQÍ>öø“---±±±„ÓóÏ=3yÒD2X` ErssÌ&3|¶hq]]ÝKÿü‡²\w{”CÊ)@8dª\è rÁÑ1,“Ð ó—4JÂhXœî ‡QNï†u—P<Ì@ëG%¨ü}?²“BÆóÿ>þÇG¯þÅ•d¹4b†NþõkìF*ä:ÿÞéYINÊÐý¨Á¡3ÈGÇ0µrÔ&ŸÂ—ÎV¥AÃùV#§;Ãa”Ó»a·@rð3?HÑR]±}ÅÂW>ýþXuKLJÎÄ Y{úTN|ÇÖÁCG­úqÅßþöÂú¢bX¾ü;¾|Û– ‰‰‰rœ 0`ÀÙõb„r~U!@nÌ‹;!*ŒÁ]³oËÚïÿ½¦é×zyt^R[õ±—¬8¼g[δóÉ]ž}æ©—^~µ±©éñ?>—ÄÇÇó¬¢JÇ^¸›®ð/ÙQ0,W5XùnC(r2,‚0[•ð¯Öj8ÊrºK¨a8Ò†#'ç—Á®ÉÁÿøL}ݽ÷þ‡Â¸ :GÊ>pßèÑ£Nì¯(Ý}ꜛ=ë¼QIq6;-*ëÛOz»3dd¤'$$x½Þýû â‹™Ôcp†eéa»¥!¹ÐÔ oF‡.:ƒä Ãadè†#'!†¾€nó7òwåû€PGµRÍÏËÍ6l(tv(øHG|<œ¬m=ÙàþÅÔ‘©ñv0Å%ŒžÔ/¿ôD5M !‘œÔBˆg!Ä¥ùÆÄk› ÏѢηñåŸd ä w1ô¬a99a| ތֲa¹9Ã*墖PݦÊõåSF.@}Bƒ3l€ ñü ß{â‹ù*fJ_rÉEäó @´Ñz/×àãmƒ5~ )&à Õ–HŽÃ0¯Ÿ!„Þ)é4L™!T8X…“JÄ ’AÞ0# ŽŽaù„v0 Ïß“ÓákÖ0,¥òk˜*GEè Õa0N™žhÁ6@E·÷©ùŠ“yOPøýŒògçgÜÉ N€AV„êܬ° ëiâ|N$Ã/ú“ãøy¸”æÎÖ ¨qˆ™ºU™¡ÓŒƒ£PÑ3¬0t¾Íÿ)z_›†ýŽfBugX´‹qÊ(Ž\BÕ´xªÀ IDAT6@E·_S2caÎ1ÑUÝÂøª–ŽÞòb-¹6Ówå,‡aÎ×Z¹ÅY»_Ê`B€Ø.3Šr€©rÔÃáÿuš„ê±óÁÊ <”ää¢c˜šÐ’’~ëÌ™3ɧð5k8,5Í„êÎ0§Œ6Z Ã¨è˜=† –I…»1Ò„:ß“2Œ˜8`ô¸¤¯±¤´ÒíõÖßõÁëËW­Ø/¢EåØÌÈÍ®.«ÇÝË¥~xrd¤pt4ÃâûÊ ÒÏÃJ59Ãr1ÅÅÅd0UKS†EÁa1¹„êÎ0UŽê¹Ïž2¢`ªV ƒ¨Z/cÌñãªÎ?1mº'ÿü×gž}@ØŒñ‚W_:ÿü©1Yã¦^ÿ°gñ›Þùx½Óž˜1râE)ã¡ûpc|ñcL®¯ÞsãS­n㵫WÆÇÇ *¤¿îš¹‹bº‹_t½1.,,$0m2‚7¬À AÃ"9Ý6N¬“(ù7ЮçAäꫳPT§][ùø¿=ûWW{·ùy > c È”™7ùª›3ÏãtûL[bZ–×å´™8žáÝ·ßÌÌÈ€”Áfß”3è‚&·×111‚R®Ãîr.”‹‚¥Íˆ<@r«¨U…‘AZÃÑ4,“P„i'‰a8\ ÕáÈ%Tw†õÒ ˆðü BýŠ0iâyÊ‘fkLjî ´¼Á@äFÀÌ™…|¡%>5+>5« ƒ,R€œaõÁ¡3„ð&Ÿ9s&ùìbprê=¬»Žœ\è Z3 ‡‘!t¹¾ƒ€W" k6 n‚´«>9J9Uίajp SvÃü•L˜_û†UB“-0" Z¨Ý%´6@…ªëµµÔ£QÛÛÒŒaµÁA3ë“I‡e‘Kh„jXó-:ƒ®[`вaÝ2}”ë™´Ê0î*SÓ£‘n ´‹u9¬ :ƒ‚½ðÊñ—1¾P¸ŒÉ$T†© Ú7¬FNw†Ã(§wúK¨a[/¦{ ½<?ÁÆz1D0ÿøbQQ‘ô•2m–cоa5rº3F9½Öx 4 UÏëþ¼¾0þŒ3„J“K¨œa¡Â£`XeýèΰHNw†ûÎ)£RN³- È@<£´c²yó¦­[·y½Sዲõ‹i!F€4+ÂŽ"Br/D¼ÄMÝ…ÿSxEQê“£Ö¬ÉdÊË럗׈ˆ‚…«îìv‘™ {‘K3t]Ï:cD­ä¡2H…(´’M–R)3Pƒ©ˆ\\\,ºz…˰Üy"D¬†#g˜LE4 z;e"g¸gOT(] ¨WêådFÁÔë¦Ý|’[©N” SaâV'ùY†…6Ég=Ô¦‡%¡ªáȦÊE(¡º3L5¦ëSF-0à =€>Ž®zÑÈZ T9ƒJ9‘aªœÂáhÄpqq±ðćð¯F¿ ½†{G ÔaÑ.ú=eôÞÕ6@¢V¨¨÷A–S  !Êr=k˜¿˜Íš5K/†{„¡wˆ ÃÒ`RãV-¢¨¨H¸»³fÍê9/ 0 t½&Ý& ÝD7»©Dáb cÉé¾`¸¨¨ˆ«Lá¦M¸ ËkA r}³†µyÊã39øŸ_?ôº ˆ:C@è)àÂÔ‰ðõ–`-0hAÎ0F†Þa8rrbè ø~cïnI=r¦‘s‡EΨá02há›Hˆ{GBugدFŽˆ©¿UÊAV¿KØåü2Pƒ#jX¸˜!„ø «4nXYNw†#':ƒêGw í#† PÑ1>ªI®¾„»·¸ûlcd0É íSÁ$UŽd ©H9Uίaª\t —1rü¨V)§—a­µ@ݦÊõÃ*å‚Hhp† P!ž¡d^ÖÞQmåLˆ¡V:,šõƒ:š‹œˆ*'b ÊEÂ0ïG‹v »áÈ%Tw†£Ùug´}Êô¨Æ°*Œ÷Ï¢gX˜tŠŠŠz¥¬G GMNw†£,g6 Kƒ Hág½è¬PLÌÇÈÿÉשhÔ,šF“d & å䔢,4_ã|0?•p4ëGw Õa‘œî *WRRèבìY³:š&–¹Û+|¶ŠÚ½°É/ƒ,01¢¾ ÉCeP)GÒ*î݆©ÁaI¨î Så"”PÝÕ %_ö7`@;ð³^Œ²¿¦<¶¨‹-…°I§kIèÎpäª;ÃT9¹˜ª;à:¡ücÚšÂúõë;®gÒ.¤¢»%ÒxÜý.‡tw‘ŠœÉ ''¥¢ºÅHE $O/6L*†’PÝŽfBugXeBùÛŒÆÅÌ€¡ê}j¹sUá«'”àДOû°Ë…ÎeÑK¨î «G¯7bB èqP®gÒÌßà? 'ªBC§2Ÿ©§º\¼äônXû Õa5rº3œ„$Í—¿É Š#oeHãå‚¥z2hANŸPÝV#§;ÃÉ0 AëÅ0`À€Þc½Ãpdåtg¸w$4j†Ã ÞF„ „Žð&+,l]ó7Rï3q«lú~ïT(ÿ:¢,G2Èɉ¨r"¹óY$× Så¤Z½Ï°J¹%Tw†#q]Aò¹¡°°P%ÐÆ¶ªTW´Ã€ UQ*!JVˆüail]÷©ïšPvè|1Eº)PõÁT„ENT(7o[¯7¹„êÎ05˜Š^o8Bß¼¸¢ÏÊèÙéHÔ«kvÚ”HÓÂw5}†aâ¯ÄäDrßJƒÂI%0(œ-"9ºur"à ߶Êrz7¹„êÎ0UŽŠÐª;à.¡!BÍÍ̯¿þ:333##ãË/¿äKÈç÷ß?räH«Õ:~üø¯¾úŠ$Ž!4þ|`YöÁLNNNJJzà|>¿uúôéÉE´jÔE‘ügѱ¨qHîGî"­øôÓOl·ÛçÌ™sêÔ)ª i ^{íµAƒY­ÖAƒ½öÚk †å$ü¸€ŒŒ ¹Ãt»ÝóæÍs8ùùù+V¬ÒŠnã3¾IÉu$ù¢²*3q7ƒ ¦¶o* r"ÃT9…Ãé5†#—PÝŽfBugX´‹²\DqøðáòòòW^yå±Ç#-ñ¸ýöÛß}÷ÝÖÖÖ'Ÿ|òúë¯'w$Ç|ï¾û.<ýôÓ§OŸ>zôhyyy[[ÛK/½Ä²ì¬Y³®»îºáÇ¿þúë·Þz«h°Èï(¥õ«.Šä?—––’ǢơvðàÁ5kÖ(°ñ˜;wî‹/¾ØØØøË_þòÞ{索Æ,Xðõ×_¯\¹Òét._¾üË/¿ä/iI(¸ }üøñÌÌÌÅ‹ËæŸÿüç¶¶¶ŠŠŠíÛ·ÿý÷RÚ€1æ8Žã8–eY–åøð ›X–%7ñ[IaH>˜dÊ9‘V)×Uè㜟—õ‰¤$Z1Ü„a9W¾$Tw†©ÆD†¥N¤†¥rº3L ñû|¾uëÖ­[·‡ÂŸ¨°±±cìr¹„©¹ÈàÜÜÜ7ÞxÃétªáÌËË+//ç?×ÔÔŒ3c|öìÙ<ôÐCÓ§Ow¹\ fUñ@MMèXÔ8$÷Uf#áõzãââäG(8pàÁƒ…òÒÒÒ‚‚‚ $¤KF¶µµ7îÕW_U8Ìœœ¡ðÌ™3Ê)ð‹uëÖuìÏuµ/§:CèržVöÅ liOM° 뮆{·á¾\?Q¸ž)Þ¾}û¥—^š””të­·’ßËTN“ÉDvßív;_ÎßÝúä“O”ͪ®Æ¿J‡ $òsqqñäÉ“m6›hl¤°»Ùlöz½B¹Çã±X,AH(,Æø–[n™;w®òašL&–eåźuë¿Bk1PƒCgè߸£mS™¯¹³&]MÜÞï\wÞØR8¥yܘ¦#‡ m:´iÂÔæ?}Å:Ý=m8¬ Q– A r†aÝÿ‰&L˜°råʲ²² &\qÅÊÁýúõkjjÌ···€Ûí~ñÅß~ûíG}”úkP¸ÔÕ€êP=n¼ñÆGy¤¡¡A}vòòòŽ9"üyäÈ‘¼¼¼ðJ¼üòË|ûí·…êafgg õ_SS£†Yþß§ý7သ)›Æg8Ö ¨.ó-þwûÿ<åÞ]‡¦_bùÕ­ÖywÚæÏ·Î›g»ã6Û“«¹§ ‡•!Êr¡3hAÎ0¬ „¾ûî;‡Ãqî¹ç¶¶¶Š¶&&&?~|×®]iiipçw>ùä“MMM­­­/¿üòĉàî»ï¾å–[îºë®‡z覛nbYVºcpêj Æa@p»ÝãÖÖÖ>úHN…Äý÷ß×]w•––²,{àÀ»îºëþûïBBëÖ­{ñÅ¿þú똘èl]Ôüí¶Û}ôÑúúú†††¿þõ¯8|ïŒz]îÞºúàÐ""çã¾›ÑðËÜ?ŸaYïØO®çnhLéßôÑϾƒlY¹·¢Â{²Â{â„÷ô6ì×WWí}ãew×îª;Ãá’Ó¾ápÝo$¿‚¨…rŸ?ýôÓaÆ™Íæ#FüðÃ"ÚçŸÞáp$&&¾õÖ[c¯×ûð禦Úl¶Ù³g=z”ç¹ä’K0Æübñ<­hG9WÊêjüûuH­9¶uëÖ;Öl6çææ ã!©Šè ÿå—_8p Ùl8pàK/½Äu>û„\¼ô *w˜.—kÞ¼y±±±¹¹¹üc#Â-ÇuëÖu­çIÊ#™wñŠåÑ#§ÎTÖ͘1VM°ð'¢½¤(ƒr0çÅGÊð™J˜4W'™ó­˜Ab†f7½s{ì.1MLCõGÙUŸ{û”û¼$þÜtl–m0Ôõ½óþß;™C'q|“•bMàóµ75ÞT]Zålòp`·&e' –6ü°Øýs9Îa¾°Ð²Ñ}Ç|‚µ;ð–RX®a¿gÉ®}æMHÀmNà8Ü^ãûê]ÏÿÝÓvóÍm·þ¦›œ`ØdE#nˆ‡|_¬áJJ»MÄÿ+è¬vV±ëV±Ï~ص Ç⟶ú6lÇ`v ¡ób.Mg_}Û½vvaàxÀÚÙéÅØ„À ÀaìÉíK„¬aÑ Õ05"ªœß„úeКa5 å¿Á• «‘Óaeÿ hσð_­Ç =22hòä‘Ï<;cÌ †ÃƒØ´iÿòåù€gŸŸ’’@2àÎË›ãÖã\Õœv®éê›,Im>Q@» ÊŽ²kþëÝuoü(;fX´u‡LhÜ®ÕÅíFÀ0¨¡ bœ}I~÷ú¾[0XMWgKÎÇrï.ðT[™AçAb|¹ªÛÌu¤á˜ Ó=w™^+ñîÙ‰& µ$v>+#óÁ€YüñËÞkç›ã“Qs >´‡]¿»ú46Þ„9¼~¡gå Tp®ù|@È qyæûþ×ò§w|þ×kfpF¬é\«u ‡r¹gÚ¬q±lË–1LŠÕz¾HNzŸGTÃÒdI ËÅ 3á*'TتÃT9¹RŽz‘V–ÓaP—P4‹®çÚn~~V~~yp×ÜÒ¶|ùÆøøØ›ožsùS0Ær ü‰%l`&.‰qàòCÜÁø² ÅÏXZbQb2wÆ·­òwÆ»a6'šF ‡ÛXäröëãL ={¡9‘c†6ú0†š¾oWù obfšZØÏÀMMØËçg;8]ÈÌÿ‘a`êµö%í{7û6žc¾l  “õÃ:ñéuÞ“§ØãNÓdObbªôí¨ÃiGظ ؿѻý,ýL-­˜AÀµqÛ÷a{ Ó?R(3!íòÁc.ÝûÑîUGæÛбS%‡NoIräLy£TNQ!õ›+ /#åKQˆ z4L ¦¢6`@Ë躖§Ü·ê|E¸_‘ššxñÅïýíÕR’ÄçÄÀ+Ü^ÃÉc,3frŸ}É.zÇãôZºÅd"4í1šÎ úq±§-s§¼kö!K2ã‚3åëŸ~êÆœ(‡CTÎQÀ 5ç8·ix[}‹þë;\ ù¥xƒïßçkª‡?ñ”WãæCìj§ïp 2w?ý[›`ÏOlúPÓÔ‘–$3€ä~Ž× eßx†Â¾vHg!3 %'#g#ü°Øwú(›Çm>ì;Q‡ñ:ÏBcb€mâssæÚo»Æ<²?òºÏkIëÂ}û?ýŸÊµ¡#§ÖŸhµÎ2ûÖsg‰ääzÙd:¤ÉV™P¹ËŒ´†E:2L•£B$GQ–Óað—PþͳðB¡Uô Âî*¼„Z«4íøé¸ž‘VänD NðÁޏ˜©SG=ü‡›È…ä ö`g;0)˜€BÈâ`æÎµÚÛñ›yßû÷»›-qÄÉÕÞì;uܳ·7üÛµ s€Çîû  _ zî9_˜œdÀ×]® jq;¶°ÛKq¦ƒ]¸ ÌV¼v­{íZ€¼úŠ !4ô˜wÅZÜÒØõûyç#9«}ÕÞŽëêþ‹B€ŒAÜ´ÔúNœb÷œdÏþ‡Û Èë3q›=ÿÜ ü—ùœ‡â˜ c³5wx¿_ýczÌ?¶þí®×[|(É‘ÞÀÛ®~íœä©œ˜øÁŸL Q¡Ê„ÊiIJ(3hÍ0UŽÊ£l$§ŒTNw†A]Bà …«/aô¦œ—€\ù…ˆ°°°0”Õ/åì]9>ŸoРAãÆ[ºtiý@ÈG(èO.É]o後”ƒ1‡ÞÈí-åæÞiq˜»j¶y>zÓõ¯õxÇá¤s×߮ッ=Ö¾Êc9}0.¹Ð «gÀû’ëüu,EßÅFGë¸~ ÈfÀˆ3£!ÃÚ”Óá(ËiÊpQQ„u~€¾…£s= ¯P$ÕçN /^üÒK/•——oذaðàÁáòe¬_¿Þÿ|Ä¡1hÜ œæõ i¾ê†¶;ç;çßå¼ýW­—ßÞþü÷({jLJç]Ï3ûØ×u>ðHûÖDóûkb¢à-”oõ>5¯íñ·¼-ã-Ï}h÷¹ñ-/®æŽì÷|¼Øûßï9³ Láìä0Ð3X¿~ýúõë#Ç¿|ùò8Žùóç{<è~GTø,ü‹äW‘¦.¯,]ŽY™JêjÎãçŸ>//Ïf³Mš4iÉ’%|yO-åL="ªs)^yå•G}ôî»ï^°`´>…5²•N9‰rÕ^t½&ÝFÞ)ÊS Ÿ}¶ýãnç7¾¡C]|0ëÁm-\køîÎéÞ8‹ð“(QÑÙìTwUƒ§knÂm.|ü¬ï¦ŸÝ1 x›¡iùÞ nF z&®ë$ì ™ôL~[ÌÜ¥¡Íó7'Úªá€rzB£Ì 9é×O ?›E®¾zõê]»vaŒ÷»ß=õÔSÏ=÷iIøŒef³$Ãøå•—,YòØcñëG/X°`éÒ¥+W®,((8räÈ=÷Üã—Šu÷xàÅ_ܱcÇÎ;ccc.\xÝu×ñlsçÎ]²dÉe—]öþûïß{ï½Ë—/§ú$ÿ€òòò)S¦,Z´ˆ¥œM&Óïÿû—^zé‘G–rÆ?õÔSr‡O‘œsÑŽ?ÿüóÙ³g¯¹æšiÓ¦5ê™gžIJJù5²§NÊ+råª+¼èxSDÞ»»~ö|òµïP-š{úþsí$¬ÀÒñÕԞLa@ÁZ`è N9©Ç$Ý0§`Ž…±tÛ_Ï·§z¥á(ËiÊpØç#FUVVfeeÀ‰'¦OŸ~òäI‘á³òE!TSS“––æv»cccù‘MAAÁÊ•+‡ ÆÇàë™´ÜïÙÒ^íÛŸ8 #Xvuºýž)ÈfŠ \( *ƒ ÆáÉiÍpqqñŒ3"}=ä|>ŸÝn÷z½¢rõ×3é.‹¥½½ÝlîèD{½Þ¸¸8Ç£’Jnw‹Åâr¹DË.—””üáصk—ÛíæK¨×0‘ô­·ÞÊ0Ì'Ÿ|Âÿi6›ù+1»ÝÎp»Ý‚œš¾ˆœsr—'Nœ{î¹ååå‡öîÝ{ÅW”••ñ{‰U5‰Ôê /º~?CÝ! ʱüƒXr$&;>„™9ž1c4:„Õh‘r~µäbHÃ~y@þžŒ® +ð@P Õ¯aªœ„PÝ™„Fâ1}êêêø'OžÌÎÎæ?3 Ãù644„BèrÌ*wÏÉÉ‘þ<¦©¥œÕø‚ êêêâããùt3æäÉ“_|ñ•Pùè¨I@­®°£ëyaI7Žã¤qB¡(†<*9k"ãHfÒr˜!×X/ÌEf„É`jÖ©ü*åDb¨r ‡#ü©Ì }ÃaO¨~ G3¡º3,ÚE.,,T ž~ú鯯ÆúúúÇ{ì¶Ûnã óóó¿øâ —ËE~׫\Eš„ÜrÌ*©äv¿ë®»}ôѺºº¶¶¶ L™2…ïÁ¥œEGäwê–––?þøäÉ“˜À·ß~ûÊ+¯ÈV8:jP«ëüóÏsëÂó‹Ï²,˲Ë1Kרåÿ6±,+]»–dP^ý–”“.‰K2PH «”“.¶+b’ôÃr®|H¨î S‰ KH Kåtg˜,â÷…o}jü·Ð矞““;oÞ<—ËÅoZ¼xqZZZzzú×_-|Y©\EZôýF]ŽY%•Üî>ŸïÉ'ŸÌÌÌ´X,………ÇŽÃ=½”³èˆäœ‹333“,¼úê«¥–x(4‰$µº¦M›vþùçÐ\ѱ>5HútHæÖêu?n†µ §;ÃQ–ëÃü{f3gÎ1„ýý3‚ŽßÏø‹ÇuÌí+½†“[E1@\½I²\ø,b ÿT–1DYNŸPÝV#§;â}ù煮ڄxþFéÅ| –.~!4t!^™A& ù?ÉxÜýÇséÙ¥^Nο(Þ¯œÞ G.¡º3Í„êΰèO~dÆ_ÃDñ h]σ(wÁ„r¹{CÊm IDAT"…~œÀ ¬EÊQáWNdدg99½Ž\Bug˜*§À#gXœî &ù•-0 A<ßÙÄ굉ú="ç—l¦¢wŽœ\è =R?üÏcÂ3úÆÈÌ€Ž êz&×§Vš:ƒ\°aX¡wV^o·g̘Á—C4:e~ܹZ‡¨P¸í.jâÒB!Xz2Ê A9ÝÖcBugX*§;Ãêå¢ð†µA cR²H8+D…@û-Zº;,Õ ”A rz7¬ý„êΰ9Ýâ}¿  h≠0З1kÖ,¿÷ù{’ sKSý°/\ÁZ`ˆ¾œ)ºî7J눬Ga+î|†JØ*dB™A„Q.I…Äû•#i•?÷nÃÔà°$Tw†©rJ¨î CĪ;ÃÔà%4ÃÒÕÛ ðèŸñ5Èqÿ– 5+c~«Bm aÂ&>X.†”“kñÊrÂVANz\"¹c×µá`ú@5Ça†á;=À0< ˜ p±ö Sä¨1ÑI¨¾ óóè§Lô[`p† PÑu¿‘Z³R(§!D¹`*Â"'*¤žW}Á0-xÇ•!8¿žḭþZ F óÏwó“çLÐrQ3l€ ñü ÿ£49¦Vhd0ƒ‚-‘5ƯœðŒœ '×$åzŸá*õ˜´gXC-PG†…§óE†Á8eä ‡+¡Á6@E4Ö‹!¼-ígËëO–Ö”í©:¾ïlÅ¡úÊŠæ–VNªu¶¸©r’æ?P •å¨ ÇvWy=]kîiÙp ŒêÛ¯àWS†5´üŠî ‹v û)£#Ã=›P5† PÑíùF…^•pW´UÔ!{.âMö¶¸No>ºvYYÙ¡†úºv™2“2‡¥¿|ÔE—dýsþ²ß<={ÜÃ"'=L[VQÄ êsñÁT†Ç¯Xøjɼ¬ü¤pÕOä ™Ðvlô0¯Þ ÈÀØ:טՖašœˆD!¡a—Ó…aáM2~ˆÑS&,†E$½²ª1l€Š®EµÉ$) ·ùš¥“{I“ÔRQ³í£ ÿýÙü«ÿ=÷Ê'ÓS’Lîºæ£m]vàÝy».>ý°0ʖʉ˜@jXγ‚aªœˆGÊЩ…¤TÚ4 Á%ôJ¸`@n@ÿ(ø#ÀDà_[†ýµ@99…Ȫ}Ã3gÎ,**ž¿§ÊQÙ „F®†#dXÄ@5Æ„j؀̀1¦Ža…±0Y›r£]e¶±æèΣëÅ?ñΔŒT›Õj2™Àœ™4ò²1yã ý´Xð ú”êÁ¯\è†U0tDRƒ5i8Àà)–¬ð¸àà›Rs!ìŸ!ʆ#)§»„ª7Ì?Ö¨#ÃÊEÈpääü2—79øŸZ®îJŠwïÝwüw¿»F CýÞ†Êí Y7ŒïŸç` #gÈl²9L–|˹wttk÷Ÿ,:Ryô`Cc£Y­™#r.¸}dF‚Å À¬ÏYÛtàÇC‹ª}kê Œ±³ŒŸncÀÝî}õÞ忸qPù‘Æò£Mmíœ5!.}Hæœyç¤Zμ¹üìñ-[7V54±öÔÄÁÓ‡”o>2zbfá/Göqu;ËÖ./«ªr±Œ%cxÎè™ÇŽWst˜e[*ö­:¼uCÏfËÑoüyƒG¦Xh¬iûÏÃ?ν{äŽg*Ž·´»±=9¾ÿøœ©× Íˆé¨Ø¦£U¥?•ïÙY×ÔÂÆ¤&›=üÐê}³¯>jZÞñ½Õ?|´ë·/]J*ØtrËÊ£wüõþO_{{ÅŽ“{ŠO–k3ÅÇäŒéá¯%Ęù£vV7•o<¶yCUmÇšäÈŸ8°¾¼&'×~ñ¯Çñ»×ï<öóšŠò²7gJ1ò‚¡S§&\0 àS€/Úü`4@vN§€´ ×+ ñ·õb8¸àТ,!†¾€€çËg*ëV,ÿÙb6Ý}Ï/üîUY鮬òœ;5Ý„ ÛïŒÙ”ŸÉÞTRÛtFêàÌ~VĹ½5‡­\˜ø‹úedZ ²¢yÝçâ’c†N€Y¶¥ºaÿO¦vÖ>ur<ÇâkËÌfkÖÐä~çô³0ØÝäl8rlÙûÉ¿ž—cµ"wUåÞõ'öínI.Èègf[Û˾߳wsEjš 8»õÄÉ/ÞÚo/HÏ›b_sUÝží(yüØ6áåpâPÆoÇ%Ùxc§Îì,bÚYÛ¹ãâ<íìεe Éñ‰9qycÌ·7¶Öî9þ]»ãŽ»rÀuúÔŽÕ'ÊÊÝ©C3óì Ûæ:üõÎÝ?7=ZêÛ÷o<)’k¬n;´õ´ŽõKÕUµÆ¤& KOò¹ÜÿmÒE¥¦¦˜½uuÇ6•oX[—48}Ôël¯Ú|ôÀ¶ÓxöŽs>±ìýRœš=*ÛjÂÎzçÞ/wš3§M,°A5À.€Óf`ØCoj@ ! hY.t•Á s0öÁ„êΰ*¾ž‘5[UUÿÙgk“¿úÕlå½Ý\ƒM5ƒüX<©I9S ÆŒKMN²pÎö£k¼¯¿Q:û‚$þz†“9.6JÁè1IØåªÜ]¶ú‡†ýÎL<ŒßÝ™:dÖ a#’âìÈY]lÃÁ×^ß{óÜL«ÕrfsEyY Í›þËüì ›³ªþç~:¶“å;=î†ö#ËöŸ´$ßpň;öTl>¶cCÕOËO½¯Àcb{’£`Ú€‘£“°Óybó¡W7ÙZ}ÞøAüööìŒ)srIˆ±â–“gwüxä«ÅøëÙÉ’ã•Ǹ3/ÉMI0¹j‹Ö–Z:žœ”ë” Åcd¶¤d ™Õ/Ëîih:¾áÀÛ‹ŽN›š_»¿ºlgµ§ ÿôçdÙœ5»–l;½ßÃïëc¹Ã_î9Á%Ξ5tô¸‡…«)=½eÙU‹NL||(¬Ø àØ0àg@€¤o˜ŸsÐé‰(Ë…ÎQÃ3fÌmí í#† P¡êzv¶ºáXÙè^›ååU¸©©õ…¿ÿ·ÿÌqãÛíV9!ÆVÆÏyâ&ÌÈN¶"€„Ø‘WM`Ÿú”óŒ8%Õ<}NNksKé†&Œ1öY\ÍN®é À0 fÝ2dÔð”83B%䦽ø×cŸbß–ƒ›!Á1éºAý2,!G¿´é¿¶yG#¯ÛZïÙôÕé´Û‡ûêšN46Ç!“Ž~S ÷({Æœ/3Û>¹0³µ¹¹tCæ0fâ\õ•n;ƒqǾWüntÿXcB<03 ëþ÷ü¦}%õö‘9ã/ždG¿´YóG–ljB?‰ÓE;‹±Ï;nJFcm{ÛɺÇ}c””Özh“¯}@ü‰-uuxò½Ãò²­—‘|ÞuƒK7"@àóp%ŸV$Î…\ÎS»]!ŸÛ“Ð?öÀ‚]ðøP`fLØ PðG€{:tåΫõ:{GŸZw†!b ¡×´@c FtÍwÅ¿î@}PuÝúÿxá3 OµaŒÉ‘Ã}¿{eé²¿åæ¦ ¢z·!ˆ1¡:7g6ñßÔ‚™Ë$[QçW9 ‹s,¯éu:+÷Ÿ\ûIiéžÚ†7‡ã0ëñM¾|(Bˆÿ‚.p˜âÌ—db,qØçF!„N¶ûSaxj×õÛ–™o²íåeu²°£Ê޶j/á!”ž—ƒ$ªa`ÛZOí:¹~Ñáƒ{k›š<üK#7{á-c„˜á ¦.“™ìÛñ¦]¹“bgòºª=&{0cÙ‰1–oýH·yêëw~spÛº“§N´8>hoó"ÌaŒ«Ý\;Bc2,ÂîÖ”sÜQ0BȰ£ÎëûOÑcþyM°òä¿ï¸j2¥ñ€­¿¸–´BE G'Pâî‹¿ÈuQɦµ°#L«z T£~O‘†¡óÁQ iX*§YÃ%%%@¼C­,–„F¨†#g$ˆ\Bƒ3l€ UÏëwþIy¢”„Âõy ¦³ÓOåž[GÇ’)'#ÉE ¡òÕÇKîi)ÿÀ£²rb-&„À÷å+›Î”5vZë¶;Y11¨?B `k¼í»þ'Þ¢“Üóúû>Ù»}C¥oæ˜ÿ{"/³_¬ÕŒ€ó}øÔzŽëФÖ0q¼ˆ?qgÃ0ÂþÒšç¾»{yù Áãîž=oBjR²Íb„¹;Ïyð»‹óÅï†;ªÆèùŸæg¤òCG‘Dçÿ×\ˆ¸É)T.µ~@Ñ0ÖÞÓÒ ‘¢¯0RE.¡Ú7Ì?£¯^ŽÊ$4r5!Ã"ªaãy} ¢ëy}Ü9÷¥´wpÍ5…—\2I¨S¾|éÒ’×|ɯ­[¿ÀሑN£)0dLLÎjˆ_úܶ«?*Œ5wHò1ÞÖöß­}÷Bïƒdä*Ù³Vë½ó‡%Ø~†\gåqO}%ÆöÎŽRG0ê6*ï(‹Î¸¹mUÞÂ+¿ÕYq€mkÈÁ;ÌxJª¹¨Òsi?«uëˆ 017(ÆX`>TǶ'ÅÜ6wPbŒ™Ÿ±×yê ·é,ŸÞiC¨ànÕ‡êœ\i-;.ÝÌ3·ŸØës;;Z<€Í„κ¹tk‡ÎÝȶUcÌñ ëÊÝ7Ý“;á‚l›Îëq–ïÆ>Ƙ㸼¦ã§ÜsØùxWÕ1¶¹ÅgpgBhf†yk-;=žK²tõ'{À0€1!JÏQR?ÝbD U®ajÿTÄ œä d Œ‚a‘œ– óó4FM.B5Üg[ í›Ü9ߟ?$yûclµš“’‰‰q‰‰q ±‰‰qIIþײôôÄ?~<11Žaƒ-=}àø‚‰™u/ÿþ§-«ëêÜ>/ç¬i:º®tÅ?V½÷Îq2˜dÀ—dŠig׬­rº1çõž-=µêÍÒ]?VQ夎º8ƒimÙôæž²Š6ŽãËN/ÿÇÁÊ#-¼áÄìØi¿RòôÖÒ}õM-^¯›m­n<¸æÀª×Ö Âщø3ì5y~ÚX×îÁœ×{fgÙ×/ì;ðS­ÔŒÀ@¶Ès®Êt¬Ùöé¡S•.ëk,;ýÕ3êO9ù˜”XtN2Zøî‘ÆVŸõ5ªÝöù-‹ŽðÃJšh:°«þÐчk¯o9RtäÃ?ìq·³¼\þĤ´,fӂ݇ËÚ8Žk®¨^ûÖáCëø­fsÁc£¶¾¾{ÿ¦ê¦f–õúÚë[Ë~>ºì醂î Ý+ [ýHëº7 ò¼ý©Ð~¤üT9e99iƒñkXœ —””ð#35§L¡Žœáh&48èi½˜ÁƒsïýíÕ£ÏézbBn­d¶¦dM½‰‹Ýröðª}{—²^Ïëõq>Œ‘iĵ“äx3Æg´64îüa÷‡?î@€Àd‹GéiÁ%Ç…!”:¶`t‚Õ+_.ÂüÒ'qÙ\¬‹ofGLÎŒQÕØ³dǦV–e1²˜bc³eq߃ºøÅÈ û£ØóÍŽòo0B ÎßIfEad ×Ù(3Î:®¡üÀöSË^¨À›L ¤ Àv7â8.9?iò£V®=²ð‰cÀ˜K¬MÍÂÕ <ÕœûÇnßÓXüÖ†Ÿ0•9ïÙÌË9e,äš¿«XýZñ#!S¼/!!c Ê™5ö‚º²3?<´Âãñp`bìñöä~¹DB» ÑDè«u(ÄrÔoe9mË™ oBC1¬\?½ gئ§žzŠÿÄ׬0‚¦F Ç üY_2‘¼I>D$&«Ù‘™•eGˆ±ØÌÖXkBz|æ ôr'\X”dÁŸŸÓ Ÿ˜ã°Ú¬ ™qV“Õ›“–—\0)/Tzþ°”Ü!©€1™FMͳڻžøà GOëo23ÈjMHŽMJ±pÀXãl)y)ƒÏK¬8ììW6jJ60Œ)&6;ÛÊz±Ùj¶9ìIY‰9Ã2›“”d™¬Œ—‹M±'¤ÇZb¬æ¸äØôià æN*™š=0,6˨iyݰ=Ö2br˜bb’mŽx32u:%éè®Öáû žb¶›ýâãL3LL¢=¹_bÿ19ÇfåŒ/“‰JéŸ`³š-f“-ΟîÈ’>úÂÁ™1#&çØã,&›-.169ÙŒ™c­É9IÇ&6ÖyããÇÍÌsl\f¦!²;ìñŽÌAéC§æ§¤X^Ǹ3ëù¼`²´IPS/jÒ¦%bPߥrÊ-P½œ_Ãü’A¥\Ïîß¿~~~(†!L Z ‡Ë°J¹ œaª77jE#Ôù{¬ð'î~óWT2Cfe99¿ ÁÉÕ×¹ÚZÙô¬X»aî3;vö™käÔþWÝšß³†k϶³>HNµY-ÈçòœÚ²ý£OØKo>ù‚ŒàäÈÈÖo]­+³_ÔgZ±´1>'ç¦{ù3<àhw9áNã+=ÆúñËÐ;Z`.**É3‘“멎œaM%TatØÇAyÿL:¼å/xB·w¿Ÿë—¡¥¡½½¥ã^jÚrP°2柪ʎ6Ϻ¬v–­¹üìºWö¹òGáDûÙŠ¦@åÂkxýªSÍ-ì”™ÙiÉæ–“µ?þ}/3ÉÍ€²1•r‡4ü\R5çsúÙZOÖnúà@5“‘8.–'W`Hñq¦Îb ÏŠò%©€0¯Ð:Ûˆ!ì-PY.Ãjätg8Œrz7¬»„àA¯© ¯Ôàÿ²nå{Û…âÎ/Ån± Sz°¢,ïž}!›­¥‡¾ò <ø`Ga°M¿…1ôn¹°^¿~=9¾ö 뮆£,g@Šh\ÏÂÎe¹¾jx(À‘îå]÷Œë™îjî=†Á QZ/F=5+Þ Ã¡¦ÿà•òÿ¦"c½m'T(äçž9s¦^ ‡].B†#'ç—Á¸žÉ!øõbÔ# jpè ¡¦a€tW ¡ŸMº«Ãpz‡áÈÉEˆ¡/ kB¾ PkBuL€|DĠвI9jŒ_9¿†©r}Á°J¹ÞgX¥\ÔÃ3fÌà6ÓT ì³§ŒT.8è@c5ƒ_¡N…a¯°UøSZïRf>‹d¤!¹•êDÙ0Õ˜´µ‰Øz¥ajpXª;ÃT¹%´Ç ówùuaÔ¦3N©«ð&4ÃÆóúrèªŽãøŠ£Î-ŠbȺVf‚…òOe9ƒJ9‘aªœÂáôÑK¨î G3¡º3,ÚÅ8e” G.¡j  ¢k|&]+AÔ7!ûÒ7ÛaOꀚd€Îµ$üvv¨½$ÑZjäø?I9LLÿþ*úyŸ~]Ú~ß;׌Ÿ]º¹) jpè =k8ˆ„Þ?íÝWKîä××vWÕ—~³ãý·Õ4°üuû_g_>oBØ òtQÆ€¤?--/þb†]pÀ\!¾ckå¢Ü$Š‹‹gΜ©ÍCÏŽX arˆÞóú–öÆØ;Š«<,×=ÆçuUøêxB«·ëy!-?ËCÏVNèç¿{lw•(¡:ß÷<¶¯¡hUíµþúݽ÷½·ï¾Ñ…B7üÙßK>[$f´.†`ž–Þ…á6Ào´ÆÀqÛ?p`,ÖÝóúÐùŒ¾[`/;e¢“Pãyý Ðu¿‘ç\Ú1ákPx#]øS¨b!^™!+×:ëÒøï^<~î_ bbMB°«Ñµ÷Åyó§{ïP` Óœ‚iÏHYŽdv—´oX9¡­M.Ÿ%ôÙooMÍvð1-Üà…‰#vc|ç3³cl!v9½Âé*þÕÃç›­¦Èµ@ˆœè ÀkŽó€ðe݆fáJh Ò€z³Q -°—2áMhp†Á ×3¾‚8Ž#'§!Áw ø­|6o>p°´âö;.%Ã!L@lFâÀ#ñÿî8Ö˜3Äk7Çqˆó´4Ô~·_ûßœ7™ºx|>Oskéê#;6×°&kbnò°)¹#&¤Û€7øî‚Kûןu–it¶cSŒ-}pzáÍ#“¬`Bœ×Û|ºáÈÏå»·Öû¬–ŒaÙãfåå pX™ŽãªÜphˆÊê³.ÎdN˜‘•p|á{_¼„?vç麲í§öí¬mla-ÇÐ †M8/Åá0ñGGT颵ÉIéçöžfêqscóyWµ³lÕÖÿgï»ã㨮¶Ï¹S¶h¥UoVµlÉ–e÷Þ°ÁÆS HHH ï’|oBBBHHH$0˜š1ÍÛ¸÷.[¶U-Y½—•¶L¹÷ûcV£Õ6˶d$³çÇϬîœyÎsÏ9wn™;3e»¶Ôvv*h4Äf'äÎHÍÎÓ”ß||ÛÜ›sÓsã<½÷ò/6.pZBz侵ŕGk¦ÎJï#î×ô0TTÔ¯^½ý¿ïlî'g4Ff&Í›&ïÛÜÖÙ®hÊöÚöº]åÝSÇæ¥‰¡÷ÜŽfÇ篟¬¬W¬IÖ¨XƒÜÔ|j×ÙǺ´£;VŸüâÃòòJ»h5Ç$Y ´ñhéú÷êì]Цpædë–OÊ«›ÕÈkt¬ÁVZu`kmy©˜¢8ΔþNy›-q–Èh±»ªéлG÷|Z¤ÕNnm:¶¹äÀŽz'£-áF¥puÁ±Âö›â[;žë.?ÒP¸»ÕÓ?]§ËK6WÕPpØ[N”®}«ÌÁ‰á –°0h)¬9´¾ôT•¤)ØPÚÖÐå…¹ïó’ÎV¥´ª¨yˇÅ[>¯q¢3"2>Íj0 ^!…»«6}XZp¤ÑÉáѱ†ŽÓgv|R]}¦›­á¨›Cd¢ÅbƺÇ69U%!ÁøôHŽã¢-qi éÖÈ„0ÝÃŽn‰Rj‰2FĘy‘KH·Æ§Gr)Ü]USÖ Ôé쪨üôõ’vZâ,‘¼³¡¥±ð¬ÎmóûE'Ž·»81*1ÌÌ+õ‡Š7nhWUŒŒ3YD³ELȈŒO³Æ§Gr<§öWWžjêru—”®}«¬µ,±aáá\GIÝ¡5'–»´*Ýræ‹úT¹¥ xëšZ­ÊÍem‡><]ÙB#Âc“-a&h+­m*©ÀP ÚE†Àn€FG œu{8Сóm2àWyûöíÚ6ý'ìWÙ7ÏÁ¯ò°#³ãäç›[Ì˘ìr·«dõ‘HºýÆ1£G…ó²«r_ÙÖÊJÒS»ú}gŠ ÛÕv4ú IDAT䤅7f¥0Ê-훞ÝvhkM”Õ3Æ{?\ú‚ôãÅí«Z—ÆÅ0J‹7–SCìˆ #X³­xý©2L¸ÿ®IÉ "ëê:ýEá‘#u{¶ÄåÞ3Â×Éî—‚¾Nä[¬1·Þ––FÓ£ãèäLæ1©³&ÇÇÀå:µvÿ;ïUŽž5*ÌVÕVüeiÆÝפ‰¢ÒÞyâ³cÇŠê÷l‰Î½gÄ7žµþµÃ‹îÌ=1Éw€L73­½ÁÞ\Óù͟;ë<ö&[ùÚ®È;îÉ5*‚W\u'k].]¡¥YŽ8fRBb¼èhh9õåÉ•+‹Í4÷æÜ²c ”ÒÛ~: <¶o‘žJ¹ÚÅ.Ãäo.;:;‚sÚ˶Ù^½ùÓÆI?IwWYó¬ráÇ{V¾S::Ô5*¬þLçÑíõ]6R´ÈQ{‹­ª F4Shø`?°kß2 `=@@Þ9Þ7Xp®„÷m2~=AÏFçWô/œ] a]ÁÓ\ i“Wž/aá~^$ F8$~¥_ß‹imµž9y²Bÿ¯°ðL}}+´¶t>òË—Ož¬$%‚&(ˆ®Èæ*+Ïv4wH®Ö¶š:ÛiLXz…¹cÖ(þæûÆ%ZÔº¢ÆêòÕAxì.«ÔC;÷Μ+æ%DG ¼È‡%EŽ[>ÑQYLe€ÑQ㢮¾1#Þ¤T6T•Û„¤D¹­ÍYÛŽ.eÛªêùO=62Ì̬aYsRgß™Ùc™ØPïPÅ„1Ñhë>{ª¹¾I½(©f{EkI‹×B6ˆq©#“ùl9\Ò­•(]í{ö¹ qæì)–Ö:×±míó>uT†ÙlâM1ã¯É•^±®,HH<|Èâ2#=—™Æq¾G{ÿÌ»rÄœ›2““L‡‚Ű?¤ý°_ÌÖî' ~È?†êý÷p &ÓÇ?>/¢==}ñ„½N d.HuúIX'3d µíáø÷~}Ï¥^Bˆ×ÈbÓ¦ƒ~òm§»ïºóñ5?‘–– #@ß1"º‘¯ùßÔ—?·ÅEE‘ö{U[Öwg \ïÞVDd²«ãlýú9°«®¥Å©¨ZüpÂüŒn8ÒB¢ îk<á˜ê`ˆH%Gåò-«N4·¶¸TÊ4Yyш(3<Ü®~;Í`&Ú.màÍVSÂH€Úˆ©¤“Ø|T~÷ˆÎ€"“Gk ½ü“³(¦s;Ûû^óUyDì.:ÒLâr¢ãÒ-Ü +œì;FD÷й/XÛT{!xŒ¿¼Eôø#œí½ÆèéaL’‰K6s:&gˆ`LE`ˆØ&³zïÉ0êbL2Þ¬ÚK}Ì+ì[ØPí("Úd8Þ¡Þ=Ò(rà‹ :Úw¾zðÀÖêÚê®în…2ýHxü©«ÏÏuª÷gM„i´…ˆXc¼,w®Õ•Sü« LѪœšdÈO"/Þ·vêµ#3ÇÄd^‘œšn!‹ø4 a„ääñ·_ßÓÞ1ò5{6¯8zºË];#wý‡_]Ù AÏ@Ï÷è_¬ÿúíêýåïVΚ¼ô÷“rr¬‘¢À½Ãþíq/žn_é/ç˜ éKÿ–4åtmÁ¾ú³K·?¿CÌΞ׋{(íé?‘!*[·n…¾]ZHBò5÷Ë8­)kÿ.[6cæLïM`k?ßûÒKŸ®ùø‰¤¤_1Lÿæ~7iÍÇeuæ”éËóIÏZŸe7tÓ ‰Üov¼U 0gsµ«¹FGèd} ¹m·È|¢å†›Ò#Ã8žCƘ£¶DînˆdŒ‰S"¹/+]W¦a€ÒÕæ¬/e= c‰MVË;Õ\+çY‹ þ1Ö8þÚÈßlzèæöma÷d†eÅÆX8Y&²©ÂqC–QS–ÚäŽVÞ2BûÓD [»LM<0*Ûª(UXxT9àº?cŒ1êã ÷¡(“ðäàj®–m]:÷ù}ûÏe^o{š‹`b$÷E©}Y–Aôéu·T¸þ篙#s¢ "!T§½»â„Ö'1Æ(@¯Q7x-3“­Ü¦ Ç•©b˜€Œ1¥³ÙÕX%X3½˜øsbàcÇ&Ï™(Kг­yÍ+§ë±Eº'ÅÓì9ö[$)_0Âüùóõ&3,Wv„ÏÜ9BS´@rî3ˆh±˜RSãSSãÓÒ´©©ñ‘Qˆ‰±þ㟥¥%ð<Á«$füØ%wÏ]±"wj®÷ä ÃxŒ`tïþ— LQš‹kw®*:¸¶&IÑ|ŒHmÒñÂIP”†g×>[Xq¬MKS8¿à¾ÔmOì/*lï¶+Îv[ɶ³[_-×/r–ÛìGV—×Ö:d…QIn,ªÛñê®ÚSõjgJˆËÎT>;Pðbqn^T¼Å$ˆN6\±(rÛãûJÎtÛª½©ýاåEÇl™×giçNI ÷5ž8Ñáp©R—£±¨öÓ?ì“jr{sT˜iÊ™¦qpIjw}ëÁËÏVJ:‡d9SçjíRƒâûAŽJ5͸+uÇã» ÚººWGwùÎÓ…ë 4 Wp´­±ERUêhé,ÞVöá“…ÐÓ—D DvÐÒ:—O#,¸gĶÇ÷*hëêVœ­…Îìù¸.ûޱý©rÙé¶÷^=U^içLK¤œ.ÅT}õTöÜ[Î.á¼äâÍ… Â%67H_¹¨ïÅdd$ÝsïÒ9sÆŸ/g±¦çZ)$Žœ²4åð¦ïí-BU–e™S,ц@'ô•±s“]ìláGG+ÖsQ•e—E ÚQÞ,Ž\>eBù©#ï>Æ#S$f3'9«q‹›<2ÏY[VظíõZE¢ ¼!LL'B ‹Ä`ˆJŠœ2ƶnmÛ¬'¯ŠŒ1h©gе4/¯®të+û8Â1Ù…Q£S'ÎÑNœvWî¶=­Þ>xÂÄ@d¦dÀºþU è¥A “%%zô¢œ¼Æ3:É…‰ãRÆ÷pX¸tDÑÖ¢Ê=å‡#²¢¯úÖ_@¿£ISlDÆ’üé•EÇ>:v  ò!%;V;ºô‡ùûNŸÝX\-ð„1ªJÔ“Ъq“éØYµá»vWübŽhäõnÓ–uÓ”¼Ê“G>8r\@dL–Ð’ºäÚx¯Úùðd`䨱»ãà{$‘©a±ÙSSšzühŠæßÃFÓ_!‚×{ôÛÜù*_<ÂyÉ×pHü ÷Øcù– xzV’ää䨛ožDYÿ-»‹Õ”uEb d€®vgöä䈳1\°&‡ÍÙÕ)«€æ˜ðô‰)©ãâ“ÓÂ5[«#nF˜Õ³ƒcöNiÂütƒY°Ä™ÌV‘uK»¢±ÄGdÏËŠO 9.&yd4"DF&DA·Íår©(Š1éÖ˜ Kéá®å?ÈgŒqFST´Á,²®ÉiWT á Ö‘Ó2’2¬FC í¼ˆ²“k­üøHÔ]åF[yí¹mN ‘ቱ¤½É!+”3“Æ'çÍN•nÔ@ÂÓ"DdÔ©HNÁž{õX‹ÆÏN ³$‡b Óª$v›+-'6.ժ߯fŒÙ;]#ó¢-DMQ–¤x¾½É!I” 3¥\‘š7sÄÈT7‡˜XÁÞ­¸ìªªÒð(³îaÍ™ KªÁ$äL¡áëæˆ á–”d¡³Õátª(q£ÓòGÄĈ7ÚÊì’äPd…qF1&3nì•£#Âp‚ ^à,ᜠ ½C’$•1?78g·”42*)3 yNŒŠŠdN»ìrªh0$ŒIÊ—1n´Ù«vz•õü‰N´EŒ´ £ÃÙeS‰%!jÌì´ÑbLâ€7ývfˆðÛà ¯êO‚g@½4+++ýÞ6psçD𫨇a¿Ê!Aý–ƒ¶ ˆú#ýž~d}ŸŸ×—ìõr '‚®ì‰àWÙ³PTÞ‹Æ9 COÔý®©êŠŠ1 (u´4î,yó úÏOæûÞŠèa ´£¢®`ÕŽ-ÊÌŸý2%,ŒpÂAüs!„( ÃðŒ]CP Ú¿ˆ€èþS{^À/á ËÀË¬É l@‡áÁ è渀7w¾æÒg½‘~ ’ô¼v%øæQæñ¤¡~Hv)ŠDµÇ„õB¦íà&½ïvcŒ¹oƒ¹7 @ïM1m«@]¹€CÛj̽kßÍùù¿½~Åè¬, 8ºË6—íþìlâÕ í6—n+ˆ9_ÂRGgñÞÊw?vÜÿy„ “ {n3`ˆ€lßõï‹IøBЕuÆØöíÛý.3ˆ9/ýêô}¬Ø—°/ÂÐ'<à×Ààæ.€pHüŠÿ/ëô^ ¼´Õ(¯üí–uÿ9¤÷^ϰ 5™áKدò ôû] \Ì÷büŠŽDM?¤ßðô«ãi.PÆ7§õ{[Õ/á@uÖ„/ Ã°`:2Fû”ÏÛH.> ÛdvìØ¡ýô6¡œÃŽð¥¼^áø•ÞùYŸÒ¾ƒ)ÏrÖwÀÂ|F^çT”¸—À\ˆpˆð%37à„=w‚„úu&šŸ’~ùÅïèÀoAè¿òÅ#RÖ•/áò ÜùÊ ûÝÖx^ <”=|ydà¥ôðe/~ú3_—1ÆôB=®A<ëAÿÝŸ¹ó27Ü ý€;Âý17P„·mÛ¶}ûöK@Xÿj2Ã.C¢‰û{1žEˆèën­Äsjìuȯ²¯½óE æ†;á¡ÐaG¸?æаßS†¸BMfP ‡$|ß‹ IHBÒY°`Ah`’ôGúõ½ÏÑA ¦5P~•}G(!ÂKxðÌ ;ÂC* Û·o׿ 3,÷áò ô?}cã‹ì; èy4ÈH'ˆ9_bž#@ô˰_å ¨‡æ,€} ×Îëùý€Ç†a¿æ) Ãް_b¡&ãËj`z„CÏŸ’^¿Pê~¥ÔWO/ôÒñôup]Y×ñü3¸9/„~šó"ì×\ê\6„/ }ܘ—{†áKЋ!¼}ûvmfvydà°#üÕf`‡Ä¯x¿¡tþúœ×ë¨ß¡D  2R\N´Ù˜ÍÆ:;©­‹9œ )6S”4ç…dìÜ\p„¡OxðêC@ìòÒ9·¹KFøRt؆P“ØÂ!ñ+èw€à5›ö,÷[ØOeÙÁÊvÈ{ɵû0­n *‡ i\Þþ–oîYÌegwüýï¦eË„27t¾„gjëðÀ€å½µÞõÆ¡Dx8™ öU‰¯\ºýú-•êæ7]Þ†÷Ü%Þõ3†ö6zò²m“ô÷JwWYcÌ÷c¬¾úcîâ ÷Á¯ò°#|^æÜÁ>ú¨±·ðqà*mDXlÀ÷ò<¾8ö•FÕ¾p6wîÜáBxØyxègà9BýY 9÷óÔï;Dtµ«ÇÉoíƒGm˜”ƒ1V4  J$c$—wŸµÒÜÜyq©<쟗´´0UíÛð>Ø@š~p`€ ÀÏç3‡ŸB„áò tŠ1#9Ž»z17"tm.RW¡T7R*bz7}:?q´›CãIuÇ~åT9í’!&…›2‹¿r§Å¨¾H=p@9ZD;`²’© Å+'c˜`Çeÿ~åᇞݱC),Tðüä'ö»¯ãÏTÓ“e´½3¦Œânº]Œà?/¹¶oW(…ŸüÄ®þÄ&ÓB€p€5[ìŸ<0 Ñ»²ý_ $ç¥|ñ—Øœ¾Gÿ‚†‚B„áâÍ}}ä¼û3ݳÅ%Uï¿·Õd4\wý¬sžUVNKÊaÙƒ¼‘xÏ©y¦Or}p îþ–xÝ|.ÁŒ5Åò‰Ãª†yz£ôeKœ$|ûV!= :j蟲¯ü„Œˆb²}"z® °á·¯–Íã’¬ØQ£~ùóþ$Ý1ÇðÀ†âbUUñÿ0ž[>Mذ `@-À}£9êk7¦Ž MË|;³ –ñÏðò0 áÁËÀÐDmÅOæ{c¶«ËÞÞÞ€è± §½½ ZZ:~øàß?ýìÉ„„(Ž#ì*sRˆæú•òºk7½ó¥°ÙcLiÜÍ÷ ͯÉ[?–ávjÒF E§ƒ‰"ŽšÌçNwÏð¾|OU,dÆÕ|²êk("¹íñ¾_ÈÕ¹ÆxwBæd!?™¶7ªëÏлsP'ûp+5ÏàfÍÃÚClÃçôî·,órÐH„‘e· ]Dþë2üPð‚ò¨2ê%é9Ü~g˜OÀ½ÂêÇÃŒÁí7 ]ÝÌ%AC5ļ« ®7ŽF€«©`ëßWï|-ìÊñÈ3™¶DÔ$¬ü³|û×äaf8ÀèÉÂèÉ‚æáÏ>P“––­ÇÄcÌœÍÿæoâ¼o)­ 8Èâcz×hˆúÃGÄ«ó¸d@lYòmcç£]T{*ØwÌX0` @@À‹+ötƒ>‡ÓªÜŸ!ªß­Á‡£·$¹àlî|‚”\Âhn¸vMúõ½˜Ï?ßûç'ßöwº[íúë~±æã'ÒÒt/Øp-Öɘ-øyßC±FÂÓùË(‚=Ò›xÑJ%›¬qûóíüo~å|/››3“Ÿ4‘›0‘•èæ¼½>~Ëå|Aß`‚ ¨$êF=­Ï¸š«UÙ/Ð{žå±é°³’qKãøIø¥û»á¯9ÄÈ1S¬`ˆf®6§a¯*c$ˆxmñª¬—²ê ›VKo­’vÐÆ6¦P7a Dl”`g'lË%^ˆ¨0ö~)á},hNÛÙ‰wDã´XDtó‰Ê1*ŽN*±vDûŸg³Ñ¹à+atãrrTèyí\ŸÊ2Æð·=æ¿@à>€ïè!À>Ê>Ñ÷*ôÍ@osþò'‡}›;_„ùóçû½Ì]2Âhn¸â’@¢McL{]ûÁÛð$ì[í_‚ŒÇ^e¿þyÿQû'›ÕœÆ·†WÔD67[›­“&¿þaÈxƨ'R XŸ€B_ÂŒõÁïyUŽÀ¼ k…:~ßÊ‚¦ÂÆzÿ â¯?ƒg ‚®ãéŸ Ä\"Üsý'¼mÛ6m›þWKxÍ wÂC<CHz×µ§Ð}&Œ±Å‹§äËÔÿÔÔ6n<¸jÕ€o¼ñHBBT„ô)\Vúï§\?]i²†æœ6zlµkú=&]9IÀl#y÷,ûþH÷pÕÙ¬È]T´pŒ1DÃ0c—)Ìéf¶zø ò›gìð“p˜aÅ.ªœeupcúü@û³Ï@ŒÀØ?æcÓÂጴÃôh·¹Î3’`æˆ@cŽÔJ,º©R'(”°GCÒNà’aosoY’‚»öª;ŽS›“¹ì´ò¤ôâïœN»ÿlóò°N&Q„†Fvº–© §Z~LùÛï]µÕnnÉixõuÜ9÷œ¦]NèngG·»~)3Æ8žÞó?ÂGÏ87©Ô´0§U*ÿëÒ𯽎¯9¦¬ýÐUÞÈœÚ\¡>ó;)ãJ!2•@VäŠìïÿ•š»™ªÐ–úÙ®ëd¿þ÷À°×{ñH8RÏTªwš²/Pêg¼é%z ®C©w„p7þy™ ¤Ü\ €^áùóçÏ›7ï+'ìy4ˆ9ß)ÈåGø«ÍÀþ‰_¹ðïÅ@JJü7¾¹pÙµ3ΉÀ™03—ûæ­Â;éöµl7§2U•ØÙÆš[¨%¯ÏöŠØL2c™°ïùÍ;5 ¦ IDAT#LH%ÖÜÈsø%‹Ü½¯¡‹îÙ@w¯§„ P°;ÙÍßq÷1£ç 3ÊÑSÊ»¯©Œ2D»žŽœDýl~ADÞŒI©Ü’çóïÀO™SSÝuˆL"3o·>«|ô†¼É¬0Ymk†ðTþ†›Üó³[îVí£Ÿ¼îÚ‰<‚,ѶnBÁÿˆ;®¹NXHýä ×¾$À6¨q .&3FÑšH¦-çþCYýºk½¥—‡“8§®çþE>µE®8(óA„¯ „ä_#Njq< ü»’šx¦ºðŒÄݾœOOF›Ï-¹–_µYz¦L9TfkS›$4‰ç& Óó¸ÎÊ+Ï8“Âüüç“ (¿Á÷*ú_ëð«ìW¾†„ÁçNOè{1_ áøî±ÇÓ~é3Ü@.Æžå;íwg§=6Îz÷ÝK=çÚ:‚/ˆhÆÄ‘$/ëkim «k€N£HÎ$þÖ†ô‹ÏŸÊ§ÆBÐÅMdí¬²’5¶3c4¹bž“Jc†h.)š  **h}H.Za¸a‰‹Á¸ Ž6±’RZß̨€cgˆé£¹´D7áâbzÝu|D§¦Ïœ¡×]Ç[,ލ²²RZ[Í-lÙ2Þ`x±÷ûgžÁG\°À3|SKOªóÊ@¯ ž3™óµèyÔïZP€_ÂÐs nÎ ¡?v„ýÚºdía¿È!AÖ#zcLÏÏÂ@þõ-Ô•E¢ÿ—À£ÐV©lÙñÇzÓ¦ç„ó9Ì}å„/ÀÜà´ç}ÄîBí,í¯Gz„= ÃŽðà™v„‡x†¾Húµ__×Á!°WuÀÍ9Úé¡ÝêÃoÀ›§Ä0shóñ…ö*ìó—Faˆô€;Âhn¸â’@rÞﻺùÉOìÏ>Ûç0-Z~Ë/^¹¿s"ÛàL„ó3·”é>ÜòÏÏS‡$$! É`É¥ø^Ì/ixðACOÙ9. }Ía€Brµõ‹ÈÜÅ#\„/Ò\ p¾Úî’èÞ•G¸ ¤ºø ¼xs¾cäAm2!ÂCŸðà™;'BhºH.Å÷bââH\\/Z?”Jy( | ? ÐîQ z‡æçŽç•TŸo.Dx.ƒgn¾ráß‹¹`9/„¡`.D¸3½ÊÀß oè¢æ.a(˜ @„‹7÷õwvÎÎ_WЧ½Æõç”sN½½Ž™Cô‡³§¹sâšïkÂAlÁÅtØökn:ìC¨Éôà t@/ŒpHüJï¾Ïž7ø{dzœëõgte]ÇóÏàæ¼úi΋°_sAªsÙ¼€;—2 Ãް×)¡&œðà´?„CâWú<Ç yÊïà ú3ê^Gý%=Ю){½Íïˆf@Ìy!ø5ç…à×Üp'ÿ¼ þö7ÉhD:w®°p¡{PuLÙsD©ndNL$m4™=ŸK4ºýÓÕ@OŸPŸT[»@#ç SsˆÅDñÄ uû—òÒYdçÖØB] ,¾ŠŸ6­—›†°zµ ‡O©­64ZqìdnÚ8Ñss˜BS‘²i·Z×Be‚ñidÂD~â(ÔJåãôÔf“˜ÁB&Ìfæ¡Ùpà€r`²x*Ùvˆ5w‚†c0ŸÒ'|Z@]¬ê´¼ã Z׊¼FåóSòIjzÖ”©Ì:›è¶­´´Š:UfÅ”‘Ü„ñ8:Å­ÜVJ÷UK«h·Q‰düd~v§#8ZXÙIyÿq¥±Åp;…›ž×[eOseRA4wË5=ïPPÙk%c$™>‡zÎØòš‹ŸÎÅ€ÓÆJö+{ŽÒú¦"Xã`üaBDô\Ï[ËÔ}‡ÕÒ*jW0<s'q 'Í܆ rgËNÃC…´±±ÉdòL’É…û¬ÙoØ ¯_/×ÕÑÇwjCÆûî“’À“Cm£„EÆc ^þ9ðÔœŒYãøl«G€¶æC9>“›8…ë¡¡?œäh£§Õ}´¾x ŽÈO΅Ę>t«ªè¸qnÛR7k>£|¹—Õ63bÄŒ18yŸ™ä];ꂲSÊþÃJì$~É$âù¢Â–³ôè—²t•áªdBzR‚QÖÞB_}E¾÷çF+¦õhZz–Ù$fŠ€ñÓ ó¯pS>p@).¦wÞ)zfàŽjK‹zÓM¼ËO=å¼ùJRYËÎÔÐŽnÈÈ$+V^XVF?]#Ýz•ðå^µ¡…*a‘dL>?e*‰âÝþQœ´²H=zT-­a\¦dñKóV£;v¨Õeò¤1äàIZÛÄ`Ö2f"7* ±…î:¤T7¢Â f™2“ŒÎäÂ{×tJÙº_©n¤.†q©|ÞD25®0|pÀðÀ-@–D¥Á:r]½ 2$¾â}…À7]µrmlB9q¢ü£ÕÛ-a¦ù ®ðEð‰%’ë¥6Åhå=¦Xnv*Ùù–âb¢*l+Œ2à”XDDï} uHØi§²  ð„ÚÀ¸‡n š¹§Õ½;•š³ê™F‰R|Úeñê¹\[«ª¢”bQ‘ª¶Ùxô·ÛU¶±S”V˵ TEÂNœPÛl¢…|w7++S ¸X5rs{Oó¹¦vÙ™¬=u )÷À5À“;ؾ­òæíJU'0OKʘ|¯8-—DáøqõOrµÞ!ÖvS‡ƒÉ LžÂy:P#¼frö”:õ RïF98]¤J·‹Ó&ðÉáÀTèn o¾*k ² ˆ au-3Ü)Œ‹CƘ³‘n]¯î:¢¶º€1 =yŠÑÓF«öïWŸü£«þ&ñ¬)*#‘º × £¢{CQì´ø¨òñj¹¨(BXq µ9„+çñ)}k¿ÛèöÕÒç… :A¦T4bu ã(d§ èlRß]å*¬cí@¾˜––1s,<‡j7Ù­lبTt¥ÀñPT¬*wˆ3¯àâÌÞ¨Ø`Ï6yw½v‰ÁÄtW+½++#xs¶05µÎõKS£HêHêêé»ïËÕÌng Q¨h@»ŠK&!8›Ô5ïJ‡ÏÐv "/âéÓ,2‰Ó¸­_/ïß©,ž'ÔuP§ )vL­j®]ÂÍÈñNø†ÖÐÀœN(*b*cÌá5ÿôrp¥ j–N&š<8ôñOc‘¼ö87 ¹ì™½†:Kå÷V+Ó—àøÉÞþ‘m´ð€²~ƒRÙÎ$ QÀ¦V–-$źwh|þùOWV5Š(VyRùäC¥¨…9 y¬käb,43©wö®Z\@·lQJaæ¨Þ÷9¹ÚhÑ>y]?çûœ`r›:hÕùéÿ(w< öuÃ'ò“j‡ŒŒÇÉBIø±89ƒ„ °¿úÙg²gFÙ¶M**Ro¾Y$xì1GÇY‘ ÓÁ\p¼Ÿ ,+SŸxÂél†Šêp0•-­d­ª¸bž[yÇ.õÔ1åìYZ×̧ ©Ó„×OãbÂɶmÒGïJ7-åëºÀî` e²S9V̧& ÕÁÎ4±•dDZ¶SX¸€Ì‡LW›úæ«Rau*ˆÈøbùLgºÖȰP@F‹äðsQÒw‚è…ôO¼çgˆH)õ}þ\/ÔRG›—”T?ñÇUqñ‘¹¹Á±f’/ªûÚaaã$vÈÁR“¸«H™ÃYb7ç…Ô®Ôpdœ“Dmư¦~ö?â¼I$!KÕÏÞq>ö¨ë¡Lš¹ƒÇÕÅìú[„ŸO˜n|ËñüçJ¸ï½^€Ûo·¿õV˜FÆóÓ }.='åí_(ûºà÷šgdcS±´êYiÓfE"ß[Àýýï¦O?µýûߦ˜ÎcöÉàý"xäG†9W«5§ÔÕÿuþõ ékŒŒ±³{¥5_(-aÜw.N…ŽzúÛïÙßÝ@Â-ܬÑZôã xú÷¦ü ´˜€ô?0÷»Úè±FÎq¿zTœœÅ5•(ÿøµ}õF¢ðÖ©œ£]=¹^zf#ýíŸÄ+'ó‘ŒíüDút‹üŸxòô„1Vú¥ôé.%z¼ø‹o‰‘´£Šýöþî—>!1w⤠€f]]/üÝ49ºëÙ»ÿ²ÙAí±äÿ]CtÿPJ[J•mäµ¥ìáGL˦rÝ5ʪ§Û·)M¾5«ÏËå4ÿT”ÐWŸ—¦bÿx1YñªqÄ+ó1:¥ùd‡89àäzÉ.+ÇÉç{ÕÉ7 ±×ÉG8nE$I7ÔwÃÖøÍOM“F àÁuŽWÖ(Ùðê‰<"–lp½¼Q½ævñeBºK¸^~JÖ¹@i¦ò£‡ÅIÙ<í¢;>pýýc)ŒÇ9‚WÂß}·h³±×_w½õV˜Þv´&£s˜1–ÐnzhƒSç ùGçàåŸùw ëŸ+÷*SE qçðÑ$Ã!eÉ{·ÐÆ“ÊÆÊž6ò³ ³ryG½ºéɨ¨Œi:ÞË\íê® ò«ðo1ÍÎÖ »¾p†Ë€Óï¤:ÚèÉ}ÊÚ/”ànú¡°8·×œ¦ŸAæßÎÿýûR㳑#Œ"bs¹Z°NʼÁœ$‘ ®5{Yî<ñ›…ŒHÚPLÿôýÙÈ“÷£ú俞šuý‚ði)ûÉÿ–Íå’c'}NÑ[h—ÌÞ/‚¿ÿÞ4a$(+Ú#¿õ¡òŸ\+æ™4åõÛň7Ügœœ…Ýõʦ·¥Çÿ)]ñcT`•°¿ ~À8cA'=°ÖùÔ‹Òg58íJþá§Ž!`W÷¬‘ž^#¹º`þ8AvÐ’ ®g6ÒŸ?j¸jIáð&ùÝ\Ï's/ÞÃÃ€Õ ÀH€Z`£Ÿö ÀïMdˆ~.Jzu<êyB@úõ½YVìvWW—½«Ëa·»ººÝÝI’ ¹©ý®;ïêrPÊ<|ž‹rÈëÅLf¤»VVÉǵâõ©øR9€ŽRÙœDL \¿|ÖtýU|z<M˜:Ž[r±ý´KǼãVþù' WOàeUxœ·ÂÀ·«ÝÕªßêhzMìR+êáöߛ玑ƒcÅÿOˆc¬h“ZÒfŠÐ›I¿{Ù¸t.—‰Æ0ÌšÄ/¼ÕØ~Ú©™[÷oYˆæ®»WœœŽŠ b,÷ÈÓbñåì1UCHÌàú§aî8aîÓ™yÎ_Æßö ÃôÑDà y ÿ‹?‰íjÑ6Úêðƒ¿IËÿ`Z6Mˆ2qÆR~á"òÅ3’†ðé›JÂ4á†o y©h çFäò~ÁP´Fn)w_ÈbÒù;ž6ÎKÂŒ$>ƒ»÷Gâø,Ü÷¶âåŸc[”ò"Xþ3óâq(ÙIVü`è¢Ç>Süz¸‹²Z„E3820&…[|›¸ô›Bˆìdo<*-ú©yÙ!Õ Àáèiü=??|Ô¥8v}¨:^¿aÖ(^²31–{àQ±þ ZºGõL*ÍoäÆD“LþSÀ€©ìõ•4g6Ÿ›Àή—% T¡U›]1ù‚)ÚíãQ¹Ü/ÿfœ?ž„›ˆ1g,7dfCw­»Êo<*M»Û q£éùâÿþ†×¹À´…ÜCŠ3ÆrL‘dñÝÆØHæl’%<¢Ÿï}è <#z9èþÑ9xùÇ’.N±2W‡²§¹çND_ø€æÌ ã'_ÿì[¯¶tÃm¿2,ÌçŒD¥r·ýÐ4:ŸïiÞ„OíW ÒÛŸ1^3…D˜‰5‘,½Ë8y¯'¼ìdÇ×KzIîÁ=ô[Ãâ\ηv|IÌ—éójlqP…ž(¡onb?ø¼ÿŠ’½L¼þwZfNàÿü‚áÀkJg]‡Ét+ ¾ó„ñºe|Zœ»3óÛÆ£bÉï^6ÎO¬f0Zpü~Ò\¾«Rq+#ùï ¿ÿ‘81 Qü²ï›Ú)R§û†}Þtîá'M ¯ & œu“1c?q÷ã'MsóÐ$€ÉÊ-XaŒ {½]mðÆ£Òò?˜®™Å%„?_¸évñ“?8ŽÌø+À½ù€+r «—°W•½®¢¡ïÅô_ÜÏŸ1w9ƒË>úhÇŸŸ|ÛßénµysÿwÍÇO¤¥%ôðYr O'™·rG^¢ê®ê#%*[HœÃLJ©ã¿É?û"ÅçùŠ·iâ4!n"ñÇ%ÑÅ» !‡œTÙM˜º`Û§òë¯J;«u­L¡ÀaéUzˆoNx;å íD½#S[áDÆXxšÈœrí©‚[¹ïz,ÞçqEàBU7ÂçͰýSç³O;=½„ÈüžûÞaŒˆßL"~óR'ŒH¦Ç‘S‰F ¬# LéVì š%XYÆZ—Ûžë» qäH¢!|ÙwÄ’Ù ½œ£s²½S•˜V¯#þ ›èæ,É¢!Br¶ËˆÆžZ#!¤ ‹¼ò±£kµôKwE4nðàƒ¨¯Šxz8wùÁ nI~×­· “òÈÄiü˜‘$Á Q\Y ­+lÏùV™ìlÇ7Þ”ìÿ–îïM-- ¼ç Œn.w7ý”ú¯gT\È·vîÿo¤0G7QÿSkŸ¢ÓÿÅÅg¹}'ââèÞ*ó ÇTUƒ]Y íßë~Žù熈™&˜a%zþ °Þç‡<ê—°'MMç û'‡åßÿµš~þººäÿxDlØã,1‹ßKäÆZúpÐ̲Ìã­™½ùãÛÆõ GÄb–Éøz.AŸ&£é|úGû£›ð×›–Íã¬|sžŠ#¼d¸úqeþŸ„„b«’ÏVª q†o%ØÐŽ¿Jĉ1=mŠÇè\£«­ƒÊD¢“éK˜h#TÀåq$ÅÔ§åxFD3‡7ÄõÖ”9àTª¸¡]6å­¥÷WˇOÓ–N¦² •£:?ª7šœˆœ€#æGºù1ƈˆÈT@ÄnŠ+k¡Å§1FF"" =dw @$à=@½väyýöëáz·äz‹¾@ǘ¾{ÁÏ3íè©ïù0 KåwKT6|¹f]ǦŒ‘Ck_ó;‰1níq–¿r­n˜£Œ±Þ7óØ:üÅsÎuÇiüñµGI|41ðŒÞ¿1ªsT5OnžZBÏ›šu}Oì=§‡[o¡ÂØ~!Þþ-cÏ-z÷¥9!Ý€Œq=–=úÓüìI¿O¥€-°{gD4ÏÐç=âåUûžrméµG¼¢ìi1ÆTÆ-ãõg³•ë>c,2²·;÷ôNôHîÖ?˜Çܬ(¤G¤u«œ¦‘üõ+ ßYJ4ÏlØž…|Ÿm«hµ‚fëÞÄû4Z¸^§@LLúoK&Fæ“ÖOœ ’¸î—Ò„o™'à˜Q¤¨›®û§|篹ê`U"¤›˜Vc­F} ÷úHaìݵ–1™Ä/7ŸõüôÃÍý}<9xºZ—àÂ3øLÑå(“Nvs¹a°òyÜ=¦˜l¤}÷ayõÊßZ{¦„ž}Ò½G'+›·¥}G¹¬‘85Ý9½›b_ÞYÝBÒd®p³RtšÎú©èiŽQÊtÂ=yêÉ! £—àÎè—¾Ó} †›¿øH.eE‘ 0mF§gÃAÛú¿^…zô)c c» ­‘<ó¼ÙHˆgæÞ p£ûò©WÑërêåy¿†Ð-°œûýˆ8oÞ„””8í/=;¶¼ÿþí÷?þùP\\d Z¹œW‹MØÚIn5’t3p@£¸q®ÒÖn2Ý„IF=f=÷¿mÅÔCîºYFx»ªd™{>@¨ïÓù}%Õ ¾l`7&»M S· „CPýä˜wíÓsfXAŒâ\‰dB„§‚çŠJV~kÇœlg;›Ø²D÷Q{LxB "8X…%‘x[<ü=?Ñg»àdLŽr—ØÎJ‚‰#‚{rÐ.³OkØ·3Üà®VUqPÑÂyáŒ2C}6ÄàäØÞ±áDˆL&S#Hz³Ùø–Zõ½µÊ¡MÒw–Kb°ÒŠcÒÈCŸêk°ãð>m äŠH?NóÞLFÄrPzî ²î0üþw$7#(—”D•O][sö‘b\à9²`I 6Fâ´ÜüŠï¥_?‹ pÚݧ~ŠæŸ ˆˆÓgª/­QŸ\ÂÞ(Á§&s#£ý_ÜrÌx¼•mo`×&û9ìu "¦ae÷eù÷UÖ"ñ‰.öîFùÍvæX!΃^=¿€7á}ßæ>9JÃŒ¬ š5SòãYn7L ‡SmÝã"…®³’Á#ˆ(àšdˆïÙ¢8¨ê¢¾œ/à‚®ŸñöAzç¯ K– ÉQhTf¯‘ɹð|ë‘7Xƒ%‘¸<Ã\P¬VïâóáêÃÎ-ýz?HRRÌìÙãgÏ?gÎø9sòµß™#“Àjµüìç·Ï™3ÞhÏ‚`1â©l]¡\“À¢ÑD „›ðÖöÆ>©)Ž3Zˆ×Õ9HÃyìîbµm €ÌΞT^ý‡TÙsÈÄAŠ;Ï2…˃üqdD¼ÿŠ|²š© Úké§oÊ©“yàFá`-tJ窜ޜ¯½‘··ÑŸÉ LR@•Xu‰ºî]We©~c/8”¶T{Ô5o*ÅuLeÐZ­¾ó¢–IR&p‡·ÝÉ¿ýœt¢Œµwƒ"Cg =±_^û®KCXº˜«>¡|±N9ÛÂ$k­R_þ«”:GˆHrm®go>#V1™bG#Ýð¾\VÅry7Ç “Hz*®yS>]E%TšªÕë¤#»e/šœ©¦Ï½%7³„T2&—ËJE#ƒ®v‚÷Ü/|ºJÙw@mê`²öNVz\yÿe§,Ì]Äñ Ö}$—×1IUbuêÆÕ®’BÕ×?!ú¾ IDAT€“ðÊ+àÝ¿:Û¦²0ʼ‰d§“)qê /ÊcïŒá~®~“êžû…­÷rsv±ÊÓ½ÜD*à¡"€í©f¬ßW"Í?ž¼ü)¹Üˆdræמ•’kŽaLFø4;ÍÜÔ$B„Õ¯Ë'*™B¡»…î^+ÕVÌÀœ±$7ßzZ:\F] Ú;Ø‘­réqEW°$q‹–‹·-áøõÃUÒ¦êiÎK¦Ýh°VŽ­rU´€%Ÿ×3Ö]~-wr·²y³;-Ϩ/ÿU»L ‹%a$ ¯¯WÛìŒQÖVG7 Û­øâû­rpÑ«Åa] ks"¸:ÙéƒÊ?ÿ$9çð6§Û´Dà=÷ o?'9E[lLV «ž>¢¬yÝÁMªÿæBÒ¹¨ïÅ$$D/_>çŽ;÷çDD4š`Ñ5øð{’eœÉšêfX|¹åUÉ:ÉhŠó3 ÒG1^q?‡[¿_ýô¿®¢$Ât4³SåØérë$Çgqo½æ: Å‹øœÎw¸q7¥‘­“ßyƒ&FG‡Zr ²fñsfD´˜àŽEÜÇ﹎ǠY€©S8ÏÅúº¥×?ù× ëÔã…Êšf&p :íÿ¿½ë£8ß3»WuE½XV±%¹÷^qÁØb0„ %$$¿„Bâ„`š .Œ»{ïÝ–-[¶ŠÕÛ©^Ý2óûcïV{»{§“îNÖÉû>~Ÿv¿{ßw¿oövf¶á–”Údº7D>?¢Is3bÎ3+6ÑL8Ñåë`üCªÑ#€!NX¨Ù½˜Ý½ÑuD ;ì@£sÀœ§>»œ¹~Z^F˜u¶âS¥Ä}¿ 3@óÞœNÜÜ8o¢ «&SKú¦ÃÑYÄŠ/\çŒð¨“Ýç2}þ6qùyæ ‰&³z¢*jé—xÁ{ú³Œ<ç0kŒjd=®ÜÇ~·%DˆÆM h~*™ê¶-þVþä˜éê3ËèïWƒfX`mFã'ªúB£RÈÙ÷C£‰Þ¶]¿X3cé=ñàÎ!œ˜DÛÏ¢QÄÔÛU¤‡cÜšŸÑWwÓ˯1ft4¡s¥Ä#¿#“!`À@r´y3 ‰(5tÚPU ªh9’{àDr">‚Ý=D*c×,wŽ…€–j6¯‚`Úóp7‘œÖˆ'=¡Ùö>sduNI;혦À}žó2[ \›s$·2:þ¾˜=âïš;î¹ççΠ6ÀÞ ÔIï2#ÆéžSâ˜qŸ¦÷Nzô,")¥µ-’$˜5K­Ry1èõ`Ö,5·dì<52-Û˜ý¹,aB*9i¡V“32aÏtøØ3š¿|ÍìhÄ,ú“ýúÉüéSÈ13 ÄôºÝô™ZhL„Ã'«ïž©º-À›ÌðéŸëÞûš:|»`6Á1c€Ðèh8c†{aTÕÜ;aòavë>º Sfô%'LS'¤€”bìXñ,”4ÉɹSঃÌÉ:hH$&ÿH{ß$2-H-ŒÏQ¿þ,üb u¦ÕÛ>†ì{1f¦ÛCt_õý?‚»wÒÏ0;0Ä‘3ŸÕ=8–0Ür) ð‹TË·0gk±Ö ‡MÖÌœª—áVŸ5Kšbä8UŒ¬ÙÂ-`]'ô$GNPõª–ݯÒÁc3Éõ[Ù=yˆ%qr&9nºjÚí*$€©—úWã-»˜c§ØªF 2€Ì¾ä´{µ*5èÉ™Óab½i7{­;HíEŒ›¦NÉ–éˆp[¡‰é“Ô3§ãçfÑw€>™Èž©s<˜ M„{aF9r¤øG++‹P{*iê¥~qØô}ì[݈¡¦e“³<Þúõ#{4ˆìÑC~†cÐPlÁo 77@ ðŒªää6=ª•Æv]¦ò¼ë—KÙÏëî½Wí_«‹g ”¶ ÷@  r½~háŸqàúªÂÞð[ض¸?E?µ~^ݹd‰“ ÷èr „ðôÆØïu¯á|úbàƒù?ÁÁËuŽa«“$¡×‡EÎéÄ.ŠŽ&…ÁüaŽ_ÀÍɰ¬œÇÌ-m`‚¢°Ó f¨‚]w—A °Ù‘J ´‚€‘·‡° Çñ¨,XÀ/´Åà–=Š%ƒTÙŸ\á_9¼ù‚øùÒdaïÎÿ'ö ùx_ Ï<£™7Ï-$íŽñ Ø{.B(',-ª(XHëÿ³¹H7,,» u{òra*hÄa+hÄ– îXAS1 õBF ã³q~„Z"9^KVE‡ÖógÀó 9iããÀõ„OsSjÉ3`ÏXM¬'x.™/9a÷„2ðŸýˉ óóÝB9ì=¦”¾" [UA#ÎðÍ-hÄVv™Pt=VÏ ÀÅ`‚€LD(³†•óg¾Ðñ÷ÅHƒƒgð,‹ÈIŠôåV0¾‚FœaÙ`YÜ‚†²Ë´» ÷Hq[Œa²ðšŸrƒqÀO{¸`i%üŒñEÓ þå„ \°”PÄ +'2ì+"¹[Áp¨ q†” SA#ΰTHVîV0¾‚v̰YÈôŒ¤åäL"ËB–ÿHUº”\¤îú8ÃÈEœáÊEºáˆ+¨27ØI¿@¸\va»‚ƒgèd9ŰbøæÊ)†ÃÒ`R(ç(P @Aw@@ï‹ÍüÊ…ŠA6Kæšá5>¹ˆ3Ü= ª·áðɵɠŒÏ|¡íñYð¹kƒlpð íÂ-h8|rÁ3t9Åpº‡áðÉ…‰áV@ëÓV¸^€Ÿ¬ñ²SºÂà»"bðÓ²…r²1mʵiXVîV0 \÷3 \§4â ËÊÝ †”ë@A;fX,¼î§A¸œÏ)?ìå×òJó.e†’Ç‘ù"®•uâß°¬1ik±uKòÁ!)hÄ–• SA#ΰ¬1e—‘º mA;`X¹ŸÚZóâyß¹û!Ó"ð E1Â\ûgàƒùáŸþåD ʉ ËÊùÙœnc8|8ÃYЈ3,úŠ²Ëø7¾‚bX,¼Žó\¦dþü=ꢵ²] _7´sÁ¢GAÊv‹B"'bðÓ÷ñ/é†ÃWЈ3Ü™8Ã@ÙeºF İY(÷Ÿ)†o¾\Äîd9ŰbX¬@ ÷ù3‡`AßA¸[Ž=ó¿ÂY`ÿ ¾‚¥óÈR9ÿ ,q†»GAÃá6>¹ˆ3ÜÅ ªÏ|¡õxæµ´Ë÷M:SN1¬¾¹rŠaŰÊõ ¾Ðî¼ß5hCWS ‡¡{Ÿ\ð ]AN1Be48Ú}<v:Viw£ÓäÚd V Ë¢{Ÿ\ð ]!?WÐ[İYt<óÕ£ ¼´+8x_ÁŠa>8x†îa8pt{ÃÊ.ã?8x†›žánå}1mËEºá®_Ј3ˆ\Ä¡\¤ޏ‚*àà>à‹2Õ•Ï…v¾œbX1|såÊai°)Z¯oÄr­êM—‹8ÃÝ£ ŠápŸ\ÄîâUŽg¾Ðz<“æË EåáWµÉÀKë*ê›yd”Òúÿܽ ˇ¤ gXV.L8à l8òÁa*h +×ëûBëóõç‰aÒôq ùµ~z|ŒŸç­ñ þcüˉ ûyÞš9ƒ¯mhÃá+hÄ–•ódA#Î0Pv™®Ñ1¬@^Ï#dËu |•¡] Ë"$r¢…¾žÛÖí ‡¯ gX6XÝÞ°²Ëø—»‰†ÈÂ=ß(»Î×X[vê ]cmÑlƒÿ¹á¸ÈÍ ø’“ëð\DD– IA#ΰ¬\˜ q†e)»ŒÔUh ÚÃÊμÆg\âDýÆÙRWSWTÖÌý)ŠæZyùE×4¾—_DœáÎ,hÄ}EÙeü_A1¬@m_¯_eïúE'-ý>~k¢¨% -|a»:YN1¬¾¹rŠaŰ4XmŒ[1M½¿dÝË¿|áàÖߟ¶ÒãI (h/TŒ±ìc HÕ™æ«éÚ=uoÿ÷â†×FøíúdL+ûg Æ’‰iŒQaÕÁ=Û÷•-hªj¡).6=¦ÿøÞwÍí5~P\J€rh84ra2>¹ˆ3Ü= ª·áðɵɠŒÏ|AåkEÉ¡ÖôéÉÑCfzmÌ–/OYý~õ/V&¨a{ÏE¶+û²Á’…ÌÎs_yå‡ãµ…µöF+íd"HuåÚŪS‡Jï\8hÁƒ9#Évú §áÉÏÐÉrÁ3t9Åpº‡áðÉ…‰áV€ÏãÙ®ÕçRïdÒ³{& k¤.1vÀóÿþ·W¿€6ľüáüÿÎýòÈÛoÕOüHêÇ%UkÐ;Ì…¡Bh¡(דּ²àüÊ©·ÿßœ·>ý÷«ä'‹—,^±¹1þ¶·ïJFZKløæËßýmC-­é5`ÄŒ;ç=øðnë«%yfÀ¡$„à–A÷Bi›€Þ>… Ò^•”Aºi"Y a†ý“„Ü0ð±´™è· ÝÆpø q†eådÙ@{ q†E ²†oâ.£ÀÜo4À‚g_rw­óà’Q©©cÞ¾+^‡›üãdÁÉJÆ#ª¡"ï‡ÆW¹y1ð´<ƒ³¾¢úĦFûîãs`HÏ,Sm½aãÖž]þº³¹c|ì,ÛDLùß÷Ûön^¶h\ìæ%¼ÿö/½þñ¾< O5_¯‹…Àà´ÓµÛjçåZšWÑÔ ©ê­ÑŒžžö~²§tëDkù˜P1H3,ÍOåD1²1ð1ŠáP4â ‡P.Ò wñ¨ÀZ;\g±Üà—TëŒ1¿þÍ8­ùß÷¹Ó–ÒsÛ¿|céΫÌ3@HÀˆ¶æÿýç¯9u±…AR§Ö%›Y¦é›“…õÖ¬Vii„œˆ²5äoyï‰?}[Ó`cìyY£{N_8¨áCGMyò—ï._ú‡áÉàÈê}´äãך93’hˆœ»¶ïû“+s­ 4¢jŽ/Þ³òzm9À !±ïœ;¼ü{ð…p¬åc„ò['bÀ·Éà•aA°¬¥–•ó5ÁÒ½ wfA#ΰÿB(»Œ/¹´c†ÈÂ}½>7žE¹ªÊ«/ŸoNéMBqâKkÜmTŸ´\ݱãø¨×Õ\n ¢‰R{ÆÃ!‚ 0F,CU•];¹3O“½H›:í¶xµ1#sä ¿{©'[uýô [QUµÍ¦)¸|zãfC]Î-ªºt9Ïk£I3¡Ã7šj1ÆA“ûϾ#gõ–“7¯OˆNšôæÓŽúæœúw¬…gË›òvç~T]³=N­¡¨š e竜v³ù¶é½g.Êêã1ãžµ}š5ƒ%ïÖã!dXž®/'Û@¥r¾Ì„Ö°¯¡aÙê~†eå|ÅYЈ3 ÂVЈ3Ü™-°c†ÈÂ}<ã„vÔ”^Þ±z# e{ ˜rÑ,ë,Û»sÃÕ‹'c\ fÝsÐ4“ ÐÝí ‚Ðè“§áoÎ^+šP3í¶xRŸ1õ'ÇV¶PPE¦éÕ&{á¥ãß~QîLOªGȵjÕ*“ž¤’·„cGu­fjKòÏœØÚú“)ÑÚèø÷ *…š‡+/Ýh.=p=B,Iê¢u ýRGHŸõ£>S‡› гQüÖI»Š¢é{Ñ,6–0Hs"Ìž(FøYJ%έ`Ò<܆…о  ,h71Ü™8ÃYЈ3,T mA;fX,Ä÷S«M:Uб`ë__5iŠûSS­†ˆ]øìãѤ¤$„ºGÎàá½c×6ÒM-\Ô]ΰ±Ù¬k“O©.Õ² ,2W%Ü1sjMMu5ë„„Ú[36-gtZHœ^æâîrSMèÿdZüm£J¨Ê+m©³±´Fmê=´çäié#úD'ß{Q ¾Ý´‹Áÿnß9r·¦áÀq Ê.ã7¸+¾5!>žéŽ}àO?<è¾N„_Îõ; çº#áW¤ÝŒ1„ÑÖgëZ葤Ö,ü „¥Zòmަôé÷?úË¿=݇§e%i$4q~äxšŒÄ1‰cxkô–k³ð#z>‡”ÁW°pIø ËÊ)†ƒ1ˆ\Ä¡\¤ޏ‚*àà¾^_¸ˆ?ˆOf¥ñÒ`Œ(ëUK *™¡ÉQiq| Ç`+]¸ìR¡qÜÔ ƒP­G²Àåd—w€A68x†›k8$U ·W.â ‡P.Ò wñ¨À|>¿1 Êj)<ôÈí¯V5i~úNö¨‘qµTË¥7_øÏ±£•Ó^ìýÀ¤$/7ºÞþ™‹‹²gâaVÖ¬ýÐ^ç (P  BÑÖûb$g_c^n9m­½~áè†ï×}»qïõ&݃oþ÷Á‰2µÆ3Φš‚=›7|ñùʋČ—ÿðø£÷öÑ‘<¡9~a«ºÔ/ô?HÕ&û7r¹0Ÿ\ÄîU ‡ÛpøäÚdP†k¾ ¾^_zá,Ÿ;ì¹t‡»ÒT†¨ÆkÏìß½çÈñ3WKkaÒÀŸ=¿pþÜ)}’£5˜©¯,Ë;úè‘c—‹+ }&<ÿøÔ)S'HKБ2rœŠHŽCbTâò{—ó süÀœ#L5¥Šd/Åž+b… ÒýJt-oà†Ei^‰+mfXVNº/A»™áåÂTЈ3¬ì2þåBRÐŽV ‹ÖùFÙÌJá» ¤FgLÉÈ Í'ê“Ós&MŸž£Q“³H¥ÖšcÓ³ÅçŒìÑ«ï¡Lzï{8Dr<Œã¢!‹„†ùCÚ ¹?ý´ ig²÷ÁøgðoXˆ 3Fþ ËËâ4 ”]¦kì2 dá>È®.õP„kÝ" ™Ž†XOrzÓ¡p­¬ÿ†[ 両œ´ßÔý Ë·]P9’H7,+¦‚FœaYcÊ.#uÚ‚vÀ°ŸÀ-ŽÖ¼p#ã>Hãø…¢˜Ö\Ã6ø`>Fø§9C †E_ñ%çssº‘á´;îÌ‚FœaÑW”]Æ¿áð4à dáï1e^qÊË/"Öpø q†;³ g(»L×hV ù;õD£iárÙ…í ž¡“åÊá›+§V KƒHâëõƒg Æ’‰iÅph ‡O.â w‚*†Ãm8|rm2(Ç3_hû¼bð¹kƒlpð íÂ-h8|rÁ3t9Åpº‡áðÉ…‰áV@»¯“éÞ-©{ìiŠá2t…_¢®l¸{4â +E»gÂqǪâk¬Ý rm2È+†eÑ= ‡O.x†®Ÿˆ+è-bX,:žùêÑÞÚ<ƒ¯`Å0¹ˆ3ÜÅ ªÏ|¡õx&Í– ‹Êïj“–ÖUÔ7òÈ2('¤õÿ¹{– IA#ΰ¬\˜ q†AØ q†eƒÃTÐVžßè î¼päž&M·_ë§wÀÇøyÞÏà?Æ¿œÈ°Ÿç­ù—1øÚöˆ6¾‚FœaY9_1A4â e—é-0à dáõ<â@†±ü›¤«Bò®Ù`Y„éÕ ·¦áð4â ËË¢ÛVvÿr7ѰY¸çe×ùkËN´k¬-šmð?!×¹9_rRcž‹ˆhòÁ!)hÄ–• SA#ΰ¬1e—‘º mA;`X9Âù‚û}žÂ”a¹×Å"ÏË3E-O~9W-_ÒÿužÁW°È°¬¿Ü·Ê¿\¤_A#ΰ¬œ,Oð8Ã@Ùe_¹‰-0à dùÜy-õî}—Ë.lWpð ,§V ß\9ŰbX¬@ eܪ@ º”÷Å(†Ã+q†»GAÃá6>¹6”ñ™/(ï‹ –¡{Ÿ\ð ]AN1B†îa8|rab¸ ¼/¦í`Åpº‡áðÉÏÐäÃ!dPŽdÃ}}c›)ãøao‡ÏR¶9ô­íðQާм_ãýˆ6ìG WЈ3,+¦‚Fœa ì2hP´c†ÈÂë~j.q~nYžäŠþ „æc„ú—1('2,+çgsºáð4â wfA#ΰè+Ê.ãßpø ˆa²ðšoä2åëþyÙµ²] >X.XøM)CåD ²r"Y¹H7¾‚FœáÎ,hÄÊ.Ó5Z` †ÈB¹ÿL1|óå"Îp'Ë)†ÃÒ`Ro½õö€Ëöž-ä–ó)-ôÃà+X4,+矡“åBh¸ñÊ·‡œZFmŽSAQpÉúŽ>yJ퓎üD\AÛ4œ÷Ñ3òšíQ©=âôa¸«e¸cr—>°í+ØH$ÆøÜº.e¸T9žùBëH–ÕBEÃ[,7¢ýÿAÈÀI,d~EVQu–óŸWÛ=ô©Õ§OZüûçÀ8ŠU•ì¬qø—ãÓp­ºtÅÙVòvcÄØ‹ÞþÝOœ+p²HDH7ZSô¥rÍÁ}7-W*(¯€6åD_AÛdè4îº*:©çÉË(÷Ìu«½´žR_rA¶ÀˆÛe<-ÐVöëb\bïhA1pÕ!ª|÷°Dé¦I=wÍ]†ÿL;ñ†G¦j‡Ä‘‚€À ŠY`+EÕjrÀ@X™ËìgˆAs4ñªp]»hØ—\{ +…ªíoˆrx¢ùàvÕ¦-9l-«¼±÷x˽îLSÕ±¢ÊĤ¤!²rÞ líÑ•1ýÔ£˜¥¹‡¶®YýÍå*'Pé¢t€Y!Ä"¨ŽB1£Æ+—K_¬I›„áÖ•„&NOªH(Æ“:}tjÿѽt—ήú`{ösñ%·iÙ§'­JeÔ‘Ð×QþÚ‚¶É ¼aU”1¾×ð cÔ•Nï¯Ê¾ç™ Ké«‹.;ºwÛŽ½gJl)I±cŒBÒ¥ŠGíÿeéb»Œˆ7ÖѵÃ4Â@_rþ C Š‚ñ½É,3ܶ„> ç̆„˰Œ~WjlX,:žÉ%Yª,M–¦¬A9eh „#†r”^³8I½Ž¤lÍÚØ|ƒÉR î(lì¡ÑÆÐGõ^¨JS‘ ÜñcÚÞ|àów—îfgÜsïüÙSçôŒÒ!±@•”™£×A$’!,m‡a› H(lÈè×?`†q•Êߕʟ}whÁ»ÿ¹gþÜÌh]ö«v$8x†Àƒ… ÍýF ÇÓÔ9½02´ÊaÄ”žÙµuõªï.“÷-Z¸`öø˜(IŒZ£).«WbH wŒ¡]ðÏ@BÐ_ ÏHºS"øa€0÷#GaŒhlÔÀ*¼† ¾Y-°ÃrÙ$º=dŽgXîAjüB÷H™µØèÌÑk¿ÿçk2🩠Ï@7×ÙÔ&F£#ÀŒ­±â‡UÿÝ{ƒHMÐ×—\­± IcŒ#5­ÜF½J«!…ì>å Š Î&B°0‰$b³ç?úð¢Y³5D둆÷IAÈO ˆòÃ#ä²6Ô6ÙX„IµÎd6 QËF3,¡Uñ'~U*•Z£“»t˜«HIIIž21ͬ¥¢Ž6ÇÇÇc„œ¶¦†fE3€ µzƒÑh4èÔ¼eoi±ZíNŠE€T©Ññ±&m«‡¶Êáe¸Í Y†@Z ¬a¨ÖhÔœŸ cÚ¥GTŒ>±ï ‰ú¿ŸÅêT²B†±Y)›qÒA@¨T:³.Î@’„§Áˆw¬vä¢@Œ6Û@\Œ|~ÚkXÊȘƒ[E¡‘#Ô@£jºõ+,kmt¶8ŠÁBRMêLºX³ZŒáˆhfX,T@2ÉËÍØŠâ„™…ÒŽK 3Jõ€ÿ`©Ï —eÈÿòÕ}6ièÐ)©Q˜e ýÓor×¹}Ç/–éç,¼mpxz×¶%»Ç÷”–•ƒ*•>.þGÿzï·}ÚvepÚàŒáqZ©a(øŽÿüðË]Ö†cŸ¾þÔ_WÖ8‰´A“ŸzáùGš“¬&Z™<ŸcsµÖ‡ôÔx³Zé&455eggžzê)À /¼ðïÿÛik:òÕŸßüïš‹Åu„)eôÌÿÉcß1ÿzÞÞ5Ÿùõ†çj­8¾× …/ýù­''FiÕ"r_['.gû *,ZØ® ËÈAH„,I› ¤Î4àž‡‡8ѺÖþ'÷™7F'ù ®©Þþé¹k ޶4š¸ìäñOO|ï‘ÌÌϯ¶x—±3›6£Ãgá^„[Nü㤔3|–#ˆ!€PÐ ƒ‘4T!,+ýöï§Vl/9_á°ëô©}S&,ûÆ‹}úcXvy‡ ûg¶†Ù°_èàûb4¦ñwŸýÚÝ™¬ËêB¡ï5`䢜7N6¸2|ôÛc¦¤F J¯6¦i LØ»Æ1,-©O¯sÈ$¡J;kÙO\ùlÍÑ ‡|ÝÜÚ³±,UYt}å¿ßðƺ3çÏûÃÜ„“{÷ýsí Ùàë§®üiþ¯K\l€ ÑÑÑ㸸¸Í›7#„þýï;ªsO¯zyþO=·xs~EMÞáoîJª\õÏ7ßÙ[É}¥ì‡ßüß?Öºú-\wüjMÕõ>~éä›söíåÂzWàÕíAjÓ§ ñÚÝ’G~íD@¶Õ¥oÝ¿é•9æŒ]š÷J陇—Nf½¼rஞÊwÈ'“Póæ«^ÿ%i»ÎŒüQ·}OË4V—¾5ö›—W×%½<{ÃõW ·ÞõËÛì?¼¼rà%U†m›B‚Ž‚ž¡´p)–@´PqõÔW}mÎ̹Óïxà«“µÍNFD-%‘ʇ!Wmñùÿ½òÜOúù»Ë.ŽAÇ–þê`^~µƒ‘— .r•õ/µÁ­òìRâšö]>ÿÃõ¦À ûZåj¨®?ÜœýÚ]CÒRS3ÆŒЃl®?Vlk±9.„qê€þþëŸC¢Tð2,¢RU[v¬¿úÀâ¿Ü><+Ö ‹ï9ðÞGçÜ>6é䊭\ÀúÏõš5oÎCsúöˆÕb{úçÅœúb}Sem›ÉñÐÞ ûA{[ FÌõógþõʯ¨aY9é*söð~w?×røõJí+ X±gUuSÝäAÓ§õ—¬IMôØ”E°[Žo®´TÈ&µ„^ãb@ê0õ¬Þ2;]0†;aq€(Ø?‰÷rŒ1nq´¬Ø³ÊN»îuïØŒA ºøþéc·ö›½+­öæ  ËtØp{#EËÛÔ P®†p÷¹ñ,wœl¾0ÆüZ¡ÓrððÁ;/Øæ=´àvÍ¥¥ÿÜ×Üè2øyÞö Ÿ}Æ ¨ÓÅŸyg\;÷ßúÛ¾ÜuNa·FÇ×Ú1E!%€±ïç­ù—ãÛ%·ÖÜküCÓ3@á‰ã;ö»pkŒ‡Áßt¹H€(—³¶šuYM:ܘ»uï¹ýû÷ÕW­¡XÞÌÁ/>~ç•W~÷î¿¶ŸºÓ¿¯‰„À¯aQ†…Ūn¡ßh~zæðäè(J¥ÖRûŒKNïS›¿› Ø‘_74'mtNªA«&RgJ>óéºü´£A*$+×® ÓÍ ˆ¦XÆQråÄŽ5K­ Ë3ŽÊC›—¿ý›_¼üÚ;_n>+eðnìáM?Ú¸b¨ò&—0c £tƒ§ÏiŠ *‹6[ :*¾÷ ÏÏ‹[ûÁ«ñlϪŠâ:Ú566iˆ1NC¨tšäÌä{Àå5›® ^E˜Hìħ™>tN5ùÊ0fqY>óÉ{Ž'Ÿ²ÿq1U\ Xìï1†²-PQ†öYPW#,Ä,Î=æÚ¿‰r ™Ù°±ÌªŠb'bg&¥õ1˜I@š¢²2’ïW¬¢kÇ wt÷o˜7ÓÞß@i€¬œ,‚7¬@^Ï#d––»ËÏa9_TtÙB'?ôÐ=÷M6æ¾ìrR² ˆª>uú⩳7@Q A€jš]MN¯Z:kr·ȽTT ÊÛcĬ_|ñ1}å±ÕŸ-ûáà¹*[ëh,¶g”JC`д²û¶ëÀ¶ŽTGOžso¶å?²7¿IÊÐfÓ"ÂYwåàñ‹G.V© ±¦^eË7ûO~¹ôËuû«š›à(ßï¹û Õk\Í•§÷oýôã¥K>[ÛÈ`è×°ŸiwÂ5 ;8F«&Ý *}©e)÷/l™‹MÒ«â´ž37ÐÆ BT9@._û•H®ô¡ kV.Yü¯¥k6í.³¹i°õt®¥²Æ! ¶•ŸZ±lWiI(??Í÷iäÎÏÁë7ì8t©¼¼ôú‘¯–Vèdô¹Éˆª.¬o¹|åjñÉM{‹Z8D7V9¬&¤ô?sjI±Õ—aYðm¬,:¶cýgŸüï_ïýù««-ü¥¤ŒILŸûȺ3ë¾9R^×B‰®ÓŒãHĪH„•*À270²‹‚99W3sö0½|‰k×VzÙ6ܦá²\v×Zú@5ÈLƒß¯ ·  '‚" ¬ÅÌwßP_~êúbµv+“[àîmÉ>{0Àü` låì²ÏØê̲èÔi´~ M{·yƒHŽÆø:Í RI2Š»Z„0’ª4C_ÇXœÉ Üe|=›±r7ѰYx=Äÿ9L.­\gA­KŠ‹O‰3ÂÒÒr—I‘ `,dh½¹9ê›ê­-õ•—Ží¨¤X„˜â ‡^.¸Ö <Ó€,e—W¯úvß©ÜF H}”ÎÔóî'_}öá‰å‡6¯_³áø¥¬h¿"úl»¶ÇàùwLJU=Ç«y¶áwßûȳOÌ›<Õ\üï‡ÿÙpº–¢Qà†…Ð0QEæ5S rF”¹UÚT. UKÖ9ÙŠu3@@5åšT@h}íä­çùn):²nÝ®“g.í_÷Ýšµ›v•Z ‚åîß°vW~q`WSCÃÅÜF€­fëç+÷•ÖCHÖ4»ÎÔzòƒÖ¿#ß®Ÿ¸`áì)ý/ŸÜvÎFÓ-cª×ˆ¡iú:k*0€WCéÑæ:Yloh¹zpÍž*aÅ}åGÀ‰”¥àô¡}[w½”›»þïï.»ÒØB·þB© ñ)#üxŠñ«¯7TZ(ïŽL¶Z¥ƒ°£&÷A„B¨@ªÒ!%i#|é8Ú´…9_õ‡›¿ ùc¿ÉˆÇ¶³6»ûŒ]ávß^–˜¨yý÷:PFªÁ• aµà+yìáB (ºÎ–Ü@ÅEèÒ9f÷Vzå fûQLac „óN³ µ­n°5?˜ÅÕUøÚuLÂVCÿ÷ ºª“$QR .K."°®_<Ž0lÝ¿Zó`¶ZE`PÁ°vn»eÊ*u6„­W‰~Rd!û“" íßÇeòãÍÈo`›»L›-0à dá5>ã'Ûï ö†â+gΜ»RPÞbw’ “‡Ž¾sXý3WÊšYî‡F–Ô¦ß1c·÷)¿vqÕ‡ï¶8(ÊqdåâuçÖ;_-Ì:ÈDë•W O]iq¹\Ë2,M¥ Ý'-ÖVq£äZã=wŒæ'—üôˆÜ?^Ö&ÚZMSuM”½Ppª#IJ¬‹¦Y–eY–a«'M9*o_u¦¬™[ˆ¢(ŠfXäã÷¢õ^fÄ:ÉÛ37òö^²kâ’Ǽÿç×4‡ÖX1wÍŸýüÓS³ã‰ÂM§–eXlNN2é®§~öÂ/žž“H]ùË’S-L¦t>ÝKN°6Ù¨™núlï…š&Ã"Êa­È?VS^—5 ˜•¾°âtQ•b†r4×^Øûy|Î,µ>®Í—_ Úyù›wWœcçÿdÁäñYȲ,EÑ,CíøÏ_ä]¯jqÚ›Š®\<ñŪ–e±öJãp2,Ã2£Ö³ˆm‚„9%>»ÿ„´a Få.–›ÈååXš¡êm\E€*}ÂÀì™ÓnÏÿÈ÷Ű,k­¼üùûn:p↵¹<ÿÄÚÿôÙ¡*Qy[GéÑõÛ÷ž¬ŽÿÒÏ_žhPcÄR4Í0 §KÓ ©Ñ?óÛ…ÎKOåæ—7QB†…=2ÔÚcõ5g›ê(ÄØUÅU뀩‰wëµ=ÄMc[»ú3çÑ+xÂãÚ…?&j¸*)ÀàÖMf(ÔPÞÿ•óL²Ñ€4 ŽÄvGb;m.¶â"½m#õŸ#,CãRµú™ŸéþðGýKOiFõÄG78^}Ûuò:¦Y™ÓRÄn_EååÑNÖ{E€e³<ƬۊXc-k¡±‹4\ ¤ìèÜAú“¿;ó›Å EªöÈÔBbW]E¾µ‰b)«½ ´f+0£ÇU*“°uI›œŸ([PáW”÷Å(ðºÿŒ;0r]{UÉž·ž|ôÛ¢ñóŸüåÏ~”“ž˜9tAÆD×7fª—™ §³Æu+0Æ;ë¹;– «•Í»désýjï3]Ú¨ŽbT„ +Õ9C&HJªniνQoPé4¶å½öÔ«Cþé3=8}ˆ wßc€€; a áehÞ罸>NÓ•.ûYW’þ²~âjG¯ýãcÚjuTW•èlZáFG IINìÚòΗ'>{j wñ®Íf+¯­³±X­òºÒšƒ{“!$HMïc¤÷:RÙ{£,Å@FÅ §/4/èÝ?c°ÖtQ]÷õê²òñ,6Šni°ÔVV&DéRz yitüovíÄÌí¼ é*zeØûªâž½ïzpؽ¿üý¤ßž:¤²äo\¶õH ;åçó¸€ûŸ»ý…lÛÚÄÆ/œK”]<ðú¯6MùëžØÔÖ{„}É9)vó’Ã1/>£ Õf³ÙíDUEAÝ`Ðöˆ"IWSUeéû³§Î½± ¼<©±ÚÁШÞR[QUßÐÝ÷Ð@‚Tß3²Ï÷g ·|³#Yc‡6³U!d›?œ%&gŠOT”[XßÛHèê[šëª›m-¨o‚f7I Ë!*·„kçöäWÛÕ©ÃzYëjZXä²ÔQ VO’‚nuꢩ±K–¯>ž9£7áaX4óñÍ[¿8qywŽ6=sðXªáÔ§{WéÕ1÷O¸¯g|Oq“ ˆ«ŸØÎ§í™Ú>F›£Ñ8m_–àç3@ŒÊ½É´ òŠ©÷Ohþ˜G$Âa#g-±y½Kœ aµàò2¬*`%ت¥ÅlRO¢Î‚T ¢‰)s5:=xì7®ÇOžø\«1Š7ùìÎø^¸ÚH”:q$‚!à²àÊJ¬¯¥ÏžAmêò ØT  kkPe%hnAÒ&ÑPÆœ§_c޳+f‘¢£˜ôÆE3ÿhõÛO}7X“Ñ»¼üàŠ£ëõꘟÌxÔ¬o=ž ó#­‘´ÊTÄ Ý)¤ "ÃÂ&!%"$†eå:`X<0ÆØý@„¢m-öêrÑB„%ÿüWwgëâf¯^ò樾šÖœBHhþ0·¢Þ)ŒG,¢(–aùÇwímrßù¬‰Î~õß]jvq«89[ÍÖÙ3Gˆj5ð¡÷Î\«dB1NÆQçÄm˜~ÿ›ßm:Y‹:µnÍ+3&¾YÜÄ®=ÿúoÿú÷?.¿Æ3s V¼ÿé cŸvôÃÿ÷êÂ< ·üû'ÌŽÓž+R­zߣïç7Hó#”³×ízá™»<ÍBB=é¶Ø9/®^we¬+¿Z¢òqS6„ê¨Ä‡,õÍ<áù=;Ÿ1àp“Ë—½>[cݎůŒïßÓ¨Óš{ÍXøë¯¶_ä3Œ:½á“oÒj©ýÆýò?»­v—”V*gml¼'^o ;¸/ 9ªb…´ Õ¸gÓ²Á9Ù¯7Ùí!ÔtýâþŒX—:â¯Çªyæµ{÷Í'=×âV_Z#„Ð?ž¢”ºmÒøÒ_çÛ(a~JJÖ¼±ñžA&éßÖþ’2äóû_ͯwÉ$!´ï‘¦©±–ácZþ÷5m¹Áü6£á¶Wé⯭¦ZØf6ÎyÇu¨€1¼7´¡§Ö€ð_=õÞK,X QŸ[É:Y±‡µw¶üåç-onsí­s/t4±ÿÈnHT‹D´Óîhn¤ÅM¢|·ë³û›§ÿ‡æ.û½íϯØr­n¹‚‚ÿýô›Û³þ«{[ó·Þc–?²øj¾ÿrˆ¶+¸+0t¾œ)Ü?Àžã?TãFÖ¹zSþãw÷Áül„ÆžÉã÷SjòÛ®q|¶åQ=Nj@SbF‚I……aÌ2ÌÙKý2³ dkrZìI9y'¿-kF)樤䳞係‘cùïþYqÃüÆŸ>yxÁÔÖŸ+SBrœ „!ÄÀÆÐ׋ŽÖï<ÖkîììþÙF–¶·”ov½cVs[a¯°“úx}ª¾•c@â¤ñ£‡è§í•m6³cŒ˜Æõ-É=õí3?brBu”Ñ”`Ä‚YQ0bíkÞ]zéXóÏ¿û›_ÜÏ}®øtÑË?X\¼é{}UÁ•ô£Þøüó 1‰$H£Ùå1íT³º -!¬‘ÇOIIAžËZCô„E¿]=ïEŠf¡ÒEM&“0¦-x}ä¯rÏQkL1ñ: )ËŒ%³QñüÊ sd÷T»Ï„!Ä”µ€ôh ÆØÏI­Vk$Z[Ƶ&ÁDBî’N¡ZTZΨl½úÇÖ)>ß}RHš¸Ô83j`IÒ$« ?5âj ¼ý‰g_y칩њÖö/{úæØØX­W799ùΗnŸðÄD'¤šÔ™£L$É9É G7ÍìÚq‚Y¾Âqb?l¥zý'D¬É+É‹7]EpP1^ë„Á‰f4üƒ¨¿'G!ÇȺ0©#nÌŒ*àÍÀ¤wÕ‰F"9‘èÉ5 œú¢ ý|µaZ?"^%Üd~ôQÀàÙnÞmy3>RÌ}[ ja a’ÚÒ³ço&Üùk†b0‚P¥&uf}¼Wõ%åVÙO³”eð¬ï´AýbUò/¶ðµPÀ}Àˆ­Ì;òÍŠ/¾ßUÔkÊüžx('§@§>ûò‚¦o¶>zÈ×{Ø=y×Ðþ‰r®­()//«jvÌzáDµÏËYYYÞY'¢bõÑ ¾âµs’¡õ&ô6·Î³iNÊyíX‹ëY½÷훨&0ÆÎškeG¾9fþéðä3ÛÎ÷98k@o3—ù&á½™Œ£¸©á¤…Í•è‚.µFŸ’Ù'E†ÁWÀey•5µÚ´¾Mä êàÖu#ßj=êß·ÑÝ›‘þ¤úÉJeŒSãä‚¥r†4rÑKº;,˜%€^¡ öê£Ô­Ì®&T°‡ÚPƒŸÌ„‰†VÆ«¹Î4‚™ÄÐ~dŽÞó é·¹z{ˆ¨¶|æºz±`· sèb‚œ6€Þ‡Ðr >ÐXÀœ=As€'û@ÀklU-ЍJ˜=ó¾jµ9Qíõ¬aNü\ ‚ÿAïÊrab¸ y~#$õÆø#ƯûûןíÝ’$!À,å´Ö×Yf=ú«>Ñ&]@™…„&.§_âÆý¶mª¨«©´±¦‰?z\cjÝÓ¬ÎNQéã WUѵKgOî=tª°œžöøssçßÙ¯W’‹`ï‚P¥3Ç œÔûë½ç/ž=æp:Z-8*}ܼbH‚Õb5Æ©Ññ q‚YDŽP›“SãJò›¶ûe£ÍérØ-Õ7Lýïê?tlŒà·¯c‡4ĸšëÊ.œ:²cÏÑ•ö±ò¾þ÷MÉœ"\þábWI +\"b` 6Ÿ)sKœåßAƒçÀÀR ù:Si?uÕn£Ì*Ÿ ~–s ¯ [H¨‡QZ@ÙpEk§ˆ%uÆD{Ý^ç‡[h¯AyÙë5`Û_ùzh©F͘!al,Üvôõ¥†gG>; a€hUàÍUÁ7øPï2¡d^îÖäx†i®ZGΛrâkóIȨÕ’QæøžFgNºû±Ä(ô'¾=yêÐ&'Ô1‰ ½Ž¿cz|œc®'§êã£5¢¶C‚4%gÍ?ò´‰i±F­÷¯ñuFÃÄî¹ÖˆJª¬NšÔ{ö>nú$¡**.5£uXÆ{ãzôí3BÍT;aA…ÅI£>ƒGœ0oÌð~З\;Š1ÆSrÖ´1sÇOŸ‘kPAa~’ûšÝo” o9hЉ7ÅÄ·™áŽnƒek¬*É?ºoÏÚµ§ç=ñb¯¸X­gh®1§$›?+.ãÛÆÅúdÊ9ª òóŽ¼Øs{lQ´Ü8£ý†albX¿Ï¾‡"†¶7”Ÿ:vpÍÊÝÆ´a£F{õf‘0ˆÈ<Ë3Q'ºUcŒfYï X.¾†.籕uXm"ú !ö‚̺pIºz•UM,è3XýøS€»‰ èqQBg­r9¼vöNeö8IDATœþäÀˆ•{1`Œ‘ Ÿ>Ê\)`í ŒO# V=r;„0 ˆŽ‡Ññî&Á² Ö{ÂRÀ »<Ø ôÙÓw™Î1¬@{ÀýÍ:«K‹¯­:”ôÂÔ¼¯r3Fe™RbÔ¤&*Ê`Š3ë¼GK^³+þ»<Âà;•~:Y®û– figKC]q~î‰Ãû¼ØdúÎâ·úTÏU©í6Œ1ëhv’Úº‚ '*nVgšvßÔÁDˆ ·ÑéÆÈio®­(¹|úðÆKÙÌûŸ~rö”‘ÉZ2@†à *b ZØ#»™-ÛèÜBlêIθOóì=*€1cC—ϱ{v±gòXC:9mžöÞ P£ku‚aOækÃ+>qmÝÇ4#˜3Bu÷<õ¬1Tv™›dX¹ÃÚ 0CÜ£nj/ܸºçˆá±ñGŸÝ?øíYCûôŽÑO*ùi$¸³¯„0×\°¯²ñr«Z…eã¸%Ò>²!p9(8ÛÏw”„ @Ò¤ºa~•´£ç§ ®¦êóGwlÙy$¿^5tâ´‡™—¡Wc±LKá™*cªÍÒbމONŠ7zÞ3Ãþ[ ë²U_Ú÷Æoöä÷1푟üh`Z’„á+h›†‹]Ndµ SÔ“ „3€]¡íÜØ€ô1P¯z•²Ë„ì7°†•ã™/È·êðv48x†N–»5 #É]êÁË(sž¬Ó2Ì&nÙ‚*†»“a @­ó\§€ÿ<ÉåÊ/žnˆ°[Á/ôÃà+XÔA“•óÏÐÉrg¸{T1nÃá“‹8Ã]¼ ÊñÌZgÒa¹QyøUm2ðÁÒºŠú&BY†å„´þ?woòÁ!)hÄ–• SA#Î0[A#ΰlp˜ ÚÃÊ|£/tð}1¾èøÌûb–¥1øñ¿ím8|8òr¾b‚,hÄÊ.Ó5Z` †È¢ƒï‹ñU†v1,‹È‰úy†w÷6¾‚FœaÙ`Yt{ÃÊ.ã_î&V ¯ùYà£/À­â°Ü34ß!³hzÁ¿œhîk Þ¦œÈ°¯HÇûÝÞp¨ q†” SA#ΰTHVîV0¾‚v̰YÈù¥åäL"ËB–ÿHUº”\¤îú8ÃÈEœáÊEºáˆ+¨ÊõúŠá›/q†;YN1¬–+B™™U @Ýâ÷ÅÁÝD3¿²D¡b Æ’¹fÅph ‡O.â w‚*†Ãm8|rm2(ã3_h{||îÚÅ @vJW|w@D ~Z¶PN6¦M¹6 ËÊÝ †”ë~†”ë´‚FœaY¹[Áp€r(hÇ +…ûù ²ë„ËùœòÃ^~-ÿ§4ïRf®ŠÂH_„µ²Nü–5&mm"¶niX68$8òra*hÄ–5¦ì2RW¡-h +w¤ù‚×ýÔ\âüܲ<ÉýÌÇÿô/'bPNdXVÎÏætÃá+hÄîÌ‚FœaÑW”]Æ¿áð4à dáuœç2åëþyÙµ²] >X.XøM)CåD ~ú>þå"Ýpø q†;³ g(»L×hV åþ3ÅðÍ—‹8Ã,§V KƒHá>Æ!"Þ•pÓå"Îp÷(¨b8܆Ã'q†»xA•ã™/´ϼ–vù¾IgÊ)†Ã7WN1¬B¹ÄÚ—à»íbè rŠá2tÃá“ ž¡+È)†CÈ ŒÆG»gÂÎBǪ"íntš\› ²ÁŠaYtÃá“ ž¡+ä'â z‹V ‹€Žg¾z47‚vÏà+X1ÌÏÐ= ŽnoXÙeüÏpÓ3Üí¡’.ÂrR“Ÿ\NýdV–ÿHUº”\$n c~oÄž¯Œ„½º˜aŸr]*ÃÈEœáÊEºáˆ+¨ò™‚]ø\hçËE²á·x ÀíY’Øh»˜á2to9ŰbX¬@ e«@ ºþ(Ô†dEÇIEND®B`‚openacs-5.7.0/packages/acs-core-docs/www/how-do-I.html0000644000175000017500000003057511501005400022264 0ustar frankiefrankie How Do I?

    How Do I?

    How do I edit the front page of a new site through a web interface?

    The easiest way is to install the Edit-This-Page package.

    1. Log in to the web site as an administrator.

    2. Click on Admin > Install Software > Install from OpenACS Repository / Install new application

    3. Choose Edit This Page and install

    4. Follow the instructions within Edit This Page (the link will only work after Edit This Page is installed).

    How do I let anybody who registers post to a weblog?

    Go to /admin/permissions and grant Create to Registered Users

    How do I replace the front page of a new site with the front page of an application on that site

    Suppose you install a new site and install Weblogger, and you want all visitors to see weblogger automatically.

    1. On the front page, click the Admin button.

    2. On the administration page, click Parameters link.

    3. Change the parameter IndexRedirectUrl to be the URI of the desired application. For a default weblogger installation, this would be weblogger/. Note the trailing slash.

    How do I put custom functionality on front page of a new site?

    Every page within an OpenACS site is part of a subsite More information). The home page of the entire site is the front page is a special, default instance of a subsite, served from /var/lib/aolserver/$OPENACS_SERVICE_NAME/www. If an index page is not found there, the default index page for all subsites is used. To customize the code on the front page, copy the default index page from the Subsite package to the Main site and edit it:

    1. cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-subsite/www/index* /var/lib/aolserver/$OPENACS_SERVICE_NAME/www
    2. Edit the new index.adp to change the text; you shouldn't need to edit index.tcl unless you are adding new functionality.

    How do I change the site-wide style?

    Almost all pages on an OpenACS site use ACS Templating, and so their appearance is driven by a layer of different files. Let's examine how this works:

    • A templated page uses an ADP/TCL pair. The first line in the ADP file is usually:

      <master>

      If it appears exactly like this, without any arguments, the template processer uses default-master for that subsite. For pages in /var/lib/aolserver/$OPENACS_SERVICE_NAME/www, this is /var/lib/aolserver/$OPENACS_SERVICE_NAME/www/default-master.adp and the associated .tcl file.

    • The default-master is itself a normal ADP page. It draws the subsite navigation elements and invokes site-master (/var/lib/aolserver/$OPENACS_SERVICE_NAME/www/site-master.adp and .tcl)

    • The site-master draws site-wide navigation elements and invokes blank-master (/var/lib/aolserver/$OPENACS_SERVICE_NAME/www/blank-master.adp and .tcl).

    • Blank-master does HTML housekeeping and provides a framework for special sitewide navigation "meta" elements such as Translator widgets and Admin widgets.

    Figure 4.1. Site Templates

    Site Templates

    How do I diagnose a permissions problem?

    • Steps to Reproduce. The events package does not allow users to register for new events.

      1. Go to the http://yourserver.net/events as a visitor (ie, log out and, if necessary, clear cookies). This in on a 4.6.3 site with events version 0.1d3.

      2. Select an available event

      3. A link such as Registration: Deadline is 03/15/2004 10:00am. » Login or sign up to register for this event. is visible. Click on "Login or sign up"

      4. Complete a new registration. Afterwards, you should be redirected back to the same page.

      Actual Results: The page says "You do not have permission to register for this event."

      Expected results: A link or form to sign up for the event is shown.

    • Finding the problem. We start with the page that has the error. In the URL it's http://myserver.net/events/event-info.tcl, so open the file /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/events/www/event-info.tcl. It contains this line:

      set can_register_p [events::security::can_register_for_event_p -event_id $event_id]

      We need to know what that procedure does, so go to /api-doc, paste events::security::can_register_for_event_p into the ACS Tcl API Search box, and click Feeling Lucky. The next pages shows the proc, and we click "show source" to see more information. The body of the proc is simply

      return [permission::permission_p -party_id $user_id -object_id $event_id -privilege write]

      This means that a given user must have the write privilige on the event in order to register. Let's assume that the priviliges inherit, so that if a user has the write privilige on the whole package, they will have the write privilege on the event.

    • Setting Permissions. A permission has three parts: the privilige, the object of the privilige, and the subject being granted the privilige. In this case the privilige is "write," the object is the Events package, and the subject is all Registered Users.

      1. To grant permissions on a package, start at the site map. Find the event package and click "Set permissions".

      2. Click "Grant Permission"

      3. Grant the write permission to Registered Users.

        Figure 4.2. Granting Permissions

        Granting Permissions

      OpenACS 5.0 offers a prettier version at /admin/applications.

      Figure 4.3. Granting Permissions in 5.0

      Granting Permissions in 5.0

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/variables.html0000644000175000017500000000665411501005400022652 0ustar frankiefrankie Variables

    Variables

    Date and Time Variables

    ($Id: variables.html,v 1.28 2010/12/11 23:36:32 ryang Exp $)

    By joel@aufrecht.org

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Starting with OpenACS 5.0 and the introduction of acs-lang, we recommend retrieving date/time information from the database in ANSI format and then using lc_time_fmt to format it for display.

    Example 11.1. Getting datetime from the database ANSI-style

    db_multirow -extend { mydate_pretty } {
        select to_char(mydate, 'YYYY-MM-DD HH24:MI:SS') as mydate_ansi,
              ...
        ...
    } {
        set mydate_ansi [lc_time_system_to_conn $mydate_ansi]
        set mydate_pretty [lc_time_fmt $mydate_ansi "%x %X"]
    }
    

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/permissions-design.html0000644000175000017500000005402611501005400024520 0ustar frankiefrankie Permissions Design

    Permissions Design

    By John Prevost and Rafael H. Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Essentials

    Introduction

    The goal of the Permissions system is to provide generic means to both programmers and site administrators to designate operations (methods) as requiring permissions, and then to check, grant, or revoke permissions via a consistent interface. For example, we might decide that the transaction that bans a user from a sub-site is an operation a site administrator is able to assign to a particular user. Or perhaps an application developer might decide that viewing a certain set of pages within the application is an operation to be individually granted or revoked from a user. It's expected that the Permissions system will be seeing a lot of use - almost every page will make at least one permissions API call, and some will make several.

    For programmers, the Permissions API provides a means to work with access control in a consistent manner. If a programmer's OpenACS package defines new methods for itself, the Permissions API must provide simple calls to determine whether the current user is authorized to perform the given method. In addition, using the Permissions API, queries should easily select only those package objects on which a user has certain permissions.

    For site administrators and other authorized users, the Permissions UI provides a means to aggregate the primitive operations (methods) made available by the programmer into logical privileges (like read, write, and admin) that can be granted and revoked.

    Historical Considerations

    In earlier versions of the OpenACS, permissions and access control was handled on a module-by-module basis, often even on a page-by-page basis. For example, a typical module might allow any registered user to access its pages read-only, but only allow members of a certain group to make changes. The way this group was determined also varied greatly between modules. Some modules used "roles", while others did not. Other modules did all access control based simply on coded rules regarding who can act on a given database row based on the information in that row.

    Problems resulting from this piecemeal approach to permissions and access control were many, the two major ones being inconsistency, and repeated/redundant code. Thus the drive in OpenACS 4 to provide a unified, consistent permissions system that both programmers and administrators can readily use.

    Competitive Analysis

    None available as of 10/2000.

    Design Tradeoffs

    The core of the permissions data model is quite simple. Unfortunately, the hierarchical nature of default permissions entails quite a number of tree queries which could slow the system down. Since every page will have at least one permissions check, a number of views and auxiliary tables (de-normalizations of the data model) have been created to speed up access queries. As a consequence, speed of updates are decreased and requirements for additional storage space increase.

    Data Model Discussion

    As described in section V., the core of the permissions data model is simple, though a number of views and auxiliary tables exist to ensure adequate performance. The core model consists of five tables:

    acs_methods

    The set of all defined methods.

    acs_privileges

    The set of all defined privileges.

    acs_privilege_method_rules

    A relation describing the set of methods directly associated with each privilege.

    acs_privilege_hierarchy

    A relation describing which privileges directly "contain" other privileges.

    acs_permissions

    A table with one (party, object, privilege) row for every privilege directly granted on any object in the system - this is a denormalization of acs_privilege_method_rules and acs_privilege_hierarchy

    There are also a number of views to make it easier to ask specific questions about permissions. For example, a number of the above tables describe "direct" or explicit permissions. Inheritance and default values can, however, introduce permissions which are not directly specified. (For example, read access on a forum allows read access on all the messages in the forum.)

    The following views provide flattened versions of inherited information:

    acs_privilege_method_map

    Map of privileges to the methods they contain either directly or because of another privilege which is included (at any depth).

    acs_object_grantee_priv_map

    Relation on (object, party, privilege) for privileges from acs_privileges) granted directly on the object, or on the context of the object (at any depth).

    acs_object_party_privilege_map

    Relation on (object, party, privilege) for privileges directly from acs_object_grantee_priv_map or also because a party is a member of a group (at any depth).

    acs_object_party_method_map

    Relation with every (object, party, method) tuple implied by the above trees.

    In general, only acs_object_party_method_map should be used for queries from other modules. The other views are intermediate steps in building that query.

    The data model also includes two simple PL/SQL procedures (acs_permission.grant_permission and acs_permission.revoke_permission) for granting and revoking a specific privilege for a specific user on a specific object.

    To sum up, the PL/SQL procedures are meant to be used to grant or revoke permissions. The five base tables represent the basic data model of the system, with a set of views provided to convert them into a format suitable for joining to answer specific questions. The exact means by which this transformation takes place should not be depended on, since they may change for efficiency reasons.

    The transformations done create a set of default permissions, in which:

    • parties get the privileges of any groups they are directly or indirectly a member of

    • privileges get associated with the methods of any other privileges they have taken methods from (at any level) (see acs_privilege_hierarchy)

    • objects get access control from direct grants, or inherit permissions from their context (unless the "don't inherit" flag is set)

    Legal Transactions

    There are three essential areas in which all transactions in the permissions system fall:

    • Modification of methods and privileges

    • Modification of permissions

    • Queries on permissions

    "Modification of methods and privileges." This refers to actions that happen mainly at package installation time - a package will create a number of methods for its own use, then associate them with the system's standard privileges, or new privileges which the package has created. The association step might also happen later, if the site-wide administrator chooses to change permissions policy.

    These steps involve directly manipulating the acs_methods, acs_privileges, and acs_privilege_method_rules tables. A web page for manipulating these features should be limited to site-wide administrators.

    "Modification of permissions" - involves fairly common operations. Users are typically able to administer permissions for objects they themselves create. The two basic operations here are "grant" and "revoke". Granting permissions is done via acs_permissions.grant_permission, and revocation via acs_permissions.revoke_permission. These directly manipulate the acs_permissions table.

    Web pages for making these changes are available to all users, so they should not be in an admin area. In order to grant and revoke permissions on an object, the user must have the administer_privileges method permission on that object.

    "Queries on permissions" - by far the most common operation is querying the permissions database. Several kinds of questions are commonly asked: First, and most commonly, "Can this party perform this method on this object?" Two Tcl functions are provided to answer this - one which returns a boolean, the other of which results in an error page. These tcl functions directly access the acs_object_party_method_map.

    The second most commonly asked question occurs when a list of objects is being displayed, often in order to provide appropriate UI functionality: "For this party, what methods are available on these objects?" Here, the SQL query needs to filter based on whether the party/user can perform some operation on the object. This is done via a join or sub-select against acs_object_party_method_map, or by calling the Tcl functions for appropriate methods.

    Finally, when administering the permissions for an object, a web page needs to know all permissions directly granted on that object. This is done by querying against acs_permissions.

    API

    The API to the permissions system consists of a few well-known tables, plus a pair of PL/SQL procedures and a pair of Tcl functions.

    Tables

    acs_methods, acs_privileges, and acs_privilege_method_rules manage the set of permissions in the system. At installation time, a package will add to these three tables to introduce new permissions into the system.

    The main table for queries is acs_object_party_method_map, which contains (object, party, method) triples for all allowed operations in the system.

    Also of interest for queries is acs_permissions, which lists directly granted privileges. Neither acs_object_party_method_map (which is a view) nor acs_permissions should be updated directly.

    PL/SQL Procedures

    acs_permissions.grant_permission introduces new permissions for an object. It should be given an (object, party, privilege) triple, and will always succeed. If the permission is already in the system, no change occurs. The interface for this procedure is:

    procedure grant_permission (
      object_id    acs_permissions.object_id%TYPE,
      grantee_id   acs_permissions.grantee_id%TYPE,
      privilege    acs_permissions.privilege%TYPE
    );
    

    acs_permissions.revoke_permission removes a permission entry given a triple. It always succeeds--if a permission does not exist, nothing changes. The interface for this procedure is:

    procedure revoke_permission (
      object_id    acs_permissions.object_id%TYPE,
      grantee_id   acs_permissions.grantee_id%TYPE,
      privilege    acs_permissions.privilege%TYPE
    );
    

    These procedures are defined in permissions-create.sql

    Tcl Procedures

    Two tcl procedures provide a simple call for the query, "Can this user perform this method on this object?" One returns true or false, the other presents an error page.

    To receive a true or false value, Tcl code should call:

    ad_permission_p $object_id $object_type $method -user_id $user_id
    

    If the user_id argument is left out, then the currently logged in user is checked. To create an error page, Tcl code should call:

    ad_require_permission $object_id $object_type $method
    

    These procedures are defined in acs-permissions-procs.tcl.

    User Interface

    All users of the permissions system are the same at the user-interface level. If you have the administer_privileges method permission on an object, then you may edit privileges for that object with the UI.

    The UI currently provides a list of all granted permissions on the object. If the user wishes to revoke privileges, she may select a set of grants, choose revoke, confirm their deletion, and be returned to the same page after those privileges have been revoked.

    Granting permissions currently (as of 10/2000) works by providing a list of all possible permissions and a list of all parties in the system. (For large sites, some future search mechanism will be necessary.) After choosing privileges to grant, the user is returned to the "edit privileges for one object" screen.

    If it makes sense, the system will also display a checkbox which the user may select to toggle whether permissions are inherited from the object's context.

    There are a number of potential future enhancements for the permissions UI, outlined below.

    Configuration/Parameters

    There are no configuration options for the permissions system.

    Future Improvements/Areas of Likely Change

    The most important future changes to the Permissions system are likely to be in the UI:

    • There should be a page displaying a list of all objects for which the current user is allowed to administer privileges.

    • Users should be able to view the permissions on any object, or perhaps on objects which they have the "read_permissions" method. This would allow them to see what grants are affecting their objects through inheritance.

    Authors

    System creator

    Rafael H. Schloming

    System owner

    Rafael H. Schloming

    Documentation author

    John Prevost

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation9/11/2000John Prevost
    0.2Edited for ACS 4 Beta release10/04/2000Kai Wu
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-comments.html0000644000175000017500000000724411501005400024364 0ustar frankiefrankie Adding Comments

    Adding Comments

    You can track comments for any ACS Object. Here we'll track comments for notes. On the note-edit.tcl/adp pair, which is used to display individual notes, we want to put a link to add comments at the bottom of the screen. If there are any comments, we want to show them.

    First, we need to generate a url for adding comments. In note-edit.tcl:

     set comment_add_url "[general_comments_package_url]comment-add?[export_vars {
      { object_id $note_id } 
      { object_name $title } 
      { return_url "[ad_conn url]?[ad_conn query]"} 
     }]"
     

    This calls a global, public tcl function that the general_comments package registered, to get its url. You then embed in that url the id of the note and its title, and set the return_url to the current url so that the user can return after adding a comment.

    We need to create html that shows any existing comments. We do this with another general_comments function:

    set comments_html [general_comments_get_comments
         -print_content_p 1 $note_id]

    First, we pass in an optional parameter that that says to actually show the contents of the comments, instead of just the fact that there are comments. Then you pass the note id, which is also the acs_object id.

    We put our two new variables in the note-edit.adp page.

    <a href="@comment_add_url@">Add a comment</a>
     @comments_html@
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n-convert.html0000644000175000017500000005750511501005400023140 0ustar frankiefrankie How to Internationalize a Package

    How to Internationalize a Package

    Tip

    For multilingual websites we recommend using the UTF8 charset. In order for AOLserver to use utf8 you need to set the config parameters OutputCharset and URLCharset to utf-8 in your AOLserver config file (use the etc/config.tcl template file). This is the default for OpenACS 5.1 and later. For sites running on Oracle you need to make sure that AOLserver is running with the NLS_LANG environment variable set to .UTF8. You should set this variable in the nsd-oracle run script (use the acs-core-docs/www/files/nds-oracle.txt template file).

    1. Replace all text with temporary message tags. From/acs-admin/apm/, select a package and then click on Internationalization, then Convert ADP, Tcl, and SQL files to using the message catalog.. This pass only changes the adp files; it does not affect catalog files or the catalog in the database.

      You will now be walked through all of the selected adp pages. The UI shows you the intended changes and lets you edit or cancel them key by key.

    2. Replace the temporary message tags in ADP files. From the same Convert ADP ... page in /acs-admin/apm as in the last step, repeat the process but deselect Find human language text ... and select Replace <# ... #> tags ... and click OK. This step replaces all of the temporary tags with "short" message lookups, inserts the message keys into the database message catalog, and then writes that catalog out to an xml file.

    3. Replace human-readable text in TCL files with temporary tags. Examine all of the tcl files in the packages for human-readable text and replace it with temporary tags. The temporary tags in TCL are slightly different from those in ADP. If the first character in the temporary tag is an underscore (_), then the message keys will be auto-generated from the original message text. Here is an unmodified tcl file:

      set title "Messages for $a(name) in $b(label)"
      set context [list [list . "SimPlay"] \
                        [list [export_vars -base case-admin { case_id }] \ 
                          "Administer $a(name)"] \
                        "Messages for $a(name)"]
      

      ... and here is the same file after temporary message tags have been manually added:

      set title <#admin_title Messages for %a.name% in %b.label%#>
      set context [list [list . <#_ SimPlay#>] \
                        [list [export_vars -base case-admin { case_id }] \
                          <#_ Administer %a.name%#>] \
                        <#_ Messages for %a.name%#>]
      

      Note that the message key case_admin_page_title was manually selected, because an autogenerated key for this text, with its substitute variables, would have been very confusing

    4. Replace the temporary message tags in TCL files. Repeat step 2 for tcl files. Here is the example TCL file after conversion:

      set title [_ simulation.admin_title]
      set context [list [list . [_ simulation.SimPlay]] \
                        [list [export_vars -base case-admin { case_id }] \
                          [_ simulation.lt_Administer_name_gt]] \
                        [_ simulation.lt_Messages_for_role_pre]]
      
    5. Internationalize SQL Code. If there is any user-visible TCL code in the .sql or .xql files, internationalize that the same way as for the TCL files.

    6. Internationalize Package Parameters.  See Multilingual APM Parameters

    7. Internationalize Date and Time queries. 

      1. Find datetime in .xql files. Use command line tools to find suspect SQL code:

        grep -r "to_char.*H" *
        grep -r "to_date.*H" *
        
      2. In SQL statements, replace the format string with the ANSI standard format, YYYY-MM-DD HH24:MI:SS and change the field name to *_ansi so that it cannot be confused with previous, improperly formatting fields. For example,

        to_char(timestamp,'MM/DD/YYYY HH:MI:SS') as foo_date_pretty

        becomes

        to_char(timestamp,'YYYY-MM-DD HH24:MI:SS') as foo_date_ansi
      3. In TCL files where the date fields are used, convert the datetime from local server timezone, which is how it's stored in the database, to the user's timezone for display. Do this with the localizing function lc_time_system_to_conn:

        set foo_date_ansi [lc_time_system_to_conn $foo_date_ansi]

        When a datetime will be written to the database, first convert it from the user's local time to the server's timezone with lc_time_conn_to_system.

      4. When a datetime field will be displayed, format it using the localizing function lc_time_fmt. lc_time_fmt takes two parameters, datetime and format code. Several format codes are usable for localization; they are placeholders that format dates with the appropriate codes for the user's locale. These codes are: %x, %X, %q, %Q, and %c.

        set foo_date_pretty [lc_time_fmt $foo_date_ansi "%x %X"]

        Use the _pretty version in your ADP page.

        • %c: Long date and time (Mon November 18, 2002 12:00 AM)

        • %x: Short date (11/18/02)

        • %X: Time (12:00 AM)

        • %q: Long date without weekday (November 18, 2002)

        • %Q: Long date with weekday (Monday November 18, 2002)

        The "q" format strings are OpenACS additions; the rest follow unix standards (see man strftime).

    8. Internationalize Numbers.  To internationalize numbers, use lc_numeric $value, which formats the number using the appropriate decimal point and thousand separator for the locale.

    9. Internationalizing Forms. When coding forms, remember to use message keys for each piece of text that is user-visible, including form option labels and button labels.

    10. Checking the Consistency of Catalog Files.  This section describes how to check that the set of keys used in message lookups in tcl, adp, and info files and the set of keys in the catalog file are identical. The scripts below assume that message lookups in adp and info files are on the format \#package_key.message_key\#, and that message lookups in tcl files are always is done with one of the valid lookups described above. The script further assumes that you have perl installed and in your path. Run the script like this: acs-lang/bin/check-catalog.sh package_key

      where package_key is the key of the package that you want to test. If you don't provide the package_key argument then all packages with catalog files will be checked. The script will run its checks primarily on en_US xml catalog files.

    Avoiding common i18n mistakes

    • Replace complicated keys with longer, simpler keys. When writing in one language, it is possible to create clever code to make correct text. In English, for example, you can put an if command at the end of a word which adds "s" if a count is anything but 1. This pluralizes nouns correctly based on the data. However, it is confusing to read and, when internationalized, may result in message keys that are both confusing and impossible to set correctly in some languages. While internationalizing, watch out that the automate converter does not create such keys. Also, refactor compound text as you encounter it.

      The automated system can easily get confused by tags within message texts, so that it tries to create two or three message keys for one long string with a tag in the middle. In these cases, uncheck those keys during the conversion and then edit the files directly. For example, this code:

        <p class="form-help-text"><b>Invitations</b> are sent,
                when this wizard is completed and casting begins.</p>

      has a bold tag which confuses the converter into thinking there are two message keys for the text beginning "Invitations ..." where there should be one:

      Instead, we cancel those keys, edit the file manually, and put in a single temporary message tag:

        <p class="form-help-text"> <#Invitations_are_sent <b>Invitations</b> are sent, 
      when this wizard is completed and casting begins.#>
        </p>

      Complex if statements may produce convoluted message keys that are very hard to localize. Rewrite these if statements. For example:

      Select which case <if @simulation.casting_type@ eq "open">and
      role</if> to join, or create a new case for yourself.  If you do not
      select a case <if @simulation.casting_type@ eq "open">and role</if>
      to join, you will be automatically assigned to a case <if
      @simulation.casting_type@ eq "open">and role</if> when the
      simulation begins.

      ... can be rewritten:

      <if @simulation.casting_type@ eq "open">
      
      Select which case and role to join, or create a new case for
      yourself.  If you do not select a case and role to join, you will
      be automatically assigned to a case and role when the simulation
      begins.
      
      </if>
      <else>
      
      Select which case to join, or create a new case for
      yourself.  If you do not select a case to join, you will
      be automatically assigned to a case when the simulation
      begins.
      
      </else>

      Another example, where bugs are concatenated with a number:

      <if @components.view_bugs_url@ not nil>
        <a href="@components.view_bugs_url@" title="View the @pretty_names.bugs@ for this component">
        </if>
        @components.num_bugs@ 
        <if @components.num_bugs@ eq 1>
          @pretty_names.bug@
        </if>
        <else>
          @pretty_names.bugs@
        </else>
        <if @components.view_bugs_url@ not nil>
        </a>
        </if>
      
      <if @components.view_bugs_url@ not nil>
      <a href="@components.view_bugs_url@" title="#bug-tracker.View_the_bug_fo_component#">
      </if>
      @components.num_bugs@ 
      <if @components.num_bugs@ eq 1>
      @pretty_names.bug@
      </if>
      <else>
      @pretty_names.bugs@
      </else>
      <if @components.view_bugs_url@ not nil>
      </a>
      </if>
      

      It would probably be better to do this as something like:

      <if @components.view_bugs_url@ not nil>
        <if @components.num_bugs@ eq 1>
          <a href="@components.view_bugs_url@" title="#bug-tracker.View_the_bug_fo_component#">#bug-tracker.one_bug#</a>
        </if><else>
          <a href="@components.view_bugs_url@" title="#bug-tracker.View_the_bug_fo_component#">#bug-tracker.N_bugs#</a>
        </else>
      </if>
    • Don't combine keys in display text. Converting a phrase from one language to another is usually more complicated than simply replacing each word with an equivalent. When several keys are concatenated, the resulting word order will not be correct for every language. Different languages may use expressions or idioms that don't match the phrase key-for-key. Create complete, distinct keys instead of building text from several keys. For example:

      Original code:

      multirow append links "New [bug_tracker::conn Bug]" 

      Problematic conversion:

      multirow append links "[_ bug-tracker.New] [bug_tracker::conn Bug]"

      Better conversion:

      set bug_label [bug_tracker::conn Bug]
      multirow append links "[_ bug-tracker.New_Bug]" "${url_prefix}bug-add"

      ... and include the variable in the key: "New %bug_label%". This gives translators more control over the phrase.

      In this example of bad i18n, full name is created by concatenating first and last name (admittedly this is pervasive in the toolkit):

      <a href="@past_version.maintainer_url@" title="#bug-tracker.Email# @past_version.maintainer_email@">
      @past_version.maintainer_first_names@ @past_version.maintainer_last_name@</a>
    • Avoid unnecessary duplicate keys. When phrases are exactly the same in several places, use a single key.

      For common words such as Yes and No, you can use a library of keys at acs-kernel. For example, instead of using myfirstpackage.Yes, you can use acs-kernel.Yes. You can also use the Message Key Search facility to find duplicates. Be careful, however, building up sentences from keys because grammar and other elements may not be consistent across different locales.

      Additional discussion: Re: Bug 961 ("Control Panel" displayed instead of "Administer"), Translation server upgraded, and Localization questions.

    • Don't internationalize internal code words. Many packages use code words or key words, such as "open" and "closed", which will never be shown to the user. They may match key values in the database, or be used in a switch or if statement. Don't change these.

      For example, the original code is

      workflow::case::add_log_data \ 	    
             -entry_id $entry_id \ 	    
             -key "resolution" \ 	    
             -value [db_string select_resolution_code {}]

      This is incorrectly internationalized to

        workflow::case::add_log_data \ 	    
             -entry_id $entry_id \
             -key "[_ bug-tracker.resolution]" \
             -value [db_string select_resolution_code {}]

      But resolution is a keyword in a table and in the code, so this breaks the code. It should not have been internationalized at all. Here's another example of text that should not have been internationalized:

      {show_patch_status "open"}

      It is broken if changed to

      {show_patch_status "[_ bug-tracker.open]"}
    • Fix automatic truncated message keys. The automatic converter may create unique but crytic message keys. Watch out for these and replace them with more descriptive keys. For example:

      <msg key="You">You can filter by this %component_name% by viisting %filter_url_string%</msg>
      <msg key="You_1">You do not have permission to map this patch to a bug. Only the submitter of the patch 
      and users with write permission on this Bug Tracker project (package instance) may do so.</msg>
      <msg key="You_2">You do not have permission to edit this patch. Only the submitter of the patch 
      and users with write permission on the Bug Tracker project (package instance) may do so.</msg>

      These would be more useful if they were, "you_can_filter", "you_do_not_have_permission_to_map_this_patch", and "you_do_not_have_permission_to_edit_this_patch". Don't worry about exactly matching the english text, because that might change; instead try to capture the meaning of the phrase. Ask yourself, if I was a translator and didn't know how this application worked, would this key and text make translation easy for me?

      Sometimes the automatic converter creates keys that don't semantically match their text. Fix these:

      <msg key="Fix">for version</msg>
      <msg key="Fix_1">for</msg>
      <msg key="Fix_2">for Bugs</msg>

      Another example: Bug-tracker component maintainer" was converted to "[_ bug-tracker.Bug-tracker]". Instead, it should be bug_tracker_component_maintainer.

    • Translations in Avoid "clever" message reuse. Translations may need to differ depending on the context in which the message appears.

    • Avoid plurals. Different languages create plurals differently. Try to avoid keys which will change based on the value of a number. OpenACS does not currently support internationalization of plurals. If you use two different keys, a plural and a singular form, your application will not localize properly for locales which use different rules or have more than two forms of plurals.

    • Quoting in the message catalog for tcl. Watch out for quoting and escaping when editing text that is also code. For example, the original string

      set title "Patch \"$patch_summary\" is nice."

      breaks if the message text retains all of the escaping that was in the tcl command:

      <msg>Patch \"$patch_summary\" is nice.</msg>

      When it becomes a key, it should be:

      <msg>Patch "$patch_summary" is nice.</msg>

      Also, some keys had %var;noquote%, which is not needed since those variables are not quoted (and in fact the variable won't even be recognized so you get the literal %var;noquote% in the output).

    • Be careful with curly brackets. Code within curly brackets isn't evaluated. TCL uses curly brackets as an alternative way to build lists. But TCL also uses curly brackets as an alternative to quotation marks for quoting text. So this original code

      array set names { key "Pretty" ...} 

      ... if converted to

      array set names { key "[_bug-tracker.Pretty]" ...} 

      ... won't work since the _ func will not be called. Instead, it should be

      array set names [list key [_bug-tracker.Pretty] ...]
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/apm-design.html0000644000175000017500000012662311501005400022725 0ustar frankiefrankie Package Manager Design

    Package Manager Design

    By Bryan Quinn

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Essentials

    Introduction

    In general terms, a package is a unit of software that serves a single well-defined purpose. That purpose may be to provide a service directly to one or more classes of end-user, (e.g., discussion forums and file storage for community members, user profiling tools for the site publisher), or it may be to act as a building block for other packages (e.g., an application programming interface (API) for storing and querying access control rules, or an API for scheduling email alerts). Thus, packages fall into one of two categories:

    An installation of the OpenACS includes the OpenACS Kernel, some services that extend the kernel's functionality, and some applications intended for end-users. Packages function as individual pieces of subsites. A subsite can contain multiple application and service instances that provide the end-user with capabilities and content customized to the particular subsite.

    This architecture supports the growth of collaborative commerce. For example, Jane User starts a forum focusing on the merits of View Cameras by creating an instance of the Forum application for her personal subsite on an OpenACS Installation. Jack User discovers Jane's forum and includes a link to it in his subsite. As interest in Jane's forum grows, she creates a subsite specializing in providing information about View cameras. This subsite now includes several package instances beyond Forum; it could potentially include its own Ecommerce capabilities (ala Yahoo! Shopping). This could include a knowledge management application that allows users to spread expertise about view cameras and a portal application that links to reliable camera models and resellers. Any subsite enabled package that is added to the OpenACS installation through APM is another potential package instance that can become part of Jane's View Camera subsite.

    The APM provides an architecture for packaging software, making instances of that software available to subsites, specifying configuration parameters for each instance, and managing the creation and release of new packages.

    Historical Considerations

    Prior to ACS 3.3, all packages were lumped together into one monolithic distribution without explicit boundaries; the only way to ascertain what comprised a given package was to look at the top of the corresponding documentation page, where, by convention, the package developer would specify where to find:

    • the data model

    • the Tcl procedures

    • the user-accessible pages

    • the administration pages

    Experience has shown us that this lack of explicit boundaries causes a number of maintainability problems for pre-3.3 installations:

    1. Package interfaces were not guaranteed to be stable in any formal way, so a change in the interface of one package would often break dependent packages (which we would only discover through manual regression testing). In this context, any of the following could constitute an interface change:

      • renaming a file or directory that appears in a URL

      • changing what form variables are expected as input by a page

      • changing a procedural abstraction, e.g., a PL/SQL or Java stored procedure or a Tcl procedure

      • changing a functional abstraction, e.g., a database view or a PL/SQL or Java stored function

      • changing the data model

      This last point is especially important. In most cases, changing the data model should not affect dependent packages. Rather, the package interface should provide a level of abstraction above the data model (as well as the rest of the package implementation). Then, users of the package can take advantage of implementation improvements that don't affect the interface (e.g., faster performance from intelligent denormalization of the data model), without having to worry that code outside the package will now break.

    2. A typical ACS-backed site only uses a few of the modules included in the distribution, yet there was no well-understood way to pick only what you needed when installing the ACS, or even to uninstall what you didn't need, post-installation. Unwanted code had to be removed manually.

    3. Releasing a new version of the ACS was complicated, owing again to the monolithic nature of the software. Since we released everything in the ACS together, all threads of ACS development had to converge on a single deadline, after which we would undertake a focused QA effort whose scale increased in direct proportion to the expansion of the ACS codebase.

    4. There was no standard way for developers outside of ArsDigita to extend the ACS with their own packages. Along the same lines, ArsDigita programmers working on client projects had no standard way to keep custom development cleanly separated from ACS code. Consequently, upgrading an already installed ACS was an error-prone and time-consuming process.

    Consistent use of the APM format and tools will go a long way toward solving the maintainability problems listed above. Moreover, APM is the substrate that will enable us to establish a central package repository, where developers will be able publish their packages for other OpenACS users to download and install.

    For a simple illustration of the difference between ACS without APM (pre-3.3) and ACS with APM (3.3 and beyond), consider a hypothetical ACS installation that uses only two of the thirty-odd modules available circa ACS 3.2 (say, bboard and e-commerce):

    APM itself is part of a package, the OpenACS Kernel, an OpenACS service that is the only mandatory component of an OpenACS installation.

    Competitive Analysis

    The OpenACS is a platform for web-based application software, and any software platform has the potential to develop problems like those described above. Fortunately, there are many precedents for systematic solutions, including:

    Borrowing from all of the above, OpenACS 3.3 introduces its own package management system, the OpenACS Package Manager (APM), which consists of:

    • a standard format for APM packages (also called "OpenACS packages"), including:

      • version numbering, independent of any other package and the OpenACS as a whole

      • specification of the package interface

      • specification of dependencies on other packages (if any)

      • attribution (who wrote it) and ownership (who maintains it)

    • web-based tools for package management:

      • obtaining packages from a remote distribution point

      • installing packages, if and only if:

        1. all prerequisite packages are installed

        2. no conflicts will be created by the installation

      • configuring packages (obsoleting the monolithic OpenACS configuration file)

      • upgrading packages, without clobbering local modifications

      • uninstalling unwanted packages

    • a registry of installed packages, database-backed and integrated with filesystem-based version control

    • web-based tools for package development:

      • creating new packages locally

      • releasing new versions of locally-created packages

    Design Tradeoffs

    The design chosen for APM was meant to satisfy the following constraints:

    • The process of authoring a package must be as simple as possible.

    • Strict conventions must be established that provide a set of canonical locations and names for files and patterns, for OpenACS application development.

    • The processes of installing, upgrading, and using packages must be straightforward and accessible through a web-based UI.

    • Package instances must be able to have subsite-specific content available at an easily configurable URL.

    All of these requirements were met, but at the cost of development simplicity. As Packages demonstrates, a set of strict directory conventions are required in order for a package to use APM. This contrasts with the apparent simplicity available to developers of the OpenACS 3.3 system. However, while the system has become more complex for developers to build packages, this complexity is easily managed and is compensated for by additional capabilities.

    For example, to make a new application available to the system, a developer must:

    1. Create the necessary files to support the data model, Tcl API, and UI pages.

    2. Put the files in the correct locations for APM to be aware of them.

    3. Use APM to create a new package and enable it.

    4. Use the Site Map facility to create an instance of the package, mount it on an appropriate URL, and set parameters for that particular instance.

    While this is complex, especially to a new OpenACS developer, the documentation walks the developer through each of these steps. Moreover, from following these steps, the package can be subsite specific, available to subsites across the system, and be available for distribution to other OpenACS installations without doing a monolithic upgrade or reinstall.

    API

    The APM is composed of systems for accomplishing a set of package-related tasks. Each of these tasks comprise a feature area that has an API, data model, and a UI:

    • Authoring a Package

    • Maintaining Multiple Versions of a Package

    • Creating Instances of the Package

    • Specifying Configuration Parameters for each Instance

    Authoring a Package

    Full instructions on how to prepare an OpenACS package are available in Packages. The API here can be invoked manually by a package's data model creation script, but need not to be used. This API is part of the APM PL/SQL package.

    
    -- Informs the APM that this application is available for use.
    procedure register_application (
        package_key         in apm_package_types.package_key%TYPE,
        pretty_name         in apm_package_types.pretty_name%TYPE,
        pretty_plural       in apm_package_types.pretty_plural%TYPE,
        package_uri         in apm_package_types.package_uri%TYPE,
        singleton_p         in apm_package_types.singleton_p%TYPE
                                    default 'f',
        spec_file_path      in apm_package_types.spec_file_path%TYPE
                                    default null,
        spec_file_mtime     in apm_package_types.spec_file_mtime%TYPE
                                    default null
    );
    
    

    The procedure above registers an OpenACS application in the APM. It creates a new OpenACS object and stores information about the package, such as its name, in the APM data model. There is an analogous procedure for OpenACS services, called apm.register_service.

    To remove an application from the system, there are the calls apm.unregister_application and apm.unregister_service.

    
    -- Remove the application from the system.  
    procedure unregister_application (
        package_key     in apm_package_types.package_key%TYPE,
        -- Delete all objects associated with this application.
        cascade_p       in char default 'f'  
    );
    
    

    Use the cascade_p only if you want to completely remove the package from the OpenACS.

    In order to determine if a particular package exists in the system, use the register_p predicate. It returns 1 if the specified package_key exists in the system, 0 otherwise.

    
    function register_p (
        package_key     in apm_package_types.package_key%TYPE
    ) return integer;
    
    

    Maintaining Multiple Versions of a Package

    While the package authoring API provides a means for registering a package, some information about a package is version dependent. For example, between versions, the owner of a package, its vendor, its URI, and its dependency information may change. The API for package versions allows this information to be specified. All of these APIs are part of the apm_package_version PL/SQL package.

    To create a new package version, use the apm_package_version.new constructor function.

    
    function new (
        version_id          in apm_package_versions.version_id%TYPE
                    default null,
        package_key         in apm_package_versions.package_key%TYPE,
        version_name        in apm_package_versions.version_name%TYPE
                                    default null,
        version_uri         in apm_package_versions.version_uri%TYPE,
        summary         in apm_package_versions.summary%TYPE,
        description_format      in apm_package_versions.description_format%TYPE,
        description         in apm_package_versions.description%TYPE,
        release_date        in apm_package_versions.release_date%TYPE,
        vendor          in apm_package_versions.vendor%TYPE,
        vendor_uri          in apm_package_versions.vendor_uri%TYPE,
        installed_p         in apm_package_versions.installed_p%TYPE
                                    default 'f',
        data_model_loaded_p     in apm_package_versions.data_model_loaded_p%TYPE
                            default 'f'
    ) return apm_package_versions.version_id%TYPE;
    
    

    In order to use this function, an existing package_key must be specified. The version_name parameter must follow a strict convention:

    1. A major version number

    2. at least one minor version number. Although any number of minor version numbers may be included, three minor version numbers is sufficient and is the convention of software developers.

    3. One of the following:

      • The letter d, indicating a development-only version

      • The letter a, indicating an alpha release

      • The letter b, indicating a beta release

      • No letter at all, indicating a final production release

    In addition, the letters d, a, and b may be followed by another integer, indicating a version within the release.

    For those who like regular expressions:

    
    version_number := ^[0-9]+((\.[0-9]+)+((d|a|b|)[0-9]?)?)$
    
    

    So the following is a valid progression for version numbers:

    0.9d, 0.9d1, 0.9a1, 0.9b1, 0.9b2, 0.9, 1.0, 1.0.1, 1.1b1, 1.1

    To delete a given version of a package, use the apm_package_version.delete procedure:

    
    procedure delete (
        package_id      in apm_packages.package_id%TYPE  
    );
    
    

    After creating a version, it is possible to edit the information associated with it using apm_package_version.edit.

    
    function edit (
          new_version_id        in apm_package_versions.version_id%TYPE
                    default null,
          version_id        in apm_package_versions.version_id%TYPE,
          version_name      in apm_package_versions.version_name%TYPE
                    default null,
          version_uri       in apm_package_versions.version_uri%TYPE,
          summary           in apm_package_versions.summary%TYPE,
          description_format    in apm_package_versions.description_format%TYPE,
          description       in apm_package_versions.description%TYPE,
          release_date      in apm_package_versions.release_date%TYPE,
          vendor            in apm_package_versions.vendor%TYPE,
          vendor_uri        in apm_package_versions.vendor_uri%TYPE,
          installed_p       in apm_package_versions.installed_p%TYPE
                    default 'f',
          data_model_loaded_p   in apm_package_versions.data_model_loaded_p%TYPE
                    default 'f'
    ) return apm_package_versions.version_id%TYPE;
    
    

    Versions can be enabled or disabled. Enabling a version instructs APM to source the package's libraries on startup and to make the package available to the OpenACS.

    
    procedure enable (
        version_id          in apm_package_versions.version_id%TYPE
    );
    
    procedure disable (
        version_id          in apm_package_versions.version_id%TYPE  
    );
    
    

    Files associated with a version can be added and removed. The path is relative to the package-root which is acs-server-root/packages/package-key.

    -- Add a file to the indicated version. 
    function add_file(
        file_id             in apm_package_files.file_id%TYPE 
                            default null, 
        version_id in       apm_package_versions.version_id%TYPE, 
        path                in apm_package_files.path%TYPE,
        file_type           in apm_package_file_types.file_type_key%TYPE 
    ) return apm_package_files.file_id%TYPE; 
    
    -- Remove a file from the indicated version.
    procedure remove_file( 
        version_id          in apm_package_versions.version_id%TYPE,
        path                in apm_package_files.path%TYPE 
    );
    

    Package versions need to indicate that they provide interfaces for other software. An interface is an API that other packages can access and utilize. Interfaces are identified as a URI and a version name, that comply with the specification of a version name for package URIs.

    
    -- Add an interface provided by this version.
    function add_interface(
        interface_id        in apm_package_dependencies.dependency_id%TYPE
                        default null,
        version_id          in apm_package_versions.version_id%TYPE,
        interface_uri       in apm_package_dependencies.service_uri%TYPE,
        interface_version       in apm_package_dependencies.service_version%TYPE
    ) return apm_package_dependencies.dependency_id%TYPE;
    
    procedure remove_interface(
        interface_id        in apm_package_dependencies.dependency_id%TYPE,
        version_id          in apm_package_versions.version_id%TYPE
    );
    
    procedure remove_interface(
        interface_uri       in apm_package_dependencies.service_uri%TYPE,
        interface_version       in apm_package_dependencies.service_version%TYPE,
        version_id          in apm_package_versions.version_id%TYPE
    );
    
    

    The primary use of interfaces is for other packages to specify required interfaces, known as dependencies. A package cannot be correctly installed unless all of its dependencies have been satisfied.

    
    -- Add a requirement for this version.  A requirement is some interface that this
    -- version depends on.
    function add_dependency(
        requirement_id      in apm_package_dependencies.dependency_id%TYPE
                        default null,
        version_id          in apm_package_versions.version_id%TYPE,
        requirement_uri     in apm_package_dependencies.service_uri%TYPE,
        requirement_version     in apm_package_dependencies.service_version%TYPE
    ) return apm_package_dependencies.dependency_id%TYPE;
    
    procedure remove_dependency(
        requirement_id      in apm_package_dependencies.dependency_id%TYPE,
        version_id          in apm_package_versions.version_id%TYPE
    );
    
    procedure remove_dependency(
        requirement_uri     in apm_package_dependencies.service_uri%TYPE,
        requirement_version     in apm_package_dependencies.service_version%TYPE,
        version_id          in apm_package_versions.version_id%TYPE
    );
    
    

    As new versions of packages are created, it is necessary to compare their version names. These two functions assist in that task.

    
    -- Given a version_name (e.g. 3.2a), return
    -- something that can be lexicographically sorted.
    function sortable_version_name (
        version_name        in apm_package_versions.version_name%TYPE
    ) return varchar;
    
    -- Given two version names, return 1 if one > two, -1 if two > one, 0 otherwise. 
    -- Deprecate?
    function compare(
        version_name_one        in apm_package_versions.version_name%TYPE,
        version_name_two        in apm_package_versions.version_name%TYPE
    ) return integer;
    
    

    Creating Instances of a Package

    Once a package is registered in the system, it is possible to create instances of it. Each instance can maintain its own content and parameters.

    
    create or replace package apm_application
    as
    
    function new (
        application_id  in acs_objects.object_id%TYPE default null,
        instance_name   in apm_packages.instance_name%TYPE
                default null,
        package_key     in apm_package_types.package_key%TYPE,
        object_type     in acs_objects.object_type%TYPE
                   default 'apm_application',
        creation_date   in acs_objects.creation_date%TYPE default sysdate,
        creation_user   in acs_objects.creation_user%TYPE default null,
        creation_ip     in acs_objects.creation_ip%TYPE default null,
        context_id      in acs_objects.context_id%TYPE default null
    ) return acs_objects.object_id%TYPE;
    
    procedure delete (
        application_id      in acs_objects.object_id%TYPE
    );
    end apm_application;
    
    

    Just creating a package instance is not sufficient for it to be served from the web server. A corresponding site node must be created for it. As an example, here is how the OpenACS API Documentation service makes itself available on the OpenACS main site:

    
    declare
        api_doc_id integer;
    begin
        api_doc_id := apm_service.new (
          instance_name => 'OpenACS API Browser',
          package_key => 'acs-api-browser',
          context_id => main_site_id
        );
    
        apm_package.enable(api_doc_id);
    
        api_doc_id := site_node.new (
          parent_id => site_node.node_id('/'),
          name => 'api-doc',
          directory_p => 't',
          pattern_p => 't',
          object_id => api_doc_id
        );
    
        commit;
    end;
    /
    show errors
    
    
    

    Specifying Configuration Parameters for each Instance

    A parameter is a setting that can be changed on a package instance basis. Parameters are registered on each package_key, and the values are associated with each instance. Parameters can have default values and can be of type 'string' or 'number.' There is support with this API for setting a number of minimum and maximum values for each parameter, but for most instances, the minimum and maximum should be 1. It is useful to allow or require multiple values for packages that need to store multiple pieces of information under one parameter. Default values are automatically set when instances are created, but can be changed for each instance.

    All of the functions below are in the APM PL/SQL package.

    
    -- Indicate to APM that a parameter is available to the system.
    function register_parameter (
        parameter_id        in apm_parameters.parameter_id%TYPE 
                    default null,
        parameter_name      in apm_parameters.parameter_name%TYPE,
        description         in apm_parameters.description%TYPE
                    default null,
        package_key         in apm_parameters.package_key%TYPE,
        datatype            in apm_parameters.datatype%TYPE 
                    default 'string',
        default_value       in apm_parameters.default_value%TYPE 
                    default null,
        section_name        in apm_parameters.section_name%TYPE
                    default null,
        min_n_values        in apm_parameters.min_n_values%TYPE 
                    default 1,
        max_n_values        in apm_parameters.max_n_values%TYPE 
                    default 1
    ) return apm_parameters.parameter_id%TYPE;
    
    function update_parameter (
        parameter_id        in apm_parameters.parameter_id%TYPE,
        parameter_name      in apm_parameters.parameter_name%TYPE,
        description         in apm_parameters.description%TYPE
                    default null,
        package_key         in apm_parameters.package_key%TYPE,
        datatype            in apm_parameters.datatype%TYPE 
                    default 'string',
        default_value       in apm_parameters.default_value%TYPE 
                    default null,
        section_name        in apm_parameters.section_name%TYPE
                    default null,
        min_n_values        in apm_parameters.min_n_values%TYPE 
                    default 1,
        max_n_values        in apm_parameters.max_n_values%TYPE 
                    default 1
    ) return apm_parameters.parameter_name%TYPE;
    
    -- Remove any uses of this parameter.
    procedure unregister_parameter (
        parameter_id        in apm_parameters.parameter_id%TYPE 
                    default null
    );
    
    

    The following functions are used to associate values with parameters and instances:

    
    -- Return the value of this parameter for a specific package and parameter.
    function get_value (
        parameter_id        in apm_parameter_values.parameter_id%TYPE,
        package_id          in apm_packages.package_id%TYPE         
    ) return apm_parameter_values.attr_value%TYPE;
    
    function get_value (
        package_id          in apm_packages.package_id%TYPE,
        parameter_name      in apm_parameters.parameter_name%TYPE
    ) return apm_parameter_values.attr_value%TYPE;
    
    -- Sets a value for a parameter for a package instance.
    procedure set_value (
        parameter_id        in apm_parameter_values.parameter_id%TYPE,
        package_id          in apm_packages.package_id%TYPE,        
        attr_value          in apm_parameter_values.attr_value%TYPE
    );
    
    procedure set_value (
        package_id          in apm_packages.package_id%TYPE,
        parameter_name      in apm_parameters.parameter_name%TYPE,
        attr_value          in apm_parameter_values.attr_value%TYPE
    );  
    
    

    Data Model Discussion

    The central piece of the data model is the apm_package_types table where each package is registered. When a new application or service is installed on an OpenACS instance, a corresponding row in this table is inserted with information about the type of package, e.g. if the forum package is installed on your OpenACS server, a row in apm_package_types will be created, noting that it's an application package type.

    The apm_packages table is used to contain information about the instances of packages currently created in the system. The package_key column references the apm_package_types table to ensure that no package instance can be created for a type that does not exist.

    The apm_package_versions table contains information specific to a particular version of a package. Several tables reference this one to provide further information about the particular version:

    • apm_package_owners Stores information about the owners of a particular version of a package.

    • apm_package_files Stores information about the files that are part of a version.

    • apm_package_dependencies Stores information about what interfaces the package provides and requires.

    Parameter information is maintained through two tables:

    • apm_parameters This table contains the definition of each of the parameters for a package.

    • apm_parameter_values This table holds all of the values of parameters for specific package instances.

    A number of views are available for obtaining information about packages registered in the APM.

    • apm_package_version_info Provides information about all of the versions in the system with information available from the apm_package_types table.

    • apm_enabled_package_versions A view (subset) of the above table with only enabled versions.

    • apm_file_info Provides a public interface for querying file information.

    User Interface

    The APM's user interface is part of the OpenACS Administration Service. The UI is the primary point of contact with APM by developers and administrators. It is part of OpenACS Administration, because only the site-wide administrator should be able to access it. Thus in order to develop a package, the developer must be granted site-wide administration.

    Configuration/Parameters

    APM has two parameters for configuring how it interacts with the UNIX filesystem, accessible via the Site Map admin page. These parameters need not be changed under most circumstances, but may need to be tweaked for Windows compatibility.

    • GzipExecutableDirectory This directory points to where the gunzip program can be found for uncompressing gzip archives. This is needed for the installation of .apm files which are simply gziped tarballs. Default is /usr/local/bin

    • InfoFilePermissionsMode This sets the default UNIX permissions used when creating files using the APM. Default is 775.

    Future Improvements/Areas of Likely Change

    APM has been in production since OpenACS 3.3, and as of version 4.0 offers a stable set of features. One major feature planned is integration with the OpenACS Package Repository for automatic dependency satisfaction. When a user tries to install a package that depends on other packages, the APM will contact the package repository, determine what packages depend on it, and offer the user a chance to download and install them all. This improvement offers value to end users by facilitating the extension of their OpenACS systems.

    Architecturally, minor improvements to the data model and the specification file are planned to increase modularity. The current implementation puts all package specification information in a single file. This approach has certain advantages, such as centralization, but splitting this information into several files allows for flexible extensions to the APM architecture over time.

    APM packages currently lack provisions to verify security information. There are plans to add MD5 time stamps and PGP signatures to packages to enable secure authentication of packages. These steps are necessary for APM to be usable as a scalable method to distribute packages on multiple repositories worldwide.

    Another anticipated change is to split the APM UI into separate systems for authoring, maintaining, and installing packages. The current UI presents all of this functionality in one interface and it can be confusing from a usability perspective.

    Authors

    • System creator: Bryan Quinn, Jon Salz, Michael Yoon, Lars Pind, Todd Nightingale.

    • System owner: Bryan Quinn

    • Documentation author: Bryan Quinn, building from earlier versions by Jon Salz, Michael Yoon, and Lars Pind.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation9/25/2000Bryan Quinn
    0.8Ready for QA9/29/2000Bryan Quinn
    0.9Edited for ACS 4 Beta release10/02/2000Kai Wu
    1.0Edited for OpenACS 4.5 Beta release03/02/2002Roberto Mello
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-categories.html0000644000175000017500000004154711501005400024670 0ustar frankiefrankie Categories

    Categories

    extended by Nima Mazloumi

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    You can associate any ACS Object with one or more categories. In this tutorial we'll show how to equip your application with user interface to take advantage of the Categories service.

    We'll start by installing the Categories service. Go to /acs/admin and install it. This step won't be necessary for the users of your applications because you'll create a dependency with the Package Manager which will take care that the Categories service always gets installed when your application gets installed.

    Now that we have installed the Categories service we can proceed to modifying our application so that it can take advantage of it. We'll do it in three steps:

    1. The Categories service provides a mechanism to associate one or more category trees that are relevant to your application. One example of such tree is a tree of geographical locations. Continents are on the top of such tree, each continent containing countries etc. Another tree might contain market segments etc. Before users of your application can take advantage of the Categories service there needs to be a way for administrators of your application to choose which category trees are applicable for the application.

      The way to achieve this is is to provide a link to the Category Management pages. Add the following snippet to your /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.tcl file:

      		  set category_map_url [export_vars -base "[site_node::get_package_url -package_key categories]cadmin/one-object" { { object_id $package_id } }]
                

      and the following snippet to your /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.adp file:

         			<a href="@category_map_url@"<#categories.Site_wide_Categories#</a>
                

      The link created by the above code (category_map_url) will take the admin to the generic admin UI where he can pick category trees that make sense for this application. The same UI also includes facilities to build and edit category trees. Notice that the only parameter in this example is package_id so that category trees will be associated with the object identified by this package_id. The categorization service is actually more general than that: instead of package_id you could use an ID of some other object that serves as a "container" in your application. For example, if your discussion forums application supports multiple forums you would use forum_id to associate category trees with just that one forum rather than the entire application instance.

    2. Once the category trees have been selected users need a way to categorize items. The easiest way to do this is by adding the category widget type of the form builder to note-edit.tcl. To achieve this we'll need to use the -extend switch to the ad_form command. Here's the "meat" of the note-edit.tcl page:

      			    #extend the form to support categories
      			    set package_id [ad_conn package_id]
      			    
          			category::ad_form::add_widgets -form_name note -container_object_id $package_id -categorized_object_id [value_if_exists item_id]
      
          			ad_form -extend -name note -on_submit {
              			set category_ids [category::ad_form::get_categories -container_object_id $package_id]
          			} -new_data {
          				....
      					category::map_object -remove_old -object_id $item_id $category_ids
                  		db_dml insert_asc_named_object "insert into acs_named_objects (object_id, object_name, package_id) values ( :item_id, :title, :package_id)"
      	    		} -edit_data {
                  		....
              			db_dml update_asc_named_object "update acs_named_objects set object_name = :title, package_id = :package_id where object_id = :item_id"
              			category::map_object -remove_old -object_id $item_id $category_ids
          			} -after_submit {
              				ad_returnredirect "."
              				ad_script_abort
          			}
      			

      While the category::ad_form::add_widgets proc is taking care to extend your form with associated categories you need to ensure that your items are mapped to the corresponding category object yourself. Also since the categories package knows nothing from your objects you have to keep the acs_named_objects table updated with any changes taking place. We use the items title so that they are listed in the categories browser by title.

      Make sure that you also delete these entries if your item is delete. Add this to your corresponding delete page:

      			db_dml delete_named_object "delete from acs_named_objects where object_id = :item_id"
      			

      note-edit.tcl requires a note_id to determine which record should be deleted. It also looks for a confirmation variable, which should initially be absert. If it is absent, we create a form to allow the user to confirm the deletion. Note that in entry-edit.tcl we used ad_form to access the Form Template commands; here, we call them directly because we don't need the extra features of ad_form. The form calls itself, but with hidden variables carrying both note_id and confirm_p. If confirm_p is present, we delete the record, set redirection back to the index, and abort script execution.

      The database commands:

      [$OPENACS_SERVICE_NAME@yourserver www]$ emacs note-delete.xql
      <?xml version="1.0"?>
      <queryset>
        <fullquery name="do_delete">
          <querytext>
            select samplenote__delete(:note_id)
          </querytext>
        </fullquery>
        <fullquery name="get_name">
          <querytext>
            select samplenote__name(:note_id)
          </querytext>
        </fullquery>
      </queryset>

      And the adp page:

      [$OPENACS_SERVICE_NAME@yourserver www]$ emacs note-delete.adp
      <master>
      <property name="title">@title@</property>
      <property name="context">{@title@}</property>
      <h2>@title@</h2>
      <formtemplate id="note-del-confirm"></formtemplate>
      </form>

      The ADP is very simple. The formtemplate tag outputs the HTML form generated by the ad_form command with the matching name. Test it by adding the new files in the APM and then deleting a few samplenotes.

    3. We will now make categories optional on package instance level and also add a configuration page to allow the package admin to enable/disable categories for his package.

      Go to the APM and create a number parameter with the name "EnableCategoriesP" and the default value "0".

      Add the following lines to your index.tcl:

                set return_url [ns_conn url]
                set use_categories_p [parameter::get -parameter "EnableCategoriesP"]
                

      Change your to this:

      			<a href=configure?<%=[export_url_vars return_url]%>>Configure</a>
      			<if @use_categories_p@>
         			<a href="@category_map_url@"<#categories.Site_wide_Categories#</a>
         			</if>
                

      Now create a configure page

                	ad_page_contract {
          			This page allows an admin to change the categories usage mode.
      			} {
          			{return_url ""}
      			}
      
      			set title "Configure category mode"
      			set context [list $title]
      			set use_categories_p [parameter::get -parameter "EnableCategoriesP"]
      
      			ad_form -name categories_mode -form {
          			{enabled_p:text(radio)
              			{label "Enable Categories"}
              			{options {{Yes 1} {No 0}}}
              			{value $use_categories_p}
          			}
          			{return_url:text(hidden) {value $return_url}}
          			{submit:text(submit) {label "Set Mode"}}
      			} -on_submit {
          			parameter::set_value  -parameter "EnableCategoriesP" -value $enabled_p
          			if {![empty_string_p $return_url]} {
              			ns_returnredirect $return_url
          			}
      			}
                 

      and add this to its corresponding ADP page

                	<master>
      			<property name="title">@title@</property>
      			<property name="context">@context@</property>
      
      			<formtemplate id="categories_mode"></formtemplate>
      	      

      Reference this page from your admin page

      		#TCL:
      		set return_url [ad_conn url]
      
      		#ADP:
      		<a href=configure?<%=[export_url_vars return_url]%>>Configure</a>
      		

      Change the note-edit.tcl:

      		# Use Categories?
      		set use_categories_p [parameter::get -parameter "EnableCategoriesP" -default 0]
      		if { $use_categories_p == 1 } {
      			# YOUR NEW FORM DEFINITION
      		} else {
          		# YOUR OLD FORM DEFINITION
      		}
      	
    4. You can filter your notes using categories. The below example does not support multiple filters and displays a category in a flat format.

      The first step is to define the optional parameter category_id for index.tcl:

       	  	ad_page_contract {
        		YOUR TEXT
      		} {
      			YOURPARAMS
          		{category_id:integer,optional {}}
      		}
       	  

      Now you have to check whether categories are enabled or not. If this is the case and a category id is passed you need to extend your sql select query to support filtering. One way would be to extend the mfp::note::get proc to support two more swiches -where_clause and -from_clause.

       	  	set use_categories_p [parameter::get -parameter "EnableCategoriesP" -default 0]
      
      		if { $use_categories_p == 1 && [exists_and_not_null category_id] } {
      
      			set from_clause "category_object_map com, acs_named_objects nam"
      			set_where_clause "com.object_id = qa.entry_id and
      								nam.package_id = :package_id and
      								com.object_id = nam.object_id and
      								com.category_id = :category_id"
      			
      			...
      								
          		mfp::note::get \
          		-item_id $item_id \
          		-array note_array \
          		-where_clause $where_clause \
          		-from_clause $from_clause
          		
          		...
      		} else {
          		# OLD STUFF
      		}
       	  

      Also you need to make sure that the user can see the corresponding categories. Add the following snippet to the end of your index page:

       	  # Site-Wide Categories
      		if { $use_categories_p == 1} {
          		set package_url [ad_conn package_url]
          		if { ![empty_string_p $category_id] } {
              		set category_name [category::get_name $category_id]
              		if { [empty_string_p $category_name] } {
                  		ad_return_exception_page 404 "No such category" "Site-wide \
                			Category with ID $category_id doesn't exist"
                  		return
              		}
              		# Show Category in context bar
              		append context_base_url /cat/$category_id
              		lappend context [list $context_base_url $category_name]
              		set type "all"
          		}
      
          		# Cut the URL off the last item in the context bar
          		if { [llength $context] > 0 } {
              		set context [lreplace $context end end [lindex [lindex $context end] end]]
          		}
      
          		db_multirow -unclobber -extend { category_name tree_name } categories categories {
              		select c.category_id as category_id, c.tree_id
              		from   categories c, category_tree_map ctm
              		where  ctm.tree_id = c.tree_id
              		and    ctm.object_id = :package_id
          		} {
              		set category_name [category::get_name $category_id]
              		set tree_name [category_tree::get_name $tree_id]
          		}
      		}
      		

      and to the corresponding index ADP page:

      		<if @use_categories_p@>
       			<multiple name="categories">
                 		<h2>@categories.tree_name@
                 		<group column="tree_id">
                   		<a href="@package_url@cat/@categories.category_id@?@YOURPARAMS@&category_id=@categories.category_id@">@categories.category_name@
                 		</group>
               	</multiple>
      		<a href="@package_url@view?@YOURPARAMS@">All Items</if>
       	  

      Finally you need a an index.vuh in your www folder to rewrite the URLs correctly, Using .vuh files for pretty urls:

       	  	set url /[ad_conn extra_url]
      
      		if {[regexp {^/+cat/+([^/]+)/*} $url \
                ignore_whole category_id]} {
                rp_form_put category_id $category_id
      		}
      		rp_internal_redirect "/packages/YOURPACKAGE/www/index" 	  
       	  

      Now when ever the user select a category only notes that belong to this category are displayed.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/upgrade-overview.html0000644000175000017500000001163211501005400024165 0ustar frankiefrankie Overview

    Overview

    Starting with Version 4.5, all OpenACS core packages support automatic upgrade. That means that, if you have OpenACS 4.5 or better, you should always be able to upgrade all of your core packages automatically. If you haven't changed anything, no manual intervention should be required. If you are running OpenACS prior to 4.5, upgrading will require manual effort.

    If all of these conditions are true:

    • Your OpenACS Core is 5.0.0 or later

    • You do not keep your OpenACS site in a local CVS repository

    • You do not have any custom code

    then you can upgrade automatically using the automated installer in the OpenACS Package Manager (APM), and you can probably skip the rest of this chapter. To upgrade directly from the OpenACS repository using the APM:

    1. Browse to the Installer.

    2. Click install or upgrade under "Install from OpenACS Repository" and select the packages to install or upgrade.

    3. The APM will download the requested packages from OpenACS.org, install the files on your hard drive, run any appropriate database upgrade scripts, and prompt you to restart the server. After restarting the server again, the upgrade is complete.

    Figure 5.1. Upgrading with the APM

    Upgrading with the APM

    It's always a good idea to precede an upgrade attempt with a snapshot backup.

    Table 5.1. Assumptions in this section

    name of OpenACS user$OPENACS_SERVICE_NAME
    OpenACS server name$OPENACS_SERVICE_NAME
    Root of OpenACS file tree/var/lib/aolserver/$OPENACS_SERVICE_NAME
    Database backup directory/var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-newpackage.html0000644000175000017500000002705111501005400024642 0ustar frankiefrankie Creating an Application Package

    Creating an Application Package

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    The intended page map

    Overview

    To start developing new code in OpenACS, we build a new package. A package is a a discrete collection of web pages, tcl code, and database tables and procedures. A package with user interface is called an application; a package which provides functions to other packages and has no direct interface, a service. A package can be installed, upgraded, and removed. It communicates with other packages through an API. This chapter walks you through the minimum steps to create a useful package, including writing documentation, setting up database tables and procedures, writing web pages, debugging, and automatic regression testing.

    This tutorial uses the content repository package. This radically simplifies the database work, but forces us to work around the content repository's limitations, including an incomplete TCL API. So the tutorial is messier than we'd like right now. Code that is temporary hackage is clearly marked.

    In this tutorial, we will make an application package for displaying a list of text notes.

    Before you begin

    You will need:

    • A computer with a working installation of OpenACS. If you don't have this, see Chapter 2. Installation Overview.

    • Example files, which are included in the standard OpenACS 5.6.0 distribution.

    Figure 8.1. Assumptions in this section

    Fully qualified domain name of your serveryourserver.test
    URL of your serverhttp://yourserver.test:8000
    Name of development account$OPENACS_SERVICE_NAME
    New Package keymyfirstpackage

    Use the APM to initialize a new package

    We use the ACS Package Manager (APM) to add, remove, and upgrade packages. It handles package meta-data, such as lists of files that belong in the package. Each package is uniquely identified by a package key. To start developing a new package, use the APM to create an empty package with our new package key, myfirstpackage. This will create the initial directories, meta-information files, and database entries for a new package. (More info on APM)

    1. Browse to http://yourserver:8000/acs-admin/apm.

    2. Click Create a New Package.

      Fill in the fields listed below. Ignore the rest (and leave the check boxes alone). (Some will change automatically. Don't mess with those.)

      • Package Key: myfirstpackage

      • Package Name: My First Package

      • Package Plural: My First Package

      • Package Type: Application

      • Initial Version: 0.1d

      • Summary: This is my first package.

      At the bottom, click Create Package.

    This creates a package rooted at /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage. This is the "home directory" of our new package, and all files in the package will be within this directory. More on the structure of packages).

    Add an Application Instance to the Server

    In order to see your work in progress, you must create a map between the URL space of incoming requests and the package application instance. You do this by adding the application in the main site administration). This creates a link between the incoming URL requests and an instance of the application. (More on applications and nodes)

    You can have instances of a package on one site, each with a different URL and different permissions, all sharing the same code and tables. This requires that a package be developed package-aware. You'll see how to do that in this tutorial.

    1. Browse to http://yourserver.test:8000/admin/applications/application-add/.

    2. Choose "My First Package" from the list and click OK (the other fields are optional).

    By mounting the package, we've caused all requests to http://yourserver.test:8000/myfirstpackage to be satisfied from the files at /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www.

    Quick start

    The remainder of the tutorial walks you through each file one at a time as you create the package. You can skip all this, and get a working package, by doing the following:

    cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/tutorial
    psql $OPENACS_SERVICE_NAME -f myfirstpackage-create.sql
    cp note-edit.* note-delete.tcl index.* ../../../../myfirstpackage/www/
    mkdir ../../../../myfirstpackage/lib
    cp note-list.* ../../../../myfirstpackage/lib/
    cp myfirstpackage-*sql ../../../../myfirstpackage/sql/postgresql/
    cp myfirstpackage-procs.tcl ../../../../myfirstpackage/tcl/test/
    cp note-procs.tcl ../../../../myfirstpackage/tcl/

    After restarting the server, the tutorial application will be installed and working at the url you selected in the previous step.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/index.adp0000644000175000017500000000622411326311615021617 0ustar frankiefrankie

    OpenACS Core Documentation

    Primers and References

    Documentation Improvement Project

    <% # This block of ADP code ensures that the Installer can still serve this # page even without a working templating system. set found_p 0 if {[db_table_exists apm_package_types]} { db_foreach get_installed_pkgs "select package_key, pretty_name from apm_package_types order by upper(pretty_name) " { if { ! $found_p } { set found_p 1 adp_puts "\n

    Installed Packages

    \n
      \n" } set index_page [lindex [glob -nocomplain \ "[acs_package_root_dir $package_key]/www/doc/index.*"] 0] if { [file exists $index_page] } { if {![empty_string_p $pretty_name]} { adp_puts "
    • $pretty_name\n" } else { adp_puts "
    • $package_key\n" } } else { if {![empty_string_p $pretty_name]} { adp_puts "
    • $pretty_name\n" } else { adp_puts "
    • $package_key\n" } } } } if {!$found_p} { adp_puts "
    • No installed packages.\n" } adp_puts "
    " set packages [core_docs_uninstalled_packages] if { ! [empty_string_p $packages] } { adp_puts "\n

    Uninstalled packages

    \n
      " foreach {key name} $packages { set index_page [lindex [glob -nocomplain \ "[acs_package_root_dir $key]/www/doc/index.*"] 0] if { [file exists $index_page] } { adp_puts "
    • $name\n" } else { adp_puts "
    • $name\n" } } adp_puts "\n
    " } %>

    This software is licensed under the GNU General Public License, version 2 (June 1991)

    Questions or comments about the documentation?
    Please visit the OpenACS forums or send email to docs@openacs.org.

    openacs-5.7.0/packages/acs-core-docs/www/index.vuh0000644000175000017500000000115507543727162021671 0ustar frankiefrankie# packages/acs-core-docs/www/index.vuh set purlv [split [ad_conn path_info] /] set package_key [lindex $purlv 0] # replace the package key by "doc" (preserve presence of any trailing slash). set path_tail \ "doc[string range [ad_conn path_info] [string length $package_key] end]" if {![string compare [ad_conn path_info] "index.html"]} { rp_internal_redirect "/packages/acs-core-docs/www/index.adp" } elseif {[file isdirectory "[acs_root_dir]/packages/$package_key/www/doc"]} { rp_internal_redirect "/packages/$package_key/www/$path_tail" } else { rp_internal_redirect "/packages/$package_key/$path_tail" } openacs-5.7.0/packages/acs-core-docs/www/tutorial.html0000644000175000017500000000530611501005400022536 0ustar frankiefrankie Chapter 8. Development Tutorial
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/general-documents.html0000644000175000017500000000467511501005400024317 0ustar frankiefrankie Chapter 1. High level information: What is OpenACS?

    Chapter 1. High level information: What is OpenACS?

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/configuring-new-site.html0000644000175000017500000000701411501005400024734 0ustar frankiefrankie Chapter 4. Configuring a new OpenACS Site

    Chapter 4. Configuring a new OpenACS Site

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    In this chapter, Configuring refers to making changes to a new OpenACS site through the web interface. In crude terms, these changes happen in the database, and are upgrade-safe. Customizing refers to changes that touch the file system, and require some planning if easy upgradability is to be maintained.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/eng-standards.html0000644000175000017500000000606611501005400023431 0ustar frankiefrankie Chapter 11. Engineering Standards
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/README.TXT0000644000175000017500000000100107525303736021357 0ustar frankiefrankieALL the files in this directory are *generated*. Do not edit them. Instead, edit the files in /packages/acs-core-docs/www/xml/ and then run 'make' from /packages/acs-core-docs/www/xml It's done this way so that everything under /packages/acs-core-docs/www/xml/ is a self-contained version of the most up-to-date docs, able to regenerate the latest HTML and files. Bottom line, if you want to edit docs, make sure you're editing files underneath the 'xml' directory. -- Vinod Kurup (vinod@kurup.com) 2002-08-10 openacs-5.7.0/packages/acs-core-docs/www/object-system-design.html0000644000175000017500000020611311501005400024731 0ustar frankiefrankie Object Model Design

    Object Model Design

    By Pete Su, Michael Yoon, Richard Li, Rafael Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    Before OpenACS 4, software developers writing OpenACS applications or modules would develop each data model separately. However, many applications built on OpenACS share certain characteristics or require certain common services. Examples of such services include:

    • User comments

    • Storage of user-defined or extensible sets of attributes

    • Access control

    • General auditing and bookkeeping (e.g. creation date, IP addresses, and so forth)

    • Presentation tools (e.g. how to display a field in a form or on a page)

    All of these services involve relating additional service-related information to application data objects. Examples of application objects include:

    • forum messages

    • A user home page

    • A ticket in the ticket tracker

    In the past, developers had to use ad-hoc and inconsistent schemes to interface to various "general" services. OpenACS 4 defines a central data model that keeps track of the application objects that we wish to manage, and serves as a primary store of metadata. By metadata, we mean data stored on behalf of an application outside of the application's data model in order to enable certain central services. The OpenACS 4 Object Model (or object system) manages several different kinds of data and metadata to allow us to provide general services to applications:

    • Object Identification

      Every application object is given a unique identifier in the system. This identifier can be used to find all data related to a particular object.

    • Object Context and Access Control

      Every object is created in a particular security context, so the system can provide centralized access control.

    • Object Types and Attributes

      Objects are instances of developer-defined object types. Object types allow developers to customize the data that is stored with each object.

    • Relation Types

      Relation types provide a general mechanism for mapping instances of one object type (e.g. users) to instances of another object type (e.g. groups).

    The next section will explore these facilities in the context of the the particular programming idioms that we wish to generalize.

    Related Links

    This design document should be read along with the design documents for the new groups system, subsites and the permissions system

    History

    The motivation for most of the facilities in the OpenACS 4 Object Model can be understood in the context of the 3.x code base and the kinds of programming idioms that evolved there. These are listed and discussed below.

    Object Identification

    Object identification is a central mechanism in OpenACS 4. Every application object in OpenACS 4 has a unique ID which is mapped to a row in a central table called acs_objects. Developers that wish to use OpenACS 4 services need only take a few simple steps to make sure that their application objects appear in this table. The fact that every object has a known unique identifier means that the core can deal with all objects in a generic way. In other words, we use object identifiers to enable centralized services in a global and uniform manner.

    Implicit Object Identifiers in OpenACS 3.x

    The motivation for implementing general object identifiers comes from several observations of data models in OpenACS 3.x. Many modules use a (user_id, group_id, scope) column-triple for the purpose of recording ownership information on objects, for access control. User/groups also uses (user_id, group_id) pairs in its user_group_map table as a way to identify data associated with a single membership relation.

    Also, in OpenACS 3.x many utility modules exist that do nothing more than attach some extra attributes to existing application data. For example, general comments maintains a table that maps application "page" data (static or dynamic pages on the website) to one or more user comments on that page. It does so by constructing a unique identifier for each page, usually a combination of the table in which the data is stored, and the value of the primary key value for the particular page. This idiom is referred to as the "(on_which_table + on_what_id)" method for identifying application data. In particular, general comments stores its map from pages to comments using a "(on_which_table + on_what_id)" key plus the ID of the comment itself.

    All of these composite key constructions are implicit object identifiers - they build a unique ID out of other pieces of the data model. The problem is that their definition and use is ad-hoc and inconsistent, making the construction of generic application-independent services unnecessarily difficult.

    Object Identifiers in OpenACS 4

    The OpenACS 4 Object Model defines a single mechanism that applications use to attach unique identifiers to application data. This identifier is the primary key of the acs_objects table. This table forms the core of what we need to provide generic services like access control, general attribute storage, general presentation and forms tools, and generalized administrative interfaces. In addition, the object system provides an API that makes it easy to create new objects when creating application data. All an application must do to take advantage of general services in OpenACS 4 is to use the new API to make sure every object the system is to manage is associated with a row in acs_objects. More importantly, if they do this, new services like general comments can be created without requiring existing applications to "hook into" them via new metadata.

    Note: Object identifiers are a good example of metadata in the new system. Each row in acs_objects stores information about the application object, but not the application object itself. This becomes more clear if you skip ahead and look at the SQL schema code that defines this table.

    Object Context and Access Control

    Until the implementation of the general permissions system, every OpenACS application had to manage access control to its data separately. Later on, a notion of "scoping" was introduced into the core data model.

    "Scope" is a term best explained by example. Consider some hypothetical rows in the address_book table:

    ...scopeuser_idgroup_id...
    ...user123 ...
    ...group 456...
    ...public ...

    The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address book.

    In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people).

    In OpenACS 4, rather than breaking the world into a limited set of scopes, every object lives in a single context. A context is just an abstract name for the default security domain to which the object belongs. Each context has a unique identifier, and all the contexts in a system form a tree. Often this tree will reflect an observed hierarchy in a site, e.g. a forum message would probably list a forum topic as its context, and a forum topic might list a subsite as its context. Thus, contexts make it easier to break the site up into security domains according to its natural structure. An object's context is stored in the context_id column of the acs_objects table.

    We use an object's context to provide a default answer to questions regarding access control. Whenever we ask a question of the form "can user X perform action Y on object Z", the OpenACS security model will defer to an object's context if there is no information about user X's permission to perform action Y on object Z.

    The context system forms the basis for the rest of the OpenACS access control system, which is described in in two separate documents: one for the permissions system and another for the party groups system. The context system is also used to implement subsites.

    Object Types

    As mentioned above, many OpenACS modules provide extensible data models, and need to use application specific mechanisms to keep track of user defined attributes and to map application data to these attributes. In the past, modules either used user/groups or their own ad hoc data model to provide this functionality.

    User/Groups in OpenACS 3.x

    The user/group system allowed developers to define group types along with attributes to be stored with each instance of a group type. Each group type could define a helper table that stored attributes on each instance of the group type. This table was called the "_info" table because the name was generated by appending _info to the name of the group type.

    The user/groups data model also provided the user_group_type_member_fields and user_group_member_fields tables to define attributes for members of groups of a specific type and for members of a specific group, respectively. The user_group_member_field_map table stored values for both categories of attributes in its field_value column. These tables allowed developers and users to define custom sets of attributes to store on groups and group members without changing the data model at the code level.

    Many applications in OpenACS 3.x and earlier used the group type mechanism in ways that were only tangentially related to groups of users, just to obtain access to this group types mechanism. Thus the motivation for generalizing the group types mechanism in OpenACS 4.

    Object Types and Subtypes

    In OpenACS 4 object types generalize the OpenACS 3.x notion of group types. Each object type can define one or more attributes to be attached to instances of the type. This allows developers to define new types without being artificially tied to a particular module (i.e. user/groups).

    In addition, the OpenACS 4 object model provides mechanism for defining subtypes of existing types. A subtype of a parent type inherits all the attributes defined in the parent type, and can define some of its own. The motivation for subtypes comes from the need for OpenACS to be more extensible. In OpenACS 3.x, many applications extended the core data models by directly adding more columns, in order to provide convenient access to new information. This resulted in core data tables that were too "fat", containing a hodge podge of unrelated information that should have been normalized away. The canonical example of this is the explosion of the users table in OpenACS 3.x. In addition to being sloppy technically, these fat tables have a couple of other problems:

    • They degrade performance.

    • Denormalization can make it hard to maintain consistency constraints on the data.

    Object subtypes provide a way to factor the data model while still keeping track of the fact that each member of a subtype (i.e. for each row in the subtype's table), is also a member of the parent type (i.e. there is a corresponding row in the parent type table). Therefore, applications an use this mechanism without worrying about this bookkeeping themselves, and we avoid having applications pollute the core data model with their specific information.

    Object Attributes, Skinny Tables

    As we described above, the OpenACS 3.x user/groups system stored object attributes in two ways. The first was to use columns in the helper table. The second consisted of two tables, one describing attributes and one storing values, to provide a flexible means for attaching attributes to metadata objects. This style of attribute storage is used in several other parts of OpenACS 3.x, and we will refer to it as "skinny tables". For example:

    • In the Ecommerce data model, the ec_custom_product_fields table defines attributes for catalog products, and the ec_custom_product_field_values table stores values for those attributes.

    • In the Photo DB data model, the ph_custom_photo_fields table defines attributes for the photographs owned by a specific user, and tables named according to the convention "ph_user_<user_id>_custom_info" are used to store values for those attributes.

    In addition, there are some instances where we are not using this model but should, e.g. the users_preferences table, which stores preferences for registered users in columns such as prefer_text_only_p and dont_spam_me_p. The "standard" way for an OpenACS 3.x-based application to add to the list of user preferences is to add a column to the users_preferences table (exactly the kind of data model change that has historically complicated the process of upgrading to a more recent OpenACS version).

    The Objet Model generalizes the scheme used in the old OpenACS 3.x user/groups system. It defines a table called acs_attributes that record what attributes belong to which object types, and how the attributes are stored. As before, attributes can either be stored in helper tables, or in a single central skinny table. The developer makes this choice on a case by case basis. For the most part, attribute data is stored in helper tables so that they can take full advantage of relational data modeling and because they will generally be more efficient. Occasionally, a data model will use skinny tables because doing so allows developers and users to dynamically update the set of attributes stored on an object without updating the data model at the code level. The bottom line: Helper tables are more functional and more efficient, skinny tables are more flexible but limited.

    Relation Types

    Many OpenACS 3.x modules use mapping tables to model relationships between application objects. Again, the 3.x user/groups system provides the canonical example of this design style. In that system, there was a single table called user_group_map that kept track of which users belonged to what groups. In addition, as we discussed in the previous section, the system used the user_group_member_fields and user_group_member_fields_map tables to allow developers to attach custom attributes to group members. In fact, these attributes were not really attached to the users, but to the fact that a user was a member of a particular group - a subtle but important distinction.

    In OpenACS 4, relation types generalize this mechanism. Relation types allow developers to define general mappings from objects of a given type T, to other objects of a given type R. Each relation type is a subtype of acs_object, extended with extra attributes that store constraints on the relation, and the types of objects the relation actually maps. In turn, each instance of a relation type is an object that represents a single fact of the form "the object t of type T is related to the object r of type R." That is, each instance of a relation type is essentially just a pair of objects.

    Relation types generalize mapping tables. For example, the 3.x user/groups data model can be largely duplicated using a single relation type describing the "group membership" relation. Group types would then be subtypes of this membership relation type. Group type attributes would be attached to the relation type itself. Group member attributes would be attached to instances of the membership relation. Finally, the mapping table would be replaced by a central skinny table that the relation type system defines.

    Relation types should be used when you want to be able to attach data to the "fact" that object X and object Y are related to each other. On the face of it, they seem like a redundant mechanism however, since one could easily create a mapping table to do the same thing. The advantage of registering this table as a relation type is that in principle the OpenACS 4 object system could use the meta data in the types table to do useful things in a generic way on all relation types. But this mechanism doesn't really exist yet.

    Relation types are a somewhat abstract idea. To get a better feel for them, you should just skip to the data model.

    Summary and Design Considerations

    The OpenACS 4 Object Model is designed to generalize and unify the following mechanisms that are repeatedly implemented in OpenACS-based systems to manage generic and application specific metadata:

    Why not Object Databases?

    The presence of a framework for subtyping and inheritance always brings up the question of why we don't just use an object database. The main reason is that all of the major object database vendors ship products that are effectively tied to some set of object oriented programming languages. Their idea is to provide tight language-level integration to lower the "impedance mismatch" between the database and the language. Therefore, database objects and types are generally directly modeled on language level objects and types. Of course, this makes it nearly impossible to interact with the database from a language that does not have this tight coupling, and it limits the data models that we can write to ideas that are expressible in the host language. In particular, we lose many of the best features of the relational database model. This is a disaster from an ease of use standpoint.

    The "Object relational" systems provide an interesting alternative. Here, some notion of subtyping is embedded into an existing SQL or SQL-like database engine. Examples of systems like this include the new Informix, PostgreSQL 7, and Oracle has something like this too. The main problem with these systems: each one implements their own non-portable extensions to SQL to implement subtyping. Thus, making OpenACS data models portable would become even more difficult. In addition, each of these object systems have strange limitations that make using inheritance difficult in practice. Finally, object databases are not as widely used as traditional relational systems. They have not been tested as extensively and their scalability to very large databases is not proven (though some will disagree with this statement).

    Oracle

    The conclusion: the best design is to add a limited notion of subtyping to our existing relational data model. By doing this, we retain all the power of the relational data model while gaining the object oriented features we need most.

    In the context of OpenACS 4, this means using the object model to make our data models more flexible, so that new modules can easily gain access to generic features. However, while the API itself doesn't enforce the idea that applications only use the object model for metadata, it is also the case that the data model is not designed to scale to large type hierarchies. In the more limited domain of the metadata model, this is acceptable since the type hierarchy is fairly small. But the object system data model is not designed to support, for example, a huge type tree like the Java runtime libraries might define.

    This last point cannot be over-stressed: the object model is not meant to be used for large scale application data storage. It is meant to represent and store metadata, not application data.

    Data Model

    Like most data models, the OpenACS Core data model has two levels:

    1. The knowledge level (i.e. the metadata model)

    2. The operational level (i.e. the concrete data model)

    You can browse the data models themselves from here:

    (Note that we have subdivided the operational level into the latter two files.)

    The operational level depends on the knowledge level, so we discuss the knowledge level first. In the text below, we include abbreviated versions of the SQL definitions of many tables. Generally, these match the actual definitions in the existing data model but they are meant to reflect design information, not implementation. Some less relevant columns may be left out, and things like constraint names are not included.

    Knowledge-Level Model

    The knowledge level data model for OpenACS objects centers around three tables that keep track of object types, attributes, and relation types. The first table is acs_object_types, shown here in an abbreviated form:

    
    create table acs_object_types (
            object_type          varchar(100) not null primary key,
            supertype            references acs_object_types (object_type),
            abstract_p           char(1) default 'f' not null
            pretty_name          varchar(100) not null unique,
            pretty_plural        varchar(100) not null unique,
            table_name           varchar(30) not null unique,
            id_column            varchar(30) not null,
            name_method          varchar(30),
            type_extension_table varchar(30)
    );
    
    
    

    This table contains one row for every object type in the system. The key things to note about this table are:

    • For every type, we store metadata for how to display this type in certain contexts (pretty_name and pretty_plural).

    • If the type is a subtype, then its parent type is stored in the column supertype.

    • We support a notion of "abstract" types that contain no instances (as of 9/2000 this is not actually used). These types exist only to be subtyped. An example might be a type representing "shapes" that contains common characteristics of all shapes, but which is only used to create subtypes that represent real, concrete shapes like circles, squares, and so on.

    • Every type defines a table in which one can find one row for every instance of this type (table_name, id_column).

    • type_extension_table is for naming a table that stores extra generic attributes.

    The second table we use to describe types is acs_attributes. Each row in this table represents a single attribute on a specific object type (e.g. the "password" attribute of the "user" type). Again, here is an abbreviated version of what this table looks like. The actual table used in the implementation is somewhat different and is discussed in a separate document.

    
    create table acs_attributes (
            attribute_id    integer not null primary key
            object_type     not null references acs_object_types (object_type),
            attribute_name  varchar(100) not null,
            pretty_name     varchar(100) not null,
            pretty_plural   varchar(100),
            sort_order      integer not null,
            datatype        not null,
            default_value   varchar(4000),
            storage         varchar(13) default 'type_specific'
                            check (storage in ('type_specific',
                                               'generic')),
            min_n_values    integer default 1 not null,
            max_n_values    integer default 1 not null,
            static_p        varchar(1)
    );
    
    
    

    The following points are important about this table:

    • Every attribute has a unique identifier.

    • Every attribute is associated with an object type.

    • We store various things about each attribute for presentation (pretty_name, sort_order).

    • The data_type column stores type information on this attribute. This is not the SQL type of the attribute; it is just a human readable name for the type of data we think the attribute holds (e.g. "String", or "Money"). This might be used later to generate a user interface.

    • The sort_order column stores information about how to sort the attribute values.

    • Attributes can either be stored explicitly in a table ("type specific storage") or in a skinny table ("generic storage"). In most cases, an attribute maps directly to a column in the table identified by the table_name of the corresponding object type, although, as mentioned above, we sometimes store attribute values as key-value pairs in a "skinny" table. However, when you ask the question "What are the attributes of this type of object?", you don't really care about how the values for each attribute are stored (in a column or as key-value pairs); you expect to receive the complete list of all attributes.

    • The max_n_values and min_n_values columns encode information about the number of values an attribute may hold. Attributes can be defined to hold 0 or more total values.

    • The static_p flag indicates whether this attribute value is shard by all instances of a type, as with static member fields in C++. Static attribute are like group level attributes in OpenACS 3.x.

    The final part of the knowledge level model keeps track of relationship types. We said above that object relationships are used to generalize the 3.x notion of group member fields. These were fields that a developer could store on each member of a group, but which were contextualized to the membership relation. That is, they were really "attached" to the fact that a user was a member of a particular group, and not really attached to the user. This is a subtle but important distinction, because it allowed the 3.x system to store multiple sets of attributes on a given user, one set for each group membership relation in which they participated.

    In OpenACS 4, this sort of data can be stored as a relationship type, in acs_rel_types. The key parts of this table look like this:

    
    create table acs_rel_types (
            rel_type        varchar(100) not null
                            references acs_object_types(object_type),
            object_type_one not null
                            references acs_object_types (object_type),
            role_one        references acs_rel_roles (role),
            object_type_two not null
                            references acs_object_types (object_type),
            role_two        references acs_rel_roles (role)
            min_n_rels_one  integer default 0 not null,
            max_n_rels_one  integer,
            min_n_rels_two  integer default 0 not null,
            max_n_rels_two  integer
    );
    
    
    

    Things to note about this table:

    • The main part of this table records the fact that the relation is between instances of object_type_one and instances of object_type_two. Therefore, each instance of this relation type will be a pair of objects of the appropriate types.

    • The role columns store human readable names for the roles played by each object in the relation (e.g. "employee" and "employer"). Each role must appear in the acs_rel_roles.

    • The min_n_rels_one column, and its three friends allow the programmer to specify constraints on how many objects any given object can be related to on either side of the relation.

    This table is easier to understand if you also know how the acs_rels table works.

    To summarize, the acs_object_types and acs_attributes tables store metadata that describes every object type and attribute in the system. These tables generalize the group types data model in OpenACS 3.x. The acs_rel_types table stores information about relation types.

    This part of the data model is somewhat analogous to the data dictionary in Oracle. The information stored here is primarily metadata that describes the data stored in the operational level of the data model, which is discussed next.

    Operational-level Data Model

    The operational level data model centers around the acs_objects table. This table contains a single row for every instance of the type acs_object. The table contains the object's unique identifier, a reference to its type, security information, and generic auditing information. Here is what the table looks like:

    
    create table acs_objects (
            object_id               integer not null,
            object_type             not null
                                    references acs_object_types (object_type),
            context_id              references acs_objects(object_id),
            security_inherit_p      char(1) default 't' not null,
                                    check (security_inherit_p in ('t', 'f')),
            creation_user           integer,
            creation_date           date default sysdate not null,
            creation_ip             varchar(50),
            last_modified           date default sysdate not null,
            modifying_user          integer,
            modifying_ip            varchar(50)
    );
    
    
    

    As we said in Section III, security contexts are hierarchical and also modeled as objects. There is another table called acs_object_context_index that stores the context hierarchy.

    Other tables in the core data model store additional information related to objects. The table acs_attribute_values and acs_static_attr_values are used to store attribute values that are not stored in a helper table associated with the object's type. The former is used for instance attributes while the latter is used for class-wide "static" values. These tables have the same basic form, so we'll only show the first:

    
    create table acs_attribute_values (
            object_id       not null
                            references acs_objects (object_id) on delete cascade,
            attribute_id    not null
                            references acs_attributes (attribute_id),
            attr_value      varchar(4000),
            primary key     (object_id, attribute_id)
    );
    
    
    

    Finally, the table acs_rels is used to store object pairs that are instances of a relation type.

    
    create table acs_rels (
            rel_id          not null
                            references acs_objects (object_id)
                            primary key
            rel_type        not null
                            references acs_rel_types (rel_type),
            object_id_one   not null
                            references acs_objects (object_id),
            object_id_two   not null
                            references acs_objects (object_id),
            unique (rel_type, object_id_one, object_id_two)
    );
    
    
    

    This table is somewhat subtle:

    • rel_id is the ID of an instance of some relation type. We do this so we can store all the mapping tables in this one table.

    • rel_type is the ID of the relation type to which this object belongs.

    • The next two object IDs are the IDs of the objects being mapped.

    All this table does is store one row for every pair of objects that we'd like to attach with a relation. Any additional attributes that we'd like to attach to this pair of objects is specified in the attributes of the relation type, and could be stored in any number of places. As in the 3.x user/groups system, these places include helper tables or generic skinny tables.

    This table, along with acs_attributes and acs_attribute_values generalize the old user/group tables user_group_map, user_group_member_fields_map and user_group_member_fields.

    Summary and Discussion

    The core tables in the OpenACS 4 data model store information about instances of object types and relation types. The acs_object table provides the central location that contains a single row for every object in the system. Services can use this table along with the metadata in stored in the knowledge level data model to create, manage, query and manipulate objects in a uniform manner. The acs_rels table has an analogous role in storing information on relations.

    These are all the tables that we'll discuss in this document. The rest of the Kernel data model is described in the documents for subsites, the permissions system and for the groups system.

    Some examples of how these tables are used in the system can be found in the discussion of the API, which comes next.

    API

    Now we'll examine each piece of the API in detail. Bear in mind that the Object Model API is defined primarily through PL/SQL packages.

    Object Types and Attributes

    The object system provides an API for creating new object types and then attaching attributes to them. The procedures create_type and drop_type are used to create and delete type definitions.

    The two calls show up in the package acs_object_type.

    
      procedure create_type (
        object_type         in acs_object_types.object_type%TYPE,
        pretty_name         in acs_object_types.pretty_name%TYPE,
        pretty_plural       in acs_object_types.pretty_plural%TYPE,
        supertype           in acs_object_types.supertype%TYPE
                               default 'acs_object',
        table_name          in acs_object_types.table_name%TYPE default null,
        id_column           in acs_object_types.id_column%TYPE default 'XXX',
        abstract_p          in acs_object_types.abstract_p%TYPE default 'f',
        type_extension_table in acs_object_types.type_extension_table%TYPE
                                default null,
        name_method         in acs_object_types.name_method%TYPE default null
      );
    
      -- delete an object type definition
      procedure drop_type (
        object_type         in acs_object_types.object_type%TYPE,
        cascade_p           in char default 'f'
      );
    
    
    

    Here the cascade_p argument indicates whether dropping a type should also remove all its subtypes from the system.

    We define a similar interface for defining attributes in the package acs_attribute:

    
      function create_attribute (
        object_type         in acs_attributes.object_type%TYPE,
        attribute_name      in acs_attributes.attribute_name%TYPE,
        datatype            in acs_attributes.datatype%TYPE,
        pretty_name         in acs_attributes.pretty_name%TYPE,
        pretty_plural       in acs_attributes.pretty_plural%TYPE default null,
        table_name          in acs_attributes.table_name%TYPE default null,
        column_name         in acs_attributes.column_name%TYPE default null,
        default_value       in acs_attributes.default_value%TYPE default null,
        min_n_values        in acs_attributes.min_n_values%TYPE default 1,
        max_n_values        in acs_attributes.max_n_values%TYPE default 1,
        sort_order          in acs_attributes.sort_order%TYPE default null,
        storage             in acs_attributes.storage%TYPE default 'type_specific',
        static_p            in acs_attributes.static_p%TYPE default 'f'
      ) return acs_attributes.attribute_id%TYPE;
    
      procedure drop_attribute (
        object_type in varchar,
        attribute_name in varchar
      );
    
    
    
    

    In addition, the following two calls are available for attaching extra annotations onto attributes:

    
      procedure add_description (
        object_type         in acs_attribute_descriptions.object_type%TYPE,
        attribute_name      in acs_attribute_descriptions.attribute_name%TYPE,
        description_key     in acs_attribute_descriptions.description_key%TYPE,
        description         in acs_attribute_descriptions.description%TYPE
      );
    
      procedure drop_description (
        object_type         in acs_attribute_descriptions.object_type%TYPE,
        attribute_name      in acs_attribute_descriptions.attribute_name%TYPE,
        description_key     in acs_attribute_descriptions.description_key%TYPE
      );
    
    
    

    At this point, what you must do to hook into the object system from your own data model becomes clear:

    • Create a table that will store the instances of the new type.

    • Call acs_object_type.create_type() to fill in the metadata table on this new type. If you want your objects to appear in the acs_objects table, then your new type must be a subtype of acs_object.

    • Call acs_attribute.create_attribute() to fill in information on the attributes that this type defines.

    So, suppose we are writing a new version of the ticket tracker for 4.0. We probably define a table to store tickets in, and each ticket might have an ID and a description. If we want each ticket to be an object, then ticket_id must reference the object_id column in acs_objects:

    
    create table tickets ( 
        ticket_id references acs_objects (object_id),
        description varchar(512), 
        ... 
    ) ;
    
    
    

    In addition to defining the table, we need this extra PL/SQL code to hook into the object type tables:

    
    declare
     attr_id acs_attributes.attribute_id%TYPE;
    begin
     acs_object_type.create_type (
       supertype => 'acs_object',
       object_type => 'ticket',
       pretty_name => 'Ticket',
       pretty_plural => 'Tickets',
       table_name => 'tickets',
       id_column => 'ticket_id',
       name_method => 'acs_object.default_name'
     );
    
     attr_id := acs_attribute.create_attribute (
       object_type => 'ticket',
       attribute_name => 'description',
       datatype => 'string',
       pretty_name => 'Description',
       pretty_plural => 'Descriptions'
     );
    
     ... more attributes ...
    
    commit;
    end;
    
    
    

    Thus, with a small amount of extra code, the new ticket tracker will now automatically be hooked into every generic object service that exists. Better still, this code need not be changed as new services are added. As an aside, the most important service that requires you to subtype acs_object is permissions.

    Objects

    The next important piece of the API is defined in the acs_object package, and is concerned with creating and managing objects. This part of the API is designed to take care of the mundane bookkeeping needed to create objects and query their attributes. Realistically however, limitations in PL/SQL and Oracle will make it hard to build generic procedures for doing large scale queries in the object system, so developers who need to do this will probably have to be fairly familiar with the data model at a lower level.

    The function acs_object.new() makes a new object for you. The function acs_object.del() deletes an object. As before, this is an abbreviated interface with all the long type specs removed. See the data model or developer's guide for the full interface.

    
     function new (
      object_id     in acs_objects.object_id%TYPE default null,
      object_type   in acs_objects.object_type%TYPE
                               default 'acs_object',
      creation_date in acs_objects.creation_date%TYPE
                               default sysdate,
      creation_user in acs_objects.creation_user%TYPE
                               default null,
      creation_ip   in acs_objects.creation_ip%TYPE default null,
      context_id    in acs_objects.context_id%TYPE default null
     ) return acs_objects.object_id%TYPE;
    
     procedure delete (
      object_id     in acs_objects.object_id%TYPE
     );
    
    
    

    Next, we define some generic functions to manipulate attributes. Again, these interfaces are useful to an extent, but for large scale queries, it's likely that developers would have to query the data model directly, and then encapsulate their queries in procedures.

    For names, the default_name function is used if you don't want to define your own name function.

    
     function name (
      object_id     in acs_objects.object_id%TYPE
     ) return varchar;
    
     function default_name (
      object_id     in acs_objects.object_id%TYPE
     ) return varchar;
    
    
    
    

    The following functions tell you where attributes are stored, and fetch single attributes for you.

    
     procedure get_attribute_storage ( 
       object_id_in      in  acs_objects.object_id%TYPE,
       attribute_name_in in  acs_attributes.attribute_name%TYPE,
       v_column          out varchar2,
       v_table_name      out varchar2,
       v_key_sql         out varchar2
     );
    
     function get_attribute (
       object_id_in      in  acs_objects.object_id%TYPE,
       attribute_name_in in  acs_attributes.attribute_name%TYPE
     ) return varchar2;
    
     procedure set_attribute (
       object_id_in      in  acs_objects.object_id%TYPE,
       attribute_name_in in  acs_attributes.attribute_name%TYPE,
       value_in          in  varchar2
     );
    
    
    

    The main use of the acs_object package is to create application objects and make them available for services via the acs_objects table. To do this, you just have to make sure you call acs_object.new() on objects that you wish to appear in the acs_objects table. In addition, all such objects must be instances of some subtype of acs_object.

    Continuing the ticket example, we might define the following sort of procedure for creating a new ticket:

    
     function new_ticket (
      package_id        in tickets.ticket_id%TYPE 
                default null,
      description       in tickets.description%TYPE default '',
         ...
      ) return tickets.ticket_id%TYPE 
      is 
       v_ticket_id tickets
      begin
       v_ticket_id := acs_object.new(
          object_id => ticket_id,
          object_type => 'ticket',
            ...
         );
        insert into tickets
        (ticket_id, description)
        values
        (v_ticket_id, description);
        return v_ticket_id;
      end new_ticket;
    
    
    

    This function will typically be defined in the context of a PL/SQL package, but we've left it stand-alone here for simplicity.

    To summarize: in order to take advantage of OpenACS 4 services, a new application need only do three things:

    • Define a data model to describe application objects. This can just be a normal SQL table.

    • Create an object type, using code like in the example from the previous section.

    • Make sure application objects are created using acs_object.new() in addition to whatever SQL code is needed to insert a new row into the application data model.

    One of the design goals of OpenACS 4 was to provide a straightforward and consistent mechanism to provide applications with general services. What we have seen here is that three simple steps and minimal changes in the application data model are sufficient to make sure that application objects are represented in the acs_objects table. Subsequently, all of the general services in OpenACS 4 (i.e. permissions, general comments, and so on) are written to work with any object that appears in acs_objects. Therefore, in general these three steps are sufficient to make OpenACS 4 services available to your application.

    Relation Types

    The relations system defines two packages: acs_rel_type for creating and managing relation types, and acs_rel for relating objects.

    These two procedures just insert and remove roles from the acs_rel_roles table. This table stores the legal relationship "roles" that can be used when creating relation types. Examples of roles are, say, "member", or "employer".

    
     procedure create_role (
        role        in acs_rel_roles.role%TYPE
      );
    
      procedure drop_role (
        role        in acs_rel_roles.role%TYPE
      );
    
    
    

    The main functions in the acs_rel_type package are used to create and drop relation types.

    
      procedure create_type (
        rel_type            in acs_rel_types.rel_type%TYPE,
        pretty_name         in acs_object_types.pretty_name%TYPE,
        pretty_plural       in acs_object_types.pretty_plural%TYPE,
        supertype           in acs_object_types.supertype%TYPE
                               default 'relationship',
        table_name          in acs_object_types.table_name%TYPE,
        id_column           in acs_object_types.id_column%TYPE,
        abstract_p          in acs_object_types.abstract_p%TYPE default 'f',
        type_extension_table in acs_object_types.type_extension_table%TYPE
                                default null,
        name_method         in acs_object_types.name_method%TYPE default null,
        object_type_one     in acs_rel_types.object_type_one%TYPE,
        role_one            in acs_rel_types.role_one%TYPE default null,
        min_n_rels_one      in acs_rel_types.min_n_rels_one%TYPE,
        max_n_rels_one      in acs_rel_types.max_n_rels_one%TYPE,
        object_type_two     in acs_rel_types.object_type_two%TYPE,
        role_two            in acs_rel_types.role_two%TYPE default null,
        min_n_rels_two      in acs_rel_types.min_n_rels_two%TYPE,
        max_n_rels_two      in acs_rel_types.max_n_rels_two%TYPE
      );
    
      procedure drop_type (
        rel_type            in acs_rel_types.rel_type%TYPE,
        cascade_p           in char default 'f'
      );
    
    
    

    Finally, the acs_rel package provides an API that you use to create and destroy instances of a relation type:

    
      function new (
        rel_id              in acs_rels.rel_id%TYPE default null,
        rel_type            in acs_rels.rel_type%TYPE default 'relationship',
        object_id_one       in acs_rels.object_id_one%TYPE,
        object_id_two       in acs_rels.object_id_two%TYPE,
        context_id          in acs_objects.context_id%TYPE default null,
        creation_user       in acs_objects.creation_user%TYPE default null,
        creation_ip         in acs_objects.creation_ip%TYPE default null
      ) return acs_rels.rel_id%TYPE;
    
      procedure delete (
        rel_id      in acs_rels.rel_id%TYPE
      );
    
    
    

    A good example of how to use relation types appears in the OpenACS 4 data model for groups. As in 3.x, group membership is modeled using a mapping table, but now we create this mapping using relation types instead of explicitly creating a table. First, we create a helper table to store state on each membership fact:

    
    create table membership_rels (
            rel_id          constraint membership_rel_rel_id_fk
                            references acs_rels (rel_id)
                            constraint membership_rel_rel_id_pk
                            primary key,
            -- null means waiting for admin approval
            member_state    varchar(20) constraint membership_rel_mem_ck
                            check (member_state in ('approved', 'banned',
                                                    'rejected', 'deleted'))
    );
    
    
    

    Then, we create a new object type to describe groups.

    
     acs_object_type.create_type (
       object_type => 'group',
       pretty_name => 'Group',
       pretty_plural => 'Groups',
       table_name => 'groups',
       id_column => 'group_id',
       type_extension_table => 'group_types',
       name_method => 'acs_group.name'
     );
    
    
    

    In this example, we've made groups a subtype of acs_object to make the code simpler. The actual data model is somewhat different. Also, we've assumed that there is a helper table called groups to store information on groups, and that there is a helper table called group_types that has been defined to store extra attributes on groups.

    Now, assuming we have another object type called person to represent objects that can be group members, we define the following relationship type for group membership:

    
     acs_rel_type.create_role ('member');
    
     acs_rel_type.create_type (
       rel_type => 'membership_rel',
       pretty_name => 'Membership Relation',
       pretty_plural => 'Membership Relationships',
       table_name => 'membership_rels',
       id_column => 'rel_id',
       object_type_one => 'group',
       min_n_rels_one => 0, max_n_rels_one => null,
       object_type_two => 'person', role_two => 'member',
       min_n_rels_two => 0, max_n_rels_two => null
     );
    
    
    

    Now we can define the following procedure to add a new member to a group. All this function does is create a new instance of the membership relation type and then insert the membership state into the helper table that we define above. In the actual implementation, this function is implemented in the membership_rel package. Here we just define an independent function:

    
    function member_add (
        rel_id              in membership_rels.rel_id%TYPE default null,
        rel_type            in acs_rels.rel_type%TYPE default 'membership_rel',
        group               in acs_rels.object_id_one%TYPE,
        member              in acs_rels.object_id_two%TYPE,
        member_state        in membership_rels.member_state%TYPE default null,
        creation_user       in acs_objects.creation_user%TYPE default null,
        creation_ip         in acs_objects.creation_ip%TYPE default null
      ) return membership_rels.rel_id%TYPE
      is
        v_rel_id integer;
      begin
          v_rel_id := acs_rel.new (
          rel_id => rel_id,
          rel_type => rel_type,
          object_id_one => group,
          object_id_two => person,
          context_id => object_id_one,
          creation_user => creation_user,
          creation_ip => creation_ip
        );
    
        insert into membership_rels
         (rel_id, member_state)
        value
         (v_rel_id, new.member_state);
      end;
    
    
    

    Another simple function can be defined to remove a member from a group:

    
      procedure member_delete (
        rel_id  in membership_rels.rel_id%TYPE
      )
      is
      begin
        delete from membership_rels
        where rel_id = membership_rel.delete.rel_id;
    
        acs_rel.del(rel_id);
      end;
    
    
    

    Summary and Discussion

    The Object Model's API and data model provides a small set of simple procedures that allow applications to create object types, object instances, and object relations. Most of the data model is straightforward; the relation type mechanism is a bit more complex, but in return it provides functionality on par with the old user/groups system in a more general way.

    Future Improvements/Areas of Likely Change

    Nothing here yet.

    Authors

    Pete Su generated this document from material culled from other documents by Michael Yoon, Richard Li and Rafael Schloming. But, any remaining lies are his and his alone.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation9/09/2000Pete Su
    0.2Edited for ACS 4 Beta9/30/2000Kai Wu
    0.3Edited for ACS 4.0.1, fixed some mistakes, removed use of term "OM"11/07/2000Pete Su
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n-design.html0000644000175000017500000000646111501005400022724 0ustar frankiefrankie Design Notes

    Design Notes

    User locale is a property of ad_conn, ad_conn locale. The request processor sets this by calling lang::conn::locale, which looks for the following in order of precedence:

    1. Use user preference for this package (stored in ad_locale_user_prefs)

    2. Use system preference for the package (stored in apm_packages)

    3. Use user's general preference (stored in user_preferences)

    4. Use Browser header (Accept-Language HTTP header)

    5. Use system locale (an APM parameter for acs_lang)

    6. default to en_US

    For ADP pages, message key lookup occurs in the templating engine. For TCL pages, message key lookup happens with the _ function. In both cases, if the requested locale is not found but a locale which is the default for the language which matches your locale's language is found, then that locale is offered instead.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n-requirements.html0000644000175000017500000010314611501005400024174 0ustar frankiefrankie OpenACS Internationalization Requirements

    OpenACS Internationalization Requirements

    by Henry Minsky, Yon Feldman, Lars Pind, Peter Marklund, Christian Hvid, and others.

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    This document describes the requirements for functionality in the OpenACS platform to support globalization of the core and optional modules. The goal is to make it possible to support delivery of applications which work properly in multiple locales with the lowest development and maintenance cost.

    Definitions

    internationalization (i18n)

    The provision within a computer program of the capability of making itself adaptable to the requirements of different native languages, local customs and coded character sets.

    locale

    The definition of the subset of a user's environment that depends on language and cultural conventions.

    localization (L10n)

    The process of establishing information within a computer system specific to the operation of particular native languages, local customs and coded character sets.

    globalization

    A product development approach which ensures that software products are usable in the worldwide markets through a combination of internationalization and localization.

    Vision Statement

    The Mozilla project suggests keeping two catchy phrases in mind when thinking about globalization:

    • One code base for the world

    • English is just another language

    Building an application often involves making a number of assumptions on the part of the developers which depend on their own culture. These include constant strings in the user interface and system error messages, names of countries, cities, order of given and family names for people, syntax of numeric and date strings and collation order of strings.

    The OpenACS should be able to operate in languages and regions beyond US English. The goal of OpenACS Globalization is to provide a clean and efficient way to factor out the locale dependent functionality from our applications, in order to be able to easily swap in alternate localizations.

    This in turn will reduce redundant, costly, and error prone rework when targeting the toolkit or applications built with the toolkit to another locale.

    The cost of porting the OpenACS to another locale without some kind of globalization support would be large and ongoing, since without a mechanism to incorporate the locale-specific changes cleanly back into the code base, it would require making a new fork of the source code for each locale.

    System/Application Overview

    A globalized application will perform some or all of the following steps to handle a page request for a specific locale:

    1. Decide what the target locale is for an incoming page request

    2. Decide which character set encoding the output should be delivered in

    3. If a script file to handle the request needs to be loaded from disk, determine if a character set conversion needs to be performed when loading the script

    4. If needed, locale-specific resources are fetched. These can include text, graphics, or other resources that would vary with the target locale.

    5. If content data is fetched from the database, check for locale-specific versions of the data (e.g. country names).

    6. Source code should use a message catalog API to translate constant strings in the code to the target locale

    7. Perform locale-specific linguistic sorting on data if needed

    8. If the user submitted form input data, decide what character set encoding conversion if any is needed. Parse locale-specific quantities if needed (number formats, date formats).

    9. If templating is being used, select correct locale-specific template to merge with content

    10. Format output data quantities in locale-specific manner (date, time, numeric, currency). If templating is being used, this may be done either before and/or after merging the data with a template.

    Since the internationalization APIs may potentially be used on every page in an application, the overhead for adding internationalization to a module or application must not cause a significant time delay in handling page requests.

    In many cases there are facilities in Oracle to perform various localization functions, and also there are facilities in Java which we will want to move to. So the design to meet the requirements will tend to rely on these capabilities, or close approximations to them where possible, in order to make it easier to maintain Tcl and Java OpenACS versions.

    Use-cases and User-scenarios

    Here are the cases that we need to be able to handle efficiently:

    1. A developer needs to author a web site/application in a language besides English, and possibly a character set besides ISO-8859-1. This includes the operation of the OpenACS itself, i.e., navigation, admin pages for modules, error messages, as well as additional modules or content supplied by the web site developer.

      What do they need to modify to make this work? Can their localization work be easily folded in to future releases of OpenACS?

    2. A developer needs to author a web site which operates in multiple languages simultaneously. For example, www.un.org with content and navigation in multiple languages.

      The site would have an end-user visible UI to support these languages, and the content management system must allow articles to be posted in these languages. In some cases it may be necessary to make the modules' admin UI's operate in more than one supported language, while in other cases the backend admin interface can operate in a single language.

    3. A developer is writing a new module, and wants to make it easy for someone to localize it. There should be a clear path to author the module so that future developers can easily add support for other locales. This would include support for creating resources such as message catalogs, non-text assets such as graphics, and use of templates which help to separate application logic from presentation.

    Competitive Analysis

    Other application servers: ATG Dyanmo, Broadvision, Vignette, ... ? Anyone know how they deal with i18n ?

    Requirements

    Because the requirements for globalization affect many areas of the system, we will break up the requirements into phases, with a base required set of features, and then stages of increasing functionality.

    Locales

    10.0

    A standard representation of locale will be used throughout the system. A locale refers to a language and territory, and is uniquely identified by a combination of ISO language and ISO country abbreviations.

    See Content Repository Requirement 100.20

    10.10 Provide a consistent representation and API for creating and referencing a locale

    10.20 There will be a Tcl library of locale-aware formatting and parsing functions for numbers, dates and times. Note that Java has builtin support for these already.

    10.30 For each locale there will be default date, number and currency formats. Currency i18n is NOT IMPLEMENTED for 5.0.0.

    10.40Administrators can upgrade their servers to use new locales via the APM. NOT IMPLEMENTED in 5.0.0; current workaround is to get an xml file and load it manually.

    Associating a Locale with a Request

    20.0

    The request processor must have a mechanism for associating a locale with each request. This locale is then used to select the appropriate template for a request, and will also be passed as the locale argument to the message catalog or locale-specific formatting functions.

    20.10 The locale for a request should be computed by the following method, in descending order of priority:

    • get locale associated with subsite or package id

    • get locale from user preference

    • get locale from site wide default

      20.20 An API will be provided for getting the current request locale from the ad_conn structure.

    Resource Bundles / Content Repository

    30.0

    A mechanism must be provided for a developer to group a set of arbitrary content resources together, keyed by a unique identifier and a locale.

    For example, what approaches could be used to implement a localizable nav-bar mechanism for a site? A navigation bar might be made up of a set of text strings and graphics, where the graphics themselves are locale-specific, such as images of English or Japanese text (as on www.un.org). It should be easy to specify alternate configurations of text and graphics to lay out the page for different locales.

    Design note: Alternative mechanisms to implement this functionality might include using templates, Java ResourceBundles, content-item containers in the Content Repository, or some convention assigning a common prefix to key strings in the message catalog.

    Message Catalog for String Translation

    40.0

    A message catalog facility will provide a database of translations for constant strings for multilingual applications. It must support the following:

    40.10 Each message will referenced via unique a key.

    40.20 The key for a message will have some hierarchical structure to it, so that sets of messages can be grouped with respect to a module name or package path.

    40.30 The API for lookup of a message will take a locale and message key as arguments, and return the appropriate translation of that message for the specifed locale.

    40.40 The API for lookup of a message will accept an optional default string which can be used if the message key is not found in the catalog. This lets the developer get code working and tested in a single language before having to initialize or update a message catalog.

    40.50 For use within templates, custom tags which invoke the message lookup API will be provided.

    40.60 Provide a method for importing and exporting a flat file of translation strings, in order to make it as easy as possible to create and modify message translations in bulk without having to use a web interface.

    40.70 Since translations may be in different character sets, there must be provision for writing and reading catalog files in different character sets. A mechanism must exist for identifying the character set of a catalog file before reading it.

    40.80 There should be a mechanism for tracking dependencies in the message catalog, so that if a string is modified, the other translations of that string can be flagged as needing update.

    40.90 The message lookup must be as efficient as possible so as not to slow down the delivery of pages.

    Character Set Encoding

    Character Sets

    50.0 A locale will have a primary associated character set which is used to encode text in the language. When given a locale, we can query the system for the associated character set to use.

    The assumption is that we are going to use Unicode in our database to hold all text data. Our current programming environments (Tcl/Oracle or Java/Oracle) operate on Unicode data internally. However, since Unicode is not yet commonly used in browsers and authoring tools, the system must be able to read and write other character sets. In particular, conversions to and from Unicode will need to be explicitly performed at the following times:

    • Loading source files (.tcl or .adp) or content files from the filesystem

    • Accepting form input data from users

    • Delivering text output to a browser

    • Composing an email message

    • Writing data to the filesystem

    Acs-templating does the following.

    • When the acs-templating package opens an an ADP or TCL file, it assumes the file is iso-8859-1. If the output charset (OutputCharset) in the AOLserver config file is set, then acs-templating assumes it's that charset. Writing Files

    • When the acs-templating package writes an an ADP or TCL file, it assumes the file is iso-8859-1. If the output charset (OutputCharset) in the AOLserver config file is set, then acs-templating assumes it's that charset.

    Tcl Source File Character Set

    There are two classes of Tcl files loaded by the system; library files loaded at server startup, and page script files, which are run on each page request.

    Should we require all Tcl files be stored as UTF8? That seems too much of a burden on developers.

    50.10 Tcl library files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.

    50.20 Tcl page script files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.

    Submitted Form Data Character Set

    50.30 Data which is submitted with a HTTP request using a GET or POST method may be in any character set. The system must be able to determine the encoding of the form data and convert it to Unicode on demand.

    50.35 The developer must be able to override the default system choice of character set when parsing and validating user form data. INCOMPLETE - form widgets in acs-templating/tcl/date-procs.tcl are not internationalized. Also, acs-templating's UI needs to be internationalized by replacing all user-visible strings with message keys.

    50.30.10In Japan and some other Asian languages where there are multiple character set encodings in common use, the server may need to attempt to do an auto-detection of the character set, because buggy browsers may submit form data in an unexpected alternate encoding.

    Output Character Set

    50.40 The output character set for a page request will be determined by default by the locale associated with the request (see requirement 20.0).

    50.50 It must be possible for a developer to manually override the output character set encoding for a request using an API function.

    ACS Kernel Issues

    60.10 All OpenACS error messages must use the message catalog and the request locale to generate error message for the appropriate locale.NOT IMPLEMENTED for 5.0.0.

    60.20 Web server error messages such as 404, 500, etc must also be delivered in the appropriate locale.

    60.30 Where files are written or read from disk, their filenames must use a character set and character values which are safe for the underlying operating system.

    Templates

    70.0 For a given abstract URL, the designer may create multiple locale-specific template files may be created (one per locale or language)

    70.10 For a given page request, the system must be able to select an approprate locale-specific template file to use. The request locale is computed as per (see requirement 20.0).

    70.20A template file may be created for a partial locale (language only, without a territory), and the request processor should be able to find the closest match for the current request locale.

    70.30 A template file may be created in any character set. The system must have a way to know which character set a template file contains, so it can properly process it.

    Formatting Datasource Output in Templates

    70.50 The properties of a datasource column may include a datatype so that the templating system can format the output for the current locale. The datatype is defined by a standard OpenACS datatype plus a format token or format string, for example: a date column might be specified as 'current_date:date LONG,' or 'current_date:date "YYYY-Mon-DD"'

    Forms

    70.60 The forms API must support construction of locale-specific HTML form widgets, such as date entry widgets, and form validation of user input data for locale-specific data, such as dates or numbers. NOT IMPLEMENTED in 5.0.0.

    70.70 For forms which allow users to upload files, a standard method for a user to indicate the charset of a text file being uploaded must be provided.

    Design note: this presumably applies to uploading data to the content repository as well

    Sorting and Searching

    80.10 Support API for correct collation (sorting order) on lists of strings in locale-dependent way.

    80.20 For the Tcl API, we will say that locale-dependent sorting will use Oracle SQL operations (i.e., we won't provide a Tcl API for this). We require a Tcl API function to return the correct incantation of NLS_SORT to use for a given locale with ORDER BY clauses in queries.

    80.40 The system must handle full-text search in any supported language.

    Time Zones

    90.10 Provide API support for specifying a time zone

    90.20 Provide an API for computing time and date operations which are aware of timezones. So for example a calendar module can properly synchronize items inserted into a calendar from users in different time zones using their own local times.

    90.30 Store all dates and times in universal time zone, UTC.

    90.40 For a registered users, a time zone preference should be stored.

    90.50 For a non-registered user a time zone preference should be attached via a session or else UTC should be used to display every date and time.

    90.60 The default if we can't determine a time zone is to display all dates and times in some universal time zone such as GMT.

    Database

    100.10 Since UTF8 strings can use up to three (UCS2) or six (UCS4) bytes per character, make sure that column size declarations in the schema are large enough to accomodate required data (such as email addresses in Japanese). Since 5.0.0, this is covered in the database install instructions for both PostgreSQL and Oracle.

    Email and Messaging

    When sending an email message, just as when delivering the content in web page over an HTTP connection, it is necessary to be able to specify what character set encoding to use, defaulting to UTF-8.

    110.10 The email message sending API will allow for a character set encoding to be specified.

    110.20 The email accepting API allows for character set to be parsed correctly (the message has a MIME character set content type header)

    Mail is not internationalized. The following issues must be addressed.

    • Many functions still call ns_sendmail. This means that there are different end points for sending mail. This should be changed to use the acs-mail-lite API instead.

    • Consumers of email services must do the following: Determine the appropriate language or languages to use for the message subject and message body and localize them (as in notifications).

    • Extreme Use case: Web site has a default language of Danish. A forum is set up for Swedes, so the forum has a package_id and a language setting of Swedish. A poster posts to the forum in Russian (is this possible?). A user is subscribed to the forum and has a language preference of Chinese. What should be in the message body and message subject?

    • Incoming mail should be localized.

    Implementation Notes

    Because globalization touches many different parts of the system, we want to reduce the implementation risk by breaking the implementation into phases.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    1Updated with results of MIT-sponsored i18n work at Collaboraid.14 Aug 2003Joel Aufrecht
    0.4converting from HTML to DocBook and importing the document to the OpenACS kernel documents. This was done as a part of the internationalization of OpenACS and .LRN for the Heidelberg University in Germany12 September 2002Peter Marklund
    0.3comments from Christian1/14/2000Henry Minsky
    0.2Minor typos fixed, clarifications to wording11/14/2000Henry Minsky
    0.1Creation11/08/2000Henry Minsky
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/parties.html0000644000175000017500000005163111501005400022344 0ustar frankiefrankie Parties in OpenACS

    Parties in OpenACS

    By Rafael H. Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    While many applications must deal with individuals and many applications must deal with groups, most applications must deal with individuals or groups. It is often the case with such applications that both individuals and groups are treated identically. Modelling individuals and groups as specializations of one supertype is a practical way to manage both. This concept is so mundane that there is no need to invent special terminology. This supertype is called a "party".

    A classic example of the "party" supertype is evident in address books. A typical address book might contain the address of a doctor, grocery store, and friend. The first field in an entry in the address book is not labeled a person or company, but a "party".

    The Data Model

    The parties developer guide begins with an introduction to the parties data model, since OpenACS community applications likely require using it in some way.

    Parties

    The central table in the parties data model is the parties table itself. Every party has exactly one row in this table. Every party has an optional unique email address and an optional url. A party is an acs object, so permissions may be granted and revoked on parties and auditing information is stored in the acs objects table.

    
    
    create table parties (
        party_id    not null
                constraint parties_party_id_fk references
                acs_objects (object_id)
                constraint parties_party_id_pk primary key,
        email       varchar(100)
                constraint parties_email_un unique,
        url     varchar(200)
    );
    
    
    

    The persons and groups tables extend the parties table. A row in the persons table represents the most generic form of individual modeled. An individual need not be known to the system as a user. A user is a further specialized form of an individual (discussed later). A row in the groups table represents the most generic form of group modeled, where a group is an aggregation of zero or more individuals.

    Persons

    If a party is an individual then there will be a row in the persons table containing first_names and last_name for that individual. The primary key of the persons table (person_id) references the primary key of the parties table (party_id), so that there is a corresponding row in the parties table when there is a row in the persons table.

    
    create table persons (
        person_id   not null
                constraint persons_person_id_fk
                references parties (party_id)
                constraint persons_person_id_pk primary key,
        first_names varchar(100) not null,
        last_name   varchar(100) not null
    );
    
    
    

    Users

    The users table is a more specialized form of persons table. A row in users table represents an individual that has login access to the system. The primary key of the users table references the primary key of the persons table. This guarantees that if there is a row in users table then there must be a corresponding row in persons and parties tables.

    Decomposing all the information associated with a user into the four tables (acs_objects, parties, persons, users) has some immediate benefits. For instance, it is possible to remove access to a user from a live system by removing his entry from the users table, while leaving the rest of his information present (i.e. turning him from a user into a person).

    Wherever possible the OpenACS data model references the persons or parties table, not the users table. Developers should be careful to only reference the users table in situations where it is clear that the reference is to a user for all cases and not to any other individual for any case.

    
    create table users (
        user_id         not null
                    constraint users_user_id_fk
                    references persons (person_id)
                    constraint users_user_id_pk primary key,
        password        varchar(100),
        salt            varchar(100),
        screen_name     varchar(100)
                    constraint users_screen_name_un
                    unique,
        priv_name       integer default 0 not null,
        priv_email      integer default 5 not null,
        email_verified_p    char(1) default 't'
                    constraint users_email_verified_p_ck
                    check (email_verified_p in ('t', 'f')),
        email_bouncing_p    char(1) default 'f' not null
                    constraint users_email_bouncing_p_ck
                    check (email_bouncing_p in ('t','f')),
        no_alerts_until     date,
        last_visit      date,
        second_to_last_visit    date,
        n_sessions      integer default 1 not null,
        password_question   varchar(1000),
        password_answer     varchar(1000)
    );
    
    
    

    Groups

    The final piece of the parties data model is the groups data model. A group is a specialization of a party that represents an aggregation of zero or more other parties. The only extra information directly associated with a group (beyond that in the parties table) is the name of the group:

    
    create table groups (
        group_id    not null
                constraint groups_group_id_fk
                references parties (party_id)
                constraint groups_group_id_pk primary key,
        group_name  varchar(100) not null
    );
    
    
    

    There is another piece to the groups data model that records relations between parties and groups.

    Group Relations

    Two types of group relations are represented in the data model: membership relations and composite relations. The full range of sophisticated group structures that exist in the real world can be modelled in OpenACS by these two relationship types.

    Membership relations represent direct membership relation between parties and groups. A party may be a "member" of a group. Direct membership relations are common in administrative practices, and do not follow basic set theory rules. If A is a member of B, and B is a member of C, A is not a member of C. Membership relations are not transitive.

    Composition relation represents composite relation between two groups. Composite relation is transitive. That is, it works like memberships in set theory. If A is a member of B, and B is a member of C, then A is a member of C.

    For example, consider the membership relations of Greenpeace, and composite relations of a multinational corporation. Greenpeace, an organization (ie. group), can have both individuals and organizations (other groups) as members. Hence the membership relation between groups and parties. However, someone is not a member of Greenpeace just because they are a member of a group that is a member of Greenpeace. Now, consider a multinational corporation (MC) that has a U.S. division and a Eurasian division. A member of either the U.S. or Eurasian division is automatically a member of the MC. In this situation the U.S. and Eurasian divisions are "components" of the MC, i.e., membership is transitive with respect to composition. Furthermore, a member of a European (or other) office of the MC is automatically a member of the MC.

    Group Membership

    Group memberships can be created and manipulated using the membership_rel package. Only one membership object can be created for a given group, party pair.

    It is possible in some circumstances to make someone a member of a group of which they are already a member. That is because the model distinguishes between direct membership and indirect membership (membership via some composite relationship). For example, a person might be listed in a system as both an individual (direct membership) and a member of a household (indirect membership) at a video rental store.

    
    
    # sql code
    create or replace package membership_rel
    as
    
      function new (
        rel_id      in membership_rels.rel_id%TYPE default null,
        rel_type        in acs_rels.rel_type%TYPE default 'membership_rel',
        object_id_one   in acs_rels.object_id_one%TYPE,
        object_id_two   in acs_rels.object_id_two%TYPE,
        member_state    in membership_rels.member_state%TYPE default null,
        creation_user   in acs_objects.creation_user%TYPE default null,
        creation_ip     in acs_objects.creation_ip%TYPE default null
      ) return membership_rels.rel_id%TYPE;
    
      procedure ban (
        rel_id  in membership_rels.rel_id%TYPE
      );
    
      procedure approve (
        rel_id  in membership_rels.rel_id%TYPE
      );
    
      procedure reject (
        rel_id  in membership_rels.rel_id%TYPE
      );
    
      procedure unapprove (
        rel_id  in membership_rels.rel_id%TYPE
      );
    
      procedure deleted (
        rel_id  in membership_rels.rel_id%TYPE
      );
    
      procedure delete (
        rel_id  in membership_rels.rel_id%TYPE
      );
    
    end membership_rel;
    /
    show errors
    
    
    

    Group Composition

    Composition relations can be created or destroyed using the composition_rel package. The only restriction on compositions is that there cannot be a reference loop, i.e., a group cannot be a component of itself either directly or indirectly. This constraint is maintained for you by the API. So users do not see some random PL/SQL error message, do not give them the option to create a composition relation that would result in a circular reference.

    
    
    # sql code
    create or replace package composition_rel
    as
    
      function new (
        rel_id      in composition_rels.rel_id%TYPE default null,
        rel_type        in acs_rels.rel_type%TYPE default 'composition_rel',
        object_id_one   in acs_rels.object_id_one%TYPE,
        object_id_two   in acs_rels.object_id_two%TYPE,
        creation_user   in acs_objects.creation_user%TYPE default null,
        creation_ip     in acs_objects.creation_ip%TYPE default null
      ) return composition_rels.rel_id%TYPE;
    
      procedure delete (
        rel_id  in composition_rels.rel_id%TYPE
      );
    
    end composition_rel;
    /
    show errors
    
    
    

    Views

    The parties data model does a reasonable job of representing many of the situations one is likely to encounter when modeling organizational structures. We still need to be able to efficiently answer questions like "what members are in this group and all of its components?", and "of what groups is this party a member either directly or indirectly?". Composition relations allow you to describe an arbitrary Directed Acyclic Graph (DAG) between a group and its components. For these reasons the party system provides a bunch of views that take advantage of the internal representation of group relations to answer questions like these very quickly.

    The group_component_map view returns all the subcomponents of a group including components of sub components and so forth. The container_id column is the group_id of the group in which component_id is directly contained. This allows you to easily distinguish whether a component is a direct component or an indirect component. If a component is a direct component then group_id will be equal to container_id. You can think of this view as having a primary key of group_id, component_id, and container_id. The rel_id column points to the row in acs_rels table that contains the relation object that relates component_id to container_id. The rel_id might be useful for retrieving or updating standard auditing info for the relation.

    
    create or replace view group_component_map
    as select group_id, component_id, container_id, rel_id
    ...
    
    
    

    The group_member_map view is similar to group_component_map except for membership relations. This view returns all membership relations regardless of membership state.

    
    create or replace view group_member_map
    as select group_id, member_id, container_id, rel_id
    ...
    
    
    

    The group_approved_member_map view is the same as group_member_map except it only returns entries that relate to approved members.

    
    create or replace view group_approved_member_map
    as select group_id, member_id, container_id, rel_id
    ...
    
    
    

    The group_distinct_member_map view is a useful view if you do not care about the distinction between direct membership and indirect membership. It returns all members of a group including members of components --the transitive closure.

    
    create or replace view group_distinct_member_map
    as select group_id, member_id
    ...
    
    
    

    The party_member_map view is the same as group_distinct_member_map, except it includes the identity mapping. It maps from a party to the fully expanded list of parties represented by that party including the party itself. So if a party is an individual, this view will have exactly one mapping that is from that party to itself. If a view is a group containing three individuals, this view will have four rows for that party, one for each member, and one from the party to itself.

    
    create or replace view party_member_map
    as select party_id, member_id
    ...
    
    
    

    The party_approved_member_map view is the same as party_member_map except that when it expands groups, it only pays attention to approved members.

    
    create or replace view party_approved_member_map
    as select party_id, member_id
    ...
    
    
    

    Extending The Parties Data Model

    The parties data model can represent some fairly sophisticated real world situations. Still, it would be foolish to assume that this data model is sufficiently efficient for every application. This section describes some of the more common ways to extend the parties data model.

    Specializing Users

    Some applications will want to collect more detailed information for people using the system. If there can be only one such piece of information per user, then it might make sense to create another type of individual that is a further specialization of a user. For example a Chess Club community web site might want to record the most recent score for each user. In a situation like this it would be appropriate to create a subtype of users, say chess_club_users. This child table of the users table would have a primary key that references the users table, thereby guaranteeing that each row in the chess_club_users table has a corresponding row in each of the users, persons, parties, and acs_objects tables. This child table could then store any extra information relevant to the Chess Club community.

    Specializing Groups

    If one were to build an intranet application on top of the party system, it is likely that one would want to take advantage of the systems efficient representation of sophisticated organizational structures, but there would be much more specialized information associated with each group. In this case it would make sense to specialize the group party type into a company party type in the same manner as Specializing Users.

    Specializing Membership Relations

    The final portion of the parties data model that is designed to be extended is the membership relationship. Consider the intranet example again. It is likely that a membership in a company would have more information associated with it than a membership in an ordinary group. An obvious example of this would be a salary. It is exactly this need to be able to extend membership relations with mutable pieces of state that drove us to include a single integer primary key in what could be thought of as a pure relation. Because a membership relation is an ordinary acs object with object identity, it is as easy to extend the membership relation to store extra information as it is to extend the users table or the groups table.

    ($Id: parties.html,v 1.49 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-openacs-delete-tablespace.html0000644000175000017500000001314611501005400027331 0ustar frankiefrankie Deleting a tablespace

    Deleting a tablespace

    Skip down for instructions on Deleting a PostgreSQL tablespace.

    Deleting an Oracle tablespace

    Should it become necessary to rebuild a tablespace from scratch, you can use the drop user command in SVRMGRL with the cascade option. This command will drop the user and every database object the user owns.

    SVRMGR> drop user $OPENACS_SERVICE_NAME cascade;

    If this does not work because svrmgrl "cannot drop a user that is currently connected", make sure to kill the AOLserver using this user. If it still does not work, do:

    SVRMGR> select username, sid, serial# from v$session where lower(username)='$OPENACS_SERVICE_NAME';

    and then

    SVRMGR> alter system kill session 'sid, serial#';

    where sid and serial# are replaced with the corresponding values for the open session.

    Use with caution!

    If you feel the need to delete everything related to the service, you can also issue the following:

    SVRMGR> drop tablespace $OPENACS_SERVICE_NAME including contents cascade constraints;

    Deleting a PostgreSQL tablespace

    Dropping a PostgreSQL tablespace is easy. You have to stop any AOLserver instances that are using the database that you wish to drop. If you're using daemontools, this is simple, just use the 'down' flag (-d). If you're using inittab, you have to comment out your server in /etc/inittab, reread the inittab with /sbin/init q, and then restart-aolserver $OPENACS_SERVICE_NAME.

    Then, to drop the db, just do:

    [$OPENACS_SERVICE_NAME ~]$ dropdb $OPENACS_SERVICE_NAME
    DROP DATABASE
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/automated-testing-best-practices.html0000644000175000017500000001216611501005400027241 0ustar frankiefrankie Automated Testing

    Automated Testing

    By Jeff Davis

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Best practices in writing OpenACS automated tests

    • Special characters in Tcl.  Try strings starting with a -Bad and strings containing [BAD], {, \077, and $Bad. For user input, [BAD] should never be evaluated, \077 should not be turned into a ? and $Bad should not be interpolated. The string -Bad [BAD] \077 { $Bad should be valid user input, should pass through the system unaltered, and if it isn't that's a bug.

    • Quoting issues. Put some html in plain text fields and make sure the result is properly quoted anywhere it shows up (I use "<b>bold</b>" usually). Look out especially for quoting errors in the context bar and in round trips via an edit form. For fields that disallow html tags you can use &amp; to check that the field is quoted properly. If it is not displayed as &amp; then the quoting for the field is incorrect. (It's not clear whether this should be considered an error but given that data for text fields can come from various sources if it's text it should be properly quoted and we should not rely on input validation to prevent XSS security holes.)

    • Whitespace input. Check that whitespace is not considered valid input for a field if it does not make sense. For example, the subject of a forum post is used to construct a link and if it is " " it will have a link of <a href="..."> </a> which would not be clickable if whitespace was allowed as a valid input.

    • Doubleclick.  Make sure that if you submit a form, use the back button, and submit again that the behavior is reasonable (correct behavior depends on what the form is for, but a server error is not reasonable).

    • Duplicate names.  Make sure that if a duplicate name is entered that there is a reasonable error rather than a server error. Check for insert, move, copy, and rename.

    ($Id: automated-testing-best-practices.html,v 1.26 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/rp-design.html0000644000175000017500000004236411501005400022570 0ustar frankiefrankie Request Processor Design

    Request Processor Design

    By Rafael H. Schloming

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    The request processor is the set of procs that responds to every HTTP request made to the OpenACS. The request processor must authenticate the connecting user, and make sure that he is authorized to perform the given request. If these steps succeed, then the request processor must locate the file that is associated with the specified URL, and serve the content it provides to the browser.

    Related Systems

    Terminology

    • pageroot -- Any directory that contains scripts and/or static files intended to be served in response to HTTP requests. A typical OpenACS installation is required to serve files from multiple pageroots.

    • global pageroot (/var/lib/aolserver/servicename/www) -- Files appearing under this pageroot will be served directly off the base url http://www.servicename.com/

    • package root (/var/lib/aolserver/servicename/packages) -- Each subdirectory of the package root is a package. A typical OpenACS installation will have several packages.

    • package pageroot (/var/lib/aolserver/servicename/packages/package_key/www) -- This is the pageroot for the package_key package.

    • request environment (ad_conn) -- This is a global namespace containing variables associated with the current request.

    • abstract URL -- A URL with no extension that doesn't directly correspond to a file in the filesystem.

    • abstract file or abstract path -- A URL that has been translated into a file system path (probably by prepending the appropriate pageroot), but still doesn't have any extension and so does not directly correspond to a file in the filesystem.

    • concrete file or concrete path -- A file or path that actually references something in the filesystem.

    System Overview

    Package Lookup

    One of the first things the request processor must do is to determine which package instance a given request references, and based on this information, which pageroot to use when searching for a file to serve. During this process the request processor divides the URL into two pieces. The first portion identifies the package instance. The rest identifies the path into the package pageroot. For example if the news package is mounted on /offices/boston/announcements/, then a request for /offices/boston/announcements/index would be split into the package_url (/offices/boston/announcements/), and the abstract (no extension info) file path (index). The request processor must be able to figure out which package_id is associated with a given package_url, and package mountings must be persistent across server restarts and users must be able to manipulate the mountings on a live site, therefore this mapping is stored in the database.

    Authentication and Authorization

    Once the request processor has located both the package_id and concrete file associated with the request, authentication is performed by the session security system. After authentication has been performed the user is authorized to have read access for the given package by the OpenACS 4 Permissions Design. If authorization succeeds then the request is served, otherwise it is aborted.

    Concrete File Search

    To actually serve a file, the request processor generates an ordered list of abstract paths and searches each path for a concrete file. The first path searched is composed of the package pageroot with the extra portion of the URL appended. The second abstract path consists of the global pageroot with the full URL appended. This means that if an instance of the news package is mounted on /offices/boston/announcements/, then any requests that are not matched by something in the news package pageroot could be matched by something under the global pageroot in the /offices/boston/announcements/ directory. Files take precedence over directory listings, so an index file in the global pageroot will be served instead of a directory listing in the package pageroot, even though the global pageroot is searched later. If a file is found at any of the searched locations then it is served.

    Virtual URL Handlers

    If no file is found during the concrete file search, then the request processor searches the filesystem for a virtual url handler (.vuh) file. This file contains normal tcl code, and is in fact handled by the same extension handling procedure that handles .tcl files. The only way this file is treated differently is in how the request processor searches for it. When a lookup fails, the request processor generates each valid prefix of all the abstract paths considered in the concrete file search, and searches these prefixes in order from most specific to least specific for a matching .vuh file. If a file is found then the ad_conn variable path_info is set to the portion of the url not matched by the .vuh script, and the script is sourced. This facility is intended to replace the concept of registered procs, since no special distinction is required between sitewide procs and package specific procs when using this facility. It is also much less prone to overlap and confusion than the use of registered procs, especially in an environment with many packages installed.

    Site Nodes

    The request processor manages the mappings from URL patterns to package instances with the site_nodes data model. Every row in the site_nodes table represents a fully qualified URL. A package can be mounted on any node in this data model. When the request processor performs a URL lookup, it determines which node matches the longest possible prefix of the request URI. In order to make this lookup operation as fast as possible, the rows in the site_nodes table are pulled out of the database at server startup, and stored in memory.

    The memory structure used to store the site_nodes mapping is a hash table that maps from the fully qualified URL of the node, to the package_id and package_key of the package instance mounted on the node. A lookup is performed by starting with the full request URI and successively stripping off the rightmost path components until a match is reached. This way the time required to lookup a URL is proportional to the length of the URL, not to the number of entries in the mapping.

    Request Environment

    The request environment is managed by the procedure ad_conn. Variables can be set and retrieved through use of the ad_conn procedure. The following variables are available for public use. If the ad_conn procedure doesn't recognize a variable being passed to it for a lookup, it tries to get a value using ns_conn. This guarantees that ad_conn subsumes the functionality of ns_conn.

    Request processor
    [ad_conn urlv] A list containing each element of the URL
    [ad_conn url] The URL associated with the request.
    [ad_conn query] The portion of the URL from the ? on (i.e. GET variables) associated with the request.
    [ad_conn file] The filepath including filename of the file being served
    [ad_conn request] The number of requests since the server was last started
    [ad_conn start_clicks] The system time when the RP starts handling the request
    Session System Variables: set in sec_handler, check security with ad_validate_security_info
    [ad_conn session_id] The unique session_id coming from the sequence sec_id_seq
    [ad_conn user_id] User_id of a person if the person is logged in. Otherwise, it is blank
    [ad_conn sec_validated] This becomes "secure" when the connection uses SSL
    Database API
    [ad_conn db,handles] What are the list of handles available to AOL?
    [ad_conn db,n_handles_used] How many database handles are currently used?
    [ad_conn db,last_used] Which database handle did we use last?
    [ad_conn db,transaction_level,$db] Specifies what transaction level we are in
    [ad_conn db,db_abort_p,$dbh] Whether the transaction is aborted
    APM
    [ad_conn xml_loaded_p] Checks whether the XML parser is loaded so that it only gets loaded once. Set in apm_load_xml_packages
    Packages
    [ad_conn package_id] The package_id of the package associated with the URL.
    [ad_conn package_url] The URL on which the package is mounted.
    Miscellaneous
    [ad_conn system_p] If true then the request has been made to one of the special directories specified in the config file (somewhere), and no authentication or authorization has been performed.
    Documentation
    [ad_conn api_page_documentation_mode_p]  
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/filename.html0000644000175000017500000003676111456662477022524 0ustar frankiefrankie Detailed Design Documentation Template

    Detailed Design Documentation Template

    By You

    Start Note

    NOTE: Some of the sections of this template may not apply to your package, e.g. there may be no user-visible UI elements for a component of the OpenACS Core. Furthermore, it may be easier in some circumstances to join certain sections together, e.g. it may make sense to discuss the data model and transactions API together instead of putting them in separate sections. And on occasion, you may find it easier to structure the design discussion by the structure used in the requirements document. As this template is just a starting point, use your own judgment, consult with peers when possible, and adapt intelligently.

    Also, bear in mind the audience for detailed design: fellow programmers who want to maintain/extend the software, AND parties interested in evaluating software quality.

    Essentials

    When applicable, each of the following items should receive its own link:

    • User directory

    • OpenACS administrator directory

    • Subsite administrator directory

    • Tcl script directory (link to the API browser page for the package)

    • PL/SQL file (link to the API browser page for the package)

    • Data model

    • Requirements document

    • ER diagram

    • Transaction flow diagram

    Introduction

    This section should provide an overview of the package and address at least the following issues:

    • What this package is intended to allow the user (or different classes of users) to accomplish.

    • Within reasonable bounds, what this package is not intended to allow users to accomplish.

    • The application domains where this package is most likely to be of use.

    • A high-level overview of how the package meets its requirements (which should have been documented elsewhere). This is to include relevant material from the "features" section of the cover sheet (the cover sheet is a wrapper doc with links to all other package docs).

    Also worthy of treatment in this section:

    • When applicable, a careful demarcation between the functionality of this package and others which - at least superficially - appear to address the same requirements.

    Note: it's entirely possible that a discussion of what a package is not intended to do differs from a discussion of future improvements for the package.

    Historical Considerations

    For a given set of requirements, typically many possible implementations and solutions exist. Although eventually only one solution is implemented, a discussion of the alternative solutions canvassed - noting why they were rejected - proves helpful to both current and future developers. All readers would be reminded as to why and how the particular solution developed over time, avoiding re-analysis of problems already solved.

    Competitive Analysis

    Although currently only a few package documentation pages contain a discussion of competing software, (e.g. chat, portals), this section should be present whenever such competition exists.

    • If your package exhibits features missing from competing software, this fact should be underscored.

    • If your package lacks features which are present in competing software, the reasons for this should be discussed here; our sales team needs to be ready for inquiries regarding features our software lacks.

    Note that such a discussion may differ from a discussion of a package's potential future improvements.

    Design Tradeoffs

    No single design solution can optimize every desirable software attribute. For example, an increase in the security of a system will likely entail a decrease in its ease-of-use, and an increase in the flexibility/generality of a system typically entails a decrease in the simplicity and efficiency of that system. Thus a developer must decide to put a higher value on some attributes over others: this section should include a discussion of the tradeoffs involved with the design chosen, and the reasons for your choices. Some areas of importance to keep in mind are:

    Areas of interest to users:

    • Performance: availability and efficiency

    • Flexibility

    • Interoperability

    • Reliability and robustness

    • Usability

    Areas of interest to developers:

    • Maintainability

    • Portability

    • Reusability

    • Testability

    API

    Here's where you discuss the abstractions used by your package, such as the procedures encapsulating the legal transactions on the data model. Explain the organization of procedures and their particulars (detail above and beyond what is documented in the code), including:

    • Problem-domain components: key algorithms, e.g. a specialized statistics package would implement specific mathematical procedures.

    • User-interface components: e.g. HTML widgets that the package may need.

    • Data management components: procedures that provide a stable interface to database objects and legal transactions - the latter often correspond to tasks.

    Remember that the correctness, completeness, and stability of the API and interface are what experienced members of our audience are looking for. This is a cultural shift for us at aD (as of mid-year 2000), in that we've previously always looked at the data models as key, and seldom spent much effort on the API (e.g. putting raw SQL in pages to handle transactions, instead of encapsulating them via procedures). Experience has taught us that we need to focus on the API for maintainability of our systems in the face of constant change.

    Data Model Discussion

    The data model discussion should do more than merely display the SQL code, since this information is already be available via a link in the "essentials" section above. Instead, there should be a high-level discussion of how your data model meets your solution requirements: why the database entities were defined as they are, and what transactions you expect to occur. (There may be some overlap with the API section.) Here are some starting points:

    • The data model discussion should address the intended usage of each entity (table, trigger, view, procedure, etc.) when this information is not obvious from an inspection of the data model itself.

    • If a core service or other subsystem is being used (e.g., the new parties and groups, permissions, etc.) this should also be mentioned.

    • Any default permissions should be identified herein.

    • Discuss any data model extensions which tie into other packages.

    • Transactions

      Discuss modifications which the database may undergo from your package. Consider grouping legal transactions according to the invoking user class, i.e. transactions by an OpenACS-admin, by subsite-admin, by a user, by a developer, etc.

    User Interface

    In this section, discuss user interface issues and pages to be built; you can organize by the expected classes of users. These may include:

    • Developers

    • OpenACS administrators (previously known as site-wide administrators)

    • Subsite administrators

    • End users

    You may want to include page mockups, site-maps, or other visual aids. Ideally this section is informed by some prototyping you've done, to establish the package's usability with the client and other interested parties.

    Note: In order that developer documentation be uniform across different system documents, these users should herein be designated as "the developer," "the OpenACS-admin," "the sub-admin," and "the user," respectively.

    Finally, note that as our templating system becomes more entrenched within the OpenACS, this section's details are likely to shift from UI specifics to template interface specifics.

    Configuration/Parameters

    Under OpenACS 5.6.0, parameters are set at two levels: at the global level by the OpenACS-admin, and at the subsite level by a sub-admin. In this section, list and discuss both levels of parameters.

    Future Improvements/Areas of Likely Change

    If the system presently lacks useful/desirable features, note details here. You could also comment on non-functional improvements to the package, such as usability.

    Note that a careful treatment of the earlier "competitive analysis" section can greatly facilitate the documenting of this section.

    Authors

    Although a system's data model file often contains this information, this isn't always the case. Furthermore, data model files often undergo substantial revision, making it difficult to track down the system creator. An additional complication: package documentation may be authored by people not directly involved in coding. Thus to avoid unnecessary confusion, include email links to the following roles as they may apply:

    • System creator

    • System owner

    • Documentation author

    Revision History

    The revision history table below is for this template - modify it as needed for your actual design document.

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.3Edited further, incorporated feedback from Michael Yoon9/05/2000Kai Wu
    0.2Edited8/22/2000Kai Wu
    0.1Creation8/21/2000Josh Finkler, Audrey McLoghlin
    ($Id: filename.html,v 1.46 2010/10/17 21:06:07 donb Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/psgml-mode.html0000644000175000017500000002523211501005400022737 0ustar frankiefrankie Using PSGML mode in Emacs

    Using PSGML mode in Emacs

    By David Lutterkort

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Note: nxml mode replaces and/or complements psgml mode. More information.

    What it is

    PSGML Mode is a mode for editing, umm, SGML and XML documents in emacs. It can parse a DTD and help you insert the right tags in the right place, knows about tags' attributes and can tell you in which contexts a tag can be used. If you give it the right DTD, that is. But even without a DTD, it can save you some typing since pressing C-c/ will close an open tag automatically.

    Where to get it

    Most newer emacsen come with PSGML mode preinstalled. You can find out whether your emacs has it with the locate-library command. In Emacs, type M-x locate-library and enter psgml. Emacs will tell you if it found it or not.

    If you don't have PSGML preinstalled in your Emacs, there are two things you can do:

    1. On Linux: Get the psgml rpm from RedHat's docbook-tools and install it as usual.

    2. On other systems: Get the tarball from the PSGML Website. Unpack it and follow the install instructions.

    Using CATALOG files

    The easiest way to teach PSGML mode about a DTD is by adding it to your own CATALOG. Here is an example of how you can set that up for the Docbook XML DTD.

    1. Get the Docbook XML DTD zip archive from docbook.org

    2. Go somewhere in your working directory and do

            mkdir -p dtd/docbook-xml
            cd dtd/docbook-xml
            unzip -a <docbook XML DTD zip archive>
         
      
    3. Create a file with the name CATALOG in the dtd directory and put the line

            CATALOG "docbook-xml/docbook.cat"
      

      in it. By maintaining your own CATALOG, it is easy to add more DTD's without changing your emacs settings. (How about that HTML 4.01 DTD you always wanted to get from W3C ? The DTD is in the zip archives and tarballs available on the site.)

    That's it. Now you are ready to tell emacs all about PSGML mode and that funky CATALOG

    What to tell emacs

    If you installed PSGML mode in a non-standard location, e.g., somewhere in your home directory, you need to add this to the load-path by adding this line to your .emacs file:

          (add-to-list 'load-path "/some/dir/that/contains/psgml.elc")
       
    

    To let PSGML mode find your CATALOG and to enable PSGML mode for all your editing, add these lines to your .emacs:

          (require 'psgml)
    
          (add-to-list 'auto-mode-alist '("\\.html" . sgml-mode))
          (add-to-list 'auto-mode-alist '("\\.adp" . xml-mode))
          (add-to-list 'auto-mode-alist '("\\.xml" . xml-mode))
          (add-to-list 'auto-mode-alist '("\\.xsl" . xml-mode))
          
          (add-to-list 'sgml-catalog-files "/path/to/your/dtd/CATALOG")
       
    

    If you want font-locking and indentation, you can also add these lines into the .emacs file:

          (setq sgml-markup-faces '((start-tag . font-lock-function-name-face)
                                    (end-tag . font-lock-function-name-face)
                    (comment . font-lock-comment-face)
                    (pi . bold)
                    (sgml . bold)
                    (doctype . bold)
                    (entity . font-lock-type-face)
                    (shortref . font-lock-function-name-face)))
          (setq sgml-set-face t)
          (setq-default sgml-indent-data t)
          ;; Some convenient key definitions:
          (define-key sgml-mode-map "\C-c\C-x\C-e" 'sgml-describe-element-type)
          (define-key sgml-mode-map "\C-c\C-x\C-i" 'sgml-general-dtd-info)
          (define-key sgml-mode-map "\C-c\C-x\C-t" 'sgml-describe-entity)
       
    

    What is a DOCTYPE ?

    All SGML and XML documents that should conform to a DTD have to declare a doctype. For the docbook XML, all your .xml files whould start with the line

          <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "docbookx.dtd">
       
    

    If your document is only part of a larger XML document, you can tell PSGML mode about it by appending the following lines to your file. In this case, do not include a DOCTYPE declaration in your file.

          <!--
           Local Variables:
           sgml-parent-document: ("top.xml" "book" "sect1")
           End:
          -->
       
    

    Which says that the parent of this document can be found in the file top.xml, that the element in the parent that will enclose the current document is a book and that the current file's topmost element is a sect1.

    How to use it

    Of course, you should read the emacs texinfo pages that come with PSGML mode from start to finish. Barring that, here are some handy commands:

    KeyCommand
    C-c C-eInsert an element. Uses completion and only lets you insert elements that are valid
    C-c C-aEdit attributes of enclosing element.
    C-c C-x C-iShow information about the document's DTD.
    C-c C-x C-eDescribe element. Shows for one element which elements can be parents, what its contents can be and lists its attributes.

    Further reading

    Start with the OpenACS Documentation Guide

    ($Id: psgml-mode.html,v 1.46 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-etp-templates.html0000644000175000017500000002353111501005400025320 0ustar frankiefrankie OpenACS Edit This Page Templates

    OpenACS Edit This Page Templates

    by Nick Carroll

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Goals

    • Learn about the OpenACS templating system.

    • Learn about subsites and site-map administration.

    Introduction

    The OpenACS templating system allows you to give your site a consistent look and feel. It also promotes code maintainability in the presentation layer, by allowing presentation components to be reused across multiple pages. If you need to change the layout for some reason, then you only need to make that change in one location, instead of across many files.

    In this problem set you will familiarise yourself with the templating system in openacs. This will be achieved through customising an existing edit-this-page application template.

    Before proceeding, it is strongly advised to read the templating documentation on your openacs installation (http://localhost:8000/doc/acs-templating). The documentation lists the special tags available for ADP files.

    Exercise 1: Create a Subsite

    • Create a subsite called pset3.

    • A subsite is simply a directory or subdirectory mounted at the end of your domain name. This can be done in one of two places:

      • http://localhost:8000/admin/site-map

      • or the subsite admin form on the main site, which is available when you login to your OpenACS installation.

    Exercise 2: Checkout and Install edit-this-page (ETP)

    • Checkout ETP from CVS:

      cd ~/openacs/packages
                  cvs -d:pserver:anonymous@openacs.org:/cvsroot login
                  cvs -d:pserver:anonymous@openacs.org:/cvsroot co edit-this-page
    • Go to the package manager at http://yoursite/acs-admin/apm. And install the new package: edit-this-page.

    • Or use the "Add Application" form available on the Main site.

    Change ETP Application

    • Work out how to change the ETP application.

    • Investigate each of the available ETP templates:

      • Default

      • News

      • FAQ

    Exercise 4: Create a New ETP Template

    • Browse the files for each of the above ETP templates at:

      cd ~/openacs/packages/edit-this-page/templates
    • Use the article template as the basis of our new col2 template.

      cp article-content.adp col2-content.adp
                  cp article-content.tcl col2-content.tcl
                  cp article-index.adp col2-index.adp
                  cp article-index.tcl col2-index.tcl
    • The template should provide us with the following ETP layout:

      Table 9.1. table showing ETP layout

      Header
      SidebarMain Content Pane

    • The "Main Content" pane should contain the editable content that ETP provides.

    • The "Header" should display the title of the page that you set in ETP.

    • The "Sidebar" should display the extlinks that you add as a content item in ETP.

    Exercise 5: Register the col2 Template with ETP

    • Need to register your template with ETP so that it appears in the drop-down menu that you would have seen in Exercise 3.

      cd ~/openacs/packages/edit-this-page/tcl
                  emacs etp-custom-init.tcl
    • Use the function etp::define_application to register your template with ETP

      • Uncomment the "asc" definition

      • Set allow_extlinks to true, the rest should be false.

    • Restart your server for the changes to take effect.

    Exercise 6: Configure ETP to use the col2 Template

    • Configure your ETP instance at /lab4/index to use the col2 template.

    • Create external links to link to other mounted ETP instances.

    • Check that your external links show up in the sidebar when you view your ETP application using the col2 template.

    Who Wrote This and When

    This problem set was originally written by Nick Carroll in August 2004 for the University of Sydney Course EBUS5002.

    This material is copyright 2004 by Nick Carroll. It may be copied, reused, and modified, provided credit is given to the original author.

    ($Id: tutorial-etp-templates.html,v 1.8 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-wysiwyg-editor.html0000644000175000017500000002042011501005400025534 0ustar frankiefrankie Enabling WYSIWYG

    Enabling WYSIWYG

    by Nima Mazloumi

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Most of the forms in OpenACS are created using the form builder, see Using Form Builder: building html forms dynamically. For detailed information on the API take a look here.

    The following section shows how you can modify your form to allow WYSIWYG functionalities.

    Convert your page to use ad_form (some changes but worth it)

    Here an examples. From:

    	template::form create my_form
    	template::element create my_form my_form_id -label "The ID" -datatype integer -widget hidden
    	template::element create my_form my_input_field_1 -html { size 30 } -label "Label 1" -datatype text -optional
    	template::element create my_form my_input_field_2 -label "Label 2" -datatype text -help_text "Some Help" -after_html {<a name="#">Anchor</a>}
    	

    To:

    	ad_form -name my_form -form {
    		my_form_id:key(acs_object_id_seq)
     		{my_input_field_1:text,optional
                   {label "Label 1"}
                   {html {size 30}}}
          	{my_input_field_2:text
                   {label "Label 2"}
                   {help_text "Some Help"}
    	       	   {after_html
                   {<a name="#">Anchor</a>}}}
    	} ...
    	

    Warning

    You must not give your your form the same name that your page has. Otherwise HTMLArea won't load.

    Convert your textarea widget to a richtext widget and enable htmlarea.

    The htmlarea_p-flag can be used to prevent WYSIWYG functionality. Defaults to true if left away.

    From:

    	{my_input_field_2:text
    	

    To:

    	{my_input_field_2:richtext(richtext)
    			{htmlarea_p "t"}
    	

    The richtext widget presents a list with two elements: text and content type. To learn more on existing content types search in Google for "MIME-TYPES" or take a look at the cr_mime_types table.

    Make sure that both values are passed as a list to your ad_form or you will have problems displaying the content or handling the data manipulation correctly.

    Depending on the data model of your package you either support a content format or don't. If you don't you can assume "text/html" or "text/richtext" or "text/enhanced".

    The relevant parts in your ad_form definition are the switches -new_data, -edit_data, -on_request and -on_submit.

    To allow your data to display correctly you need to add an -on_request block. If you have the format stored in the database pass this as well else use "text/html":

    	set my_input_field_2 [template::util::richtext::create $my_input_field_2 "text/html"]
    	

    Now make sure that your SQL queries that do the data manipulation retrieve the correct value. If you simply use my_input_field_2 you will store a list. Thus you need to add an -on_submit block:

    	set my_input_field_2 [ template::util::richtext::get_property contents $my_input_field_2]
    	set format [ template::util::richtext::get_property format $my_input_field_2] #This is optional
    	

    Now the correct values for my_input_field_2 and format are passed to the -new_data and -edit_data blocks which don't need to get touched.

    To make HTMLArea optional per package instance define a string parameter UseWysiwygP which defaults 0 for your package using the APM.

    In your edit page make the following changes

    	# Is WYSIWYG enabled?
    	set use_wysiwyg_p [parameter::get -parameter "UseWysiwygP" -default "f"]
    	
    	...
    	
    	{htmlarea_p $use_wysiwyg_p}
    	

    The -on_request switch should set this value for your form.

    	set htmlarea_p $use_wysiwyg_p
    	

    All you need now is a configuration page where the user can change this setting. Create a configure.tcl file:

    	ad_page_contract {
    
        	This page allows a faq admin to change the UseWysiwygP setting
    
    	} {
        	{return_url ""}
    	}
    
    	set title "Should we support WYSIWYG?"
    	set context [list $title]
    
    	set use_wysiwyg_p
    
    	ad_form -name categories_mode -form {
        	{enabled_p:text(radio)
            	{label "Enable WYSIWYG"}
            	{options {{Yes t} {No f}}}
            	{value $use_wysiwyg_p}
        	}
        	{return_url:text(hidden) {value $return_url}}
        	{submit:text(submit) {label "Change"}}
    	} -on_submit {
        	parameter::set_value  -parameter "UseWysiwygP" -value $enabled_p
        	if {![empty_string_p $return_url]} {
            	ns_returnredirect $return_url
        	}
    	}
    	

    In the corresponding ADP file write

    	<master>
    	<property name="title">@title@</property>
    	<property name="context">@context@</property>
    
    	<formtemplate id="categories_mode"></formtemplate>
    	

    And finally reference this page from your admin page

    	#TCL:
    	set return_url [ad_conn url]
    
    	#ADP:
    	<a href=configure?<%=[export_url_vars return_url]%>>Configure</a>
    	
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-nsopenssl.html0000644000175000017500000002307011501005400024361 0ustar frankiefrankie Install nsopenssl

    Install nsopenssl

    By Joel Aufrecht and Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This AOLserver module is required if you want people to connect to your site via https. These commands compile nsopenssl and install it, along with a tcl helper script to handle https connections. You will also need ssl certificates. Because those should be different for each server service, you won't need those instructions until later.

    Install on AOLserver3

    You will need the unpacked Aolserver tarball in /usr/local/src/aolserver and the nsopenssl tarball in /tmp.

    Red Hat 9 note: see this thread for details on compiling nsopenssl.)

    [root bin]# cd /usr/local/src/aolserver
    [root aolserver]# wget --passive http://www.scottg.net/download/nsopenssl-2.1.tar.gz
    [root aolserver]# tar xzf nsopenssl-2.1.tar.gz 
    [root aolserver]# cd nsopenssl-2.1
    [root nsopenssl-2.1]# make OPENSSL=/usr/local/ssl
    gcc -I/usr/local/ssl/include -I../aolserver/include -D_REENTRANT=1 -DNDEBUG=1 -g -fPIC -Wall -Wno-unused -mcpu=i686 -DHAVE_CMMSG=1 -DUSE_FIONREAD=1 -DHAVE_COND_EINTR=1   -c -o nsopenssl.o nsopenssl.c
    (many lines omitted)
    gcc -shared -nostartfiles -o nsopenssl.so nsopenssl.o config.o init.o ssl.o thread.o tclcmds.o -L/usr/local/ssl/lib -lssl -lcrypto
    [root nsopenssl-2.1]# cp nsopenssl.so /usr/local/aolserver/bin
    [root nsopenssl-2.1]# cp https.tcl /usr/local/aolserver/modules/tcl/
    [root nsopenssl-2.1]#
    cd /usr/local/src/aolserver
    wget --passive http://www.scottg.net/download/nsopenssl-2.1.tar.gz
    tar xzf nsopenssl-2.1.tar.gz 
    cd nsopenssl-2.1 
    make OPENSSL=/usr/local/ssl 
    cp nsopenssl.so /usr/local/aolserver/bin 
    cp https.tcl /usr/local/aolserver/modules/tcl/

    For Debian (more information):

    apt-get install libssl-dev
    cd /usr/local/src/aolserver
    tar xzf /tmp/nsopenssl-2.1.tar.gz
    cd nsopenssl-2.1
    make OPENSSL=/usr/lib/ssl
    cp nsopenssl.so /usr/local/aolserver/bin
    cp https.tcl /usr/local/aolserver/modules/tcl/

    Install on AOLserver4

    You will need the AOLserver4 source in /usr/local/src/aolserver/aolserver and OpenSSL installed in /usr/local/ssl (or at least symlinked there). The use of INST=/point/to/aolserver is being replaced with AOLSERVER=/point/to/aolserver. We are including both here, because while this module still requires INST, if one just uses AOLSERVER, the default value would be used and could intefere with another existing installation.

    FreeBSD note: build nsopenssl with gmake install OPENSSL=/usr/local/openssl AOLSERVER=/usr/local/aolserver4r10

    [root bin]# cd /usr/local/src/aolserver
    [root aolserver]# cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver login
    [root aolserver]# cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nsopenssl
    [root aolserver]# cd nsopenssl
    [root nsopenssl]# make OPENSSL=/usr/local/ssl
    gcc -I/usr/local/ssl/include (many items omitted)  -c -o sslcontext.o sslcontext.c
    (many lines omitted)
    [root nsopenssl-2.1]# make install OPENSSL=/usr/local/ssl AOLSERVER=/usr/local/aolserver4r10 INST=/usr/local/aolserver4r10
    [root nsopenssl-2.1]#
    cd /usr/local/src/aolserver
    cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver login
    cvs -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/aolserver co nsopenssl
    cd nsopenssl
    make OPENSSL=/usr/local/ssl 
    make install OPENSSL=/usr/local/ssl AOLSERVER=/usr/local/aolserver AOLSERVER=/usr/local/aolserver4r10

    If you have problems starting your server with nsopenssl.so due to missing libssl.so.0.9.7 (or lower), you have to create symlinks

    [root nsopenssl]# cd /usr/local/aolserver/lib
    [root lib]# ln -s /usr/local/ssl/lib/libssl.so.0.9.7 libssl.so.0.9.7
    [root lib]# ln -s /usr/local/ssl/lib/libcrypto.so.0.9.7 libcrypto.so.0.9.7
    [root lib]#
    cd /usr/local/aolserver/lib
    ln -s /usr/local/ssl/lib/libssl.so.0.9.7 libssl.so.0.9.7
    ln -s /usr/local/ssl/lib/libcrypto.so.0.9.7 libcrypto.so.0.9.7
    
    

    SSL support must be enabled seperately in each OpenACS server (Generate ssl certificates.

    If your ports for SSL are privileged (below 1024), you will have to start AOLserver with prebinds for both your HTTP and your HTTPS port (usually by adding -b your_ip:your_http_port,your_ip:your_https_port to the nsd call. If you are using daemontools, this can be changed in your etc/daemontools/run file).

    To enable SSL support in your server, make sure your etc/config.tcl file has a section on "OpenSSL 3 with AOLserver4". If that section is not present, try looking at the README file in /usr/local/src/aolserver/nsopenssl.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-redhat.html0000644000175000017500000006434211501005400023613 0ustar frankiefrankie Appendix A. Install Red Hat 8/9

    Appendix A. Install Red Hat 8/9

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This section takes a blank PC and sets up some supporting software. You should do this section as-is if you have a machine you can reformat and you want to be sure that your installation works and is secure; it should take about an hour. (In my experience, it's almost always a net time savings of several hours to install a new machine from scratch compared to installing each of these packages installed independently.)

    The installation guide assumes you have:

    • A PC with hard drive you can reinstall

    • Red Hat 8.0 or 9.0 install discs

    • A CD with the current Security Patches for your version of Red Hat.

    The installation guide assumes that you can do the following on your platform:

    • Adding users, groups, setting passwords

    • (For Oracle) Starting an X server and running an X program remotely

    • Basic file management using cp, rm, mv, and cd

    • Compiling a program using ./config and make.

    You can complete this install without the above knowledge, but if anything goes wrong it may take extra time to understand and correct the problem. Some useful UNIX resources.

    1. Unplug the network cable from your computer. We don't want to connect to the network until we're sure the computer is secure. (Wherever you see the word secure, you should always read it as, "secure enough for our purposes, given the amount of work we're willing to exert and the estimated risk and consequences.")

    2. Insert Red Hat 8.0 or 9.0 Disk 1 into the CD-ROM and reboot the computer

    3. At the boot: prompt, press Enter for a graphical install. The text install is fairly different, so if you need to do that instead proceed with caution, because the guide won't match the steps.

    4. Checking the media is probably a waste of time, so when it asks press Tab and then Enter to skip it.

    5. After the graphical introduction page loads, click Next

    6. Choose the language you want to use and then click Next

    7. Select the keyboard layout you will use and Click Next

    8. Choose your mouse type and Click Next

    9. Red Hat has several templates for new computers. We'll start with the "Server" template and then fine-tune it during the rest of the install. Choose Server and click Next.

    10. Reformat the hard drive. If you know what you're doing, do this step on your own. Otherwise: we're going to let the installer wipe out the everything on the main hard drive and then arrange things to its liking.

      1. Choose Automatically Partition and click Next

      2. Uncheck Review (and modify if needed) the partitions created and click Next

      3. On the pop-up window asking "Are you sure you want to do this?" click Yes IF YOU ARE WIPING YOUR HARD DRIVE.

      4. Click Next on the boot loader screen

    11. Configure Networking. Again, if you know what you're doing, do this step yourself, being sure to note the firewall holes. Otherwise, follow the instructions in this step to set up a computer directly connected to the internet with a dedicated IP address.

      1. DHCP is a system by which a computer that joins a network (such as on boot) can request a temporary IP address and other network information. Assuming the machine has a dedicated IP address (if it doesn't, it will be tricky to access the OpenACS service from the outside world), we're going to set up that address. If you don't know your netmask, 255.255.255.0 is usually a pretty safe guess. Click Edit, uncheck Configure using DHCP and type in your IP and netmask. Click Ok.

      2. Type in your host name, gateway, and DNS server(s). Then click Next.

      3. We're going to use the firewall template for high security, meaning that we'll block almost all incoming traffic. Then we'll add a few holes to the firewall for services which we need and know are secure. Choose High security level. Check WWW, SSH, and Mail (SMTP). In the Other ports box, enter 443, 8000, 8443. Click Next. Port 443 is for https (http over ssl), and 8000 and 8443 are http and https access to the development server we'll be setting up.

    12. Select any additional languages you want the computer to support and then click Next

    13. Choose your time zone and click Next.

    14. Type in a root password, twice.

    15. On the Package selection page, we're going to uncheck a lot of packages that install software we don't need, and add packages that have stuff we do need. You should install everything we're installing here or the guide may not work for you; you can install extra stuff, or ignore the instructions here to not install stuff, with relative impunity - at worst, you'll introduce a security risk that's still screened by the firewall, or a resource hog. Just don't install a database or web server, because that would conflict with the database and web server we'll install later.

      check Editors (this installs emacs),
      click Details next to Text-based Internet, check lynx, and click OK;
      check Authoring and Publishing (this installs docbook),
      uncheck Server Configuration Tools,
      uncheck Web Server,
      uncheck Windows File Server,
      check SQL Database Server (this installs PostgreSQL),
      check Development Tools (this installs gmake and other build tools),
      uncheck Administration Tools, and
      uncheck Printing Support.

      At the bottom, check Select Individual Packages and click Next

    16. We need to fine-tune the exact list of packages. The same rules apply as in the last step - you can add more stuff, but you shouldn't remove anything the guide adds. We're going to go through all the packages in one big list, so select Flat View and wait. In a minute, a list of packages will appear.

      uncheck apmd (monitors power, not very useful for servers),
      check ImageMagick (required for the photo-album packages,
      uncheckisdn4k-utils (unless you are using isdn, this installs a useless daemon),
      check mutt (a mail program that reads Maildir),
      uncheck nfs-utils (nfs is a major security risk),
      uncheck pam-devel (I don't remember why, but we don't want this),
      uncheck portmap,
      uncheck postfix (this is an MTA, but we're going to install qmail later),
      check postgresql-devel,
      uncheck rsh (rsh is a security hole),
      uncheck sendmail (sendmail is an insecure MTA; we're going to install qmail instead later),
      check tcl (we need tcl), and
      uncheck xinetd (xinetd handles incoming tcp connections. We'll install a different, more secure program, ucspi-tcp).
      Click Next
    17. Red Hat isn't completely happy with the combination of packages we've selected, and wants to satisfy some dependencies. Don't let it. On the next screen, choose Ignore Package Dependencies and click Next.

    18. Click Next to start the copying of files.

    19. Wait. Insert Disk 2 when asked.

    20. Wait. Insert Disk 3 when asked.

    21. If you know how to use it, create a boot disk. Since you can also boot into recovery mode with the Install CDs, this is less useful than it used to be, and we won't bother. Select No,I do not want to create a boot disk and click Next.

    22. Click Exit, remove the CD, and watch the computer reboot.

    23. After it finishes rebooting and shows the login prompt, log in:

      yourserver login: root
      Password:
      [root root]#
    24. Install any security patches. For example, insert your CD with patches, mount it with mount /dev/cdrom, then cd /mnt/cdrom, then rpm -UVH *rpm. Both Red Hat 8.0 and 9.0 have had both kernel and openssl/openssh root exploits, so you should be upgrading all of that. Since you are upgrading the kernel, reboot after this step.

    25. Lock down SSH

      1. SSH is the protocol we use to connect securely to the computer (replacing telnet, which is insecure). sshd is the daemon that listens for incoming ssh connections. As a security precaution, we are now going to tell ssh not to allow anyone to connect directly to this computer as root. Type this into the shell:

        emacs /etc/ssh/sshd_config
      2. Search for the word "root" by typing C-s (that's emacs-speak for control-s) and then root.

      3. Make the following changes:

        #Protocol 2,1 to Protocol 2 (this prevents any connections via SSH 1, which is insecure)
        #PermitRootLogin yes to PermitRootLogin no (this prevents the root user from logging in remotely via ssh. If you do this, be sure to create a remote access account, such as "remadmin", which you can use to get ssh before using "su" to become root)
        #PermitEmptyPasswords no to PermitEmptyPasswords no (this blocks passwordless accounts) and save and exit by typing C-x C-s C-x C-c
      4. Restart sshd so that the change takes effect.

        service sshd restart
    26. Red Hat still installed a few services we don't need, and which can be security holes. Use the service command to turn them off, and then use chkconfig to automatically edit the System V init directories to permanently (The System V init directories are the ones in /etc/rc.d. They consist of a bunch of scripts for starting and stopping programs, and directories of symlinks for each system level indicating which services should be up and down at any given service level. We'll use this system for PostgreSQL, but we'll use daemontools to perform a similar function for AOLserver. (The reason for this discrepencies is that, while daemontools is better, it's a pain in the ass to deal with and nobody's had any trouble leaving PostgreSQL the way it is.)

      [root root]# service pcmcia stop
      [root root]# service netfs stop
      [root root]# chkconfig --del pcmcia
      [root root]# chkconfig --del netfs
      [root root]#
      service pcmcia stop
      service netfs stop
      chkconfig --del pcmcia
      chkconfig --del netfs

      If you installed PostgreSQL, do also service postgresql start and chkconfig --add postgresql.

    27. Plug in the network cable.

    28. Verify that you have connectivity by going to another computer and ssh'ing to yourserver, logging in as remadmin, and promoting yourself to root:

      [joeuser@someotherserver]$  ssh remadmin@yourserver.test
      The authenticity of host 'yourserver.test (1.2.3.4)' can't be established.
      DSA key fingerprint is 10:b9:b6:10:79:46:14:c8:2d:65:ae:c1:61:4b:a5:a5.
      Are you sure you want to continue connecting (yes/no)? yes
      Warning: Permanently added 'yourserver.test (1.2.3.4)' (DSA) to the list of known hosts.
      Password:
      Last login: Mon Mar  3 21:15:27 2003 from host-12-01.dsl-sea.seanet.com
      [remadmin remadmin]$ su -
      Password: 
      [root root]#
    29. If you didn't burn a CD of patches and use it, can still download and install the necessary patches. Here's how to do it for the kernel; you should also check for other critical packages.

      Upgrade the kernel to fix a security hole. The default Red Hat 8.0 system kernel (2.4.18-14, which you can check with uname -a) has several security problems. Download the new kernel, install it, and reboot.

      [root root]# cd /var/tmp
      [root tmp]# wget http://updates.redhat.com/7.1/en/os/i686/kernel-2.4.18-27.7.x.i686.rpm
      --20:39:00--  http://updates.redhat.com/7.1/en/os/i686/kernel-2.4.18-27.7.x.i686.rpm
                 => `kernel-2.4.18-27.7.x.i686.rpm'
      Resolving updates.redhat.com... done.
      Connecting to updates.redhat.com[66.187.232.52]:80... connected.
      HTTP request sent, awaiting response... 200 OK
      Length: 12,736,430 [application/x-rpm]
      
      100%[======================================>] 12,736,430    78.38K/s    ETA 00:00
      
      20:41:39 (78.38 KB/s) - `kernel-2.4.18-27.7.x.i686.rpm' saved [12736430/12736430]
      
      root@yourserver tmp]# rpm -Uvh kernel-2.4.18-27.7.x.i686.rpm
      warning: kernel-2.4.18-27.7.x.i686.rpm: V3 DSA signature: NOKEY, key ID db42a60e
      Preparing...                ########################################### [100%]
         1:kernel                 ########################################### [100%]
      [root tmp]# reboot
      
      Broadcast message from root (pts/0) (Sat May  3 20:46:39 2003):
      
      The system is going down for reboot NOW!
      [root tmp]#
      cd /var/tmp
      wget http://updates.redhat.com/7.1/en/os/i686/kernel-2.4.18-27.7.x.i686.rpm
      rpm -Uvh kernel-2.4.18-27.7.x.i686.rpm
      reboot
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/individual-programs.html0000644000175000017500000005676111501005400024666 0ustar frankiefrankie Prerequisite Software

    Prerequisite Software

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    OpenACS requires, at a minimum, an operating system, database, and webserver to work. Many additional programs, such as a build environment, Mail Transport Agent, and source control system, are also needed for a fully effective installation.

    Table 2.2. Version Compatibility Matrix

    OpenACS Version3.2.5 4.5 4.6 4.6.14.6.24.6.35.05.15.25.35.45.5
    AOLserver3YesNo
    3.3+ad13MaybeYesNo
    3.3oacs1MaybeYesNo
    3.4.4No
    3.4.4oacs1MaybeYesNo
    3.5.5MaybeYesNo
    4.0MaybeYes
    4.5NoYes
    Tcl8.4Yes
    8.5.4 -Maybe
    PostgreSQL7.0YesNo
    7.2MaybeYesNo
    7.3.2 - 7.3.xNoYesNo
    7.4NoYesNo
    8.0NoMaybeYes
    8.1NoYes
    8.2NoCVS version onlyYes
    8.3NoYes
    Oracle8.1.6MaybeYesMaybe
    8.1.7MaybeYesMaybe
    9iNoYes
    10gNoYes
    11gNoMaybe

    The OpenACS installation instructions assume the operating system and build environment are installed. The instructions explain installation of TCL, Tcllib, tDOM, tclwebtest, a Web Server, a Database, a Process Controller, and Source Control software. The following external links are for reference only.

    • OpenACS 5.6.0. The OpenACS tarball comprises the core packages and many useful additional packages. This includes a full set of documentation. The tarball works with both PostgreSQL and Oracle. Some scripts require bash shell.

    • Operating System. OpenACS is designed for a Unix-like system. It is developed primarily in Linux. It can be run on Mac OS X, and in Windows within VMWare.

      • GNU/Linux. The installation assumes a linux kernel of 2.2.22 or newer, or 2.4.14 or newer.

      • FreeBSD. FreeBSD guide. The OpenACS Reference Platform uses shell scripts written for bash, which is the standard Linux shell. If you are using a different shell, you will need to substitute your shell's conventions for setting environment variables when appropriate, and install bash to work with the scripts. Substitute fetch when the instructions suggest you use wget to download software.

      • Mac OS X. OpenACS Installation Guide for Mac OS X

      • Windows/VMWare. OpenACS Installation Guide for Windows2000 The only way to run OpenACS on Windows is through the VMWare emulator. (Please let me know if you have OpenACS running directly in Windows.)

    • Build Environment. The Reference Platform installation compiles most programs from source code.

      • glibc 2.2 or newer, REQUIRED. You need recent versions of these libraries for Oracle to work properly. For Unicode support, you need glibc 2.2 or newer. This should be included in your operating system distribution.

      • GNU Make 3.76.1 or newer, REQUIRED. PostgreSQL and AOLserver require gmake to compile. Note that on most linux distributions, GNU Make is simply named make and there is no gmake, whereas on BSD distributions, make and gmake are different --use gmake.

    • TCL 8.4.x. 

      • TCL 8.4.x, REQUIRED. OpenACS is written in TCL, an interpreted language. A threaded version of the TCL interpreter must be installed for OpenACS to work. The TCL interpreter that is included in most standard distributions may not be thread safe.

      • TCL 8.4.x development headers and libraries, OPTIONAL.  The site-wide-search service, OpenFTS, requires these to compile. (Debian users: apt-get install tcl8.4-dev). You need this to install OpenFTS.

    • Tcllib, REQUIRED.  OpenACS 5.6.0 uses those Tcl extensions to send e-mail out, among others.

    • tDOM, REQUIRED. OpenACS 5.6.0 stores queries in XML files, so we use an AOLserver module called tDOM to parse these files. (This replaces libxml2, which was used prior to 4.6.4.)

    • tclwebtest, OPTIONAL. tclwebtest is a tool for testing web interfaces via tcl scripts.

    • Web Server. The web server handles incoming HTTP requests, provides a runtime environment for OpenACS's tcl code, connects to the database, sends out HTTP responses, and logs requests and errors. OpenACS uses AOLserver; some people have had success running Apache with mod_nsd.

      • AOLserver 4.x, REQUIRED. Provides the base HTTP server

      Mat Kovach is graciously maintaining an AOLserver distribution that includes all the patches and modules needed to run OpenACS 5.6.0. These instructions will describe how to install using his source distribution. He also has binaries for SuSE 7.3 and OpenBSD 2.8 (and perhaps more to come), currently located at uptime.openacs.org.

      It's also possible to download all the pieces and patches yourself:

      • AOLserver is available at aolserver.com

      • The OpenACS PostgreSQL driver (nspostgres.so) is available from SourceForge. If you do decide to use nspostgres.so, you have to remember to change the AOLserver config file to point to nspostgres.so instead of postgres.so. This guide uses Mat Kovach's distro (i.e. postgres.so)

      • The patch that makes exec work on BSD is available at sourceforge.net

      • The patch for aolserver 3.x that makes ns_uuencode work for binary files is available at sourceforge.net

      • The patch that makes AOLserver 3.x respect the -g flag is available at sourceforge.net

    • nsopenssl, OPTIONAL. Provides SSL capabilities for AOLserver. It requires OpenSSL. You need this if you want users to make secure (https) connections to your webserver. aolserver3.x requires nsopenssl 2.1a. aolserver4.x requires nsopenssl3; see aolserver.com for latest release. (home page)

    • ns_pam 0.1 or newer, OPTIONAL. Provides PAM capabilities for AOLserver. You need this if you want OpenACS users to authenticate through a PAM module (such as RADIUS).

    • pam_radius 1.3.16, OPTIONAL. Provides RADIUS capabilities for PAM. You need this if you want to use RADIUS authentication via PAM in OpenACS.

    • ns_ldap 0.r8, OPTIONAL. Provides LDAP capabilities for AOLserver. You need this if you want to use LDAP authentication in OpenACS.

    • OpenFTS TCL 0.3.2, OPTIONAL. Adds full-text-search to PostgreSQL and includes a driver for AOLserver. You need this if you want users to be able to search for any text on your site. For postgres 7.4.x and higher, full text search is also available via tsearch2.

    • Analog 5.32 or newer, OPTIONAL. This program examines web server request logs, looks up DNS values, and produces a report. You need this if you want to see how much traffic your site is getting.

    • Balance 3.11 or newer, OPTIONAL. "Balance is a simple but powerful generic tcp proxy with round robin load balancing and failover mechanisms." You need this or something equivalent if you are running a high-availability production site and do not have an external load balancing system.

    • Database. The data on your site (for example, user names and passwords, calender entries, and notes) is stored in the database. OpenACS separates the database with an abstraction layer, which means that several different databases all function identically. While you can run the core OpenACS on any supported database, not all contributed packages support all databases.

      • Oracle 8.1.7 (Either this or PostgreSQL is REQUIRED). You can register and download Oracle from Oracle TechNet. You need this if you want to use an Oracle database.

      • PostgreSQL 7.4.x (Either this or Oracle is REQUIRED). You need this if you want to use a PostgreSQL database.

    • Process Controller. This is software that initiates other software, and restarts that software if it fails. On Linux, we recommend using Daemontools to control AOLserver and qmail.

      • Daemontools 0.76, OPTIONAL. You need this if you want AOLserver and qmail to run "supervised," meaning that they are monitored and automatically restarted if they fail. An alternative would be to run the services from inittab.

    • Mail Transport Agent. A Mail Transport Agent is a program that handles all incoming and outgoing mail. The Reference Platform uses Qmail; any MTA that provides a sendmail wrapper (that is, that can be invoked by calling the sendmail program with the same variables that sendmail expects) can be used.

      • Netqmail 1.04, OPTIONAL. You need this (or a different Mail Transport Agent) if you want your webserver to send and receive email.

      • ucspi-tcp 0.88, OPTIONAL. This program listens for incoming TCP connections and hands them to a program. We use it instead of inetd, which is insecure. You need this if you are running qmail.

    • DocBook, OPTIONAL. (docbook-xml v4.4, docbook-xsl v1.56, libxslt 1.0.21, xsltproc 1.0.21). You need this to write or edit documentation.

    • Source Control. A Source Control system keeps track of all of the old versions of your files. It lets you recover old files, compare versions of file, and identify specific versions of files. You can use any source control system; the Reference Platform and the OpenACS.org repository (where you can get patched and development code in between releases) use cvs.

      • cvs 1.11.18, OPTIONAL. cvs is included in most unix distributions. You need this if you want to track old versions of your files, do controlled deployment of code from development to production, or get or contribute development code from openacs.org.

    ($Id: individual-programs.html,v 1.31 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/upgrade-supporting.html0000644000175000017500000003134111501005400024530 0ustar frankiefrankie Upgrading Platform components

    Upgrading Platform components

    Upgrading OpenFTS from 0.2 to 0.3.2

    OpenACS Full Text Search requires several pieces: the OpenFTS code, some database functions, and the OpenFTS Engine. This section describes how to upgrade OpenFTS from 0.2 to 0.3.2 and upgrade the search engine on an OpenACS site at the same time.

    1. Uninstall the old OpenFTS Engine from the $OPENACS_SERVICE_NAME database.

      1. Browse to http://yourserver/openfts.

      2. Click Administration.

      3. Click Drop OpenFTS Engine

    2. Build and install the new OpenFTS driver and supporting tcl procedures. (This section of shell code is not fully documented; please exercise care.)

      cd /usr/local/src/
                tar xzf /var/tmp/Search-OpenFTS-tcl-0.3.2.tar.gz
                chown -R root.root Search-OpenFTS-tcl-0.3.2/
                cd Search-OpenFTS-tcl-0.3.2/
                ./configure --with-aolserver-src=/usr/local/src/aolserver/aolserver --with-tcl=/usr/lib/
                cd aolserver/
                make
                

      Back up the old fts driver as a precaution and install the newly compiled one

      mv /usr/local/aolserver/bin/nsfts.so /usr/local/aolserver/bin/nsfts-0.2.so 
                cp nsfts.so /usr/local/aolserver/bin
                

      Build and install the OpenFTS code for PostGresSQL

      cd /usr/local/src/Search-OpenFTS-tcl-0.3.2/
                cp -r pgsql_contrib_openfts /usr/local/src/postgresql-7.2.3/contrib /usr/local/src/postgresql-7.2.3/contrib/pgsql_contrib_openfts
                make
                su - postgres
                cd tsearch/
                make
                make install
                exit

      In order for the OpenACS 4.6 OpenFTS Engine to use the OpenFTS 0.3.2 driver, we need some commands added to the database.

      [root root]# su - $OPENACS_SERVICE_NAME
                [$OPENACS_SERVICE_NAME dev]$ psql $OPENACS_SERVICE_NAME -f /usr/local/pgsql/share/contrib/openfts.sql
                CREATE
                CREATE
                [$OPENACS_SERVICE_NAME dev]$ psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.2.3/contrib/tsearch/tsearch.sql
                BEGIN
                CREATE
                (~30 more lines)
                [$OPENACS_SERVICE_NAME dev]$ exit
                [root root]# 
                su - $OPENACS_SERVICE_NAME
      psql $OPENACS_SERVICE_NAME -f /usr/local/pgsql/share/contrib/openfts.sql
      psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.2.3/contrib/tsearch/tsearch.sql
      exit
    3. OPTIONAL: Install the new OpenFTS Engine. If you want to upgrade the OpenFTS Engine, do these steps. (You must have already upgraded the OpenFTS driver to 0.3.2.)

      1. Browse to http://yourserver/admin/site-map

      2. On the openfts line, click on set parameters.

      3. Change the value of openfts_tcl_src_path from /usr/local/src/Search-OpenFTS-tcl-0.2/ to /usr/local/src/Search-OpenFTS-tcl-0.3.2/

      4. Click Set Parameters

      5. [root root]# restart-aolserver $OPENACS_SERVICE_NAME
      6. Browse to http://yourserver/openfts

      7. Click Administration.

      8. Click Initialize OpenFTS Engine

    Upgrading from PostGreSQL 7.2 to 7.3

    An OpenACS database created in PostGreSQL 7.2 will not work correctly in PostGreSQL 7.3. This is because 7.2 truncates function names to 31 characters, but 7.3 does not. This does not cause problems in 7.2, because truncation occurs both at function creation and at function calling, so they still match. But if you use a database created in 7.2 in 7.3, the function names in the database remain truncated but the function calls are not, and so they don't match. Also some functions use casting commands that no longer work in 7.3 and these functions must be recreated.

    To upgrade an OpenACS site from PostGreSQL 7.2 to 7.3, first upgrade the kernel to 4.6.3. Then, dump the database, run the upgrade script /var/lib/aolserver/$OPENACS_SERVICE_NAME/bin/pg_7.2to7.3_upgrade_helper.pl on the dump file, and reply the dump. See Forum OpenACS Q&A: PG 7.2->7.3 upgrade gotcha?. Example:

    1. Back up the database as per ???.

    2. Run the upgrade script on the backup file.

      [root root]# su - $OPENACS_SERVICE_NAME
                [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]# cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/bin
                [$OPENACS_SERVICE_NAME bin]$ ./pg_7.2to7.3_upgrade_helper.pl \
                ../database-backup/nightly.dmp \
                ../database-backup/upgrade-7.3.dmp \
                /var/lib/aolserver/$OPENACS_SERVICE_NAME
                ==================================================================
                looking for function acs_object__check_object_ancest in oacs
                grep result: /var/lib/aolserver/aufrecht-dev/packages/acs-kernel/sql/postgresql/acs-objects-create.sql:create function acs_object__check_object_ancestors (integer,integer,integer)
      
                replacing acs_object__check_object_ancest with acs_object__check_object_ancestors
      
                (many lines omitted)
                [$OPENACS_SERVICE_NAME bin]$
                
    3. Use perl to replace timestamp with timestamptz in the dump file. See example perl code in step two in /contrib/misc/upgrade_4.6_to_5.0.sh

    4. Create a new user for PostgreSQL 7.3.x, as per the Postgres installation guide. Keep in mind that your installation location is different, and your startup script (/etc/init.d/postgres73 should be named differently. You might even need to edit that file to make the paths correct). You'll also need to add export PGPORT=5434 to the .bashrc and/or .bash_profile for the postgres73 user.

    5. Install PostgreSQL 7.3.x. Note that you PostgreSQL must listen on a different port in order to work correctly, so you'll need to edit the configuration file (/usr/local/pgsql73/data/postgresql.conf) and change the port (to 5433, say). create a second postgres user to differentiate between the two postgres installs. When you do ./configure, you'll need to include --prefix=$HOME to ensure that it is installed in the postgres73 user's home directory.

    6. Change the path in $OPENACS_SERVICE_NAME's .bashrc or .bash_profile (or both) files to reflect the new postgres73 user directory. Also add in the PGPORT.

    7. Restore the database from dump as per the recovery instructions.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-cvs.html0000644000175000017500000000530111501005400023125 0ustar frankiefrankie Initialize CVS (OPTIONAL)

    Initialize CVS (OPTIONAL)

    CVS is a source control system. Create and initialize a directory for a local cvs repository.

    [root tmp]# mkdir /cvsroot
    [root tmp]# cvs -d /cvsroot init
    [root tmp]#
    mkdir /cvsroot
    cvs -d /cvsroot init
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/form-builder.html0000644000175000017500000001713511501005400023265 0ustar frankiefrankie Using Form Builder: building html forms dynamically

    Using Form Builder: building html forms dynamically

    Overview

    ($Id: form-builder.html,v 1.28 2010/12/11 23:36:32 ryang Exp $)
    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    OpenACS has a form manager called ad_form. Ad_form has an adaptable UI. Error handling includes inline error reporting, and is customizable. However, ad_form can be tricky to use. In addition to this document, the ad_form api documentation is helpful.

    Multi-part Elements

    Some elements have more than one choice, or can submit more than one value.

    SELECT elements

    1. Creating the form element. Populate a list of lists with values for the option list.

      set foo_options [db_list_of_lists foo_option_list "
          select foo,
                 foo_id
            from foos
      "]
      

      The variable foo_options should resemble {{first foo} 1234} {{second foo} 1235}

      Within ad_form, set up the element to use this list:

      {foo:text(select)
              {label "Which Foo"}
              {options $foo_options}
          }

      This will result in a single name/value pair coming back in the submitted form. Handle this within the same ad_form structure, in the -new_data and -edit_data. In the example, it is available as $foo

    See also the W3C spec for "The SELECT, OPTGROUP, and OPTION elements".

    Using refreshes to pull additional information from the database

    A situation you may run into often is where you want to pull in form items from a sub-category when the first category is selected. Ad_form makes this fairly easy to do. In the definition of your form element, include an html section

        {pm_task_id:integer(select),optional
            {label "Subject"}
            {options {$task_options}}
            {html {onChange "document.form_name.__refreshing_p.value='1';submit()"}}
            {value $pm_task_id}
        }
        

    What this will do is set the value for pm_task_id and all the other form elements, and resubmit the form. If you then include a block that extends the form, you'll have the opportunity to add in subcategories:

        if {[exists_and_not_null pm_task_id]} {
        db_1row get_task_values { }
        ad_form -extend -name form_name -form { ... }
        

    Note that you will get strange results when you try to set the values for the form. You'll need to set them explicitly in an -on_refresh section of your ad_form. In that section, you'll get the values from the database, and set the values as so:

        db_1row get_task_values { }
        template::element set_value form_name estimated_hours_work $estimated_hours_work
        

    Troubleshooting

    A good way to troubleshoot when you're using ad_form is to add the following code at the top of the .tcl page (thanks Jerry Asher):

    ns_log notice it's my page!
    set mypage [ns_getform]
    if {[string equal "" $mypage]} {
        ns_log notice no form was submitted on my page
    } else {
        ns_log notice the following form was submitted on my page
        ns_set print $mypage
    }
        

    Tips for form widgets

    Here are some tips for dealing with some of the form widgets:

    Current widget

    Common Errors

    Here are some common errors and what to do when you encounter them:

    Error when selecting values

    This generally happens when there is an error in your query.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/objects.html0000644000175000017500000005776011501005400022337 0ustar frankiefrankie OpenACS Data Models and the Object System

    OpenACS Data Models and the Object System

    By Pete Su

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Overview

    Developing data models in OpenACS 5.6.0 is much like developing data models for OpenACS 3, save for the implementation. As usual, you need to examine how to model the information that the application must store and manipulate, and define a suitable set of SQL tables. In our Notes application, we have to be able to keep track of who entered a particular note, when they did it, and the actual text of the notes that users have entered. A simple data model might look like this:

    create table notes (
        note_id           integer primary key,
        owner_id          integer references users(user_id),
        creation_user     references(user_id) not null,
        creation_date     date not null,
        last_modified     date not null,
        title             varchar(255) not null,
        body              varchar(1024)
    )
    

    We've omitted constraint names for the purpose of clarity.

    Thinking further ahead, we can imagine doing any of the following things with Notes as well:

    • Define access control policies on notes.

    • Attach user comments on notes.

    • Allow users to define custom fields to store on their notes.

    • Automatically generate input forms or output displays for notes.

    • Allow other applications to use notes in ways we don't know of yet.

    In OpenACS, the key to enabling these types of services on your application data is to take advantage of the Object System. The first question, then, is "Just what are objects, and what do you use them for anyway?". The short answer: objects are anything represented in the application's data model that will need to be managed by any central service in OpenACS, or that may be reusable in the context of future applications. Every object in the system is represented using a row in the acs_objects table. This table defines all the standard attributes that are stored on every object, including its system-wide unique ID, object type, and some generic auditing columns.

    To make use of the object system, you as the application developer have to write your data model in a way that is slightly more complex than in the ACS 3.x days. What you get for this extra work includes:

    • The Permissions System lets you track who is allowed to do what to the rows in an application table, and gives you an easy way to enforce this from Tcl.

    • Every object has an attribute called context_id that provides a way to trivially specify both the default permissions for an object, and the intended "scope" of an object. Just set the context_id to the controlling object and forget about it.

    • And most importantly, any future object-level service - from a general-comments replacement to personalized ranking - will become available to your application "for free."

    How to Use Objects

    Using ACS objects is straightforward: all that's required are a few extra steps in the design of your application data model.

    In order to hook our Notes application into the object system, we make some calls to use our notes table as the basis for a new object type. Object types are analogous to classes in programming languages such as C++ and Java. In Java, a class defines a set of attributes that store data and a set of methods that run code. In OpenACS, we use one or more database tables to store the data attributes, and we define a stored procedure package to hold procedures to define the programming interface to the data model.

    The object type itself is described using data in the acs_object_types and acs_attributes tables, which play a role similar to the data dictionary in Oracle. As in Java, object types can inherit attributes from a parent type, so the type system forms a hierarchy. Unlike Java, Oracle does not support this inheritance transparently, so we have to make sure we add our own bookkeeping code to keep everything consistent. Below you'll find the code needed to describe a new object type called notes in your system.

    Fire up your text editor and open the ROOT/packages/notes/sql/oracle/notes-create.sql (ROOT/packages/notes/sql/postgresql/notes-create.sql for the PG version) file created when we created the package. Then, do the following:

    Describe the new type to the type system

    First, add an entry to the acs_object_types table with the following PL/SQL call:

    begin  
      acs_object_type.create_type ( 
        supertype     => 'acs_object', 
        object_type   => 'note', 
        pretty_name   => 'Note', 
        pretty_plural => 'Notes', 
        table_name    => 'NOTES', 
        id_column     => 'NOTE_ID' 
      ); 
    end;
    /
    show errors;
    

    This PL/SQL call tells the system that we would like to use the table NOTES as the basis for a new object type called note. This type is a subtype of the acs_object type, which means that we want to inherit all of the basic attributes of all ACS objects. As mentioned, it will take some work on our part to make this happen, since Oracle can't do it automatically. In general, most basic applications will define types that are simple subtypes of acs_object.

    Add entries to the acs_attributes table to describe the data attributes of the new type. This data can eventually be used to do things like automatically generate user interfaces to manipulate the notes table, though that functionality isn't yet available.

    declare 
     attr_id acs_attributes.attribute_id%TYPE; 
    begin
      attr_id := acs_attribute.create_attribute ( 
        object_type    => 'note', 
        attribute_name => 'TITLE', 
        pretty_name    => 'Title', 
        pretty_plural  => 'Titles', 
        datatype       => 'string' 
      ); 
     
      attr_id := acs_attribute.create_attribute ( 
        object_type    => 'note', 
        attribute_name => 'BODY', 
        pretty_name    => 'Body', 
        pretty_plural  => 'Bodies', 
        datatype       => 'string' 
      ); 
    end; 
    / 
    show errors; 
    

    We can stop here and not bother to register the usual OpenACS 3.x attributes of creation_user, creation_date and last_modified, since the object type acs_object already defines these attributes. Again, because the new type note is a subtype of acs_object, it will inherit these attributes, so there is no need for us to define them.

    Define a table in which to store your objects

    The next thing we do is make a small modification to the data model to reflect the fact that each row in the notes table represents something that is not only an object of type note, but also an acs_object. The new table definition looks like this:

    create table notes (
        note_id    integer references acs_objects(object_id) primary key,
        owner_id   integer references users(user_id),
        title      varchar(255) not null,
        body       varchar(1024)
    )
    

    The usual creation_date and modified_date columns are absent since they already exist in acs_objects. Also, note the constraint we have added to reference the acs_objects table, which makes clear that since note is a subtype of acs_object, every row in the notes table must have a corresponding row in the acs_objects table. This is the fundamental means by which we model inheritance; it guarantees that any services that use the acs_objects table to find objects will transparently find any objects that are instances of any subtype of acs_objects.

    Define a package for type specific procedures

    The next step is to define a PL/SQL package for your new type, and write some basic procedures to create and delete objects. Here is a package definition for our new type:

    create or replace package note 
    as 
      function new ( 
        note_id             in notes.note_id%TYPE default null, 
        owner_id            in notes.owner_id%TYPE default null, 
        title               in notes.title%TYPE, 
        body                in notes.body%TYPE, 
        object_type         in acs_object_types.object_type%TYPE default 'note', 
        creation_date       in acs_objects.creation_date%TYPE 
                               default sysdate, 
        creation_user       in acs_objects.creation_user%TYPE 
                               default null, 
        creation_ip         in acs_objects.creation_ip%TYPE default null, 
        context_id          in acs_objects.context_id%TYPE default null 
      ) return notes.note_id%TYPE; 
     
      procedure delete ( 
        note_id      in notes.note_id%TYPE 
      ); 
    end note; 
    / 
    show errors 
    

    You might be wondering what all the extra parameters are to these calls, since we haven't mentioned them before. These parameters are needed to fill out information that will be stored about the object that's not stored directly in the table you defined. The OpenACS Object System defines these attributes on the type acs_object since all objects should have these attributes. Internally, there are tables that store this information for you. Most of the data is pretty self-explanatory and reflects attributes that existed in the earlier OpenACS 3.x data models, with the exception of the context_id attribute.

    The context_id attribute stores the ID of an object that represents the default security domain to which the object belongs. It is used by the permissions system in this way: if no permissions are explicitly attached to the object, then the object inherits its permissions from the context. For example, if I had told you how to use the permissions system to specify that an object OBJ was "read only", then any other object that used OBJ as its context would also be "read only" by default. We'll talk about this more later.

    Define a package body for type specific procedures

    The PL/SQL package body contains the implementations of the procedures defined above. The only subtle thing going on here is that we must use acs_object.new to insert a row into acs_objects, before inserting a row into the notes. Similarly, when we delete a row from note, we have to be sure to delete the corresponding acs_object row.

    create or replace package body note 
    as 
     
      function new ( 
        note_id             in notes.note_id%TYPE default null, 
        owner_id            in notes.owner_id%TYPE default null, 
        title               in notes.title%TYPE, 
        body                in notes.body%TYPE, 
        object_type         in acs_object_types.object_type%TYPE default 'note', 
        creation_date       in acs_objects.creation_date%TYPE 
                               default sysdate, 
        creation_user       in acs_objects.creation_user%TYPE 
                               default null, 
        creation_ip         in acs_objects.creation_ip%TYPE default null, 
        context_id          in acs_objects.context_id%TYPE default null 
      ) return notes.note_id%TYPE 
      is 
        v_note_id integer; 
      begin 
        v_note_id := acs_object.new ( 
          object_id     => note_id, 
          object_type   => object_type, 
          creation_date => creation_date, 
          creation_user => creation_user, 
          creation_ip   => creation_ip, 
          context_id    => context_id 
        ); 
        
        insert into notes 
         (note_id, owner_id, title, body) 
        values 
         (v_note_id, owner_id, title, body); 
     
         return v_note_id; 
      end new; 
      
      procedure delete ( 
        note_id      in notes.note_id%TYPE 
      ) 
      is 
      begin 
        delete from notes 
        where note_id = note.delete.note_id; 
     
        acs_object.del(note_id); 
      end delete; 
     
    end note; 
    / 
    show errors; 
    

    That's pretty much it! As long as you use the note.new function to create notes, and the note.delete function to delete them, you'll be assured that the relationship each note has with its corresponding acs_object is preserved.

    The last thing to do is to make a file ROOT/packages/notes/sql/notes-drop.sql so it's easy to drop the data model when, say, you're testing:

    begin 
      acs_object_type.drop_type ('note'); 
    end; 
    / 
    show errors 
     
    drop package note; 
    drop table notes; 
    

    When to Use Objects

    While it is hard to give general design advice without knowing anything about a particular application, you should follow the following rule of thumb when deciding when to hook part of your data model to the object system:

    Anything in your data model that needs to be available to general OpenACS services such as user comments, permissions, and so on should be a subtype of acs_object. In addition, if you want your data model to take advantage of attributes that exist in some object type that is a subtype of acs_object, then you should use the object system.

    For example, for most applications, you will want to use objects to represent the data in your application that is user visible and thus requires access control. But other internal tables, views, mapping tables and so on probably don't need to be objects. As before, this kind of design decision is mostly made on an application-by-application basis, but this is a good baseline from which to start.

    Design Guidance

    In this section we cover some overall guidelines for designing data models that are meant to be integrated with the OpenACS object system.

    There are two basic rules you should follow when designing OpenACS 5.6.0 data models:

    1. Never utilize fields in the acs_objects table in application specific ways. That is, never assign any application-specific semantics to this data. In the notes application, we use the creation_date and last_modified fields, but this is OK since we do not assign any application-specific meaning to these fields.

    2. In particular, never assign any application specific semantics to the context_id attribute of an object. This field is used for a very specific purpose by the permissions system, and using this field in any other way whatsoever is guaranteed to make your application act strangely.

      As we'll see later, the Notes example will point each note object's context_id to the package instance in which the note was created. The idea will be that in a real site, the administrator would create one package instance for every separate set of Notes (say, one per user). The instance would "own" all of the notes that it created, and the administrator would be able to use the package instance as the basis for access control, which is convenient.

    The reason behind these two rules is pretty straightforward: First, the OpenACS Object system itself is meant to be a generic and reusable tool for any application to use for basic services. Second, in order for this to work, the various parts of the OpenACS Objects data model must be interpreted in the same way by all applications that use the data model. Therefore, assigning any application-specific semantics to any part of the core data model is a bad thing to do, because then the semantics of the data model are no longer independent of the application. This would make it impossible to build the generic tools that the data model is trying to support.

    Another less important reason for these two rules is to not introduce any joins against the acs_objects table in SQL queries in your application that you do not absolutely need.

    In the Notes example, the result of applying these rules is that we are careful to define our own attribute for owner_id rather than overloading creation_user from the objects table. But, since we will probably use creation_date and so on for their intended purposes, we don't bother to define our own attributes to store that data again. This will entail joins with acs_objects but that's OK because it makes the overall data model cleaner. The real lesson is that deciding exactly how and when to use inherited attributes is fairly straightforward, but requires a good amount of thought at design time even for simple applications.

    Summary

    Hooking into the OpenACS 5.6.0 object system brings the application developer numerous benefits, and doing it involves only four easy steps:

    • Describe the a new object type to the system. Most new application types will be subtypes of the built-in type acs_object.

    • Define a table to store application object data.

    • Define a PL/SQL package to store procedures related to the new type. You have to define at least a function called new to create new application objects and a procedure called delete to delete them.

    • Define a package body that contains the implementations of the PL/SQL procedures defined above.

    • Try not to write queries in your application that join against acs_objects. This means you should never use the fields in acs_objects for application-specific purposes. This is especially true for the context_id field.

    ($Id: objects.html,v 1.50 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-nspam.html0000644000175000017500000000465311501005400023461 0ustar frankiefrankie Install nspam
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/complete-install.html0000644000175000017500000000573311501005400024153 0ustar frankiefrankie Chapter 3. Complete Installation
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-full-text-search-openfts.html0000644000175000017500000005217011501005400027203 0ustar frankiefrankie Install Full Text Search using OpenFTS (deprecated see tsearch2)

    Install Full Text Search using OpenFTS (deprecated see tsearch2)

    By Joel Aufrecht and Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    OpenFTS and tsearch1 use is deprecated in favor of Tsearch2. See Install Full Text Search using Tsearch2. Tsearch2 is much easier to install, requiring only compilation of one module from PostgreSQL contrib, with an automated install process using the tsearch2-driver package.

    Install OpenFTS module

    If you want full text search, and you are running PostgreSQL, install this module to support FTS. Do this step after you have installed both PostgreSQL and AOLserver. You will need the openfts tarball in /tmp.

    1. Install Tsearch. This is a PostgreSQL module that OpenFTS requires.

      [root root]# su - postgres
      [postgres pgsql]$ cd /usr/local/src/postgresql-7.3.4/contrib/tsearch/
      [postgres tsearch]$ make
      sed 's,MODULE_PATHNAME,$libdir/tsearch,g' tsearch.sql.in >tsearch.sql
      /usr/bin/flex  -8 -Ptsearch_yy -o'parser.c' parser.l(many lines omitted)
      rm -f libtsearch.so
      ln -s libtsearch.so.0.0 libtsearch.so
      [postgres tsearch]$ make install
      mkdir /usr/local/pgsql/share/contrib
      mkdir /usr/local/pgsql/doc/contrib
      (2 lines omitted)
      /bin/sh ../../config/install-sh -c -m 755 libtsearch.so.0.0 /usr/local/pgsql/lib/tsearch.so
      [postgres tsearch]$ exit
      logout
      
      [root root]#
      su - postgres
      cd /usr/local/src/postgresql-7.3.4/contrib/tsearch
      make
      make install
      exit
    2. Unpack the OpenFTS tarball and compile and install the driver.

      [root root]# cd /usr/local/src
      [root src]# tar xzf /tmp/Search-OpenFTS-tcl-0.3.2.tar.gz
      [root src]# cd /usr/local/src/Search-OpenFTS-tcl-0.3.2/
      [root Search-OpenFTS-tcl-0.3.2]# ./configure --with-aolserver-src=/usr/local/src/aolserver/aolserver --with-tcl=/usr/lib/
      checking prefix... /usr/local
      checking for gcc... gcc
      (many lines omitted)
      configure: creating ./config.status
      config.status: creating Makefile.global
      [root Search-OpenFTS-tcl-0.3.2]# make
      (cd parser; make all)
      make[1]: Entering directory `/usr/local/src/Search-OpenFTS-tcl-0.3.2/parser'
      (many lines omitted)
      packages provided were {Lingua::Stem::Snowball 0.3.2}
      processed fts_base_snowball.tcl
      [root Search-OpenFTS-tcl-0.3.2]# cd aolserver
      [root aolserver]# make
      gcc -c -fPIC  -DPACKAGE=\"OPENFTS\" -DVERSION=\"0.3.2\" -DHAVE_UNISTD_H=1 -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STR
      (many lines omitted)
      n_stem.o italian_stem.o norwegian_stem.o portuguese_stem.o russian_stem.o nsfts.o  -o nsfts.so
      [root aolserver]# cp nsfts.so /usr/local/aolserver/bin/
      [root aolserver]#
      cd /usr/local/src 
      tar xzf /tmp/Search-OpenFTS-tcl-0.3.2.tar.gz
      cd /usr/local/src/Search-OpenFTS-tcl-0.3.2/
      ./configure --with-aolserver-src=/usr/local/src/aolserver/aolserver --with-tcl=/usr/lib/
      make
      cd aolserver
      make
      cp nsfts.so /usr/local/aolserver/bin
      
    3. Build some supplemental modules.

      [root aolserver]# cd /usr/local/src/Search-OpenFTS-tcl-0.3.2
      [root Search-OpenFTS-tcl-0.3.2]# cp -r pgsql_contrib_openfts /usr/local/src/postgresql-7.3.4/contrib
      [root Search-OpenFTS-tcl-0.3.2]# cd /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts
      [root pgsql_contrib_openfts]# make
      sed 's,MODULE_PATHNAME,$libdir/openfts,g' openfts.sql.in >openfts.sql
      gcc -O2 -Wall -Wmissing-prototypes -Wmissing-declarations -fpic -I. -I../../src/include   -c -o openfts.o openfts.c
      gcc -shared -o openfts.so openfts.o
      rm openfts.o
      [root pgsql_contrib_openfts]# su postgres
      [postgres pgsql_contrib_openfts]$ make install
      /bin/sh ../../config/install-sh -c -m 644 openfts.sql /usr/local/pgsql/share/contrib
      /bin/sh ../../config/install-sh -c -m 755 openfts.so /usr/local/pgsql/lib
      /bin/sh ../../config/install-sh -c -m 644 ./README.openfts /usr/local/pgsql/doc/contrib
      [postgres pgsql_contrib_openfts]$ exit
      [root pgsql_contrib_openfts]#
      cd /usr/local/src/Search-OpenFTS-tcl-0.3.2
      cp -r pgsql_contrib_openfts /usr/local/src/postgresql-7.3.4/contrib
      cd /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts
      make
      su postgres
      make install
      exit

    Install OpenFTS prerequisites in PostgreSQL instance

    If you are installing Full Text Search, add required packages to the new database. (In order for full text search to work, you must also install the PostgreSQL OpenFTS module and prerequisites.)

    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/tsearch/tsearch.sql
    BEGIN
    CREATE
    (many lines omitted)
    INSERT 0 1
    COMMIT
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts/openfts.sql
    CREATE
    CREATE
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/tsearch/tsearch.sql
    /usr/local/pgsql/bin/psql $OPENACS_SERVICE_NAME -f /usr/local/src/postgresql-7.3.4/contrib/pgsql_contrib_openfts/openfts.sql

    Note

    If you get the error ERROR: could not access file "$libdir/tsearch": no such file or directory It is probably because PostgreSQL's libdir configuration variable points to a diffent directory than where tsearch is. You can find out where PostgreSQL expects to find tsearch via

    pg_config --pkglibdir

    Enable OpenFTS in config.tcl

    If you have installed OpenFTS, you can enable it for this service. Uncomment this line from config.tcl. (To uncomment a line in a tcl file, remove the # at the beginning of the line.)

    #ns_param   nsfts           ${bindir}/nsfts.so

    Install Full Text Search Engine

    1. Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install.

    2. Click on the Install software link.

    3. Click on the Install new service link.

    4. Click on the Install link next to OpenFTS Driver.

    5. Restart the service.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    6. Wait a minute, then browse back to the home page.

    7. Click on Admin on the top of the screen.

    8. Click on Main Site Administration in the "Subsite Administration" section.

    9. Click on Site Map in the "Advanced Features" section.

    10. Mount the OpenFTS Full Text Search Engine in the site map.

      1. Click the new sub folder link on the "/" line, the first line under Main Site:/.

      2. Type openfts and click New.

      3. On the new openfts line, click the mount link.

      4. Click OpenFTS Driver.

      5. On the openfts line, click set parameters.

      6. Change openfts_tcl_src_path to /usr/local/src/Search-OpenFTS-tcl-0.3.2/ and click Set Parameters

    11. Mount the Search interface in the site map.

      1. Click the new sub folder link on the Main Site line.

      2. Type search and click New.

      3. Click the new application link on the search line.

      4. Type search where it says untitled, choose search from the drop-down list, and click New.

    12. Restart the service.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$
    13. Wait a minute, then click on Main Site at the top of the page.

    14. Initialize the OpenFTS Engine. This creates a set of tables in the database to support FTS.

      Near the bottom of the page, click on the OpenFTS Driver link. Click on Administration. Click on Initialize OpenFTS Engine. Click Initialize OpenFTS Engine.

    15. Add the FTS Engine service contract

      1. Click on the DevAdmin.

      2. Click on the Service Contract link.

      3. On the FtsEngineDriver line, click Install.

    16. Restart the service.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ svc -t /service/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$

    Enable Full Text Search in packages

    Enabling Full Text Search in packages at the moment is not trivial. It involves a couple of steps, which I will illustrate taking lars-blogger as an example package

    1. Install the package.

      1. Click Admin on the top of the default home page. If prompted, log in with the account and password you entered during install.

      2. Click on the Install software link.

      3. Click on the Install new application link.

      4. Click on the Install link next to Weblogger.

      5. Install all required packages as well (always say okay until you shall restart the server)

    2. Load the service contracts datamodell and enable the service contract

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd packages/lars-blogger/sql/postgresql
      [$OPENACS_SERVICE_NAME postgresql]$ psql $OPENACS_SERVICE_NAME -f lars-blogger-sc-create.sql

      Note: Usually this script is called package_name-sc-create.sql

    3. Restart the service.

      [$OPENACS_SERVICE_NAME postgresql]$ svc -t /service/$OPENACS_SERVICE_NAME
                      [$OPENACS_SERVICE_NAME postgresl]$

    If you are lucky, Full Text Search is enabled now, if not consult http://openacs.org/forums/message-view?message_id=154759. This link also contains some hints on how to make sure it is enabled.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-origins.html0000644000175000017500000000703111501005400024006 0ustar frankiefrankie Where did this document come from?

    Where did this document come from?

    This document was created by Vinod Kurup, but it's really just plagiarism from a number of documents that came before it. If I've used something that you've written without proper credit, let me know and I'll fix it right away.

    Versions 4.6.2 to present were edited by Joel Aufrecht.

    These are a few of my sources:

    Please also see the Credits section for more acknowledgements.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/kernel-doc.html0000644000175000017500000001032611501005400022714 0ustar frankiefrankie Chapter 14. Kernel Documentation
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-tclwebtest.html0000644000175000017500000000576711501005400024532 0ustar frankiefrankie Install tclwebtest.

    Install tclwebtest.

    Download the tclwebtest source, unpack it, and put it an appropriate place. (tclwebtest 1.0 will be required for auto-tests in OpenACS 5.1. When it exists, the cvs command here will be replaced with http://prdownloads.sourceforge.net/tclwebtest/tclwebtest-0.3.tar.gz?download.) As root:

    cd /tmp
    cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/tclwebtest co tclwebtest
    #wget http://umn.dl.sourceforge.net/sourceforge/tclwebtest/tclwebtest-1.0.tar.gz
    #tar xvzf tclwebtest-1-0.tar.gz
    mv tclwebtest-0.3 /usr/local/
    ln -s /usr/local/tclwebtest-0.3 /usr/local/tclwebtest
    ln -s /usr/local/tclwebtest/tclwebtest /usr/local/bin
    
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/releasing-openacs-core.html0000644000175000017500000004017711501005400025225 0ustar frankiefrankie OpenACS Core and .LRN

    OpenACS Core and .LRN

    1. Update Translations. How to Update the translations

    2. Rebuild the Changelog. Rebuild the Changelog. I use a tool called cvs2cl. Run this command from the package root to automatically generate a Changelog file in the same dir. We generate two changelogs, one for the minor branch and one for the most recent release. The example below is for OpenACS 5.0.2:

      cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
      cvs2cl -F oacs-5-0 --delta openacs-5-0-0-final:oacs-5-0 -f ChangeLog
      cvs2cl -F oacs-5-0 --delta openacs-5-0-1-final:oacs-5-0 -f ChangeLog-recent
    3. Update Version Numbers. The version numbers in the documentation and in the packages must be updated. This should only happen after a release candidate is approved.

      .LRN: this must be repeated for .LRN modules (dotlrn-core in the dotlrn cvs tree) and for any modified modules in the .LRN prerequisites (dotlrn-prereq in openacs cvs tree). My current working model is that I bulk-update .LRN and OpenACS core but that I don't touch dotlrn-prereq modules - I just use the most recent release and it's up to individual package developers to tag and release those packages when they change. This model is already broken because following it means that dotlrn-prereqs don't get new translations.

      1. Update /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/xml/variables.ent with the new version number.

      2. Add new section in /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/xml/for-everyone/release-notes.xml

      3. Regenerate all HTML docs

        cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/xml
        make
      4. Update /var/lib/aolserver/$OPENACS_SERVICE_NAME/readme.txt with the new version number

      5. Update version number and release date in all of the core packages. Use /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/update-info.sh with the new version number and the release date as arguments. Run it from /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages:

        cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages
               ./acs-core-docs/www/files/update-info 5.2.1 2006-01-16
      6. Install a new site using the modified code and verify that the automated tests pass.

      7. Commit changes to CVS

    4. Tag the files in CVS. The steps to this point should have ensured that the head of the current branch contains the full set of code to release. Now we need to tag it as the code to be released.

      1. Check out OpenACS Core. The files must be checked out through a cvs account with write access and should be a checkout from the release branch. In this example, we are assuming this is being done as a local user on openacs.org (which make the checkout and tagging operations much faster).

        cd /var/tmp
        cvs -d /cvsroot checkout -r oacs-5-0 acs-core

        If doing .LRN, repeat with the dotlrn cvs tree.

        cd /var/tmp
        mkdir dotlrn-packages
        cd dotlrn-packages
        cvs -d /dotlrn-cvsroot checkout -r dotlrn-2-0 dotlrn-all
        
      2. Tag the tree. If it's a final release of core, move or create the appropriate openacs-major-minor-compat tag. (Ie, if releasing 5.0.3 final, move the openacs-5-0-compat flag.)

        cd /var/tmp/openacs-4
        cvs tag -F openacs-5-0-0a1
        cvs tag -F openacs-5-0-compat
        

        Branching

        When we feature-freeze on HEAD as part of the release process, we are blocking new development. To avoid this, we branch the code at this point, so that new work can continue on HEAD while the branch is stabilized for release. However, branching means that bug fixes have to be synchronized between HEAD and the branch, and bug fixes tend to be more frequent right at this time. Therefore, our actual branch point is as late as possible - essentially, we do not branch until and unless new feature work is actively blocked by the feature freeze. Branching is almost the same as tagging, except for the flag and slightly different tag nomenclature. To see the list of old branches, cvs status -v somefile.

        cvs tag -b oacs-5-0

        If doing .LRN: Since the .LRN packages aren't all in one module, we iterate through all of the modules. Log in first (cvs login) so that you don't have to log in for each module.

        cd /var/tmp/dotlrn-packages
        for dir in *; do ( cd $dir && cvs tag dotlrn-2-0-2-final ); done
        for dir in *; do ( cd $dir && cvs tag -F openacs-5-0-compat ); done
        

        Note that for the compat tag we use the -F flag which will force the tag to the new version (just in case someone has created the tag already on another version). Excercise care when doing this since you don't want to inadvertently move a prior release tag. Also if the tagging goes horribly wrong for some reason you can delete the tag via "cvs tag -d <symbolic_tag>".

      3. Apply the final tag across the tree. First, check out the entire OpenACS tree, getting the most recent stable version of each package. This is most simply done on openacs.org:

        cd /var/tmp
        cvs -d /cvsroot checkout -r openacs-5-1-compat openacs-4
        cd openacs-4
        cvs tag openacs-5-1-2-final
    5. Make the tarball(s). 

      • openacs-core. 

        1. Go to a new working space and export the tagged files.

          mkdir /var/tmp/tarball
          cd /var/tmp/tarball
          cvs -d /cvsroot export -r openacs-5-0-0a1 acs-core
        2. Generate the tarball.

          cd /var/tmp/tarball
          mv openacs-4 openacs-5.0.0a1
          tar cz -f openacs-5.0.0a1.tar.gz openacs-5.0.0a1
          
      • dotlrn. 

        1. Go to a new working space and export the tagged files. (was getting errors here trying to use -d, so gave up and just moved things from openacs-4 to openacs at the end)

          mkdir /var/tmp/dotlrn-tarball
          cd /var/tmp/dotlrn-tarball
          cvs -d /cvsroot export -r openacs-5-0-0a1 acs-core
          cd /var/tmp/dotlrn-tarball/openacs-4/packages
          cvs -d /cvsroot export -r openacs-5-0-0a1 dotlrn-prereq
          cvs -d /dotlrn-cvsroot export -r dotlrn-2-0-0a1 dotlrn-core
          
        2. Copy the dotlrn install.xml file, which controls which packages are installed on setup, to the root location:

          cp /var/tmp/dotlrn-tarball/openacs-4/packages/dotlrn/install.xml \
             /var/tmp/dotlrn-tarball/openacs-4
          
        3. Generate the tarball

          cd /var/tmp/dotlrn-tarball
          mv openacs-4 dotlrn-2.0.0a1
          tar cz -f dotlrn-2.0.0a1.tar.gz dotlrn-2.0.0a1
          
    6. Test the new tarball(s). Download the tarballs just created and install them and make sure everything looks okay and that automated tests pass.

    7. Update Web site. Update the different places on OpenACS.org where we track status.

      • Release Status for the current version - something like http://openacs.org/projects/openacs/5.0/milestones

      • Home page of openacs.org

      • Post a new news item

    8. Clean Up. Clean up after yourself.

      cd /var/tmp
      rm -rf tarball dotlrn-tarball dotlrn-packages openacs-5.0.0a1
      rm -rf /var/tmp/openacs-4

    Here is a shell script that automates packaging the tarball (it's a bit out of date with the new steps - I've been doing everything manually or with little throwaway scripts as detailed above until the process is stabilized).

    #!/bin/bash
    
    # if TAG=1 create the cvs tags otherwise assume they exist.
    TAG=1
    
    # What release version are we building; version format should be
    # dashes rather than dots eg. OACS_VERSION=5-0-0b4
    
    OACS_VERSION=5-0-0b4
    DOTLRN_VERSION=2-0-0b4
    
    OACS_BRANCH=oacs-5-0
    DOTLRN_BRANCH=dotlrn-2-0
    
    DOTLRN_CVSROOT=/dotlrn-cvsroot
    OACS_CVSROOT=/cvsroot
    
    #
    # Nothing below here should need to change...
    #
    BASE=/var/tmp/release-$OACS_VERSION
    mkdir $BASE
    if [ ! -d $BASE ]; then 
        echo "Failed creating base dir $BASE"
        exit 1
    fi
    
    cd $BASE 
    
    if [ $TAG -eq 1 ]; then 
    
        # Checkout and tag the release 
        cvs -d $OACS_CVSROOT checkout -r $OACS_BRANCH openacs-4
        cd openacs-4 
        cvs tag -F openacs-$OACS_VERSION 
        cd ../
    
    
        # Checkout and tag the dotlrn release
        mkdir dotlrn-packages
        cd dotlrn-packages
        cvs -d $DOTLRN_CVSROOT checkout -r $DOTLRN_BRANCH dotlrn-all
        for dir in *; do ( cd $dir && cvs tag -F dotlrn-$DOTLRN_VERSION ); done
        cd ../
    
        #
        # Should check for .sql .xql .adp .tcl .html .xml executable files and squak if found.
        #
    
    fi
    
    
    
    # Generate tarballs...
    #
    
    # openacs
    #
    mkdir tarball
    cd tarball
    cvs -d $OACS_CVSROOT export -r openacs-$OACS_VERSION acs-core
    mv opeancs-4 openacs-${OACS_VERSION//-/.}
    tar -czf ../openacs-${OACS_VERSION//-/.}.tar.gz openacs-${OACS_VERSION//-/.}
    cd ..
    
    # dotlrn
    #
    mkdir dotlrn-tarball
    cd dotlrn-tarball
    cvs -d $OACS_CVSROOT export -r openacs-$OACS_VERSION acs-core
    cd  openacs-4/packages
    cvs -d $OACS_CVSROOT export -r openacs-$OACS_VERSION dotlrn-prereq
    cvs -d $DOTLRN_CVSROOT export -r dotlrn-$DOTLRN_VERSION dotlrn-core
    cd ../..
    cp -f openacs-4/packages/dotlrn/install.xml openacs-4
    mv openacs-4 dotlrn-${DOTLRN_VERSION//-/.}
    tar -czf ../dotlrn-${DOTLRN_VERSION//-/.}.tar.gz dotlrn-${DOTLRN_VERSION//-/.}
    
    
    # Clean up after ourselves...
    cd $BASE && rm -rf dotlrn-tarball tarball openacs-4 dotlrn-packages
    
    ($Id: releasing-openacs-core.html,v 1.18 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n-overview.html0000644000175000017500000001070711501005400023317 0ustar frankiefrankie Internationalization and Localization Overview

    Internationalization and Localization Overview

    Table 13.1. Internationalization and Localization Overview

    StageTaskWho
    InternationalizationPackage Developer uses the acs-lang tools to replace all visible text in a package with message keys. (More information)Package Developer
    Release ManagementThe newly internationalized package is released.Package Developer
    The translation server is updated with the new package.Translation server maintainers
    LocalizationTranslators work in their respective locales to write text for each message key. (More information)Translators
    Release ManagementThe translated text in the database of the translation server is compared to the current translations in the OpenACS code base, conflicts are resolved, and the new text is written to catalog files on the translation server.Translation server maintainers
    The catalog files are committed to the OpenACS code base.Translation server maintainers
    A new version of OpenACS core and/or affected packages is released and published in the OpenACS.org repository.Release Manager
    UpgradingSite Administrators upgrade their OpenACS sites, either via the automatic upgrade from the Repository or via tarball or CVS Site Administrators
    Site Administrators import the new translations. Existing local translations, if they exist, are not overwritten.Site Administrators

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/permissions.html0000644000175000017500000003476711501005400023263 0ustar frankiefrankie Groups, Context, Permissions

    Groups, Context, Permissions

    By Pete Su

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Overview

    The OpenACS 5.6.0 Permissions system allows developers and administrators to set access control policies at the object level, that is, any application or system object represented by a row in the acs_objects table can be access-controlled via a PL/SQL or Tcl interface. The permissions system manages a data model that then allows scripts to check permissions using another API call.

    Although object level permissions seems appropriate, no developer or administrator wants to explicitly set access control rights for every user and every object on a site. Therefore, OpenACS has two auxiliary mechanisms for making this easier:

    1. the Groups system allows users to be grouped together in flexible ways.

    2. the object model defines a notion of object context, which allows applications to group objects together into larger security domains.

    The rest of this document discusses each of these parts, and how they fit together with the permissions system.

    Groups

    OpenACS 5.6.0 has an abstraction called a party. Parties have a recursive definition. We can illustrate how it works with the following simplified data model. First, we define the parties table, where each party has an email address and a URL for contact information.

    
    create table parties (
        party_id  integer not null references acs_objects(object_id),
        email varchar(100),
        url varchar(100)
    )
    
    

    Now we define two subtypes of party, one for persons, and one for groups:

    
    create table groups (
        group_id  not null references parties(party_id),
        group_name varchar(100) not null
    )
    
    create table persons (
        person_id not null references parties(party_id),
        first_names varchar(100) not null,
        last_name varchar(100) not null
    )
    
    

    The users table is also defined in this data model as a subtype of person.

    Finally, we define two relations, one for group membership and one for group composition.

    The composition relation expresses that every member of group A should also be a member of group B. This relation allows us to define a hierarchy of groups.

    The membership relation maps groups to parties. Each member of a group is a party rather than just a user. That is, groups consist of members that are either a person or an entire group. This allows us to say that group A should be a member of another group B.

    The groups data model is recursive. Modelling parties as either a person or a group provides a way to model complex hierarchical groupings of persons and groups.

    The full details of the groups data model is beyond the scope of this tutorial. See Parties in OpenACS or OpenACS 4 Groups Design for more details.

    Permissions

    NOTE: Much more detailed information about the permissions system and how to use it is available in the ??? document.

    The permissions data model is a mapping between privileges, parties and objects. Parties and objects have already been discussed. Now we focus on privileges.

    In OpenACS, a privilege describes the right to perform some operation on some object. Privileges are the basic units out of which we build access control policies. For example in the Unix filesystem, access is controlled by granting users some combination of read, write, or execute privileges on files and directories. In OpenACS 5.6.0, the table of privileges is organized hierarchically so that developers can define privileges that aggregate some set of privileges together. For example, if we have read, write, create and delete privileges, it might be convenient to combine them into a new privilege called "admin". Then, when a user is granted "admin" privilege, she is automatically granted all the child privileges that the privilege contains. The OpenACS 5.6.0 kernel data model defines these privileges:

    # 
    begin
     acs_privilege.create_privilege('read');
     acs_privilege.create_privilege('write');
     acs_privilege.create_privilege('create');
     acs_privilege.create_privilege('delete');
     acs_privilege.create_privilege('admin');
    
     acs_privilege.add_child('admin', 'read');
     acs_privilege.add_child('admin', 'write');
     acs_privilege.add_child('admin', 'create');
     acs_privilege.add_child('admin', 'delete');
    
     commit;
    end;
    
    

    Note that a user does not gain admin privileges when granted read, write, create and delete privileges, because some operations explicitly require admin privileges. No substitutions.

    To give a user permission to perform a particular operation on a particular object you call acs_permission.grant_permission like this:

    # sql code
        acs_permission.grant_permission (
          object_id => some_object_id,
          grantee_id => some_party_id,
          privilege => 'some_privilege_name'
          );
    
    

    Using just these mechanisms is enough for developers and administrators to effectively define access control for every object in a system.

    Explicitly defining permissions to every object individually would become very tedious. OpenACS provides a object contexts as a means for controlling permissions of a large group of objects at the same time.

    Object Context

    In OpenACS 5.6.0, object context is a scoping mechanism. "Scoping" and "scope" are terms best explained by example: consider some hypothetical rows in the address_book table:

    ...scopeuser_idgroup_id...
    ...user123 ...
    ...group 456...
    ...public ...

    The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address book. In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people).

    Every object lives in a single context. A context is just an another object that represents the security domain to which the object belongs. By convention, if an object A does not have any permissions explicitly attached to it, then the system will look at the context_id column in acs_objects and check the context object there for permissions. Two things control the scope of this search:

    1. the structure of the context hierarchy itself, and

    2. the value of the security_inherit_p flag in each object.

    If security_inherit_p flag is set to 't', then the automatic search through the context happens, otherwise it does not. You might set this field to 'f' if you want to override the default permissions in a subtree of some context.

    For an example of how to use context hierarchy, consider the forums application. With only row-level permissions it is not obvious how to reasonably initialize the access control list when creating a message. At best, we have to explicitly grant various read and write privileges whenever we create a message, which is tedious. A reasonable thing to do is to create an object representing a forum, and point the context_id field of a new message at the forum. Then, suppose we grant every user in the system read-access to this forum. By default, they will automatically have read-access to the new message we just inserted, since the system automatically checks permissions on the message's context. To allow the creator of the message to change the message after it has been posted we grant the user write-access on the message, and we are done.

    This mechanism allows developers and administrators to define a hierarchy that matches the structure they need for access control in their application. The following picture shows a typical context hierarchy for a hypothetical site:

    The top two contexts in the diagram are called "magic" numbers, because in some sense, they are created by default by OpenACS for a specific purpose. The object default_context represents the root of the context hierarchy for the entire site. All permission searches walk up the tree to this point and then stop. If you grant permissions on this object, then by default those permissions will hold for every object in the system, regardless of which subsite they happen to live in. The object security_context_root has a slightly different role. If some object has no permissions attached to it, and its value for security_inherit_p is 'f', or context_id is null, this context is used by default.

    See the package developer tutorials for examples on how to use permissions code.

    Summary

    OpenACS 5.6.0 defines three separate mechanisms for specifying access control in applications.

    1. The Groups data model allows you to define hierarchical organizations of users and groups of users.

    2. The Permissions data model allows you to define a hierarchy of user rights.

    3. The Context hierarchy allows you to define organize default permissions in a hierarchical fashion.

    A PL/SQL or Tcl API is then used to check permissions in application pages.

    ($Id: permissions.html,v 1.48 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/maint-performance.html0000644000175000017500000002422611501005400024304 0ustar frankiefrankie Diagnosing Performance Problems

    Diagnosing Performance Problems

    • Did performance problems happen overnight, or did they sneak up on you? Any clue what caused the performance problems (e.g. loading 20K users into .LRN)

    • Is the file system out of space? Is the machine swapping to disk constantly?

    • Isolating and solving database problems.

      • Without daily internal maintenance, most databases slowly degrade in performance. For PostGreSQL, see Vacuum Postgres nightly. For Oracle, use exec dbms_stats.gather_schema_stats('SCHEMA_NAME') (Andrew Piskorski's Oracle notes).

      • You can track the exact amount of time each database query on a page takes:

        1. Go to Main Site : Site-Wide Administration : Install Software

        2. Click on "Install New Application" in "Install from OpenACS Repository"

        3. Choose "ACS Developer Support">

        4. After install is complete, restart the server.

        5. Browse to Developer Support, which is automatically mounted at /ds.

        6. Turn on Database statistics

        7. Browse directly to a slow page and click "Request Information" at the bottom of the page.

        8. This should return a list of database queries on the page, including the exact query (so it can be cut-paste into psql or oracle) and the time each query took.

          Figure 6.8. Query Analysis example

          Query Analysis example

      • Identify a runaway Oracle query: first, use ps aux or top to get the UNIX process ID of a runaway Oracle process.

        Log in to SQL*Plus as the admin:

        [$OPENACS_SERVICE_NAME ~]$ svrmgrl
        
        Oracle Server Manager Release 3.1.7.0.0 - Production
        
        Copyright (c) 1997, 1999, Oracle Corporation.  All Rights Reserved.
        
        Oracle8i Enterprise Edition Release 8.1.7.3.0 - Production
        With the Partitioning option
        JServer Release 8.1.7.3.0 - Production
        
        SVRMGR> connect internal	        
        Password:

        See all of the running queries, and match the UNIX PID:

        select p.spid  -- The UNIX PID
               ,s.sid  ,s.serial#
               ,p.username  as os_user
               ,s.username  ,s.status
               ,p.terminal  ,p.program
          from v$session s  ,v$process p
         where p.addr = s.paddr
         order by s.username ,p.spid ,s.sid ,s.serial# ;

        See the SQL behind the oracle processes:

        select s.username
               ,s.sid  ,s.serial#
               ,sql.sql_text
          from v$session s, v$sqltext sql
         where sql.address    = s.sql_address
           and sql.hash_value = s.sql_hash_value
         --and upper(s.username) like 'USERNAME%'
         order by s.username ,s.sid ,s.serial# ,sql.piece ;

        To kill a troubled process:

        alter system kill session 'SID,SERIAL#';  --substitute values for SID and SERIAL#

        (See Andrew Piskorski's Oracle notes)

      • Identify a runaway Postgres query. First, logging must be enabled in the database. This imposes a performance penalty and should not be done in normal operation.

        Edit the file postgresql.conf - its location depends on the PostGreSQL installation - and change

        #stats_command_string = false

        to

        stats_command_string = true

        Next, connect to postgres (psql service0) and select * from pg_stat_activity;. Typical output should look like:

          datid   |   datname   | procpid | usesysid | usename |  current_query
        ----------+-------------+---------+----------+---------+-----------------
         64344418 | openacs.org |   14122 |      101 | nsadmin | <IDLE>
         64344418 | openacs.org |   14123 |      101 | nsadmin |
                                                                 delete
                                                                 from acs_mail_lite_queue
                                                                 where message_id = '2478608';
         64344418 | openacs.org |   14124 |      101 | nsadmin | <IDLE>
         64344418 | openacs.org |   14137 |      101 | nsadmin | <IDLE>
         64344418 | openacs.org |   14139 |      101 | nsadmin | <IDLE>
         64344418 | openacs.org |   14309 |      101 | nsadmin | <IDLE>
         64344418 | openacs.org |   14311 |      101 | nsadmin | <IDLE>
         64344418 | openacs.org |   14549 |      101 | nsadmin | <IDLE>
        (8 rows)
        openacs.org=>

    Creating an appropriate tuning and monitoring environment

    The first task is to create an appropriate environment for finding out what is going on inside Oracle. Oracle provides Statspack, a package to monitor and save the state of the v$ performance views. These reports help finding severe problems by exposing summary data about the Oracle wait interface, executed queries. You'll find the installation instructions in $ORACLE_HOME/rdbms/admin/spdoc.txt. Follow the instructions carefully and take periodic snapshots, this way you'll be able to look at historical performance data.

    Also turn on the timed_statistics in your init.ora file, so that Statspack reports (and all other Oracle reports) are timed, which makes them a lot more meaningful. The overhead of timing data is about 1% per Oracle Support information.

    To be able to get a overview of how Oracle executes a particular query, install "autotrace". I usually follow the instructions here http://asktom.oracle.com/~tkyte/article1/autotrace.html.

    Make sure, that the Oracle CBO works with adequate statistics

    The Oracle Cost Based optimizer is a piece of software that tries to find the "optimal" execution plan for a given SQL statement. For that it estimates the costs of running a SQL query in a particular way (by default up to 80.000 permutations are being tested in a Oracle 8i). To get an adequate cost estimate, the CBO needs to have adequate statistics. For that Oracle supplies the dbms_stats package.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/credits.html0000644000175000017500000001172411501005400022331 0ustar frankiefrankie Appendix C. Credits

    Appendix C. Credits

    By Vinod Kurup

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Vinod Kurup put together the January 2002 version of this guide from many sources of information.

    Joel Aufrecht updated the document starting in March 2003.

    Acknowledgments for versions of the above documents go (in no particular order) to Bryan Quinn, Adam Farkas, Brian Stein, Doug Hoffman, Ravi Jasuja, Hiro Iwashima, Ryan Lee, Jonathan Goler, Audrey Mcloghlin, Doug Harris, Zvi Boshernitzan, Michael Yoon, Cesar Brea, Dennis Gregorovic, David Fullagar, Chris Spears, Kevin Tupper, Michael Duffy, Simon Carstensen, Dave Bauer, Tracy Adams, Greg Haverkamp, Philip Greenspun, Jin Choi, Sean Yamamoto, David Cohen, Chris Rasch, Richard Li, Jon Griffin, Roberto Mello, Gilbert Wong, Don Baccus, Ben Adida, Michael Cleverly, Janne Blonqvist, Jonathan Ellis, Janine Sisk, Jade Rubick, Chris Hardy, Jonathan Marsden, Vinod Kurup, Charles Hall, Tom Jackson and Karl Lehenbauer.

    Several people have helped with this document, including Torben Brosten, Don Baccus, Roberto Mello, Talli Somekh, Dave Bauer, Jim Lynch, Jon Griffin, Daryl Biberdorf, Bjorn Thor Jonsson, Jade Rubick, Fred Yankowski, Dan Chak, Sebastiano Pilla, Reuven Lerner, Malte Sussdorff, Stan Kaufman and Pascal Scheffers.

    All questions and comments regarding this guide should be posted on the OpenACS forums.

    ($Id: credits.html,v 1.45 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-caching.html0000644000175000017500000001110411501005400024121 0ustar frankiefrankie Basic Caching

    Basic Caching

    Based on a post by Dave Bauer.

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Caching using the database API is described in the database API tutorial.

    Caching using util_memoize

    1. Implement your proc as my_proc_not_cached

    2. Create a version of your proc called my_proc which wraps the non-cached version in the caching mechanism. In this example, my_proc_not_cached takes one argument, -foo, so the wrapper passes that on. The wrapper also uses the list command, to ensure that the arguments get passed correctly and to prevent commands passed in as arguments from being executed.

      ad_proc my_proc {-foo} {
              Get a cached version of my_proc.
      } {
          return [util_memoize [list my_proc_not_cached -foo $foo]]
      }
    3. In your code, always call my_proc. There will be a seperate cache item for each unique call to my_proc_not_cached so that calls with different arguments are cached seperately. You can flush the cache for each cache key by calling util_memoize_flush my_proc_not_cached args.

    4. The cached material will of course become obsolete over time. There are two ways to handle this.

      • Timed Expiration: pass in max_age to util_memoize. If the content is older than max_age, it will be re-generated.

      • Direct Flushing. In any proc which invalidates the cached content, call util_memoize_flush my_proc_not_cached args.

    5. If you are correctly flushing the cached value, then it will need to be reloaded. You may wish to pre-load it, so that the loading delay does not impact users. If you have a sequence of pages, you could call the cached proc in advance, to increase the chances that it's loaded and current when the user reaches it. Or, you can call (and discard) it immediately after flushing it.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/apm-requirements.html0000644000175000017500000012116711501005400024175 0ustar frankiefrankie Package Manager Requirements

    Package Manager Requirements

    By Bryan Quinn and Todd Nightingale

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    The following is a requirements document for the OpenACS Package Manager (APM), version 4.0 (APM4). APM4 offers a superset of APM v3.3 functionality with the following specific enhancements:

    • A public procedural API. (v 3.3 only has web-based UI)

    • Support for dependency checking.

    • Support for compound packages (to support installation chaining).

    • Support for on-line parameter setting.

    • Support for sub-site level configuration (requires revised parameter and /admin pages at sub-site level; deprecation of site-wide parameter file).

    To differentiate these new requirements from the requirements of version 3.3, all requirements new in v4 are prefaced with the number 4.

    We gratefully acknowledge the authors of APM 3 for their original design documentation which suggested these features, as well as the influence of the design and open-source implementation of the Red Hat Package manager, the Debian packaging system, and PERL's CPAN in the development of the ideas behind this document.

    Vision Statement

    A typical website will tend to offer its users a number of web-based services or applications, e.g. a bulletin board, calendaring, classified ads, etc. A website may also have underlying subsystems, such as a permissions system, content management system, etc. For such applications and subsystem components, modularity - or the degree to which a component can be encapsulated and decoupled from the rest of the system - is of great value. Thus the OpenACS Package Manager (APM) was created to allow website components, or packages, to be added, removed, and upgraded easily, with minimum disturbance to the rest of the system. This allows site owners to steadily offer users new and improved services, and also allows programmers to quickly and easily distribute their OpenACS components in a standardized manner to other OpenACS sites.

    In general terms, a package is a unit of software that serves a single well-defined purpose. The OpenACS Package Manager (APM) provides a mechanism for packaging, installing, and configuring OpenACS software in a consistent, user-friendly, and subsite-aware manner.

    System Overview

    The OpenACS Package Manager (APM) consists of:

    • A standard format for APM packages including:

      • Version numbering, independent of any other package and the OpenACS as a whole

      • Specification of the package interface

      • Specification of dependencies on other packages (if any)

      • Attribution (who wrote it) and ownership (who maintains it)

    • Web-based tools for package management:

      • Obtaining packages from a remote distribution point

      • Installing packages, if and only if:

        1. All prerequisite packages are installed

        2. No conflicts will be created by the installation

      • Configuring packages (obsoleting the monolithic OpenACS configuration file)

      • Upgrading packages, without clobbering local modifications

      • Uninstalling unwanted packages

    • A registry of installed packages, database-backed and integrated with file system-based version control

    • Web-based tools for package development:

      • Creating new packages locally

      • Releasing new versions of locally-created packages

      • Uploading packages to a global package repository on the web

      • Use of these tools should be safe, i.e. installing or removing a package should never break an OpenACS installation

    • Web-based tools for package configuration:

      • The ability to change package parameter values on-line through a simple web interface.

      • A new ad_parameter which does not require a monolithic site-wide parameter's file or server restarts for changes to take effect.

      • The ability to manage multiple package instances at the sub-site level.

    Use-cases and User-scenarios

    The APM is intended for the following classes of users, which may or may not overlap:

    1. Developers (referred to as 'the developer') use the APM to create a software package for distribution and use the procedural API for direct control of the APM system.

    2. Site-wide administrators (referred to as 'the administrator') use the APM to install packages for their OpenACS instance, and optionally make them available to sub-sites.

    3. Sub-site administrators (referred to as 'the sub-admin') use an administration interface to configure and enable packages for their sub-site.

    Initial Package Development

    David Developer writes a piece of software used to do knowledge management (km) for the OpenACS. He distributes his data model, procedure code, UI pages, and his documentation according to the APM specification. He splits the documentation and the code into sub-packages, and creates a KM installation-chain to install both with the APM developer UI. Noting that his software was built with Patricia Programmer's Super Widget toolkit, he specifies that as a dependency. Moreover, since this package is capable of being used at the sub-site level, David configures this option in the package. When the package development is complete, David uses the APM developer UI to construct a distribution file. He assigns it a version number, 1.0, and makes the package available for download at the OpenACS package repository.

    Initial Package Installation

    Annie Admin learns of David's KM system by browsing the OpenACS package repository. Annie Admin uses the APM administrator UI on her system. She selects to install a package from a URL and types the URL displayed on the system. The APM automatically downloads the package. The dependency checker notices that Patricia's Super Widget toolkit is required, so it warns Annie of this. Annie selects an option to find a package that satisfies the dependency at the OpenACS APM repository. The APM informs Annie that it can download and install Jim's Super Widget toolkit. Annie confirms this option. After successfully installing Jim's toolkit, Annie proceeds to install David's KM system. The data model is loaded and all of the files necessary for the software are installed. Because installation was successful, the package is available for use.

    Since the package is available for use, its initialization routines are set to run automatically on server startup. Annie is warned that since there are initialization routines, she must restart the server for the package to be ready for use. Annie restarts the server.

    Initial Subsite Use of Package

    Annie Admin decides to make the KM module available only to a particular sub-site type on her OpenACS system, and not others. She specifies this option using the Sub-site type UI (not part of APM).

    Annie Admin notifies Sally SubAdmin by e-mail that a new package is now available for use. Sally goes to her sub-site /admin page and sees that a new entry, KM, is available. Sally clicks on it and finds links to the installed KM documentation and to the web based configuration utility. Then, Sally configures the package using an automatically generated web interface and enables KM for use on her sub-site. After some initial use of the package, Sally decides to change some parameters using the SubAdmin UI. These changes take effect immediately, without any server restarts.

    Upgrade Process

    Sally SubAdmin finds a bug in the KM system and sends a report to David Developer. David reads the bug report and verifies that the bugs are present in the current version. Because the bugs are present in the shared procedure file, David assigns a watch to the file. David makes the necessary modifications to the source code and saves the file. Because a watch was assigned to the file, the APM automatically reloads the updated code. David tests the program and confirms that the bug is fixed. He increments the minor version number and makes km v 1.1 available for download at the repository.

    Sally SubAdmin asks Annie Administrator to upgrade the package using the APM UI. This upgrade supersedes the old version of KM at the site-wide level. Once Annie upgrades the package, the new version starts working immediately in Sally's sub-site.

    Procedural API

    Danielle Developer wants her software to perform different actions depending on what version of another package is installed. She uses the APM procedural API to check if KM version 1.0 is installed or version 1.1. Based on the results of this procedural call, the software exhibits different behavior.

    Requirements: Data Model

    • 4.500.0 Package Identification (All of these items are entered by the developer using the developer UI.)

      4.500.1 A human readable package key that is guaranteed to be unique to the local OpenACS site must be maintained by the APM. For example, "apm."

      4.500.5 A package id (primary key) that is guaranteed to be unique to the local site must be maintained by the APM. For example, "25."

      4.500.10 A package URL that is guaranteed to be unique across all sites must be maintained by the APM. The package URL should point to a server that allows download of the latest version of the package. For example, "http://openacs.org/software."

    • 4.505.0 Version Identification (All of these items are entered by the developer using the developer UI.)

      4.505.1 A version id (primary key) that is guaranteed to be unique to the local site must be maintained by the APM.

      4.505.5 A version URL that is guaranteed to be unique across all sites must be maintained by the APM. The version URL should point to a server that allows download of a specific version of the package.

    Requirements: API

    The API for APM v3 is explicitly a private API. However, it would be useful to obtain information from the APM through a procedural API. Implementing the API specified below is quite easy given that there are pages that already do all of the below in raw SQL.

    • 4.400.0 Packages Status Predicates

      4.400.1 Given defining information such as a package URL, the APM API can return the status of the package on the local OpenACS instance.

    • 4.405.0 Package Information Procedures

      4.405.1 The APM API can return information for any locally installed packages, including the version number, paths and files, and package key.

    • 4.410.0 Sub-site Procedures

      4.410.1 After a package has been installed at the site-wide level, the system API will provide means to check for package presence, creation, enabling, disabling, and destruction on a subsite.

    • 4.415.0 Parameter Values (replaces ad_parameter)

      4.415.1 The system API shall allow subsite parameters for an installed package to be set by either site-wide administrators or sub-site admins. The subsite parameter can be set to be non-persistent (but default is to survive server restarts). The subsite parameter can also be set to only take effect after a server restart (default is immediate).

      4.415.5 Parameters for a given subsite and package can be returned by the system API.

    Requirements: Security

    Provisions will be made to assure that packages are securely identified.

    • 4.600.1 Each package will have a PGP signature and there will be MD5 time stamps for each file within the package.

    • 4.600.5 The APM will provide a facility to validate both the PGP signature and MD5 stamps information before a package install.

    Requirements: The User Interface

    The user interface is a set of HTML pages that are used to drive the underlying API. It is restricted to site-wide administrators because the actions taken here can dramatically affect the state of the running OpenACS.

    Requirements: The Developer's Interface

    The intent of the developer's interface is to enable the developer to construct and maintain APM packages. It will be possible to disable the developer's interface for production sites to help reduce the chance of site failure; much of the functionality here can have cascading effects throughout the OpenACS and should not be used on a production site.

    • 10.0 Define a package.

      The developer must be able to create a new package by specifying some identifying information for the package. This includes a package name, a package key, version information, owner information, and a canonical URL.

      10.1 The APM must maintain the state of all locally generated packages.

      10.50 If the developer fails to provide the required information, the package cannot be created.

      10.55 All of the package information should be editable after creation, except for the package key.

      4.10.60 The package creator must specify whether the package is capable of being used in sub-sites, or if only a single, global instance of the package is permitted.

      4.10.65 If the developer fails to provide unique information for unique fields specified in the data model requirements, the package cannot be created.

    • 20.0 Add files to a package

      20.1 The developer must be able to add files to the package. This is done by copying the files into the package directory in the host OS's file system. Files can be added at any point after package creation.

      20.3 Once a package has been versioned and distributed, no new files should be added to the package without incrementing the version number.

      20.5 The APM's UI should facilitate the process of adding new files, by scanning the file system for new files automatically, and allowing the developer to confirm adding them.

      20.10 The developer cannot add files to a given package via the UI that do not exist in the file system already.

      20.15 Package file structure must follow a specified convention. Please see the design document for what we do currently.

    • 30.0 Remove files from a package

      The developer must be able to remove files from a package. This can be done in two ways.

      • 30.1 Access the APM UI, browse the file list, and remove files.

        30.1.1If a file is removed from the package list, but not from the file system, an error should be generated at package load time.

      • 30.5 Remove the file from file system.

        30.5.1 The APM UI should take note of the fact that the file is gone and offer the developer an option to confirm the file's deletion.

    • 40.0 Modify files in a package.

      40.1 The developer should be able to modify files in the file system. The APM UI should not interfere with this.

      40.5 However, if the developer modifies files containing procedural definitions, APM UI should allow a means to watch those files and automatically reload them if changed. See requirement 50.0 for more detail.

      40.10 Also, although a change in files implies that the package distribution file is out of date, it is the developer's responsibility to update it.

    • 4.45.0 Manage Package Dependency Information.

      4.45.1 The developer should be able to specify which interfaces the package requires.

      4.45.5 The developer should be able to specify which interfaces the package provides.

      4.45.10 Circular dependencies are not allowed.

    • 50.0 Watch a file

      4.50.1 The developer should be able to assign a watch to any Tcl procedure file, whether in /packages or /tcl.

      50.5 If a watched file is locally modified, then it will be automatically reloaded, thus allowing for any changes made to take affect immediately.

      4.50.10 The setting of a watch should be persistent across server restarts.

    • 60.0 Display an XML package specification

      60.1 The developer should be able to view the XML package specification that encodes all package information.

    • 70.0 Write an XML package specification to the file system

      70.1 The developer should be able to write an up-to-date XML specification to disk.

      70.5 The developer should be able to request the current XML specification for all installed, locally generated packages.

    • 130.0 Distribution file generation

      130.1 The developer should be able to generate a .APM distribution file for the package with just one click.

      130.5 Generating a distribution file implies doing an "up-to-date" check on all of the files. If any of the files have changed since package installation, then a new version of the package is created.

    • 140.0 Access CVS information

      140.1 The developer should be able to determine the CVS status of a package, or all packages, with a single click.

    • 4.400.0 Compound Package Construction

      4.400.1 The developer can include .APM packages (sub-packages) within a package (the compound package) like any other file.

      4.400.5 The recommended usage for this feature is to allow for separation of optional and required components from the installation as well as better organization of files once installed. For example, all documentation for the community-core can be packages as community-core-doc.apm. It is legal to include sub-packages with dependencies that are not satisfied by the packages in the compound package, but this is discouraged. In such a case, the sub-package should really be a separate package that is required by the compound package.

      4.400.10 If a sub-package is required for the installation of the compound package, the compound package should have a registered dependency on the sub-package.

    Requirements: The Site-Wide Administrator's Interface

    The requirement of the administrator's interface is to enable the administrator to install, enable, upgrade, disable, deinstall, and delete packages.

    • 80.0 Package Enable/Disable

      4.80.1 The administrator should be able mark an installed package as enabled. This means that the package is activated and its functionality is delivered through the Request Processor. As of OpenACS 4, this is done through the sub-site system.

      4.80.5 Moreover, the administrator must be able to disable a package, thereby removing the functionality provided to a sub-site. As of OpenACS 4, this is done through the sub-site system.

    • 90.0 Package Install

      90.1 The administrator must be able to install new packages either from locally maintained .APM files or from URLs.

      90.5 In the case of an URL, the APM transparently downloads the APM file off the web, proceeds with a file based installation, and then optionally removes the .APM file just downloaded.

      90.10.1 If .APM files are present in a package, then it is considered a compound package (use 4.410.0).

      90.15.0 Installation requires these steps:

      1. 90.15.1The package dependencies are scanned. If some dependencies are not present, the system warns the administrator that installation cannot proceed until those packages are installed.

      2. 90.15.2 Assuming all dependencies are present, APM extracts the contents of the APM file into the /packages directory.

      3. 90.15.3 The administrator is offered the option of importing directly into CVS.

      4. 90.15.4 The administrator is given a list of data model scripts found in the package and can select which ones to be executed.

      5. 90.15.5 If no errors are recorded during this process, the package is enabled.

    • 4.410.0 Compound package Install

      4.410.1 If .APM files are present in a package, then it is considered a compound package.

      4.410.5.0 Installation of a compound package proceeds according to the following sequence:

      1. 4.410.5.1 Identify the set of all sub-packages within the compound package by scanning for all files with .APM.

      2. 4.410.5.2 Identify which sub-packages are required by checking the dependencies of the compound package. If there dependencies not satisfied by the current system or the packages included with the compound package, halt installation and inform user to install these packages first.

      3. 4.410.5.3 Present Administrator with the ability to choose which sub-packages to install. Required sub-packages must be installed.

      4. 4.410.5.4 Proceed with the installation of each sub-package, starting with required packages. If the sub-package is already installed, then do nothing. Else, If the sub-package is a normal package, proceed according to 90.15.0, otherwise if it is a compound package, proceed according to 4.410.5.0.

      5. 4.410.5.5 If all required sub-packages are installed, proceed to install non-required sub-packages. If there was a failure during the installation of a required sub-package, then the installation of the compound package is also a failure.

      6. 4.410.5.6 Any attempt to install a compound package in the future involves a choice presented to the admin of installing any uninstalled sub-packages.

    • 4.420.0 Recovering from failed package installation

      4.420.1 If any error is generated during package installation, the package is not considered installed. To recover from this failure, the package should be selected for installation again.

    • 100.0 Version Upgrade

      100.1 The administrator can upgrade to a new version of a package. This entails

      1. 100.1.1 Running any necessary and included upgrade scripts.

      2. 100.1.5 Replacing any old files with new versions.

      3. 100.1.10 Marking the old version of the package as 'superseded' and disabling it.

      4. 100.1.15 Assuming no errors from above, the new package is enabled.

    • 110.0 Package Deinstall

      110.1 The administrator must be able to deinstall a package that has already been installed. Deinstallation entails:

      1. 110.1.1 Running any data model scripts necessary to drop the package.

      2. 110.1.5 Moving all of the files into a separate location in the file system from the installed packages.

      3. 4.110.1.10 If the package is a compound package, then the administrator must confirm removing all sub-packages. Optionally, some sub-packages can be kept.

      110.5 Deinstalled packages can be re-installed at a later date.

      4.110.10 If deinstalling a package or any of its sub-packages breaks a dependency, then deinstallation cannot proceed until the package registering the dependency is removed.

    • 120.0 Package Deletion

      120.1 The administrator should be able to completely erase all records of the package. This involves removing all instances of the package, all related database tables and content.

      120.5 This option can only be used if all package instances are deleted or marked as disabled. This is purposefully cumbersome because deleting all instances of a package can have far-sweeping consequences throughout a site and should almost never be done.

    • 150.0 Scan for new or modified packages

      150.1 The administrator should be able to scan the file system for any changes made in any of the installed package files.

      150.5 The administrator should be able to scan the file system for any newly installed packages.

    Requirements: The Sub-Site Administrator's Interface

    If the developer is in charge of creating packages and the administrator for installing them, then the sub-site administrator is responsible for configuring and enabling packages. In order for a package to be available for a sub-site it must be associated with the sub-site's type specification. This interface is part of the sub-site /admin interface.

    • 4.300 Creating a package instance.

      4.300.1 From the sub-site /admin interface, there should be an option to view all packages available in the system as well as an option to add a package to the subsite.

      4.300.5 From the "add" option, the sub-admin can select from a list of packages registered as available in the sub-site type to which the sub-site belongs.

      4.300.19 Once a package instance is added, it is available on the list of the subsite's available packages.

    • 4.305 Configuring a package instance.

      4.305.1 An automatic web interface that lists all parameters with current values must be available.

      4.305.5 Changing the values for the parameters is accomplished simply by submitting an HTML form.

    • 4.310 Enabling a package instance.

      4.310.1 The sub-admin should be able to enable a package with a single click. Enabling a package means that the OpenACS will serve its URLs properly.

    • 4.315 Disabling a package instance.

      4.315.1 The sub-admin should be able to disable a package with a single click. Disabling a package means that the OpenACS will no longer serve those URLs.

    • 4.320 Deleting a package instance.

      4.320.1 Deleting a package instance involves deleting not only the package instance, but any and all content associated with it. It is questionable whether this option should even be available due to its drastic consequences. Reviewer comments appreciated.

    Implementation notes

    Despite the fact that requirements are meant to be design/implementation neutral, the following thoughts were in our head when specifying these requirements. You must be familiar with the new object design for this to be comprehensible.

    When a package is installed system-wide, a corresponding acs_object_type is created for it. All parameters registered for the package are registered for that acs_object_type.

    When a package instance is created, it is an acs_object. Its parameters are set using the acs_attribute_values table. The automatic web interface for setting package parameters should be one and the same with the interface for setting acs object attribute values. Consequently, the implementation of these features should be quite straightforward.

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation8/10/2000Bryan Quinn, Todd Nightingale
    Reviewed8/11/2000John Prevost, Mark Thomas, and Pete Su
    0.2Revised and updated8/12/2000Bryan Quinn
    0.3Reviewed, revised, and updated - conforms to requirements template.8/18/2000Kai Wu
    0.4Minor edits before ACS 4 Beta.9/30/2000Kai Wu
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-second-database.html0000644000175000017500000001173611501005400025555 0ustar frankiefrankie Connect to a second database

    Connect to a second database

    It is possible to use the OpenACS TCL database API with other databases. In this example, the OpenACS site uses a PostGre database, and accesses another PostGre database called legacy.

    1. Modify config.tcl to accomodate the legacy database, and to ensure that the legacy database is not used for standard OpenACS queries:

      ns_section ns/db/pools
      ns_param   pool1              "Pool 1"
      ns_param   pool2              "Pool 2"
      ns_param   pool3              "Pool 3"
      ns_param   legacy             "Legacy"
      
      ns_section ns/db/pool/pool1
      #Unchanged from default
      ns_param   maxidle            1000000000
      ns_param   maxopen            1000000000
      ns_param   connections        5
      ns_param   verbose            $debug
      ns_param   extendedtableinfo  true
      ns_param   logsqlerrors       $debug
      if { $database == "oracle" } {
          ns_param   driver             ora8
          ns_param   datasource         {}
          ns_param   user               $db_name
          ns_param   password           $db_password
      } else {
          ns_param   driver             postgres
          ns_param   datasource         ${db_host}:${db_port}:${db_name}
          ns_param   user               $db_user
          ns_param   password           ""
      }
      
      ns_section ns/db/pool/pool2
      #Unchanged from default, removed for clarity
      
      ns_section ns/db/pool/pool3
      #Unchanged from default, removed for clarity
      
      ns_section ns/db/pool/legacy
      ns_param   maxidle            1000000000
      ns_param   maxopen            1000000000
      ns_param   connections        5
      ns_param   verbose            $debug
      ns_param   extendedtableinfo  true
      ns_param   logsqlerrors       $debug
      ns_param   driver             postgres
      ns_param   datasource         ${db_host}:${db_port}:legacy_db
      ns_param   user               legacy_user
      ns_param   password           legacy_password
      
      
      ns_section ns/server/${server}/db
      ns_param   pools              *
      ns_param   defaultpool        pool1
      
      ns_section ns/server/${server}/acs/database
      ns_param database_names [list main legacy]
      ns_param pools_main [list pool1 pool2 pool3]
      ns_param pools_legacy [list legacy]
    2. To use the legacy database, use the -dbn flag for any of the db_ API calls. For example, suppose there is a table called "foo" in the legacy system, with a field "bar". List "bar" for all records with this tcl file:

      db_foreach -dbn legacy get_bar_query {
        select bar from foo
        limit 10
      } {
        ns_write "<br/>$bar"
      }
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-openacs-inittab.html0000644000175000017500000001707511501005400025425 0ustar frankiefrankie AOLserver keepalive with inittab

    AOLserver keepalive with inittab

    This is an alternative method for keeping the AOLserver process running. The recommended method is to run AOLserver supervised.

    This step should be completed as root. This can break every service on your machine, so proceed with caution.

    • There are 2 general steps to getting this working.

      1. Install a script called restart-aolserver. This script doesn't actually restart AOLserver - it just kills it.

      2. Ask the OS to restart our service whenever it's not running. We do this by adding a line to /etc/inittab.

      Calling restart-aolserver kills our service. The OS notices that our service is not running, so it automatically restarts it. Thus, calling restart-aolserver effectively restarts our service.

    • Copy this file into /var/tmp/restart-aolserver.txt.

    • This script needs to be SUID-root, which means that the script will run as root. This is necessary to ensure that the AOLserver processes are killed regardless of who owns them. However the script should be executable by the web group to ensure that the users updating the web page can use the script, but that general system users cannot run the script. You also need to have Perl installed and also a symbolic link to it in /usr/local/bin.

      [joeuser ~]$ su - 
      Password: ***********
      [root ~]# cp /var/tmp/restart-aolserver.txt /usr/local/bin/restart-aolserver
      [root ~]# chown root.web /usr/local/bin/restart-aolserver
      [root ~]# chmod 4750 /usr/local/bin/restart-aolserver
      [root ~]# ln -s /usr/bin/perl /usr/local/bin/perl
      [root ~]# exit
    • Test the restart-aolserver script. We'll first kill all running servers to clean the slate. Then, we'll start one server and use restart-aolserver to kill it. If it works, then there should be no more servers running. You should see the following lines.

      [joeuser ~]$ killall nsd
      nsd: no process killed
      [joeuser ~]$ /usr/local/aolserver/bin/nsd-postgres -t ~/var/lib/aolserver/birdnotes/nsd.tcl
      [joeuser ~]$ restart-aolserver birdnotes
      Killing 23727 
      [joeuser ~]$ killall nsd
      nsd: no process killed

      The number 23727 indicates the process id(s) (PIDs) of the processes being killed. It is important that no processes are killed by the second call to killall. If there are processes being killed, it means that the script is not working.

    • Assuming that the restart-aolserver script worked, login as root and open /etc/inittab for editing.

      [joeuser ~]$ su -
      Password: ************
      [root ~]# emacs -nw /etc/inittab
    • Copy this line into the bottom of the file as a template, making sure that the first field nss1 is unique.

      nss1:345:respawn:/usr/local/aolserver/bin/nsd-postgres -i -u nobody -g web -t /home/joeuser/var/lib/aolserver/birdnotes/nsd.tcl
    • Important: Make sure there is a newline at the end of the file. If there is not a newline at the end of the file, the system may suffer catastrophic failures.

    • Still as root, enter the following command to re-initialize /etc/inittab.

      [root ~]# killall nsd    
      nsd: no process killed
      [root ~]# /sbin/init q
    • See if it worked by running the restart-aolserver script again.

      [root ~]# restart-aolserver birdnotes
      Killing 23750

    If processes were killed, congratulations, your server is now automated for startup and shutdown.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/eng-standards-plsql.html0000644000175000017500000002361111501005400024555 0ustar frankiefrankie PL/SQL Standards

    PL/SQL Standards

    By Richard Li and Yon Feldman

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Like any other part of the OpenACS, PL/SQL (or pl/pgsql) code must be maintainable and professional. This means that it must be consistent and therefore must abide by certain standards. The standards will ensure that our product will be useful long after the current people building and maintaining it are around. Following are some standards and guidelines that will help us achieve this goal:

    General

    1. All PL/SQL code must be well documented. We must write code that is maintainable by others, this is especially true in our case because we are building an open source toolkit than anyone can download and browse the source code. So document like you are trying to impress your "Introduction to Programming" professor or TA.

    2. It is important to be consistent throughout an application as much as is possible given the nature of team development. This means carrying style and other conventions suchs as naming within an application, not just within one file.

    Code

    1. Encapsulation of related fuctionality is key to maintainability and upgradeability of our software. Try to bundle your code into packages whenever possible. This will make upgrading, bug fixing, and customizing, among other things, a possibility.

    2. When creating functions or procedures use the following template, it demonstrates most of the guidelines set forth in this document that correspond to functions and procedures:

       
              create or replace procedure|function <proc_or_func_name> (
                       <param_1>    in|out|inout <datatype>,
                       <param_2>    in|out|inout <datatype>,
                       ...
                       <param_n>    in|out|inout <datatype>
              )
              [return <datatype>]
              is
                      <local_var_1>    <datatype>
                      <local_var_2>    <datatype>
                      ...
                      <local_var_n>    <datatype>
              begin
                      ...
              end <proc_or_func_name>;
              /
              show errors
           
      
    3. Always use create or replace procedure|function <proc_or_func_name>. It makes reloading packages much easier and painless to someone who is upgrading or fixing a bug.

    4. Always qualify end statements, i.e., the end statement for a package should be end <package_name>;, not just end;; same goes for procedures, functions, package bodies, and triggers.

    5. Always use the "show errors" SQL*Plus command after each PL/SQL block. It will help you debug when there are compilation errors in your PL/SQL code.

    6. Name parameters as simply as possible, i.e., use the column name if the parameter corresponds to a table column. We're deprecating the v_* and *_in syntax in favor of named parameters notation:

      
            
              acs_user.create(first_names => 'Jane', last_name => 'Doe', etc.)
            
              instead of
            
              acs_user.create(first_names_in => 'Jane', last_name_in => 'Doe', etc.)
            
           
      

      To achieve this we must fully qualify arguements passed into procedures or functions when using them inside a SQL statement. This will get rid of any ambiguities in your code, i.e. it will tell the parser when you want the value of the column and when you want the value from the local variable. Here is an example:

      
              create or replace package body mypackage 
                  .
                  .
                  procedure myproc(party_id in parties.party_id%TYPE) is begin
                      .
                      .
                      delete
                        from parties
                       where party_id = myproc.party_id;
                      .
                      .
                  end myproc;
                  .
                  .
              end mypackage;
              /
              show errors
           
      
    7. Explicitly designate each parameter as "in," "out," or "inout."

    8. Each parameter should be on its own line, with a tab after the parameter name, then in/out/inout, then a space, and finally the datatype.

    9. Use %TYPE and %ROWTYPE whenever possible.

    10. Use 't' and 'f' for booleans, not the PL/SQL "boolean" datatype because it can't be used in SQL queries.

    11. All new functions (e.g., acs_object.new, party.new, etc.) should optionally accept an ID:

      
            
              create or replace package acs_object
              as
                  function new (
                      object_id       in acs_objects.object_id%TYPE default null,
                      object_type     in acs_objects.object_type%TYPE default 'acs_object',
      	        creation_date   in acs_objects.creation_date%TYPE default sysdate,
                      creation_user   in acs_objects.creation_user%TYPE default null,
                      creation_ip     in acs_objects.creation_ip%TYPE default null,
                      context_id      in acs_objects.context_id%TYPE default null
                 ) return acs_objects.object_id%TYPE;
           
          
      

      takes the optional argument object_id. Do this to allow people to use the same API call when they are doing double click protection, that is, tehy have already gotten an object_id and now they want to create the object with that object_id.

    Style

    Some general style guidelines to follow for the purpose of consistency across applications.

    1. Standard indentation is 4 spaces. Our PL/SQL code is not only viewable in the SQL files but also through our SQL and PL/SQL browsers. This means that we should try to make it as consistent as possible to all source code readers.

    2. Lowercase everything, with the exception of %TYPE and %ROWTYPE.

    ($Id: eng-standards-plsql.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/db-api.html0000644000175000017500000012255411501005400022034 0ustar frankiefrankie The OpenACS Database Access API

    The OpenACS Database Access API

    By Pete Su and Jon Salz. Modified by Roberto Mello.

    Overview

    One of OpenACS's great strengths is that code written for it is very close to the database. It is very easy to interact with the database from anywhere within OpenACS, and we have a coherent API for database access which makes this even easier.

    More detailed information about the DB api is available at Database Access API.

    DB API Examples

    The OpenACS database API is meant to save developers from making common mistakes and to provide a more structured syntax for specifying database operations, including transactions. Here's an example of the API.

    set count 0
    set tcl_var "foo"
    set sql {
          	SELECT foo, bar, baz
           FROM some_table, some_other_table
           WHERE some_table.id = some_other_table.id
             and some_table.condition_p = :tcl_var
    }
    
    db_transaction {
        db_foreach my_example_query_name $sql {
            lappend rows [list $foo $bar $baz]
            incr count
        }
        foreach row $rows { 
            call_some_proc $foo $bar $baz
        }
    }

    There are several things to note here:

    1. No explicit code for grabbing and releasing handles. Usage of the Database API implicitly deals with all handle management issues.

    2. The db_transaction command makes the scope of a transaction clear; db_transaction takes the code block argument and automatically runs it in the context of a transaction. If you use something like db_foreach though, you need to make sure that there are no calls in the code block which would take a second db handle since the transaction is only valid for one handle (thats why we build up a list of returned values and call a second proc outside the db_foreach loop).

    3. The command db_foreach writes our old while loop for us.

    4. Every SQL query has a name, which is used in conjunction with .XQL files to support multiple databases.

    5. Finally and most importantly, there API implements bind variables, which we will cover next.

    Bind Variables

    Bind variables are placeholders for literal values in an SQL query being sent to the server. In the old way, data was generally passed to directly to the DB backend, via Tcl string interpolation. In the example above, the query would look like:

    select foo, bar, baz 
    from some_table, some_other_table
    where some_table.id=some_other_table.id  
    and some_table.condition_p = '$foo'

    There are a few problems with this:

    1. If the value of $foo is a huge string, then we waste a lot of time in the database server doing useless parsing.

    2. Second, if the literal value contains characters like single quotes, we have to be careful to properly escape them, because not quoting them will lead to surprising errors.

    3. Third, no type checking occurs on the literal value. Finally, if the Tcl variable is passed in or between web forms or otherwise subject to external modification, there is nothing keeping malicious users from setting the Tcl variable to some string that changes the query textually. This type of attack, called SQL smuggling, can be very damaging - entire tables can be exposed or have their contents deleted, for example.

      Another very important reason for using bind variables is performance. Oracle can cache previously parsed queries. If there are values in the where clause, that is how the query is cached. It also performs bind variable susbstitution after parsing the SQL statement. This means that SQL statements that use bind variables will always match (assuming all else is the same) while SQL statements that do not use bind variables will not match unless the values in the statement are exactly the same. This will improve the query cache considerably, which can make the server much more efficient.

    What the DB API (in conjuntion with the database drivers implemented for aolserver) do is send the SQL statement to the server for parsing, then bind values to the variables and sends those values along seperately as a second step. This seperate binding step is where the term bind variable comes from.

    This split has several advantages. First, type checking happens on the literal. If the column we are comparing against holds numbers, and we send a string, we get a nice error. Second, since string literals are no longer in the query, no extra quoting is required. Third, substitution of bind variables cannot change the actual text of the query, only the literal values in the placeholders. The database API makes bind variables easy to use by hooking them smoothly into the Tcl runtime so you simply provide :tclvar and the value of $tclvar is sent to the backend to actually execute the query.

    The database API parses the query and pulls out all the bind variable specifications and replaces them with generic placeholders. It then automatically pulls the values of the named Tcl vars out of the runtime environment of the script, and passes them to the database.

    Note that while this looks like a simple syntactic change, it really is very different from how interpolated text queries work. You use bind variables to replace what would otherwise be a literal value in a query, and Tcl style string interpolation does not happen. So you cannot do something like:

    set table "baz"
    set condition "where foo = bar"
    
    db_foreach my_query { select :table from some_table where :condition }
        

    SQL will not allow a literal to occur where we've put the bind variables, so the query is syntactically incorrect. You have to remember that while the bind variable syntax looks similar to variable interpolation in Tcl, It is not the same thing at all.

    Finally, the DB API has several different styles for passing bind variable values to queries. In general, use the style presented here because it is the most convenient.

    Usage

    Every db_* command accepting a SQL command as an argument supports bind variables. You can either

    • Specify the -bind switch to provide a set with bind variable values, or

    • Specify the -bind switch to explicitly provide a list of bind variable names and values, or

    • Not specify a bind variable list at all, in which case Tcl variables are used as bind variables.

    The default behavior (i.e., if the -bind switch is omitted) is that these procedures expect to find local variables that correspond in name to the referenced bind variables, e.g.:

    
    set user_id 123456
    set role "administrator"
    
    db_foreach user_group_memberships_by_role {
        select g.group_id, g.group_name
        from user_groups g, user_group_map map
        where g.group_id = map.user_id
        and map.user_id = :user_id
        and map.role = :role
    } {
        # do something for each group of which user 123456 is in the role
        # of "administrator"
    }
    
          

    The value of the local Tcl variable user_id (123456) is bound to the user_id bind variable.

    The -bind switch can takes the name of an ns_set containing keys for each bind variable named in the query, e.g.:

    
    set bind_vars [ns_set create]
    ns_set put $bind_vars user_id 123456
    ns_set put $bind_vars role "administrator"
    
    db_foreach user_group_memberships_by_role {
        select g.group_id, g.group_name
        from user_groups g, user_group_map map
        where g.group_id = map.user_id
        and map.user_id = :user_id
        and map.role = :role
    } -bind $bind_vars {
        # do something for each group in which user 123456 has the role
        # of "administrator"
    }
    
          

    Alternatively, as an argument to -bind you can specify a list of alternating name/value pairs for bind variables:

    	
    db_foreach user_group_memberships_by_role {
        select g.group_id, g.group_name
        from user_groups g, user_group_map map
        where g.group_id = map.user_id
        and map.user_id = :user_id
        and map.role = :role
    } -bind [list user_id 123456 role "administrator"] {
        # do something for each group in which user 123456 has the role
        # of "administrator"
    }
    
          

    Nulls and Bind Variables

    When processing a DML statement, Oracle coerces empty strings into null. (This coercion does not occur in the WHERE clause of a query, i.e. col = '' and col is null are not equivalent.)

    As a result, when using bind variables, the only way to make Oracle set a column value to null is to set the corresponding bind variable to the empty string, since a bind variable whose value is the string "null" will be interpreted as the literal string "null".

    These Oracle quirks complicate the process of writing clear and abstract DML difficult. Here is an example that illustrates why:

    
    #
    # Given the table:
    #
    #   create table foo (
    #           bar        integer,
    #           baz        varchar(10)
    #   );
    #
    
    set bar ""
    set baz ""
    
    db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)"
    #
    # the values of the "bar" and "baz" columns in the new row are both
    # null, because Oracle has coerced the empty string (even for the
    # numeric column "bar") into null in both cases
    
          

    Since databases other than Oracle do not coerce empty strings into null, this code has different semantics depending on the underlying database (i.e., the row that gets inserted may not have null as its column values), which defeats the purpose of SQL abstraction.

    Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the empty string): db_null.

    Use it instead of the empty string whenever you want to set a column value explicitly to null, e.g.:

    set bar [db_null]
    set baz [db_null]
    
    db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)"
    #
    # sets the values for both the "bar" and "baz" columns to null

    Sequence Pooling

    The database library can transparently maintain pools of sequence values, so that each request for a new sequence value (using db_nextval) does not incur a roundtrip to the server. For instance, this functionality is very useful in the security/sessions library, which very frequently allocates values from the sec_id_seq sequence. To utilize this functionality for a particular sequence, register the sequence to be pooled, either using the db_register_pooled_sequence procedure at server startup time, or by including a configuration parameter of the form

    
    PoolSequence.sequence_name_seq=count
    
        

    in any configuration section in the yourservername.ini file, e.g.,

    
    [ns/server/yourservername/acs/security]
    PoolSequence.sec_id_seq=20
    
        

    The database library will allocate this number of sequence values at server startup. It will periodically scan pools and allocate new values for sequences which are less than half-full. (This normally occurs every 60 seconds, and is configurable via the PooledSequenceUpdateInterval parameter in the [ns/server/ yourservername /acs/database] configuration section.)

    Basic API

    The Database API has several functions that wrap familiar parts of the AOLserver database API.

    Note that you never have to use ns_db anymore (including ns_db gethandle)! Just start doing stuff, and (if you want) call db_release_unused_handles when you're done as a hint to release the database handle.

    db_abort_transaction
    db_abort_transaction
    	  

    Aborts all levels of a transaction. That is if this is called within several nested transactions, all of them are terminated. Use this insetead of db_dml "abort" "abort transaction".

    db_multirow
    db_multirow [ -local ] [ -append ] [ -extend column_list ] \
        var-name statement-name sql \
        [ -bind bind_set_id | -bind bind_value_list ] \
        code_block [ if_no_rows if_no_rows_block ]
    	

    Performs the SQL query sql, saving results in variables of the form var_name:1, var_name:2, etc, setting var_name:rowcount to the total number of rows, and setting var_name:columns to a list of column names.

    Each row also has a column, rownum, automatically added and set to the row number, starting with 1. Note that this will override any column in the SQL statement named 'rownum', also if you're using the Oracle rownum pseudo-column.

    If the -local is passed, the variables defined by db_multirow will be set locally (useful if you're compiling dynamic templates in a function or similar situations).

    You may supply a code block, which will be executed for each row in the loop. This is very useful if you need to make computations that are better done in Tcl than in SQL, for example using ns_urlencode or ad_quotehtml, etc. When the Tcl code is executed, all the columns from the SQL query will be set as local variables in that code. Any changes made to these local variables will be copied back into the multirow.

    You may also add additional, computed columns to the multirow, using the -extend { col_1 col_2 ... } switch. This is useful for things like constructing a URL for the object retrieved by the query.

    If you're constructing your multirow through multiple queries with the same set of columns, but with different rows, you can use the -append switch. This causes the rows returned by this query to be appended to the rows already in the multirow, instead of starting a clean multirow, as is the normal behavior. The columns must match the columns in the original multirow, or an error will be thrown.

    Your code block may call continue in order to skip a row and not include it in the multirow. Or you can call break to skip this row and quit looping.

    Notice the nonstandard numbering (everything else in Tcl starts at 0); the reason is that the graphics designer, a non programmer, may wish to work with row numbers.

    Example:

    db_multirow -extend { user_url } users users_query {
        select user_id first_names, last_name, email from cc_users
    } {
        set user_url [acs_community_member_url -user_id $user_id]
    }
        

    You can also iterate over a multirow after it has been created - check the documentation for template::multirow

    For example,

    db_multirow assets assets {
      select asset_id,
        from ...
    }
    
    ..
    
    set asset_id_l [list]
    multirow foreach assets {
      lappend asset_id_l $asset_id
    }
              

    Technically it's equivalent to using a code block on the end of your db_multirow.

    db_null
    db_null
    	  

    Returns a value which can be used in a bind variable to represent the SQL value null. See Nulls and Bind Variables above.

    db_foreach
    db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \
        [ -column_array array_name | -column_set set_name ] \
        code_block [ if_no_rows if_no_rows_block ]
    	  

    Performs the SQL query sql , executing code_block once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes if_no_rows_block (if provided).

    Example:

    
    db_foreach select_foo "select foo, bar from greeble" {
        doc_body_append "<li>foo=$foo; bar=$bar\n"
    } if_no_rows {
        doc_body_append "<li>There are no greebles in the database.\n"
    }
    
    	  

    The code block may contain break statements (which terminate the loop and flush the database handle) and continue statements (which continue to the next row of the loop).

    db_1row
    db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \
        [ -column_array array_name | -column_set set_name ]
    	  

    Performs the SQL query sql, setting variables to column values. Raises an error if the query does not return exactly 1 row.

    Example:

    
    db_1row select_foo "select foo, bar from greeble where greeble_id = $greeble_id"
    # Bombs if there's no such greeble!
    # Now $foo and $bar are set.
    
    	  
    db_0or1row
    db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \
        [ -column_array array_name | -column_set set_name ]
    	  

    Performs the SQL query sql. If a row is returned, sets variables to column values and returns 1. If no rows are returned, returns 0. If more than one row is returned, throws an error.

    db_nextval
    db_nextval sequence-name
    	  

    Returns the next value for the sequence sequence-name (using a SQL statement like SELECT sequence-name.nextval FROM DUAL). If sequence pooling is enabled for the sequence, transparently uses a value from the pool if available to save a round-trip to the database (see Sequence Pooling).

    db_register_pooled_sequence
    db_register_pooled_sequence sequence-name pool-size
    	  

    Registers the sequence sequence-name to be pooled, with a pool size of pool-size sequence values (see Sequence Pooling).

    db_string
    db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ]
    	  

    Returns the first column of the result of SQL query sql. If sql doesn't return a row, returns default (or throws an error if default is unspecified). Analogous to database_to_tcl_string and database_to_tcl_string_or_null.

    db_list
    db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    	  

    Returns a Tcl list of the values in the first column of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. Analogous to database_to_tcl_list.

    db_list_of_lists
    db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    	  

    Returns a Tcl list, each element of which is a list of all column values in a row of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. (Analogous to database_to_tcl_list_list.)

    db_dml
    db_dml statement-name sql \
        [ -bind bind_set_id | -bind bind_value_list ] \
        [ -blobs blob_list | -clobs clob_list |
          -blob_files blob_file_list | -clob_files clob_file_list ]
    	  

    Performs the DML or DDL statement sql.

    If a length-n list of blobs or clobs is provided, then the SQL should return n blobs or clobs into the bind variables :1, :2, ... :n. blobs or clobs, if specified, should be a list of individual BLOBs or CLOBs to insert; blob_files or clob_files, if specified, should be a list of paths to files containing the data to insert. Only one of -blobs, -clobs, -blob_files, and -clob_files may be provided.

    Example:

    
    db_dml insert_photos "
            insert photos(photo_id, image, thumbnail_image)
            values(photo_id_seq.nextval, empty_blob(), empty_blob())
            returning image, thumbnail_image into :1, :2
        "  -blob_files [list "/var/tmp/the_photo" "/var/tmp/the_thumbnail"] 
    
    	  

    This inserts a new row into the photos table, with the contents of the files /var/tmp/the_photo and /var/tmp/the_thumbnail in the image and thumbnail columns, respectively.

    db_write_clob, db_write_blob, db_blob_get_file
    db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    
    db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    
    db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    	  

    Analagous to ns_ora write_clob/write_blob/blob_get_file.

    db_release_unused_handles
    	    db_release_unused_handles
    	  

    Releases any allocated, unused database handles.

    db_transaction
    db_transaction code_block [ on_error { code_block } ]
    	  

    Executes code_block transactionally. Nested transactions are supported (end transaction is transparently ns_db dml'ed when the outermost transaction completes). The db_abort_transaction command can be used to abort all levels of transactions. It is possible to specify an optional on_error code block that will be executed if some code in code_block throws an exception. The variable errmsg will be bound in that scope. If there is no on_error code, any errors will be propagated.

    Example:

    
    proc replace_the_foo { col } {
        db_transaction {
            db_dml "delete from foo"
            db_dml "insert into foo(col) values($col)"
        }
    }
    
    proc print_the_foo {} {
        doc_body_append "foo is [db_string "select col from foo"]<br>\n"
    }
    
    replace_the_foo 8
    print_the_foo ; # Writes out "foo is 8"
    
    db_transaction {
        replace_the_foo 14
        print_the_foo ; # Writes out "foo is 14"
        db_dml "insert into some_other_table(col) values(999)"
        ...
        db_abort_transaction
    } on_error {
        doc_body_append "Error in transaction: $errmsg"
    }
        
    
    print_the_foo ; # Writes out "foo is 8"
    
    	  
    db_resultrows
    db_resultrows
    	  

    Returns the number of rows affected or returned by the previous statement.

    db_with_handle
    db_with_handle var code_block
    	  

    Places a database handle into the variable var and executes code_block. This is useful when you don't want to have to use the new API (db_foreach, db_1row, etc.), but need to use database handles explicitly.

    Example:

    
    proc lookup_the_foo { foo } {
        db_with_handle db {
            return [db_string unused "select ..."]
        }
    }
    
    db_with_handle db {
        # Now there's a database handle in $db.
        set selection [ns_db select $db "select foo from bar"]
        while { [ns_db getrow $db $selection] } {
            set_variables_after_query
    
            lookup_the_foo $foo
        }
    }
    
    	  
    db_nullify_empty_string
    db_nullify_empty_string string
    	  

    For true SQL purists, we provide the convenience function db_nullify_empty_string, which returns [db_null] if its string argument is the empty string and can be used to encapsulate another Oracle quirk:

    
    set baz ""
    
    # Clean out the foo table
    #
    db_dml unused "delete from foo"
    
    db_dml unused "insert into foo(baz) values('$baz')"
    
    set n_rows [db_string unused "select count(*) from foo where baz is null"]
    #
    # $n_rows is 1; in effect, the "baz is null" criterion is matching
    # the empty string we just inserted (because of Oracle's coercion
    # quirk)
    
    	  

    To balance out this asymmetry, you can explicitly set baz to null by writing:

    
    db_dml foo_insert "insert into foo(baz) values(:1)" {[db_nullify_empty_string $baz]}
    
    	  

    ($Id: db-api.html,v 1.48 2010/12/11 23:36:32 ryang Exp $)

    Caching Database API Results

    The database API allows for direct caching of query results. Repeated calls will return the cached value until it is either explicitly flushed using db_flush_cache, times out (configured the ns_cache is called to create the cache), or another cached query fills the cache, causing older entries to be flushed.

    Values returned by a query are cached if you pass the "-cache_key" switch to the database procedure. The switch value will be used as the key in the ns_cache eval call used to execute the query and processing code. The db_flush proc should be called to flush the cache when appropriate. The "-cache_pool" parameter can be used to specify the cache pool to be used, and defaults to db_cache_pool. The size of the default cache is governed by the kernel parameter "DBCacheSize" in the "caching" section.

    Currently db_string, db_list, db_list_of_lists, db_1row, db_0or1row, and db_multirow support caching.

    For caching to be effective, one must carefully design a cache_pool and cache_key strategy that uniquely identifies a query within the system, including the relevant objects being referenced by the query. Typically a cache_key should include one or more object_ids and a name that identifies the operation being done.

    Here is an example from the layout-manager package:

    
    # Query to return the elements of a page as a list. The prefix "page_" is used to denote
    # that this is a page-related query, page_id is used to uniquely identify the query
    # by object, and the suffix uniquely defines the operation being performed on the
    # page object.
    
    db_list -cache_key page_${page_id}_get_elements get_elements {}
    
    # When the contents of a page are changed, we flush all page-related queries for the given
    # page object using db_flush_cache.
    
    db_flush_cache -cache_key_pattern page_${page_id}_*
    
        
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-hierarchical.html0000644000175000017500000001460611501005400025155 0ustar frankiefrankie Hierarchical data

    Hierarchical data

    by Jade Rubick with help from many people in the OpenACS community

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    One of the nice things about using the OpenACS object system is that it has a built-in facility for tracking hierarchical data in an efficient way. The algorithm behind this is called tree_sortkey.

    Any time your tables are subclasses of the acs_objects table, then you automatically get the ability to structure them hierarchically. The way you do this is currently via the context_id column of acs_objects (Note that there is talk of adding in a parent_id column instead, because the use of context_id has been ambiguous in the past). So when you want to build your hierarchy, simply set the context_id values. Then, when you want to make hierarchical queries, you can do them as follows:

          db_multirow categories blog_categories "
          SELECT
          c.*,
          o.context_id,
          tree_level(o.tree_sortkey)
          FROM
          blog_categories c,
          acs_objects o
          WHERE
          c.category_id = o.object_id
          ORDER BY
          o.tree_sortkey"
        

    Note the use of the tree_level() function, which gives you the level, starting from 1, 2, 3...

    Here's an example, pulling all of the children for a given parent:

          SELECT 
          children.*,
          tree_level(children.tree_sortkey) -
            tree_level(parent.tree_sortkey) as level
          FROM 
          some_table parent, 
          some_table children
          WHERE 
          children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey)
          and parent.tree_sortkey <> children.tree_sortkey
          and parent.key = :the_parent_key;
          

    The reason we substract the parent's tree_level from the child's tree_level is that the tree_levels are global, so if you want the parent's tree_level to start with 0, you'll want the subtraction in there. This is a reason you'll commonly see magic numbers in tree_sortkey SQL queries, like tree_level(children.tree_sortkey) - 4. That is basically an incorrect way to do it, and subtracting the parent's tree_level is the preferred method.

    This example does not include the parent. To return the entire subtree including the parent, leave out the non-equals clause:

          SELECT
          subtree.*,
          tree_level(subtree.tree_sortkey) -
            tree_level(parent.tree_sortkey) as level
          FROM some_table parent, some_table subtree
          WHERE 
          subtree.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey)
          and parent.key = :the_parent_key;
        

    If you are using the Content Repository, you get a similar facility, but the parent_id column is already there. Note you can do joins with tree_sortkey:

          SELECT
          p.item_id,
          repeat(:indent_pattern, (tree_level(p.tree_sortkey) - 5)* :indent_factor) as indent,
          p.parent_id as folder_id,
          p.project_name
          FROM pm_projectsx p, cr_items i
          WHERE p.project_id = i.live_revision
          ORDER BY i.tree_sortkey
        

    This rather long thread explains How tree_sortkeys work and this paper describes the technique for tree_sortkeys, although the OpenACS implementation has a few differences in the implementation, to make it work for many languages and the LIKE construct in Postgres.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-ssl.html0000644000175000017500000001603411501005400023140 0ustar frankiefrankie Installing SSL Support for an OpenACS service

    Installing SSL Support for an OpenACS service

    Debian Users: apt-get install openssl before proceeding.

    1. Make sure nsopenssl.so is installed for AOLserver.

    2. Uncomment this line from config.tcl.

      #ns_param   nsopenssl       ${bindir}/nsopenssl.so
      
    3. Prepare a certificate directory for the service.

      [$OPENACS_SERVICE_NAME etc]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs
      [$OPENACS_SERVICE_NAME etc]$ chmod 700 /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs
      [$OPENACS_SERVICE_NAME etc]$ 
      mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs
      chmod 700 /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs
    4. It takes two files to support an SSL connection. The certificate is the public half of the key pair - the server sends the certificate to browser requesting ssl. The key is the private half of the key pair. In addition, the certificate must be signed by Certificate Authority or browsers will protest. Each web browser ships with a built-in list of acceptable Certificate Authorities (CAs) and their keys. Only a site certificate signed by a known and approved CA will work smoothly. Any other certificate will cause browsers to produce some messages or block the site. Unfortunately, getting a site certificate signed by a CA costs money. In this section, we'll generate an unsigned certificate which will work in most browsers, albeit with pop-up messages.

      Use an OpenSSL perl script to generate a certificate and key.

      Debian users: use /usr/lib/ssl/misc/CA.pl instead of /usr/share/ssl/CA

      Mac OS X users: use perl /System/Library/OpenSSL/misc/CA.pl -newcert instead of /usr/share/ssl/CA

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/certs
      [$OPENACS_SERVICE_NAME certs]$ perl /usr/share/ssl/misc/CA -newcert
      Using configuration from /usr/share/ssl/openssl.cnf
      Generating a 1024 bit RSA private key
      ...++++++
      .......++++++
      writing new private key to 'newreq.pem'
      Enter PEM pass phrase:

      Enter a pass phrase for the CA certificate. Then, answer the rest of the questions. At the end you should see this:

      Certificate (and private key) is in newreq.pem
      [$OPENACS_SERVICE_NAME certs]$

      newreq.pem contains our certificate and private key. The key is protected by a passphrase, which means that we'll have to enter the pass phrase each time the server starts. This is impractical and unnecessary, so we create an unprotected version of the key. Security implication: if anyone gets access to the file keyfile.pem, they effectively own the key as much as you do. Mitigation: don't use this key/cert combo for anything besides providing ssl for the web site.

      [root misc]# openssl rsa -in newreq.pem -out keyfile.pem
      read RSA key
      Enter PEM pass phrase:
      writing RSA key
      [$OPENACS_SERVICE_NAME certs]$ 

      To create the certificate file, we take the combined file, copy it, and strip out the key.

      [$OPENACS_SERVICE_NAME certs]$ cp newreq.pem certfile.pem
      [root misc]# emacs certfile.pem

      Strip out the section that looks like

      -----BEGIN RSA PRIVATE KEY-----
      Proc-Type: 4,ENCRYPTED
      DEK-Info: DES-EDE3-CBC,F3EDE7CA1B404997
      S/Sd2MYA0JVmQuIt5bYowXR1KYKDka1d3DUgtoVTiFepIRUrMkZlCli08mWVjE6T
      (11 lines omitted)
      1MU24SHLgdTfDJprEdxZOnxajnbxL420xNVc5RRXlJA8Xxhx/HBKTw==
      -----END RSA PRIVATE KEY-----
    5. If you start up using the etc/daemontools/run script, you will need to edit this script to make sure the ports are bound for SSL. Details of this are in the run script.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/release-notes.html0000644000175000017500000007731511501005400023452 0ustar frankiefrankie OpenACS Release Notes

    OpenACS Release Notes

    The ChangeLogs include an annotated list of changes (Changelog (most recent release only)) since the last release and in the entire 5.6 release sequence Changelog for oacs-5-6.

    Release 5.6.0

    • Added new package dependency type, "embeds". This is a variant of the "extends" package dependency type added in OpenACS 5.5.0. It allows one to write embeddable packages, with scripts made visible in client packages using URLs which include the embedded package's package key. An example embeddable package might be a rewritten "attachments" package. The current implementation requires a global instance be mounted, and client packages generate urls to that global instance. Among other things, this leads to the user navigating to the top-level subsite, losing any subsite theming that might be associated with a community. Using "embeds", a rewritten package would run in the client package's context, maintaining theming and automatically associating attachments with the client package.

      Added global package parameters - parameters can now have scope "local" or "global", with "local" being the default..

      Fixes for ns_proxy handling

      Significant speedup for large sites

      Optional support for selenium remote control (acs-automated-tests)

      New administration UI to manage mime types and extension map

      Added acs-mail-lite package params for rollout support

      Support for 3-chars language codes in acs-lang

      Added OOXML mime types in acs-content-repository

    Release 5.5.0

    • PostgreSQL 8.3 is now fully supported, including the use of the built-in standard version of tsearch2.

      TinyMCE has been upgraded to 3.2.4.1 with language pack support.

      acs-mail-lite now correctly implements rollout support.

      Added new package dependency type, "extends". Implements a weak form of package inheritance (parameters and, optionally, templates). Multiple inheritance is supported. For instance, the non-core "layout-managed-subsite" extends the "acs-subsite" and "layout-manager" packages, resulting in a package that combines the semantics of both.

      Added new package attribute "implements-subsite-p" (default "f"). If true, this package may be mounted as a subsite and is expected to implement subsite semantics. Typically used by packages which extend acs-subsite.

      Added new package attribute "inherit-templates-p" (default "t"). If true, the package inherits templates defined in the packages it extends. This means that the package only needs to specify templates where the UI of an extended package is modified or extended. This greatly reduces the need to fork base packages when one needs to customize it. Rather than modify the package directly, use "extends" rather than "requires" then rewrite those templates you need to customize.

      Added a simple mechanism for defining subsite themes, removing the hard-wired choices implemented in earlier versions of OpenACS. The default theme has been moved into a new package, "openacs-default-theme". Simplifies the customization of the look and feel of OpenACS sites and subsites.

      The install xml facility has been enhanced to allow the calling of arbitrary Tcl procedures and includes various other enhancements written by Xarg. Packages can extend the facility, too. As an example of what can be done, the configuration of .LRN communities could be moved from a set of interacting parameters to a cleaner XML description of how to build classes and clubs, etc.

      Notifications now calls lang::util::localize on the message subject and body before sending the message out, using the recipient locale if set, the site-wide one if not. This will cause message keys (entered as #....# strings) to be replaced with the language text for the chosen locale.

    Release 5.4.2

    • This is a minor bugfix release.

      Site node caching was removed as doesn't work correctly

      Critical issues with search on oracle were fixed

      More html strict work etc

    Release 5.4.1

    • This is a minor bugfix release.

    Release 5.4.0

    • New Templating API added to add scripts, css, etc to the HTML HEAD and BODY sections of the generated HTML document. Please see /packages/acs-templating/tcl/head-procs.tcl or visit the template::head procs in the API browser for details.

      Templates have been modified to comply with HTML strict

      The Search package's results page has been improved

      TinyMCE WYSIWYG support has been added, RTE and HTMLArea support dropped

      acs-mail-lite's send has been cleaned up to properly encode content, to handle file attachments, etc. "complex-send" will disappear from acs-core in a future release.

    The ChangeLogs include an annotated list of changes (Changelog (most recent release only)) since the last release and in the entire 5.6 release sequence Changelog for oacs-5-6.

    Release 5.3.1

    • Bug fixes.

      New TIPs implemented.

      All Core Automated Tests for Postgres pass.

      New Site and Blank master templates and CSS compatible with the .LRN Zen work. Compatibility master templates are provided for existing sites.

    The ChangeLogs include an annotated list of changes (Changelog (most recent release only)) since the last release and in the entire 5.6 release sequence Changelog for oacs-5-6.

    Release 5.3.0

    • Bug fixes.

      New TIPs implemented.

      All Core Automated Tests for Postgres pass.

    Release 5.2.0

    • Bug fixes.

      New TIPs implemented.

      This release does not include new translations.

    Release 5.1.4

    • Bug fixes.

      The missing CR TCL API has been filled in, thanks to Rocael and his team and Dave Bauer.

      This release does not include new translations.

    Release 5.1.3

    • Bug fixes, primarily for .LRN compatibility in support of upcoming .LRN 2.1.0 releases. This release does not include new translations since 5.1.2.

    Release 5.1.2

    • Translations syncronized with the translation server. Basque and Catalan added.

    • For a complete change list, see the Change list since 5.1.0 in Changelog for oacs-5-6.

    Release 5.1.1

    • This is the first release using the newest adjustment to the versioning convention. The OpenACS 5.1.1 tag will apply to OpenACS core as well as to the most recent released version of every package, including .LRN.

    • Translations syncronized with the translation server.

    • Bug 1519 fixed. This involved renaming all catalog files for ch_ZH, TH_TH, AR_EG, AR_LB, ms_my, RO_RO, FA_IR, and HR_HR. If you work with any of those locales, you should do a full catalog export and then import (via /acs-lang/admin) after upgrading acs-lang. (And, of course, make a backup of both the files and database before upgrading.)

    • Other bug fixes since 5.1.0: 1785, 1793, and over a dozen additional bug fixes.

    • For a complete change list, see the Change list since 5.0.0 in Changelog for oacs-5-6.

    Release 5.1.0

    • Lots of little tweaks and fixes

    • Complete Change list since 5.0.0 in Changelog

    • Many Bug fixes

    Release 5.0.4

    • New translations, including for .LRN 2.0.2.

    Release 5.0.1

    • All work on the translation server from 7 Nov 2003 to 7 Feb 2004 is now included in catalogs.

    • One new function in acs-tcl, util::age_pretty

    • Complete Change list since 5.0.0 in Changelog

    • Many documentation updates and doc bug fixes

    Release 5.0.0

    This is OpenACS 5.0.0. This version contains no known security, data loss, or crashing bugs, nor any bugs judged release blockers. This version has received manual testing. It has passed current automated testing, which is not comprehensive. This release contains work done on the translation server http://translate.openacs.org through 7 Nov 2003.

    Please report bugs using our Bug Tracker at the OpenACS website.

    You may want to begin by reading our installation documentation for a Unix-like system. Note that the Windows documentation is not current for OpenACS 5.6.0, but an alternative is to use John Sequeira's Oasis VM project.

    After installation, the full documentation set can be found by visiting http://yourserver/doc.

    New features in this release:

    • Internationalization support. A message catalog to store translated text, localization of dates, number formatting, timezone conversion, etc. Allows you to serve your users in their language.

    • External authenticaiton. Integrate with outside user databases through e.g. LDAP, RADIUS, Kerberos, MS Active Directory. Imports user information through IMS Enterprise 1.1 format. Easily extended to support other authentication, password management, account creation, and account import mechanisms. This includes improvements to the basic cookie handling, so logins can be expired without the user's identity being completely lost. You can set login to expire after a certain period (e.g. 8 hours, then password must be refreshed), or you can have all issues login cookies expired at once, e.g. if you have left a permanent login cookie on a public machine somewhere.

    • User interface enhancements. All pages, including site-wide and subsite admin pages, will be templated, so they can be styled using master template and site-wide stylesheets. We have a new default-master template, which includes links to administration, your workspace, and login/logout, and is rendered using CSS. And there's a new community template (/packages/acs-subsite/www/group-master), which provides useful navigation to the applications and administrative UI in a subsite. In addition, there's new, simpler UI for managing members of a subsite, instantiating and mounting applications, setting permissions, parameters, etc. Site-wide admin as also seen the addition of a new simpler software install UI to replace the APM for non-developer users, and improved access to parameters, internationalization, automated testing, service contracts, etc. The list builder has been added for easily generating templated tables and lists, with features such as filtering, sorting, actions on multiple rows with checkboxes, etc. Most of all, it's fast to use, and results in consistently-looking, consistently-behaving, templated tables.

    • Automated testing. The automated testing framework has been improved significantly, and there are automated tests for a number of packages.

    • Security enhancements. HTML quoting now happens in the templating system, greatly minimizing the chance that users can sneak malicious HTML into the pages of other users.

    • Oracle 9i support.

    • Who's online feature.

    • Spell checking.

    Potential incompatibilities:

    • With the release of OpenACS 5, PostgreSQL 7.2 is no longer supported. Upgrades are supported from OpenACS 4.6.3 under Oracle or PostgreSQL 7.3.

    • The undocumented special handling of ~ and +variable+ in formtemplates, found in packages/acs-templating/resources/*, has been removed in favor of using <noparse> and \@variable\@ (the standard templating mechanisms). Locally provided formtemplate styles still using these mechanisms will break.

    • Serving backup files and files from the CVS directories is turned off by default via the acs-kernel parameter ExcludedFiles in section request-processor (The variable provides a string match glob list of files and is defaulted to "*/CVS/* *~")

    ($Id: release-notes.html,v 1.53 2010/12/11 23:36:32 ryang Exp $)

    Changelog (most recent release only)

    ChangeLog missing
    -->

    Changelog for oacs-5-6

    2009-09-05 21:44  donb
    
    	* packages/acs-content-repository/tcl/apm-callback-procs.tcl: The
    	  after upgrade callback needed a documentation block.
    
    2009-09-05 16:27  donb
    
    	* packages/: acs-admin/acs-admin.info,
    	  acs-api-browser/acs-api-browser.info,
    	  acs-authentication/acs-authentication.info,
    	  acs-automated-testing/acs-automated-testing.info,
    	  acs-bootstrap-installer/acs-bootstrap-installer.info,
    	  acs-content-repository/acs-content-repository.info,
    	  acs-core-docs/acs-core-docs.info, acs-kernel/acs-kernel.info,
    	  acs-lang/acs-lang.info, acs-mail-lite/acs-mail-lite.info,
    	  acs-messaging/acs-messaging.info,
    	  acs-reference/acs-reference.info,
    	  acs-service-contract/acs-service-contract.info,
    	  acs-subsite/acs-subsite.info, acs-tcl/acs-tcl.info,
    	  acs-templating/acs-templating.info,
    	  acs-translations/acs-translations.info,
    	  intermedia-driver/intermedia-driver.info,
    	  notifications/notifications.info,
    	  openacs-default-theme/openacs-default-theme.info,
    	  ref-timezones/ref-timezones.info, search/search.info,
    	  tsearch2-driver/tsearch2-driver.info: Bumped version number to
    	  5.5.1b1 in preparation for release.
    
    2009-09-02 17:32  daveb
    
    	* packages/acs-tcl/tcl/request-processor-procs.tcl: Fix redirect
    	  when ForceHostP is true. Fix redirect to/from HTTP/HTTPS where
    	  full URLs are used.
    
    2009-08-10 23:40  donb
    
    	* packages/acs-subsite/tcl/: package-procs-oracle.xql,
    	  package-procs-postgresql.xql, package-procs.tcl:
    	  package_exec_plsql didn't work if the sql proc being called has a
    	  parameter named "package_name"...
    
    2009-08-10 18:35  michaels
    
    	* packages/acs-templating/tcl/richtext-procs.tcl: remove html
    	  security check bypass for admins in the richtext validation per
    	  OCT discussion
    
    2009-07-29 22:21  donb
    
    	* packages/search/: search.info, tcl/apm-callback-procs.tcl,
    	  tcl/search-init.tcl: Added a package instantiate callback so when
    	  someone mounts "search", the search indexer is correctly started
    	  up without a server restart being required.
    
    2009-07-24 14:12  victorg
    
    	* packages/acs-templating/: acs-templating.info,
    	  tcl/apm-callback-procs.tcl: Providing upgrade logic for removing
    	  Xinha invalid plugins from the parameter XinhaDefaultPlugins.
    
    2009-07-22 20:47  emmar
    
    	* packages/acs-subsite/acs-subsite.info: Fix dependencies and their
    	  version
    
    2009-07-21 22:14  emmar
    
    	* packages/acs-templating/tcl/date-procs.tcl: Localized default
    	  format for date widget
    
    2009-07-20 21:29  emmar
    
    	* packages/acs-templating/tcl/richtext-procs.tcl: Close LABEL tag
    	  before adding the Format and Spellcheck widgets. This HTML should
    	  be build in the template rather than in the rendering proc. Each
    	  widget should be computed separately.
    
    2009-07-20 12:24  emmar
    
    	* packages/acs-content-repository/: acs-content-repository.info,
    	  sql/common/mime-type-data.sql, tcl/apm-callback-procs.tcl:
    	  Implements TIP #135 (OOXML formats)
    
    2009-07-20 09:32  emmar
    
    	* packages/acs-core-docs/www/individual-programs.html: Fix Tcl
    	  version
    
    2009-07-20 08:42  emmar
    
    	* packages/acs-core-docs/www/xml/install-guide/software.xml: Fix
    	  Tcl version
    
    2009-07-17 11:48  emmar
    
    	* packages/: acs-admin/acs-admin.info,
    	  acs-api-browser/acs-api-browser.info,
    	  acs-authentication/acs-authentication.info,
    	  acs-automated-testing/acs-automated-testing.info,
    	  acs-bootstrap-installer/acs-bootstrap-installer.info,
    	  acs-content-repository/acs-content-repository.info,
    	  acs-core-docs/acs-core-docs.info, acs-kernel/acs-kernel.info,
    	  acs-lang/acs-lang.info, acs-mail-lite/acs-mail-lite.info,
    	  acs-messaging/acs-messaging.info,
    	  acs-reference/acs-reference.info,
    	  acs-service-contract/acs-service-contract.info,
    	  acs-subsite/acs-subsite.info, acs-tcl/acs-tcl.info,
    	  acs-templating/acs-templating.info,
    	  acs-translations/acs-translations.info,
    	  intermedia-driver/intermedia-driver.info,
    	  notifications/notifications.info,
    	  openacs-default-theme/openacs-default-theme.info,
    	  ref-timezones/ref-timezones.info, search/search.info,
    	  tsearch2-driver/tsearch2-driver.info: Bumped version to 5.5.1d1
    
    2009-07-14 11:44  emmar
    
    	* packages/notifications/:
    	  catalog/notifications.en_US.ISO-8859-1.xml,
    	  catalog/notifications.es_ES.ISO-8859-1.xml,
    	  tcl/notification-procs.tcl, www/manage.adp, www/manage.tcl,
    	  www/request-change-frequency.adp,
    	  www/request-change-frequency.tcl, www/request-new.adp,
    	  www/request-new.tcl: Localization (level AA requirement)
    
    2009-07-14 09:47  emmar
    
    	* packages/acs-subsite/: catalog/acs-subsite.en_US.ISO-8859-1.xml,
    	  catalog/acs-subsite.es_ES.ISO-8859-1.xml,
    	  www/shared/whos-online.adp, www/shared/whos-online.tcl:
    	  Localization
    
    2009-07-06 11:17  emmar
    
    	* packages/acs-core-docs/www/: database-management.html,
    	  docbook-primer.html, install-next-nightly-vacuum.html,
    	  install-openacs-delete-tablespace.html,
    	  programming-with-aolserver.html, remote-postgres.html,
    	  unix-installation.html: Regenerate HTML files after updating
    	  variables values and the compatibility table
    
    2009-07-06 11:14  emmar
    
    	* packages/acs-core-docs/www/: acs-admin.html,
    	  acs-package-dev.html, acs-plat-dev.html, aolserver.html,
    	  aolserver4.html, apm-design.html, apm-requirements.html,
    	  automated-backup.html, automated-testing-best-practices.html,
    	  backup-recovery.html, backups-with-cvs.html,
    	  complete-install.html, configuring-configuring-packages.html,
    	  configuring-configuring-permissions.html,
    	  configuring-install-packages.html,
    	  configuring-mounting-packages.html, credits.html,
    	  cvs-guidelines.html, cvs-tips.html, db-api-detailed.html,
    	  db-api.html, dev-guide.html, doc-standards.html,
    	  eng-standards-constraint-naming.html,
    	  eng-standards-filenaming.html, eng-standards-plsql.html,
    	  eng-standards-versioning.html, ext-auth-requirements.html,
    	  filename.html, form-builder.html, groups-design.html,
    	  high-avail.html, how-do-I.html, i18n-convert.html, index.html,
    	  individual-programs.html, install-cvs.html,
    	  install-daemontools.html, install-full-text-search-openfts.html,
    	  install-full-text-search-tsearch2.html,
    	  install-next-add-server.html, install-next-backups.html,
    	  install-openacs-keepalive.html, install-qmail.html,
    	  install-redhat.html, install-steps.html, ix01.html,
    	  kernel-doc.html, mac-installation.html, maint-performance.html,
    	  maintenance-deploy.html, object-identity.html,
    	  object-system-design.html, object-system-requirements.html,
    	  objects.html, openacs-unpack.html, openacs.html, oracle.html,
    	  packages.html, parties.html,
    	  permissions-tediously-explained.html, permissions.html,
    	  postgres.html, psgml-for-emacs.html, psgml-mode.html,
    	  release-notes.html, releasing-openacs-core.html,
    	  request-processor.html, requirements-template.html,
    	  rp-design.html, security-notes.html, snapshot-backup.html,
    	  style-guide.html, subsites.html, templates.html,
    	  tutorial-database.html, tutorial-debug.html,
    	  tutorial-newpackage.html, tutorial-pages.html, tutorial.html,
    	  upgrade-4.5-to-4.6.html, upgrade-openacs-files.html,
    	  upgrade-overview.html, variables.html: Updated with correct
    	  variable values and last changes in the compatibility table
    
    2009-07-06 11:02  emmar
    
    	* packages/acs-core-docs/www/xml/: variables.ent,
    	  install-guide/compatibility.xml, install-guide/software.xml:
    	  Updated the compatibility table.  Set the variables according to
    	  the last final release.  Removed unused (and duplicated) file.
    
    
    
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/os-security.html0000644000175000017500000000753611501005400023170 0ustar frankiefrankie Security Information

    Security Information

    Once you get your OS installed, it's imperative that you secure your installation. As Jon Griffin repeatedly warns us, "No distribution is secure out of the box." The Reference Platform implements some basic precautions, but security is a process, not a condition. If you are responsible for a computer hooked to the internet, you are responsible for learning some rudiments of security, such as monitoring the state of a computer, maintaining patch levels, and keeping backups. We recommend these resources:

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/upgrade-4.5-to-4.6.html0000644000175000017500000001462111501005400023553 0ustar frankiefrankie Upgrading 4.5 or higher to 4.6.3

    Upgrading 4.5 or higher to 4.6.3

    The required platform for OpenACS 4.6 is the same as 4.5, with the exception of OpenFTS. OpenACS 4.6 and later require OpenFTS 0.3.2 for full text search on PostGreSQL. If you have OpenFTS 0.2, you'll need to upgrade.

    If upgrading from 4.4, you need to manually run acs-kernel/sql/postgres/upgrade-4.4-4.5.sql. See Bug #632

    1. Make a Backup. Back up the database and file system (see ???).

    2. OPTIONAL: Upgrade OpenFTS. Upgrading OpenFTS from 0.2 to 0.3.2

    3. Stop the server

      [root root]# svc -d /service/$OPENACS_SERVICE_NAME
    4. Upgrade the file system. Upgrading the OpenACS files

    5. Start the server

      [root root]# svc -u /service/$OPENACS_SERVICE_NAME
    6. Use APM to upgrade the database. 

      1. Browse to the package manager, http://yourserver/acs-admin/apm.

      2. Click Install packages.

      3. Select the packages you want to install. This should be everything that says upgrade, plus any new packages you want. It's safest to upgrade the kernel by itself, and then come back and upgrade the rest of the desired packages in a second pass.

      4. On the next screen, click Install Packages

      5. When prompted, restart the server:

        [root root]# restart-aolserver $OPENACS_SERVICE_NAME
      6. Wait a minute, then browse to the package manager, http://yourserver/acs-admin/apm.

      7. Check that the kernel upgrade worked by clicking All and making sure that acs-kernel version is 5.6.0.

    7. Rollback. If anything goes wrong, roll back to the backup snapshot.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/postgres.html0000644000175000017500000010275711501005400022551 0ustar frankiefrankie Install PostgreSQL

    Install PostgreSQL

    by Vinod Kurup

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Skip this section if you will run only Oracle.

    OpenACS 5.6.0 will run with PostgreSQL 7.3.2, 7.3.3, and 7.3.4 and 7.4.x. 7.4.7 is the recommended version of PostgreSQL.

    • Special notes for Mac OS X. If you are running Mac OS X prior to 10.3, you should be able to install and use PostGreSQL 7.3.x. Mac OS X 10.3 requires PostGreSQL 7.4.

    • Special Notes for Debian. 

      Debian stable user should install PostGreSQL from source as detailed below, or they should use the www.backports.org backport for Postgres to get a more current version. Debian unstable users: the following process has been known to work (but you should double-check that the version of PostGreSQL is 7.3 or above):

      For Debian stable users, you can use backports, by adding this line to the /etc/apt/sources.list

              deb http://www.backports.org/debian stable bison postgresql openssl openssh tcl8.4 courier debconf spamassassin tla diff patch neon chkrootkit
              
            
      apt-get install postgresql postgresql-dev postgresql-doc
      ln -s /usr/include/postgresql/ /usr/include/pgsql
      ln -s /var/lib/postgres /usr/local/pgsql
      ln -s /usr/include/pgsql /usr/local/pgsql/include
      su postgres -c "/usr/lib/postgresql/bin/createlang plpgsql template1"

      and proceed to Tune postgres. (OPTIONAL) or to the next section.

    • Special Notes for Red Hat. Red Hat users: If you install PostgreSQL 7.3.2 from the Red Hat 9 RPM, you can skip a few steps. These shell commands add some links for compatibility with the directories from a source-based install; start the service; create a new group for web service users, and modify the postgres user's environment (more information):

      [root root]# ln -s /usr/lib/pgsql/ /var/lib/pgsql/lib
      [root root]# ln -s /var/lib/pgsql /usr/local/pgsql
      [root root]# ln -s /etc/init.d/postgresql /etc/init.d/postgres
      [root root]# ln -s /usr/bin /usr/local/pgsql/bin
      [root root]# service postgresql start
      Initializing database:
                                                                 [  OK  ]
      Starting postgresql service:                               [  OK  ]
      [root root]# echo "export LD_LIBRARY_PATH=/usr/local/pgsql/lib" >> ~postgres/.bash_profile
      [root root]# echo "export PATH=$PATH:/usr/local/pgsql/bin" >> ~postgres/.bash_profile
      [root root]# groupadd web
      [root root]# su - postgres
      -bash-2.05b$
      
      ln -s /usr/lib/pgsql/ /var/lib/pgsql/lib
      ln -s /var/lib/pgsql /usr/local/pgsql
      ln -s /usr/bin /usr/local/pgsql/bin
      service postgresql start
      echo "export LD_LIBRARY_PATH=/usr/local/pgsql/lib" >> ~postgres/.bash_profile
      echo "export PATH=$PATH:/usr/local/pgsql/bin" >> ~postgres/.bash_profile
      groupadd web
      su - postgres

      ... and then skip to . Something similar may work for other binary packages as well.

    • Safe approach: install from source

      1. Unpack PostgreSQL 7.4.7. If you have not downloaded the postgresql tarball to /var/tmp/postgresql-7.4.7.tar.gz, get it.

        [root root]# cd /usr/local/src
        [root src]# tar xzf /var/tmp/postgresql-7.4.7.tar.gz
        [root src]# 
        cd /usr/local/src
        tar xzf /var/tmp/postgresql-7.4.7.tar.gz
      2. ALTERNATIVE: Unpack PostgreSQL 7.4.7. If you have not downloaded the postgresql tarball to /var/tmp/postgresql-7.4.7.tar.bz2, get it.

        [root root]# cd /usr/local/src
        [root src]# tar xfj /var/tmp/postgresql-7.4.7.tar.bz2
        [root src]# 
        cd /usr/local/src
        tar xfj /var/tmp/postgresql-7.4.7.tar.bz2
      3. Install Bison. Only do this if bison --version is smaller than 1.875 and you install PostgreSQL 7.4 from cvs instead of tarball.

        [root root]# cd /usr/local/src
        [root src]# wget http://ftp.gnu.org/gnu/bison/bison-1.875.tar.gz
        [root src]# tar xfz bison-1.875.tar.gz
        [root src]# cd bison-1.875
        [root src]# ./configure
        [root src]# make install
              
      4. Create the Postgres user.  Create a user and group (if you haven't done so before) for PostgreSQL. This is the account that PostgreSQL will run as since it will not run as root. Since nobody will log in directly as that user, we'll leave the password blank.

        Debian users should probably use adduser instead of useradd. Type man adduser

        [root src]# groupadd web
        [root src]# useradd -g web -d /usr/local/pgsql postgres
        [root src]# mkdir -p /usr/local/pgsql
        [root src]# chown -R postgres.web /usr/local/pgsql /usr/local/src/postgresql-7.4.7
        [root src]# chmod 750 /usr/local/pgsql
        [root src]#
        groupadd web
        useradd -g web -d /usr/local/pgsql postgres
        mkdir -p /usr/local/pgsql
        chown -R postgres.web /usr/local/pgsql /usr/local/src/postgresql-7.4.7
        chmod 750 /usr/local/pgsql
        • Mac OS X: Do instead: First make sure the gids and uids below are available (change them if they are not).To list taken uids and gids:

          nireport / /groups name gid | grep "[0123456789][0123456789]"
          nireport / /users name uid | grep "[0123456789][0123456789]"
                    

          Now you can install the users

          sudo niutil -create / /groups/web
          sudo niutil -createprop / /groups/web gid 201
          sudo niutil -create / /users/postgres
          sudo niutil -createprop / /users/postgres gid 201
          sudo niutil -createprop / /users/postgres uid 502
          sudo niutil -createprop / /users/postgres home /usr/local/pgsql
          sudo niutil -create / /users/$OPENACS_SERVICE_NAME
          sudo niutil -createprop / /users/$OPENACS_SERVICE_NAME gid  201
          sudo niutil -createprop / /users/$OPENACS_SERVICE_NAME uid 201
          mkdir -p /usr/local/pgsql
          chown -R postgres:web /usr/local/pgsql /usr/local/src/postgresql-7.4.7
          chmod 750 /usr/local/pgsql
        • FreeBSD users:  need to add more parameters.

          [root src]# mkdir -p /usr/local/pgsql
          [root src]# pw groupadd -n web
          [root src]# pw useradd -n postgres -g web -d /usr/local/pgsql -s /bin/bash
          [root src]# chown -R postgres:web /usr/local/pgsql /usr/local/src/postgresql-7.4.7
          [root src]# chmod -R 750 /usr/local/pgsql
          [root src]#
          mkdir -p /usr/local/pgsql
          pw groupadd -n web
          pw useradd -n postgres -g web -d /usr/local/pgsql -s /bin/bash
          chown -R postgres:web /usr/local/pgsql /usr/local/src/postgresql-7.4.7
          chmod -R 750 /usr/local/pgsql
      5. Set up postgres's environment variables. They are necessary for the executable to find its supporting libraries. Put the following lines into the postgres user's environment.

        [root src]# su - postgres
        [postgres ~] emacs ~postgres/.bashrc

        Paste this line into .bash_profile:

        source $HOME/.bashrc

        Paste these lines into .bashrc:

        export PATH=/usr/local/bin/:$PATH:/usr/local/pgsql/bin
        export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib

        Test this by logging in as postgres and checking the paths; you should see /usr/local/pgsql/bin somewhere in the output (the total output is system-dependent so yours may vary)

        [root src]# su - postgres
        [postgres pgsql]$ env | grep PATH
        LD_LIBRARY_PATH=:/usr/local/pgsql/lib
        PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin/X11:/usr/X11R6/bin:/root/bin:/usr/local/pgsql/bin:/usr/local/pgsql/bin
        [postgres pgsql]$ exit
        

        Don't continue unless you see correct output from env | grep PATH

      6. Compile and install PostgreSQL.  Change to the postgres user and run ./configure to set the compilation options automatically. This is the point at which you can configure PostgreSQL in various ways. For example, if you are installing on "OS X" add the flags --with-includes=/sw/include/ --with-libraries=/sw/lib. If you want to see what the other possibilities are, run ./configure --help.

        On debian woody (stable, 3.0), do ./configure --without-readline --without-zlib.

        [root src]# su - postgres
        [postgres pgsql]$ cd /usr/local/src/postgresql-7.4.7
        [postgres postgresql-7.4.7]$ ./configure
        creating cache ./config.cache
        checking host system type... i686-pc-linux-gnu
        (many lines omitted>
        linking ./src/makefiles/Makefile.linux to src/Makefile.port
        linking ./src/backend/port/tas/dummy.s to src/backend/port/tas.s
        [postgres postgresql-7.4.7]$ make all
        make -C doc all
        make[1]: Entering directory `/usr/local/src/postgresql-7.4.7/doc'
        (many lines omitted)
        make[1]: Leaving directory `/usr/local/src/postgresql-7.4.7/src'
        All of PostgreSQL successfully made. Ready to install.
        [postgres postgresql-7.4.7]$ make install
        make -C doc install
        make[1]: Entering directory `/usr/local/src/postgresql-7.4.7/doc'
        (many lines omitted)
        Thank you for choosing PostgreSQL, the most advanced open source database
        engine.
        su - postgres
        cd /usr/local/src/postgresql-7.4.7
        ./configure 
        make all
        make install
      7. Start PostgreSQL.  The initdb command initializes the database. pg_ctl is used to start up PostgreSQL. If PostgreSQL is unable to allocate enough memory, see section 11 Tuning PostgreSQL (below).

        [postgres postgresql-7.4.7]$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
        The files belonging to this database system will be owned by user "postgres".
        This user must also own the server process.
        (17 lines omitted)
        or
            /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start
        [postgres postgresql-7.4.7]$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l /usr/local/pgsql/data/server.log start
        postmaster successfully started
        [postgres postgresql-7.4.7]$
        /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data
        /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l /usr/local/pgsql/data/server.log start

        PostgreSQL errors will be logged in /usr/local/pgsql/data/server.log

      8. Install Pl/pgSQL. Set up plpgsq and allow your user to have access. Plpgsql is a PL/SQL-like language. We add it to template1, which is the template from which all new databases are created. We can verify that it was created with the createlang command in list mode.

        [postgres postgresql-7.4.7]$ createlang plpgsql template1
        [postgres pgsql]$ createlang -l template1
        Procedural languages
          Name   | Trusted?
        ---------+----------
         plpgsql | t
        (1 row)
        
        [postgres pgsql-7.4.7]$
        createlang plpgsql template1
        createlang -l template1
      9. Test PostgreSQL (OPTIONAL). Create a database and try some simple commands. The output should be as shown.

        [postgres pgsql]$ createdb mytestdb
        CREATE DATABASE
        [postgres pgsql]$ psql mytestdb
        Welcome to psql, the PostgreSQL interactive terminal.
        
        Type:  \copyright for distribution terms
               \h for help with SQL commands
               \? for help on internal slash commands
               \g or terminate with semicolon to execute query
               \q to quit
        
        mytestdb=# select current_timestamp;
                  timestamptz
        -------------------------------
         2003-03-07 22:18:29.185413-08
        (1 row)
        
        mytestdb=# create function test1() returns integer as 'begin return 1; end;' language 'plpgsql';
        CREATE
        mytestdb=# select test1();
         test1
        -------
             1
        (1 row)
        
        mytestdb=# \q
        [postgres pgsql]$ dropdb mytestdb
        DROP DATABASE
        [postgres pgsql]$ exit
        logout
        
        [root src]#
      10. Set PostgreSQL to start on boot. First, we copy the postgresql.txt init script, which automates startup and shutdown, to the distribution-specific init.d directory. Then we verify that it works. Then we automate it by setting up a bunch of symlinks that ensure that, when the operating system changes runlevels, postgresql goes to the appropriate state. Red Hat and Debian and SuSE each work a little differently. If you haven't untarred the OpenACS tarball, you will need to do so now to access the postgresql.txt file.

        • Red Hat RPM:

          The init script is already installed; just turn it on for the appropriate run levels.

          [root root]# chkconfig --level 345 postgresql on
          [root root]# 
        • Red Hat from source:

          [root src]# cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql
          [root src]# chown root.root /etc/rc.d/init.d/postgresql
          [root src]# chmod 755 /etc/rc.d/init.d/postgresql
          [root src]# 
          cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql
          chown root.root /etc/rc.d/init.d/postgresql
          chmod 755 /etc/rc.d/init.d/postgresql

          Test the script.

          [root root]# service postgresql stop
          Stopping PostgreSQL: ok
          [root root]# 

          If PostgreSQL successfully stopped, then use the following command to make sure that the script is run appropriately at boot and shutdown. And turn it back on because we'll use it later.

          [root root]# chkconfig --add postgresql
          [root root]# chkconfig --level 345 postgresql on
          [root root]# chkconfig --list postgresql
          postgresql      0:off   1:off   2:on    3:on    4:on    5:on    6:off
          [root root]# service postgresql start
          Starting PostgreSQL: ok
          [root root]#
          chkconfig --add postgresql
          chkconfig --level 345 postgresql on
          chkconfig --list postgresql
          service postgresql start
        • Debian:

          [root ~]# cp /var/tmp/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql
          [root ~]# chown root.root /etc/init.d/postgresql
          [root ~]# chmod 755 /etc/init.d/postgresql
          [root ~]# 
          cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/postgresql.txt /etc/init.d/postgresql
          chown root.root /etc/init.d/postgresql
          chmod 755 /etc/init.d/postgresql

          Test the script

          [root ~]# /etc/init.d/postgresql stop
          Stopping PostgreSQL: ok
          [root ~]# 

          If PostgreSQL successfully stopped, then use the following command to make sure that the script is run appropriately at boot and shutdown.

          [root ~]# update-rc.d postgresql defaults
           Adding system startup for /etc/init.d/postgresql ...
             /etc/rc0.d/K20postgresql -> ../init.d/postgresql
             /etc/rc1.d/K20postgresql -> ../init.d/postgresql
             /etc/rc6.d/K20postgresql -> ../init.d/postgresql
             /etc/rc2.d/S20postgresql -> ../init.d/postgresql
             /etc/rc3.d/S20postgresql -> ../init.d/postgresql
             /etc/rc4.d/S20postgresql -> ../init.d/postgresql
             /etc/rc5.d/S20postgresql -> ../init.d/postgresql
          [root ~]# /etc/init.d/postgresql start
          Starting PostgreSQL: ok
          [root ~]#
        • FreeBSD:

          [root ~]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/postgresql.txt /usr/local/etc/rc.d/postgresql.sh
          [root ~]# chown root:wheel /usr/local/etc/rc.d/postgresql.sh
          [root ~]# chmod 755 /usr/local/etc/rc.d/postgresql.sh
          [root ~]# 
          cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/postgresql.txt /usr/local/etc/rc.d/postgresql.sh
          chown root:wheel /usr/local/etc/rc.d/postgresql.sh
          chmod 755 /usr/local/etc/rc.d/postgresql.sh

          Test the script

          [root ~]# /usr/local/etc/rc.d/postgresql.sh stop
          Stopping PostgreSQL: ok
          [root ~]# 

          If PostgreSQL successfully stopped, then turn it back on because we'll use it later.

          [root root]# /usr/local/etc/rc.d/postgresql.sh start
          Starting PostgreSQL: ok
          [root root]#
          /usr/local/etc/rc.d/postgresql.sh start
        • SuSE:

          Note

          I have received reports that SuSE 8.0 is different from previous versions. Instead of installing the boot scripts in /etc/rc.d/init.d/, they should be placed in /etc/init.d/. If you're using SuSE 8.0, delete the rc.d/ part in each of the following commands.

          [root ~]# cp /var/tmp/openacs-5.6.0/packages/acs-core-docs/www/files/postgresql.txt /etc/rc.d/init.d/postgresql
          [root ~]# chown root.root /etc/rc.d/init.d/postgresql
          [root ~]# chmod 755 /etc/rc.d/init.d/postgresql

          Test the script.

          [root ~]# /etc/rc.d/init.d/postgresql stop
          Stopping PostgreSQL: ok

          If PostgreSQL successfully stopped, then use the following command to make sure that the script is run appropriately at boot and shutdown.

          [root ~]# cd /etc/rc.d/init.d
          root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/postgresql K20postgresql
          root:/etc/rc.d/init.d# ln -s /etc/rc.d/init.d/postgresql S20postgresql  
          root:/etc/rc.d/init.d# cp K20postgresql rc2.d
          root:/etc/rc.d/init.d# cp S20postgresql rc2.d
          root:/etc/rc.d/init.d# cp K20postgresql rc3.d
          root:/etc/rc.d/init.d# cp S20postgresql rc3.d
          root:/etc/rc.d/init.d# cp K20postgresql rc4.d
          root:/etc/rc.d/init.d# cp S20postgresql rc4.d 
          root:/etc/rc.d/init.d# cp K20postgresql rc5.d
          root:/etc/rc.d/init.d# cp S20postgresql rc5.d
          root:/etc/rc.d/init.d# rm K20postgresql
          root:/etc/rc.d/init.d# rm S20postgresql
          root:/etc/rc.d/init.d# 

          Test configuration.

          root:/etc/rc.d/init.d # cd
          root:~ # /etc/rc.d/init.d/rc2.d/S20postgresql start
          Starting PostgreSQL: ok
          root:~ # 
        • Mac OS X 10.3:

          1. Install the startup script:

            cd /System/Library/StartupItems/
            tar xfz /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/osx-postgres-startup-item.tgz
            
        • Mac OS X 10.4 can use Launchd:

          1. Install the startup script:

            cd /Library/LaunchDaemons
            cp
            /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/osx-postgres-launchd-item.txt
            org.postgresql.PostgreSQL.plist
            

            If postgres does not start automatically on reboot, see what error you get when manually starting it with:

            $ sudo launchctl load /Library/LaunchDaemons/org.postgresql.PostgreSQL.plist
            $ sudo launchctl start org.postgresql.PostgreSQL

        From now on, PostgreSQL should start automatically each time you boot up and it should shutdown gracefully each time you shut down. (Note: Debian defaults to starting all services on runlevels 2-5. Red Hat defaults to starting services on 3-5. So, on Red Hat, PostgreSQL won't start on runlevel 2 unless you alter the above commands a little. This usually isn't a problem as Red Hat defaults to runlevel 3)

      11. Tune postgres. (OPTIONAL). The default values for PostgreSQL are very conservative; we can safely change some of them and improve performance.

        1. Change the kernel parameter for maximum shared memory segment size to 128Mb:

          [root root]# echo 134217728 >/proc/sys/kernel/shmmax
          [root root]#

          Make that change permanent by editing /etc/sysctl.conf to add these lines at the end:

          # increase shared memory limit for postgres
          kernel.shmmax = 134217728
        2. Edit the PostgreSQL config file, /usr/local/pgsql/data/postgresql.conf, to use more memory. These values should improve performance in most cases. (more information)

          #       Shared Memory Size
          #
          shared_buffers = 15200      # 2*max_connections, min 16
          
          #       Non-shared Memory Sizes
          #
          sort_mem = 32168            # min 32
          
          
          #       Write-ahead log (WAL)
          #
          checkpoint_segments = 3     # in logfile segments (16MB each), min 1
          

          Restart postgres (service postgresql restart) or (/etc/init.d/postgres restart) so that the changes take effect.

        FreeBSD users: See man syctl, man 5 sysctl and man 5 loader.conf.

        Performance tuning resources:

    more information about PostgreSQL

    ($Id: postgres.html,v 1.49 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/i18n-translators.html0000644000175000017500000001147311501005400024026 0ustar frankiefrankie Translator's Guide

    Translator's Guide

    Most translators use the OpenACS Public Translation Server, because the process of getting new message keys onto the server and getting new translations back into the distribution are handled by the maintainers of that machine. You can also do translation work on your own OpenACS site; this makes your own translations more readily available to you but also means that your work will not be shared with other users unless you take extra steps (contacting an OpenACS core developer or submitting a patch) to get your work back to the OpenACS core.

    The basic steps for translators:

    • Go to the Localization page and choose the locale that you are translating to. If the locale is not present you need to visit Administration of Localization and create the locale.

    • Translating with Translator Mode. To translate messages in the pages they appear, Toggle Translator Mode and then browse to the page you want to translate. Untranslated messages will have a yellow background and a red star that you click to translate the message. Translated messages have a green star next to them that is a hyperlink to editing your translation. There is a history mechanism that allows you to see previous translations in case you would want to revert a translation.

      While in Translator mode, a list of all message keys appears at the bottom of each page.

    • Batch translation. To translate many messages at once, go to Administration of Localization, click on the locale to translate, then click on a package, and then click Batch edit these messages.

    When creating a new locale based on an existing one, such as creating the Guatamalan version of Spanish, you can copy the existing locale's catalog files using the script /packages/acs-core-docs/www/files/create-new-catalog.sh.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-openacs-keepalive.html0000644000175000017500000003142211501005400025730 0ustar frankiefrankie Starting and Stopping an OpenACS instance.

    Starting and Stopping an OpenACS instance.

    The simplest way to start and stop and OpenACS site is to run the startup shell script provided, /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/run. This runs as a regular task, and logs to the logfile. To stop the site, kill the script.

    A more stable way to run OpenACS is with a "keepalive" mechanism of some sort, so that whenever the server halts or is stopped for a reset, it restarts automatically. This is recommended for development and production servers.

    The Reference Platform uses Daemontools to control AOLserver. A simpler method, using init, is here.

    1. Daemontools must already be installed. If not, install it.

    2. Each service controlled by daemontools must have a directory in /service. That directory must have a file called run. It works like this:

      • The init program starts every time the computer is booted.

      • A line in init's configuration file, /etc/inittab, tells init to run, and to restart if necessary, svscanboot.

      • svscanboot checks the directory /service every few seconds.

      • If it sees a subdirectory there, it looks for a file in the subdirectory called run. If it finds a run file, it creates a supervise process

      • supervise executes the run script. Whenever the run script stops, supervise executes it again. It also creates additional control files in the same directory.

      Hence, the AOLserver instance for your development server is started by the file /service/$OPENACS_SERVICE_NAME/run. But we use a symlink to make it easier to add and remove stuff from the /service, so the actual location is /var/lib/aolserver/$OPENACS_SERVICE_NAMEetc/daemontools/run.

      Daemontools creates additional files and directories to track status and log. A daemontools directory is included in the OpenACS tarball at /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools. To use it, first ill any existing AOLserver instances. As root, link the daemontools directory into the /service directory. Daemontools' svscan process checks this directory every five seconds, and will quickly execute run.

      [$OPENACS_SERVICE_NAME etc]$ killall nsd
      nsd: no process killed
      [$OPENACS_SERVICE_NAME etc]$ emacs /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/run
      [$OPENACS_SERVICE_NAME etc]$ exit
      
      [root root]# ln -s /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/daemontools/ /service/$OPENACS_SERVICE_NAME

      Verify that AOLserver is running.

      [root root]# ps -auxw | grep nsd
      $OPENACS_SERVICE_NAME   5562 14.4  6.2 22436 15952 ?       S    11:55   0:04 /usr/local/aolserver/bin/nsd -it /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/config.tcl -u serve
      root      5582  0.0  0.2  3276  628 pts/0    S    11:55   0:00 grep nsd
      [root root]#
    3. The user $OPENACS_SERVICE_NAME can now control the service $OPENACS_SERVICE_NAME with these commands:

      • svc -d /service/$OPENACS_SERVICE_NAME - Bring the server down

      • svc -u /service/$OPENACS_SERVICE_NAME - Start the server up and leave it in keepalive mode.

      • svc -o /service/$OPENACS_SERVICE_NAME - Start the server up once. Do not restart it if it stops.

      • svc -t /service/$OPENACS_SERVICE_NAME - Stop and immediately restart the server.

      • svc -k /service/$OPENACS_SERVICE_NAME - Sends the server a KILL signal. This is like KILL -9. AOLserver exits immediately. If svc -t fails to fully kill AOLserver, use this option. This does not take the server out of keepalive mode, so it should still bounce back up immediately.

    4. Install a script to automate the stopping and starting of AOLserver services via daemontools. You can then restart a service via restart-aolserver $OPENACS_SERVICE_NAME

      [root root]# cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/restart-aolserver-daemontools.txt /usr/local/bin/restart-aolserver
      [root root]# chmod 755 /usr/local/bin/restart-aolserver
      [root root]#
    5. At this point, these commands will work only for the root user. Grant permission for the web group to use svc commands on the $OPENACS_SERVICE_NAME server.

      [root root]# /usr/local/bin/svgroup web /service/$OPENACS_SERVICE_NAME
      [root root]#
    6. Verify that the controls work. You may want to tail -f /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/$OPENACS_SERVICE_NAME-error.log in another window, so you can see what happens when you type these commands.

      Most of this information comes from Tom Jackson's AOLserver+Daemontools Mini-HOWTO.

    Table 6.1. How it Works

    ProgramInvoked by this program ...... using this fileWhere to find errorsLog goes toUse these commands to control it
    svscanboot init/etc/inittabps -auxw | grep readproctitlen/a 
    aolserversupervise (a child of svscanboot)/service/$OPENACS_SERVICE_NAME/run/var/lib/aolserver/$OPENACS_SERVICE_NAME/log/error.log/var/lib/aolserver/$OPENACS_SERVICE_NAME/log/$OPENACS_SERVICE_NAME.logsvc -k /service/$OPENACS_SERVICE_NAME
    postgresqlRedhat init scripts during boot/etc/init.d/postgresql/usr/local/pgsql/data/server.log service postgresql start (Red Hat), /etc/init.d/postgresql start (Debian)

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/object-system-requirements.html0000644000175000017500000010772411501005400026213 0ustar frankiefrankie Object Model Requirements

    Object Model Requirements

    By Pete Su

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    I. Introduction

    A major goal in OpenACS 4 is to unify and normalize many of the core services of the system into a coherent common data model and API. In the past, these services were provided to applications in an ad-hoc and irregular fashion. Examples of such services include:

    • General Comments

    • User/groups

    • Attribute storage in user/groups

    • General Permissions

    • Site wide search

    • General Auditing

    All of these services involve relating extra information and services to application data objects, examples of which include:

    • Bboard messages

    • A user home page

    • A ticket in the Ticket Tracker

    • A photograph in the PhotoDB

    In the past, developers had to use ad-hoc and inconsistent schemes to interface to the various "general" services mentioned above. Since each service used its own scheme for storing its metadata and mapping this data to application objects, we could not implement any kind of centralized management system or consistent administrative pages for all the services. Consequently, a large amount of duplicate code appeared throughout the system for dealing with these services.

    Unifying and "normalizing" these interfaces, to minimize the amount of code repetition in applications, is a primary goal of OpenACS 4. Thus the Object Model (OM, also referred to later as the object system) is concerned primarily with the storage and management of metadata, on any object within a given instance of OpenACS 4. The term "metadata" refers to any extra data the OM stores on behalf of the application - outside of the application's data model - in order to enable certain generic services. The term "object" refers to any entity being represented within the OpenACS, and typically corresponds to a single row within the relational database.

    Vision Statement

    The OpenACS 4 Object Model must address five high-level requirements that repeatedly exhibit themselves in the context of existing services in OpenACS 3.x, as described below.

    Object Identifiers for General Services

    Generic services require a single unambiguous way of identifying application objects that they manage or manipulate. In OpenACS 3.x, there are several different idioms that construct object identifiers from other data. Many modules use a (user_id, group_id, scope) triple combination for the purpose of recording ownership information on objects for access control. User/groups also uses (user_id, group_id) pairs in its user_group_map table as a way to identify data associated with a single membership relation.

    Also in OpenACS 3.x, many utility modules exist that do nothing more than attach some extra attributes to existing application data. For example, general comments maintains a mapping table that maps application "page" data (static or dynamic) to one or more user comments on the page, by constructing a unique identifier for each page. This identifier is usually a combination of the table in which the data is stored, and the value of the primary key value for the particular page. This idiom is referred to as the "(on_which_table + on_what_id)" method for identifying application data. General comments stores its map from pages to comments using a "(on_which_table + on_what_id)" key, plus the id of the comment itself.

    All of these composite key constructions are implicit object identifiers: they build a unique ID out of other pieces of the data model. The problem is that their definition and use is ad-hoc and inconsistent. This makes the construction of generic application-independent services difficult. Therefore, the OpenACS 4 Object Model should provide a centralized and uniform mechanism for tagging application objects with unique identifiers.

    Support for Unified Access Control

    Access control should be as transparent as possible to the application developer. Until the implementation of the general permissions system, every OpenACS application had to manage access control to its data separately. Later on, a notion of "scoping" was introduced into the core data model.

    "Scope" is a term best explained by example. Consider some hypothetical rows in the address_book table:

    ...scopeuser_idgroup_id...
    ...user123 ...
    ...group 456...
    ...public ...

    The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address book.

    In this way, the scoping columns identify the security context in which a given object belongs, where each context is either a person or a group of people or the general public (itself a group of people).

    The problem with this scheme is that we are limited to using only users and groups as scopes for access control, limiting applications to a single level of hierarchy. Worse, the scoping system demanded that every page needing access to a given application had to do an explicit scope check to make sure access was allowed - if a developer was careless on just one site page, a security problem could result.

    Thus the OpenACS 4 Object Model must support a more general access control system that allows access control domains to be hierarchical, and specifiable with a single piece of data, instead of the old composite keys described above.

    Extensible Data Models

    Another problem with previous OpenACS data models is that many of the central tables in the system became bloated as they were extended to support an increasing number of modules. The users table is the best case in point: it became full of columns that exist for various special applications (e.g. user portraits), but that aren't really related to each other in any way except that they store information on users, i.e. the table became grossly denormalized. Normalizing (breaking-down) this table into several pieces, each of which is specific to a particular application, would improve maintainability greatly. Furthermore, the ability to allow applications or users to define new extensions to existing tables, and have some central metadata facility for keeping track of what data belong to which tables, would be very useful.

    Thus the motivation for providing object types and subtyping in the OpenACS 4 Object Model. The OM should allow developers to define a hierarchy of metadata object types with subtyping and inheritance. Developers can then use the framework to allow users to define custom extensions to the existing data models, and the OM does the bookkeeping necessary to make this easier, providing a generic API for object creation that automatically keeps track of the location and relationships between data.

    Design Note: While this doesn't really belong in a requirements document, the fact that we are constrained to using relational databases means that certain constraints on the overall design of the object data model exist, which you can read about in Summary and Design Considerations.

    Modifiable Data Models

    Another recurring applications problem is how to store a modifiable data model, or how to store information that may change extensively between releases or in different client installations. Furthermore, we want to avoid changes to an application's database queries in the face of any custom extensions, since such changes are difficult or dangerous to make at runtime, and can make updating the system difficult. Some example applications in OpenACS 3.x with modifiable data models include:

    • User/groups: developers and users can attach custom data to group types, groups, and members of groups.

    • In the Ecommerce data model, the ec_custom_product_fields table defines attributes for catalog products, and the ec_custom_product_field_values table stores values for those attributes.

    • In the PhotoDB data model, the ph_custom_photo_fields table defines attributes for the photographs owned by a specific user, and tables named according to the convention "ph_user_<user_id>_custom_info" are used to store values for those attributes.

    Thus the Object Model must provide a general mechanism for applications and developers to modify or extend data models, without requiring changes to the SQL schema of the system. This ensures that all applications use the same base schema, resulting in a uniform and more maintainable system.

    Generic Relations

    Many OpenACS applications define simple relationships between application objects, and tag those relationships with extra data. In OpenACS 3.x, this was done using mapping tables. The user/groups module has the most highly developed data model for this purpose, using a single table called user_group_map that mapped users to groups. In addition, it uses the the user_group_member_fields and user_group_member_fields_map tables to allow developers to attach custom attributes to group members. In fact, these custom attributes were not really attached to the users, but to the fact that a user was a member of a particular group - a subtle but important distinction. As a historical note, in OpenACS 3.x, user/groups was the only part of the system that provided this kind of data model in a reusable way. Therefore, applications that needed this capability often hooked into user/groups for no other reason than to use this part of its data model.

    The OpenACS 4 data model must support generic relations by allowing developers to define a special kind of object type called a relation type. Relation types are themselves object types that do nothing but represent relations. They can be used by applications that previously used user/groups for the same purpose, but without the extraneous, artificial dependencies.

    System Overview

    The Object Model package is a combination of data model and a procedural API for manipulating application objects within an OpenACS instance. The OM allows developers to describe a hierarchical system of object types that store metadata on application objects. The object type system supports subtyping with inheritance, so new object types can be defined in terms of existing object types.

    The OM data model forms the main part of the OpenACS 4 Kernel data model. The other parts of the Kernel data model include:

    • Parties and Groups

    • Permissions

    Each of these is documented elsewhere at length.

    Use-cases and User-scenarios

    (Pending as of 8/27/00)

    Requirements: Data Model

    The data model for the object system provides support for the following kinds of schema patterns that are used by many existing OpenACS modules:

    10.0 Object Identification and Storage

    Object identification is a central mechanism in the new metadata system. The fact that every object has a known unique identifier means that the core can deal with all objects in a generic way. Thus the only action required of an application to obtain any general service is to "hook into" the object system.

    In OpenACS 3.x, modules use ad-hoc means to construct unique identifiers for objects that they manage. Generally, these unique IDs are built from other IDs that happen to be in the data model. Because there is no consistency in these implementations, every application must hook into every service separately.

    Examples of utilities that do this in OpenACS 3.x system are:

    • User/groups: Information is attached to group membership relations.

    • General Comments: Comments are attached to objects representing some kind of document.

    • General Permissions: Stores access control information on application data.

    • User Profiling: Maps users to pieces of content that they have looked at; content identifiers must be managed in a uniform way.

    • Site Wide Search: Stores all content in a single flat table, with object identifiers pointing to the object containing the content in the first place. This way, we can search the contents of many different types of objects in a uniform way.

    The OM will support and unify this programming idiom by providing objects with unique identifiers (unique within a given OpenACS instance) and with information about where the application data associated with the object is stored. The identifier can be used to refer to collections of heterogeneous application data. More importantly, object identifiers will enable developers to readily build and use generic services that work globally across a system.

    The object identifiers should be subject to the following requirements:

    10.10 Uniqueness

    The object ID should be unique among all the IDs in the entire OpenACS system in which the object lives.

    10.20 Useful as a Reference

    Applications should be able to use the unique object ID as a reference, with which they can fetch any or all of the object's attributes.

    10.30 Storable

    Object IDs should be storable in tables. e.g. you should be able to use them to implement mapping tables between objects, to represent relationships.

    10.40 Moveable

    Objects should be mobile between databases. That is, information will often need to be moved between multiple servers (development, staging, and production), so a mechanism for moving this data is necessary. In addition, a mechanism for tagging these objects in a way similar to CVS would be useful in determining which objects need to be synchronized.

    20.0 Object Types

    An object type refers to a specification of one or more attributes to be managed along with a piece of application data.

    The object system should provide a data model for describing and representing object types. This data model is somewhat analogous to the Oracle data dictionary, which stores information about all user defined tables in the system.

    The canonical example of this kind of data model occurs in the current OpenACS 3.x user/groups module, which allows the developer to create new group types that can contain not only generic system level attributes but also extended, developer-defined attributes. In addition, these attributes can either be attached to the group type itself, and shared by all instances, or they can be different for each instance. At its core, the OpenACS 4 object system is meant to be a generalization of this mechanism. The data model should allow developers to at least do everything they used to with user/groups, but without its administrative hassles.

    Therefore, the data model must be able to represent object types that have the following characteristics:

    20.10 Type Name

    A human readable name for the object type.

    20.20 Type Attributes

    Attributes whose values are shared by all instances of the object type.

    20.30 Object Attributes

    Attributes that are specific to each particular object belonging to a given type.

    The data model must also enforce certain constraints on object types:

    20.40 Type Uniqueness

    Object type names must be unique.

    20.50 Attribute Name Uniqueness

    Attribute names must be unique in the scope of a single object type and any of its parent types.

    30.0 Type Extension

    The Object Model must support the definition of object types that are subtypes of existing types. A subtype inherits all the attributes of its parent type, and defines some attributes of its own. A critical aspect of the OM is parent types may be altered, and any such change must propagate to child subtypes.

    The OM data model must enforce constraints on subtypes that are similar to the ones on general object types.

    30.10 Subtype Uniqueness

    Subtype names must be unique (this parallels requirement 10.40).

    30.20 Subtype Attribute Name Uniqueness

    Attribute names must be unique in the scope of a single object subtype.

    30.30 Parent Type Prerequisite

    Subtypes must be defined in terms of parent types that, in fact, already exist.

    30.40

    The extended attribute names in a subtype must not be the same as those in its parent type.

    35.0 Methods

    35.10 Method and Type Association

    The OM data model should define a mechanism for associating procedural code, called methods, with objects of a given type. Methods are associated with the each object type - not each object instance.

    35.20 Method Sharing

    All instances of a given object type should share the same set of defined methods for that type.

    40.0 Object Attribute Value Storage

    In addition to information on types, the OM data model provides for the centralized storage of object attribute values. This facility unifies the many ad-hoc attribute/value tables that exist in various OpenACS 3.x data models, such as:

    • User groups: Each instance of a group type can have custom data.

    • Photo DB: Users can define their own custom metadata to attach to photograph objects.

    • Ecommerce: Vendors can attach custom fields to the data model describing their products.

    40.10 Generic Retrieval

    Attributes should be stored so that they are retrievable in a way that is independent of the type of the object that they belong to. That is, the only data needed to retrieve an attribute should be the system-wide ID of an object (see requirement 10.20 above) and the attribute name.

    40.20 Inherited Attributes

    The system should allow for the automatic retrieval of inherited attribute values, for an object belonging to a subtype.

    40.30. Constraints on Attributes

    The system should allow the developer to put down constraints on the values that an attribute may hold, for the purposes of maintaining application specific integrity rules.

    50.0 Object Contexts

    In OpenACS 3.x, there was a notion of "scope" for application objects. An object could be belong to one of three scopes: public, group or user. This provided a crude way to associate objects with particular scopes in the system, but it was awkward to use and limited in flexibility.

    The OpenACS 4 Object Model provides a generalized notion of scope that allows developers to represent a hierarchy of object contexts. These contexts are used as the basis for the permissions system. In general, if an object has no explicit permissions attached to it, then it inherits permissions from its context.

    The context data model also forms the basis of the subsites system, and is a basic part of the permissions system, described in separate documents.

    The context data model should provide the following facilities:

    50.10 Unique ID

    Every context should have a unique ID in the system.

    50.20 Tree Structure

    The data model should support a tree structured organization of contexts. That is, contexts can be logically "contained" within other contexts (i.e. contexts have parents) and contexts can contain other contexts (i.e. contexts can have children).

    50.30 Data Model Constraints

    All objects must have a context ID. This ID must refer to an existing context or be NULL. The meaning of a NULL context is determined by the implementation.

    Note:

    The current system interprets the NULL context as meaning the default "site-wide" context in some sense. I wanted to note this fact for others, but there is no need to make this a requirement of the system. I think it would be reasonable to have a NULL context be an error (psu 8/24/2000).

    55.0 Object Relations

    The data model should include a notion of pair-wise relations between objects. Relations should be able to record simple facts of the form "object X is related to object Y by relationship R," and also be able to attach attributes to these facts.

    Requirements: API

    The API should let programmers accomplish the following actions:

    60.0 Object Type Creation

    60.10 Create a New Object Type

    The object system API should provide a procedure call that creates a new object type by running the appropriate transactions on the object system data model. This API call is subject to the constraints laid out in the data model. We call this operation "instantiating" an object.

    60.20 Create a New Object Subtype

    The object system API should provide a procedure call for creating subtypes of a given type. Operationally, this API is the same as requirement 60.10. Instances of subtypes automatically contain all attributes of the parent type in addition to all attributes of the subtype. This API is subject to the constraints laid out in the data model.

    60.30 Create a New Relation Type

    There should be an API call to create a new type of object relation. Relation types can be modeled as object types. The API below for manipulating attributes can then be used to add attributes to relation types.

    70.0 Update an Object Type

    The object system API must allow the programmer to modify, add, and delete attributes from any object type. Updates should be propagated to any child subtypes. This API is subject to the constraints laid out in the data model.

    80.0 Delete an Object Type

    The system provides an API call for deleting an object type.

    80.10

    Deleting an object type destroys all instances of the type. It should be an error to delete types that have dependent subtypes. This API is subject to the constraints laid out in the data model.

    80.10.10

    However, the programmer should also be able to specify that all the subtypes and instances of those subtypes be destroyed before destroying the object type. This is similar to a "delete cascade" constraint in SQL.

    90.0 Object Instance Creation and Destruction

    The system must provide API calls to manage the creation and destruction of object instances.

    90.10 Create an Instance of an Object Type

    The system should provide an API call for creating a new instance of a given object type. The new instance should be populated with values for each of the attributes specified in the definition of the type. In addition, it should be possible to create the new instance with an optional context ID that refers to the default context that the object will live in.

    90.20 Delete an Object Instance

    The OM should provide an API call for object deletion. Objects can be deleted only when no other objects in the system refer to them. Since it might not be practical to provide a mechanism like "delete cascade" here in a reliable way, providing such a facility in the system is optional.

    94.0 Object Relation Creation and Destruction

    The system must provide API calls to manage the creation and destruction of object relations.

    94.10 Create an Object Relation

    The OM must provide an API call to declare that two objects are related to each other by a given relation type. This API call should also allow programmers to attach attributes to this object relation.

    94.20 Destroy an Object Relation

    There should be an API call for destroying object relations and their attributes.

    95.10 Create and Destroy Contexts

    The system should provide an API to create and destroy object contexts.

    100.10 Set Attribute Values for an Object

    The system should provide an API for updating the attribute values of a particular instance of an object type.

    110.10 Get Attribute Values for an Object

    The system should provide an API for retrieving attribute values from a particular instance of an object type.

    120.10 Efficiency

    The Object Model must support the efficient storage and retrieval of object attributes. Since the OM is intended to form the core of many general services in the OpenACS, and these services will likely make extensive use of the OM tables, queries on these tables must be fast. The major problem here seems to be supporting subtyping and inheritance in a way that does not severely impact query performance.

    130.10 Ease of Use

    Most OpenACS packages will be expected to use the Object Model in one way or another. Since it is important that the largest audience of developers possible adopts and uses the OM, it must be easy to incorporate into applications, and it must not impose undue requirements on an application's data model. In other words, it should be easy to "hook into" the object model, and that ability should not have a major impact on the application data model.

    Note: Is the API the only way to obtain values? How does this integrate with application level SQL queries?

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation08/10/2000Bryan Quinn
    0.2Major re-write08/11/2000Pete Su
    0.3Draft completed after initial reviews08/22/2000Pete Su
    0.4Edited, updated to conform to requirements template, pending freeze08/23/2000Kai Wu
    Final edits before freeze08/24/2000Pete Su
    0.5Edited for consistency08/27/2000Kai Wu
    0.6Put Object ID stuff first, because it makes more sense08/28/2000Pete Su
    0.7Added requirement that knowledge-level objects must be moveable between databases.08/29/2000Richard Li
    0.8Rewrote intro to match language and concepts in the design document. Also cleaned up usage a bit in the requirements section. Added short vague requirements on relation types.09/06/2000Pete Su
    0.9Edited for ACS 4 Beta release.09/30/2000Kai Wu
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/profile-code.html0000644000175000017500000000544611501005400023250 0ustar frankiefrankie Profile your code

    Profile your code

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    There are several facilities for profiling your code in OpenACS. The first thing to do is to install the developer-support package and play around with it. But there is also support in the API for profiling your code: profiling your code using ds_profile

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-admin-pages.html0000644000175000017500000001411111501005400024713 0ustar frankiefrankie Admin Pages

    Admin Pages

    There are at least two flavors of admin user interface:

    • Admins use same pages as all other users, except that they are offered admin links and buttons where appropriate. For example, if admins have privilege to bulk-delete items you could provide checkboxes next to every item seen on a list and the Delete Selected button on the bottom of the list.

    • Dedicated admin pages. If you want admins to have access to data that users aren't interested in or aren't allowed to see you will need dedicated admin pages. The conventional place to put those dedicated admin pages is in the /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin directory.

      [$OPENACS_SERVICE_NAME www]$ mkdir admin
      [$OPENACS_SERVICE_NAME www]$ cd admin

      Even if your application doesn't need any admin pages of its own you will usually need at least one simple page with a bunch of links to existing administration UI such as Category Management or standard Parameters UI. Adding the link to Category Management is described in the section on categories. The listing below adds a link to the Parameters UI of our package.

      [$OPENACS_SERVICE_NAME admin]$ vi index.adp
      <master>
      <property name="title">@title;noquote@</property>
      <property name="context">@context;noquote@</property>
      
      <ul class="action-links">
        <li><a href="@parameters_url@" title="Set parameters" class="action_link">Set parameters</a></li>
      </ul>
      
      [$OPENACS_SERVICE_NAME admin]$ vi index.tcl
      ad_page_contract {} {
      } -properties {
          context_bar
      }
      
      set package_id [ad_conn package_id]
      
      permission::require_permission \
                -object_id $package_id \
                -privilege admin]
      
      set context [list]
      
      set title "Administration"
      
      set parameters_url [export_vars -base "/shared/parameters" {
        package_id { return_url [ad_return_url] }
      }]
      
      

      Now that you have the first admin page it would be nice to have a link to it somewhere in the system so that admins don't have to type in the /admin every time they need to reach it. You could put a static link to the toplevel index.adp but that might be distracting for people who are not admins. Besides, some people consider it impolite to first offer a link and then display a nasty "You don't have permission to access this page" message.

      In order to display the link to the admin page only to users that have admin privileges add the following code near the top of /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.tcl:

      
      set package_id [ad_conn package_id]
      
      set admin_p [permission::permission_p -object_id $package_id \
        -privilege admin -party_id [ad_conn untrusted_user_id]]
      
      if { $admin_p } {
          set admin_url "admin"
          set admin_title Administration
      }
      

      In /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/www/admin/index.adp put:

      <if @admin_p@ ne nil>
        <a href="@admin_url@">@admin_title@</a>
      </if>
      
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/permissions-tediously-explained.html0000644000175000017500000013431311456662500027260 0ustar frankiefrankie OpenACS Permissions Tediously Explained

    OpenACS Permissions Tediously Explained

    by Vadim Nasardinov. Modified and converted to Docbook XML by Roberto Mello

    The code has been modified since this document was written so it is now out of date. See this forum thread.

    Permissions Overview

    Who (grantee_id) can do what (privilege) on which object (object_id).

    The general permissions system has a flexible (and relatively complex) data model in OpenACS. Developers who have not had the time to learn the internals of the data model may end up writing seemingly correct code that crashes their system in weird ways. This writeup is the result of my running into such a piece of code and trying to understand exactly what went wrong. It is geared towards developers who understand the general permissions system to the extent that is described in the Groups, Context, Permissions documentation, but who have not had the opportunity to take a long, careful look at the system internals.

    In OpenACS, most of the interesting tables are expected to extend (subtype) the acs_objects table, i.e. they are expected to have an integer primary key column that references the object_id column of acs_objects.

    create table acs_objects (
          object_id             integer
              not null
              constraint acs_objects_pk primary key,
          object_type
              not null
              constraint acs_objects_object_type_fk references acs_object_types (object_type),
          context_id
              constraint acs_objects_context_id_fk references acs_objects(object_id),
          security_inherit_p	  char(1) default 't'
              not null,
          constraint acs_objects_sec_inherit_p_ck
              check (security_inherit_p in ('t', 'f')),
          creation_user         integer,
          creation_date         date default sysdate not null,
          creation_ip           varchar2(50),
          last_modified         date default sysdate not null,
          modifying_user        integer,
          modifying_ip          varchar2(50),
          constraint acs_objects_context_object_un
              unique (context_id, object_id) disable
    );
        

    This means that items that want to use the features of the OpenACS object system needs to have an entry in the acs_objects. This allows developers to define relationships between any two entities A and B by defining a relationship between their corresponding entries in the acs_objects table. One of the applications of this powerful capability is the general permissions system.

    At the heart of the permission system are two tables: acs_privileges and acs_permissions.

      create table acs_privileges (
          privilege           varchar2(100) not null
              constraint acs_privileges_pk primary key,
          pretty_name         varchar2(100),
          pretty_plural       varchar2(100)
      );
        
      create table acs_permissions (
          object_id
              not null
              constraint acs_permissions_on_what_id_fk references acs_objects (object_id),
          grantee_id
              not null
              constraint acs_permissions_grantee_id_fk references parties (party_id),
          privilege
              not null
              constraint acs_permissions_priv_fk references acs_privileges (privilege),
          constraint acs_permissions_pk
              primary key (object_id, grantee_id, privilege)
      );
        

    The acs_privileges table stores named privileges like read, write, delete, create, and admin. The acs_permissions table stores assertions of the form:

    Who (grantee_id) can do what (privilege) on which object (object_id).

    The micromanaging approach to system security would be to require application developers to store permission information explicitly about every object, i.e. if the system has 100,000 and 1,000 users who have the read privilege on all objects, then we would need to store 100,000,000 entries of the form:

    object_idgrantee_idprivilege
    object_id_1user_id_1'read'
    object_id_1user_id_2'read'
    ...
    object_id_1user_id_n'read'
    object_id_2user_id_1'read'
    object_id_2user_id_2'read'
    ...
    object_id_2user_id_n'read'
    ...
    ...
    object_id_muser_id_1'read'
    object_id_muser_id_2'read'
    ...
    object_id_muser_id_n'read'

    Although quite feasible, this approach fails to take advantage of the fact that objects in the system are commonly organized hierarchally, and permissions usually follow the hierarchical structure, so that if user X has the read privilege on object A, she typically also has the read privilege on all objects attached under A.

    The general permission system takes advantage of the hierarchical organization of objects to unburden developers of the necessity to explicitly maintain security information for every single object. There are three kinds of hierarchies involved. These are discussed in the following sections.

    Context Hierarchy

    Suppose objects A, B, ..., and F form the following hierarchy.

    Table 11.2. Context Hierarchy Example

    A

    object_id=10

    B

    object_id=20

    C

    object_id=30

    D

    object_id=40

    E

    object_id=50

    F

    object_id=60

    This can be represented in the acs_objects table by the following entries:

    Table 11.3. acs_objects example data

    object_idcontext_id
    2010
    3010
    4020
    5020
    6030

    The first entry tells us that object 20 is the descendant of object 10, and the third entry shows that object 40 is the descendant of object 20. By running a CONNECT BY query, we can compute that object 40 is the second-generation descendant of object 10. With this in mind, if we want to record the fact that user Joe has the read privilege on objects A, ..., F, we only need to record one entry in the acs_permissions table.

    objectgranteeprivilege
    AJoeread

    The fact that Joe can also read B, C, ..., and F can be derived by ascertaining that these objects are children of A by traversing the context hierarchy. As it turns out, hierarchical queries are expensive. As Rafael Schloming put it so aptly, Oracle can't deal with hierarchies for shit.

    One way to solve this problem is to cache a flattened view of the context tree like so:

    objectancestorn_generations
    AA0
    BB0
    BA1
    CC0
    CA1
    DD0
    DB1
    DA2
    EE0
    EB1
    EA2
    FF0
    FC1
    FA2

    Note that the number of entries in the flattened view grows exponentially with respect to the depth of the context tree. For instance, if you have a fully populated binary tree with a depth of n, then the number of entries in its flattened view is

    1 + 2*2 + 3*4 + 4*8 + 5*16 + ... + (n+1)*2n = n*2n+1 + 1

    Despite its potentially great storage costs, maintaining a flattened representation of the context tree is exactly what OpenACS does. The flattened context tree is stored in the acs_object_context_index table.

      create table acs_object_context_index (
          object_id
              not null
              constraint acs_obj_context_idx_obj_id_fk references acs_objects (object_id),
          ancestor_id
              not null
              constraint acs_obj_context_idx_anc_id_fk references acs_objects (object_id),
          n_generations	    integer
              not null
              constraint acs_obj_context_idx_n_gen_ck check (n_generations >= 0),
          constraint acs_object_context_index_pk
              primary key (object_id, ancestor_id)
      ) organization index;
        

    A few things to note about this table are these. Number one, it is an index-organized table, which means it is substantially optimized for access by primary key. Number two, as the above computations suggest, the size of the table grows polynomially with respect to the average number of descendants that an object has, and exponentially with respect to the depth of the context tree.

    The acs_object_context_index is kept in sync with the acs_objects table by triggers like this:

    create or replace trigger acs_objects_context_id_in_tr
    after insert on acs_objects
    for each row
    begin
        insert into acs_object_context_index
         (object_id, ancestor_id, n_generations)
        values
         (:new.object_id, :new.object_id, 0);
    
        if :new.context_id is not null and :new.security_inherit_p = 't' then
          insert into acs_object_context_index
           (object_id, ancestor_id,
            n_generations)
          select
           :new.object_id as object_id, ancestor_id,
           n_generations + 1 as n_generations
          from acs_object_context_index
          where object_id = :new.context_id;
        elsif :new.object_id != 0 then
          -- 0 is the id of the security context root object
          insert into acs_object_context_index
           (object_id, ancestor_id, n_generations)
          values
           (:new.object_id, 0, 1);
        end if;
    end;
    

    One final note about acs_objects. By setting an object's security_inherit_p column to 'f', you can stop permissions from cascading down the context tree. In the following example, Joe does not have the read permissions on C and F.


    A
    object_id=10
    readable by Joe
          


    B
    object_id=20
    readable by Joe
                  


    C
    object_id=30
    security_inherit_p = 'f'
    not readable by Joe
          


    D
    object_id=40
          


    E
    object_id=50
          


    F
    object_id=60
    security_inherit_p = 'f'
    not readable by Joe
          

    Privilege Hierarchy

    Privileges are also organized hierarchically. In addition to the five main system privileges defined in the ACS Kernel data model, application developers may define their own. Note, however, that this is no longer recommended practice.

    By defining parent-child relationship between privileges, the OpenACS data model makes it easier for developers to manage permissions. Instead of granting a user explicit read, write, delete, and create privileges on an object, it is sufficient to grant the user the admin privilege to which the first four privileges are tied. Privileges are structured as follows.

    admin
    createdeletereadwrite

    Note that admin privileges are greater than read, write, create and delete privileges combined. Issuing someone read, write, create and delete privileges will not result in the person getting admin privileges.

    The parent-child relationship between privileges is represented in the acs_privilege_hierarchy table:

      create table acs_privilege_hierarchy (
          privilege
              not null
              constraint acs_priv_hier_priv_fk references acs_privileges (privilege),
          child_privilege
              not null
              constraint acs_priv_hier_child_priv_fk references acs_privileges (privilege),
          constraint acs_privilege_hierarchy_pk
              primary key (privilege, child_privilege)
      );
        

    As in the case of the context hierarchy, it is convenient to have a flattened representation of this hierarchal structure. This is accomplished by defining the following view.

      create or replace view acs_privilege_descendant_map
      as
      select
        p1.privilege,
        p2.privilege as descendant
      from
        acs_privileges p1,
        acs_privileges p2
      where
        p2.privilege in 
          (select
             child_privilege
           from
             acs_privilege_hierarchy
           start with
             privilege = p1.privilege
           connect by
             prior child_privilege = privilege
          )
        or p2.privilege = p1.privilege;
        

    As the number of different privileges in the system is expected to be reasonably small, there is no pressing need to cache the flattened ansector-descendant view of the privilege hierarchy in a specially maintained table like it is done in the case of the context hierarchy.

    Party Hierarchy

    Now for the third hierarchy playing a promiment role in the permission system. The party data model is set up as follows.

      create table parties (
          party_id
              not null
              constraint parties_party_id_fk references acs_objects (object_id)
              constraint parties_pk primary key,
          email               varchar2(100)
              constraint parties_email_un unique,
          url                 varchar2(200)
      );
        
      create table persons (
          person_id
              not null
              constraint persons_person_id_fk references parties (party_id)
              constraint persons_pk primary key,
          first_names          varchar2(100)
              not null,
          last_name            varchar2(100)
              not null
      );
        
      create table users (
          user_id
              not null
              constraint users_user_id_fk references persons (person_id)
              constraint users_pk primary key,
          password        char(40),
          -- other attributes
      );
        
     
      create table groups (
          group_id
              not null
              constraint groups_group_id_fk references parties (party_id)
              constraint groups_pk primary key,
          group_name           varchar2(100) not null
      );
        

    Recall that the grantee_id column of the acs_permissions table references parties.party_id. This means that you can grant a privilege on an object to a party, person, user, or group. Groups represent aggregations of parties. The most common scenario that you are likely to encounter is a group that is a collection of users, although you could also have collections of persons, groups, parties, or any mix thereof.

    Given that the most common use of groups is to partition users, how do you build groups? One way is to grant membership explicitly. If you have a group named Pranksters, you can assign membership to Pete, Poly, and Penelope. The fact that these users are members of the Pranksters group will be recorded in the membership_rels and acs_rels tables:

      create table acs_rels (
          rel_id
              not null
              constraint acs_rels_rel_id_fk references acs_objects (object_id)
              constraint acs_rels_pk primary key,
          rel_type
              not null
              constraint acs_rels_rel_type_fk references acs_rel_types (rel_type),
          object_id_one
              not null
              constraint acs_object_rels_one_fk references acs_objects (object_id),
          object_id_two
              not null
              constraint acs_object_rels_two_fk references acs_objects (object_id),
          constraint acs_object_rels_un
              unique (rel_type, object_id_one, object_id_two)
      );
        
      create table membership_rels (
          rel_id
              constraint membership_rel_rel_id_fk references acs_rels (rel_id)
              constraint membership_rel_rel_id_pk primary key,
          -- null means waiting for admin approval
          member_state         varchar2(20)
              constraint membership_rel_mem_ck
               check (member_state in ('approved', 'banned', 'rejected', 'deleted'))
      );
        

    The acs_rels table entries would look like so:

    rel_typeobject_oneobject_two
    membership_rel Pranksters Pete
    membership_rel Pranksters Poly
    membership_rel Pranksters Penelope

    Read acs_rels: right-side is a subset of left-side, ie object2 is a part of object1.

    Another way of building up groups is by adding subgroups. Suppose we define Merry Pranksters and Sad Pranksters as subgroups of Pranksters. We say that the Pranksters group is composed of groups Merry Pranksters and Sad Pranksters. This information is stored in the acs_rels and composition_rels tables.

    create table composition_rels (
        rel_id
            constraint composition_rels_rel_id_fk references acs_rels (rel_id)
            constraint composition_rels_rel_id_pk primary key
    );
        

    The relevant entries in the acs_rels look like so.

    rel_typeobject_oneobject_two
    composition_rel Pranksters Merry Pranksters
    composition_rel Pranksters Sad Pranksters

    The composition relationship means that if I add Matt, Mel, and Mary to the Merry Pranksters, they should also automatically become members of the Pranksters group. The situation we are facing in trying to determine whether or not a user is member of a group is similar to the one discussed above in the case of the context hierarchy. Groups can form hierarchies with respect to the composition relationship. The compositon relationship is transitive. If G1 is a subgroup of G2, and G2 is a subgroup of G3, then G1 is a subgroup of G3; that is, any member of G1 is also a member of G3.

    Traversing the group composition hierarchy requires running hierarchical queries, which are expensive in Oracle. As we saw in the Context Hierarchy section, one way of reducing the performance hit incurred by hierarchical queries is to cache query results in a table maintained by triggers. The OpenACS data model defines two such tables:

     create table group_component_index (
              group_id        not null
                              constraint group_comp_index_group_id_fk
                              references groups (group_id),
              component_id    not null
                              constraint group_comp_index_comp_id_fk
                              references groups (group_id),
              rel_id          not null
                              constraint group_comp_index_rel_id_fk
                              references composition_rels (rel_id),
              container_id    not null
                              constraint group_comp_index_cont_id_ck
                              references groups (group_id),
              constraint group_component_index_ck
              check (group_id != component_id),
              constraint group_component_index_pk
              primary key (group_id, component_id, rel_id)
      ) organization index;
        
      create table group_member_index (
          group_id
              not null
              constraint group_member_index_grp_id_fk references groups (group_id),
          member_id
              not null
              constraint group_member_index_mem_id_fk references parties (party_id),
          rel_id
              not null
              constraint group_member_index_rel_id_fk references membership_rels (rel_id),
          container_id
              not null
              constraint group_member_index_cont_id_fk references groups (group_id),
          constraint group_member_index_pk
              primary key (member_id, group_id, rel_id)
      ) organization index;
        

    The group_component_index table stores a flattened representation of the group composition hierarchy that is maintained in sync with the acs_rels and composition_rels tables through triggers.

    additional comments

    As far as the group_member_index table goes, I am not sure I understand its purpose. It maintains group-member relationships that are resolved with respect to group composition. Note that information stored in group_member_index can be trivially derived by joining membership_rels, acs_rels, and group_component_index. Here is a view that does it. (This view is not part of the OpenACS Kernel data model.)

    create or replace view group_member_view
    as
    select
      gci.group_id, r.object_id_two as member_id
    from
      (
       select
         group_id, group_id as component_id
       from
         groups
       union
       select
         group_id, component_id
       from
         group_component_index
      ) gci,
      membership_rels mr,
      acs_rels r
    where
      mr.rel_id = r.rel_id
      and r.object_id_one = gci.component_id;
        

    A heuristic way to verify that group_member_view is essentially identical to group_member_index is to compute the symmetric difference between the two:

    select
      group_id, member_id
    from
      (
       select group_id, member_id from group_member_view
       minus
       select group_id, member_id from group_member_index
      )
    union
    select
      group_id, member_id
    from
      (
       select group_id, member_id from group_member_index
       minus
       select group_id, member_id from group_member_view
      )
        

    The query returns no rows. The important point is, if we have a flattened view of the composition hierarchy -- like one provided by the group_component_index table -- membership relationship resolution can be computed trivially with no hierarchical queries involved. There is no need to keep the view in a denormalized table, unless doing so results in substantial performance gains.

    Putting It All Together

    Security information is queried by calling the acs_permission.permission_p function in OpenACS. This is accessible from Tcl via the permission::permission_p procedure.

      
      create or replace package body acs_permission
      as
        -- some stuff removed for the sake of brevity
      
        function permission_p (
          object_id	 acs_objects.object_id%TYPE,
          party_id	 parties.party_id%TYPE,
          privilege	 acs_privileges.privilege%TYPE
        ) return char
        as
          exists_p char(1);
        begin
          -- XXX This must be fixed: -1 shouldn't be hardcoded (it is the public)
          select decode(count(*),0,'f','t') into exists_p
            from acs_object_party_privilege_map
           where object_id = permission_p.object_id
             and party_id in (permission_p.party_id, -1)
             and privilege = permission_p.privilege;
          return exists_p;
        end;
    
      end acs_permission;
        

    problem avoidance

    The function queries acs_object_party_privilege_map, which is a humongous view that joins three flattened hierarchies: the context tree, the privilege hierarchy, the party composition (and membership) hierarchy. It contains an extremely large number of rows. About the only kind of query you can run against it is the one performed by the acs_permission.permission_p function. Anything other than that would take forever to finish or would ultimately result in a query error.

    For example, do not try to do things like

    select count(*)
      from acs_object_party_privilege_map;
        

    To give another example of things to avoid, I have seen code like this:

      declare
          cursor cur is
            select
               object_id, party_id
            from
               acs_object_party_privilege_map
            where
               privilege = 'foo_create';
      begin
          -- revoke all 'foo_create' permissions
          for rec in cur
          loop
              acs_permission.revoke_permission (
                  object_id  => rec.object_id,
                  grantee_id => rec.party_id,
                  privilege  => 'foo_create'
              );
          end loop;
    
          acs_privilege.remove_child('admin','foo_create');
          acs_privilege.drop_privilege('foo');
    
      end;
      /
        

    The acs_permission.revoke_permission function merely runs a delete statement like so:

      
      delete from
         acs_permissions
      where
         object_id = revoke_permission.object_id
         and grantee_id = revoke_permission.grantee_id
         and privilege = revoke_permission.privilege;
        

    Note that in the above example, acs_permissions had only one entry that needed to be deleted:

    object_idgrantee_idprivilege
    default_context registered_users foo_create

    The above script would never get around to deleting this entry because it had to loop through a gazillion rows in the humongous acs_object_party_privilege_map view.

    Appendix: Various View Definitions

    create or replace view acs_object_party_privilege_map
    as
    select
      ogpm.object_id,
      gmm.member_id as party_id,
      ogpm.privilege
    from
      acs_object_grantee_priv_map ogpm,
      group_member_map gmm
    where
      ogpm.grantee_id = gmm.group_id
    union
    select
      object_id,
      grantee_id as party_id,
      privilege
    from
      acs_object_grantee_priv_map;
        
    create or replace view acs_object_grantee_priv_map
    as
    select
      a.object_id,
      a.grantee_id,
      m.descendant as privilege
    from
      acs_permission_all a,
      acs_privilege_descendant_map m
    where
      a.privilege = m.privilege;
        
     
    create or replace view acs_permissions_all
    as
    select
      op.object_id,
      p.grantee_id,
      p.privilege
    from
      acs_object_paths op,
      acs_permissions p
    where
      op.ancestor_id = p.object_id;
        
    create or replace view acs_object_paths
    as
    select
      object_id,
      ancestor_id,
      n_generations
    from
      acs_object_context_index;
        
     
    
    create or replace view group_member_map
    as
    select
      group_id,
      member_id,
      rel_id,
      container_id
    from
      group_member_index;
        
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/high-avail.html0000644000175000017500000000546411501005400022711 0ustar frankiefrankie High Availability/High Performance Configurations

    High Availability/High Performance Configurations

    See also Running a PostgreSQL database on another server.

    Figure 6.1. Multiple-server configuration

    Multiple-server configuration

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-debug.html0000644000175000017500000004342311501005400023624 0ustar frankiefrankie Debugging and Automated Testing

    Debugging and Automated Testing

    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Debugging

    Developer Support. The Developer Support package adds several goodies: debug information for every page; the ability to log comments to the page instead of the error log, and fast user switching so that you can test pages as anonymous and as dummy users without logging in and out.

    PostgreSQL. You can work directly with the database to do debugging steps like looking directly at tables and testing stored procedures. Start emacs. Type M-x sql-postgres. Press enter for server name and use $OPENACS_SERVICE_NAME for database name. You can use C-(up arrow) and C-(down arrow) for command history.

    Hint: "Parse error near *" usually means that an xql file wasn't recognized, because the tcl file is choking on the *SQL* placeholder that it falls back on.

    Watching the server log. 

    To set up real-time monitoring of the AOLserver error log, type

    less /var/lib/aolserver/$OPENACS_SERVICE_NAME/log/openacs-dev-error.log

    F to show new log entries in real time (like tail -f)
    C-c to stop and F to start it up again. 
    G goes to the end.
    ? searches backward 
    / searches forward. 
              

    Manual testing

    Make a list of basic tests to make sure it works

    Test NumActionExpected Result
    001Browse to the index page while not logged in and while one or more notes exist.No edit or delete or add links should appear.
    002Browse to the index page while logged in. An Edit link should appear. Click on it. Fill out the form and click Submit.The text added in the form should be visible on the index page.
    API-001Invoke mfp::note::create with a specific word as the title.Proc should return an object id.
    API-002Given an object id from API-001, invoke mfp::note::get.Proc should return the specific word in the title.
    API-003Given the object id from API-001, invoke mfp::note::delete.Proc should return 0 for success.

    Other things to test: try to delete someone else's note. Try to delete your own note. Edit your own note. Search for a note.

    Write automated tests

    by Simon Carstensen and Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    It seems to me that a lot of people have been asking for some guidelines on how to write automated tests. I've done several tests by now and have found the process to be extremely easy and useful. It's a joy to work with automated testing once you get the hang of it.

    Create the directory that will contain the test script and edit the script file. The directory location and file name are standards which are recognized by the automated testing package:

    [$OPENACS_SERVICE_NAME www]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/test
    [$OPENACS_SERVICE_NAME www]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/test
    [$OPENACS_SERVICE_NAME test]$ emacs myfirstpackages-procs.tcl

    Write the tests. This is obviously the big step :) The script should first call ad_library like any normal -procs.tcl file:

    ad_library {
        ...
    }
    

    To create a test case you call aa_register_case test_case_name.. Once you've created the test case you start writing the needed logic. We'll use the tutorial package, "myfirstpackage," as an example. Let's say you just wrote an API for adding and deleting notes in the notes packages and wanted to test that. You'd probably want to write a test that first creates a note, then verifies that it was inserted, then perhaps deletes it again, and finally verifies that it is gone.

    Naturally this means you'll be adding a lot of bogus data to the database, which you're not really interested in having there. To avoid this I usually do two things. I always put all my test code inside a call to aa_run_with_teardown which basically means that all the inserts, deletes, and updates will be rolled back once the test has been executed. A very useful feature. Instead of inserting bogus data like: set name "Simon", I tend to generate a random script in order avoid inserting a value that's already in the database:

    set name [ad_generate_random_string]
    

    Here's how the test case looks so far:

    aa_register_case mfp_basic_test {
        My test
    } {
        aa_run_with_teardown \
           -rollback \
           -test_code  {
    
           }
    }
    

    Now let's look at the actual test code. That's the code that goes inside -test_code {}. We want to implement test case API-001, "Given an object id from API-001, invoke mfp::note::get. Proc should return the specific word in the title."

          set name [ad_generate_random_string]
          set new_id [mfp::note::add -title $name]
          aa_true "Note add succeeded" [exists_and_not_null new_id]

    To test our simple case, we must load the test file into the system (just as with the /tcl file in the basic tutorial, since the file didn't exist when the system started, the system doesn't know about it.) To make this file take effect, go to the APM and choose "Reload changed" for "MyFirstPackage". Since we'll be changing it frequently, select "watch this file" on the next page. This will cause the system to check this file every time any page is requested, which is bad for production systems but convenient for developing. We can also add some aa_register_case flags to make it easier to run the test. The -procs flag, which indicates which procs are tested by this test case, makes it easier to find procs in your package that aren't tested at all. The -cats flag, setting categories, makes it easier to control which tests to run. The smoke test setting means that this is a basic test case that can and should be run any time you are doing any test. (a definition of "smoke test")

    Once the file is loaded, go to ACS Automated Testing and click on myfirstpackage. You should see your test case. Run it and examine the results.

    TCLWebtest tests

    API testing can only test part of our package - it doesn't test the code in our adp/tcl pairs. For this, we can use TCLwebtest. TCLwebtest must be installed for this test to work. This provides a library of functions that make it easy to call a page through HTTP, examine the results, and drive forms. TCLwebtest's functions overlap slightly with acs-automated-testing; see the example provided for one approach on integrating them.

    Example

    Now we can add the rest of the API tests, including a test with deliberately bad data. The complete test looks like:

    ad_library {
        Test cases for my first package.
    }
    
    aa_register_case \
        -cats {smoke api} \
        -procs {mfp::note::add mfp::note::get mfp::note::delete} \
        mfp_basic_test \
        {
            A simple test that adds, retrieves, and deletes a record.
        } {
            aa_run_with_teardown \
                -rollback \
                -test_code  {
                    set name [ad_generate_random_string]
                    set new_id [mfp::note::add -title $name]
                    aa_true "Note add succeeded" [exists_and_not_null new_id]
                    
                    mfp::note::get -item_id $new_id -array note_array
                    aa_true "Note contains correct title" [string equal $note_array(title) $name]
                    
                    mfp::note::delete -item_id $new_id
                    
                    set get_again [catch {mfp::note::get -item_id $new_id -array note_array}]
                    aa_false "After deleting a note, retrieving it fails" [expr {$get_again == 0}]
                }
        }
    
    aa_register_case \
        -cats {api} \
        -procs {mfp::note::add mfp::note::get mfp::note::delete} \
        mfp_bad_data_test \
        {
            A simple test that adds, retrieves, and deletes a record, using some tricky data.
        } {
            aa_run_with_teardown \
                -rollback \
                -test_code  {
                    set name {-Bad [BAD] \077 { $Bad}} 
                    append name [ad_generate_random_string]
                    set new_id [mfp::note::add -title $name]
                    aa_true "Note add succeeded" [exists_and_not_null new_id]
                    
                    mfp::note::get -item_id $new_id -array note_array
                    aa_true "Note contains correct title" [string equal $note_array(title) $name]
                    aa_log "Title is $name"
                    mfp::note::delete -item_id $new_id
                    
                    set get_again [catch {mfp::note::get -item_id $new_id -array note_array}]
                    aa_false "After deleting a note, retrieving it fails" [expr {$get_again == 0}]
                }
        }
    
    
    aa_register_case \
        -cats {web smoke} \
        -libraries tclwebtest \
        mfp_web_basic_test \
        {
            A simple tclwebtest test case for the tutorial demo package.
            
            @author Peter Marklund
        } {
            # we need to get a user_id here so that it's available throughout
            # this proc
            set user_id [db_nextval acs_object_id_seq]
    
            set note_title [ad_generate_random_string]
    
            # NOTE: Never use the aa_run_with_teardown with the rollback switch
            # when running Tclwebtest tests since this will put the test code in
            # a transaction and changes won't be visible across HTTP requests.
            
            aa_run_with_teardown -test_code {
                
                #-------------------------------------------------------------
                # Login
                #-------------------------------------------------------------
                
                # Make a site-wide admin user for this test
                # We use an admin to avoid permission issues
                array set user_info [twt::user::create -admin -user_id $user_id]
                
                # Login the user
                twt::user::login $user_info(email) $user_info(password)
                
                #-------------------------------------------------------------
                # New Note
                #-------------------------------------------------------------
                
                # Request note-edit page
                set package_uri [apm_package_url_from_key myfirstpackage]
                set edit_uri "${package_uri}note-edit"
                aa_log "[twt::server_url]$edit_uri"
                twt::do_request "[twt::server_url]$edit_uri"
                
                # Submit a new note
    
                tclwebtest::form find ~n note
                tclwebtest::field find ~n title
                tclwebtest::field fill $note_title
                tclwebtest::form submit
                
                #-------------------------------------------------------------
                # Retrieve note
                #-------------------------------------------------------------
                
                # Request index page and verify that note is in listing
                tclwebtest::do_request $package_uri                 
                aa_true "New note with title \"$note_title\" is found in index page" \
                    [string match "*${note_title}*" [tclwebtest::response body]]
                
                #-------------------------------------------------------------
                # Delete Note
                #-------------------------------------------------------------
                # Delete all notes
    
                # Three options to delete the note
                # 1) go directly to the database to get the id
                # 2) require an API function that takes name and returns ID
                # 3) screen-scrape for the ID
                # all options are problematic.  We'll do #1 in this example:
    
                set note_id [db_string get_note_id_from_name " 
                    select item_id 
                      from cr_items 
                     where name = :note_title  
                       and content_type = 'mfp_note'
                " -default 0]
    
                aa_log "Deleting note with id $note_id"
    
                set delete_uri "${package_uri}note-delete?item_id=${note_id}"
                twt::do_request $delete_uri
                
                # Request index page and verify that note is in listing
                tclwebtest::do_request $package_uri                 
                aa_true "Note with title \"$note_title\" is not found in index page after deletion." \
                    ![string match "*${note_title}*" [tclwebtest::response body]]
                
            } -teardown_code {
                
                twt::user::delete -user_id $user_id
            }
        }
    
    

    See also Automated Testing.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/upgrade-openacs-files.html0000644000175000017500000004651211501005400025054 0ustar frankiefrankie Upgrading the OpenACS files

    Upgrading the OpenACS files

    Chosing a Method to Upgrade your Files

    OpenACS is distributed in many different ways:

    • as a collection of files

    • as one big tarball

    • via CVS

    • via automatic download from within the APM (package manager)

    Upgrades work by first changing the file system (via any of the previous methods), and then using the APM to scan the file system, find upgrade scripts, and execute them. Starting with OpenACS 5.0, the last method was added, which automatically changes the file system for you. If you are using the last method, you can skip this page. This page describes whether or not you need to be upgrading using this page or not: Upgrading an OpenACS 5.0.0 or greater installation

    Methods of upgrading OpenACS files

    • Upgrading files for a site which is not in a CVS repository. Unpack the tarball into a new directory and copy its contents on top of your working directory. Or just 'install software', select remote repository, and upgrade your files from there.

      [root root]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver
      [$OPENACS_SERVICE_NAME web]$ tar xzf /var/tmp/openacs-5-1.tar.gz
      [$OPENACS_SERVICE_NAME web]$ cp -r openacs-5-1/* openacs-4
      [$OPENACS_SERVICE_NAME openacs-upgrade]$ exit
      [root root]#
      su - $OPENACS_SERVICE_NAME
      cd /var/lib/aolserver
      tar xzf /var/tmp/openacs-5-1.tgz
      cp -r openacs-5-1/* openacs-4
      exit
    • Upgrading files for a site in a private CVS repository

      Many OpenACS site developers operate their own CVS repository to keep track of local customizations. In this section, we describe how to upgrade your local CVS repository with the latest OpenACS version, without overriding your own local customizations.

      This diagram explains the basic idea. However, the labels are incorrect. Step 1(a) has been removed, and Step 1(b) should be labelled Step 1.

      Figure 5.2. Upgrading a local CVS repository

      Upgrading a local CVS repository

      • Step 0: Set up a working CVS checkout. To get your OpenACS code into your local CVS repository, you will set up a working CVS checkout of OpenACS. When you want to update your site, you'll update the working CVS checkout, import those changes into your local CVS checkout, create a temporary CVS checkout to merge your local changes, fix any conflicts, commit your changes, and then update your site. It sounds complicated, but it's not too bad, and it is the best way to work around CVS's limitations.

        This part describes how to set up your working CVS checkout. Once it is set up, you'll be able to update any packages using the existing working CVS checkout. We use one dedicated directory for each branch of OpenACS - if you are using OpenACS 5.1,x, you will need a 5.1 checkout. That will be good for 5.1, 5.11, 5.12, and so on. But when you want to upgrade to OpenACS 5.2, you'll need to check out another branch.

        The openacs-5-1-compat tag identifies the latest released version of OpenACS 5.1 (ie, 5.1.3 or 5.1.4) and the latest compatible version of each package. Each minor release of OpenACS since 5.0 has this tagging structure. For example, OpenACS 5.1.x has openacs-5-1-compat.

        You will want to separately check out all the packages you are using.

        [root root]# su - $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver
        [$OPENACS_SERVICE_NAME aolserver]$ cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r openacs-5-1-compat acs-core
        [$OPENACS_SERVICE_NAME aolserver]$ cd openacs-4/packages
        [$OPENACS_SERVICE_NAME aolserver]$ cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot checkout -r openacs-5-1-compat packagename packagename2...
        [$OPENACS_SERVICE_NAME aolserver]$ cd ../..
        [$OPENACS_SERVICE_NAME aolserver]$ mv openacs-4 openacs-5-1

        Make sure your working CVS checkout doesn't have the entire CVS tree from OpenACS. A good way to check this is if it has a contrib directory. If it does, you probably checked out the entire tree. You might want to start over, remove your working CVS checkout, and try again.

      • Step 1: Import new OpenACS code. 

        • Update CVS. Update your local CVS working checkout (unless you just set it up).

          [root root]# su - $OPENACS_SERVICE_NAME
          [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/openacs-5-1
          [$OPENACS_SERVICE_NAME aolserver]$ cvs up -Pd ChangeLog *.txt bin etc tcl www packages/*
        • Update a single package via cvs working checkout. You can add or upgrade a single package at a time, if you already have a cvs working directory.

          [root root]# su - $OPENACS_SERVICE_NAME
          [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/packages/openacs-5-1
          [$OPENACS_SERVICE_NAME openacs-5-1]$ cvs up -Pd packagename

          In the next section, the import must be tailored to just this package.

      • Step 2: Merge New OpenACS code. Now that you have a local copy of the new OpenACS code, you need to import it into your local CVS repository and resolve any conflicts that occur.

        Import the new files into your cvs repository; where they match existing files, they will become the new version of the file.

        [$OPENACS_SERVICE_NAME openacs-5-1]$  cd /var/lib/aolserver/openacs-5-1
        [$OPENACS_SERVICE_NAME openacs-5-1]$  cvs -d /var/lib/cvs import -m "upgrade to OpenACS 5.1" $OPENACS_SERVICE_NAME OpenACS openacs-5-1
                    

        Tip

        If adding or upgrading a single package, run the cvs import from within the base directory of that package, and adjust the cvs command accordingly. In this example, we are adding the myfirstpackage package.

        [root root]# su - $OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME aolserver]$ cd /var/lib/aolserver/openacs-5-0/package/myfirstpackage
        [$OPENACS_SERVICE_NAME myfirstpackage]$ cvs -d /var/lib/cvs/ import -m "importing package" $OPENACS_SERVICE_NAME/packages/myfirstpackage OpenACS openacs-5-1

        Create a new directory as temporary working space to reconcile conflicts between the new files and your current work. The example uses the cvs keyword yesterday, making the assumption that you haven't checked in new code to your local tree in the last day. This section should be improved to use tags instead of the keyword yesterday!

        [$OPENACS_SERVICE_NAME openacs-5.1]$  cd /var/lib/aolserver
        [$OPENACS_SERVICE_NAME tmp]$ rm -rf $OPENACS_SERVICE_NAME-upgrade
        [$OPENACS_SERVICE_NAME tmp]$ mkdir $OPENACS_SERVICE_NAME-upgrade
        [$OPENACS_SERVICE_NAME tmp]$ cvs checkout -d $OPENACS_SERVICE_NAME-upgrade -jOpenACS:yesterday -jOpenACS -kk $OPENACS_SERVICE_NAME > cvs.txt 2>&1
        (CVS feedback here)

        The file /var/tmp/openacs-upgrade/cvs.txt contains the results of the upgrade. If you changed files that are part of the OpenACS tarball and those changes conflict, you'll have to manually reconcile them. Use the emacs command M-x sort-lines (you may have to click Ctrl-space at the beginning of the file, and go to the end, and then try M-x sort-lines) and then, for each line that starts with a C, open that file and manually resolve the conflict by deleting the excess lines. When you're finished, or if there aren't any conflicts, save and exit.

        Once you've fixed any conflicts, commit the new code to your local tree.

        [$OPENACS_SERVICE_NAME tmp]$ cd $OPENACS_SERVICE_NAME-upgrade
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME-upgrade]$ cvs commit -m "Upgraded to 5.1"
      • Step 3: Upgrade your local staging site. Update your working tree with the new files. The CVS flags ensure that new directories are created and pruned directories destroyed.

        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME-upgrade]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs up -Pd
        (CVS feedback)
        [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
        [root root]# 

    Upgrading files for a site using the OpenACS CVS repository (cvs.openacs.org)

    1. [$OPENACS_SERVICE_NAME ~]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs up -Pd
      (CVS feedback)
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$

    Upgrading a Production Site Safely

    If you are upgrading a production OpenACS site which is on a private CVS tree, this process lets you do the upgrade without risking extended downtime or an unusable site:

    1. Declare a freeze on new cvs updates - ie, you cannot run cvs update on the production site

    2. Make a manual backup of the production site in addition to the automated backups

    3. Import the new code (for example, OpenACS 5.0.4, openacs-5-0-compat versions of ETP, blogger, and other applications) into a "vendor branch" of the $OPENACS_SERVICE_NAME CVS tree, as described in "Upgrading a local CVS repository", step 1, above. As soon as we do this, any cvs update command on production might bring new code onto the production site, which would be bad.

      Do step 2 above (merging conflicts in a $OPENACS_SERVICE_NAME-upgrade working tree).

    4. Manually resolve any conflicts in the working upgrade tree

    5. Use the upgrade script and a recent backup of the production database, to ake a new upgraded database called $OPENACS_SERVICE_NAME-upgrade. Now we have a new website called $OPENACS_SERVICE_NAME-upgrade.

    6. Test the $OPENACS_SERVICE_NAME-upgrade site

    7. If $OPENACS_SERVICE_NAME-upgrade is fully functional, do the real upgrade.

      1. Take down the $OPENACS_SERVICE_NAME site and put up a "down for maintenance" page.

      2. Repeat the upgrade with the most recent database

      3. Test the that the new site is functional. If so, change the upgraded site to respond to yourserver.net requests. If not, bring the original production site back up and return to the merge.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/groups-design.html0000644000175000017500000007057411501005400023472 0ustar frankiefrankie Groups Design

    Groups Design

    By Rafael H. Schloming and Mark Thomas

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Essentials

    Introduction

    Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services for different user communities.

    Historical Considerations

    The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships expensive.

    In addition, the Module Scoping design in OpenACS 3.0 introduced a party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer to:

    • add these three columns to each "scoped" table

    • define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null group_id)

    • perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and group_id values

    Competitive Analysis

    ...

    Design Tradeoffs

    The core of the Group Systems data model is quite simple, but it was designed in the hopes of modeling "real world" organizations which can be complex graph structures. The Groups System only considers groups that can be modeled using directed acyclic graphs, but queries over these structures are still complex enough to slow the system down. Since almost every page will have at least one membership check, a number of triggers, views, and auxiliary tables have been created in the hopes of increasing performance. To keep the triggers simple and the number of triggers small, the data model disallows updates on the membership and composition tables, only inserts and deletes are permitted.

    The data model has tried to balance the need to model actual organizations without making the system too complex or too slow. The added triggers, views, and tables and will increase storage requirements and the insert and delete times in an effort to speed access time. The limited flexibility (no updates on membership) trades against the complexity of the code.

    Data Model Discussion

    The Group System data model consists of the following tables:

    parties

    The set of all defined parties: any person, user, or group must have a corresponding row in this table.

    persons

    The set of all defined persons. To allow easy sorting of persons, the name requirement 30.10 is met by splitting the person's name into two columns: first_names and last_name.

    users

    The set of all registered users; this table includes information about the user's email address and the user's visits to the site.

    user_preferences

    Preferences for the user.

    groups

    The set of all defined groups.

    group_types

    When a new type of group is created, this table holds additional knowledge level attributes for the group and its subtypes.

    membership_rels

    The set of direct membership relationships between a group and a party.

    group_member_index

    A mapping of a party P to the groups {Gi}the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table.

    composition_rels

    The set of direct component relationships between a group and another group.

    group_component_index

    A mapping of a group Gto the set of groups {Gi} that G is a component of; this mapping includes the type of relationship by including the appropriaterel_id from the composition_rels table.

    New groups are created through the group.new constructor. When a specialized type of group is required, the group type can be extended by an application developer. Membership constraints can be specified at creation time by passing a parent group to the constructor.

    The membership_rels and composition_rels tables indicate a group's direct members and direct components; these tables do not provide a record of the members or components that are in the group by virtue of being a member or component of one of the group's component groups. Site pages will query group membership often, but the network of component groups can become a very complex directed acyclic graph and traversing this graph for every query will quickly degrade performance. To make membership queries responsive, the data model includes triggers (described in the next paragraph) which watch for changes in membership or composition and update tables that maintain the group party mappings, i.e., group_member_index and group_component_index. One can think of these tables as a manually maintained index.

    The following triggers keep the group_*_index tables up to date:

    membership_rels_in_tr

    Is executed when a new group/member relationship is created (an insert on membership_rels)

    membership_rels_del_tr

    Is executed when a group/member relationship is deleted (a delete on membership_rels)

    composition_rels_in_tr

    Is executed when a new group/component relationship is created (an insert on composition_rels)

    composition_rels_del_tr

    Is executed when a group/component relationship is deleted (a delete on composition_rels)

    The data model provides the following views onto the group_member_index and group_component_index tables. No code outside of Groups System should modify the group_*_index tables.

    group_member_map

    A mapping of a party to the groups the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table.

    group_approved_member_map

    A mapping of a party to the groups the party is an approved member of (member_state is 'approved'); this mapping includes the type of relationship by including the appropriaterel_id from the membership_rels table.

    group_distinct_member_map

    A person may appear in the group member map multiple times, for example, by being a member of two different groups that are both components of a third group. This view is strictly a mapping of approved members to groups.

    group_component_map

    A mapping of a group Gto the set of groups {Gi} group G is a component of; this mapping includes the type of relationship by including the appropriaterel_id from the composition_rels table.

    party_member_map

    A mapping of a party P to the set of parties {Pi} party P is a member of.

    party_approved_member_map

    A mapping of a party P to the set of parties {Pi} party P is an approved member of.

    API

    The API consists of tables and views and PL/SQL functions.

    Tables and Views

    The group_types table is used to create new types of groups.

    The group_member_map, group_approved_member_map, group_distinct_member_map, group_component_map, party_member_map, and party_approved_member_map views are used to query group membership and composition.

    PL/SQL API

    Person

    person.new creates a new person and returns the person_id. The function must be given the full name of the person in two pieces: first_names and last_name. All other fields are optional and default to null except for object_type which defaults to person and creation_date which defaults to sysdate. The interface for this function is:

    function person.new (
      person_id          persons.person_id%TYPE,
      object_type        acs_objects.object_type%TYPE,
      creation_date      acs_objects.creation_date%TYPE,
      creation_user      acs_objects.creation_user%TYPE,
      creation_ip        acs_objects.creation_ip%TYPE,
      email              parties.email%TYPE,
      url                parties.url%TYPE,
      first_names        persons.first_names%TYPE,
      last_name          persons.last_name%TYPE
    ) return persons.person_id%TYPE;
    

    person.delete deletes the person whose person_id is passed to it. The interface for this procedure is:

    procedure person.delete (
      person_id     persons.person_id%TYPE
    );
    

    person.name returns the name of the person whose person_id is passed to it. The interface for this function is:

    function person.name (
      person_id     persons.person_id%TYPE
    ) return varchar;
    

    User

    acs_user.new creates a new user and returns the user_id. The function must be given the user's email address and the full name of the user in two pieces: first_names and last_name. All other fields are optional. The interface for this function is:

    function acs_user.new (
      user_id            users.user_id%TYPE,
      object_type        acs_objects.object_type%TYPE,
      creation_date      acs_objects.creation_date%TYPE,
      creation_user      acs_objects.creation_user%TYPE,
      creation_ip        acs_objects.creation_ip%TYPE,
      email              parties.email%TYPE,
      url                parties.url%TYPE,
      first_names        persons.first_names%TYPE,
      last_name          persons.last_name%TYPE
      password           users.password%TYPE,
      salt               users.salt%TYPE,
      password_question  users.password_question%TYPE,
      password_answer    users.password_answer%TYPE,
      screen_name        users.screen_name%TYPE,
      email_verified_p   users.email_verified_p%TYPE
    ) return users.user_id%TYPE;
    

    acs_user.delete deletes the user whose user_id is passed to it. The interface for this procedure is:

    procedure acs_user.delete (
      user_id       users.user_id%TYPE
    );
    

    acs_user.receives_alerts_p returns 't' if the user should receive email alerts and 'f' otherwise. The interface for this function is:

    function acs_user.receives_alerts_p (
      user_id       users.user_id%TYPE
    ) return varchar;
    

    Use the procedures acs_user.approve_email and acs_user.unapprove_email to specify whether the user's email address is valid. The interface for these procedures are:

    procedure acs_user.approve_email (
      user_id       users.user_id%TYPE
    );
    
    procedure acs_user.unapprove_email (
      user_id       users.user_id%TYPE
    );
    

    Group

    acs_group.new creates a new group and returns the group_id. All fields are optional and default to null except for object_type which defaults to 'group', creation_date which defaults to sysdate, and group_name which is required. The interface for this function is:

    function acs_group.new (
      group_id           groups.group_id%TYPE,
      object_type        acs_objects.object_type%TYPE,
      creation_date      acs_objects.creation_date%TYPE,
      creation_user      acs_objects.creation_user%TYPE,
      creation_ip        acs_objects.creation_ip%TYPE,
      email              parties.email%TYPE,
      url                parties.url%TYPE,
      group_name         groups.group_name%TYPE
    ) return groups.group_id%TYPE;
    

    acs_group.name returns the name of the group whose group_id is passed to it. The interface for this function is:

    function acs_group.name (
      group_id      groups.group_id%TYPE
    ) return varchar;
    

    acs_group.member_p returns 't' if the specified party is a member of the specified group. Returns 'f' otherwise. The interface for this function is:

    function acs_group.member_p (
      group_id      groups.group_id%TYPE,
      party_id      parties.party_id%TYPE,
    ) return char;
    

    Membership Relationship

    membership_rel.new creates a new membership relationship type between two parties and returns the relationship type's rel_id. All fields are optional and default to null except for rel_type which defaults to membership_rel. The interface for this function is:

    function membership_rel.new (
      rel_id             membership_rels.rel_id%TYPE,
      rel_type           acs_rels.rel_type%TYPE,
      object_id_one      acs_rels.object_id_one%TYPE,
      object_id_two      acs_rels.object_id_two%TYPE,
      member_state       membership_rels.member_state%TYPE,
      creation_user      acs_objects.creation_user%TYPE,
      creation_ip        acs_objects.creation_ip%TYPE,
    ) return membership_rels.rel_id%TYPE;
    

    membership_rel.ban sets the member_state of the given rel_id to 'banned'. The interface for this procedure is:

    procedure membership_rel.ban (
      rel_id           membership_rels.rel_id%TYPE
    );
    

    membership_rel.approve sets the member_state of the given rel_id to 'approved'. The interface for this procedure is:

    procedure membership_rel.approve (
      rel_id           membership_rels.rel_id%TYPE
    );
    

    membership_rel.reject sets the member_state of the given rel_id to 'rejected. The interface for this procedure is:

    procedure membership_rel.reject (
      rel_id           membership_rels.rel_id%TYPE
    );
    

    membership_rel.unapprove sets the member_state of the given rel_id to an empty string ''. The interface for this procedure is:

    procedure membership_rel.unapprove (
      rel_id           membership_rels.rel_id%TYPE
    );
    

    membership_rel.deleted sets the member_state of the given rel_id to 'deleted'. The interface for this procedure is:

    procedure membership_rel.deleted (
      rel_id           membership_rels.rel_id%TYPE
    );
    

    membership_rel.delete deletes the given rel_id. The interface for this procedure is:

    procedure membership_rel.delete (
      rel_id           membership_rels.rel_id%TYPE
    );
    

    Composition Relationship

    composition_rel.new creates a new composition relationship type and returns the relationship's rel_id. All fields are optional and default to null except for rel_type which defaults to composition_rel. The interface for this function is:

    function membership_rel.new (
      rel_id             composition_rels.rel_id%TYPE,
      rel_type           acs_rels.rel_type%TYPE,
      object_id_one      acs_rels.object_id_one%TYPE,
      object_id_two      acs_rels.object_id_two%TYPE,
      creation_user      acs_objects.creation_user%TYPE,
      creation_ip        acs_objects.creation_ip%TYPE,
    ) return composition_rels.rel_id%TYPE;
    

    composition_rel.delete deletes the given rel_id. The interface for this procedure is:

    procedure membership_rel.delete (
      rel_id           composition_rels.rel_id%TYPE
    );
    

    User Interface

    Describe the admin pages.

    Configuration/Parameters

    ...

    Acceptance Tests

    ...

    Future Improvements/Areas of Likely Change

    ...

    Authors

    System creator

    Rafael H. Schloming

    System owner

    Rafael H. Schloming

    Documentation author

    Mark Thomas

    Revision History

    Document Revision #Action Taken, NotesWhen?By Whom?
    0.1Creation08/22/2000Rafael H. Schloming
    0.2Initial Revision08/30/2000 Mark Thomas
    0.3Additional revisions; tried to clarify membership/compostion09/08/2000 Mark Thomas
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/acs-package-dev.html0000644000175000017500000002027711501005377023627 0ustar frankiefrankie Part III. For OpenACS Package Developers

    Part III. For OpenACS Package Developers

    Tutorials and reference material for creating new OpenACS packages.

    Table of Contents

    8. Development Tutorial
    Creating an Application Package
    Setting Up Database Objects
    Creating Web Pages
    Debugging and Automated Testing
    9. Advanced Topics
    Write the Requirements and Design Specs
    Add the new package to CVS
    OpenACS Edit This Page Templates
    Adding Comments
    Admin Pages
    Categories
    Profile your code
    Prepare the package for distribution.
    Distributing upgrades of your package
    Notifications
    Hierarchical data
    Using .vuh files for pretty urls
    Laying out a page with CSS instead of tables
    Sending HTML email from your application
    Basic Caching
    Scheduled Procedures
    Enabling WYSIWYG
    Adding in parameters for your package
    Writing upgrade scripts
    Connect to a second database
    Future Topics
    10. Development Reference
    OpenACS Packages
    OpenACS Data Models and the Object System
    The Request Processor
    The OpenACS Database Access API
    Using Templates in OpenACS
    Groups, Context, Permissions
    Writing OpenACS Application Pages
    Parties in OpenACS
    Object Identity
    Programming with AOLserver
    Using Form Builder: building html forms dynamically
    11. Engineering Standards
    OpenACS Style Guide
    CVS Guidelines
    Release Version Numbering
    Constraint naming standard
    ACS File Naming and Formatting Standards
    PL/SQL Standards
    Variables
    Automated Testing
    12. Documentation Standards
    OpenACS Documentation Guide
    Using PSGML mode in Emacs
    Using nXML mode in Emacs
    System/Application Requirements Template
    13. Internationalization
    Internationalization and Localization Overview
    How Internationalization/Localization works in OpenACS
    How to Internationalize a Package
    Design Notes
    Translator's Guide
    D. Using CVS with an OpenACS Site
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/uptime.html0000644000175000017500000000515011501005400022173 0ustar frankiefrankie External uptime validation

    External uptime validation

    The OpenACS uptime site can monitor your site and send you an email whenever your site fails to respond. If you test the url http://yourserver.test/SYSTEM/dbtest.tcl, you should get back the string success.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/backup-recovery.html0000644000175000017500000000726011456662477024035 0ustar frankiefrankie Chapter 8. Backup and Recovery

    Chapter 8. Backup and Recovery

    ($Id: backup-recovery.html,v 1.41 2010/10/17 21:06:07 donb Exp $)

    By Don Baccus with additions by Joel Aufrecht

    We will cover some basic backup and recovery strategies. These are intended to be robust but simple enough to set up. For a large scale production site you would probably need to create your own backup strategies (in particular full dumps from oracle, while easy to set up, are far from the best solution).

    There are three basic things which need to be backed up, the database data, the server source tree, and the acs-content-repository (which is in the server source tree).

    Figure 8.1. Backup and Recovery Strategy

    Backup and Recovery Strategy

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-upgrade-scripts.html0000644000175000017500000000702611501005400025651 0ustar frankiefrankie Writing upgrade scripts

    Writing upgrade scripts

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    If your package changes its data model, you have to write an upgrade script. This is very easy in OpenACS.

    First, you want to make sure you change the original .sql file so that new installation will have the new data model.

    Next, check what version your package is currently at. For example, it may be at version 1.0b1. Create a file in sql/postgres/upgrade called packagename-1.0b1-1.0b2.sql and put the SQL code that will update the data model. For example, if you add in a column, you would have an alter table add column statement in this file. Test this out very well, because data model changes are more serious and fundamental changes than the program .tcl files.

    Now use the APM to create a new package version 1.0b2. Commit all your changes, tag the release (Distributing upgrades of your package), and both new installations and upgrades will be taken care of.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/db-api-detailed.html0000644000175000017500000014002311501005400023574 0ustar frankiefrankie Database Access API

    Database Access API

    By Jon Salz. Revised and expanded by Roberto Mello (rmello at fslc dot usu dot edu), July 2002.

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    • Tcl procedures: /packages/acs-kernel/10-database-procs.tcl

    • Tcl initialization: /packages/acs-kernel/database-init.tcl

    The Big Picture

    One of OpenACS's great strengths is that code written for it is very close to the database. It is very easy to interact with the database from anywhere within OpenACS. Our goal is to develop a coherent API for database access which makes this even easier.

    There were four significant problems with the way OpenACS previously used the database (i.e., directly through the ns_db interface):

    1. Handle management. We required code to pass database handles around, and for routines which needed to perform database access but didn't receive a database handle as input, it was difficult to know from which of the three "magic pools" (main, subquery, and log) to allocate a new handle.

    2. Nested transactions. In our Oracle driver, begin transaction really means "turn auto-commit mode off" and end transaction means "commit the current transaction and turn auto-commit mode on." Thus if transactional code needed to call a routine which needed to operate transactionally, the semantics were non-obvious. Consider:

      
      proc foo { db args } {
          db_transaction {
            ...
          }
      }
      
      db_transaction {
      db_dml unused "insert into greeble(bork) values(33)"
      foo $db
      db_dml unused "insert into greeble(bork) values(50)"
      }
      
      

      This would insert greeble #33 and do all the stuff in foo transactionally, but the end transaction in foo would actually cause a commit, and greeble #50 would later be inserted in auto-commit mode. This could cause subtle bugs: e.g., in the case that the insert for greeble #50 failed, part of the "transaction" would have already have been committed!. This is not a good thing.

    3. Unorthodox use of variables. The standard mechanism for mapping column values into variables involved the use of the set_variables_after_query routine, which relies on an uplevel variable named selection (likewise for set_variables_after_subquery and subselection).

    4. Hard-coded reliance on Oracle. It's difficult to write code supporting various different databases (dynamically using the appropriate dialect based on the type of database being used, e.g., using DECODE on Oracle and CASE ... WHEN on Postgres).

    The Database Access API addresses the first three problems by:

    1. making use of database handles transparent

    2. wrapping common database operations (including transaction management) in Tcl control structures (this is, after all, what Tcl is good at!)

    It lays the groundwork for addressing the fourth problem by assigning each SQL statement a logical name. In a future version of the OpenACS Core, this API will translate logical statement names into actual SQL, based on the type of database in use. (To smooth the learning curve, we provide a facility for writing SQL inline for a "default SQL dialect", which we assume to be Oracle for now.)

    To be clear, SQL abstraction is not fully implemented in OpenACS 3.3.1. The statement names supplied to each call are not used by the API at all. The API's design for SQL abstraction is in fact incomplete; unresolved issues include:

    • how to add WHERE clause criteria dynamically

    • how to build a dynamic ORDER BY clause (Ben Adida has a proposed solution for this)

    • how to define a statement's formal interface (i.e., what bind variables it expects, what columns its SELECT clause must contain if it's a query) without actually implementing the statement in a specific SQL dialect

    So why is the incremental change of adding statement naming to the API worth the effort? It is worth the effort because we know that giving each SQL statement a logical name will be required by the complete SQL abstraction design. Therefore, we know that the effort will not be wasted, and taking advantage of the new support for bind variables will already require code that uses 3.3.0 version of the API to be updated.

    The Bell Tolls for set_variables_after_query

    set_variables_after_query is gone! (Well, it's still there, but you'll never need to use it.) The new API routines set local variables automatically. For instance:

    
    db_1row select_names "select first_names, last_name from users where user_id = [ad_get_user_id]"
    doc_body_append "Hello, $first_names $last_name!"
    
    

    Like ns_db 1row, this will bomb if the query doesn't return any rows (no such user exists). If this isn't what you want, you can write:

    
    if { [db_0or1row select_names "select first_names, last_name from users where user_id = [ad_get_user_id]"] } {
        doc_body_append "Hello, $first_names $last_name!"
    } else {
        # Executed if the query returns no rows.
        doc_body_append "There's no such user!"
    }
    
    

    Selecting a bunch of rows is a lot prettier now:

    
    db_foreach select_names "select first_names, last_name from users" {
         doc_body_append "Say hi to $first_names $last_name for me!<br>"
    }
    
    

    That's right, db_foreach is now like ns_db select plus a while loop plus set_variables_after_query plus an if statement (containing code to be executed if no rows are returned).

    
    db_foreach select_names "select first_names, last_name from users where last_name like 'S%'" {
         doc_body_append "Say hi to $first_names $last_name for me!<br>"
    } if_no_rows {
         doc_body_append "There aren't any users with last names beginnings with S!"
    }
    
    

    Handle Management

    The new API keeps track of which handles are in use, and automatically allocates new handles when they are necessary (e.g., to perform subqueries while a select is active). For example:

    
    doc_body_append "<ul>"
    db_foreach select_names "select first_names, last_name, user_id from users" {
        # Automatically allocated a database handle from the main pool.
        doc_body_append "<li>User $first_names $last_name\n<ul>"
    
        db_foreach select_groups "select group_id from user_group_map where user_id = $user_id" {
            # There's a selection in progress, so we allocated a database handle
            # from the subquery pool for this selection.
            doc_body_append "<li>Member of group #$group_id.\n"
        } if_no_rows {
            # Not a member of any groups.
            doc_body_append "<li>Not a member of any group.\n"
        }
    }
    doc_body_append "</ul>"
    db_release_unused_handles
    
    

    A new handle isn't actually allocated and released for every selection, of course - as a performance optimization, the API keeps old handles around until db_release_unused_handles is invoked (or the script terminates).

    Note that there is no analogue to ns_db gethandle - the handle is always automatically allocated the first time it's needed.

    Bind Variables

    Introduction

    Most SQL statements require that the code invoking the statement pass along data associated with that statement, usually obtained from the user. For instance, in order to delete a WimpyPoint presentation, a Tcl script might use the SQL statement

    
    delete from wp_presentations where presentation_id = some_presentation_id
    
    

    where some_presentation_id is a number which is a valid presentation ID of the presentation I want to delete. It's easy to write code handling situations like this since SQL statements can include bind variables, which represent placeholders for actual data. A bind variable is specified as a colon followed by an identifier, so the statement above can be coded as:

    
    db_dml presentation_delete {
        delete from wp_presentations where presentation_id = :some_presentation_id
    }
    
    

    When this SQL statement is invoked, the value for the bind variable :some_presentation_id is pulled from the Tcl variable $some_presentation_id (in the caller's environment). Note that bind variables are not limited to one per statement; you can use an arbitrary number, and each will pull from the correspondingly named Tcl variable. (Alternatively, you can also specify an list or ns_set providing bind variables' values; see Usage.)

    The value of a bind variable is taken literally by the database driver, so there is never any need to put single-quotes around the value for a bind variable, or to use db_quote to escape single-quotes contained in the value. The following works fine, despite the apostrophe:

    
    set exclamation "That's all, folks!"
    db_dml exclamation_insert { insert into exclamations(exclamation) values(:exclamation) }
    
    

    Note that you can use a bind variable in a SQL statement only where you could use a literal (a number or single-quoted string). Bind variables cannot be placeholders for things like SQL keywords, table names, or column names, so the following will not work, even if $table_name is set properly:

    
    select * from :table_name
    
    

    Why Bind Variables Are Useful

    Why bother with bind variables at all - why not just write the Tcl statement above like this:

    
    db_dml presentation_delete "
        delete from wp_presentations where presentation_id = $some_presentation_id
    "
    
    

    (Note the use of double-quotes to allow the variable reference to $some_presentation_id to be interpolated in.) This will work, but consider the case where some devious user causes some_presentation_id to be set to something like '3 or 1 = 1', which would result in the following statement being executed:

    
    delete from wp_presentations where presentation_id = 3 or 1 = 1
    
    

    This deletes every presentation in the database! Using bind variables eliminates this gaping security hole: since bind variable values are taken literally. Oracle will attempt to delete presentations whose presentation ID is literally '3 or 1 = 1' (i.e., no presentations, since '3 or 1 = 1' can't possibly be a valid integer primary key for wp_presentations. In general, since Oracle always considers the values of bind variables to be literals, it becomes more difficult for users to perform URL surgery to trick scripts into running dangerous queries and DML.

    Usage

    Every db_* command accepting a SQL command as an argument supports bind variables. You can either

    • specify the -bind switch to provide a set with bind variable values, or

    • specify the -bind switch to explicitly provide a list of bind variable names and values, or

    • not specify a bind variable list at all, in which case Tcl variables are used as bind variables.

    The default behavior (i.e., if the -bind switch is omitted) is that these procedures expect to find local variables that correspond in name to the referenced bind variables, e.g.:

    
    set user_id 123456
    set role "administrator"
    
    db_foreach user_group_memberships_by_role {
        select g.group_id, g.group_name
        from user_groups g, user_group_map map
        where g.group_id = map.user_id
        and map.user_id = :user_id
        and map.role = :role
    } {
        # do something for each group of which user 123456 is in the role
        # of "administrator"
    }
    
    

    The value of the local Tcl variable user_id (123456) is bound to the user_id bind variable.

    The -bind switch can takes the name of an ns_set containing keys for each bind variable named in the query, e.g.:

    
    set bind_vars [ns_set create]
    ns_set put $bind_vars user_id 123456
    ns_set put $bind_vars role "administrator"
    
    db_foreach user_group_memberships_by_role {
        select g.group_id, g.group_name
        from user_groups g, user_group_map map
        where g.group_id = map.user_id
        and map.user_id = :user_id
        and map.role = :role
    } -bind $bind_vars {
        # do something for each group in which user 123456 has the role
        # of "administrator"
    }
    
    

    Alternatively, as an argument to -bind you can specify a list of alternating name/value pairs for bind variables:

    
    db_foreach user_group_memberships_by_role {
        select g.group_id, g.group_name
        from user_groups g, user_group_map map
        where g.group_id = map.user_id
        and map.user_id = :user_id
        and map.role = :role
    } -bind [list user_id 123456 role "administrator"] {
        # do something for each group in which user 123456 has the role
        # of "administrator"
    }
    
    

    Nulls and Bind Variables

    When processing a DML statement, Oracle coerces empty strings into null. (This coercion does not occur in the WHERE clause of a query, i.e. col = '' and col is null are not equivalent.)

    As a result, when using bind variables, the only way to make Oracle set a column value to null is to set the corresponding bind variable to the empty string, since a bind variable whose value is the string "null" will be interpreted as the literal string "null".

    These Oracle quirks complicate the process of writing clear and abstract DML difficult. Here is an example that illustrates why:

    
    #
    # Given the table:
    #
    #   create table foo (
    #           bar        integer,
    #           baz        varchar(10)
    #   );
    #
    
    set bar ""
    set baz ""
    
    db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)"
    #
    # the values of the "bar" and "baz" columns in the new row are both
    # null, because Oracle has coerced the empty string (even for the
    # numeric column "bar") into null in both cases
    
    

    Since databases other than Oracle do not coerce empty strings into null, this code has different semantics depending on the underlying database (i.e., the row that gets inserted may not have null as its column values), which defeats the purpose of SQL abstraction.

    Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the empty string): db_null.

    Use it instead of the empty string whenever you want to set a column value explicitly to null, e.g.:

    
    set bar [db_null]
    set baz [db_null]
    
    db_dml foo_create "insert into foo(bar, baz) values(:bar, :baz)"
    #
    # sets the values for both the "bar" and "baz" columns to null
    
    

    SQL Abstraction

    We now require that each SQL statement be assigned a logical name for the statement that is unique to the procedure or page in which it is defined. This is so that (eventually) we can implement logically named statements with alternative SQL for non-Oracle databases (e.g., Postgres). More on this later.

    Placing Column Values in Arrays and Sets

    Normally, db_foreach, db_0or1row, and db_1row places the results of queries in Tcl variables, so you can say:

    
    db_foreach users_select "select first_names, last_name from users" {
        doc_body_append "<li>$first_names $last_name\n"
    }
    
    

    However, sometimes this is not sufficient: you may need to examine the rows returned, to dynamically determine the set of columns returned by the query, or to avoid collisions with existing variables. You can use the -column_array and -column_set switches to db_foreach, db_0or1row, and db_1row to instruct the database routines to place the results in a Tcl array or ns_set, respectively, where the keys are the column names and the values are the column values. For example:

    
    db_foreach users_select "select first_names, last_name from users" -column_set columns {
        # Now $columns is an ns_set.
        doc_body_append "<li>"
        for { set i 0 } { $i < [ns_set size $columns] } { incr i } {
            doc_body_append "[ns_set key $columns $i] is [ns_set value $columns $i]. \n"
        }
    }
    
    

    will write something like:

    • first_names is Jon. last_name is Salz.

    • first_names is Lars. last_name is Pind.

    • first_names is Michael. last_name is Yoon.

    API

    Note that you never have to use ns_db anymore (including ns_db gethandle)! Just start doing stuff, and (if you want) call db_release_unused_handles when you're done as a hint to release the database handle.

    db_null
    db_null
    

    Returns a value which can be used in a bind variable to represent the SQL value null. See Nulls and Bind Variables above.

    db_foreach
    db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \
        [ -column_array array_name | -column_set set_name ] \
        code_block [ if_no_rows if_no_rows_block ]
    

    Performs the SQL query sql, executing code_block once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes if_no_rows_block (if provided).

    Example:

    
    db_foreach select_foo "select foo, bar from greeble" {
        doc_body_append "<li>foo=$foo; bar=$bar\n"
    } if_no_rows {
        doc_body_append "<li>There are no greebles in the database.\n"
    }
    
    

    The code block may contain break statements (which terminate the loop and flush the database handle) and continue statements (which continue to the next row of the loop).

    db_1row
    db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \
        [ -column_array array_name | -column_set set_name ]
    

    Performs the SQL query sql, setting variables to column values. Raises an error if the query does not return exactly 1 row.

    Example:

    
    db_1row select_foo "select foo, bar from greeble where greeble_id = $greeble_id"
    # Bombs if there's no such greeble!
    # Now $foo and $bar are set.
    
    
    db_0or1row
    db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \
        [ -column_array array_name | -column_set set_name ]
    

    Performs the SQL query sql. If a row is returned, sets variables to column values and returns 1. If no rows are returned, returns 0. If more than one row is returned, throws an error.

    db_string
    db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ]
    

    Returns the first column of the result of SQL query sql. If sql doesn't return a row, returns default (or throws an error if default is unspecified). Analogous to database_to_tcl_string and database_to_tcl_string_or_null.

    db_nextval
    db_nextval sequence-name
    

    Returns the next value for the sequence sequence-name (using a SQL statement like SELECT sequence-name.nextval FROM DUAL). If sequence pooling is enabled for the sequence, transparently uses a value from the pool if available to save a round-trip to the database.

    db_list
    db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    

    Returns a Tcl list of the values in the first column of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. Analogous to database_to_tcl_list.

    db_list_of_lists
    db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    

    Returns a Tcl list, each element of which is a list of all column values in a row of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. (Analogous to database_to_tcl_list_list.)

    db_list_of_ns_sets
    db_list_of_ns_sets statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    

    Returns a list of ns_sets with the values of each column of each row returned by the sql query specified.

    db_dml
    db_dml statement-name sql \
        [ -bind bind_set_id | -bind bind_value_list ] \
        [ -blobs blob_list | -clobs clob_list |
          -blob_files blob_file_list | -clob_files clob_file_list ]
    

    Performs the DML or DDL statement sql.

    If a length-n list of blobs or clobs is provided, then the SQL should return n blobs or clobs into the bind variables :1, :2, ... :n. blobs or clobs, if specified, should be a list of individual BLOBs or CLOBs to insert; blob_files or clob_files, if specified, should be a list of paths to files containing the data to insert. Only one of -blobs, -clobs, -blob_files, and -clob_files may be provided.

    Example:

    
    db_dml insert_photos "
            insert photos(photo_id, image, thumbnail_image)
            values(photo_id_seq.nextval, empty_blob(), empty_blob())
            returning image, thumbnail_image into :1, :2
        "  -blob_files [list "/var/tmp/the_photo" "/var/tmp/the_thumbnail"] 
    
    

    This inserts a new row into the photos table, with the contents of the files /var/tmp/the_photo and /var/tmp/the_thumbnail in the image and thumbnail columns, respectively.

    db_write_clob, db_write_blob, db_blob_get_file
    db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    
    db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    
    db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ]
    

    Analagous to ns_ora write_clob/write_blob/blob_get_file.

    db_release_unused_handles
    db_release_unused_handles
    

    Releases any allocated, unused database handles.

    db_transaction
    db_transaction code_block [ on_error { code_block } ]
    

    Executes code_block transactionally. Nested transactions are supported (end transaction is transparently ns_db dml'ed when the outermost transaction completes). The db_abort_transaction command can be used to abort all levels of transactions. It is possible to specify an optional on_error code block that will be executed if some code in code_block throws an exception. The variable errmsg will be bound in that scope. If there is no on_error code, any errors will be propagated.

    Example:

    
    proc replace_the_foo { col } {
        db_transaction {
            db_dml "delete from foo"
            db_dml "insert into foo(col) values($col)"
        }
    }
    
    proc print_the_foo {} {
        doc_body_append "foo is [db_string "select col from foo"]<br>\n"
    }
    
    replace_the_foo 8
    print_the_foo ; # Writes out "foo is 8"
    
    db_transaction {
        replace_the_foo 14
        print_the_foo ; # Writes out "foo is 14"
        db_dml "insert into some_other_table(col) values(999)"
        ...
        db_abort_transaction
    } on_error {
        doc_body_append "Error in transaction: $errmsg"
    }
        
    
    print_the_foo ; # Writes out "foo is 8"
    
    
    db_abort_transaction
    db_abort_transaction
    

    Aborts all levels of a transaction. That is if this is called within several nested transactions, all of them are terminated. Use this insetead of db_dml "abort" "abort transaction".

    db_multirow
    db_multirow [ -local ] [ -append ] [ -extend column_list ] \
        var-name statement-name sql \
        [ -bind bind_set_id | -bind bind_value_list ] \
        code_block [ if_no_rows if_no_rows_block ]
    

    Performs the SQL query sql, saving results in variables of the form var_name:1, var_name:2, etc, setting var_name:rowcount to the total number of rows, and setting var_name:columns to a list of column names.

    Each row also has a column, rownum, automatically added and set to the row number, starting with 1. Note that this will override any column in the SQL statement named 'rownum', also if you're using the Oracle rownum pseudo-column.

    If the -local is passed, the variables defined by db_multirow will be set locally (useful if you're compiling dynamic templates in a function or similar situations).

    You may supply a code block, which will be executed for each row in the loop. This is very useful if you need to make computations that are better done in Tcl than in SQL, for example using ns_urlencode or ad_quotehtml, etc. When the Tcl code is executed, all the columns from the SQL query will be set as local variables in that code. Any changes made to these local variables will be copied back into the multirow.

    You may also add additional, computed columns to the multirow, using the -extend { col_1 col_2 ... } switch. This is useful for things like constructing a URL for the object retrieved by the query.

    If you're constructing your multirow through multiple queries with the same set of columns, but with different rows, you can use the -append switch. This causes the rows returned by this query to be appended to the rows already in the multirow, instead of starting a clean multirow, as is the normal behavior. The columns must match the columns in the original multirow, or an error will be thrown.

    Your code block may call continue in order to skip a row and not include it in the multirow. Or you can call break to skip this row and quit looping.

    Notice the nonstandard numbering (everything else in Tcl starts at 0); the reason is that the graphics designer, a non programmer, may wish to work with row numbers.

    Example:

    db_multirow -extend { user_url } users users_query {
        select user_id first_names, last_name, email from cc_users
    } {
        set user_url [acs_community_member_url -user_id $user_id]
    }
        
    db_resultrows
    db_resultrows
    

    Returns the number of rows affected or returned by the previous statement.

    db_with_handle
    db_with_handle var code_block
    

    Places a database handle into the variable var and executes code_block. This is useful when you don't want to have to use the new API (db_foreach, db_1row, etc.), but need to use database handles explicitly.

    Example:

    
    proc lookup_the_foo { foo } {
        db_with_handle db {
            return [db_string unused "select ..."]
        }
    }
    
    db_with_handle db {
        # Now there's a database handle in $db.
        set selection [ns_db select $db "select foo from bar"]
        while { [ns_db getrow $db $selection] } {
            set_variables_after_query
    
            lookup_the_foo $foo
        }
    }
    
    
    db_name
    			
    				db_name
    			
    		

    Returns the name of the database, as returned by the driver.

    db_type
    			
    				db_type
    			
    		

    Returns the RDBMS type (i.e. oracle, postgresql) this OpenACS installation is using. The nsv ad_database_type is set up during the bootstrap process.

    db_compatible_rdbms_p
    			db_compatible_rdbms_p db_type
    		

    Returns 1 if the given db_type is compatible with the current RDBMS.

    db_package_supports_rdbms_p
    			db_package_supports_rdbms_p db_type_list
    		

    Returns 1 if db_type_list contains the current RDMBS type. A package intended to run with a given RDBMS must note this in it's package info file regardless of whether or not it actually uses the database.

    db_legacy_package_p
    			db_legacy_package_p db_type_list
    		

    Returns 1 if the package is a legacy package. We can only tell for certain if it explicitly supports Oracle 8.1.6 rather than the OpenACS more general oracle.

    db_version
    			db_version
    		

    Returns the RDBMS version (i.e. 8.1.6 is a recent Oracle version; 7.1 a recent PostgreSQL version.

    db_current_rdbms
    			db_current_rdbms
    		

    Returns the current rdbms type and version.

    db_known_database_types
    			db_known_database_types
    		

    Returns a list of three-element lists describing the database engines known to OpenACS. Each sublist contains the internal database name (used in file paths, etc), the driver name, and a "pretty name" to be used in selection forms displayed to the user.

    The nsv containing the list is initialized by the bootstrap script and should never be referenced directly by user code. Returns the current rdbms type and version.

    ($Id: db-api-detailed.html,v 1.46 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/mac-installation.html0000644000175000017500000000733711501005400024140 0ustar frankiefrankie OpenACS Installation Guide for Mac OS X

    OpenACS Installation Guide for Mac OS X

    Prerequisites. Install readline:

    1. Download readline from http://ftp.gnu.org/pub/gnu/readline/readline-4.3.tar.gz into /usr/local/src

    2. Extract readline in /usr/local/src, configure, compile, and install:

      su - root
      cd /usr/local/src
      tar xvfz readline-4.3.tar.gz
      readline-4.3
      ./configure
      make
      make install
    3. Proceed with the Unix-like system instructions. OS X is incompatible with Oracle 8, and Oracle 9i on OSX is not yet verified for OpenACS. So continue with Install PostgreSQL. Additional special steps for OS X are documented inline with the standard Unix-like instructions.

    Additional resources for installing on OS X.

    ($Id: mac-installation.html,v 1.40 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-next-backups.html0000644000175000017500000001016511456662500024765 0ustar frankiefrankie Backup Strategy

    Backup Strategy

    The purpose of backup is to enable recovery. Backup and recovery are always risky; here are some steps that minimize the chance recovery is necessary:

    • Store everything on a fault-tolerant disk array (RAID 1 or 5 or better).

    • Use battery backup.

    • Use more reliable hardware, such as SCSI instead of IDE.

    These steps improve the chances of successful recovery:

    • Store backups on a third disk on another controller

    • Store backups on a different computer on a different network in a different physical location. (Compared to off-line backup such as tapes and CDRs, on-line backup is faster and more likely to succeed, but requires maintenance of another machine.)

    • Plan and configure for recovery from the beginning.

    • Test your recovery strategy from time to time.

    • Make it easy to maintain and test your recovery strategy, so that you are more likely to do it.

    OpenACS installations comprise files and database contents. If you follow the reference install and put all files, including configuration files, in /var/lib/aolserver/$OPENACS_SERVICE_NAME/, and back up the database nightly to a file in /var/lib/aolserver/$OPENACS_SERVICE_NAME/database-backup, then you can apply standard file-based backup strategies to /var/lib/aolserver/$OPENACS_SERVICE_NAME

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/update-repository.html0000644000175000017500000001077111501005400024374 0ustar frankiefrankie How to Update the OpenACS.org repository

    How to Update the OpenACS.org repository

    1. Setup a local OpenACS server running 5.0 or better.

    2. Edit packages/acs-admin/www/apm/build-repository.tcl and adjust the Configuration Settings.

    3. Request /acs-admin/apm/build-repository on your new server.

      1. The page will find all branches in the cvs repository labeled oacs-x-y, and build a repository channel for each of those branches where x>=5 (so not for 4.6 and earlier). It will also build a channel for HEAD, which will be named after what you set in 'head_channel' above.

      2. For each channel, it'll do an anonymous checkout of packges and contrib/packages, then build .apm files for each package in the checkout.

      3. The files will be stored on the server's hard drive in the directory specified by the 'repository_dir' variable in the page script, by default "[acs_root_dir]/www/repository/".

    4. If you're on openacs.org, everything should now be fine. Otherwise, you need to move the entire directory tree to openacs.org:/web/openacs/www/repository, replacing what was already there.

      This is automated on OpenACS.org by having a dedicated site just for building the repository, invoked with this shell script. Since the page circumvents security checks for ease of use, the entire site is limited to local requests. The script is called daily with a cron job.

      #!/bin/sh
      #set -x
      
      STATUS=`wget --output-document - http://127.0.0.1:8002/build-repository.tcl | grep DONE | wc -l`
      
      if [ $STATUS -eq "1" ]
      then
          rm -rf /web/openacs.org/www/repository.old
          mv /web/openacs.org/www/repository /web/openacs.org/www/repository.old
          cp -r /web/repository/www/repository /web/openacs.org/www/repository
      fi
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/analog-setup.html0000644000175000017500000001320411501005400023266 0ustar frankiefrankie Set up Log Analysis Reports

    Set up Log Analysis Reports

    Analog is a program with processes webserver access logs, performs DNS lookup, and outputs HTML reports. Analog should already be installed. A modified configuration file is included in the OpenACS tarball.

    1. [root src]# su - $OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ mkdir www/log
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cp -r /usr/share/analog-5.32/images www/log/
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ 
      su - $OPENACS_SERVICE_NAME
      cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
      cp /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/acs-core-docs/www/files/analog.cfg.txt etc/analog.cfg
      mkdir www/log
      cp -r /usr/share/analog-5.32/images www/log/

      Edit /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/analog.cfg and change the variable in HOSTNAME "[my organisation]" to reflect your website title. If you don't want the traffic log to be publicly visible, change OUTFILE /var/lib/aolserver/$OPENACS_SERVICE_NAME/www/log/traffic.html to use a private directory. You'll also need to edit all instances of service0 to your $OPENACS_SERVICE_NAME.

    2. Run it.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ /usr/share/analog-5.32/analog -G -g/var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/analog.cfg
      /usr/share/analog-5.32/analog: analog version 5.32/Unix
      /usr/share/analog-5.32/analog: Warning F: Failed to open DNS input file
        /home/$OPENACS_SERVICE_NAME/dnscache: ignoring it
        (For help on all errors and warnings, see docs/errors.html)
      /usr/share/analog-5.32/analog: Warning R: Turning off empty Search Word Report
      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$

      Verify that it works by browing to http://yourserver.test:8000/log/traffic.html

    3. Automate this by creating a file in /etc/cron.daily.

      [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
      logout
      
      [root root]# emacs /etc/cron.daily/analog

      Put this into the file:

      #!/bin/sh
      
      /usr/share/analog-5.32/analog -G -g/var/lib/aolserver/$OPENACS_SERVICE_NAME/etc/analog.cfg
      [root root]# chmod 755 /etc/cron.daily/analog

      Test it by running the script.

      [root root]# sh /etc/cron.daily/analog

      Browse to http://yourserver.test/log/traffic.html

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-overview.html0000644000175000017500000000516111501005400024204 0ustar frankiefrankie Chapter 2. Installation Overview

    Chapter 2. Installation Overview

    by Vinod Kurup

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-pam-radius.html0000644000175000017500000001667211501005400024411 0ustar frankiefrankie Install PAM Radius for use as external authentication

    Install PAM Radius for use as external authentication

    By Malte Sussdorff

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    This step by step guide is derived from the installation instructions which you can find at yourdomain.com/doc/acs-authentication/ext-auth-pam-install.html. It is build upon PAM 0.77 (tested) and does not work on RedHat Linux Enterprise 3 (using PAM 0.75). It makes use of the ns_pam module written by Mat Kovach. The instructions given in here do work with PAM LDAP accordingly and differences will be shown at the end of the file.

    1. Install ns_pam. Download and install ns_pam

      [root aolserver]# cd /usr/local/src/aolserver/
                [root aolserver]# wget http://braindamage.alal.com/software/ns_pam-0.1.tar.gz
                [root aolserver]# tar xvfz ns_pam-0.1.tar.gz
                [root aolserver]# cd ns_pam-0.1
                [root ns_pam-0.1]# make install INST=/usr/local/aolserver
                [root ns_pam-0.1]#
      cd /usr/local/src/aolserver/
      wget http://braindamage.alal.com/software/ns_pam-0.1.tar.gz
      tar xvfz ns_pam-0.1.tar.gz
      cd ns_pam-0.1
      make install INST=/usr/local/aolserver
      
                
    2. Configure ns_pam. Configure AOLserver for ns_pam

      To enable ns_pam in AOLServer you will first have to edit your config.tcl file and enable the loading of the ns_pam module and configure the aolservers pam configuration file.

      • Change config.tcl. Remove the # in front of ns_param nspam ${bindir}/nspam.so to enable the loading of the ns_pam module.

      • Change config.tcl. Replace pam_domain in the section ns/server/${server}/module/nspam with aolserver

      • Create /etc/pam.d/aolserver.

                      [root ns_pam]#cp /var/lib/aolserver/service0/packages/acs-core-docs/www/files/pam-aolserver.txt /etc/pam.d/aolserver
                    
    3. Configure PAM Radius. Configure and install PAM Radius

      You have to make sure that pam_radius v.1.3.16 or higher is installed, otherwise you will have to install it.

      [root ns_pam]# cd /usr/local/src/
                [root src]# wget ftp://ftp.freeradius.org/pub/radius/pam_radius-1.3.16.tar
                [root src]# tar xvf pam_radius-1.3.16
                [root src]# cd pam_radius
                [root pam_radius]# make
                [root pam_radius]# cp pam_radius_auth.so /lib/security/
                [root pam_radius]#
      cd /usr/local/src
      wget ftp://ftp.freeradius.org/pub/radius/pam_radius-1.3.16.tar
      tar xvf pam_radius-1.3.16
      cd pam_radius
      make
      cp pam_radius_auth.so /lib/security/
      
                

      Next you have to add the configuration lines to your Radius configuration file (/etc/rddb/server). For AOLserver to be able to access this information you have to change the access rights to this file as well.

      [root pam_radius]# echo "radius.yourdomain.com:1645 your_radius_password >>/etc/rddb/server
                [root src]# chown service0:web /etc/rddb/server
                
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/backups-with-cvs.html0000644000175000017500000001132711456662477024125 0ustar frankiefrankie Using CVS for backup-recovery

    Using CVS for backup-recovery

    CVS-only backup is often appropriate for development sites. If you are already using CVS and your data is not important, you probably don't need to do anything to back up your files. Just make sure that your current work is checked into the system. You can then roll back based on date - note the current system time, down to the minute. For maximum safety, you can apply a tag to your current files. You will still need to back up your database.

    Note that, if you did the CVS options in this document, the /var/lib/aolserver/$OPENACS_SERVICE_NAME/etc directory is not included in cvs and you may want to add it.

    [root root]# su - $OPENACS_SERVICE_NAME
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs commit -m "last-minute commits before upgrade to 4.6"
    cvs commit: Examining .
    cvs commit: Examining bin
    (many lines omitted)
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs tag before_upgrade_to_4_6
    cvs server: Tagging bin
    T bin/acs-4-0-publish.sh
    T bin/ad-context-server.pl
    (many lines omitted)
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
    [root root]# 
    su - $OPENACS_SERVICE_NAME
    cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
    cvs commit -m "last-minute commits before upgrade to 4.6"
    cvs tag before_upgrade_to_4_6
    exit

    To restore files from a cvs tag such as the one used above:

    [root root]# su - $OPENACS_SERVICE_NAME
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ cvs up -r current
    [$OPENACS_SERVICE_NAME $OPENACS_SERVICE_NAME]$ exit
    su - $OPENACS_SERVICE_NAME
    cd /var/lib/aolserver/$OPENACS_SERVICE_NAME
    cvs up -r current
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-next-add-server.html0000644000175000017500000000745311501005400025354 0ustar frankiefrankie Running multiple services on one machine

    Running multiple services on one machine

    Services on different ports. To run a different service on another port but the same ip, simply repeat Install OpenACS 5.6.0 replacing $OPENACS_SERVICE_NAME, and change the

    set httpport              8000
    set httpsport             8443 

    to different values.

    Services on different host names. For example, suppose you want to support http://service0.com and http://bar.com on the same machine. The easiest way is to assign each one a different ip address. Then you can install two services as above, but with different values for

    set hostname               [ns_info hostname]
    set address                127.0.0.1 

    If you want to install two services with different host names sharing the same ip, you'll need nsvhr to redirect requests based on the contents of the tcp headers. See AOLserver Virtual Hosting with TCP by markd.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/tutorial-upgrades.html0000644000175000017500000000651511501005400024351 0ustar frankiefrankie Distributing upgrades of your package

    Distributing upgrades of your package

    by Jade Rubick

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    The OpenACS Package Repository builds a list of packages that can be installed on OpenACS installations, and can be used by administrators to update their packages. If you are a package developer, there are a couple of steps you need to take in order to release a new version of your package.

    For the sake of this example, let's assume you are the package owner of the notes package. It is currently at version 1.5, and you are planning on releasing version 1.6. It is also located in OpenACS's CVS.

    To release your package:

    cd /path/to/notes
    cvs commit -m "Update package to version 1.6."
    cvs tag notes-1-6-final
    cvs tag -F openacs-5-1-compat
    

    Of course, make sure you write upgrade scripts (Writing upgrade scripts)

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/install-daemontools.html0000644000175000017500000002041711501005400024663 0ustar frankiefrankie Install Daemontools (OPTIONAL)

    Install Daemontools (OPTIONAL)

    Daemontools is a collection of programs for controlling other processes. We use daemontools to run and monitor AOLserver. It is installed in /package. These commands install daemontools and svgroup. svgroup is a script for granting permissions, to allow users other than root to use daemontools for specific services.

    1. Install Daemontools

      download daemontools and install it.

      • Red Hat 8

        [root root]# mkdir -p /package
        [root root]# chmod 1755 /package/
        [root root]# cd /package/
        [root package]# tar xzf /tmp/daemontools-0.76.tar.gz
        [root package]# cd admin/daemontools-0.76/
        [root daemontools-0.76]# package/install
        Linking ./src/* into ./compile...
        
        Creating /service...
        Adding svscanboot to inittab...
        init should start svscan now.
        [root root]#
        mkdir -p /package 
        chmod 1755 /package 
        cd /package 
        tar xzf /tmp/daemontools-0.76.tar.gz 
        cd admin/daemontools-0.76 
        package/install
      • Red Hat 9, Fedora Core 1-4

        Make sure you have the source tarball in /tmp, or download it.

        [root root]# mkdir -p /package
        [root root]# chmod 1755 /package/
        [root root]# cd /package/
        [root package]# tar xzf /tmp/daemontools-0.76.tar.gz
        [root package]# cd admin
        [root admin]# wget http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch
        --14:19:24--  http://moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch
                   => `daemontools-0.76.errno.patch'
        Resolving moni.csi.hu... done.
        Connecting to www.qmail.org[141.225.11.87]:80... connected.
        HTTP request sent, awaiting response... 200 OK
        Length: 355 [text/plain]
        
        100%[====================================>] 355          346.68K/s    ETA 00:00
        
        14:19:24 (346.68 KB/s) - `daemontools-0.76.errno.patch' saved [355/355]
        
        [root admin]# cd daemontools-0.76
        [root daemontools-0.76]# patch -p1 < ../daemontools-0.76.errno.patch
        [root daemontools-0.76]# package/install
        Linking ./src/* into ./compile...(many lines omitted)
        Creating /service...
        Adding svscanboot to inittab...
        init should start svscan now.
        [root root]#
        mkdir -p /package 
        chmod 1755 /package 
        cd /package 
        tar xzf /tmp/daemontools-0.76.tar.gz 
        cd admin
        wget http://moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch
        cd daemontools-0.76
        patch -p1 < ../daemontools-0.76.errno.patch
        package/install
      • FreeBSD (follow standard install)

        Make sure you have the source tarball in /tmp, or download it.

        [root root]# mkdir -p /package
        [root root]# chmod 1755 /package/
        [root root]# cd /package/
        [root package]# tar xzf /tmp/daemontools-0.76.tar.gz
        [root package]# cd admin/daemontools-0.76
        [root daemontools-0.76]# package/install
        Linking ./src/* into ./compile...(many lines omitted)
        Creating /service...
        Adding svscanboot to inittab...
        init should start svscan now.
        [root root]#
        mkdir -p /package 
        chmod 1755 /package 
        cd /package 
        tar xzf /tmp/daemontools-0.76.tar.gz 
        cd admin/daemontools-0.76
        package/install
      • Debian

        [root ~]# apt-get install daemontools-installer
        [root ~]# build-daemontools
    2. Verify that svscan is running. If it is, you should see these two processes running:

      [root root]# ps -auxw | grep service
      root     13294  0.0  0.1  1352  272 ?        S    09:51   0:00 svscan /service
      root     13295  0.0  0.0  1304  208 ?        S    09:51   0:00 readproctitle service errors: .......................................
      [root root]#
    3. Install a script to grant non-root users permission to control daemontools services.

      [root root]# cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/svgroup.txt /usr/local/bin/svgroup
      [root root]# chmod 755 /usr/local/bin/svgroup
      cp /tmp/openacs-5.6.0/packages/acs-core-docs/www/files/svgroup.txt /usr/local/bin/svgroup 
      chmod 755 /usr/local/bin/svgroup
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/openacs-unpack.html0000644000175000017500000000736511501005400023611 0ustar frankiefrankie Unpack the OpenACS tarball

    Unpack the OpenACS tarball

    The OpenACS tarball contains sample configuration files for some of the packages listed below. In order to access those files, unpack the tarball now.

    [root root]# cd /tmp
    [root tmp]# tar xzf openacs-5.6.0.tgz
    cd /tmp
    tar xzf openacs-5.6.0.tgz

    If you are installing from a different method and just need the configuration files, you can instead get them from CVS:

    [root root]# cd /tmp
    [root tmp]# cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot co openacs-4/packages/acs-core-docs/www/files/
    cvs checkout: warning: failed to open /root/.cvspass for reading: No such file or directory
    cvs server: Updating openacs-4/packages/acs-core-docs/www/files
    U openacs-4/packages/acs-core-docs/www/files/README.TXT
    (many lines omitted)
    U openacs-4/packages/acs-core-docs/www/files/template-ini.ini
    U openacs-4/packages/acs-core-docs/www/files/winnsd.txt
    [root tmp]# mv openacs-4 openacs-5.6.0
    cd /tmp
    cvs -d :pserver:anonymous@cvs.openacs.org:/cvsroot co openacs-4/packages/acs-core-docs/www/files/
    mv openacs-4 openacs-5.0.0a4
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/programming-with-aolserver.html0000644000175000017500000003746011501005400026174 0ustar frankiefrankie Programming with AOLserver

    Programming with AOLserver

    By Michael Yoon, Jon Salz and Lars Pind.

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    The global command

    When using AOLserver, remember that there are effectively two types of global namespace, not one:

    1. Server-global: As you'd expect, there is only one server-global namespace per server, and variables set within it can be accessed by any Tcl code running subsequently, in any of the server's threads. To set/get server-global variables, use AOLserver 3's nsv API (which supersedes ns_share from the pre-3.0 API).

    2. Script-global: Each Tcl script (ADP, Tcl page, registered proc, filter, etc.) executing within an AOLserver thread has its own global namespace. Any variable set in the top level of a script is, by definition, script-global, meaning that it is accessible only by subsequent code in the same script and only for the duration of the current script execution.

    The Tcl built-in command global accesses script-global, not server-global, variables from within a procedure. This distinction is important to understand in order to use global correctly when programming AOLserver.

    Also, AOLserver purges all script-global variables in a thread (i.e., Tcl interpreter) between HTTP requests. If it didn't, that would affect (and complicate) our use of script-global variables dramatically, which would then be better described as thread-global variables. Given AOLserver's behaviour, however, "script-global" is a more appropriate term.

    Threads and Scheduled Procedures

    ns_schedule_proc and ad_schedule_proc each take a -thread flag to cause a scheduled procedure to run asychronously, in its own thread. It almost always seems like a good idea to specify this switch, but there's a problem.

    It turns out that whenever a task scheduled with ns_schedule_proc -thread or ad_schedule_proc -thread t is run, AOLserver creates a brand new thread and a brand new interpreter, and reinitializes the procedure table (essentially, loads all procedures that were created during server initialization into the new interpreter). This happens every time the task is executed - and it is a very expensive process that should not be taken lightly!

    The moral: if you have a lightweight scheduled procedure which runs frequently, don't use the -thread switch.

    Note also that thread is initialized with a copy of what was installed during server startup, so if the procedure table have changed since startup (e.g. using the APM watch facility), that will not be reflected in the scheduled thread.

    Using return

    The return command in Tcl returns control to the caller procedure. This definition allows nested procedures to work properly. However, this definition also means that nested procedures cannot use return to end an entire thread. This situation is most common in exception conditions that can be triggered from inside a procedure e.g., a permission denied exception. At this point, the procedure that detects invalid permission wants to write an error message to the user, and completely abort execution of the caller thread. return doesn't work, because the procedure may be nested several levels deep. We therefore use ad_script_abort to abort the remainder of the thread. Note that using return instead of ad_script_abort may raise some security issues: an attacker could call a page that performed some DML statement, pass in some arguments, and get a permission denied error -- but the DML statement would still be executed because the thread was not stopped. Note that return -code return can be used in circumstances where the procedure will only be called from two levels deep.

    Returning More Than One Value From a Function

    Many functions have a single return value. For instance, empty_string_p returns a number: 1 or 0. Other functions need to return a composite value. For instance, consider a function that looks up a user's name and email address, given an ID. One way to implement this is to return a three-element list and document that the first element contains the name, and the second contains the email address. The problem with this technique is that, because Tcl does not support constants, calling procedures that returns lists in this way necessitates the use of magic numbers, e.g.:

    set user_info [ad_get_user_info $user_id]
    set first_name [lindex $user_info 0]
    set email [lindex $user_info 1]
    

    AOLserver/Tcl generally has three mechanisms that we like, for returning more than one value from a function. When to use which depends on the circumstances.

    Using Arrays and Pass-By-Value

    The one we generally prefer is returning an array get-formatted list. It has all the nice properties of pass-by-value, and it uses Tcl arrays, which have good native support.

    ad_proc ad_get_user_info { user_id } {
        db_1row user_info { select first_names, last_name, email from users where user_id = :user_id }
        return [list \
            name "$first_names $last_name" \
        email $email \
        namelink "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>" \
        emaillink "<a href=\"mailto:$email\">$email</a>"]
    }
    
    array set user_info [ad_get_user_info $user_id]
    
    doc_body_append "$user_info(namelink) ($user_info(emaillink))"
    

    You could also have done this by using an array internally and using array get:

    
    ad_proc ad_get_user_info { user_id } {
        db_1row user_info { select first_names, last_name, email from users where user_id = :user_id }
        set user_info(name) "$first_names $last_name"
        set user_info(email) $email
        set user_info(namelink) "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>"
        set user_info(emaillink) "<a href=\"mailto:$email\">$email</a>"
        return [array get user_info]
    }
    
    

    Using Arrays and Pass-By-Reference

    Sometimes pass-by-value incurs too much overhead, and you'd rather pass-by-reference. Specifically, if you're writing a proc that uses arrays internally to build up some value, there are many entries in the array, and you're planning on iterating over the proc many times. In this case, pass-by-value is expensive, and you'd use pass-by-reference.

    The transformation of the array into a list and back to an array takes, in our test environment, approximately 10 microseconds per entry of 100 character's length. Thus you can process about 100 entries per milisecond. The time depends almost completely on the number of entries, and almost not at all on the size of the entries.

    You implement pass-by-reference in Tcl by taking the name of an array as an argument and upvar it.

    
    ad_proc ad_get_user_info { 
        -array:required
        user_id 
    } {
        upvar $array user_info
        db_1row user_info { select first_names, last_name, email from users where user_id = :user_id }
        set user_info(name) "$first_names $last_name"
        set user_info(email) $email
        set user_info(namelink) "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>"
        set user_info(emaillink) "<a href=\"mailto:$email\">$email</a>"
    }
    
    ad_get_user_info -array user_info $user_id
    
    doc_body_append "$user_info(namelink) ($user_info(emaillink))"
    
    

    We prefer pass-by-value over pass-by-reference. Pass-by-reference makes the code harder to read and debug, because changing a value in one place has side effects in other places. Especially if have a chain of upvars through several layers of the call stack, you'll have a hard time debugging.

    Multisets: Using ns_sets and Pass-By-Reference

    An array is a type of set, which means you can't have multiple entries with the same key. Data structures that can have multiple entries for the same key are known as a multiset or bag.

    If your data can have multiple entries with the same key, you should use the AOLserver built-in ns_set. You can also do a case-insensitive lookup on an ns_set, something you can't easily do on an array. This is especially useful for things like HTTP headers, which happen to have these exact properties.

    You always use pass-by-reference with ns_sets, since they don't have any built-in way of generating and reconstructing themselves from a string representation. Instead, you pass the handle to the set.

    
    ad_proc ad_get_user_info {
        -set:required
        user_id
    } {
        db_1row user_info { select first_names, last_name, email from users where user_id = :user_id }
        ns_set put $set name "$first_names $last_name"
        ns_set put $set email $email
        ns_set put $set namelink "<a href=\"/shared/community-member?user_id=[ns_urlencode $user_id]\">$first_names $last_name</a>"
        ns_set put $set emaillink "<a href=\"mailto:$email\">$email</a>"
    }
    
    set user_info [ns_set create]
    ad_get_user_info -set $user_info $user_id
    
    doc_body_append "[ns_set get $user_info namelink] ([ns_set get $user_info emaillink])"
    
    

    We don't recommend ns_set as a general mechanism for passing sets (as opposed to multisets) of data. Not only do they inherently use pass-by-reference, which we dis-like, they're also somewhat clumsy to use, since Tcl doesn't have built-in syntactic support for them.

    Consider for example a loop over the entries in a ns_set as compared to an array:

    
    # ns_set variant
    set size [ns_set size $myset]
    for { set i 0 } { $i < $size } { incr i } {
        puts "[ns_set key $myset $i] = [ns_set value $myset $i]"
    }
    
    # array variant
    foreach name [array names myarray] {
        puts "$myarray($name) = $myarray($name)"
    }
    
    

    And this example of constructing a value:

    
    # ns_set variant
    set myset [ns_set create]
    ns_set put $myset foo $foo
    ns_set put $myset baz $baz
    return $myset
    
    # array variant
    return [list
        foo $foo
        baz $baz
    ]
    
    

    ns_sets are designed to be lightweight, so memory consumption should not be a problem. However, when using ns_set get to perform lookup by name, they perform a linear lookup, whereas arrays use a hash table, so ns_sets are slower than arrays when the number of entries is large.

    ($Id: programming-with-aolserver.html,v 1.47 2010/12/11 23:36:32 ryang Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/maintenance-web.html0000644000175000017500000000702611501005400023731 0ustar frankiefrankie Chapter 6. Production Environments
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/acs-plat-dev.html0000644000175000017500000001153711501005377023173 0ustar frankiefrankie Part IV. For OpenACS Platform Developers
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/www/security-design.html0000644000175000017500000011444411501005400024015 0ustar frankiefrankie Security Design

    Security Design

    By Richard Li and Archit Shah

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    Introduction

    This document explains security model design for OpenACS 4. The security system with the OpenACS core must authenticate users in both secure and insecure environments. In addition, this subsystem provides sessions on top of the stateless HTTP protocol. This system also provides session level properties as a generic service to the rest of the OpenACS.

    The atoms used in the implementation:

    • Cookies: RFC 2109, HTTP State Management Mechanism

      Cookies provide client side state. They are used to identify the user. Expiration of cookies is used to demark the end of a session.

    • SHA: SHA-1

      This secure hash algorithm enables us to digitally sign cookies which guarantee that they have not been tampered with. It is also used to hash passwords.

    • SSL with server authentication: SSL v3

      SSL provides the client with a guarantee that the server is actually the server it is advertised as being. It also provides a secure transport.

    Design

    Sessions

    A session is defined as a series of clicks in which no two clicks are separated by more than some constant. This constant is the parameter SessionTimeout. Using the expiration time on the signatures of the signed cookies, we can verify when the cookie was issued and determine if two requests are part of the same session. It is important to note that the expiration time set in the cookie protocol is not trusted. Only the time inserted by the signed cookie mechanism is trusted.

    Authentication

    Two levels of access can be granted: insecure and secure. This grant lasts for the remainder of the particular session. Secure authentication tokens are only issued over secured connections.

    One consequence of this security design is that secure tokens are not automatically issued to users who authenticate themselves over insecure connections. This means that users will need to reauthenticate themselves over SSL when performing some action that requires secure authentication.

    Although this makes the site less user friendly, this design significantly increases the security of the system because this insures that the authentication tokens presented to a secure section of the web site were not sniffed. The system is not entirely secure, since the actual authentication password can be sniffed from the system, after which the sniffer can apply for a secure authentication token. However, the basic architecture here lays the foundation for a secure system and can be easily adapted to a more secure authentication system by forcing all logins to occur over HTTPS.

    Details

    The authentication system issues up to four signed cookies (see below), with each cookie serving a different purpose. These cookies are:

    namevaluemax-agesecure?
    ad_session_idsession_id,user_idSessionTimeoutno
    ad_user_loginuser_idInfinityno
    ad_user_login_secureuser_id,randomInfinityyes
    ad_secure_tokensession_id,user_id,randomSessionLifetimeyes
    • ad_session_id

      • reissued on any hit separated by more than SessionRenew seconds from the previous hit that received a cookie

      • is valid only for SessionTimeout seconds

      • is the canonical source for the session ID in ad_conn

    • ad_user_login

      • is used for permanent logins

    • ad_user_login_secure

      • is used for permanent secure logins

      • contains random garbage (ns_time) to prevent attack against the secure hash

    • ad_secure_token

      • is a session-level cookie from the browser's standpoint

      • its signature expires in SessionLifetime seconds

      • contains random garbage (ns_time) to prevent attack against the secure hash

      • user_id is extraneous

    Authentication Process

    The Tcl function (sec_handler) is called by the request processor to authenticate the user. It first checks the ad_session_id cookie. If there is no valid session in progress, a new session is created with sec_setup_session. If the user has permanent login cookies (ad_user_login and ad_user_login_secure), then they are looked at to determine what user the session should be authorized as. Which cookie is examined is determined by whether or not the request is on a secure connection. If neither cookie is present, then a session is created without any authentication. If the ad_session_id cookie is valid, the user_id and session_id are pulled from it and put into ad_conn.

    Authenticating Secure Connections

    Secure connections are authenticated slightly differently. The function ad_secure_conn_p is used to determine whether or not the URL being accessed is requires a secure login. The function simply checks if the location begins with "https". (This is safe because the location is set during the server initialization.)

    If secure authentication is required, the ad_secure_token cookie is checked to make sure its data matches the data stored in ad_session_id. This is true for all pages except those that are part of the login process. On these pages, the user can not yet have received the appropriate ad_secure_token cookie, so no check against it is performed. The set of pages that skip that processing are determined by determined by ad_login_page. Since the ad_secure_token cookie is a session cookie, it is deleted by the browser when the browser exits. Since an attacker could conceivably store the secure cookie in a replay attack (since expiration date is not validated), the data in the secure cookie is never used to set any data in ad_conn; user_id and session_id is set from the ad_session_id cookie.

    It is important to note that the integrity of secure authentication rests on the two Tcl function ad_secure_conn_p and ad_login_page. If ad_secure_conn_p is false, secure authentication is not required. If ad_login_page is false, secure authentication is not required.

    Login Process

    The Tcl function ad_user_login does two things. First it performs the appropriate manipulation of the permanent login cookies, and then it updates the current session to reflect the new user_id. The manipulation of the permanent login cookies is based on 3 factors:

    • previous login: other user, same user

    • permanent: was a permanent login requested?

    • secure: is this a secure connection?

    Both the secure and insecure permanent login cookie can have one of three actions taken on it:

    • set: cookie with no expiration is set

    • delete: set to "" with max age of 0, so it is expired immediately

    • nothing: if the cookie is present, it remains

    The current state of the permanent login cookies is not taken into account when determining the appropriate action.

    previous login statepermanent login requestedsecure connectionaction on insecureaction on secure
    otheryysetset
    sameyysetset
    otherynsetdelete
    sameynsetnothing
    samenynothingdelete
    othernydeletedelete
    othernndeletedelete
    samenndeletedelete

    ad_user_login callssec_setup_session which actually calls sec_generate_session_id_cookie to generate the new cookie with refer to the appropriate user_id. If the connection is secure the ad_secure_token cookie is generated by a call to sec_generate_secure_token_cookie. This function is only called from sec_setup_session. Only sec_handler and sec_setup_session call sec_generate_session_id_cookie.

    ad_user_logout logs the user out by deleting all 4 cookies that are used by the authentication system.

    Session Creation

    The creation and setup of sessions is handled in sec_setup_session, which is called either to create a new session from sec_handler or from ad_user_login when there is a change in authorization level. The session management code must do two things: insure that session-level data does not float between users, and update the users table which has columns for n_sessions, last_visit, and second_to_last_visit.

    If there is no session already setup on this hit, a new session is created. This happens when sec_setup_session is called from sec_handler. If the login is from a user to another user, a new session is created, otherwise, the current session is continued, simply with a higher authorization state. This allows for data associated with a session to be carried over when a user logs in.

    The users table is updated by sec_update_user_session_info which is called when an existing session is assigned a non-zero user_id, or when a session is created with a non-zero user_id.

    Passwords

    ad_user_login assumes a password check has already been performed (this will change in the future). The actual check is done by ad_check_password. The database stores a salt and a hash of the password concatenated with the salt. Updating the password (ad_change_password) simply requires getting a new salt (ns_time) concatenating and rehashing. Both the salt and the hashed password field are updated.

    Performance Enhancements

    A session is labeled by a session_id sequence. Creating a session merely requires incrementing the session_id sequence. We do two things to improve the performance of this process. First, sequence values are precomputed and cached in the Oracle SGA. In addition, sequence values are incremented by 100 with each call to nextval. These sequences values are cached on a per-thread basis. The cost of allocating a new session thus becomes the cost of executing an incr Tcl command per thread. This minimizes lock contention for the session ID sequence and also minimizes the number of DB requests, since each thread can allocate 100 sessions before requiring another DB hit. This cache works by keeping two counters: tcl_max_value and tcl_current_sequence_id. When tcl_current_sequence_id is greater than tcl_max_value a new value is requested from the db and tcl_max_value is incremented by 100. This is done on a per-thread basis so that no locking is required.

    In addition, two procedures are dynamically generated at startup in security-init.tcl. These two procedures use ad_parameter to obtain the constant value of a given parameter; these values are used to dynamically generate a procedure that returns a constant. This approach avoids (relatively) expensive calls to ad_parameter in sec_handler. The impact of this approach is that these parameters cannot be dynamically changed at runtime and require a server restart.

    Session Properties

    Session properties are stored in a single table that maps session IDs to named session properties and values. This table is periodically purged. For maximum performance, the table is created with nologging turned on and new extents are allocated in 50MB increments to reduce fragmentation. This table is swept periodically by sec_sweep_session which removes sessions whose first hit was more than SessionLifetime seconds (1 week by default) ago. Session properties are removed through that same process with cascading delete.

    Secure Session Properties

    Session properties can be set as secure. In this case, ad_set_client_property will fail if the connection is not secure. ad_get_client_property will behave as if the property had not been set if the property was not set securely.

    Digital Signatures & Signed Cookies

    Signed cookies are implemented using the generic secure digital signature mechanism. This mechanism guarantees that the user can not tamper with (or construct a value of his choice) without detection. In addition, it provides the optional facility of timing out the signature so it is valid for only a certain period of time. This works by simply including an expiration time as part of the value that is signed.

    The signature produced by ad_sign is the Tcl list of token_id,expire_time,hash, where hash = SHA1(value,token_id,expire_time,secret_token). The secret_token is a forty character randomly generated string that is never sent to any user agent. The scheme consists of one table:

    
    create table secret_tokens (
        token_id                    integer
                                    constraint secret_tokens_token_id_pk primary key,
        token                       char(40),
        token_timestamp             sysdate
    );
    
    

    ad_verify_signature takes a value and a signature and verifies that the signature was generated using that value. It works simply by taking the token_id and expire_time from the signature, and regenerating the hash using the supplied value and the secret_token corresponding to the token_id. This regenerated hash is compared to the hash extracted from the supplied signature. The expire_time is also verified to be greater than the current time. An expire_time of 0 is also allowed, as it indicates no time out on the signature.

    Signed cookies include in their RFC2109 VALUE field a Tcl list of the value and the signature. In addition to the expiration of the digital signature, RFC 2109 specifies an optional max age that is returned to the client. For most cookies, this max age matches the expiration date of the cookie's signature. The standard specifies that when the max age is not included, the cookie should be "discarded when the user agent exits." Because we can not trust the client to do this, we must specify a timeout for the signature. The SessionLifetime parameter is used for this purpose, as it represents the maximum possible lifetime of a single session.

    RFC 2109 specifies this optional "secure" parameter which mandates that the user-agent use "secure means" to contact the server when transmitting the cookie. If a secure cookie is returned to the client over https, then the cookie will never be transmitted over insecure means.

    Performance

    Performance is a key goal of this implementation of signed cookies. To maximize performance, we will use the following architecture. At the lowest level, we will use the secret_tokens table as the canonical set of secret tokens. This table is necessary for multiple servers to maintain the same set of secret tokens. At server startup, a random subset of these secret tokens will be loaded into an ns_cache called secret_tokens. When a new signed cookie is requested, a random token_id is returned out of the entire set of cached token_ids. In addition, a thread-persistent cache called tcl_secret_tokens is maintained on a per-thread basis.

    Thus, the L2 ns_cache functions as a server-wide LRU cache that has a minimum of 100 tokens in it. The cache has a dual purpose:

    • LRU cache Note that cache misses will only occur in the multiple server case, where a user agent may have a signature guaranteed by a secret token issued by another server in the cluster.

    • signature cache Since the cache always maintains a minimum of 100 (set by a parameter) tokens populated at startup, it can be used to provide a random token for signature purposes.

    The per-thread cache functions as an L1 cache that indiscriminately caches all secret tokens. Note that this is not an LRU cache because there is no cache eviction policy per se -- the cache is cleared when the thread is destroyed by AOLserver.

    Security

    Storing information on a client always presents an additional security risk.

    Since we are only validating the information and not trying to protect it as a secret, we don't use salt. Cryptographic salt is useful if you are trying to protect information from being read (e.g., hashing passwords).

    External SSL

    External SSL mechanisms (firewall, dedicated hardware, etc.) can be used by creating two pools of AOLservers. In one pool the servers should be configured with the location parameter of nssock module set to "https://yourservername". The servers in the other pool are configured as normal. The external SSL agent should direct SSL queries to the pool of secure servers, and it should direct non-SSL queries to the insecure servers.

    PRNG

    The pseudorandom number generator depends primarily on ns_rand, but is also seeded with ns_time and the number of page requests served since the server was started. The PRNG takes the SHA1(seed,ns_rand,ns_time,requests,clicks), and saves the first 40 bits as the seed for the next call to the PRNG in a thread-persistent global variable. The remaining 120 bits are rehashed to produce 160 bits of output.

    API

    Login/Password

    ad_user_login user_id Logs the user in as user user_id. Optional forever flag determines whether or not permanent cookies are issued.

    ad_user_logout Logs the user out.

    ad_check_password user_id password returns 0 or 1.

    ad_change_password user_id new password

    Digital Signatures and Signed Cookies

    ad_sign value Returns the digital signature of this value. Optional parameters allow for the specification of the secret used, the token_id used and the max_age for the signature. ad_verify_signature value signatureReturns 1 or 0 indicating whether or not the signature matches the value specified. The secret parameter allows for specification of a different secret token to be used.

    ad_set_signed_cookie name data Sets a signed cookie name with value data.

    ad_get_signed_cookie name Gets the signed cookie name. It raises an error if the cookie has been tampered with, or if its expiration time has passed.

    Session Properties

    ad_set_client_property module name data Sets a session property with name to value data for the module module. The optional secure flag specifies the property should only be set if the client is authorized for secure access (ad_secure_conn_p is true). There is also an optional session_id flag to access data from sessions other than the current one.

    ad_get_client_property module name data Gets a session property with name to for the module module. The optional secure flag specifies the property should only be retrieved if the client is authorized for secure access (ad_secure_conn_p is true). There is also an optional session_id flag to access data from sessions other than the current one.

    Parameters

    SessionTimeout the maximum time in seconds (default 1200) between requests that are part of the same session

    SessionRenew the time in seconds (default 300) between reissue of the session cookie. The minimum time that can pass after a session cookie is issued and before it is rejected is (SessionTimeout - SessionRenew). This parameter is used so that only one session_id cookie is set on a single page even if there are multiple images that are being downloaded.

    SessionLifetime the maximum possible lifetime of a session in seconds (default 604800 = 7 days)

    NumberOfCachedSecretTokens the number of secret tokens to cache. (default 100)

    Future Improvements

    PRNG implementation

    The pseudorandom number generator used in the OpenACS is cryptographically weak, and depends primarily on the randomness of the ns_rand function for its randomness. The implementation of the PRNG could be substantially improved.

    ad_user_login

    Add a password argument. It is non-optimal to make the default behavior to assume that the password was provided.

    Secret Tokens

    The secret tokens pool is currently static. Ideally, this pool should be changed on a random but regular basis, and the number of secret_tokens increased as the number of users come to the web site.

    Since the security of the entire system depends on the secret tokens pool, access to the secret tokens table should be restricted and accessible via a strict PL/SQL API. This can be done by revoking standard SQL permissions on the table for the AOLserver user and giving those permissions to a PL/SQL package.

    Robots

    Deferring session to creation until the second hit from a browser seems to be a good way of preventing a lot of overhead processing for robots. If we do this, send cookie on first hit to test if cookies are accepted, then actually allocate on second hit. To preserve a record of the first hit of the session, just include any info about that first hit in the probe cookie sent. Look at how usca_p (user session cookie attempted) is used in OpenACS 3.x ecommerce.

    Client properties

    Currently there are only session properties. Because sessions have a maximum life, properties have a maximum life. It would be nice to expand the interface to allow for more persistent properties. In the past, there was a sec_browser_properties table that held permanent properties about each unique visitor (for logged in users, these are just user properties). This was unscalable because there was no way to delete these properties, and the table tended to grow to millions of rows. It would be nice to view browser and session properties as two types of client properties, but with different deletion patterns (there are other differences as well, browser properties can be shared between concurrent sessions). The applications should have control over the deletion patterns, but should not be able to ignore the amount of data stored.

    Session information

    It would be nice to keep some info about sessions: first hit, last hit, and URLs visited come to mind. Both logging and API for accessing this info would be nice. WimpyPoint is an application that already wants to use this information to show how long the current presentation has been viewed. The right way may be to put the session_id into the access log and use log analyzers (leaving it in server memory for applications to access). Putting it into the database at all is probably too big a hammer. Certainly putting it into the database on every hit is too big a hammer.

    Cookieless Sessions

    Two trends drive the requirement for removing cookie dependence. WAP browsers that do not have cookies, and publc perceptions of cookies as an invasion of privacy. The rely on the cookies mechanism in HTTP to distinguish one request from the next, and we trust it to force requests from the same client to carry the same cookie headers. The same thing can be accomplished by personalizing the URLs sent back to each browser. If we can store an identifier in the URL and get it back on the next hit, the sessions system would continue to work.

    Problems that arise:

    • URL sharing could be dangerous. If I happen to be browsing Amazon while logged in and I email a friend, he could conceivably receive it and follow it before my session has expired, gaining all of the privileges I had.

    • User-entered URLs are harder to handler. If a user is in the middle of a session and then types in the URL of some page, he could be kicked out of his session.

    Both of these problems can be mitigated by doing detection of cookie support (see the section on robot detection). To help deal with the first problem, One could also make the restriction that secure sessions are only allowed over cookied HTTP.

    Vulnerability Analysis

    This section is not meant to be a comprehensive analysis of the vulnerabilities of the security system. Listed below are possible attack points for the system; these vulnerabilities are currently theoretical in nature. The major cryptographic vulnerability of the system stems from the pseudorandom nature of the random number generators used in the system.

    • Cryptographically weak PRNG see above.

    • Dependence on sample SQL command The list of random token that are placed in the secret tokens cache is randomly chosen by the Oracle sample command. This command may not be entirely random, so predicting the contents of the secret tokens cache may not be as difficult as someone may anticipate.

    • Dependence on ns_rand The actual token that is chosen from the cache to be used is chosen by a call to ns_rand.

    • ad_secure_conn_p As discussed above, the security of the secure sessions authentication system is dependent upon this function.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-core-docs/acs-core-docs.info0000644000175000017500000000235611575167337022517 0ustar frankiefrankie Documentation Documentation t t OpenACS Documentation Team Documentation for the OpenACS Core. 2011-06-12 OpenACS GPL 3 Static HTML documentation for the OpenACS core (includes the DocBook sources). openacs-5.7.0/packages/acs-mail-lite/0000755000175000017500000000000011724401447017176 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/tcl/0000755000175000017500000000000011724401447017760 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-procs-oracle.xql0000644000175000017500000000525311061305203025506 0ustar frankiefrankie oracle8.1.6 insert into acs_mail_lite_queue (message_id, creation_date, locking_server, to_addr, from_addr, reply_to, subject, package_id, file_ids, mime_type, no_callback_p, use_sender_p, cc_addr, bcc_addr, body, extraheaders, object_id ) values (acs_mail_lite_id_seq.nextval, :creation_date, :locking_server, :to_addr, :from_addr, :reply_to, :subject, :package_id, :file_ids, :mime_type, decode(:no_callback_p,'1','t','f'), decode(:use_sender_p,'1','t','f'), :cc_addr, :bcc_addr, :body, :extraheaders, :object_id ) update acs_mail_lite_mail_log set last_mail_date = sysdate where party_id = :user_id insert into acs_mail_lite_mail_log (party_id, last_mail_date) values (:user_id, sysdate) select message_id as id, creation_date, locking_server, to_addr, cc_addr, bcc_addr, from_addr, reply_to, subject, body, package_id, file_ids, mime_type, decode(no_callback_p,'t',1,0) as no_callback_p, extraheaders, decode(use_sender_p,'t',1,0) as use_sender_p, object_id from acs_mail_lite_queue where locking_server = '' or locking_server is NULL openacs-5.7.0/packages/acs-mail-lite/tcl/bounce-procs.tcl0000644000175000017500000001440311456662500023066 0ustar frankiefrankiead_library { Provides a simple API for reliably sending email. @author Eric Lorenzo (eric@openforce.net) @creation-date 22 March 2002 @cvs-id $Id: bounce-procs.tcl,v 1.9 2010/10/17 21:06:08 donb Exp $ } package require mime 1.4 package require smtp 1.4 package require base64 2.3.1 namespace eval acs_mail_lite { #--------------------------------------- ad_proc -private bounce_prefix {} { @return bounce prefix for x-envelope-from } { return [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter "EnvelopePrefix"] } #--------------------------------------- ad_proc -public bouncing_email_p { -email:required } { Checks if email address is bouncing mail @option email email address to be checked for bouncing @return boolean 1 if bouncing 0 if ok. } { return [db_string bouncing_p {} -default 0] } #--------------------------------------- ad_proc -public bouncing_user_p { -user_id:required } { Checks if email address of user is bouncing mail @option user_id user to be checked for bouncing @return boolean 1 if bouncing 0 if ok. } { return [db_string bouncing_p {} -default 0] } #--------------------------------------- ad_proc -public bounce_address { -user_id:required -package_id:required -message_id:required } { Composes a bounce address @option user_id user_id of the mail recipient @option package_id package_id of the mail sending package (needed to call package-specific code to deal with bounces) @option message_id message-id of the mail @return bounce address } { return "[bounce_prefix]-$user_id-[ns_sha1 $message_id]-$package_id@[address_domain]" } #--------------------------------------- ad_proc -public parse_bounce_address { -bounce_address:required } { This takes a reply address, checks it for consistency, and returns a list of user_id, package_id and bounce_signature found @option bounce_address bounce address to be checked @return tcl-list of user_id package_id bounce_signature } { set regexp_str "\[[bounce_prefix]\]-(\[0-9\]+)-(\[^-\]+)-(\[0-9\]*)\@" if {![regexp $regexp_str $bounce_address all user_id signature package_id]} { ns_log Debug "acs-mail-lite: bounce address not found for $bounce_address" return "" } return [list $user_id $package_id $signature] } #--------------------------------------- ad_proc -public scan_replies {} { Scheduled procedure that will scan for bounced mails } { # Make sure that only one thread is processing the queue at a time. if {[nsv_incr acs_mail_lite check_bounce_p] > 1} { nsv_incr acs_mail_lite check_bounce_p -1 return } with_finally -code { ns_log Debug "acs-mail-lite: about to load qmail queue for [mail_dir]" load_mails -queue_dir [mail_dir] } -finally { nsv_incr acs_mail_lite check_bounce_p -1 } } #--------------------------------------- ad_proc -private check_bounces { } { Daily proc that sends out warning mail that emails are bouncing and disables emails if necessary } { set max_bounce_count [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter MaxBounceCount -default 10] set max_days_to_bounce [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter MaxDaysToBounce -default 3] set notification_interval [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter NotificationInterval -default 7] set max_notification_count [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter MaxNotificationCount -default 4] set notification_sender [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter NotificationSender -default "reminder@[address_domain]"] # delete all bounce-log-entries for users who received last email # X days ago without any bouncing (parameter) db_dml delete_log_if_no_recent_bounce {} # disable mail sending for users with more than X recently # bounced mails db_dml disable_bouncing_email {} # notify users of this disabled mail sending db_dml send_notification_to_bouncing_email {} # now delete bounce log for users with disabled mail sending db_dml delete_bouncing_users_from_log {} set subject "[ad_system_name] Email Reminder" # now periodically send notifications to users with # disabled email to tell them how to reenable the email set notifications [db_list_of_ns_sets get_recent_bouncing_users {}] # send notification to users with disabled email foreach notification $notifications { set notification_list [util_ns_set_to_list -set $notification] array set user $notification_list set user_id $user(user_id) set body "Dear $user(name),\n\nDue to returning mails from your email account, we currently do not send you any email from our system. To reenable your email account, please visit\n[ad_url]/register/restore-bounce?[export_url_vars user_id]" send -to_addr $notification_list -from_addr $notification_sender -subject $subject -body $body -valid_email ns_log Notice "Bounce notification send to user $user_id" # schedule next notification db_dml log_notication_sending {} } } ad_proc -public record_bounce { {-user_id ""} {-email ""} } { Records that an email bounce for this user } { if {$user_id eq ""} { set user_id [party::get_by_email -email $email] } if { $user_id ne "" && ![acs_mail_lite::bouncing_user_p -user_id $user_id] } { ns_log Debug "acs_mail_lite::incoming_email impl acs-mail-lite: Bouncing email from user $user_id" # record the bounce in the database db_dml record_bounce {} if {![db_resultrows]} { db_dml insert_bounce {} } } } } openacs-5.7.0/packages/acs-mail-lite/tcl/bounce-procs.xql0000755000175000017500000000363710672240205023113 0ustar frankiefrankie select case when email_bouncing_p = 't' then 1 else 0 end as send_p from users, parties where lower(email) = lower(:email) and party_id = user_id select case when email_bouncing_p = 't' then 1 else 0 end as send_p from users where user_id = :user_id delete from acs_mail_lite_bounce where party_id in (select party_id from acs_mail_lite_mail_log where last_mail_date < sysdate - :max_days_to_bounce) update users set email_bouncing_p = 't' where user_id in (select party_id from acs_mail_lite_bounce where bounce_count >= :max_bounce_count) delete from acs_mail_lite_bounce where bounce_count >= :max_bounce_count update acs_mail_lite_bounce set bounce_count = bounce_count + 1 where party_id = :user_id insert into acs_mail_lite_bounce (party_id, bounce_count) values (:user_id, 1) openacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-callback-procs.tcl0000644000175000017500000000705611160274213025764 0ustar frankiefrankie# packages/acs-mail-lite/tcl/acs-mail-lite-callback-procs.tcl ad_library { Callback procs for acs-mail-lite @author Malte Sussdorff (sussdorff@sussdorff.de) @creation-date 2005-06-15 @arch-tag: d9aec4df-102d-4b0d-8d0e-3dc470dbe783 @cvs-id $Id: acs-mail-lite-callback-procs.tcl,v 1.22 2009/03/18 22:41:15 emmar Exp $ } ad_proc -public -callback acs_mail_lite::send { -package_id:required -message_id:required -from_addr:required -to_addr:required -body:required {-mime_type "text/plain"} {-subject} {-cc_addr} {-bcc_addr} {-file_ids} {-object_id} } { Callback for executing code after an email has been send using the send mechanism. @param package_id Package ID of the sending package @param message_id the generated message_id for this mail @param from_addr email of the sender @param to_addr list of emails to whom did we send this email @param body Text body of the email @param mime_type Mime type of the email body @param subject of the email @param cc_addr list of emails to whom did we send this email in CC @param bcc_addr list of emails to whom did we send this email in BCC @param file_ids List of file ids sent as attachments. @param object_id The ID of the object that is responsible for sending the mail in the first place } - ad_proc -public -callback acs_mail_lite::incoming_email { -array:required -package_id } { Callback that is executed for incoming e-mails if the email is *NOT* like $object_id@servername } - ad_proc -public -callback acs_mail_lite::incoming_object_email { -array:required -object_id:required } { Callback that is executed for incoming e-mails if the email is like $object_id@servername } - ad_proc -public -callback acs_mail_lite::email_form_elements { -varname:required } { } - ad_proc -public -callback acs_mail_lite::files { -varname:required -recipient_ids:required } { } - ad_proc -public -callback acs_mail_lite::incoming_email -impl acs-mail-lite { -array:required -package_id:required } { Implementation of the interface acs_mail_lite::incoming_email for acs-mail-lite. This proc takes care of emails bounced back from mailer deamons. The required syntax for the To header is as follows: EnvelopPrefix-user_id-signature-package_id@myhost.com. This email was set for the Return-Path header of the original email. The signature is created by calculating the SHA value of the original Message-Id header. Thus an email is valid if the signature is correct and the user is known. If this is the case we record the bounce. @author Nima Mazloumi (nima.mazloumi@gmx.de) @creation-date 2005-07-15 @param array An array with all headers, files and bodies. To access the array you need to use upvar. @param package_id The package instance that registered the prefix @return nothing @error } { upvar $array email set to [acs_mail_lite::parse_email_address -email $email(to)] ns_log Debug "acs_mail_lite::incoming_email -impl acs-mail-lite called. Recepient $to" util_unlist [acs_mail_lite::parse_bounce_address -bounce_address $to] user_id package_id signature # If no user_id found or signature invalid, ignore message if {$user_id eq ""} { ns_log Debug "acs_mail_lite::incoming_email impl acs-mail-lite: No equivalent user found for $to" } else { ns_log Debug "acs_mail_lite::incoming_email impl acs-mail-lite: Bounce checking $to, $user_id" acs_mail_lite::record_bounce -user_id $user_id } } openacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-callback-procs.xql0000644000175000017500000000104710542707767026022 0ustar frankiefrankie update acs_mail_lite_bounce set bounce_count = bounce_count + 1 where party_id = :user_id insert into acs_mail_lite_bounce (party_id, bounce_count) values (:user_id, 1) openacs-5.7.0/packages/acs-mail-lite/tcl/bounce-procs-postgresql.xql0000644000175000017500000000341710606355251025312 0ustar frankiefrankie postgresql7.1 insert into acs_mail_lite_bounce_notif (party_id, notification_count, notification_time) select party_id, 0 as notification_count, date_trunc('day', current_timestamp - to_interval(1 + :notification_interval, 'days')) as notification_time from acs_mail_lite_bounce where bounce_count >= :max_bounce_count select u.user_id, u.email, u.first_names || ' ' || u.last_name as name from cc_users u, acs_mail_lite_bounce_notif n where u.user_id = n.party_id and u.email_bouncing_p = 't' and n.notification_time < current_timestamp - to_interval(:notification_interval, 'days') and n.notification_count < :max_notification_count update acs_mail_lite_bounce_notif set notification_time = date_trunc('day',current_timestamp), notification_count = notification_count + 1 where party_id = :user_id delete from acs_mail_lite_bounce where party_id in (select party_id from acs_mail_lite_mail_log where last_mail_date < current_timestamp - to_interval(:max_days_to_bounce, 'days')) openacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-procs.tcl0000644000175000017500000005350311544326011024230 0ustar frankiefrankiead_library { Provides a simple API for reliably sending email. @author Eric Lorenzo (eric@openforce.net) @creation-date 22 March 2002 @cvs-id $Id: acs-mail-lite-procs.tcl,v 1.89 2011/03/29 09:53:13 gustafn Exp $ } package require mime 1.4 package require smtp 1.4 package require base64 2.3.1 namespace eval acs_mail_lite { ad_proc -public get_package_id {} { @return package_id of this package } { return [apm_package_id_from_key acs-mail-lite] } ad_proc -public get_parameter { -name:required {-default ""} } { Returns an apm-parameter value of this package @option name parameter name @option default default parameter value @return apm-parameter value of this package } { return [parameter::get -package_id [get_package_id] -parameter $name -default $default] } ad_proc -private mail_dir {} { @return incoming mail directory to be scanned for bounces } { return [get_parameter -name "BounceMailDir"] } #--------------------------------------- ad_proc -public parse_email_address { -email:required } { Extracts the email address out of a mail address (like Joe User ) @option email mail address to be parsed @return only the email address part of the mail address } { if {![regexp {<([^>]*)>} $email all clean_email]} { return $email } else { return $clean_email } } #--------------------------------------- ad_proc -private log_mail_sending { -user_id:required } { Logs mail sending time for user @option user_id user for whom email sending should be logged } { db_dml record_mail_sent {} if {![db_resultrows]} { db_dml insert_log_entry {} } } #--------------------------------------- ad_proc -public generate_message_id { } { Generate an id suitable as a Message-Id: header for an email. @return valid message-id for mail header } { # The combination of high resolution time and random # value should be pretty unique. return "<[clock clicks].[ns_time].oacs@[address_domain]>" } #--------------------------------------- ad_proc -public valid_signature { -signature:required -message_id:required } { Validates if provided signature matches message_id @option signature signature to be checked @option msg message-id that the signature should be checked against @return boolean 0 or 1 } { if {![regexp "(<\[\-0-9\]+\\.\[0-9\]+\\.oacs@[address_domain]>)" $message_id match id] || $signature ne [ns_sha1 $id] } { # either couldn't find message-id or signature doesn't match return 0 } return 1 } #--------------------------------------- ad_proc -private smtp { -multi_token:required -headers:required -originator:required } { Send messages via SMTP @param multi_token Multi Token generated which is passed directly to smtp::sendmessage @param headers List of list of header key-value pairs like {{from malte@cognovis.de} {to malte@cognovis.de}} } { set mail_package_id [apm_package_id_from_key "acs-mail-lite"] # Get the SMTP Parameters set smtp [parameter::get -parameter "SMTPHost" \ -package_id $mail_package_id \ -default [ns_config ns/parameters mailhost]] if {$smtp eq ""} { set smtp localhost } set timeout [parameter::get -parameter "SMTPTimeout" \ -package_id $mail_package_id \ -default [ns_config ns/parameters smtptimeout]] if {$timeout eq ""} { set timeout 60 } set smtpport [parameter::get -parameter "SMTPPort" \ -package_id $mail_package_id \ -default 25] set smtpuser [parameter::get -parameter "SMTPUser" \ -package_id $mail_package_id] set smtppassword [parameter::get -parameter "SMTPPassword" \ -package_id $mail_package_id] set cmd_string "smtp::sendmessage $multi_token -originator $originator" foreach header $headers { append cmd_string " -header {$header}" } append cmd_string " -servers $smtp -ports $smtpport -username $smtpuser -password $smtppassword" ns_log Debug "send cmd_string: $cmd_string" eval $cmd_string } #--------------------------------------- ad_proc -private get_address_array { -addresses:required } { Checks if passed variable is already an array of emails, user_names and user_ids. If not, get the additional data from the db and return the full array. @option addresses variable to checked for array @return array of emails, user_names and user_ids to be used for the mail procedures } { if {[catch {array set address_array $addresses}] || ![string equal [lsort [array names address_array]] [list email name user_id]]} { # either user just passed a normal address-list or # user passed an array, but forgot to provide user_ids # or user_names, so we have to get this data from the db if {![info exists address_array(email)]} { # so user passed on a normal address-list set address_array(email) $addresses } set address_list [list] foreach email $address_array(email) { # strip out only the emails from address-list lappend address_list [string tolower [parse_email_address -email $email]] } array unset address_array # now get the user_names and user_ids foreach email $address_list { set email [string tolower $email] if {[db_0or1row get_user_name_and_id ""]} { lappend address_array(email) $email lappend address_array(name) $user_name lappend address_array(user_id) $user_id } else { lappend address_array(email) $email lappend address_array(name) "" lappend address_array(user_id) "" } } } return [array get address_array] } #--------------------------------------- ad_proc -public send { -send_immediately:boolean -valid_email:boolean -to_addr:required -from_addr:required {-subject ""} -body:required {-mime_type "text/plain"} {-cc_addr ""} {-bcc_addr ""} {-reply_to ""} {-package_id ""} -no_callback:boolean {-file_ids ""} {-extraheaders ""} -use_sender:boolean {-object_id ""} } { Prepare an email to be send with the option to pass in a list of file_ids as well as specify an html_body and a mime_type. It also supports multiple "TO" recipients as well as CC and BCC recipients. Runs entirely off MIME and SMTP to achieve this. @param send_immediately The email is send immediately and not stored in the acs_mail_lite_queue @param to_addr List of e-mail addresses to send this mail to. @param from_addr E-Mail address of the sender. @param subject of the email @param body Text body of the email @param cc_addr List of CC Users e-mail addresses to send this mail to. @param bcc_addr List of CC Users e-mail addresses to send this mail to. @param package_id Package ID of the sending package @param file_ids List of file ids (items or revisions) to be send as attachments. This will only work with files stored in the file system. @param mime_type MIME Type of the mail to send out. Can be "text/plain", "text/html". @param extraheaders List of keywords and their values passed in for headers. Interesting ones are: "Precedence: list" to disable autoreplies and mark this as a list message. This is as list of lists !! @param no_callback Boolean that indicates if callback should be executed or not. If you don't provide it it will execute callbacks @param use_sender Boolean indicating that from_addr should be used regardless of fixed-sender parameter } { # check, if send_immediately is set # if not, take global parameter if { !$send_immediately_p } { set send_immediately_p [parameter::get -package_id [get_package_id] -parameter "send_immediately" -default 0] } # if send_immediately_p true, then start acs_mail_lite::send_immediately, so mail is not stored in the db before delivery if { $send_immediately_p } { acs_mail_lite::send_immediately \ -to_addr $to_addr \ -cc_addr $cc_addr \ -bcc_addr $bcc_addr \ -from_addr $from_addr \ -reply_to $reply_to \ -subject $subject \ -body $body \ -package_id $package_id \ -file_ids $file_ids \ -mime_type $mime_type \ -no_callback_p $no_callback_p \ -extraheaders $extraheaders \ -use_sender_p $use_sender_p \ -object_id $object_id } else { # else, store it in the db and let the sweeper deliver the mail set creation_date [clock format [clock seconds] -format "%Y.%m.%d %H:%M:%S"] set locking_server "" db_dml create_queue_entry {} } } #--------------------------------------- ad_proc -private sweeper {} { Send messages in the acs_mail_lite_queue table. } { # Make sure that only one thread is processing the queue at a time. if {[nsv_incr acs_mail_lite send_mails_p] > 1} { nsv_incr acs_mail_lite send_mails_p -1 return } with_finally -code { db_foreach get_queued_messages {} { # check if record is already there and free to use set return_id [db_string get_queued_message {} -default -1] if {$return_id == $id} { # lock this record for exclusive use set locking_server [ad_url] db_dml lock_queued_message {} # send the mail set err [catch { acs_mail_lite::send_immediately \ -to_addr $to_addr \ -cc_addr $cc_addr \ -bcc_addr $bcc_addr \ -from_addr $from_addr \ -reply_to $reply_to \ -subject $subject \ -body $body \ -package_id $package_id \ -file_ids $file_ids \ -mime_type $mime_type \ -no_callback_p $no_callback_p \ -extraheaders $extraheaders \ -use_sender_p $use_sender_p } errMsg] if {$err} { ns_log Error "Error while sending queued mail: $errMsg" # release the lock set locking_server "" db_dml lock_queued_message {} } else { # mail was sent, delete the queue entry db_dml delete_queue_entry {} } } } } -finally { nsv_incr acs_mail_lite send_mails_p -1 } } #--------------------------------------- ad_proc -private send_immediately { {-valid_email_p "0"} -to_addr:required {-cc_addr ""} {-bcc_addr ""} -from_addr:required {-reply_to ""} {-subject ""} -body:required {-package_id ""} {-file_ids ""} {-mime_type "text/plain"} {-no_callback_p "0"} {-extraheaders ""} {-use_sender_p "0"} {-object_id ""} } { Prepare an email to be send immediately with the option to pass in a list of file_ids as well as specify an html_body and a mime_type. It also supports multiple "TO" recipients as well as CC and BCC recipients. Runs entirely off MIME and SMTP to achieve this. @param to_addr List of e-mail addresses to send this mail to. @param from_addr E-Mail address of the sender. @param reply_to E-Mail address to which replies should go. Defaults to from_addr @param subject of the email @param body Text body of the email @param cc_addr List of CC Users e-mail addresses to send this mail to. @param bcc_addr List of CC Users e-mail addresses to send this mail to. @param package_id Package ID of the sending package @param file_ids List of file ids (items or revisions) to be send as attachments. This will only work with files stored in the file system. @param mime_type MIME Type of the mail to send out. Can be "text/plain", "text/html". @param extraheaders List of keywords and their values passed in for headers. Interesting ones are: "Precedence: list" to disable autoreplies and mark this as a list message. This is as list of lists !! @param no_callback_p Indicates if callback should be executed or not. If you don't provide it it will execute callbacks. @param use_sender_p Boolean indicating that from_addr should be used regardless of fixed-sender parameter @param object_id Object id that caused this email to be sent } { # Package_id required by the callback (emmar: no idea what for) set mail_package_id [apm_package_id_from_key "acs-mail-lite"] if {$package_id eq ""} { set package_id $mail_package_id } # Decide which sender to use set fixed_sender [parameter::get -parameter "FixedSenderEmail" \ -package_id $mail_package_id] if { $fixed_sender ne "" && !$use_sender_p} { set from_addr $fixed_sender } # Set the Reply-To if {$reply_to eq ""} { set reply_to $from_addr } # Set the message_id set message_id "[mime::uniqueID]" # Set the date set message_date [acs_mail_lite::utils::build_date] # Build the message body set tokens [acs_mail_lite::utils::build_body -mime_type $mime_type -- $body] # Add attachments if any if {[exists_and_not_null file_ids]} { set item_ids [list] # Check if we are dealing with revisions or items. foreach file_id $file_ids { set item_id [content::revision::item_id -revision_id $file_id] if {$item_id eq ""} { lappend item_ids $file_id } else { lappend item_ids $item_id } } db_foreach get_file_info {} { lappend tokens [mime::initialize \ -param [list name "[ad_quotehtml $title]"] \ -header [list "Content-Disposition" "attachment; filename=\"$name\""] \ -header [list Content-Description $title] \ -canonical $mime_type \ -file "[cr_fs_path]$filename"] } set tokens [mime::initialize -canonical "multipart/mixed" -parts "$tokens"] } ### Add the headers mime::setheader $tokens "message-id" $message_id mime::setheader $tokens date $message_date # Set the subject if { $subject ne "" } { set subject [acs_mail_lite::utils::build_subject $subject] mime::setheader $tokens Subject $subject } # Add extra headers foreach header $extraheaders { mime::setheader $tokens "[lindex $header 0]" "[lindex $header 1]" } # Rollout support set delivery_mode [parameter::get -package_id [get_package_id] -parameter EmailDeliveryMode -default default] switch $delivery_mode { log { set send_mode "log" set notice "logging email instead of sending" } filter { set send_mode "smtp" set allowed_addr [parameter::get -package_id [get_package_id] -parameter EmailAllow] foreach recipient [concat $to_addr $cc_addr $bcc_addr] { # if any of the recipient is not in the allowed list # email message has to be sent to the log instead if { [lsearch -exact $allowed_addr $recipient] eq -1 } { set send_mode "log" set notice "logging email because one of the recipient ($recipient) is not in the EmailAllow list" break } } } redirect { set send_mode "smtp" # Since we have to redirect to a list of addresses # we need to remove the CC and BCC ones set to_addr [parameter::get -package_id [get_package_id] -parameter EmailRedirectTo] set cc_addr "" set bcc_addr "" } default { set send_mode "smtp" } } # Prepare the headers list of recipients set headers_list [list [list From "$from_addr"] \ [list Reply-To "$reply_to"] \ [list To [join $to_addr ","]]] if { $cc_addr ne "" } { lappend headers_list [list CC [join $cc_addr ","]] } if { $bcc_addr ne ""} { # BCC implementation in tcllib 1.8 to 1.11 is awkward. It # sends the blind copy as an attachment, changes the From # header replacing it with the originator, etc. So we use # DCC instead which behaves as one would expect Bcc to # behave. lappend headers_list [list DCC [join $bcc_addr ","]] } # Build the originator address to be used as enveloppe sender set rcpt_id 0 if { [llength $to_addr] eq 1 } { set rcpt_id [party::get_by_email -email $to_addr] } set rcpt_id [ad_decode $rcpt_id "" 0 $rcpt_id] set originator [bounce_address -user_id $rcpt_id \ -package_id $package_id \ -message_id $message_id] if { $send_mode eq "log" } { # Add recipients to headers foreach header $headers_list { mime::setheader $tokens "[lindex $header 0]" "[lindex $header 1]" } # Retrieve the email message as a string set packaged [mime::buildmessage $tokens] # Close all mime tokens mime::finalize $tokens -subordinates all # Send the email message to the log ns_log Notice "acs-mail-lite::send: $notice\n\n**********\nEnveloppe sender: $originator\n\n$packaged\n**********" } else { acs_mail_lite::smtp -multi_token $tokens \ -headers $headers_list \ -originator $originator # Close all mime tokens mime::finalize $tokens -subordinates all } if { !$no_callback_p } { callback acs_mail_lite::send \ -package_id $package_id \ -message_id $message_id \ -from_addr $from_addr \ -to_addr $to_addr \ -body $body \ -mime_type $mime_type \ -subject $subject \ -cc_addr $cc_addr \ -bcc_addr $bcc_addr \ -file_ids $file_ids \ -object_id $object_id } } #--------------------------------------- ad_proc -private message_interpolate { {-values:required} {-text:required} } { Interpolates a set of values into a string. This is directly copied from the bulk mail package @param values a list of key, value pairs, each one consisting of a target string and the value it is to be replaced with. @param text the string that is to be interpolated @return the interpolated string } { foreach pair $values { regsub -all [lindex $pair 0] $text [lindex $pair 1] text } return $text } #--------------------------------------- ad_proc -public -deprecated sendmail { to from subject body {extraheaders {}} {bcc {}} } { Replacement for ns_sendmail for backward compability. } { ns_log Warning "ns_sendmail is no longer supported in OpenACS. Use acs_mail_lite::send instead." set extraheaders_list [list] if { $extraheaders ne "" } { foreach {key value} [util_ns_set_to_list -set $extraheaders] { lappend extraheaders_list [list $key $value] } } acs_mail_lite::send \ -to_addr [split $to ","] \ -from_addr $from \ -subject $subject \ -body $body \ -bcc_addr [split $bcc ","] \ -extraheaders $extraheaders_list } } openacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-procs.xql0000755000175000017500000000262410741175622024263 0ustar frankiefrankie select person_id as user_id, first_names || ' ' || last_name as user_name from parties, persons where email = :email and party_id = person_id order by party_id desc limit 1 select message_id as id from acs_mail_lite_queue where message_id=:id and (locking_server = '' or locking_server is NULL) update acs_mail_lite_queue set locking_server = :locking_server where message_id=:id delete from acs_mail_lite_queue where message_id=:id select r.mime_type,r.title, r.content as filename, i.name from cr_revisions r, cr_items i where r.revision_id = i.latest_revision and i.item_id in ([join $item_ids ","]) openacs-5.7.0/packages/acs-mail-lite/tcl/apm-callback-procs.tcl0000644000175000017500000000214410741140744024116 0ustar frankiefrankiead_library { Installation procs for acs-mail-lite @author Emmanuelle Raffenne (eraffenne@gmail.com) } namespace eval acs_mail_lite {} ad_proc -private acs_mail_lite::after_upgrade { {-from_version_name:required} {-to_version_name:required} } { After upgrade callback for acs-mail-lite } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { 5.4.0d2 5.4.0d3 { db_transaction { db_dml remove_param_values { delete from apm_parameter_values where parameter_id in (select parameter_id from apm_parameters where package_key = 'acs-mail-lite' and parameter_name='SendmailBin') } db_dml remove_param { delete from apm_parameters where package_key = 'acs-mail-lite' and parameter_name='SendmailBin' } } on_error { ns_log Error "acs-mail-lite::after_upgrade from 5.4.0d2 to 5.4.0d3: $errmsg" } } } } openacs-5.7.0/packages/acs-mail-lite/tcl/incoming-mail-procs.tcl0000644000175000017500000002207611456662500024343 0ustar frankiefrankiead_library { Provides a simple API for reliably sending email. @author Eric Lorenzo (eric@openforce.net) @creation-date 22 March 2002 @cvs-id $Id: incoming-mail-procs.tcl,v 1.5 2010/10/17 21:06:08 donb Exp $ } package require mime 1.4 package require smtp 1.4 package require base64 2.3.1 namespace eval acs_mail_lite { #--------------------------------------- ad_proc -public address_domain {} { @return domain address to which bounces are directed to } { set domain [parameter::get_from_package_key -package_key "acs-mail-lite" -parameter "BounceDomain"] if { $domain eq "" } { regsub {http://} [ns_config ns/server/[ns_info server]/module/nssock hostname] {} domain } return $domain } #--------------------------------------- ad_proc -private load_mails { -queue_dir:required } { Scans for incoming email. You need An incoming email has to comply to the following syntax rule: [][-]-Whatever@ [] = optional <> = Package Parameters If no SitePrefix is set we assume that there is only one OpenACS installation. Otherwise only messages are dealt with which contain a SitePrefix. ReplyPrefixes are provided by packages that implement the callback acs_mail_lite::incoming_email and provide a package parameter called ReplyPrefix. Only implementations are considered where the implementation name is equal to the package key of the package. Also we only deal with messages that contain a valid and registered ReplyPrefix. These prefixes are automatically set in the acs_mail_lite_prefixes table. @author Nima Mazloumi (nima.mazloumi@gmx.de) @creation-date 2005-07-15 @option queue_dir The location of the qmail mail (BounceMailDir) queue in the file-system i.e. /home/service0/mail. @see acs_mail_lite::incoming_email @see acs_mail_lite::parse_email } { # get list of all incoming mail if {[catch { set messages [glob "$queue_dir/new/*"] } errmsg]} { if {[string match "no files matched glob pattern*" $errmsg ]} { ns_log Debug "load_mails: queue dir = $queue_dir/new/*, no messages" } else { ns_log Error "load_mails: queue dir = $queue_dir/new/ error $errmsg" } return [list] } # loop over every incoming mail foreach msg $messages { ns_log Debug "load_mails: opening $msg" array set email {} # This will parse the E-mail and extract the files to the file system parse_email -file $msg -array email set email(to) [parse_email_address -email $email(to)] set email(from) [parse_email_address -email $email(from)] set subject [lindex $email(subject) 0] if {$email(bodies) eq ""} { ad_script_abort ns_log Notice "E-Mail without body" } # Do no execute any callbacks if the email is an autoreply. # Thanks to Vinod for the idea and the code set callback_executed_p [acs_mail_lite::autoreply_p -subject $subject -from $email(from)] if {!$callback_executed_p} { # Special treatment for e-mails which look like they contain an object_id set pot_object_id [lindex [split $email(to) "@"] 0] ns_log Debug "Object_id for mail:: $pot_object_id" if {[ad_var_type_check_number_p $pot_object_id]} { if {[acs_object::object_p -id $pot_object_id]} { callback acs_mail_lite::incoming_object_email -array email -object_id $pot_object_id # Mark that the callback has been executed already set no_callback_p 1 } } } if {!$callback_executed_p} { # We execute all callbacks now callback acs_mail_lite::incoming_email -array email } #let's delete the file now if {[catch {ns_unlink $msg} errmsg]} { ns_log Error "load_mails: unable to delete queued message $msg: $errmsg" } else { ns_log Debug "load_mails: deleted $msg" } } } #--------------------------------------- ad_proc parse_email { -file:required -array:required } { An email is splitted into several parts: headers, bodies and files lists and all headers directly. The headers consists of a list with header names as keys and their correponding values. All keys are lower case. The bodies consists of a list with two elements: content-type and content. The files consists of a list with three elements: content-type, filename and content. The array with all the above data is upvared to the caller environment. Important headers are: -message-id (a unique id for the email, is different for each email except it was bounced from a mailer deamon) -subject -from -to Others possible headers: -date -received -references (this references the original message id if the email is a reply) -in-reply-to (this references the original message id if the email is a reply) -return-path (this is used for mailer deamons to bounce emails back like bounce-user_id-signature-package_id@service0.com) Optional application specific stuff only exist in special cases: X-Mozilla-Status X-Virus-Scanned X-Mozilla-Status2 X-UIDL X-Account-Key X-Sasl-enc You can therefore get a value for a header either through iterating the headers list or simply by calling i.e. "set message_id $email(message-id)". Note: We assume "application/octet-stream" for all attachments and "base64" for as transfer encoding for all files. Note: tcllib required - mime, base64 @author Nima Mazloumi (nima.mazloumi@gmx.de) @creation-date 2005-07-15 } { upvar $array email #prepare the message if {[catch {set mime [mime::initialize -file $file]} errormsg]} { ns_log error "Email could not be delivered for file $file" set stream [open $file] set content [read $stream] close $stream ns_log error "$content" ns_unlink $file return } #get the content type set content [mime::getproperty $mime content] #get all available headers set keys [mime::getheader $mime -names] set headers [list] # create both the headers array and all headers directly for the email array foreach header $keys { set value [mime::getheader $mime $header] set email([string tolower $header]) $value lappend headers [list $header $value] } set email(headers) $headers #check for multipart, otherwise we only have one part if { [string first "multipart" $content] != -1 } { set parts [mime::getproperty $mime parts] } else { set parts [list $mime] } # travers the tree and extract parts into a flat list set all_parts [list] foreach part $parts { if {[mime::getproperty $part content] eq "multipart/alternative"} { foreach child_part [mime::getproperty $part parts] { lappend all_parts $child_part } } else { lappend all_parts $part } } set bodies [list] set files [list] #now extract all parts (bodies/files) and fill the email array foreach part $all_parts { # Attachments have a "Content-disposition" part # Therefore we filter out if it is an attachment here if {[catch {mime::getheader $part Content-disposition}] || [mime::getheader $part Content-disposition] eq "inline"} { switch [mime::getproperty $part content] { "text/plain" { lappend bodies [list "text/plain" [mime::getbody $part]] } "text/html" { lappend bodies [list "text/html" [mime::getbody $part]] } } } else { set encoding [mime::getproperty $part encoding] set body [mime::getbody $part -decode] set content $body set params [mime::getproperty $part params] array set param $params # Append the file if there exist a filename to use. Otherwise do not append if {[exists_and_not_null param(name)]} { set filename $param(name) # Determine the content_type set content_type [mime::getproperty $part content] if {$content_type eq "application/octet-stream"} { set content_type [ns_guesstype $filename] } lappend files [list $content_type $encoding $filename $content] } } } set email(bodies) $bodies set email(files) $files #release the message mime::finalize $mime -subordinates all } ad_proc -public autoreply_p { {-subject ""} {-from ""} } { Parse the subject, from and body to determin if the email is an auto reply Typical autoreplies are "Out of office" messages. This is what the procedure does @param subject Subject of the Email that will be scanned for "out of office" @param from From address which will be checked if it is coming from a mailer daemon @return 1 if this is actually an autoreply } { set autoreply_p 0 if {$subject ne ""} { # check subject set autoreply_p [regexp -nocase "(out of.*office|automated response|autoreply)" $subject] set autoreply_p [regexp "NDN" $subject] set autoreply_p [regexp "\[QuickML\] Error" $subject] } if {$from ne ""} { # check from if it comes from the mailer daemon set autoreply_p [regexp -nocase "mailer.*daemon" $from] } return $autoreply_p } }openacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-init.tcl0000644000175000017500000000230111347672463024053 0ustar frankiefrankiead_library { initialization for acs_mail_lite module @author Eric Lorenzo (eric@openforce.net) @creation-date 22 March, 2002 @cvs-id $Id: acs-mail-lite-init.tcl,v 1.13 2010/03/16 12:10:27 emmar Exp $ } # Default interval is about one minute (reduce lock contention with other jobs scheduled at full minutes) ad_schedule_proc -thread t 61 acs_mail_lite::sweeper set queue_dir [parameter::get_from_package_key -parameter "BounceMailDir" -package_key "acs-mail-lite"] if {$queue_dir ne ""} { # if BounceMailDir is set then handle incoming mail ad_schedule_proc -thread t 120 acs_mail_lite::load_mails -queue_dir $queue_dir } # check every few minutes for bounces #ad_schedule_proc -thread t [acs_mail_lite::get_parameter -name BounceScanQueue -default 120] acs_mail_lite::scan_replies nsv_set acs_mail_lite send_mails_p 0 nsv_set acs_mail_lite check_bounce_p 0 # ad_schedule_proc -thread t -schedule_proc ns_schedule_daily [list 0 25] acs_mail_lite::check_bounces # Redefine ns_sendmail as a wrapper for acs_mail_lite::send ns_log Notice "acs-mail-lite: renaming acs_mail_lite::sendmail to ns_sendmail" rename ns_sendmail _old_ns_sendmail rename acs_mail_lite::sendmail ns_sendmail openacs-5.7.0/packages/acs-mail-lite/tcl/bounce-procs-oracle.xql0000644000175000017500000000321510606355251024350 0ustar frankiefrankie oracle8.1.6 insert into acs_mail_lite_bounce_notif (party_id, notification_count, notification_time) (select user_id, 0 as notification_count, trunc(sysdate-1-:notification_interval) as notification_time from acs_mail_lite_bounce where bounce_count >= :max_bounce_count) select u.user_id, u.email, u.first_names || ' ' || u.last_name as name from cc_users u, acs_mail_lite_bounce_notif n where u.user_id = n.party_id and u.email_bouncing_p = 't' and n.notification_time < sysdate - :notification_interval and n.notification_count < :max_notification_count update acs_mail_lite_bounce_notif set notification_time = trunc(sysdate), notification_count = notification_count + 1 where party_id = :user_id delete from acs_mail_lite_bounce where party_id in (select party_id from acs_mail_lite_mail_log where last_mail_date < sysdate - :max_days_to_bounce) openacs-5.7.0/packages/acs-mail-lite/tcl/acs-mail-lite-procs-postgresql.xql0000644000175000017500000000543611061305203026447 0ustar frankiefrankie postgresql7.1 insert into acs_mail_lite_queue (message_id, creation_date, locking_server, to_addr, cc_addr, bcc_addr, from_addr, reply_to, subject, body, package_id, file_ids, mime_type, no_callback_p, extraheaders, use_sender_p, object_id ) values (nextval('acs_mail_lite_id_seq'), :creation_date, :locking_server, :to_addr, :cc_addr, :bcc_addr, :from_addr, :reply_to, :subject, :body, :package_id, :file_ids, :mime_type, (case when :no_callback_p = '1' then TRUE else FALSE end), :extraheaders, (case when :use_sender_p = '1' then TRUE else FALSE end), :object_id ) update acs_mail_lite_mail_log set last_mail_date = current_timestamp where party_id = :user_id insert into acs_mail_lite_mail_log (party_id, last_mail_date) values (:user_id, current_timestamp) select message_id as id, creation_date, locking_server, to_addr, cc_addr, bcc_addr, from_addr, reply_to, subject, body, package_id, file_ids, mime_type, (case when no_callback_p = TRUE then 1 else 0 end) as no_callback_p, extraheaders, (case when use_sender_p = TRUE then 1 else 0 end) as use_sender_p, object_id from acs_mail_lite_queue where locking_server = '' or locking_server is NULL openacs-5.7.0/packages/acs-mail-lite/tcl/utils-procs.tcl0000644000175000017500000001220611054043367022750 0ustar frankiefrankie# packages/acs-mail-lite/tcl/utils-procs.tcl ad_library { Helper procs to build email messages @author Emmanuelle Raffenne (eraffenne@gmail.com) @creation-date 2007-12-16 @arch-tag: 820de9a9-533f-4fc3-b11d-2c9fb616a620 @cvs-id $Id: utils-procs.tcl,v 1.4 2008/08/23 17:20:55 gustafn Exp $ } namespace eval acs_mail_lite {} namespace eval acs_mail_lite::utils {} package require mime ad_proc acs_mail_lite::utils::build_subject { {-charset "UTF-8"} subject } { Encode the subject, using quoted-printable, of an email message and trim long lines. Depending on the available mime package version, it uses either the mime::word_encode proc to do it or local code (word_encode is buggy in mime < 1.5.2 ) } { set charset [string toupper $charset] set charset_code [ns_encodingforcharset $charset] # maxlen for each line # 69 = 76 - 7 where 7 is for "=?"+"?Q?+"?=" set maxlen [expr {69 - [string length $charset]}] set result "" set line "" set i 0 set subject_length [string length $subject] while { $i < $subject_length } { set chunk [string index $subject $i] # encode that chunk set chunk [encoding convertto $charset_code "$chunk"] if { $chunk eq "\x3F" } { # ER: workaround (kludge!) for tcllib error set chunk "=3F" } else { set chunk [mime::qp_encode "$chunk" 1 0] } set newline $line append newline $chunk if { [string length $newline] <= $maxlen } { append line $chunk } else { append result "=?$charset?Q?$line?=\n " set line $chunk } incr i } if { $line ne "" } { append result "=?$charset?Q?$line?=" } return $result } ad_proc acs_mail_lite::utils::build_date { {date ""} } { Depending on the available mime package version, it uses either the mime::parsedatetime to do it or local code (parsedatetime is buggy in mime < 1.5.2 ) @param date A 822-style date-time specification "YYYYMMDD HH:MI:SS" } { if { $date eq "" } { set clock [clock seconds] set date [clock format $clock -format "%Y-%m-%d %H:%M:%S"] } else { set clock [clock scan $date] } if { [catch {package require mime 1.5.2}] } { set gmt [clock format $clock -format "%Y-%m-%d %H:%M:%S" -gmt true] if {[set diff [expr {($clock-[clock scan $gmt])/60}]] < 0} { set s - set diff [expr {-($diff)}] } else { set s + } set zone [format %s%02d%02d $s [expr {$diff/60}] [expr {$diff%60}]] set wdays_short [list Sun Mon Tue Wed Thu Fri Sat] set months_short [list Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec] set wday [lindex $wdays_short [clock format $clock -format %w]] set mon [lindex $months_short [expr {[string trimleft [clock format $clock -format %m] 0] - 1}]] set result [clock format $clock -format "$wday, %d $mon %Y %H:%M:%S $zone"] } else { set result [mime::parsedatetime $date proper] } return $result } ad_proc acs_mail_lite::utils::build_body { {-mime_type "text/plain"} {-charset "UTF-8"} body } { Encode the body using quoted-printable and build the alternative part if necessary Return a list of message tokens } { # Encode the body set encoding [ns_encodingforcharset $charset] set body [encoding convertto $encoding $body] if { $mime_type eq "text/plain" } { # Set the message token set message_token [mime::initialize \ -canonical "$mime_type" \ -param [list charset $charset] \ -encoding "quoted-printable" \ -string "$body"] } else { set message_html_part [mime::initialize \ -canonical "text/html" \ -param [list charset $charset] \ -encoding "quoted-printable" \ -string "$body"] set message_text_part [mime::initialize \ -canonical "text/plain" \ -param [list charset $charset] \ -encoding "quoted-printable" \ -string [ad_html_to_text "$body"]] set message_token [mime::initialize \ -canonical "multipart/alternative" \ -parts [list $message_text_part $message_html_part]] } return [list $message_token] } ad_proc -public acs_mail_lite::utils::valid_email_p { email } { Checks if the email is valid. Returns 1 if it is. Uses mime::parsemail to determine this } { array set test [lindex [mime::parseaddress "$email"] 0] if {$email ne $test(proper)} { regsub "\"" $test(proper) "" proper if {$email ne $proper} { return 0 } else { return 1 } } else { return 1 } } openacs-5.7.0/packages/acs-mail-lite/sql/0000755000175000017500000000000011724401447017775 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/sql/oracle/0000755000175000017500000000000011724401447021242 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/sql/oracle/acs-mail-lite-create.sql0000644000175000017500000000445611160274213025647 0ustar frankiefrankie-- -- A simple mail queue -- -- @author eric@openforce.net -- @version $Id: acs-mail-lite-create.sql,v 1.13 2009/03/18 22:41:15 emmar Exp $ -- create sequence acs_mail_lite_id_seq; CREATE TABLE acs_mail_lite_queue ( message_id integer constraint acs_mail_lite_queue_pk PRIMARY KEY, creation_date varchar(4000), locking_server varchar(4000), to_addr varchar(4000), cc_addr clob, bcc_addr clob, from_addr varchar(400), reply_to varchar(400), subject varchar(4000), body clob, package_id integer constraint amlq_package_id_fk references apm_packages, file_ids varchar(4000), mime_type varchar(200), object_id integer, no_callback_p char(1) constraint amlq_no_callback_p_ck check (no_callback_p in ('t','f')), extraheaders clob, use_sender_p char(1) constraint amlq_use_sender_p_ck check (use_sender_p in ('t','f')) ); create table acs_mail_lite_mail_log ( party_id integer constraint acmlml_party_id_fk references parties (party_id) on delete cascade constraint acs_mail_lite_log_pk primary key, last_mail_date date default sysdate ); create table acs_mail_lite_bounce ( party_id integer constraint acmlb_party_id_fk references parties (party_id) on delete cascade constraint acs_mail_lite_bou_pk primary key, bounce_count integer default 1 ); create table acs_mail_lite_bounce_notif ( party_id integer constraint amlbn_party_id_fk references parties (party_id) on delete cascade constraint acs_mail_lite_notif_pk primary key, notification_time date default sysdate, notification_count integer default 0 ); openacs-5.7.0/packages/acs-mail-lite/sql/oracle/acs-mail-lite-drop.sql0000644000175000017500000000054611160274213025344 0ustar frankiefrankie-- -- A simple mail queue -- -- @author eric@openforce.net -- @version $Id: acs-mail-lite-drop.sql,v 1.5 2009/03/18 22:41:15 emmar Exp $ -- drop table acs_mail_lite_queue; drop sequence acs_mail_lite_id_seq; drop table acs_mail_lite_mail_log; drop table acs_mail_lite_bounce; drop table acs_mail_lite_bounce_notif; openacs-5.7.0/packages/acs-mail-lite/sql/oracle/upgrade/0000755000175000017500000000000011575225527022700 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/sql/oracle/upgrade/upgrade-5.4.0d1-5.4.0d2.sql0000644000175000017500000000165511160274213026620 0ustar frankiefrankie-- Make sure that emails are going to parties not to users and -- therefore logging is for parties, not for users. alter table acs_mail_lite_mail_log add party_id integer constraint amlml_party_id_fk references parties(party_id) on delete cascade; update acs_mail_lite_mail_log set party_id = user_id; alter table acs_mail_lite_mail_log drop column user_id; alter table acs_mail_lite_bounce add party_id integer constraint amlb_party_id_fk references parties(party_id) on delete cascade; update acs_mail_lite_bounce set party_id = user_id; alter table acs_mail_lite_bounce drop column user_id; alter table acs_mail_lite_bounce_notif drop constraint acs_mail_li_bou_notif_us_id_fk; alter table acs_mail_lite_bounce_notif add party_id integer constraint amlbn_party_id_fk references parties (party_id) on delete cascade; update acs_mail_lite_bounce_notif set party_id = user_id; alter table acs_mail_lite_bounce_notif drop column user_id; openacs-5.7.0/packages/acs-mail-lite/sql/oracle/upgrade/acs-mail-lite-upgrade-0.1d-0.2a.sql0000644000175000017500000000307310064053206030551 0ustar frankiefrankiealter table acs_mail_lite_queue add (package_id integer constraint acs_mail_lite_queue_pck_fk references apm_packages); alter table acs_mail_lite_queue add (valid_email_p varchar2(1) constraint acs_mail_lite_qu_valid_em_p_ck check (valid_email_p in ('t','f'))); create table acs_mail_lite_mail_log ( user_id integer constraint acs_mail_lite_log_user_id_fk references users (user_id) on delete cascade constraint acs_mail_lite_log_pk primary key, last_mail_date date default sysdate ); create table acs_mail_lite_bounce ( user_id integer constraint acs_mail_lite_bou_user_id_fk references users (user_id) on delete cascade constraint acs_mail_lite_bou_pk primary key, bounce_count integer default 1 ); create table acs_mail_lite_bounce_notif ( user_id integer constraint acs_mail_li_bou_notif_us_id_fk references users (user_id) on delete cascade constraint acs_mail_lite_notif_pk primary key, notification_time date default sysdate, notification_count integer default 0 ); openacs-5.7.0/packages/acs-mail-lite/sql/oracle/upgrade/upgrade-5.4.0d2-5.4.0d3.sql0000644000175000017500000000266410742372443026634 0ustar frankiefrankie-- acs-mail-lite/sql/oracle/upgrade/upgrade-5.4.0d2-5.4.0d3.sql -- -- Upgrade acs_mail_lite_queue; -- -- new columns alter table acs_mail_lite_queue add creation_date varchar(4000); alter table acs_mail_lite_queue add locking_server varchar(4000); alter table acs_mail_lite_queue add cc_addr clob; alter table acs_mail_lite_queue add reply_to varchar(400); alter table acs_mail_lite_queue add file_ids varchar(4000); alter table acs_mail_lite_queue add mime_type varchar(200); alter table acs_mail_lite_queue add object_id integer; alter table acs_mail_lite_queue add no_callback_p char(1) constraint amlq_no_callback_p_ck check (no_callback_p in ('t','f')); alter table acs_mail_lite_queue add use_sender_p char(1) constraint amlq_use_sender_p_ck check (use_sender_p in ('t','f')); -- renamed columns alter table acs_mail_lite_queue rename column bcc to bcc_addr; alter table acs_mail_lite_queue rename column extra_headers to extraheaders; -- datatype changes alter table acs_mail_lite_queue modify to_addr varchar(4000); alter table acs_mail_lite_queue modify from_addr varchar(400); alter table acs_mail_lite_queue modify subject varchar(4000); openacs-5.7.0/packages/acs-mail-lite/sql/postgresql/0000755000175000017500000000000011575225527022207 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/sql/postgresql/acs-mail-lite-create.sql0000644000175000017500000000405111160274213026574 0ustar frankiefrankie-- -- A simple mail queue -- -- @author eric@openforce.net -- @version $Id: acs-mail-lite-create.sql,v 1.12 2009/03/18 22:41:15 emmar Exp $ -- create sequence acs_mail_lite_id_seq; CREATE TABLE acs_mail_lite_queue ( message_id integer constraint acs_mail_lite_queue_pk primary key, creation_date text, locking_server text, to_addr text, cc_addr text, bcc_addr text, from_addr text, reply_to text, subject text, body text, package_id integer constraint amlq_package_id_fk references apm_packages, file_ids text, mime_type text, object_id integer, no_callback_p boolean, extraheaders text, use_sender_p boolean ); create table acs_mail_lite_mail_log ( party_id integer constraint amlml_party_id_fk references parties (party_id) on delete cascade constraint acs_mail_lite_log_pk primary key, last_mail_date timestamptz default current_timestamp ); create table acs_mail_lite_bounce ( party_id integer constraint amlb_party_id_fk references parties (party_id) on delete cascade constraint acs_mail_lite_bou_pk primary key, bounce_count integer default 1 ); create table acs_mail_lite_bounce_notif ( party_id integer constraint amlbn_party_id_fk references parties (party_id) on delete cascade constraint acs_mail_lite_bounce_notif_pk primary key, notification_time timestamptz default current_timestamp, notification_count integer default 0 ); openacs-5.7.0/packages/acs-mail-lite/sql/postgresql/acs-mail-lite-drop.sql0000644000175000017500000000054611160274213026302 0ustar frankiefrankie-- -- A simple mail queue -- -- @author eric@openforce.net -- @version $Id: acs-mail-lite-drop.sql,v 1.6 2009/03/18 22:41:15 emmar Exp $ -- drop table acs_mail_lite_queue; drop sequence acs_mail_lite_id_seq; drop table acs_mail_lite_mail_log; drop table acs_mail_lite_bounce; drop table acs_mail_lite_bounce_notif; openacs-5.7.0/packages/acs-mail-lite/sql/postgresql/upgrade/0000755000175000017500000000000011575225527023636 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/sql/postgresql/upgrade/upgrade-5.4.0d1-5.4.0d2.sql0000644000175000017500000000170111160274213027546 0ustar frankiefrankie-- Make sure that emails are going to parties not to users and -- therefore logging is for parties, not for users. alter table acs_mail_lite_mail_log add column party_id integer constraint amlml_party_id_fk references parties(party_id) on delete cascade; update acs_mail_lite_mail_log set party_id = user_id; alter table acs_mail_lite_mail_log drop column user_id; alter table acs_mail_lite_bounce add column party_id integer constraint amlb_party_id_fk references parties(party_id) on delete cascade; update acs_mail_lite_bounce set party_id = user_id; alter table acs_mail_lite_bounce drop column user_id; alter table acs_mail_lite_bounce_notif drop constraint acs_mail_li_bou_notif_us_id_fk; alter table acs_mail_lite_bounce_notif add column party_id integer constraint amlbn_party_id_fk references parties(party_id) on delete cascade; update acs_mail_lite_bounce_notif set party_id = user_id; alter table acs_mail_lite_bounce_notif drop column user_id; openacs-5.7.0/packages/acs-mail-lite/sql/postgresql/upgrade/acs-mail-lite-upgrade-0.1d-0.2a.sql0000644000175000017500000000302510001260335031476 0ustar frankiefrankiealter table acs_mail_lite_queue add column package_id integer constraint acs_mail_lite_queue_pck_fk references apm_packages; alter table acs_mail_lite_queue add column valid_email_p boolean; create table acs_mail_lite_mail_log ( user_id integer constraint acs_mail_lite_log_user_id_fk references users (user_id) on delete cascade constraint acs_mail_lite_log_pk primary key, last_mail_date timestamptz default current_timestamp ); create table acs_mail_lite_bounce ( user_id integer constraint acs_mail_lite_bou_user_id_fk references users (user_id) on delete cascade constraint acs_mail_lite_bou_pk primary key, bounce_count integer default 1 ); create table acs_mail_lite_bounce_notif ( user_id integer constraint acs_mail_li_bou_notif_us_id_fk references users (user_id) on delete cascade constraint acs_mail_lite_notif_pk primary key, notification_time timestamptz default current_timestamp, notification_count integer default 0 ); openacs-5.7.0/packages/acs-mail-lite/sql/postgresql/upgrade/upgrade-5.4.0d2-5.4.0d3.sql0000644000175000017500000000155210741201627027557 0ustar frankiefrankie-- acs-mail-lite/sql/postgresql/upgrade/upgrade-5.4.0d2-5.4.0d3.sql -- -- Modify acs_mail_lite_queue -- -- New columns alter table acs_mail_lite_queue add column creation_date text, add column locking_server text, add column cc_addr text, add column reply_to text, add column file_ids text, add column mime_type text, add column object_id integer, add column no_callback_p boolean, add column use_sender_p boolean; -- Renamed columns alter table acs_mail_lite_queue rename column bcc to bcc_addr; alter table acs_mail_lite_queue rename column extra_headers to extraheaders; -- Column datatype changes alter table acs_mail_lite_queue alter column from_addr type text, alter column subject type text; openacs-5.7.0/packages/acs-mail-lite/www/0000755000175000017500000000000011575225530020023 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/www/doc/0000755000175000017500000000000011724401447020567 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/www/doc/index.html0000644000175000017500000000674610046743605022602 0ustar frankiefrankie User Documentation for ACS Mail Lite

    User Documentation for ACS Mail Lite

    Acs Mail Lite handles sending of email via sendmail or smtp and includes a bounce management system for invalid email accounts.

    When called to send a mail, the mail will either get sent immediately or placed in an outgoing queue (changeable via parameter) which will be processed every few minutes.

    ACS Mail Lite uses either sendmail (you have to provide the location of the binary as a parameter) or SMTP to send the mail. If the sending fails, the mail will be placed in the outgoing queue again and be given another try a few minutes later when processing the queue again.

    Each email contains an X-Envelope-From adress constructed as follows:
    The adress starts with "bounce" (can be changed by a parameter) followed by the user_id, a hashkey and the package_id of the package instance that sent the email, separated by "-". The domain name of this adress can be changed with a parameter.

    The system checks every 2 minutes (configurable) in a certain maildirectory (configurable) for newly bounced emails, so the mailsystem will have to place every mail to an address beginning with "bounce" (or whatever the appropriate parameter says) in that directory. The system then processes each of the bounced emails, strips out the message_id and verifies the hashkey in the bounce-address. After that the package-key of the package sending the original mail is found out by using the package_id provided in the bounce adress. With that, the system then tries to invoke a callback procedure via a service contract if one is registered for that particular package-key. This enables each package to deal with bouncing mails on their own - probably logging this in special tables. ACS Mail Lite then logs the event of a bounced mail of that user.

    Every day a procedure is run that checks if an email account has to be disabled from receiving any more mail. This is done the following way:

    • If a user received his last mail X days ago without any further bounced mail then his bounce-record gets deleted since it can be assumed that his email account is working again and no longer refusing emails. This value can be changed with the parameter "MaxDaysToBounce".
    • If more then Y emails were returned by a particular user then his email account gets disabled from receiving any more mails from the system by setting the email_bouncing_p flag to t. This value can be changed with the parameter "MaxBounceCount".
    • To notify users that they will not receive any more mails and to tell them how to reenable the email account in the system again, a notification email gets sent every 7 days (configurable) up to 4 times (configurable) that contains a link to reenable the email account.
    To use this system here is a quick guide how to do it with postfix.
    • Edit /etc/postfix/main.cf
      • Set "recipient_delimiter" to " - "
      • Set "home_mailbox" to "Maildir/"
      • Make sure that /etc/postfix/aliases is hashed for the alias database
    • Edit /etc/postfix/aliases. Redirect all mail to "bounce" (if you leave the parameter as it was) to "nsadmin" (in case you only run one server).
    In case of multiple services on one system, create a bounce email for each of them (e.g. changeing "bounce" to "bounce_service1") and create a new user that runs the aolserver process for each of them. You do not want to have service1 deal with bounces for service2. openacs-5.7.0/packages/acs-mail-lite/www/restore-bounce.adp0000644000175000017500000000036310606123352023440 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    #acs-mail-lite.Bounce_disabled#

    » #acs-subsite.Continue#

    openacs-5.7.0/packages/acs-mail-lite/www/restore-bounce.tcl0000644000175000017500000000105310606123352023453 0ustar frankiefrankiead_page_contract { The page restores a user from the deleted state. @cvs-id $Id: restore-bounce.tcl,v 1.1 2007/04/08 08:25:14 maltes Exp $ } { {return_url {[ad_pvt_home]}} } set page_title [_ acs-mail-lite.Restore_bounce] set context [list [list [ad_pvt_home] [ad_pvt_home_name]] $page_title] # We do require authentication, though their account will be closed set user_id [auth::require_login] db_dml unbounce_user "update users set email_bouncing_p = 'f' where user_id = :user_id" # Used in a message key set system_name [ad_system_name] openacs-5.7.0/packages/acs-mail-lite/acs-mail-lite.info0000644000175000017500000001520411575167337022511 0ustar frankiefrankie Mail Services Lite Mail Services Lite t t f t Malte Sussdorff Timo Hentschel Simplified reliable email transmission with bounce management. 2011-06-12 OpenACS This package provides a service for sending messages, queueing messages in the database to ensure reliable sending and make sending a message 'transactional'. Replacement for acs-mail. 2 openacs-5.7.0/packages/acs-mail-lite/catalog/0000755000175000017500000000000011724401447020610 5ustar frankiefrankieopenacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.gl_ES.ISO-8859-1.xml0000644000175000017500000000146410727201372026147 0ustar frankiefrankie Arquivos asociados: CC Enviar copia a varias direccións separadas por &quot;;&quot; Seleccionar/deseleccionar Ocorreu un erro ó procesar a súa petición Mensaxe Destinatarios Enviar Asunto Sin título Subir Arquivo A súa mensaxe foi enviada a: <strong>%recipients%</strong> openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.de_DE.ISO-8859-1.xml0000644000175000017500000000174310727201372026116 0ustar frankiefrankie Verknüpfte Dateien: CC Liste von E-Mail Adressen durch ";" getrennt an die eine Kopie der E-Mail geschickt werden soll. Alle/Keine auswählen Es gab einen Fehler bei der Verarbeitung Ihrer Anfrage Nachricht Serverprozeß Queue-Zeitpunkt Empfänger Senden Absender Betreff Unbenannt Datei hinzufügen Ihre Nachricht wurde an die folgende Empfänger geschickt: %recipients% openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.nl_NL.ISO-8859-1.xml0000644000175000017500000000151110727201372026151 0ustar frankiefrankie Verbintenis met de bestanden: CC Stuur kopie aan meerdere adressen gescheiden door ";" Aanvinken/Afvinken Er is een fout opgetreden tijdens het verwerken van dit verzoek. Bericht Ontvangers Verstuur Onderwerp Naamloos Bestand opladen Uw bericht is verstuurd aan <strong>%recipients%</strong> openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.pl_PL.utf-8.xml0000644000175000017500000000141410727201372025717 0ustar frankiefrankie PowiÄ…zane Pliki: CC WyÅ›lij kopie pod wiele adresów rozdzielajÄ…c je ";" Zaznacz/Odznacz WystÄ…piÅ‚ błąd. Komunikat Adresaci WyÅ›lij Temat Bez TytuÅ‚u Wgraj Plik Twój komunikat wysÅ‚ano do: &lt;strong&gt;%recipients%&lt;/strong&gt; openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.ca_ES.ISO-8859-1.xml0000644000175000017500000000153210727201371026123 0ustar frankiefrankie Fitxers associats: CC Envia'n còpia a diverses adreces separades per &quot;;&quot; Selecciona/Deselecciona S'ha produït un error en processar aquesta petició. Missatge Destinataris Envia Assumpte Sense títol Carrega arxiu El missatge s'ha enviat a: &amp;lt;strong&amp;gt;%recipients%&amp;lt;/strong&amp;gt; openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.nl_ZA.ISO-8859-1.xml0000644000175000017500000000151310720367135026157 0ustar frankiefrankie Verbintenis met die lêers: CC Stuur kopie aan meerdere adresse geskeide deur ";" Vink aan/Vink af Daar het 'n fout opgetree tydens verwerking van hierdie versoek. Berig Ontvangers Verstuur Onderwerp Naamloos Laai lêer U berig is verstuur aan <string>%recipients%</strong> openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.el_GR.utf-8.xml0000644000175000017500000000210410720404625025675 0ustar frankiefrankie Συσχετισμένα ΑÏχεία: CC Στείλτε αντίγÏαφο σε πεÏισσότεÏες από μια διευθÏνσεις διαχωÏίζοντας τες με ";" Ελεγμένο/Μη ελεγμένο ΠÏοέκυψε ένα σφάλμα κατά την επεξεÏγασία του αιτήματος. Μήνυμα Αποδέκτες Αποστολή Θέμα χωÏίς τίτλο Ανέβασμα αÏχείου Το μήνυμα σας έχει αποσταλλεί στους: &lt;strong&gt;%recipients%&lt;/strong&gt; openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.en_US.ISO-8859-1.xml0000644000175000017500000000216210727201372026163 0ustar frankiefrankie Associated Files: BCC Bouncing recorded as disabled. You will receive E-Mails again. Bouncing users CC Send copy to multiple addresses separated by ";" Check/Uncheck There was an error processing this request. Message Queue server Queueing time Recipients Send Sender Subject Unbounce Untitled Upload File Your message was sent to: &lt;strong&gt;%recipients%&lt;/strong&gt; openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.pt_BR.ISO-8859-1.xml0000644000175000017500000000151310727201372026157 0ustar frankiefrankie Arquivos Associados: CC Enviar cópia para múltiplos endereços de email separados por ";" Marcar/Desmarcar Ocorreu um erro ao processar esta solicitação. Mensagem Destinatários Enviar Assunto Sem título Anexar Arquivo Sua mensagem foi enviada para: &lt;strong&gt;%recipients%&lt;/strong&gt; openacs-5.7.0/packages/acs-mail-lite/catalog/acs-mail-lite.es_ES.ISO-8859-1.xml0000644000175000017500000000220211332116047026140 0ustar frankiefrankie Archivos asociados: CCO Bounce deshabilitado. Volverá a recibir emails. Usuarios con emails erróneos CC Enviar copia a varias direcciones separadas por ";" Seleccionar/deseleccionar Ocurrió un error al procesar su petición. Mensaje Servidor Tiempo en la cola Destinatarios Enviar Remitente Asunto No rechazar Sin título Subir Archivo Su mensaje ha sido enviado a: <strong>%recipients%</strong> openacs-5.7.0/packages/acs-messaging/0000755000175000017500000000000011724401447017276 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/tcl/0000755000175000017500000000000011724401447020060 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/tcl/test/0000755000175000017500000000000011575225532021042 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/tcl/test/acs-messaging-procs.tcl0000644000175000017500000000156007756066260025424 0ustar frankiefrankiead_library { Automated tests. @author Joel Aufrecht @creation-date 2 Nov 2003 @cvs-id $Id: acs-messaging-procs.tcl,v 1.4 2003/11/17 06:37:36 simonc Exp $ } aa_register_case acs_messaging_format_as_html { Test acs_messaging_format_as_html proc. } { aa_run_with_teardown \ -rollback \ -test_code { # initialize random values set name [ad_generate_random_string] set formatted_name [acs_messaging_format_as_html text/html $name] aa_true "Name is formatted" ![string match "
    $name
    " $formatted_name]
            }
    }
    
    aa_register_case acs_messaging_message_p {
        Test message_p proc.
    } {    
    
        aa_run_with_teardown \
            -rollback \
            -test_code {
    
                set message_p [acs_message_p "0"]
                aa_true "Integer is not a message_id" !$message_p
    
            }
    }
    openacs-5.7.0/packages/acs-messaging/tcl/acs-messaging-procs-oracle.xql0000644000175000017500000000506507305711160025720 0ustar  frankiefrankie
    
    
       oracle8.1.6
    
          
          
          
            insert into acs_messages_outgoing
                (message_id, to_address, grouping_id, wait_until)
            select :m__message_id, p.email, q.grouping_id,
                   nvl(q.wait_until, SYSDATE) as wait_until
                from ($query) q, parties p
                where not exists (select 1 from acs_messages_outgoing o
                                      where o.message_id = :m__message_id
                                        and p.email = o.to_address)
                  and p.party_id = q.recipient_id
        
          
    
    
          
          
          
    	begin
    	    :1 := acs_message.message_p(:message_id);
    	end;
        
          
    
    
     
          
          
          
    	select acs_message.first_ancestor(:message_id) as ancestor_id from dual
        
          
    
    
     
          
          
          
            insert into acs_messages_outgoing
                (message_id, to_address, grouping_id, wait_until)
            select :m__message_id, p.email, q.grouping_id,
                   nvl(q.wait_until, SYSDATE) as wait_until
                from ($query) q, parties p
                where not exists (select 1 from acs_messages_outgoing o
                                      where o.message_id = :m__message_id
                                        and p.email = o.to_address)
                  and p.party_id = q.recipient_id
        
          
    
    
     
          
          
          
            select o.message_id as sending_message_id,
                   o.to_address as recip_email,
                   p.email as sender_email,
                   to_char(m.sent_date, 'Dy, DD Mon YYYY HH24:MI:SS') as sent_date,
                   m.rfc822_id,
                   m.title,
                   m.mime_type,
                   m.content,
                   m2.rfc822_id as in_reply_to
                from acs_messages_outgoing o,
                     acs_messages_all m,
                     acs_messages_all m2,
                     parties p
                where o.message_id = m.message_id
                    and m2.message_id(+) = m.reply_to
                    and p.party_id = m.sender
                    and wait_until <= sysdate
        
          
    
    
     
    
    openacs-5.7.0/packages/acs-messaging/tcl/acs-messaging-procs-postgresql.xql0000644000175000017500000000357711226233616026666 0ustar  frankiefrankie
    
    
       postgresql7.1
    
          
          
          
            insert into acs_messages_outgoing
                (message_id, to_address, grouping_id, wait_until)
            select :m__message_id, p.email, q.grouping_id,
                   coalesce(q.wait_until, current_timestamp) as wait_until
                from ($query) q, parties p
                where not exists (select 1 from acs_messages_outgoing o
                                      where o.message_id = :m__message_id
                                        and p.email = o.to_address)
                  and p.party_id = q.recipient_id
        
          
    
    
    
          
          
    	    select acs_message__message_p(:message_id);
          
    
     
    
        
            select acs_message__first_ancestor(:message_id) as ancestor_id 
        
    
    
     
          
          
            select o.message_id as sending_message_id,
                   o.to_address as recip_email,
                   p.email as sender_email,
                   to_char(m.sent_date, 'Dy, DD Mon YYYY HH24:MI:SS') as sent_date,
                   m.rfc822_id,
                   m.title,
                   m.mime_type,
                   m.content,
                   m2.rfc822_id as in_reply_to
                from acs_messages_outgoing o,
                     acs_messages_all m left outer join acs_messages_all m2 on (m2.message_id = m.reply_to),
                     parties p
                where o.message_id = m.message_id
                    and p.party_id = m.sender
                    and wait_until <= current_timestamp
          
    
    
     
    
    openacs-5.7.0/packages/acs-messaging/tcl/acs-messaging-init.tcl0000644000175000017500000000047611226233616024253 0ustar  frankiefrankiead_library {
    
        Set up a scheduled process to send out email messages.
    
        @cvs-id $Id: acs-messaging-init.tcl,v 1.3 2009/07/12 01:08:30 donb Exp $
        @author John Prevost 
        @creation-date 2000-10-28
    
    }
    
    # Schedule every 15 minutes
    ad_schedule_proc -thread t 900 acs_messaging_process_queue
    
    openacs-5.7.0/packages/acs-messaging/tcl/acs-messaging-procs.tcl0000644000175000017500000001131111226233616024424 0ustar  frankiefrankiead_library {
        Utility procs for working with messages
    
        @author John Prevost 
        @creation-date 2000-09-01
        @cvs-id $Id: acs-messaging-procs.tcl,v 1.7 2009/07/12 01:08:30 donb Exp $
    }
    
    ad_proc -public acs_message_p {
        {message_id}
    } {
        Check if an integer is a valid OpenACS message id.
    } {
        return [string equal [db_exec_plsql acs_message_p {
    	begin
    	    :1 := acs_message.message_p(:message_id);
    	end;
        }] "t"]
    }
    
    ad_page_contract_filter acs_message_id { name value } {
        Checks whether the value (assumed to be an integer) is the id
        of an already-existing OpenACS message.
    } {
        # empty is okay (handled by notnull)
        if {$value eq ""} {
            return 1
        }
        if {![acs_message_p $value]} {
            ad_complain "$name ($value) does not refer to a valid OpenACS message"
            return 0
        }
        return 1
    }
    
    ad_proc -public acs_messaging_format_as_html {
        {mime_type}
        {content}
    } {
        Returns a string of HTML which appropriately renders the content
        given its mime content-type.  This function supports three content
        types, "text/plain", "text/plain; format=flowed", and "text/html"
        @param mime_type MIME content-type of content
        @param content   Text to view
    } {
        if {$mime_type eq "text/plain"} {
    	set result "
    [ad_quotehtml $content]
    " } elseif {$mime_type eq "text/plain; format=flowed"} { set result [ad_text_to_html -- $content] } elseif {$mime_type eq "text/html"} { set result $content } else { set result "content type undecipherable" } return $result } ad_proc -public acs_messaging_first_ancestor { {message_id} } { Takes the message_id of an acs_message and returns the message_id of the first ancestor message (i.e. the message that originated the thread). } { db_1row acs_message_first_ancestor { select acs_message.first_ancestor(:message_id) as ancestor_id from dual } return $ancestor_id } ad_proc -public acs_messaging_send { {-message_id:required} {-recipient_id:required} {-grouping_id ""} {-wait_until ""} } { Schedule one message to be sent to one party. } { db_dml { begin acs_message.send ( message_id => :message_id, recipient_id => :recipient_id, grouping_id => :grouping_id, wait_until => :wait_until ); end; } } ad_proc -public acs_messaging_send_query { {-message_id:required} {-query:required} {-bind ""} } { Given an SQL query returning columns recipient_id, grouping_id, and wait_until, arrange for all to be sent for this message. Example: acs_message_send_query -message_id $new_message -query { select subscriber_id as recipient_id, forum_id as grouping_id, bboard_util.next_period(period) as wait_until from bboard_forum_subscribers where forum_id = :forum_id } -bind [list forum_id $forum_id] Assuming bboard_util.next_period(period) returns the next date at which a digest should be sent, the above will enter info to send all subscriptions for a single message. The bind argument, if given, must be a list, NOT an ns_set. } { # Makes sure not to insert values that are already there--silent "failure" # because it's really a vacuous success. db_dml insert_messaging_by_query " insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select :m__message_id, p.email, q.grouping_id, nvl(q.wait_until, SYSDATE) as wait_until from ($query) q, parties p where not exists (select 1 from acs_messages_outgoing o where o.message_id = :m__message_id and p.email = o.to_address) and p.party_id = q.recipient_id " -bind [concat $bind [list m__message_id $message_id]] } ad_proc -private acs_messaging_timezone_offset { } { Returns a best guess of the timezone offset for the machine. } { return [format "%+05d" [expr ([lindex [ns_localtime] 2] - [lindex [ns_gmtime] 2]) * 100]] } ad_proc -private acs_messaging_process_queue { } { Process the message queue, sending any reasonable messages. } { db_foreach acs_message_send {} { if {![catch { acs_mail_lite::send -send_immediately \ -to_addr $recip_email \ -from_addr $sender_email \ -subject $title \ -body $content } errMsg]} { # everything went well, dequeue db_dml acs_message_remove_from_queue {} } else { ns_log "Error" "acs-messaging: Error processing queue: $errMsg" } } } openacs-5.7.0/packages/acs-messaging/tcl/acs-messaging-procs.xql0000644000175000017500000000055507305711160024454 0ustar frankiefrankie delete from acs_messages_outgoing where message_id = :sending_message_id and to_address = :recip_email openacs-5.7.0/packages/acs-messaging/sql/0000755000175000017500000000000011724401447020075 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/sql/oracle/0000755000175000017500000000000011724401447021342 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/sql/oracle/acs-messaging-drop.sql0000644000175000017500000000060007263134052025540 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-drop.sql -- -- @author akk@arsdigita.com -- @creation-date 2000-08-31 -- @cvs-id $Id: acs-messaging-drop.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- begin acs_object_type.drop_type('acs_message'); end; / show errors drop package acs_message; drop table acs_messages_outgoing; drop view acs_messages_all; drop table acs_messages; openacs-5.7.0/packages/acs-messaging/sql/oracle/acs-messaging-create.sql0000644000175000017500000001076110506241601026041 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-create.sql -- -- @author John Prevost -- @creation-date 2000-08-27 -- @cvs-id $Id: acs-messaging-create.sql,v 1.5 2006/09/26 15:13:05 byronl Exp $ -- set feedback off -- Object System Metadata ---------------------------------------------- begin acs_object_type.create_type ( supertype => 'content_item', object_type => 'acs_message', pretty_name => 'Message', pretty_plural => 'Messages', table_name => 'acs_messages', id_column => 'message_id', name_method => 'acs_message.name' ); acs_object_type.create_type ( supertype => 'content_revision', object_type => 'acs_message_revision', pretty_name => 'Message Revision', pretty_plural => 'Message Revisions', name_method => 'acs_object.default_name' ); end; / show errors -- Raw Tables and Comments --------------------------------------------- create table acs_messages ( -- extends cr_items message_id integer constraint acs_messages_message_id_fk references cr_items (item_id) on delete cascade constraint acs_messages_message_id_pk primary key, -- we will need to find a way to make reply_to go to 0 instead of null -- to improve scalability reply_to integer constraint acs_messages_reply_to_fk references acs_messages (message_id) on delete set null, sent_date date constraint acs_messages_sent_date_nn not null, sender integer constraint acs_messages_sender_fk references parties (party_id), rfc822_id varchar2(250) constraint acs_messages_rfc822_id_nn not null constraint acs_messages_rfc822_id_un unique ); create index acs_messages_reply_to_idx on acs_messages (reply_to); create index acs_messages_sender_idx on acs_messages (sender); comment on table acs_messages is ' A generic message which may be attached to any object in the system. '; comment on column acs_messages.reply_to is ' Pointer to a message this message contains a reply to, for threading. '; comment on column acs_messages.sent_date is ' The date the message was sent (may be distinct from when it was created or published in the system.) '; comment on column acs_messages.sender is ' The person who sent the message (may be distinct from the person who entered the message in the system.) '; comment on column acs_messages.rfc822_id is ' The RFC822 message-id of this message, for sending email. '; create table acs_messages_outgoing ( message_id integer constraint amo_message_id_fk references acs_messages (message_id) on delete cascade, to_address varchar2(1000) constraint amo_to_address_nn not null, grouping_id integer, wait_until date constraint amo_wait_until_nn not null, constraint acs_messages_outgoing_pk primary key (message_id, to_address) ); comment on table acs_messages_outgoing is ' Set of messages to be sent to parties. It is assumed that sending a message either queues it in a real MTA or fails, so no information about what''s been tried how many times is kept. '; comment on column acs_messages_outgoing.to_address is ' The email address to send this message to. Note that this will probably become a party_id again once upgrading a party to a user is possible. '; comment on column acs_messages_outgoing.grouping_id is ' This identifier is used to group sets of messages to be sent as digests. When a message is about to be sent, any other messages with the same grouping_id will be put together with it in a digest. It is recommended but not required that an object id is used. Bboard, for example, might use the forum id that the user''s subscribed to. For instant (non-digest) updates, it would be appropriate to use null, which is never equal to anything else. '; comment on column acs_messages_outgoing.wait_until is ' Don''t schedule a send until after this date. If another message with the same grouping ID is scheduled to be sent, then this message may be sent at the same time. (So, for example, daily digests would be achieved by setting the grouping_id to the same value, and the wait_until value to the end of the current day. As soon as one message in the group is to be sent, all will be sent.) '; @@ acs-messaging-views @@ acs-messaging-packages set feedback on openacs-5.7.0/packages/acs-messaging/sql/oracle/acs-messaging-views.sql0000644000175000017500000000155007263134052025736 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-create.sql -- -- @author John Prevost -- @creation-date 2000-11-15 -- @cvs-id $Id: acs-messaging-views.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- create or replace view acs_messages_all as select m.message_id, m.reply_to, m.sent_date, m.sender, m.rfc822_id, r.revision_id, r.title, r.mime_type, r.content from cr_items i, cr_revisions r, acs_messages m where i.item_id = m.message_id and r.revision_id = i.live_revision; create or replace view acs_messages_latest as select m.message_id, m.reply_to, m.sent_date, m.sender, m.rfc822_id, r.revision_id, r.title, r.mime_type, r.content from cr_items i, cr_revisions r, acs_messages m where i.item_id = m.message_id and r.revision_id = content_item.get_latest_revision(i.item_id); openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/0000755000175000017500000000000011575225531022773 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-5.2.1d1-5.2.1d2.sql0000644000175000017500000006525310440426464026731 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-packages.sql -- -- @author John Prevost -- @author Phong Nguyen -- @creation-date 2000-08-27 -- @cvs-id $Id: upgrade-5.2.1d1-5.2.1d2.sql,v 1.2 2006/06/04 00:45:40 donb Exp $ -- create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default -4, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure del ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ); procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ); function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_file ( file_id in cr_items.item_id%TYPE ); function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_image ( image_id in cr_items.item_id%TYPE ); function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE; function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ); function name ( message_id in acs_objects.object_id%TYPE ) return varchar2; end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default -4, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin -- generate a message id now so we can get an rfc822 message-id if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; -- this needs to be fixed up, but Oracle doesn't give us a way -- to get the FQDN if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_message_id := content_item.new ( name => v_rfc822_id, parent_id => parent_id, content_type => 'acs_message_revision', item_id => message_id, context_id => context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type, package_id => package_id ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message.edit ( message_id => v_message_id, title => title, description => description, mime_type => mime_type, text => text, data => data, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_message_id; end new; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin -- create a new revision using whichever call is appropriate if edit.data is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, data => data, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); elsif title is not null or text is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, text => text, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); end if; -- test for auto approval of revision if edit.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit; procedure del ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.del.message_id; content_item.del(message_id); end del; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id integer; begin select decode(count(message_id),0,0,1) into v_check_message_id from acs_messages where message_id = message_p.message_id; if v_check_message_id <> 0 then return 't'; else return 'f'; end if; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) values (message_id, to_address, grouping_id, v_wait_until); end send; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select send.message_id, p.email, send.grouping_id, v_wait_until from parties p where p.party_id = send.recipient_id; end send; function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE is v_message_id acs_messages.message_id%TYPE; begin select message_id into v_message_id from (select message_id, reply_to from acs_messages connect by message_id = prior reply_to start with message_id = first_ancestor.message_id) ancestors where reply_to is null; return v_message_id; end first_ancestor; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE is v_file_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_file_id := content_item.new ( name => file_name, parent_id => message_id, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, storage_type => storage_type, package_id => package_id ); -- create an initial revision for the new attachment v_revision_id := edit_file ( file_id => v_file_id, title => title, description => description, mime_type => mime_type, content => content, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_file_id; end new_file; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => title, mime_type => mime_type, data => content, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- test for auto approval of revision if is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_file; procedure delete_file ( file_id in cr_items.item_id%TYPE ) is begin content_item.del(delete_file.file_id); end delete_file; function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE is v_image_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_image_id := content_item.new ( name => file_name, parent_id => message_id, item_id => image_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, storage_type => storage_type, package_id => package_id ); -- create an initial revision for the new attachment v_revision_id := edit_image ( image_id => v_image_id, title => title, description => description, mime_type => mime_type, content => content, width => width, height => height, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_image_id; end new_image; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => edit_image.title, mime_type => edit_image.mime_type, data => edit_image.content, item_id => edit_image.image_id, creation_date => edit_image.creation_date, creation_user => edit_image.creation_user, creation_ip => edit_image.creation_ip ); -- insert new width and height values -- XXX fix after image.new exists insert into images (image_id, width, height) values (v_revision_id, width, height); -- test for auto approval of revision if edit_image.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_image; procedure delete_image ( image_id in cr_items.item_id%TYPE ) is begin -- XXX fix after image.delete exists delete from images where image_id = delete_image.image_id; content_item.del(image_id); end delete_image; -- XXX should just call content_extlink.new function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink.new ( name => new_extlink.name, url => new_extlink.url, label => new_extlink.label, description => new_extlink.description, parent_id => new_extlink.parent_id, extlink_id => new_extlink.extlink_id, creation_date => new_extlink.creation_date, creation_user => new_extlink.creation_user, creation_ip => new_extlink.creation_ip, package_id => new_extlink.package_id ); end new_extlink; -- XXX should just edit extlink function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_is_extlink char; begin v_is_extlink := content_extlink.is_extlink(edit_extlink.extlink_id); if v_is_extlink = 't' then update cr_extlinks set url = edit_extlink.url, label = edit_extlink.label, description = edit_extlink.description where extlink_id = edit_extlink.extlink_id; end if; return v_is_extlink; end edit_extlink; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin content_extlink.del(extlink_id => delete_extlink.extlink_id); end delete_extlink; function name ( message_id in acs_objects.object_id%TYPE ) return varchar2 is v_message_name acs_messages_all.title%TYPE; begin select title into v_message_name from acs_messages_all where message_id = name.message_id; return v_message_name; end name; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-4.0.1a-4.0.1.sql0000644000175000017500000000233507265644232026407 0ustar frankiefrankie-- -- acs-messaging sql/upgrade-4.0.1a-4.0.1.sql -- -- @author jmp@arsdigita.com -- @creation-date 2000-11-15 -- @cvs-id $Id: upgrade-4.0.1a-4.0.1.sql,v 1.1 2001/04/13 18:42:34 donb Exp $ -- begin acs_object_type.create_type ( supertype => 'content_revision', object_type => 'acs_message_revision', pretty_name => 'Message Revision', pretty_plural => 'Message Revisions', table_name => 'CR_REVISIONS', id_column => 'REVISION_ID', name_method => 'ACS_OBJECT.DEFAULT_NAME' ); end; / show errors alter table acs_messages_outgoing add ( to_address varchar2(1000) constraint amo_to_address_nn not null disable ); update acs_messages_outgoing set to_address = (select email from parties where party_id = recipient_id); alter table acs_messages_outgoing drop constraint acs_messages_outgoing_pk; alter table acs_messages_outgoing add constraint acs_messages_outgoing_pk primary key (message_id, to_address); alter table acs_messages_outgoing modify constraint amo_to_address_nn enable; alter table acs_messages_outgoing drop column recipient_id; @@ acs-messaging-views @@ acs-messaging-packages set feedback on openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-4.1-4.1.1.sql0000644000175000017500000006431007263134052026102 0ustar frankiefrankie-- packages/acs-messaging/sql/upgrade/sql/upgrade/upgrade-4.1-4.1.1.sql -- -- upgrade script for acs-messaging 4.1 to 4.1.1. -- @author teeters@arsdigita.com -- @creation-date 2000-03-06 -- @cvs-id $Id: upgrade-4.1-4.1.1.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- Change in acs-messaging/sql/acs-messaging-create.sql -- content_item name_method changed from 'ACS_OBJECT.DEFAULT_NAME' to 'ACS_MESSAGE.NAME' update acs_object_types set name_method = 'ACS_MESSAGE.NAME' where object_type = 'acs_message'; -- Added function name to package acs_message; -- @../../../acs-messaging/sql/acs-messaging-packages.sql -- would like to source file using @, but for some reason source not working -- have to copy file. -- -- packages/acs-messaging/sql/acs-messaging-packages.sql -- -- @author John Prevost -- @author Phong Nguyen -- @creation-date 2000-08-27 -- @cvs-id $Id: upgrade-4.1-4.1.1.sql,v 1.1 2001/04/05 18:23:38 donb Exp $ -- create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default 0, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ); procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ); function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_file ( file_id in cr_items.item_id%TYPE ); function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_image ( image_id in cr_items.item_id%TYPE ); function new_extlink ( name in cr_items.name%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE; function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ); function name ( message_id in acs_objects.object_id%TYPE ) return varchar2; end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default null, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default 0, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't' ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin -- generate a message id now so we can get an rfc822 message-id if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; -- this needs to be fixed up, but Oracle doesn't give us a way -- to get the FQDN if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_message_id := content_item.new ( name => v_rfc822_id, parent_id => parent_id, content_type => 'acs_message_revision', item_id => message_id, context_id => context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message.edit ( message_id => v_message_id, title => title, description => description, mime_type => mime_type, text => text, data => data, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_message_id; end new; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin -- create a new revision using whichever call is appropriate if edit.data is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, data => data, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); elsif title is not null or text is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, text => text, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); end if; -- test for auto approval of revision if edit.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit; procedure delete ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.delete.message_id; content_item.delete(message_id); end delete; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id integer; begin select decode(count(message_id),0,0,1) into v_check_message_id from acs_messages where message_id = message_p.message_id; if v_check_message_id <> 0 then return 't'; else return 'f'; end if; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) values (message_id, to_address, grouping_id, v_wait_until); end send; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select send.message_id, p.email, send.grouping_id, v_wait_until from parties p where p.party_id = send.recipient_id; end send; function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE is v_message_id acs_messages.message_id%TYPE; begin select message_id into v_message_id from (select message_id, reply_to from acs_messages connect by message_id = prior reply_to start with message_id = first_ancestor.message_id) ancestors where reply_to is null; return v_message_id; end first_ancestor; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_file_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_file_id := content_item.new ( name => file_name, parent_id => message_id, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- create an initial revision for the new attachment v_revision_id := edit_file ( file_id => v_file_id, title => title, description => description, mime_type => mime_type, content => content, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_file_id; end new_file; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => title, mime_type => mime_type, data => content, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- test for auto approval of revision if is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_file; procedure delete_file ( file_id in cr_items.item_id%TYPE ) is begin content_item.delete(delete_file.file_id); end delete_file; function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_image_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_image_id := content_item.new ( name => file_name, parent_id => message_id, item_id => image_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- create an initial revision for the new attachment v_revision_id := edit_image ( image_id => v_image_id, title => title, description => description, mime_type => mime_type, content => content, width => width, height => height, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_image_id; end new_image; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => edit_image.title, mime_type => edit_image.mime_type, data => edit_image.content, item_id => edit_image.image_id, creation_date => edit_image.creation_date, creation_user => edit_image.creation_user, creation_ip => edit_image.creation_ip ); -- insert new width and height values -- XXX fix after image.new exists insert into images (image_id, width, height) values (v_revision_id, width, height); -- test for auto approval of revision if edit_image.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_image; procedure delete_image ( image_id in cr_items.item_id%TYPE ) is begin -- XXX fix after image.delete exists delete from images where image_id = delete_image.image_id; content_item.delete(image_id); end delete_image; -- XXX should just call content_extlink.new function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink.new ( name => new_extlink.name, url => new_extlink.url, label => new_extlink.label, description => new_extlink.description, parent_id => new_extlink.parent_id, extlink_id => new_extlink.extlink_id, creation_date => new_extlink.creation_date, creation_user => new_extlink.creation_user, creation_ip => new_extlink.creation_ip ); end new_extlink; -- XXX should just edit extlink function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_is_extlink char; begin v_is_extlink := content_extlink.is_extlink(edit_extlink.extlink_id); if v_is_extlink = 't' then update cr_extlinks set url = edit_extlink.url, label = edit_extlink.label, description = edit_extlink.description where extlink_id = edit_extlink.extlink_id; end if; return v_is_extlink; end edit_extlink; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin content_extlink.delete(extlink_id => delete_extlink.extlink_id); end delete_extlink; function name ( message_id in acs_objects.object_id%TYPE ) return varchar2 is v_message_name acs_messages_all.title%TYPE; begin select title into v_message_name from acs_messages_all where message_id = name.message_id; return v_message_name; end name; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-4.5-5.0d1.sql0000644000175000017500000006367607741041152026211 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-packages.sql -- -- @author John Prevost -- @author Phong Nguyen -- @creation-date 2000-08-27 -- @cvs-id $Id: upgrade-4.5-5.0d1.sql,v 1.1 2003/10/08 16:59:22 mohanp Exp $ -- create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default 0, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure del ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ); procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ); function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file' ) return acs_objects.object_id%TYPE; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_file ( file_id in cr_items.item_id%TYPE ); function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file' ) return acs_objects.object_id%TYPE; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_image ( image_id in cr_items.item_id%TYPE ); function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE; function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ); function name ( message_id in acs_objects.object_id%TYPE ) return varchar2; end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default 0, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't' ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin -- generate a message id now so we can get an rfc822 message-id if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; -- this needs to be fixed up, but Oracle doesn't give us a way -- to get the FQDN if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_message_id := content_item.new ( name => v_rfc822_id, parent_id => parent_id, content_type => 'acs_message_revision', item_id => message_id, context_id => context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message.edit ( message_id => v_message_id, title => title, description => description, mime_type => mime_type, text => text, data => data, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_message_id; end new; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin -- create a new revision using whichever call is appropriate if edit.data is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, data => data, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); elsif title is not null or text is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, text => text, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); end if; -- test for auto approval of revision if edit.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit; procedure del ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.del.message_id; content_item.del(message_id); end del; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id integer; begin select decode(count(message_id),0,0,1) into v_check_message_id from acs_messages where message_id = message_p.message_id; if v_check_message_id <> 0 then return 't'; else return 'f'; end if; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) values (message_id, to_address, grouping_id, v_wait_until); end send; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select send.message_id, p.email, send.grouping_id, v_wait_until from parties p where p.party_id = send.recipient_id; end send; function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE is v_message_id acs_messages.message_id%TYPE; begin select message_id into v_message_id from (select message_id, reply_to from acs_messages connect by message_id = prior reply_to start with message_id = first_ancestor.message_id) ancestors where reply_to is null; return v_message_id; end first_ancestor; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file' ) return acs_objects.object_id%TYPE is v_file_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_file_id := content_item.new ( name => file_name, parent_id => message_id, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, storage_type => storage_type ); -- create an initial revision for the new attachment v_revision_id := edit_file ( file_id => v_file_id, title => title, description => description, mime_type => mime_type, content => content, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_file_id; end new_file; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => title, mime_type => mime_type, data => content, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- test for auto approval of revision if is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_file; procedure delete_file ( file_id in cr_items.item_id%TYPE ) is begin content_item.del(delete_file.file_id); end delete_file; function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file' ) return acs_objects.object_id%TYPE is v_image_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_image_id := content_item.new ( name => file_name, parent_id => message_id, item_id => image_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, storage_type => storage_type ); -- create an initial revision for the new attachment v_revision_id := edit_image ( image_id => v_image_id, title => title, description => description, mime_type => mime_type, content => content, width => width, height => height, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_image_id; end new_image; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => edit_image.title, mime_type => edit_image.mime_type, data => edit_image.content, item_id => edit_image.image_id, creation_date => edit_image.creation_date, creation_user => edit_image.creation_user, creation_ip => edit_image.creation_ip ); -- insert new width and height values -- XXX fix after image.new exists insert into images (image_id, width, height) values (v_revision_id, width, height); -- test for auto approval of revision if edit_image.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_image; procedure delete_image ( image_id in cr_items.item_id%TYPE ) is begin -- XXX fix after image.delete exists delete from images where image_id = delete_image.image_id; content_item.del(image_id); end delete_image; -- XXX should just call content_extlink.new function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink.new ( name => new_extlink.name, url => new_extlink.url, label => new_extlink.label, description => new_extlink.description, parent_id => new_extlink.parent_id, extlink_id => new_extlink.extlink_id, creation_date => new_extlink.creation_date, creation_user => new_extlink.creation_user, creation_ip => new_extlink.creation_ip ); end new_extlink; -- XXX should just edit extlink function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_is_extlink char; begin v_is_extlink := content_extlink.is_extlink(edit_extlink.extlink_id); if v_is_extlink = 't' then update cr_extlinks set url = edit_extlink.url, label = edit_extlink.label, description = edit_extlink.description where extlink_id = edit_extlink.extlink_id; end if; return v_is_extlink; end edit_extlink; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin content_extlink.del(extlink_id => delete_extlink.extlink_id); end delete_extlink; function name ( message_id in acs_objects.object_id%TYPE ) return varchar2 is v_message_name acs_messages_all.title%TYPE; begin select title into v_message_name from acs_messages_all where message_id = name.message_id; return v_message_name; end name; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-5.3.0d1-5.3.0d2.sql0000644000175000017500000000014610475321744026722 0ustar frankiefrankieupdate acs_object_types set table_name=null, id_column=null where object_type='acs_message_revision'; openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-5.1.0d1-5.1.0d2.sql0000644000175000017500000000040210024403024026667 0ustar frankiefrankieupdate acs_objects set title = (select name from cr_items where item_id = object_id), package_id = acs_object__package_id(content_item.get_root_folder(object_id)) where object_type = 'acs_message'; @@ ../acs-messaging-packages.sql openacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-4.0.1-4.1.sql0000644000175000017500000000046507265644232026112 0ustar frankiefrankie-- -- acs-messaging sql/upgrade-4.0.1-4.1.sql -- -- @author John Prevost -- @creation-date 2001-01-16 -- @cvs-id $Id: upgrade-4.0.1-4.1.sql,v 1.1 2001/04/13 18:42:34 donb Exp $ -- -- do all the views and packages in case something changed @@ acs-messaging-views @@ acs-messaging-packagesopenacs-5.7.0/packages/acs-messaging/sql/oracle/upgrade/upgrade-4.0-4.0.1a.sql0000644000175000017500000002136607265644232026255 0ustar frankiefrankie-- -- acs-messaging sql/upgrade-4.0-4.0.1a.sql -- -- @author jmp@arsdigita.com -- @creation-date 2000-11-03 -- @cvs-id $Id: upgrade-4.0-4.0.1a.sql,v 1.1 2001/04/13 18:42:34 donb Exp $ -- alter table acs_messages add ( sent_date date constraint acs_messages_sent_date_nn not null disable, sender integer constraint acs_messages_sender_fk references parties (party_id) disable, rfc822_id varchar2(250) constraint acs_messages_rfc822_id_nn not null disable constraint acs_messages_rfc822_id_un unique disable ); create table acs_mess_up ( id integer primary key, sent_date date, sender integer, rfc822_id varchar2(250) ); insert into acs_mess_up select m.message_id, r.publish_date as sent_date, o.creation_user as sender, (sysdate || '.' || message_id || '@' || utl_inaddr.get_host_name||'.hate') as rfc822_id from acs_objects o, cr_items i, cr_revisions r, acs_messages m where m.message_id = i.item_id and m.message_id = o.object_id and r.revision_id = i.live_revision; update acs_messages set sent_date = (select sent_date from acs_mess_up where id = message_id), sender = (select sender from acs_mess_up where id = message_id), rfc822_id = (select rfc822_id from acs_mess_up where id = message_id); drop table acs_mess_up; alter table acs_messages modify constraint acs_messages_sent_date_nn enable; alter table acs_messages modify constraint acs_messages_sender_fk enable; alter table acs_messages modify constraint acs_messages_rfc822_id_nn enable; alter table acs_messages modify constraint acs_messages_rfc822_id_un enable; create or replace view acs_messages_all as select m.message_id, m.reply_to, m.sent_date, m.sender, m.rfc822_id, r.title, r.mime_type, r.content, o.context_id from acs_objects o, cr_items i, cr_revisions r, acs_messages m where o.object_id = m.message_id and i.item_id = m.message_id and r.revision_id = i.live_revision; create table acs_messages_outgoing ( message_id integer constraint amo_message_id_fk references acs_messages (message_id) on delete cascade, recipient_id integer constraint amo_recipient_id_fk references parties (party_id), grouping_id integer, wait_until date not null, constraint acs_messages_outgoing_pk primary key (message_id, recipient_id) ); comment on column acs_messages_outgoing.grouping_id is ' This identifier is used to group sets of messages to be sent as digests. When a message is about to be sent, any other messages with the same grouping_id will be put together with it in a digest. It is recommended but not required that an object id is used. Bboard, for example, might use the forum id that the user''s subscribed to. For instant (non-digest) updates, it would be appropriate to use null, which is never equal to anything else. '; comment on column acs_messages_outgoing.wait_until is ' Don''t schedule a send until after this date. If another message with the same grouping ID is scheduled to be sent, then this message may be sent at the same time. (So, for example, daily digests would be achieved by setting the grouping_id to the same value, and the wait_until value to the end of the current day. As soon as one message in the group is to be sent, all will be sent.) '; create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message' ) return acs_objects.object_id%TYPE; procedure delete ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default NULL, wait_until in date default SYSDATE ); end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message' ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_name cr_items.name%TYPE; begin if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_name := v_rfc822_id; v_message_id := content_item.new ( name => v_name, parent_id => context_id, item_id => message_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type, title => title, mime_type => mime_type, text => text, data => data, is_live => 't' ); -- I hate you, milkman CR. -- Fix the broken permissions stuff content_item.new does update acs_objects set security_inherit_p = 't' where object_id = v_message_id; delete from acs_permissions where object_id = v_message_id; insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); return v_message_id; end new; procedure delete ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.delete.message_id; content_item.delete(message_id); end; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id char(1); begin select decode(count(message_id),0,'f','t') into v_check_message_id from acs_messages where message_id = message_p.message_id; return v_check_message_id; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default NULL, wait_until in date default SYSDATE ) is v_wait_until date; begin v_wait_until := nvl(wait_until, SYSDATE); insert into acs_messages_outgoing (message_id, recipient_id, grouping_id, wait_until) values (message_id, recipient_id, grouping_id, nvl(wait_until,SYSDATE)); end; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/oracle/acs-messaging-packages.sql0000644000175000017500000006525210440426464026372 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-packages.sql -- -- @author John Prevost -- @author Phong Nguyen -- @creation-date 2000-08-27 -- @cvs-id $Id: acs-messaging-packages.sql,v 1.8 2006/06/04 00:45:40 donb Exp $ -- create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default -4, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure del ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ); procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ); function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_file ( file_id in cr_items.item_id%TYPE ); function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_image ( image_id in cr_items.item_id%TYPE ); function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE; function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ); function name ( message_id in acs_objects.object_id%TYPE ) return varchar2; end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default -4, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin -- generate a message id now so we can get an rfc822 message-id if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; -- this needs to be fixed up, but Oracle doesn't give us a way -- to get the FQDN if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_message_id := content_item.new ( name => v_rfc822_id, parent_id => parent_id, content_type => 'acs_message_revision', item_id => message_id, context_id => context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type, package_id => package_id ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message.edit ( message_id => v_message_id, title => title, description => description, mime_type => mime_type, text => text, data => data, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_message_id; end new; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin -- create a new revision using whichever call is appropriate if edit.data is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, data => data, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); elsif title is not null or text is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, text => text, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); end if; -- test for auto approval of revision if edit.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit; procedure del ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.del.message_id; content_item.del(message_id); end del; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id integer; begin select decode(count(message_id),0,0,1) into v_check_message_id from acs_messages where message_id = message_p.message_id; if v_check_message_id <> 0 then return 't'; else return 'f'; end if; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) values (message_id, to_address, grouping_id, v_wait_until); end send; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select send.message_id, p.email, send.grouping_id, v_wait_until from parties p where p.party_id = send.recipient_id; end send; function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE is v_message_id acs_messages.message_id%TYPE; begin select message_id into v_message_id from (select message_id, reply_to from acs_messages connect by message_id = prior reply_to start with message_id = first_ancestor.message_id) ancestors where reply_to is null; return v_message_id; end first_ancestor; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE is v_file_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_file_id := content_item.new ( name => file_name, parent_id => message_id, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, storage_type => storage_type, package_id => package_id ); -- create an initial revision for the new attachment v_revision_id := edit_file ( file_id => v_file_id, title => title, description => description, mime_type => mime_type, content => content, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_file_id; end new_file; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => title, mime_type => mime_type, data => content, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- test for auto approval of revision if is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_file; procedure delete_file ( file_id in cr_items.item_id%TYPE ) is begin content_item.del(delete_file.file_id); end delete_file; function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't', storage_type in cr_items.storage_type%TYPE default 'file', package_id in acs_objects.package_id%TYPE default null ) return acs_objects.object_id%TYPE is v_image_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_image_id := content_item.new ( name => file_name, parent_id => message_id, item_id => image_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, storage_type => storage_type, package_id => package_id ); -- create an initial revision for the new attachment v_revision_id := edit_image ( image_id => v_image_id, title => title, description => description, mime_type => mime_type, content => content, width => width, height => height, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_image_id; end new_image; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => edit_image.title, mime_type => edit_image.mime_type, data => edit_image.content, item_id => edit_image.image_id, creation_date => edit_image.creation_date, creation_user => edit_image.creation_user, creation_ip => edit_image.creation_ip ); -- insert new width and height values -- XXX fix after image.new exists insert into images (image_id, width, height) values (v_revision_id, width, height); -- test for auto approval of revision if edit_image.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_image; procedure delete_image ( image_id in cr_items.item_id%TYPE ) is begin -- XXX fix after image.delete exists delete from images where image_id = delete_image.image_id; content_item.del(image_id); end delete_image; -- XXX should just call content_extlink.new function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, package_id in acs_objects.package_id%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink.new ( name => new_extlink.name, url => new_extlink.url, label => new_extlink.label, description => new_extlink.description, parent_id => new_extlink.parent_id, extlink_id => new_extlink.extlink_id, creation_date => new_extlink.creation_date, creation_user => new_extlink.creation_user, creation_ip => new_extlink.creation_ip, package_id => new_extlink.package_id ); end new_extlink; -- XXX should just edit extlink function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_is_extlink char; begin v_is_extlink := content_extlink.is_extlink(edit_extlink.extlink_id); if v_is_extlink = 't' then update cr_extlinks set url = edit_extlink.url, label = edit_extlink.label, description = edit_extlink.description where extlink_id = edit_extlink.extlink_id; end if; return v_is_extlink; end edit_extlink; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin content_extlink.del(extlink_id => delete_extlink.extlink_id); end delete_extlink; function name ( message_id in acs_objects.object_id%TYPE ) return varchar2 is v_message_name acs_messages_all.title%TYPE; begin select title into v_message_name from acs_messages_all where message_id = name.message_id; return v_message_name; end name; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/postgresql/0000755000175000017500000000000011575225531022302 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/sql/postgresql/acs-messaging-drop.sql0000644000175000017500000000704210024403024026470 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-drop.sql -- -- @author akk@arsdigita.com -- @creation-date 2000-08-31 -- @cvs-id $Id: acs-messaging-drop.sql,v 1.7 2004/03/12 18:48:52 jeffd Exp $ -- -- drop functions drop trigger acs_message_insert_tr on acs_messages; drop trigger acs_message_update_tr on acs_messages; drop function acs_message_insert_tr(); drop function acs_message_update_tr(); drop function acs_message__edit (integer,varchar,varchar,varchar, text,integer,timestamptz,integer,varchar,boolean); drop function acs_message__new (integer,integer,timestamptz,integer, varchar,varchar,varchar,varchar,varchar,text, integer,integer,integer,varchar,varchar,boolean); drop function acs_message__new (integer,integer,timestamptz,integer, varchar,varchar,varchar,varchar,varchar,text, integer,integer,integer,varchar,varchar,boolean,integer); drop function acs_message__delete (integer); drop function acs_message__message_p (integer); drop function acs_message__send (integer,varchar,integer,timestamptz); drop function acs_message__send (integer,integer,integer,timestamptz); drop function acs_message__first_ancestor (integer); drop function acs_message__new_file (integer,integer,varchar,varchar, text,varchar,text,timestamptz,integer, varchar,boolean); drop function acs_message__new_file (integer,integer,varchar,varchar, text,varchar,text,timestamptz,integer, varchar,boolean,integer); drop function acs_message__edit_file (integer,varchar,text,varchar, text,timestamptz,integer,varchar,boolean); drop function acs_message__delete_file (integer); drop function acs_message__new_image (integer,integer,varchar,varchar, text,varchar,text,integer,integer, timestamptz,integer,varchar,boolean); drop function acs_message__new_image (integer,integer,varchar,varchar, text,varchar,text,integer,integer, timestamptz,integer,varchar,boolean,integer); drop function acs_message__edit_image (integer,varchar,text,varchar, text,integer,integer,timestamptz,integer, varchar,boolean); drop function acs_message__delete_image (integer); drop function acs_message__new_extlink (varchar,integer,varchar,varchar,text, integer,timestamptz,integer,varchar); drop function acs_message__new_extlink (varchar,integer,varchar,varchar,text, integer,timestamptz,integer,varchar,integer); drop function acs_message__edit_extlink (integer,varchar,varchar,text); drop function acs_message__delete_extlink (integer); drop function acs_message__name (integer); -- drop views drop view acs_messages_all; drop view acs_messages_latest; -- drop indices drop index acs_messages_reply_to_idx; drop index acs_messages_sender_idx; -- drop tables drop table acs_messages_outgoing; drop table acs_messages; -- drop acs_object_types select acs_object_type__drop_type('acs_message_revision', 't'); select acs_object_type__drop_type('acs_message', 't'); --drop package acs_message; --drop table acs_messages_outgoing; --drop view acs_messages_all; --drop table acs_messages; openacs-5.7.0/packages/acs-messaging/sql/postgresql/acs-messaging-create.sql0000644000175000017500000001632410506040771027005 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-create.sql -- -- @author John Prevost -- @author Jon Griffin -- @creation-date 2000-08-27 -- -- @cvs-id $Id: acs-messaging-create.sql,v 1.14 2006/09/25 20:54:17 byronl Exp $ -- updated for OpenACS -- Object System Metadata ---------------------------------------------- select acs_object_type__create_type ( 'acs_message', 'Message', 'Messages', 'content_item', 'acs_messages', 'message_id', null, 'f', null, 'acs_message__name' ); select acs_object_type__create_type ( 'acs_message_revision', 'Message Revision', 'Message Revisions', 'content_revision', null, null, null, 'f', null, 'acs_object__default_name' ); -- Raw Tables and Comments --------------------------------------------- create table acs_messages ( -- extends cr_items message_id integer constraint acs_messages_message_id_fk references cr_items (item_id) on delete cascade constraint acs_messages_message_id_pk primary key, -- we will need to find a way to make reply_to go to 0 instead of null -- to improve scalability reply_to integer constraint acs_messages_reply_to_fk references acs_messages (message_id) on delete set null, sent_date timestamptz constraint acs_messages_sent_date_nn not null, sender integer constraint acs_messages_sender_fk references parties (party_id), rfc822_id varchar(250) constraint acs_messages_rfc822_id_nn not null constraint acs_messages_rfc822_id_un unique, tree_sortkey varbit ); create index acs_messages_tree_skey_idx on acs_messages (tree_sortkey); create index acs_messages_reply_to_idx on acs_messages (reply_to); create index acs_messages_sender_idx on acs_messages (sender); create index acs_messages_sent_idx on acs_messages (sent_date); comment on table acs_messages is ' A generic message which may be attached to any object in the system. '; comment on column acs_messages.reply_to is ' Pointer to a message this message contains a reply to, for threading. '; comment on column acs_messages.sent_date is ' The date the message was sent (may be distinct from when it was created or published in the system.) '; comment on column acs_messages.sender is ' The person who sent the message (may be distinct from the person who entered the message in the system.) '; comment on column acs_messages.rfc822_id is ' The RFC822 message-id of this message, for sending email. '; -- support for tree queries on acs_messages create or replace function acs_message_get_tree_sortkey(integer) returns varbit as ' declare p_message_id alias for $1; begin return tree_sortkey from acs_messages where message_id = p_message_id; end;' language 'plpgsql' stable strict; create or replace function acs_message_insert_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; begin if new.reply_to is null then select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from acs_messages where reply_to is null; else select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from acs_messages where reply_to = new.reply_to; select tree_sortkey into v_parent_sk from acs_messages where message_id = new.reply_to; end if; new.tree_sortkey := tree_next_key(v_parent_sk, v_max_value); return new; end;' language 'plpgsql'; create trigger acs_message_insert_tr before insert on acs_messages for each row execute procedure acs_message_insert_tr (); create function acs_message_update_tr () returns opaque as ' declare v_parent_sk varbit default null; v_max_value integer; v_rec record; clr_keys_p boolean default ''t''; begin if new.message_id = old.message_id and ((new.reply_to = old.reply_to) or (new.reply_to is null and old.reply_to is null)) then return new; end if; for v_rec in select message_id, reply_to from acs_messages where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey) order by tree_sortkey LOOP if clr_keys_p then update acs_messages set tree_sortkey = null where tree_sortkey between new.tree_sortkey and tree_right(new.tree_sortkey); clr_keys_p := ''f''; end if; select max(tree_leaf_key_to_int(tree_sortkey)) into v_max_value from acs_messages where reply_to = v_rec.reply_to; select tree_sortkey into v_parent_sk from acs_messages where message_id = v_rec.reply_to; update acs_messages set tree_sortkey = tree_next_key(v_parent_sk, v_max_value) where message_id = v_rec.message_id; end LOOP; return new; end;' language 'plpgsql'; create trigger acs_message_update_tr after update on acs_messages for each row execute procedure acs_message_update_tr (); create table acs_messages_outgoing ( message_id integer constraint amo_message_id_fk references acs_messages (message_id) on delete cascade, to_address varchar(1000) constraint amo_to_address_nn not null, grouping_id integer, wait_until timestamptz constraint amo_wait_until_nn not null, constraint acs_messages_outgoing_pk primary key (message_id, to_address) ); comment on table acs_messages_outgoing is ' Set of messages to be sent to parties. It is assumed that sending a message either queues it in a real MTA or fails, so no information about what''s been tried how many times is kept. '; comment on column acs_messages_outgoing.to_address is ' The email address to send this message to. Note that this will probably become a party_id again once upgrading a party to a user is possible. '; comment on column acs_messages_outgoing.grouping_id is ' This identifier is used to group sets of messages to be sent as digests. When a message is about to be sent, any other messages with the same grouping_id will be put together with it in a digest. It is recommended but not required that an object id is used. Bboard, for example, might use the forum id that the user''s subscribed to. For instant (non-digest) updates, it would be appropriate to use null, which is never equal to anything else. '; comment on column acs_messages_outgoing.wait_until is ' Don''t schedule a send until after this date. If another message with the same grouping ID is scheduled to be sent, then this message may be sent at the same time. (So, for example, daily digests would be achieved by setting the grouping_id to the same value, and the wait_until value to the end of the current day. As soon as one message in the group is to be sent, all will be sent.) '; \i acs-messaging-views.sql \i acs-messaging-packages.sql openacs-5.7.0/packages/acs-messaging/sql/postgresql/acs-messaging-views.sql0000644000175000017500000000171107321154011026663 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-create.sql -- -- @author John Prevost -- @author Jon Griffin -- -- @creation-date 2000-11-15 -- @cvs-id $Id: acs-messaging-views.sql,v 1.2 2001/07/05 21:11:37 lukep Exp $ -- -- Updated by Jon Griffin for OpenACS create view acs_messages_all as select m.message_id, m.reply_to, m.sent_date, m.sender, m.rfc822_id, m.tree_sortkey, r.revision_id, r.title, r.mime_type, r.content from cr_items i, cr_revisions r, acs_messages m where i.item_id = m.message_id and r.revision_id = i.live_revision; create view acs_messages_latest as select m.message_id, m.reply_to, m.sent_date, m.sender, m.rfc822_id, m.tree_sortkey, r.revision_id, r.title, r.mime_type, r.content from cr_items i, cr_revisions r, acs_messages m where i.item_id = m.message_id and r.revision_id = content_item__get_latest_revision(i.item_id); openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/0000755000175000017500000000000011575225531023731 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-4.0.1a-4.0.1.sql0000644000175000017500000000233507302763673027350 0ustar frankiefrankie-- -- acs-messaging sql/upgrade-4.0.1a-4.0.1.sql -- -- @author jmp@arsdigita.com -- @creation-date 2000-11-15 -- @cvs-id $Id: upgrade-4.0.1a-4.0.1.sql,v 1.1 2001/05/23 16:39:23 jong Exp $ -- begin acs_object_type.create_type ( supertype => 'content_revision', object_type => 'acs_message_revision', pretty_name => 'Message Revision', pretty_plural => 'Message Revisions', table_name => 'CR_REVISIONS', id_column => 'REVISION_ID', name_method => 'ACS_OBJECT.DEFAULT_NAME' ); end; / show errors alter table acs_messages_outgoing add ( to_address varchar2(1000) constraint amo_to_address_nn not null disable ); update acs_messages_outgoing set to_address = (select email from parties where party_id = recipient_id); alter table acs_messages_outgoing drop constraint acs_messages_outgoing_pk; alter table acs_messages_outgoing add constraint acs_messages_outgoing_pk primary key (message_id, to_address); alter table acs_messages_outgoing modify constraint amo_to_address_nn enable; alter table acs_messages_outgoing drop column recipient_id; @@ acs-messaging-views @@ acs-messaging-packages set feedback on openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-4.1-4.1.1.sql0000644000175000017500000006431007302763673027053 0ustar frankiefrankie-- packages/acs-messaging/sql/upgrade/sql/upgrade/upgrade-4.1-4.1.1.sql -- -- upgrade script for acs-messaging 4.1 to 4.1.1. -- @author teeters@arsdigita.com -- @creation-date 2000-03-06 -- @cvs-id $Id: upgrade-4.1-4.1.1.sql,v 1.1 2001/05/23 16:39:23 jong Exp $ -- Change in acs-messaging/sql/acs-messaging-create.sql -- content_item name_method changed from 'ACS_OBJECT.DEFAULT_NAME' to 'ACS_MESSAGE.NAME' update acs_object_types set name_method = 'ACS_MESSAGE.NAME' where object_type = 'acs_message'; -- Added function name to package acs_message; -- @../../../acs-messaging/sql/acs-messaging-packages.sql -- would like to source file using @, but for some reason source not working -- have to copy file. -- -- packages/acs-messaging/sql/acs-messaging-packages.sql -- -- @author John Prevost -- @author Phong Nguyen -- @creation-date 2000-08-27 -- @cvs-id $Id: upgrade-4.1-4.1.1.sql,v 1.1 2001/05/23 16:39:23 jong Exp $ -- create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default 0, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ); procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ); function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_file ( file_id in cr_items.item_id%TYPE ); function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE, content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE; procedure delete_image ( image_id in cr_items.item_id%TYPE ); function new_extlink ( name in cr_items.name%TYPE, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE; function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ); function name ( message_id in acs_objects.object_id%TYPE ) return varchar2; end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default null, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, parent_id in cr_items.parent_id%TYPE default 0, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message', is_live in char default 't' ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin -- generate a message id now so we can get an rfc822 message-id if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; -- this needs to be fixed up, but Oracle doesn't give us a way -- to get the FQDN if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_message_id := content_item.new ( name => v_rfc822_id, parent_id => parent_id, content_type => 'acs_message_revision', item_id => message_id, context_id => context_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message.edit ( message_id => v_message_id, title => title, description => description, mime_type => mime_type, text => text, data => data, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_message_id; end new; function edit ( message_id in acs_messages.message_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin -- create a new revision using whichever call is appropriate if edit.data is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, data => data, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); elsif title is not null or text is not null then v_revision_id := content_revision.new ( item_id => message_id, title => title, description => description, text => text, mime_type => mime_type, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); end if; -- test for auto approval of revision if edit.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit; procedure delete ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.delete.message_id; content_item.delete(message_id); end delete; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id integer; begin select decode(count(message_id),0,0,1) into v_check_message_id from acs_messages where message_id = message_p.message_id; if v_check_message_id <> 0 then return 't'; else return 'f'; end if; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, to_address in varchar2, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) values (message_id, to_address, grouping_id, v_wait_until); end send; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default null, wait_until in date default sysdate ) is v_wait_until date; begin v_wait_until := nvl(wait_until, sysdate); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select send.message_id, p.email, send.grouping_id, v_wait_until from parties p where p.party_id = send.recipient_id; end send; function first_ancestor ( message_id in acs_messages.message_id%TYPE ) return acs_messages.message_id%TYPE is v_message_id acs_messages.message_id%TYPE; begin select message_id into v_message_id from (select message_id, reply_to from acs_messages connect by message_id = prior reply_to start with message_id = first_ancestor.message_id) ancestors where reply_to is null; return v_message_id; end first_ancestor; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. function new_file ( message_id in acs_messages.message_id%TYPE, file_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_file_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_file_id := content_item.new ( name => file_name, parent_id => message_id, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- create an initial revision for the new attachment v_revision_id := edit_file ( file_id => v_file_id, title => title, description => description, mime_type => mime_type, content => content, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_file_id; end new_file; function edit_file ( file_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => title, mime_type => mime_type, data => content, item_id => file_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- test for auto approval of revision if is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_file; procedure delete_file ( file_id in cr_items.item_id%TYPE ) is begin content_item.delete(delete_file.file_id); end delete_file; function new_image ( message_id in acs_messages.message_id%TYPE, image_id in cr_items.item_id%TYPE default null, file_name in cr_items.name%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_image_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_image_id := content_item.new ( name => file_name, parent_id => message_id, item_id => image_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip ); -- create an initial revision for the new attachment v_revision_id := edit_image ( image_id => v_image_id, title => title, description => description, mime_type => mime_type, content => content, width => width, height => height, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, is_live => is_live ); return v_image_id; end new_image; function edit_image ( image_id in cr_items.item_id%TYPE, title in cr_revisions.title%TYPE default null, description in cr_revisions.description%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', content in cr_revisions.content%TYPE default null, width in images.width%TYPE default null, height in images.height%TYPE default null, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, is_live in char default 't' ) return acs_objects.object_id%TYPE is v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision.new ( title => edit_image.title, mime_type => edit_image.mime_type, data => edit_image.content, item_id => edit_image.image_id, creation_date => edit_image.creation_date, creation_user => edit_image.creation_user, creation_ip => edit_image.creation_ip ); -- insert new width and height values -- XXX fix after image.new exists insert into images (image_id, width, height) values (v_revision_id, width, height); -- test for auto approval of revision if edit_image.is_live = 't' then content_item.set_live_revision(v_revision_id); end if; return v_revision_id; end edit_image; procedure delete_image ( image_id in cr_items.item_id%TYPE ) is begin -- XXX fix after image.delete exists delete from images where image_id = delete_image.image_id; content_item.delete(image_id); end delete_image; -- XXX should just call content_extlink.new function new_extlink ( name in cr_items.name%TYPE default null, extlink_id in cr_extlinks.extlink_id%TYPE default null, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null, parent_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink.new ( name => new_extlink.name, url => new_extlink.url, label => new_extlink.label, description => new_extlink.description, parent_id => new_extlink.parent_id, extlink_id => new_extlink.extlink_id, creation_date => new_extlink.creation_date, creation_user => new_extlink.creation_user, creation_ip => new_extlink.creation_ip ); end new_extlink; -- XXX should just edit extlink function edit_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE, url in cr_extlinks.url%TYPE, label in cr_extlinks.label%TYPE default null, description in cr_extlinks.description%TYPE default null ) return cr_extlinks.extlink_id%TYPE is v_is_extlink char; begin v_is_extlink := content_extlink.is_extlink(edit_extlink.extlink_id); if v_is_extlink = 't' then update cr_extlinks set url = edit_extlink.url, label = edit_extlink.label, description = edit_extlink.description where extlink_id = edit_extlink.extlink_id; end if; return v_is_extlink; end edit_extlink; procedure delete_extlink ( extlink_id in cr_extlinks.extlink_id%TYPE ) is begin content_extlink.delete(extlink_id => delete_extlink.extlink_id); end delete_extlink; function name ( message_id in acs_objects.object_id%TYPE ) return varchar2 is v_message_name acs_messages_all.title%TYPE; begin select title into v_message_name from acs_messages_all where message_id = name.message_id; return v_message_name; end name; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-5.3.0d1-5.3.0d2.sql0000644000175000017500000000014610475321744027660 0ustar frankiefrankieupdate acs_object_types set table_name=null, id_column=null where object_type='acs_message_revision'; openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-4.6.2-4.6.3.sql0000644000175000017500000001016510042701712027203 0ustar frankiefrankie-- DRB: The drop is needed otherwise we'll get ambiguous function -- errors on calls from query files using bindvar emulation, where -- all the parameters are quoted and therefore of unknown type. create or replace function acs_message__new (integer,integer,timestamptz,integer, varchar,varchar,varchar,varchar,text,integer,integer,integer,integer, varchar,varchar,boolean) returns integer as ' declare p_message_id alias for $1; --default null, p_reply_to alias for $2; --default null, p_sent_date alias for $3; --default sysdate, p_sender alias for $4; --default null, p_rfc822_id alias for $5; --default null, p_title alias for $6; --default null, p_description alias for $7; --default null, p_mime_type alias for $8; --default ''text/plain'', p_text alias for $9; --default null, p_data alias for $10; --default null, p_parent_id alias for $11; --default 0, p_context_id alias for $12; p_creation_date timestamptz := current_timestamp; -- alias for $13 --default sysdate, p_creation_user alias for $13; --default null, p_creation_ip alias for $14; --default null, p_object_type alias for $15; --default ''acs_message'', p_is_live alias for $16; --default ''t'' v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_system_url varchar; v_domain_name varchar; v_idx integer; begin -- generate a message id now so we can get an rfc822 message-id if p_message_id is null then select acs_object_id_seq.nextval into v_message_id; else v_message_id := p_message_id; end if; -- need to make this mandatory also - jg -- this needs to be fixed up, but Oracle doesn''t give us a way -- to get the FQDN -- vk: get SystemURL parameter and use it to extract domain name select apm__get_value(package_id, ''SystemURL'') into v_system_url from apm_packages where package_key=''acs-kernel''; v_idx := position(''http://'' in v_system_url); v_domain_name := trim (substr(v_system_url, v_idx + 7)); if p_rfc822_id is null then v_rfc822_id := current_date || ''.'' || v_message_id || ''@'' || v_domain_name || ''.hate''; else v_rfc822_id := p_rfc822_id; end if; v_message_id := content_item__new ( v_rfc822_id, -- name p_parent_id, -- parent_id p_message_id, -- item_id null, -- locale p_creation_date, -- creation_date p_creation_user, -- creation_user p_context_id, -- context_id p_creation_ip, -- creation_ip p_object_type, -- item_subtype ''acs_message_revision'', -- content_type null, -- title null, -- description ''text/plain'', -- mime_type null, -- nls_language null, -- text ''text'' -- storage_type ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, p_reply_to, p_sent_date, p_sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message__edit ( v_message_id, -- message_id p_title, -- title p_description, -- description p_mime_type, -- mime_type p_text, -- text p_data, -- data p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip, -- creation_ip p_is_live -- is_live ); return v_message_id; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-5.1.0d1-5.1.0d2.sql0000644000175000017500000000040310024403024027626 0ustar frankiefrankieupdate acs_objects set title = (select name from cr_items where item_id = object_id), package_id = acs_object__package_id(content_item__get_root_folder(object_id)) where object_type = 'acs_message'; \i ../acs-messaging-packages.sql openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-4.0.1-4.1.sql0000644000175000017500000000046507302763673027053 0ustar frankiefrankie-- -- acs-messaging sql/upgrade-4.0.1-4.1.sql -- -- @author John Prevost -- @creation-date 2001-01-16 -- @cvs-id $Id: upgrade-4.0.1-4.1.sql,v 1.1 2001/05/23 16:39:23 jong Exp $ -- -- do all the views and packages in case something changed @@ acs-messaging-views @@ acs-messaging-packagesopenacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-4.0-4.0.1a.sql0000644000175000017500000002136607302763673027216 0ustar frankiefrankie-- -- acs-messaging sql/upgrade-4.0-4.0.1a.sql -- -- @author jmp@arsdigita.com -- @creation-date 2000-11-03 -- @cvs-id $Id: upgrade-4.0-4.0.1a.sql,v 1.1 2001/05/23 16:39:23 jong Exp $ -- alter table acs_messages add ( sent_date date constraint acs_messages_sent_date_nn not null disable, sender integer constraint acs_messages_sender_fk references parties (party_id) disable, rfc822_id varchar2(250) constraint acs_messages_rfc822_id_nn not null disable constraint acs_messages_rfc822_id_un unique disable ); create table acs_mess_up ( id integer primary key, sent_date date, sender integer, rfc822_id varchar2(250) ); insert into acs_mess_up select m.message_id, r.publish_date as sent_date, o.creation_user as sender, (sysdate || '.' || message_id || '@' || utl_inaddr.get_host_name||'.hate') as rfc822_id from acs_objects o, cr_items i, cr_revisions r, acs_messages m where m.message_id = i.item_id and m.message_id = o.object_id and r.revision_id = i.live_revision; update acs_messages set sent_date = (select sent_date from acs_mess_up where id = message_id), sender = (select sender from acs_mess_up where id = message_id), rfc822_id = (select rfc822_id from acs_mess_up where id = message_id); drop table acs_mess_up; alter table acs_messages modify constraint acs_messages_sent_date_nn enable; alter table acs_messages modify constraint acs_messages_sender_fk enable; alter table acs_messages modify constraint acs_messages_rfc822_id_nn enable; alter table acs_messages modify constraint acs_messages_rfc822_id_un enable; create or replace view acs_messages_all as select m.message_id, m.reply_to, m.sent_date, m.sender, m.rfc822_id, r.title, r.mime_type, r.content, o.context_id from acs_objects o, cr_items i, cr_revisions r, acs_messages m where o.object_id = m.message_id and i.item_id = m.message_id and r.revision_id = i.live_revision; create table acs_messages_outgoing ( message_id integer constraint amo_message_id_fk references acs_messages (message_id) on delete cascade, recipient_id integer constraint amo_recipient_id_fk references parties (party_id), grouping_id integer, wait_until date not null, constraint acs_messages_outgoing_pk primary key (message_id, recipient_id) ); comment on column acs_messages_outgoing.grouping_id is ' This identifier is used to group sets of messages to be sent as digests. When a message is about to be sent, any other messages with the same grouping_id will be put together with it in a digest. It is recommended but not required that an object id is used. Bboard, for example, might use the forum id that the user''s subscribed to. For instant (non-digest) updates, it would be appropriate to use null, which is never equal to anything else. '; comment on column acs_messages_outgoing.wait_until is ' Don''t schedule a send until after this date. If another message with the same grouping ID is scheduled to be sent, then this message may be sent at the same time. (So, for example, daily digests would be achieved by setting the grouping_id to the same value, and the wait_until value to the end of the current day. As soon as one message in the group is to be sent, all will be sent.) '; create or replace package acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message' ) return acs_objects.object_id%TYPE; procedure delete ( message_id in acs_messages.message_id%TYPE ); function message_p ( message_id in acs_messages.message_id%TYPE ) return char; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default NULL, wait_until in date default SYSDATE ); end acs_message; / show errors create or replace package body acs_message as function new ( message_id in acs_messages.message_id%TYPE default null, reply_to in acs_messages.reply_to%TYPE default null, sent_date in acs_messages.sent_date%TYPE default sysdate, sender in acs_messages.sender%TYPE default null, rfc822_id in acs_messages.rfc822_id%TYPE default null, title in cr_revisions.title%TYPE default null, mime_type in cr_revisions.mime_type%TYPE default 'text/plain', text in varchar2 default null, data in cr_revisions.content%TYPE default null, context_id in acs_objects.context_id%TYPE, creation_date in acs_objects.creation_date%TYPE default sysdate, creation_user in acs_objects.creation_user%TYPE default null, creation_ip in acs_objects.creation_ip%TYPE default null, object_type in acs_objects.object_type%TYPE default 'acs_message' ) return acs_objects.object_id%TYPE is v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_name cr_items.name%TYPE; begin if message_id is null then select acs_object_id_seq.nextval into v_message_id from dual; else v_message_id := message_id; end if; if rfc822_id is null then v_rfc822_id := sysdate || '.' || v_message_id || '@' || utl_inaddr.get_host_name || '.hate'; else v_rfc822_id := rfc822_id; end if; v_name := v_rfc822_id; v_message_id := content_item.new ( name => v_name, parent_id => context_id, item_id => message_id, creation_date => creation_date, creation_user => creation_user, creation_ip => creation_ip, item_subtype => object_type, title => title, mime_type => mime_type, text => text, data => data, is_live => 't' ); -- I hate you, milkman CR. -- Fix the broken permissions stuff content_item.new does update acs_objects set security_inherit_p = 't' where object_id = v_message_id; delete from acs_permissions where object_id = v_message_id; insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, reply_to, sent_date, sender, v_rfc822_id); return v_message_id; end new; procedure delete ( message_id in acs_messages.message_id%TYPE ) is begin delete from acs_messages where message_id = acs_message.delete.message_id; content_item.delete(message_id); end; function message_p ( message_id in acs_messages.message_id%TYPE ) return char is v_check_message_id char(1); begin select decode(count(message_id),0,'f','t') into v_check_message_id from acs_messages where message_id = message_p.message_id; return v_check_message_id; end message_p; procedure send ( message_id in acs_messages.message_id%TYPE, recipient_id in parties.party_id%TYPE, grouping_id in integer default NULL, wait_until in date default SYSDATE ) is v_wait_until date; begin v_wait_until := nvl(wait_until, SYSDATE); insert into acs_messages_outgoing (message_id, recipient_id, grouping_id, wait_until) values (message_id, recipient_id, grouping_id, nvl(wait_until,SYSDATE)); end; end acs_message; / show errors openacs-5.7.0/packages/acs-messaging/sql/postgresql/upgrade/upgrade-5.0.0b3-5.0.0b4.sql0000644000175000017500000000036007766162052027654 0ustar frankiefrankie-- call image__delete instead. create or replace function acs_message__delete_image (integer) returns integer as ' declare p_image_id alias for $1; begin perform image__delete(p_image_id); return 1; end;' language 'plpgsql'; openacs-5.7.0/packages/acs-messaging/sql/postgresql/acs-messaging-packages.sql0000644000175000017500000006364211144344032027321 0ustar frankiefrankie-- -- packages/acs-messaging/sql/acs-messaging-packages.sql -- -- @author John Prevost -- @author Phong Nguyen -- @author Jon Griffin -- @creation-date 2000-08-27 -- @cvs-id $Id: acs-messaging-packages.sql,v 1.19 2009/02/10 18:31:54 jeffd Exp $ -- -- updated for OpenACS by Jon Griffin -- create or replace function acs_message__edit (integer,varchar,varchar,varchar,text,integer,timestamptz,integer,varchar,boolean) returns integer as ' declare p_message_id alias for $1; p_title alias for $2; -- default null p_description alias for $3; -- default null p_mime_type alias for $4; -- default ''text/plain'' p_text alias for $5; -- default null p_data alias for $6; -- default null p_creation_date alias for $7; -- default sysdate p_creation_user alias for $8; -- default null p_creation_ip alias for $9; -- default null p_is_live alias for $10; -- default ''t'' v_revision_id cr_revisions.revision_id%TYPE; begin -- create a new revision using whichever call is appropriate if p_data is not null then -- need to take care of blob? v_revision_id := content_revision__new ( p_message_id, -- item_id p_title, -- title p_description, -- description p_data, -- data p_mime_type, -- mime_type p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip -- creation_ip ); else if p_title is not null or p_text is not null then v_revision_id := content_revision__new ( p_title, -- title p_description, -- description now(), -- publish_date p_mime_type, -- mime_type null, -- nls_language p_text, -- text p_message_id, -- item_id null, -- revision_id p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip -- creation_ip ); end if; end if; -- test for auto approval of revision if p_is_live then perform content_item__set_live_revision(v_revision_id); end if; return v_revision_id; end;' language 'plpgsql'; ---------------- -- MAJOR NOTE OF NON-COMPLIANCE -- I am exercising my rights as the porter here! -- I can only use 16 parameters so I am changing one -- creation_date will default to sysdate and not be a parameter -- possibly another function can be made to change that -- although I really don't see much need for this. -- Jon Griffin 05-21-2001 ---------------- create or replace function acs_message__new (integer,integer,timestamptz,integer, varchar,varchar,varchar,varchar,text,integer,integer,integer,integer, varchar,varchar,boolean,integer) returns integer as ' declare p_message_id alias for $1; --default null, p_reply_to alias for $2; --default null, p_sent_date alias for $3; --default sysdate, p_sender alias for $4; --default null, p_rfc822_id alias for $5; --default null, p_title alias for $6; --default null, p_description alias for $7; --default null, p_mime_type alias for $8; --default ''text/plain'', p_text alias for $9; --default null, p_data alias for $10; --default null, p_parent_id alias for $11; --default 0, p_context_id alias for $12; p_creation_date timestamptz := current_timestamp; -- alias for $13 --default sysdate, p_creation_user alias for $13; --default null, p_creation_ip alias for $14; --default null, p_object_type alias for $15; --default ''acs_message'', p_is_live alias for $16; --default ''t'' p_package_id alias for $17; v_message_id acs_messages.message_id%TYPE; v_rfc822_id acs_messages.rfc822_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; v_system_url varchar; v_domain_name varchar; v_idx integer; begin -- generate a message id now so we can get an rfc822 message-id if p_message_id is null then select nextval(''t_acs_object_id_seq'') into v_message_id; else v_message_id := p_message_id; end if; -- need to make this mandatory also - jg -- this needs to be fixed up, but Oracle doesn''t give us a way -- to get the FQDN -- vk: get SystemURL parameter and use it to extract domain name select apm__get_value(package_id, ''SystemURL'') into v_system_url from apm_packages where package_key=''acs-kernel''; v_idx := position(''http://'' in v_system_url); v_domain_name := trim (substr(v_system_url, v_idx + 7)); if p_rfc822_id is null then v_rfc822_id := current_date || ''.'' || v_message_id || ''@'' || v_domain_name || ''.hate''; else v_rfc822_id := p_rfc822_id; end if; v_message_id := content_item__new ( v_rfc822_id, -- name p_parent_id, -- parent_id p_message_id, -- item_id null, -- locale p_creation_date, -- creation_date p_creation_user, -- creation_user p_context_id, -- context_id p_creation_ip, -- creation_ip p_object_type, -- item_subtype ''acs_message_revision'', -- content_type null, -- title null, -- description ''text/plain'', -- mime_type null, -- nls_language null, -- text ''text'', -- storage_type p_package_id ); insert into acs_messages (message_id, reply_to, sent_date, sender, rfc822_id) values (v_message_id, p_reply_to, p_sent_date, p_sender, v_rfc822_id); -- create an initial revision for the new message v_revision_id := acs_message__edit ( v_message_id, -- message_id p_title, -- title p_description, -- description p_mime_type, -- mime_type p_text, -- text p_data, -- data p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip, -- creation_ip p_is_live -- is_live ); return v_message_id; end;' language 'plpgsql'; create or replace function acs_message__new (integer,integer,timestamptz,integer, varchar,varchar,varchar,varchar,text,integer,integer,integer,integer, varchar,varchar,boolean) returns integer as ' declare p_message_id alias for $1; --default null, p_reply_to alias for $2; --default null, p_sent_date alias for $3; --default sysdate, p_sender alias for $4; --default null, p_rfc822_id alias for $5; --default null, p_title alias for $6; --default null, p_description alias for $7; --default null, p_mime_type alias for $8; --default ''text/plain'', p_text alias for $9; --default null, p_data alias for $10; --default null, p_parent_id alias for $11; --default 0, p_context_id alias for $12; p_creation_date timestamptz := current_timestamp; -- alias for $13 --default sysdate, p_creation_user alias for $13; --default null, p_creation_ip alias for $14; --default null, p_object_type alias for $15; --default ''acs_message'', p_is_live alias for $16; --default ''t'' begin return acs_message__new (p_message_id, p_reply_to, p_sent_date, p_sender, p_rfc822_id, p_title, p_description, p_mime_type, p_text, p_data, p_parent_id, p_context_id, p_creation_user, p_creation_ip, p_object_type, p_is_live, null::integer ); end;' language 'plpgsql'; create or replace function acs_message__delete (integer) returns integer as ' declare p_message_id alias for $1; begin delete from acs_messages where message_id = p_message_id; perform content_item__delete(p_message_id); return 1; end;' language 'plpgsql'; create or replace function acs_message__message_p (integer) returns boolean as ' declare p_message_id alias for $1; v_check_message_id integer; begin select count(message_id) into v_check_message_id from acs_messages where message_id = p_message_id; if v_check_message_id <> 0 then return ''t''; else return ''f''; end if; end;' language 'plpgsql' stable; create or replace function acs_message__send (integer,varchar,integer,timestamptz) returns integer as ' declare p_message_id alias for $1; p_to_address alias for $2; p_grouping_id alias for $3; -- default null p_wait_until alias for $4; -- default sysdate v_wait_until timestamptz; begin v_wait_until := coalesce(p_wait_until, current_timestamp); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) values (p_message_id, p_to_address, p_grouping_id, v_wait_until); return 1; end;' language 'plpgsql'; create or replace function acs_message__send (integer,integer,integer,timestamptz) returns integer as ' declare p_message_id alias for $1; p_recipient_id alias for $2; p_grouping_id alias for $3; -- default null p_wait_until alias for $4; -- default sysdate v_wait_until timestamptz; begin v_wait_until := coalesce (p_wait_until, current_timestamp); insert into acs_messages_outgoing (message_id, to_address, grouping_id, wait_until) select p_message_id, p.email, p_grouping_id, v_wait_until from parties p where p.party_id = p_recipient_id; return 1; end;' language 'plpgsql'; -- Ported to take advantage of tree_sortkey column by DLP create or replace function acs_message__first_ancestor (integer) returns integer as ' declare p_message_id alias for $1; v_message_id acs_messages.message_id%TYPE; v_ancestor_sk varbit; begin select tree_ancestor_key(tree_sortkey, 1) into v_ancestor_sk from acs_messages where message_id = p_message_id; select message_id into v_message_id from acs_messages where tree_sortkey = v_ancestor_sk; return v_message_id; end;' language 'plpgsql' stable strict; -- ACHTUNG! WARNING! ACHTUNG! WARNING! ACHTUNG! WARNING! -- -- Developers: Please don't depend on the following functionality -- to remain in the same place. Chances are very good these -- functions will migrate to another PL/SQL package or be replaced -- by direct calls to CR code in the near future. create or replace function acs_message__new_file (integer,integer,varchar,varchar, text,varchar,integer,timestamptz,integer,varchar,boolean,varchar,integer) returns integer as ' declare p_message_id alias for $1; p_file_id alias for $2; -- default null p_file_name alias for $3; p_title alias for $4; -- default null p_description alias for $5; -- default null p_mime_type alias for $6; -- default ''text/plain'' p_data alias for $7; -- default null p_creation_date alias for $8; -- default sysdate p_creation_user alias for $9; -- default null p_creation_ip alias for $10; -- default null p_is_live alias for $11; -- default ''t'' p_storage_type alias for $12; -- default ''file'' p_package_id alias for $13; -- default null v_file_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_file_id := content_item__new ( p_file_name, -- name p_message_id, -- parent_id p_file_id, -- item_id null, -- locale p_creation_date, -- creation_date p_creation_user, -- creation_user null, -- context_id p_creation_ip, -- creation_ip ''content_item'', -- item_subtype ''content_revision'', -- content_type null, -- title null, -- description ''text/plain'', -- mime_type null, -- nls_language null, -- text p_storage_type, -- storage_type p_package_id -- package_id ); -- create an initial revision for the new attachment v_revision_id := acs_message__edit_file ( v_file_id, -- file_id p_title, -- title p_description, -- description p_mime_type, -- mime_type p_data, -- data p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip, -- creation_ip p_is_live -- is_live ); return v_file_id; end;' language 'plpgsql'; create or replace function acs_message__new_file (integer,integer,varchar,varchar, text,varchar,integer,timestamptz,integer,varchar,boolean,varchar) returns integer as ' declare p_message_id alias for $1; p_file_id alias for $2; -- default null p_file_name alias for $3; p_title alias for $4; -- default null p_description alias for $5; -- default null p_mime_type alias for $6; -- default ''text/plain'' p_data alias for $7; -- default null p_creation_date alias for $8; -- default sysdate p_creation_user alias for $9; -- default null p_creation_ip alias for $10; -- default null p_is_live alias for $11; -- default ''t'' p_storage_type alias for $12; -- default ''file'' begin return acs_message__new_file (p_message_id, p_file_id, p_file_name, p_title, p_description, p_mime_type, p_data, p_creation_date, p_creation_user, p_creation_ip, p_is_live, p_storage_type, null ); end;' language 'plpgsql'; create or replace function acs_message__edit_file (integer,varchar,text,varchar, integer,timestamptz,integer,varchar,boolean) returns integer as ' declare p_file_id alias for $1; p_title alias for $2; -- default null p_description alias for $3; -- default null p_mime_type alias for $4; -- default ''text/plain'' p_data alias for $5; -- default null p_creation_date alias for $6; -- default sysdate p_creation_user alias for $7; -- default null p_creation_ip alias for $8; -- default null p_is_live alias for $9; -- default ''t'' v_revision_id cr_revisions.revision_id%TYPE; begin v_revision_id := content_revision__new ( p_title, -- title p_description, current_timestamp, p_mime_type, -- mime_type NULL, p_data, -- data p_file_id, -- item_id NULL, p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip -- creation_ip ); -- test for auto approval of revision if p_is_live then perform content_item__set_live_revision(v_revision_id); end if; return v_revision_id; end;' language 'plpgsql'; create or replace function acs_message__delete_file (integer) returns integer as ' declare p_file_id alias for $1; begin perform content_item__delete(p_file_id); return 1; end;' language 'plpgsql'; create or replace function acs_message__new_image (integer,integer,varchar,varchar, text,varchar,integer,integer,integer,timestamptz,integer,varchar,boolean,varchar,integer) returns integer as ' declare p_message_id alias for $1; p_image_id alias for $2; -- default null p_file_name alias for $3; p_title alias for $4; -- default null p_description alias for $5; -- default null p_mime_type alias for $6; -- default ''text/plain'' p_data alias for $7; -- default null p_width alias for $8; -- default null p_height alias for $9; -- default null p_creation_date alias for $10; -- default sysdate p_creation_user alias for $11; -- default null p_creation_ip alias for $12; -- default null p_is_live alias for $13; -- default ''t'' p_storage_type alias for $14; -- default ''file'' p_package_id alias for $15; -- default null v_image_id cr_items.item_id%TYPE; v_revision_id cr_revisions.revision_id%TYPE; begin v_image_id := content_item__new ( p_file_name, -- name p_message_id, -- parent_id p_image_id, -- item_id null, -- locale p_creation_date, -- creation_date p_creation_user, -- creation_user null, -- context_id p_creation_ip, -- creation_ip ''content_item'', -- item_subtype ''content_revision'', -- content_type null, -- title null, -- description ''text/plain'', -- mime_type null, -- nls_language null, -- text ''file'', -- storage_type p_package_id -- package_id ); -- create an initial revision for the new attachment v_revision_id := acs_message__edit_image ( v_image_id, -- image_id p_title, -- title p_description, -- description p_mime_type, -- mime_type p_data, -- data p_width, -- width p_height, -- height p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip, -- creation_ip p_is_live -- is_live ); return v_image_id; end;' language 'plpgsql'; create or replace function acs_message__new_image (integer,integer,varchar,varchar, text,varchar,integer,integer,integer,timestamptz,integer,varchar,boolean,varchar) returns integer as ' declare p_message_id alias for $1; p_image_id alias for $2; -- default null p_file_name alias for $3; p_title alias for $4; -- default null p_description alias for $5; -- default null p_mime_type alias for $6; -- default ''text/plain'' p_data alias for $7; -- default null p_width alias for $8; -- default null p_height alias for $9; -- default null p_creation_date alias for $10; -- default sysdate p_creation_user alias for $11; -- default null p_creation_ip alias for $12; -- default null p_is_live alias for $13; -- default ''t'' p_storage_type alias for $14; -- default ''file'' begin return acs_message__new_image (p_message_id, p_image_id, p_file_name, p_title, p_description, p_mime_type, p_data, p_width, p_height, p_creation_date, p_creation_user, p_creation_ip, p_is_live, p_storage_type, null ); end;' language 'plpgsql'; create or replace function acs_message__edit_image (integer,varchar,text,varchar, integer,integer,integer,timestamptz,integer,varchar,boolean) returns integer as ' declare p_image_id alias for $1; p_title alias for $2; -- default null p_description alias for $3; -- default null p_mime_type alias for $4; -- default ''text/plain'' p_data alias for $5; -- default null p_width alias for $6; -- default null p_height alias for $7; -- default null p_creation_date alias for $8; -- default sysdate p_creation_user alias for $9; -- default null p_creation_ip alias for $10; -- default null p_is_live alias for $11; -- default ''t'' v_revision_id cr_revisions.revision_id%TYPE; begin -- not sure which __new to use v_revision_id := content_revision__new ( p_title, -- title NULL, -- description current_timestamp, -- publish_date p_mime_type, -- mime_type NULL, -- nls_language p_data, -- data p_image_id, -- item_id NULL, -- revision_id p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip -- creation_ip ); -- insert new width and height values -- XXX fix after image.new exists insert into images (image_id, width, height) values (v_revision_id, p_width, p_height); -- test for auto approval of revision if p_is_live then perform content_item__set_live_revision(v_revision_id); end if; return v_revision_id; end;' language 'plpgsql'; create or replace function acs_message__delete_image (integer) returns integer as ' declare p_image_id alias for $1; begin perform image__delete(p_image_id); return 0; end;' language 'plpgsql'; -- XXX should just call content_extlink.new create or replace function acs_message__new_extlink (varchar,integer,varchar, varchar,text,integer,timestamptz,integer,varchar,integer) returns integer as ' declare p_name alias for $1; -- default null p_extlink_id alias for $2; -- default null p_url alias for $3; p_label alias for $4; -- default null p_description alias for $5; -- default null p_parent_id alias for $6; p_creation_date alias for $7; -- default sysdate p_creation_user alias for $8; -- default null p_creation_ip alias for $9; -- default null p_package_id alias for $10; -- default null v_extlink_id cr_extlinks.extlink_id%TYPE; begin v_extlink_id := content_extlink__new ( p_name, -- name p_url, -- url p_label, -- label p_description, -- description p_parent_id, -- parent_id p_extlink_id, -- extlink_id p_creation_date, -- creation_date p_creation_user, -- creation_user p_creation_ip, -- creation_ip p_package_id ); return v_extlink_id; end;' language 'plpgsql'; create or replace function acs_message__new_extlink (varchar,integer,varchar, varchar,text,integer,timestamptz,integer,varchar) returns integer as ' declare p_name alias for $1; -- default null p_extlink_id alias for $2; -- default null p_url alias for $3; p_label alias for $4; -- default null p_description alias for $5; -- default null p_parent_id alias for $6; p_creation_date alias for $7; -- default sysdate p_creation_user alias for $8; -- default null p_creation_ip alias for $9; -- default null begin return acs_message__new_extlink (p_name, p_extlink_id, p_url, p_label, p_description, p_parent_id, p_creation_date, p_creation_user, p_creation_ip, null ); end;' language 'plpgsql'; -- XXX should just edit extlink create or replace function acs_message__edit_extlink (integer,varchar,varchar,text) returns integer as ' declare p_extlink_id alias for $1; p_url alias for $2; p_label alias for $3; -- default null p_description alias for $4; -- default null v_is_extlink boolean; begin v_is_extlink := content_extlink__is_extlink(p_extlink_id); if v_is_extlink = ''t'' then update cr_extlinks set url = p_url, label = p_label, description = p_description where extlink_id = p_extlink_id; end if; return 0; end;' language 'plpgsql'; create or replace function acs_message__delete_extlink (integer) returns integer as ' declare p_extlink_id alias for $1; begin perform content_extlink__delete(p_extlink_id); return 0; end;' language 'plpgsql'; create or replace function acs_message__name (integer) returns varchar as ' declare p_message_id alias for $1; v_message_name cr_revisions.title%TYPE; begin select title into v_message_name from acs_messages_all where message_id = p_message_id; return v_message_name; end;' language 'plpgsql' stable strict; openacs-5.7.0/packages/acs-messaging/www/0000755000175000017500000000000011575225532020125 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/www/doc/0000755000175000017500000000000011575225532020672 5ustar frankiefrankieopenacs-5.7.0/packages/acs-messaging/www/doc/design.html0000644000175000017500000000711311043666757023043 0ustar frankiefrankie ACS Messaging Design

    ACS Messaging Design


    ACS Messaging was born out of the design of the new bboard. One thing we discovered when researching requirements for bboard and discussion software in general was that there are a variety of ways one may wish to structure and organize threads of messages e.g. in discrete forums with tagged categories, attached to other user objects annotated with user ratings, etc.,. Our design addressed this by separating the store of messages from the organizational data model and any user interfaces.

    ACS Messaging is this separate layer. Built atop the content repository, it provides the storage and retrieval of messages. We take messages to be objects that consist of a sender (an ACS party), a text body, an optional reference to a parent message, optional file attachments, and some miscellaneous auditing data.

    With these constraining constraining set of semantics, we can build a library of component functionality to operate on messages. For example: code that displays a message, forwards a message, compiles a set of messages into a digest, displays a specific attachment, etc., This functionality can then be reused across messaging applications such as bboard, webmail, and general comments. We can maintain user preferences on HTML vs. text email, inline attachments vs. URLs across the system, and have simple procedures that do the right thing when sending email. Another example: if we built the IMAP server functionality 3.4 webmail provides against acs-messaging, then bboard forums, pages of comments, and webmail folders could be viewed uniformly through your email client. The IMAP mapping isn't quite trivial, but you can see the idea.

    To reiterate, if applications are storing the same sort of data (a text-ish messages with optional attachments and replies), they should store them the same way. Then code from particular applications can possibly be refactored into generic functionality.

    spam/general alerts/etc isn't meant to be replaced by ACS Messaging, at least not with what is there currently. Currently it is just a store; but we intend it to be the canonical store for messages that need to be stored in the database. If messages are automatically generated from other user objects, they might need to be queue'd up or archived in the RDBMS. If so this should be done in the acs-messaging tables. We can implement the generic incoming email system by stashing messages in acs-messaging, then dispatching the message id to package specific code for processing.

    Currently (11/2000), ACS Messaging is very slim; it just supports bboard. We intend to add attachments (most likely implemented as content repository items that are children of the message), extensible headers (just like the webmail datamodel), and versioning as provided by the content repository.

    API

    ACS Messaging provides the acs_messages_all view as the primary mechanism for message queries.
    create or replace view acs_messages_all as
        select m.message_id, m.reply_to, o.context_id, r.title, r.publish_date,
               r.mime_type, r.content, o.creation_user
        ...
      
    ACS Messaging provides the PL/SQL function acs_message.post to add new messages.
    akk@arsdigita.com
    openacs-5.7.0/packages/acs-messaging/www/doc/index.html0000644000175000017500000000100107253523116022654 0ustar frankiefrankie ACS Messaging Docs

    ACS Messaging Docs


    Anukul Kapoor
    Last modified: Sat Sep 30 17:45:40 EDT 2000 openacs-5.7.0/packages/acs-messaging/www/doc/requirements.html0000644000175000017500000002303707253523116024305 0ustar frankiefrankie ACS Messaging Requirements

    ACS Messaging Requirements

    by Anukul Kapoor and Pete Su
    This is only a DRAFT

    I. Introduction

    In ACS 3.x, each messaging application (e.g. bboard, general comments, spam, ticket tracker and so on) used its own specialized data model for representing and manipulating messages. ACS Messages provides a common data model and API for these applications. The service provides the following common mechanisms:

    • A single data model for representing message objects. Message objects model electronic messages between users of a collaborative system. Mail messages, USENET news messages, Bboard messages, user comments are all examples of applications that might use message objects.
    • Storage of message objects.
    • Central support for attachments, threading, and search.
    • Mechanisms for sending and receiving message objects as e-mail.

    II. Vision Statement

    Messaging applications constitute some of the most useful forms of web collaboration. Many of the application packages that have been developed for ACS have a messaging component. Therefore, ACS Messaging provides a standard set of abstractions for storing, sending and receiving messages through a web service. Our goal is to support a diverse group of messaging applications through a single centralized facility.

    III. System/Application Overview

    The ACS Messaging package defines a data model and API for the storage and retrieval of messages. While the package standarizes how messages are stored, applications may use any data model they want for higher level organization of messages into threads, forums, and so on. ACS Messaging places no organizational constraints on client applications.

    The package consists of the following components:

    • A data model for representing and storing messages.
    • A data model for representing and storing attachments to messages.
    • A mechanism for sending messages as e-mail.
    • A mechanism for integrating the message store into site wide search.

    IV. Use-cases and User Scenarios

    ACS Messaging is generally not used directly by users, so there are no user interface level scenarios to consider at this point. It's possible that in the future we will want to extend the system with generic administrative user interfaces, but this is not clear right now.

    We scenarios that we should consider are the kinds of applications that we mean to support with this package, and what the developers of those applications would like to see in the data model and API.

    The following applications in ACS 3.x could have been implemented using this package:

    • BBoard
    • Webmail
    • General Comments
    • Spam
    • Various parts of the ticket tracker.

    Each of these applications requires a message store and each defines it's own high level organization for messages whithin that store.

    • Bboard organizes messages into forums and categories and threads. It also allows users to send and reply to messages via e-mail.
    • Webmail organizes messages into mail folders.
    • General comments attaches messages to objects representing static or other content.
    • Spam queues messages and sends them to groups of people as e-mail.

    The main requirement of the ACS Messages package is to support this diverse set of applications with a common infrastructure. This is because all of these applications would like the following kinds of common functionality:

    • Reply chaining and threading.
    • Messages with attachments of various types.
    • Representing messages as multipart MIME e-mail.
    • Queuing and sending messages as e-mail.

    V. Related Links

    VI.A Requirements: Datamodel

    10.0 Message Store

    ACS Messages should provide a single store for objects representing messages.

    20.0 Message Content

    A message should have a primary content body consisting of a specified MIME type and a block of storage holding the content. In addition, applications may store one or more seperate revisions of a message.

    30.0 Attachments

    Messages may be composed of additional attachments. Each attachment should be tagged with a MIME type to indicate what type of data is stored there. Each attachment can only be attached to a single parent message. In addition, the system must be able to store one or more revisions of each attachment.

    40.0 Unique ID

    Messages should have universally unique identifiers to allow global reference and RFC-822 compliance.

    50.0 Sender

    Messages should be related to the sending party.

    60.0 Threading

    The system model simple message threads, that is chains of messages that are replies to each other. If message M is a reply to some other message N, then M should be able to refer to N in a straightforward way.

    70.0 Search

    Messages should be searchable as part of a site wide search. Therefore, the data model must integrate with the data model for site wide search.

    VI.B Requirements: API

    80.0 Messages

    The system should provide the following interfaces for manipulating messages:

    80.10 Creation

    Applications should be able to create new messages objects.

    80.20 Revisions

    Applications should be able to create a new revision of a given message object.

    80.30 Deletion

    Applications should be able to delete a message and all of its revisions and attachments. (is this true?).

    80.40 Type Checking Applications should be able to check whether or not a given object is a message.

    90.0 Message Attachments

    The system should provide the following interfaces for manipulating message attachments.

    90.10 Creation

    Applications should be able to create new message attachments and connect to their parent object.

    90.20 Revisions

    Applications should be able to create a new revision of a given attachment.

    90.30 MIME Types

    Each attachment should have a MIME type. The system should be able in principle to deal with an arbitrary collection of MIME types, although initial implementations may be more limited.

    100.0 Messages and E-Mail

    The system should provide the following interfaces for integrating with existing E-mail systems. Note that these requirements only deal with sending mail. Our feeling that a seperate package should be implemented to deal with receiving mail that would use ACS Messages for storage of incoming messages.

    100.10 Sending Single Messages

    The system should provide a mechanism for specifying that a message should be sent as outgoing E-mail. Outgoing messages should be queued so that the system can maintain auditing information to deal with transport failures and so on.

    100.20 Sending MIME Messages

    The system should be able to send messages with attachments as multipart MIME messages.

    100.30 Sending Digests

    The system should be able to group multiple messages together as a single e-mail digest. For example, all the messages in a single bboard thread could be sent to a user as a digest.

    VII. Revision History

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Creation 10/04/2000 Anukul Kapoor
    0.2 Edited and extended for more general data model 11/07/2000 Pete Su

    Last modified: $Id: requirements.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ openacs-5.7.0/packages/acs-messaging/acs-messaging.info0000644000175000017500000000314411575167337022711 0ustar frankiefrankie Messaging Messaging Services t t Anukul Kapoor John Prevost Vinod Kurup General messaging for bboard and general comments. 2011-06-12 3 OpenACS GPL 3 Provides generic message services, with email sending. acs-mail-lite and notifications are the prefered packages for delivering this functionality and it is anticipated that this package will ultimately be deprecated. openacs-5.7.0/packages/acs-api-browser/0000755000175000017500000000000011724401450017545 5ustar frankiefrankieopenacs-5.7.0/packages/acs-api-browser/lib/0000755000175000017500000000000011724401450020313 5ustar frankiefrankieopenacs-5.7.0/packages/acs-api-browser/lib/search.adp0000644000175000017500000000601511043711736022255 0ustar frankiefrankie
    @db_doc_search_export;noquote@

    OpenACS Tcl API Search


    Browse OpenACS Tcl API

    Name contains:
    Exact name:
      
    Parameters:
    Documentation:
    Source:

    OpenACS PL/SQL API Search

    Browse OpenACS PL/SQL API

    AOLserver Tcl API Search


    (enter exact procedure name)
    Browse AOLserver Tcl API

    Tcl Documentation Search


    (enter exact procedure name)
    Browse the Tcl documentation

    @db_pretty@ Search


    @db_pretty@ Documentation

    Browse the @db_pretty@ documentation

    OpenACS and Package Documentation

    Browse OpenACS documentation
    openacs-5.7.0/packages/acs-api-browser/lib/search.tcl0000644000175000017500000000461710603053036022272 0ustar frankiefrankie# # API Browser search widget # # @cvs-id $Id: search.tcl,v 1.6 2007/03/30 00:13:18 victorg Exp $ # # Expects: query_string:optional # if { ![info exists query_string] } { set query_string {} } set aolserver_tcl_api_root "http://www.aolserver.com/docs/devel/tcl/api/" set tcl_docs_root "http://tcl.tk/man/tcl[info tclversion]/TclCmd/contents.htm" set package_url [apm_package_url_from_key "acs-api-browser"] set openacs_search_url "${package_url}proc-search" set openacs_browse_url "${package_url}proc-browse" set openacs_plsql_browse_url "${package_url}plsql-subprograms-all" set aolserver_search_url "${package_url}tcl-proc-view" set tcl_search_url "${package_url}tcl-doc-search" switch [db_type] { postgresql { set db_pretty "PostgreSQL [db_version]" set db_doc_url "http://www.postgresql.org/docs/[db_version]/interactive/index.html" set db_doc_search_url "http://search.postgresql.org/www.search" set db_doc_search_export [export_vars -form { { ul "http://www.postgresql.org/docs/[db_version]/static/%" } }] set db_doc_search_query_name "q" } oracle { set db_pretty "Oracle [db_version]" # Oracle docs require login, can't offer direct search link switch -glob [db_version] { 8.1.7 { set db_doc_url "http://otn.oracle.com/documentation/oracle8i.html" set db_doc_search_url "http://otn.oracle.com/pls/tahiti/tahiti.drilldown" set db_doc_search_export "" set db_doc_search_query_name "word" } 8.1.6 { set db_doc_url "http://otn.oracle.com/documentation/oracle8i_arch_816.html" } 9* { set db_doc_url "http://otn.oracle.com/documentation/oracle9i.html" set db_doc_search_url "http://otn.oracle.com/pls/db92/db92.drilldown" set db_doc_search_export "" set db_doc_search_query_name "word" } 10* { set db_doc_url "" set db_doc_search_url "http://otn.oracle.com/pls/db10g/db10g.drilldown" set db_doc_search_export "http://otn.oracle.com/pls/db10g/db10g.homepage" set db_doc_search_query_name "word" } default { set db_doc_url "" set db_doc_search_url "" set db_doc_search_export "" set db_doc_search_query_name "" } } } } openacs-5.7.0/packages/acs-api-browser/tcl/0000755000175000017500000000000011724401450020327 5ustar frankiefrankieopenacs-5.7.0/packages/acs-api-browser/tcl/test/0000755000175000017500000000000011575225377021326 5ustar frankiefrankieopenacs-5.7.0/packages/acs-api-browser/tcl/test/acs-api-browser-procs.tcl0000644000175000017500000000125610013646776026154 0ustar frankiefrankiead_library { Automated tests. @author Joel Aufrecht @creation-date 2 Nov 2003 @cvs-id $Id: acs-api-browser-procs.tcl,v 1.2 2004/02/15 10:46:22 tilmanns Exp $ } aa_register_case \ -cats {api smoke} \ acs_api_browser_trivial_smoke_test { Minimal smoke test for acs-api-browser package. } { aa_run_with_teardown \ -rollback \ -test_code { set result [api_library_documentation packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl] aa_true "api documentation proc can document itself" \ [ string match "*packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl*" $result] } }openacs-5.7.0/packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl0000644000175000017500000011226111143367766026366 0ustar frankiefrankie# /packages/acs-core/api-documentation-procs.tcl ad_library { Routines for generating API documentation. @author Jon Salz (jsalz@mit.edu) @author Lars Pind (lars@arsdigita.com) @creation-date 21 Jun 2000 @cvs-id $Id: acs-api-documentation-procs.tcl,v 1.27 2009/02/07 20:32:54 gustafn Exp $ } ad_proc -private api_first_sentence { string } { Returns the first sentence of a string. } { if { [regexp {^(.+?\.)\s} $string "" sentence] } { return $sentence } return $string } ad_proc -public api_read_script_documentation { path } { Reads the contract from a Tcl content page. @param path the path of the Tcl file to examine, relative to the OpenACS root directory. @return a list representation of the documentation element array, or an empty list if the file does not contain a doc_page_contract block. @error if the file does not exist. } { # First, examine the file to determine whether the first non-comment # line begins with the string "ad_page_contract". set has_contract_p 0 if { ![file exists "[acs_root_dir]/$path"] } { return -code error "File $path does not exist" } set file [open "[acs_root_dir]/$path" "r"] while { [gets $file line] >= 0 } { # Eliminate any comment characters. regsub -all {#.*$} $line "" line set line [string trim $line] if { $line ne "" } { set has_contract_p [regexp {^ad_page_contract\s} $line] break } } close $file if { !$has_contract_p } { return [list] } doc_set_page_documentation_mode 1 set errno [catch { source "[acs_root_dir]/$path" } error] doc_set_page_documentation_mode 0 if { $errno == 1 } { global errorInfo if { [regexp {^ad_page_contract documentation} $errorInfo] } { array set doc_elements $error } } else { global errorCode global errorInfo return -code $errno -errorcode $errorCode -errorinfo $errorInfo $error } if { [info exists doc_elements] } { return [array get doc_elements] } return [list] } ad_proc -private api_format_see_list { sees } { Generate an HTML list of referenced procs and pages. } { append out "
    See Also:\n
      " foreach see $sees { append out "
    • [api_format_see $see]\n" } append out "
    \n" return $out } ad_proc -private api_format_author_list { authors } { Generates an HTML-formatted list of authors (including <dt> and <dd> tags). @param authors the list of author strings. @return the formatted list, or an empty string if there are no authors. } { if { [llength $authors] == 0 } { return "" } append out "
    Author[ad_decode [llength $authors] 1 "" "s"]:\n" foreach author $authors { append out "
    [api_format_author $author]
    \n" } return $out } ad_proc -private api_format_changelog_change { change } { Formats the change log line: turns email addresses in parenthesis into links. } { regsub {\(([^ \n\r\t]+@[^ \n\r\t]+\.[^ \n\r\t]+)\)} $change {(\1)} change return $change } ad_proc -private api_format_changelog_list { changelog } { Format the change log info } { append out "
    Changelog:\n" foreach change $changelog { append out "
    [api_format_changelog_change $change]
    \n" } return $out } ad_proc -private api_format_common_elements { doc_elements_var } { upvar $doc_elements_var doc_elements set out "" if { [info exists doc_elements(author)] } { append out [api_format_author_list $doc_elements(author)] } if { [info exists doc_elements(creation-date)] } { append out "
    Created:\n
    [lindex $doc_elements(creation-date) 0]
    \n" } if { [info exists doc_elements(change-log)] } { append out [api_format_changelog_list $doc_elements(change-log)] } if { [info exists doc_elements(cvs-id)] } { append out "
    CVS ID:\n
    [ns_quotehtml [lindex $doc_elements(cvs-id) 0]]
    \n" } if { [info exists doc_elements(see)] } { append out [api_format_see_list $doc_elements(see)] } return $out } ad_proc -public api_script_documentation { { -format text/html } path } { Generates formatted documentation for a content page. Sources the file to obtain the comment or contract at the beginning. @param format the type of documentation to generate. Currently, only text/html is supported. @param path the path of the Tcl file to examine, relative to the OpenACS root directory. @return the formatted documentation string. @error if the file does not exist. } { append out "

    [file tail $path]

    \n" # If it's not a Tcl file, we can't do a heck of a lot yet. Eventually # we'll be able to handle ADPs, at least. if {[file extension $path] eq ".xql"} { append out "
    DB Query file
    \n" return $out } elseif { [file extension $path] ne ".tcl" } { append out "
    Delivered as [ns_guesstype $path]
    \n" return $out } if { [catch { array set doc_elements [api_read_script_documentation $path] } error] } { append out "
    Unable to read $path: [ns_quotehtml $error]
    \n" return $out } array set params [list] if { [info exists doc_elements(param)] } { foreach param $doc_elements(param) { if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } { set params($name) $value } } } append out "
    " if { [info exists doc_elements(main)] } { append out [lindex $doc_elements(main) 0] } else { append out "Does not contain a contract." } append out "
    \n" # XXX: This does not work at the moment. -bmq # if { [array size doc_elements] > 0 } { # array set as_flags $doc_elements(as_flags) # array set as_filters $doc_elements(as_filters) # array set as_default_value $doc_elements(as_default_value) # if { [llength $doc_elements(as_arg_names)] > 0 } { # append out "
    Query Parameters:
    \n" # foreach arg_name $doc_elements(as_arg_names) { # append out "$arg_name" # set notes [list] # if { [info exists as_default_value($arg_name)] } { # lappend notes "defaults to \"$as_default_value($arg_name)\"" # } # set notes [concat $notes $as_flags($arg_name)] # foreach filter $as_filters($arg_name) { # set filter_proc [ad_page_contract_filter_proc $filter] # lappend notes "$filter" # } # if { [llength $notes] > 0 } { # append out " ([join $notes ", "])" # } # if { [info exists params($arg_name)] } { # append out " - $params($arg_name)" # } # append out "
    \n" # } # append out "
    \n" # } # if { [info exists doc_elements(type)] && $doc_elements(type) ne "" } { # append out "
    Returns Type:
    $doc_elements(type)\n" # } # # XXX: Need to support "Returns Properties:" # } append out "
    Location:
    $path\n" append out [api_format_common_elements doc_elements] append out "
    " return $out } ad_proc -private api_format_author { author_string } { if { [regexp {^[^ \n\r\t]+$} $author_string] && \ [string first "@" $author_string] >= 0 && \ [string first ":" $author_string] < 0 } { return "$author_string" } elseif { [regexp {^([^\(\)]+)\s+\((.+)\)$} [string trim $author_string] {} name email] } { return "$name <$email>" } return $author_string } ad_proc -private api_format_see { see } { regsub -all {proc *} $see {} see set see [string trim $see] if {[nsv_exists api_proc_doc $see]} { return "$see" } if {[string match "/doc/*.html" $see] || [util_url_valid_p $see]} { return "$see" } if {[file exists "[get_server_root]${see}"]} { return "$see" } return ${see} } ad_proc -public api_library_documentation { { -format text/html } path } { Generates formatted documentation for a Tcl library file (just the header, describing what the library does). @param path the path to the file, relative to the OpenACS path root. } { if { $format ne "text/html" } { return -code error "Only text/html documentation is currently supported" } set out "

    [file tail $path]

    " if { [nsv_exists api_library_doc $path] } { array set doc_elements [nsv_get api_library_doc $path] append out "
    \n" append out [lindex $doc_elements(main) 0] append out "
    \n" append out "
    Location:\n
    $path\n" if { [info exists doc_elements(creation-date)] } { append out "
    Created:\n
    [lindex $doc_elements(creation-date) 0]\n" } if { [info exists doc_elements(author)] } { append out "
    Author[ad_decode [llength $doc_elements(author)] 1 "" "s"]:\n" foreach author $doc_elements(author) { append out "
    [api_format_author $author]\n" } } if { [info exists doc_elements(cvs-id)] } { append out "
    CVS Identification:\n
    [ns_quotehtml [lindex $doc_elements(cvs-id) 0]]\n" } append out "
    \n" append out "
    \n" } return $out } ad_proc -public api_type_documentation { type } { @return html fragment of the api docs. } { array set doc_elements [nsv_get doc_type_doc $type] append out "

    $type

    \n" array set properties [nsv_get doc_type_properties $type] append out "
    [lindex $doc_elements(main) 0]
    Properties:
    " array set property_doc [list] if { [info exists doc_elements(property)] } { foreach property $doc_elements(property) { if { [regexp {^([^ \t]+)[ \t](.+)$} $property "" name value] } { set property_doc($name) $value } } } foreach property [lsort [array names properties]] { set info $properties($property) set type [lindex $info 0] append out "$property" if { $type ne "onevalue" } { append out " ($type)" } if { [info exists property_doc($property)] } { append out " - $property_doc($property)" } if {$type eq "onerow"} { append out "
    \n" } else { set columns [lindex $info 1] append out "
      \n" foreach column $columns { append out "
    • $column" if { [info exists property_doc($property.$column)] } { append out " - $property_doc($property.$column)" } } append out "
    \n" } } append out [api_format_common_elements doc_elements] append out "
    Location:
    $doc_elements(script)\n" append out "
    \n" return $out } ad_proc -private api_set_public { version_id { public_p "" } } { Gets or sets the user's public/private preferences for a given package. @param version_id the version of the package @param public_p if empty, return the user's preferred setting or the default (1) if no preference found. If not empty, set the user's preference to public_p @return public_p } { set public_property_name "api,package,$version_id,public_p" if { $public_p eq "" } { set public_p [ad_get_client_property acs-api-browser $public_property_name] if { $public_p eq "" } { set public_p 1 } } else { ad_set_client_property acs-api-browser $public_property_name $public_p } return $public_p } ad_proc -public api_quote_file { filename } { returns a quoted version of the given filename } { if {![catch {set fp [open $filename r]} err]} { set content [ad_quotehtml [read $fp]] close $fp return $content } return {} } ad_proc -public api_proc_documentation { {-format text/html} -script:boolean -source:boolean -xql:boolean -label {-first_line_tag

    } proc_name } { Generates formatted documentation for a procedure. @param format the type of documentation to generate. Currently, only text/html and text/plain are supported. @param script include information about what script this proc lives in? @param xql include the source code for the related xql files? @param source include the source code for the script? @param proc_name the name of the procedure for which to generate documentation. @param label the label printed for the proc in the header line @param first_line_tag tag for the markup of the first line @return the formatted documentation string. @error if the procedure is not defined. } { if { $format ne "text/html" && \ $format ne "text/plain" } { return -code error "Only text/html and text/plain documentation are currently supported" } array set doc_elements [nsv_get api_proc_doc $proc_name] array set flags $doc_elements(flags) array set default_values $doc_elements(default_values) if {![info exists label]} { set label $proc_name } if { $script_p } { set pretty_name [api_proc_pretty_name -label $label $proc_name] } else { set pretty_name [api_proc_pretty_name -link -label $label $proc_name] } if {[regexp {<([^ >]+)} $first_line_tag match tag]} { set end_tag "" } else { set first_line_tag "

    " set end_tag "

    " } append out $first_line_tag$pretty_name$end_tag if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match cl prefix method]} { set xotcl 1 set scope "" if {[regexp {^(.+) (.+)$} $cl match scope cl]} { set cl "$scope do $cl" } if {$prefix eq ""} { set pretty_proc_name "[::xotcl::api object_link $scope $cl] $method" } else { set pretty_proc_name \ "<instance of\ [::xotcl::api object_link $scope $cl]> $method" } } else { set xotcl 0 set pretty_proc_name $proc_name } lappend command_line $pretty_proc_name foreach switch $doc_elements(switches) { if {$xotcl} { if { [lsearch $flags($switch) "boolean"] >= 0} { set value "on|off " } elseif { [lsearch $flags($switch) "switch"] >= 0} { set value "" } else { set value "$switch " } if { [lsearch $flags($switch) "required"] >= 0} { lappend command_line "-$switch $value" } else { lappend command_line "\[ -$switch $value\]" } } else { if { [lsearch $flags($switch) "boolean"] >= 0} { lappend command_line "\[ -$switch \]" } elseif { [lsearch $flags($switch) "required"] >= 0 } { lappend command_line "-$switch $switch" } else { lappend command_line "\[ -$switch $switch \]" } } } set counter 0 foreach positional $doc_elements(positionals) { if { [info exists default_values($positional)] } { lappend command_line "\[ $positional \]" } else { lappend command_line "$positional" } } if { $doc_elements(varargs_p) } { lappend command_line "\[ args... \]" } append out "[util_wrap_list $command_line]\n
    \n" if { $script_p } { append out "Defined in $doc_elements(script)

    " } if { $doc_elements(deprecated_p) } { append out "Deprecated." if { $doc_elements(warn_p) } { append out " Invoking this procedure generates a warning." } append out "

    \n" } append out "[lindex $doc_elements(main) 0]

    " if { [info exists doc_elements(param)] } { foreach param $doc_elements(param) { if { [regexp {^([^ \t\n]+)[ \t\n]+(.*)$} $param "" name value] } { set params($name) $value } } } if { [llength $doc_elements(switches)] > 0 } { append out "
    Switches:
    \n" foreach switch $doc_elements(switches) { append out "
    -$switch" if { [lsearch $flags($switch) "boolean"] >= 0 } { append out " (boolean)" } if { [info exists default_values($switch)] && \ $default_values($switch) ne "" } { append out " (defaults to \"$default_values($switch)\")" } if { [lsearch $flags($switch) "required"] >= 0 } { append out " (required)" } else { append out " (optional)" } append out "
    " if { [info exists params($switch)] } { append out "
    $params($switch)
    " } } append out "
    \n" } if { [llength $doc_elements(positionals)] > 0 } { append out "
    Parameters:
    \n" foreach positional $doc_elements(positionals) { append out "$positional" if { [info exists default_values($positional)] } { if { $default_values($positional) eq "" } { append out " (optional)" } else { append out " (defaults to \"$default_values($positional)\")" } } if { [info exists params($positional)] } { append out " - $params($positional)" } append out "
    \n" } append out "
    \n" } # @option is used in template:: and cms:: (and maybe should be used in some other # things like ad_form which have internal arg parsers. although an option # and a switch are the same thing, just one is parsed in the proc itself rather than # by ad_proc. if { [info exists doc_elements(option)] } { append out "Options:
    " foreach param $doc_elements(option) { if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } { append out "
    -$name
    $value
    " } } append out "
    " } if { [info exists doc_elements(return)] } { append out "
    Returns:
    [join $doc_elements(return) "
    "]
    \n" } if { [info exists doc_elements(error)] } { append out "
    Error:
    [join $doc_elements(error) "
    "]
    \n" } append out [api_format_common_elements doc_elements] if { $source_p } { if {[parameter::get_from_package_key \ -package_key acs-api-browser \ -parameter FancySourceFormattingP \ -default 1]} { append out "
    Source code:
    [api_tcl_to_html $proc_name]

    \n" } else { append out "

    Source code:
    [ns_quotehtml [api_get_body $proc_name]]

    \n" } } set xql_base_name [get_server_root]/ append xql_base_name [file rootname $doc_elements(script)] if { $xql_p } { set there {} set missing {} if { [file exists ${xql_base_name}.xql] } { append there "

    Generic XQL file:
    [api_quote_file ${xql_base_name}.xql]

    \n" } else { lappend missing Generic } if { [file exists ${xql_base_name}-postgresql.xql] } { append there "

    Postgresql XQL file:
    [api_quote_file ${xql_base_name}-postgresql.xql]

    \n" } else { lappend missing PostgreSQL } if { [file exists ${xql_base_name}-oracle.xql] } { append there "

    Oracle XQL file:
    [api_quote_file ${xql_base_name}-oracle.xql]

    \n" } else { lappend missing Oracle } if {[llength $missing] > 0} { append out "

    XQL Not present:
    [join $missing ", "]
    " } append out $there } # No "see also" yet. append out "
    " return $out } ad_proc api_proc_pretty_name { -link:boolean -label proc } { Return a pretty version of a proc name @param label the label printed for the proc in the header line @param link provide a link to the documentation pages } { if {![info exists label]} { set label $proc } if { $link_p } { append out "$label" } else { append out "$label" } array set doc_elements [nsv_get api_proc_doc $proc] if { $doc_elements(public_p) } { append out " (public)" } if { $doc_elements(private_p) } { append out " (private)" } return $out } ad_proc -private ad_sort_by_score_proc {l1 l2} { basically a -1,0,1 result comparing the second element of the list inputs then the first. (second is int) } { if {[lindex $l1 1] == [lindex $l2 1]} { return [string compare [lindex $l1 0] [lindex $l2 0]] } else { if {[lindex $l1 1] > [lindex $l2 1]} { return -1 } else { return 1 } } } ad_proc -private ad_sort_by_second_string_proc {l1 l2} { basically a -1,0,1 result comparing the second element of the list inputs then the first (both strings) } { if {[lindex $l1 1] eq [lindex $l2 1]} { return [string compare [lindex $l1 0] [lindex $l2 0]] } else { return [string compare [lindex $l1 1] [lindex $l2 1]] } } ad_proc -private ad_sort_by_first_string_proc {l1 l2} { basically a -1,0,1 result comparing the second element of the list inputs then the first. (both strings) } { if {[lindex $l1 0] eq [lindex $l2 0]} { return [string compare [lindex $l1 1] [lindex $l2 1]] } else { return [string compare [lindex $l1 0] [lindex $l2 0]] } } ad_proc -private ad_keywords_score {keywords string_to_search} { returns number of keywords found in string to search. No additional score for repeats } { # turn keywords into space-separated things # replace one or more commads with a space regsub -all {,+} $keywords " " keywords set score 0 foreach word $keywords { # turns out that "" is never found in a search, so we # don't really have to special case $word eq "" if {[string match -nocase "*$word*" $string_to_search]} { incr score } } return $score } ad_proc -public api_apropos_functions { string } { Returns the functions in the system that contain string in their name and have been defined using ad_proc. } { set matches [list] foreach function [nsv_array names api_proc_doc] { if {[string match -nocase *$string* $function]} { array set doc_elements [nsv_get api_proc_doc $function] lappend matches [list "$function" "$doc_elements(positionals)"] } } return $matches } ad_proc -public api_describe_function { { -format text/plain } proc } { Describes the functions in the system that contain string and that have been defined using ad_proc. The description includes the documentation string, if any. } { set matches [list] foreach function [nsv_array names api_proc_doc] { if {[string match -nocase $proc $function]} { array set doc_elements [nsv_get api_proc_doc $function] switch $format { text/plain { lappend matches [ad_html_to_text -- [api_proc_documentation -script $function]] } default { lappend matches [api_proc_documentation -script $function] } } } } switch $format { text/plain { set matches [join $matches "\n"] } default { set matches [join $matches "\n

    \n"] } } return $matches } ad_proc -private api_is_xotcl_object {scope proc_name} { Checks, whether the specified argument is an xotcl object. Does not cause problems when xocl is not loaded. @return boolean value } { set result 0 if {[string match "::*" $proc_name]} { ;# only check for absolute names catch {set result [::xotcl::api inscope $scope ::xotcl::Object isobject $proc_name]} } return $result } ad_proc -public api_get_body {proc_name} { This function returns the body of a tcl proc or an xotcl method. @param proc_name the name spec of the proc @return body of the specified prox } { if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match obj prefix method]} { if {[regexp {^(.*) (.*)$} $obj match thread obj]} { # the definition is located in a disconnected thread return [$thread do ::Serializer methodSerialize $obj $method $prefix] } else { # the definition is locally in the connection thread return [::Serializer methodSerialize $obj $method $prefix] } } elseif {[regexp {^([^ ]+)(Class|Object) (.*)$} $proc_name match thread kind obj]} { return [$thread do $obj serialize] } else { return [info body $proc_name] } } ad_proc -private api_tcl_to_html {proc_name} { Given a proc name, formats it as HTML, including highlighting syntax in various colors and creating hyperlinks to other proc definitions.
    The inspiration for this proc was the tcl2html script created by Jeff Hobbs.

    Known Issues:

    1. This proc will mistakenly highlight switch strings that look like commands as commands, etc.
    2. There are many undocumented AOLserver commands including all of the commands added by modules.
    3. When a proc inside a string has explicitly quoted arguments, they are not formatted.
    4. regexp and regsub are hard to parse properly. E.g. If we use the start option, and we quote its argument, and we have an ugly regexp, then this code might highlight it incorrectly.
    @author Jamie Rasmussen (jrasmuss@mle.ie) @param proc_name procedure to format in HTML } { if {[info command ::xotcl::api] ne ""} { set scope [::xotcl::api scope_from_proc_index $proc_name] } else { set scope "" } set proc_namespace "" regexp {^(::)?(.*)::[^:]+$} $proc_name match colons proc_namespace return [api_tclcode_to_html -scope $scope -proc_namespace $proc_namespace [api_get_body $proc_name]] } ad_proc -private api_tclcode_to_html {{-scope ""} {-proc_namespace ""} script} { Given a script, this proc formats it as HTML, including highlighting syntax in various colors and creating hyperlinks to other proc definitions.
    The inspiration for this proc was the tcl2html script created by Jeff Hobbs. @param script script to be formated in HTML } { # Returns length of a variable name proc length_var {data} { if {[regexp -indices {^\$\{[^\}]+\}} $data found]} { return [lindex $found 1] } elseif {[regexp -indices {^\$[A-Za-z0-9_]+(\([\$A-Za-z0-9_\-/]+\))?} $data found]} { return [lindex $found 1] } return 0 } # Returns length of a command name proc length_proc {data} { if {[regexp -indices {^(::)?[A-Za-z][:A-Za-z0-9_@]+} $data found]} { return [lindex $found 1] } return 0 } # Returns length of subexpression, from open to close quote inclusive proc length_string {data} { regexp -indices {[^\\]\"} $data match return [expr {[lindex $match 1]+1}] } # Returns length of subexpression, from open to close brace inclusive # Doesn't deal with unescaped braces in substrings proc length_braces {data} { set i 1 for {set count 1} {1} {incr i} { if {[string index $data $i] eq "\\"} { incr i } elseif {[string index $data $i] eq "\{"} { incr count } elseif {[string index $data $i] eq "\}"} { incr count -1 } if {!$count} { break } } return [expr {$i+1}] } # Returns number of spaces until next subexpression proc length_spaces {data} { regexp -indices {\s+} $data match return [expr {[lindex $match 1]+1}] } # Returns length of a generic subexpression proc length_exp {data} { if {[string index $data 0] eq "\""} { return [length_string $data] } elseif {[string index $data 0] eq "\{"} { return [length_braces $data] } elseif {[string index $data 0] eq " "} { return [length_spaces $data] } if { [regexp -indices { } $data match] } { return [lindex $match 1] } return 0 } # Calculate how much text we should ignore proc length_regexp {data} { set i 0 set found_regexp 0 set curchar [string index $data $i] while {$curchar != "\$" && $curchar != "\[" && ($curchar ne "\{" || !$found_regexp)} { if {$curchar eq "\{"} {set found_regexp 1} if {[string match "-start" [string range $data $i [expr {$i+5}]]]} { incr i [length_exp [string range $data $i end]] ;# -start incr i [length_exp [string range $data $i end]] ;# spaces incr i [length_exp [string range $data $i end]] ;# expression - it could be a var } incr i [length_exp [string range $data $i end]] set curchar [string index $data $i] } return [expr {$i -1}] } array set HTML { comment {} /comment {} procs {} /procs {} str {} /str {} var {} /var {} object {} /object {} } # Keywords will be colored as other procs, but not hyperlinked # to api-doc pages. Perhaps we should hyperlink them to the TCL man pages? # else and elseif are be treated as special cases later set KEYWORDS [concat \ {if while foreach for switch default} \ {after break continue return error catch} \ {upvar uplevel eval exec source variable namespace package load} \ {set unset trace append global vwait split join} \ {concat list lappend lset lindex linsert llength lrange lreplace lsearch lsort} \ {info incr expr regexp regsub binary} \ {string array open close read cd pwd glob seek pid} \ {file fblocked fcopy fconfigure fileevent filename flush eof} \ {clock encoding proc rename subst update} \ {gets puts socket tell format scan} \ ] if {[info command ::xotcl::api] ne ""} { set XOTCL_KEYWORDS [list self my next] # only command names are highlighted, otherwise we could add xotcl method # names by [lsort -unique [concat [list self my next] .. # [::xotcl::Object info methods] [::xotcl::Class info methods] ]] } else { set XOTCL_KEYWORDS {} } # Returns a list of the commands from all namespaces. proc list_all_procs {{parentns ::}} { set result [info commands ${parentns}::*] foreach ns [namespace children $parentns] { set result [concat $result [list_all_procs $ns]] } return $result } set COMMANDS [list_all_procs] set data [string map [list & "&" < "<" > ">"] \n$script] set in_comment 0 set in_quotes 0 set proc_ok 1 set l [string length $data] for {set i 0} {$i < $l} {incr i} { set char [string index $data $i] switch -- $char { "\\" { append html [string range $data $i [incr i]] # This might have been a backslash added to escape &, <, or >. if {[regexp {^(amp;|lt;|gt;)} [string range $data $i end] match esc]} { append html $esc incr i [string length $esc] } } "\$" { if {$in_comment || ([string index $data [expr {$i + 1}]] == " ")} { append html "\$" } else { set varl [length_var [string range $data $i end]] append html "$HTML(var)[string range $data $i [expr {$i + $varl}]]$HTML(/var)" incr i $varl } } "\"" { if {$in_comment} { append html "\"" } elseif {$in_quotes} { append html \"$HTML(/str) set in_quotes 0 } else { append html $HTML(str)\" set in_quotes 1 set proc_ok 0 } } "\#" { set prevchar [string index $data [expr {$i-1}]] if {$proc_ok && !$in_comment && [regexp {[\s;]} $prevchar]} { set in_comment 1 set proc_ok 0 append html $HTML(comment) } append html "#" } "\n" { set proc_ok 1 if {$in_quotes} { set proc_ok 0 } if {$in_comment} { append html $HTML(/comment) } append html "\n" set in_comment 0 } "\{" - ";" { if {!$in_quotes} { set proc_ok 1 } append html $char } "\}" { append html "\}" # Special case else and elseif if {[regexp {^\}(\s*)(else|elseif)(\s*\{)} [string range $data $i end] match pre els post]} { append html "${pre}$HTML(procs)${els}$HTML(/procs)${post}" set proc_ok 1 incr i [expr [string length $pre] + \ [string length $els] + \ [string length $post]] } } "\[" { if {!$in_comment} { set proc_ok 1 } append html "\[" } " " { append html " " } default { if {$proc_ok} { set proc_ok 0 set procl [length_proc [string range $data $i end]] set proc_name [string range $data $i [expr {$i + $procl}]] if {[lsearch -exact $KEYWORDS $proc_name] != -1 || ([regexp {^::(.*)} $proc_name match had_colons] && [lsearch -exact $KEYWORDS $had_colons] != -1)} { append html "$HTML(procs)${proc_name}$HTML(/procs)" } elseif {[lsearch -exact $XOTCL_KEYWORDS $proc_name] != -1 } { append html "$HTML(procs)${proc_name}$HTML(/procs)" } elseif {[api_is_xotcl_object $scope $proc_name]} { set url [::xotcl::api object_url \ -show_source 1 -show_methods 2 \ $scope $proc_name] append html "$HTML(object)${proc_name}$HTML(/object)" } elseif {[string match "ns*" $proc_name]} { set url "/api-doc/tcl-proc-view?tcl_proc=$proc_name" append html "$HTML(procs)${proc_name}$HTML(/procs)" } elseif {[string match "*__arg_parser" $proc_name]} { append html "$HTML(procs)${proc_name}$HTML(/procs)" } elseif {[lsearch -exact $COMMANDS ::${proc_namespace}::${proc_name}] != -1} { set url [api_proc_url ${proc_namespace}::${proc_name}] append html "$HTML(procs)${proc_name}$HTML(/procs)" } elseif {[lsearch -exact $COMMANDS ::$proc_name] != -1} { set url [api_proc_url $proc_name] append html "$HTML(procs)${proc_name}$HTML(/procs)" } else { append html ${proc_name} set proc_ok 1 } incr i $procl # Hack for nasty regexp stuff if {"regexp" eq $proc_name || "regsub" eq $proc_name} { set regexpl [length_regexp [string range $data $i end]] append html [string range $data [expr {$i+1}] [expr {$i + $regexpl}]] incr i $regexpl } } else { append html $char set proc_ok 0 } } } } # We added a linefeed at the beginning to simplify processing return [string range $html 1 end] } #################### # # Linking to api-documentation # #################### # # procs for linking to libraries, pages, etc, should go here too. # ad_proc api_proc_url { proc } { Returns the URL of the page that documents the given proc. @author Lars Pind (lars@pinds.com) @creation-date 14 July 2000 } { return "/api-doc/proc-view?proc=[ns_urlencode $proc]" } ad_proc api_proc_link { proc } { Returns a full HTML link to the documentation for the proc. @author Lars Pind (lars@pinds.com) @creation-date 14 July 2000 } { return "$proc" } ad_proc -private api_xql_links_list { path } { Returns list of xql files related to tcl script file @param path path and filename from [acs_root_dir] } { set linkList [list] set filename "[acs_root_dir]/$path" set path_dirname [file dirname $path] set file_dirname [file dirname $filename] set file_rootname [file rootname [file tail $filename]] regsub {(-oracle|-postgresql)$} $file_rootname {} file_rootname set files \ [lsort -decreasing \ [glob -nocomplain \ -directory $file_dirname \ "${file_rootname}{,-}{,oracle,postgresql}.{adp,tcl,xql}" ]] foreach file $files { lappend linkList [list \ filename $file \ link "content-page-view?source_p=1&path=[ns_urlencode "$path_dirname/[file tail $file]"]" \ ] } return $linkList } openacs-5.7.0/packages/acs-api-browser/www/0000755000175000017500000000000011575225377020411 5ustar frankiefrankieopenacs-5.7.0/packages/acs-api-browser/www/proc/0000755000175000017500000000000011724401450021334 5ustar frankiefrankieopenacs-5.7.0/packages/acs-api-browser/www/proc/index.vuh0000644000175000017500000000032107572170712023175 0ustar frankiefrankieset query_string [string range [ad_conn extra_url] [string length "proc/"] end] set url "[ad_conn package_url]proc-search?[export_vars { query_string { search_type "Feeling Lucky" } }]" ad_returnredirect $url openacs-5.7.0/packages/acs-api-browser/www/proc-view.adp0000644000175000017500000000142010235514011022761 0ustar frankiefrankie @title;noquote@ @context;noquote@ @error_msg;noquote@
    @documentation;noquote@
    [ show source ] [ hide source ] | [ make this the default ]
    Show another procedure:
    openacs-5.7.0/packages/acs-api-browser/www/proc-view.tcl0000644000175000017500000000424310235514021023006 0ustar frankiefrankiead_page_contract { Display information about one procedure. @cvs-id $Id: proc-view.tcl,v 1.6 2005/05/02 21:13:53 skaufman Exp $ } { proc source_p:optional,integer,trim {version_id ""} } -properties { title:onevalue context:onevalue source_p:onevalue default_source_p:onevalue return_url:onevalue documentation:onevalue error_msg:onevalue } set title $proc set context [list] if { [exists_and_not_null version_id] } { db_1row package_info_from_package_id { select pretty_name, package_key, version_name from apm_package_version_info where version_id = :version_id } lappend context [list "package-view?version_id=$version_id&kind=procs" "$pretty_name $version_name"] } lappend context [list $proc] set default_source_p [ad_get_client_property -default 0 acs-api-browser api_doc_source_p] set return_url [ns_urlencode [ad_conn url]?[export_url_vars proc version_id]] set error_msg "" if { ![info exists source_p] } { set source_p $default_source_p } # Try and be helpful about the procedure. if { ![nsv_exists api_proc_doc $proc] } { if {![empty_string_p [namespace eval :: [list info procs $proc]]]} { set error_msg "

    This procedure is defined in the server but not documented via ad_proc or proc_doc and may be intended as a private interface.

    The procedure is defined as:

    proc $proc {[info args $proc]} {
    [ad_quotehtml [info body $proc]]
    }

    " } elseif {![empty_string_p [namespace eval :: [list info commands $proc]]]} { set error_msg "

    The procedure $proc is an available command on the server and might be found in the TCL or AOLServer documentation or in documentation for a loadable module (like ns_cache for example).

    " } else { set error_msg "

    The procedure $proc is not defined in the server.

    " } } else { if { $source_p } { set documentation [api_proc_documentation -script -xql -source $proc] } else { set documentation [api_proc_documentation -script $proc] } } openacs-5.7.0/packages/acs-api-browser/www/tcl-doc-search.adp0000644000175000017500000000102407663154060023655 0ustar frankiefrankie @title;noquote@ @context;noquote@ Sorry, no Tcl procedures were found with that name.

    You can try searching the Tcl documentation yourself.

    Tcl Documentation Search:

    openacs-5.7.0/packages/acs-api-browser/www/tcl-doc-search.tcl0000644000175000017500000000217211420043145023663 0ustar frankiefrankiead_page_contract { Will redirect you to dev.scriptics.com if documentation can be found @cvs-id $Id: tcl-doc-search.tcl,v 1.6 2010/07/16 11:45:41 gustafn Exp $ } { tcl_proc } -properties { title:onevalue context:onevalue tcl_proc:onevalue } set tcl_docs_root "http://tcl.tk/man/tcl[info tclversion]/TclCmd/" set tcl_docs_url "${tcl_docs_root}contents.htm" with_catch errmsg { set tcl_docs_index_page [util_memoize "ns_httpget $tcl_docs_url"] } { ad_return_error "Cannot Connect" "We're sorry, but we're having problems connecting to the server containing the Tcl documentation: $tcl_docs_url" ad_script_abort } set tcl_proc [lindex $tcl_proc 0] set len [string length $tcl_proc] for { set i [expr { $len-1 }] } { $i >= 0 } { incr i -1 } { set search_for [string range $tcl_proc 0 $i] if { [regexp "\]+)\">$search_for" $tcl_docs_index_page match relative_url] } { ad_returnredirect -allow_complete_url "$tcl_docs_root$relative_url" ad_script_abort } } set title "Tcl API Procedure Search for: \"$tcl_proc\"" set context [list "TCL API Search: $tcl_proc"] openacs-5.7.0/packages/acs-api-browser/www/plsql-subprograms-all-postgresql.xql0000644000175000017500000000057707705405557027614 0ustar frankiefrankie postgresql7.1 select proname as name, 'FUNCTION' as type from pg_proc where proowner=(select usesysid from pg_user where usename = current_user) order by proname openacs-5.7.0/packages/acs-api-browser/www/display-sql.adp0000644000175000017500000000020307663154060023325 0ustar frankiefrankie @title;noquote@ @context;noquote@

    @sql@
    
    openacs-5.7.0/packages/acs-api-browser/www/display-sql.tcl0000644000175000017500000000431610551254371023350 0ustar frankiefrankiead_page_contract { Enables user to see a .sql file without encountering the AOLserver's db module magic (offering to load the SQL into a database) or without returning the SQL as content-type application/x-sql. Patched by philg at Jeff Banks's request on 12/5/99 to close the security hole whereby a client adds extra form vars. Patched on 07/06/2000 by deison to restrict access to only .sql files and only files in /doc or /pageroot. 2000 August 8 Updated for ACS4 packages - richardl@arsdigita.com. @param url The full relative path of the file to display the source for. @param package_key The key of the package the file is part of. @creation-date 12/19/98 @author philg@mit.edu @cvs-id $Id: display-sql.tcl,v 1.4 2007/01/10 21:22:01 gustafn Exp $ } { url:notnull { version_id "" } { package_key ""} } -properties { title:onevalue context:onevalue sql:onevalue } set context [list] if {[exists_and_not_null version_id]} { db_0or1row package_info_from_package_id { select pretty_name, package_key, version_name from apm_package_version_info where version_id = :version_id } lappend context [list "package-view?version_id=$version_id&kind=sql_files" "$pretty_name $version_name"] } lappend context [file tail $url] set title "[file tail $url]" # This is normally a password-protected page, but to be safe let's # check the incoming URL for ".." to make sure that someone isn't # doing # https://photo.net/doc/sql/display-sql.tcl?url=/../../../../etc/passwd # for example if { [string match "*..*" $url] || [string match "*..*" $package_key] } { ad_return_error "Can't back up beyond the pageroot" "You can't use display-sql.tcl to look at files underneath the pageroot." return } if {[exists_and_not_null package_key]} { set safe_p [regexp {/?(.*)} $url package_url] } if { $safe_p } { if [catch { set sql [ad_quotehtml [read [open "[acs_package_root_dir $package_key]/sql/$url"]]] }] { ad_return_error "Problem reading file" "There was a problem reading $url" } } else { ad_return_error "Invalid file location" "Can only display files in package or doc directory" } openacs-5.7.0/packages/acs-api-browser/www/proc-browse.adp0000644000175000017500000000130107725122370023323 0ustar frankiefrankie @title;noquote@ @context;noquote@ @dimensional_slider;noquote@
      <% set last_file "" %> <% if { $proc_list(file) != $last_file } { %>
    @proc_list.file@ Sorry, no procedures found @proc_list:rowcount@ Procedures Found openacs-5.7.0/packages/acs-api-browser/www/proc-browse.tcl0000644000175000017500000000334010551254371023344 0ustar frankiefrankie# acs-api-browser/www/proc-browse.tcl ad_page_contract { returns a list of all the procedures present in server memory @author Todd Nightingale @creation-date 2000-7-14 @cvs-id $Id: proc-browse.tcl,v 1.4 2007/01/10 21:22:01 gustafn Exp $ } { { type "Public" } { sort_by "file"} } -properties { title:onevalue context:onevalue dimensional_slider:onevalue proc_list:multirow } set dimensional { {type "Type" "Public" { {All "All" ""} {Public "Public" ""} {Private "Private" ""} {Deprecated "Deprecated" ""} } } {sort_by "Sorted By" "file" { {file "File" ""} {name "Name" ""} } } } set title "$type Procedures" set context [list "Browse Procedures"] set dimensional_slider [ad_dimensional $dimensional] set matches [list] foreach proc [nsv_array names api_proc_doc] { array set doc_elements [nsv_get api_proc_doc $proc] if { $type eq "All"} { lappend matches [list $proc $doc_elements(script)] } elseif {$type eq "Deprecated" && $doc_elements(deprecated_p)} { lappend matches [list $proc $doc_elements(script)] } elseif {$type eq "Private" && $doc_elements(private_p) } { lappend matches [list $proc $doc_elements(script)] } elseif {$type eq "Public" && $doc_elements(public_p) } { lappend matches [list $proc $doc_elements(script)] } } if {$sort_by eq "file"} { set matches [lsort -command ad_sort_by_second_string_proc $matches] } else { set matches [lsort -command ad_sort_by_first_string_proc $matches] } multirow create proc_list file proc url foreach sublist $matches { set proc [lindex $sublist 0] set file [lindex $sublist 1] set url [api_proc_url $proc] multirow append proc_list $file $proc $url } openacs-5.7.0/packages/acs-api-browser/www/plsql-subprogram-one-oracle.xql0000644000175000017500000000045707434025104026462 0ustar frankiefrankie oracle8.1.6 select text from user_source where name = upper(:name) and type = upper(:type) order by line openacs-5.7.0/packages/acs-api-browser/www/tcl-proc-view.adp0000644000175000017500000000103507663154060023562 0ustar frankiefrankie @title;noquote@ @context;noquote@ Sorry, no AOLserver Tcl API procedures were found with that name.

    You can try searching the AOLserver documentation yourself.

    Tcl Api Search:

    openacs-5.7.0/packages/acs-api-browser/www/tcl-proc-view.tcl0000644000175000017500000000263111143367766023612 0ustar frankiefrankiead_page_contract { Will redirect you to aolserver.com if documentation can be found @cvs-id $Id: tcl-proc-view.tcl,v 1.6 2009/02/07 20:32:54 gustafn Exp $ } { tcl_proc } -properties { title:onevalue context:onevalue tcl_proc:onevalue } # old aolserver documentation #set tcl_api_host "http://www.aolserver.com/" #set tcl_api_index "docs/devel/tcl/api/" # wiki on dev.aolserver; might be the place in the future #set tcl_api_host "http://dev.aolserver.com/" #set tcl_api_index "wiki/Tcl_API" # wiki on panpotic set tcl_api_host "http://panoptic.com/" set tcl_api_index "wiki/aolserver/Tcl_API" set tcl_api_root ${tcl_api_host}${tcl_api_index} set tcl_api_index_page [util_memoize "ns_httpget $tcl_api_root"] ns_log notice index=$tcl_api_root set tcl_proc [lindex $tcl_proc 0] set len [string length $tcl_proc] for { set i [expr { $len-1 }] } { $i >= 0 } { incr i -1 } { set search_for [string range $tcl_proc 0 $i] if { [regexp "\"'\]+)\[\"'\]\[^>\]*>$search_for" $tcl_api_index_page match relative_url] } { if {[string match "/*" $relative_url]} { set url ${tcl_api_host}$relative_url } else { set url ${tcl_api_root}$relative_url } ad_returnredirect -allow_complete_url $url ad_script_abort } } set title "AOLserver Tcl API Search for: \"$tcl_proc\"" set context [list "TCL API Search: $tcl_proc"] openacs-5.7.0/packages/acs-api-browser/www/plsql-subprograms-all-oracle.xql0000644000175000017500000000065707434025104026636 0ustar frankiefrankie oracle8.1.6 select object_type as type, object_name as name from user_objects where object_type in ('PACKAGE', 'PROCEDURE', 'FUNCTION') order by decode(object_type, 'PACKAGE', 0, 'PROCEDURE', 1, 'FUNCTION', 2) asc openacs-5.7.0/packages/acs-api-browser/www/package-view.adp0000644000175000017500000000373507663154060023443 0ustar frankiefrankie @title;noquote@ @context;noquote@ @dimensional_slider;noquote@

    @procs_files.path@       @procs_files.first_sentence@ 
    @procedures.proc@       @procedures.first_sentence@ 
    @sql_files.path@        
    @content_pages.indentation;noquote@ @content_pages.name@ @content_pages.first_sentence@ @content_pages.indentation;noquote@@content_pages.name@/
    openacs-5.7.0/packages/acs-api-browser/www/package-view.tcl0000644000175000017500000001351710210133524023440 0ustar frankiefrankiead_page_contract { Shows APIs for a particular package. @param version_id the ID of the version whose API to view. @param public_p view only public APIs? @param kind view which type of APIs? One of procs_files, procs or content. @author Jon Salz (jsalz@mit.edu) @creation-date 3 Jul 2000 @cvs-id $Id: package-view.tcl,v 1.6 2005/02/26 17:52:20 jeffd Exp $ } { version_id { public_p "" } { kind "procs_files" } } -properties { title:onevalue context:onevalue dimensional_slider:onevalue kind:onevalue version_id:onevalue package_key:onevalue procs_files:multirow procedures:multirow sql_files:multirow content_pages:multirow } set public_p [api_set_public $version_id $public_p] db_1row pretty_name_from_package_id { select pretty_name, package_key, version_name from apm_package_version_info where version_id = :version_id } set dimensional_list { { kind "Kind:" procs_files { { procs_files "Library Files" "" } { procs "Procedures" "" } { sql_files "SQL Files" "" } { content "Content Pages" "" } } } { public_p "Publicity:" 1 { { 1 "Public Only" } { 0 "All" } } } } set title "$pretty_name $version_name" set context [list $title] set dimensional_slider "[ad_dimensional \ $dimensional_list \ "" \ [ad_tcl_vars_to_ns_set version_id kind public_p]]" switch $kind { procs_files { array set procs [list] multirow create procs_files path full_path first_sentence foreach path [apm_get_package_files -package_key $package_key -file_types tcl_procs] { set full_path "packages/$package_key/$path" if { [nsv_exists api_library_doc $full_path] } { array set doc_elements [nsv_get api_library_doc $full_path] set first_sentence "[api_first_sentence [lindex $doc_elements(main) 0]]" } else { set first_sentence "" } multirow append procs_files $path $full_path $first_sentence } } procs { array set procs [list] foreach path [apm_get_package_files -package_key $package_key -file_types tcl_procs] { if { [nsv_exists api_proc_doc_scripts "packages/$package_key/$path"] } { foreach proc [nsv_get api_proc_doc_scripts "packages/$package_key/$path"] { set procs($proc) 1 } } } multirow create procedures proc first_sentence foreach proc [lsort [array names procs]] { array set doc_elements [nsv_get api_proc_doc $proc] if { $public_p } { if { !$doc_elements(public_p) } { continue } } multirow append procedures $proc [api_first_sentence [lindex $doc_elements(main) 0]] } } sql_files { multirow create sql_files path relative_path set file_types [list data_model data_model_create data_model_drop data_model_upgrade] foreach path [apm_get_package_files -package_key $package_key -file_types $file_types] { # Set relative path to everything after sql/ (just using # file tail breaks when you've got subdirs of sql) regexp {^sql/(.*)} $path match relative_path multirow append sql_files $path $relative_path } } content { multirow create content_pages indentation full_path content_type name type first_sentence set last_components [list] foreach path [apm_get_package_files -package_key $package_key -file_types content_page] { set components [split $path "/"] if { [info exists doc_elements] } { unset doc_elements } # don't stop completely if the page is gone if { [catch { set full_path "packages/$package_key/$path" array set doc_elements [api_read_script_documentation $full_path] for { set n_same_components 0 } \ { $n_same_components < [llength $last_components] } \ { incr n_same_components } { if { ![string equal [lindex $last_components $n_same_components] \ [lindex $components $n_same_components]] } { break } } for { set i $n_same_components } { $i < [llength $components] } { incr i } { set indentation "" for { set j 0 } { $j < $i } { incr j } { append indentation "     " } set name [lindex $components $i] set type "" set first_sentence "" if { $i == [llength $components] - 1 } { set content_type page if { [info exists doc_elements(type)] } { set type $doc_elements(type) } if { [info exists doc_elements(main)] } { set first_sentence [api_first_sentence [lindex $doc_elements(main) 0]] } } else { set content_type directory } multirow append content_pages $indentation $full_path $content_type $name $type $first_sentence } set last_components $components } error] } { ns_log Error "API Broswer: Package View: $error" # couldn't read info from the file. it probably doesn't exist. } } } } openacs-5.7.0/packages/acs-api-browser/www/index-postgresql.xql0000644000175000017500000000062310457653227024445 0ustar frankiefrankie postgresql7.1 select version_id from apm_package_version_info where installed_p = 't' and enabled_p = 't' and package_key = :about_package_key limit 1 openacs-5.7.0/packages/acs-api-browser/www/index.adp0000644000175000017500000000171211570011426022166 0ustar frankiefrankie @title;noquote@ @context;noquote@

    Installed Enabled Packages

    Disabled Packages

    • @disabled_packages.pretty_name@ @disabled_packages.version_name@

    Uninstalled Packages

    • @uninstalled_packages.pretty_name@ @uninstalled_packages.version_name@

    openacs-5.7.0/packages/acs-api-browser/www/index.tcl0000644000175000017500000000334210457653227022223 0ustar frankiefrankiead_page_contract { Offers links to other pages, and lets the user type the name of a specific procedure. If about_package_key is set to an installed package, then this page will automatically return /package-view page for the package-key, which is a handy way of integrating static docs with evolving api, especially for core packages. @about_package_key a package-key @author Jon Salz (jsalz@mit.edu) @author Lars Pind (lars@pinds.com) @cvs-id $Id: index.tcl,v 1.5 2006/07/20 10:10:31 torbenb Exp $ } { about_package_key:optional } -properties { title:onevalue context:onevalue installed_packages:multirow disabled_packages:multirow uninstalled_packages:multirow } set title "API Browser" set context [list] if { [info exists about_package_key] } { if { [db_0or1row get_local_package_version_id {} ] } { rp_form_put version_id $version_id rp_internal_redirect package-view } } else { db_multirow installed_packages installed_packages_select { select version_id, pretty_name, version_name from apm_package_version_info where installed_p = 't' and enabled_p = 't' order by upper(pretty_name) } db_multirow disabled_packages disabled_packages_select { select version_id, pretty_name, version_name from apm_package_version_info where installed_p = 't' and enabled_p = 'f' order by upper(pretty_name) } db_multirow uninstalled_packages uninstalled_packages_select { select version_id, pretty_name, version_name from apm_package_version_info where installed_p = 'f' and enabled_p = 'f' order by upper(pretty_name) } } openacs-5.7.0/packages/acs-api-browser/www/content-page-view.adp0000644000175000017500000000167210217030747024424 0ustar frankiefrankie @title;noquote@ @context;noquote@ @script_documentation;noquote@

    Related Files

    [ show source ] [ hide source ] | [ make this the default ]

    Content File Source

    <%= $file_contents %>
    openacs-5.7.0/packages/acs-api-browser/www/content-page-view.tcl0000644000175000017500000000465311473424643024453 0ustar frankiefrankiead_page_contract { Displays information about a content page. @param version_id the id of the package version the file belongs to @param path the path and filename of the page to document, relative to [acs_root_dir] @author Jon Salz (jsalz@mit.edu) @author Lars Pind (lars@pinds.com) @creation-date 1 July 2000 @cvs-id $Id: content-page-view.tcl,v 1.5 2010/11/25 09:17:23 gustafn Exp $ } { version_id:integer,optional source_p:integer,optional,trim path } -properties { title:onevalue context:onevalue script_documentation:onevalue } set context [list] set url_vars [export_url_vars path version_id] set return_url [ns_urlencode [ad_conn url]?][ns_urlencode $url_vars] set default_source_p [ad_get_client_property -default 0 acs-api-browser api_doc_source_p] if { ![info exists source_p] } { set source_p $default_source_p } if { ![info exists version_id] && \ [regexp {^packages/([^ /]+)/} $path "" package_key] } { db_0or1row version_id_from_package_key { select version_id from apm_enabled_package_versions where package_key = :package_key } } if { [info exists version_id] } { db_1row package_info_from_version_id { select pretty_name, package_key, version_name from apm_package_version_info where version_id = :version_id } lappend context [list "package-view?version_id=$version_id&kind=content" "$pretty_name $version_name"] } lappend context [file tail $path] set filename "[acs_root_dir]/$path" if {[regsub -all {[.][.]/} $filename "" shortened_filename]} { ns_log notice "INTRUDER ALERT:\n\nsomesone tried to snarf '$filename'!\n file exists: [file exists $filename]\n user_id: [ad_conn user_id]\n peer: [ad_conn peeraddr]\n" set filename shortened_filename } if {![file exists $filename] || [file isdirectory $filename]} { set file_contents "file '$filename' not found" } else { if { $source_p } { if {[catch { set fd [open $filename r] set file_contents [read $fd] close $fd } err ]} { set file_contents "error opening '$filename'\n$err" } else { set file_contents [ad_quotehtml $file_contents] } } template::util::list_to_multirow xql_links [api_xql_links_list $path] } set title [file tail $path] set script_documentation [api_script_documentation $path] openacs-5.7.0/packages/acs-api-browser/www/plsql-subprograms-all.adp0000644000175000017500000000067607663154060025344 0ustar frankiefrankie All PL/SQL Subprograms @context;noquote@

    @all_subprograms.type@

    openacs-5.7.0/packages/acs-api-browser/www/plsql-subprograms-all.tcl0000644000175000017500000000153007536221402025342 0ustar frankiefrankie# /packages/api-doc/www/api-doc/plsql-subprograms-all.tcl ad_page_contract { Lists all subprograms (packages, procedures, or functions) in the database. @author Michael Yoon (michael@arsdigita.com) @creation-date 2000-08-23 @cvs-id $Id: plsql-subprograms-all.tcl,v 1.4 2002/09/06 21:49:54 jeffd Exp $ } -properties { title:onevalue context:onevalue all_subprograms:multirow } set context [list "All PL/SQL Subprograms"] # Organize the subprograms under three headings: FUNCTION, PROCEDURE, # and PACKAGE. db_multirow all_subprograms all_subprograms { select object_type as type, object_name as name from user_objects where object_type in ('PACKAGE', 'PROCEDURE', 'FUNCTION') order by decode(object_type, 'PACKAGE', 0, 'PROCEDURE', 1, 'FUNCTION', 2) asc } db_release_unused_handles ad_return_templateopenacs-5.7.0/packages/acs-api-browser/www/set-default.tcl0000644000175000017500000000063307253523116023322 0ustar frankiefrankiead_page_contract { Set user preferences for API browsing. } { source_p:integer,optional,notnull return_url } set found_p 0 if { [info exists source_p] } { ad_set_client_property -persistent t acs-api-browser api_doc_source_p $source_p set found_p 1 } if { $found_p } { ad_returnredirect $return_url } else { ad_return_error "Unknown Property" "Couldn't find any property to set" }openacs-5.7.0/packages/acs-api-browser/www/plsql-subprogram-one.adp0000644000175000017500000000045407663154060025164 0ustar frankiefrankie @title;noquote@ @context;noquote@
    [ <%= [join $package_slider_list " | "] %> ]
    @source_text@
    
    openacs-5.7.0/packages/acs-api-browser/www/plsql-subprogram-one.tcl0000644000175000017500000000233107536221402025170 0ustar frankiefrankie# /packages/acs-api-browser/www/api-doc/plsql-subprogram-one.tcl ad_page_contract { Returns the specification for a given PL/SQL subprogram (package, procedure, or function). @param name @param type @author Michael Yoon (michael@arsdigita.com) @creation-date 2000-03-05 @cvs-id $Id: plsql-subprogram-one.tcl,v 1.3 2002/09/06 21:49:54 jeffd Exp $ } { name type } -properties { title:onevalue context:onevalue } set title $name set context [list {"plsql-subprograms-all" "All PL/SQL Subprograms"} "One PL/SQL Subprogram"] set source_text "" db_foreach source_text "select text from user_source where name = upper(:name) and type = upper(:type) order by line" { append source_text $text } switch $type { "PACKAGE" { set type "PACKAGE BODY" set package_slider_list [list "package" "package body"] } "PACKAGE BODY" { set type "PACKAGE" set package_slider_list [list "package" "package body"] } default { set package_slider_list [list] } } # Lowercase looks nicer. # set name [string tolower $name] db_release_unused_handles ad_return_template openacs-5.7.0/packages/acs-api-browser/www/deprecated.adp0000644000175000017500000000055207663154060023172 0ustar frankiefrankie @title;noquote@ @context;noquote@

    Deprecated Procedures:

    No deprecated procedures found openacs-5.7.0/packages/acs-api-browser/www/deprecated.tcl0000644000175000017500000000123507537470214023211 0ustar frankiefrankiead_page_contract { returns a list of all the deprecated procedures present in server memory @author Todd Nightingale @creation-date 2000-7-14 @cvs-id $Id: deprecated.tcl,v 1.3 2002/09/10 22:22:04 jeffd Exp $ } { } -properties { title:onevalue context:onevalue deprecated:multirow } set title "Deprecated Procedure Search" set context [list "Deprecated Procedures"] multirow create deprecated proc args foreach proc [nsv_array names api_proc_doc] { array set doc_elements [nsv_get api_proc_doc $proc] if {$doc_elements(deprecated_p) == 1} { multirow append deprecated $proc $doc_elements(positionals) } } openacs-5.7.0/packages/acs-api-browser/www/index-oracle.xql0000644000175000017500000000072010457653227023505 0ustar frankiefrankie oracle8.1.6 select * from ( select version_id from apm_package_version_info where installed_p = 't' and enabled_p = 't' and package_key = :about_package_key ) where rownum = 1 openacs-5.7.0/packages/acs-api-browser/www/plsql-subprogram-one-postgresql.xql0000644000175000017500000000044107434025104027411 0ustar frankiefrankie postgresql7.1 select definition as text from acs_func_defs where lower(fname)=lower(:name) openacs-5.7.0/packages/acs-api-browser/www/proc-search.adp0000644000175000017500000000355211570011426023271 0ustar frankiefrankie @title;noquote@ @context;noquote@

    Procedure Matches

    No results found

    Show | Hide @private_results:rowcount@ private procedure matches

    Show | Hide @private_results:rowcount@ private procedure matches

    Show | Hide @deprecated_results:rowcount@ deprecated procedure matches

    Show | Hide @deprecated_results:rowcount@ deprecated procedure matches


    openacs-5.7.0/packages/acs-api-browser/www/proc-search.tcl0000644000175000017500000001366310551254371023321 0ustar frankiefrankie# acs-api-browser/www/proc-search.tcl ad_page_contract { Searches for procedures with containing query_string if lucky redirects to best match Weight the different hits with the propper weights Shows a list of returned procs with links to proc-view Note: api documentation information taken from nsv array @author Todd Nightingale (tnight@arsdigita.com) @creation-date Jul 14, 2000 @cvs-id $Id: proc-search.tcl,v 1.12 2007/01/10 21:22:01 gustafn Exp $ } { {name_weight:optional 0} {doc_weight:optional 0} {param_weight:optional 0} {source_weight:optional 0} {search_type:optional 0} {show_deprecated_p 0} {show_private_p 0} query_string } -properties { title:onevalue context:onevalue name_weight:onevalue doc_weight:onevalue param_weight:onevalue source_weight:onevalue query_string:onevalue results:multirow } ########################################################## ## Begin Page set quick_view [string equal $search_type "Only best match"] ######################### ## Optimizes quick search if {$quick_view && [nsv_exists api_proc_doc $query_string]} { ad_returnredirect [api_proc_url $query_string] ad_script_abort } ########################### # No weighting use default: if { ($name_weight == 0) && ($doc_weight == 0) && ($param_weight == 0) && ($source_weight ==0) } { set name_weight 1 } # Exact name search if {$name_weight eq "exact"} { set name_weight 5 set exact_match_p 1 } else { set exact_match_p 0 } set counter 0 set matches [list] set deprecated_matches [list] set private_matches [list] # place a [list proc_name score positionals] into matches for every proc foreach proc [nsv_array names api_proc_doc] { set score 0 array set doc_elements [nsv_get api_proc_doc $proc] ############### ## Name Search: ############### if {$name_weight} { # JCD: this was a little perverse since exact matches were # actually worth less than matches in the name (if there were # 2 or more, which happens with namespaces) so I doubled the # value of an exact match. ##Exact match: if {[string tolower $query_string] == [string tolower $proc]} { incr score [expr {$name_weight * 2}] } elseif { ! $exact_match_p } { incr score [expr {$name_weight * [ad_keywords_score $query_string $proc]}] } } ################ ## Param Search: ################ if {$param_weight} { incr score [expr {$param_weight * [ad_keywords_score $query_string "$doc_elements(positionals) $doc_elements(switches)"]}] } ############## ## Doc Search: ############## if {$doc_weight} { set doc_string "[lindex $doc_elements(main) 0]" if {[info exists doc_elements(param)]} { foreach parameter $doc_elements(param) { append doc_string " $parameter" } } if {[info exists doc_elements(return)]} { append doc_string " $doc_elements(return)" } incr score [expr {$doc_weight * [ad_keywords_score $query_string $doc_string]}] } ################# ## Source Search: ################# if {$source_weight} { if {![catch {set source [info body $proc]}]} { incr score [expr {$source_weight * [ad_keywords_score $query_string $source]}] } } ##### ## Place Needed info in matches if {$score} { if {$doc_elements(varargs_p)} { set args "$doc_elements(positionals) \[ args... \]" } else { set args $doc_elements(positionals) } if { $doc_elements(deprecated_p) } { lappend deprecated_matches [list $proc $score $args] } else { if { $doc_elements(public_p) } { lappend matches [list $proc $score $args] } else { lappend private_matches [list $proc $score $args] } } } } set matches [lsort -command ad_sort_by_score_proc $matches] if {$quick_view && $matches ne "" || [llength $matches] == 1 } { ad_returnredirect [api_proc_url [lindex [lindex $matches 0] 0]] ad_script_abort } set title "Procedure Search for: \"$query_string\"" set context [list "Search: $query_string"] multirow create results score proc args url foreach output $matches { incr counter set proc [lindex $output 0] set score [lindex $output 1] set args [lindex $output 2] set url [api_proc_url $proc] multirow append results $score $proc $args $url } multirow create deprecated_results score proc args url foreach output $deprecated_matches { incr counter set proc [lindex $output 0] set score [lindex $output 1] set args [lindex $output 2] set url [api_proc_url $proc] multirow append deprecated_results $score $proc $args $url } set show_deprecated_url [export_vars -base [ad_conn url] -override { { show_deprecated_p 1 } } { name_weight doc_weight param_weight source_weight search_type query_string show_private_p }] set hide_deprecated_url [export_vars -base [ad_conn url] -override { { show_deprecated_p 0 } } { name_weight doc_weight param_weight source_weight search_type query_string show_private_p }] multirow create private_results score proc args url foreach output $private_matches { incr counter set proc [lindex $output 0] set score [lindex $output 1] set args [lindex $output 2] set url [api_proc_url $proc] multirow append private_results $score $proc $args $url } set show_private_url [export_vars -base [ad_conn url] -override { { show_private_p 1 } } { name_weight doc_weight param_weight source_weight search_type query_string show_deprecated_p }] set hide_private_url [export_vars -base [ad_conn url] -override { { show_private_p 0 } } { name_weight doc_weight param_weight source_weight search_type query_string show_deprecated_p }] openacs-5.7.0/packages/acs-api-browser/www/procs-file-view.adp0000644000175000017500000000075507663154060024112 0ustar frankiefrankie @title;noquote@ @context;noquote@ @dimensional_slider;noquote@ @library_documentation;noquote@

    Procedures in this file

    • @proc_list.proc;noquote@

    Detailed information

    @proc_doc_list.doc;noquote@
     

    openacs-5.7.0/packages/acs-api-browser/www/procs-file-view.tcl0000644000175000017500000000424310551254371024120 0ustar frankiefrankiead_page_contract { Displays procs in a Tcl library file. @cvs-id $Id: procs-file-view.tcl,v 1.3 2007/01/10 21:22:01 gustafn Exp $ } { version_id:optional { public_p "" } path } -properties { title:onevalue context:onevalue dimensional_slider:onevalue library_documentation:onevalue proc_list:multirow proc_doc_list:multirow } if { ![info exists version_id] && \ [regexp {^packages/([^ /]+)/} $path "" package_key] } { db_0or1row version_id_from_package_key { select version_id from apm_enabled_package_versions where package_key = :package_key } } if {[info exists version_id]} { set public_p [api_set_public $version_id $public_p] } else { set public_p [api_set_public "" $public_p] } set dimensional_list { { public_p "Publicity:" 1 { { 1 "Public Only" } { 0 "All" } } } } set context [list] if { [info exists version_id] } { db_1row package_info_from_package_id { select pretty_name, package_key, version_name from apm_package_version_info where version_id = :version_id } lappend context [list "package-view?version_id=$version_id" "$pretty_name $version_name"] } lappend context [file tail $path] set title [file tail $path] set dimensional_slider [ad_dimensional $dimensional_list] set library_documentation [api_library_documentation $path] multirow create proc_list proc multirow create proc_doc_list doc if { [nsv_exists api_proc_doc_scripts $path] } { foreach proc [lsort [nsv_get api_proc_doc_scripts $path]] { if { $public_p } { array set doc_elements [nsv_get api_proc_doc $proc] if { !$doc_elements(public_p) } { continue } } multirow append proc_list [api_proc_pretty_name -link $proc] } foreach proc [lsort [nsv_get api_proc_doc_scripts $path]] { if { $public_p } { array set doc_elements [nsv_get api_proc_doc $proc] if { !$doc_elements(public_p) } { continue } } multirow append proc_doc_list [api_proc_documentation $proc] } } openacs-5.7.0/packages/acs-api-browser/www/type-view.adp0000644000175000017500000000017707663154060023026 0ustar frankiefrankie @title;noquote@ @context;noquote@ @documentation@openacs-5.7.0/packages/acs-api-browser/www/type-view.tcl0000644000175000017500000000174010005232275023026 0ustar frankiefrankiead_page_contract { Displays information about a type. @cvs-id $Id: type-view.tcl,v 1.3 2004/01/26 15:39:41 jeffd Exp $ } { version_id:optional type } -properties { title:onevalue context:onevalue documentation:onevalue } if { ![info exists version_id] && \ [regexp {^([^ /]+)/} $type "" package_key] } { db_0or1row version_id_from_package_key { select version_id from apm_enabled_package_versions where package_key = :package_key } } set public_p [api_set_public $version_id] set context [list] if { [info exists version_id] } { db_1row package_info_from_version_id { select package_name, package_key, version_name from apm_package_version_info where version_id = :version_id } lappend context [list "package-view?version_id=$version_id&kind=types" "$package_name $version_name"] } lappend context $type set title $type set documentation [api_type_documentation $type]openacs-5.7.0/packages/acs-api-browser/acs-api-browser.info0000644000175000017500000000274711575167336023452 0ustar frankiefrankie API Browser API Browsers t t OpenACS

    Interactive documentation for the Tcl and SQL APIs. 2011-06-12 3 OpenACS GPL 3 On line interactive documentation for the locally installed Tcl and SQL APIs. Links to the Tcl core and AOLServer online documentation as well. openacs-5.7.0/packages/intermedia-driver/0000755000175000017500000000000011724401447020167 5ustar frankiefrankieopenacs-5.7.0/packages/intermedia-driver/tcl/0000755000175000017500000000000011575226023020750 5ustar frankiefrankieopenacs-5.7.0/packages/intermedia-driver/tcl/intermedia-init.tcl0000644000175000017500000000055511022567614024544 0ustar frankiefrankie# ad_library { Scheduled proc init for intermedia driver @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2008-04-15 @cvs-id $Id: intermedia-init.tcl,v 1.2 2008/06/07 20:29:00 donb Exp $ } ad_schedule_proc -thread t 14400 db_exec_plsql optimize_intermedia_index {begin Ctx_Ddl.Optimize_Index ('swi_index','FAST'); end;} openacs-5.7.0/packages/intermedia-driver/tcl/intermedia-procs.tcl0000644000175000017500000001704710537571752024743 0ustar frankiefrankiead_library { procedures to support intermedia search engine for Oracle } ad_proc -public -callback search::index -impl intermedia-driver {} { Search Index Callback for Oracle Intermedia @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-06-12 } { # we want the datasource array reference in case we want to do something clever if {![string equal "" $datasource]} { upvar $datasource _datasource } set content "${title} ${content}" # if storage type is file, store the text in the site_wide_index table if {![db_string index_exists "select 1 from site_wide_index where object_id=:object_id" -default 0]} { db_dml index "insert into site_wide_index (object_id, object_name, package_id, relevant_date, community_id, indexed_content) values (:object_id, :title, :package_id, :relevant_date, :community_id, empty_clob() ) returning indexed_content into :1" -clobs [list $content] } else { # call the update index proc since this object is already indexed callback -impl intermedia-driver search::update_index \ -object_id $object_id \ -content $content \ -title $title \ -keywords $keywords \ -community_id $community_id \ -relevant_date $relevant_date \ -description $description \ -datasource $datasource \ -package_id $package_id } } ad_proc -public -callback search::update_index -impl intermedia-driver {} { Update item in the index @author Dave Bauer (dave@thedesignexperience.org @creation-date 2005-08-01 } { if {![string equal "" $datasource]} { upvar $datasource _datasource } if {![db_string index_exists "select 1 from site_wide_index where object_id=:object_id" -default 0]} { callback -impl intermedia-driver search::index \ -object_id $object_id \ -content $content \ -title $title \ -keywords $keywords \ -community_id $community_id \ -relevant_date $relevant_date \ -description $description \ -datasource $datasource \ -package_id $package_id return } else { db_dml index "update site_wide_index set object_name=:title, package_id=:package_id, community_id=:community_id, relevant_date=:relevant_date, indexed_content=empty_clob() where object_id=:object_id returning indexed_content into :1" -clobs [list $content] } } ad_proc -public -callback search::unindex -impl intermedia-driver {} { Remove item from search index @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-06-12 } { db_dml unindex "delete from site_wide_index where object_id=:object_id" } ad_proc -public -callback search::search -impl intermedia-driver {} { Search full text index @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-05-29 @param query @param offset @param limit @param user_id @param df @param dt @param package_ids @param object_type } { if {[info exists package_ids] && [llength $package_ids]} { set package_ids_clause " and swi.package_id in ([template::util::tcl_to_sql_list $package_ids]) " } else { set package_ids_clause "" } if {[info exists object_type] && [string equal $object_type "forums"]} { set object_type_clause " and o.object_type in ('forums_forum', 'forums_message') " } elseif {[info exists object_type] && ![string equal $object_type "all"]} { set object_type_clause " and o.object_type = :object_type " } else { set object_type_clause "" } set weighted_score "score(10) - case when object_type='faq' then nvl(months_between(sysdate,relevant_date)/4,20) when object_type='forums' then nvl(months_between(sysdate,relevant_date)*1.5,20) when object_type='phb_person' then 0 when object_type='news' then nvl(months_between(sysdate,relevant_date)*2,20) when object_type='cal_item' then nvl(months_between(sysdate,relevant_date)*2,20) when object_type='file_storage_object' then nvl(months_between(sysdate,relevant_date)*1.5,20) when object_type='survey' then nvl(months_between(sysdate,relevant_date)*1.5,20) when object_type='static_portal_content' then nvl(months_between(sysdate,relevant_date)*1.5,20) end" set people_search_clause { o.object_type = 'phb_person' or } if [apm_package_installed_p "dotlrn"] { set is_guest_p [search::is_guest_p] if {$is_guest_p} { set people_search_clause { and }; # doesn't look like legal SQL } set is_member { exists ( select 1 from dotlrn_member_rels_approved where community_id = swi.community_id and user_id = :user_id)} set community_id_clause " and (swi.community_id is null or $is_member) " set member_clause " and $is_member " } else { set community_id_clause {} set member_clause {} } set results_ids [db_list search "select s.object_id from (select rownum as r,o.object_id from site_wide_index swi, acs_objects o where swi.object_id= o.object_id $object_type_clause and contains (swi.indexed_content,:query, 10)> 0 and ( $people_search_clause (exists (select 1 from acs_object_party_privilege_map m where m.object_id = o.object_id and m.party_id = :user_id and m.privilege = 'read') $community_id_clause)) $package_ids_clause order by $weighted_score desc) s where r > $offset and r <= $offset + $limit"] # TODO implement stopwords reporting for user query set count [db_string count "select count(swi.object_id) from site_wide_index swi, acs_objects o where o.object_id=swi.object_id $object_type_clause and contains (swi.indexed_content,:query)> 0 and ( $people_search_clause (exists (select 1 from acs_object_party_privilege_map m where m.object_id = o.object_id and m.party_id = :user_id and m.privilege = 'read') $member_clause)) $package_ids_clause "] set stop_words "" ns_log notice " ----------------------------------------------------------------------------- DAVEB99 intermedia::search query = '{$query}' package_ids = '${package_ids}' return = '[list ids $results_ids stopwords $stop_words count $count]' ----------------------------------------------------------------------------- " return [list ids $results_ids stopwords $stop_words count $count] } ad_proc -public -callback search::summary -impl intermedia-driver { } { Get summary for an object @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-05-29 @param object_id } { # TODO implement intermedia::summary return [string range $text 0 100] } ad_proc -public -callback search::driver_info -impl intermedia-driver { } { Info for the service contract implementation for intermedia @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-05-29 } { return [list package_key intermedia-driver version 1 automatic_and_queries_p 1 stopwords_p 1] } openacs-5.7.0/packages/intermedia-driver/sql/0000755000175000017500000000000011724401447020766 5ustar frankiefrankieopenacs-5.7.0/packages/intermedia-driver/sql/oracle/0000755000175000017500000000000011575226023022232 5ustar frankiefrankieopenacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-ctxsys.sql0000644000175000017500000000222411022567614027721 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Create ctxsys schema objects for .LRN site-wide search -- -- @author openacs@dirkgomez.de -- @version $Id: intermedia-driver-ctxsys.sql,v 1.2 2008/06/07 20:29:00 donb Exp $ -- @creation-date 13-May-2005 -- -- Partly ported from ACES. CREATE OR replace procedure sws_user_proc_&1 ( rid IN ROWID, tlob IN OUT nocopy clob ) AS BEGIN &1..sws_user_datastore_proc(rid, tlob); END; / show errors; grant execute on sws_user_proc_&1 to &1; grant ctxapp to &1; -- stuff to make interMedia faster exec ctx_adm.set_parameter('max_index_memory', '1G'); exit; openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-packages-create.sql0000644000175000017500000001456311022567614031414 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Create database packages for .LRN site-wide search -- -- @author Dirk Gomez -- @version $Id: intermedia-driver-packages-create.sql,v 1.2 2008/06/07 20:29:00 donb Exp $ -- @creation-date 13-May-2005 -- Partly ported from ACES. -- The site_wide_search packages holds generally useful -- PL/SQL procedures and functions. create or replace package site_wide_search as procedure register_event (p_object_id search_observer_queue.object_id%TYPE, p_event search_observer_queue.event%TYPE); procedure logger (p_logmessage varchar); function im_convert( query in varchar2 default null ) return varchar2; end site_wide_search; / show errors create or replace package body site_wide_search as procedure register_event (p_object_id search_observer_queue.object_id%TYPE, p_event search_observer_queue.event%TYPE) is begin insert into search_observer_queue (object_id, event) values (p_object_id, p_event); end register_event; procedure logger (p_logmessage varchar) is begin insert into sws_log_messages (logmessage) values (p_logmessage); end logger; -- Query to take free text user entered query and frob it into something -- that will make interMedia happy. Provided by Oracle. function im_convert( query in varchar2 default null ) return varchar2 is i number :=0; len number :=0; char varchar2(1); minusString varchar2(256); plusString varchar2(256); mainString varchar2(256); mainAboutString varchar2(500); finalString varchar2(500); hasMain number :=0; hasPlus number :=0; hasMinus number :=0; token varchar2(256); tokenStart number :=1; tokenFinish number :=0; inPhrase number :=0; inPlus number :=0; inWord number :=0; inMinus number :=0; completePhrase number :=0; completeWord number :=0; code number :=0; begin len := length(query); -- we iterate over the string to find special web operators for i in 1..len loop char := substr(query,i,1); if(char = '"') then if(inPhrase = 0) then inPhrase := 1; tokenStart := i; else inPhrase := 0; completePhrase := 1; tokenFinish := i-1; end if; elsif(char = ' ') then if(inPhrase = 0) then completeWord := 1; tokenFinish := i-1; end if; elsif(char = '+') then inPlus := 1; tokenStart := i+1; elsif((char = '-') and (i = tokenStart)) then inMinus :=1; tokenStart := i+1; end if; if(completeWord=1) then token := '{ '||substr(query,tokenStart,tokenFinish-tokenStart+1)||' }'; if(inPlus=1) then plusString := plusString||','||token||'*10'; hasPlus :=1; elsif(inMinus=1) then minusString := minusString||'OR '||token||' '; hasMinus :=1; else mainString := mainString||' NEAR '||token; mainAboutString := mainAboutString||' '||token; hasMain :=1; end if; tokenStart :=i+1; tokenFinish :=0; inPlus := 0; inMinus :=0; end if; completePhrase := 0; completeWord :=0; end loop; -- find the last token token := '{ '||substr(query,tokenStart,len-tokenStart+1)||' }'; if(inPlus=1) then plusString := plusString||','||token||'*10'; hasPlus :=1; elsif(inMinus=1) then minusString := minusString||'OR '||token||' '; hasMinus :=1; else mainString := mainString||' NEAR '||token; mainAboutString := mainAboutString||' '||token; hasMain :=1; end if; mainString := substr(mainString,6,length(mainString)-5); mainAboutString := replace(mainAboutString,'{',' '); mainAboutString := replace(mainAboutString,'}',' '); mainAboutString := replace(mainAboutString,')',' '); mainAboutString := replace(mainAboutString,'(',' '); plusString := substr(plusString,2,length(plusString)-1); minusString := substr(minusString,4,length(minusString)-4); -- we find the components present and then process them based on the specific combinations code := hasMain*4+hasPlus*2+hasMinus; if(code = 7) then finalString := '('||plusString||','||mainString||'*2.0,about('||mainAboutString||')*0.5) NOT ('||minusString||')'; elsif (code = 6) then finalString := plusString||','||mainString||'*2.0'||',about('||mainAboutString||')*0.5'; elsif (code = 5) then finalString := '('||mainString||',about('||mainAboutString||')) NOT ('||minusString||')'; elsif (code = 4) then finalString := mainString; finalString := replace(finalString,'*1,',NULL); finalString := '('||finalString||')*2.0,about('||mainAboutString||')'; elsif (code = 3) then finalString := '('||plusString||') NOT ('||minusString||')'; elsif (code = 2) then finalString := plusString; elsif (code = 1) then -- not is a binary operator for intermedia text finalString := 'totallyImpossibleString'||' NOT ('||minusString||')'; elsif (code = 0) then finalString := ''; end if; return finalString; end; end site_wide_search; / show errors -------------------------------------------------------- -- The user_datastore proc which is called on every change of the datastore. create or replace procedure sws_user_datastore_proc ( p_rid in rowid, p_tlob in out nocopy clob ) is v_object_id site_wide_index.object_id%type; begin site_wide_search.logger ('entered sws_user_datastore_proc'); select indexed_content into p_tlob from site_wide_index swi, acs_objects ao where swi.object_id = ao.object_id and p_rid = swi.rowid; site_wide_search.logger ('in sws_user_datastore_proc with type ' || v_object_id); end; / show errors; exit; openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-tables-create.sql0000644000175000017500000000460011022567614031077 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Create database tables for .LRN site-wide search -- -- @author openacs@dirkgomez.de -- @version $Id: intermedia-driver-tables-create.sql,v 1.2 2008/06/07 20:29:00 donb Exp $ -- @creation-date 13-May-2005 -- -- Partly ported from ACES. -- Central table for site-wide search. declare v_aux integer; begin select count(table_name) into v_aux from user_tables where table_name = 'SITE_WIDE_INDEX'; IF v_aux = 0 THEN execute immediate 'create table site_wide_index ( object_id integer constraint sws_index_pk primary key constraint sws_index_fk references acs_objects(object_id) on delete cascade, object_name varchar(4000), indexed_content clob, -- Dirk Gomez: no not null constraint because we also want to -- be able to index objects which are not tied to an object, -- in particular people. package_id integer constraint swi_package_id_fk references apm_packages on delete cascade, -- Dirk Gomez: That''s the place to put an object''s relevant -- date which is part of the ranking function. In calendar -- this is the item date, in forum it could be the last reply -- date to a thread etc. relevant_date date )'; END IF; select count(table_name) into v_aux from user_tables where table_name = 'SWS_LOG_MESSAGES'; IF v_aux = 0 THEN -- Intermedia sometimes is painful to debug, so I added a logging -- mechanism which relies on Oracle's autonomous transactions: DML -- statements are committed immediately so you can access this data -- from a different session right away. execute immediate 'create table sws_log_messages ( logmessage varchar2(4000), logtime date default sysdate )'; END IF; END; / exit; openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-tables-drop.sql0000644000175000017500000000007111022567614030576 0ustar frankiefrankiedrop table site_wide_index; drop table sws_log_messages; openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-drop.sql~0000644000175000017500000000014511022567614027526 0ustar frankiefrankie@@ search-sc-drop.sql @@ search-packages-drop.sql @@ search-index-drop.sql @@ search-tables-drop.sql openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-drop.sql0000644000175000017500000000016011022567614027325 0ustar frankiefrankie@@ intermedia-driver-packages-drop.sql @@ intermedia-driver-index-drop.sql @@ intermedia-driver-tables-drop.sql openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-packages-drop.sql0000644000175000017500000000010311022567614031076 0ustar frankiefrankiedrop package body site_wide_search; drop package site_wide_search; openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-index-drop.sql0000644000175000017500000000166511022567614030445 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Drop the intermedia index for .LRN site-wide search -- -- @author Dirk Gomez -- @version $Id: intermedia-driver-index-drop.sql,v 1.2 2008/06/07 20:29:00 donb Exp $ -- @creation-date 13-May-2005 begin ctx_ddl.drop_section_group('swsgroup'); ctx_ddl.drop_preference('sws_user_datastore'); end; / drop index swi_index; exit; openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-index-create.sql0000644000175000017500000000261411022567614030737 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Create the intermedia index for .LRN site-wide search -- -- @author openacs@dirkgomez.de -- @version $Id: intermedia-driver-index-create.sql,v 1.2 2008/06/07 20:29:00 donb Exp $ -- @creation-date 13-May-2005 -- -- Partly ported from ACES. -- create section groups for within clauses begin ctx_ddl.create_section_group('swsgroup', 'basic_section_group'); ctx_ddl.add_field_section('swsgroup', 'oneline', 'oneline', TRUE); end; / create index swi_index on site_wide_index (indexed_content) indextype is ctxsys.context parameters ('datastore ctxsys.default_datastore memory 250M'); -- create intermedia index for site wide index begin ctx_ddl.create_preference('sws_user_datastore', 'user_datastore'); ctx_ddl.set_attribute('sws_user_datastore', 'procedure', 'sws_user_proc_&1'); end; / exit;openacs-5.7.0/packages/intermedia-driver/sql/oracle/intermedia-driver-create.sql0000644000175000017500000000016611022567614027632 0ustar frankiefrankie@@ intermedia-driver-tables-create.sql @@ intermedia-driver-index-create.sql @@ intermedia-driver-packages-create.sql openacs-5.7.0/packages/intermedia-driver/intermedia-driver.info0000644000175000017500000000227111575167337024473 0ustar frankiefrankie Intermedia Driver Intermedia Driver f t David Bauer Dirk Gomez Search package callback implementation for Oracle Intermedia. 2011-06-12 Implemented the search package callback interface for search engine driver using Oracle Intermedia. 3 openacs-5.7.0/packages/acs-lang/0000755000175000017500000000000011724401447016242 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/bin/0000755000175000017500000000000011724401447017012 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/bin/check-catalog.sh0000755000175000017500000001671607750206735022060 0ustar frankiefrankie#!/bin/sh # # This script attempts to check that catalog files of a certain package # (or all packages if no package key is provided) are consistent with # eachother and that they are consistent with lookups in the code. More # specifically the script does the following: # # 1) Checks that the info in the catalog filename matches info in # its xml content (package_key, locale and charset). # # 2) Checks that the set of keys in the message catalog is identical to the # set of keys in the adp, info, sql, and tcl files in the package. # # 3) Checks that the set of keys in non-en_US catalog files is present # in the en_US catalog file of the package. # Currently disabled as I'm not sure how to read the non-en_US files in the # the right charset. # # 4) Checks that all keys in non-en_US catalog files are present in the en_US one. # Currently disabled as I'm not sure how to read the non-en_US files in the # the right charset. # # 5) Checks that the package version in every catalog file is consistent with what # is in the corresponding info file. Currently only uses en_US files. # # The scripts assumes that message lookups in adp and info files are # on the format #package_key.message_key#, and that message lookups # in tcl files are always done with the underscore procedure. # # usage: check-catalog.sh [package_key package_key ...] # # @author Peter Marklund (peter@collaboraid.biz) export script_path=$(dirname $(which $0)) ### Functions start source ${script_path}/functions.sh get_date_time_key() { message_key=$1 localization_msg_part=$(echo $message_key | ${script_path}/mygrep '^localization-(.*)$') echo $localization_msg_part } check_one_key_in_catalog_file() { message_key=$1 catalog_package_key=$2 if ! egrep -q "" $en_US_file || echo "$0: $package_key - Warning: key $catalog_key in $file_name missing in $en_US_file" done done } check_catalog_keys_have_lookups() { # Check that all keys in the catalog file are either in tcl or adp or info files for catalog_key in `get_catalog_keys catalog/${package_key}.en_US.ISO-8859-1.xml` do date_time_key=$(get_date_time_key $catalog_key) if [ -n "$date_time_key" ]; then # Need special regexp for date time message keys lookup_lines=$(find $find_dirs -regex '.*\.\(info\|adp\|sql\|tcl\)' | xargs egrep "lc_get[^]]+$date_time_key") else lookup_lines=$(find $find_dirs -regex '.*\.\(info\|adp\|sql\|tcl\)' | xargs egrep "${package_key}\.$catalog_key") fi if [ -z "$lookup_lines" ]; then echo "$0: $package_key - Warning: key $catalog_key in catalog file not found in any adp, info, sql, or tcl file" fi done } check_tcl_file_lookups_are_in_catalog() { # Check that all message lookups in tcl files have entries in the message catalog #echo "$0: $package_key - checking non-datetime tcl lookups" message_key_pattern=$(get_message_key_pattern) # We are using the widest possible regexp here that could in rare cases lead to false alarms # However, that's better than risk removing keys used in tcl scripts for tcl_message_key in $(find $find_dirs -iname '*.tcl'|xargs ${script_path}/mygrep \ "(?:\[_\s+[{\"]?${package_key}|\[lang::message::lookup.*${package_key}|\#${package_key})\.($message_key_pattern)") do check_one_key_in_catalog_file $tcl_message_key $package_key done # Date time message lookups are special cases as they use lc_get #echo "$0: $package_key - checking datetime tcl lookups" for tcl_message_key in $(find $find_dirs -iname '*.tcl'|xargs ${script_path}/mygrep \ "(?ms)\[lc_get[^]]+?($message_key_pattern)\"?\]") do check_one_key_in_catalog_file "localization-$tcl_message_key" acs-lang done } check_adp_file_lookups_are_in_catalog() { catalog_file=catalog/${package_key}.en_US.ISO-8859-1.xml # Check that all message lookups in adp and info files are in the catalog file message_key_pattern=$(get_message_key_pattern) for adp_message_key in $(find $find_dirs -regex '.*\.\(info\|adp\|sql\)'|xargs ${script_path}/mygrep \ "#${package_key}\.($message_key_pattern)#") do check_one_key_in_catalog_file $adp_message_key $package_key done } ### Functions end packages_dir="${script_path}/../../" find_dirs="$packages_dir ${packages_dir}../www" # Process arguments if [ "$#" == "0" ]; then # No package provided - check all packages for catalog_dir in $(find $package_dir -iname catalog -type d) do # Recurse with each package key that has a catalog dir $0 $(basename $(dirname $catalog_dir)) done exit 0 fi for package_key in "$@" do export package_key # Check that the catalog file exists catalog_file_path="${packages_dir}${package_key}/catalog/${package_key}.en_US.ISO-8859-1.xml" if [ ! -e $catalog_file_path ]; then echo "$0: Error - the file $catalog_file_path in package $package_key doesn't exist, exiting" exit 1 fi package_path="${script_path}/../../${package_key}" cd $package_path for file_name in $(ls catalog/*en_US*.xml) do ${script_path}/check-catalog-file-path.pl "${package_path}/${file_name}" done echo "$0: $package_key - checking en_US catalog keys are in lookups" check_catalog_keys_have_lookups echo "$0: $package_key - checking tcl lookups are in en_US catalog file" check_tcl_file_lookups_are_in_catalog echo "$0: $package_key - checking adp lookups are in en_US catalog file" check_adp_file_lookups_are_in_catalog #check_consistency_non_en_US_files echo "$0: $package_key - checking that package version in each catalog file is consistent with package version in corresponding info file" check_package_version_of_catalog_files done openacs-5.7.0/packages/acs-lang/bin/check-catalog-file-path.pl0000755000175000017500000000263307633441722023716 0ustar frankiefrankie#!/usr/bin/perl -w # # Check that a catalog file has a consistent path and that package_key, locale, and # charset info in the xml is consistent with info embedded in the filename. # # @author Peter Marklund my $usage = "catalog-file-name.pl catalog_file_path"; use strict; # Get arguments my $file_path = shift or die "usage: $usage"; # Parse information from the file path $file_path =~ m#(?i)([a-z-]+)/catalog/\1\.([a-z]{2,3}_[a-z]{2})\.(.*)\.xml$# or die "catalog file path $file_path is not on format package_key/catalog/package_key.locale.charset.xml"; my ($file_package, $file_locale, $file_charset) = ($1, $2, $3, $4); # Get the same info from the xml of the catalog file open(FILE_INPUT, "< $file_path"); # Undefine the record separator to read the whole file in one go undef $/; my $file_contents = ; $file_contents =~ m## or die "catalog file $file_path does not have a root xml node on parsable format"; my ($xml_package, $xml_locale, $xml_charset) = ($1, $2, $3); # Assert that info in filename and xml be the same if ( $file_package ne $xml_package || $file_locale ne $xml_locale || $file_charset ne $xml_charset) { die "FAILURE: $file_path does not pass check since info in file path ($file_package, $file_locale, $file_charset) does not match info in xml ($xml_package, $xml_locale, $xml_charset)\n"; } openacs-5.7.0/packages/acs-lang/bin/functions.sh0000644000175000017500000000050307750456165021367 0ustar frankiefrankie# Functions re-used by scripts in acs-lang/bin # # @author Peter Marklund # Assumes script_path to be set get_catalog_keys() { file_name=$1 echo $(${script_path}/mygrep ' [files...] # # @author Peter Marklund (peter@collaboraid.biz) if ($ARGV[0] =~ /^-m/) { shift; # Undefine the record separator to read the whole file in one go undef $/; $pattern = shift; # Let . match newline if ($pattern !~ /^\w*\(\?\w*s\w*\)/) { $pattern = "(?s)$pattern"; } } else { $pattern = shift; } # Take input from STDIN or from files my $have_match = 0; while ($line = <>) { while ($line =~ /$pattern/) { if (defined($1)) { print STDOUT "$1\n"; } # Do next matching on whatever comes after last match $line=$'; $have_match = 1; } } $have_match ? exit 0 : exit 1; openacs-5.7.0/packages/acs-lang/lib/0000755000175000017500000000000011724401447017010 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/lib/conflict-link.adp0000644000175000017500000000023610047443532022231 0ustar frankiefrankie openacs-5.7.0/packages/acs-lang/lib/conflict-link.tcl0000644000175000017500000000105007766162050022251 0ustar frankiefrankie# Optional parameters: # # package_key # locale # Default params to empty string # and build the link export list set link_export_list [list] foreach param {package_key locale} { if { ![info exists $param] } { set $param "" } else { # param provided lappend link_export_list $param } } set conflict_count [lang::message::conflict_count \ -package_key $package_key \ -locale $locale] set message_conflicts_url [export_vars -base message-conflicts $link_export_list] openacs-5.7.0/packages/acs-lang/lib/change-locale-bar.adp0000755000175000017500000000071710061371042022720 0ustar frankiefrankie @locale_list.l10n_label@ @locale_list.l10n_label@ @change_locale_text@ @lang_admin_text@ openacs-5.7.0/packages/acs-lang/lib/change-locale-bar.tcl0000755000175000017500000000560110061371042022733 0ustar frankiefrankie# optional inputs: # return_url # max_locales # avail_key set current_locale [lang::conn::locale] set base_lang_url [site_node::get_package_url -package_key acs-lang] if { ![exists_and_not_null return_url]} { # Use referer header set return_url [ad_return_url] } if { ![exists_and_not_null max_locales]} { set max_locales 8 } if { ![exists_and_not_null avail_key] } { set avail_key "this-language" } # get a count of enabled locales set enabled_locale_count [db_string enabled_locale_count " select count(*) from enabled_locales el " -default 0] # get a list of valid locales for switching db_multirow -extend {l10n_label switch_url} locale_list get_locale_list " select el.label, el.locale, (select count(*) from user_preferences where locale = el.locale) as user_count from enabled_locales el where (select count(*) from lang_messages where message_key = :avail_key and locale = el.locale) > 0 order by user_count desc limit $max_locales " { set l10n_label [lang::message::lookup $locale acs-lang.${avail_key} "" "" 0] set switch_url [export_vars -base ${base_lang_url}change-locale {{return_p "t"} {user_locale $locale} return_url}] } set switchable_count [template::multirow size locale_list] set change_locale_url "" ####################################################################### # The text to change locales, in decreasing order of desirability # 1) "Change Locale" in the browser's requested locale. # 2) If there is a list of locales, "..." # (NOT to the system default for "Change Locale". The reason is that, after a list of # language names, "..." should be more recognizable than a foreign word) # 3) Fall back on the standard defaults for Change Locale set browser_locale [lang::conn::browser_locale] set localized_change_exists_p [lang::message::message_exists_p $browser_locale acs-lang.change-locale] if { $localized_change_exists_p } { set change_locale_text "[lang::message::lookup $browser_locale acs-lang.change-locale]" } else { set change_locale_text "[_ acs-lang.change-locale]" } if {$enabled_locale_count > 1 && $enabled_locale_count > $switchable_count} { set change_locale_url [export_vars -base ${base_lang_url} {return_url}] } if {$localized_change_exists_p && $switchable_count > 1 && $enabled_locale_count > $switchable_count} { set change_locale_text "..." } ####################################################################### # administrators' link set acs_lang_id [apm_package_id_from_key acs-lang] set lang_admin_p [permission::permission_p -privilege admin -object_id $acs_lang_id] set lang_admin_url [export_vars -base ${base_lang_url}admin {return_url}] if { $enabled_locale_count > 1 } { set lang_admin_text "Administer Locales" } else { set lang_admin_text "Add Locales" } openacs-5.7.0/packages/acs-lang/lib/messages-to-translate.adp0000644000175000017500000000021011043666757023724 0ustar frankiefrankie

    #acs-lang.Translated_messages_on_this_page#

    openacs-5.7.0/packages/acs-lang/lib/messages-to-translate.tcl0000644000175000017500000000405310551254373023741 0ustar frankiefrankieset locale [ad_conn locale] set display_p [expr {[lang::util::translator_mode_p] && [ad_conn locale] ne "en_US" }] template::list::create \ -name messages \ -multirow messages \ -elements { message_key { label "Message key" } orig_text { label "English text" } translated_text { label "Translation" display_template { Translate @messages.translated_text@ } } edit { label "" display_template { Edit } sub_class narrow } } if { $display_p } { multirow create messages message_key orig_text translated_text translate_url translated_p foreach message_key [lang::util::get_message_lookups] { set locale [ad_conn locale] # Extra args mean no substitution set orig_text [lang::message::lookup "en_US" $message_key {} {} 0 0] set translated_text [lang::message::lookup $locale $message_key {} {} 0 0] set key_split [split $message_key "."] set package_key_part [lindex $key_split 0] set message_key_part [lindex $key_split 1] set translate_url "/acs-lang/admin/edit-localized-message?[export_vars {{message_key $message_key_part} {package_key $package_key_part} locale { return_url [ad_return_url] } }]" set translated_p [lang::message::message_exists_p [ad_conn locale] $message_key] multirow append messages $message_key $orig_text $translated_text $translate_url $translated_p } } openacs-5.7.0/packages/acs-lang/tcl/0000755000175000017500000000000011724401447017024 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/tcl/locale-procs-oracle.xql0000644000175000017500000000055207573164536023416 0ustar frankiefrankie oracle8.1.6 select ( (sysdate - timezone.local_to_utc (timezone.get_id(:system_timezone), sysdate)) * 24 ) from dual openacs-5.7.0/packages/acs-lang/tcl/localization-procs.tcl0000644000175000017500000005412211002042112023323 0ustar frankiefrankie#/packages/lang/tcl/localization-procs.tcl ad_library { Routines for localizing numbers, dates and monetary amounts

    This is free software distributed under the terms of the GNU Public License. Full text of the license is available from the GNU Project: http://www.fsf.org/copyleft/gpl.html @creation-date 30 September 2000 @author Jeff Davis (davis@xarg.net) @author Ashok Argent-Katwala (akatwala@arsdigita.com) @cvs-id $Id: localization-procs.tcl,v 1.23 2008/04/18 06:48:42 victorg Exp $ } ad_proc -public lc_parse_number { num locale {integer_only_p 0} } { Converts a number to its canonical representation by stripping everything but the decimal seperator and triming left 0's so it won't be octal. It can process the following types of numbers:

    • Just digits (allows leading zeros).
    • Digits with a valid thousands separator, used consistently (leading zeros not allowed)
    • Either of the above with a decimal separator plus optional digits after the decimal marker
    The valid separators are taken from the given locale. Does not handle localized signed numbers in this version. The sign may only be placed before the number (with/without whitespace). Also allows the empty string, returning same. @param num Localized number @param locale Locale @param integer_only_p True if only integers returned @error If unsupported locale or not a number @return Canonical form of the number } { if {$num eq ""} { return "" } set dec [lc_get -locale $locale "decimal_point"] set thou [lc_get -locale $locale "mon_thousands_sep"][lc_get -locale $locale "thousands_sep"] set neg [lc_get -locale $locale "negative_sign"] set pos [lc_get -locale $locale "positive_sign"] lang::util::escape_vars_if_not_null {dec thou neg pos} # Pattern actually looks like this (separators notwithstanding): # {^\ *([-]|[+])?\ *([0-9]+|[1-9][0-9]{1,2}([,][0-9]{3})+)([.][0-9]*)?\ *$} set pattern "^\\ *($neg|$pos)?\\ *((\[0-9\]+|\[1-9\]\[0-9\]{0,2}($thou\[0-9\]\{3\})+)" if {$integer_only_p} { append pattern "?)(${dec}0*)?" } else { append pattern "?($dec\[0-9\]*)?)" } append pattern "\\ *\$" set is_valid_number [regexp -- $pattern $num match sign number] if {!$is_valid_number} { error "Not a number $num" } else { regsub -all "$thou" $number "" number if {!$integer_only_p} { regsub -all "$dec" $number "." number } # Strip leading zeros regexp -- "0*(\[0-9\.\]+)" $number match number # if number is real and mod(number)<1, then we have pulled off the leading zero; i.e. 0.231 -> .231 -- this is still fine for tcl though... # Last pathological case if {"." eq $number } { set number 0 } if {[string match "\\\\\\${sign}" $neg]} { set number -$number } return $number } } ad_proc -private lc_sepfmt { num {grouping {3}} {sep ,} {num_re {[0-9]}} } { Called by lc_numeric and lc_monetary.

    Takes a grouping specifier and inserts the given seperator into the string. Given a separator of : and a number of 123456789 it returns:

        grouping         Formatted Value
        {3 -1}               123456:789     
        {3}                  123:456:789    
        {3 2 -1}             1234:56:789    
        {3 2}                12:34:56:789   
        {-1}                 123456789      
        
    @param num Number @param grouping Grouping specifier @param sep Thousands separator @param num_re Regular expression for valid numbers @return Number formatted with thousand separator } { # with empty seperator or grouping string we behave # posixly if {$grouping eq "" || $sep eq "" } { return $num } # we need to sanitize the subspec regsub -all -- "(\[&\\\\\])" $sep "\\\\\\1" sep set match "^(-?$num_re+)(" set group [lindex $grouping 0] while { 1 && $group > 0} { set re "$match[string repeat $num_re $group])" if { ![regsub -- $re $num "\\1$sep\\2" num] } { break } if {[llength $grouping] > 1} { set grouping [lrange $grouping 1 end] } set group [lindex $grouping 0] } return $num } ad_proc -public lc_numeric { num {fmt {}} {locale ""} } { Given a number and a locale return a formatted version of the number for that locale. @param num Number in canonical form @param fmt Format string used by the tcl format command (should be restricted to the form "%.Nf" if present). @param locale Locale @return Localized form of the number } { if {$fmt ne ""} { set out [format $fmt $num] } else { set out $num } set sep [lc_get -locale $locale "thousands_sep"] set dec [lc_get -locale $locale "decimal_point"] set grouping [lc_get -locale $locale "grouping"] # Fall back on en_US if grouping is not on valid format if { $locale ne "en_US" && ![regexp {^[0-9 -]+$} $grouping] } { ns_log Warning "lc_numeric: acs-lang.localization-grouping key has invalid value $grouping for locale $locale" set sep , set dec . set grouping 3 } regsub {\.} $out $dec out return [lc_sepfmt $out $grouping $sep] } ad_proc -public lc_monetary_currency { { -label_p 0 } { -style local } num currency locale } { Formats a monetary amount, based on information held on given currency (ISO code), e.g. GBP, USD. @param label_p Set switch to a true value if you want to specify the label used for the currency. @param style Set to int to display the ISO code as the currency label. Otherwise displays an HTML entity for the currency. The label parameter must be true for this flag to take effect. @param num Number to format as a monetary amount. @param currency ISO currency code. @param locale Locale used for formatting the number. @return Formatted monetary amount } { set row_returned [db_0or1row lc_currency_select {}] if { !$row_returned } { ns_log Warning "lc_monetary_currency: Unsupported monetary currency, defaulting digits to 2" set fractional_digits 2 set html_entity "" } if { $label_p } { if {$style eq "int" } { set use_as_label $currency } else { set use_as_label $html_entity } } else { set use_as_label "" } return [lc_monetary -- $num $locale $fractional_digits $use_as_label] } ad_proc -private lc_monetary { { -label_p 0 } { -style local } num locale {forced_frac_digits ""} {forced_currency_symbol ""} } { Formats a monetary amount. @param label Specify this switch if you want to specify the label used for the currency. @param style Set to int to display the ISO code as the currency label. Otherwise displays an HTML entity for the currency. The label parameter must be specified for this flag to take effect. @param num Number to format as a monetary amount. If this number could be negative you should put "--" in your call before it. @param currency ISO currency code. @param locale Locale used for formatting the number. @return Formatted monetary amount } { if {$forced_frac_digits ne "" && [string is integer $forced_frac_digits]} { set dig $forced_frac_digits } else { # look up the digits if {$style eq "int" } { set dig [lc_get -locale $locale "int_frac_digits"] } else { set dig [lc_get -locale $locale "frac_digits"] } } # figure out if negative if {$num < 0} { set num [expr {abs($num)}] set neg 1 } else { set neg 0 } # generate formatted number set out [format "%.${dig}f" $num] # look up the label if needed if {$forced_currency_symbol eq ""} { if {$label_p} { if {$style eq "int" } { set sym [lc_get -locale $locale "int_curr_symbol"] } else { set sym [lc_get -locale $locale "currency_symbol"] } } else { set sym {} } } else { set sym $forced_currency_symbol } # signorama if {$neg} { set cs_precedes [lc_get -locale $locale "n_cs_precedes"] set sep_by_space [lc_get -locale $locale "n_sep_by_space"] set sign_pos [lc_get -locale $locale "n_sign_posn"] set sign [lc_get -locale $locale "negative_sign"] } else { set cs_precedes [lc_get -locale $locale "p_cs_precedes"] set sep_by_space [lc_get -locale $locale "p_sep_by_space"] set sign_pos [lc_get -locale $locale "p_sign_posn"] set sign [lc_get -locale $locale "positive_sign"] } # decimal seperator set dec [lc_get -locale $locale "mon_decimal_point"] regsub {\.} $out $dec out # commify set sep [lc_get -locale $locale "mon_thousands_sep"] set grouping [lc_get -locale $locale "mon_grouping"] set num [lc_sepfmt $out $grouping $sep] return [subst [nsv_get locale "money:$cs_precedes$sign_pos$sep_by_space"]] } ad_proc -public clock_to_ansi { seconds } { Convert a time in the Tcl internal clock seeconds format to ANSI format, usable by lc_time_fmt. @author Lars Pind (lars@pinds.com) @return ANSI (YYYY-MM-DD HH24:MI:SS) formatted date. @see lc_time_fmt } { return [clock format $seconds -format "%Y-%m-%d %H:%M:%S"] } ad_proc -public lc_get { {-locale ""} key } { Get a certain format string for the current locale. @param key the key of for the format string you want. @return the format string for the current locale. @author Lars Pind (lars@pinds.com) } { # All localization message keys have a certain prefix set message_key "acs-lang.localization-$key" # Set upvar level to 0 so that no attempt is made to interpolate variables # into the string # Set translator_mode_p to 0 so we don't dress the message up with a link to translate return [lang::message::lookup $locale $message_key {} {} 0 0] } ad_proc -public lc_time_fmt { datetime fmt {locale ""} } { Formats a time for the specified locale. @param datetime Strictly in the form "YYYY-MM-DD HH24:MI:SS". Formulae for calculating day of week from the Calendar FAQ (http://www.tondering.dk/claus/calendar.html) @param fmt An ISO 14652 LC_TIME style formatting string. The highlighted functions localize automatically based on the user's locale; other strings will use locale-specific text but not necessarily locale-specific formatting.
        
          %a           FDCC-set's abbreviated weekday name.
          %A           FDCC-set's full weekday name.
          %b           FDCC-set's abbreviated month name.
          %B           FDCC-set's full month name.
          %c           FDCC-set's appropriate date and time
                       representation.
          %C           Century (a year divided by 100 and truncated to
                       integer) as decimal number (00-99).
          %d           Day of the month as a decimal number (01-31).
          %D           Date in the format mm/dd/yy.
          %e           Day of the month as a decimal number (1-31 in at
                       two-digit field with leading  fill).
          %E           Month number as a decimal number (1-12 in at
                       two-digit field with leading  fill).
          %f           Weekday as a decimal number (1(Monday)-7).
          %F           is replaced by the date in the format YYYY-MM-DD
                       (ISO 8601 format)
          %h           A synonym for %b.
          %H           Hour (24-hour clock) as a decimal number (00-23).
          %I           Hour (12-hour clock) as a decimal number (01-12).
          %j           Day of the year as a decimal number (001-366).
          %m           Month as a decimal number (01-13).
          %M           Minute as a decimal number (00-59).
          %n           A  character.
          %p           FDCC-set's equivalent of either AM or PM.
          %r           Hours and minutes using 12-hour clock AM/PM
                       notation, e.g. '06:12 AM'. 
          %q           Long date without weekday (OpenACS addition to the standard)
          %Q           Long date with weekday (OpenACS addition to the standard)
          %S           Seconds as a decimal number (00-61).
          %t           A  character.
          %T           24-hour clock time in the format HH:MM:SS.
          %u           Week number of the year as a decimal number with
                       two digits and leading zero, according to "week"
                       keyword.
          %U           Week number of the year (Sunday as the first day of
                       the week) as a decimal number (00-53).
          %w           Weekday as a decimal number (0(Sunday)-6).
          %W           Week number of the year (Monday as the first day of
                       the week) as a decimal number (00-53).
          %x           FDCC-set's appropriate date representation.
          %X           FDCC-set's appropriate time representation.
          %y           Year (offset from %C) as a decimal number (00-99).
          %Y           Year with century as a decimal number.
          %Z           The connection's timezone, e.g. 'America/New_York'.
          %%           A  character.
        
    See also
    man strftime
    on a UNIX shell prompt for more of these abbreviations. @param locale Locale identifier must be in the locale database @error Fails if given a non-existant locale or a malformed datetime Doesn't check for impossible dates. Ask it for 29 Feb 1999 and it will tell you it was a Monday (1st March was a Monday, it wasn't a leap year). Also it only works with the Gregorian calendar - but that's reasonable, but could be a problem if you are running a seriously historical site (or have an 'on this day in history' style page that goes back a good few hundred years). @return A date formatted for a locale } { if { $datetime eq "" } { return "" } if { ![exists_and_not_null locale] } { set locale [ad_conn locale] } # Some initialisation... # Now, expect d_fmt, t_fmt and d_t_fmt to exist of the form in ISO spec # Rip $date into $lc_time_* as numbers, no leading zeroes set matchdate {([0-9]{4})\-0?(1?[0-9])\-0?([1-3]?[0-9])} set matchtime {0?([1-2]?[0-9]):0?([1-5]?[0-9]):0?([1-6]?[0-9])} set matchfull "$matchdate $matchtime" set lc_time_p 1 if {![regexp -- $matchfull $datetime match lc_time_year lc_time_month lc_time_days lc_time_hours lc_time_minutes lc_time_seconds]} { if {[regexp -- $matchdate $datetime match lc_time_year lc_time_month lc_time_days]} { set lc_time_hours 0 set lc_time_minutes 0 set lc_time_seconds 0 } else { error "Invalid date: $datetime" } } set a [expr (14 - $lc_time_month) / 12] set y [expr {$lc_time_year - $a}] set m [expr {$lc_time_month + 12*$a - 2}] # day_no becomes 0 for Sunday, through to 6 for Saturday. Perfect for addressing zero-based lists pulled from locale info. set lc_time_day_no [expr (($lc_time_days + $y + ($y/4) - ($y / 100) + ($y / 400)) + ((31*$m) / 12)) % 7] return [subst [util_memoize "lc_time_fmt_compile {$fmt} $locale"]] } ad_proc -public lc_time_fmt_compile { fmt locale } { Compiles ISO 14652 LC_TIME style formatting string to variable substitions and proc calls. @param fmt An ISO 14652 LC_TIME style formatting string. @param locale Locale identifier must be in the locale database @return A string that should be subst'ed in the lc_time_fmt proc after local variables have been set. } { set to_process $fmt set compiled_string "" while {[regexp -- {^(.*?)%(.)(.*)$} $to_process match done_portion percent_modifier remaining]} { switch -exact -- $percent_modifier { x { append compiled_string $done_portion set to_process "[lc_get -locale $locale "d_fmt"]$remaining" } X { append compiled_string $done_portion set to_process "[lc_get -locale $locale "t_fmt"]$remaining" } c { append compiled_string $done_portion set to_process "[lc_get -locale $locale "d_t_fmt"]$remaining" } q { append compiled_string $done_portion set to_process "[lc_get -locale $locale "dlong_fmt"]$remaining" } Q { append compiled_string $done_portion set to_process "[lc_get -locale $locale "dlongweekday_fmt"]$remaining" } default { append compiled_string "${done_portion}$::lang::util::percent_match($percent_modifier)" set to_process $remaining } } } # What is left to_process must be (%.)-less, so it should be included without transformation. append compiled_string $to_process return $compiled_string } ad_proc -public lc_time_utc_to_local { time_value {tz ""} } { Converts a Universal Time to local time for the specified timezone. @param time_value UTC time in the ISO datetime format. @param tz Timezone that must exist in tz_data table. @return Local time } { if { $tz eq "" } { set tz [lang::conn::timezone] } set local_time $time_value if {[catch { set local_time [db_exec_plsql utc_to_local {}] } errmsg] } { ns_log Warning "lc_time_utc_to_local: Query exploded on time conversion from UTC, probably just an invalid date, $time_value: $errmsg" } if {$local_time eq ""} { # If no conversion possible, log it and assume local is as given (i.e. UTC) ns_log Notice "lc_time_utc_to_local: Timezone adjustment in ad_localization.tcl found no conversion to UTC for $time_value $tz" } return $local_time } ad_proc -public lc_time_local_to_utc { time_value {tz ""} } { Converts a local time to a UTC time for the specified timezone. @param time_value Local time in the ISO datetime format, YYYY-MM-DD HH24:MI:SS @param tz Timezone that must exist in tz_data table. @return UTC time. } { if { $tz eq "" } { set tz [lang::conn::timezone] } set utc_time $time_value if {[catch { set utc_time [db_exec_plsql local_to_utc {}] } errmsg] } { ns_log Warning "lc_time_local_to_utc: Query exploded on time conversion to UTC, probably just an invalid date, $time_value: $errmsg" } if {$utc_time eq ""} { # If no conversion possible, log it and assume local is as given (i.e. UTC) ns_log Notice "lc_time_local_to_utc: Timezone adjustment in ad_localization.tcl found no conversion to local time for $time_value $tz" } return $utc_time } ad_proc -public lc_time_system_to_conn { time_value } { Converts a date from the system (database) to the connection's timezone, using the OpenACS timezone setting and user's preference @param time_value Timestamp from the database in the ISO datetime format. @return Timestamp in conn's local time, also in ISO datetime format. } { if { ![ad_conn isconnected] } { return $time_value } set system_tz [lang::system::timezone] set conn_tz [lang::conn::timezone] if { $conn_tz eq "" || $system_tz eq $conn_tz } { return $time_value } return [lc_time_tz_convert -from $system_tz -to $conn_tz -time_value $time_value] } ad_proc -public lc_time_conn_to_system { time_value } { Converts a date from the connection's timezone to the system (database) timezone, using the OpenACS timezone setting and user's preference @param time_value Timestamp from conn input in the ISO datetime format. @return Timestamp in the database's time zone, also in ISO datetime format. } { if { ![ad_conn isconnected] } { return $time_value } set system_tz [lang::system::timezone] set conn_tz [lang::conn::timezone] if { $conn_tz eq "" || $system_tz eq $conn_tz } { return $time_value } return [lc_time_tz_convert -from $conn_tz -to $system_tz -time_value $time_value] } ad_proc -public lc_time_tz_convert { {-from:required} {-to:required} {-time_value:required} } { Converts a date from one timezone to another. @param time_value Timestamp in the 'from' timezone, in the ISO datetime format. @return Timestamp in the 'to' timezone, also in ISO datetime format. } { with_catch errmsg { set time_value [db_exec_plsql convert {}] } { ns_log Warning "lc_time_tz_convert: Error converting timezone: $errmsg" } return $time_value } ad_proc -public lc_list_all_timezones { } { @return list of pairs containing all timezone names and offsets. Data drawn from acs-reference package timezones table } { return [db_list_of_lists all_timezones {}] } ad_proc -private lc_time_drop_meridian { hours } { Converts HH24 to HH12. } { if {$hours>12} { incr hours -12 } elseif {$hours==0} { set hours 12 } return $hours } ad_proc -private lc_wrap_sunday { day_no } { To go from 0(Sun) - 6(Sat) to 1(Mon) - 7(Sun) } { if {$day_no==0} { return 7 } else { return $day_no } } ad_proc -private lc_time_name_meridian { locale hours } { Returns locale data depending on AM or PM. } { if {$hours > 11} { return [lc_get -locale $locale "pm_str"] } else { return [lc_get -locale $locale "am_str"] } } ad_proc -private lc_leading_space {num} { Inserts a leading space for numbers less than 10. } { if {$num < 10} { return " $num" } else { return $num } } ad_proc -private lc_leading_zeros { the_integer n_desired_digits } { Adds leading zeros to an integer to give it the desired number of digits } { return [format "%0${n_desired_digits}d" $the_integer] } openacs-5.7.0/packages/acs-lang/tcl/localization-procs.xql0000644000175000017500000000074307661402556023401 0ustar frankiefrankie select fractional_digits, html_entity from currency_codes where iso = :currency select distinct tz, gmt_offset from timezones order by tz openacs-5.7.0/packages/acs-lang/tcl/test/0000755000175000017500000000000011575225526020011 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/tcl/test/acs-lang-message-procs.tcl0000755000175000017500000000177510475640431024757 0ustar frankiefrankiead_library { Test cases for lang-message-procs @author Veronica De La Cruz (veronica@viaro.net) @creation-date 11 Aug 2006 } aa_register_case -cats {smoke api} \ -procs {lang::message::register lang::message::get} \ test_message_register { Simple test that registrates a new message to the BD. } { aa_run_with_teardown -rollback -test_code { set message_key [ad_generate_random_string] set message [ad_generate_random_string] set package_key "acs-translations" set locale "en_US" aa_log "Creating message : $message || message key: $message_key" # Creates the new message lang::message::register $locale $package_key $message_key $message # Try to retrieve the new message created. lang::message::get -package_key $package_key -message_key $message_key -locale $locale -array message_new aa_true "Message add succeeded" [string equal $message_new(message) $message] } } openacs-5.7.0/packages/acs-lang/tcl/test/acs-lang-test-procs.tcl0000644000175000017500000011664510551254374024314 0ustar frankiefrankiead_library { Helper test Tcl procedures. @author Peter Marklund (peter@collaboraid.biz) @creation-date 18 October 2002 } namespace eval lang::test {} ad_proc -private lang::test::get_dir {} { The test directory of the acs-lang package (where this file resides). @author Peter Marklund (peter@collaboraid.biz) @creation-date 28 October 2002 } { return "[acs_package_root_dir acs-lang]/tcl/test" } ad_proc -private lang::test::assert_browser_locale {accept_language expect_locale} { Assert that with given accept language header lang::conn::browser_locale returns the expected locale. @author Peter Marklund } { ns_set update [ns_conn headers] "Accept-Language" $accept_language set browser_locale [lang::conn::browser_locale] aa_equals "accept-language header \"$accept_language\"" $browser_locale $expect_locale } ad_proc -private lang::test::test_package_key {} { return "acs-lang-test-tmp" } ad_proc -private lang::test::setup_test_package {} { set package_key [test_package_key] set package_name "acs-lang temporary test package" set package_dir [file join [acs_root_dir] packages $package_key] file mkdir $package_dir set info_file_path "${package_dir}/${package_key}.info" set info_file_contents " $package_name $package_name f f Peter Marklund Temporary acs-lang test package 2003-11-07 Collaboraid Temporary test package created by acs-lang test case. " template::util::write_file $info_file_path $info_file_contents # Install the test package without catalog files apm_package_install \ -enable \ [apm_package_info_file_path $package_key] aa_true "Package install: package enabled" \ [expr [lsearch -exact [apm_enabled_packages] $package_key] != -1] } ad_proc -private lang::test::teardown_test_package {} { apm_package_delete -remove_files=1 [test_package_key] } ad_proc -private lang::test::check_import_result { {-package_key:required} {-locale:required} {-upgrade_array:required} {-base_array:required} {-db_array:required} {-file_array:required} } { This proc checks that the properties of messages in the database are what we expect after a message catalog import or upgrade. @author Peter Marklund } { upvar $upgrade_array upgrade_expect upvar $base_array base_messages upvar $db_array db_messages upvar $file_array file_messages # Check that we have the expected message properties in the database after upgrade foreach message_key [lsort [array names upgrade_expect]] { array set expect_property $upgrade_expect($message_key) switch $expect_property(message) { db { set expect_message $db_messages($message_key) } file { set expect_message $file_messages($message_key) } base { set expect_message $base_messages($message_key) } } array unset message_actual lang::message::get \ -package_key $package_key \ -message_key $message_key \ -locale $locale \ -array message_actual # Check message properties aa_equals "Import check: $message_key - lang_messages.message" $message_actual(message) $expect_message aa_equals "Import check: $message_key - lang_messages.deleted_p" $message_actual(deleted_p) $expect_property(deleted_p) aa_equals "Import check: $message_key - lang_messages.conflict_p" $message_actual(conflict_p) $expect_property(conflict_p) aa_equals "Import check: $message_key - lang_messages.upgrade_status" \ $message_actual(upgrade_status) $expect_property(upgrade_status) if {$expect_property(sync_time) eq "not_null"} { aa_true "Import check: $message_key - lang_messages.sync_time not null" \ [expr {$message_actual(sync_time) ne ""}] } else { aa_true "Import check: $message_key - lang_messages.sync_time null" \ [expr {$message_actual(sync_time) eq ""}] } } } ad_proc -private lang::test::execute_upgrade { {-locale:required} } { Executes the logic of the upgrade test case for a certain locale. @author Peter Marklund } { set package_key [lang::test::test_package_key] # The key numbers correspond to the 14 cases described in the api-doc for lang::catalog::upgrade array set base_messages { key01 "Key 1" key04 "Key 4" key05 "Key 5" key06 "Key 6" key07 "Key 7" key10 "Key 10" key11 "Key 11" key12 "Key 12" key13 "Key 13 differ" key14 "Key 14 base" } array set db_messages { key02 "Key 2" key06 "Key 6 differ" key07 "Key 7" key08 "Key 8" key09 "Key 9" key10 "Key 10" key11 "Key 11 differ" key12 "Key 12" key13 "Key 13" key14 "Key 14 db" } array set file_messages { key03 "Key 3" key04 "Key 4 differ" key05 "Key 5" key08 "Key 8 differ" key09 "Key 9" key10 "Key 10" key11 "Key 11" key12 "Key 12 differ" key13 "Key 13" key14 "Key 14 file" } # Add the locale to each message so we can tell messages in # different locales apart foreach array_name {base_messages db_messages file_messages} { foreach message_key [array names $array_name] { append ${array_name}($message_key) " $locale" } } array set upgrade_expect { key01 { message base deleted_p t conflict_p f sync_time not_null upgrade_status no_upgrade } key02 { message db deleted_p f conflict_p f sync_time null upgrade_status no_upgrade } key03 { message file deleted_p f conflict_p f sync_time not_null upgrade_status added } key04 { message file deleted_p f conflict_p t sync_time not_null upgrade_status added } key05 { message base deleted_p t conflict_p f sync_time null upgrade_status no_upgrade } key06 { message db deleted_p t conflict_p t sync_time not_null upgrade_status deleted } key07 { message db deleted_p t conflict_p f sync_time not_null upgrade_status deleted } key08 { message file deleted_p f conflict_p t sync_time not_null upgrade_status updated } key09 { message db deleted_p f conflict_p f sync_time not_null upgrade_status no_upgrade } key10 { message db deleted_p f conflict_p f sync_time not_null upgrade_status added } key11 { message db deleted_p f conflict_p f sync_time null upgrade_status no_upgrade } key12 { message file deleted_p f conflict_p f sync_time not_null upgrade_status updated } key13 { message db deleted_p f conflict_p f sync_time not_null upgrade_status no_upgrade } key14 { message file deleted_p f conflict_p t sync_time not_null upgrade_status updated } } # # Execution plan: # # 1. Import some messages (base_messages below) # 2. Make changes to DB (db_messages below) # 3. Make changes to catalog files and import again (file_messages below) # 4. Check that merged result is what we expect (upgrade_expect below) # 5. Import again # 6. Check that we still have the same result (verify idempotent) # 7. Resolve some conflicts, but not all # 8. Import again # 9. Check that we have what's expected then # aa_log "-------------------------------------------------------------------" aa_log "*** Executing upgrade test with locale $locale" aa_log "-------------------------------------------------------------------" #---------------------------------------------------------------------- # 1. Import some messages (base_messages) #---------------------------------------------------------------------- aa_log "locale=$locale ----------1. import some messages----------" # Write original catalog file set catalog_file_path [lang::catalog::get_catalog_file_path \ -package_key $package_key \ -locale $locale] lang::catalog::export_to_file $catalog_file_path [array get base_messages] aa_true "Initial export: messages exported to file $catalog_file_path" [file exists $catalog_file_path] aa_log [template::util::read_file $catalog_file_path] # Import the catalog file array unset message_count array set message_count [lang::catalog::import -package_key $package_key -locales [list $locale]] aa_log "Imported messages: [array get message_count]" # Check that we have the expected messages in the database array unset actual_db_messages array set actual_db_messages [lang::catalog::messages_in_db -package_key $package_key -locale $locale] foreach message_key [lsort [array names base_messages]] { aa_equals "Initial import: message for key $message_key in db same as in file" \ $actual_db_messages($message_key) $base_messages($message_key) } #---------------------------------------------------------------------- # 2. Make changes to DB (db_messages) #---------------------------------------------------------------------- aa_log "locale=$locale ----------2. Make changes to DB----------" # Carry out changes to the message catalog in the db foreach message_key [lsort [array names upgrade_expect]] { set register_p 0 if { ![info exists db_messages($message_key)] } { # Message is not supposed to exist in DB if { [info exists base_messages($message_key)] } { # Message currently does exist in DB: Delete aa_log "Deleting message $message_key" lang::message::delete \ -package_key $package_key \ -message_key $message_key \ -locale $locale } } else { # Message is supposed to exist in DB # Is it new or changed? if { ![info exists base_messages($message_key)] || \ $base_messages($message_key) ne $db_messages($message_key) } { # Added || updated aa_log "Adding/updating message $message_key" lang::message::register \ $locale \ $package_key \ $message_key \ $db_messages($message_key) } } } #---------------------------------------------------------------------- # 3. Make changes to catalog files and import again (file_messages) #---------------------------------------------------------------------- aa_log "locale=$locale ----------3. Make changes to catalog files and do first upgrade----------" # Update the catalog file file delete -force $catalog_file_path lang::catalog::export_to_file $catalog_file_path [array get file_messages] aa_true "First upgrade: catalog file $catalog_file_path updated" [file exists $catalog_file_path] # Execute a first upgrade lang::catalog::import -package_key $package_key -locales [list $locale] #---------------------------------------------------------------------- # 4. Check that merged result is what we expect (upgrade_expect) #---------------------------------------------------------------------- aa_log "locale=$locale ----------4. Check merge result of first upgrade----------" lang::test::check_import_result \ -package_key $package_key \ -locale $locale \ -upgrade_array upgrade_expect \ -base_array base_messages \ -db_array db_messages \ -file_array file_messages #---------------------------------------------------------------------- # 5. First upgrade (second import) #---------------------------------------------------------------------- aa_log "locale=$locale ----------5. Second upgrade ----------" lang::catalog::import -package_key $package_key -locales [list $locale] #---------------------------------------------------------------------- # 6. Check that we still have the same result (verify idempotent) #---------------------------------------------------------------------- aa_log "locale=$locale ----------6. Check merge results of second upgrade (verify idempotent)----------" lang::test::check_import_result \ -package_key $package_key \ -locale $locale \ -upgrade_array upgrade_expect \ -base_array base_messages \ -db_array db_messages \ -file_array file_messages #---------------------------------------------------------------------- # 7. Resolve some conflicts, but not all #---------------------------------------------------------------------- aa_log "locale=$locale ----------7. Resolve some conflicts, but not all----------" array set conflict_resolutions { key06 "key06 resolution message" key08 "accept" } foreach message_key [array names conflict_resolutions] { if {$conflict_resolutions($message_key) eq "accept"} { # Resolution is an accept - just toggle conflict_p flag lang::message::edit $package_key $message_key $locale [list conflict_p f] # Set the message to be what's in the database (the accepted message) set conflict_resolutions($message_key) [lang::message::get_element \ -package_key $package_key \ -message_key $message_key \ -locale $locale \ -element message] } else { # Resolution is an edit lang::message::register \ $locale \ $package_key \ $message_key \ $conflict_resolutions($message_key) } } # TODO: test resolution being to retain the message (just toggle conflict_p) # TODO: test resolution being to delete a resurrected message # TODO: test other resolution possibilities #---------------------------------------------------------------------- # 8. Third upgrade #---------------------------------------------------------------------- aa_log "locale=$locale ----------8. Do third upgrade----------" lang::catalog::import -package_key $package_key -locales [list $locale] #---------------------------------------------------------------------- # 9. Check that we have what's expected then (resolutions are sticky) #---------------------------------------------------------------------- aa_log "locale=$locale ----------9. Check results of third upgrade (that resolutions are sticky)----------" foreach message_key [array names conflict_resolutions] { array unset message_array lang::message::get \ -package_key $package_key \ -message_key $message_key \ -locale $locale \ -array message_array aa_equals "$message_key - conflict message that has been resolved in UI has conflict_p=f" \ $message_array(conflict_p) "f" aa_equals "$message_key - the resolved conflict is not clobbered by an additional import" \ $message_array(message) $conflict_resolutions($message_key) } } aa_register_case \ -procs { lang::util::replace_temporary_tags_with_lookups lang::catalog::export_messages_to_file lang::catalog::parse lang::catalog::read_file lang::util::get_temporary_tags_indices } util__replace_temporary_tags_with_lookups { A test tcl file and catalog file are created. The temporary tags in the tcl file are replaced with message lookups and keys and messages are appended to the catalog file. @author Peter Marklund (peter@collaboraid.biz) @creation-date 18 October 2002 } { # Peter NOTE: cannot get this test case to work with the rollback code in automated testing # and couldn't track down why. I'm threrefor resorting to manual teardown which is fragile and hairy # The files involved in the test set package_key acs-lang set test_dir [lang::test::get_dir] set catalog_dir [lang::catalog::package_catalog_dir $package_key] set catalog_file "${catalog_dir}/acs-lang.xxx_xx.ISO-8859-1.xml" set backup_file_suffix ".orig" set catalog_backup_file "${catalog_file}${backup_file_suffix}" regexp {^.*(packages/.*)$} $test_dir match test_dir_rel set tcl_file "${test_dir_rel}/test-message-tags.tcl" set tcl_backup_file "${tcl_file}${backup_file_suffix}" # The test messages to use for the catalog file array set messages_array [list key_1 text_1 key_2 text_2 key_3 text_3] # NOTE: must be kept up-to-date for teardown to work set expected_new_keys [list Auto_Key key_1_1] # Write the test tcl file set tcl_file_id [open "[acs_root_dir]/$tcl_file" w] set new_key_1 "_" set new_text_1 "Auto Key" set new_key_2 "key_1" set new_text_2 "text_1_different" set new_key_3 "key_1" set new_text_3 "$messages_array(key_1)" puts $tcl_file_id "# The following key should be auto-generated and inserted # <# ${new_key_1} ${new_text_1} #> # # The following key should be made unique and inserted # <#${new_key_2} ${new_text_2}#> # # The following key should not be inserted in the message catalog # <#${new_key_3} ${new_text_3}#>" close $tcl_file_id # Write the catalog file lang::catalog::export_to_file $catalog_file [array get messages_array] # We need to force the API to export to the test catalog file aa_stub lang::catalog::get_catalog_file_path " return $catalog_file " # Replace message tags in the tcl file and insert into catalog file lang::util::replace_temporary_tags_with_lookups $tcl_file aa_unstub lang::catalog::get_catalog_file_path # Read the contents of the catalog file array set catalog_array [lang::catalog::parse [lang::catalog::read_file $catalog_file]] array set updated_messages_array [lindex [array get catalog_array messages] 1] # Assert that the old messages are unchanged foreach old_message_key [array names messages_array] { aa_true "old key $old_message_key should be unchanged" [string equal $messages_array($old_message_key) \ $updated_messages_array($old_message_key)] } # Check that the first new key was autogenerated aa_true "check autogenerated key" [string equal $updated_messages_array(Auto_Key) $new_text_1] # Check that the second new key was made unique and inserted aa_true "check key made unique" [string equal $updated_messages_array(${new_key_2}_1) $new_text_2] # Check that the third key was not inserted aa_true "third key not inserted" [string equal [lindex [array get updated_messages_array $new_key_3] 1] \ $messages_array($new_key_3)] # Check that there are no tags left in the tcl file set tcl_file_id [open "[acs_root_dir]/$tcl_file" r] set updated_tcl_contents [read $tcl_file_id] close $tcl_file_id aa_true "tags in tcl file replaced" [expr [llength [lang::util::get_temporary_tags_indices $updated_tcl_contents]] == 0] # Delete the test message keys foreach message_key [concat [array names messages_array] $expected_new_keys] { lang::message::unregister $package_key $message_key } # Delete the catalog files file delete $catalog_backup_file file delete $catalog_file # Delete the tcl files file delete "[acs_root_dir]/$tcl_file" file delete "[acs_root_dir]/$tcl_backup_file" } aa_register_case \ -procs { lang::util::get_hash_indices } util__get_hash_indices { @author Peter Marklund (peter@collaboraid.biz) @creation-date 21 October 2002 } { set multilingual_string "#package1.key1# abc\# #package2.key2#" set indices_list [lang::util::get_hash_indices $multilingual_string] set expected_indices_list [list [list 0 14] [list 21 35]] aa_true "there should be two hash entries" [expr {[llength $indices_list] == 2}] set counter 0 foreach index_item $indices_list { set expected_index_item [lindex $expected_indices_list $counter] aa_true "checking start and end indices of item $counter" \ [expr [string equal [lindex $index_item 0] [lindex $expected_index_item 0]] && \ [string equal [lindex $index_item 1] [lindex $expected_index_item 1]]] set counter [expr {$counter + 1}] } } aa_register_case \ -procs { lang::util::convert_adp_variables_to_percentage_signs lang::util::convert_percentage_signs_to_adp_variables } util__convert_adp_variables_to_percentage_signs { @author Peter Marklund (peter@collaboraid.biz) @creation-date 25 October 2002 } { set adp_chunk "@array.variable_name@ @variable_name2;noquote@ peter@collaboraid.biz" set adp_chunk_converted [lang::util::convert_adp_variables_to_percentage_signs $adp_chunk] set adp_chunk_expected "%array.variable_name% %variable_name2;noquote% peter@collaboraid.biz" aa_equals "adp vars should be subsituted with percentage sings" $adp_chunk_converted $adp_chunk_expected set adp_chunk_converted_back [lang::util::convert_percentage_signs_to_adp_variables $adp_chunk_converted] aa_equals "after having converted the text with percentage signs back to adp we should have what we started with" $adp_chunk_converted $adp_chunk_expected # Test that a string can start with adp vars set adp_chunk "@first_names.foobar;noquote@ @last_name@ peter@collaboraid.biz" set adp_chunk_converted [lang::util::convert_adp_variables_to_percentage_signs $adp_chunk] set adp_chunk_expected "%first_names.foobar;noquote% %last_name% peter@collaboraid.biz" aa_equals "adp vars should be subsituted with percentage sings" $adp_chunk_converted $adp_chunk_expected set adp_chunk_converted_back [lang::util::convert_percentage_signs_to_adp_variables $adp_chunk_converted] aa_equals "after having converted the text with percentage signs back to adp we should have what we started with" $adp_chunk_converted $adp_chunk_expected set percentage_chunk {You are %role.character_title% (%role.role_pretty%)} set percentage_chunk_converted [lang::util::convert_percentage_signs_to_adp_variables $percentage_chunk] set percentage_chunk_expected {You are @role.character_title@ (@role.role_pretty@)} aa_equals "converting percentage vars to adp vars" $percentage_chunk_converted $percentage_chunk_expected } aa_register_case \ -procs { lang::util::replace_adp_text_with_message_tags } util__replace_adp_text_with_message_tags { @author Peter Marklund (peter@collaboraid.biz) @creation-date 28 October 2002 } { # File paths used set adp_file_path "[lang::test::get_dir]/adp_tmp_file.adp" # Write the adp test file set adp_file_id [open $adp_file_path w] puts $adp_file_id " @first_names@ @last_name@ peter@collaboraid.biz @context_bar@ Test text" close $adp_file_id # Do the substitutions lang::util::replace_adp_text_with_message_tags $adp_file_path "write" # Read the changed test file set adp_file_id [open $adp_file_path r] set adp_contents [read $adp_file_id] close $adp_file_id set expected_adp_pattern { <#[a-zA-Z_]+ @first_names@ @last_name@ peter@collaboraid.biz#> @context_bar@ <#[a-zA-Z_]+ Test text\s*} # Assert proper replacements have been done aa_true "replacing adp text with tags" \ [regexp $expected_adp_pattern $adp_contents match] # Remove the adp test file file delete $adp_file_path } aa_register_case \ -procs { lang::message::format } message__format { @author Peter Marklund (peter@collaboraid.biz) @creation-date 21 October 2002 } { set localized_message "The %frog% jumped across the %fence%. About 50% of the time, he stumbled, or maybe it was %%20 %times%." set value_list {frog frog fence fence} set subst_message [lang::message::format $localized_message $value_list] set expected_message "The frog jumped across the fence. About 50% of the time, he stumbled, or maybe it was %20 %times%." aa_equals "the frog should jump across the fence" $subst_message $expected_message set my_var(my_key) foo set localized_message "A text with an array variable %my_var.my_key% in it" set subst_message [lang::message::format $localized_message {} 1] set expected_message "A text with an array variable foo in it" aa_equals "embedded array variable" $subst_message $expected_message } aa_register_case \ -procs { lang::message::get_embedded_vars } message__get_embedded_vars { @author Peter Marklund (peter@collaboraid.biz) @creation-date 12 November 2002 } { set en_us_message "This message contains no vars" set new_message "This is a message with some %vars% and some more %variables%" set missing_vars_list [util_get_subset_missing \ [lang::message::get_embedded_vars $new_message] \ [lang::message::get_embedded_vars $en_us_message]] if { ![aa_true "Find missing vars 'vars' and 'variables'" [util_sets_equal_p $missing_vars_list { vars variables }]] } { aa_log "Missing variables returned was: '$missing_vars_list'" aa_log "en_US Message: '$en_us_message' -> Variables: '[lang::message::get_embedded_vars $en_us_message]'" aa_log "Other Message: '$new_message' -> Variables: '[lang::message::get_embedded_vars $new_message]'" } # This failed on the test servers set en_us_message "Back to %ad_url%%return_url%" set new_message "Tillbaka till %ad_url%%return_url%" set missing_vars_list [util_get_subset_missing \ [lang::message::get_embedded_vars $new_message] \ [lang::message::get_embedded_vars $en_us_message]] if { ![aa_equals "No missing vars" [llength $missing_vars_list] 0] } { aa_log "Missing vars: $missing_vars_list" } # Testing variables with digits in the variable names set en_us_message "Some variables %var1%%var2% again" set new_message "Nogle variable %var1%%var2% igen" set missing_vars_list [util_get_subset_missing \ [lang::message::get_embedded_vars $new_message] \ [lang::message::get_embedded_vars $en_us_message]] if { ![aa_equals "No missing vars" [llength $missing_vars_list] 0] } { aa_log "Missing vars: $missing_vars_list" } } aa_register_case \ -procs { lang::system::set_locale lang::system::locale lang::system::site_wide_locale } locale__test_system_package_setting { Tests whether the system package level setting works @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-08-12 } { set use_package_level_locales_p_org [parameter::get -parameter UsePackageLevelLocalesP -package_id [apm_package_id_from_key "acs-lang"]] parameter::set_value -parameter UsePackageLevelLocalesP -package_id [apm_package_id_from_key "acs-lang"] -value 1 # There's no foreign key constraint on the locales column, so this should work set locale_to_set [ad_generate_random_string] set retrieved_locale {} # We could really use a 'finally' block on 'with_catch' (a block, which gets executed at the end, regardless of whether there was an error or not) with_catch errmsg { # Let's pick a random unmounted package to test with set package_id [apm_package_id_from_key "acs-kernel"] set org_setting [lang::system::site_wide_locale] lang::system::set_locale -package_id $package_id $locale_to_set set retrieved_locale [lang::system::locale -package_id $package_id] } { parameter::set_value -parameter UsePackageLevelLocalesP -package_id [apm_package_id_from_key "acs-lang"] -value $use_package_level_locales_p_org global errorInfo error $errmsg $errorInfo } parameter::set_value -parameter UsePackageLevelLocalesP -package_id [apm_package_id_from_key "acs-lang"] -value $use_package_level_locales_p_org aa_true "Retrieved system locale ('$retrieved_locale') equals the one we just set ('$locale_to_set')" [string equal $locale_to_set $retrieved_locale] } aa_register_case \ -procs { lang::conn::browser_locale } locale__test_lang_conn_browser_locale { @author Peter Marklund @creation-date 2003-08-13 } { aa_run_with_teardown \ -rollback \ -test_code { # The tests assume that the danish locale is enabled db_dml enable_all_locales { update ad_locales set enabled_p = 't' where locale = 'da_DK' } util_memoize_flush_regexp {^lang::system::get_locales} # First locale is perfect language match lang::test::assert_browser_locale "da,en-us;q=0.8,de;q=0.5,es;q=0.3" "da_DK" # First locale is perfect locale match lang::test::assert_browser_locale "da_DK,en-us;q=0.8,de;q=0.5,es;q=0.3" "da_DK" # Tentative match being discarded lang::test::assert_browser_locale "da_BLA,foobar,en" "en_US" # Tentative match being used lang::test::assert_browser_locale "da_BLA,foobar" "da_DK" # Several tentative matches, all being discarded lang::test::assert_browser_locale "da_BLA,foobar,da_BLUB,da_DK" "da_DK" } } aa_register_case \ -cats db \ strange_oracle_problem { Strange Oracle problem when selecting by language } { set language "da " set locale da_DK set db_string [db_string select_default_locale { select locale from ad_locales where language = :language } -default "WRONG"] aa_false "Does not return 'WRONG'" [string equal $db_string "WRONG"] } aa_register_case \ -procs { lang::user::set_timezone lang::system::set_timezone lang::system::timezone } set_get_timezone { Test that setting and getting user timezone works } { # We cannot test timezones if they are not installed if { [lang::system::timezone_support_p] } { # Make sure we have a logged in user set org_user_id [ad_conn user_id] if { $org_user_id == 0 } { set user_id [db_string user { select min(user_id) from users }] ad_conn -set user_id $user_id } else { set user_id $org_user_id } # Remember originals so we can restore them set system_timezone [lang::system::timezone] set user_timezone [lang::user::timezone] set timezones [lc_list_all_timezones] set desired_user_timezone [lindex [lindex $timezones [randomRange [expr {[llength $timezones]-1}]]] 0] set desired_system_timezone [lindex [lindex $timezones [randomRange [expr {[llength $timezones]-1}]]] 0] set error_p 0 with_catch errmsg { # User timezone lang::user::set_timezone $desired_user_timezone aa_equals "User timezone retrieved is the same as the one set" [lang::user::timezone] $desired_user_timezone # Storage set user_id [ad_conn user_id] aa_equals "User timezone stored in user_preferences table" \ [db_string user_prefs { select timezone from user_preferences where user_id = :user_id }] \ $desired_user_timezone # System timezone lang::system::set_timezone $desired_system_timezone aa_equals "System timezone retrieved is the same as the one set" [lang::system::timezone] $desired_system_timezone # Connection timezone aa_equals "Using user timezone" [lang::conn::timezone] $desired_user_timezone ad_conn -set isconnected 0 aa_equals "Fallback to system timezone when no connection" [lang::conn::timezone] $desired_system_timezone ad_conn -set isconnected 1 lang::user::set_timezone {} aa_equals "Fallback to system timezone when no user pref" [lang::conn::timezone] $desired_system_timezone } { set error_p 1 } # Clean up lang::system::set_timezone $system_timezone lang::user::set_timezone $user_timezone ad_conn -set user_id $org_user_id if { $error_p } { # rethrow the error global errorInfo error $errmsg $errorInfo } } } aa_register_case \ -procs { lang::user::set_timezone lang::system::timezone } set_timezone_not_logged_in { Test that setting and getting user timezone throws an error when user is not logged in } { # We cannot test timezones if they are not installed if { [lang::system::timezone_support_p] } { set user_id [ad_conn user_id] ad_conn -set user_id 0 aa_equals "Fallback to system timezone when no user" [lang::conn::timezone] [lang::system::timezone] set error_p [catch { lang::user::set_timezone [lang::system::timezone] } errmsg] aa_true "Error when setting user timezone when user not logged in" $error_p # Reset the user_id ad_conn -set user_id $user_id } } aa_register_case lc_time_fmt_Z_timezone { lc_time_fmt %Z returns current connection timezone } { aa_equals "%Z returns current timezone" [lc_time_fmt "2003-08-15 13:40:00" "%Z"] [lang::conn::timezone] } aa_register_case \ -procs { lang::message::lookup } locale_language_fallback { Test that we fall back to 'default locale for language' when requesting a message which exists in default locale for language, but not in the current locale } { # Assuming we have en_US and en_GB set package_key "acs-lang" set message_key [ad_generate_random_string] set us_message [ad_generate_random_string] set gb_message [ad_generate_random_string] set error_p 0 with_catch saved_error { lang::message::register "en_US" $package_key $message_key $us_message aa_equals "Looking up message in GB returns US message" \ [lang::message::lookup "en_GB" "$package_key.$message_key" "NOT FOUND"] \ $us_message lang::message::register "en_GB" $package_key $message_key $gb_message aa_equals "Looking up message in GB returns GB message" \ [lang::message::lookup "en_GB" "$package_key.$message_key" "NOT FOUND"] \ $gb_message } { set error_p 1 global errorInfo set saved_errorInfo $errorInfo } # Clean up db_dml delete_msg { delete from lang_messages where package_key = :package_key and message_key = :message_key } db_dml delete_key { delete from lang_message_keys where package_key = :package_key and message_key = :message_key } if { $error_p } { error $saved_error $saved_errorInfo } } aa_register_case \ -procs { lang::catalog::import lang::message::edit lang::message::get } upgrade { Test that a package can be upgraded with new catalog files and that the resulting keys and messages in the database can then be exported properly. What we are testing is a scenario similar to what we have on the OpenACS Translation server (http://translate.openacs.org). @author Peter Marklund } { # Create the test package in the file system lang::test::setup_test_package # Can't run this test case with the usual rollback switch since if everthing # is wrapped in one transaction then the creation_date of the messages will be the # same and the query in lang::catalog::last_sync_messages will return duplicates. aa_run_with_teardown \ -test_code { lang::test::execute_upgrade -locale en_US lang::system::locale_set_enabled \ -locale de_DE \ -enabled_p t lang::test::execute_upgrade -locale de_DE } -teardown_code { foreach message_key [array names upgrade_expect] { lang::message::unregister $package_key $message_key } lang::test::teardown_test_package } } aa_register_case -procs { lang::util::localize } localize { @author Peter Marklund } { set package_key "acs-lang" set message_key "__test-key" set message "Test message" aa_run_with_teardown \ -rollback \ -test_code { # Create a temporary test message to test with lang::message::register en_US $package_key $message_key $message # Create some random character strings to surround the embedded key set pre_text "a;iuwgon#" set message_key_embedded "#${package_key}.${message_key}#" # Test replacements set text1 $message_key_embedded aa_equals "One message key with no surrounding text" [lang::util::localize $text1] "${message}" set text1 "${pre_text}${message_key_embedded}${post_text}" aa_equals "One message key with surrounding text" [lang::util::localize $text1] "${pre_text}${message}${post_text}" set text1 "${pre_text}${message_key_embedded}" aa_equals "One message key with text before" [lang::util::localize $text1] "${pre_text}${message}" set text1 "${message_key_embedded}${post_text}" aa_equals "One message key with text after" [lang::util::localize $text1] "${message}${post_text}" set text1 "${pre_text}${message_key_embedded}${post_text}${pre_text}${message_key_embedded}${post_text}" aa_equals "Two message keys with surrounding text" [lang::util::localize $text1] \ "${pre_text}${message}${post_text}${pre_text}${message}${post_text}" } -teardown_code { # We need to clear the cache lang::message::unregister $package_key $message_key } } openacs-5.7.0/packages/acs-lang/tcl/lang-audit-procs.tcl0000644000175000017500000000137307766162051022713 0ustar frankiefrankie#/packages/acs-lang/tcl/lang-message-procs.tcl ad_library { Auditing of lang_messages @creation-date 3 December 2002 @author Peter Marklund (peter@collaboraid.biz) @cvs-id $Id: lang-audit-procs.tcl,v 1.5 2003/12/11 21:39:53 jeffd Exp $ } namespace eval lang::audit { ad_proc -public changed_message { old_message package_key message_key locale comment deleted_p sync_time conflict_p upgrade_status } { Save a message that is overwritten. @author Peter Marklund } { # Save the old message in the audit table set overwrite_user [ad_conn user_id] db_dml lang_message_audit {} -clobs [list $old_message $comment] } } openacs-5.7.0/packages/acs-lang/tcl/lang-util-procs.tcl0000644000175000017500000010046411321666756022566 0ustar frankiefrankie#/packages/acs-lang/tcl/lang-util-procs.tcl ad_library { Utility routines for translating pages. Many of these procs deal with message keys embedded in strings with the #key# or the <#key text#> syntax.

    This is free software distributed under the terms of the GNU Public License. Full text of the license is available from the GNU Project: http://www.fsf.org/copyleft/gpl.html @creation-date 10 September 2000 @author Jeff Davis (davis@xarg.net) @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) @author Peter Marklund (peter@collaboraid.biz) @author Lars Pind (lars@collaboraid.biz) @author Christian Hvid @cvs-id $Id: lang-util-procs.tcl,v 1.46 2010/01/08 17:39:58 emmar Exp $ } namespace eval lang::util {} ad_proc -public lang::util::lang_sort { field {locale {}} } { Each locale can have a different alphabetical sort order. You can test this proc with the following data:

        insert into lang_testsort values ('lama');
        insert into lang_testsort values ('lhasa');
        insert into lang_testsort values ('llama');
        insert into lang_testsort values ('lzim');  
        
    @author Jeff Davis (davis@xarg.net) @param field Name of Oracle column @param locale Locale for sorting. If locale is unspecified just return the column name @return Language aware version of field for Oracle ORDER BY clause. } { # Use west european for english since I think that will fold # cedilla etc into reasonable values... set lang(en) "XWest_european" set lang(de) "XGerman_din" set lang(fr) "XFrench" set lang(es) "XSpanish" if { $locale eq "" || ![info exists lang($locale)] } { return $field } else { return "NLSSORT($field,'NLS_SORT = $lang($locale)')" } } ad_proc -private lang::util::get_hash_indices { multilingual_string } { Returns a list of two element lists containing the start and end indices of a #message_key# match in the multilingual string. This proc is used by the localize proc. @author Peter marklund (peter@collaboraid.biz) } { set regexp_pattern {(?:^|[^\\])(\#[-a-zA-Z0-9_:]+\.[-a-zA-Z0-9_:]+\#)} return [get_regexp_indices $multilingual_string $regexp_pattern] } ad_proc lang::util::message_tag_regexp {} { The regexp expression used by proc get_temporary_tags_indices and elsewhere to extract temporary message catalog tags (<#...#>) from adp and tcl files. The first sub match of the expression is the whole tag, the second sub match is the message key, and the third sub match is the message text in en_US locale. @author Peter marklund (peter@collaboraid.biz) } { return {(<#\s*?([-a-zA-Z0-9_:\.]+)\s+(.+?)\s*?#>)} } ad_proc lang::util::get_temporary_tags_indices { adp_file_string } { Given the contents of an adp file return the indices of the start and end chars of embedded message keys on the syntax: <#package_key.message_key Some en_US text#> @author Peter marklund (peter@collaboraid.biz) } { return [lang::util::get_regexp_indices $adp_file_string [message_tag_regexp]] } ad_proc -private lang::util::get_regexp_indices { multilingual_string regexp_pattern } { Returns a list of two element lists containing the start and end indices of what is captured by the first parenthesis in the given regexp pattern in the multilingual string. The regexp pattern must follow the syntax of the expression argument to the TCL regexp command. It must also contain exactly one capturing parenthesis for the pieces of text that indices are to be returned for. @see get_hash_indices @author Peter marklund (peter@collaboraid.biz) } { set multilingual_string_offset "0" set offset_string $multilingual_string set indices_list [list] while { [regexp -indices $regexp_pattern $offset_string full_match_idx key_match_idx] } { set start_idx [lindex $key_match_idx 0] set end_idx [lindex $key_match_idx 1] lappend indices_list [list [expr {$multilingual_string_offset + $start_idx}] \ [expr {$multilingual_string_offset + $end_idx}]] set new_offset [expr {$end_idx + 1}] set multilingual_string_offset [expr {$multilingual_string_offset + $new_offset}] set offset_string [string range $offset_string $new_offset end] } return $indices_list } ad_proc lang::util::replace_temporary_tags_with_lookups { file_list } { Modify the given adp or tcl files by replacing occurencies of <#package_key.message_key Some text#> with message lookups (i.e. #package_key.message_key# for adp files and [_ "package_key.message_key"] for tcl files) and create entries in the catalog file for each of these keys. If the short hand form <#_ Some en_US text#> is used then the key will be autogenerated based on the text. Returns the number of replacements done. This procedure only reads from and writes to the catalog file specified (the en_US catalog file per default) of the package that the files belong to, the database is not accessed in any way. @param file_list A list of paths to adp or tcl files to do replacements in. The paths should be relative to [acs_root_dir]. All files must belong to the same package. @author Peter marklund (peter@collaboraid.biz) } { # Return if there are no files to process if { [llength $file_list] == 0 } { ns_log Warning "lang::util::replace_temporary_tags_with_lookups: Invoked with no files to process, returning" return } # Get package_key set first_file [lindex $file_list 0] if { ![regexp {/?packages/([^/]+)/} $first_file match package_key] } { error "lang::util::replace_temporary_tags_with_lookups: Could not extract package_key from file $first_file" } # Always create new keys in en_US set locale "en_US" # Read messages from any existing catalog file set catalog_file_path [lang::catalog::get_catalog_file_path \ -package_key $package_key \ -locale $locale] if { [file exists $catalog_file_path] } { set catalog_file_contents [lang::catalog::read_file $catalog_file_path] array set catalog_array [lang::catalog::parse $catalog_file_contents] array set messages_array [lindex [array get catalog_array messages] 1] } else { array set messages_array {} } # Keep track of how many message tags we have replaced (will be returned by this proc) set number_of_replacements "0" # Loop over and process each file foreach file $file_list { ns_log debug "lang::util::replace_temporary_tags_with_lookups: processing file $file" set full_file_path "[acs_root_dir]/$file" regexp {\.([^.]+)$} $file match file_ending # Attempt a backup of the file first. Do not overwrite an old backup file. if { [catch "file -- copy $full_file_path \"${full_file_path}.orig\"" errmsg] } { ns_log Warning "The file $full_file_path could not be backed up before message key extraction since backup file ${full_file_path}.orig already exists" } # Read the contents of the file set file_contents [template::util::read_file $full_file_path] set modified_file_contents $file_contents # Loop over each message tag in the file # Get the indices of the first and last char of the <#...#> text snippets set message_key_indices [lang::util::get_temporary_tags_indices $file_contents] foreach index_pair $message_key_indices { incr number_of_replacements set tag_start_idx [lindex $index_pair 0] set tag_end_idx [lindex $index_pair 1] set message_tag "[string range $file_contents $tag_start_idx $tag_end_idx]" # Extract the message key and the text from the message tag # The regexp on the message tag string should never fail as the message tag # was extracted with a known regexp if { ![regexp [message_tag_regexp] $message_tag full_match \ message_tag message_key new_text] } { ns_log Error [list lang::util::replace_temporary_tags_with_lookups - could not extract message key \ and text from the message tag $message_tag in file $file. This means there is a \ mismatch with the regexp that extracted the message key.] continue } # if the message key is the _ symbol (an underscore) then automatically generate a key # based on the message text if {$message_key eq "_"} { set message_key [suggest_key $new_text] } # If this is an adp file - replace adp variable syntax with percentage variables if {$file_ending eq "adp"} { set new_text [convert_adp_variables_to_percentage_signs $new_text] } # Check if the key already exists, if it does and texts differ - make key unique set key_comp_counter "0" set unique_key $message_key while { 1 } { set existing_text [lindex [array get messages_array $unique_key] 1] if { $existing_text ne "" } { # The key already exists if {$existing_text eq $new_text} { # New and old texts are identical - don't add the key ns_log Notice [list lang::util::replace_temporary_tags_with_lookups - \ message key $unique_key already exists in catalog \ file with same value, will not add] # We are done break } else { # New and old texts differ, try to make the key unique and check again set unique_key "${message_key}_[expr {${key_comp_counter} + 1}]" } } else { # The key is new - save it in the array for addition if { $message_key ne $unique_key } { # The message key had to be changed to be made unique ns_log Warning [list lang::util::replace_temporary_tags_with_lookups - \ The message key $message_key was changed to $unique_key \ to be made unique. If the value was mistyped and should have been \ the same as previously then you must manually remove the entry for \ $unique_key from the catalog file and change the key in \ the file $file fom $unique_key to $message_key] } else { ns_log Notice [list lang::util::replace_temporary_tags_with_lookups - Will be adding \ new key $unique_key to catalog file for package $package_key] } set messages_array($unique_key) $new_text # We are done break } incr key_comp_counter } # Replace the message tag with a message key lookup in the file switch -regexp -- $file_ending { {^(adp|sql)$} { regsub [message_tag_regexp] \ $modified_file_contents \ "#${package_key}.${unique_key}#" \ modified_file_contents } {^tcl$} { regsub [message_tag_regexp] \ $modified_file_contents \ "\[_ ${package_key}.${unique_key}\]" \ modified_file_contents } {.*} { error "Unknown ending $file_ending of file $file, aborting" } } } # Update the file with the replaced message keys set file_id [open "${full_file_path}" w] puts -nonewline $file_id $modified_file_contents close $file_id } if { $number_of_replacements > 0 } { # Register the messages in the database so that the new messages are immediately reflected # in the system foreach {message_key message_text} [array get messages_array] { lang::message::register en_US $package_key $message_key $message_text } # Generate a new catalog file lang::catalog::export -locales [list $locale] -package_key $package_key } return $number_of_replacements } ad_proc -public lang::util::localize { string_with_hashes {locale ""} } { Takes a string with embedded message keys on the format #message_key_name# and returns the same string but with the message keys (and their surrounding hash marks) replaced with the corresponding value in the message catalog. Message lookup is done with the locale of the request. If message lookup fails for a certain key then a translation missing message will be used instead. @author Peter marklund (peter@collaboraid.biz) } { # Return quickly for the fairly frequent case where there are no embedded message keys if { ![string match "*#*" $string_with_hashes] } { return $string_with_hashes } if {$locale eq ""} { set locale [ad_conn locale] } set indices_list [get_hash_indices $string_with_hashes] set subst_string "" set start_idx 0 foreach item_idx $indices_list { # The replacement string starts and ends with a hash mark set replacement_string [string range $string_with_hashes [lindex $item_idx 0] \ [lindex $item_idx 1]] set message_key [string range $replacement_string 1 [expr {[string length $replacement_string] - 2}]] # Attempt a message lookup set message_value [lang::message::lookup $locale $message_key "" "" 2] # Replace the string # LARS: We don't use regsub here, because regsub interprets certain characters # in the replacement string specially. append subst_string [string range $string_with_hashes $start_idx [expr {[lindex $item_idx 0]-1}]] append subst_string $message_value set start_idx [expr {[lindex $item_idx 1] + 1}] } append subst_string [string range $string_with_hashes $start_idx end] return $subst_string } ad_proc -public lang::util::charset_for_locale { locale } { Returns the MIME charset name corresponding to a locale. @author Henry Minsky (hqm@mit.edu) @param locale Name of a locale, as language_COUNTRY using ISO 639 and ISO 3166 @return IANA MIME character set name } { # DRB: cache this now that ad_conn tracks it return [db_string -cache_key ad_lang_mime_charset_$locale charset_for_locale {}] } ad_proc -private lang::util::default_locale_from_lang_not_cached { language } { Returns the default locale for a language. Not cached. @author Henry Minsky (hqm@mit.edu) @param language Name of a language, using a two or three letter ISO code @return Default locale @see lang::util::default_locale_from_lang } { # LARS: # Note that this query does not use bind variables, because these cause the query to not # match any rows in Oracle when the language key is less than 3 characters, # because the column is a char(3), not a varchar2(3). return [db_string default_locale_from_lang {} -default ""] } ad_proc -public lang::util::default_locale_from_lang { language } { Returns an enabled default locale for a language. If a language only has one locale then that locale is returned. If no locale could be found the empty string is returned. @author Henry Minsky (hqm@mit.edu) @param language Name of a country, using ISO-3166 two letter code @return Default locale } { return [util_memoize [list lang::util::default_locale_from_lang_not_cached $language]] } ad_proc -public lang::util::nls_language_from_language { language } { Returns the nls_language name for a language @author Henry Minsky (hqm@mit.edu) @param language Name of a country, using ISO-3166 two letter code @return The nls_language name of the language. } { return [db_string nls_language_from_language {}] } ad_proc -private lang::util::remove_gt_lt { s } { Removes < > and replaces them with < > } { regsub -all "<" $s {\<} s regsub -all ">" $s {\>} s return $s } ad_proc -private lang::util::suggest_key { text } { Suggest a key for given text. } { regsub -all " " $text "_" key # Do not allow . in the key as dot is used as a separator to qualify a key # with the package key. The prepending with package key is done at a later # stage regsub -all {[^-a-zA-Z0-9_]} $key "" key # is this key too long? if { [string length $key] > 20 } { set key "lt_[string range $key 0 20]" } return $key } ad_proc -private lang::util::convert_adp_variables_to_percentage_signs { text } { Convert ADP variables to percentage_signs - the notation used to interpolate variable values into acs-lang messages. @author Peter Marklund } { # substitute array variable references # loop to handle the case of adjacent variable references, like @a@@b@ while {[regsub -all [template::adp_array_variable_regexp] $text {\1%\2.\3%} text]} {} while {[regsub -all [template::adp_array_variable_regexp_noquote] $text {\1%\2.\3;noquote%} text]} {} # substitute simple variable references while {[regsub -all [template::adp_variable_regexp] $text {\1%\2%} text]} {} while {[regsub -all [template::adp_variable_regexp_noquote] $text {\1%\2;noquote%} text]} {} return $text } ad_proc -private lang::util::convert_percentage_signs_to_adp_variables { text } { Convert percentage_signs message vars to adp var syntax. @see lang::util::convert_adp_variables_to_percentage_signs @author Peter Marklund } { # substitute array variable references # loop to handle the case of adjacent variable references, like @a@@b@ regsub -all {@} [template::adp_array_variable_regexp] {%} pattern while {[regsub -all $pattern $text {\1@\2.\3@} text]} {} regsub -all {@} [template::adp_array_variable_regexp_noquote] {%} pattern while {[regsub -all $pattern $text {\1@\2.\3;noquote@} text]} {} # substitute simple variable references regsub -all {@} [template::adp_variable_regexp] {%} pattern while {[regsub -all $pattern $text {\1@\2@} text]} {} regsub -all {@} [template::adp_variable_regexp_noquote] {%} pattern while {[regsub -all $pattern $text {\1@\2;noquote@} text]} {} return $text } ad_proc -public lang::util::replace_adp_text_with_message_tags { file_name mode {keys {}} } { Prepares an .adp-file for localization by inserting temporary hash-tags around text strings that looks like unlocalized plain text. Needless to say this is a little shaky so not all plain text is caught and the script may insert hash-tags around stuff that should not be localized. It is conservative though. There are two modes the script can be run in: - report : do *not* write changes to the file but return a report with suggested changes. - write : write changes in the file - it expects a list of keys and will insert them in the order implied by the report - a report is also returned. @param file_name The name of the adp file to do replacements in. @param mode Either report or write. @param keys A list of keys to use for the texts that may be provided in write mode. If the keys are not provided then autogenerated keys will be used. If a supplied key is the empty string this indicates that the corresponding text should be left untouched. @return The report is list of two lists: The first being a list of pairs (key, text with context) and the second is a list of suspious looking garbage. In report mode the keys are suggested keys and in write mode the keys are the keys supplied in the keys parameter. @author Christian Hvid @author Peter Marklund @author Jeff Davis } { set state text set out {} set report [list] set garbage [list] set n 0 # open file and read its content set fp [open $file_name "r"] set s [read $fp] close $fp #ns_write "input== s=[string range $s 0 600]\n" set x {} while {$s ne "" && $n < 1000} { if { $state eq "text" } { # clip non tag stuff if {![regexp {(^[^<]*?)(<.*)$} $s match text s x]} { set text $s set s {} } # Remove parts from the text that we know are not translatable # such as adp variables, message key lookups, and   set translatable_remainder $text set adp_var_patterns [list [template::adp_array_variable_regexp] \ [template::adp_array_variable_regexp_noquote] \ [template::adp_variable_regexp] \ [template::adp_variable_regexp_noquote]] foreach adp_var_pattern $adp_var_patterns { regsub -all $adp_var_pattern $translatable_remainder "" translatable_remainder } regsub -all {#[a-zA-Z0-9\._-]+#} $translatable_remainder "" translatable_remainder regsub -all { } $translatable_remainder "" translatable_remainder # Only consider the text translatable if the remainder contains # at least one letter if { [string match -nocase {*[A-Z]*} $translatable_remainder] } { regexp {^(\s*)(.*?)(\s*)$} $text match lead text lag if { $mode eq "report" } { # create a key for the text set key [suggest_key $text] lappend report [list $key "[string range [remove_gt_lt $out$lead] end-20 end]$text[string range [remove_gt_lt $lag$s] 0 20]" ] } else { # Write mode if { [llength $keys] != 0} { # Use keys supplied if { [lindex $keys $n] ne "" } { # Use supplied key set write_key [lindex $keys $n] } else { # The supplied key for this index is empty so leave the text untouched set write_key "" } } else { # No keys supplied - autogenerate a key set write_key [suggest_key $text] } if { $write_key ne "" } { # Write tag to file lappend report [list ${write_key} "[string range [remove_gt_lt $out$lead] end-20 end]$text[string range [remove_gt_lt $lag$s] 0 20]" ] append out "$lead<\#${write_key} $text\#>$lag" } else { # Leave the text untouched lappend garbage "[string range [remove_gt_lt $out$lead] end-20 end]$text [string range [remove_gt_lt $lag$s] 0 20]" append out "$lead$text$lag" } } incr n } else { # this was not something we should localize append out $text # but this maybe something that should be localized by hand if { ![string match {*\#*} $text] && ![string is space $text] && [string match -nocase {*[A-Z]*} $text] && ![regexp {^\s*@[^@]+@\s*$} $text] } { # log a comment on it and make a short version of the text that is easier to read regsub -all "\n" $text "" short_text set short_text [string range $short_text 0 40] lappend garbage "$short_text" } } set state tag } elseif { $state eq "tag"} { if {![regexp {(^<[^>]*?>)(.*)$} $s match tag s]} { set s {} } append out $tag set state text } } if { $mode eq "write" } { if { $n > 0 } { # backup original file - fail silently if backup already exists if { [catch {file copy -- $file_name $file_name.orig}] } { } set fp [open $file_name "w"] puts $fp $out close $fp } } return [list $report $garbage] } ad_proc -public lang::util::translator_mode_p {} { Whether translator mode is enabled for this session or not. Translator mode will cause all non-translated messages to appear as a link to a page where the message can be translated, instead of the default "not translated" message. @author Lars Pind (lars@collaboraid.biz) @creation-date October 24, 2002 @return 1 if translator mode is enabled, 0 otherwise. Returns 0 if there is no HTTP connection. @see lang::util::translator_mode_set } { if { [ad_conn isconnected] } { # THere is an HTTP connection - return the client property return [ad_get_client_property -default 0 acs-lang translator_mode_p] } else { # No HTTP connection return 0 } } ad_proc -public lang::util::translator_mode_set { translator_mode_p } { Sets whether translator mode is enabled for this session or not. @author Lars Pind (lars@collaboraid.biz) @creation-date October 24, 2002 @param translator_mode_p 1 if you want translator mode to be enabled, 0 otherwise. @see lang::util::translator_mode_p } { ad_set_client_property acs-lang translator_mode_p $translator_mode_p } ad_proc -private lang::util::record_message_lookup { message_key } { Record a message lookup in translator mode. In translator mode we collect all message lookups at the bottom of the page for translation. @author Peter Marklund } { global __lang_message_lookups # Only makes sense to offer translation list if we're not in en_US locale if { [ad_conn locale] ne "en_US" } { if { ![info exists __lang_message_lookups] } { lappend __lang_message_lookups $message_key } elseif { [lsearch -exact $__lang_message_lookups $message_key] == -1 } { lappend __lang_message_lookups $message_key } } } ad_proc -private lang::util::get_message_lookups {} { Get the list of all message keys looked up so far during the current request. @author Peter Marklund } { global __lang_message_lookups if { [info exists __lang_message_lookups] } { return $__lang_message_lookups } else { return {} } } ad_proc -public lang::util::get_label { locale } { Returns the label (name) of locale @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) @param locale Code for the locale, eg "en_US" @return String containing the label for the locale } { return [db_string select {}] } ad_proc -private lang::util::escape_vars_if_not_null { list } { Processes a list of variables before they are passed into a regexp command. @param list List of variable names } { foreach lm $list { upvar $lm foreign_var if { [exists_and_not_null foreign_var] } { set foreign_var "\[$foreign_var\]" } } } ad_proc -public lang::util::convert_to_i18n { {-locale} {-package_key "acs-translations"} {-message_key ""} {-prefix ""} {-text:required} } { Internationalising of Attributes. This is done by storing the attribute with it's acs-lang key } { # If the package acs-translations is installed do the conversion # magic, otherwise just return the text again. if {[apm_package_id_from_key acs-translations]} { if {$message_key eq ""} { if {$prefix eq ""} { # Having no prefix or message_key is discouraged as it # might have interesting side effects due to double # meanings of the same english string in multiple contexts # but for the time being we should still allow this. set message_key [lang::util::suggest_key $text] } else { set message_key "${prefix}_[lang::util::suggest_key $text]" } } # Register the language keys lang::message::register en_US $package_key $message_key $text if {[exists_and_not_null locale]} { lang::message::register $locale $package_key $message_key $text } return "#${package_key}.${message_key}#" } else { return "$text" } } ad_proc -public lang::util::localize_list_of_lists { {-list} } { localize the elements of a list_of_lists } { set list_output [list] foreach item $list { set item_output [list] foreach part $item { lappend item_output [lang::util::localize $part] } lappend list_output $item_output } return $list_output } ad_proc -public lang::util::get_locale_options { } { Return a list of locales know to the system } { return [util_memoize lang::util::get_locale_options_not_cached] } ad_proc -private lang::util::get_locale_options_not_cached {} { Return all enabled locales in the system in a format suitable for the options argument of a form. @author Lars Pind } { return [db_list_of_lists select_locales {}] } ad_proc -public lang::util::edit_lang_key_url { -message:required {-package_key "acs-translations"} } { } { if { [regsub "^${package_key}." [string trim $message "\#"] {} message_key] } { set edit_url [export_vars -base "[apm_package_url_from_key "acs-lang"]admin/edit-localized-message" { { locale {[ad_conn locale]} } package_key message_key { return_url [ad_return_url] } }] } else { set edit_url "" } return $edit_url } ad_proc -public lang::util::iso6392_from_language { -language:required } { Returns the ISO-639-2 code for a language. @param language Language, using ISO-639 code (2 or 3 chars) @return The ISO-639-2 terminology code for the language } { set iso6392_code "" set lang_len [string length $language] if { $lang_len eq 2 } { # input is iso-639-1 language code set iso6392_code [db_string get_iso2_code_from_iso1 {} -default ""] } elseif { $lang_len eq 3 } { # input is iso-639-2 language code # we check in the table in case the language code is wrong set iso6392_code [db_string get_iso2_code_from_iso2 {} -default ""] } return $iso6392_code } ad_proc -public lang::util::iso6392_from_locale { -locale:required } { Returns the ISO-639-2 code for a locale. @param locale Locale to get the language ISO-639-2 code for @return The ISO-639-2 language code for the locale } { # Don't use string range since 3 digits languages may be used set language [lindex [split $locale "_"] 0] return [lang::util::iso6392_from_language -language $language] } ad_proc -public lang::util::language_label { -language:required } { Returns the ISO-639 label for a language code. @param language Language, using ISO-639 code (2 or 3 chars) @return The ISO-639 label for the language } { set lang_label "" set lang_len [string length $language] if { $lang_len eq 2 } { # input is iso-639-1 language code set lang_label [db_string get_label_from_iso1 {} -default ""] } elseif { $lang_len eq 3 } { # input is iso-639-2 language code # we check in the table in case the language code is wrong set lang_label [db_string get_label_from_iso2 {} -default ""] } return $lang_label } openacs-5.7.0/packages/acs-lang/tcl/lang-util-procs.xql0000644000175000017500000000402111456662500022570 0ustar frankiefrankie select mime_charset from ad_locales where locale = :locale select locale from ad_locales where language = '[db_quote $language]' and enabled_p = 't' and (default_p = 't' or (select count(*) from ad_locales where language = '[db_quote $language]') = 1 ) select label from ad_locales where lower(locale) = lower(:locale) select label, locale from ad_locales order by label select iso_639_2 from language_639_2_codes where iso_639_1 = :language select iso_639_2 from language_639_2_codes where iso_639_2 = :language select label from language_639_2_codes where iso_639_1 = :language select label from language_639_2_codes where iso_639_2 = :language openacs-5.7.0/packages/acs-lang/tcl/lang-message-procs.tcl0000644000175000017500000010414611022567607023227 0ustar frankiefrankie#/packages/acs-lang/tcl/lang-message-procs.tcl ad_library { Routines for displaying web pages in multiple languages

    This is free software distributed under the terms of the GNU Public License. Full text of the license is available from the GNU Project: http://www.fsf.org/copyleft/gpl.html @creation-date 10 September 2000 @author Jeff Davis (davis@xarg.net) @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) @author Peter Marklund (peter@collaboraid.biz) @author Lars Pind (lars@collaboraid.biz) @cvs-id $Id: lang-message-procs.tcl,v 1.51 2008/06/07 20:28:55 donb Exp $ } namespace eval lang::message {} ad_proc -public lang::message::register { {-update_sync:boolean} {-upgrade_status "no_upgrade"} {-conflict:boolean} {-comment ""} locale package_key message_key message } {

    Registers a message for a given locale and package. Inserts the message key into the database if it doesn't already exists. Inserts the message itself in the given locale into the database if it doesn't exist and updates it if it does. Also updates the cache with the message.

    @author Jeff Davis @author Peter Marklund @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) @author Christian Hvid @see _mr @param locale Locale or language of the message. If a language is supplied, the default locale for the language is looked up. @param package_key The package key of the package that the message belongs to. @param message_key The key that identifies the message within the package. @param message The message text @param update_sync If this switch is provided the sync_time of the message will be set to current time. The sync time for a message should only be not null when we know that message in catalog file and db are identical (in sync). This message is then used as a merge base for message catalog upgrades. For more info, see the lang::catalog::upgrade proc. @param upgrade_status Set the upgrade status of the new message to "added", "updated", "deleted". Defaults to "no_upgrade". @param conflict Set this switch if the upgrade represents a conflict between changes made in the database and in catalog files. @see lang::message::lookup @see _ } { # Qualify the locale variable value with a country code if it is # just a language if { [string length $locale] == 2 } { # It seems to be a language (iso codes are 2 characters) # We don't do a more throughout check since this is not # invoked by users. # let's get the default locale for that language set locale [lang::util::default_locale_from_lang $locale] } # Create a globally (across packages) unique key for the cache set key "${package_key}.${message_key}" # Insert the message key into the database if it doesn't # already exist set key_exists_p [db_string message_key_exists_p {}] if { ! $key_exists_p } { if {$locale eq "en_US"} { db_dml insert_message_key {} } else { # Non-default locale # The system will not function correctly if there are keys registered in other locales # than en_US that are not present for en_US. This introduces the inconvenience of having to # register the en_US messages first, but that is manageable set error_message "lang::message::register - refusing to register message for non-en_US locale ${locale}. The message key ${package_key}.${message_key} must be registered in en_US first" ns_log Error $error_message error $error_message } } # Check that non-en_US messages don't have invalid embedded variables # Exclude the special case of datetime configuration messages in acs-lang. An alternative # to treating those messages as a special case here would be to have those messages use # quoted percentage signs (double percentage signs). if { $locale ne "en_US" && ![regexp {^acs-lang\.localization-} $key] } { set embedded_vars [get_embedded_vars $message] set embedded_vars_en_us [get_embedded_vars [lang::message::lookup en_US $key {} {} 0]] set missing_vars [util_get_subset_missing $embedded_vars $embedded_vars_en_us] if { [llength $missing_vars] > 0 } { error "Message key '$key' in locale '$locale' has these embedded variables not present in the en_US locale: [join $missing_vars ","]. Message has not been imported." } } # Build up an array of columns to set array set cols [list] if { $update_sync_p } { set cols(sync_time) [db_map sync_time] } else { set cols(sync_time) "null" } if { [empty_string_p [string trim $message]] } { set cols(message) "null" } else { set cols(message) [db_map message] } set cols(upgrade_status) :upgrade_status set conflict_db_p [db_boolean $conflict_p] set cols(conflict_p) :conflict_db_p # Different logic for update and insert if { [nsv_exists lang_message_$locale $key] } { # Update existing message if the message has changed # For use in audit log call set old_message [nsv_get lang_message_$locale $key] # Peter TODO: should these attributes be cached? lang::message::get \ -package_key $package_key \ -message_key $message_key \ -locale $locale \ -array old_message_array # An updated message is no longer deleted set deleted_p f set cols(deleted_p) :deleted_p # For use in update query set set_clauses [list] foreach col [array names cols] { lappend set_clauses "$col = $cols($col)" } db_transaction { # Update audit log lang::audit::changed_message \ $old_message \ $package_key \ $message_key \ $locale \ $comment \ $old_message_array(deleted_p) \ $old_message_array(sync_time) \ $old_message_array(conflict_p) \ $old_message_array(upgrade_status) # Trying to avoid hitting Oracle bug#2011927 if { [empty_string_p [string trim $message]] } { db_dml lang_message_null_update {} } else { set cols(message) [db_map message] db_dml lang_message_update {} -clobs [list $message] } } } else { # Insert new message set cols(package_key) :package_key set cols(message_key) :message_key set cols(locale) :locale # We wrap this in a catch, so that it still works in the bootstrap-installer where ad_conn user_id will fail. # LARS NOTE: Why not make ad_conn user_id return 0 in the bootstrap-installer? catch { set creation_user [ad_conn user_id] set cols(creation_user) :creation_user } set col_clauses [list] set val_clauses [list] foreach col [array names cols] { lappend col_clauses $col lappend val_clauses $cols($col) } # avoiding bug#2011927 from Oracle. if { [empty_string_p [string trim $message]] } { db_dml lang_message_insert_null_msg {} } else { db_dml lang_message_insert {} -clobs [list $message] } } # Update the message catalog cache nsv_set lang_message_$locale $key $message } ad_proc -public lang::message::delete { -package_key:required -message_key:required -locale:required } { Deletes a message in a particular locale. @author Lars Pind (lars@collaboraid.biz) } { lang::message::edit \ $package_key \ $message_key \ $locale \ [list deleted_p t \ upgrade_status no_upgrade \ conflict_p f \ sync_time [db_null] \ ] } ad_proc -public lang::message::revert { {-package_key:required} {-message_key:required} {-locale:required} } { Revert a message to the last overwritten version of it, i.e. revert the last change. @author Peter Marklund } { set last_overwritten_message [db_string select_last_overwritten_message { select old_message from lang_messages_audit lma1 where lma1.package_key = :package_key and lma1.message_key = :message_key and lma1.locale = :locale and lma1.audit_id = (select max(lma2.audit_id) from lang_messages_audit lma2 where lma2.package_key = lma1.package_key and lma2.message_key = lma1.message_key and lma2.locale = lma1.locale ) }] lang::message::register \ $locale \ $package_key \ $message_key \ $last_overwritten_message } ad_proc -public lang::message::get_element { -package_key:required -message_key:required -locale:required -element:required } { Get value of a single attribute of a message. @param element The name of the attribute that you want. @see lang::message::get @author Peter Marklund } { lang::message::get \ -package_key $package_key \ -message_key $message_key \ -locale $locale \ -array message_array return $message_array($element) } ad_proc -public lang::message::get { -package_key:required -message_key:required -locale:required -array:required } { Get all properties of a message in a particular locale. @param array Name of an array in the caller's namespace into which you want the message properties delivered. @return The array will contain the following entries: message_key, package_key, locale, message, deleted_p, sync_time, conflict_p, upgrade_status, creation_date_ansi, creation_user, key_description. @author Lars Pind (lars@collaboraid.biz) } { upvar 1 $array row db_1row select_message_props { select m.message_key, m.package_key, m.locale, m.message, m.deleted_p, m.sync_time, m.conflict_p, m.upgrade_status, to_char(m.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date_ansi, m.creation_user, k.description as key_description from lang_messages m, lang_message_keys k where m.package_key = :package_key and m.message_key = :message_key and m.locale = :locale and k.package_key = m.package_key and k.message_key = m.message_key } -column_array row } ad_proc -public lang::message::unregister { package_key message_key } { Unregisters a message key, i.e. deletes it along with all its messages from the database and deleted entries in the cache. This proc is useful when installing a package. To delete an individual message, as opposed to the entire key, use lang::message::delete. @see lang::message::delete @author Peter Marklund } { # Deletes messages as well db_dml delete_key { delete from lang_message_keys where message_key = :message_key and package_key = :package_key } remove_from_cache $package_key $message_key } ad_proc -private lang::message::edit { {-update_sync:boolean} package_key message_key locale edit_array_list } { Edit properties (meta data) of a language catalog message, but not the message text itself. To update or add message catalog text, use the lang::message::register proc.

    Implementation note: some of the dynamic sql edit code of this proc was copied from the auth::authority::edit proc and should probably be broken out into a general API.

    @param package_key The package_key of the message to update @param message_key The message_key of the message to update @param locale The locale of the message to update @param edit_array_list An array list holding names of columns and and the values to set them to. Valid keys in this array list are any column names in the lang_messages table. @param update_sync If this switch is provided the sync_time of the message will be updated to current time. If not provided no update to sync_time will be made. If sync_time is contained in the edit_array_list then that value will override the update_sync flag. @author Peter Marklund } { array set edit_array $edit_array_list if { [info exists edit_array(message)] } { error "The proc lang::message::edit was invoked with the message attribute in the edit array. To edit the message text of a message use the lang::message::register proc instead" } if { [info exists edit_array(deleted_p)] } { set edit_array(deleted_p) [db_boolean [template::util::is_true $edit_array(deleted_p)]] # If we are deleting we need to preserve the old message in the audit log if { [template::util::is_true $edit_array(deleted_p)] } { # Peter TODO: should these attributes be cached? lang::message::get \ -package_key $package_key \ -message_key $message_key \ -locale $locale \ -array old_message_array lang::audit::changed_message \ $old_message_array(message) \ $package_key \ $message_key \ $locale \ "deleted" \ $old_message_array(deleted_p) \ $old_message_array(sync_time) \ $old_message_array(conflict_p) \ $old_message_array(upgrade_status) # If we are deleting an en_US message we need to mark the message deleted in all locales if {$locale eq "en_US"} { set message_locales [db_list all_message_locales { select locale from lang_messages where package_key = :package_key and message_key = :message_key and locale <> 'en_US' }] foreach message_locale $message_locales { lang::message::delete \ -package_key $package_key \ -message_key $message_key \ -locale $message_locale } } } } set set_clauses [list] foreach name [array names edit_array] { lappend set_clauses "$name = :$name" set $name $edit_array($name) } if { $update_sync_p } { if { ![info exists edit_array(sync_time)] } { lappend set_clauses [db_map set_sync_time_now] } } if { [llength $set_clauses] > 0 } { set sql " update lang_messages set [join $set_clauses ", "] where package_key = :package_key and message_key = :message_key and locale = :locale " db_dml edit_message $sql } } ad_proc -public lang::message::conflict_count { {-package_key ""} {-locale ""} } { Return the number of messages with conflicts (conflict_p=t) resulting from catalog imports. @param package_key Restrict count to package with this key @param locale Restrict count to messages of this locale @author Peter Marklund } { # Build any package and locale where clauses set where_clauses [list] foreach col {package_key locale} { if { ![empty_string_p [set $col]] } { lappend where_clauses "$col = :${col}" } } set where_clause [ad_decode $where_clauses "" "" "and [join $where_clauses " and "]"] return [db_string conflict_count " select count(*) from lang_messages where conflict_p = 't' $where_clause "] } ad_proc -private lang::message::remove_from_cache { package_key message_key } { Delete a certain message key from the cache for all locales. @author Peter Marklund } { set locales_list [db_list select_system_locales { select locale from ad_locales }] # Delete from the cache for all enabled locales foreach locale $locales_list { set nsv_array lang_message_$locale set nsv_key "${package_key}.${message_key}" if { [nsv_exists $nsv_array $nsv_key] } { nsv_unset $nsv_array $nsv_key } } } ad_proc -private lang::message::get_embedded_vars { message } { Returns a list of embedded substitution variables on the form %varname% in a message. This is useful if you want to check that the variables used in a translated message also appear in the en_US message. If not, there's likely to be a typo. @param message A message with embedded %varname% notation @return The list of variables in the message @author Peter Marklund (peter@collaboraid.biz) @creation-date 12 November 2002 } { set variables_list [list] set remaining_message $message while { [regexp [embedded_vars_regexp] $remaining_message \ match before_percent percent_match remaining_message] } { if {$percent_match eq "%%"} { # A quoted percentage sign - ignore continue } else { lappend variables_list [string range $percent_match 1 end-1] } } return $variables_list } ad_proc -private lang::message::format { localized_message {value_array_list {}} {upvar_level 3} } { Substitute all occurencies of %array_key% in the given localized message with the value from a lookup in the value_array_list with array_key (what's between the percentage sings). If value_array_list is not provided then attempt to fetch variable values the number of levels up given by upvar_level (defaults to 3 because this proc is typically invoked from the underscore lookup proc). Here is an example: set localized_message "The %animal% jumped across the %barrier%. About 50% of the time, he stumbled, or maybe it was %%20 %times%." set value_list { animal "frog" barrier "fence" } puts "[format $localized_message $value_list]" The output from the example is: The frog jumped across the fence. About 50% of the time, he stumbled, or maybe it was %20 %times%. } { array set value_array $value_array_list set value_array_keys [array names value_array] set remaining_message $localized_message set formated_message "" while { [regexp [embedded_vars_regexp] $remaining_message match before_percent percent_match remaining_message] } { append formated_message $before_percent if {$percent_match eq "%%"} { # A quoted percent sign append formated_message "%" } else { set variable_string [string range $percent_match 1 end-1] if { [llength $value_array_list] > 0 } { # A substitution list is provided, the key should be in there if { [lsearch -exact $value_array_keys $variable_string] == -1 } { ns_log Warning "lang::message::format: The value_array_list \"$value_array_list\" does not contain the variable name $variable_string found in the message: $localized_message" # There is no value available to do the substitution with # so don't substitute at all append formated_message $percent_match } else { # Do the substitution append formated_message [lindex [array get value_array $variable_string] 1] } } else { regexp {^([^.]+)(?:\.([^.]+))?$} $variable_string match variable_name array_key # No substitution list provided - attempt to fetch variable value # from scope calling lang::message::lookup upvar $upvar_level $variable_name local_variable if { [info exists local_variable] } { if { ![exists_and_not_null array_key] } { # Normal Tcl variable append formated_message $local_variable } else { # Array variable append formated_message $local_variable($array_key) } } else { error "Message contains a variable named '$variable_name' which doesn't exist in the caller's environment: message $localized_message" } } } } # Append text after the last match append formated_message $remaining_message return $formated_message } ad_proc -private lang::message::embedded_vars_regexp {} { The regexp pattern used to loop over variables embedded in message catalog texts. @author Peter Marklund (peter@collaboraid.biz) @creation-date 12 November 2002 } { return {^(.*?)(%%|%[-a-zA-Z0-9_:\.]+(?:;noquote)?%)(.*)$} } ad_proc -public lang::message::message_exists_p { locale key } { Return 1 if message exists in given locale, 0 otherwise. @author Peter Marklund } { # Make sure messages are in the cache cache return [nsv_exists lang_message_$locale $key] } ad_proc -public lang::message::lookup { locale key {default "TRANSLATION MISSING"} {substitution_list {}} {upvar_level 1} {translator_mode_p 1} } { This proc is normally accessed through the _ procedure. Returns a translated string for the given locale and message key. If the user is a translator, inserts tags to link to the translator interface. This allows a translator to work from the context of a web page. Messages will have %name% replaced with variables either from substitution_list, if present, or from the caller's namespace (or upvar_level's namespace). Set upvar_level to 0 and substitution_list empty to prevent substitution from happening Note that this proc does not use named parameters, because named parameters are relatively slow, and this is going to get called a whole lot on each request. @param locale Locale (e.g., "en_US") or language (e.g., "en") string. If locale is the empty string ad_conn locale will be used if we are in an HTTP connection, otherwise the system locale (SiteWideLocale) will be used. @param key Unique identifier for this message. Will be the same identifier for each locale. All keys belong to a certain package and should be prefixed with the package key of that package on the format package_key.message_key (the dot is reserved for separating the package key, the rest of the key should contain only alpha-numeric characters and underscores). If the key does not belong to any particular package it should not contain a dot. A lookup is always attempted with the exact key given to this proc. @param default Text to return if there is no message in the message catalog for the given locale. This argument is optional. If this argument is not provided or is the empty string then the text returned will be TRANSLATION MISSING - $key. @param substitution_list A list of values to substitute into the message. This argument should only be given for certain messages that contain place holders (on the syntax %var_name%) for embedding variable values, see lang::message::format. If this list is not provided and the message has embedded variables, then the variable values can be fetched with upvar from the scope calling this proc (see upvar_level). @param upvar_level If there are embedded variables and no substitution list provided, this parameter specifies how many levels up to fetch the values of the variables in the message. The default is 1. @param translator_mode_p Set to 0 if you do not want this call to honor translator mode. Useful if you're not using this message in the page itself, but e.g. for localization data or for the list of messages on the page. @author Jeff Davis (davis@xarg.net) @author Henry Minsky (hqm@arsdigita.com) @author Peter Marklund (peter@collaboraid.biz) @see _ @see lang::message::register @return A localized piece of text. } { # Make sure messages are in the cache cache # Make sure that a default of "" is transformed into Translation Missing # As per discussion on IRC on 2008-03-06 if { $default eq ""} { set default "TRANSLATION MISSING" } if { $locale eq "" } { # No locale provided if { [ad_conn isconnected] } { # We are in an HTTP connection (request) so use that locale set locale [ad_conn locale] } else { # There is no HTTP connection - resort to system locale set locale [lang::system::locale] } } elseif { [string length $locale] == 2 } { # Only language provided, let's get the default locale for this language set default_locale [lang::util::default_locale_from_lang $locale] if { $default_locale eq "" } { error "Could not look up locale for language $locale" } else { set locale $default_locale } } # We remember the passed-in locale, because we want the translator mode to show which # messages have been translated, and which have not. set org_locale $locale # Trying locale directly if { [message_exists_p $locale $key] } { set message [nsv_get lang_message_$locale $key] } else { # Trying default locale for language set language [lindex [split $locale "_"] 0] set locale [lang::util::default_locale_from_lang $language] if { [message_exists_p $locale $key] } { set message [nsv_get lang_message_$locale $key] } else { # Trying system locale for package (or site-wide) set locale [lang::system::locale] if { [message_exists_p $locale $key] } { set message [nsv_get lang_message_$locale $key] } else { # Trying site-wide system locale set locale [lang::system::locale -site_wide] if { [message_exists_p $locale $key] } { set message [nsv_get lang_message_$locale $key] } else { # Resorting to en_US set locale "en_US" if { [message_exists_p $locale $key] } { set message [nsv_get lang_message_$locale $key] } else { if {"TRANSLATION MISSING" != $default} { set message $default } else { if {[string match "acs-translations.*" $key]} { ns_log Debug "lang::message::lookup: Key '$key' does not exist in en_US" set message "MESSAGE KEY MISSING: '$key'" } else { ns_log Error "lang::message::lookup: Key '$key' does not exist in en_US" set message "MESSAGE KEY MISSING: '$key'" } } } } } } } # Do any variable substitutions (interpolation of variables) # Set upvar_level to 0 and substitution_list empty to prevent substitution from happening if { [llength $substitution_list] > 0 || ($upvar_level >= 1 && [string first "%" $message] != -1) } { set message [lang::message::format $message $substitution_list [expr {$upvar_level + 1}]] } if { [lang::util::translator_mode_p] } { # Translator mode - record the message lookup lang::util::record_message_lookup $key if { $translator_mode_p } { global message_key_num if { ![info exists message_key_num] } { set message_key_num 1 } else { incr message_key_num } # encode the key in the page set message "$message\x002(\x001$key\x001)\x002" } } return $message } ad_proc -private lang::message::translate { msg locale } { Translates an English string into a different language using Babelfish. Warning - october 2002: This is broken. @author Henry Minsky (hqm@mit.edu) @param msg String to translate @param lang Abbreviation for lang in which to translate string @return Translated string } { set lang [string range $locale 0 2] set marker "XXYYZZXX. " set qmsg "$marker $msg" set url "http://babel.altavista.com/translate.dyn?doit=done&BabelFishFrontPage=yes&bblType=urltext&url=" set babel_result [ns_httpget "$url&lp=$lang&urltext=[ns_urlencode $qmsg]"] set result_pattern "$marker (\[^<\]*)" if {[regexp -nocase $result_pattern $babel_result ignore msg_tr]} { regsub "$marker." $msg_tr "" msg_tr return [string trim $msg_tr] } else { error "Babelfish translation error" } } ad_proc -private lang::message::cache { {-package_key {}} } { Loads the entire message catalog from the database into the cache. } { # We segregate messages by language. It might reduce contention # if we segregage instead by package. Check for problems with ns_info locks. # LARS TODO: Use a mutex if { ![nsv_exists lang_message_cache executed_p] } { nsv_set lang_message_cache executed_p 1 if { $package_key eq "" } { set package_where_clause "" } else { set package_where_clause "where package_key = :package_key" } set i 0 db_foreach select_locale_keys {} { nsv_set lang_message_$locale "${package_key}.${message_key}" $message incr i } db_release_unused_handles ns_log Notice "lang::message::cache - Initialized message cache with $i rows from database" } } ##### # # Shorthand notation procs _ and _mr # ##### ad_proc -public _mr { locale key message } { Registers a message in a given locale or language. Inserts the message into the table lang_messages if it does not exist and updates if it does. For backward compability - it assumes that the key is the concatenation of message and package key like this: package_key.message_key @author Jeff Davis (davis@xarg.net) @param locale Abbreviation for language of the message or the locale. @param key Unique identifier for this message. Will be the same identifier for each language @param message Text of the message @see lang::message::register } { regexp {^([^\.]+)\.([^\.]+)$} $key match package_key message_key return [lang::message::register $locale $package_key $message_key $message] } ad_proc -public _ { key {substitution_list {}} } { Short hand proc that invokes the lang::message::lookup proc. Returns a localized text from the message catalog with the locale ad_conn locale if invoked within a request, or the system locale otherwise.

    Example:

        set the_url [export_vars -base "[ad_conn package_url]view" { item_id }]
        set body [_ my-package.lt_To_view_this_item [list item_url $the_url]]
    
    If the message value is "To view this item, please click here: %item_url%", then the URL will be insert into the message. @param key Unique identifier for this message. Will be the same identifier for each locale. The key is on the format package_key.message_key @param substitution_list A list of values to substitute into the message on the form { name value name value ... }. This argument should only be given for certain messages that contain place holders (on the syntax %1:pretty_name%, %2:another_pretty_name% etc) for embedding variable values. If the message contains variables that should be interpolated and this argument is not provided then upvar will be used to fetch the variable values. @return A localized message @author Jeff Davis (davis@xarg.net) @author Peter Marklund (peter@collaboraid.biz) @author Christian Hvid (chvid@collaboraid.biz) @see lang::message::lookup @see lang::message::format } { return [lang::message::lookup "" $key "TRANSLATION MISSING" $substitution_list 2] } ##### # # Backwards compatibility procs # ##### ad_proc -public lang::message::update_description { {-package_key:required} {-message_key:required} {-description:required} } { @author Simon Carstensen @creation_date 2003-08-12 } { if { [empty_string_p [string trim $description]] } { db_dml update_description_insert_null {} } else { db_dml update_description {} -clobs [list $description] } } openacs-5.7.0/packages/acs-lang/tcl/lang-message-procs.xql0000644000175000017500000000341707766162051023254 0ustar frankiefrankie select count(*) from lang_message_keys where package_key = :package_key and message_key = :message_key select count(*) from lang_messages where package_key = :package_key and message_key = :message_key insert into lang_message_keys (message_key, package_key) values (:message_key, :package_key) update lang_messages set [join $set_clauses ", "] where locale = :locale and package_key = :package_key and message_key = :message_key insert into lang_messages ([join $col_clauses ", "]) values ([join $val_clauses ", "]) select locale, package_key, message_key, message from lang_messages $package_where_clause update lang_message_keys set description = null where message_key = :message_key and package_key = :package_key openacs-5.7.0/packages/acs-lang/tcl/lang-catalog-procs.tcl0000644000175000017500000012562611164474552023226 0ustar frankiefrankie#/packages/acs-lang/tcl/lang-catalog-procs.tcl ad_library {

    Routines for importing/exporting messages from/to XML message catalog files. Every OpenACS package has one message catalog file for each locale (language and region) that its UI supports. Importing of messages means reading the messages from XML catalog files and storing them in the database. Exporting of messages refers to the opposite process. The key procedures in this library are:

    • lang::catalog::import - Import all catalog files on the system into the database. Can be restricted to only import from one package and only certain locales.
    • lang::catalog::import_from_file - Import from a single catalog file
    • lang::catalog::export - Export all messages in the database to catalog files. Can be restricted to only export from one package and only certain locales.
    • lang::catalog::export_to_file - Export messages to a single file

    @creation-date 10 September 2000 @author Jeff Davis @author Peter Marklund (peter@collaboraid.biz) @author Lars Pind (lars@collaboraid.biz) @cvs-id $Id: lang-catalog-procs.tcl,v 1.49 2009/03/31 20:13:30 emmar Exp $ } namespace eval lang::catalog {} ################## # # Helper procs # ################## ad_proc -private lang::catalog::default_charset_if_unsupported { charset } { Will return the system default charset and issue a warning in the log file if the given charset is not supported by tcl. Otherwise the given charset is simply returned. @author Jeff Davis @author Peter Marklund (peter@collaboraid.biz) } { set ns_charsets [concat [ns_charsets] [encoding names]] # Do case insensitive matching if {[lsearch -regexp $ns_charsets "(?i)^${charset}\$"] < 0} { #set default_charset [encoding system] # LARS: Default to utf-8 set default_charset utf-8 ns_log Warning "charset $charset not supported by tcl, assuming $default_charset" set charset_to_use $default_charset } else { set charset_to_use $charset } return $charset_to_use } ad_proc -private lang::catalog::get_required_xml_attribute { element attribute } { Return the value of the given attribute and raise an error if the value is missing or empty. @author Peter Marklund (peter@collaboraid.biz) } { set value [xml_node_get_attribute $element $attribute] if { $value eq "" } { error "Required attribute \"$attribute\" missing from <[xml_node_get_name $element]>" } return $value } ad_proc -private lang::catalog::all_messages_for_package_and_locale { package_key locale } { Set a multirow with name all_messages locally in the callers scope with the columns message_key and message for all message keys that do not have an upgrade status of deleted. @author Peter Marklund } { db_multirow -local -upvar_level 2 all_messages get_messages {} } ad_proc -private lang::catalog::package_catalog_dir { package_key } { Return the catalog directory of the given package. @author Peter Marklund (peter@collaboraid.biz) @creation-date 18 October 2002 } { return "[acs_package_root_dir $package_key]/catalog" } ad_proc -private lang::catalog::is_upgrade_backup_file { file_path } { Given a file path return 1 if the path represents a file with messages backed up from message catalog upgrade. @author Peter Marklund } { array set filename_info [apm_parse_catalog_path $file_path] if { [array size filename_info] == 0 } { # Parsing failed set return_value 0 } else { # Parsing succeeded set prefix $filename_info(prefix) if { [regexp "^[message_backup_file_prefix]" $prefix match] } { # The prefix looks right set return_value 1 } else { # Catalog file with unknown prefix ns_log Warning "The file $file_path has unknown prefix $prefix" set return_value 0 } } return $return_value } ad_proc -private lang::catalog::message_backup_file_prefix {} { The prefix used for files where we store old messages that were overwritten during message catalog upgrade. } { return "overwritten_messages_upgrade_" } ad_proc -private lang::catalog::assert_catalog_file { catalog_file_path } { Throws an error if the given path is not valid for a catalog file. @see apm_is_catalog_file @author Peter Marklund } { if { ![apm_is_catalog_file $catalog_file_path] } { error "lang::catalog::assert_filename_format - Invalid message catalog path, cannot extract package_key, locale, and charset from file path $catalog_file_path" } } ad_proc -private lang::catalog::package_has_files_in_locale_p {package_key locale} { Return 1 if the given package has any catalog files for the given locale and 0 otherwise. @author Peter Marklund } { if { [catch {glob [package_catalog_dir $package_key]/$package_key.${locale}.*}] } { set has_file_in_locale_p 0 } else { set has_file_in_locale_p 1 } return $has_file_in_locale_p } ad_proc -private lang::catalog::get_catalog_file_path { {-backup_from_version ""} {-backup_to_version ""} {-package_key:required} {-locale:required} {-charset ""} } { Get the full path of the catalog file for a given package, and locale. @param charset Should normally not be provided. Will force the charset to a certain value. If not provided an appropriate charset to write the locale in will be used. @see apm_parse_catalog_path @see lang::catalog::package_has_files_in_locale_p @author Peter Marklund } { set catalog_dir [package_catalog_dir $package_key] if { $charset ne "" } { set file_charset $charset } else { # We had problems storing digits in ISO-8859-6 so we decided # to use UTF-8 for all files except for locales that use ISO-8859-1. The reason we are making # ISO-8859-1 an exception is that some developers may make the shortcut of editing # the en_US catalog files directly to add keys and they might mess up the # utf-8 encoding of the files when doing so. set system_charset [lang::util::charset_for_locale $locale] set file_charset [ad_decode $system_charset "ISO-8859-1" $system_charset utf-8] } set message_backup_prefix "" if { $backup_from_version ne "" } { set message_backup_prefix "[message_backup_file_prefix]${backup_from_version}-${backup_to_version}_" } set filename "${message_backup_prefix}${package_key}.${locale}.${file_charset}.xml" set file_path "[package_catalog_dir $package_key]/$filename" return $file_path } ad_proc -private lang::catalog::get_catalog_files { package_key } { Return the full paths of all message catalog files of the given package. @param package_key The key of the package to return catalog file paths for @return A list of catalog file paths @author Peter Marklund } { set catalog_paths [list] set catalog_dir [lang::catalog::package_catalog_dir $package_key] foreach file_path [glob -nocomplain "$catalog_dir/*"] { if { [apm_is_catalog_file $file_path] } { lappend catalog_paths $file_path } } return $catalog_paths } ad_proc -private lang::catalog::messages_in_db { {-package_key:required} {-locale:required} } { Return a list of all messages for a certain package and locale. @return An array list with message keys as keys and messages as values. @see lang::catalog::all_messages_for_package_and_locale @author Peter Marklund } { set message_list [list] all_messages_for_package_and_locale $package_key $locale template::util::multirow_foreach all_messages { lappend message_list @all_messages.message_key@ @all_messages.message@ } return $message_list } ad_proc -private lang::catalog::last_sync_messages { {-package_key:required} {-locale:required} } { For a certain package, and locale, return the messages in the database the last time catalog files and db were in sync. This is the message that we use as merge base during message catalog upgrades. @return An array list with message keys as keys and messages as values. @author Peter Marklund } { set message_list [list] db_foreach last_sync_messages {} { if { ![template::util::is_true $deleted_p] } { lappend message_list $message_key $message } } return $message_list } ad_proc -private lang::catalog::uninitialized_packages {} { Return a list of keys for installed and enabled packages that do not have any message keys associated with them. This would suggest that either the package is not internationalized, or we have not yet imported the message keys for the package. @author Peter Marklund } { return [db_list select_uninitialized {}] } ################## # # Exporting procs # ################## ad_proc -private lang::catalog::export_to_file { {-descriptions_list ""} file_path messages_list } { Export messages for a certain locale and package from the database to a given XML catalog file. If the catalog file already exists it will be backed up to a file with the same name but the extension .orig added to it. If there is an old backup file no new backup is done. @param file_path The path of the catalog file to write messages to. The filename needs to be parseable by apm_parse_catalog_path. The file and the catalog directory will be created if they don't exist. @param message_list A list with message keys on even indices followed by corresponding messages on odd indices. @author Peter Marklund (peter@collaboraid.biz) } { # Extract package_key, locale, and charset from the file path array set filename_info [apm_parse_catalog_path $file_path] # Check that the filename is parsable. We are not requiring any particular directory though if { [array size filename_info] == 0 } { error "Could not parse package_key, locale, and charset from filename of file $file_path" } # Put the messages and descriptions in an array so it's easier to access them array set messages_array $messages_list array set descriptions_array $descriptions_list # Sort the keys so that it's easier to manually read and edit the catalog files set message_key_list [lsort -dictionary [array names messages_array]] # Create the catalog directory if it doesn't exist set catalog_dir [package_catalog_dir $filename_info(package_key)] if { ![file isdirectory $catalog_dir] } { ns_log Notice "Creating new catalog directory $catalog_dir" file mkdir $catalog_dir } # Create a backup file first if a file already exists set backup_path "${file_path}.orig" if { [file exists $file_path] } { ns_log Notice "Creating backup catalog file $backup_path" file copy -force -- $file_path $backup_path } # Since the output charset, and thus the filename, may have changed since # last time that we wrote the catalog file we remove old files with the same locale foreach old_catalog_file [get_catalog_files $filename_info(package_key)] { # Parse locale from filename array set old_filename_info [apm_parse_catalog_path $old_catalog_file] if {$old_filename_info(locale) eq $filename_info(locale)} { file delete $old_catalog_file } } # Open the catalog file for writing, truncate if it exists set file_encoding [ns_encodingforcharset [default_charset_if_unsupported $filename_info(charset)]] set catalog_file_id [open $file_path w] fconfigure $catalog_file_id -encoding $file_encoding # Open the root node of the document puts $catalog_file_id " " # Loop over and write the messages to the file set message_count "0" foreach message_key $message_key_list { puts $catalog_file_id " [ad_quotehtml $messages_array($message_key)]" if { [exists_and_not_null descriptions_array($message_key)] && $filename_info(locale) eq "en_US" } { puts $catalog_file_id " [ad_quotehtml $descriptions_array($message_key)]\n" } incr message_count } # Close the root node and close the file puts $catalog_file_id "" close $catalog_file_id ns_log Notice "Wrote $message_count messages to file $file_path with encoding $file_encoding" } ad_proc -public lang::catalog::export { {-package_key {}} {-locales {}} } { Exports I18N messages from the database to XML catalog files. By default exports messages for all enabled packages and all enabled locales on the system. Can be restricted to export only for a certain package and/or a list of locales. @param package_key A key of a package to restrict the export to @param locales A list of locales to restrict the export to @author Peter Marklund } { if { $package_key ne "" } { set package_key_list $package_key } else { set package_key_list [apm_enabled_packages] } foreach package_key $package_key_list { # We do not want to export acs-translations. This usually is a very bad idea as the object_ids are different from site to site. if {$package_key ne "acs-translations" } { # Loop over all locales that the package has messages in # and write a catalog file for each such locale db_foreach get_locales_for_package {} { # If we are only exporting certain locales and this is not one of them - continue if { [llength $locales] > 0 && [lsearch -exact $locales $locale] == -1 } { continue } # Get messages and descriptions for the locale set messages_list [list] set descriptions_list [list] all_messages_for_package_and_locale $package_key $locale template::util::multirow_foreach all_messages { lappend messages_list @all_messages.message_key@ @all_messages.message@ lappend descriptions_list @all_messages.message_key@ @all_messages.description@ } set catalog_file_path [get_catalog_file_path \ -package_key $package_key \ -locale $locale] export_to_file -descriptions_list $descriptions_list $catalog_file_path $messages_list # Messages exported to file are in sync with file db_dml update_sync_time {} } } } } ################## # # Importing procs # ################## ad_proc -private lang::catalog::read_file { catalog_filename } { Returns the contents of the given catalog file as a string reading the file with the charset given in the filename. @param catalog_file_name The full path of the catalog file to read. The basename of the file should be on the form package_key.locale.charset.ending where ending is either cat or xml (i.e. dotlrn.en_US.iso-8859-1.xml or dotlrn.en_US.iso-8859-1.cat). The cat ending is for the deprecated tcl-based catalog files. @author Jeff Davis @author Peter Marklund (peter@collaboraid.biz) } { if {![regexp {/([^/]*)\.([^/]*)\.(?:xml|cat)$} $catalog_filename match base msg_encoding]} { ns_log Warning "Charset info missing in filename assuming $catalog_filename is iso-8859-1" set msg_encoding iso-8859-1 } set msg_encoding [default_charset_if_unsupported $msg_encoding] ns_log Notice "reading $catalog_filename in $msg_encoding" set in [open $catalog_filename] fconfigure $in -encoding [ns_encodingforcharset $msg_encoding] set catalog_file_contents [read $in] close $in return $catalog_file_contents } ad_proc -private lang::catalog::parse { catalog_file_contents } { Parse the given catalog file xml contents and return the data as an array. The array will contain the following keys:
          package_key
          locale
          charset
          messages    - An array-list with message keys as keys and the message texts as values.
          descriptions - An array-list with message keys as keys and the descriptions as values.
        
    @author Peter Marklund (peter@collaboraid.biz) @author Simon Carstensen (simon@collaboraid.biz) } { # Check arguments if { $catalog_file_contents eq "" } { error "lang::catalog::parse the catalog_file_contents arguments is the empty string" } # The names of xml tags and attributes set MESSAGE_CATALOG_TAG "message_catalog" set PACKAGE_KEY_ATTR "package_key" set LOCALE_ATTR "locale" set CHARSET_ATTR "charset" set MESSAGE_TAG "msg" set DESCRIPTION_TAG "description" set KEY_ATTR "key" # Initialize the array to return array set msg_catalog_array {} # Parse the xml document set tree [xml_parse -persist $catalog_file_contents] # Get the message catalog root node set root_node [xml_doc_get_first_node $tree] if { ![string equal [xml_node_get_name $root_node] ${MESSAGE_CATALOG_TAG}] } { error "lang::catalog_parse: Could not find root node ${MESSAGE_CATALOG_TAG}" } # Set the message catalog root level attributes set msg_catalog_array(package_key) [get_required_xml_attribute $root_node ${PACKAGE_KEY_ATTR}] set msg_catalog_array(locale) [get_required_xml_attribute $root_node ${LOCALE_ATTR}] set msg_catalog_array(charset) [get_required_xml_attribute $root_node ${CHARSET_ATTR}] # Loop over the keys and message texts set message_node_list [xml_node_get_children_by_name $root_node ${MESSAGE_TAG}] array set key_text_array {} foreach message_node $message_node_list { set key [get_required_xml_attribute $message_node ${KEY_ATTR}] set text [xml_node_get_content $message_node ] set key_text_array($key) $text } # Add the keys and the texts to the messages array set msg_catalog_array(messages) [array get key_text_array] # Loop over the keys and descriptions set description_node_list [xml_node_get_children_by_name $root_node ${DESCRIPTION_TAG}] array set key_description_array {} foreach description_node $description_node_list { set key [get_required_xml_attribute $description_node ${KEY_ATTR}] set description [xml_node_get_content $description_node ] set key_description_array($key) $description } # Add the keys and the texts to the descriptions array set msg_catalog_array(descriptions) [array get key_description_array] return [array get msg_catalog_array] } ad_proc -private lang::catalog::import_from_file { file_path } {

    Import messages for a certain locale and package from a given XML catalog file to the database. This procedure invokes lang::catalog::parse to read the catalog file and lang::message::register to register the messages with the system (updates database and cache).

    The import should be considered an upgrade if the package has had messages imported before. In this case the proc lang::catalog::import_messages will be used to register the new messages with the system and handle the upgrade logic (a merge with what's in the database).

    @param file_path The absolute path of the XML file to import messages from. The path must be on valid format, see apm_is_catalog_file @return An array list containing the number of messages processed, number of messages added, number of messages updated, and the number of messages deleted by the import. The keys of the array list are processed, added, updated, and deleted. @see lang::catalog::parse @see lang::message::register @see lang::catalog::import_messages @author Peter Marklund } { # Check arguments assert_catalog_file $file_path # Parse the catalog file and put the information in an array # LARS NOTE: Change parse to take three array-names, catalog, messages, descriptions, and use upvar array set catalog_array [parse [read_file $file_path]] # Extract package_key, locale, and charset from the file path array set filename_info [apm_parse_catalog_path $file_path] # Setting these variables to improve readability of code in this proc set package_key $filename_info(package_key) set locale $filename_info(locale) set charset $filename_info(charset) # Compare xml package_key with file path package_key - abort if there is a mismatch if { $package_key ne $catalog_array(package_key) } { error "the package_key $catalog_array(package_key) in the file $file_path does not match the package_key $package_key in the filesystem" } # Get the messages array, and the list of message keys to iterate over array set messages_array [lindex [array get catalog_array messages] 1] set messages_array_names [array names messages_array] # Get the descriptions array array set descriptions_array [lindex [array get catalog_array descriptions] 1] ns_log Notice "Loading messages in file $file_path" # Register messages array set message_count [lang::catalog::import_messages \ -file_messages_list [array get messages_array] \ -package_key $package_key \ -locale $locale] # Register descriptions foreach message_key $messages_array_names { if { [info exists descriptions_array($message_key)] } { with_catch errmsg { lang::message::update_description \ -package_key $catalog_array(package_key) \ -message_key $message_key \ -description $descriptions_array($message_key) } { global errorInfo ns_log Error "Registering description for key ${package_key}.${message_key} in locale $locale failed with error message \"$errmsg\"\n\n$errorInfo" } } } return [array get message_count] } ad_proc -private lang::catalog::import_messages { {-file_messages_list:required} {-package_key:required} {-locale:required} } {

    Import a given set of messages from a catalog file to the database for a certain package and locale. If we already have messages in the db for the given package and locale then a merge between the database messages and the file messages will be performed.

    Foreach message to import, the base messages for the merge is the messages in the db from the last time db and catalog file were in sync for the corresponding message key. The first such sync point is the initial import of a message. After that, any export of messages to the file system will be a sync point. Also, after an upgrade, a large number of the resulting messages in the db will be identical to those in the file (the file messages take precedence on conflict) and those messages will also be sync points. A message being in sync between db and file is indicated by the lang_message.sync_time column being set to a not null value.

    This proc is idempotent which means that it can be executed multiple times and after the first time it's been executed it won't have any effect on the db. See the corresponding acs-automated-testing test case called upgrade.

    What follows below is a description of the logic of the proc in terms of its input, the cases considered, and the logical actions taken for each case.

    There are three sets of keys, file, db, and base keys. For each key in the union of these keys there are three messages that can exist: the file message, the db message, and the base message. The base message serves as the base for the merge. We will distinguish all the different permutations of each of the three messages existing or not, and all permutations of the messages being different from eachother. We don't distinguish how two messages are different, only whether they are different or not. In total that gives us 14 cases (permutations) to consider.

        *** Exactly one of messages exists (3 cases):
    
        1. base message (deleted in file and db). upgrade_action=none, conflict_p=f
    
        2. db message (added in db). upgrade_action=none, conflict_p=f
    
        3. file message (added in file). upgrade_action=add, conflict_p=f
    
        *** Exactly two of the messages exist (6 cases):
    
        - Base and file message (db message deleted):
          4. Differ (conflicting change). upgrade_action=resurrect, conflict_p=t
          5. No difference (no conflicting change). upgrade_action=none, conflict_p=f
    
        - Base and db message (file message deleted):
          6. Differ (conflicting change): upgrade_action=delete, conflict_p=t
          7. No difference (no conflicting change): upgrade_action=delete, conflict_p=f
    
        - File and db message (message added in both db and file):
          8. Differ (conflicting change). upgrade_action=update, conflict_p=t
          9. No difference (identical changes). upgrade_action=none, conflict_p=f
    
        *** All three messages exist (5 cases):
    
        10. All the same. upgrade_action=none, conflict_p=f
    
        11. File and base the same. upgrade_action=none, conflict_p=f
    
        12. DB and base the same. upgrade_action=update, conflict_p=f
    
        13. File and DB the same. upgrade_action=none, conflict_p=f
    
        14. All different. upgrade_action=update, conflict_p=t
        
    @param file_messages_list An array list with message keys as keys and the message of those keys as values, i.e. (key, value, key, value, ...) @param package_key The package_key for the messages. @param locale The locale of the messages. @return An array list containing the number of messages processed, number of messages added, number of messages updated, number of messages deleted by the import, and a list of errors produced. The keys of the array list are processed, added, updated, and deleted, and errors. @author Peter Marklund @author Lars Pind } { set message_count(processed) 0 set message_count(added) 0 set message_count(updated) 0 set message_count(deleted) 0 set message_count(errors) [list] # Form arrays for all three sets of messages array set file_messages $file_messages_list array set db_messages [lang::catalog::messages_in_db \ -package_key $package_key \ -locale $locale] array set base_messages [lang::catalog::last_sync_messages \ -package_key $package_key \ -locale $locale] foreach arrname { base_messages file_messages db_messages } { set dummy [list] foreach elm [lsort [array names $arrname]] { lappend dummy "$elm=[set ${arrname}($elm)]" } ns_log Debug "lang::catalog::import_messages - $arrname: $dummy" } # Remember each time we've processed a key, so we don't process it twice array set message_key_processed_p [list] # Loop over the union of import and db keys. foreach message_key [lsort [concat [array names db_messages] [array names file_messages] [array names base_messages]]] { if { [info exists message_key_processed_p($message_key)] } { continue } set message_key_processed_p($message_key) 1 ########################################### # # Figure out how db and file messages have changed with regards to the base message # ########################################### # The variables indicate how the db and file messages have changed # from the base message. Valid values are: none, add, update, delete set db_change "none" set file_change "none" if { [info exists base_messages($message_key)] } { # The base message exists if { [info exists db_messages($message_key)] } { # db message exists if { $db_messages($message_key) ne $base_messages($message_key) } { # db message and base message differ set db_change "update" } } else { # db message does not exist set db_change "delete" } if { [info exists file_messages($message_key)] } { # file message exists if { $file_messages($message_key) ne $base_messages($message_key) } { # file message and base message differ set file_change "update" } } else { # file message does not exist set file_change "delete" } } else { # The base message does not exist if { [info exists db_messages($message_key)] } { # db message exists set db_change "add" } if { [info exists file_messages($message_key)] } { # file message exists set file_change "add" } } ########################################### # # Based on the change in file and db messages, # and based on whether file and db messages differ, decide # which upgrade actions to take # ########################################### # Default values cover the cases 2, 5, 9, 10, 11, 13 set import_case "in 2, 5, 9, 10, 11, 13" set upgrade_status "no_upgrade" set conflict_p "f" switch $db_change { none { switch $file_change { none {} add { # case 3 set import_case 3 # add message from file to db set upgrade_status "added" } update { # case 12 set import_case 12 # update db with file message set upgrade_status "updated" } delete { # case 7 set import_case 7 # mark message in db deleted set upgrade_status "deleted" } } } add { switch $file_change { none {} add { if { $db_messages($message_key) ne $file_messages($message_key) } { # case 8 set import_case 8 # differing additions in db and file set upgrade_status "updated" set conflict_p "t" } } } } update { switch $file_change { none {} update { if { $db_messages($message_key) ne $file_messages($message_key) } { # case 14 set import_case 14 # differing updates in file and db set upgrade_status "updated" set conflict_p "t" } } delete { # case 6 set import_case 6 # deletion in file but update in db set upgrade_status "deleted" set conflict_p "t" } } } delete { switch $file_change { none {} update { # case 4 set import_case 4 # deletion in db but update in file set upgrade_status "added" ;# resurrect set conflict_p "t" } delete { # case 1 set import_case 1 # deletion in both db and file # no status change, no conflict # sync time should be updated below } } } } ########################################### # # Execute upgrade actions # ########################################### # For certain messages we need to move the sync point so that we have a current base for the next upgrade. if { $db_change eq "none" || $file_change ne "none" } { # If there is no db change then any change in the file will be reflected in # db (file takes precedence) and file and db are identical. # Also, regardless of what's happened in db, if # there has been a change in the file then that change will take effect in # the db and file and db are again identical (in sync). set update_sync_p 1 } else { set update_sync_p 0 } # Store a new message in the database if we are adding or updating set error_p 0 if { $upgrade_status eq "added" || $upgrade_status eq "updated" } { ns_log Debug "lang::catalog::import_messages - invoking lang::message::register with import_case=\"$import_case\" -update_sync=$update_sync_p $message_key $upgrade_status $conflict_p" if { [catch {lang::message::register \ -update_sync \ -upgrade_status $upgrade_status \ -conflict=$conflict_p \ $locale \ $package_key \ $message_key \ $file_messages($message_key)} errmsg] } { lappend message_count(errors) $errmsg set error_p 1 } } elseif { $update_sync_p || $upgrade_status eq "deleted" } { # Set the upgrade_status, deleted_p, conflict_p, and sync_time properties of the message # If we are doing nothing, the only property of the message we might want to update in the db # is the sync_time as we might have discovered that db and file are in sync array unset edit_array if { $upgrade_status ne "no_upgrade" } { set edit_array(upgrade_status) $upgrade_status set edit_array(deleted_p) [string equal $upgrade_status "deleted"] set edit_array(conflict_p) $conflict_p } ns_log Debug "lang::catalog::import_messages - invoking lang::message::edit with import_case=\"$import_case\" -update_sync=$update_sync_p $message_key [array get edit_array]" if { [catch {lang::message::edit \ -update_sync=$update_sync_p \ $package_key \ $message_key \ $locale \ [array get edit_array]} errmsg] } { lappend message_count(errors) $errmsg set error_p 1 } } else { ns_log Debug "lang::catalog::import_messages - not doing anything: import_case=\"$import_case\" $message_key $upgrade_status $conflict_p" } if { [lsearch -exact {added updated deleted} $upgrade_status] != -1 } { if { ! $error_p } { incr message_count($upgrade_status) } } incr message_count(processed) } ;# End of message key loop return [array get message_count] } ad_proc -public lang::catalog::import { {-package_key {}} {-locales {}} {-initialize:boolean} {-cache:boolean} } { Import messages from catalog files to the database. By default all messages for enabled packages and enabled locales will be imported. Optionally, the import can be restricted to a certain package and/or a list of locales. Invokes the proc lang::catalog::import_messages that deals with multiple imports (upgrades). @param package_key Restrict the import to the package with this key @param locales A list of locales to restrict the import to @param initialize Only load messages from packages that have never before had any message imported @param cache Provide this switch if you want the proc to cache all the imported messages @return An array list containing the number of messages processed, number of messages added, number of messages updated, number of messages deleted by the import, and a list of errors produced. The keys of the array list are processed, added, updated, and deleted, and errors. @see lang::catalog::import_messages @author Peter Marklund } { set message_count(processed) 0 set message_count(added) 0 set message_count(updated) 0 set message_count(deleted) 0 set message_count(errors) [list] if { $package_key ne "" } { set package_key_list $package_key } else { set package_key_list [apm_enabled_packages] } if { $initialize_p } { set uninitialized_packages [uninitialized_packages] } foreach package_key $package_key_list { if {$initialize_p && [lsearch -exact $uninitialized_packages $package_key] == -1} { # The package is already initialized continue } # Skip the package if it has no catalog files at all if { ![file exists [package_catalog_dir $package_key]] } { continue } set catalog_files [get_catalog_paths_for_import \ -package_key $package_key \ -locales $locales] # Issue a warning and exit if there are no catalog files if { $catalog_files eq "" } { ns_log Warning "No catalog files found for package $package_key" continue } foreach file_path $catalog_files { # Use a catch so that parse failure of one file doesn't cause the import of all files to fail array unset loop_message_count if { [catch { array set loop_message_count [lang::catalog::import_from_file $file_path] } errMsg] } { global errorInfo ns_log Error "The import of file $file_path failed, error message is:\n\n${errMsg}\n\nstack trace:\n\n$errorInfo\n\n" } else { foreach action [array names loop_message_count] { if { $action ne "errors" } { set message_count($action) [expr {$message_count($action) + $loop_message_count($action)}] } } set message_count(errors) [concat $message_count(errors) $loop_message_count(errors)] } } } if { $cache_p } { lang::message::cache } return [array get message_count] } ad_proc -private lang::catalog::get_catalog_paths_for_import { {-package_key:required} {-locales {}} } { Return a list of file paths for the catalog files of the given package. Can be restricted to only return files for certain locales. The list will be sorted in an order appropriate for import to the database. @param package_key The key of the package to get catalog file paths for @param locales A list of locales to restrict the catalog files to @author Peter Marklund } { # We always need to register en_US messages first as they create the keys set en_us_locale_list [list en_US] set other_locales_list [db_list locales { select locale from ad_locales where enabled_p = 't' and locale <> 'en_US' }] set locales_list [concat $en_us_locale_list $other_locales_list] # Get all catalog files for enabled locales set catalog_files [list] foreach locale $locales_list { # If we are only processing certain locales and this is not one of them - continue if { [llength $locales] > 0 && [lsearch -exact $locales $locale] == -1 } { continue } # If the package has no files in this locale - continue if { ![package_has_files_in_locale_p $package_key $locale] } { continue } set file_path [get_catalog_file_path \ -package_key $package_key \ -locale $locale] if { [file exists $file_path] } { lappend catalog_files $file_path } else { ns_log Error "Catalog file $file_path not found. Failed to import messages for package $package_key and locale $locale" } } return $catalog_files } ################## # # Mischellaneous procs # ################## ad_proc -public lang::catalog::package_delete { {-package_key:required} } { Unregister the I18N messages for the package. @author Peter Marklund } { set message_key_list [db_list all_message_keys_for_package { select message_key from lang_message_keys where package_key = :package_key }] db_dml delete_package_keys { delete from lang_message_keys where package_key = :package_key } foreach message_key $message_key_list { lang::message::remove_from_cache $package_key $message_key } } ################## # # Inactive and unmaintained procs # ################## ad_proc -private lang::catalog::translate {} { Translates all untranslated strings in a message catalog from English into Spanish, French and German using Babelfish. NOTE: this proc is unmaintained. Quick way to get a multilingual site up and running if you can live with the quality of the translations.

    Not a good idea to run this procedure if you have a large message catalog. Use for testing purposes only. @author John Lowry (lowry@arsdigita.com) } { set default_locale [parameter::get -package_id [apm_package_id_from_key acs-lang] -parameter SiteWideLocale] db_foreach get_untranslated_messages {} { foreach lang [list es_ES fr_FR de_DE] { if [catch { set translated_message [lang_babel_translate $message en_$lang] } errmsg] { ns_log Notice "Error translating $message into $lang: $errmsg" } else { lang::message::register $lang $package_key $message_key $translated_message } } } } openacs-5.7.0/packages/acs-lang/tcl/lang-catalog-procs.xql0000644000175000017500000000601707766162051023241 0ustar frankiefrankie select package_key from apm_package_types where exists (select 1 from apm_package_versions where package_key = apm_package_types.package_key and installed_p = 't' and enabled_p = 't') and not exists (select 1 from lang_message_keys where package_key = apm_package_types.package_key) select distinct locale from lang_messages where package_key = :package_key select lm.message_key, lm.message, lmk.description from lang_messages lm, lang_message_keys lmk where lm.message_key = lmk.message_key and lm.package_key = lmk.package_key and lm.package_key = :package_key and lm.locale = :locale and lm.deleted_p = 'f' select message_key, package_key, message from lang_messages lm1 where locale = :default_locale and not exists (select message_key, package_key from lang_messages lm2 where locale != :default_locale and lm1.message_key = lm2.message_key and lm1.package_key = lm2.package_key) update lang_message_keys set upgrade_status = 'no_upgrade' where package_key = :package_key update lang_messages set upgrade_status = 'no_upgrade' where package_key = :package_key and locale = :locale update lang_messages set upgrade_status = 'deleted' where package_key = :package_key and message_key = :message_key and locale = :locale update lang_message_keys set upgrade_status = 'deleted' where package_key = :package_key and message_key = :message_key openacs-5.7.0/packages/acs-lang/tcl/lang-install-procs.tcl0000644000175000017500000000204710236715140023237 0ustar frankiefrankiead_library { Support procedures for install.xml actions. @creation-date 20050129 @author Jeff Davis davis@xarg.net @cvs-id $Id: lang-install-procs.tcl,v 1.4 2005/05/06 16:25:04 richardh Exp $ } namespace eval ::install::xml::action {} ad_proc -private ::install::xml::action::set-system-locale { node } { set the systewide locale <set-system-locale locale="en_US"> } { set locale [apm_required_attribute_value $node locale] lang::system::set_locale $locale } ad_proc -private ::install::xml::action::enable-locale { node } { Enable a locale <enable-locale locale="en_US"> } { set locale [apm_required_attribute_value $node locale] lang::system::locale_set_enabled -locale $locale -enabled_p t } ad_proc -private ::install::xml::action::disable-locale { node } { Disable a locale <disable-locale locale="en_US"> } { set locale [apm_required_attribute_value $node locale] lang::system::locale_set_enabled -locale $locale -enabled_p f } openacs-5.7.0/packages/acs-lang/tcl/lang-widget-procs.tcl0000644000175000017500000000453511120236537023061 0ustar frankiefrankiead_library { Widgets for acs-lang. Currently just a special version of the select widget which adds a "lang" attribute to each option, as required by accessibility standards. @author Don Baccus (dhogaza@pacifier.com) @creation-date November 3, 2006 @cvs-id $Id: lang-widget-procs.tcl,v 1.7 2008/12/11 16:18:39 emmar Exp $ } namespace eval template {} namespace eval template::widget {} ad_proc -public template::widget::select_locales { element_reference tag_attributes } { Generate a select widget for locales. We need a custom widget for this one case because accessibility standards require us to put out a "lang" attribute if the text is not in the same language as the rest of the page. } { upvar $element_reference element if { [info exists element(html)] } { array set attributes $element(html) } if { [info exists element(values)] } { template::util::list_to_lookup $element(values) values } array set attributes $tag_attributes if { $element(mode) ne "edit" } { set selected_list [list] foreach option $element(options) { set label [lindex $option 0] set value [lindex $option 1] if { [info exists values($value)] } { lappend selected_list $label append output "" } } append output [join $selected_list ", "] } else { append output "" } return $output } openacs-5.7.0/packages/acs-lang/tcl/lang-catalog-procs-postgresql.xql0000644000175000017500000000336410720127056025432 0ustar frankiefrankie postgresql7.2 update lang_messages set sync_time = current_timestamp where package_key = :package_key and locale = :locale select message_key, message, deleted_p from lang_messages where package_key = :package_key and locale = :locale and sync_time is not null union select lma1.message_key, lma1.old_message, lma1.deleted_p from lang_messages_audit lma1 where lma1.package_key = :package_key and lma1.locale = :locale and lma1.sync_time is not null and lma1.audit_id = (select max(lma2.audit_id) from lang_messages_audit lma2 where lma2.package_key = lma1.package_key and lma2.message_key = lma1.message_key and lma2.locale = :locale and lma2.sync_time is not null ) and not exists (select 1 from lang_messages where package_key = lma1.package_key and message_key = lma1.message_key and locale = :locale and sync_time is not null ) openacs-5.7.0/packages/acs-lang/tcl/acs-lang-init.tcl0000644000175000017500000000047107743724224022167 0ustar frankiefrankiead_library { Do initialization at server startup for the acs-lang package. @creation-date 23 October 2000 @author Peter Marklund (peter@collaboraid.biz) @cvs-id $Id: acs-lang-init.tcl,v 1.9 2003/10/17 08:30:12 peterm Exp $ } # Cache I18N messages in memory for fast lookups lang::message::cache openacs-5.7.0/packages/acs-lang/tcl/lang-message-procs-postgresql.xql0000644000175000017500000000245307766162051025454 0ustar frankiefrankie postgresql7.2 update lang_messages set [join $set_clauses ", "] where locale = :locale and message_key = :message_key and package_key = :package_key insert into lang_messages ([join $col_clauses ", "]) values ([join $val_clauses ", "]) current_timestamp :message update lang_message_keys set description = :description where message_key = :message_key and package_key = :package_key sync_time = current_timestamp openacs-5.7.0/packages/acs-lang/tcl/localization-procs-postgresql.xql0000644000175000017500000000174307715740703025602 0ustar frankiefrankie postgresql7.1 select to_char(timezone__convert_to_local(timezone__get_id(:tz), :time_value), 'YYYY-MM-DD HH24:MI:SS') select to_char(timezone__convert_to_utc(timezone__get_id(:tz), :time_value), 'YYYY-MM-DD HH24:MI:SS') select to_char( timezone__convert_to_local(timezone__get_id(:to), to_char(timezone__convert_to_utc(timezone__get_id(:from), :time_value), 'YYYY-MM-DD HH24:MI:SS') ), 'YYYY-MM-DD HH24:MI:SS') openacs-5.7.0/packages/acs-lang/tcl/locale-procs.tcl0000644000175000017500000005070411321666756022132 0ustar frankiefrankie#/packages/lang/tcl/ad-locale.tcl ad_library { Localization procedures for OpenACS

    This is free software distributed under the terms of the GNU Public License. Full text of the license is available from the GNU Project: http://www.fsf.org/copyleft/gpl.html @creation-date 28 September 2000 @author Henry Minsky (hqm@mit.edu) @author Lars Pind (lars@pinds.com) @cvs-id $Id: locale-procs.tcl,v 1.37 2010/01/08 17:39:58 emmar Exp $ } namespace eval lang::system {} namespace eval lang::user {} namespace eval lang::conn {} ##### # # lang::system # ##### ad_proc -public lang::system::use_package_level_locales_p {} { Returns whether we're using package level locales. } { return [parameter::get -parameter UsePackageLevelLocalesP -package_id [apm_package_id_from_key "acs-lang"] -default 0] } ad_proc -public lang::system::site_wide_locale { } { Get the site wide system locale setting. } { set parameter_locale [parameter::get \ -package_id [apm_package_id_from_key "acs-lang"] \ -parameter "SiteWideLocale" \ -default "en_US"] # Check validity of parameter setting set valid_locales [lang::system::get_locales] if { [lsearch -exact $valid_locales $parameter_locale] == -1 } { ns_log Error "The parameter setting acs-lang.SiteWideLocale=\"$parameter_locale\" is invalid. Valid locales are: \"$valid_locales\". Defaulting to en_US locale" return en_US } return $parameter_locale } ad_proc -private lang::system::package_level_locale_not_cached { package_id } { return [db_string get_package_locale {} -default {}] } ad_proc -public lang::system::package_level_locale { package_id } { @return empty string if not use_package_level_locales_p, or the package locale from apm_packages table. } { if { ![use_package_level_locales_p] } { return {} } return [util_memoize [list lang::system::package_level_locale_not_cached $package_id]] } ad_proc -public lang::system::locale { {-package_id ""} {-site_wide:boolean} } { Get system locale setting for a given package instance. @param package_id The package for which you want to get the locale setting. @param site_wide Set this if you want to get the site-wide locale setting. } { if { $site_wide_p } { return [site_wide_locale] } if { $package_id eq "" && [ad_conn isconnected] } { set package_id [ad_conn package_id] } # Get locale for package set locale [package_level_locale $package_id] # If there's no package setting, use the site-wide setting if { $locale eq "" } { set locale [site_wide_locale] } return $locale } ad_proc -public lang::system::set_locale { {-package_id ""} locale } { Set system locale setting for a given package instance, or the site-wide system locale. @param package_id The package for which you want to set the locale setting, if you want to set system setting for one package only. Leave blank for site-wide setting. @param locale The new locale that you want to use as your system locale. } { if { $package_id eq "" } { parameter::set_value \ -package_id [apm_package_id_from_key "acs-lang"] \ -parameter SiteWideLocale \ -value $locale } else { # Update the setting db_dml update_system_locale {} # Flush the cache util_memoize_flush [list lang::system::package_level_locale_not_cached $package_id] # TODO: We will need to have site-map inheritance for this, so packages under a subsite/dotlrn inherit the subsite's/dotlrn's setting } } ad_proc -public lang::system::language { {-package_id ""} {-site_wide:boolean} {-iso6392:boolean} } { Get system language setting for a given package instance. @param package_id The package for which you want to get the language setting. @param site_wide Set this if you want to get the site-wide language setting. @param iso6392 Set this if you want to force iso-639-2 code (3 digits) @return 3 chars language code if iso6392 is set, left part of locale otherwise } { set locale [locale -package_id $package_id -site_wide=$site_wide_p] set sys_lang [lindex [split $locale "_"] 0] if { $iso6392_p } { return [lang::util::iso6392_from_language -language $sys_lang] } else { return $sys_lang } } ad_proc -public lang::system::timezone {} { Ask OpenACS what it thinks our timezone is. @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) } { if { ![lang::system::timezone_support_p] } { return "" } set package_id [apm_package_id_from_key "acs-lang"] return [parameter::get -package_id $package_id -parameter SystemTimezone -default "Etc/UTC"] } ad_proc -private lang::system::timezone_support_p {} { Return 1 if this installation of acs-lang offers timezone services and 0 otherwise. For the acs-lang package to offer timezone support the ref-timezones and acs-reference packages need to be installed. Those packages are currently not part of the OpenACS kernel. } { return [apm_package_installed_p ref-timezones] } ad_proc -public lang::system::set_timezone { timezone } { Tell OpenACS what timezone we think it's running in. @param timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) } { if { ![lang::system::timezone_support_p] } { return "" } set package_id [apm_package_id_from_key "acs-lang"] parameter::set_value -package_id $package_id -parameter SystemTimezone -value $timezone } ad_proc -public lang::system::timezone_utc_offset { } { @return number of hours to subtract from local (database) time to get UTC } { if { ![lang::system::timezone_support_p] } { return "" } set system_timezone [timezone] return [db_string system_utc_offset {}] } ad_proc -public lang::system::get_locales {} { Return all enabled locales in the system. Cached @author Peter Marklund } { return [util_memoize lang::system::get_locales_not_cached] } ad_proc -public lang::system::get_locale_options {} { Return all enabled locales in the system in a format suitable for the options argument of a form. @author Lars Pind } { return [util_memoize lang::system::get_locale_options_not_cached] } ad_proc -public lang::system::locale_set_enabled { {-locale:required} {-enabled_p:required} } { Enables or disables a locale. @param enabled_p Should be t or f @author Peter Marklund } { db_dml set_enabled_p { update ad_locales set enabled_p = :enabled_p where locale = :locale } # Flush caches util_memoize_flush_regexp {^lang::util::default_locale_from_lang_not_cached} util_memoize_flush_regexp {^lang::system::get_locales} util_memoize_flush_regexp {^lang::system::get_locale_options} } ad_proc -private lang::system::get_locales_not_cached {} { Return all enabled locales in the system. @author Peter Marklund } { return [db_list select_system_locales { select locale from ad_locales where enabled_p = 't' }] } ad_proc -private lang::system::get_locale_options_not_cached {} { Return all enabled locales in the system in a format suitable for the options argument of a form. @author Lars Pind } { return [db_list_of_lists select_locales {}] } ##### # # lang::user # ##### ad_proc -private lang::user::package_level_locale_not_cached { user_id package_id } { Get the user's preferred package level locale for a package given by its package id. Will return the empty string if the user has not preference for the package. } { return [db_string get_user_locale {} -default ""] } ad_proc -public lang::user::package_level_locale { {-user_id ""} package_id } { Get the user's preferred package level locale for a package given by its package id. } { # default to current user if { $user_id eq "" } { set user_id [ad_conn untrusted_user_id] } # If package-level locales are turned off, or the user isn't logged in, return the empty string if { ![lang::system::use_package_level_locales_p] || $user_id == 0 } { return {} } # Cache for the lifetime of sessions (7 days) return [util_memoize [list lang::user::package_level_locale_not_cached $user_id $package_id] [sec_session_timeout]] } ad_proc -public lang::user::site_wide_locale { {-user_id ""} } { Get the user's preferred site wide locale. } { # default to current user if { $user_id eq "" } { set user_id [ad_conn untrusted_user_id] } # For all the users with a user_id of 0 don't cache. if { $user_id == 0} { return [lang::user::site_wide_locale_not_cached $user_id] } # Cache for the lifetime of sessions (7 days) return [util_memoize [list lang::user::site_wide_locale_not_cached $user_id] [sec_session_timeout]] } ad_proc -private lang::user::site_wide_locale_not_cached { user_id } { Get the user's preferred site wide locale. } { set system_locale [lang::system::site_wide_locale] if { $user_id == 0 } { set locale [ad_get_cookie "ad_locale"] } else { set locale [db_string get_user_site_wide_locale {} -default "$system_locale"] } if { $locale eq "" } { set locale $system_locale } return $locale } ad_proc -public lang::user::locale { {-package_id ""} {-site_wide:boolean} {-user_id ""} } { Get user locale preference for a given package instance. @param package_id The package for which you want to get the locale preference. @param site_wide Set this if you want to get the site-wide locale preference. @param user_id Set this to the user you want to get the locale of, defaults to current user. } { # default to current user if { $user_id eq "" } { set user_id [ad_conn untrusted_user_id] } # default to current connection package if { $package_id eq "" } { set package_id [ad_conn package_id] } # Try package level locale first set locale [package_level_locale -user_id $user_id $package_id] # If there's no package setting, then use the site-wide setting if { $locale eq "" } { set locale [site_wide_locale -user_id $user_id] } return $locale } ad_proc -public lang::user::set_locale { {-package_id ""} {-user_id ""} locale } { Set user locale setting for a given package instance. @param package_id The package for which you want to set the locale setting, if you want to set it for a specific package, as opposed to a site-wide setting. @param locale The new locale that you want to use as your system locale. } { if { $user_id eq "" } { set user_id [ad_conn user_id] } if { $user_id == 0 } { # Not logged in, use a cookie-based client locale ad_set_cookie -replace t -max_age inf "ad_locale" $locale # Flush the site-wide user preference cache util_memoize_flush [list lang::user::site_wide_locale_not_cached $user_id] return } if { $package_id eq "" } { # Set site-wide locale in user_preferences table db_dml set_user_site_wide_locale {} # Flush the site-wide user preference cache util_memoize_flush [list lang::user::site_wide_locale_not_cached $user_id] return } # The rest is for package level locale settings only # Even if package level locales are disabled, we'll still do this set user_locale_exists_p [db_string user_locale_exists_p {}] if { $user_locale_exists_p } { if { $locale ne "" } { db_dml update_user_locale {} } else { db_dml delete_user_locale {} } } else { if { $locale ne "" } { db_dml insert_user_locale {} } } # Flush the user locale preference cache util_memoize_flush [list lang::user::package_level_locale_not_cached $user_id $package_id] } ad_proc -public lang::user::language { {-package_id ""} {-site_wide:boolean} {-iso6392:boolean} } { Get user language preference for a given package instance. This preliminary implementation only has one site-wide setting, though. @param package_id The package for which you want to get the language setting. @param site_wide Set this if you want to get the site-wide language setting. @param iso6392 Set this if you want to force iso-639-2 code (3 digits) @return 3 chars language code if iso6392 is set, left part of locale otherwise } { set locale [locale -package_id $package_id -site_wide=$site_wide_p] set user_lang [lindex [split $locale "_"] 0] if { $iso6392_p } { return [lang::util::iso6392_from_language -language $user_lang] } else { return $user_lang } } ad_proc -private lang::user::timezone_no_cache {user_id} { return [db_string select_user_timezone {} -default ""] } ad_proc -public lang::user::timezone {} { Get the user's timezone. Returns the empty string if the user has no timezone set. @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) } { set user_id [ad_conn user_id] if { ![lang::system::timezone_support_p] || $user_id == 0 } { return "" } return [util_memoize [list lang::user::timezone_no_cache $user_id]] } ad_proc -public lang::user::set_timezone { timezone } { Set the user's timezone setting. @param timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) } { if { ![lang::system::timezone_support_p] } { return "" } set user_id [ad_conn user_id] if { $user_id == 0 } { error "User not logged in" } else { db_dml set_user_timezone {} util_memoize_flush [list lang::user::timezone_no_cache $user_id] } } ##### # # lang::conn # ##### ad_proc -public lang::conn::locale { {-package_id ""} {-site_wide:boolean} } { Get the locale for this request, perhaps for a given package instance. This procedure will never return an error. Everything that could fail is wrapped in a catch. @param package_id The package for which you want to get the locale. @param site_wide Set this if you want to get the site-wide locale. } { if { $site_wide_p } { set locale [lang::user::site_wide_locale] if { $locale eq "" } { set locale [lang::system::site_wide_locale] } return $locale } # default value for package_id if { $package_id eq "" } { set package_id [ad_conn package_id] } # use user's package level locale set locale [lang::user::package_level_locale $package_id] # if that does not exist use system's package level locale if { $locale eq "" } { set locale [lang::system::package_level_locale $package_id] } # if that does not exist use user's site wide locale if { $locale eq "" } { set locale [lang::user::site_wide_locale] } # Use the accept-language browser heading if { $locale eq "" } { set locale [lang::conn::browser_locale] } # if that does not exist use system's site wide locale if { $locale eq "" } { set locale [lang::system::site_wide_locale] } # if that does not exist then we are back to just another language # let's pick uhmm... en_US if { $locale eq "" } { set locale en_US } return $locale } ad_proc -private lang::conn::browser_locale {} { Get the users preferred locale from the accept-language HTTP header. @return A locale or an empty string if no locale can be found that is supported by the system @author Lars Pind @author Peter Marklund } { set conn_locales [lang::conn::get_accept_language_header] set system_locales [lang::system::get_locales] foreach locale $conn_locales { regexp {^([^_]+)(?:_([^_]+))?$} $locale locale language region if { [exists_and_not_null region] } { # We have both language and region, e.g. en_US if { [lsearch -exact $system_locales $locale] != -1 } { # The locale was found in the system, a perfect match set perfect_match $locale break } else { # We don't have the full locale in the system but check if # we have a different locale with matching language, # i.e. a tentative match if { ![info exists tentative_match] } { set default_locale [lang::util::default_locale_from_lang $language] if { $default_locale ne "" } { set tentative_match $default_locale } } else { # We already have a tentative match with higher priority so # continue searching for a perfect match continue } } } else { # We have just a language, e.g. en set default_locale [lang::util::default_locale_from_lang $locale] if { $default_locale ne "" } { set perfect_match $default_locale break } } } if { [exists_and_not_null perfect_match] } { return $perfect_match } elseif { [exists_and_not_null tentative_match] } { return $tentative_match } else { # We didn't find a match return "" } } ad_proc -private lang::conn::get_accept_language_header {} { set acclang [ns_set iget [ns_conn headers] "Accept-Language"] # Split by comma, and get rid of any ;q=0.5 parts # acclang is something like 'da,en-us;q=0.8,es-ni;q=0.5,de;q=0.3' set acclangv [list] foreach elm [split $acclang ","] { # Get rid of trailing ;q=0.5 part set elm [lindex [split $elm ";"] 0] # elm is now either like 'da' or 'en-us' # make it into something like 'da' or 'en_US' set elmv [split $elm "-"] set elm [lindex $elmv 0] if { [llength $elmv] > 1 } { append elm "_[string toupper [lindex $elmv 1]]" } lappend acclangv $elm } return $acclangv } ad_proc -public lang::conn::language { {-package_id ""} {-site_wide:boolean} {-iso6392:boolean} } { Get the language for this request, perhaps for a given package instance. @param package_id The package for which you want to get the language. @param site_wide Set this if you want to get the site-wide language. @param iso6392 Set this if you want to force the iso-639-2 code @return 3 chars language code if iso6392 is set, left part of locale otherwise } { set locale [locale -package_id $package_id -site_wide=$site_wide_p] set conn_lang [lindex [split $locale "_"] 0] if { $iso6392_p } { return [lang::util::iso6392_from_language -language $conn_lang] } else { return $conn_lang } } ad_proc -public lang::conn::charset { } { Returns the MIME charset name corresponding to the current connection's locale. @author Lars Pind (lars@pinds.com) @param locale Name of a locale, as language_COUNTRY using ISO 639 and ISO 3166 @return IANA MIME character set name } { return [lang::util::charset_for_locale [lang::conn::locale]] } ad_proc -public lang::conn::timezone {} { Get this connection's timezone. This is the user timezone, if set, otherwise the system timezone. @return a timezone name from acs-reference package (e.g., Asia/Tokyo, America/New_York) } { if { ![lang::system::timezone_support_p] } { return "" } set timezone {} if { [ad_conn isconnected] } { set timezone [lang::user::timezone] } if { $timezone eq "" } { # No user timezone, return the system timezone set timezone [lang::system::timezone] } return $timezone } ##### # # Backwards compatibility procs # ##### ad_proc -deprecated -warn -public ad_locale_get_label { locale } { Returns the label (name) of locale To be removed in 5.3 @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) @param locale Code for the locale, eg "en_US" @return String containing the label for the locale @see lang::util::get_label } { return [db_string select_locale_label { select label from ad_locales where lower(locale) = lower(:locale) }] } openacs-5.7.0/packages/acs-lang/tcl/locale-procs.xql0000644000175000017500000000554310210446623022136 0ustar frankiefrankie select default_locale from apm_packages where package_id = :package_id update apm_packages set default_locale = :locale where package_id = :package_id select locale from ad_locale_user_prefs where user_id = :user_id and package_id = :package_id select locale from user_preferences where user_id = :user_id update user_preferences set locale = :locale where user_id = :user_id select count(*) from ad_locale_user_prefs where user_id = :user_id and package_id = :package_id update ad_locale_user_prefs set locale = :locale where user_id = :user_id and package_id = :package_id insert into ad_locale_user_prefs (user_id, package_id, locale) values (:user_id, :package_id, :locale) delete from ad_locale_user_prefs where user_id = :user_id and package_id = :package_id update user_preferences set timezone = :timezone where user_id = :user_id select timezone from user_preferences where user_id = :user_id select label, locale from ad_locales where enabled_p = 't' openacs-5.7.0/packages/acs-lang/tcl/locale-procs-postgresql.xql0000644000175000017500000000100707714712707024344 0ustar frankiefrankie postgresql7.1 select (extract(epoch from current_timestamp + timezone__get_offset (timezone__get_id(:system_timezone), current_timestamp) ) - extract(epoch from current_timestamp) ) / 60/60; openacs-5.7.0/packages/acs-lang/tcl/lang-audit-procs-postgresql.xql0000644000175000017500000000123610017410256025116 0ustar frankiefrankie postgresql7.2 insert into lang_messages_audit (audit_id, package_key, message_key, locale, old_message, comment_text, overwrite_user, deleted_p, sync_time, conflict_p, upgrade_status) values (nextval('lang_messages_audit_id_seq'::text), :package_key, :message_key, :locale, :old_message, :comment, :overwrite_user, :deleted_p, :sync_time, :conflict_p, :upgrade_status) openacs-5.7.0/packages/acs-lang/tcl/localization-data-init.tcl0000644000175000017500000001371610551254374024102 0ustar frankiefrankie#/packages/lang/tcl/localization-data-init.tcl ad_library { Database required for localization routines Currently only supports five locales (US, UK, France, Spain and Germany). Add new entries to support additional locales. @creation-date 10 September 2000 @author Jeff Davis (davis@xarg.net) @cvs-id $Id: localization-data-init.tcl,v 1.18 2007/01/10 21:22:04 gustafn Exp $ } # Monetary amounts # number after money: is interpreted like this: # # first digit: currency symbol position: # 0 = currency symbol after amount # 1 = currency symbol before amount # # second digit: position of sign # 0 = wrap number in parenthesis, no sign symbol # 1 = sign symbol precedes number and currency symbol # 2 = sign symbol follows number and currency symbol # 3 = sign comes before the currency symbol # 4 = sign comes after the currency symbol # # third digit: space separation # 0 = no space # 1 = there's a space somewhere # 2 = there's a space somewhere # # TODO: Ask Jeff # It looks like the logic *should* be that 1 means a space in the first position, # 2 is a space in the second position, but that's not what the table below does # nsv_set locale money:000 {($num$sym)} nsv_set locale money:001 {($num $sym)} nsv_set locale money:002 {($num$sym)} nsv_set locale money:010 {$sign$num$sym} nsv_set locale money:011 {$sign$num $sym} nsv_set locale money:012 {$sign$num $sym} nsv_set locale money:020 {$num$sym$sign} nsv_set locale money:021 {$num $sym$sign} nsv_set locale money:022 {$num$sym $sign} nsv_set locale money:030 {$num$sign$sym} nsv_set locale money:031 {$num $sign$sym} nsv_set locale money:032 {$num$sign $sym} nsv_set locale money:040 {$num$sym$sign} nsv_set locale money:041 {$num $sym$sign} nsv_set locale money:042 {$num$sym $sign} nsv_set locale money:100 {($sym$num)} nsv_set locale money:101 {($sym$num)} nsv_set locale money:102 {($sym$num)} nsv_set locale money:110 {$sign$sym$num} nsv_set locale money:111 {$sign$sym$num} nsv_set locale money:112 {$sign$sym$num} nsv_set locale money:120 {$sym$num$sign} nsv_set locale money:121 {$sym$num$sign} nsv_set locale money:122 {$sym$num$sign} nsv_set locale money:130 {$sign$sym$num} nsv_set locale money:131 {$sign$sym$num} nsv_set locale money:132 {$sign$sym$num} nsv_set locale money:140 {$sym$sign$num} nsv_set locale money:141 {$sym$sign$num} nsv_set locale money:142 {$sym$sign$num} namespace eval ::lang::util { variable percent_match # Date format codes. This was brought over from lc_time_fmt, to avoid having to rebuild the # array each time the procedure is called, which is often. # AG: FOR BUGFREE OPERATION it's important that variable names get # properly delimited. This is not usually a problem because most # of the assignments occur in square brackets where spaces are # allowed. But it can be a problem with array values that are set # to single variables. Example: # # Bad: set percent_match(Y) {$lc_time_year} # Good: set percent_match(Y) {${lc_time_year}} # # The error trigger is: message catalog messages that don't have any # whitespace between the variable name and other parts of the message. In # this case the lc_time_fmt_compile function may return expressions where # the variable name is appended to by the message catalog contents, # resulting in variables that look like this: $lc_time_year\345\271\264 # Tcl will throw an error when it encounters undefined variables. # Unsupported number things set percent_match(W) "" set percent_match(U) "" set percent_match(u) "" set percent_match(j) "" # Composites, now directly expanded, note that writing for %r specifically would be quicker than what we have here. set percent_match(T) {[lc_leading_zeros $lc_time_hours 2]:[lc_leading_zeros $lc_time_minutes 2]:[lc_leading_zeros $lc_time_seconds 2]} set percent_match(D) {[lc_leading_zeros $lc_time_days 2]/[lc_leading_zeros $lc_time_month 2]/[lc_leading_zeros [expr {$lc_time_year%100}] 2]} set percent_match(F) {${lc_time_year}-[lc_leading_zeros $lc_time_month 2]-[lc_leading_zeros $lc_time_days 2]} set percent_match(r) {[lc_leading_zeros [lc_time_drop_meridian $lc_time_hours] 2]:[lc_leading_zeros $lc_time_minutes 2] [lc_time_name_meridian $locale $lc_time_hours]} # Direct Subst set percent_match(e) {[lc_leading_space $lc_time_days]} set percent_match(E) {[lc_leading_space $lc_time_month]} set percent_match(f) {[lc_wrap_sunday $lc_time_day_no]} set percent_match(Y) {${lc_time_year}} # Plus padding set percent_match(d) {[lc_leading_zeros $lc_time_days 2]} set percent_match(H) {[lc_leading_zeros $lc_time_hours 2]} set percent_match(S) {[lc_leading_zeros $lc_time_seconds 2]} set percent_match(m) {[lc_leading_zeros $lc_time_month 2]} set percent_match(M) {[lc_leading_zeros $lc_time_minutes 2]} # Calculable values (based on assumptions above) set percent_match(C) {[expr {int($lc_time_year/100)}]} set percent_match(I) {[lc_leading_zeros [lc_time_drop_meridian $lc_time_hours] 2]} set percent_match(w) {[expr {$lc_time_day_no}]} set percent_match(y) {[lc_leading_zeros [expr {$lc_time_year%100}] 2]} set percent_match(Z) [lang::conn::timezone] # Straight (localian) lookups set percent_match(a) {[lindex [lc_get -locale $locale "abday"] $lc_time_day_no]} set percent_match(A) {[lindex [lc_get -locale $locale "day"] $lc_time_day_no]} set percent_match(b) {[lindex [lc_get -locale $locale "abmon"] [expr {$lc_time_month-1}]]} set percent_match(h) {[lindex [lc_get -locale $locale "abmon"] [expr {$lc_time_month-1}]]} set percent_match(B) {[lindex [lc_get -locale $locale "mon"] [expr {$lc_time_month-1}]]} set percent_match(p) {[lc_time_name_meridian $locale $lc_time_hours]} # Finally, static string replacements set percent_match(t) {\t} set percent_match(n) {\n} set percent_match(%) {%} } openacs-5.7.0/packages/acs-lang/tcl/lang-util-procs-oracle.xql0000644000175000017500000000066711022567607024050 0ustar frankiefrankie oracle8.1.6 select nls_language from ad_locales where lower(trim(language)) = lower(:language) and enabled_p = 't' and rownum = 1 openacs-5.7.0/packages/acs-lang/tcl/apm-callback-procs.tcl0000644000175000017500000000126511456662500023170 0ustar frankiefrankie# /packages/acs-lang/tcl/apm-callback-procs.tcl ad_library { APM callbacks library @creation-date August 2009 @author Emmanuelle Raffenne (eraffenne@gmail.com) @cvs-id $Id: apm-callback-procs.tcl,v 1.2 2010/10/17 21:06:08 donb Exp $ } namespace eval lang {} namespace eval lang::apm {} ad_proc -private lang::apm::after_install { } { After install callback } { } ad_proc -private lang::apm::after_upgrade { {-from_version_name:required} {-to_version_name:required} } { After upgrade callback for acs-lang } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { } } openacs-5.7.0/packages/acs-lang/tcl/lang-audit-procs-oracle.xql0000644000175000017500000000132510017410256024157 0ustar frankiefrankie oracle8.1.6 insert into lang_messages_audit (audit_id, package_key, message_key, locale, old_message, comment_text, overwrite_user, deleted_p, sync_time, conflict_p, upgrade_status) values (lang_messages_audit_id_seq.nextval, :package_key, :message_key, :locale, empty_clob(), empty_clob(), :overwrite_user, :deleted_p, :sync_time, :conflict_p, :upgrade_status) returning old_message, comment_text into :1, :2 openacs-5.7.0/packages/acs-lang/tcl/lang-catalog-procs-oracle.xql0000644000175000017500000000343210720127056024470 0ustar frankiefrankie oracle8.1.6 update lang_messages set sync_time = sysdate where package_key = :package_key and locale = :locale select message_key, dbms_lob.substr(message) as message, deleted_p from lang_messages where package_key = :package_key and locale = :locale and sync_time is not null union select lma1.message_key, dbms_lob.substr(lma1.old_message) as message, lma1.deleted_p from lang_messages_audit lma1 where lma1.package_key = :package_key and lma1.locale = :locale and lma1.sync_time is not null and lma1.audit_id = (select max(lma2.audit_id) from lang_messages_audit lma2 where lma2.package_key = lma1.package_key and lma2.message_key = lma1.message_key and lma2.locale = :locale and lma2.sync_time is not null ) and not exists (select 1 from lang_messages where package_key = lma1.package_key and message_key = lma1.message_key and locale = :locale and sync_time is not null ) openacs-5.7.0/packages/acs-lang/tcl/lang-message-procs-oracle.xql0000644000175000017500000000255207766162051024516 0ustar frankiefrankie oracle8.1.6 update lang_messages set [join $set_clauses ", "] where locale = :locale and message_key = :message_key and package_key = :package_key returning message into :1 insert into lang_messages ([join $col_clauses ", "]) values ([join $val_clauses ", "]) returning message into :1 sysdate empty_clob() update lang_message_keys set description = empty_clob() where message_key = :message_key and package_key = :package_key returning description into :1 sync_time = sysdate openacs-5.7.0/packages/acs-lang/tcl/localization-procs-oracle.xql0000644000175000017500000000213607715740703024641 0ustar frankiefrankie oracle8.1.6 begin :1 := to_char(timezone.utc_to_local(timezone.get_id(:tz), to_date(:time_value, 'YYYY-MM-DD HH24:MI:SS')), 'YYYY-MM-DD HH24:MI:SS'); end; begin :1 := to_char(timezone.local_to_utc(timezone.get_id(:tz), to_date(:time_value, 'YYYY-MM-DD HH24:MI:SS')), 'YYYY-MM-DD HH24:MI:SS'); end; begin :1 := to_char( timezone.utc_to_local(timezone.get_id(:to), timezone.local_to_utc(timezone.get_id(:from), to_date(:time_value, 'YYYY-MM-DD HH24:MI:SS')) ), 'YYYY-MM-DD HH24:MI:SS'); end; openacs-5.7.0/packages/acs-lang/tcl/lang-util-procs-postgresql.xql0000644000175000017500000000065711022567607025005 0ustar frankiefrankie postgresql7.1 select nls_language from ad_locales where lower(trim(language)) = lower(:language) and enabled_p = 't' limit 1 openacs-5.7.0/packages/acs-lang/sql/0000755000175000017500000000000011724401447017041 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/sql/oracle/0000755000175000017500000000000011724401447020306 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/sql/oracle/acs-lang-create.sql0000644000175000017500000000103607376550000023753 0ustar frankiefrankie-- Data model to support i18n of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Henry Minsky (hqm@arsdigita.com) -- $Id: acs-lang-create.sql,v 1.2 2001/11/20 21:49:52 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html prompt ** Creating locales table ... @@ ad-locales.sql prompt ** Creating translation catalog tables ... @@ message-catalog.sql openacs-5.7.0/packages/acs-lang/sql/oracle/ad-locales-drop.sql0000644000175000017500000000126111456662500023776 0ustar frankiefrankie-- -- packages/language/sql/language-create.sql -- -- @author Jeff Davis (davis@xarg.net) -- @creation-date 2000-09-10 -- @cvs-id $Id: ad-locales-drop.sql,v 1.5 2010/10/17 21:06:08 donb Exp $ -- -- **************************************************************************** -- * The lang_messages table holds the message catalog. -- * It is populated by ad_lang_message_register. -- * The registered_p flag denotes that a message exists in a file -- * that gets loaded on server startup, and hence should not get updated. -- **************************************************************************** drop table ad_locale_user_prefs; drop view enabled_locales; drop table ad_locales; openacs-5.7.0/packages/acs-lang/sql/oracle/message-catalog.sql0000644000175000017500000001455710506240060024064 0ustar frankiefrankie-- -- packages/acs-lang/sql/oracle/language-create.sql -- -- @author Jeff Davis (davis@arsdigita.com) -- @author Christian Hvid -- @author Bruno Mattarollo (bruno.mattarollo@ams.greenpeace.org) -- -- @creation-date 2000-09-10 -- @cvs-id $Id: message-catalog.sql,v 1.14 2006/09/26 14:58:56 byronl Exp $ -- create table lang_user_timezone ( user_id integer constraint lang_user_timezone_user_id_fk references users (user_id) on delete cascade, timezone varchar2(100) ); create table lang_message_keys ( message_key varchar2(200) constraint lang_message_keys_m_key_nn not null, package_key varchar2(100) constraint lang_message_keys_fk references apm_package_types(package_key) on delete cascade constraint lang_message_keys_p_key_nn not null, description clob, constraint lang_message_keys_pk primary key (message_key, package_key) ); create table lang_messages ( message_key varchar2(200) constraint lang_messages_message_key_nn not null, package_key varchar2(100) constraint lang_messages_package_key_nn not null, locale varchar2(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message clob, deleted_p char(1) default 'f' constraint lang_messages_dp_ck check (deleted_p in ('t','f')), sync_time date, conflict_p char(1) default 'f' constraint lang_messages_cp_ck check (conflict_p in ('t','f')), upgrade_status varchar2(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')), creation_date date default sysdate not null, creation_user integer constraint lang_messages_create_u_fk references users (user_id), constraint lang_messages_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade, constraint lang_messages_pk primary key (message_key, package_key, locale) ); comment on table lang_messages is ' Holds all the messages translated. The key is the way to get to a message. This table should be read at boot time -from ACS- to load all the messages into an nsv_array. '; create table lang_messages_audit ( audit_id integer constraint lang_messages_audit_pk primary key, message_key varchar2(200) constraint lang_messages_audit_key_nn not null, package_key varchar2(100) constraint lang_messages_audit_p_key_nn not null, locale varchar2(30) constraint lang_messages_audit_locale_fk references ad_locales(locale) constraint lang_messages_audit_l_nn not null, old_message clob, deleted_p char(1) default 'f' constraint lang_messages_audit_dp_ck check (deleted_p in ('t','f')), sync_time date, conflict_p char(1) default 'f' constraint lang_messages_audit_cp_ck check (conflict_p in ('t','f')), upgrade_status varchar2(30) constraint lang_messages_audit_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')), comment_text clob, overwrite_date date default sysdate not null, overwrite_user integer constraint lang_messages_audit_ou_fk references users (user_id), constraint lang_messages_audit_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade ); create sequence lang_messages_audit_id_seq; -- **************************************************************************** -- * The lang_translate_columns table holds the columns that require translation. -- * It is needed to generate the user interface for translating the web site. -- * Note that we register on_what_column itself for translation. -- **************************************************************************** create table lang_translate_columns ( column_id integer constraint ltc_column_id_pk primary key, -- cant do references on user_tables cause oracle sucks on_which_table varchar2(50), on_what_column varchar2(50), -- -- whether all entries in a column must be translated for the -- site to function. -- -- probably ultimately need something more sophisticated than -- simply required_p -- required_p char(1) constraint ltc_required_p_ck check(required_p in ('t','f')), -- -- flag for whether to use the lang_translations table for content -- or add a row in the on_which_table table with the translated content. -- short_p char(1) constraint ltc_short_p_ck check(short_p in ('t','f')), constraint ltc_un unique (on_which_table, on_what_column) ); -- **************************************************************************** -- * The lang_translation_registry table identifies a row as requiring translation -- * to a given language. This should identify the parent table not the broken-apart -- * child table. -- **************************************************************************** create table lang_translation_registry ( on_which_table varchar(50), on_what_id integer constraint ltr_on_what_id_nn not null, locale varchar2(30) constraint ltr_locale_fk references ad_locales(locale), -- -- should have dependency info here -- constraint lang_translation_registry_pk primary key(on_what_id, on_which_table, locale) ); openacs-5.7.0/packages/acs-lang/sql/oracle/ad-locales.sql0000644000175000017500000004471111456662500023043 0ustar frankiefrankie-- -- packages/language/sql/language-create.sql -- -- @author Jeff Davis (davis@xarg.net) -- @creation-date 2000-09-10 -- @cvs-id $Id: ad-locales.sql,v 1.37 2010/10/17 21:06:08 donb Exp $ -- -- **************************************************************************** -- * The lang_messages table holds the message catalog. -- * It is populated by ad_lang_message_register. -- * The registered_p flag denotes that a message exists in a file -- * that gets loaded on server startup, and hence should not get updated. -- **************************************************************************** create table ad_locales ( locale varchar2(30) constraint ad_locales_locale_pk primary key, language char(3) constraint ad_locales_language_nn not null, country char(2) constraint ad_locales_country_nn not null, variant varchar2(30), label varchar2(200) constraint ad_locale_label_nn not null constraint ad_locales_label_un unique, nls_language varchar2(30) constraint ad_locales_nls_lang_nn not null, nls_territory varchar2(30), nls_charset varchar2(30), mime_charset varchar2(30), -- is this the default locale for its language default_p char(1) default 'f' constraint ad_locale_defp_ck check (default_p in ('t','f')), enabled_p char(1) default 't' constraint ad_locale_enp_ck check (enabled_p in ('t','f')) ); comment on table ad_locales is ' An OpenACS locale is identified by a language and country. Locale definitions in Oracle consist of a language, and optionally territory and character set. (Languages are associated with default territories and character sets when not defined). The formats for numbers, currency, dates, etc. are determined by the territory. language is the shortest ISO 639 code (lowercase). country is two letter (uppercase) abbrev is ISO 3166 country code mime_charset is IANA charset name nls_charset is Oracle charset name '; create or replace view enabled_locales as select * from ad_locales where enabled_p = 't'; create table ad_locale_user_prefs ( user_id integer constraint ad_locale_user_prefs_users_fk references users (user_id) on delete cascade, package_id integer constraint lang_package_l_u_package_id_fk references apm_packages(package_id) on delete cascade, locale varchar(30) not null constraint ad_locale_user_prefs_locale_fk references ad_locales (locale) on delete cascade ); -- alter user_preferences to add the locale column alter table user_preferences add ( locale varchar2(30) constraint user_preferences_locale_fk references ad_locales(locale) ); -- -- -- And now for some default locales -- -- insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_US', 'English (US)', 'en', 'US', 'AMERICAN', 'AMERICA', 'WE8ISO8859P1', 'ISO-8859-1', 't', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_GB', 'English (GB)', 'en', 'GB', 'ENGLISH', 'GREAT BRITAIN', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('de_DE', 'German (DE)', 'de', 'DE', 'GERMAN', 'GERMANY', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_ES', 'Spanish (ES)', 'es', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ast_ES', 'Asturian (ES)', 'ast', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('gl_ES', 'Galician (ES)', 'gl', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_FR', 'French (FR)', 'fr', 'FR', 'FRENCH', 'FRANCE', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ja_JP', 'Japanese (JP)', 'ja', 'JP', 'JAPANESE', 'JAPAN', 'JA16SJIS', 'Shift_JIS', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('da_DK', 'Danish (DK)', 'da', 'DK', 'DANISH', 'DENMARK', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('sv_SE', 'Swedish (SE)', 'sv', 'SE', 'SWEDISH', 'SWEDEN', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fi_FI', 'Finnish (FI)', 'fi', 'FI', 'FINNISH', 'FINLAND', 'WE8ISO8859P15', 'ISO-8859-15', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nl_NL', 'Dutch (NL)', 'nl', 'NL', 'DUTCH', 'THE NETHERLANDS', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_CN', 'Chinese (CN)', 'zh', 'CN', 'SIMPLIFIED CHINESE', 'CHINA', 'ZHT32EUC', 'ISO-2022-CN', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pl_PL', 'Polish (PL)', 'pl', 'PL', 'POLISH', 'POLAND', 'EE8ISO8859P2', 'ISO-8859-2', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('no_NO', 'Norwegian (NO)', 'no', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('tl_PH', 'Tagalog (PH)', 'tl', 'PH', 'TAGALOG', 'PHILIPPINES', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('el_GR', 'Greek (GR)', 'el', 'GR', 'GREEK', 'GREECE', 'EL8ISO8859P7', 'ISO-8859-7', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('it_IT', 'Italian (IT)', 'it', 'IT', 'ITALIAN', 'ITALY', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ru_RU', 'Russian (RU)', 'ru', 'RU', 'RUSSIAN', 'CIS', 'RU8PC855', 'windows-1251', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('si_LK', 'Sinhalese (LK)','si', 'LK', 'ENGLISH', 'UNITED KINGDOM', 'UTF8', 'ISO-10646-UTF-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('sh_HR', 'Serbo-Croatian (SR/HR)', 'sr', 'YU', 'SLOVENIAN', 'SLOVENIA', 'YUG7ASCII', 'ISO-8859-5', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nn_NO', 'Norwegian (NN)','nn', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pt_BR', 'Portuguese (BR)', 'pt', 'BR', 'BRAZILIAN PORTUGUESE', 'BRAZIL', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pt_PT', 'Portuguese (PT)', 'pt', 'PT', 'PORTUGUESE', 'PORTUGAL', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('th_TH', 'Thai (TH)', 'th', 'TH', 'THAI', 'THAILAND', 'TH8TISASCII', 'TIS-620', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_EG', 'Arabic (EG)', 'ar', 'EG', 'ARABIC', 'EGYPT', 'AR8ISO8859P6', 'ISO-8859-6', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_LB', 'Arabic (LB)', 'ar', 'LB', 'ARABIC', 'LEBANON', 'AR8ISO8859P6', 'ISO-8859-6', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('tr_TR', 'Turkish (TR)', 'tr', 'TR', 'TURKISH', 'TURKEY', 'WE8ISO8859P9', 'ISO-8859-9', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ms_MY', 'Malaysia (MY)', 'ms', 'MY', 'MALAY', 'MALAYSIA', 'US7ASCII', 'US-ASCII', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hi_IN', 'Hindi (IN)', 'hi', 'IN', 'HINDI', 'INDIA', 'UTF8', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ko_KR', 'Korean (KO)', 'ko', 'KR', 'KOREAN', 'KOREA', 'KO16KSC5601', 'EUC-KR', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_TW', 'Chinese (TW)', 'zh', 'TW', 'TRADITIONAL CHINESE', 'TAIWAN', 'ZHT16BIG5', 'Big5', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hu_HU', 'Hungarian (HU)', 'hu', 'HU', 'HUNGARIAN', 'HUNGARY', 'EE8ISO8859P2', 'ISO-8859-2', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fa_IR', 'Farsi (IR)', 'fa', 'IR', 'FARSI', 'IRAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ro_RO', 'Romainian (RO)', 'ro', 'RO', 'ROMAINIAN', 'ROMAINIA', 'EE8ISO8859P2', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hr_HR', 'Croatian (HR)', 'hr', 'HR', 'CROATIAN', 'CROATIA','UTF8','UTF-8','t','f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_GT', 'Spanish (GT)', 'es', 'GT', 'SPANISH', 'GUATEMALA', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('eu_ES', 'Basque (ES)', 'eu', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ca_ES', 'Catalan (ES)', 'ca', 'ES', 'SPANISH', 'SPAIN','WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_CO', 'Spanish (CO)', 'es', 'CO', 'SPANISH', 'COLOMBIA', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ind_ID', 'Bahasa Indonesia (ID)', 'id', 'ID', 'INDONESIAN', 'INDONESIA', 'WEB8ISO8559P1', 'ISO-8559-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('bg_BG', 'Bulgarian (BG)', 'bg', 'BG', 'Bulgarian', 'BULGARIAN_BULGARIA', 'CL8ISO8859P5', 'windows-1251', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pa_IN', 'Punjabi', 'pa', 'IN', 'Punjabi', 'India', 'UTF8', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_BE', 'French (BE)', 'fr', 'BE', 'French (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nl_BE', 'Dutch (BE)', 'nl', 'BE', 'Dutch (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_CA', 'English (CA)', 'en', 'CA', 'English (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_CA', 'French (CA)', 'fr', 'CA', 'French (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_HK', 'Simplified Chinese (HK)', 'zh', 'HK', 'Simplified Chinese (Hong Kong)', 'Hong Kong', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('cz_CZ', 'Czech (CZ)', 'cs', 'CZ', 'Czech (Czech Republic)', 'Czech Republic', 'EE8ISO8859P2', 'ISO-8859-2', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_EC', 'Spanish (EC)', 'es', 'EC', 'Spanish', 'Ecuador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('et_EE', 'Estonian (EE)', 'et', 'EE', 'Estonian', 'Estonia', 'BLT8', 'ISO-8859-15', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('is_IS', 'Icelandic (IS)', 'is', 'IS', 'Icelandic', 'Iceland', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lt_LT', 'Lithuanian (LT)', 'lt', 'LT', 'Lithuanian', 'Lithuania', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lv_LV', 'Latvian (LV)', 'lv', 'LV', 'Latvian', 'Latvia', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_MX', 'Spanish (MX)', 'es', 'MX', 'Mexican Spanish', 'Mexico', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PA', 'Spanish (PA)', 'es', 'PA', 'Spanish (Panama)', 'Panama', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PY', 'Spanish (PY)', 'es', 'PY', 'Spanish (Paraguay)', 'Paraguay', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_SV', 'Spanish (SV)', 'es', 'SV', 'Spanish (El Salvador)', 'El Salvador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('uk_UA', 'Ukranian (UA)', 'uk', 'UA', 'Ukranian', 'Ukraine', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_VE', 'Spanish (VE)', 'es', 'VE', 'Spanish (Venezuela)', 'Venezuela', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/0000755000175000017500000000000011575225524021741 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d5-4.7d6.sql0000644000175000017500000000202707736530420025407 0ustar frankiefrankiedeclare v_table_exists_p integer; begin select count(*) into v_table_exists_p from user_objects where object_name = 'AD_LOCALE_USER_PREFS'; if v_table_exists_p = 0 then -- Need to create table execute immediate 'create table ad_locale_user_prefs ( user_id integer constraint ad_locale_user_prefs_users_fk references users (user_id) on delete cascade, package_id integer constraint lang_package_l_u_package_id_fk references apm_packages(package_id) on delete cascade, locale varchar(30) not null constraint trb_language_preference_lid_fk references ad_locales (locale) on delete cascade )'; end if; end; / show errors openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.0d1-5.0d2.sql0000644000175000017500000000102607734005221025353 0ustar frankiefrankieinsert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('AR_LB', 'Arabic (AR_LB)', 'AR ', 'LB', 'ARABIC', 'LEBANON', 'AR8ISO8859P6', 'ISO-8859-6', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pt_PT', 'Portuguese (PT)', 'pt', 'PT', 'PORTUGUESE', 'PORTUGAL', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.4.1d2-5.4.1d3.sql0000644000175000017500000000030311022567606025665 0ustar frankiefrankie-- packages/acs-lang/sql/oracle/upgrade/upgrade-5.4.1d2-5.4.1d3.sql -- alter table user_preferences add constraint user_preferences_locale_fk foreign key (locale) references ad_locales(locale); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.1.1d1-5.1.1d2.sql0000644000175000017500000001562610070240703025657 0ustar frankiefrankie-- @author Rocael Hernandez roc@viaro.net -- Add some new locales insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_GT', 'Spanish (GT)', 'es', 'GT', 'SPANISH', 'GUATEMALA', 'WE8DEC', 'ISO-8859-1', 't', 'f'); -- resolves bug 1519 ---------------------------------------------------------------------- -- ch_ZH -> zh_CN insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_CN', 'Chinese (CN)', 'CH', 'ZH', 'SIMPLIFIED CHINESE', 'CHINA', 'ZHT32EUC', 'ISO-2022-CN', 't', 'f'); update ad_locale_user_prefs set locale='zh_CN' where locale='ch_zh'; update lang_messages set locale='zh_CN' where locale='ch_zh'; update lang_messages_audit set locale='zh_CN' where locale='ch_zh'; update lang_translation_registry set locale='zh_CN' where locale='ch_zh'; delete from ad_locales where locale = 'ch_zh'; ---------------------------------------------------------------------- -- TH_TH -> th_TH insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('th_TH', 'Thai (TH)temp', 'th', 'TH', 'THAI', 'THAILAND', 'TH8TISASCII', 'TIS-620', 't', 'f'); update ad_locale_user_prefs set locale='th_TH' where locale='TH_TH'; update lang_messages set locale='th_TH' where locale='TH_TH'; update lang_messages_audit set locale='th_TH' where locale='TH_TH'; update lang_translation_registry set locale='th_TH' where locale='TH_TH'; delete from ad_locales where locale = 'TH_TH'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Thai (TH)' where locale = 'th_TH'; ---------------------------------------------------------------------- -- AR_EG -> ar_EG insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_EG', 'Arabic (EG)temp', 'ar', 'EG', 'ARABIC', 'EGYPT', 'AR8ISO8859P6', 'ISO-8859-6', 'f', 'f'); update ad_locale_user_prefs set locale='ar_EG' where locale='AR_EG'; update lang_messages set locale='ar_EG' where locale='AR_EG'; update lang_messages_audit set locale='ar_EG' where locale='AR_EG'; update lang_translation_registry set locale='ar_EG' where locale='AR_EG'; delete from ad_locales where locale = 'AR_EG'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Arabic (EG)' where locale = 'ar_EG'; ---------------------------------------------------------------------- -- AR_LB -> ar_LB insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_LB', 'Arabic (LB)temp', 'ar', 'LB', 'ARABIC', 'LEBANON', 'AR8ISO8859P6', 'ISO-8859-6', 't', 'f'); update ad_locale_user_prefs set locale='ar_LB' where locale='AR_LB'; update lang_messages set locale='ar_LB' where locale='AR_LB'; update lang_messages_audit set locale='ar_LB' where locale='AR_LB'; update lang_translation_registry set locale='ar_LB' where locale='AR_LB'; delete from ad_locales where locale = 'AR_LB'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Arabic (LB)' where locale = 'ar_LB'; ---------------------------------------------------------------------- -- ms_my -> ms_MY insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ms_MY', 'Malaysia (MY)temp', 'ms', 'MY', 'MALAY', 'MALAYSIA', 'US7ASCII', 'US-ASCII', 't', 'f'); update ad_locale_user_prefs set locale='ms_MY' where locale='ms_my'; update lang_messages set locale='ms_MY' where locale='ms_my'; update lang_messages_audit set locale='ms_MY' where locale='ms_my'; update lang_translation_registry set locale='ms_MY' where locale='ms_my'; delete from ad_locales where locale = 'ms_my'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Malaysia (MY)' where locale = 'ms_MY'; ---------------------------------------------------------------------- -- RO_RO -> ro_RO insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ro_RO', 'Romainian (RO)temp', 'ro', 'RO', 'ROMAINIAN', 'ROMAINIA', 'EE8ISO8859P2', 'UTF-8', 't', 'f'); update ad_locale_user_prefs set locale='ro_RO' where locale='RO_RO'; update lang_messages set locale='ro_RO' where locale='RO_RO'; update lang_messages_audit set locale='ro_RO' where locale='RO_RO'; update lang_translation_registry set locale='ro_RO' where locale='RO_RO'; delete from ad_locales where locale = 'RO_RO'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Romainian (RO)' where locale = 'ro_RO'; ---------------------------------------------------------------------- -- FA_IR -> fa_IR insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fa_IR', 'Farsi (IR)temp', 'fa', 'IR', 'FARSI', 'IRAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); update ad_locale_user_prefs set locale='fa_IR' where locale='FA_IR'; update lang_messages set locale='fa_IR' where locale='FA_IR'; update lang_messages_audit set locale='fa_IR' where locale='FA_IR'; update lang_translation_registry set locale='fa_IR' where locale='FA_IR'; delete from ad_locales where locale = 'FA_IR'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Farsi (IR)' where locale = 'fa_IR'; ---------------------------------------------------------------------- -- HR_HR -> hr_HR insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hr_HR', 'Croatian (HR)temp', 'hr', 'HR', 'CROATIAN', 'CROATIA','UTF8','UTF-8','t','f'); update ad_locale_user_prefs set locale='hr_HR' where locale='HR_HR'; update lang_messages set locale='hr_HR' where locale='HR_HR'; update lang_messages_audit set locale='hr_HR' where locale='HR_HR'; update lang_translation_registry set locale='hr_' where locale='HR_HR'; delete from ad_locales where locale = 'HR_HR'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Croatian (HR)' where locale = 'hr_HR'; ---------------------------------------------------------------------- -- trim some trailing spaces update ad_locales set language='tr' where language='tr '; update ad_locales set language='hi' where language='hi '; update ad_locales set language='ko' where language='ko '; update ad_locales set language='zh' where language='zh '; update ad_locales set language='hu' where language='hu '; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.0.0b4-5.0.0b5.sql0000644000175000017500000000355710017410254025656 0ustar frankiefrankie-- Datamodel changes in message-catalog.sql related to the new message catalog upgrade support. -- See Tcl proc lang::catalog::import_messages. -- -- @author Peter Marklund -- Changes to lang_message_keys table -- Column not needed as en_US row in lang_messages table has same info alter table lang_message_keys drop column upgrade_status; -- Add new columns to the lang_messages table alter table lang_messages add deleted_p char(1) default 'f' constraint lang_messages_dp_ck check (deleted_p in ('t','f')); alter table lang_messages add sync_time date; alter table lang_messages add conflict_p char(1) default 'f' constraint lang_messages_cp_ck check (conflict_p in ('t','f')); update lang_messages set deleted_p = 'f', conflict_p = 'f'; -- Add new columns to the lang_messages_audit tables alter table lang_messages_audit add deleted_p char(1) default 'f' constraint lang_messages_audit_dp_ck check (deleted_p in ('t','f')); alter table lang_messages_audit add sync_time date; alter table lang_messages_audit add conflict_p char(1) default 'f' constraint lang_messages_audit_cp_ck check (conflict_p in ('t','f')); alter table lang_messages_audit add upgrade_status varchar2(30) constraint lang_messages_audit_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')); update lang_messages_audit set deleted_p = 'f', conflict_p = 'f', upgrade_status = 'no_upgrade'; -- Missing this primary key made some queries below very slow alter table lang_messages_audit add constraint lang_messages_audit_pk primary key (package_key, message_key, locale, overwrite_date); -- We have to leave sync_time null since we don't know when the messages in the db were last in sync -- with the catalog files openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d8-4.7d9.sql0000644000175000017500000000273107732616011025414 0ustar frankiefrankie-- New locales from the translation server insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('AR_EG', 'Arabic (AR_EG)', 'AR ', 'EG', 'ARABIC', 'EGYPT', 'AR8ISO8859P6', 'ISO-8859-6', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('tr_TR', 'Turkish (TR)', 'tr ', 'TR', 'TURKISH', 'TURKEY', 'WE8ISO8859P9', 'ISO-8859-9', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ms_my', 'Malaysia (MY)', 'ms ', 'MY', 'MALAY', 'MALAYSIA', 'US7ASCII', 'US-ASCII', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('hi_IN', 'Hindi (IN)', 'hi ', 'IN', 'HINDI', 'INDIA', 'UTF8', 'UTF-8', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ko_KR', 'Korean(KOR)', 'ko ', 'KR', 'KOREAN', 'KOREA', 'KO16KSC5601', 'EUC-KR', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('zh_TW', 'Chinese (TW)', 'zh ', 'TW', 'TRADITIONAL CHINESE', 'TAIWAN', 'ZHT16BIG5', 'Big5', 't'); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.6.0d1-5.6.0d2.sql0000644000175000017500000000045211321666756025702 0ustar frankiefrankie-- Fix wrong data in ad_locales update ad_locales set language = 'ar' where language = 'AR'; update ad_locales set language = 'ind' where locale = 'ind_ID'; update ad_locales set language = 'cs' where locale = 'cz_CZ'; update ad_locales set language = 'zh', country = 'HK' where locale = 'zh_HK'; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d4-4.7d5.sql0000644000175000017500000000776207621261165025420 0ustar frankiefrankie-- Upgrade script that adds new locale from the dotLRN translation server insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('fi_FI', 'Finnish (FI)', 'fi', 'FI', 'FINNISH', 'FINLAND', 'WE8ISO8859P15', 'ISO-8859-15', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('nl_NL', 'Dutch (NL)', 'nl', 'NL', 'DUTCH', 'THE NETHERLANDS', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ch_zh', 'Chinese (ZH)', 'CH', 'ZH', 'SIMPLIFIED CHINESE', 'CHINA', 'ZHT32EUC', 'ISO-2022-CN', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('pl_PL', 'Polish (PL)', 'pl', 'PL', 'POLISH', 'POLAND', 'EE8ISO8859P2', 'ISO-8859-2', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('no_NO', 'Norwegian (NO)', 'no', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('tl_PH', 'Tagalog (PH)', 'tl', 'PH', 'AMERICAN', 'ALGERIA', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('el_GR', 'Greek (GR)', 'el', 'GR', 'GREEK', 'GREECE', 'EL8ISO8859P7', 'ISO-8859-7', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('it_IT', 'Italian (IT)', 'it', 'IT', 'ITALIAN', 'ITALY', 'WE8DEC', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ru_RU', 'Russian (RU)', 'ru', 'RU', 'RUSSIAN', 'CIS', 'RU8PC855', 'windows-1251', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('si_LK', 'Sinhalese (LK)','si', 'LK', 'ENGLISH', 'UNITED KINGDOM', 'UTF8', 'ISO-10646-UTF-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('sh_HR', 'Serbo-Croatian (SR/HR)', 'sr', 'YU', 'SLOVENIAN', 'SLOVENIA', 'YUG7ASCII', 'ISO-8859-5', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('nn_NO', 'Norwegian (NN)','nn', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('pt_BR', 'Portuguese (BR)', 'pt', 'BR', 'BRAZILIAN PORTUGUESE', 'BRAZIL', 'WE8ISO8859P1', 'ISO-8859-1', 't' ); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('TH_TH', 'Thai (TH)', 'th', 'TH', 'THAI', 'THAILAND', 'TH8TISASCII', 'TIS-620', 't'); -- Forgot to add this locale earlier, some installations may have it already declare v_locale_exists_p integer; begin select count(*) into v_locale_exists_p from ad_locales where locale = 'sv_SE'; if v_locale_exists_p = 0 then insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('sv_SE', 'Swedish (SE)', 'sv', 'SE', 'SWEDISH', 'SWEDEN', 'WE8ISO8859P1', 'ISO-8859-1', 't'); end if; end; / show errors openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.6.0d2-5.6.0d3.sql0000644000175000017500000000122011456662500025666 0ustar frankiefrankie-- update comment on ad_locales to be more accurate about how to -- create new locales. comment on table ad_locales is ' An OpenACS locale is identified by a language and country. Locale definitions in Oracle consist of a language, and optionally territory and character set. (Languages are associated with default territories and character sets when not defined). The formats for numbers, currency, dates, etc. are determined by the territory. language is the shortest ISO 639 code (lowercase). country is two letter (uppercase) abbrev is ISO 3166 country code mime_charset is IANA charset name nls_charset is Oracle charset name '; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d7-4.7d8.sql0000644000175000017500000000046407627106237025422 0ustar frankiefrankie-- Make message keys cascade when packages are deleted alter table lang_message_keys drop constraint lang_message_keys_fk; alter table lang_message_keys add constraint lang_message_keys_fk foreign key (package_key) references apm_package_types(package_key) on delete cascade; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d9-5.0d1.sql0000644000175000017500000000306107720125556025402 0ustar frankiefrankie-- -- Oracle upgrade script from 4.7d9 to 5.0d1 -- -- 1. Adds an enabled_p flag to ad_locales. -- -- 2. Adds a comment field to lang_messages_audit -- -- 3. Renames the lang_messages_audit.message column to 'old_message' in order to make the meaning more clear. -- -- 4. Adds a description column to lang_message_keys. -- -- @author Simon Carstensen (simon@collaboraid.biz) -- @author Lars Pind (lars@collaboraid.biz) -- -- @creation-date 2003-08-11 -- @cvs-id $Id: upgrade-4.7d9-5.0d1.sql,v 1.3 2003/08/18 10:33:18 lars Exp $ -- -- 1. Adds an enabled_p flag to ad_locales. -- New enabled_p column in ad_locales alter table ad_locales add enabled_p char(1) default 't' constraint ad_locale_enp_tf check(enabled_p in ('t','f')); -- Let all locales be enabled for sites that are upgrading update ad_locales set enabled_p = 't'; -- New view create or replace view enabled_locales as select * from ad_locales where enabled_p = 't'; -- 2. Adds a comment field to lang_messages_audit -- Add a comment field to the message audit table alter table lang_messages_audit add comment_text clob; commit; -- 3. Renames the lang_messages_audit.message column to 'old_message' in order to make the meaning more clear. -- Rename the coclumn 'message' to 'old_message' in the lang_messages_audit table alter table lang_messages_audit add old_message clob; update lang_messages_audit set old_message = message; commit; alter table lang_messages_audit drop (message); -- 4. Adds a description column to lang_message_keys. alter table lang_message_keys add description clob; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d3-4.7d4.sql0000644000175000017500000000253407736273727025424 0ustar frankiefrankiealter table lang_message_keys add upgrade_status varchar2(30) constraint lang_message_keys_us_ck check (upgrade_status in ('no_upgrade', 'added','deleted')); alter table lang_messages add upgrade_status varchar2(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')); create table lang_messages_audit ( message_key varchar2(200) constraint lang_messages_audit_key_nn not null, package_key varchar2(100) constraint lang_messages_audit_p_key_nn not null, locale varchar2(30) constraint lang_messages_audit_l_fk references ad_locales(locale) constraint lang_messages_audit_l_nn not null, message clob, overwrite_date date default sysdate not null, overwrite_user integer constraint lang_messages_audit_ou_fk references users (user_id), constraint lang_messages_audit_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade ); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.3.0d1-5.3.0d2.sql0000644000175000017500000001114010447161764025665 0ustar frankiefrankie-- -- -- -- @author Torben Brosten (torben@kappacorp.com) -- @creation-date 2006-06-22 -- @arch-tag: -- @cvs-id $Id: -- --new locales for oacs-5-2 --these locales from sql-ledger for accounts-* and related packages insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_BE', 'French (BE)', 'fr', 'BE', 'French (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nl_BE', 'Dutch (BE)', 'nl', 'BE', 'Dutch (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_CA', 'English (CA)', 'ca', 'EN', 'English (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_CA', 'French (CA)', 'ca', 'FR', 'French (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_HK', 'Chinese, Simplified (HK)', 'hk', 'ZH', 'Simplified Chinese (Hong Kong)', 'Hong Kong', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('cz_CZ', 'Czech (CZ)', 'cz', 'CZ', 'Czech (Czech Republic)', 'Czech Republic', 'EE8ISO8859P2', 'ISO-8859-2', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_EC', 'Spanish (EC)', 'es', 'EC', 'Spanish', 'Ecuador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('et_EE', 'Estonian (EE)', 'et', 'EE', 'Estonian', 'Estonia', 'BLT8', 'ISO-8859-15', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('is_IS', 'Icelandic (IS)', 'is', 'IS', 'Icelandic', 'Iceland', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lt_LT', 'Lithuanian (LT)', 'lt', 'LT', 'Lithuanian', 'Lithuania', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lv_LV', 'Latvian (LV)', 'lv', 'LV', 'Latvian', 'Latvia', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_MX', 'Spanish (MX)', 'es', 'MX', 'Mexican Spanish', 'Mexico', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PA', 'Spanish (PA)', 'es', 'PA', 'Spanish (Panama)', 'Panama', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PY', 'Spanish (PY)', 'es', 'PY', 'Spanish (Paraguay)', 'Paraguay', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_SV', 'Spanish (SV)', 'es', 'SV', 'Spanish (El Salvador)', 'El Salvador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('uk_UA', 'Ukranian (UA)', 'uk', 'UA', 'Ukranian', 'Ukraine', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_VE', 'Spanish (VE)', 'es', 'VE', 'Spanish (Venezuela)', 'Venezuela', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.2.3d1-5.2.3d2.sql0000644000175000017500000000242610440426463025671 0ustar frankiefrankie-- -- -- -- @author Victor Guerra (guerra@galileo.edu) -- @creation-date 2006-01-26 -- @arch-tag: dc7aa6da-eb77-48df-9d42-6c3fb2d4ddcb -- @cvs-id $Id: upgrade-5.2.3d1-5.2.3d2.sql,v 1.2 2006/06/04 00:45:39 donb Exp $ -- --new locales for oacs-5-2 insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_CO', 'Spanish (CO)', 'es', 'CO', 'SPANISH', 'COLOMBIA', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ind_ID', 'Bahasa Indonesia (ID)', 'in', 'ID', 'INDONESIAN', 'INDONESIA', 'WEB8ISO8559P1', 'ISO-8559-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('bg_BG', 'Bulgarian (BG)', 'bg', 'BG', 'Bulgarian', 'BULGARIAN_BULGARIA', 'CL8ISO8859P5', 'windows-1251', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pa_IN', 'Punjabi', 'pa', 'IN', 'Punjabi', 'India', 'UTF8', 'UTF-8', 't', 'f'); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.0.0-5.0.1.sql0000644000175000017500000000422010017410254025166 0ustar frankiefrankie-- @author Peter Marklund -- Change the lang_messages_audit table to have a new integer primary key column create sequence lang_messages_audit_id_seq; alter table lang_messages_audit add audit_id integer; alter table lang_messages_audit drop constraint lang_messages_audit_pk; begin for one_row in (select message_key, package_key, locale, overwrite_date from lang_messages_audit order by overwrite_date ) loop update lang_messages_audit set audit_id = lang_messages_audit_id_seq.nextval where message_key = one_row.message_key and package_key = one_row.package_key and locale = one_row.locale and overwrite_date = one_row.overwrite_date; end loop; end; / show errors alter table lang_messages_audit add constraint lang_messages_audit_pk primary key (audit_id); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hu_HU', 'Hungarian (HU)', 'hu ', 'HU', 'HUNGARIAN', 'HUNGARY', 'EE8ISO8859P2', 'ISO-8859-2', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('FA_IR', 'Farsi', 'FA ', 'IR', 'AMERICAN', 'ALGERIAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('RO_RO', 'Romainian', 'RO ', 'RO', 'ROMAINIAN', 'ROMAINIA', 'EE8ISO8859P2', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('HR_HR', 'Croatian', 'HR', 'HR', 'CROATIAN', 'CROATIA','UTF8','UTF-8','t','f'); -- fix http://openacs.org/bugtracker/openacs/bug?bug%5fnumber=1464 update ad_locales set nls_language='TAGALOG', nls_territory='PHILIPPINES' where locale = 'tl_PH'; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.1.2d2-5.1.2d3.sql0000644000175000017500000000104610171476716025673 0ustar frankiefrankie-- @author Joel Aufrecht -- Add new locales insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('eu_ES', 'Basque (ES)', 'eu', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ca_ES', 'Catalan (ES)', 'ca', 'ES', 'SPANISH', 'SPAIN','WE8DEC', 'ISO-8859-1', 't', 'f'); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d6-4.7d7.sql0000644000175000017500000000014307624264771025417 0ustar frankiefrankie-- We now allow for three character language codes alter table ad_locales modify language char(3); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.0d2-5.0d3.sql0000644000175000017500000000042207733560655025374 0ustar frankiefrankiealter table lang_messages add creation_date date default sysdate not null; alter table lang_messages add creation_user integer constraint lang_messages_create_u_fk references users (user_id); openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-5.4.1d1-5.4.1d2.sql0000644000175000017500000000043011022567606025664 0ustar frankiefrankie-- packages/acs-lang/sql/oracle/upgrade/upgrade-5.4.1d1-5.4.1d2.sql -- -- language and country codes for Canada were wrong (ca, EN/FR) update ad_locales set language='en', country='CA' where locale='en_CA'; update ad_locales set language='fr', country='CA' where locale='fr_CA'; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.1-4.7d2.sql0000644000175000017500000000422207552553264025152 0ustar frankiefrankie-- -- Upgrade script from 4.1 to 4.7 -- -- Changes lang_messages so it uses locale instead of language -- by looking up the default locale in ad_locales. -- -- There two things that could go wrong here: -- -- 1. There could be no locale at all for some language -- in that case the scripts adds a new locale -- 2. There could be no default locale -- the script makes sure that theres is one default locale -- pr. language -- -- @author Christian Hvid -- -- Make sure that there is a default for every language UPDATE ad_locales SET default_p = 't' WHERE (SELECT count(*) FROM ad_locales a WHERE a.language = ad_locales.language AND default_p='t') = 0; -- Make sure that there is a locale for every language used in lang_messages INSERT INTO ad_locales (language, locale, country, label, nls_language, default_p) SELECT language, language || '_' || UPPER(language) as locale, '??' as country, 'Locale created by upgrade-4.1-4.7 for language ' || language as label, '??' as nls_language, 't' as default_p FROM ((SELECT DISTINCT lang as language FROM lang_messages) MINUS (SELECT DISTINCT language FROM ad_locales)); create table temp ( key varchar(200), lang varchar(2), message clob, registered_p char(1) ); INSERT INTO temp(key, lang, message, registered_p) SELECT key, lang, message, registered_p FROM lang_messages; DROP TABLE lang_messages; create table lang_messages ( key varchar2(200), locale varchar2(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message clob, registered_p char(1) constraint lm_tranlated_p_ck check(registered_p in ('t','f')), constraint lang_messages_pk primary key (key, locale) ); INSERT INTO lang_messages(key, locale, message, registered_p) SELECT key, ad_locales.locale, message, registered_p FROM temp, ad_locales WHERE ad_locales.language = temp.lang; DROP TABLE temp; openacs-5.7.0/packages/acs-lang/sql/oracle/upgrade/upgrade-4.7d2-4.7d3.sql0000644000175000017500000000457007554763535025423 0ustar frankiefrankie-- -- Upgrade script from 4.7d2 to 4.7d3 -- -- Split message keys and remove registered_p -- Copy all messages to a temporary table create table temp ( key varchar2(200), locale varchar2(30), message clob ); INSERT INTO temp(key, locale, message) SELECT key, locale, message FROM lang_messages; -- drop old table DROP TABLE lang_messages; -- create new table create table lang_message_keys ( message_key varchar2(200) constraint lang_message_keys_m_key_nn not null, package_key varchar2(100) constraint lang_message_keys_fk references apm_package_types(package_key) constraint lang_message_keys_p_key_nn not null, constraint lang_message_keys_pk primary key (message_key, package_key) ); create table lang_messages ( message_key varchar2(200) constraint lang_messages_message_key_nn not null, package_key varchar2(100) constraint lang_messages_package_key_nn not null, locale varchar2(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message clob, constraint lang_messages_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade, constraint lang_messages_pk primary key (message_key, package_key, locale) ); -- insert old data -- into lang_message_keys INSERT INTO lang_message_keys(message_key, package_key) SELECT DISTINCT SUBSTR(key, INSTR(key, '.')+1) message_key, SUBSTR(key, 0, INSTR(key, '.')-1) package_key FROM temp, apm_package_types WHERE SUBSTR(key, 0, INSTR(key, '.')-1) = package_key; -- into lang_messages INSERT INTO lang_messages(message_key, package_key, locale, message) SELECT SUBSTR(key, INSTR(key, '.')+1) message_key, SUBSTR(key, 0, INSTR(key, '.')-1) package_key, locale, message FROM temp, apm_package_types WHERE SUBSTR(key, 0, INSTR(key, '.')-1) = package_key; DROP TABLE temp; openacs-5.7.0/packages/acs-lang/sql/oracle/message-catalog-drop.sql0000644000175000017500000000142010016636574025026 0ustar frankiefrankie-- -- packages/language/sql/language-drop.sql -- -- @author davis@arsdigita.com -- @creation-date 2000-09-10 -- @cvs-id $Id: message-catalog-drop.sql,v 1.6 2004/02/24 12:03:08 jeffd Exp $ -- -- drop the timezone stuff drop index tz_data_idx2; drop index tz_data_idx1; drop table tz_data; drop function lc_time_utc_to_local; drop function lc_time_local_to_utc; -- drop the lang stuff drop table lang_translation_registry; drop table lang_translate_columns; drop table lang_messages_audit; drop table lang_messages; drop table lang_message_keys; drop table lang_user_timezone; -- This might fail if the data model includes other multilingual tables -- that reference ad_locales. Really need to cascade here to ensure -- it goes away, but that is dangerous. -- drop table ad_locales; openacs-5.7.0/packages/acs-lang/sql/oracle/acs-lang-drop.sql0000644000175000017500000000024210016636574023460 0ustar frankiefrankie-- Author: Jon Griffin (jon@jongriffin.com) -- $Id: acs-lang-drop.sql,v 1.1 2004/02/24 12:03:08 jeffd Exp $ @@ message-catalog-drop.sql @@ ad-locales-drop.sql openacs-5.7.0/packages/acs-lang/sql/postgresql/0000755000175000017500000000000011575225524021250 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/sql/postgresql/acs-lang-create.sql0000644000175000017500000000104507376550000024711 0ustar frankiefrankie-- Data model to support i18n of the ArsDigita Community -- System -- Copyright (C) 1999-2000 ArsDigita Corporation -- Author: Henry Minsky (hqm@arsdigita.com) -- $Id: acs-lang-create.sql,v 1.2 2001/11/20 21:49:52 donb Exp $ -- This is free software distributed under the terms of the GNU Public -- License. Full text of the license is available from the GNU Project: -- http://www.fsf.org/copyleft/gpl.html -- prompt ** Creating locales table ... \i ad-locales.sql -- prompt ** Creating translation catalog tables ... \i message-catalog.sql openacs-5.7.0/packages/acs-lang/sql/postgresql/ad-locales-drop.sql0000644000175000017500000000126011456662500024733 0ustar frankiefrankie-- -- packages/language/sql/language-create.sql -- -- @author Jeff Davis (davis@xarg.net) -- @creation-date 2000-09-10 -- @cvs-id $Id: ad-locales-drop.sql,v 1.5 2010/10/17 21:06:08 donb Exp $ -- -- **************************************************************************** -- * The lang_messages table holds the message catalog. -- * It is populated by ad_lang_message_register. -- * The registered_p flag denotes that a message exists in a file -- * that gets loaded on server startup, and hence should not get updated. -- **************************************************************************** drop table ad_locale_user_prefs; drop view enabled_locales; drop table ad_locales; openacs-5.7.0/packages/acs-lang/sql/postgresql/message-catalog.sql0000644000175000017500000001370210506037350025017 0ustar frankiefrankie -- -- packages/acs-lang/sql/postgresql/message-catalog.sql -- -- @author Jeff Davis (davis@xarg.net) -- @author Christian Hvid -- @creation-date 2000-09-10 -- @cvs-id $Id: message-catalog.sql,v 1.17 2006/09/25 20:41:12 byronl Exp $ -- begin; create table lang_user_timezone ( user_id integer constraint lang_user_timezone_user_id_fk references users (user_id) on delete cascade, timezone varchar(30) ); create table lang_message_keys ( message_key varchar(200) constraint lang_message_keys_message_key_nn not null, package_key varchar(100) constraint lang_message_keys_pkg_key_fk references apm_package_types(package_key) on delete cascade constraint lang_message_keys_package_key_nn not null, description text, constraint lang_message_keys_pk primary key (message_key, package_key) ); create table lang_messages ( message_key varchar(200) constraint lang_messages_message_key_nn not null, package_key varchar(100) constraint lang_messages_package_key_nn not null, locale varchar(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message text, deleted_p boolean default 'f', sync_time timestamptz, conflict_p boolean default 'f', upgrade_status varchar(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')), creation_date timestamptz default now() not null, creation_user integer constraint lang_messages_creation_user_fk references users (user_id), constraint lang_messages_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade, constraint lang_messages_pk primary key (message_key, package_key, locale) ); create table lang_messages_audit ( audit_id integer constraint lang_messages_audit_pk primary key, message_key varchar(200) constraint lang_messages_audit_key_nn not null, package_key varchar(100) constraint lang_messages_audit_p_key_nn not null, locale varchar(30) constraint lang_messages_audit_locale_fk references ad_locales(locale) constraint lang_messages_audit_l_nn not null, -- The old, overwritten message, not the new message being -- entered on this date by this user. old_message text, deleted_p boolean default 'f', sync_time timestamptz, conflict_p boolean default 'f', upgrade_status varchar(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')), comment_text text, overwrite_date timestamptz default now() not null, overwrite_user integer constraint lang_messages_audit_ou_fk references users (user_id), constraint lang_messages_audit_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade ); create sequence lang_messages_audit_id_seq; -- **************************************************************************** -- * The lang_translate_columns table holds the columns that require translation. -- * It is needed to generate the user interface for translating the web site. -- * Note that we register on_what_column itself for translation. -- **************************************************************************** create table lang_translate_columns ( column_id integer constraint ltc_column_id_pk primary key, -- cant do references on user_tables cause oracle sucks on_which_table varchar(50), on_what_column varchar(50), -- -- whether all entries in a column must be translated for the -- site to function. -- -- probably ultimately need something more sophisticated than -- simply required_p -- required_p boolean, -- -- flag for whether to use the lang_translations table for content -- or add a row in the on_which_table table with the translated content. -- short_p boolean, constraint ltc_un unique (on_which_table, on_what_column) ); -- **************************************************************************** -- * The lang_translation_registry table identifies a row as requiring translation -- * to a given language. This should identify the parent table not the broken-apart -- * child table. -- **************************************************************************** create table lang_translation_registry ( on_which_table varchar(50), on_what_id integer not null, locale varchar(30) constraint ltr_locale_fk references ad_locales(locale), -- -- should have dependency info here -- constraint lang_translation_registry_pk primary key(on_what_id, on_which_table, locale) ); end; openacs-5.7.0/packages/acs-lang/sql/postgresql/ad-locales.sql0000644000175000017500000004523211456662500024000 0ustar frankiefrankie-- -- packages/language/sql/language-create.sql -- -- @author Jeff Davis (davis@xarg.net) -- @creation-date 2000-09-10 -- @cvs-id $Id: ad-locales.sql,v 1.33 2010/10/17 21:06:08 donb Exp $ -- -- **************************************************************************** -- * The lang_messages table holds the message catalog. -- * It is populated by ad_lang_message_register. -- * The registered_p flag denotes that a message exists in a file -- * that gets loaded on server startup, and hence should not get updated. -- **************************************************************************** begin; create table ad_locales ( locale varchar(30) constraint ad_locales_locale_pk primary key, language char(3) constraint ad_locales_language_nn not null, country char(2) constraint ad_locales_country_nn not null, variant varchar(30), label varchar(200) constraint ad_locales_label_nn not null constraint ad_locales_label_un unique, nls_language varchar(30) constraint ad_locale_nls_lang_nn not null, nls_territory varchar(30), nls_charset varchar(30), mime_charset varchar(30), -- is this the default locale for its language default_p boolean default 'f', -- Determines which locales a user can choose from for the UI enabled_p boolean default 't' ); comment on table ad_locales is ' An OpenACS locale is identified by a language and country. Locale definitions in Oracle consist of a language, and optionally territory and character set. (Languages are associated with default territories and character sets when not defined). The formats for numbers, currency, dates, etc. are determined by the territory. language is the shortest ISO 639 code (lowercase). country is two letter (uppercase) abbrev is ISO 3166 country code mime_charset is IANA charset name nls_charset is Oracle charset name '; create view enabled_locales as select * from ad_locales where enabled_p = 't'; create table ad_locale_user_prefs ( user_id integer constraint ad_locale_user_prefs_users_fk references users (user_id) on delete cascade, package_id integer constraint lang_package_l_u_package_id_fk references apm_packages(package_id) on delete cascade, locale varchar(30) not null constraint ad_locale_user_prefs_locale_fk references ad_locales (locale) on delete cascade ); -- alter user_preferences to add the locale column alter table user_preferences add locale varchar(30) constraint user_preferences_locale_fk references ad_locales(locale); -- -- -- And now for some default locales -- -- insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_US', 'English (US)', 'en', 'US', 'AMERICAN', 'AMERICA', 'WE8ISO8859P1', 'ISO-8859-1', 't', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_GB', 'English (GB)', 'en', 'GB', 'ENGLISH', 'GREAT BRITAIN', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('de_DE', 'German (DE)', 'de', 'DE', 'GERMAN', 'GERMANY', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('de_CH', 'German (CH)', 'de', 'CH', 'GERMAN', 'SWITZERLAND', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_ES', 'Spanish (ES)', 'es', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ast_ES', 'Asturian (ES)', 'ast', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('gl_ES', 'Galician (ES)', 'gl', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_FR', 'French (FR)', 'fr', 'FR', 'FRENCH', 'FRANCE', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ja_JP', 'Japanese (JP)', 'ja', 'JP', 'JAPANESE', 'JAPAN', 'JA16SJIS', 'Shift_JIS', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('da_DK', 'Danish (DK)', 'da', 'DK', 'DANISH', 'DENMARK', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('sv_SE', 'Swedish (SE)', 'sv', 'SE', 'SWEDISH', 'SWEDEN', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fi_FI', 'Finnish (FI)', 'fi', 'FI', 'FINNISH', 'FINLAND', 'WE8ISO8859P15', 'ISO-8859-15', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nl_NL', 'Dutch (NL)', 'nl', 'NL', 'DUTCH', 'THE NETHERLANDS', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_CN', 'Chinese (CN)', 'zh', 'CN', 'SIMPLIFIED CHINESE', 'CHINA', 'ZHT32EUC', 'ISO-2022-CN', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pl_PL', 'Polish (PL)', 'pl', 'PL', 'POLISH', 'POLAND', 'EE8ISO8859P2', 'ISO-8859-2', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('no_NO', 'Norwegian (NO)', 'no', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('tl_PH', 'Tagalog (PH)', 'tl', 'PH', 'TAGALOG', 'PHILIPPINES', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('el_GR', 'Greek (GR)', 'el', 'GR', 'GREEK', 'GREECE', 'EL8ISO8859P7', 'ISO-8859-7', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('it_IT', 'Italian (IT)', 'it', 'IT', 'ITALIAN', 'ITALY', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ru_RU', 'Russian (RU)', 'ru', 'RU', 'RUSSIAN', 'CIS', 'RU8PC855', 'windows-1251', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('si_LK', 'Sinhalese (LK)','si', 'LK', 'ENGLISH', 'UNITED KINGDOM', 'UTF8', 'ISO-10646-UTF-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('sh_HR', 'Serbo-Croatian (SR/HR)', 'sr', 'YU', 'SLOVENIAN', 'SLOVENIA', 'YUG7ASCII', 'ISO-8859-5', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nn_NO', 'Norwegian (NN)','nn', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pt_BR', 'Portuguese (BR)', 'pt', 'BR', 'BRAZILIAN PORTUGUESE', 'BRAZIL', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pt_PT', 'Portuguese (PT)', 'pt', 'PT', 'PORTUGUESE', 'PORTUGAL', 'WE8ISO8859P1', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('th_TH', 'Thai (TH)', 'th', 'TH', 'THAI', 'THAILAND', 'TH8TISASCII', 'TIS-620', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_EG', 'Arabic (EG)', 'ar', 'EG', 'ARABIC', 'EGYPT', 'AR8ISO8859P6', 'ISO-8859-6', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_LB', 'Arabic (LB)', 'ar', 'LB', 'ARABIC', 'LEBANON', 'AR8ISO8859P6', 'ISO-8859-6', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('tr_TR', 'Turkish (TR)', 'tr', 'TR', 'TURKISH', 'TURKEY', 'WE8ISO8859P9', 'ISO-8859-9', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ms_MY', 'Malaysia (MY)', 'ms', 'MY', 'MALAY', 'MALAYSIA', 'US7ASCII', 'US-ASCII', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hi_IN', 'Hindi (IN)', 'hi', 'IN', 'HINDI', 'INDIA', 'UTF8', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ko_KR', 'Korean (KO)', 'ko', 'KR', 'KOREAN', 'KOREA', 'KO16KSC5601', 'EUC-KR', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_TW', 'Chinese (TW)', 'zh', 'TW', 'TRADITIONAL CHINESE', 'TAIWAN', 'ZHT16BIG5', 'Big5', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hu_HU', 'Hungarian (HU)', 'hu', 'HU', 'HUNGARIAN', 'HUNGARY', 'EE8ISO8859P2', 'ISO-8859-2', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fa_IR', 'Farsi (IR)', 'fa', 'IR', 'FARSI', 'IRAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ro_RO', 'Romainian (RO)', 'ro', 'RO', 'ROMAINIAN', 'ROMAINIA', 'EE8ISO8859P2', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hr_HR', 'Croatian (HR)', 'hr', 'HR', 'CROATIAN', 'CROATIA','UTF8','UTF-8','t','f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_GT', 'Spanish (GT)', 'es', 'GT', 'SPANISH', 'GUATEMALA', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('eu_ES', 'Basque (ES)', 'eu', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ca_ES', 'Catalan (ES)', 'ca', 'ES', 'SPANISH', 'SPAIN','WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_CO', 'Spanish (CO)', 'es', 'CO', 'SPANISH', 'COLOMBIA', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ind_ID', 'Bahasa Indonesia (ID)', 'id', 'ID', 'INDONESIAN', 'INDONESIA', 'WEB8ISO8559P1', 'ISO-8559-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('bg_BG', 'Bulgarian (BG)', 'bg', 'BG', 'Bulgarian', 'BULGARIAN_BULGARIA', 'CL8ISO8859P5', 'windows-1251', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pa_IN', 'Punjabi', 'pa', 'IN', 'Punjabi', 'India', 'UTF8', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_BE', 'French (BE)', 'fr', 'BE', 'French (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nl_BE', 'Dutch (BE)', 'nl', 'BE', 'Dutch (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_CA', 'English (CA)', 'en', 'CA', 'English (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_CA', 'French (CA)', 'fr', 'CA', 'French (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_HK', 'Chinese, Simplified (HK)', 'zh', 'HK', 'Simplified Chinese (Hong Kong)', 'Hong Kong', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('cz_CZ', 'Czech (CZ)', 'cs', 'CZ', 'Czech (Czech Republic)', 'Czech Republic', 'EE8ISO8859P2', 'ISO-8859-2', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_EC', 'Spanish (EC)', 'es', 'EC', 'Spanish', 'Ecuador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('et_EE', 'Estonian (EE)', 'et', 'EE', 'Estonian', 'Estonia', 'BLT8', 'ISO-8859-15', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('is_IS', 'Icelandic (IS)', 'is', 'IS', 'Icelandic', 'Iceland', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lt_LT', 'Lithuanian (LT)', 'lt', 'LT', 'Lithuanian', 'Lithuania', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lv_LV', 'Latvian (LV)', 'lv', 'LV', 'Latvian', 'Latvia', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_MX', 'Spanish (MX)', 'es', 'MX', 'Mexican Spanish', 'Mexico', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PA', 'Spanish (PA)', 'es', 'PA', 'Spanish (Panama)', 'Panama', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PY', 'Spanish (PY)', 'es', 'PY', 'Spanish (Paraguay)', 'Paraguay', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_SV', 'Spanish (SV)', 'es', 'SV', 'Spanish (El Salvador)', 'El Salvador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('uk_UA', 'Ukranian (UA)', 'uk', 'UA', 'Ukranian', 'Ukraine', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_VE', 'Spanish (VE)', 'es', 'VE', 'Spanish (Venezuela)', 'Venezuela', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); end; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/0000755000175000017500000000000011575225524022677 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.0d1-5.0d2.sql0000644000175000017500000000102607734005221026311 0ustar frankiefrankieinsert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('AR_LB', 'Arabic (AR_LB)', 'AR ', 'LB', 'ARABIC', 'LEBANON', 'AR8ISO8859P6', 'ISO-8859-6', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pt_PT', 'Portuguese (PT)', 'pt', 'PT', 'PORTUGUESE', 'PORTUGAL', 'WE8ISO8859P1', 'ISO-8859-1', 'f', 'f'); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.4.1d2-5.4.1d3.sql0000644000175000017500000000030711022567607026630 0ustar frankiefrankie-- packages/acs-lang/sql/postgresql/upgrade/upgrade-5.4.1d2-5.4.1d3.sql -- alter table user_preferences add constraint user_preferences_locale_fk foreign key (locale) references ad_locales(locale); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.1.1d1-5.1.1d2.sql0000644000175000017500000001562610070240704026616 0ustar frankiefrankie-- @author Rocael Hernandez roc@viaro.net -- Add some new locales insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_GT', 'Spanish (GT)', 'es', 'GT', 'SPANISH', 'GUATEMALA', 'WE8DEC', 'ISO-8859-1', 't', 'f'); -- resolves bug 1519 ---------------------------------------------------------------------- -- ch_ZH -> zh_CN insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_CN', 'Chinese (CN)', 'CH', 'ZH', 'SIMPLIFIED CHINESE', 'CHINA', 'ZHT32EUC', 'ISO-2022-CN', 't', 'f'); update ad_locale_user_prefs set locale='zh_CN' where locale='ch_zh'; update lang_messages set locale='zh_CN' where locale='ch_zh'; update lang_messages_audit set locale='zh_CN' where locale='ch_zh'; update lang_translation_registry set locale='zh_CN' where locale='ch_zh'; delete from ad_locales where locale = 'ch_zh'; ---------------------------------------------------------------------- -- TH_TH -> th_TH insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('th_TH', 'Thai (TH)temp', 'th', 'TH', 'THAI', 'THAILAND', 'TH8TISASCII', 'TIS-620', 't', 'f'); update ad_locale_user_prefs set locale='th_TH' where locale='TH_TH'; update lang_messages set locale='th_TH' where locale='TH_TH'; update lang_messages_audit set locale='th_TH' where locale='TH_TH'; update lang_translation_registry set locale='th_TH' where locale='TH_TH'; delete from ad_locales where locale = 'TH_TH'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Thai (TH)' where locale = 'th_TH'; ---------------------------------------------------------------------- -- AR_EG -> ar_EG insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_EG', 'Arabic (EG)temp', 'ar', 'EG', 'ARABIC', 'EGYPT', 'AR8ISO8859P6', 'ISO-8859-6', 'f', 'f'); update ad_locale_user_prefs set locale='ar_EG' where locale='AR_EG'; update lang_messages set locale='ar_EG' where locale='AR_EG'; update lang_messages_audit set locale='ar_EG' where locale='AR_EG'; update lang_translation_registry set locale='ar_EG' where locale='AR_EG'; delete from ad_locales where locale = 'AR_EG'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Arabic (EG)' where locale = 'ar_EG'; ---------------------------------------------------------------------- -- AR_LB -> ar_LB insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ar_LB', 'Arabic (LB)temp', 'ar', 'LB', 'ARABIC', 'LEBANON', 'AR8ISO8859P6', 'ISO-8859-6', 't', 'f'); update ad_locale_user_prefs set locale='ar_LB' where locale='AR_LB'; update lang_messages set locale='ar_LB' where locale='AR_LB'; update lang_messages_audit set locale='ar_LB' where locale='AR_LB'; update lang_translation_registry set locale='ar_LB' where locale='AR_LB'; delete from ad_locales where locale = 'AR_LB'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Arabic (LB)' where locale = 'ar_LB'; ---------------------------------------------------------------------- -- ms_my -> ms_MY insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ms_MY', 'Malaysia (MY)temp', 'ms', 'MY', 'MALAY', 'MALAYSIA', 'US7ASCII', 'US-ASCII', 't', 'f'); update ad_locale_user_prefs set locale='ms_MY' where locale='ms_my'; update lang_messages set locale='ms_MY' where locale='ms_my'; update lang_messages_audit set locale='ms_MY' where locale='ms_my'; update lang_translation_registry set locale='ms_MY' where locale='ms_my'; delete from ad_locales where locale = 'ms_my'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Malaysia (MY)' where locale = 'ms_MY'; ---------------------------------------------------------------------- -- RO_RO -> ro_RO insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ro_RO', 'Romainian (RO)temp', 'ro', 'RO', 'ROMAINIAN', 'ROMAINIA', 'EE8ISO8859P2', 'UTF-8', 't', 'f'); update ad_locale_user_prefs set locale='ro_RO' where locale='RO_RO'; update lang_messages set locale='ro_RO' where locale='RO_RO'; update lang_messages_audit set locale='ro_RO' where locale='RO_RO'; update lang_translation_registry set locale='ro_RO' where locale='RO_RO'; delete from ad_locales where locale = 'RO_RO'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Romainian (RO)' where locale = 'ro_RO'; ---------------------------------------------------------------------- -- FA_IR -> fa_IR insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fa_IR', 'Farsi (IR)temp', 'fa', 'IR', 'FARSI', 'IRAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); update ad_locale_user_prefs set locale='fa_IR' where locale='FA_IR'; update lang_messages set locale='fa_IR' where locale='FA_IR'; update lang_messages_audit set locale='fa_IR' where locale='FA_IR'; update lang_translation_registry set locale='fa_IR' where locale='FA_IR'; delete from ad_locales where locale = 'FA_IR'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Farsi (IR)' where locale = 'fa_IR'; ---------------------------------------------------------------------- -- HR_HR -> hr_HR insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hr_HR', 'Croatian (HR)temp', 'hr', 'HR', 'CROATIAN', 'CROATIA','UTF8','UTF-8','t','f'); update ad_locale_user_prefs set locale='hr_HR' where locale='HR_HR'; update lang_messages set locale='hr_HR' where locale='HR_HR'; update lang_messages_audit set locale='hr_HR' where locale='HR_HR'; update lang_translation_registry set locale='hr_' where locale='HR_HR'; delete from ad_locales where locale = 'HR_HR'; -- reset the label to remove the unique constraint workaround update ad_locales set label = 'Croatian (HR)' where locale = 'hr_HR'; ---------------------------------------------------------------------- -- trim some trailing spaces update ad_locales set language='tr' where language='tr '; update ad_locales set language='hi' where language='hi '; update ad_locales set language='ko' where language='ko '; update ad_locales set language='zh' where language='zh '; update ad_locales set language='hu' where language='hu '; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.0.0b4-5.0.0b5.sql0000644000175000017500000000336110017410255026606 0ustar frankiefrankie-- Datamodel changes in message-catalog.sql related to the new message catalog upgrade support. -- See Tcl proc lang::catalog::import_messages. -- -- @author Peter Marklund -- Changes to lang_message_keys table -- Column not needed as en_US row in lang_messages table has same info alter table lang_message_keys drop column upgrade_status; -- Add new columns to the lang_messages table alter table lang_messages add deleted_p boolean; alter table lang_messages alter column deleted_p set default 'f'; alter table lang_messages add sync_time timestamptz; alter table lang_messages add conflict_p boolean; alter table lang_messages alter column conflict_p set default 'f'; update lang_messages set deleted_p = 'f', conflict_p = 'f'; -- Add new columns to the lang_messages_audit tables alter table lang_messages_audit add deleted_p boolean; alter table lang_messages_audit alter column deleted_p set default 'f'; alter table lang_messages_audit add sync_time timestamptz; alter table lang_messages_audit add conflict_p boolean; alter table lang_messages_audit alter column conflict_p set default 'f'; alter table lang_messages_audit add upgrade_status varchar(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')); update lang_messages_audit set deleted_p = 'f', conflict_p = 'f', upgrade_status = 'no_upgrade'; -- Missing this primary key made some queries below very slow alter table lang_messages_audit add constraint lang_messages_audit_pk primary key (package_key, message_key, locale, overwrite_date); -- We have to leave sync_time null since we don't know when the messages in the db were last in sync -- with the catalog files openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d8-4.7d9.sql0000644000175000017500000000273107732616011026352 0ustar frankiefrankie-- New locales from the translation server insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('AR_EG', 'Arabic (AR_EG)', 'AR ', 'EG', 'ARABIC', 'EGYPT', 'AR8ISO8859P6', 'ISO-8859-6', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('tr_TR', 'Turkish (TR)', 'tr ', 'TR', 'TURKISH', 'TURKEY', 'WE8ISO8859P9', 'ISO-8859-9', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ms_my', 'Malaysia (MY)', 'ms ', 'MY', 'MALAY', 'MALAYSIA', 'US7ASCII', 'US-ASCII', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('hi_IN', 'Hindi (IN)', 'hi ', 'IN', 'HINDI', 'INDIA', 'UTF8', 'UTF-8', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ko_KR', 'Korean(KOR)', 'ko ', 'KR', 'KOREAN', 'KOREA', 'KO16KSC5601', 'EUC-KR', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('zh_TW', 'Chinese (TW)', 'zh ', 'TW', 'TRADITIONAL CHINESE', 'TAIWAN', 'ZHT16BIG5', 'Big5', 't'); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.6.0d1-5.6.0d2.sql0000644000175000017500000000045211321666756026640 0ustar frankiefrankie-- Fix wrong data in ad_locales update ad_locales set language = 'ar' where language = 'AR'; update ad_locales set language = 'ind' where locale = 'ind_ID'; update ad_locales set language = 'cs' where locale = 'cz_CZ'; update ad_locales set language = 'zh', country = 'HK' where locale = 'zh_HK'; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d4-4.7d5.sql0000644000175000017500000001015307621261225026337 0ustar frankiefrankie-- Upgrade script that adds new locales from translation server insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('fi_FI', 'Finnish (FI)', 'fi', 'FI', 'FINNISH', 'FINLAND', 'WE8ISO8859P15', 'ISO-8859-15', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('nl_NL', 'Dutch (NL)', 'nl', 'NL', 'DUTCH', 'THE NETHERLANDS', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ch_zh', 'Chinese (ZH)', 'CH', 'ZH', 'SIMPLIFIED CHINESE', 'CHINA', 'ZHT32EUC', 'ISO-2022-CN', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('pl_PL', 'Polish (PL)', 'pl', 'PL', 'POLISH', 'POLAND', 'EE8ISO8859P2', 'ISO-8859-2', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('no_NO', 'Norwegian (NO)', 'no', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('tl_PH', 'Tagalog (PH)', 'tl', 'PH', 'AMERICAN', 'ALGERIA', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('el_GR', 'Greek (GR)', 'el', 'GR', 'GREEK', 'GREECE', 'EL8ISO8859P7', 'ISO-8859-7', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('it_IT', 'Italian (IT)', 'it', 'IT', 'ITALIAN', 'ITALY', 'WE8DEC', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('ru_RU', 'Russian (RU)', 'ru', 'RU', 'RUSSIAN', 'CIS', 'RU8PC855', 'windows-1251', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('si_LK', 'Sinhalese (LK)','si', 'LK', 'ENGLISH', 'UNITED KINGDOM', 'UTF8', 'ISO-10646-UTF-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('sh_HR', 'Serbo-Croatian (SR/HR)', 'sr', 'YU', 'SLOVENIAN', 'SLOVENIA', 'YUG7ASCII', 'ISO-8859-5', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('nn_NO', 'Norwegian (NN)','nn', 'NO', 'NORWEGIAN', 'NORWAY', 'WE8ISO8859P1', 'ISO-8859-1', 't'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('pt_BR', 'Portuguese (BR)', 'pt', 'BR', 'BRAZILIAN PORTUGUESE', 'BRAZIL', 'WE8ISO8859P1', 'ISO-8859-1', 't' ); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values ('TH_TH', 'Thai (TH)', 'th', 'TH', 'THAI', 'THAILAND', 'TH8TISASCII', 'TIS-620', 't'); -- Forgot to add this locale earlier, some installations may have it already create function inline_0 () returns integer as ' declare v_locale_exists_p integer; begin select count(*) into v_locale_exists_p from ad_locales where locale = ''sv_SE''; if v_locale_exists_p = ''0'' then insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p) values (''sv_SE'', ''Swedish (SE)'', ''sv'', ''SE'', ''SWEDISH'', ''SWEDEN'', ''WE8ISO8859P1'', ''ISO-8859-1'', ''t''); end if; return 1; end;' language 'plpgsql'; select inline_0 (); drop function inline_0 (); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.6.0d2-5.6.0d3.sql0000644000175000017500000000122011456662500026624 0ustar frankiefrankie-- update comment on ad_locales to be more accurate about how to -- create new locales. comment on table ad_locales is ' An OpenACS locale is identified by a language and country. Locale definitions in Oracle consist of a language, and optionally territory and character set. (Languages are associated with default territories and character sets when not defined). The formats for numbers, currency, dates, etc. are determined by the territory. language is the shortest ISO 639 code (lowercase). country is two letter (uppercase) abbrev is ISO 3166 country code mime_charset is IANA charset name nls_charset is Oracle charset name '; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d7-4.7d8.sql0000644000175000017500000000167407627106367026370 0ustar frankiefrankie-- Make message keys cascade when packages are deleted create table upgrade_temp as select * from lang_message_keys; drop table lang_message_keys; create table lang_message_keys ( message_key varchar(200) constraint lang_message_keys_message_key_nn not null, package_key varchar(100) constraint lang_message_keys_fk references apm_package_types(package_key) on delete cascade constraint lang_message_keys_package_key_nn not null, upgrade_status varchar(30) constraint lang_message_keys_us_ck check (upgrade_status in ('no_upgrade', 'added','deleted')), constraint lang_message_keys_pk primary key (message_key, package_key) ); insert into lang_message_keys select * from upgrade_temp; drop table upgrade_temp; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d9-5.0d1.sql0000644000175000017500000000511207736273727026352 0ustar frankiefrankie-- -- PostgreSQL upgrade script from 4.7d9 to 5.0d1 -- -- 1. Adds an enabled_p flag to ad_locales. -- -- 2. Adds a comment field to lang_messages_audit -- -- 3. Renames the lang_messages_audit.message column to 'old_message' in order to make the meaning more clear. -- -- 4. Adds a description column to lang_message_keys. -- -- @author Simon Carstensen (simon@collaboraid.biz) -- @author Lars Pind (lars@collaboraid.biz) -- -- @creation-date 2003-08-11 -- @cvs-id $Id: upgrade-4.7d9-5.0d1.sql,v 1.4 2003/09/30 12:32:23 peterm Exp $ -- -- 1. Adds an enabled_p flag to ad_locales. -- New enabled_p column in ad_locales alter table ad_locales add enabled_p boolean; alter table ad_locales alter enabled_p set default 't'; -- Let all locales be enabled for sites that are upgrading update ad_locales set enabled_p = 't'; -- New view create view enabled_locales as select * from ad_locales where enabled_p = 't'; -- 2. Adds a comment field to lang_messages_audit -- 3. Renames the lang_messages_audit.message column to 'old_message' in order to make the meaning more clear. create table lang_messages_audit_new ( message_key varchar(200) constraint lang_messages_audit_key_nn not null, package_key varchar(100) constraint lang_messages_audit_p_key_nn not null, locale varchar(30) constraint lang_messages_audit_l_fk references ad_locales(locale) constraint lang_messages_audit_l_nn not null, old_message text, comment_text text, overwrite_date timestamptz default now() not null, overwrite_user integer constraint lang_messages_audit_ou_fk references users (user_id), constraint lang_messages_audit_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade ); insert into lang_messages_audit_new ( message_key, package_key, locale, old_message, overwrite_date, overwrite_user ) select message_key, package_key, locale, message, overwrite_date, overwrite_user from lang_messages_audit; drop table lang_messages_audit; alter table lang_messages_audit_new rename to lang_messages_audit; -- 4. Adds a description column to lang_message_keys. alter table lang_message_keys add column description text; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d3-4.7d4.sql0000644000175000017500000000261307736512401026341 0ustar frankiefrankiealter table lang_message_keys add upgrade_status varchar(30) constraint lang_message_keys_us_ck check (upgrade_status in ('no_upgrade', 'added','deleted')); alter table lang_messages add upgrade_status varchar(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')); create table lang_messages_audit ( message_key varchar(200) constraint lang_messages_audit_key_nn not null, package_key varchar(100) constraint lang_messages_audit_p_key_nn not null, locale varchar(30) constraint lang_messages_audit_l_fk references ad_locales(locale) constraint lang_messages_audit_l_nn not null, message text, overwrite_date timestamptz default now() not null, overwrite_user integer constraint lang_messages_audit_ou_fk references users (user_id), constraint lang_messages_audit_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade ); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.3.0d1-5.3.0d2.sql0000644000175000017500000001114010447161764026623 0ustar frankiefrankie-- -- -- -- @author Torben Brosten (torben@kappacorp.com) -- @creation-date 2006-06-22 -- @arch-tag: -- @cvs-id $Id: -- --new locales for oacs-5-2 --these locales from sql-ledger for accounts-* and related packages insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_BE', 'French (BE)', 'fr', 'BE', 'French (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('nl_BE', 'Dutch (BE)', 'nl', 'BE', 'Dutch (Belgium)', 'Belgium', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('en_CA', 'English (CA)', 'ca', 'EN', 'English (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('fr_CA', 'French (CA)', 'ca', 'FR', 'French (Canada)', 'Canada', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('zh_HK', 'Chinese, Simplified (HK)', 'hk', 'ZH', 'Simplified Chinese (Hong Kong)', 'Hong Kong', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('cz_CZ', 'Czech (CZ)', 'cz', 'CZ', 'Czech (Czech Republic)', 'Czech Republic', 'EE8ISO8859P2', 'ISO-8859-2', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_EC', 'Spanish (EC)', 'es', 'EC', 'Spanish', 'Ecuador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('et_EE', 'Estonian (EE)', 'et', 'EE', 'Estonian', 'Estonia', 'BLT8', 'ISO-8859-15', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('is_IS', 'Icelandic (IS)', 'is', 'IS', 'Icelandic', 'Iceland', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lt_LT', 'Lithuanian (LT)', 'lt', 'LT', 'Lithuanian', 'Lithuania', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('lv_LV', 'Latvian (LV)', 'lv', 'LV', 'Latvian', 'Latvia', 'BLT8', 'ISO-8859-13', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_MX', 'Spanish (MX)', 'es', 'MX', 'Mexican Spanish', 'Mexico', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PA', 'Spanish (PA)', 'es', 'PA', 'Spanish (Panama)', 'Panama', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_PY', 'Spanish (PY)', 'es', 'PY', 'Spanish (Paraguay)', 'Paraguay', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_SV', 'Spanish (SV)', 'es', 'SV', 'Spanish (El Salvador)', 'El Salvador', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('uk_UA', 'Ukranian (UA)', 'uk', 'UA', 'Ukranian', 'Ukraine', 'UTF8', 'UTF-8', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_VE', 'Spanish (VE)', 'es', 'VE', 'Spanish (Venezuela)', 'Venezuela', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.2.3d1-5.2.3d2.sql0000644000175000017500000000242610440426463026627 0ustar frankiefrankie-- -- -- -- @author Victor Guerra (guerra@galileo.edu) -- @creation-date 2006-01-26 -- @arch-tag: dc7aa6da-eb77-48df-9d42-6c3fb2d4ddcb -- @cvs-id $Id: upgrade-5.2.3d1-5.2.3d2.sql,v 1.2 2006/06/04 00:45:39 donb Exp $ -- --new locales for oacs-5-2 insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('es_CO', 'Spanish (CO)', 'es', 'CO', 'SPANISH', 'COLOMBIA', 'WE8DEC', 'ISO-8859-1', 'f', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ind_ID', 'Bahasa Indonesia (ID)', 'in', 'ID', 'INDONESIAN', 'INDONESIA', 'WEB8ISO8559P1', 'ISO-8559-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('bg_BG', 'Bulgarian (BG)', 'bg', 'BG', 'Bulgarian', 'BULGARIAN_BULGARIA', 'CL8ISO8859P5', 'windows-1251', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('pa_IN', 'Punjabi', 'pa', 'IN', 'Punjabi', 'India', 'UTF8', 'UTF-8', 't', 'f'); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.0.0-5.0.1.sql0000644000175000017500000000463110017410255026133 0ustar frankiefrankie-- @author Peter Marklund -- Change the lang_messages_audit table to have a new integer primary key column -- Add some new locales create sequence lang_messages_audit_id_seq; alter table lang_messages_audit add column audit_id integer; alter table lang_messages_audit drop constraint lang_messages_audit_pk; create function inline_0() returns integer as ' declare v_rec record; v_next_id integer; begin for v_rec in select message_key, package_key, locale, overwrite_date from lang_messages_audit order by overwrite_date loop select nextval(''lang_messages_audit_id_seq''::text) into v_next_id; update lang_messages_audit set audit_id = v_next_id where message_key = v_rec.message_key and package_key = v_rec.package_key and locale = v_rec.locale and overwrite_date = v_rec.overwrite_date; end loop; return 0; end;' language 'plpgsql'; select inline_0(); drop function inline_0(); alter table lang_messages_audit alter column audit_id set not null; alter table lang_messages_audit add constraint lang_messages_audit_pk primary key (audit_id); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('hu_HU', 'Hungarian (HU)', 'hu ', 'HU', 'HUNGARIAN', 'HUNGARY', 'EE8ISO8859P2', 'ISO-8859-2', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('FA_IR', 'Farsi', 'FA ', 'IR', 'AMERICAN', 'ALGERIAN', 'AL24UTFFSS', 'windows-1256', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('RO_RO', 'Romainian', 'RO ', 'RO', 'ROMAINIAN', 'ROMAINIA', 'EE8ISO8859P2', 'UTF-8', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('HR_HR', 'Croatian', 'HR', 'HR', 'CROATIAN', 'CROATIA','UTF8','UTF-8','t','f'); -- fix http://openacs.org/bugtracker/openacs/bug?bug%5fnumber=1464 update ad_locales set nls_language='TAGALOG', nls_territory='PHILIPPINES' where locale = 'tl_PH'; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.1.2d2-5.1.2d3.sql0000644000175000017500000000104610171476716026631 0ustar frankiefrankie-- @author Joel Aufrecht -- Add new locales insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('eu_ES', 'Basque (ES)', 'eu', 'ES', 'SPANISH', 'SPAIN', 'WE8DEC', 'ISO-8859-1', 't', 'f'); insert into ad_locales (locale, label, language, country, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p) values ('ca_ES', 'Catalan (ES)', 'ca', 'ES', 'SPANISH', 'SPAIN','WE8DEC', 'ISO-8859-1', 't', 'f'); openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d6-4.7d7.sql0000644000175000017500000000172407624265104026352 0ustar frankiefrankie-- We now allow for three character language codes create table temp as select * from ad_locales; drop table ad_locales; create table ad_locales ( locale varchar(30) constraint ad_locale_abbrev_pk primary key, language char(3) constraint ad_language_name_nil not null, country char(2) constraint ad_country_name_nil not null, variant varchar(30), label varchar(200) constraint ad_locale_name_nil not null constraint ad_locale_name_unq unique, nls_language varchar(30) constraint ad_locale_nls_lang_nil not null, nls_territory varchar(30), nls_charset varchar(30), mime_charset varchar(30), -- is this the default locale for its language default_p boolean default 'f' ); insert into ad_locales select * from temp; drop table temp; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.0d2-5.0d3.sql0000644000175000017500000000347307733560655026343 0ustar frankiefrankie-- Adding columns creation_user and creation_date to lang_messages -- Need to add not-null column so re-creating table create table lang_messages_tmp ( message_key varchar(200), package_key varchar(100), locale varchar(30), message text, upgrade_status varchar(30) ); insert into lang_messages_tmp select message_key, package_key, locale, message, upgrade_status from lang_messages; drop table lang_messages; create table lang_messages ( message_key varchar(200) constraint lang_messages_message_key_nn not null, package_key varchar(100) constraint lang_messages_package_key_nn not null, locale varchar(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message text, upgrade_status varchar(30) constraint lang_messages_us_ck check (upgrade_status in ('no_upgrade', 'added', 'deleted', 'updated')), creation_date timestamptz default now() not null, creation_user integer constraint lang_messages_creation_u_fk references users (user_id), constraint lang_messages_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade, constraint lang_messages_pk primary key (message_key, package_key, locale) ); insert into lang_messages select message_key, package_key, locale, message, upgrade_status, now(), null from lang_messages_tmp; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-5.4.1d1-5.4.1d2.sql0000644000175000017500000000043411022567607026627 0ustar frankiefrankie-- packages/acs-lang/sql/postgresql/upgrade/upgrade-5.4.1d1-5.4.1d2.sql -- -- language and country codes for Canada were wrong (ca, EN/FR) update ad_locales set language='en', country='CA' where locale='en_CA'; update ad_locales set language='fr', country='CA' where locale='fr_CA'; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.1-4.7d2.sql0000644000175000017500000000445307552553265026117 0ustar frankiefrankie-- -- Upgrade script from 4.1 to 4.7 -- -- Changes lang_messages so it uses locale instead of language -- by looking up the default locale in ad_locales. -- -- There two things that could go wrong here: -- -- 1. There could be no locale at all for some language -- in that case the scripts adds a new locale -- 2. There could be no default locale -- the script makes sure that theres is one default locale -- pr. language -- -- @author Christian Hvid -- -- Make sure that there is a default for every language UPDATE ad_locales SET default_p = 't' WHERE (SELECT count(*) FROM ad_locales AS a WHERE a.language = ad_locales.language AND default_p='t') = 0; -- Make sure that there is a locale for every language used in lang_messages INSERT INTO ad_locales (language, locale, country, label, nls_language, default_p) SELECT language, language || '_' || UPPER(language) as locale, '??' as country, 'Locale created by upgrade-4.1-4.7 for language ' || language as label, '??' as nls_language, 't' as default_p FROM ((SELECT DISTINCT lang as language FROM lang_messages) EXCEPT (SELECT DISTINCT language FROM ad_locales)) as new_languages; create table temp ( key varchar(200), lang varchar(2), message text, registered_p boolean ); INSERT INTO temp(key, lang, message, registered_p) SELECT key, lang, message, registered_p FROM lang_messages; DROP TABLE lang_messages; create table lang_messages ( key varchar(200), locale varchar(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message text, registered_p boolean, constraint lang_messages_pk primary key (key, locale) ); INSERT INTO lang_messages(key, locale, message, registered_p) SELECT key, ad_locales.locale, message, registered_p FROM temp, ad_locales WHERE cast (ad_locales.language as text) = cast (temp.lang as text) AND ad_locales.default_p = 't'; DROP TABLE temp; openacs-5.7.0/packages/acs-lang/sql/postgresql/upgrade/upgrade-4.7d2-4.7d3.sql0000644000175000017500000000460607554763537026363 0ustar frankiefrankie-- -- Upgrade script from 4.7d2 to 4.7d3 -- -- Split message keys and remove registered_p -- Copy all messages to a temporary table create table temp ( key varchar(200), locale varchar(30), message text ); INSERT INTO temp(key, locale, message) SELECT key, locale, message FROM lang_messages; -- drop old table DROP TABLE lang_messages; -- create new table create table lang_message_keys ( message_key varchar(200) constraint lang_message_keys_message_key_nn not null, package_key varchar(100) constraint lang_message_keys_fk references apm_package_types(package_key) constraint lang_message_keys_package_key_nn not null, constraint lang_message_keys_pk primary key (message_key, package_key) ); create table lang_messages ( message_key varchar(200) constraint lang_messages_message_key_nn not null, package_key varchar(100) constraint lang_messages_package_key_nn not null, locale varchar(30) constraint lang_messages_locale_fk references ad_locales(locale) constraint lang_messages_locale_nn not null, message text, constraint lang_messages_fk foreign key (message_key, package_key) references lang_message_keys(message_key, package_key) on delete cascade, constraint lang_messages_pk primary key (message_key, package_key, locale) ); -- insert old data -- into lang_message_keys INSERT INTO lang_message_keys(message_key, package_key) SELECT DISTINCT SUBSTR(key, STRPOS(key, '.')+1) as message_key, SUBSTR(key, 0, STRPOS(key, '.')) as package_key FROM temp, apm_package_types WHERE SUBSTR(key, 0, STRPOS(key, '.')) = package_key; -- into lang_messages INSERT INTO lang_messages(message_key, package_key, locale, message) SELECT SUBSTR(key, STRPOS(key, '.')+1) as message_key, SUBSTR(key, 0, STRPOS(key, '.')) as package_key, locale, message FROM temp, apm_package_types WHERE SUBSTR(key, 0, STRPOS(key, '.')) = package_key; DROP TABLE temp; openacs-5.7.0/packages/acs-lang/sql/postgresql/message-catalog-drop.sql0000644000175000017500000000142610016636575025773 0ustar frankiefrankie-- -- packages/language/sql/language-drop.sql -- -- @author davis@xarg.net -- @creation-date 2000-09-10 -- @cvs-id $Id: message-catalog-drop.sql,v 1.5 2004/02/24 12:03:09 jeffd Exp $ -- -- drop the timezone stuff --drop index tz_data_idx2; --drop index tz_data_idx1; --drop table tz_data; --drop function lc_time_utc_to_local; --drop function lc_time_local_to_utc; -- drop the lang stuff drop table lang_translation_registry; drop table lang_translate_columns; drop table lang_messages_audit; drop table lang_messages; drop table lang_message_keys; drop table lang_user_timezone; -- This might fail if the data model includes other multilingual tables -- that reference ad_locales. Really need to cascade here to ensure -- it goes away, but that is dangerous. -- drop table ad_locales; openacs-5.7.0/packages/acs-lang/sql/postgresql/acs-lang-drop.sql0000644000175000017500000000024210016636575024417 0ustar frankiefrankie-- Author: Jon Griffin (jon@jongriffin.com) -- $Id: acs-lang-drop.sql,v 1.1 2004/02/24 12:03:09 jeffd Exp $ \i message-catalog-drop.sql \i ad-locales-drop.sql openacs-5.7.0/packages/acs-lang/www/0000755000175000017500000000000011575225527017075 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/www/doc/0000755000175000017500000000000011724401447017633 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/www/doc/index.html0000644000175000017500000000105007766162052021633 0ustar frankiefrankie ACS 4 Localization This is now documented within ACS Core Documentation at:

    openacs-5.7.0/packages/acs-lang/www/doc/acs4-patches.txt0000644000175000017500000001410607270120475022655 0ustar frankiefrankie================================================================ charset-related parameters in .tcl AOLserver init file ns_section ns/parameters ns_param HackContentType 1 ns_param URLCharset shift_jis ns_param OutputCharset shift_jis ns_param HttpOpenCharset shift_jis ns_section ns/server/kiki/adp ns_param Map /*.adp ns_param DefaultParser fancy #ns_section ns/server/kiki/mimetypes ns_section ns/mimetypes ns_param Default text/plain ns_param NoExtension text/plain ns_param .pcd image/x-photo-cd ns_param .prc application/x-pilot ns_param .html "text/html" ns_param .tcl "text/html; charset=shift_jis" ns_param .adp "text/html; charset=shift_jis" ns_param .html_ej "text/html; charset=euc-jp" ================================================================ nsd-oracle: settings to make sure your Oracle client (i.e. AOLserver oracle driver) is using UTF8 ================================================================ #!/bin/bash export ORACLE_HOME="/ora8/m01/app/oracle/product/8.1.6" export ORACLE_BASE="/ora8/m01/app/oracle" export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/ctx/lib:/usr/lib:/lib:/usr/X11R6/lib::$ORACLE_HOME/jdbc/lib:/usr/local/lib export PATH=$ORACLE_HOME/bin:$ORACLE_HOME/ctx/lib:$PATH export ORACLE_SID='ora8' export ORACLE_TERM='vt100' export ORAENV_ASK=NO export NLS_DATE_FORMAT="YYYY-MM-DD" export ORACLE_OWNER=oracle export ORACLE_TERM='vt100' export CLASSPATH=$ORACLE_HOME/jdbc/lib/classes111.zip:$ORACLE_HOME/jdbc/lib/classes12.zip:$ORACLE_HOME/jdbc/lib/nls_charset12.zip export NLS_CHARACTER_SET=UTF8 PATH="$PATH:/usr/local/bin" export PATH export TCL_LIBRARY=/home/aol30/aolserver-18n export NLS_LANG=.UTF8 export TZ=GMT exec /home/aol30/bin/nsd $* ================================================================ /home/web/kiki/packages/acs-templating/tcl/util-procs.tcl: ================================================================ proc template::util::read_file { path } { set type [ns_guesstype $path] set encoding [ns_encodingfortype $type] set fd [open $path r] fconfigure $fd -encoding $encoding set text [read $fd] close $fd return $text } ================================================================ /web/kiki/packages/acs-tcl/tcl/request-processor-procs.tcl: ================================================================ ad_proc -private rp_handle_tcl_request {} { Handles a request for a .tcl file. Sets up the stack of datasource frames, in case the page is templated. } { namespace eval template variable parse_level [info level] ns_log Notice "calling rp_handle_tcl_request with [ad_conn file]" source_with_encoding [ad_conn file] } ad_proc -private rp_handle_adp_request {} { Handles a request for an .adp file. } { doc_init set mimetype [ns_guesstype [ad_conn file]] set encoding [ns_encodingfortype $mimetype] set fd [open [ad_conn file] r] fconfigure $fd -encoding $encoding set template [read $fd] close $fd set adp [ns_adp_parse -string $template] if { [doc_exists_p] } { doc_set_property body $adp doc_serve_document } else { set content_type [ns_set iget [ns_conn outputheaders] "content-type"] if { $content_type == "" } { set content_type [ns_guesstype [ad_conn file]] } else { ns_set idelkey [ns_conn outputheaders] "content-type" } doc_return 200 $content_type $adp } } proc_doc source_with_encoding {filename} { loads filename, using a charset encoding looked up via the ns_encodingforcharset command, based on the ns_guesstype MIME type of the filename. } { set type [ns_guesstype $filename] set encoding [ns_encodingfortype $type] set fd [open $filename r] fconfigure $fd -encoding $encoding set code [read $fd] close $fd # set the default output encoding to the file mime type ns_startcontent -type $type uplevel 1 $code } ================================================================ /web/kiki/packages/acs-templating/tcl/acs-integration-procs.tcl ================================================================ You only need this if you are trying to output adp files which use a different character set than the site default as specified by these init file params: ns_param URLCharset shift_jis ns_param OutputCharset shift_jis ns_param HttpOpenCharset shift_jis ================================================================ ad_proc adp_parse_ad_conn_file {} { handle a request for an adp and/or tcl file in the template system. } { namespace eval template variable parse_level "" #ns_log debug "adp_parse_ad_conn_file => file '[file root [ad_conn file]]'" set parsed_template [template::adp_parse [file root [ad_conn file]] {}] db_release_unused_handles if {![empty_string_p $parsed_template]} { set content_type [ns_set iget [ns_conn outputheaders] "content-type"] if { $content_type == "" } { set content_type [ns_guesstype [ad_conn file]] } else { ns_set idelkey [ns_conn outputheaders] "content-type" } ns_return 200 $content_type $parsed_template } } ================================================================ /web/kiki/packages/acs-templating/tcl/tag-init.tcl ================================================================ template_tag trn { chunk params } { set key [ns_set iget $params key] set lang [ns_set iget $params lang] set type [ns_set iget $params type] if [empty_string_p $type] { set type user } if {[empty_string_p $lang]} { set lang [ad_locale $type locale] } # Is the "static" attribute present? set static_p [expr [ns_set find $params static] >= 0] # If "static" attribute is present, do the call now if {$static_p} { set msg [lang_message_lookup $lang $key $chunk] # quote dollar signs, square bracket and quotes regsub -all {[\]\[""\\$]} $msg {\\&} quoted_msg template::adp_append_code "append __adp_output {$quoted_msg}" } else { # emit code to call lang_message_lookup at runtime template::adp_append_code "append __adp_output \[lang_message_lookup \[ad_locale $type language\] {$key}\]" } } openacs-5.7.0/packages/acs-lang/www/doc/index.xml0000644000175000017500000000116207716151467021476 0ustar frankiefrankie 1. Browser makes request. Browser might contain HTTP-header 2. Request processor initializes ad_conn object. In doing so, it calls a function in /packages/acs-lang/tcl/change-locale-include.tcl lang::user::set_locale to set ad_conn.locale. User preference User's package setting ad_locale_user_prefs per package per user. User's general preference: stored in user_preferences.locale User's browser preference: look at Browser's "HTTP-Accept-Language" header system setting for the package (not implemented) sitewide default locale, stored as acs_lang parameter "SitewideLocale" openacs-5.7.0/packages/acs-lang/www/doc/i18n-design.html0000644000175000017500000006670311126245327022562 0ustar frankiefrankie ACS 4 Globalization Detailed Design

    ACS 4 Globalization Detailed Design

    by Henry Minsky

    I. Essentials

    When applicable, each of the following items should receive its own link:

    • User directory: none
    • ACS administrator: acs-lang
    • Subsite administrator directory: none

    • Tcl script directory: /api-doc
    • PL/SQL file:
    • Data model:

    • Requirements document

    II. Introduction

    III. Historical Considerations

    V. Design Tradeoffs

    • Performance: availability and efficiency

      For Internationalization to be effective, it needs to be integrated into every module in the system. Thus making the overhead as low as possible is a priority, otherwise developers will be reluctant to use it in their code.

      Wherever possible, caching in AOLserver shared memory is used to remove the need to touch the database. Precompiling of template files should reduce the overhead to zero in most cases for translation message lookups. The amount of overhead added to the request processor can be reduced by caching filesystem information on matching of template files for locales.

    • Flexibility
    • Interoperability

    • Reliability and robustness

    • Usability
    Areas of interest to developers:
    • Maintainability
    • Portability

      The ACS Tcl I18N APIs should be as close as possible to the ultimate Java APIs. This means that using the same templates if possible, as well as the same message catalogs and format strings should be a strong goal.

    • Reusability
    • Testability

      A set of unit tests are included in the acs-lang package, to allow automatic testing after installation.

    VI. API

    VI.A Locale API

    10.30 A Locale object represents a specific geographical, political, or cultural region. An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user. For example, displaying a number is a locale-sensitive operation--the number should be formatted according to the customs/conventions of the user's native country, region, or culture.

    We will refer to a Locale by a combination of a language and country. In the Java Locale API there is an optional variant which can be added to a locale, which we will omit in the Tcl API.

    The language is a valid ISO Language Code. These codes are the lower-case two-letter codes as defined by ISO-639. You can find a full list of these codes at a number of sites, such as:
    http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt

    The country is a valid ISO Country Code. These codes are the upper-case two-letter codes as defined by ISO-3166. You can find a full list of these codes at a number of sites, such as:
    http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html

    Examples are

    en_US English US
    ja_JP Japanese
    fr_FR France French.

    The i18n module figures out the locale for a current request makes it accessible via the ad_locale function:

    [ad_locale user locale] => fr_FR
    [ad_locale subsite locale] => en_US
    
    It has not yet been decided how the user's preferred locale will be initialized. For now, there is a site wide default package parameter [parameter::get -parameter DefaultLocale -default "en_US"], and an API for setting the locale with the preference stored in a session variable: The ad_locale_set function is used to set the user's preferred locale to a desired value. It saves the value in the current session.
        ad_locale_set locale "en_US"
           will also automatically set [ad_locale user language]
              ( to "en" in this case)
    
        ad_locale_set timezone "PST"
    
        
    
    The request processor should use the ad_locale API to figure out the preferred locale for a request (perhaps combining user preference with subsite defaults in some way). It will make this information accesible via the ad_conn function:
        ad_conn locale 
    

    Character Sets and Encodings

    We refer to MIME character set names which are the valid values which can be passed in a MIME header, such as
    Content-Type: text/html; charset=iso-8859-1
    

    You can obtain the preferred character set for a locale via the ad_locale API shown below:

    set locale "en_US"
    [ad_locale charset $locale] => "iso-8859-1" or "shift_jis"
    
    Returns a case-insensitive name of a MIME character set.

    We already have an AOLserver function to convert a MIME charset name to a Tcl encoding name:

    [ns_encodingforcharset "iso-8859-1"] => iso8859-1
    

    Templating

    The goal of templates is to separate program logic from data presentation.

    For presenting data in multiple languages, there are two basic ways to use templates for a given abstract URL. Say we have the URL "foo", for example. We can provide templates for it in the following ways:

    • Separate template for each target language

      Have a copy of each template file in each language you support, e.g., foo.en.adp, foo.fr.adp, foo.de.adp, etc.

      We will refer to this style of template pages as language-specific templates.

    • A single template file for multiple languages

      You write your template to contain references to translation strings either from data sources or using <TRN> tags.

      For example, a site might support multiple languages, but use a single file foo.adp which contains no language-specific content, and would only make use of data sources or <TRN> tags which in turn use the message catalog to look up language-specific content.

      We will refer to this style of page as a multilingual template.

    Both styles of authoring templates will probably be used; For pages which contain a lot of free form text content, then having a separate template page for each language would be easiest.

    But for a page which has a very fixed format, such as a data entry form, it would mean a lot less redundant work to use a single template source page to handle all the languages, and to have all language-dependent strings be looked in a message catalog. We can do this either by creating data sources which call lang_message_lookup, or else use the <TRN> tag to do the same thing from within an ADP file.

    Caching multilingual ADP Templates

    Message catalog lookups can be potentially expensive, if many of them are done in a page. The templating system can already precompile and and cache adp pages. This works fine for a page in a specific language such as foo.en.adp, but we need to modify the caching mechanism if we want to use a single template file to target multiple languages.

    Computing the Effective Locale

    Let's say you have a template file "foo.adp" and it contains calls to look up message strings using the TRN tag:

    <master>
    <trn key=username_prompt>Please enter your username</tr>
    <input type=text name=username>
    <p>
    <trn key=password_prompt>Enter Password:</trn>
    <input type=password name=passwd>
    
    If the user requests the page foo, and their ad_locale is "en_US" then effective locale is "en_US". Message lookups are done using the effective locale. If the user's locale is "fr_FR", then the effective locale will be "fr_FR".

    If we evaluate the TRN tags at compile time then we need to associate the effective locale in which the page was evaluated with the cached compiled page code.

    The effective locale of a template page that has an explicit locale, such as a file named "foo.en.adp" or "foo.en_US.adp", will be that explicit locale. So for example, even if a user has a preferred locale of "fr_FR", if there is only a page named "foo.en.adp", then that page will be evaluated (and cached) with an effective locale of en_US.

    VI.B Naming of Template Files To Encode Language and Character Set

    10.40 The templating system will use the Locale API to obtain the preferred locale for a page request, and will attempt to find a template file which most closely matches that locale.

    We will use the following convention for naming template files: filename.locale_or_language.adp.

    Examples:

    foo.en_US.adp
    foo.en.adp
    
    foo.fr_FR.adp
    foo.fr.adp
    
    foo.ja_JP.adp
    foo.ja.adp
    
    

    The user request has a locale which is of the form language_country. If someone wants English, they will implicitly be choosing a default, such as en_US or en_GB. The default locale for a language can be configured in the system locale tables. So for example the default locale for "en" could be "en_US".

    The algorithm for finding the best matching template for a request in a given locale is given below:

    1. Find the desired target locale using [ad_conn locale] NOTE: This will always be a specific Locale (i.e., language_COUNTRY)

    2. Look for a template file whose locale suffix matches exactly.

      For example, if the filename in the URL request is simply foo and [ad_conn locale] returns en_US then look for a file named foo.en_US.adp.

    3. If an exact match is not found, look for template files whose name matches the language portion of the target locale.

      For example, if the URL request name is foo and [ad_conn locale] returns en_US and a file named foo.en_US.adp is not found, then look for all templates matching "en_*" as well as any template which just has the "en" suffix.

      So for example if the user's locale en_GB and the following files exist:

      foo.en_US.adp

      then use foo.en_US.adp

      If however both foo.en_US.adp and foo.en.adp exist, then use foo.en.adp preferentially, i.e., don't switch locales if you can avoid it. The reasoning here is that people can be very touchy about switching locales, so if there is a generic matching language template available for a language, use it rather than using an incorrect locale-specific template.

    4. If no locale-specific template is found, look for a template matching just the language

      I.e., if the request is for en_US, and there exists a file foo.en.adp, use that.

    5. If no locale-specific template is found, look for a simple .adp file, such as foo.adp.

    Once a template file is found we must decide what character set it is authored in, so that we can correctly load it into Tcl (which converts it to UTF8 internally).

    It would be simplest to mandate that all templates are authored in UTF8, but that is just not a practical thing to enforce at this point, I believe. Many designers and other people who actually author the HTML template files will still find it easier to use legacy tools that author in their "native" character sets, such as ShiftJIS in Japan, or BIG5 in China.

    So we make the convention that the template file is authored in it's effective locale's character set. For multilingual templates, we will load the template in the site default character set as specified by the AOLserver OutputCharset initializatoin parameter. For now, we will say that authoring generic multilingual adp files can and should be done in ASCII. Eventually we can switch to using UTF8.

    A character set corresponding to a locale can be found using the [ad_locale charset $locale] command. The templating system should call this right after it computes the effective locale, so it can set up that charset encoding conversion before reading the template file from disk.

    We read the template file using this encoding, and set the default output character set to it as well. Inside of either the .adp page or the parent .tcl page, it is possible for the developer to issue a command to override this default output character set. The way this is done is currently to stick an explicit content-type header in the AOLserver output headers, for example to force the output to ISO-8859-1, you would do

    ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=iso-8859-1"	
    
    design questionWe should have an API for this. The hack now is that the adp handler adp_parse_ad_locale user_file looks at the output headers, and if it sees a content type with an explicit charset, it passes it along to ns_return.

    The default character set for a template .adp file should be the default system encoding.

    VI.C Loading Regular Tcl Script Files

    10.50 By default, tcl and template files in the system will be loaded using the default system encoding. This is generally ISO-8859-1 for AOLserver running on Unix systems in English.

    This default can be overridden by setting the AOLserver init parameter for the MIME type of .tcl files to include an explcit character set. If an explicit MIME type is not found, ns_encodingfortype will default to the AOLserver init parameter value DefaultCharset if it is set.

    Example AOLserver .ini configuration file to set default script file and template file charset to ShiftJIS:

    ns_section {ns/mimetypes }
    ...
    ns_param .tcl {text/plain; charset=shift_jis}
    ns_param .adp {text/html; charset=shift_jis}
    
    ns_section ns/parameters
    ...
    # charset hacking
    ns_param HackContentType 1
    ns_param URLCharset shift_jis
    ns_param OutputCharset shift_jis
    ns_param HttpOpenCharset shift_jis
    ns_param DefaultCharset shift_jis
    
    

    VI.A Message Catalog API

    We want to use something like the Java ResourceBundle, where the developer can declare a set of resources for a given namespace and locale.

    For AOLserver/TCL, to make the message catalog more manageable, we will split it into one message catalog per package, plus one default global message namespace in case we need it. So for example,

    Message lookups are done using a combination of a key string and a locale or language, as well as an implicit package prefix on the key string. The API for using the message catalog is as follows:

    lang_message_lookup locale key [default_string]
    
    lang_message_lookup is abbreviated by the procedure named "_", which is the convention used by the GNU strings message catalog package.

    The locale arg can actually be a full locale, or else a simple language abbrev, such as fr, en, etc. The lookup rules for finding strings based on key and locale are tried in order as follows:
    1. Lookup is first tried with the full locale (if present) and package.key
    2. Lookup is tried with just the language portion of the locale and package.key
    3. Lookup is tried with the full locale and key without package prefix.
    4. Lookup is tried with language and key without package prefix.
    Example: You are looking up the message string "Title" in the notes package.

    [lang_message_lookup $locale notes.title "Title"]
    
    can be abbreviated by
    [_ $locale notes.title "Title"]
    
    # message key "title" is implicitly with respect to package key
    #  "notes", i.e., notes.title
    [_ $locale title "Title"]
    
    
    The string is looked up by the symbolic key notes.title (or title for short), and the constant value "Title" is supplied as documentation and as a default value. Having a default value allows developers to code their application immediately without waiting to populate the message catalog.

    Default Package Namespace

    By default, keys are prefixed with the name of the current package (if a page request is being processed). So a lookup of the key "title" in a page in the bboard package will actually reference the "bboard.title" entry in the message catalog.

    You can override this behavior by either using a fully qualified key such as bboard.title or else by changing the message catalog namespace using the lang_set_package command:

    [lang_set_package "bboard"]
    
    So for example code that runs in a scheduled proc, where there is not necessarily any concept of a "current package", would either use fully qualified keys to look up messages, or else call lang_set_package before doing a message lookup.

    Message Catalog Definition Files

    A message catalog is defined by placing a file in the catalog subdirectory of a package. Each file defines a set of messages in different locales, and the file is written in a character set specified by it's file suffix:
    /packages/bboard/catalog/
    			 bboard.iso-8859-1
    			 bboard.shift_jis
    			 bboard.iso-8859-6
    
    A message catalog file consists of tcl code to define messages in a given language or locale:
    
    _mr en mail_notification "This is an email notification"
    _mr fr mail_notification "Le notification du email"
    ...
    
    
    In the example above, if the catalog file was loaded from the bboard package, all of the keys would be prefixed autmatically with "bboard.".

    Loading A Message Catalog At Package Init Time

    The API function
    lang_catalog_load package_key
    
    Is used to load the message catalogs for a package. The catalog files are stored in a package subdirectory called catalog. Their file names have the form *.encoding.cat, where encoding is the name of a MIME charset encoding (not a Tcl charset name as was used in a previous version of this command).
    /packages/bboard/catalog
                            /main.iso8859-1.cat
                            /main.shift_jis.cat
                            /main.iso-8859-6.cat
                            /other.iso8859-1.cat
                            /other.shift_jis.cat
                            /other.iso-8859-6.cat
    

    You can add more pseudo-levels of hierarchy in naming the message keys, using any separator character you want, for example

    _mr fr alerts.mail_notification "Le notification du email"
    
    which will be stored with the full key of bboard.alerts.mail_notification.

    Calling the Message Catalog API from inside of Templates

    Inside of a template, you can always make a call to the message catalog API via a Tcl escape:
    <%= [_ $locale bboard.passwordPrompt "Enter Password"]%> 
    
    However, this is awkward and ugly to use. We have defined an ADP tag which invokes the message catalog lookup. As explained in the previous section, since our system precompiles adp templates, we can get a performance improvement if we can cache the message lookups at template compile time.

    The <TRN> tag is a call to lang_message_lookup that can be used inside of an ADP file. Here is the documention:

    Procedure that gets called when the <trn> tag is encountered on an ADP page. The purpose of the procedure is to register the text string enclosed within a pair of <trn> tags as a message in the catalog, and to display the appropriate translated string. Takes three optional parameters: lang, type and key.
    • key specifies the key in the message catalog. If it is omitted this procedure returns simply the text enclosed by the tags.
    • lang specifies the language of the text string enclosed within the flags. If it is ommitted value defaults to English.
    • type specifies the context in which the translation is made. If omitted, type is user which means that the translation is provided in the user's preferred language.
    • static specifies that this tag should be translated once at templat compile time, rather than dynamically every time the page is run. This will be unneccessaru and will be deprecated once we have implemented effective locale based cacheing for templates.
    Example 1: Display the text string Hello on an ADP page (i.e. do nothing special):
        <trn>Hello</trn>
        
    Example 2: Assign the key key hello to the text string Hello and display the translated string in the user's preferred language:
        <trn key="hello">Hello</trn>
        
    Example 3: Specify that Bonjour needs to be registered as the French translation for the key hello (in addition to displaying the translation in the user's preferred language):
        <trn key="hello" lang="fr">Bonjour</trn>
        
    Example 4: Register the string and display it in the preferred language of the current user. Note that the possible values for the type paramater are determined by what has been implemented in the ad_locale procedure. By default, only the user type is implemented. An example of a type that could be implemented is subsite, for displaying strings in the language of the subsite that owns the current web page.
        <trn key="hello" type="user">Hello</trn>
        

    Example 5: Translates the string once at template compile time, using the effective local of the page.

        <trn key="hello" static>Hello</trn>
        

    VII. Data Model Discussion

    Internationalizing the Data Models

    Some data which is stored in ACS package and core database tables may be presented to users, and thus may need to be stored in multiple languages. Examples of this are the descriptions of package or site parameters in the administrative interface, the "pretty names" of objects, and group names.

    Tables which are in acs kernel and have user-visible names that may need to be translated in order to create an admin back end in another language:

    user groups:
       group_name
    
    acs_object_types:
       pretty_name
       pretty_plural
    
    acs_attributes:
       pretty_name
       pretty_plural
    
    acs_attribute_descriptions
       description (clob)
    
    procedure add_description- add a lang arg ?
    
    acs_enum_values ? pretty_name
    
    acs_privileges: 
      pretty_name
      pretty_plural
    
    apm_package_types
      pretty_name
      pretty_plural
    
    
    apm_package "instance_name"? Maybe a given instance
    gets instantiated with a name in the desired language?
    
    
    apm_parameters: 
       parameter_name
       section_name
    
    One approach is to split a table into two tables, one holding language-independent datam, and the other holding language-dependent data. This approach was described in the ASJ Multilingual Site Article.

    In that case, it is convenient to create a new view which looks like the original table, with the addition of a language column that you can specify in the queries.

    Drawbacks to Splitting Tables

    It is not totally transparent to developers
    Every query against the table which requests or modifies language-dependent columns must now include a WHERE clause to select the language.

    Extra join may slow things down
    The extra join of the two tables may cause queries to slow down, although I am not sure what the actual performance hit might be. It shouldn't be too large, because the join is against a fully indexed table.

    VIII. User Interface

    IX. Configuration/Parameters

    X. Code Examples

    • fconfigure -encoding blah
    • content type in outputheaders set for encoding conversion
      ad_proc adp_parse_ad_conn_file {} {
          handle a request for an adp and/or tcl file in the template system.
      } {
          namespace eval template variable parse_level ""
          #ns_log debug "adp_parse_ad_conn_file => file '[file root [ad_conn file]]'"
          set parsed_template [template::adp_parse [file root [ad_conn file]] {}]
          db_release_unused_handles
          if {![empty_string_p $parsed_template]} {
              set content_type [ns_set iget [ns_conn outputheaders] "content-type"]
              if { $content_type == "" } {
      	    set content_type  [ns_guesstype [ad_conn file]]
              } else {
                  ns_set idelkey [ns_conn outputheaders] "content-type"
              }
      	ns_return 200 $content_type $parsed_template
          }
      }
      
      

    XI. Future Improvements/Areas of Likely Change

    XII. Authors

    • System creator
    • System owner: hqm@arsdigita.com
    • Documentation author: hqm@arsdigita.com

    XII. Revision History

    The revision history table below is for this template - modify it as needed for your actual design document.

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Creation 12/4/2000 Henry Minsky
    0.2 More specific template search algorithm, extended message catalog API to use package keys or other namespace 12/4/2000 Henry Minsky
    0.3 Details on how the <TRN> tag works in templates 12/4/2000 Henry Minsky
    0.4 Definition of effective locale for template caching, documentation of TRN tag 12/12/2000 Henry Minsky


    hqm@arsdigita.com
    openacs-5.7.0/packages/acs-lang/www/doc/i18n-requirements.html0000644000175000017500000005322007714712710024025 0ustar frankiefrankie ACS 4 Globalization Requirements

    ACS 4 Globalization Requirements

    by Henry Minsky, Yon Feldman, Lars Pind, others


    I. Introduction

    This document describes the requirements for functionality in the ACS platform to support globalization of the core and optional modules. The goal is to make it possible to support delivery of applications which work properly in multiple locales with the lowest development and maintenance cost.

    Definitions

    internationalization (i18n)

    The provision within a computer program of the capability of making itself adaptable to the requirements of different native languages, local customs and coded character sets.

    locale

    The definition of the subset of a user's environment that depends on language and cultural conventions.

    localization (L10n)

    The process of establishing information within a computer system specific to the operation of particular native languages, local customs and coded character sets.

    globalization

    A product development approach which ensures that software products are usable in the worldwide markets through a combination of internationalization and localization.

    II. Vision Statement

    The Mozilla project suggests keeping two catchy phrases in mind when thinking about globalization:
    • One code base for the world
    • English is just another language

    Building an application often involves making a number of assumptions on the part of the developers which depend on their own culture. These include constant strings in the user interface and system error messages, names of countries, cities, order of given and family names for people, syntax of numeric and date strings and collation order of strings.

    The ACS should be able to operate in languages and regions beyond US English. The goal of ACS Globalization is to provide a clean and efficient way to factor out the locale dependent functionality from our applications, in order to be able to easily swap in alternate localizations.

    This in turn will reduce redundant, costly, and error prone rework when targeting the toolkit or applications built with the toolkit to another locale.

    The cost of porting the ACS to another locale without some kind of globalization support would be large and ongoing, since without a mechanism to incorporate the locale-specific changes cleanly back into the code base, it would require making a new fork of the source code for each locale.

    III. System/Application Overview

    A globalized application will perform some or all of the following steps to handle a page request for a specific locale:
    1. Decide what the target locale is for an incoming page request
    2. Decide which character set encoding the output should be delivered in
    3. If a script file to handle the request needs to be loaded from disk, determine if a character set conversion needs to be performed when loading the script
    4. If needed, locale-specific resources are fetched. These can include text, graphics, or other resources that would vary with the target locale.
    5. If content data is fetched from the database, check for locale-specific versions of the data (e.g. country names).
    6. Source code should use a message catalog API to translate constant strings in the code to the target locale
    7. Perform locale-specific linguistic sorting on data if needed
    8. If the user submitted form input data, decide what character set encoding conversion if any is needed. Parse locale-specific quantities if needed (number formats, date formats).
    9. If templating is being used, select correct locale-specific template to merge with content
    10. Format output data quantities in locale-specific manner (date, time, numeric, currency). If templating is being used, this may be done either before and/or after merging the data with a template.

    Since the internationalization APIs may potentially be used on every page in an application, the overhead for adding internationalization to a module or application must not cause a significant time delay in handling page requests.

    In many cases there are facilities in Oracle to perform various localization functions, and also there are facilities in Java which we will want to move to. So the design to meet the requirements will tend to rely on these capabilities, or close approximations to them where possible, in order to make it easier to maintain Tcl and Java ACS versions.

    IV. Use-cases and User-scenarios

    Here are the cases that we need to be able to handle efficiently:
    1. A developer needs to author a web site/application in a language besides English, and possibly a character set besides ISO-8859-1. This includes the operation of the ACS itself, i.e., navigation, admin pages for modules, error messages, as well as additional modules or content supplied by the web site developer.

      What do they need to modify to make this work? Can their localization work be easily folded in to future releases of ACS?

    2. A developer needs to author a web site which operates in multiple languages simultaneously. For example, arsDigita.com with content and navigation in English, German, and Japanese.

      The site would have an end-user visible UI to support these languages, and the content management system must allow articles to be posted in these languages. In some cases it may be necessary to make the modules' admin UI's operate in more than one supported language, while in other cases the backend admin interface can operate in a single language.

    3. A developer is writing a new module, and wants to make it easy for someone to localize it. There should be a clear path to author the module so that future developers can easily add support for other locales. This would include support for creating resources such as message catalogs, non-text assets such as graphics, and use of templates which help to separate application logic from presentation.

    Competitive Analysis

    Other application servers: ATG Dyanmo, Broadvision, Vignette, ... ? Anyone know how they deal with i18n ?

    V. Related Links

    VI Requirements

    Because the requirements for globalization affect many areas of the system, we will break up the requirements into phases, with a base required set of features, and then stages of increasing functionality.

    VI.A Locales

    10.0 A standard representation of locale will be used throughout the system. A locale refers to a language and territory, and is uniquely identified by a combination of ISO language and ISO country abbreviations.
    See Content Repository Requirement 100.20

    10.10 Provide a consistent representation and API for creating and referencing a locale

    10.20 There will be a Tcl library of locale-aware formatting and parsing functions for numbers, dates and times. Note that Java has builtin support for these already.

    10.30 For each locale there will be default date, number and currency formats.

    VI.B Associating a Locale with a Request

    20.0 The request processor must have a mechanism for associating a locale with each request. This locale is then used to select the appropriate template for a request, and will also be passed as the locale argument to the message catalog or locale-specific formatting functions.

    20.10 The locale for a request should be computed by the following method, in descending order of priority:

    • get locale associated with subsite or package id
    • get locale from user preference
    • get locale from site wide default

      20.20 An API will be provided for getting the current request locale from the ad_conn structure.

    VI.C Resource Bundles / Content Repository

    30.0 A mechanism must be provided for a developer to group a set of arbitrary content resources together, keyed by a unique identifier and a locale.

    For example, what approaches could be used to implement a localizable nav-bar mechanism for a site? A navigation bar might be made up of a set of text strings and graphics, where the graphics themselves are locale-specific, such as images of English or Japanese text (as on www.arsdigita.com). It should be easy to specify alternate configurations of text and graphics to lay out the page for different locales.

    Design note: Alternative mechanisms to implement this functionality might include using templates, Java ResourceBundles, content-item containers in the Content Repository, or some convention assigning a common prefix to key strings in the message catalog.

    VI.D Message Catalog for String Translation

    40.0 A message catalog facility will provide a database of translations for constant strings for multilingual applications. It must support the following:

    40.10 Each message will referenced via unique a key.

    40.20 The key for a message will have some hierarchical structure to it, so that sets of messages can be grouped with respect to a module name or package path.

    40.30 The API for lookup of a message will take a locale and message key as arguments, and return the appropriate translation of that message for the specifed locale.

    40.40 The API for lookup of a message will accept an optional default string which can be used if the message key is not found in the catalog. This lets the developer get code working and tested in a single language before having to initialize or update a message catalog.

    40.50 For use within templates, custom tags which invoke the message lookup API will be provided.

    40.60 Provide a method for importing and exporting a flat file of translation strings, in order to make it as easy as possible to create and modify message translations in bulk without having to use a web interface.

    40.70 Since translations may be in different character sets, there must be provision for writing and reading catalog files in different character sets. A mechanism must exist for identifying the character set of a catalog file before reading it.

    40.80 There should be a mechanism for tracking dependencies in the message catalog, so that if a string is modified, the other translations of that string can be flagged as needing update.

    40.90 The message lookup must be as efficient as possible so as not to slow down the delivery of pages.


    Design question: Is there any reason to implement the message catalog on top of the content repository as the underlying storage and retrieval service, with a layer of caching for performance? Would we get a nice user interface and version control almost for free?

    VI.E Character Set Encoding

    Character Sets

    50.0 A locale will have a primary associated character set which is used to encode text in the language. When given a locale, we can query the system for the associated character set to use.

    The assumption is that we are going to use Unicode in our database to hold all text data. Our current programming environments (Tcl/Oracle or Java/Oracle) operate on Unicode data internally. However, since Unicode is not yet commonly used in browsers and authoring tools, the system must be able to read and write other character sets. In particular, conversions to and from Unicode will need to be explicitly performed at the following times:

    • Loading source files (.tcl or .adp) or content files from the filesystem
    • Accepting form input data from users
    • Delivering text output to a browser
    • Composing an email message
    • Writing data to the filesystem


    Design question: Do we want to mandate that all template files be stored in UTF8? I don't think so, because most people don't have Unicode editors, or don't want to be bothered with an extra step to convert files to UTF8 and back when editing them in their favorite editor.

    Same question for script and template files, how do we know what language and character set they are authored in? Should we overload the filename suffix (e.g., '.shiftjis.adp', '.ja_JP.euc.adp')?

    The simplest design is probably just to assign a default mapping from each locale to character a set: e.g. ja_JP -> ShiftJIS, fr_FR -> ISO-8859-1. +++ (see new ACS/Java notes) +++

    Tcl Source File Character Set

    There are two classes of Tcl files loaded by the system; library files loaded at server startup, and page script files, which are run on each page request.


    Should we require all Tcl files be stored as UTF8? That seems too much of a burden on developers.

    50.10 Tcl library files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.

    50.20 Tcl page script files can be authored in any character set. The system must have a way to determine the character set before loading the files, probably from the filename.

    Submitted Form Data Character Set

    50.30 Data which is submitted with a HTTP request using a GET or POST method may be in any character set. The system must be able to determine the encoding of the form data and convert it to Unicode on demand.

    50.35 The developer must be able to override the default system choice of character set when parsing and validating user form data.

    50.30.10 Extra hair: In Japan and some other Asian languages where there are multiple character set encodings in common use, the server may need to attempt to do an auto-detection of the character set, because buggy browsers may submit form data in an unexpected alternate encoding.

    Output Character Set

    50.40 The output character set for a page request will be determined by default by the locale associated with the request (see requirement 20.0).

    50.50 It must be possible for a developer to manually override the output character set encoding for a request using an API function.

    VI.F ACS Kernel Issues

    60.10 All ACS error messages must use the message catalog and the request locale to generate error message for the appropriate locale.

    60.20 Web server error messages such as 404, 500, etc must also be delivered in the appropriate locale.

    60.30 Where files are written or read from disk, their filenames must use a character set and character values which are safe for the underlying operating system.

    VI.G Templates

    70.0 For a given abstract URL, the designer may create multiple locale-specific template files may be created (one per locale or language)

    70.10 For a given page request, the system must be able to select an approprate locale-specific template file to use. The request locale is computed as per (see requirement 20.0).

    Design note: this would probably be implemented by suffixing the locale or a locale abbreviation to the template filename, such as foo.ja.adp or foo.en_GB.adp.

    70.20A template file may be created for a partial locale (language only, without a territory), and the request processor should be able to find the closest match for the current request locale.

    70.30 A template file may be created in any character set. The system must have a way to know which character set a template file contains, so it can properly process it.

    Formatting Datasource Output in Templates

    70.50 The properties of a datasource column may include a datatype so that the templating system can format the output for the current locale. The datatype is defined by a standard ACS datatype plus a format token or format string, for example: a date column might be specified as 'current_date:date LONG,' or 'current_date:date "YYYY-Mon-DD"'

    Forms

    70.60 The forms API must support construction of locale-specific HTML form widgets, such as date entry widgets, and form validation of user input data for locale-specific data, such as dates or numbers.

    70.70 For forms which allow users to upload files, a standard method for a user to indicate the charset of a text file being uploaded must be provided.

    Design note: this presumably applies to uploading data to the content repository as well

    VI.H Sorting and Searching

    80.10 Support API for correct collation (sorting order) on lists of strings in locale-dependent way.

    80.20 For the Tcl API, we will say that locale-dependent sorting will use Oracle SQL operations (i.e., we won't provide a Tcl API for this). We require a Tcl API function to return the correct incantation of NLS_SORT to use for a given locale with ORDER BY clauses in queries.

    80.40 The system must handle full-text search in any supported language.

    VI.G Time Zones

    90.10 Provide API support for specifying a time zone

    90.20 Provide an API for computing time and date operations which are aware of timezones. So for example a calendar module can properly synchronize items inserted into a calendar from users in different time zones using their own local times.

    90.30 Store all dates and times in universal time zone, UTC.

    90.40 For a registered users, a time zone preference should be stored.

    90.50 For a non-registered user a time zone preference should be attached via a session or else UTC should be used to display every date and time.

    90.60 The default if we can't determine a time zone is to display all dates and times in some universal time zone such as GMT.

    VI.H Database

    100.10 Since UTF8 strings can use up to three (UCS2) or six (UCS4) bytes per character, make sure that column size declarations in the schema are large enough to accomodate required data (such as email addresses in Japanese).

    VI.I Email and Messaging

    When sending an email message, just as when delivering the content in web page over an HTTP connection, it is necessary to be able to specify what character set encoding to use.

    110.10 The email message sending API will allow for a character set encoding to be specified.

    110.20 The email accepting API will allow for character set to be parsed correctly (hopefully a well formatted message will have a MIME character set content type header)

    Implementation Notes

    Because globalization touches many different parts of the system, we want to reduce the implementation risk by breaking the implementation into phases.

    VII. Revision History

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Creation 11/08/2000 Henry Minsky
    0.2 Minor typos fixed, clarifications to wording 11/14/2000 Henry Minsky
    0.3 comments from Christian 1/14/2000 Henry Minsky

    hqm@arsdigita.com

    Last modified: $Date: 2003/08/08 12:21:28 $

    openacs-5.7.0/packages/acs-lang/www/doc/questions0000644000175000017500000001025407270120475021612 0ustar frankiefrankieX-Authentication-Warning: gnabgib.no: brech set sender to christian@arsdigita.com using -f From: Christian Brechbuehler Date: Thu, 11 Jan 2001 22:03:13 -0500 (EST) To: Henry Minsky Subject: internationalization X-Mailer: VM 6.75 under Emacs 20.4.1 X-MIME-Autoconverted: from quoted-printable to 8bit by life.ai.mit.edu id RAA06790 Hi Henry, you put a few questions in the requirements document. I'd like to follow up on these, and comment about some other requirements. * Resource Bundles / Content Repository Not sure. Nav-bar: I'd probably try to write it as an able templated page, a.k.a. widget. With several locales, the (yet to be specified) template selection mechanism will pick the right one. > Design question: Do we want to mandate that all template files be > stored in UTF8? I don't think so, because most people don't have > Unicode editors, or don't want to be bothered with an extra step to > convert files to UTF8 and back when editing them in their favorite > editor. Most people around here seem to have emacs as their favorite editor. There seems to be some UTF-8 support around, although some of the stuff involves recompiling emacs. I'd prefer an appropriate (minor?) mode for editing UTF-8. From http://www.cl.cam.ac.uk/~mgk25/unicode.html:
  • Miyashita Hisashi has written MULE-UCS, a character set translation package for Emacs 20.6 or higher, which can translate between the Mule encoding (used internally by Emacs) and ISO 10646.
  • Otfried Cheong provides on his Unicode encoding for GNU Emacs page an extension to MULE-UCS that covers the entire BMP by adding utf-8 as another Emacs character set. His page also contains a short installation guide for MULE-UCS.
  • UTF-8 xemacs patch by Tomohiko Morioka. > Same question for script and template files, how do we know what > language and character set they are authored in? Should we overload > the filename suffix (e.g., '.shiftjis.adp', '.ja_JP.euc.adp')? I think we'll have to mess with the request processor anyway to teach it that x.ja_JP.adp is a hit for HTTP request "x", at least if the locale is ja_JP. Then we can bring in the encoding in the name as well. We could put the encoding in the first line, but that would go against requirement 50.20 (similar to 40.70). > Should we mandate that there is a one-to-one mapping from locale to > character set? e.g. ja_JP -> ShiftJIS, fr_FR -> ISO-8859-1 Make that many-to-one. E.g., quite a number of Western locales use ISO-8859-1. > Should we require all Tcl files be stored as UTF8? That seems too > much of a burden on developers. Most tcl scripts will be 7-bit ASCII anyway, and hence UTF-8 a priori. This requirement doesn't seem too strict to me. I just shouldn't put "@author=Brechbühler" in them :-). 60.10 (ACS error messages): I just looked into those error mechanism for http://www.arsdigita.com/sdm/one-ticket?ticket_id=9178. When we go templated as I suggest, we should be do that with awareness to the lang package. 70.0 Question: "created" by the designer(s)? 70.10 Comment: Shan Shan Huang is writing a WAP package. For now she chose ".wdp" extension (I didn't like .wml, because normal templates use .adp, not .html). But I'd like to treat wap more or less the same way; we might switch to foo.wml.adp, or even foo.fr.wml.adp for the french WAP version. 70.20 is an interesting problem. So far the RP looks under the page root for foo.{adp,tcl,html,...}, then in the file according to the site map. We'll have to extend it to look first for foo.en_GB.adp, then foo.en.adp, then foo.adp. This solution would imply that foo.adp (or even a foo.tcl) in the server root overrides any more specific templates in a mounted package. 80.10 Yes, even Swedish and German differ! (Both ISO-8859-1, right?) 90.50 drop "would" from "would should". 100.10 "three bytes" implies UCS-2 (and not UCS-4). Just my assorted thoughts Christianopenacs-5.7.0/packages/acs-lang/www/admin/0000755000175000017500000000000011724401447020156 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/www/admin/test/0000755000175000017500000000000011724401447021135 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/www/admin/test/timezone-oracle.xql0000644000175000017500000000044307550315421024757 0ustar frankiefrankie oracle8.1.6 SELECT to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') AS system_time FROM dual openacs-5.7.0/packages/acs-lang/www/admin/test/show.tcl0000644000175000017500000000070707550315421022623 0ustar frankiefrankieset file [ns_queryget file] if { [regexp {\.\.|^/} $file] } { set output "Only files within this directory may be shown." } else { # [ns_url2file [ns_conn url]] fails under request processor ! # the file for URL pkg/page may be in packages/pkg/www/page, not www/pkg/page set dir [file dirname [ad_conn file]] set text [ns_quotehtml [template::util::read_file $dir/$file]] set output "
    $text
    " } ns_return 200 text/html $output openacs-5.7.0/packages/acs-lang/www/admin/test/test-postgresql.xql0000644000175000017500000000044007550315421025037 0ustar frankiefrankie postgresql7.1 SELECT to_char(current_time, 'YYYY-MM-DD HH24:MI:SS') AS system_time openacs-5.7.0/packages/acs-lang/www/admin/test/compile.tcl0000644000175000017500000000076307550315421023275 0ustar frankiefrankieset file [ns_queryget file] if { [regexp {\.\.|^/} $file] } { set compiled "Only files within this directory may be shown." } else { # [ns_url2file [ns_conn url]] fails under request processor ! # the file for URL pkg/page may be in packages/pkg/www/page, not www/pkg/page set dir [file dirname [ad_conn file]] set compiled [ns_quotehtml [template::adp_compile -file $dir/$file]] } ns_return 200 text/html "
    $compiled
    " set dir [file dirname [ns_url2file [ns_conn url]]] openacs-5.7.0/packages/acs-lang/www/admin/test/catalog-test.adp0000644000175000017500000000327407550315421024216 0ustar frankiefrankie<% ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=iso-8859-1" %> @header@

    @title@

    @context_bar@

    [ad_locale user locale] ==> @locale@
    [ad_locale user language] ==> @language@
    [ad_locale_language_name @language@] ==> @language_name@

    Test 1

    Verify that the message catalog loader ran successfully at server startup.

    Word to lookupLanguageResults of catalog lookup
    EnglishEnglish@english@
    FrenchFrench@french@
    SpanishSpanish@spanish@
    GermanGerman@german@

    Test 2

    Verify that the <trn> ADP tag works when the user's preferred language is set to English, French, Spanish, or German.

    Test of inline adp tags:
    Word to lookup <TRN> \#...#
    English English #test.English#
    French French #test.French#
    Spanish Spanish #test.Spanish#
    German German #test.German#

    @footer@ openacs-5.7.0/packages/acs-lang/www/admin/test/catalog-test.tcl0000644000175000017500000000144310210116412024212 0ustar frankiefrankie#/packages/lang/www/test.tcl ad_page_contract { Tests procedures in the lang package @author John Lowry (lowry@ardigita.com) @creation-date 29 September 2000 @cvs-id $Id: catalog-test.tcl,v 1.2 2005/02/26 16:00:10 jeffd Exp $ } { } set title "Test acs-lang package message catalog and locale API" set header [ad_header $title] set context_bar [ad_context_bar "Message Catalog Test"] set footer [ad_footer] # Test 1 verifies that the message catalog has loaded successfully set english [_ en test.English] set french [_ fr test.French] set spanish [_ es test.Spanish] set german [_ de test.German] set locale [lang::user::locale] #set locale "ja_JP" set language [lang::user::language] #set language ja set language_name [ad_locale_language_name $language] ad_return_templateopenacs-5.7.0/packages/acs-lang/www/admin/test/test.adp0000644000175000017500000000613307550315421022603 0ustar frankiefrankie<% ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=iso-8859-1" %> @header@

    @title@

    Your Workspace : Testing the language and localization API

    Test 1

    Verify that the message catalog loader ran successfully at server startup.

    Word to lookupLanguageResults of catalog lookup
    EnglishEnglish@english@
    FrenchFrench@french@
    SpanishSpanish@spanish@
    GermanGerman@german@

    Test 2

    Verify that the <trn> ADP tag works when the user's preferred language is set to English, French, Spanish, or German.

    Word to lookupResult when user's preferred language is @language@
    English@trn_english@
    French@trn_french@
    Spanish@trn_spanish@
    German@trn_german@

    Test 3

    Verify that data required to convert from local times for Europe/Paris into Universal Time is loaded into the database.

    TimezoneStart dateEnd dateUTC offset
    @tz_results.timezone@@tz_results.local_start@ @tz_results.local_end@@tz_results.utc_offset@

    Test 4

    Verify that the conversions between UTC and local time work correctly.

    Oracle sysdate (should be UTC)@system_time@
    Local time in Europe/Paris@paris_time@
    UTC time (converted from Paris time)@local_time@
    Local time in Tokyo, Japan@tokyo_time@
    UTC time (converted from Tokyo time)@tokyo_utc_time@

    Test 5

    Verify the results of localization routines.

    Routineen_US locale en_FR locale
    Displaying a number @us_number@ @fr_number@
    Parsing a number @us_parse@ @fr_parse@
    Displaying a monetary amount @us_currency@ @fr_currency@
    @us_label@ @fr_label@
    Displaying a date @us_time@ @fr_time@

    @footer@ openacs-5.7.0/packages/acs-lang/www/admin/test/test.tcl0000644000175000017500000000573310551254374022632 0ustar frankiefrankie#/packages/lang/www/test.tcl ad_page_contract { Tests procedures in the lang package @author John Lowry (lowry@ardigita.com) @creation-date 29 September 2000 @cvs-id $Id: test.tcl,v 1.3 2007/01/10 21:22:04 gustafn Exp $ } { } set title "Test lang package" set header [ad_header $title] # set navbar [ad_context_bar "Test"] set footer [ad_footer] # Test 1 verifies that the message catalog has loaded successfully set english [_ en test.English] set french [_ fr test.French] set spanish [_ es test.Spanish] set german [_ de test.German] #set lang [lang::user::language] set lang [ad_get_client_property lang locale] if {$lang eq ""} { set lang "en" } db_1row lang_get_lang_name "SELECT nls_language as language FROM ad_locales WHERE language = :lang" if {$language eq ""} { set language English } # Test 2 checks the locale cookie to display in user's preferred language. # We cannot embed the tags in the template because they will not get run each time. # So we won't see the results of changing the locale cookie immediately. set trn_english [ns_adp_parse "English"] set trn_french [ns_adp_parse "French"] set trn_spanish [ns_adp_parse "Spanish"] set trn_german [ns_adp_parse "German"] # Test 3 checks that the timezone tables are installed # Need this data to check that test 4 works set tz_sql "SELECT tz as timezone ,local_start ,local_end ,ROUND(timezones.gmt_offset * 24) as utc_offset FROM timezone_rules, timezones WHERE timezones.tz = 'Europe/Paris' and timezone_rules.tz_id = timezones.tz_id AND local_start > sysdate - 365 AND local_end < sysdate + 365 ORDER BY local_start" db_multirow tz_results lang_tz_get_data $tz_sql # Test 4 checks that we can convert from local time to UTC db_1row lang_system_time_select "SELECT to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') AS system_time FROM dual" set paris_time [lc_time_utc_to_local $system_time "Europe/Paris"] set local_time [lc_time_local_to_utc $paris_time "Europe/Paris"] set tokyo_time [lc_time_utc_to_local $system_time "Asia/Tokyo"] set tokyo_utc_time [lc_time_local_to_utc $paris_time "Asia/Tokyo"] # Test 5 checks the localization routines set us_number [lc_numeric 123456.789 {} en_US] set fr_number [lc_numeric 123456.789 {} fr_FR] set us_parse [lc_parse_number 123,456.789 en_US] set fr_parse [lc_parse_number "123 456,789" fr_FR] set us_currency [lc_monetary_currency -label_p 1 -style local 123.4 USD en_US] set fr_currency [lc_monetary_currency -label_p 1 -style local 123.4 USD fr_FR] set us_label [lc_monetary_currency -label_p 1 -style local 1234 FRF en_US] set fr_label [lc_monetary_currency -label_p 1 -style local 1234 FRF fr_FR] set us_time [lc_time_fmt $system_time "%c" en_US] set fr_time [lc_time_fmt $system_time "%c" fr_FR] ad_return_templateopenacs-5.7.0/packages/acs-lang/www/admin/test/index.html0000644000175000017500000000103107736253000023123 0ustar frankiefrankie ACS I18N Tests

    ACS I18N Tests

    Note, the timezone and currency formatting tests require the acs-reference package to be loaded. openacs-5.7.0/packages/acs-lang/www/admin/test/tz-test.tcl0000644000175000017500000000076707550315421023263 0ustar frankiefrankie ad_page_contract { Test system timezone offset mechanism } { } append page " ad_locale_system_timezone = [ad_locale_get_system_timezone] ad_locale_system_tz_offset = [ad_locale_system_tz_offset]

    " set widget "" append page "

    Timezone $widget

    " doc_return 200 text/html $page openacs-5.7.0/packages/acs-lang/www/admin/test/timezone-postgresql.xql0000644000175000017500000000046207550315421025716 0ustar frankiefrankie postgresql7.1 select to_char(current_time, 'YYYY-MM-DD HH24:MI:SS') AS system_time openacs-5.7.0/packages/acs-lang/www/admin/test/test-oracle.xql0000644000175000017500000000044307550315421024104 0ustar frankiefrankie oracle8.1.6 SELECT to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') AS system_time FROM dual openacs-5.7.0/packages/acs-lang/www/admin/test/timezone.adp0000644000175000017500000000364707550315421023465 0ustar frankiefrankie<% ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=iso-8859-1" %> @header@

    @title@

    Your Workspace : Testing the timezone API

    Test 3

    Verify that data required to convert from local times for Europe/Paris into Universal Time is loaded into the database.

    TimezoneStart dateEnd dateUTC offset
    @tz_results.timezone@@tz_results.local_start@ @tz_results.local_end@@tz_results.utc_offset@

    Test 4

    Verify that the conversions between UTC and local time work correctly.

    LocaleTimeTest Passed?
    Oracle sysdate (should be UTC)@system_time@ 
     
    Local time in America/New_York@NYC_time@ 
    UTC time (converted from New York time)@NYC_utc_time@@NYC_p@
     
    Local time in America/Los_Angeles@LA_time@  
    UTC time (converted from Los Angeles time)@LA_utc_time@@LA_p@
     
    Local time in Europe/Paris@paris_time@ 
    UTC time (converted from Paris time)@paris_utc_time@@paris_p@
     
    Local time in Asia/Tokyo@tokyo_time@ 
    UTC time (converted from Tokyo time)@tokyo_utc_time@@tokyo_p@

    @footer@ openacs-5.7.0/packages/acs-lang/www/admin/test/timezone.tcl0000644000175000017500000000420210551254374023473 0ustar frankiefrankie#/packages/lang/www/test.tcl ad_page_contract { Tests procedures in the lang package @author John Lowry (lowry@ardigita.com) @creation-date 29 September 2000 @cvs-id $Id: timezone.tcl,v 1.2 2007/01/10 21:22:04 gustafn Exp $ } { } set title "Test acs-lang package timezones" set header [ad_header $title] # set navbar [ad_context_bar "Test"] set footer [ad_footer] # Test 3 checks that the timezone tables are installed # Need this data to check that test 4 works set tz_sql "SELECT tz as timezone ,local_start ,local_end ,ROUND(timezones.gmt_offset * 24) as utc_offset FROM timezone_rules, timezones WHERE timezones.tz = 'Europe/Paris' and timezone_rules.tz_id = timezones.tz_id AND local_start > sysdate - 365 AND local_end < sysdate + 365 ORDER BY local_start" db_multirow tz_results lang_tz_get_data $tz_sql # Test 4 checks that we can convert from local time to UTC db_1row lang_system_time_select "SELECT to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') AS system_time FROM dual" set NYC_time [lc_time_utc_to_local $system_time "America/New_York"] set NYC_utc_time [lc_time_local_to_utc $NYC_time "America/New_York"] if {$system_time eq $NYC_utc_time } { set NYC_p "OK" } else { set NYC_p "FAILED" } set LA_time [lc_time_utc_to_local $system_time "America/Los_Angeles"] set LA_utc_time [lc_time_local_to_utc $LA_time "America/Los_Angeles"] if {$system_time eq $LA_utc_time } { set LA_p "OK" } else { set LA_p "FAILED" } set paris_time [lc_time_utc_to_local $system_time "Europe/Paris"] set paris_utc_time [lc_time_local_to_utc $paris_time "Europe/Paris"] if {$system_time eq $paris_utc_time } { set paris_p "OK" } else { set paris_p "FAILED" } set tokyo_time [lc_time_utc_to_local $system_time "Asia/Tokyo"] set tokyo_utc_time [lc_time_local_to_utc $tokyo_time "Asia/Tokyo"] if {$system_time eq $tokyo_utc_time } { set tokyo_p "OK" } else { set tokyo_p "FAILED" } ad_return_template openacs-5.7.0/packages/acs-lang/www/admin/test/format-test-postgresql.xql0000644000175000017500000000046207550315421026331 0ustar frankiefrankie postgresql7.1 SELECT to_char(current_time, 'YYYY-MM-DD HH24:MI:SS') AS system_time openacs-5.7.0/packages/acs-lang/www/admin/test/show-catalog.adp0000644000175000017500000000063307550315421024213 0ustar frankiefrankie<% ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=utf-8" %> Message Catalog
    Lang Message
    @catalog.key@
    @catalog.locale@ @catalog.message@
    openacs-5.7.0/packages/acs-lang/www/admin/test/show-catalog.tcl0000644000175000017500000000125607550315421024233 0ustar frankiefrankie#/packages/acs-lang/www/show-catalog.tcl ad_page_contract { List contents of message catalog @author Henry Minsky (hqm@ardigita.com) @creation-date 29 September 2000 @cvs-id $Id: show-catalog.tcl,v 1.1 2002/10/07 14:32:49 lars Exp $ } { } set title "Show Message Catalog" set header [ad_header $title] # set navbar [ad_context_bar "Show Message Catalog "] set footer [ad_footer] # Test 3 checks that the timezone tables are installed # Need this data to check that test 4 works set cat_sql "SELECT key, locale, message, registered_p FROM lang_messages ORDER BY key, locale" db_multirow catalog catalog_data $cat_sql ad_return_template openacs-5.7.0/packages/acs-lang/www/admin/test/format-test-oracle.xql0000644000175000017500000000044307550315421025372 0ustar frankiefrankie oracle8.1.6 SELECT to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') AS system_time FROM dual openacs-5.7.0/packages/acs-lang/www/admin/test/format-test.adp0000644000175000017500000000205307550315421024066 0ustar frankiefrankie<% ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=iso-8859-1" %> @header@

    @title@

    Your Workspace : Testing the locale-dependent formatting API

    Test 5

    Verify the results of localization routines.

    Routineen_US locale en_FR locale
    Displaying a number @us_number@ @fr_number@
    Parsing a number @us_parse@ @fr_parse@
    Displaying a monetary amount @us_currency@ @fr_currency@
    @us_label@ @fr_label@
    Displaying a date @us_time@ @fr_time@

    @footer@ openacs-5.7.0/packages/acs-lang/www/admin/test/format-test.tcl0000644000175000017500000000221607550315421024105 0ustar frankiefrankie#/packages/lang/www/test.tcl ad_page_contract { Tests procedures in the lang package @author John Lowry (lowry@ardigita.com) @creation-date 29 September 2000 @cvs-id $Id: format-test.tcl,v 1.1 2002/10/07 14:32:49 lars Exp $ } { } set title "Test acs-lang package formatting routines" set header [ad_header $title] # set navbar [ad_context_bar "Test"] set footer [ad_footer] db_1row lang_system_time_select "SELECT to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') AS system_time FROM dual" # Test 5 checks the localization routines set us_number [lc_numeric 123456.789 {} en_US] set fr_number [lc_numeric 123456.789 {} fr_FR] set us_parse [lc_parse_number 123,456.789 en_US] set fr_parse [lc_parse_number "123 456,789" fr_FR] set us_currency [lc_monetary_currency -label_p 1 -style local 123.4 USD en_US] set fr_currency [lc_monetary_currency -label_p 1 -style local 123.4 USD fr_FR] set us_label [lc_monetary_currency -label_p 1 -style local 1234 FRF en_US] set fr_label [lc_monetary_currency -label_p 1 -style local 1234 FRF fr_FR] set us_time [lc_time_fmt $system_time "%c" en_US] set fr_time [lc_time_fmt $system_time "%c" fr_FR] ad_return_templateopenacs-5.7.0/packages/acs-lang/www/admin/test/translator-mode.adp0000644000175000017500000000065007736253000024735 0ustar frankiefrankie

    Tcl message: @tcl_message@

    ADP Message: #acs-lang.Spanish#

    Form:

    In an HTML attribute: #acs-lang.Spanish#

    Two HTML attributes: #acs-lang.Spanish#

    Message inside a message: @complete_message@

    openacs-5.7.0/packages/acs-lang/www/admin/test/translator-mode.tcl0000644000175000017500000000143007736253000024750 0ustar frankiefrankiead_page_contract { Testing translator mode. } set tcl_message [_ acs-lang.French] set options [list] foreach elm { English French German Spanish } { lappend options [list [_ acs-lang.$elm] $elm] } ad_form -name test -form { {lang:text(select) {label Language} {options $options} } {lang2:text(select) {label Language} {options $options} } } lang::message::register \ en_US \ acs-lang \ Test_Contained_Message \ "Contains message %contained_message% inside of it." lang::message::register \ [ad_conn locale] \ acs-lang \ Test_Contained_Message \ "Contains message %contained_message% inside of it." set contained_message [_ acs-lang.German] set complete_message [_ acs-lang.Test_Contained_Message] openacs-5.7.0/packages/acs-lang/www/admin/message-conflict-revert.tcl0000644000175000017500000000111010017410257025374 0ustar frankiefrankiead_page_contract { Revert the a message to the last overwritten version. Mark conflict of an I18N message as resolved, i.e. set the conflict_p flag to false. @author Peter Marklund } { package_key message_key locale {return_url {[export_vars -base "message-conflicts" { package_key locale }]}} } db_transaction { lang::message::revert \ -package_key $package_key \ -message_key $message_key \ -locale $locale lang::message::edit $package_key $message_key $locale [list conflict_p f] } ad_returnredirect $return_url openacs-5.7.0/packages/acs-lang/www/admin/batch-editor-oracle.xql0000644000175000017500000000244207716731574024533 0ustar frankiefrankie oracle8.1.6 select q2.* from (select rownum as inner_rownum, q.* from (select lm1.message_key, lm1.package_key, lm1.message as default_message, lm2.message as translated_message, lmk.description from lang_messages lm1, lang_messages lm2, lang_message_keys lmk where lm1.locale = :default_locale and lm2.locale (+) = :locale and lm2.message_key (+) = lm1.message_key and lm2.package_key (+) = lm1.package_key and lm1.message_key = lmk.message_key and lm1.package_key = lmk.package_key and lm1.package_key = :package_key $where_clause order by upper(lm1.message_key), lm1.message_key ) q ) q2 where inner_rownum between :page_start + 1 and :page_start + 10 order by inner_rownum openacs-5.7.0/packages/acs-lang/www/admin/edit-history.adp0000644000175000017500000000115707752702013023273 0ustar frankiefrankie Displaying:

    • Locale: @locale@
    • Number of edits: @number_of_edits@
    • Excluding emails like: @email_exclude@

    Key Overwrite date Old message User
    @history.package_key@.@history.message_key@ @history.overwrite_date@ @history.old_message@ @history.user_name@
    openacs-5.7.0/packages/acs-lang/www/admin/edit-history.tcl0000644000175000017500000000317107752702013023307 0ustar frankiefrankiead_page_contract { A page displaying recent editing of translations. @author Peter Marklund } { {locale "de_DE"} {number_of_edits 400} {email_exclude ""} } set list_of_locales [db_list_of_lists locale_loop { select label, locale from enabled_locales order by label }] set admin_email peter@collaboraid.biz ad_form \ -name locale \ -method GET \ -form { {locale:text(select) {label "Locale"} {options $list_of_locales} } {number_of_edits:text,optional {label "Number of edits"} {value $number_of_edits} } {email_exclude:text,optional {label "Email pattern to exclude"} {value $email_exclude} } } set email_clause [ad_decode $email_exclude "" "" "and cu.email not like '%$email_exclude%'"] db_multirow -extend { key_url } history german_edit_history " select q.* from (select lma.overwrite_date, lma.old_message, lma.message_key, lma.package_key, lma.locale, cu.first_names || cu.last_name as user_name from lang_messages_audit lma, cc_users cu where cu.user_id = lma.overwrite_user and lma.locale = :locale $email_clause order by lma.overwrite_date desc) q where rownum < :number_of_edits " { set key_url [export_vars -base /acs-lang/admin/edit-localized-message {package_key message_key locale}] } openacs-5.7.0/packages/acs-lang/www/admin/batch-editor.adp0000644000175000017500000000346010052153350023202 0ustar frankiefrankie @page_title@ @context;noquote@

    Show: | @show_opts.label@ (@show_opts.count@) @show_opts.label@ (@show_opts.count@)

    No messages

    @pagination.text@ @pagination.text@

    @pagination.text@ @pagination.text@

    openacs-5.7.0/packages/acs-lang/www/admin/batch-editor.tcl0000644000175000017500000002060710622143337023231 0ustar frankiefrankiead_page_contract { A quick and dirty batch editor for translation. @author Christian Hvid } { locale package_key {show "all"} {page_start 0} } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Batch edit messages" set context [list [list "package-list?[export_vars { locale }]" $locale_label] \ [list "message-list?[export_vars { locale package_key show }]" $package_key] \ $page_title] # TODO: PG ##### # # Handle filtering # ##### # LARS: The reason I implemented this overly complex way of doing it is that I was just about to # merge this page with messages-search ... set where_clauses [list] set keys_where_clauses [list] switch -exact $show { translated { lappend where_clauses {lm2.message is not null} lappend keys_where_clauses {exists (select 1 from lang_messages lm where lm.package_key = lmk.package_key and lm.message_key = lmk.message_key and lm.locale = :current_locale)} } untranslated { lappend where_clauses {lm2.message is null} lappend keys_where_clauses {not exists (select 1 from lang_messages lm where lm.package_key = lmk.package_key and lm.message_key = lmk.message_key and lm.locale = :current_locale)} } } set where_clause {} set keys_where_clause {} if { [llength $where_clauses] > 0 } { set where_clause "and [join $where_clauses "\n and "]" } if { [llength $keys_where_clauses] > 0 } { set keys_where_clause "and [join $keys_where_clauses "\n and "]" } ##### # # Counting messages # ##### db_1row counts { select (select count(*) from lang_messages where package_key = :package_key and locale = :locale) as num_translated, (select count(*) from lang_message_keys where package_key = :package_key) as num_messages from dual } set num_untranslated [expr {$num_messages - $num_translated}] set num_messages_pretty [lc_numeric $num_messages] set num_translated_pretty [lc_numeric $num_translated] set num_untranslated_pretty [lc_numeric $num_untranslated] ##### # # Initialize pagination # ##### set keys [db_list get_keys " select lmk.message_key from lang_message_keys lmk where lmk.package_key = :package_key $keys_where_clause order by upper(lmk.message_key), lmk.message_key "] set total [llength $keys] set page_end [expr {$page_start + 10}] ##### # # Build the form # ##### set edit_buttons [list] if { $show ne "untranslated" && $page_start > 0 } { lappend edit_buttons { "< Update and back" "prev" } } lappend edit_buttons { "Update" "ok" } if { $show ne "untranslated" && $page_end < [expr {$total}] } { lappend edit_buttons { "Update and next >" "next" } } ad_form -name batch_editor -edit_buttons $edit_buttons -form { {locale:text(hidden) {value $locale}} {package_key:text(hidden) {value $package_key}} {page_start:integer(hidden),optional} {show:text(hidden),optional} } # Each message has the following fields: # # message_key_x:text(hidden) # message_key_pretty_x:text(inform) # description_x:text(inform) # default_locale_message_x:text(textarea) # message_x:text(textarea) # org_message_x:text(hidden) set count $page_start array set sections {} db_foreach get_messages {} { ad_form -extend -name batch_editor -form \ [list [list "message_key_$count:text(hidden)" {value $message_key}]] set message_url "edit-localized-message?[export_vars { locale package_key message_key show }]" # Adding section set section_name "$package_key.$message_key" if { ![info exists sections($section_name)] } { set sec [list "-section" $section_name {legendtext "$section_name"}] ad_form -extend -name batch_editor -form [list $sec] set sections($section_name) "$section_name" } ad_form -extend -name batch_editor -form \ [list [list "message_key_pretty_$count:text(inform)" \ {label "Message Key"} \ {value "$package_key.$message_key"}]] if { $description ne "" } { set description_edit_url "edit-description?[export_vars { locale package_key message_key show }]" set description "[ad_text_to_html -- $description] [subst { (edit)}]" ad_form -extend -name batch_editor -form \ [list [list "description_$count:text(inform),optional" \ {label "Description"} \ {value $description}]] } if { $current_locale ne $default_locale } { ad_form -extend -name batch_editor -form \ [list [list "default_locale_message_$count:text(inform),optional" \ {label $default_locale_label} \ {value {[ad_quotehtml $default_message]}}]] } if { [string length $translated_message] > 80 } { set html { cols 80 rows 15 } } else { set html { cols 60 rows 2 } } ad_form -extend -name batch_editor -form \ [list [list "org_message_$count:text(hidden),optional"]] ad_form -extend -name batch_editor -form \ [list [list "message_$count:text(textarea),optional" {label $locale_label} {html $html}]] # We set this as a local variable, so that ad_form's normal system works set message_$count $translated_message incr count } ad_form -extend -name batch_editor -on_request { # Set from local vars } -on_submit { for { set i $page_start } { $i < $page_end && $i < $total } { incr i } { if { [set org_message_$i] ne [set message_$i] } { lang::message::register $current_locale $package_key \ [set message_key_$i] \ [set message_$i] } } set button [form::get_button batch_editor] if { $button ne "ok" } { switch $button { prev { set page_start [expr {$page_start - 10}] if { $page_start < 0 } { set page_start 0 } } next { set page_start [expr {$page_start + 10}] if { $page_start > $total } { set page_start [expr {$total - ($total % 10)}] } } } } ad_returnredirect "[ad_conn url]?[export_vars { locale package_key show page_start }]" ad_script_abort } ##### # # Slider for pagination # ##### multirow create pagination text hint url selected group for {set count 0} {$count < $total} {incr count 10 } { set end_page [expr {$count + 9}] if { $end_page > [expr {$total-1}] } { set end_page [expr {$total-1}] } set text {} if { [string match "lt_*" [lindex $keys $count]] } { append text [string range [lindex $keys $count] 3 5] } else { append text [string range [lindex $keys $count] 0 2] } append text " - " if { [string match "lt_*" [lindex $keys $end_page]] } { append text [string range [lindex $keys $end_page] 3 5] } else { append text [string range [lindex $keys $end_page] 0 2] } multirow append pagination \ $text \ "[lindex $keys $count] - [lindex $keys $end_page]" \ "batch-editor?[export_vars { { page_start $count } locale package_key show }]" \ [expr {$count == $page_start}] \ [expr {$count / 100}] } ##### # # Slider for 'show' options # ##### multirow create show_opts value label count multirow append show_opts "all" "All" $num_messages_pretty multirow append show_opts "translated" "Translated" $num_translated_pretty multirow append show_opts "untranslated" "Untranslated" $num_untranslated_pretty multirow extend show_opts url selected_p multirow foreach show_opts { set selected_p [string equal $show $value] if {$value eq "all"} { set url "[ad_conn url]?[export_vars { locale package_key }]" } else { set url "[ad_conn url]?[export_vars { locale package_key {show $value} }]" } } openacs-5.7.0/packages/acs-lang/www/admin/batch-editor-postgresql.xql0000644000175000017500000000157407716731574025476 0ustar frankiefrankie postgresql7.1 select lm1.message_key, lm1.package_key, lm1.message as default_message, lm2.message as translated_message, lmk.description from lang_messages lm1 left outer join lang_messages lm2 on (lm2.locale = :locale and lm2.message_key = lm1.message_key and lm2.package_key = lm1.package_key), lang_message_keys lmk where lm1.locale = :default_locale and lm1.package_key = :package_key and lm1.message_key = lmk.message_key and lm1.package_key = lmk.package_key $where_clause order by upper(lm1.message_key), lm1.message_key offset $page_start limit 10 openacs-5.7.0/packages/acs-lang/www/admin/message-delete.adp0000644000175000017500000000051711002042113023507 0ustar frankiefrankie @page_title@ @context;noquote@

    Deleting message for key @package_key@.@message_key@ in locale @locale@.

    @form_export_vars;noquote@
    openacs-5.7.0/packages/acs-lang/www/admin/message-delete.tcl0000644000175000017500000000217411002042113023526 0ustar frankiefrankiead_page_contract { Delete a message @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-08-15 @cvs-id $Id: message-delete.tcl,v 1.5 2008/04/18 06:48:43 victorg Exp $ } { locale package_key message_key show:optional confirm_p:optional } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Delete Message" set context [list [list "package-list?[export_vars { locale }]" $locale_label] \ [list "message-list?[export_vars { locale package_key show }]" $package_key] \ $page_title] set form_export_vars [export_vars -form { locale package_key message_key show {confirm_p 1} }] if { [exists_and_not_null confirm_p] && [template::util::is_true $confirm_p] } { lang::message::delete \ -package_key $package_key \ -message_key $message_key \ -locale $locale ad_returnredirect "message-list?[export_vars { locale package_key show }]" ad_script_abort } openacs-5.7.0/packages/acs-lang/www/admin/locale-set-enabled-p.tcl0000644000175000017500000000057207766162051024551 0ustar frankiefrankiead_page_contract { Sets enabled_p for a locale. @author Simon Carstensen (simon@collaboraid.biz) @creation-date 2003-08-08 } { locale enabled_p:boolean } lang::system::locale_set_enabled \ -locale $locale \ -enabled_p $enabled_p if {$enabled_p} { lang::catalog::import -locales [list $locale] } ad_returnredirect . ad_script_abort openacs-5.7.0/packages/acs-lang/www/admin/message-list-postgresql.xql0000644000175000017500000000156610017410257025503 0ustar frankiefrankie postgresql7.1 select lm1.message_key, lm1.message as default_message, lm2.message as translated_message, lmk.description, coalesce(lm2.deleted_p, 'f') as deleted_p from lang_messages lm1 left outer join lang_messages lm2 on (lm2.locale = :locale and lm2.message_key = lm1.message_key and lm2.package_key = lm1.package_key), lang_message_keys lmk where lm1.locale = :default_locale and lm1.package_key = :package_key and lm1.message_key = lmk.message_key and lm1.package_key = lmk.package_key $where_clause order by upper(lm1.message_key), lm1.message_key openacs-5.7.0/packages/acs-lang/www/admin/message-search-postgresql.xql0000644000175000017500000000177707714712710026012 0ustar frankiefrankie postgresql7.1 select lm1.message_key, lm1.package_key, lm1.message as default_message, coalesce(lm2.message, 'TRANSLATION MISSING') as translated_message from lang_messages lm1 left outer join lang_messages lm2 on (lm2.locale = :locale and lm2.message_key = lm1.message_key and lm2.package_key = lm1.package_key) where lm1.locale = :default_locale and exists (select 1 from lang_messages lm3 where lm3.locale = :search_locale and lm3.message_key = lm1.message_key and lm3.package_key = lm1.package_key and lm3.message ilike :search_string) order by upper(lm1.message_key) openacs-5.7.0/packages/acs-lang/www/admin/lookup.adp0000644000175000017500000000072111547574033022162 0ustar frankiefrankie @page_title@ @context;noquote@ lookup.key

    #acs-lang.Look_up_message#

    #acs-lang.Translated_Message#

    @message@

    openacs-5.7.0/packages/acs-lang/www/admin/lookup.tcl0000644000175000017500000000140511547574033022200 0ustar frankiefrankiead_page_contract { Test message lookup } set page_title "Test Message Lookup" set context [list $page_title] set message_p 0 ad_form -name lookup -form { {key:text {label "[_ acs-lang.Message_key]"} {help_text "[_ acs-lang.Include_package_key_as]"} {html {size 50}} } {locale:text {label "[_ acs-lang.Locale]"} {help_text "[_ acs-lang.Can_be_two_character]"} } } -on_submit { # No substitution set message [lang::message::lookup $locale $key] set keyv [split $key "."] set package_key [lindex $keyv 0] set message_key [lindex $keyv 1] set edit_url [export_vars -base edit-localized-message { package_key locale message_key {return_url [ad_return_url]} }] set message_p 1 } openacs-5.7.0/packages/acs-lang/www/admin/load-catalog-files.tcl0000644000175000017500000000040407743473744024326 0ustar frankiefrankiead_page_contract { Load all catalog files. @author Peter Marklund (peter@collaboraid.biz) @creation-date 2002-10-07 @cvs-id $Id: load-catalog-files.tcl,v 1.5 2003/10/16 10:50:12 peterm Exp $ } lang::catalog::import ad_returnredirect "index" openacs-5.7.0/packages/acs-lang/www/admin/message-list.adp0000644000175000017500000000661211002042113023222 0ustar frankiefrankie @page_title@ @context;noquote@
    @form_vars;noquote@
    Language

    Show: | @show_opts.label@ (@show_opts.count@) @show_opts.label@ (@show_opts.count@)

    Message Key @default_locale_label@ Message @locale_label@ Message
    @messages.message_key_pretty@ @messages.default_message@ DELETED (@messages.translated_message@) @messages.translated_message@ Not translated
    openacs-5.7.0/packages/acs-lang/www/admin/message-list.tcl0000644000175000017500000001151611547363053023266 0ustar frankiefrankiead_page_contract { Displays messages for translation @author Bruno Mattarollo @author Lars Pind (lars@collaboraid.biz) @creation-date 26 October 2001 @cvs-id $Id: message-list.tcl,v 1.15 2011/04/07 16:28:27 emmar Exp $ } { locale package_key {show "all"} } -validate { show_valid -requires { show } { if { [lsearch { all deleted translated untranslated } $show] == -1 } { ad_complain "Show must be one of 'all', 'deleted', 'translated', or 'untranslated'." } } } # 'show' can be "all", "translated", "untranslated" # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title $package_key set context [list [list [export_vars -base package-list { locale }] $locale_label] $page_title] set site_wide_admin_p [acs_user::site_wide_admin_p] set export_messages_url [export_vars -base "export-messages" { package_key locale { return_url {[ad_return_url]} } }] set import_messages_url [export_vars -base "import-messages" { package_key locale { return_url {[ad_return_url]} } }] # We let you create new messages keys if you're in the default locale set create_p [string equal $current_locale $default_locale] set new_message_url "localized-message-new?[export_vars { locale package_key }]" ##### # # Counting messages # ##### db_1row counts { select (select count(*) from lang_messages where package_key = :package_key and locale = :locale and deleted_p = 'f') as num_translated, (select count(*) from lang_messages where package_key = :package_key and locale = :default_locale and deleted_p = 'f') as num_messages, (select count(*) from lang_messages where package_key = :package_key and locale = :default_locale and deleted_p = 't') as num_deleted from dual } set num_untranslated [expr {$num_messages - $num_translated}] set num_messages_pretty [lc_numeric [expr {$num_messages + $num_deleted}]] set num_translated_pretty [lc_numeric $num_translated] set num_untranslated_pretty [lc_numeric $num_untranslated] set num_deleted_pretty [lc_numeric $num_deleted] ##### # # Handle filtering # ##### # LARS: The reason I implemented this overly complex way of doing it is that I was just about to # merge this page with messages-search ... set where_clauses [list] switch -exact $show { all { lappend where_clauses {lm1.deleted_p = 'f'} } translated { lappend where_clauses {lm2.message is not null} lappend where_clauses {(lm2.deleted_p = 'f' or lm2.deleted_p is null)} lappend where_clauses {lm1.deleted_p = 'f'} } untranslated { lappend where_clauses {(lm2.deleted_p = 'f' or lm2.deleted_p is null)} lappend where_clauses {lm1.deleted_p = 'f'} lappend where_clauses {lm2.message is null} } deleted { lappend where_clauses {lm1.deleted_p = 't'} } } if { [llength $where_clauses] == 0 } { set where_clause {} } else { set where_clause "and [join $where_clauses "\n and "]" } db_multirow -extend { edit_url delete_url message_key_pretty } messages select_messages {} { set edit_url "edit-localized-message?[export_vars { locale package_key message_key show {return_url {[ad_return_url]}} }]" set delete_url "message-delete?[export_vars { locale package_key message_key show {return_url {[ad_return_url]}} }]" set message_key_pretty "$package_key.$message_key" } # TODO: PG # TODO: Create message set batch_edit_url "batch-editor?[export_vars { locale package_key show }]" ##### # # Slider for 'show' options # ##### multirow create show_opts value label count multirow append show_opts "all" "All" $num_messages_pretty multirow append show_opts "translated" "Translated" $num_translated_pretty multirow append show_opts "untranslated" "Untranslated" $num_untranslated_pretty multirow append show_opts "deleted" "Deleted" $num_deleted_pretty multirow extend show_opts url selected_p multirow foreach show_opts { set selected_p [string equal $show $value] if {$value eq "all"} { set url "[ad_conn url]?[export_vars { locale package_key }]" } else { set url "[ad_conn url]?[export_vars { locale package_key {show $value} }]" } } # Locale switch set languages [lang::system::get_locale_options] ad_form -name locale_form -action [ad_conn url] -export { tree_id category_id } -form { {locale:text(select) {label "Language"} {value $locale} {options $languages}} } set form_vars [export_ns_set_vars form {locale form:mode form:id __confirmed_p __refreshing_p formbutton:ok} [ad_conn form]] openacs-5.7.0/packages/acs-lang/www/admin/set-system-timezone-oracle.xql0000644000175000017500000000072607573164573026136 0ustar frankiefrankie oracle8.1.6 select to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') from dual select to_char(timezone.local_to_utc(timezone.get_id(:system_timezone), sysdate), 'YYYY-MM-DD HH24:MI:SS') from dual openacs-5.7.0/packages/acs-lang/www/admin/locale-delete.adp0000644000175000017500000000052211456662500023343 0ustar frankiefrankie @page_title@ @context;noquote@

    Delete @locale_label@

    Are you sure you want to delete @locale_label@ which locale is @locale@?

    @form_export_vars;noquote@
    openacs-5.7.0/packages/acs-lang/www/admin/locale-delete.tcl0000644000175000017500000000206310210116412023342 0ustar frankiefrankie# /packages/acs-lang/www/admin/locale-delete.tcl ad_page_contract { Deletes a locale @author Bruno Mattarollo @creation-date 19 march 2002 @cvs-id $Id: locale-delete.tcl,v 1.5 2005/02/26 16:00:10 jeffd Exp $ } { locale confirm_p:optional } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Delete $locale_label" set context [list $page_title] set form_export_vars [export_vars -form { locale {confirm_p 1} }] if { [exists_and_not_null confirm_p] && [template::util::is_true $confirm_p] } { db_transaction { db_dml delete_messages { delete from lang_messages where locale = :locale } db_dml delete_audit { delete from lang_messages_audit where locale = :locale } db_dml delete_locale { delete from ad_locales where locale = :locale } } ad_returnredirect "." ad_script_abort } openacs-5.7.0/packages/acs-lang/www/admin/locale-new.adp0000644000175000017500000000043511321666756022705 0ustar frankiefrankie @page_title@ @context;noquote@ locale_creation.country

    Please fill in the fields to create a new locale.

    openacs-5.7.0/packages/acs-lang/www/admin/locale-new.tcl0000644000175000017500000000742211321666756022726 0ustar frankiefrankie# /packages/acs-lang/www/admin/locale-new.tcl ad_page_contract { Creates a new locale @author Bruno Mattarollo @creation-date 15 march 2002 @cvs-id $Id: locale-new.tcl,v 1.5 2010/01/08 17:39:58 emmar Exp $ } set locale_user [ad_conn locale] set page_title "Create Locale" set context [list $page_title] form create locale_creation # The v$nls_valid_values view contains all the valid NLS values # for the oracle instance. It is up to the user to select the correct # values (combinations of language, territories and character sets. More # information on this view can be found in the docs at http://tahiti.oracle.com/ # look for the PDF file of Oracle 8i "national language support guide" catch { set nls_values_list [db_list_of_lists select_nls_values {select parameter, value from v$nls_valid_values order by parameter, value}] foreach nls_value $nls_values_list { set value [lindex $nls_value 1] switch [lindex $nls_value 0] { LANGUAGE { lappend list_nls_language "\"$value\" \"$value\"" } TERRITORY { lappend list_nls_territory "\"$value\" \"$value\"" } CHARACTERSET { lappend list_nls_charset "\"$value\" \"$value\"" } } } } set countries_list [db_list_of_lists select_countries {}] element create locale_creation country \ -label "Country" \ -datatype text \ -widget select \ -options $countries_list set languages_list [db_list_of_lists select_languages {}] element create locale_creation language \ -label "Language" \ -datatype text \ -widget select \ -options $languages_list if { [info exists list_nls_language] } { element create locale_creation nls_language -label "NLS Language" \ -datatype text -widget select -options $list_nls_language element create locale_creation nls_territory -label "NLS Territory" \ -datatype text -widget select -options $list_nls_territory element create locale_creation nls_charset -label "NLS Charset" \ -datatype text -widget select -options $list_nls_charset } else { element create locale_creation nls_language -label "NLS Language" \ -datatype text -widget text element create locale_creation nls_territory -label "NLS Territory" \ -datatype text -widget text element create locale_creation nls_charset -label "NLS Charset" \ -datatype text -widget text } element create locale_creation mime_charset \ -label "MIME Charset" -datatype text -value "UTF8" if { [form is_request locale_creation] } { # Finish building the form to present to the user # Since it's a standard form and no special values need to # set up, we do nothing! :) } else { # If we are not building a request form, we are processing a submission. # Get the values from the form and validate them form get_values locale_creation } if { [form is_valid locale_creation] } { # We are receiving a valid submission form get_values locale_creation # label is built from language and country set label "[lang::util::language_label -language $language] ($country)" append locale $language "_" $country db_transaction { # If there is already a default for this language, then it will remain # the current one. We don't change that. set default_p "f" # We first make sure that there is no default for this language set is_default_p [db_string select_default {}] if { $is_default_p == "0" } { # There is a no default for this language set default_p "t" } db_dml insert_locale {} } forward "index?tab=locales" } openacs-5.7.0/packages/acs-lang/www/admin/locale-new.xql0000644000175000017500000000175411456662500022742 0ustar frankiefrankie select default_name, iso from countries order by default_name select label, coalesce(iso_639_1, iso_639_2) from language_639_2_codes order by label select count(*) from ad_locales where language = :language and default_p = 't' insert into ad_locales ( locale, language, country, variant, label, nls_language, nls_territory, nls_charset, mime_charset, default_p, enabled_p ) values ( :locale, :language, :country, NULL, :label, :nls_language, :nls_territory, :nls_charset, :mime_charset, :default_p, 'f' ) openacs-5.7.0/packages/acs-lang/www/admin/message-search-oracle.xql0000644000175000017500000000176107714712710025045 0ustar frankiefrankie oracle8.1.6 select lm1.message_key, lm1.package_key, lm1.message as default_message, lm2.message as translated_message from lang_messages lm1, lang_messages lm2 where lm1.locale = :default_locale and lm2.locale (+) = :locale and lm2.message_key (+) = lm1.message_key and lm2.package_key (+) = lm1.package_key and exists (select 1 from lang_messages lm3 where lm3.locale = :search_locale and lm3.message_key = lm1.message_key and lm3.package_key = lm1.package_key and upper(dbms_lob.substr(lm3.message)) like upper(:search_string)) order by upper(lm1.message_key) openacs-5.7.0/packages/acs-lang/www/admin/reload-cache.tcl0000644000175000017500000000037507556257517023215 0ustar frankiefrankiead_page_contract { Load all catalog files. @author Peter Marklund (peter@collaboraid.biz) @creation-date 2002-10-07 @cvs-id $Id: reload-cache.tcl,v 1.1 2002/10/25 15:12:15 peterm Exp $ } lang::message::cache ad_returnredirect "index" openacs-5.7.0/packages/acs-lang/www/admin/export-locale-to-files.adp0000644000175000017500000000036610006467722025147 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    Export finished.

    openacs-5.7.0/packages/acs-lang/www/admin/export-locale-to-files.tcl0000644000175000017500000000066310210116412025145 0ustar frankiefrankiead_page_contract { Export all catalog messages for a given locale to the file system. @author Lars Pind (lars@collaboraid.biz) } { locale } set locale_label [lang::util::get_label $locale] set page_title "Export all messages for locale $locale" set return_url [export_vars -base package-list { locale }] set context [list [list $return_url $locale_label] $page_title] lang::catalog::export -locales [list $locale] openacs-5.7.0/packages/acs-lang/www/admin/edit-description.adp0000644000175000017500000000033310052153350024077 0ustar frankiefrankie @page_title@ @context;noquote@ description.description openacs-5.7.0/packages/acs-lang/www/admin/edit-description.tcl0000644000175000017500000000321210210116412024106 0ustar frankiefrankiead_page_contract { Edit description of message key. @author Simon Carstensen @creation-date 2003-08-13 } { locale package_key message_key show:optional {description ""} } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Edit description" set context [list [list "package-list?[export_vars { locale }]" $locale_label] \ [list "message-list?[export_vars { locale package_key message_key show }]" $package_key] \ [list "edit-localized-message?[export_vars { locale package_key message_key show }]" "$package_key.$message_key"] \ $page_title] ad_form -name description -form { {locale:text(hidden)} {package_key:text(hidden)} {message_key:text(hidden)} {show:text(hidden)} {message_key_pretty:text(inform) {value "$package_key.$message_key"} {label "Message Key"} } {description:text(textarea),optional {label "Description"} {html { rows 15 cols 60 }} } {org_message:text(inform) {label "$default_locale_label Message"} } {submit:text(submit) {label " Update "} } } -on_request { db_1row select_description {} } -on_submit { lang::message::update_description \ -package_key $package_key \ -message_key $message_key \ -description $description ad_returnredirect "edit-localized-message?[export_vars { locale package_key message_key show }]" ad_script_abort } openacs-5.7.0/packages/acs-lang/www/admin/edit-description.xql0000644000175000017500000000111407717110324024145 0ustar frankiefrankie select lmk.description, (select lm.message as message from lang_messages lm where lm.package_key= :package_key and lm.message_key = :message_key and locale = :default_locale) as org_message from lang_message_keys lmk where lmk.package_key = :package_key and lmk.message_key = :message_key openacs-5.7.0/packages/acs-lang/www/admin/locale-make-default.tcl0000644000175000017500000000163610210116412024444 0ustar frankiefrankie# /packages/acs-lang/www/admin/locale-make-default.tcl ad_page_contract { Makes a locale the default for its language @author Bruno Mattarollo @creation-date 19 march 2002 @cvs-id $Id: locale-make-default.tcl,v 1.6 2005/02/26 16:00:10 jeffd Exp $ } { locale } -properties { } # If have first to revert the other locale to default_p = f db_transaction { set language_from_locale [db_string select_lang_from_locale "select language from ad_locales where locale = :locale"] db_dml make_locale_not_default "update ad_locales set default_p = 'f' where language = :language_from_locale and default_p = 't'" db_dml make_locale_default "update ad_locales set default_p = 't' where locale = :locale" } # Flush caches util_memoize_flush_regexp {^lang::util::default_locale_from_lang_not_cached} template::forward "index?tab=locales" openacs-5.7.0/packages/acs-lang/www/admin/import-messages.adp0000644000175000017500000000166311002042113023745 0ustar frankiefrankie @page_title;noquote@ Import results for all packages package @package_key@ and all locales locale @locale@ .

    Import finished. Number of messages processed: @message_count.processed@, added: @message_count.added@, updated: @message_count.updated@, deleted: @message_count.deleted@.

    The following errors were produced: @errors_list;noquote@

    There are @conflict_count@ message conflicts in the database. There are currently no conflicts in the database. openacs-5.7.0/packages/acs-lang/www/admin/import-messages.tcl0000644000175000017500000000156311002042113023762 0ustar frankiefrankiead_page_contract { Import messages from catalog files to the database. @author Peter Marklund } { {locale ""} {package_key ""} {return_url "/acs-lang/admin"} } set page_title "Import messages" if { ![acs_user::site_wide_admin_p] } { ad_return_warning "Permission denied" "Sorry, only site-wide administrators are allowed to import message catalog files to the database." ad_script_abort } array set message_count [lang::catalog::import \ -package_key $package_key \ -locales $locale] set conflict_count [lang::message::conflict_count \ -package_key $package_key \ -locale $locale] set errors_list "
    • [join $message_count(errors) "
    • "]
    " set conflict_url [export_vars -base message-conflicts { package_key locale }] openacs-5.7.0/packages/acs-lang/www/admin/set-system-timezone.adp0000644000175000017500000000562307716731574024634 0ustar frankiefrankie @page_title@ @context;noquote@

    Here's what the configuration looks like at this point:

    "#00bb00""red">
    Current time, according to the database: @sysdate@
    OpenACS Timezone setting: @system_timezone@
    Difference between database time and UTC according to OpenACS timezone setting above: @system_utc_offset@ hours
    UTC time according to database and the OpenACS timezone setting above: @sysdate_utc@
    Actual UTC time according to timeanddate.com: @utc_ansi@
    Does it look like the OpenACS timezone setting above is correct: YES! (Congratulations) NO. Set below.

    If the last two date and times are within a few seconds or minutes of each other, you're fine. Otherwise, you probably want to adjust what timezone OpenACS should think it's in below.


    You can use the form below to tell ACS what timezone your database is operating in. (There does not appear to be a nice way to ask the database this question automatically).

    Your server appears to be @recommended_offset_pretty@ which includes the following timezones:

    Or select from all zones:

    Set Timezone:

    openacs-5.7.0/packages/acs-lang/www/admin/set-system-timezone.tcl0000644000175000017500000000772210622143337024634 0ustar frankiefrankie# set-system-timezone.tcl ad_page_contract { Set the acs-lang system parameter which says what the local timezone offset is } { {timezone_all ""} {timezone_recommended ""} } -properties { page_title system_timezone sysdate system_utc_offset timezones:multirow utc_ansi } if { ![lang::system::timezone_support_p] } { ad_return_error "Timezone support not installed" "This installation of the acs-lang package does not support timezone settings. The ref-timezones package needs to be installed first" ad_script_abort } if { $timezone_recommended ne "" } { lang::system::set_timezone $timezone_recommended } elseif { $timezone_all ne "" } { lang::system::set_timezone $timezone_all } set page_title "Set System Timezone" set context [list $page_title] set system_timezone [lang::system::timezone] set sysdate [db_string sysdate {}] set sysdate_utc [db_string sysdate_utc {}] set system_utc_offset [lang::system::timezone_utc_offset] multirow create timezones label value selected_p foreach entry [lc_list_all_timezones] { set tz [lindex $entry 0] multirow append timezones $entry $tz [string equal $tz $system_timezone]> } # Try to get the correct UTC time from www.timeanddate.com if { [catch { set time_and_date_page [util_httpget "http://www.timeanddate.com/worldclock/"] regexp {Current UTC \(or GMT/Zulu\)-time used: ]*>([^<]*)} $time_and_date_page match utc_from_page # UTC in format: # Wednesday, November 20, 2002, at 2:49:07 PM # Wednesday, August 6, 2003, at 12:11:48 regexp {^([^,]*), *([^ ]*) *([0-9]*), *([0-9]*) at (.*)$} $utc_from_page match weekday month day year time set utc_epoch [clock scan "${month} ${day}, ${year} ${time}"] set utc_ansi [clock format $utc_epoch -format "%Y-%m-%d %T"] } errmsg] } { global errorInfo ns_log Error "Problem getting UTC time from timeanddate.com, they may have changed their design so our regexp stopped working.\n$errorInfo" set utc_ansi {Couldn't get time from timeanddate.com, sorry.} } set correct_p {} if { [info exists utc_epoch] } { with_catch errmsg { set sysdate_utc_epoch [clock scan $sysdate_utc] set delta_hours [expr {round(($sysdate_utc_epoch - $utc_epoch)*4.0 / (60*60)) / 4.0}] set recommended_offset [expr {$system_utc_offset + $delta_hours}] set recommended_offset_pretty "UTC [format "+%d:%02d" [expr {int($recommended_offset)}] [expr {int($recommended_offset*60) % 60}]]" if { $delta_hours == 0 } { set correct_p 1 } else { set correct_p 0 } set try_offsets [list] foreach offset [list $recommended_offset [expr {$recommended_offset -24}]] { # LARS 2003-11-05 # This is a workaround for a Tcl 8.3 bug on Solaris that causes int() on negative decimal # numbers to fail with "integer value too large to represent". # Example: 'expr int(-1.0)' throws an error; 'expr int(-1)' does not. if { $offset < 0 } { lappend try_offsets "'[db_quote [expr -int(abs($offset)*60*60)]]'" } else { lappend try_offsets "'[db_quote [expr {int($offset*60*60)}]]'" } } set query " select tz.tz, tz.gmt_offset from timezones tz, timezone_rules tzr where tzr.gmt_offset in ([join $try_offsets ", "]) and tzr.tz_id = tz.tz_id and to_date('$utc_ansi', 'YYYY-MM-DD HH24:MI:SS') between tzr.utc_start and tzr.utc_end order by tz " db_multirow -extend { value label selected_p } suggested_timezones select_suggested_timezones $query { set selected_p [string equal $tz $system_timezone] set value $tz set label "$tz $gmt_offset" } } { # Didn't work, too bad global errorInfo error $errmsg $errorInfo } } openacs-5.7.0/packages/acs-lang/www/admin/index.adp0000644000175000017500000001044211547574033021761 0ustar frankiefrankie @page_title@ @context@

    @page_title@

    #acs-lang.Actions#

    #acs-lang.Installed_Locales#

    #acs-lang.Locale# #acs-lang.Label# #acs-lang.Translated# #acs-lang.Untranslated# #acs-lang.Enabled# #acs-lang.Default_Locale_For_Language#
    #acs-lang.Edit_definition_of_locale# @locales.locale@ @locales.locale_label@ @locales.num_translated_pretty@ @locales.num_untranslated_pretty@ #acs-lang.Disable_this_locale# #acs-lang.Enable_this_locale# @locales.language@: #acs-lang.Default_Locale_For_Language# @locales.language@: #acs-lang.Make_this_locale_the_default_locale_for_language# #acs-lang.Delete_this_locale#
    openacs-5.7.0/packages/acs-lang/www/admin/index.tcl0000644000175000017500000000500511547574033021776 0ustar frankiefrankie# /packages/acs-lang/www/admin/index.tcl ad_page_contract { Administration of the localized messages @author Bruno Mattarollo @author Lars Pind (lars@collaboraid.biz) @creation-date 19 October 2001 @cvs-id $Id: index.tcl,v 1.11 2011/04/08 11:57:15 emmar Exp $ } # We rename to avoid conflict in queries set system_locale [lang::system::locale -site_wide] set system_locale_label [lang::util::get_label $system_locale] set page_title [_ acs-lang.Administration_of_Localization] set context [list] set site_wide_admin_p [acs_user::site_wide_admin_p] set timezone_p [lang::system::timezone_support_p] set timezone [lang::system::timezone] set translator_mode_p [lang::util::translator_mode_p] set import_url [export_vars -base import-messages] set export_url [export_vars -base export-messages] set parameter_url [export_vars -base "/shared/parameters" { {package_id {[ad_conn package_id]} } { return_url {[ad_return_url]} } }] ##### # # Locales # ##### set default_locale "en_US" db_1row counts { select count(*) as num_messages from lang_messages where locale = :default_locale and deleted_p = 'f' } db_multirow -extend { escaped_locale msg_edit_url locale_edit_url locale_delete_url locale_make_default_url locale_enabled_p_url num_translated_pretty num_untranslated num_untranslated_pretty } locales select_locales { select l.locale, l.label as locale_label, l.language, l.default_p as default_p, l.enabled_p as enabled_p, (select count(*) from ad_locales l2 where l2.language = l.language) as num_locales_for_language, (select count(*) from lang_messages lm2 where lm2.locale = l.locale and lm2.deleted_p = 'f') as num_translated from ad_locales l order by locale_label } { set escaped_locale [ns_urlencode $locale] set msg_edit_url "package-list?[export_vars { locale }]" set locale_edit_url "locale-edit?[export_vars { locale }]" set locale_delete_url "locale-delete?[export_vars { locale }]" set locale_make_default_url "locale-make-default?[export_vars { locale }]" set toggle_enabled_p [ad_decode $enabled_p "t" "f" "t"] set locale_enabled_p_url "locale-set-enabled-p?[export_vars { locale {enabled_p $toggle_enabled_p} }]" set num_translated_pretty [lc_numeric $num_translated] set num_untranslated [expr {$num_messages - $num_translated}] set num_untranslated_pretty [lc_numeric $num_untranslated] } openacs-5.7.0/packages/acs-lang/www/admin/package-list.adp0000644000175000017500000000461511547574033023223 0ustar frankiefrankie @page_title;noquote@ @context;noquote@ Search for
    #acs-lang.Package# #acs-lang.Translated# #acs-lang.Untranslated# #acs-lang.Total#
    @packages.package_key@ @packages.num_translated_pretty@ @packages.num_untranslated_pretty@ @packages.num_messages_pretty@
    openacs-5.7.0/packages/acs-lang/www/admin/package-list.tcl0000644000175000017500000000635211547363053023237 0ustar frankiefrankiead_page_contract { Displays packages that contain messages. @author Bruno Mattarollo @author Lars Pind (lars@collaboraid.biz) @creation-date 26 October 2001 @cvs-id $Id: package-list.tcl,v 1.10 2011/04/07 16:28:27 emmar Exp $ } { locale } -properties { locale_label page_title context current_locale default_locale packages:multirow search_form } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title $locale_label set context [list $page_title] set locale_enabled_p [expr [lsearch [lang::system::get_locales] $current_locale] != -1] set site_wide_admin_p [acs_user::site_wide_admin_p] ##### # # Package/message list # ##### db_multirow -extend { num_messages_pretty num_translated_pretty num_untranslated num_untranslated_pretty batch_edit_url view_messages_url view_translated_url view_untranslated_url } packages select_packages { select q.*, (select count(*) from lang_messages lm where lm.package_key = q.package_key and lm.locale = :current_locale and lm.deleted_p = 'f') as num_translated from (select lmk.package_key, count(message_key) as num_messages from lang_messages lmk where lmk.locale = :default_locale and lmk.deleted_p = 'f' group by package_key) q order by package_key } { set num_untranslated [expr {$num_messages - $num_translated}] set num_messages_pretty [lc_numeric $num_messages] set num_translated_pretty [lc_numeric $num_translated] set num_untranslated_pretty [lc_numeric $num_untranslated] set batch_edit_url "batch-editor?[export_vars { locale package_key }]" set view_messages_url "message-list?[export_vars { locale package_key }]" set view_translated_url "message-list?[export_vars { locale package_key { show "translated" } }]" set view_untranslated_url "message-list?[export_vars { locale package_key { show "untranslated" } }]" } ##### # # Search form # ##### set search_locales [list \ [list "Current locale - [lang::util::get_label $current_locale]" $current_locale] \ [list "Master locale - [lang::util::get_label $default_locale]" $default_locale]] ad_form -name search -action message-search -form { {locale:text(hidden) {value $locale}} } if { $default_locale ne $current_locale } { ad_form -extend -name search -form { {search_locale:text(select) {options $search_locales} {label "Search locale"} } } } else { ad_form -extend -name search -form { {search_locale:text(hidden) {value $current_locale} } } } ad_form -extend -name search -form { {q:text {label "Search for"} } } set import_all_url [export_vars -base import-messages { { locale $current_locale } {return_url {[ad_return_url]}} }] set export_all_url [export_vars -base export-messages { { locale $current_locale } {return_url {[ad_return_url]}} }] openacs-5.7.0/packages/acs-lang/www/admin/localized-message-new.adp0000644000175000017500000000032707745527771025046 0ustar frankiefrankie Edit a message @context;noquote@ @focus;noquote@ openacs-5.7.0/packages/acs-lang/www/admin/localized-message-new.tcl0000644000175000017500000000677411002042113025033 0ustar frankiefrankie# /packages/acs-lang/www/admin/localized-message-new.tcl ad_page_contract { Displays the form for the creation of a new localized message. @author Bruno Mattarollo @author Christian Hvid @creation-date 15 April 2002 @cvs-id $Id: localized-message-new.tcl,v 1.11 2008/04/18 06:48:43 victorg Exp $ } { locale package_key {message_key ""} {return_url {[export_vars -base message-list { locale package_key }]}} } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Create New Message" set context [list [list "package-list?[export_vars { locale }]" $locale_label] \ [list "message-list?[export_vars { locale package_key show }]" $package_key] \ $page_title] # We check that this request is coming for the system wide default # locale. If not, we can't allow the creation of a new localized # message. if { $current_locale ne $default_locale } { ad_return_error "Can only create messages in the default locale" "Can only create messages in the default locale" ad_script_abort } form create message_new element create message_new package_key_display -label "Package" -datatype text \ -widget inform -value $package_key element create message_new message_key -label "Message key" -datatype text -widget text -html { size 50 } element create message_new message -label "Message" -datatype text \ -widget textarea -html { rows 6 cols 40 } element create message_new package_key -datatype text -widget hidden element create message_new return_url -datatype text -widget hidden -optional # The two hidden tags that we need to pass on the key and language to the # processing of the form element create message_new locale -label "locale" -datatype text -widget hidden if { [form is_request message_new] } { element set_value message_new package_key $package_key element set_value message_new locale $current_locale element set_value message_new message_key $message_key element set_value message_new return_url $return_url if { $message_key eq "" } { set focus message_new.message_key } else { set focus message_new.message } } else { # We are not getting a request, so it's a post. Get and validate # the values form get_values message_new # We have to check the format of the key submitted by the user, # We can't accept whitespaces or tabs, only alphanumerical and "-", # "_" or "." characters. The 1st character can't be a "." if { [regexp {[^[:alnum:]\_\-\.\?]} $message_key] } { # We matched for a forbidden character element set_error message_new message_key \ "Key can only have alphanumeric or \"-\", \"_\", \".\" or \"?\" characters" } if { [string length $message_key] >= 200 } { # Oops. The length of the key is too high. element set_error message_new key \ "Key can only have less than 200 characters" } } if { [form is_valid message_new] } { # We get the values from the form form get_values message_new package_key message_key locale message # We use the acs-lang registration of a translation. Simple, eh? lang::message::register $locale $package_key $message_key $message set escaped_locale [ns_urlencode $locale] forward $return_url } set focus "" ad_return_templateopenacs-5.7.0/packages/acs-lang/www/admin/set-system-timezone-postgresql.xql0000644000175000017500000000102507714712710027052 0ustar frankiefrankie postgresql7.1 select to_char(current_timestamp, 'YYYY-MM-DD HH24:MI:SS') select to_char(timezone__convert_to_utc(timezone__get_id(:system_timezone), to_char(current_timestamp, 'YYYY-MM-DD HH24:MI:SS')), 'YYYY-MM-DD HH24:MI:SS') openacs-5.7.0/packages/acs-lang/www/admin/translator-mode-toggle.tcl0000644000175000017500000000054710551254374025264 0ustar frankiefrankiead_page_contract { Toggle translator mode on/off. @author Lars Pind (lars@collaboraid.biz) @creation-date October 24, 2002 @cvs-id $Id: translator-mode-toggle.tcl,v 1.2 2007/01/10 21:22:04 gustafn Exp $ } { {return_url "."} } lang::util::translator_mode_set [expr {![lang::util::translator_mode_p]}] ad_returnredirect $return_url openacs-5.7.0/packages/acs-lang/www/admin/export-messages.adp0000644000175000017500000000123711547574033024002 0ustar frankiefrankie @page_title;noquote@

    #acs-lang.Export_results_for#

    • #acs-lang.Package_# #acs-lang.all_packages# @package_key@
    • #acs-lang.Locale_# #acs-lang.all_locales# @locale@

    #acs-lang.Export_complete#

    #acs-lang.Catalog_files_are_stored_in_the_directory# @catalog_dir@

    openacs-5.7.0/packages/acs-lang/www/admin/export-messages.tcl0000644000175000017500000000110407766162051024012 0ustar frankiefrankiead_page_contract { Export messages from the database to catalog files. @author Peter Marklund } { {locale:multiple ""} {package_key ""} {return_url "/acs-lang/admin"} } set page_title "Export messages" if { ![acs_user::site_wide_admin_p] } { ad_return_warning "Permission denied" "Sorry, only site-wide administrators are allowed to export messages from the database to catalog files." ad_script_abort } lang::catalog::export \ -package_key $package_key \ -locales $locale set catalog_dir [lang::catalog::package_catalog_dir $package_key] openacs-5.7.0/packages/acs-lang/www/admin/message-conflicts.adp0000644000175000017500000000105410005232301024230 0ustar frankiefrankie @page_title@ @context;noquote@

    This page lists conflicts resulting from message catalog imports that need manual resolution by a translator or administrator.

    openacs-5.7.0/packages/acs-lang/www/admin/message-conflicts.tcl0000644000175000017500000001001310017410257024254 0ustar frankiefrankiead_page_contract { Show message conflicts resulting from message catalog imports. Optionally filter by package and locale. @author Peter Marklund } { locale:optional package_key:optional upgrade_status:optional } foreach optional_var {locale package_key} { if { [info exists $optional_var] } { if { [empty_string_p [set $optional_var]] } { unset $optional_var } } } set page_title "I18N Message Conflicts" set context [list $page_title] list::create \ -name messages \ -multirow messages \ -no_data "There are no conflicts" \ -sub_class narrow \ -elements { edit { label "" display_template { } link_url_col edit_url } package_key { label "Package" } message_key { label "Key" } locale { label "Locale" } accept { label "" display_template "Accept new" link_url_col accept_url } message { label "New Message" display_col message_truncated } old_message { label "Old Message" display_col old_message_truncated } revert { label "" display_template "Revert to old" link_url_col revert_url } upgrade_status { label "Status" } } -filters { locale { label "Locale" where_clause "lm.locale = :locale" values {[db_list_of_lists locales {select distinct locale, locale from lang_messages where conflict_p = 't'}]} } package_key { label "Package" where_clause "lm.package_key = :package_key" values {[db_list_of_lists packages { select pt.pretty_name, pt.package_key from apm_package_types pt where pt.package_key in (select m.package_key from lang_messages m where m.conflict_p = 't') order by pretty_name }]} } upgrade_status { label "Status" where_clause "lm.upgrade_status = :upgrade_status" values {[db_list_of_lists upgrade_statuses { select distinct upgrade_status, upgrade_status from lang_messages where conflict_p = 't' }]} } } db_multirow -unclobber -extend { edit_url accept_url revert_url message_truncated old_message_truncated } messages select_messages " select lm.package_key, lm.locale, lm.message_key, lm.message, lma.old_message, lm.deleted_p, lm.upgrade_status from lang_messages lm, lang_messages_audit lma where lm.conflict_p = 't' and lm.package_key = lma.package_key and lm.message_key = lma.message_key and lm.locale = lma.locale and lma.audit_id = (select max(audit_id) from lang_messages_audit lma2 where lma2.package_key = lm.package_key and lma2.message_key = lm.message_key and lma2.locale = lm.locale ) [template::list::filter_where_clauses -and -name messages] order by lm.package_key, lm.message_key " { set edit_url [export_vars -base "edit-localized-message" { package_key locale message_key }] set accept_url [export_vars -base "message-conflict-resolve" { package_key locale message_key {return_url [ad_return_url]}}] set revert_url [export_vars -base "message-conflict-revert" { package_key locale message_key {return_url [ad_return_url]}}] set message_truncated [string_truncate -len 150 -- $message] set old_message_truncated [string_truncate -len 150 -- $old_message] } openacs-5.7.0/packages/acs-lang/www/admin/message-list-oracle.xql0000644000175000017500000000156711002042113024531 0ustar frankiefrankie oracle8.1.6 select lmk.message_key, lm1.message as default_message, lm2.message as translated_message, lmk.description, nvl(lm2.deleted_p, 'f') as deleted_p from lang_messages lm1, lang_messages lm2, lang_message_keys lmk where lmk.package_key = :package_key and lm1.locale = :default_locale and lm1.message_key = lmk.message_key and lm1.package_key = lmk.package_key and lm2.locale (+) = :locale and lm2.message_key (+) = lmk.message_key and lm2.package_key (+) = lmk.package_key and lm1.deleted_p = 'f' $where_clause order by upper(lm1.message_key), lm1.message_key openacs-5.7.0/packages/acs-lang/www/admin/message-conflict-resolve.tcl0000644000175000017500000000057107766162051025573 0ustar frankiefrankiead_page_contract { Mark conflict of an I18N message as resolved, i.e. set the conflict_p flag to false. @author Peter Marklund } { package_key message_key locale {return_url {[export_vars -base "message-conflicts" { package_key locale }]}} } lang::message::edit $package_key $message_key $locale [list conflict_p f] ad_returnredirect $return_url openacs-5.7.0/packages/acs-lang/www/admin/locales-tabs.adp0000644000175000017500000000123607550315420023214 0ustar frankiefrankie
       @tabs.name@   @tabs.name@   
    openacs-5.7.0/packages/acs-lang/www/admin/locale-edit.adp0000644000175000017500000000037611456662500023035 0ustar frankiefrankie doc @context;noquote@ locale_editing.country

    Editing locale @locale_label@

    openacs-5.7.0/packages/acs-lang/www/admin/locale-edit.tcl0000644000175000017500000001362011456662500023047 0ustar frankiefrankiead_page_contract { Edits a locale @author Bruno Mattarollo Modified by Christian Hvid @creation-date 19 march 2002 @cvs-id $Id: locale-edit.tcl,v 1.10 2010/10/17 21:06:08 donb Exp $ } { locale } # Get the locale for the user so that we 'spit' the content back in the # proper locale set locale_user [ad_conn locale] # AS - doesn't work # set encoding_charset [ad_locale charset $locale_user] # ns_setformencoding $encoding_charset # ns_set put [ns_conn outputheaders] "content-type" "text/html; charset=$encoding_charset" set doc(title) "Edit Locale" set context [list $doc(title)] form create locale_editing # It's a request, not a submission of the form # # LARS: # Hm.. this is Oracle-specific. Need to figure out what to do with this for PostgreSQL. # # The v$nls_valid_values view contains all the valid NLS values # for the oracle instance. It is up to the user to select the correct # values (combinations of language, territories and character sets. More # information on this view can be found in the docs at http://tahiti.oracle.com/ # look for the PDF file of Oracle 8i "national language support guide" catch { set nls_values_list [db_list_of_lists select_nls_values {select parameter, value from v$nls_valid_values order by parameter, value}] foreach nls_value $nls_values_list { set value [lindex $nls_value 1] switch [lindex $nls_value 0] { LANGUAGE { lappend list_nls_language "\"$value\" \"$value\"" } TERRITORY { lappend list_nls_territory "\"$value\" \"$value\"" } CHARACTERSET { lappend list_nls_charset "\"$value\" \"$value\"" } } } } # Greenpeace had a table of contries and languages and their two-digit ISO-code # but not so in ACS-LANG - here you must provide the two-digit ISO-code element create locale_editing locale -label "Locale" \ -datatype text -widget inform element create locale_editing label -label "Label" -datatype text -widget inform element create locale_editing country -label "Country" \ -datatype text -widget inform element create locale_editing language -label "Language" \ -datatype text -widget inform if { [info exists list_nls_language] } { element create locale_editing nls_language -label "NLS Language" \ -datatype text -widget select -options $list_nls_language element create locale_editing nls_territory -label "NLS Territory" \ -datatype text -widget select -options $list_nls_territory element create locale_editing nls_charset -label "NLS Charset" \ -datatype text -widget select -options $list_nls_charset } else { element create locale_editing nls_language -label "NLS Language" \ -datatype text -widget text element create locale_editing nls_territory -label "NLS Territory" \ -datatype text -widget text element create locale_editing nls_charset -label "NLS Charset" \ -datatype text -widget text } element create locale_editing mime_charset \ -label "MIME Charset" -datatype text element create locale_editing default_p -label "Default" \ -datatype text -widget hidden if { [form is_request locale_editing] } { # Finish building the form to present to the user db_1row select_details_locale "select locale as locale_locale, language as locale_language, country as locale_country, label as locale_label, nls_language as locale_nls_language, nls_territory as locale_nls_territory, nls_charset as locale_nls_charset, mime_charset as locale_mime_charset, default_p as locale_default_p from ad_locales where locale = :locale" set locale_language [string trim $locale_language] element set_properties locale_editing locale -value $locale_locale element set_properties locale_editing label -value $locale_label element set_properties locale_editing nls_language -value $locale_nls_language element set_properties locale_editing nls_territory -value $locale_nls_territory element set_properties locale_editing nls_charset -value $locale_nls_charset element set_properties locale_editing mime_charset -value $locale_mime_charset element set_properties locale_editing default_p -value $locale_default_p set lang_query "select label from language_639_2_codes" if { [string length $locale_language] eq 3 } { append lang_query " where iso_639_2 = :locale_language" } else { append lang_query " where iso_639_1 = :locale_language" } element set_properties locale_editing language \ -value [db_string get_lang_label $lang_query -default $locale_language] element set_properties locale_editing country \ -value [db_string get_country_name { select default_name from countries where iso = :locale_country } -default $locale_country] } else { # If we are not building a request form, we are processing a submission. # Get the values from the form and validate them form get_values locale_editing set locale_label [lang::util::get_label $locale] if { $label eq "" } { element set_error locale_editing label "Label is required" } if { $mime_charset eq "" } { element set_error locale_editing mime_charset "Mime charset is required" } } if { [form is_valid locale_editing] } { # We are receiving a valid submission form get_values locale_editing db_transaction { db_dml update_locale "update ad_locales set nls_language = :nls_language, nls_territory = :nls_territory, nls_charset = :nls_charset, mime_charset = :mime_charset, default_p = :default_p where locale = :locale" } db_flush_cache -cache_key_pattern ad_lang_mime_charset_$locale forward "index?tab=locales" } openacs-5.7.0/packages/acs-lang/www/admin/lookups-include.adp0000644000175000017500000000006607573164573024000 0ustar frankiefrankieMessage key usage:
    @message_key_context@
    
    openacs-5.7.0/packages/acs-lang/www/admin/lookups-include.tcl0000644000175000017500000000110607600363140023770 0ustar frankiefrankie# Include takes arguments full_key and message_key_list set full_key_pattern "${package_key}.([join $message_key_list "|"])" set message_key_context "" if { [catch {set message_key_context [exec find [acs_root_dir] -type f -regex ".*\\.\\(info\\|adp\\|sql\\|tcl\\)" | xargs egrep "${full_key_pattern}"]} error] } { global errorInfo regexp "^(.*)child process exited abnormally" $errorInfo match message_key_context set message_key_context [ad_quotehtml $message_key_context] regsub -all "${full_key_pattern}" $message_key_context {\0} message_key_context } openacs-5.7.0/packages/acs-lang/www/admin/import-locale-from-files.adp0000644000175000017500000000036610006467722025461 0ustar frankiefrankie @page_title;noquote@ @context;noquote@

    Import finished.

    openacs-5.7.0/packages/acs-lang/www/admin/import-locale-from-files.tcl0000644000175000017500000000103410210116412025450 0ustar frankiefrankiead_page_contract { Import all catalog messages for a given locale from the file system. Should typically only be done once as it may overwrite translations already in the database for the given locale @author Peter Marklund } { locale } set locale_label [lang::util::get_label $locale] set page_title "Import all messages for locale $locale" set return_url [export_vars -base package-list { locale }] set context [list [list $return_url $locale_label] $page_title] lang::catalog::import -locales [list $locale] openacs-5.7.0/packages/acs-lang/www/admin/audit-include.adp0000644000175000017500000000147607716731574023420 0ustar frankiefrankie
    • "@audit.old_message@" -> "@audit.new_message@" "@audit.new_message@"
      @audit.comment_text@

      -- @audit.creation_user_name@ at @audit.creation_date@

    No changes or comments.

    openacs-5.7.0/packages/acs-lang/www/admin/audit-include.tcl0000644000175000017500000000354707733362367023436 0ustar frankiefrankieset trail_counter 0 set new_message [db_string current_message { select message from lang_messages where locale = :current_locale and package_key = :package_key and message_key = :message_key } -default ""] multirow create audit_inv creation_user_id creation_user_name creation_date old_message new_message old_new_message comment_text db_foreach audit_inv_select { select a.old_message, p.first_names || ' ' || p.last_name as overwrite_user_name, a.overwrite_user, to_char(a.overwrite_date, 'YYYY-MM-DD HH24:MI:SS') as overwrite_date, a.comment_text from lang_messages_audit a, persons p where locale = :current_locale and message_key = :message_key and package_key = :package_key and a.overwrite_user = p.person_id order by overwrite_date desc } { multirow append audit_inv \ $overwrite_user \ $overwrite_user_name \ [lc_time_fmt $overwrite_date "%x %X"] \ $old_message \ $new_message \ "$old_message,$new_message" \ $comment_text set new_message $old_message incr trail_counter } if { $trail_counter > 0 } { set original_message $new_message } # invert the audit trail multirow create audit creation_user_id creation_user_name creation_date old_message new_message old_new_message comment_text for { set i [multirow size audit_inv] } { $i > 0 } { incr i -1 } { multirow get audit_inv $i multirow append audit \ $audit_inv(creation_user_id) \ $audit_inv(creation_user_name) \ $audit_inv(creation_date) \ $audit_inv(old_message) \ $audit_inv(new_message) \ $audit_inv(old_new_message) \ $audit_inv(comment_text) } multirow extend audit creation_user_url multirow foreach audit { set creation_user_url [acs_community_member_url -user_id $creation_user_id] } openacs-5.7.0/packages/acs-lang/www/admin/edit-localized-message.adp0000644000175000017500000000174110052153350025150 0ustar frankiefrankie Edit a message @context;noquote@ message.message

    Audit Trail

    @first_translated_message;noquote@

    Files that use this message

    Show | Hide files that use this message.

    Show | Hide files that use this message key.

    openacs-5.7.0/packages/acs-lang/www/admin/edit-localized-message.tcl0000644000175000017500000001447711126516041025203 0ustar frankiefrankiead_page_contract { Displays the localized message from the database for translation (displays an individual message) @author Bruno Mattarollo @author Christian Hvid @creation-date 30 October 2001 @cvs-id $Id: edit-localized-message.tcl,v 1.17 2008/12/30 22:09:37 emmar Exp $ } { locale package_key message_key show:optional {usage_p "f"} {return_url {}} } if { [string length $locale] == 2 } { # Only language provided, let's get the default locale for this language set default_locale [lang::util::default_locale_from_lang $locale] if { $default_locale eq "" } { error "Could not look up locale for language $locale" } else { set locale $default_locale } } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Edit $package_key.$message_key" set context [list [list [export_vars -base package-list { locale }] $locale_label] \ [list [export_vars -base message-list { locale package_key show }] $package_key] \ "$package_key.$message_key"] # We let you create/delete messages keys if you're in the default locale set create_p [string equal $current_locale $default_locale] set description_edit_url [export_vars -base edit-description { locale package_key message_key show }] set usage_hide_url [export_vars -base [ad_conn url] { locale package_key message_key show return_url }] set usage_show_url [export_vars -base [ad_conn url] { locale package_key message_key show {usage_p 1} return_url }] set delete_url [export_vars -base message-delete { locale package_key message_key show {return_url {[ad_return_url]}} }] ad_form -name message -form { {locale:text(hidden),optional {value $current_locale}} {package_key:text(hidden),optional {value $package_key}} {message_key:text(hidden),optional {value $message_key}} {show:text(hidden),optional} {return_url:text(hidden),optional {value $return_url}} {message_key_pretty:text(inform) {label "Message Key"} {value "$package_key.$message_key"} } {description:text(inform) {label "Description"} {after_html {}} } } if { $default_locale ne $current_locale } { ad_form -extend -name message -form { {original_message:text(inform) {label "$default_locale_label Message"} } } } ad_form -extend -name message -form { {message:text(textarea) {label "$locale_label Message"} {html { rows 6 cols 40 }} } {comment:text(textarea),optional {label "Comment"} {html { rows 6 cols 40 }} } {submit:text(submit) {label " Update "} } } -on_request { set original_message {} set description {} db_0or1row select_original_message { select lm.message as original_message, lmk.description from lang_messages lm, lang_message_keys lmk where lm.message_key = lmk.message_key and lm.package_key = lmk.package_key and lm.package_key = :package_key and lm.message_key = :message_key and lm.locale = :default_locale } set translated_p [db_0or1row select_translated_message { select lm.message as message, cu.first_names || ' ' || cu.last_name as creation_user_name, cu.user_id as creation_user_id, to_char(lm.creation_date, 'YYYY-MM-DD') as creation_date from lang_messages lm, cc_users cu where lm.package_key = :package_key and lm.message_key = :message_key and lm.locale = :current_locale and cu.user_id = lm.creation_user }] if { [exists_and_not_null message] } { set message $message } else { set message $original_message } set original_message [ad_quotehtml $original_message] if { $description eq "" } { set description [subst {(add description)}] } else { set description "[ad_text_to_html -- $description] [subst { (edit)}]" } # Augment the audit trail with info on who created the first message if { $current_locale ne $default_locale && $translated_p } { set edited_p [db_string edit_count { select count(*) from lang_messages_audit where package_key = :package_key and message_key = :message_key and locale = :current_locale }] if { $edited_p } { # The translation has been edited # Get the creation user of the first revision db_1row select_first_revision { select cu.first_names || ' ' || cu.last_name as creation_user_name, cu.user_id as creation_user_id, to_char(lma.overwrite_date, 'YYYY-MM-DD') as creation_date from lang_messages_audit lma, cc_users cu where lma.package_key = :package_key and lma.message_key = :message_key and lma.locale = :current_locale and cu.user_id = lma.overwrite_user and lma.audit_id = (select min(lm2.audit_id) from lang_messages_audit lm2 where lm2.package_key = :package_key and lm2.message_key = :message_key and lm2.locale = :current_locale ) } } set first_translated_message "
    • First translated by [acs_community_member_link -user_id $creation_user_id -label $creation_user_name] on $creation_date
    " } else { set first_translated_message "" } } -on_submit { # Register message via acs-lang lang::message::register -comment $comment $locale $package_key $message_key $message if { $return_url eq "" } { set return_url "[ad_conn url]?[export_vars { locale package_key message_key show }]" } ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-lang/www/admin/message-usage-include.adp0000644000175000017500000000021007716731574025021 0ustar frankiefrankie

    @message_usage.file@:

    @message_usage.code@
    openacs-5.7.0/packages/acs-lang/www/admin/message-usage-include.tcl0000644000175000017500000000252210551254374025034 0ustar frankiefrankie# @input message_key # @input package_key # # @author Peter Marklund (peter@collaboraid.biz) # @author Lars Pind (lars@collaboraid.biz) # @cvs-id $Id: message-usage-include.tcl,v 1.5 2007/01/10 21:22:04 gustafn Exp $ set full_key "$package_key.$message_key" # Since acs-lang.localization- messages use the lc_get proc (that leaves out the acs-lang.localization- part) # for lookups we need a special regexp for them if { [string match "acs-lang.localization-*" $full_key] } { set grepfor "${full_key}|lc_get \[\"\{\]?[string range $message_key [string length "localization-"] end]\[\"\}\]?" } else { set grepfor "\\W${full_key}\\W" } multirow create message_usage file code with_catch errmsg { exec find [acs_root_dir] -type f -regex ".*\\.\\(info\\|adp\\|sql\\|tcl\\)" -follow | xargs egrep "$grepfor" 2>/dev/null } { #error "find [acs_root_dir] -type f -regex \".*\\.\\(info\\|adp\\|sql\\|tcl\\)\" -follow | xargs egrep \"${full_key_pattern}\"" global errorInfo foreach line [split $errmsg "\n"] { if { [string first "child process exited abnormally" $line] == -1 } { set colon [string first ":" $line] multirow append message_usage \ [string range $line 0 [expr {$colon-1}]] \ [string trim [string range $line [expr {$colon+1}] end]] } } } openacs-5.7.0/packages/acs-lang/www/admin/message-search.adp0000644000175000017500000000407310006467722023537 0ustar frankiefrankie @page_title@ @context;noquote@ search.q Search for

    Search Results

    Package Message Key @default_locale_label@ Message @locale_label@ Message
    @messages.package_key@ @messages.message_key_pretty@ @messages.default_message@ @messages.translated_message@ Not translated
    No messages found.
    openacs-5.7.0/packages/acs-lang/www/admin/message-search.tcl0000644000175000017500000000447310551254374023563 0ustar frankiefrankiead_page_contract { Search for localized messages containing a certain substring, in order to help translators ensure consistent terminology. } { locale search_locale:optional q:optional } # We rename to avoid conflict in queries set current_locale $locale set default_locale en_US set locale_label [lang::util::get_label $current_locale] set default_locale_label [lang::util::get_label $default_locale] set page_title "Search Messages" set context [list [list "package-list?[export_vars { locale }]" $locale_label] $page_title] set default_locale en_US set search_locales [list] lappend search_locales [list "Current locale - [lang::util::get_label $locale]" $locale ] lappend search_locales [list "Master locale - [lang::util::get_label $default_locale]" $default_locale] set submit_p 0 ad_form -name search -action message-search -form { {locale:text(hidden) {value $locale}} } if { $default_locale ne $current_locale } { ad_form -extend -name search -form { {search_locale:text(select) {options $search_locales} {label "Search locale"} } } } else { ad_form -extend -name search -form { {search_locale:text(hidden) {value $current_locale} } } } ad_form -extend -name search -form { {q:text {label "Search for"} } } -on_request { # locale will be set now } if { [exists_and_not_null search_locale] && [exists_and_not_null q] } { set submit_p 1 set search_string "%$q%" db_multirow -extend { package_url edit_url message_key_pretty } messages select_messages {} { set edit_url "edit-localized-message?[export_vars { locale package_key message_key {return_url {[ad_return_url]} } }]" set package_url "message-list?[export_vars { locale package_key }]" set message_key_pretty "$package_key.$message_key" } if { $current_locale ne $default_locale } { if {$default_locale eq $search_locale} { set other_locale $locale_label set other_search_url "[ad_conn url]?[export_vars { locale q {search_locale $current_locale} }]" } else { set other_locale $default_locale_label set other_search_url "[ad_conn url]?[export_vars { locale q {search_locale $default_locale} }]" } } } openacs-5.7.0/packages/acs-lang/www/change-locale-include.adp0000644000175000017500000000005207557227161023664 0ustar frankiefrankie openacs-5.7.0/packages/acs-lang/www/change-locale-include.tcl0000644000175000017500000001013110676223674023702 0ustar frankiefrankie# includelet pseudo-contract # Change user preferred locale # @author Peter Marklund (peter@collaboraid.biz) # @author Christian Hvid if { ![exists_and_not_null return_url] } { # Use referer header set return_url [ns_set iget [ns_conn headers] referer] } if { ![exists_and_not_null package_id] } { set package_id [ad_conn package_id] } set use_timezone_p [expr {[lang::system::timezone_support_p] && [ad_conn user_id]}] # # LARS: # I'm thinking the UI here needs to be different. # # Your locale preference and your timezone is going to be set through 'Your Account" # The package-specific locale setting should be set through a page in dotlrn/acs-subsite # # This page should only be accessed through "Your Account" # # There's no reason to offer an option of 'default' preferred locale. # # Create a list of lists containing the possible locale choiches set list_of_locales [list] db_foreach locale_loop {} { if { [lang::message::message_exists_p $locale acs-lang.this-language] } { set label "[lang::message::lookup $locale acs-lang.this-language]" } lappend list_of_locales [list ${label} $locale] } set list_of_package_locales [linsert $list_of_locales 0 [list (default) ""]] form create locale # Export variables element create locale package_id_info -datatype text -widget hidden -optional element create locale return_url_info -datatype text -widget hidden -optional if { [form is_valid locale] } { set return_url [element get_value locale return_url_info] set package_id [element get_value locale package_id_info] } # are we selecting package level locale as well? set package_level_locales_p [expr {[lang::system::use_package_level_locales_p] && $package_id ne "" && [ad_conn user_id] != 0}] if { $package_level_locales_p } { element create locale site_wide_explain -datatype text -widget inform -label " " \ -value "[_ acs-lang.Your_locale_site_wide]" } element create locale site_wide_locale \ -datatype text \ -widget select_locales \ -optional \ -label "[_ acs-lang.Your_Preferred_Locale]" \ -options $list_of_locales \ -values [ad_conn locale] if { $package_level_locales_p } { set package_name [apm_instance_name_from_id $package_id] element create locale package_level_explain -datatype text -widget inform -label " " \ -value "[_ acs-lang.Your_locale_for_package]" element create locale package_level_locale -datatype text -widget select -optional \ -label "[_ acs-lang.Locale_for]" \ -options $list_of_package_locales } if { $use_timezone_p } { set timezone_options [db_list_of_lists all_timezones {}] element create locale timezone -datatype text -widget select -optional \ -label "[_ acs-lang.Your_timezone]" \ -options $timezone_options } if { [form is_request locale] } { if { $package_level_locales_p } { element set_properties locale package_level_locale -value [lang::user::package_level_locale $package_id] } set site_wide_locale [lang::user::site_wide_locale] if { $site_wide_locale eq "" } { set site_wide_locale [lang::system::site_wide_locale] } element set_properties locale site_wide_locale -value $site_wide_locale element set_properties locale return_url_info -value $return_url element set_properties locale package_id_info -value $package_id if { $use_timezone_p } { set timezone [lang::user::timezone] if { $timezone eq "" } { set timezone [lang::system::timezone] } element set_properties locale timezone -value $timezone } } if { [form is_valid locale] } { set site_wide_locale [element get_value locale site_wide_locale] lang::user::set_locale $site_wide_locale if { $package_level_locales_p } { set package_level_locale [element get_value locale package_level_locale] lang::user::set_locale -package_id $package_id $package_level_locale } if { $use_timezone_p } { lang::user::set_timezone [element get_value locale timezone] } ad_returnredirect $return_url ad_script_abort } openacs-5.7.0/packages/acs-lang/www/change-locale-include.xql0000644000175000017500000000066110047433234023716 0ustar frankiefrankie select tz || ' ' || gmt_offset as tz, tz from timezones select label, locale from enabled_locales order by label openacs-5.7.0/packages/acs-lang/www/index.adp0000644000175000017500000000061110047443366020664 0ustar frankiefrankie @instance_name;noquote@ @context_bar;noquote@ openacs-5.7.0/packages/acs-lang/www/index.tcl0000644000175000017500000000047510210116412020667 0ustar frankiefrankiead_page_contract { Localization home } { {return_url ""} {return_p "f"} } set instance_name [ad_conn instance_name] set context_bar [ad_context_bar] # # Get user pref setting # set locale [lang::user::locale] set language [lang::user::language] set admin_p [ad_permission_p [ad_conn package_id] admin] openacs-5.7.0/packages/acs-lang/www/change-locale.tcl0000644000175000017500000000057311022567607022263 0ustar frankiefrankiead_page_contract { } { user_locale return_url } if { [catch {lang::user::set_locale $user_locale} errmsg] } { ns_log Error "acs-lang/www/change-locale crashed calling lang::user::set_locale with user_locale='$user_locale'\n$errmsg" ad_return_error [_ acs-lang.Error_changing_locale] [_ acs-lang.User_locale_not_set] } else { ad_returnredirect $return_url } openacs-5.7.0/packages/acs-lang/acs-lang.info0000644000175000017500000000455711575167337020632 0ustar frankiefrankie Localization Localization t t Peter Marklund OpenACS Internationalization Support. 2011-06-12 Collaboraid GPL 3 Internationalization and localization support routines and admin UI for manipulating Locales, request processor hooks, templating, accessing and managing the message catalog, and locale-specific formatting functions for localizing dates, times, monetary amounts etc. openacs-5.7.0/packages/acs-lang/catalog/0000755000175000017500000000000011724401447017654 5ustar frankiefrankieopenacs-5.7.0/packages/acs-lang/catalog/acs-lang.ru_RU.utf-8.xml0000644000175000017500000000476011022567605024067 0ustar frankiefrankie ДоÑтупна на английÑком Изменить локаль ÐнглийÑкий ФранцузÑкий Ðемецкий {Ð’Ñ} {Пн} {Ð’Ñ‚} {Ср} {Чт} {Пт} {Сб} {Ñнв} {фев} {мар} {апр} {май} {июн} {июл} {авг} {Ñен} {окт} {ноÑ} {дек} ДП Ñ€. %d.%m.%y %a %d %B %Y ?., %H:%M %Z {ВоÑкреÑенье} {Понедельник} {Вторник} {Среда} {Четверг} {ПÑтница} {Суббота} . %B %d, %Y %A %B %d, %Y 1 DD MONTH YYYY HH24:MI 2 3 3 RUB 2 {Январь} {февраль} {Март} {Ðпрель} {Май} {Июнь} {Июль} {ÐвгуÑÑ‚} {СентÑбрь} {ОктÑбрь} {ÐоÑбрь} {Декабрь} . 3 3 , 0 0 1 - 0 0 1 ПП + %H:%M ИÑпанÑкий РуÑÑкий openacs-5.7.0/packages/acs-lang/catalog/acs-lang.fa_IR.utf-8.xml0000644000175000017500000000025510727201371024002 0ustar frankiefrankie انگلیسی openacs-5.7.0/packages/acs-lang/catalog/acs-lang.en_US.ISO-8859-1.xml0000644000175000017500000001672211547574033024312 0ustar frankiefrankie Actions Administration of Localization all packages Are you sure you want to export all I18N messages to catalog files? Are you sure you want to import all I18N messages from catalog files? Available in English The language referred to in the message body should be the language of the locale, not a localized version of "English". Can be two-character for language only or five-character full locale Catalog files are stored in the directory Change locale Change system locale Change system timezone Create New Locale Current system locale is <strong>%system_locale%: %system_locale_label%</strong> Current system timezone is <strong>%timezone%</strong> Default Locale for Language Delete this locale Disable this locale Edit definition of locale Edit localized messages for %locales.locale_label% Edit this message Enable this locale Enabled English Error changing locale Export all messages Export all messages for this locale to catalog files Export all messages for this locale Export complete Export messages system-wide to catalog files Export results for French German Import all messages Import all messages for this locale from catalog files Import all messages for this locale Imports messages system-wide from catalog files Include package key, as in package-key.message-key Installed Locales Label Locale locale Locale: Locale for %package_name% {Sun} {Mon} {Tue} {Wed} {Thu} {Fri} {Sat} {Jan} {Feb} {Mar} {Apr} {May} {Jun} {Jul} {Aug} {Sep} {Oct} {Nov} {Dec} AM $ %m/%d/%y %a %B %d, %Y %r %Z {Sunday} {Monday} {Tuesday} {Wednesday} {Thursday} {Friday} {Saturday} . %B %d, %Y %A %B %d, %Y 0 MONTH DD YYYY HH12:MI AM 2 3 3 USD 2 {January} {February} {March} {April} {May} {June} {July} {August} {September} {October} {November} {December} . 3 3 , 1 0 An integer set to 0 if no space separates the currency_symbol or int_curr_symbol from the value for a negative monetary quantity, set to 1 if a space separates the symbol from the value and set to 2 if a space separates the symbol and the sign string, if adjacent. 1 - 1 0 0 means that no space should be printed between the symbol and the value. 1 means that a space should be printed between the symbol and the value. 2 means that a space should be printed between the symbol and the sign string, if adjacent. 1 PM + %r , Look up message Make this locale the default locale for language '%locales.language%' Message key Off On Package Package: Resolve message conflicts Return Spanish Switch to English English (US) The label of the locale, in the locale's language. This should be different for each locale. This should not be English unless the locale is "en". This is the only locale for this language Toggle translator mode Total Translated Translated Message Translated messages on this page (%locale%) Untranslated Your locale %user_locale% couldn't be set, probably because it's not available. Your locale setting for %package_name%. If set, this will override the site-wide setting in this particular application. Your locale setting for the whole site Your Preferred Locale Your Timezone openacs-5.7.0/packages/acs-lang/catalog/acs-lang.hu_HU.utf-8.xml0000644000175000017500000000165510727201371024037 0ustar frankiefrankie {H} {K} {Sze} {Cs} {P} {Szo} {V} {jan.} {feb.} {márc.} {ápr.} {máj.} {jún.} {júl.} {aug.} {szept.} {okt.} {nov.} {dec.} %Y.%m.%d {vasárnap} {hétfÅ‘} {kedd} {szerda} {csütörtök} {péntek} {szombat} , %Y. %B %e. 1 3 3 {január} {február} {március} {április} {május} {június} {július} {augusztus} {szeptember} {október} {november} {december} %H:%M . openacs-5.7.0/packages/acs-lang/catalog/acs-lang.pt_BR.ISO-8859-1.xml0000644000175000017500000000571410727201371024275 0ustar frankiefrankie Disponível em Português Alterar idioma Inglês Francês Alemão Localização Localização para %package_name% {Dom} {Seg} {Ter} {Qua} {Qui} {Sex} {Sáb} {Jan} {Fev} {Mar} {Abr} {Mai} {Jun} {Jul} {Ago} {Set} {Out} {Nov} {Dez} AM R$ %d/%m/%y %a, %d de %B de %Y, %r %Z {Domingo} {Segunda} {Terça} {Quarta} {Quinta} {Sexta} {Sábado} , %d de %B de %Y %A, %d de %B de %Y 0 DD MONTH YYYY HH24:MI 2 3 3 BRL 2 {Janeiro} {Fevereiro} {Março} {Abril} {Maio} {Junho} {Julho} {Agosto} {Setembro} {Outubro} {Novembro} {Dezembro} , 3 3 . 1 0 1 - 1 0 1 PM + %r , Resolver mensagens conflitantes Espanhol Português Traduzir mensagens nesta página (%locale%) Sua definição de localização para %package_name%. Uma vez configurada, esta definição irá sobrescrever a configuração estabelecida como padrão da instalação apenas para esta aplicação particular. Sua definição de localização padrão da instalação Sua localização preferida Seu fuso-horário openacs-5.7.0/packages/acs-lang/catalog/acs-lang.tr_TR.utf-8.xml0000644000175000017500000000437410727201371024062 0ustar frankiefrankie Turkce Olmali Konum Degistir İnglizce Fransızca Almanca {Pazar} {P.tesi} {Sali} {Carsamba} {Persembe} {Cuma} {C.tesi} {Ock} {Sub} {Mrt} {Nis} {May} {Haz} {Tem} {Agu} {Eyl} {Ekm} {Kas} {Ara} Ogleden once $ %m/%d/%y %a %B %d, %Y %r %Z {Pazar} {Pazartesi} {Sali} {Carsamba} {Persembe} {Cuma} {Cumartesi} . %B %d, %Y %A %B %d, %Y 0 AA GG YYYY HH12:MI AM 2 3 3 USD 2 {Ocak} {Subat} {Mart} {Nisan} {Mayis} {Haziran} {Temmuz} {Agustos} {Eylul} {Ekim} {Kasim} {Aralik} . 3 3 , 1 0 1 - 1 0 1 Ogleden sonra + %r , İspanyolca Turkce openacs-5.7.0/packages/acs-lang/catalog/acs-lang.fi_FI.utf-8.xml0000644000175000017500000000406510727201371024001 0ustar frankiefrankie Englanti Ranska Saksa {su} {ma} {ti} {ke} {to} {pe} {la} {tammi} {helmi} {maalis} {huhti} {touko} {kesä} {heinä} {elo} {syys} {loka} {marras} {joulu} € %d.%m.%Y %a, %d. %Bta %Y %H:%M %Z {sunnuntai} {maanantai} {tiistai} {keskiviikko} {torstai} {perjantai} {lauantai} , %d. %Bta %Y %A, %d. %Bta %Y 1 HH24:MI 2 3 3 EUR 2 {tammikuu} {helmikuu} {maaliskuu} {huhtikuu} {toukokuu} {kesäkuu} {heinäkuu} {elokuu} {syyskuu} {lokakuu} {marraskuu} {joulukuu} , 3 3 1 0 1 - 1 0 1 %H:%M Espanja openacs-5.7.0/packages/acs-lang/catalog/acs-lang.eu_ES.ISO-8859-1.xml0000644000175000017500000000442510727201371024265 0ustar frankiefrankie Eskuragai Euskaraz Hizkuntza aldatu Ingelesa Frantsesa Alemana {Iga} {Ast} {Ast} {Ast} {Ost} {Ost} {Lar} {Urt} {Ots} {Mar} {Api} {Mai} {Eka} {Uzt} {Abu} {Ira} {Urr} {Aza} {Abe} AM ? %y-%m-%d %a, %Y(e)ko %Bren %d, %T %Z {Igandea} {Astelehena} {Asteartea} {Asteazkena} {Osteguna} {Ostirala} {Larunbata} , %Y-ko %Bren %d %A, %Y(e)ko %Bren %d 1 YYYY MONTH DD HH24:MI 2 3 3 EUR 2 {Urtarrila} {Otsaila} {Martxoa} {Apirila} {Maiatza} {Ekaina} {Uztaila} {Abuztua} {Iraila} {Urria} {Azaroa} {Abendua} , 3 3 . 1 0 1 - 1 1 1 PM + %T . Espainola Euskara openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ar_EG.utf-8.xml0000644000175000017500000000047510727201371024003 0ustar frankiefrankie إنجليزيّ ÙَرَنْسÙيّ أَلْمانÙيّ Ø¥ÙØ³Ù’بانÙيّ openacs-5.7.0/packages/acs-lang/catalog/acs-lang.da_DK.ISO-8859-1.xml0000644000175000017500000000433410727201371024226 0ustar frankiefrankie Findes på dansk Ændre sprog Engelsk Fransk Tysk {søn} {man} {tir} {ons} {tor} {fre} {lør} {jan} {feb} {mar} {apr} {maj} {jun} {jul} {aug} {sep} {okt} {nov} {dec} AM kr %d/%m-%y %a %e. %B %Y %r %Z {søndag} {mandag} {tirsdag} {onsdag} {torsdag} {fredag} {lørdag} , %e. %B %Y %A den %e. %B %Y 1 MÅNED DD ÅÅÅÅ HH24:MI 2 3 3 DKK 2 {januar} {februar} {marts} {april} {maj} {juni} {juli} {august} {september} {oktober} {november} {december} , 3 3 . 1 0 1 - 1 0 1 PM + %H:%M . Spansk Dansk openacs-5.7.0/packages/acs-lang/catalog/acs-lang.no_NO.ISO-8859-1.xml0000644000175000017500000000437510727201371024301 0ustar frankiefrankie Tilgjengelig på bokmål Ny språksetting Engelsk Fransk Tysk {søn} {man} {tir} {ons} {tor} {fre} {lør} {jan} {feb} {mar} {apr} {mai} {jun} {jul} {aug} {sep} {okt} {nov} {des} Formiddag kr %e/%m-%y %a %e. %B %Y %r %Z {søndag} {mandag} {tirsdag} {onsdag} {torsdag} {fredag} {lørdag} , %e. %B %Y %A den %e. %B %Y 1 MÅNED DD YYYY HH24:MI 2 3 3 NOK 2 {januar} {februar} {mars} {april} {mai} {juni} {juli} {august} {september} {oktober} {november} {desember} , 3 3 . 1 0 1 - 1 0 1 Ettermiddag + %H:%M . Spansk Norsk bokmål openacs-5.7.0/packages/acs-lang/catalog/acs-lang.es_CO.ISO-8859-1.xml0000644000175000017500000000436110727201371024254 0ustar frankiefrankie Disponible en Español Cambiar local Inglés Francés Alemán {Dom} {Lun} {Mar} {Mié} {Jue} {Vie} {Sáb} {Ene} {Feb} {Mar} {Abr} {May} {Jun} {Jul} {Ago} {Sep} {Oct} {Nov} {Dic} AM %d/%m/%y %a %d %B %Y %H:%M %Z {Domingo} {Lunes} {Martes} {Miércoles} {Jueves} {Viernes} {Sábado} . %d, %B %Y %A %d %B %Y 0 DD MES AAAA HH24:MI 0 -1 -1 EUR 0 {Enero} {Febrero} {Marzo} {Abril} {Mayo} {Junio} {Julio} {Agosto} {Septiembre} {Octubre} {Noviembre} {Diciembre} . 3 3 . 1 1 1 - 1 1 1 PM + %H:%M , Español Español (CO) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.es_ES.ISO-8859-1.xml0000644000175000017500000001514711547574033024277 0ustar frankiefrankie Acciones Administración de Localización todos los paquetes ¿Está seguro que desea exportar todos los mensajes a catálogos? ¿Está seguro que desea importar todos los mensajes desde los catálogos? Disponible en español Puede ser 2 caracteres sólo para el idioma o 5 caracteres para toda la localización Los catálogos están en Cambiar idioma Cambiar el idioma del sistema Cambiar la hora del sistema Crear un nuevo idioma El idioma actual del sistema es <strong>%system_locale%: %system_locale_label%</strong> La zona horaria actual del sistema es <strong>%timezone%</strong> Configuración regional predeterminada del idioma Borrar este idioma Desactivar este idioma Editar la definición del idioma Editar los mensajes de %locales.locale_label% Editar este mensaje Activar este idioma Activado Inglés Error al cambiar de idioma Exportar todos los mensajes Exportar a catálogos todos los mensajes de este idioma Exportar todos los mensajes para este idioma Exportación completa Exportar a catálogos todos los mensajes Resultados de exportación de Francés Alemán Importar todos los mensajes Importar todos los mensajes de idioma desde los catálogos Importar todos los mensajes para este idioma Importar todos los mensajes desde catálogos Incluya el nombre del paquete, es decir: package-key.message-key Idiomas Instalados Etiqueta Idioma idioma Idioma: Idioma para %package_name% {Dom} {Lun} {Mar} {Mié} {Jue} {Vie} {Sáb} {Ene} {Feb} {Mar} {Abr} {May} {Jun} {Jul} {Ago} {Sep} {Oct} {Nov} {Dic} AM ? %d/%m/%y %a %d %B %Y %H:%M %Z {domingo} {lunes} {martes} {miércoles} {jueves} {viernes} {sábado} , %d %B %Y %A %d %B %Y 1 DD MONTH YYYY HH24:MI 2 3 3 EUR 2 {enero} {febrero} {marzo} {abril} {mayo} {junio} {julio} {agosto} {septiembre} {octubre} {noviembre} {diciembre} , 3 3 . 1 1 1 - 1 1 1 PM + %H:%M . Buscar mensaje Establecer como idioma por defecto para el lenguaje '%locales.language%' Clave de mensaje Desactivar Activar Paquete Paquete: Resolver conflictos de mensajes Volver Español Cambiar a Español Español (ES) Esta es el único idioma para este lenguaje Establecer el modo traductor Total Traducido Mensaje Traducido Mensajes traducidos en esta página (%locale%) Sin traducir Su idioma %user_locale% no ha podido ser cambiado, probablemente porque no está disponible. Su selección de idioma para %package_name%. Si está activado, sobreescribirá la selección general en esta aplicación en particular. Su selección de idioma para todo el sitio Su idioma Su zona horaria openacs-5.7.0/packages/acs-lang/catalog/acs-lang.it_IT.ISO-8859-1.xml0000644000175000017500000000554310727201371024277 0ustar frankiefrankie Disponibile in Italiano Cambia localizzazione Inglese Francese Tedesco Locale Locale per %package_name% {Dom} {Lun} {Mar} {Mer} {Gio} {Ven} {Sab} {Gen} {Feb} {Mar} {Apr} {Mag} {Giu} {Lug} {Ago} {Set} {Ott} {Nov} {Dic} AM €? %d/%m/%y %a %d %B %Y %H:%M %Z {Domenica} {Lunedì} {Martedì} {Mercoledì} {Giovedì} {Venerdì} {Sabato} , %d %B %Y %A %d %B %Y 1 DD MONTH YYYY HH24:MI 2 3 3 Euro 2 {Gennaio} {Febbraio} {Marzo} {Aprile} {Maggio} {Giugno} {Luglio} {Agosto} {Settembre} {Ottobre} {Novembre} {Dicembre} . 3 3 , 1 0 1 - 1 0 1 PM + %H:%M , Risolvi conflitti Spagnolo Italiano Messaggi tradotti in questa pagina (%locale%) La tua impostazione di locale per %package_name%. Se impostata prevarrà su quella del sito per questo package. La tua impostazione di locale per l'intero sito Il tuo locale preferito La tua timezone openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ja_JP.utf-8.xml0000644000175000017500000000161410727201371024005 0ustar frankiefrankie 英語 フランス語 ドイツ語 {日曜日} {月曜日} {ç«æ›œæ—¥} {水曜日} {木曜日} {金曜日} {土曜日} {1 月} {2 月} {3 月} {4 月} {5 月} {6 月} {7 月} {8 月} {9 月} {10 月} {11 月} {12 月} Â¥ {日曜日} {月曜日} {ç«æ›œæ—¥} {水曜日} {木曜日} {金曜日} {土曜日} JPY {1 月} {2 月} {3 月} {4 月} {5 月} {6 月} {7 月} {8 月} {9 月} {10 月} {11 月} {12 月} スペイン語 openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ar_LB.utf-8.xml0000644000175000017500000000475210727201371024007 0ustar frankiefrankie Ù…ØªÙˆÙØ± بالانجليزية تغير الموقع إنجليزيّ ÙَرَنْسÙيّ أَلْمانÙيّ {أح} {إث} {ثل} {أر} {خم} {جم} {سب} {Ùƒ2} {شبا} {آذا} {نيس} {أيا} {حزي} {تمو} {آب} {أيل} {ت1} {ت2} {Ùƒ1} ص Ù„.Ù„. %d/%m/%y %a %d %B %Y %H:%M %Z {أحد} {إثنين} {الثلاثاء} {الأربعاء} {الخميس} {الجمعة} {السبت} , %d %B %Y %A %d %B %Y 1 الشهر اليوم السنة HH12:MI AM 2 3 3 Ù„.Ù„. 2 {كانون الثاني} {شباط} {آذار} {نيسان} {أيار} {حزيران} {تموز} {آب} {أيلول} {تشرين الاول} {تشرين الثاني} {كانون الاول} . 3 3 ØŒ 0 1 1 - 0 1 1 صباحا + %r , Ø¥ÙØ³Ù’بانÙيّ اللبنانية openacs-5.7.0/packages/acs-lang/catalog/acs-lang.en_AU.ISO-8859-1.xml0000644000175000017500000000436011055111700024241 0ustar frankiefrankie Available in English Change locale English French German {Sun} {Mon} {Tue} {Wed} {Thu} {Fri} {Sat} {Jan} {Feb} {Mar} {Apr} {May} {Jun} {Jul} {Aug} {Sep} {Oct} {Nov} {Dec} AM $ %m/%d/%y %a %B %d, %Y %r %Z {Sunday} {Monday} {Tuesday} {Wednesday} {Thursday} {Friday} {Saturday} . %B %d, %Y %A %B %d, %Y 0 MONTH DD YYYY HH12:MI AM 2 3 3 USD 2 {January} {February} {March} {April} {May} {June} {July} {August} {September} {October} {November} {December} . 3 3 , 1 0 1 - 1 0 1 PM + %r , Spanish English (AU) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ko_KR.utf-8.xml0000644000175000017500000000412310727201371024025 0ustar frankiefrankie ì˜ì–´ë¡œ 가능 ì˜ì–´ 프랑스어 ë…ì¼ì–´ {ì¼} {ì›”} {í™”} {수} {목} {금} {토} {1¿?} {2¿?} {3¿?} {4¿?} {5¿?} {6¿?} {7¿?} {8¿?} {9¿?} {10¿?} {11¿?} {12¿?} 오전 â‚© %m/%d/%y %a %B %d, %Y %r %Z {?????} {¿?¿???} {?¿???} {¼?¿???} {¸?¿???} {±????} {??¿???} . %B %d, %Y %A %B %d, %Y 0 HH12:MI 오전 2 3 3 KRW 2 {1ì›”} {2ì›”} {3ì›”} {4ì›”} {5ì›”} {6ì›”} {7ì›”} {8ì›”} {9ì›”} {10ì›”} {11ì›”} {12ì›”} . 3 3 , 1 0 1 - 1 0 1 오후 + %H:%M , 스페ì¸ì–´ openacs-5.7.0/packages/acs-lang/catalog/acs-lang.hi_IN.utf-8.xml0000644000175000017500000000567410727201371024022 0ustar frankiefrankie अनà¥à¤—à¥à¤°à¥‡à¥›à¥€ मे उपà¥à¤²à¤¬à¥à¤§ घतनासà¥à¤¥à¤² बदलना अनà¥à¤—à¥à¤°à¥‡à¥›à¥€ फ़à¥à¤°à¥‡à¤¨à¥à¤š गेरà¥à¤®à¤¨ {रवि} {सोम} {मनà¥à¤—ल} {बà¥à¤§} {गà¥à¤°à¥} {शà¥à¤°à¥à¤•} {शनि} {जनवरी} {फ़रवरी} {मारà¥à¤š} {अपà¥à¤°à¥ˆà¤²} {मई} {जून} {जà¥à¤²à¤¾à¤ˆ} {अगसà¥à¤¤} {सितमà¥à¤¬à¤°} {अकतूबर} {नवमà¥à¤¬à¤°} {दिसमà¥à¤¬à¤°} à¤à¤® $ %म/%ड/%य %अ %ब %ड, %य %र %ज़ी {रविवार} {सोमवार} {मनà¥à¤—लवार} {बà¥à¤§à¤µà¤¾à¤°} {गà¥à¤°à¥à¤µà¤¾à¤°} {शà¥à¤°à¥à¤•वार} {शनिवार} । %ब %ड, %य %अ %ब %ड, %य ० महीना डड यययय हह १२:मठअम २ ३ ३ अमरीका डालर २ {जनवरी} {फ़रवरी} {मारà¥à¤š} {अपà¥à¤°à¥ˆà¤²} {मई} {जून} {जà¥à¤²à¤¾à¤ˆ} {अगसà¥à¤¤} {सितमà¥à¤¬à¤°} {अकतूबर} {नवमà¥à¤¬à¤°} {दिसमà¥à¤¬à¤°} . ३ ३ , १ ० १ - १ ० १ प म + %र , सà¥à¤ªà¤¾à¤¨à¤¿à¤¶ अनà¥à¤—à¥à¤°à¥‡à¥›à¥€ openacs-5.7.0/packages/acs-lang/catalog/acs-lang.sv_SE.ISO-8859-1.xml0000644000175000017500000000411610727201371024301 0ustar frankiefrankie Tillgängligt på svenska Engelska Franska Tyska {Sön} {Mån} {Tis} {Ons} {Tor} {Fre} {Lör} {Jan} {Feb} {Mar} {Apr} {Maj} {Jun} {Jul} {Aug} {Sep} {Okt} {Nov} {Dec} FM kr %Y-%m-%d %a %e. %B %Y %r %Z {Söndag} {Måndag} {Tisdag} {Onsdag} {Torsdag} {Fredag} {Lördag} , %d %B, %Y %A den %e. %B %Y 1 HH24:MI 2 3 3 SEK 2 {Januari} {Februari} {Mars} {April} {Maj} {Juni} {Juli} {Augusti} {September} {Oktober} {November} {December} , 3 3 . 1 0 1 - 1 1 1 EM %H:%M . Spanska openacs-5.7.0/packages/acs-lang/catalog/acs-lang.fr_FR.ISO-8859-1.xml0000644000175000017500000000436110727201371024262 0ustar frankiefrankie Disponible en français Changer Langue Anglais Français Allemand {dim} {lun} {mar} {mer} {jeu} {ven} {sam} {jan} {fév} {mar} {avr} {mai} {jun} {jui} {aoû} {sep} {oct} {nov} {déc} AM ? %d.%m.%Y %a %d %B %Y %H:%M %Z {dimanche} {lundi} {mardi} {mercredi} {jeudi} {vendredi} {samedi} , %d %B %Y %A %d %B %Y 1 MOIS JJ AAAA HH24:MI 2 3 3 EUR 2 {janvier} {février} {mars} {avril} {mai} {juin} {juillet} {août} {septembre} {octobre} {novembre} {décembre} , 3 3 . 0 1 1 - 0 1 1 PM + %H:%M . Espagnol Français (FR) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.gl_ES.ISO-8859-1.xml0000644000175000017500000000556010727201371024257 0ustar frankiefrankie Dispoñible en galego Cambiar idioma Inglés Francés Alemán Idioma Idioma para %package_name% {Dom} {Seg} {Ter} {Cua} {Qui} {Sex} {Sáb} {Xan} {Feb} {Mar} {Abr} {Mai} {Xuñ} {Xul} {Ago} {Set} {Out} {Nov} {Dec} AM $ %d-%m-%Y %a %d %B %Y %R %Z {Domingo} {Segunda} {Terceira} {Cuarta} {Quinta} {Sexta} {Sábado} , %d de %B de %Y %A, %d de %B de %Y 0 DD MONTH YYYY HH24:MI 2 3 3 EUR 2 {Xaneiro} {Febreiro} {Marzo} {Abril} {Maio} {Xuño} {Xullo} {Agosto} {Setembro} {Outubro} {Novembro} {Decembro} , 3 3 . 1 0 1 - 1 0 1 PM + %r . Resolver conflictos de mensaxes Español Galician-Portugese (ES) Mensaxes traducidos nesta páxina (%locale%) A súa selección de idioma para %package_name%. Si está activado, sobreescribirá a selección xeral nesta aplicación en particular. A súa selección de idioma para todo o sitio. O seu idioma A súa zona horaria openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ro_RO.utf-8.xml0000644000175000017500000000425710727201371024050 0ustar frankiefrankie Disponibil in Engleza alege altă limbă Engleză Franceză Germană Dum Lun Mar Mie Joi Vin Sam Ian Feb Mar Apr Mai Iun Iul Aug Sep Oct Nov Dec AM $ %d/%m/%y %a %B %d, %Y %r %Z Duminică Luni MarÅ£i Miercuri Joi Vineri Sâmbătă . %d %B, %Y %A %B %d, %Y 0 DD MONTH YYYY HH12:MI AM 2 3 3 USD 2 Ianuarie Februarie Martie Aprilie Mai Iunie Iulie August Septembrie Octombrie Noiembrie Decembrie . 3 3 , 1 0 1 - 1 0 1 PM + %r , Spaniolă Romainian (RO) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.pl_PL.utf-8.xml0000644000175000017500000000561510727201371024035 0ustar frankiefrankie DostÄ™pne po polsku ZmieÅ„ jÄ™zyk Angielski Francuski Niemiecki JÄ™zyk JÄ™zyk dla %package_name% {Nd} {Pn} {Wt} {Åšr} {Czw} {Pt} {So} {Sty} {Lut} {Mar} {Kwi} {Maj} {Cze} {Lip} {Sie} {Wrz} {Paź} {Lis} {Gru} PP zÅ‚ %d-%m-%y %d %B %Y %T %Z {Niedziela} {PoniedziaÅ‚ek} {Wtorek} {Åšroda} {Czwartek} {PiÄ…tek} {Sobota} , %B %d, %Y %A %B %d, %Y 0 MIESIÄ„C DD RRRR GG12:MI PP 2 3 3 PLN 2 {StyczeÅ„} {Luty} {Marzec} {KwiecieÅ„} {Maj} {Czerwiec} {Lipiec} {SierpieÅ„} {WrzesieÅ„} {Październik} {Listopad} {GrudzieÅ„} , 3 3 , 1 1 1 - 1 0 1 PP + %T &nbsp; Rozwiąż konflikty komunikatów HiszpaÅ„ski Polski PrzetÅ‚umaczone teksty na tej stronie (%locale%) Konfiguracja jÄ™zyka dla %package_name%. JeÅ›li wartość jest ustawiona, zmienia ustawienia jÄ™zykowe dla tej wÅ‚aÅ›nie aplikacji. Ustawienia jÄ™zykowe dla caÅ‚ego serwisu Twój Preferowany JÄ™zyk Twoja Strefa Czasowa openacs-5.7.0/packages/acs-lang/catalog/acs-lang.zh_TW.utf-8.xml0000644000175000017500000000431110727201371024052 0ustar frankiefrankie ç¹é«”中文版 變更地å€è¨­å®š 英文 法文 å¾·æ–‡ æ—¥ 一 二 三 å›› 五 å…­ 一月 二月 三月 四月 五月 六月 七月 八月 乿œˆ åæœˆ å一月 å二月 ä¸Šåˆ $ %m%d%y %a %B %d, %Y %r %Z 週日 週一 週二 週三 週四 週五 週六 . %Yå¹´%B%dæ—¥ %A %B %d, %Y 0 MONTH DD YYYY ä¸Šåˆ HH12:MI 2 3 3 NTD 2 一月 二月 三月 四月 五月 六月 七月 八月 乿œˆ åæœˆ å一月 å二月 . 3 3 , 1 0 1 - 1 0 1 ä¸‹åˆ + %r , 西ç­ç‰™æ–‡ 英文 openacs-5.7.0/packages/acs-lang/catalog/acs-lang.en_GB.ISO-8859-1.xml0000644000175000017500000000365310727201371024241 0ustar frankiefrankie {Sun} {Mon} {Tue} {Wed} {Thu} {Fri} {Sat} {Jan} {Feb} {Mar} {Apr} {May} {Jun} {Jul} {Aug} {Sep} {Oct} {Nov} {Dec} £ %d/%m/%y %a %d %B %Y %H:%M %Z {Sunday} {Monday} {Tuesday} {Wednesday} {Thursday} {Friday} {Saturday} . %d %B %Y %A %d %B %Y 0 HH24:MI 2 3 3 GBP 2 {January} {February} {March} {April} {May} {June} {July} {August} {September} {October} {November} {December} . 3 3 , 1 0 1 - 1 0 1 %H:%M , English (GB) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.de_DE.ISO-8859-1.xml0000644000175000017500000000561310720127055024224 0ustar frankiefrankie Deutsche Version verfügbar Sprache wechseln Englisch Französisch Deutsch Locale Locale für %package_name% {So} {Mo} {Di} {Mi} {Do} {Fr} {Sa} {Jan} {Feb} {Mrz} {Apr} {Mai} {Jun} {Jul} {Aug} {Sep} {Okt} {Nov} {Dez} A.M. ? %d.%m.%Y %a, %d. %B %Y %H:%M %Z {Sonntag} {Montag} {Dienstag} {Mittwoch} {Donnerstag} {Freitag} {Samstag} , %d. %B %Y %A, %d. %B %Y 1 DD MONTH YYYY HH24:MI 2 3 3 EUR 2 {Januar} {Februar} {März} {April} {Mai} {Juni} {Juli} {August} {September} {Oktober} {November} {Dezember} , 3 3 . 1 0 1 - 1 0 1 P.M. + %H:%M . Übersetzungskonflikte aufläsen Spanisch Deutsch Übersetzte Nachrichten auf dieser Seite (%locale%) Die Spracheinstellung für %package_name%. Wenn gesetzt wird diese die Systemweiten Einstellungen für diese Applikation überschreiben Ihre Spracheinstellung für die gesamte Website Ihre bevorzugte Spracheinstellung Ihre Zeitzone openacs-5.7.0/packages/acs-lang/catalog/acs-lang.nl_NL.ISO-8859-1.xml0000644000175000017500000000560110727201371024264 0ustar frankiefrankie Nederlandse versie is beschikbaar Taal instellen Engels Frans Duits Taalregio Taalregio voor voor %package_name% {zon} {maa} {din} {woe} {don} {vr?} {zat} {jan} {feb} {mrt} {apr} {mei} {jun} {jul} {aug} {sep} {okt} {nov} {dec} Voormiddag ? %d.%m.%Y %a %d %B %Y %H:%M %Z {zondag} {maandag} {dinsdag} {woensdag} {donderdag} {vrijdag} {zaterdag} , %d %B %Y %A %d %B %Y 1 Maand DD JJJJ HH24:MI 2 3 3 EUR 2 {januari} {februari} {maart} {april} {mei} {juni} {juli} {augustus} {september} {oktober} {november} {december} , 3 3 . 1 0 1 - 1 0 1 Namiddag + %H:%M . Berichtconflicten oplossen Spaans Nederlands Vertaalde berichten op deze pagina (%locale%) Uw taalregioinstelling voor %package_name%. Indien u deze instelt, overroept deze de sitebrede instelling in deze applicatie. Uw taalregioinstelling voor de hele site Uw gewenste taalregio Uw tijdzone openacs-5.7.0/packages/acs-lang/catalog/acs-lang.pa_IN.utf-8.xml0000644000175000017500000000531610727201371024013 0ustar frankiefrankie ਅੰਗਰੇਜ਼ੀ 'ਚ ਉਪਲੱਬਧ ਹੈ ਲੋਕੇਲ ਤਬਦੀਲ ਅੰਗਰੇਜ਼ੀ ਫਰੈਂਚ ਜਰਮਨ {à¨à¨¤} {ਸੋਮ} {ਮੰਗਲ} {ਬà©à©±à¨§} {ਵੀਰ} {ਸ਼à©à©±à¨•ਰ} {ਸ਼ਨਿੱਚਰ} {ਜਨਵਰੀ}{ਫਰਵਰੀ}{ਮਾਰਚ}{ਅਪਰੈਲ}{ਮਈ}{ਜੂਨ}{ਜà©à¨²à¨¾à¨ˆ}{ਅਗਸਤ}{ਸਤੰਬਰ}{ਅਕਤੂਬਰ}{ਨਵੰਬਰ}{ਦਸੰਬਰ} ਸਵੇਰੇ $ %m/%d/%y %a %B %d, %Y %r %Z {à¨à¨¤à¨µà¨¾à¨°}{ਸੋਮਵਾਰ}{ਮੰਗਲਵਾਰ}{ਬà©à©±à¨§à¨µà¨¾à¨°}{ਵੀਰਵਾਰ}{ਸ਼à©à©±à¨•ਰਵਾਰ}{ਸ਼ਨਿੱਚਰਵਾਰ} . %B %d, %Y %A %B %d, %Y 0 MONTH DD YYYY HH12:MI AM 2 3 3 INR 2 {ਜਨਵਰੀ} {ਫਰਵਰੀ} {ਮਾਰਚ} {ਅਪਰੈਲ} {ਮਈ} {ਜੂਨ} {ਜà©à¨²à¨¾à¨ˆ} {ਅਗਸਤ} {ਸਤੰਬਰ} {ਅਕਤੂਬਰ} {ਨਵੰਬਰ} {ਦਸੰਬਰ} . 3 3 , 1 0 1 - 1 0 1 ਸ਼ਾਮ + %r , ਸਪੇਨੀ ਅੰਗਰੇਜ਼ੀ openacs-5.7.0/packages/acs-lang/catalog/acs-lang.es_GT.ISO-8859-1.xml0000644000175000017500000000425610727201371024270 0ustar frankiefrankie Disponible en Español Cambiar idioma Inglés Francés Alemán {Dom} {Lun} {Mar} {Mié} {Jue} {Vie} {Sáb} {Ene} {Feb} {Mar} {Abr} {May} {Jun} {Jul} {Ago} {Sep} {Oct} {Nov} {Dic} AM %d/%m/%y %a %d %B %Y %H:%M %Z {Domingo} {Lunes} {Martes} {Miércoles} {Jueves} {Viernes} {Sábado} . %d, %B %Y %A %d %B %Y 0 HH24:MI 0 -1 -1 EUR 0 {Enero} {Febrero} {Marzo} {Abril} {Mayo} {Junio} {Julio} {Agosto} {Septiembre} {Octubre} {Noviembre} {Diciembre} . 3 3 . 1 1 1 - 1 1 1 PM + %H:%M , Español Español (GT) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.th_TH.utf-8.xml0000644000175000017500000000153510727201371024032 0ustar frankiefrankie ภาษาอังà¸à¸¤à¸© ภาษาà¸à¸£à¸±à¹ˆà¸‡à¹€à¸¨à¸ª ภาษาเยอรมัน {อ} {จ} {อ} {พ} {พฤ} {ศ} {ส} AM {มà¸à¸£à¸²à¸„ม} {à¸à¸¸à¸¡à¸ à¸²à¸žà¸±à¸™à¸˜à¹Œ} {มีนาคม} {เมษายน} {พฤษภาคม} {มิถุนายน} {à¸à¸£à¸à¸Žà¸²à¸„ม} {สิงหาคม} {à¸à¸±à¸™à¸¢à¸²à¸¢à¸™} {ตุลาคม} {พฤศจิà¸à¸²à¸¢à¸™} {ธันวาคม} PM ภาษาสเปน openacs-5.7.0/packages/acs-lang/catalog/acs-lang.zh_CN.utf-8.xml0000644000175000017500000000443610727201371024030 0ustar frankiefrankie 中文版 改å˜è¯­è¨€ 英语 法语 德语 {周日} {周一} {周二} {周三} {周四} {周五} {周六} {1月} {2月} {3月} {4月} {5月} {6月} {7月} {8月} {9月} {10月} {11月} {12月} ä¸Šåˆ Â¥ %yå¹´%m月%dæ—¥ %a %Yå¹´ %B月 %dæ—¥ %r %Z {星期日} {星期一} {星期二} {星期三} {星期四} {星期五} {星期六} . %Yå¹´ %B月 %dæ—¥ %A% Yå¹´ %B月 %dæ—¥ 0 MONTH DD YYYY HH12:MI AM 2 3 3 RMB 2 {1月} {2月} {3月} {4月} {5月} {6月} {7月} {8月} {9月} {10月} {11月} {12月} . 3 3 , 1 0 1 — 1 0 1 ä¸‹åˆ + %r , 西ç­ç‰™è¯­ 英语 openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ch_zh.utf-8.xml0000644000175000017500000000404211055111700024102 0ustar frankiefrankie 中文版 英语 法语 德语 周日 周一 周二 周三 周四 周五 周六 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 ä¸Šåˆ Â¥ %yå¹´%m月%dæ—¥ %a %B %d, %Y %r %Z 星期日 星期一 星期二 星期三 星期四 星期五 星期六 . %Yå¹´ %B %dæ—¥ %A %B %d, %Y 0 HH12:MI AM 2 3 3 RMB 2 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 . 3 3 , 1 0 1 — 1 0 1 ä¸‹åˆ + %r , 西ç­ç‰™è¯­ openacs-5.7.0/packages/acs-lang/catalog/acs-lang.nn_NO.ISO-8859-1.xml0000644000175000017500000000436710727201371024301 0ustar frankiefrankie Tilgjengeleg på norsk Change locale Engelsk Fransk Tysk {sun} {mån} {tys} {ons} {tor} {fre} {lau} {jan} {feb} {mar} {apr} {mai} {jun} {jul} {aug} {sep} {okt} {nov} {des} Formiddag kr %e%m-%y %a %e. %B %Y %r %Z {sundag} {måndag} {tysdag} {onsdag} {torsdag} {fredag} {laurdag} , %e. %B %Y %A %e. %B %Y 1 MONTH DD YYYY HH24:MI 2 3 3 NOK 2 {januar} {februar} {mars} {april} {mai} {juni} {juli} {august} {september} {oktober} {november} {desember} , 3 3 . 1 0 1 - 1 0 1 Ettermiddag + %H:%M . Spansk Norwegian (NO) openacs-5.7.0/packages/acs-lang/catalog/acs-lang.el_GR.utf-8.xml0000644000175000017500000000667210720404625024023 0ustar frankiefrankie Διαθέσιμο στα Αγγλικά Αλλαγή γλώσσας Αγγλικά Γαλλικά ΓεÏμανικά Ρυθμίσεις γλώσσας Ρυθμίσεις γλώσσας για %package_name% {Κ} {Δ} {Τ} {Τ} {Π} {Π} {Σ} {Ιαν} {Φεβ} {ΜαÏ} {ΑπÏ} {Μαι} {Ιουν} {Ιουλ} {Αυγ} {Σεπ} {Οκτ} {Îοε} {Δεκ} πμ Euro %d%m%y %d %a %B, %Y %r %Z {ΚυÏιακή} {ΔευτέÏα} {ΤÏίτη} {ΤετάÏτη} {Πέμπτη} {ΠαÏασκευή} {Σάββατο} , %d %B,%Y %d %A %B, %Y 0 DD MONTH YYYY HH12:MI AM 2 3 3 Euro 2 {ΙανουάÏιος} {ΦεβÏουάÏιος} {ΜάÏτιος} {ΑπÏίλιος} {Μάιος} {ΙοÏνιος} {ΙοÏλιος} {ΑÏγουστος} {ΣεπτέμβÏιος} {ΟκτώβÏιος} {ÎοέμβÏιος} {ΔεκέμβÏιος} , 3 3 . 1 0 1 - 1 0 1 μμ + %r . Επίλυση Ï€Ïοβλημάτων μηνÏματος Ισπανικά Ελληνικά ΜεταφÏασμένα μηνÏματα σε αυτή την σελίδα (%locale%) Οι Ïυθμίσεις γλώσσας για %package_name%. Εαν τις ενεÏγοποιήσετε θα επικαλÏψετε τις Ïυθμίσεις που έχουν οÏιστεί για τη συγκεκÏιμένη εφαÏμογή. Οι Ïυθμίσεις γλώσσας που επιλέξατε για όλο τον ιστοχώÏο Ρυθμίσεις Γλώσσας Ζώνη ÏŽÏας openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ca_ES.ISO-8859-1.xml0000644000175000017500000000562410727201371024241 0ustar frankiefrankie Disponible en català Canvia idioma Anglès Francès Alemany Configuració local Idioma per a %package_name% {dg.} {dl.} {dt.} {dc.} {dj.} {dv.} {ds.} {gen.} {febr.} {març} {abr.} {maig} {juny} {jul.} {ag.} {set.} {oct.} {nov.} {des.} AM ? %m/%d/%y %a %d %B %Y %H:%M %Z {diumenge} {dilluns} {dimarts} {dimecres} {dijous} {divendres} {dissabte} , %d %B %Y %A %d %B %Y 1 DD MONTH YYYY HH12:MI AM 2 3 3 EUR 2 {gener} {febrer} {març} {abril} {maig} {juny} {juliol} {agost} {setembre} {octubre} {novembre} {desembre} , 3 3 . 1 1 1 - 1 1 1 PM + %H:%M . Resolució de conflictes entre missatges Castellà Català Missatges traduïts en aquesta pàgina (%locale%) La configuració local en %package_name%. Si se selecciona, anul·larà la configuració de tot el lloc per aquesta aplicació. El vostre idioma s'aplica a tot el lloc El vostre idioma preferit La vostra zona horària openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ast_ES.ISO-8859-1.xml0000644000175000017500000000375710727201371024452 0ustar frankiefrankie Inglés Francés Alemán {Dom} {llu} {Mar} {Mié} {Xue} {Vie} {Sab} {Xin} {Feb} {Mar} {Abr} {May} {Xun} {Xul} {Ago} {Set} {Otu} {Nov} {Avi} AM $ "%d-%m-%y" "%a %d %B %Y %R %Z" {Domingo} {Llunes} {Martes} {Miércoles} {Xueves} {Vienres} {Sábado} ' "%d de(d')%m del %Y" "%A, %d de(d') %B del %Y" 1 HH24:MI 2 3 3 EUR 2 {Xinero} {Febrero} {Marzo} {Abril} {Mayo} {Xuno} {Xuneto} {Agosto} {Setiembre} {Otubre} {Noviembre} {Aviento} , 3 3 . 1 0 1 - 1 0 1 PM . Castellano openacs-5.7.0/packages/acs-lang/catalog/acs-lang.pt_PT.ISO-8859-1.xml0000644000175000017500000000401310727201371024304 0ustar frankiefrankie Inglês Francês Alemão {Dom} {Seg} {Ter} {Qua} {Qui} {Sex} {Sáb} {Jan} {Fev} {Mar} {Abr} {Mai} {Jun} {Jul} {Ago} {Set} {Out} {Nov} {Dez} AM ? %d-%m-%Y %a %d %B %Y %R %Z {Domingo} {Segunda} {Terça} {Quarta} {Quinta} {Sexta} {Sábado} . %d de %B de %Y %A, %d de %B de %Y 0 HH24:MI 2 3 3 EUR 2 {Janeiro} {Fevereiro} {Março} {Abril} {Maio} {Junho} {Julho} {Agosto} {Setembro} {Outubro} {Novembro} {Dezembro} . 3 3 , 1 0 1 - 1 0 1 PM %r , Espanhol openacs-5.7.0/packages/acs-lang/catalog/acs-lang.ms_MY.utf-8.xml0000644000175000017500000000425510727201371024052 0ustar frankiefrankie Sedia ada dalam Bahasa Melayu Penempatan Bahasa Inggeris Bahasa Perancis Bahasa Jerman {Aha} {Isn} {Sel} {Rab} {Kha} {Jum} {Sab} {Jan} {Feb} {Mac} {Apr} {Mei} {Jun} {Jul} {Ogo} {Sep} {Okt} {Nov} {Dis} AM $ %m/%d/%y %a %B %d %Y %r %Z {Ahad} {Isnin} {Selasa} {Rabu} {Khamis} {Jumaat} {Sabtu} . %B %d %Y %A %B %d %Y 0 HH12:MI AM 2 3 3 RM 2 {Januari} {Februari} {Mac} {April} {Mei} {Jun} {Julai} {Ogos} {September} {Oktober} {November} {Disember} . 3 3 , 1 0 1 - 1 0 1 PM %r , Bahasa Sepanyol Bahasa Melayu openacs-5.7.0/packages/acs-lang/catalog/acs-lang.cs_CZ.utf-8.xml0000644000175000017500000000410211055111700024005 0ustar frankiefrankie Dostupné v angliÄtinÄ› ZmÄ›nit národní nastavení angliÄtina francouzÅ¡tina nÄ›mÄina {Ne} {Po} {Út} {St} {ÄŒt} {Pá} {So} {led} {úno} {bÅ™e} {dub} {kvÄ›} {Ävn} {Ävc} {srp} {zář} {říj} {lis} {pro} dop. %d.%m.%y {nedÄ›le} {pondÄ›lí} {úterý} {stÅ™eda} {Ätvrtek} {pátek} {sobota} , 1 DD. MONTH YYYY HH24:MI 2 3 3 2 {leden} {únor} {bÅ™ezen} {duben} {kvÄ›ten} {Äerven} {Äervenec} {srpen} {září} {říjen} {listopad} {prosinec} , 3 3 . 0 1 1 - + 0 0 odp. + . Å¡panÄ›lÅ¡tina ÄeÅ¡tina openacs-5.7.0/packages/acs-lang/catalog/acs-lang.nl_ZA.ISO-8859-1.xml0000644000175000017500000000556111055111700024261 0ustar frankiefrankie Afrikaanse weergave is beskikbaar Stel taal in Engels Frans Duits Taalaera Taalarea vir %package_name% {Son} {Maa} {Din} {Woe} {Don} {Vry} {Sat} {Jan} {Feb} {Mrt} {Apr} {Mei} {Jun} {Jul} {Aug} {Sep} {Okt} {Nov} {Des} Voormiddag ? %d.%m.%Y %a %d %B %Y %H:%M %Z {Sondag} {Maandag} {Dinsdag} {Woensdag} {Donderdag} {Vrydag} {Saterdag} , %d %B %Y %A %d %B %Y 1 DD MONTH YYYY HH24:MI 2 3 3 Rand 2 {Januarie} {Februarie} {Maart} {April} {Mei} {Junie} {Julie} {Augustus} {September} {Oktober} {November} {Desember} , 3 3 . 1 0 1 - 1 0 1 Namiddag + %H:%M . Los berigkonflikte op Spaans Afrikaans Vertaalde berigte op hierdie bladsy (%locale%) U taalareainstelling vir %package_name%. Indien ingestel sal dit die werfbrede instelling in hierdie ene toepassing oorroep. U taalareainstelling vir die gehele werd U voorkeurstaalarea U tydsone openacs-5.7.0/packages/acs-lang/catalog/acs-lang.sh_HR.utf-8.xml0000644000175000017500000000042010727201371024017 0ustar frankiefrankie Engleski Francuski Nemacki Spanski openacs-5.7.0/packages/acs-tcl/0000755000175000017500000000000011724401447016103 5ustar frankiefrankieopenacs-5.7.0/packages/acs-tcl/lib/0000755000175000017500000000000011724401447016651 5ustar frankiefrankieopenacs-5.7.0/packages/acs-tcl/lib/ad-return-complaint.adp0000644000175000017500000000071410720375265023231 0ustar frankiefrankie #acs-tcl.lt_Problem_with_your_inp#

    #acs-tcl.We_had# #acs-tcl.some_problems# #acs-tcl.a_problem# #acs-tcl.with_your_input#

      @exception_text;noquote@

    #acs-tcl.lt_Please_back_up_using_# #acs-tcl.errors##acs-tcl.error##acs-tcl.lt__and_resubmit_your_en#

    #acs-tcl.Thank_you#

    openacs-5.7.0/packages/acs-tcl/lib/progress-bar.adp0000644000175000017500000000330710721035754021750 0ustar frankiefrankie @title@

    @title;noquote@

    @message_1@

                            

    @message_2@

    openacs-5.7.0/packages/acs-tcl/lib/actions.adp0000644000175000017500000000077010217144013020770 0ustar frankiefrankie

    @actions.title_text@

    @actions.long_text;noquote@
    @actions.text@
    @actions.long_text;noquote@
    openacs-5.7.0/packages/acs-tcl/lib/actions.tcl0000644000175000017500000000163110551254403021011 0ustar frankiefrankie# Generate an html version of the given package_id's admin actions. # expects to be in a conn. # # @param package_id # @param package_key # @param return_url set user_id [ad_conn user_id] multirow create actions type url_stub text title_text long_text if {![catch { lindex [callback -catch -impl $package_key navigation::package_admin -user_id $user_id -package_id $package_id -return_url $return_url] 0 } action_list]} { foreach action $action_list { if {[lindex $action 0] eq "LINK"} { foreach {type stub text title long} $action {break} multirow append actions $type "$base_url$stub" $text $title $long } elseif {[lindex $action 0] eq "SECTION"} { foreach {type title long} $action {break} multirow append actions $type {} {} $title $long } else { error "actions.tcl: type [lindex $action 0] unknown" } } } openacs-5.7.0/packages/acs-tcl/lib/page-error.adp0000644000175000017500000000104510661350267021404 0ustar frankiefrankie #acs-tcl.Server#

    #acs-tcl.There#

    @message;noquote@


    #acs-tcl.Return_prev#

    #acs-tcl.Bug_History#

    @stacktrace@
    openacs-5.7.0/packages/acs-tcl/lib/page-error.tcl0000644000175000017500000003421211226233616021420 0ustar frankiefrankie# /packages/acs-tcl/lib/page-error.tcl ad_page_contract { @author Victor Guerra (guerra@galileo.edu) @creation-date 2005-02-03 @arch-tag: 983f3d87-40c8-4327-8873-c6a01ba7d875 @cvs-id $Id: page-error.tcl,v 1.7 2009/07/12 01:08:30 donb Exp $ } { {bug_number ""} } set show_patch_status open set user_agent_p 1 set error_info $stacktrace set comment_action 0 set return_url $prev_url if {$user_id eq 0} { set user_name "[_ acs-tcl.Public_User]" set public_userm_email [parameter::get -package_id [ad_acs_kernel_id] -parameter HostAdministrator -default ""] } else { db_1row get_user_info { *SQL* } set public_userm_email $user_email } set send_email_p [parameter::get -package_id [ad_acs_kernel_id] -parameter SendErrorEmailP -default 0] set system_name [ad_system_name] set subject "[_ acs-tcl.lt_Error_Report_in_ad_sy] ( [_ acs-tcl.File ] $error_file )" set found_in_version "" set send_to [parameter::get -package_id [ad_acs_kernel_id] -parameter HostAdministrator -default "[ad_system_owner]"] set error_desc_email " --------------------------------------------------------
    [_ acs-tcl.Error_Report]
    --------------------------------------------------------
    [_ acs-tcl.Previus] $return_url
    [_ acs-tcl.Page] $error_url
    [_ acs-tcl.File] $error_file
    [_ acs-tcl.User_Name] $user_name
    [_ acs-tcl.lt_User_Id_of_the_user_t] $user_id
    IP: [ns_conn peeraddr]
    [_ acs-tcl.Browser_of_the_user] [ad_quotehtml [ns_set get [ns_conn headers] User-Agent]]

    -----------------------------
    [_ acs-tcl.Error_details]
    -----------------------------
    [ad_quotehtml $error_info]

    ------------------------------


    [_ acs-tcl.lt_NB_This_error_was_sub]" if { $bug_number eq "" && $send_email_p} { acs_mail_lite::send -send_immediately -to_addr $send_to -from_addr $public_userm_email -subject $subject -body $error_desc_email } set bt_instance [parameter::get -package_id [ad_acs_kernel_id] \ -parameter BugTrackerInstance -default ""] if { $bt_instance ne "" } { array set community_info [site_node::get -url "${bt_instance}/[bug_tracker::package_key]"] set bt_package_id $community_info(package_id) set auto_submit_p [parameter::get -parameter AutoSubmitErrorsP -package_id $bt_package_id -default 0] } else { set auto_submit_p 0 } if {$auto_submit_p && $user_id > 0} { # Is this project using multiple versions? set versions_p [bug_tracker::versions_p] # Paches enabled for this project? set patches_p [bug_tracker::patches_p] set enabled_action_id [form get_action bug_edit] set exist_bug [db_string search_bug {} -default ""] if { $exist_bug eq ""} { #Submit the new Bug into the Bug - Tracker && Into the # Auto_bugs tabble set bug_id [db_nextval acs_object_id_seq] set keyword_ids [list] foreach {category_id category_name} [bug_tracker::category_types -package_id $bt_package_id] { lappend keyword_ids [bug_tracker::get_default_keyword -parent_id $category_id -package_id $bt_package_id] } bug_tracker::bug::new \ -bug_id $bug_id \ -package_id $bt_package_id \ -component_id [bug_tracker::conn component_id] \ -found_in_version $found_in_version \ -summary $subject \ -description $error_desc_email \ -desc_format text/html \ -keyword_ids $keyword_ids \ -user_id $user_id bug_tracker::bugs_exist_p_set_true -package_id $bt_package_id db_dml insert_auto_bug { *SQL* } } else { #Comment on the Existing Bug even if the user dont want to add # commentaries # If the bug is closed or fixed we have to reopen the bug array set row [list] set bug_id $exist_bug if {$bug_number eq ""} { db_dml increase_reported_times { *SQL* } } # Get the bug data bug_tracker::bug::get -bug_id $bug_id -array bug -enabled_action_id $enabled_action_id set case_id [workflow::case::get_id \ -object_id $bug_id \ -workflow_short_name [bug_tracker::bug::workflow_short_name]] foreach available_enabled_action_id [workflow::case::get_available_enabled_action_ids -case_id $case_id] { workflow::case::enabled_action_get -enabled_action_id $available_enabled_action_id -array enabled_action workflow::action::get -action_id $enabled_action(action_id) -array available_action if {[string match "*Reopen*" $available_action(pretty_name)]} { bug_tracker::bug::edit \ -bug_id $bug_id \ -enabled_action_id $available_enabled_action_id \ -description " [_ acs-tcl.reopened_auto ] " \ -desc_format text/html \ -array row \ -entry_id $bug(entry_id) } if {[string match "*Comment*" $available_action(pretty_name)]} { set comment_action $available_enabled_action_id } } bug_tracker::bug::edit \ -bug_id $bug_id \ -enabled_action_id $comment_action \ -description $error_desc_email \ -desc_format text/html \ -array row \ -entry_id $bug(entry_id) } set case_id [workflow::case::get_id \ -object_id $bug_id \ -workflow_short_name [bug_tracker::bug::workflow_short_name]] set workflow_id [bug_tracker::bug::get_instance_workflow_id -package_id $bt_package_id] # set enabled_action_id [form get_action bug_edit] # Registration required for all actions set action_id "" #if { $enabled_action_id ne "" } { # workflow::case::enabled_action_get -enabled_action_id $enabled_action_id -array enabled_action # set action_id $enabled_action(action_id) # } set times_rep [db_string select_times_reported {} -default 0 ] ad_form -name bug_edit -export {comment_action reopen_action bt_instance bt_package_id user_id bug_package_id} -form { {bug_number_display:text(inform) {label "[bug_tracker::conn Bug] \\\#"} {mode display} } {component_id:integer(select),optional {label "[_ bug-tracker.Component]"} {options {[bug_tracker::components_get_options]}} {mode display} } {summary:text(text) {label "[_ bug-tracker.Summary]"} {before_html ""} {after_html ""} {mode display} {html {size 50}} } {pretty_state:text(inform) {label "[_ bug-tracker.Status]"} {before_html ""} {after_html ""} {mode display} } {resolution:text(select),optional {label "[_ bug-tracker.Resolution]"} {options {[bug_tracker::resolution_get_options]}} {mode display} } {previus_url:text(inform) {label "[_ acs-tcl.Previus]"} {value $prev_url} } {err_url:text(inform) {label "[_ acs-tcl.Page]"} {value $error_url} } {err_file:text(inform) {label "[_ acs-tcl.File]"} {value $error_file} } {times_reported:text(inform) {label "[_ acs-tcl.Times_reported]"} {value $times_rep} } } foreach {category_id category_name} [bug_tracker::category_types] { ad_form -extend -name bug_edit -form [list \ [list "${category_id}:integer(select)" \ [list label $category_name] \ [list options [bug_tracker::category_get_options -parent_id $category_id]] \ [list mode display] \ ] \ ] } ad_form -extend -name bug_edit -form { {found_in_version:text(select),optional {label "[_ bug-tracker.Found_in_Version]"} {options {[bug_tracker::version_get_options -include_unknown]}} {mode display} } } workflow::case::role::add_assignee_widgets -case_id $case_id -form_name bug_edit ad_form -extend -name bug_edit -form { {user_agent:text(inform) {label "[_ bug-tracker.User_Agent]"} {mode display} } {fix_for_version:text(select),optional {label "[_ bug-tracker.Fix_for_Version]"} {options {[bug_tracker::version_get_options -include_undecided]}} {mode display} } {fixed_in_version:text(select),optional {label "[_ bug-tracker.Fixed_in_Version]"} {options {[bug_tracker::version_get_options -include_undecided]}} {mode display} } {description:richtext(richtext),optional {label "[_ bug-tracker.Description]"} {html {cols 60 rows 13}} } {return_url:text(hidden) {value $return_url} } {bug_number:key} {entry_id:integer(hidden),optional} } -on_submit { array set row [list] # if { $enabled_action_id ne "" } { # foreach field [workflow::action::get_element -action_id $action_id -element edit_fields] { # set row($field) [element get_value bug_edit $field] # } # foreach {category_id category_name} [bug_tracker::category_types] { # set row($category_id) [element get_value bug_edit $category_id] # } # } set description [element get_value bug_edit description] set error_desc_html " --------------------------------------------------------
    [_ acs-tcl.Error_Report]
    --------------------------------------------------------

    [_ acs-tcl.Previus] $prev_url
    [_ acs-tcl.Page] $error_url
    [_ acs-tcl.File] $error_file
    [_ acs-tcl.User_Name] $user_name
    [_ acs-tcl.lt_User_Id_of_the_user_t] $user_id
    [_ acs-tcl.Browser_of_the_user] [ad_quotehtml [ns_set get [ns_conn headers] User-Agent]]

    [_ acs-tcl.User_comments]
    [template::util::richtext::get_property contents $description]

    " foreach available_enabled_action_id [workflow::case::get_available_enabled_action_ids -case_id $case_id] { workflow::case::enabled_action_get -enabled_action_id $available_enabled_action_id -array enabled_action workflow::action::get -action_id $enabled_action(action_id) -array available_action if {[string match "*Comment*" $available_action(pretty_name)]} { set comment_action $available_enabled_action_id } } bug_tracker::bug::edit \ -bug_id $bug_id \ -enabled_action_id $comment_action \ -description [template::util::richtext::get_property contents $description] \ -desc_format [template::util::richtext::get_property format $description] \ -array row \ -entry_id [element get_value bug_edit entry_id] ad_returnredirect $return_url ad_script_abort } -edit_request { # ID form complains if -edit_request is missing } if { ![form is_valid bug_edit] } { # Get the bug data bug_tracker::bug::get -bug_id $bug_id -array bug -enabled_action_id $enabled_action_id # Make list of form fields set element_names { bug_number component_id summary pretty_state resolution found_in_version user_agent fix_for_version fixed_in_version bug_number_display entry_id } # update the element_name list and bug array with category stuff foreach {category_id category_name} [bug_tracker::category_types] { lappend element_names $category_id set bug($category_id) [cr::keyword::item_get_assigned -item_id $bug(bug_id) -parent_id $category_id] if {$bug($category_id) eq "" } { set bug($category_id) [bug_tracker::get_default_keyword -parent_id $category_id] } } # Display value for patches set bug(patches_display) "[bug_tracker::get_patch_links -bug_id $bug(bug_id) -show_patch_status $show_patch_status]   \[ [_ bug-tracker.Upload_Patch] \]" # Hide elements that should be hidden depending on the bug status foreach element $bug(hide_fields) { element set_properties bug_edit $element -widget hidden } if { !$versions_p } { foreach element { found_in_version fix_for_version fixed_in_version } { if { [info exists bug_edit:$element] } { element set_properties bug_edit $element -widget hidden } } } if { !$patches_p } { foreach element { patches } { if { [info exists bug_edit:$element] } { element set_properties bug_edit $element -widget hidden } } } # Optionally hide user agent if { !$user_agent_p } { element set_properties bug_edit user_agent -widget hidden } # Set regular element values foreach element $element_names { # check that the element exists if { [info exists bug_edit:$element] && [info exists bug($element)] } { if {[form is_request bug_edit] || [string equal [element get_property bug_edit $element mode] "display"] } { if { [string first "\#" $bug($element)] == 0 } { element set_value bug_edit $element [lang::util::localize $bug($element)] } else { element set_value bug_edit $element $bug($element) } } } } # Add empty option to resolution code if { $enabled_action_id ne "" } { if { [lsearch [workflow::action::get_element -action_id $action_id -element edit_fields] "resolution"] == -1 } { element set_properties bug_edit resolution -options [concat {{{} {}}} [element get_property bug_edit resolution options]] } } else { element set_properties bug_edit resolution -widget hidden } # Get values for the role assignment widgets workflow::case::role::set_assignee_values -case_id $case_id -form_name bug_edit # Set values for elements with separate display value foreach element { patches } { # check that the element exists if { [info exists bug_edit:$element] } { element set_properties bug_edit $element -display_value $bug(${element}_display) } } # Set values for description field ad_form -name bug_history -has_submit 1 -form { {history:text(inform) {label "[_ acs-tcl.User_comments]"} {value ""} } } element set_properties bug_history history \ -after_html [workflow::case::get_activity_html -case_id $case_id -action_id $action_id] } } openacs-5.7.0/packages/acs-tcl/lib/page-error.xql0000644000175000017500000000263410207651303021440 0ustar frankiefrankie select p.first_names||' '||p.last_name as user_name, pa.email as user_email from persons p, parties pa where pa.party_id = p.person_id and p.person_id = :user_id select bug_id from bt_auto_bugs where error_file =:error_file and package_id = :bug_package_id insert into bt_auto_bugs(bug_id, package_id, error_file) values (:bug_id, :bug_package_id, :error_file) update bt_auto_bugs set times_reported = times_reported + 1 where bug_id = :bug_id select times_reported from bt_auto_bugs where bug_id = :bug_id openacs-5.7.0/packages/acs-tcl/lib/ad-return-error.adp0000644000175000017500000000020611334362063022362 0ustar frankiefrankie @title;noquote@

    @explanation;noquote@

    openacs-5.7.0/packages/acs-tcl/lib/complain.adp0000644000175000017500000000101511022567611021133 0ustar frankiefrankie #acs-tcl.lt_Problem_with_your_inp#

    #acs-tcl.We_had# #acs-tcl.some_problems# #acs-tcl.a_problem# #acs-tcl.with_your_input#

    • @complaints.text;noquote@

    #acs-tcl.lt_Please_back_up_using_# #acs-tcl.errors##acs-tcl.error##acs-tcl.lt__and_resubmit_your_en#

    #acs-tcl.Thank_you#

    openacs-5.7.0/packages/acs-tcl/lib/static-progress-bar.adp0000755000175000017500000000164511060243522023232 0ustar frankiefrankie
    #acs-tcl.Percentage_complete# #acs-tcl.Page_current_of_total#
    @percentage_done@ %   0 %

    openacs-5.7.0/packages/acs-tcl/lib/static-progress-bar.tcl0000755000175000017500000000301410622143342023242 0ustar frankiefrankie# packages/acs-tcl/lib/static-progress-bar.tcl # # The OTHER progress-bar.adp is animated. # include this to show a progress bar for an assessment (or other multi-page # flow) # # @author Deds Castillo (deds@i-manila.com.ph) # @creation-date 2004-11-08 # # params: total (int) - number of pages in entire assessment # current (int) - current page being shown # finish (optional,boolean) - if supplied, then this is the final page # bgcolor background color # fontcolor color of text # bgimage URL of background image # # NOTE: shows progress in terms of pages, NOT questions foreach required_param {total current} { if {![info exists $required_param]} { return -code error "$required_param is a required parameter." } } if {![info exists finish]} { set finish 0 } if {![info exists bgcolor]} { set bgcolor "\#aaaaaa" } if {![info exists fontcolor]} { set fontcolor "white" } if {![info exists bgimage]} { set bgimage "/resources/acs-subsite/pb-bg.gif" } if {![info exists header_color]} { set header_color "black" } if { ($total == 0) || [string is true $finish] } { set percentage_done 100 } elseif {[info exists finished_page] && $finished_page == $current} { # subtract 1 from current, since we haven't completed this page yet set percentage_done [expr {round($current * 100.0 / $total)}] } else { # subtract 1 from current, since we haven't completed this page yet set percentage_done [expr {round(($current - 1) * 100.0 / $total)}] } openacs-5.7.0/packages/acs-tcl/tcl/0000755000175000017500000000000011575225566016677 5ustar frankiefrankieopenacs-5.7.0/packages/acs-tcl/tcl/site-node-object-map-procs-postgresql.xql0000644000175000017500000000075007504712423026650 0ustar frankiefrankie postgresql7.1 select site_node_object_map__new(:object_id, :node_id) select site_node_object_map__del(:object_id) openacs-5.7.0/packages/acs-tcl/tcl/xml-1-dom-procs.tcl0000644000175000017500000013443410551254404022235 0ustar frankiefrankiead_library { # dom.tcl -- # # This file implements the Tcl language binding for the DOM - # the Document Object Model. Support for the core specification # is given here. Layered support for specific languages, # such as HTML and XML, will be in separate modules. # # Copyright (c) 1998 Zveno Pty Ltd # http://www.zveno.com/ # # Zveno makes this software available free of charge for any purpose. # Copies may be made of this software but all of this notice must be included # on any copy. # # The software was developed for research purposes only and Zveno does not # warrant that it is error free or fit for any purpose. Zveno disclaims any # liability for all claims, expenses, losses, damages and costs any user may # incur as a result of using, copying or modifying this software. # @cvs-id $Id: xml-1-dom-procs.tcl,v 1.3 2007/01/10 21:22:12 gustafn Exp $ } package provide dom 1.6 namespace eval dom { namespace export DOMImplementation namespace export document documentFragment node namespace export element textNode attribute namespace export processingInstruction } # Data structure # # Documents are stored in an array within the dom namespace. # Each element of the array is indexed by a unique identifier. # Each element of the array is a key-value list with at least # the following fields: # id docArray # node:parentNode node:childNodes node:nodeType # Nodes of a particular type may have additional fields defined. # Note that these fields in many circumstances are configuration options # for a node type. # # "Live" data objects are stored as a separate Tcl variable. # Lists, such as child node lists, are Tcl list variables (ie scalar) # and keyed-value lists, such as attribute lists, are Tcl array # variables. The accessor function returns the variable name, # which the application should treat as a read-only object. # # A token is a FQ array element reference for a node. # dom::GetHandle -- # # Checks that a token is valid and sets an array variable # in the caller to contain the node's fields. # # This is expensive, so it is only used when called by # the application. # # Arguments: # type node type (for future use) # token token passed in # varName variable name in caller to associate with node # # Results: # Variable gets node's fields, otherwise returns error. # Returns empty string. proc dom::GetHandle {type token varName} { if {![info exists $token]} { return -code error "invalid token \"$token\"" } upvar 1 $varName data array set data [set $token] # Type checking not implemented # if {$data(node:nodeType) ne "document" } { # return -code error "node is not of type document" # } return {} } # dom::PutHandle -- # # Writes the values from the working copy of the node's data # into the document's global array. # # NB. Token checks are performed in GetHandle # NB(2). This is still expensive, so is not used. # # Arguments: # token token passed in # varName variable name in caller to associate with node # # Results: # Sets array element for this node to have new values. # Returns empty string. proc dom::PutHandle {token varName} { upvar 1 $varName data set $token [array get data] return {} } # dom::DOMImplementation -- # # Implementation-dependent functions. # Most importantly, this command provides a function to # create a document instance. # # Arguments: # method method to invoke # token token for node # args arguments for method # # Results: # Depends on method used. namespace eval dom { variable DOMImplementationOptions {} variable DOMImplementationCounter 0 } proc dom::DOMImplementation {method args} { variable DOMImplementationOptions variable DOMImplementationCounter switch -- $method { hasFeature { if {[llength $args] != 2} { return -code error "wrong number of arguments" } # Later on, could use Tcl package facility if {[regexp {create|destroy|parse|serialize|trim} [lindex $args 0]]} { if {[lindex $args 1] eq "1.0" } { return 1 } else { return 0 } } else { return 0 } } create { # Bootstrap a document instance switch [llength $args] { 0 { # Allocate unique document array name set name [namespace current]::document[incr DOMImplementationCounter] } 1 { # Use array name provided. Should check that it is safe. set name [lindex $args 0] catch {unset $name} } default { return -code error "wrong number of arguments" } } set varPrefix ${name}var set arrayPrefix ${name}arr array set $name [list counter 1 \ node1 [list id node1 docArray $name \ node:nodeType documentFragment \ node:parentNode {} \ node:childNodes ${varPrefix}1 \ documentFragment:masterDoc node1 \ document:implementation {} \ document:xmldecl {version 1.0} \ document:documentElement {} \ document:doctype {} \ ]] # Initialise child node list set ${varPrefix}1 {} # Return the new toplevel node return ${name}(node1) } destroy { # Cleanup a document if {[llength $args] != 1} { return -code error "wrong number of arguments" } array set node [set [lindex $args 0]] # Patch from Gerald Lester ## ## First release all the associated variables ## upvar #0 $node(docArray) docArray for {set i 0} {$i < $docArray(counter)} {incr i} { catch {unset ${docArrayName}var$i} catch {unset ${docArrayName}arr$i} } ## ## Then release the main document array ## if {[catch {unset $node(docArray)}]} { return -code error "unable to destroy document" } return {} } parse { # This implementation allows use of either of two event-based, # non-validating XML parsers: # . TclXML Tcl-only parser (version 1.3 or higher) # . TclExpat parser array set opts {-parser {} -progresscommand {} -chunksize 8196} if {[catch {array set opts [lrange $args 1 end]}]} { return -code error "bad configuration options" } # Create a state array for this parse session set state [namespace current]::parse[incr DOMImplementationCounter] array set $state [array get opts -*] array set $state [list progCounter 0] set errorCleanup {} switch -- $opts(-parser) { expat { if {[catch {package require expat} version]} { eval $errorCleanup return -code error "expat extension is not available" } set parser [expat [namespace current]::xmlparser] } tcl { if {[catch {package require xml 1.3} version]} { eval $errorCleanup return -code error "XML parser package is not available" } set parser [::xml::parser xmlparser] } default { # Automatically determine which parser to use if {[catch {package require expat} version]} { if {[catch {package require xml 1.3} version]} { eval $errorCleanup return -code error "unable to load XML parser" } else { set parser [::xml::parser xmlparser] } } else { set parser [expat [namespace current]::xmlparser] } } } $parser configure \ -elementstartcommand [namespace code [list ParseElementStart $state]] \ -elementendcommand [namespace code [list ParseElementEnd $state]] \ -characterdatacommand [namespace code [list ParseCharacterData $state]] \ -processinginstructioncommand [namespace code [list ParseProcessingInstruction $state]] \ -final true # TclXML has features missing from expat catch { $parser configure \ -xmldeclcommand [namespace code [list ParseXMLDeclaration $state]] \ -doctypecommand [namespace code [list ParseDocType $state]] } # Create top-level document array set $state [list docNode [DOMImplementation create]] array set $state [list current [lindex [array get $state docNode] 1]] # Parse data # Bug in TclExpat - doesn't handle non-final inputs if {0 && [string length $opts(-progresscommand)]} { $parser configure -final false while {[string length [lindex $args 0]]} { $parser parse [string range [lindex $args 0] 0 $opts(-chunksize)] set args [lreplace $args 0 0 \ [string range [lindex $args 0] $opts(-chunksize) end]] uplevel #0 $opts(-progresscommand) } $parser configure -final true } elseif {[catch {$parser parse [lindex $args 0]} err]} { catch {rename $parser {}} catch {unset $state} return -code error $err } # Free data structures which are no longer required catch {rename $parser {}} set doc [lindex [array get $state docNode] 1] unset $state return $doc } serialize { if {[llength $args] < 1} { return -code error "wrong number of arguments" } GetHandle documentFragment [lindex $args 0] node return [eval [list Serialize:$node(node:nodeType)] $args] } trim { # Removes textNodes that only contain white space if {[llength $args] != 1} { return -code error "wrong number of arguments" } Trim [lindex $args 0] return {} } default { return -code error "unknown method \"$method\"" } } return {} } # dom::document -- # # Functions for a document node. # # Arguments: # method method to invoke # token token for node # args arguments for method # # Results: # Depends on method used. namespace eval dom { variable documentOptionsRO doctype|implementation|documentElement variable documentOptionsRW {} } proc dom::document {method token args} { variable documentOptionsRO variable documentOptionsRW # GetHandle also checks token GetHandle document $token node set result {} switch -- $method { cget { if {[llength $args] != 1} { return -code error "too many arguments" } if {[regexp [format {^-(%s)$} $documentOptionsRO] [lindex $args 0] discard option]} { return $node(document:$option) } elseif {[regexp [format {^-(%s)$} $documentOptionsRW] [lindex $args 0] discard option]} { return $node(document:$option) } else { return -code error "unknown option \"[lindex $args 0]\"" } } configure { if {[llength $args] == 1} { return [document cget $token [lindex $args 0]] } elseif {[expr {[llength $args] % 2}]} { return -code error "no value specified for option \"[lindex $args end]\"" } else { foreach {option value} $args { if {[regexp [format {^-(%s)$} $documentOptionsRW] $option discard opt]} { set node(document:$opt) $value } elseif {[regexp [format {^-(%s)$} $documentOptionsRO] $option discard opt]} { return -code error "attribute \"$option\" is read-only" } else { return -code error "unknown option \"$option\"" } } } PutHandle $token node } createElement { if {[llength $args] != 1} { return -code error "wrong number of arguments" } # Check that the element name is kosher # BUG: The definition of 'Letter' here as ASCII letters # is not sufficient. Also, CombiningChar and Extenders # must be added. if {![regexp {^[A-Za-z_:][-A-Za-z0-9._:]*$} [lindex $args 0]]} { return -code error "invalid element name \"[lindex $args 0]\"" } # Invoke internal factory function set result [CreateElement $token [lindex $args 0] {}] } createDocumentFragment { if {[llength $args]} { return -code error "wrong number of arguments" } set result [CreateGeneric $token node:nodeType documentFragment] } createTextNode { if {[llength $args] != 1} { return -code error "wrong number of arguments" } set result [CreateTextNode $token [lindex $args 0]] } createComment { if {[llength $args] != 1} { return -code error "wrong number of arguments" } set result [CreateGeneric $token node:nodeType comment node:nodeValue [lindex $args 0]] } createCDATASection { if {[llength $args] != 1} { return -code error "wrong number of arguments" } set result [CreateGeneric $token node:nodeType CDATASection node:nodeValue [lindex $args 0]] } createProcessingInstruction { if {[llength $args] != 2} { return -code error "wrong number of arguments" } set result [CreateGeneric $token node:nodeType processingInstruction \ node:nodeName [lindex $args 0] node:nodeValue [lindex $args 1]] } createAttribute { if {[llength $args] != 1} { return -code error "wrong number of arguments" } set result [CreateGeneric $token node:nodeType attribute node:nodeName [lindex $args 0]] } createEntity { set result [CreateGeneric $token node:nodeType entity] } createEntityReference { set result [CreateGeneric $token node:nodeType entityReference] } createDocTypeDecl { # This is not a standard DOM 1.0 method if {[llength $args] < 1 || [llength $args] > 5} { return -code error "wrong number of arguments" } foreach {name extid dtd entities notations} $args break set result [CreateDocType $token $name $extid $dtd $entities $notations] } getElementsByTagName { if {[llength $args] != 1} { return -code error "wrong number of arguments" } return [Element:GetByTagName $token [lindex $args 0]] } default { return -code error "unknown method \"$method\"" } } return $result } ### Factory methods ### ### These are lean-and-mean for fastest possible tree building # dom::CreateElement -- # # Append an element to the given (parent) node (if any) # # Arguments: # token parent node # name element name (no checking performed here) # aList attribute list # args configuration options # # Results: # New node created, parent optionally modified proc dom::CreateElement {token name aList args} { if {[string length $token]} { array set parent [set $token] upvar #0 $parent(docArray) docArray set docArrayName $parent(docArray) } else { array set opts $args upvar #0 $opts(-docarray) docArray set docArrayName $opts(-docarray) } set id node[incr docArray(counter)] set child ${docArrayName}($id) # Create the new node # NB. normally we'd use Node:create here, # but inline it instead for performance set docArray($id) [list id $id docArray $docArrayName \ node:parentNode $token \ node:childNodes ${docArrayName}var$docArray(counter) \ node:nodeType element \ node:nodeName $name \ node:nodeValue {} \ element:attributeList ${docArrayName}arr$docArray(counter) \ ] # Initialise associated variables set ${docArrayName}var$docArray(counter) {} array set ${docArrayName}arr$docArray(counter) $aList # Update parent record # Does this element qualify as the document element? # If so, then has a document element already been set? if {[string length $token]} { if {$parent(node:nodeType) eq "documentFragment" } { if {$parent(id) == $parent(documentFragment:masterDoc)} { if {[info exists parent(document:documentElement)] && \ [string length $parent(document:documentElement)]} { unset docArray($id) return -code error "document element already exists" } else { # Check against document type decl if {[string length $parent(document:doctype)]} { array set doctypedecl [set $parent(document:doctype)] if {$name ne $doctypedecl(doctype:name) } { return -code error "mismatch between root element type in document type declaration \"$doctypedecl(doctype:name)\" and root element \"$name\"" } } else { # Synthesize document type declaration CreateDocType $token $name {} {} # Resynchronise parent record array set parent [set $token] } set parent(document:documentElement) $child set $token [array get parent] } } } lappend $parent(node:childNodes) $child } return $child } # dom::CreateTextNode -- # # Append a textNode node to the given (parent) node (if any). # # This factory function can also be performed by # CreateGeneric, but text nodes are created so often # that this specific factory procedure speeds things up. # # Arguments: # token parent node # text initial text # args additional configuration options # # Results: # New node created, parent optionally modified proc dom::CreateTextNode {token text args} { if {[string length $token]} { array set parent [set $token] upvar #0 $parent(docArray) docArray set docArrayName $parent(docArray) } else { array set opts $args upvar #0 $opts(-docarray) docArray set docArrayName $opts(-docarray) } set id node[incr docArray(counter)] set child ${docArrayName}($id) # Create the new node # NB. normally we'd use Node:create here, # but inline it instead for performance # Text nodes never have children, so don't create a variable set docArray($id) [list id $id docArray $docArrayName \ node:parentNode $token \ node:childNodes {} \ node:nodeType textNode \ node:nodeValue $text \ ] if {[string length $token]} { # Update parent record lappend $parent(node:childNodes) $child set $token [array get parent] } return $child } # dom::CreateGeneric -- # # This is a template used for type-specific factory procedures # # Arguments: # token parent node # args optional values # # Results: # New node created, parent modified proc dom::CreateGeneric {token args} { if {[string length $token]} { array set parent [set $token] upvar #0 $parent(docArray) docArray set docArrayName $parent(docArray) } else { array set opts $args upvar #0 $opts(-docarray) docArray set docArrayName $opts(-docarray) array set tmp [array get opts] foreach opt [array names tmp -*] { unset tmp($opt) } set args [array get tmp] } set id node[incr docArray(counter)] set child ${docArrayName}($id) # Create the new node # NB. normally we'd use Node:create here, # but inline it instead for performance set docArray($id) [eval list [list id $id docArray $docArrayName \ node:parentNode $token \ node:childNodes ${docArrayName}var$docArray(counter)] \ $args ] set ${docArrayName}var$docArray(counter) {} if {[string length $token]} { # Update parent record lappend $parent(node:childNodes) $child set $token [array get parent] } return $child } ### Specials # dom::CreateDocType -- # # Create a Document Type Declaration node. # # Arguments: # token node id for the document node # name root element type # extid external entity id # dtd internal DTD subset # # Results: # Returns node id of the newly created node. proc dom::CreateDocType {token name {extid {}} {dtd {}} {entities {}} {notations {}}} { array set doc [set $token] upvar #0 $doc(docArray) docArray set id node[incr docArray(counter)] set child $doc(docArray)($id) set docArray($id) [list \ id $id docArray $doc(docArray) \ node:parentNode $token \ node:childNodes {} \ node:nodeType docType \ node:nodeName {} \ node:nodeValue {} \ doctype:name $name \ doctype:entities {} \ doctype:notations {} \ doctype:externalid $extid \ doctype:internaldtd $dtd \ ] # NB. externalid and internaldtd are not standard DOM 1.0 attributes # Update parent set doc(document:doctype) $child # Add this node to the parent's child list # This must come before the document element, # so this implementation may be buggy lappend $doc(node:childNodes) $child set $token [array get doc] return $child } # dom::node -- # # Functions for a general node. # # Arguments: # method method to invoke # token token for node # args arguments for method # # Results: # Depends on method used. namespace eval dom { variable nodeOptionsRO nodeName|nodeType|parentNode|childNodes|firstChild|lastChild|previousSibling|nextSibling|attributes variable nodeOptionsRW nodeValue } proc dom::node {method token args} { variable nodeOptionsRO variable nodeOptionsRW GetHandle node $token node set result {} switch -glob -- $method { cg* { # cget # Some read-only configuration options are computed if {[llength $args] != 1} { return -code error "too many arguments" } if {[regexp [format {^-(%s)$} $nodeOptionsRO] [lindex $args 0] discard option]} { switch $option { childNodes { # How are we going to handle documentElement? set result $node(node:childNodes) } firstChild { upvar #0 $node(node:childNodes) children switch $node(node:nodeType) { documentFragment { set result [lindex $children 0] catch {set result $node(document:documentElement)} } default { set result [lindex $children 0] } } } lastChild { upvar #0 $node(node:childNodes) children switch $node(node:nodeType) { documentFragment { set result [lindex $children end] catch {set result $node(document:documentElement)} } default { set result [lindex $children end] } } } previousSibling { # BUG: must take documentElement into account # Find the parent node GetHandle node $node(node:parentNode) parent upvar #0 $parent(node:childNodes) children set idx [lsearch $children $token] if {$idx >= 0} { set sib [lindex $children [incr idx -1]] if {[llength $sib]} { set result $sib } else { set result {} } } else { set result {} } } nextSibling { # BUG: must take documentElement into account # Find the parent node GetHandle node $node(node:parentNode) parent upvar #0 $parent(node:childNodes) children set idx [lsearch $children $token] if {$idx >= 0} { set sib [lindex $children [incr idx]] if {[llength $sib]} { set result $sib } else { set result {} } } else { set result {} } } attributes { if {$node(node:nodeType) ne "element" } { set result {} } else { set result $node(element:attributeList) } } default { return [GetField node(node:$option)] } } } elseif {[regexp [format {^-(%s)$} $nodeOptionsRW] [lindex $args 0] discard option]} { return [GetField node(node:$option)] } else { return -code error "unknown option \"[lindex $args 0]\"" } } co* { # configure if {[llength $args] == 1} { return [document cget $token [lindex $args 0]] } elseif {[expr {[llength $args] % 2}]} { return -code error "no value specified for option \"[lindex $args end]\"" } else { foreach {option value} $args { if {[regexp [format {^-(%s)$} $nodeOptionsRW] $option discard opt]} { set node(node:$opt) $value } elseif {[regexp [format {^-(%s)$} $nodeOptionsRO] $option discard opt]} { return -code error "attribute \"$option\" is read-only" } else { return -code error "unknown option \"$option\"" } } } } in* { # insertBefore # Previous and next sibling relationships are OK, # because they are dynamically determined if {[llength $args] < 1 || [llength $args] > 2} { return -code error "wrong number of arguments" } GetHandle node [lindex $args 0] newChild if {$newChild(docArray) ne $node(docArray) } { return -code error "new node must be in the same document" } switch [llength $args] { 1 { # Append as the last node if {[string length $newChild(node:parentNode)]} { node removeChild $newChild(node:parentNode) [lindex $args 0] } lappend $node(node:childNodes) [lindex $args 0] set newChild(node:parentNode) $token } 2 { GetHandle node [lindex $args 1] refChild if {$refChild(docArray) ne $newChild(docArray) } { return -code error "nodes must be in the same document" } set idx [lsearch [set $node(node:childNodes)] [lindex $args 1]] if {$idx < 0} { return -code error "no such reference child" } else { # Remove from previous parent if {[string length $newChild(node:parentNode)]} { node removeChild $newChild(node:parentNode) [lindex $args 0] } # Insert into new node set $node(node:childNodes) \ [linsert [set $node(node:childNodes)] $idx [lindex $args 0]] set newChild(node:parentNode) $token } } } PutHandle [lindex $args 0] newChild } rep* { # replaceChild if {[llength $args] != 2} { return -code error "wrong number of arguments" } GetHandle node [lindex $args 0] newChild GetHandle node [lindex $args 1] oldChild # Find where to insert new child set idx [lsearch [set $node(node:childNodes)] [lindex $args 1]] if {$idx < 0} { return -code error "no such old child" } # Remove new child from current parent if {[string length $newChild(node:parentNode)]} { node removeChild $newChild(node:parentNode) [lindex $args 0] } set $node(node:childNodes) \ [lreplace [set $node(node:childNodes)] $idx $idx [lindex $args 0]] set newChild(node:parentNode) $token # Update old child to reflect lack of parentage set oldChild(node:parentNode) {} PutHandle [lindex $args 1] oldChild PutHandle [lindex $args 0] newChild set result [lindex $args 0] } rem* { # removeChild if {[llength $args] != 1} { return -code error "wrong number of arguments" } array set oldChild [set [lindex $args 0]] if {$oldChild(docArray) != $node(docArray)} { return -code error "node \"[lindex $args 0]\" is not a child" } # Remove the child from the parent upvar #0 $node(node:childNodes) myChildren if {[set idx [lsearch $myChildren [lindex $args 0]]] < 0} { return -code error "node \"[lindex $args 0]\" is not a child" } set myChildren [lreplace $myChildren $idx $idx] # Update the child to reflect lack of parentage set oldChild(node:parentNode) {} set [lindex $args 0] [array get oldChild] set result [lindex $args 0] } ap* { # appendChild if {[llength $args] != 1} { return -code error "wrong number of arguments" } # Add to new parent node insertBefore $token [lindex $args 0] } hasChildNodes { set result [Min 1 [llength [set $node(node:childNodes)]]] } cl* { # cloneNode set deep 0 switch [llength $args] { 0 { } 1 { set deep [Boolean [lindex $args 0]] } default { return -code error "too many arguments" } } switch $node(node:nodeType) { element { set result [CreateElement {} $node(node:nodeName) [array get $node(element:attributeList)] -docarray $node(docArray)] if {$deep} { foreach child [set $node(node:childNodes)] { node appendChild $result [node cloneNode $child] } } } textNode { set result [CreateTextNode {} $node(node:nodeValue) -docarray $node(docArray)] } document - documentFragment - default { set result [CreateGeneric {} node:nodeType $node(node:nodeType) -docarray $node(docArray)] if {$deep} { foreach child [set $node(node:childNodes)] { node appendChild $result [node cloneNode $child] } } } } } ch* { # children -- non-standard method # If this is a textNode, then catch the error set result {} catch {set result [set $node(node:childNodes)]} } pa* { # parent -- non-standard method return $node(node:parentNode) } default { return -code error "unknown method \"$method\"" } } PutHandle $token node return $result } # dom::Node:create -- # # Generic node creation. # See also CreateElement, CreateTextNode, CreateGeneric. # # Arguments: # pVar array in caller which contains parent details # args configuration options # # Results: # New child node created. proc dom::Node:create {pVar args} { upvar $pVar parent array set opts {-name {} -value {}} array set opts $args upvar #0 $parent(docArray) docArray # Create new node if {![info exists opts(-id)]} { set opts(-id) node[incr docArray(counter)] } set docArray($opts(-id)) [list id $opts(-id) \ docArray $parent(docArray) \ node:parentNode $opts(-parent) \ node:childNodes $parent(docArray)var$docArray(counter) \ node:nodeType $opts(-type) \ node:nodeName $opts(-name) \ node:nodeValue $opts(-value) \ element:attributeList $parent(docArray)arr$docArray(counter) \ ] set $parent(docArray)var$docArray(counter) {} array set $parent(docArray)arr$docArray(counter) {} # Update parent node if {![info exists parent(document:documentElement)]} { lappend parent(node:childNodes) [list [lindex $opts(-parent) 0] $opts(-id)] } return $parent(docArray)($opts(-id)) } # dom::Node:set -- # # Generic node update # # Arguments: # token node token # args configuration options # # Results: # Node modified. proc dom::Node:set {token args} { upvar $token node foreach {key value} $args { set node($key) $value } set $token [array get node] return {} } # dom::element -- # # Functions for an element. # # Arguments: # method method to invoke # token token for node # args arguments for method # # Results: # Depends on method used. namespace eval dom { variable elementOptionsRO {tagName empty} variable elementOptionsRW {} } proc dom::element {method token args} { variable elementOptionsRO variable elementOptionsRW GetHandle node $token node set result {} switch -- $method { cget { # Some read-only configuration options are computed if {[llength $args] != 1} { return -code error "too many arguments" } if {[regexp [format {^-(%s)$} $elementOptionsRO] [lindex $args 0] discard option]} { switch $option { tagName { set result [lindex $node(node:nodeName) 0] } empty { if {![info exists node(element:empty)]} { return 0 } else { return $node(element:empty) } } default { return $node(node:$option) } } } elseif {[regexp [format {^-(%s)$} $elementOptionsRW] [lindex $args 0] discard option]} { return $node(node:$option) } else { return -code error "unknown option \"[lindex $args 0]\"" } } configure { if {[llength $args] == 1} { return [document cget $token [lindex $args 0]] } elseif {[expr {[llength $args] % 2}]} { return -code error "no value specified for option \"[lindex $args end]\"" } else { foreach {option value} $args { if {[regexp [format {^-(%s)$} $elementOptionsRO] $option discard opt]} { return -code error "attribute \"$option\" is read-only" } elseif {[regexp [format {^-(%s)$} $elementOptionsRW] $option discard opt]} { return -code error "not implemented" } else { return -code error "unknown option \"$option\"" } } } } getAttribute { if {[llength $args] != 1} { return -code error "wrong number of arguments" } upvar #0 $node(element:attributeList) attrList catch {set result $attrList([lindex $args 0])} } setAttribute { if {[llength $args] == 0 || [llength $args] > 2} { return -code error "wrong number of arguments" } # TODO: Check that the attribute name is legal upvar #0 $node(element:attributeList) attrList set attrList([lindex $args 0]) [lindex $args 1] } removeAttribute { if {[llength $args] != 1} { return -code error "wrong number of arguments" } upvar #0 $node(element:attributeList) attrList catch {unset attrList([lindex $args 0])} } getAttributeNode { } setAttributeNode { } removeAttributeNode { } getElementsByTagName { if {[llength $args] != 1} { return -code error "wrong number of arguments" } return [Element:GetByTagName $token [lindex $args 0]] } normalize { if {[llength $args]} { return -code error "wrong number of arguments" } Element:Normalize node [set $node(node:childNodes)] } default { return -code error "unknown method \"$method\"" } } PutHandle $token node return $result } # Element:GetByTagName -- # # Search for (child) elements # NB. This does not descend the hierarchy. Check the DOM spec. # # Arguments: # token parent node # name (child) elements to search for # # Results: # List of matching node tokens proc dom::Element:GetByTagName {token name} { array set node [set $token] set result {} if {$node(node:nodeType) ne "documentFragment" } { foreach child [set $node(node:childNodes)] { catch {unset childNode} array set childNode [set $child] if {$childNode(node:nodeType) eq "element" && \ [GetField childNode(node:nodeName)] eq $name } { lappend result $child } } } elseif {[llength $node(document:documentElement)]} { # Document Element must exist and must be an element type node catch {unset childNode} array set childNode [set $node(document:documentElement)] if {$childNode(node:nodeName) eq $name } { set result $node(document:documentElement) } } return $result } # Element:Normalize -- # # Normalize the text nodes # # Arguments: # pVar parent array variable in caller # nodes list of node tokens # # Results: # Adjacent text nodes are coalesced proc dom::Element:Normalize {pVar nodes} { upvar $pVar parent set textNode {} foreach n $nodes { GetHandle node $n child set cleanup {} switch $child(node:nodeType) { textNode { if {[llength $textNode]} { # Coalesce into previous node append text(node:nodeValue) $child(node:nodeValue) # Remove this child upvar #0 $parent(node:childNodes) childNodes set idx [lsearch $childNodes $n] set childNodes [lreplace $childNodes $idx $idx] unset $n set cleanup {} PutHandle $textNode text } else { set textNode $n catch {unset text} array set text [array get child] } } element - document - documentFragment { set textNode {} Element:Normalize child [set $child(node:childNodes)] } default { set textNode {} } } eval $cleanup } return {} } # dom::processinginstruction -- # # Functions for a processing intruction. # # Arguments: # method method to invoke # token token for node # args arguments for method # # Results: # Depends on method used. namespace eval dom { variable piOptionsRO target variable piOptionsRW data } proc dom::processinginstruction {method token args} { variable piOptionsRO variable piOptionsRW GetHandle node $token node set result {} switch -- $method { cget { # Some read-only configuration options are computed if {[llength $args] != 1} { return -code error "too many arguments" } if {[regexp [format {^-(%s)$} $elementOptionsRO] [lindex $args 0] discard option]} { switch $option { target { set result [lindex $node(node:nodeName) 0] } default { return $node(node:$option) } } } elseif {[regexp [format {^-(%s)$} $elementOptionsRW] [lindex $args 0] discard option]} { switch $option { data { return $node(node:nodeValue) } default { return $node(node:$option) } } } else { return -code error "unknown option \"[lindex $args 0]\"" } } configure { if {[llength $args] == 1} { return [document cget $token [lindex $args 0]] } elseif {[expr {[llength $args] % 2}]} { return -code error "no value specified for option \"[lindex $args end]\"" } else { foreach {option value} $args { if {[regexp [format {^-(%s)$} $elementOptionsRO] $option discard opt]} { return -code error "attribute \"$option\" is read-only" } elseif {[regexp [format {^-(%s)$} $elementOptionsRW] $option discard opt]} { switch $opt { data { set node(node:nodeValue) $value } default { set node(node:$opt) $value } } } else { return -code error "unknown option \"$option\"" } } } } default { return -code error "unknown method \"$method\"" } } PutHandle $token node return $result } ################################################# # # Serialisation # ################################################# # dom::Serialize:documentFragment -- # # Produce text for documentFragment. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:documentFragment {token args} { array set node [set $token] if {"node1" ne $node(documentFragment:masterDoc) } { return [eval [list Serialize:node $token] $args] } else { if {{} ne [GetField node(document:documentElement)] } { return [eval Serialize:document [list $token] $args] } else { return -code error "document has no document element" } } } # dom::Serialize:document -- # # Produce text for document. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:document {token args} { array set node [set $token] if {![info exists node(document:documentElement)]} { return -code error "document has no document element" } elseif {![string length $node(document:doctype)]} { return -code error "no document type declaration given" } else { array set doctype [set $node(document:doctype)] # BUG: Want to serialize all children except for the # document element, and then do the document element. # Bug fix: can't use Serialize:attributeList for XML declaration, # since attributes must occur in a given order (XML 2.8 [23]) return "\n\n[eval Serialize:element [list $node(document:documentElement)] $args]" } } # dom::Serialize:ExternalID -- # # Returned appropriately quoted external identifiers # # Arguments: # id external indentifiers # # Results: # text proc dom::Serialize:ExternalID id { set result {} foreach ident $id { append result { } \"$ident\" } return $result } # dom::Serialize:XMLDecl -- # # Produce text for an arbitrary node. # This simply serializes the child nodes of the node. # # Arguments: # attr required attribute # attList attribute list # # Results: # XML format text. proc dom::Serialize:XMLDecl {attr attrList} { array set data $attrList if {![info exists data($attr)]} { return {} } elseif {[string length $data($attr)]} { return " $attr='$data($attr)'" } else { return {} } } # dom::Serialize:node -- # # Produce text for an arbitrary node. # This simply serializes the child nodes of the node. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:node {token args} { array set node [set $token] set result {} foreach childToken [set $node(node:childNodes)] { catch {unset child} array set child [set $childToken] append result [eval [list Serialize:$child(node:nodeType) $childToken] $args] } return $result } # dom::Serialize:element -- # # Produce text for an element. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:element {token args} { array set node [set $token] array set opts {-newline {}} array set opts $args set result {} set newline {} if {[lsearch $opts(-newline) $node(node:nodeName)] >= 0} { append result \n set newline \n } append result "<$node(node:nodeName)" append result [Serialize:attributeList [array get $node(element:attributeList)]] if {![llength [set $node(node:childNodes)]]} { append result />$newline } else { append result >$newline # Do the children append result [eval Serialize:node [list $token] $args] append result "$newline$newline" } return $result } # dom::Serialize:textNode -- # # Produce text for a text node. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:textNode {token args} { array set node [set $token] return [Encode $node(node:nodeValue)] } # dom::Serialize:processingInstruction -- # # Produce text for a PI node. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:processingInstruction {token args} { array set node [set $token] return "<$node(node:nodeName) $node(node:nodeValue)>" } # dom::Serialize:comment -- # # Produce text for a comment node. # # Arguments: # token node token # args configuration options # # Results: # XML format text. proc dom::Serialize:comment {token args} { array set node [set $token] return } # dom::Encode -- # # Encode special characters # # Arguments: # value text value # # Results: # XML format text. proc dom::Encode value { array set Entity { $ $ < < > > & & \" " ' ' } regsub -all {([$<>&"'])} $value {$Entity(\1)} value return [subst -nocommand -nobackslash $value] } # dom::Serialize:attributeList -- # # Produce text for an attribute list. # # Arguments: # l name/value paired list # # Results: # XML format text. proc dom::Serialize:attributeList {l} { set result {} foreach {name value} $l { append result { } $name = # Handle special characters regsub -all < $value {\<} value if {![string match *\"* $value]} { append result \"$value\" } elseif {![string match *'* $value]} { append result '$value' } else { regsub -all \" $value {\"} value append result \"$value\" } } return $result } ################################################# # # Parsing # ################################################# # ParseElementStart -- # # Push a new element onto the stack. # # Arguments: # stateVar global state array variable # name element name # attrList attribute list # args configuration options # # Results: # An element is created within the currently open element. proc dom::ParseElementStart {stateVar name attrList args} { upvar #0 $stateVar state array set opts $args lappend state(current) \ [CreateElement [lindex $state(current) end] $name $attrList] if {[info exists opts(-empty)] && $opts(-empty)} { # Flag this node as being an empty element array set node [set [lindex $state(current) end]] set node(element:empty) 1 set [lindex $state(current) end] [array get node] } # Temporary: implement -progresscommand here, because of broken parser if {[string length $state(-progresscommand)]} { if {!([incr state(progCounter)] % $state(-chunksize))} { uplevel #0 $state(-progresscommand) } } } # ParseElementEnd -- # # Pop an element from the stack. # # Arguments: # stateVar global state array variable # name element name # args configuration options # # Results: # Currently open element is closed. proc dom::ParseElementEnd {stateVar name args} { upvar #0 $stateVar state set state(current) [lreplace $state(current) end end] } # ParseCharacterData -- # # Add a textNode to the currently open element. # # Arguments: # stateVar global state array variable # data character data # # Results: # A textNode is created. proc dom::ParseCharacterData {stateVar data} { upvar #0 $stateVar state CreateTextNode [lindex $state(current) end] $data } # ParseProcessingInstruction -- # # Add a PI to the currently open element. # # Arguments: # stateVar global state array variable # name PI name # target PI target # # Results: # A processingInstruction node is created. proc dom::ParseProcessingInstruction {stateVar name target} { upvar #0 $stateVar state CreateGeneric [lindex $state(current) end] node:nodeType processingInstruction node:nodeName $name node:nodeValue $target } # ParseXMLDeclaration -- # # Add information from the XML Declaration to the document. # # Arguments: # stateVar global state array variable # version version identifier # encoding character encoding # standalone standalone document declaration # # Results: # Document node modified. proc dom::ParseXMLDeclaration {stateVar version encoding standalone} { upvar #0 $stateVar state array set node [set $state(docNode)] array set xmldecl $node(document:xmldecl) array set xmldecl [list version $version \ standalone $standalone \ encoding $encoding \ ] set node(document:xmldecl) [array get xmldecl] set $state(docNode) [array get node] return {} } # ParseDocType -- # # Add a Document Type Declaration node to the document. # # Arguments: # stateVar global state array variable # root root element type # publit public identifier literal # systemlist system identifier literal # dtd internal DTD subset # # Results: # DocType node added proc dom::ParseDocType {stateVar root {publit {}} {systemlit {}} {dtd {}}} { upvar #0 $stateVar state CreateDocType $state(docNode) $root [list $publit $systemlit] $dtd {} {} # Last two are entities and notaions (as namedNodeMap's) return {} } ################################################# # # Trim white space # ################################################# # dom::Trim -- # # Remove textNodes that only contain white space # # Arguments: # nodeid node to trim # # Results: # textNode nodes may be removed (from descendants) proc dom::Trim nodeid { array set node [set $nodeid] switch $node(node:nodeType) { textNode { if {![string length [string trim $node(node:nodeValue)]]} { node removeChild $node(node:parentNode) $nodeid } } default { foreach child [set $node(node:childNodes)] { Trim $child } } } return {} } ################################################# # # Miscellaneous # ################################################# # GetField -- # # Return a value, or empty string if not defined # # Arguments: # var name of variable to return # # Results: # Returns the value, or empty string if variable is not defined. proc GetField var { upvar $var v return [expr {[info exists v] ? $v : {}}] } # dom::Min -- # # Return the minimum of two numeric values # # Arguments: # a a value # b another value # # Results: # Returns the value which is lower than the other. proc dom::Min {a b} { return [expr {$a < $b ? $a : $b}] } # dom::Max -- # # Return the maximum of two numeric values # # Arguments: # a a value # b another value # # Results: # Returns the value which is greater than the other. proc dom::Max {a b} { return [expr {$a > $b ? $a : $b}] } # dom::Boolean -- # # Return a boolean value # # Arguments: # b value # # Results: # Returns 0 or 1 proc dom::Boolean b { regsub -nocase {^(true|yes|1|on)$} $b 1 b regsub -nocase {^(false|no|0|off)$} $b 0 b return $b } openacs-5.7.0/packages/acs-tcl/tcl/test/0000755000175000017500000000000011724401447017644 5ustar frankiefrankieopenacs-5.7.0/packages/acs-tcl/tcl/test/test-set-cookie-procs.tcl0000644000175000017500000000374710467437145024535 0ustar frankiefrankie#/packages/acs-tcl/tcl/test ad_library { Test Case for set_cookie procs @author Cesar Hernandez (cesarhj@galileo.edu) @creation-date 2006-08-10 @arch-tag: 0AA7362F-83FF-4067-B391-A2F8D6918F3E @cvs-id $Id: test-set-cookie-procs.tcl,v 1.1 2006/08/12 20:47:33 cesarh Exp $ } aa_register_case \ -cats {web smoke} \ -libraries tclwebtest \ test_set_cookie_procs \ { Test Case for testing if a cookie is fixed } { #----------------------------------------------------------------------------- #Set values for default #----------------------------------------------------------------------------- set data [ad_generate_random_string] aa_log "The content of the cookie is: $data" aa_run_with_teardown -test_code { #------------------------------------------------------------------------- #set the cookie #------------------------------------------------------------------------- ad_set_cookie "test_cookie_test_case" "$data" #------------------------------------------------------------------------- #Get the cookie and we try if exist #------------------------------------------------------------------------- set cookie_info_p [ad_get_cookie -include_set_cookies t test_cookie_test_case "" ] aa_true "Check if the cookie exist" [string equal $cookie_info_p $data] #------------------------------------------------------------------------- #clearing the cookie #------------------------------------------------------------------------- ad_set_cookie -replace t -max_age 0 test_cookie_test_case "" set cookie_info_d [ad_get_cookie -include_set_cookies t test_cookie_test_case ""] #------------------------------------------------------------------------- #Check if the cookie was cleared #------------------------------------------------------------------------- aa_false "Check if the cookie was cleared" [string equal $cookie_info_d $data] } -teardown_code { } } openacs-5.7.0/packages/acs-tcl/tcl/test/openacs-kernel-procs.tcl0000644000175000017500000000512310466675474024422 0ustar frankiefrankiead_library { Tests for additional utilities. @creation-date 03 August 2006 } aa_register_case -cats {api smoke} -procs {oacs_util::csv_foreach} csv_foreach { Test block execution for rows in a csv file. } { aa_run_with_teardown -test_code { # Create cvs file set file_loc "/tmp/test.csv" set file_id [open $file_loc w] puts $file_id "first_name,last_name,instrument" puts $file_id "Charles,Mingus,Bass" puts $file_id "Miles,Davis,Trumpet" puts $file_id "Jhon,Coltrane,Saxo" puts $file_id "Charlie,Parker,Saxo" puts $file_id "Thelonius,Monk,Piano" close $file_id set csv_data "\nfirst_name,last_name,instrument\nCharles,Mingus,Bass\nMiles,Davis,Trumpet\nJhon,Coltrane,Saxo\nCharlie,Parker,Saxo\nThelonius,Monk,Piano" aa_log "CSV file created with artists data:\n $csv_data" set artist_list {} oacs_util::csv_foreach -file $file_loc -array_name row\ { lappend artist_list "$row(first_name) $row(last_name) - $row(instrument)" } aa_equals "Getting artists from csv file" $artist_list {{Charles Mingus - Bass}\ {Miles Davis - Trumpet}\ {Jhon Coltrane - Saxo}\ {Charlie Parker - Saxo}\ {Thelonius Monk - Piano}} } -teardown_code { file delete -force $file_loc } } aa_register_case -cats {api smoke} -procs {oacs_util::process_objects_csv} process_objects_csv { Test object creation for every row in a csv file. } { aa_run_with_teardown -rollback -test_code { # Create cvs file of persons set file_loc "/tmp/test.csv" set file_id [open $file_loc w] puts $file_id "email,first_names,last_name" puts $file_id "cmingus@foo.bar,Charles,Mingus" puts $file_id "mdavis@foo.bar,Miles,Davis" puts $file_id "cparker@foo.bar,Charlie,Parker" close $file_id set csv_data "\nemail,first_names,last_name\ncmingus@foo.bar,Charles,Mingus\nmdavis@foo.bar,Miles,Davis\ncparker@foo.bar,Charlie,Parker" aa_log "CSV file for \"person\" objects creation with data:\n $csv_data" set person_ids [oacs_util::process_objects_csv -object_type "person" -file $file_loc] aa_log "Persons id's created: $person_ids" set person_list {} foreach person_id $person_ids { array set person_array [person::get -person_id $person_id] lappend person_list "$person_array(first_names) $person_array(last_name)" } aa_equals "Getting persons from database table \"persons\"" $person_list {{Charles Mingus}\ {Miles Davis}\ {Charlie Parker}} } -teardown_code { file delete -force $file_loc } } openacs-5.7.0/packages/acs-tcl/tcl/test/test-permissions-procs.tcl0000644000175000017500000001467010551254404025030 0ustar frankiefrankie# ad_library { Test for Permission Procedures @author Cesar Hernandez (cesarhj@galileo.edu) @creation-date 2006-07-14 @arch-tag: 0823E65B-D0B0-417A-AB6F-CA86E0461A8E @cvs-id $Id: test-permissions-procs.tcl,v 1.2 2007/01/10 21:22:12 gustafn Exp $ } aa_register_case -cats {api smoke} ad_proc_permission_grant_and_revoke { Test for Permission Procedures of grant and revoke. } { #we get an user_id as party_id. set user_id [db_nextval acs_object_id_seq] aa_run_with_teardown -rollback -test_code { #Create the user array set user_info [twt::user::create -user_id $user_id] #Create and mount new subsite to test the permissions on this instance set site_name [ad_generate_random_string] set new_package_id [site_node::instantiate_and_mount \ -node_name $site_name \ -package_key acs-subsite] #Grant privileges of admin,read,write and create, after check #this ones, after revoke this ones. #Grant admin privilege permission::grant -party_id $user_id -object_id $new_package_id -privilege "admin" #Verifying the admin privilege on the user aa_true "testing admin privilige" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "admin"] == 1}] #Revoking admin privilege permission::revoke -party_id $user_id -object_id $new_package_id -privilege "admin" aa_true "testing if admin privilige was revoked" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "admin"] == 0}] #Grant read privilege permission::grant -party_id $user_id -object_id $new_package_id -privilege "read" #Verifying the read privilege on the user aa_true "testing read permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "read" ] == 1}] #Revoking read privilege permission::revoke -party_id $user_id -object_id $new_package_id -privilege "read" #We tested with a query because we have problems with inherit aa_true "testing if read privilige was revoked" \ [expr {[db_string test_read "select 1 from acs_permissions where object_id = :new_package_id and grantee_id = :user_id" -default 0] == 0}] #Grant write privilege permission::grant -party_id $user_id -object_id $new_package_id -privilege "write" #Verifying the write privilege on the user aa_true "testing write permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "write" ] == 1}] #Revoking write privilege permission::revoke -party_id $user_id -object_id $new_package_id -privilege "write" aa_true "testing if write permissions was revoked" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "write" ] == 0}] #Grant create privilege permission::grant -party_id $user_id -object_id $new_package_id -privilege "create" #Verifying the create privelege on the user aa_true "testing create permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "create" ] == 1}] #Revoking create privilege permission::revoke -party_id $user_id -object_id $new_package_id -privilege "create" aa_true "testing if create privileges was revoked" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "create" ] == 0}] #Grant delete privilege permission::grant -party_id $user_id -object_id $new_package_id -privilege "delete" #Verifying the delete privilege on the user aa_true "testing delete permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "delete" ] == 1}] #Revoking delete privilege permission::revoke -party_id $user_id -object_id $new_package_id -privilege "delete" aa_true "testing if delete permissions was revoked" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "delete" ] == 0}] } } aa_register_case -cats {api smoke} ad_proc_permission_permission_p { Test for Permission Procedures of permission_p } { #we get an user_id as party_id. set user_id [db_nextval acs_object_id_seq] aa_run_with_teardown -rollback -test_code { #Create the user array set user_info [twt::user::create -user_id $user_id] #Create and mount new subsite to test the permissions on this # instance set site_name [ad_generate_random_string] set new_package_id [site_node::instantiate_and_mount \ -node_name $site_name \ -package_key acs-subsite] #Grant permissions for this user in this object permission::grant -party_id $user_id -object_id $new_package_id -privilege "delete" aa_true "testing admin permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "delete" ] == 1}] permission::revoke -party_id $user_id -object_id $new_package_id -privilege "delete" permission::grant -party_id $user_id -object_id $new_package_id -privilege "create" aa_true "testing create permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "create" ] == 1}] permission::revoke -party_id $user_id -object_id $new_package_id -privilege "create" permission::grant -party_id $user_id -object_id $new_package_id -privilege "write" aa_true "testing write permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "write" ] == 1}] permission::revoke -party_id $user_id -object_id $new_package_id -privilege "write" permission::grant -party_id $user_id -object_id $new_package_id -privilege "read" aa_true "testing read permissions" \ [expr {[db_string test_read "select 1 from acs_permissions where object_id = :new_package_id and grantee_id = :user_id" -default 0] == 1}] permission::revoke -party_id $user_id -object_id $new_package_id -privilege "read" permission::grant -party_id $user_id -object_id $new_package_id -privilege "admin" aa_true "testing delete permissions" \ [expr {[permission::permission_p -party_id $user_id -object_id $new_package_id -privilege "admin" ] == 1}] permission::revoke -party_id $user_id -object_id $new_package_id -privilege "admin" } }openacs-5.7.0/packages/acs-tcl/tcl/test/acs-tcl-test-procs.tcl0000644000175000017500000013004111353521435023774 0ustar frankiefrankiead_library { Tcl helper procedures for the acs-automated-testing tests of the acs-tcl package. @author Peter Marklund (peter@collaboraid.biz) @creation-date 22 January 2003 } ad_proc apm_test_callback_file_path {} { The path of the test file used to check that the callback proc executed ok. } { return "[acs_package_root_dir acs-tcl]/tcl/test/callback_proc_test_file" } ad_proc apm_test_callback_proc { {-arg1:required} {-arg2:required} } { Writes the arbitrary values of arg1 and arg2 to a file so that we can check that the proc was executed. @param arg1 Arbitrary value. @param arg2 Arbitrary value. } { # Write something to a file so that can check that the proc executed set file_path [apm_test_callback_file_path] set file_id [open $file_path w] puts $file_id "$arg1 $arg2" close $file_id } aa_register_case -cats {api smoke} util__sets_equal_p { Test the util_sets_equal_p proc. @author Peter Marklund } { aa_true "lists are identical sets" [util_sets_equal_p [list a a a b b c] [list c a a b b a]] aa_true "lists are identical sets 2" [util_sets_equal_p [list a b c] [list a b c]] aa_false "lists are not identical sets" [util_sets_equal_p [list a a a b b c] [list c c a b b a]] aa_false "lists are not identical sets 2" [util_sets_equal_p [list a b c] [list a b c d]] } # By stubbing this proc we can define callbacks valid only during testing # that are guaranteed not to interfere with any real callbacks in the system aa_stub apm_supported_callback_types { return [list __test-callback-type] } aa_stub apm_arg_names_for_callback_type { return [list arg1 arg2] } aa_register_case -cats {api db smoke} apm__test_info_file { Test that the procs for interfacing with package info files - apm_generate_package_spec and apm_read_package_info_file - handle the newly added callback and auto-mount tags properly. @creation-date 22 January 2003 @author Peter Marklund } { set test_dir "[acs_package_root_dir acs-tcl]/tcl/test" set spec_path "${test_dir}/tmp-test-info-file.xml" set allowed_type [lindex [apm_supported_callback_types] 0] array set callback_array [list unknown-type proc_name1 $allowed_type proc_name2] set version_id [db_string aa_version_id {select version_id from apm_enabled_package_versions where package_key = 'acs-automated-testing'}] set auto_mount_orig [db_string aa_auto_mount {select auto_mount from apm_package_versions where version_id = :version_id}] set auto_mount $auto_mount_orig if { $auto_mount eq "" } { set auto_mount "test_auto_mount_dir" db_dml set_test_mount {update apm_package_versions set auto_mount = :auto_mount where version_id = :version_id} } set error_p [catch { # Add a few test callbacks foreach {type proc} [array get callback_array] { db_dml insert_callback {insert into apm_package_callbacks (version_id, type, proc) values (:version_id, :type, :proc)} } # Get the xml string set spec [apm_generate_package_spec $version_id] # Write xml to file set spec_file_id [open $spec_path w] puts $spec_file_id $spec close $spec_file_id # Read the xml file array set spec_array [apm_read_package_info_file $spec_path] # Assert that info parsed from xml file is correct array set parsed_callback_array $spec_array(callbacks) aa_true "Only one permissible callback should be returned, got array [array get parsed_callback_array]" \ [expr [llength [array names parsed_callback_array]] == 1] aa_equals "Checking name of callback of allowed type $allowed_type" \ $parsed_callback_array($allowed_type) $callback_array($allowed_type) aa_equals "Checking that auto-callback is correct" $spec_array(auto-mount) $auto_mount } error] # Teardown file delete $spec_path foreach {type proc} [array get callback_array] { db_dml remove_callback {delete from apm_package_callbacks where version_id = :version_id and type = :type } } db_dml reset_auto_mount {update apm_package_versions set auto_mount = :auto_mount_orig where version_id = :version_id} if { $error_p } { global errorInfo error "$error - $errorInfo" } } aa_register_case -cats {api db smoke} apm__test_callback_get_set { Test the procs apm_get_callback_proc, apm_set_callback_proc, apm_package_install_callbacks apm_remove_callback_proc, apm_post_instantiation_tcl_proc_from_key. @author Peter Marklund } { # The proc should not accept an invalid callback type set invalid_type "not-allowed-type" set error_p [catch {apm_get_callback_proc -type $invalid_type -package_key acs-kernel} error] aa_true "invalid types should result in error, got error: $error" $error_p # Try setting a package callback proc set callback_type [lindex [apm_supported_callback_types] 0] set proc_name "test_proc" set package_key "acs-automated-testing" set version_id [apm_version_id_from_package_key $package_key] set error_p [catch { apm_package_install_callbacks [list $callback_type $proc_name] $version_id # Retrieve the callback proc set retrieved_proc_name \ [apm_get_callback_proc -package_key $package_key \ -type $callback_type] aa_equals "apm_get_callback_proc retrieve callback proc" \ $retrieved_proc_name $proc_name } error] # Teardown apm_remove_callback_proc -package_key $package_key -type $callback_type if { $error_p } { global errorInfo error "$error - $errorInfo" } } aa_register_case -cats {db api smoke} apm__test_callback_invoke { Test the proc apm_invoke_callback_proc @author Peter Marklund } { set package_key acs-automated-testing set version_id [apm_version_id_from_package_key $package_key] set type [lindex [apm_supported_callback_types] 0] set file_path [apm_test_callback_file_path] set error_p [catch { # Set the callback to be to our little test proc apm_set_callback_proc -version_id $version_id -type $type "apm_test_callback_proc" apm_invoke_callback_proc -version_id $version_id -arg_list [list arg1 value1 arg2 value2] -type $type set file_id [open $file_path r] set file_contents [read $file_id] aa_equals "The callback proc should have been executed and written argument values to file" \ [string trim $file_contents] "value1 value2" close $file_id # Provide invalid argument list and the invoke proc should bomb # TODO... } error] # Teardown file delete $file_path apm_remove_callback_proc -package_key $package_key -type $type if { $error_p } { global errorInfo error "$error - $errorInfo" } } aa_register_case -cats {api smoke} xml_get_child_node_content_by_path { Test xml_get_child_node_content_by_path } { set tree [xml_parse -persist { Dunelm Services Limited Telecommunications LMS DATABASE UPDATE 2001-08-08 Add a new Person record. Dunelm Services Limited CK1 Clark Kent Kent, C Superman 2 The Daily Planet Metropolis USA }] set root_node [xml_doc_get_first_node $tree] aa_equals "person -> name -> nickname is Superman" \ [xml_get_child_node_content_by_path $root_node { { person name nickname } }] "Superman" aa_equals "Same, but after trying a couple of non-existent paths or empty notes" \ [xml_get_child_node_content_by_path $root_node { { does not exist } { properties } { person name nickname } { person sourcedid id } }] "Superman" aa_equals "properties -> datetime" \ [xml_get_child_node_content_by_path $root_node { { person commments foo } { person name first_names } { properties datetime } }] "2001-08-08" } aa_register_case -cats {api} -on_error { site_node::get_children returns root node! } site_node_get_children { Test site_node::get_children } { # Start with a known site-map entry set node_id [site_node::get_node_id -url "/"] set child_node_ids [site_node::get_children \ -all \ -element node_id \ -node_id $node_id] # lsearch returns '-1' if not found aa_equals "site_node::get_children does not return root node" [lsearch -exact $child_node_ids $node_id] -1 # -package_key set nodes [site_node::get_children -all -element node_id -node_id $node_id -filters { package_key "acs-admin" }] aa_equals "package_key arg. identical to -filters" \ [site_node::get_children -all -element node_id -node_id $node_id -package_key "acs-admin"] \ $nodes aa_equals "Found exactly one acs-admin node" [llength $nodes] 1 # -package_type set nodes [site_node::get_children -all -element node_id -node_id $node_id -filters { package_type "apm_service" }] aa_equals "package_type arg. identical to filter_element package_type" \ [site_node::get_children -all -element node_id -node_id $node_id -package_type "apm_service"] \ $nodes aa_true "Found at least one apm_service node" [expr {[llength $nodes] > 0}] # nonexistent package_type aa_true "No nodes with package type 'foo'" \ [expr [llength [site_node::get_children -all -element node_id -node_id $node_id -package_type "foo"]] == 0] } aa_register_case -cats {api smoke} text_to_html { Test code the supposedly causes ad_html_to_text to break } { # Test bad <<<'s set offending_post {><<<} set errno [catch { set text_version [ad_html_to_text -- $offending_post] } errmsg] if { ![aa_equals "Does not bomb" $errno 0] } { global errorInfo aa_log "errmsg: $errmsg" aa_log "errorInfo: $errorInfo" } else { aa_equals "Expected identical result" $text_version $offending_post } # Test offending post sent by Dave Bauer set offending_post { I have a dynamically assigned ip address, so I use dyndns.org to change addresses for my acs server. Mail is sent to any yahoo address fine. Mail sent to aol fails. I am not running a dns server on my acs box. What do I need to do to correct this problem?
    Here's my error message:
    Mail Delivery Subsystem
    | Block Address | Add to Address Book
    To: gmt3rd@yahoo.com
    Subject: Returned mail: Service unavailable

    The original message was received at Sat, 17 Mar 2001 11:48:57 -0500 from IDENT:nsadmin@localhost [127.0.0.1]
    ----- The following addresses had permanent fatal errors ----- gmt3rd@aol.com
    ----- Transcript of session follows -----

    ... while talking to mailin-04.mx.aol.com.: <<< 550-AOL no longer accepts connections from dynamically assigned <<< 550-IP addresses to our relay servers. Please contact your ISP <<< 550 to have your mail redirected through your ISP's SMTP servers. ... while talking to mailin-02.mx.aol.com.: >>> QUIT

    Attachment: Message/delivery-status Reporting-MTA: dns; testdsl.homeip.net Received-From-MTA: DNS; localhost Arrival-Date: Sat, 17 Mar 2001 11:48:57 -0500 Final-Recipient: RFC822; gmt3rd@aol.com Action: failed Status: 5.5.0 Remote-MTA: DNS; mailin-01.mx.aol.com Diagnostic-Code: SMTP; 550-AOL no longer accepts connections from dynamically assigned Last-Attempt-Date: Sat, 17 Mar 2001 11:48:57 -0500

    anybody have any ideas? } set errno [catch { set text_version [ad_html_to_text -- $offending_post] } errmsg] if { ![aa_equals "Does not bomb" $errno 0] } { global errorInfo aa_log "errmsg: $errmsg" aa_log "errorInfo: $errorInfo" } else { aa_log "Text version: $text_version" } # Test placement of [1] reference set html {Here is http://openacs.org my friend} set text_version [ad_html_to_text -- $html] aa_log "Text version: $text_version" } aa_register_case -cats {api smoke} ad_page_contract_filters { Test ad_page_contract_filters } { set filter integer foreach { value result } { "1" 1 "a" 0 "1.2" 0 "'" 0 } { if { $result } { aa_true "$value is $filter" [ad_page_contract_filter_invoke $filter dummy value] } else { aa_false "$value is NOT $filter" [ad_page_contract_filter_invoke $filter dummy value] } } set filter naturalnum foreach { value result } { "1" 1 "-1" 0 "a" 0 "1.2" 0 "'" 0 } { if { $result } { aa_true "$value is $filter" [ad_page_contract_filter_invoke $filter dummy value] } else { aa_false "$value is NOT $filter" [ad_page_contract_filter_invoke $filter dummy value] } } set filter html foreach { value result } { "'" 1 "

    " 1 } { if { $result } { aa_true "$value is $filter" [ad_page_contract_filter_invoke $filter dummy value] } else { aa_false "$value is NOT $filter" [ad_page_contract_filter_invoke $filter dummy value] } } set filter nohtml foreach { value result } { "a" 1 "

    " 0 } { if { $result } { aa_true "$value is $filter" [ad_page_contract_filter_invoke $filter dummy value] } else { aa_false "$value is NOT $filter" [ad_page_contract_filter_invoke $filter dummy value] } } } aa_register_case -cats {api smoke} export_vars { Testing export_vars } { set foo 1 set bar {} aa_equals "{ foo bar }" \ [export_vars { foo bar }] \ "foo=1&bar=" aa_equals "-no_empty { foo bar }" \ [export_vars -no_empty { foo bar }] \ "foo=1" aa_equals "-no_empty { foo bar { baz greble } }" \ [export_vars -no_empty { foo bar { baz greble } }] \ "foo=1&baz=greble" aa_equals "-no_empty -override { { bar \"\" } } { foo bar }" \ [export_vars -no_empty -override { { bar "" } } { foo bar }] \ "foo=1&bar=" \ aa_equals "-no_empty -override { { baz greble } } { foo bar }" \ [export_vars -no_empty -override { baz } { foo bar }] \ "foo=1" aa_equals "-no_empty { foo { bar \"\" } }" \ [export_vars -no_empty { foo { bar "" } }] \ "foo=1&bar=" # Test base with query vars set var1 a set var2 {} set base [export_vars -base test-page { foo bar }] set export_no_base [export_vars {var1 var2}] aa_equals "base with query vars" \ [export_vars -base $base {var1 var2}] \ "$base&$export_no_base" # Test base without query vars set base test-page aa_equals "base without query vars" \ [export_vars -base $base {var1 var2}] \ "$base?$export_no_base" } aa_register_case -cats {api smoke} site_node_verify_folder_name { Testing site_node::veriy_folder_name } { set main_site_node_id [site_node::get_node_id -url /] # Try a few folder names which we know exist aa_equals "Folder name 'user' is not allowed" \ [site_node::verify_folder_name -parent_node_id $main_site_node_id -folder "user"] "" aa_equals "Folder name 'pvt' is not allowed" \ [site_node::verify_folder_name -parent_node_id $main_site_node_id -folder "pvt"] "" # Try one we believe will be allowed set folder [ad_generate_random_string] aa_equals "Folder name '$folder' is allowed" \ [site_node::verify_folder_name -parent_node_id $main_site_node_id -folder $folder] $folder # Try the code that generates a folder name # (We only want to try this if there doesn't happen to be a site-node named user-2) if { ![site_node::exists_p -url "/register-2"] } { aa_equals "Instance name 'Register'" \ [site_node::verify_folder_name -parent_node_id $main_site_node_id -instance_name "register"] "register-2" } set first_child_node_id [lindex [site_node::get_children -node_id $main_site_node_id -element node_id] 0] set first_child_name [site_node::get_element -node_id $first_child_node_id -element name] aa_equals "Renaming folder '$first_child_name' ok" \ [site_node::verify_folder_name \ -parent_node_id $main_site_node_id \ -folder $first_child_name \ -current_node_id $first_child_node_id] $first_child_name aa_false "Creating new folder named '$first_child_name' not ok" \ [string equal [site_node::verify_folder_name \ -parent_node_id $main_site_node_id \ -folder $first_child_name] $first_child_name] } aa_register_case -cats {api db smoke} db__transaction { test db_transaction } { # create a temp table for testing catch {db_dml remove_table {drop table tmp_db_transaction_test}} db_dml new_table {create table tmp_db_transaction_test (a integer constraint tmp_db_transaction_test_pk primary key, b integer)} aa_equals "Test we can insert a row in a db_transaction clause" \ [db_transaction {db_dml test1 {insert into tmp_db_transaction_test(a,b) values (1,2)}}] "" aa_equals "Verify clean insert worked" \ [db_string check1 {select a from tmp_db_transaction_test} -default missing] 1 # verify the on_error clause is called set error_called 0 catch {db_transaction { set foo } on_error {set error_called 1}} errMsg aa_equals "error clause invoked on tcl error" \ $error_called 1 # Check that the tcl error propigates up from the code block set error_p [catch {db_transaction { error "BAD CODE"}} errMsg] aa_equals "Tcl error propigates to errMsg from code block" \ $errMsg "Transaction aborted: BAD CODE" # Check that the tcl error propigates up from the on_error block set error_p [catch {db_transaction {set foo} on_error { error "BAD CODE"}} errMsg] aa_equals "Tcl error propigates to errMsg from on_error block" \ $errMsg "BAD CODE" # check a dup insert fails and the primary key constraint comes back in the error message. set error_p [catch {db_transaction {db_dml test2 {insert into tmp_db_transaction_test(a,b) values (1,2)}}} errMsg] aa_true "error thrown inserting duplicate row" $error_p aa_true "error message contains constraint violated" [string match -nocase {*tmp_db_transaction_test_pk*} $errMsg] # check a sql error calls on_error clause set error_called 0 set error_p [catch {db_transaction {db_dml test3 {insert into tmp_db_transaction_test(a,b) values (1,2)}} on_error {set error_called 1}} errMsg] aa_false "no error thrown with on_error clause" $error_p aa_equals "error message empty with on_error clause" \ $errMsg {} # Check on explicit aborts set error_p [catch { db_transaction { db_dml test4 { insert into tmp_db_transaction_test(a,b) values (2,3) } db_abort_transaction } } errMsg] aa_true "error thrown with explicit abort" $error_p aa_equals "row not inserted with explicit abort" \ [db_string check4 {select a from tmp_db_transaction_test where a = 2} -default missing] "missing" # Check a failed sql command can do sql in the on_error block set sqlok {} set error_p [catch { db_transaction { db_dml test5 { insert into tmp_db_transaction_test(a,b) values (1,2) } } on_error { set sqlok [db_string check5 {select a from tmp_db_transaction_test where a = 1}] } } errMsg] aa_false "No error thrown doing sql in on_error block" $error_p aa_equals "Query succeeds in on_error block" \ $sqlok 1 # Check a failed transactions dml is rolled back in the on_error block set error_p [catch { db_transaction { error "BAD CODE" } on_error { db_dml test6 { insert into tmp_db_transaction_test(a,b) values (3,4) } } } errMsg] aa_false "No error thrown doing insert dml in on_error block" $error_p aa_equals "Insert in on_error block rolled back, code error" \ [db_string check6 {select a from tmp_db_transaction_test where a = 3} -default {missing}] missing # Check a failed transactions dml is rolled back in the on_error block set error_p [catch { db_transaction { db_dml test7 { insert into tmp_db_transaction_test(a,b) values (1,2) } } on_error { db_dml test8 { insert into tmp_db_transaction_test(a,b) values (3,4) } } } errMsg] aa_false "No error thrown doing insert dml in on_error block" $error_p aa_equals "Insert in on_error block rolled back, sql error" \ [db_string check8 {select a from tmp_db_transaction_test where a = 3} -default {missing}] missing # check nested db_transactions work properly with clean code set error_p [catch { db_transaction { db_dml test9 { insert into tmp_db_transaction_test(a,b) values (5,6) } db_transaction { db_dml test10 { insert into tmp_db_transaction_test(a,b) values (6,7) } } } } errMsg] aa_false "No error thrown doing nested db_transactions" $error_p aa_equals "Data inserted in outer db_transaction" \ [db_string check9 {select a from tmp_db_transaction_test where a = 5} -default {missing}] 5 aa_equals "Data inserted in nested db_transaction" \ [db_string check10 {select a from tmp_db_transaction_test where a = 6} -default {missing}] 6 # check error in outer transaction rolls back nested transaction set error_p [catch { db_transaction { db_dml test11 { insert into tmp_db_transaction_test(a,b) values (7,8) } db_transaction { db_dml test12 { insert into tmp_db_transaction_test(a,b) values (8,9) } } error "BAD CODE" } } errMsg] aa_true "Error thrown doing nested db_transactions" $error_p aa_equals "Data rolled back in outer db_transactions with error in outer" \ [db_string check11 {select a from tmp_db_transaction_test where a = 7} -default {missing}] missing aa_equals "Data rolled back in nested db_transactions with error in outer" \ [db_string check12 {select a from tmp_db_transaction_test where a = 8} -default {missing}] missing # check error in outer transaction rolls back nested transaction set error_p [catch { db_transaction { db_dml test13 { insert into tmp_db_transaction_test(a,b) values (9,10) } db_transaction { db_dml test14 { insert into tmp_db_transaction_test(a,b) values (10,11) } error "BAD CODE" } } } errMsg] aa_true "Error thrown doing nested db_transactions: $errMsg" $error_p aa_equals "Data rolled back in outer db_transactions with error in nested" \ [db_string check13 {select a from tmp_db_transaction_test where a = 9} -default {missing}] missing aa_equals "Data rolled back in nested db_transactions with error in nested" \ [db_string check14 {select a from tmp_db_transaction_test where a = 10} -default {missing}] missing db_dml drop_table {drop table tmp_db_transaction_test} } aa_register_case -cats {api smoke} util__subset_p { Test the util_subset_p proc. @author Peter Marklund } { aa_true "List is a subset" [util_subset_p [list c b] [list c a a b b a]] aa_true "List is a subset" [util_subset_p [list a b c] [list c a b]] aa_false "List is not a subset" [util_subset_p [list a a a b b c] [list c c a b b a]] aa_false "List is not a subset" [util_subset_p [list a b c d] [list a b c]] aa_equals "List is a subset" [util_get_subset_missing [list a a a b b c] [list c c a b b a]] [list] aa_equals "List is a subset" [util_get_subset_missing [list a a a b b c] [list c c a b b a]] [list] aa_equals "List is not a subset" [util_get_subset_missing [list a b c d] [list a b c]] [list d] } aa_register_case -cats {api smoke} util__randomize_list { Test util::randomize_list } { aa_equals "Emtpy list" [util::randomize_list {}] {} aa_equals "One-element list" [util::randomize_list {a}] {a} aa_true "Two-element list" [util_sets_equal_p [list a b] [util::randomize_list [list a b]]] set org_list [list a b c d e f g h i j] set randomized_list [util::randomize_list $org_list] aa_true "Ten-element list: $randomized_list" [util_sets_equal_p $org_list $randomized_list] set len [randomRange 200] set org_list [list] for { set i 0 } { $i < $len } { incr i } { lappend org_list [ad_generate_random_string] } set randomized_list [util::randomize_list $org_list] aa_true "Long random list" [util_sets_equal_p $org_list $randomized_list] } aa_register_case -cats {api} acs_tcl__util_url_valid_p { A very rudimentary test of util_url_valid_p @creation-date 2004-01-10 @author Branimir Dolicki (bdolicki@branimir.com) } { foreach url { "http://example.com" "https://example.com" "ftp://example.com" "http://example.com/" "HTTP://example.com" "http://example.com/foo/bar/blah" "http://example.com?foo=bar&bar=foo" } { aa_true "Valid web URL $url" [util_url_valid_p "$url"] } foreach url { "xhttp://example.com" "httpx://example.com" "wysiwyg://example.com" "mailto:joe@example.com" "foo" "/foo/bar" } { aa_false "Invalid web URL $url" [util_url_valid_p "$url"] } } aa_register_case -cats {web smoke} -libraries tclwebtest front_page_1 { } { #set ::auto_path "/usr/local/tclwebtest/lib" #aa_log "auto_path: $auto_path" ::twt::do_request "[ad_url]/" ::tclwebtest::assert text "Main Site" } aa_register_case -cats {smoke api} util__age_pretty { Test the util::age_pretty proc. } { aa_log "Forcing locale to en_US for all strings so that tests work in any locale" aa_equals "0 secs" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:00" -locale en_US] "1 minute ago" aa_equals "1 sec" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:01" -locale en_US] "1 minute ago" aa_equals "29 secs" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:29" -locale en_US] "1 minute ago" aa_equals "30 secs" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:30" -locale en_US] "1 minute ago" aa_equals "31 secs" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:31" -locale en_US] "1 minute ago" aa_equals "59 secs" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:59" -locale en_US] "1 minute ago" aa_equals "1 min" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:01:00" -locale en_US] "1 minute ago" aa_equals "1 min 1 sec" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:01:01" -locale en_US] "1 minute ago" aa_equals "1 min 29 sec" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:01:29" -locale en_US] "1 minute ago" aa_equals "1 min 30 sec" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:01:30" -locale en_US] "2 minutes ago" aa_equals "1 min 31 sec" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:01:31" -locale en_US] "2 minutes ago" aa_equals "11 hours 59 minutes" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-01 23:59:00" -locale en_US] "11 hours 59 minutes ago" aa_equals "15 hours 0 minutes with override" \ [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-02 03:00:00" -hours_limit 16 -locale en_US] "15 hours ago" aa_equals "12 hours 0 minutes" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-02 00:00:00" -locale en_US] "12:00 PM, Thursday" aa_equals "15 hours 0 minutes" [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-02 03:00:00" -locale en_US] "12:00 PM, Thursday" aa_equals "4 days 0 hours 0 minutes with override" \ [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-05 12:00:00" -days_limit 5 -locale en_US] "12:00 PM, Thursday" aa_equals "3 days 0 hours 0 minutes" \ [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-04 12:00:00" -locale en_US] "12:00 PM, 01 Jan 2004" aa_equals "5 days 0 hours 0 minutes" \ [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2004-01-06 12:00:00" -locale en_US] "12:00 PM, 01 Jan 2004" aa_equals "10 years" \ [util::age_pretty -timestamp_ansi "2004-01-01 12:00:00" -sysdate_ansi "2014-01-01 12:00:00" -locale en_US] "12:00 PM, 01 Jan 2004" aa_log "100 years - we know it's wrong because of Tcl library limitations: [util::age_pretty -timestamp_ansi "1904-01-01 12:00:00" -sysdate_ansi "2004-01-01 12:00:00"]" } aa_register_case \ -procs db_get_quote_indices \ -cats {api} \ db_get_quote_indices { Test the proc db_get_quote_indices. @author Peter Marklund } { aa_equals "" [db_get_quote_indices {'a'}] {0 2} aa_equals "" [db_get_quote_indices {'a''}] {} aa_equals "" [db_get_quote_indices {'a'a'a'}] {0 2 4 6} aa_equals "" [db_get_quote_indices {a'b'c'd''s'}] {1 3 5 10} aa_equals "" [db_get_quote_indices {'}] {} aa_equals "" [db_get_quote_indices {''}] {} aa_equals "" [db_get_quote_indices {a''a}] {} aa_equals "" [db_get_quote_indices {a'b'a}] {1 3} aa_equals "" [db_get_quote_indices {'a''b'}] {0 5} } aa_register_case \ -procs db_bind_var_substitution \ -cats {api} \ db_bind_var_substitution { Test the proc db_bind_var_substitution. @author Peter Marklund } { # DRB: Not all of these test cases work for Oracle (select can't be used in # db_exec_plsql) and bindvar substituion is done by Oracle, not the driver, # anyway so there's not much point in testing. These tests really test # Oracle bindvar emulation, in other words... if { [db_type] ne "oracle" } { set sql {to_char(fm.posting_date, 'YYYY-MM-DD HH24:MI:SS')} aa_equals "don't subst bind vars in quoted date" [db_bind_var_substitution $sql {SS 3 MI 4}] $sql set sql {to_char(fm.posting_date, :SS)} aa_equals "don't subst bind vars in quoted date" [db_bind_var_substitution $sql {SS 3 MI 4}] {to_char(fm.posting_date, '3')} set sql {to_char(fm.posting_date, don''t subst ':SS', do subst :SS )} aa_equals "don't subst bind vars in quoted date" [db_bind_var_substitution $sql {SS 3 MI 4}] {to_char(fm.posting_date, don''t subst ':SS', do subst '3' )} set SS 3 set db_value [db_exec_plsql test_bind { select ':SS' }] aa_equals "db_exec_plsql should not bind quoted var" $db_value ":SS" set db_value [db_exec_plsql test_bind { select :SS }] aa_equals "db_exec_plsql bind not quoted var" $db_value "3" } } aa_register_case -cats {api} \ -bugs 1450 \ acs_tcl__process_enhanced_correctly { Process sample text correctly @author Nima Mazloumi } { set string_with_img {} aa_log "Original string is $string_with_img" set html_version [ad_enhanced_text_to_html $string_with_img] aa_true "new: $html_version should be the same" [string equal $html_version $string_with_img] } aa_register_case -cats {api db} db__caching { test db_* API caching } { # Check db_string caching # Check that cached and non-cached calls return the same value. We need to # check the caching API call twice, once to fill the cache and return the # value, and again to see that the call returns the proper value from the # cache. This series ends by testing the flushing of db_cache_pool with an # exact pattern. set not_cached \ [db_string test1 {select first_names from persons where person_id = 0}] aa_equals "Test that caching and non-caching db_string call return same result" \ [db_string -cache_key test1 test1 {select first_names from persons where person_id = 0}] \ $not_cached aa_true "Test1 cached value found." \ ![catch {ns_cache get db_cache_pool test1} errmsg] aa_equals "Test that cached db_string returns the right value from the cache" \ [db_string -cache_key test1 test1 {select first_names from persons where person_id = 0}] \ $not_cached db_flush_cache -cache_key_pattern test1 aa_true "Flush of test1 from cache using the exact key" \ [catch {ns_cache get db_cache_pool test1} errmsg] # Check that cached and non-cached calls return the same default if no value # is returned by the query. This series ends by testing the flushing of the # entire db_cache_pool cache. set not_cached \ [db_string test2 {select first_names from persons where person_id=1 and person_id=2} \ -default foo] aa_equals "Test that caching and non-caching db_string call return same default value" \ [db_string -cache_key test2 test2 {select first_names from persons where person_id=1 and person_id=2} \ -default foo] \ $not_cached aa_true "Test2 cached value found." \ ![catch {ns_cache get db_cache_pool test2} errmsg] aa_equals "Test that caching and non-caching db_string call return same default value" \ [db_string -cache_key test2 test2 {select first_names from persons where person_id=1 and person_id=2} \ -default foo] \ $not_cached db_flush_cache aa_true "Flush of test2 by flushing entire pool" \ [catch {ns_cache get db_cache_pool test2} errmsg] # Check that cached and non-cached calls return an error if the query returns # no data and no default is supplied. This series ends by testing cache flushing # by "string match" pattern. aa_true "Uncached db_string call returns error if query returns no data" \ [catch {db_string test3 "select first_names from persons where person_id=1 and person_id=2"}] aa_true "Cached db_string call returns error if query returns no data" \ [catch {db_string -cache_key test3 test3 "select first_names from persons where person_id=1 and person_id=2"}] aa_true "db_string call returns error if caching call returned error" \ [catch {db_string -cache_key test3 test3 "select first_names from persons where person_id=1 and person_id=2"}] db_flush_cache -cache_key_pattern tes*3 aa_true "Flush of test3 from cache using pattern" \ [catch {ns_cache get db_cache_pool test3} errmsg] # Check db_list caching set not_cached \ [db_list test4 {select first_names from persons where person_id = 0}] aa_equals "Test that caching and non-caching db_list call return same result" \ [db_list -cache_key test4 test4 {select first_names from persons where person_id = 0}] \ $not_cached aa_true "Test4 cached value found." \ ![catch {ns_cache get db_cache_pool test4} errmsg] aa_equals "Test that cached db_list returns the right value from the cache" \ [db_list -cache_key test4 test4 {select first_names from persons where person_id = 0}] \ $not_cached db_flush_cache # Check db_list_of_list caching set not_cached \ [db_list_of_lists test5 {select * from persons where person_id = 0}] aa_equals "Test that caching and non-caching db_list_of_lists call return same result" \ [db_list_of_lists -cache_key test5 test5 {select * from persons where person_id = 0}] \ $not_cached aa_true "Test5 cached value found." \ ![catch {ns_cache get db_cache_pool test5} errmsg] aa_equals "Test that cached db_list_of_lists returns the right value from the cache" \ [db_list_of_lists -cache_key test5 test5 {select * from persons where person_id = 0}] \ $not_cached db_flush_cache # Check db_multirow caching db_multirow test6 test6 {select * from persons where person_id = 0} set not_cached \ [list test6:rowcount test6:columns [array get test6:1]] db_multirow -cache_key test6 test6 test6 {select * from persons where person_id = 0} set cached \ [list test6:rowcount test6:columns [array get test6:1]] aa_equals "Test that caching and non-caching db_multirow call return same result" \ $cached $not_cached aa_true "Test6 cached value found." \ ![catch {ns_cache get db_cache_pool test6} errmsg] db_multirow -cache_key test6 test6 test6 {select * from persons where person_id = 0} set cached \ [list test6:rowcount test6:columns [array get test6:1]] aa_equals "Test that cached db_multirow returns the right value from the cache" \ $cached $not_cached db_flush_cache # Check db_0or1row caching set not_cached \ [db_0or1row test7 {select * from persons where person_id = 0} -column_array test7] lappend not_cached [array get test7] set cached \ [db_0or1row -cache_key test7 test7 {select * from persons where person_id = 0} -column_array test7] lappend cached [array get test7] aa_equals "Test that caching and non-caching db_0or1row call return same result for 1 row" \ $cached $not_cached aa_true "Test7 cached value found." \ ![catch {ns_cache get db_cache_pool test7} errmsg] set cached \ [db_0or1row -cache_key test7 test7 {select * from persons where person_id = 0} -column_array test7] lappend cached [array get test7] aa_equals "Test that cached db_0or1row returns the right value from the cache for 1 row" \ $cached $not_cached db_flush_cache # Check db_0or1row caching returns 0 if query returns no values set not_cached \ [db_0or1row test8 {select * from persons where person_id=1 and person_id=2} -column_array test8] set cached \ [db_0or1row -cache_key test8 test8 {select * from persons where person_id=1 and person_id=2} -column_array test8] aa_equals "Test that caching and non-caching db_0or1row call return same result for 0 rows" \ $cached $not_cached aa_true "Test8 cached value found." \ ![catch {ns_cache get db_cache_pool test8} errmsg] set cached \ [db_0or1row -cache_key test8 test8 {select * from persons where person_id=1 and person_id=2} -column_array test8] aa_equals "Test that cached db_0or1row returns the right value from the cache for 0 rows" \ $cached $not_cached db_flush_cache # Won't check db_1row because it just calls db_0or1row } aa_register_case \ -cats {api smoke} \ -procs {parameter::get parameter::get_from_package_key parameter::set_default parameter::set_default parameter::set_value parameter::set_from_package_key parameter::set_global_value parameter::get_global_value} \ parameter__check_procs { Test the parameter::* procs @author Rocael Hernandez (roc@viaro.net) } { aa_run_with_teardown \ -rollback \ -test_code { aa_log "Test global parameter functionality" set parameter_id [db_nextval "acs_object_id_seq"] apm_parameter_register -parameter_id $parameter_id -scope global x_test_x "" acs-tcl 0 number parameter::set_global_value -package_key acs-tcl -parameter x_test_x -value 3 aa_true "check global parameter value set/get" [string equal [parameter::get_global_value -package_key acs-tcl -parameter x_test_x] 3] apm_parameter_unregister $parameter_id db_foreach get_param { select ap.parameter_name, ap.package_key, ap.default_value, ap.parameter_id from apm_parameters ap, apm_package_types apt where ap.package_key = apt.package_key and apt.singleton_p ='t' and ap.package_key <> 'acs-kernel' } { set value [random] if {$parameter_name ne "PasswordExpirationDays" && $value > 0.7} { set package_id [apm_package_id_from_key $package_key] set actual_value [db_string real_value { select apm_parameter_values.attr_value from apm_parameter_values where apm_parameter_values.package_id = :package_id and apm_parameter_values.parameter_id = :parameter_id }] aa_log "$package_key $parameter_name $actual_value" aa_true "check parameter::get" [string equal [parameter::get -package_id $package_id -parameter $parameter_name] $actual_value] aa_true "check parameter::get_from_package_key" \ [string equal [parameter::get_from_package_key -package_key $package_key -parameter $parameter_name] $actual_value] parameter::set_default -package_key $package_key -parameter $parameter_name -value $value set value_db [db_string get_values { select default_value from apm_parameters where package_key = :package_key and parameter_name = :parameter_name }] aa_true "check parameter::set_default" \ [string equal $value $value_db] set value [expr {$value + 10}] parameter::set_from_package_key -package_key $package_key -parameter $parameter_name -value $value aa_true "check parameter::set_from_package_key" \ [string equal $value [parameter::get -package_id $package_id -parameter $parameter_name]] set value [expr {$value + 10}] parameter::set_value -package_id $package_id -parameter $parameter_name -value $value aa_true "check parameter::set_value" \ [string equal $value [parameter::get -package_id $package_id -parameter $parameter_name]] break; } } } } aa_register_case -cats {api smoke} acs_object__package_id { Tests the acs_object__package_id procedure @author Malte Sussdorff } { # Retrieve an objects_package_id set object_id [db_string get_object_id "select max(object_id) from acs_objects where package_id >0"] set package_id [db_string get_package_id "select package_id from acs_objects where object_id = :object_id"] aa_true "package_id returned is correct" [string equal $package_id [acs_object::package_id -object_id $object_id]] } aa_register_case -cats {api smoke} acs_user__registered_user_p { Tests the acs_user::registered_user_p procedure @author Malte Sussdorff } { # Retrieve a registered user set user_id [db_string get_registered_id "select max(user_id) from registered_users"] # Check if the registered_user_p procedure finds him set is_registered_p [acs_user::registered_user_p -user_id $user_id] # Ban the user and check if he is not a registered_user anymore acs_user::ban -user_id $user_id set is_not_registered_p [acs_user::registered_user_p -user_id $user_id] if {$is_registered_p eq 1 && $is_not_registered_p eq 0} { set works_p 1 } else { set works_p 0 } acs_user::approve -user_id $user_id aa_true "registered_user_p works correct" $works_p } openacs-5.7.0/packages/acs-tcl/tcl/test/file-test-procs.tcl0000644000175000017500000002663511456662501023406 0ustar frankiefrankiead_library { Sweep the all the files in the system looking for systematic errors. @author Jeff Davis @creation-date 2005-02-28 @cvs-id $Id: file-test-procs.tcl,v 1.9 2010/10/17 21:06:09 donb Exp $ } aa_register_case -cats {smoke production_safe} files__tcl_file_syntax_errors { Test all known tcl files for successful parsing "(in the [info complete] sense at least)" and other common errors. @author Jeff Davis davis@xarg.net } { set good 0 set nfiles 0 # couple of local helper procs proc ::tcl_p {file} { return [expr {[string match {*.tcl} $file] || [file isdirectory $file]}] } # if startdir is not [acs_root_dir]/packages, then somebody checked in the wrong thing by accident set startdir [acs_root_dir]/packages aa_log "Checks starting from $startdir" #inspect every tcl file in the directory tree starting with $startdir foreach file [ad_find_all_files -check_file_func ::tcl_p $startdir] { incr nfiles set fp [open $file "r"] set data [read $fp] close $fp # Check that the file parses if {! [info complete $data] } { aa_log_result fail "$file parses successfully" } else { incr good } } aa_log "$good good of $nfiles checked" } aa_register_case -cats {smoke production_safe} -error_level error files__tcl_file_common_errors { Check for some common error patterns. @author Jeff Davis davis@xarg.net } { # couple of local helper procs proc ::tcl_p {file} { return [expr {[string match {*.tcl} $file] || [file isdirectory $file]}] } # if startdir is not [acs_root_dir]/packages, then somebody checked in the wrong thing by accident set startdir [acs_root_dir]/packages aa_log "Checks starting from $startdir" set count 0 #inspect every tcl file in the directory tree starting with $startdir foreach file [ad_find_all_files -check_file_func ::tcl_p $startdir] { if {[string match */acs-tcl/tcl/test/file-test-procs.tcl $file]} continue set fp [open $file "r"] set data [read $fp] close $fp if {[string first @returns $data] > -1} { aa_log_result fail "$file should not contain '@returns'. @returns is probably a typo of @return" } } aa_log "Checked $count tcl files" } aa_register_case -cats {smoke production_safe} files__check_info_files { Check that all the info files parse correctly and are internally consistent. @author Jeff Davis davis@xarg.net } { foreach spec_file [glob -nocomplain "[acs_root_dir]/packages/*/*.info"] { set errp 0 if { [catch {array set version [apm_read_package_info_file $spec_file]} errMsg] } { aa_log_result fail "$spec_file returned $errMsg" set errp 1 } else { regexp {packages/([^/]*)/} $spec_file match key if {![string equal $version(package.key) $key]} { aa_log_result fail "MISMATCH DIRECTORY/PACKAGE KEY: $spec_file $version(package.key) != $key" set errp 1 } # check on the requires, provides, etc stuff. if {$version(provides) eq "" && [string equal $version(package.type) apm_service] } { aa_log_result fail "$spec_file SERVICE MISSING PROVIDES: $key" set errp 1 } elseif { $version(provides) ne ""} { if { ![string equal $version(name) [lindex [lindex $version(provides) 0] 1]]} { aa_log_result fail "$spec_file: MISMATCH PROVIDES VERSION: $version(provides) $version(name)" set errp 1 } if { ![string equal $key [lindex [lindex $version(provides) 0] 0]]} { aa_log_result fail "$spec_file MISMATCH PROVIDES KEY: $key $version(provides)" set errp 1 } } # check for duplicate parameters array unset params foreach param $version(parameters) { set name [lindex $param 0] if {[info exists params($name)]} { aa_log_result fail "$spec_file: DUPLICATE PARAMETER: $name" set errp 1 } set params($name) $name } } if {!$errp} { aa_log_result pass "$spec_file no errors" } } } aa_register_case -cats {smoke production_safe} files__check_upgrade_ordering { Check that all the upgrade files are well ordered (non-overlapping and v1 > v2) @author Jeff Davis davis@xarg.net } { foreach dir [lsort [glob -nocomplain -types f "[acs_root_dir]/packages/*/*.info"]] { set error_p 0 regexp {/([^/]*).info} $dir match package set files [apm_get_package_files -package_key $package -file_types data_model_upgrade] # build list of files for each db type, sort, check strict ordering. foreach db_type {postgresql oracle} { set upgrades [list] foreach file $files { # DRB: Ignore old upgrade scripts that aren't in the proper place. We # still have old ACS 3 -> ACS 4 upgrade scripts lying around, and # I don't want to report them as failures nor delete them ... if { [string first sql $file] == -1 && [string first upgrade $file] == -1 } { set db [apm_guess_db_type $package $file] if {[string is space $db] || $db eq $db_type} { set tail [file tail $file] if {[regexp {\-(.*)-(.*).sql} $tail match v1 v2]} { set v1s [apm_version_sortable $v1] set v2s [apm_version_sortable $v2] if {$v1s ne $v2s > -1} { set error_p 1 aa_log_result fail "$file: from after to version" } else { lappend upgrades [list $v1s $v2s $v1 $v2 $file] } } else { set error_p 1 aa_log_result fail "$file: could not find version numbers" } } } } # if we have more than 1 upgrade check they are well ordered. if {[llength $upgrades] > 1} { set u1 [lsort -dictionary -index 0 $upgrades] set u2 [lsort -dictionary -index 1 $upgrades] foreach f1 $u1 f2 $u2 { if {$f1 ne $f2 } { set error_p 1 aa_log_result fail "$package upgrade not well ordered [lindex $f1 end] [lindex $f2 end]\n" } } } } if {!$error_p} { aa_log_result pass "$package upgrades well ordered" } } } aa_register_case -cats {smoke} files__check_xql_files { Check for some common errors in the xql files like missing rdbms, missing corresponding tcl files, etc. Not production safe since malformed xql can crass aolserver in the parse. @author Jeff Davis davis@xarg.net } { # couple of local helper procs proc ::xql_p {file} { return [expr {[string match {*.xql} $file] || [file isdirectory $file]}] } # if startdir is not [acs_root_dir]/packages, then somebody checked in the wrong thing by accident set startdir [acs_root_dir]/packages aa_log "Checks starting from $startdir" #inspect every tcl file in the directory tree starting with $startdir foreach file [ad_find_all_files -check_file_func ::xql_p $startdir] { set fp [open $file "r"] set data [read $fp] close $fp ns_log debug "acs_tcl__check_xql_files: read $file" set data [db_qd_internal_prepare_queryfile_content $data] if { [catch {set parse [xml_parse $data]} errMsg] } { ns_log warning "acs_tcl__check_xql_files: failed parse $file $errMsg" aa_log_result fail "XML Parse Error: $file [ad_quotehtml $errMsg]" } else { # lets walk the nodes and check they are what we want to see. # We are done so just let it go man. } # Errors: # .xql files without .tcl # dbname not blank or postgresql or oracle # -oracle w/o generic or -postgresql # -postgresql w/o generic or -oracle # regexp {(.*)[.]xql$} $file match base if {![file exists ${base}.tcl] && ![file exists ${base}.vuh]} { # the file did not exist so we must have a -db extension... regexp {(.*?)(-)?([A-Za-z_]*)[.]xql$} $file match base dummy db if { $db ne "" && $dummy ne "" && ![string match $db oracle] && ![string match $db postgresql] } { aa_log_result fail "bad db name \"$db\" file $file (or maybe .tcl or .vuh missing)" } elseif { $db ne "" && $dummy ne "" && ![regexp $db $data] } { aa_log_result fail "rdbms \"$db\" missing $file" } elseif {$dummy eq "" && [regexp {} $data] } { aa_log_result fail "rdbms found in generic $file" } if {$db eq "postgresql" || $dummy eq ""} { if {[regexp -nocase {(nvl[ ]*\(|decode[ ]*\(| connect by )} $data match]} { aa_log_result fail "postgres or generic with oracle code $file: $match" } if {[regexp -nocase {((limit|offset)[ ]*:)} $data match]} { aa_log_result fail "postgres <7.4 does not support limit :var binding with our driver" } set allxql($base) $file } else { if {[regexp -nocase {(now[ ]*\(| limit | offset | outer join )} $data match ] || $dummy eq ""} { aa_log_result fail "oracle or generic with postgres code $file: $match" } set allxql($base) $file } } else { set allxql($base) $file } } foreach xql [array names allxql] { # check there is a corresponding .tcl file if {![file exists ${xql}.tcl] && ![file exists ${xql}.vuh]} { # JCD: Hack to exclude calendar/www/views which is the only current file which has # no associated tcl file. if {[string first calendar/www/views $allxql($xql)] < 0} { aa_log_result fail "missing .tcl or .vuh file for $allxql($xql)" } } if { 0 } { # JCD: disabled for now... # check that if there is a db specific version that the corresponding # generic or other db file exists... if {[info exists onexql(${xql}-oracle)] && !([info exists onexql(${xql}-postgresql)] || [info exists onexql(${xql})]) } { aa_log_result fail "No postgresql or generic $allxql($xql)" } if {[info exists onexql(${xql}-postgresql)] && !([info exists onexql(${xql}-oracle)] || [info exists onexql(${xql})]) } { aa_log_result fail "No oracle or generic $allxql($xql)" } } } } openacs-5.7.0/packages/acs-tcl/tcl/test/memoizing-procs.tcl0000644000175000017500000000274610475570643023512 0ustar frankiefrankiead_library { automated-testing for memoizing procs @author Adrian Catalan (ykro@galileo.edu) @creation-date 2006-07-28 } namespace eval memoizing_procs_test {} ad_proc -private memoizing_procs_test::return_string { {-name:required} } { Test proc that returns a string } { set response "This is a test for " append response $name return $response } ad_proc -private memoizing_procs_test::return_upper_case_text { {-txt:required} } { Test proc that returns a string in upper case } { set response $txt append response " in upper case is " append response [string toupper $txt] return $response } aa_register_case -cats {api smoke} ad_proc_cache { Test cache of a proc executed before } { aa_log "caching a proc" util_memoize {memoizing_procs_test::return_string -name "foobar"} aa_log "checking if the proc is cached" set success_p [util_memoize_cached_p {memoizing_procs_test::return_string -name "foobar"}] aa_equals "proc was cached succesful" $success_p 1 } aa_register_case -cats {api smoke} ad_proc_flush { Test flush of a proc cached } { aa_log "caching" util_memoize {memoizing_procs_test::return_string -name "foobar"} aa_log "checking if the proc is cached" aa_log "flushing" util_memoize_flush_regexp {return_upper_case_text} set success_p [util_memoize_cached_p {memoizing_procs_test::return_upper_case_text -txt "foobar"}] aa_equals "proc was flushed succesful" $success_p 0 } openacs-5.7.0/packages/acs-tcl/tcl/test/community-core-test-procs.tcl0000644000175000017500000001174611211475654025436 0ustar frankiefrankie# ad_library { @author byron Haroldo Linares Roman (bhlr@galileo.edu) @creation-date 2006-07-28 @arch-tag: 0D0EAC28-2481-4BEE-9645-A143B939DBCA @cvs-id $Id: community-core-test-procs.tcl,v 1.5 2009/06/03 13:33:32 donb Exp $ } aa_register_case \ -cats {api smoke} \ -procs {cc_lookup_email_user cc_email_from_party} \ community_cc_procs \ { test community core procs returned values } { set user_id [db_nextval acs_object_id_seq] set username [ad_generate_random_string] set password [ad_generate_random_string] aa_run_with_teardown -test_code { array set user_info [twt::user::create -user_id $user_id] set user_id_p [cc_lookup_email_user $user_info(email)] aa_true "User ID CORRECTO" \ [string match $user_id_p $user_info(user_id)] set email_p [cc_email_from_party $user_info(user_id)] aa_log "returns: $email_p , creation: $user_info(email)" aa_true "Email correcto" \ [string match $email_p [string tolower $user_info(email)]] } } aa_register_case \ -cats {api smoke} \ -procs {person::person_p person::get person::new person::update person::get_bio person::update_bio} \ person_procs_test \ { test if the values returned by the person procs are correct } { set user_id [db_nextval acs_object_id_seq] set username "[ad_generate_random_string]" set email "${username}@test.test" set password [ad_generate_random_string] set first_names [ad_generate_random_string] set last_name [ad_generate_random_string] array set user_info [auth::create_user -user_id $user_id -username $username \ -email $email -first_names $first_names -last_name $last_name \ -password $password -secret_question [ad_generate_random_string] \ -secret_answer [ad_generate_random_string]] if { $user_info(creation_status) ne "ok" } { # Could not create user error "Could not create test user with username=$username user_info=[array get user_info]" } set user_info(password) $password set user_info(email) $email aa_log "Created user with email=\"$email\" and password=\"$password\"" aa_run_with_teardown -rollback \ -test_code { aa_true "party is a person" [person::person_p -party_id $user_id] array set user_inf [person::get -person_id $user_info(user_id)] aa_true "first_names correct" [string match $user_inf(first_names) $first_names] aa_true "last_name correct" [string match $user_inf(last_name) $last_name] aa_true "person_id correct" [string match $user_inf(person_id) $user_id] aa_true "correct name" [string match [person::name -person_id $user_info(user_id)] "$first_names $last_name"] set prs_id [person::new -first_names $first_names -last_name $last_name -email "${email}s"] set email_p [cc_email_from_party $prs_id] aa_true "New person pass" [string match $email_p [string tolower "${email}s"]] person::update -person_id $prs_id -first_names "hh$first_names" -last_name "hh$last_name" aa_true "name changed" [string match [person::name -person_id $prs_id] "hh$first_names hh$last_name"] set bio "bio :: [ad_generate_random_string] :: bio" person::update_bio -person_id $prs_id -bio $bio aa_true "bio(graphy) ok" [string match $bio [person::get_bio -person_id $prs_id -exists_var bio_p]] person::delete -person_id $prs_id aa_true "person deleted" ![person::person_p -party_id $prs_id] } } aa_register_case \ -cats {api smoke} \ -procs {party::get_by_email party::update} \ party_procs_test \ { test if the values returned by the party procs are correct } { set user_id [db_nextval acs_object_id_seq] set username "[ad_generate_random_string]" set email "${username}@test.test" set password [ad_generate_random_string] set first_names [ad_generate_random_string] set last_name [ad_generate_random_string] set url "url[ad_generate_random_string]" array set user_info [auth::create_user -user_id $user_id -username $username -email $email -first_names $first_names \ -last_name $last_name -password $password \ -secret_question [ad_generate_random_string] \ -secret_answer [ad_generate_random_string]] if { $user_info(creation_status) ne "ok" } { # Could not create user error "Could not create test user with username=$username user_info=[array get user_info]" } set user_info(password) $password set user_info(email) $email aa_log "Created user with email=\"$email\" and password=\"$password\"" aa_run_with_teardown -rollback \ -test_code { aa_true "correct party_id" [string match [party::get_by_email -email $email] $user_info(user_id)] party::update -party_id $user_info(user_id) -email "${email}2" -url $url aa_true "correct party with new mail" [string match [party::get_by_email -email "${email}2"] $user_info(user_id)] } } openacs-5.7.0/packages/acs-tcl/tcl/test/doc-check-procs.tcl0000644000175000017500000000310510455461024023310 0ustar frankiefrankiead_library { Check all the proc documentation @author Jeff Davis @creation-date 2005-02-28 @cvs-id $Id: doc-check-procs.tcl,v 1.2 2006/07/13 15:09:08 rocaelh Exp $ } aa_register_case -cats {smoke production_safe} documentation__check_proc_doc { checks if documentation exists for public procs. @author Jeff Davis davis@xarg.net } { set count 0 set good 0 foreach p [lsort -dictionary [nsv_array names api_proc_doc]] { array set pa [nsv_get api_proc_doc $p] if { $pa(public_p) && !($pa(deprecated_p) || $pa(warn_p)) } { incr count if { [string is space $pa(main)] } { aa_log_result fail "No documentation for public proc $p" } else { incr good } } array unset pa } aa_log "Found $good good of $count checked" } aa_register_case -cats {smoke production_safe} -error_level warning documentation__check_deprecated_see { checks if deprecated procs have an @see clause @author Jeff Davis davis@xarg.net } { set count 0 set good 0 foreach p [lsort -dictionary [nsv_array names api_proc_doc]] { array set pa [nsv_get api_proc_doc $p] if { $pa(deprecated_p)||$pa(warn_p) } { incr count if { ![info exists pa(see)] || [string is space $pa(see)] } { aa_log_result fail "No @see for deprecated proc $p" } else { incr good } } array unset pa } aa_log "Found $good of $count procs checked" } openacs-5.7.0/packages/acs-tcl/tcl/test/acs-tcl-apm-procs.tcl0000755000175000017500000000531510551254404023600 0ustar frankiefrankiead_library { Tcl helper procedures for the acs-automated-testing tests of the acs-tcl package. @author Veronica De La Cruz (veronica@viaro.net) @creation-date 11 August 2006 } aa_register_case -cats {api smoke} -procs { apm_parameter_register } test_apm_parameter__register { Test the apm_parameter_register procedure @author Veronica De La Cruz (veronica@viaro.net) } { aa_run_with_teardown -rollback -test_code { set package_list [db_list get_packages "select package_key from apm_package_types"] aa_log "List of packages:\{$package_list\}" set list_index [randomRange [expr {[llength $package_list] - 1}]] set package_key [lrange $package_list $list_index $list_index] set parameter_name [ad_generate_random_string] set description [ad_generate_random_string] set values { {number} {string} } set index [randomRange 1] # Choose randomly the parameter whether will be string or number. # Also choose randomly its default value. set datatype [lrange $values $index $index] if {$datatype eq "number"} { set default_value 0 } else { set default_value [ad_generate_random_string] } aa_log "Paramater to be added: name : $parameter_name \n descr: $description \n datatype: $datatype \n default_value: $default_value" set parameter_id [apm_parameter_register $parameter_name $description $package_key $default_value $datatype] aa_true "Parameter register succeeded" [exists_and_not_null parameter_id] } } aa_register_case -cats {api smoke} -procs {apm_package_instance_new} test_apm_package_instance__new { Test the apm_package_instance_new procedure @author Veronica De La Cruz (veronica@viaro.net) } { aa_run_with_teardown -rollback -test_code { set package_list [db_list get_packages "select package_key from apm_package_types"] aa_log "List of packages:\{$package_list\}" set list_index [randomRange [expr {[llength $package_list] - 1}]] set package_key [lrange $package_list $list_index $list_index] set instance_name $package_key append instance_name "-[ad_generate_random_string]" aa_log "Package to be instantiated: $package_key" aa_log "Instance name to be added: $instance_name" set error_ocurred [catch {set package_id [apm_package_instance_new -package_key $package_key -instance_name $instance_name ]} err_men] aa_log "Error Message $error_ocurred: $err_men " aa_true "Setting the new instance succeeded" [exists_and_not_null package_id] } } openacs-5.7.0/packages/acs-tcl/tcl/test/datamodel-test-procs.tcl0000644000175000017500000002074111475741535024417 0ustar frankiefrankiead_library { Sweep the all the files in the system looking for systematic errors. @author Jeff Davis @creation-date 2005-02-28 @cvs-id $Id: datamodel-test-procs.tcl,v 1.13 2010/12/02 16:03:41 jeffd Exp $ } aa_register_case -cats {db smoke production_safe} datamodel__named_constraints { Check that all the contraints meet the constraint naming standards. @author Jeff Davis davis@xarg.net } { set db_is_pg_p [string equal [db_name] "PostgreSQL"] if { $db_is_pg_p } { set get_constraints "select cla.relname as table_name, con.conrelid, con.conname as constraint_name, CASE when con.contype='c' then 'ck' when con.contype='f' then 'fk' when con.contype='p' then 'pk' when con.contype='u' then 'un' else '' END as constraint_type, con.conkey, '' as search_condition from pg_constraint con, pg_class cla where con.conrelid != 0 and cla.oid=con.conrelid order by table_name,constraint_name" set get_constraint_col "select attname from pg_attribute where attnum = :columns_list and attrelid = :conrelid" } else { # Oracle set get_constraints "select acc.*, ac.search_condition, decode(ac.constraint_type,'C','CK','R','FK','P','PK','U','UN','') as constraint_type from (select count(column_name) as columns, table_name, constraint_name from user_cons_columns group by table_name, constraint_name) acc, user_constraints ac where ac.constraint_name = acc.constraint_name order by acc.table_name, acc.constraint_name" set get_constraint_col "select column_name from user_cons_columns where constraint_name = :constraint_name" } db_foreach check_constraints $get_constraints { if { $db_is_pg_p || [string last "$" $table_name] eq -1 } { regsub {_[[:alpha:]]+$} $constraint_name "" name_without_type set standard_name "${name_without_type}_${constraint_type}" set standard_name_alt "${name_without_type}_[ad_decode $constraint_type pk pkey fk fkey un key ck ck missing]" if { $db_is_pg_p } { set columns_list [split [string range $conkey 1 end-1] ","] set columns [llength $columns_list] } if { $columns eq 1 } { set column_name [db_string get_col $get_constraint_col] # NOT NULL constraints (oracle only) if { [string equal $search_condition "\"$column_name\" IS NOT NULL"] } { set constraint_type "NN" } set standard_name ${table_name}_${column_name}_${constraint_type} if { [string length $standard_name] > 30 } { # Only check the abbreviation set standard_name "${name_without_type}_${constraint_type}" } } # Giving a hint for constraint naming if {[string range $standard_name 0 2] eq "SYS"} { set hint "unnamed" } else { set hint "hint: $standard_name" } if { $standard_name ne $constraint_name && $standard_name_alt ne $constraint_name } { aa_log_result fail "Table $table_name constraint $constraint_name ($constraint_type) violates naming standard ($hint)" } } } } aa_register_case -cats {db smoke production_safe} datamodel__acs_object_type_check { Check that the object type tables exist and that the id column is present and the name method works. @author Jeff Davis davis@xarg.net } { db_foreach object_type {select * from acs_object_types} { if {[string tolower $table_name] ne $table_name } { aa_log_result fail "Type $object_type: table_name $table_name mixed case" } if {[string tolower $id_column] ne $id_column } { aa_log_result fail "Type $object_type: id_column $id_column mixed case" } set table_name [string tolower $table_name] set id_column [string tolower $id_column] set the_pk {} while { [string is space $table_name] && $object_type ne $supertype } { if {![db_0or1row get_supertype "select * from acs_object_types where object_type = :supertype"]} { break } } if {![db_table_exists $table_name]} { aa_log_result fail "Type $object_type: table $table_name does not exit" } else { if {[string is space $id_column]} { aa_log_result fail "Type $object_type: id_column not specified" } else { # we could just check the column exists but since we want to # check the name method try at least to get a real object_id if {[catch {db_0or1row check_exists "select min($id_column) as the_pk from $table_name"} errMsg]} { aa_log_result fail "Type $object_type: select $id_column from $table_name failed:\n$errMsg" } } } if {![string is space $name_method]} { if {[string tolower $name_method] ne $name_method } { aa_log_result fail "Type $object_type: name method $name_method mixed case" } set name_method [string tolower $name_method] if {[string is integer -strict $the_pk]} { # intentionally don't use bind variables here which is ok # since we just checked the_pk was an integer if { [catch {db_0or1row name_method "select ${name_method}($the_pk) as NAME from dual"} errMsg] } { aa_log_result fail "Type $object_type: name method $name_method failed\n$errMsg" } } } if {![string is space $type_extension_table] && ![db_table_exists $type_extension_table]} { aa_log_result fail "Type $object_type: type extension table $type_extension_table does not exist" } } } aa_register_case -cats {db smoke production_safe} datamodel__acs_attribute_check { Check that the acs_attribute column is present and the datatype is vaguely consistent with the db datatype. @author Jeff Davis davis@xarg.net } { array set allow_types { string {TEXT VARCHAR CHAR VARCHAR2} boolean {BOOL INT2 INT4 CHAR} number {NUMERIC INT2 INT4 INT8 FLOAT4 FLOAT8 NUMBER} integer {INT2 INT4 INT8 NUMBER} money {NUMERIC FLOAT4 FLOAT8} timestamp {TIMESTAMPTZ} time_of_day {TIMESTAMPTZ} enumeration {INT2 INT4 INT8} url {VARCHAR TEXT VARCHAR2} email {VARCHAR TEXT VARCHAR2} text {VARCHAR TEXT CLOB VARCHAR2} keyword {CHAR VARCHAR TEXT VARCHAR2} } db_foreach attribute {select a.*, lower(ot.table_name) as obj_type_table from acs_attributes a, acs_object_types ot where ot.object_type = a.object_type order by a.object_type} { if {[string tolower $table_name] ne $table_name } { aa_log_result fail "Type $object_type attribute $table_name.$attribute_name mixed case" set table_name [string tolower $table_name] } elseif {[string is space $table_name]} { set table_name $obj_type_table } switch -exact $storage { type_specific { if {![info exists columns($table_name)]} { set columns($table_name) [db_columns $table_name] } if {[string is space $column_name]} { set column_name $attribute_name } set column_name [string tolower $column_name] if {[lsearch $columns($obj_type_table) $column_name] < 0} { aa_log_result fail "Type $object_type attribute column $column_name not found in $obj_type_table" } else { # check the type of the column is vaguely like the acs_datatype type. if {[info exists allow_types($datatype)]} { set actual_type [db_column_type $table_name $column_name] if {$actual_type eq "-1"} { aa_log_result fail "Type $object_type attribute $attribute_name database type get for ($table_name.$column_name) failed" } else { if {[lsearch $allow_types($datatype) $actual_type] < 0} { aa_log_result fail "Type $object_type attribute $attribute_name database type was $actual_type for $datatype" } } } } } generic { # nothing really to do here... } default { # it was null which is probably not sensible. aa_log_result fail "Type $object_type attribute $table_name.$attribute_name storage type null" } } } } openacs-5.7.0/packages/acs-tcl/tcl/test/multirow-test.adp0000644000175000017500000000012610505053770023166 0ustar frankiefrankie@test_rows.label@ openacs-5.7.0/packages/acs-tcl/tcl/test/multirow-test.tcl0000644000175000017500000000043110520736006023200 0ustar frankiefrankiead_page_contract { Tests the ad_context_bar_multirow referenced in navigation-procs.tcl. @author Juan Pablo Amaya jpamaya@unicauca.edu.co @creation-date 21 September 2006 } ad_context_bar_multirow -multirow test_rows -from_node $from_node -node_id $node_id $context openacs-5.7.0/packages/acs-tcl/tcl/test/ad-proc-test-procs.tcl0000644000175000017500000001116510551254404023776 0ustar frankiefrankiead_library { Tests for ad_proc. @author Lee Denison lee@xarg.co.uk @creation-date 2005-03-11 } aa_register_case -cats {api smoke} ad_proc_create_callback { Tests the creation of a callback and an implementation with some forced error cases. } { aa_true "throw error for ad_proc -callback with extraneous proc body" \ [catch { ad_proc -callback a_callback { arg1 arg2 } { docs } { body } } error] aa_true "throw error for callback called contract" \ [catch { ad_proc -callback contract { arg1 arg2 } { docs } - } error] ad_proc -callback a_callback { -arg1 arg2 } { this is a test callback } - set callback_procs [info procs ::callback::a_callback::*] aa_true "creation of a valid callback contract with '-' body" \ [expr {[lsearch -exact \ $callback_procs \ ::callback::a_callback::contract] >= 0}] ad_proc -callback a_callback_2 { arg1 arg2 } { this is a test callback } {} set callback_procs [info procs ::callback::a_callback_2::*] aa_true "creation of a valid callback contract with no body" \ [expr {[lsearch -exact \ $callback_procs \ ::callback::a_callback_2::contract] >= 0}] aa_true "throw error for missing -callback on implementation definition" \ [catch { ad_proc -impl an_impl {} { docs } { body } } error] aa_true "throw error for implementation named impl" \ [catch { ad_proc -callback a_callback -impl impl {} { docs } { body } } error] ad_proc -callback a_callback -impl an_impl {} { this is a test callback implementation } { } set impl_procs [info procs ::callback::a_callback::impl::*] aa_true "creation of a valid callback implementation" \ [expr {[lsearch -exact \ $impl_procs \ ::callback::a_callback::impl::an_impl] >= 0}] } ad_proc -callback a_callback { -arg1:required arg2 } { this is a test callback } - ad_proc -callback b_callback { -arg1:required arg2 } { this is a test callback } - ad_proc -callback c_callback { -arg1:required arg2 } { this is a test callback } - ad_proc -callback a_callback -impl an_impl1 {} { this is a test callback implementation } { return 1 } ad_proc -callback a_callback -impl an_impl2 {} { this is a test callback implementation which does an upvar of an array. } { upvar $arg1 arr if {[info exists arr(test)]} { return $arr(test) } return {} } ad_proc -callback a_callback -impl fail_impl {} { this is a test callback implementation } { error "should fail" } ad_proc EvilCallback {} { This is a test callback implementation that should not be invoked. } { error "Should not be invoked" } aa_register_case -cats {api smoke} ad_proc_fire_callback { Tests a callback with two implementations . } { aa_true "throws error for invalid arguments even if no implementations" \ [catch {callback c_callback bar} error] aa_true "callback returns empty list with no implementations" \ [expr {[llength [callback b_callback -arg1 foo bar]] == 0}] set foo(test) 2 aa_true "callback returns value for each defined callback and catches the error callback" \ [expr {[llength [callback -catch a_callback -arg1 foo bar]] == 2}] aa_true "callback returns correct value for specified implementation" \ [expr {[callback -impl an_impl1 a_callback -arg1 foo bar] == 1}] aa_true "callback returns correct value for an array ref" \ [expr {[callback -impl an_impl2 a_callback -arg1 foo bar] == 2}] aa_true "callback works with {} args" \ [expr {[callback -impl an_impl2 a_callback -arg1 {} {}] == {}}] aa_true "callback errors with missing arg" \ [expr {[catch {callback -impl an_impl2 a_callback -arg1 foo} err] == 1}] aa_true "throws error for invalid arguments with implementations" \ [catch {callback a_callback bar} error] aa_true "throws error when a non-existent implementation is specified" \ [catch {callback -impl non_existent a_callback -arg1 foo bar} error] aa_true "throws error without -catch when an error occurs in a callback" \ [catch {callback a_callback -arg1 foo bar} error] set x [catch {callback -impl an_impl2 a_callback -arg1 foo {[EvilCallback]}} error] aa_false "EvilCallback not invoked returned $error" $x set x [catch {callback -impl an_impl2 a_callback -arg1 {[EvilCallback]} bar} error] aa_false "EvilCallback not invoked returned $error" $x } openacs-5.7.0/packages/acs-tcl/tcl/test/whos-online-procs.tcl0000644000175000017500000000567211144363303023742 0ustar frankiefrankiead_library { Check whos-online procs @author Juan Pablo Amaya jpamaya@unicauca.edu.co @creation-date 2006-08-02 } aa_register_case -cats { smoke production_safe web } -libraries tclwebtest -procs { whos_online::num_users whos_online::set_invisible whos_online::all_invisible_user_ids whos_online::unset_invisible whos_online::user_ids } whos_online__check_online_visibility { Check procs related with users online visibility } { set user_id [db_nextval acs_object_id_seq] aa_run_with_teardown -test_code { #--------------------------------------------------------------------------------------------------- #Test num_users #--------------------------------------------------------------------------------------------------- set logged_users [whos_online::num_users] aa_log "Logged users: $logged_users" # Login user array set user_info [twt::user::create -admin -user_id $user_id] twt::user::login $user_info(email) $user_info(password) set logged_users [whos_online::num_users] aa_true "New user logged - Users logged: $logged_users" [expr { $logged_users > 0 } ] #--------------------------------------------------------------------------------------------------- #Test set_invisible #--------------------------------------------------------------------------------------------------- aa_log "User $user_info(email) is visible" whos_online::set_invisible $user_id aa_true "User $user_info(email) is Invisible" [expr {[nsv_exists invisible_users $user_id] == 1 }] #--------------------------------------------------------------------------------------------------- #Test all-invisible_user_ids #--------------------------------------------------------------------------------------------------- aa_true "User $user_info(email) with user_id=$user_id is in the invisible list"\ [expr [lsearch [whos_online::all_invisible_user_ids] $user_id] >= 0] #--------------------------------------------------------------------------------------------------- #Test unset_invisible #--------------------------------------------------------------------------------------------------- aa_log "User $user_info(email) is invisible" whos_online::unset_invisible $user_id aa_false "User $user_info(email) is Visible" \ [expr {[whos_online::user_invisible_p $user_id ] == 1 }] #--------------------------------------------------------------------------------------------------- #Test user_ids #--------------------------------------------------------------------------------------------------- aa_true "User $user_info(email) with user_id=$user_id is in the visible list"\ [expr [lsearch [whos_online::user_ids] $user_id] >= 0] twt::user::logout twt::user::delete -user_id $user_id } -teardown_code { twt::user::delete -user_id $user_id } } openacs-5.7.0/packages/acs-tcl/tcl/test/html-email-procs.tcl0000644000175000017500000000060611022567612023525 0ustar frankiefrankiead_library { Test html email procs } aa_register_case -cats {api smoke} build_mime_message { Basic test of build mime mesage } { aa_false "Build mime message, no error" \ [catch {build_mime_message \ "Test Mesage" \ "

    Test Message

    "} errmsg] aa_log err=$errmsg aa_false "Package require mime package found" \ [catch {package require mime} errmsg] }openacs-5.7.0/packages/acs-tcl/tcl/test/log-test-procs.tcl0000644000175000017500000000216510763244726023245 0ustar frankiefrankiead_library { Examine error logs @author Lars Pind (lars@collaboraid.biz) @creation-date 22 January 2003 } aa_register_case -cats {smoke} -error_level warning server_error_log { Examine server error log. } { # Log error lines start with something like this: # [19/Nov/2003:00:54:45][10491.319494][-conn1-] Error: set logfile [ns_info log] if {$logfile eq "STDOUT"} { set logfile "[acs_root_dir]/log/error/current" } set fd [open $logfile r] set entry {} set inside_error_p 0 while { [gets $fd line] != -1 } { if { [regexp {^\[([^\]]*)\]\[[^\]]*\]\[[^\]]*\] ([^: ]*): (.*)$} $line match timestamp level rest] } { if { $inside_error_p } { aa_log_result "fail" "$timestamp: $entry" set inside_error_p 0 } if {$level eq "Error"} { set inside_error_p 1 set entry {} append entry $rest \n #"(Rest was=$rest)" \n } } elseif { $inside_error_p } { append entry $line \n } } close $fd } openacs-5.7.0/packages/acs-tcl/tcl/test/object-test-case-procs.tcl0000644000175000017500000000740210551254404024627 0ustar frankiefrankie# ad_library { @author byron Haroldo Linares Roman (bhlr@galileo.edu) @creation-date 2006-08-11 @arch-tag: E1207E78-A4E3-4DC7-BEB7-49EA35B99D69 @cvs-id $Id: object-test-case-procs.tcl,v 1.5 2007/01/10 21:22:12 gustafn Exp $ } aa_register_case \ -cats {api smoke} \ -procs {acs_object::get acs_object::get_element acs_object::set_context_id} \ acs_object_procs_test \ { test the acs_object::* procs } { set pretty_name [ad_generate_random_string] set object_type [string tolower $pretty_name] set name_method "${object_type}.name" set creation_user [ad_conn user_id] set creation_ip [ad_conn peeraddr] set context_id [ad_conn package_id] set context_id2 [apm_package_id_from_key "acs-tcl"] set the_id [db_nextval acs_object_id_seq] aa_run_with_teardown -test_code { if {[db_name] eq "PostgreSQL"} { set type_create_sql "select acs_object_type__create_type ( :object_type, :pretty_name, :pretty_name, 'acs_object', null, null, null, 'f', null, :name_method);" set new_type_sql "select acs_object__new ( :the_id, :object_type, now(), :creation_user, :creation_ip, :context_id );" set object_del_sql "select acs_object__delete(:the_id)" set type_drop_sql "select acs_object_type__drop_type( :object_type, 't' )" } else { # oracle set type_create_sql "begin acs_object_type.create_type ( object_type => :object_type, pretty_name => :pretty_name, pretty_plural => :pretty_name, supertype => 'acs_object', abstract_p => 'f', name_method => :name_method); end;" set new_type_sql "begin :1 := acs_object.new ( object_id => :the_id, object_type => :object_type, creation_user => :creation_user, creation_ip => :creation_ip, context_id => :context_id); end;" set object_del_sql "begin acs_object.del(:the_id); end;" set type_drop_sql "begin acs_object_type.drop_type( object_type => :object_type, cascade_p => 't'); end;" } aa_log "test object_type $object_type :: $context_id2" db_exec_plsql type_create $type_create_sql set the2_id [db_exec_plsql new_type $new_type_sql] acs_object::get -object_id $the_id -array array aa_true "object_id $the_id :: $array(object_id)" \ [string match $the_id $array(object_id)] aa_true "object_type $object_type :: $array(object_type)" \ [string match $object_type $array(object_type)] aa_true "context_id $context_id :: $array(context_id)" \ [string match $context_id $array(context_id)] aa_true \ "creation_user $creation_user :: [acs_object::get_element -object_id $the_id -element creation_user]" \ [string match $creation_user [acs_object::get_element \ -object_id $the_id \ -element creation_user]] aa_true \ "creation_ip $creation_ip :: [acs_object::get_element -object_id $the_id -element creation_ip]" \ [string match $creation_ip [acs_object::get_element \ -object_id $the_id \ -element creation_ip]] acs_object::set_context_id -object_id $the_id \ -context_id $context_id2 aa_true \ "context_id $context_id2 :: [acs_object::get_element -object_id $the_id -element context_id]" \ [string match $context_id2 [acs_object::get_element \ -object_id $the_id \ -element context_id]] } -teardown_code { db_exec_plsql object_del $object_del_sql db_exec_plsql type_drop $type_drop_sql } } openacs-5.7.0/packages/acs-tcl/tcl/test/html-conversion-procs.tcl0000644000175000017500000003034111226234001024607 0ustar frankiefrankiead_library { Tests that deal with the html parsing procs of openacs. @creation-date 15 November 2003 } aa_register_case -cats {api smoke} ad_html_to_text_bold { Test if it converts b tags correctly. } { set html "Some bold test" set result [ad_html_to_text $html] aa_true "contains asterisks?" [regexp {\*bold\*} $result] } aa_register_case -cats {api smoke} -bugs 386 -error_level warning \ ad_html_to_text_clipped_link { Test if it converts clipped links. } { # try with missing leading and trailing quote foreach html {{ Some linktext bla

    following text }} { set result [ad_html_to_text $html] # make sure the desired text is in there and _before_ the # footnotes aa_true "contains link" [regexp {linktext.*\[1\]} $result] aa_true "contains following text" [regexp {following text.*\[1\]} $result] } } aa_register_case -cats {api smoke} ad_html_security_check_href_allowed { tests is href attribute is allowed of A tags } { set html "An Link" aa_true "href is allowed for A tags" [string equal [ad_html_security_check $html] ""] } aa_register_case -cats {api smoke} util_close_html_tags { Tests closing HTML tags. } { aa_equals "" [util_close_html_tags "Foobar"] "Foobar" aa_equals "" [util_close_html_tags "Foobar"] "Foobar" aa_equals "" [util_close_html_tags "Foobar is a very long word"] "Foobar is a very long word" aa_equals "" [util_close_html_tags "Foobar is a very long word" 15] "Foobar is a" aa_equals "" [util_close_html_tags "Foobar is a very long word" 0 20 "..."] "Foobar is a very..." } aa_register_case -cats {api smoke} ad_html_text_convert { Testing ad_html_text_convert. } { #---------------------------------------------------------------------- # from text/enhanced #---------------------------------------------------------------------- set string "What?\nNever mind, buddy" aa_equals "" [ad_html_text_convert -from "text/enhanced" -to "text/html" -truncate_len 14 -- $string] \ [ad_enhanced_text_to_html "What?\nNever..."] # The string is longer in plaintext, because the "_" symbol to denote italics is counted as well. aa_equals "" [ad_html_text_convert -from "text/enhanced" -to "text/plain" -truncate_len 15 -- $string] "What?\n_Never..." #---------------------------------------------------------------------- # from text/plain #---------------------------------------------------------------------- set string "What?\nNever mind, buddy" aa_equals "" [ad_html_text_convert -from "text/plain" -to "text/html" -truncate_len 14 -- $string] \ [ad_text_to_html "What?\nNever..."] aa_equals "" [ad_html_text_convert -from "text/plain" -to "text/plain" -truncate_len 14 -- $string] \ "What?\nNever..." #---------------------------------------------------------------------- # from text/fixed-width #---------------------------------------------------------------------- set string "What?\nNever mind, buddy" aa_equals "" [ad_html_text_convert -from "text/fixed-width" -to "text/html" -truncate_len 14 -- $string] \ "

    What?\nNever
    ..." aa_equals "" [ad_html_text_convert -from "text/fixed-width" -to "text/plain" -truncate_len 14 -- $string] \ "What?\nNever..." #---------------------------------------------------------------------- # from text/html #---------------------------------------------------------------------- set string "What?
    Never mind, buddy" aa_equals "" [ad_html_text_convert -from "text/html" -to "text/html" -truncate_len 14 -- $string] \ "What?
    Never..." aa_equals "" [ad_html_text_convert -from "text/html" -to "text/plain" -truncate_len 15 -- $string] \ "What?\n_Never..." set long_string [string repeat "Very long text. " 10] aa_equals "No truncation" [ad_html_text_convert -from "text/html" -to "text/html" -truncate_len [string length $long_string] -- $long_string] $long_string } aa_register_case -cats {api smoke} string_truncate { Testing string truncation } { aa_equals "" [string_truncate -len 5 -ellipsis "" -- "foo"] "foo" aa_equals "" [string_truncate -len 5 -ellipsis "" -- "foobar greble"] "fooba" aa_equals "" [string_truncate -len 6 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 7 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 8 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 9 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 10 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 11 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 12 -ellipsis "" -- "foobar greble"] "foobar" aa_equals "" [string_truncate -len 13 -ellipsis "" -- "foobar greble"] "foobar greble" aa_equals "" [string_truncate -len 5 -ellipsis "..." -- "foo"] "foo" aa_equals "" [string_truncate -len 5 -ellipsis "..." -- "foobar greble"] "fo..." aa_equals "" [string_truncate -len 6 -ellipsis "..." -- "foobar greble"] "foo..." aa_equals "" [string_truncate -len 7 -ellipsis "..." -- "foobar greble"] "foob..." aa_equals "" [string_truncate -len 8 -ellipsis "..." -- "foobar greble"] "fooba..." aa_equals "" [string_truncate -len 9 -ellipsis "..." -- "foobar greble"] "foobar..." aa_equals "" [string_truncate -len 10 -ellipsis "..." -- "foobar greble"] "foobar..." aa_equals "" [string_truncate -len 11 -ellipsis "..." -- "foobar greble"] "foobar..." aa_equals "" [string_truncate -len 12 -ellipsis "..." -- "foobar greble"] "foobar..." aa_equals "" [string_truncate -len 13 -ellipsis "..." -- "foobar greble"] "foobar greble" set long_string [string repeat "Very long text. " 100] aa_equals "No truncation" [string_truncate -len [string length $long_string] -- $long_string] $long_string } aa_register_case -cats {api smoke} -procs {util_convert_line_breaks_to_html} util_convert_line_breaks_to_html { Test if it converts spaces and line breaks correctly. } { #Convert leading and trailing spaces or tabs set html "\tinter spaces " aa_log "html= \"$html\" - Contains tabs and spaces" set result [util_convert_line_breaks_to_html $html] aa_false "Now html=\"$result\"" [regexp {\sinter spaces\s} $result] #convert single break set html "\r\n inter\r\nbreaks \r\n" aa_log "html= \"$html\" - Contains a single break" set result [util_convert_line_breaks_to_html $html] aa_false "Now html=\"$result\"" [regexp {inter\nspaces} $result] #convert paragraph break set html "\r\n inter\r\n\r\nbreaks \r\n" aa_log "html= \"$html\" - Contains a double break" set result [util_convert_line_breaks_to_html $html] aa_false "Now html=\"$result\"" [regexp {inter

    spaces} $result] #convert more than 2 breaks set html "\r\n inter\r\n\r\n\r\nbreaks \r\n" aa_log "html= \"$html\" - Contains more than 2 breaks" set result [util_convert_line_breaks_to_html $html] aa_false "Now html=\"$result\"" [regexp {inter\n\n\nspaces} $result] } aa_register_case -cats {api smoke} -procs {ad_quotehtml ad_unquotehtml} quote_unquote_html { Test if it quote and unquote html } { #quote html set html "\"<&text>\"" aa_log "Unquote html=$html" set result [ad_quotehtml $html] aa_true "Quoute html=$result" [string equal ""<&text>"" $result] #unquote html set html $result aa_log "Quote html=$html" set result [ad_unquotehtml $html] aa_true "Unquote html=$result" [string equal "\"<&text>\"" $result] } aa_register_case -cats {api smoke} -procs {ad_looks_like_html_p} ad_looks_like_html_p { Test if it guess the text supplied is html } { set html "Home Page" aa_log "A link html=$html" aa_true "Is html text" [ad_looks_like_html_p $html] set html "

    This is a paragraph

    " aa_log "A paragraph html=$html" aa_true "Is html text" [ad_looks_like_html_p $html] set html "This is
    a short text" aa_log "Some text with
    html=$html" aa_true "Is html text" [ad_looks_like_html_p $html] } aa_register_case -cats {api smoke} -procs {util_remove_html_tags} util_remove_html_tags { Test if it remove all between tags } { set html "

    some text to probe if it remove all between \"<\" and \">\"
    " set result [util_remove_html_tags $html] aa_true "Without all between \"<\" and \">\" html=\"$result\""\ [string equal "some text to probe if it remove all between \"\"" $result] } aa_register_case -cats {api smoke} -procs {ad_parse_html_attributes} ad_parse_html_attributes { Test if returns a list of attributes inside an HTML tag } { set pos 5 # Two attributes without values set html "" aa_log "A tag with two attributes without values - $html" set result [ad_parse_html_attributes $html $pos] aa_equals "Attributes - $result" $result {foo bar} # One Attribute with value and one whitout value set html "" aa_log "A tag with one Attribute with value and one whitout value - $html" set result [ad_parse_html_attributes $html $pos] aa_equals "Attributes - $result" $result {{foo bar} tob} # More attributes set html {} aa_log "A tag with one attribute between quotes - $html" set result [ad_parse_html_attributes $html $pos] aa_equals "Attributes - $result" $result {{foo bar} {greeting {welcome home}} {ja blah}} } aa_register_case -cats {api smoke} -procs {ad_html_text_convert} ad_text_html_convert_outlook_word_comments { Test is MS Word HTML Comments are stripped or not } { set html {} set result [ad_html_text_convert -from text/html -to text/plain $html] aa_equals "Standard HTML Comments cleaned $result" $result "" set html { } set result [ad_html_text_convert -from text/html -to text/plain $html] aa_equals "MS Word Comments cleaned $result" $result "" set html {Regular Text} set result [ad_html_text_convert -from text/html -to text/plain $html] aa_equals "Some HTML with Comment ok" $result "*Bold* _Italic_" } openacs-5.7.0/packages/acs-tcl/tcl/test/test-membership-rel-procs.tcl0000644000175000017500000000430010466373510025362 0ustar frankiefrankiead_library { Test Cases of Membership rel procs @author Cesar Hernandez (cesarhj@galileo.edu) @creation-date 2006-07-31 @arch-tag: 92464550-0231-4D33-8885-595623B00DB6 @cvs-id $Id: test-membership-rel-procs.tcl,v 1.2 2006/08/09 14:55:04 maltes Exp $ } aa_register_case -cats {api smoke} ad_proc_change_state_member { Test the proc change_state } { #we get a user_id as party_id set user_id [db_nextval acs_object_id_seq] aa_run_with_teardown -rollback -test_code { #Create the user array set user_info [twt::user::create -user_id $user_id] set rel_id [db_string get_rel_id "select max(rel_id) from acs_rels where object_id_two = :user_id" -default 0] #Try to change his state to approved aa_log "We change the state to approved" membership_rel::approve -rel_id $rel_id acs_user::get -user_id $user_id -array user #Verifying if the state was changed aa_true "Changed State to aprroved" \ [string equal $user(member_state) "approved"] #Try to change his state to banned aa_log "We change the state to banned" membership_rel::ban -rel_id $rel_id acs_user::get -user_id $user_id -array user #Verifying if the state was changed aa_true "Changed State to banned" \ [string equal $user(member_state) "banned"] #Try to change his state to rejected aa_log "We change the state to rejected" membership_rel::reject -rel_id $rel_id acs_user::get -user_id $user_id -array user #Verifying if the state was changed aa_true "Changed State to rejected" \ [string equal $user(member_state) "rejected"] #Try to change his state to unapproved aa_log "We change the state to unapproved" membership_rel::unapprove -rel_id $rel_id acs_user::get -user_id $user_id -array user #Verifying if the state was changed aa_true "Changed State to unapproved" \ [string equal $user(member_state) "needs approval"] #Try to change his state to deleted aa_log "We change the state to deleted" membership_rel::delete -rel_id $rel_id acs_user::get -user_id $user_id -array user #Verifying if the state was changed aa_true "Changed State to deleted" \ [string equal $user(member_state) "deleted"] } }openacs-5.7.0/packages/acs-tcl/tcl/test/application-data-link-procs.tcl0000644000175000017500000002157511320443575025653 0ustar frankiefrankiead_library { Tests for applicaiton data links } aa_register_case -cats api data_links_scan_links { Test scanning content for object URLs } { # get a new object_id from the sequence, this object will not exist set nonexistant_object_id [db_nextval "acs_object_id_seq"] set text {Some random text Some More Random Text /o/10 /file/11 /image/12 /o/[junk] /file/[junk] /image/[junk] /o/" /file/" /image/" /o/[ /file/[ /image/[ } append text " " aa_log "ad_url = '[ad_url]'" set links [application_data_link::scan_for_links -text $text] set correct_links [list 0] aa_log "Links = '${links}'" aa_true "Number of links found is correct" \ [expr {[llength $correct_links] eq [llength $links]}] } aa_register_case -cats api data_links_update_links { Test updating references, tests scan_for_links and delete_links in the process } { aa_run_with_teardown \ -rollback \ -test_code \ { # create some test objects set name [ns_mktemp "cr_item__XXXXXX"] for {set i 0} {$i<10} {incr i} { set o($i) [content::item::new \ -name ${name}_$i \ -title ${name}_$i] } # generate some text with links between the objects foreach n [array names o] { append text "\nTest Content Link to $o($n) Link \n" } # update the links foreach n [array names o] { application_data_link::update_links_from \ -object_id $o($n) \ -text $text } # scan for links and compare set correct_links [lsort \ [application_data_link::scan_for_links \ -text $text]] aa_true "Correct links is not empty" [llength $correct_links] foreach n [array names o] { set links [lsort \ [application_data_link::get_links_from \ -object_id $o($n)]] aa_true "Object \#${n} references correct" \ [expr {$correct_links eq $links}] } # now change the text and update one of the objects for {set i 0} {$i < 5} {incr i} { append new_text "\nTest Content Link to $o($i) /o/$o($i) \n" } for {set i 0} {$i < 5} {incr i} { application_data_link::update_links_from \ -object_id $o($i) \ -text $new_text } set new_correct_links [lsort \ [application_data_link::scan_for_links \ -text $new_text]] for {set i 0} {$i < 5} {incr i} { set links [lsort \ [application_data_link::get_links_from \ -object_id $o($i)]] aa_true "Object \#${i} updated references correct" \ [expr {$new_correct_links eq $links}] } } } aa_register_case -cats api data_links_scan_links_with_tag { Test scanning content for object URLs with relation tag } { # get a new object_id from the sequence, this object will not exist set nonexistant_object_id [db_nextval "acs_object_id_seq"] set text {Some random text Some More Random Text /o/10 /file/11 /image/12 /o/[junk] /file/[junk] /image/[junk] /o/" /file/" /image/" /o/[ /file/[ /image/[ } append text " " aa_log "ad_url = '[ad_url]'" set links [application_data_link::scan_for_links -text $text] set correct_links [list 0] aa_log "Links = '${links}'" aa_true "Number of links found is correct" \ [expr {[llength $correct_links] eq [llength $links]}] } aa_register_case -cats api data_links_update_links_with_tag { Test updating references, tests scan_for_links and delete_links in the process. Uses relation tags } { aa_run_with_teardown \ -rollback \ -test_code \ { # create some test objects set name [ns_mktemp "cr_item__XXXXXX"] for {set i 0} {$i<10} {incr i} { set o($i) [content::item::new \ -name ${name}_$i \ -title ${name}_$i] } # generate some text with links between the objects foreach n [array names o] { append text "\nTest Content Link to $o($n) Link \n" } # update the links foreach n [array names o] { application_data_link::update_links_from \ -object_id $o($n) \ -text $text \ -relation_tag tag } # scan for links and compare set correct_links [lsort \ [application_data_link::scan_for_links \ -text $text]] aa_true "Correct links is not empty" [llength $correct_links] foreach n [array names o] { set links [lsort \ [application_data_link::get_links_from \ -object_id $o($n) -relation_tag tag]] aa_true "Object \#${n} references correct" \ [expr {$correct_links eq $links}] } # now change the text and update one of the objects for {set i 0} {$i < 5} {incr i} { append new_text "\nTest Content Link to $o($i) /o/$o($i) \n" } for {set i 0} {$i < 5} {incr i} { application_data_link::update_links_from \ -object_id $o($i) \ -text $new_text \ -relation_tag tag } set new_correct_links [lsort \ [application_data_link::scan_for_links \ -text $new_text]] for {set i 0} {$i < 5} {incr i} { set links [lsort \ [application_data_link::get_links_from \ -object_id $o($i) \ -relation_tag tag]] aa_true "Object \#${i} updated references correct" \ [expr {$new_correct_links eq $links}] } } } aa_register_case -cats api data_links_with_tag { Test creating new link, exists test, get, get_linked and delete. Uses relation tags. } { aa_run_with_teardown \ -rollback \ -test_code \ { # create some test objects set name [ns_mktemp "cr_item__XXXXXX"] for {set i 0} {$i<6} {incr i} { set o($i) [content::item::new \ -name ${name}_$i \ -title ${name}_$i] } aa_log "Creating link between objects" application_data_link::new -this_object_id $o(0) -target_object_id $o(1) -relation_tag tag aa_true "Verify objects are linked" \ [application_data_link::link_exists \ -from_object_id $o(0) \ -to_object_id $o(1) \ -relation_tag tag] aa_log "Deleting links attached to first object" application_data_link::delete_links -object_id $o(0) aa_false "Verify objects are deleted" \ [application_data_link::link_exists \ -from_object_id $o(0) \ -to_object_id $o(1) \ -relation_tag tag] aa_log "Creating many links between objects" application_data_link::new -this_object_id $o(0) -target_object_id $o(1) -relation_tag tag1 application_data_link::new -this_object_id $o(0) -target_object_id $o(2) -relation_tag tag1 application_data_link::new -this_object_id $o(0) -target_object_id $o(3) -relation_tag tag2 application_data_link::new -this_object_id $o(3) -target_object_id $o(4) -relation_tag tag2 application_data_link::new -this_object_id $o(3) -target_object_id $o(5) -relation_tag tag2 aa_true "Verify link for tag1" [expr [llength [application_data_link::get_linked -from_object_id $o(0) \ -to_object_type [acs_object_type $o(0)] -relation_tag tag1]] == 2] aa_true "Verify link for tag2" [expr [llength [application_data_link::get_linked -from_object_id $o(3) \ -to_object_type [acs_object_type $o(3)] -relation_tag tag2]] == 3] aa_true "Verify content link" [expr [llength [application_data_link::get_linked_content -from_object_id $o(0) \ -to_content_type content_revision -relation_tag tag1]] == 2] aa_true "Verify links to one object with multiple link tags" \ [expr [llength [application_data_link::get -object_id $o(0) -relation_tag tag1]] == 2] aa_true "Verify links to one object with multiple link tags" \ [expr [llength [application_data_link::get -object_id $o(0) -relation_tag tag2]] == 1] } }openacs-5.7.0/packages/acs-tcl/tcl/test/navigation-procs.tcl0000755000175000017500000001621211144363303023632 0ustar frankiefrankiead_library { Tests that deal with the context bar creation. @author Juan Pablo Amaya jpamaya@unicauca.edu.co @creation-date 11 August 2006 } namespace eval navigation::test {} ad_proc navigation::test::context_bar_multirow_filter {} { Procuedure for the context_bar_multirow test filter } { aa_run_with_teardown -test_code { set testnode_1 [list "/navigation_test_node1/" "navigation_test_node1"] set testnode_2 [list "[lindex $testnode_1 0]navigation_test_node2/" "navigation_test_node2"] # Create hierarchy from the random created nodes db_1row query { select MIN(node_id) as first_node from site_nodes } set idp $first_node set idr_1 [site_node::new -name [lindex $testnode_1 1] -parent_id $idp] set idr_2 [site_node::new -name [lindex $testnode_2 1] -parent_id $idr_1] set from_node $first_node set node_id $idr_2 set context "last" set page [ad_parse_template -params [list [list from_node $from_node] [list node_id $node_id] [list context $context]] "/packages/acs-tcl/tcl/test/multirow-test"] site_node::delete -node_id $idr_2 site_node::delete -node_id $idr_1 } -teardown_code { site_node::delete -node_id $idr_2 site_node::delete -node_id $idr_1 } ns_return 200 text/html $page return filter_return } aa_register_case -cats { api smoke } -procs { ad_context_bar_html } ad_context_bar_html { Test if returns a html fragment from a list. } { set ref_list [list [list "/doc/doc0.html" "href0"] [list "/doc/doc1.html" "href1"] [list "/doc/doc2.html" "href2"]] set c {} set ref_list_print [foreach element $ref_list { append c [lindex $element 0] " " [lindex $element 1]\n}] set separator "-" aa_log "List with three references:\n\n$c\nseparator= \" - \" " aa_equals "" [ad_context_bar_html -separator $separator $ref_list] "[lindex [lindex $ref_list 0] 1] - [lindex [lindex $ref_list 1] 1] - [lindex [lindex $ref_list 2] 0] [lindex [lindex $ref_list 2] 1]" } aa_register_case -cats { api smoke } -procs { ad_context_bar } ad_context_bar { Test if returns a well formed context_bar in html format from a site node. } { aa_run_with_teardown -rollback -test_code { # Setup nodes from the context bar, create two random nodes to include set separator "-" set random [ad_generate_random_string] set testnode_1 [list "/$random/" $random] set random [ad_generate_random_string] set testnode_2 [list "[lindex $testnode_1 0]$random/" $random] set leave_node "ref_final" set root_node [list "/" \#acs-kernel.Main_Site\#] if { [string match "admin/*" [ad_conn extra_url]] } { set admin_node [list "[ad_conn package_url]admin/" "Administration"] } else { set admin_node "" } # Create hierarchy from the random created nodes db_1row query { select MIN(node_id) as first_node from site_nodes } set idp $first_node set idr_1 [site_node::new -name [lindex $testnode_1 1] -parent_id $idp] set idr_2 [site_node::new -name [lindex $testnode_2 1] -parent_id $idr_1] aa_log "Created two test sites nodes: testnode_1 = [lindex $testnode_1 1],testnode_2 = [lindex $testnode_2 1]\n\ntestnode_2 is a testnode_1 children" #----------------------------------------------------------------------- # Case 1: node_id = testnode_1 #----------------------------------------------------------------------- aa_log "Case 1: node_id = testnode_1" set bar_components [list $root_node $testnode_1 $admin_node] set context_barp "" foreach value $bar_components { append context_barp "" append context_barp [lindex $value 1] append context_barp "" append context_barp " $separator " } append context_barp "$leave_node" set context_bar [ad_context_bar -node_id $idr_1 -separator $separator $leave_node] # Test aa_true "Context_bar = $context_barp" [string equal $context_bar $context_barp] #----------------------------------------------------------------------- # Case 2: node_id = testnode_2 (testnode2 is a testnode_1 children) #----------------------------------------------------------------------- aa_log "Case 2: node_id = testnode_2 (testnode2 is a testnode_1 children)" set bar_components [list $root_node $testnode_1 $testnode_2 $admin_node] set context_barp "" foreach value $bar_components { append context_barp "" append context_barp [lindex $value 1] append context_barp "" append context_barp " $separator " } append context_barp "$leave_node" set context_bar [ad_context_bar -node_id $idr_2 -separator $separator $leave_node] aa_true "Context_bar = $context_barp" [string equal $context_bar $context_barp] #---------------------------------------------------------------------------- # Case 3: from_node = testnode_1 and node_id = testnode_2 #---------------------------------------------------------------------------- aa_log "Case 3: from_node = testnode_1 and node_id = testnode_2" set bar_components [list $testnode_1 $testnode_2 $admin_node] set context_barp "" foreach value $bar_components { append context_barp "" append context_barp [lindex $value 1] append context_barp "" append context_barp " $separator " } append context_barp "$leave_node" set context_bar [ad_context_bar -from_node $idr_1 -node_id $idr_2 -separator $separator $leave_node] aa_true "Context_bar = $context_barp" [string equal $context_bar $context_barp] } } aa_register_case -cats { api smoke web } -libraries tclwebtest -procs { ad_context_bar_multirow } ad_context_bar_multirow { Test if returns a well formed context_bar in html format from a site node in a multirow. } { # Setup nodes from the context bar, create two nodes to include set separator "" set testnode_1 [list "/navigation_test_node1/" "navigation_test_node1"] set testnode_2 [list "[lindex $testnode_1 0]navigation_test_node2/" "navigation_test_node2"] set root_node [list "/" "Main Site"] set last_node [list "" "last"] set bar_components [list $root_node $testnode_1 $testnode_2 $last_node] set context_barp "" foreach value $bar_components { append context_barp "" append context_barp [lindex $value 1] append context_barp "" } ad_register_filter postauth GET /test.testf navigation::test::context_bar_multirow_filter set server [twt::server_url] ::twt::do_request "$server/test.testf" aa_log "Filter page created: [tclwebtest::response url]\ shows the multirow" set response_body [::tclwebtest::response body] aa_equals "Context bar $context_barp" $response_body $context_barp } openacs-5.7.0/packages/acs-tcl/tcl/test/apm-parameter-test-procs.tcl0000644000175000017500000000270411352533030025176 0ustar frankiefrankiead_library { Testing for parameter registration @author Adrian Catalan (ykro@galileo.edu) @creation-date 2006-08-10 } aa_register_case -cats {api smoke} parameter_register_test { Test the registration of a parameter } { set parameter_id [db_nextval "acs_object_id_seq"] set parameter_name [ad_generate_random_string] set description "Description for the new parameter" set package_key "acs-tcl" set default_value "5" set datatype "number" set scope "instance" aa_log "Registering an instance parameter" apm_parameter_register -parameter_id $parameter_id -scope $scope $parameter_name $description $package_key $default_value $datatype set package_id [apm_package_id_from_key $package_key] aa_true "check apm_parameter_register instance parameter" [string equal [parameter::get -package_id $package_id -parameter $parameter_name] $default_value] aa_log "Unregistering an instance parameter" apm_parameter_unregister $parameter_id set scope "global" aa_log "Registering a global parameter" apm_parameter_register -parameter_id $parameter_id -scope $scope $parameter_name $description $package_key $default_value $datatype aa_true "check apm_parameter_register global parameter" [string equal [parameter::get_global_value -package_key $package_key -parameter $parameter_name] $default_value] aa_log "Unregistering an global parameter" apm_parameter_unregister $parameter_id } openacs-5.7.0/packages/acs-tcl/tcl/test/site-nodes-test-procs.tcl0000644000175000017500000001766410744624377024553 0ustar frankiefrankie# /packages/acs-tcl/tcl/test/site-nodes-test-procs.tcl ad_library { Test site node procs @author Vinod Kurup [vinod@kurup.com] @creation-date Mon Oct 20 16:16:04 2003 @cvs-id $Id: site-nodes-test-procs.tcl,v 1.5 2008/01/20 10:57:03 donb Exp $ } aa_register_case -cats { api } site_node_update_cache { Test site_node::update_cache } { aa_run_with_teardown -rollback -test_code { # 1) mount /doc1 /doc2 /doc1/doc3 set doc1_name [ad_generate_random_string] set doc2_name [ad_generate_random_string] set doc3_name [ad_generate_random_string] set node1_pkg_id [site_node::instantiate_and_mount \ -node_name $doc1_name \ -package_key acs-core-docs] set node1_node_id [site_node::get_node_id -url "/$doc1_name"] set node2_pkg_id [site_node::instantiate_and_mount \ -node_name $doc2_name \ -package_key acs-core-docs] set node2_node_id [site_node::get_node_id -url "/$doc2_name"] set node3_pkg_id [site_node::instantiate_and_mount \ -parent_node_id $node1_node_id \ -node_name $doc3_name \ -package_key acs-core-docs] set node3_node_id [site_node::get_node_id -url "/$doc1_name/$doc3_name"] set root_node_id [site_node::get_node_id -url /] aa_equals "Verify url /doc1 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc1_name/" aa_equals "Verify url /doc1/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc1_name/$doc3_name/" aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" # 2) rename /doc1 => doc4: Test /doc4 /doc4/doc3 /doc2 set doc4_name [ad_generate_random_string] site_node::rename -node_id $node1_node_id -name $doc4_name aa_equals "Check new url /doc4" [site_node::get_node_id -url "/$doc4_name"] $node1_node_id aa_equals "Check new url /doc4/doc3" [site_node::get_node_id -url "/$doc4_name/$doc3_name"] $node3_node_id aa_equals "Check old url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id aa_equals "Make sure old url /doc1 now matches /" [site_node::get_node_id -url "/$doc1_name/"] $root_node_id aa_equals "Make sure old url /doc1/doc3 now matches /" [site_node::get_node_id -url "/$doc1_name/$doc3_name/"] $root_node_id aa_equals "Verify url /doc4 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc4_name/" aa_equals "Verify url /doc4/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc4_name/$doc3_name/" aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" # 3) init_cache: Test /doc5 /doc5/doc3 /doc2 set doc5_name [ad_generate_random_string] db_dml rename_node1 { update site_nodes set name = :doc5_name where node_id = :node1_node_id } site_node::init_cache aa_equals "Check url /doc5" [site_node::get_node_id -url "/$doc5_name"] $node1_node_id aa_equals "Check url /doc5/doc3" [site_node::get_node_id -url "/$doc5_name/$doc3_name"] $node3_node_id aa_equals "Check url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id aa_equals "Make sure old url /doc1 now matches" [site_node::get_node_id -url "/$doc1_name/"] $root_node_id aa_equals "Make sure old url /doc1/doc3 now matches" [site_node::get_node_id -url "/$doc1_name/$doc3_name/"] $root_node_id aa_equals "Make sure old url /doc4 now matches" [site_node::get_node_id -url "/$doc4_name/"] $root_node_id aa_equals "Make sure old url /doc4/doc3 now matches" [site_node::get_node_id -url "/$doc4_name/$doc3_name/"] $root_node_id aa_equals "Verify url /doc5 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc5_name/" aa_equals "Verify url /doc5/doc3 for node3" [site_node::get_url -node_id $node3_node_id] "/$doc5_name/$doc3_name/" aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" # 4) delete doc3: Test /doc5 /doc2, nonexisting /doc5/doc3 site_node::unmount -node_id $node3_node_id site_node::delete -node_id $node3_node_id aa_equals "Check url /doc5" [site_node::get_node_id -url "/$doc5_name"] $node1_node_id aa_equals "Check url /doc2" [site_node::get_node_id -url "/$doc2_name"] $node2_node_id aa_equals "Make sure old url /doc5/doc3 now matches /doc5" [site_node::get_node_id -url "/$doc5_name/$doc3_name/"] $node1_node_id aa_equals "Verify url /doc5 for node1" [site_node::get_url -node_id $node1_node_id] "/$doc5_name/" aa_equals "Verify url /doc2 for node2" [site_node::get_url -node_id $node2_node_id] "/$doc2_name/" } } aa_register_case -cats { api } site_node_closest_ancestor_package { Test site_node::closest_ancestor_package } { aa_run_with_teardown -rollback -test_code { # 1) set up the site-map # /{acs-core-docs}/{empty-folder} # node-names generated randomly set doc_name [ad_generate_random_string] set folder_name [ad_generate_random_string] # get root package_id and node_id set root_pkg_id [subsite::main_site_id] set root_node_id [site_node::get_node_id -url /] # create the acs-core-docs instance set doc_pkg_id [site_node::instantiate_and_mount \ -node_name $doc_name \ -package_key acs-core-docs] set doc_node_id [site_node::get_node_id -url "/$doc_name"] # create a folder underneate acs-core-docs set folder_node_id [site_node::new \ -parent_id $doc_node_id \ -name $folder_name] # 2) test -url parameter # test doc's parent set package_id [site_node::closest_ancestor_package -url /$doc_name] aa_equals "Doc's parent is correct" $package_id $root_pkg_id # test folder's parent set package_id [site_node::closest_ancestor_package \ -url /$doc_name/$folder_name] aa_equals "Folder's parent is correct" $package_id $doc_pkg_id # 3) test -node_id parameter # test doc's parent set package_id [site_node::closest_ancestor_package \ -node_id $doc_node_id] aa_equals "Doc's parent is correct" $package_id $root_pkg_id # test folder's parent set package_id [site_node::closest_ancestor_package \ -node_id $folder_node_id] aa_equals "Folder's parent is correct" $package_id $doc_pkg_id # find ancestors of the main-site (should fail) set package_id [site_node::closest_ancestor_package \ -node_id $root_node_id] aa_equals "Root has no ancestors" $package_id "" # 4) test -package_key parameter # find ancestors of doc which are subsites set package_id [site_node::closest_ancestor_package \ -node_id $doc_node_id \ -package_key acs-subsite] aa_equals "Doc ancestor is a subsite" $package_id $root_pkg_id # find ancestors of doc which are photo-albums (should fail) set package_id [site_node::closest_ancestor_package \ -node_id $doc_node_id \ -package_key photo-album] aa_equals "Doc has no photo-album ancestors" $package_id "" # find ancestors of folder which are subsites (2 levels up) set package_id [site_node::closest_ancestor_package \ -node_id $folder_node_id \ -package_key acs-subsite] aa_equals "Folder's closest subsite ancestor is root" \ $package_id $root_pkg_id # 5) test -self parameter # find ancestors of doc, including doc in the search set package_id [site_node::closest_ancestor_package \ -node_id $doc_node_id \ -package_key acs-core-docs \ -include_self] aa_equals "Doc found itself" $package_id $doc_pkg_id } } openacs-5.7.0/packages/acs-tcl/tcl/defs-procs-oracle.xql0000644000175000017500000000070610540362770022726 0ustar frankiefrankie oracle8.1.6 insert into query_strings (query_date, query_string, subsection, n_results, user_id) values (sysdate, :query_string, :subsection, :n_results, :user_id) openacs-5.7.0/packages/acs-tcl/tcl/community-core-procs-oracle.xql0000644000175000017500000000773110467045076024771 0ustar frankiefrankie oracle8.1.6 begin :1 := acs.add_user( user_id => :user_id, email => :email, url => :url, authority_id => :authority_id, username => :username, first_names => :first_names, last_name => :last_name, screen_name => :screen_name, password => :hashed_password, salt => :salt, creation_user => :creation_user, creation_ip => :peeraddr, email_verified_p => :email_verified_p, member_state => :member_state ); end; begin acs.remove_user( user_id => :user_id ); end; begin person.del( person_id => :person_id ); end; select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id from cc_users u where lower(nvl(u.first_names || ' ', '') || nvl(u.last_name || ' ', '') || u.email || ' ' || nvl(u.screen_name, '')) like lower('%'||:value||'%') order by name select user_id, username, authority_id, first_names, last_name, first_names || ' ' || last_name as name, email, url, screen_name, priv_name, priv_email, email_verified_p, email_bouncing_p, no_alerts_until, last_visit, to_char(last_visit, 'YYYY-MM-DD HH24:MI:SS') as last_visit_ansi, second_to_last_visit, to_char(second_to_last_visit, 'YYYY-MM-DD HH24:MI:SS') as second_to_last_visit_ansi, n_sessions, password_question, password_answer, password_changed_date, member_state, rel_id, trunc(sysdate - password_changed_date) as password_age_days, creation_date, creation_ip from cc_users where user_id = :user_id select user_id, username, authority_id, first_names, last_name, first_names || ' ' || last_name as name, email, url, screen_name, priv_name, priv_email, email_verified_p, email_bouncing_p, no_alerts_until, last_visit, to_char(last_visit, 'YYYY-MM-DD HH24:MI:SS') as last_visit_ansi, second_to_last_visit, to_char(second_to_last_visit, 'YYYY-MM-DD HH24:MI:SS') as second_to_last_visit_ansi, n_sessions, password_question, password_answer, password_changed_date, member_state, rel_id, trunc(sysdate - password_changed_date) as password_age_days, creation_date, creation_ip from cc_users where authority_id = :authority_id and lower(username) = lower(:username) openacs-5.7.0/packages/acs-tcl/tcl/acs-private-data-procs.tcl0000644000175000017500000000330011140471413023626 0ustar frankiefrankie ad_library { Tcl procs for managing privacy @author ben@openforce.net @creation-date 2000-12-02 @cvs-id $Id: acs-private-data-procs.tcl,v 1.7 2009/01/30 03:24:59 donb Exp $ } namespace eval acs_privacy { ad_proc -public privacy_control_enabled_p {} { Returns whether privacy control is turned on or not. This is provided in order to have complete backwards compatibility with past behaviors, where private information was in no way regulated. } { # If no parameter set, then we assume privacy control is DISABLED return [parameter::get -package_id [ad_acs_kernel_id] -parameter PrivacyControlEnabledP -default 0] } ad_proc -public privacy_control_set {val} { set the privacy control } { return [parameter::set_value -value $val -package_id [ad_acs_kernel_id] -parameter PrivacyControlEnabledP] } ad_proc -public user_can_read_private_data_p { {-user_id ""} {-object_id:required} } { check if a user can access an object's private data } { if {[privacy_control_enabled_p]} { return [ad_permission_p -user_id $user_id $object_id read_private_data] } else { # backwards compatibility return 1 } } ad_proc -public set_user_read_private_data { {-user_id:required} {-object_id:required} {-value:required} } { grant permission to access private data } { if { [template::util::is_true $value] } { ad_permission_grant $user_id $object_id read_private_data } else { ad_permission_revoke $user_id $object_id read_private_data } } } openacs-5.7.0/packages/acs-tcl/tcl/exception-procs.tcl0000644000175000017500000000244410551254404022513 0ustar frankiefrankiead_library { @author rhs@mit.edu @creation-date 2000-09-09 @cvs-id $Id: exception-procs.tcl,v 1.3 2007/01/10 21:22:12 gustafn Exp $ } ad_proc -private ad_raise {exception {value ""}} { @author rhs@mit.edu @creation-date 2000-09-09 Raise an exception. If you use this I will kill you. } { return -code error -errorcode [list "AD" "EXCEPTION" $exception] $value } ad_proc -private ad_try {code args} { @author rhs@mit.edu @creation-date 2000-09-09 Executes $code, catches any exceptions thrown by ad_raise and runs any matching exception handlers. If you use this I will kill you. @see with_finally @see with_catch } { global errorInfo errorCode if {[set errno [catch {uplevel $code} result]]} { if {$errno == 1 && [string equal [lindex $errorCode 0] "AD"] && \ [string equal [lindex $errorCode 1] "EXCEPTION"]} { set exception [lindex $errorCode 2] set matched 0 for {set i 0} {$i < [llength $args]} {incr i 3} { if {[string match [lindex $args $i] $exception]} { set matched 1 break } } if {$matched} { upvar [lindex $args [expr {$i + 1}]] var set var $result set errno [catch {uplevel [lindex $args [expr {$i + 2}]]} result] } } return -code $errno -errorcode $errorCode -errorinfo $errorInfo $result } } openacs-5.7.0/packages/acs-tcl/tcl/openacs-kernel-procs.tcl0000644000175000017500000001060310763244725023431 0ustar frankiefrankie ad_library { A library of additional OpenACS utilities @author ben@openforce @creation-date 2002-03-05 @cvs-id $Id: openacs-kernel-procs.tcl,v 1.10 2008/03/04 13:08:37 gustafn Exp $ } namespace eval oacs_util {} ad_proc -public oacs_util::process_objects_csv { {-object_type:required} {-file:required} {-header_line 1} {-override_headers {}} {-constants ""} } { This processes a CSV of objects, taking the csv and calling package_instantiate_object for each one. @return a list of the created object_ids } { # FIXME: We should catch the error here set csv_stream [open $file r] # Check if there are headers if {$override_headers ne ""} { set headers $override_headers } else { if {!$header_line} { return -code error "There is no header!" } # get the headers ns_getcsv $csv_stream headers } set list_of_object_ids [list] # Process the file db_transaction { while {1} { # Get a line set n_fields [ns_getcsv $csv_stream one_line] # end of things if {$n_fields == -1} { break } # Process the row set extra_vars [ns_set create] for {set i 0} {$i < $n_fields} {incr i} { set varname [string tolower [lindex $headers $i]] set varvalue [lindex $one_line $i] # Set the value ns_log debug "oacs_util::process_objects_csv: setting $varname to $varvalue" ns_set put $extra_vars $varname $varvalue } # Add in the constants if {$constants ne ""} { # This modifies extra_vars, without touching constants ns_set merge $constants $extra_vars } # Create object and go for it set object_id [package_instantiate_object -extra_vars $extra_vars $object_type] lappend list_of_object_ids $object_id # Clean Up ns_set free $extra_vars } } close $csv_stream # Return the list of objects return $list_of_object_ids } ad_proc -public oacs_util::csv_foreach { {-file:required} {-header_line 1} {-override_headers {}} {-array_name:required} code_block } { reads a csv and executes code block for each row in the csv. @param file the csv file to read. @param header_line the line with the list of var names @param override_headers the list of variables in the csv @param array_name the name of the array to set with the values from the csv as each line is read. } { # FIXME: We should catch the error here set csv_stream [open $file r] # Check if there are headers if {$override_headers ne ""} { set headers $override_headers } else { if {!$header_line} { return -code error "There is no header!" } # get the headers ns_getcsv $csv_stream headers } # provide access to errorInfo and errorCode global errorInfo errorCode # Upvar Magic! upvar 1 $array_name row_array while {1} { # Get a line set n_fields [ns_getcsv $csv_stream one_line] # end of things if {$n_fields == -1} { break } # Process the row for {set i 0} {$i < $n_fields} {incr i} { set varname [string tolower [lindex $headers $i]] set varvalue [lindex $one_line $i] set row_array($varname) $varvalue } # Now we are ready to process the code block set errno [catch { uplevel 1 $code_block } error] if {$errno > 0} { close $csv_stream } # handle error, return, break, continue # (source: http://wiki.tcl.tk/unless last case) switch -exact -- $errno { 0 {} 1 {return -code error -errorinfo $errorInfo \ -errorcode $errorCode $error} 2 {return $error} 3 {break} 4 {} default {return -code $errno $error} } } } ad_proc -public oacs_util::vars_to_ns_set { {-ns_set:required} {-var_list:required} } { Does an ns_set put on each variable named in var_list @param var_list list of variable names in the calling scope @param ns_set an ns_set id that already exists. } { foreach var $var_list { upvar $var one_var ns_set put $ns_set $var $one_var } } openacs-5.7.0/packages/acs-tcl/tcl/membership-rel-procs-postgresql.xql0000644000175000017500000000225710440426473025661 0ustar frankiefrankie postgresql7.1 begin return membership_rel__approve(:rel_id); end; begin return membership_rel__ban(:rel_id); end; begin return membership_rel__deleted(:rel_id); end; begin return membership_rel__reject(:rel_id); end; begin return membership_rel__unapprove(:rel_id); end; begin return membership_rel__merge(:rel_id); end; openacs-5.7.0/packages/acs-tcl/tcl/admin-init.tcl0000644000175000017500000000313410070240710021406 0ustar frankiefrankiead_library { security filters for the admin pages. @creation-date 18 Nov 1998 @author Allen Pulsifer (pulsifer@mediaone.net) @cvs-id $Id: admin-init.tcl,v 1.8 2004/06/29 10:17:44 jeffd Exp $ } # This can be very time consuming on a large site and may be # disabled by setting RegisterRestrictToSSLFilters in the kernel params. if { [security::https_available_p] && [parameter::get -package_id [ad_acs_kernel_id] -parameter RegisterRestrictToSSLFilters -default 1]} { set admin_ssl_filters_installed_p 1 db_foreach path_select {} { ns_log Notice "admin-init.tcl: Processing RestrictToSSL for $url" foreach pattern [parameter::get -package_id $package_id -parameter RestrictToSSL] { ad_register_filter preauth GET "$url$pattern" ad_restrict_to_https ns_log Notice "admin-init.tcl: URLs matching \"$url$pattern\" are restricted to SSL" } } db_release_unused_handles } # if the kernel param is on, then these filters will be registered. after that, # a subsite param controls whether that subsite is restricted or not if { [parameter::get -package_id [ad_acs_kernel_id] -parameter RegisterRestrictEntireServerToRegisteredUsersFilters -default 0]} { db_foreach path_select {} { ns_log Notice "admin-init.tcl: Registering ad_restrict_entire_server_to_registered_users for ${url}*" ad_register_filter preauth GET "${url}*" ad_restrict_entire_server_to_registered_users ad_register_filter preauth POST "${url}*" ad_restrict_entire_server_to_registered_users ad_register_filter preauth HEAD "${url}*" ad_restrict_entire_server_to_registered_users } } openacs-5.7.0/packages/acs-tcl/tcl/community-core-procs.tcl0000644000175000017500000005027211351666647023510 0ustar frankiefrankiead_library { Community routines (dealing with users, parties, etc.). @author Jon Salz (jsalz@arsdigita.com) @creation-date 11 Aug 2000 @cvs-id $Id: community-core-procs.tcl,v 1.60 2010/03/22 13:16:23 emmar Exp $ } namespace eval party {} namespace eval person {} namespace eval acs_user {} ad_proc -private cc_lookup_screen_name_user { screen_name } { return [db_string user_select {*SQL*} -default {}] } ad_proc cc_screen_name_user { screen_name } { Returns the user ID for a particular screen name, or an empty string if none exists. } { return [util_memoize [list cc_lookup_screen_name_user $screen_name]] } ad_proc -private cc_lookup_email_user { email } { Return the user_id of a user given the email. Returns the empty string if no such user exists. } { return [db_string user_select {*SQL*} -default {}] } ad_proc -public cc_email_from_party { party_id } { @return The email address of the indicated party. } { return [db_string email_from_party {*SQL*} -default {}] } ad_proc cc_email_user { email } { Returns the user ID for a particular email address, or an empty string if none exists. } { return [util_memoize [list cc_lookup_email_user $email]] } ad_proc -private cc_lookup_name_group { name } { return [db_string group_select {*SQL*} -default {}] } ad_proc cc_name_to_group { name } { Returns the group ID for a particular name, or an empty string if none exists. } { return [util_memoize [list cc_lookup_name_group $name]] } ad_proc -deprecated ad_user_new { email first_names last_name password password_question password_answer {url ""} {email_verified_p "t"} {member_state "approved"} {user_id ""} {username ""} {authority_id ""} {screen_name ""} } { Creates a new user in the system. The user_id can be specified as an argument to enable double click protection. If this procedure succeeds, returns the new user_id. Otherwise, returns 0. @see auth::create_user @see auth::create_local_account } { if { $user_id eq "" } { set user_id [db_nextval acs_object_id_seq] } if { $password_question eq "" } { set password_question [db_null] } if { $password_answer eq "" } { set password_answer [db_null] } if { $url eq "" } { set url [db_null] } set creation_user "" set peeraddr "" # This may fail, either because there's no connection, or because # we're in the bootstrap-installer, at which point [ad_conn user_id] is undefined. catch { set creation_user [ad_conn user_id] set peeraddr [ad_conn peeraddr] } set salt [sec_random_token] set hashed_password [ns_sha1 "$password$salt"] set error_p 0 db_transaction { set user_id [db_exec_plsql user_insert {}] # set password_question, password_answer db_dml update_question_answer {*SQL*} if {[catch { # Call the extension acs_user_extension::user_new -user_id $user_id } errmsg]} { # At this point, we don't want the user addition to fail # if some extension is screwing things up } } on_error { # we got an error. log it and signal failure. global errorInfo ns_log Error "Problem creating a new user: $errorInfo" set error_p 1 } if { $error_p } { return 0 } # success. return $user_id } ad_proc -public person::person_p { {-party_id:required} } { is this party a person? Cached } { return [util_memoize [list ::person::person_p_not_cached -party_id $party_id]] } ad_proc -public person::person_p_not_cached { {-party_id:required} } { is this party a person? Cached } { if {[db_0or1row contact_person_exists_p {select '1' from persons where person_id = :party_id}]} { return 1 } else { return 0 } } ad_proc -public person::new { {-first_names:required} {-last_name:required} {-email {}} } { create a new person } { set extra_vars [ns_set create] ns_set put $extra_vars first_names $first_names ns_set put $extra_vars last_name $last_name ns_set put $extra_vars email $email set object_type "person" return [package_instantiate_object -extra_vars $extra_vars $object_type] } ad_proc -public person::delete { {-person_id:required} } { delete a person } { db_exec_plsql delete_person {} } ad_proc -public person::get { {-person_id:required} } { get info for a person as a tcl array in list form } { db_1row get_person {} set person(person_id) $person_id set person(first_names) $first_names set person(last_name) $last_name return [array get person] } ad_proc -public person::name { {-person_id ""} {-email ""} } { get the name of a person. Cached. } { if {$person_id eq "" && $email eq ""} { error "You need to provide either person_id or email" } elseif {"" ne $person_id && "" ne $email } { error "Only provide provide person_id OR email, not both" } else { return [util_memoize [list person::name_not_cached -person_id $person_id -email $email]] } } ad_proc -public person::name_flush { {-person_id:required} {-email ""} } { Flush the person::name cache. } { util_memoize_flush [list person::name_not_cached -person_id $person_id -email $email] acs_user::flush_cache -user_id $person_id } ad_proc -public person::name_not_cached { {-person_id ""} {-email ""} } { get the name of a person } { if {$email eq ""} { db_1row get_person_name {} } else { # As the old functionality returned an error, but I want an empty string for e-mail # Therefore for emails we use db_string set person_name [db_string get_party_name {} -default ""] } return $person_name } ad_proc -public person::update { {-person_id:required} {-first_names:required} {-last_name:required} } { update the name of a person } { db_dml update_person {} db_dml update_object_title {} name_flush -person_id $person_id } # DRB: Though I've moved the bio field to type specific rather than generic storage, I've # maintained the API semantics exactly as they were before mostly in order to make upgrade # possible. In the future, the number of database hits can be diminished by getting rid of # the seperate queries for bio stuff. However, I have removed bio_mime_type because it's # unused and unsupported in the existing code. ad_proc -public person::get_bio { {-person_id {}} {-exists_var {}} } { Get the value of the user's bio(graphy) field. @option person_id The person_id of the person to get the bio for. Leave blank for currently logged in user. @option exists_var The name of a variable in the caller's namespace, which will be set to 1 if the bio column is not null. Leave blank if you're not interested in this information. @return The bio of the user as a text string. @author Lars Pind (lars@collaboraid.biz) } { if { $person_id eq "" } { set person_id [ad_conn user_id] } if { $exists_var ne "" } { upvar $exists_var exists_p } db_1row select_bio {} set exists_p [expr {$bio ne ""}] return $bio } ad_proc -public person::update_bio { {-person_id:required} {-bio:required} } { Update the bio for a person. @param person_id The ID of the person to edit bio for @param bio The new bio for the person @author Lars Pind (lars@collaboraid.biz) } { db_dml update_bio {} } ad_proc -public acs_user::change_state { {-user_id:required} {-state:required} } { Change the membership state of a user. } { set rel_id [db_string select_rel_id {*SQL*} -default {}] if {$rel_id eq ""} { return } membership_rel::change_state -rel_id $rel_id -state $state } ad_proc -public acs_user::approve { {-user_id:required} } { Approve a user } { change_state -user_id $user_id -state "approved" } ad_proc -public acs_user::ban { {-user_id:required} } { Ban a user } { change_state -user_id $user_id -state "banned" } ad_proc -public acs_user::reject { {-user_id:required} } { Reject a user } { change_state -user_id $user_id -state "rejected" } ad_proc -public acs_user::delete { {-user_id:required} {-permanent:boolean} } { Delete a user @param permanent If provided the user will be deleted permanently from the database. Otherwise the user state will merely be set to "deleted". } { if { ! $permanent_p } { change_state -user_id $user_id -state "deleted" acs_user::flush_cache -user_id $user_id } else { db_exec_plsql permanent_delete {} } } ad_proc -public acs_user::unapprove { {-user_id:required} } { Unapprove a user } { change_state -user_id $user_id -state "needs approval" } ad_proc -public acs_user::get_by_username { {-authority_id ""} {-username:required} } { Returns user_id from authority and username. Returns the empty string if no user found. @param authority_id The authority. Defaults to local authority. @param username The username of the user you're trying to find. @return user_id of the user, or the empty string if no user found. } { # Default to local authority if { $authority_id eq "" } { set authority_id [auth::authority::local] } set user_id [util_memoize [list acs_user::get_by_username_not_cached -authority_id $authority_id -username $username]] if {$user_id eq ""} { util_memoize_flush [list acs_user::get_by_username_not_cached -authority_id $authority_id -username $username] } return $user_id } ad_proc -public acs_user::get_by_username_not_cached { {-authority_id:required} {-username:required} } { Returns user_id from authority and username. Returns the empty string if no user found. @param authority_id The authority. Defaults to local authority. @param username The username of the user you're trying to find. @return user_id of the user, or the empty string if no user found. } { return [db_string user_id_from_username {} -default {}] } ad_proc -public acs_user::get { {-user_id {}} {-authority_id {}} {-username {}} {-array:required} {-include_bio:boolean} } { Get basic information about a user. Uses util_memoize to cache info from the database. You may supply either user_id, or username. If you supply username, you may also supply authority_id, or you may leave it out, in which case it defaults to the local authority. If you supply neither user_id nor username, and we have a connection, the currently logged in user will be assumed. @option user_id The user_id of the user to get the bio for. Leave blank for current user. @option include_bio Whether to include the bio in the user information @param array The name of an array into which you want the information put. The attributes returned are:
    • user_id
    • username
    • authority_id
    • first_names
    • last_name
    • name (first_names last_name)
    • email
    • url
    • screen_name
    • priv_name
    • priv_email
    • email_verified_p
    • email_bouncing_p
    • no_alerts_until
    • last_visit
    • second_to_last_visit
    • n_sessions
    • password_question
    • password_answer
    • password_changed_date
    • member_state
    • rel_id
    • bio (if -include_bio switch is present)
    @author Lars Pind (lars@collaboraid.biz) } { if { $user_id eq "" } { if { $username eq "" } { set user_id [ad_conn user_id] } else { if { $authority_id eq "" } { set authority_id [auth::authority::local] } } } upvar $array row if { $user_id ne "" } { array set row [util_memoize [list acs_user::get_from_user_id_not_cached $user_id] [cache_timeout]] } else { array set row [util_memoize [list acs_user::get_from_username_not_cached $username $authority_id] [cache_timeout]] set user_id $row(user_id) } if { $include_bio_p } { set row(bio) [person::get_bio -person_id $user_id] } } ad_proc -private acs_user::get_from_user_id_not_cached { user_id } { Returns an array list with user info from the database. Should never be called from application code. Use acs_user::get instead. @author Peter Marklund } { db_1row select_user_info {*SQL*} -column_array row return [array get row] } ad_proc -private acs_user::get_from_username_not_cached { username authority_id } { Returns an array list with user info from the database. Should never be called from application code. Use acs_user::get instead. @author Peter Marklund } { db_1row select_user_info {*SQL*} -column_array row return [array get row] } ad_proc -private acs_user::cache_timeout {} { Returns the number of seconds the user info cache is kept. @author Peter Marklund } { # TODO: This should maybe be an APM parameter return 3600 } ad_proc -public acs_user::flush_cache { {-user_id:required} } { Flush the acs_user::get cache for the given user_id. @author Peter Marklund } { util_memoize_flush [list acs_user::get_from_user_id_not_cached $user_id] # get username and authority_id so we can flush the get_from_username_not_cached proc if { ![catch { acs_user::get -user_id $user_id -array user }] } { util_memoize_flush [list acs_user::get_from_username_not_cached $user(username) $user(authority_id)] util_memoize_flush [list acs_user::get_by_username_not_cached -authority_id $user(authority_id) -username $user(username)] } } ad_proc -public acs_user::get_element { {-user_id {}} {-authority_id {}} {-username {}} {-element:required} } { Get a particular element from the basic information about a user returned by acs_user::get. Throws an error if the element does not exist. @option user_id The user_id of the user to get the bio for. Leave blank for current user. @option element Which element you want to retrieve. @return The element asked for. @see acs_user::get } { acs_user::get \ -user_id $user_id \ -authority_id $authority_id \ -username $username \ -array row \ -include_bio=[string equal $element "bio"] return $row($element) } ad_proc -public acs_user::update { {-user_id:required} {-authority_id} {-username} {-screen_name} {-password_question} {-password_answer} {-email_verified_p} } { Update information about a user. Feel free to expand this with more switches later as needed, as long as they're optional. @param user_id The ID of the user to edit @option authority_id Authortiy @option username Username @option screen_name The new screen_name for the user @option password_question The new password_question for the user @option password_answer The new password_question for the user @option email_verified_p Whether the email address has been verified @author Lars Pind (lars@collaboraid.biz) } { set cols [list] foreach var { authority_id username screen_name password_question password_answer email_verified_p } { if { [info exists $var] } { lappend cols "$var = :$var" } } db_dml user_update {} flush_cache -user_id $user_id } ad_proc -public acs_user::get_user_id_by_screen_name { {-screen_name:required} } { Returns the user_id from a screen_name, or empty string if no user found. Searches all users, including banned, deleted, unapproved, etc. } { return [db_string select_user_id_by_screen_name {*SQL*} -default {}] } ad_proc -public acs_user::site_wide_admin_p { {-user_id ""} } { Return 1 if the specified user (defaults to logged in user) is site-wide administrator and 0 otherwise. @param user_id The id of the user to check for admin privilege. @author Peter Marklund } { if { $user_id eq ""} { set user_id [ad_conn user_id] } return [permission::permission_p -party_id $user_id \ -object_id [acs_lookup_magic_object security_context_root] \ -privilege "admin"] } ad_proc -public acs_user::registered_user_p { {-user_id ""} } { Return 1 if the specified user (defaults to logged in user) is a registered user and 0 otherwise. A registered user is a user who is in the view registered_users and this is primarily true for any user who is approved and has a verified e-mail. @param user_id The id of the user to check. @author Malte Sussdorff (malte.sussdorff@cognovis.de) } { if { $user_id eq ""} { set user_id [ad_conn user_id] } return [db_string registered_user_p {} -default 0] } ad_proc -public acs_user::ScreenName {} { Get the value of the ScreenName parameter. Checked to ensure that it only returns none, solicit, or require. } { set value [parameter::get -parameter ScreenName -package_id [ad_acs_kernel_id] -default "solicit"] if { [lsearch { none solicit require } $value] == -1 } { ns_log Error "acs-kernel.ScreenName parameter invalid. Set to '$value', should be one of none, solicit, or require." return "solicit" } else { return $value } } ad_proc -public party::update { {-party_id:required} {-email} {-url} } { Update information about a party. @param party_id The ID of the party to edit @param email The new email for the party @param url The new URL for the party @author Lars Pind (lars@collaboraid.biz) } { set cols [list] foreach var { email url } { if { [info exists $var] } { lappend cols "$var = :$var" } } db_dml party_update {} if {[info exists email]} { db_dml object_title_update {} } acs_user::flush_cache -user_id $party_id } ad_proc -public party::get_by_email { {-email:required} } { Return the party_id of the party with the given email. Uses a lowercase comparison as we don't allow for parties to have emails that only differ in case. Returns empty string if no party found. @return party_id } { # return [db_string select_party_id {*SQL*} -default ""] # The following query is identical in the result as the one above # It just takes into account that some applications (like contacts) make email not unique # Instead of overwriting this procedure in those packages, I changed it here, as the functionality # is unchanged. return [lindex [db_list select_party_id {}] 0] } ad_proc -public party::approved_members { {-party_id:required} {-object_type ""} } { Get a list of approved members of the given party. @param party_id The id of the party to get members for @param object_type Restrict to only members of this object type. For example, if you are only interested in users, set to "user". @author Peter Marklund } { if { $object_type ne "" } { set from_clause ", acs_objects ao" set where_clause "and pamm.member_id = ao.object_id and ao.object_type = :object_type" } return [db_list select_party_members " select pamm.member_id from party_approved_member_map pamm $from_clause where pamm.party_id = :party_id $where_clause"] } ad_proc -public acs_user::get_portrait_id { {-user_id:required} } { Return the image_id of the portrait of a user, if it does not exist, return 0 @param user_id user_id of the user for whom we need the portrait } { return [util_memoize [list acs_user::get_portrait_id_not_cached -user_id $user_id] 600] } ad_proc -public acs_user::get_portrait_id_not_cached { {-user_id:required} } { Return the image_id of the portrait of a user, if it does not exist, return 0 @param user_id user_id of the user for whom we need the portrait } { return [db_string get_item_id "" -default 0] } openacs-5.7.0/packages/acs-tcl/tcl/community-core-procs.xql0000644000175000017500000001122511253305221023500 0ustar frankiefrankie select user_id from acs_users_all where lower(screen_name) = lower(:screen_name) select user_id from acs_users_all where lower(email) = lower(:email) select email from parties where party_id = :party_id select group_id from groups where group_name = :name select first_names, last_name from persons where person_id = :person_id update persons set first_names = :first_names, last_name = :last_name where person_id = :person_id update acs_objects set title = :first_names || ' ' || :last_name where object_id = :person_id select distinct first_names||' '||last_name as person_name from persons where person_id = :person_id select distinct first_names||' '||last_name as person_name from persons, parties where person_id = party_id and email = :email select bio from persons where person_id = :person_id update persons set bio = :bio where person_id = :person_id update users set [join $cols ", "] where user_id = :user_id select user_id from users where lower(username) = lower(:username) and authority_id =:authority_id select 1 from registered_users where user_id = :user_id update parties set [join $cols ", "] where party_id = :party_id update acs_objects set title = :email where object_id = :party_id and object_type = 'party' select party_id from parties where lower(email) = lower(:email) select user_id from users where lower(screen_name) = lower(:screen_name) select rel_id from cc_users where user_id = :user_id update users set password_question = :password_question, password_answer = :password_answer where user_id = :user_id select c.item_id from acs_rels a, cr_items c where a.object_id_two = c.item_id and a.object_id_one = :user_id and a.rel_type = 'user_portrait_rel' openacs-5.7.0/packages/acs-tcl/tcl/navigation-callback-procs.tcl0000644000175000017500000000453010231440651024400 0ustar frankiefrankiead_library { Callback contract definitions for page rendering. Typically the callbacks also have a corresponing .adp for rendering their output, see the specific callbacks for details. @author Jeff Davis (davis@xarg.net) @creation-date 2005-03-11 @cvs-id $Id: navigation-callback-procs.tcl,v 1.2 2005/04/20 11:48:57 eduardop Exp $ } ad_proc -public -callback navigation::package_admin { -package_id -user_id {-return_url {}} } {

    Returns the list of available admin actions for the passed in user on the passed in package_id.

        {
           {LINK url_stub text title_text long_text}
           {SECTION title long_text}
        }
        

    Where LINK and SECTION are the literal strings.

    For LINK the url and text are required, text and title should be plain text but long_text should be html (and renderers should present it noquote).

    For SECTION both title and long_text can be blank which for the rendering agent would imply a section break with something like blank space or an <hr> tag. Also keep in mind the rendering agent may be creating dropdown menus which would only display the link text and title or might be rendering in a page in which case all things might be rendered so try to make sure the short "title" and "text" fields are not abiguous. heading should be plain text but long_text is treated as html.

    url_stub should be relative to the package mountpoint and without a leading / since the link may be prefixed by the full path or by the vhost url depending on context.

    The /packages/acs-tcl/lib/actions.adp file is an include which will render admin actions returned by this callback.

    @param package_id - the package for which to generate the admin links @param user_id - the user_id for whom the list should be generated @param return_url - a return_url provided by the rendering agent for those actions which could come back @return a list with one element, the list of actions {{{LINK url_stub text title_text long_text} ... }} @see callback::package::admin_actions::impl::forums @see /packages/acs-tcl/lib/actions.adp @see /packages/acs-tcl/lib/actions.tcl @author Jeff Davis (davis@xarg.net) } - openacs-5.7.0/packages/acs-tcl/tcl/request-processor-procs-oracle.xql0000644000175000017500000000041107361111424025476 0ustar frankiefrankie oracle8.1.6 select site_node.url(:node_id) as url from dual openacs-5.7.0/packages/acs-tcl/tcl/install-procs.tcl0000644000175000017500000011577411354755704022211 0ustar frankiefrankiead_library { Procs which may be invoked using similarly named elements in an install.xml file. @creation-date 2004-06-16 @author Lee Denison (lee@thaum.net) @cvs-id $Id: install-procs.tcl,v 1.29 2010/03/31 23:33:24 donb Exp $ } namespace eval install {} namespace eval install::xml {} namespace eval install::xml::util {} namespace eval install::xml::action {} namespace eval install::xml::object_id {} ad_proc -public install::xml::action::text { node } { A documentation element which ignores its contents and does no processing. } { return {} } ad_proc -private ::install::xml::action::source { node } { Source an install.xml file, sql file or tcl script during execution of the current install.xml. If no type attribute is specified then this tag will attempt to guess type of the sourced script from the file extension, otherwise it defaults to install.xml. The type of the sourced script may be explicitly declared as 'tcl', 'sql' or 'install.xml' using the type attribute. @author Lee Denison lee@xarg.co.uk @creation-date 2005-02-04 } { set src [apm_required_attribute_value $node src] set type [apm_attribute_value -default {} $node type] if {$type eq ""} { switch -glob $src { *.tcl { set type tcl } *.sql { set type sql } default { set type install.xml } } } set params [xml_node_get_children [lindex $node 0]] foreach param $params { if {[xml_node_get_name $param] ne "param"} { error "Unknown xml element \"[xml_node_get_name $param]\"" } set name [apm_required_attribute_value $param name] set id [apm_attribute_value -default {} $param id] set value [apm_attribute_value -default {} $param value] if {$id ne ""} { set value [install::xml::util::get_id $id] } set parameters($name) $value } switch -exact $type { tcl { set code [template::util::read_file [acs_root_dir]$src] set out [eval $code] } sql { db_source_sql_file [acs_root_dir]$src set out "$src completed" } install.xml { set binds [array get parameters] set out [apm::process_install_xml -nested $src $binds] } default { error "Unknown script type $type" } } return $out } ad_proc -public install::xml::action::install { node } { Installs a package including dependencies.

    <install package="package-key />

    } { set package_key [apm_required_attribute_value $node package] apm_simple_package_install $package_key return } ad_proc -public install::xml::action::mount { node } { Mounts a package on a specified node.

    <mount package="package-key instance-name="name" mount-point="url" />

    } { set package_key [apm_required_attribute_value $node package] set instance_name [apm_required_attribute_value $node instance-name] set id [apm_attribute_value -default "" $node id] set mount_point [apm_attribute_value -default "" $node mount-point] set context_id [apm_attribute_value -default "" $node context-id] set security_inherit_p [apm_attribute_value -default "t" $node security-inherit-p] set out [list] # Remove double slashes regsub -all {//} $mount_point "/" mount_point set mount_point [string trim $mount_point " /"] if {[string is space $mount_point] || $mount_point eq "/"} { array set site_node [site_node::get -url "/"] if {$site_node(object_id) ne ""} { ns_log Error "A package is already mounted at '$mount_point', ignoring mount command" lappend out "A package is already mounted at '$mount_point', ignoring mount command" set node_id "" } if {$context_id eq ""} { set context_id default_context } set context_id [install::xml::util::get_id $context_id] } else { set leaf_url $mount_point set parent_url "" regexp {(.*)/([^/]*)$} $mount_point match parent_url leaf_url set parent_id [site_node::get_node_id -url "/$parent_url"] # technically this isn't safe - between us checking that the node exists # and using it it may have been deleted. # We could "select for update" but since it's in a memory cache anyway, # it won't help us very much! # Instead we just press on and if there's an error handle it at the top level. # create the node and reget iff it doesn't exist if { [catch { array set site_node [site_node::get_from_url -exact -url "/$mount_point"] } error] } { set node_id [site_node::new -name $leaf_url -parent_id $parent_id] array set site_node [site_node::get_from_url -exact -url "/$mount_point"] } # There now definitely a node with that path if {$site_node(object_id) eq ""} { # no package mounted - good! set node_id $site_node(node_id) } else { ns_log Error "A package is already mounted at '$mount_point', ignoring mount command" lappend out "A package is already mounted at '$mount_point', ignoring mount command" set node_id "" } if {$context_id eq ""} { set context_id [install::xml::util::get_id $context_id] } } if {$node_id ne ""} { lappend out "Mounting new instance of package $package_key at /$mount_point" set package_id [site_node::instantiate_and_mount \ -node_id $node_id \ -context_id $context_id \ -node_name $mount_point \ -package_name $instance_name \ -package_key $package_key] if {![template::util::is_true $security_inherit_p]} { permission::set_not_inherit -object_id $package_id } if {$id ne ""} { set ::install::xml::ids($id) $package_id } } return $out } ad_proc -public install::xml::action::mount-existing { node } { Mounts an existing package on a specified node.

    <mount-existing package-id="package-id mount-point="url" />

    } { set package_id [apm_attribute_value -default "" $node package-id] set package_key [apm_attribute_value -default "" $node package-key] set mount_point [apm_attribute_value -default "" $node mount-point] set out [list] # Remove double slashes regsub -all {//} $mount_point "/" mount_point set mount_point [string trim $mount_point " /"] if {[string is space $mount_point] || $mount_point eq "/"} { array set site_node [site_node::get -url "/"] if {$site_node(object_id) ne ""} { ns_log Error "A package is already mounted at '$mount_point', ignoring mount command" lappend out "A package is already mounted at '$mount_point', ignoring mount command" set node_id "" } } else { set leaf_url $mount_point set parent_url "" regexp {(.*)/([^/]*)$} $mount_point match parent_url leaf_url set parent_id [site_node::get_node_id -url "/$parent_url"] # technically this isn't safe - between us checking that the node exists # and using it it may have been deleted. # We could "select for update" but since it's in a memory cache anyway, # it won't help us very much! # Instead we just press on and if there's an error handle it at the top level. # create the node and reget iff it doesn't exist if { [catch { array set site_node [site_node::get_from_url -exact -url "/$mount_point"] } error] } { set node_id [site_node::new -name $leaf_url -parent_id $parent_id] array set site_node [site_node::get_from_url -exact -url "/$mount_point"] } # There now definitely a node with that path if {$site_node(object_id) eq ""} { # no package mounted - good! set node_id $site_node(node_id) } else { ns_log Error "A package is already mounted at '$mount_point', ignoring mount command" lappend out "A package is already mounted at '$mount_point', ignoring mount command" set node_id "" } } if {$node_id ne ""} { lappend out "Mounting existing package $package_id at /$mount_point" if {$package_id ne ""} { set package_id [install::xml::util::get_id $package_id] } elseif {$package_key ne ""} { set package_id [apm_package_id_from_key $package_key] } set package_id [site_node::mount \ -node_id $node_id \ -object_id $package_id] } return $out } ad_proc -public install::xml::action::rename-instance { node } { Change the instance name of an existing package (such as the main subsite). Either the url (if it's mounted) or package_id of the package may be given.

    <rename-instance package-id="package-id" url="url" instance-name="new instance name" />

    } { set package_id [apm_attribute_value -default "" $node package-id] set url [apm_attribute_value -default "" $node url] set instance_name [apm_required_attribute_value $node instance-name] if { $url ne "" && $package_id ne "" } { error "rename-instance specified with both url and package-id arguments" } elseif { $package_id ne "" } { set package_id [install::xml::util::get_id $package_id] set url [lindex [site_node::get_url_from_object_id -object_id $package_id] 0] } else { array set site_node [site_node::get_from_url -url $url -exact] set package_id $site_node(object_id) } apm_package_rename -package_id $package_id -instance_name $instance_name return [list "Package mounted at \"$url\" renamed to \"$instance_name\""] } ad_proc -public install::xml::action::create-package { node } { Create a relation type. } { variable ::install::xml::ids set package_key [apm_required_attribute_value $node package-key] set instance_name [apm_attribute_value -default "" $node name] set context_id [apm_attribute_value -default "" $node context-id] set security_inherit_p [apm_attribute_value -default "t" $node security-inherit-p] if {$context_id eq ""} { set context_id [db_null] } else { set context_id [install::xml::util::get_id $context_id] } set package_id [apm_package_instance_new \ -instance_name $instance_name \ -package_key $package_key \ -context_id $context_id] if {![template::util::is_true $security_inherit_p]} { permission::set_not_inherit -object_id $package_id } if {![string is space $id]} { set ::install::xml::ids($id) $package_id } return } ad_proc -public install::xml::action::register-parameter { node } { Registers a package parameter.

    <register-parameter name="parameter" description="description" package-key="package-key" scope="instance or global" default-value="default-value" datatype="datatype" [ [ [ section="section" ] min-n-values="min-n-values" ] max-n-values="max-n-values" ] [ callback="callback" ] [ parameter-id="parameter-id" ]

    } { set name [apm_required_attribute_value $node name] set desc [apm_required_attribute_value $node description] set package_key [apm_required_attribute_value $node package-key] set default_value [apm_required_attribute_value $node default-value] set scope [apm_attribute_value -default instance $node scope] set datatype [apm_required_attribute_value $node datatype] set min_n_values [apm_attribute_value -default {} $node min-n-values] set max_n_values [apm_attribute_value -default {} $node max-n-values] set section [apm_attribute_value -default {} $node section] set callback [apm_attribute_value -default {} $node callback] set parameter_id [apm_attribute_value -default {} $node parameter-id] set command "apm_parameter_register" if {$callback ne ""} { append command " -callback $callback" } if {$parameter_id ne ""} { append command " -parameter_id $parameter_id" } append command " -scope $scope $name \"$desc\" $package_key $default_value $datatype" if {$section ne ""} { append command " $section" if {$min_n_values ne ""} { append command " $min_n_values" if {$max_n_values ne ""} { append command " $max_n_values" } } } eval $command return } ad_proc -public install::xml::action::set-parameter { node } { Sets a package parameter.

    <set-parameter name="parameter" [ package="package-key | url="package-url" ] type="[id|literal]" value="value" />

    } { variable ::install::xml::ids set name [apm_required_attribute_value $node name] set value [apm_attribute_value -default {} $node value] set package_id [install::xml::object_id::package $node] set type [apm_attribute_value -default "literal" $node type] switch -- $type { literal { parameter::set_value -package_id $package_id \ -parameter $name \ -value $value } id { parameter::set_value -package_id $package_id \ -parameter $name \ -value $ids($value) } } return } ad_proc -public install::xml::action::set-parameter-default { node } { Sets a package parameter default value <set-parameter-default name="parameter" package-key="package-key" value="val"> } { set name [apm_required_attribute_value $node name] set package_key [apm_required_attribute_value $node package-key] set value [apm_attribute_value -default {} $node value] parameter::set_default \ -package_key $package_key \ -parameter $name \ -value $value return } ad_proc -public install::xml::action::set-permission { node } { Sets permissions on an object.

    <set-permissions grantee="party" privilege="package-key />

    } { set privileges [apm_required_attribute_value $node privilege] set privilege_list [split $privileges ","] set grantees_node [xml_node_get_children_by_name [lindex $node 0] grantee] set grantees [xml_node_get_children [lindex $grantees_node 0]] foreach grantee $grantees { set party_id [apm_invoke_install_proc -type object_id -node $grantee] set objects_node [xml_node_get_children_by_name [lindex $node 0] object] set objects [xml_node_get_children [lindex $objects_node 0]] foreach object $objects { set object_id [apm_invoke_install_proc -type object_id \ -node $object] foreach privilege $privilege_list { permission::grant -object_id $object_id \ -party_id $party_id \ -privilege $privilege } } } return } ad_proc -public install::xml::action::unset-permission { node } { Revokes a permissions on an object - has no effect if the permission is not granted directly (ie does not act as negative permissions).

    <unset-permissions grantee="party" privilege="package-key />

    } { set privileges [apm_required_attribute_value $node privilege] set privilege_list [split $privileges ","] set grantees_node [xml_node_get_children_by_name [lindex $node 0] grantee] set grantees [xml_node_get_children [lindex $grantees_node 0]] foreach grantee $grantees { set party_id [apm_invoke_install_proc -type object_id -node $grantee] set objects_node [xml_node_get_children_by_name [lindex $node 0] object] set objects [xml_node_get_children [lindex $objects_node 0]] foreach object $objects { set object_id [apm_invoke_install_proc -type object_id \ -node $object] foreach privilege $privilege_list { permission::revoke -object_id $object_id \ -party_id $party_id \ -privilege $privilege } } } return } ad_proc -public install::xml::action::set-join-policy { node } { Set the join policy of a group. } { set join_policy [apm_required_attribute_value $node join-policy] set objects [xml_node_get_children [lindex $node 0]] foreach object $objects { set group_id [apm_invoke_install_proc -type object_id -node $object] group::get -group_id $group_id -array group set group(join_policy) $join_policy group::update -group_id $group_id -array group } return } ad_proc -public install::xml::action::create-user { node } { Create a new user. local-p should be set to true when this action is used in the bootstrap install.xml - this ensures we call the auth::local api directly while the service contract has not been setup. } { set email [apm_required_attribute_value $node email] set first_names [apm_required_attribute_value $node first-names] set last_name [apm_required_attribute_value $node last-name] set password [apm_required_attribute_value $node password] set salt [apm_attribute_value -default "" $node salt] set username [apm_attribute_value -default "" $node username] set screen_name [apm_attribute_value -default "" $node screen-name] set url [apm_attribute_value -default "" $node url] set secret_question [apm_attribute_value -default "" $node secret-question] set secret_answer [apm_attribute_value -default "" $node secret-answer] set id [apm_attribute_value -default "" $node id] set site_wide_admin_p [apm_attribute_value -default "" $node site-wide-admin] set local_p [apm_attribute_value -default 0 $node local-p] set local_p [template::util::is_true $local_p] if {$salt ne ""} { set salt_password $password set password dummy } if {$local_p} { foreach elm [auth::get_all_registration_elements] { if { [info exists $elm] } { set user_info($elm) [set $elm] } } set user_info(email_verified_p) 1 array set result [auth::create_local_account \ -authority_id [auth::authority::local] \ -username $username \ -array user_info] if {$result(creation_status) eq "ok"} { # Need to find out which username was set set username $result(username) array set result [auth::local::registration::Register \ {} \ $username \ [auth::authority::local] \ $first_names \ $last_name \ $screen_name \ $email \ $url \ $password \ $secret_question \ $secret_answer] } } else { array set result [auth::create_user -email $email \ -first_names $first_names \ -last_name $last_name \ -password $password \ -username $username \ -screen_name $screen_name \ -url $url \ -secret_question $secret_question \ -secret_answer $secret_answer \ -email_verified_p 1 \ -nologin \ ] } if {$result(creation_status) eq "ok"} { if {[template::util::is_true $site_wide_admin_p]} { permission::grant -object_id [acs_magic_object "security_context_root"] \ -party_id $result(user_id) -privilege "admin" } if {$salt ne ""} { set user_id $result(user_id) db_dml set_real_passsword { UPDATE users SET salt = :salt, password = :salt_password WHERE user_id = :user_id } } if {$id ne ""} { set ::install::xml::ids($id) $result(user_id) } return [list $result(creation_message)] } else { ns_log error "create-user: $result(creation_status): $result(creation_message)" return } } ad_proc -public install::xml::action::add-subsite-member { node } { Add a member to a subsites application group. } { set member_state [apm_attribute_value -default "" $node member-state] set group_id [::install::xml::object_id::application-group $node] set user_nodes [xml_node_get_children [lindex $node 0]] foreach node $user_nodes { if {[xml_node_get_name $node] ne "user"} { error "Unknown xml element \"[xml_node_get_name $node]\"" } set user_id [::install::xml::object_id::object $node] group::add_member -user_id $user_id \ -group_id $group_id \ -member_state $member_state \ -no_perm_check } return } ad_proc -public install::xml::action::add-subsite-admin { node } { Add a member to a subsite's admins group. } { set member_state [apm_attribute_value -default "" $node member-state] # group id is registered using the package id set package_id [install::xml::object_id::package $node] set group_id [subsite::get_admin_group -package_id $package_id] set user_nodes [xml_node_get_children [lindex $node 0]] foreach node $user_nodes { if {[xml_node_get_name $node] ne "user"} { error "Unknown xml element \"[xml_node_get_name $node]\"" } set user_id [::install::xml::object_id::object $node] group::add_member -user_id $user_id \ -group_id $group_id \ -member_state $member_state \ -no_perm_check } return } ad_proc -public install::xml::action::relation-type { node } { Create a relation type. } { set rel_type [apm_required_attribute_value $node rel-type] set pretty_name [apm_required_attribute_value $node pretty-name] set pretty_plural [apm_required_attribute_value $node pretty-plural] set object_type_one [apm_required_attribute_value $node object-type-one] set min_n_rels_one [apm_required_attribute_value $node min-n-rels-one] set max_n_rels_one [apm_attribute_value -default "" $node max-n-rels-one] set object_type_two [apm_required_attribute_value $node object-type-two] set min_n_rels_two [apm_required_attribute_value $node min-n-rels-two] set max_n_rels_two [apm_attribute_value -default "" $node max-n-rels-two] rel_types::new $rel_type \ $pretty_name \ $pretty_plural \ $object_type_one \ $min_n_rels_one \ $max_n_rels_one \ $object_type_two \ $min_n_rels_two \ $max_n_rels_two return } ad_proc -public install::xml::action::relation-add { node } { Create a relation. } { set rel_type [apm_required_attribute_value $node rel-type] set object_one [apm_required_attribute_value $node object-one] set object_two [apm_required_attribute_value $node object-two] relation_add $rel_type $object_one $object_two return } ad_proc -public install::xml::action::ats-page { node } { Creates an ATS Page. } { set id [apm_attribute_value -default "" $node id] set package [apm_attribute_value -default "" $node package] set context [apm_attribute_value -default "" $node context] set path [apm_attribute_value $node path] if {$context ne ""} { set context [install::xml::util::get_id $context] } if {$package ne ""} { set package [install::xml::util::get_id $package] } set extension "*" regexp {(.*)\.(.*)} $path match path extension set result [db_string get_type_select { select page_id from ats_pages where path = :path} -default ""] if {$result eq ""} { set result [location::ats::create_template -path $path \ -extension $extension \ -package_id $package \ -context_id $context] } if {$id ne ""} { set ::install::xml::ids($id) $result } return } ad_proc -public install::xml::action::location { node } { Creates a url location object. } { set id [apm_attribute_value -default "" $node id] set parent [apm_attribute_value -default "" $node parent] set name [apm_attribute_value -default "" $node name] set package [apm_attribute_value -default "" $node package] set context [apm_attribute_value -default "" $node context] set model [apm_attribute_value -default "" $node model] set view [apm_attribute_value -default "" $node view] set controller [apm_attribute_value -default "" $node controller] set path_arg [apm_attribute_value -default "" $node path-arg] set child_arg [apm_attribute_value -default "" $node child-arg] set directory_p [apm_attribute_value -default "t" $node directory-p] set title [apm_attribute_value -default "" $node title] if {$parent ne ""} { set parent [install::xml::util::get_id $parent] } if {$context ne ""} { set context [install::xml::util::get_id $context] } if {$package ne ""} { set package [install::xml::util::get_id $package] } if {$model ne ""} { set model [install::xml::util::get_id $model] } if {$view ne ""} { set view [install::xml::util::get_id $view] } set directory_p [template::util::is_true $directory_p] set location_id [location::create -parent_id $parent \ -name $name \ -title $title \ -model_id $model \ -view_id $view \ -controller $controller \ -path_arg $path_arg \ -package_id $package \ -context_id $context \ -directory_p $directory_p] set children [xml_node_get_children [lindex $node 0]] foreach child $children { switch -exact -- [xml_node_get_name $child] { param { set name [apm_required_attribute_value $child name] set value [apm_attribute_value -default "" $child value] set type [apm_attribute_value -default literal $child type] set subtree_p [apm_attribute_value -default f $child subtree-p] set subtree_p [template::util::is_true $subtree_p] if {$type eq "id"} { set value [install::xml::util::get_id $value] } location::parameter::create -location_id $location_id \ -name $name \ -value $value \ -subtree_p $subtree_p } forward { set name [apm_required_attribute_value $child name] set url [apm_required_attribute_value $child url] set exports [apm_attribute_value -default "" $child exports] set subtree_p [apm_attribute_value -default f $child subtree-p] set subtree_p [template::util::is_true $subtree_p] location::parameter::create -location_id $location_id \ -name "forward::$name" \ -value $url \ -subtree_p $subtree_p if {$exports ne ""} { location::parameter::create -location_id $location_id \ -name "forward::${name}::exports" \ -value $exports \ -subtree_p $subtree_p } } location { xml_node_set_attribute $child parent $location_id if {$child_arg ne ""} { xml_node_set_attribute $child path-arg $child_arg } if {$package ne "" && ![xml_node_has_attribute $child package-id]} { xml_node_set_attribute $child package-id $package } if {$context ne "" && ![xml_node_has_attribute $child context-id]} { xml_node_set_attribute $child context-id $parent_id } apm_invoke_install_proc -node $child } default { error "Unknown xml element \"[xml_node_get_name $child]\"" } } } if {$id ne ""} { set ::install::xml::ids($id) $location_id } return $location_id } ad_proc -public install::xml::action::wizard { node } { Creates a wizard using the subtags for each step. } { set id [apm_attribute_value -default "" $node id] set name [apm_attribute_value -default "" $node name] set package [apm_attribute_value -default "" $node package] set context [apm_attribute_value -default "" $node context] set title [apm_attribute_value -default "" $node title] set child_arg [apm_attribute_value -default "" $node child-arg] set process [apm_attribute_value -default "" $node process] if {$context ne ""} { set context [install::xml::util::get_id $context] } if {$package ne ""} { set package [install::xml::util::get_id $package] } set parent_id [location::create -parent_id "" \ -name $name \ -title $title \ -model_id "" \ -view_id "" \ -controller "" \ -path_arg "" \ -package_id $package \ -context_id $context] if {$process ne ""} { location::parameter::create -location_id $parent_id \ -name "wizard::process" \ -subtree_p t \ -value $process } set steps [xml_node_get_children [lindex $node 0]] foreach step $steps { if {[xml_node_get_name $step] ne "step"} { error "Unknown xml element \"[xml_node_get_name $step]\"" } set step_export [apm_attribute_value -default "" $step exports] set step_export_proc [apm_attribute_value -default "" $step exports-proc] xml_node_set_attribute $step parent $parent_id if {$child_arg ne ""} { xml_node_set_attribute $step path-arg $child_arg } if {$package ne "" && ![xml_node_has_attribute $step package-id]} { xml_node_set_attribute $step package-id $package } if {$context ne "" && ![xml_node_has_attribute $step context-id]} { xml_node_set_attribute $step context-id $parent_id } set directory_p [apm_attribute_value -default f $step directory-p] xml_node_set_attribute $step directory-p \ [template::util::is_true $directory_p] set step_id [::install::xml::action::location $step] if {$step_export ne ""} { location::parameter::create -location_id $step_id \ -name "wizard::exports" \ -subtree_p t \ -value $step_export } if {$step_export_proc ne ""} { location::parameter::create -location_id $step_id \ -name "wizard::exports::proc" \ -subtree_p t \ -value $step_export_proc } } if {$id ne ""} { set ::install::xml::ids($id) $parent_id } return $parent_id } ad_proc -private ::install::xml::action::call-tcl-proc { node } { Call an arbitrary Tcl library procedure. Parameters which have a name are called using the "-param" syntax. If there's no name given, the value is passed directly as a positional parameter. It is the user's responsibility to list all named parameters before any positional parameter (as is necessary if the proc is declared using ad_proc). If a named parameter has an XML attribute declaring its type to be boolean, and the value is blank, the switch is passed without a value. Otherwise, the boolparam=value syntax is used. You can cheat and use this to execute arbitrary Tcl code if you dare, since Tcl commands are just procs ... @author Don Baccus donb@pacifier.com @creation-date 2008-12-04 } { set cmd [list [apm_required_attribute_value $node name]] set params [xml_node_get_children [lindex $node 0]] foreach param $params { if {[xml_node_get_name $param] ne "param"} { error "Unknown xml element \"[xml_node_get_name $param]\"" } set name [apm_attribute_value -default {} $param name] set id [apm_attribute_value -default {} $param id] set value [apm_attribute_value -default {} $param value] set type [apm_attribute_value -default {} $param type] if {$id ne ""} { set value [install::xml::util::get_id $id] } if { $name ne "" && $type eq "boolean" } { if { $value ne "" } { lappend cmd -${name}=$value } else { lappend cmd -$name } } else { if { $name ne "" } { lappend cmd -$name } lappend cmd $value } } set result [eval $cmd] set id [apm_attribute_value -default "" $node id] if {$id ne ""} { set ::install::xml::ids($id) $result } return } ad_proc -private ::install::xml::action::instantiate-object { node } { Instantiate an object using package_instantiate_object. This will work for both PostgreSQL and Oracle if the proper object package and new() function have been defined. @author Don Baccus donb@pacifier.com @creation-date 2008-12-04 } { set type [apm_required_attribute_value $node type] set params [xml_node_get_children [lindex $node 0]] set var_list {} foreach param $params { if {[xml_node_get_name $param] ne "param"} { error "Unknown xml element \"[xml_node_get_name $param]\"" } set name [apm_required_attribute_value $param name] set id [apm_attribute_value -default {} $param id] set value [apm_attribute_value -default {} $param value] if {$id ne ""} { set value [install::xml::util::get_id $id] } lappend var_list [list $name $value] } set object_id [package_instantiate_object -var_list $var_list $type] set id [apm_attribute_value -default "" $node id] if {$id ne ""} { set ::install::xml::ids($id) $object_id } return } ad_proc -public install::xml::object_id::package { node } { Returns an object_id for a package specified in node. The node name is ignored so any node which provides the correct attributes may be used.

    <package [ id="id" | key="package-key" | url="package-url" ] />

    } { set id [apm_attribute_value -default "" $node package-id] set url [apm_attribute_value -default "" $node url] set package_key [apm_attribute_value -default "" $node package-key] if {$package_key eq ""} { set package_key [apm_attribute_value -default "" $node package] } # Remove double slashes regsub -all {//} $url "/" url if { $package_key ne "" && $url ne "" } { error "set-parameter: Can't specify both package and url for $url and $package_key" } elseif { $id ne "" } { if {[string is integer $id]} { return $id } else { return [install::xml::util::get_id $id] } } elseif { $package_key ne "" } { return [apm_package_id_from_key $package_key] } else { return [site_node::get_object_id \ -node_id [site_node::get_node_id -url $url]] } } ad_proc -public install::xml::object_id::group { node } { Returns an object_id for a group or relational segment. The node name is ignored so any node which provides the correct attributes may be used.

    <group id="group_id" [ type="group type" relation="relation-type" ] />

    } { set group_type [apm_attribute_value -default "group" $node type] set relation_type [apm_attribute_value -default "membership_rel" $node relation] if {$group_type eq "group"} { set id [apm_required_attribute_value $node group-id] } elseif {$group_type eq "rel_segment"} { set id [apm_required_attribute_value $node parent-id] } set group_id [install::xml::util::get_id $id] if {$group_type eq "group"} { return $group_id } elseif {$group_type ne "rel_segment"} { return [group::get_rel_segment -group_id $group_id -type $relation_type] } } ad_proc -public install::xml::object_id::application-group { node } { Returns an object_id for an application group or relational segment of a given package. The node name is ignored so any node which provides the correct attributes may be used. } { set group_type [apm_attribute_value -default "group" $node type] set relation_type [apm_attribute_value -default "membership_rel" $node relation] set package_id [::install::xml::object_id::package $node] set group_id [application_group::group_id_from_package_id \ -package_id $package_id] if {$group_type eq "group"} { return $group_id } elseif {$group_type eq "rel_segment"} { return [group::get_rel_segment -group_id $group_id -type $relation_type] } } ad_proc -public install::xml::object_id::member-group { node } { } { set package_id [::install::xml::object_id::package $node] return [subsite::get_member_group -package_id $package_id] } ad_proc -public install::xml::object_id::admin-group { node } { } { set package_id [::install::xml::object_id::package $node] return [subsite::get_admin_group -package_id $package_id] } ad_proc -public install::xml::object_id::object { node } { Returns a literal object_id for an object. use <object id="-100"> to return the literal id -100. } { set id [apm_required_attribute_value $node id] if {[string is integer $id]} { return $id } else { return [install::xml::util::get_id $id] } } ad_proc -public ::install::xml::action::set-id { node } { set a name/id pair for use in other install xml things } { set name [apm_required_attribute_value $node name] set value [apm_required_attribute_value $node value] variable ::install::xml::ids set ids($name) $value } ad_proc -public install::xml::util::get_id { id } { Returns an id from the global ids variable if it exists and attempts to find an acs_magic_object if not. } { variable ::install::xml::ids if {[catch { if {[string is integer $id]} { set result $id } elseif {[info exists ids($id)]} { set result $ids($id) } else { set result [acs_magic_object $id] } } err]} { error "$id is not an integer, is not defined in this install.xml, and is not an acs_magic_object" } return $result } openacs-5.7.0/packages/acs-tcl/tcl/acs-permissions-procs-postgresql.xql0000644000175000017500000000215710171476753026073 0ustar frankiefrankie postgresql7.1 select acs_permission__grant_permission( :object_id, :party_id, :privilege ); select acs_permission__revoke_permission( :object_id, :party_id, :privilege ); select acs_object__name(:object_id) from dual update acs_objects set security_inherit_p = not security_inherit_p where object_id = :object_id openacs-5.7.0/packages/acs-tcl/tcl/apm-file-procs-postgresql.xql0000644000175000017500000000551107370061037024433 0ustar frankiefrankie postgresql7.1 select content_item__new( varchar :name, null, null, null, now(), null, null, :creation_ip, 'content_item', 'content_revision', null, null, 'text/plain', null, null, 'file' ) declare v_revision_id integer; begin v_revision_id := content_revision__new( :title, 'gzipped tarfile', now(), 'text/plain', null, 'not_important', :item_id, null, now(), :user_id, :creation_ip ); update cr_items set live_revision = v_revision_id where item_id = :item_id; return v_revision_id; end; update cr_revisions set content = '[set content_file [cr_create_content_file $item_id $revision_id $tmpfile]]' where revision_id = :revision_id update apm_package_versions set content_length = [cr_file_size $content_file] where version_id = :version_id select '[cr_fs_path]' || r.content as content, i.storage_type from cr_revisions r, cr_items i where r.item_id = i.item_id and r.revision_id = (select content_item__get_latest_revision(item_id) from apm_package_versions where version_id = :version_id) select apm_package_version__add_file( :file_id, :version_id, :path, :file_type, :db_type ) select apm_package_version__remove_file( :version_id, :path ) openacs-5.7.0/packages/acs-tcl/tcl/set-operation-procs.tcl0000644000175000017500000000522711145041201023275 0ustar frankiefrankiead_library { Simple set-manipulation procedures. @creation-date 19 January 2001 @author Eric Lorenzo (elorenzo@arsdigita.com) @cvs-id $Id: set-operation-procs.tcl,v 1.3 2009/02/12 15:38:41 jeffd Exp $ } ad_proc set_member? { s v } {

    Tests whether or not $v is a member of set $s.

    } { if { [lsearch -exact $s $v] == -1 } { return 0 } else { return 1 } } ad_proc set_append! { s-name v } {

    Adds the element v to the set named s-name in the calling environment, if it isn't already there.

    } { upvar $s-name s if { ![set_member? $s $v] } { lappend s $v } } ad_proc set_union { u v } {

    Returns the union of sets $u and $v.

    } { set result $u foreach ve $v { if { ![set_member? $result $ve] } { lappend result $ve } } return $result } ad_proc set_union! { u-name v } {

    Computes the union of the set stored in the variable named $u-name in the calling environment and the set v, sets the variable named $u-name in the calling environment to that union, and also returns that union.

    } { upvar $u-name u foreach ve $v { if { ![set_member? $u $ve] } { lappend u $ve } } return $u } ad_proc set_intersection { u v } {

    Returns the intersection of sets $u and $v.

    } { set result [list] foreach ue $u { if { [set_member? $v $ue] } { lappend result $ue } } return $result } ad_proc set_intersection! { u-name v } {

    Computes the intersection of the set stored in the variable named $u-name in the calling environment and the set v, sets the variable named $u-name in the calling environment to that intersection, and also returns that intersection.

    } { upvar $u-name u set result [list] foreach ue $u { if { [set_member? $v $ue] } { lappend result $ue } } set u $result return $result } ad_proc set_difference { u v } {

    Returns the difference of sets $u and $v. (i.e. The set of all members of u that aren't also members of $v.)

    } { set result [list] foreach ue $u { if { ![set_member? $v $ue] } { lappend result $ue } } return $result } ad_proc set_difference! { u-name v } {

    Computes the difference of the set stored in the variable named $u-name in the calling environment and the set v, sets the variable named $u-name in the calling environment to that difference, and also returns that difference.

    } { upvar $u-name u set result [list] foreach ue $u { if { ![set_member? $v $ue] } { lappend result $ue } } set u $result return $result } openacs-5.7.0/packages/acs-tcl/tcl/database-init.tcl0000644000175000017500000000067210622143342022074 0ustar frankiefrankiead_library { Initialization code for database routines. @creation-date 7 Aug 2000 @author Jon Salz (jsalz@arsdigita.com) @cvs-id $Id: database-init.tcl,v 1.3 2007/05/14 20:30:26 donb Exp $ } #DRB: the default value is needed during the initial install of OpenACS ns_cache create db_cache_pool -size \ [parameter::get_from_package_key \ -package_key acs-kernel \ -parameter DBCacheSize -default 50000] openacs-5.7.0/packages/acs-tcl/tcl/acs-permissions-procs-oracle.xql0000644000175000017500000000267010171476753025135 0ustar frankiefrankie oracle8.1.6 declare begin acs_permission.grant_permission( object_id => :object_id, grantee_id => :party_id, privilege => :privilege ); end; declare begin acs_permission.revoke_permission( object_id => :object_id, grantee_id => :party_id, privilege => :privilege ); end; select acs_object.name(:object_id) from dual update acs_objects set security_inherit_p = case when security_inherit_p = 't' then 'f' else 't' end where object_id = :object_id openacs-5.7.0/packages/acs-tcl/tcl/memoize-procs.tcl0000644000175000017500000001125411346132464022165 0ustar frankiefrankiead_library { Defines a convenient cache mechanism, util_memoize. @author Various [acs@arsdigita.com] @author Rob Mayoff @creation-date 2000-10-19 @cvs-id $Id: memoize-procs.tcl,v 1.13 2010/03/11 09:17:40 gustafn Exp $ } # Use shiny new ns_cache-based util_memoize. ad_proc -public util_memoize {script {max_age ""}} { If script has been executed before, return the value it returned last time, unless it was more than max_age seconds ago.

    Otherwise, evaluate script and cache and return the result.

    Note: script is not evaluated with uplevel. @param script A Tcl script whose value should be memoized. May be best to pass this as a list, e.g. [list someproc $arg1 $arg2]. @param max_age The maximum age in seconds for the cached value of script. If the cached value is older than max_age seconds, script will be re-executed. @return The possibly-cached value returned by script. } { if {$max_age ne "" && $max_age < 0} { error "max_age must not be negative" } set current_time [ns_time] set cached_p [ns_cache get util_memoize $script pair] if {$cached_p && $max_age ne "" } { set cache_time [lindex $pair 0] if {$current_time - $cache_time > $max_age} { ns_cache flush util_memoize $script set cached_p 0 } } if {!$cached_p} { set pair [ns_cache eval util_memoize $script { list $current_time [eval $script] }] } return [lindex $pair 1] } ad_proc -public util_memoize_seed {script value {max_age ""}} { Pretend util_memoize was called with script and it returned value. Cache value, replacing any previous cache entry for script.

    If clustering is enabled, this command flushes script's value from the caches on all servers in the cluster before storing the new value. The new value is only stored in the local cache. @param script A Tcl script that presumably would return value. @param value The value to cache for script. @param max_age Not used. } { util_memoize_flush $script ns_cache set util_memoize $script [list [ns_time] $value] } ad_proc -private util_memoize_flush_local {script} { Forget any cached value for script. You probably want to use util_memoize_flush to flush the caches on all servers in the cluster, in case clustering is enabled. @param script The Tcl script whose cached value should be flushed. } { ns_cache flush util_memoize $script } ad_proc -public util_memoize_cached_p {script {max_age ""}} { Check whether script's value has been cached, and whether it was cached no more than max_age seconds ago. @param script A Tcl script. @param max_age Maximum age of cached value in seconds. @return Boolean value. } { if {![ns_cache get util_memoize $script pair]} { return 0 } if {$max_age eq ""} { return 1 } else { set cache_time [lindex $pair 0] return [expr {[ns_time] - $cache_time <= $max_age}] } } ad_proc -public util_memoize_initialized_p {} { Return 1 if the util_memoize cache has been initialized and is ready to be used and 0 otherwise. @author Peter Marklund } { return [ad_decode [catch {ns_cache set util_memoize __util_memoize_installed_p 1} error] 0 1 0] } ad_proc -public util_memoize_flush_regexp { -log:boolean expr } { Loop through all cached scripts, flushing all that match the regular expression that was passed in. @param expr The regular expression to match. @param log Whether to log keys checked and flushed (useful for debugging). } { foreach name [ns_cache names util_memoize] { if {$log_p} { ns_log Debug "util_memoize_flush_regexp: checking $name for $expr" } if { [regexp $expr $name] } { if {$log_p} { ns_log Debug "util_memoize_flush_regexp: flushing $name" } util_memoize_flush $name } } } ad_proc -public util_memoize_flush_pattern { -log:boolean pattern } { Loop through all cached scripts, flushing all that match the pattern that was passed in. @param pattern Match pattern (glob pattern like in 'string match $pattern'). @param log Whether to log keys checked and flushed (useful for debugging). } { foreach name [ns_cache names util_memoize $pattern] { if {$log_p} { ns_log Debug "util_memoize_flush_regexp: flushing $name" } util_memoize_flush $name } } openacs-5.7.0/packages/acs-tcl/tcl/apm-install-procs.tcl0000644000175000017500000027036111456662501022751 0ustar frankiefrankiead_library { Routines used for installing packages. @creation-date September 11 2000 @author Bryan Quinn (bquinn@arsdigita.com) @cvs-id $Id: apm-install-procs.tcl,v 1.106 2010/10/17 21:06:09 donb Exp $ } namespace eval apm {} namespace eval apm::package_version {} namespace eval apm::package_version::attributes {} namespace eval ::install::xml::action {} ad_proc apm_scan_packages { {-callback apm_dummy_callback} {-new:boolean} {path ""} } { Scans a directory for unregistered package specification files. @param new. Specify this parameter if you don't want packages that are already present to be picked up by the scan. The initial installer needs to specify this. @return A list of unregistered .info files that can be parsed for further information. } { if { $path eq "" } { set path "[apm_workspace_install_dir]" } ### Scan for all unregistered .info files. ns_log Notice "apm_scan_packages: Scanning for new unregistered packages..." set new_spec_files [list] # Loop through all directories in the /packages directory, searching each for a # .info file. foreach dir [lsort [glob -nocomplain "$path/*"]] { set package_key [file tail $dir] if { ![file isdirectory $dir] } { continue } if { [apm_ignore_file_p $dir] } { apm_callback_and_log $callback "Skipping the directory \"$package_key\"." continue } # At this point, we should have a directory that is equivalent to a package_key. if { [apm_package_installed_p $package_key] } { if {$new_p} { continue } } # Locate the .info file for this package. if { [catch { set info_file [apm_package_info_file_path -path $path $package_key] } error] } { apm_callback_and_log -severity Warning $callback "Unable to locate specification file for package $package_key: $error" continue } # We found the .info file. lappend new_spec_files $info_file } if { [llength $new_spec_files] == 0 } { ns_log Notice "apm_scan_packages: No new packages found." } return $new_spec_files } ad_proc -public apm_dependency_provided_p { { -dependency_list [list] } dependency_uri dependency_version } { Returns 1 if the current system provides the dependency inquired about. Returns -1 if the version number is too low. Returns 0 otherwise. @param dependency_list Specify this if you want to a check a list of dependencies of form {dependency_name dependency_version} in addition to querying the database for what the system currently provides. @param dependency_uri The dependency that is being checked. @param dependency_version The version of the dependency being checked. } { set old_version_p 0 set found_p 0 ns_log Debug "apm_dependency_provided_p: Scanning for $dependency_uri version $dependency_version" db_foreach apm_dependency_check {} { if { $version_p >= 0 } { ns_log Debug "apm_dependency_provided_p: Dependency satisfied by previously installed package" set found_p 1 } elseif { $version_p == -1 } { set old_version_p 1 } } # Can't return while inside a db_foreach. if {$found_p} { return 1 } if { $dependency_list ne "" } { # They provided a list of provisions. foreach prov $dependency_list { if {$dependency_uri eq [lindex $prov 0]} { set provided_version [lindex $prov 1] set provided_p [db_string version_greater_p {}] if { $provided_p >= 0 } { ns_log Debug "apm_dependency_provided_p: Dependency satisfied in list of provisions." return 1 } else { set old_version_p 1 } } } } if { $old_version_p} { return -1 } else { return 0 } } ad_proc -private pkg_info_new { package_key spec_file_path embeds extends provides requires {dependency_p ""} {comment ""}} { Returns a datastructure that maintains information about a package. @param package_key The key of the package. @param spec_file_path The path to the package specification file @param embeds A list of packages to be embedded in the package. @param extends A list of packages extended by the package. @param provides A list of dependencies provided by the package. @param requires A list of requirements provided by the package.. @param dependency_p Can the package be installed without violating dependency checking. @param comment Some text about the package. Useful to explain why it fails dependency check. @return a list whose first element is a package key and whose second element is a path to the associated .info file. } { return [list $package_key $spec_file_path $embeds $extends $provides $requires $dependency_p $comment] } ad_proc -private pkg_info_key {pkg_info} { @return The package-key stored in the package info map. } { return [lindex $pkg_info 0] } ad_proc -private pkg_info_spec {pkg_info} { @return The .info file stored in the package info map. } { return [lindex $pkg_info 1] } ad_proc -private pkg_info_path {pkg_info} { @return The full path of the packages dir stored in the package info map. Assumes that the info file is stored in the root dir of the package. } { return [file dirname [pkg_info_spec $pkg_info]] } ad_proc -private pkg_info_embeds {pkg_info} { @return The "embeds" dependencies of the package. } { return [lindex $pkg_info 2] } ad_proc -private pkg_info_extends {pkg_info} { @return The "extends" dependencies of the package. } { return [lindex $pkg_info 3] } ad_proc -private pkg_info_provides {pkg_info} { @return The dependencies provided by the package. } { return [lindex $pkg_info 4] } ad_proc -private pkg_info_requires {pkg_info} { @return The dependencies "requires" dependencies of the package. } { return [lindex $pkg_info 5] } ad_proc -private pkg_info_dependency_p {pkg_info} { @return Does it pass the dependency checker? "" Means it has not been run yet. } { return [lindex $pkg_info 6] } ad_proc -private pkg_info_comment {pkg_info} { @return Any comment specified about this package. } { return [lindex $pkg_info 7] } # DRB: This routine does more than check dependencies, it also parses spec files, # something that really should be done separately, at least for bootstrap installation. # I'm leaving it alone for now, though, and kludging it further by passing in a # boolean to determine whether to process all spec files or just those needed for # initial bootstrap installation. I've also modified it to screen out packages that # don't support the currently running RDBMS - a bit of a hack to do it here but it # needed doing somewhere... ad_proc -private apm_dependency_check { {-callback apm_dummy_callback} {-initial_install:boolean} {-pkg_info_all {}} spec_files } { Check dependencies of all the packages provided. @param spec_files A list of spec files to be processed. @param initial_install Only process spec files with the initial install attribute. @param pkg_info_all If you supply this argument, when a requirement goes unsatisfied, instead of failing, this proc will try to add whatever other packages are needed to the install set. The list of package keys to add will be the third element in the list returned. @return A list whose first element indicates whether dependencies were satisfied (1 if so, 0 otherwise).\ The second element is the package info list with the packages ordered according to dependencies.\ Packages that can be installed come first. Any packages that failed the dependency check come last. The third element is a list of package keys on additional packages to install, in order to satisfy dependencies. } { #### Iterate over the list of info files. ## Every time we satisfy another package, remove it from install_pend, and loop again. ## If we don't satisfy at least one more package, halt. ## install_in - Package info structures for packages that can be installed in a satisfactory order. ## install_pend - Stores package info structures fro packages that might have their dependencies satisfied ## by packages in the install set. ## extra_package_keys - package keys of extra packages to install to satisfy all requirements. set extra_package_keys [list] set updated_p 1 set install_in [list] foreach spec_file $spec_files { if { [catch { array set package [apm_read_package_info_file $spec_file] if { ([string equal $package(initial-install-p) "t"] || !$initial_install_p) && \ [apm_package_supports_rdbms_p -package_key $package(package.key)] } { lappend install_pend [pkg_info_new \ $package(package.key) \ $spec_file \ $package(embeds) \ $package(extends) \ $package(provides) \ $package(requires) \ ""] } # Remove this package from the pkg_info_all list ... # either we're already installing it, or it can't be installed set counter 0 foreach pkg_info $pkg_info_all { if { [string equal [pkg_info_key $pkg_info] $package(package.key)] } { set pkg_info_all [lreplace $pkg_info_all $counter $counter] break } incr counter } } errmsg]} { # Failed to parse the specificaton file. apm_callback_and_log $callback "$spec_file could not be parsed correctly. It is not being installed. The error: $errmsg" } } # Outer loop tries to find a package from the pkg_info_all list to add if # we're stuck because of unsatisfied dependencies set updated_p 1 while { $updated_p } { # Inner loop tries to add another package from the install_pend list while { $updated_p && [exists_and_not_null install_pend]} { set install_in_provides [list] set new_install_pend [list] set updated_p 0 # Generate the list of dependencies currently provided by the install set. foreach pkg_info $install_in { foreach prov [pkg_info_provides $pkg_info] { lappend install_in_provides $prov } } # Now determine if we can add another package to the install set. foreach pkg_info $install_pend { set satisfied_p 1 foreach req [concat [pkg_info_embeds $pkg_info] [pkg_info_extends $pkg_info] [pkg_info_requires $pkg_info]] { if {[apm_dependency_provided_p -dependency_list $install_in_provides \ [lindex $req 0] [lindex $req 1]] != 1} { # Unsatisfied dependency. set satisfied_p 0 # Check to see if we've recorded it already set errmsg "Requires [lindex $req 0] of version >= [lindex $req 1]." if { ![info exists install_error([pkg_info_key $pkg_info])] || \ [lsearch -exact $install_error([pkg_info_key $pkg_info]) $errmsg] == -1} { lappend install_error([pkg_info_key $pkg_info]) $errmsg } lappend new_install_pend $pkg_info break } } if { $satisfied_p } { # At least one more package was added to the list that can be installed, so repeat. lappend install_in [pkg_info_new \ [pkg_info_key $pkg_info] \ [pkg_info_spec $pkg_info] \ [pkg_info_embeds $pkg_info] \ [pkg_info_extends $pkg_info] \ [pkg_info_provides $pkg_info] \ [pkg_info_requires $pkg_info] \ "t" \ "Package satisfies dependencies."] set updated_p 1 } } set install_pend $new_install_pend } set updated_p 0 if { [exists_and_not_null install_pend] && [llength $pkg_info_all] > 0 } { # Okay, there are some packages that could not be installed # Let's find a package, which # - have unsatisfied requirements # - and we have a package in pkg_info_all which provides what this package requires foreach pkg_info $install_pend { set satisfied_p 1 foreach req [concat [pkg_info_embeds $pkg_info] [pkg_info_extends $pkg_info] [pkg_info_requires $pkg_info]] { set counter 0 foreach pkg_info_add $pkg_info_all { # Will this package do anything to change whether this requirement has been satisfied? if { [string equal [pkg_info_key $pkg_info_add] [lindex $req 0]] && [apm_dependency_provided_p -dependency_list [pkg_info_provides $pkg_info_add] \ [lindex $req 0] [lindex $req 1]] == 1 } { # It sure does. Add it to list of packages to install lappend install_pend $pkg_info_add # Add it to list of extra package keys lappend extra_package_keys [pkg_info_key $pkg_info_add] # Remove it from list of packages that we can possibly install set pkg_info_all [lreplace $pkg_info_all $counter $counter] # Note that we've made changes set updated_p 1 # Now break out of pkg_info_all loop break } incr counter } if { $updated_p } { break } } if { $updated_p } { break } } } } set install_order(order) $install_in # Update all of the packages that cannot be installed. if { [exists_and_not_null install_pend] } { foreach pkg_info $install_pend { lappend install_in [pkg_info_new [pkg_info_key $pkg_info] [pkg_info_spec $pkg_info] \ [pkg_info_embeds $pkg_info] [pkg_info_extends $pkg_info] \ [pkg_info_provides $pkg_info] [pkg_info_requires $pkg_info] \ "f" $install_error([pkg_info_key $pkg_info])] } return [list 0 $install_in] } return [list 1 $install_in $extra_package_keys] } ad_proc -private apm_dependency_check_new { {-repository_array:required} {-package_keys:required} } { Checks dependencies and finds out which packages are required to install the requested packages. In case some packages cannot be installed due to failed dependencies, it returns which packages out of the requested can be installed, and which packages, either originally requested or required by those, could not be installed, and why. @param package_keys The list of package_keys of the packages requested to be installed. @param repository_array Name of an array in the caller's namespace containing the repository of available packages as returned by apm_get_package_repository. @return An array list with the following elements:

    • status: 'ok' or 'failed'.
    • install: If status is 'ok', this is the complete list of packages that need to be installed, in the order in which they need to be installed. If status is 'failed', the list of packages that can be installed.
    • failed: If status is 'failed', an array list keyed by package_key of 2-tuples of (required-uri, required-version) of requirements that could not be satisfied.
    • packages: The list of package_keys of the packages touched upon, either because they were originally requested, or because they were required. If status is 'ok', will be identical to 'install'.
    @see apm_get_package_repository } { upvar 1 $repository_array repository array set result { status failed install {} failed {} packages {} } # 'pending_packages' is an array keyed by package_key with a value of 1 for each package pending installation # When dependencies have been met, the entry will be unset array set pending_packages [list] foreach package_key $package_keys { set pending_packages($package_key) 1 } # 'installed_packages' is an array keyed by package_key with a value of 1 for each package # whose dependencies have been met and is ready to be installed array set installed_packages [list] # 'provided' will keep track of what we've provided with the currently installed packages # combined with the packages which we're already able to install apm_get_installed_provides -array provided # 'required' will keep track of unsatisfied dependencies # keyed by (service-uri) and will contain the largest version number required array set required [list] # 'required_by' will keep track of unsatisfied dependencies # keyed by (service-uri) and will contain the largest version number required array set required_by [list] # Just to get us started set updated_p 1 ns_log Debug "apm_dependency_check_new: STARTING DEPENDENCY CHECK" # Outer loop tries to find a package from the repository to add if # we're stuck because of unsatisfied dependencies while { $updated_p } { # Keep looping over pending_package_keys, trying to add packages # So long as we've added another, try looping again, as there may be cross-dependencies while { $updated_p && [llength [array names pending_packages]] > 0 } { set updated_p 0 # Try to add a package from foreach package_key [array names pending_packages] { array unset version array set version $repository($package_key) set satisfied_p 1 foreach req [concat $version(embeds) $version(extends) $version(requires)] { set req_uri [lindex $req 0] set req_version [lindex $req 1] if { ![info exists provided($req_uri)] || \ [apm_version_names_compare $provided($req_uri) $req_version]== -1 } { ns_log Debug "apm_dependency_check_new: $package_key embeds, extends or requires $req_uri $req_version => failed" set satisfied_p 0 # Mark this as a requirement if { ![info exists required($req_uri)] || \ [apm_version_names_compare $required($req_uri) $req_version] == -1 } { set required($req_uri) $req_version } } else { ns_log Debug "apm_dependency_check_new: $package_key embeds, extends or requires $req_uri $req_version => OK" } } if { $satisfied_p } { # Record as set to go set installed_packages($package_key) 1 # Remove from pending list unset pending_packages($package_key) # Add to install-list, as this is important for ordering the installation of packages correctly lappend result(install) $package_key # Add to list of packages touched lappend result(packages) $package_key # Record what this package provides, and remove it from the required list, if appropriate foreach prov $version(provides) { set prov_uri [lindex $prov 0] set prov_version [lindex $prov 1] # If what we provide is not already provided, or the alredady provided version is # less than what we provide, record this new provision if { ![info exists provided($prov_uri)] || \ [apm_version_names_compare $provided($prov_uri) $prov_version] == -1 } { set provided($prov_uri) $prov_version } # If what we provide is required, and the required version is less than what we provide, # drop the requirement if { [info exists required($prov_uri)] && \ [apm_version_names_compare $required($prov_uri) $prov_version] <= 0 } { array unset required($prov_uri) } } # Another package has been added, so repeat set updated_p 1 } } } # Inner loop completed. Either we're done, or there are packages that have dependencies # not currently on the pending_package_keys list. set updated_p 0 if { [llength [array names pending_packages]] > 0 } { # There are packages that have unsatisfied dependencies # Those unmet requirements will be registered in the 'required' array # Let's find a package which satisfies at least one of the requirements in 'required' foreach package_key [array names repository] { if { [info exists pending_packages($package_key)] || \ [info exists installed_packages($package_key)] } { # Packages already on the pending list, or already verified ok won't help us any continue } array unset version array set version $repository($package_key) ns_log Debug "apm_dependency_check_new: Considering $package_key: [array get version]" # Let's see if this package provides anything we need foreach prov $version(provides) { set prov_uri [lindex $prov 0] set prov_version [lindex $prov 1] if { [info exists required($prov_uri)] && \ [apm_version_names_compare $required($prov_uri) $prov_version] <= 0 } { ns_log Debug "apm_dependency_check_new: Adding $package_key, as it provides $prov_uri $prov_version" # If this package provides something that's required in a version high enough # add it to the pending list set pending_packages($package_key) 1 # We've changed something set updated_p 1 # Let's try for another go at installing packages break } } # Break all the way back to installing pending packages again if { $updated_p } { break } } } } if { [llength [array names pending_packages]] == 0 } { set result(status) ok } else { set result(status) failed array set failed [list] # There were problems, now be helpful # Find out which packages couldn't be installed and why foreach package_key [array names pending_packages] { array unset version array set version $repository($package_key) # Add to touched upon packages lappend result(packages) $package_key # Find unsatisfied requirements foreach req [concat $version(embeds) $version(extends) $version(requires)] { set req_uri [lindex $req 0] set req_version [lindex $req 1] if { ![info exists provided($req_uri)] || \ [apm_version_names_compare $provided($req_uri) $req_version] == -1 } { lappend failed($package_key) [list $req_uri $req_version] if { [info exists provided($req_uri)] } { ns_log Debug "apm_dependency_check_new: Failed dependency: $package_key embeds/extends/requires $req_uri $req_version, but we only provide $provided($req_uri)" } else { ns_log Debug "apm_dependency_check_new: Failed dependency: $package_key embeds/extends/requires $req_uri $req_version, but we don't have it" } } } } set result(failed) [array get failed] } return [array get result] } ad_proc -private apm_load_catalog_files { -upgrade:boolean package_key } { Load catalog files for a package that is either installed or upgraded. If the package is upgraded message key upgrade status is reset before loading the files. During installation of OpenACS when the acs-lang package hasn't been installed yet this procedure won't do anything. That's not a problem since catalog files will be loaded upon next server restart. Also caches the messages it loads. @author Peter Marklund } { # If acs-lang hasn't been installed yet we simply return if { [llength [info proc lang::catalog::import]] == 0 || ![apm_package_installed_p acs-lang] } { return } # Load and cache I18N messages for all enabled locales lang::catalog::import -cache -package_key $package_key } namespace eval apm {} ad_proc -public apm_simple_package_install { package_key } { Simple basic package install function. Wraps up basically what the old install xml action did. } { set package_info_path "[acs_root_dir]/packages/${package_key}/*.info" set install_spec_files [list] foreach install_spec_file [glob -nocomplain $package_info_path] { if { [catch { array set package [apm_read_package_info_file $install_spec_file] } errmsg] } { # Unable to parse specification file. error "install: $install_spec_file could not be parsed correctly. The error: $errmsg" return } if { [apm_package_supports_rdbms_p -package_key $package(package.key)] && ![apm_package_installed_p $package(package.key)] } { lappend install_spec_files $install_spec_file } } set pkg_info_list [list] foreach spec_file [glob -nocomplain "[acs_root_dir]/packages/*/*.info"] { # Get package info, and find out if this is a package we should install if { [catch { array set package [apm_read_package_info_file $spec_file] } errmsg] } { # Unable to parse specification file. error "install: $spec_file could not be parsed correctly. The error: $errmsg" } if { [apm_package_supports_rdbms_p -package_key $package(package.key)] && ![apm_package_installed_p $package(package.key)] } { # Save the package info, we may need it for dependency # satisfaction later lappend pkg_info_list [pkg_info_new $package(package.key) \ $spec_file \ $package(embeds) \ $package(extends) \ $package(provides) \ $package(requires) \ ""] } } if { [llength $install_spec_files] > 0 } { set dependency_results [apm_dependency_check \ -pkg_info_all $pkg_info_list \ $install_spec_files] if { [lindex $dependency_results 0] == 1 } { apm_packages_full_install -callback apm_ns_write_callback \ [lindex $dependency_results 1] } else { foreach package_spec [lindex $dependency_results 1] { if {[string is false [pkg_info_dependency_p $package_spec]]} { append err_out "install: package \"[pkg_info_key $package_spec]\"[join [pkg_info_comment $package_spec] ","]\n" } } error $err_out } } } ad_proc -private apm_package_install { {-enable:boolean} {-callback apm_dummy_callback} {-load_data_model:boolean} {-data_model_files 0} {-package_path ""} {-mount_path ""} spec_file_path } { Registers a new package and/or version in the database, returning the version_id. If $callback is provided, periodically invokes this procedure with a single argument containing a human-readable (English) status message. @param spec_file_path The path to an XML .info file relative to @return The version_id if successfully installed, 0 otherwise. } { set version_id 0 array set version [apm_read_package_info_file $spec_file_path] set package_key $version(package.key) apm_callback_and_log $callback "

    Installing $version(package-name) $version(name)

    " # Determine if we are upgrading or installing. set upgrade_from_version_name [apm_package_upgrade_from $package_key $version(name)] set upgrade_p [expr {$upgrade_from_version_name ne ""}] if { [string match "[apm_workspace_install_dir]*" $package_path] } { # Package is being installed from the apm_workspace dir (expanded from .apm file) # Backup any existing (old) package in packages dir first set old_package_path [acs_package_root_dir $package_key] if { [file exists $old_package_path] } { util::backup_file -file_path $old_package_path } # Move the package into the packages dir #exec "mv" "$package_path" "[acs_root_dir]/packages" file rename $package_path [acs_root_dir]/packages # We moved the spec file, so update its path set package_path $old_package_path set spec_file_path [apm_package_info_file_path -path [file dirname $package_path] $package_key] } with_catch errmsg { set package_uri $version(package.url) set package_type $version(package.type) set package_name $version(package-name) set pretty_plural $version(pretty-plural) set initial_install_p $version(initial-install-p) set singleton_p $version(singleton-p) set implements_subsite_p $version(implements-subsite-p) set inherit_templates_p $version(inherit-templates-p) set auto_mount $version(auto-mount) set version_name $version(name) set version_uri $version(url) set summary $version(summary) set description_format $version(description.format) set description $version(description) set release_date $version(release-date) set vendor $version(vendor) set vendor_uri $version(vendor.url) set split_path [split $spec_file_path /] set relative_path [join [lreplace $split_path 0 [lsearch -exact $package_key $split_path]] /] # Register the package if it is not already registered. if { ![apm_package_registered_p $package_key] } { apm_package_register \ -spec_file_path $relative_path \ $package_key \ $package_name \ $pretty_plural \ $package_uri \ $package_type \ $initial_install_p \ $singleton_p \ $implements_subsite_p \ $inherit_templates_p } # Source Tcl procs and queries to be able # to invoke any Tcl callbacks after mounting and instantiation. Note that this reloading # is only done in the Tcl interpreter of this particular request. # Note that acs-tcl is a special case as its procs are always sourced on startup from boostrap.tcl if { $package_key ne "acs-tcl" } { apm_load_libraries -procs -force_reload -packages $package_key apm_load_queries -packages $package_key } # Get the callbacks in an array, since we can't rely on the # before-upgrade being in the db (since it might have changed) # and the before-install definitely won't be there since # it's not added til later here. array set callbacks $version(callbacks) if {$upgrade_p} { # Run before-upgrade if {[info exists callbacks(before-upgrade)]} { apm_invoke_callback_proc \ -proc_name $callbacks(before-upgrade) \ -version_id $version_id \ -type before-upgrade \ -arg_list [list from_version_name $upgrade_from_version_name to_version_name $version(name)] } } else { # Run before-install if {[info exists callbacks(before-install)]} { apm_invoke_callback_proc \ -proc_name $callbacks(before-install) \ -version_id $version_id \ -type before-install } } if { $load_data_model_p } { apm_package_install_data_model -callback $callback -data_model_files $data_model_files $spec_file_path } # If an older version already exists in apm_package_versions, update it; # otherwise, insert a new version. if { $upgrade_p } { # We are upgrading a package # Load catalog files with upgrade switch before package version is changed in db apm_load_catalog_files -upgrade $package_key set version_id [apm_package_install_version \ -callback $callback \ -array version \ $package_key $version_name \ $version_uri $summary $description $description_format $vendor $vendor_uri $auto_mount $release_date] apm_version_upgrade $version_id apm_package_install_dependencies -callback $callback \ $version(embeds) $version(extends) $version(provides) $version(requires) $version_id apm_build_one_package_relationships $package_key apm_package_upgrade_parameters -callback $callback $version(parameters) $package_key } else { # We are installing a new package set version_id [apm_package_install_version \ -callback $callback \ -array version \ $package_key $version_name \ $version_uri $summary $description $description_format $vendor $vendor_uri $auto_mount $release_date] if { !$version_id } { # There was an error. ns_log Error "apm_package_install: Package $package_key could not be installed. Received version_id $version_id" apm_callback_and_log $callback "The package version could not be created." } apm_load_catalog_files $package_key apm_package_install_dependencies -callback $callback \ $version(embeds) $version(extends) $version(provides) $version(requires) $version_id apm_build_one_package_relationships $package_key apm_copy_inherited_params $package_key [concat $version(embeds) $version(extends)] # Install the parameters for the version. apm_package_install_parameters -callback $callback $version(parameters) $package_key } # Update all other package information. apm_package_install_owners -callback $callback $version(owners) $version_id apm_package_install_callbacks -callback $callback $version(callbacks) $version_id apm_build_subsite_packages_list apm_callback_and_log $callback "

    Installed $version(package-name), version $version(name).

    " } { global errorInfo ns_log Error "apm_package_install: Error installing $version(package-name) version $version(name): $errmsg\n$errorInfo" apm_callback_and_log -severity Error $callback "

    Failed to install $version(package-name), version $version(name). The following error was generated:

    [ad_quotehtml $errmsg]

    NOTE: If the error comes from a sql script you may try to source it manually. When you are done with that you should revisit the APM and try again but remember to leave the manually souced sql scipts unchecked on the previous page.

    " return 0 } # Enable the package if { $enable_p } { nsv_set apm_enabled_package $package_key 1 apm_version_enable -callback $callback $version_id } # Instantiating, mounting, and after-install callback only invoked on initial install if { ! $upgrade_p } { # After install Tcl proc callback apm_invoke_callback_proc -version_id $version_id -type after-install set priority_mount_path [ad_decode $version(auto-mount) "" $mount_path $version(auto-mount)] if { $priority_mount_path ne "" } { # This is a package that should be auto mounted set parent_id [site_node::get_node_id -url "/"] if { [catch { db_transaction { set node_id [site_node::new -name $priority_mount_path -parent_id $parent_id] } } error] } { # There is already a node with that path, check if there is a package mounted there array set node [site_node::get -url "/${priority_mount_path}"] if { $node(object_id) eq "" } { # There is no package mounted there so go ahead and mount the new package set node_id $node(node_id) } else { # Don't unmount already mounted packages set node_id "" } } if { $node_id ne "" } { site_node::instantiate_and_mount \ -node_id $node_id \ -node_name $priority_mount_path \ -package_name $version(package-name) \ -package_key $package_key apm_callback_and_log $callback "

    Mounted an instance of the package at /${priority_mount_path}

    " } { # Another package is mounted at the path so we cannot mount global errorInfo set error_text "Package $version(package-name) could not be mounted at /$version(auto-mount) , there may already be a package mounted there, the error is: $error" ns_log Error "apm_package_install: $error_text \n\n$errorInfo" apm_callback_and_log $callback "

    $error_text

    " } } elseif { $package_type eq "apm_service" && $singleton_p eq "t" } { # This is a singleton package. Instantiate it automatically, but don't mount. # Using empty context_id apm_package_instance_new -instance_name $version(package-name) \ -package_key $package_key } } else { # After upgrade Tcl proc callback apm_invoke_callback_proc -version_id $version_id -type after-upgrade -arg_list [list from_version_name $upgrade_from_version_name to_version_name $version(name)] } # Flush the installed_p cache util_memoize_flush [list apm_package_installed_p_not_cached $package_key] return $version_id } ad_proc apm_unregister_disinherited_params { package_key dependency_id } { Remove parameters for package_key that have been disinherited (i.e., the dependency that caused them to be inherited have been removed). Called only by the APM and keep it that way, please. } { foreach parameter_id [db_list get_parameter_ids {}] { apm_parameter_unregister $parameter_id } } ad_proc apm_copy_param_to_descendents { new_package_key parameter_name } { Copy a new parameter in a package to its descendents. Called when a package is upgraded or a parameter added in the APM. } { db_1row param {} foreach descendent_package_key [nsv_get apm_package_descendents $new_package_key] { if { [db_exec_plsql param_exists {}] } { error "$parameter_name already exists in package $descendent_package_key" } else { db_exec_plsql copy_descendent_param {} } } } ad_proc apm_copy_inherited_params { new_package_key dependencies } { Copy parameters from a packages ancestors. Called for "embeds" and "extends" dependencies. } { foreach dependency $dependencies { set inherited_package_key [lindex $dependency 0] db_foreach inherited_params {} { if { [db_exec_plsql param_exists {}] } { error "$parameter_name already exists in package $new_package_key" } else { db_exec_plsql copy_inherited_param {} } } } } ad_proc -private apm_package_install_version { {-callback apm_dummy_callback} {-array:required} {-version_id ""} package_key version_name version_uri summary description description_format vendor vendor_uri auto_mount {release_date ""} } { Installs a version of a package. @param array The name of the array in the callers scope holding package version attributes @return The assigned version id. } { upvar $array local_array if { $version_id eq "" } { set version_id [db_null] } if { $release_date eq "" } { set release_date [db_null] } set version_id [db_exec_plsql version_insert {}] apm::package_version::attributes::store \ -version_id $version_id \ -array local_array # Every package provides by default the service that is the package itself # This spares the developer from having to visit the dependency page apm_interface_add $version_id $package_key $version_name return $version_id } ad_proc -private apm_package_deinstall { { -callback apm_dummy_callback } package_key } { Deinstalls a package from the filesystem. @param package_key The package to be deinstaleled. } { if {![apm_package_registered_p $package_key]} { apm_callback_and_log $callback "This package is not installed. Done." return 0 } # Obtain the portion of the email address before the at sign. We'll use this in the name of # the backup directory for the package. regsub {@.+} [cc_email_from_party [ad_get_user_id]] "" my_email_name set backup_dir "[apm_workspace_dir]/$package_key-removed-$my_email_name-[ns_fmttime [ns_time] "%Y%m%d-%H:%M:%S"]" apm_callback_and_log $callback "
  • Moving packages/$package_key to $backup_dir... " if { [catch { file rename "[acs_root_dir]/packages/$package_key" $backup_dir } error] } { apm_callback_and_log $callback "[ns_quotehtml $error]" } else { apm_callback_and_log $callback "moved." } db_dml apm_uninstall_record { update apm_package_versions set installed_p = 'f', enabled_p = 'f' where package_key = :package_key } apm_callback_and_log $callback "
  • Package marked as deinstalled. " return 1 } ad_proc -private apm_package_delete { {-sql_drop_scripts ""} { -callback apm_dummy_callback } {-remove_files:boolean} package_key } { Deinstall a package from the system. Will unmount and uninstantiate package instances, invoke any before-unstall callback, source any provided sql drop scripts, remove message keys, and delete the package from the APM tables. } { set version_id [apm_version_id_from_package_key $package_key] # Unmount all instances of this package with the Tcl API that # invokes before-unmount callbacks db_transaction { db_foreach all_package_instances { select site_nodes.node_id from apm_packages, site_nodes where apm_packages.package_id = site_nodes.object_id and apm_packages.package_key = :package_key } { set url [site_node::get_url -node_id $node_id] apm_callback_and_log $callback "Unmounting package instance at url $url
    " site_node::unmount -node_id $node_id } # Delete the package instances with Tcl API that invokes # before-uninstantiate callbacks db_foreach all_package_instances { select package_id from apm_packages where package_key = :package_key } { apm_callback_and_log $callback "Deleting package instance $package_id
    " apm_package_instance_delete $package_id } # Invoke the before-uninstall Tcl callback before the sql drop scripts apm_invoke_callback_proc -version_id $version_id -type before-uninstall # Unregister I18N messages lang::catalog::package_delete -package_key $package_key # Remove package from APM tables apm_callback_and_log $callback "
  • Deleting $package_key..." db_exec_plsql apm_package_delete { begin apm_package_type.drop_type( package_key => :package_key, cascade_p => 't' ); end; } } # Source SQL drop scripts if {$sql_drop_scripts ne ""} { apm_callback_and_log $callback "Now executing drop scripts.
      " foreach path $sql_drop_scripts { apm_callback_and_log $callback "
    • "
              	db_source_sql_file -callback $callback "[acs_package_root_dir $package_key]/$path"
              	apm_callback_and_log $callback "
      " } } # Optionally remove the files from the filesystem if {$remove_files_p==1} { if { [catch { file delete -force [acs_package_root_dir $package_key] } error] } { apm_callback_and_log $callback "
    • Unable to delete [acs_package_root_dir $package_key]:$error" } } # Flush the installed_p cache util_memoize_flush [list apm_package_installed_p_not_cached $package_key] apm_callback_and_log $callback "

      Done." } ad_proc -private apm_package_version_delete { { -callback apm_dummy_callback } version_id } { Deletes a version from the database. } { db_exec_plsql apm_version_delete { begin apm_package_version.del(version_id => :version_id); end; } } ad_proc -public apm_package_version_count {package_key} { @return The number of versions of the indicated package. } { return [db_string apm_package_version_count { select count(*) from apm_package_versions where package_key = :package_key } -default 0] } ad_proc -private apm_package_install_data_model { {-callback apm_dummy_callback} {-upgrade_from_version_name ""} {-data_model_files "0"} {-path ""} spec_file } { Given a spec file, reads in the data model files to load from it. } { array set version [apm_read_package_info_file $spec_file] set package_key $version(package.key) set upgrade_to_version_name $version(name) if { $path eq "" } { set path "[acs_package_root_dir $package_key]" } set ul_p 0 if {($data_model_files == 0)} { set data_model_files [apm_data_model_scripts_find \ -upgrade_from_version_name $upgrade_from_version_name \ -upgrade_to_version_name $upgrade_to_version_name \ -package_path $path \ $package_key] } if { $data_model_files ne "" } { apm_callback_and_log $callback "

    • Installing data model for $version(package-name) $version(name)...\n" } foreach item $data_model_files { set file_path [lindex $item 0] set file_type [lindex $item 1] ns_log Debug "apm_package_install_data_model: Now processing $file_path of type $file_type" if {$file_type eq "data_model_create" || \ $file_type eq "data_model_upgrade" } { if { !$ul_p } { apm_callback_and_log $callback "
        \n" set ul_p 1 } apm_callback_and_log $callback "
      • Loading data model $path/$file_path...
        "
        	    db_source_sql_file -callback $callback $path/$file_path
        	    apm_callback_and_log $callback "
        \n" } elseif { $file_type eq "sqlj_code" } { if { !$ul_p } { apm_callback_and_log $callback "
          \n" set ul_p 1 } apm_callback_and_log $callback "
        • Loading SQLJ code $path/$file_path...
          "
          	    db_source_sqlj_file -callback $callback "$path/$file_path"
          	    apm_callback_and_log $callback "
          \n" } elseif {$file_type eq "ctl_file"} { ns_log Debug "apm_package_install_data_model: Now processing $file_path of type ctl_file" if { !$ul_p } { apm_callback_and_log $callback "
            \n" set ul_p 1 } apm_callback_and_log $callback "
          • Loading data file $path/$file_path...
            "
                        db_load_sql_data -callback $callback $path/$file_path
            	    apm_callback_and_log $callback "
            \n" } } if {$ul_p} { apm_callback_and_log $callback "

          " } if { [llength $data_model_files] } { #Installations/upgrades are done in a separate process, making #changes that could affect our sessions. This is particularly a #problem with the content_item package on Oracle. To be on the safe #side we refresh the db connections after each install/upgrade. ns_log Debug "apm_package_install_data_model: Bouncing db pools." db_bounce_pools } } ad_proc -private apm_package_upgrade_parameters { {-callback apm_dummy_callback} parameters package_key } { Upgrades the parameters to the current version. } { # Update each parameter that exists. foreach parameter $parameters { set parameter_name [lindex $parameter 0] # Keep a running tally of all parameters that are in the current version. set description [lindex $parameter 1] set section_name [lindex $parameter 2] set scope [lindex $parameter 3] set datatype [lindex $parameter 4] set min_n_values [lindex $parameter 5] set max_n_values [lindex $parameter 6] set default_value [lindex $parameter 7] if {[db_0or1row parameter_id_get { select parameter_id from apm_parameters where parameter_name = :parameter_name and package_key = :package_key }]} { ns_log Debug "apm_package_upgrade_parameters: Updating parameter, $parameter_name:$parameter_id" # DRB: We don't allow one to upgrade scope and should probably throw an error. apm_parameter_update $parameter_id $package_key $parameter_name $description \ $default_value $datatype $section_name $min_n_values $max_n_values } else { ns_log Debug "apm_package_upgrade_parameters: Registering parameter, $parameter_name." apm_parameter_register -scope $scope $parameter_name $description $package_key $default_value \ $datatype $section_name $min_n_values $max_n_values } } ns_log Debug "apm_package_upgrade_parameters: Parameter Upgrade Complete." } ad_proc -private apm_package_install_parameters { {-callback apm_dummy_callback} parameters package_key } { Installs a set of parameters into the package denoted by package_key. } { foreach parameter $parameters { set parameter_name [lindex $parameter 0] set description [lindex $parameter 1] set section_name [lindex $parameter 2] set scope [lindex $parameter 3] set datatype [lindex $parameter 4] set min_n_values [lindex $parameter 5] set max_n_values [lindex $parameter 6] set default_value [lindex $parameter 7] apm_parameter_register -scope $scope $parameter_name $description $package_key $default_value $datatype \ $section_name $min_n_values $max_n_values } } ad_proc -private apm_package_install_dependencies { {-callback apm_dummy_callback} embeds \ extends provides requires version_id} { Install all package dependencies. } { ns_log Debug "apm_package_install_dependencies: Installing dependencies." # Delete any dependencies register for this version. db_foreach all_dependencies_for_version { select dependency_id from apm_package_dependencies where version_id = :version_id } { apm_dependency_remove $dependency_id } foreach item $provides { set interface_uri [lindex $item 0] set interface_version [lindex $item 1] ns_log Debug "apm_package_install_dependencies: Registering dependency $interface_uri, $interface_version for $version_id" apm_interface_add $version_id $interface_uri $interface_version } foreach item $embeds { set dependency_uri [lindex $item 0] set dependency_version [lindex $item 1] ns_log Debug "apm_package_install_dependencies: Registering dependency $dependency_uri, $dependency_version for $version_id" apm_dependency_add embeds $version_id $dependency_uri $dependency_version } foreach item $extends { set dependency_uri [lindex $item 0] set dependency_version [lindex $item 1] ns_log Debug "apm_package_install_dependencies: Registering dependency $dependency_uri, $dependency_version for $version_id" apm_dependency_add extends $version_id $dependency_uri $dependency_version } foreach item $requires { set dependency_uri [lindex $item 0] set dependency_version [lindex $item 1] ns_log Debug "apm_package_install_dependencies: Registering dependency $dependency_uri, $dependency_version for $version_id" apm_dependency_add requires $version_id $dependency_uri $dependency_version } } ad_proc -private apm_package_install_owners_prepare {owner_names owner_uris } { Prepare the owners data structure for installation. } { set owners [list] for {set i 0} {$i < [llength $owner_names] } {incr i} { if { ![empty_string_p [lindex $owner_names $i]] } { lappend owners [list [lindex $owner_names $i] [lindex $owner_uris $i]] } } return $owners } ad_proc -private apm_package_install_owners { {-callback apm_dummy_callback} owners version_id} { Install all of the owners of the package version. } { db_dml apm_delete_owners { delete from apm_package_owners where version_id = :version_id } set counter 0 foreach item $owners { set owner_name [lindex $item 0] set owner_uri [lindex $item 1] db_dml owner_insert { insert into apm_package_owners(version_id, owner_uri, owner_name, sort_key) values(:version_id, :owner_uri, :owner_name, :counter) } incr counter } } ad_proc -private apm_package_install_callbacks { {-callback apm_dummy_callback} callback_list version_id } { Install the Tcl proc callbacks for the package version. @author Peter Marklund } { db_dml delete_all_callbacks { delete from apm_package_callbacks where version_id = :version_id } foreach {type proc} $callback_list { apm_set_callback_proc -version_id $version_id -type $type $proc } } ad_proc -private apm_package_install_spec { version_id } { Writes the XML-formatted specification for a package to disk, marking it in the database as the only installed version of the package. Creates the package directory if it doesn't already exist. Overwrites any existing specification file; or if none exists yet, creates $package_key/$package_key.info and adds this new file to apm_version_files in the database. Adds minimal directories. } { set spec [apm_generate_package_spec $version_id] apm_version_info $version_id db_1row package_version_info_select { select package_key, version_id from apm_package_version_info where version_id = :version_id } ns_log Debug "apm_package_install_spec: Checking existence of package directory." set root [acs_package_root_dir $package_key] if { ![file exists $root] } { file mkdir $root # doesn't work under windows. its not very useful anyway. # file attributes $root -permissions [parameter::get -parameter InfoFilePermissionsMode -default 0755] } db_transaction { ns_log Debug "apm_package_install_spec: Determining path of .info file." set path "[acs_package_root_dir $package_key]/$package_key.info" ns_log Debug "apm_package_install_spec: Writing APM .info file to the database." db_dml apm_spec_file_register {} ns_log Debug "apm_package_install_spec: Writing .info file." set file [open $path "w"] puts -nonewline $file $spec close $file # create minimal directories foreach dir {www www/doc tcl tcl/test sql sql/postgresql sql/oracle} { set path "[acs_package_root_dir $package_key]/$dir" if { ![file exists $path] } { file mkdir $path } } # Mark $version_id as the only installed version of the package. db_dml version_mark_installed { update apm_package_versions set installed_p = decode(version_id, :version_id, 't', 'f') where package_key = :package_key } } ns_log Debug "apm_package_install_spec: Done updating .info file." } ad_proc -public apm_version_enable { {-callback apm_dummy_callback} version_id } { Enables a version of a package (disabling any other version of the package). @param version_id The id of the version to be enabled. } { db_exec_plsql apm_package_version_enable { begin apm_package_version.enable( version_id => :version_id ); end; } apm_callback_and_log $callback "

          Package enabled." } ad_proc -public apm_version_disable { {-callback apm_dummy_callback} version_id } { Disables a version of a package. @param version_id The id of the version to be disabled. } { db_exec_plsql apm_package_version_disable { begin apm_package_version.disable( version_id => :version_id ); end; } apm_callback_and_log $callback "

          Package disabled." } ad_proc -public apm_package_register { {-spec_file_path ""} {-spec_file_mtime ""} package_key pretty_name pretty_plural package_uri package_type initial_install_p singleton_p implements_subsite_p inherit_templates_p } { Register the package in the system. } { if { $spec_file_path eq "" } { set spec_file_path [db_null] } if { $spec_file_mtime eq "" } { set spec_file_mtime [db_null] } if { $package_type eq "apm_application" } { db_exec_plsql application_register {} } elseif { $package_type eq "apm_service" } { db_exec_plsql service_register {} } else { error "Unrecognized package type: $package_type" } } ad_proc -public apm_version_update { {-callback apm_dummy_callback} {-array:required} version_id version_name version_uri summary description description_format vendor vendor_uri auto_mount {release_date ""} } { Update a version in the system to new information. } { upvar $array local_array if { $release_date eq "" } { set release_date [db_null] } set version_id [db_exec_plsql apm_version_update {}] apm::package_version::attributes::store \ -version_id $version_id \ -array local_array return $version_id } ad_proc -private apm_packages_full_install { {-callback apm_dummy_callback} pkg_info_list } { Loads the data model, installs, enables, instantiates, and mounts all of the packages in pkg_list. } { foreach pkg_info $pkg_info_list { if { [catch { set spec_file [pkg_info_spec $pkg_info] set package_key [pkg_info_key $pkg_info] apm_package_install \ -load_data_model \ -enable \ -callback $callback \ $spec_file } errmsg] } { global errorInfo apm_callback_and_log -severity Error $callback "

          [string totitle $package_key] not installed.

          Error:

          [ad_quotehtml $errmsg]
          [ad_quotehtml $errorInfo]
          " } } } ad_proc -private apm_package_upgrade_p {package_key version_name} { @return 1 if a version of the indicated package_key of version lower than version_name \ is already installed in the system, 0 otherwise. } { return [db_string apm_package_upgrade_p { select apm_package_version.version_name_greater(:version_name, version_name) upgrade_p from apm_package_versions where package_key = :package_key and version_id = apm_package.highest_version (:package_key) } -default 0] } ad_proc -private apm_package_upgrade_from { package_key version_name } { @param package_key The package you're installing @param version_name The version of the package you're installing @return the version of the package currently installed, which we're upgrading from, if it's different from the version_name passed in. If this is not an upgrade, returns the empty string. } { return [db_string apm_package_upgrade_from { select version_name from apm_package_versions where package_key = :package_key and version_id = apm_package.highest_version(:package_key) and version_name != :version_name } -default ""] } ad_proc -private apm_version_upgrade {version_id} { Upgrade a package to a locally maintained later version. } { db_exec_plsql apm_version_upgrade { begin apm_package_version.upgrade(version_id => :version_id); end; } } ad_proc -private apm_upgrade_for_version_p {path initial_version_name final_version_name} { @return 1 if the file indicated by path is valid .sql script to upgrade initial_version_name to final_version_name } { ns_log Debug "apm_upgrade_for_version_p: upgrade_p $path, $initial_version_name $final_version_name" return [db_exec_plsql apm_upgrade_for_version_p { begin :1 := apm_package_version.upgrade_p( path => :path, initial_version_name => :initial_version_name, final_version_name => :final_version_name ); end; }] } ad_proc -private apm_order_upgrade_scripts {upgrade_script_names} { Upgrade scripts are ordered so that they may be executed in a sequence that upgrades package. For example, if you start at version 1.0, and need to go to version 2.0, a correct order would be 1.0-1.5, 1.5-1.6, 1.6-2.0. @return an ordered list of upgrade script names. } { return [lsort -increasing -command apm_upgrade_script_compare $upgrade_script_names] } ad_proc -private apm_upgrade_script_compare {f1 f2} { @return 1 if f1 comes after f2, 0 if they are the same, -1 if f1 comes before f2. } { # Strip off any path information. set f1 [lindex [split $f1 /] end] set f2 [lindex [split $f2 /] end] # Get the version number from, e.g. the 2.0 from upgrade-2.0-3.0.sql if {[regexp {\-(.*)-.*.sql} $f1 match f1_version_from] && [regexp {\-(.*)-.*.sql} $f2 match f2_version_from]} { # At this point we should have something like 2.0 and 3.1d which Tcl string # comparison can handle. set f1_version_from [db_exec_plsql test_f1 {}] set f2_version_from [db_exec_plsql test_f2 {}] return [string compare $f1_version_from $f2_version_from] } else { error "Invalid upgrade script syntax. Should be \"upgrade-major.minor-major.minor.sql\"." } } ad_proc -private apm_data_model_scripts_find { {-upgrade_from_version_name ""} {-upgrade_to_version_name ""} {-package_path ""} package_key } { @param version_id What version the files belong to. @param upgrade Set this switch if you want the scripts for upgrading. @file_list A list of files and file types of form [list [list "foo.sql" "data_model_upgrade"] ...] } { set types_to_retrieve [list "sqlj_code"] if {$upgrade_from_version_name eq ""} { lappend types_to_retrieve "data_model_create" # Assuming here that ctl_file files are not upgrade scripts # TODO: Make it possible to determine which ctl files are upgrade scripts and which aren't lappend types_to_retrieve "ctl_file" } else { lappend types_to_retrieve "data_model_upgrade" } set data_model_list [list] set upgrade_file_list [list] set ctl_file_list [list] set file_list [apm_get_package_files -file_types $types_to_retrieve -package_path $package_path -package_key $package_key] foreach path $file_list { set file_type [apm_guess_file_type $package_key $path] set file_db_type [apm_guess_db_type $package_key $path] apm_log APMDebug "apm_data_model_scripts_find: Checking \"$path\" of type \"$file_type\" and db_type \"$file_db_type\"." if {[lsearch -exact $types_to_retrieve $file_type] != -1 } { set list_item [list $path $file_type $package_key] if {$file_type eq "data_model_upgrade"} { # Upgrade script if {[apm_upgrade_for_version_p $path $upgrade_from_version_name \ $upgrade_to_version_name]} { # Its a valid upgrade script. ns_log Debug "apm_data_model_scripts_find: Adding $path to the list of upgrade files." lappend upgrade_file_list $list_item } } elseif {$file_type eq "ctl_file"} { lappend ctl_file_list $list_item } else { # Install script apm_log APMDebug "apm_data_model_scripts_find: Adding $path to the list of data model files." lappend data_model_list $list_item } } } # ctl files need to be loaded after the sql create scripts set file_list [concat [apm_order_upgrade_scripts $upgrade_file_list] \ $data_model_list \ $ctl_file_list] apm_log APMDebug "apm_data_model_scripts_find: Data model scripts for $package_key: $file_list" return $file_list } ad_proc -private apm_query_files_find { package_key file_list } { @file_list A list of files and file types of form [list [list "foo.sql" "data_model_upgrade"] ...] } { set query_file_list [list] foreach file $file_list { set path [lindex $file 0] set file_type [lindex $file 1] set file_db_type [lindex $file 2] ns_log Debug "apm_query_files_find: Checking \"$path\" of type \"$file_type\" and db_type \"$file_db_type\"." # DRB: we return query files which match the given database type or for which no db_type # is defined, which we interpret to mean a file containing queries that work with all of our # supported databases. if {[lsearch -exact "query_file" $file_type] != -1 && \ ($file_db_type eq "" || [db_type] eq $file_db_type )} { ns_log Debug "apm_query_files_find: Adding $path to the list of query files." lappend query_file_list $path } } ns_log Notice "apm_query_files_find: Query files for $package_key: $query_file_list" return $query_file_list } ad_proc -private apm_mount_core_packages {} {

          Mount, and set permissions for a number of packages part of the OpenACS core. The packages are singletons that have already been instantiated during installation. The main site needs to have been set up prior to invoking this proc.

          The reason mounting is done here and not via the auto-mount feature of the APM is that there is a circular dependency between acs-subsite and acs-content-repository. The package acs-subsite requires acs-content-repository and so we cannot install acs-subsite before acs-content-repository in order to be able to mount acs-content-repository.

          @see site_node::instantiate_and_mount @author Peter Marklund } { ns_log Notice "apm_mount_core_packages: Starting mounting of core packages" # Mount acs-lang ns_log Notice "apm_mount_core_packages: Mounting acs-lang" set acs_lang_id [site_node::instantiate_and_mount -package_key acs-lang] permission::grant -party_id [acs_magic_object the_public] \ -object_id $acs_lang_id \ -privilege read # Mount acs-admin ns_log Notice "apm_mount_core_packages: Mounting acs-admin" site_node::instantiate_and_mount -package_key acs-admin # Mount acs-service-contract ns_log Notice "apm_mount_core_packages: Mounting acs-service-contract" site_node::instantiate_and_mount -package_key acs-service-contract # Mount the acs-content-repository ns_log Notice "apm_mount_core_packages: Mounting acs-content-repository" site_node::instantiate_and_mount -package_key acs-content-repository # Mount acs-core-docs ns_log Notice "apm_mount_core_packages: Mounting acs-core-docs" site_node::instantiate_and_mount -node_name doc \ -package_key acs-core-docs # Mount the acs-api-browser ns_log Notice "apm_mount_core_packages: Mounting acs-api-browser" set api_browser_id \ [site_node::instantiate_and_mount -node_name api-doc \ -package_key acs-api-browser] # Only registered users should have permission to access the # api-browser permission::grant -party_id [acs_magic_object registered_users] \ -object_id $api_browser_id \ -privilege read permission::set_not_inherit -object_id $api_browser_id # Mount acs-automated-testing ns_log Notice "apm_mount_core_packages: Mounting acs-automated-testing" site_node::instantiate_and_mount -node_name test \ -package_key acs-automated-testing ns_log Notice "apm_mount_core_packages: Finished mounting of core packages" } ad_proc -public apm_version_sortable { version } { Return a sortable version of the version name. @author Jeff Davis } { return [db_string sortable_version {}] } ad_proc -public apm_version_names_compare { version_name_1 version_name_2 } { Compare two version names for which is earlier than the other. Example:
          • apm_version_names_compare "1.2d3" "3.5b" => -1
          • apm_version_names_compare "3.5b" "3.5b" => 0
          • apm_version_names_compare "3.5b" "1.2d3" => 1
          @param version_name_1 the first version name @param version_name_2 the second version name @return
          • -1: the first version is smallest
          • 0: they're identical
          • 1: the second version is smallest
          @author Lars Pind } { db_1row select_sortable_versions {} return [string compare $sortable_version_1 $sortable_version_2] } ad_proc -private apm_upgrade_logic_compare { from_to_key_1 from_to_key_2 } { Compare the from-versions in two of apm_upgrade_logic's array entries on the form 'from_version_name,to_version_name'. @param from_to_key the key from the array in apm_upgrade_logic @return 1 if 1 comes after 2, 0 if they are the same, -1 if 1 comes before 2. @author Lars Pind } { return [apm_version_names_compare [lindex [split $from_to_key_1 ","] 0] [lindex [split $from_to_key_2 ","] 0]] } ad_proc -public apm_upgrade_logic { {-from_version_name:required} {-to_version_name:required} {-spec:required} } { Logic to help upgrade a package. The spec contains a list on the form \{ from_version to_version code_chunk from_version to_version code_chunk ... \}. The list is compared against the from_version_name and to_version_name parameters supplied, and the code_chunks that fall within the from_version_name and to_version_name it'll get executed in the caller's namespace, ordered by the from_version.

          Example:

          
              ad_proc my_upgrade_callback {
                  {-from_version_name:required}
                  {-to_version_name:required}
              } {
                  apm_upgrade_logic \ 
                          -from_version_name $from_version_name \ 
                          -to_version_name $to_version_name \ 
                          -spec {
                      1.1 1.2 {
                          ...
                      }
                      1.2 1.3 {
                          ...
                      }
                      1.4d 1.4d1 {
                          ...
                      }
                      2.1 2.3 {
                          ...
                      }
                      2.3 2.4 {
                          ...
                      }
                  }
              }
          
              
          @param from_version_name The version you're upgrading from, e.g. '1.3'. @param to_version_name The version you're upgrading to, e.g. '2.4'. @param spec The code chunks in the format described above @author Lars Pind } { if { [expr {[llength $spec] % 3}] != 0 } { error "The length of spec should be dividable by 3" } array set chunks [list] foreach { elm_from elm_to elm_chunk } $spec { # Check that # from_version_name < elm_from < elm_to < to_version_name if { [apm_version_names_compare $from_version_name $elm_from] <= 0 && \ [apm_version_names_compare $elm_from $elm_to] <= 0 && \ [apm_version_names_compare $elm_to $to_version_name] <= 0 } { set chunks($elm_from,$elm_to) $elm_chunk } } foreach key [lsort -increasing -command apm_upgrade_logic_compare [array names chunks]] { uplevel $chunks($key) } } ############## # # Repository procs # ############# ad_proc -private apm_get_package_repository { {-repository_url ""} {-array:required} } { Gets a list of packages available for install from either a remote package repository or the local file system. @param repository_url The URL for the repository channel to get from, or the empty string to seach the local file system instead. @param array Name of an array where you want the repository stored. It will be keyed by package-key, and each entry will be an array list list what's returned by apm_read_package_info_file. @see apm_read_package_info_file @author Lars Pind (lars@collaboraid.biz) } { # This will be a list of array-lists of packages available for install upvar 1 $array repository apm_get_installed_versions -array installed_version if { $repository_url ne "" } { set manifest_url "${repository_url}manifest.xml" # See if we already have it in a client property set manifest [ad_get_client_property acs-admin [string range $manifest_url end-49 end]] if { $manifest eq "" } { # Nope, get it now array set result [ad_httpget -timeout 120 -url $manifest_url] if { $result(status) ne "200" } { error "Couldn't get the package list. Please try again later." } set manifest $result(page) # Store for subsequent requests ad_set_client_property -clob t acs-admin [string range $manifest_url end-49 end] $manifest } # Parse manifest set tree [xml_parse -persist $manifest] set root_node [xml_doc_get_first_node $tree] foreach package_node [xml_node_get_children_by_name $root_node "package"] { array unset version set version(package.key) [xml_node_get_content [xml_node_get_first_child_by_name $package_node "package-key"]] set version(name) [xml_node_get_content [xml_node_get_first_child_by_name $package_node "version"]] set version(package-name) [xml_node_get_content [xml_node_get_first_child_by_name $package_node "pretty-name"]] set version(package.type) [xml_node_get_content [xml_node_get_first_child_by_name $package_node "package-type"]] set version(download_url) [xml_node_get_content [xml_node_get_first_child_by_name $package_node "download-url"]] set version(summary) [xml_node_get_content [xml_node_get_first_child_by_name $package_node "summary"]] apm::package_version::attributes::parse_xml \ -parent_node $package_node \ -array version foreach dependency_type { provides requires embeds extends } { set version($dependency_type) {} foreach dependency_node [xml_node_get_children_by_name $package_node "$dependency_type"] { lappend version($dependency_type) \ [list [xml_node_get_attribute $dependency_node "url"] \ [xml_node_get_attribute $dependency_node "version"]] } } if { ![info exists installed_version($version(package.key))] } { # Package is not installed set version(install_type) install } elseif { [string equal $version(name) $installed_version($version(package.key))] || \ [apm_higher_version_installed_p $version(package.key) $version(name)] != 1 } { # This version or a higher version already installed set version(install_type) already_installed } else { # Earlier version installed, this is an upgrade set version(install_type) upgrade } ns_log Debug "apm_get_package_repository: $version(package.key) = $version(install_type) -- [array get installed_version]" if { $version(install_type) ne "already_installed" } { set repository($version(package.key)) [array get version] } } } else { # Parse spec files foreach spec_file [apm_scan_packages "[acs_root_dir]/packages"] { with_catch errmsg { array unset version array set version [apm_read_package_info_file $spec_file] # If the package doesn't support this RDBMS, it's not really available for install if { [apm_package_supports_rdbms_p -package_key $version(package.key)] } { if { ![info exists installed_version($version(package.key))] } { # Package is not installed set version(install_type) install } elseif { [string equal $version(name) $installed_version($version(package.key))] || \ [apm_higher_version_installed_p $version(package.key) $version(name)] != 1 } { # This version or a higher version already installed set version(install_type) already_installed } else { # Earlier version installed, this is an upgrade set version(install_type) upgrade } if { $version(install_type) ne "already_installed" } { set repository($version(package.key)) [array get version] } } } { # We don't error hard here, because we don't want the whole process to fail if there's just one # package with a bad .info file global errorInfo ns_log Error "apm_get_package_repository: Error while checking package info file $spec_file: $errmsg\n$errorInfo" } } } } ad_proc -public apm_get_repository_channel {} { Returns the channel to use when installing software from the repository. Based on the version of the acs-kernel package, e.g. if acs-kernel is version 5.0.1, then this will return 5-0. } { set kernel_versionv [split [ad_acs_version] .] return [join [lrange $kernel_versionv 0 1] "-"] } ad_proc -private apm_load_install_xml {filename binds} { Loads an install file and returns the root node. errors out if the file is not there. substitutes variables before parsing so you can provide interpolated values. @param filename relative to serverroot, leading slash needed. @param binds list of {variable value variable value ...} @return root_node of the parsed xml file. @author Jeff Davis davis@xarg.net @creation-date 2003-10-30 } { # Abort if there is no install.xml file set filename [acs_root_dir]$filename if { ![file exists $filename] } { error "File $filename not found" } # Read the whole file set file [open $filename] set __the_body__ [read $file] close $file # Interpolate the vars. if {$binds ne ""} { foreach {var val} $binds { set $var [ad_quotehtml $val] } if {![info exists Id]} { set Id {$Id} } if {[catch {set __the_body__ [subst -nobackslashes -nocommands ${__the_body__}]} err]} { error $err } } set root_node [xml_doc_get_first_node [xml_parse -persist ${__the_body__}]] return $root_node } ad_proc -public apm::process_install_xml { -nested:boolean filename binds } { process an xml install definition file which is expected to contain directives to install, mount and configure a series of packages. @parameter filename path to the xml file relative to serverroot. @param binds list of {variable value variable value ...} @return list of messages @author Jeff Davis (swiped from acs-bootstrap-installer though) @creation-date 2003-10-30 } { variable ::install::xml::ids # If it's not a nested call then initialize the ids array. # If it is nested we will typically need id's from the parent if {!$nested_p} { array unset ids array set ids [list] # set default ids for the main site and core packages set ids(ACS_KERNEL) [apm_package_id_from_key acs-kernel] set ids(ACS_TEMPLATING) [apm_package_id_from_key acs-templating] set ids(ACS_AUTHENTICATION) [apm_package_id_from_key acs-authentication] set ids(ACS_LANG) [apm_package_id_from_key acs-lang] set ids(MAIN_SITE) [subsite::main_site_id] } variable ::template::parse_level lappend ::template::parse_level [info level] set root_node [apm_load_install_xml $filename $binds] set acs_application(name) [apm_required_attribute_value $root_node name] set acs_application(pretty_name) [apm_attribute_value -default $acs_application(name) $root_node pretty-name] lappend out "Loading packages for the $acs_application(pretty_name) application." set actions [xml_node_get_children_by_name $root_node actions] if { [llength $actions] != 1 } { ns_log Error "Error in \"$filename\": only one action node is allowed, found: [llength $actions]" error "Error in \"$filename\": only one action node is allowed" } set actions [xml_node_get_children [lindex $actions 0]] foreach action $actions { set install_proc_out [apm_invoke_install_proc -node $action] set out [concat $out $install_proc_out] } # pop off parse level template::util::lpop parse_level return $out } ad_proc -private apm_invoke_install_proc { {-type "action"} {-node:required} } { read an xml install element and invoke the appropriate processing procedure. @param type the type of element to search for @param node the xml node to process @return the result of the invoked proc @author Lee Denison @creation-date 2004-06-16 } { set name [xml_node_get_name $node] set command [info commands ::install::xml::${type}::${name}] if {[llength $command] == 0} { error "Error: got bad node \"$name\"" } return [eval [list ::install::xml::${type}::${name} $node]] } ############## # # Dynamic package version attributes (namespace apm::package_version::attributes) # ############# ad_proc -private apm::package_version::attributes::set_all_instances_names {} { Set all names of the instances for those packages that have the attribute package_instance_name. After running this script you must restart your installation. } { # packages list db_foreach get_packages_keys { select package_key from apm_enabled_package_versions } { # Getting the instance name set package_instance_name [apm::package_version::attributes::get_instance_name $package_key] # Getting package_name set path [apm_package_info_file_path $package_key] array set version_properties [apm_read_package_info_file $path] set package_name $version_properties(package-name) # Getting instances name db_foreach get_instances_names { select instance_name from apm_packages where package_key = :package_key } { # Removing the character "#". regsub -all {[\#]*} $instance_name {\1} instance_name # Verifying whether this instance_name is a message_key set is_msg [lang::message::message_exists_p [ad_conn locale] $instance_name] if {$package_name eq $instance_name && $is_msg eq 0} { if { $package_instance_name ne ""} { # Updating the names of the instances for this package_key db_transaction { db_dml app_rename { update apm_packages set instance_name = :package_instance_name where package_key = :package_key } } } } } } } ad_proc -private apm::package_version::attributes::get_instance_name { package_key } { Return the package_instance_name which is used for naming instances in .LRN, every time that we are creating a class. @author Cesar Hernandez } { set parameter "package_instance_name" set version_id [apm_version_id_from_package_key $package_key] if {$version_id ne ""} { apm::package_version::attributes::get -version_id $version_id -array packages_names # it was added this catch for those packages that does not # have the attribute package instance name, in this case # return "" if {[catch {set instance_name $packages_names($parameter)} errmsg]} { return "" } else { return $instance_name } } } ad_proc -private apm::package_version::attributes::get_spec {} { Return dynamic attributes of package versions in an array list. The rationale for introducing the dynamic package version attributes is to make it easy to add new package attributes. @return An array list with attribute names as keys and attribute specs as values. The attribute specs are themselves array lists with keys default_value, validation_proc, and pretty_name. @author Peter Marklund } { return { maturity { pretty_name Maturity default_value 0 validation_proc apm::package_version::attributes::validate_maturity } license { pretty_name License } license_url { pretty_name "License URL" } package_instance_name { pretty_name "Package instance name" } } } ad_proc -private apm::package_version::attributes::get_pretty_name { attribute_name } { Return the pretty name of attribute with given short name. @author Peter Marklund } { array set attributes [apm::package_version::attributes::get_spec] array set attribute $attributes($attribute_name) return $attribute(pretty_name) } ad_proc -private apm::package_version::attributes::validate_maturity { maturity } { set error_message "" if { $maturity ne "" } { if { ![regexp {^-?[0-9]+$} $maturity] } { set error_message "Maturity must be integer" } elseif { [expr {$maturity < -1 || $maturity > 3}] } { set error_message "Maturity must be integer between -1 and 3" } } return $error_message } ad_proc -private apm::package_version::attributes::maturity_int_to_text { maturity } { Get the internationalized maturity description corresponding to the given integer package maturity level. @author Peter Marklund } { if {[exists_and_not_null maturity]} { if { ![expr {$maturity >= -1 && $maturity <= 3}] } { error "Maturity must be between -1 and 3 but is \"$maturity\"" } set maturity_key(-1) "#acs-tcl.maturity_incompatible#" set maturity_key(0) "#acs-tcl.maturity_new_submission#" set maturity_key(1) "#acs-tcl.maturity_immature#" set maturity_key(2) "#acs-tcl.maturity_mature#" set maturity_key(3) "#acs-tcl.maturity_mature_and_standard#" set result [lang::util::localize $maturity_key($maturity)] } else { set result "" } return $result } ad_proc -private apm::package_version::attributes::parse_xml { {-parent_node:required} {-array:required} } { Given the parent node in an XML tree parse the package version attributes and set their values with upvar in the array with given name. @param parent_node A reference to the parent XML node of the attribute nodes @param array The name of the array in the callers scope to set the attribute values in. @author Peter Marklund } { upvar $array attributes array set dynamic_attributes [apm::package_version::attributes::get_spec] foreach attribute_name [array names dynamic_attributes] { set attribute_node [xml_node_get_first_child_by_name $parent_node $attribute_name] array set attribute $dynamic_attributes($attribute_name) if { $attribute_node ne "" } { # There is a tag for the attribute so use the tag contents set attributes($attribute_name) [xml_node_get_content $attribute_node] } else { # No tag for the attribute - use default value set attributes($attribute_name) [apm::package_version::attributes::default_value $attribute_name] } } } ad_proc -private apm::package_version::attributes::default_value { attribute_name } { Return the default value for the given attribute name. @author Peter Marklund } { array set dynamic_attributes [apm::package_version::attributes::get_spec] array set attribute $dynamic_attributes($attribute_name) if { [info exists attribute(default_value)] } { set default_value $attribute(default_value) } else { # No default value so use the empty string (the default default value) set default_value "" } return $default_value } ad_proc -private apm::package_version::attributes::store { {-version_id:required} {-array:required} } { Store the dynamic attributes of a certain package version in the database. @param version_id The id of the package version to store attribute values for @param array The name of the array in the callers scope containing the attribute values to store @author Peter Marklund } { upvar $array attributes db_transaction { db_dml clear_old_attributes { delete from apm_package_version_attr where version_id = :version_id } array set dynamic_attributes [apm::package_version::attributes::get_spec] foreach attribute_name [array names dynamic_attributes] { if { [info exists attributes($attribute_name)] } { set attribute_value $attributes($attribute_name) db_dml insert_attribute { insert into apm_package_version_attr (attribute_name, attribute_value, version_id) values (:attribute_name, :attribute_value, :version_id) } } } } } ad_proc -private apm::package_version::attributes::get { {-version_id:required} {-array:required} } { Set an array with the attribute values of a certain package version. @param version_id The id of the package version to return attribute values for @param The name of an array in the callers environment in which the attribute values will be set (with attribute names as keys and attribute values as values). @author Peter Marklund } { upvar $array attributes db_foreach select_attribute_values { select attribute_name, attribute_value from apm_package_version_attr where version_id = :version_id } { set attributes($attribute_name) $attribute_value } } ad_proc -private apm::package_version::attributes::generate_xml { {-version_id:required} {-indentation ""} } { Return an XML string with the dynamic package version attributes for a certain package version. @param version_id The id of the package version to generate the attribute XML for. @param indentation A string with whitespace to indent each tag with @author Peter Marklund } { set xml_string "" array set attributes [apm::package_version::attributes::get \ -version_id $version_id \ -array attributes] # sort the array so that the xml is always in the same order so # its stable for CVS. foreach attribute_name [lsort [array names attributes]] { # Only output tag if its value is non-empty if { $attributes($attribute_name) ne "" } { append xml_string "${indentation}<${attribute_name}>[ad_quotehtml $attributes($attribute_name)]\n" } } return $xml_string } ############## # # Deprecated Procedures # ############# openacs-5.7.0/packages/acs-tcl/tcl/apm-install-procs.xql0000644000175000017500000000603311456662501022764 0ustar frankiefrankie update apm_package_versions set installed_p = 'f', enabled_p = 'f' where package_key = :package_key select count(*) from apm_package_versions where package_key = :package_key select parameter_id from apm_parameters where parameter_name = :parameter_name and package_key = :package_key select dependency_id from apm_package_dependencies where version_id = :version_id delete from apm_package_owners where version_id = :version_id insert into apm_package_owners(version_id, owner_uri, owner_name, sort_key) values(:version_id, :owner_uri, :owner_name, :counter) select package_key, version_id from apm_package_version_info where version_id = :version_id update apm_package_types set spec_file_path = :path where package_key = :package_key delete from apm_package_callbacks where version_id = :version_id select ap.parameter_id from apm_parameters ap where ap.package_key = :package_key and exists (select 1 from apm_parameters ap2, apm_package_dependencies apd where ap2.package_key = apd.service_uri and ap2.parameter_name = ap.parameter_name and apd.dependency_id = :dependency_id) select ap.* from apm_parameters ap where package_key = :new_package_key and parameter_name = :parameter_name select ap.* from apm_parameters ap where package_key = :inherited_package_key and scope = 'instance' openacs-5.7.0/packages/acs-tcl/tcl/request-processor-procs-postgresql.xql0000644000175000017500000000040007361111434026433 0ustar frankiefrankie postgresql7.1 select site_node__url(:node_id) as url openacs-5.7.0/packages/acs-tcl/tcl/20-memoize-init.tcl0000644000175000017500000000227311124154044022212 0ustar frankiefrankie# Create the cache used by util_memoize. # Note: we must pass the package_id to parameter::get, because # otherwise parameter::get will end up calling util_memoize to figure # out the package_id. ns_cache create util_memoize -size \ [parameter::get -package_id [ad_acs_kernel_id] -parameter MaxSize -default 200000] # We construct the body of util_memoize_flush differently depending # on whether clustering is enabled and what command is available for # cluster-wide flushing. if {[llength [info commands ncf.send]] > 0} { set flush_body { ncf.send util_memoize $script } } elseif {[server_cluster_enabled_p] && [info commands server_cluster_httpget_from_peers] ne ""} { set flush_body { server_cluster_httpget_from_peers "/SYSTEM/flush-memoized-statement.tcl?statement=[ns_urlencode $script]" } } else { set flush_body {} } append flush_body { ns_cache flush util_memoize $script } ad_proc -public util_memoize_flush {script} { Forget any cached value for script. If clustering is enabled, flush the caches on all servers in the cluster. @param script The Tcl script whose cached value should be flushed. } $flush_body unset flush_body openacs-5.7.0/packages/acs-tcl/tcl/form-processing-procs.tcl0000644000175000017500000015337411345565523023654 0ustar frankiefrankiead_library { Form processing utilities. @author Don Baccus (dhogaza@pacifier.net) } ad_proc -public ad_form { args } { This procedure implements a high-level, declarative syntax for the generation and handling of HTML forms. It includes special syntax for the handling of forms tied to database entries, including the automatic generation and handling of primary keys generated from sequences. You can declare code blocks to be executed when the form is submitted, new data is to be added, or existing data modified. You can declare form validation blocks that are similar in spirit to those found in ad_page_contract.

          Developer's Guide fo ad_form

          We use the standard OpenACS Templating System (ATS) form builder's form and element create procedures to generate forms, and its state-tracking code to determine when to execute various code blocks. Because of this, you can use any form builder datatype or widget with this procedure, and extending its functionality is a simple matter of implementing new ones. Because ad_form is just a wrapper for the ATS, you must familiarize yourself with it to be able to use ad_form effectively.

          In general the full functionality of the form builder is exposed by ad_form, but with a much more user-friendly and readable syntax and with state management handled automatically.

          Important note about how ad_form works: ad_form operates in two modes:
          1. Declaring the form
          2. Executing the form
          Through the -extend switch, you can declare the form in multiple steps, adding elements. But as soon as you add an action block (on_submit, after_submit, new_data, edit_data, etc.), ad_form will consider the form complete, and execute the form, meaning validating element values, and executing the action blocks. The execution will happen automatically the first time you call ad_form with an action block, and after that point, you cannot -extend the form later. Also, if you don't supply any action blocks at all, the form will never be considered finished, and thus validation will not get executed. Instead, you will get an error when the form is rendered.

          Bottom line:

          1. You must always have at least one action block, even if it's just -on_submit { }.
          2. You cannot extend the form after you've supplied any action block.

          In order to make it possible to use ad_form to build common form snippets within procs, code blocks are executed at the current template parse level. This is necessary if validate and similar blocks are to have access to the form's contents but may cause surprises for the unwary. So be wary.

          On the other hand when subst is called, for instance when setting values in the form, the caller's level is used. Why do this? A proc building a common form snippet may need to build a list of valid select elements or similarly compute values that need to be set in the form, and these should be computed locally.

          Yes, this is a bit bizarre and not necessarily well thought out. The semantics were decided upon when I was writing a fairly complex package for Greenpeace, International and worked well there so for now, I'm leaving them the way they are.

          Here's an example of a simple page implementing an add/edit form:

          
              ad_page_contract {
          
          
                  Simple add/edit form
          
              } {
                  my_table_key:optional
              }
          
              ad_form -name form_name -export {foo {bar none}} -form {
          
                  my_table_key:key(my_table_sequence)
          
                  {value:text(textarea)             {label "Enter text"}
                                                     {html {rows 4 cols 50}}}
              } -select_query {
                  select value from my_table where my_table_key = :my_table_key
              } -validate {
                  {value
                   {[string length $value] >= 3}
                   "\"value\" must be a string containing three or more characters"
                  }
              } -new_data {
                  db_dml do_insert "
                      insert into my_table
                        (my_table_key, value)
                      values
                        (:key, :value)"
              } -edit_data {
                  db_dml do_update "
                      update my_table
                      set value = :value
                      where my_table_key = :key"
              } -after_submit {
                  ad_returnredirect "somewhere"
                  ad_script_abort
              }
          
              

          In this example, ad_form will first check to see if "my_table_key" was passed to the script. If not, the database will be called to generate a new key value from "my_table_sequence" (the sequence name defaults to acs_object_id_seq). If defined, the query defined by "-select_query" will be used to fill the form elements with existing data (an error will be thrown if the query fails).

          The call to ad_return_template then renders the page - it is your responsibility to render the form in your template by use of the ATS formtemplate tag.

          On submission, the validation block checks that the user has entered at least three characters into the textarea (yes, this is a silly example). If the validation check fails the "value" element will be tagged with the error message, which will be displayed in the form when it is rendered. If the validation check returns true, one of the new_data or edit_data code blocks will be executed depending on whether or not "my_table_key" was defined during the initial request. "my_table_key" is passed as a hidden form variable and is signed and verified, reducing the opportunity for key spoofing by malicious outsiders.

          This example includes dummy redirects to a script named "somewhere" to make clear the fact that after executing the new_data or edit_data block ad_form returns to the caller.

          General information about parameters

          Parameters which take a name (for instance "-name" or "-select_query_name") expect a simple name not surrounded by curly braces (in other words not a single-element list). All other parameters expect a single list to be passed in.

          Here's a complete list of switches that are supported by ad_form:

          -extend

          Extend an existing form. This allows one to build forms incrementally. Forms are built at the template level. As a consequence one can write utility procs that use -extend to build form snippets common to several data entry forms. Note that the full form block must be built up (extended) and completed before any action blocks such as select_query, new_request, edit_request etc. are defined.

          This must be the first switch passed into ad_form

          -name

          Declares the name of the form. Defaults to the name of the script being served.

          -action

          The name of the script to be called when the form is submitted. Defaults to the name of the script being served.

          -actions

          A list of lists of actions (e.g. {{" Delete " delete} {" Resolve " resolve}} ), which gets translated to buttons at the bottom of the form. You can find out what button was pressed with [template::form get_action form_id], usually in the -edit_request block to perform whatever actions you deem appropriate. When the form is loaded the action will be empty.

          -mode { display | edit }

          If set to 'display', the form is shown in display-only mode, where the user cannot edit the fields. Each widget knows how to display its contents appropriately, e.g. a select widget will show the label, not the value. If set to 'edit', the form is displayed as normal, for editing. Defaults to 'edit'. Switching to edit mode when a button is clicked in display mode is handled automatically

          -has_edit { 0 | 1 }

          Set to 1 to suppress the Edit button automatically added by the form builder. Use this if you include your own.

          -has_submit { 0 | 1 }

          Set to 1 to suppress the OK button automatically added by the form builder. Use this if you include your own.

          -method

          The standard METHOD attribute to specify in the HTML FORM tag at the beginning of the rendered form. Defaults to POST.

          -form

          Declare form elements (described in detail below)

          -cancel_url

          The URL the cancel button should take you to. If this is specified, a cancel button will show up during the edit phase.

          -cancel_label

          The label for the cancel button.

          -html

          The given html will be added to the "form" tag when page is rendered. This is commonly used to define multipart file handling forms.

          -export

          Similar to the utility export_vars. Takes a list of values to insert in the form as "hidden" elements. Each value is either a name, in which case the Tcl variable at the caller's level is passed to the form if it exists, or a name-value pair. "multiple", "array", "sign" and similar flags are not allowed though it would be good to do so in the future.

          -select_query

          Defines a query that returns a single row containing values for each element of the form meant to be modifiable by the user. Can only be used if an element of type key has been declared. Values returned from the query are available in the form, but not the ADP template (for that, use -edit_request instead).

          -select_query_name

          Identical to -select_query, except instead of specifying the query inline, specifies a query name. The query with that name from the appropriate XQL file will be used. Use -select_query_name rather than -select_query whenever possible, as query files are the mechanism used to make the support of multiple RDMBS systems possible.

          -show_required_p { 0 | 1 }

          Should the form template show which elements are required. Use 1 or t for true, 0 or f for false. Defaults to true.

          -on_request

          A code block which sets the values for each element of the form meant to be modifiable by the user when the built-in key management feature is being used or to define options for select lists etc. Set the values as local variables in the code block, and they'll get fetched and used as element values for you. This block is executed everytime the form is loaded except when the form is being submitted (in which case the -on_submit block is executed.)

          -edit_request

          A code block which sets the values for each element of the form meant to be modifiable by the user. Use this when a single query to grab database values is insufficient. Any variables set in an -edit_request block are available to the ADP template as well as the form, while -select_query sets variables in the form only. Can only be used if an element of type key is defined. This block is only executed if the page is called with a valid key, i.e. a self-submit form to add or edit an item called to edit the data. Set the values as local variables in the code block, and they'll get fetched and used as element values for you.

          -new_request

          A code block which sets the values for each element of the form meant to be modifiable by the user. Use this when a single query to grab database values is insufficient. Can only be used if an element of type key is defined. This block complements the -edit_request block. You just need to set the values as local variables in the code block, and they'll get fetched and used as element values for you.

          -confirm_template

          The name of a confirmation template to be called before any on_submit, new_data or edit_data block. When the user confirms input control will be passed to the appropriate submission block. The confirmation template can be used to provide a bboard-like preview/confirm page. Your confirmation template should render the form contents in a user-friendly way then include "/packages/acs-templating/resources/forms/confirm-button". The "confirm-button" template not only provides a confirm button but includes the magic incantation that tells ad_form that the form has been confirmed by the user and that it is safe to call the proper submission block.

          -on_refresh

          Executed when the form comes back from being refreshed using javascript with the __refreshing_p flag set.

          -on_submit

          When the form is submitted, this code block will be executed before any new_data or edit_data code block. Use this if your form doesn't interact with the database or if the database type involved includes a Tcl API that works for both new and existing data. The values of the form's elements will be available as local variables. Calling 'break' inside this block causes the submission process to be aborted, and neither new_data, edit_data, nor after_submit will get executed. Useful in combination with template::form set_error to display an error on a form element.

          -new_data

          This code block will be executed when a form for a new database row is submitted. This block should insert the data into the database or create a new database object or content repository item containing the data. Calling 'break' inside this block causes the submission process to be aborted, and after_submit will not get executed. Useful in combination with template::form set_error to display an error on a form element.

          -edit_data

          This code block will be executed when a form for an existing database row is submitted. This block should update the database or create a new content revision for the exisiting item if the data's stored in the content repository. Calling 'break' inside this block causes the submission process to be aborted, and after_submit will not get executed. Useful in combination with template::form set_error to display an error on a form element.

          -after_submit

          This code block will be executed after the three blocks on_submit, new_data or edit_data have been executed. It is useful for putting in stuff like ad_returnredirect that is the same for new and edit.

          -validate

          A code block that validates the elements in the form. The elements are set as local values. The block has the following form:
          {element_name
              {tcl code that returns 1 or 0}
              "Message to be shown by that element in case of error"
          }
          {...}
                 

          -on_validation_error

          A code block that is executed if validation fails. This can be done to set a custom page title or some similar action.
          Two hidden values of interest are available to the caller of ad_form when processing a submit:

          __new_p

          If a database key has been declared, __new_p will be set true if the form submission is for a new value. If false, the key refers to an existing values. This is useful for forms that can easily process either operation in a single on_submit block, rather than use separate new_data and edit_data blocks.

          __refreshing_p

          This should be set true by Javascript widgets which change a form element then submit the form to refresh values.

          Declaring form elements

          ad_form uses the form builder's form element create procedure to generate elements declared in the -form block. ad_form does rudimentary error checking to make sure the data type and widget exist, and that options are legal.

          The -form block is a list of form elements, which themselves are lists consisting of one or two elements. The first member of each element sublist declares the form element name, datatype, widget, whether or not the element is a multiple element (multiselect, for instance), and optional conversion arguments. The second, optional member consists of a list of form element parameters and values. All parameters accepted by the form element create procedure are allowed.

          • Avaliable datatypes. For example, the procedure template::data::validate::float on this list implements the 'float' datatype.
          • Available widgets. For example, the procedure template::widget::radio implements the 'radio' widget. Not all widgets are compatible with all datatypes.
          • Form element parameters and values. For example, the parameter -label "My label" is written {label "My label"} in the element sublist of the -form block to ad_form.

          Some form builder datatypes build values that do not directly correspond to database types. When using the form builder directly these are converted by calls to datatype::get_property and datatype::acquire. When using ad_form, "to_html(property)", "to_sql(property)" and "from_sql(property)" declare the appropriate properties to be retrieved or set before calling code blocks that require the converted values. The "to_sql" operation is performed before any on_submit, new_data or edit_data block is executed. The "from_sql" operation is performed after a select_query or select_query_name query is executed. No automatic conversion is performed for edit_request blocks (which manually set form values). The "to_html" operation is performed before execution of a confirm template.

          Currently only the date and currency datatypes require these conversion operations.

          In the future the form builder will be enhanced so that ad_form can determine the proper conversion operation automatically, freeing the programmer from the need to specify them. When this is implemented the current notation will be retained for backwards compatibility.

          ad_form defines a "key" pseudotype. Only one element of type "key" is allowed per form, and it is assigned the integer datatype. Only keys which are generated from a database sequence are managed automatically by ad_form. If the sequence name is not specified, the sequence acs_object_id_seq is used to generate new keys. Examples:

              my_key:key
              

          Define the key "my_key", assigning new values by calling acs_object_id_seq.nextval

              my_key:key(some_sequence_name)
              

          Define the key "my_key", assigning new values by calling some_sequence_name.nextval

              {my_key:text(multiselect),multiple       {label "select some values"}
                                                        {options {first second third fourth fifth}}
                                                        {html {size 4}}}
                                            
              

          Define a multiple select element with five choices, in a four-line select box.

              {hide_me:text(hidden)                     {value 3}}
              

          Define the hidden form element "hide_me" with the value 3

              start_date:date,to_sql(linear_date),to_html(sql_date),optional
              

          Define the optional element "start_date" of type "date", get the sql_date property before executing any new_data, edit_data or on_submit block, set the sql_date property after performing any select_query.

              {email:text,nospell                      {label "Email Address"}
                                                        {html {size 40}}}
              

          Define an element of type text with spell-checking disabled. In case spell-checking is enabled globally for the widget of this element ("text" in the example), the "nospell" flag will override that parameter and disable spell-checking on this particular element. Currently, spell-checking can be enabled for these widgets: text, textarea, and richtext.

          @see ad_form_new_p @see ad_set_element_value @see ad_set_form_values } { set level [template::adp_level] # Are we extending the form? if {[lindex $args 0] eq "-extend"} { set extend_p 1 set args [lrange $args 1 end] } else { set extend_p 0 } # Parse the rest of the arguments if { [llength $args] == 0 } { return -code error "No arguments to ad_form" } set valid_args { form method action mode html name select_query select_query_name new_data on_refresh edit_data validate on_submit after_submit confirm_template on_request new_request edit_request export cancel_url cancel_label has_submit has_edit actions edit_buttons display_buttons show_required_p on_validation_error fieldset }; ad_arg_parser $valid_args $args # Set the form name, defaulting to the name of the template that called us if { [info exists name] } { if { [string first "__" $name] >= 0 } { return -code error "Form name \"$name\" may not contain \"__\"" } set form_name $name } else { set form_name [file rootname [lindex [ad_conn urlv] end]] } if { [info exists af_parts(${form_name}__extend)] } { return -code error "Can't extend form \"$form_name\" - a parameter block requiring the full form has already been declared" } # Allow an empty form to work until we see an action block, useful for building up # forms piecemeal. global af_element_names if { !$extend_p } { set af_element_names($form_name) [list] } global af_parts foreach valid_arg $valid_args { if { [info exists $valid_arg] } { if { [info exists af_parts(${form_name}__$valid_arg)] && [lsearch { form name validate export } $valid_arg] == -1 } { return -code error "Form \"$form_name\" already has a \"$valid_arg\" section" } set af_parts(${form_name}__$valid_arg) "" # Force completion of the form if we have any action block. We only allow the form # and validation block to be extended, for now at least until I get more experience # with this ... if { [lsearch { name form method action html validate export mode cancel_url has_edit has_submit actions edit_buttons display_buttons fieldset on_validation_error} $valid_arg ] == -1 } { set af_parts(${form_name}__extend) "" } } } #################### # # Step 1: Parse the form specification # #################### # We need the full list of element names and their flags during submission, so track # them globally. (Future implementation note: the form builder tracks these already # and we should extend its data and use it directly, but there's not time to do this # right for Greenpeace so I'm hacking the hell out of it) global af_flag_list global af_to_sql global af_from_sql global af_to_html # Track element names and their parameters locally as we'll generate those in this form # or extend block on the fly set element_names [list] array set af_element_parameters [list] if { [info exists form] } { # Remove comment lines in form section (DanW) regsub -all -line -- {^\s*\#.*$} $form "" form foreach element $form { set element_name_part [lindex $element 0] # This can easily be generalized if we add more embeddable form commands ... if {$element_name_part eq "-section"} { lappend af_element_names($form_name) "[concat "-section" [uplevel [list subst [lrange $element 1 end]]]]" } else { set element_name_part [uplevel [list subst $element_name_part]] if { ![regexp {^([^ \t:]+)(?::([a-zA-Z0-9_,(|)]*))?$} $element_name_part match element_name flags] } { return -code error "Form element '$element_name_part' doesn't have the right format. It must be var\[:flag\[,flag ...\]\]" } lappend af_element_names($form_name) $element_name set af_extra_args($element_name) [lrange $element 1 end] set pre_flag_list [split [string tolower $flags] ,] set af_flag_list(${form_name}__$element_name) [list] # find parameterized flags. We only allow one parameter. foreach flag $pre_flag_list { set af_element_parameters($element_name:$flag) [list] set left_paren [string first "(" $flag] if { $left_paren != -1 } { if { [string index $flag end] ne ")" } { return -code error "Missing or misplaced end parenthesis for flag '$flag' on argument '$element_name'" } set flag_stem [string range $flag 0 [expr {$left_paren - 1}]] lappend af_element_parameters($element_name:$flag_stem) [string range $flag [expr {$left_paren + 1}] [expr {[string length $flag]-2}]] lappend af_flag_list(${form_name}__$element_name) $flag_stem } else { lappend af_flag_list(${form_name}__$element_name) $flag } } } lappend element_names [lindex $af_element_names($form_name) end] } } # Check the validation block for boneheaded errors if it exists. We explicitly allow a form element # to appear twice in the validation block so the caller can pair different error messages to different # checks. We implement this by building a global list of validation elements global af_validate_elements if { !$extend_p } { set af_validate_elements($form_name) [list] } if { [info exists validate] } { # Remove comment lines in validate section (DanW) regsub -all -line -- {^\s*\#.*$} $validate "" validate foreach validate_element $validate { if { [llength $validate_element] != 3 } { return -code error "Validate block must have three arguments: element name, expression, error message" } if {[lsearch $af_element_names($form_name) [lindex $validate_element 0]] == -1 && ![template::element::exists $form_name [lindex $validate_element 0]]} { return -code error "Element \"[lindex $validate_element 0]\" is not a form element" } lappend af_validate_elements($form_name) $validate_element } } if { !$extend_p } { set create_command [list template::form create $form_name] if { [info exists action] } { lappend create_command "-action" $action } if { [info exists method] } { lappend create_command "-method" $method } if { [info exists mode] } { lappend create_command "-mode" $mode } if { [info exists cancel_url] } { lappend create_command "-cancel_url" $cancel_url } if { [info exists cancel_label] } { lappend create_command "-cancel_label" $cancel_label } if { [info exists html] } { lappend create_command "-html" $html } if { [info exists has_edit] } { lappend create_command "-has_edit" $has_edit } if { [info exists has_submit] } { lappend create_command "-has_submit" $has_submit } if { [info exists actions] } { lappend create_command "-actions" $actions } if { [info exists edit_buttons] } { lappend create_command "-edit_buttons" $edit_buttons } if { [info exists display_buttons] } { lappend create_command "-display_buttons" $display_buttons } if { [info exists fieldset] } { lappend create_command "-fieldset" $fieldset } if { [info exists show_required_p] } { lappend create_command "-show_required_p" $show_required_p } # Create the form eval $create_command # Now make it impossible to add params specific to form creation to an extend # block # if a confirm template has been specified, it will be returned unless __confirmed_p is set # true. This is most easily done by including resources/forms/confirm-button in the confirm # template. template::element create $form_name __confirmed_p -datatype integer -widget hidden -value 0 # javascript widgets can change a form value and submit the result in order to allow the # generating script to fill in a value such as an image. The widget must set __refreshing_p # true. template::element create $form_name __refreshing_p -datatype integer -widget hidden -value 0 # add the hidden button element template::element create $form_name "__submit_button_name" -datatype text -widget hidden -value "" template::element create $form_name "__submit_button_value" -datatype text -widget hidden -value "" } if { [info exists export] } { foreach value $export { set name [lindex $value 0] if { [llength $value] == 1 } { if { [uplevel [list info exists $name]] } { template::element create $form_name $name -datatype text -widget hidden -value [uplevel [list set $name]] } } else { template::element create $form_name $name -datatype text -widget hidden -value [uplevel [list subst [lindex $value 1]]] } } } # We need to track these for submission time and for error checking global af_type global af_key_name global af_sequence_name foreach element_name $element_names { if { [lindex $element_name 0] eq "-section" } { set command [list template::form section] foreach {option} [lrange $element_name 2 end] { set switch [lindex $option 0] set args [lindex $option 1] switch $switch { fieldset - legendtext - legend { lappend command -$switch lappend command $args } default {return -code error "\"$switch\" is not a legal -section option"} } } lappend command $form_name lappend command [lindex $element_name 1] eval $command } else { set form_command [list template::element create $form_name $element_name] foreach flag $af_flag_list(${form_name}__$element_name) { switch $flag { key { if { [info exists af_key_name($form_name)] } { return -code error "element $element_name: a form can only declare one key" } set af_key_name($form_name) $element_name set af_type(${form_name}__$element_name) integer if { $af_element_parameters($element_name:key) ne "" } { if { [info exists af_sequence_name($form_name)] } { return -code error "element $element_name: duplicate sequence" } set af_sequence_name($form_name) $af_element_parameters($element_name:key) } lappend form_command "-datatype" "integer" "-widget" "hidden" template::element create $form_name __key_signature -datatype text -widget hidden -value "" template::element create $form_name __key -datatype text -widget hidden -value $element_name template::element create $form_name __new_p -datatype integer -widget hidden -value 0 } multiple { if { $af_element_parameters($element_name:$flag) ne "" } { return -code error "element $element_name: $flag attribute can not have a parameter" } } nospell - optional { if { $af_element_parameters($element_name:$flag) ne "" } { return -code error "element $element_name: $flag attribute can not have a parameter" } lappend form_command "-$flag" } from_sql - to_sql - to_html { if { $af_element_parameters($element_name:$flag) eq "" } { return -code error "element $element_name: \"$flag\" attribute must have a parameter" } set name af_$flag global af_$flag append name "(${form_name}__$element_name)" if { [info exists $name] } { return -code error "element $element_name: \"$flag\" appears twice" } set $name $af_element_parameters($element_name:$flag) } default { if { [empty_string_p [info commands "::template::data::validate::$flag"]] } { return -code error "element $element_name: data type \"$flag\" is not valid" } lappend form_command "-datatype" lappend form_command $flag set af_type(${form_name}__$element_name) $flag if { $af_element_parameters($element_name:$flag) eq "" } { if { ![empty_string_p [info command "::template::widget::$flag"]] } { lappend form_command "-widget" $flag } } else { if { [empty_string_p [info commands "::template::widget::$af_element_parameters($element_name:$flag)"]] } { return -code error "element $element_name: widget \"$af_element_parameters($element_name:$flag)\" does not exist" } lappend form_command "-widget" $af_element_parameters($element_name:$flag) } } } } foreach extra_arg $af_extra_args($element_name) { lappend form_command "-[lindex $extra_arg 0]" lappend form_command [uplevel [list subst [lindex $extra_arg 1]]] } eval $form_command } } # Check that any acquire and get_property attributes are supported by their element's datatype # These are needed at submission and fill-the-form-with-db-values time foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [info exists af_from_sql(${form_name}__$element_name)] } { if { [info commands "::template::util::$af_type(${form_name}__$element_name)::acquire"] eq "" } { return -code error "\"from_sql\" not valid for type \"$af_type(${form_name}__$element_name)\"" } } if { [info exists af_to_sql(${form_name}__$element_name)] } { if { [info commands ::template::util::$af_type(${form_name}__$element_name)::get_property] eq "" } { return -code error "\"to_sql\" not valid for type \"$af_type(${form_name}__$element_name)\"" } } if { [info exists af_to_html(${form_name}__$element_name)] } { if { [empty_string_p [info commands ::template::util::$af_type(${form_name}__$element_name)::get_property]] } { return -code error "\"to_html\" not valid for type \"$af_type(${form_name}__$element_name)\"" } } } } # Check for consistency if database operations are to be triggered by this form if { [info exists af_sequence_name($form_name)] && ![info exists af_key_name($form_name)] } { return -code error "You've supplied a sequence name no \"key_name\" parameter" } # Handle a request form that triggers database operations upvar #$level $form_name:properties properties # If we haven't seen an "action block" that requires the entire form, return. If the calling # script never finishes its form, tough. It won't work. if { ![info exists af_parts(${form_name}__extend)] } { return } if { ![info exists af_parts(${form_name}__form)] } { return -code error "No \"form\" block has been specified for form \"$form_name\"" } if { [template::form is_request $form_name] } { upvar #$level __ad_form_values__ values if { [template::form is_request $form_name] && [info exists on_request] } { ad_page_contract_eval uplevel #$level $on_request foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [uplevel \#$level [list info exists $element_name]] } { set values($element_name) [uplevel \#$level [list set $element_name]] if { [info exists af_from_sql(${form_name}__$element_name)] } { set values($element_name) [template::util::$af_type(${form_name}__$element_name)::acquire \ $af_from_sql(${form_name}__$element_name) $values($element_name)] } } } } } if { [info exists af_key_name($form_name)] } { set key_name $af_key_name($form_name) upvar #$level $key_name $key_name # Check to see if we're editing an existing database value if { [info exists $key_name] } { if { [info exists edit_request] } { if { [info exists select_query] || [info exists select_query_name] } { return -code error "Edit request block conflicts with select query" } ad_page_contract_eval uplevel #$level $edit_request foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [uplevel \#$level [list info exists $element_name]] } { set values($element_name) [uplevel \#$level [list set $element_name]] } } } } else { # The key exists, grab the existing values if we have an select_query clause if { ![info exists select_query] && ![info exists select_query_name] } { return -code error "Key \"$key_name\" has the value \"[set $key_name]\" but no select_query, select_query_name, or edit_request clause exists. (This can be caused by having ad_form request blocks in the wrong order.)" } if { [info exists select_query_name] } { set select_query "" } else { set select_query_name "" } if { ![uplevel #$level [list db_0or1row $select_query_name [join $select_query " "] -column_array __ad_form_values__]] } { return -code error "Error when selecting values: No rows returned." } foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [info exists af_from_sql(${form_name}__$element_name)] } { set values($element_name) [template::util::$af_type(${form_name}__$element_name)::acquire \ $af_from_sql(${form_name}__$element_name) $values($element_name)] } elseif { [info commands ::template::data::from_sql::$af_type(${form_name}__$element_name)] ne "" } { set values($element_name) [template::data::from_sql::$af_type(${form_name}__$element_name) $values($element_name)] } } } } set values($key_name) [set $key_name] set values(__new_p) 0 } else { # Make life easy for the OACS 4.5 hacker by automagically generating a value for # our new database row. Set a local so the query can use bindvar notation (the driver # doesn't support array bind vars) if { [info exists af_sequence_name($form_name)] } { set sequence_name $af_sequence_name($form_name) } else { set sequence_name "acs_object_id_seq" } if { [catch {set values($key_name) [db_nextval $sequence_name]} errmsg]} { return -code error "Couldn't get the next value from sequence: $errmsg\"" } set values(__new_p) 1 if { [info exists new_request] } { ad_page_contract_eval uplevel #$level $new_request # LARS: Set form values based on local vars in the new_request block foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [uplevel \#$level [list info exists $element_name]] } { set values($element_name) [uplevel \#$level [list set $element_name]] } } } } } set values(__key_signature) [ad_sign -- "$values($key_name):$form_name"] } foreach element_name $properties(element_names) { if { [info exists values($element_name)] } { if { [info exists af_flag_list(${form_name}__$element_name)] && \ [lsearch $af_flag_list(${form_name}__$element_name) multiple] >= 0 } { template::element set_values $form_name $element_name $values($element_name) } else { template::element set_value $form_name $element_name $values($element_name) } } } } elseif { [template::form is_submission $form_name] } { # Handle form submission. We create the form values in the caller's context and execute validation # expressions if they exist # Get all the form elements. We can't call form get_values because it doesn't handle multiples # in a reasonable way. foreach element_name $properties(element_names) { if { [info exists af_flag_list(${form_name}__$element_name)] && \ [lsearch $af_flag_list(${form_name}__$element_name) multiple] >= 0 } { set values [uplevel #$level [list template::element get_values $form_name $element_name]] uplevel #$level [list set $element_name $values] } else { set value [uplevel #$level [list template::element get_value $form_name $element_name]] uplevel #$level [list set $element_name $value] } } # Update the clicked button if it does not already exist uplevel #$level { if {![exists_and_not_null ${__submit_button_name}]} { set ${__submit_button_name} ${__submit_button_value} } } if { [info exists key_name] } { upvar #$level $key_name __key upvar #$level __key_signature __key_signature if { [info exists __key] && ![ad_verify_signature "$__key:$form_name" $__key_signature] } { ad_return_error "Bad key signature" "Verification of the database key value failed" } } # Execute validation expressions. We've already done some sanity checks so know the basic structure # is OK foreach validate_element $af_validate_elements($form_name) { foreach {element_name validate_expr error_message} $validate_element { if { ![template::element error_p $form_name $element_name] && \ ![uplevel #$level [list expr $validate_expr]] } { template::element set_error $form_name $element_name [uplevel [list subst $error_message]] } } } } if { [template::form is_submission $form_name] } { if { [uplevel #$level {set __refreshing_p}] } { uplevel array unset ${form_name}:error if { [info exists on_refresh] } { ad_page_contract_eval uplevel #$level $on_refresh } } else { # Not __refreshing_p if { [template::form is_valid $form_name] } { # Run confirm and preview templates before we do final processing of the form if { [info exists confirm_template] && ![uplevel #$level {set __confirmed_p}] } { # Pass the form variables to the confirm template, applying the to_html filter if present set args [list] foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [info exists af_to_html(${form_name}__$element_name)] } { uplevel #$level [list set $element_name \ [uplevel #$level [list template::util::$af_type(${form_name}__$element_name)::get_property \ $af_to_html(${form_name}__$element_name) \ [uplevel #$level [list set $element_name]]]]] } lappend args [list $element_name [uplevel #$level [list set $element_name]]] } } # This is serious abuse of ad_return_exception_template, but hell, I wrote it so I'm entitled ... ad_return_exception_template -status 200 -params $args $confirm_template } # We have three possible ways to handle the form # 1. an on_submit block (useful for forms that don't touch the database or can share smart Tcl API # for both add and edit forms) # 2. an new_data block (when __new_p is true) # 3. an edit_data block (when __new_p is false) # 4. an after_submit block (for ad_returnredirect and the like that is the same for new and edit) # We don't need to interrogate the af_parts structure because we know we're in the last call to # to ad_form at this point and that this call contained the "action blocks". # Execute our to_sql filters, if any, before passing control to the caller's # on_submit, new_data, edit_data or after_submit blocks foreach element_name $af_element_names($form_name) { if { [llength $element_name] == 1 } { if { [info exists af_to_sql(${form_name}__$element_name)] } { uplevel #$level [list set $element_name \ [uplevel #$level [list template::util::$af_type(${form_name}__$element_name)::get_property \ $af_to_sql(${form_name}__$element_name) \ [uplevel #$level [list set $element_name]]]]] } } } # Lars: We're wrapping this in a catch to allow people to throw a "break" inside # the code block, causing submission to be canceled # In order to make this work, I had to eliminate the ad_page_contract_eval's below # and replace them with simple uplevel's. Otherwise, we'd get an error saying # 'break used outside of a loop'. set errno [catch { if { [info exists on_submit] } { uplevel #$level $on_submit } upvar #$level __new_p __new_p if { [info exists new_data] && $__new_p } { uplevel #$level $new_data template::element::set_value $form_name __new_p 0 } elseif { [info exists edit_data] && !$__new_p } { uplevel #$level $edit_data } if { [info exists after_submit] } { uplevel #$level $after_submit } } error] # Handle or propagate the error. Can't use the usual # "return -code $errno..." trick due to the db_with_handle # wrapped around this loop, so propagate it explicitly. switch $errno { 0 { # TCL_OK } 1 { # TCL_ERROR global errorInfo errorCode error $error $errorInfo $errorCode } 2 { # TCL_RETURN error "Cannot return from inside an ad_form block" } 3 { # TCL_BREAK # nothing -- this is what we want to support } 4 { # TCL_CONTINUE continue } default { error "Unknown return code: $errno" } } } elseif { [info exists on_validation_error] } { uplevel #$level $on_validation_error } } } template::element::set_value $form_name __refreshing_p 0 template::element::set_value $form_name __confirmed_p 0 } ad_proc -public ad_set_element_value { -element:required value } { Set the value of a particular element in the current form being built by ad_form. @param element The name of the element @param value The value to set } { upvar #[template::adp_level] __ad_form_values__ values set values($element) $value } ad_proc -public ad_set_form_values { args } { Set multiple values in the current form. @param args A list of values to set. Each two-element value in the list is evaluated as a name, value pair. Each single-element value is assumed to have its value set in a variable of the same name local to our caller. Example: set_element_values language_id { some_var some_value } { another_var another_value } } { foreach arg $args { if { [llength $arg] == 1 } { upvar $arg value ad_set_element_value -element $arg -- $value } else { set value [uplevel subst \{[lindex $arg 1]\}] ad_set_element_value -element [lindex $arg 0] -- $value } } } ad_proc -public ad_form_new_p { -key:required } { This is for pages built with ad_form that handle edit and add requests in one file. It returns 1 if the current form being built for the entry of new data, 0 if for the editing of existing data.

          It does not make sense to use this in pages that don't use ad_form.

          @param key The database key for the form, which must be declared to be of type "key"

          Example usage:

              if { [ad_form_new_p -key item_id] } {
                  ad_require_permission $package_id create
                  set page_title "New Item"
              } else {
                  ad_require_permission $item_id write
                  set page_title "Edit Item"
              }
          
              
          @param key the name of the key element. In the above example: ad_form_new_p -key item_id } { set form [ns_getform] return [expr {$form eq "" || [ns_set find $form $key] == -1 || [ns_set get $form __new_p] == 1 }] } openacs-5.7.0/packages/acs-tcl/tcl/security-procs-oracle.xql0000644000175000017500000000471607723347127023671 0ustar frankiefrankie oracle8.1.6 update users set second_to_last_visit = last_visit, last_visit = sysdate, n_sessions = n_sessions + 1 where user_id = :user_id select test_sql('select 1 from dual where 1=[DoubleApos $value]') from dual select test_sql('select 1 from dual where 1=[DoubleApos "'$value'"]') from dual insert /*+ APPEND */ into secret_tokens(token_id, token, token_timestamp) values(sec_security_token_id_seq.nextval, :random_token, sysdate) select * from ( select token_id, token from secret_tokens sample(15) ) where rownum < :num_tokens update sec_session_properties set property_value = null, property_clob = empty_clob(), secure_p = :secure, last_hit = :last_hit where session_id = :session_id and module = :module and property_name = :name returning property_clob into :1 update sec_session_properties set property_value = :value, property_clob = null, secure_p = :secure, last_hit = :last_hit where session_id = :session_id and module = :module and property_name = :name update users set password = :new_password, salt = :salt, password_changed_date = sysdate where user_id = :user_id openacs-5.7.0/packages/acs-tcl/tcl/acs-kernel-procs.tcl0000644000175000017500000000313410024403027022526 0ustar frankiefrankiead_library { @author rhs@mit.edu @creation-date 2000-09-09 @cvs-id $Id: acs-kernel-procs.tcl,v 1.9 2004/03/12 18:48:55 jeffd Exp $ } ad_proc -public ad_acs_administrator_exists_p {} { @return 1 if a user with admin privileges exists, 0 otherwise. } { return [db_string admin_exists_p {} -default 0] } ad_proc -public ad_acs_admin_node {} { @return The node id of the ACS administration service if it is mounted, 0 otherwise. } { # Obtain the id of the ACS Administration node. # DRB: this used to say "and rownum = 1" but I've changed it to an SQL92 form # that's ummm...portable! return [db_string acs_admin_node_p { select case when count(object_id) = 0 then 0 else 1 end from site_nodes where object_id = (select package_id from apm_packages where package_key = 'acs-admin') } -default 0] } ad_proc -public ad_verify_install {} { Returns 1 if the acs is properly installed, 0 otherwise. } { # define util_memoize with proc here to avoid error messages about multiple # defines. if { ![db_table_exists apm_packages] || ![db_table_exists site_nodes] } { proc util_memoize {script {max_age ""}} {eval $script} return 0 } set kernel_install_p [apm_package_installed_p acs-kernel] set admin_exists_p [ad_acs_administrator_exists_p] ns_log Debug "Verifying Installation: Kernel Installed? $kernel_install_p \ An Administrator? $admin_exists_p" if { $kernel_install_p && $admin_exists_p} { return 1 } else { proc util_memoize {script {max_age ""}} {eval $script} return 0 } } openacs-5.7.0/packages/acs-tcl/tcl/acs-kernel-procs.xql0000644000175000017500000000165307661404442022573 0ustar frankiefrankie select 1 as admin_exists_p from dual where exists (select 1 from all_object_party_privilege_map m, users u, acs_magic_objects amo where m.object_id = amo.object_id and amo.name = 'security_context_root' and m.party_id = u.user_id and m.privilege = 'admin') select case when count(object_id) = 0 then 0 else 1 end from site_nodes where object_id = (select package_id from apm_packages where package_key = 'acs-admin') openacs-5.7.0/packages/acs-tcl/tcl/site-node-object-map-procs-oracle.xql0000644000175000017500000000116307504712423025711 0ustar frankiefrankie oracle8.1.6 declare begin site_node_object_map.new(object_id => :object_id, node_id => :node_id); end; declare begin site_node_object_map.del(object_id => :object_id); end; openacs-5.7.0/packages/acs-tcl/tcl/admin-init-postgresql.xql0000644000175000017500000000051307271213362023643 0ustar frankiefrankie postgresql7.1 select package_id, site_node__url(node_id) as url from apm_packages p, site_nodes n where p.package_id = n.object_id openacs-5.7.0/packages/acs-tcl/tcl/object-type-procs-postgresql.xql0000644000175000017500000000303410226573710025164 0ustar frankiefrankie postgresql7.1 select o2.object_type, o2.pretty_name, '' as indent, tree_level(o2.tree_sortkey) as level from (select * from acs_object_types where object_type = :object_type) o1, acs_object_types o2 where o2.tree_sortkey <= o1.tree_sortkey and o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey) order by level desc select object_type, pretty_name, repeat('$indent_string',(tree_level(tree_sortkey) - 1) * $indent_width) as indent from acs_object_types order by tree_sortkey select o2.object_type from acs_object_types o1, acs_object_types o2 where o1.object_type = :subtype and o2.tree_sortkey < o1.tree_sortkey and o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey) order by tree_level(o2.tree_sortkey) desc openacs-5.7.0/packages/acs-tcl/tcl/site-nodes-procs-oracle.xql0000644000175000017500000000333210777764030024064 0ustar frankiefrankie oracle8.1.6 begin site_node.del(:node_id); end; select n.node_id, n.parent_id, n.name, n.directory_p, n.pattern_p, n.object_id, p.package_key, p.package_id, p.instance_name, t.package_type from apm_packages p, apm_package_types t, (select node_id, parent_id, name, directory_p, pattern_p, object_id, rownum as nodes_rownum from site_nodes connect by parent_id = prior node_id start with node_id = :node_id) n where n.object_id = p.package_id(+) and t.package_key (+) = p.package_key order by n.nodes_rownum select n.node_id, n.parent_id, n.name, n.directory_p, n.pattern_p, n.object_id, p.package_key, p.package_id, p.instance_name, t.package_type from apm_packages p, apm_package_types t, site_nodes n where n.node_id = :node_id and n.object_id = p.package_id(+) and t.package_key (+) = p.package_key select site_node.url(node_id) from site_nodes where object_id = :object_id order by site_node.url(node_id) desc openacs-5.7.0/packages/acs-tcl/tcl/site-nodes-procs.tcl0000644000175000017500000011502011350247053022562 0ustar frankiefrankiead_library { site node api @author rhs@mit.edu @author yon (yon@openforce.net) @creation-date 2000-09-06 @cvs-id $Id: site-nodes-procs.tcl,v 1.89 2010/03/17 21:48:27 victorg Exp $ } #---------------------------------------------------------------------- # site_nodes data structure #---------------------------------------------------------------------- # # nsv site_nodes($url) = array-list with all info about a node # nsv site_node_url_by_node_id($node_id) = url for that node_id # nsv site_node_url_by_object_id($object_id) = list of URLs where that object_id is mounted, # ordered longest path first # nsv site_node_url_by_package_key($package_key) = list of URLs where that package_key is mounted, # no ordering # nsv site_nodes_mutex = mutex object used to control concurrency namespace eval site_node {} ad_proc -public site_node::new { {-name:required} {-parent_id:required} {-directory_p t} {-pattern_p t} } { create a new site node } { set var_list [list \ [list name $name] \ [list parent_id $parent_id] \ [list directory_p $directory_p] \ [list pattern_p $pattern_p]] set node_id [package_instantiate_object -var_list $var_list site_node] #Now update the nsv caches. We don't need to update the object_id and package_key caches #because nothing is mounted here yet. # Grab the lock so our URL key doesn't change on us midstream ns_mutex lock [nsv_get site_nodes_mutex mutex] with_finally -code { set url [site_node::get_url -node_id $parent_id] append url $name if { $directory_p == "t" } { append url "/" } nsv_set site_node_url_by_node_id $node_id $url nsv_set site_nodes $url \ [list url $url node_id $node_id parent_id $parent_id name $name \ directory_p $directory_p pattern_p $pattern_p \ object_id "" object_type "" \ package_key "" package_id "" \ instance_name "" package_type ""] } -finally { ns_mutex unlock [nsv_get site_nodes_mutex mutex] } return $node_id } ad_proc -public site_node::delete { {-node_id:required} } { delete the site node } { db_exec_plsql delete_site_node {} update_cache -node_id $node_id } ad_proc -public site_node::mount { {-node_id:required} {-object_id:required} {-context_id} } { mount object at site node } { db_dml mount_object {} db_dml update_object_package_id {} ns_mutex lock [nsv_get site_nodes_mutex mutex] with_finally -code { #Now update the nsv caches. array set node [site_node::get_from_node_id -node_id $node_id] foreach var [list object_type package_key package_id instance_name package_type] { set $var "" } db_0or1row get_package_info { select 'apm_package' as object_type, p.package_key, p.package_id, p.instance_name, t.package_type from apm_packages p, apm_package_types t where p.package_id = :object_id and t.package_key = p.package_key } nsv_set site_nodes $node(url) \ [list url $node(url) node_id $node(node_id) parent_id $node(parent_id) name $node(name) \ directory_p $node(directory_p) pattern_p $node(pattern_p) \ object_id $object_id object_type $object_type \ package_key $package_key package_id $package_id \ instance_name $instance_name package_type $package_type] set url_by_object_id [list $node(url)] if { [nsv_exists site_node_url_by_object_id $object_id] } { set url_by_object_id [concat [nsv_get site_node_url_by_object_id $object_id] $url_by_object_id] set url_by_object_id [lsort \ -decreasing \ -command util::string_length_compare \ $url_by_object_id] } nsv_set site_node_url_by_object_id $object_id $url_by_object_id if { $package_key ne "" } { set url_by_package_key [list $node(url)] if { [nsv_exists site_node_url_by_package_key $package_key] } { set url_by_package_key [concat [nsv_get site_node_url_by_package_key $package_key] $url_by_package_key] } nsv_set site_node_url_by_package_key $package_key $url_by_package_key } } -finally { ns_mutex unlock [nsv_get site_nodes_mutex mutex] } # DAVEB update context_id if it is passed in # some code relies on context_id to be set by # instantiate_and_mount so we can't assume # anything at this point. Callers that need to set context_id # for example, when an unmounted package is mounted, # should pass in the correct context_id if {[info exists context_id]} { db_dml update_package_context_id "" } set package_key [apm_package_key_from_id $object_id] foreach inherited_package_key [nsv_get apm_package_inherit_order $package_key] { apm_invoke_callback_proc \ -package_key $inherited_package_key \ -type after-mount \ -arg_list [list package_id $package_id node_id $node_id] } } ad_proc -public site_node::rename { {-node_id:required} {-name:required} } { Rename the site node. } { # We need to update the cache for all the child nodes as well set node_url [get_url -node_id $node_id] set child_node_ids [get_children -all -node_id $node_id -element node_id] db_dml rename_node {} db_dml update_object_title {} update_cache -sync_children -node_id $node_id } ad_proc -public site_node::instantiate_and_mount { {-node_id ""} {-parent_node_id ""} {-node_name ""} {-package_name ""} {-context_id ""} {-package_key:required} {-package_id ""} } { Instantiate and mount a package of given type. Will use an existing site node if possible. @param node_id The id of the node in the site map where the package should be mounted. @param parent_node_id If no node_id is specified this will be the parent node under which the new node is created. Defaults to the main site node id. @param node_name If node_id is not specified then this will be the name of the new site node that is created. Defaults to package_key. @param package_name The name of the new package instance. Defaults to pretty name of package type. @param context_id The context_id of the package. Defaults to the closest ancestor package in the site map. @param package_key The key of the package type to instantiate. @param package_id The id of the new package. Optional. @return The id of the instantiated package @author Peter Marklund } { # Create a new node if none was provided and none exists if { $node_id eq "" } { # Default parent node to the main site if { $parent_node_id eq "" } { set parent_node_id [site_node::get_node_id -url "/"] } # Default node_name to package_key if { $node_name eq "" } { set node_name $package_key } # Create the node if it doesn't exists set parent_url [get_url -notrailing -node_id $parent_node_id] set url "${parent_url}/${node_name}" if { ![exists_p -url $url] } { set node_id [site_node::new -name $node_name -parent_id $parent_node_id] } else { # Check that there isn't already a package mounted at the node array set node [get -url $url] if { [exists_and_not_null node(object_id)] } { error "Cannot mount package at url $url as package $node(object_id) is already mounted there" } set node_id $node(node_id) } } # Default context id to the closest ancestor package_id if { $context_id eq "" } { set context_id [site_node::closest_ancestor_package -node_id $node_id] } # Instantiate the package set package_id [apm_package_instance_new \ -package_id $package_id \ -package_key $package_key \ -instance_name $package_name \ -context_id $context_id] # Mount the package site_node::mount -node_id $node_id -object_id $package_id return $package_id } ad_proc -public site_node::unmount { {-node_id:required} } { unmount an object from the site node } { set package_id [get_object_id -node_id $node_id] set package_key [apm_package_key_from_id $package_id] foreach inherited_package_key [nsv_get apm_package_inherit_order $package_key] { apm_invoke_callback_proc \ -package_key $inherited_package_key \ -type before-unmount \ -arg_list [list package_id $package_id node_id $node_id] } db_dml unmount_object {} db_dml update_object_package_id {} update_cache -node_id $node_id } ad_proc -private site_node::init_cache {} { initialize the site node cache } { nsv_array reset site_nodes [list] nsv_array reset site_node_url_by_node_id [list] nsv_array reset site_node_url_by_object_id [list] nsv_array reset site_node_url_by_package_key [list] set root_node_id [db_string get_root_node_id {} -default {}] if { $root_node_id ne "" } { site_node::update_cache -sync_children -node_id $root_node_id } } ad_proc -private site_node::update_cache { {-sync_children:boolean} {-node_id:required} } { Brings the in memory copy of the site nodes hierarchy in sync with the database version. Only updates the given node and its children. } { # don't let any other thread try to do a concurrent update # until cache is fully updated ns_mutex lock [nsv_get site_nodes_mutex mutex] with_finally -code { # Lars: We need to record the object_id's touched, so we can sort the # object_id->url mappings again. We store them sorted by length of the URL if { [nsv_exists site_node_url_by_node_id $node_id] } { set old_url [nsv_get site_node_url_by_node_id $node_id] if { $sync_children_p } { append old_url * } # This is a little cumbersome, but we have to remove the entry for # the object_id->url mapping, for each object_id that used to be # mounted here # Loop over all the URLs under the node we're updating set cur_nodes [nsv_array get site_nodes $old_url] foreach {cur_node_url curr_node_values} $cur_nodes { array set cur_node $curr_node_values # Find the object_id previously mounted there set cur_object_id $cur_node(object_id) if { $cur_object_id ne "" } { # Remove the URL from the url_by_object_id entry for that object_id set cur_url_by_object_id [nsv_get site_node_url_by_object_id $cur_object_id] set cur_idx [lsearch -exact $cur_url_by_object_id $cur_node_url] if { $cur_idx != -1 } { set cur_url_by_object_id \ [lreplace $cur_url_by_object_id $cur_idx $cur_idx] nsv_set site_node_url_by_object_id $cur_object_id $cur_url_by_object_id } } # Find the package_key previously mounted there set cur_package_key $cur_node(package_key) if { $cur_package_key ne "" } { # Remove the URL from the url_by_package_key entry for that package_key set cur_url_by_package_key [nsv_get site_node_url_by_package_key $cur_package_key] set cur_idx [lsearch -exact $cur_url_by_package_key $cur_node_url] if { $cur_idx != -1 } { set cur_url_by_package_key \ [lreplace $cur_url_by_package_key $cur_idx $cur_idx] nsv_set site_node_url_by_package_key $cur_package_key $cur_url_by_package_key } } nsv_unset site_nodes $cur_node_url nsv_unset site_node_url_by_node_id $cur_node(node_id) } } # Note that in the queries below, we use connect by instead of site_node.url # to get the URLs. This is less expensive. if { $sync_children_p } { set query_name select_child_site_nodes } else { set query_name select_site_node } set cur_obj_ids [list] db_foreach $query_name {} { if {$parent_id eq ""} { # url of root node set url "/" } else { # append directory to url of parent node set url [nsv_get site_node_url_by_node_id $parent_id] append url $name if { $directory_p == "t" } { append url "/" } } # save new url nsv_set site_node_url_by_node_id $node_id $url if { $object_id ne "" } { nsv_lappend site_node_url_by_object_id $object_id $url lappend cur_obj_ids $object_id } if { $package_key ne "" } { nsv_lappend site_node_url_by_package_key $package_key $url } if { $package_id eq "" } { set object_type "" } else { set object_type "apm_package" } # save new node nsv_set site_nodes $url \ [list url $url node_id $node_id parent_id $parent_id name $name \ directory_p $directory_p pattern_p $pattern_p \ object_id $object_id object_type $object_type \ package_key $package_key package_id $package_id \ instance_name $instance_name package_type $package_type] } # AG: This lsort used to live in the db_foreach loop above. I moved it here # to avoid redundant re-sorting on systems where multiple URLs are mapped to # the same object_id. This was causing a 40 minute startup delay on a .LRN site # with 4000+ URLs mapped to one instance of the attachments package. # The sort facilitates deleting child nodes before parent nodes. foreach object_id [lsort -unique $cur_obj_ids] { nsv_set site_node_url_by_object_id $object_id [lsort \ -decreasing \ -command util::string_length_compare \ [nsv_get site_node_url_by_object_id $object_id] ] } } -finally { ns_mutex unlock [nsv_get site_nodes_mutex mutex] } } ad_proc -public site_node::get { {-url ""} {-node_id ""} } { returns an array representing the site node that matches the given url either url or node_id is required, if both are passed url is ignored The array elements are: package_id, package_key, object_type, directory_p, instance_name, pattern_p, parent_id, node_id, object_id, url. } { if {$url eq "" && $node_id eq ""} { error "site_node::get \"must pass in either url or node_id\"" } if {$node_id ne ""} { return [get_from_node_id -node_id $node_id] } if {$url ne ""} { return [get_from_url -url $url] } } ad_proc -public site_node::get_element { {-node_id ""} {-url ""} {-element:required} } { returns an element from the array representing the site node that matches the given url either url or node_id is required, if both are passed url is ignored The array elements are: package_id, package_key, object_type, directory_p, instance_name, pattern_p, parent_id, node_id, object_id, url. @see site_node::get } { array set node [site_node::get -node_id $node_id -url $url] return $node($element) } ad_proc -public site_node::get_from_node_id { {-node_id:required} } { returns an array representing the site node for the given node_id @see site_node::get } { return [get_from_url -url [get_url -node_id $node_id]] } ad_proc -public site_node::get_from_url { {-url:required} {-exact:boolean} } { Returns an array representing the site node that matches the given url.

          A trailing '/' will be appended to $url if required and not present.

          If the '-exact' switch is not present and $url is not found, returns the first match found by successively removing the trailing $url path component.

          @see site_node::get } { # attempt an exact match if {[nsv_exists site_nodes $url]} { return [nsv_get site_nodes $url] } # attempt adding a / to the end of the url if it doesn't already have # one if {[string index $url end] ne "/" } { append url "/" if {[nsv_exists site_nodes $url]} { return [nsv_get site_nodes $url] } } # chomp off part of the url and re-attempt if {!$exact_p} { while {$url ne ""} { set url [string trimright $url /] set url [string range $url 0 [string last / $url]] if {[nsv_exists site_nodes $url]} { array set node [nsv_get site_nodes $url] if {$node(pattern_p) == "t" && $node(object_id) ne ""} { return [array get node] } } } } error "site node not found at url \"$url\"" } ad_proc -public site_node::exists_p { {-url:required} } { Returns 1 if a site node exists at the given url and 0 otherwise. @author Peter Marklund } { set url_no_trailing [string trimright $url "/"] return [nsv_exists site_nodes "$url_no_trailing/"] } ad_proc -public site_node::get_from_object_id { {-object_id:required} } { return the site node associated with the given object_id WARNING: Returns only the first site node associated with this object. } { return [get -url [lindex [get_url_from_object_id -object_id $object_id] 0]] } ad_proc -public site_node::get_all_from_object_id { {-object_id:required} } { Return a list of site node info associated with the given object_id. The nodes will be ordered descendingly by url (children before their parents). } { set node_id_list [list] set url_list [list] foreach url [get_url_from_object_id -object_id $object_id] { lappend node_id_list [get -url $url] } return $node_id_list } ad_proc -public site_node::get_url { {-node_id:required} {-notrailing:boolean} } { return the url of this node_id @notrailing If true then strip any trailing slash ('/'). This means the empty string is returned for the root. } { set url "" if {[nsv_exists site_node_url_by_node_id $node_id]} { set url [nsv_get site_node_url_by_node_id $node_id] } if { $notrailing_p } { set url [string trimright $url "/"] } return $url } ad_proc -public site_node::get_url_from_object_id { {-object_id:required} } { returns a list of urls for site_nodes that have the given object mounted or the empty list if there are none. The url:s will be returned in descending order meaning any children will come before their parents. This ordering is useful when deleting site nodes as we must delete child site nodes before their parents. } { if { [nsv_exists site_node_url_by_object_id $object_id] } { return [nsv_get site_node_url_by_object_id $object_id] } else { return [list] } } ad_proc -public site_node::get_node_id { {-url:required} } { return the node_id for this url } { array set node [get -url $url] return $node(node_id) } ad_proc -public site_node::get_node_id_from_object_id { {-object_id:required} } { return the site node id associated with the given object_id } { set url [lindex [get_url_from_object_id -object_id $object_id] 0] if { $url ne "" } { return [get_node_id -url $url] } else { return {} } } ad_proc -public site_node::get_parent_id { {-node_id:required} } { return the parent_id of this node } { array set node [get -node_id $node_id] return $node(parent_id) } ad_proc -public site_node::get_parent { {-node_id:required} } { return the parent node of this node } { array set node [get -node_id $node_id] return [get -node_id $node(parent_id)] } ad_proc -public site_node::get_ancestors { {-node_id:required} {-element ""} } { return the ancestors of this node } { set result [list] set array_result_p [string equal $element ""] while {$node_id ne "" } { array set node [get -node_id $node_id] if {$array_result_p} { lappend result [array get node] } else { lappend result $node($element) } set node_id $node(parent_id) } return $result } ad_proc -public site_node::get_object_id { {-node_id:required} } { return the object_id for this node } { array set node [get -node_id $node_id] return $node(object_id) } ad_proc -public site_node::get_children { {-all:boolean} {-package_type {}} {-package_key {}} {-filters {}} {-element {}} {-node_id:required} } { This proc gives answers to questions such as: What are all the package_id's (or any of the other available elements) for all the instances of package_key or package_type mounted under node_id xxx? @param node_id The node for which you want to find the children. @option all Set this if you want all children, not just direct children @option package_type If specified, this will limit the returned nodes to those with an package of the specified package type (normally apm_service or apm_application) mounted. Conflicts with the -package_key option. @param package_key If specified, this will limit the returned nodes to those with a package of the specified package key mounted. Conflicts with the -package_type option. Can take one or more packges keys as a Tcl list. @param filters Takes a list of { element value element value ... } for filtering the result list. Only nodes where element is value for each of the filters in the list will get included. For example: -filters { package_key "acs-subsite" }. @param element The element of the site node you wish returned. Defaults to url, but the following elements are available: object_type, url, object_id, instance_name, package_type, package_id, name, node_id, directory_p. @return A list of URLs of the site_nodes immediately under this site node, or all children, if the -all switch is specified. @author Lars Pind (lars@collaboraid.biz) } { if { $package_type ne "" && $package_key ne "" } { error "You may specify either package_type, package_key, or filter_element, but not more than one." } if { $package_type ne "" } { lappend filters package_type $package_type } elseif { $package_key ne "" } { lappend filters package_key $package_key } set node_url [site_node::get_url -node_id $node_id] if { !$all_p } { set child_urls [list] set s [string length "$node_url"] # find all child_urls who have only one path element below node_id # by clipping the node url and last character and seeing if there # is a / in the string. about 2x faster than the RE version. foreach child_url [nsv_array names site_nodes "${node_url}?*"] { if { [string first / [string range $child_url $s end-1]] < 0 } { lappend child_urls $child_url } } } else { set child_urls [nsv_array names site_nodes "${node_url}?*"] } if { [llength $filters] > 0 } { set return_val [list] foreach child_url $child_urls { array unset site_node if {![catch {array set site_node [nsv_get site_nodes $child_url]}]} { set passed_p 1 foreach { elm val } $filters { # package_key supports one or more package keys # since we can filter on the site node pretty name # we can't just treat all filter values as a list if {$elm eq "package_key" && [llength $val] > 1 && [lsearch $val $site_node($elm)] < 0} { set passed_p 0 break } elseif {($elm ne "package_key" || [llength $val] == 1) && $site_node($elm) ne $val } { set passed_p 0 break } } if { $passed_p } { if { $element ne "" } { lappend return_val $site_node($element) } else { lappend return_val $child_url } } } } } elseif { $element ne "" } { set return_val [list] foreach child_url $child_urls { array unset site_node if {![catch {array set site_node [nsv_get site_nodes $child_url]}]} { lappend return_val $site_node($element) } } } # if we had filters or were getting a particular element then we # have our results in return_val otherwise it's just urls if { $element ne "" || [llength $filters] > 0} { return $return_val } else { return $child_urls } } ad_proc -public site_node::closest_ancestor_package { {-url ""} {-node_id ""} {-package_key ""} {-include_self:boolean} {-element "object_id"} } { Starting with the node at with given id, or at given url, climb up the site map and return the id of the first not-null mounted object. If no ancestor object is found the empty string is returned. Will ignore itself and only return true ancestors unless include_self is set. @param url The url of the node to start from. You must provide either url or node_id. An empty url is taken to mean the main site. @param node_id The id of the node to start from. Takes precedence over any provided url. @param package_key Restrict search to objects of this package type. You may supply a list of package_keys. @param include_self Return the package_id at the passed-in node if it is of the desired package_key. Ignored if package_key is empty. @return The id of the first object found and an empty string if no object is found. Throws an error if no node with given url can be found. @author Peter Marklund } { # Make sure we have a url to work with if { $url eq "" } { if { $node_id eq "" } { set url "/" } else { set url [site_node::get_url -node_id $node_id] } } # should we return the package at the passed-in node/url? if { $include_self_p && $package_key ne ""} { array set node_array [site_node::get -url $url] if { [lsearch -exact $package_key $node_array(package_key)] != -1 } { return $node_array($element) } } set elm_value {} while { $elm_value eq "" && $url ne "/"} { # move up a level set url [string trimright $url /] set url [string range $url 0 [string last / $url]] array set node_array [site_node::get -url $url] # are we looking for a specific package_key? if { $package_key eq "" || \ [lsearch -exact $package_key $node_array(package_key)] != -1 } { set elm_value $node_array($element) } } return $elm_value } ad_proc -public site_node::get_package_url { {-package_key:required} } { Get the URL of any mounted instance of a package with the given package_key. If there is more than one mounted instance of a package, returns the first URL. To see all of the mounted URLs, use the site_node::get_children proc. @return a URL, or empty string if no instance of the package is mounted. @see site_node::get_children } { if { [nsv_exists site_node_url_by_package_key $package_key] } { return [lindex [nsv_get site_node_url_by_package_key $package_key] 0] } else { return {} } } ad_proc -public site_node::verify_folder_name { {-parent_node_id:required} {-current_node_id ""} {-instance_name ""} {-folder ""} } { Verifies that the given folder name is valid for a folder under the given parent_node_id. If current_node_id is supplied, it's assumed that we're renaming an existing node, not creating a new one. If folder name is not supplied, we'll generate one from the instance name, which must then be supplied. Returns folder name to use, or empty string if the supplied folder name wasn't acceptable. } { set existing_urls [site_node::get_children -node_id $parent_node_id -element name] array set parent_node [site_node::get -node_id $parent_node_id] if { $parent_node(package_key) ne "" } { # Find all the page or directory names under this package foreach path [glob -nocomplain -types d "[acs_package_root_dir $parent_node(package_key)]/www/*"] { lappend existing_urls [lindex [file split $path] end] } foreach path [glob -nocomplain -types f "[acs_package_root_dir $parent_node(package_key)]/www/*.adp"] { lappend existing_urls [file rootname [lindex [file split $path] end]] } foreach path [glob -nocomplain -types f "[acs_package_root_dir $parent_node(package_key)]/www/*.tcl"] { set name [file rootname [lindex [file split $path] end]] if { [lsearch $existing_urls $name] == -1 } { lappend existing_urls $name } } } if { $folder ne "" } { if { [lsearch $existing_urls $folder] != -1 } { # The folder is on the list if { $current_node_id eq "" } { # New node: Complain return {} } else { # Renaming an existing node: Check to see if the node is merely conflicting with itself set parent_url [site_node::get_url -node_id $parent_node_id] set new_node_url "$parent_url$folder" if { ![site_node::exists_p -url $new_node_url] || \ $current_node_id != [site_node::get_node_id -url $new_node_url] } { return {} } } } } else { # Autogenerate folder name if { $instance_name eq "" } { error "Instance name must be supplied when folder name is empty." } set folder [util_text_to_url \ -existing_urls $existing_urls \ -text $instance_name] } return $folder } ############## # # Deprecated Procedures # ############# ad_proc -public site_node_delete_package_instance { {-node_id:required} } { Wrapper for apm_package_instance_delete @author Arjun Sanyal (arjun@openforc.net) @creation-date 2002-05-02 } { db_transaction { set package_id [site_node::get_object_id -node_id $node_id] site_node::unmount -node_id $node_id apm_package_instance_delete $package_id } on_error { site_node::update_cache -node_id $node_id } } ad_proc -public site_map_unmount_application { { -sync_p "t" } { -delete_p "f" } node_id } { Unmounts the specified node. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2001-02-07 @param sync_p If "t", we flush the in-memory site map @param delete_p If "t", we attempt to delete the site node. This will fail if you have not cleaned up child nodes @param node_id The node_id to unmount } { db_transaction { site_node::unmount -node_id $node_id if {$delete_p == "t"} { site_node::delete -node_id $node_id } } } ad_proc -public site_node_id {url} { Returns the node_id of a site node. Throws an error if there is no matching node. } { return [site_node::get_node_id -url $url] } ad_proc -public site_nodes_sync {args} { Brings the in memory copy of the url hierarchy in sync with the database version. } { site_node::init_cache } ad_proc -deprecated -warn site_node_closest_ancestor_package { { -default "" } { -url "" } package_keys } {

          Use site_node::closest_ancestor_package. Note that site_node_closest_ancestor_package will include the passed-in node in the search, whereas the new proc doesn't by default. If you want to include the passed-in node, call site_node::closest_ancestor_package with the -include_self flag

          Finds the package id of a package of specified type that is closest to the node id represented by url (or by ad_conn url).Note that closest means the nearest ancestor node of the specified type, or the current node if it is of the correct type.

          Usage:

              # Pull out the package_id of the subsite closest to our current node
              set pkg_id [site_node_closest_ancestor_package "acs-subsite"]
              
          @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 1/17/2001 @param default The value to return if no package can be found @param current_node_id The node from which to start the search @param package_keys The type(s) of the package(s) for which we are looking @return package_id of the nearest package of the specified type (package_key). Returns $default if no such package can be found. @see site_node::closest_ancestor_package } { if {$url eq ""} { set url [ad_conn url] } # Try the URL as is. if {[catch {nsv_get site_nodes $url} result] == 0} { array set node $result if { [lsearch -exact $package_keys $node(package_key)] != -1 } { return $node(package_id) } } # Add a trailing slash and try again. if {[string index $url end] ne "/"} { append url "/" if {[catch {nsv_get site_nodes $url} result] == 0} { array set node $result if { [lsearch -exact $package_keys $node(package_key)] != -1 } { return $node(package_id) } } } # Try successively shorter prefixes. while {$url ne ""} { # Chop off last component and try again. set url [string trimright $url /] set url [string range $url 0 [string last / $url]] if {[catch {nsv_get site_nodes $url} result] == 0} { array set node $result if {$node(pattern_p) == "t" && $node(object_id) ne "" && [lsearch -exact $package_keys $node(package_key)] != -1 } { return $node(package_id) } } } return $default } ad_proc -deprecated -public site_node_closest_ancestor_package_url { { -default "" } { -package_key {} } } { Returns the url stub of the nearest application of the specified type. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2001-02-05 @param package_key The types of packages for which we're looking (defaults to subsite packages) @param default The default value to return if no package of the specified type was found @see site::node::closest_ancestor_package } { if {$package_key eq ""} { set package_key [subsite::package_keys] } set subsite_pkg_id [site_node::closest_ancestor_package \ -include_self \ -package_key $package_key \ -url [ad_conn url] ] if {$subsite_pkg_id eq ""} { # No package was found... return the default return $default } return [lindex [site_node::get_url_from_object_id -object_id $subsite_pkg_id] 0] } ad_proc -public site_node::conn_url { } { Use this in place of ns_conn url when referencing host_nodes. This proc returns the appropriate ns_conn url value, depending on if host_node_map is used for current connection, or hostname's domain. } { set ns_conn_url [ns_conn url] # get config.tcl's hostname set nssock [ns_config ns/server/[ns_info server]/modules nssock] set nsunix [ns_config ns/server/[ns_info server]/modules nsunix] if {$nsunix ne ""} { set driver nsunix } else { set driver nssock } set config_hostname [ns_config ns/server/[ns_info server]/module/$driver Hostname] set current_location [util_current_location] # if current domain and hostdomain are different (and UseHostnameDomain), revise ns_conn_url if { ![string match -nocase "*${config_hostname}*" $current_location] } { # revise return_url to use hostname's domain set host_node_map_hosts_list [db_list -cache_key security-locations-host-names get_node_host_names "select host from host_node_map"] if { [llength $host_node_map_hosts_list] > 0 } { foreach hostname $host_node_map_hosts_list { if { [string match -nocase "http://${hostname}*" $current_location] || [string match -nocase "https://${hostname}*" $current_location] } { db_1row get_node_id_from_host_name "select node_id as host_node_id from host_node_map where host = :hostname" if { ![regsub -- "[site_node::get_url -node_id ${host_node_id} -notrailing]" $ns_conn_url {} ns_conn_url] } { ns_log Warning "site_node:conn_url(ref1111): regsub was unable to modify conn_url. User may not have reached intended url. ns_conn_url: ${ns_conn_url} ns_conn url: [ns_conn url]" } } } } } } openacs-5.7.0/packages/acs-tcl/tcl/site-nodes-procs.xql0000644000175000017500000000344710777764030022630 0ustar frankiefrankie update site_nodes set object_id = :object_id where node_id = :node_id update acs_objects set package_id = :object_id where object_id = :node_id update acs_objects set context_id = :context_id where object_id = :object_id update site_nodes set name = :name where node_id = :node_id update acs_objects set title = :name where object_id = :node_id update site_nodes set object_id = null where node_id = :node_id update acs_objects set package_id = null where object_id = :node_id select node_id from site_nodes where parent_id is null openacs-5.7.0/packages/acs-tcl/tcl/site-nodes-procs-postgresql.xql0000644000175000017500000000335510777764030025027 0ustar frankiefrankie postgresql7.1 select site_node__delete(:node_id); select n.node_id, n.parent_id, n.name, n.directory_p, n.pattern_p, n.object_id, p.package_key, p.package_id, p.instance_name, t.package_type from site_nodes n left join apm_packages p on n.object_id = p.package_id left join apm_package_types t using (package_key) where n.tree_sortkey between site_node_get_tree_sortkey(:node_id) and tree_right(site_node_get_tree_sortkey(:node_id)) order by n.tree_sortkey select n.node_id, n.parent_id, n.name, n.directory_p, n.pattern_p, n.object_id, p.package_key, p.package_id, p.instance_name, t.package_type from site_nodes n left join apm_packages p on n.object_id = p.package_id left join apm_package_types t using (package_key) where n.node_id = :node_id select site_node__url(node_id) from site_nodes where object_id = :object_id order by site_node__url(node_id) desc openacs-5.7.0/packages/acs-tcl/tcl/admin-init-oracle.xql0000644000175000017500000000051007271213362022702 0ustar frankiefrankie oracle8.1.6 select package_id, site_node.url(node_id) as url from apm_packages p, site_nodes n where p.package_id = n.object_id openacs-5.7.0/packages/acs-tcl/tcl/table-display-procs.tcl0000644000175000017500000010205611145353730023251 0ustar frankiefrankiead_library { This is the table, dimensional bar and sort tools. an example of their use can be found in /acs-examples @cvs-id $Id: table-display-procs.tcl,v 1.20 2009/02/13 20:28:08 jeffd Exp $ } # Dimensional selection bars. # ad_proc ad_dimensional {option_list {url {}} {options_set ""} {optionstype url}} { Generate an option bar as in the ticket system;
          • option_list -- the structure with the option data provided
          • url -- url target for select (if blank we set it to ad_conn url).
          • options_set -- if not provided defaults to [ns_getform], for hilite of selected options.
          • optionstype -- only url is used now, was thinking about extending so we get radio buttons and a form since with a slow select updating one thing at a time would be stupid.

          option_list structure is

              { 
                  {variable "Title" defaultvalue
                      {
                          {value "Text" {key clause}}
                          ...
                      }
                  }
                  ...
              }
          
              an example:
          
              set dimensional_list {
                  {visited "Last Visit" 1w {
                      {never "Never" {where "last_visit is null"}}
                      {1m "Last Month" {where "last_visit + 30 > sysdate"}}
                      {1w "Last Week" {where "last_visit + 7 > sysdate"}}
                      {1d "Today" {where "last_visit > trunc(sysdate)"}}
                  }}
                  ..(more of the same)..
              }
              
          } { set html {} if {$option_list eq ""} { return } if {$options_set eq ""} { set options_set [ns_getform] } if {$url eq ""} { set url [ad_conn url] } append html "
  • \n\n" foreach option $option_list { append html " \n" } append html "\n" append html "\n" foreach option $option_list { append html " \n" } append html "\n
    [lindex $option 1]
    \[" # find out what the current option value is. # check if a default is set otherwise the first value is used set option_key [lindex $option 0] set option_val {} if { $options_set ne ""} { set option_val [ns_set get $options_set $option_key] } if { $option_val eq "" } { set option_val [lindex $option 2] } set first_p 1 foreach option_value [lindex $option 3] { set thisoption [lindex $option_value 0] if { $first_p } { set first_p 0 } else { append html " | " } if {$option_val eq $thisoption } { append html "[lindex $option_value 1]" } else { append html "[lindex $option_value 1]" } } append html "\]
    \n" } ad_proc ad_dimensional_sql {option_list {what "where"} {joiner "and"} {options_set ""}} { see ad_dimensional for the format of option_list

    Given what clause we are asking for and the joiner this returns the sql fragment } { set out {} if {$option_list eq ""} { return } if {$options_set eq ""} { set options_set [ns_getform] } foreach option $option_list { # find out what the current option value is. # check if a default is set otherwise the first value is used set option_key [lindex $option 0] set option_val {} # get the option from the form if { $options_set ne ""} { set option_val [ns_set get $options_set $option_key] } #otherwise get from default if { $option_val eq "" } { set option_val [lindex $option 2] } foreach option_value [lindex $option 3] { set thisoption [lindex $option_value 0] if {$option_val eq $thisoption } { set code [lindex $option_value 2] if {$code ne ""} { if {[lindex $code 0] eq $what } { append out " $joiner [uplevel [list subst [lindex $code 1]]]" } } } } } return $out } ad_proc ad_dimensional_set_variables {option_list {options_set ""}} { set the variables defined in option_list from the form provided (form defaults to ad_conn form) or to default value from option_list if not in the form data.

    You only really need to call this if you need the variables (for example to pick which select statement and table to actually use) } { set out {} if {$option_list eq ""} { return } if {$options_set eq ""} { set options_set [ns_getform] } foreach option $option_list { # find out what the current option value is. # check if a default is set otherwise the first value is used set option_key [lindex $option 0] set option_val {} # get the option from the form if { $options_set ne "" && [ns_set find $options_set $option_key] != -1} { uplevel [list set $option_key [ns_set get $options_set $option_key]] } else { uplevel [list set $option_key [lindex $option 2]] } } } ad_proc -deprecated ad_table { { -Torder_target_url {} -Torderby {} -Tasc_order_img {^} -Tdesc_order_img {v} -Tmissing_text "No data found." -Tsuffix {} -Tcolumns {} -Taudit {} -Trows_per_band 1 -Tband_colors {{} "#ececec"} -Tband_classes {{even} {odd}} -Trows_per_page 0 -Tmax_rows 0 -Ttable_extra_html {cellpadding=3 cellspacing=0 class="table-display"} -Theader_row_extra {style="background-color:#f8f8f8" class="table-header"} -Ttable_break_html "

    " -Tpre_row_code {} -Trow_code {[subst $Trow_default]} -Tpost_data_ns_sets {} -Textra_vars {} -Textra_rows {} -bind {} -dbn {} } statement_name sql_qry Tdatadef } { DRB: New code should use the listbuilder. Note: all the variables in this function are named Tblah since we could potentially have namespace collisions

    build and return an html fragment given an active query and a data definition.

    • sql_qry -- The query that should be executed to generate the table.
      You can specify an optional -bind argument to specify a ns_set of bind variables.
    • Tdatadef -- the table declaration.
    Datadef structure :
     
        { 
            {column_id "Column_Heading" order_clause display_info}
            ...
        }
        
    • column_id -- what to set as orderby for sorting and also is the default variable for the table cell.
    • the text for the heading to be wrapped in <th> and </th> tags. I am not entirely happy that things are wrapped automatically since you might not want plain old th tags but I also don;t want to add another field in the structure.
    • order_clause -- the order clause for the field. If null it defaults to "column_id $order". It is also interpolated, with orderby and order defined as variables so that:
                   {upper(last_name) $order, upper(first_names) $order}
               
      would do the right thing.

      the value "no_sort" should be used for columns which should not allow sorting.

      the value "sort_by_pos" should be used if the columns passed in are column positions rather than column names.

    • display_info. If this is a null string you just default to generating <td>column_id</td>. If it is a string in the lookup list then special formatting is applied; this is l r c tf 01 for align=left right center, Yes/No (from tf), Yes/No from 0/1.

      if the display stuff is not any of the above then it is interpolated and the results returned (w/o any <td> tags put in). An example:

          set table_def { 
              {ffn "Full Name" 
                  {upper(last_name) $order, upper(first_names) $order}
                  {<td><a href="/admin/users/one?user_id=$user_id">$first_names $last_name</a></td>}}
              {email "e-Mail" {} {<td><a href="mailto:$email">$email</a>}}
              {email_bouncing_p "e-Bouncing?" {} tf}
              {user_state "State" {} {}}
              {last_visit "Last Visit" {} r}
              {actions "Actions" no_sort {<td>
                      <a href="/admin/users/basic-info-update?user_id=$user_id">Edit Info</a> | 
                      <a href="/admin/users/password-update?user_id=$user_id">New Password</a> |
                  [ad_registration_finite_state_machine_admin_links $user_state $user_id]}}
          }
          
    @param dbn The database name to use. If empty_string, uses the default database. } { set full_statement_name [db_qd_get_fullname $statement_name] # This procedure needs a full rewrite! db_with_handle -dbn $dbn Tdb { # Execute the query set selection [db_exec select $Tdb $full_statement_name $sql_qry] set Tcount 0 set Tband_count 0 set Tpage_count 0 set Tband_color 0 set Tband_class 0 set Tn_bands [llength $Tband_colors] set Tn_band_classes [llength $Tband_classes] set Tform [ad_conn form] # export variables from calling environment if {$Textra_vars ne ""} { foreach Tvar $Textra_vars { upvar $Tvar $Tvar } } # get the current ordering information set Torderbykey {::not_sorted::} set Treverse {} regexp {^([^*,]+)([*])?} $Torderby match Torderbykey Treverse if {$Treverse eq "*"} { set Torder desc } else { set Torder asc } # set up the target url for new sorts if {$Torder_target_url eq ""} { set Torder_target_url [ad_conn url] } set Texport "[uplevel [list export_ns_set_vars url [list orderby$Tsuffix]]]&" if {$Texport == "&"} { set Texport {} } set Tsort_url "$Torder_target_url?${Texport}orderby$Tsuffix=" set Thtml {} set Theader {} # build the list of columns to display... set Tcolumn_list [ad_table_column_list $Tdatadef $Tcolumns] # generate the header code # append Theader "\n" if {$Theader_row_extra eq ""} { append Theader "\n" } else { append Theader "\n" } foreach Ti $Tcolumn_list { set Tcol [lindex $Tdatadef $Ti] if { ( [ns_set find $selection [lindex $Tcol 0]] < 0 && ([empty_string_p [lindex $Tcol 2]] || ([lindex $Tcol 2] ne "sort_by_pos" ) ) ) || [lindex $Tcol 2] eq "no_sort" } { # not either a column in the select or has sort code # then just a plain text header so do not do sorty things append Theader " \n" } else { if {[lindex $Tcol 0] eq $Torderbykey } { if {$Torder eq "desc"} { set Tasord $Tasc_order_img } else { set Tasord $Tdesc_order_img } } else { set Tasord {} } append Theader " \n" } } append Theader "\n" # # This has gotten kind of ugly. Here we are looping over the # rows returned and then potentially a list of ns_sets which can # be passed in (grrr. Richard Li needs for general protections stuff # for "fake" public record which does not exist in DB). # set Tpost_data 0 while { 1 } { if {!$Tpost_data && [ns_db getrow $Tdb $selection]} { # in all its evil majesty set_variables_after_query } else { # move on to fake rows... incr Tpost_data } if { $Tpost_data && $Tpost_data <= [llength $Tpost_data_ns_sets] } { # bind the Tpost_data_ns_sets row of the passed in data set_variables_after_query_not_selection [lindex $Tpost_data_ns_sets [expr {$Tpost_data - 1}]] } elseif { $Tpost_data } { # past the end of the fake data drop out. break } if { $Tmax_rows && $Tcount >= $Tmax_rows } { if { ! $Tpost_data } { # we hit max count and had rows left to read... ns_db flush $Tdb } break } # deal with putting in the header if need if { $Tcount == 0 } { append Thtml "$Theader" } elseif { $Tpage_count == 0 } { append Thtml "
    [lindex $Tcol 1]\n" append Theader "[lindex $Tcol 1] $Tasord
    \n$Ttable_break_html\n$Theader" } # first check if we are in audit mode and if the audit columns have changed set Tdisplay_changes_only 0 if {$Taudit ne "" && $Tcount > 0} { # check if the audit key columns changed foreach Taudit_key $Taudit { if {[set $Taudit_key] eq [set P$Taudit_key] } { set Tdisplay_changes_only 1 } } } # this is for breaking on sorted field etc. append Thtml [subst $Tpre_row_code] if { ! $Tdisplay_changes_only } { # in audit mode a record spans multiple rows. incr Tcount incr Tband_count } incr Tpage_count if { $Trows_per_page && $Tpage_count >= $Trows_per_page } { set Tband_color 0 set Tband_class 0 set Tband_count 0 set Tpage_count 0 } set Trow_default {} # generate the row band color if { $Tband_count >= $Trows_per_band } { set Tband_count 0 set Tband_color [expr ($Tband_color + 1) % $Tn_bands ] set Tband_class [expr ($Tband_class + 1) % $Tn_band_classes ] } # do this check since we would like the ability to band with # page background as well if {$Tn_bands && ![empty_string_p [lindex $Tband_colors $Tband_color]]} { append Trow_default " style=\"background-color:[lindex $Tband_colors $Tband_color]\"" } if {$Tn_band_classes && ![empty_string_p [lindex $Tband_classes $Tband_class]]} { append Trow_default " class=\"[lindex $Tband_classes $Tband_class]\"" } set Trow_default "" append Thtml [subst $Trow_code] foreach Ti $Tcolumn_list { set Tcol [lindex $Tdatadef $Ti] # If we got some special formatting code we handle it # single characters r l c are special for alignment set Tformat [lindex $Tcol 3] set Tcolumn [lindex $Tcol 0] switch $Tformat { "" {set Tdisplay_field " [set $Tcolumn]\n"} r {set Tdisplay_field " [set $Tcolumn]\n"} l {set Tdisplay_field " [set $Tcolumn]\n"} c {set Tdisplay_field " [set $Tcolumn]\n"} tf {set Tdisplay_field " [util_PrettyBoolean [set $Tcolumn]]\n"} 01 {set Tdisplay_field " [util_PrettyTclBoolean [set $Tcolumn]]\n"} bz {set Tdisplay_field "  [blank_zero [set $Tcolumn]]\n"} default {set Tdisplay_field " [subst $Tformat]\n"} } if { $Tdisplay_changes_only && $Tdisplay_field eq $Tlast_display($Ti) } { set Tdisplay_field { } } else { set Tlast_display($Ti) $Tdisplay_field } append Thtml $Tdisplay_field } append Thtml "\n" # keep the last row around so we can do fancy things. # so on next row we can say things like if $Pvar != $var not blank if { $Tpost_data && $Tpost_data <= [llength $Tpost_data_ns_sets] } { # bind the Tpost_data_ns_sets row of the passed in data set_variables_after_query_not_selection [lindex $Tpost_data_ns_sets [expr {$Tpost_data - 1}]] P } else { set_variables_after_query_not_selection $selection P } } if { $Tcount > 0} { append Thtml "$Textra_rows \n" } else { append Thtml $Tmissing_text } } return $Thtml } ad_proc ad_table_column_list { { -sortable all } datadef columns } { build a list of pointers into the list of column definitions

    returns a list of indexes into the columns one per column it found

    -sortable from t/f/all } { set column_list {} if {$columns eq ""} { for {set i 0} {$i < [llength $datadef]} {incr i} { if {$sortable eq "all" || ($sortable eq "t" && [lindex [lindex $datadef $i] 2] != "no_sort") || ($sortable eq "f" && [lindex [lindex $datadef $i] 2] == "no_sort") } { lappend column_list $i } } } else { set colnames {} foreach col $datadef { if {$sortable eq "all" || ($sortable eq "t" && [lindex $col 2] ne "no_sort") || ($sortable eq "f" && [lindex $col 2] eq "no_sort") } { lappend colnames [lindex $col 0] } else { # placeholder for invalid column lappend colnames "X+X" } } foreach col $columns { set i [lsearch $colnames $col] if {$i > -1} { lappend column_list $i } } } return $column_list } ad_proc ad_sort_primary_key orderby { return the primary (first) key of an order spec used by } { if {[regexp {^([^*,]+)} $orderby match]} { return $match } return $orderby } ad_proc ad_table_same varname { Called from inside ad_table. returns true if the variable has same value as on the previous row. Always false for 1st row. } { if { [uplevel set Tcount] && [uplevel string compare \$$varname \$P$varname] == 0} { return 1 } else { return 0 } } ad_proc ad_table_span {str {td_html "align=\"left\""}} { given string the function generates a row which spans the whole table. } { return "$str" } ad_proc ad_table_form {datadef {type select} {return_url {}} {item_group {}} {item {}} {columns {}} {allowed {}}} { builds a form for chosing the columns to display

    columns is a list of the currently selected columns.

    allowed is the list of all the displayable columns, if empty all columns are allowed. } { # first build a map of all available columns set sel_list [ad_table_column_list $datadef $allowed] # build the map of currently selected columns set sel_columns [ad_table_column_list $datadef $columns] set max_columns [llength $sel_list] set n_sel_columns [llength $sel_columns] set html {} if {$item eq "CreateNewCustom" } { set item {} } # now spit out the form fragment. if {$item ne ""} { append html "

    Editing $item

    " append html "
    " append html "" append html "" append html "[export_form_vars item_group item]" if {$return_url ne ""} { append html "[export_form_vars return_url]" } append html "
    " } append html "
    " if {$return_url ne ""} { append html "[export_form_vars return_url]" } if {$item_group eq ""} { set item_group [ad_conn url] } append html "[export_form_vars item_group]" if {$item ne ""} { set item_original $item append html "[export_form_vars item_original]" append html "" } else { append html "" } append html "" append html "" if {$item ne ""} { set item_original item append html "[export_form_vars item_original]" append html "" } if {$type eq "select" } { # select table set options "" foreach opt $sel_list { append options " " } for {set i 0} { $i < $max_columns} {incr i} { if {$i < $n_sel_columns} { set match [lindex [lindex $datadef [lindex $sel_columns $i]] 0] regsub "(\n" } } else { # radio button table append html "" foreach opt $sel_list { append html "" } append html "" foreach opt $sel_list { append options "" } for {set i 0} { $i < $max_columns} {incr i} { if {$i < $n_sel_columns} { set match [lindex [lindex $datadef [lindex $sel_columns $i]] 0] regsub "( type=\"radio\" )(value=\"$match\">)" $options "\\1 checked=\"checked\" \\2" out } else { set out $options } regsub -all {@@} $out $i out append html "$out\n" } } append html "
    Name:
     Editing the name will rename the view
    [expr {$i + 1}]
    Col \#[lindex [lindex $datadef $opt] 1]
    [expr {$i + 1}]
    " return $html } ad_proc ad_table_sort_form {datadef {type select} {return_url {}} {item_group {}} {item {}} {sort_spec {}} {allowed {}}} { builds a form for setting up custom sorts.

    • datadef is the table definition as in ad_table.
    • type is select or radio (only select is implemented now)
    • return_url is the return url passed through to the page that validates and saves the sort customization.
    • item_group is a string identifying the customization "ticket_tracker_main_sort" for example.
    • item is the user entered identifier
    • sort_spec is the sort specifier as in ad_new_sort_by
    • allowed is the list of all the columns allowed, if empty all are allowed.

    An example from the ticket system:

          ad_table_sort_form $tabledef select $return_url ticket_tracker_main_sort $ticket_sort $orderby
        
    } { # first build a map of all available columns set sel_list [ad_table_column_list -sortable t $datadef $allowed] # build the map of currently selected columns set full_column [split $sort_spec ","] set sel_columns [list] set direction [list] foreach col $full_column { regexp {([^*,]+)([*])?} $col match coln dirn if {$dirn eq "*"} { set dirn desc } else { set dirn asc } lappend sel_columns $coln lappend direction $dirn } set max_columns 4 set n_sel_columns [llength $sel_columns] set html {} if {$item eq "CreateNewCustom" } { set item {} } # now spit out the form fragment. if {$item ne ""} { append html "

    Editing $item

    " append html "
    " append html "" append html "" append html "[export_form_vars item_group item]" if {$return_url ne ""} { append html "[export_form_vars return_url]" } append html "
    " } append html "
    " if {$return_url ne ""} { append html "[export_form_vars return_url]" } if {$item_group eq ""} { set item_group [ad_conn url] } append html "[export_form_vars item_group]" if {$item ne ""} { set item_original $item append html "[export_form_vars item_original]" append html "" } else { append html "" } append html "" append html "" if {$item ne ""} { set item_original item append html "[export_form_vars item_original]" append html "" } set options "" foreach opt $sel_list { append options " " } for {set i 0} { $i < $max_columns} {incr i} { if {$i < $n_sel_columns} { set match [lindex $sel_columns $i] regsub "(\n" } append html "
    Name:
     Editing the name will rename the sort
    [expr {$i + 1}]" switch [lindex $direction $i] { asc { append html "" } default { append html "" } } append html "\n
    " return $html } ad_proc ad_order_by_from_sort_spec {sort_by tabledef} { Takes a sort_by spec, and translates it into into an "order by" clause with each sort_by key dictated by the sort info in tabledef } { set order_by_clause {} foreach sort_key_spec [split $sort_by ","] { if { [regexp {^([A-Za-z_0-9]+)(\*?)$} $sort_key_spec match sort_key reverse] } { # if there's a "*" after the key, we want to reverse the usual order foreach order_spec $tabledef { if { $sort_key == [lindex $order_spec 0] } { if { $reverse eq "*" } { set order "desc" } else { set order "asc" } if { $order_by_clause eq "" } { append order_by_clause "\norder by " } else { append order_by_clause ", " } # tack on the order by clause if {![empty_string_p [lindex $order_spec 2]] && ([lindex $order_spec 2] ne "sort_by_pos" )} { append order_by_clause "[subst [lindex $order_spec 2]]" } else { append order_by_clause "$sort_key $order" } break } } } } return $order_by_clause } ad_proc ad_new_sort_by {key keys} { Makes a new sort_by string, sorting by "key". If the key is followed by "*", that indicates the ordering should be reversed from the default ordering for that key. Old sort keys are retained, so the sort appears to be a little more stable. That is, suppose two things are sorted into an order, and their values for a different column are the same. If that different column is used as the primary sort key to reorder, the things which have the same value for the newly-sorted column will remain in the same relative order. } { if { $keys eq "" } { return $key } elseif { [regexp "^${key}(\\*?)," "$keys," match reverse] } { # if this was already the first key, then reverse order if { $reverse eq "*" } { regsub "\\*," "$keys," "," keys } else { regsub "," "$keys," "*," keys } regsub ",$" $keys "" keys return $keys } else { regsub ",$key\\*?," "$keys," "," keys regsub ",$" $keys "" keys return "$key,$keys" } } ad_proc ad_same_page_link {variable value text {form ""}} { Makes a link to this page, with a new value for "variable". } { if { $form eq "" } { set form [ns_getform] } set url_vars [export_ns_set_vars url $variable $form] return "$text" } ad_proc ad_reverse order { returns the opposite sort order from the one it is given. Mostly for columns whose natural sort order is not the default. } { switch [string tolower $order] { desc {return asc} asc {return desc} } return $order } ad_proc ad_custom_load {user_id item_group item item_type} { load a persisted user customization as saved by for example table-custom.tcl. } { if { ![db_0or1row load_user_customization { select value_type, value from user_custom where user_id = :user_id and item_type = :item_type and item_group = :item_group and item = :item }] } { set value {} } return $value } ad_proc ad_custom_list {user_id item_group item_set item_type target_url custom_url {new_string "new view"}} { Generates the html fragment for choosing, editing and creating user customized data } { set items [db_list custom_list { select item from user_custom where user_id = :user_id and item_type = :item_type and item_group = :item_group }] set break {} foreach item $items { if {$item_set eq $item } { append html "$break$item (edit)" } else { append html "$break$item" } set break " | " } append html "$break ($new_string)\n" return $html } ad_proc ad_custom_page_defaults defaults { set the page defaults. If the form is empty do a returnredirect with the defaults set } { set form [ns_getform] if {$form eq "" && $defaults ne ""} { # we did not get a form so set all the variables # and redirect to set them set redirect "[ad_conn url]?" set pre {} foreach kvp $defaults { append redirect "$pre[lindex $kvp 0]=[ns_urlencode [lindex $kvp 1]]" set pre {&} } ad_returnredirect $redirect ad_script_abort } # we have a form so stuff in the ones we dont find. # should think about how to support lists and ns_set persist too. foreach kvp $defaults { if {[ns_set find $form [lindex $kvp 0]] < 0} { ns_set put $form [lindex $kvp 0] [lindex $kvp 1] } } } ad_proc ad_custom_form {return_url item_group item} { sets up the head of a form to feed to /tools/form-custom.tcl } { append html "
    \n" if {$return_url ne ""} { append html "[export_form_vars return_url]\n" } if {$item_group eq ""} { set item_group [ad_conn url] } set item_original $item append html "[export_form_vars item_group item item_original]\n" append html "" } ad_proc ad_dimensional_settings {define current} { given a dimensional slider definition this routine returns a form to set the defaults for the given slider. NB...this does not close either the table or the form... } { foreach opt $define { append html "[lindex $opt 1]" append html "\n" } return $html } ad_proc ad_table_orderby_sql {datadef orderby order} { create the order by clause consistent with the orderby and order variables and the datadef which built the table } { set orderclause "order by $orderby $order" foreach col $datadef { if {$orderby eq [lindex $col 0] } { if {![empty_string_p [lindex $col 2]]} { set orderclause [subst [lindex $col 2]] } } } return $orderclause } openacs-5.7.0/packages/acs-tcl/tcl/utilities-procs.tcl0000644000175000017500000044736211463110545022544 0ustar frankiefrankiead_library { Provides a variety of non-ACS-specific utilities, including the procs to support the who's online feature. @author Various (acs@arsdigita.com) @creation-date 13 April 2000 @cvs-id $Id: utilities-procs.tcl,v 1.127 2010/10/30 21:43:01 gustafn Exp $ } namespace eval util {} # Let's define the nsv arrays out here, so we can call nsv_exists # on their keys without checking to see if it already exists. # we create the array by setting a bogus key. proc proc_source_file_full_path {proc_name} { if { ![nsv_exists proc_source_file $proc_name] } { return "" } else { set tentative_path [nsv_get proc_source_file $proc_name] regsub -all {/\./} $tentative_path {/} result return $result } } ad_proc util_report_library_entry {{extra_message ""}} "Should be called at beginning of private Tcl library files so that it is easy to see in the error log whether or not private Tcl library files contain errors." { set tentative_path [info script] regsub -all {/\./} $tentative_path {/} scrubbed_path if { $extra_message eq "" } { set message "Loading $scrubbed_path" } else { set message "Loading $scrubbed_path; $extra_message" } ns_log Notice $message } ad_proc check_for_form_variable_naughtiness { name value } { stuff to process the data that comes back from the users if the form looked like and then after you run this function you'll have Tcl vars $foo and $bar set to whatever the user typed in the form this uses the initially nauseating but ultimately delicious tcl system function "uplevel" that lets a subroutine bash the environment and local vars of its caller. It ain't Common Lisp... This is an ad-hoc check to make sure users aren't trying to pass in "naughty" form variables in an effort to hack the database by passing in SQL. It is called in all instances where a Tcl variable is set from a form variable. Checks the given variable for against known form variable exploits. If it finds anything objectionable, it throws an error. } { # security patch contributed by michael@cleverly.com if { [string match "QQ*" $name] } { error "Form variables should never begin with QQ!" } # contributed by michael@cleverly.com if { "Vform_counter_i" eq $name } { error "Vform_counter_i not an allowed form variable" } # The statements below make ACS more secure, because it prevents # overwrite of variables from something like set_the_usual_form_variables # and it will be better if it was in the system. Yet, it is commented # out because it will cause an unstable release. To add this security # feature, we will need to go through all the code in the ACS and make # sure that the code doesn't try to overwrite intentionally and also # check to make sure that when tcl files are sourced from another proc, # the appropriate variables are unset. If you want to install this # security feature, then you can look in the release notes for more info. # # security patch contributed by michael@cleverly.com, # fixed by iwashima@arsdigita.com # # upvar 1 $name name_before # if { [info exists name_before] } { # The variable was set before the proc was called, and the # form attempts to overwrite it # error "Setting the variables from the form attempted to overwrite existing variable $name" # } # no naughtiness with uploaded files (discovered by ben@mit.edu) # patch by richardl@arsdigita.com, with no thanks to # jsc@arsdigita.com. if { [string match "*tmpfile" $name] } { set tmp_filename [ns_queryget $name] # ensure no .. in the path ns_normalizepath $tmp_filename set passed_check_p 0 # check to make sure path is to an authorized directory set tmpdir_list [ad_parameter_all_values_as_list TmpDir] if { $tmpdir_list eq "" } { set tmpdir_list [list "/var/tmp" "/tmp"] } foreach tmpdir $tmpdir_list { if { [string match "$tmpdir*" $tmp_filename] } { set passed_check_p 1 break } } if { !$passed_check_p } { error "You specified a path to a file that is not allowed on the system!" } } # integrates with the ad_set_typed_form_variable_filter system # written by dvr@arsdigita.com # see if this is one of the typed variables global ad_typed_form_variables if { [info exists ad_typed_form_variables] } { foreach typed_var_spec $ad_typed_form_variables { set typed_var_name [lindex $typed_var_spec 0] if { ![string match $typed_var_name $name] } { # no match. Go to the next variable in the list continue } # the variable matched the pattern set typed_var_type [lindex $typed_var_spec 1] if { "" eq $typed_var_type } { # if they don't specify a type, the default is 'integer' set typed_var_type integer } set variable_safe_p [ad_var_type_check_${typed_var_type}_p $value] if { !$variable_safe_p } { ns_returnerror 500 "variable $name failed '$typed_var_type' type check" ns_log Error "check_for_form_variable_naughtiness: [ad_conn url] called with \$$name = $value" error "variable $name failed '$typed_var_type' type check" } # we've found the first element in the list that matches, # and we don't want to check against any others break } } } ad_proc -private DoubleApos {string} { if the user types "O'Malley" and you try to insert that into an SQL database, you will lose big time because the single quote is magic in SQL and the insert has to look like 'O''Malley'.

    You should be using bind variables rather than calling DoubleApos @return string with single quotes converted to a pair of single quotes } { regsub -all ' "$string" '' result return $result } # debugging kludges ad_proc -public NsSettoTclString {set_id} { returns a plain text version of the passed ns_set id } { set result "" for {set i 0} {$i<[ns_set size $set_id]} {incr i} { append result "[ns_set key $set_id $i] : [ns_set value $set_id $i]\n" } return $result } ad_proc -public get_referrer {} { gets the Referer for the headers } { return [ns_set get [ad_conn headers] Referer] } ## # Database-related code ## ad_proc ad_dbclick_check_dml { { -bind "" } statement_name table_name id_column_name generated_id return_url insert_dml } { This proc is used for pages using double click protection. table_name is table_name for which we are checking whether the double click occured. id_column_name is the name of the id table column. generated_id is the generated id, which is supposed to have been generated on the previous page. return_url is url to which this procedure will return redirect in the case of successful insertion in the database. insert_sql is the sql insert statement. if data is ok this procedure will insert data into the database in a double click safe manner and will returnredirect to the page specified by return_url. if database insert fails, this procedure will return a sensible error message to the user. } { if { [catch { if { $bind ne "" } { db_dml $statement_name $insert_dml -bind $bind } else { db_dml $statement_name $insert_dml } } errmsg] } { # Oracle choked on the insert # detect double click if { [db_0or1row double_click_check " select 1 as one from $table_name where $id_column_name = :generated_id " -bind [ad_tcl_vars_to_ns_set generated_id]] } { ad_returnredirect $return_url return } ns_log Error "[info script] choked. Oracle returned error: $errmsg" ad_return_error "Error in insert" " We were unable to do your insert in the database. Here is the error that was returned:

    	$errmsg
    	

    " return } ad_returnredirect $return_url # should this be ad_script_abort? Should check how its being used. return } ad_proc -public util_AnsiDatetoPrettyDate {sql_date} { Converts 1998-09-05 to September 5, 1998 } { set sql_date [string range $sql_date 0 9] if { ![regexp {(.*)-(.*)-(.*)$} $sql_date match year month day] } { return "" } else { set allthemonths {January February March April May June July August September October November December} # we have to trim the leading zero because Tcl has such a # brain damaged model of numbers and decided that "09-1" # was "8.0" set trimmed_month [string trimleft $month 0] set pretty_month [lindex $allthemonths [expr {$trimmed_month - 1}]] set trimmed_day [string trimleft $day 0] return "$pretty_month $trimmed_day, $year" } } ad_proc -public remove_nulls_from_ns_set {old_set_id} { Creates and returns a new ns_set without any null value fields @return new ns_set } { set new_set_id [ns_set new "no_nulls$old_set_id"] for {set i 0} {$i<[ns_set size $old_set_id]} {incr i} { if { [ns_set value $old_set_id $i] ne "" } { ns_set put $new_set_id [ns_set key $old_set_id $i] [ns_set value $old_set_id $i] } } return $new_set_id } ad_proc -public merge_form_with_query { { -bind {} } form statement_name sql_qry } { Merges a form with a query string. @param form the form to be stuffed. @param statement_name An identifier for the sql_qry to be executed. @param sql_qry The sql that must be executed. @param bind A ns_set stuffed with bind variables for the sql_qry. } { set set_id [ns_set create] ns_log debug "merge_form_with_query: statement_name = $statement_name" ns_log debug "merge_form_with_query: sql_qry = $sql_qry" ns_log debug "merge_form_with_query: set_id = $set_id" db_0or1row $statement_name $sql_qry -bind $bind -column_set set_id if { $set_id ne "" } { for {set i 0} {$i<[ns_set size $set_id]} {incr i} { set form [ns_formvalueput $form [ns_set key $set_id $i] [ns_set value $set_id $i]] } } return $form } proc util_PrettyBoolean {t_or_f { default "default" } } { if { $t_or_f eq "t" || $t_or_f eq "T" } { return "Yes" } elseif { $t_or_f eq "f" || $t_or_f eq "F" } { return "No" } else { # Note that we can't compare default to the empty string as in # many cases, we are going want the default to be the empty # string if { $default eq "default" } { return "Unknown (\"$t_or_f\")" } else { return $default } } } ad_proc util_PrettyTclBoolean {zero_or_one} "Turns a 1 (or anything else that makes a Tcl IF happy) into Yes; anything else into No" { if {$zero_or_one} { return "Yes" } else { return "No" } } ad_proc -public randomInit {seed} { seed the random number generator. } { nsv_set rand ia 9301 nsv_set rand ic 49297 nsv_set rand im 233280 nsv_set rand seed $seed } ad_proc -public random {} { Return a pseudo-random number between 0 and 1. } { nsv_set rand seed [expr {([nsv_get rand seed] * [nsv_get rand ia] + [nsv_get rand ic]) % [nsv_get rand im]}] return [expr {[nsv_get rand seed]/double([nsv_get rand im])}] } ad_proc -public randomRange {range} { Returns a pseudo-random number between 0 and range. @return integer } { return [expr {int([random] * $range)}] } ad_proc -public db_html_select_options { { -bind "" } { -select_option "" } stmt_name sql } { Generate html option tags for an html selection widget. If select_option is passed, this option will be marked as selected. @author yon [yon@arsdigita.com] } { set select_options "" if { $bind ne "" } { set options [db_list $stmt_name $sql -bind $bind] } else { set options [db_list $stmt_name $sql] } foreach option $options { if { $option eq $select_option } { append select_options "\n" } else { append select_options "\n" } } return $select_options } ad_proc -public db_html_select_value_options { { -bind "" } { -select_option [list] } { -value_index 0 } { -option_index 1 } stmt_name sql } { Generate html option tags with values for an html selection widget. if select_option is passed and there exists a value for it in the values list, this option will be marked as selected. select_option can be passed a list, in which case all options matching a value in the list will be marked as selected. @author yon [yon@arsdigita.com] } { set select_options "" if { $bind ne "" } { set options [db_list_of_lists $stmt_name $sql -bind $bind] } else { set options [uplevel [list db_list_of_lists $stmt_name $sql]] } foreach option $options { if { [lsearch -exact $select_option [lindex $option $value_index]] >= 0 } { append select_options "\n" } else { append select_options "\n" } } return $select_options } ##### # # Export Procs # ##### ad_proc -public export_vars { -sign:boolean -form:boolean -url:boolean -quotehtml:boolean -entire_form:boolean -no_empty:boolean {-base} {-anchor} {-exclude {}} {-override {}} {vars {}} } { Exports variables either in URL or hidden form variable format. It should replace export_form_vars, export_url_vars and all their friends.

    Example usage: [export_vars -form { foo bar baz }]

    This will export the three variables foo, bar and baz as hidden HTML form fields. It does exactly the same as [export_form_vars foo bar baz].

    Example usage: [export_vars -url -sign -override {{foo "new value"}} -exclude { bar } { foo bar baz }]

    This will export a variable named foo with the value "new value" and a variable named baz with the value of baz in the caller's environment. Since we've specified that bar should be excluded, bar won't get exported even though it's specified in the last argument. Additionally, even though foo is specified also in the last argument, the value we use is the one given in the override argument. Finally, both variables are signed, because we specified the -sign switch.

    You can specify variables with three different precedences, namely override, exclude or vars. If a variable is present in override, that's what'll get exported, no matter what. If a variable is in exclude and not in override, then it will not get output. However, if it is in vars and not in either of override or exclude, then it'll get output. In other words, we check override, exclude and vars in that order of precedence.

    The two variable specs, vars and override both look the same: They take a list of variable specs. Examples of variable specs are:

    • foo
    • foo:multiple,sign
    • {foo "the value"}
    • {foo {[my_function arg]}}
    • {foo:array,sign {[array get my_array]}}
    In general, there's one or two elements. If there are two, the second element is the value we should use. If one, we pull the value from the variable of the same name in the caller's environment. Note that when you specify the value directly here, we call subst on it, so backslashes, square brackets and variables will get substituted correctly. Therefore, make sure you use curly braces to surround this instead of the [list] command; otherwise the contents will get substituted twice, and you'll be in trouble.

    Right after the name, you may specify a colon and some flags, separated by commas. Valid flags are:

    multiple
    Treat the value as a list and output each element separately.
    array
    The value is an array and should be exported in a way compliant with the :array flag of ad_page_contract, which means that each entry will get output as name.key=value.

    If you don't specify a value directly, but want it pulled out of the Tcl environment, then you don't need to specify :array. If you do, and the variable is in fact not an array, an error will be thrown.

    sign
    Sign this variable. This goes hand-in-hand with the :verify flag of ad_page_contract and makes sure that the value isn't tampered with on the client side. The -sign switch to export_vars, is a short-hand for specifying the :sign switch on every variable.
    The argument exclude simply takes a list of names of variables that you don't want exported, even though they're specified in vars.

    Intended use: A page may have a set of variables that it cares about. You can store this in a variable once and pass that to export_vars like this:

    set my_vars { user_id sort_by filter_by }
    ... [export_vars $my_vars] ...

    Then, say one of them contains a column to filter on. When you want to clear that column, you can say [export_vars -exclude { filter_by } $my_vars].

    Similarly, if you want to change the sort order, you can say [export_vars -override { { sort_by $column } } $my_vars], and sorting will be done according to the new value of column.

    If the variable name contains a colon (:), that colon must be escaped with a backslash, so for example "form:id" becomes "form\:id". Sorry. @param sign Sign all variables. @param url Export in URL format. This is the default. @param form Export in form format. You can't specify both URL and form format. @param quotehtml HTML quote the entire resulting string. This is an interim solution while we're waiting for the templating system to do the quoting for us. @param entire_form Export the entire form from the GET query string or the POST. @option no_empty If specified, variables with an empty string value will be suppressed from being exported. This avoids cluttering up the URLs with lots of unnecessary variables. @option base The base URL to make a link to. This will be prepended to the query string along with a question mark (?), if the query is non-empty. so the returned string can be used directly in a link. This is only relevant to URL export. @author Lars Pind (lars@pinds.com) @creation-date December 7, 2000 } { if { $form_p && $url_p } { return -code error "You must select either form format or url format, not both." } # default to URL format if { !$form_p && !$url_p } { set url_p 1 } # 'noprocessing_vars' is yet another container of variables, # only this one doesn't have the values subst'ed # and we don't try to find :multiple and :array flags in the namespec set noprocessing_vars [list] if { $entire_form_p } { set the_form [ns_getform] if { $the_form ne "" } { for { set i 0 } { $i < [ns_set size $the_form] } { incr i } { set varname [ns_set key $the_form $i] set varvalue [ns_set value $the_form $i] lappend noprocessing_vars [list $varname $varvalue] } } } ##### # # Parse the arguments # ##### # 1. if they're in override, use those # 2. if they're in vars, but not in exclude or override, use those # There'll always be an entry here if the variable is to be exported array set exp_precedence_type [list] # This contains entries of the form exp_flag(name:flag) e.g., exp_flag(foo:multiple) array set exp_flag [list] # This contains the value if provided, otherwise we'll pull it out of the caller's environment array set exp_value [list] foreach precedence_type { override exclude vars noprocessing_vars } { foreach var_spec [set $precedence_type] { if { [llength $var_spec] > 2 } { return -code error "A varspec must have either one or two elements." } if { $precedence_type ne "noprocessing_vars" } { # Hide escaped colons for below split regsub -all {\\:} $var_spec "!!cOlOn!!" var_spec set name_spec [split [lindex $var_spec 0] ":"] # Replace escaped colons with single colon regsub -all {!!cOlOn!!} $name_spec ":" name_spec set name [lindex $name_spec 0] } else { set name [lindex $var_spec 0] # Nothing after the colon, since we don't interpret any colons set name_spec [list $name {}] } # If we've already encountered this varname, ignore it if { ![info exists exp_precedence_type($name)] } { set exp_precedence_type($name) $precedence_type if { $precedence_type ne "exclude" } { set flags [split [lindex $name_spec 1] ","] foreach flag $flags { set exp_flag($name:$flag) 1 } if { $sign_p } { set exp_flag($name:sign) 1 } if { [llength $var_spec] > 1 } { if { $precedence_type ne "noprocessing_vars" } { set value [uplevel subst \{[lindex $var_spec 1]\}] } else { set value [lindex $var_spec 1] } set exp_value($name) $value # If the value is specified explicitly, we include it even if the value is empty } else { upvar 1 $name upvar_variable if { [info exists upvar_variable] } { if { [array exists upvar_variable] } { if { $no_empty_p } { # If the no_empty_p flag is set, remove empty string values first set exp_value($name) [list] foreach { key value } [array get upvar_variable] { if { $value ne "" } { lappend exp_value($name) $key $value } } } else { # If no_empty_p isn't set, just do an array get set exp_value($name) [array get upvar_variable] } set exp_flag($name:array) 1 } else { if { [info exists exp_flag($name:array)] } { return -code error "Variable \"$name\" is not an array" } if { !$no_empty_p } { set exp_value($name) $upvar_variable } else { # no_empty_p flag set, remove empty strings if { [info exists exp_flag($name:multiple)] } { # This is a list, remove empty entries set exp_value($name) [list] foreach elm $upvar_variable { if { $elm ne "" } { lappend exp_value($name) $elm } } } else { # Simple value, this is easy if { $upvar_variable ne "" } { set exp_value($name) $upvar_variable } } } } } } } } } } ##### # # Put the variables into the export_set # ##### # We use an ns_set, because there may be more than one entry with the same name set export_set [ns_set create] foreach name [array names exp_precedence_type] { if { $exp_precedence_type($name) ne "exclude" } { if { [info exists exp_value($name)] } { if { [info exists exp_flag($name:array)] } { if { [info exists exp_flag($name:multiple)] } { foreach { key value } $exp_value($name) { foreach item $value { ns_set put $export_set "${name}.${key}" $item } } } else { foreach { key value } $exp_value($name) { ns_set put $export_set "${name}.${key}" $value } } if { [info exists exp_flag($name:sign)] } { # DRB: array get does not define the order in which elements are returned, # meaning that arrays constructed in different ways can have different # signatures unless we sort the returned list. I ran into this the # very first time I tried to sign an array passed to a page that used # ad_page_contract to verify the veracity of the parameter. ns_set put $export_set "$name:sig" [ad_sign [lsort $exp_value($name)]] } } else { if { [info exists exp_flag($name:multiple)] } { foreach item $exp_value($name) { ns_set put $export_set $name $item } } else { ns_set put $export_set $name "$exp_value($name)" } if { [info exists exp_flag($name:sign)] } { ns_set put $export_set "$name:sig" [ad_sign $exp_value($name)] } } } } } ##### # # Translate it into the appropriate format # ##### set export_size [ns_set size $export_set] set export_string {} if { $url_p } { set export_list [list] for { set i 0 } { $i < $export_size } { incr i } { lappend export_list "[ns_urlencode [ns_set key $export_set $i]]=[ns_urlencode [ns_set value $export_set $i]]" } set export_string [join $export_list "&"] } else { for { set i 0 } { $i < $export_size } { incr i } { append export_string "

    \n" } } if { $quotehtml_p } { set export_string [ad_quotehtml $export_string] } # Prepend with the base URL if { [exists_and_not_null base] } { if { $export_string ne "" } { if { [regexp {\?} $base] } { # The base already has query vars set export_string "${base}&${export_string}" } else { # The base has no query vars set export_string "$base?$export_string" } } else { set export_string $base } } # Append anchor if { [exists_and_not_null anchor] } { append export_string "\#$anchor" } return $export_string } ad_proc -deprecated ad_export_vars { -form:boolean {-exclude {}} {-override {}} {include {}} } { Note This proc is deprecated in favor of export_vars. They're very similar, but export_vars have a number of advantages:
    • It can sign variables (the the :sign flag)
    • It can export variables as a :multiple.
    • It can export arrays with on-the-fly values (not pulled from the environment)
    It doesn't have the foo(bar) syntax to pull a single value from an array, however, but you can do the same by saying export_vars {{foo.bar $foo(bar)}}.

    Helps export variables from one page to the next, either as URL variables or hidden form variables. It'll reach into arrays and grab either all values or individual values out and export them in a way that will be consistent with the ad_page_contract :array flag.

    Example:

    doc_body_append [ad_export_vars { msg_id user(email) { order_by date } }]
    will export the variable msg_id and the value email from the array user, and it will export a variable named order_by with the value date.

    The args is a list of variable names that you want exported. You can name

    • a scalar varaible, foo,
    • the name of an array, bar, in which case all the values in that array will get exported, or
    • an individual value in an array, bar(baz)
    • a list in [array get] format { name value name value ..}. The value will get substituted normally, so you can put a computation in there.

    A more involved example:

    set my_vars { msg_id user(email) order_by }
    doc_body_append [ad_export_vars -override { order_by $new_order_by } $my_vars]
    @param form set this parameter if you want the variables exported as hidden form variables, as opposed to URL variables, which is the default. @param exclude takes a list of names of variables you don't want exported, even though they might be listed in the args. The names take the same form as in the args list. @param override takes a list of the same format as args, which will get exported no matter what you have excluded. @author Lars Pind (lars@pinds.com) @creation-date 21 July 2000 @see export_vars } { #################### # # Build up an array of values to export # #################### array set export [list] set override_p 0 foreach argument { include override } { foreach arg [set $argument] { if { [llength $arg] == 1 } { if { $override_p || [lsearch -exact $exclude $arg] == -1 } { upvar $arg var if { [array exists var] } { # export the entire array foreach name [array names var] { if { $override_p || [lsearch -exact $exclude "${arg}($name)"] == -1 } { set export($arg.$name) $var($name) } } } elseif { [info exists var] } { if { $override_p || [lsearch -exact $exclude $arg] == -1 } { # if the var is part of an array, we'll translate the () into a dot. set left_paren [string first ( $arg] if { $left_paren == -1 } { set export($arg) $var } else { # convert the parenthesis into a dot before setting set export([string range $arg 0 [expr { $left_paren - 1}]].[string \ range $arg [expr { $left_paren + 1}] end-1]) $var } } } } } elseif { [llength $arg] %2 == 0 } { foreach { name value } $arg { if { $override_p || [lsearch -exact $exclude $name] == -1 } { set left_paren [string first ( $name] if { $left_paren == -1 } { set export($name) [lindex [uplevel list \[subst [list $value]\]] 0] } else { # convert the parenthesis into a dot before setting set export([string range $arg 0 [expr { $left_paren - 1}]].[string \ range $arg [expr { $left_paren + 1}] end-1]) \ [lindex [uplevel list \[subst [list $value]\]] 0] } } } } else { return -code error "All the exported values must have either one or an even number of elements" } } incr override_p } #################### # # Translate this into the desired output form # #################### if { !$form_p } { set export_list [list] foreach varname [array names export] { lappend export_list "[ns_urlencode $varname]=[ns_urlencode $export($varname)]" } return [join $export_list &] } else { set export_list [list] foreach varname [array names export] { lappend export_list "" } return [join $export_list \n] } } ad_proc -deprecated export_form_vars { -sign:boolean args } { Exports a number of variables as hidden input fields in a form. Specify a list of variable names. The proc will reach up in the caller's name space to grab the value of the variables. Variables that are not defined are silently ignored. You can append :multiple to the name of a variable. In this case, the value will be treated as a list, and each of the elements output separately.

    export_vars is now the prefered interface.

    Example usage: [export_form_vars -sign foo bar:multiple baz] @param sign If this flag is set, all the variables output will be signed using ad_sign. These variables should then be verified using the :verify flag to ad_page_contract, which in turn uses ad_verify_signature. This ensures that the value hasn't been tampered with at the user's end. @see export_vars } { set hidden "" foreach var_spec $args { set var_spec_pieces [split $var_spec ":"] set var [lindex $var_spec_pieces 0] set type [lindex $var_spec_pieces 1] upvar 1 $var value if { [info exists value] } { switch $type { multiple { foreach item $value { append hidden "\n" } } default { append hidden "\n" } } if { $sign_p } { append hidden "\n" } } } return $hidden } ad_proc -public export_entire_form {} { Exports everything in ns_getform to the ns_set. This should generally not be used. It's much better to explicitly name the variables you want to export. export_vars is now the prefered interface. @see export_vars } { set hidden "" set the_form [ns_getform] if { $the_form ne "" } { for {set i 0} {$i<[ns_set size $the_form]} {incr i} { set varname [ns_set key $the_form $i] set varvalue [ns_set value $the_form $i] append hidden "\n" } } return $hidden } ad_proc export_ns_set_vars {{format "url"} {exclusion_list ""} {setid ""}} { Returns all the params in an ns_set with the exception of those in exclusion_list. If no setid is provide, ns_getform is used. If format = url, a url parameter string will be returned. If format = form, a block of hidden form fragments will be returned. export_vars is now the prefered interface. @param format either url or form @param exclusion_list list of fields to exclude @param setid if null then it is ns_getform @see export_vars } { if { $setid eq "" } { set setid [ns_getform] } set return_list [list] if { $setid ne "" } { set set_size [ns_set size $setid] set set_counter_i 0 while { $set_counter_i<$set_size } { set name [ns_set key $setid $set_counter_i] set value [ns_set value $setid $set_counter_i] if {[lsearch $exclusion_list $name] == -1 && $name ne ""} { if {$format eq "url"} { lappend return_list "[ns_urlencode $name]=[ns_urlencode $value]" } else { lappend return_list " name=\"[ad_quotehtml $name]\" value=\"[ad_quotehtml $value]\"" } } incr set_counter_i } } if {$format eq "url"} { return [join $return_list "&"] } else { return "

    \n
    " } } ad_proc export_url_vars { -sign:boolean args } { export_vars is now the prefered interface. Returns a string of key=value pairs suitable for inclusion in a URL; you can pass it any number of variables as arguments. If any are defined in the caller's environment, they are included. See also export_entire_form_as_url_vars.

    Instead of naming a variable you can also say name=value. Note that the value here is not the name of a variable but the literal value you want to export e.g., export_url_vars [ns_urlencode foo]=[ns_urlencode $the_value].

    For normal variables, you can say export_url_vars foo:multiple. In this case, the value of foo will be treated as a Tcl list, and each value will be output separately e.g., foo=item0&foo=item1&foo=item2...

    You cannot combine the foo=bar syntax with the foo:multiple syntax. Why? Because there's no way we can distinguish between the :multiple being part of the value of foo or being a flag intended for export_url_vars. @param sign If this flag is set, all the variables output will be signed using ad_sign. These variables should then be verified using the :verify flag to ad_page_contract, which in turn uses ad_verify_signature. This ensures that the value hasn't been tampered with at the user's end. @see export_vars } { set params {} foreach var_spec $args { if { [string first "=" $var_spec] != -1 } { # There shouldn't be more than one equal sign, since the value should already be url-encoded. set var_spec_pieces [split $var_spec "="] set var [lindex $var_spec_pieces 0] set value [lindex $var_spec_pieces 1] lappend params "$var=$value" if { $sign_p } { lappend params "[ns_urlencode [ns_urldecode $var]:sig]=[ns_urlencode [ad_sign [ns_urldecode $value]]]" } } else { set var_spec_pieces [split $var_spec ":"] set var [lindex $var_spec_pieces 0] set type [lindex $var_spec_pieces 1] upvar 1 $var upvar_value if { [info exists upvar_value] } { switch $type { multiple { foreach item $upvar_value { lappend params "[ns_urlencode $var]=[ns_urlencode $item]" } } default { lappend params "[ns_urlencode $var]=[ns_urlencode $upvar_value]" } } if { $sign_p } { lappend params "[ns_urlencode "$var:sig"]=[ns_urlencode [ad_sign $upvar_value]]" } } } } return [join $params "&"] } ad_proc -public export_entire_form_as_url_vars { {vars_to_passthrough ""} } { export_vars is now the prefered interface. Returns a URL parameter string of name-value pairs of all the form parameters passed to this page. If vars_to_passthrough is given, it should be a list of parameter names that will be the only ones passed through. @see export_vars } { set params [list] set the_form [ns_getform] if { $the_form ne "" } { for {set i 0} {$i<[ns_set size $the_form]} {incr i} { set varname [ns_set key $the_form $i] set varvalue [ns_set value $the_form $i] if { $vars_to_passthrough eq "" || ([lsearch -exact $vars_to_passthrough $varname] != -1) } { lappend params "[ns_urlencode $varname]=[ns_urlencode $varvalue]" } } return [join $params "&"] } } ad_proc -public util_get_current_url {} { Returns a URL for re-issuing the current request, with query variables. If a form submission is present, that is converted into query vars as well. @return URL for the current page @author Lars Pind (lars@pinds.com) @creation-date February 11, 2003 } { set url [ad_conn url] set query [ns_getform] if { $query ne "" } { append url "?[export_entire_form_as_url_vars]" } return $url } ad_proc -public with_catch {error_var body on_error} { execute code in body with the catch errorMessage in error_var and if there is a non-zero return code from body execute the on_error block. } { upvar 1 $error_var $error_var global errorInfo errorCode if { [catch { uplevel $body } $error_var] } { set code [catch {uplevel $on_error} string] # Return out of the caller appropriately. if { $code == 1 } { return -code error -errorinfo $errorInfo -errorcode $errorCode $string } elseif { $code == 2 } { return -code return $string } elseif { $code == 3 } { return -code break } elseif { $code == 4 } { return -code continue } elseif { $code > 4 } { return -code $code $string } } } # putting commas into numbers (thank you, Michael Bryzek) ad_proc -public util_commify_number { num } { Returns the number with commas inserted where appropriate. Number can be positive or negative and can have a decimal point. e.g. -1465.98 => -1,465.98 } { while { 1 } { # Regular Expression taken from Mastering Regular Expressions (Jeff Friedl) # matches optional leading negative sign plus any # other 3 digits, starting from end if { ![regsub -- {^(-?[0-9]+)([0-9][0-9][0-9])} $num {\1,\2} num] } { break } } return $num } ad_proc -public util_search_list_of_lists {list_of_lists query_string {sublist_element_pos 0}} { Returns position of sublist that contains QUERY_STRING at SUBLIST_ELEMENT_POS. } { set sublist_index 0 foreach sublist $list_of_lists { set comparison_element [lindex $sublist $sublist_element_pos] if { $query_string eq $comparison_element } { return $sublist_index } incr sublist_index } # didn't find it return -1 } # --- network stuff ad_proc -public util_get_http_status {url {use_get_p 1} {timeout 30}} { Returns the HTTP status code, e.g., 200 for a normal response or 500 for an error, of a URL. By default this uses the GET method instead of HEAD since not all servers will respond properly to a HEAD request even when the URL is perfectly valid. Note that this means AOLserver may be sucking down a lot of bits that it doesn't need. } { if {$use_get_p} { set http [ns_httpopen GET $url "" $timeout] } else { set http [ns_httpopen HEAD $url "" $timeout] } set rfd [lindex $http 0] set wfd [lindex $http 1] close $rfd close $wfd set headers [lindex $http 2] set response [ns_set name $headers] set status [lindex $response 1] ns_set free $headers return $status } ad_proc -public util_link_responding_p { url {list_of_bad_codes "404"} } { Returns 1 if the URL is responding (generally we think that anything other than 404 (not found) is okay). @see util_get_http_status } { if { [catch { set status [util_get_http_status $url] } errmsg] } { # got an error; definitely not valid return 0 } else { # we got the page but it might have been a 404 or something if { [lsearch $list_of_bad_codes $status] != -1 } { return 0 } else { return 1 } } } # system by Tracy Adams (teadams@arsdigita.com) to permit AOLserver to POST # to another Web server; sort of like ns_httpget ad_proc -public util_httpopen { method url {rqset ""} {timeout 30} {http_referer ""} } { Like ns_httpopen but works for POST as well; called by util_httppost } { if { ![string match "http://*" $url] } { return -code error "Invalid url \"$url\": _httpopen only supports HTTP" } set url [split $url /] set hp [split [lindex $url 2] :] set host [lindex $hp 0] set port [lindex $hp 1] if { [string match $port ""] } {set port 80} set uri /[join [lrange $url 3 end] /] set fds [ns_sockopen -nonblock $host $port] set rfd [lindex $fds 0] set wfd [lindex $fds 1] if { [catch { _ns_http_puts $timeout $wfd "$method $uri HTTP/1.0\r" _ns_http_puts $timeout $wfd "Host: $host\r" if {$rqset ne ""} { for {set i 0} {$i < [ns_set size $rqset]} {incr i} { _ns_http_puts $timeout $wfd \ "[ns_set key $rqset $i]: [ns_set value $rqset $i]\r" } } else { _ns_http_puts $timeout $wfd \ "Accept: */*\r" _ns_http_puts $timeout $wfd "User-Agent: Mozilla/1.01 \[en\] (Win95; I)\r" _ns_http_puts $timeout $wfd "Referer: $http_referer \r" } } errMsg] } { global errorInfo #close $wfd #close $rfd if { [info exists rpset] } {ns_set free $rpset} return -1 } return [list $rfd $wfd ""] } # httppost; give it a URL and a string with formvars, and it # returns the page as a Tcl string # formvars are the posted variables in the following form: # arg1=value1&arg2=value2 # in the event of an error or timeout, -1 is returned ad_proc -public util_httppost {url formvars {timeout 30} {depth 0} {http_referer ""}} { Returns the result of POSTing to another Web server or -1 if there is an error or timeout. formvars should be in the form \"arg1=value1&arg2=value2\".

    post is encoded as application/x-www-form-urlencoded. See util_http_file_upload for file uploads via post (encoded multipart/form-data).

    @see util_http_file_upload } { if { [catch { if {[incr depth] > 10} { return -code error "util_httppost: Recursive redirection: $url" } set http [util_httpopen POST $url "" $timeout $http_referer] set rfd [lindex $http 0] set wfd [lindex $http 1] #headers necesary for a post and the form variables _ns_http_puts $timeout $wfd "Content-type: application/x-www-form-urlencoded \r" _ns_http_puts $timeout $wfd "Content-length: [string length $formvars]\r" _ns_http_puts $timeout $wfd \r _ns_http_puts $timeout $wfd "$formvars\r" flush $wfd close $wfd set rpset [ns_set new [_ns_http_gets $timeout $rfd]] while 1 { set line [_ns_http_gets $timeout $rfd] if { ![string length $line] } break ns_parseheader $rpset $line } set headers $rpset set response [ns_set name $headers] set status [lindex $response 1] if {$status == 302} { set location [ns_set iget $headers location] if {$location ne ""} { ns_set free $headers close $rfd return [util_httpget $location {} $timeout $depth] } } set length [ns_set iget $headers content-length] if { "" eq $length } {set length -1} set type [ns_set iget $headers content-type] set_encoding $type $rfd set err [catch { while 1 { set buf [_ns_http_read $timeout $rfd $length] append page $buf if { "" eq $buf } break if {$length > 0} { incr length -[string length $buf] if {$length <= 0} break } } } errMsg] ns_set free $headers close $rfd if {$err} { global errorInfo return -code error -errorinfo $errorInfo $errMsg } } errmgs ] } {return -1} return $page } ad_proc -public util_report_successful_library_load {{extra_message ""}} { Should be called at end of private Tcl library files so that it is easy to see in the error log whether or not private Tcl library files contain errors. } { set tentative_path [info script] regsub -all {/\./} $tentative_path {/} scrubbed_path if { $extra_message eq "" } { set message "Done... $scrubbed_path" } else { set message "Done... $scrubbed_path; $extra_message" } ns_log Notice $message } ad_proc -public exists_and_not_null { varname } { Returns 1 if the variable name exists in the caller's environment and is not the empty string. Note you should enter the variable name, and not the variable value (varname not $varname which will pass variable varnames value into this function). } { upvar 1 $varname var return [expr { [info exists var] && $var ne "" }] } ad_proc -public exists_or_null { varname } { Returns the contents of the variable if it exists, otherwise returns empty string } { upvar 1 $varname var if {[info exists var]} { return $var } return "" } ad_proc -public exists_and_equal { varname value } { Returns 1 if the variable name exists in the caller's envirnoment and is equal to the given value. @see exists_and_not_null @author Peter Marklund } { upvar 1 $varname var return [expr { [info exists var] && $var eq $value } ] } ad_proc -private set_encoding { {-text_translation {auto binary}} content_type channel } {

    The ad_http* and util_http* machineries depend on the AOLserver/NaviServer socket I/O layer provided by [ns_sockopen]. This proc allows you to request Tcl encoding filtering for ns_sockopen channels (i.e., the read and write channels return by [ns_sockopen]), to be applied right before performing socket I/O operations (i.e., reads).

    The major task is to resolve the corresponding Tcl encoding (e.g.: ascii) for a given IANA/MIME charset name (or alias; e.g.: US-ASCII); the main resolution scheme is implemented by [ns_encodingfortype] which is available bother under AOLserver and NaviServer (see tcl/charsets.tcl). The mappings between Tcl encoding names (as shown by [encoding names]) and IANA/MIME charset names (i.e., names and aliases in the sense of IANA's charater sets registry) is provided by:

    • A static, built-in correspondence map: see nsd/encoding.c
    • An extensible correspondence map (i.e., the ns/charsets section in config.tcl).

    [ns_encodingfortype] introduces several levels of precedence when resolving the actual IANA/MIME charset and the corresponding Tcl encoding to use:

    1. The "content_type" string contains a charset specification, e.g.: "text/xml; charset=UTF-8". This spec fragment takes the highest precedence.
    2. The "content_type" string points to a "text/*" media subtype, but does not specify a charset (e.g., "text/xml"). In this case, the charset defined by ns/parameters/OutputCharset (see config.tcl) applies. If this parameter is missing, the default is "iso-8859-1" (see tcl/charsets.tcl; this follows from RFC 2616 (HTTP 1.1); Section 3.7.1).
    3. If neither case 1 or case 2 become effective, the encoding is resolved to "binary".
    4. If [ns_encodingfortype] fails to resolve any Tcl encoding name (i.e., returns an empty string), the general fallback is "iso8859-1" for text/* media subtypes and "binary" for any other. This is the case in two situations:
      • Invalid IANA/MIME charsets: The name in the "charset" parameter of the content type spec is not a valid name or alias in IANA's charater sets registry (a special variant would be an empty charset value, e.g. "text/plain; charset=")
      • Unknown IANA/MIME charsets: The name in the "charset" parameter of the content type spec does not match any known (= registered) IANA/MIME charset in the MIME/Tcl mappings.
    References: @author stefan.sobernig@wu.ac.at } { set trl [expr {[string match "text/*" $content_type] ? $text_translation : "binary"}] set enc [ns_encodingfortype $content_type] if {$enc eq ""} { set enc [expr {[string match "text/*" $content_type] ? "iso8859-1" : "binary"}] ns_log debug "--- Resolving a Tcl encoding for the CONTENT-TYPE '$content_type' failed; falling back to '$enc'." } fconfigure $channel -translation $trl -encoding $enc } ad_proc -public ad_httpget { -url {-headers ""} {-timeout 30} {-depth 0} } { Just like ns_httpget, but first headers is an ns_set of headers to send during the fetch. ad_httpget also makes use of Conditional GETs (if called with a Last-Modified header). Returns the data in array get form with array elements page status modified. } { ns_log debug "Getting {$url} {$headers} {$timeout} {$depth}" if {[incr depth] > 10} { return -code error "ad_httpget: Recursive redirection: $url" } set http [ns_httpopen GET $url $headers $timeout] set rfd [lindex $http 0] close [lindex $http 1] set headers [lindex $http 2] set response [ns_set name $headers] set status [lindex $response 1] set last_modified [ns_set iget $headers last-modified] if {$status == 302 || $status == 301} { set location [ns_set iget $headers location] if {$location ne ""} { ns_set free $headers close $rfd return [ad_httpget -url $location -timeout $timeout -depth $depth] } } elseif { $status == 304 } { # The requested variant has not been modified since the time specified # A conditional get didn't return anything. return an empty page and set page {} ns_set free $headers close $rfd } else { set length [ns_set iget $headers content-length] if { $length eq "" } {set length -1} set type [ns_set iget $headers content-type] set_encoding $type $rfd set err [catch { while 1 { set buf [_ns_http_read $timeout $rfd $length] append page $buf if { "" eq $buf } break if {$length > 0} { incr length -[string length $buf] if {$length <= 0} break } } } errMsg] ns_set free $headers close $rfd if {$err} { global errorInfo return -code error -errorinfo $errorInfo $errMsg } } # order matters here since we depend on page content # being element 1 in this list in util_httpget return [list page $page \ status $status \ modified $last_modified] } ad_proc -public util_httpget { url {headers ""} {timeout 30} {depth 0} } { util_httpget simply calls ad_httpget which also returns status and last_modfied @see ad_httpget } { return [lindex [ad_httpget -url $url -headers $headers -timeout $timeout -depth $depth] 1] } # some procs to make it easier to deal with CSV files (reading and writing) # added by philg@mit.edu on October 30, 1999 ad_proc util_escape_quotes_for_csv {string} "Returns its argument with double quote replaced by backslash double quote" { regsub -all \" $string {\"} result return $result } ad_proc -deprecated validate_integer {field_name string} { Throws an error if the string isn't a decimal integer; otherwise strips any leading zeros (so this won't work for octals) and returns the result.

    validate via ad_page_contract @see ad_page_contract } { if { ![regexp {^[0-9]+$} $string] } { error "$field_name is not an integer" } # trim leading zeros, so as not to confuse Tcl set string [string trimleft $string "0"] if { $string eq "" } { # but not all of the zeros return "0" } return $string } ad_proc -deprecated validate_zip_code {field_name zip_string country_code} { Given a string, signals an error if it's not a legal zip code

    validate via ad_page_contract @see ad_page_contract } { if { $country_code eq "" || [string toupper $country_code] eq "US" } { if { [regexp {^[0-9][0-9][0-9][0-9][0-9](-[0-9][0-9][0-9][0-9])?$} $zip_string] } { set zip_5 [string range $zip_string 0 4] if { ![db_0or1row zip_code_exists { select 1 from dual where exists (select 1 from zip_codes where zip_code like :zip_5) }] } { error "The entry for $field_name, \"$zip_string\" is not a recognized zip code" } } else { error "The entry for $field_name, \"$zip_string\" does not look like a zip code" } } else { if { $zip_string ne "" } { error "Zip code is not needed outside the US" } } return $zip_string } ad_proc -deprecated validate_ad_dateentrywidget {field_name column form {allow_null 0}} {

    validate via ad_page_contract @see ad_page_contract } { set col $column set day [ns_set get $form "$col.day"] ns_set update $form "$col.day" [string trimleft $day "0"] set month [ns_set get $form "$col.month"] set year [ns_set get $form "$col.year"] # check that either all elements are blank # date value is formated correctly for ns_dbformvalue if { [empty_string_p "$day$month$year"] } { if { $allow_null == 0 } { error "$field_name must be supplied" } else { return "" } } elseif { $year ne "" && [string length $year] != 4 } { error "The year must contain 4 digits." } elseif { [catch { ns_dbformvalue $form $column date date } errmsg ] } { error "The entry for $field_name had a problem: $errmsg." } return $date } ad_proc -private util_WriteWithExtraOutputHeaders {headers_so_far {first_part_of_page ""}} { Takes in a string of headers to write to an HTTP connection, terminated by a newline. Checks \[ad_conn outputheaders\] and adds those headers if appropriate. Adds two newlines at the end and writes out to the connection. May optionally be used to write the first part of the page as well (saves a packet). } { ns_set put [ad_conn outputheaders] Server "[ns_info name]/[ns_info version]" set set_headers_i 0 set set_headers_limit [ns_set size [ad_conn outputheaders]] while {$set_headers_i < $set_headers_limit} { append headers_so_far "[ns_set key [ad_conn outputheaders] $set_headers_i]: [ns_set value [ad_conn outputheaders] $set_headers_i]\r\n" incr set_headers_i } append entire_string_to_write $headers_so_far "\r\n" $first_part_of_page ns_write $entire_string_to_write } ad_proc -public ReturnHeaders {{content_type text/html}} { We use this when we want to send out just the headers and then do incremental writes with ns_write. This way the user doesn't have to wait for streamed output (useful when doing bulk uploads, installs, etc.). It returns status 200 and all headers including any added to outputheaders. } { if {[string match "text/*" $content_type] && ![string match *charset=* $content_type]} { append content_type "; charset=[ns_config ns/parameters OutputCharset iso-8859-1]" } if {[ns_info name] eq "NaviServer"} { ns_headers 200 $content_type } else { set all_the_headers "HTTP/1.0 200 OK MIME-Version: 1.0 Content-Type: $content_type\r\n" util_WriteWithExtraOutputHeaders $all_the_headers if {[string match "text/*" $content_type]} { ns_startcontent -type $content_type } else { ns_startcontent } } } ad_proc -public ad_return_top_of_page {first_part_of_page {content_type text/html}} { Returns HTTP headers plus the top of the user-visible page. } { ReturnHeaders $content_type if { $first_part_of_page ne "" } { ns_write $first_part_of_page } } ad_proc -public ad_apply {func arglist} { Evaluates the first argument with ARGLIST as its arguments, in the environment of its caller. Analogous to the Lisp function of the same name. } { set func_and_args [concat $func $arglist] return [uplevel $func_and_args] } ad_proc -public safe_eval args { Version of eval that checks its arguments for brackets that may be used to execute unsafe code. } { foreach arg $args { if { [regexp {[\[;]} $arg] } { return -code error "Unsafe argument to safe_eval: $arg" } } return [ad_apply uplevel $args] } ad_proc -public lmap {list proc_name} { Applies proc_name to each item of the list, appending the result of each call to a new list that is the return value. } { set lmap [list] foreach item $list { lappend lmap [safe_eval $proc_name $item] } return $lmap } ad_proc -public ad_decode { args } { this procedure is analogus to sql decode procedure. first parameter is the value we want to decode. this parameter is followed by a list of pairs where first element in the pair is convert from value and second element is convert to value. last value is default value, which will be returned in the case convert from values matches the given value to be decoded } { set num_args [llength $args] set input_value [lindex $args 0] set counter 1 while { $counter < [expr {$num_args - 2}] } { lappend from_list [lindex $args $counter] incr counter lappend to_list [lindex $args $counter] incr counter } set default_value [lindex $args $counter] if { $counter < 2 } { return $default_value } set index [lsearch -exact $from_list $input_value] if { $index < 0 } { return $default_value } else { return [lindex $to_list $index] } } ad_proc -public ad_urlencode { string } { same as ns_urlencode except that dash and underscore are left unencoded. } { set encoded_string [ns_urlencode $string] regsub -all {%2d} $encoded_string {-} encoded_string regsub -all {%5f} $encoded_string {_} ad_encoded_string return $ad_encoded_string } ad_proc -public ad_get_cookie { { -include_set_cookies t } name { default "" } } { Returns the value of a cookie, or $default if none exists. } { if { $include_set_cookies eq "t" } { set headers [ad_conn outputheaders] for { set i 0 } { $i < [ns_set size $headers] } { incr i } { if { ![string compare [string tolower [ns_set key $headers $i]] "set-cookie"] && \ [regexp "^$name=(\[^;\]*)" [ns_set value $headers $i] "" "value"] } { return $value } } } set headers [ad_conn headers] set cookie [ns_set iget $headers Cookie] if { [regexp " $name=(\[^;\]*)" " $cookie" match value] } { # If the cookie was set to a blank value we actually stored two quotes. We need # to undo the kludge on the way out. if { $value eq "\"\"" } { set value "" } return $value } return $default } ad_proc -public ad_set_cookie { { -replace f -secure f -expire f -max_age "" -domain "" -path "/" -discard f } name {value ""} } { Sets a cookie. @param max_age specifies the maximum age of the cookies in seconds (consistent with RFC 2109). max_age inf specifies cookies that never expire. The default behavior is to issue session cookies. @param expire specifies whether we should expire (clear) the cookie. Setting Max-Age to zero ought to do this, but it doesn't in some browsers (tested on IE 6). @param path specifies a subset of URLs to which this cookie applies. It must be a prefix of the URL being accessed. @param domain specifies the domain(s) to which this cookie applies. See RFC2109 for the semantics of this cookie attribute. @param secure specifies to the user agent that the cookie should only be transmitted back to the server of secure transport. @param replace forces the current output headers to be checked for the same cookie. If the same cookie is set for a second time without the replace option being specified, the client will receive both copies of the cookie. @param discard instructs the user agent to discard the cookie when when the user agent terminates. @param value is autmatically URL encoded. @see ad_get_cookie } { set headers [ad_conn outputheaders] if { $replace ne "f" } { # Try to find an already-set cookie named $name. for { set i 0 } { $i < [ns_set size $headers] } { incr i } { if { ![string compare [string tolower [ns_set key $headers $i]] "set-cookie"] && \ [regexp "^$name=" [ns_set value $headers $i]] } { ns_set delete $headers $i } } } # need to set some value, so we put "" as the cookie value if { $value eq "" } { set cookie "$name=\"\"" } else { set cookie "$name=$value" } if { $path ne "" } { append cookie "; Path=$path" } if { $discard ne "f" } { append cookie "; Discard" } elseif { $max_age eq "inf" } { if { $expire ne "t" } { # netscape seemed unhappy with huge max-age, so we use # expires which seems to work on both netscape and IE append cookie "; Expires=Mon, 01-Jan-2035 01:00:00 GMT" } } elseif { $max_age ne "" } { append cookie "; Max-Age=$max_age; Expires=[util::cookietime [expr {[ns_time] + $max_age}]]" } if {$expire eq "t"} { append cookie "; Expires=Tue, 01-Jan-1980 01:00:00 GMT" } if { $domain ne "" } { append cookie "; Domain=$domain" } if { $secure ne "f" } { append cookie "; Secure" } ns_log Debug "OACS Set-Cookie: $cookie" ns_set put $headers "Set-Cookie" $cookie } ad_proc -private ad_run_scheduled_proc { proc_info } { Runs a scheduled procedure and updates monitoring information in the shared variables. } { if {[ns_info name] eq "NaviServer"} { set proc_info [lindex $proc_info 0] } # Grab information about the scheduled procedure. set thread [lindex $proc_info 0] set once [lindex $proc_info 1] set interval [lindex $proc_info 2] set proc [lindex $proc_info 3] set args [lindex $proc_info 4] set time [lindex $proc_info 5] set count 0 set debug [lindex $proc_info 7] ns_mutex lock [nsv_get ad_procs mutex] set procs [nsv_get ad_procs .] # Find the entry in the shared variable. Splice it out. for { set i 0 } { $i < [llength $procs] } { incr i } { set other_proc_info [lindex $procs $i] for { set j 0 } { $j < 5 } { incr j } { if { [lindex $proc_info $j] != [lindex $other_proc_info $j] } { break } } if { $j == 5 } { set count [lindex $other_proc_info 6] set procs [lreplace $procs $i $i] break } } if { $once eq "f" } { # The proc will run again - readd it to the shared variable (updating ns_time and # incrementing the count). lappend procs [list $thread $once $interval $proc $args [ns_time] [expr { $count + 1 }] $debug] } nsv_set ad_procs . $procs ns_mutex unlock [nsv_get ad_procs mutex] ns_log debug "Running scheduled proc $proc..." # Actually run the procedure. eval [concat [list $proc] $args] ns_log debug "Done running scheduled proc $proc." } # Initialize NSVs for ad_schedule_proc. if { [apm_first_time_loading_p] } { nsv_set ad_procs mutex [ns_mutex create oacs:sched_procs] nsv_set ad_procs . "" } ad_proc -public ad_schedule_proc { { -thread f -once f -debug f -all_servers f -schedule_proc "" } interval proc args } { Replacement for ns_schedule_proc and friends, allowing us to track what's going on. Can be monitored via /admin/monitoring/schedule-procs.tcl. The procedure defaults to run on only the canonical server unless the all_servers flag is set to true. @param thread t/f If true run scheduled proc in its own thread @param once t/f. If true only run the scheduled proc once @param debug t/f If true log debugging information @param all_servers If true run on all servers in a cluster @param schedule_proc ns_schedule_daily, ns_schedule_weekly or blank @param interval If schedule_proc is empty, the interval to run the proc in seconds, otherwise a list of interval arguments to pass to ns_schedule_daily or ns_schedule_weekly @param proc The proc to schedule @param args And the args to pass it } { # we don't schedule a proc to run if we have enabled server clustering, # we're not the canonical server, and the procedure was not requested to run on all servers. if { [server_cluster_enabled_p] && ![ad_canonical_server_p] && $all_servers eq "f" } { return } # Protect the list of scheduled procs with a mutex. ns_mutex lock [nsv_get ad_procs mutex] set proc_info [list $thread $once $interval $proc $args [ns_time] 0 $debug] ns_log debug "Scheduling proc $proc" # Add to the list of scheduled procedures, for monitoring. set procs [nsv_get ad_procs .] lappend procs $proc_info nsv_set ad_procs . $procs ns_mutex unlock [nsv_get ad_procs mutex] set my_args [list] if { $thread eq "t" } { lappend my_args "-thread" } if { $once eq "t" } { lappend my_args "-once" } # Schedule the wrapper procedure (ad_run_scheduled_proc). if { $schedule_proc eq "" } { eval [concat [list ns_schedule_proc] $my_args [list $interval ad_run_scheduled_proc [list $proc_info]]] } else { eval [concat [list $schedule_proc] $my_args $interval [list ad_run_scheduled_proc [list $proc_info]]] } } ad_proc util_ReturnMetaRefresh { url { seconds_delay 0 } } { Ugly workaround to deal with IE5.0 bug handling multipart/form-data using Meta Refresh page instead of a redirect. } { ReturnHeaders ns_write "

    Loading...

    If your browser does not automatically redirect you, please click here. " } # Brad Duell (bduell@ncacasi.org) 07/10/2003 # User session variables, then redirect ad_proc -public ad_cache_returnredirect { url { persistent "f" } { excluded_vars "" } } { An addition to ad_returnredirect. It caches all variables in the redirect except those in excluded_vars and then calls ad_returnredirect with the resultant string. @author Brad Duell (bduell@ncacasi.org) } { util_memoize_flush_regexp [list [ad_conn session_id] [ad_conn package_id]] set url_list [split $url "?"] set url [lindex $url_list 0] set vars [lindex $url_list 1] set excluded_vars_list "" set excluded_vars_url "" for { set i 0 } { $i < [llength $excluded_vars] } { incr i } { set item [lindex [lindex $excluded_vars $i] 0] set value [lindex [lindex $excluded_vars $i] 1] if { $value eq "" } { # Obtain value from adp level upvar #[template::adp_level] __item item_reference set item_reference $item upvar #[template::adp_level] __value value_reference uplevel #[template::adp_level] {set __value [expr {$$__item}]} set value $value_reference } lappend excluded_vars_list $item if { $value ne "" } { # Value provided if { $excluded_vars_url ne "" } { append excluded_vars_url "&" } append excluded_vars_url [export_vars -url [list [list "$item" "$value"]]] } } set saved_list "" if { $vars ne "" } { foreach item_value [split $vars "&"] { set item_value_pair [split $item_value "="] set item [lindex $item_value_pair 0] set value [ns_urldecode [lindex $item_value_pair 1]] if { [lsearch -exact $excluded_vars_list $item] == -1 } { # No need to save the value if it's being passed ... if { [lsearch -exact $saved_list $item] != -1 } { # Allows for multiple values ... append value " [ad_get_client_property [ad_conn package_id] $item]" } else { # We'll keep track of who we've saved for this package ... lappend saved_list $item } ad_set_client_property -persistent $persistent [ad_conn package_id] $item $value } } } ad_returnredirect "$url?$excluded_vars_url" } # branimir 2000/04/25 ad_returnredirect and helper procs : # util_complete_url_p util_absolute_path_p util_current_location # util_current_directory # See: http://rhea.redhat.com/bboard-archive/acs_design/0003eV.html ad_proc -public ad_returnredirect { {-message {}} {-html:boolean} {-allow_complete_url:boolean} target_url } { Write the HTTP response required to get the browser to redirect to a different page, to the current connection. This does not cause execution of the current page, including serving an ADP file, to stop. If you want to stop execution of the page, you should call ad_script_abort immediately following this call.

    This proc is a replacement for ns_returnredirect, but improved in two important respects:

    • When the supplied target_url isn't complete, (e.g. /foo/bar.tcl or foo.tcl) the prepended location part is constructed by looking at the HTTP 1.1 Host header.
    • If an URL relative to the current directory is supplied (e.g. foo.tcl) it prepends location and directory.
    @param message A message to display to the user. See util_user_message. @param html Set this flag if your message contains HTML. If specified, you're responsible for proper quoting of everything in your message. Otherwise, we quote it for you. @param allow_complete_url By default we disallow redirecting to urls outside the current host. This is based on the currently set host header or the host name in the config file if there is no host header. Set allow_complete_url if you are redirecting to a known safe external web site. This prevents redirecting to a site by URL query hacking. @see util_user_message @see ad_script_abort } { if { [string is false $html_p] } { util_user_message -message $message } else { util_user_message -message $message -html } if { [util_complete_url_p $target_url] } { # http://myserver.com/foo/bar.tcl style - just pass to ns_returnredirect # check if the hostname matches the current host if {[util::external_url_p $target_url] && !$allow_complete_url_p} { error "Redirection to external hosts is not allowed." } set url $target_url } elseif { [util_absolute_path_p $target_url] } { # /foo/bar.tcl style - prepend the current location: set url [util_current_location]$target_url } else { # URL is relative to current directory. if {$target_url eq "."} { set url [util_current_location][util_current_directory] } else { set url [util_current_location][util_current_directory]$target_url } } #Ugly workaround to deal with IE5.0 bug handling multipart/form-data using #Meta Refresh page instead of a redirect. # jbank@arsdigita.com 6/7/2000 set use_metarefresh_p 0 set type [ns_set iget [ad_conn headers] content-type] if { [string match *multipart/form-data* [string tolower $type]] } { set user_agent [ns_set get [ad_conn headers] User-Agent] set use_metarefresh_p [regexp -nocase "msie 5.0" $user_agent match] } if {[string match "https://*" [ad_conn location]] && [string match "http://*" $url]} { # workaround the You are about to be redirected to a connection that # is not secure bug in IE set use_metarefresh_p 1 } if { $use_metarefresh_p != 0 } { util_ReturnMetaRefresh $url } else { ns_returnredirect $url } } ad_proc -public util_user_message { {-replace:boolean} {-html:boolean} {-message {}} } { Sets a message to be displayed on the next page request. @param message The message to display. @param replace Set this if you want to replace existing messages. Default behavior is to append to a list of messages. @param html Set this flag if your message contains HTML. If specified, you're responsible for proper quoting of everything in your message. Otherwise, we quote it for you. @see util_get_user_messages } { if { $message ne "" } { if { [string is false $html_p] } { set message [ad_quotehtml $message] } if { !$replace_p } { set new_messages [ad_get_client_property -default {} -cache_only t "acs-kernel" "general_messages"] lappend new_messages $message } else { set new_messages [list $message] } ad_set_client_property "acs-kernel" "general_messages" $new_messages } elseif { $replace_p } { ad_set_client_property "acs-kernel" "general_messages" {} } } ad_proc -public util_get_user_messages { {-keep:boolean} {-multirow:required} } { Gets and clears the message to be displayed on the next page load. @param multirow Name of a multirow in the current template namespace where you want the user messages set. The multirow will have one column, which is 'message'. @param keep If set, then we will not clear the list of messages after getting them. Normal behavior is to clear them, so we only display the same messages once. @see util_user_message } { set messages [ad_get_client_property -default {} -cache_only t "acs-kernel" "general_messages"] if { !$keep_p && $messages ne "" } { ad_set_client_property "acs-kernel" "general_messages" {} } template::multirow create $multirow message foreach message $messages { template::multirow append $multirow $message } } ad_proc -public util_complete_url_p {{} string} { Determine whether string is a complete URL, i.e. wheteher it begins with protocol: where protocol consists of letters only. } { if {[regexp -nocase {^[a-z]+:} $string]} { return 1 } else { return 0 } } ad_proc -public util_absolute_path_p {{} path} { Check whether the path begins with a slash } { set firstchar [string index $path 0] if {$firstchar ne "/" } { return 0 } else { return 1 } } ad_proc -public util_driver_info { {-array:required} {-driver ""} } { Returns the protocol and port for the specified driver. @param driver the driver to query (defaults to [ad_conn driver]) @param array the array to populate with proto and port } { upvar $array result if {$driver eq ""} { set driver [ad_conn driver] } switch $driver { nssock { set result(proto) http set result(port) [ns_config -int "ns/server/[ns_info server]/module/nssock" Port] } nsunix { set result(proto) http set result(port) {} } nsssl - nsssle { set result(port) [ns_config -int "ns/server/[ns_info server]/module/[ad_conn driver]" Port] set result(proto) https } nsopenssl { set result(port) [ns_config -int "ns/server/[ns_info server]/module/[ad_conn driver]" ServerPort] set result(proto) https } default { ns_log Error "Unknown driver: [ad_conn driver]. Only know nssock, nsunix, nsssl, nsssle, nsopenssl" set result(port) [ns_config -int "ns/server/[ns_info server]/module/nssock" Port] set result(proto) http } } } ad_proc -public util_current_location {{}} { Like ad_conn location - Returns the location string of the current request in the form protocol://hostname[:port] but it looks at the Host header, that is, takes into account the host name the client used although it may be different from the host name from the server configuration file. If the Host header is missing or empty util_current_location falls back to ad_conn location. cro@ncacasi.org 2002-06-07 Note: IE fouls up the Host header if a server is on a non-standard port; it does not change the port number when redirecting to https. So we would get redirects from http://some-host:8000 to https://some-host:8000 @author Lars Pind (lars@collaboraid.biz) @author Peter Marklund } { set default_port(http) 80 set default_port(https) 443 util_driver_info -array driver set proto $driver(proto) set port $driver(port) # This is the host from the browser's HTTP request set Host [ns_set iget [ad_conn headers] Host] set Hostv [split $Host ":"] set Host_hostname [lindex $Hostv 0] set Host_port [lindex $Hostv 1] # suppress the configured http port when server is behind a proxy, to keep connection behind proxy set suppress_port [parameter::get -package_id [apm_package_id_from_key acs-tcl] -parameter SuppressHttpPort -default 0] if { $suppress_port && [string equal $port [ns_config -int "ns/server/[ns_info server]/module/nssock" Port]] } { ns_log Debug "util_current_location: suppressing http port $Host_port" set Host_port "" set port "" } # Server config location if { ![regexp {^([a-z]+://)?([^:]+)(:[0-9]*)?$} [ad_conn location] match location_proto location_hostname location_port] } { ns_log Error "util_current_location couldn't regexp '[ad_conn location]'" } if { $Host eq "" } { # No Host header, return protocol from driver, hostname from [ad_conn location], and port from driver set hostname $location_hostname } else { set hostname $Host_hostname if { $Host_port ne "" } { set port $Host_port } } if { $port ne "" && $port ne $default_port($proto) } { return "$proto://$hostname:$port" } else { return "$proto://$hostname" } } ad_proc -public util_current_directory {{}} { Returns the directory of the current URL.

    We can't just use [file dirname [ad_conn url]] because we want /foo/bar/ to return /foo/bar/ and not /foo .

    Also, we want to return directory WITH the trailing slash so that programs that use this proc don't have to treat the root directory as a special case. } { set path [ad_conn url] set lastchar [string range $path [expr {[string length $path]-1}] end] if {$lastchar eq "/" } { return $path } else { set file_dirname [file dirname $path] # Treat the case of the root directory special if {$file_dirname eq "/" } { return / } else { return $file_dirname/ } } } ad_proc -public ad_call_proc_if_exists { proc args } { Calls a procedure with particular arguments, only if the procedure is defined. } { if { [llength [info procs $proc]] == 1 } { eval $proc $args } } ad_proc -public ad_get_tcl_call_stack { {level -2} } { Returns a stack trace from where the caller was called. See also ad_print_stack_trace which generates a more readable stack trace at the expense of truncating args. @param level The level to start from, relative to this proc. Defaults to -2, meaning the proc that called this proc's caller. @author Lars Pind (lars@pinds.com) @see ad_print_stack_trace } { set stack "" for { set x [expr {[info level] + $level}] } { $x > 0 } { incr x -1 } { append stack " called from [info level $x]\n" } return $stack } ad_proc -public ad_ns_set_to_tcl_vars { {-duplicates overwrite} {-level 1} set_id } { Takes an ns_set and sets variables in the caller's environment correspondingly, i.e. if key is foo and value is bar, the Tcl var foo is set to bar. @param duplicates This optional switch argument defines what happens if the Tcl var already exists, or if there are duplicate entries for the same key. overwrites just overwrites the var, which amounts to letting the ns_set win over pre-defined vars, and later entries in the ns_set win over earlier ones. ignore means the variable isn't overwritten. fail will make this proc fail with an error. This makes it easier to track subtle errors that could occur because of unpredicted name clashes. @param level The level to upvar to. @author Lars Pind (lars@pinds.com) } { if { [lsearch -exact {ignore fail overwrite} $duplicates] == -1 } { return -code error "The optional switch duplicates must be either overwrite, ignore or fail" } set size [ns_set size $set_id] for { set i 0 } { $i < $size } { incr i } { set varname [ns_set key $set_id $i] upvar $level $varname var if { [info exists var] } { switch $duplicates { fail { return -code error "ad_ns_set_to_tcl_vars tried to set the var $varname which is already set" } ignore { # it's already set ... don't overwrite it continue } } } set var [ns_set value $set_id $i] } } ad_proc -public ad_tcl_vars_to_ns_set { -set_id -put:boolean args } { Takes a list of variable names and ns_set updates values in an ns_set correspondingly: key is the name of the var, value is the value of the var. The caller is (obviously) responsible for freeing the set if need be. @param set_id If this switch is specified, it'll use this set instead of creating a new one. @param put If this boolean switch is specified, it'll use ns_set put instead of ns_set update (update is default) @param args A number of variable names that will be transported into the ns_set. @author Lars Pind (lars@pinds.com) } { if { ![info exists set_id] } { set set_id [ns_set create] } if { $put_p } { set command put } else { set command update } foreach varname $args { upvar $varname var ns_set $command $set_id $varname $var } return $set_id } ad_proc -public ad_tcl_vars_list_to_ns_set { -set_id -put:boolean vars_list } { Takes a TCL list of variable names and ns_set updates values in an ns_set correspondingly: key is the name of the var, value is the value of the var. The caller is (obviously) responsible for freeing the set if need be. @param set_id If this switch is specified, it'll use this set instead of creating a new one. @param put If this boolean switch is specified, it'll use ns_set put instead of ns_set update (update is default) @param args A TCL list of variable names that will be transported into the ns_set. @author Lars Pind (lars@pinds.com) } { if { ![info exists set_id] } { set set_id [ns_set create] } if { $put_p } { set command put } else { set command update } foreach varname $vars_list { upvar $varname var ns_set $command $set_id $varname $var } return $set_id } ad_proc -public util_sets_equal_p { list1 list2 } { Tests whether each unique string in list1 occurs as many times in list1 as in list2 and vice versa (regarless of order). @return 1 if the lists have identical sets and 0 otherwise @author Peter Marklund } { if { [llength $list1] != [llength $list2] } { return 0 } set sorted_list1 [lsort $list1] set sorted_list2 [lsort $list2] for { set index1 0 } { $index1 < [llength $sorted_list1] } { incr index1 } { if { [lindex $sorted_list1 $index1] ne [lindex $sorted_list2 $index1] } { return 0 } } return 1 } ad_proc -public util_subset_p { list1 list2 } { Tests whether list1 is a subset of list2. @return 1 if list1 is a subset of list2. @author Peter Marklund } { if { [llength $list1] == 0 } { # The empty list is always a subset of any list return 1 } set sorted_list1 [lsort $list1] set sorted_list2 [lsort $list2] set len1 [llength $sorted_list1] set len2 [llength $sorted_list2] # Loop over list1 and list2 in sort order, comparing the elements set index1 0 set index2 0 while { $index1 < $len1 && $index2 < $len2 } { set elm1 [lindex $sorted_list1 $index1] set elm2 [lindex $sorted_list2 $index2] set compare [string compare $elm1 $elm2] switch -exact -- $compare { -1 { # elm1 < elm2 # The first element in list1 is smaller than any element in list2, # therefore this element cannot exist in list2, and therefore list1 is not a subset of list2 return 0 } 0 { # A match, great, next element incr index1 incr index2 continue } 1 { # elm1 > elm2 # Move to the next element in list2, knowing that this will be larger, and therefore # potentially equal to the element in list1 incr index2 } } } if { $index1 == $len1 } { # We've reached the end of list1, finding all elements along the way, we're done return 1 } else { # One or more elements in list1 not found in list2 return 0 } } ad_proc -public util_get_subset_missing { list1 list2 } { Returns the elements in list1 that are not in list2. Ignores duplicates. @return The list of elements from list1 that could not be found in list2. @author Peter Marklund } { if { [llength $list1] == 0 } { # The empty list is always a subset of any list return [list] } set sorted_list1 [list] foreach elm [lsort $list1] { if { [llength $sorted_list1] == 0 || [lindex $sorted_list1 end] ne $elm } { lappend sorted_list1 $elm } } set sorted_list2 [lsort $list2] set len1 [llength $sorted_list1] set len2 [llength $sorted_list2] set missing_elms [list] # Loop over list1 and list2 in sort order, comparing the elements set index1 0 set index2 0 while { $index1 < $len1 && $index2 < $len2 } { set elm1 [lindex $sorted_list1 $index1] set elm2 [lindex $sorted_list2 $index2] set compare [string compare $elm1 $elm2] switch -exact -- $compare { -1 { # elm1 < elm2 # The first element in list1 is smaller than any element in list2, # therefore this element cannot exist in list2, and therefore list1 is not a subset of list2 lappend missing_elms $elm1 incr index1 } 0 { # A match, great, next element incr index1 incr index2 continue } 1 { # elm1 > elm2 # Move to the next element in list2, knowing that this will be larger, and therefore # potentially equal to the element in list1 incr index2 } } } if { $index1 == $len1 } { # We've reached the end of list1, finding all elements along the way, we're done return [list] } else { # One or more elements in list1 not found in list2 return [concat $missing_elms [lrange $sorted_list1 $index1 end]] } } ad_proc -public ad_tcl_list_list_to_ns_set { -set_id -put:boolean kv_pairs } { Takes a list of lists of key/value pairs and ns_set updates values in an ns_set. @param set_id If this switch is specified, it'll use this set instead of creating a new one. @param put If this boolean switch is specified, it'll use ns_set put instead of ns_set update (update is default) @param kv_pairs A list of lists containing key/value pairs to be stuffed into the ns_set @author Yonatan Feldman (yon@arsdigita.com) } { if { ![info exists set_id] } { set set_id [ns_set create] } if { $put_p } { set command put } else { set command update } foreach kv_pair $kv_pairs { ns_set $command $set_id [lindex $kv_pair 0] [lindex $kv_pair 1] } return $set_id } ad_proc -public ad_ns_set_keys { -colon:boolean {-exclude ""} set_id } { Returns the keys of a ns_set as a Tcl list, like array names. @param colon If set, will prepend all the keys with a colon; useful for bind variables @param exclude Optional Tcl list of key names to exclude @author Lars Pind (lars@pinds.com) } { set keys [list] set size [ns_set size $set_id] for { set i 0 } { $i < $size } { incr i } { set key [ns_set key $set_id $i] if { [lsearch -exact $exclude $key] == -1 } { if { $colon_p } { lappend keys ":$key" } else { lappend keys $key } } } return $keys } ad_proc -public util_wrap_list { { -eol " \\" } { -indent 4 } { -length 70 } items } { Wraps text to a particular line length. @param eol the string to be used at the end of each line. @param indent the number of spaces to use to indent all lines after the first. @param length the maximum line length. @param items the list of items to be wrapped. Items are HTML-formatted. An individual item will never be wrapped onto separate lines. } { set out "

    "
        set line_length 0
        foreach item $items {
    	regsub -all {<[^>]+>} $item "" item_notags
    	if { $line_length > $indent } {
    	    if { $line_length + 1 + [string length $item_notags] > $length } {
    		append out "$eol\n"
    		for { set i 0 } { $i < $indent } { incr i } {
    		    append out " "
    		}
    		set line_length $indent
    	    } else {
    		append out " "
    		incr line_length
    	    }
    	}
    	append out $item
    	incr line_length [string length $item_notags]
        }
        append out "
    " return $out } ad_proc -public util_text_to_url { {-existing_urls {}} {-no_resolve:boolean} {-replacement "-"} {-text ""} {_text ""} } { Modify a string so that it is suited as a well formatted URL path element. Also, if given a list of existing urls it can catch duplicate or optionally create an unambiguous url by appending a dash and a digit.

    Examples:
    util_text_to_url -text "Foo Bar" returns foo-bar
    util_text_to_url -existing_urls {foo-bar some-other-item} -text "Foo Bar" returns foo-bar-2
    @param text the text to modify, e.g. "Foo Bar" @param _text the text to modify, e.g. "Foo Bar" (Deprecated, use -text instead. Fails when the value starts with a dash.) @param existing_urls a list of URLs that already exist on the same level and would cause a conflict @param no_resolve Specify this flag if you do not want util_text_to_url to automatically generate "foo-bar-2" if "foo-bar" is already in existing_urls, and would rather have an error thrown. @param replacement the character that is used to replace illegal characters @author Tilmann Singer } { if { $text eq "" } { set text $_text } set original_text $text set text [string trim [string tolower $original_text]] # Save some german and french characters from removal by replacing # them with their ascii counterparts. set text [string map { \x00e4 ae \x00f6 oe \x00fc ue \x00df ss \x00f8 o \x00e0 a \x00e1 a \x00e8 e \x00e9 e } $text] # here's the Danish ones (hm. the o-slash conflicts with the definition above, which just says 'o') set text [string map { \x00e6 ae \x00f8 oe \x00e5 aa \x00C6 Ae \x00d8 Oe \x00c5 Aa } $text] # substitute all non-word characters regsub -all {([^a-z0-9])+} $text $replacement text set text [string trim $text $replacement] # throw an error when the resulting string is empty if { $text eq "" } { error "Cannot compute a URL of this string: \"$original_text\" because after removing all illegal characters it's an empty string." } # check if the resulting url is already present if { [lsearch -exact $existing_urls $text] > -1 } { if { $no_resolve_p } { # URL is already present in the existing_urls list and we # are asked to not automatically resolve the collision error "The url $text is already present" } else { # URL is already present in the existing_urls list - # compute an unoccupied replacement using a pattern like # this: if foo is taken, try foo-2, then foo-3 etc. # Holes will not be re-occupied. E.g. if there's foo-2 and # foo-4, a foo-5 will be created instead of foo-3. This # way confusion through replacement of deleted content # with new stuff is avoided. set number 2 foreach url $existing_urls { if { [regexp "${text}${replacement}(\\d+)\$" $url match n] } { # matches the foo-123 pattern if { $n >= $number } { set number [expr {$n + 1}] } } } set text "$text$replacement$number" } } return $text } ad_proc -public util_unlist { list args } { Places the nth element of list into the variable named by the nth element of args. } { for { set i 0 } { $i < [llength $args] } { incr i } { upvar [lindex $args $i] val set val [lindex $list $i] } } ad_proc util_email_valid_p { query_email } { Returns 1 if an email address has more or less the correct form. The regexp was taken from Jeff Friedls book "Mastering Regular Expressions". @author Philip Greenspun (philg@mit.edu) @author Jeff Friedl (jfriedl@oreilly.com) @author Lars Pind (lars@arsdigita.com) } { # This regexp was very kindly contributed by Jeff Friedl, author of # _Mastering Regular Expressions_ (O'Reilly 1997). return [regexp "^\[^@<>\"\t ]+@\[^@<>\".\t ]+(\\.\[^@<>\".\n ]+)+$" $query_email] } ad_proc -public util_email_unique_p { email } { Returns 1 if the email passed in does not yet exist in the system. @author yon (yon@openforce.net) } { return [db_string email_unique_p {}] } ad_proc -public util_url_valid_p { query_url } { Returns 1 if a URL is a web URL (HTTP, HTTPS or FTP). @author Philip Greenspun (philg@mit.edu) } { return [regexp -nocase {^(http|https|ftp)://[^ ].+} [string trim $query_url]] } ad_proc -public value_if_exists { var_name } { If the specified variable exists in the calling environment, returns the value of that variable. Otherwise, returns the empty_string. } { upvar $var_name $var_name if { [info exists $var_name] } { return [set $var_name] } } ad_proc -public min { args } { Returns the minimum of a list of numbers. Example: min 2 3 1.5 returns 1.5. @author Ken Mayer (kmayer@bitwrangler.com) @creation-date 26 September 2002 } { set min [lindex $args 0] foreach arg $args { if { $arg < $min } { set min $arg } } return $min } ad_proc -public max { args } { Returns the maximum of a list of numbers. Example: max 2 3 1.5 returns 3. @author Lars Pind (lars@pinds.com) @creation-date 31 August 2000 } { set max [lindex $args 0] foreach arg $args { if { $arg > $max } { set max $arg } } return $max } # usage: # suppose the variable is called "expiration_date" # put "[ad_dateentrywidget expiration_date]" in your form # and it will expand into lots of weird generated var names # put ns_dbformvalue [ns_getform] expiration_date date expiration_date # and whatever the user typed will be set in $expiration_date proc ad_dateentrywidget {column {default_date "1940-11-03"}} { if {[ns_info name] ne "NaviServer"} { ns_share NS } else { set NS(months) [list January February March April May June \ July August September October November December] } set output "  " return [ns_dbformvalueput $output $column date $default_date] } ad_proc -public util_ns_set_to_list { {-set:required} } { Convert an ns_set into a list suitable for passing in to the "array set" command (key value key value ...). @param set The ns_set to convert @return An array of equivalent keys and values as the ns_set specified. } { set result [list] for {set i 0} {$i < [ns_set size $set]} {incr i} { lappend result [ns_set key $set $i] lappend result [ns_set value $set $i] } return $result } ad_proc -public util_list_to_ns_set { aList } { Convert a list in the form "key value key value ..." into a ns_set. @param aList The list to convert @return The id of a (non-persistent) ns_set } { set setid [ns_set create] foreach {k v} $aList { ns_set put $setid $k $v } return $setid } ad_proc -public util_sets_equal_p { list1 list2 } { Tests whether each unique string in list1 occurs as many times in list1 as in list2 and vice versa (regarless of order). @return 1 if the lists have identical sets and 0 otherwise @author Peter Marklund } { if { [llength $list1] != [llength $list2] } { return 0 } set sorted_list1 [lsort $list1] set sorted_list2 [lsort $list2] for { set index1 0 } { $index1 < [llength $sorted_list1] } { incr index1 } { if { [lindex $sorted_list1 $index1] ne [lindex $sorted_list2 $index1] } { return 0 } } return 1 } ad_proc -public util_http_file_upload { -file -data -binary:boolean -filename -name {-mime_type */*} {-mode formvars} {-rqset ""} url {formvars {}} {timeout 30} {depth 10} {http_referer ""} } { Implement client-side HTTP file uploads as multipart/form-data as per RFC 1867.

    Similar to util_httppost, but enhanced to be able to upload a file as multipart/form-data. Also useful for posting to forms that require their input to be encoded as multipart/form-data instead of as application/x-www-form-urlencoded.

    The switches -file /path/to/file and -data $raw_data are mutually exclusive. You can specify one or the other, but not both. NOTE: it is perfectly valid to not specify either, in which case no file is uploaded, but form variables are encoded using multipart/form-data instead of the usual encoding (as noted aboved).

    If you specify either -file or -data you must supply a value for -name, which is the name of the <INPUT TYPE="file" NAME="..."> form tag.

    Specify the -binary switch if the file (or data) needs to be base-64 encoded. Not all servers seem to be able to handle this. (For example, http://mol-stage.usps.com/mml.adp, which expects to receive an XML file doesn't seem to grok any kind of Content-Transfer-Encoding.)

    If you specify -file then -filename is optional (it can be infered from the name of the file). However, if you specify -data then it is mandatory.

    If -mime_type is not specified then ns_guesstype is used to try and find a mime type based on the filename. If ns_guesstype returns */* the generic value of application/octet-stream will be used.

    Any form variables may be specified in one of four formats:

    • array (list of key value pairs like what [array get] returns)
    • formvars (list of url encoded formvars, i.e. foo=bar&x=1)
    • ns_set (an ns_set containing key/value pairs)
    • vars (a list of tcl vars to grab from the calling enviroment)

    -rqset specifies an ns_set of extra headers to send to the server when doing the POST.

    timeout, depth, and http_referer are optional, and are included as optional positional variables in the same order they are used in util_httppost. NOTE: util_http_file_upload does not (currently) follow any redirects, so depth is superfulous. @author Michael A. Cleverly (michael@cleverly.com) @creation-date 3 September 2002 } { # sanity checks on switches given if {[lsearch -exact {formvars array ns_set vars} $mode] == -1} { error "Invalid mode \"$mode\"; should be one of: formvars,\ array, ns_set, vars" } if {[info exists file] && [info exists data]} { error "Both -file and -data are mutually exclusive; can't use both" } if {[info exists file]} { if {![file exists $file]} { error "Error reading file: $file not found" } if {![file readable $file]} { error "Error reading file: $file permission denied" } set fp [open $file] fconfigure $fp -translation binary set data [read $fp] close $fp if {![info exists filename]} { set filename [file tail $file] } if {[string equal */* $mime_type] || $mime_type eq ""} { set mime_type [ns_guesstype $file] } } set boundary [ns_sha1 [list [clock clicks -milliseconds] [clock seconds]]] set payload {} if {[info exists data] && [string length $data]} { if {![info exists name]} { error "Cannot upload file without specifing form variable -name" } if {![info exists filename]} { error "Cannot upload file without specifing -filename" } if {[string equal $mime_type */*] || $mime_type eq ""} { set mime_type [ns_guesstype $filename] if {[string equal $mime_type */*] || $mime_type eq ""} { set mime_type application/octet-stream } } if {$binary_p} { set data [base64::encode base64] set transfer_encoding base64 } else { set transfer_encoding binary } append payload --$boundary \ \r\n \ "Content-Disposition: form-data; " \ "name=\"$name\"; filename=\"$filename\"" \ \r\n \ "Content-Type: $mime_type" \ \r\n \ "Content-transfer-encoding: $transfer_encoding" \ \r\n \ \r\n \ $data \ \r\n } set variables [list] switch -- $mode { array { set variables $formvars } formvars { foreach formvar [split $formvars &] { set formvar [split $formvar =] set key [lindex $formvar 0] set val [join [lrange $formvar 1 end] =] lappend variables $key $val } } ns_set { for {set i 0} {$i < [ns_set size $formvars]} {incr i} { set key [ns_set key $formvars $i] set val [ns_set value $formvars $i] lappend variables $key $val } } vars { foreach key $formvars { upvar 1 $key val lappend variables $key $val } } } foreach {key val} $variables { append payload --$boundary \ \r\n \ "Content-Disposition: form-data; name=\"$key\"" \ \r\n \ \r\n \ $val \ \r\n } append payload --$boundary-- \r\n if { [catch { if {[incr depth -1] <= 0} { return -code error "util_http_file_upload:\ Recursive redirection: $url" } set http [util_httpopen POST $url $rqset $timeout $http_referer] set rfd [lindex $http 0] set wfd [lindex $http 1] _ns_http_puts $timeout $wfd \ "Content-type: multipart/form-data; boundary=$boundary\r" _ns_http_puts $timeout $wfd "Content-length: [string length $payload]\r" _ns_http_puts $timeout $wfd \r _ns_http_puts $timeout $wfd "$payload\r" flush $wfd close $wfd set rpset [ns_set new [_ns_http_gets $timeout $rfd]] while 1 { set line [_ns_http_gets $timeout $rfd] if { ![string length $line] } break ns_parseheader $rpset $line } set headers $rpset set response [ns_set name $headers] set status [lindex $response 1] set length [ns_set iget $headers content-length] if { "" eq $length } { set length -1 } set type [ns_set iget $headers content-type] set_encoding $type $rfd set err [catch { while 1 { set buf [_ns_http_read $timeout $rfd $length] append page $buf if { "" eq $buf } break if {$length > 0} { incr length -[string length $buf] if {$length <= 0} break } } } errMsg] ns_set free $headers close $rfd if {$err} { global errorInfo return -code error -errorinfo $errorInfo $errMsg } } errmsg] } { if {[info exists wfd] && [lsearch [file channels] $wfd] >= 0} { close $wfd } if {[info exists rfd] && [lsearch [file channels] $rfd] >= 0} { close $rfd } set page -1 } return $page } ad_proc -public util_list_of_ns_sets_to_list_of_lists { {-list_of_ns_sets:required} } { Transform a list of ns_sets (most likely produced by db_list_of_ns_sets) into a list of lists that match the array set format in the sublists (key value key value ...) @param -list_of_ns_sets A list of ns_set ids @author Ola Hansson (ola@polyxena.net) @creation-date September 27, 2002 } { set result [list] foreach ns_set $list_of_ns_sets { lappend result [util_ns_set_to_list -set $ns_set] } return $result } ad_proc -public xml_get_child_node_content_by_path { node path_list } { Return the first non-empty contents of a child node down a given path from the current node.

    Example:

    set tree [xml_parse -persist {
        <enterprise>
          <properties>
            <datasource>Dunelm Services Limited</datasource>
            <target>Telecommunications LMS</target>
            <type>DATABASE UPDATE</type>
            <datetime>2001-08-08</datetime>
          </properties>
          <person recstatus = "1">
            <comments>Add a new Person record.</comments>
            <sourcedid>
              <source>Dunelm Services Limited</source>
              <id>CK1</id>
            </sourcedid>
            <name>
              <fn>Clark Kent</fn>
              <sort>Kent, C</sort>
              <nickname>Superman</nickname>
            </name>
            <demographics>
              <gender>2</gender>
            </demographics>
            <adr>
              <extadd>The Daily Planet</extadd>
              <locality>Metropolis</locality>
              <country>USA</country>
            </adr>
          </person>
        </enterprise>
    }]
    
    set root_node [xml_doc_get_first_node $tree]
    
    aa_equals "person -> name -> nickname is Superman" \
        [xml_get_child_node_content_by_path $root_node { { person name nickname } }] "Superman"
    
    aa_equals "Same, but after trying a couple of non-existent paths or empty notes" \
        [xml_get_child_node_content_by_path $root_node { { does not exist } { properties } { person name nickname } { person sourcedid id } }] "Superman"
    aa_equals "properties -> datetime" \
        [xml_get_child_node_content_by_path $root_node { { person commments foo } { person name first_names } { properties datetime } }] "2001-08-08"
    
    @param node The node to start from @param path_list List of list of nodes to try, e.g. { { user_id } { sourcedid id } }, or { { name given } { name fn } }. @author Lars Pind (lars@collaboraid.biz) } { set result {} foreach path $path_list { set current_node $node foreach element_name $path { set current_node [xml_node_get_first_child_by_name $current_node $element_name] if { $current_node eq "" } { # Try the next path break } } if { $current_node ne "" } { set result [xml_node_get_content $current_node] if { $result ne "" } { # Found the value, we're done break } } } return $result } ad_proc -public xml_get_child_node_attribute_by_path { node path_list attribute_name } { Return the attribute of a child node down a give path from the current node.

    Example:

        set tree [xml_parse -persist "
    <enterprise>
      <properties>
        <datasource>University of Durham: SIS</datasource>
        <target>University of Durham: LMS</target>
        <type>CREATE</type>
        <datetime>2001-08-08</datetime>
      </properties>
      <group recstatus = "1">
        <sourcedid>
          <source>University of Durham</source>
          <id>CS1</id>
        </sourcedid>
        <grouptype>
          <scheme>University of Durham</scheme>
          <typevalue level = "2"/>
        </grouptype>
    
        .....
    
      </group>
    </enterprise>
    
    "]
        set root_node [xml_doc_get_first_node $tree]
        set group_node [xml_node_get_children_by_name $root_node "group"] 
        set typevalue [xml_get_child_node_attribute_by_path $group_node {grouptype typevalue} "level"]
    
        @param node        The node to start from
        @param path_list   List of the node to try, e.g. 
                             { grouptype typevalue }.
        @param attribute_name   Attribute name at the very end of the very botton of the tree route at path_list.
    
        @author Rocael Hernandez (roc@viaro.net)
    
    } {
    
        set attribute {}
        set current_node $node
        foreach element_name $path_list {
    	set current_node [xml_node_get_first_child_by_name $current_node $element_name]
    	if { $current_node eq "" } {
    	    # Try the next path
    	    break
    	}
        }
    
        if { $current_node ne "" } {
    	set attribute [xml_node_get_attribute $current_node $attribute_name ""]
        }
    
        return $attribute
    
    }
    
    
    ad_proc -public ad_generate_random_string {{length 8}} {
        Generates a random string made of numbers and letters
    } {
        return [string range [sec_random_token] 0 $length]
    }
    
    ad_proc -public with_finally {
        -code:required
        -finally:required
    } {
        Execute CODE, then execute cleanup code FINALLY.
        If CODE completes normally, its value is returned after
        executing FINALLY.
        If CODE exits non-locally (as with error or return), FINALLY
        is executed anyway.
    
        @param code Code to be executed that could throw and error
        @param finally Cleanup code to be executed even if an error occurs
    } {
        global errorInfo errorCode
    
        # Execute CODE.
        set return_code [catch {uplevel $code} string]
        set s_errorInfo $errorInfo
        set s_errorCode $errorCode
    
        # As promised, always execute FINALLY.  If FINALLY throws an
        # error, Tcl will propagate it the usual way.  If FINALLY contains
        # stuff like break or continue, the result is undefined.
        uplevel $finally
    
        switch $return_code {
    	0 {
    	    # CODE executed without a non-local exit -- return what it
    	    # evaluated to.
    	    return $string
    	}
    	1 {
    	    # Error
    	    return -code error -errorinfo $s_errorInfo -errorcode $s_errorCode $string
    	}
    	2 {
    	    # Return from the caller.
    	    return -code return $string
    	}
    	3 {
    	    # break
    	    return -code break
    	}
    	4 {
    	    # continue
    	    return -code continue
    	}
    	default {
    	    return -code $return_code $string
    	}
        }
    }
    
    ad_proc util_background_exec {
        {-pass_vars ""}
        {-name:required}
        code_chunk
    } {
        Executes a chunk of code in the background. The code is run exclusively, 
        meaning that no two threads with the same name can run at the same time.
        
        @param name The name of the thread. No two chunks with the same name can run at the same time.
    
        @param pass_vars Names of variables which you want passed to the code chunk
    
        @param code_chunk The chunk you want executed
    } {
        ns_log Debug "util_background_exec: Starting, waiting for mutex"
    
    #    ns_mutex lock [nsv_get util_background_exec_mutex .]
    
        ns_log Debug "util_background_exec: Got mutex"
    
        set running_p [nsv_exists util_background_exec $name]
        if { !$running_p } {
            nsv_set util_background_exec [list $name] 1
        }
    
    #    ns_mutex unlock [nsv_get util_background_exec_mutex .]
        ns_log Debug "util_background_exec: Released mutex"
    
        if { $running_p } {
            ns_log Notice "util_background_exec: $name is already running, exiting"
            return
        }
    
        set code {}
        foreach var $pass_vars {
            upvar 1 $var the_var
            if { [array exists the_var] } {
                append code "array set [list $var] [list [array get the_var]]\n"
            } else {
                append code "set [list $var] [list $the_var]\n"
            }
        }
    
        append code "
            set errno \[catch {
                $code_chunk
            } errmsg\]
    
            set errinfo {}
            set errcode {}
            if { \$errno == 1 } {
                global errorInfo errorCode
                set errinfo \$errorInfo
                set errcode \$errorCode
            }
    
            if { \$errno == 1 } {
                \# This is an error
                ns_log Error \"util_background_exec: Error in thread named '$name': \$errorInfo\"
            }
    
            \# errno = 0 (TCL_OK) or 2 (TCL_RETURN) is considered normal, i.e. first elm is true
            set success_p \[expr { \$errno == 0 || \$errno == 2 }\]
            set result \[list \$success_p \$errmsg \$errno \$errinfo \$errcode]
    
            ns_log debug \"util_background_exec: Thread named '$name' returned \$result\"
    
            nsv_unset util_background_exec [list $name]
            nsv_set util_background_exec_result [list $name] \$result
    
        "
        ns_log Debug "util_background_exec: Scheduling code\n$code"
    
        ns_schedule_proc -thread -once 1 $code
    }
    
    ad_proc util_background_running_p {
        {-name:required}
    } {
        
    } { 
        set running_p [nsv_exists util_background_exec $name]
        return $running_p
    }
    
    ad_proc util_background_get_result {
        {-name:required}
    } {
        Gets the result of a completed background thread execution.
    } { 
        return [nsv_get util_background_exec_result $name]
    }
    
    ad_proc util_background_reset {
        {-name:required}
    } {
        Gets the result of a completed background thread execution.
    } { 
        nsv_unset util_background_exec $name
    }
    
    
    
    #####
    #
    # This is some old security crud from before we had ad_page_contract
    #
    #####
    
    
    # michael@arsdigita.com: A better name for this proc would be
    # "ad_block_sql_fragment_form_data", since "form data" is the
    # official term for query string (URL) variables and form input
    # variables.
    #
    ad_proc -public -deprecated ad_block_sql_urls {
        conn
        args
        why
    } {
    
        A filter that detect attempts to smuggle in SQL code through form data
        variables. The use of bind variables and ad_page_contract input 
        validation to prevent SQL smuggling is preferred.
    
        @see ad_page_contract
    } {
        set form [ns_getform]
        if { $form eq "" } { return filter_ok }
    
        # Check each form data variable to see if it contains malicious
        # user input that we don't want to interpolate into our SQL
        # statements.
        #
        # We do this by scanning the variable for suspicious phrases; at
        # this time, the phrases we look for are: UNION, UNION ALL, and
        # OR.
        #
        # If one of these phrases is found, we construct a test SQL query
        # that incorporates the variable into its WHERE clause and ask
        # the database to parse it. If the query does parse successfully,
        # then we know that the suspicious user input would result in a
        # executing SQL that we didn't write, so we abort processing this
        # HTTP request.
        #
        set n_form_vars [ns_set size $form]
        for { set i 0 } { $i < $n_form_vars } { incr i } {
            set key [ns_set key $form $i]
            set value [ns_set value $form $i]
    
    	# michael@arsdigita.com:
    	#
    	# Removed 4000-character length check, because that allowed
    	# malicious users to smuggle SQL fragments greater than 4000
    	# characters in length.
    	#
            if {
    	    [regexp -nocase {[^a-z_]or[^a-z0-9_]} $value] ||
    	    [regexp -nocase {union([^a-z0-9_].*all)?[^a-z0-9_].*select} $value]
    	} {
    	    # Looks like the user has added "union [all] select" to
    	    # the variable, # or is trying to modify the WHERE clause
    	    # by adding "or ...".
    	    #
                # Let's see if Oracle would accept this variables as part
    	    # of a typical WHERE clause, either as string or integer.
    	    #
    	    # michael@arsdigita.com: Should we grab a handle once
    	    # outside of the loop?
    	    #
                set parse_result_integer [db_string sql_test_1 "select test_sql('select 1 from dual where 1=[DoubleApos $value]') from dual"]
    
                if { [string first "'" $value] != -1 } {
    		#
    		# The form variable contains at least one single
    		# quote. This can be a problem in the case that
    		# the programmer forgot to QQ the variable before
    		# interpolation into SQL, because the variable
    		# could contain a single quote to terminate the
    		# criterion and then smuggled SQL after that, e.g.:
    		#
    		#   set foo "' or 'a' = 'a"
    		#
    		#   db_dml "delete from bar where foo = '$foo'"
    		#
    		# which would be processed as:
    		#
    		#   delete from bar where foo = '' or 'a' = 'a'
    		#
    		# resulting in the effective truncation of the bar
    		# table.
    		#
                    set parse_result_string [db_string sql_test_2 "select test_sql('select 1 from dual where 1=[DoubleApos "'$value'"]') from dual"]
                } else {
                    set parse_result_string 1
                }
    
                if {
    		$parse_result_integer == 0 ||
    		$parse_result_integer == -904  ||
    		$parse_result_integer == -1789 ||
    		$parse_result_string == 0 ||
    		$parse_result_string == -904 ||
    		$parse_result_string == -1789
    	    } {
                    # Code -904 means "invalid column", -1789 means
    		# "incorrect number of result columns". We treat this
    		# the same as 0 (no error) because the above statement
    		# just selects from dual and 904 or 1789 only occur
    		# after the parser has validated that the query syntax
    		# is valid.
    
                    ns_log Error "ad_block_sql_urls: Suspicious request from [ad_conn peeraddr]. Parameter $key contains code that looks like part of a valid SQL WHERE clause: [ad_conn url]?[ad_conn query]"
    
    		# michael@arsdigita.com: Maybe we should just return a
    		# 501 error.
    		#
                    ad_return_error "Suspicious Request" "Parameter $key looks like it contains SQL code. For security reasons, the system won't accept your request."
    
                    return filter_return
                }
            }
        }
    
        return filter_ok
    }
    
    ad_proc -public -deprecated ad_set_typed_form_variable_filter {
        url_pattern
        args
    } {
        
        #
        # Register special rules for form variables.
        #
        # Example:
        #
        #    ad_set_typed_form_variable_filter /my_module/* {a_id number} {b_id word} {*_id integer}
        #
        # For all pages under /my_module, set_form_variables would set 
        # $a_id only if it was number, and $b_id only if it was a 'word' 
        # (a string that contains only letters, numbers, dashes, and 
        # underscores), and all other variables that match the pattern
        # *_id would be set only if they were integers.
        #
        # Variables not listed have no restrictions on them.
        #
        # By default, the three supported datatypes are 'integer', 'number',
        # and 'word', although you can add your own type by creating
        # functions named ad_var_type_check_${type_name}_p which should
        # return 1 if the value is a valid $type_name, or 0 otherwise.
        #
        # There's also a special datatype named 'nocheck', which will
        # return success regardless of the value. (See the docs for 
        # ad_var_type_check_${type_name}_p to see how this might be
        # useful.)
        #
        # The default data_type is 'integer', which allows you shorten the
        # command above to:
        #
        #    ad_set_typed_form_variable_filter /my_module/* a_id {b_id word}
        #
    
        ad_page_contract is the preferred mechanism to do automated
        validation of form variables.
        
    @see ad_page_contract } { ad_register_filter postauth GET $url_pattern ad_set_typed_form_variables $args ad_register_filter postauth POST $url_pattern ad_set_typed_form_variables $args } proc ad_set_typed_form_variables {conn args why} { global ad_typed_form_variables eval lappend ad_typed_form_variables [lindex $args 0] return filter_ok } # # All the ad_var_type_check* procs get called from # check_for_form_variable_naughtiness. Read the documentation # for ad_set_typed_form_variable_filter for more details. ad_proc ad_var_type_check_integer_p {value} {
        #
        # return 1 if $value is an integer, 0 otherwise.
        #
        
    } {
    
        if { [regexp {[^0-9]} $value] } {
            return 0
        } else {
            return 1
        }
    }
    
    ad_proc ad_var_type_check_safefilename_p {value} {
        
        #
        # return 0 if the file contains ".."
        #
        
    } {
    
        if { [string match *..* $value] } {
            return 0
        } else {
            return 1
        }
    }
    
    ad_proc ad_var_type_check_dirname_p {value} {
        
        #
        # return 0 if $value contains a / or \, 1 otherwise.
        #
        
    } {
    
        if { [regexp {[/\\]} $value] } {
            return 0
        } else {
            return 1
        }
    }
    
    ad_proc ad_var_type_check_number_p {value} {
        
        #
        # return 1 if $value is a valid number
        #
        
    } {
        if { [catch {expr 1.0 * $value}] } {
            return 0
        } else {
            return 1
        }
    }
    
    ad_proc ad_var_type_check_word_p {value} {
        
        #
        # return 1 if $value contains only letters, numbers, dashes, 
        # and underscores, otherwise returns 0.
        #
        
    } { if { [regexp {[^-A-Za-z0-9_]} $value] } { return 0 } else { return 1 } } ad_proc ad_var_type_check_nocheck_p {{value ""}} {
        #
        # return 1 regardless of the value. This useful if you want to 
        # set a filter over the entire site, then create a few exceptions.
        #
        # For example:
        #
        #   ad_set_typed_form_variable_filter /my-dangerous-page.tcl {user_id nocheck}
        #   ad_set_typed_form_variable_filter /*.tcl user_id
        #
        
    } { return 1 } ad_proc ad_var_type_check_noquote_p {value} {
        #
        # return 1 if $value contains any single-quotes
        #
        
    } {
    
        if { [string match *'* $value] } {
            return 0
        } else {
            return 1
        }
    }
    
    ad_proc ad_var_type_check_integerlist_p {value} {
        
        #
        # return 1 if list contains only numbers, spaces, and commas.
        # Example '5, 3, 1'. Note: it doesn't allow negative numbers,
        # because that could let people sneak in numbers that get
        # treated like math expressions like '1, 5-2'
        #
        #
        
    } {
    
        if { [regexp {[^ 0-9,]} $value] } {
            return 0
        } else {
            return 1
        }
    }
    
    ad_proc ad_var_type_check_fail_p {value} {
        
        #
        # A check that always returns 0. Useful if you want to disable all access
        # to a page.
        #
        
    } {
        return 0
    }
    
    ad_proc ad_var_type_check_third_urlv_integer_p {{args ""}} {
        
        #
        # Returns 1 if the third path element in the URL is integer.
        #
        
    } {
    
        set third_url_element [lindex [ad_conn urlv] 3]
    
        if { [regexp {[^0-9]} $third_url_element] } {
            return 0
        } else {
            return 1
        }
    }
    
    ####################
    #
    # Procs in the util namespace
    #
    ####################
    
    ad_proc util::name_to_path {
        -name:required
    } {
        Transforms a pretty name to a reasonable path name.
    } {
        regsub -all -nocase { } [string trim [string tolower $name]] {-} name
        regsub -all {[^[:alnum:]\-]} $name {} name
        return $name
    }
    
    ad_proc -public util::backup_file {
        {-file_path:required}
        {-backup_suffix ".bak"}
    } {
        Backs up (move) the file or directory with given path to a file/directory with a backup suffix.
        Will avoid overwriting old backup files by adding a number to the filename to make it unique.
        For example, suppose you are backing up /web/my-server/packages/my-package/file.txt and
        the file has already been backed up to /web/my-server/packages/my-package/file.txt.bak. Invoking
        this proc will then generate the backup file /web/my-server/packages/my-package/file.txt.bak.2
    
        @param backup_suffix The suffix to add to the backup file.
    
        @author Peter Marklund
    } {
        # Keep generating backup paths until we find one that doesn't already exist
        set backup_counter 1
        while 1 {
            if { $backup_counter == "1" } {
                set backup_path "${file_path}${backup_suffix}"
            } else {
                set backup_path "${file_path}${backup_suffix}.${backup_counter}"
            }
            
            if { ![file exists $backup_path] } {
                # We found a non-existing backup path
                break
            }
    
            incr backup_counter
        }
    
        #exec "mv" "$file_path" "$backup_path"
        file rename $file_path $backup_path
    }
    
    
    
    ad_proc -public util::subst_safe { string } {
        Make string safe for subst'ing.
    } {
        regsub -all {\$} $string {\$} string
        regsub -all {\[} $string {\[} string
        regsub -all {\]} $string {\]} string
        return $string
    }
    
    ad_proc -public util::array_list_spec_pretty { 
        list 
        {indent 0} 
    } {
        Pretty-format an array-list spec with proper indentation.
    } {
        set output {}
        foreach { elm val } $list {
            if { [llength $val] > 1 && [expr {[llength $val] % 2}] == 0  } {
                append output [string repeat " " $indent] "$elm \{" \n
    
                append output [util::array_list_spec_pretty $val [expr {$indent + 4}]]
    
                append output [string repeat " " $indent] \} \n
            } else {
                append output [string repeat " " $indent] [list $elm] " " [list $val] \n
            }
        }
        return $output
    }
    
    ad_proc -public util::interval_pretty {
        {-seconds 0}
    } { 
        Takes a number of seconds and returns a pretty interval of the form "3h 49m 13s"
    } {
        set result {}
        if { $seconds > 0 } {
            set hrs [expr {$seconds / (60*60)}]
            set mins [expr ($seconds / 60) % 60]
            set secs [expr {$seconds % 60}]
            if { $hrs > 0 } { append result "${hrs}h " }
            if { $hrs > 0 || $mins > 0 } { append result "${mins}m " }
            append result "${secs}s"
        }
        return $result
    }
    
    ad_proc -public util::randomize_list {
        list
    } {
        Returns a random permutation of the list.
    } {
        set len [llength $list]
        set result [list]
        while { [llength $list] > 0 } {
            set index [randomRange [llength $list]]
            lappend result [lindex $list $index]
            set list [lreplace $list $index $index]
        }
        return $result
    }
    
    ad_proc -public util::random_list_element {
        list
    } {
        Returns a random element from the list.
    } {
        set len [llength $list]
        set idx [expr {int(rand() * $len)}]
        return [lindex $list $idx]
    }
    
    ad_proc -public util::age_pretty {
        -timestamp_ansi:required
        -sysdate_ansi:required
        {-hours_limit 12}
        {-days_limit 3}
        {-mode_2_fmt "%X, %A"}
        {-mode_3_fmt "%X, %d %b %Y"}
        {-locale ""}
    } {
        Formats past time intervals in one of three different modes depending on age.  The first mode is "1 hour 3 minutes" and is NOT currently internationalized.  The second mode is e.g. "14:10, Thursday" and is internationalized.  The third mode is "14:10, 01 Mar 2001" and is internationalized.  Both the locale and the exact format string for modes 2 and 3 can be overridden by parameters.  (Once mode 1 is i18nd, the following sentence will be true:'In mode 1, only the locale can be overridden.'  Until then, move along.  These aren't the timestamps you're looking for.)
    
        @param timestamp_ansi The older timestamp in full ANSI: YYYY-MM-DD HH24:MI:SS
        @param sysdate_ansi The newer timestamp.
    
        @param hours_limit The upper limit, in hours, for mode 1.
        @param days_limit The upper limit, in days, for mode 2.
        @param mode_2_fmt A formatting string, as per lc_time_fmt, for mode 2
        @param mode_3_fmt A formatting string, as per lc_time_fmt, for mode 3
        @param locale If present, overrides the default locale
        @return Interval between timestamp and sysdate, as localized text string.
    } {
        set age_seconds [expr {[clock scan $sysdate_ansi] - [clock scan $timestamp_ansi]}]
    
        if { $age_seconds < 30 } {
            # Handle with normal processing below -- otherwise this would require another string to localize
            set age_seconds 60
        }
    
       if { $age_seconds < [expr {$hours_limit * 60 * 60}] } {
            set hours [expr {abs($age_seconds / 3600)}]
            set minutes [expr {round(($age_seconds% 3600)/60.0)}]
            if {[expr {$hours < 24}]} {
                switch $hours {
                    0 { set result "" }
                    1 { set result "One hour " }
                    default { set result "$hours hours "}
                }
                switch $minutes {
                    0 {}
                    1 { append result "$minutes minute " }
                    default { append result "$minutes minutes " }
                }
            } else {
                set days [expr {abs($hours / 24)}]
                switch $days {
                    1 { set result "One day " }
                    default { set result "$days days "}
                }
            }
    
            append result "ago"
        } elseif { $age_seconds < [expr {$days_limit * 60 * 60 * 24}] } {
            set result [lc_time_fmt $timestamp_ansi $mode_2_fmt $locale]
        } else {
            set result [lc_time_fmt $timestamp_ansi $mode_3_fmt $locale]
    
        }
    }
    
    
    ad_proc -public util::word_diff {
    	{-old:required}
    	{-new:required}
    	{-split_by {}}
    	{-filter_proc {ad_quotehtml}}
    	{-start_old {}}
    	{-end_old {}}
    	{-start_new {}}
    	{-end_new {}}
    } {
    	Does a word (or character) diff on two lines of text and indicates text
    	that has been deleted/changed or added by enclosing it in
    	start/end_old/new.
    	
    	@param	old	The original text.
    	@param	new	The modified text.
    	
    	@param	split_by	If split_by is a space, the diff will be made
    	on a word-by-word basis. If it is the empty string, it will be made on
    	a char-by-char basis.
    
    	@param	filter_proc	A filter to run the old/new text through before
    	doing the diff and inserting the HTML fragments below. Keep in mind
    	that if the input text is HTML, and the start_old, etc... fragments are
    	inserted at arbitrary locations depending on where the diffs are, you
    	might end up with invalid HTML unless the original HTML is quoted.
    
    	@param	start_old	HTML fragment to place before text that has been removed.
    	@param	end_old		HTML fragment to place after text that has been removed.
    	@param	start_new	HTML fragment to place before new text.
    	@param	end_new		HTML fragment to place after new text.
    
    	@see ad_quotehtml
    	@author Gabriel Burca
    } {
    
    	if {$filter_proc ne ""} {
    		set old [$filter_proc $old]
    		set new [$filter_proc $new]
    	}
    
    	set old_f [ns_tmpnam]
    	set new_f [ns_tmpnam]
    	set old_fd [open $old_f "w"]
    	set new_fd [open $new_f "w"]
    	puts $old_fd [join [split $old $split_by] "\n"]
    	puts $new_fd [join [split $new $split_by] "\n"]
    	close $old_fd
    	close $new_fd
    
    	# Diff output is 1 based, our lists are 0 based, so insert a dummy
    	# element to start the list with.
    	set old_w [linsert [split $old $split_by] 0 {}]
    	set sv 1
    
    #	For debugging purposes:
    #	set diff_pipe [open "| diff -f $old_f $new_f" "r"]
    #	while {![eof $diff_pipe]} {
    #		append res "[gets $diff_pipe]
    " # } set diff_pipe [open "| diff -f $old_f $new_f" "r"] while {![eof $diff_pipe]} { gets $diff_pipe diff if {[regexp {^d(\d+)(\s+(\d+))?$} $diff full m1 m2]} { if {$m2 ne ""} {set d_end $m2} else {set d_end $m1} for {set i $sv} {$i < $m1} {incr i} { append res "${split_by}[lindex $old_w $i]" } for {set i $m1} {$i <= $d_end} {incr i} { append res "${split_by}${start_old}[lindex $old_w $i]${end_old}" } set sv [expr {$d_end + 1}] } elseif {[regexp {^c(\d+)(\s+(\d+))?$} $diff full m1 m2]} { if {$m2 ne ""} {set d_end $m2} else {set d_end $m1} for {set i $sv} {$i < $m1} {incr i} { append res "${split_by}[lindex $old_w $i]" } for {set i $m1} {$i <= $d_end} {incr i} { append res "${split_by}${start_old}[lindex $old_w $i]${end_old}" } while {![eof $diff_pipe]} { gets $diff_pipe diff if {$diff eq "."} { break } else { append res "${split_by}${start_new}${diff}${end_new}" } } set sv [expr {$d_end + 1}] } elseif {[regexp {^a(\d+)$} $diff full m1]} { set d_end $m1 for {set i $sv} {$i < $m1} {incr i} { append res "${split_by}[lindex $old_w $i]" } while {![eof $diff_pipe]} { gets $diff_pipe diff if {$diff eq "."} { break } else { append res "${split_by}${start_new}${diff}${end_new}" } } set sv [expr {$d_end + 1}] } } for {set i $sv} {$i < [llength $old_w]} {incr i} { append res "${split_by}[lindex $old_w $i]" } file delete -- $old_f $new_f return $res } ad_proc -public util::string_length_compare { s1 s2 } { String length comparison function for use with lsort's -command switch. } { set l1 [string length $s1] set l2 [string length $s2] if { $l1 < $l2 } { return -1 } elseif { $l1 > $l2 } { return 1 } else { return 0 } } ad_proc -public util::roll_server_log {{}} { Invoke the AOLserver ns_logroll command with some bookend log records. This rolls the error log, not the access log. } { # This param controlls how many backups of the server log to keep, ns_config -int "ns/parameters" logmaxbackup 10 ns_log Notice "util::roll_server_log: Rolling the server log now..." ns_logroll ns_log Notice "util::roll_server_log: Done rolling the server log." return 0 } ad_proc -public util::cookietime {time} { Return an RFC2109 compliant string for use in "Expires". } { regsub {, (\d+) (\S+) (\d+)} [ns_httptime $time] {, \1-\2-\3} string return $string } ad_proc -public util::find_all_files { {-include_dirs 0} {-max_depth 1} {-check_file_func ""} {-extension ""} {-path:required} } { Returns a list of lists with full paths and filename to all files under $path in the directory tree (descending the tree to a depth of up to $max_depth). Clients should not depend on the order of files returned. DOES NOT WORK ON WINDOWS (you have to change the splitter and I don't know how to detect a windows system) @param include_dirs Should directories be included in the list of files. @param max_depth How many levels of directories should be searched. Defaults to 1 which is the current directory @param check_file_func Function which can be executed upon the file to determine if it is worth the effort @param extension Only return files with this extension (single value !) @param path The path in which to search for the files. Note that this is an absolute Path @return list of lists (filename and full_path) of all files found. } { # Use the examined_files array to track files that we've examined. array set examined_files [list] # A list of files that we will return (in the order in which we # examined them). set files [list] # A list of files that we still need to examine. set files_to_examine [list $path] # Perform a breadth-first search of the file tree. For each level, # examine files in $files_to_examine; if we encounter any directories, # add contained files to $new_files_to_examine (which will become # $files_to_examine in the next iteration). while { [incr max_depth -1] > -2 && [llength $files_to_examine] != 0 } { set new_files_to_examine [list] foreach file $files_to_examine { # Only examine the file if we haven't already. (This is just a safeguard # in case, e.g., Tcl decides to play funny games with symbolic links so # we end up encountering the same file twice.) if { ![info exists examined_files($file)] } { # Remember that we've examined the file. set examined_files($file) 1 if { $check_file_func eq "" || [eval [list $check_file_func $file]] } { # If it's a file, add to our list. If it's a # directory, add its contents to our list of files to # examine next time. set filename [lindex [split $file "/"] end] set file_extension [lindex [split $filename "."] end] if { [file isfile $file] } { if {$extension eq "" || $file_extension eq $extension} { lappend files [list $filename $file] } } elseif { [file isdirectory $file] } { if { $include_dirs == 1 } { lappend files $file } set new_files_to_examine [concat $new_files_to_examine [glob -nocomplain "$file/*"]] } } } } set files_to_examine $new_files_to_examine } return $files } ad_proc -public util::string_check_urlsafe { s1 } { This proc accepts a string and verifies if it is url safe. - make sure there is no space - make sure there is no special characters except '-' or '_' Returns 1 if yes and 0 if not. Meant to be used in the validation section of ad_form. } { return [regexp {[<>:\"|/@\#%&+\\ ]} $s1] } ad_proc -public util::which {prog} { @author Gustaf Neumann Use environment variable PATH to search for the specified executable program. Replacement for UNIX command "which", avoiding exec. exec which: 3368.445 microseconds per iteration ::util::which: 282.372 microseconds per iteration In addition of being more than 10 time faster than the version via exec, this version is less platform dependent. @param prog name of the program to be located on the search path @return fully qualified name including path, when specified program is found, or otherwise empty string } { switch $::tcl_platform(platform) { windows { # # Notice: Windows has an alternative search environment # via registry. Maybe it is necessary in the future # to locate the program via registry (sketch below) # # package require registry # set key {HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths} # set entries [registry keys $key $prog.*] # if {[llength $entries]>0} { # set fullkey "$key\\[lindex $entries 0]" # return [registry get $fullkey ""] # } # return "" # set searchdirs [split $::env(PATH) \;] set exts [list .exe .dll .com .bat] } default { set searchdirs [split $::env(PATH) :] set exts [list ""] } } foreach dir $searchdirs { set fullname [file join $dir $prog] foreach ext $exts { if {[file executable $fullname$ext]} { return $fullname$ext } } } return "" } ad_proc util::catch_exec {command result_var} { Catch a call to Tcl exec. Handle shell return codes consistently. Works like catch. The result of the exec is put into the variable named in result_var. Inspired by http://wiki.tcl.tk/1039 @param command A list of arguments to pass to exec @param result_var Variable name in caller's scope to set the result in @return 0 or 1. 0 if no error, 1 if an error occured. If an error occured the error message will be put into result_var in the caller's scope. @author Dave Bauer @creation-date 2008-01-28 } { upvar result_var result set status [catch [concat exec $command] result] if { $status == 0 } { # The command succeeded, and wrote nothing to stderr. # $result contains what it wrote to stdout, unless you # redirected it ns_log debug "util::catch_exec: Status == 0 $result" } elseif {$::errorCode eq "NONE"} { # The command exited with a normal status, but wrote something # to stderr, which is included in $result. ns_log debug "util::catch_exec: Normal Status $result" } else { switch -exact -- [lindex $::errorCode 0] { CHILDKILLED { foreach { - pid sigName msg } $::errorCode break # A child process, whose process ID was $pid, # died on a signal named $sigName. A human- # readable message appears in $msg. ns_log notice "util::catch_exec: childkilled $pid $sigName $msg $result" set result "process $pid died with signal $sigName \"$msg\"" return 1 } CHILDSTATUS { foreach { - pid code } $::errorCode break # A child process, whose process ID was $pid, # exited with a non-zero exit status, $code. ns_log notice "util::catch_exec: Childstatus $pid $code $result" } CHILDSUSP { foreach { - pid sigName msg } $::errorCode break # A child process, whose process ID was $pid, # has been suspended because of a signal named # $sigName. A human-readable description of the # signal appears in $msg. ns_log notice "util::catch_exec: Child susp $pid $sigName $msg $result" set result "process $pid was suspended with signal $sigName \"$msg\"" return 1 } POSIX { foreach { - errName msg } $::errorCode break # One of the kernel calls to launch the command # failed. The error code is in $errName, and a # human-readable message is in $msg. ns_log notice "util::catch_exec: posix $errName $msg $result" set result "an error occured $errName \"$msg\"" return 1 } } } return 0 } ad_proc util::external_url_p { url } { check if this URL is external to the current host or a valid alternative valid alternatives include HTTPS or HTTP protocol change HTTP or HTTPS port number added or removed from current host name or another hostname that the host responds to (from host_node_map) } { set locations_list [security::locations] # there may be as many as 3 valid full urls from one hostname set external_url_p [util_complete_url_p $url] # more valid url pairs with host_node_map foreach location $locations_list { set encoded_location [ns_urlencode $location] # ns_log Notice "util::external_url_p location \"$location/*\" url $url match [string match "${encoded_location}/*" $url]" set external_url_p [expr { $external_url_p && ![string match "$location/*" $url] } ] set external_url_p [expr { $external_url_p && ![string match "${encoded_location}/*" $url] } ] } return $external_url_p } openacs-5.7.0/packages/acs-tcl/tcl/utilities-procs.xql0000644000175000017500000000134507442266242022561 0ustar frankiefrankie select 1 as one from $table_name where $id_column_name = :generated_id select 1 from dual where exists (select 1 from zip_codes where zip_code like :zip_5) select count(*) from dual where not exists (select 1 from parties where email = lower(:email)) openacs-5.7.0/packages/acs-tcl/tcl/10-charset-compat-procs.tcl0000644000175000017500000000077207265357252023664 0ustar frankiefrankiead_library { Compatibily procs in case we're not running a version of AOLServer that supports charsets. @author Rob Mayoff [mayoff@arsdigita.com] @author Nada Amin [namin@arsdigita.com] @creation-date June 28, 2000 @cvs-id $Id: 10-charset-compat-procs.tcl,v 1.1 2001/04/12 16:58:18 donb Exp $ } set compat_procs [list ns_startcontent ns_encodingfortype] foreach one_proc $compat_procs { if {[llength [info command $one_proc]] == 0} { proc $one_proc {args} { } } } openacs-5.7.0/packages/acs-tcl/tcl/deprecated-utilities-procs.tcl0000644000175000017500000000607711145041201024621 0ustar frankiefrankiead_library { Provides a variety of non-ACS-specific utilities that have been deprecated Note the 5.2 deprecated procs have been moved to deprecated/5.2/acs-tcl @author yon [yon@arsdigita.com] @creation-date 9 Jul 2000 @cvs-id $Id: deprecated-utilities-procs.tcl,v 1.8 2009/02/12 15:38:41 jeffd Exp $ } # if you do a # set selection [ns_db 1row $db "select foo,bar from my_table where key=37"] # set_variables_after_query # then you will find that the Tcl vars $foo and $bar are set to whatever # the database returned. If you don't like these var names, you can say # set selection [ns_db 1row $db "select count(*) as n_rows from my_table"] # set_variables_after_query # and you will find the Tcl var $n_rows set # You can also use this in a multi-row loop # set selection [ns_db select $db "select *,email from mailing_list order by email"] # while { [ns_db getrow $db $selection] } { # set_variables_after_query # ... your code here ... # } # then the appropriate vars will be set during your loop # # CAVEAT NERDOR: you MUST use the variable name "selection" # # # we pick long names for the counter and limit vars # because we don't want them to conflict with names of # database columns or in parent programs # ad_proc -deprecated -warn set_variables_after_query {} { to be removed. @see packages/acs-tcl/tcl/00-database-procs.tcl } { uplevel { set set_variables_after_query_i 0 set set_variables_after_query_limit [ns_set size $selection] while {$set_variables_after_query_i<$set_variables_after_query_limit} { set [ns_set key $selection $set_variables_after_query_i] [ns_set value $selection $set_variables_after_query_i] incr set_variables_after_query_i } } } # as above, but you must use sub_selection ad_proc -deprecated -warn set_variables_after_subquery {} { to be removed. @see packages/acs-tcl/tcl/00-database-procs.tcl } { uplevel { set set_variables_after_query_i 0 set set_variables_after_query_limit [ns_set size $sub_selection] while {$set_variables_after_query_i<$set_variables_after_query_limit} { set [ns_set key $sub_selection $set_variables_after_query_i] [ns_set value $sub_selection $set_variables_after_query_i] incr set_variables_after_query_i } } } #same as philg's but you can: #1. specify the name of the "selection" variable #2. append a prefix to all the named variables ad_proc -deprecated -warn set_variables_after_query_not_selection {selection_variable {name_prefix ""}} { to be removed. @see packages/acs-tcl/tcl/00-database-procs.tcl } { set set_variables_after_query_i 0 set set_variables_after_query_limit [ns_set size $selection_variable] while {$set_variables_after_query_i<$set_variables_after_query_limit} { # NB backslash squarebracket needed since mismatched {} would otherwise mess up value stmt. uplevel " set ${name_prefix}[ns_set key $selection_variable $set_variables_after_query_i] \[ns_set value $selection_variable $set_variables_after_query_i] " incr set_variables_after_query_i } } openacs-5.7.0/packages/acs-tcl/tcl/deprecated-utilities-procs.xql0000644000175000017500000000056507271213363024656 0ustar frankiefrankie update id_numbers set :id_name = :id_name + 1 select unique :id_name from id_numbers openacs-5.7.0/packages/acs-tcl/tcl/aolserver-3-procs.tcl0000644000175000017500000001116111346146745022666 0ustar frankiefrankiead_library { Contains procedures specific to AOLserver 3 (mostly recreating functionality dropped from AOLserver 2). @creation-date 27 Feb 2000 @author Jon Salz [jsalz@arsdigita.com] @cvs-id $Id: aolserver-3-procs.tcl,v 1.6 2010/03/11 11:03:01 gustafn Exp $ } # -1 = Not there or value was "" # 0 = NULL, set value to NULL. # 1 = Got value, set value to it. proc ns_dbformvalue {formdata column type valuebyref} { upvar $valuebyref value if {[ns_set get $formdata $column.NULL] eq "t"} { set value "" return 0 } set value [ns_set get $formdata $column] if { [string match $value ""] } { switch $type { date { set value [ns_buildsqldate \ [ns_set get $formdata $column.month] \ [ns_set get $formdata $column.day] \ [ns_set get $formdata $column.year]] } time { set value [ns_buildsqltime \ [ns_set get $formdata $column.time] \ [ns_set get $formdata $column.ampm]] } datetime - timestamp { set value [ns_buildsqltimestamp \ [ns_set get $formdata $column.month] \ [ns_set get $formdata $column.day] \ [ns_set get $formdata $column.year] \ [ns_set get $formdata $column.time] \ [ns_set get $formdata $column.ampm]] } default { } } } if { [string match $value ""] } { return -1 } else { return 1 } } proc ns_dbformvalueput {htmlform column type value} { switch $type { date { set retval [ns_formvalueput $htmlform $column.NULL f] set retval [ns_formvalueput $retval $column.month \ [ns_parsesqldate month $value]] set retval [ns_formvalueput $retval $column.day \ [ns_parsesqldate day $value]] set retval [ns_formvalueput $retval $column.year \ [ns_parsesqldate year $value]] } time { set retval [ns_formvalueput $htmlform $column.NULL f] set retval [ns_formvalueput $retval $column.time \ [ns_parsesqltime time $value]] set retval [ns_formvalueput $retval $column.ampm \ [ns_parsesqltime ampm $value]] } datetime - timestamp { set retval [ns_formvalueput $htmlform $column.NULL f] set retval [ns_formvalueput $retval $column.month \ [ns_parsesqltimestamp month $value]] set retval [ns_formvalueput $retval $column.day \ [ns_parsesqltimestamp day $value]] set retval [ns_formvalueput $retval $column.year \ [ns_parsesqltimestamp year $value]] set retval [ns_formvalueput $retval $column.time \ [ns_parsesqltimestamp time $value]] set retval [ns_formvalueput $retval $column.ampm \ [ns_parsesqltimestamp ampm $value]] } default { set retval [ns_formvalueput $htmlform $column $value] } } return $retval } proc _ns_updatebutton {table var} { upvar $var updatebutton if { ![info exists updatebutton] } { set updatebutton "" } if { "" eq $updatebutton } { db_with_handle db { set updatebutton [ns_table value $db $table update_button_label] } } if { "" eq $updatebutton } { set updatebutton "Update Record" } } proc _http_read {timeout sock length} { return [_ns_http_read $timeout $sock $length] } ;# _http_read # tcl page support proc ns_putscript {conn ignored} { ns_returnbadrequest $conn "Cannot PUT a script file" } if {[ns_info name] ne "NaviServer"} { # # Naviserver has dropped support for ns_share. # ns_share NS set NS(months) [list January February March April May June \ July August September October November December] } # _ns_dateentrywidget is not very popular and is not # internationalized. We keep it in Naviserver for backward # compatibility. It should become deprecated. proc _ns_dateentrywidget {column} { if {[ns_info name] ne "NaviServer"} { ns_share NS } else { set NS(months) [list January February March April May June \ July August September October November December] } set output "  " return [ns_dbformvalueput $output $column date [lindex [split [ns_localsqltimestamp] " "] 0]] } proc _ns_timeentrywidget {column} { set output " " return [ns_dbformvalueput $output $column time [lindex [split [ns_localsqltimestamp] " "] 1]] } openacs-5.7.0/packages/acs-tcl/tcl/ad-functional-procs.tcl0000644000175000017500000005454111145041201023233 0ustar frankiefrankie# ad-functional-procs.tcl ad_library { Functional Programming in Tcl? - Absolutely!

    This library adds the expressive power of functional languages like LISP, Gofer or Haskell to the Tcl language!

    If you don't know what functional programming is, here's a good place to start:

    A general naming convention in this file is:

    f = a function
    x = an element
    xs = a list of elements @author Mark Dettinger (mdettinger@arsdigita.com) @creation-date March 29, 2000 @last-updated July 25, 2000 @cvs-id $Id: ad-functional-procs.tcl,v 1.7 2009/02/12 15:38:41 jeffd Exp $ This was part of ACS 3 Added to OpenACS by bdolicki on 11 Feb 2004 I just converted proc_doc to ad_proc, added ad_library, fixed an unmatched brace in a doc string and wrapped everything in a namespace } namespace eval ::f { # This library was completely rewritten on July 18, 2000. # The design is now much cleaner. Constructed functions # are no longer represented by strings, but by real # (callable) function objects. The auxiliary functions # eval_unary and eval_binary are gone. # Special thanks go to Sarah Arnold and Carsten Clasohm for extensive # testing of this library and using it in the Sharenet project. # Also many thanks to Branimir Dolicki for inventing the lambda function # and to Archit Shah for finding a simple way to eliminate its memory leak. # -------------------------------------------------------------------------------- # Lambda # -------------------------------------------------------------------------------- ad_proc -public lambda {args body} { The lambda function - one of the foundations of functional programming - defines an anonymous proc and returns it. This is useful if you quickly need an auxiliary function for a small task.

    Examples

    • map [lambda {x} {expr $x*$x}] {1 2 3 4 5}
      = {1 4 9 16 25}
    • zip_with [lambda {x y} {return "$x and $y"}] {1 2 3} {4 5 6}
      = "1 and 4" "2 and 5" "3 and 6"

    Note

    Although lambda defines a proc and therefore consumes memory, executing the same lambda expression twice will just re-define this proc. Thus, there is no memory leak, if you have a lambda inside a loop. } { proc $args.$body $args $body return $args.$body } # I know, I know - it looks sooo harmless. But it unleashes the real power of Tcl. # It defines a proc with name "args.body" (weird, but unique name) that takes "args" # as arguments and has the body "body". Then, this proc is returned. # Example: # [lambda {x} {expr $x*$x}] 5 = 25 # -------------------------------------------------------------------------------- # binding values to arguments of a function # -------------------------------------------------------------------------------- ad_proc -public bind {f args} { binds args to the first k arguments of the n-ary function f and returns the resulting (n-k)-ary function } { set i 0 foreach arg $args { append code "set [lindex [info args $f] $i] {$arg}\n" incr i } append code [info body $f] set proc_args [info args $f] set num_proc_args [llength $proc_args] lambda [lrange $proc_args [llength $args] $num_proc_args] $code } ad_proc -public bind2nd {f arg} "binds arg to the 2nd argument of f" { set code "set [lindex [info args $f] 1] {$arg}\n" append code [info body $f] set proc_args [info args $f] set num_proc_args [llength $proc_args] lambda [cons [head $proc_args] [lrange $proc_args 2 $num_proc_args]] $code } # -------------------------------------------------------------------------------- # We now define several binary operators as procs, so we can pass them # as arguments to other functions. # -------------------------------------------------------------------------------- proc + {a b} {expr {$a + $b}} proc - {a b} {expr {$a - $b}} proc * {a b} {expr {$a * $b}} proc / {a b} {expr {$a / $b}} proc && {a b} {expr {$a && $b}} proc || {a b} {expr {$a || $b}} proc > {a b} {expr {$a > $b}} proc < {a b} {expr {$a < $b}} # Example: # + 5 6 = 11 # -------------------------------------------------------------------------------- # map # -------------------------------------------------------------------------------- ad_proc -public map {f xs} { Takes a function f and a list { x1 x2 x3 ...}, applies the function on each element of the list and returns the result, i.e. { f x1, f x2, f x3, ...}.

    Examples

    (fib = fibonacci function, sqr = square function)
    • Applying a function to each element of a list:
      map fib [list 0 1 2 3 4 5 6 7 8] = {0 1 1 2 3 5 8 13 21}

    • Applying a function to each element of a matrix (a list of lists) can be done with a nested call:
      map [lambda {row} {map sqr $row}] [list [list 1 2 3] [list 4 5 6]] = {{1 4 9} {16 25 36}}
    } { set result {} foreach x $xs { lappend result [$f $x] } return $result } # -------------------------------------------------------------------------------- # fold # -------------------------------------------------------------------------------- ad_proc -public fold {f e xs} { Takes a binary function f, a start element e and a list {x1 x2 ...} and returns f (...(f (f (f e x1) x2) x3)...).

    Examples

    • fold + 0 [list 1 2 3 4] = 10
    • fold * 1 [list 1 2 3 4] = 24
    } { set result $e foreach x $xs { set result [$f $result $x] } return $result } ad_proc -public fold1 {f xs} { Takes a binary function f and a list {x1 x2 x3 ...} and returns (...(f (f (f x1 x2) x3) x4)...).

    "fold1" behaves like "fold", but does not take a start element and does not work for empty lists.

    Examples

    • fold1 min [list 3 1 4 1 5 9 2 6] = 1
    • fold1 max [list 3 1 4 1 5 9 2 6] = 9
    } { if { [null_p $xs] } { error "ERROR: fold1 is undefined for empty lists." } else { fold $f [head $xs] [tail $xs] } } # -------------------------------------------------------------------------------- # scanl # -------------------------------------------------------------------------------- ad_proc -public scanl {f e xs} "takes a binary function f, a start element e and a list {x1 x2 ...} and returns {e (f e x1) (f (f e x1) x2) ...}" { set current_element $e set result [list $e] foreach x $xs { set current_element [$f $current_element $x] lappend result $current_element } return $result } # Example: # scanl + 0 [list 1 2 3 4] = {0 1 3 6 10} # scanl * 1 [list 1 2 3 4] = {1 1 2 6 24} ad_proc -public scanl1 {f xs} "takes a binary function f and a list {x1 x2 x3 ...} and returns {x1 (f x1 x2) (f (f x1 x2) x3) ...}" { if { [null_p $xs] } { error "ERROR: scanl1 is undefined for empty lists." } else { scanl $f [head $xs] [tail $xs] } } # "scanl1" behaves like "scanl", but does not take a start element and # does not work for empty lists. # # Example: # scanl1 min [list 3 1 4 1 5 9 2 6] = {3 1 1 1 1 1 1 1} # scanl1 max [list 3 1 4 1 5 9 2 6] = {3 3 4 4 5 9 9 9} # -------------------------------------------------------------------------------- # Standard combinators # -------------------------------------------------------------------------------- ad_proc -public id {x} { Identity function: just returns its argument.

    I'm not kidding! An identity function can be useful sometimes, e.g. as a default initializer for optional arguments of functional kind. } { return $x } # Example application of id function: ad_proc -public qsort {xs {value id}} "sorts a sequence with the quicksort algorithm" { if { [llength $xs]<2 } { return $xs } set pivot [head $xs] set big_elmts {} set small_elmts {} foreach x [tail $xs] { if { [$value $x] > [$value $pivot] } { lappend big_elmts $x } else { lappend small_elmts $x } } concat [qsort $small_elmts $value] [list $pivot] [qsort $big_elmts $value] } # % qsort {5 2 9 4} # 2 4 5 9 # % qsort {Oracle ArsDigita SAP Vignette} [lambda {s} {string length $s}] # SAP Oracle Vignette ArsDigita ad_proc -public const {k} { Returns a unary function that ignores its argument and constantly returns k.

    Example

    • map [const 7] [list 1 2 3 4 5] = {7 7 7 7 7}
    } { lambda {x} [list return $k] } ad_proc -public curry {f args} { Converts a function that takes one tuple as an argument into a function that takes a series of single arguments. } { uplevel [list $f $args] } ad_proc -public uncurry {f tuple} { Converts a function that takes a series of single arguments into a function that takes one tuple as an argument.

    Example

    • min 3 5 = 3
    • min {3 5} = error (because min expects two arguments)
    • uncurry min {3 5} = 3
    } { uplevel [list eval "$f $tuple"] } # Exercise 1 # ---------- # Using "map" and "uncurry", convert the tuple list # {{3 1} {4 1} {5 9} {2 6}} into {1 1 5 2} (each tuple is replaced # by the minimum of its two components). ad_proc -public fst {xs} "returns the first element of a list" { lindex $xs 0 } ad_proc -public snd {xs} "returns the second element of a list" { lindex $xs 1 } ad_proc -public thd {xs} "returns the third element of a list" { lindex $xs 2 } # Example: # set people [db_list_of_lists get "select first_name, last_name, email ..."] # set first_names [map fst $people] # set last_names [map snd $people] # set emails [map thd $people] ad_proc -public flip {f a b} "takes a binary function f and two arguments a and b and returns f b a (arguments are flipped)" { $f $b $a } # Example: # flip lindex 0 {42 37 59 14} = 42 # Exercise 2 # ---------- # Using "fold", "map", "flip" and "lindex", # compute the sum of the 4th column of the matrix # [list [list 3 1 4 1 5] # [list 9 2 6 5 3] # [list 5 8 9 7 9] # [list 3 2 3 8 4]] # Hint: # First try to extract the list {1 5 7 8} using "map", "flip" and "lindex", # then reduce it to 21 using "fold". ad_proc -public compose {f g x} "function composition: evaluates f (g x)" { $f [$g $x] } # Example: # map [bind compose sqr [bind + 7]] {1 2 3 4 5} = {64 81 100 121 144} # Algebraic Property: # map [bind compose f g] $xs = map f [map g $xs] # -------------------------------------------------------------------------------- # Standard numerical functions # -------------------------------------------------------------------------------- ad_proc -public abs {x} "returns the absolute value of x" { expr {$x<0 ? -$x : $x} } ad_proc -public gcd {x y} "returns the greatest common divisor of x and y" { gcd' [abs $x] [abs $y] } proc gcd' {x y} { if { $y==0 } { return $x } gcd' $y [expr {$x%$y}] } ad_proc -public lcm {x y} "returns the least common multiple of x and y" { if { $x==0} { return 0 } if { $y==0} { return 0 } abs [expr {$x/[gcd $x $y]*$y}] } ad_proc -public odd_p {n} "returns 1 if n is odd and 0 otherwise" { expr {$n%2} } ad_proc -public even_p {n} "returns 1 if n is even and 0 otherwise" { expr {1-$n%2} } ad_proc -public min {x y} "returns the minimum of x and y" { expr {$x<$y ? $x : $y} } ad_proc -public max {x y} "returns the maximum of x and y" { expr {$x>$y ? $x : $y} } # -------------------------------------------------------------------------------- # List Aggregate Functions # -------------------------------------------------------------------------------- ad_proc -public and {xs} "reduces a list of boolean values using &&" { fold && 1 $xs } # Example # and {1 1 0 1} = 0 # and {1 1 1 1} = 1 ad_proc -public or {xs} "reduces a list of boolean values using ||" { fold || 0 $xs } # Example # or {1 1 0 1} = 1 # or {0 0 0 0} = 0 ad_proc -public all {pred xs} { Takes a predicate pred and a list xs and returns 1 if all elements of xs fulfill pred.

    Examples

    • all even_p {2 44 64 80 10} = 1
    • all even_p {2 44 65 80 10} = 0
    } { and [map $pred $xs] } ad_proc -public any {pred xs} "takes a predicate pred and a list xs and returns 1 if there exists an element of xs that fulfills pred" { or [map $pred $xs] } # Example: # any odd_p {2 44 64 80 10} = 0 # any odd_p {2 44 65 80 10} = 1 ad_proc -public lmin {xs} "returns the minimum element of the list xs" { fold1 min $xs } ad_proc -public lmax {xs} "returns the maximum element of the list xs" { fold1 max $xs } ad_proc -public sum {xs} "returns the sum of the elements of the list xs" { fold + 0 $xs } ad_proc -public product {xs} "returns the product of the elements of the list xs" { fold * 1 $xs } ad_proc -public sums {xs} "returns the list of partial sums of the list xs" { scanl + 0 $xs } ad_proc -public products {xs} "returns the list of partial products of the list xs" { scanl * 1 $xs } # -------------------------------------------------------------------------------- # Standard list processing functions # -------------------------------------------------------------------------------- ad_proc -public head {xs} "first element of a list" { lindex $xs 0 } ad_proc -public last {xs} "last element of a list" { lindex $xs [expr {[llength $xs]-1}] } ad_proc -public init {xs} "all elements of a list but the last" { lrange $xs 0 [expr {[llength $xs]-2}] } ad_proc -public tail {xs} "all elements of a list but the first" { lrange $xs 1 [expr {[llength $xs]-1}] } ad_proc -public take {n xs} "returns the first n elements of xs" { lrange $xs 0 [expr {$n-1}] } ad_proc -public drop {n xs} "returns the remaining elements of xs (without the first n)" { lrange $xs $n [expr {[llength $xs]-1}] } ad_proc -public filter {pred xs} { Returns all elements of the list xs that fulfill the predicate pred.

    Examples

    • filter even_p {3 1 4 1 5 9 2 6} = {4 2 6}
    • filter [lambda {x} {expr $x>500}] {317 826 912 318} = {826 912}
    } { set result {} foreach x $xs { if { [$pred $x] } { lappend result $x } } return $result } ad_proc -public copy {n x} "returns list of n copies of x" { set result {} for {set i 0} {$i<$n} {incr i} { lappend result $x } return $result } # Example: # copy 10 7 = {7 7 7 7 7 7 7 7 7 7} ad_proc -public cycle {n xs} "returns concatenated list of n copies of xs" { set result {} for {set i 0} {$i<$n} {incr i} { set result [concat $result $xs] } return $result } # Example: # cycle 4 {1 2 3} = {1 2 3 1 2 3 1 2 3 1 2 3} ad_proc -public cons {x xs} "inserts x at the front of the list xs" { concat [list $x] $xs } ad_proc -public reverse {xs} "reverses the list xs" { fold [bind flip cons] {} $xs } ad_proc -public elem_p {x xs} "checks if x is contained in s" { expr {[lsearch $xs $x]==-1 ? 0 : 1} } ad_proc -public not_elem_p {x xs} "checks if x is not contained in s" { expr {[lsearch $xs $x]==-1 ? 1 : 0} } ad_proc -public nub {xs} "removes duplicates from xs" { set result {} foreach x $xs { if { [not_elem_p $x $result] } { lappend result $x } } return $result } ad_proc -public null_p {xs} "checks if xs is the empty list" { expr {[llength $xs]==0} } ad_proc -public enum_from_to {lo hi} "generates {lo lo+1 ... hi-1 hi}" { set result {} for {set i $lo} {$i<=$hi} {incr i} { lappend result $i } return $result } # -------------------------------------------------------------------------------- # zip and zip_with functions # -------------------------------------------------------------------------------- ad_proc -public zip {args} "takes two lists {x1 x2 x3 ...} and {y1 y2 y3 ...} and returns a list of tuples {x1 y1} {x2 y2} {x3 y3} ... Works analogously with 3 or more lists." { transpose $args } # Example: # % set first_names {Nicole Tom} # % set last_names {Kidman Cruise} # % zip $first_names $last_names # {Nicole Kidman} {Tom Cruise} # % map [bind flip join _] [zip $first_names $last_names] # Nicole_Kidman Tom_Cruise ad_proc -public zip_with {f xs ys} "takes two lists {x1 x2 x3 ...} and {y1 y2 y3 ...} and returns the list {(f x1 y1) (f x2 y2) (f x3 y3) ...}" { set result {} foreach x $xs y $ys { if { !([null_p $x] || [null_p $y]) } { lappend result [$f $x $y] } } return $result } # Example: # % set first_names {Sandra Catherine Nicole} # % set last_names {Bullock Zeta-Jones Kidman} # % zip_with [lambda {f l} {return "$f $l"}] $first_names $last_names # "Sandra Bullock" "Catherine Zeta-Jones" "Nicole Kidman" ad_proc -public transpose {lists} "tranposes a matrix (a list of lists)" { set num_lists [llength $lists] if {!$num_lists} { return "" } for {set i 0} {$i<$num_lists} {incr i} { set l($i) [lindex $lists $i] } set result {} while {1} { set element {} for {set i 0} {$i<$num_lists} {incr i} { if {[null_p $l($i)]} { return $result } lappend element [head $l($i)] set l($i) [tail $l($i)] } lappend result $element } # Note: This function takes about n*n seconds # to transpose a (100*n) x (100*n) matrix. # Pretty fast, don't you think? :) } # -------------------------------------------------------------------------------- # Other Functions (that maybe are too weird for the ACS) # -------------------------------------------------------------------------------- ad_proc -public iterate {n f x} { Returns {x (f x) (f (f x) (f (f (f x))) ...}.

    Examples

    • iterate 10 [lambda {x} {expr $x+1}] 5 = {5 6 7 8 9 10 11 12 13 14}
    • iterate 10 [lambda {x} {expr $x*2}] 1 = {1 2 4 8 16 32 64 128 256 512}
    • iterate 4 tail {1 2 3 4 5} = {1 2 3 4 5} {2 3 4 5} {3 4 5} {4 5}
    } { set result {} for {set i 0} {$i<$n} {incr i} { lappend result $x set x [$f $x] } return $result } ad_proc -public unzip {xs} "unzip takes a list of tuples {x1 y1} {x2 y2} {x3 y3} ... and returns a tuple of lists {x1 x2 x3 ...} {y1 y2 y3 ...}." { set left {} set right {} foreach x $xs { # assertion: x is a tuple lappend left [lindex $x 0] lappend right [lindex $x 1] } return [list $left $right] } # "unzip" is just a special case of the function "transpose" # and is here just for completeness. # -------------------------------------------------------------------------------- # List breaking functions: To gain a real advantage from using these functions, # you would actually need a language that has "lazy evaluation" (like Haskell). # In Tcl they can be useful too, but they are not as powerful. # # split_at n xs = (take n xs, drop n xs) # # take_while p xs returns the longest initial segment of xs whose # elements satisfy p # drop_while p xs returns the remaining portion of the list # span p xs = (takeWhile p xs, dropWhile p xs) # # take_until p xs returns the list of elements upto and including the # first element of xs which satisfies p # # -------------------------------------------------------------------------------- ad_proc -public split_at {n xs} "splits a list using take and drop" { list [take $n $xs] [drop $n $xs] } ad_proc -public take_while {p xs} "returns the longest initial segment of xs whose elements satisfy p" { set index 0 foreach x $xs { if { ![$p $x] } { break } incr index } take $index $xs } ad_proc -public drop_while {p xs} "returns the remaining portion of the list" { set index 0 foreach x $xs { if { ![$p $x] } { break } incr index } drop $index $xs } ad_proc -public span {p xs} "splits a list using take_while and drop_while" { list [take_while $p $xs] [drop_while $p $xs] } ad_proc -public take_until {p xs} "returns the list of elements upto and including the first element of xs which satisfies p" { set index 0 foreach x $xs { incr index if { [$p $x] } { break } } take $index $xs } # -------------------------------------------------------------------------------- # Tests and Experiments # -------------------------------------------------------------------------------- ad_proc -public factorial {n} { compute n! } { product [enum_from_to 1 $n] } ad_proc -public mul {n fraction} "multiplies n with a fraction (given as a tuple)" { set num [fst $fraction] set denom [snd $fraction] set g [gcd $n $denom] expr {($n/$g)*$num/($denom/$g)} } ad_proc -public choose {n k} "Here's how to compute 'n choose k' like a real nerd." { fold mul 1 [transpose [list [iterate $k [bind flip - 1] $n] [enum_from_to 1 $k]]] } ad_proc -public pascal {size} "prints Pascal's triangle" { for {set n 0} {$n<=$size} {incr n} { puts [map [bind choose $n] [enum_from_to 0 $n]] } } ad_proc -public prime_p {n} { @return 1 if n is prime } { if { $n<2 } { return 0 } if { $n==2 } { return 1 } if { [even_p $n] } { return 0 } for {set i 3} {$i*$i<=$n} {incr i 2} { if { $n%$i==0 } { return 0 } } return 1 } # % filter prime_p [enum_from_to 1 100] # 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 proc multiplication_table {x} { # This is an extreme example for test purposes only. # This way of programming is not recommended. Kids: do not try this at home. flip join \n [map [bind compose [bind flip join ""] [bind map [bind compose \ [lambda {s} {format %4d $s}] product]]] \ [map transpose [transpose [list [map [bind copy $x] [enum_from_to 1 $x]] \ [copy $x [enum_from_to 1 $x]]]]]] } # -------------------------------------------------------------------------------- # Literature about functional programming on the web # -------------------------------------------------------------------------------- # http://www.haskell.org/aboutHaskell.html # http://www.md.chalmers.se/~rjmh/Papers/whyfp.html namespace export * } openacs-5.7.0/packages/acs-tcl/tcl/application-link-procs-postgresql.xql0000644000175000017500000000125210247265704026201 0ustar frankiefrankie postgresql7.2 select acs_rel__new ( null, 'application_link', :this_package_id, :target_package_id, :this_package_id, :user_id, :id_addr ) select acs_rel__new ( null, 'application_link', :target_package_id, :this_package_id, :this_package_id, :user_id, :id_addr ) openacs-5.7.0/packages/acs-tcl/tcl/proxy-procs.tcl0000644000175000017500000000173511350250713021675 0ustar frankiefrankie# packages/acs-tcl/tcl/proxy-procs.tcl ad_library { Proxy procs @author () @creation-date 2007-09-17 @cvs-id $Id: proxy-procs.tcl,v 1.4 2010/03/17 22:03:55 victorg Exp $ } # First check that ns_proxy is configured if {![catch {set handler [ns_proxy get exec_proxy]}]} { ns_proxy release $handler namespace eval proxy {} ad_proc -public proxy::exec { {-call} } { Execute the statement in a proxy instead of normal exec @param call Call which is passed to the "exec" command } { set handle [ns_proxy get exec_proxy] with_finally -code { set return_string [ns_proxy eval $handle "exec $call"] } -finally { ns_proxy release $handle } return $return_string } # Now rename exec rename exec real_exec ad_proc exec {args} {This is the wrapped version of exec} {proxy::exec -call $args} } openacs-5.7.0/packages/acs-tcl/tcl/document-init.tcl0000644000175000017500000000051707253523116022153 0ustar frankiefrankiead_library { An API for managing documents. @creation-date 22 May 2000 @author Jon Salz [jsalz@arsdigita.com] @cvs-id $Id: document-init.tcl,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $ } ns_register_adptag ad-document "/ad-document" doc_tag_ad_document ns_register_adptag ad-property "/ad-property" doc_tag_ad_property openacs-5.7.0/packages/acs-tcl/tcl/adp-parser-procs.tcl0000644000175000017500000002701510551254403022553 0ustar frankiefrankiead_library { Routines for a pure-Tcl parser supporting an ADP-like syntax. Tags are registered with doc_register_adptag. To use the parser, either
    • Use doc_adp_execute -file to execute an ADP file, or
    • Compile an ADP using doc_adp_compile, and use doc_adp_execute to executed the compiled ADP.
    Differences from the standard ADP parser include:
    • In handlers for balanced tags (<some-tag> ... </some-tag>), the second argument is not an ADP string, but rather with a handle to ADP code which should be executed with doc_adp_execute in order for the handler to recursively evaluate code.
    • ADPs are never evaluated in the same stack frame as when doc_adp_execute is invoked; each recursively executed ADP code receives its own stack frame as well. This can probably be worked around, if necessary, with a little uplevel magic.
    @author Jon Salz (jsalz@mit.edu) @creation-date 26 June 2000 @cvs-id $Id: adp-parser-procs.tcl,v 1.2 2007/01/10 21:22:11 gustafn Exp $ } # NSV: doc_adptags($tag) is a list representation of an array containing: # # - balanced_p: do we expect a close tag for $tag? # - literal_p: was literal provided to doc_register_adp_tag? # - handler: the name of the handler proc. See document-procs.tcl for some good # examples. ad_proc -public doc_register_adptag { -literal:boolean -balanced:boolean tag handler } { Registers a handler for an ADP tag. @param literal should the handler for a balanced tag accept as its second argument the contents of the block (literally) rather than code to execute? Useful when the contents may contain registered tags which we do not want to be interpreted (e.g., declaring templates with <template>. } { nsv_set doc_adptags $tag [list balanced_p $balanced_p literal_p $literal_p handler $handler] } ad_proc -private doc_adp_quote_tcl_string { string } { Turns literal text into a string which can be used as a Tcl argument. Quotes special Tcl characters and newlines. } { regsub -all {([\{\}\[\]\$\"\\])} $string {\\\1} string regsub -all {\n} $string {\\n} string return "\"$string\"" } ad_proc -private doc_adp_append_code { line } { Helper procedure to append a line of code to the Tcl translation of an ADP. Adds the line of code to the caller's $code variable, indenting depending on the size of the caller's $balanced_tag_stack. } { upvar code code upvar balanced_tag_stack balanced_tag_stack for { set i 0 } { $i < [llength $balanced_tag_stack] } { incr i } { append code " " } append code "$line\n" } ad_proc -private doc_adp_flush_text_buffer {} { Helper procedure to generate a doc_adp_puts call for any text remaining in the text buffer. } { upvar text_buffer text_buffer upvar code code upvar balanced_tag_stack balanced_tag_stack doc_adp_append_code "doc_adp_puts [doc_adp_quote_tcl_string $text_buffer]" set text_buffer "" } ad_proc -private doc_eval_in_separate_frame { __code } { Evaluates __code in a separate stack frame. } { eval $__code } ad_proc -public doc_adp_abort {} { Aborts evaluation of an ADP block. } { error "doc_adp_abort" "" "doc_adp_abort" } ad_proc -public doc_adp_execute_file { -no_cache:boolean file_name } { Compiles and executes an ADP file. Caches the results of compilation unless -no_cache is specified. } { if { $no_cache_p } { # Not caching at all - just read and compile. set file [open $file_name "r"] set adp_code [read $file] close $file set tcl_code [doc_adp_compile $adp_code] } else { set reparse_p 0 set mtime [file mtime $file_name] set size [file size $file_name] # See whether the file has been cached, i.e., the __doc_adp_cache_info,$file_name # proc has been declared. If it has, the proc will return a two-element list # consisting of the mtime/size of the file when it was cached, which we then compare # to the current mtime/size of the file. If they don't match, read in the file, # compile, and save the results in __doc_adp_cache,$file_name; if they do match, # then __doc_adp_cache,$file_name has already been defined. # # We use procs so that the Tcl code can be byte-code-compiled for extra performance # benefit. if { [catch { set info [__doc_adp_cache_info,$file_name] }] || \ [lindex $info 0] != $mtime || \ [lindex $info 1] != $size } { set reparse_p 1 } else { ns_log "Error" "CACHE HIT for $file_name" } if { $reparse_p } { ns_log "Error" "parsing $file_name" set file [open $file_name "r"] set adp_code [read $file] close $file proc __doc_adp_cache,$file_name {} [doc_adp_compile $adp_code] proc __doc_adp_cache_info,$file_name {} "return { $mtime $size }" } set tcl_code "__doc_adp_cache,$file_name" } } ad_proc -public doc_adp_execute { compiled_adp } { Evaluates an ADP block returned by doc_adp_compile. May be invoked recursively by tag handlers. } { global doc_adp_depth if { ![info exists doc_adp_depth] } { set doc_adp_depth 0 } incr doc_adp_depth upvar #0 doc_adp,$doc_adp_depth adp_var set adp_var "" set errno [catch { doc_eval_in_separate_frame $compiled_adp } error] incr doc_adp_depth -1 global errorCode if { $errno == 0 || $errorCode eq "doc_adp_abort" } { return $adp_var } global errorInfo return -code $errno -errorcode $errorCode -errorinfo $errorInfo $error } ad_proc -public doc_adp_puts { value } { Puts a string in the current ADP context. } { global doc_adp_depth upvar #0 doc_adp,$doc_adp_depth adp_var append adp_var $value } ad_proc -public doc_adp_compile { adp } { Compiles a block of ADP code. @return a value which can be passed to doc_adp_execute to run the ADP. } { # A buffer of literal text to output. set text_buffer "" # A stack of tags for which we expect to see end tags. set balanced_tag_stack [list] # The current offset in the $adp character string. set index 0 # The code buffer we're going to return. set code "" set adp_length [string length $adp] while { 1 } { set lt_index [string first "<" $adp $index] if { $lt_index < 0 } { append text_buffer [string range $adp $index end] break } # Append to the text buffer any text before the "<". append text_buffer [string range $adp $index [expr { $lt_index - 1 }]] set index $lt_index if { [info exists tag] } { unset tag } # Note that literal_tag may be set at this point, indicating that we shouldn't # process any tags right now (we should just be looking for the end tag named # . # Currently index points to a "<". incr index if { [string index $adp $index] eq "/" } { set end_tag_p 1 incr index } elseif { ![info exists literal_tag] && [string index $adp $index] == "%" } { doc_adp_flush_text_buffer incr index if { [string index $adp $index] == "=" } { incr index set puts_p 1 } else { set puts_p 0 } set tcl_code_begin $index while { $index < [string length $adp] && \ ([string index $adp $index] != "%" || [string index $adp [expr { $index + 1 }]] != ">") } { incr index } if { $index >= [string length $adp] } { return -code error "Unbalanced Tcl evaluation block" } set tcl_code [string range $adp $tcl_code_begin [expr { $index - 1 }]] if { $puts_p } { doc_adp_append_code "doc_adp_puts \[subst [doc_adp_quote_tcl_string $tcl_code]]" } else { doc_adp_append_code $tcl_code } # Skip the %> at the end. incr index 2 continue } elseif { ![info exists literal_tag] && [string index $adp $index] == "$" } { incr index set tag "var" set end_tag_p 0 } else { set end_tag_p 0 } if { ![info exists tag] } { # Find the next non-word character. set tag_begin $index while { [string index $adp $index] eq "-" || \ [string is wordchar -strict [string index $adp $index]] } { incr index } set tag [string range $adp $tag_begin [expr { $index - 1 }]] } if { (![info exists literal_tag] || ($end_tag_p && $tag eq $literal_tag)) && \ [nsv_exists doc_adptags $tag] } { doc_adp_flush_text_buffer if { [info exists literal_tag] } { unset literal_tag } array set tag_info [nsv_get doc_adptags $tag] # It's a registered tag. Parse the attribute list. set attributes [ns_set create] while { 1 } { # Skip whitespace. while { [string is space -strict [string index $adp $index]] } { incr index } # If it's a >, we're done. if { [string index $adp $index] == ">" } { # Done with attribute list. incr index break } # Not a > - must be an attribute name. set attr_name_begin $index while { $index < $adp_length && \ [string index $adp $index] != ">" && \ [string index $adp $index] != "=" && \ ![string is space -strict [string index $adp $index]] } { incr index } if { $attr_name_begin == $index } { return -code error "Weird attribute format to tag \"$tag\"" } set attr_name [string range $adp $attr_name_begin [expr { $index - 1 }]] if { [string index $adp $index] == "=" } { incr index while { [string is space -strict [string index $adp $index]] } { incr index } if { [string index $adp $index] eq "\"" } { # Quoted string. set value_begin [incr index] while { $index < $adp_length && [string index $adp $index] ne "\"" } { incr index } set value_end $index incr index } else { set value_begin $index while { $index < $adp_length && \ [string index $adp $index] != ">" && \ [string index $adp $index] != "=" && \ ![string is space -strict [string index $adp $index]] } { incr index } set value_end $index } ns_set put $attributes $attr_name [string range $adp $value_begin [expr { $value_end - 1 }]] } else { ns_set put $attributes $attr_name $attr_name } } if { $end_tag_p } { if { [llength $balanced_tag_stack] == 0 } { return -code error "Unexpected end tag " } if { $tag ne [lindex $balanced_tag_stack end] } { return -code error "Expected end tag to be , not " } set balanced_tag_stack [lrange $balanced_tag_stack 0 [expr { [llength $balanced_tag_stack] - 2 }]] doc_adp_append_code "\}" } else { doc_adp_append_code "set __doc_attributes \[ns_set create\]" for { set i 0 } { $i < [ns_set size $attributes] } { incr i } { doc_adp_append_code "ns_set put \$__doc_attributes [doc_adp_quote_tcl_string [ns_set key $attributes $i]] [doc_adp_quote_tcl_string [ns_set value $attributes $i]]" } if { $tag_info(balanced_p) } { doc_adp_append_code "$tag_info(handler) \$__doc_attributes \{" lappend balanced_tag_stack $tag if { $tag_info(literal_p) } { # Remember that we're inside a literal tag. set literal_tag $tag } } else { doc_adp_append_code "$tag_info(handler) \$__doc_attributes" } } } else { append text_buffer [string range $adp $lt_index [expr { $index - 1 }]] } } if { [llength $balanced_tag_stack] > 0 } { return -code error "Expected end tag but got end of file" } doc_adp_flush_text_buffer return $code } openacs-5.7.0/packages/acs-tcl/tcl/widgets-procs.tcl0000644000175000017500000003371311565422762022200 0ustar frankiefrankiead_library { UI widgets for use in forms, etc. @cvs-id $Id: widgets-procs.tcl,v 1.16.4.1 2011/05/20 08:27:30 victorg Exp $ } ad_proc state_widget { {default ""} {select_name "usps_abbrev"}} "Returns a state selection box" { set widget_value "\n" return $widget_value } ad_proc country_widget { {default ""} {select_name "country_code"} {size_subtag "size=4"}} "Returns a country selection box" { set widget_value "\n" return $widget_value } # teadams - It is usually more approprate to use html_select_options or # html_select_value_options. ad_proc ad_generic_optionlist {items values {default ""}} "Use this to build select form fragments. Given a list of items and a list of values, will return the option tags with default highlighted as appropriate." { # items is a list of the items you would like the user to select from # values is a list of corresponding option values # default is the value of the item to be selected set count 0 set return_string "" foreach value $values { if { $default eq $value } { append return_string "\n" } else { append return_string "\n" } incr count } return $return_string } # use ad_integer_optionlist instead of day_list proc day_list {} { return {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31} } ad_proc month_list {} "Returns list of month abbreviations" { return {Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec} } ad_proc long_month_list {} "Returns list of months" { return {January February March April May June July August September October November December} } # use ad_integer_optionlist instead of month_value_list proc month_value_list {} { return {1 2 3 4 5 6 7 8 9 10 11 12} } ad_proc future_years_list {{num_year 10}} "Returns a list containing the next num_year years in the future." { set year [ns_fmttime [ns_time] %Y] set counter 0 while {$counter < $num_year } { incr counter lappend year_list $year incr year } return $year_list } # produces the optionlist for a range of integers # if pad_to_two_p is 1, the option values will be # padded to 2 digites with a leading 0 ad_proc ad_integer_optionlist {start_value end_value {default ""} { pad_to_two_p 0} } "Produces an optionlist for a range of integers from start_value to end_value. If default matches one of the options, it is selection. If pad_to_two_p is 1, the option values will be padded to 2 digites with a leading 0." { # items is a list of the items you would like the user to select from # values is a list of corresponding option values # default is the value of the item to be selected set count 0 set return_string "" for { set x $start_value } { $x <= $end_value } { incr x } { if { $pad_to_two_p && $x >= 0 && $x < 10 } { set value "0$x" } else { set value $x } if { $default == $value } { append return_string "\n" } else { append return_string "\n" } } return $return_string } ad_proc ad_dateentrywidget {column { value 0 } } { Returns form pieces for a date entry widget. A null date may be selected. } { # if you would like the default to be null, call with value= "" if {[ns_info name] ne "NaviServer"} { ns_share NS } else { set NS(months) [list January February March April May June \ July August September October November December] } if { $value == 0 } { # no default, so use today set value [lindex [split [ns_localsqltimestamp] " "] 0] } set date_parts [split $value "-"] if { $value eq "" } { set month "" set day "" set year "" } else { set date_parts [split $value "-"] set month [lindex $date_parts 1] set year [lindex $date_parts 0] set day [lindex $date_parts 2] } set output " " return $output } ad_proc ad_db_select_widget { { -size 0 -multiple 0 -default {} -option_list {} -blank_if_no_db 0 -hidden_if_one_db 0 -bind {} } statement_name sql_qry name } { given a sql query this generates a select group. If there is only one value it returns the text and a hidden variable setting that value. The first selected column should contain the optionlist items. The second selected column should contain the optionlist values.

    option_list is a list in the same format (i.e. {{str val} {str2 val2}...}) which is prepended to the list

    if sql_qry is null then the list is constructed from option_list only.

    if there is only one item the select is not generated and the value is passed in hidden form variable.

    if -multiple is given the a multi select is returned.

    if -blank_if_no_db set then do not return a select widget unless there are rows from the database } { set retval {} set count 0 set dbcount 0 if {$option_list ne ""} { foreach opt $option_list { incr count set item [lindex $opt 1] set value [lindex $opt 0] if { (!$multiple && $value eq $default ) || ($multiple && [lsearch -exact $default $value] > -1)} { append retval "\n" } else { append retval "\n" } } } if { $blank_if_no_db} { set count 0 } if {$sql_qry ne ""} { set columns [ns_set create] db_foreach $statement_name $sql_qry -column_set selection -bind $bind { incr count incr dbcount set item [ns_set value $selection 0] set value [ns_set value $selection 1] if { (!$multiple && $value eq $default ) || ($multiple && [lsearch -exact $default $value] > -1)} { append retval "\n" } else { append retval "\n" } } if_no_rows { if {$default ne ""} { return "\n" } else { return {} } } } if { $count == 1 || ($dbcount == 1 && $hidden_if_one_db) } { return "$item\n" } elseif {!$count && !$dbcount && $blank_if_no_db} { return {} } else { set select "" } } ad_proc currency_widget {{default ""} {select_name "currency_code"} {size_subtag "size=\"4\""}} "Returns a currency selection box" { set widget_value "\n" return $widget_value } ad_proc ad_html_colors {} "Returns an array of HTML colors and names." { return { { Black 0 0 0 } { Silver 192 192 192 } { Gray 128 128 128 } { White 255 255 255 } { Maroon 128 0 0 } { Red 255 0 0 } { Purple 128 0 128 } { Fuchsia 255 0 255 } { Green 0 128 0 } { Lime 0 255 0 } { Olive 128 128 0 } { Yellow 255 255 0 } { Navy 0 0 128 } { Blue 0 0 255 } { Teal 0 128 128 } { Aqua 0 255 255 } } } ad_proc ad_color_widget_js {} "Returns JavaScript code necessary to use color widgets." { return { var adHexTupletValues = '0123456789ABCDEF'; function adHexTuplet(val) { return adHexTupletValues.charAt(Math.floor(val / 16)) + adHexTupletValues.charAt(Math.floor(val % 16)); } function adUpdateColorText(field) { var form = document.forms[0]; var element = form[field + ".list"]; var rgb = element.options[element.selectedIndex].value; var r,g,b; if (rgb == "" || rgb == "none" || rgb == "custom") { r = g = b = ""; } else { var components = rgb.split(","); r = components[0]; g = components[1]; b = components[2]; } form[field + ".c1"].value = r; form[field + ".c2"].value = g; form[field + ".c3"].value = b; document['color_' + field].src = '/shared/1pixel.tcl?r=' + r + '&g=' + g + '&b=' + b; } function adUpdateColorList(field) { var form = document.forms[0]; var element = form[field + ".list"]; var c1 = form[field + ".c1"].value; var c2 = form[field + ".c2"].value; var c3 = form[field + ".c3"].value; if (c1 != parseInt(c1) || c2 != parseInt(c2) || c3 != parseInt(c3) || c1 < 0 || c2 < 0 || c3 < 0 || c1 > 255 || c2 > 255 || c3 > 255) { element.selectedIndex = 1; document['color_' + field].src = '/shared/1pixel.tcl?r=255&g=255&b=255'; return; } document['color_' + field].src = '/shared/1pixel.tcl?r=' + c1 + '&g=' + c2 + '&b=' + c3; var rgb = parseInt(form[field + ".c1"].value) + "," + parseInt(form[field + ".c2"].value) + "," + parseInt(form[field + ".c3"].value); var found = 0; for (var i = 0; i < element.length; ++i) if (element.options[i].value == rgb) { element.selectedIndex = i; found = 1; break; } if (!found) element.selectedIndex = 0; } } } ad_proc ad_color_widget { name default { use_js 0 } } "Returns a color selection widget, optionally using JavaScript. Default is a string of the form '0,192,255'." { set out "
    \n" if { ![regexp {^([0-9]+),([0-9]+),([0-9]+)$} $default all c1 c2 c3] } { set c1 "" set c2 "" set c3 "" } foreach component { c1 c2 c3 } { append out " " } if { $use_js == 1 } { if { $c1 eq "" } { set c1 255 set c2 255 set c3 255 } append out "  " } append out "
    \n" return $out } ad_proc ad_process_color_widgets args { Sets variables corresponding to the color widgets named in $args. } { foreach field $args { upvar $field var set var [ns_queryget "$field.list"] if { $var eq "custom" } { set var "[ns_queryget "$field.c1"],[ns_queryget "$field.c2"],[ns_queryget "$field.c3"]" } if { ![regexp {^([0-9]+),([0-9]+),([0-9]+)$} $var "" r g b] || $r > 255 || $g > 255 || $b > 255 } { set var "" } } } ad_proc ad_color_to_hex { triplet } { Converts a string of the form 0,192,255 to a string of the form #00C0FF. } { if { [regexp {^([0-9]+),([0-9]+),([0-9]+)$} $triplet all r g b] } { return "#[format "%02x%02x%02x" $r $g $b]" } else { return "" } } openacs-5.7.0/packages/acs-tcl/tcl/widgets-procs.xql0000644000175000017500000000112407365347526022220 0ustar frankiefrankie select state_name, abbrev from states order by state_name select default_name, iso from countries order by default_name select currency_name, iso from currency_codes where supported_p='t' order by currency_name openacs-5.7.0/packages/acs-tcl/tcl/30-xml-utils-procs.tcl0000644000175000017500000000567610551254403022704 0ustar frankiefrankie# This is a set of utilities for dealing with XML in a nice way, # using tDOM. # # It would be nice if this could be used without the ACS, so we're not # using ad_proc constructs for this at this point. ## ## The proc that checks that XML support is complete ## proc xml_support_ok {varname} { upvar $varname xml_status_msg set ok_p 1 if {[llength [info commands tdom]] < 1} { set xml_status_msg "tDOM is not installed! You must have tDOM installed, or nothing will work." set ok_p 0 } return $ok_p } # Parse a document and return a doc_id proc xml_parse args { # ns_log notice "xml_parse $args" if {[lindex $args 0] eq "-persist"} { return [dom parse -simple [lindex $args 1]] } else { dom parse -simple [lindex $args 0] doc return $doc } } # Free the doc proc xml_doc_free {doc_id} { # ns_log notice "xml_doc_free $doc_id" $doc_id delete } # Get first node proc xml_doc_get_first_node {doc_id} { # ns_log notice "xml_doc_get_first_node $doc_id --> [[$doc_id documentElement] nodeName]" return [$doc_id documentElement] } # Get children nodes proc xml_node_get_children {parent_node} { return [$parent_node child all] } # Find nodes of a parent that have a given name proc xml_node_get_children_by_name {parent_node name} { # set msg "xml_node_get_children_by_name [$parent_node nodeName] $name --> " # foreach child [$parent_node child all $name] { # append msg "[$child nodeName] " # } # ns_log notice $msg return [$parent_node child all $name] } proc xml_node_get_first_child {parent_node } { # ns_log notice "xml_node_get_first_child [$parent_node nodeName] --> [[$parent_node child 1] nodeName]" return [$parent_node child 1] } proc xml_node_get_first_child_by_name {parent_node name} { # ns_log notice "xml_node_get_first_child_by_name [$parent_node nodeName] $name --> [[$parent_node child 1 $name] nodeName]" return [$parent_node child 1 $name] } # Get Node Name proc xml_node_get_name {node_id} { return [$node_id nodeName] } # Get Node Attribute proc xml_node_get_attribute {node_id attribute_name {default ""}} { # ns_log notice "xml_node_get_attribute [$node_id nodeName] $attribute_name --> [$node_id getAttribute $attribute_name $default]" return [$node_id getAttribute $attribute_name $default] } # Set Node Attribute proc xml_node_set_attribute {node_id attribute_name value} { $node_id setAttribute $attribute_name $value } # Get Content proc xml_node_get_content {node_id} { # ns_log notice "xml_node_get_content [$node_id nodeName] --> [$node_id text]" return [$node_id text] } # Get Node Type proc xml_node_get_type {node_id} { return [$node_id nodeType] } # Render the doc proc xml_doc_render {doc_id {indent_p f}} { if { [string is true $indent_p] } { return [$doc_id asXML] } else { return [$doc_id asXML -indent none] } } proc xml_node_get_children_by_select {parent_node xpath} { return [$parent_node selectNodes $xpath] } openacs-5.7.0/packages/acs-tcl/tcl/request-processor-procs.tcl0000644000175000017500000015177411527017545024244 0ustar frankiefrankiead_library { The ACS Request Processor: the set of routines called upon every single HTTP request to an ACS server. @author Jon Salz (jsalz@arsdigita.com) @creation-date 15 May 2000 @cvs-id $Id: request-processor-procs.tcl,v 1.104 2011/02/16 19:03:01 daveb Exp $ } ##### # # PUBLIC API # ##### ad_proc -public rp_internal_redirect { -absolute_path:boolean path } { Tell the request processor to return some other page. The path can either be relative to the current directory (e.g. "some-template") relative to the server root (e.g. "/packages/my-package/www/some-template"), or an absolute path (e.g. "/home/donb/openacs-4/templates/some-cms-template"). When there is no extension then the request processor will choose the matching file according to the extension preferences. Parameters will stay the same as in the initial request. Keep in mind that if you do an internal redirect to something other than the current directory, relative links returned to the clients browser may be broken (since the client will have the original URL). Use rp_form_put or rp_form_update if you want to feed query variables to the redirected page. @param absolute_path If set the path is an absolute path within the host filesystem @param path path to the file to serve @see rp_form_put, rp_form_update } { # protect from circular redirects global __rp_internal_redirect_recursion_counter if { ![info exists __rp_internal_redirect_recursion_counter] } { set __rp_internal_redirect_recursion_counter 0 } elseif { $__rp_internal_redirect_recursion_counter > 10 } { error "rp_internal_redirect: Recursion limit exceeded." } else { incr __rp_internal_redirect_recursion_counter } if { [string is false $absolute_path_p] } { if { [string index $path 0] ne "/" } { # it's a relative path, prepend the current location set path "[file dirname [ad_conn file]]/$path" } else { set path "[acs_root_dir]$path" } } # save the current file setting set saved_file [ad_conn file] rp_serve_abstract_file $path # restore the file setting. we need to do this because # rp_serve_abstract_file sets it to the path we internally # redirected to, and rp_handler will cache the file setting # internally in the tcl_url2file variable when PerformanceModeP is # switched on. This way it caches the location that was originally # requested, not the path that we redirected to. ad_conn -set file $saved_file } ad_proc rp_getform {} { This proc is a simple wrapper around AOLserver's standard ns_getform proc, that will create the form if it doesn't exist, so that you can then add values to that form. This is useful in conjunction with rp_internal_redirect to redirect to a different page with certain query variables set. @author Lars Pind (lars@pinds.com) @creation-date August 20, 2002 @return the form ns_set, just like ns_getform, except it will always be non-empty. } { # The form may not exist, if there's nothing in it if { ![empty_string_p [ns_getform]] } { # It's there return [ns_getform] } { # It doesn't exist, create a new one # This is the magic global Tcl variable that AOLserver uses # to store the ns_set that contains the query args or form. global _ns_form # Simply create a new ns_set and store it in the global _ns_set variable set _ns_form [ns_set create] return $_ns_form } } ad_proc rp_form_put { name value } { This proc adds a query variable to AOLserver's internal ns_getform form, so that it'll be picked up by ad_page_contract and other procs that look at the query variables or form supplied. This is useful when you do an rp_internal_redirect to a new page, and you want to feed that page with certain query variables. Note that the variable will just be appended to the form ns_set which may not be what you want, if it exists already you will now have two entries in the ns_set which may cause ad_page_contract to break. Also, only simple variables may be added, not arrays. @author Lars Pind (lars@pinds.com) @creation-date August 20, 2002 @return the form ns_set, in case you're interested. Mostly you will want to discard the result. } { set form [rp_getform] ns_set put $form $name $value return $form } ad_proc rp_form_update { name value } { Identical to rp_form_put, but uses ns_set update instead. @return the form ns_set, in case you're interested. Mostly you will want to discard the result. } { set form [rp_getform] ns_set update $form $name $value return $form } ad_proc ad_return { args } { Works like the "return" Tcl command, with one difference. Where "return" will always return TCL_RETURN, regardless of the -code switch this way, by burying it inside a proc, the proc will return the code you specify.

    Why? Because "return" only sets the "returnCode" attribute of the interpreter object, which the function actually interpreting the procedure then reads and uses as the return code of the procedure. This proc adds just that level of processing to the statement.

    When is that useful or necessary? Here:

      set errno [catch {
        return -code error "Boo!"
      } error]
      
    In this case, errno will always contain 2 (TCL_RETURN). If you use ad_return instead, it'll contain what you wanted, namely 1 (TCL_ERROR). } { eval return $args } ad_proc -private rp_registered_proc_info_compare { info1 info2 } { A comparison predicate for registered procedures, returning -1, 0, or 1 depending the relative sorted order of $info1 and $info2 in the procedure list. Items with longer paths come first. } { set info1_path [lindex $info1 1] set info2_path [lindex $info2 1] set info1_path_length [string length $info1_path] set info2_path_length [string length $info2_path] if { $info1_path_length < $info2_path_length } { return 1 } if { $info1_path_length > $info2_path_length } { return -1 } return 0 } ad_proc -public ad_register_proc { -sitewide:boolean { -debug f } { -noinherit f } { -description "" } method path proc { arg "" } } { Registers a procedure (see ns_register_proc for syntax). Use a method of "*" to register GET, POST, and HEAD filters. If debug is set to "t", all invocations of the procedure will be logged in the server log. @param sitewide specifies that the filter should be applied on a sitewide (not subsite-by-subsite basis). } { if {$method eq "*"} { # Shortcut to allow registering filter for all methods. Just # call ad_register_proc again, with each of the three methods. foreach method { GET POST HEAD } { ad_register_proc -debug $debug -noinherit $noinherit $method $path $proc $arg } return } if { [lsearch -exact { GET POST HEAD } $method] == -1 } { error "Method passed to ad_register_proc must be one of GET, POST, or HEAD" } set proc_info [list $method $path $proc $arg $debug $noinherit $description [info script]] nsv_lappend rp_registered_procs . $proc_info } ad_proc -private rp_invoke_filter { conn filter_info why } { Invokes the filter described in $argv, writing an error message to the browser if it fails (unless kind is trace). } { set startclicks [clock clicks -milliseconds] util_unlist $filter_info filter_index debug_p arg_count proc arg rp_debug -debug $debug_p "Invoking $why filter $proc" switch $arg_count { 0 { set errno [catch { set result [$proc] } error] } 1 { set errno [catch { set result [$proc $why] } error] } 2 { set errno [catch { set result [$proc $conn $why] } error] } default { set errno [catch { ad_try { set result [$proc $conn $arg $why] } ad_script_abort val { set result "filter_return" } } error] } } global errorCode if { $errno } { # Uh-oh - an error occurred. global errorInfo ds_add rp [list filter [list $why [ns_conn method] [ns_conn url] $proc $arg] $startclicks [clock clicks -milliseconds] "error" $errorInfo] # make sure you report catching the error! rp_debug "error in filter $proc for [ns_conn method] [ns_conn url]?[ns_conn query] errno is $errno message is $errorInfo" rp_report_error set result "filter_return" } elseif {$result ne "filter_ok" && $result ne "filter_break" && \ [string compare $result "filter_return"] } { set error_msg "error in filter $proc for [ns_conn method] [ns_conn url]?[ns_conn query]. Filter returned invalid result \"$result\"" ds_add rp [list filter [list $why [ns_conn method] [ns_conn url] $proc $arg] $startclicks [clock clicks -milliseconds] "error" $error_msg] # report the bad filter_return message rp_debug -debug t -ns_log_level error $error_msg rp_report_error -message $error_msg set result "filter_return" } else { ds_add rp [list filter [list $why [ns_conn method] [ns_conn url] $proc $arg] $startclicks [clock clicks -milliseconds] $result] } rp_debug -debug $debug_p "Done invoking $why filter $proc (returning $result)" # JCD: Why was this here? the rp_finish_serving_page is called inside the # handlers and this handles trace filters # if {$result ne "filter_return" } { # rp_finish_serving_page # } return $result } ad_proc -private rp_invoke_proc { conn argv } { Invokes a registered procedure. } { set startclicks [clock clicks -milliseconds] util_unlist $argv proc_index debug_p arg_count proc arg rp_debug -debug $debug_p "Invoking registered procedure $proc" switch $arg_count { 0 { set errno [catch $proc error] } 1 { set errno [catch "$proc $arg" error] } default { set errno [catch { ad_try { $proc [list $conn] $arg } ad_script_abort val { # do nothing } } error] } } global errorCode if { $errno } { # Uh-oh - an error occurred. global errorInfo ds_add rp [list registered_proc [list $proc $arg] $startclicks [clock clicks -milliseconds] "error" $errorInfo] rp_debug "error in $proc for [ns_conn method] [ns_conn url]?[ns_conn query] errno is $errno message is $errorInfo" rp_report_error } else { ds_add rp [list registered_proc [list $proc $arg] $startclicks [clock clicks -milliseconds]] } rp_debug -debug $debug_p "Done Invoking registered procedure $proc" rp_finish_serving_page } ad_proc -private rp_finish_serving_page {} { global doc_properties if { [info exists doc_properties(body)] } { rp_debug "Returning page:[info level [expr {[info level] - 1}]]: [ad_quotehtml [string range $doc_properties(body) 0 100]]" doc_return 200 text/html $doc_properties(body) } } ad_proc -public ad_register_filter { { -debug f } { -priority 10000 } { -critical f } { -description "" } kind method path proc { arg "" } } { Registers a filter that gets called during page serving. The filter should return one of
    • filter_ok, meaning the page serving will continue;
    • filter_break meaning the rest of the filters of this type will not be called;
    • filter_return meaning the server will close the connection and end the request processing.
    @param kind Specify preauth, postauth or trace. @param method Use a method of "*" to register GET, POST, and HEAD filters. @param priority Priority is an integer; lower numbers indicate higher priority. @param critical If a filter is critical, page viewing will abort if a filter fails. @param debug If debug is set to "t", all invocations of the filter will be ns_logged. @param sitewide specifies that the filter should be applied on a sitewide (not subsite-by-subsite basis). } { if {$method eq "*"} { # Shortcut to allow registering filter for all methods. foreach method { GET POST HEAD } { ad_register_filter -debug $debug -priority $priority -critical $critical $kind $method $path $proc $arg } return } if { [lsearch -exact { GET POST HEAD } $method] == -1 } { error "Method passed to ad_register_filter must be one of GET, POST, or HEAD" } # Append the filter to the list. The list will be sorted according to priority # and the filters will be bulk-registered after package-initialization. # Also, the "Monitoring" package will be able to list the filters in this list. nsv_lappend rp_filters . \ [list $priority $kind $method $path $proc $arg $debug $critical $description [info script]] # Register the filter immediately if the call is not from an *-init.tcl script. if { ![apm_first_time_loading_p] } { # Figure out how to invoke the filter, based on the number of arguments. if { [llength [info procs $proc]] == 0 } { # [info procs $proc] returns nothing when the procedure has been # registered by C code (e.g., ns_returnredirect). Assume that neither # "conn" nor "why" is present in this case. set arg_count 1 } else { set arg_count [llength [info args $proc]] } set filter_index {} ns_register_filter $kind $method $path rp_invoke_filter [list $filter_index $debug $arg_count $proc $arg] } } ad_proc -private rp_html_directory_listing { dir } { Generates an HTML-formatted listing of a directory. This is mostly stolen from _ns_dirlist in an AOLserver module (fastpath.tcl). } { # Create the table header. set list " " # Loop through the files, adding a row to the table for each. foreach file [lsort [glob -nocomplain $dir/*]] { set tail [file tail $file] set link "$tail" # Build the stat array containing information about the file. file stat $file stat set size [expr {$stat(size) / 1000 + 1}]K set mtime $stat(mtime) set time [clock format $mtime -format "%d-%h-%Y %H:%M"] # Write out the row. append list "\n" } append list "
    FileSizeDate
    ..
    $link$size$time
    " return $list } ##### # # NSV arrays used by the request processor: # # - rp_filters($method,$kind), where $method in (GET, POST, HEAD) # and kind in (preauth, postauth, trace) A list of $kind filters # to be considered for HTTP requests with method $method. The # value is of the form # # [list $priority $kind $method $path $proc $args $debug \ # $critical $description $script] # # - rp_registered_procs($method), where $method in (GET, POST, HEAD) # A list of registered procs to be considered for HTTP requests with # method $method. The value is of the form # # [list $method $path $proc $args $debug $noinherit \ # $description $script] # # - rp_system_url_sections($url_section) # Indicates that $url_section is a system directory (like # SYSTEM) which is exempt from Host header checks and # session/security handling. # # ad_register_filter and ad_register_procs are used to add elements to # these NSVs. We use lists rather than arrays for these data # structures since "array get" and "array set" are rather expensive # and we want to keep lookups fast. # ##### ad_proc -private rp_resources_filter { why } { This filter runs on all URLs of the form /resources/*. The acs-resources package mounts itself at /resources but we short circuit references here in order to maximize throughput for resource files. We just ns_returnfile the file, no permissions are checked, the ad_conn structure is not initialized, etc. There are two mapping possibilities: /resources/package-key/* maps to root/packages/package-key/www/resources/* If that fails, we map to root/www/resources/* If the file doesn't exist we'll log an error and return filter_ok, which will allow packages mounted at "/resources" in a legacy site to work correctly. This is a horrible kludge which may disappear after discussion with the gang. @author Don Baccus (dhogaza@pacifier.com) } { set path "[acs_package_root_dir [lindex [ns_conn urlv] 1]]/www/resources/[join [lrange [ns_conn urlv] 2 end] /]" if { ![file isfile $path] } { set path "[acs_root_dir]/www/resources/[join [lrange [ns_conn urlv] 1 end] /]" } if { [file isfile $path] } { ns_returnfile 200 [ns_guesstype $path] $path return filter_return } else { ns_log Error "rp_sources_filter: file \"$path\" does not exists trying to serve as a normal request" return filter_ok } } ad_proc -private rp_filter { why } { This is the first filter that runs for non-resource URLs. It sets up ad_conn and handles session security. } { ##### # # Initialize the environment: reset ad_conn, and populate it with # a few things. # ##### ad_conn -reset ad_conn -set request [nsv_incr rp_properties request_count] ad_conn -set user_id 0 ad_conn -set start_clicks [clock clicks -milliseconds] ds_collect_connection_info # ------------------------------------------------------------------------- # Start of patch "hostname-based subsites" # ------------------------------------------------------------------------- # 1. determine the root of the host and the requested URL set root [root_of_host [ad_host]] set url [ad_conn url] # 2. handle special case: if the root is a prefix of the URL, # remove this prefix from the URL, and redirect. if { $root ne "" } { if { [regexp "^${root}(.*)$" $url match url] } { if { [regexp {^GET [^\?]*\?(.*) HTTP} [ns_conn request] match vars] } { append url ?$vars } if { [security::secure_conn_p] } { # it's a secure connection. ad_returnredirect \ -allow_complete_url https://[ad_host][ad_port]$url return "filter_return" } else { ad_returnredirect \ -allow_complete_url http://[ad_host][ad_port]$url return "filter_return" } } # Normal case: Prepend the root to the URL. # 3. set the intended URL ad_conn -set url ${root}${url} # 4. set urlv and urlc for consistency set urlv [lrange [split $root /] 1 end] ad_conn -set urlc [expr [ad_conn urlc]+[llength $urlv]] ad_conn -set urlv [concat $urlv [ad_conn urlv]] } # ------------------------------------------------------------------------- # End of patch "hostname-based subsites" # ------------------------------------------------------------------------- # Force the URL to look like [ns_conn location], if desired... # JCD: Only do this if ForceHostP set and root is {} # if root non empty then we had a hostname based subsite and # should not redirect since we got a hostname we know about. ### BLOCK NASTY YAHOO START set headers [ns_conn headers] set user_agent [ns_set iget $headers User-Agent] ns_log Debug "user agent is $user_agent" set match_seeker [regexp ".*YahooSeeker.*" $user_agent] set match_slurp [regexp ".*Yahoo! Slurp.*" $user_agent] if {$match_seeker == 1 || $match_slurp == 1} { ns_log Notice "nasty spider $user_agent" ns_returnredirect "http://www.yahoo.com" return "filter_return" } ## BLOCK NASTY YAHOO FINISH set acs_kernel_id [util_memoize ad_acs_kernel_id] if { $root eq "" && [parameter::get -package_id $acs_kernel_id -parameter ForceHostP -default 0] } { set host_header [ns_set iget [ns_conn headers] "Host"] regexp {^([^:]*)} $host_header "" host_no_port regexp {^https?://([^:]+)} [ns_conn location] "" desired_host_no_port if { $host_header ne "" && $host_no_port ne $desired_host_no_port } { set query [ns_getform] if { $query ne "" } { set query "?[export_entire_form_as_url_vars]" } ad_returnredirect -allow_complete_url "[ns_conn location][ns_conn url]$query" return "filter_return" } } # DRB: a bug in ns_conn causes urlc to be set to one greater than the number of URL # directory elements and the trailing element of urlv to be set to # {} if you hit the site with the host name alone. This confuses code that # expects urlc to be set to the length of urlv and urlv to have a non-null # trailing element except in the case where urlc is 0 and urlv the empty list. if { [lindex [ad_conn urlv] end] == "" } { ad_conn -set urlc [expr {[ad_conn urlc] - 1}] ad_conn -set urlv [lrange [ad_conn urlv] 0 [expr {[llength [ad_conn urlv]] - 2}] ] } rp_debug -ns_log_level debug -debug t "rp_filter: setting up request: [ns_conn method] [ns_conn url] [ns_conn query]" if { [catch { array set node [site_node::get -url [ad_conn url]] } errmsg] } { # log and do nothing rp_debug "error within rp_filter [ns_conn method] [ns_conn url] [ns_conn query]. $errmsg" } else { if {$node(url) eq "[ad_conn url]/"} { ad_returnredirect $node(url) rp_debug "rp_filter: returnredirect $node(url)" rp_debug "rp_filter: return filter_return" return "filter_return" } ad_conn -set node_id $node(node_id) ad_conn -set node_name $node(name) ad_conn -set object_id $node(object_id) ad_conn -set object_url $node(url) ad_conn -set object_type $node(object_type) ad_conn -set package_id $node(object_id) ad_conn -set package_key $node(package_key) ad_conn -set package_url $node(url) ad_conn -set instance_name $node(instance_name) ad_conn -set extra_url [string range [ad_conn url] [string length $node(url)] end] } ##### # # See if any libraries have changed. This may look expensive, but all it # does is check an NSV. # ##### if { ![rp_performance_mode] } { # We wrap this in a catch, because we don't want an error here to # cause the request to fail. if { [catch { apm_load_any_changed_libraries } error] } { global errorInfo ns_log Error "rp_filter: error apm_load_any_changed_libraries: $errorInfo" } } ##### # # Read in and/or generate security cookies. # ##### # sec_handler (defined in security-procs.tcl) sets the ad_conn # session-level variables such as user_id, session_id, etc. we can # call sec_handler at this point because the previous return # statements are all error-throwing cases or redirects. # ns_log Notice "OACS= RP start" sec_handler # ns_log Notice "OACS= RP end" # Set locale and language of the request. We need ad_conn user_id to be set at this point if { [catch { ad_conn -set locale [lang::conn::locale] ad_conn -set language [lang::conn::language] ad_conn -set charset [lang::util::charset_for_locale [ad_conn locale]] }] } { # acs-lang doesn't seem to be installed. Even though it must be installed now, # the problem is that if it isn't, everything breaks. So we wrap it in # a catch, and set locale and language to the empty strings. # This is a temporary work-around until it's reasonably safe # to assume that most people have added acs-lang to their system. ad_conn -set locale "" ad_conn -set language "" ad_conn -set charset "" } # Who's online whos_online::user_requested_page [ad_conn untrusted_user_id] ##### # # Make sure the user is authorized to make this request. # ##### if { ![empty_string_p [ad_conn object_id]] } { ad_try { switch -glob -- [ad_conn extra_url] { admin/* { # double check someone has not accidentally granted # admin to public and require logins for all admin pages auth::require_login permission::require_permission -object_id [ad_conn object_id] -privilege admin } sitewide-admin/* { permission::require_permission -object_id [acs_lookup_magic_object security_context_root] -privilege admin } default { permission::require_permission -object_id [ad_conn object_id] -privilege read } } } ad_script_abort val { rp_finish_serving_page rp_debug "rp_filter: return filter_return" return "filter_return" } } rp_debug "rp_filter: return filter_ok" return "filter_ok" } ad_proc -private rp_debug { { -debug f } { -ns_log_level notice } string } { Logs a debugging message, including a high-resolution (millisecond) timestamp. } { if { [parameter::get -package_id [ad_acs_kernel_id] -parameter DebugP -default 0] } { global ad_conn set clicks [clock clicks -milliseconds] ds_add rp [list debug $string $clicks $clicks] } if { [parameter::get -package_id [ad_acs_kernel_id] -parameter LogDebugP -default 0] || $debug eq "t" || $debug eq "1" } { global ad_conn if { [info exists ad_conn(start_clicks)] } { set timing " ([expr {([clock clicks -milliseconds] - $ad_conn(start_clicks))}] ms)" } else { set timing "" } ns_log $ns_log_level "RP$timing: $string" } } ad_proc rp_report_error { -message } { Writes an error to the connection. @param message The message to write (pulled from $errorInfo if none is specified). } { if { ![info exists message] } { global errorInfo # We need 'message' to be a copy, because errorInfo will get overridden by some of the template parsing below set message $errorInfo } set error_url "[ad_url][ad_conn url]?[export_entire_form_as_url_vars]" # set error_file [template::util::url_to_file $error_url] set error_file [ad_conn file] set package_key [] set prev_url [get_referrer] set feedback_id [db_nextval acs_object_id_seq] set user_id [ad_conn user_id] set bug_package_id [ad_conn package_id] set error_info $message set vars_to_export [export_vars -form { error_url error_info user_id prev_url error_file feedback_id bug_package_id }] ds_add conn error $message set params [list] #Serve the stacktrace set params [list [list stacktrace $message] [list user_id $user_id] [list error_file $error_file] [list prev_url $prev_url] [list feedback_id $feedback_id] [list error_url $error_url] [list bug_package_id $bug_package_id] [list vars_to_export $vars_to_export]] if {![parameter::get -package_id [ad_acs_kernel_id] -parameter RestrictErrorsToAdminsP -default 0] || \ [permission::permission_p -object_id [ad_conn package_id] -privilege admin] } { } with_catch errmsg { set rendered_page [ad_parse_template -params $params "/packages/acs-tcl/lib/page-error"] } { # An error occurred during rendering of the error page global errorInfo ns_log Error "rp_report_error: Error rendering error page (!)\n$errorInfo" set rendered_page "
    [ns_quotehtml $message]
    [ad_footer]" } ns_return 500 text/html $rendered_page set headers [ns_conn headers] ns_log Error "[ns_conn method] http://[ns_set iget $headers host][ns_conn url]?[ns_conn query] referred by \"[ns_set iget $headers referer]\" $message" } ad_proc -private rp_path_prefixes {path} { Returns all the prefixes of a path ordered from most to least specific. } { if {[string index $path 0] ne "/"} { set path "/$path" } set path [string trimright $path /] if { $path eq "" } { return "/" } set components [split $path "/"] set prefixes [list] for {set i [expr {[llength $components] -1}]} {$i > 0} {incr i -1} { lappend prefixes "[join [lrange $components 0 $i] "/"]/" lappend prefixes "[join [lrange $components 0 $i] "/"]" } lappend prefixes "/" return $prefixes } ad_proc -private rp_handler {} { The request handler, which responds to absolutely every HTTP request made to the server. } { # DRB: Fix obscure case where we are served a request like GET http://www.google.com. # In this case AOLserver 4.0.10 (at least) doesn't run the preauth filter "rp_filter", # but rather tries to serve /global/file-not-found directly. rp_handler dies a horrible # death if it's called without ad_conn being set up. My fix is to simply redirect # to the url AOLserver substitutes if ad_conn does not exist (rp_filter begins with # ad_conn -reset) ... global ad_conn if { ![info exists ad_conn] } { ad_returnredirect [ns_conn url] return } # JCD: keep track of rp_handler call count to prevent dev support from recording # information twice when for example we get a 404 internal redirect. We should probably set recursion_count [ad_conn recursion_count] ad_conn -set recursion_count [incr recursion_count] set startclicks [clock clicks -milliseconds] rp_debug "rp_handler: handling request: [ns_conn method] [ns_conn url]?[ns_conn query]" if { [set code [catch { if { [rp_performance_mode] } { global tcl_url2file tcl_url2path_info if { ![catch { set file $tcl_url2file([ad_conn url]) set path_info $tcl_url2path_info([ad_conn url]) } errmsg] } { ad_conn -set file $file ad_conn -set path_info $path_info rp_serve_concrete_file $file return } rp_debug -debug t "error in rp_handler: $errmsg" } set resolve_values [concat [ns_info pageroot][string trimright [ad_conn package_url] /] \ [apm_package_url_resolution [ad_conn package_key]]] foreach resolve_value $resolve_values { foreach {root match_prefix} $resolve_value {} set extra_url [ad_conn extra_url] if { $match_prefix ne "" } { if { [string first $match_prefix $extra_url] == 0 } { # An empty root indicates we should reject the attempted reference. This # is used to block references to embeded package [sitewide-]admin pages that # avoid the request processor permission check if { $root eq "" } { break } set extra_url [string trimleft \ [string range $extra_url [string length $match_prefix] end] /] } else { continue } } ds_add rp [list notice "Trying rp_serve_abstract_file $root/$extra_url" $startclicks [clock clicks -milliseconds]] ad_try { rp_serve_abstract_file "$root/$extra_url" set tcl_url2file([ad_conn url]) [ad_conn file] set tcl_url2path_info([ad_conn url]) [ad_conn path_info] } notfound val { ds_add rp [list notice "File $root/$extra_url: Not found" $startclicks [clock clicks -milliseconds]] ds_add rp [list transformation [list notfound "$root / $extra_url" $val] $startclicks [clock clicks -milliseconds]] continue } redirect url { ds_add rp [list notice "File $root/$extra_url: Redirect" $startclicks [clock clicks -milliseconds]] ds_add rp [list transformation [list redirect $root/$extra_url $url] $startclicks [clock clicks -milliseconds]] ad_returnredirect $url } directory dir_index { ds_add rp [list notice "File $root/$extra_url: Directory index" $startclicks [clock clicks -milliseconds]] ds_add rp [list transformation [list directory $root/$extra_url $dir_index] $startclicks [clock clicks -milliseconds]] continue } return } if {[info exists dir_index] && ![string match */CVS/* $dir_index] } { if { [nsv_get rp_directory_listing_p .] } { ns_returnnotice 200 "Directory listing of $dir_index" \ [rp_html_directory_listing $dir_index] return } } # OK, we didn't find a normal file. Let's look for a path info style thingy, # visiting possible file matches from most specific to least. foreach prefix [rp_path_prefixes $extra_url] { foreach resolve_value $resolve_values { foreach {root match_prefix} $resolve_value {} set extra_url [ad_conn extra_url] if { $match_prefix ne "" } { if { [string first $match_prefix $extra_url] == 0 } { set extra_url [string trimleft \ [string range $extra_url [string length $match_prefix] end] /] } else { continue } } ad_try { ad_conn -set path_info \ [string range $extra_url [expr {[string length $prefix] - 1}] end] rp_serve_abstract_file -noredirect -nodirectory \ -extension_pattern ".vuh" "$root$prefix" set tcl_url2file([ad_conn url]) [ad_conn file] set tcl_url2path_info([ad_conn url]) [ad_conn path_info] } notfound val { ds_add rp [list transformation [list notfound $root$prefix $val] $startclicks [clock clicks -milliseconds]] continue } redirect url { ds_add rp [list transformation [list redirect $root$prefix $url] $startclicks [clock clicks -milliseconds]] ad_returnredirect $url } directory dir_index { ds_add rp [list transformation [list directory $root$prefix $dir_index] $startclicks [clock clicks -milliseconds]] continue } return } } ds_add rp [list transformation [list notfound $root/$extra_url notfound] $startclicks [clock clicks -milliseconds]] ns_returnnotfound } errmsg]] } { if {$code == 1} { if {[ns_conn query] ne "" } { set q ? } else { set q "" } rp_debug "error in rp_handler: serving [ns_conn method] [ns_conn url]$q[ns_conn query] \n\tad_url \"[ad_conn url]\" maps to file \"[ad_conn file]\"\nerrmsg is $errmsg" rp_report_error } } } ad_proc -private rp_serve_abstract_file { -noredirect:boolean -nodirectory:boolean {-extension_pattern ".*"} path } { Serves up a file given the abstract path. Raises the following exceptions in the obvious cases:
    • notfound (passes back an empty value)
    • redirect (passes back the url to which it wants to redirect)
    • directory (passes back the path of the directory)
    Should not be used in .vuh files or elsewhere, instead use the public function rp_internal_redirect. @see rp_internal_redirect } { if {[string index $path end] eq "/"} { if { [file isdirectory $path] } { # The path specified was a directory; return its index file. # Directory name with trailing slash. Search for an index.* file. # Remember the name of the directory in $dir_index, so we can later # generate a directory listing if necessary. set dir_index $path set path "[string trimright $path /]/index" } else { # If there's a trailing slash on the path, the URL must refer to a # directory (which we know doesn't exist, since [file isdirectory $path] # returned 0). ad_raise notfound } } ### no more trailing slash. if { [file isfile $path] } { # It's actually a file. ad_conn -set file $path } else { # The path provided doesn't correspond directly to a file - we # need to glob. (It could correspond directly to a directory.) if { ![file isdirectory [file dirname $path]] } { ad_raise notfound } ad_conn -set file [rp_concrete_file -extension_pattern $extension_pattern $path] if { [empty_string_p [ad_conn file]] } { if { [file isdirectory $path] && !$noredirect_p } { # Directory name with no trailing slash. Redirect to the same # URL but with a trailing slash. set url "[ad_conn url]/" if { [ad_conn query] ne "" } { append url "?[ad_conn query]" } ad_raise redirect $url } else { if { [info exists dir_index] && !$nodirectory_p } { ad_raise directory $dir_index } else { # Nothing at all found! 404 time. ad_raise notfound } } } } rp_serve_concrete_file [ad_conn file] } ad_proc -public rp_serve_concrete_file {file} { Serves a file. } { set extension [file extension $file] set startclicks [clock clicks -milliseconds] if { [nsv_exists rp_extension_handlers $extension] } { set handler [nsv_get rp_extension_handlers $extension] if { [set errno [catch { ad_try { $handler } ad_script_abort val { # do nothing } rp_finish_serving_page ds_add rp [list serve_file [list $file $handler] $startclicks [clock clicks -milliseconds]] } error]] } { global errorCode errorInfo ds_add rp [list serve_file [list $file $handler] $startclicks [clock clicks -milliseconds] error "$errorCode: $errorInfo"] return -code $errno -errorcode $errorCode -errorinfo $errorInfo $error } } else { # Some other random kind of file - guess the type and return it. # first check that we are not serving a forbidden file like a .xql, a backup or CVS file foreach match [parameter::get -parameter ExcludedFiles -package_id [ad_acs_kernel_id] -default {}] { if {[string match $match $file]} { ad_raise notfound } } if {[string equal $extension ".xql"] && ![parameter::get -parameter ServeXQLFiles -package_id [ad_acs_kernel_id] -default 0] } { ad_raise notfound } else { set type [ns_guesstype $file] ds_add rp [list serve_file [list $file $type] $startclicks [clock clicks -milliseconds]] ns_returnfile 200 $type $file } } } ad_proc -private rp_concrete_file { {-extension_pattern ".*"} path } { Given a path in the filesystem, returns the file that would be served, trying all possible extensions. Returns an empty string if there's no file "$path.*" in the filesystem (even if the file $path itself does exist). } { # Sub out funky characters in the pathname, so the user can't request # http://www.arsdigita.com/*/index (causing a potentially expensive glob # and bypassing registered procedures)! regsub -all {[^0-9a-zA-Z_/:.]} $path {\\&} path_glob # Grab a list of all available files with extensions. set files [glob -nocomplain "$path_glob$extension_pattern"] # Search for files in the order specified in ExtensionPrecedence. set precedence [parameter::get -package_id [ad_acs_kernel_id] -parameter ExtensionPrecedence -default tcl] foreach extension [split [string trim $precedence] ","] { if { [lsearch -glob $files "*.$extension"] != -1 } { return "$path.$extension" } } # None of the extensions from ExtensionPrecedence were found - just pick # the first in alphabetical order. if { [llength $files] > 0 } { set files [lsort $files] return [lindex $files 0] } # Nada! return "" } ad_proc -public ad_script_abort {} { Aborts the current running Tcl script, returning to the request processor. Used to stop processing after doing ad_returnredirect or other commands which have already returned output to the client. } { ad_raise ad_script_abort } ad_proc -private ad_acs_kernel_id_mem {} { Returns the package_id of the kernel. (not cached) } { return [db_string acs_kernel_id_get {} -default 0] } # use proc rather than ad_proc on redefine since we don't want to see a # multiple define proc warning... ad_proc -public ad_acs_kernel_id {} { Returns the package_id of the kernel. } { set acs_kernel_id [ad_acs_kernel_id_mem] proc ad_acs_kernel_id {} "return $acs_kernel_id" return $acs_kernel_id } ad_proc -public ad_conn {args} { Returns a property about the connection. See the request processor documentation for an (almost complete) list of allowable values.

    If -set is passed then it sets a property.

    If the property has not been set directly by OpenACS it will be passed on to aolservers ns_conn: http://www.aolserver.com/docs/devel/tcl/api/conn.html#ns_conn. If it is not a valid option for ns_conn either then it will throw an error. Valid options for ad_conn are: request, sec_validated, browser_id, session_id, user_id, token, last_issue, deferred_dml, start_clicks, node_id, object_id, object_url, object_type, package_id, package_url, instance_name, package_key, extra_url, system_p, path_info, recursion_count.

    Added recursion_count to properly deal with internalredirects. } { global ad_conn set flag [lindex $args 0] if {[string index $flag 0] ne "-"} { set var $flag set flag "-get" } else { set var [lindex $args 1] } switch -- $flag { -connected_p { return [info exists ad_conn(request)] } -set { set ad_conn($var) [lindex $args 2] } -unset { unset ad_conn($var) } -reset { if {[info exists ad_conn]} { unset ad_conn } array set ad_conn { request "" sec_validated "" browser_id "" session_id "" user_id "" token "" last_issue "" deferred_dml "" start_clicks "" node_id "" object_id "" object_url "" object_type "" package_id "" package_url "" instance_name "" package_key "" extra_url "" file "" system_p 0 path_info "" system_p 0 recursion_count 0 form_count -1 } array unset ad_conn subsite_id array unset ad_conn locale } -get { # Special handling for the form, because "ns_conn form" can # cause the server to hang until the socket times out. This # happens on pages handling multipart form data, where # ad_page_contract already has called ns_getform and has # retrieved all data from the client. ns_getform has its # own caching, so calling it instead of [ns_conn form] # is OK. switch $var { form { return [ns_getform] } all { return [array get ad_conn] } default { if { [info exists ad_conn($var)] } { return $ad_conn($var) } # Fallback switch $var { locale { set ad_conn(locale) [parameter::get \ -parameter SiteWideLocale \ -package_id [apm_package_id_from_key "acs-lang"] \ -default {en_US}] return $ad_conn(locale) } subsite_node_id { set ad_conn(subsite_node_id) [site_node::closest_ancestor_package \ -node_id [ad_conn node_id] \ -package_key [subsite::package_keys] \ -include_self \ -element "node_id"] return $ad_conn(subsite_node_id) } subsite_id { set ad_conn(subsite_id) [site_node::get_object_id \ -node_id [ad_conn subsite_node_id]] return $ad_conn(subsite_id) } subsite_url { set ad_conn(subsite_url) [site_node::get_url \ -node_id [ad_conn subsite_node_id]] return $ad_conn(subsite_url) } vhost_subsite_url { set ad_conn(vhost_subsite_url) [subsite::get_url] return $ad_conn(vhost_subsite_url) } vhost_package_url { set subsite_package_url [string range [ad_conn package_url] [string length [ad_conn subsite_url]] end] set ad_conn(vhost_package_url) "[ad_conn vhost_subsite_url]$subsite_package_url" return $ad_conn(vhost_package_url) } recursion_count { # sometimes recusion_count will be uninitialized and # something will call ad_conn recursion_count - return 0 # in that instance. This is filters ahead of rp_filter which throw # an ns_returnnotfound or something like that. set ad_conn(recursion_count) 0 return 0 } peeraddr { # Get the address provided by a reverse proxy such as NGINX via # X-Forwarded-For, if available set headers [ns_conn headers] set i [ns_set find $headers "X-Forwarded-For"] if {$i < 0 } { # Use ns_conn return [ns_conn $var] } else { return [ns_set value $headers $i] } } default { return [ns_conn $var] } } } } } default { error "ad_conn: unknown flag $flag" } } } ad_proc -private rp_register_extension_handler { extension args } { Registers a proc used to handle requests for files with a particular extension. } { if { [llength $args] == 0 } { error "Must specify a procedure name" } ns_log Debug "rp_register_extension_handler: Registering [join $args " "] to handle $extension files" nsv_set rp_extension_handlers ".$extension" $args } ad_proc -private rp_handle_tcl_request {} { Handles a request for a .tcl file. Sets up the stack of datasource frames, in case the page is templated. } { namespace eval template variable parse_level [info level] source [ad_conn file] } ad_proc -private rp_handle_adp_request {} { Handles a request for an .adp file. } { doc_init set adp [ns_adp_parse -file [ad_conn file]] if { [doc_exists_p] } { doc_set_property body $adp doc_serve_document } else { set content_type [ns_set iget [ad_conn outputheaders] "content-type"] if { $content_type eq "" } { set content_type "text/html" } doc_return 200 $content_type $adp } } ad_proc -private rp_handle_html_request {} { Handles a request for an HTML file. } { ad_serve_html_page [ad_conn file] } if { [apm_first_time_loading_p] } { # Initialize nsv_sets nsv_array set rp_filters [list] nsv_array set rp_registered_procs [list] nsv_array set rp_extension_handlers [list] # The following stuff is in a -procs.tcl file rather than a -init.tcl file # since we want it done really really early in the startup process. Don't # try this at home! foreach method { GET POST HEAD } { nsv_set rp_registered_procs $method [list] } } ad_proc -private ad_http_cache_control { } { This adds specific headers to the http output headers for the current request in order to prevent user agents and proxies from caching the page.

    It should be called only when the method to return the data to the client is going to be ns_return. In other cases, e.g. ns_returnfile, one can assume that the returned content is not dynamic and can in fact be cached. Besides that, aolserver implements its own handling of Last-Modified headers with ns_returnfile. Also it should be called as late as possible - shortly before ns_return, so that other code has the chance to set no_cache_control_p to 1 before it runs.

    This proc can be disabled per request by calling "ad_conn -set no_http_cache_control_p 1" before this proc is reached. It will not modify any headers if this variable is set to 1.

    If the acs-kernel parameter CacheControlP is set to 0 then it's fully disabled. @author Tilmann Singer (tils-oacs@tils.net) } { if { ![parameter::get -package_id [ad_acs_kernel_id] -parameter HttpCacheControlP -default 0]} { return } global ad_conn if { [info exists ad_conn(no_http_cache_control_p)] && $ad_conn(no_http_cache_control_p) } { return } set headers [ad_conn outputheaders] # Check if any relevant header is already present - in this case # don't touch anything. set modify_p 1 if { ([ns_set ifind $headers "cache-control"] > -1 || [ns_set ifind $headers "expires"] > -1) } { set modify_p 0 } else { for { set i 0 } { $i < [ns_set size $headers] } { incr i } { if { [string tolower [ns_set key $headers $i]] == "pragma" && [string tolower [ns_set value $headers $i]] == "no-cache" } { set modify_p 0 break } } } # Set three headers, to be sure it won't get cached. If you are in # doubt, check the spec: # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html if { $modify_p } { # actually add the headers ns_setexpires 0 ns_set put $headers "Pragma" "no-cache" ns_set put $headers "Cache-Control" "no-cache" } # Prevent subsequent calls of this proc from adding the same # headers again. ad_conn -set no_http_cache_control_p 1 } # ------------------------------------------------------------------------- # procs for hostname-based subsites # ------------------------------------------------------------------------- ad_proc ad_host {} { Returns the hostname as it was typed in the browser, provided forcehostp is set to 0. } { set host_and_port [ns_set iget [ns_conn headers] Host] if { [regexp {^([^:]+)} $host_and_port match host] } { return $host } else { return "unknown host" } } ad_proc ad_port {} { Returns the port as it was typed in the browser, provided forcehostp is set to 0. } { set host_and_port [ns_set iget [ns_conn headers] Host] if { [regexp {^([^:]+):([0-9]+)} $host_and_port match host port] } { return ":$port" } else { return "" } } ad_proc root_of_host {host} { Maps a hostname to the corresponding sub-directory. } { # The main hostname is mounted at /. if { [string equal $host [ns_config ns/server/[ns_info server]/module/nssock Hostname]] } { return "" } # Other hostnames map to subsites. set node_id [util_memoize [list rp_lookup_node_from_host $host]] if {$node_id eq ""} { set host [regsub "www\." $host ""] set node_id [rp_lookup_node_from_host $host] } if { $node_id ne "" } { set url [site_node::get_url -node_id $node_id] return [string range $url 0 [expr {[string length $url]-2}]] } else { # Hack to provide a useful default return "" } } ad_proc -private rp_lookup_node_from_host { host } { return [db_string node_id { *SQL* } -default ""] } ad_proc -public request_denied_filter { why } { Deny serving the request } { ad_return_forbidden \ "Forbidden URL" \ "

    No, we're not going to show you this file
    " return filter_return } if {[ns_info name] eq "NaviServer"} { # this is written for NaviServer 4.99.1 or newer foreach filter {rp_filter rp_resources_filter request_denied_filter} { if {[info command ::${filter}_aolserver] eq ""} { rename $filter ${filter}_aolserver } proc $filter {why} [list ${filter}_aolserver \$why ] } if {[info command rp_invoke_filter_conn] eq ""} { rename rp_invoke_filter rp_invoke_filter_conn rename rp_invoke_proc rp_invoke_proc_conn } proc rp_invoke_filter { why filter_info} { rp_invoke_filter_conn _ $filter_info $why} proc rp_invoke_proc { argv } { rp_invoke_proc_conn _ $argv } } openacs-5.7.0/packages/acs-tcl/tcl/request-processor-procs.xql0000644000175000017500000000115607621227562024254 0ustar frankiefrankie select package_id from apm_packages where package_key = 'acs-kernel' select package_id from apm_packages where package_key = 'acs-admin' select node_id from host_node_map where host = :host openacs-5.7.0/packages/acs-tcl/tcl/admin-procs.tcl0000644000175000017500000004154411171413746021616 0ustar frankiefrankiead_library { Procedures used only in admin pages (mostly the user class stuff). @author Multiple @creation-date 11/18/98 @cvs-id $Id: admin-procs.tcl,v 1.21 2009/04/15 17:22:46 emmar Exp $ } ad_proc -public ad_restrict_to_https {conn args why} { Redirects user to HTTPS. @author Allen Pulsifer (pulsifer@mediaone.net) @creation-date 2 November 2000 } { if { [security::secure_conn_p] } { return "filter_ok" } ad_returnredirect [security::get_secure_qualified_url [ad_return_url]] # No abort since in filter return "filter_return" } ad_proc -public ad_approval_system_inuse_p {} { Returns 1 if the system is configured to use and approval system. } { if {[parameter::get -parameter RegistrationRequiresEmailVerification] && [parameter::get -parameter RegistrationRequiresApprovalP] } { return 1 } else { return 0 } } ad_proc -private ad_user_class_parameters {} { Returns the list of parameter var names used to define a user class. } { return [list category_id country_code usps_abbrev intranet_user_p group_id last_name_starts_with email_starts_with expensive user_state sex age_above_years age_below_years registration_during_month registration_before_days registration_after_days registration_after_date last_login_before_days last_login_after_days last_login_equals_days number_visits_below number_visits_above user_class_id sql_post_select crm_state curriculum_elements_completed] } ad_proc -private ad_user_class_description { set_id } { Takes an ns_set of key/value pairs and produces a human-readable description of the class of users specified. } { set clauses [list] set pretty_description "" # turn all the parameters in the ns_set into tcl vars ad_ns_set_to_tcl_vars -duplicates fail $set_id # All the SQL statements are named after the criteria name (e.g. category_id) foreach criteria [ad_user_class_parameters] { if { [info exists $criteria] && ![empty_string_p [set $criteria]] } { switch $criteria { "category_id" { set pretty_category [db_string $criteria { select category from categories where category_id = :category_id } ] lappend clauses "said they were interested in $pretty_category" } "country_code" { set pretty_country [db_string $criteria { select country_name from country_codes where iso = :country_code } ] lappend clauses "told us that they live in $pretty_country" } "usps_abbrev" { set pretty_state [db_string $criteria { select state_name from states where usps_abbrev = :usps_abbrev } ] lappend clauses "told us that they live in $pretty_state" } "intranet_user_p" { lappend clauses "are an employee" } "group_id" { set group_name [db_string $criteria { select group_name from groups where group_id = :group_id } ] lappend clauses "are a member of $group_name" } "last_name_starts_with" { lappend clauses "have a last name starting with $last_name_starts_with" } "email_starts_with" { lappend clauses "have an email address starting with $email_starts_with" } "expensive" { lappend clauses "have accumulated unpaid charges of more than [parameter::get -parameter ExpensiveThreshold]" } "user_state" { lappend clauses "have user state of $user_state" } "sex" { lappend clauses "are $sex." } "age_above_years" { lappend clauses "is older than $age_above_years years" } "age_below_years" { lappend clauses "is younger than $age_below_years years" } "registration_during_month" { set pretty_during_month [db_string $criteria { select to_char(to_date(:registration_during_month,'YYYYMM'),'fmMonth YYYY') from dual } ] lappend clauses "registered during $pretty_during_month" } "registration_before_days" { lappend clauses "registered over $registration_before_days days ago" } "registration_after_days" { lappend clauses "registered in the last $registration_after_days days" } "registration_after_date" { lappend clauses "registered on or after $registration_after_date" } "last_login_before_days" { lappend clauses "have not visited the site in $last_login_before_days days" } "last_login_after_days" { lappend clauses "have not visited the site in $last_login_after_days days" } "last_login_equals_days" { if { $last_login_equals_days == 1 } { lappend clauses "visited the site exactly 1 day ago" } else { lappend clauses "visited the site exactly $last_login_equals_days days ago" } } "number_of_visits_below" { lappend clauses "have visited less than $number_visits_below times" } "number_of_visits_above" { lappend clauses "have visited more than $number_visits_above times" } "user_class_id" { set pretty_class_name [db_string $criteria { select name from user_classes where user_class_id = :user_class_id } ] lappend clauses "are in the user class $pretty_class_name" } "sql_post_select" { lappend clauses "are returned by \"select users(*) from $sql_post_select" } "crm_state" { lappend clauses "are in the customer state \"$crm_state\"" } "curriculum_elements_completed" { if { $curriculum_elements_completed == 1 } { lappend clauses "who have completed exactly $curriculum_elements_completed curriculum element" } else { lappend clauses "who have completed exactly $curriculum_elements_completed curriculum elements" } } } } } if { [info exists combine_method] && $combine_method eq "or" } { set pretty_description [join $clauses " or "] } else { set pretty_description [join $clauses " and "] } return $pretty_description } ad_proc -private ad_user_class_query { set_id } { Takes an ns_set of key/value pairs and produces a query for the class of users specified (one user per row returned). @param set_id The id of a ns_set containing all the parameters of the user class. } { # we might need this set where_clauses [list] set join_clauses [list] set group_clauses [list] set having_clauses [list] set tables [list users] # turn all the parameters in the ns_set into tcl vars ad_ns_set_to_tcl_vars -duplicates fail $set_id # if we are using a user_class, just get the info # Get all the non-LOB columns. set user_columns [list] foreach column [db_columns users] { if { $column ne "portrait" && $column ne "portrait_thumbnail" } { lappend user_columns "users.$column" } } if { [info exists count_only_p] && $count_only_p } { set select_list "count(users.user_id)" } else { set select_list $user_columns } if { [info exists include_contact_p] && $include_contact_p} { lappend select_list "user_contact_summary(users.user_id) as contact_summary" } if { [info exists include_demographics_p] && $include_demographics_p} { lappend select_list "user_demographics_summary(users.user_id) as demographics_summary" } if { [info exists user_class_id] && $user_class_id ne "" } { set sql_post_select [db_string sql_post_select_for_user_class " select sql_post_select from user_classes where user_class_id = [ns_dbquotevalue $user_class_id] "] return "select [join $select_list ",\n "]\n$sql_post_select" } if { [info exists sql_post_select] && $sql_post_select ne "" } { return "select [join $select_list ",\n "]\n$sql_post_select" } foreach criteria [ad_user_class_parameters] { if { [info exists $criteria] && ![empty_string_p [set $criteria]] } { switch $criteria { "category_id" { if {[lsearch $tables "users_interests"] == -1 } { lappend tables "users_interests" lappend join_clauses "users.user_id = users_interests.user_id" } lappend where_clauses "users_interests.category_id = [ns_dbquotevalue $category_id]" } "Country_code" { if {[lsearch $tables "users_contact"] == -1 } { lappend tables "users_contact" lappend join_clauses "users.user_id = users_contact.user_id" } lappend where_clauses "users_contact.ha_country_code = [ns_dbquotevalue $country_code]" } "usps_abbrev" { if {[lsearch $tables "users_contact"] == -1 } { lappend tables "users_contact" lappend join_clauses "users.user_id = users_contact.user_id" } lappend where_clauses "(users_contact.ha_state = [ns_dbquotevalue $usps_abbrev] and (users_contact.ha_country_code is null or users_contact.ha_country_code = 'us'))" } "intranet_user_p" { if {$intranet_user_p eq "t" && [lsearch $tables "intranet_users"] == -1 } { lappend tables "intranet_users" lappend join_clauses "users.user_id = intranet_users.user_id" } } "group_id" { lappend tables "group_member_map" lappend join_clauses "users.user_id = group_member_map.member_id" lappend where_clauses "group_member_map.group_id = $group_id" } "last_name_starts_with" { lappend where_clauses "lower(users.last_name) like lower([ns_dbquotevalue "${last_name_starts_with}%"])" # note the added percent sign here } "email_starts_with" { lappend where_clauses "lower(users.email) like lower([ns_dbquotevalue "${email_starts_with}%"])" # note the added percent sign here } "expensive" { if { [info exists count_only_p] && $count_only_p } { lappend where_clauses "[parameter::get -parameter ExpensiveThreshold] < (select sum(amount) from users_charges where users_charges.user_id = users.user_id)" } else { if {[lsearch $tables "user_charges"] == -1 } { lappend tables "users_charges" lappend join_clauses "users.user_id = users_charges.user_id" } set group_clauses [concat $group_clauses $user_columns] lappend having_clauses "sum(users_charges.amount) > [parameter::get -parameter ExpensiveThreshold]" # only the ones where they haven't paid lappend where_clauses "users_charges.order_id is null" } } "user_state" { lappend where_clauses "users.user_state = [ns_dbquotevalue $user_state]" } "sex" { if {[lsearch $tables "users_demographics"] == -1 } { lappend tables "users_demographics" lappend join_clauses "users.user_id = users_demographics.user_id" } lappend where_clauses "users_demographics.sex = [ns_dbquotevalue $sex]" } "age_below_years" { if {[lsearch $tables "users_demographics"] == -1 } { lappend tables "users_demographics" lappend join_clauses "users.user_id = users_demographics.user_id" } lappend where_clauses "users_demographics.birthdate > sysdate - ([ns_dbquotevalue $age_below_years] * 365.25)" } "age_above_years" { if {[lsearch $tables "users_demographics"] == -1 } { lappend tables "users_demographics" lappend join_clauses "users.user_id = users_demographics.user_id" } lappend where_clauses "users_demographics.birthdate < sysdate - ([ns_dbquotevalue $age_above_years] * 365.25)" } "registration_during_month" { lappend where_clauses "to_char(users.registration_date,'YYYYMM') = [ns_dbquotevalue $registration_during_month]" } "registration_before_days" { lappend where_clauses "users.registration_date < sysdate - [ns_dbquotevalue $registration_before_days]" } "registration_after_days" { lappend where_clauses "users.registration_date > sysdate - [ns_dbquotevalue $registration_after_days]" } "registration_after_date" { lappend where_clauses "users.registration_date > [ns_dbquotevalue $registration_after_date]" } "last_login_before_days" { lappend where_clauses "users.last_visit < sysdate - [ns_dbquotevalue $last_login_before_days]" } "last_login_after_days" { lappend where_clauses "users.last_visit > sysdate - [ns_dbquotevalue $last_login_after_days]" } "last_login_equals_days" { lappend where_clauses "round(sysdate-last_visit) = [ns_dbquotevalue $last_login_equals_days]" } "number_visits_below" { lappend where_clauses "users.n_sessions < [ns_dbquotevalue $number_visits_below]" } "number_visits_above" { lappend where_clauses "users.n_sessions > [ns_dbquotevalue $number_visits_above]" } "crm_state" { lappend where_clauses "users.crm_state = [ns_dbquotevalue $crm_state]" } "curriculum_elements_completed" { lappend where_clauses "[ns_dbquotevalue $curriculum_elements_completed] = (select count(*) from user_curriculum_map ucm where ucm.user_id = users.user_id and ucm.curriculum_element_id in (select curriculum_element_id from curriculum))" } } } } #stuff related to the query itself if { [info exists combine_method] && $combine_method eq "or" } { set complete_where [join $where_clauses " or "] } else { set complete_where [join $where_clauses " and "] } if { [info exists include_accumulated_charges_p] && $include_accumulated_charges_p && (![info exists count_only_p] || !$count_only_p) } { # we're looking for expensive users and not just counting them lappend select_list "sum(users_charges.amount) as accumulated_charges" } if { [llength $join_clauses] == 0 } { set final_query "select [join $select_list ",\n "] from [join $tables ", "]" if { $complete_where ne "" } { append final_query "\nwhere $complete_where" } } else { # we're joining at set final_query "select [join $select_list ",\n "] from [join $tables ", "] where [join $join_clauses "\nand "]" if { $complete_where ne "" } { append final_query "\n and ($complete_where)" } } if { [llength $group_clauses] > 0 } { append final_query "\ngroup by [join $group_clauses ", "]" } if { [llength $having_clauses] > 0 } { append final_query "\nhaving [join $having_clauses " and "]" } return $final_query } ad_proc -private ad_user_class_query_count_only { set_id } { Takes an ns_set of key/value pairs and produces a query that will compute the number of users in the class specified. } { set new_set [ns_set copy $set_id] ns_set update $new_set count_only_p 1 return [ad_user_class_query $new_set] } ad_proc -private ad_registration_finite_state_machine_admin_links { -nohtml:boolean member_state email_verified_p user_id {return_url ""} } { Returns the admininistation links to change the user's state in the user_state finite state machine. If the nohtml switch is set, then a list of lists will be returned (url label). } { set user_finite_states [list] switch $member_state { "approved" { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state banned}}] [_ acs-tcl.ban]] \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state deleted}}] [_ acs-tcl.delete]] } "deleted" { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state approved}}] [_ acs-tcl.undelete]] \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state banned}}] [_ acs-tcl.ban]] } "needs approval" { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state approved}}] [_ acs-tcl.approve]] \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state rejected}}] [_ acs-tcl.reject]] } "rejected" { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state approved}}] [_ acs-tcl.approve]] } "banned" { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {member_state approved}}] [_ acs-tcl.approve]] } } if { $email_verified_p eq "t" } { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {email_verified_p f}}] [_ acs-tcl.lt_require_email_verific]] } else { lappend user_finite_states \ [list [export_vars -base "/acs-admin/users/member-state-change" {user_id return_url {email_verified_p t}}] [_ acs-tcl.approve_email]] } if { $nohtml_p } { # Return the list of lists (url label) return $user_finite_states } else { # Build the list of A tags set user_finite_state_links [list] foreach elm $user_finite_states { set url [lindex $elm 0] set label [lindex $elm 1] lappend user_finite_state_links [subst {$label}] } return $user_finite_state_links } } openacs-5.7.0/packages/acs-tcl/tcl/admin-procs.xql0000644000175000017500000000266107271732156021642 0ustar frankiefrankie select sql_post_select from user_classes where user_class_id = [ns_dbquotevalue $user_class_id] select category from categories where category_id = :category_id select country_name from country_codes where iso = :country_code select state_name from states where usps_abbrev = :usps_abbrev select group_name from groups where group_id = :group_id select to_char(to_date(:registration_during_month,'YYYYMM'),'fmMonth YYYY') from dual select name from user_classes where user_class_id = :user_class_id openacs-5.7.0/packages/acs-tcl/tcl/apm-procs-oracle.xql0000644000175000017500000001261411352533030022552 0ustar frankiefrankie oracle8.1.6 begin :1 := apm_package.highest_version ( package_key => :package_key ); end; select version_name from apm_package_versions where package_key = :package_key and version_id = apm_package.highest_version(:package_key) begin :1 := apm_package.num_instances( package_key => :package_key ); end; begin :1 := apm.register_parameter( parameter_id => :parameter_id, package_key => :package_key, parameter_name => :parameter_name, description => :description, scope => :scope, datatype => :datatype, default_value => :default_value, section_name => :section_name, min_n_values => :min_n_values, max_n_values => :max_n_values ); end; begin apm.unregister_parameter(:parameter_id); end; select nvl(v.package_id, 0) as package_id, p.parameter_name, decode(v.value_id, null, p.default_value, v.attr_value) as attr_value from apm_parameters p, apm_parameter_values v where p.package_key = :package_key and p.parameter_id = v.parameter_id (+) begin :1 := apm_package_version.add_dependency( dependency_type => :dependency_type, dependency_id => :dependency_id, version_id => :version_id, dependency_uri => :dependency_uri, dependency_version => :dependency_version ); end; begin apm_package_version.remove_dependency( dependency_id => :dependency_id ); end; begin :1 := apm_package_version.add_interface( interface_id => :interface_id, version_id => :version_id, interface_uri => :interface_uri, interface_version => :interface_version ); end; begin apm_package_version.remove_interface( interface_id => :interface_id ); end; select decode(count(*), 0, 0, 1) from apm_package_versions where package_key = :package_key and version_name = :version_name select decode(count(*), 0, 0, 1) from apm_package_versions where package_key = :package_key and version_name = :version_name begin :1 := apm_package.new( package_id => :package_id, instance_name => :instance_name, package_key => :package_key, context_id => :context_id ); end; begin apm_package.del( package_id => :package_id ); end; select site_node.url(min(node_id)) from site_nodes where object_id = :package_id select package_key, pretty_name from apm_package_types where not (apm_package.singleton_p(package_key) = 1 and apm_package.num_instances(package_key) >= 1) order by pretty_name select apm_parameter_value.new( package_id => :package_id, parameter_id => ap.parameter_id, value => ap.default_value) from apm_parameters ap where ap.package_key = :new_package_key and not exists (select 1 from apm_parameters ap2 where ap2.package_key = :old_package_key and ap2.parameter_name = ap.parameter_name) openacs-5.7.0/packages/acs-tcl/tcl/parameter-procs-postgresql.xql0000644000175000017500000000120411345565523024722 0ustar frankiefrankie postgresql7.1 select apm__set_value( :package_key::varchar, :parameter, :value ); select apm__set_value( :package_id::integer, :parameter, :value ); openacs-5.7.0/packages/acs-tcl/tcl/text-html-procs.tcl0000644000175000017500000020256211346151020022437 0ustar frankiefrankiead_library { Contains procs used to manipulate chunks of text and html, most notably converting between them. @author Lars Pind (lars@pinds.com) @creation-date 19 July 2000 @cvs-id $Id: text-html-procs.tcl,v 1.65 2010/03/11 11:20:48 gustafn Exp $ } #################### # # text -> HTML # #################### ad_proc -public ad_text_to_html { -no_links:boolean -no_lines:boolean -no_quote:boolean -includes_html:boolean -encode:boolean text } { Converts plaintext to html. Also translates any recognized email addresses or URLs into a hyperlink. @param no_links will prevent it from highlighting @param no_quote will prevent it from HTML-quoting output, so this can be run on semi-HTML input and preserve that formatting. This will also cause spaces/tabs to not be replaced with nbsp's, because this can too easily mess up HTML tags. @param includes_html Set this if the text parameter already contains some HTML which should be preserved. @param encode This will encode international characters into it's html equivalent, like "ü" into ü @author Branimir Dolicki (branimir@arsdigita.com) @author Lars Pind (lars@pinds.com) @creation-date 19 July 2000 } { if { $text eq "" } { return {} } if { !$no_links_p } { # We start by putting a space in front so our URL/email highlighting will work # for URLs/emails right in the beginning of the text. set text " $text" # if something is " http://" or " https://" # we assume it is a link to an outside source. # (bd) The only purpose of thiese sTaRtUrL and # eNdUrL markers is to get rid of trailing dots, # commas and things like that. Note that there # is a \x001 special char before and after each marker. regsub -nocase -all {([^a-zA-Z0-9]+)(http://[^\(\)"<>\s]+)} $text "\\1\x001sTaRtUrL\\2eNdUrL\x001" text regsub -nocase -all {([^a-zA-Z0-9]+)(https://[^\(\)"<>\s]+)} $text "\\1\x001sTaRtUrL\\2eNdUrL\x001" text regsub -nocase -all {([^a-zA-Z0-9]+)(ftp://[^\(\)"<>\s]+)} $text "\\1\x001sTaRtUrL\\2eNdUrL\x001" text # Don't dress URLs that are already HREF=... or SRC=... chunks if { $includes_html_p } { regsub -nocase -all {(href\s*=\s*['"]?)\x001sTaRtUrL([^\x001]*)eNdUrL\x001} $text {\1\2} text regsub -nocase -all {(src\s*=\s*['"]?)\x001sTaRtUrL([^\x001]*)eNdUrL\x001} $text {\1\2} text } # email links have the form xxx@xxx.xxx # JCD: don't treat things =xxx@xxx.xxx as email since most # common occurance seems to be in urls (although VPATH bounce # emails like bounce-user=domain.com@sourcehost.com will then not # work correctly). It's all quite ugly. regsub -nocase -all {([^a-zA-Z0-9=]+)(mailto:)?([^=\(\)\s:;,@<>]+@[^\(\)\s.:;,@<>]+[.][^\(\)\s:;,@<>]+)} $text \ "\\1\x001sTaRtEmAiL\\3eNdEmAiL\x001" text } # At this point, before inserting some of our own <, >, and "'s # we quote the ones entered by the user: if { !$no_quote_p } { set text [ad_quotehtml $text] } if { $encode_p} { set myChars { ª º À à Â Ã Ä Ã… Æ Ç È É Ê Ë ÃŒ à Î à à Ñ Ã’ Ó Ô Õ Ö Ø Ù Ú Û Ü à Þ ß à á â ã ä Ã¥ æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ ¿ } set myHTML { ª º À Á Â Ã Ä Å &Aelig; Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ ¿ } for { set i 0 } { $i < [ llength $myChars ] } { incr i } { set text [ string map "[ lindex $myChars $i ] [ lindex $myHTML $i ]" $text ] } } # Convert line breaks if { !$no_lines_p } { if { $includes_html_p } { set text [util_convert_line_breaks_to_html -includes_html -- $text] } else { set text [util_convert_line_breaks_to_html -- $text] } } if { !$no_quote_p } { # Convert every two spaces to an nbsp regsub -all { } $text "\\\  " text # Convert tabs to four nbsp's regsub -all {\t} $text {\ \ \ \ } text } if { !$no_links_p } { # Move the end of the link before any punctuation marks at the end of the URL regsub -all {([]!?.:;,<>\(\)\}"'-]+)(eNdUrL\x001)} $text {\2\1} text regsub -all {([]!?.:;,<>\(\)\}"'-]+)(eNdEmAiL\x001)} $text {\2\1} text # Dress the links and emails with A HREF regsub -all {\x001sTaRtUrL([^\x001]*)eNdUrL\x001} $text {\1} text regsub -all {\x001sTaRtEmAiL([^\x001]*)eNdEmAiL\x001} $text {\1} text set text [string trimleft $text] } # JCD: Remove all the eNd sTaRt stuff and warn if we do it since its bad # to have these left (means something is broken in our regexps above) if {[regsub -all {(\x001sTaRtUrL|eNdUrL\x001|\x001sTaRtEmAiL|eNdEmAiL\x001)} $text {} text]} { ns_log warning "Replaced sTaRt/eNd magic tags in ad_text_to_html" } return $text } ad_proc -public util_convert_line_breaks_to_html { {-includes_html:boolean} text } { Convert line breaks to

    and
    tags, respectively. } { # Remove any leading or trailing whitespace regsub {^[\s]*} $text {} text regsub {[\s]*$} $text {} text # Make sure all line breaks are single \n's regsub -all {\r\n} $text "\n" text regsub -all {\r} $text "\n" text # Remove whitespace before \n's regsub -all {[ \t]*\n} $text "\n" text # Wrap P's around paragraphs regsub -all {([^\n\s])\n\n([^\n\s])} $text {\1

    \2} text # Convert _single_ CRLF's to
    's to preserve line breaks # Lars: This must be done after we've made P tags, because otherwise the line # breaks will already have been converted into BR's. # remove line breaks right before and after HTML tags that will insert a paragraph break themselves if { $includes_html_p } { foreach tag { ul ol li blockquote p div table tr td th } { regsub -all -nocase "\\n\\s*(\]*>)" $text {\1} text regsub -all -nocase "(\]*>)\\s*\\n" $text {\1} text } } regsub -all {\n} $text "
    \n" text # Add line breaks to P tags regsub -all {

    } $text "

    \n" text return $text } ad_proc -public ad_quotehtml { arg } { Quotes ampersands, double-quotes, and angle brackets in $arg. Analogous to ns_quotehtml except that it quotes double-quotes (which ns_quotehtml does not). @see ad_unquotehtml } { return [string map {& & \" " < < > >} $arg] } ad_proc -public ad_unquotehtml {arg} { reverses ad_quotehtml @see ad_quotehtml } { return [string map {> > < < " \" & &} $arg] } #################### # # HTML -> HTML # #################### # # lars@pinds.com, 19 July 2000: # Should this proc change name to something in line with the rest # of the library? # ad_proc -private util_close_html_tags { html_fragment {break_soft 0} {break_hard 0} {ellipsis ""} {more ""} } { Given an HTML fragment, this procedure will close any tags that have been left open. The optional arguments let you specify that the fragment is to be truncated to a certain number of displayable characters. After break_soft, it truncates and closes open tags unless you're within non-breaking tags (e.g., Af). After break_hard displayable characters, the procedure simply truncates and closes any open HTML tags that might have resulted from the truncation.

    Note that the internal syntax table dictates which tags are non-breaking. The syntax table has codes:

    • nobr -- treat tag as nonbreaking.
    • discard -- throws away everything until the corresponding close tag.
    • remove -- nuke this tag and its closing tag but leave contents.
    • close -- close this tag if left open.
    @param break_soft the number of characters you want the html fragment truncated to. Will allow certain tags (A, ADDRESS, NOBR) to close first. @param break_hard the number of characters you want the html fragment truncated to. Will truncate, regardless of what tag is currently in action. @param ellipsis This will get put at the end of the truncated string, if the string was truncated. However, this counts towards the total string length, so that the returned string including ellipsis is guaranteed to be shorter than the 'len' provided. @param more This will get put at the end of the truncated string, if the string was truncated. @author Jeff Davis (davis@xarg.net) } { set frag $html_fragment # # The code in this function had an exponential behavior based on # the size. On the current OpenACS.org site (Jan 2009), the # function took on certain forums entries 6 to 9 hours # (e.g. /forums/message-view?message_id=357753). This is in # particular a problem, since bots like googlebot will timeout on # these entries (while OpenACS is still computing the content) and # retry after some time until they get the result (which never # happened). So, often multiple computation ran at the same # time. Since OpenACS.org is configured with only a few connection # threads, this is essentially a "bot DOS attack". # # Therefore, the tdom-based code in the next paragraph is used to # speedup the process significantly (most entries are anyway # correct). The forum processing query from above takes now 7.3 # seconds instead of 9h. The tdom-based code was developed as an # emergency measure. # # The code below the mentioned paragraph could be certainly as # well made faster, but this will require some more detailed # analysis. # # The best solution for forums would be to check the fragment not # at rendering time, but at creation time. # # -gustaf neumann (Jan 2009) if {$break_soft == 0 && $break_hard == 0} { set frag [string map [list &# "&#"] $html_fragment] if {[catch {dom parse -html $frag doc} errorMsg]} { # we got an error, so do normal processing ns_log notice "tdom can't parse the provided HTML, error=$errorMsg,\n\ checking fragment without tdom" } else { $doc documentElement root set html "" # discared forms foreach node [$root selectNodes //form] {$node delete} # output wellformed html set b [lindex [$root selectNodes {//body}] 0] foreach n [$b childNodes] { append html [$n asHTML] } return $html } } set frag $html_fragment # original code continues set syn(a) nobr set syn(address) nobr set syn(nobr) nobr # set syn(form) discard # set syn(blink) remove # set syn(table) close set syn(font) close set syn(b) close set syn(big) close set syn(i) close set syn(s) close set syn(small) close set syn(strike) close set syn(sub) close set syn(sup) close set syn(tt) close set syn(u) close set syn(abbr) close set syn(acronym) close set syn(cite) close set syn(code) close set syn(del) close set syn(dfn) close set syn(em) close set syn(ins) close set syn(kbo) close set syn(samp) close set syn(strong) close set syn(var) close set syn(dir) close set syn(dl) close set syn(menu) close set syn(ol) close set syn(ul) close set syn(h1) close set syn(h2) close set syn(h3) close set syn(h4) close set syn(h5) close set syn(h6) close set syn(bdo) close set syn(blockquote) close set syn(center) close set syn(div) close set syn(pre) close set syn(q) close set syn(span) close set out {} set out_len 0 # counts how deep we are nested in nonbreaking tags, tracks the nobr point # and what the nobr string length would be set nobr 0 set nobr_out_point 0 set nobr_tagptr 0 set nobr_len 0 if { $break_hard > 0 } { if { $break_soft == 0 } { set break_soft $break_hard } } set broken_p 0 set discard 0 set tagptr -1 # First try to fix up < not part of a tag. regsub -all {<([^/[:alpha:]!])} $frag {\<\1} frag # no we do is chop off any trailing unclosed tag # since when we substr blobs this sometimes happens # this should in theory cut any tags which have been cut open. while {[regexp {(.*)<[^>]*$} $frag match frag]} {} while { "$frag" != "" } { # here we attempt to cut the string into "pretagposttag" # and build the output list. if {![regexp "(\[^<]*)(<(/?)(\[^ \r\n\t>]+)(\[^>]*)>)?(.*)" $frag match pretag fulltag close tag tagbody frag]} { # should never get here since above will match anything. ns_log Error "util_close_html_tag - NO MATCH: should never happen! frag=$frag" append out $frag set frag {} } else { #ns_log Notice "pretag=$pretag\n fulltag=$fulltag\n close=$close\n tag=$tag\n tagbody=$tagbody frag length is [string length $frag]" if { ! $discard } { # figure out if we can break with the pretag chunk if { $break_soft } { if {! $nobr && [expr {[string length $pretag] + $out_len}] > $break_soft } { # first chop pretag to the right length set pretag [string range $pretag 0 [expr {$break_soft - $out_len - [string length $ellipsis]}]] # clip the last word regsub "\[^ \t\n\r]*$" $pretag {} pretag append out [string range $pretag 0 $break_soft] set broken_p 1 break } elseif { $nobr && [expr {[string length $pretag] + $out_len}] > $break_hard } { # we are in a nonbreaking tag and are past the hard break # so chop back to the point we got the nobr tag... set tagptr $nobr_tagptr if { $nobr_out_point > 0 } { set out [string range $out 0 [expr {$nobr_out_point - 1}]] } else { # here maybe we should decide if we should keep the tag anyway # if zero length result would be the result... set out {} } set broken_p 1 break } } # tack on pretag append out $pretag incr out_len [string length $pretag] } # now deal with the tag if we got one... if { $tag eq "" } { # if the tag is empty we might have one of the bad matched that are not eating # any of the string so check for them if {[string length $match] == [string length $frag]} { append out $frag set frag {} } } else { set tag [string tolower $tag] if { ![info exists syn($tag)]} { # if we don't have an entry in our syntax table just tack it on # and hope for the best. if { ! $discard } { append out $fulltag } } else { if { $close ne "/" } { # new tag # "remove" tags are just ignored here # discard tags if { $discard } { if { $syn($tag) eq "discard" } { incr discard incr tagptr set tagstack($tagptr) $tag } } else { switch $syn($tag) { nobr { if { ! $nobr } { set nobr_out_point [string length $out] set nobr_tagptr $tagptr set nobr_len $out_len } incr nobr incr tagptr set tagstack($tagptr) $tag append out $fulltag } discard { incr discard incr tagptr set tagstack($tagptr) $tag } close { incr tagptr set tagstack($tagptr) $tag append out $fulltag } } } } else { # we got a close tag if { $discard } { # if we are in discard mode only watch for # closes to discarded tags if { $syn($tag) eq "discard"} { if {$tagptr > -1} { if { $tag != $tagstack($tagptr) } { #puts "/$tag without $tag" } else { incr tagptr -1 incr discard -1 } } } } else { if { $syn($tag) ne "remove"} { # if tag is a remove tag we just ignore it... if {$tagptr > -1} { if {$tag != $tagstack($tagptr) } { # puts "/$tag without $tag" } else { incr tagptr -1 if { $syn($tag) eq "nobr"} { incr nobr -1 } append out $fulltag } } } } } } } } } # on exit of the look either we parsed it all or we truncated. # we should now walk the stack and close any open tags. # Chop off extra whitespace at the end if { $broken_p } { set end_index [expr {[string length $out] -1}] while { $end_index >= 0 && [string is space [string index $out $end_index]] } { incr end_index -1 } set out [string range $out 0 $end_index] } for { set i $tagptr } { $i > -1 } { incr i -1 } { set tag $tagstack($i) # LARS: Only close tags which we aren't supposed to remove if { $syn($tag) ne "discard" && $syn($tag) ne "remove" } { append out "" } } if { $broken_p } { append out $ellipsis append out $more } return $out } ad_proc ad_parse_html_attributes { -attribute_array html {pos 0} } { This is a wrapper proc for ad_parse_html_attributes_upvar, so you can parse attributes from a string without upvar'ing. See the documentation for the other proc. @author Lars Pind (lars@pinds.com) @creation-date November 10, 2000 } { if { [info exists attribute_array] } { upvar $attribute_array attribute_array_var return [ad_parse_html_attributes_upvar -attribute_array attribute_array_var html pos] } else { return [ad_parse_html_attributes_upvar html pos] } } ad_proc ad_parse_html_attributes_upvar { -attribute_array html_varname pos_varname } { Parse attributes in an HTML fragment and return them as a list of lists.

    Each element of that list is either a single element, if the attribute had no value, or a two-tuple, with the first element being the name of the attribute and the second being the value. The attribute names are all converted to lowercase.

    If you don't really care what happens when the same attribute is present twice, you can also use the attribute_array argument, and the attributes will be set there. For attributes without any value, we'll use the empty string.

    Example:

    set html {<tag foo = bar baz greble="&quot;hello you sucker&quot;" foo='blah' Heres = '  something for   you to = "consider" '>}
    set pos 5 ; # the 'f' in the first 'foo'
    
    set attribute_list [ad_parse_html_attributes_upvar -attribute_array attribute_array html pos]
    attribute_list will contain the following:
    {foo bar} baz {greble {"hello you sucker"}} {foo blah} {heres {  something for   you to = "consider" }}
    attribute_array will contain:
    attribute_array(foo)='blah'
    attribute_array(greble)='"hello you sucker"'
    attribute_array(baz)=''
    attribute_array(heres)='  something for   you to = "consider" '

    Won't alter the string passed in .. promise! We will modify pos_var. Pos_var should point to the first character inside the tag, after the tag name (we don't care if you let if there's some whitespace before the first attribute) @param html_varname the name of the variable holding the HTML fragment. We promise that we won't change the contents of this variable. @param pos_varname the name of the variable holding the position within the html_varname string from which we should start. This should point to a character inside the tag, just after the tag name, and before the first attribute. Note, that we will modify this variable. When this proc is done, this variable will point to the tag-closing >. Example: if the tag is <img src="foo">, pos_varname should point to either the space between img and src, or the s in src. @param attribute_array This is an alternate way of returning the attributes, if you don't care about what happens when the same attribute name is defined twice. @return A list of list holding the attribute names and values. Each element of that list is either a single element, if the attribute had no value, or a two-tuple, with the first element being the name of the attribute and the second being the value. The attribute names are all converted to lowercase. @author Lars Pind (lars@pinds.com) @creation-date November 10, 2000 } { upvar $html_varname html upvar $pos_varname i if { [info exists attribute_array] } { upvar $attribute_array attribute_array_var } # This is where we're going to return the result set attributes {} # Loop over the attributes. # We maintain counter is so that we don't accidentally enter an infinite loop set count 0 while { $i < [string length $html] && ![string equal [string index $html $i] {>}] } { if { [incr count] > 1000 } { error "There appears to be a programming bug in ad_parse_html_attributes_upvar: We've entered an infinite loop. We are here: \noffset $i: [string range $html $i [expr {$i + 60}]]" } if { [string equal [string range $html $i [expr { $i + 1 }]] "/>"] } { # This is an XML-style tag ending: <... /> break } # This regexp matches an attribute name and an equal sign, if present. # Also eats whitespace before or after. # The \A corresponds to ^, except it matches the position we're starting from, not the start of the string if { ![regexp -indices -start $i {\A\s*([^\s=>]+)\s*(=?)\s*} $html match attr_name_idx equal_sign_idx] } { # Apparantly, there's no attribute name here. Let's eat all whitespace and lonely equal signs. regexp -indices -start $i {\A[\s=]*} $html match set i [expr { [lindex $match 1] + 1 }] } { set attr_name [string tolower [string range $html [lindex $attr_name_idx 0] [lindex $attr_name_idx 1]]] # Move past the attribute name just found set i [expr { [lindex $match 1] + 1}] # If there is an equal sign, we're expecting the next token to be a value if { [lindex $equal_sign_idx 1] - [lindex $equal_sign_idx 0] < 0 } { # No equal sign, no value lappend attributes $attr_name if { [info exists attribute_array] } { set attribute_array_var($attr_name) {} } } else { # is there a single or double quote sign as the first character? switch -- [string index $html $i] { {"} { set exp {\A"([^"]*)"\s*} } {'} { set exp {\A'([^']*)'\s*} } default { set exp {\A([^\s>]*)\s*} } } if { ![regexp -indices -start $i $exp $html match attr_value_idx] } { # No end quote. set attr_value [string range $html [expr {$i+1}] end] set i [string length $html] } else { set attr_value [string range $html [lindex $attr_value_idx 0] [lindex $attr_value_idx 1]] set i [expr { [lindex $match 1] + 1}] } set attr_value [util_expand_entities_ie_style $attr_value] lappend attributes [list $attr_name $attr_value] if { [info exists attribute_array] } { set attribute_array_var($attr_name) $attr_value } } } } return $attributes } ad_proc ad_html_security_check { html } { Returns a human-readable explanation if the user has used any HTML tag other than the ones marked allowed in antispam section of ad.ini. Otherwise returns an empty string. @return a human-readable, plaintext explanation of what's wrong with the user's input. @author Lars Pind (lars@pinds.com) @creation-date 20 July 2000 } { if { [string first <% $html] > -1 } { return "For security reasons, you're not allowed to have the less-than-percent combination in your input." } array set allowed_attribute [list] array set allowed_tag [list] array set allowed_protocol [list] # Use the antispam tags for this package instance and whatever is on the kernel. set allowed_tags_list [concat \ [ad_parameter_all_values_as_list -package_id [ad_acs_kernel_id] AllowedTag antispam] \ [ad_parameter_all_values_as_list AllowedTag antispam]] set allowed_attributes_list [concat \ [ad_parameter_all_values_as_list -package_id [ad_acs_kernel_id] AllowedAttribute antispam] \ [ad_parameter_all_values_as_list AllowedAttribute antispam]] set allowed_protocols_list [concat \ [ad_parameter_all_values_as_list -package_id [ad_acs_kernel_id] AllowedProtocol antispam] \ [ad_parameter_all_values_as_list AllowedProtocol antispam]] foreach tag $allowed_tags_list { set allowed_tag([string tolower $tag]) 1 } foreach attribute $allowed_attributes_list { set allowed_attribute([string tolower $attribute]) 1 } foreach tagname $allowed_tags_list { set allowed_tag([string tolower $tagname]) 1 } foreach protocol $allowed_protocols_list { set allowed_protocol([string tolower $protocol]) 1 } # loop over all tags for { set i [string first < $html] } { $i != -1 } { set i [string first < $html $i] } { # move past the tag-opening < incr i if { ![regexp -indices -start $i {\A/?([-_a-zA-Z0-9]+)\s*} $html match name_idx] } { # The tag-opener isn't followed by USASCII letters (with or without optional inital slash) # Not considered a tag. Shouldn't do any harm in browsers. # (Tested with digits, with A syntax, with whitespace) } else { # The tag was valid ... now let's see if it's on the allowed list. set tagname [string tolower [string range $html [lindex $name_idx 0] [lindex $name_idx 1]]] if { ![info exists allowed_tag($tagname)] && ![info exists allowed_tag(*)] } { # Nope, this was a naughty tag. return "For security reasons we only accept the submission of HTML containing the following tags: [join $allowed_tags_list " "]. You have a [string toupper $tagname] tag in there." } else { # Legal tag. # Make i point to the first character inside the tag, after the tag name and any whitespace set i [expr { [lindex $match 1] + 1}] set attr_list [ad_parse_html_attributes_upvar html i] set attr_count 0 foreach attribute $attr_list { incr attr_count set attr_name [lindex $attribute 0] set attr_value [lindex $attribute 1] if { ![info exists allowed_attribute($attr_name)] && ![info exists allowed_attribute(*)] } { return "The attribute '$attr_name' is not allowed for $tagname tags" } if { [string tolower $attr_name] ne "style" } { if { [regexp {^\s*([^\s:]+):} $attr_value match protocol] } { if { ![info exists allowed_protocol([string tolower $protocol])] && ![info exists allowed_protocol(*)] } { return "Your URLs can only use these protocols: [join $allowed_protocols_list ", "]. You have a '$protocol' protocol in there." } } } } } } } return {} } #################### # # HTML -> Text # #################### ad_proc -public ad_html_to_text { {-maxlen 70} {-showtags:boolean} {-no_format:boolean} html } { Returns a best-guess plain text version of an HTML fragment. Parses the HTML and does some simple formatting. The parser and formatting is pretty stupid, but it's better than nothing. @param maxlen the line length you want your output wrapped to. @param showtags causes any unknown (and uninterpreted) tags to get shown in the output. @param no_format causes hyperlink tags not to get listed at the end of the output. @author Lars Pind (lars@pinds.com) @author Aaron Swartz (aaron@swartzfam.com) @creation-date 19 July 2000 } { set output(text) {} set output(linelen) 0 set output(maxlen) $maxlen set output(pre) 0 set output(p) 0 set output(br) 0 set output(space) 0 set output(blockquote) 0 set length [string length $html] set last_tag_end 0 # For showing the URL of links. set href_urls [list] set href_stack [list] for { set i [string first < $html] } { $i != -1 } { set i [string first < $html $i] } { # append everything up to and not including the tag-opening < ad_html_to_text_put_text output [string range $html $last_tag_end [expr {$i - 1}]] # Check that: # - we're not past the end of the string # - and that the tag starts with either # - alpha or # - a slash, and then alpha # Otherwise, it's probably just a lone < character if { $i >= [expr {$length-1}] || \ (![string is alpha [string index $html [expr {$i + 1}]]] && \ [string index $html [expr {$i + 1}]] ne "!" && \ (![string equal "/" [string index $html [expr {$i + 1}]]] || \ ![string is alpha [string index $html [expr {$i + 2}]]])) } { # Output the < and continue with next character ad_html_to_text_put_text output "<" set last_tag_end [incr i] continue } elseif {[string match "!--*" [string range $html [expr {$i + 1}] end]]} { # handle HTML comments, I can't beleive noone noticed this before. # this code maybe not be elegant but it works # find the closing comment tag. set comment_idx [string first "-->" $html $i] if {$comment_idx == -1} { # no comment close, escape set last_tag_end $i set i $comment_idx break } set i [expr {$comment_idx + 3}] set last_tag_end $i continue } # we're inside a tag now. Find the end of it # make i point to the char after the < incr i set tag_start $i set count 0 while 1 { if {[incr count] > 1000 } { # JCD: the programming bug is that an unmatched < in the input runs off forever looking for # it's closing > and in some long text like program listings you can have lots of quotes # before you find that > error "There appears to be a programming bug in ad_html_to_text: We've entered an infinite loop." } # Find the positions of the first quote, apostrophe and greater-than sign. set quote_idx [string first \" $html $i] set apostrophe_idx [string first ' $html $i] set gt_idx [string first > $html $i] # If there is no greater-than sign, then the tag isn't closed. if { $gt_idx == -1 } { set i $length break } # Find the first of the quote and the apostrophe if { $apostrophe_idx == -1 } { set string_delimiter_idx $quote_idx } else { if { $quote_idx == -1 } { set string_delimiter_idx $apostrophe_idx } else { if { $apostrophe_idx < $quote_idx } { set string_delimiter_idx $apostrophe_idx } else { set string_delimiter_idx $quote_idx } } } set string_delimiter [string index $html $string_delimiter_idx] # If the greater than sign appears before any of the string delimters, we've found the tag end. if { $gt_idx < $string_delimiter_idx || $string_delimiter_idx == -1 } { # we found the tag end set i $gt_idx break } # Otherwise, we'll have to skip past the ending string delimiter set i [string first $string_delimiter $html [incr string_delimiter_idx]] if { $i == -1 } { # Missing string end delimiter set i $length break } incr i } set full_tag [string range $html $tag_start [expr { $i - 1 }]] if { ![regexp {^(/?)([^\s]+)[\s]*(\s.*)?$} $full_tag match slash tagname attributes] } { # A malformed tag -- just delete it } else { # Reset/create attribute array array unset attribute_array # Parse the attributes ad_parse_html_attributes -attribute_array attribute_array $attributes switch -- [string tolower $tagname] { p - ul - ol - table { set output(p) 1 } br { ad_html_to_text_put_newline output } tr - td - th { set output(br) 1 } h1 - h2 - h3 - h4 - h5 - h6 { set output(p) 1 if { $slash eq "" } { ad_html_to_text_put_text output [string repeat "*" [string index $tagname 1]] } } li { set output(br) 1 if { $slash eq "" } { ad_html_to_text_put_text output "- " } } strong - b { ad_html_to_text_put_text output "*" } em - i - cite - u { ad_html_to_text_put_text output "_" } a { if { !$no_format_p } { if { $slash eq ""} { if { [info exists attribute_array(href)] } { if { [info exists attribute_array(title)] } { set title ": '$attribute_array(title)'" } else { set title "" } set href_no [expr {[llength $href_urls] + 1}] lappend href_urls "\[$href_no\] $attribute_array(href) " lappend href_stack "\[$href_no$title\]" } elseif { [info exists attribute_array(title)] } { lappend href_stack "\[$attribute_array(title)\]" } else { lappend href_stack {} } } else { if { [llength $href_stack] > 0 } { if { ![empty_string_p [lindex $href_stack end]] } { ad_html_to_text_put_text output " [lindex $href_stack end]" } set href_stack [lreplace $href_stack end end] } } } } pre { set output(p) 1 if { $slash eq "" } { incr output(pre) } else { incr output(pre) -1 } } blockquote { set output(p) 1 if { $slash eq "" } { incr output(blockquote) incr output(maxlen) -4 } else { incr output(blockquote) -1 incr output(maxlen) 4 } } hr { set output(p) 1 ad_html_to_text_put_text output [string repeat "-" $output(maxlen)] set output(p) 1 } q { ad_html_to_text_put_text output \" } img { if { $slash eq "" && !$no_format_p } { set img_info {} if { [info exists attribute_array(alt)] } { lappend img_info "'$attribute_array(alt)'" } if { [info exists attribute_array(src)] } { lappend img_info $attribute_array(src) } if { [llength $img_info] == 0 } { ad_html_to_text_put_text output {[IMAGE]} } else { ad_html_to_text_put_text output "\[IMAGE: [join $img_info " "] \]" } } } default { # Other tag if { $showtags_p } { ad_html_to_text_put_text output "<$slash$tagname$attributes>" } } } } # set end of last tag to the character following the > set last_tag_end [incr i] } # append everything after the last tag ad_html_to_text_put_text output [string range $html $last_tag_end end] # Close any unclosed tags set output(pre) 0 while { $output(blockquote) > 0 } { incr output(blockquote) -1 incr output(maxlen) 4 } # write out URLs, if necessary: if { [llength $href_urls] > 0 } { append output(text) "\n\n[join $href_urls "\n"]" } #--- # conversion like in ad_text_to_html # 2006/09/12 set myChars { ª º À à Â Ã Ä Ã… Æ Ç È É Ê Ë ÃŒ à Î à à Ñ Ã’ Ó Ô Õ Ö Ø Ù Ú Û Ü à Þ ß à á â ã ä Ã¥ æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ ¿ } set myHTML { ª º À Á Â Ã Ä Å &Aelig; Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ ¿ } for { set i 0 } { $i < [ llength $myHTML ] } { incr i } { set output(text) [ string map "[ lindex $myHTML $i ] [ lindex $myChars $i ]" $output(text) ] } #--- return $output(text) } ad_proc -private ad_html_to_text_put_newline { output_var } { Helper proc for ad_html_to_text @author Lars Pind (lars@pinds.com) @author Aaron Swartz (aaron@swartzfam.com) @creation-date 22 September 2000 } { upvar $output_var output append output(text) \n set output(linelen) 0 append output(text) [string repeat { } $output(blockquote)] } ad_proc -private ad_html_to_text_put_text { output_var text } { Helper proc for ad_html_to_text @author Lars Pind (lars@pinds.com) @author Aaron Swartz (aaron@swartzfam.com) @creation-date 19 July 2000 } { upvar $output_var output # Expand entities before outputting set text [util_expand_entities $text] # If we're not in a PRE if { $output(pre) <= 0 } { # collapse all whitespace regsub -all {\s+} $text { } text # if there's only spaces in the string, wait until later if {$text eq " "} { set output(space) 1 return } # if it's nothing, do nothing if { $text eq "" } { return } # if the first character is a space, set the space bit if {[string index $text 0] eq " "} { set output(space) 1 set text [string trimleft $text] } } else { # we're in a PRE: clean line breaks and tabs regsub -all {\r\n} $text "\n" text regsub -all {\r} $text "\n" text # tabs become four spaces regsub -all {[\v\t]} $text { } text } # output any pending paragraph breaks, line breaks or spaces. # as long as we're not at the beginning of the document if { $output(p) || $output(br) || $output(space) } { if { $output(text) ne "" } { if { $output(p) } { ad_html_to_text_put_newline output ad_html_to_text_put_newline output } elseif { $output(br) } { ad_html_to_text_put_newline output } else { # Don't add the space if we're at the beginning of a line, # unless we're in a PRE if { $output(pre) > 0 || $output(linelen) != 0 } { append output(text) " " incr output(linelen) } } } set output(p) 0 set output(br) 0 set output(space) 0 } # if the last character is a space, save it until the next time if { [regexp {^(.*) $} $text match text] } { set output(space) 1 } # If there's a blockquote in the beginning of the text, we wouldn't have caught it before if { $output(text) eq "" } { append output(text) [string repeat { } $output(blockquote)] } # Now output the text. while { [regexp {^( +|\s|\S+)(.*)$} $text match word text] } { # convert  's # We do this now, so that they're displayed, but not treated, whitespace. regsub -all { } $word { } word set wordlen [string length $word] switch -glob -- $word { " *" { append output(text) "$word" incr output(linelen) $wordlen } "\n" { if { $output(text) ne "" } { ad_html_to_text_put_newline output } } default { if { [expr {$output(linelen) + $wordlen}] > $output(maxlen) && $output(maxlen) != 0 } { ad_html_to_text_put_newline output } append output(text) "$word" incr output(linelen) $wordlen } } } } ad_proc util_expand_entities { html } { Replaces all occurrences of common HTML entities with their plaintext equivalents in a way that's appropriate for pretty-printing.

    Currently, the following entities are converted: &lt;, &gt;, &apm;quot;, &amp;, &mdash; and &#151;.

    This proc is more suitable for pretty-printing that it's sister-proc, util_expand_entities_ie_style. The two differences are that this one is more strict: it requires proper entities i.e., both opening ampersand and closing semicolon, and it doesn't do numeric entities, because they're generally not safe to send to browsers. If we want to do numeric entities in general, we should also consider how they interact with character encodings. } { regsub -all {<} $html {<} html regsub -all {>} $html {>} html regsub -all {"} $html "\"" html regsub -all {—} $html {--} html regsub -all {—} $html {--} html # Need to do the & last, because otherwise it could interfere with the other expansions, # e.g., if the text said &lt;, that would be translated into <, instead of < regsub -all {&} $html {\&} html return $html } ad_proc util_expand_entities_ie_style { html } { Replaces all occurrences of &#111; and &x0f; type HTML character entities to their ASCII equivalents. It also handles lt, gt, quot, ob, cb and amp.

    This proc does the expansion in the style of IE and Netscape, which is to say that it doesn't require the trailing semicolon on the entity to replace it with something else. The reason we do that is that this proc was designed for checking HTML for security-issues, and since entities can be used for hiding malicious code, we'd better simulate the liberal interpretation that browsers does, even though it complicates matters.

    Unlike it's sister proc, util_expand_entities, it also expands numeric entities (#999 or #xff style). @author Lars Pind (lars@pinds.com) @creation-date October 17, 2000 } { array set entities { lt < gt > quot \" ob \{ cb \} amp & } # Expand HTML entities on the value for { set i [string first & $html] } { $i != -1 } { set i [string first & $html $i] } { set match_p 0 switch -regexp -- [string index $html [expr {$i+1}]] { # { switch -regexp -- [string index $html [expr {$i+2}]] { [xX] { regexp -indices -start [expr {$i+3}] {[0-9a-fA-F]*} $html hex_idx set hex [string range $html [lindex $hex_idx 0] [lindex $hex_idx 1]] set html [string replace $html $i [lindex $hex_idx 1] \ [subst -nocommands -novariables "\\x$hex"]] set match_p 1 } [0-9] { regexp -indices -start [expr {$i+2}] {[0-9]*} $html dec_idx set dec [string range $html [lindex $dec_idx 0] [lindex $dec_idx 1]] # $dec might contain leading 0s. Since format evaluates $dec as expr # leading 0s cause octal interpretation and therefore errors on e.g. & set dec [string trimleft $dec 0] if {$dec eq ""} {set dec 0} set html [string replace $html $i [lindex $dec_idx 1] \ [format "%c" $dec]] set match_p 1 } } } [a-zA-Z] { if { [regexp -indices -start [expr {$i}] {\A&([^\s;]+)} $html match entity_idx] } { set entity [string tolower [string range $html [lindex $entity_idx 0] [lindex $entity_idx 1]]] if { [info exists entities($entity)] } { set html [string replace $html $i [lindex $match 1] $entities($entity)] } set match_p 1 } } } incr i if { $match_p } { # remove trailing semicolon if { [string equal [string index $html $i] {;}] } { set html [string replace $html $i $i] } } } return $html } #################### # # Text -> Text # #################### ad_proc wrap_string {input {threshold 80}} { wraps a string to be no wider than 80 columns by inserting line breaks } { set result_rows [list] set start_of_line_index 0 while 1 { set this_line [string range $input $start_of_line_index [expr {$start_of_line_index + $threshold - 1}]] if { $this_line eq "" } { return [join $result_rows "\n"] } set first_new_line_pos [string first "\n" $this_line] if { $first_new_line_pos != -1 } { # there is a newline lappend result_rows [string range $input $start_of_line_index [expr {$start_of_line_index + $first_new_line_pos - 1}]] set start_of_line_index [expr {$start_of_line_index + $first_new_line_pos + 1}] continue } if { [expr {$start_of_line_index + $threshold + 1}] >= [string length $input] } { # we're on the last line and it is < threshold so just return it lappend result_rows $this_line return [join $result_rows "\n"] } set last_space_pos [string last " " $this_line] if { $last_space_pos == -1 } { # no space found! Try the first space in the whole rest of the string set next_space_pos [string first " " [string range $input $start_of_line_index end]] set next_newline_pos [string first "\n" [string range $input $start_of_line_index end]] if {$next_space_pos == -1} { set last_space_pos $next_newline_pos } elseif {$next_space_pos < $next_newline_pos} { set last_space_pos $next_space_pos } else { set last_space_pos $next_newline_pos } if { $last_space_pos == -1 } { # didn't find any more whitespace, append the whole thing as a line lappend result_rows [string range $input $start_of_line_index end] return [join $result_rows "\n"] } } # OK, we have a last space pos of some sort set real_index_of_space [expr {$start_of_line_index + $last_space_pos}] lappend result_rows [string range $input $start_of_line_index [expr {$real_index_of_space - 1}]] set start_of_line_index [expr {$start_of_line_index + $last_space_pos + 1}] } } #################### # # Wrappers to make it easier to write generic code # #################### ad_proc -public ad_html_text_convertable_p { -from -to } { Returns true of ad_html_text_convert can handle the given from and to mime types. } { set valid_froms { text/enhanced text/plain text/fixed-width text/html text/xml } set valid_tos { text/plain text/html } # Validate procedure input set from [ad_decode $from "html" "text/html" "text" "text/plain" "plain" "text/plain" $from] set to [ad_decode $to "html" "text/html" "text" "text/plain" "plain" "text/plain" $to] return [expr {[lsearch $valid_froms $from] != -1 && [lsearch $valid_tos $to] != -1}] } ad_proc -public ad_html_text_convert { {-from text/plain} {-to text/html} {-maxlen 70} {-truncate_len 0} {-ellipsis "..."} {-more ""} text } { Converts a chunk of text from a variety of formats to either text/html or text/plain.

    Example: ad_html_text_convert -from "text/html" -to "text/plain" -- "text"

    Putting in the -- prevents Tcl from treating a - in text portion from being treated as a parameter.

    Html to html closes any unclosed html tags (see util_close_html_tags).

    Text to html does ad_text_to_html, and html to text does a ad_html_to_text. See those procs for details.

    When text is empty, then an empty string will be returned regardless of any format. This is especially useful when displaying content that was created with the richtext widget and might contain empty values for content and format. @param from specify what type of text you're providing. Allowed values:

    • text/plain
    • text/enhanced
    • text/fixed-width
    • text/html
    @param to specify what format you want this translated into. Allowed values:
    • text/plain
    • text/html
    @param maxlen The maximum line width when generating text/plain @param truncate_len The maximum total length of the output, included ellipsis. @param ellipsis This will get put at the end of the truncated string, if the string was truncated. However, this counts towards the total string length, so that the returned string including ellipsis is guaranteed to be shorter than the 'truncate_len' provided. @param more This will get put at the end of the truncated string, if the string was truncated. @author Lars Pind (lars@pinds.com) @creation-date 19 July 2000 } { # DRB: Modified this to accept mime types (text/plain or # text/html). Simplies things when providing confirmation pages # for input destined for the content repository ... if { $text eq "" } { return "" } # For backwards compatibility set from [ad_decode $from "html" "text/html" "text" "text/plain" "plain" "text/plain" $from] set to [ad_decode $to "html" "text/html" "text" "text/plain" "plain" "text/plain" $to] if { ![ad_html_text_convertable_p -from $from -to $to] } { error "Illegal mime types for conversion - from: $from to: $to" } # Do the conversion switch $from { text/enhanced { switch $to { text/html { set text [ad_enhanced_text_to_html $text] } text/plain { set text [ad_enhanced_text_to_plain_text -maxlen $maxlen -- $text] } } } text/plain { switch $to { text/html { set text [ad_text_to_html -- $text] } text/plain { set text [wrap_string $text $maxlen] } } } text/fixed-width { switch $to { text/html { set text "
    [ad_text_to_html -no_lines -- $text]
    " } text/plain { set text [wrap_string $text $maxlen] } } } text/html { switch $to { text/html { # Handled below } text/plain { set text [ad_html_to_text -maxlen $maxlen -- $text] } } } text/xml { switch $to { text/html { set text "
    [ad_text_to_html -no_lines -- $text]
    " } text/plain { set text [wrap_string $text $maxlen] } } } } # Handle closing of HTML tags, truncation switch $to { text/html { set text [util_close_html_tags $text $truncate_len $truncate_len $ellipsis $more] } text/plain { set text [string_truncate -ellipsis $ellipsis -more $more -len $truncate_len -- $text] } } return $text } ad_proc -public ad_enhanced_text_to_html { text } { Converts enhanced text format to normal HTML. @author Lars Pind (lars@pinds.com) @creation-date 2003-01-27 } { return [ad_text_to_html -no_quote -includes_html -- $text] } ad_proc -public ad_enhanced_text_to_plain_text { {-maxlen 70} text } { Converts enhanced text format to normal plaintext format. @author Lars Pind (lars@pinds.com) @creation-date 2003-01-27 } { # Convert the HTML version to plaintext. return [ad_html_to_text -maxlen $maxlen -- [ad_enhanced_text_to_html $text]] } ad_proc -public ad_convert_to_html { {-html_p f} text } { Convenient interface to convert text or html into html. Does the same as ad_html_text_convert -to html. @param html_p specify t if the value of text is formatted in HTML, or f if text is plaintext. @author Lars Pind (lars@pinds.com) @creation-date 19 July 2000 } { if {$html_p eq "t"} { set from "text/html" } else { set from "text/plain" } return [ad_html_text_convert -from $from -to "text/html" -- $text] } ad_proc -public ad_convert_to_text { {-html_p t} text } { Convenient interface to convert text or html into plaintext. Does the same as ad_html_text_convert -to text. @param html_p specify t if the value of text is formatted in HTML, or f if text is plaintext. @author Lars Pind (lars@pinds.com) @creation-date 19 July 2000 } { if {$html_p eq "t"} { set from "text/html" } else { set from "text/plain" } return [ad_html_text_convert -from $from -to "text/plain" -- $text] } ad_proc -public ad_looks_like_html_p { text } { Tries to guess whether the text supplied is text or html. @param text the text you want tested. @return 1 if it looks like html, 0 if not. @author Lars Pind (lars@pinds.com) @creation-date 19 July 2000 } { if { [regexp -nocase {

    } $text] || [regexp -nocase {
    } $text] || [regexp -nocase {]*>} $html {} html return $html } ##### # # Truncate # ##### ad_proc -public string_truncate { {-len 200} {-ellipsis "..."} {-more ""} string } { Truncates a string to len characters (defaults to the parameter TruncateDescriptionLength), adding the string provided in the ellipsis parameter if the string was truncated. If format is html (default), any open HTML tags are closed. Otherwise, it's converted to text using ad_html_to_text. The length of the resulting string, including the ellipsis, is guaranteed to be within the len specified. Should always be called as string_truncate [-flags ...] -- string since otherwise strings which start with a - will treated as switches, and will cause an error. @param len The lenght to truncate to. If zero, no truncation will occur. @param ellipsis This will get put at the end of the truncated string, if the string was truncated. However, this counts towards the total string length, so that the returned string including ellipsis is guaranteed to be shorter than the 'len' provided. @param more This will get put at the end of the truncated string, if the string was truncated. @param string The string to truncate. @return The truncated string, with HTML tags cloosed or converted to text, depending on format. @author Lars Pind (lars@pinds.com) @creation-date September 8, 2002 } { if { $len > 0 } { if { [string length $string] > $len } { set end_index [expr $len-[string length $ellipsis]-1] # Back up to the nearest whitespace if { ![string is space [string index $string [expr {$end_index + 1}]]] } { while { $end_index >= 0 && ![string is space [string index $string $end_index]] } { incr end_index -1 } } # If that laves us with an empty string, then ignore whitespace and just truncate mid-word if { $end_index == -1 } { set end_index [expr $len-[string length $ellipsis]-1] } # Chop off extra whitespace at the end while { $end_index >= 0 && [string is space [string index $string $end_index]] } { incr end_index -1 } set string [string range $string 0 $end_index] append string $ellipsis append string $more } } return $string } #################### # # Legacy stuff # #################### ad_proc -deprecated util_striphtml {html} { Deprecated. Use ad_html_to_text instead. @see ad_html_to_text } { return [ad_html_to_text -- $html] } ad_proc -deprecated util_convert_plaintext_to_html { raw_string } { Almost everything this proc does can be accomplished with the ad_text_to_html. Use that proc instead.

    Only difference is that ad_text_to_html doesn't check to see if the plaintext might in fact be HTML already by mistake. But we usually don't want that anyway, because maybe the user wanted a <p> tag in his plaintext. We'd rather let the user change our opinion about the text, e.g. html_p = 't'. @see ad_text_to_html } { if { [regexp -nocase {

    } $raw_string] || [regexp -nocase {
    } $raw_string] } { # user was already trying to do this as HTML return $raw_string } else { return [ad_text_to_html -no_links -- $raw_string] } } ad_proc -deprecated util_maybe_convert_to_html {raw_string html_p} { This proc is deprecated. Use ad_convert_to_html instead. @see ad_convert_to_html } { if { $html_p eq "t" } { return $raw_string } else { return [util_convert_plaintext_to_html $raw_string] } } ad_proc -deprecated -warn util_quotehtml { arg } { This proc does exactly the same as ad_quotehtml. Use that instead. This one will be deleted eventually. @see ad_quotehtml } { return [ad_quotehtml $arg] } ad_proc -deprecated util_quote_double_quotes {arg} { This proc does exactly the same as ad_quotehtml. Use that instead. This one will be deleted eventually. @see ad_quotehtml } { return [ad_quotehtml $arg] } ad_proc -deprecated philg_quote_double_quotes {arg} { This proc does exactly the same as ad_quotehtml. Use that instead. This one will be deleted eventually. @see ad_quotehtml } { return [ad_quotehtml $arg] } openacs-5.7.0/packages/acs-tcl/tcl/apm-install-procs-postgresql.xql0000644000175000017500000001537711354707673025207 0ustar frankiefrankie postgresql7.1 select apm_package_version__new( :version_id, :package_key, :version_name, :version_uri, :summary, :description_format, :description, :release_date, :vendor, :vendor_uri, :auto_mount, 't', 't' ); select apm_package_type__drop_type( :package_key, 't' ); select apm_package_version__delete(:version_id); update apm_package_versions set installed_p = (version_id = :version_id) where package_key = :package_key select apm_package_version__disable( :version_id ); select apm__register_application ( :package_key, :pretty_name, :pretty_plural, :package_uri, :initial_install_p, :singleton_p, :implements_subsite_p, :inherit_templates_p, :spec_file_path, :spec_file_mtime ); select apm__register_service ( :package_key, :pretty_name, :pretty_plural, :package_uri, :initial_install_p, :singleton_p, :implements_subsite_p, :inherit_templates_p, :spec_file_path, :spec_file_mtime ); select apm_package_version__edit( null, :version_id, :version_name, :version_uri, :summary, :description_format, :description, :release_date, :vendor, :vendor_uri, :auto_mount, 't', 't' ); select apm_package_version__upgrade(:version_id); select apm_package_version__upgrade_p( :path, :initial_version_name, :final_version_name ); select apm_package_version__sortable_version_name(:f1_version_from); select apm_package_version__sortable_version_name(:f2_version_from); select apm_package_version__version_name_greater(service_version, :dependency_version) as version_p from apm_package_dependencies d, apm_package_types a, apm_package_versions v where d.dependency_type = 'provides' and d.version_id = v.version_id and d.service_uri = :dependency_uri and v.installed_p = 't' and a.package_key = v.package_key select apm_package_version__version_name_greater(:provided_version, :dependency_version) select version_id from apm_package_versions where package_key = :package_key and version_id = apm_package__highest_version(:package_key) select apm__parameter_p(:descendent_package_key, :parameter_name); select apm__register_parameter(null, :descendent_package_key, :parameter_name, :description, :scope, :datatype, :default_value, :section_name, :min_n_values, :max_n_values) select apm__parameter_p(:new_package_key, :parameter_name); select apm__register_parameter(null, :new_package_key, :parameter_name, :description, :scope, :datatype, :default_value, :section_name, :min_n_values, :max_n_values) select apm_package_version__version_name_greater(:version_name, version_name) as upgrade_p from apm_package_versions where package_key = :package_key and version_id = apm_package__highest_version (:package_key) select apm_package_version__enable( :version_id ); select version_name from apm_package_versions where package_key = :package_key and version_id = apm_package__highest_version(:package_key) select apm_package_version__sortable_version_name(:version_name_1) as sortable_version_1, apm_package_version__sortable_version_name(:version_name_2) as sortable_version_2 from dual select apm_package_version__sortable_version_name(:version) openacs-5.7.0/packages/acs-tcl/tcl/site-node-object-map-procs.tcl0000644000175000017500000000237210551254404024423 0ustar frankiefrankie# tcl/portal-node-mapping-procs.tcl ad_library { Portal Node Mappings @author Ben Adida (ben@openforce.net) @creation-date April 2002 @cvs-id $Id: site-node-object-map-procs.tcl,v 1.4 2007/01/10 21:22:12 gustafn Exp $ } namespace eval site_node_object_map {} ad_proc -public site_node_object_map::new { {-object_id:required} {-node_id:required} } { map object object_id to site_node node_id in table site_node_object_mappings } { db_exec_plsql set_node_mapping {} } ad_proc -public site_node_object_map::del { {-object_id:required} } { unmap object object_id from site_node node_id in table site_node_object_mappings } { db_exec_plsql unset_node_mapping {} } ad_proc -public site_node_object_map::get_node_id { {-object_id:required} } { @return the node_id of the site_node of the passed object_id } { return [db_string select_node_mapping {} -default ""] } ad_proc -public site_node_object_map::get_url { {-object_id:required} } { @return the url corresponding to the site_node to which the passed object_id is mapped. } { set node_id [site_node_object_map::get_node_id -object_id $object_id] if {$node_id eq ""} { return {} } return [site_node::get_url -node_id $node_id] } openacs-5.7.0/packages/acs-tcl/tcl/site-node-object-map-procs.xql0000644000175000017500000000044607504712423024451 0ustar frankiefrankie select node_id from site_node_object_mappings where object_id = :object_id openacs-5.7.0/packages/acs-tcl/tcl/apm-install-procs-oracle.xql0000644000175000017500000002202611354707673024236 0ustar frankiefrankie oracle8.1.6 begin :1 := apm_package_version.new( version_id => :version_id, package_key => :package_key, version_name => :version_name, version_uri => :version_uri, summary => :summary, description_format => :description_format, description => :description, release_date => :release_date, vendor => :vendor, vendor_uri => :vendor_uri, auto_mount => :auto_mount, installed_p => 't', data_model_loaded_p => 't' ); end; begin :1 := apm_package_version.new( version_id => :version_id, package_key => :package_key, version_name => :version_name, version_uri => :version_uri, summary => :summary, description_format => :description_format, description => :description, release_date => :release_date, vendor => :vendor, vendor_uri => :vendor_uri, auto_mount => :auto_mount, installed_p => 't', data_model_loaded_p => 't' ); end; begin apm_package_type.drop_type( package_key => :package_key, cascade_p => 't' ); end; begin apm_package_version.del(version_id => :version_id); end; update apm_package_versions set installed_p = decode(version_id, :version_id, 't', 'f') where package_key = :package_key begin apm_package_version.enable( version_id => :version_id ); end; begin apm_package_version.disable( version_id => :version_id ); end; begin apm.register_application ( package_key => :package_key, package_uri => :package_uri, pretty_name => :pretty_name, pretty_plural => :pretty_plural, initial_install_p => :initial_install_p, singleton_p => :singleton_p, implements_subsite_p => :implements_subsite_p, inherit_templates_p => :inherit_templates_p, spec_file_path => :spec_file_path, spec_file_mtime => :spec_file_mtime ); end; begin apm.register_service ( package_key => :package_key, package_uri => :package_uri, pretty_name => :pretty_name, pretty_plural => :pretty_plural, initial_install_p => :initial_install_p, singleton_p => :singleton_p, implements_subsite_p => :implements_subsite_p, inherit_templates_p => :inherit_templates_p, spec_file_path => :spec_file_path, spec_file_mtime => :spec_file_mtime ); end; begin :1 := apm_package_version.edit( version_id => :version_id, version_name => :version_name, version_uri => :version_uri, summary => :summary, description_format => :description_format, description => :description, release_date => :release_date, vendor => :vendor, vendor_uri => :vendor_uri, auto_mount => :auto_mount, installed_p => 't', data_model_loaded_p => 't' ); end; begin apm_package_version.upgrade(version_id => :version_id); end; begin :1 := apm_package_version.upgrade_p( path => :path, initial_version_name => :initial_version_name, final_version_name => :final_version_name ); end; begin :1 := apm_package_version.sortable_version_name('$f1_version_from'); end; begin :1 := apm_package_version.sortable_version_name('$f2_version_from'); end; select apm_package_version.version_name_greater(service_version, :dependency_version) as version_p from apm_package_dependencies d, apm_package_types a, apm_package_versions v where d.dependency_type = 'provides' and d.version_id = v.version_id and d.service_uri = :dependency_uri and v.installed_p = 't' and a.package_key = v.package_key select apm_package_version.version_name_greater(:provided_version, :dependency_version) from dual select version_id from apm_package_versions where package_key = :package_key and version_id = apm_package.highest_version(:package_key) begin :1 := apm.parameter_p( package_key => :descendent_package_key, parameter_name => :parameter_name); end; begin :1 := apm.register_parameter( package_key => :descendent_package_key, parameter_name => :parameter_name, description => :description, scope => :scope, datatype => :datatype, default_value => :default_value, section_name => :section_name, min_n_values => :min_n_values, max_n_values => :max_n_values); end; begin :1 := apm.parameter_p( package_key => :new_package_key, parameter_name => :parameter_name); end; begin :1 := apm.register_parameter( package_key => :new_package_key, parameter_name => :parameter_name, description => :description, scope => :scope, datatype => :datatype, default_value => :default_value, section_name => :section_name, min_n_values => :min_n_values, max_n_values => :max_n_values); end; select apm_package_version.version_name_greater(:version_name, version_name) upgrade_p from apm_package_versions where package_key = :package_key and version_id = apm_package.highest_version (:package_key) select version_name from apm_package_versions where package_key = :package_key and version_id = apm_package.highest_version(:package_key) select apm_package_version.sortable_version_name(:version_name_1) as sortable_version_1, apm_package_version.sortable_version_name(:version_name_2) as sortable_version_2 from dual select apm_package_version.sortable_version_name(:version) from dual openacs-5.7.0/packages/acs-tcl/tcl/xml-0-sgml-procs.tcl0000644000175000017500000013774510551254404022427 0ustar frankiefrankiead_library { @original-header # sgml.tcl -- # # This file provides generic parsing services for SGML-based # languages, namely HTML and XML. # # NB. It is a misnomer. There is no support for parsing # arbitrary SGML as such. # # Copyright (c) 1998,1999 Zveno Pty Ltd # http://www.zveno.com/ # # Zveno makes this software available free of charge for any purpose. # Copies may be made of this software but all of this notice must be included # on any copy. # # The software was developed for research purposes only and Zveno does not # warrant that it is error free or fit for any purpose. Zveno disclaims any # liability for all claims, expenses, losses, damages and costs any user may # incur as a result of using, copying or modifying this software. # # Copyright (c) 1997 ANU and CSIRO on behalf of the # participants in the CRC for Advanced Computational Systems ('ACSys'). # # ACSys makes this software and all associated data and documentation # ('Software') available free of charge for any purpose. You may make copies # of the Software but you must include all of this notice on any copy. # # The Software was developed for research purposes and ACSys does not warrant # that it is error free or fit for any purpose. ACSys disclaims any # liability for all claims, expenses, losses, damages and costs any user may # incur as a result of using, copying or modifying the Software. # @cvs-id $Id: xml-0-sgml-procs.tcl,v 1.3 2007/01/10 21:22:12 gustafn Exp $ } package provide sgml 1.7 namespace eval sgml { namespace export tokenise parseEvent namespace export parseDTD # Convenience routine proc cl x { return "\[$x\]" } # Define various regular expressions # Character classes variable BaseChar \u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3 variable Ideographic \u4E00-\u9FA5\u3007\u3021-\u3029 variable CombiningChar \u0300-\u0345\u0360-\u0361\u0483-\u0486\u0591-\u05A1\u05A3-\u05B9\u05BB-\u05BD\u05BF\u05C1-\u05C2\u05C4\u064B-\u0652\u0670\u06D6-\u06DC\u06DD-\u06DF\u06E0-\u06E4\u06E7-\u06E8\u06EA-\u06ED\u0901-\u0903\u093C\u093E-\u094C\u094D\u0951-\u0954\u0962-\u0963\u0981-\u0983\u09BC\u09BE\u09BF\u09C0-\u09C4\u09C7-\u09C8\u09CB-\u09CD\u09D7\u09E2-\u09E3\u0A02\u0A3C\u0A3E\u0A3F\u0A40-\u0A42\u0A47-\u0A48\u0A4B-\u0A4D\u0A70-\u0A71\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0B01-\u0B03\u0B3C\u0B3E-\u0B43\u0B47-\u0B48\u0B4B-\u0B4D\u0B56-\u0B57\u0B82-\u0B83\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55-\u0C56\u0C82-\u0C83\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5-\u0CD6\u0D02-\u0D03\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EC8-\u0ECD\u0F18-\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86-\u0F8B\u0F90-\u0F95\u0F97\u0F99-\u0FAD\u0FB1-\u0FB7\u0FB9\u20D0-\u20DC\u20E1\u302A-\u302F\u3099\u309A variable Digit \u0030-\u0039\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE7-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29 variable Extender \u00B7\u02D0\u02D1\u0387\u0640\u0E46\u0EC6\u3005\u3031-\u3035\u309D-\u309E\u30FC-\u30FE variable Letter $BaseChar|$Ideographic # white space variable Wsp " \t\r\n" variable noWsp [cl ^$Wsp] # variable Char \x9|\xA|\xD|\[\x20-\uD7FF\]|\[\uE000-\uFFFD\]|\[\u10000-\u10FFFF\] # Various XML names variable NameChar \[-$Letter$Digit._:$CombiningChar$Extender\] variable Name \[_:$BaseChar$Ideographic\]$NameChar* variable Names ${Name}(?:$Wsp$Name)* variable Nmtoken $NameChar+ variable Nmtokens ${Nmtoken}(?:$Wsp$Nmtoken)* # Other variable ParseEventNum if {![info exists ParseEventNum]} { set ParseEventNum 0 } variable ParseDTDnum if {![info exists ParseDTDNum]} { set ParseDTDNum 0 } # table of predefined entities for XML variable EntityPredef array set EntityPredef { lt < gt > amp & quot \" apos ' } } # sgml::tokenise -- # # Transform the given HTML/XML text into a Tcl list. # # Arguments: # sgml text to tokenize # elemExpr RE to recognise tags # elemSub transform for matched tags # args options # # Valid Options: # -final boolean True if no more data is to be supplied # -statevariable varName Name of a variable used to store info # # Results: # Returns a Tcl list representing the document. proc sgml::tokenise {sgml elemExpr elemSub args} { array set options {-final 1} catch {array set options $args} set options(-final) [Boolean $options(-final)] # If the data is not final then there must be a variable to store # unused data. if {!$options(-final) && ![info exists options(-statevariable)]} { return -code error {option "-statevariable" required if not final} } # Pre-process stage # # Extract the internal DTD subset, if any catch {upvar #0 $options(-internaldtdvariable) dtd} if {[regexp {]*$)} [lindex $sgml end] x text unused]} { set sgml [lreplace $sgml end end $text] } } else { # Performance note (Tcl 8.0): # In this case, no conversion to list object is performed regsub -all $elemExpr $sgml $elemSub sgml set sgml "{} {} {} \{$sgml\}" } return $sgml } # sgml::parseEvent -- # # Produces an event stream for a XML/HTML document, # given the Tcl list format returned by tokenise. # # This procedure checks that the document is well-formed, # and throws an error if the document is found to be not # well formed. Warnings are passed via the -warningcommand script. # # The procedure only check for well-formedness, # no DTD is required. However, facilities are provided for entity expansion. # # Arguments: # sgml Instance data, as a Tcl list. # args option/value pairs # # Valid Options: # -final Indicates end of document data # -elementstartcommand Called when an element starts # -elementendcommand Called when an element ends # -characterdatacommand Called when character data occurs # -entityreferencecommand Called when an entity reference occurs # -processinginstructioncommand Called when a PI occurs # -externalentityrefcommand Called for an external entity reference # # (Not compatible with expat) # -xmldeclcommand Called when the XML declaration occurs # -doctypecommand Called when the document type declaration occurs # -commentcommand Called when a comment occurs # # -errorcommand Script to evaluate for a fatal error # -warningcommand Script to evaluate for a reportable warning # -statevariable global state variable # -normalize whether to normalize names # -reportempty whether to include an indication of empty elements # # Results: # The various callback scripts are invoked. # Returns empty string. # # BUGS: # If command options are set to empty string then they should not be invoked. proc sgml::parseEvent {sgml args} { variable Wsp variable noWsp variable Nmtoken variable Name variable ParseEventNum array set options [list \ -elementstartcommand [namespace current]::noop \ -elementendcommand [namespace current]::noop \ -characterdatacommand [namespace current]::noop \ -processinginstructioncommand [namespace current]::noop \ -externalentityrefcommand [namespace current]::noop \ -xmldeclcommand [namespace current]::noop \ -doctypecommand [namespace current]::noop \ -commentcommand [namespace current]::noop \ -entityreferencecommand {} \ -warningcommand [namespace current]::noop \ -errorcommand [namespace current]::Error \ -final 1 \ -emptyelement [namespace current]::EmptyElement \ -parseattributelistcommand [namespace current]::noop \ -normalize 1 \ -internaldtd {} \ -reportempty 0 \ -entityvariable [namespace current]::EntityPredef \ ] catch {array set options $args} if {![info exists options(-statevariable)]} { set options(-statevariable) [namespace current]::ParseEvent[incr ParseEventNum] } upvar #0 $options(-statevariable) state upvar #0 $options(-entityvariable) entities if {![info exists state]} { # Initialise the state variable array set state { mode normal haveXMLDecl 0 haveDocElement 0 context {} stack {} line 0 } } foreach {tag close param text} $sgml { # Keep track of lines in the input incr state(line) [regsub -all \n $param {} discard] incr state(line) [regsub -all \n $text {} discard] # If the current mode is cdata or comment then we must undo what the # regsub has done to reconstitute the data set empty {} switch $state(mode) { comment { # This had "[string length $param] && " as a guard - # can't remember why :-( if {[regexp ([cl ^-]*)--\$ $tag discard comm1]} { # end of comment (in tag) set tag {} set close {} set state(mode) normal uplevel #0 $options(-commentcommand) [list $state(commentdata)<$comm1] unset state(commentdata) } elseif {[regexp ([cl ^-]*)--\$ $param discard comm1]} { # end of comment (in attributes) uplevel #0 $options(-commentcommand) [list $state(commentdata)<$close$tag>$comm1] unset state(commentdata) set tag {} set param {} set close {} set state(mode) normal } elseif {[regexp ([cl ^-]*)-->(.*) $text discard comm1 text]} { # end of comment (in text) uplevel #0 $options(-commentcommand) [list $state(commentdata)<$close$tag$param>$comm1] unset state(commentdata) set tag {} set param {} set close {} set state(mode) normal } else { # comment continues append state(commentdata) <$close$tag$param>$text continue } } cdata { if {[string length $param] && [regexp ([cl ^\]]*)\]\][cl $Wsp]*\$ $tag discard cdata1]} { # end of CDATA (in tag) uplevel #0 $options(-characterdatacommand) [list $state(cdata)<$close$cdata1$text] set text {} set tag {} unset state(cdata) set state(mode) normal } elseif {[regexp ([cl ^\]]*)\]\][cl $Wsp]*\$ $param discard cdata1]} { # end of CDATA (in attributes) uplevel #0 $options(-characterdatacommand) [list $state(cdata)<$close$tag$cdata1$text] set text {} set tag {} set param {} unset state(cdata) set state(mode) normal } elseif {[regexp ([cl ^\]]*)\]\][cl $Wsp]*>(.*) $text discard cdata1 text]} { # end of CDATA (in text) uplevel #0 $options(-characterdatacommand) [list $state(cdata)<$close$tag$param>$cdata1$text] set text {} set tag {} set param {} set close {} unset state(cdata) set state(mode) normal } else { # CDATA continues append state(cdata) <$close$tag$param>$text continue } } default { # The trailing slash on empty elements can't be automatically separated out # in the RE, so we must do it here. regexp (.*)(/)[cl $Wsp]*$ $param discard param empty } } # default: normal mode # Bug: if the attribute list has a right angle bracket then the empty # element marker will not be seen set empty [uplevel #0 $options(-emptyelement) [list $tag $param $empty]] switch -glob -- [string length $tag],[regexp {^\?|!.*} $tag],$close,$empty { 0,0,, { # Ignore empty tag - dealt with non-normal mode above } *,0,, { # Start tag for an element. # Check if the internal DTD entity is in an attribute value regsub -all &xml:intdtd\; $param \[$options(-internaldtd)\] param ParseEvent:ElementOpen $tag $param options set state(haveDocElement) 1 } *,0,/, { # End tag for an element. ParseEvent:ElementClose $tag options } *,0,,/ { # Empty element ParseEvent:ElementOpen $tag $param options -empty 1 ParseEvent:ElementClose $tag options -empty 1 } *,1,* { # Processing instructions or XML declaration switch -glob -- $tag { {\?xml} { # XML Declaration if {$state(haveXMLDecl)} { uplevel #0 $options(-errorcommand) "unexpected characters \"<$tag\" around line $state(line)" } elseif {![regexp {\?$} $param]} { uplevel #0 $options(-errorcommand) "XML Declaration missing characters \"?>\" around line $state(line)" } else { # Get the version number if {[regexp {[ ]*version="(-+|[a-zA-Z0-9_.:]+)"[ ]*} $param discard version] || [regexp {[ ]*version='(-+|[a-zA-Z0-9_.:]+)'[ ]*} $param discard version]} { if {$version ne "1.0" } { # Should we support future versions? # At least 1.X? uplevel #0 $options(-errorcommand) "document XML version \"$version\" is incompatible with XML version 1.0" } } else { uplevel #0 $options(-errorcommand) "XML Declaration missing version information around line $state(line)" } # Get the encoding declaration set encoding {} regexp {[ ]*encoding="([A-Za-z]([A-Za-z0-9._]|-)*)"[ ]*} $param discard encoding regexp {[ ]*encoding='([A-Za-z]([A-Za-z0-9._]|-)*)'[ ]*} $param discard encoding # Get the standalone declaration set standalone {} regexp {[ ]*standalone="(yes|no)"[ ]*} $param discard standalone regexp {[ ]*standalone='(yes|no)'[ ]*} $param discard standalone # Invoke the callback uplevel #0 $options(-xmldeclcommand) [list $version $encoding $standalone] } } {\?*} { # Processing instruction if {![regsub {\?$} $param {} param]} { uplevel #0 $options(-errorcommand) "PI: expected '?' character around line $state(line)" } else { uplevel #0 $options(-processinginstructioncommand) [list [string range $tag 1 end] [string trimleft $param]] } } !DOCTYPE { # External entity reference # This should move into xml.tcl # Parse the params supplied. Looking for Name, ExternalID and MarkupDecl set matched [regexp ^[cl $Wsp]*($Name)[cl $Wsp]*(.*) $param x state(doc_name) param] set state(doc_name) [Normalize $state(doc_name) $options(-normalize)] set externalID {} set pubidlit {} set systemlit {} set externalID {} if {[regexp -nocase ^[cl $Wsp]*(SYSTEM|PUBLIC)(.*) $param x id param]} { switch [string toupper $id] { SYSTEM { if {[regexp ^[cl $Wsp]+"([cl ^"]*)"(.*) $param x systemlit param] || [regexp ^[cl $Wsp]+'([cl ^']*)'(.*) $param x systemlit param]} { set externalID [list SYSTEM $systemlit] ;# " } else { uplevel #0 $options(-errorcommand) {{syntax error: SYSTEM identifier not followed by literal}} } } PUBLIC { if {[regexp ^[cl $Wsp]+"([cl ^"]*)"(.*) $param x pubidlit param] || [regexp ^[cl $Wsp]+'([cl ^']*)'(.*) $param x pubidlit param]} { if {[regexp ^[cl $Wsp]+"([cl ^"]*)"(.*) $param x systemlit param] || [regexp ^[cl $Wsp]+'([cl ^']*)'(.*) $param x systemlit param]} { set externalID [list PUBLIC $pubidlit $systemlit] } else { uplevel #0 $options(-errorcommand) "syntax error: PUBLIC identifier not followed by system literal around line $state(line)" } } else { uplevel #0 $options(-errorcommand) "syntax error: PUBLIC identifier not followed by literal around line $state(line)" } } } if {[regexp -nocase ^[cl $Wsp]+NDATA[cl $Wsp]+($Name)(.*) $param x notation param]} { lappend externalID $notation } } uplevel #0 $options(-doctypecommand) [list $state(doc_name) $pubidlit $systemlit $options(-internaldtd)] } !--* { # Start of a comment # See if it ends in the same tag, otherwise change the # parsing mode regexp {!--(.*)} $tag discard comm1 if {[regexp ([cl ^-]*)--[cl $Wsp]*\$ $comm1 discard comm1_1]} { # processed comment (end in tag) uplevel #0 $options(-commentcommand) [list $comm1_1] } elseif {[regexp ([cl ^-]*)--[cl $Wsp]*\$ $param discard comm2]} { # processed comment (end in attributes) uplevel #0 $options(-commentcommand) [list $comm1$comm2] } elseif {[regexp ([cl ^-]*)-->(.*) $text discard comm2 text]} { # processed comment (end in text) uplevel #0 $options(-commentcommand) [list $comm1$param$empty>$comm2] } else { # start of comment set state(mode) comment set state(commentdata) "$comm1$param$empty>$text" continue } } {!\[CDATA\[*} { regexp {!\[CDATA\[(.*)} $tag discard cdata1 if {[regexp {(.*)]]$} $param discard cdata2]} { # processed CDATA (end in attribute) uplevel #0 $options(-characterdatacommand) [list $cdata1$cdata2$text] set text {} } elseif {[regexp {(.*)]]>(.*)} $text discard cdata2 text]} { # processed CDATA (end in text) uplevel #0 $options(-characterdatacommand) [list $cdata1$param$empty>$cdata2$text] set text {} } else { # start CDATA set state(cdata) "$cdata1$param>$text" set state(mode) cdata continue } } !ELEMENT { # Internal DTD declaration } !ATTLIST { } !ENTITY { } !NOTATION { } !* { uplevel #0 $options(-processinginstructioncommand) [list $tag $param] } default { uplevel #0 $options(-errorcommand) [list "unknown processing instruction \"<$tag>\" around line $state(line)"] } } } *,1,* - *,0,/,/ { # Syntax error uplevel #0 $options(-errorcommand) [list [list syntax error: closed/empty tag: tag $tag param $param empty $empty close $close around line $state(line)]] } } # Process character data if {$state(haveDocElement) && [llength $state(stack)]} { # Check if the internal DTD entity is in the text regsub -all &xml:intdtd\; $text \[$options(-internaldtd)\] text # Look for entity references if {([array size entities] || [string length $options(-entityreferencecommand)]) && \ [regexp {&[^;]+;} $text]} { # protect Tcl specials regsub -all {([][$\\])} $text {\\\1} text # Mark entity references regsub -all {&([^;]+);} $text [format {%s; %s {\1} ; %s %s} \}\} [namespace code [list Entity options $options(-entityreferencecommand) $options(-characterdatacommand) $options(-entityvariable)]] [list uplevel #0 $options(-characterdatacommand)] \{\{] text set text "uplevel #0 $options(-characterdatacommand) {{$text}}" eval $text } else { # Restore protected special characters regsub -all {\\([{}\\])} $text {\1} text uplevel #0 $options(-characterdatacommand) [list $text] } } elseif {[string length [string trim $text]]} { uplevel #0 $options(-errorcommand) "unexpected text \"$text\" in document prolog around line $state(line)" } } # If this is the end of the document, close all open containers if {$options(-final) && [llength $state(stack)]} { eval $options(-errorcommand) [list [list element [lindex $state(stack) end] remains unclosed around line $state(line)]] } return {} } # sgml::ParseEvent:ElementOpen -- # # Start of an element. # # Arguments: # tag Element name # attr Attribute list # opts Option variable in caller # args further configuration options # # Options: # -empty boolean # indicates whether the element was an empty element # # Results: # Modify state and invoke callback proc sgml::ParseEvent:ElementOpen {tag attr opts args} { variable Name variable Wsp upvar $opts options upvar #0 $options(-statevariable) state array set cfg {-empty 0} array set cfg $args if {$options(-normalize)} { set tag [string toupper $tag] } # Update state lappend state(stack) $tag # Parse attribute list into a key-value representation if {[string compare $options(-parseattributelistcommand) {}]} { if {[catch {uplevel #0 $options(-parseattributelistcommand) [list $attr]} attr]} { if {[lindex $attr 0] ne "unterminated attribute value" } { uplevel #0 $options(-errorcommand) [list $attr around line $state(line)] set attr {} } else { # It is most likely that a ">" character was in an attribute value. # This manifests itself by ">" appearing in the element's text. # In this case the callback should return a three element list; # the message "unterminated attribute value", the attribute list it # did manage to parse and the remainder of the attribute list. foreach {msg attlist brokenattr} $attr break upvar text elemText if {[string first > $elemText] >= 0} { # Now piece the attribute list back together regexp ($Name)[cl $Wsp]*=[cl $Wsp]*("|')(.*) $brokenattr discard attname delimiter attvalue regexp (.*)>([cl ^>]*)\$ $elemText discard remattlist elemText regexp ([cl ^$delimiter]*)${delimiter}(.*) $remattlist discard remattvalue remattlist append attvalue >$remattvalue lappend attlist $attname $attvalue # Complete parsing the attribute list if {[catch {uplevel #0 $options(-parseattributelistcommand) [list $remattlist]} attr]} { uplevel #0 $options(-errorcommand) [list $attr around line $state(line)] set attr {} set attlist {} } else { eval lappend attlist $attr } set attr $attlist } else { uplevel #0 $options(-errorcommand) [list $attr around line $state(line)] set attr {} } } } } set empty {} if {$cfg(-empty) && $options(-reportempty)} { set empty {-empty 1} } # Invoke callback uplevel #0 $options(-elementstartcommand) [list $tag $attr] $empty return {} } # sgml::ParseEvent:ElementClose -- # # End of an element. # # Arguments: # tag Element name # opts Option variable in caller # args further configuration options # # Options: # -empty boolean # indicates whether the element as an empty element # # Results: # Modify state and invoke callback proc sgml::ParseEvent:ElementClose {tag opts args} { upvar $opts options upvar #0 $options(-statevariable) state array set cfg {-empty 0} array set cfg $args # WF check if {$tag ne [lindex $state(stack) end] } { uplevel #0 $options(-errorcommand) [list "end tag \"$tag\" does not match open element \"[lindex $state(stack) end]\" around line $state(line)"] return } # Update state set state(stack) [lreplace $state(stack) end end] set empty {} if {$cfg(-empty) && $options(-reportempty)} { set empty {-empty 1} } # Invoke callback uplevel #0 $options(-elementendcommand) [list $tag] $empty return {} } # sgml::Normalize -- # # Perform name normalization if required # # Arguments: # name name to normalize # req normalization required # # Results: # Name returned as upper-case if normalization required proc sgml::Normalize {name req} { if {$req} { return [string toupper $name] } else { return $name } } # sgml::Entity -- # # Resolve XML entity references (syntax: &xxx;). # # Arguments: # opts options array variable in caller # entityrefcmd application callback for entity references # pcdatacmd application callback for character data # entities name of array containing entity definitions. # ref entity reference (the "xxx" bit) # # Results: # Returns substitution text for given entity. proc sgml::Entity {opts entityrefcmd pcdatacmd entities ref} { upvar 2 $opts options upvar #0 $options(-statevariable) state if {![string length $entities]} { set entities [namespace current]::EntityPredef } switch -glob -- $ref { %* { # Parameter entity - not recognised outside of a DTD } #x* { # Character entity - hex if {[catch {format %c [scan [string range $ref 2 end] %x tmp; set tmp]} char]} { return -code error "malformed character entity \"$ref\"" } uplevel #0 $pcdatacmd [list $char] return {} } #* { # Character entity - decimal if {[catch {format %c [scan [string range $ref 1 end] %d tmp; set tmp]} char]} { return -code error "malformed character entity \"$ref\"" } uplevel #0 $pcdatacmd [list $char] return {} } default { # General entity upvar #0 $entities map if {[info exists map($ref)]} { if {![regexp {<|&} $map($ref)]} { # Simple text replacement - optimise uplevel #0 $pcdatacmd [list $map($ref)] return {} } # Otherwise an additional round of parsing is required. # This only applies to XML, since HTML doesn't have general entities # Must parse the replacement text for start & end tags, etc # This text must be self-contained: balanced closing tags, and so on set tokenised [tokenise $map($ref) $::xml::tokExpr $::xml::substExpr] set final $options(-final) unset options(-final) eval parseEvent [list $tokenised] [array get options] -final 0 set options(-final) $final return {} } elseif {[string length $entityrefcmd]} { uplevel #0 $entityrefcmd [list $ref] return {} } } } # If all else fails leave the entity reference untouched uplevel #0 $pcdatacmd [list &$ref\;] return {} } #################################### # # DTD parser for SGML (XML). # # This DTD actually only handles XML DTDs. Other language's # DTD's, such as HTML, must be written in terms of a XML DTD. # # A DTD is represented as a three element Tcl list. # The first element contains the content models for elements, # the second contains the attribute lists for elements and # the last element contains the entities for the document. # #################################### # sgml::parseDTD -- # # Entry point to the SGML DTD parser. # # Arguments: # dtd data defining the DTD to be parsed # args configuration options # # Results: # Returns a three element list, first element is the content model # for each element, second element are the attribute lists of the # elements and the third element is the entity map. proc sgml::parseDTD {dtd args} { variable Wsp variable ParseDTDnum array set opts [list \ -errorcommand [namespace current]::noop \ state [namespace current]::parseDTD[incr ParseDTDnum] ] array set opts $args set exp ]+)[cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*([cl ^>]*)> set sub {{\1} {\2} {\3} } regsub -all $exp $dtd $sub dtd foreach {decl id value} $dtd { catch {DTD:[string toupper $decl] $id $value} err } return [list [array get contentmodel] [array get attributes] [array get entities]] } # Procedures for handling the various declarative elements in a DTD. # New elements may be added by creating a procedure of the form # parse:DTD:_element_ # For each of these procedures, the various regular expressions they use # are created outside of the proc to avoid overhead at runtime # sgml::DTD:ELEMENT -- # # defines an element. # # The content model for the element is stored in the contentmodel array, # indexed by the element name. The content model is parsed into the # following list form: # # {} Content model is EMPTY. # Indicated by an empty list. # * Content model is ANY. # Indicated by an asterix. # {ELEMENT ...} # Content model is element-only. # {MIXED {element1 element2 ...}} # Content model is mixed (PCDATA and elements). # The second element of the list contains the # elements that may occur. #PCDATA is assumed # (ie. the list is normalised). # # Arguments: # id identifier for the element. # value other information in the PI proc sgml::DTD:ELEMENT {id value} { dbgputs DTD_parse [list DTD:ELEMENT $id $value] variable Wsp upvar opts state upvar contentmodel cm if {[info exists cm($id)]} { eval $state(-errorcommand) element [list "element \"$id\" already declared"] } else { switch -- $value { EMPTY { set cm($id) {} } ANY { set cm($id) * } default { if {[regexp [format {^\([%s]*#PCDATA[%s]*(\|([^)]+))?[%s]*\)*[%s]*$} $Wsp $Wsp $Wsp $Wsp] discard discard mtoks]} { set cm($id) [list MIXED [split $mtoks |]] } else { if {[catch {CModelParse $state(state) $value} result]} { eval $state(-errorcommand) element [list $result] } else { set cm($id) [list ELEMENT $result] } } } } } } # sgml::CModelParse -- # # Parse an element content model (non-mixed). # A syntax tree is constructed. # A transition table is built next. # # This is going to need alot of work! # # Arguments: # state state array variable # value the content model data # # Results: # A Tcl list representing the content model. proc sgml::CModelParse {state value} { upvar #0 $state var # First build syntax tree set syntaxTree [CModelMakeSyntaxTree $state $value] # Build transition table set transitionTable [CModelMakeTransitionTable $state $syntaxTree] return [list $syntaxTree $transitionTable] } # sgml::CModelMakeSyntaxTree -- # # Construct a syntax tree for the regular expression. # # Syntax tree is represented as a Tcl list: # rep {:choice|:seq {{rep list1} {rep list2} ...}} # where: rep is repetition character, *, + or ?. {} for no repetition # listN is nested expression or Name # # Arguments: # spec Element specification # # Results: # Syntax tree for element spec as nested Tcl list. # # Examples: # (memo) # {} {:seq {{} memo}} # (front, body, back?) # {} {:seq {{} front} {{} body} {? back}} # (head, (p | list | note)*, div2*) # {} {:seq {{} head} {* {:choice {{} p} {{} list} {{} note}}} {* div2}} # (p | a | ul)+ # + {:choice {{} p} {{} a} {{} ul}} proc sgml::CModelMakeSyntaxTree {state spec} { upvar #0 $state var variable Wsp variable name # Translate the spec into a Tcl list. # None of the Tcl special characters are allowed in a content model spec. if {[regexp {\$|\[|\]|\{|\}} $spec]} { return -code error "illegal characters in specification" } regsub -all [format {(%s)[%s]*(\?|\*|\+)?[%s]*(,|\|)?} $name $Wsp $Wsp] $spec [format {%sCModelSTname %s {\1} {\2} {\3}} \n $state] spec regsub -all {\(} $spec "\nCModelSTopenParen $state " spec regsub -all [format {\)[%s]*(\?|\*|\+)?[%s]*(,|\|)?} $Wsp $Wsp] $spec [format {%sCModelSTcloseParen %s {\1} {\2}} \n $state] spec array set var {stack {} state start} eval $spec # Peel off the outer seq, its redundant return [lindex [lindex $var(stack) 1] 0] } # sgml::CModelSTname -- # # Processes a name in a content model spec. # # Arguments: # state state array variable # name name specified # rep repetition operator # cs choice or sequence delimiter # # Results: # See CModelSTcp. proc sgml::CModelSTname {state name rep cs args} { if {[llength $args]} { return -code error "syntax error in specification: \"$args\"" } CModelSTcp $state $name $rep $cs } # sgml::CModelSTcp -- # # Process a content particle. # # Arguments: # state state array variable # name name specified # rep repetition operator # cs choice or sequence delimiter # # Results: # The content particle is added to the current group. proc sgml::CModelSTcp {state cp rep cs} { upvar #0 $state var switch -glob -- [lindex $var(state) end]=$cs { start= { set var(state) [lreplace $var(state) end end end] # Add (dummy) grouping, either choice or sequence will do CModelSTcsSet $state , CModelSTcpAdd $state $cp $rep } :choice= - :seq= { set var(state) [lreplace $var(state) end end end] CModelSTcpAdd $state $cp $rep } start=| - start=, { set var(state) [lreplace $var(state) end end [expr {$cs eq "," ? ":seq" : ":choice"}]] CModelSTcsSet $state $cs CModelSTcpAdd $state $cp $rep } :choice=| - :seq=, { CModelSTcpAdd $state $cp $rep } :choice=, - :seq=| { return -code error "syntax error in specification: incorrect delimiter after \"$cp\", should be \"[expr {$cs eq "," ? "|" : ","}]\"" } end=* { return -code error "syntax error in specification: no delimiter before \"$cp\"" } default { return -code error "syntax error" } } } # sgml::CModelSTcsSet -- # # Start a choice or sequence on the stack. # # Arguments: # state state array # cs choice oir sequence # # Results: # state is modified: end element of state is appended. proc sgml::CModelSTcsSet {state cs} { upvar #0 $state var set cs [expr {$cs eq "," ? ":seq" : ":choice"}] if {[llength $var(stack)]} { set var(stack) [lreplace $var(stack) end end $cs] } else { set var(stack) [list $cs {}] } } # sgml::CModelSTcpAdd -- # # Append a content particle to the top of the stack. # # Arguments: # state state array # cp content particle # rep repetition # # Results: # state is modified: end element of state is appended. proc sgml::CModelSTcpAdd {state cp rep} { upvar #0 $state var if {[llength $var(stack)]} { set top [lindex $var(stack) end] lappend top [list $rep $cp] set var(stack) [lreplace $var(stack) end end $top] } else { set var(stack) [list $rep $cp] } } # sgml::CModelSTopenParen -- # # Processes a '(' in a content model spec. # # Arguments: # state state array # # Results: # Pushes stack in state array. proc sgml::CModelSTopenParen {state args} { upvar #0 $state var if {[llength $args]} { return -code error "syntax error in specification: \"$args\"" } lappend var(state) start lappend var(stack) [list {} {}] } # sgml::CModelSTcloseParen -- # # Processes a ')' in a content model spec. # # Arguments: # state state array # rep repetition # cs choice or sequence delimiter # # Results: # Stack is popped, and former top of stack is appended to previous element. proc sgml::CModelSTcloseParen {state rep cs args} { upvar #0 $state var if {[llength $args]} { return -code error "syntax error in specification: \"$args\"" } set cp [lindex $var(stack) end] set var(stack) [lreplace $var(stack) end end] set var(state) [lreplace $var(state) end end] CModelSTcp $state $cp $rep $cs } # sgml::CModelMakeTransitionTable -- # # Given a content model's syntax tree, constructs # the transition table for the regular expression. # # See "Compilers, Principles, Techniques, and Tools", # Aho, Sethi and Ullman. Section 3.9, algorithm 3.5. # # Arguments: # state state array variable # st syntax tree # # Results: # The transition table is returned, as a key/value Tcl list. proc sgml::CModelMakeTransitionTable {state st} { upvar #0 $state var # Construct nullable, firstpos and lastpos functions array set var {number 0} foreach {nullable firstpos lastpos} [ \ TraverseDepth1st $state $st { # Evaluated for leaf nodes # Compute nullable(n) # Compute firstpos(n) # Compute lastpos(n) set nullable [nullable leaf $rep $name] set firstpos [list {} $var(number)] set lastpos [list {} $var(number)] set var(pos:$var(number)) $name } { # Evaluated for nonterminal nodes # Compute nullable, firstpos, lastpos set firstpos [firstpos $cs $firstpos $nullable] set lastpos [lastpos $cs $lastpos $nullable] set nullable [nullable nonterm $rep $cs $nullable] } \ ] break set accepting [incr var(number)] set var(pos:$accepting) # # var(pos:N) maps from position to symbol. # Construct reverse map for convenience. # NB. A symbol may appear in more than one position. # var is about to be reset, so use different arrays. foreach {pos symbol} [array get var pos:*] { set pos [lindex [split $pos :] 1] set pos2symbol($pos) $symbol lappend sym2pos($symbol) $pos } # Construct the followpos functions catch {unset var} followpos $state $st $firstpos $lastpos # Construct transition table # Dstates is [union $marked $unmarked] set unmarked [list [lindex $firstpos 1]] while {[llength $unmarked]} { set T [lindex $unmarked 0] lappend marked $T set unmarked [lrange $unmarked 1 end] # Find which input symbols occur in T set symbols {} foreach pos $T { if {$pos != $accepting && [lsearch $symbols $pos2symbol($pos)] < 0} { lappend symbols $pos2symbol($pos) } } foreach a $symbols { set U {} foreach pos $sym2pos($a) { if {[lsearch $T $pos] >= 0} { # add followpos($pos) if {$var($pos) == {}} { lappend U $accepting } else { eval lappend U $var($pos) } } } set U [makeSet $U] if {[llength $U] && [lsearch $marked $U] < 0 && [lsearch $unmarked $U] < 0} { lappend unmarked $U } set Dtran($T,$a) $U } } return [list [array get Dtran] [array get sym2pos] $accepting] } # sgml::followpos -- # # Compute the followpos function, using the already computed # firstpos and lastpos. # # Arguments: # state array variable to store followpos functions # st syntax tree # firstpos firstpos functions for the syntax tree # lastpos lastpos functions # # Results: # followpos functions for each leaf node, in name/value format proc sgml::followpos {state st firstpos lastpos} { upvar #0 $state var switch -- [lindex [lindex $st 1] 0] { :seq { for {set i 1} {$i < [llength [lindex $st 1]]} {incr i} { followpos $state [lindex [lindex $st 1] $i] \ [lindex [lindex $firstpos 0] [expr {$i - 1}]] \ [lindex [lindex $lastpos 0] [expr {$i - 1}]] foreach pos [lindex [lindex [lindex $lastpos 0] [expr {$i - 1}]] 1] { eval lappend var($pos) [lindex [lindex [lindex $firstpos 0] $i] 1] set var($pos) [makeSet $var($pos)] } } } :choice { for {set i 1} {$i < [llength [lindex $st 1]]} {incr i} { followpos $state [lindex [lindex $st 1] $i] \ [lindex [lindex $firstpos 0] [expr {$i - 1}]] \ [lindex [lindex $lastpos 0] [expr {$i - 1}]] } } default { # No action at leaf nodes } } switch -- [lindex $st 0] { ? { # We having nothing to do here ! Doing the same as # for * effectively converts this qualifier into the other. } * { foreach pos [lindex $lastpos 1] { eval lappend var($pos) [lindex $firstpos 1] set var($pos) [makeSet $var($pos)] } } } } # sgml::TraverseDepth1st -- # # Perform depth-first traversal of a tree. # A new tree is constructed, with each node computed by f. # # Arguments: # state state array variable # t The tree to traverse, a Tcl list # leaf Evaluated at a leaf node # nonTerm Evaluated at a nonterminal node # # Results: # A new tree is returned. proc sgml::TraverseDepth1st {state t leaf nonTerm} { upvar #0 $state var set nullable {} set firstpos {} set lastpos {} switch -- [lindex [lindex $t 1] 0] { :seq - :choice { set rep [lindex $t 0] set cs [lindex [lindex $t 1] 0] foreach child [lrange [lindex $t 1] 1 end] { foreach {childNullable childFirstpos childLastpos} \ [TraverseDepth1st $state $child $leaf $nonTerm] break lappend nullable $childNullable lappend firstpos $childFirstpos lappend lastpos $childLastpos } eval $nonTerm } default { incr var(number) set rep [lindex [lindex $t 0] 0] set name [lindex [lindex $t 1] 0] eval $leaf } } return [list $nullable $firstpos $lastpos] } # sgml::firstpos -- # # Computes the firstpos function for a nonterminal node. # # Arguments: # cs node type, choice or sequence # firstpos firstpos functions for the subtree # nullable nullable functions for the subtree # # Results: # firstpos function for this node is returned. proc sgml::firstpos {cs firstpos nullable} { switch -- $cs { :seq { set result [lindex [lindex $firstpos 0] 1] for {set i 0} {$i < [llength $nullable]} {incr i} { if {[lindex [lindex $nullable $i] 1]} { eval lappend result [lindex [lindex $firstpos [expr {$i + 1}]] 1] } else { break } } } :choice { foreach child $firstpos { eval lappend result $child } } } return [list $firstpos [makeSet $result]] } # sgml::lastpos -- # # Computes the lastpos function for a nonterminal node. # Same as firstpos, only logic is reversed # # Arguments: # cs node type, choice or sequence # lastpos lastpos functions for the subtree # nullable nullable functions forthe subtree # # Results: # lastpos function for this node is returned. proc sgml::lastpos {cs lastpos nullable} { switch -- $cs { :seq { set result [lindex [lindex $lastpos end] 1] for {set i [expr {[llength $nullable] - 1}]} {$i >= 0} {incr i -1} { if {[lindex [lindex $nullable $i] 1]} { eval lappend result [lindex [lindex $lastpos $i] 1] } else { break } } } :choice { foreach child $lastpos { eval lappend result $child } } } return [list $lastpos [makeSet $result]] } # sgml::makeSet -- # # Turn a list into a set, ie. remove duplicates. # # Arguments: # s a list # # Results: # A set is returned, which is a list with duplicates removed. proc sgml::makeSet s { foreach r $s { if {[llength $r]} { set unique($r) {} } } return [array names unique] } # sgml::nullable -- # # Compute the nullable function for a node. # # Arguments: # nodeType leaf or nonterminal # rep repetition applying to this node # name leaf node: symbol for this node, nonterm node: choice or seq node # subtree nonterm node: nullable functions for the subtree # # Results: # Returns nullable function for this branch of the tree. proc sgml::nullable {nodeType rep name {subtree {}}} { switch -glob -- $rep:$nodeType { :leaf - +:leaf { return [list {} 0] } \\*:leaf - \\?:leaf { return [list {} 1] } \\*:nonterm - \\?:nonterm { return [list $subtree 1] } :nonterm - +:nonterm { switch -- $name { :choice { set result 0 foreach child $subtree { set result [expr {$result || [lindex $child 1]}] } } :seq { set result 1 foreach child $subtree { set result [expr {$result && [lindex $child 1]}] } } } return [list $subtree $result] } } } # These regular expressions are defined here once for better performance namespace eval sgml { variable Wsp # Watch out for case-sensitivity set attlist_exp [cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*(#REQUIRED|#IMPLIED) set attlist_enum_exp [cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*\\(([cl ^)]*)\\)[cl $Wsp]*("([cl ^")])")? ;# " set attlist_fixed_exp [cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*(#FIXED)[cl $Wsp]*([cl ^$Wsp]+) set param_entity_exp [cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*([cl ^"$Wsp]*)[cl $Wsp]*"([cl ^"]*)" set notation_exp [cl $Wsp]*([cl ^$Wsp]+)[cl $Wsp]*(.*) } # sgml::DTD:ATTLIST -- # # defines an attribute list. # # Arguments: # id Element an attribute list is being defined for. # value data from the PI. # # Results: # Attribute list variables are modified. proc sgml::DTD:ATTLIST {id value} { variable attlist_exp variable attlist_enum_exp variable attlist_fixed_exp dbgputs DTD_parse [list DTD:ATTLIST $id $value] upvar opts state upvar attributes am if {[info exists am($id)]} { eval $state(-errorcommand) attlist [list "attribute list for element \"$id\" already declared"] } else { # Parse the attribute list. If it were regular, could just use foreach, # but some attributes may have values. regsub -all {([][$\\])} $value {\\\1} value regsub -all $attlist_exp $value {[DTDAttribute {\1} {\2} {\3}]} value regsub -all $attlist_enum_exp $value {[DTDAttribute {\1} {\2} {\3}]} value regsub -all $attlist_fixed_exp $value {[DTDAttribute {\1} {\2} {\3} {\4}]} value subst $value set am($id) [array get attlist] } } # sgml::DTDAttribute -- # # Parse definition of a single attribute. # # Arguments: # name attribute name # type type of this attribute # default default value of the attribute # value other information proc sgml::DTDAttribute {name type default {value {}}} { upvar attlist al # This needs further work set al($name) [list $default $value] } # sgml::DTD:ENTITY -- # # PI # # Arguments: # id identifier for the entity # value data # # Results: # Modifies the caller's entities array variable proc sgml::DTD:ENTITY {id value} { variable param_entity_exp dbgputs DTD_parse [list DTD:ENTITY $id $value] upvar opts state upvar entities ents if {"%" ne $id } { # Entity declaration if {[info exists ents($id)]} { eval $state(-errorcommand) entity [list "entity \"$id\" already declared"] } else { if {![regexp {"([^"]*)"} $value x entvalue] && ![regexp {'([^']*)'} $value x entvalue]} { eval $state(-errorcommand) entityvalue [list "entity value \"$value\" not correctly specified"] } ;# " set ents($id) $entvalue } } else { # Parameter entity declaration switch -glob [regexp $param_entity_exp $value x name scheme data],[string compare {} $scheme] { 0,* { eval $state(-errorcommand) entityvalue [list "parameter entity \"$value\" not correctly specified"] } *,0 { # SYSTEM or PUBLIC declaration } default { set ents($id) $data } } } } # sgml::DTD:NOTATION -- proc sgml::DTD:NOTATION {id value} { variable notation_exp upvar opts state if {[regexp $notation_exp $value x scheme data] == 2} { } else { eval $state(-errorcommand) notationvalue [list "notation value \"$value\" incorrectly specified"] } } ### Utility procedures # sgml::noop -- # # A do-nothing proc # # Arguments: # args arguments # # Results: # Nothing. proc sgml::noop args { return 0 } # sgml::identity -- # # Identity function. # # Arguments: # a arbitrary argument # # Results: # $a proc sgml::identity a { return $a } # sgml::Error -- # # Throw an error # # Arguments: # args arguments # # Results: # Error return condition. proc sgml::Error args { uplevel return -code error [list $args] } ### Following procedures are based on html_library # sgml::zapWhite -- # # Convert multiple white space into a single space. # # Arguments: # data plain text # # Results: # As above proc sgml::zapWhite data { regsub -all "\[ \t\r\n\]+" $data { } data return $data } proc sgml::Boolean value { regsub {1|true|yes|on} $value 1 value regsub {0|false|no|off} $value 0 value return $value } proc sgml::dbgputs {where text} { variable dbg catch {if {$dbg} {puts stdout "DBG: $where ($text)"}} } openacs-5.7.0/packages/acs-tcl/tcl/application-link-procs.tcl0000644000175000017500000000660710551254404023760 0ustar frankiefrankiead_library { Procs of application linking @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-05-23 } namespace eval application_link {} ad_proc -public application_link::new { -this_package_id:required -target_package_id:required } { Create a new link between this_package_id and target_package_id. @param this_package_id ID of the package that you want linked to the target package. @param target_package_id The ID of the target package. } { if {[catch {ad_conn user_id} user_id]} { set user_id 0 } if {[catch {ad_conn peeraddr} id_addr]} { set id_addr 127.0.0.1 } set result [db_exec_plsql create_forward_link {}] db_exec_plsql create_backward_link {} return $result } ad_proc -public application_link::delete_links { -package_id:required } { Delete application links for all packages linking to the given package_id. @param package_id Package ID that you want application links removed from. } { set rel_ids [db_list linked_packages {}] foreach rel_id $rel_ids { relation_remove $rel_id } } ad_proc -public application_link::get { -package_id:required } { Retrieves a list of package_ids for all applications linked to the given package_id. @return List of linked package ids. } { return [db_list linked_packages {}] } ad_proc -public application_link::get_linked { -from_package_id:required -to_package_key:required } { Gets the ID for the application linked to from_package_id and matches the to_package_type. @param from_package_id Object ID of linked-from application. @param to_package_type Object type of linked-to application. @return package_id of linked package. } { return [db_list linked_package {}] } ad_proc -private ::install::xml::action::application-link { node } { Create an application link:

    <application-link from-package-id="from-package-id" to-package-id="to-package-id"/>

    } { set id [apm_attribute_value -default "" $node id] set this_package_url [apm_attribute_value \ -default "" \ $node \ this_package_url] set target_package_url [apm_attribute_value \ -default "" \ $node \ target_package_url] set from_package_id [apm_attribute_value -default "" $node from-package-id] set to_package_id [apm_attribute_value -default "" $node to-package-id] if {$this_package_url ne "" } { set this_package_id [site_node::get_element -url $this_package_url \ -element package_id] } elseif {$from_package_id ne "" } { set this_package_id [install::xml::util::get_id $from_package_id] } else { error "application-link tag must specify either this_package_url or from-package-id" } if {$target_package_url ne "" } { set target_package_id [site_node::get_element -url $target_package_url \ -element package_id] } elseif {$to_package_id ne "" } { set target_package_id [install::xml::util::get_id $to_package_id] } else { error "application-link tag must specify either target_package_url or to-package-id" } set link_id [application_link::new -this_package_id $this_package_id \ -target_package_id $target_package_id] if {![string is space $id]} { set ::install::xml::ids($id) $link_id } } openacs-5.7.0/packages/acs-tcl/tcl/application-link-procs.xql0000644000175000017500000000150610247265704024002 0ustar frankiefrankie select rel_id from acs_rels where rel_type = 'application_link' and (object_id_one = :package_id or object_id_two = :package_id) select object_id_two from acs_rels where object_id_one = :package_id and rel_type = 'application_link' select p.package_id from acs_rels r, apm_packages p where r.object_id_one = :from_package_id and r.object_id_two = p.package_id and p.package_key = :to_package_key and r.rel_type = 'application_link' openacs-5.7.0/packages/acs-tcl/tcl/pools-init.tcl0000644000175000017500000000375011456662501021475 0ustar frankiefrankieif {[ns_info version] eq "4.5"} { set cfgsection "ns/server/[ns_info server]" set minthreads [ns_config $cfgsection minthreads 5] set maxthreads [ns_config $cfgsection maxthreads 10] set maxconns [ns_config $cfgsection maxconnections 100] set timeout [ns_config $cfgsection threadtimeout 120] ns_pools set default -minthreads $minthreads -maxthreads $maxthreads -maxconns $maxconns -timeout $timeout ns_log Notice "Default Pool: [ns_pools get default]" # Setup optional threadpools set poolSection $cfgsection/pools set poolSet [ns_configsection $poolSection] if {"$poolSet" ne ""} { set poolSize [ns_set size $poolSet] for {set i 0} {$i < $poolSize} {incr i} { set poolName [ns_set key $poolSet $i] set poolDescription [ns_set value $poolSet $i] set poolConfigSection "ns/server/[ns_info server]/pool/$poolName" set poolConfigSet [ns_configsection $poolConfigSection] if {"$poolConfigSet" eq ""} { continue } set poolMinthreads [ns_config $poolConfigSection minthreads $minthreads] set poolMaxthreads [ns_config $poolConfigSection maxthreads $maxthreads] set poolMaxconns [ns_config $poolConfigSection maxconnections $maxconns] set poolTimeout [ns_config $poolConfigSection threadtimeout $timeout] ns_pools set $poolName -minthreads $poolMinthreads -maxthreads $poolMaxthreads -maxconns $poolMaxconns -timeout $poolTimeout ns_log Notice "$poolName Pool: [ns_pools get $poolName]" set poolConfigSize [ns_set size $poolConfigSet] for {set j 0} {$j < $poolConfigSize} {incr j} { if {[string tolower [ns_set key $poolConfigSet $j]] eq "map"} & #123; set mapList [split [ns_set value $poolConfigSet $j]] set poolMethod [lindex $mapList 0] set poolPattern [lindex $mapList 1] ns_pools register $poolName [ns_info server] $poolMethod $poolPattern ns_log Notice "ns_pools registered $poolName [ns_info server] $poolMethod $poolPattern" } } } } openacs-5.7.0/packages/acs-tcl/tcl/acs-permissions-procs.tcl0000644000175000017500000002274311334362063023641 0ustar frankiefrankiead_library { Tcl procs for the acs permissioning system. @author rhs@mit.edu @creation-date 2000-08-17 @cvs-id $Id: acs-permissions-procs.tcl,v 1.31 2010/02/09 22:39:47 emmar Exp $ } namespace eval permission {} # define cache_p to be 0 here. Note that it is redefined # to return the value of the PermissionCacheP kernel parameter # on the first call. also the namespace eval is needed to # make the redefinition work for ttrace. ad_proc -private permission::cache_p {} { returns 0 or 1 depending if permission_p caching is enabled or disabled. by default caching is disabled. } { set cache_p [parameter::get -package_id [ad_acs_kernel_id] -parameter PermissionCacheP -default 0] namespace eval ::permission [list proc cache_p {} "return $cache_p"] return $cache_p } ad_proc -public permission::grant { {-party_id:required} {-object_id:required} {-privilege:required} } { grant privilege Y to party X on object Z } { db_exec_plsql grant_permission {} util_memoize_flush "permission::permission_p_not_cached -party_id $party_id -object_id $object_id -privilege $privilege" permission::permission_thread_cache_flush } ad_proc -public permission::revoke { {-party_id:required} {-object_id:required} {-privilege:required} } { revoke privilege Y from party X on object Z } { db_exec_plsql revoke_permission {} util_memoize_flush [list permission::permission_p_not_cached -party_id $party_id -object_id $object_id -privilege $privilege] permission::permission_thread_cache_flush } # args to permission_p and permission_p_no_cache must match ad_proc -public permission::permission_p { {-no_login:boolean} {-no_cache:boolean} {-party_id ""} {-object_id:required} {-privilege:required} } { does party X have privilege Y on object Z @param no_cache force loading from db even if cached (flushes cache as well) @param no_login Don't bump to registration to refresh authentication, if the user's authentication is expired. This is specifically required in the case where you're calling this from the proc that gets the login page. @param party_id if null then it is the current user_id @param object_id The object you want to check permissions on. @param privilege The privilege you want to check for. } { if { $party_id eq "" } { set party_id [ad_conn user_id] } if { $no_cache_p } { permission::permission_thread_cache_flush } if { $no_cache_p || ![permission::cache_p] } { util_memoize_flush [list permission::permission_p_not_cached -party_id $party_id -object_id $object_id -privilege $privilege] set permission_p [permission::permission_p_not_cached -party_id $party_id -object_id $object_id -privilege $privilege] } else { set permission_p [util_memoize \ [list permission::permission_p_not_cached -party_id $party_id -object_id $object_id -privilege $privilege] \ [parameter::get -package_id [ad_acs_kernel_id] -parameter PermissionCacheTimeout -default 300]] } if { !$no_login_p && $party_id == 0 && [ad_conn user_id] == 0 && [ad_conn untrusted_user_id] != 0 && ![template::util::is_true $permission_p] } { set untrusted_permission_p [permission_p_not_cached \ -party_id [ad_conn untrusted_user_id] \ -object_id $object_id \ -privilege $privilege] if { $permission_p != $untrusted_permission_p } { # Bump to registration page ns_log Debug "permission_p: party_id=$party_id ([acs_object_name $party_id]), object_id=$object_id ([acs_object_name $object_id]), privilege=$privilege. Result=>$permission_p. Untrusted-Result=>$untrusted_permission_p\n[ad_get_tcl_call_stack]" if { ![ad_login_page] } { auth::require_login } } } return $permission_p } # accepts nocache to match permission_p arguments # since we alias it to permission::permission_p if # caching disabled. ad_proc -private permission::permission_p_not_cached { {-no_cache:boolean} {-party_id ""} {-object_id:required} {-privilege:required} } { does party X have privilege Y on object Z @see permission::permission_p } { if { $party_id eq "" } { set party_id [ad_conn user_id] } # We have a thread-local cache here global permission__permission_p__cache if { ![info exists permission__permission_p__cache($party_id,$object_id,$privilege)] } { set permission__permission_p__cache($party_id,$object_id,$privilege) [db_0or1row select_permission_p {}] } return $permission__permission_p__cache($party_id,$object_id,$privilege) } ad_proc -private permission::permission_thread_cache_flush {} { Flush thread cache } { global permission__permission_p__cache array unset permission__permission_p__cache } ad_proc -public permission::require_permission { {-party_id ""} {-object_id:required} {-privilege:required} } { require that party X have privilege Y on object Z } { if {$party_id eq ""} { set party_id [ad_conn user_id] } if {![permission_p -party_id $party_id -object_id $object_id -privilege $privilege]} { if {!${party_id}} { auth::require_login } else { ns_log notice "permission::require_permission: $party_id doesn't have $privilege on object $object_id" ad_return_forbidden \ "Permission Denied" \ "You don't have permission to $privilege [db_string name {}]." } ad_script_abort } } ad_proc -public permission::inherit_p { {-object_id:required} } { does this object inherit permissions } { return [db_string select_inherit_p {} -default 0] } ad_proc -public permission::toggle_inherit { {-object_id:required} } { toggle whether or not this object inherits permissions from it's parent } { db_dml toggle_inherit {} permission::permission_thread_cache_flush } ad_proc -public permission::set_inherit { {-object_id:required} } { set inherit to true } { db_dml set_inherit {} permission::permission_thread_cache_flush } ad_proc -public permission::set_not_inherit { {-object_id:required} } { set inherit to false } { db_dml set_not_inherit {} permission::permission_thread_cache_flush } ad_proc -public permission::write_permission_p { {-object_id:required} {-party_id ""} {-creation_user ""} } { Returns whether a user is allowed to edit an object. The logic is that you must have either write permission, or you must be the one who created the object. @param object_id The object you want to check write permissions for @param party_id The party to have or not have write permission. @param creation_user Optionally specify creation_user directly as an optimization. Otherwise a query will be executed. @return True (1) if user has permission to edit the object, 0 otherwise. @see permission::require_write_permission } { if { [permission::permission_p -privilege write -object_id $object_id -party_id $party_id] } { return 1 } if { $creation_user eq "" } { set creation_user [acs_object::get_element -object_id $object_id -element creation_user] } if { [ad_conn user_id] == $creation_user } { return 1 } return 0 } ad_proc -public permission::require_write_permission { {-object_id:required} {-creation_user ""} {-party_id ""} {-action "edit"} } { If the user is not allowed to edit this object, returns a permission denied page. @param creation_user Optionally specify creation_user directly as an optimization. Otherwise a query will be executed. @param party_id The party to have or not have write permission. @see permission::write_permission_p } { if { ![permission::write_permission_p -object_id $object_id -party_id $party_id] } { ad_return_forbidden "Permission Denied" "You don't have permission to $action this object." ad_script_abort } } ad_proc -deprecated ad_permission_grant { user_id object_id privilege } { Grant a permission @author ben@openforce.net @see permission::grant } { permission::grant -party_id $user_id -object_id $object_id -privilege $privilege } ad_proc -deprecated ad_permission_revoke { user_id object_id privilege } { Revoke a permission @author ben@openforce.net @see permission::revoke } { permission::revoke -party_id $user_id -object_id $object_id -privilege $privilege } ad_proc -deprecated ad_permission_p { {-user_id ""} object_id privilege } { @see permission::permission_p } { return [permission::permission_p -party_id $user_id -object_id $object_id -privilege $privilege] } ad_proc -deprecated ad_require_permission { object_id privilege } { @see permission::require_permission } { permission::require_permission -object_id $object_id -privilege $privilege } ad_proc -private ad_admin_filter {} { permission::require_permission -object_id [ad_conn object_id] -privilege "admin" return filter_ok } ad_proc -private ad_user_filter {} { permission::require_permission -object_id [ad_conn object_id] -privilege "read" return filter_ok } openacs-5.7.0/packages/acs-tcl/tcl/acs-permissions-procs.xql0000644000175000017500000000250410171476753023666 0ustar frankiefrankie select count(*) from acs_privileges where privilege = :privilege select case when security_inherit_p = 't' then 1 else 0 end from acs_objects where object_id = :object_id update acs_objects set security_inherit_p = 't' where object_id = :object_id update acs_objects set security_inherit_p = 'f' where object_id = :object_id select 1 from dual where exists ( select 1 from acs_object_party_privilege_map ppm where ppm.object_id = :object_id and ppm.party_id = :party_id and ppm.privilege = :privilege ) openacs-5.7.0/packages/acs-tcl/tcl/image-procs.tcl0000644000175000017500000000206507750001551021576 0ustar frankiefrankiead_library { Procedures to manage image files. @author Lars Pind (lars@collaboraid.biz) @creationd-date 2003-10-29 @cvs-id $Id: image-procs.tcl,v 1.1 2003/10/29 18:14:01 lars Exp $ } namespace eval image {} ad_proc -public image::get_info { {-filename:required} {-array:required} } { Get the width and height of an image file. The width and height are returned as 'height' and 'width' entries in the array named in the parameter. Uses ImageMagick instead of aolserver function because it can handle more than just gifs and jpegs. The plan is to add the ability to get more details later. @param filename Name of the image file in the file system. @param array Name of an array where you want the information returned. } { upvar 1 $array row array set row { height {} width {} } catch { set identify_string [exec identify $filename] regexp {[ ]+([0-9]+)[x]([0-9]+)[\+]*} $identify_string x width height set row(width) $width set row(height) $height } } openacs-5.7.0/packages/acs-tcl/tcl/site-nodes-init.tcl0000644000175000017500000000034711073636333022411 0ustar frankiefrankiead_library { @author rhs@mit.edu @creation-date 2000-09-07 @cvs-id $Id: site-nodes-init.tcl,v 1.5 2008/10/10 11:30:35 gustafn Exp $ } nsv_set site_nodes_mutex mutex [ns_mutex create oacs:site_nodes] site_node::init_cache openacs-5.7.0/packages/acs-tcl/tcl/security-init.tcl0000644000175000017500000000271111124154044022172 0ustar frankiefrankiead_library { Provides methods for authorizing and identifying ACS (both logged in and not) and tracking their sessions. @creation-date 16 Feb 2000 @author Jon Salz (jsalz@arsdigita.com) @author Richard Li (richardl@arsdigita.com) @cvs-id $Id: security-init.tcl,v 1.5 2008/12/23 12:23:00 gustafn Exp $ } # Schedule a procedure to sweep for sessions. ad_schedule_proc -thread f [parameter::get -parameter SessionSweepInterval -default 7200] sec_sweep_sessions # Verify that the secret_tokens table is populated set secret_tokens_exists [db_string secret_tokens_exists "select decode(count(*),0,0,1) from secret_tokens"] if { $secret_tokens_exists == 0 } { populate_secret_tokens_db } ns_log Notice "security-init.tcl: Creating secret_tokens ns_cache..." ns_cache create secret_tokens -size 32768 ns_log Notice "security-init.tcl: Populating secret_tokens ns_cache..." populate_secret_tokens_cache # These procedures are dynamically defined so that parameter::get # does not need to be called directly in the RP. proc sec_session_timeout {} " return \"[parameter::get -package_id [ad_acs_kernel_id] -parameter SessionTimeout -default 1200]\" " proc sec_session_renew {} " return \"[expr {[sec_session_timeout] - [parameter::get -package_id [ad_acs_kernel_id] -parameter SessionRenew -default 300]}]\" " proc sec_login_timeout {} " return \"[parameter::get -package_id [ad_acs_kernel_id] -parameter LoginTimeout -default 28800]\" " openacs-5.7.0/packages/acs-tcl/tcl/security-init.xql0000644000175000017500000000033507271732156022232 0ustar frankiefrankie select case when count(*) = 0 then 0 else 1 end from secret_tokens openacs-5.7.0/packages/acs-tcl/tcl/whos-online-init.tcl0000644000175000017500000000037007737246006022603 0ustar frankiefrankiead_library { Initializes datastrctures for whos online. @creation-date 03 October 2003 @cvs-id $Id: whos-online-init.tcl,v 1.1 2003/10/03 10:14:30 lars Exp $ } # Schedule proc to clean up whos_online data structure whos_online::init openacs-5.7.0/packages/acs-tcl/tcl/security-procs.tcl0000644000175000017500000016016611553151141022367 0ustar frankiefrankiead_library { Provides methods for authorizing and identifying ACS users (both logged in and not) and tracking their sessions. @creation-date 16 Feb 2000 @author Jon Salz (jsalz@arsdigita.com) @author Richard Li (richardl@arsdigita.com) @author Archit Shah (ashah@arsdigita.com) @cvs-id $Id: security-procs.tcl,v 1.72 2011/04/19 00:08:01 daveb Exp $ } namespace eval security {} # cookies (all are signed cookies): # cookie value max-age secure # ad_session_id session_id,user_id,login_level SessionTimeout no # ad_user_login user_id,issue_time,auth_token never expires no # ad_user_login_secure user_id,random never expires yes # ad_secure_token session_id,random,peeraddr SessionLifetime yes # # the random data is used to hinder attack the secure hash. # currently the random data is ns_time # peeraddr is used to avoid session hijacking # # ad_user_login issue_time: [ns_time] at the time the user last authenticated # # ad_session_id login_level: 0 = none/expired, 1 = ok, 2 = auth ok, but account closed # ad_proc -private sec_random_token {} { Generates a random token. } { # tcl_sec_seed is used to maintain a small subset of the previously # generated random token to use as the seed for the next # token. this makes finding a pattern in sec_random_token harder # to guess when it is called multiple times in the same thread. global tcl_sec_seed if { [ad_conn -connected_p] } { set request [ad_conn request] set start_clicks [ad_conn start_clicks] } else { set request "yoursponsoredadvertisementhere" set start_clicks "cvs.openacs.org" } if { ![info exists tcl_sec_seed] } { set tcl_sec_seed "listentowmbr89.1" } set random_base [ns_sha1 "[ns_time][ns_rand]$start_clicks$request$tcl_sec_seed"] set tcl_sec_seed [string range $random_base 0 10] return [ns_sha1 [string range $random_base 11 39]] } ad_proc -private sec_session_lifetime {} { Returns the maximum lifetime, in seconds, for sessions. } { # default value is 7 days ( 7 * 24 * 60 * 60 ) return [parameter::get -package_id [ad_acs_kernel_id] -parameter SessionLifetime -default 604800] } ad_proc -private sec_sweep_sessions {} { set expires [expr {[ns_time] - [sec_session_lifetime]}] db_dml sessions_sweep {} db_release_unused_handles } ad_proc -private sec_handler {} { Reads the security cookies, setting fields in ad_conn accordingly. } { ns_log debug "OACS= sec_handler: enter" #foreach c [list ad_session_id ad_secure_token ad_user_login ad_user_login_secure] { # lappend msg "$c [ad_get_cookie $c]" #} #ns_log notice "OACS cookies: $msg" if { [catch { set cookie_list [ad_get_signed_cookie "ad_session_id"] } errmsg ] } { # Cookie is invalid because either: # -> it was never set # -> it failed the cryptographic check # -> it expired. # Now check for login cookie ns_log Debug "OACS: Not a valid session cookie, looking for login cookie '$errmsg'" ad_user_logout sec_login_handler } else { # The session cookie already exists and is valid. set cookie_data [split [lindex $cookie_list 0] {,}] set session_last_renew_time [lindex $cookie_data 3] if {![string is integer -strict $session_last_renew_time]} { # This only happens if the session cookie is old style # previous to openacs 5.7 and does not have session review time # embedded. # Assume cookie expired and force login handler set session_last_renew_time 0 } set session_expr [expr {$session_last_renew_time + [sec_session_timeout]}] if {$session_expr < [ns_time]} { sec_login_handler } set session_id [lindex $cookie_data 0] set untrusted_user_id [lindex $cookie_data 1] set login_level [lindex $cookie_data 2] set user_id 0 set account_status closed switch $login_level { 1 { set auth_level ok set user_id $untrusted_user_id set account_status ok } 2 { set auth_level ok } default { if { $untrusted_user_id == 0 } { set auth_level none } else { set auth_level expired } } } ns_log Debug "Security: Insecure session OK: session_id = $session_id, untrusted_user_id = $untrusted_user_id, auth_level = $auth_level, user_id = $user_id" # We're okay, insofar as the insecure session, check if it's also secure if { $auth_level eq "ok" && [security::secure_conn_p] } { catch { set sec_token [split [ad_get_signed_cookie "ad_secure_token"] {,}] if {[lindex $sec_token 0] eq $session_id && [lindex $sec_token 2] eq [ad_conn peeraddr] } { set auth_level secure } } ns_log Debug "Security: Secure session checked: session_id = $session_id, untrusted_user_id = $untrusted_user_id, auth_level = $auth_level, user_id = $user_id" } # Setup ad_conn ad_conn -set session_id $session_id ad_conn -set untrusted_user_id $untrusted_user_id ad_conn -set user_id $user_id ad_conn -set auth_level $auth_level ad_conn -set account_status $account_status # reissue session cookie so session doesn't expire if the # renewal period has passed. this is a little tricky because # the cookie doesn't know about sec_session_renew; it only # knows about sec_session_timeout. # [sec_session_renew] = SessionTimeout - SessionRenew (see security-init.tcl) # $session_expr = PreviousSessionIssue + SessionTimeout if { $session_expr - [sec_session_renew] < [ns_time] } { # LARS: We abandoned the use of sec_login_handler here. This lets people stay logged in forever # if only the keep requesting pages frequently enough, but the alternative was that # the situation where LoginTimeout = 0 (infinte) and the user unchecks the "Remember me" checkbox # would cause users' sessions to expire as soon as the session needed to be renewed sec_generate_session_id_cookie } } } ad_proc -private sec_login_read_cookie {} { Fetches values either from ad_user_login_secure or ad_user_login, depending whether we are in a secured connection or not. @author Victor Guerra @return List of values read from cookie ad_user_login_secure or ad_user_login } { # If over HTTPS, we look for a secure cookie, otherwise we look for the normal one set login_list [list] if { [security::secure_conn_p] } { catch { set login_list [split [ad_get_signed_cookie "ad_user_login_secure"] ","] } } if { $login_list eq "" } { set login_list [split [ad_get_signed_cookie "ad_user_login"] ","] } return $login_list } ad_proc -private sec_login_handler {} { Reads the login cookie, setting fields in ad_conn accordingly. } { ns_log debug "OACS= sec_login_handler: enter" set auth_level none set new_user_id 0 set untrusted_user_id 0 set account_status closed # check for permanent login cookie catch { set login_list [sec_login_read_cookie] set untrusted_user_id [lindex $login_list 0] set login_expr [lindex $login_list 1] set auth_token [lindex $login_list 2] set auth_level expired # Check authentication cookie # First, check expiration if { [sec_login_timeout] == 0 || [ns_time] - $login_expr < [sec_login_timeout] } { # Then check auth_token if {$auth_token eq [sec_get_user_auth_token $untrusted_user_id]} { # Are we secure? if { [security::secure_conn_p] } { # We retrieved the secure login cookie over HTTPS, we're secure set auth_level secure } else { set auth_level ok } } } # Check account status set account_status [auth::get_local_account_status -user_id $untrusted_user_id] if {$account_status eq "no_account"} { set untrusted_user_id 0 set auth_level none set account_status "closed" } } sec_setup_session $untrusted_user_id $auth_level $account_status } ad_proc -public ad_user_login { {-account_status "ok"} -forever:boolean user_id } { Logs the user in, forever (via the user_login cookie) if -forever is true. This procedure assumes that the user identity has been validated. } { set prev_user_id [ad_conn user_id] # deal with the permanent login cookies (ad_user_login and ad_user_login_secure) if { $forever_p } { set max_age inf } else { # ad_user_login cookie will live for as long as the maximum login time set max_age [sec_login_timeout] } set auth_level "ok" set domain [parameter::get -parameter CookieDomain -package_id [ad_acs_kernel_id]] # If you're logged in over a secure connection, you're secure if { [security::secure_conn_p] } { ad_set_signed_cookie \ -max_age $max_age \ -secure t \ -domain $domain \ ad_user_login_secure \ "$user_id,[ns_time],[sec_get_user_auth_token $user_id],[ns_time],$forever_p" # We're secure set auth_level "secure" } elseif { $prev_user_id != $user_id } { # Hose the secure login token if this user is different # from the previous one. ad_set_cookie -max_age 0 ad_user_login_secure "" } ns_log Debug "ad_user_login: Setting new ad_user_login cookie with max_age $max_age" ad_set_signed_cookie \ -max_age $max_age \ -domain $domain \ -secure f \ ad_user_login \ "$user_id,[ns_time],[sec_get_user_auth_token $user_id],$forever_p" # deal with the current session sec_setup_session $user_id $auth_level $account_status } ad_proc -public sec_get_user_auth_token { user_id } { Get the user's auth token for verifying login cookies. } { set auth_token [db_string select_auth_token { select auth_token from users where user_id = :user_id } -default {}] db_release_unused_handles if { $auth_token eq "" } { ns_log Debug "Security: User $user_id does not have any auth_token, creating a new one." set auth_token [sec_change_user_auth_token $user_id] } return $auth_token } ad_proc -public sec_change_user_auth_token { user_id } { Change the user's auth_token, which invalidates all existing login cookies, ie. forces user logout at the server. } { set auth_token [ad_generate_random_string] ns_log Debug "Security: Changing user $user_id's auth_token to '$auth_token'" db_dml update_auth_token { update users set auth_token = :auth_token where user_id = :user_id } db_release_unused_handles return $auth_token } ad_proc -public ad_user_logout {} { Logs the user out. } { set domain [parameter::get -parameter CookieDomain -package_id [ad_acs_kernel_id]] ad_set_cookie -replace t -max_age 0 -domain $domain ad_session_id "" ad_set_cookie -replace t -max_age 0 -domain $domain ad_secure_token "" ad_set_cookie -replace t -max_age 0 -domain $domain ad_user_login "" ad_set_cookie -replace t -max_age 0 -domain $domain ad_user_login_secure "" } ad_proc -public ad_check_password { user_id password_from_form } { Returns 1 if the password is correct for the given user ID. } { set found_p [db_0or1row password_select {select password, salt from users where user_id = :user_id}] db_release_unused_handles if { !$found_p } { return 0 } set salt [string trim $salt] if {$password ne [ns_sha1 "$password_from_form$salt"] } { return 0 } return 1 } ad_proc -public ad_change_password { user_id new_password } { Change the user's password } { # In case someone wants to change the salt from now on, you can do # this and still support old users by changing the salt below. if { $user_id eq "" } { error "No user_id supplied" } set salt [sec_random_token] set new_password [ns_sha1 "$new_password$salt"] db_dml password_update {} db_release_unused_handles } ad_proc -private sec_setup_session { new_user_id auth_level account_status } { Set up the session, generating a new one if necessary, and generates the cookies necessary for the session } { ns_log debug "OACS= sec_setup_session: enter" set session_id [ad_conn session_id] # figure out the session id, if we don't already have it if { $session_id eq ""} { ns_log debug "OACS= empty session_id" set session_id [sec_allocate_session] # if we have a user on an newly allocated session, update # users table ns_log debug "OACS= newly allocated session $session_id" if { $new_user_id != 0 } { ns_log debug "OACS= about to update user session info, user_id NONZERO" sec_update_user_session_info $new_user_id ns_log debug "OACS= done updating user session info, user_id NONZERO" } } else { # $session_id is an active verified session # this call is either a user logging in # on an active unidentified session, or a change in identity # for a browser that is already logged in # this is an active session [ad_conn user_id] will not return # the empty string set prev_user_id [ad_conn user_id] if { $prev_user_id != 0 && $prev_user_id != $new_user_id } { # this is a change in identity so we should create # a new session so session-level data is not shared set session_id [sec_allocate_session] } if { $prev_user_id != $new_user_id } { # a change of user_id on an active session # demands an update of the users table sec_update_user_session_info $new_user_id } } set user_id 0 # If both auth_level and account_status are 'ok' or better, we have a solid user_id if { ($auth_level eq "ok" || $auth_level eq "secure") && $account_status eq "ok" } { set user_id $new_user_id } # Set ad_conn variables ad_conn -set untrusted_user_id $new_user_id ad_conn -set session_id $session_id ad_conn -set auth_level $auth_level ad_conn -set account_status $account_status ad_conn -set user_id $user_id ns_log debug "OACS= about to generate session id cookie" sec_generate_session_id_cookie ns_log debug "OACS= done generating session id cookie" if { $auth_level eq "secure" && [security::secure_conn_p] && $new_user_id != 0 } { # this is a secure session, so the browser needs # a cookie marking it as such sec_generate_secure_token_cookie } } ad_proc -private sec_update_user_session_info { user_id } { Update the session info in the users table. Should be called when the user login either via permanent cookies at session creation time or when they login by entering their password. } { db_dml update_last_visit { update users set second_to_last_visit = last_visit, last_visit = sysdate, n_sessions = n_sessions + 1 where user_id = :user_id } db_release_unused_handles } ad_proc -private sec_generate_session_id_cookie {} { Sets the ad_session_id cookie based on global variables. } { set user_id [ad_conn untrusted_user_id] set session_id [ad_conn session_id] set auth_level [ad_conn auth_level] set account_status [ad_conn account_status] set login_level 0 if { $auth_level eq "ok" || $auth_level eq "secure" } { if {$account_status eq "ok"} { set login_level 1 } else { set login_level 2 } } ns_log Debug "Security: [ns_time] sec_generate_session_id_cookie setting session_id=$session_id, user_id=$user_id, login_level=$login_level" set domain [parameter::get -parameter CookieDomain -package_id [ad_acs_kernel_id]] # we fetch the last value element of ad_user_login cookie (or ad_user_login_secure) that indicates # if user wanted to be remembered when loggin in set discard t set max_age [sec_session_timeout] catch { set login_list [sec_login_read_cookie] if {[lindex $login_list end] == 1} { set discard f set max_age inf } } ad_set_signed_cookie -discard $discard -replace t -max_age $max_age -domain $domain \ "ad_session_id" "$session_id,$user_id,$login_level,[ns_time]" } ad_proc -private sec_generate_secure_token_cookie { } { Sets the ad_secure_token cookie. } { ad_set_signed_cookie -secure t "ad_secure_token" "[ad_conn session_id],[ns_time],[ad_conn peeraddr]" } ad_proc -public -deprecated -warn ad_secure_conn_p {} { Use security::secure_conn_p instead. @see security::secure_conn_p } { return [security::secure_conn_p] } ad_proc -private sec_allocate_session {} { Returns a new session id } { global tcl_max_value global tcl_current_sequence_id if { ![info exists tcl_max_value] || ![info exists tcl_current_sequence_id] || $tcl_current_sequence_id > $tcl_max_value } { # Thread just spawned or we exceeded preallocated count. set tcl_current_sequence_id [db_nextval sec_id_seq] db_release_unused_handles set tcl_max_value [expr {$tcl_current_sequence_id + 100}] } set session_id $tcl_current_sequence_id incr tcl_current_sequence_id return $session_id } ad_proc -private ad_login_page {} { Returns 1 if the page is used for logging in, 0 otherwise. } { set url [ad_conn url] if { [string match "*register/*" $url] || [string match "/index*" $url] || \ [string match "/index*" $url] || \ "/" eq $url || \ [string match "*password-update*" $url] } { return 1 } return 0 } ##### # # Login/logout URLs, redirecting, etc. # ##### ad_proc -public ad_redirect_for_registration {} { Redirects user to [subsite]/register/index to require the user to register. When registration is complete, the user will be returned to the current location. All variables in ns_getform (both posts and gets) will be maintained.

    It's up to the caller to issue an ad_script_abort, if that's what you want. @see ad_get_login_url } { ad_returnredirect [ad_get_login_url -return] } ad_proc -public ad_get_login_url { -authority_id -username -return:boolean } { Returns a URL to the login page of the closest subsite, or the main site, if there's no current connection. @option return If set, will export the current form, so when the registration is complete, the user will be returned to the current location. All variables in ns_getform (both posts and gets) will be maintained. @author Lars Pind (lars@collaboraid.biz) } { if { [ad_conn isconnected] } { set url [subsite::get_element -element url] # Check to see that the user (most likely "The Public" party, since there's probably no user logged in) # actually have permission to view that subsite, otherwise we'll get into an infinite redirect loop array set site_node [site_node::get_from_url -url $url] set package_id $site_node(object_id) if { ![permission::permission_p -no_login -object_id $site_node(object_id) -privilege read -party_id 0] } { set url / } } else { set url / } set UseHostnameDomainforReg [parameter::get -package_id [apm_package_id_from_key acs-tcl] -parameter UseHostnameDomainforReg -default 0] if { $UseHostnameDomainforReg } { # get config.tcl's hostname set nssock [ns_config ns/server/[ns_info server]/modules nssock] set nsunix [ns_config ns/server/[ns_info server]/modules nsunix] if {$nsunix ne ""} { set driver nsunix } else { set driver nssock } set config_hostname [ns_config ns/server/[ns_info server]/module/$driver Hostname] set current_location [util_current_location] # if current domain and hostdomain are different (and UseHostnameDomain), revise url if { ![string match -nocase "*${config_hostname}*" $current_location] } { if { [string range $url 0 0] eq "/" } { # Make the url fully qualified if { [security::secure_conn_p] } { set url_decoded [security::get_secure_qualified_url $url] } else { set url_decoded [security::get_insecure_qualified_url $url] } } else { set url_decoded $url } # revise url to use hostname's domain # if url points to a non / host_node, redirect to main hostname set host_node_map_hosts_list [db_list -cache_key security-locations-host-names get_node_host_names "select host from host_node_map"] if { [llength $host_node_map_hosts_list] > 0 } { foreach hostname $host_node_map_hosts_list { if { [string match -nocase "http://${hostname}*" $url_decoded] || [string match -nocase "https://${hostname}*" $url_decoded] } { db_1row get_node_id_from_host_name "select node_id as host_node_id from host_node_map where host = :hostname" # site node already in url, so just switching domain. if { ![regsub -- "${hostname}" $url_decoded "${config_hostname}" url_decoded] } { ns_log Warning "ad_get_login_url(ref619): regsub was unable to modify url to hostname's domain. User may not appear to be logged-in after login. url_decoded: ${url_decoded} url: ${url}" } } } } set url $url_decoded } } append url "register/" set export_vars [list] if { [exists_and_not_null authority_id] } { lappend export_vars authority_id } if { [exists_and_not_null username] } { lappend export_vars username } # We don't add a return_url if you're currently under /register, because that will frequently # interfere with normal login procedure if { [ad_conn isconnected] && $return_p && ![string match "register/*" [ad_conn extra_url]] } { if { [security::secure_conn_p] || ![security::RestrictLoginToSSLP] } { set return_url [ad_return_url] } else { set return_url [ad_return_url -qualified] } if { $UseHostnameDomainforReg } { # if current domain and hostdomain are different (and UseHostnameDomainforReg), revise return_url if { ![string match -nocase "*${config_hostname}*" $current_location] } { if { [string range $return_url 0 0] eq "/" } { # Make the return_url fully qualified if { [security::secure_conn_p] } { set return_url_decoded [security::get_secure_qualified_url $return_url] } else { set return_url_decoded [security::get_insecure_qualified_url $return_url] } } else { set return_url_decoded $return_url } # revise return_url to use hostname's domain # if return_url points to a non / host_node, redirect to main hostname set host_node_map_hosts_list [db_list -cache_key security-locations-host-names get_node_host_names "select host from host_node_map"] if { [llength $host_node_map_hosts_list] > 0 } { foreach hostname $host_node_map_hosts_list { if { [string match -nocase "http://${hostname}*" $return_url_decoded] || [string match -nocase "https://${hostname}*" $return_url_decoded] } { db_1row get_node_id_from_host_name "select node_id as host_node_id from host_node_map where host = :hostname" if { ![regsub -- "${hostname}" $return_url_decoded "${config_hostname}[site_node::get_url -node_id ${host_node_id} -notrailing]" return_url_decoded] } { ns_log Warning "ad_get_login_url(ref672): regsub was unable to modify return_url to hostname's domain. User may not appear to be logged-in after login. return_url_decoded: ${return_url_decoded} return_url: ${return_url}" } } } } set return_url $return_url_decoded } } lappend export_vars { return_url } } if { [llength $export_vars] > 0 } { set url [export_vars -base $url $export_vars] } return $url } ad_proc -public ad_get_logout_url { -return:boolean {-return_url ""} } { Returns a URL to the logout page of the closest subsite, or the main site, if there's no current connection. @option return If set, will export the current form, so when the logout is complete the user will be returned to the current location. All variables in ns_getform (both posts and gets) will be maintained. @author Lars Pind (lars@collaboraid.biz) } { if { [ad_conn isconnected] } { set url [subsite::get_element -element url] } else { set url / } append url "register/logout" if { $return_p && $return_url eq "" } { set return_url [ad_return_url] } if { $return_url ne "" } { set url [export_vars -base $url { return_url }] } return $url } # JCD 20020915 I think this probably should not be deprecated since it is # far more reliable than permissioning esp for a development server ad_proc -public ad_restrict_entire_server_to_registered_users { conn args why } { A preauth filter that will halt service of any page if the user is unregistered, except the site index page and stuff underneath [subsite]/register. Use permissions on the site node map to control access. } { if {"/favicon.ico" ne [ad_conn url] && "/index.tcl" ne [ad_conn url] && "/" ne [ad_conn url] && ![string match "/global/*" [ad_conn url]] && ![string match "*/register/*" [ad_conn url]] && ![string match "*/SYSTEM/*" [ad_conn url]] && ![string match "*/user_please_login.tcl" [ad_conn url]]} { # not one of the magic acceptable URLs set user_id [ad_conn user_id] if {$user_id == 0} { ad_returnredirect "[subsite::get_element -element url]register/?return_url=[ns_urlencode [ad_conn url]?[ad_conn query]]" return filter_return } } return filter_ok } ##### # # Signed cookie handling # ##### ad_proc -public ad_sign { {-secret ""} {-token_id ""} {-max_age ""} value } { Returns a digital signature of the value. Negative token_ids are reserved for secrets external to the ACS digital signature mechanism. If a token_id is specified, a secret must also be specified. @param max_age specifies the length of time the signature is valid in seconds. The default is forever. @param secret allows the caller to specify a known secret external to the random secret management mechanism. @param token_id allows the caller to specify a token_id which is then ignored so don't use it. @param value the value to be signed. } { if { $secret eq "" } { if {$token_id eq ""} { # pick a random token_id set token_id [sec_get_random_cached_token_id] } set secret_token [sec_get_token $token_id] } else { set secret_token $secret } ns_log Debug "Security: Getting token_id $token_id, value $secret_token" if { $max_age eq "" } { set expire_time 0 } else { set expire_time [expr {$max_age + [ns_time]}] } set hash [ns_sha1 "$value$token_id$expire_time$secret_token"] set signature [list $token_id $expire_time $hash] return $signature } ad_proc -public ad_verify_signature { {-secret ""} value signature } { Verifies a digital signature. Returns 1 for success, and 0 for failed validation. Validation can fail due to tampering or expiration of signature. @param secret specifies an external secret to use instead of the one provided by the ACS signature mechanism. } { set token_id [lindex $signature 0] set expire_time [lindex $signature 1] set hash [lindex $signature 2] return [__ad_verify_signature $value $token_id $secret $expire_time $hash] } ad_proc -public ad_verify_signature_with_expr { {-secret ""} value signature } { Verifies a digital signature. Returns either the expiration time or 0 if the validation fails. @param secret specifies an external secret to use instead of the one provided by the ACS signature mechanism. } { set token_id [lindex $signature 0] set expire_time [lindex $signature 1] set hash [lindex $signature 2] if { [__ad_verify_signature $value $token_id $secret $expire_time $hash] } { return $expire_time } else { return 0 } } ad_proc -private __ad_verify_signature { value token_id secret expire_time hash } { Returns 1 if signature validated; 0 if it fails. } { if { $secret eq "" } { if { $token_id eq "" } { ns_log Debug "__ad_verify_signature: Neither secret, nor token_id supplied" return 0 } set secret_token [sec_get_token $token_id] } else { set secret_token $secret } ns_log Debug "__ad_verify_signature: Getting token_id $token_id, value $secret_token ; " ns_log Debug "__ad_verify_signature: Expire_Time is $expire_time (compare to [ns_time]), hash is $hash" # validate cookie: verify hash and expire_time set computed_hash [ns_sha1 "$value$token_id$expire_time$secret_token"] # Need to verify both hash and expiration set hash_ok_p 0 set expiration_ok_p 0 if {$computed_hash eq $hash} { ns_log Debug "__ad_verify_signature: Hash matches - Hash check OK" set hash_ok_p 1 } else { # check to see if IE is lame (and buggy!) and is expanding \n to \r\n # See: http://rhea.redhat.com/bboard-archive/webdb/000bfF.html set value [string map [list \r ""] $value] set org_computed_hash $computed_hash set computed_hash [ns_sha1 "$value$token_id$expire_time$secret_token"] if {$computed_hash eq $hash} { ns_log Debug "__ad_verify_signature: Hash matches after correcting for IE bug - Hash check OK" set hash_ok_p 1 } else { ns_log Debug "__ad_verify_signature: Hash ($hash) doesn't match what we expected ($org_computed_hash) - Hash check FAILED" } } if { $expire_time == 0 } { ns_log Debug "__ad_verify_signature: No expiration time - Expiration OK" set expiration_ok_p 1 } elseif { $expire_time > [ns_time] } { ns_log Debug "__ad_verify_signature: Expiration time ($expire_time) greater than current time ([ns_time]) - Expiration check OK" set expiration_ok_p 1 } else { ns_log Debug "__ad_verify_signature: Expiration time ($expire_time) less than or equal to current time ([ns_time]) - Expiration check FAILED" } # Return validation result return [expr {$hash_ok_p && $expiration_ok_p}] } ad_proc -public ad_get_signed_cookie { {-include_set_cookies t} {-secret ""} name } { Retrieves a signed cookie. Validates a cookie against its cryptographic signature and insures that the cookie has not expired. Throws an exception if validation fails. } { if { $include_set_cookies eq "t" } { set cookie_value [ns_urldecode [ad_get_cookie $name]] } else { set cookie_value [ns_urldecode [ad_get_cookie -include_set_cookies f $name]] } if { $cookie_value eq "" } { error "Cookie does not exist." } set value [lindex $cookie_value 0] set signature [lindex $cookie_value 1] ns_log Debug "ad_get_signed_cookie: Got signed cookie $name with value $value, signature $signature." if { [ad_verify_signature $value $signature] } { ns_log Debug "ad_get_signed_cookie: Verification of cookie $name OK" return $value } ns_log Debug "ad_get_signed_cookie: Verification of cookie $name FAILED" error "Cookie could not be authenticated." } ad_proc -public ad_get_signed_cookie_with_expr { {-include_set_cookies t} {-secret ""} name } { Retrieves a signed cookie. Validates a cookie against its cryptographic signature and insures that the cookie has not expired. Returns a two-element list, the first element of which is the cookie data, and the second element of which is the expiration time. Throws an exception if validation fails. } { if { $include_set_cookies eq "t" } { set cookie_value [ns_urldecode [ad_get_cookie $name]] } else { set cookie_value [ns_urldecode [ad_get_cookie -include_set_cookies f $name]] } if { $cookie_value eq "" } { error "Cookie does not exist." } set value [lindex $cookie_value 0] set signature [lindex $cookie_value 1] set expr_time [ad_verify_signature_with_expr $value $signature] ns_log Debug "Security: Done calling get_cookie $cookie_value for $name; received $expr_time expiration, getting $value and $signature." if { $expr_time } { return [list $value $expr_time] } error "Cookie could not be authenticated." } ad_proc -public ad_set_signed_cookie { {-replace f} {-secure f} {-discard f} {-max_age ""} {-signature_max_age ""} {-domain ""} {-path "/"} {-secret ""} {-token_id ""} name value } { Sets a signed cookie. Negative token_ids are reserved for secrets external to the signed cookie mechanism. If a token_id is specified, a secret must be specified. @author Richard Li (richardl@arsdigita.com) @creation-date 18 October 2000 @param max_age specifies the maximum age of the cookies in seconds (consistent with RFC 2109). max_age inf specifies cookies that never expire. (see ad_set_cookie). The default is session cookies. @param secret allows the caller to specify a known secret external to the random secret management mechanism. @param token_id allows the caller to specify a token_id. @param value the value for the cookie. This is automatically url-encoded. } { if { $signature_max_age eq "" } { if { $max_age eq "inf" } { set signature_max_age "" } elseif { $max_age ne "" } { set signature_max_age $max_age } else { # this means we want a session level cookie, # but that is a user interface expiration, that does # not give us a security expiration. (from the # security perspective, we use SessionLifetime) ns_log Debug "Security: SetSignedCookie: Using sec_session_lifetime [sec_session_lifetime]" set signature_max_age [sec_session_lifetime] } } set cookie_value [ad_sign -secret $secret -token_id $token_id -max_age $signature_max_age $value] set data [ns_urlencode [list $value $cookie_value]] ad_set_cookie -replace $replace -secure $secure -discard $discard -max_age $max_age -domain $domain -path $path $name $data } ##### # # Token generation and handling # ##### ad_proc -private sec_get_token { token_id } { Returns the token corresponding to the token_id. This first checks the thread-persistent TCL cache, then checks the server size-limited cache before finally hitting the db in the worst case if the secret_token value is not in either cache. The procedure also updates the caches. Cache eviction is handled by the ns_cache API for the size-limited cache and is handled by AOLserver (via thread termination) for the thread-persistent TCL cache. } { global tcl_secret_tokens if { [info exists tcl_secret_tokens($token_id)] } { return $tcl_secret_tokens($token_id) } else { set token [ns_cache eval secret_tokens $token_id { set token [db_string get_token {select token from secret_tokens where token_id = :token_id} -default 0] db_release_unused_handles # Very important to throw the error here if $token == 0 if { $token == 0 } { error "Invalid token ID" } return $token }] set tcl_secret_tokens($token_id) $token return $token } } ad_proc -private sec_get_random_cached_token_id {} { Randomly returns a token_id from the ns_cache. } { set list_of_names [ns_cache names secret_tokens] set random_seed [ns_rand [llength $list_of_names]] return [lindex $list_of_names $random_seed] } ad_proc -private populate_secret_tokens_cache {} { Randomly populates the secret_tokens cache. } { set num_tokens [parameter::get -package_id [ad_acs_kernel_id] -parameter NumberOfCachedSecretTokens -default 100] # this is called directly from security-init.tcl, # so it runs during the install before the data model has been loaded if { [db_table_exists secret_tokens] } { db_foreach get_secret_tokens { select * from ( select token_id, token from secret_tokens sample(15) ) where rownum < :num_tokens } { ns_cache set secret_tokens $token_id $token } } db_release_unused_handles } ad_proc -private populate_secret_tokens_db {} { Populates the secret_tokens table. Note that this will take awhile to run. } { set num_tokens [parameter::get -package_id [ad_acs_kernel_id] -parameter NumberOfCachedSecretTokens -default 100] # we assume sample size of 10%. set num_tokens [expr {$num_tokens * 10}] set counter 0 set list_of_tokens [list] # the best thing to use here would be an array_dml, except # that an array_dml makes it hard to use sysdate and sequences. while { $counter < $num_tokens } { set random_token [sec_random_token] db_dml insert_random_token {} incr counter } db_release_unused_handles } ##### # # Client property procs # ##### ad_proc -private sec_lookup_property { id module name } { Used as a helper procedure for util_memoize to look up a particular property from the database. Returns [list $property_value $secure_p]. } { if { ![db_0or1row property_lookup_sec { select property_value, secure_p from sec_session_properties where session_id = :id and module = :module and property_name = :name }] } { return "" } set new_last_hit [clock seconds] db_dml update_last_hit_dml { update sec_session_properties set last_hit = :new_last_hit where session_id = :id and property_name = :name } return [list $property_value $secure_p] } ad_proc -public ad_get_client_property { {-cache t} {-cache_only f} {-default ""} {-session_id ""} module name } { Looks up a property for a session. If $cache is true, will use the cached value if available. If $cache_only is true, will never incur a database hit (i.e., will only return a value if cached). If the property is secure, we must be on a validated session over SSL. @param session_id controls which session is used } { if { $session_id eq "" } { set id [ad_conn session_id] # if session_id is still undefined in the connection then we # should just return the default if { $id eq "" } { return $default } } else { set id $session_id } set cmd [list sec_lookup_property $id $module $name] if { $cache_only eq "t" && ![util_memoize_cached_p $cmd] } { return "" } if { $cache ne "t" } { util_memoize_flush $cmd } set property [util_memoize $cmd [sec_session_timeout]] if { $property eq "" } { return $default } set value [lindex $property 0] set secure_p [lindex $property 1] if { $secure_p ne "f" && ![security::secure_conn_p] } { return "" } return $value } ad_proc -public ad_set_client_property { {-clob f} {-secure f} {-persistent t} {-session_id ""} module name value } { Sets a client (session-level) property. If $persistent is true, the new value will be written through to the database. If $deferred is true, the database write will be delayed until connection close (although calls to ad_get_client_property will still return the correct value immediately). If $secure is true, the property will not be retrievable except via a validated, secure (HTTPS) connection. @param session_id controls which session is used @param clob tells us to use a large object to store the value } { if { $secure ne "f" && ![security::secure_conn_p] } { error "Unable to set secure property in insecure or invalid session" } if { $session_id eq "" } { set session_id [ad_conn session_id] } if { $persistent eq "t" } { # Write to database - either defer, or write immediately. First delete the old # value if any; then insert the new one. set last_hit [ns_time] db_transaction { # DRB: Older versions of this code did a delete/insert pair in an attempt # to guard against duplicate insertions. This didn't work if there was # no value for this property in the table and two transactions ran in # parallel. The problem is that without an existing row the delete had # nothing to lock on, thus allowing the two inserts to conflict. This # was discovered on a page built of frames, where the two requests from # the browser spawned two AOLserver threads to service them. # Oracle doesn't allow a RETURNING clause on an insert with a # subselect, so this code first inserts a dummy value if none exists # (ensuring it does exist afterwards) then updates it with the real # value. Ugh. set clob_update_dml [db_map prop_update_dml_clob] db_dml prop_insert_dml "" if { $clob eq "t" && $clob_update_dml ne "" } { db_dml prop_update_dml_clob "" -clobs [list $value] } else { db_dml prop_update_dml "" } } } # Remember the new value, seeding the memoize cache with the proper value. util_memoize_seed [list sec_lookup_property $session_id $module $name] [list $value $secure] } ##### # # Deprecated procs # ##### ad_proc -public -deprecated ad_get_user_id {} { Gets the user ID. 0 indicates the user is not logged in. Deprecated since user_id now provided via ad_conn user_id @see ad_conn } { return [ad_conn user_id] } ad_proc -public -deprecated -warn ad_verify_and_get_user_id { {-secure f} } { Returns the current user's ID. 0 indicates user is not logged in Deprecated since user_id now provided via ad_conn user_id @see ad_conn } { return [ad_conn user_id] } # handling privacy ad_proc -public -deprecated ad_privacy_threshold {} { Pages that are consider whether to display a user's name or email address should test to make sure that a user's priv_ from the database is less than or equal to what ad_privacy_threshold returns. Now deprecated. @see ad_conn } { set session_user_id [ad_get_user_id] if {$session_user_id == 0} { # viewer of this page isn't logged in, only show stuff # that is extremely unprivate set privacy_threshold 0 } else { set privacy_threshold 5 } return $privacy_threshold } ad_proc -deprecated ad_maybe_redirect_for_registration {} { Checks to see if a user is logged in. If not, redirects to [subsite]/register/index to require the user to register. When registration is complete, the user will return to the current location. All variables in ns_getform (both posts and gets) will be maintained. Note that this will return out of its caller so that the caller need not explicitly call "return". Returns the user id if login was succesful. @see auth::require_login } { auth::require_login } ##### # # security namespace public procs # ##### ad_proc -public security::https_available_p {} { Return 1 if AOLserver is configured to support HTTPS and 0 otherwise. @author Peter Marklund } { return [expr ![empty_string_p [get_https_port]]] } ad_proc -public security::secure_conn_p {} { Returns true if the connection [ad_conn] is secure (HTTPS), or false otherwise. } { return [string match "https:*" [util_current_location]] } ad_proc -public security::RestrictLoginToSSLP {} { Return 1 if login pages and other pages taking user password should be restricted to a secure (HTTPS) connection and 0 otherwise. Based on acs-kernel parameter with same name. @author Peter Marklund } { if { ![security::https_available_p] } { return 0 } return [parameter::get \ -boolean \ -parameter RestrictLoginToSSLP \ -package_id [ad_acs_kernel_id]] } ad_proc -public security::require_secure_conn {} { Redirect back to the current page in secure mode (HTTPS) if we are not already in secure mode. Does nothing if the server is not configured for HTTPS support. @author Peter Marklund } { if { ![https_available_p] } { return } if { ![security::secure_conn_p] } { security::redirect_to_secure [ad_return_url -qualified] } } ad_proc -public security::redirect_to_secure { url } { Redirect to the given URL and enter secure (HTTPS) mode. Does nothing if the server is not configured for HTTPS support. @author Peter Marklund } { if { ![https_available_p] } { return } set secure_url [get_secure_qualified_url $url] ad_returnredirect $secure_url ad_script_abort } ad_proc -public security::redirect_to_insecure { url } { Redirect to the given URL and enter insecure (HTTP) mode. @author Peter Marklund } { set insecure_url [get_insecure_qualified_url $url] ad_returnredirect $insecure_url ad_script_abort } ##### # # security namespace private procs # ##### ad_proc -private security::get_https_port {} { Return the HTTPS port specified in the AOLserver config file. @return The HTTPS port or the empty string if none is configured. @author Peter Marklund } { set secure_port "" # decide if we are using nsssl or nsopenssl or nsssle, favor nsopenssl set nsssl [ns_config ns/server/[ns_info server]/modules nsssl] set nsopenssl [ns_config ns/server/[ns_info server]/modules nsopenssl] set nsssle [ns_config ns/server/[ns_info server]/modules nsssle] if { $nsopenssl ne "" } { set sdriver nsopenssl } elseif { $nsssl ne "" } { set sdriver nsssl } elseif { $nsssle ne "" } { set sdriver nsssle } else { return "" } # ec_secure_location # nsopenssl 3 has variable locations for the secure port, openacs standardized at: set secure_port [ns_config -int "ns/server/[ns_info server]/module/$sdriver/ssldriver/users" port 443] # nsssl, nsssle etc if {$secure_port eq ""} { set secure_port [ns_config -int "ns/server/[ns_info server]/module/$sdriver" port] } # checking nsopenssl 2.0 which has different names for the secure port etc, and is not supported with this version of OpenACS if {$secure_port eq "" || $secure_port eq "443"} { set secure_port [ns_config -int "ns/server/[ns_info server]/module/$sdriver" ServerPort 443] } return $secure_port } ad_proc -private security::get_secure_qualified_url { url } { Given a relative or qualified url, return the fully qualified HTTPS version. @author Peter Marklund } { # Get part of URL after location set qualified_uri [get_qualified_uri $url] set secure_url [get_secure_location]${qualified_uri} return $secure_url } ad_proc -private security::get_insecure_qualified_url { url } { Given a relative or qualified url, return the fully qualified HTTP version. @author Peter Marklund } { # Get part of URL after location set qualified_uri [get_qualified_uri $url] set insecure_url [get_insecure_location]${qualified_uri} return $insecure_url } ad_proc -private security::get_uri_part { url } { Get the URI following the location of the given URL. Assumes the given URL has the http or https protocol or is a relative URL. @author Peter Marklund } { regexp {^(?:http://[^/]+)?(.*)} $url match uri return $uri } ad_proc -private security::get_qualified_uri { url } { } { set uri [get_uri_part $url] if { ![regexp {^/} $uri] } { # Make relative URI qualified set qualified_uri [ad_conn url]/$uri } else { set qualified_uri $uri } return $qualified_uri } ad_proc -private security::get_secure_location {} { Return the current location in secure (https) mode. @author Peter Marklund } { set current_location [util_current_location] set https_prefix {https://} if { [regexp $https_prefix $current_location] } { # Current location is already secure - do nothing set secure_location $current_location } else { # Current location is insecure - get location from config file set secure_location [ad_conn location] # Prefix with https regsub {^(?:http://)?} $secure_location {https://} secure_location # remove port number if using nonstandard port regexp {^(.*:.*):([0-9]+)} $secure_location match secure_location port # Add port number if non-standard set https_port [get_https_port] if { $https_port ne "443" } { set secure_location ${secure_location}:$https_port } } return $secure_location } ad_proc -private security::get_insecure_location {} { Return the current location in insecure mode (http). @author Peter Marklund } { set current_location [util_current_location] set http_prefix {http://} if { [regexp $http_prefix $current_location] } { # Current location is already insecure - do nothing set insecure_location $current_location } else { # Current location is secure - use location from config file set insecure_location [ad_conn location] regsub -all {https://} $insecure_location "" insecure_location if { ![regexp $http_prefix $insecure_location] } { # Prepend http:// set insecure_location ${http_prefix}${insecure_location} } } return $insecure_location } ad_proc -public security::locations {} { @return insecure location and secure location followed possibly by alternate insecure location(s) as a list. The location consists of protocol://domain:port for website. This proc is ported from ec_insecure_location and ec_secure_location for reliably getting locations. If acs-tcl's SuppressHttpPort parameter is true, then the alternate ec_insecure_location without port is appended to the list, since it is a valid alternate. This proc also assumes hostnames from host_node_map table are accurate and legit. } { set locations [list] # following from ec_preferred_drivers set driver "" set sdriver "" if {[ns_conn isconnected]} { set hdrs [ns_conn headers] set host [ns_set iget $hdrs host] if {$host eq ""} { set driver nssock } } # Determine nssock or nsunix if {$driver eq ""} { # decide if we're using nssock or nsunix set nssock [ns_config ns/server/[ns_info server]/modules nssock] set nsunix [ns_config ns/server/[ns_info server]/modules nsunix] if {$nsunix ne ""} { set driver nsunix } else { set driver nssock } } # decide if we are using nsssl or nsopenssl, favor nsopenssl set nsssl [ns_config ns/server/[ns_info server]/modules nsssl] set nsopenssl [ns_config ns/server/[ns_info server]/modules nsopenssl] set nsssle [ns_config ns/server/[ns_info server]/modules nsssle] if { $nsopenssl ne ""} { set sdriver nsopenssl } elseif { $nsssl ne ""} { set sdriver nsssl } elseif { $nsssle ne "" } { set sdriver nsssle } else { set sdriver "" } # set the driver results array set drivers [list driver $driver sdriver $sdriver] set driver $drivers(driver) # check if port number is included here, we'll reattach it after # the request if its a non-standard port. Since we build the # secure url from this host name we need to replace the port with # the secure port set host_post "" # set host_name if {![regexp {(http://|https://)(.*?):(.*?)/?} [util_current_location] discard host_protocol host_name host_port]} { regexp {(http://|https://)(.*?)/?} [util_current_location] discard host_protocol host_name } # let's give a warning if util_current_location returns host_name # not same as from config.tcl, may help with proxy issues etc set config_hostname [ns_config ns/server/[ns_info server]/module/$driver Hostname] if { $config_hostname ne $host_name } { ns_log Warning "security::locations hostname '[ns_config ns/server/[ns_info server]/module/$driver Hostname]' from config.tcl does not match from util_current_location: $host_name" } # insecure locations set insecure_port [ns_config -int "ns/server/[ns_info server]/module/$driver" port 80] set insecure_location "http://${host_name}" set host_map_http_port "" if { $insecure_port ne "" && $insecure_port ne 80 } { set alt_insecure_location $insecure_location append insecure_location ":$insecure_port" set host_map_http_port ":$insecure_port" } # secure location, favoring nsopenssl # nsopenssl 3 has variable locations for the secure port, openacs standardized at: if { $sdriver eq "nsopenssl" } { set secure_port [ns_config -int "ns/server/[ns_info server]/module/$sdriver/ssldriver/users" port 443] } elseif { $sdriver ne "" } { # get secure port for all other cases of nsssl, nsssle etc set secure_port [ns_config -int "ns/server/[ns_info server]/module/$sdriver" port] # checking nsopenssl 2.0 which has different names for the secure port etc, and deprecated with this version of OpenACS if {$secure_port eq "" || $secure_port eq "443" } { set secure_port [ns_config -int "ns/server/[ns_info server]/module/$sdriver" ServerPort 443] } } else { set secure_port "" } lappend locations $insecure_location # if we have a secure location, add it set host_map_https_port "" if { $sdriver ne "" } { set secure_location "https://${host_name}" if {$secure_port ne "" && $secure_port ne "443"} { append secure_location ":$secure_port" set host_map_https_port ":$secure_port" } lappend locations $secure_location } # consider if we are behind a proxy and don't want to publish the proxy's backend port set suppress_http_port [parameter::get -parameter SuppressHttpPort -package_id [apm_package_id_from_key acs-tcl] -default 0] if { [info exists alt_insecure_location] && $suppress_http_port } { lappend locations $alt_insecure_location } # add locations from host_node_map set host_node_map_hosts_list [db_list -cache_key security-locations-host-names get_node_host_names "select host from host_node_map"] # fastest place for handling this special case: if { $config_hostname ne $host_name } { ns_log Notice "security::locations adding $config_hostname since utl_current_location different than config.tcl." lappend host_node_map_hosts_list $config_hostname } if { [llength $host_node_map_hosts_list] > 0 } { if { $suppress_http_port } { foreach hostname $host_node_map_hosts_list { lappend locations "http://${hostname}" lappend locations "https://${hostname}${host_map_https_port}" } } else { foreach hostname $host_node_map_hosts_list { lappend locations "http://${hostname}${host_map_http_port}" lappend locations "https://${hostname}${host_map_https_port}" } } } return $locations } openacs-5.7.0/packages/acs-tcl/tcl/security-procs.xql0000644000175000017500000000320307723347127022414 0ustar frankiefrankie delete from sec_session_properties where last_hit < :expires select password, salt from users where user_id = :user_id select property_value, secure_p from sec_session_properties where session_id = :id and module = :module and property_name = :name select token from secret_tokens where token_id = :token_id insert into sec_session_properties (session_id, module, property_name, secure_p, last_hit) select :session_id, :module, :name, :secure, :last_hit from dual where not exists (select 1 from sec_session_properties where session_id = :session_id and module = :module and property_name = :name) update sec_session_properties set last_hit = :new_last_hit where session_id = :id and property_name = :name openacs-5.7.0/packages/acs-tcl/tcl/tcl-documentation-procs.tcl0000644000175000017500000021156711567526627024177 0ustar frankiefrankiead_library { Routines to support documenting pages and processing query arguments. @author Lars Pind (lars@pinds.com) @author Jon Salz (jsalz@mit.edu) @author Yonatan Feldman (yon@arsdigita.com) @author Bryan Quinn (bquinn@arsdigita.com) @creation-date 16 June 2000 @cvs-id tcl-documentation-procs.tcl,v 1.6 2002/09/23 11:25:02 jeffd Exp } #################### # # Documentation-mode procs # #################### ad_proc api_page_documentation_mode_p { } { Determines whether the thread is in "gathering documentation" or "executing the page" mode. @return true if the thread is in "gathering documentation" mode, or false otherwise. @see doc_set_page_documentation_mode } { global ad_conn if { [info exists ad_conn(api_page_documentation_mode_p)] } { return $ad_conn(api_page_documentation_mode_p) } return 0 } ad_proc doc_set_page_documentation_mode { page_documentation_mode_p } { Set a flag in the environment determining whether the thread is in "gathering documentation" or "executing the page" mode. @param page_documentation_mode_p true to set the "gathering documentation" flag, or false to clear it. @see api_page_documentation_mode_p } { global ad_conn set ad_conn(api_page_documentation_mode_p) $page_documentation_mode_p } #################### # # Complaints procs # #################### # global: # ad_page_contract_complaints: list of error messages reported using ad_complain # # ad_page_contract_errorkeys: [list] is a stack of errorkeys # # ad_page_contract_error_string(name:flag) "the string" # ad_proc -private ad_complaints_init {} { Initializes the complaints system. @author Lars Pind (lars@pinds.com) @creation-date 24 July 2000 } { global ad_page_contract_complaints ad_page_contract_errorkeys set ad_page_contract_complaints [list] set ad_page_contract_errorkeys [list] } ad_proc -public ad_complain { {-key ""} {message ""} } { Used to report a problem while validating user input. This proc does not in itself make your code terminate, you must call return if you do not want control to return to the caller.

    @param key @param message @author Lars Pind (lars@pinds.com) @creation-date 24 July 2000 } { global ad_page_contract_complaints ad_page_contract_errorkeys ad_page_contract_error_string # if no key was specified, grab one from the internally kept stack if { $key eq "" && [info exists ad_page_contract_errorkeys] } { set key [lindex $ad_page_contract_errorkeys 0] } if { [info exists ad_page_contract_error_string($key)] } { lappend ad_page_contract_complaints $ad_page_contract_error_string($key) } elseif { $message eq "" } { lappend ad_page_contract_complaints "[_ acs-tcl.lt_Validation_key_compla]" } else { lappend ad_page_contract_complaints $message } } ad_proc -private ad_complaints_with_key { errorkey code } { Sets the default errorkey to be used when ad_complaint is called. This essentially maintains a stack of errorkeys, so we can just say ad_complain without any arguments, when called from within some code that is surrounded by ad_complaints_with_key. @author Lars Pind @creation-date 25 July 2000 } { global ad_page_contract_errorkeys set ad_page_contract_errorkeys [concat $errorkey $ad_page_contract_errorkeys] uplevel 1 $code set ad_page_contract_errorkeys [lrange $ad_page_contract_errorkeys 1 end] } ad_proc -private ad_complaints_count {} { Returns the number of complaints encountered so far. @author Lars Pind @creation-date 25 July 2000 } { global ad_page_contract_complaints return [llength $ad_page_contract_complaints] } ad_proc -private ad_complaints_get_list {} { Returns the list of complaints encountered so far. @author Lars Pind (lars@pinds.com) @creation-date 24 July 2000 } { global ad_page_contract_complaints return $ad_page_contract_complaints } ad_proc -private ad_complaints_parse_error_strings { errorstrings } { Parses the error-strings argument to ad_page_contract and stores the result in global variables, so it can be used by ad_complain. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { global ad_page_contract_error_string array set ad_page_contract_error_string [list] foreach { errorkeys text } $errorstrings { foreach errorkey $errorkeys { set errorkeyv [split $errorkey ":"] if { [llength $errorkeyv] > 2 } { return -code error "Error name '$error' doesn't have the right format. It must be var\[:flag\]" } set name [lindex $errorkeyv 0] set flags [lindex $errorkeyv 1] if { $flags eq "" } { set ad_page_contract_error_string($name) $text } else { foreach flag [split $flags ","] { if { $flag ne "" } { set ad_page_contract_error_string($name:$flag) $text } else { set ad_page_contract_error_string($name) $text } } } } } } #################### # # Validation OK procs # #################### # global: # ad_page_contract_validations_passed(name) 1 the variable was supplied # ad_page_contract_validations_passed(name:flag) 1 the filter returned 1 # ad_proc -private ad_page_contract_set_validation_passed { key } { Call this to signal that a certain validation block has passed successfully. This can be tested later using ad_page_contract_get_validation_passed_p. @param key Is the key, in the format of either formal_name or formal_name:flag_name. @author Lars Pind (lars@pinds.com) @creation-date 24 July 2000 } { global ad_page_contract_validations_passed set ad_page_contract_validations_passed($key) 1 } ad_proc -private ad_page_contract_get_validation_passed_p { key } { Find out whether the named validation block has been passed or not. @param key Is the key, in the format of either formal_name or formal_name:flag_name. @author Lars Pind (lars@pinds.com) @creation-date 24 July 2000 } { global ad_page_contract_validations_passed return [info exists ad_page_contract_validations_passed($key)] } #################### # # Eval helper proc # #################### ad_proc ad_page_contract_eval { args } { This just uplevels it's args. We need this proc, so that the return -code statements get processed correctly inside a catch block. This processing is namely done by the proc invocation. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { uplevel 1 $args } #################### # # ad_page_contract # #################### # global: # ad_page_contract_variables: list of all the variables, required or # optional, specified in the ad_page_contract call error ad_proc -public ad_page_contract { {-form {}} -properties docstring args } { Specifies the contract between programmer and graphic designer for a page. When called with the magic "documentation-gathering" flag set (to be defined), the proc will record the information about this page, so it can be displayed as documentation. When called during normal page execution, it will validate the query string and set corresponding variables in the caller's environment.

    Example:

    ad_page_contract  {
        Some documentation.
        @author me (my@email)
        @cvs-id $Id$
    } {
        foo
        bar:integer,notnull,multiple,trim
        {greble:integer {[expr {[lindex $bar 0] + 1}]}}
    } -validate {
        greble_is_in_range -requires {greble:integer} {
    	if { $greble < 1 || $greble > 100 } {
    	    ad_complain
    	}
        }
        greble_exists -requires { greble_is_in_range } {
            global greble_values
    	if { ![info exists greble_values($greble)] } {
    	    ad_complain "[_ acs-tcl.lt_Theres_no_greble_with]"
    	}
        }
    } -errors {
        foo {error message goes here}
        bar:,integer,notnull {another error message}
        greble_is_in_range {Greble must be between 1 and 100}
    }
    An argspec takes one of two forms, depending on whether there's a default value or not:
    1. {name[:flag,flag,flag] default}
    2. name[:flag,flag,flag]

    If no default value is specified, the argument is considered required, but the empty string is permissible unless you specify :notnull. For all arguments, the filter :nohtml is applied by default. If the arg is named *.tmpfile, the tmpfile filter is applied.

    Possible flags are:

    trim
    The value will be string trimmed.
    notnull
    When set, will barf if the value is the empty string. Checked after processing the trim flag. If not set, the empty string is always considered valid input, and no other filters are processed for that particular value. If it's an array or multiple variable, the filters will still be applied for other values, though.
    optional
    If there's a default value present, it's considered optional even without the flag. If a default is given, and the argument is present but blank, the default value will be used. Optional and no default value means the variable will not be set, if the argument is not present in the query string.
    multiple
    If multiple is specified, the var will be set as a list of all the argument values (e.g. arg=val1&arg=val2 will turn into arg=[list val1 val2]). The defaults are filled in from left to right, so it can depend on values of arguments to its left.
    array
    This syntax maps query variables into Tcl arrays. If you specify customfield:array, then query var customfield.foo will translate into the Tcl array entry $customfield(foo). In other words: whatever comes after the dot is used as the key into the array, or, more mathematically: x.y=z => set x(y) z. If you use dot or comma is part of your key (i.e., y above contains comma or dot), then you can easily split on it in your Tcl code. Remember that you can use any other flag or filter with array.
    verify
    Will invoke ad_verify_signature to verify the value of the variable, to make sure it's the value that was output by us, and haven't been tampered with. If you use export_form_vars -sign or export_url_vars -sign to export the variable, use this flag to verify it. To verify a variable named foo, the verify flag looks for a form variable named foo:sig. For a :multiple, it only expects one single signature for the whole list. For :array it also expects one signature only, taken on the [array get] form of the array.
    cached
    This syntax will check to see if a value is being passed in for this variable. If it is not, it will then look in cache for this variable in the package that this page is located, and get this value if it exists.
    date
    Pluggable filter, installed by default, that makes sure the array validates as a date. Use this filter with :array to do automatic date filtering. To use it, set up in your HTML form a call to \[ad_dateentrywidget varname\]. Then on the receiving page, specify the filter using varname:array,date. If the date validates, there will be a variable set in your environment varname with four keys: day, month, year, and date. You can safely pass $varname(date) to Oracle.
    time
    Pluggable filter, installed by default, that makes sure the array validates as a time in am/pm format. That is that it has two fields: time and ampm that have valid values. Use this filter with :array to do automoatic time filtering. To use it, set up in you HTML form using \[ec_timeentrywidget varname\] or equivalent. Then on the processing page specify the filter using varname:array,time. If the time validates, there will be a variable set in your environment varname with five keys: time, ampm, hours, minutes, and seconds.
    time24
    Pluggable filter, installed by default, that makes sure the array validates as a time in 24hr format. That is that it has one field: time that has valid values. Use this filter with :array to do automoatic time filtering. To use it, set up in you HTML form using <input type=text name=varname.time>. Then on the processing page specify the filter using varname:array,time24. If the time validates, there will be a variable set in your environment varname with four keys: time, hours, minutes, and seconds.
    integer
    Pluggable filter, installed by default, that makes sure the value is integer, and removed any leading zeros.
    naturalnum
    Pluggable filter, installed by default, that makes sure the value is a natural number, i.e. non-decimal numbers >= 0.
    range
    Pluggable filter, installed by default, that makes sure the value X is in range \[Y, Z\]. To use it say something like: foo:(1|100)
    nohtml
    Pluggable filter, installed by default, that disallows any and all html.
    html
    Pluggable filter, installed by default, that only allows certain, safe allowed tags to pass (see ad_html_security_check). The purpose of screening naughty html is to prevent users from uploading HTML with tags that hijack page formatting or execute malicious code on the users's computer.
    allhtml
    Pluggable filter, installed by default, that allows any and all html. Use of this filter is not reccomended, except for cases when the HTML will not be presented to the user or there is some other reason for overriding the site-wide control over naughty html.
    tmpfile
    Checks to see if the path and file specified by tmpfile are allowed on this system.
    sql_identifier
    Pluggable filter, installed by default, that makes sure the value is a valid SQL identifier.
    more filters...

    Note that there can be no spaces between name, colon, flags, commas, etc. The first space encountered denotes the beginning of the default value. Also, variable names can't contain commas, colons or anything Tcl accepts as list element seperators (space, tab, newline, possibly others) If more than one value is specified for something that's not a multiple, a complaint will be thrown ("you supplied more than one value for foo").

    There's an interface for enhancing ad_page_contract with pluggable filters, whose names can be used in place of flags (see ad_page_contract_filter). There's also an interface for pluggable filter rules, which determine what filters are applied to arguments (see ad_page_contract_filter_rule).

    Note on QQ-variables: Unlike the old ad_page_variables, ad_page_contract does not set QQ-versions of variables. The QQ-versions (had each single-quote replaced by two single-quotes) were only necessary for building up SQL statements directly in a Tcl string. Now that we're using bind variables, the QQ-variables aren't necessary anymore, and thus, ad_page_contract doesn't waste time setting them.

    Default Values

    Default values are filled in from left to right (or top to bottom), so it can depend on the values or variables that comes before it, like in the example above. Default values are only used when the argument is not supplied, thus you can't use default values to override the empty string. (This behavior has been questioned and may have to be changed at a later point.) Also, default values are not checked, even if you've specified flags and filters. If the argument has the multiple flag specified, the default value is treated as a list. If the array flag is specified, we expect it to be in array get format, i.e. a list of { name value name value ... } pairs. If both multiple and array are set, the value elements of the before-mentioned array get format are treated as lists themselves.

    Errors Argument

    The -errors block defines custom error messages. The format is a list in array get format with alternating error-names and error texts. The error names can be foo, which means it's thrown when the variable is not supplied. Or foo:flag,flag,..., which means it'll get thrown whenever one of the flags fail. If you want the same error to be thrown for both not supplying a var, and for a flag, you can say foo:,flag,... (a comma immediately after the colon).

    Validation Blocks

    The -validate is used to fully customized user input validation. The format is a list of named chunks of code, for example:
    -validate {
        name {
            code block
        }
        another_name -requires { argname[:filter-or-validation-block-name,...] ... } {
            code block
        }
    }
    The name is for use with the -errors block, and for use within the -requires argument of another validation block. The validation blocks will get executed after all flags and filters have been evaluated. The code chunk should perform some validation, and if it's unhappy it should call ad_complain, optionally with an error message. If no error message is specified, the error should be declared in the -errors section.

    Each validation block can also have a -requires switch, which takes a list of validations that must already have been successfully passed, for the validation to get executed. The intent is that you want to provide as much feedback as possible at once, but you don't want redundant feedback, like "foo must be an integer" and "foo must be in range 10 to 20". So a check for foo in range 10 to 20 would have a -requires { foo:integer } switch, to ensure that the check only gets executed if foo was sucessfully validated as an integer.

    In the -requires argument, you can specify a list of (1) the name of an argument, which means that the argument must be supplied. Or (2) you can specify argname:filter or argname:validation_block to say that a given filter, flag or valdiation block must have been executed and satisfied for this validation block to get executed. You can have as many requirements as you like.

    @param docstring the documentation for your page; will be parsed like ad_proc and ad_library. @param query the query arguments that this page accepts. The query argument takes form of a list of argument specs. See above. @param properties what properties the resulting document will contain. @param form Optionally supply the parameters directly here instead of fetching them from the page's form (ns_getform). This should be a reference to an ns_set. @author Lars Pind (lars@pinds.com) @author Yonatan Feldman (yon@arsdigita.com) @author Bryan Quinn (bquinn@arsdigita.com) @creation-date 16 June 2000 } { ad_complaints_init #################### # # Parse arguments # #################### if { [llength $args] == 0 } { set query [list] } else { set valid_args { validate errors return_errors properties }; # add type later # If the first arg isn't a switch, it should be the query if { [string index [lindex $args 0] 0] != "-" } { set query [lindex $args 0] set args [lrange $args 1 end] } else { # otherwise, accept a -query argument lappend valid_args query set query [list] } ad_arg_parser $valid_args $args } #################### # # Check supplied query form and set up variables in caller's environment # #################### # # These are the steps: # 1. go over the formal args, massaging it into an internal data structure that's easier to manipulate # 2. go over the form (actual args), match actual to formal args, apply filters # 3. go over the formal args again: defaulting, post filters, complain if required but not supplied # 4. execute the validation blocks # #################### #################### # # Step 1: Massage the query arg into some useful data structure. # #################### # BASIC STUFF: # list apc_formals list of formals in the order specified by in the arguments # array apc_formal($name) 1 if there is a formal argument with that name # array apc_default_value($name) the default value, if any # # FILTERS: # array apc_internal_filter($name:$flag): 1 if the given flag is set, undefined # array apc_filters($name): contains a list of the filters to apply # array apc_post_filters($name): contains a list of the post filters to apply # array apc_filter_parameters($name:$flag:): contains a list of the parameters for a filter # # DOCUMENTATION: # array apc_flags($name): contains a list of the flags that apply # set apc_formals [list] array set apc_formal [list] array set apc_default_value [list] array set apc_internal_filter [list] array set apc_filters [list] array set apc_post_filters [list] array set apc_filter_parameters [list] array set apc_flags [list] foreach element $query { set element_len [llength $element] if { $element_len > 2 } { return -code error "[_ acs-tcl.lt_Argspec_element_is_in]" } set arg_spec [lindex $element 0] if { ![regexp {^([^ \t:]+)(?::([a-zA-Z0-9_,(|)]*))?$} $arg_spec match name flags] } { return -code error "Argspec '$arg_spec' doesn't have the right format. It must be var\[:flag\[,flag ...\]\]" } lappend apc_formals $name set apc_formal($name) 1 if { $element_len == 2 } { set apc_default_value($name) [lindex $element 1] } set pre_flag_list [split [string tolower $flags] ,] set flag_list [list] # find parameterized flags foreach flag $pre_flag_list { set left_paren [string first "(" $flag] if { $left_paren == -1 } { lappend flag_list $flag } else { if { [string index $flag end] ne ")" } { return -code error "Missing or misplaced end parenthesis for flag '$flag' on argument '$name'" } set flag_parameters [string range $flag [expr {$left_paren + 1}] [expr {[string length $flag]-2}]] set flag [string range $flag 0 [expr {$left_paren - 1}]] lappend flag_list $flag foreach flag_parameter [split $flag_parameters "|"] { lappend apc_filter_parameters($name:$flag) $flag_parameter } } } # # Apply filter rules # foreach filter_rule [nsv_array names ad_page_contract_filter_rules] { [ad_page_contract_filter_rule_proc $filter_rule] $name flag_list } # # Sort the flag list according to priority # set flag_list_for_sorting [list] foreach flag $flag_list { lappend flag_list_for_sorting [list [ad_page_contract_filter_priority $flag] $flag] } set flag_list_sorted [lsort -index 0 $flag_list_for_sorting] # # Split flag_list up into the different kinds, i.e. internal, filter (classic) or post_filter. # # apc_flags($name) is for documentation only. # set apc_flags($name) [list] set apc_filters($name) [list] set apc_post_filters($name) [list] foreach flag_entry $flag_list_sorted { set flag [lindex $flag_entry 1] lappend apc_flags($name) $flag switch [ad_page_contract_filter_type $flag] { internal { set apc_internal_filter($name:$flag) 1 } filter { lappend apc_filters($name) $flag } post { lappend apc_post_filters($name) $flag } default { return -code error "Unrecognized flag or filter \"$flag\" specified for query argument $name" } } } } #################### # # Documentation-gathering mode # #################### if { [api_page_documentation_mode_p] } { # Just gather documentation for this page ad_parse_documentation_string $docstring doc_elements # copy all the standard elements over foreach element { query properties } { if { [info exists $element] } { set doc_elements($element) [set $element] } } # then the arrays foreach element { apc_default_value apc_flags } { set doc_elements($element) [array get $element] } # then the array names set doc_elements(apc_arg_names) $apc_formals # figure out where the calling script is located, relative to the ACS root set root_dir [nsv_get acs_properties root_directory] set script [info script] set root_length [string length $root_dir] if { ![string compare $root_dir [string range $script 0 [expr { $root_length - 1 }]]] } { set script [string range $script [expr { $root_length + 1 }] end] } error [array get doc_elements] "ad_page_contract documentation" } # # Page serving mode # #################### # # Parse -properties argument # #################### # This must happen even if the query (aka parameters, formals) is empty if { [info exists properties] } { upvar 1 __page_contract_property property array set property [doc_parse_property_string $properties] } # If there are no query arguments to process, we're done if { ![info exists query] || $query eq "" } { return } #################### # # Parse -validate block # #################### # # array apc_validation_blocks($name): an array of lists that contain the validation blocks # the list will contain either 1 or 2 elements, a possible # list of required completed filters/blocks and the code block # for the validation block. Once the block has executed, this entry # self destructs, i.e. unset apc_validation_blocks($name) array set apc_validation_blocks [list] if { ![info exists validate] } { set validate [list] } set validate_len [llength $validate] for { set i 0 } { $i < $validate_len } { incr i } { set name [lindex $validate $i] if { [string first : $name] != -1 } { return -code error "[_ acs-tcl.lt_Validation_block_name]" } if { [info exists apc_formal($name)] } { return -code error "[_ acs-tcl.lt_You_cant_name_your_va]" } if { [info exists apc_validation_blocks($name)] } { return -code error "[_ acs-tcl.lt_You_cant_have_two_val]" } incr i if { [string index [lindex $validate $i] 0] == "-" } { if { [lindex $validate $i] ne "-requires" } { return -code error "[_ acs-tcl.lt_Valid_switches_are_-r]" } set requires [lindex $validate [incr i]] foreach element $requires { if { [string first , $element] != -1 } { return -code error "[_ acs-tcl.lt_The_-requires_element]" } set parts_v [split $element ":"] set parts_c [llength $parts_v] if { $parts_c > 2 } { return -code error "[_ acs-tcl.lt_The_-requires_element_1]" } set req_filter [lindex $parts_v 1] if { $req_filter eq "array" || $req_filter eq "multiple" } { return -code error "You can't require \"$req_name:$req_filter\" for block \"$name\"." } } incr i } else { set requires [list] } set code [lindex $validate $i] set apc_validation_blocks($name) [list $requires $code] } #################### # # Parse -errors argument # #################### if { [info exists errors] } { ad_complaints_parse_error_strings $errors } #################### # # Step 2: Go through all the actual arguments supplied in the form # #################### if { $form eq "" } { set form [ns_getform] } if { $form eq "" } { set form_size 0 } else { set form_size [ns_set size $form] } # This is the array in which we store the signature variables as we come across them # Whenever we see a variable named foo:sig, we record it here as apc_signatures(foo). array set apc_signatures [list] for { set form_counter_i 0 } { $form_counter_i < $form_size } { incr form_counter_i } { # # Map actual argument to formal argument ... only complication is from arrays # # Check the name of the argument to passed in the form, ignore if not valid if { [regexp -nocase -- {^[a-z0-9_\-\.\:]*$} [ns_set key $form $form_counter_i] ] } { set actual_name [ns_set key $form $form_counter_i] # The name of the formal argument in the page set formal_name $actual_name # This will be var(key) for an array set variable_to_set var # This is the value set actual_value [ns_set value $form $form_counter_i] # This is needed for double click protection so we can access the two variables down below. if {$actual_name eq "__submit_button_name" || $actual_name eq "__submit_button_value"} { set $actual_name $actual_value } # It may be a signature for another variable if { [regexp {^(.*):sig$} $actual_name match formal_name] } { set apc_signatures($formal_name) $actual_value # We're done with this variable continue } # If there is no formal with this name, _or_ the formal that has this name is an array, # in which case it can't be the right formal, since we'd have to have a dot and then the key if { ![info exists apc_formal($formal_name)] || [info exists apc_internal_filter($formal_name:array)] } { # loop over all the occurrences of dot in the argument name # and search for a variable spec with that name, e.g. # foo.bar.greble can be interpreted as foo(bar.greble) or foo.bar(greble) set found_p 0 set actual_name_v [split $actual_name "."] set actual_name_c [expr { [llength $actual_name_v] - 1 }] for { set i 0 } { $i < $actual_name_c } { incr i } { set formal_name [join [lrange $actual_name_v 0 $i] "."] if { [info exists apc_internal_filter($formal_name:array)] } { set found_p 1 set variable_to_set var([join [lrange $actual_name_v [expr {$i+1}] end] "."]) break } } if { !$found_p } { # The user supplied a value for which we didn't have any arg_spec # It might be safest to fail completely in this case, but for now, # we just ignore it and go on with the next arg continue } } if { [info exists apc_internal_filter($formal_name:multiple)] && $actual_value eq "" } { # LARS: # If you lappend an emptry_string, it'll actually add the empty string to the list as an element # which is not what we want continue } # Remember that we've found the spec so we don't complain that this argument is missing ad_page_contract_set_validation_passed $formal_name # # Apply filters # if { [info exists apc_internal_filter($formal_name:trim)] } { set actual_value [string trim $actual_value] ad_page_contract_set_validation_passed $formal_name:trim } if { $actual_value eq "" } { if { [info exists apc_internal_filter($formal_name:notnull)] } { ad_complain -key $formal_name:notnull "[_ acs-tcl.lt_You_must_specify_some]" continue } else { ad_page_contract_set_validation_passed $formal_name:notnull } } else { global ad_page_contract_errorkeys ad_page_contract_validations_passed set ad_page_contract_validations_passed($formal_name:notnull) 1 foreach filter $apc_filters($formal_name) { set ad_page_contract_errorkeys [concat $formal_name:$filter $ad_page_contract_errorkeys] if { ![info exists apc_filter_parameters($formal_name:$filter)] } { set filter_ok_p [[ad_page_contract_filter_proc $filter] $formal_name actual_value] } else { set filter_ok_p [[ad_page_contract_filter_proc $filter] $formal_name actual_value \ $apc_filter_parameters($formal_name:$filter)] } set ad_page_contract_errorkeys [lrange $ad_page_contract_errorkeys 1 end] if { $filter_ok_p } { set ad_page_contract_validations_passed($formal_name:$filter) 1 } else { break } } } # # Set the variable in the caller's environment # upvar 1 $formal_name var if { [info exists apc_internal_filter($formal_name:multiple)] } { lappend $variable_to_set $actual_value } else { if { [info exists $variable_to_set] } { ad_complain -key $formal_name:-doublevalue "[_ acs-tcl.lt_Youve_supplied_two_va]" ns_log Warning "User experienced Youve_supplied_two_va when submitting a form related to path_info: [ad_conn path_info]" continue } else { set $variable_to_set $actual_value } } } else { ns_log Error "ad_page_contract: attempt to use a nonstandard variable name in form. [ns_set key $form $form_counter_i] " } } #################### # # Step 3: Pass over each formal argument to make sure all the required # things are there, and setting defaults if they're provided, # apply post filters, and validate signatures. # #################### foreach formal_name $apc_formals { upvar 1 $formal_name var if { [info exists apc_internal_filter($formal_name:cached)] } { if { ![ad_page_contract_get_validation_passed_p $formal_name] && ![info exists apc_internal_filter($formal_name:notnull)] && (![info exists apc_default_value($formal_name)] || $apc_default_value($formal_name) eq "") } { if { [info exists apc_internal_filter($formal_name:array)] } { # This is an array variable, so we need to loop through each name.* variable for this package we have ... set array_list "" foreach arrayvar [ns_cache names util_memoize] { if [regexp [list [ad_conn session_id] [ad_conn package_id] "$formal_name."] $arrayvar] { set arrayvar [lindex $arrayvar [expr {[llength $arrayvar] - 1}]] if { $array_list ne "" } { append array_list " " } set arrayvar_formal [string range $arrayvar [expr {[string first "." $arrayvar] + 1}] [string length $arrayvar]] append array_list "{$arrayvar_formal} {[ad_get_client_property [ad_conn package_id] $arrayvar]}" } } set apc_default_value($formal_name) $array_list } else { set apc_default_value($formal_name) [ad_get_client_property [ad_conn package_id] $formal_name] } } } if { [ad_page_contract_get_validation_passed_p $formal_name] } { if { [info exists apc_internal_filter($formal_name:verify)] } { if { ![info exists apc_internal_filter($formal_name:array)] } { # This is not an array, verify the variable if { ![info exists apc_signatures($formal_name)] || \ ![ad_verify_signature $var $apc_signatures($formal_name)] } { ad_complain -key $formal_name:verify "[_ acs-tcl.lt_The_signature_for_the]" continue } } else { # This is an array: verify the [array get] form of the array if { ![info exists apc_signatures($formal_name)] || \ ![ad_verify_signature [lsort [array get var]] $apc_signatures($formal_name)] } { ad_complain -key $formal_name:verify "[_ acs-tcl.lt_The_signature_for_the]" continue } } } # Apply post filters if { [info exists var] } { foreach filter $apc_post_filters($formal_name) { ad_complaints_with_key $formal_name:$filter { if { ![info exists apc_filter_parameters($formal_name:$filter)] } { set filter_ok_p [[ad_page_contract_filter_proc $filter] $formal_name var] } else { set filter_ok_p [[ad_page_contract_filter_proc $filter] $formal_name var $apc_filter_parameters($formal_name:$filter)] } } if { $filter_ok_p } { ad_page_contract_set_validation_passed $formal_name:$filter } else { break } } } } else { # no value supplied for this arg spec if { [info exists apc_default_value($formal_name)] } { # Only use the default value if there has been no complaints so far # Why? Because if there are complaints, the page isn't going to serve anyway, # and because one default value may depend on another variable having a correct value. if { [ad_complaints_count] == 0 } { # we need to set the default value if { [info exists apc_internal_filter($formal_name:array)] } { array set var [uplevel subst \{$apc_default_value($formal_name)\}] } else { set var [uplevel subst \{$apc_default_value($formal_name)\}] } } } elseif { ![info exists apc_internal_filter($formal_name:optional)] } { ad_complain -key $formal_name "[_ acs-tcl.lt_You_must_supply_a_val]" } } } #################### # # Step 4: Execute validation blocks # #################### set done_p 0 global ad_page_contract_validations_passed ad_page_contract_errorkeys while { !$done_p } { set done_p 1 foreach validation_name [array names apc_validation_blocks] { set dependencies [lindex $apc_validation_blocks($validation_name) 0] set code [lindex $apc_validation_blocks($validation_name) 1] set dependencies_met_p 1 foreach dependency $dependencies { if { ![info exists ad_page_contract_validations_passed($dependency)] } { set dependencies_met_p 0 break } } if { $dependencies_met_p } { # remove from validation blocks array, so we don't execute the same block twice unset apc_validation_blocks($validation_name) set no_complaints_before [ad_complaints_count] # Execute the validation block with an environment with a default error key set set ad_page_contract_errorkeys [concat $validation_name $ad_page_contract_errorkeys] set validation_ok_p [ad_page_contract_eval uplevel 1 $code] set ad_page_contract_errorkeys [lrange $ad_page_contract_errorkeys 1 end] if { $validation_ok_p eq "" || \ ($validation_ok_p ne "1" && $validation_ok_p ne "0" )} { set validation_ok_p [expr {[ad_complaints_count] == $no_complaints_before}] } if { $validation_ok_p } { set ad_page_contract_validations_passed($validation_name) 1 # more stuff to process still set done_p 0 } } } } #################### # # Done. Spit out error, if any # #################### # Initialize the list of page variables for other scripts to use global ad_page_contract_variables set ad_page_contract_variables $apc_formals if { [ad_complaints_count] > 0 } { if { [info exists return_errors] } { upvar 1 $return_errors error_list set error_list [ad_complaints_get_list] } else { template::multirow create complaints text foreach elm [ad_complaints_get_list] { template::multirow append complaints $elm } ns_return 200 text/html [ad_parse_template -params [list complaints] "/packages/acs-tcl/lib/complain"] ad_script_abort } } # Set the __submit_button_variable. This is used in double click protection. if {[exists_and_not_null __submit_button_name] && [info exists __submit_button_value]} { uplevel 1 [list set $__submit_button_name $__submit_button_value] } } ad_proc -public ad_page_contract_get_variables { } { Returns a list of all the formal variables specified in ad_page_contract. If no variables have been specified, returns an empty list. } { global ad_page_contract_variables if { [exists_and_not_null ad_page_contract_variables] } { return $ad_page_contract_variables } return [list] } #################### # # Filter subsystem # #################### # # ad_page_contract_filters($flag) = [list $type $priority $proc_name $doc_string [info script]] # # ad_page_contract_mutex(filters) = mutex # # types are: internal, filter, post # if { [apm_first_time_loading_p] } { nsv_array set ad_page_contract_filters { multiple {internal} array {internal} optional {internal} trim {internal} notnull {internal} verify {internal} cached {internal} } nsv_array set ad_page_contract_filter_rules [list] nsv_set ad_page_contract_mutex filters [ns_mutex create] nsv_set ad_page_contract_mutex filter_rules [ns_mutex create] } ad_proc -public ad_page_contract_filter { {-type filter} {-priority 1000} name proc_args doc_string body } { Declare a filter to be available for use in ad_page_contract.

    Here's an example of how to declare a filter:

        ad_page_contract_filter integer { name value } {
    	Checks whether the value is a valid integer, and removes any leading zeros so as 
    	not to confuse Tcl into thinking it's octal
        } {
    	if { ![regexp {^[0-9]+$} $value] } {
    	    ad_complain "[_ acs-tcl.lt_Value_is_not_an_integ]"
    	    return 0
    	}
    	# trim leading zeros, so as not to confuse Tcl
    	set value [string trimleft $value "0"]
    	if { $value eq "" } {
    	    # but not all of the zeros
    	    set value "0"
    	}
    	return 1
        }
        
    After the filter has been declared, it can be used as a flag in ad_page_contract, e.g.
        ad_page_contract {
    	foo:integer
        } {}
        
    Note that there's only one global namespace for names. At some point, we might add package-local filters, but we don't have it yet.

    The filter proc must return either 1 if it accepts the value or 0 if it rejects it. Any problem with the value is reported using ad_complain (see documentation for this). Note: Any modifications you make to value from inside your code block will modify the actual value being set in the page.

    There are two types of filters. They differ in scope for variables that are multiple or array. The standard type of filter (filter classic) is invoked on each individual value before it's being put into the list or the array. A post filter is invoked after all values have been collected, and is invoked on the list or array as a whole.

    @param type The type of filter; i.e. filter or post. Default is filter. @param name The name of the flag as used in ad_page_contract @param proc_args the arguments to your filter. The filter must take three arguments, name, value, and parameters, although you can name them any way you want. The first will be set to the name of the variable, the second will be upvar'd to the value, so that any change you make to the value will be reflected in the value ultimately being set in the page's environment, and the third is a list of arguments to the filter. This third argument can have multiple parameters split by | with no spaces or any other characters. Something like foo:range(3|5) @param body The body is a procedure body that performs the filtering. It'll automatically have one argument named value set, and it must either return the possibly transformed value, or throw an error. The error message will be displayed to the user. @param doc_string Standard documentation-string. Tell other programmers what your filter does. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { ![string is wordchar $name] || $name eq "" } { return -code error "[_ acs-tcl.lt_Flag_name_must_be_a_v]" } if { [string tolower $name] ne $name } { return -code error "[_ acs-tcl.lt_Flag_names_must_be_al]" } if { ![string match $type filter] && ![string match $type post] } { return -code error "[_ acs-tcl.lt_Filter_type_must_be_f]" } set proc_args_len [llength $proc_args] if { $proc_args_len != 2 && $proc_args_len != 3 } { return -code error "[_ acs-tcl.lt_Invalid_number_of_arg]" } set script [info script] set proc_name ad_page_contract_filter_proc_$name # # Register the filter # set mutex [nsv_get ad_page_contract_mutex filters] ns_mutex lock $mutex set prior_type [ad_page_contract_filter_type $name] if {$prior_type eq "internal"} { ns_mutex unlock $mutex return -code error "[_ acs-tcl.lt_The_flag_name_name_is]" } elseif { $prior_type ne "" } { set prior_script [ad_page_contract_filter_script $name] if { $prior_script ne $script } { ns_log Warning "[_ acs-tcl.lt_Multiple_definitions_]" } } nsv_set ad_page_contract_filters $name [list $type $proc_name $doc_string $script $priority] ns_mutex unlock $mutex # # Declare the proc # # this may look complicated, but it's really pretty simple: # If you declare a filter like this: ad_page_contract_filter foo { name value } { ... } # it turns into this proc: # ad_proc ad_page_contract_filter_proc_foo { name value_varname } { upvar $value_varname value ; ... } # so that when the filtger proc is passed the name of a variable, the body of the proc # will have access to that variable as if the value had been passed. set arg0 [lindex $proc_args 0] set arg1 [lindex $proc_args 1] if { $proc_args_len == 2 } { ad_proc -public $proc_name [list $arg0 ${arg1}_varname] $doc_string "upvar \$${arg1}_varname $arg1\n$body" } else { set arg2 [lindex $proc_args 2] ad_proc -public $proc_name [list $arg0 ${arg1}_varname $arg2] $doc_string "upvar \$${arg1}_varname $arg1\n$body" } } ad_proc ad_page_contract_filter_type { filter } { Returns the type of proc that executes the given ad_page_contract filter, or the empty string if the filter is not defined. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { [nsv_exists ad_page_contract_filters $filter] } { return [lindex [nsv_get ad_page_contract_filters $filter] 0] } else { return {} } } ad_proc ad_page_contract_filter_proc { filter } { Returns the proc that executes the given ad_page_contract filter. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { return [lindex [nsv_get ad_page_contract_filters $filter] 1] } ad_proc ad_page_contract_filter_script { filter } { Returns the type of proc that executes the given ad_page_contract filter, or the empty string if the filter is not defined. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { return [lindex [nsv_get ad_page_contract_filters $filter] 3] } ad_proc ad_page_contract_filter_priority { filter } { Returns the type of proc that executes the given ad_page_contract filter, or the empty string if the filter is not defined. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { return [lindex [nsv_get ad_page_contract_filters $filter] 4] } ad_proc ad_page_contract_filter_invoke { filter name value_varname {parameters ""} } { Invokes a filter on the argument and returns the result (1 or 0). The value may be modified during the invocation of the filter. @param filter the name of the filter to invoke @param name the logical name of the variable to filter @param value_varname the name of the variable holding the value to be filtered. @param parameters any arguments to pass to the filter @author Lars Pind (lars@pinds.com) @author Yonatan Feldman (yon@arsdigita.com) @creation-date 25 July 2000 } { upvar $value_varname value if { $parameters eq "" } { set filter_result [[ad_page_contract_filter_proc $filter] $name value] } else { set filter_result [[ad_page_contract_filter_proc $filter] $name value $parameters] } if { $filter_result } { ad_page_contract_set_validation_passed $name:$filter } return $filter_result } #################### # # Filter rules # #################### # # ad_page_contract_filter_rules($name) = [list $proc_name $doc_string [info script]] # # ad_page_contract_mutex(filter_rules) = mutex # ad_proc ad_page_contract_filter_rule { name proc_args doc_string body } { A filter rule determines what filters are applied to a given value. The code is passed the name of the formal argument and the list of filters currently being applied, and should on that basis modify the list of filters to suit its needs. Usually a filter rule will add a certain filter, unless some list of filters are already present.

    Unlike the filters themselves (registered with ad_page_contract_filter, all rules are always applied to all formal arguments of all pages. @param name filter rules must be named. The name isn't referred to anywhere. @param proc_args the filter rule proc must take two arguments, name and filters, although you can name them as you like. The first will be set to the name of the formal argument, the second will be upvar'd to the list of filters, so that any modifications you make to this list are reflected in the actual list of filters being applied. @param doc_string let other programmers know what your filter rule does. @param body the code to manipulate the filter list. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { [llength $proc_args] != 2 } { return -code error "[_ acs-tcl.lt_The_proc_must_accept_]" } set script [info script] set proc_name ad_page_contract_filter_rule_proc_$name set mutex [nsv_get ad_page_contract_mutex filter_rules] ns_mutex lock $mutex if { [nsv_exists ad_page_contract_filter_rules $name] } { set prior_script [ad_page_contract_filter_rule_script $name] if { $script ne $prior_script } { ns_log Warning "Multiple definitions of the ad_page_contract_filter_rule \"$name\" in $script and $prior_script" } } nsv_set ad_page_contract_filter_rules $name [list $proc_name $doc_string $script] ns_mutex unlock $mutex # same trick as ad_page_contract_filter does. set arg0 [lindex $proc_args 0] set arg1 [lindex $proc_args 1] ad_proc $proc_name [list $arg0 ${arg1}_varname] $doc_string "upvar \$${arg1}_varname $arg1\n$body" } ad_proc ad_page_contract_filter_rule_proc { filter } { Returns the proc that executes the given ad_page_contract default-filter. } { return [lindex [nsv_get ad_page_contract_filter_rules $filter] 0] } ad_proc ad_page_contract_filter_rule_script { filter } { Returns the proc that executes the given ad_page_contract default-filter. } { return [lindex [nsv_get ad_page_contract_filter_rules $filter] 2] } #################### # # Declare standard filters # #################### ad_page_contract_filter integer { name value } { Checks whether the value is a valid integer, and removes any leading zeros so as not to confuse Tcl into thinking it's octal. Allows negative numbers. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { # first simple a quick check avoiding the slow regexp if {[string is integer $value]} { return 1 } if { [regexp {^(-)?(0*)([1-9][0-9]*|0)$} $value match sign zeros value] } { # Trim the value for any leading zeros set value $sign$value # the string might be still to large, so check again... if {[string is integer $value]} { return 1 } } ad_complain "[_ acs-tcl.lt_name_is_not_an_intege]" return 0 } ad_page_contract_filter naturalnum { name value } { Checks whether the value is a valid integer >= 0, and removes any leading zeros so as not to confuse Tcl into thinking it's octal. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { [regexp {^(0*)([1-9][0-9]*|0)$} $value match zeros value] } { if {[string is integer $value]} { return 1 } } ad_complain "[_ acs-tcl.lt_name_is_not_a_natural]" return 0 } ad_page_contract_filter range { name value range } { Checks whether the value falls between the specified range. Range must be a list of two elements: min and max. @author Yonatan Feldman (yon@arsdigita.com) @creation-date August 18, 2000 } { if { [llength $range] != 2 } { error "[_ acs-tcl.lt_Invalid_number_of_par]" ad_script_abort } set min [lindex $range 0] set max [lindex $range 1] if { $value < $min || $value > $max } { ad_complain "[_ acs-tcl.lt_name_is_not_in_the_ra]" return 0 } return 1 } ad_page_contract_filter sql_identifier { name value } { Checks whether the value is a valid SQL identifier @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { ![string is wordchar $value] } { ad_complain "[_ acs-tcl.lt_name_is_not_a_valid_S]" return 0 } return 1 } ad_page_contract_filter allhtml { name value } { Allows any html tags (a no-op filter) @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { return 1 } ad_page_contract_filter nohtml { name value } { Doesn't allow any HTML to pass through. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { [string first < $value] >= 0 } { ad_complain "[_ acs-tcl.lt_Value_for_name_contai]" return 0 } return 1 } ad_page_contract_filter html { name value } { Checks whether the value contains naughty HTML @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { set naughty_prompt [ad_html_security_check $value] if { $naughty_prompt ne "" } { ad_complain $naughty_prompt return 0 } return 1 } ad_page_contract_filter tmpfile { name value } { Checks to see that the tmpfile path is allowed on the system @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { # ensure no .. in the path ns_normalizepath $value # check to make sure path is to an authorized directory set tmpdir_list [ad_parameter_all_values_as_list -package_id [ad_conn subsite_id] TmpDir] if { $tmpdir_list eq "" } { set tmpdir_list [list "/var/tmp" "/tmp"] } foreach tmpdir $tmpdir_list { if { [string match "$tmpdir*" $value] } { return 1 } } # Log details about this filter failing, to make it easier to debug. ns_log Notice "ad_page_contract tmpfile filter on variable '$name' at URL '[ad_conn url]': The tmpfile given was '$value', and the list of valid directories is '$tmpdir_list'." ad_complain "[_ acs-tcl.lt_You_specified_a_path_]" return 0 } ad_page_contract_filter -type post date { name date } { Validates date type variables @author Yonatan Feldman (yon@arsdigita.com) @creation-date 25 July 2000 } { foreach date_element { day month year } { if { ![info exists date($date_element)] } { ad_complain "[_ acs-tcl.lt_Invalid_date_date_ele]" return 0 } } # check if all elements are blank if { [empty_string_p "$date(day)$date(month)$date(year)"] } { set date(date) {} return 1 } foreach date_element { day year } { if { ![regexp {^(0*)(([1-9][0-9]*|0))$} $date($date_element) match zeros real_value] } { ad_complain "[_ acs-tcl.lt_Invalid_date_date_ele_1]" return 0 } set date($date_element) $real_value } if { $date(year) ne "" && [string length $date(year)] != 4 } { ad_complain "[_ acs-tcl.lt_Invalid_date_The_year]" return 0 } if { [regexp {^(0*)(([1-9][0-9]*|0))$} $date(month) match zeros real_value] } { set date(month) $real_value } else { set months_list {January February March April May June July August September October November December} set date(month) [expr {[lsearch $months_list $date(month)] + 1}] } if { "" eq $date(month) \ || "" eq $date(day) \ || "" eq $date(year) \ || $date(month) < 1 || $date(month) > 12 \ || $date(day) < 1 || $date(day) > 31 \ || $date(year) < 1 \ || ($date(month) == 2 && $date(day) > 29) \ || (($date(year) % 4) != 0 && $date(month) == 2 && $date(day) > 28) \ || ($date(month) == 4 && $date(day) > 30) \ || ($date(month) == 6 && $date(day) > 30) \ || ($date(month) == 9 && $date(day) > 30) \ || ($date(month) == 11 && $date(day) > 30) } { ad_complain "[_ acs-tcl.lt_Invalid_date_datemont]" return 0 } set date(date) [format "%04d-%02d-%02d" $date(year) $date(month) $date(day)] return 1 } ad_page_contract_filter -type post time { name time } { Validates time type variables of the regular variety (that is 8:12:21 PM) @author Yonatan Feldman (yon@arsdigita.com) @creation-date 25 July 2000 } { foreach time_element { time ampm } { if { ![info exists time($time_element)] } { ad_complain "[_ acs-tcl.lt_Invalid_time_time_ele]" return 0 } } # check if all elements are blank if { [empty_string_p "$time(time)$time(ampm)"] } { return 1 } set time_element_values [split $time(time) ":"] if { [llength $time_element_values] != 3 } { ad_complain "[_ acs-tcl.lt_Invalid_time_timetime]" return 0 } set time_element_names [list hours minutes seconds] for { set i 0 } { $i < 3 } { incr i } { array set time [list [lindex $time_element_names $i] [lindex $time_element_values $i]] } if { "" eq $time(hours) \ || "" eq $time(minutes) \ || "" eq $time(seconds) \ || (![string equal -nocase "pm" $time(ampm)] && ![string equal -nocase "am" $time(ampm)]) || $time(hours) < 1 || $time(hours) > 12 \ || $time(minutes) < 0 || $time(minutes) > 59 \ || $time(seconds) < 0 || $time(seconds) > 59 } { ad_complain "[_ acs-tcl.lt_Invalid_time_timetime_1]" return 0 } return 1 } ad_page_contract_filter -type post time24 { name time } { Validates time type variables of the 24HR variety (that is 20:12:21) @author Yonatan Feldman (yon@arsdigita.com) @creation-date 25 July 2000 } { if { ![info exists time(time)] } { ad_complain "[_ acs-tcl.lt_Invalid_time_time_is_]" return 0 } # check if all elements are blank if { [empty_string_p "$time(time)"] } { return 1 } set time_element_values [split $time(time) ":"] if { [llength $time_element_values] != 3 } { ad_complain "[_ acs-tcl.lt_Invalid_time_timetime]" return 0 } set time_element_names [list hours minutes seconds] for { set i 0 } { $i < 3 } { incr i } { array set time [list [lindex $time_element_names $i] [lindex $time_element_values $i]] } if { "" eq $time(hours) \ || "" eq $time(minutes) \ || "" eq $time(seconds) \ || $time(hours) < 0 || $time(hours) > 23 \ || $time(minutes) < 0 || $time(minutes) > 59 \ || $time(seconds) < 0 || $time(seconds) > 59 } { ad_complain "[_ acs-tcl.lt_Invalid_time_timetime_2]" return 0 } return 1 } ad_page_contract_filter string_length_range { name value range} { Checks whether the string is within the specified range, inclusive @author Randy Beggs (randyb@arsdigita.com) @creation-date August 2000 } { if { [string length $value] < [lindex $range 0] } { ad_complain "[_ acs-tcl.lt_name_is_too_short__Pl]" return 0 } elseif { [string length $value] > [lindex $range 1] } { ad_complain "[_ acs-tcl.lt_name_is_too_long__Ple]" return 0 } return 1 } ad_page_contract_filter string_length { name value length } { Checks whether the string is less or greater than the minimum or maximum length specified, inclusive e.g.address_1:notnull,string_length(max|100) will test address_1 for maximum length of 100. @author Randy Beggs (randyb@arsdigita.com) @creation-date August 2000 } { if { [lindex $length 0] eq "min" } { if { [string length $value] < [lindex $length 1] } { ad_complain "[_ acs-tcl.lt_name_is_too_short__Pl_1]" return 0 } } else { if { [string length $value] > [lindex $length 1] } { ad_complain "[_ acs-tcl.lt_name_is_too_long__Ple_1]" return 0 } } return 1 } ad_page_contract_filter email { name value } { Checks whether the value is a valid email address (stolen from philg_email_valid_p) @author Philip Greenspun (philip@mit.edu) @author Randy Beggs (randyb@arsdigita.com) @creation-date 22 August 20000 } { set valid_p [regexp "^\[^@\t ]+@\[^@.\t]+(\\.\[^@.\n ]+)+$" $value] if { !$valid_p } { ad_complain "[_ acs-tcl.lt_name_does_not_appear_]" return 0 } return 1 } ad_page_contract_filter float { name value } { Checks to make sure that the value in question is a valid number, possibly with a decimal point - randyb took this from the ACS dev bboard @author Steven Pulito (stevenp@seas.upenn.edu) @creation-date 22 August 2000 } { # Check if the first character is a "+" or "-" set signum "" if {[regexp {^([\+\-])(.*)} $value match signum rest]} { set value $rest } # remove the first decimal point, the theory being that # at this point a valid float will pass an integer test regsub {\.} $value "" value_to_be_tested if { ![regexp {^[0-9]+$} $value_to_be_tested] } { ad_complain "[_ acs-tcl.lt_Value_is_not_an_decim]" return 0 } # trim leading zeros, so as not to confuse Tcl set value [string trimleft $value "0"] if { $value eq "" } { # but not all of the zeros set value "0" } # finally add the signum character again set value "$signum$value" return 1 } ad_page_contract_filter negative_float { name value } { Same as float but allows negative numbers too @author Brian Fenton @creation-date 1 December 2004 } { # remove the first decimal point, the theory being that # at this point a valid float will pass an integer test regsub {\.} $value "" value2 # remove the first minus sign, the theory being that # at this point a valid float will pass an integer test regsub {\-} $value2 "" value_to_be_tested if { ![regexp {^[0-9]+$} $value_to_be_tested] } { ad_complain "Value is not an decimal number." return 0 } # trim leading zeros, so as not to confuse Tcl set value [string trimleft $value "0"] if { $value eq "" } { # but not all of the zeros set value "0" } return 1 } ad_page_contract_filter phone { name value } { Checks whether the value is more or less a valid phone number with the area code. Specifically, area code excluding leading "1", optionally enclosed in parentheses; followed by phone number in the format xxx xxx xxxx (either spaces, periods or dashes separating the number). This filter matches the beginning of the value being checked, and considers any user input following the match as valid (to allow for extensions, etc.). Add a $ at the end of the regexp to disallow extensions. Examples:

    • (800) 888-8888 will pass
    • 800-888-8888 will pass
    • 800.888.8888 will pass
    • 8008888888 will pass
    • (800) 888-8888 extension 405 will pass
    • (800) 888-8888abcd will pass
    • "" (the empty string) will pass
    • 1-800-888-8888 will fail
    • 10-10-220 800.888.8888 will fail
    • abcd(800) 888-8888 will fail
    @author Randy Beggs (randyb@arsdigita.com) @creation-date August 2000 } { if { ![empty_string_p [string trim $value]] } { if { ![regexp {^\(?([1-9][0-9]{2})\)?(-|\.|\ )?([0-9]{3})(-|\.|\ )?([0-9]{4})} $value] } { ad_complain "[_ acs-tcl.lt_value_does_not_appear]" return 0 } } return 1 } ad_page_contract_filter usphone { name value } { Checks whether the value is more or less a valid US phone number with the area code. Exact filter is XXX-XXX-XXXX @author Randy Beggs (randyb@arsdigita.com) @creation-date 22 August 2000 } { if {![empty_string_p [string trim $value]] && ![regexp {[1-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]} $value]} { ad_complain "[_ acs-tcl.lt_name_does_not_appear__1]" return 0 } return 1 } ad_page_contract_filter boolean { name value } { Checks whether the value is boolean (1 or 0) or predicate (t or f) or otherwise a 2 state value (true or false, y or n, yes or no) @author Randy Beggs (randyb@arsdigita.com) @creation-date 23 August 2000 } { set lcase_value [string tolower $value] if {[string match $value "0"] || \ [string match $value "1"] || \ [string match $lcase_value "f"] || \ [string match $lcase_value "t"] || \ [string match $lcase_value "true"] || \ [string match $lcase_value "false"] || \ [string match $lcase_value "y"] || \ [string match $lcase_value "n"] || \ [string match $lcase_value "yes"] || \ [string match $lcase_value "no"] } { return 1 } else { ad_complain "[_ acs-tcl.lt_name_does_not_appear__2]" return 0 } } #################### # # Standard filter rules # #################### ad_page_contract_filter_rule html { name filters } { Makes sure the filter nohtml gets applied, unless some other html filter (html or allhtml) is already specified. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { foreach flag $filters { if { [lsearch { nohtml html allhtml integer naturalnum } $flag] != -1 } { return } } lappend filters nohtml } ad_page_contract_filter_rule tmpfile { name filters } { Makes sure the tmpfile filter gets applied for all vars named *.tmpfile. @author Lars Pind (lars@pinds.com) @creation-date 25 July 2000 } { if { [string match "*tmpfile" $name] && [lsearch -exact $filters tmpfile] == -1 } { lappend filters tmpfile } } #################### # # Templating system things # #################### ad_proc ad_page_contract_verify_datasources {} { Check if all the datasources (properties) promised in the page contract have actually been set. @author Chrisitan Brechbuehler @creation-date 13 Aug 2000 } { # for now this is a dummy proc. # todo: check if all datasources are defined based on property declarations return 1; # ok } ad_proc ad_page_contract_handle_datasource_error {error} { Output a diagnostic page. Treats both special and generic error messages. @author Chrisitan Brechbuehler @creation-date 13 Aug 2000 } { # copied from defs-procs.tcl: ad_return_complaint doc_return 200 text/html "[ad_header_with_extra_stuff \ "[_ acs-tcl.lt_Problem_with_a_Templa]" "" ""]

    [_ acs-tcl.lt_Problem_with_a_Page_o]


    [_ acs-tcl.lt_We_had_a_problem_proc]
    • $error

    [_ acs-tcl.Sorry] [ad_footer] " } openacs-5.7.0/packages/acs-tcl/tcl/defs-procs-postgresql.xql0000644000175000017500000000070610540362770023664 0ustar frankiefrankie postgresql7.1 insert into query_strings (query_date, query_string, subsection, n_results, user_id) values (now(), :query_string, :subsection, :n_results, :user_id) openacs-5.7.0/packages/acs-tcl/tcl/application-link-procs-oracle.xql0000644000175000017500000000173410247265704025250 0ustar frankiefrankie oracle8.0 begin :1 = acs_rel.new ( rel_id => null, rel_type => 'application_link', object_id_one => :this_package_id, object_id_two => :target_package_id, context_id => :this_package_id, creation_user => :user_id, creation_ip => :id_addr ); end; begin :1 = acs_rel.new ( rel_id => null, rel_type => 'application_link', object_id_one => :target_package_id, object_id_two => :this_package_id, context_id => :this_package_id, creation_user => :user_id, creation_ip => :id_addr ); end; openacs-5.7.0/packages/acs-tcl/tcl/defs-procs.tcl0000644000175000017500000006402111352533030021430 0ustar frankiefrankiead_library { ACS-specific general utility routines. @author Philip Greenspun (philg@arsdigita.com) @author Many others at ArsDigita and in the OpenACS community. @creation-date 2 April 1998 @cvs-id $Id: defs-procs.tcl,v 1.60 2010/03/25 01:02:16 donb Exp $ } ad_proc -public ad_acs_version_no_cache {} { The OpenACS version of this instance. Uses the version name of the acs-kernel package. @author Peter Marklund } { apm_version_get -package_key acs-kernel -array kernel return $kernel(version_name) } ad_proc -public ad_acs_version {} { The OpenACS version of this instance. Uses the version name of the acs-kernel package. @author Peter Marklund } { return [util_memoize ad_acs_version_no_cache] } ad_proc -public ad_acs_release_date {} { The OpenACS release date of this instance. Uses the release date of the acs-kernel package. @author Peter Marklund } { apm_version_get -package_key acs-kernel -array kernel return $kernel(release_date) } ad_proc -public ad_host_administrator {} { As defined in the HostAdministrator kernel parameter. @return The e-mail address of a technical person who can fix problems } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter HostAdministrator] } ad_proc -public ad_outgoing_sender {} { @return The email address that will sign outgoing alerts } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter OutgoingSender] } ad_proc -public ad_system_name {} { This is the main name of the Web service that you're offering on top of the OpenACS Web Publishing System. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter SystemName] } ad_proc -public ad_pvt_home {} { This is the URL of a user's private workspace on the system, usually [subsite]/pvt/home.tcl } { return "[subsite::get_element -element url -notrailing][parameter::get -package_id [ad_acs_kernel_id] -parameter HomeURL]" } ad_proc -public ad_admin_home {} { Returns the directory for the admin home. } { return "[subsite::get_element -element url]admin" } # is this accurate? (rbm, aug 2002) ad_proc -public ad_package_admin_home { package_key } { @return directory for the especified package's admin home. } { return "[ad_admin_home]/$package_key" } ad_proc -public ad_pvt_home_name {} { This is the name that will be used for the user's workspace (usually "Your Workspace"). @return the name especified for the user's workspace in the HomeName kernel parameter. } { return [lang::util::localize [parameter::get -package_id [ad_acs_kernel_id] -parameter HomeName]] } ad_proc -public ad_pvt_home_link {} { @return the html fragment for the /pvt link } { return "[ad_pvt_home_name]" } ad_proc -public ad_site_home_link {} { @return a link to the user's workspace if the user is logged in. Otherwise, a link to the page root. } { if { [ad_get_user_id] != 0 } { return "[subsite::get_element -element name]" } else { # we don't know who this person is return "[subsite::get_element -element name]" } } ad_proc -public ad_system_owner {} { Person who owns the service this person would be interested in user feedback, etc. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter SystemOwner] } ad_proc -public ad_publisher_name {} { A human-readable name of the publisher, suitable for legal blather. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter PublisherName] } ad_proc -public ad_url {} { This will be called by email alerts. Do not use ad_conn location @return the system url as defined in the kernel parameter SystemURL. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter SystemURL] } ad_proc -public acs_community_member_page {} { @return the url for the community member page } { return "[subsite::get_element -element url -notrailing][parameter::get \ -package_id [ad_acs_kernel_id] -parameter CommunityMemberURL]" } ad_proc -public acs_community_member_url { {-user_id:required} } { @return the url for the community member page of a particular user } { return "[acs_community_member_page]?[export_vars user_id]" } ad_proc -public acs_community_member_link { {-user_id:required} {-label ""} } { @return the link of the community member page of a particular user @see acs_community_member_url } { if {$label eq ""} { acs_user::get -user_id $user_id -array user set label "$user(first_names) $user(last_name)" } return "$label" } ad_proc -deprecated ad_present_user { user_id name } { This function is an alias to acs_community_member_link and receives identical parameters, but the former finds out the name of the user if a blank is passed. That's why it's marked as deprecated. @return the HTML link of the community member page of a particular user @author Unknown @author Roberto Mello @see acs_community_member_link } { return [acs_community_member_link -user_id $user_id -label $name] } ad_proc -public acs_community_member_admin_url { {-user_id:required} } { @return the url for the community member admin page of a particular user } { return [export_vars -base [parameter::get -package_id [ad_acs_kernel_id] -parameter CommunityMemberAdminURL] { user_id }] } ad_proc -public acs_community_member_admin_link { {-user_id:required} {-label ""} } { @return the HTML link of the community member page of a particular admin user. } { if {$label eq ""} { set label [db_string select_community_member_link_label { select persons.first_names || ' ' || persons.last_name from persons where person_id = :user_id } -default $user_id] } return "$label" } ad_proc -deprecated ad_admin_present_user { user_id name } { This function is an alias to acs_community_member_admin_link and receives identical parameters, but the former finds out the name of the user if a blank is passed. That's why it's marked as deprecated. @return the HTML link of the community member page of a particular admin user. @author Unknown @author Roberto Mello @see acs_community_member_admin_link } { return [acs_community_member_admin_link -user_id $user_id -label $name] } ad_proc -deprecated ad_header { {-focus ""} page_title {extra_stuff_for_document_head ""} } { writes HEAD, TITLE, and BODY tags to start off pages in a consistent fashion @see Documentation on the site master template for the proper way to standardize page headers } { # if {[ad_parameter MenuOnUserPagesP pdm] == 1} { # return [ad_header_with_extra_stuff -focus $focus $page_title [ad_pdm] [ad_pdm_spacer]] # } else { # } return [ad_header_with_extra_stuff -focus $focus $page_title $extra_stuff_for_document_head] } ad_proc -deprecated ad_header_with_extra_stuff { {-focus ""} page_title {extra_stuff_for_document_head ""} {pre_content_html ""} } { This is the version of the ad_header that accepts extra stuff for the document head and pre-page content html @see Documentation on the site master template for the proper way to standardize page headers } { set html " $extra_stuff_for_document_head $page_title " array set attrs [list] set attrs(bgcolor) [parameter::get -package_id [ad_acs_kernel_id] -parameter bgcolor -default "white"] set attrs(text) [parameter::get -package_id [ad_acs_kernel_id] -parameter textcolor -default "black"] if { $focus ne "" } { set attrs(onLoad) "javascript:document.${focus}.focus()" } foreach attr [array names attrs] { lappend attr_list "$attr=\"$attrs($attr)\"" } append html "\n" append html $pre_content_html return $html } ad_proc -deprecated ad_footer { {signatory ""} {suppress_curriculum_bar_p 0} } { Writes a horizontal rule, a mailto address box (ad_system_owner if not specified as an argument), and then closes the BODY and HTML tags @see Documentation on the site master template for the proper way to standardize page footers } { global sidegraphic_displayed_p if { $signatory eq "" } { set signatory [ad_system_owner] } if { [info exists sidegraphic_displayed_p] && $sidegraphic_displayed_p } { # we put in a BR CLEAR=RIGHT so that the signature will clear any side graphic # from the ad-sidegraphic.tcl package set extra_br "
    " } else { set extra_br "" } if { [parameter::get -package_id [ad_acs_kernel_id] -parameter EnabledP -default 0] && [parameter::get -package_id [ad_acs_kernel_id] -parameter StickInFooterP -default 0] && !$suppress_curriculum_bar_p} { set curriculum_bar "

    [curriculum_bar]
    " } else { set curriculum_bar "" } if { [llength [info procs ds_link]] == 1 } { set ds_link [ds_link] } else { set ds_link "" } return " $extra_br $curriculum_bar
    $ds_link
    $signatory
    " } # need special headers and footers for admin pages # notably, we want pages signed by someone different # (the user-visible pages are probably signed by # webmaster@yourdomain.com; the admin pages are probably # used by this person or persons. If they don't like # the way a page works, they should see a link to the # email address of the programmer who can fix the page). ad_proc -public ad_admin_owner {} { @return E-mail address of the Administrator of this site. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter AdminOwner] } ad_proc -deprecated ad_admin_header { {-focus ""} page_title } { @see Documentation on the site master template for the proper way to standardize page headers } { # if {[ad_parameter -package_id [ad_acs_kernel_id] MenuOnAdminPagesP pdm] == 1} { # return [ad_header_with_extra_stuff -focus $focus $page_title [ad_pdm "admin" 5 5] [ad_pdm_spacer "admin"]] # } else {} return [ad_header_with_extra_stuff -focus $focus $page_title] } ad_proc -deprecated ad_admin_footer {} { Signs pages with ad_admin_owner (usually a programmer who can fix bugs) rather than the signatory of the user pages @see Documentation on the site master template for the proper way to standardize page footers } { if { [llength [info procs ds_link]] == 1 } { set ds_link [ds_link] } else { set ds_link "" } return "
    $ds_link
    [ad_admin_owner]
    " } ad_proc -public ad_return_string_as_file { -string -filename -mime_type } { Return a string as the content of a file @param string Content of the file to be sent back @param filename Name of the file to be returned @param mime_type Mime Type of the file being returned } { ns_set put [ns_conn outputheaders] "Content-Disposition" "attachment; filename=\"$filename\"" ReturnHeaders "$mime_type" ns_write $string } ad_proc -public ad_return_complaint { exception_count exception_text } { Return a page complaining about the user's input (as opposed to an error in our software, for which ad_return_error is more appropriate) @param exception_count Number of exceptions. Used to say either 'a problem' or 'some problems'. @param exception_text HTML chunk to go inside an UL tag with the error messages. } { set complaint_template [parameter::get_from_package_key -package_key "acs-tcl" -parameter "ReturnComplaint" -default "/packages/acs-tcl/lib/ad-return-complaint"] ns_return 200 text/html [ad_parse_template \ -params [list [list exception_count $exception_count] \ [list exception_text $exception_text]] \ $complaint_template] # raise abortion flag, e.g., for templating global request_aborted set request_aborted [list 200 "Problem with Your Input"] } ad_proc ad_return_exception_page { status title explanation } { Returns an exception page. @author Unknown @param status HTTP status to be returned (e.g. 500, 404) @param title Title to be used for the error (will be shown to user) @param explanation Explanation for the exception. } { set error_template [parameter::get_from_package_key -package_key "acs-tcl" -parameter "ReturnError" -default "/packages/acs-tcl/lib/ad-return-error"] set page [ad_parse_template -params [list [list title $title] [list explanation $explanation]] $error_template] if {$status > 399 && [string match {*; MSIE *} [ns_set iget [ad_conn headers] User-Agent]] && [string length $page] < 512 } { append page [string repeat " " [expr 513 - [string length $page]]] } ns_return $status text/html $page # raise abortion flag, e.g., for templating global request_aborted set request_aborted [list $status $title] } ad_proc ad_return_error { title explanation } { Returns a page with the HTTP 500 (Error) code, along with the given title and explanation. Should be used when an unexpected error is detected while processing a page. } { ad_return_exception_page 500 $title $explanation } ad_proc ad_return_warning { title explanation } { Returns a page with the HTTP 200 (Success) code, along with the given title and explanation. Should be used when an exceptional condition arises while processing a page which the user should be warned about, but which does not qualify as an error. } { ad_return_exception_page 200 $title $explanation } ad_proc ad_return_forbidden { {title ""} {explanation ""} } { Returns a page with the HTTP 403 (Forbidden) code, along with the given title and explanation. Should be used by access-control filters that determine whether a user has permission to request a particular page. Title and explanation is optional. If neither is specified, then a default "Permission Denied" message will be displayed. } { if { [template::util::is_nil title] && [template::util::is_nil explanation] } { set title "Permission Denied" set explanation "Sorry, you haven't been given access to this area." } ad_return_exception_page 403 $title $explanation } ad_proc ad_return_if_another_copy_is_running { {max_simultaneous_copies 1} {call_adp_break_p 0} } { Returns a page to the user about how this server is busy if another copy of the same script is running. Then terminates execution of the thread. Useful for expensive pages that do sequential searches through database tables, etc. You don't want to tie up all of your database handles and deny service to everyone else. The call_adp_break_p argument is essential if you are calling this from an ADP page and want to avoid the performance hit of continuing to parse and run. This proc is dangerous, and needs to be rewritten. See: http://openacs.org/forums/message-view?message_id=203381 } { # first let's figure out how many are running and queued set this_connection_url [ad_conn url] set n_matches 0 foreach connection [ns_server active] { set query_connection_url [lindex $connection 4] if { $query_connection_url == $this_connection_url } { # we got a match (we'll always get at least one # since we should match ourselves) incr n_matches } } if { $n_matches > $max_simultaneous_copies } { ad_return_warning "Too many copies" "This is an expensive page for our server, which is already running the same program on behalf of some other users. Please try again at a less busy hour." # blow out of the caller as well if {$call_adp_break_p} { # we were called from an ADP page; we have to abort processing ns_adp_break } return -code return } # we're okay return 1 } ad_proc ad_pretty_mailing_address_from_args { line1 line2 city state postal_code country_code } { Returns a prettily formatted address with country name, given an address. @author Unknown @author Roberto Mello } { set lines [list] if { $line2 eq "" } { lappend lines $line1 } elseif { $line1 eq "" } { lappend lines $line2 } else { lappend lines $line1 lappend lines $line2 } lappend lines "$city, $state $postal_code" if { $country_code ne "" && $country_code ne "us" } { lappend lines [ad_country_name_from_country_code $country_code] } return [join $lines "\n"] } ad_proc ad_get_user_info {} { Sets first_names, last_name, email in the environment of its caller. @return ad_return_error if user_id can't be found. @author Unknown @author Roberto Mello } { uplevel { set user_id [ad_conn user_id] if { [catch { db_1row user_name_select { select first_names, last_name, email from persons, parties where person_id = :user_id and person_id = party_id } } errmsg] } { ad_return_error "Couldn't find user info" "Couldn't find user info." return } } } # for pages that have optional decoration ad_proc ad_decorate_top { simple_headline potential_decoration } { Use this for pages that might or might not have an image defined in ad.ini; if the second argument isn't the empty string, ad_decorate_top will make a one-row table for the top of the page } { if { $potential_decoration eq "" } { return $simple_headline } else { return "
    $potential_decoration$simple_headline
    " } } ad_proc -private ad_requested_object_id {} { @return The requested object id, or if it is not available, the kernel id. } { set package_id "" # Use the object id stored in ad_conn. if { [ad_conn -connected_p] } { set package_id [ad_conn package_id] } if { $package_id eq "" } { if { [catch { set package_id [ad_acs_kernel_id] }] } { set package_id 0 } } return $package_id } ad_proc -deprecated ad_parameter { -localize:boolean -set {-package_id ""} name {package_key ""} {default ""} } { Package instances can have parameters associated with them. This function is used for accessing and setting these values. Parameter values are stored in the database and cached within memory. New parameters can be created with the APM and values can be set using the Site Map UI.. Because parameters are specified on an instance basis, setting the package_key parameter (preserved from the old version of this function) does not affect the parameter retrieved. If the code that calls ad_parameter is being called within the scope of a running server, the package_id will be determined automatically. However, if you want to use a parameter on server startup or access an arbitrary parameter (e.g., you are writing bboard code, but want to know an acs-kernel parameter), specifiy the package_id parameter to the object id of the package you want.

    Note: The parameters/ad.ini file is deprecated. @see parameter::set_value @see parameter::get @param -set Use this if you want to indicate a value to set the parameter to. @param -package_id Specify this if you want to manually specify what object id to use the new parameter. @return The parameter of the object or if it doesn't exist, the default. } { if {[info exists set]} { set ns_param [parameter::set_value -package_id $package_id -parameter $name -value $set] } else { set ns_param [parameter::get -localize=$localize_p -package_id $package_id -parameter $name -default $default] } return $ns_param } ad_proc -public ad_parameter_from_file { name {package_key ""} } { This proc returns the value of a parameter that has been set in the parameters/ad.ini file. Note: The use of the parameters/ad.ini file is discouraged. Some sites need it to provide instance-specific parameter values that are independent of the contents of the apm_parameter tables. @param name The name of the parameter. @return The parameter of the object or if it doesn't exist, the default. } { set ns_param "" # The below is really a hack because none of the calls to ad_parameter in the system # actually call 'ad_parameter param_name acs-kernel'. if { $package_key eq "" || $package_key eq "acs-kernel"} { set ns_param [ns_config "ns/server/[ns_info server]/acs" $name] } else { set ns_param [ns_config "ns/server/[ns_info server]/acs/$package_key" $name] } return $ns_param } ad_proc -private ad_parameter_cache { -set -delete:boolean -global:boolean key parameter_name } { Manages the cache for ad_paremeter. @param -set Use this flag to indicate a value to set in the cache. @param -delete Delete the value from the cache @param -global If true, global param, false, instance param @param key Specifies the key for the cache'd parameter, either the package instance id (instance parameter) or package key (global parameter). @param parameter_name Specifies the parameter name that is being cached. @return The cached value. } { if {$delete_p} { if {[nsv_exists ad_param_$key $parameter_name]} { nsv_unset ad_param_$key $parameter_name } return } if {[info exists set]} { nsv_set "ad_param_${key}" $parameter_name $set return $set } elseif { [nsv_exists ad_param_$key $parameter_name] } { return [nsv_get ad_param_$key $parameter_name] } elseif { $global_p } { set value [db_string select_global_parameter_value {} -default ""] } else { set value [db_string select_instance_parameter_value {} -default ""] } nsv_set "ad_param_${key}" $parameter_name $value return $value } ad_proc -private ad_parameter_cache_all {} { Loads all package instance parameters into the proper nsv arrays } { # Cache all parameters for enabled packages. . db_foreach parameters_get_all { select v.package_id, p.parameter_name, v.attr_value from apm_parameters p, apm_parameter_values v where p.parameter_id = v.parameter_id } { ad_parameter_cache -set $attr_value $package_id $parameter_name } } # returns particular parameter values as a Tcl list (i.e., it selects # out those with a certain key) ad_proc -public ad_parameter_all_values_as_list { {-package_id ""} name {subsection ""} } { Returns multiple values for a parameter as a list. } { return [join [parameter::get -package_id $package_id -parameter $name ] " "] } ad_proc doc_return {args} { A wrapper to be used instead of ns_return. It calls db_release_unused_handles prior to calling ns_return. This should be used instead of ns_return at the bottom of every non-templated user-viewable page. } { db_release_unused_handles ad_http_cache_control eval "ns_return $args" } ad_proc -public ad_return_url { -urlencode:boolean -qualified:boolean {extra_args {}} } { Build a return url suitable for passing to a page you expect to return back to the current page.

    Example for direct inclusion in a link:

        ad_returnredirect "foo?return_url=[ad_return_url -url_encode]"
        
    Example setting a variable to be used by export_vars:
        set return_url [ad_return_url]
        set edit_link "edit?[export_vars item_id return_url]"
        
    Example setting a variable with extra_vars:
        set return_url [ad_return_url [list some_id $some_id] [some_other_id $some_other_id]]
        
    @author Don Baccus (dhogaza@pacifier.com) @param urlencode If true url-encode the result @param qualified If provided the return URL will be fully qualified including http or https. @param extra_args A list of {name value} lists to append to the query string } { set query_list [export_entire_form_as_url_vars] foreach {extra_arg} $extra_args { lappend query_list [join $extra_arg "="] } if { [llength $query_list] == 0 } { set url [ns_conn url] } else { set url "[ns_conn url]?[join $query_list "&"]" } if { $qualified_p } { # Make the return_url fully qualified if { [security::secure_conn_p] } { set url [security::get_secure_qualified_url $url] } else { set url [security::get_insecure_qualified_url $url] } } if { $urlencode_p } { return [ns_urlencode $url] } else { return $url } } ad_proc -public ad_progress_bar_begin { {-title:required} {-message_1 ""} {-message_2 ""} {-template "/packages/acs-tcl/lib/progress-bar"} } { Return a proress bar.

    Example:

    ad_progress_bar_begin -title "Installing..." -message_1 "Please wait..." -message_2 "Will continue automatically"
    ...
    ad_progress_bar_end -url $next_page
    @param title The title of the page @param message_1 Message to display above the progress bar. @param message_2 Message to display below the progress bar. @param template Name of template to use. Default value is recommended. @see ad_progress_bar_end } { db_release_unused_handles ad_http_cache_control ReturnHeaders ns_write [ad_parse_template -params [list [list title $title] [list message_1 $message_1] [list message_2 $message_2]] $template] } ad_proc -public ad_progress_bar_end { {-url:required} {-message_after_redirect ""} } { Ends the progress bar by causing the browser to redirect to a new URL. @see ad_progress_bar_begin } { util_user_message -message $message_after_redirect ns_write "" ns_conn close } openacs-5.7.0/packages/acs-tcl/tcl/defs-procs.xql0000644000175000017500000000255311352533030021454 0ustar frankiefrankie select first_names, last_name, email from persons, parties where person_id = :user_id and person_id = party_id select apm_parameter_values.attr_value from apm_parameters, apm_parameter_values where apm_parameter_values.package_id is null and apm_parameter_values.parameter_id = apm_parameters.parameter_id and apm_parameters.parameter_name = :parameter_name select apm_parameter_values.attr_value from apm_parameters, apm_parameter_values where apm_parameter_values.package_id = :key and apm_parameter_values.parameter_id = apm_parameters.parameter_id and apm_parameters.parameter_name = :parameter_name select v.package_id, p.parameter_name, v.attr_value from apm_parameters p, apm_parameter_values v where p.parameter_id = v.parameter_id openacs-5.7.0/packages/acs-tcl/tcl/pdf-procs.tcl0000644000175000017500000000754410440426473021300 0ustar frankiefrankie# packages/acs-tcl/tcl/pdf-procs.tcl ad_library { Functions for handling Template-documents @author Christian Langmann (C_Langmann@gmx.de) @creation-date 2005-07-07 } namespace eval text_templates {} ad_proc -public text_templates::create_pdf_content { {-template_id:required} {-set_var_call:required} } { Create the pdf content from a template @author Christian Langmann (C_Langmann@gmx.de) @creation-date 2005-07-07 @param template_id The template to use for the preview. It is \ assumed that the template_id is the same as the revision_id to \ be used for the template. @param set_var_call procedure-name which sets the variables used @return the pdf-file-name } { set tmp_filename [ns_tmpnam] # create html.file set html_content [create_html_content -template_id $template_id -set_var_call $set_var_call] set tmp_html_filename "${tmp_filename}.html" set fp [open $tmp_html_filename w] puts $fp $html_content close $fp # create pdf-file set tmp_pdf_filename "${tmp_filename}.pdf" set htmldoc_bin [parameter::get -parameter "HtmlDocBin" -default "/usr/bin/htmldoc"] if {[catch {exec $htmldoc_bin --webpage --quiet -t pdf -f $tmp_pdf_filename $tmp_html_filename} err]} { ns_log Notice "Error during conversion from html to pdf: $err" } file delete $tmp_html_filename if {[file exists $tmp_pdf_filename]} { return $tmp_pdf_filename } else { return "" } } ad_proc -public text_templates::create_pdf_from_html { {-html_content:required} } { The HTML Content is transformed into a PDF file @param html_content HTML Content that is transformed into PDF @return filename of the pdf file } { set tmp_filename [ns_tmpnam] set tmp_html_filename "${tmp_filename}.html" set fp [open $tmp_html_filename w] puts $fp $html_content close $fp # create pdf-file set tmp_pdf_filename "${tmp_filename}.pdf" set htmldoc_bin [parameter::get -parameter "HtmlDocBin" -default "/usr/bin/htmldoc"] if {[catch {exec $htmldoc_bin --webpage --quiet -t pdf -f $tmp_pdf_filename $tmp_html_filename} err]} { ns_log Notice "Error during conversion from html to pdf: $err" } if {[file exists $tmp_pdf_filename]} { return $tmp_pdf_filename } else { return "" } } ad_proc -public text_templates::store_final_document { {-pdf_file:required} {-folder_id:required} {-title:required} {-description:required} } { The document is stored in the given folder. @author Christian Langmann (C_Langmann@gmx.de) @creation-date 2005-07-07 @param pdf_file the pdf-file to save @param folder_id the folder the document is stored in @title Title or name of the document @description Description of the document @return @error } { set file_size [file size $pdf_file] set item_id [cr_import_content -title $title -description $description $folder_id $pdf_file $file_size application/pdf $title] return item_id } ad_proc -private text_templates::create_html_content { {-template_id ""} {-set_var_call:required} {-filename:required} } { Create the filled out template as html @author Christian Langmann (C_Langmann@gmx.de) @creation-date 2005-07-07 @param template_id The template to use for the preview. It is assumed that the template_id is the same as the revision_id to be used for the template. @param set_var_call procedure-name which sets the variables used } { eval $set_var_call # retrieve template and write to tmpfile # set content [content::get_content_value $template_id] set file [open $filename] fconfigure $file -translation binary set content [read $file] # parse template and replace placeholders eval [template::adp_compile -string $content] set final_content $__adp_output return $final_content } openacs-5.7.0/packages/acs-tcl/tcl/membership-rel-procs.tcl0000644000175000017500000000651610551254404023434 0ustar frankiefrankiead_library { Manage Membership Relations @author yon (yon@openforce.net) @creation-date 2002-03-15 @cvs-id $Id: membership-rel-procs.tcl,v 1.8 2007/01/10 21:22:12 gustafn Exp $ } namespace eval membership_rel { ad_proc -public change_state { {-rel_id:required} {-state:required} } { Change the state of a membership relation } { db_transaction { # We need the id of the user that we are changing state for set rel_user_id [db_string select_rel_user_id { select u.user_id from acs_rels r, users u where r.rel_id = :rel_id and u.user_id = r.object_id_two } -default {}] # If user is being undeleted - remove him from the public group acs_user::get -user_id $rel_user_id -array user if { $user(member_state) eq "deleted" && $state eq "approved" } { group::remove_member \ -group_id [acs_magic_object the_public] \ -user_id $rel_user_id } switch -exact $state { "approved" { db_exec_plsql approve {} } "banned" { db_exec_plsql ban {} } "rejected" { db_exec_plsql reject {} } "deleted" { db_exec_plsql delete {} # Add user to public group - see bug 1468 group::add_member \ -no_perm_check \ -group_id [acs_magic_object the_public] \ -user_id $rel_user_id } "needs approval" { db_exec_plsql unapprove {} } "merged" { db_exec_plsql merge {} } } # Record who changed the state # This will trigger an update of the acs_objects.modified_date column. # We use this in the ApprovalExpiration feature to make sure that a user isn't # bumped back to needs_approval right after an administrator has approved them, # even if the user doesn't log in in the meantime. if { [ad_conn isconnected] } { set user_id [ad_conn user_id] } else { set user_id [db_null] } db_dml update_modifying_user {} } if { $rel_user_id ne "" } { acs_user::flush_cache -user_id $rel_user_id } } ad_proc -public approve { {-rel_id:required} } { Approve a membership relation } { change_state -rel_id $rel_id -state "approved" } ad_proc -public ban { {-rel_id:required} } { Ban a membership relation } { change_state -rel_id $rel_id -state "banned" } ad_proc -public reject { {-rel_id:required} } { Reject a membership relation } { change_state -rel_id $rel_id -state "rejected" } ad_proc -public delete { {-rel_id:required} } { Delete a membership relation } { change_state -rel_id $rel_id -state "deleted" } ad_proc -public unapprove { {-rel_id:required} } { Unapprove a membership relation } { change_state -rel_id $rel_id -state "needs approval" } } openacs-5.7.0/packages/acs-tcl/tcl/membership-rel-procs.xql0000644000175000017500000000041207723347127023457 0ustar frankiefrankie update acs_objects set modifying_user = :user_id where object_id = :rel_id openacs-5.7.0/packages/acs-tcl/tcl/community-core-2-procs.tcl0000644000175000017500000000110407537470226023632 0ustar frankiefrankiead_library { Community routines (dealing with users, parties, etc.). Redone with scoping and nice abstraction (Ben) @author Ben Adida (ben@openforce.net) @creation-date May 29th, 2002 @cvs-id $Id: community-core-2-procs.tcl,v 1.2 2002/09/10 22:22:14 jeffd Exp $ } # The User Namespace namespace eval oacs::user { ad_proc -public get { {-user_id:required} {-array:required} } { Load up user information } { # Upvar the Tcl Array upvar $array row db_1row select_user {} -column_array row } } openacs-5.7.0/packages/acs-tcl/tcl/community-core-2-procs.xql0000644000175000017500000000062107475444467023670 0ustar frankiefrankie select user_id, screen_name, last_visit, second_to_last_visit, first_names, last_name, email, first_names || ' ' || last_name as full_name from users, parties, persons where users.user_id = parties.party_id and users.user_id = persons.person_id and user_id= :user_id openacs-5.7.0/packages/acs-tcl/tcl/00-database-procs.tcl0000644000175000017500000036104511456662501022511 0ustar frankiefrankiead_library { An API for managing database queries. @creation-date 15 Apr 2000 @author Jon Salz (jsalz@arsdigita.com) @cvs-id $Id: 00-database-procs.tcl,v 1.80 2010/10/17 21:06:09 donb Exp $ } # Database caching. # # Values returned by a query are cached if you pass the "-cache_key" switch # to the database procedure. The switch value will be used as the key in the # ns_cache eval call used to execute the query and processing code. The # db_flush proc should be called to flush the cache when appropriate. The # "-cache_pool" parameter can be used to specify the cache pool to be used, # and defaults to db_cache_pool. The # size of the default cache is governed # by the kernel parameter "DBCacheSize" in the "caching" section. # # Currently db_string, db_list, db_list_of_lists, db_0or1row, and db_multirow support # caching. # # Don Baccus 2/25/2006 - my 52nd birthday! # As originally released in (at least) ACS 4.2 through OpenACS 4.6, # this DB API supported only a single, default database. You could # define any number of different database drivers and pools in # AOLserver, but could only use ONE database here. # # I have eliminated this restriction. Now, in OpenACS 5.0 and later, # to access a non-default database, simply pass the optional -dbn # (Database Name) switch to any of the DB API procs which support it. # # Supported AOLserver database drivers: # # - Oracle (nsoracle): Everything should work. # # - PostgreSQL (nspostgres): Everything should work. # # - ODBC (nsodbc): # - Anything using bind variables will only work if you're using a # version of the driver with bind variable emulation hacked in # (copied from the PostgreSQL driver). # - Some features, like LOBs, simply won't work at all. # - The basic functionality worked fine back in Sept. 2001, but I # have NOT tested it since then at all, so maybe there are bugs. # # - Any others: Basic stuff using only the standard ns_db api will # likely work, but any special features of the driver (e.g., LOBs) # definitely won't. Feel free to add support! # # --atp@piskorski.com, 2003/04/09 19:18 EDT # Note that "-dbn" specifies a "Database Name", NOT a database pool! # # I could have provided access to secondary databases via a -pool # rather than a -dbn switch, but chose not to, as the existing DB API # already had the nicely general feature that if you try to do nested # queries, the DB API will transparently grab a second database handle # from another pool to make it work. You can nest your queries as # many levels deep as you have database pools defined for that # database. So, the existing API essentially already supported the # notion of "binning" database pools into logical "databases", it just # didn't provide any way to define more than the single, default # database! Thus I chose to preserve this "binning" by specifying # databases via the -dbn switch rather than database pools via a -pool # switch. # (JoelA, 27 Dec 2004 - replaced example config.tcl with link) # # see http://openacs.org/doc/openacs-5-1/tutorial-second-database.html # for config and usage examples # TODO: The "driverkey_" overrides in the config file are NOT # implemented yet! # # --atp@piskorski.com, 2003/03/16 21:30 EST # NOTE: don't forget to add your new pools into the # ns_section ns/db/pools # The "driverkey" indirection layer: # # Note that in the AOLserver config file, you may optionally add one # entry for each database definining its "driver key". If you do NOT # specify a driver key in the AOLserver config file, the appropriate # key will be determined for you by calling "ns_db driver" once on # startup for the first pool defined in each database. Therefore, # most people should NOT bother to give a driverkey in the config # file. # # So, just what is this "driverkey" thing used for anyway? AOLserver # defines the ns_db API, and the OpenACS db_* API depends utterly on # it. However, there are a few holes in the functionality of the # ns_db API, and each AOLserver database driver tends to fill in those # holes by adding extra functionality with its own, drive specifc # functions. Therefore, in order to make the db_* API work with # multiple db drivers, we need to introduce some switches or if # statements in our code. # # Currently (2003/04/08), at least for the Oracle, PostgreSQL, and # ODBC drivers, the database driver name returned by "ns_db driver" is # completely sufficient for these switch statements. But, rather than # using ns_db driver directly in the switches, we add the simple # "driver key" layer of indirection between the two, to make the # default behavior easier to override if that should ever be # necessary. # # --atp@piskorski.com, 2003/04/08 03:39 EDT # We now use the following global variables: # # Server-Wide NSV arrays, keys: # db_default_database . # db_available_pools $dbn # db_driverkey $dbn # db_pool_to_dbn $pool # # Per-thread Tcl global variables: # One Tcl Array per Database Name: # db_state_${dbn} # # The db_available_pools and db_state arrays are used in exactly the # same manner as they were originally (in ACS 4.0 to OpenACS 4.6 # code), except that in the original DB API we had only one of each # array total, while now we have one of each array per database. # # The db_pool_to_dbn nsv is simply a map to quickly tell use which dbn # each AOLserver database pool belongs to. (Any pools which do not # belong to any dbn have no entry here.) # # We use the procs db_state_array_name_is, db_available_pools, and # db_driverkey to help keep track of these different arrays. # Note that most code should now NEVER read from any of the # db_available_pools nsvs listed above, but should instead use the # proc db_available_pools provided for that purpose. # # The original implementation comments on the use of these global # variables are below: # # --atp@piskorski.com, 2003/03/16 21:30 EST ad_proc -private db_state_array_name_is {{ -dbn "" }} { @return the name of the global db_state array for the given database name. @param dbn The database name to use. If empty_string, uses the default database. @author Andrew Piskorski (atp@piskorski.com) @creation-date 2003/03/16 } { if { $dbn eq "" } { set dbn [nsv_get {db_default_database} .] } return "db_state_${dbn}" } ad_proc -private db_driverkey {{ -handle_p 0 } dbn } { Normally, a dbn is passed to this proc. Unfortunately, there are one or two cases where a proc that needs to call this one has only a db handle, not the dbn that handle came from. Therefore, they instead use -handle_p 1 and pass the db handle. @return The driverkey for use in db_* API switch statements. @author Andrew Piskorski (atp@piskorski.com) @creation-date 2003/04/08 } { set proc_name {db_driverkey} if { $handle_p } { set handle $dbn ; set dbn {} set pool [ns_db poolname $handle] if { [nsv_exists {db_pool_to_dbn} $pool] } { set dbn [nsv_get {db_pool_to_dbn} $pool] } else { # db_pool_to_dbn_init runs on startup, so other than some # broken code deleting the nsv key (very unlikely), the # only way this could happen is for someone to call this # proc with a db handle from a pool which is not part of # any dbn. error "No database name (dbn) found for pool '$pool'. Check the 'ns/server/[ns_info server]/acs/database' section of your config file." } } if { ![nsv_exists {db_driverkey} $dbn] } { # This ASSUMES that any overriding of this default value via # "ns_param driverkey_dbn" has already been done: if { $handle_p } { set driver [ns_db driver $handle] } else { db_with_handle -dbn $dbn handle { set driver [ns_db driver $handle] } } # These are the default driverkey values, if they are not set # in the config file: if { [string match "Oracle*" $driver] } { set driverkey {oracle} } elseif { [string equal $driver {PostgreSQL}] } { set driverkey {postgresql} } elseif { [string equal $driver {ODBC}] } { set driverkey {nsodbc} } else { set driverkey {} ns_log Error "$proc_name: Unknown driver '$driver_type'." } nsv_set {db_driverkey} $dbn $driverkey } return [nsv_get {db_driverkey} $dbn] } ad_proc -public db_type { } { @return the RDBMS type (i.e. oracle, postgresql) this OpenACS installation is using. The nsv ad_database_type is set up during the bootstrap process. } { # Currently this should always be either "oracle" or "postgresql": # --atp@piskorski.com, 2003/03/16 22:01 EST return [nsv_get ad_database_type .] } ad_proc -public db_compatible_rdbms_p { db_type } { @return 1 if the given db_type is compatible with the current RDBMS. } { return [expr { $db_type eq "" || [db_type] eq $db_type }] } ad_proc -deprecated db_package_supports_rdbms_p { db_type_list } { @return 1 if db_type_list contains the current RDMBS type. A package intended to run with a given RDBMS must note this in it's package info file regardless of whether or not it actually uses the database. @see apm_package_supports_rdbms_p } { if { [lsearch $db_type_list [db_type]] != -1 } { return 1 } # DRB: Legacy package check - we allow installation of old aD Oracle 4.2 packages, # though we don't guarantee that they work. if { [db_type] eq "oracle" && [lsearch $db_type_list "oracle-8.1.6"] != -1 } { return 1 } return 0 } ad_proc -private db_legacy_package_p { db_type_list } { @return 1 if the package is a legacy package. We can only tell for certain if it explicitly supports Oracle 8.1.6 rather than the OpenACS more general oracle. } { if { [lsearch $db_type_list "oracle-8.1.6"] != -1 } { return 1 } return 0 } ad_proc -public db_version { } { @return the RDBMS version (i.e. 8.1.6 is a recent Oracle version; 7.1 a recent PostgreSQL version. } { return [nsv_get ad_database_version .] } ad_proc -public db_current_rdbms { } { @return the current rdbms type and version. } { return [db_rdbms_create [db_type] [db_version]] } ad_proc -public db_known_database_types { } { @return a list of three-element lists describing the database engines known to OpenACS. Each sublist contains the internal database name (used in file paths, etc), the driver name, and a "pretty name" to be used in selection forms displayed to the user. The nsv containing the list is initialized by the bootstrap script and should never be referenced directly by user code. } { return [nsv_get ad_known_database_types .] } # db_null, db_quote, db_nullify_empty_string - were all previously # defined Oracle only, no Postgres equivalent existed at all. So, it # can't hurt anything to have them defined in when OpenACS is using # Postgres too. --atp@piskorski.com, 2003/04/08 05:34 EDT ad_proc db_null { } { @return an empty string, which Oracle thinks is null. This routine was invented to provide an RDBMS-specific null value but doesn't actually work. I (DRB) left it in to speed porting - we should really clean up the code an pull out the calls instead, though. } { return "" } ad_proc -public db_quote { string } { Quotes a string value to be placed in a SQL statement. } { regsub -all {'} "$string" {''} result return $result } ad_proc -public db_nullify_empty_string { string } { A convenience function that returns [db_null] if $string is the empty string. } { if { $string eq "" } { return [db_null] } else { return $string } } ad_proc -public db_boolean { bool } { Converts a Tcl boolean (1/0) into a SQL boolean (t/f) @return t or f } { if { $bool } { return "t" } else { return "f" } } ad_proc -public db_nextval {{ -dbn "" } sequence } { Example:
         set new_object_id [db_nextval acs_object_id_seq]
         
    @return the next value for a sequence. This can utilize a pool of sequence values. @param sequence the name of an sql sequence @param dbn The database name to use. If empty_string, uses the default database. @see /doc/db-api-detailed.html } { set driverkey [db_driverkey $dbn] # PostgreSQL has a special implementation here, any other db will # probably work with the default: switch $driverkey { postgresql { # # the following query will return a nextval if the sequnce # # is of relkind = 'S' (a sequnce). if it is not of relkind = 'S' # # we will try querying it as a view: # if { [db_0or1row -dbn $dbn nextval_sequence " # select nextval('${sequence}') as nextval # where (select relkind # from pg_class # where relname = '${sequence}') = 'S' # "]} { # return $nextval # } else { # ns_log debug "db_nextval: sequence($sequence) is not a real sequence. perhaps it uses the view hack." # db_0or1row -dbn $dbn nextval_view "select nextval from ${sequence}" # return $nextval # } # # The code above is just for documentation, how it worked # before the change below. We keep now a per-thread table of # the "known" sequences to avoid at runtime the query, # whether the specified sequence is a real sequence or a # view. This change makes this function more than a factor # of 2 faster than before. # # Note, that solely the per-thread information won't work for # freshly created sequences. Therefore, we keep the old # code for checking at runtime in the database for such # occurrences. # # Note, that the sequence handling in OpenACS is quite a # mess. Some sequences are named t_SEQUENCE (10 in dotlrn), # others are are called just SEQUENCE (18 in dotlrn), for # some sequences, additional views are defined with an # attribute 'nextval', and on top of this, db_nextval is # called sometimes with the view name and sometimes with the # sequence name. Checking this at runtime is unnecessary # complex and costly. # # The best solution would certainly be to call db_nextval # only with real sequence names. In that case, the whole # function would for postgres would collapse to a single # line, without any need for sequence name caching. # # - gustaf neumann (18.5.2008) # if {![info exists ::db::sequences]} { ns_log notice "-- creating per thread sequence table" namespace eval ::db {} foreach s [db_list -dbn $dbn relnames "select relname, relkind from pg_class where relkind = 'S'"] { set ::db::sequences($s) 1 } } if {[info exists ::db::sequences(t_$sequence)]} { #ns_log notice "-- found t_$sequence" set nextval [db_string -dbn $dbn "nextval" "select nextval('t_$sequence')"] } elseif {[info exists ::db::sequences($sequence)]} { #ns_log notice "-- found $sequence" set nextval [db_string -dbn $dbn "nextval" "select nextval('$sequence')"] } elseif { [db_0or1row -dbn $dbn nextval_sequence " select nextval('${sequence}') as nextval where (select relkind from pg_class where relname = '${sequence}') = 'S' "]} { # # We do not have an according sequence-table. Use the system catalog to check # for the sequence # # ... the query sets nextval if it succeeds # } else { # # finally, there might be a view with a nextval # ns_log debug "db_nextval: sequence($sequence) is not a real sequence. perhaps it uses the view hack." set nextval [db_string -dbn $dbn "nextval" "select nextval from $sequence"] } return $nextval } oracle - nsodbc - default { return [db_string -dbn $dbn "nextval" "select $sequence.nextval from dual"] } } } ad_proc -public db_nth_pool_name {{ -dbn "" } n } { @return the name of the pool used for the nth-nested selection (0-relative). @param dbn The database name to use. If empty_string, uses the default database. } { set available_pools [db_available_pools $dbn] if { $n < [llength $available_pools] } { set pool [lindex $available_pools $n] } else { return -code error "Ran out of database pools ($available_pools)" } return $pool } ad_proc -public db_with_handle {{ -dbn "" } db code_block } { Places a usable database handle in db and executes code_block. @param dbn The database name to use. If empty_string, uses the default database. } { upvar 1 $db dbh upvar "#0" [db_state_array_name_is -dbn $dbn] db_state # Initialize bookkeeping variables. if { ![info exists db_state(handles)] } { set db_state(handles) [list] } if { ![info exists db_state(n_handles_used)] } { set db_state(n_handles_used) 0 } if { $db_state(n_handles_used) >= [llength $db_state(handles)] } { set pool [db_nth_pool_name -dbn $dbn $db_state(n_handles_used)] set start_time [clock clicks -milliseconds] set errno [catch { set db [ns_db gethandle $pool] } error] ds_collect_db_call $db gethandle "" $pool $start_time $errno $error lappend db_state(handles) $db if { $errno } { global errorInfo errorCode return -code $errno -errorcode $errorCode -errorinfo $errorInfo $error } } set my_dbh [lindex $db_state(handles) $db_state(n_handles_used)] set dbh $my_dbh set db_state(last_used) $my_dbh incr db_state(n_handles_used) set errno [catch { uplevel 1 $code_block } error] incr db_state(n_handles_used) -1 # This may have changed while the code_block was being evaluated. set db_state(last_used) $my_dbh # Unset dbh, so any subsequence use of this variable will bomb. if { [info exists dbh] } { unset dbh } # If errno is 1, it's an error, so return errorCode and errorInfo; # if errno = 2, it's a return, so don't try to return errorCode/errorInfo # errno = 3 or 4 give undefined results if { $errno == 1 } { # A real error occurred global errorInfo errorCode return -code $errno -errorcode $errorCode -errorinfo $errorInfo $error } if { $errno == 2 } { # The code block called a "return", so pass the message through but don't try # to return errorCode or errorInfo since they may not exist return -code $errno $error } } ad_proc -public db_exec_plsql {{ -dbn "" } statement_name sql args } { Oracle: Executes a PL/SQL statement, and returns the variable of bind variable :1.

    PostgreSQL: Performs a pl/pgsql function or procedure call. The caller must perform a select query that returns the value of the function.

    Examples:

        # Oracle:
        db_exec_plsql delete_note {
            begin  note.del(:note_id);  end;
        }
    
        # PostgreSQL:
        db_exec_plsql delete_note {
            select note__delete(:note_id);
        }
        

    If you need the return value, then do something like this:

        # Oracle:
        set new_note_id [db_exec_plsql create_note {
            begin
            :1 := note.new(
              owner_id => :user_id,
              title    => :title,
              body     => :body,
              creation_user => :user_id,
              creation_ip   => :peeraddr,
              context_id    => :package_id
            );
            end;
        }]
    
        # PostgreSQL:
        set new_note_id [db_exec_plsql create_note {
            select note__new(
                             null,
                             :user_id,
                             :title,
                             :body,
                             'note',
                             now(),
                             :user_id,
                             :peeraddr,
                             :package_id
                             );
        }]
        

    You can call several pl/sql statements at once, like this:

        # Oracle:
        db_exec_plsql delete_note {
            begin
            note.del(:note_id);
            note.del(:another_note_id);
            note.del(:yet_another_note_id);
            end;
        }
    
        # PostgreSQL:
        db_exec_plsql delete_note {
            select note__delete(:note_id);
            select note__delete(:another_note_id);
            select note__delete(:yet_another_note_id);
        }
        
    If you are using xql files then put the body of the query in a yourfilename-oracle.xql or yourfilename-postgresql.xql file, as appropriate. E.g. the first example transformed to use xql files looks like this:

    yourfilename.tcl:

        db_exec_plsql delete_note { }

    yourfilename-oracle.xql:

        <fullquery name="delete_note">      
          <querytext>
            begin
            note.del(:note_id);
            end;
          </querytext>
        </fullquery>

    yourfilename-postgresql.xql:

        <fullquery name="delete_note">      
          <querytext>
            select note__delete(:note_id);
          </querytext>
        </fullquery>
    @param dbn The database name to use. If empty_string, uses the default database. @see /doc/db-api-detailed.html } { ad_arg_parser { bind_output bind } $args # Query Dispatcher (OpenACS - ben) set full_statement_name [db_qd_get_fullname $statement_name] if { [info exists bind_output] } { return -code error "the -bind_output switch is not currently supported" } set driverkey [db_driverkey $dbn] switch $driverkey { postgresql { set postgres_p 1 } oracle - nsodbc - default { set postgres_p 0 } } if { ! $postgres_p } { db_with_handle -dbn $dbn db { # Right now, use :1 as the output value if it occurs in the statement, # or not otherwise. set test_sql [db_qd_replace_sql $full_statement_name $sql] if { [regexp {:1} $test_sql] } { return [db_exec exec_plsql_bind $db $full_statement_name $sql 2 1 ""] } else { return [db_exec dml $db $full_statement_name $sql] } } } else { # Postgres doesn't have PL/SQL, of course, but it does have # PL/pgSQL and other procedural languages. Rather than assign the # result to a bind variable which is then returned to the caller, # the Postgres version of OpenACS requires the caller to perform a # select query that returns the value of the function. # We are no longer calling db_string, which screws up the bind # variable stuff otherwise because of calling environments. (ben) ad_arg_parser { bind_output bind } $args # I'm not happy about having to get the fullname here, but right now # I can't figure out a cleaner way to do it. I will have to # revisit this ASAP. (ben) set full_statement_name [db_qd_get_fullname $statement_name] if { [info exists bind_output] } { return -code error "the -bind_output switch is not currently supported" } db_with_handle -dbn $dbn db { # plsql calls that are simple selects bypass the plpgsql # mechanism for creating anonymous functions (OpenACS - Dan). # if a table is being created, we need to bypass things, too (OpenACS - Ben). set test_sql [db_qd_replace_sql $full_statement_name $sql] if {[regexp -nocase -- {^\s*select} $test_sql match]} { # ns_log Debug "PLPGSQL: bypassed anon function" set selection [db_exec 0or1row $db $full_statement_name $sql] } elseif {[regexp -nocase -- {^\s*create table} $test_sql match] || [regexp -nocase -- {^\s*drop table} $test_sql match]} { ns_log Debug "PLPGSQL: bypassed anon function for create/drop table" set selection [db_exec dml $db $full_statement_name $sql] return "" } else { # ns_log Debug "PLPGSQL: using anonymous function" set selection [db_exec_plpgsql $db $full_statement_name $sql \ $statement_name] } return [ns_set value $selection 0] } } } ad_proc -private db_exec_plpgsql { db statement_name pre_sql fname } { PostgreSQL only.

    A helper procedure to execute a SQL statement, potentially binding depending on the value of the $bind variable in the calling environment (if set).

    Low level replacement for db_exec which replaces inline code with a proc. db proc is dropped after execution. This is a temporary fix until we can port all of the db_exec_plsql calls to simple selects of the inline code wrapped in function calls.

    emulation of plsql calls from oracle. This routine takes the plsql statements and wraps them in a function call, calls the function, and then drops the function. Future work might involve converting this to cache the function calls

    This proc is private - use db_exec_plsql instead! @see db_exec_plsql } { set start_time [clock clicks -milliseconds] set sql [db_qd_replace_sql $statement_name $pre_sql] set unique_id [db_nextval "anon_func_seq"] set function_name "__exec_${unique_id}_${fname}" # insert tcl variable values (Openacs - Dan) if {$sql ne $pre_sql } { set sql [uplevel 2 [list subst -nobackslashes $sql]] } ns_log Debug "PLPGSQL: converted: $sql to: select $function_name ()" # create a function definition statement for the inline code # binding is emulated in tcl. (OpenACS - Dan) set errno [catch { upvar bind bind if { [info exists bind] && [llength $bind] != 0 } { if { [llength $bind] == 1 } { set bind_vars [list] set len [ns_set size $bind] for {set i 0} {$i < $len} {incr i} { lappend bind_vars [ns_set key $bind $i] \ [ns_set value $bind $i] } set proc_sql [db_bind_var_substitution $sql $bind_vars] } else { set proc_sql [db_bind_var_substitution $sql $bind] } } else { set proc_sql [uplevel 2 [list db_bind_var_substitution $sql]] } ns_db dml $db "create function $function_name () returns varchar as ' [DoubleApos $proc_sql] ' language 'plpgsql'" set ret_val [ns_db 0or1row $db "select $function_name ()"] # drop the anonymous function (OpenACS - Dan) # JCD: ignore return code -- maybe we should be smarter about this though. catch {ns_db dml $db "drop function $function_name ()"} return $ret_val } error] global errorInfo errorCode set errinfo $errorInfo set errcode $errorCode ds_collect_db_call $db 0or1row $statement_name $sql $start_time $errno $error if { $errno == 2 } { return $error } else { catch {ns_db dml $db "drop function $function_name ()"} } return -code $errno -errorinfo $errinfo -errorcode $errcode $error } ad_proc -private db_get_quote_indices { sql } { Given a piece of SQL, return the indices of single quotes. This is useful when we do bind var substitution because we should not attempt bind var substitution inside quotes. Examples:

            sql          return value
           {'a'}           {0 2}      
           {'a''}           {}
          {'a'a'a'}       {0 2 4 6}
          {a'b'c'd'}      {1 3 5 7}
        
    @see db_bind_var_subsitution } { set quote_indices [list] # Returns a list on the format # Example - for sql={'a'a'a'} returns # {0 2} {0 0} {2 2} {3 6} {4 4} {6 6} set all_indices [regexp -inline -indices -all -- {(?:^|[^'])(')(?:[^']|'')+(')(?=$|[^'])} $sql] for {set i 0} { $i < [llength $all_indices] } { incr i 3 } { lappend quote_indices [lindex [lindex $all_indices [expr {$i + 1}]] 0] lappend quote_indices [lindex [lindex $all_indices [expr {$i + 2}]] 0] } return $quote_indices } ad_proc -private db_bind_var_quoted_p { sql bind_start_idx bind_end_idx} { } { foreach {quote_start_idx quote_end_idx} [db_get_quote_indices $sql] { if { [expr {$bind_start_idx > $quote_start_idx}] && [expr {$bind_end_idx < $quote_end_idx}]} { return 1 } } return 0 } ad_proc -private db_bind_var_substitution { sql { bind "" } } { This proc emulates the bind variable substitution in the postgresql driver. Since this is a temporary hack, we do it in tcl instead of hacking up the driver to support plsql calls. This is only used for the db_exec_plpgsql function. } { if {$bind eq ""} { upvar __db_sql lsql set lsql $sql uplevel { set __db_lst [regexp -inline -indices -all -- {:?:\w+} $__db_sql] for {set __db_i [expr {[llength $__db_lst] - 1}]} {$__db_i >= 0} {incr __db_i -1} { set __db_ws [lindex [lindex $__db_lst $__db_i] 0] set __db_we [lindex [lindex $__db_lst $__db_i] 1] set __db_bind_var [string range $__db_sql $__db_ws $__db_we] if {![string match "::*" $__db_bind_var] && ![db_bind_var_quoted_p $__db_sql $__db_ws $__db_we]} { set __db_tcl_var [string range $__db_bind_var 1 end] set __db_tcl_var [set $__db_tcl_var] if {$__db_tcl_var eq ""} { set __db_tcl_var null } else { set __db_tcl_var "'[DoubleApos $__db_tcl_var]'" } set __db_sql [string replace $__db_sql $__db_ws $__db_we $__db_tcl_var] } } } } else { array set bind_vars $bind set lsql $sql set lst [regexp -inline -indices -all -- {:?:\w+} $sql] for {set i [expr {[llength $lst] - 1}]} {$i >= 0} {incr i -1} { set ws [lindex [lindex $lst $i] 0] set we [lindex [lindex $lst $i] 1] set bind_var [string range $sql $ws $we] if {![string match "::*" $bind_var] && ![db_bind_var_quoted_p $lsql $ws $we]} { set tcl_var [string range $bind_var 1 end] set val $bind_vars($tcl_var) if {$val eq ""} { set val null } else { set val "'[DoubleApos $val]'" } set lsql [string replace $lsql $ws $we $val] } } } return $lsql } ad_proc -public db_release_unused_handles {{ -dbn "" }} { Releases any database handles that are presently unused. @param dbn The database name to use. If empty_string, uses the default database. } { upvar "#0" [db_state_array_name_is -dbn $dbn] db_state if { [info exists db_state(n_handles_used)] } { # Examine the elements at the end of db_state(handles), killing off # handles that are unused and not engaged in a transaction. set index_to_examine [expr { [llength $db_state(handles)] - 1 }] while { $index_to_examine >= $db_state(n_handles_used) } { set db [lindex $db_state(handles) $index_to_examine] # Stop now if the handle is part of a transaction. if { [info exists db_state(transaction_level,$db)] && \ $db_state(transaction_level,$db) > 0 } { break } set start_time [clock clicks -milliseconds] ns_db releasehandle $db ds_collect_db_call $db releasehandle "" "" $start_time 0 "" incr index_to_examine -1 } set db_state(handles) [lrange $db_state(handles) 0 $index_to_examine] } } ad_proc -private db_getrow { db selection } { A helper procedure to perform an ns_db getrow, invoking developer support routines as necessary. } { set start_time [clock clicks -milliseconds] set errno [catch { return [ns_db getrow $db $selection] } error] ds_collect_db_call $db getrow "" "" $start_time $errno $error if { $errno == 2 } { return $error } global errorInfo errorCode return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error } ad_proc -private db_exec { type db statement_name pre_sql {ulevel 2} args } { A helper procedure to execute a SQL statement, potentially binding depending on the value of the $bind variable in the calling environment (if set). } { set start_time [clock clicks -milliseconds] set start_time_fine [clock seconds] set driverkey [db_driverkey -handle_p 1 $db] # Note: Although marked as private, db_exec is in fact called # extensively from several other packages. We DEFINITELY don't # want to have to change all those procs to pass in the # (redundant) $dbn just so we can use it in the call to # db_driverkey, so db_driverkey MUST support its -handle switch. # --atp@piskorski.com, 2003/04/09 12:13 EDT set sql [db_qd_replace_sql $statement_name $pre_sql] # insert tcl variable values (Openacs - Dan) if {$sql ne $pre_sql } { set sql [uplevel $ulevel [list subst -nobackslashes $sql]] } set errno [catch { upvar bind bind if { [info exists bind] && [llength $bind] != 0 } { if { [llength $bind] == 1 } { # $bind is an ns_set id: switch $driverkey { oracle { return [eval [list ns_ora $type $db -bind $bind $sql] $args] } postgresql { return [eval [list ns_pg_bind $type $db -bind $bind $sql]] } nsodbc { return [eval [list ns_odbc_bind $type $db -bind $bind $sql]] } default { error "Unknown database driver. Bind variables not supported for this database." } } } else { # $bind is a Tcl list, convert it to an ns_set: set bind_vars [ns_set create] foreach { name value } $bind { ns_set put $bind_vars $name $value } } switch $driverkey { oracle { # TODO: Using $args outside the list is # potentially bad here, depending on what is in # args and if the items contain any embedded # whitespace. Or maybe it works fine. But it's # hard to know. Document or fix. # --atp@piskorski.com, 2003/04/09 15:33 EDT return [eval [list ns_ora $type $db -bind $bind_vars $sql] $args] } postgresql { return [eval [list ns_pg_bind $type $db -bind $bind_vars $sql]] } nsodbc { return [eval [list ns_odbc_bind $type $db -bind $bind_vars $sql]] } default { error "Unknown database driver. Bind variables not supported for this database." } } } else { # Bind variables, if any, are defined solely as individual # Tcl variables: switch $driverkey { oracle { return [uplevel $ulevel [list ns_ora $type $db $sql] $args] } postgresql { return [uplevel $ulevel [list ns_pg_bind $type $db $sql]] } nsodbc { return [uplevel $ulevel [list ns_odbc_bind $type $db $sql]] } default { # Using plain ns_db like this will work ONLY if # the query is NOT using bind variables: # --atp@piskorski.com, 2001/09/03 08:41 EDT return [uplevel $ulevel [list ns_db $type $db $sql] $args] } } } } error] # JCD: we log the clicks, dbname, query time, and statement to catch long running queries. # If we took more than 5 seconds yack about it. if { [expr {[clock clicks -milliseconds] - $start_time}] > 5000} { ns_log Warning "db_exec: longdb [expr {[clock seconds] - $start_time_fine}] seconds $db $type $statement_name" } else { ns_log Debug "db_exec: timing [expr {[clock seconds] - $start_time_fine}] seconds $db $type $statement_name" } ds_collect_db_call $db $type $statement_name $sql $start_time $errno $error if { $errno == 2 } { return $error } global errorInfo errorCode return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error } ad_proc -public db_string { { -dbn "" } -cache_key {-cache_pool db_cache_pool} statement_name sql args } { Usage: db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] @return the first column of the result of the SQL query sql. If the query doesn't return a row, returns default or raises an error if no default is provided. @param dbn The database name to use. If empty_string, uses the default database. @param cache_key Cache the result using given value as the key. Default is to not cache. @param cache_pool Override the default db_cache_pool } { # Query Dispatcher (OpenACS - ben) set full_name [db_qd_get_fullname $statement_name] ad_arg_parser { default bind } $args if { [info exists cache_key] } { set value [ns_cache eval $cache_pool $cache_key { db_with_handle -dbn $dbn db { set selection [db_exec 0or1row $db $full_name $sql] } if { $selection ne ""} { set selection [list [ns_set value $selection 0]] } set selection }] if { $value eq "" } { if { [info exists default] } { return $default } return -code error "Selection did not return a value, and no default was provided" } else { return [lindex $value 0] } } else { db_with_handle -dbn $dbn db { set selection [db_exec 0or1row $db $full_name $sql] } if { $selection eq ""} { if { [info exists default] } { return $default } return -code error "Selection did not return a value, and no default was provided" } return [ns_set value $selection 0] } } ad_proc -public db_list { { -dbn "" } -cache_key {-cache_pool db_cache_pool} statement_name sql args } { Usage: db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] @return a Tcl list of the values in the first column of the result of SQL query sql. If sql doesn't return any rows, returns an empty list. @param dbn The database name to use. If empty_string, uses the default database. @param cache_key Cache the result using given value as the key. Default is to not cache. @param cache_pool Override the default db_cache_pool } { ad_arg_parser { bind } $args # Query Dispatcher (OpenACS - SDW) set full_statement_name [db_qd_get_fullname $statement_name] # Can't use db_foreach in this proc, since we need to use the ns_set directly. if { [info exists cache_key] } { return [ns_cache eval $cache_pool $cache_key { db_with_handle -dbn $dbn db { set selection [db_exec select $db $full_statement_name $sql] set result [list] while { [db_getrow $db $selection] } { lappend result [ns_set value $selection 0] } } set result }] } db_with_handle -dbn $dbn db { set selection [db_exec select $db $full_statement_name $sql] set result [list] while { [db_getrow $db $selection] } { lappend result [ns_set value $selection 0] } } return $result } ad_proc -public db_list_of_lists { { -dbn "" } -cache_key {-cache_pool db_cache_pool} statement_name sql args } { Usage: db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] @return a Tcl list, each element of which is a list of all column values in a row of the result of the SQL querysql. If sql doesn't return any rows, returns an empty list. It checks if the element is I18N and replaces it, thereby reducing the need to do this with every single package @param dbn The database name to use. If empty_string, uses the default database. @param cache_key Cache the result using given value as the key. Default is to not cache. @param cache_pool Override the default db_cache_pool } { ad_arg_parser { bind } $args # Query Dispatcher (OpenACS - SDW) set full_statement_name [db_qd_get_fullname $statement_name] # Can't use db_foreach here, since we need to use the ns_set directly. if { [info exists cache_key] } { return [ns_cache eval $cache_pool $cache_key { db_with_handle -dbn $dbn db { set selection [db_exec select $db $full_statement_name $sql] set result [list] while { [db_getrow $db $selection] } { set this_result [list] for { set i 0 } { $i < [ns_set size $selection] } { incr i } { lappend this_result [ns_set value $selection $i] } lappend result $this_result } } set result }] } db_with_handle -dbn $dbn db { set selection [db_exec select $db $full_statement_name $sql] set result [list] while { [db_getrow $db $selection] } { set this_result [list] for { set i 0 } { $i < [ns_set size $selection] } { incr i } { lappend this_result [ns_set value $selection $i] } lappend result $this_result } } return $result } ad_proc -public db_list_of_ns_sets { { -dbn "" } statement_name sql args } { Usage: db_list_of_ns_sets statement-name sql [ -bind bind_set_id | -bind bind_value_list ] @return a list of ns_sets with the values of each column of each row returned by the sql query specified. @param statement_name The name of the query. @param sql The SQL to be executed. @param args Any additional arguments. @return list of ns_sets, one per each row return by the SQL query @param dbn The database name to use. If empty_string, uses the default database. } { ad_arg_parser { bind } $args set full_statement_name [db_qd_get_fullname $statement_name] db_with_handle -dbn $dbn db { set result [list] set selection [db_exec select $db $full_statement_name $sql] while {[db_getrow $db $selection]} { lappend result [ns_set copy $selection] } } return $result } ad_proc -public db_foreach {{ -dbn "" } statement_name sql args } { Usage:
    db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ] \ code_block [ if_no_rows if_no_rows_block ]

    Performs the SQL query sql, executing code_block once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes if_no_rows_block (if provided).

    Example:

    db_foreach greeble_query "select foo, bar from greeble" {
            ns_write "<li>foo=$foo; bar=$bar\n"
        } if_no_rows {
            # This block is optional.
            ns_write "<li>No greebles!\n"
        }
    @param dbn The database name to use. If empty_string, uses the default database. } { # Query Dispatcher (OpenACS - ben) set full_statement_name [db_qd_get_fullname $statement_name] ad_arg_parser { bind column_array column_set args } $args # Do some syntax checking. set arglength [llength $args] if { $arglength == 1 } { # Have only a code block. set code_block [lindex $args 0] } elseif { $arglength == 3 } { # Should have code block + if_no_rows + code block. if { [lindex $args 1] ne "if_no_rows" && [lindex $args 1] ne "else" } { return -code error "Expected if_no_rows as second-to-last argument" } set code_block [lindex $args 0] set if_no_rows_code_block [lindex $args 2] } else { return -code error "Expected 1 or 3 arguments after switches" } if { [info exists column_array] && [info exists column_set] } { return -code error "Can't specify both column_array and column_set" } if { [info exists column_array] } { upvar 1 $column_array array_val } if { [info exists column_set] } { upvar 1 $column_set selection } db_with_handle -dbn $dbn db { set selection [db_exec select $db $full_statement_name $sql] set counter 0 while { [db_getrow $db $selection] } { incr counter if { [info exists array_val] } { unset array_val } if { ![info exists column_set] } { for { set i 0 } { $i < [ns_set size $selection] } { incr i } { if { [info exists column_array] } { set array_val([ns_set key $selection $i]) [ns_set value $selection $i] } else { upvar 1 [ns_set key $selection $i] column_value set column_value [ns_set value $selection $i] } } } set errno [catch { uplevel 1 $code_block } error] # Handle or propagate the error. Can't use the usual "return -code $errno..." trick # due to the db_with_handle wrapped around this loop, so propagate it explicitly. switch $errno { 0 { # TCL_OK } 1 { # TCL_ERROR global errorInfo errorCode error $error $errorInfo $errorCode } 2 { # TCL_RETURN error "Cannot return from inside a db_foreach loop" } 3 { # TCL_BREAK ns_db flush $db break } 4 { # TCL_CONTINUE - just ignore and continue looping. } default { error "Unknown return code: $errno" } } } # If the if_no_rows_code is defined, go ahead and run it. if { $counter == 0 && [info exists if_no_rows_code_block] } { uplevel 1 $if_no_rows_code_block } } } proc db_multirow_helper {} { uplevel 1 { if { !$append_p || ![info exists counter]} { set counter 0 } db_with_handle -dbn $dbn db { set selection [db_exec select $db $full_statement_name $sql] set local_counter 0 # Make sure 'next_row' array doesn't exist # The this_row and next_row variables are used to always execute the code block one result set row behind, # so that we have the opportunity to peek ahead, which allows us to do group by's inside # the multirow generation # Also make the 'next_row' array available as a magic __db_multirow__next_row variable upvar 1 __db_multirow__next_row next_row if { [info exists next_row] } { unset next_row } set more_rows_p 1 while { 1 } { if { $more_rows_p } { set more_rows_p [db_getrow $db $selection] } else { break } # Setup the 'columns' part, now that we know the columns in the result set # And save variables which we might clobber, if '-unclobber' switch is specified. if { $local_counter == 0 } { for { set i 0 } { $i < [ns_set size $selection] } { incr i } { lappend local_columns [ns_set key $selection $i] } set local_columns [concat $local_columns $extend] if { !$append_p || ![info exists columns] } { # store the list of columns in the var_name:columns variable set columns $local_columns } else { # Check that the columns match, if not throw an error if { ![string equal [join [lsort -ascii $local_columns]] [join [lsort -ascii $columns]]] } { error "Appending to a multirow with differing columns. Original columns : [join [lsort -ascii $columns] ", "]. Columns in this query: [join [lsort -ascii $local_columns] ", "]" "" "ACS_MULTIROW_APPEND_COLUMNS_MISMATCH" } } # Save values of columns which we might clobber if { $unclobber_p && $code_block ne "" } { foreach col $columns { upvar 1 $col column_value __saved_$col column_save if { [info exists column_value] } { if { [array exists column_value] } { array set column_save [array get column_value] } else { set column_save $column_value } # Clear the variable unset column_value } } } } if { $code_block eq "" } { # No code block - pull values directly into the var_name array. # The extra loop after the last row is only for when there's a code block if { !$more_rows_p } { break } incr counter upvar $level_up "$var_name:$counter" array_val set array_val(rownum) $counter for { set i 0 } { $i < [ns_set size $selection] } { incr i } { set array_val([ns_set key $selection $i]) \ [ns_set value $selection $i] } } else { # There is a code block to execute # Copy next_row to this_row, if it exists if { [info exists this_row] } { unset this_row } set array_get_next_row [array get next_row] if { $array_get_next_row ne "" } { array set this_row [array get next_row] } # Pull values from the query into next_row if { [info exists next_row] } { unset next_row } if { $more_rows_p } { for { set i 0 } { $i < [ns_set size $selection] } { incr i } { set next_row([ns_set key $selection $i]) [ns_set value $selection $i] } } # Process the row if { [info exists this_row] } { # Pull values from this_row into local variables foreach name [array names this_row] { upvar 1 $name column_value set column_value $this_row($name) } # Initialize the "extend" columns to the empty string foreach column_name $extend { upvar 1 $column_name column_value set column_value "" } # Execute the code block set errno [catch { uplevel 1 $code_block } error] # Handle or propagate the error. Can't use the usual # "return -code $errno..." trick due to the db_with_handle # wrapped around this loop, so propagate it explicitly. switch $errno { 0 { # TCL_OK } 1 { # TCL_ERROR global errorInfo errorCode error $error $errorInfo $errorCode } 2 { # TCL_RETURN error "Cannot return from inside a db_multirow loop" } 3 { # TCL_BREAK ns_db flush $db break } 4 { # TCL_CONTINUE continue } default { error "Unknown return code: $errno" } } # Pull the local variables back out and into the array. incr counter upvar $level_up "$var_name:$counter" array_val set array_val(rownum) $counter foreach column_name $columns { upvar 1 $column_name column_value set array_val($column_name) $column_value } } } incr local_counter } } # Restore values of columns which we've saved if { $unclobber_p && $code_block ne "" && $local_counter > 0 } { foreach col $columns { upvar 1 $col column_value __saved_$col column_save # Unset it first, so the road's paved to restoring if { [info exists column_value] } { unset column_value } # Restore it if { [info exists column_save] } { if { [array exists column_save] } { array set column_value [array get column_save] } else { set column_value $column_save } # And then remove the saved col unset column_save } } } # Unset the next_row variable, just in case if { [info exists next_row] } { unset next_row } } } ad_proc -public db_multirow { -local:boolean -append:boolean {-upvar_level 1} -unclobber:boolean {-extend {}} {-dbn ""} -cache_key {-cache_pool db_cache_pool} var_name statement_name sql args } { @param dbn The database name to use. If empty_string, uses the default database. @param cache_key Cache the result using given value as the key. Default is to not cache. @param cache_pool Override the default db_cache_pool @param unclobber If set, will cause the proc to not overwrite local variables. Actually, what happens is that the local variables will be overwritten, so you can access them within the code block. However, if you specify -unclobber, we will revert them to their original state after execution of this proc. Usage:
    db_multirow [ -local ] [ -upvar_level n_levels_up ] [ -append ] [ -extend column_list ] \ var-name statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ code_block [ if_no_rows if_no_rows_block ]

    Performs the SQL query sql, saving results in variables of the form var_name:1, var_name:2, etc, setting var_name:rowcount to the total number of rows, and setting var_name:columns to a list of column names.

    If "cache_key" is set, cache the array that results from the query *and* any code block for future use. When this result is returned from cache, THE CODE BLOCK IS NOT EXECUTED. Therefore any values calculated by the code block that aren't listed as arguments to "extend" will not be created. In practice this impacts relatively few queries, but do take care.

    You can not simultaneously append to and cache a non-empty multirow.

    Each row also has a column, rownum, automatically added and set to the row number, starting with 1. Note that this will override any column in the SQL statement named 'rownum', also if you're using the Oracle rownum pseudo-column.

    If the -local is passed, the variables defined by db_multirow will be set locally (useful if you're compiling dynamic templates in a function or similar situations). Use the -upvar_level switch to specify how many levels up the variable should be set.

    You may supply a code block, which will be executed for each row in the loop. This is very useful if you need to make computations that are better done in Tcl than in SQL, for example using ns_urlencode or ad_quotehtml, etc. When the Tcl code is executed, all the columns from the SQL query will be set as local variables in that code. Any changes made to these local variables will be copied back into the multirow.

    You may also add additional, computed columns to the multirow, using the -extend { col_1 col_2 ... } switch. This is useful for things like constructing a URL for the object retrieved by the query.

    If you're constructing your multirow through multiple queries with the same set of columns, but with different rows, you can use the -append switch. This causes the rows returned by this query to be appended to the rows already in the multirow, instead of starting a clean multirow, as is the normal behavior. The columns must match the columns in the original multirow, or an error will be thrown.

    Your code block may call continue in order to skip a row and not include it in the multirow. Or you can call break to skip this row and quit looping.

    Notice the nonstandard numbering (everything else in Tcl starts at 0); the reason is that the graphics designer, a non programmer, may wish to work with row numbers.

    Example:

    db_multirow -extend { user_url } users users_query {
        select user_id first_names, last_name, email from cc_users
    } {
        set user_url [acs_community_member_url -user_id $user_id]
    }
    @see template::multirow } { # Query Dispatcher (OpenACS - ben) set full_statement_name [db_qd_get_fullname $statement_name] if { $local_p } { set level_up $upvar_level } else { set level_up \#[template::adp_level] } ad_arg_parser { bind args } $args # Do some syntax checking. set arglength [llength $args] if { $arglength == 0 } { # No code block. set code_block "" } elseif { $arglength == 1 } { # Have only a code block. set code_block [lindex $args 0] } elseif { $arglength == 3 } { # Should have code block + if_no_rows + code block. if { [lindex $args 1] ne "if_no_rows" \ && [lindex $args 1] ne "else" } { return -code error "Expected if_no_rows as second-to-last argument" } set code_block [lindex $args 0] set if_no_rows_code_block [lindex $args 2] } else { return -code error "Expected 1 or 3 arguments after switches" } upvar $level_up "$var_name:rowcount" counter upvar $level_up "$var_name:columns" columns if { [info exists cache_key] && $append_p && [info exists counter] && $counter > 0 } { return -code error "Can't append and cache a non-empty multirow datasource simultaneously" } if { [info exists cache_key] } { set value [ns_cache eval $cache_pool $cache_key { db_multirow_helper set values [list] for { set count 1 } { $count <= $counter } { incr count } { upvar $level_up "$var_name:[expr {$count}]" array_val lappend values [array get array_val] } return [list $counter $columns $values] }] set counter [lindex $value 0] set columns [lindex $value 1] set values [lindex $value 2] set count 1 foreach value $values { upvar $level_up "$var_name:[expr {$count}]" array_val array set array_val $value incr count } } else { db_multirow_helper } # If the if_no_rows_code is defined, go ahead and run it. if { $counter == 0 && [info exists if_no_rows_code_block] } { uplevel 1 $if_no_rows_code_block } } ad_proc -public db_multirow_group_last_row_p { {-column:required} } { Used inside the code_block to db_multirow to ask whether this row is the last row before the value of 'column' changes, or the last row of the result set.

    This is useful when you want to build up a multirow for a master/slave table pair, where you only want one row per row in the master table, but you want to include data from the slave table in a column of the multirow.

    Here's an example:

        # Initialize the lines variable to hold a list of order line summaries
        set lines [list]
    
        # Start building the multirow. We add the dynamic column 'lines_pretty', which will
        # contain the pretty summary of the order lines.
        db_multirow -extend { lines_pretty } orders select_orders_and_lines { 
            select o.order_id, 
                   o.customer_name,
                   l.item_name,
                   l.quantity
            from   orders o,
                   order_lines l
            where  l.order_id = o.order_id
            order  by o.order_id, l.item_name
        } {
            lappend lines "$quantity $item_name"
            if { [db_multirow_group_last_row_p -column order_id] } {
                # Last row of this order, prepare the pretty version of the order lines
                set lines_pretty [join $lines ", "]
    
                # Reset the lines list, so we start from a fresh with the next row
                set lines [list]
            } else {
                # There are yet more order lines to come for this order,
                # continue until we've collected all the order lines
                # The 'continue' keyword means this line will not be added to the resulting multirow
                continue
            }
        }
    
    @author Lars Pind (lars@collaboraid.biz) @param column The name of the column defining the groups. @return 1 if this is the last row before the column value changes, 0 otherwise. } { upvar 1 __db_multirow__next_row next_row if { ![info exists next_row] } { # If there is no next row, this is the last row return 1 } upvar 1 $column column_value # Otherwise, it's the last row in the group if the next row has a different value than this row return [expr {$column_value ne $next_row($column) }] } ad_proc -public db_dml {{ -dbn "" } statement_name sql args } { Do a DML statement.

    args can be one of: -clobs, -blobs, -clob_files or -blob_files. See the db-api doc referenced below for more information. @param dbn The database name to use. If empty_string, uses the default database. @see /doc/db-api-detailed.html } { ad_arg_parser { clobs blobs clob_files blob_files bind } $args set driverkey [db_driverkey $dbn] switch $driverkey { postgresql { set postgres_p 1 } oracle - nsodbc - default { set postgres_p 0 } } # Query Dispatcher (OpenACS - ben) set full_statement_name [db_qd_get_fullname $statement_name] # This "only one of..." check didn't exist in the PostgreSQL # version, but it shouldn't't hurt anything: --atp@piskorski.com, # 2003/04/08 06:19 EDT # Only one of clobs, blobs, clob_files, and blob_files is allowed. # Remember which one (if any) is provided: set lob_argc 0 set lob_argv [list] set command "dml" if { [info exists clobs] } { set command "clob_dml" set lob_argv $clobs incr lob_argc } if { [info exists blobs] } { set command "blob_dml" set lob_argv $blobs incr lob_argc } if { [info exists clob_files] } { set command "clob_dml_file" set lob_argv $clob_files incr lob_argc } if { [info exists blob_files] } { set command "blob_dml_file" set lob_argv $blob_files incr lob_argc } if { $lob_argc > 1 } { error "Only one of -clobs, -blobs, -clob_files, or -blob_files may be specified as an argument to db_dml" } if { ! $postgres_p } { # Oracle: db_with_handle -dbn $dbn db { if { $lob_argc == 1 } { # Bind :1, :2, ..., :n as LOBs (where n = [llength $lob_argv]) set bind_vars [list] for { set i 1 } { $i <= [llength $lob_argv] } { incr i } { lappend bind_vars $i } eval [list db_exec "${command}_bind" $db $full_statement_name $sql 2 $bind_vars] $lob_argv } else { eval [list db_exec $command $db $full_statement_name $sql] $lob_argv } } } elseif {$command eq "blob_dml_file"} { # PostgreSQL: db_with_handle -dbn $dbn db { # another ugly hack to avoid munging tcl files. # __lob_id needs to be set inside of a query (.xql) file for this # to work. Say for example that you need to create a lob. In # Oracle, you would do something like: # db_dml update_photo "update foo set bar = empty_blob() # where bar = :bar # returning foo into :1" -blob_files [list $file] # for postgresql we can do the equivalent by placing the following # in a query file: # update foo set bar = [set __lob_id [db_string get_id "select empty_lob()"]] # where bar = :bar # __lob_id acts as a flag that signals that blob_dml_file is # required, and it is also used to pass along the lob_id. It # is unsert afterwards to avoid name clashes with other invocations # of this routine. # (DanW - Openacs) db_exec dml $db $full_statement_name $sql if {[uplevel {info exists __lob_id}]} { ns_pg blob_dml_file $db [uplevel {set __lob_id}] $blob_files uplevel {unset __lob_id} } } } else { # PostgreSQL: db_with_handle -dbn $dbn db { db_exec dml $db $full_statement_name $sql } } } ad_proc -public db_resultrows {{ -dbn "" }} { @return the number of rows affected by the last DML command. @param dbn The database name to use. If empty_string, uses the default database. } { upvar "#0" [db_state_array_name_is -dbn $dbn] db_state set driverkey [db_driverkey $dbn] switch $driverkey { oracle { return [ns_ora resultrows $db_state(last_used)] } postgresql { return [ns_pg ntuples $db_state(last_used)] } nsodbc { error "db_resultrows is not supported for this database." } default { error "Unknown database driver. db_resultrows is not supported for this database." } } } ad_proc -public db_0or1row { {-dbn ""} -cache_key {-cache_pool db_cache_pool} statement_name sql args } { Usage:

    db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ]

    Performs the SQL query sql. If a row is returned, sets variables to column values (or a set or array populated if -column_array or column_set is specified) and returns 1. If no rows are returned, returns 0. @return 1 if variables are set, 0 if no rows are returned. If more than one row is returned, throws an error. @param dbn The database name to use. If empty_string, uses the default database. @param cache_key Cache the result using given value as the key. Default is to not cache. @param cache_pool Override the default db_cache_pool } { ad_arg_parser { bind column_array column_set } $args # Query Dispatcher (OpenACS - ben) set full_statement_name [db_qd_get_fullname $statement_name] if { [info exists column_array] && [info exists column_set] } { return -code error "Can't specify both column_array and column_set" } if { [info exists column_array] } { upvar 1 $column_array array_val if { [info exists array_val] } { unset array_val } } if { [info exists column_set] } { upvar 1 $column_set selection } if { [info exists cache_key] } { set values [ns_cache eval $cache_pool $cache_key { db_with_handle -dbn $dbn db { set selection [db_exec 0or1row $db $full_statement_name $sql] } set values [list] if { $selection ne "" } { for {set i 0} { $i < [ns_set size $selection] } {incr i} { lappend values [list [ns_set key $selection $i] [ns_set value $selection $i]] } } set values }] if { $values eq "" } { set selection "" } else { set selection [ns_set create] foreach value $values { ns_set put $selection [lindex $value 0] [lindex $value 1] } } } else { db_with_handle -dbn $dbn db { set selection [db_exec 0or1row $db $full_statement_name $sql] } } if { $selection eq "" } { return 0 } if { [info exists column_array] } { for { set i 0 } { $i < [ns_set size $selection] } { incr i } { set array_val([ns_set key $selection $i]) [ns_set value $selection $i] } } elseif { ![info exists column_set] } { for { set i 0 } { $i < [ns_set size $selection] } { incr i } { upvar 1 [ns_set key $selection $i] return_value set return_value [ns_set value $selection $i] } } return 1 } ad_proc -public db_1row { args } { Usage:

    db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ [ -column_array array_name | -column_set set_name ]

    Performs the SQL query sql. If a row is returned, sets variables to column values (or a set or array populated if -column_array or column_set is specified). If no rows are returned, throws an error. @return 1 if variables are set. @param dbn The database name to use. If empty_string, uses the default database. @param cache_key Cache the result using given value as the key. Default is to not cache. @param cache_pool Override the default db_cache_pool } { if { ![uplevel db_0or1row $args] } { return -code error "Query did not return any rows." } } ad_proc -public db_transaction {{ -dbn ""} transaction_code args } { Usage: db_transaction transaction_code [ on_error { error_code_block } ] Executes transaction_code with transactional semantics. This means that either all of the database commands within transaction_code are committed to the database or none of them are. Multiple db_transactions may be nested (end transaction is transparently ns_db dml'ed when the outermost transaction completes).

    To handle errors, use db_transaction {transaction_code} on_error {error_code_block}. Any error generated in transaction_code will be caught automatically and process control will transfer to error_code_block with a variable errmsg set. The error_code block can then clean up after the error, such as presenting a usable error message to the user. Following the execution of error_code_block the transaction will be aborted. If you want to explicity abort the transaction, call db_abort_transaction from within the transaction_code block or the error_code block.

    Example 1:
    In this example, db_dml triggers an error, so control passes to the on_error block which prints a readable error.

        db_transaction {
            db_dml test "nonsense"
        } on_error {
            ad_return_error "Error in blah/foo/bar" "The error was: $errmsg"
        }
        
    Example 2:
    In this example, the second command, "nonsense" triggers an error. There is no on_error block, so the transaction is immediately halted and aborted.
        db_transaction {
            db_dml test {insert into footest values(1)}
            nonsense
            db_dml test {insert into footest values(2)}
        } 
        
    @param dbn The database name to use. If empty_string, uses the default database. } { upvar "#0" [db_state_array_name_is -dbn $dbn] db_state set syn_err "db_transaction: Invalid arguments. Use db_transaction { code } \[on_error { error_code_block }\] " set arg_c [llength $args] if { $arg_c != 0 && $arg_c != 2 } { # Either this is a transaction with no error handling or there must be an on_error { code } block. error $syn_err } elseif { $arg_c == 2 } { # We think they're specifying an on_error block if {[lindex $args 0] ne "on_error" } { # Unexpected: they put something besides on_error as a connector. error $syn_err } else { # Success! We got an on_error code block. set on_error [lindex $args 1] } } # Make the error message and database handle available to the on_error block. upvar errmsg errmsg db_with_handle -dbn $dbn db { # Preserve the handle, since db_with_handle kills it after executing # this block. set dbh $db # Remember that there's a transaction happening on this handle. if { ![info exists db_state(transaction_level,$dbh)] } { set db_state(transaction_level,$dbh) 0 } set level [incr db_state(transaction_level,$dbh)] if { $level == 1 } { ns_db dml $dbh "begin transaction" } } # Execute the transaction code. set errno [catch { uplevel 1 $transaction_code } errmsg] incr db_state(transaction_level,$dbh) -1 set err_p 0 switch $errno { 0 { # TCL_OK } 2 { # TCL_RETURN } 3 { # TCL_BREAK - Abort the transaction and do the break. ns_db dml $dbh "abort transaction" db_release_unused_handles -dbn $dbn break } 4 { # TCL_CONTINUE - just ignore. } default { # TCL_ERROR or unknown error code: Its a real error. set err_p 1 } } if { $err_p || [db_abort_transaction_p -dbn $dbn]} { # An error was triggered or the transaction has been aborted. db_abort_transaction -dbn $dbn if { [info exists on_error] && $on_error ne "" } { if {"postgresql" eq [db_type]} { # JCD: with postgres we abort the transaction prior to # executing the on_error block since there is nothing # you can do to "fix it" and keeping it meant things like # queries in the on_error block would then fail. # # Note that the semantics described in the proc doc # are not possible to support on postresql. # DRB: I removed the db_release_unused_handles call that # this patch included because additional aborts further # down triggered an illegal db handle error. I'm going to # have the code start a new transaction as well. If we # don't, if a transaction fails and the on_error block # fails, the on_error block DML will have been committed. # Starting a new transaction here means that DML by both # the transaction and on_error clause will be rolled back. # On the other hand, if the on_error clause doesn't fail, # any DML in that block will be committed. This seems more # useful than simply punting ... ns_db dml $dbh "abort transaction" ns_db dml $dbh "begin transaction" } # An on_error block exists, so execute it. set errno [catch { uplevel 1 $on_error } on_errmsg] # Determine what do with the error. set err_p 0 switch $errno { 0 { # TCL_OK } 2 { # TCL_RETURN } 3 { # TCL_BREAK ns_db dml $dbh "abort transaction" db_release_unused_handles break } 4 { # TCL_CONTINUE - just ignore. } default { # TCL_ERROR or unknown error code: Its a real error. set err_p 1 } } if { $err_p } { # An error was generated from the $on_error block. if { $level == 1} { # We're at the top level, so we abort the transaction. set db_state(db_abort_p,$dbh) 0 ns_db dml $dbh "abort transaction" } # We throw this error because it was thrown from the error handling code that the programmer must fix. global errorInfo errorCode error $on_errmsg $errorInfo $errorCode } else { # Good, no error thrown by the on_error block. if { [db_abort_transaction_p -dbn $dbn] } { # This means we should abort the transaction. if { $level == 1 } { set db_state(db_abort_p,$dbh) 0 ns_db dml $dbh "abort transaction" # We still have the transaction generated error. We don't want to throw it, so we log it. ns_log Error "Aborting transaction due to error:\n$errmsg" } else { # Propagate the error up to the next level. global errorInfo errorCode error $errmsg $errorInfo $errorCode } } else { # The on_error block has resolved the transaction error. If we're at the top, commit and exit. # Otherwise, we continue on through the lower transaction levels. if { $level == 1} { ns_db dml $dbh "end transaction" } } } } else { # There is no on_error block, yet there is an error, so we propagate it. if { $level == 1 } { set db_state(db_abort_p,$dbh) 0 ns_db dml $dbh "abort transaction" global errorInfo errorCode error "Transaction aborted: $errmsg" $errorInfo $errorCode } else { db_abort_transaction -dbn $dbn global errorInfo errorCode error $errmsg $errorInfo $errorCode } } } else { # There was no error from the transaction code. if { [db_abort_transaction_p -dbn $dbn] } { # The user requested the transaction be aborted. if { $level == 1 } { set db_state(db_abort_p,$dbh) 0 ns_db dml $dbh "abort transaction" } } elseif { $level == 1 } { # Success! No errors and no requested abort. Commit. ns_db dml $dbh "end transaction" } } } ad_proc -public db_abort_transaction {{ -dbn "" }} { Aborts all levels of a transaction. That is if this is called within several nested transactions, all of them are terminated. Use this instead of db_dml "abort" "abort transaction". @param dbn The database name to use. If empty_string, uses the default database. } { upvar "#0" [db_state_array_name_is -dbn $dbn] db_state db_with_handle -dbn $dbn db { # We set the abort flag to true. set db_state(db_abort_p,$db) 1 } } ad_proc -private db_abort_transaction_p {{ -dbn "" }} { @param dbn The database name to use. If empty_string, uses the default database. } { upvar "#0" [db_state_array_name_is -dbn $dbn] db_state db_with_handle -dbn $dbn db { if { [info exists db_state(db_abort_p,$db)] } { return $db_state(db_abort_p,$db) } else { # No abort flag registered, so we assume everything is ok. return 0 } } } ad_proc -public db_name {{ -dbn "" }} { @return the name of the database as reported by the driver. @param dbn The database name to use. If empty_string, uses the default database. } { db_with_handle -dbn $dbn db { set dbtype [ns_db dbtype $db] } return $dbtype } ad_proc -public db_get_username {{ -dbn "" }} { @return the username parameter from the driver section of the first database pool for the dbn. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] return [ns_config "ns/db/pool/$pool" User] } ad_proc -public db_get_password {{ -dbn "" }} { @return the password parameter from the driver section of the first database pool for the dbn. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] return [ns_config "ns/db/pool/$pool" Password] } ad_proc -public db_get_sql_user {{ -dbn "" }} { Oracle only.

    @return a valid Oracle user@database/password string to access a database through sqlplus.

    This proc may well work for databases other than Oracle, but its return value won't really be of any use. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] set datasource [ns_config "ns/db/pool/$pool" DataSource] if { $datasource ne "" && ![string is space $datasource] } { return "[ns_config ns/db/pool/$pool User]/[ns_config ns/db/pool/$pool Password]@$datasource" } else { return "[ns_config ns/db/pool/$pool User]/[ns_config ns/db/pool/$pool Password]" } } ad_proc -public db_get_pgbin {{ -dbn "" }} { PostgreSQL only.

    @return the pgbin parameter from the driver section of the first database pool. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] set driver [ns_config "ns/db/pool/$pool" Driver] return [ns_config "ns/db/driver/$driver" pgbin] } ad_proc -public db_get_port {{ -dbn "" }} { PostgreSQL only.

    @return the port number from the first database pool. It assumes the datasource is properly formatted since we've already verified that we can connect to the pool. It returns an empty string for an empty port value. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] set datasource [ns_config "ns/db/pool/$pool" DataSource] set last_colon_pos [string last ":" $datasource] if { $last_colon_pos == -1 } { ns_log Error "datasource contains no \":\"? datasource = $datasource" return "" } set first_colon_pos [string first ":" $datasource] if { $first_colon_pos == $last_colon_pos || [expr {$last_colon_pos - $first_colon_pos}] == 1 } { # No port specified return "" } return [string range $datasource [expr {$first_colon_pos + 1}] [expr {$last_colon_pos - 1}] ] } ad_proc -public db_get_database {{ -dbn "" }} { PostgreSQL only.

    @return the database name from the first database pool. It assumes the datasource is properly formatted since we've already verified that we can connect to the pool. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] set datasource [ns_config "ns/db/pool/$pool" DataSource] set last_colon_pos [string last ":" $datasource] if { $last_colon_pos == -1 } { ns_log Error "datasource contains no \":\"? datasource = $datasource" return "" } return [string range $datasource [expr {$last_colon_pos + 1}] end] } ad_proc -public db_get_dbhost {{ -dbn "" }} { PostgreSQL only.

    @return the name of the database host from the first database pool. It assumes the datasource is properly formatted since we've already verified that we can connect to the pool. @param dbn The database name to use. If empty_string, uses the default database. } { set pool [lindex [db_available_pools $dbn] 0] set datasource [ns_config "ns/db/pool/$pool" DataSource] set first_colon_pos [string first ":" $datasource] if { $first_colon_pos == -1 } { ns_log Error "datasource contains no \":\"? datasource = $datasource" return "" } return [string range $datasource 0 [expr {$first_colon_pos - 1}]] } ad_proc -public db_source_sql_file {{ -dbn "" -callback apm_ns_write_callback } file } { Sources a SQL file into Oracle (SQL*Plus format file) or PostgreSQL (psql format file). @param dbn The database name to use. If empty_string, uses the default database. } { set proc_name {db_source_sql_file} set driverkey [db_driverkey $dbn] switch $driverkey { oracle { global env set user_pass [db_get_sql_user -dbn $dbn] cd [file dirname $file] set fp [open "|[file join $env(ORACLE_HOME) bin sqlplus] $user_pass @$file" "r"] while { [gets $fp line] >= 0 } { # Don't bother writing out lines which are purely whitespace. if { ![string is space $line] } { apm_callback_and_log $callback "[ad_quotehtml $line]\n" } } close $fp } postgresql { global tcl_platform set file_name [file tail $file] set pguser [db_get_username] if { $pguser ne "" } { set pguser "-U $pguser" } set pgport [db_get_port] if { $pgport ne "" } { set pgport "-p $pgport" } set pgpass [db_get_password] if { $pgpass ne "" } { set pgpass "<<$pgpass" } # DRB: Submitted patch was in error - the driver opens a -h hostname connection # unless the hostname is localhost. We need to do the same here. The submitted # patch checked for a blank hostname, which fails in the driver. Arguably the # driver's wrong but a lot of non-OpenACS folks use it, and even though I'm the # maintainer we shouldn't break existing code over such trivialities... if { [string equal [db_get_dbhost] "localhost"] || [string equal [db_get_dbhost] ""] } { set pghost "" } else { set pghost "-h [db_get_dbhost]" } cd [file dirname $file] if { $tcl_platform(platform) eq "windows" } { set fp [open "|[file join [db_get_pgbin] psql] $pghost $pgport $pguser -f $file_name [db_get_database] $pgpass" "r"] } else { set fp [open "|[file join [db_get_pgbin] psql] $pghost $pgport $pguser -f $file_name [db_get_database] $pgpass" "r"] } while { [gets $fp line] >= 0 } { # Don't bother writing out lines which are purely whitespace. if { ![string is space $line] } { apm_callback_and_log $callback "[ad_quotehtml $line]\n" } } # PSQL dumps errors and notice information on stderr, and has no option to turn # this off. So we have to chug through the "error" lines looking for those that # really signal an error. set errno [ catch { close $fp } error] if { $errno == 2 } { return $error } # Just filter out the "NOTICE" lines, so we get the stack dump along with real # ERRORs. This could be done with a couple of opaque-looking regexps... set error_found 0 foreach line [split $error "\n"] { if { [string first NOTICE $line] == -1 } { append error_lines "$line\n" set error_found [expr { $error_found || [string first ERROR $line] != -1 || \ [string first FATAL $line] != -1 } ] } } if { $error_found } { global errorCode return -code error -errorinfo $error_lines -errorcode $errorCode $error_lines } } nsodbc { error "$proc_name is not supported for this database." } default { error "$proc_name is not supported for this database." } } } ad_proc -public db_load_sql_data {{ -dbn "" -callback apm_ns_write_callback } file } { Loads a CSV formatted file into a table using PostgreSQL's COPY command or Oracle's SQL*Loader utility. The file name format consists of a sequence number used to control the order in which tables are loaded, and the table name with "-" replacing "_". This is a bit of a kludge but greatly speeds the loading of large amounts of data, such as is done when various "ref-*" packages are installed. @param dbn The database name to use. If empty_string, uses the default database. @file Filename in the format dd-table-name.ctl where 'dd' is a sequence number used to control the order in which data is loaded. This file is an RDBMS-specific data loader control file. } { switch [db_driverkey $dbn] { oracle { global env set user_pass [db_get_sql_user -dbn $dbn] set tmpnam [ns_tmpnam] set fd [open $file r] set file_contents [read $fd] close $fd set file_contents [subst $file_contents] set fd1 [open "${tmpnam}.ctl" w] puts $fd1 $file_contents close $fd1 cd [file dirname $file] set fd [open "|[file join $env(ORACLE_HOME) bin sqlldr] userid=$user_pass control=$tmpnam" "r"] while { [gets $fd line] >= 0 } { # Don't bother writing out lines which are purely whitespace. if { ![string is space $line] } { apm_callback_and_log $callback "[ad_quotehtml $line]\n" } } close $fd } postgresql { global tcl_platform set pguser [db_get_username] if { $pguser ne "" } { set pguser "-U $pguser" } set pgport [db_get_port] if { $pgport ne "" } { set pgport "-p $pgport" } set pgpass [db_get_password] if { $pgpass ne "" } { set pgpass "<<$pgpass" } if { [string equal [db_get_dbhost] "localhost"] || [string equal [db_get_dbhost] ""] } { set pghost "" } else { set pghost "-h [db_get_dbhost]" } set fd [open $file r] set copy_command [subst -nobackslashes [read $fd]] close $fd set copy_file [ns_mktemp /tmp/psql-copyfile-XXXXXX] set fd [open $copy_file "CREAT EXCL WRONLY" 0600] puts $fd $copy_command close $fd if { $tcl_platform(platform) eq "windows" } { set fp [open "|[file join [db_get_pgbin] psql] -f $copy_file $pghost $pgport $pguser [db_get_database]" "r"] } else { set fp [open "|[file join [db_get_pgbin] psql] -f $copy_file $pghost $pgport $pguser [db_get_database] $pgpass" "r"] } while { [gets $fp line] >= 0 } { # Don't bother writing out lines which are purely whitespace. if { ![string is space $line] } { apm_callback_and_log $callback "[ad_quotehtml $line]\n" } } # PSQL dumps errors and notice information on stderr, and has no option to turn # this off. So we have to chug through the "error" lines looking for those that # really signal an error. set errno [ catch { close $fp } error] # remove the copy file. file delete -force $copy_file if { $errno == 2 } { return $error } # Just filter out the "NOTICE" lines, so we get the stack dump along with real # ERRORs. This could be done with a couple of opaque-looking regexps... set error_found 0 foreach line [split $error "\n"] { if { [string first NOTICE $line] == -1 } { append error_lines "$line\n" set error_found [expr { $error_found || [string first ERROR $line] != -1 || \ [string first FATAL $line] != -1 } ] } } if { $error_found } { global errorCode return -code error -errorinfo $error_lines -errorcode $errorCode $error_lines } } nsodbc { error "db_load_sql_data is not supported for this database." } default { error "db_load_sql_data is not supported for this database." } } } ad_proc -public db_source_sqlj_file {{ -dbn "" -callback apm_ns_write_callback } file } { Oracle only.

    Sources a SQLJ file using loadjava. @param dbn The database name to use. If empty_string, uses the default database. } { global env set user_pass [db_get_sql_user -dbn $dbn] set fp [open "|[file join $env(ORACLE_HOME) bin loadjava] -verbose -user $user_pass $file" "r"] # Despite the fact that this works, the text does not get written to the stream. # The output is generated as an error when you attempt to close the input stream as # done below. while { [gets $fp line] >= 0 } { # Don't bother writing out lines which are purely whitespace. if { ![string is space $line] } { apm_callback_and_log $callback "[ad_quotehtml $line]\n" } } if { [catch { close $fp } errmsg] } { apm_callback_and_log $callback "[ad_quotehtml $errmsg]\n" } } ad_proc -public db_tables { -pattern {-dbn ""} } { @return a Tcl list of all the tables owned by the connected user. @param pattern Will be used as LIKE 'pattern%' to limit the number of tables returned. @param dbn The database name to use. If empty_string, uses the default database. @author Don Baccus (dhogaza@pacifier.com) @author Lars Pind (lars@pinds.com) @change-log yon@arsdigita.com 20000711 changed to return lower case table names } { set proc_name {db_tables} set driverkey [db_driverkey $dbn] switch $driverkey { oracle { set sql_table_names_with_pattern { select lower(table_name) as table_name from user_tables where table_name like upper(:pattern) } set sql_table_names_without_pattern { select lower(table_name) as table_name from user_tables } } postgresql { set sql_table_names_with_pattern { select relname as table_name from pg_class where relname like lower(:pattern) and relname !~ '^pg_' and relkind = 'r' } set sql_table_names_without_pattern { select relname as table_name from pg_class where relname !~ '^pg_' and relkind = 'r' } } nsodbc - default { error "$proc_name is not supported for this database." } } set tables [list] if { [info exists pattern] } { db_foreach -dbn $dbn table_names_with_pattern \ $sql_table_names_with_pattern { lappend tables $table_name } } else { db_foreach -dbn $dbn table_names_without_pattern \ $sql_table_names_without_pattern { lappend tables $table_name } } return $tables } ad_proc -public db_table_exists {{ -dbn "" } table_name } { @return 1 if a table with the specified name exists in the database, otherwise 0. @param dbn The database name to use. If empty_string, uses the default database. @author Don Baccus (dhogaza@pacifier.com) @author Lars Pind (lars@pinds.com) } { set proc_name {db_table_exists} set driverkey [db_driverkey $dbn] switch $driverkey { oracle { set n_rows [db_string -dbn $dbn table_count { select count(*) from user_tables where table_name = upper(:table_name) }] } postgresql { set n_rows [db_string -dbn $dbn table_count { select count(*) from pg_class where relname = lower(:table_name) and relname !~ '^pg_' and relkind = 'r' }] } nsodbc - default { error "$proc_name is not supported for this database." } } return $n_rows } ad_proc -public db_columns {{ -dbn "" } table_name } { @return a Tcl list of all the columns in the table with the given name. @param dbn The database name to use. If empty_string, uses the default database. @author Lars Pind (lars@pinds.com) @change-log yon@arsdigita.com 20000711 changed to return lower case column names } { set columns [list] # Works for both Oracle and PostgreSQL: db_foreach -dbn $dbn table_column_names { select lower(column_name) as column_name from user_tab_columns where table_name = upper(:table_name) } { lappend columns $column_name } return $columns } ad_proc -public db_column_exists {{ -dbn "" } table_name column_name } { @return 1 if the row exists in the table, 0 if not. @param dbn The database name to use. If empty_string, uses the default database. @author Lars Pind (lars@pinds.com) } { set columns [list] # Works for both Oracle and PostgreSQL: set n_rows [db_string -dbn $dbn column_exists { select count(*) from user_tab_columns where table_name = upper(:table_name) and column_name = upper(:column_name) }] return [expr {$n_rows > 0}] } ad_proc -public db_column_type {{ -dbn "" } table_name column_name } { @return the Oracle Data Type for the specified column. @return -1 if the table or column doesn't exist. @param dbn The database name to use. If empty_string, uses the default database. @author Yon Feldman (yon@arsdigita.com) @change-log 10 July, 2000: changed to return error if column name doesn't exist (mdettinger@arsdigita.com) @change-log 11 July, 2000: changed to return lower case data types (yon@arsdigita.com) @change-log 11 July, 2000: changed to return error using the db_string default clause (yon@arsdigita.com) } { # Works for both Oracle and PostgreSQL: return [db_string -dbn $dbn column_type_select " select data_type as data_type from user_tab_columns where upper(table_name) = upper(:table_name) and upper(column_name) = upper(:column_name) " -default "-1"] } ad_proc -public ad_column_type {{ -dbn "" } table_name column_name } { @return 'numeric' for number type columns, 'text' otherwise Throws an error if no such column exists. @param dbn The database name to use. If empty_string, uses the default database. @author Yon Feldman (yon@arsdigita.com) } { set column_type [db_column_type -dbn $dbn $table_name $column_name] if { $column_type == -1 } { return "Either table $table_name doesn't exist or column $column_name doesn't exist" } elseif {$column_type ne "NUMBER" } { return "numeric" } else { return "text" } } ad_proc -public db_write_clob {{ -dbn "" } statement_name sql args } { @param dbn The database name to use. If empty_string, uses the default database. } { ad_arg_parser { bind } $args set proc_name {db_write_clob} set driverkey [db_driverkey $dbn] # TODO: Below, is db_qd_get_fullname necessary? Why this # difference between Oracle and Postgres code? # --atp@piskorski.com, 2003/04/09 10:00 EDT switch $driverkey { oracle { set full_statement_name [db_qd_get_fullname $statement_name] db_with_handle -dbn $dbn db { db_exec write_clob $db $full_statement_name $sql } } postgresql { db_with_handle -dbn $dbn db { db_exec write_clob $db $statement_name $sql } } nsodbc - default { error "$proc_name is not supported for this database." } } } ad_proc -public db_write_blob {{ -dbn "" } statement_name sql args } { @param dbn The database name to use. If empty_string, uses the default database. } { ad_arg_parser { bind } $args set full_statement_name [db_qd_get_fullname $statement_name] db_with_handle -dbn $dbn db { db_exec_lob write_blob $db $full_statement_name $sql } } ad_proc -public db_blob_get_file {{ -dbn "" } statement_name sql args } { @param dbn The database name to use. If empty_string, uses the default database.

    TODO: This proc should probably be changed to take a final file argument, only, rather than the current args variable length argument list. Currently, it is called only 4 places in OpenACS, and each place args, if used at all, is always "-file $file". However, such a change might break custom code... I'm not sure. --atp@piskorski.com, 2003/04/09 11:39 EDT } { ad_arg_parser { bind file args } $args set proc_name {db_blob_get_file} set driverkey [db_driverkey $dbn] set full_statement_name [db_qd_get_fullname $statement_name] switch $driverkey { oracle { db_with_handle -dbn $dbn db { eval [list db_exec_lob blob_get_file $db $full_statement_name $sql $file] } } postgresql { db_with_handle -dbn $dbn db { db_exec_lob blob_select_file $db $full_statement_name $sql $file } } nsodbc - default { error "$proc_name is not supported for this database." } } } ad_proc -public db_blob_get {{ -dbn "" } statement_name sql args } { PostgreSQL only. @param dbn The database name to use. If empty_string, uses the default database. } { ad_arg_parser { bind } $args set proc_name {db_blob_get} set driverkey [db_driverkey $dbn] switch $driverkey { postgresql { set full_statement_name [db_qd_get_fullname $statement_name] db_with_handle -dbn $dbn db { set data [db_exec_lob blob_get $db $full_statement_name $sql] } return $data } oracle { set pre_sql $sql set full_statement_name [db_qd_get_fullname $statement_name] set sql [db_qd_replace_sql $full_statement_name $pre_sql] # insert tcl variable values (borrowed from Dan W - olah) if {$sql ne $pre_sql } { set sql [uplevel 2 [list subst -nobackslashes $sql]] } set data [db_string dummy_statement_name $sql] return $data } nsodbc - default { error "$proc_name is not supported for this database." } } } ad_proc -private db_exec_lob {{ -ulevel 2 } type db statement_name pre_sql { file "" } } { A helper procedure to execute a SQL statement, potentially binding depending on the value of the $bind variable in the calling environment (if set). } { set proc_name {db_exec_lob} set driverkey [db_driverkey -handle_p 1 $db] # Note: db_exec_lob is marked as private and in the entire # toolkit, is ONLY called from a few other procs defined in this # same file. So we definitely could change it to take a -dbn # switch and remove the passed in db handle altogether, and call # 'db_driverkey -dbn' rather than 'db_driverkey -handle'. But, # db_exec NEEDS 'db_driverkey -handle', so we might as well use it # here too. --atp@piskorski.com, 2003/04/09 12:13 EDT # TODO: Using this as a wrapper for the separate _oracle and # _postgresql versions of this proc is ugly. But also simplest # and safest at this point, as it let me change as little as # possible of those two relatively complex procs. # --atp@piskorski.com, 2003/04/09 11:55 EDT switch $driverkey { oracle { set which_proc {db_exec_lob_oracle} } postgresql { set which_proc {db_exec_lob_postgresql} } nsodbc - default { error "$proc_name is not supported for this database." } } ns_log Debug "$proc_name: $which_proc -ulevel [expr {$ulevel +1}] $type $db $statement_name $pre_sql $file" return [$which_proc -ulevel [expr {$ulevel +1}] $type $db $statement_name $pre_sql $file] } ad_proc -private db_exec_lob_oracle {{ -ulevel 2 } type db statement_name pre_sql { file "" } } { A helper procedure to execute a SQL statement, potentially binding depending on the value of the $bind variable in the calling environment (if set). } { set start_time [clock clicks -milliseconds] set sql [db_qd_replace_sql $statement_name $pre_sql] # insert tcl variable values (Openacs - Dan) if {$sql ne $pre_sql } { set sql [uplevel $ulevel [list subst -nobackslashes $sql]] } set file_storage_p 0 upvar $ulevel storage_type storage_type if {[info exists storage_type] && $storage_type eq "file"} { set file_storage_p 1 set original_type $type set qtype 1row ns_log Debug "db_exec_lob: file storage in use" } else { set qtype $type ns_log Debug "db_exec_lob: blob storage in use" } set errno [catch { upvar bind bind # Below, note that 'ns_ora blob_get_file' takes 3 parameters, # while 'ns_ora write_blob' takes only 2. So if file is empty # string (which it always will/should be for $qtype # write_blob), we must not pass any 3rd parameter to the # ns_ora command: --atp@piskorski.com, 2003/04/09 15:10 EDT if { [info exists bind] && [llength $bind] != 0 } { if { [llength $bind] == 1 } { if { $file eq "" } { set selection [eval [list ns_ora $qtype $db -bind $bind $sql]] } else { set selection [eval [list ns_ora $qtype $db -bind $bind $sql $file]] } } else { set bind_vars [ns_set create] foreach { name value } $bind { ns_set put $bind_vars $name $value } if { $file eq "" } { set selection [eval [list ns_ora $qtype $db -bind $bind_vars $sql]] } else { set selection [eval [list ns_ora $qtype $db -bind $bind_vars $sql $file]] } } } else { if { $file eq "" } { set selection [uplevel $ulevel [list ns_ora $qtype $db $sql]] } else { set selection [uplevel $ulevel [list ns_ora $qtype $db $sql $file]] } } if {$file_storage_p} { set content [ns_set value $selection 0] for {set i 0} {$i < [ns_set size $selection]} {incr i} { set name [ns_set key $selection $i] if {$name eq "content"} { set content [ns_set value $selection $i] } } switch $original_type { blob_get_file { if {[file exists $content]} { file copy -- $content $file return $selection } else { error "file: $content doesn't exist" } } write_blob { if {[file exists $content]} { set ofp [open $content r] fconfigure $ofp -encoding binary ns_writefp $ofp close $ofp return $selection } else { error "file: $content doesn't exist" } } } } else { return $selection } } error] ds_collect_db_call $db $type $statement_name $sql $start_time $errno $error if { $errno == 2 } { return $error } global errorInfo errorCode return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error } ad_proc -private db_exec_lob_postgresql {{ -ulevel 2 } type db statement_name pre_sql { file "" } } { A helper procedure to execute a SQL statement, potentially binding depending on the value of the $bind variable in the calling environment (if set). Low level replacement for db_exec which emulates blob handling. } { set start_time [clock clicks -milliseconds] # Query Dispatcher (OpenACS - ben) set sql [db_qd_replace_sql $statement_name $pre_sql] # insert tcl variable values (Openacs - Dan) if {$sql ne $pre_sql } { set sql [uplevel $ulevel [list subst -nobackslashes $sql]] } # create a function definition statement for the inline code # binding is emulated in tcl. (OpenACS - Dan) set errno [catch { upvar bind bind if { [info exists bind] && [llength $bind] != 0 } { if { [llength $bind] == 1 } { set bind_vars [list] set len [ns_set size $bind] for {set i 0} {$i < $len} {incr i} { lappend bind_vars [ns_set key $bind $i] \ [ns_set value $bind $i] } set lob_sql [db_bind_var_substitution $sql $bind_vars] } else { set lob_sql [db_bind_var_substitution $sql $bind] } } else { set lob_sql [uplevel $ulevel [list db_bind_var_substitution $sql]] } # get the content - asssume it is in column 0, or optionally it can # be returned as "content" with the storage type indicated by the # "storage_type" column. set selection [ns_db 1row $db $lob_sql] set content [ns_set value $selection 0] for {set i 0} {$i < [ns_set size $selection]} {incr i} { set name [ns_set key $selection $i] if {$name eq "storage_type"} { set storage_type [ns_set value $selection $i] } elseif {$name eq "content"} { set content [ns_set value $selection $i] } } # this is an ugly hack, but it allows content to be written # to a file/connection if it is stored as a lob or if it is # stored in the content-repository as a file. (DanW - Openacs) switch $type { blob_get { if {[info exists storage_type]} { switch $storage_type { file { if {[file exists $content]} { set ifp [open $content r] # DRB: this could be made faster by setting the buffersize # to the size of the file, but for very large files allocating # that much more memory on top of that needed by Tcl for storage # of the data might not be wise. fconfigure $ifp -translation binary set data [read $ifp] close $ifp return $data } else { error "file: $content doesn't exist" } } lob { if {[regexp {^[0-9]+$} $content match]} { return [ns_pg blob_get $db $content] } else { error "invalid lob_id: should be an integer" } } default { error "invalid storage type" } } } elseif {[file exists $content]} { set ifp [open $content r] fconfigure $ifp -translation binary set data [read $ifp] close $ifp return $data } elseif {[regexp {^[0-9]+$} $content match]} { return [ns_pg blob_get $db $content] } else { error "invalid query" } } blob_select_file { if {[info exists storage_type]} { switch $storage_type { file { if {[file exists $content]} { file copy -- $content $file } else { error "file: $content doesn't exist" } } lob { if {[regexp {^[0-9]+$} $content match]} { ns_pg blob_select_file $db $content $file } else { error "invalid lob_id: should be an integer" } } default { error "invalid storage type" } } } elseif {[file exists $content]} { file copy -- $content $file } elseif {[regexp {^[0-9]+$} $content match]} { ns_pg blob_select_file $db $content $file } else { error "invalid query" # TODO: Page /file-storage/download-archive/index # fails here on cvs head both before and after my # mult-db db_* api work, I don't know why. See bug: # http://openacs.org/bugtracker/openacs/com/file-storage/bug?bug%5fnumber=427 # --atp@piskorski.com, 2003/04/09 18:04 EDT } } write_blob { if {[info exists storage_type]} { switch $storage_type { file { if {[file exists $content]} { set ofp [open $content r] fconfigure $ofp -encoding binary ns_writefp $ofp close $ofp } else { error "file: $content doesn't exist" } } text { ns_write $content } lob { if {[regexp {^[0-9]+$} $content match]} { ns_pg blob_write $db $content } else { error "invalid lob_id: should be an integer" } } default { error "invalid storage type" } } } elseif {[file exists $content]} { set ofp [open $content r] fconfigure $ofp -encoding binary ns_writefp $ofp close $ofp } elseif {[regexp {^[0-9]+$} $content match]} { ns_pg blob_write $db $content } else { ns_write $content } } } return } error] global errorInfo errorCode set errinfo $errorInfo set errcode $errorCode ds_collect_db_call $db 0or1row $statement_name $sql $start_time $errno $error if { $errno == 2 } { return $error } return -code $errno -errorinfo $errinfo -errorcode $errcode $error } ad_proc -public db_flush_cache { {-cache_key_pattern *} {-cache_pool db_cache_pool} } { Flush the given cache of entries with keys that match the given pattern. @param cache_key_pattern The "string match" pattern used to flush keys (default is to flush all entries) @param cache_pool The pool to flush (default is to flush db_cache_pool) @author Don Baccus (dhogasa@pacifier.com) } { foreach key [ns_cache names $cache_pool $cache_key_pattern] { ns_cache flush $cache_pool $key } } ad_proc -public db_bounce_pools {{ -dbn "" }} { @return Call ns_db bouncepool on all pools for the named database. @param dbn The database name to use. Uses the default database if not supplied. } { foreach pool [db_available_pools $dbn] { ns_db bouncepool $pool } } openacs-5.7.0/packages/acs-tcl/tcl/object-type-procs-oracle.xql0000644000175000017500000000232710226573710024232 0ustar frankiefrankie oracle8.1.6 select object_type, pretty_name, '' as indent from acs_object_types start with object_type = :object_type connect by prior supertype = object_type order by level desc select object_type, pretty_name, replace(lpad(' ', (level - 1) * $indent_width), ' ', '$indent_string') as indent from acs_object_types start with supertype is null connect by supertype = prior object_type select object_type from acs_object_types start with object_type = :subtype connect by prior supertype = object_type where object_type != :substype order by level desc openacs-5.7.0/packages/acs-tcl/tcl/server-cluster-procs.tcl0000644000175000017500000000757011145353730023511 0ustar frankiefrankiead_library { Provides methods for communicating between load-balanced servers. @cvs-id $Id: server-cluster-procs.tcl,v 1.8 2009/02/13 20:28:08 jeffd Exp $ @author Jon Salz @creation-date 7 Mar 2000 } ad_proc server_cluster_enabled_p {} { Returns true if clustering is enabled. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter ClusterEnabledP -default 0] } ad_proc server_cluster_all_hosts {} { Returns a list of all hosts, possibly including this host, in the server cluster. } { if { ![server_cluster_enabled_p] } { return [list] } return [parameter::get -package_id [ad_acs_kernel_id] -parameter ClusterPeerIP] } ad_proc server_cluster_peer_hosts {} { Returns a list of all hosts, excluding this host, in the server cluster. } { set peer_hosts [list] set my_ip [ns_config ns/server/[ns_info server]/module/nssock Address] foreach host [server_cluster_all_hosts] { #AGUSTIN if { ![regexp {(.*):(.*)} $host match myhost myport] } { set myport 80 set myhost $host } if { $myhost ne $my_ip } { lappend peer_hosts $host } } return $peer_hosts } ad_proc server_cluster_authorized_p { ip } { Can a request coming from $ip be a valid cluster request, i.e., matches some value in ClusterIPMask or is 127.0.0.1? } { if { ![server_cluster_enabled_p] } { return 0 } if { $ip == "127.0.0.1" } { return 1 } # lsearch -glob appears to crash AOLserver 2. Oh well. foreach glob [parameter::get -package_id [ad_acs_kernel_id] -parameter ClusterAuthorizedIP] { if { [string match $glob $ip] } { return 1 } } return 0 } proc server_cluster_do_httpget { url timeout } { if { [catch { set page [ns_httpget $url $timeout 0] if { ![regexp -nocase successful $page] } { ns_log "Error" "Clustering: ns_httpget $url returned unexpected value. Is /SYSTEM/flush-memoized-statement.tcl set up on this host?" } } error] } { ns_log "Error" "Clustering: Unable to ns_httpget $url (with timeout $timeout): $error" } } ad_proc -private server_cluster_logging_p {} { Returns true if we're logging cluster requests. } { return [parameter::get -package_id [ad_acs_kernel_id] -parameter EnableLoggingP -default 0] } ad_proc -private server_cluster_httpget_from_peers { { -timeout 5 } url } { Schedules an HTTP GET request to be issued immediately to all peer hosts (using ad_schedule_proc -once t -thread f -debug t 0). } { if { ![string match "/*" $url] } { set url "/$url" } foreach host [server_cluster_peer_hosts] { # Schedule the request. Don't actually issue the request in this thread, since # (a) we want to parallelize the requests, and (b) we want this procedure to # return immediately. ad_schedule_proc -once t -thread f -debug t -all_servers t 0 server_cluster_do_httpget "http://$host$url" $timeout } } ad_proc -private ad_canonical_server_p {} { Returns true if this is the primary server, false otherwise. we're using IP:port to uniquely identify the canonical server, since hostname or IP does not always uniquely identify an instance of aolserver (for instance, if we have the aolservers sitting behind a load balancer). } { set canonical_server [parameter::get -package_id [ad_acs_kernel_id] -parameter CanonicalServer] if { $canonical_server eq "" } { ns_log Error "Your configuration is not correct for server clustering. Please ensure that you have the CanonicalServer parameter set correctly." return 1 } if { ![regexp {(.*):(.*)} $canonical_server match canonical_ip canonical_port] } { set canonical_port 80 set canonical_ip $canonical_server } if { [ns_config ns/server/[ns_info server]/module/nssock Address] == $canonical_ip && \ [ns_config ns/server/[ns_info server]/module/nssock Port 80] == $canonical_port } { return 1 } return 0 } openacs-5.7.0/packages/acs-tcl/tcl/object-procs.tcl0000644000175000017500000000724610557363702022000 0ustar frankiefrankiead_library { Object support for ACS. @author Jon Salz (jsalz@arsdigita.com) @creation-date 11 Aug 2000 @cvs-id $Id: object-procs.tcl,v 1.11 2007/01/29 12:25:38 maltes Exp $ } namespace eval acs_object {} ad_proc -private acs_lookup_magic_object_no_cache { name } { Non memoized version of acs_magic_object. @return the magic object's object ID @see acs_magic_object } { return [db_string magic_object_select {} ] } ad_proc -private acs_lookup_magic_object { name } { Non memoized version of acs_magic_object. @return the magic object's object ID @see acs_magic_object } { return [util_memoize [list acs_lookup_magic_object_no_cache $name]] } ad_proc -public acs_magic_object { name } { Returns the object ID of a magic object. @param name the name of the magic object (as listed in the acs_magic_objects table). @return the object ID. @error if no object exists with that magic name. } { return [util_memoize [list acs_lookup_magic_object $name]] } ad_proc -public acs_object_name { object_id } { Returns the name of an object. } { return [db_string object_name_get {}] } ad_proc -public acs_object_type { object_id } { Returns the type of an object. } { return [db_string object_type_select { select object_type from acs_objects where object_id = :object_id } -default ""] } ad_proc -public acs_object::get { {-object_id:required} {-array:required} } { Gets information about an acs_object. Returns object_id, package_id, object_type, context_id, security_inherit_p, creation_user, creation_date_ansi, creation_ip, last_modified_ansi, modifying_user, modifying_ip, tree_sortkey, object_name @param array An array in the caller's namespace into which the info should be delivered (upvared) } { upvar 1 $array row db_1row select_object {} -column_array row } ad_proc -public acs_object::package_id { {-object_id:required} } { Gets the package_id of the object @author Malte Sussdorff (malte.sussdorff@cognovis.de) @creation-date 2006-08-10 @param object_id the object to get the package_id for @return package_id of the object. Empty string if the package_id is not stored } { return [util_memoize [list acs_object::package_id_not_cached -object_id $object_id]] } ad_proc -public acs_object::package_id_not_cached { {-object_id:required} } { Gets the package_id of the object @author Malte Sussdorff (malte.sussdorff@cognovis.de) @creation-date 2006-08-10 @param object_id the object to get the package_id for @return package_id of the object. Empty string if the package_id is not stored } { return [db_string get_package_id {} -default ""] } ad_proc -public acs_object::get_element { {-object_id:required} {-element:required} } { Gets a specific element from the info returned by acs_object::get. @param object_id the object to get data for @param element the field to return @return the value of the specified element @see acs_object::get } { acs_object::get -object_id $object_id -array row return $row($element) } ad_proc -public acs_object::object_p { -id:required } { @author Jim Lynch (jim@jam.sessionsnet.org) @author Malte Sussdorff @creation-date 2007-01-26 @param id ID of the potential acs-object @return true if object whose id is $id exists } { return [db_string object_exists {} -default 0] } ad_proc -public acs_object::set_context_id { {-object_id:required} {-context_id:required} } { Sets the context_id of the specified object. } { db_dml update_context_id {} } openacs-5.7.0/packages/acs-tcl/tcl/object-procs.xql0000644000175000017500000000175110557363702022015 0ustar frankiefrankie select object_id from acs_magic_objects where name = :name select package_id from acs_objects where object_id = :object_id select object_type from acs_objects where object_id = :object_id update acs_objects set context_id = :context_id where object_id = :object_id select 1 from acs_objects where object_id = :id openacs-5.7.0/packages/acs-tcl/tcl/apm-file-procs-oracle.xql0000644000175000017500000000513107277142634023504 0ustar frankiefrankie oracle8.1.6 begin :1 := content_item.new(name => :name, creation_ip => :creation_ip, storage_type => 'file' ); end; begin :1 := content_revision.new(title => :title, description => 'gzipped tarfile', text => 'not_important', mime_type => 'text/plain', item_id => :item_id, creation_user => :user_id, creation_ip => :creation_ip ); update cr_items set live_revision = :1 where item_id = :item_id; end; update cr_revisions set filename = '[set content_file [cr_create_content_file $item_id $revision_id $tmpfile]]' where revision_id = :revision_id update apm_package_versions set content_length = [cr_file_size $content_file] where version_id = :version_id select '[cr_fs_path]' || r.filename as content, i.storage_type from cr_revisions r, cr_items i where r.item_id = i.item_id and r.revision_id = (select content_item.get_latest_revision(item_id) from apm_package_versions where version_id = :version_id) begin :1 := apm_package_version.add_file( file_id => :file_id, version_id => :version_id, path => :path, file_type => :file_type, db_type => :db_type ); end; begin apm_package_version.remove_file( path => :path, version_id => :version_id ); end; openacs-5.7.0/packages/acs-tcl/tcl/whos-online-procs.tcl0000644000175000017500000001337610551254404022765 0ustar frankiefrankiead_library { Provides support for registering which users are online. @author Bjoern Kiesbye @author Peter Marklund @author Lars Pind @creation-date 03 October 2003 @cvs-id $Id: whos-online-procs.tcl,v 1.4 2007/01/10 21:22:12 gustafn Exp $ } # TODO: Count anonymous users based on their IP, just to have the number namespace eval whos_online {} ad_proc -private whos_online::init {} { Schedules the flush proc that cleans up old who's online values. Makes sure the unregistered visitor (user_id=0) is invisible. @author Bjoern Kiesbye } { ad_schedule_proc -thread t 3600 whos_online::flush # We typically don't want to see the unregistered user in the who's online list set_invisible 0 } ad_proc -private whos_online::flush {} { Removing all user_ids from the last_hit (nsv_set) wich have a time Stamp older than the number of seconds indicated by the proc whos_online::interval. @author Bjoern Kiesbye } { array set last_hit [nsv_array get last_hit] set onliners_out [list] set interval 1 set oldtime [expr {[ns_time] - [interval]}] for { set search [array startsearch last_hit] } { [array anymore last_hit $search] } {} { set user [array nextelement last_hit $search] set time $last_hit($user) if {$time<$oldtime} { lappend onliners_out $user } } array donesearch last_hit $search for { set i 0 } { $i < [llength $onliners_out] } { incr i } { set user_id [lindex $onliners_out $i] foreach name { last_hit invsible_users first_hit } { if { [nsv_exists $name $user_id] } { nsv_unset $name $user_id } } } } ad_proc -private whos_online::interval {} { Returns the last number of seconds within a user must have requested a page to be considered online. Based on the LastVisitUpdateInterval parameter of the main site and defaults to 600 seconds = 10 minutes. @author Peter Marklund } { return [parameter::get \ -package_id [subsite::main_site_id] \ -parameter LastVisitUpdateInterval \ -default 600] } ad_proc -private whos_online::user_requested_page { user_id } { Records that the user with given id requested a page on the server @author Bjoern Kiesbye } { if { $user_id != 0 } { nsv_set last_hit $user_id [ns_time] if { ![nsv_exists first_hit $user_id] } { nsv_set first_hit $user_id [ns_time] } } else { # TODO: Record the IP address from [ad_conn peeraddr] } } ad_proc -public whos_online::seconds_since_last_request { user_id } { Returns the number of seconds since the user with given id requested a page. Returns the empty string if the user is not currently online. @author Peter Marklund } { if { [nsv_exists last_hit $user_id] } { return [expr {[ns_time] - [nsv_get last_hit $user_id]}] } else { return {} } } ad_proc -public whos_online::seconds_since_first_request { user_id } { Returns the number of seconds since the user with given id first requested a page. Returns the empty string if the user is not currently online. @author Peter Marklund } { if { [nsv_exists last_hit $user_id] } { return [expr {[ns_time] - [nsv_get first_hit $user_id]}] } else { return {} } } ad_proc -public whos_online::num_users {} { Get the number of registered users currently online, and not invisible } { # We might want to optimize this, but for now, let's just do it this way: return [llength [whos_online::user_ids]] } ad_proc -public whos_online::num_anonymous {} { Get the number of anony users currently online, and not invisible } { # Not implemented yet: number of anonymous users counted by IP + number of invisible users return 0 } ad_proc -public whos_online::user_ids { {-all:boolean} } { This function returns a list of user_ids from users wich have requested a page from this Server in the last 10 min.And aren't set to invisible. @param all Set this flag if you want to include invisible users. @author Bjoern Kiesbye } { array set last_hit [nsv_array get last_hit] set onliners [list] set oldtime [expr {[ns_time] - [interval]}] for { set search [array startsearch last_hit] } { [array anymore last_hit $search] } {} { set user_id [array nextelement last_hit $search] if { $last_hit($user_id) > $oldtime } { # User is online if { $all_p || ![user_invisible_p $user_id] } { # And he's not invisible, or we want all users lappend onliners $user_id } } } array donesearch last_hit $search return $onliners } ad_proc -public whos_online::set_invisible { user_id } { This procedure sets the user user_id to invisible, his user_id will not be returned by user_ids. The invisible state will only last as long as the user is online. @author Bjoern Kiesbye } { nsv_set invisible_users $user_id [ns_time] } ad_proc -public whos_online::unset_invisible { user_id } { This procedure unsets the invisible state of user_id. @author Bjoern Kiesbye } { if { [nsv_exists invisible_users $user_id] } { nsv_unset invisible_users $user_id } } ad_proc -public whos_online::user_invisible_p { user_id } { This function checks if the user user_id is set to invisible. Returns a Tcl boolean. @author Bjoern Kiesbye } { return [nsv_exists invisible_users $user_id] } ad_proc -public whos_online::all_invisible_user_ids {} { This function returns a list with all user_ids wich are set to invisible @author Bjoern Kiesbye } { return [nsv_array names invisible_users] } openacs-5.7.0/packages/acs-tcl/tcl/object-type-procs.tcl0000644000175000017500000001006111553066454022745 0ustar frankiefrankiead_library { Supporting procs for ACS Object Types @author Yonatan Feldman (yon@arsdigita.com) @creation-date August 13, 2000 @cvs-id $Id: object-type-procs.tcl,v 1.9 2011/04/18 16:56:12 emmar Exp $ } namespace eval acs_object_type {} ad_proc -public acs_object_type_hierarchy { -object_type { -indent_string " " } { -indent_width "4" } { -join_string "
    " } { -additional_html "" } } { Returns an HTML snippet representing a hierarchy of ACS Object Types @author Yonatan Feldman (yon@arsdigita.com) @creation-date August 13, 2000 @param object_type the object type for which to show a hierarchy for. @param indent_string string with which to lpad @param indent_width number of times to insert indent_string into indentation @param join_string string with which to join each row returned by the query @param additional_html any additional html you might want to print per line } { set result "" if { [exists_and_not_null object_type] } { set sql [db_map object_type_not_null] set join_string " > " } else { set sql [db_map object_type_is_null] } set i 0 db_foreach object_types "$sql" { if { $i > 0 } { append result $join_string } incr i append result [subst {\n $indent[lang::util::localize $pretty_name]}] append result $additional_html } return $result } ad_proc -public acs_object_type::get { -object_type:required -array:required } { Get info about an object type. Returns columns

    • object_type,
    • supertype,
    • abstract_p,
    • pretty_name,
    • pretty_plural,
    • table_name,
    • id_column,
    • package_name,
    • name_method,
    • type_extension_table,
    • dynamic_p
    } { upvar 1 $array row db_1row select_object_type_info { select object_type, supertype, abstract_p, pretty_name, pretty_plural, table_name, id_column, package_name, name_method, type_extension_table, dynamic_p from acs_object_types where object_type = :object_type } -column_array row } ad_proc -private acs_object_type::acs_object_instance_of { {-object_id:required} {-type:required} } { Returns true if the specified object_id is a subtype of the specified type. This is an inclusive check. @author Lee Denison (lee@thaum.net) } { acs_object::get -object_id $object_id -array obj return [acs_object_type::supertype \ -supertype $type \ -subtype $obj(object_type)] } ad_proc -private acs_object_type::supertype { {-supertype:required} {-subtype:required} } { Returns true if subtype is equal to, or a subtype of, supertype. @author Lee Denison (lee@thaum.net) } { set supertypes [object_type::supertypes] append supertypes $subtype return [expr {[lsearch $supertypes $supertype] >= 0}] } ad_proc -private acs_object_type::supertypes { {-subtype:required} {-no_cache:boolean} } { Returns a list of the supertypes of subtypes. @author Lee Denison (lee@thaum.net) } { if {$no_cache_p} { return [db_list supertypes {}] } else { return [util_memoize [list acs_object_type::supertypes \ -subtype $subtype \ -no_cache]] } } ad_proc -private acs_object_type::get_table_name { -object_type:required } { Return the table name associated with an object_type. Allow caching of the table_name as it is unlikely to change without a restart of the server (\which is mandatory after an upgrade) } { return [util_memoize [list acs_object_type::get_table_name_not_cached -object_type $object_ty\pe]] } ad_proc -private acs_object_type::get_table_name_not_cached { -object_type:required } { Return the table name associated with an object_type. } { return [db_string get_table_name ""] }openacs-5.7.0/packages/acs-tcl/tcl/object-type-procs.xql0000644000175000017500000000061210227153437022763 0ustar frankiefrankie $sql select table_name from acs_object_types where object_type = :object_type openacs-5.7.0/packages/acs-tcl/tcl/00-database-procs-oracle.tcl0000644000175000017500000000075207661404442023750 0ustar frankiefrankiead_library { Oracle-specific database API and utility procs @creation-date 15 Apr 2000 @author Jon Salz (jsalz@arsdigita.com) @cvs-id $Id: 00-database-procs-oracle.tcl,v 1.22 2003/05/17 10:04:18 jeffd Exp $ } # This file is now obsolete. All procs have been merged into # 00-database-procs.tcl, so that all supported databases are useable # with the db_* API all the time, regardless of which database type # OpenACS is using. --atp@piskorski.com, 2003/04/09 12:04 EDT openacs-5.7.0/packages/acs-tcl/tcl/callback-procs.tcl0000644000175000017500000000170410226574141022251 0ustar frankiefrankiead_library { Supports the use of callbacks. @author Lee Denison (lee@xarg.co.uk) } namespace eval callback {} ad_proc -public callback::impl_exists { {-callback:required} {-impl:required} } { Returns whether the specified implementation exists. } { return [expr {![string equal \ [info commands ::callback::${callback}::impl::${impl}] \ ""]}] } ad_proc -public callback::get_object_type_impl { {-object_type:required} {-callback:required} } { Finds the most type specific implementation of callback. } { if {[callback::impl_exists -callback $callback -impl $object_type]} { return $object_type } else { set supertypes [acs_object_type::supertypes \ -subtype $object_type] foreach type $supertypes { if {[callback::impl_exists -callback $callback -impl $type]} { return $type } } } return "" } openacs-5.7.0/packages/acs-tcl/tcl/html-email-procs.tcl0000644000175000017500000001275111323323245022546 0ustar frankiefrankiead_library { Contains procs to send HTML email outside of the context of ACS Mail package. @author Doug Harris (dharris@worldbank.org) @author Janine Sisk (jsisk@mit.edu) @creation-date 25 Feb 2002 @cvs-id $Id: html-email-procs.tcl,v 1.18 2010/01/13 10:55:33 emmar Exp $ } # switched to using tcllib, its required for openacs >= 5.3 package require mime ad_proc build_mime_message { text_body html_body {charset "UTF-8"} } { Composes multipart/alternative email containing plain text and html versions of the message, parses out the headers we need, constructs an array and returns it to the caller. This proc is based on ad_html_sendmail, written by Doug Harris at the World Bank. } { # convert text to charset set encoding [ns_encodingforcharset $charset] if {[lsearch [encoding names] $encoding] != -1} { set html_body [encoding convertto $encoding $html_body] set text_body [encoding convertto $encoding $text_body] } else { ns_log error "ad_html_sendmail: unknown charset passed in ($charset)" } # build body ## JCD: I fail to see why you would want both a base64 and a quoted-printable ## version of html part of this email. I am removing the base64 version. ## set base64_html_part [mime::initialize -canonical text/html -param [list charset $charset] -encoding base64 -string $html_body] set html_part [mime::initialize -canonical text/html \ -param [list charset $charset] \ -encoding quoted-printable \ -string $html_body] set text_part [mime::initialize -canonical text/plain \ -param [list charset $charset] \ -encoding quoted-printable \ -string $text_body] set multi_part [mime::initialize \ -canonical multipart/alternative \ -parts [list $text_part $html_part]] # this gives us a complete mime message, minus the headers because # we don't pass any in. This code is designed to send a fully-formed # message out through an SMTP socket, but we're not doing that so we # have to hijack the process a bit. set mime_body [mime::buildmessage $multi_part] # mime-encode the periods at the beginning of a line in the # message text or they are lost. Most noticable when the line # is broken within a URL regsub {^\.} $mime_body {=2E} mime_body # the first three lines of the message are special; we need to grab # the info, add it to the message headers, and discard the lines set lines [split $mime_body \n] set message_data [ns_set new] # get mime version regexp {MIME-Version: (.*)} [lindex $lines 0] junk mime_version ns_set put $message_data MIME-Version $mime_version # the content id regexp {Content-ID: (.*)} [lindex $lines 1] junk content_id ns_set put $message_data Content-ID $content_id # and the content type and boundary regexp {Content-Type: (.*)} [lindex $lines 2] junk content_type set content_type "$content_type\n[lindex $lines 3]" ns_set put $message_data Content-Type $content_type # the rest of the lines form the message body. We strip off the last # line, which is the last boundary, because acs_mail_lite::send seems to be # adding another one on for us. ## JCD: not anymore. maybe an aolserver 3.3 bug? removing the clipping. ns_set put $message_data body [join [lrange $lines 4 end] \n] return $message_data } ad_proc parse_incoming_email { message } { Takes an incoming message and splits it into parts. The main goal of this proc is to return something that can be stuffed into the database somewhere, such as a forum message. Since we aggressively filter HTML, the HTML tags are stripped out of the returned content. The message may have only plain text, plain text and HTML, or plain text and something else (Apple Mail uses text/enhanced, for example). To make our lives simpler we support only text/html as a special case; in all other cases the plain text is returned. } { set mime [mime::initialize -string $message] set content [mime::getproperty $mime content] if { [string first "multipart" $content] != -1 } { set parts [mime::getproperty $mime parts] } else { set parts [list $mime] } # Expand any first-level multipart/alternative children. set expanded_parts [list] foreach part $parts { catch {mime::getproperty $part content} this_content if { $this_content eq "multipart/alternative"} { foreach child_part [mime::getproperty $part parts] { lappend expanded_parts $child_part } } else { lappend expanded_parts $part } } foreach part $expanded_parts { catch {mime::getproperty $part content} this_content switch $this_content { "text/plain" { if { ![info exists plain] } { set plain [mime::getbody $part] } } "text/html" { if { ![info exists html] } { set html [mime::getbody $part] } } } } if { [info exists plain] } { set body $plain } elseif { [info exists html] } { set body [ad_html_to_text -- $html] } else { set body $message } mime::finalize $mime -subordinates all return $body } openacs-5.7.0/packages/acs-tcl/tcl/apm-file-procs.tcl0000644000175000017500000005407611124300136022206 0ustar frankiefrankiead_library { Functions that APM uses to interact with the file system and I/O. @author Bryan Quinn (bquinn@arsdigita.com) @creation-date Fri Oct 6 21:46:05 2000 @cvs-id $Id: apm-file-procs.tcl,v 1.35 2008/12/24 00:20:46 gustafn Exp $ } ad_proc -private apm_mkdir {path} { Creates the directory specified by path and returns it. } { if { [catch { file mkdir $path }] } { # There must be a file blocking the directory creation. if { [catch { file delete -force $path file mkdir $path } errmsg]} { error "Error creationg directory $path: $errmsg" } } return $path } ad_proc -public apm_workspace_dir {} { Return the path to the apm-workspace, creating the directory if necessary. } { set path [file join [acs_root_dir] apm-workspace] if { [file isdirectory $path] } { return $path } else { return [apm_mkdir $path] } } ad_proc -public apm_workspace_install_dir {} { Return the path to the installation directory of the apm-workspace, creating the directory if necessary. } { set base_path [apm_workspace_dir] set install_path "$base_path/install" if { [file isdirectory $install_path] } { return $install_path } else { return [apm_mkdir $install_path] } } ad_proc -public apm_file_type_names {} { Returns an array list with filetypes as keys and filetype pretty names as values. @author Peter Marklund } { return { documentation "Documentation" tcl_procs "Tcl procedure library" tcl_init "Tcl initialization" tcl_util "Tcl utility script" content_page "Content page" package_spec "Package specification" sql_data "SQL Data" ctl_file "SQL data loader control" data_model "Data model" data_model_create "Data model installation" data_model_drop "Data model deinstallation" data_model_upgrade "Data model upgrade" java_code "Java code" java_archive "Java archive" query_file "Query file" template "Template file" shell "Shell utility" sqlj_code "SQLJ library" message_catalog "Message Catalog" } } ad_proc -public apm_file_type_keys {} { Returns a list of valid file type keys. @see apm_file_type_names @see apm_pretty_name_for_file_type @author Peter Marklund } { array set file_type_names [apm_file_type_names] return [array names file_type_names] } ad_proc -public apm_db_type_keys {} { Returns a list of valid database type keys. } { return [util_memoize [list db_list db_type_keys "select db_type_key from apm_package_db_types"]] } ad_proc -public apm_package_info_file_path { { -path "" } package_key } { Returns the path to a .info file in a package directory, or throws an error if none exists. Currently, only $package_key.info is recognized as a specification file. } { if { $path eq "" } { set path "[acs_package_root_dir $package_key]/$package_key.info" } else { set path "$path/$package_key/$package_key.info" } if { [file exists $path] } { return $path } error "The $path/$package_key does not contain a package specification file ($package_key.info)." } ad_proc -private apm_extract_tarball { version_id dir } { Extracts a distribution tarball into a particular directory, overwriting any existing files. DCW - 2001-05-03, modified to extract tarball from content repository. } { set apm_file [ns_tmpnam] db_blob_get_file distribution_tar_ball_select { select content from cr_revisions where revision_id = (select content_item.get_latest_revision(item_id) from apm_package_versions where version_id = :version_id) } $apm_file file mkdir $dir # avoid chdir #ns_log notice "exec sh -c 'cd $dir ; [apm_gzip_cmd] -d -q -c $apm_file | [apm_tar_cmd] xf - 2>/dev/null'" exec [apm_gzip_cmd] -d -q -c -S .apm $apm_file | [apm_tar_cmd] -xf - -C $dir 2> [apm_dev_null] file delete $apm_file } ad_proc -private apm_generate_tarball { version_id } { Generates a tarball for a version, placing it in the content repository. DCW - 2001-05-03, change to use the content repository for tarball storage. } { set package_key [apm_package_key_from_version_id $version_id] set files [apm_get_package_files -all_db_types -package_key $package_key] set tmpfile [ns_tmpnam] db_1row package_key_select { select package_key from apm_package_version_info where version_id = :version_id } # Generate a command like: # # tar cf - -C /web/arsdigita/packages acs-kernel/00-proc-procs.tcl \ # -C /web/arsdigita/packages 10-database-procs.tcl ... \ # | gzip -c > $tmpfile # # Note that -C changes the working directory before compressing the next # file; we need this to ensure that the tarballs are relative to the # package root directory ([acs_root_dir]/packages). set cmd [list exec [apm_tar_cmd] cf - 2> [apm_dev_null]] foreach file $files { lappend cmd -C "[acs_root_dir]/packages" lappend cmd "$package_key/$file" } lappend cmd "|" [apm_gzip_cmd] -c ">" $tmpfile eval $cmd # At this point, the APM tarball is sitting in $tmpfile. Save it in # the database. set creation_ip [ad_conn peeraddr] set user_id [ad_conn user_id] set name "tarball-for-package-version-${version_id}" set title "${package_key}-tarball" set create_item " begin :1 := content_item.new(name => :name, creation_ip => :creation_ip ); end;" set create_revision " begin :1 := content_revision.new(title => :title, description => 'gzipped tarfile', text => 'not_important', mime_type => 'text/plain', item_id => :item_id, creation_user => :user_id, creation_ip => :creation_ip ); update cr_items set live_revision = :1 where item_id = :item_id; end;" db_1row item_exists_p {select case when item_id is null then 0 else item_id end as item_id from apm_package_versions where version_id = :version_id} if {!$item_id} { # content item hasen't been created yet - create one. set item_id [db_exec_plsql create_item $create_item] db_dml set_item_id "update apm_package_versions set item_id = :item_id where version_id = :version_id" set revision_id [db_exec_plsql create_revision $create_revision] } else { #tarball exists, so all we have to do is to make a new revision for it #Let's check if a current revision exists: if {![db_0or1row get_revision_id "select live_revision as revision_id from cr_items where item_id = :item_id"] || $revision_id eq ""} { # It's an insert rather than an update set revision_id [db_exec_plsql create_revision $create_revision] } } db_dml update_tarball {update cr_revisions set content = empty_blob() where revision_id = :revision_id returning content into :1} -blob_files [list $tmpfile] db_dml update_content_length { update apm_package_versions set content_length = (select dbms_lob.getlength(content) from cr_revisons where revision_id = :revision_id) where version_id = :version_id } file delete $tmpfile } ad_proc -private apm_files_load { {-force_reload:boolean 0} {-callback apm_dummy_callback} files } { Load the set of files into the currently running Tcl interpreter. @param -force_reload Indicates if the file should be loaded even if it \ is already loaded in the interpreter. } { # This will be the first time loading for each of these files (since if a # file has already been loaded, we just skip it in the loop below). global apm_first_time_loading_p set apm_first_time_loading_p 1 global apm_current_package_key foreach file_info $files { util_unlist $file_info package_key path if { $force_reload_p || ![nsv_exists apm_library_mtime packages/$package_key/$path] } { if { [file exists "[acs_root_dir]/packages/$package_key/$path"] } { apm_callback_and_log $callback "Loading packages/$package_key/$path..." set apm_current_package_key $package_key apm_source "[acs_root_dir]/packages/$package_key/$path" # Release outstanding database handles (in case this file # used the db_* database API and a subsequent one uses # ns_db). db_release_unused_handles apm_callback_and_log $callback "Loaded packages/$package_key/$path." unset apm_current_package_key } else { apm_callback_and_log $callback "Unable to load packages/$package_key/$path - file is marked as contained in a package but is not present in the filesystem" } } } unset apm_first_time_loading_p } ad_proc -public apm_file_watch {path} { Marks the file of the indicated path to be watched. If the file changes, it will be reloaded prior to the next page load. @param path The path of the file relative to server root } { if {$path eq "packages/acs-bootstrap-installer/tcl/30-apm-load-procs.tcl"} { ns_log Warning "apm_file_watch: Skipping file $path as it cannot be watched. You have to restart the server instead" } nsv_set apm_reload_watch $path 1 } ad_proc -public apm_file_watch_cancel { {path ""} } { Stop watching a certain file, or all watched files if path is not specified. If the file is not watched this procedure does nothing. @param path The path relative to server root of the file to stop watching. Optional. @author Peter Marklund } { if { $path ne "" } { catch { nsv_unset apm_reload_watch $path } } else { catch {nsv_unset apm_reload_watch} } } ad_proc -public apm_file_watchable_p { path } { Given the path of a file determine if it is appropriate to be watched for reload. The file should be db compatible with the system and be of right type (for example contain tcl procs or xql queries). @param The path of the file relative to server root @return 1 If file is watchable and 0 otherwise. The proc will throw an error if the file doesn't exist or if the given path cannot be parsed as a path relative to server root. @see apm_guess_file_type @see apm_guess_db_type @author Peter Marklund } { # The apm_guess procs need package_key and a path relative to package root # so parse those out of the given path if { [regexp {^packages/([^/]+)/(.*)$} $path match package_key package_rel_path] } { if { ![file exists "[acs_root_dir]/$path"] } { error "apm_file_watchable_p: path $path does not correspond to an existing file" } } else { error "apm_file_watchable_p: path $path cannot be parsed as a path relative to server root" } # Check the db type set file_db_type [apm_guess_db_type $package_key $package_rel_path] set right_db_type_p [expr {$file_db_type eq ""} || \ [string equal $file_db_type [db_type]]] # Check the file type set file_type [apm_guess_file_type $package_key $package_rel_path] # I would like to add test_procs to the list but currently test_procs files are used to register test cases # and we don't want to resource these files in every interpreter. Test procs should be defined in test_init files. set watchable_file_types [list tcl_procs query_file test_procs] set right_file_type_p [expr {[lsearch -exact $watchable_file_types $file_type] != -1}] # Both db type and file type must be right set watchable_p [expr {$right_db_type_p && $right_file_type_p}] return $watchable_p } ad_proc -private apm_watch_all_files { package_key } { Watch all Tcl procs and xql query files in the given package @see apm_file_watch @see apm_get_watchable_files @author Peter Marklund } { foreach rel_path [apm_get_watchable_files $package_key] { apm_file_watch $rel_path } } ad_proc -private apm_cancel_all_watches { package_key } { Cancel all watches in the given package. @param package_key The package_key of the package to stop watching. @see apm_file_watch_cancel @see apm_get_watchable_files @author Peter Marklund } { foreach rel_path [apm_get_watchable_files $package_key] { apm_file_watch_cancel $rel_path } } ad_proc -private apm_get_watchable_files { package_key } { Get a list of paths relative to server root of watchable files in the given package @param package_key Key of the package to get paths for @author Peter Marklund } { set watchable_files [list] set files [ad_find_all_files [acs_root_dir]/packages/$package_key] foreach file [lsort $files] { set rel_path [ad_make_relative_path $file] if { [apm_file_watchable_p $rel_path] } { lappend watchable_files $rel_path } } return $watchable_files } ad_proc -public pkg_home {package_key} { @return A server-root relative path to the directory for a package. Usually /packages/package-key } { return "/packages/$package_key" } ad_proc -private apm_system_paths {} { @return a list of acceptable system paths to search for executables in. } { set paths [ad_parameter_all_values_as_list -package_id [ad_acs_kernel_id] SystemCommandPaths acs-kernel] if {$paths eq ""} { return [list "/usr/local/bin" "/usr/bin" "/bin" "/usr/sbin" "/sbin" "/usr/sbin"] } else { return $paths } } ad_proc -private apm_gzip_cmd {} { @return A valid pointer to gzip, 0 otherwise. } { return gzip } ad_proc -private apm_tar_cmd {} { @return A valid pointer to tar, 0 otherwise. } { return tar } ad_proc -private apm_dev_null {} { @return null device } { if {$::tcl_platform(platform) ne "windows"} { return /dev/null } else { return nul } } ad_proc -private apm_transfer_file { {-url} {-output_file_name} } { # # The original solution using ns_httpopen + file_copy does not work # reliably under windows, for unknown reasons the downloaded file is # truncated. # # Therefore, we check first if the optional xotcl-core components # are available... # if {[info command ::xo::HttpRequest] ne ""} { # # ... use xo::HttpRequest... # #ns_log notice "Transfer $url based to $output_file_name on ::xo::HttpRequest" # set r [::xo::HttpRequest new -url $url] set fileChan [open $output_file_name w 0640] fconfigure $fileChan -translation binary -encoding binary puts -nonewline $fileChan [$r set data] close $fileChan } elseif {[set wget [::util::which wget]] ne ""} { # # ... if we have no ::xo::* and we have "wget" installed, we use # it. # ns_log notice "Transfer $url based on wget" catch {exec $wget -O $output_file_name $url} } else { # # Everything else failed, fall back to the original solution. # ns_log notice "Transfer $url based on ns_httpopen" # Open a destination file. set fileChan [open $output_file_name w 0640] # Open the channel to the server. set httpChan [lindex [ns_httpopen GET $url] 0] ns_log Debug "APM: Copying data from $url" fconfigure $httpChan -encoding binary fconfigure $fileChan -encoding binary # Copy the data fcopy $httpChan $fileChan # Clean up. ns_log Debug "APM: Done copying data." close $httpChan close $fileChan } } ad_proc -private apm_load_apm_file { {-callback apm_dummy_callback} {-url {}} {file_path {}} } { Uncompresses and loads an APM file into the filesystem. @param url If specified, will download the APM file first. @return If successful, a path to the .info file of the package uncompressed into the apm-workspace directory } { # First download the apm file if a URL is provided if { $url ne "" } { set file_path [ns_tmpnam].apm apm_callback_and_log $callback "
  • Downloading $url..." if { [catch {apm_transfer_file -url $url -output_file_name $file_path} errmsg] } { apm_callback_and_log $callback "Unable to download. Please check your URL.. The following error was returned:
    [ad_quotehtml $errmsg]
                
    [ad_footer]" return } if {![file exists $file_path]} { apm_callback_and_log $callback " The file cannot be found. Your URL or your file name is incorrect. Please verify that the file name is correct and try again." ns_log Error "Error loading APM file form url $url: The file cannot be found." return } } #ns_log notice "*** try to exec [apm_gzip_cmd] -d -q -c -S .apm $file_path | [apm_tar_cmd] tf - 2> [apm_dev_null]" if { [catch { set files [split [string trim \ [exec [apm_gzip_cmd] -d -q -c -S .apm $file_path | [apm_tar_cmd] tf - 2> [apm_dev_null]]] "\n"] apm_callback_and_log $callback "
  • Done. Archive is [format %.1f [expr { [file size $file_path] / 1024.0 }]]KB, with [llength $files] files.
  • " } errmsg] } { apm_callback_and_log $callback "The follow error occured during the uncompression process:
    [ad_quotehtml $errmsg]

    " global errorInfo ns_log Error "Error loading APM file form url $url: $errmsg\n$errorInfo" return } if { [llength $files] == 0 } { apm_callback_and_log $callback "The archive does not contain any files.\n" ns_log Error "Error loading APM file form url $url: The archive does not contain any files." return } set package_key [lindex [split [lindex $files 0] "/"] 0] # Find that .info file. foreach file $files { set components [split $file "/"] if {[lindex $components 0] ne $package_key } { apm_callback_and_log $callback "All files in the archive must be contained in the same directory (corresponding to the package's key). This is not the case, so the archive is not a valid APM file.\n" ns_log Error "Error loading APM file form url $url: Invalid APM file. All files in the archive must be contained in the same directory corresponding to the package's key." return } if { [llength $components] == 2 && [file extension $file] eq ".info" } { if { [info exists info_file] } { apm_callback_and_log $callback "The archive contains more than one package/*/*.info file, so it is not a valid APM file.\n" ns_log Error "Error loading APM file form url $url: Invalid APM file. More than one package .info file." return } else { set info_file $file } } } if { ![info exists info_file] || [regexp {[^a-zA-Z0-9\-\./_]} $info_file] } { apm_callback_and_log $callback "The archive does not contain a */*.info file, so it is not a valid APM file.\n" ns_log Error "Error loading APM file form url $url: Invalid APM file. No package .info file." return } apm_callback_and_log $callback "Extracting the .info file ($info_file)..." set tmpdir [ns_tmpnam] file mkdir $tmpdir exec [apm_gzip_cmd] -d -q -c -S .apm $file_path | [apm_tar_cmd] -xf - -C $tmpdir $info_file 2> [apm_dev_null] #exec sh -c "cd $tmpdir ; [apm_gzip_cmd] -d -q -c -S .apm $file_path | [apm_tar_cmd] xf - $info_file" 2> [apm_dev_null] if { [catch { array set package [apm_read_package_info_file [file join $tmpdir $info_file]] } errmsg]} { file delete -force $tmpdir apm_callback_and_log $callback "The archive contains an unparseable package specification file: $info_file. The following error was produced while trying to parse it:
    [ad_quotehtml $errmsg]
    .

    The package cannot be installed. \n" global errorInfo ns_log Error "Error loading APM file form url $url: Bad package .info file. $errmsg\n$errorInfo" return } file delete -force $tmpdir set package_key $package(package.key) set pretty_name $package(package-name) set version_name $package(name) ns_log Debug "APM: Preparing to load $pretty_name $version_name" # Determine if this package version is already installed. if {[apm_package_version_installed_p $package_key $version_name]} { apm_callback_and_log $callback "

  • $pretty_name $version_name is already installed in your system." ns_log Error "Error loading APM file form url $url: Package $pretty_name $version_name is already installed" } else { set install_path "[apm_workspace_install_dir]" if { ![file isdirectory $install_path] } { file mkdir $install_path } apm_callback_and_log $callback "
  • Extracting files into the filesytem." apm_callback_and_log $callback "
  • $pretty_name $version_name ready for installation." #ns_log notice "exec sh -c 'cd $install_path ; [apm_gzip_cmd] -d -q -c $file_path | [apm_tar_cmd] xf -' 2>/dev/null" exec [apm_gzip_cmd] -d -q -c -S .apm $file_path | [apm_tar_cmd] -xf - -C $install_path 2> [apm_dev_null] return "${install_path}/${package_key}/${package_key}.info" } } openacs-5.7.0/packages/acs-tcl/tcl/apm-file-procs.xql0000644000175000017500000000212607734354634022245 0ustar frankiefrankie select case when item_id is null then 0 else item_id end as item_id from apm_package_versions where version_id = :version_id update apm_package_versions set item_id = :item_id where version_id = :version_id select live_revision as revision_id from cr_items where item_id = :item_id select db_type_key from apm_package_db_types select package_key from apm_package_version_info where version_id = :version_id openacs-5.7.0/packages/acs-tcl/tcl/ds-stub-procs.tcl0000644000175000017500000000125510551254404022075 0ustar frankiefrankiead_library { Stub procs for developer support procs we call in acs-tcl for logging. We check here if the procs are defined before we stub them out. This is done since the old ad_call_proc_if_exists is somewhat expensive and these are called a lot in every request. @author Jeff Davis @creationd-date 2005-03-02 @cvs-id $Id: ds-stub-procs.tcl,v 1.2 2007/01/10 21:22:12 gustafn Exp $ } if {{} eq [info procs ds_add]} { proc ds_add {args} {} } if {{} eq [info procs ds_collect_db_call]} { proc ds_collect_db_call {args} {} } if {{} eq [info procs ds_collect_connection_info]} { proc ds_collect_connection_info {} {} } openacs-5.7.0/packages/acs-tcl/tcl/00-database-procs-postgresql.tcl0000644000175000017500000000076107661404442024706 0ustar frankiefrankiead_library { Postgres-specific database API and utility procs. @creation-date 15 Apr 2000 @author Jon Salz (jsalz@arsdigita.com) @cvs-id $Id: 00-database-procs-postgresql.tcl,v 1.43 2003/05/17 10:04:18 jeffd Exp $ } # This file is now obsolete. All procs have been merged into # 00-database-procs.tcl, so that all supported databases are useable # with the db_* API all the time, regardless of which database type # OpenACS is using. --atp@piskorski.com, 2003/04/09 12:04 EDT openacs-5.7.0/packages/acs-tcl/tcl/util-diff-procs.tcl0000644000175000017500000001733711102543342022402 0ustar frankiefrankiead_library { Procedures to generate pretty formatted diffs of some text } namespace eval util:: {} ad_proc -public util::diff { -old -new {-show_old_p "t"} } { Perform a UNIX diff on 'old' and 'new', and return a HTML fragment of the changes. Requires struct::list (from tcllib) @author Vinod Kurup vinod@kurup.com @creation-date 2005-10-18 @param old original text @param new new text @return HTML fragment of differences between 'old' and 'new' } { package require struct::list set old [split $old " "] set new [split $new " "] # tcllib procs to get a list of differences between 2 lists # see: http://tcllib.sourceforge.net/doc/struct_list.html set len1 [llength $old] set len2 [llength $new] set result [::struct::list longestCommonSubsequence $old $new] set result [::struct::list lcsInvert $result $len1 $len2] # each chunk is either 'deleted', 'added', or 'changed' set i 0 foreach chunk $result { ns_log notice "\n$chunk\n" set action [lindex $chunk 0] set old_index1 [lindex [lindex $chunk 1] 0] set old_index2 [lindex [lindex $chunk 1] 1] set new_index1 [lindex [lindex $chunk 2] 0] set new_index2 [lindex [lindex $chunk 2] 1] while {$i < $old_index1} { lappend output [lindex $old $i] incr i } if { $action eq "changed" } { if {$show_old_p} { lappend output foreach item [lrange $old $old_index1 $old_index2] { lappend output [string trim $item] } lappend output } lappend output foreach item [lrange $new $new_index1 $new_index2] { lappend output [string trim $item] } lappend output incr i [expr {$old_index2 - $old_index1 + 1}] } elseif { $action eq "deleted" } { lappend output foreach item [lrange $old $old_index1 $old_index2] { lappend output [string trim $item] } lappend output incr i [expr {$old_index2 - $old_index1 + 1}] } elseif { $action eq "added" } { while {$i < $old_index2} { lappend output [lindex $old $i] incr i } lappend output foreach item [lrange $new $new_index1 $new_index2] { lappend output [string trim $item] } lappend output } } # add any remaining words at the end. while {$i < $len1} { lappend output [lindex $old $i] incr i } set output [join $output " "] set output [string map {"" {} "" "" {} "" } $output] return "$output" } ad_proc -public util::html_diff { -old -new {-show_old_p "t"} } { Perform a UNIX diff on 'old' and 'new', and return a HTML fragment of the changes. Requires struct::list (from tcllib) @author Vinod Kurup vinod@kurup.com @creation-date 2005-10-18 @param old original text @param new new text @return HTML fragment of differences between 'old' and 'new' } { package require struct::list set frag $old set old_list [list] while {$frag ne ""} { if {![regexp "(\[^<]*)(<(/?)(\[^ \r\n\t>]+)(\[^>]*)>)?(.*)" $frag match pretag fulltag close tag tagbody frag]} { # we should never get here, the regexp should match anything # should never get here since above will match anything. ns_log Error "util_close_html_tag - NO MATCH: should never happen! frag=$frag" lappend old_list $frag set frag {} } if {$pretag ne ""} { set pretag [string map {\n " "} $pretag] set pretag2 [list] foreach element [split $pretag " "] { if {[string trim $element] ne ""} { lappend pretag2 [string trim $element] } } if {[llength $pretag2]} { eval "lappend old_list $pretag2" } } if {$fulltag ne ""} { lappend old_list $fulltag } } set frag $new set new_list [list] while {$frag ne ""} { if {![regexp "(\[^<]*)(<(/?)(\[^ \r\n\t>]+)(\[^>]*)>)?(.*)" $frag match pretag fulltag close tag tagbody frag]} { # we should never get here, the regexp should match anything # should never get here since above will match anything. lappend new_list $frag set frag {} } if {$pretag ne ""} { set pretag [string map {\n " "} $pretag] set pretag2 [list] foreach element [split $pretag " "] { if {[string trim $element] ne ""} { lappend pretag2 [string trim $element] } } if {[llength $pretag2]} { eval "lappend new_list $pretag2" } } if {$fulltag ne ""} { lappend new_list $fulltag } } # tcllib procs to get a list of differences between 2 lists # see: http://tcllib.sourceforge.net/doc/struct_list.html set len1 [llength $old_list] set len2 [llength $new_list] set result [::struct::list longestCommonSubsequence $old_list $new_list] set result [::struct::list lcsInvert $result $len1 $len2] # each chunk is either 'deleted', 'added', or 'changed' set i 0 set last_chunk "" foreach chunk $result { set action [lindex $chunk 0] set old_index1 [lindex [lindex $chunk 1] 0] set old_index2 [lindex [lindex $chunk 1] 1] set new_index1 [lindex [lindex $chunk 2] 0] set new_index2 [lindex [lindex $chunk 2] 1] while {$i < $old_index1} { lappend output [lindex $old_list $i] incr i } if { $action eq "changed" } { if {$show_old_p} { ns_log notice "adding <@d@>" lappend output <@d@> foreach item [lrange $old_list $old_index1 $old_index2] { if {![string match "<*>" [string trim $item]]} { ns_log notice "deleting item '${item}'" # showing deleted tags is a bad idea. lappend output [string trim $item] } else { ns_log notice "SKIPPED DELETE of tag $item" } } ns_log notice "adding " lappend output } ns_log notice "adding <@a@>" lappend output <@a@> foreach item [lrange $new_list $new_index1 $new_index2] { if {![string match "<*>" [string trim $item]]} { ns_log notice "adding item '${item}'" lappend output [string trim $item] } else { lappend output ${item}<@a@> ns_log notice "adding${item}<@a@>" } } ns_log notice "adding " lappend output incr i [expr {$old_index2 - $old_index1 + 1}] } elseif { $action eq "deleted" } { lappend output <@d@> foreach item [lrange $old_list $old_index1 $old_index2] { lappend output [string trim $item] } lappend output incr i [expr {$old_index2 - $old_index1 + 1}] } elseif { $action eq "added" } { while {$i < $old_index2} { ns_log notice "unchanged item" lappend output [lindex $old_list $i] incr i } lappend output <@a@> foreach item [lrange $new_list $new_index1 $new_index2] { if {![string match "<*>" [string trim $item]]} { ns_log notice "adding item" lappend output [string trim $item] } } lappend output } } # add any remaining words at the end. while {$i < $len1} { lappend output [lindex $old_list $i] incr i } set output [join $output " "] set output [string map {"<@d@>" {} "" "<@a@>" {} "" } $output] return "$output" }openacs-5.7.0/packages/acs-tcl/tcl/document-procs.tcl0000644000175000017500000001404411145353730022334 0ustar frankiefrankiead_library { An API for managing documents. @creation-date 22 May 2000 @author Jon Salz [jsalz@arsdigita.com] @cvs-id $Id: document-procs.tcl,v 1.5 2009/02/13 20:28:08 jeffd Exp $ } ad_proc -private doc_parse_property_string { properties } { Parses a properties declaration of the form that programmers specify. @param properties The property string as the programmer specified it. @error if there's any problems with the string. @return an internal array-as-a-list representation of the properties declaration. } { set property_array_list [list] set lines [split $properties \n] foreach line_raw $lines { set line [string trim $line_raw] if { $line eq "" } { continue } if { ![regexp {^([^:]+)(?::([^(]+)(?:\(([^)]+)\))?)?$} $line \ match name_raw type_raw columns] } { return -code error \ "Property doesn't have the right format, i.e. our regexp failed" } set name [string trim $name_raw] if { ![string is wordchar -strict $name] } { return -code error "Property name $name contains characters that\ are not Unicode word characters, but we don't allow that." } if { [info exists type_raw] && $type_raw ne "" } { set type [string trim $type_raw] } else { set type onevalue } # The following statement will set "type_repr" to our internal # representation of the type of this property. switch -- $type { onevalue - onelist - multilist { set type_repr $type } onerow - multirow { if { ![info exists columns] } { return -code error "Columns not defined for $type type\ property $name" } set column_split [split $columns ","] set column_list [list] foreach column_raw $column_split { set column [string trim $column_raw] if { $column eq "" } { return -code error "You have an empty column name in\ the definition of the $property property in the\ type $type" } lappend column_list $column } set type_repr [list $type $column_list] } default { return -code error \ "Unknown property type $type for property $name" } } lappend property_array_list $name $type_repr } return $property_array_list } ad_proc doc_init {} { Initializes the global environment for document handling. } { global doc_properties if { [info exists doc_properties] } { unset doc_properties } array set doc_properties {} } ad_proc doc_set_property { name value } { Sets a document property. } { global doc_properties set doc_properties($name) $value } ad_proc doc_property_exists_p { name } { Return 1 if a property exists, or 0 if not. } { global doc_properties return [info exists doc_properties($name)] } ad_proc doc_get_property { name } { Returns a property (or an empty string if no such property exists). } { global doc_properties if { [info exists doc_properties($name)] } { return $doc_properties($name) } return "" } ad_proc doc_body_append { str } { Appends $str to the body property. } { global doc_properties append doc_properties(body) $str } ad_proc doc_set_mime_type { mime_type } { Sets the mime-type property. } { doc_set_property mime_type $mime_type } ad_proc doc_exists_p {} { Returns 1 if there is a document in the global environment. } { global doc_properties if { [array size doc_properties] > 0 } { return 1 } return 0 } ad_proc doc_body_flush {} { Flushes the body (if possible). } { # Currently a no-op. } ad_proc doc_find_template { filename } { Finds a master.adp file which can be used as a master template, looking in the directory containing $filename and working our way down the directory tree. } { set path_root [acs_root_dir] set start [clock clicks -milliseconds] set dir [file dirname $filename] while { [string length $dir] > 1 && [string first $path_root $dir] == 0 } { # Only look in directories under the path root. if { [file isfile "$dir/master.adp"] } { return "$dir/master.adp" } set dir [file dirname $dir] } if { [file exists "$path_root/templates/master.adp"] } { return "$path_root/templates/master.adp" } # Uhoh. Nada! return "" } ad_proc doc_serve_template { __template_path } { Serves the document in the environment using a particular template. } { upvar #0 doc_properties __doc_properties foreach __name [array names __doc_properties] { set $__name $__doc_properties($__name) } set adp [ns_adp_parse -file $__template_path] set content_type [ns_set iget [ad_conn outputheaders] "content-type"] if { $content_type eq "" } { set content_type "text/html" } doc_return 200 $content_type $adp } ad_proc doc_serve_document {} { Serves the document currently in the environment. } { if { ![doc_exists_p] } { error "No document has been built." } set mime_type [doc_get_property mime_type] if { $mime_type eq "" } { if { [doc_property_exists_p title] } { set mime_type "text/html;content-pane" } else { set mime_type "text/html" } } switch $mime_type { text/html;content-pane - text/x-html-content-pane { # It's a content pane. Find the appropriate template. set template_path [doc_find_template [ad_conn file]] if { $template_path eq "" } { ns_returnerror 500 "Unable to find master template" ns_log error \ "Unable to find master template for file '[ad_conn file]'" } else { doc_serve_template $template_path } } default { # Return a complete document. ns_return 200 $mime_type [doc_get_property body] } } } proc doc_tag_ad_document { contents params } { for { set i 0 } { $i < [ns_set size $params] } { incr i } { doc_set_property [ns_set key $params $i] [ns_set value $params $i] } doc_set_property _adp 1 return [ns_adp_parse -string $contents] } proc doc_tag_ad_property { contents params } { set name [ns_set iget $params name] if { $name eq "" } { return "No name property in AD-PROPERTY tag" } doc_set_property $name $contents } openacs-5.7.0/packages/acs-tcl/tcl/membership-rel-procs-oracle.xql0000644000175000017500000000227110440426473024717 0ustar frankiefrankie oracle8.1.6 begin membership_rel.approve(rel_id => :rel_id); end; begin membership_rel.ban(rel_id => :rel_id); end; begin membership_rel.deleted(rel_id => :rel_id); end; begin membership_rel.reject(rel_id => :rel_id); end; begin membership_rel.unapprove(rel_id => :rel_id); end; begin membership_rel.merge(rel_id => :rel_id); end; openacs-5.7.0/packages/acs-tcl/tcl/tdom-procs.tcl0000644000175000017500000000616710771250204021464 0ustar frankiefrankie# /packages/acs-tcl/tcl/tdom-procs.tcl ad_library { Procedures to make parsing XML using TDOM a little easier @author avni@ucla.edu (AK) @creation-date 2004/10/19 @cvs-id $Id: tdom-procs.tcl,v 1.3 2008/03/22 18:31:32 gustafn Exp $ @tdom::get_node_object @tdom::get_parent_node_object @tdom::get_tag_value @tdom::get_attribute_value @tdom::get_node_xml } namespace eval tdom {} ad_proc -public tdom::get_node_object { parent_node_object args } { Returns a tdom object to the args given If the tdom object doesn't exist or the value is null, return null
        Example -----------------------------------------------------
        XML:     <experiment>
                     <experimenter>
                         <first-name>Annabelle Lee</first-name>
                         <last-name>Poe</last-name>
                     </experimenter>
                 </experiment>
        Params:  parent_node_object=$tdom_experiment_object
                 args=experimenter experimenter_two
        Returns: TDOM object for experimenter node
        End Example -------------------------------------------------
        
    } { # Do a loop for the args. The first non null result is returned set node_object "" foreach node_name $args { catch {set node_object [$parent_node_object getElementsByTagName "$node_name"]} if {$node_object ne "" } { return $node_object } } return $node_object } ad_proc -public tdom::get_parent_node_object { child_node_object } { Returns a tdom object for the parent node of the child node object passed in } { set parent_node_object "" catch {set parent_node_object [$child_node_object parentNode]} return $parent_node_object } ad_proc -public tdom::get_tag_value { node_object args } { Returns the tag value of the tag_name passed in If tag doesn't exist or the value is null, returns null
        Example -----------------------------------------------------
        XML:     <experiment-id>1222</experiment-id>
        Params:  node_object=$document
                 args=experiment-id EXPERIMENT-ID
        Returns: 1222
        End Example -------------------------------------------------
        
    } { # Do a loop for the args. The first non null result is returned set tag_value "" foreach tag_name $args { catch {set tag_value [[$node_object getElementsByTagName "$tag_name"] text]} errormsg if {[string trim $tag_value] ne "" } { return $tag_value } } return $tag_value } ad_proc -public tdom::get_attribute_value { node_object attribute_name {default_value ""} } { Returns the value of the attribute specified } { set attribute_value "" catch {set attribute_value [$node_object getAttribute $attribute_name $default_value]} return [string trim $attribute_value] } ad_proc -public tdom::get_node_xml { node_object } { Returns xml of the data pointed to by the node object If tag doesn't exist or the value is null, returns null } { set node_xml "" catch {set node_xml [$node_object asXML]} return [string trim $node_xml] }openacs-5.7.0/packages/acs-tcl/tcl/00-database-procs-postgresql-postgresql.xql0000644000175000017500000000075407572172052027133 0ustar frankiefrankie postgresql7.1 select nextval(:sequence) as nextval where (select relkind from pg_class where relname = :sequence) = 'S' select nextval from ${sequence} openacs-5.7.0/packages/acs-tcl/tcl/http-auth-procs.tcl0000644000175000017500000000714011346151020022422 0ustar frankiefrankie# packages/acs-tcl/tcl/http-auth-procs.tcl ad_library { Use openacs user logins for HTTP authentication } namespace eval http_auth {} ad_proc http_auth::set_user_id {} { Get the user_id from HTTP authentication headers. NOTE: This should be handled through SSL since plain HTTP auth is easy to decode } { # should be something like "Basic 29234k3j49a" set a [ns_set get [ns_conn headers] Authorization] if {[string length $a]} { ns_log debug "\nTDAV auth_check authentication info $a" # get the second bit, the base64 encoded bit set up [lindex [split $a " "] 1] # after decoding, it should be user:password; get the username set user [lindex [split [ns_uudecode $up] ":"] 0] set password [lindex [split [ns_uudecode $up] ":"] 1] ns_log debug "\nACS VERSION [ad_acs_version]" ns_log debug "\nHTTP authentication" # check all authorities foreach authority [auth::authority::get_authority_options] { set authority_id [lindex $authority 1] array set auth [auth::authenticate \ -username $user \ -password $password \ -authority_id $authority_id \ -no_cookie] if {$auth(auth_status) ne "ok" } { array set auth [auth::authenticate \ -email $user \ -password $password \ -authority_id $authority_id \ -no_cookie] } if {$auth(auth_status) eq "ok"} { # we can stop checking break } } if {$auth(auth_status) ne "ok" } { ns_log debug "\nTDAV 5.0 auth status $auth(auth_status)" ns_returnunauthorized return 0 } ns_log debug "\nTDAV: auth_check openacs 5.0 user_id= $auth(user_id)" ad_conn -set user_id $auth(user_id) } else { # no authenticate header, anonymous visitor ad_conn -set user_id 0 ad_conn -set untrusted_user_id 0 } } ad_proc http_auth::register_filter { -url_pattern {-proc ""} } { Setup HTTP authentication for a URL pattern @param url_pattern Follows ns_register_filter rules for defining the pattern to match. @param proc Name of tcl procedure to call to check permissions. Use this to figure out what object the URL pattern matches to. This proc should accept two named parameters user_id and url. Should return a valid Tcl true or false value. If empty the site_node matching the URL will be checked. @return Tcl true or false @author Dave Bauer (dave@solutiongrove.com) @creation-date 2007-03-08 } { ad_register_filter preauth GET $url_pattern http_auth::authorize $proc ad_register_filter preauth POST $url_pattern http_auth::authorize $proc ad_register_filter preauth HEAD $url_pattern http_auth::authorize $proc } ad_proc http_auth::authorize { conn args why } { Check HTTP authentication for an openacs user account and call the registered procedure to handle the URL to check permissions } { set user_id [http_auth::set_user_id] set proc [lindex $args 0] if {$proc eq {}} { set proc http_auth::site_node_authorize } return [eval [list $proc -user_id $user_id -url [ns_conn url]]] } ad_proc http_auth::site_node_authorize { -user_id -url } { Procedure to take HTTP authenticated user_id and check site_node permissions. Default if http auth is proc is not specified. } { set node_id [site_node::get_element -element node_id -url $url] if {[permission::permission_p \ -party_id $user_id \ -privilege read \ -object_id $node_id]} { return filter_ok } ns_returnunauthorized return filter_return } openacs-5.7.0/packages/acs-tcl/tcl/community-core-procs-postgresql.xql0000644000175000017500000000766107766162054025735 0ustar frankiefrankie postgresql7.1 select acs__add_user( :user_id, 'user', now(), null, :peeraddr, :authority_id, :username, :email, :url, :first_names, :last_name, :hashed_password, :salt, :screen_name, :email_verified_p, :member_state ); select acs__remove_user(:user_id); select person__delete(:person_id); select distinct u.first_names || ' ' || u.last_name || ' (' || u.email || ')' as name, u.user_id from cc_users u where lower(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || coalesce(u.screen_name, '')) like lower('%'||:value||'%') order by name select user_id, username, authority_id, first_names, last_name, first_names || ' ' || last_name as name, email, url, screen_name, priv_name, priv_email, email_verified_p, email_bouncing_p, no_alerts_until, last_visit, to_char(last_visit, 'YYYY-MM-DD HH24:MI:SS') as last_visit_ansi, second_to_last_visit, to_char(second_to_last_visit, 'YYYY-MM-DD HH24:MI:SS') as second_to_last_visit_ansi, n_sessions, password_question, password_answer, password_changed_date, member_state, rel_id, trunc(date_part('epoch', age(password_changed_date))/(60*60*24)) as password_age_days, creation_date, creation_ip from cc_users where user_id = :user_id select user_id, username, authority_id, first_names, last_name, first_names || ' ' || last_name as name, email, url, screen_name, priv_name, priv_email, email_verified_p, email_bouncing_p, no_alerts_until, last_visit, to_char(last_visit, 'YYYY-MM-DD HH24:MI:SS') as last_visit_ansi, second_to_last_visit, to_char(second_to_last_visit, 'YYYY-MM-DD HH24:MI:SS') as second_to_last_visit_ansi, n_sessions, password_question, password_answer, password_changed_date, member_state, rel_id, trunc(date_part('epoch', age(password_changed_date))/(60*60*24)) as password_age_days, creation_date, creation_ip from cc_users where authority_id = :authority_id and lower(username) = lower(:username) openacs-5.7.0/packages/acs-tcl/tcl/parameter-procs-oracle.xql0000644000175000017500000000145311345565523023772 0ustar frankiefrankie oracle8.1.6 begin apm.set_value( package_key => :package_key, parameter_name => :parameter, attr_value => :value ); end; begin apm.set_value( package_id => :package_id, parameter_name => :parameter, attr_value => :value ); end; openacs-5.7.0/packages/acs-tcl/tcl/object-procs-oracle.xql0000644000175000017500000000174310201461114023237 0ustar frankiefrankie oracle8.1.6 select acs_object.name(:object_id) from dual select o.object_id, o.title, o.package_id, o.object_type, o.context_id, o.security_inherit_p, o.creation_user, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date_ansi, o.creation_ip, to_char(o.last_modified, 'YYYY-MM-DD HH24:MI:SS') as last_modified_ansi, o.modifying_user, o.modifying_ip, acs_object.name(o.object_id) as object_name from acs_objects o where o.object_id = :object_id openacs-5.7.0/packages/acs-tcl/tcl/parameter-procs.tcl0000644000175000017500000002042511352533030022467 0ustar frankiefrankiead_library { parameter procs @author yon (yon@openforce.net) @creation-date May 12, 2002 @cvs-id $Id: parameter-procs.tcl,v 1.18 2010/03/25 01:02:16 donb Exp $ } namespace eval parameter {} ad_proc -public parameter::set_default { -package_key:required -parameter:required -value:required } { Set the default for the package parameter to the provided value. The new default will be used for new installs of the package but does not change existing package instances values. @param package_key what package to set the parameter for @param parameter which parameter's value to set @param value what value to set said parameter to } { db_dml set {} } ad_proc -public parameter::set_global_value { {-package_key:required} {-parameter:required} {-value:required} } { Set a global package parameter. Do not confuse this with the proc "set_from_package_key", which was previously used to emulate global parameters declared for singleton packages. @param package_key identifies the package to which the global param belongs @param parameter which parameter's value to set @param value what value to set said parameter to } { db_exec_plsql set_parameter_value {} return [ad_parameter_cache -set $value $package_key $parameter] } ad_proc -public parameter::get_global_value { -localize:boolean -boolean:boolean {-package_key:required} {-parameter:required} {-default ""} } { Get the value of a global package parameter. @param localize should we attempt to localize the parameter @param boolean insure boolean parameters are normalized to 0 or 1 @param package_key identifies the package to which the global param belongs @param parameter which parameter's value to get @param default what to return if we don't find a value. Defaults to returning the empty string. @return The string trimmed (leading and trailing spaces removed) parameter value } { # Is there a parameter by this name in the parameter file? If so, it takes precedence. # Note that this makes *far* more sense for global parameters than for package instance # parameters. # 1. use the parameter file set value [ad_parameter_from_file $parameter $package_key] # 2. check the parameter cache if {$value eq ""} { set value [ad_parameter_cache -global $package_key $parameter] } # 3. use the default value if {$value eq ""} { set value $default } if { $localize_p } { # Replace message keys in hash marks with localized texts set value [lang::util::localize $value] } # Trimming the value as people may have accidentally put in trailing spaces set value [string trim $value] # Special parsing for boolean parameters, true and false can be written # in many different ways if { $boolean_p } { if { [catch { if { [template::util::is_true $value] } { set value 1 } else { set value 0 } } errmsg] } { global errorInfo ns_log Error "Parameter $parameter not a boolean:\n$errorInfo" set value $default } } return $value } ad_proc -public parameter::set_value { {-package_id ""} {-parameter:required} {-value:required} } { Set the value of a package instance parameter @param package_id what package to set the parameter in. defaults to [ad_conn package_id] @param parameter which parameter's value to set @param value what value to set said parameter to } { if {$package_id eq ""} { set package_id [ad_requested_object_id] } db_exec_plsql set_parameter_value {} return [ad_parameter_cache -set $value $package_id $parameter] } ad_proc -public parameter::get { -localize:boolean -boolean:boolean {-package_id ""} {-parameter:required} {-default ""} } { Get the value of a package instance parameter. @param localize should we attempt to localize the parameter @param boolean insure boolean parameters are normalized to 0 or 1 @param package_id what package to get the parameter from. defaults to [ad_conn package_id] @param parameter which parameter's value to get @param default what to return if we don't find a value. Defaults to returning the empty string. @return The string trimmed (leading and trailing spaces removed) parameter value } { if {$package_id eq ""} { set package_id [ad_requested_object_id] } set package_key "" set value "" if {$package_id ne ""} { # This can fail at server startup--OpenACS calls parameter::get to # get the size of the util_memoize cache so it can setup the cache. # apm_package_key_from_id needs that cache, but on server start # when the toolkit tries to get the parameter for the cache size # the cache doesn't exist yet, so apm_package_key_from_id fails catch { set package_key [apm_package_key_from_id $package_id] } } # If I convert the package_id to a package_key, is there a parameter by this # name in the parameter file? If so, it takes precedence. # 1. use the parameter file if {$package_key ne ""} { set value [ad_parameter_from_file $parameter $package_key] } # 2. check the parameter cache if {$value eq ""} { set value [ad_parameter_cache $package_id $parameter] } # 3. use the default value if {$value eq ""} { set value $default } if { $localize_p } { # Replace message keys in hash marks with localized texts set value [lang::util::localize $value] } # Trimming the value as people may have accidentally put in trailing spaces set value [string trim $value] # Special parsing for boolean parameters, true and false can be written # in many different ways if { $boolean_p } { if { [catch { if { [template::util::is_true $value] } { set value 1 } else { set value 0 } } errmsg] } { global errorInfo ns_log Error "Parameter $parameter not a boolean:\n$errorInfo" set value $default } } return $value } ad_proc -public parameter::set_from_package_key { {-package_key:required} {-parameter:required} {-value:required} } { sets an instance parameter for the package corresponding to package_key. Note that this makes the assumption that the package is a singleton and does not set the value for all packages corresponding to package_key. New packages should use global parameters instead. } { parameter::set_value \ -package_id [apm_package_id_from_key $package_key] \ -parameter $parameter \ -value $value } ad_proc -public parameter::get_from_package_key { -localize:boolean -boolean:boolean {-package_key:required} {-parameter:required} {-default ""} } { Gets an instance parameter for the package corresponding to package_key. Note that this makes the assumption that the package is a singleton. New packages should use global parameters instead. @param package_key what package to get the parameter from. we will try to get the package_id from the package_key. this may cause an error if there are more than one instance of this package @param parameter which parameter's value to get @param default what to return if we don't find a value } { # 1. check to see if this parameter is being set in the server's # configuration file; this value has highest precedence set value [ad_parameter_from_file $parameter $package_key] # 2. try to get a package_id for this package_key and use the standard # parameter::get function to get the value if {$value eq ""} { with_catch errmsg { set value [parameter::get \ -localize=$localize_p \ -boolean=$boolean_p \ -package_id [apm_package_id_from_key $package_key] \ -parameter $parameter \ -default $default \ ] } { set value $default } } return $value } openacs-5.7.0/packages/acs-tcl/tcl/parameter-procs.xql0000644000175000017500000000040510221364161022506 0ustar frankiefrankie update apm_parameters set default_value = :value where package_key = :package_key and parameter_name = :parameter openacs-5.7.0/packages/acs-tcl/tcl/stack-trace-procs.tcl0000644000175000017500000000276510551254404022724 0ustar frankiefrankie# stack-trace-procs.tcl # (bdolicki 2000) - formerly known as StackTrace.tcl # Print stack trace after catch # Taken from http://photo.net/bboard/q-and-a-fetch-msg.tcl?msg_id=000kCh ad_library { @author bdolicki@branimir.com @creation-date 2000 @cvs-id $Id: stack-trace-procs.tcl,v 1.3 2007/01/10 21:22:12 gustafn Exp $ } ad_proc -public ad_print_stack_trace {} { Formerly known as PrintStackTrace. This is useful if you use catch but you'd still want to access the full Tcl stack trace e.g. to dump it into the log file This command truncatates the actual commands to improve readability while ad_get_tcl_call_stack dumps the full stack @see ad_get_tcl_call_stack } { uplevel { global errorInfo if {$errorInfo ne ""} { set callStack [list $errorInfo "invoked from within"] } else { set callStack {} } for {set i [info level]} {$i > 0} {set i [expr {$i - 1}]} { set call [info level $i] if {[string length $call] > 160} { set call "[string range $call 0 150]..." } regsub -all {\n} $call {\\n} call lappend callStack " $call" if {$i > 1} { lappend callStack "invoked from within" } } return [join $callStack "\n"] } } ad_proc -public ad_log_stack_trace {} { A wrapper for ad_print_stack_trace which does the logging for you. } { ns_log Error [ad_print_stack_trace] } openacs-5.7.0/packages/acs-tcl/tcl/application-data-link-procs.tcl0000644000175000017500000003053011547562462024673 0ustar frankiefrankiead_library { Procs of application data linking @author Timo Hentschel (timo@timohentschel.de) @creation-date 2005-05-23 } namespace eval application_data_link {} # modified 2006/07/25 nfl: db_transaction around db_dml # modified 2006/07/26 nfl: change db_transaction to catch ad_proc -public application_data_link::new { -this_object_id:required -target_object_id:required {-relation_tag ""} } { Create a new data link between this_object_id and target_object_id. @param this_object_id ID of the object that you want linked to the target object. @param target_object_id The ID of the target object. @param relation_tag Relationship identifier } { if { [catch { application_data_link::new_from \ -object_id $this_object_id \ -to_object_id $target_object_id \ -relation_tag $relation_tag application_data_link::new_to \ -object_id $this_object_id \ -from_object_id $target_object_id \ -relation_tag $relation_tag }]} { # check if error occured because of existing link if { [application_data_link::exist_link -object_id $this_object_id -target_object_id $target_object_id -relation_tag $relation_tag] eq "1" } { ns_log Debug "application_data_link::new: link already exists" } else { ns_log Error "application_data_link::new: link creation failure" } } } ad_proc -public application_data_link::new_from { -object_id:required -to_object_id:required {-relation_tag ""} } { Create a new data link between this_object_id and target_object_id. @param object_id ID of the object that you want linked to the target object. @param to_object_id The ID of the target object. @param relation_tag Relationship identifier } { set forward_rel_id [db_nextval acs_data_links_seq] # Flush the cache for both items util_memoize_flush_regexp "application_data_link::get_linked_not_cached -from_object_id $object_id -relation_tag $relation_tag .*" util_memoize_flush_regexp "application_data_link::get_linked_not_cached -from_object_id $to_object_id -relation_tag $relation_tag .*" util_memoize_flush_regexp "application_data_link::get_linked_content_not_cached -from_object_id $object_id .*" util_memoize_flush_regexp "application_data_link::get_linked_content_not_cached -from_object_id $to_object_id .*" db_dml create_forward_link {} } ad_proc -public application_data_link::new_to { -object_id:required -from_object_id:required {-relation_tag ""} } { Create a new data link between this_object_id and target_object_id. @param object_id ID of the object that you want linked to the target object. @param from_object_id The ID of the target object. @param relation_tag Relationship identifier } { set backward_rel_id [db_nextval acs_data_links_seq] # Flush the cache for both items util_memoize_flush_regexp "application_data_link::get_linked_not_cached -from_object_id $object_id -relation_tag $relation_tag .*" util_memoize_flush_regexp "application_data_link::get_linked_not_cached -from_object_id $from_object_id -relation_tag $relation_tag .*" util_memoize_flush_regexp "application_data_link::get_linked_content_not_cached -from_object_id $object_id .*" util_memoize_flush_regexp "application_data_link::get_linked_content_not_cached -from_object_id $from_object_id .*" db_dml create_backward_link {} } # created 2006/07/25 nfl exist a link, returns 0 or 1 ad_proc -public application_data_link::exist_link { -object_id:required -target_object_id:required {-relation_tag ""} } { Check for the existence of a link from an object_id to a target_object_id, with optional relation_tag. @param object_id The object we're looking for a link from @param target_object_id The object we're looking for a link to @param relation_tag Relationship identifier } { set linked_objects [ application_data_link::get -object_id $object_id -relation_tag $relation_tag] if { [lsearch -exact $linked_objects "$target_object_id"] != -1 } { # found link return 1 } else { return 0 } } ad_proc -public application_data_link::delete_links { -object_id:required {-relation_tag ""} } { Delete application data links for all objects linking to the given object_id. Optionally delete by object_id and relation_tag. @param object_id Object ID that you want application data links removed from. @param relation_tag Relationship identifier. } { set rel_ids [db_list linked_objects {}] foreach rel_id $rel_ids { db_dml delete_link {} } } ad_proc -public application_data_link::delete_from_list { -object_id -link_object_id_list {-relation_tag ""} } { Delete references @param object_id Object to delete links from @param link_object_id_list List of linked object_ids to delete @param relation_tag Relationship identifier @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-31 } { if {[llength $link_object_id_list]} { db_dml delete_links "" } } ad_proc -public application_data_link::get { -object_id:required {-relation_tag ""} } { Retrieves a list of object_ids for all objects linked to the given object_id, tagged with the optional relation_tag. @param object_id Retrieve objects linked to this object_id @param relation_tag Relationship identifier. @return List of linked object ids. } { return [db_list linked_objects {}] } ad_proc -public application_data_link::get_linked { -from_object_id:required -to_object_type:required {-relation_tag ""} } { Gets the ID for the object linked to from_object_id and matches the to_object_type. Optionally, pass a relationship tag. @param from_object_id Object ID of linked-from object. @param to_object_type Object type of linked-to object. @param relation_tag Relationship identifier @return object_id of linked object. } { return [util_memoize [list application_data_link::get_linked_not_cached -from_object_id $from_object_id -to_object_type $to_object_type -relation_tag $relation_tag]] } ad_proc -public application_data_link::get_linked_not_cached { -from_object_id:required -to_object_type:required {-relation_tag ""} } { Gets the ID for the object linked to from_object_id and matches the to_object_type. Optionally, pass a relationship tag. @param from_object_id Object ID of linked-from object. @param to_object_type Object type of linked-to object. @param relation_tag Relationship identifier @return object_id of linked object. } { return [db_list linked_object {}] } ad_proc -public application_data_link::get_linked_content { -from_object_id:required -to_content_type:required {-relation_tag ""} } { Gets the content of the linked object. @param from_object_id Object ID of linked-from object. @param to_content_type Content type of linked-to object. @param relation_tag @return item_id for the content item. } { return [util_memoize [list application_data_link::get_linked_content_not_cached -from_object_id $from_object_id -to_content_type $to_content_type -relation_tag $relation_tag]] } ad_proc -public application_data_link::get_linked_content_not_cached { -from_object_id:required -to_content_type:required {-relation_tag ""} } { Gets the content of the linked object. @param from_object_id Object ID of linked-from object. @param to_content_type Content type of linked-to object. @param relation_tag @return item_id for the content item. } { return [db_list linked_object {}] } ad_proc -public application_data_link::get_links_from { -object_id:required {-to_type} {-relation_tag ""} } { Get a list of objects that are linked from an object, possible using the relation_tag. If to_type is a subtype of content_revision, we lookup content_items that have that content_type @param object_id object_id one, get objects linked from this object @param to_type object_type of the objects to get links to } { set to_type_where_clause "" set content_type_from_clause "" if {[info exists to_type] && $to_type ne ""} { set to_type_clause [db_map to_type_where_clause] if {[content::type::is_content_type -object_type $to_type]} { set to_type_clause [db_map content_type_where_clause] set content_type_from_clause [db_map content_type_from_clause] } } return [db_list links_from {}] } ad_proc -public application_data_link::get_links_to { -object_id:required {-from_type} {-relation_tag ""} } { Get a list of objects that are linked to an object, possible using the relation_tag. If from_type is a subtype of content_revision, we lookup content_items that have that content_type @param object_id object_id two, get objects linked to this object @param from_type object_type of the objects to get links from } { set from_type_where_clause "" set content_type_from_clause "" if {[info exists from_type] && $from_type ne ""} { set from_type_clause [db_map from_type_where_clause] if {[content::type::is_content_type -content_type $from_type]} { set from_type_clause [db_map content_type_where_clause] set content_type_from_clause [db_map content_type_from_clause] } } return [db_list links_to {}] } ad_proc -public application_data_link::scan_for_links { -text } { Search for object references within text Supports /o/ /file/ /image/ object URL formats @param text Text to scan for object links @return List of linked object_ids @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-31 } { set refs [list] set http_url [string trimright [ad_url] /]/ set https_url [string map {http https} $http_url] set re "(?:\")(?:$http_url|$https_url|/)(?:o|image|file)/(\\d{1,8})" set ref_data [regexp -inline -all $re $text] foreach {discard ref} $ref_data { lappend refs $ref } if {[llength $refs]} { set refs [db_list confirm_object_ids {}] } return $refs } ad_proc -public application_data_link::update_links_from { -object_id {-text {}} {-link_object_ids {}} {-relation_tag ""} } { Update the references to this object in the database, optionally update links using the given relation_tag. @param object_id Object_id to update @param text Text to scan for references @param linked_object_ids List of object ids to update the links to. Links not in this list will be deleted, and any in this list that are not in teh database will be added. @param relation_tag Relationship identifier @return List of updated linked object_ids @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-31 } { set old_links [application_data_link::get_links_from -object_id $object_id -relation_tag $relation_tag] if {![llength $link_object_ids]} { set link_object_ids [application_data_link::scan_for_links -text $text] } set delete_ids [list] foreach old_link $old_links { if {[lsearch $link_object_ids $old_link] < 0} { lappend delete_ids $old_link } } application_data_link::delete_from_list -object_id $object_id -link_object_id_list $delete_ids -relation_tag $relation_tag foreach new_link $link_object_ids { if {![application_data_link::link_exists \ -from_object_id $object_id \ -to_object_id $new_link \ -relation_tag $relation_tag]} { application_data_link::new_from -object_id $object_id -to_object_id $new_link -relation_tag $relation_tag } } } ad_proc -public application_data_link::link_exists { -from_object_id -to_object_id {-relation_tag ""} } { Check if a link exists, only checks in the directon requested. Optionally check if the link has the given tag. @param from_object_id @param to_object_id @param relation_tag @return 0 or 1 @author Dave Bauer (dave@solutiongrove.com) @creation-date 2006-08-31 } { return [db_0or1row link_exists ""] } ad_proc -public application_data_link::relation_tag_where_clause { {-relation_tag ""} } { Utility proc to return relation tag where clause fragment. We show all object links regardless of tag if relation_tag is empty string. @param relation_tag Relationship identifier } { if {$relation_tag eq ""} { return "" } else { return [db_map where_clause] } } openacs-5.7.0/packages/acs-tcl/tcl/application-data-link-procs.xql0000644000175000017500000001202311542146423024700 0ustar frankiefrankie insert into acs_data_links (rel_id, object_id_one, object_id_two, relation_tag) values (:forward_rel_id, :object_id, :to_object_id, :relation_tag) insert into acs_data_links (rel_id, object_id_one, object_id_two, relation_tag) values (:backward_rel_id, :from_object_id, :object_id, :relation_tag) select rel_id from acs_data_links where (object_id_one = :object_id or object_id_two = :object_id) [application_data_link::relation_tag_where_clause -relation_tag $relation_tag] delete from acs_data_links where rel_id = :rel_id select object_id_two from acs_data_links where object_id_one = :object_id [application_data_link::relation_tag_where_clause -relation_tag $relation_tag] order by object_id_two select o.object_id from acs_objects o where o.object_type = :to_object_type and o.object_id in (select object_id_two from acs_data_links where object_id_one = :from_object_id [application_data_link::relation_tag_where_clause -relation_tag $relation_tag]) order by o.object_id select i.item_id from cr_items i where i.content_type = :to_content_type and i.item_id in (select object_id_two from acs_data_links where object_id_one = :from_object_id [application_data_link::relation_tag_where_clause -relation_tag $relation_tag]) order by i.item_id select object_id_two from acs_data_links, acs_objects $content_type_from_clause where object_id_one = :object_id and object_id = object_id_two [application_data_link::relation_tag_where_clause -relation_tag $relation_tag] $to_type_where_clause and object_type = :to_type , cr_items and content_type = :object_type select object_id_one from acs_data_links, acs_objects $content_type_from_clause where object_id_two = :object_id and object_id = object_id_one [application_data_link::relation_tag_where_clause -relation_tag $relation_tag] $from_type_where_clause and object_type = :from_type , cr_items and content_type = :object_type delete from acs_data_links where object_id_one=:object_id and object_id_two in ([template::util::tcl_to_sql_list $link_object_id_list]) [application_data_link::relation_tag_where_clause -relation_tag $relation_tag] select 1 from acs_data_links where object_id_one = :from_object_id and object_id_two = :to_object_id [application_data_link::relation_tag_where_clause -relation_tag $relation_tag] select object_id from acs_objects where object_id in ([template::util::tcl_to_sql_list $refs]) and relation_tag = :relation_tag openacs-5.7.0/packages/acs-tcl/tcl/apm-procs-postgresql.xql0000644000175000017500000001016611352533030023510 0ustar frankiefrankie postgresql7.1 select apm_package__highest_version ( :package_key ); select version_name from apm_package_versions where package_key = :package_key and version_id = apm_package__highest_version(:package_key) select apm_package__num_instances( :package_key ); select apm__register_parameter( :parameter_id, :package_key, :parameter_name, :description, :scope, :datatype, :default_value, :section_name, :min_n_values, :max_n_values ); select apm__unregister_parameter(:parameter_id) select apm_package_version__add_dependency( :dependency_type, :dependency_id, :version_id, :dependency_uri, :dependency_version ); select apm_package_version__remove_dependency( :dependency_id ); select apm_package_version__add_interface( :interface_id, :version_id, :interface_uri, :interface_version ); select apm_package_version__remove_interface( :interface_id ); select case when count(*) = 0 then 0 else 1 end from apm_package_versions where package_key = :package_key and version_name = :version_name select apm_package__new( :package_id, :instance_name, :package_key, 'apm_package', now(), null, null, :context_id ); select apm_package__delete(:package_id); select site_node__url(min(node_id)) from site_nodes where object_id = :package_id select package_key, pretty_name from apm_package_types where not (apm_package__singleton_p(package_key) = 1 and apm_package__num_instances(package_key) >= 1) order by pretty_name select apm_parameter_value__new(null, :package_id, ap.parameter_id, ap.default_value) from apm_parameters ap where ap.package_key = :new_package_key and not exists (select 1 from apm_parameters ap2 where ap2.package_key = :old_package_key and ap2.parameter_name = ap.parameter_name) openacs-5.7.0/packages/acs-tcl/tcl/security-procs-postgresql.xql0000644000175000017500000000400610673446134024613 0ustar frankiefrankie postgresql7.1 update sec_session_properties set property_value = :value, secure_p = :secure, last_hit = :last_hit where session_id = :session_id and module = :module and property_name = :name update users set second_to_last_visit = last_visit, last_visit = now(), n_sessions = n_sessions + 1 where user_id = :user_id select test_sql('select 1 where 1=[DoubleApos $value]') select test_sql('select 1 where 1=[DoubleApos "'$value'"]') insert into secret_tokens(token_id, token, token_timestamp) values(nextval('t_sec_security_token_id_seq'), :random_token, now()) select token_id, token from secret_tokens, (select trunc(random()*(select count(*)-15 from secret_tokens))::integer as first) r where token_id >= r.first and r.first+15 > token_id; update users set password = :new_password, salt = :salt, password_changed_date = current_timestamp where user_id = :user_id openacs-5.7.0/packages/acs-tcl/tcl/navigation-procs.tcl0000644000175000017500000005223011325443027022653 0ustar frankiefrankiead_library { Provides procedures to spit out the navigational parts of the site. @cvs-id $Id: navigation-procs.tcl,v 1.29 2010/01/19 23:53:59 torbenb Exp $ @author philg@mit.edu @creation-date 11/5/98 (adapted originally from the Cognet server) } # edited February 28, 1999 by philg to include support for a # Yahoo-style navigation system (showing users where they are in a # hierarchy) ad_proc -public ad_context_bar_html { -separator context } { Generate the an html fragement for a context bar. This is the function that takes a list in the format
        [list [list url1 text1] [list url2 text2] ... "terminal text"] 
        
        and generates the html fragment.  In general the higher level 
        proc ad_context_bar should be
        used, and then only in the sitewide master rather than on 
        individual pages.
    
        @param separator The text placed between each link
        @param context list as with ad_context_bar 
        
        @return html fragment
    
        @see ad_context_bar
    } { 
        
        # Get the separator from subsite parameter
        if { ![info exists separator] } {
            set subsite_id [ad_conn subsite_id]
            set separator [parameter::get -package_id $subsite_id -parameter ContextBarSeparator -default ":"]
        }
    
        set out {}
        foreach element [lrange $context 0 [expr {[llength $context] - 2}]] { 
            append out "[lindex $element 1] $separator "
        }
        append out [lindex $context end]
    
        return $out
    }
    
    ad_proc ad_context_node_list {
        {-from_node ""}
        node_id
    } {
        Starting with the given node_id, return a list of
        [list url instance_name] items for parent nodes.
    
        @option from_node The top-most node_id for which we'll show context bar. This can be used with 
        the node_id of the nearest subsite to get the context-bar only up to the nearest subsite.
    
        @author Peter Marklund
    } {
        set context [list]
    
        while { $node_id ne "" } {
            array set node [site_node::get -node_id $node_id]
            
            # JCD: Provide something for the name if the instance name is
            # absent.  name is the tail bit of the url which seems like a
            # reasonable thing to display.
            if {$node(instance_name) eq ""
                && [info exists node(name)]} { 
                set node(instance_name) $node(name)
            }
    
            set context [concat [list [list $node(url) [ad_quotehtml $node(instance_name)]]] $context]
    
            # We have the break here, so that 'from_node' itself is included
            if {$node_id eq $from_node} {
                break
            }
            
            set node_id $node(parent_id)
        }
    
        return $context
    }
    
    ad_proc -public ad_context_bar_multirow { 
        {-from_node ""}
        -node_id
        {-multirow "context"}
        context
    } {
        Returns a Yahoo-style hierarchical navbar. Includes "Administration"
        if applicable, and the subsite if not global. 'args' can be either
        one or more lists, or a simple string.
    
        @param node_id If provided work up from this node, otherwise the current node
        @param from_node If provided do not generate links to the given node and above.
        @param separator The text placed between each link (passed to ad_context_bar_html if provided)
        @return an html fragment generated by ad_context_bar_html
        
        @see ad_context_bar_html
    } {
        if {![parameter::get -package_id [ad_conn subsite_id] -parameter ShowContextBarP -default 1]} {
    	return ""
        }
        
        if { ![exists_and_not_null node_id] } {
            set node_id [ad_conn node_id]
        }
    
        set temp_node_id [util_current_location_node_id]
        if { $temp_node_id eq "" } {
            # not a site host_node 
            set node_id_url ""
            set node_id_url_end 0
        } else {
            set from_node $temp_node_id
            set node_id_url [site_node::get_url -node_id ${temp_node_id} -notrailing]    
            set node_id_url_end [string length $node_id_url]
        }
    
        template::multirow create $multirow url label
    
        foreach elm [ad_context_node_list -from_node $from_node $node_id] {
            set elm_0 [lindex $elm 0]
            set elm_1 [lindex $elm 1]
            if { $node_id_url_end > 0 && [string match -nocase $node_id_url [string range $elm_0 0 ${node_id_url_end}-1] ] } {
                set elm_0 [string range $elm_0 $node_id_url_end end]
            }
            template::multirow append $multirow $elm_0 $elm_1
        }
        
        if { [string match "admin/*" [ad_conn extra_url]] } {
            template::multirow append $multirow "[ad_conn package_url]admin/" "[_ acs-tcl.Administration]"
        }
        
        if { [llength $context] == 0 } { 
            # fix last element to just be literal string
            template::multirow set $multirow [template::multirow size $multirow] url {}
        } else {
            foreach elm [lrange $context 0 end-1] {
                template::multirow append $multirow [lindex $elm 0] [lindex $elm 1]
            }
            template::multirow append $multirow {} [lindex $context end]
        }
    }
    
    ad_proc -public ad_context_bar { 
        {-from_node ""}
        -node_id
        -separator
        args
    } {
        Returns a Yahoo-style hierarchical navbar. Includes "Administration"
        if applicable, and the subsite if not global. 'args' can be either
        one or more lists, or a simple string.
    
        @param node_id If provided work up from this node, otherwise the current node
        @param from_node If provided do not generate links to the given node and above.
        @param separator The text placed between each link (passed to ad_context_bar_html if provided)
        @return an html fragment generated by ad_context_bar_html
        
        @see ad_context_bar_html
    } {
        if {![parameter::get -package_id [ad_conn subsite_id] -parameter ShowContextBarP -default 1]} {
    	return ""
        }
    
        if { ![exists_and_not_null node_id] } {
            set node_id [ad_conn node_id]
        }
    
        set context [ad_context_node_list -from_node $from_node $node_id]
    
        if { [string match "admin/*" [ad_conn extra_url]] } {
            lappend context [list "[ad_conn package_url]admin/" \
                                 "[_ acs-tcl.Administration]"]
        }
    
        if {[llength $args] == 0} { 
            # fix last element to just be literal string
            set context [lreplace $context end end [lindex [lindex $context end] 1]]
        } else {
    	if {![string match "\{*" $args]} {
    	    # args is not a list, transform it into one.
    	    set args [list $args]
    	}	
        }
    
        if { [info exists separator] } {
            return [ad_context_bar_html -separator $separator [concat $context $args]]
        } else {
            return [ad_context_bar_html [concat $context $args]]
        }
    }
    
    
    
    ad_proc -deprecated -public ad_context_bar_ws args {
        Returns a Yahoo-style hierarchical navbar. Use ad_context_bar instead.
    
        @param list of url desc ([list [list url desc] [list url desc] ... "terminal"])
        @return an html fragment generated by ad_context_bar_html
    
        @see ad_context_bar
    } {
        return [ad_context_bar $args]
    }
    
    # a context bar, rooted at the workspace or index, depending on whether
    # user is logged in
    
    ad_proc -deprecated -public ad_context_bar_ws_or_index args {
        Returns a Yahoo-style hierarchical navbar. Use ad_context_bar instead.
    
        @param args list of url desc ([list [list url desc] [list url desc] ... "terminal"])
        @return an html fragment generated by ad_context_bar
    
        @see ad_context_bar
    } {
        return [ad_context_bar $args]
    }
    
    ad_proc -public -deprecated ad_admin_context_bar args { 
        Returns a Yahoo-style hierarchical navbar. Use ad_context_bar instead.
    
        @param args list of url desc ([list [list url desc] [list url desc] ... "terminal"])
        @return an html fragment generated by ad_context_bar
    
        @see ad_context_bar
    } {
        return [ad_context_bar $args]
    }
    
    ad_proc -public ad_navbar args {
        produces navigation bar. notice that navigation bar is different
        than context bar, which displays packages in the site map. Navbar will
        only generate HTML for those links passed to it.
    
        @param args list of url desc ([list [list url desc] [list url desc]])
    
        @return html fragment
    
        @see ad_context_bar_html
    } {
        set counter 0
        foreach arg $args {
    	lappend link_list "[lindex $arg 1]"
    	incr counter
        }
        if { $counter } {
    	return "\[[join $link_list " | "]\]"
        } else {
    	return ""
        }
    }
    
    ad_proc -public ad_choice_bar { items links values {default ""} } {
        Displays a list of choices (Yahoo style), with the currently selected one highlighted.
    
        @see ad_navbar 
    } {
    
        set count 0
        set return_list [list]
    
        foreach value $values {
    	if { $default eq $value  } {
    	        lappend return_list "[lindex $items $count]"
    	} else {
    	        lappend return_list "[lindex $items $count]"
    	}
    
    	incr count
        }
    
        if { [llength $return_list] > 0 } {
            return "\[[join $return_list " | "]\]"
        } else {
    	return ""
        }
        
    }
    
    ad_proc -public util_current_location_node_id { } {
        returns node_id of util_current_location. Useful for hostnode mapped sites using ad_context_bar
    } {
        regexp {^([a-z]+://)?([^:]+)(:[0-9]*)?$} [util_current_location] match location_proto location_hostname location_port
        if { [string match -nocase "www.*" $location_hostname] } {
            set location_hostname [string range $location_hostname 4 end]
        } 
        db_0or1row -cache_key util-${location_hostname}-node-id get_node_id_from_hostname "select node_id from host_node_map where host = :location_hostname"
        if { ![info exists node_id ] } {
            set node_id ""
        }
        return $node_id
    }
    
    # directories that should not receive links to move up one level
    
    proc ad_no_uplevel_patterns {} {
        set regexp_patterns [list]
        lappend regexp_patterns "*/pvt/home.tcl"
        # tcl files in the root directory
        lappend regexp_patterns "^/\[^/\]*\.tcl\$"
        lappend regexp_patterns "/admin*"
    }
    
    
    # determines if java_script should be enabled
        
    proc java_script_capabilities {} {
        set user_agent ""
        set version 0
        set internet_explorer_p 0
        set netscape_p 0
    	
        # get the version
        set user_agent [ns_set get [ad_conn headers] User-Agent]
        regexp -nocase "mozilla/(\[^\.\ \]*)" $user_agent match version
    
        # IE browsers have MSIE and Mozilla in their user-agent header
        set internet_explorer_p [regexp -nocase "msie" $user_agent match]
    
        # Netscape browser just have Mozilla in their user-agent header
        if {$internet_explorer_p == 0} {
    	set netscape_p [regexp -nocase "mozilla" $user_agent match]
        }
       
        set java_script_p 0
     
        if { ($netscape_p && ($version >= 3)) || ($internet_explorer_p && ($version >= 4)) } {
    	set java_script_p 1
        }
    
        return $java_script_p
    }
    
    # netscape3 browser has a different output
    
    proc netscape3_browser {} {
        set user_agent ""
        set version 0
        set internet_explorer_p 0
        set netscape_p 0
        
        # get the version
        set user_agent [ns_set get [ad_conn headers] User-Agent]
        regexp -nocase "mozilla/(\[^\.\ \]*)" $user_agent match version
        
        # IE browsers have MSIE and Mozilla in their user-agent header
        set internet_explorer_p [regexp -nocase "msie" $user_agent match]
        
        # Netscape browser just have Mozilla in their user-agent header
        if {$internet_explorer_p == 0} {
    	set netscape_p [regexp -nocase "mozilla" $user_agent match]
        }
     
        set netscape3_p 0
     
        if { ($netscape_p && ($version == 3))} {
    	set netscape3_p 1
        }
    
        return $netscape3_p
    }
    
    
    
    # creates the generic javascript/nonjavascript
    # select box for the submenu
    
    proc menu_submenu_select_list {items urls {highlight_url "" }} {
        set return_string ""
        set counter 0
    
        append return_string "
    
    \n" } # this incorporates HTML designed by Ben (not adida, some other guy) proc ad_menu_header {{section ""} {uplink ""}} { set section [string tolower $section] # if it is an excluded directory, just return set url_stub [ad_conn url] set full_filename "[ns_info pageroot]$url_stub" foreach naked_pattern [ad_naked_html_patterns] { if { [string match $naked_pattern $url_stub] } { # want the global admins with no menu, but not the domain admin return "" } } # title is the title for the title bar # section is the highlight for the menu set menu_items [menu_items] set java_script_p [java_script_capabilities] # Ben has a different table structure for netscape 3 set netscape3_p [netscape3_browser] set return_string "" if { $java_script_p } { append return_string " " } else { append return_string " " } # We divide up the screen into 4 areas top to bottom: # + The top table which is the cognet logo and search stuff. # + The next table down is the CogNet name and area name. # + The next area is either 1 large table with 2 sub-tables, or two tables (NS 3.0). # The left table is the navigation table and the right one is the content. # + Finally, the bottom table holds the bottom navigation bar. append return_string "[ad_body_tag]" if {$netscape3_p} { append return_string "\"Cognet\" " } else { append return_string "
    \"Cognet\" " } append return_string "
    Search
         " if {$netscape3_p} { append return_string "  
    " } else { append return_string "\"go\"
    " } append return_string " " set uplevel_string "" foreach url_pattern [ad_no_uplevel_patterns] { if { [regexp $url_pattern $url_stub match] } { set uplevel_string "" } } append return_string $uplevel_string append return_string "
    \"$section\"\"Up\"
    " if {$netscape3_p} { append return_string "" } else { append return_string "
    openacs-5.7.0/packages/acs-templating/www/doc/demo/fibo.tcl0000644000175000017500000000007110551254405023420 0ustar frankiefrankieset one_less [expr {$n - 1}] set two_less [expr {$n - 2}]openacs-5.7.0/packages/acs-templating/www/doc/demo/puts.adp0000644000175000017500000000070407253523117023465 0ustar frankiefrankie

    There's More than One Way to Do it

    ADP

    x is four x differs from four

    TCL

    You can call adp_puts from Tcl. This procedure is undocumented, and its use is deprecated.

    <% if {$x == 4} { adp_puts "x is four" } { adp_puts "x differs from four" } %> openacs-5.7.0/packages/acs-templating/www/doc/demo/puts.tcl0000644000175000017500000000017107537470230023503 0ustar frankiefrankiead_page_contract { @cvs-id $Id: puts.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { x:onevalue } set x 5 openacs-5.7.0/packages/acs-templating/www/doc/demo/form.adp0000644000175000017500000000044307253523117023435 0ustar frankiefrankie

    Add a User



    openacs-5.7.0/packages/acs-templating/www/doc/demo/form.tcl0000644000175000017500000000214607531053324023452 0ustar frankiefrankieform create add_user -elements { user_id -label "User ID" -datatype integer -widget hidden first_name -html { size 30 } -label "First Name" -datatype text last_name -html { size 30 } -label "Last Name" -datatype text address1 -html { size 40 } -label "Address 1" -optional -datatype text address2 -html { size 40 } -label "Address 2" -optional -datatype text city -html { size 25 } -label "City" -optional -datatype text state -html { size 3 maxlength 2 } \ -label "State" -datatype keyword \ -validate { {expr [string length $value] == 2 } \ { State must be 2 characters in length } } } \ -html { onSubmit "return confirm('Are you sure you want to submit?');" } # set values if { [form is_request add_user] } { set user_id [db_string get_user_id ""] element set_properties add_user user_id -value $user_id } if { [form is_valid add_user] } { db_dml insert_sample " insert into ad_template_sample_users values ( :user_id, :first_name, :last_name, :address1, :address2, :city, :state )" -bind [ns_getform] template::forward index.html } openacs-5.7.0/packages/acs-templating/www/doc/demo/form.xql0000644000175000017500000000030607661404626023501 0ustar frankiefrankie select ad_template_sample_users_seq.nextval openacs-5.7.0/packages/acs-templating/www/doc/demo/index.html0000644000175000017500000005223610374102560024001 0ustar frankiefrankieTemplating System Samples

    Samples

    Templating System : Demo
    As the links reveal, the "Data" files have the extension .tcl and the "Template" files have .adp. If you want to see a little behind the scenes, you can look at the tcl code into which we compile the template. The last column will deliver the resulting page to your browser.

    Mechanisms underlaid in red are known to not work.

    General

    " } # Navigation Table foreach item $menu_items { if { $item == [menu_highlight $section] } { append return_string "" } else { append return_string "" } } append return_string "
    \"$item\"
    \"$item\"
    [menu_subsection $section]
    " if {$netscape3_p} { append return_string "" } else { append return_string "
    " } append return_string "
    " } proc ad_menu_footer {{section ""}} { # if it is an excluded directory, just return set url_stub [ad_conn url] set full_filename "[ns_info pageroot]$url_stub" foreach naked_pattern [ad_naked_html_patterns] { if { [string match $naked_pattern $url_stub] } { return "" } } set netscape3_p 0 if {[netscape3_browser]} { set netscape3_p 1 } append return_string "
    " # close up the table if {$netscape3_p != 1} { append return_string "
    " } # bottom bar append return_string "
    \"top\" \"rules\"\"help\"
    " return $return_string } openacs-5.7.0/packages/acs-tcl/tcl/xml-2-procs.tcl0000644000175000017500000002111610551254404021451 0ustar frankiefrankiead_library { @original-header # xml.tcl -- # # This file provides XML services. # These services include a XML document instance and DTD parser, # as well as support for generating XML. # # Copyright (c) 1998,1999 Zveno Pty Ltd # http://www.zveno.com/ # # Zveno makes this software and all associated data and documentation # ('Software') available free of charge for non-commercial purposes only. You # may make copies of the Software but you must include all of this notice on # any copy. # # The Software was developed for research purposes and Zveno does not warrant # that it is error free or fit for any purpose. Zveno disclaims any # liability for all claims, expenses, losses, damages and costs any user may # incur as a result of using, copying or modifying the Software. # # Copyright (c) 1997 Australian National University (ANU). # # ANU makes this software and all associated data and documentation # ('Software') available free of charge for non-commercial purposes only. You # may make copies of the Software but you must include all of this notice on # any copy. # # The Software was developed for research purposes and ANU does not warrant # that it is error free or fit for any purpose. ANU disclaims any # liability for all claims, expenses, losses, damages and costs any user may # incur as a result of using, copying or modifying the Software. # @cvs-id $Id: xml-2-procs.tcl,v 1.2 2007/01/10 21:22:12 gustafn Exp $ } package provide xml 1.9 namespace eval xml { # Procedures for parsing XML documents namespace export parser # Procedures for parsing XML DTDs namespace export DTDparser # Counter for creating unique parser objects variable ParserCounter 0 # Convenience routine proc cl x { return "\[$x\]" } # Define various regular expressions # white space variable Wsp " \t\r\n" variable noWsp [cl ^$Wsp] # Various XML names and tokens variable NameChar $::sgml::NameChar variable Name $::sgml::Name variable Nmtoken $::sgml::Nmtoken # Tokenising expressions variable tokExpr <(/?)([cl ^$Wsp>/]+)([cl $Wsp]*[cl ^>]*)> variable substExpr "\}\n{\\2} {\\1} {\\3} \{" # table of predefined entities variable EntityPredef array set EntityPredef { lt < gt > amp & quot \" apos ' } } # xml::parser -- # # Creates XML parser object. # # Arguments: # args Unique name for parser object # plus option/value pairs # # Recognised Options: # -final Indicates end of document data # -elementstartcommand Called when an element starts # -elementendcommand Called when an element ends # -characterdatacommand Called when character data occurs # -processinginstructioncommand Called when a PI occurs # -externalentityrefcommand Called for an external entity reference # # (Not compatible with expat) # -xmldeclcommand Called when the XML declaration occurs # -doctypecommand Called when the document type declaration occurs # # -errorcommand Script to evaluate for a fatal error # -warningcommand Script to evaluate for a reportable warning # -statevariable global state variable # -reportempty whether to provide empty element indication # # Results: # The state variable is initialised. proc xml::parser {args} { variable ParserCounter if {[llength $args] > 0} { set name [lindex $args 0] set args [lreplace $args 0 0] } else { set name parser[incr ParserCounter] } if {[info command [namespace current]::$name] != {}} { return -code error "unable to create parser object \"[namespace current]::$name\" command" } # Initialise state variable and object command upvar \#0 [namespace current]::$name parser set sgml_ns [namespace parent]::sgml array set parser [list name $name \ -final 1 \ -elementstartcommand ${sgml_ns}::noop \ -elementendcommand ${sgml_ns}::noop \ -characterdatacommand ${sgml_ns}::noop \ -processinginstructioncommand ${sgml_ns}::noop \ -externalentityrefcommand ${sgml_ns}::noop \ -xmldeclcommand ${sgml_ns}::noop \ -doctypecommand ${sgml_ns}::noop \ -warningcommand ${sgml_ns}::noop \ -statevariable [namespace current]::$name \ -reportempty 0 \ internaldtd {} \ ] proc [namespace current]::$name {method args} \ "eval ParseCommand $name \$method \$args" eval ParseCommand [list $name] configure $args return [namespace current]::$name } # xml::ParseCommand -- # # Handles parse object command invocations # # Valid Methods: # cget # configure # parse # reset # # Arguments: # parser parser object # method minor command # args other arguments # # Results: # Depends on method proc xml::ParseCommand {parser method args} { upvar \#0 [namespace current]::$parser state switch -- $method { cget { return $state([lindex $args 0]) } configure { foreach {opt value} $args { set state($opt) $value } } parse { ParseCommand_parse $parser [lindex $args 0] } reset { if {[llength $args]} { return -code error "too many arguments" } ParseCommand_reset $parser } default { return -code error "unknown method \"$method\"" } } return {} } # xml::ParseCommand_parse -- # # Parses document instance data # # Arguments: # object parser object # xml data # # Results: # Callbacks are invoked, if any are defined proc xml::ParseCommand_parse {object xml} { upvar \#0 [namespace current]::$object parser variable Wsp variable tokExpr variable substExpr set parent [namespace parent] if {"::" eq $parent } { set parent {} } set tokenised [lrange \ [${parent}::sgml::tokenise $xml \ $tokExpr \ $substExpr \ -internaldtdvariable [namespace current]::${object}(internaldtd)] \ 4 end] eval ${parent}::sgml::parseEvent \ [list $tokenised \ -emptyelement [namespace code ParseEmpty] \ -parseattributelistcommand [namespace code ParseAttrs]] \ [array get parser -*command] \ [array get parser -entityvariable] \ [array get parser -reportempty] \ -normalize 0 \ -internaldtd [list $parser(internaldtd)] return {} } # xml::ParseEmpty -- # # Used by parser to determine whether an element is empty. # This is dead easy in XML. # # Arguments: # tag element name # attr attribute list (raw) # e End tag delimiter. # # Results: # Return value of e proc xml::ParseEmpty {tag attr e} { return $e } # xml::ParseAttrs -- # # Parse element attributes. # # There are two forms for name-value pairs: # # name="value" # name='value' # # Arguments: # attrs attribute string given in a tag # # Results: # Returns a Tcl list representing the name-value pairs in the # attribute string # # A ">" occurring in the attribute list causes problems when parsing # the XML. This manifests itself by an unterminated attribute value # and a ">" appearing the element text. # In this case return a three element list; # the message "unterminated attribute value", the attribute list it # did manage to parse and the remainder of the attribute list. proc xml::ParseAttrs attrs { variable Wsp variable Name set result {} while {[string length [string trim $attrs]]} { if {[regexp ($Name)[cl $Wsp]*=[cl $Wsp]*("|')([cl ^<]*?)\\2(.*) $attrs discard attrName delimiter value attrs]} { lappend result $attrName $value } elseif {[regexp $Name[cl $Wsp]*=[cl $Wsp]*("|')[cl ^<]*\$ $attrs]} { return -code error [list {unterminated attribute value} $result $attrs] } else { return -code error "invalid attribute list" } } return $result } # xml::ParseCommand_reset -- # # Initialize parser data # # Arguments: # object parser object # # Results: # Parser data structure initialised proc xml::ParseCommand_reset object { upvar \#0 [namespace current]::$object parser array set parser [list \ -final 1 \ internaldtd {} \ ] } # xml::noop -- # # A do-nothing proc proc xml::noop args {} ### Following procedures are based on html_library # xml::zapWhite -- # # Convert multiple white space into a single space. # # Arguments: # data plain text # # Results: # As above proc xml::zapWhite data { regsub -all "\[ \t\r\n\]+" $data { } data return $data } # # DTD parser for XML is wholly contained within the sgml.tcl package # # xml::parseDTD -- # # Entry point to the XML DTD parser. # # Arguments: # dtd XML data defining the DTD to be parsed # args configuration options # # Results: # Returns a three element list, first element is the content model # for each element, second element are the attribute lists of the # elements and the third element is the entity map. proc xml::parseDTD {dtd args} { return [eval [expr {[namespace parent] == {::} ? {} : [namespace parent]}]::sgml::parseDTD [list $dtd] $args] } openacs-5.7.0/packages/acs-tcl/tcl/object-procs-postgresql.xql0000644000175000017500000000177110201461114024176 0ustar frankiefrankie postgresql7.1 select acs_object__name(:object_id); select o.object_id, o.title, o.package_id, o.object_type, o.context_id, o.security_inherit_p, o.creation_user, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date_ansi, o.creation_ip, to_char(o.last_modified, 'YYYY-MM-DD HH24:MI:SS') as last_modified_ansi, o.modifying_user, o.modifying_ip, o.tree_sortkey, acs_object__name(o.object_id) as object_name from acs_objects o where o.object_id = :object_id openacs-5.7.0/packages/acs-tcl/tcl/apm-xml-procs.tcl0000644000175000017500000003544011456662501022100 0ustar frankiefrankiead_library { Functions that APM uses to parse and generate XML. @author Bryan Quinn (bquinn@arsdigita.com) @author Ben Adida (ben@mit.edu) @author Bart Teeuwisse (bart.teeuwisse@thecodemill.biz) @creation-date Fri Oct 6 21:47:39 2000 @cvs-id $Id: apm-xml-procs.tcl,v 1.30 2010/10/17 21:06:09 donb Exp $ } ad_proc -private apm_required_attribute_value { element attribute } { Returns an attribute of an XML element, throwing an error if the attribute is not set. } { set value [apm_attribute_value $element $attribute] if { $value eq "" } { error "Required attribute \"$attribute\" missing from <[xml_node_get_name $element]>" } return $value } ad_proc -private apm_attribute_value { { -default "" } element attribute } { Parses the XML element to return the value for the specified attribute. } { ns_log Debug "apm_attribute_value $element $attribute $default --> [xml_node_get_attribute $element $attribute $default]" return [xml_node_get_attribute $element $attribute $default] } ad_proc -private apm_tag_value { { -default "" } root property_name } { Parses the XML element and returns the associated property name if it exists. } { ns_log Debug "apm_tag_value [$root nodeName] $property_name" set node [xml_node_get_first_child_by_name $root $property_name] if { $node ne "" } { return [xml_node_get_content $node] } ns_log Debug "apm_tag_value $root $property_name $default --> $default" return $default } ad_proc -private apm_generate_package_spec { version_id } { Generates an XML-formatted specification for a version of a package. } { set spec {} db_1row package_version_select {} apm_log APMDebug "APM: Writing Package Specification for $pretty_name $version_name" set auto_mount_tag [ad_decode $auto_mount "" "" "$auto_mount\n"] append spec " [ad_quotehtml $pretty_name] [ad_quotehtml $pretty_plural] $initial_install_p $singleton_p $implements_subsite_p $inherit_templates_p ${auto_mount_tag} \n" db_foreach owner_info {} { append spec " [ad_quotehtml $owner_name]\n" } apm_log APMDebug "APM: Writing Version summary and description" if { $summary ne "" } { append spec " [ad_quotehtml $summary]\n" } if { $release_date ne "" } { append spec " [ad_quotehtml [string range $release_date 0 9]]\n" } if { $vendor ne "" || $vendor_uri ne "" } { append spec " [ad_quotehtml $vendor]\n" } if { $description ne "" } { append spec " [ad_quotehtml $description]\n" } append spec [apm::package_version::attributes::generate_xml \ -version_id $version_id \ -indentation " "] append spec "\n" apm_log APMDebug "APM: Writing Dependencies." db_foreach dependency_info {} { append spec " <$dependency_type url=\"[ad_quotehtml $service_uri]\" version=\"[ad_quotehtml $service_version]\"/>\n" } else { append spec " \n" } append spec "\n \n" apm_log APMDebug "APM: Writing callbacks" db_foreach callback_info {} { append spec " \n" } append spec " " append spec "\n \n" apm_log APMDebug "APM: Writing parameters" set parent_package_keys [lrange [apm_one_package_inherit_order $package_key] 0 end-1] db_foreach parameter_info {} { append spec " \n" } if_no_rows { append spec " \n" } append spec " \n\n" append spec " " apm_log APMDebug "APM: Finished writing spec." return $spec } ad_proc -public apm_read_package_info_file { path } { Reads a .info file, returning an array containing the following items:
    • path: a path to the file read
    • mtime: the mtime of the file read
    • provides, embeds, extends, and requires:

      lists of dependency information, containing elements of the form [list $url $version]

    • owners: a list of owners containing elements of the form [list $url $name]
    • files: a list of files in the package, containing elements of the form [list $path $type] NOTE: Files are no longer stored in info files but are always retrieved directly from the file system. This element in the array will always be the empty list.
    • callbacks: an array list of callbacks of the package on the form [list callback_type1 proc_name1 callback_type2 proc_name2 ...]
    • Element and attribute values directly from the XML specification: package.key, package.url, package.type pretty-plural initial-install-p singleton-p auto-mount name (the version name, e.g., 3.3a1, url (the version URL), package-name, option, summary, description, release-date, vendor, group, vendor.url, and description.format.
    This routine will typically be called like so:
    array set version_properties [apm_read_package_info_file $path]
    to populate the version_properties array.

    If the .info file cannot be read or parsed, this routine throws a descriptive error. } { global ad_conn # If the .info file hasn't changed since last read (i.e., has the same # mtime), return the cached info list. set mtime [file mtime $path] if { [nsv_exists apm_version_properties $path] } { set cached_version [nsv_get apm_version_properties $path] if { [lindex $cached_version 0] == $mtime } { return [lindex $cached_version 1] } } # Set the path and mtime in the array. set properties(path) $path set properties(mtime) $mtime apm_log APMDebug "Reading specification file at $path" set file [open $path] set xml_data [read $file] close $file set tree [xml_parse -persist $xml_data] set root_node [xml_doc_get_first_node $tree] apm_log APMDebug "XML: root node is [xml_node_get_name $root_node]" set package $root_node set root_name [xml_node_get_name $package] # Debugging Children set root_children [xml_node_get_children $root_node] apm_log APMDebug "XML - there are [llength $root_children] child nodes" foreach child $root_children { apm_log APMDebug "XML - one root child: [xml_node_get_name $child]" } if { $root_name ne "package" } { apm_log APMDebug "XML: the root name is $root_name" error "Expected as root node" } set properties(package.key) [apm_required_attribute_value $package key] set properties(package.url) [apm_required_attribute_value $package url] set properties(package.type) [apm_attribute_value -default "apm_application" $package type] set properties(package-name) [apm_tag_value $package package-name] set properties(initial-install-p) [apm_tag_value -default "f" $package initial-install-p] set properties(auto-mount) [apm_tag_value -default "" $package auto-mount] set properties(singleton-p) [apm_tag_value -default "f" $package singleton-p] set properties(implements-subsite-p) [apm_tag_value -default "f" $package implements-subsite-p] set properties(inherit-templates-p) [apm_tag_value -default "t" $package inherit-templates-p] set properties(pretty-plural) [apm_tag_value -default "$properties(package-name)s" $package pretty-plural] set versions [xml_node_get_children_by_name $package version] if { [llength $versions] != 1 } { error "Package must contain exactly one node" } set version [lindex $versions 0] set properties(name) [apm_required_attribute_value $version name] set properties(url) [apm_required_attribute_value $version url] # Set an entry in the properties array for each of these tags. foreach property_name { summary description release-date vendor } { set properties($property_name) [apm_tag_value $version $property_name] } apm::package_version::attributes::parse_xml \ -parent_node $version \ -array properties # Set an entry in the properties array for each of these attributes: # # -> vendor.url # -> description.format foreach { property_name attribute_name } { vendor url description format } { set node [xml_node_get_first_child_by_name $version $property_name] if { $node ne "" } { set properties($property_name.$attribute_name) [apm_attribute_value $node $attribute_name] } else { set properties($property_name.$attribute_name) "" } } # We're done constructing the properties array - save the properties into the # moby array which we're going to return. set properties(properties) [array get properties] # Build lists of the services provided by and required by the package. set properties(provides) [list] set properties(requires) [list] set properties(embeds) [list] set properties(extends) [list] foreach dependency_type { provides requires embeds extends } { set dependency_types [xml_node_get_children_by_name $version $dependency_type] foreach node $dependency_types { set service_uri [apm_required_attribute_value $node url] set service_version [apm_required_attribute_value $node version] # Package always provides itself, we'll add that below, so don't add it here if { $dependency_type ne "provides" || ![string equal $service_uri $properties(package.key)] } { lappend properties($dependency_type) [list $service_uri $service_version] } } } # Package provides itself always lappend properties(provides) [list $properties(package.key) $properties(name)] set properties(files) [list] # Build a list of package callbacks array set callback_array {} set callbacks_node_list [xml_node_get_children_by_name $version callbacks] foreach callbacks_node $callbacks_node_list { set callback_node_list [xml_node_get_children_by_name $callbacks_node callback] foreach callback_node $callback_node_list { set type [apm_attribute_value $callback_node type] set proc [apm_attribute_value $callback_node proc] if { [llength [array get callback_array $type]] != 0 } { # A callback proc of this type already found in the xml file ns_log Error "package info file $path contains more than one callback proc of type $type" continue } if { [lsearch -exact [apm_supported_callback_types] $type] < 0 } { # The callback type is not supported ns_log Error "package info file $path contains an unsupported callback type $type - ignoring. Valid values are [apm_supported_callback_types]" continue } set callback_array($type) $proc } } set properties(callbacks) [array get callback_array] # Build a list of the package's owners (if any). set properties(owners) [list] set owners [xml_node_get_children_by_name $version owner] foreach node $owners { set url [apm_attribute_value $node url] set name [xml_node_get_content $node] lappend properties(owners) [list $name $url] } # Build a list of the packages parameters (if any) set properties(parameters) [list] apm_log APMDebug "APM: Reading Parameters" set parameters [xml_node_get_children_by_name $version parameters] foreach node $parameters { set parameter_nodes [xml_node_get_children_by_name $node parameter] foreach parameter_node $parameter_nodes { set default_value [apm_attribute_value $parameter_node default] set min_n_values [apm_attribute_value $parameter_node min_n_values] set max_n_values [apm_attribute_value $parameter_node max_n_values] set description [apm_attribute_value $parameter_node description] set section_name [apm_attribute_value $parameter_node section_name] set datatype [apm_attribute_value $parameter_node datatype] set name [apm_attribute_value $parameter_node name] set scope [apm_attribute_value $parameter_node scope] if { $scope eq "" } { set scope instance } apm_log APMDebug "APM: Reading parameter $name with default $default_value" lappend properties(parameters) [list $name $description $section_name $scope $datatype $min_n_values $max_n_values $default_value] } } # Release the XML tree xml_doc_free $tree # Serialize the array into a list. set return_value [array get properties] # Cache the property info based on $mtime. nsv_set apm_version_properties $path [list $mtime $return_value] return $return_value } openacs-5.7.0/packages/acs-tcl/tcl/apm-xml-procs.xql0000644000175000017500000000470411456662501022121 0ustar frankiefrankie select t.package_key, t.package_uri, t.pretty_name, t.pretty_plural, t.package_type, t.initial_install_p, t.singleton_p, t.implements_subsite_p, t.inherit_templates_p, v.* from apm_package_versions v, apm_package_types t where v.version_id = :version_id and v.package_key = t.package_key select owner_uri, owner_name from apm_package_owners where version_id = :version_id order by sort_key, owner_uri select dependency_type, service_uri, service_version from apm_package_dependencies where version_id = :version_id order by dependency_type, service_uri select type, proc from apm_package_callbacks where version_id = :version_id select type, proc from apm_package_callbacks where version_id = :version_id select ap.parameter_name, ap.description, ap.datatype, ap.section_name, ap.default_value, ap.min_n_values, ap.max_n_values, ap.scope from apm_parameters ap where ap.package_key = :package_key and not exists (select 1 from apm_parameters ap2 where ap.parameter_name = ap2.parameter_name and ap2.package_key in ('[join $parent_package_keys ',']') ) order by ap.parameter_name openacs-5.7.0/packages/acs-tcl/tcl/sql-statement-procs.tcl0000644000175000017500000000432610551254404023317 0ustar frankiefrankiead_library { Procs for manipulating SQL statements @author lars@pinds.com, May 2000 @cvs-id $Id: sql-statement-procs.tcl,v 1.3 2007/01/10 21:22:12 gustafn Exp $ How to use this: You simply call ad_sql_append any number of times, then ad_sql_get to feed to the database. What you gain from using these two procs is that the parts of the sql statement will always be output in the right sequence. How this works: We represent a SQL statement as a Tcl array of the form stmt(select) { t1.column1 t2.column2 t2.column3 ... } join by , stmt(from) { { table1 t1} {table2 t2} } join by , stmt(where) { condition1 condition2 } join by and stmt(groupby) { groupcol1 groupcol2 } join by , stmt(orderby) { {ordercol1 asc} {ordercol2 desc}} join by , } ad_proc -public ad_sql_get { { } sqlarrayname } { @param sqlarrayname array reference @return a sql statement constructed from the pieces provided via ad_sql_append @see ad_sql_append } { upvar $sqlarrayname sql if { ![info exists sql(select)] } { error "SQL statement doesn't have any SELECT clause" } if { ![info exists sql(from)] } { error "SQL statement doesn't have any FROM clause" } set sql_string "select [join $sql(select) ", "]\nfrom [join $sql(from) ", "]\n" if { [info exists sql(where)] && [llength $sql(where)] > 0 } { append sql_string "where [join $sql(where) "\nand "]\n" } if { [info exists sql(groupby)] && [llength $sql(groupby)] > 0 } { append sql_string "group by [join $sql(groupby) ", "]\n" } if { [info exists sql(orderby)] && [llength $sql(orderby)] > 0 } { append sql_string "order by [join $sql(orderby) ", "]\n" } return $sql_string } ad_proc -public ad_sql_append { { -select {} -from {} -where {} -groupby {} -orderby {} } sqlarrayname } { Adds to the SQL statement. } { upvar $sqlarrayname sql if { $select ne "" } { lappend sql(select) $select } if { $from ne "" } { lappend sql(from) $from } if { $where ne "" } { lappend sql(where) $where } if { $groupby ne "" } { lappend sql(groupby) $groupby } if { $orderby ne "" } { lappend sql(orderby) $orderby } } openacs-5.7.0/packages/acs-tcl/tcl/site-node-apm-integration-procs.tcl0000644000175000017500000000421310551254404025474 0ustar frankiefrankiead_library { site node / apm integration procs @author arjun (arjun@openforce.net) @author yon (yon@openforce.net) @creation-date 2002-07-10 @cvs-id $Id: site-node-apm-integration-procs.tcl,v 1.12 2007/01/10 21:22:12 gustafn Exp $ } namespace eval site_node_apm_integration { ad_proc -public delete_site_nodes_and_package { {-package_id:required} } { First deletes ALL the site nodes this instance is mapped to, then deletes the instance. } { db_transaction { # should here be a pre-destruction proc like the post instantiation proc? foreach site_node_info_list [site_node::get_all_from_object_id -object_id $package_id] { ns_log debug "delete_site_nodes_and_package: $site_node_info_list" array set site_node $site_node_info_list site_node::unmount -node_id $site_node(node_id) site_node::delete -node_id $site_node(node_id) site_node::update_cache -node_id $site_node(node_id) } apm_package_instance_delete $package_id } } ad_proc -public get_child_package_id { {-package_id ""} {-package_key:required} } { get the package_id of package_key that is mounted directly under package_id. returns empty string if not found. } { if {$package_id eq ""} { if {[ad_conn isconnected]} { set package_id [ad_conn package_id] } else { error "Not in a connection and no package_id provided" } } return [db_string select_child_package_id {} -default ""] } ad_proc -public child_package_exists_p { {-package_id ""} {-package_key:required} } { Returns 1 if there exists a child package with the given package_key, or 0 if not. } { set child_package_id [get_child_package_id \ -package_id $package_id \ -package_key $package_key ] if {$child_package_id eq ""} { return 0 } else { return 1 } } } openacs-5.7.0/packages/acs-tcl/tcl/site-node-apm-integration-procs.xql0000644000175000017500000000111307513153751025521 0ustar frankiefrankie select sn1.object_id from site_nodes sn1, apm_packages where sn1.parent_id = (select sn2.node_id from site_nodes sn2 where sn2.object_id = :package_id) and sn1.object_id = apm_packages.package_id and apm_packages.package_key = :package_key openacs-5.7.0/packages/acs-tcl/tcl/utilities-init.tcl0000644000175000017500000000120711346200003022326 0ustar frankiefrankiead_library { Initializes datastructures for utility procs. @creation-date 02 October 2000 @author Bryan Quinn @cvs-id $Id: utilities-init.tcl,v 1.9 2010/03/11 14:36:51 victorg Exp $ } # initialize the random number generator randomInit [ns_time] # Create mutex for util_background_exec nsv_set util_background_exec_mutex . [ns_mutex create oacs:bg_exec] # if logmaxbackup in config is missing or zero, don't run auto-logrolling set logmaxbackup [ns_config -int "ns/parameters" logmaxbackup 0] if { $logmaxbackup } { ad_schedule_proc -all_servers t -schedule_proc ns_schedule_daily \ [list 00 00] util::roll_server_log } openacs-5.7.0/packages/acs-tcl/tcl/request-processor-init.tcl0000644000175000017500000001067611145041201024032 0ustar frankiefrankiead_library { Initialization stuff for the request processing pipeline. @creation-date 30 May 2000 @author Jon Salz [jsalz@arsdigita.com] @cvs-id $Id: request-processor-init.tcl,v 1.14 2009/02/12 15:38:41 jeffd Exp $ } # These procedures are dynamically defined at startup to alleviate # lock contention. Thanks to davis@xarg.net. if { [parameter::get -package_id [ad_acs_kernel_id] -parameter PerformanceModeP -default 0] } { ad_proc -private rp_performance_mode {} { Returns 1 if the request processor is in performance mode, 0 otherwise. } { return 1 } } else { ad_proc -private rp_performance_mode {} { Returns 1 if the request processor is in performance mode, 0 otherwise. } { return 0 } } # JCD this belongs in acs-permission-init.tcl but I did not want to duplicate [ad_acs_kernel_id] # Nuke the existing definition. and create one with the parameter set #JCD move into first call of cache_p nsv_set rp_properties request_count 0 foreach method {GET HEAD POST} { ns_register_filter preauth $method /resources/* rp_resources_filter ns_register_filter preauth $method * rp_filter ns_register_proc $method / rp_handler } # Unregister any GET/HEAD/POST handlers for /*.tcl (since they # interfere with the abstract URL system). AOLserver automatically # registers these in file.tcl if EnableTclPages=On. ns_unregister_proc GET /*.tcl ns_unregister_proc HEAD /*.tcl ns_unregister_proc POST /*.tcl set listings [ns_config "ns/server/[ns_info server]" "directorylisting" "none"] if { $listings eq "fancy" || $listings eq "simple" } { nsv_set rp_directory_listing_p . 1 } else { nsv_set rp_directory_listing_p . 0 } # this initialization must be in a package alphabetically before # acs-templating, so this adp handler can be overwritten there. foreach { type handler } { tcl rp_handle_tcl_request adp rp_handle_adp_request vuh rp_handle_tcl_request } { rp_register_extension_handler $type $handler } ad_after_server_initialization filters_register { if {[nsv_exists rp_filters .]} { set filters [nsv_get rp_filters .] } else { set filters [list] } # This lsort is what makes the priority stuff work. It guarantees # that filters are registered in order of priority. AOLServer will # then run the filters in the order they were registered. set filters [lsort -integer -index 0 $filters] nsv_set rp_filters . $filters set filter_index 0 foreach filter_info $filters { util_unlist $filter_info priority kind method path \ proc arg debug critical description script # Figure out how to invoke the filter, based on the number of arguments. if { [llength [info procs $proc]] == 0 } { # [info procs $proc] returns nothing when the procedure has been # registered by C code (e.g., ns_returnredirect). Assume that neither # "conn" nor "why" is present in this case. set arg_count 1 } else { set arg_count [llength [info args $proc]] } if { $debug eq "t" } { set debug_p 1 } else { set debug_p 0 } ns_log Notice "ns_register_filter $kind $method $path rp_invoke_filter \ [list $filter_index $debug_p $arg_count $proc $arg]" ns_register_filter $kind $method $path rp_invoke_filter \ [list $filter_index $debug_p $arg_count $proc $arg] incr filter_index } } ad_after_server_initialization procs_register { if {[nsv_exists rp_registered_procs .]} { set procs [nsv_get rp_registered_procs .] } else { set procs [list] } set proc_index 0 foreach proc_info $procs { util_unlist $proc_info method path proc arg debug noinherit description script if { $noinherit eq "t" } { set noinherit_switch "-noinherit" } else { set noinherit_switch "" } # Figure out how to invoke the filter, based on the number of arguments. if { [llength [info procs $proc]] == 0 } { # [info procs $proc] returns nothing when the procedure has been # registered by C code (e.g., ns_returnredirect). Assume that neither # "conn" nor "why" is present in this case. set arg_count 1 } else { set arg_count [llength [info args $proc]] } if { $debug eq "t" } { set debug_p 1 } else { set debug_p 0 } ns_log Notice "ns_register_proc $noinherit_switch [list $method $path rp_invoke_proc [list $proc_index $debug_p $arg_count $proc $arg]]" eval ns_register_proc $noinherit_switch \ [list $method $path rp_invoke_proc [list $proc_index $debug_p $arg_count $proc $arg]] } } openacs-5.7.0/packages/acs-tcl/tcl/request-processor-init.xql0000644000175000017500000000067207271213363024066 0ustar frankiefrankie select package_id from apm_packages where package_key = 'acs-admin' select package_id from apm_packages where package_key = 'acs-admin' openacs-5.7.0/packages/acs-tcl/tcl/json-procs.tcl0000644000175000017500000004535211541163310021466 0ustar frankiefrankiead_library { Utility ad_procs for Tcl <-> JSON conversion. This is based on the tcllib json package written by Andreas Kupries, and later rewritten to parse via regular expressions by Thomas Maeder. The tcllib version suffers from generating Tcl structures from JSON strings with no type (JSON array or object) information. The resulting structures can't be converted back to JSON strings, you have to munge them with type information first. And the code making use the Tcl structure also needs to know whether each field is an object or array. It also depends on the DICT package or Tcl 8.5. This rewrite doesn't depend on DICT, declares procs using ad_proc (so the API will be picked up by our API browser), and is symmetrical (you can convert from JSON to the Tcl representation and back again). I've not renamed internal variables in the typical OpenACS style. I've placed these in the global util namespace for two reasons: 1. Don't want to clash with the tcllib json package in case someone else decides to use it. 2. Might put it in acs-tcl as part of the utility stuff someday. More information ... See http://www.json.org/ && http://www.ietf.org/rfc/rfc4627.txt Total rework of the code published with version number 1.0 by Thomas Maeder, Glue Software Engineering AG @creation-date 2010/04/09 @author Don Baccus @cvs-id $Id: json-procs.tcl,v 1.3 2011/03/19 17:24:24 donb Exp $ } namespace eval util { namespace eval json { namespace eval array {} namespace eval object {} # Regular expression for tokenizing a JSON text (cf. http://json.org/) # tokens consisting of a single character variable singleCharTokens { "{" "}" ":" "\\[" "\\]" "," } variable singleCharTokenRE "\[[join $singleCharTokens {}]\]" # quoted string tokens variable escapableREs { "[\\\"\\\\/bfnrt]" "u[[:xdigit:]]{4}" } variable escapedCharRE "\\\\(?:[join $escapableREs |])" variable unescapedCharRE {[^\\\"]} variable stringRE "\"(?:$escapedCharRE|$unescapedCharRE)*\"" # (unquoted) words variable wordTokens { "true" "false" "null" } variable wordTokenRE [join $wordTokens "|"] # number tokens # negative lookahead (?!0)[[:digit:]]+ might be more elegant, but # would slow down tokenizing by a factor of up to 3! variable positiveRE {[1-9][[:digit:]]*} variable cardinalRE "-?(?:$positiveRE|0)" variable fractionRE {[.][[:digit:]]+} variable exponentialRE {[eE][+-]?[[:digit:]]+} variable numberRE "${cardinalRE}(?:$fractionRE)?(?:$exponentialRE)?" # JSON token variable tokenRE "$singleCharTokenRE|$stringRE|$wordTokenRE|$numberRE" # 0..n white space characters set whiteSpaceRE {[[:space:]]*} # Regular expression for validating a JSON text variable validJsonRE "^(?:${whiteSpaceRE}(?:$tokenRE))*${whiteSpaceRE}$" } } ad_proc -private util::json::validate {jsonText} { Validate JSON text @param jsonText JSON text @return 1 iff $jsonText conforms to the JSON grammar (@see http://json.org/) } { variable validJsonRE return [regexp -- $validJsonRE $jsonText] } ad_proc util::json::parse {jsonText} { Parse JSON text into a tcl list. @param jsonText JSON text @return List containing the object represented by jsonText } { variable tokenRE set tokens [regexp -all -inline -- $tokenRE $jsonText] set nrTokens [llength $tokens] set tokenCursor 0 return [parseValue $tokens $nrTokens tokenCursor] } ad_proc -private util::json::unexpected {tokenCursor token expected} { Throw an exception signaling an unexpected token } { return -code error "unexpected token \"$token\" at position $tokenCursor; expecting $expected" } ad_proc -private util::json::unquoteUnescapeString {token} { Get rid of the quotes surrounding a string token and substitute the real characters for escape sequences within it @param token @return Unquoted, unescaped value of the string contained in token } { set unquoted [string range $token 1 end-1] return [subst -nocommands -novariables $unquoted] } ad_proc -private util::json::parseObjectMember {tokens nrTokens tokenCursorName objectDictName} { Parse an object member @param tokens list of tokens @param nrTokens length of $tokens @param tokenCursorName name (in caller's context) of variable holding current position in $tokens @param objectDictName name (in caller's context) of dict representing the JSON object of which to parse the next member } { upvar $tokenCursorName tokenCursor upvar $objectDictName objectDict set token [lindex $tokens $tokenCursor] incr tokenCursor set leadingChar [string index $token 0] if {$leadingChar eq "\""} { set memberName [unquoteUnescapeString $token] if {$tokenCursor == $nrTokens} { unexpected $tokenCursor "END" "\":\"" } else { set token [lindex $tokens $tokenCursor] incr tokenCursor if {$token eq ":"} { set memberValue [parseValue $tokens $nrTokens tokenCursor] lappend objectDict $memberName $memberValue } else { unexpected $tokenCursor $token "\":\"" } } } else { unexpected $tokenCursor $token "STRING" } } ad_proc -private util::json::parseObjectMembers {tokens nrTokens tokenCursorName objectDictName} { Parse the members of an object @param tokens list of tokens @param nrTokens length of $tokens @param tokenCursorName name (in caller's context) of variable holding current position in $tokens @param objectDictName name (in caller's context) of dict representing the JSON object of which to parse the next member } { upvar $tokenCursorName tokenCursor upvar $objectDictName objectDict while true { parseObjectMember $tokens $nrTokens tokenCursor objectDict set token [lindex $tokens $tokenCursor] incr tokenCursor switch -exact $token { "," { # continue } "\}" { break } default { unexpected $tokenCursor $token "\",\"|\"\}\"" } } } } ad_proc -private util::json::parseObject {tokens nrTokens tokenCursorName} { Parse an object @param tokens list of tokens @param nrTokens length of $tokens @param tokenCursorName name (in caller's context) of variable holding current position in $tokens @return parsed object (Tcl dict) } { upvar $tokenCursorName tokenCursor if {$tokenCursor == $nrTokens} { unexpected $tokenCursor "END" "OBJECT" } else { set result {} set token [lindex $tokens $tokenCursor] if {$token eq "\}"} { # empty object incr tokenCursor } else { parseObjectMembers $tokens $nrTokens tokenCursor result } return [list _object_ $result] } } ad_proc -private util::json::parseArrayElements {tokens nrTokens tokenCursorName resultName} { Parse the elements of an array @param tokens list of tokens @param nrTokens length of $tokens @param tokenCursorName name (in caller's context) of variable holding current position in $tokens @param resultName name (in caller's context) of the list representing the JSON array } { upvar $tokenCursorName tokenCursor upvar $resultName result while true { lappend result [parseValue $tokens $nrTokens tokenCursor] if {$tokenCursor == $nrTokens} { unexpected $tokenCursor "END" "\",\"|\"\]\"" } else { set token [lindex $tokens $tokenCursor] incr tokenCursor switch -exact $token { "," { # continue } "\]" { break } default { unexpected $tokenCursor $token "\",\"|\"\]\"" } } } } } ad_proc -private util::json::parseArray {tokens nrTokens tokenCursorName} { Parse an array @param tokens list of tokens @param nrTokens length of $tokens @param tokenCursorName name (in caller's context) of variable holding current position in $tokens @return parsed array (Tcl list) } { upvar $tokenCursorName tokenCursor if {$tokenCursor == $nrTokens} { unexpected $tokenCursor "END" "ARRAY" } else { set result {} set token [lindex $tokens $tokenCursor] set leadingChar [string index $token 0] if {$leadingChar eq "\]"} { # empty array incr tokenCursor } else { parseArrayElements $tokens $nrTokens tokenCursor result } return [list _array_ $result] } } ad_proc -private util::json::parseValue {tokens nrTokens tokenCursorName} { Parse a value @param tokens list of tokens @param nrTokens length of $tokens @param tokenCursorName name (in caller's context) of variable holding current position in $tokens @return parsed value (dict, list, string, number) } { upvar $tokenCursorName tokenCursor if {$tokenCursor == $nrTokens} { unexpected $tokenCursor "END" "VALUE" } else { set token [lindex $tokens $tokenCursor] incr tokenCursor set leadingChar [string index $token 0] switch -exact $leadingChar { "\{" { return [parseObject $tokens $nrTokens tokenCursor] } "\[" { return [parseArray $tokens $nrTokens tokenCursor] } "\"" { # quoted string return [unquoteUnescapeString $token] } "t" - "f" - "n" { # bare word: true, false or null return $token } default { # number? if {[string is double -strict $token]} { return $token } else { unexpected $tokenCursor $token "VALUE" } } } } } ad_proc -private util::json::gen_inner {value} { Generate a JSON string for a sub-list of a Tcl JSON "object". @param value A list representing a JSON object/array or value @return Valid JSON object, array, or value string. } { foreach { type arg } $value { switch -- $type { _object_ { return [util::json::object2json $arg] } _array_ { return [util::json::array2json $arg] } default { if { ![string is double -strict $value] && ![regexp {^(?:true|false|null)$} $value]} { set value "\"$value\"" } # Cleanup linebreaks regsub -all {\r\n} $value "\n" value regsub -all {\r} $value "\n" value # JSON requires new line characters be escaped regsub -all {\n} $value "\\n" value return $value } } } } ad_proc -private util::json::object2json {objectVal} { Generate a JSON string for a two-element Tcl JSON object list. @param objectVal [list object values] @return Valid JSON object string. } { set values {} foreach {key val} $objectVal { if { $val eq "" } { lappend values "\"$key\":\"\"" } else { lappend values "\"$key\":[util::json::gen_inner $val]" } } return "\{[join $values ,]\}" } ad_proc -private util::json::array2json {arrayVal} { Generate a JSON string for a two-element Tcl JSON array list. @param objectVal [list array values] @return Valid JSON array string. } { set values {} foreach val $arrayVal { if { $val eq "" } { lappend values "\"\"" } else { lappend values [util::json::gen_inner $val] } } return "\[[join $values ,]\]" } ad_proc util::json::gen {value} { Top-level procedure to generate a JSON string from its Tcl list representation. @param value A two-element object/array Tcl list. @return A valid JSON string. } { if { [llength $value] != 2 } { return -code error "Ill-formed JSON object: length in gen is [llength $value]" } return [util::json::gen_inner $value] } ad_proc util::json::json_value_to_sql_value {value} { While mysql happily treats false as 0, real SQL does not. And we need to protect against apostrophes in strings. And handle null. You get the idea. @param value A value from a parsed JSON string @return Something that works in Real SQL, not to be confused with MySQL. This includes not trying to insert '' into columns of type real, when "null" is meant (we mimic Oracle bindvar/PG bindvar emulation sematics). The Ilias RTE JavaScript returns '' rather than null for JS null variables. } { switch $value { false { return 0 } true { return 1 } null - "" { return null } default { return "'[DoubleApos $value]'" } } } ad_proc util::json::array::create {values} { Construct a JSON object with the given values list } { return [list _array_ $values] } ad_proc util::json::array::get_values {item} { Verify that the given Tcl structure is an object, and return its values list. } { if { [lindex $item 0] ne "_array_" } { return -code error "Expected \"_array_\", got \"[lindex $item 0]\"" } else { return [lindex $item 1] } } ad_proc util::json::object::create {values} { Construct a JSON object with the given values list } { return [list _object_ $values] } ad_proc util::json::object::get_values {item} { Verify that the given Tcl structure is an object, and return its values list. } { if { [lindex $item 0] ne "_object_" } { return -code error "Expected \"_object_\", got \"[lindex $item 0]\"" } else { return [lindex $item 1] } } ad_proc util::json::type_of {item} { Return the type of the item, "object" or "array" } { switch [lindex $item 0] { _object_ { return object } _array_ { return array } default { return -code error "Expected \"_array_\" or \"_object_\", got \"[lindex $item 0]\"" } } } ad_proc util::json::object::get_value { -object:required -attribute:required } { Returns the value of an attribute in an object. If the attribute doesn't exist, an error will result. @param object The JSON object which contains the attribute. @param attribute The attribute name. @return The attribute value or an error, if the attribute doesn't exist. } { array set values [util::json::object::get_values $object] return $values($attribute) } ad_proc util::json::object::set_value { -object:required -attribute:required -value:required } { Set an attribute value in an object structure. If the attribute doesn't exist in the object, it's created. @param object The object we want to set the value in. @param attribute The name of the attribute. @param value The value to set attribute to. @return A new object with the attribute/value pair. } { array set values [util::json::object::get_values $object] set values($attribute) $value return [util::json::object::create [array get values]] } ad_proc util::json::object::set_by_path { -object:required -path:required -value:required } { This is an odd utility that mimics some odd code in the Ilias SCORM module, included here because it might be of more general use. Essentially we walk down an object tree structure using the "path" parameter. If we encounter a leaf on the way, we replace it with a new object node and continue. The last element of the path is interpreted as a leaf of the tree and is set to "value". Example: util::json::gen [util::json::object::set_by_path -object "" -path {a b c} -value 3] Result: {"a":{"b":{"c":3}}} Example: util::json::gen \ [util::json::object::set_by_path \ -object [util::json::object::create \ [list a [util::json::object::create [list d null]]]] \ -path {a b c} \ -value 3] Result: {"a":{"b":{"c":3},"d":null}} "a" is the top level object with two subnodes "b" and "d", with "b" having a subnode "c" of value 3, and "d" being a leaf of "a" with value "null". @param object The object to add subnodes to. @param path The path through the tree with the last value being the name of a new or existing leaf. @param value The value to set the final leaf to. @return A new object with the new tree structure interwoven into it. } { if { [llength $object] < 2 } { array set values "" } else { array set values [util::json::object::get_values $object] } if { [llength $path] == 0 } { return $value } else { if { ![info exists values([lindex $path 0])] } { set values([lindex $path 0]) "" } set values([lindex $path 0]) \ [util::json::object::set_by_path \ -object $values([lindex $path 0]) \ -path [lrange $path 1 end] \ -value $value] return [util::json::object::create [array get values]] } } ad_proc util::json::indent { -simplify:boolean json } { Indent a JSON string to make it more easily digestable by the human mind. This works best (by far) if the JSON string doesn't already contain newlines (as will be true of JSON strings generated by util::json::gen). @param simplify If true, remove all fields that don't contribute to the structure of the object/array combination being described by the string. @param json The string to indent @return The beautifully indented, and optionally simplified, string } { set indent -1 set output "" set json [string map {, ,\n :\{ :\n\{ :\[ :\[\n} $json] foreach jsonette [split $json \n] { if { $simplify_p && ![regexp {[\{\[\}\]]} $jsonette] } { continue } set incr_indent [regexp "^\{" $jsonette] incr indent $incr_indent lappend output \ [string repeat " " $indent][expr { $incr_indent ? "" : " " }]${jsonette} incr indent \ [expr {[regexp -all "\{" $jsonette]-$incr_indent-[regexp -all "\}" $jsonette]}] } return [join $output \n] } openacs-5.7.0/packages/acs-tcl/tcl/user-extensions-procs.tcl0000644000175000017500000000424410551254404023670 0ustar frankiefrankie ad_library { Procs to manage extensions to user data. This calls the UserData service contract for allowing packages to be notified of changes in user information. @author ben@openforce.net @creation-date 2002-01-22 @cvs-id $Id: user-extensions-procs.tcl,v 1.5 2007/01/10 21:22:12 gustafn Exp $ } namespace eval acs_user_extension { ad_proc -private dispatch { {-op:required} {-list_of_args:required} {-impl ""} } { Dispatches (calls the service contract routines) the requested method so that the operation gets executed, and packages are notified of changes in user information. } { if {$impl eq ""} { set extensions [list_extensions] } else { set extensions [list $impl] } # Loop through the extensions foreach extension $extensions { acs_sc_call UserData $op $list_of_args $extension } } ad_proc -public list_extensions {} { List the extensions (User Data contract) } { return [db_list select_extensions {}] } ad_proc -public user_new { {-user_id:required} } { Notifies packages when a new user is added to the system. @see dispatch } { dispatch -op UserNew -list_of_args [list $user_id] } ad_proc -public user_approve { {-user_id:required} } { Notifies packages when a user is approved. @see dispatch } { dispatch -op UserApprove -list_of_args [list $user_id] } ad_proc -public user_deapprove { {-user_id:required} } { Notifies packages when a user is deapproved. @see dispatch } { dispatch -op UserDeapprove -list_of_args [list $user_id] } ad_proc -public user_modify { {-user_id:required} } { Notifies packages when a user is modified. @see dispatch } { dispatch -op UserModify -list_of_args [list $user_id] } ad_proc -public user_delete { {-user_id:required} } { Notifies packages when a user is deleted. @see dispatch } { dispatch -op UserDelete -list_of_args [list $user_id] } } openacs-5.7.0/packages/acs-tcl/tcl/user-extensions-procs.xql0000644000175000017500000000070207611533245023713 0ustar frankiefrankie select impl_name from acs_sc_impls, acs_sc_bindings, acs_sc_contracts where acs_sc_impls.impl_id = acs_sc_bindings.impl_id and acs_sc_contracts.contract_id = acs_sc_bindings.contract_id and acs_sc_contracts.contract_name = 'UserData' openacs-5.7.0/packages/acs-tcl/tcl/apm-procs.tcl0000644000175000017500000017455011475206717021314 0ustar frankiefrankiead_library { Routines used by the package manager. @creation-date 13 Apr 2000 @author Bryan Quinn (bquinn@arsdigita.com) @author Jon Salz (jsalz@arsdigita.com) @cvs-id $Id: apm-procs.tcl,v 1.89 2010/11/30 14:44:31 jeffd Exp $ } namespace eval apm {} ##### # Globals used by the package manager: # # apm_current_package_key # Identifies which package is currently being loaded. # # # # NSV arrays used by the package_manager: (note that all paths are relative # to [acs_path_root] unless otherwise indicated) # # apm_version_properties($info_file_path) # # Contains a list [list $mtime $properties_array], where $properties_array # is a cached copy of the version properties array last returned by # [apm_read_package_info_file $info_file_path], and $mtime is the # modification time of the $info_file_path when it was last examined. # # This is a cache for apm_read_package_info_file. # # apm_library_mtime($path) # # The modification time of $file (a *-procs.tcl, *-init.tcl or .xql file) # when it was last loaded. # # apm_version_procs_loaded_p($version_id) # apm_version_init_loaded_p($version_id) # # 1 if the *-procs.tcl and *-init.tcl files (respectively) have been # loaded for package version $version_id. # # apm_vc_status($path) # # A cached result from apm_fetch_cached_vc_status (of the form # [list $mtime $path]) containing the last-known CVS status of # $path. # # apm_properties(reload_level) # # The current "reload level" for the server. # # apm_reload($reload_level) # # A list of files which need to be loaded to bring the current interpreter # up to reload level $reload_level from level $reload_level - 1. # # apm_reload_watch($path) # # Indicates that $path is a -procs.tcl file which should be examined # every time apm_load_any_changed_libraries is invoked, to see whether # it has changed since last loaded. The path starts at acs_root_dir. # # RELOADING VOODOO # # To allow for automatically reloading of Tcl libraries, we introduce the # concept of a server-wide "reload level" (starting at zero) stored in # the apm_properties(reload_level) NSV array entry. Whenever we determine # we want to have all interpreters source a particular -procs.tcl file, # we: # # 1) Increment apm_properties(reload_level), as a signal to each # interpreter that it needs to source some new -procs.tcl files # to bring itself up to date. # 2) Set apm_reload($reload_level), where $reload_level is the new # value of apm_properties(reload_level) set in step #1, to the # list of files which actually need to be sourced. # # Each interpreter maintains its private, interpreter-specific reload level # as a proc named apm_reload_level_in_this_interpreter. Every time the # request processor sees a request, it invokes # apm_load_any_changed_libraries, which compares the server-wide # reload level to the interpreter-private one. If it notes a difference, # it reloads the set of files necessary to bring itself up-to-date (i.e., # files noted in the applicable entries of apm_reload). # # Example: # # - The server is started. apm_properties(reload_level) is 0. # - I modify /packages/acs-tcl/utilities-procs.tcl. # - Through the package manager GUI, I invoke # apm_mark_version_for_reload. It notices that utilities-procs.tcl # has changed. It increments apm_properties(reload_level) to 1, # and sets apm_reload(1) to [list "packages/acs-tcl/utilities-procs.tcl"]. # - A request is handled in some other interpreter, whose reload # level (as returned by apm_reload_level_in_this_interpreter) # is 0. apm_load_any_changed_libraries notes that # [apm_reload_level_in_this_interpreter] != [nsv_get apm_properties reload_level], # so it sources the files listed in apm_reload(1) (i.e., utilities-procs.tcl) # and redefines apm_reload_level_in_this_interpreter to return 1. # ##### ### Callback functions are used to control the logging that occurs during ### the execution of any apm_package that uses the -callback argument. ad_proc -public apm_dummy_callback { string } { A dummy callback routine which does nothing. } { # Do nothing! } ad_proc -public apm_ns_write_callback { string } { A simple callback which prints out the log message to the server stream. } { ns_write $string } ad_proc -public apm_doc_body_callback { string } { This callback uses the document api to append more text to the stream. } { doc_body_append $string } ad_proc apm_callback_and_log { { -severity Notice } callback message } { Executes the $callback callback routine with $message as an argument, and calls ns_log with the given $severity. } { $callback $message ns_log $severity $message } ad_proc apm_one_package_descendents { package_key } { Returns a list of package keys of all packages that inherit from the given package } { global apm_visited_package_keys global apm_package_descendents foreach descendent [db_list get_descendents {}] { if { [info exists apm_visited_package_keys($descendent)] } { continue } set apm_visited_package_keys($descendent) 1 lappend apm_package_descendents $descendent apm_one_package_descendents $descendent } } ad_proc apm_build_subsite_packages_list {} { Build the nsv_set cache of all packages which claim to implement subsite semantics. The kludge to add acs-subsite if it's not declared with the subsite attribute set true is needed during the upgrade process ... } { nsv_set apm_subsite_packages_list package_keys {} # Make sure old versions work ... catch { nsv_set apm_subsite_packages_list package_keys [db_list get_subsites {}] } if { [lsearch -exact [nsv_get apm_subsite_packages_list package_keys] acs-subsite] == -1 } { nsv_lappend apm_subsite_packages_list package_keys acs-subsite } } ad_proc apm_package_list_url_resolution { package_list } { Use a left-right, breadth-first traverse of the inheritance DAG to build a structure to be used by the request processor to resolve URLs based on a package's "extends" and "embeds" dependencies. } { global apm_visited_package_keys global apm_package_url_resolution foreach package $package_list { foreach {package_key dependency_type} $package {} if { [info exists apm_visited_package_keys($package_key)] } { continue } switch $dependency_type { extends - "" { lappend apm_package_url_resolution [acs_root_dir]/packages/$package_key/www } embeds { # Reference to an embedded package is through URLs relative to the embedding # package's mount point, taking one of the forms package-key, # admin/package-key and sitewide-admin/package-key. These map to package-key/embed, # package-key/embed/admin, and package-key/embed/sitewide-admin respectively. # We break references like package-key/admin because such references are unsafe, # as the request processor will not perform the expected permission check. lappend apm_package_url_resolution \ [list [acs_root_dir]/packages/$package_key/embed/admin admin/$package_key] lappend apm_package_url_resolution \ [list "" $package_key/admin] lappend apm_package_url_resolution \ [list [acs_root_dir]/packages/$package_key/embed/sitewide-admin \ sitewide-admin/$package_key] lappend apm_package_url_resolution \ [list "" $package_key/sitewide-admin] lappend apm_package_url_resolution \ [list [acs_root_dir]/packages/$package_key/embed $package_key] } default { error "apm_package_list_url_resolution: dependency type is $dependency_type" } } set apm_visited_package_keys($package_key) 1 } # Make sure old versions work ... foreach package $package_list { foreach {package_key dependency_type} $package {} set inherit_templates_p t #fix! catch { db_1row get_inherit_templates_p {} } apm_package_list_url_resolution [db_list_of_lists get_dependencies {}] } } ad_proc apm_one_package_inherit_order { package_key } { Returns a list of package keys in package inheritance order. } { global apm_visited_package_keys global apm_package_inherit_order if { [info exists apm_visited_package_keys($package_key)] } { return } set apm_visited_package_keys($package_key) 1 foreach dependency [db_list get_dependencies {}] { apm_one_package_inherit_order $dependency } lappend apm_package_inherit_order $package_key } ad_proc apm_one_package_load_libraries_dependencies { package_key } { Generate a list of package keys in library load dependency order. } { global apm_visited_package_keys global apm_package_load_libraries_order if { [info exists apm_visited_package_keys($package_key)] } { return } set apm_visited_package_keys($package_key) 1 set package_key_list "" foreach dependency [db_list get_dependencies {}] { apm_one_package_load_libraries_dependencies $dependency } lappend apm_package_load_libraries_order $package_key } ad_proc apm_build_one_package_relationships { package_key } { Builds the nsv dependency structures for a single package. } { global apm_visited_package_keys global apm_package_url_resolution global apm_package_inherit_order global apm_package_load_libraries_order global apm_package_descendents array unset apm_visited_package_keys set apm_package_url_resolution [list] apm_package_list_url_resolution $package_key nsv_set apm_package_url_resolution $package_key $apm_package_url_resolution array unset apm_visited_package_keys set apm_package_inherit_order [list] apm_one_package_inherit_order $package_key nsv_set apm_package_inherit_order $package_key $apm_package_inherit_order array unset apm_visited_package_keys set apm_package_load_libraries_order [list] apm_one_package_load_libraries_dependencies $package_key nsv_set apm_package_load_libraries_order $package_key $apm_package_load_libraries_order array unset apm_visited_package_keys set apm_package_descendents [list] apm_one_package_descendents $package_key nsv_set apm_package_descendents $package_key $apm_package_descendents } ad_proc apm_build_package_relationships {} { Builds the nsv dependency and ancestor structures. } { foreach package_key [apm_enabled_packages] { apm_build_one_package_relationships $package_key } } ad_proc apm_package_descendents { package_key } { Wrapper that returns the cached package descendents list. } { return [nsv_get apm_package_descendents $package_key] } ad_proc apm_package_inherit_order { package_key } { Wrapper that returns the cached package inheritance order list. } { return [nsv_get apm_package_inherit_order $package_key] } ad_proc apm_package_url_resolution { package_key } { Wrapper that returns the cached package search order list. } { return [nsv_get apm_package_url_resolution $package_key] } ad_proc apm_package_load_libraries_order { package_key } { Wrapper that returns the cached package library load order list. } { return [nsv_get apm_package_load_libraries_order $package_key] } ad_proc -public apm_version_loaded_p { version_id } { Returns 1 if a version of a package has been loaded and initialized, or 0 otherwise. } { return [nsv_exists apm_version_init_loaded_p $version_id] } ad_proc -private apm_mark_files_for_reload { {-force_reload:boolean} file_list } { Mark the given list of Tcl and query files for reload in all interpreters. Only marks files for reload if they haven't been loaded before or they have changed since last reload. @param file_list A list of paths relative to acs_root_dir @param force_reload Mark the files for reload even if their modification time in the nsv cache doesn't differ from the one in the filesystem. @return The list of files marked for reload. @author Peter Marklund } { set changed_files [list] foreach relative_path $file_list { set full_path "[acs_root_dir]/$relative_path" # If the file exists, and either has never been loaded or has an mtime # which differs the mtime it had when last loaded, mark to be loaded. if { [file isfile $full_path] } { set mtime [file mtime $full_path] if { $force_reload_p || (![nsv_exists apm_library_mtime $relative_path] || \ [nsv_get apm_library_mtime $relative_path] != $mtime) } { lappend changed_files $relative_path } } } if { [llength $changed_files] > 0 } { set reload [nsv_incr apm_properties reload_level] nsv_set apm_reload $reload $changed_files } return $changed_files } ad_proc -private apm_mark_version_for_reload { version_id { changed_files_var "" } } { Examines all tcl_procs files in package version $version_id; if any have changed since they were loaded, marks (in the apm_reload array) that they must be reloaded by each Tcl interpreter (using the apm_load_any_changed_libraries procedure).

    Saves a list of files that have changed (and thus marked to be reloaded) in the variable named $file_info_var, if provided. Each element of this list is of the form:

    [list $file_id $path]
    } { if { $changed_files_var ne "" } { upvar $changed_files_var changed_files } set package_key [apm_package_key_from_version_id $version_id] set changed_files [list] set file_types [list tcl_procs query_file] if { [apm_load_tests_p] } { lappend file_types test_procs } foreach path [apm_get_package_files -package_key $package_key -file_types $file_types] { set full_path "[acs_package_root_dir $package_key]/$path" set relative_path "packages/$package_key/$path" set reload_file [apm_mark_files_for_reload $relative_path] if { [llength $reload_file] > 0 } { # The file marked for reload lappend changed_files $relative_path } } } ad_proc -private apm_version_load_status { version_id } { If a version needs to be reloaded (i.e., a -procs.tcl has changed or been added since the version was loaded), returns "needs_reload". If the version has never been loaded, returns "never_loaded". If the version is up-to-date, returns "up_to_date". } { # See if the version was ever loaded. if { ![apm_package_version_enabled_p $version_id] } { return "never_loaded" } set package_key [apm_package_key_from_version_id $version_id] set procs_types [list tcl_procs] if { [apm_load_tests_p] } { lappend procs_types test_procs } foreach file [apm_get_package_files -package_key $package_key -file_types $procs_types] { # If $file has never been loaded, i.e., it has been added to the version # since the version was initially loaded, return needs_reload. if { ![nsv_exists apm_library_mtime "packages/$package_key/$file"] } { return "needs_reload" } set full_path "[acs_package_root_dir $package_key]/$file" # If $file had a different mtime when it was last loaded, return # needs_reload. (If the file should exist but doesn't, just skip it.) if { [file exists $full_path] && [file mtime $full_path] != [nsv_get apm_library_mtime "packages/$package_key/$file"] } { return "needs_reload" } } foreach file [apm_get_package_files -package_key $package_key -file_types "query_file"] { # If $file has never been loaded, i.e., it has been added to the version # since the version was initially loaded, return needs_reload. if { ![nsv_exists apm_library_mtime "packages/$package_key/$file"] } { return "needs_reload" } set full_path "[acs_package_root_dir $package_key]/$file" # If $file had a different mtime when it was last loaded, return # needs_reload. (If the file should exist but doesn't, just skip it.) if { [file exists $full_path] && [file mtime $full_path] != [nsv_get apm_library_mtime "packages/$package_key/$file"] } { return "needs_reload" } } return "up_to_date" } ad_proc -private apm_load_libraries { {-force_reload:boolean 0} {-packages {}} {-callback apm_dummy_callback} {-procs:boolean} {-init:boolean} {-test_procs:boolean} {-test_init:boolean} } { Loads all -procs.tcl (if $procs_or_init is "procs") or -init.tcl files into the current interpreter for installed, enabled packages. Only loads files which have not yet been loaded. This is intended to be called only during server initialization (since it loads libraries only into the running interpreter, as opposed to in *all* active interpreters). } { set file_types [list] if { $procs_p } { lappend file_types tcl_procs } if { $init_p } { lappend file_types tcl_init } if { $test_procs_p } { lappend file_types test_procs } if { $test_init_p } { lappend file_types test_init } if { $packages eq "" } { set packages [apm_enabled_packages] } # Scan the package directory for files to source. set files [list] foreach package $packages { set paths [apm_get_package_files -package_key $package -file_types $file_types] foreach path [lsort $paths] { lappend files [list $package $path] } } # Release all outstanding database handles (since the file we're sourcing # might be using the ns_db database API as opposed to the new db_* API). db_release_unused_handles apm_files_load -force_reload=$force_reload_p -callback $callback $files } ad_proc -public apm_load_tests_p {} { Determine whether to load acs-automated-testing tests for packages. @return 1 if tests should be loaded and 0 otherwise @author Peter Marklund } { return [apm_package_enabled_p "acs-automated-testing"] } ad_proc -public apm_load_packages { {-force_reload:boolean 0} {-load_libraries_p 1} {-load_queries_p 1} {-packages {}} } { Load Tcl libraries and queries for the packages with given keys. Only loads procs into the current interpreter. Will load Tcl tests if the acs-automated-testing package is enabled. @param force_reload Reload Tcl libraries even if they are already loaded. @param load_libraries Switch to indicate if Tcl libraries in (-procs.tcl and -init.tcl) files should be loaded. Defaults to true. @param load_queries Switch to indicate if xql query files should be loaded. Default true. @param packages A list of package_keys for packages to be loaded. Defaults to all enabled packages. These packages, along with the packages they depend on, will be loaded in dependency-order using the information provided in the packages' "provides" and "requires" attributes. @see apm_mark_version_for_reload @author Peter Marklund } { if { $packages eq "" } { set packages [apm_enabled_packages] } set packages_to_load [list] foreach package_key $packages { foreach package_to_load [apm_package_load_libraries_order $package_key] { if { [lsearch -exact $packages_to_load $package_to_load] == -1 } { lappend packages_to_load $package_to_load } } } # Should acs-automated-testing tests be loaded? set load_tests_p [apm_load_tests_p] # Load *-procs.tcl files if { $load_libraries_p } { apm_load_libraries -force_reload=$force_reload_p -packages $packages_to_load -procs } # Load up the Queries (OpenACS, ben@mit.edu) if { $load_queries_p } { apm_load_queries -packages $packages_to_load } # Load up the Automated Tests and associated Queries if necessary if {$load_tests_p} { apm_load_libraries -force_reload=$force_reload_p -packages $packages -test_procs apm_load_queries -packages $packages_to_load -test_queries } if { $load_libraries_p } { # branimir: acs-lang needs to be initialized before anything else # because there are packages whose *-init.tcl files depend on it. apm_load_libraries -force_reload=$force_reload_p -init -packages acs-lang apm_load_libraries -force_reload=$force_reload_p -init -packages $packages_to_load } # Load up the Automated Tests initialisation scripts if necessary if {$load_tests_p} { apm_load_libraries -force_reload=$force_reload_p -packages $packages_to_load -test_init } } ad_proc -private apm_load_queries { {-packages {}} {-callback apm_dummy_callback} {-test_queries:boolean} } { Load up the queries for all enabled packages (or all specified packages). Follows the pattern of the load_libraries proc, but only loads query information @param packages Optional list of keys for packages to load queries for. @author ben@mit.edu } { if { $packages eq "" } { set packages [apm_enabled_packages] } # Scan the package directory for files to source. set files [list] foreach package $packages { set files [ad_find_all_files [acs_root_dir]/packages/$package] if { [llength $files] == 0 } { ns_log Error "apm_load_queries: Unable to locate [acs_root_dir]/packages/$package/*. when scanning for SQL queries to load." } set testdir "[acs_root_dir]/packages/$package/tcl/test" set testlength [string length $testdir] foreach file [lsort $files] { set file_db_type [apm_guess_db_type $package $file] set file_type [apm_guess_file_type $package $file] if {![string compare -length $testlength $testdir $file]} { set is_test_file_p 1 } else { set is_test_file_p 0 } # # Note this exclusive or represents the following: # test_queries_p - Load normal xql files or load test xql files # is_test_file_p - Current file is a test file or not. # # !(test_queries_p ^ is_test_file_p) = Load it or not? # !( 0 ^ 0 ) = Yep # !( 0 ^ 1 ) = Nope # !( 1 ^ 0 ) = Nope # !( 1 ^ 1 ) = Yep # if {![expr {$test_queries_p ^ $is_test_file_p}] && $file_type eq "query_file" && ($file_db_type eq "" || $file_db_type eq [db_type])} { db_qd_load_query_file $file } } } ns_log debug "apm_load_queries: DONE looping through files from which to load queries" } ad_proc -private apm_subdirs { path } { Returns a list of subdirectories of path (including path itself) } { set dirs [list] lappend dirs $path foreach subdir [glob -nocomplain -type d [file join $path *]] { set dirs [concat $dirs [apm_subdirs $subdir]] } return $dirs } ad_proc -private apm_pretty_name_for_file_type { type } { Returns the pretty name corresponding to a particular file type key @see apm_file_type_names @see apm_file_type_keys @author Peter Marklund } { array set file_type_names [apm_file_type_names] return $file_type_names($type) } ad_proc -private apm_pretty_name_for_db_type { db_type } { Returns the pretty name corresponding to a particular file type key (memoizing to save a database hit here and there). } { return [util_memoize [list db_string pretty_db_name_select " select pretty_db_name from apm_package_db_types where db_type_key = :db_type " -default "all" -bind [list db_type $db_type]]] } ad_proc -public apm_load_any_changed_libraries {} { In the running interpreter, reloads files marked for reload by apm_mark_version_for_reload. If any watches are set, examines watched files to see whether they need to be reloaded as well. This is intended to be called only by the request processor (since it should be invoked before any filters or registered procedures are applied). } { # Determine the current reload level in this interpreter by calling # apm_reload_level_in_this_interpreter. If this fails, we define the reload level to be # zero. if { [catch { set reload_level [apm_reload_level_in_this_interpreter] } error] } { proc apm_reload_level_in_this_interpreter {} { return 0 } set reload_level 0 } # Check watched files, adding them to files_to_reload if they have # changed. set files_to_reload [list] foreach file [nsv_array names apm_reload_watch] { set path "[acs_root_dir]/$file" ns_log Debug "APM: File being watched: $path" if { [file exists $path] && \ (![nsv_exists apm_library_mtime $file] || \ [file mtime $path] != [nsv_get apm_library_mtime $file]) } { lappend files_to_reload $file } } # If there are any changed watched files, stick another entry on the # reload queue. if { [llength $files_to_reload] > 0 } { ns_log Notice "apm_load_any_changed_libraries: Watched file[ad_decode [llength $files_to_reload] 1 "" "s"] [join $files_to_reload ", "] [ad_decode [llength $files_to_reload] 1 "has" "have"] changed: reloading." set new_level [nsv_incr apm_properties reload_level] nsv_set apm_reload $new_level $files_to_reload } set changed_reload_level_p 0 # Keep track of which files we've reloaded in this loop so we never # reload the same one twice. array set reloaded_files [list] while { $reload_level < [nsv_get apm_properties reload_level] } { incr reload_level set changed_reload_level_p 1 # If there's no entry in apm_reload for that reload level, back out. if { ![nsv_exists apm_reload $reload_level] } { incr reload_level -1 break } foreach file [nsv_get apm_reload $reload_level] { # If we haven't yet reloaded the file in this loop, source it. if { ![info exists reloaded_files($file)] } { if { [array size reloaded_files] == 0 } { # Perform this ns_log only during the first iteration of this loop. ns_log Notice "apm_load_any_changed_libraries: Reloading *-procs.tcl files in this interpreter..." } # File is usually of form packages/package_key set file_path "[acs_root_dir]/$file" set file_ext [file extension $file_path] switch $file_ext { .tcl { # Make sure this is not a -init.tcl file as those should only be sourced on server startup if { ![regexp {\-init\.tcl$} $file_path] } { ns_log Notice "apm_load_any_changed_libraries: Reloading $file..." apm_source $file_path } } .xql { ns_log Notice "apm_load_any_changed_libraries: Reloading $file..." db_qd_load_query_file $file_path } default { ns_log Notice "apm_load_any_changed_libraries: File $file_path has unknown extension. Not reloading." } } set reloaded_files($file) 1 } } } # We changed the reload level in this interpreter, so redefine the # apm_reload_level_in_this_interpreter proc. if { $changed_reload_level_p } { proc apm_reload_level_in_this_interpreter {} "return $reload_level" } } ad_proc -private apm_package_version_release_tag { package_key version_name } { Returns a CVS release tag for a particular package key and version name. 2} { regsub -all {\.} [string toupper "$package_key-$version_name"] "-" release_tag return $release_tag } ad_proc -public apm_package_parameters {package_key} { @return A list of all the package parameter names. } { return [db_list get_names { select parameter_name from apm_parameters where package_key = :package_key }] } ad_proc -public apm_package_supported_databases { package_key } { Return a list of db types (i.e. oracle, postgresql) supported by the package with given key. @author Peter Marklund @see db_known_database_types @see apm_package_supoorts_rdbms_p } { set supported_databases_list [list] foreach db_type_info [db_known_database_types] { set db_type [lindex $db_type_info 0] if { [apm_package_supports_rdbms_p -package_key $package_key] } { lappend supported_databases_list $db_type } } return $supported_databases_list } ad_proc -public apm_package_registered_p { package_key } { Returns 1 if there is a registered package with the indicated package_key. Returns 0 otherwise. } { ### Query the database for the indicated package_key return [db_string apm_package_registered_p { select 1 from apm_package_types where package_key = :package_key } -default 0] } ad_proc -public apm_package_installed_p { package_key } { Returns 1 if there is an installed package version corresponding to the package_key, 0 otherwise. Uses a cached value for performance. } { if { [util_memoize_initialized_p] } { return [util_memoize [list apm_package_installed_p_not_cached $package_key]] } else { return [apm_package_installed_p_not_cached $package_key] } } ad_proc -private apm_package_installed_p_not_cached { package_key } { return [db_string apm_package_installed_p {} -default 0] } ad_proc -public apm_package_enabled_p { package_key } { Returns 1 if there is an enabled package version corresponding to the package_key and 0 otherwise. } { return [db_string apm_package_enabled_p {} -default 0] } ad_proc -public apm_enabled_packages {} { Returns a list of package_key's for all enabled packages. @author Peter Marklund } { return [db_list enabled_packages {}] } ad_proc -public apm_version_installed_p { version_id } { @return Returns 1 if the specified version_id is installed, 0 otherwise. } { return [db_string apm_version_installed_p {} -default 0] } ad_proc -public apm_highest_version {package_key} { Return the highest version of the indicated package. @return the version_id of the highest installed version of a package. } { return [db_exec_plsql apm_highest_version { begin :1 := apm_package.highest_version ( package_key => :package_key ); end; }] } ad_proc -public apm_highest_version_name {package_key} { Return the highest version of the indicated package. @return the version_name of the highest installed version of a package. } { return [db_string apm_highest_version_name {} -default ""] } ad_proc -public apm_num_instances {package_key} { @return The number of instances of the indicated package. } { return [db_exec_plsql apm_num_instances { begin :1 := apm_package.num_instances( package_key => :package_key ); end; }] } ad_proc -public apm_parameter_update { { -callback apm_dummy_callback } parameter_id package_key parameter_name description default_value datatype \ {section_name ""} {min_n_values 1} {max_n_values 1} } { @return The parameter id that has been updated. } { if {$section_name eq ""} { set section_name [db_null] } db_dml parameter_update { update apm_parameters set parameter_name = :parameter_name, default_value = :default_value, datatype = :datatype, description = :description, section_name = :section_name, min_n_values = :min_n_values, max_n_values = :max_n_values where parameter_id = :parameter_id } db_dml object_title_update { update acs_objects set title = :parameter_name where object_id = :parameter_id } return $parameter_id } ad_proc -public apm_parameter_register { { -callback apm_dummy_callback -parameter_id "" -scope instance } parameter_name description package_key default_value datatype {section_name ""} {min_n_values 1} {max_n_values 1} } { Register a parameter in the system. The new "scope" parameter is named rather than positional to avoid breaking existing code. @return The parameter id of the new parameter. } { if {$parameter_id eq ""} { set parameter_id [db_null] } if {$section_name eq ""} { set section_name [db_null] } ns_log debug "apm_parameter_register: Registering $parameter_name, $section_name, $default_value" set parameter_id [db_exec_plsql parameter_register {}] # Propagate to descendents if it's an instance parameter. if { $scope eq "instance" } { apm_copy_param_to_descendents $package_key $parameter_name } # Update the cache. db_foreach apm_parameter_cache_update { } { ad_parameter_cache -set $attr_value $package_id $parameter_name } return $parameter_id } ad_proc -public apm_parameter_unregister { {-callback apm_dummy_callback} {-package_key ""} {-parameter ""} parameter_id } { Unregisters a parameter from the system. } { if { $parameter_id eq "" } { set parameter_id [db_string select_parameter_id {}] } db_1row get_scope_and_name {} ns_log Debug "apm_parameter_unregister: Unregistering parameter $parameter_id." if { $scope eq "global" } { ad_parameter_cache -delete $package_key $parameter_name } else { db_foreach all_parameters_packages {} { ad_parameter_cache -delete $package_id $parameter_name } } db_exec_plsql unregister {} } ad_proc -public apm_dependency_add { { -callback apm_dummy_callback -dependency_id "" } dependency_type version_id dependency_uri dependency_version } { Add a dependency to a version. @return The id of the new dependency. } { if {$dependency_id eq ""} { set dependency_id [db_null] } return [db_exec_plsql dependency_add {}] } ad_proc -public apm_dependency_remove {dependency_id} { Removes a dependency from the system. } { db_exec_plsql dependency_remove { begin apm_package_version.remove_dependency( dependency_id => :dependency_id ); end; } } ad_proc -public apm_interface_add { { -callback apm_dummy_callback -interface_id "" } version_id interface_uri interface_version } { Add a interface to a version. @return The id of the new interface. } { if {$interface_id eq ""} { set interface_id [db_null] } return [db_exec_plsql interface_add { begin :1 := apm_package_version.add_interface( interface_id => :interface_id, version_id => :version_id, interface_uri => :interface_uri, interface_version => :interface_version ); end; }] } ad_proc -public apm_interface_remove {interface_id} { Removes a interface from the system. } { db_exec_plsql interface_remove { begin apm_package_version.remove_interface( interface_id => :interface_id ); end; } } ad_proc -public apm_version_get { {-version_id ""} {-package_key ""} {-array:required} } { Gets information about a package version. TODO: Cache this proc, put it in a namespace and make sure it's used everywhere. @param version_id The id of the package version to get info for @param package_key Can be specified instead of version_id in which case the live version of the package will be used. @param array The name of the array variable to upvar the info to @author Peter Marklund } { upvar $array row if { $package_key ne "" } { set version_id [apm_version_id_from_package_key $package_key] } db_1row select_version_info {} -column_array row } # # package_id -> package_key # ad_proc -public apm_package_key_from_id {package_id} { @return The package key of the instance. } { return [util_memoize "apm_package_key_from_id_mem $package_id"] } ad_proc -private apm_package_key_from_id_mem {package_id} { unmemoized version of apm_package_key_from_id } { return [db_string apm_package_key_from_id { select package_key from apm_packages where package_id = :package_id } -default ""] } # # package_id -> instance_name # ad_proc -public apm_instance_name_from_id {package_id} { @return The name of the instance. } { return [util_memoize "apm_instance_name_from_id_mem $package_id"] } ad_proc -private apm_instance_name_from_id_mem {package_id} { unmemoized version of apm_instance_name_from_id } { return [db_string apm_package_instance_name_from_id { select instance_name from apm_packages where package_id = :package_id } -default ""] } # # package_key -> package_id # ad_proc -public apm_package_id_from_key {package_key} { @return The package id of the instance of the package. 0 if no instance exists, error if several instances exist. } { return [util_memoize "apm_package_id_from_key_mem $package_key"] } ad_proc -private apm_package_id_from_key_mem {package_key} { unmemoized version of apm_package_id_from_key } { return [db_string apm_package_id_from_key { select package_id from apm_packages where package_key = :package_key } -default 0] } ad_proc -public apm_package_ids_from_key { -package_key:required -mounted:boolean } { @param package_key The package key we are looking for the package @param mounted Does the package have to be mounted? @return List of package ids of all instances of the package. Empty string } { return [util_memoize [list apm_package_ids_from_key_mem -package_key $package_key -mounted_p $mounted_p]] } ad_proc -private apm_package_ids_from_key_mem { -package_key:required {-mounted_p "0"} } { unmemoized version of apm_package_ids_from_key } { if {$mounted_p} { set package_ids [list] db_foreach apm_package_ids_from_key { select package_id from apm_packages where package_key = :package_key } { if {"" ne [site_node::get_node_id_from_object_id -object_id $package_id] } { lappend package_ids $package_id } } return $package_ids } else { return [db_list apm_package_ids_from_key { select package_id from apm_packages where package_key = :package_key }] } } # # package_id -> package_url # ad_proc -public apm_package_url_from_id {package_id} { Will return the first url found for a given package_id @return The package url of the instance of the package. } { return [util_memoize [list apm_package_url_from_id_mem $package_id]] } ad_proc -private apm_package_url_from_id_mem {package_id} { return [db_string apm_package_url_from_id {*SQL*} -default {}] } # # package_key -> package_url # ad_proc -public apm_package_url_from_key {package_key} { @return The package url of the instance of the package. only valid for singleton packages. } { return [util_memoize "apm_package_url_from_key_mem $package_key"] } ad_proc -private apm_package_url_from_key_mem {package_key} { set package_id [apm_package_id_from_key $package_key] return [apm_package_url_from_id $package_id] } # # package_key -> version_id # ad_proc -public apm_version_id_from_package_key { package_key } { Return the id of the enabled version of the given package_key. If no such version id can be found, returns the empty string. @author Peter Marklund } { return [db_string get_id {} -default ""] } # # version_id -> package_key # ad_proc -public apm_package_key_from_version_id {version_id} { Returns the package_key for the given APM package version id. Goes to the database the first time called and then uses a cached value. Calls the proc apm_package_key_from_version_id_mem. @author Peter Marklund (peter@collaboraid.biz) } { return [util_memoize "apm_package_key_from_version_id_mem $version_id"] } ad_proc -private apm_package_key_from_version_id_mem {version_id} { Returns the package_key for the given APM package version id. Goes to the database everytime called. @author Peter Marklund (peter@collaboraid.biz) } { return [db_string apm_package_id_from_key { select package_key from apm_package_version_info where version_id = :version_id } -default 0] } ad_proc -public apm_version_info {version_id} { Sets a set of common package information in the caller's environment. } { uplevel 1 { db_1row apm_package_by_version_id { select pretty_name, version_name, package_key, installed_p, distribution_uri, tagged_p from apm_package_version_info where version_id = :version_id } } } ad_proc -public apm_package_version_installed_p {package_key version_name} { @return 1 if the indiciated package version is installed, 0 otherwise. } { return [db_string apm_package_version_installed_p {}] } ad_proc -public apm_package_version_enabled_p {version_id} { @return 1 if the indiciated package version is installed, 0 otherwise. } { return [db_string apm_package_version_enabled_p {}] } ad_proc -private apm_post_instantiation_tcl_proc_from_key { package_key } { Generates the name of the TCL procedure we execute for post-instantiation. @author Michael Bryzek (mbryzek@arsdigita.com) @creation-date 2001-03-05 @return The name of a tcl procedure, if it exists, or empty string if no such tcl procedure was found. } { set procedure_name [string tolower "[string trim $package_key]_post_instantiation"] # Change all "-" to "_" to mimic our tcl standards regsub -all {\-} $procedure_name "_" procedure_name if { [empty_string_p [info procs ::$procedure_name]] } { # No such procedure exists... return "" } # Procedure exists return $procedure_name } ad_proc -public apm_package_rename { {-package_id ""} {-instance_name:required} } { Renames a package instance } { if { $package_id eq "" } { set package_id [ad_conn package_id] } db_transaction { db_dml app_rename { update apm_packages set instance_name = :instance_name where package_id = :package_id } db_dml rename_acs_object { update acs_objects set title = :instance_name where object_id = :package_id } } foreach node_id [db_list nodes_to_sync {}] { site_node::update_cache -node_id $node_id } } ad_proc -public apm_set_callback_proc { {-version_id ""} {-package_key ""} {-type:required} proc } { Set the name of an APM Tcl procedure callback for a certain package version. Checks if the callback already exists and updates if it does. If version_id is not supplied the id of the currently enabled version of the package will be used. @see apm_supported_callback_types @author Peter Marklund } { apm_assert_callback_type_supported $type if { $version_id eq "" } { if { $package_key eq "" } { error "apm_set_package_callback_proc: Invoked with both version_id and package_key empty. You must supply either of these" } set version_id [apm_version_id_from_package_key $package_key] } set current_proc [apm_get_callback_proc -type $type -version_id $version_id] if { $current_proc eq "" } { # We are adding db_dml insert_proc {} } else { # We are editing db_dml update_proc {} } } ad_proc -public apm_get_callback_proc { {-type:required} {-package_key ""} {-version_id ""} } { Return Tcl procedure name for the callback of a certain type for the given package. If no callback proc for the given type is present returns the empty string. @see apm_supported_callback_types @author Peter Marklund } { apm_assert_callback_type_supported $type if { $version_id eq "" } { set version_id [apm_version_id_from_package_key $package_key] } return [db_string select_proc {} -default ""] } ad_proc -public apm_remove_callback_proc { {-type:required} {-package_key:required} } { Remove the callback of a certain type for the given package. @author Peter Marklund } { apm_assert_callback_type_supported $type return [db_dml delete_proc {}] } ad_proc -public apm_unused_callback_types { {-version_id:required} } { Get a list enumerating the supported callback types that are not used by the given package version. } { set used_callback_types [db_list used_callback_types { select distinct type from apm_package_callbacks where version_id = :version_id }] set supported_types [apm_supported_callback_types] set unused_types [list] foreach supported_type $supported_types { if { [lsearch -exact $used_callback_types $supported_type] < 0 } { lappend unused_types $supported_type } } return $unused_types } ad_proc -public apm_invoke_callback_proc { {-proc_name {}} {-version_id ""} {-package_key ""} {-arg_list {}} {-type:required} } { Invoke the Tcl callback proc of a given type for a given package version. Any errors during invocation are logged. @param callback_proc if this is provided it is called instead of attempting to look up the proc via the package_key or version_id (needed for before-install callbacks since the db is not populated when those are called). @return 1 if invocation was carried out successfully, 0 if no proc to invoke could be found. Will propagate any error thrown by the callback. @author Peter Marklund } { array set arg_array $arg_list if {$proc_name eq ""} { set proc_name [apm_get_callback_proc \ -version_id $version_id \ -package_key $package_key \ -type $type] } if { $proc_name eq "" } { if {$type eq "after-instantiate"} { # We check for the old proc on format: package_key_post_instantiation package_id if { $package_key eq "" } { set package_key [apm_package_key_from_version_id $version_id] } set proc_name [apm_post_instantiation_tcl_proc_from_key $package_key] if { $proc_name eq "" } { # No callback and no old-style callback proc - no options left return 0 } $proc_name $arg_array(package_id) return 1 } else { # No other callback procs to fall back on return 0 } } # We have a non-empty name of a callback proc to invoke # Form the full command including arguments set command "${proc_name} [apm_callback_format_args -type $type -arg_list $arg_list]" # We are ready for invocation ns_log Notice "apm_invoke_callback_proc: invoking callback $type with command $command" eval $command return 1 } ad_proc -public apm_assert_callback_type_supported { type } { Throw an error if the given callback type is not supported. @author Peter Marklund } { if { ![apm_callback_type_supported_p $type] } { error "The supplied callback type $type is not supported. Supported types are: [apm_supported_callback_types]" } } ad_proc -public apm_callback_type_supported_p { type } { Return 1 if the given type of callback is supported and 0 otherwise. @author Peter Marklund } { return [expr [lsearch -exact [apm_supported_callback_types] $type] >= 0] } ad_proc -public apm_callback_format_args { {-version_id ""} {-package_key ""} {-type:required} {-arg_list {}} } { Return a string on format -arg_name1 arg_value1 -arg_name2 arg_value2 ... for the callback proc of given type. @author Peter Marklund } { array set args_array $arg_list set arg_string "" set provided_arg_names [array names args_array] foreach required_arg_name [apm_arg_names_for_callback_type -type $type] { if { [lsearch -exact $provided_arg_names $required_arg_name] < 0 } { error "required argument $required_arg_name not supplied to callback proc of type $type" } append arg_string " -${required_arg_name} $args_array($required_arg_name)" } return $arg_string } ad_proc -public apm_arg_names_for_callback_type { {-type:required} } { Return the list of required argument names for the given callback type. @author Peter Marklund } { array set arguments { after-instantiate { package_id } before-uninstantiate { package_id } before-unmount { package_id node_id } after-mount { package_id node_id } before-upgrade { from_version_name to_version_name } after-upgrade { from_version_name to_version_name } } if { [info exists arguments($type)] } { return $arguments($type) } else { return {} } } ad_proc -public apm_supported_callback_types {} { Gets the list of package callback types that are supported by the system. Each callback type represents a certain event or time when a Tcl procedure should be invoked, such as after-install @author Peter Marklund } { return { before-install after-install before-upgrade after-upgrade before-uninstall after-instantiate before-uninstantiate after-mount before-unmount } } ad_proc -private apm_callback_has_valid_args { {-type:required} {-proc_name:required} } { Returns 1 if the specified callback proc of a certain type has a valid argument list in its definition and 0 otherwise. Assumes that the callback proc is defined with ad_proc. @author Peter Marklund } { if { [empty_string_p [info procs ::${proc_name}]] } { return 0 } set test_arg_list "" foreach arg_name [apm_arg_names_for_callback_type -type $type] { append test_arg_list " -${arg_name} value" } if { $test_arg_list eq "" } { # The callback proc should take no args return [empty_string_p [info args ::${proc_name}]] } # The callback proc should have required arg switches. Check # that the ad_proc arg parser doesn't throw an error with # test arg list if { [catch { set args $test_arg_list ::${proc_name}__arg_parser } errmsg] } { return 0 } else { return 1 } } ad_proc -public apm_package_instance_new { {-package_key:required} {-instance_name ""} {-package_id ""} {-context_id ""} } { Creates a new instance of a package and calls the post instantiation proc, if any. If the package is a singleton and already exists then this procedure will silently do nothing. @param package_key The package_key of the package to instantiate. @param instance_name The name of the package instance, defaults to the pretty name of the package type. @param package_id The id of the new package. Optional. @param context_id The context_id of the new package. Optional. @return The id of the instantiated package } { if { $instance_name eq "" } { set p_name [apm::package_version::attributes::get_instance_name $package_key] if {$p_name eq ""} { set instance_name [db_string pretty_name_from_key {select pretty_name from apm_enabled_package_versions where package_key = :package_key}] } else { set instance_name "$p_name" } } if { $package_id eq "" } { set package_id [db_null] } set package_id [db_exec_plsql invoke_new {}] apm_parameter_sync $package_key $package_id foreach inherited_package_key [nsv_get apm_package_inherit_order $package_key] { apm_invoke_callback_proc \ -package_key $inherited_package_key \ -type after-instantiate \ -arg_list [list package_id $package_id] } return $package_id } ad_proc apm_parameter_sync {package_key package_id} { Syncs the parameters in the database with the memory cache. This must be called after creating a new package instance. } { # Get all the parameter names and values for this package_id. set names_and_values [db_list_of_lists apm_parameter_names_and_values { select parameter_name, attr_value from apm_parameters p, apm_parameter_values v, apm_packages a where p.parameter_id = v.parameter_id and a.package_id = v.package_id and a.package_id = :package_id }] # Put it in the cache. foreach name_value_pair $names_and_values { ad_parameter_cache -set [lindex $name_value_pair 1] $package_id [lindex $name_value_pair 0] } } ad_proc -public apm_package_instance_delete { package_id } { Deletes an instance of a package } { set package_key [apm_package_key_from_id $package_id] foreach inherited_package_key [nsv_get apm_package_inherit_order $package_key] { apm_invoke_callback_proc \ -package_key $inherited_package_key \ -type before-uninstantiate \ -arg_list [list package_id $package_id] } db_exec_plsql apm_package_instance_delete {} } ad_proc -public apm_get_installed_versions { -array:required } { Sets the current installed version of packages installed on this system in an array keyed by package_key. @param array Name of array in caller's namespace where you want this set } { upvar 1 $array installed_version db_foreach installed_packages { select package_key, version_name from apm_package_versions where enabled_p = 't' } { set installed_version($package_key) $version_name } } ad_proc -public apm_get_installed_provides { -array:required } { Sets the dependencies provided by the packages installed on this system in an array keyed by dependency service-uri. @param array Name of array in caller's namespace where you want this set } { upvar 1 $array installed_provides # All packages provides themselves apm_get_installed_versions -array installed_provides # Now check what the provides clauses say db_foreach installed_provides { select service_uri, service_version from apm_package_dependencies d, apm_package_versions v where d.dependency_type = 'provides' and d.version_id = v.version_id and v.enabled_p = 't' } { if { ![info exists installed_provides($service_uri)] || \ [apm_version_names_compare $installed_provides($service_uri) $service_version] == -1 } { set installed_provides($service_uri) $service_version } } } ## ## Logging ## ad_proc -public apm_log { level msg } { Centralized APM logging. If you want to debug the APM, change APMDebug to Debug and restart the server. } { if {"APMDebug" ne $level } { ns_log $level $msg } } ad_proc -private apm_application_new_checkbox {} { Return an HTML checkbox of package_key and package names for applications that can be mounted in the site-map. Excludes singletons that are already instantiated. @author Peter Marklund } { set html_string "" return $html_string } ad_proc -private apm::read_files {path file_list} { Read the contents from a list of files at a certain path. Return the data to the caller as a big string. } { set data "" foreach file $file_list { if {![catch {set fp [open ${path}/${file} r]} err]} { append data [read $fp] close $fp } } return $data } ad_proc -public apm::metrics { -package_key -file_type -array } { Return some code metrics about the files in package $package_key. This will return an array of 3 items:
    • count - the number of files
    • lines - the number of lines in the files
    • procs - the number of procs, if applicable (0 if not applicable)
    This will be placed in the array variable that is provided to this proc.

    Valid file_type's:

    • data_model_pg - PG datamodel files
    • data_model_ora - Oracle datamodel files
    • include_page - ADP files in package_key/lib
    • content_page - ADP files in package_key/www
    • tcl_procs - TCL procs in package_key/tcl
    • test_procs - automated tests in package_key/tcl/test
    • documentation - docs in package_key/www/doc
    This proc is cached. @author Vinod Kurup @creation-date 2006-02-09 @param package_key The package_key of interest @param file_type See options above @param array variable to hold the array that will be returned } { upvar $array metrics array set metrics [util_memoize [list apm::metrics_internal $package_key $file_type]] } ad_proc -private apm::metrics_internal { package_key file_type } { The cached version of apm::metrics @see apm::metrics } { array set metrics {} set package_path [acs_package_root_dir $package_key] # We'll be using apm_get_package_files to get a list of files # by file type. switch $file_type { data_model_pg - data_model_ora { set file_types [list data_model_create data_model] } default { set file_types $file_type } } set filelist [apm_get_package_files \ -all_db_types \ -package_key $package_key \ -file_types $file_types] # filelist needs to be weeded for certain file types switch $file_type { include_page - content_page { # weed out non-.adp files set adp_files {} foreach file $filelist { if { [string match {*.adp} $file] } { lappend adp_files $file } } set filelist $adp_files } data_model_pg { # ignore drop and upgrade scripts set pg_files {} foreach file $filelist { if { [string match {*/postgresql/*} $file] && ![string match *-drop.sql $file] && ![string match {*/upgrade/*} $file] } { lappend pg_files $file } } set filelist $pg_files } data_model_ora { # ignore drop and upgrade scripts set ora_files {} foreach file $filelist { if { [string match {*/oracle/*} $file] && ![string match *-drop.sql $file] && ![string match {*/upgrade/*} $file] } { lappend ora_files $file } } set filelist $ora_files } } # read the files, so we can count lines and grep for procs set filedata [apm::read_files $package_path $filelist] # The first 2 metrics are easy (file count and line count) set metrics(count) [llength $filelist] set metrics(lines) [llength [split $filedata \n]] # extract procs, depending on the file_type switch -exact $file_type { tcl_procs { set metrics(procs) [regexp -all -line {^\s*ad_proc} $filedata] } test_procs { set metrics(procs) [regexp -all -line {^\s*aa_register_case} $filedata] } data_model_pg { set metrics(procs) [regexp -all -line -nocase {^\s*create\s+or\s+replace\s+function\s+} $filedata] } data_model_ora { set metrics(procs) [expr {[regexp -all -line -nocase {^\s+function\s+} $filedata] + [regexp -all -line -nocase {^\s+procedure\s+} $filedata]}] } default { # other file-types don't have procs set metrics(procs) 0 } } return [array get metrics] } ad_proc -public apm::get_package_descendent_options { package_key } { Get a list of pretty name, package key pairs for all packages which are descendents of the given package key. @param package_key The parent package's key. @return a list of pretty name, package key pairs suitable for use in a template select widget. } { set in_clause '[join [apm_package_descendents $package_key] ',']' return [db_list_of_lists get {}] } ad_proc -public apm::convert_type { -package_id:required -old_package_key:required -new_package_key:required } { Convert a package instance to a new type, doing the proper instantiate and mount callbacks and parameter creation. @param package_id The package instance to convert. @param old_package_key The package key we're converting from. @param new_package_key The new subsite type we're converting to. } { db_dml update_package_key {} util_memoize_flush "apm_package_key_from_id_mem $package_id" set node_id [site_node::get_node_id_from_object_id -object_id $package_id] if { $node_id ne "" } { site_node::update_cache -node_id $node_id } # DRB: parameter fix! db_foreach get_params {} { db_1row get_new_parameter_id {} db_dml update_param {} } db_list copy_new_params {} apm_parameter_sync $new_package_key $package_id foreach inherited_package_key [apm_package_inherit_order $new_package_key] { if { [lsearch -exact [apm_package_inherit_order $old_package_key] $inherited_package_key] == -1 } { apm_invoke_callback_proc \ -package_key $inherited_package_key \ -type after-instantiate \ -arg_list [list package_id $package_id] if { $node_id ne "" } { apm_invoke_callback_proc \ -package_key $inherited_package_key \ -type after-mount \ -arg_list [list node_id $node_id package_id $package_id] } } } } openacs-5.7.0/packages/acs-tcl/tcl/apm-procs.xql0000644000175000017500000002611411354515530021316 0ustar frankiefrankie select apv.package_key from apm_package_versions apv, apm_package_dependencies apd where apd.version_id = apv.version_id and apv.enabled_p = 't' and apd.dependency_type in ('extends', 'embeds') and apd.service_uri = :package_key select package_key from apm_package_types where implements_subsite_p = 't' select apd.service_uri from apm_package_versions apv, apm_package_dependencies apd where apv.package_key = :package_key and apv.installed_p = 't' and apd.version_id = apv.version_id and apd.dependency_type in ('extends', 'embeds') order by apd.dependency_id select inherit_templates_p from apm_package_types where package_key = :package_key select apd.service_uri, apd.dependency_type from apm_package_versions apv, apm_package_dependencies apd where apv.package_key = :package_key and apv.installed_p = 't' and apd.version_id = apv.version_id and (apd.dependency_type = 'embeds' or apd.dependency_type = 'extends' and :inherit_templates_p = 't') order by apd.dependency_id select apd.service_uri from apm_package_versions apv, apm_package_dependencies apd where apv.package_key = :package_key and apv.installed_p = 't' and apd.version_id = apv.version_id and apd.dependency_type in ('extends', 'embeds') order by apd.dependency_id desc select apd.service_uri from apm_package_versions apv, apm_package_dependencies apd where apv.package_key = :package_key and apv.installed_p = 't' and apd.version_id = apv.version_id and apd.dependency_type in ('requires', 'embeds', 'extends') order by apd.dependency_id desc select case when count(*) = 0 then 0 else 1 end from apm_package_versions where version_id = :version_id and enabled_p = 't' select coalesce(v.package_id, 0) as package_id, p.parameter_name, case when v.value_id is null then p.default_value else v.attr_value end as attr_value from apm_parameters p left outer join apm_parameter_values v using (parameter_id) where p.package_key = :package_key select distinct package_key from apm_package_versions where enabled_p='t' order by package_key select pretty_db_name from apm_package_db_types where db_type_key = :db_type select parameter_name from apm_parameters where package_key = :package_key select 1 from apm_package_types where package_key = :package_key select 1 from apm_package_versions where package_key = :package_key and installed_p = 't' select 1 from apm_package_versions where package_key = :package_key and enabled_p = 't' select 1 from apm_package_versions where version_id = :version_id and installed_p = 't' update apm_parameters set parameter_name = :parameter_name, default_value = :default_value, datatype = :datatype, description = :description, section_name = :section_name, min_n_values = :min_n_values, max_n_values = :max_n_values where parameter_id = :parameter_id update acs_objects set title = :parameter_name where object_id = :parameter_id select parameter_id from apm_parameters where package_key = :package_key and parameter_name = :parameter select scope, parameter_name from apm_parameters where parameter_id = :parameter_id select package_id, parameter_id, parameter_name from apm_packages p, apm_parameters ap where p.package_key = ap.package_key and ap.parameter_id = :parameter_id select package_key from apm_packages where package_id = :package_id select version_id from apm_enabled_package_versions where package_key = :package_key select package_id from apm_packages where package_key = :package_key select pretty_name, version_name, package_key, installed_p, distribution_uri, tagged_p from apm_package_version_info where version_id = :version_id select node_id from site_nodes where object_id = :package_id select parameter_name, attr_value from apm_parameters p, apm_parameter_values v, apm_packages a where p.scope = 'instance' and p.parameter_id = v.parameter_id and a.package_id = v.package_id and a.package_id = :package_id select proc from apm_package_callbacks where version_id = :version_id and type = :type insert into apm_package_callbacks (version_id, type, proc) values (:version_id, :type, :proc) update apm_package_callbacks set proc = :proc where version_id = :version_id and type = :type delete from apm_package_callbacks where version_id = (select version_id from apm_enabled_package_versions where package_key = :package_key) and type = :type select v.version_id, v.package_key, v.version_name, v.version_uri, v.summary, v.description_format, v.description, to_char(v.release_date, 'YYYY-MM-DD') as release_date, v.vendor, v.vendor_uri, v.enabled_p, v.installed_p, v.tagged_p, v.imported_p, v.data_model_loaded_p, v.cvs_import_results, v.activation_date, v.deactivation_date, v.item_id, v.content_length, v.distribution_uri, v.distribution_date, v.auto_mount, t.pretty_name, t.pretty_plural from apm_package_versions v, apm_package_types t where v.version_id = :version_id and t.package_key = v.package_key select pretty_name, package_key from apm_package_types where implements_subsite_p = 't' and package_key in ($in_clause) order by pretty_name update apm_packages set package_key = :new_package_key where package_id = :package_id select parameter_name, parameter_id from apm_parameters where package_key = :old_package_key select parameter_id as new_parameter_id from apm_parameters where package_key = :new_package_key and parameter_name = :parameter_name update apm_parameter_values set parameter_id = :new_parameter_id where parameter_id = :parameter_id and package_id = :package_id openacs-5.7.0/packages/acs-tcl/acs-tcl.info0000644000175000017500000000477011575167337020331 0ustar frankiefrankie Tcl Library Tcl Libraries t t OpenACS The Kernel Tcl API library. 2009-11-26 3 GPL version 2 OpenACS Contains all the core Tcl API, including the request processor, security and session management, permissions, site-nodes, package management infrastructure, etc. GPL version 2 3 openacs-5.7.0/packages/acs-tcl/catalog/0000755000175000017500000000000011724401447017515 5ustar frankiefrankieopenacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.en_US.ISO-8859-1.xml0000644000175000017500000002367011323212446024001 0ustar frankiefrankie a problem Administration approve approve email ban User's Browser: <b> Comments: </b><br> <span style="color:red;"> (Please explain what you where trying to do) </span> delete Details: Email: Error Description: error Error Description Error Details Error Report errors File with error: Theres was an error Inserting the Information to the Data Base: , and resubmit your entry. Argspec '%element%' is invalid, because it contains more than two elements. Error Submitted Automatically Error Report in %system_name% Filter type must be 'filter' or 'post' Flag name must be a valid identifier Flag names must be all lowercase Invalid date: %date_element% is missing Invalid date: %date_element% is not a natural number Invalid date: %date(month)% %date(day)% %date(year)% Invalid date: The year must contain 4 digits. Invalid number of arguments declared for the proc: the argument name and the value and possibly parameters Invalid number of parameters passed to filter range/ Invalid time: %time_element% is missing Invalid time: time is missing Invalid time: %time(time)% is in invalid format Invalid time: %time(time)% %time(ampm)% Invalid time: %time(time)% Multiple definitions of ad_page_contract filter \"%name%\" in %script% and %prior_script% %name% does not appear to be a valid email address. %name% does not appear to be a valid US phone number. %name% does not appear to be a boolean value. %name% is not a natural number, that is an integer greater than or equal to 0. %name% is not a valid SQL identifier %name% is not an integer %name% is not in the range \[%min%, %max%\] %name% is too long. Please enter a value of at most [lindex $range 1] characters long. The value you entered was [string length $value] characters long. This string looks broken! %name% is too long. Please enter a value of at most [lindex $length 1] characters long. The value you entered was [string length $value] characters long. This message text looks broken! %name% is too short. Please enter a value of at least [lindex $range 0] characters long. The value you entered was [string length $value] characters long. %name% is too short. Please enter a value of at least [lindex $length 1] characters long. The value you entered was [string length $value] characters long. This error was submitted Please back up using your browser, correct the above Problem with a Page (or maybe Your Input) Problem with a Templated Page Problem with your input require email verification The -requires element \"%element%\" has a comma in it. The -requires element \"%element%\" has too many colons Please, enter a valid email address. The flag name \"%name%\" is reserved for ad_page_contract The proc must accept two arguments, the name of the variable and a list of filters The signature for the variable '%formal_name%' was incorrect. There's no greble with that value User ID: Valid switches are: -requires Validation block names cannot contain colon Validation \"%key%\" complained %value% does not appear to be a valid U.S. phone number. Value for %name% contains HTML tags Value is not an decimal number. Value is not an integer We had a problem processing your request: You can't have two validation blocks named '%name%' You can't name your validation blocks the same as a formal argument You must specify something for %formal_name% You must supply a value for %formal_name% You specified a path to a file that is not allowed on the system. You've supplied two values for '%formal_name%' Immature Maturity level is visible in the Installer and when browsing the repository Level 1: Immature. Meets Level 0 Criterion Current release has no open priority 1 or priority 2 bugs. Has been available in a final major-minor release for at least one month and major-minor-dot release for one week. All API functions have documentation Source code is available at published location. http://openacs.org/forums/message-view?message%5fid=161393 Compatibility problems Mature Maturity level is visible in the Installer and when browsing the repository. Level 2: Mature. Meets all Level 1 criteia Has installation guide and user documentation OCT member verifies no serious deviations from general coding practices Has no namespace conflicts with existing level 2 packages. http://openacs.org/forums/message-view?message%5fid=161393 Mature and Standard Maturity level is visible in the Installer and when browsing the repository. Level 3: Mature and Standard. Meets all Level 2 Criteria OCT member verifies code meets published coding standards Contains no non-internationalized text Available on all supported databases. http://openacs.org/forums/message-view?message%5fid=161393 New Submission or Maturity Unknown Maturity level is visible in the Installer and when browsing the repository. Level 0: New Submission. This is the default for packages that don't have it set explicitly, and for new contributions. The only criterion for level 0 is that at package is uploaded into the repository. http://openacs.org/forums/message-view?message%5fid=161393 Page with error: Page %current% of %total% Percentage complete Previous Page: Public User reject Report Error Take me back where I was (before the error) Server Error some problems Sorry. The Error has been reported to the developers Thank you. The error whas the following: There was a server error processing your request. We apologize. There was a server error This file has generated an error. undelete User's Comments: User Name: We would appreciate if you can specify some details about what you were trying to do. We had with your input: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ja_JP.utf-8.xml0000644000175000017500000000024310727201372023505 0ustar frankiefrankie 削除 openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.pt_BR.ISO-8859-1.xml0000644000175000017500000002020310727201372023766 0ustar frankiefrankie um problema aprovar aprovar email banir Navegador do Usuário: <b> Commentários: </b><br> <span style="color:red;"> (Por favor explique o que está tentando fazer) </span> apagar Detalhes: Endereço Eletrônico: Descrição do Erro: erro Descrição do Erro Detalhes do Erro Relatório do Erro erros Arquivo com erro: Ocorreu um erro ao inserir a informaçao no banco de dados: , e submeta os dados novamente. Argspec '%element%' é inválidoi, porque contém mais de dois elementos. Erro submetido automaticamente Relatório de Erro em %system_name% Tipo de filtro deve ser 'filter' ou 'post' Nome do Flag deve ser um identificador válido Nomes do Flag devem ser grafados em caixa baixa Data inválida; %date_element% está faltando Data inválida: %date_element% não é um número natural Data inválida: %date(month)% %date(day)% %date(year)% Invalid date: O ano deve conter quatro dígitos. Número inválido de argumentos declarados para o procedimento: nome do argumento, valor e possíveis parâmetros Número inválido de parâmetros passados para a faixa do filtro/ Horário inválido: %time_element% omitido Horário inválido: hora omitida Horário inválido: %time(time)% é um formato inválido Horário inválido: %time(time)% %time(ampm)% Horário inválido: %time(time)% Múltiplas definições do filtro ad_page_contract \"%name%\" no %script% e %prior_script% %name% não parece ser um endereço eletrõnico válido %name% não parece ser um número de telefone Americano válido %name% não parece ser um valor boleano %name% não é um número natural, que é um inteiro maior ou igual a zero %name% não é um identificador SQL válido %name% não é um inteiro %name% não está na faixa \[%min%, %max%\] %name% é muito longo. Por favor digite um valor com no máximo [lindex $range 1] caracteres. O valor digitado por você tem [string length $value] caracteres. %name% é muito longo. Por favor digite um valor com no máximo [lindex $range 1] caracteres. O valor digitado por você tem [string length $value] caracteres. %name% é muito curto. Por favor digite um valor com no mínimo [lindex $range 0] caracteres. O valor digitado por você tem [string length $value] caracteres. %name% é muito curto. Por favor digite um valor com no mínimo [lindex $length 1] caracteres. O valor digitado por você tem [string length $value] caracteres. O erro foi enviado Por favor use o botão "Retornar à página anterior" do seu navegador, e corrija os erros acima Problema com a página (ou com os dados digitados) Problema com o Modelo de Página Problema com so dados digitados exigir verificação por email O elemento \"%element%\" em -requires tem uma vírgula. O elemento \"%element%\" em -requires tem muitos dois pontos. Por favor, digite um endereço de email válido. O nome de flag \"%name%\" é reservado por ad_page_contract O procedimento deve aceitar dois argumentos: o nome da variável e uma lista de filtros A assinatura para a variável '%formal_name%' estava errada. ID do usuário: As opções válidas são: -requires Nomes dos blocos de validação não podem ter dois pontos \"%key%\" de validação solicitada %value% não parece ser um telefone dos EUA Os valores para %name% contém tags em HTML O valor fornecido não é um número decimal. O valor fornecido não é inteiro Tivemos um problema processando o seu pedido: Você não pode ter dois blocos de validação chamados '%name%' Você não pode nomear seus blocos de validação da mesma maneira que um argumento formal Você deve especificar alguma coisa para %formal_name% Você deve fornecer um valor para %formal_name% Você especificou um caminho para um arquivo que não é permitido pelo sistema. Você forneceu dois valores para '%formal_name%' Imaturo Problemas de compatibilidade Maduro Maduro e Padrão Novo Envio ou Maturidade Desconhecida Página com erro: Página anterior: Usuário Público rejeitar Reportar Erro Me leve de volta para onde eu estava (antes do erro) Erro no Servidor alguns problemas Desculpe-me. O erro foi enviado aos desenvolvedores Obrigado. O erro foi o seguinte: Houve um erro ao processar seu pedido. Pedimos desculpas. Houve um erro no servidor Este arquivo gerou um erro. recuperar Comentários do Usuário: Nome do Usuário: Gostaríamos que você pudesse especificar alguns detalhes sobre o que estão tentando fazer. Nós tivemos com a sua entrada: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ar_LB.utf-8.xml0000644000175000017500000000076510727201372023512 0ustar frankiefrankie صدّقْ صدّقْ بريد إلكتروني حَظْر إمحي تطلّبْ تحقّقَ من البريد الإلكتروني Ø¥Ø±ÙØ¶ أعدْ الممحي openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.eu_ES.ISO-8859-1.xml0000644000175000017500000000066010727201372023765 0ustar frankiefrankie onartu posta onartu debekatu ezabatu e-postaren egiaztapena behar ezetsi des-ezabatu openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.da_DK.ISO-8859-1.xml0000644000175000017500000000066210727201372023731 0ustar frankiefrankie godkend godkend e-mail bandlys slet kræv bekræftelse via e-mail afvis fortryd sletning openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ko_KR.utf-8.xml0000644000175000017500000000065110727201372023532 0ustar frankiefrankie ìŠ¹ì¸ ìŠ¹ì¸ ì „ìžìš°íޏ 금지 ì‚­ì œ ì „ìžìš°íޏ í™•ì¸ ìš”ì²­ ê±°ì ˆ 삭제취소 openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.no_NO.ISO-8859-1.xml0000644000175000017500000000066510727201372024002 0ustar frankiefrankie godkjenn godkjenn e-post ikke tillat slett trenger e-postverifisering forkast gjenopprett openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.es_CO.ISO-8859-1.xml0000644000175000017500000000070110727201372023751 0ustar frankiefrankie aprobar aprobar correo prohibir eliminar requerir verificación de correo rechazar recuperar (borrado) openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.es_ES.ISO-8859-1.xml0000644000175000017500000002062211332116047023760 0ustar frankiefrankie un problema Administración aprobar aprobar correo expulsar Navegador del usuario: <b> Comentarios: </b><br> <span style="color:red;"> (Por favor, describa los pasos que ha seguido) </span> borrar Detalles: Email: Descripción del error: el error Descripción del Error Detalles del Error Informe de Error Errores Archivo con error: Ha habido un error al guardar la información en la base de datos y vuelva a intentarlo. Argspec %element% no es válido ya que contiene más de 2 elementos. Error Registrado Automáticamente Informe de Error en %system_name% El tipo del filtro debe ser "filter" o "post" El nombre del indicador debe ser un identificador válido Los nombres de indicadores debe estar en minúsculas Fecha inválida: falta %date_element% Fecha inválida: %date_element% no es un número natural Fecha inválida: %date(month)% %date(day)% %date(year)% Fecha inválida: el año debe contener 4 dígitos Número inválido de argumentos declarados para el procedimiento: el nombre del argumento, su valor y posibles parámetros Número inválido de parámetros pasados al filtro Hora inválida: falta %time_element% Hora inválida: falta la hora Hora inválida: %time(time)% no está en un formato válido Hora inválida: %time(time)% %time(ampm)% Hora inválida: %time(time)% Definiciones múltiples del filtro "%name%" en ad_page_contract de %script% y %prior_script% %name% no es una dirección de correo válida %name% no es un número de teléfono válido %name% no es un valor booleano %name% no es un número natural, es un entero superior o igual a 0 %name% no es un identificador SQL válido %name% no es un entero %name% no está en el rango \[%min%, %max%\] %name% es demasiado largo. Por favor, introduzca un valor no superior a [lindex $range 1] caracteres. El valor introducido contiene [string length $value] caracteres. %name% es demasiado largo. Por favor, introduzca un valor no superior a [lindex $length 1] caracteres. El valor introducido contiene [string length $value] caracteres. %name% es demasiado corto. Por favor, introduzca un valor de al menos [lindex $range 0] caracteres. El valor introducido contiene [string length $value] caracteres. %name% es demasiado corto. Por favor, introduzca un valor de al menos [lindex $length 0] caracteres. El valor introducido contiene [string length $value] caracteres. El error ha sido registrado Por favor, vuelva atrás, corrija Hubo un problema con la página Hubo un problema con la plantilla de la página Hubo un problema con los datos introducidos solicitar verificación de correo El elemento -requires "%element%" contiene una coma. El elemento -requires "%element%" contiene demasiados ":". Por favor, introduzca una dirección de correo válida. El nombre de indicador "%name%" está reservado para ad_page_contract El procedimiento debe aceptar 2 argumentos, el nombre de la variable y una lista de filtros La signatura de la variable %formal_name% no es correcta. No hay "greble" con ese valor ID de usuario: Los switches válidos son: -requires El nombre del bloque de validación no puede contener ":" Advertencia desde la validación "%key%" %value% no es un número de teléfono válido. El valor de %name% contiene etiquetas HTML El valor no es un número decimal. El valor no es un entero Hubo un problema al procesar su petición: No puede haber 2 bloques de validación con el nombre "%name%" El bloque de validación no puede tener el mismo nombre que un argumento formal Debe especificar algo para %formal_name% Debe dar un valor a %formal_name% Especificó un camino hacía un fichero que no está permitido en este sistema Ha proporcionado dos valores a %formal_name% Inestable Problemas de compatibilidad Estable Estable y Estándar Nueva aportación o Nivel de Estabilidad Desconocido Página con error: Página %current% de %total% Porcentaje completado Página anterior: Público rechazar Informe de Error Volver donde estaba (antes del error) Error de Servidor algunos problemas Lo sentimos. El error ha sido enviado a los desarrolladores Gracias. El error ha sido el siguiente: Ha habido un error al procesar su petición. Disculpe las molestias. Ha habido un error del servidor El archivo ha generado un error. recuperar (borrado) Commentarios de usuario: Nombre de Usuario: Le agradecemos que indique algunos detalles sobre lo que estaba intentando realizar. Ha sucedido con su petición: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.it_IT.ISO-8859-1.xml0000644000175000017500000000066610727201372024003 0ustar frankiefrankie approva approva l'email bandisci cancella richiedi la verifica dell'email rifiuta recupera openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.hi_IN.utf-8.xml0000644000175000017500000000113410727201372023510 0ustar frankiefrankie मनà¥à¤œà¥‚र करना इ-मैल मनà¥à¤œà¥‚र करना पà¥à¤°à¤¤à¤¿à¤¬à¤¨à¥à¤§ लगाना मिटाना इ-मैल सतà¥à¤¯à¤¾à¤ªà¤¨ की जरूरत असà¥à¤µà¥€à¤•र करना अ-मिटाना openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ro_RO.utf-8.xml0000644000175000017500000000066710727201372023554 0ustar frankiefrankie aprobă aprobă email interzice ÅŸterge necesită verificare prin email respinge anulează ÅŸtergerea openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.pl_PL.utf-8.xml0000644000175000017500000000373610727201372023542 0ustar frankiefrankie problem zatwierdź zatwierdź email wyrzuć PrzeglÄ…darka Użytkownika: usuÅ„ Szczegóły: Email: Opis Błędu: błąd Opis Błędu Szczegóły Błędu Raprort Błędu błędy Plik z błędem: Podczas wstawianie danych do bazy wystÄ…piÅ‚ błąd: , i ponownie wyÅ›lij Twój wpis. Błąd WysÅ‚any Automatycznie Raport Błędów w %system_name% Typu filtru musi być 'filer' lub 'post' Nazwa flagi musi byc prawidÅ‚owym identyfikatorem Nazwy flag mogÄ… zawierać tylko maÅ‚e litery Błędna data: brak elementu %date_element% Błędna data: Rok musi zawierać 4 cyfry. Błędny czas: nie wprowadzono czasu Błędny czas: %time(time)% ma błędny format %name% nie jest prawidÅ‚owym adresem email %name% nie jest prawidÅ‚owym numerem telefonu w USA wymagaj potwierdzenia emailem odrzuć przywróć openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.zh_TW.utf-8.xml0000644000175000017500000000064610727201372023564 0ustar frankiefrankie æ ¸å¯ æ ¸å¯é›»å­éƒµä»¶ ç¦æ­¢ 刪除 需è¦é›»å­éƒµä»¶ç¢ºèª 拒絕 撤消刪除 openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.en_AU.ISO-8859-1.xml0000644000175000017500000000064711056032452023756 0ustar frankiefrankie approve approve email ban delete require email verification reject undelete openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.zh_CN.utf-8.xml0000644000175000017500000000063010727201372023523 0ustar frankiefrankie 批准 批准email ç¦æ­¢ 删除 需è¦email确认 æ‹’ç» æ’¤æ¶ˆåˆ é™¤ openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.sv_SE.ISO-8859-1.xml0000644000175000017500000000066110727201372024005 0ustar frankiefrankie godkänn godkänn e-postadressen bannlys radera kräv e-postverifikation avslå återställ openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.fr_FR.ISO-8859-1.xml0000644000175000017500000000066510727201372023770 0ustar frankiefrankie admettre admettre email interdire effacer vérification email nécessaire rejeter récupérer openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.gl_ES.ISO-8859-1.xml0000644000175000017500000002005410727201372023755 0ustar frankiefrankie un problema aprobar aprobar correo-e expulsar Navegador do usuario: <b> Comentarios: </b><br> <span style="color:red;"> (Por favor, describa os pasos que seguiu) </span> eliminar Detalles Email: Descripción do erro erro Descripción do error Detalles dos erros Informe de erro erros Arquivo con erro Houbo un erro ó guardar a información na base de datos , e volva a intentalo Argspec '%element%' non é válido, xa que contén máis de 2 elementos Erro Rexistrado Automáticamente Informe de erro en %system_name% O tipo do filtro debe ser 'filter' ou 'post' O nome do indicador deber ser un identificador válido Os nomes de indicadores debe estar en minúsculas Data inválida: %date_element% is missing Data inválida: %date_element% non é un número natural Data inválida: %date(month)% %date(day)% %date(year)% Fecha inválida: O ano debe conter 4 díxitos Número inválido de argumentos declarados para o procedemento: o nome do argumento, o seu valor e posibles parámetros Número inválido de parámetros pasados ao filtro Hora inválida: falta %time_element% Hora inválida: falta a hora Hora inválida: %time(time)% non está nun formato válido Hora inválida: %time(time)% %time(ampm)% Hora inválida: %time(time)% Definicións múltiples do filtro "%name%" en ad_page_contract de %script% e %prior_script% %name% non é unha dirección de correo válida %name% non é un número de teléfono válido %name% non é un valor booleano %name% non é un número natural, é un entero superior ou igual a 0. %name% non é un identificador SQL válido %name% non é un entero %name% non está no rango \[%min%, %max%\] %name% é demasiado longo. Por favor, introduza un valor non superior a [lindex $range 1] caracteres. O valor introducido conten [string length $value] caracteres. %name% é demasiado longo. Por favor, introduza un valor non superior a [lindex $length 1] caracteres. O valor introducido conten [string length $value] caracteres. %name% é demasiado corto. Por favor, introduza un valor de polo menos [lindex $range 0] caracteres. O valor introducido conten [string length $value] caracteres. %name% é demasiado corto. Por favor, introduza un valor de polo menos [lindex $length 0] caracteres. O valor introducido contén [string length $value] caracteres. O erro foi rexistrado Por favor, volve atrás e corrixa o descrito arriba Houbo un problema coa páxina Houbo un problema coa plantilla da páxina Houbo un problema cos datos introducidos requerir verificación por correo-e O elemento -requires "%element%" contén unha coma. O elemento -requires "%element%" contén demasiados ":". Por favor, introduza unha dirección de correo válida. O nome de indicador "%name%" está reservado para ad_page_contract O procedemento debe aceptar 2 argumentos, o nome da variable e unha lista de filtros. A asignatura da variable %formal_name% non é correcta. Non hai "greble" con ese valor ID de usuario: Los switches válidos son: -requires O nome do bloque de validación non pode conter ":" Advertencia desde a validación "%key%" %value% non é un número de teléfono válido. O valor de %name% contén etiquetas HTML O valor non é un número decimal. O valor non é un enteiro Houbo un problema ó procesa-la súa petición: Non pode haber 2 bloques de validación co nome'%name%' O bloque de validación non pode ter o mesmo nome que un argumento formal Debe especificar algo para %formal_name% Debe dar un valor a %formal_name% Especificou un camiño cara un fichero que non está permitido neste sistema Debe dar 2 valores a '%formal_name%' Inestable Problemas de compatibilidade Estable Estable e Estándar Nova aportación ou Nivel de Estabilidade Desconocido Páxina con error: Páxina anterior: Público rexeitar Informe de Erro Voltar onde estaba (antes do erro) Erro de Servidor algúns problemas O sentimos O erro foi enviado aos desarrolladores Gracias O erro foi o seguinte: Houbo un erro ó procesa-la súa petición. Disculpe as molestias Houbo un erro do servidor O arquivo xenerou un erro. recuperar Comentarios de usuario: Nome de Usuario Agradecémoslle que indique algúns detalles sobre o que estaba intentando realizar. We had Ca súa petición: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ch_zh.utf-8.xml0000644000175000017500000000063011056032452023612 0ustar frankiefrankie 批准 批准email ç¦æ­¢ 删除 需è¦email确认 æ‹’ç» æ’¤æ¶ˆåˆ é™¤ openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ast_ES.ISO-8859-1.xml0000644000175000017500000000066610727201372024151 0ustar frankiefrankie aprobar aprobar correo espulsar eliminar pidir verificación per correo rechazar recuperar openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.de_DE.ISO-8859-1.xml0000644000175000017500000002101310720127056023717 0ustar frankiefrankie Ein Problem Freischalten E-Mail-Adresse bestätigen Deaktivieren Der Browser des Users: <b> Kommentare: </b><br> <span style="color:red;"> (Bitte erläutern Sie warum sie dies machen wollen) </span> Löschen Details: e-Mail: Fehlerbeschreibung Fehler Fehlerbeschreibung Fehler Details Fehler Report Fehler Datei mit Fehler: Bei der Einfügung der Information in die Datenbank trat ein Fehler: und wiederholen Ihre Eingabe. Die Spezifikation des Arguments '%element%' is ungültig, weil es mehr als zwei Elemente enthält Fehler automatisch gemeldet Fehlermeldung in %system_name% Filtertyp muss 'filter' oder 'post' sein Namen von Markierungszeichen müssen eine gültige Bezeichnung haben. Namen für Markierungszeichen dürfen nur kleine Buchstaben nutzen Ungültiges Datum: %date_element% fehlt Ungültiges Datum: %date_element% ist keine natürliche Zahl Ungültiges Datum: %date(month)% %date(day)% %date(year)% Ungültiges Datum: Das Jahr muss vier Ziffern haben. Ungültige Anzahl an Argumenten für den Prozess (proc): Der Name des Arguments und der Wert und mögliche Parameter Ungültige Anzahl von Parametern angegeben, um die Auswahl zu filtern Ungültige Zeit: %time_element% fehlt Ungültige Zeit: Zeit fehlt Ungültige Zeit: %time(time)% ist ein ungültiges Format Ungültige Zeit: %time(time)% %time(ampm)% Ungültige Zeit: %time(time)% Mehrere Definitionen des ad_page_contract Filters \"%name%\" in %script% and %prior_script% %name% scheint keine gültige e-Mail Adresse zu sein. %name% scheint keine gültige US-Telefonnummer zu sein. %name% scheint kein Boolean Wert zu sein. %name% ist keine natürliche Zahl, die eine ganzzahlige Zahl größer oder gleich 0 ist. %name% ist kein gültiger SQL Identifikator %name% ist keine ganzzahlige Zahl %name% ist nicht im Bereich von \[%min%, %max%\] %name% ist zu lang. Bitte geben Sie einen Wert ein, der höchstens [lindex $range 1] Buchstaben hat. Der Wert, den Sie eingegeben haben war [string length $value] Buchstaben lang. %name% ist zu lang. Bitte geben Sie einen Wert ein der mindestens [lindex $length 1] Zeichen lang ist. Der Wert den Sie eingeben haben war [string length $value] Zeichen lang. %name% ist zu kurz. Bitte geben Sie einen Wert ein, der mindestens [lindex $range 0] Zeichen lang ist. Der Wert den Sie eingegeben haben war [string length $value] Zeichen lang. %name% ist zu kurz. Bitte geben Sie einen Wert ein, der mindestens [lindex $length 1] Zeichen lang ist. Der Wert, den Sie eingegeben haben ist [string length $value] Zeichen lang. Der Fehler wurde übermittelt Bitte gehen Sie mit Ihrem Browser zurück und korrigieren den oben stehenden Problem mit Ihrer Seite (oder vielleicht mit Ihrer Eingabe) Problem mit einer Template Seite Problem mit Ihrer Eingabe E-Mail-Verifizierung anfordern Das -requires element \"%element%\" enthält ein Komma. Das -requires element \"%element%\" hat zu viele Doppelpunkte Bitte geben Sie eine gültige e-Mail Adresse ein. Der Namen der Markierung \"%name%\" ist für ad_page_contract reserviert Die Prozedur muss zwei Argumente akzeptieren, den Namen der Variablen und eine Liste von Filtern Die Signatur für die Variable '%formal_name%' war nicht korrekt. Es gibt kein "greble" bei diesem Wert User ID: Gültige Parameter sind: '-requires' Prüfblock Namen können keine Doppelpunkte enthalten Prüfung von "%key%" gab einen Fehler %value% scheint keine gültige US-Telefonnummer zu sein. Wert für %name% enthält HTML Tags Wert ist keine Dezimalzahl. Wert ist keine ganzzahlige Zahl Wir hatten ein Problem, Ihre Anfrage zu verarbeiten: Sie können nicht zwei Prüfblöcke namens '%name%' haben Sie können nicht den Prüfblock wie ein formalen Parameter benennen. Sie müssen etwas für %formal_name% spezifizieren Sie müssen einen Wert für %formal_name% bestimmen Sie haben einen Pfad spezifiziert, der im System nicht erlaubt ist. Sie haben zwei Werte für '%formal_name%' angegeben Unausgereift Kompatibilitätsprobleme Ausgereift Ausgereift und Standard Neues Paket oder unbekannter Reifegrad Seite mit Fehler: Vorhergehende Seite: Öffentlicher (nicht registrierter) User Ablehnen Fehler melden Zu der Seite zurückgehen, auf der ich vor dem Fehler war Server Error einige Probleme Entschuldigen Sie bitte! Der Fehler wurde an die Entwickler berichtet Danke! Der Fehler war der folgende: Es gab einen Server Error während Ihre Anfrage bearbeitet wurde. Wir entschuldigen uns! Es gab einen Server Error Diese Datei hat einen Fehler erzeugt. Wiederherstellen Kommentare des Users: User Name: Wir würden es begrüßen, wenn sie einige Details dessen,m was Sie gerade zu tun versuchten, spezifizieren könnten. Wir hatten mit ihrer Eingabe: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.nl_NL.ISO-8859-1.xml0000644000175000017500000002044710727201372023774 0ustar frankiefrankie een probleem goedkeuren e-mail goedkeuren uitsluiten Browser van gebruiker <b>Opmerkingen: </b><br> <span style="color:red;"> (Leg alstublieft uit wat u wilt doen) </span> verwijderen Details: E-mail: Foutbeschrijving: fout Foutbeschrijving Foutdetails Foutrapport fouten Bestand met fout: Er is een fout opgetreden bij het invoegen van de gegevens in de databank. , en dien uw lid opnieuw in Argspec '%element%' is ongeldig omdat het meer dan twee elementen bevat Fout automatisch ingestuurd Foutrapport in %system_name% Filter moet van het type 'filter' of 'post' zijn Vlagnaam moet een geldige symboolnaam zijn Vlagnamen moeten geheel uit kleine letters bestaan Ongeldige datum: %date_element% ontbreekt Ongeldige datum: %date_element% is geen natuurlijk getal Ongeldige datum: %date(month)% %date(day)% %date(year)% Ongeldige datum: Een jaar bestaat uit 4 cijfers. Ongeldig aantal paramaters gedeclareerd voor de procedure: de parameternaam en de waarde en evenuteel nog extra parameters Ongeldig aantal parameters aan filterbereik doorgegeven Ongeldige tijd: %time_element% ontbreekt Ongeldige tijd: tijd ontbreekt Ongeldige tijd: %time(time)% heeft een ongeldige indeling Ongeldige tijd: %time(time)% %time(ampm)% Ongeldige tijd %time(time)% Meerdere definities van ad_page_contract_filter \"%name%\" in %script% en %prior_script% %name% ziet er niet uit als een geldig e-mailadres %name% ziet er niet uit als een Amerikaans telefoonnummer %name% ziet er niet uit als een booleaanse waarde %name% ziet er niet uit als een natuurlijk getal, dat is, een geheel getal groter dan 0. %name% is geen geldig SQL-symbool %naam% is geen geheel getal %name% zit niet in het bereik \[%min%..%max%\] %name% is te lang. Geef alstublieft een waarde van minimaal [lindex $range 1] tekens lang in. De waarde die u ingaf was [string length $value] tekens lang. %name% is te lang. Geef alstublieft een waarde in van maximaal [lindex $length 1] tekens lang. De waarde die u ingaf was [string length $value] tekens lang. %name% is te kort. Geef alstublieft een waarde van minimaal [lindex $range 0] tekens lang in. De waarde die u ingaf was [string length $value] tekens lang. %name% is te kort. Geef alstublieft een waarde van minimaal [lindex $length 1] tekens lang in. De waarde die u ingaf was [string length $value] tekens lang. Deze fout is ingestuurd Ga met uw browser terug naar de vorige bladzijde en corrigeer het bovenstaande Probleem met pagina (kan door uw invoer veroorzaakt zijn) Probleem met sjabloonpagina Probleem met uw invoer E-mailbevestiging vereisen The element van -requires, \"%element%\" bevat een komma. The element van -requires, \"%element%\" bevat te veel dubbele punten. Geef alstublieft een geldig e-mailadres is. De vlagnaam \"%name%\" gereserveerd voor ad_page_contract. De procedure moet twee parameters accepteren, de naam van de variabele en een lijst van filters. De handtekening voor de variabele '%formal_name%' was niet juist. Er is geen "greble" met die waarde Gebruikers-ID Geldige opties zijn: -requires Validatiebloknamen kunnen geen puntkomma bevatten. Validatie \"%key%\" klaagde %value% ziet er niet als een Amerikaans telefoonnummer uit Waarde voor %name% bevat HTML-tags Waarde is geen decimaal getal. Waarde is geen integer Er is een probleem opgetreden tijdens het verwerken van uw verzoek: U kunt geen twee validatieblokken met de naam '%name%' hebben. U kunt uw validatieblokken niet hetzelfde noemen als een formele parameter U moet iets opgeven voor %formal_name% U moet een waarde opgeven voor %formal_name% U heeft een pad naar een bestand opgegeven dat niet toegestaan op het systeem is. U hebt twee waarden voor '%formal_name%' opgegeven. Nog niet rijp voor produktie Compatibiliteitsproblemen Rijp voor produktie Produktierijp en standaard. Nieuw ingezonden of produktierijpheid niet bekend Pagina met fout: Vorige fout: Publieke gebruiker weigeren Rapporteert fout Breng me terug naar waar ik was (voor de fout) Serverfout enige problemen Sorry. De fout is naar het ontwikkelteam gestuurd. Dank u. De fout was als volgt: Er is een serverfout opgetreden tijdens het behandelen van uw verzoek. We verontschuldigen ons. Er is een serverfout opgetreden Dit bestand heeft een fout gegenereerd. terughalen Gebruikersopmerkingen Gebruikersnaam: We zouden het op prijs stellen als u enige details kon geven wat u aan het doen was. Er is met uw invoer: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.el_GR.utf-8.xml0000644000175000017500000002733410720404625023523 0ustar frankiefrankie ένα Ï€Ïόβλημα έγκÏιση έγκÏιση email απαγόÏευση Λογισμικό πλοήγησης χÏήστη: <b> Σχόλια: </b><br> <span style="color:red;"> (ΠαÏακαλοÏμε εξηγείστε τι Ï€Ïοσπαθείτε να κάνετε) </span> διαγÏαφή ΛεπτομέÏειες: Email: ΠεÏιγÏαφή σφάλματος: σφάλμα ΠεÏιγÏαφή σφάλματος ΛεπτομέÏειες σφάλματος Αποτελέσματα σφάλματος σφάλματα ΑÏχείο με σφάλμα: ΠÏοέκυψε ένα σφάλμα κατά την εισαγωγή πληÏοφοÏιών στη βάση δεδομένων: , και επαναλάβετε την εισαγωγή. Το Argspec '%element%' είναι άκυÏο, επειδή πεÏιέχει πεÏισσότεÏα από δÏο στοιχεία. Το σφάλμα στάλθηκε αυτόματα Σφάλμα στο %system_name% Ο Ï„Ïπος φίλτÏου θα Ï€Ïέπει να είναι 'filter' ή 'post' Το όνομα σημαίας Ï€Ïέπει να είναι έγκυÏο Τα ονόματα σημαίας Ï€Ïέπει να είναι πεζά ΆκυÏη ημεÏομηνία: το %date_element% λείπει ΆκυÏη ημεÏομηνία: το %date_element% δεν είναι ένας φυσικός αÏιθμός ΆκυÏη ημεÏομηνία: %date(month)% %date(day)% %date(year)% ΆκυÏη ημεÏομηνία: Το έτος θα Ï€Ïέπει να πεÏιέχει 4 ψηφία. ΆκυÏος αÏιθμός επιχειÏημάτων που έχουν δηλωθεί για τη διαδικασία: το όνομα του επιχειÏήματος και η τιμή του είναι πιθανότατα παÏάμετÏοι ΆκυÏος αÏιθμός παÏαμέτÏων στο εÏÏος φίλτÏου ΆκυÏος χÏόνος: το %time_element% λείπει ΆκυÏος χÏόνος: η ÏŽÏα λείπει ΆκυÏος χÏόνος: %time(time)% είναι σε άκυÏη μοÏφή ΆκυÏος χÏόνος: %time(time)% %time(ampm)% ΆκυÏος χÏόνος: %time(time)% Πολλαπλοί οÏισμοί του φίλτÏου ad_page_contract \"%name%\" στα %script% και %prior_script% Το %name% δεν φαίνεται να είναι έγκυÏη διεÏθυνση email. To %name% δεν φαίνεται να είναι ένα έγκυÏο τηλέφωνο ΗΠΑ. Ο %name% δεν είναι μια boolean τιμή. Ο %name% δεν είναι ένας φυσικός αÏιθμός, δηλαδή ένας ακέÏαιος ίσος ή μεγαλÏτεÏος του 0. Ο %name% είναι ένα άκυÏο SQL identifier Ο %name% δεν είναι ακέÏαιος Ο %name% δεν είναι εντός οÏίων \[%min%, %max%\] Ο %name% είναι Ï€Î¿Î»Ï Î¼Î±ÎºÏÏÏ‚. ΠαÏακαλοÏμε εισάγετε μια τιμή για το μέγιστο αÏιθμό χαÏακτήÏων [lindex $range 1]. Η τιμή που εισάγατε διαθέτει [string length $value] χαÏακτήÏες μήκος. O %name% αποτελείται από πολλά ψηφία. ΠαÏακαλοÏμε εισάγετε μια τιμή με το Ï€Î¿Î»Ï [lindex $length 1] ψηφία. Η τιμή που είχατε δώσει ήταν [string length $value] ψηφίων. O %name% αποτελείται από Ï€Î¿Î»Ï Î»Î¯Î³Î± ψηφία. ΠαÏακαλοÏμε εισάγετε μια τιμή με το λιγότεÏο [lindex $range 0] ψηφία. Η τιμή που είχατε δώσει ήταν [string length $value] ψηφίων. Ο %name% άποτελείται από Ï€Î¿Î»Ï Î»Î¯Î³Î± ψηφία. ΠαÏακαλοÏμε εισάγετε μια τιμή τουλάχιστον [lindex $length 1] ψηφίων. Η τιμλη που είχατε εισάγει ήταν [string length $value] ψηφίων. Το σφάλμα έχει αποσταλλεί ΠαÏακαλοÏμε επιστÏέψετε πίσω με το λογισμικό πλοήγησης, διοÏθώστε τα παÏαπάνω Σφάλμα σε μια σελίδα (ή ίσως στις πληÏοφοÏίες που δώσατε) Σφάλμα με μια Ï€Ïότυπη σελίδα Σφάλμα στις πληÏοφοÏίες που δώσατε απαίτηση επιβεβαίωσης email Το -requires element \"%element%\" διαθέτει ένα κόμμα εντλος του. Το -requires element \"%element%\" διαθέτει πάÏα πολλές στήλους ΠαÏακαλοÏμε, δώστε ένα έγκυÏο email. Το όνομα σημαίας \"%name%\" έχει παÏακÏατηθεί για ad_page_contract Η διαδικασία θα Ï€Ïέπει να αποδέχεται δÏο επιχειÏήματα - δεδομένα, το όνομα της μεταβλητής και τη λίστα των φίλτÏων Η υπογÏαφή για την παÏάμετÏο '%formal_name%' ήταν λάθος. Δεν υπάÏχει greble με αυτή την τιμή Ταυτότητα χÏήστη: ΈγκυÏοι διακόπτες είναι: -requires η Επιβεβαίωση ομάδας ονομάτων δεν είναι δυνατόν να πεÏιέχει στήλες Το κλειδί επιβεβαίωσης \"%key%\" διαμαÏτυÏήθηκε Η τιμή %value% δεν μοιάζει με έγκυÏο αÏιθμό τηλεφώνου ΗΠΑ. Η τιμή για το %name%πεÏιέχει σημάνσεις HTML Η τιμή δεν είναι δεκαδικός αÏιθμός. Η τιμή δεν είναι ακέÏαιος ΠαÏουσιάστηκε ένα σφάλμα κατά την επεξεÏγασία του αιτήματος σας: Δεν είναι δυνατόν να έχετε δÏο ομάδες επιβεβαίωσης με το όνομα '%name%' Δεν μποÏείτε να ονομάσετε τις ομάδες θεώÏησης με το ίδιο όνομα που δώσατε σε ένα τυπικό επιχείÏημα Θα Ï€Ïέπει να καθοÏίσετε κάτι για το %formal_name% ΠÏέπει να οÏίσετε μια τιμή για το %formal_name% ΟÏίσατε διαδÏομή για ένα αÏχείο που δεν είναι επιτÏεπτή από το σÏστημα. Δώσατε δÏο τιμές για το '%formal_name%' ΑνώÏιμο ΠÏοβλήματα συμβατότητας ÎÏιμο ÎÏιμο και Τυπικό Îέα εισαγωγή ή άγνωστη ωÏιμότητα Σελίδα με σφάλμα: Σελίδα %current% από %total% Ποσοστό ολοκληÏώθηκε ΠÏοηγοÏμενη σελίδα: Γενικός χÏήστης απόÏÏιψη ΑναφοÏά σφάλματος ΕπιστÏοφή εκεί που ήμουν (Ï€Ïιν το σφάλμα) Σφάλμα εξυπηÏετητή μεÏικά σφάλματα Μας συγχωÏείτε. Το σφάλμα έχει ήδη αναφεÏθεί στην ομάδα ανάπτυξης ΕυχαÏιστοÏμε. Το σφάλμα ήταν το ακόλουθο: ΠαÏουσιάστηκε ένα σφάλμα εξυπηÏετητή κατά την εκτέλεση του αιτήματος σας. ΖητοÏμε συγνώμη για αυτό. ΠαÏουσιάστηκε ένα σφάλμα εξυπηÏετητή Το αÏχείο ανέφεÏε ένα σφάλμα. επαναφοÏά από διαγÏαφή Σχόλια χÏήστη: Όνομα χÏήστη: ΘΑ το εκτιμοÏσαμε εαν μποÏοÏσατε να αναφέÏετε μεÏικές λεπτομέÏειες για το τι Ï€Ïοσπαθείτε να κάνετε. Είχαμε με την εισαγωγή από εσας: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.es_GT.ISO-8859-1.xml0000644000175000017500000000070110727201372023762 0ustar frankiefrankie aprobar aprobar correo prohibir eliminar requerir verificación de correo rechazar recuperar (borrado) openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ind_ID.utf-8.xml0000644000175000017500000000057110727201372023654 0ustar frankiefrankie setujui setujui email ban hapus membutuhkan verifikasi email tolak openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ms_MY.utf-8.xml0000644000175000017500000000064410727201372023553 0ustar frankiefrankie lulus luluskan e-mel halang buang perlukan pengesahan e-mel ditolak tak jadi buang openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.cs_CZ.utf-8.xml0000644000175000017500000000065511056032452023527 0ustar frankiefrankie schválit schválit e-mail zakázat smazat požadovat ověření e-mailu odmítnout obnovit openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.sh_HR.utf-8.xml0000644000175000017500000000064610727201372023534 0ustar frankiefrankie dozvoli potvrdi email izgnaj izbrisi zahteva potvrdu emaila odbaci povrati izbrisano openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.nn_NO.ISO-8859-1.xml0000644000175000017500000000067110727201372023776 0ustar frankiefrankie godkjenn godkjenn e-post ikkje tillat slett ventar på e-postverifisering forkast rett opp att openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ca_ES.ISO-8859-1.xml0000644000175000017500000000517610727201372023746 0ustar frankiefrankie aprova aprova el correu expulsa Cercador d'usuaris: &lt;b&gt; Comentaris: &lt;/b&gt;&lt;br&gt; &lt;span style=&quot;color:red;&quot;&gt; (Per favor, indiqueu què intentàveu fer) &lt;/span&gt; suprimeix Detalls: Correu electrònic: Descripció de l'error: Descripció de l'error: Detalls de l'error Informe de l'error Arxiu amb error: S'ha produït un error en inserint informació en la base de dades: Error enviat automàticament Informe d'error en %system_name% Aquest error s'ha enviat sol·licita verificació de correu Per favor, introduïu una adreça de correu vàlida. ID d'usuari: Immadur Problemes de compatibilitat Madur Madur i estàndard nova presentació o venciment desconegut Pàgina amb error: Pàgina anterior: Usuari públic refusa Informa de l'error Torna enrere on estaves (abans de l'error) Error del servidor S'ha informat de l'error als desenvolupadors L'error era el següent: S'ha produït un error en el servidor en processar la vostra petició. Ho lamentem. S'ha produït un error de servidor Aquest arxiu ha generat un error. recupera (eliminat) Comentaris de l'usuari: Nom de l'usuari: Hauríeu d'especificar alguns detalls sobre el que intentàveu fer. openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ru_RU.utf-8.xml0000644000175000017500000000107210727201372023557 0ustar frankiefrankie утвердить утвердить Ñлектронный Ð°Ð´Ñ€ÐµÑ Ð·Ð°Ð¿Ñ€ÐµÑ‚Ð¸Ñ‚ÑŒ удалить требовать подтверждение по Ñлектронной почте отказать воÑÑтановить openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.fa_IR.utf-8.xml0000644000175000017500000000046710727201372023512 0ustar frankiefrankie تائيد تائيد پست الکترونيک حذ٠رد کردن openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.hu_HU.utf-8.xml0000644000175000017500000000066210727201372023537 0ustar frankiefrankie jóváhagy emailt jóváhagy letilt töröl email ellenÅ‘rzést igényel elutasít visszaállít openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.pt_PT.ISO-8859-1.xml0000644000175000017500000000066610727201372024021 0ustar frankiefrankie aprovar aprovar email banir eliminar requere verificação de email rejeitar anular eliminar openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.tr_TR.utf-8.xml0000644000175000017500000000065310727201372023561 0ustar frankiefrankie onayla eposta onayla yasakla sil eposta doÄŸrulaması gerektir red et silineni geri getir openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.fi_FI.utf-8.xml0000644000175000017500000000070010727201372023474 0ustar frankiefrankie hyväksy hyväksy sähköpostiviesti laita pannaan poista vaadi vahvistus sähköpostilla hylkää peru poisto openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.nl_ZA.ISO-8859-1.xml0000644000175000017500000002036211056032452023766 0ustar frankiefrankie 'n probleem goedkeur e-pos goedkeur uitsluit Blaaier van gebruiker <b>Opmerkinge: </b><br> <span style="color:red;"> (Leg assublief uit wat u wil doen) </span> verwyder Details: E-pos: Foutbeskrywing: fout Foutbeskrywing Foutdetails Foutrapport foute Lêer met fout: Daar is 'n fout opgetree by invoeging van die inligtinge in die databank. , en dien u lid opnuut in Argspec '%element%' is ongeldig omdat dit meer as twee elemente bevat Fout outomaties ingestuur Foutrapport in %system_name% Filter moet van het tipe 'filter' of 'post' wees Vlagnaam moet een geldige simboolnaam wees Vlagname moet geheel uit kleine letters bestaan Ongeldige datum: %date_element% ontbreek Ongeldige datum: %date_element% is geen natuurlike getal nie Ongeldige datum: %date(month)% %date(day)% %date(year)% Ongeldige datum: 'n Jaar bestaan uit 4 cyfers. Ongeldig aantal paramaters gedeklareer vir die prosedure: die parameternaam en die waarde en eventueel nog ekstra parameters Ongeldig aantal parameters aan filterbereik deurgegeef Ongeldige tyd: %time_element% ontbreek Ongeldige tyd: tyd ontbreek Ongeldige tyd: %time(time)% het 'n ongeldige indeling Ongeldige tyd: %time(time)% %time(ampm)% Ongeldige tyd %time(time) Meerdere definisies van ad_page_contract_filter \"%name%\" in %script% en %prior_script% %name% sien daar nie uit nie as 'n geldige e-posadres %name% sien daar nie uit nie as 'n Amerikaans telefoonnummer %name% sien daar nie uit nie as 'n booleaanse waarde %name% sien daar nie uit nie as 'n natuurlike getal, dat is, 'n geheel getal groter as 0. %name% is geen geldig SQL-simbool %naam% is geen geheel getal nie %name% sit nie in die bereik \[%min%..%max%\] nie %name% is te lang. Geef assublief 'n waarde van maximaal [lindex $range 1] tekens lang in. De waarde die u ingegeef het was [string length $value] tekens lang. %name% is te lang. Geef assublief 'n waarde in van maximaal [lindex $length 1] tekens lang. Die waarde wat u ingegeef het was [string length $value] tekens lang. %name% is te kort. Geef assublief 'n waarde van minimaal [lindex $range 0] tekens lang in. Die waarde wat u ingegeef het was [string length $value] tekens lang. %name% is te kort. Geef assublief 'n waarde van minimaal [lindex $length 1] tekens lang in. Die waarde wat u ingegeef het was [string length $value] tekens lang. Deze fout is ingestuur Gaan met u blaaier terug na die vorige bladsy en korrigeer die bostaande Probleem met bladsy (kan door uw invoer veroorzaak wees) Probleem met sjabloonbladsy Probleem met u invoer E-posbevestiging vereis Die element van -requires, \"%element%\" bevat 'n komma. Die element van -requires, \"%element%\" bevat te veel dubbele punte. Geef assublief 'n geldige e-posadres is. Die vlagnaam \"%name%\" is gereserveerd voor ad_page_contract. Die prosedure moet twee parameters aksepteer, die naam van die variabele en 'n lys van filters. Die handtekening vir die variabele '%formal_name%' was nie juis nie. Er is geen "greble" met die waarde Gebruikers-ID: Geldige opsies is: -requires Validatieblokname kan geen puntkomma's bevat nie. Validatie \"%key%\" het geklaag %value% sien daar nie as 'n Amerikaans telefoonnummer uit nie Waarde vir %name% bevat HTML-tags Waarde is geen desimaal getal nie. Waarde is geen integer nie Daar het 'n probleem opgetree tydens verwerking van u versoek: U kan geen twee validatieblokke met die naam '%name%' hê nie. U kan u validatieblokke nie dieselfde noem as 'n formele parameter U moet iets opgeef vir %formal_name% U moet 'n waarde opgeef voor %formal_name% U het 'n pad naar 'n lêer opgegeef wat nie toegestaan op dit stelsel is nie. U het twee waardes vir '%formal_name%' opgegeef. Nog nie ryp vir produksie nie Kompatibiliteitsprobleme Ryp vir produksie Produksieryp en standaard. Nuut ingesend of produksierypheid nie bekend nie Bladsy met fout Vorige bladsy Publieke gebruiker weiger Rapporteer fout Breng my terug na waar ek was (voor die fout) Bedienerfout enige probleme Helaas. Die fout is na die ontwikkelteam gestuur. Dank u. Die fout was as volg: Daar het 'n bedienerfout opgetree tydens behandeling van u versoek. Ons verskoon ons. Daar is 'n bedienerfout opgetree Hierdie lêer heeft een fout gegenereer. terughaal Gebruikersopmerkinge Gebruikersnaam: Ons sou dit op prys stel as u enige details kan geef waar u mee besig was Daar is met u invoer: openacs-5.7.0/packages/acs-tcl/catalog/acs-tcl.ar_EG.utf-8.xml0000644000175000017500000000076510727201372023510 0ustar frankiefrankie صدّقْ صدّقْ بريد إلكتروني حَظَر امحي تطلّبْ تحقّقَ من البريد الإلكتروني Ø§Ø±ÙØ¶ أعدْ الممحي openacs-5.7.0/packages/search/0000755000175000017500000000000011724401446016021 5ustar frankiefrankieopenacs-5.7.0/packages/search/lib/0000755000175000017500000000000011724401447016570 5ustar frankiefrankieopenacs-5.7.0/packages/search/lib/navbar.adp0000644000175000017500000000201710737741750020536 0ustar frankiefrankie
    openacs-5.7.0/packages/search/lib/navbar.tcl0000644000175000017500000000434511145362623020552 0ustar frankiefrankieset package_id [ad_conn package_id] set limit [parameter::get -package_id $package_id -parameter LimitDefault] set pages_per_group [parameter::get -package_id $package_id -parameter PagesPerGroup] set current_result_page [expr {$low / $limit}] set from_result_page [expr {($current_result_page / $pages_per_group) * $pages_per_group}] set last_result_page [expr {($count + $limit - 1)/ $limit - 1}] set to_result_page [expr {($last_result_page < $pages_per_group + $from_result_page - 1 ? $last_result_page : $pages_per_group + $from_result_page - 1)} ] set current_page_group [expr { int($current_result_page / $pages_per_group) }] set last_page_group [expr { int($last_result_page / $pages_per_group) }] set first_page_in_group [expr { $current_page_group * $pages_per_group }] set last_page_in_group [expr { ($current_page_group + 1) * $pages_per_group - 1 }] if { $current_page_group >= 1 } { set offset [expr {($current_page_group - 1) * $pages_per_group * $limit}] set url_previous_group [export_vars -base search {{q $urlencoded_query} search_package_id offset num}] } else { set url_previous_group "" } if { $current_page_group < $last_page_group } { set offset [expr {($current_page_group + 1) * $pages_per_group * $limit}] set url_next_group [export_vars -base search {{q $urlencoded_query} search_package_id offset num}] } else { set url_next_group "" } if { $current_result_page > 0 } { set offset [expr ($current_result_page - 1) * $limit] set url_previous [export_vars -base search {{q $urlencoded_query} search_package_id offset num}] } else { set url_previous "" } if { $current_result_page < $last_result_page } { set offset [expr {$current_result_page * $limit + $limit}] set url_next [export_vars -base search {{q $urlencoded_query} search_package_id offset num}] } else { set url_next "" } template::multirow create results_paginator item link current_p for { set __i $from_result_page } { $__i <= $to_result_page} { incr __i } { set link "search?q=${urlencoded_query}&search_package_id=$search_package_id" append link "&offset=[expr {$__i * $limit}]" append link "&num=$num" template::multirow append results_paginator [expr {$__i + 1}] $link [expr {$__i == $current_result_page}] } openacs-5.7.0/packages/search/lib/search.adp0000755000175000017500000000051311547562054020532 0ustar frankiefrankie
    openacs-5.7.0/packages/search/lib/search.tcl0000755000175000017500000000022710047447427020552 0ustar frankiefrankieset base_url [site_node::get_package_url -package_key search] set search_url "${base_url}search" set advanced_search_url "${base_url}advanced-search" openacs-5.7.0/packages/search/tcl/0000755000175000017500000000000011724401447016604 5ustar frankiefrankieopenacs-5.7.0/packages/search/tcl/search-init.tcl0000644000175000017500000000147011253303102021502 0ustar frankiefrankienamespace eval search {} namespace eval search::init {} nsv_set search_static_variables item_counter 0 ad_proc -private search::init::schedule_indexer {} { Schedule the indexer if the search package has been instantiated (indexing doesn't work if it hasn't been, so why should we schedule it?). We use the uncached version of apm_package_id_from_key to avoid forcing the user to restart their server after mounting search. } { set package_id [apm_package_id_from_key_mem search] if { $package_id != 0 } { ad_schedule_proc \ -thread t [parameter::get \ -package_id $package_id \ -parameter SearchIndexerInterval \ -default 60 ] \ search::indexer } } search::init::schedule_indexer openacs-5.7.0/packages/search/tcl/extra-args-procs.tcl0000644000175000017500000000204311156526217022512 0ustar frankiefrankie# ad_library { Handle extra arguments not defined in service contract. Preliminary support for package_ids and object_type as an example @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2009-03-13 @cvs-id $Id: extra-args-procs.tcl,v 1.1 2009/03/13 18:57:19 daveb Exp $ } ad_proc -callback search::extra_arg -impl object_type { -value -object_table_alias } { Implement per object type search } { if {$object_table_alias eq "" || ![info exists object_table_alias] || $value eq ""} { return [list] } return [list from_clause {} where_clause "$object_table_alias.object_type = '[db_quote $value]'"] } ad_proc -callback search::extra_arg -impl package_ids { -value -object_table_alias } { Implement per package_id search } { if {$object_table_alias eq "" || ![info exists object_table_alias] || $value eq ""} { return [list] } return [list from_clause {} where_clause "$object_table_alias.package_id in ([template::util::tcl_to_sql_list $value])"] }openacs-5.7.0/packages/search/tcl/search-procs.tcl0000644000175000017500000003534511354470053021711 0ustar frankiefrankiead_library { full-text search engine @author Neophytos Demetriou (k2pts@yahoo.com) @cvs-id $Id: search-procs.tcl,v 1.47 2010/03/30 21:42:03 donb Exp $ } namespace eval search {} ad_proc -public search::queue { -object_id -event } { Add an object to the search_observer_queue table with an event. You should excercise care that the entry is not being created from a trigger (although search is robust for multiple entries so it will not insert or update the same object more than once per sweep). @param object_id acs_objects object_id @param event INSERT or UPDATE or DELETE @author Jeff Davis (davis@xarg.net) } { if {$object_id ne "" && $event ne ""} { package_exec_plsql \ -var_list [list \ [list object_id $object_id] \ [list event $event] ] \ search_observer enqueue } else { ns_log warning "search::queue: invalid: called with object_id=$object_id event=$event\n[ad_print_stack_trace]\n" } } ad_proc -public search::dequeue { -object_id -event_date -event } { Remove an object from the search queue @param object_id acs_objects object_id @param event_date the event date as retrieved from the DB (and which should not be changed) @param event INSERT or UPDATE or DELETE @author Jeff Davis (davis@xarg.net) } { if {$object_id ne "" && $event_date ne "" && $event ne ""} { package_exec_plsql \ -var_list [list [list object_id $object_id] \ [list event_date $event_date] \ [list event $event] ] \ search_observer dequeue } else { ns_log warning "search::dequeue: invalid: called with object_id=$object_id event_date=$event_date event=$event\n[ad_print_stack_trace]\n" } } ad_proc -public search::is_guest_p { } { Checks whether the logged-in user is a guest } { set user_id [ad_conn user_id] # return [db_string get_is_guest_p {select dotlrn_privacy.guest_p(:user_id) from dual}] return 0 } ad_proc -public -callback search::action { -action -object_id -datasource -object_type } { Do something with a search datasource Called by the indexer after having created the datasource. @param action UPDATE INSERT DELETE @param datasource name of the datasource array @return ignored @author Jeff Davis (davis@xarg.net) } - ad_proc -private search::indexer {} { Search indexer loops over the existing entries in the search_observer_queue table and calls the appropriate driver functions to index, update, or delete the entry. @author Neophytos Demetriou @author Jeff Davis (davis@xarg.net) } { set driver [parameter::get -package_id [apm_package_id_from_key search] -parameter FtsEngineDriver] if { $driver eq "" || (![callback::impl_exists -callback search::index -impl $driver] && ! [acs_sc_binding_exists_p FtsEngineDriver $driver])} { # Nothing to do if no driver ns_log Debug "search::indexer: driver=$driver binding exists? [acs_sc_binding_exists_p FtsEngineDriver $driver]" return } # JCD: pull out the rows all at once so we release the handle foreach row [db_list_of_lists search_observer_queue_entry {}] { # DRB: only do Oracle shit for oracle (doh) if { [ns_config "ns/db/drivers" oracle] ne "" } { nsv_incr search_static_variables item_counter if {[nsv_get search_static_variables item_counter] > 1000} { nsv_set search_static_variables item_counter 0 db_exec_plsql optimize_intermedia_index {begin ctx_ddl.sync_index ('swi_index'); end; } } } foreach {object_id event_date event} $row { break } array unset datasource switch -- $event { UPDATE - INSERT { # Don't bother reindexing if we've already inserted/updated this object in this run if {![info exists seen($object_id)]} { set object_type [acs_object_type $object_id] ns_log debug "\n-----DB-----\n SEARCH INDEX object type = '${object_type}' \n------------\n " if {[callback::impl_exists -callback search::datasource -impl $object_type] \ || [acs_sc_binding_exists_p FtsContentProvider $object_type]} { array set datasource {mime {} storage_type {} keywords {}} if {[catch { # check if a callback exists, if not fall # back to service contract if {[callback::impl_exists -callback search::datasource -impl $object_type]} { #ns_log notice "\n-----DB-----\n SEARCH INDEX callback datasource exists for object_type '${object_type}'\n------------\n " array set datasource [lindex [callback -impl $object_type search::datasource -object_id $object_id] 0] } else { array set datasource [acs_sc_call FtsContentProvider datasource [list $object_id] $object_type] } search::content_get txt $datasource(content) $datasource(mime) $datasource(storage_type) $object_id if {[callback::impl_exists -callback search::index -impl $driver]} { if {![info exists datasource(package_id)]} { set datasource(package_id) "" } # set datasource(community_id) [search::dotlrn::get_community_id -package_id $datasource(package_id)] if {![info exists datasource(relevant_date)]} { set datasource(relevant_date) "" } callback -impl $driver search::index -object_id $object_id -content $txt -title $datasource(title) -keywords $datasource(keywords) -package_id $datasource(package_id) -community_id $datasource(community_id) -relevant_date $datasource(relevant_date) -datasource datasource } else { acs_sc_call FtsEngineDriver \ [ad_decode $event UPDATE update_index index] \ [list $datasource(object_id) $txt $datasource(title) $datasource(keywords)] $driver } } errMsg]} { ns_log Error "search::indexer: error getting datasource for $object_id $object_type: $errMsg\n[ad_print_stack_trace]\n" } else { # call the action so other people who do indexey things have a hook callback -catch search::action \ -action $event \ -object_id $object_id \ -datasource datasource \ -object_type $object_type # Remember seeing this object so we can avoid reindexing it later set seen($object_id) 1 search::dequeue -object_id $object_id -event_date $event_date -event $event } } } } DELETE { if {[catch { acs_sc_call FtsEngineDriver unindex [list $object_id] $driver } errMsg]} { ns_log Error "search::indexer: error unindexing $object_id [acs_object_type $object_id]: $errMsg\n[ad_print_stack_trace]\n" } else { # call the search action callbacks. callback -catch search::action \ -action $event \ -object_id $object_id \ -datasource NONE \ -object_type {} search::dequeue -object_id $object_id -event_date $event_date -event $event } # unset seen since you could conceivably delete one but then subsequently # reinsert it (eg when rolling back/forward the live revision). if {[info exists seen($object_id)]} { unset seen($object_id) } } } # Don't put that dequeue in a default block of the swith above # otherwise objects with insert/update and delete operations in the same # run would crash and never get dequeued search::dequeue -object_id $object_id -event_date $event_date -event $event } } ad_proc -private search::content_get { _txt content mime storage_type object_id } { @author Neophytos Demetriou @param content holds the filename if storage_type=file holds the text data if storage_type=text holds the lob_id if storage_type=lob } { upvar $_txt txt set txt "" # lob and file are not currently implemented switch $storage_type { text { set data $content } file { set data [cr_fs_path][db_string get_filename "select content from cr_revisions where revision_id=:object_id"] } lob { set data [db_blob_get get_lob_data {}] } } search::content_filter txt data $mime } ad_proc -private search::content_filter { _txt _data mime } { @author Neophytos Demetriou } { upvar $_txt txt upvar $_data data switch -glob -- $mime { {text/*} { set txt $data } default { set txt [search::convert::binary_to_text -filename $data -mime_type $mime] } } } ad_proc -callback search::datasource { -object_id:required } { This callback is invoked by the search indexer when and object is indexed for search. The datasource implementation name should be the object_type for the object. } - # define for all objects, not just search? ad_proc -callback search::search { -query:required -user_id {-offset 0} {-limit 10} {-df ""} {-dt ""} {-package_ids ""} {-object_type ""} {-extra_args {}} } { This callback is invoked when a search is to be performed. Query will be a list of lists. The first list is required and will be a list of search terms to send to the full text search engine. Additional optional lists will be a two element list. THe first element will be the name of an advanced search operator. The second element will be a list of data to restrict search results based on that operator. } - ad_proc -callback search::unindex { -object_id:required } { This callback is invoked to remove and item from the search index. } - ad_proc -callback search::url { -object_id:required } { This callback is invoked when a URL needs to be generated for an object. Usually this is called from /o.vuh which defers URL calculation until a link is actually clicked, so generating a list of URLs for various object types is quick. } - ad_proc -callback search::index { -object_id -content -title -keywords -community_id -relevant_date {-description ""} {-datasource ""} {-package_id ""} } { This callback is invoked from the search::indexer scheduled procedure to add an item to the index } - ad_proc -callback search::update_index { -object_id -content -title -keywords -community_id -relevant_date {-description ""} {-datasource ""} {-package_id ""} } { This callback is invoked from the search::indexer scheduled procedure to update an item already in the index } - ad_proc -callback search::summary { -query -text } { This callback is invoked to return an HTML fragment highlighting the terms in query } - ad_proc -callback search::driver_info { } { This callback returns information about the search engine implementation } - ad_proc -public search::driver_name { } { Return the name of the current search driver. } { return [parameter::get -package_id [apm_package_id_from_key search] -parameter FtsEngineDriver] } # dotlrn specific procs namespace eval search::dotlrn {} ad_proc -public search::dotlrn::get_community_id { -package_id } { if dotlrn is installed find the package's community_id @param package_id Package to find community @return dotLRN community_id. empty string if package_id is not under a dotlrn package instance } { if {[apm_package_installed_p dotlrn]} { set site_node [site_node::get_node_id_from_object_id -object_id $package_id] set dotlrn_package_id [site_node::closest_ancestor_package -node_id $site_node -package_key dotlrn -include_self] set community_id [db_string get_community_id {select community_id from dotlrn_communities_all where package_id=:dotlrn_package_id} -default [db_null]] return $community_id } return "" } ad_proc -callback search::extra_arg { -value {-object_table_alias {}} } { Generate a query fragment for search filtering by extra argument Argument name will be the implementation name called Search driver should call this for every extra argument and then build the search query using the query fragments returned @param value value of the argument @param object_table_alias SQL alias of table that contains the object_id to join against @return list in array format of {from_clause {} where_clause {}} } - ad_proc search::extra_args_names { } { List of names of extra args implemented } { set names [list] foreach procname [info procs ::callback::search::extra_arg::impl::*] { lappend names [namespace tail $procname] } return $names } ad_proc search::extra_args_page_contract { } { Generate ad_page_contract fragment for extra_args options Get all the callback impls for extra_args and add a page contract declaration @return string containing the ad_page_contract query delcarations for the extra_args that are implemented } { set contract "" foreach name [extra_args_names] { append contract "\{$name \{\}\}\n" } return $contract } ad_proc search::extra_args { } { List of extra_args to pass to search::search callback } { set extra_args [list] foreach name [extra_args_names] { upvar $name local_$name ns_log debug "extra_args name = '${name}' exists [info exists local_${name}]" if {[info exists local_$name]} { lappend extra_args $name [set local_$name] } } return $extra_args } openacs-5.7.0/packages/search/tcl/search-procs.xql0000644000175000017500000000165310466152006021724 0ustar frankiefrankie insert into search_observer_queue (object_id, event_date, event) values (:object_id, now(), :event) select object_id, event_date, event from search_observer_queue order by event_date asc select :content as content, 'file' as storage_type from dual select :content as content, 'lob' as storage_type from dual openacs-5.7.0/packages/search/tcl/syndicate-procs.tcl0000644000175000017500000000405411071053207022412 0ustar frankiefrankiead_library { Syndication callback and support routines. @author Jeff Davis (davis@xarg.net) @cvs-id $Id: syndicate-procs.tcl,v 1.3 2008/10/02 05:05:11 ryang Exp $ } ad_proc -public -callback search::action -impl syndicate {} { create or replace the record in the syndication table for the given object_id See photo-album-search-procs for an example of what you need to do in the FtsContentProvider datasource proc to make something syndicable. JCD: to fix: should not just glue together XML this way, also assumes rss 2.0, no provision for alternate formats, assumes content:encoded will be defined in the wrapper. } { if {![parameter::get -boolean -package_id [apm_package_id_from_key search] -parameter Syndicate -default 0]} { return } if {$action eq "DELETE"} { db_dml nuke {delete from syndication where object_id = :object_id} } else { upvar $datasource d if {![info exists d(syndication)]} { return } array set syn { category {} author {} guid {} } array set syn $d(syndication) set object_id $d(object_id) set url $syn(link) set body $d(content) set published [lc_time_fmt $syn(pubDate) "%a, %d %b %Y %H:%M:%S GMT"] set xmlMap [list & "&" < "<" > ">" \" """ ' "'"] set rss_xml_frag " [string map $xmlMap $d(title)] [string map $xmlMap $url] [string map $xmlMap $syn(guid)] [string map $xmlMap $syn(description)] [string map $xmlMap $syn(author)] [string map $xmlMap $syn(category)] $published " db_dml nuke {delete from syndication where object_id = :object_id} db_dml insert {insert into syndication(object_id, rss_xml_frag, body, url) values (:object_id, :rss_xml_frag, :body, :url)} } } openacs-5.7.0/packages/search/tcl/apm-callback-procs.tcl0000644000175000017500000000120011355251640022732 0ustar frankiefrankienamespace eval search {} namespace eval search::install {} ad_proc search::install::after_instantiate { -package_id:required } { Package after instantiation callback proc. Schedule the indexer so the admin doesn't have to restart their server to get search up and running after mounting it. } { # DRB: Unless it is being instantiated from initial install as specified by an install.xml # file, in which case the init file hasn't been sourced, and the user has to restart their # server anyway ... if { [info procs search::init::schedule_indexer] ne "" } { search::init::schedule_indexer } } openacs-5.7.0/packages/search/tcl/search-procs-oracle.xql0000644000175000017500000000057610334166507023177 0ustar frankiefrankie oracle8.1.6 select object_id, event_date, event from search_observer_queue where rownum < 100 order by event_date asc openacs-5.7.0/packages/search/tcl/search-convert-procs.tcl0000644000175000017500000000467310720360757023374 0ustar frankiefrankiead_library { Binaries conversion procedures for the search package. Thanks to Carsten Clasohm for suggesting the converter programs. @author Dirk Gomez @creation-date 2005-06-25 @cvs-id $Id: search-convert-procs.tcl,v 1.3 2007/11/19 19:20:15 emmar Exp $ } namespace eval search {} namespace eval search::convert {} ad_proc -public search::convert::binary_to_text { {-filename:required} {-mime_type:required} } { Converts the binary file to text and returns this as a string. (Carsten Clasohm provided the converters.) @author Dirk Gomez @creation-date 2005-06-25 } { set tmp_filename [ns_tmpnam] set result "" switch $mime_type { {application/msword} - {application/vnd.ms-word} { set convert_command {catdoc $filename >$tmp_filename} } {application/msexcel} - {application/vnd.ms-excel} { set convert_command {xls2csv $filename >$tmp_filename} } {application/mspowerpoint} - {application/vnd.ms-powerpoint} { set convert_command {ppthtml $filename >$tmp_filename} } {application/pdf} { set convert_command {pdftotext $filename $tmp_filename} } {application/vnd.oasis.opendocument.text} - {application/vnd.oasis.opendocument.text-template} - {application/vnd.oasis.opendocument.text-web} - {application/vnd.oasis.opendocument.text-master} - {application/vnd.oasis.opendocument.presentation} - {application/vnd.oasis.opendocument.presentation-template} - {application/vnd.oasis.opendocument.spreadsheet} - {application/vnd.oasis.opendocument.spreadsheet-template} { set convert_command {unzip -p $filename content.xml >$tmp_filename} } {text/html} { return [catch {[ns_striphtml $filename]} error] } default { # If there's nothing implemented for a particular mime type # we'll just index filename and pathname return "" } } if {[catch {eval exec $convert_command} err]} { catch {file delete $tmp_filename} ns_log Error "SEARCH: conversion failed - $convert_command: $err" file delete $tmp_filename return } set fd [open $tmp_filename "r"] set result [read $fd] close $fd file delete $tmp_filename return $result } openacs-5.7.0/packages/search/sql/0000755000175000017500000000000011724401447016621 5ustar frankiefrankieopenacs-5.7.0/packages/search/sql/oracle/0000755000175000017500000000000011724401447020066 5ustar frankiefrankieopenacs-5.7.0/packages/search/sql/oracle/search-sc-drop.sql0000644000175000017500000000263707736271243023440 0ustar frankiefrankiedeclare begin acs_sc_contract.del(contract_name => 'FtsContentProvider'); acs_sc_msg_type.del(msg_type_name => 'FtsContentProvider.Datasource.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsContentProvider.Datasource.OutputType'); acs_sc_msg_type.del(msg_type_name => 'FtsContentProvider.Url.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsContentProvider.Url.OutputType'); acs_sc_contract.del(contract_name => 'FtsEngineDriver'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Search.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Search.OutputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Index.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Index.OutputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Unindex.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Unindex.OutputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.UpdateIndex.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.UpdateIndex.OutputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Summary.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Summary.OutputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Info.InputType'); acs_sc_msg_type.del(msg_type_name => 'FtsEngineDriver.Info.OutputType'); end; / show errors openacs-5.7.0/packages/search/sql/oracle/search-tables-create.sql0000644000175000017500000000223411022567615024567 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- -- @author openacs@dirkgomez.de -- @version $Id: search-tables-create.sql,v 1.8 2008/06/07 20:29:01 donb Exp $ -- @creation-date 13-May-2005 -- -- Partly ported from ACES. create table search_observer_queue ( object_id integer, event_date date default sysdate, event varchar(6) constraint search_observer_queue_event_ck check (event in ('INSERT','DELETE','UPDATE')) ); openacs-5.7.0/packages/search/sql/oracle/search-from-scratch.sql0000644000175000017500000000447510475510121024444 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Populate .LRN's intermedia index -- -- @author Dirk Gomez -- @version $Id: search-from-scratch.sql,v 1.3 2006/08/31 07:31:29 emmar Exp $ -- @creation-date 13-May-2005 -- truncate table search_observer_queue; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects where object_type in ('cal_item') ; commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects, cr_items where object_id=live_revision and object_type in ('file_storage_object') ; commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects where object_type in ('static_portal_content'); commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects where object_type in ('forums_message') ; commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects where object_type in ('forums_forum') ; commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects, cr_items, cr_news where news_id=live_revision and object_id=live_revision and object_type in ('news'); -- and archive_date is null; commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects where object_type in ('faq') ; commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects where object_type in ('survey'); commit; insert into search_observer_queue (object_id, event) select object_id, 'INSERT' from acs_objects,cr_items where object_type in ('phb_person') and object_id=live_revision ; commit; --alter index swi_index rebuild parameters ('sync') ; openacs-5.7.0/packages/search/sql/oracle/search-packages-drop.sql0000644000175000017500000000010110334166506024562 0ustar frankiefrankiedrop package body search_observer; drop package search_observer; openacs-5.7.0/packages/search/sql/oracle/syndication-create.sql0000644000175000017500000000123310475510121024363 0ustar frankiefrankiecreate table syndication ( object_id integer constraint syndication_object_id_fk references acs_objects (object_id) on delete cascade constraint syndication_pk primary key, last_updated date default sysdate constraint syndication_last_updated_nn not null, rss_xml_frag blob, body blob, url blob ); comment on table syndication is 'stores xml fragments for consolidating into rss feeds. Also stores an html version of the content item and it''s url from the link field of the rss'; openacs-5.7.0/packages/search/sql/oracle/search-packages-create.sql0000644000175000017500000000375311022567615025102 0ustar frankiefrankie-- -- Copyright (C) 2005 MIT -- -- This file is part of dotLRN. -- -- dotLRN is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software -- Foundation; either version 2 of the License, or (at your option) any later -- version. -- -- dotLRN is distributed in the hope that it will be useful, but WITHOUT ANY -- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -- details. -- -- -- Create database packages for .LRN site-wide search -- -- @author Dirk Gomez -- @version $Id: search-packages-create.sql,v 1.5 2008/06/07 20:29:01 donb Exp $ -- @creation-date 13-May-2005 -- Partly ported from ACES. -- The site_wide_search packages holds generally useful -- PL/SQL procedures and functions. create or replace package search_observer as procedure enqueue ( object_id acs_objects.object_id%TYPE, event search_observer_queue.event%TYPE ); procedure dequeue ( object_id acs_objects.object_id%TYPE, event search_observer_queue.event%TYPE, event_date search_observer_queue.event_date%TYPE ); end search_observer; / show errors create or replace package body search_observer as procedure enqueue ( object_id acs_objects.object_id%TYPE, event search_observer_queue.event%TYPE ) is begin insert into search_observer_queue ( object_id, event ) values ( enqueue.object_id, enqueue.event ); end enqueue; procedure dequeue ( object_id acs_objects.object_id%TYPE, event search_observer_queue.event%TYPE, event_date search_observer_queue.event_date%TYPE ) is begin delete from search_observer_queue where object_id = dequeue.object_id and event = dequeue.event and to_char(dequeue.event_date,'yyyy-mm-dd hh24:mi:ss') = to_char(dequeue.event_date,'yyyy-mm-dd hh24:mi:ss'); end dequeue; end search_observer; / show errors openacs-5.7.0/packages/search/sql/oracle/syndication-drop.sql0000644000175000017500000000003010475510121024056 0ustar frankiefrankiedrop table syndication; openacs-5.7.0/packages/search/sql/oracle/search-create.sql0000644000175000017500000000015410475510121023305 0ustar frankiefrankie@@ search-tables-create.sql @@ search-packages-create.sql @@ search-sc-create.sql @@ syndication-create.sql openacs-5.7.0/packages/search/sql/oracle/upgrade/0000755000175000017500000000000011575226026021517 5ustar frankiefrankieopenacs-5.7.0/packages/search/sql/oracle/upgrade/upgrade-5.2.0d2-5.2.0d3.sql0000644000175000017500000000007610101200570025423 0ustar frankiefrankie-- Create the syndication table @@ ../syndication-create.sql openacs-5.7.0/packages/search/sql/oracle/search-drop.sql0000644000175000017500000000011407510203546023010 0ustar frankiefrankie@@ search-sc-drop.sql @@ search-packages-drop.sql @@ search-tables-drop.sql openacs-5.7.0/packages/search/sql/oracle/search-tables-drop.sql0000644000175000017500000000004210334166507024263 0ustar frankiefrankiedrop table search_observer_queue; openacs-5.7.0/packages/search/sql/oracle/search-sc-create.sql0000644000175000017500000001360010475510121023710 0ustar frankiefrankiedeclare foo integer; begin -- -- ACS-SC Contract: FtsEngineDriver -- foo := acs_sc_contract.new( contract_name => 'FtsEngineDriver', contract_desc => 'Full Text Search Engine Driver' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Search.InputType', msg_type_spec => 'query:string,offset:integer,limit:integer,user_id:integer,df:timestamp,dt:timestamp' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Search.OutputType', msg_type_spec => 'ids:integer[],stopwords:string[]' ); foo := acs_sc_operation.new( contract_name => 'FtsEngineDriver', operation_name => 'search', operation_desc => 'Search', operation_iscachable_p => 'f', operation_nargs => 6, operation_inputtype => 'FtsEngineDriver.Search.InputType', operation_outputtype => 'FtsEngineDriver.Search.OutputType' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Index.InputType', msg_type_spec => 'object_id:integer,txt:string,title:string,keywords:string' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Index.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'FtsEngineDriver', operation_name => 'index', operation_desc => 'Index', operation_iscachable_p => 'f', operation_nargs => 4, operation_inputtype => 'FtsEngineDriver.Index.InputType', operation_outputtype => 'FtsEngineDriver.Index.OutputType' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Unindex.InputType', msg_type_spec => 'object_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Unindex.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'FtsEngineDriver', operation_name => 'unindex', operation_desc => 'Unindex', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'FtsEngineDriver.Unindex.InputType', operation_outputtype => 'FtsEngineDriver.Unindex.OutputType' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.UpdateIndex.InputType', msg_type_spec => 'object_id:integer,txt:string,title:string,keywords:string' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.UpdateIndex.OutputType', msg_type_spec => '' ); foo := acs_sc_operation.new( contract_name => 'FtsEngineDriver', operation_name => 'update_index', operation_desc => 'Update Index', operation_iscachable_p => 'f', operation_nargs => 4, operation_inputtype => 'FtsEngineDriver.UpdateIndex.InputType', operation_outputtype => 'FtsEngineDriver.UpdateIndex.OutputType' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Summary.InputType', msg_type_spec => 'query:string,txt:string' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Summary.OutputType', msg_type_spec => 'summary:string' ); foo := acs_sc_operation.new( contract_name => 'FtsEngineDriver', operation_name => 'summary', operation_desc => 'Summary', operation_iscachable_p => 'f', operation_nargs => 2, operation_inputtype => 'FtsEngineDriver.Summary.InputType', operation_outputtype => 'FtsEngineDriver.Summary.OutputType' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Info.InputType', msg_type_spec => '' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsEngineDriver.Info.OutputType', msg_type_spec => 'package_key:string,version:version,automatic_and_queries_p:boolean,stopwords_p:boolean' ); foo := acs_sc_operation.new( contract_name => 'FtsEngineDriver', operation_name => 'info', operation_desc => 'Information about the driver', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'FtsEngineDriver.Info.InputType', operation_outputtype => 'FtsEngineDriver.Info.OutputType' ); -- -- ACS-SC Contract: FtsContentProvider -- foo := acs_sc_contract.new( contract_name => 'FtsContentProvider', contract_desc => 'Full Text Search Content Provider' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsContentProvider.Datasource.InputType', msg_type_spec => 'object_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsContentProvider.Datasource.OutputType', msg_type_spec => 'object_id:integer,title:string,content:string,mime:string,storage_type:string' ); foo := acs_sc_operation.new( contract_name => 'FtsContentProvider', operation_name => 'datasource', operation_desc => 'Data Source', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'FtsContentProvider.Datasource.InputType', operation_outputtype => 'FtsContentProvider.Datasource.OutputType' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsContentProvider.Url.InputType', msg_type_spec => 'object_id:integer' ); foo := acs_sc_msg_type.new( msg_type_name => 'FtsContentProvider.Url.OutputType', msg_type_spec => 'url:uri' ); foo := acs_sc_operation.new( contract_name => 'FtsContentProvider', operation_name => 'url', operation_desc => 'URL', operation_iscachable_p => 'f', operation_nargs => 1, operation_inputtype => 'FtsContentProvider.Url.InputType', operation_outputtype => 'FtsContentProvider.Url.OutputType' ); end; / show errors openacs-5.7.0/packages/search/sql/postgresql/0000755000175000017500000000000011575226026021026 5ustar frankiefrankieopenacs-5.7.0/packages/search/sql/postgresql/search-sc-drop.sql0000644000175000017500000000233307351546066024370 0ustar frankiefrankieselect acs_sc_contract__delete('FtsContentProvider'); select acs_sc_msg_type__delete ('FtsContentProvider.Datasource.InputType'); select acs_sc_msg_type__delete ('FtsContentProvider.Datasource.OutputType'); select acs_sc_msg_type__delete ('FtsContentProvider.Url.InputType'); select acs_sc_msg_type__delete ('FtsContentProvider.Url.OutputType'); select acs_sc_contract__delete('FtsEngineDriver'); select acs_sc_msg_type__delete ('FtsEngineDriver.Search.InputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Search.OutputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Index.InputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Index.OutputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Unindex.InputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Unindex.OutputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.UpdateIndex.InputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.UpdateIndex.OutputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Summary.InputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Summary.OutputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Info.InputType'); select acs_sc_msg_type__delete ('FtsEngineDriver.Info.OutputType'); openacs-5.7.0/packages/search/sql/postgresql/search-tables-create.sql0000644000175000017500000000037407661416240025531 0ustar frankiefrankiecreate table search_observer_queue ( object_id integer, event_date timestamptz default current_timestamp, event varchar(6) constraint search_observer_queue_event_ck check (event in ('INSERT','DELETE','UPDATE')) ); openacs-5.7.0/packages/search/sql/postgresql/search-packages-drop.sql0000644000175000017500000000017607661416240025536 0ustar frankiefrankiedrop function search_observer__dequeue(integer,timestamptz,varchar); drop function search_observer__enqueue(integer,varchar); openacs-5.7.0/packages/search/sql/postgresql/syndication-create.sql0000644000175000017500000000135610520460062025326 0ustar frankiefrankiecreate table syndication ( object_id integer constraint syndication_object_id_fk references acs_objects (object_id) on delete cascade constraint syndication_object_id_pk primary key, last_updated timestamptz constraint syndication_last_updated_nn not null default now(), rss_xml_frag text, body text, url text ); comment on table syndication is 'stores xml fragments for consolidating into rss feeds. Also stores an html version of the content item and it''s url from the link field of the rss'; openacs-5.7.0/packages/search/sql/postgresql/search-packages-create.sql0000644000175000017500000000212310051116277026021 0ustar frankiefrankie-- Search Observer Package -- -- @cvs-id $Id: search-packages-create.sql,v 1.6 2004/05/14 10:17:35 jeffd Exp $ create or replace function search_observer__enqueue(integer,varchar) returns integer as ' declare p_object_id alias for $1; p_event alias for $2; begin insert into search_observer_queue ( object_id, event ) values ( p_object_id, p_event ); return 0; end;' language 'plpgsql'; select define_function_args('search_observer__enqueue','object_id,event'); create or replace function search_observer__dequeue(integer,timestamptz,varchar) returns integer as ' declare p_object_id alias for $1; p_event_date alias for $2; p_event alias for $3; begin delete from search_observer_queue where object_id = p_object_id and event = p_event and to_char(event_date,''yyyy-mm-dd hh24:mi:ss.us-tz'') = to_char(p_event_date,''yyyy-mm-dd hh24:mi:ss.us-tz''); return 0; end;' language 'plpgsql'; select define_function_args('search_observer__dequeue','object_id,event_date,event'); openacs-5.7.0/packages/search/sql/postgresql/search-create.sql0000644000175000017500000000015410101431445024240 0ustar frankiefrankie\i search-tables-create.sql \i search-packages-create.sql \i search-sc-create.sql \i syndication-create.sql openacs-5.7.0/packages/search/sql/postgresql/upgrade/0000755000175000017500000000000011575226026022455 5ustar frankiefrankieopenacs-5.7.0/packages/search/sql/postgresql/upgrade/upgrade-5.2.0d2-5.2.0d3.sql0000644000175000017500000000007610101200571026362 0ustar frankiefrankie-- Create the syndication table \i ../syndication-create.sql openacs-5.7.0/packages/search/sql/postgresql/upgrade/upgrade-5.2.0d1-5.2.0d2.sql0000644000175000017500000000032510051116300026355 0ustar frankiefrankie-- define args so we can package_exec_plsql -- JCD select define_function_args('search_observer__enqueue','object_id,event'); select define_function_args('search_observer__dequeue','object_id,event_date,event'); openacs-5.7.0/packages/search/sql/postgresql/upgrade/upgrade-4.5-4.5.1.sql0000644000175000017500000000147407742351654025611 0ustar frankiefrankie-- packages/search/sql/postgresql/upgrade/upgrade-4.2-4.5.sql -- -- @author jon@jongriffi.com -- @creation-date 2002-08-02 -- @cvs-id $Id: upgrade-4.5-4.5.1.sql,v 1.4 2003/10/12 22:20:28 tilmanns Exp $ -- -- search-packages-create.sql drop function search_observer__dequeue(integer,timestamp with time zone,varchar); create function search_observer__dequeue(integer,timestamp with time zone,varchar) returns integer as ' declare p_object_id alias for $1; p_event_date alias for $2; p_event alias for $3; begin delete from search_observer_queue where object_id = p_object_id and event = p_event and event_date = p_event_date; return 0; end;' language 'plpgsql'; -- alter table search_observer_queue rename column date to event_date; openacs-5.7.0/packages/search/sql/postgresql/search-drop.sql0000644000175000017500000000011407510203547023747 0ustar frankiefrankie\i search-sc-drop.sql \i search-packages-drop.sql \i search-tables-drop.sql openacs-5.7.0/packages/search/sql/postgresql/search-tables-drop.sql0000644000175000017500000000004207344473133025224 0ustar frankiefrankiedrop table search_observer_queue; openacs-5.7.0/packages/search/sql/postgresql/search-sc-create.sql0000644000175000017500000001225207363705753024673 0ustar frankiefrankie-- -- ACS-SC Contract: FtsEngineDriver -- select acs_sc_contract__new ( 'FtsEngineDriver', -- contract_name 'Full Text Search Engine Driver' -- contract_desc ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Search.InputType', 'query:string,offset:integer,limit:integer,user_id:integer,df:timestamp,dt:timestamp' ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Search.OutputType', 'ids:integer[],stopwords:string[]' ); select acs_sc_operation__new ( 'FtsEngineDriver', -- contract_name 'search', -- operation_name 'Search', -- operation_desc 'f', -- operation_iscachable_p 6, -- operation_nargs 'FtsEngineDriver.Search.InputType', -- operation_inputtype 'FtsEngineDriver.Search.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Index.InputType', 'object_id:integer,txt:string,title:string,keywords:string' ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Index.OutputType', '' ); select acs_sc_operation__new ( 'FtsEngineDriver', -- contract_name 'index', -- operation_name 'Index', -- operation_desc 'f', -- operation_iscachable_p 4, -- operation_nargs 'FtsEngineDriver.Index.InputType', -- operation_inputtype 'FtsEngineDriver.Index.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Unindex.InputType', 'object_id:integer' ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Unindex.OutputType', '' ); select acs_sc_operation__new ( 'FtsEngineDriver', -- contract_name 'unindex', -- operation_name 'Unindex', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'FtsEngineDriver.Unindex.InputType', -- operation_inputtype 'FtsEngineDriver.Unindex.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ( 'FtsEngineDriver.UpdateIndex.InputType', 'object_id:integer,txt:string,title:string,keywords:string' ); select acs_sc_msg_type__new ( 'FtsEngineDriver.UpdateIndex.OutputType', '' ); select acs_sc_operation__new ( 'FtsEngineDriver', -- contract_name 'update_index', -- operation_name 'Update Index', -- operation_desc 'f', -- operation_iscachable_p 4, -- operation_nargs 'FtsEngineDriver.UpdateIndex.InputType', -- operation_inputtype 'FtsEngineDriver.UpdateIndex.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Summary.InputType', 'query:string,txt:string' ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Summary.OutputType', 'summary:string' ); select acs_sc_operation__new ( 'FtsEngineDriver', -- contract_name 'summary', -- operation_name 'Summary', -- operation_desc 'f', -- operation_iscachable_p 2, -- operation_nargs 'FtsEngineDriver.Summary.InputType', -- operation_inputtype 'FtsEngineDriver.Summary.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Info.InputType', '' ); select acs_sc_msg_type__new ( 'FtsEngineDriver.Info.OutputType', 'package_key:string,version:version,automatic_and_queries_p:boolean,stopwords_p:boolean' ); select acs_sc_operation__new ( 'FtsEngineDriver', -- contract_name 'info', -- operation_name 'Information about the driver', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'FtsEngineDriver.Info.InputType', -- operation_inputtype 'FtsEngineDriver.Info.OutputType' -- operation_outputtype ); -- -- ACS-SC Contract: FtsContentProvider -- select acs_sc_contract__new ( 'FtsContentProvider', -- contract_name 'Full Text Search Content Provider' -- contract_desc ); select acs_sc_msg_type__new ( 'FtsContentProvider.Datasource.InputType', 'object_id:integer' ); select acs_sc_msg_type__new ( 'FtsContentProvider.Datasource.OutputType', 'object_id:integer,title:string,content:string,mime:string,storage_type:string' ); select acs_sc_operation__new ( 'FtsContentProvider', -- contract_name 'datasource', -- operation_name 'Data Source', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'FtsContentProvider.Datasource.InputType', -- operation_inputtype 'FtsContentProvider.Datasource.OutputType' -- operation_outputtype ); select acs_sc_msg_type__new ( 'FtsContentProvider.Url.InputType', 'object_id:integer' ); select acs_sc_msg_type__new ( 'FtsContentProvider.Url.OutputType', 'url:uri' ); select acs_sc_operation__new ( 'FtsContentProvider', -- contract_name 'url', -- operation_name 'URL', -- operation_desc 'f', -- operation_iscachable_p 1, -- operation_nargs 'FtsContentProvider.Url.InputType', -- operation_inputtype 'FtsContentProvider.Url.OutputType' -- operation_outputtype ); openacs-5.7.0/packages/search/www/0000755000175000017500000000000011575226027016651 5ustar frankiefrankieopenacs-5.7.0/packages/search/www/doc/0000755000175000017500000000000011724401446017412 5ustar frankiefrankieopenacs-5.7.0/packages/search/www/doc/index.html0000644000175000017500000000103107540353253021405 0ustar frankiefrankie Search

    Search

    OpenACS documentation

    Vinod Kurup
    Last modified: Fri Sep 13 08:44:16 EDT 2002 openacs-5.7.0/packages/search/www/doc/guidelines.html0000644000175000017500000001370207357572204022443 0ustar frankiefrankie How to make an object type searchable?

    How to make an object type searchable?

    by Neophytos Demetriou (k2pts@cytanet.com.cy)
    Making an object type searchable involves three steps:
    • Choose the object type
    • Implement FtsContentProvider
    • Add triggers

    Choose the object type

    In most of the cases, choosing the object type is straightforward. However, if your object type uses the content repository then you should make sure that your object type is a subclass of the "content_revision" class. You should also make sure all content is created using that subclass, rather than simply create content with the "content_revision" type.
    • Object types that don't use the CR, can be specified using acs_object_type__create_type, but those that use the CR need to use content_type__create_type. content_type__create_type overloads acs_object_type__create_type and provides two views for inserting and viewing content data, and the CR depends on these views.
    • Whenever you call content_item__new, call it with 'content_revision' as the item_subtype and 'your_content_type' as the content_type.

    Implement FtsContentProvider

    FtsContentProvider is comprised of two abstract operations, namely datasource and url. The specification for these operations can be found in packages/search/sql/postgresql/search-sc-create.sql. You have to implement these operations for your object type by writing concrete functions that follow the specification. For example, the implementation of datasource for the object type note, looks like this:
    ad_proc notes__datasource {
        object_id
    } {
        @author Neophytos Demetriou
    } {
        db_0or1row notes_datasource {
            select n.note_id as object_id, 
                   n.title as title, 
                   n.body as content,
                   'text/plain' as mime,
                   '' as keywords,
                   'text' as storage_type
            from notes n
            where note_id = :object_id
        } -column_array datasource
    
        return [array get datasource]
    }
    
    When you are done with the implementation of FtsContentProvider operations, you should let the system know of your implementation. This is accomplished by an SQL file which associates the implementation with a contract name. The implementation of FtsContentProvider for the object type note looks like:
    select acs_sc_impl__new(
               'FtsContentProvider',                -- impl_contract_name
               'note',                              -- impl_name
               'notes'                              -- impl_owner_name
    );
    
    You should adapt this association to reflect your implementation. That is, change impl_name with your object type and the impl_owner_name to the package key. Next, you have to create associations between the operations of FtsContentProvider and your concrete functions. Here's how an association between an operation and a concrete function looks like:
    select acs_sc_impl_alias__new(
               'FtsContentProvider',                -- impl_contract_name
               'note',                              -- impl_name
               'datasource',                        -- impl_operation_name
               'notes__datasource',                 -- impl_alias
               'TCL'                                -- impl_pl
    );
    
    Again, you have to make some changes. Change the impl_name from note to your object type and the impl_alias from notes__datasource to the name that you gave to the function that implements the operation datasource.

    Add triggers

    If your object type uses the content repository to store its items, then you are done. If not, an extra step is required to inform the search_observer_queue of new content items, updates or deletions. We do this by adding triggers on the table that stores the content items of your object type. Here's how that part looks like for note.
    create function notes__itrg ()
    returns opaque as '
    begin
        perform search_observer__enqueue(new.note_id,''INSERT'');
        return new;
    end;' language 'plpgsql';
    
    create function notes__dtrg ()
    returns opaque as '
    begin
        perform search_observer__enqueue(old.note_id,''DELETE'');
        return old;
    end;' language 'plpgsql';
    
    create function notes__utrg ()
    returns opaque as '
    begin
        perform search_observer__enqueue(old.note_id,''UPDATE'');
        return old;
    end;' language 'plpgsql';
    
    
    create trigger notes__itrg after insert on notes
    for each row execute procedure notes__itrg (); 
    
    create trigger notes__dtrg after delete on notes
    for each row execute procedure notes__dtrg (); 
    
    create trigger notes__utrg after update on notes
    for each row execute procedure notes__utrg (); 
    

    Questions & Answers

    1. Q: If content is some binary file (like a pdf file stored in file storage, for example), will the content still be indexable/searchable?

      A: For each mime type we require some type of handler. Once the handler is available, i.e. pdf2txt, it is very easy to incorporate support for that mime type into the search package. Content items with unsupported mime types will be ignored by the indexer.

    2. Q: Can the search package handle lobs and files?

      A: Yes, the search package will convert everything into text based on the content and storage_type attributes. Here is the convention to use while writing the implementation of datasource:

      • Content is a filename when storage_type='file'.
      • Content is a lob id when storage_type='lob'.
      • Content is text when storage_type='text'.
    openacs-5.7.0/packages/search/www/help/0000755000175000017500000000000011724401446017575 5ustar frankiefrankieopenacs-5.7.0/packages/search/www/help/basics.html0000644000175000017500000000475607344473133021750 0ustar frankiefrankie The Basics of Our Search

    The Basics of Our Search

    Basic Search

    To enter a query, just type in a few descriptive words and hit the 'enter' key (or click on the Search button) for a list of relevant pages.

    Our search uses sophisticated text-matching techniques to find pages that are both important and relevant to your search. For instance, when our search analyzes a page, it assigns higher relevance to pages in which your query terms appear near each other.

    Automatic "and" Queries

    By default, our search only returns pages that include all of your search terms. There is no need to include "and" between terms. To restrict a search further, just include more terms.

    What is a stop word?

    Our search ignores common words and characters (known as stop words) as they tend to slow down searches without improving the quality of the results. Terms such as "where" and "how", as well as certain single digits and single letters, are not included in searches.

    See your search terms in context

    Each search result contains at least one excerpt from the found web page, which shows how your search terms are used in context on that page. Your search terms are bolded so you can tell at a glance whether the result is a page you want to visit.

    Does our search use stemming?

    Our search allows to find same words with different endings. For example, it will also try to find the word "test" if "testing" or "tests" is given in search query.

    Does capitalization matter?

    The searches are not case sensitive. All letters, regardless of how you type them, will be understood as lower case. For example, searches for "george washington", "George Washington", and "gEoRgE wAsHiNgToN" will all return the same results.

    openacs-5.7.0/packages/search/www/test.adp0000644000175000017500000000001007344473133020306 0ustar frankiefrankieopenacs-5.7.0/packages/search/www/index.adp0000644000175000017500000000062610723113472020443 0ustar frankiefrankie #search.Search# openacs-5.7.0/packages/search/www/index.tcl0000644000175000017500000000005310334166507020460 0ustar frankiefrankie# Nothing to see here... ad_return_templateopenacs-5.7.0/packages/search/www/search.adp0000644000175000017500000000627310737740752020621 0ustar frankiefrankie Results

    #search.lt_You_must_specify_some#

    #search.The# [#search.details#]
    #search.lt_bstopwordsb_is_a_very# [#search.details#]
    #search.lt_The_following_words_a# @stopwords@. [#search.details#]
    Your search - @query@ - did not match any content.
    #search.lt_No_pages_were_found_c#@query@".

    #search.Suggestions#
    • #search.lt_Make_sure_all_words_a#
    • #search.lt_Try_different_keyword#
    • #search.lt_Try_more_general_keyw#
    • #search.Try_fewer_keywords#

    #search.Searched_for_query#

    #search.Results# @low@-@high@ #search.of_about# @count@#search.________Search_took# @elapsed@ #search.seconds#

    1. #search.Untitled# @searchresult.title_summary;noquote@
      @searchresult.txt_summary;noquote@
      @searchresult.url_one@
    #search.lt_Tip_In_most_browsers_#

    #search.lt_Try_your_query_on_stw#

    #search.and_not_needed# [#search.details#]

    #search.lt_bstopwordsb_is_a_very# [#search.details#]

    #search.lt_The_following_words_a# [#search.details#]

    #search.Searched_for_query#

    #search.Results_count#

    openacs-5.7.0/packages/search/www/search.tcl0000644000175000017500000001631611332633342020622 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date September 01, 2001 @cvs-id $Id: search.tcl,v 1.36 2010/02/04 21:06:42 daveb Exp $ } { q:trim {t:trim ""} {offset:integer 0} {num:integer 0} {dfs:trim ""} {dts:trim ""} {search_package_id ""} {scope ""} {object_type ""} } -validate { keywords_p { if {![exists_and_not_null q]} { ad_complain "#search.lt_You_must_specify_some#" } } } set page_title "Search Results" set package_id [ad_conn package_id] set package_url [ad_conn package_url] set package_url_with_extras $package_url set context results set context_base_url $package_url # Do we want debugging information at the end of the page set debug_p 0 set user_id [ad_conn user_id] set driver [parameter::get -package_id $package_id -parameter FtsEngineDriver] if {[callback::impl_exists -impl $driver -callback search::driver_info]} { array set info [lindex [callback -impl $driver search::driver_info] 0] # array set info [list package_key intermedia-driver version 1 automatic_and_queries_p 1 stopwords_p 1] } else { array set info [acs_sc_call FtsEngineDriver info [list] $driver] } if { [array get info] eq "" } { ReturnHeaders ns_write "[_ search.lt_FtsEngineDriver_not_a]" ad_script_abort } if {[string trim $q] eq ""} { set query {} set empty_p 1 set url_advanced_search "advanced-search" ad_return_template # FIXME DAVEB I don't understand why I can't call ad_script_abort here instead of return.... # if I call ad_script_abort the adp is never rendered return } else { set empty_p 0 } if { $num <= 0} { set limit [parameter::get -package_id $package_id -parameter LimitDefault] } else { set limit $num } # # Work out the date restriction # set df "" set dt "" if { $dfs eq "all" } { set dfs "" } array set symbol2interval [parameter::get -package_id $package_id -parameter Symbol2Interval] if { $dfs ne "" } { set df [db_exec_plsql get_df "select now() + '$symbol2interval($dfs)'::interval"] } if { $dts ne "" } { set dt [db_exec_plsql get_dt "select now() + '$symbol2interval($dts)'::interval"] } #set q [string tolower $q] set urlencoded_query [ad_urlencode $q] if { $offset < 0 } { set offset 0 } set params [list $q $offset $limit $user_id $df] if {$search_package_id eq "" && [parameter::get -package_id $package_id -parameter SubsiteSearchP -default 1] && [subsite::main_site_id] != [ad_conn subsite_id]} { # We are in a subsite and SubsiteSearchP is true lappend params [concat [ad_conn subsite_id] [subsite::util::packages -node_id [ad_conn node_id]]] } else { lappend params $search_package_id } set t0 [clock clicks -milliseconds] # TODO calculate subsite or dotlrn package_ids if {"this" ne $scope } { # don't send package_id if its not searching this package # set search_package_id "" ;# don't overwrite this, when you are restricting search to package_id } else { set search_node_id [site_node::get_node_id_from_object_id -object_id $search_package_id] if {"dotlrn" eq [site_node::get_element -node_id $search_node_id -element package_key]} { set search_package_id [site_node::get_children -node_id $search_node_id -element package_id] } } if {[callback::impl_exists -impl $driver -callback search::search]} { # DAVEB TODO Add subsite to the callback def? # FIXME do this in the intermedia driver! # set final_query_string [db_string final_query_select "select site_wide_search.im_convert(:q) from dual"] array set result [lindex [callback -impl $driver search::search -query $q -offset $offset -limit $limit -user_id $user_id -df $df -extra_args [list package_ids $search_package_id object_type $object_type]] 0] } else { array set result [acs_sc_call FtsEngineDriver search $params $driver] } set tend [clock clicks -milliseconds] if { $t eq [_ search.Feeling_Lucky] && $result(count) > 0} { set object_id [lindex $result(ids) 0] set object_type [acs_object_type $object_id] if {[callback::impl_exists -impl $object_type -callback search::url]} { set url [callback -impl $object_type search::url -object_id $object_id] } else { set url [acs_sc_call FtsContentProvider url [list $object_id] $object_type] } ad_returnredirect $url ad_script_abort } set elapsed [format "%.02f" [expr {double(abs($tend - $t0)) / 1000.0}]] if { $offset >= $result(count) } { set offset [expr {($result(count) / $limit) * $limit}] } set low [expr {$offset + 1}] set high [expr {$offset + $limit}] if { $high > $result(count) } { set high $result(count) } if { $info(automatic_and_queries_p) && ([lsearch -exact $q and] > 0) } { set and_queries_notice_p 1 } else { set and_queries_notice_p 0 } set url_advanced_search "" append url_advanced_search "advanced-search?q=$urlencoded_query" if { $num > 0 } { append url_advanced_search "&num=$num" } set query $q set nquery [llength [split $q]] set stopwords $result(stopwords) set nstopwords [llength $result(stopwords)] set count $result(count) template::multirow create searchresult title_summary txt_summary url_one object_id for { set __i 0 } { $__i < [expr {$high - $low +1}] } { incr __i } { if {[catch { set object_id [lindex $result(ids) $__i] if {$object_id eq ""} { ns_log warning "Search object_id is empty, this should never happen query was '${q}'" continue } set object_type [acs_object_type $object_id] if {[callback::impl_exists -impl $object_type -callback search::datasource]} { array set datasource [lindex [callback -impl $object_type search::datasource -object_id $object_id] 0] set url_one [lindex [callback -impl $object_type search::url -object_id $object_id] 0] } else { ns_log warning "SEARCH search/www/search.tcl callback::datasource::$object_type not found" array set datasource [acs_sc_call FtsContentProvider datasource [list $object_id] $object_type] set url_one [acs_sc_call FtsContentProvider url [list $object_id] $object_type] } search::content_get txt $datasource(content) $datasource(mime) $datasource(storage_type) $object_id if {[callback::impl_exists -impl $driver -callback search::summary]} { set title_summary [lindex [callback -impl $driver search::summary -query $q -text $datasource(title)] 0] set txt_summary [lindex [callback -impl $driver search::summary -query $q -text $txt] 0] } else { set title_summary [acs_sc_call FtsEngineDriver summary [list $q $datasource(title)] $driver] set txt_summary [acs_sc_call FtsEngineDriver summary [list $q $txt] $driver] } } errmsg]} { ns_log error "search.tcl object_id $object_id object_type $object_type error $errmsg" } else { template::multirow append searchresult $title_summary $txt_summary $url_one } } set search_the_web [parameter::get -package_id $package_id -parameter SearchTheWeb] if {[llength $search_the_web]} { set stw "" foreach {url site} $search_the_web { append stw "$site " } } # header stuffs template::head::add_css \ -href "/resources/search/search.css" \ -media "all" openacs-5.7.0/packages/search/www/resources/0000755000175000017500000000000011724401446020657 5ustar frankiefrankieopenacs-5.7.0/packages/search/www/resources/search.css0000644000175000017500000000147610723113472022643 0ustar frankiefrankie#search-info { margin-bottom:0px; border-top:1px solid #cfcfcf; background:#dddddd; padding:3px 0; width:100%; } #search-info p { font-size:100%; color: #000000; } #search-info p.subtitle { margin-left:3px; position:absolute; left:10px; padding-left:5px; margin-top:-1px; } #search-info p.times { text-align:right; margin:0; padding-right:5px; margin-left:13em; white-space:nowrap; } #search-results li { margin-bottom:15px; display:block; } #search-results li:before { content: counter(item) ". "; counter-increment: item; } #search-results a.result-title { font-size:110%; } #search-results .result-text { padding-left: 14px; } #search-results .result-url { padding-left: 14px; color: #008000; } #results-pages { text-align:center; margin-bottom:5px; } openacs-5.7.0/packages/search/www/advanced-search.adp0000644000175000017500000000176310723113472022347 0ustar frankiefrankie #search.Advanced_Search# "advanced search"

    openacs-5.7.0/packages/search/www/advanced-search.tcl0000644000175000017500000000051711145362623022364 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou } { {q ""} {num 0} } set package_id [ad_conn package_id] if { $num == 0 } { set num [parameter::get -package_id $package_id -parameter LimitDefault] } set title "Advanced Search" set context "advanced search" set context_bar [ad_context_bar $title] ad_return_templateopenacs-5.7.0/packages/search/search.info0000644000175000017500000000611211575167337020157 0ustar frankiefrankie Search Search t t OpenACS 2011-06-12 3 Site wide search OpenACS 3 GPL version 2 Site wide search implemented with service contracts, currently supports postgres via the tsearch2 driver (OpenFTS still support but deprecated). openacs-5.7.0/packages/search/catalog/0000755000175000017500000000000011724401447017434 5ustar frankiefrankieopenacs-5.7.0/packages/search/catalog/search.de_DE.ISO-8859-1.xml0000644000175000017500000000316710720127056023567 0ustar frankiefrankie Erweiterte Suche jederzeit Datumsspanne Details Auf gut Glück '<b>%stopwords%</b>' is ein sehr gebräuchliches Wort und ist daher in der Suche nicht verwendet worden FtsEngineDriver ist nicht verfügbar Stellen Sie sicher das alle Worte richtig geschrieben sind. Versuchen Sie unterschiedliche Schlüsselwörter Versuchen Sie mehr generelle Schlüsselwörter Versuchen Sie Ihre Suche mit '%stw;noquote%' Sie müssen wenigstens ein Schlüsselwort spezifizieren Nächste letzten 3 Monate letzten 6 Monate letztes Jahr Vorhergehendes Seite mit den Resultaten: Resultate Suche Gesucht wurde nach: <b>%query%</b> Vorschläge: Versuchen Sie es mit weniger Schlüsselworten Unbenannt openacs-5.7.0/packages/search/catalog/search.nl_NL.ISO-8859-1.xml0000644000175000017500000000301410727201407023620 0ustar frankiefrankie Geavanceerd zoeken eender wanneer Datumbereik details Doe een gok "<b>%stopwords%</b>" is een zeer veel voorkomend woord en is niet in de zoekopdracht meegenomen. FtsEngineDriver niet beschikbaar Let op dat alle woorden correct gespeld zijn. Probeer andere kernwoorden. Probeer meer algemene kernwoorden. Probeer je zoekvraag op: %stw;noquote% Je moet een aantal kernwoorden opgeven. Volgende afgelopen 3 maanden afgelopen 6 maanden afgelopen jaar Vorige Resultaatpagina: Resultaten Zoeken Gezocht naar: %query% Suggesties: Probeer minder kernwoorden. Naamloos openacs-5.7.0/packages/search/catalog/search.pl_PL.utf-8.xml0000644000175000017500000000167110727201407023373 0ustar frankiefrankie Spróbuj z innymi sÅ‚owami kluczowymi. Spróbuj bardziej ogólnych słów kluczowych. Musisz podać jakieÅ› sÅ‚owa kluczowe. NastÄ™pne zeszÅ‚e 3 miesiÄ…ce zeszÅ‚ych 6 miesiÄ™cy zeszÅ‚y rok Poprzednie Strona Wyników: wyniki Szukaj Szukano frazy: <b>%query%</b> Sugestie: Spróbuj wpisać mniej słów. Bez TytuÅ‚u openacs-5.7.0/packages/search/catalog/search.nl_ZA.ISO-8859-1.xml0000644000175000017500000000442411055610261023624 0ustar frankiefrankie Gevorderde soektog "<b>AND</b>"-operator is onnodig -- ons gebruik standaard alle soekterme. eender wanneer Datumbereik details Toon Doen 'n gok "<b>%stopwords%</b>" is 'n nogal baie voorkomend woord en is nie in die soekopdrag meegeneem nie. FtsEngineDriver nie beskikbaar nie Let op dat alle woorde korrek gespel is. Geen bladsye gevind nie met " Die volgende woorde kom nogal baie voor en is nie in die soekopdrag meegeneem nie: Probeer andere kernwoorde. Probeer meer algemene kernwoorden. Probeer jou soekvraag op: %stw;noquote% Jy moet 'n aantal kernwoorde opgeef Volgende Soek is momenteel nie gekonfigureer nie. Alleen die webbaas kan dit inskakel. afgelope 3 maande afgelope 6 maande afgelope jaar Vorige Resultaatbladsy: resultate Resultate <b>%low% - %high%</b> uit ongeveer <b>%count%</b>. Soektog het %elapsed% seconde geverg. Soek Gesoek na: %query% Suggesties: Tip: In die meeste blaaiers kan u gewoon op "return" druk in plaas van op die soekknop. Probeer minder kernwoorde. Naamloos openacs-5.7.0/packages/search/catalog/search.en_US.ISO-8859-1.xml0000755000175000017500000000445711547562054023657 0ustar frankiefrankie . Search took Advanced Search "advanced search" anytime Date Range details Enter keywords to search for Feeling Lucky "<b>%stopwords%</b>" is a very common word and was not included in your search. FtsEngineDriver not available! Make sure all words are spelled correctly. No pages were found containing " The following words are very common and were not included in your search: Tip: In most browsers you can just hit the return key instead of clicking on the search button. Try different keywords. Try more general keywords. Try your query on: %stw;noquote% You must specify some keywords &nbsp;Display Next of about past 3 months past 6 months past year Previous Result page: Results results Search Search results for <strong>%query%</strong> seconds. selected Suggestions: "<b>AND</b>" operator is unnecessary -- we include all search terms by default. Try fewer keywords. Untitled openacs-5.7.0/packages/search/catalog/search.pt_BR.ISO-8859-1.xml0000644000175000017500000000310210727201407023622 0ustar frankiefrankie Busca Avançada qualquer hora Intervalo de Data detelhes Sinto-me com Sorte "<b>%stopwords%</b>" é uma palavra muito comum e não foi incluída na sua pesquisa. FtsEngineDriver não está disponível! Tenha certeza de que todas as palavras são soletradas corretamente. Tente palavras-chave diferentes. Tente palavras-chave mais específicas. Tente sua pergunta em: %stw;noquote% Você precisa especificar algumas palavras-chave. Próximo 3 meses depois 6 meses depois ano passado Anterior Página de resultados: resultados Busca Busca realizada por: <b>%query%</b> Sugestões Tente menos palavras-chave Sem Título openacs-5.7.0/packages/search/catalog/search.el_GR.utf-8.xml0000644000175000017500000000646410720404626023363 0ustar frankiefrankie . Η αναζήτηση διήÏκησε ΠÏοχωÏημένη αναζήτηση "Ï€ÏοχωÏημένη αναζήτηση" οποτεδήποτε ΧÏονική πεÏίοδος ΛεπτομέÏειες Îιώθω τυχεÏός Η "<b>%stopwords%</b>" είναι μια Ï€Î¿Î»Ï ÎºÎ¿Î¹Î½Î® λέξη και δεν συμπεÏιελήφθη στην αναζήτηση. Ο FtsEngineDriver δεν είναι διαθέσιμος! ΣιγουÏευθείτε ότι όλες οι λέξεις έχουν γÏαφεί κανονικά. Δεν βÏέθηκαν σελίδες που να πεÏιέχουν " Οι ακόλουθες λέξεις είναι Ï€Î¿Î»Ï ÎºÎ¿Î¹Î½Î­Ï‚ και δεν έχουν συμπεÏιληφθεί στην αναζήτηση σας: Συμβουλή: Στις πεÏισσότεÏες εφαÏμογές πλοήγησης μποÏείτε να πατήσετε το enter αντί να κάνετε κλικ στο κουμπί αναζήτησης. ΠÏοσπαθήστε με διάφοÏες λέξεις κλειδιά. ΠÏοσπαθήστε με πιο γενικές λέξεις κλειδιά. ΠÏοσπαθήστε την αναζήτηση σας στο: %stw;noquote% ΠÏέπει να οÏίσετε κάποιες λέξεις κλειδιά &nbsp;Display Επόμενο από τους τελευταίους 3 μήνες τους τελευταίους 6 μήνες τον τελευταίο χÏόνο ΠÏοηγοÏμενο Σελίδα αποτελεσμάτων: Αποτελέσματα αποτελέσματα Αναζήτηση Αναζήτηση αποτελεσμάτων για <strong>%query%</strong> δευτεÏόλεπτα. επιλεγμένο ΠÏοτάσεις: Το "<b>AND</b>" δεν χÏειάζεται - όλοι οι ÏŒÏοι έχουν ληφθεί υπόψη κατά την αναζήτηση. ΠÏοσπαθήστε με λιγότεÏες λέξεις κλειδιά. ΧωÏίς τίτλο openacs-5.7.0/packages/search/catalog/search.es_ES.ISO-8859-1.xml0000644000175000017500000000474011547562054023634 0ustar frankiefrankie . Búsqueda tardo Búsqueda Avanzada "búsqueda avanzada" cualquier hora Rango de Fechas detalles Introducir palabras a buscar Me siento afortunado "<b>%stopwords%</b>" es una palabra muy común y no ha sido tomada en cuenta para la búsqueda. ¡FtsEngineDriver no disponible! Asegúrese que todas las palabras estén escritas correctamente. No se ha encontrado páginas que contengan " Las palabras siguientes son demasiado comunes y no han sido incluidas en su búsqueda: Consejo: En la mayoría de los navegadores, puede pulsar la tecla Intro en lugar de pulsar el botón de búsqueda Inténtelo con otras palabras. Inténtelo con palabras más genéricas. Intente realizar la búsqueda sobre %stw;noquote% Debe especificar algunas palabras. &nbsp;Mostrar Siguiente de últimos 3 meses últimos 6 meses año anterior Anterior Página de resultados: Resultados resultados Buscar Búsquedas para: <b>%query%</b> segundos. seleccionado Sugerencias: El operador "<b>AND</b>" no es necesario -- por defecto, se incluyen todos los términos en la búsqueda. Inténtelo con más palabras. Sin título openacs-5.7.0/packages/search/catalog/search.cs_CZ.utf-8.xml0000644000175000017500000000334211055610261023360 0ustar frankiefrankie PokroÄilé hledání kdykoli Datové rozmezí podrobnosti Zkusím Å¡tÄ›stí "<b>%stopwords%</b>" je velmi běžné slovo a nebylo zahrnuto do vaÅ¡eho hledání FtsEngineDriver není dostupný! Ověřte korektní zápis vÅ¡ech slov Nebyly nalezené žádné stránky obsahující " Následující slova jsou velmi běžná a nebyla zahrnuta do vaÅ¡eho hledání Zkuste jiná klíÄová slova. Zkuste obecnÄ›jší klíÄová slova. Zkuste hledat na: %stw;noquote% Musíte zadat klíÄová slova Další poslední 3 mÄ›síce posledních 6 mÄ›síců poslední rok PÅ™edchozí Strana s výsledky: výsledky Hledat Hledaný výraz: %query% Návrhy: Zkuste ménÄ› klíÄových slov. Nepojmenováno openacs-5.7.0/packages/acs-authentication/0000755000175000017500000000000011724401450020332 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/lib/0000755000175000017500000000000011724401450021100 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/lib/local-search.adp0000755000175000017500000000007611061303766024136 0ustar frankiefrankie openacs-5.7.0/packages/acs-authentication/lib/local-search.tcl0000755000175000017500000000406411061303766024155 0ustar frankiefrankie# creation-date 2007-01-21 # author Dave Bauer (dave@solutiongrove.com) # includable search form # results should be appended to multirow called users # ADP level # default local authority search ad_form -name user-search -method GET -export {authority_id object_id} -form { {search_text:text(text),optional {label "Search"} } } -on_request { element set_value user-search search_text $search_text } -on_submit { } if {![info exists orderby]} { set orderby "" } set search_text [string tolower $search_text] set search_terms [list] foreach term [split $search_text] { lappend search_terms $term } set name_search "'()'" if {[llength $search_terms]} { set name_search "([join $search_terms |])" } set system_name [ad_system_name] db_foreach get_users " select first_names, last_name, email, username, user_id, authority_id from cc_users where ( lower(first_names) ~ :name_search or lower(last_name) ~ :name_search ) or lower(username) like '%' || :search_text || '%' or lower(email) like '%' || :search_text || '%' " { set status [list] if {[info exists object_id]} { set group_member_p [permission::permission_p -object_id $object_id -party_id $user_id -privilege $privilege] set status "" } else { set group_member_p [group::member_p -group_id $group_id -user_id $user_id -cascade] set group_name [group::get_element -element group_name -group_id $group_id] if {$group_member_p} { lappend status "[_ acs-authentication.Member_of_group_name]" } else { lappend status "[_ acs-authentication.Not_a_member_of_group_name]" } set status [join $status "
    "] } template::multirow -ulevel 2 -local append users $first_names $last_name $username $email $status $group_member_p "" "" "" $user_id $authority_id } set orderby_list [split $orderby ,] set orderby_column [lindex $orderby_list 0] set direction [lindex $orderby_list 1] set direction [string map {asc -increasing desc -decreasing} $direction] if {$orderby_column ne ""} { eval "template::multirow -ulevel 2 -local sort users $direction $orderby_column" }openacs-5.7.0/packages/acs-authentication/lib/search.adp0000755000175000017500000000432011061303766023042 0ustar frankiefrankie openacs-5.7.0/packages/acs-authentication/lib/search.tcl0000755000175000017500000001330711310023066023052 0ustar frankiefrankiead_page_contract { Includable page to search users in any authority To grant permission on an object Including page can pass in add_permisison (list of Label, URL) object_id privilege OR To add a member of a group add_to_subsite (list of label url) add_to_main_site (optional) (list of label url) group_id (optional default to subsite applicaiton group) rel_type (default to membership_rel) } { {search_text ""} {authority_id ""} orderby:optional } set authority_options [auth::authority::get_authority_options] set default_authority_id [lindex [lindex $authority_options 0] 1] if {$authority_id eq ""} { set authority_id $default_authority_id } if {![info exists rel_type] || $rel_type eq ""} { set rel_type membership_rel } if {![info exists package_id] || $package_id eq ""} { set package_id [ad_conn subsite_id] } if {![info exists return_url] || $return_url eq ""} { set return_url [ad_return_url] } set selected_authority_id $authority_id set bulk_actions [list] # we need a base url for adding a user to the site (main subsite or dotlrn, etc...) if {[info exists add_to_main_site]} { foreach elm $add_to_main_site { lappend bulk_actions $elm } } # we need a base url for adding a user to a specific community (subsite or dotlrn class instance etc...) (optional) if {[info exists add_to_subsite]} { foreach elm $add_to_subsite { lappend bulk_actions $elm } } if {[info exists add_to_subsite] && [llength $add_to_subsite]} { set add_user_url [lindex $add_to_subsite 1] set add_user_label [lindex $add_to_subsite 0] } elseif {[info exists add_to_main_site]} { set add_user_url [lindex $add_to_main_site 1] set add_user_label "[_ acs-authentication.Add_to_system_name [list system_name [ad_system_name]]]" } if {[info exists add_permission] && [llength $add_permission]} { set add_user_url [lindex $add_permission 1] set add_user_label [lindex $add_permission 0] lappend bulk_actions $add_user_label $add_user_url $add_user_label } if {![regexp {\?} $add_user_url]} { set add_user_url "${add_user_url}?" } if {![info exists group_id] || $group_id eq ""} { set group_id [application_group::group_id_from_package_id -package_id $package_id] } # generate authority links template::multirow create users first last username email auth_status group_member_p create_account_url actions extra_attributes user_id authority_id ns_log debug "MEMBER SEARCH TCL level='[template::adp_level]' [uplevel \#[template::adp_level] "info vars"]" template::list::create \ -no_data "Search returned no results" \ -name users \ -multirow users \ -key userkey \ -has_checkboxes \ -bulk_action_export_vars { authority_id return_url object_id group_id } \ -filters {search_text {} authority_id {} object_id {}} \ -elements [list \ checkbox { display_template {}} \ first [list label "First Name" link_url_eval "\[export_vars -base \"$member_url\" {user_id} \]"] \ last [list label "Last Name" link_url_eval "\[export_vars -base \"$member_url\" {user_id} \]"] \ username [list label "Username" link_url_eval "\[export_vars -base \"$member_url\" {user_id} \]"] \ email {label "Email"} \ auth_status { label "Status" } \ actions [list label "Actions" display_template "$add_user_label"] \ extra_attributes {label "Extra Attributes"} \ user_id [list hide_p [expr {!$admin_p}] label "" display_template "User Admin Page"] \ ] -bulk_actions $bulk_actions \ -orderby {first {orderby first_names} last {orderby last_name} username {orderby username} email {orderby email} auth_status {orderby auth_status}} template::multirow create authorities authority_id pretty_name local_authority_p search_url form_include foreach option_list [auth::authority::get_authority_options] { set this_authority_id [lindex $option_list 1] set local_authority_p [string match $this_authority_id [auth::authority::local]] if {$local_authority_p} { set local_authority_id $this_authority_id set form_include /packages/acs-authentication/lib/local-search } else { set form_include [acs_sc::invoke -impl_id [auth::authority::get_element -authority_id $this_authority_id -element search_impl_id] -operation FormInclude] } if {$this_authority_id eq $selected_authority_id} { set selected_form_include $form_include } template::multirow append authorities $this_authority_id [lindex $option_list 0] $local_authority_p [export_vars -base [ad_conn url] -no_empty {{authority_id $this_authority_id} search_text object_id}] $form_include } #template::multirow sort authorities -decreasing authority_id if {$selected_authority_id eq ""} { set selected_authority_id $default_authority_id } set authority_id $selected_authority_id #set search_form_html [template::adp_include $selected_form_include [list authority_id $selected_authority_id search_text $search_text return_url $return_url orderby $orderby]] # if {![info exists orderby]} { set orderby "" }openacs-5.7.0/packages/acs-authentication/tcl/0000755000175000017500000000000011724401450021114 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/tcl/test/0000755000175000017500000000000011575225402022100 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/tcl/test/sync-test-procs.tcl0000644000175000017500000011061410551254371025664 0ustar frankiefrankiead_library { Automated tests for synchronization API @author Lars Pind (lars@collaboraid.biz) @creation-date 05 September 2003 @cvs-id $Id: sync-test-procs.tcl,v 1.19 2007/01/10 21:22:01 gustafn Exp $ } aa_register_case -cats {api db} sync_start_end { Test batch job basics: Starting, getting document, adding entries, ending. } { aa_run_with_teardown \ -rollback \ -test_code { # Start non-interactive job set job_id [auth::sync::job::start \ -authority_id [auth::authority::local]] aa_true "Returns a job_id" [exists_and_not_null job_id] # Get doc auth::sync::job::start_get_document -job_id $job_id auth::sync::job::end_get_document \ -job_id $job_id \ -doc_status "ok" \ -doc_message "" \ -document {} # Valid successful log entry auth::sync::job::create_entry \ -job_id $job_id \ -operation "insert" \ -username "foobar" \ -user_id [ad_conn user_id] \ -success # Valid unsuccessful log entry auth::sync::job::create_entry \ -job_id $job_id \ -operation "insert" \ -username "foobar" \ -user_id [ad_conn user_id] \ -message "A problem" \ -element_messages "" # End job array set job [auth::sync::job::end -job_id $job_id] aa_true "Elapsed time less than 30 seconds" [expr {$job(run_time_seconds) < 30}] aa_log "Elapsed time: $job(run_time_seconds) seconds" aa_false "Not interactive" [template::util::is_true $job(interactive_p)] aa_equals "Number of actions" $job(num_actions) 2 aa_equals "Number of problems" $job(num_problems) 1 aa_false "Log URL non-empty" [expr {$job(log_url) eq ""}] # Purge not deleting the job auth::sync::purge_jobs \ -num_days 1 aa_equals "Job still exists" [db_string job_exists_p { select count(*) from auth_batch_job_entries where job_id = :job_id }] 2 # Tricking it into deleting the job aa_log "Updating the job end time" db_dml update_job { update auth_batch_jobs set job_end_time = to_date('1974-03-27', 'YYYY-MM-DD') where job_id = :job_id } auth::sync::purge_jobs \ -num_days 1 aa_equals "Job has been purged" [db_string job_exists_p { select count(*) from auth_batch_job_entries where job_id = :job_id }] 0 } } aa_register_case -cats {api} sync_actions { Test job actions: insert, update, } { aa_run_with_teardown \ -rollback \ -test_code { # Start non-interactive job set job_id [auth::sync::job::start \ -authority_id [auth::authority::local]] aa_true "Returns a job_id" [exists_and_not_null job_id] ##### # # Valid insert action # ##### array unset user_info set username1 [ad_generate_random_string] set email1 "[ad_generate_random_string]@foo.bar" set screen_name1 [ad_generate_random_string] set user_info(email) $email1 set user_info(first_names) [ad_generate_random_string] set user_info(last_name) [ad_generate_random_string] set user_info(url) "http://[ad_generate_random_string].com" set user_info(screen_name) $screen_name1 aa_log "--- Valid insert --- auth::sync::job::action -opration insert -username $username1 -email $email1" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "insert" \ -username $username1 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "t" aa_equals "entry.message" $entry(message) {} aa_equals "entry.element_messages" $entry(element_messages) {} aa_log "entry.user_id = '$entry(user_id)'" aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" if { [aa_true "Entry has user_id set" [exists_and_not_null entry(user_id)]] } { array unset user acs_user::get -user_id $entry(user_id) -array user aa_equals "user.first_names" $user(first_names) $user_info(first_names) aa_equals "user.last_name" $user(last_name) $user_info(last_name) aa_equals "user.email" $user(email) [string tolower $email1] aa_equals "user.authority_id" $user(authority_id) [auth::authority::local] aa_equals "user.username" $user(username) $username1 aa_equals "user.url" $user(url) $user_info(url) aa_equals "user.screen_name" $user(screen_name) $user_info(screen_name) } ##### # # Invalid insert action: Reusing username, email # ##### aa_log "--- Invalid insert: reusing username, email --- auth::sync::job::action -opration insert -username $username1 -email $email1" array unset user_info set user_info(first_names) [ad_generate_random_string] set user_info(last_name) [ad_generate_random_string] set user_info(email) $email1 set user_info(url) "http://" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "insert" \ -username $username1 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "f" aa_true "entry.message not empty" [exists_and_not_null entry(message)] aa_log "entry.user_id = '$entry(user_id)'" aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" ##### # # Valid update action # ##### set email2 "[ad_generate_random_string]@foo.bar" array unset user_info set user_info(first_names) [ad_generate_random_string] set user_info(last_name) [ad_generate_random_string] set user_info(url) "http://[ad_generate_random_string].com" set user_info(email) $email2 aa_log "--- Valid update --- auth::sync::job::action -opration update -username $username1" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "update" \ -username $username1 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "t" aa_equals "entry.message" $entry(message) {} aa_equals "entry.element_messages" $entry(element_messages) {} aa_log "entry.user_id = '$entry(user_id)'" aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" if { [aa_true "Entry has user_id set" [exists_and_not_null entry(user_id)]] } { array unset user acs_user::get -user_id $entry(user_id) -array user aa_equals "user.first_names" $user(first_names) $user_info(first_names) aa_equals "user.last_name" $user(last_name) $user_info(last_name) aa_equals "user.email" $user(email) [string tolower $email2] aa_equals "user.authority_id" $user(authority_id) [auth::authority::local] aa_equals "user.username" $user(username) $username1 aa_equals "user.url" $user(url) $user_info(url) } ##### # # Valid update action, not changing any columns # ##### # copy the old user_info array array set user_info2 [array get user_info] array unset user_info aa_log "--- Valid update, no changes --- auth::sync::job::action -opration update -username $username1" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "update" \ -username $username1 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "t" aa_equals "entry.message" $entry(message) {} aa_equals "entry.element_messages" $entry(element_messages) {} aa_log "entry.user_id = '$entry(user_id)'" aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" if { [aa_true "Entry has user_id set" [exists_and_not_null entry(user_id)]] } { array unset user acs_user::get -user_id $entry(user_id) -array user aa_equals "user.first_names" $user(first_names) $user_info2(first_names) aa_equals "user.last_name" $user(last_name) $user_info2(last_name) aa_equals "user.email" $user(email) $user_info2(email) aa_equals "user.authority_id" $user(authority_id) [auth::authority::local] aa_equals "user.username" $user(username) $username1 aa_equals "user.url" $user(url) $user_info2(url) } ##### # # Invalid insert action: Missing first_names, last_name invalid, email, url invalid # ##### set username2 [ad_generate_random_string] array unset user_info set user_info(last_name) {Foobar} set user_info(email) "not_an_email" set user_info(url) "NotAURL" aa_log "--- Invalid insert --- auth::sync::job::action -opration update -username $username2" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "insert" \ -username $username2 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "f" aa_log "entry.message = '$entry(message)'" if { [aa_true "entry.element_messages not empty" [exists_and_not_null entry(element_messages)]] } { aa_log "entry.element_messages = '$entry(element_messages)'" array unset elm_msgs array set elm_msgs $entry(element_messages) aa_log "array names elm_msgs = '[array names elm_msgs]'" aa_true "first_names, last_name, email, url have problems" [util_sets_equal_p { first_names last_name email url } [array names elm_msgs]] } ##### # # Valid delete action # ##### aa_log "--- Valid delete --- auth::sync::job::action -opration delete -username $username1" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "delete" \ -username $username1] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "t" aa_log "entry.message = '$entry(message)'" if { [aa_true "Entry has user_id set" [exists_and_not_null entry(user_id)]] } { array unset user acs_user::get -user_id $entry(user_id) -array user aa_equals "User member state is banned" $user(member_state) "banned" } ##### # # End job # ##### array set job [auth::sync::job::end -job_id $job_id] aa_true "Elapsed time less than 30 seconds" [expr {$job(run_time_seconds) < 30}] aa_false "Not interactive" [template::util::is_true $job(interactive_p)] aa_equals "Number of actions" $job(num_actions) 6 aa_equals "Number of problems" $job(num_problems) 2 aa_false "Log URL non-empty" [expr {$job(log_url) eq ""}] } } aa_register_case -cats {api db} sync_snapshot { Test a snapshot job } { aa_run_with_teardown \ -rollback \ -test_code { # Start non-interactive job set job_id [auth::sync::job::start \ -authority_id [auth::authority::local]] aa_true "Returns a job_id" [exists_and_not_null job_id] ##### # # Valid insert action # ##### set username1 [ad_generate_random_string] set email1 "[ad_generate_random_string]@foo.bar" array unset user_info set user_info(email) $email1 set user_info(first_names) [ad_generate_random_string] set user_info(last_name) [ad_generate_random_string] set user_info(url) "http://[ad_generate_random_string].com" aa_log "--- Valid insert --- auth::sync::job::action -opration insert -username $username1 -email $email1" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "snapshot" \ -username $username1 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "t" aa_equals "entry.message" $entry(message) {} aa_equals "entry.element_messages" $entry(element_messages) {} aa_equals "entry.operation" $entry(operation) "insert" aa_log "entry.user_id = '$entry(user_id)'" aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" if { [aa_true "Entry has user_id set" [exists_and_not_null entry(user_id)]] } { array unset user acs_user::get -user_id $entry(user_id) -array user aa_equals "user.first_names" $user(first_names) $user_info(first_names) aa_equals "user.last_name" $user(last_name) $user_info(last_name) aa_equals "user.email" $user(email) [string tolower $email1] aa_equals "user.authority_id" $user(authority_id) [auth::authority::local] aa_equals "user.username" $user(username) $username1 aa_equals "user.url" $user(url) $user_info(url) } ##### # # Valid update action # ##### array unset user_info set user_info(email) "[ad_generate_random_string]@foo.bar" set user_info(first_names) [ad_generate_random_string] set user_info(last_name) [ad_generate_random_string] set user_info(url) "http://[ad_generate_random_string].com" aa_log "--- Valid update --- auth::sync::job::action -opration update -username $username1" set entry_id [auth::sync::job::action \ -job_id $job_id \ -operation "snapshot" \ -username $username1 \ -array user_info] array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_equals "entry.success_p" $entry(success_p) "t" aa_equals "entry.message" $entry(message) {} aa_equals "entry.element_messages" $entry(element_messages) {} aa_equals "entry.operation" $entry(operation) "update" aa_log "entry.user_id = '$entry(user_id)'" aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" if { [aa_true "Entry has user_id set" [exists_and_not_null entry(user_id)]] } { array unset user acs_user::get -user_id $entry(user_id) -array user aa_equals "user.first_names" $user(first_names) $user_info(first_names) aa_equals "user.last_name" $user(last_name) $user_info(last_name) aa_equals "user.email" $user(email) [string tolower $user_info(email)] aa_equals "user.authority_id" $user(authority_id) [auth::authority::local] aa_equals "user.username" $user(username) $username1 aa_equals "user.url" $user(url) $user_info(url) } ##### # # Wrap up batch sync job # ##### # We need this number to check the counts below set authority_id [auth::authority::local] set num_users_not_banned [db_string select_num { select count(*) from cc_users where authority_id = :authority_id and member_state != 'banned' }] auth::sync::job::snapshot_delete_remaining \ -job_id $job_id ##### # # End job # ##### array set job [auth::sync::job::end -job_id $job_id] aa_true "Elapsed time less than 30 seconds" [expr {$job(run_time_seconds) < 30}] aa_false "Not interactive" [template::util::is_true $job(interactive_p)] aa_equals "Number of actions" $job(num_actions) [expr {$num_users_not_banned + 1}] aa_equals "Number of problems" $job(num_problems) 0 aa_false "Log URL non-empty" [expr {$job(log_url) eq ""}] } } aa_register_case -cats {api smoke} sync_batch_for_local { Test a batch job for the local authority } { aa_run_with_teardown \ -rollback \ -test_code { set job_id [auth::authority::batch_sync -authority_id [auth::authority::local]] auth::sync::job::get -job_id $job_id -array job aa_log "job.message = '$job(message)'" aa_true "job.message not empty when called for local authority" [exists_and_not_null job(message)] } } aa_register_case -cats {api} sync_batch_ims_example_doc { Test IMS Enterprise 1.1 batch sync with the XML document from the specification. } { aa_stub acs_sc::invoke { acs_sc::invoke__arg_parser if { $contract eq "auth_sync_retrieve" && $operation eq "GetDocument" } { array set result { doc_status ok doc_message {} document {} snapshot_p f } # Example document grabbed pulled from # http://www.imsglobal.org/enterprise/entv1p1/imsent_bestv1p1.html#1404584 set result(document) { Dunelm Services Limited Telecommunications LMS DATABASE UPDATE 2001-08-08 Add a new Person record. Dunelm Services Limited CK1 Clark Kent Kent, C Superman 2 The Daily Planet Metropolis USA Update a previously created record. Dunelm Services Limited CS1 Colin Smythe Smythe, C Colin Smythe Colin Manfred Wingarde Dr. C.Eng C.M.W. 2 1958-02-18 None. colin@dunelm.com http://www.dunelm.com 4477932335019 Dunelm Services Limited 34 Acorn Drive Stannington Sheffield S.Yorks S7 6WA UK http://www.dunelm.com/staff/colin2.gif dunelm:colinsmythe:1 Delete this record. Dunelm Services Limited LL1 Lois Lane Lane, L } return [array get result] } else { acs_sc::invoke_unstubbed \ -contract $contract \ -operation $operation \ -impl $impl \ -impl_id $impl_id \ -call_args $call_args \ -error=$error_p } } aa_run_with_teardown \ -rollback \ -test_code { # Create a new dummy authority with the dummy IMS get-document driver and the IMS Enterprise 1.1 process driver. array set new_auth { short_name dummy-test pretty_name dummy-test enabled_p t sort_order 999 auth_impl_id {} pwd_impl_id {} forgotten_pwd_url {} change_pwd_url {} register_impl_id {} register_url {} help_contact_text {} batch_sync_enabled_p f } set new_auth(get_doc_impl_id) 1 set new_auth(process_doc_impl_id) [acs_sc::impl::get_id -owner "acs-authentication" -name "IMS_Enterprise_v_1p1"] set new_auth(get_doc_impl_id) [acs_sc::impl::get_id -owner "acs-authentication" -name "HTTPGet"] set authority_id [auth::authority::create \ -array new_auth] set job_id [auth::authority::batch_sync -authority_id $authority_id] auth::sync::job::get -job_id $job_id -array job aa_equals "Number of actions" $job(num_actions) 3 aa_equals "Number of problems" $job(num_problems) 3 foreach entry_id [auth::sync::job::get_entries -job_id $job_id] { array unset entry auth::sync::job::get_entry \ -entry_id $entry_id \ -array entry aa_false "Success_p is false" [template::util::is_true $entry(success_p)] array unset elm_msgs array set elm_msgs $entry(element_messages) aa_log "entry.operation = '$entry(operation)'" aa_log "entry.username = '$entry(username)'" aa_log "entry.message = '$entry(message)'" aa_log "array names elm_msgs = '[array names elm_msgs]'" switch $entry(operation) { insert { aa_true "email has a problem (email missing)" [util_sets_equal_p { email } [array names elm_msgs]] } update { aa_true "User does not exist" [expr {$entry(message) ne ""}] } delete { aa_false "Message is not empty" [expr {$entry(message) eq ""}] } } } aa_log "job.message = '$job(message)'" } } aa_register_case -cats {api} sync_batch_ims_test { Test IMS Enterprise 1.1 batch sync with a constructed document which actually works } { aa_stub acs_sc::invoke { acs_sc::invoke__arg_parser if { $contract eq "auth_sync_retrieve" && $operation eq "GetDocument" } { array set result { doc_status ok doc_message {} document {} } global ims_doc set result(document) " $ims_doc(username) $ims_doc(first_names) $ims_doc(last_name) $ims_doc(first_names) $ims_doc(last_name) $ims_doc(email) $ims_doc(url) " return [array get result] } else { acs_sc::invoke_unstubbed \ -contract $contract \ -operation $operation \ -impl $impl \ -impl_id $impl_id \ -call_args $call_args \ -error=$error_p } } aa_run_with_teardown \ -rollback \ -test_code { # Create a new dummy authority with the dummy IMS get-document driver and the IMS Enterprise 1.1 process driver. array set new_auth { short_name dummy-test pretty_name dummy-test enabled_p t sort_order 999 auth_impl_id {} pwd_impl_id {} forgotten_pwd_url {} change_pwd_url {} register_impl_id {} register_url {} help_contact_text {} batch_sync_enabled_p f } set new_auth(process_doc_impl_id) [acs_sc::impl::get_id -owner "acs-authentication" -name "IMS_Enterprise_v_1p1"] set new_auth(get_doc_impl_id) [acs_sc::impl::get_id -owner "acs-authentication" -name "HTTPGet"] set authority_id [auth::authority::create \ -array new_auth] global ims_doc ##### # # Insert # ##### aa_log "--- Insert test ---" # Setup dummy variables set ims_doc(recstatus) 1 set ims_doc(username) [ad_generate_random_string] set ims_doc(first_names) [ad_generate_random_string] set ims_doc(last_name) [ad_generate_random_string] set ims_doc(email) [string tolower "[ad_generate_random_string]@foo.bar"] set ims_doc(url) "http://www.[ad_generate_random_string].com" set job_id [auth::authority::batch_sync -authority_id $authority_id] auth::sync::job::get -job_id $job_id -array job aa_equals "Number of actions" $job(num_actions) 1 aa_equals "Number of problems" $job(num_problems) 0 aa_log "job.message = '$job(message)'" set entry_id [auth::sync::job::get_entries -job_id $job_id] aa_equals "One entry" [llength $entry_id] 1 array unset entry auth::sync::job::get_entry -entry_id $entry_id -array entry aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" array unset user acs_user::get -user_id $entry(user_id) -array user foreach varname { username first_names last_name email url } { aa_equals "$varname" $user($varname) $ims_doc($varname) } aa_equals "authority_id" $user(authority_id) $authority_id aa_false "member_state not banned" [string equal $user(member_state) "banned"] # saving this for later set first_user_id $entry(user_id) ##### # # Update # ##### aa_log "--- Update test ---" # Setup dummy variables set ims_doc(recstatus) 2 # username is unchanged set ims_doc(first_names) [ad_generate_random_string] set ims_doc(last_name) [ad_generate_random_string] set ims_doc(email) [string tolower "[ad_generate_random_string]@foo.bar"] set ims_doc(url) "http://www.[ad_generate_random_string].com" set job_id [auth::authority::batch_sync -authority_id $authority_id] auth::sync::job::get -job_id $job_id -array job aa_equals "Number of actions" $job(num_actions) 1 aa_equals "Number of problems" $job(num_problems) 0 aa_log "job.message = '$job(message)'" set entry_id [auth::sync::job::get_entries -job_id $job_id] aa_equals "One entry" [llength $entry_id] 1 array unset entry auth::sync::job::get_entry -entry_id $entry_id -array entry aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" array unset user acs_user::get -user_id $entry(user_id) -array user foreach varname { username first_names last_name email url } { aa_equals "$varname" $user($varname) $ims_doc($varname) } aa_false "member_state not banned" [string equal $user(member_state) "banned"] ##### # # Delete # ##### aa_log "--- Delete test ---" # Setup dummy variables set ims_doc(recstatus) 3 # username is unchanged set ims_doc(first_names) [ad_generate_random_string] set ims_doc(last_name) [ad_generate_random_string] # email is unchanged set ims_doc(url) "http://www.[ad_generate_random_string].com" set job_id [auth::authority::batch_sync -authority_id $authority_id] auth::sync::job::get -job_id $job_id -array job aa_equals "Number of actions" $job(num_actions) 1 aa_equals "Number of problems" $job(num_problems) 0 aa_log "job.message = '$job(message)'" set entry_id [auth::sync::job::get_entries -job_id $job_id] aa_equals "One entry" [llength $entry_id] 1 array unset entry auth::sync::job::get_entry -entry_id $entry_id -array entry aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" array unset user acs_user::get -user_id $entry(user_id) -array user foreach varname { username } { aa_equals "$varname" $user($varname) $ims_doc($varname) } aa_equals "member_state" $user(member_state) "banned" ##### # # Reuse username and email # ##### aa_log "--- Reuse username/email of a deleted user test ---" # Setup dummy variables set ims_doc(recstatus) 1 # same username set ims_doc(first_names) [ad_generate_random_string] set ims_doc(last_name) [ad_generate_random_string] # same email set ims_doc(url) "http://www.[ad_generate_random_string].com" set job_id [auth::authority::batch_sync -authority_id $authority_id] auth::sync::job::get -job_id $job_id -array job aa_equals "Number of actions" $job(num_actions) 1 aa_equals "Number of problems" $job(num_problems) 0 aa_log "job.message = '$job(message)'" set entry_id [auth::sync::job::get_entries -job_id $job_id] aa_equals "One entry" [llength $entry_id] 1 array unset entry auth::sync::job::get_entry -entry_id $entry_id -array entry aa_log "entry.message = '$entry(message)'" aa_log "entry.element_messages = '$entry(element_messages)'" array unset user acs_user::get -user_id $entry(user_id) -array user foreach varname { username first_names last_name email url } { aa_equals "$varname" $user($varname) $ims_doc($varname) } aa_equals "authority_id" $user(authority_id) $authority_id aa_false "member_state not banned" [string equal $user(member_state) "banned"] # Check that first_user_id has had username/email changed ##### # # Test GetElements # ##### aa_log "--- GetElements test ---" set desired_elements [ad_generate_random_string] auth::driver::set_parameter_value \ -authority_id $authority_id \ -impl_id [acs_sc::impl::get_id -owner "acs-authentication" -name "IMS_Enterprise_v_1p1"] \ -parameter Elements \ -value $desired_elements set elements [auth::sync::GetElements -authority_id $authority_id] aa_equals "Elements are '$desired_elements'" $elements $desired_elements } } aa_register_case -cats {api smoke} sync_http_get_document { Test the HTTPGet implementation of GetDocument service contract. } { array set result [acs_sc::invoke \ -error \ -contract "auth_sync_retrieve" \ -impl "HTTPGet" \ -operation "GetDocument" \ -call_args [list [list SnapshotURL {} IncrementalURL "[ad_url]/SYSTEM/dbtest.tcl"]]] aa_equals "result.doc_status is ok" $result(doc_status) "ok" aa_true "result.doc_message is empty" [expr {$result(doc_message) eq ""}] aa_equals "result.document is 'success'" $result(document) "success" } aa_register_case -cats {api web} sync_file_get_document { Test the HTTPGet implementation of GetDocument service contract. } { set path "[acs_root_dir]/www/SYSTEM/dbtest.tcl" aa_log "Getting path '$path'" array set result [acs_sc::invoke \ -error \ -contract "auth_sync_retrieve" \ -impl "LocalFilesystem" \ -operation "GetDocument" \ -call_args [list [list SnapshotPath {} IncrementalPath $path]]] aa_equals "result.doc_status is ok" $result(doc_status) "ok" aa_true "result.doc_message is empty" [expr {$result(doc_message) eq ""}] aa_equals "result.document is 'success'" $result(document) [template::util::read_file $path] } openacs-5.7.0/packages/acs-authentication/tcl/test/acs-authentication-procs-oracle.xql0000644000175000017500000000153607723667655031031 0ustar frankiefrankie oracle8.1.6 select q.user_id from (select user_id from users where acs_permission.permission_p(:context_root_id, user_id, 'admin') = 't') q where rownum = 1 select q.* from (select u.user_id, aa.authority_id, u.username from users u, auth_authorities aa where u.authority_id = aa.authority_id and aa.short_name = 'local') q where rownum = 1 openacs-5.7.0/packages/acs-authentication/tcl/test/acs-authentication-procs.tcl0000644000175000017500000010065211144343374027520 0ustar frankiefrankiead_library { Automated tests. @author Peter Marklund @creation-date 21 August 2003 @cvs-id $Id: acs-authentication-procs.tcl,v 1.42 2009/02/10 18:27:08 jeffd Exp $ } aa_register_case \ -cats {api}\ auth_authenticate { Test the auth::authenticate proc. } { # Initialize variables set username "auth_create_user1" set password "changeme" aa_run_with_teardown \ -rollback \ -test_code { array set result [auth::create_user \ -username $username \ -email "auth_create_user1@test_user.com" \ -first_names "Test" \ -last_name "User" \ -password $password \ -secret_question "no_question" \ -secret_answer "no_answer"] if { ![aa_equals "creation_status for successful creation" $result(creation_status) "ok"] } { aa_log "Creation result: [array get result]" } set user_id [acs_user::get_by_username -username $username] # Successful authentication array unset result array set result [auth::authenticate \ -no_cookie \ -username $username \ -password $password] aa_log "Result: [array get result]" aa_equals "auth_status for successful authentication" $result(auth_status) "ok" # Failed authentications # Incorrect password array unset auth_info array set auth_info \ [auth::authenticate \ -no_cookie \ -username $username \ -password "blabla"] aa_equals "auth_status for bad password authentication" $auth_info(auth_status) "bad_password" aa_true "auth_message for bad password authentication" [expr {$auth_info(auth_message) ne ""}] # Blank password array unset auth_info array set auth_info \ [auth::authenticate \ -no_cookie \ -username $username \ -password ""] aa_equals "auth_status for blank password authentication" $auth_info(auth_status) "bad_password" aa_true "auth_message for blank password authentication" [expr {$auth_info(auth_message) ne ""}] # Incorrect username array unset auth_info array set auth_info \ [auth::authenticate \ -no_cookie \ -username "blabla" \ -password $password] aa_equals "auth_status for bad username authentication" $auth_info(auth_status) "no_account" aa_true "auth_message for bad username authentication" [expr {$auth_info(auth_message) ne ""}] # Blank username array unset auth_info array set auth_info \ [auth::authenticate \ -no_cookie \ -username "" \ -password $password] aa_equals "auth_status for blank username authentication" $auth_info(auth_status) "auth_error" aa_true "auth_message for blank username authentication" [expr {$auth_info(auth_message) ne ""}] # Authority bogus array unset auth_info array set auth_info \ [auth::authenticate \ -no_cookie \ -authority_id -123 \ -username $username \ -password $password] aa_equals "auth_status for bad authority_id authentication" $auth_info(auth_status) "failed_to_connect" aa_true "auth_message for bad authority_id authentication" [expr {$auth_info(auth_message) ne ""}] # Closed account status set closed_states {banned rejected "needs approval" deleted} foreach closed_state $closed_states { acs_user::change_state -user_id $user_id -state $closed_state # Successful authentication array unset auth_info array set auth_info \ [auth::authenticate \ -no_cookie \ -username $username \ -password $password] aa_equals "auth_status for '$closed_state' user" $auth_info(auth_status) "ok" if {$auth_info(auth_status) eq "ok"} { # Only perform this test if auth_status is ok, otherwise account_status won't be set aa_equals "account_status for '$closed_state' user" $auth_info(account_status) "closed" } } if { $user_id ne "" } { acs_user::delete -user_id $user_id } # Error handling # TODO or too hard? } } aa_register_case \ -cats {api} \ auth_create_user { Test the auth::create_user proc. } { # create_user returns ok when trying to create a user # whose email already lives in the db. We should test # against that aa_run_with_teardown \ -rollback \ -test_code { # Successful creation array set user_info [auth::create_user \ -username "auth_create_user1" \ -email "auth_create_user1@test_user.com" \ -first_names "Test" \ -last_name "User" \ -password "changeme" \ -secret_question "no_question" \ -secret_answer "no_answer"] aa_true "returns creation_status" [info exists user_info(creation_status)] if { [info exists user_info(creation_status)] } { aa_equals "creation_status for successful creation" $user_info(creation_status) "ok" if { $user_info(creation_status) ne "ok" } { aa_log "Element messages: '$user_info(element_messages)'" aa_log "Element messages: '$user_info(creation_message)'" } } aa_false "No creation_message for successful creation" [exists_and_not_null user_info(creation_message)] aa_true "returns user_id" [info exists user_info(user_id)] if { [info exists user_info(user_id)] } { aa_true "returns integer user_id ([array get user_info])" [regexp {[1-9][0-9]*} $user_info(user_id)] } # Duplicate email and username array unset user_info array set user_info [auth::create_user \ -username "auth_create_user1" \ -email "auth_create_user1@test_user.com" \ -first_names "Test3" \ -last_name "User" \ -password "changeme" \ -secret_question "no_question" \ -secret_answer "no_answer"] aa_equals "creation_status for duplicate email and username" $user_info(creation_status) "data_error" aa_true "element_messages exists" [exists_and_not_null user_info(element_messages)] if { [exists_and_not_null user_info(element_messages)] } { array unset elm_msgs array set elm_msgs $user_info(element_messages) aa_true "element_message for username exists" [exists_and_not_null elm_msgs(username)] aa_true "element_message for email exists" [exists_and_not_null elm_msgs(email)] } set user_id [acs_user::get_by_username -username auth_create_user1] if { $user_id ne "" } { acs_user::delete -user_id $user_id } # Missing first_names, last_name, email array unset user_info array set user_info [auth::create_user \ -username "auth_create_user2" \ -email "" \ -first_names "" \ -last_name "" \ -password "changeme" \ -secret_question "no_question" \ -secret_answer "no_answer"] aa_equals "creation_status is data_error" $user_info(creation_status) "data_error" aa_true "element_messages exists" [exists_and_not_null user_info(element_messages)] if { [exists_and_not_null user_info(element_messages)] } { array unset elm_msgs array set elm_msgs $user_info(element_messages) if { [aa_true "element_message(email) exists" [exists_and_not_null elm_msgs(email)]] } { aa_log "element_message(email) = $elm_msgs(email)" } if { [aa_true "element_message(first_names) exists" [exists_and_not_null elm_msgs(first_names)]] } { aa_log "element_message(first_names) = $elm_msgs(first_names)" } if { [aa_true "element_message(last_name) exists" [exists_and_not_null elm_msgs(last_name)]] } { aa_log "element_message(last_name) = $elm_msgs(last_name)" } } set user_id [acs_user::get_by_username -username auth_create_user2] if { $user_id ne "" } { acs_user::delete -user_id $user_id } # Malformed email array unset user_info array set user_info [auth::create_user \ -username [ad_generate_random_string] \ -email "not an email" \ -first_names "[ad_generate_random_string]<[ad_generate_random_string]" \ -last_name "[ad_generate_random_string]<[ad_generate_random_string]" \ -password [ad_generate_random_string] \ -secret_question [ad_generate_random_string] \ -secret_answer [ad_generate_random_string]] aa_equals "creation_status is data_error" $user_info(creation_status) "data_error" aa_true "element_messages exists" [exists_and_not_null user_info(element_messages)] if { [exists_and_not_null user_info(element_messages)] } { array unset elm_msgs array set elm_msgs $user_info(element_messages) if { [aa_true "element_message(email) exists" [exists_and_not_null elm_msgs(email)]] } { aa_log "element_message(email) = $elm_msgs(email)" } if { [aa_true "element_message(first_names) exists" [exists_and_not_null elm_msgs(first_names)]] } { aa_log "element_message(first_names) = $elm_msgs(first_names)" } if { [aa_true "element_message(last_name) exists" [exists_and_not_null elm_msgs(last_name)]] } { aa_log "element_message(last_name) = $elm_msgs(last_name)" } } } } aa_register_case \ -cats {db api smoke} \ auth_confirm_email { Test the auth::set_email_verified proc. } { set user_id [ad_conn user_id] aa_run_with_teardown \ -rollback \ -test_code { db_dml update { update users set email_verified_p = 'f' where user_id = :user_id } acs_user::flush_cache -user_id $user_id aa_equals "email should be not verified" [acs_user::get_element -user_id $user_id -element email_verified_p] "f" auth::set_email_verified -user_id $user_id aa_equals "email should be verified" [acs_user::get_element -user_id $user_id -element email_verified_p] "t" acs_user::flush_cache -user_id $user_id } } aa_register_case \ -cats {api smoke} \ -error_level {warning} \ auth_get_registration_elements { Test the auth::get_registration_elements proc } { array set element_array [auth::get_registration_elements] aa_log "Elements array: '[array get element_array]'" aa_true "there is more than one required element" [expr {[llength $element_array(required)] > 0}] aa_true "there is more than one optional element" [expr {[llength $element_array(optional)] > 0}] } aa_register_case \ -cats {api smoke} \ -error_level {warning} \ auth_get_registration_form_elements { Test the auth::get_registration_form_elements proc } { set form_elements [auth::get_registration_form_elements] aa_true "Form elements are not empty: $form_elements" [expr {$form_elements ne ""}] } ########### # # Password API # ########### aa_register_case \ -cats {api smoke} \ auth_password_get_change_url { Test the auth::password::get_change_url proc. } { # Test whether auth::password::get_change_url returns the correct URL to redirect when "change_pwd_url" is set. auth::test::get_password_vars -array_name test_vars if { [info exists test_vars(user_id)] } { set change_pwd_url [auth::password::get_change_url -user_id $test_vars(user_id)] aa_true "Check that auth::password::get_change_url returns correct redirect URL when change_pwd_url is not null" \ [regexp {password-update} $change_pwd_url] } } aa_register_case \ -cats {api smoke} \ -error_level {warning} \ auth_password_can_change_p { Test the auth::password::can_change_p proc. } { auth::test::get_password_vars -array_name test_vars aa_equals "Should return 1 when CanChangePassword is true for the local driver " \ [auth::password::can_change_p -user_id $test_vars(user_id)] \ "1" } aa_register_case \ -cats {api} \ auth_password_change { Test the auth::password::change proc. } { aa_stub acs_mail_lite::send { acs_mail_lite::send__arg_parser global ns_sendmail_to set ns_sendmail_to $to_addr } aa_run_with_teardown \ -rollback \ -test_code { # create user we'll use for testing set email "test2@user.com" array set user_info [auth::create_user \ -email $email \ -first_names "Test" \ -last_name "User" \ -password "changeme" \ -secret_question "no_question" \ -secret_answer "no_answer"] set user_id $user_info(user_id) global ns_sendmail_to set ns_sendmail_to {ns_sendmail_UNCALLED} parameter::set_value -parameter EmailAccountOwnerOnPasswordChangeP -package_id [ad_acs_kernel_id] -value 1 aa_true "Send email" [parameter::get -parameter EmailAccountOwnerOnPasswordChangeP -package_id [ad_acs_kernel_id] -default 1] # password_status "ok" set old_password "changeme" set new_password "changedyou" array set auth_info [auth::password::change \ -user_id $user_id \ -old_password $old_password \ -new_password $new_password] aa_equals "Should return 'ok'" \ $auth_info(password_status) \ "ok" # Check that user gets email about changed password aa_equals "Email sent to user" $ns_sendmail_to $email set ns_sendmail_to {} # check that the new password is actually set correctly set password_correct_p [ad_check_password $user_id $new_password] aa_equals "check that the new password is actually set correctly" \ $password_correct_p \ "1" ad_parameter_cache -delete [ad_acs_kernel_id] EmailAccountOwnerOnPasswordChangeP if { $user_id ne "" } { acs_user::delete -user_id $user_id } } } aa_register_case \ -cats {api smoke} \ auth_password_recover { Test the auth::password::recover_password proc. } { auth::test::get_password_vars -array_name test_vars # Stub get_forgotten_url to avoid the redirect aa_stub auth::password::get_forgotten_url { return "" } # We don't want email to go out aa_stub auth::password::email_password { return } aa_run_with_teardown \ -rollback \ -test_code { array set password_result [auth::password::recover_password \ -authority_id $test_vars(authority_id) \ -username $test_vars(username)] aa_equals "status ok" $password_result(password_status) "ok" aa_true "non-empty message" [expr {$password_result(password_message) ne ""}] } } aa_register_case \ -cats {api smoke} \ auth_password_get_forgotten_url { Test the auth::password::get_forgotten_url proc. } { auth::test::get_password_vars -array_name test_vars # With user info set url [auth::password::get_forgotten_url -authority_id $test_vars(authority_id) -username $test_vars(username)] aa_true "there is a local recover-password page with user info ($url)" [regexp {recover-password} $url] set url [auth::password::get_forgotten_url -authority_id $test_vars(authority_id) -username $test_vars(username) -remote_only] aa_equals "cannot get remote url with missing forgotten_pwd_url" $url "" # Without user info set url [auth::password::get_forgotten_url -authority_id "" -username "" -remote_only] aa_equals "cannot get remote url without user info" $url "" set url [auth::password::get_forgotten_url -authority_id "" -username ""] aa_true "there is a local recover-password page without user info" [regexp {recover-password} $url] } aa_register_case \ -cats {api smoke} \ auth_password_retrieve { Test the auth::password::retrieve proc. } { auth::test::get_password_vars -array_name test_vars array set result [auth::password::retrieve \ -authority_id $test_vars(authority_id) \ -username $test_vars(username)] aa_equals "retrieve pwd from local auth" $result(password_status) "ok" aa_true "must have message on failure" [expr {$result(password_message) ne ""}] } aa_register_case \ -cats {api} \ auth_password_reset { Test the auth::password::reset proc. } { # We don't want email to go out aa_stub auth::password::email_password { return } aa_run_with_teardown \ -rollback \ -test_code { array set test_user { username "test_username" email "test_username@test.test" password "test_password" first_names "test_first_names" last_name "test_last_name" } array set create_result [auth::create_user \ -username $test_user(username) \ -email $test_user(email) \ -password $test_user(password) \ -first_names $test_user(first_names) \ -last_name $test_user(last_name) \ -secret_question "foo" \ -secret_answer "bar"] aa_equals "status should be ok for creating user" $create_result(creation_status) "ok" if { $create_result(creation_status) ne "ok" } { aa_log "Create-result: '[array get create_result]'" } array set reset_result [auth::password::reset \ -authority_id [auth::authority::local] \ -username $test_user(username)] aa_equals "status should be ok for reseting password" $reset_result(password_status) "ok" aa_true "Result contains new password" [info exists reset_result(password)] if { [info exists reset_result(password)] } { array set auth_result [auth::authentication::Authenticate \ -username $test_user(username) \ -authority_id [auth::authority::local] \ -password $reset_result(password)] aa_equals "can authenticate with new password" $auth_result(auth_status) "ok" array unset auth_result array set auth_result [auth::authentication::Authenticate \ -username $test_user(username) \ -authority_id [auth::authority::local] \ -password $test_user(password)] aa_false "cannot authenticate with old password" [string equal $auth_result(auth_status) "ok"] } set user_id [acs_user::get_by_username -username $test_user(username)] if { $user_id ne "" } { acs_user::delete -user_id $user_id } } } ########### # # Authority Management API # ########### aa_register_case \ -cats {api db} \ auth_authority_api { Test the auth::authority::create, auth::authority::edit, and auth::authority::delete procs. } { aa_run_with_teardown \ -rollback \ -test_code { # Add authority and test that it was added correctly. array set columns { pretty_name "Test authority" help_contact_text "Blah blah" enabled_p "t" sort_order "1000" auth_impl_id "" pwd_impl_id "" forgotten_pwd_url "" change_pwd_url "" register_impl_id "" register_url "" get_doc_impl_id "" process_doc_impl_id "" batch_sync_enabled_p "f" } set columns(short_name) [ad_generate_random_string] set authority_id [auth::authority::create -array columns] set authority_added_p [db_string authority_added_p { select count(*) from auth_authorities where authority_id = :authority_id } -default "0"] aa_true "was the authority added?" $authority_added_p aa_log "authority_id = '$authority_id'" # Edit authority and test that it has actually changed. array set columns { pretty_name "Test authority2" help_contact_text "Blah blah2" enabled_p "f" sort_order "1001" forgotten_pwd_url "foobar.com" change_pwd_url "foobar.com" register_url "foobar.com" } set columns(short_name) [ad_generate_random_string] auth::authority::edit \ -authority_id $authority_id \ -array columns auth::authority::get \ -authority_id $authority_id \ -array edit_result foreach column [array names columns] { aa_equals "edited column $column" $edit_result($column) $columns($column) } # Delete authority and test that it was actually added. auth::authority::delete -authority_id $authority_id set authority_exists_p [db_string authority_added_p { select count(*) from auth_authorities where authority_id = :authority_id } -default "0"] aa_false "was the authority deleted?" $authority_exists_p } } aa_register_case \ -cats {api} \ auth_driver_get_parameter_values { Test the auth::driver::set_parameter_values proc. } { aa_run_with_teardown \ -rollback \ -test_code { auth::authority::get -authority_id [auth::authority::local] -array authority set sync_retrieve_impl_id [acs_sc::impl::get_id -owner acs-authentication -name HTTPGet] array set parameters_array [auth::driver::get_parameters -impl_id $sync_retrieve_impl_id] set parameters [array names parameters_array] aa_true "List of parameters is not empty" [expr {[llength $parameters] != 0}] array set values [list] # Set the values foreach parameter $parameters { set value($parameter) [ad_generate_random_string] # Set a parameter value auth::driver::set_parameter_value \ -authority_id $authority(authority_id) \ -impl_id $sync_retrieve_impl_id \ -parameter $parameter \ -value $value($parameter) } # Get and verify values array set retrieved_value [auth::driver::get_parameter_values \ -authority_id $authority(authority_id) \ -impl_id $sync_retrieve_impl_id] foreach parameter $parameters { if { [aa_true "Parameter $parameter exists" [info exists retrieved_value($parameter)]] } { aa_equals "Parameter value retrieved is the one we set" $retrieved_value($parameter) $value($parameter) } array unset retrieved_value $parameter } aa_true "Only the right parameters were retrieved" [expr [llength [array names retrieved_value]] == 0] } } aa_register_case \ -cats {api} \ auth_use_email_for_login_p { Test auth::UseEmailForLoginP } { aa_stub auth::get_register_authority { return [auth::authority::local] } aa_run_with_teardown \ -rollback \ -test_code { # Test various values to see that it doesn't break parameter::set_value -parameter UseEmailForLoginP -package_id [ad_acs_kernel_id] -value 0 aa_false "Param UseEmailForLoginP 0 -> false" [auth::UseEmailForLoginP] array set elms [auth::get_registration_elements] aa_false "Registration elements do contain username" [expr [lsearch [concat $elms(required) $elms(optional)] "username"] == -1] parameter::set_value -parameter UseEmailForLoginP -package_id [ad_acs_kernel_id] -value {} aa_true "Param UseEmailForLoginP {} -> true" [auth::UseEmailForLoginP] parameter::set_value -parameter UseEmailForLoginP -package_id [ad_acs_kernel_id] -value {foo} aa_true "Param UseEmailForLoginP foo -> true" [auth::UseEmailForLoginP] # Test login/registration parameter::set_value -parameter UseEmailForLoginP -package_id [ad_acs_kernel_id] -value 1 aa_true "Param UseEmailForLoginP 1 -> true" [auth::UseEmailForLoginP] # GetElements array set elms [auth::get_registration_elements] aa_true "Registration elements do NOT contain username" [expr {[lsearch [concat $elms(required) $elms(optional)] "username"] == -1}] # Create a user with no username set email [string tolower "[ad_generate_random_string]@foobar.com"] set password [ad_generate_random_string] array set result [auth::create_user \ -email $email \ -password $password \ -first_names [ad_generate_random_string] \ -last_name [ad_generate_random_string] \ -secret_question [ad_generate_random_string] \ -secret_answer [ad_generate_random_string] \ -screen_name [ad_generate_random_string]] aa_equals "Registration OK" $result(creation_status) "ok" # Authenticate as that user array unset result array set result [auth::authenticate \ -email $email \ -password $password \ -no_cookie] aa_equals "Authentication OK" $result(auth_status) "ok" } } aa_register_case \ -cats {api} \ auth_email_on_password_change { Test acs-kernel.EmailAccountOwnerOnPasswordChangeP parameter } { aa_stub acs_mail_lite::send { acs_mail_lite::send__arg_parser global ns_sendmail_to set ns_sendmail_to $to_addr } aa_run_with_teardown \ -rollback \ -test_code { parameter::set_value -parameter EmailAccountOwnerOnPasswordChangeP -package_id [ad_acs_kernel_id] -value 1 global ns_sendmail_to set ns_sendmail_to {} # Create a dummy local user set username [ad_generate_random_string] set email [string tolower "[ad_generate_random_string]@foobar.com"] set password [ad_generate_random_string] array set result [auth::create_user \ -username $username \ -email $email \ -password $password \ -first_names [ad_generate_random_string] \ -last_name [ad_generate_random_string] \ -secret_question [ad_generate_random_string] \ -secret_answer [ad_generate_random_string] \ -screen_name [ad_generate_random_string]] aa_equals "Create user OK" $result(creation_status) "ok" set user_id $result(user_id) aa_log "auth_id = [db_string sel { select authority_id from users where user_id = :user_id }]" # Change password array unset result set new_password [ad_generate_random_string] array set result [auth::password::change \ -user_id $user_id \ -old_password $password \ -new_password $new_password] if { ![aa_equals "Password change OK" $result(password_status) "ok"] } { aa_log "Message was: $result(password_message)" } # Check that we get email aa_equals "Email sent to user" $ns_sendmail_to $email set ns_sendmail_to {ns_sendmail_UNCALLED} # Set parameter to false parameter::set_value -parameter EmailAccountOwnerOnPasswordChangeP -package_id [ad_acs_kernel_id] -value 0 # Change password array unset result set new_new_password [ad_generate_random_string] array set result [auth::password::change \ -user_id $user_id \ -old_password $new_password \ -new_password $new_new_password] aa_equals "Password change OK" $result(password_status) "ok" # Check that we do not get an email aa_equals "Email NOT sent to user" $ns_sendmail_to {ns_sendmail_UNCALLED} ad_parameter_cache -delete [ad_acs_kernel_id] EmailAccountOwnerOnPasswordChangeP } } ##### # # Helper procs # #### namespace eval auth::test {} ad_proc -private auth::test::get_admin_user_id {} { Return the user id of a site-wide-admin on the system } { set context_root_id [acs_lookup_magic_object security_context_root] return [db_string select_user_id {}] } ad_proc -private auth::test::get_password_vars { {-array_name:required} } { Get test vars for test case. } { upvar $array_name test_vars db_1row select_vars {} -column_array test_vars } openacs-5.7.0/packages/acs-authentication/tcl/test/acs-authentication-procs-postgresql.xql0000644000175000017500000000144607723115430031742 0ustar frankiefrankie postgresql7.1 select user_id from users where acs_permission__permission_p(:context_root_id, user_id, 'admin') = 't' limit 1 select u.user_id, aa.authority_id, u.username from users u, auth_authorities aa where u.authority_id = aa.authority_id and aa.short_name = 'local' limit 1 openacs-5.7.0/packages/acs-authentication/tcl/authority-procs.tcl0000644000175000017500000004360311166461133025006 0ustar frankiefrankiead_library { Procs for authority management. @author Lars Pind (lars@collaobraid.biz) @creation-date 2003-05-14 @cvs-id $Id: authority-procs.tcl,v 1.28 2009/04/06 20:13:15 daveb Exp $ } namespace eval auth {} namespace eval auth::authority {} ##### # # auth::authority # ##### ad_proc -public auth::authority::create { {-authority_id ""} {-array:required} } { Create a new authentication authority. @option authority_id Authority_id, or blank if you want one generated for you. @param array Name of an array containing the column values. The entries are:
    • short_name Short name for authority. Used as a key by applications to identify this authority.
    • pretty_name Label for the authority to be shown in a list to users picking a authority.
    • enabled_p 't' if this authority available, 'f' if it's disabled. Defaults to 't'.
    • sort_order Sort ordering determines the order in which authorities are listed in the user interface. Defaults to the currently highest sort order plus one.
    • auth_impl_id The ID of the implementation of the 'auth_authentication' service contract. Defaults to none.
    • pwd_impl_id The ID of the implementation of the 'auth_password' service contract. Defaults to none.
    • forgotten_pwd_url An alternative URL to redirect to when the user has forgotten his/her password. Defaults to none.
    • change_pwd_url An alternative URL to redirect to when the user wants to change his/her password. Defaults to none.
    • register_impl_id The ID of the implementation of the 'auth_registration' service contract. Defaults to none.
    • register_url An alternative URL to redirect to when the user wants to register for an account. Defaults to none.
    • user_info_impl_id The ID of the implementation of the 'auth_user_info' service contract. Defaults to none.
    • get_doc_impl_id Id of the 'auth_sync_retrieve' service contract implementation
    • process_doc_impl_id Id of the 'auth_sync_process' service contract implementation
    • batch_sync_enabled_p Is batch sync enabled for the authority?
    @author Lars Pind (lars@collaboraid.biz) } { upvar $array row db_transaction { if { $authority_id eq "" } { set authority_id [db_nextval "acs_object_id_seq"] } set names [array names row] array set column_defaults [get_column_defaults] set all_columns [array names column_defaults] # Check that the columns provided in the array are all valid # Set array entries as local variables foreach name $names { if { [lsearch -exact $all_columns $name] == -1 } { error "Attribute '$name' isn't valid for auth_authorities." } set $name $row($name) } # Check that the required columns are there foreach name [get_required_columns] { if { ![info exists $name] } { error "Required column '$name' missing for auth_authorities." } } # Set default values for columns not provided foreach column $all_columns { if { [lsearch $names $column] == -1 } { set $column $column_defaults($column) } } if { ![exists_and_not_null context_id] } { set context_id [ad_conn package_id] } if { ![exists_and_not_null creation_user] } { set creation_user [ad_conn user_id] } if { ![exists_and_not_null creation_ip] } { set creation_ip [ad_conn peeraddr] } # Auto generate short name if not provided and make # sure it's unique # TODO: check for max length 255? if { $short_name eq "" } { set existing_short_names [db_list select_short_names { select short_name from auth_authorities }] set short_name [util_text_to_url \ -replacement "_" \ -existing_urls $existing_short_names \ -text $pretty_name] } db_transaction { set authority_id [db_exec_plsql create_authority {}] # Set the arguments not taken by the new function with an update statement # LARS: Great, we had a nice abstraction going, so you only had to add a new column in # one place, now that abstraction is broken, because you have to add it here as well foreach column { user_info_impl_id get_doc_impl_id process_doc_impl_id batch_sync_enabled_p help_contact_text_format } { set edit_columns($column) [set $column] } edit -authority_id $authority_id -array edit_columns } } # Flush the cache, so that if we've tried to request this short_name while it didn't exist, we will now find it if { [exists_and_not_null row(short_name)] } { get_id_flush -short_name $row(short_name) } return $authority_id } ad_proc -public auth::authority::get { {-authority_id:required} {-array:required} } { Get info about an authority, either by authority_id, user_id, or authority short_name. @param authority_id The authority you want to get. @param array Name of an array into which you want the attributes delivered. @return authority_id @author Lars Pind (lars@collaboraid.biz) } { upvar $array row array set row [util_memoize [list auth::authority::get_not_cached $authority_id]] return $authority_id } ad_proc -public auth::authority::get_element { {-authority_id:required} {-element:required} } { Return a specific element of the auth_authority data table. Does a complete database query each time. Should not be used multiple times in a row. Use auth::authority::get instead. @see auth::authority::get } { if { [lsearch [get_select_columns] $element] == -1 } { error "Column '$element' not found in the auth_authority data source." } get -authority_id $authority_id -array row return $row($element) } ad_proc -public auth::authority::get_id { {-short_name:required} } { Get authority_id by short_name. @param short_name The short_name of the authority you wish to get information for. @return authority_id or the empty string if short_name doesn't exist. @author Lars Pind (lars@collaboraid.biz) } { return [util_memoize [list auth::authority::get_id_not_cached -short_name $short_name]] } ad_proc -public auth::authority::edit { {-authority_id:required} {-array:required} } { Edit info about a authority. Note, that there's no checking that the columns you name exist. @param authority_id The authority you want to get. @param array Name of an array with column values to update. @author Lars Pind (lars@collaboraid.biz) } { # We need this to flush the cache later set old_short_name [get_element -authority_id $authority_id -element short_name] upvar $array row set names [array names row] # Construct clauses for the update statement set set_clauses [list] foreach name $names { lappend set_clauses "$name = :$name" } if { [llength $set_clauses] == 0 } { # No rows to update return } set columns [get_columns] # Check that the columns provided in the array are all valid # Set array entries as local variables foreach name $names { if { [lsearch -exact $columns $name] == -1 } { error "Attribute '$name' isn't valid for auth_authorities." } if {$name eq "authority_id"} { error "Attribute '$name' is the primary key for auth_authorities, and thus cannot be edited." } set $name $row($name) } db_dml update_authority " update auth_authorities set [join $set_clauses ", "] where authority_id = :authority_id " get_flush -authority_id $authority_id get_id_flush -short_name $old_short_name # check if we need to update the object title set new_short_name [get_element -authority_id $authority_id -element short_name] if {$old_short_name ne $new_short_name } { db_dml update_object_title {} } } ad_proc -public auth::authority::delete { {-authority_id:required} } { Delete an authority. } { db_exec_plsql delete_authority {} } ad_proc -public auth::authority::get_authority_options {} { Returns options (value label pairs) for building the authority HTML select box. @author Simon Carstensen } { return [db_list_of_lists select_authorities {}] } ad_proc -public auth::authority::batch_sync { -authority_id:required } { Execute batch synchronization for this authority now. @param authority_id @param snapshot If set, we will delete all authority's users not touched by the process document proc. @return job_id } { set job_id [auth::sync::job::start \ -authority_id $authority_id] get -authority_id $authority_id -array authority set message {} # Verify that we have implementations if { $authority(get_doc_impl_id) eq "" } { set message "No Get Document implementation" } elseif { $authority(process_doc_impl_id) eq "" } { set message "No Process Document implementation" } else { auth::sync::job::start_get_document -job_id $job_id array set doc_result { doc_status failed_to_connect doc_message {} document {} snapshot_p f } with_catch errmsg { array set doc_result [auth::sync::GetDocument -authority_id $authority_id] } { global errorInfo ns_log Error "Error getting sync document:\n$errorInfo" set doc_result(doc_status) failed_to_connect set doc_result(doc_message) $errmsg } set snapshot_p [template::util::is_true $doc_result(snapshot_p)] auth::sync::job::end_get_document \ -job_id $job_id \ -doc_status $doc_result(doc_status) \ -doc_message $doc_result(doc_message) \ -document $doc_result(document) \ -snapshot=$snapshot_p if { $doc_result(doc_status) eq "ok" && $doc_result(document) ne "" } { with_catch errmsg { auth::sync::ProcessDocument \ -authority_id $authority_id \ -job_id $job_id \ -document $doc_result(document) set ack_doc [auth::sync::GetAcknowledgementDocument \ -authority_id $authority_id \ -job_id $job_id \ -document $doc_result(document)] set ack_file_name [parameter::get_from_package_key \ -parameter AcknowledgementFileName \ -package_key acs-authentication \ -default {}] if { $ack_file_name ne "" } { # Interpolate set pairs [list \ acs_root_dir [acs_root_dir] \ ansi_date [clock format [clock seconds] -format %Y-%m-%d] \ authority $authority(short_name)] foreach { var value } $pairs { regsub -all "{$var}" $ack_file_name $value ack_file_name } template::util::write_file \ $ack_file_name \ $ack_doc } } { global errorInfo ns_log Error "Error processing sync document:\n$errorInfo" set message "Error processing sync document: $errmsg" } } else { if { $message eq "" } { set message $doc_result(doc_message) } } if { $snapshot_p } { # If this is a snapshot, we need to delete all the users belonging to this authority # that weren't included in the snapshot. auth::sync::job::snapshot_delete_remaining \ -job_id $job_id } } auth::sync::job::end \ -job_id $job_id \ -message $message return $job_id } ad_proc -public auth::authority::get_short_names {} { Return a list of authority short names. @author Peter Marklund } { return [db_list select_authority_short_names { select short_name from auth_authorities }] } ##### # # Private # ##### ad_proc -private auth::authority::get_columns {} { Get a list of the columns in the auth_authorities table. @author Lars Pind (lars@collaboraid.biz) } { array set column_defaults [get_column_defaults] return [array names column_defaults] } ad_proc -private auth::authority::get_column_defaults {} { Get an array list with column names as keys and their default value as values. Note however that required columns are not defaulted. @author Peter Marklund } { set columns { authority_id "" short_name "" pretty_name "" help_contact_text "" help_contact_text_format "text/enhanced" enabled_p "f" sort_order "" auth_impl_id "" pwd_impl_id "" forgotten_pwd_url "" change_pwd_url "" register_impl_id "" register_url "" user_info_impl_id "" get_doc_impl_id "" process_doc_impl_id "" batch_sync_enabled_p "f" } if {[apm_version_names_compare [ad_acs_version] 5.5.0] > -1} { lappend columns allow_user_entered_info_p "f" search_impl_id "" } return $columns } ad_proc -private auth::authority::get_required_columns {} { Get a list of the required columns in the auth_authorities table. @author Lars Pind (lars@collaboraid.biz) } { return { authority_id short_name pretty_name } } ad_proc -private auth::authority::get_sc_impl_columns {} { Get a list of column names for storing service contract implementation ids of the authority. @author Peter Marklund } { # DAVEB set columns {auth_impl_id pwd_impl_id register_impl_id user_info_impl_id get_doc_impl_id process_doc_impl_id} if {[apm_version_names_compare [ad_acs_version] 5.5.0] > -1} { lappend columns search_impl_id } return $columns } ad_proc -private auth::authority::get_select_columns {} { Get a list of the columns which can be selected from auth_authorities table. @author Lars Pind (lars@collaboraid.biz) } { set columns [concat [get_columns] auth_impl_name pwd_impl_name register_impl_name user_info_impl_name get_doc_impl_name process_doc_impl_name] if {[apm_version_names_compare [ad_acs_version] 5.5.0] > -1} { lappend columns get_search_impl_name } return $columns } ad_proc -private auth::authority::get_flush { {-authority_id ""} } { Flush the cache for auth::authority::get. @see auth::authority::get } { if { $authority_id ne "" } { util_memoize_flush [list auth::authority::get_not_cached $authority_id] } else { util_memoize_flush_regexp [list auth::authority::get_not_cached .*] } } ad_proc -private auth::authority::get_not_cached { authority_id } { Get info about an authority, either by authority_id, user_id, or authority short_name. Not cached @see auth::authority::get } { set columns [get_columns] lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = auth_impl_id) as auth_impl_name" lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = pwd_impl_id) as pwd_impl_name" lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = register_impl_id) as register_impl_name" lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = user_info_impl_id) as user_info_impl_name" if {[apm_version_names_compare [ad_acs_version] 5.5.0] > -1} { lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = search_impl_id) as search_impl_name" } lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = get_doc_impl_id) as get_doc_impl_name" lappend columns "(select impl_pretty_name from acs_sc_impls where impl_id = process_doc_impl_id) as process_doc_impl_name" db_1row select_authority " select [join $columns ",\n "] from auth_authorities where authority_id = :authority_id " -column_array row return [array get row] } ad_proc -private auth::authority::get_id_flush { {-short_name ""} } { Flush the cache for gett authority_id by short_name. } { if { $short_name eq "" } { util_memoize_flush_regexp [list auth::authority::get_id_not_cached .*] } else { util_memoize_flush [list auth::authority::get_id_not_cached -short_name $short_name] } } ad_proc -private auth::authority::get_id_not_cached { {-short_name:required} } { Get authority_id by short_name. Not cached. } { return [db_string select_authority_id {} -default {}] } ad_proc -public auth::authority::local {} { Returns the authority_id of the local authority. } { return [auth::authority::get_id -short_name "local"] } openacs-5.7.0/packages/acs-authentication/tcl/authority-procs.xql0000644000175000017500000000145210024403015025007 0ustar frankiefrankie update acs_objects set title = :new_short_name where object_id = :authority_id select pretty_name, authority_id from auth_authorities where enabled_p = 't' and auth_impl_id is not null order by sort_order select authority_id from auth_authorities where short_name = :short_name openacs-5.7.0/packages/acs-authentication/tcl/sync-procs-postgresql.xql0000644000175000017500000000606207743747006026167 0ustar frankiefrankie postgresql7.1 select job_id, to_char(job_start_time, 'YYYY-MM-DD HH24:MI:SS') as job_start_time, to_char(job_end_time, 'YYYY-MM-DD HH24:MI:SS') as job_end_time, interactive_p, snapshot_p, authority_id, (select aa.pretty_name from auth_authorities aa where aa.authority_id = j.authority_id) as authority_pretty_name, message, creation_user, to_char(doc_start_time, 'YYYY-MM-DD HH24:MI:SS') as doc_start_time, to_char(doc_end_time, 'YYYY-MM-DD HH24:MI:SS') as doc_end_time, doc_status, doc_message, trunc(extract(epoch from (j.job_end_time - j.job_start_time))) as run_time_seconds, (select count(e1.entry_id) from auth_batch_job_entries e1 where e1.job_id = j.job_id) as num_actions, (select count(e2.entry_id) from auth_batch_job_entries e2 where e2.job_id = j.job_id and e2.success_p = 'f') as num_problems from auth_batch_jobs j where j.job_id = :job_id update auth_batch_jobs set doc_start_time = current_timestamp where job_id = :job_id update auth_batch_jobs set doc_end_time = current_timestamp, doc_status = :doc_status, doc_message = :doc_message, document = :document, snapshot_p = :snapshot_p where job_id = :job_id update auth_batch_jobs set job_end_time = current_timestamp, message = :message where job_id = :job_id insert into auth_batch_job_entries (entry_id, job_id, operation, username, user_id, success_p, message, element_messages) values (:entry_id, :job_id, :operation, :username, :user_id, :success_p_db, :message, :element_messages) delete from auth_batch_jobs where job_end_time < current_timestamp - interval '$num_days days' openacs-5.7.0/packages/acs-authentication/tcl/authority-procs-postgresql.xql0000644000175000017500000000176607727563721027253 0ustar frankiefrankie postgresql7.1 select authority__new( :authority_id, null, -- object_type :short_name, :pretty_name, :enabled_p, :sort_order, :auth_impl_id, :pwd_impl_id, :forgotten_pwd_url, :change_pwd_url, :register_impl_id, :register_url, :help_contact_text, :creation_user, :creation_ip, :context_id ); select authority__del( :authority_id ); openacs-5.7.0/packages/acs-authentication/tcl/driver-procs-oracle.xql0000644000175000017500000000146607725442334025547 0ustar frankiefrankie oracle8.1.6 update auth_driver_params set value = empty_clob() where authority_id = :authority_id and impl_id = :impl_id and key = :parameter returning value into :1 insert into auth_driver_params (authority_id, impl_id, key, value) values (:authority_id, :impl_id, :parameter, empty_clob()) returning value into :1 openacs-5.7.0/packages/acs-authentication/tcl/authority-procs-oracle.xql0000644000175000017500000000245107727563721026305 0ustar frankiefrankie oracle8.1.6 begin :1 := authority.new( authority_id => :authority_id, short_name => :short_name, pretty_name => :pretty_name, enabled_p => :enabled_p, sort_order => :sort_order, auth_impl_id => :auth_impl_id, pwd_impl_id => :pwd_impl_id, forgotten_pwd_url => :forgotten_pwd_url, change_pwd_url => :change_pwd_url, register_impl_id => :register_impl_id, register_url => :register_url, help_contact_text => :help_contact_text, creation_user => :creation_user, creation_ip => :creation_ip, context_id => :context_id ); end; begin :1 := authority.del( delete_authority_id => :authority_id ); end; openacs-5.7.0/packages/acs-authentication/tcl/driver-procs-postgresql.xql0000644000175000017500000000134407725442334026500 0ustar frankiefrankie postgresql7.1 update auth_driver_params set value = :value where authority_id = :authority_id and impl_id = :impl_id and key = :parameter insert into auth_driver_params (authority_id, impl_id, key, value) values (:authority_id, :impl_id, :parameter, :value) openacs-5.7.0/packages/acs-authentication/tcl/local-procs.tcl0000644000175000017500000004703511263374112024051 0ustar frankiefrankiead_library { Procs for local authentication. @author Lars Pind (lars@collaobraid.biz) @creation-date 2003-05-13 @cvs-id $Id: local-procs.tcl,v 1.37 2009/10/08 14:33:46 daveb Exp $ } namespace eval auth {} namespace eval auth::local {} namespace eval auth::local::authentication {} namespace eval auth::local::password {} namespace eval auth::local::registration {} namespace eval auth::local::user_info {} namespace eval auth::local::search {} ##### # # auth::local # ##### ad_proc -private auth::local::install {} { Register local service contract implementations, and update the local authority with live information. } { db_transaction { # Register the local service contract implementations set row(auth_impl_id) [auth::local::authentication::register_impl] set row(pwd_impl_id) [auth::local::password::register_impl] set row(register_impl_id) [auth::local::registration::register_impl] set row(user_info_impl_id) [auth::local::user_info::register_impl] # Set the authority pretty-name to be the system name set row(pretty_name) [ad_system_name] auth::authority::edit \ -authority_id [auth::authority::local] \ -array row } } ad_proc -private auth::local::uninstall {} { Unregister the local service contract implementation, and update the local authority to reflect that. } { db_transaction { # Update the local authority to reflect the loss of the implementations set row(auth_impl_id) {} set row(pwd_impl_id) {} set row(register_impl_id) {} auth::authority::edit \ -authority_id [auth::authority::local] \ -array row # Unregister the implementations auth::local::authentication::unregister_impl auth::local::password::unregister_impl auth::local::registration::unregister_impl } } ##### # # auth::local::authentication # ##### # # The 'auth_authentication' service contract implementation # ad_proc -private auth::local::authentication::register_impl {} { Register the 'local' implementation of the 'auth_authentication' service contract. @return impl_id of the newly created implementation. } { set spec { contract_name "auth_authentication" owner "acs-authentication" name "local" pretty_name "Local" aliases { MergeUser auth::local::authentication::MergeUser Authenticate auth::local::authentication::Authenticate GetParameters auth::local::authentication::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::local::authentication::unregister_impl {} { Unregister the 'local' implementation of the 'auth_authentication' service contract. } { acs_sc::impl::delete -contract_name "auth_authentication" -impl_name "local" } ad_proc -private auth::local::authentication::MergeUser { from_user_id to_user_id {authority_id ""} } { Merge Implementation of local authentication. This will merge the names, emails, usernames, permissions, etc of the two users to merge. } { ns_log Notice "Starting auth::local::authentication::MergeUser" db_transaction { ns_log Notice " Merging user portraits" ns_log notice " Merging username, email and basic info in general" set new_username "merged_$from_user_id" append new_username "_$to_user_id" # Shall we keep the domain for email? # Actually, the username 'merged_xxx_yyy' # won't be an email, so we will keep it without # domain set new_email $new_username set rel_id [db_string getrelid { *SQL* }] membership_rel::change_state -rel_id $rel_id -state "merged" acs_user::update -user_id $from_user_id -username "$new_username" -screen_name "$new_username" party::update -party_id $from_user_id -email "$new_email" } ns_log notice "Finishing auth::local::authentication::MergeUser" } ad_proc -private auth::local::authentication::Authenticate { username password {parameters {}} {authority_id {}} } { Implements the Authenticate operation of the auth_authentication service contract for the local account implementation. } { array set auth_info [list] if {$authority_id eq ""} { set authority_id [auth::authority::local] } set user_id [acs_user::get_by_username -authority_id $authority_id -username $username] if { $user_id eq "" } { set result(auth_status) "no_account" return [array get result] } if { [ad_check_password $user_id $password] } { set auth_info(auth_status) "ok" } else { set auth_info(auth_status) "bad_password" set auth_info(auth_message) [_ acs-authentication.Invalid_username_or_password] return [array get auth_info] } # We set 'external' account status to 'ok', because the # local account status will be checked anyways by the framework set auth_info(account_status) ok return [array get auth_info] } ad_proc -private auth::local::authentication::GetParameters {} { Implements the GetParameters operation of the auth_authentication service contract for the local account implementation. } { # No parameters return [list] } ##### # # auth::local::password # ##### # # The 'auth_password' service contract implementation # ad_proc -private auth::local::password::register_impl {} { Register the 'local' implementation of the 'auth_password' service contract. @return impl_id of the newly created implementation. } { set spec { contract_name "auth_password" owner "acs-authentication" name "local" pretty_name "Local" aliases { CanChangePassword auth::local::password::CanChangePassword ChangePassword auth::local::password::ChangePassword CanRetrievePassword auth::local::password::CanRetrievePassword RetrievePassword auth::local::password::RetrievePassword CanResetPassword auth::local::password::CanResetPassword ResetPassword auth::local::password::ResetPassword GetParameters auth::local::password::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::local::password::unregister_impl {} { Unregister the 'local' implementation of the 'auth_password' service contract. } { acs_sc::impl::delete -contract_name "auth_password" -impl_name "local" } ad_proc -private auth::local::password::CanChangePassword { {parameters ""} } { Implements the CanChangePassword operation of the auth_password service contract for the local account implementation. } { # Yeah, we can change your password return 1 } ad_proc -private auth::local::password::CanRetrievePassword { {parameters ""} } { Implements the CanRetrievePassword operation of the auth_password service contract for the local account implementation. } { # passwords are stored hashed, so we send the hash and let the user choose a new password return 1 } ad_proc -private auth::local::password::CanResetPassword { {parameters ""} } { Implements the CanResetPassword operation of the auth_password service contract for the local account implementation. } { # Yeah, we can reset for you. return 1 } ad_proc -private auth::local::password::ChangePassword { username new_password {old_password ""} {parameters {}} {authority_id {}} } { Implements the ChangePassword operation of the auth_password service contract for the local account implementation. } { array set result { password_status {} password_message {} } set user_id [acs_user::get_by_username -authority_id $authority_id -username $username] if { $user_id eq "" } { set result(password_status) "no_account" return [array get result] } if { $old_password ne "" } { if { ![ad_check_password $user_id $old_password] } { set result(password_status) "old_password_bad" return [array get result] } } if { [catch { ad_change_password $user_id $new_password } errmsg] } { set result(password_status) "change_error" global errorInfo ns_log Error "Error changing local password for username $username, user_id $user_id: \n$errorInfo" return [array get result] } set result(password_status) "ok" if { [parameter::get -parameter EmailAccountOwnerOnPasswordChangeP -package_id [ad_acs_kernel_id] -default 1] } { with_catch errmsg { acs_user::get -username $username -authority_id $authority_id -array user set system_name [ad_system_name] set pvt_home_name [ad_pvt_home_name] set password_update_link_text [_ acs-subsite.Change_my_Password] if { [auth::UseEmailForLoginP] } { set account_id_label [_ acs-subsite.Email] set account_id $user(email) } else { set account_id_label [_ acs-subsite.Username] set account_id $user(username) } set subject [_ acs-subsite.Password_changed_subject] set body [_ acs-subsite.Password_changed_body] acs_mail_lite::send \ -send_immediately \ -to_addr $user(email) \ -from_addr [ad_outgoing_sender] \ -subject $subject \ -body $body } { global errorInfo ns_log Error "Error sending out password changed notification to account owner with user_id $user(user_id), email $user(email): $errmsg\n$errorInfo" } } return [array get result] } ad_proc -private auth::local::password::RetrievePassword { username parameters } { Implements the RetrievePassword operation of the auth_password service contract for the local account implementation. } { set result(password_status) "ok" set result(password_message) [_ acs-subsite.Request_Change_Password_token_email] db_1row get_usr_id_and_password_hash {SELECT user_id, password as password_hash FROM users WHERE username = :username} set email [party::email -party_id $user_id] # TODO: This email message text should go in the recipient user language, english or every language supported set subject "[ad_system_name]: [_ acs-subsite.change_password_email_subject] $username" set body "[_ acs-subsite.change_password_email_body_0]\n\n[export_vars -base "[ad_url]/user/password-reset" {user_id password_hash}]\n\n[_ acs-subsite.change_password_email_body_1]" acs_mail_lite::send \ -send_immediately \ -to_addr $email \ -from_addr [ad_outgoing_sender] \ -subject $subject \ -body $body return [array get result] } ad_proc -private auth::local::password::ResetPassword { username parameters {authority_id {}} {new_password {}} } { Implements the ResetPassword operation of the auth_password service contract for the local account implementation. } { array set result { password_status ok password_message {} } set user_id [acs_user::get_by_username -authority_id $authority_id -username $username] if { $user_id eq "" } { set result(password_status) "no_account" return [array get result] } # Reset the password if {[exists_and_not_null new_password]} { set password $new_password } else { set password [ad_generate_random_string] } ad_change_password $user_id $password # We return the new passowrd here and let the OpenACS framework send the email with the new password set result(password) $password return [array get result] } ad_proc -private auth::local::password::GetParameters {} { Implements the GetParameters operation of the auth_password service contract for the local account implementation. } { # No parameters return [list] } ##### # # auth::local::register # ##### # # The 'auth_registration' service contract implementation # ad_proc -private auth::local::registration::register_impl {} { Register the 'local' implementation of the 'auth_registration' service contract. @return impl_id of the newly created implementation. } { set spec { contract_name "auth_registration" owner "acs-authentication" name "local" pretty_name "Local" aliases { GetElements auth::local::registration::GetElements Register auth::local::registration::Register GetParameters auth::local::registration::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::local::registration::unregister_impl {} { Unregister the 'local' implementation of the 'auth_register' service contract. } { acs_sc::impl::delete -contract_name "auth_registration" -impl_name "local" } ad_proc -private auth::local::registration::GetElements { {parameters ""} } { Implements the GetElements operation of the auth_registration service contract for the local account implementation. } { set result(required) {} if { ![auth::UseEmailForLoginP] } { set result(required) username } set result(required) [concat $result(required) { email first_names last_name }] set result(optional) { url } if { ![parameter::get -package_id [ad_conn subsite_id] -parameter RegistrationProvidesRandomPasswordP -default 0] } { lappend result(optional) password } if { [parameter::get -package_id [ad_acs_kernel_id] -parameter RequireQuestionForPasswordResetP -default 0] && [parameter::get -package_id [ad_acs_kernel_id] -parameter UseCustomQuestionForPasswordReset -default 0] } { lappend result(required) secret_question secret_answer } return [array get result] } ad_proc -private auth::local::registration::Register { parameters username authority_id first_names last_name screen_name email url password secret_question secret_answer } { Implements the Register operation of the auth_registration service contract for the local account implementation. } { array set result { creation_status "ok" creation_message {} element_messages {} account_status "ok" account_message {} generated_pwd_p 0 password {} } # We don't create anything here, so creation always succeeds # And we don't check local account, either # LARS TODO: Move this out of the local driver and into the auth framework # Generate random password? set generated_pwd_p 0 if { $password eq "" || [parameter::get -package_id [ad_conn subsite_id] -parameter RegistrationProvidesRandomPasswordP -default 0] } { set password [ad_generate_random_string] set generated_pwd_p 1 } set result(generated_pwd_p) $generated_pwd_p set result(password) $password # Set user's password set user_id [acs_user::get_by_username -username $username] ad_change_password $user_id $password # Used in messages below set system_name [ad_system_name] set system_url [ad_url] # LARS TODO: Move this out of the local driver and into the auth framework # Send password confirmation email to user if { [set email_reg_confirm_p [parameter::get -parameter EmailRegistrationConfirmationToUserP -package_id [ad_conn subsite_id] -default 0]] != -1 } { if { $generated_pwd_p || \ [parameter::get -parameter RegistrationProvidesRandomPasswordP -package_id [ad_conn subsite_id] -default 0] || \ $email_reg_confirm_p } { with_catch errmsg { auth::password::email_password \ -username $username \ -authority_id $authority_id \ -password $password \ -from [parameter::get -parameter NewRegistrationEmailAddress -package_id [ad_conn subsite_id] -default [ad_system_owner]] \ -subject_msg_key "acs-subsite.email_subject_Registration_password" \ -body_msg_key "acs-subsite.email_body_Registration_password" } { # We don't fail hard here, just log an error global errorInfo ns_log Error "Error sending registration confirmation to $email.\n$errorInfo" } } } # LARS TODO: Move this out of the local driver and into the auth framework # Notify admin on new registration if { [parameter::get -parameter NotifyAdminOfNewRegistrationsP -default 0] } { with_catch errmsg { set admin_email [parameter::get \ -parameter NewRegistrationEmailAddress \ -package_id [ad_conn subsite_id] \ -default [ad_system_owner]] set admin_id [party::get_by_email -email $admin_email] if { $admin_id eq "" } { set admin_locale [lang::system::site_wide_locale] } else { set admin_locale [lang::user::locale -user_id $admin_id] } set system_url [ad_url] acs_mail_lite::send \ -send_immediately \ -to_addr $admin_email \ -from_addr [ad_outgoing_sender] \ -subject [lang::message::lookup $admin_locale acs-subsite.lt_New_registration_at_s] \ -body [lang::message::lookup $admin_locale acs-subsite.lt_first_names_last_name] } { # We don't fail hard here, just log an error global errorInfo ns_log Error "Error sending admin notification to $admin_email.\n$errorInfo" } } return [array get result] } ad_proc -private auth::local::registration::GetParameters {} { Implements the GetParameters operation of the auth_registration service contract for the local account implementation. } { # No parameters return [list] } ##### # # The 'auth_user_info' service contract implementation # ad_proc -private auth::local::user_info::register_impl {} { Register the 'local' implementation of the 'auth_user_info' service contract. @return impl_id of the newly created implementation. } { set spec { contract_name "auth_user_info" owner "acs-authentication" name "local" pretty_name "Local" aliases { GetUserInfo auth::local::user_info::GetUserInfo GetParameters auth::local::user_info::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::local::user_info::unregister_impl {} { Unregister the 'local' implementation of the 'auth_user_info' service contract. } { acs_sc::impl::delete -contract_name "auth_user_info" -impl_name "local" } ad_proc -private auth::local::user_info::GetUserInfo { user_id {parameters ""} } { Implements the GetUserInfo operation of the auth_user_info service contract for the local account implementation. } { set result(info_status) [auth::get_local_account_status -user_id $user_id] set result(info_message) "" db_1row get_user_info {} -column_array user_info set result(user_info) [array get user_info] return [array get result] } ad_proc -private auth::local::user_info::GetParameters {} { Implements the GetParameters operation of the auth_user_info service contract for the local account implementation. } { # No parameters return [list] } ad_proc -private auth::local::search::Search { search_text {parameters ""} } { Implements the Search operation of the auth_search service contract for the local account implementation. } { set results [list] db_foreach user_search {} { lappend results $user_id } return $results } ad_proc -private auth::local::search::GetParameters {} { Implements the GetParameters operation of the auth_search service contract for the local account implementation. } { # No parameters return [list] } openacs-5.7.0/packages/acs-authentication/tcl/local-procs.xql0000644000175000017500000000177211061303702024062 0ustar frankiefrankie select rel_id from cc_users where user_id = :from_user_id select distinct user_id, username, email from cc_users u where upper(coalesce(u.first_names || ' ', '') || coalesce(u.last_name || ' ', '') || u.email || ' ' || u.username || ' ' || coalesce(u.screen_name, '')) like upper('%'||:search_text||'%') order by username, email select user_id, first_names, last_name, username, email from cc_users where user_id = :user_id openacs-5.7.0/packages/acs-authentication/tcl/sync-procs-oracle.xql0000644000175000017500000000610707744775714025241 0ustar frankiefrankie oracle8.1.6 select job_id, to_char(job_start_time, 'YYYY-MM-DD HH24:MI:SS') as job_start_time, to_char(job_end_time, 'YYYY-MM-DD HH24:MI:SS') as job_end_time, interactive_p, snapshot_p, authority_id, (select aa.pretty_name from auth_authorities aa where aa.authority_id = j.authority_id) as authority_pretty_name, message, creation_user, to_char(doc_start_time, 'YYYY-MM-DD HH24:MI:SS') as doc_start_time, to_char(doc_end_time, 'YYYY-MM-DD HH24:MI:SS') as doc_end_time, doc_status, doc_message, round((j.job_end_time - j.job_start_time) * 24*60*60) as run_time_seconds, (select count(e1.entry_id) from auth_batch_job_entries e1 where e1.job_id = j.job_id) as num_actions, (select count(e2.entry_id) from auth_batch_job_entries e2 where e2.job_id = j.job_id and e2.success_p = 'f') as num_problems from auth_batch_jobs j where j.job_id = :job_id update auth_batch_jobs set doc_start_time = sysdate where job_id = :job_id update auth_batch_jobs set doc_end_time = sysdate, doc_status = :doc_status, doc_message = :doc_message, document = empty_clob(), snapshot_p = :snapshot_p where job_id = :job_id returning document into :1 update auth_batch_jobs set job_end_time = sysdate, message = :message where job_id = :job_id insert into auth_batch_job_entries (entry_id, job_id, operation, username, user_id, success_p, message, element_messages) values (:entry_id, :job_id, :operation, :username, :user_id, :success_p_db, :message, empty_clob()) returning element_messages into :1 delete from auth_batch_jobs where job_end_time < sysdate - :num_days openacs-5.7.0/packages/acs-authentication/tcl/apm-callback-procs.tcl0000644000175000017500000005254211064755720025274 0ustar frankiefrankiead_library { Installation procs for authentication, account management, and password management, @author Lars Pind (lars@collaobraid.biz) @creation-date 2003-05-13 @cvs-id $Id: apm-callback-procs.tcl,v 1.19 2008/09/19 17:05:20 gustafn Exp $ } namespace eval auth {} namespace eval auth::authentication {} namespace eval auth::password {} namespace eval auth::registration {} namespace eval auth::get_doc {} namespace eval auth::process_doc {} namespace eval auth::user_info {} namespace eval auth::search {} ad_proc -private auth::package_install {} {} { db_transaction { # Create service contracts auth::authentication::create_contract auth::password::create_contract auth::registration::create_contract auth::get_doc::create_contract auth::process_doc::create_contract auth::user_info::create_contract auth::search::create_contract # Register local authentication implementations and update the local authority auth::local::install # Register HTTP method for GetDocument auth::sync::get_doc::http::register_impl # Register local file system method for GetDocument auth::sync::get_doc::file::register_impl # Register IMS Enterprise 1.1 ProcessDocument implementation auth::sync::process_doc::ims::register_impl } } ad_proc -private auth::package_uninstall {} {} { db_transaction { # Unregister IMS Enterprise 1.1 ProcessDocument implementation auth::sync::process_doc::ims::unregister_impl # Unregister HTTP method for GetDocument auth::sync::get_doc::http::unregister_impl # Unregister local file system method for GetDocument auth::sync::get_doc::file::unregister_impl # Unregister local authentication implementations and update the local authority auth::local::uninstall # Delete service contracts auth::authentication::delete_contract auth::password::delete_contract auth::registration::delete_contract auth::get_doc::delete_contract auth::process_doc::delete_contract auth::user_info::delete_contract auth::search::delete_contract } } ad_proc -private auth::after_upgrade { {-from_version_name:required} {-to_version_name:required} } { After upgrade callback. } { apm_upgrade_logic \ -from_version_name $from_version_name \ -to_version_name $to_version_name \ -spec { 5.0a1 5.0a2 { db_transaction { # Delete and recreate contract auth::process_doc::delete_contract auth::process_doc::create_contract # The old implementation is still there, but now it's unbound # We change the name of the old implementation, so we can recreate it, but don't break foreign key references to it set old_impl_id [acs_sc::impl::get_id -name "IMS_Enterprise_v_1p1" -owner "acs-authentication"] db_dml update { update acs_sc_impls set impl_name = 'IMS_Enterprise_v_1p1_old' where impl_id = :old_impl_id } db_dml update { update acs_sc_impl_aliases set impl_name = 'IMS_Enterprise_v_1p1_old' where impl_id = :old_impl_id } # Create the new implementation set new_impl_id [auth::sync::process_doc::ims::register_impl] # Update authorities that used to use the old impl to use the new impl db_dml update_authorities { update auth_authorities set process_doc_impl_id = :new_impl_id where process_doc_impl_id = :old_impl_id } # Delete the old implementation acs_sc::impl::delete -contract_name "auth_sync_process" -impl_name "IMS_Enterprise_v_1p1_old" } } 5.1.1 5.1.2d1 { db_transaction { # this is a direct update to the SC tables, we should expect a new # API for handling updates on SC, but since there's no one yet, # we'll do this way now .... (roc) set sc_change [list {auth_authentication.Authenticate.InputType} {auth_password.ChangePassword.InputType} {auth_password.ResetPassword.InputType}] set element_msg_type_name integer foreach msg_type_name $sc_change { set msg_type_id [db_string get_msg_type_id { select msg_type_id from acs_sc_msg_types where msg_type_name = :msg_type_name }] set element_pos [db_string get_pos { select max(element_pos) from acs_sc_msg_type_elements where msg_type_id = :msg_type_id }] incr element_pos acs_sc::msg_type::element::new \ -msg_type_name $msg_type_name \ -element_name authority_id \ -element_msg_type_name $element_msg_type_name \ -element_msg_type_isset_p f \ -element_pos $element_pos } } } 5.1.5 5.2.0a1 { db_transaction { # I will add support to MergeUser operation # this is a direct update to the SC tables, # we should expect a new API for handling updates on SC, # but since there's no one yet, we'll do it # in this way. (quio@galileo.edu) ns_log notice "acs_authentication: Starting Upgrade (adding merge support)" acs_sc::contract::operation::new \ -contract_name "auth_authentication" \ -operation "MergeUser" \ -input { from_user_id:integer to_user_id:integer authority_id:integer } \ -output {} \ -description "Merges two accounts given the user_id of each one" acs_sc::impl::alias::new \ -contract_name "auth_authentication" \ -impl_name "local" \ -operation "MergeUser" \ -alias "auth::local::authentication::MergeUser" \ ns_log notice "acs_authentication: Finishing Upgrade (adding merge support)" } } 5.5.0d1 5.5.0d2 { auth::search::create_contract } } } ##### # # auth_authentication service contract # ##### ad_proc -private auth::authentication::create_contract {} { Create service contract for authentication. } { set spec { name "auth_authentication" description "Authenticate users and retrieve their account status." operations { Authenticate { description { Validate this username/password combination, and return the result. Valid auth_status codes are 'ok', 'no_account', 'bad_password', 'auth_error', 'failed_to_connect'. The last, 'failed_to_connect', is reserved for communications or implementation errors. auth_message is a human-readable explanation of what went wrong, may contain HTML. Only checked if auth_status is not ok. Valid account_status codes are 'ok' and 'closed'. account_message may be supplied regardless of account_status, and may contain HTML. } input { username:string password:string parameters:string,multiple authority_id:integer } output { auth_status:string auth_message:string account_status:string account_message:string } } MergeUser { description { Merges two accounts given the user_id of each one } input { from_user_id:integer to_user_id:integer authority_id:integer } output {} } GetParameters { description { Get an arraay-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::authentication::delete_contract {} { Delet service contract for authentication. } { acs_sc::contract::delete -name "auth_authentication" } ##### # # auth_password service contract # ##### ad_proc -private auth::password::create_contract {} { Create service contract for password management. } { set spec { name "auth_password" description "Update, reset, and retrieve passwords for authentication." operations { CanChangePassword { description { Return whether the user can change his/her password through this implementation. The value is not supposed to depend on the username and should be cachable. } input { parameters:string,multiple } output { changeable_p:boolean } iscachable_p "t" } ChangePassword { description { Change the user's password. } input { username:string old_password:string new_password:string parameters:string,multiple authority_id:integer } output { password_status:string password_message:string } } CanRetrievePassword { description { Return whether the user can retrieve his/her password through this implementation. The value is not supposed to depend on the username and should be cachable. } input { parameters:string,multiple } output { retrievable_p:boolean } iscachable_p "t" } RetrievePassword { description { Retrieve the user's password. The implementation can either return the password, in which case the authentication API will email the password to the user. Or it can email the password itself, in which case it would return the empty string for password. } input { username:string parameters:string,multiple } output { password_status:string password_message:string password:string } } CanResetPassword { description { Return whether the user can reset his/her password through this implementation. The value is not supposed to depend on the username and should be cachable. } input { parameters:string,multiple } output { resettable_p:boolean } iscachable_p "t" } ResetPassword { description { Reset the user's password to a new, randomly generated value. The implementation can either return the password, in which case the authentication API will email the password to the user. Or it can email the password itself, in which case it would return the empty string. } input { username:string parameters:string,multiple authority_id:integer } output { password_status:string password_message:string password:string } } GetParameters { description { Get an arraay-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::password::delete_contract {} { Delete service contract for password management. } { acs_sc::contract::delete -name "auth_password" } ##### # # auth_registration service contract # ##### ad_proc -private auth::registration::create_contract {} { Create service contract for account registration. } { set spec { name "auth_registration" description "Registering accounts for authentication" operations { GetElements { description { Get a list of required and a list of optional fields available when registering accounts through this service contract implementation. } input { parameters:string,multiple } output { requiered:string,multiple optional:string,multiple } } Register { description { Register a new account. Valid status codes are: 'ok', 'data_error', and 'reg_error', and 'fail'. 'data_error' means that the implementation is returning an array-list of element-name, message with error messages for each individual element. 'reg_error' is any other registration error, and 'fail' is reserved to communications or implementation errors. } input { parameters:string,multiple username:string authority_id:integer first_names:string last_name:string screen_name:string email:string url:string password:string secret_question:string secret_answer:string } output { creation_status:string creation_message:string element_messages:string,multiple account_status:string account_message:string } } GetParameters { description { Get an array-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::registration::delete_contract {} { Delete service contract for account registration. } { acs_sc::contract::delete -name "auth_registration" } ##### # # auth_get_doc service contract # ##### ad_proc -private auth::get_doc::create_contract {} { Create service contract for account registration. } { set spec { name "auth_sync_retrieve" description "Retrieve a document, e.g. using HTTP, SMP, FTP, SOAP, etc." operations { GetDocument { description { Retrieves the document. Returns doc_status of 'ok', 'get_error', or 'failed_to_connect'. If not 'ok', then it should set doc_message to explain the problem. If 'ok', it must set document to the document retrieved, and set snapshot_p to t if it has retrieved a snapshot document. } input { parameters:string,multiple } output { doc_status:string doc_message:string document:string snapshot_p:string } } GetParameters { description { Get an array-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::get_doc::delete_contract {} { Delete service contract for account registration. } { acs_sc::contract::delete -name "auth_sync_retrieve" } ##### # # auth_process_doc service contract # ##### ad_proc -private auth::process_doc::create_contract {} { Create service contract for account registration. } { set spec { name "auth_sync_process" description "Process a document containing user information from a remote authentication authority" operations { ProcessDocument { description { Process a user synchronization document. } input { job_id:integer document:string parameters:string,multiple } } GetAcknowledgementDocument { description { Return an acknowledgement document in a format suitable for display on. } input { job_id:integer document:string parameters:string,multiple } } GetElements { description { Get an list of the elements handled by this batch synchronization (first_names, last_name, username, email, etc). These elements will not be editable by the user, so as not to risk overwriting the user's changes with a later synchronization. } input { parameters:string,multiple } output { elements:string,multiple } } GetParameters { description { Get an array-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::process_doc::delete_contract {} { Delete service contract for account registration. } { acs_sc::contract::delete -name "auth_sync_process" } ##### # # auth_user_info service contract # ##### ad_proc -private auth::user_info::create_contract {} { Create service contract for account registration. } { set spec { name "auth_user_info" description "Get information about a user in real-time" operations { GetUserInfo { description { Request information about a user. Returns info_status 'ok', 'no_account', 'info_error', or 'failed_to_connect'. info_message is a human-readable explanation to the user. } input { username:string parameters:string,multiple } output { info_status:string info_message:string user_info:string,multiple } } GetParameters { description { Get an array-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::user_info::delete_contract {} { Delete service contract for account registration. } { acs_sc::contract::delete -name "auth_user_info" } ##### # # auth_search service contract # ##### ad_proc -private auth::search::create_contract {} { Create service contract for authority searches. } { set spec { name "auth_search" description "Search users in given authority" operations { Search { description { Search authority using "search" string. Returns array-list of usernames. } input { search:string parameters:string,multiple } output { usernames:string,multiple } } GetParameters { description { Get an array-list of the parameters required by this service contract implementation. } output { parameters:string,multiple } } FormInclude { description { File location of an includable search form } output { form_include:string } } } } acs_sc::contract::new_from_spec -spec $spec } ad_proc -private auth::search::delete_contract {} { Delete service contract for authority search. } { acs_sc::contract::delete -name "auth_search" } openacs-5.7.0/packages/acs-authentication/tcl/sync-procs.tcl0000644000175000017500000007635411226233607023743 0ustar frankiefrankiead_library { API for managing synchronization of user data. @creation-date 2003-09-05 @author Lars Pind (lars@collaboraid.biz) @cvs-id $Id: sync-procs.tcl,v 1.34 2009/07/12 01:08:23 donb Exp $ } namespace eval auth {} namespace eval auth::sync {} namespace eval auth::sync::job {} namespace eval auth::sync::get_doc {} namespace eval auth::sync::get_doc::http {} namespace eval auth::sync::get_doc::file {} namespace eval auth::sync::entry {} namespace eval auth::sync::process_doc {} namespace eval auth::sync::process_doc::ims {} ##### # # auth::sync::job namespace # ##### ad_proc -public auth::sync::job::get { {-job_id:required} {-array:required} } { Get information about a batch job in an array. @param job_id The ID of the batch job you're ending. @param array Name of an array into which you want the information. @author Lars Pind (lars@collaboraid.biz) } { upvar 1 $array row db_1row select_job {} -column_array row set row(log_url) [export_vars -base "[ad_url]/acs-admin/auth/batch-job" { job_id }] } ad_proc -public auth::sync::job::get_entries { {-job_id:required} } { Get a list of entry_ids of the job log entries, ordered by entry_time. @param job_id The ID of the batch job you're ending. @author Lars Pind (lars@collaboraid.biz) } { return [db_list select_entries { select entry_id from auth_batch_job_entries where job_id = :job_id order by entry_time }] } ad_proc -public auth::sync::job::get_authority_id { {-job_id:required} } { Get the authority_id from a job_id. Cached. @param job_id The ID of the batch job you're ending. @author Lars Pind (lars@collaboraid.biz) } { return [util_memoize [list auth::sync::job::get_authority_id_not_cached $job_id]] } ad_proc -private auth::sync::job::get_authority_id_flush { {-job_id ""} } { Flush cache @param job_id The ID of the batch job you're ending. @author Lars Pind (lars@collaboraid.biz) } { if { $job_id ne "" } { util_memoize_flush [list auth::sync::job::get_authority_id_not_cached $job_id] } else { util_memoize_flush_regexp [list auth::sync::job::get_authority_id_not_cached .*] } } ad_proc -private auth::sync::job::get_authority_id_seed { {-job_id:required} {-authority_id:required} } { Flush cache @param job_id The ID of the batch job you're ending. @author Lars Pind (lars@collaboraid.biz) } { util_memoize_seed [list auth::sync::job::get_authority_id_not_cached $job_id] $authority_id } ad_proc -private auth::sync::job::get_authority_id_not_cached { job_id } { Get the authority_id from a job_id. Not cached. @param job_id The ID of the batch job you're ending. @author Lars Pind (lars@collaboraid.biz) @see auth::sync::job::get_authority_id } { return [db_string select_auth_id { select authority_id from auth_batch_jobs where job_id = :job_id }] } ad_proc -public auth::sync::job::start { {-job_id ""} {-authority_id:required} {-interactive:boolean} {-creation_user ""} } { Record the beginning of a job. @param authority_id The ID of the authority you're trying to sync @param interactive Set this if this is an interactive job, i.e. it's initiated by a user. @return job_id An ID for the new batch job. Used when calling other procs in this API. @author Lars Pind (lars@collaboraid.biz) } { db_transaction { if { $job_id eq "" } { set job_id [db_nextval "auth_batch_jobs_job_id_seq"] } if { $interactive_p && $creation_user eq "" } { set creation_user [ad_conn user_id] } set interactive_p [db_boolean $interactive_p] db_dml job_insert { insert into auth_batch_jobs (job_id, interactive_p, creation_user, authority_id) values (:job_id, :interactive_p, :creation_user, :authority_id) } } # See the cache, we're going to need it shortly auth::sync::job::get_authority_id_seed -job_id $job_id -authority_id $authority_id return $job_id } ad_proc -public auth::sync::job::end { {-job_id:required} {-message ""} } { Record the end of a batch job. Closes out the transaction log and sends out notifications. @param job_id The ID of the batch job you're ending. @return array list with result of auth::sync::job::get. @see auth::sync::job::get @author Lars Pind (lars@collaboraid.biz) } { db_dml update_job_end {} # interactive_p, run_time_seconds, num_actions, num_problems get -job_id $job_id -array job set email_p [parameter::get_from_package_key \ -parameter SyncEmailConfirmationP \ -package_key "acs-authentication" \ -default 0] if { ![template::util::is_true $job(interactive_p)] && $email_p } { # Only send out email if not an interactive job with_catch errmsg { acs_mail_lite::send -send_immediately \ -to_addr [ad_system_owner] \ -from_addr [ad_system_owner] \ -subject "Batch user synchronization for $job(authority_pretty_name) complete" \ -body "Batch user synchronization for $job(authority_pretty_name) is complete. Authority : $job(authority_pretty_name) Running time : $job(run_time_seconds) seconds Number of actions : $job(num_actions) Number of problems: $job(num_problems) Job message : $job(message) To view the complete log, please visit\n$job(log_url)" } { # We don't fail hard here, just log an error global errorInfo ns_log Error "Error sending registration confirmation to [ad_system_owner].\n$errorInfo" } } return [array get job] } ad_proc -public auth::sync::job::start_get_document { {-job_id:required} } { Record the that we're starting to get the document. @param job_id The ID of the batch job you're ending. } { db_dml update_doc_start_time {} } ad_proc -public auth::sync::job::end_get_document { {-job_id:required} {-doc_status:required} {-doc_message ""} {-document ""} {-snapshot:boolean} } { Record the that we've finished getting the document, and record the status. @param job_id The ID of the batch job you're ending. @param snapshot Set this if this is a snapshot job, as opposed to an incremental ('event driven') job. } { set snapshot_p [db_boolean $snapshot_p] db_dml update_doc_end {} -clobs [list $document] } ad_proc -public auth::sync::job::create_entry { {-job_id:required} {-operation:required} {-username:required} {-user_id ""} {-success:boolean} {-message ""} {-element_messages ""} } { Record a batch job entry. @param job_id The ID of the batch job you're ending. @param operation One of 'insert', 'update', or 'delete'. @param username The username of the user being inserted/updated/deleted. @param user_id The user_id of the local user account, if known. @param success Whether or not the operation went well. @param message Any error message to stick into the log. @return entry_id } { set success_p_db [ad_decode $success_p 1 "t" "f"] set entry_id [db_nextval "auth_batch_job_entry_id_seq"] db_dml insert_entry {} -clobs [list $element_messages] return $entry_id } ad_proc -public auth::sync::job::get_entry { {-entry_id:required} {-array:required} } { Get information about a log entry } { upvar 1 $array row db_1row select_entry { select e.entry_id, e.job_id, e.entry_time, e.operation, j.authority_id, e.username, e.user_id, e.success_p, e.message, e.element_messages from auth_batch_job_entries e, auth_batch_jobs j where e.entry_id = :entry_id and j.job_id = e.job_id } -column_array row } ad_proc -public auth::sync::job::action { {-job_id:required} {-operation:required} {-username:required} {-array ""} } { Inserts/updates/deletes a user, depending on the operation. @param job_id The job which this is part of for logging purposes. @param operation 'insert', 'update', 'delete', or 'snapshot'. @param username The username which this action refers to. @param array Name of an array containing the relevant registration elements. Not required if this is a delete operation. @return entry_id of newly created entry } { if { $operation ne "delete" && $array eq "" } { error "Switch -array is required when operation is not delete" } upvar 1 $array user_info set entry_id {} set user_id {} set authority_id [get_authority_id -job_id $job_id] db_transaction { set user_id [acs_user::get_by_username \ -authority_id $authority_id \ -username $username] set success_p 1 array set result { message {} element_messages {} } switch $operation { snapshot { if { $user_id ne "" } { # user exists, it's an update set operation "update" } else { # user does not exist, it's an insert set operation "insert" } } update - delete { if { $user_id eq "" } { # Updating/deleting a user that doesn't exist set success_p 0 set result(message) "A user with username '$username' does not exist" } else { acs_user::get -user_id $user_id -array existing_user_info if {$existing_user_info(member_state) eq "banned"} { # Updating/deleting a user that's already deleted set success_p 0 set result(message) "The user with username '$username' has been deleted (banned)" } } } insert { if { $user_id ne "" } { acs_user::get -user_id $user_id -array existing_user_info if { $existing_user_info(member_state) ne "banned" } { # Inserting a user that already exists (and is not deleted) set success_p 0 set result(message) "A user with username '$username' already exists" } } } } # Only actually perform the action if we didn't already encounter a problem if { $success_p } { with_catch errmsg { switch $operation { "insert" { # We set email_verified_p to 't', because we trust the email we get from the remote system set user_info(email_verified_p) t array set result [auth::create_local_account \ -authority_id $authority_id \ -username $username \ -array user_info] if { $result(creation_status) ne "ok" } { set result(message) $result(creation_message) set success_p 0 } else { set user_id $result(user_id) set add_to_dotlrn_p [parameter::get_from_package_key \ -parameter SyncAddUsersToDotLrnP \ -package_key "acs-authentication" \ -default 0] if { $add_to_dotlrn_p } { # Add user to .LRN # Beware that this creates a portal and lots of other things for each user set type [parameter::get_from_package_key \ -parameter SyncDotLrnUserType \ -package_key "acs-authentication" \ -default "student"] set can_browse_p [parameter::get_from_package_key \ -parameter SyncDotLrnAccessLevel \ -package_key "acs-authentication" \ -default 1] set read_private_data_p [parameter::get_from_package_key \ -parameter SyncDotLrnReadPrivateDataP \ -package_key "acs-authentication" \ -default 1] dotlrn::user_add \ -id $user_info(email) \ -type $type \ -can_browse=$can_browse_p \ -user_id $user_id dotlrn_privacy::set_user_is_non_guest \ -user_id $user_id \ -value $read_private_data_p } } # We ignore account_status } "update" { # We set email_verified_p to 't', because we trust the email we get from the remote system set user_info(email_verified_p) t array set result [auth::update_local_account \ -authority_id $authority_id \ -username $username \ -array user_info] if { $result(update_status) ne "ok" } { set result(message) $result(update_message) set success_p 0 } else { set user_id $result(user_id) } } "delete" { array set result [auth::delete_local_account \ -authority_id $authority_id \ -username $username] if { $result(delete_status) ne "ok" } { set result(message) $result(delete_message) set success_p 0 } else { set user_id $result(user_id) } } } } { # Get errorInfo and log it global errorInfo ns_log Error "Error during batch syncrhonization job:\n$errorInfo" set success_p 0 set result(message) $errorInfo } } # Make a log entry set entry_id [auth::sync::job::create_entry \ -job_id $job_id \ -operation $operation \ -username $username \ -user_id $user_id \ -success=$success_p \ -message $result(message) \ -element_messages $result(element_messages)] } return $entry_id } ad_proc -public auth::sync::job::snapshot_delete_remaining { {-job_id:required} } { Deletes the users that weren't included in the snapshot. } { set authority_id [get_authority_id -job_id $job_id] set usernames [db_list select_user_ids { select username from cc_users where authority_id = :authority_id and user_id not in (select user_id from auth_batch_job_entries where job_id = :job_id and authority_id = :authority_id) and member_state != 'banned' }] foreach username $usernames { auth::sync::job::action \ -job_id $job_id \ -operation "delete" \ -username $username } } ##### # # auth::sync namespace # ##### ad_proc -public auth::sync::purge_jobs { {-num_days ""} } { Purge jobs that are older than KeepBatchLogDays days. } { if { ![exists_and_not_null num_days] } { set num_days [parameter::get_from_package_key \ -parameter KeepBatchLogDays \ -package_key "acs-authentication" \ -default 0] } validate_integer num_days $num_days if { $num_days > 0 } { db_dml purge_jobs {} } } ad_proc -private auth::sync::get_sync_elements { {-user_id ""} {-authority_id ""} } { Get a Tcl list of the user profile elements controlled by the batch synchronization. These should not be editable by the user. Supply either user_id or authority_id. Authority_id is the most efficient. } { if { $authority_id eq "" } { if { $user_id eq "" } { error "You must supply either user_id or authority_id" } set authority_id [acs_user::get_element -user_id $user_id -element authority_id] } set elms [list] with_catch errmsg { set elms [auth::sync::GetElements -authority_id $authority_id] } {} return $elms } ad_proc -private auth::sync::sweeper {} { db_foreach select_authorities { select authority_id from auth_authorities where enabled_p = 't' and batch_sync_enabled_p = 't' } { auth::authority::batch_sync \ -authority_id $authority_id } } ad_proc -private auth::sync::GetDocument { {-authority_id:required} } { Wrapper for the GetDocument operation of the auth_sync_retrieve service contract. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "get_doc_impl_id"] if { $impl_id eq "" } { # No implementation of GetDocument set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support GetDocument" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_sync_retrieve" \ -impl_id $impl_id \ -operation GetDocument \ -call_args [list $parameters]] } ad_proc -private auth::sync::ProcessDocument { {-authority_id:required} {-job_id:required} {-document:required} } { Wrapper for the ProcessDocument operation of the auth_sync_process service contract. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "process_doc_impl_id"] if { $impl_id eq "" } { # No implementation of auth_sync_process set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support auth_sync_process" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_sync_process" \ -impl_id $impl_id \ -operation ProcessDocument \ -call_args [list $job_id $document $parameters]] } ad_proc -private auth::sync::GetAcknowledgementDocument { {-authority_id:required} {-job_id:required} {-document:required} } { Wrapper for the GetAckDocument operation of the auth_sync_process service contract. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "process_doc_impl_id"] if { $impl_id eq "" } { # No implementation of auth_sync_process set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support auth_sync_process" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_sync_process" \ -impl_id $impl_id \ -operation GetAcknowledgementDocument \ -call_args [list $job_id $document $parameters]] } ad_proc -private auth::sync::GetElements { {-authority_id:required} } { Wrapper for the GetElements operation of the auth_sync_process service contract. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "process_doc_impl_id"] if { $impl_id eq "" } { # No implementation of auth_sync_process set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support auth_sync_process" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_sync_process" \ -impl_id $impl_id \ -operation GetElements \ -call_args [list $parameters]] } ##### # # auth::sync::get_doc::http namespace # ##### ad_proc -private auth::sync::get_doc::http::register_impl {} { Register this implementation } { set spec { contract_name "auth_sync_retrieve" owner "acs-authentication" name "HTTPGet" pretty_name "HTTP GET" aliases { GetDocument auth::sync::get_doc::http::GetDocument GetParameters auth::sync::get_doc::http::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::sync::get_doc::http::unregister_impl {} { Unregister this implementation } { acs_sc::impl::delete -contract_name "auth_sync_retrieve" -impl_name "HTTPGet" } ad_proc -private auth::sync::get_doc::http::GetParameters {} { Parameters for HTTP GetDocument implementation. } { return { IncrementalURL {The URL from which to retrieve document for incremental update. Will retrieve this most of the time.} SnapshotURL {The URL from which to retrieve document for snapshot update. If specified, will get this once per month.} } } ad_proc -private auth::sync::get_doc::http::GetDocument { parameters } { Retrieve the document by HTTP } { array set result { doc_status failed_to_conntect doc_message {} document {} snapshot_p f } array set param $parameters if { ($param(SnapshotURL) ne "" && [string equal [clock format [clock seconds] -format "%d"] "01"]) || \ $param(IncrementalURL) eq "" } { # On the first day of the month, we get a snapshot set url $param(SnapshotURL) set result(snapshot_p) "t" } else { # All the other days of the month, we get the incremental set url $param(IncrementalURL) } if { $url eq "" } { error "You must specify at least one URL to get." } set result(document) [util_httpget $url] set result(doc_status) "ok" return [array get result] } ##### # # auth::sync::get_doc::file namespace # ##### ad_proc -private auth::sync::get_doc::file::register_impl {} { Register this implementation } { set spec { contract_name "auth_sync_retrieve" owner "acs-authentication" name "LocalFilesystem" pretty_name "Local Filesystem" aliases { GetDocument auth::sync::get_doc::file::GetDocument GetParameters auth::sync::get_doc::file::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::sync::get_doc::file::unregister_impl {} { Unregister this implementation } { acs_sc::impl::delete -contract_name "auth_sync_retrieve" -impl_name "LocalFilesystem" } ad_proc -private auth::sync::get_doc::file::GetParameters {} { Parameters for FILE GetDocument implementation. } { return { IncrementalPath {The path to the document for incremental update. Will retrieve this most of the time.} SnapshotPath {The path to the document for snapshot update. If specified, will get this once per month.} } } ad_proc -private auth::sync::get_doc::file::GetDocument { parameters } { Retrieve the document from local file system } { array set result { doc_status failed_to_conntect doc_message {} document {} snapshot_p f } array set param $parameters if { ($param(SnapshotPath) ne "" && [string equal [clock format [clock seconds] -format "%d"] "01"]) || \ $param(IncrementalPath) eq "" } { # On the first day of the month, we get a snapshot set path $param(SnapshotPath) set result(snapshot_p) "t" } else { # All the other days of the month, we get the incremental set path $param(IncrementalPath) } if { $path eq "" } { error "You must specify at least one path to get." } set result(document) [template::util::read_file $path] set result(doc_status) "ok" return [array get result] } ##### # # auth::sync::process_doc::ims namespace # ##### ad_proc -private auth::sync::process_doc::ims::register_impl {} { Register this implementation } { set spec { contract_name "auth_sync_process" owner "acs-authentication" name "IMS_Enterprise_v_1p1" pretty_name "IMS Enterprise 1.1" aliases { ProcessDocument auth::sync::process_doc::ims::ProcessDocument GetAcknowledgementDocument auth::sync::process_doc::ims::GetAcknowledgementDocument GetElements auth::sync::process_doc::ims::GetElements GetParameters auth::sync::process_doc::ims::GetParameters } } return [acs_sc::impl::new_from_spec -spec $spec] } ad_proc -private auth::sync::process_doc::ims::unregister_impl {} { Unregister this implementation } { acs_sc::impl::delete -contract_name "auth_sync_process" -impl_name "IMS_Enterprise_v_1p1" } ad_proc -private auth::sync::process_doc::ims::GetParameters {} { Parameters for IMS Enterprise 1.1 auth_sync_process implementation. } { return { Elements {List of elements covered by IMS batch synchronization, which we should prevent users from editing in OpenACS. Example: 'username email first_names last_name url'.} } } ad_proc -private auth::sync::process_doc::ims::GetElements { parameters } { Elements controlled by IMS Enterprise 1.1 auth_sync_process implementation. } { array set param $parameters return $param(Elements) } ad_proc -private auth::sync::process_doc::ims::ProcessDocument { job_id document parameters } { Process IMS Enterprise 1.1 document. } { set tree [xml_parse -persist $document] set root_node [xml_doc_get_first_node $tree] if { [xml_node_get_name $root_node] ne "enterprise" } { error "Root node was not " } # Loop over records foreach person_node [xml_node_get_children_by_name $root_node "person"] { switch [xml_node_get_attribute $person_node "recstatus"] { 1 { set operation "insert" } 2 { set operation "update" } 3 { set operation "delete" } default { set operation "snapshot" } } # Initialize this record array unset user_info set username [xml_get_child_node_content_by_path $person_node { { userid } { sourcedid id } }] set user_info(email) [xml_get_child_node_content_by_path $person_node { { email } }] set user_info(url) [xml_get_child_node_content_by_path $person_node { { url } }] # We need a little more logic to deal with first_names/last_name, since they may not be split up in the XML set user_info(first_names) [xml_get_child_node_content_by_path $person_node { { name n given } }] set user_info(last_name) [xml_get_child_node_content_by_path $person_node { { name n family } }] if { $user_info(first_names) eq "" || $user_info(last_name) eq "" } { set formatted_name [xml_get_child_node_content_by_path $person_node { { name fn } }] if { $formatted_name ne "" || [string first " " $formatted_name] > -1 } { # Split, so everything up to the last space goes to first_names, the rest to last_name regexp {^(.+) ([^ ]+)$} $formatted_name match user_info(first_names) user_info(last_name) } } auth::sync::job::action \ -job_id $job_id \ -operation $operation \ -username $username \ -array user_info } } ad_proc -public auth::sync::process_doc::ims::GetAcknowledgementDocument { job_id document parameters } { Generates an record-wise acknolwedgement document in home-brewed adaptation of the IMS Enterprise v 1.1 spec. } { set tree [xml_parse -persist $document] set root_node [xml_doc_get_first_node $tree] if { [xml_node_get_name $root_node] ne "enterprise" } { error "Root node was not " } set timestamp [xml_get_child_node_content_by_path $root_node { { properties datetime } }] append doc {} \n append doc {} \n append doc { } \n append doc { acknowledgement} \n append doc { } $timestamp {} \n append doc { } \n array set recstatus { insert 1 update 2 delete 3 } # Loop over successful actions db_foreach select_success_actions { select entry_id, operation, username from auth_batch_job_entries where job_id = :job_id and success_p = 't' order by entry_id } { if { [info exists recstatus($operation)] } { append doc { } \n append doc { OpenACS} $username {} \n append doc { } \n } else { ns_log Error "Illegal operation encountered in job action log: '$operation'. Entry_id is '$entry_id'." } } append doc {} \n return $doc } openacs-5.7.0/packages/acs-authentication/tcl/sync-procs.xql0000644000175000017500000000150507730117237023754 0ustar frankiefrankie select e.entry_id, to_char(e.entry_time, 'YYYY-MM-DD HH24:MI:SS') as entry_time, e.operation, a.authority_id, a.pretty_name as authority_pretty_name, e.job_id, e.username, e.user_id, e.success_p, e.message, e.element_messages from auth_batch_job_entries e, auth_authorities a, auth_batch_jobs j where e.entry_id = :entry_id and e.job_id = j.job_id and j.authority_id = a.authority_id openacs-5.7.0/packages/acs-authentication/tcl/sync-init.tcl0000644000175000017500000000103507727344077023557 0ustar frankiefrankiead_library { Set up scheduled procs for running nightly batch sync, and for purging old logs. @cvs-id $Id: sync-init.tcl,v 1.1 2003/09/09 12:31:59 lars Exp $ @author Lars Pind (lars@collaboraid.biz) @creation-date 2003-09-09 } # Schedule old job log purge ad_schedule_proc \ -thread t \ -schedule_proc ns_schedule_daily \ [list 0 30] \ auth::sync::purge_jobs # Schedule batch sync sweeper ad_schedule_proc \ -thread t \ -schedule_proc ns_schedule_daily \ [list 1 0] \ auth::sync::sweeper openacs-5.7.0/packages/acs-authentication/tcl/driver-procs.tcl0000644000175000017500000000543310551254371024251 0ustar frankiefrankiead_library { Procs for driver paramaters service contract implementations. @author Simon Carstensen (simon@collaobraid.biz) @creation-date 2003-08-27 @cvs-id $Id: driver-procs.tcl,v 1.7 2007/01/10 21:22:01 gustafn Exp $ } namespace eval auth {} namespace eval auth::driver {} ##### # # auth::driver # ##### ad_proc -public auth::driver::get_parameters { {-impl_id:required} } { Returns a list of names of parameters for the driver @author Simon Carstensen (simon@collaboraid.biz) @creation-date 2003-08-27 } { if { $impl_id eq "" } { return {} } set parameters {} with_catch errmsg { set parameters [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation GetParameters] } { global errorInfo ns_log Error "Error getting parameters for impl_id $impl_id: $errmsg\n$errorInfo" } return $parameters } ad_proc -public auth::driver::get_parameter_values { {-authority_id:required} {-impl_id:required} } { Gets a list of parameter values ready to be passed to a service contract implementation. If a parameter doesn't have a value, the value will be the empty string. @author Simon Carstensen (simon@collaboraid.biz) @creation-date 2003-08-27 } { array set param [list] db_foreach select_values { select key, value from auth_driver_params where impl_id = :impl_id and authority_id = :authority_id } { set param($key) $value } # We need to ensure that the driver gets all the parameters it is asking for, and nothing but the ones it is asking for set params [list] foreach { name desc } [get_parameters -impl_id $impl_id] { if { [info exists param($name)] } { lappend params $name $param($name) } else { lappend params $name {} } } return $params } ad_proc -public auth::driver::set_parameter_value { {-authority_id:required} {-impl_id:required} {-parameter:required} {-value:required} } { Updates the parameter value in the database. @author Simon Carstensen (simon@collaboraid.biz) @creation-date 2003-08-27 } { set exists_p [db_string param_exists_p {}] if { $exists_p } { db_dml update_parameter {} -clobs [list $value] } else { db_dml insert_parameter {} -clobs [list $value] } } ad_proc -public auth::driver::GetParameters { {-impl_id:required} } { Returns a list of names of parameters for the driver @author Simon Carstensen (simon@collaboraid.biz) @creation-date 2003-08-27 } { return [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation GetParameters] } openacs-5.7.0/packages/acs-authentication/tcl/driver-procs.xql0000644000175000017500000000055707725442334024304 0ustar frankiefrankie select count(*) from auth_driver_params where impl_id = :impl_id and authority_id = :authority_id and key = :parameter openacs-5.7.0/packages/acs-authentication/tcl/password-procs.tcl0000644000175000017500000006726511323323014024620 0ustar frankiefrankiead_library { Tcl API for password management. @author Lars Pind (lars@collaobraid.biz) @creation-date 2003-09-03 @cvs-id $Id: password-procs.tcl,v 1.18 2010/01/13 10:53:00 emmar Exp $ } namespace eval auth::password {} ##### # # auth::password public procs # ##### ad_proc -public auth::password::get_change_url { {-user_id:required} } { Returns the URL to redirect to for changing passwords. If the user's authority has a "change_pwd_url" set, it'll return that, otherwise it'll return a link to /user/password-update under the nearest subsite. @param user_id The ID of the user whose password you want to change. @return A URL that can be linked to for changing password. } { db_1row select_vars { select aa.change_pwd_url, u.username from auth_authorities aa, users u where aa.authority_id = u.authority_id and u.user_id = :user_id } # Interpolate any username variable in URL regsub -all "{username}" $change_pwd_url $username change_pwd_url # Default to the OpenACS change password URL if { $change_pwd_url eq "" } { set change_pwd_url [export_vars -base "[subsite::get_element -element url]user/password-update" { user_id }] } return $change_pwd_url } ad_proc -public auth::password::can_change_p { {-user_id:required} } { Returns whether we can change the password for the given user. This depends on the user's authority and the configuration of that authority. @param user_id The ID of the user whose password you want to change. @return 1 if the user can change password, 0 otherwise. } { set authority_id [acs_user::get_element -user_id $user_id -element authority_id] set result_p 0 with_catch errmsg { set result_p [auth::password::CanChangePassword -authority_id $authority_id] } { global errorInfo ns_log Error "Error invoking CanChangePassword operation for authority_id $authority_id:\n$errorInfo" } return $result_p } ad_proc -public auth::password::change { {-user_id:required} {-old_password:required} {-new_password:required} } { Change the user's password. @param user_id The ID of the user whose password you want to change. @param old_password The current password of that user. This is required for security purposes. @param new_password The desired new password of the user. @return An array list with the following entries:
    • password_status: "ok", "no_account", "not_supported", "old_password_bad", "new_password_bad", "change_error", "failed_to_connect"
    • password_message: A human-readable description of what went wrong.
    } { acs_user::get -user_id $user_id -array user with_catch errmsg { array set result [auth::password::ChangePassword \ -authority_id $user(authority_id) \ -username $user(username) \ -new_password $new_password \ -old_password $old_password ] # We do this so that if there aren't even a password_status in the array, that gets caught below set dummy $result(password_status) } { set result(password_status) failed_to_connect set result(password_message) $errmsg global errorInfo ns_log Error "Error invoking password management driver for authority_id = $user(authority_id):\n$errorInfo" } # Check the result code and provide canned responses switch $result(password_status) { ok { # Invalidate existing login tokens sitting on random other browsers out there set connection_user_id [ad_conn user_id] sec_change_user_auth_token $user_id # Refresh the current user's cookies, so he doesn't get logged out, # if this user was logged in before changing password if { [ad_conn isconnected] && $user_id == $connection_user_id } { ad_user_login -account_status [ad_conn account_status] $user_id } } no_account - not_supported - old_password_bad - new_password_bad - change_error - failed_to_connect { if { ![exists_and_not_null result(password_message)] } { array set default_message { no_account {Unknown username} not_supported {This operation is not supported} old_password_bad {Current password incorrect} new_password_bad {New password not accepted} change_error {Error changing password} failed_to_connect {Error communicating with authentication server} } set result(password_message) $default_message($result(password_status)) } } default { set result(password_status) "failed_to_connect" set result(password_message) "Illegal code returned from password management driver" ns_log Error "Error invoking password management driver for authority_id = $user(authority_id): Illegal return code from driver: $result(password_status)" } } return [array get result] } ad_proc -public auth::password::recover_password { {-authority_id ""} {-username ""} {-email ""} } { Handles forgotten passwords. Attempts to retrieve a password; if not possibe, attempts to reset a password. If it succeeds, it emails the user. For all outcomes, it returns a message to be displayed. @param authority_id The ID of the authority that the user is trying to log into. @param username The username that the user's trying to log in with. @param email Email can be supplied instead of authority_id and username. @return Array list with the following entries:
    • password_status: ok, no_support, failed_to_connect
    • password_message: Human-readable message to be relayed to the user. May contain HTML.
    } { if { $username eq "" } { if { $email eq "" } { set result(password_status) "failed_to_connect" if { [auth::UseEmailForLoginP] } { set result(password_message) "Email required" } else { set result(password_message) "Username required" } return [array get result] } set user_id [cc_lookup_email_user $email] if { $user_id eq "" } { set result(password_status) "failed_to_connect" set result(password_message) "Unknown email" return [array get result] } acs_user::get -user_id $user_id -array user set authority_id $user(authority_id) set username $user(username) } else { # Default to local authority if { $authority_id eq "" } { set authority_id [auth::authority::local] } } set forgotten_url [auth::password::get_forgotten_url \ -remote_only \ -authority_id $authority_id \ -username $username] if { $forgotten_url ne "" } { ad_returnredirect -allow_complete_url $forgotten_url ad_script_abort } if { [auth::password::can_retrieve_p -authority_id $authority_id] } { array set result [auth::password::retrieve \ -authority_id $authority_id \ -username $username] } elseif { [auth::password::can_reset_p -authority_id $authority_id] } { array set result [auth::password::reset \ -authority_id $authority_id \ -username $username] } else { # Can't reset or retrieve - we give up set result(password_status) "not_supported" set result(password_message) [_ acs-subsite.sorry_forgotten_pwd] } return [array get result] } ad_proc -public auth::password::get_forgotten_url { {-authority_id ""} {-username ""} {-email ""} {-remote_only:boolean} } { Returns the URL to redirect to for forgotten passwords. @param authority_id The ID of the authority that the user is trying to log into. @param username The username that the user's trying to log in with. @param remote_only If provided, only return any remote URL (not on this server). @return A URL that can be linked to when the user has forgotten his/her password, or the empty string if none can be found. } { if { $username ne "" } { set local_url [export_vars -no_empty -base "[subsite::get_element -element url]register/recover-password" { authority_id username }] } else { set local_url [export_vars -no_empty -base "[subsite::get_element -element url]register/recover-password" { email }] } set forgotten_pwd_url {} if { $username ne "" } { if { $authority_id eq "" } { set authority_id [auth::authority::local] } } else { set user_id [cc_lookup_email_user $email] if { $user_id ne "" } { acs_user::get -user_id $user_id -array user set authority_id $user(authority_id) set username $user(username) } } if { $username ne "" } { # We have the username or email set forgotten_pwd_url [auth::authority::get_element -authority_id $authority_id -element forgotten_pwd_url] if { $forgotten_pwd_url ne "" } { regsub -all "{username}" $forgotten_pwd_url $username forgotten_pwd_url } elseif { !$remote_only_p } { if { [auth::password::can_retrieve_p -authority_id $authority_id] || [auth::password::can_reset_p -authority_id $authority_id] } { set forgotten_pwd_url $local_url } } } else { # We don't have the username if { !$remote_only_p } { set forgotten_pwd_url "[subsite::get_element -element url]register/recover-password" } } return $forgotten_pwd_url } ad_proc -public auth::password::can_retrieve_p { {-authority_id:required} } { Returns whether the given authority can retrive forgotten passwords. @param authority_id The ID of the authority that the user is trying to log into. @return 1 if the authority allows retrieving passwords, 0 otherwise. } { set result_p 0 with_catch errmsg { set result_p [auth::password::CanRetrievePassword \ -authority_id $authority_id] } { global errorInfo ns_log Error "Error invoking CanRetrievePassword operation for authority_id $authority_id:\n$errorInfo" return 0 } return $result_p } ad_proc -public auth::password::retrieve { {-authority_id:required} {-username:required} } { Retrieve the user's password. @param authority_id The ID of the authority that the user is trying to log into. @param username The username that the user's trying to log in with. @return An array list with the following entries:
    • password_status: ok, no_account, not_supported, retrieve_error, failed_to_connect
    • password_message: A human-readable message to be relayed to the user. May be empty if password_status is ok. May include HTML.
    • password: The retrieved password.
    } { with_catch errmsg { array set result [auth::password::RetrievePassword \ -authority_id $authority_id \ -username $username] # We do this so that if there aren't even a password_status in the array, that gets caught below set dummy $result(password_status) } { set result(password_status) failed_to_connect set result(password_message) "Error invoking the password management driver." global errorInfo ns_log Error "Error invoking password management driver for authority_id = $authority_id: $errorInfo" } # Check the result code and provide canned responses switch $result(password_status) { ok { if { [exists_and_not_null result(password)] } { # We have retrieved or reset a forgotten password that we should email to the user with_catch errmsg { auth::password::email_password \ -authority_id $authority_id \ -username $username \ -password $result(password) \ -subject_msg_key "acs-subsite.email_subject_Forgotten_password" \ -body_msg_key "acs-subsite.email_body_Forgotten_password" } { # We could not inform the user of his email - we failed set result(password_status) "failed_to_connect" set result(password_message) [_ acs-subsite.Error_sending_mail] global errorInfo ns_log Error "We had an error sending out email with new password to username $username, authority $authority_id:\n$errorInfo" } } if { ![exists_and_not_null result(password_message)] } { set result(password_message) [_ acs-subsite.Check_Your_Inbox] } } no_account - not_supported - retrieve_error - failed_to_connect { if { ![exists_and_not_null result(password_message)] } { array set default_message { no_account {Unknown username} not_supported {This operation is not supported} retrieve_error {Error retrieving password} failed_to_connect {Error communicating with authentication server} } set result(password_message) $default_message($result(password_status)) } } default { set result(password_status) "failed_to_connect" set result(password_message) "Illegal error code returned from password management driver" } } return [array get result] } ad_proc -public auth::password::can_reset_p { {-authority_id:required} } { Returns whether the given authority can reset forgotten passwords. @param authority_id The ID of the authority that the user is trying to log into. @return 1 if the authority allows resetting passwords, 0 otherwise. } { set result_p 0 with_catch errmsg { set result_p [auth::password::CanResetPassword \ -authority_id $authority_id] } { global errorInfo ns_log Error "Error invoking CanResetPassword operation for authority_id $authority_id:\n$errorInfo" } return $result_p } ad_proc -public auth::password::reset { {-admin:boolean} {-authority_id:required} {-username:required} } { Reset the user's password, which means setting it to a new randomly generated password and inform the user of that new password. @param admin Specify this flag if this call represents an admin changing a user's password. @param authority_id The authority of the user @param username The username of the user @return An array list with the following entries:
    • password_status: ok, no_account, not_supported, reset_error, failed_to_connect
    • password_message: A human-readable message to be relayed to the user. May be empty if password_status is ok. May include HTML. Could be empty if password_status is ok.
    • password: The new, automatically generated password. If no password is included in the return array, that means the new password has already been sent to the user somehow. If it is returned, it means that caller is responsible for informing the user of his/her new password.
    } { with_catch errmsg { array set result [auth::password::ResetPassword \ -authority_id $authority_id \ -username $username] # We do this so that if there aren't even a password_status in the array, that gets caught below set dummy $result(password_status) } { set result(password_status) failed_to_connect set result(password_message) "Error invoking the password management driver." global errorInfo ns_log Error "Error invoking password management driver for authority_id = $authority_id: $errorInfo" } # Check the result code and provide canned responses switch $result(password_status) { ok { if { [exists_and_not_null result(password)] && \ (!$admin_p || [parameter::get \ -parameter EmailChangedPasswordP \ -package_id [ad_conn subsite_id] \ -default 1]) } { # We have retrieved or reset a forgotten password that we should email to the user with_catch errmsg { auth::password::email_password \ -authority_id $authority_id \ -username $username \ -password $result(password) \ -subject_msg_key "acs-subsite.email_subject_Forgotten_password" \ -body_msg_key "acs-subsite.email_body_Forgotten_password" } { # We could not inform the user of his email - we failed set result(password_status) "failed_to_connect" set result(password_message) [_ acs-subsite.Error_sending_mail] global errorInfo ns_log Error "We had an error sending out email with new password to username $username, authority $authority_id:\n$errorInfo" } } if { ![exists_and_not_null result(password_message)] } { set result(password_message) [_ acs-subsite.Check_Your_Inbox] } } no_account - not_supported - retrieve_error - failed_to_connect { if { ![exists_and_not_null result(password_message)] } { array set default_message { no_account {Unknown username} not_supported {This operation is not supported} reset_error {Error resetting password} failed_to_connect {Error communicating with authentication server} } set result(password_message) $default_message($result(password_status)) } } default { set result(password_status) "failed_to_connect" set result(password_message) "Illegal error code returned from password management driver" } } return [array get result] } ##### # # auth::password private procs # ##### ad_proc -private auth::password::email_password { {-username:required} {-authority_id:required} {-password:required} {-subject_msg_key "acs-subsite.email_subject_Forgotten_password"} {-body_msg_key "acs-subsite.email_body_Forgotten_password"} {-from ""} } { Send an email to ther user with given username and authority with the new password. @param from The email's from address. Can be in email@foo.com format. Defaults to ad_system_owner. @param subject_msg_key The message key you wish to use for the email subject. @param body_msg_key The message key you wish to use for the email body. @return Does not return anything. Any errors caused by acs_mail_lite::send are propagated @author Peter Marklund } { set user_id [acs_user::get_by_username -authority_id $authority_id -username $username] acs_user::get -user_id $user_id -array user # Set up variables for use in message key set reset_password_url [export_vars -base "[ad_url]/user/password-update" {user_id {old_password $password}}] set system_owner [ad_system_owner] set system_name [ad_system_name] set system_url [ad_url] if { [auth::UseEmailForLoginP] } { set account_id_label [_ acs-subsite.Email] set account_id $user(email) } else { set account_id_label [_ acs-subsite.Username] set account_id $user(username) } # Hm, all this crummy code, just to justify the colons in the email body set password_label [_ acs-subsite.Password] if { [string length $password_label] > [string length $account_id_label] } { set length [string length $password_label] } else { set length [string length $account_id_label] } set account_id_label [string range "$account_id_label[string repeat " " $length]" 0 [expr {$length-1}]] set password_label [string range "$password_label[string repeat " " $length]" 0 [expr {$length-1}]] set first_names $user(first_names) set last_name $user(last_name) if { [ad_conn untrusted_user_id] != 0 } { acs_user::get -user_id [ad_conn untrusted_user_id] -array admin_user set admin_first_names $admin_user(first_names) set admin_last_name $admin_user(last_name) } else { set admin_first_names {} set admin_last_name {} } set subject [_ $subject_msg_key] set body [_ $body_msg_key] if { $from eq "" } { set from [ad_system_owner] } # Send email acs_mail_lite::send -send_immediately \ -to_addr $user(email) \ -from_addr $system_owner \ -subject $subject \ -body $body } ad_proc -private auth::password::CanChangePassword { {-authority_id:required} } { Invoke the CanChangePassword operation on the given authority. Returns 0 if the authority does not have a password management driver. @param authority_id The ID of the authority that we are inquiring about. @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "pwd_impl_id"] if { $impl_id eq "" } { return 0 } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_password" \ -impl_id $impl_id \ -operation CanChangePassword \ -call_args [list $parameters]] } ad_proc -private auth::password::CanRetrievePassword { {-authority_id:required} } { Invoke the CanRetrievePassword operation on the given authority. Returns 0 if the authority does not have a password management driver. @param authority_id The ID of the authority that we are inquiring about. @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "pwd_impl_id"] if { $impl_id eq "" } { return 0 } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_password" \ -impl_id $impl_id \ -operation CanRetrievePassword \ -call_args [list $parameters]] } ad_proc -private auth::password::CanResetPassword { {-authority_id:required} } { Invoke the CanResetPassword operation on the given authority. Returns 0 if the authority does not have a password management driver. @param authority_id The ID of the authority that we are inquiring about. @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "pwd_impl_id"] if { $impl_id eq "" } { return 0 } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_password" \ -impl_id $impl_id \ -operation CanResetPassword \ -call_args [list $parameters]] } ad_proc -private auth::password::ChangePassword { {-username:required} {-old_password ""} {-new_password:required} {-authority_id:required} } { Invoke the ChangePassword operation on the given authority. Throws an error if the authority does not have a password management driver. @param username @param old_password @param new_password @param authority_id The ID of the authority the user belongs to. @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "pwd_impl_id"] if { $impl_id eq "" } { set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support password management" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_password" \ -impl_id $impl_id \ -operation ChangePassword \ -call_args [list $username \ $new_password \ $old_password \ $parameters \ $authority_id]] } ad_proc -private auth::password::RetrievePassword { {-username:required} {-authority_id:required} } { Invoke the RetrievePassword operation on the given authority. Throws an error if the authority does not have a password management driver. @param username @param authority_id The ID of the authority the user belongs to. @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "pwd_impl_id"] if { $impl_id eq "" } { set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support password management" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_password" \ -impl_id $impl_id \ -operation RetrievePassword \ -call_args [list $username \ $parameters]] } ad_proc -private auth::password::ResetPassword { {-username:required} {-authority_id ""} } { Invoke the ResetPassword operation on the given authority. Throws an error if the authority does not have a password management driver. @param username @param authority_id The ID of the authority the user belongs to. @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "pwd_impl_id"] if { $impl_id eq "" } { set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support password management" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -contract "auth_password" \ -impl_id $impl_id \ -operation ResetPassword \ -call_args [list $username \ $parameters \ $authority_id]] } openacs-5.7.0/packages/acs-authentication/tcl/authentication-procs.tcl0000644000175000017500000020033311466101426025767 0ustar frankiefrankiead_library { Tcl API for authentication, account management, and account registration. @author Lars Pind (lars@collaobraid.biz) @creation-date 2003-05-13 @cvs-id $Id: authentication-procs.tcl,v 1.87 2010/11/08 23:09:10 victorg Exp $ } namespace eval auth {} namespace eval auth::authentication {} namespace eval auth::registration {} namespace eval auth::user_info {} ##### # # auth namespace public procs # ##### ad_proc -public auth::require_login { {-level ok} {-account_status ok} } { If the current session is not authenticated, redirect to the login page, and aborts the current page script. Otherwise, returns the user_id of the user logged in. Use this in a page script to ensure that only registered and authenticated users can execute the page, for example for posting to a forum. @return user_id of user, if the user is logged in. Otherwise will issue a returnredirect and abort the current page. @see ad_script_abort } { set user_id [auth::get_user_id \ -level $level \ -account_status $account_status] if { $user_id != 0 } { # user is in fact logged in, return user_id return $user_id } set message {} if {[ad_conn auth_level] eq "expired"} { set message [_ acs-subsite.lt_Your_login_has_expire] } set return_url [ad_get_login_url -return] # Long URLs (slightly above 4000 bytes) can kill aolserver-4.0.10, causing # a restart. They lead to empty Bowser-windows with aolserver 4.5 (but no # crash so far). May browsers have length limitations for URLs. E.g. # 2083 is the documented maximal length of MSIE. # # Long URLs will be generated e.g. when # a) a user edits a form with text entries # b) before submitting the form logs out of OpenACS from a different browser window # c) submits the form. # When submitting needs authentication, OpenACS generates the redirect to # /register with the form-data coded into the URL to continue there..... # set user_agent [string tolower [ns_set get [ns_conn headers] User-Agent]] # ns_log notice "URL have url, len=[string length $return_url] $user_agent" if {[expr {[string length $return_url] > 2083}]} { set message "Your login expired and the computed URL for automated continuation is too long. " append message "If you were editing a from, please use the back button after logging in and resubmit the form." set return_url [ad_get_login_url] } # The -return switch causes the URL to return to the current page ad_returnredirect -message $message -- $return_url ad_script_abort } ad_proc -public auth::refresh_login {} { If there currently is a user associated with this session, but the user's authentication is expired, redirect the user to refresh his/her login. This allows for users to not be logged in, but if the user is logged in, then we require that the authentication is not expired. @return user_id of user, if the user is logged in and auth_status is not expired, or 0 if the user is not logged in. If user's auth_status is expired, this proc will issue a returnredirect and abort the current page. @see ad_script_abort } { if { [ad_conn auth_level] ne "expired" } { return [ad_conn user_id] } # The -return switch causes the URL to return to the current page ad_returnredirect [ad_get_login_url -return] ad_script_abort } ad_proc -public auth::self_registration {} { Check AllowSelfRegister parameter and set user message if self registration not allowed. } { if { [string is false [parameter::get_from_package_key \ -package_key acs-authentication \ -parameter AllowSelfRegister]] } { util_user_message -message "Self registration is not allowed" auth::require_login } } ad_proc -public auth::get_user_id { {-level ok} {-account_status ok} } { Get the current user_id with at least the level of security specified. If no user is logged in, or the user is not logged in at a sufficiently high security level, return 0. @return user_id of user, if the user is logged in, 0 otherwise. @see ad_script_abort } { set untrusted_user_id [ad_conn untrusted_user_id] # Do we have any user_id at all? if { $untrusted_user_id == 0 } { return 0 } # Check account status if { $account_status eq "ok" && [ad_conn account_status] ne "ok" } { return 0 } array set levelv { none 0 expired 1 ok 2 secure 3 } # If HTTPS isn't available, we can't require secure authentication if { ![security::https_available_p] } { set levelv(secure) 2 } # Check if auth_level is sufficiently high if { $levelv([ad_conn auth_level]) < $levelv($level) } { return 0 } return $untrusted_user_id } ad_proc -public auth::UseEmailForLoginP {} { Do we use email address for login? code wrapped in a catch, so the proc will not break regardless of what the parameter value is. } { return [parameter::get -boolean -parameter UseEmailForLoginP -package_id [ad_acs_kernel_id] -default 1] } ad_proc -public auth::authenticate { {-return_url ""} {-authority_id ""} {-username ""} {-email ""} {-password:required} {-persistent:boolean} {-no_cookie:boolean} {-first_names ""} {-last_name ""} } { Try to authenticate and login the user forever by validating the username/password combination, and return authentication and account status codes. @param return_url If specified, this can be included in account status messages. @param authority_id The ID of the authority to ask to verify the user. Defaults to local authority. @param username Authority specific username of the user. @param email User's email address. You must supply either username or email. @param passowrd The password as the user entered it. @param persistent Set this if you want a permanent login cookie @param no_cookie Set this if you don't want to issue a login cookie @return Array list with the following entries:
    • auth_status: Whether authentication succeeded. ok, no_account, bad_password, auth_error, failed_to_connect
    • auth_message: Human-readable message about what went wrong. Guaranteed to be set if auth_status is not ok. Should be ignored if auth_status is ok. May contain HTML.
    • account_status: Account status from authentication server. ok, closed.
    • account_url: A URL to redirect the user to. Could e.g. ask the user to update his password.
    • account_message: Human-readable message about account status. Guaranteed to be set if auth_status is not ok and account_url is empty. If non-empty, must be relayed to the user regardless of account_status. May contain HTML. This proc is responsible for concatenating any remote and/or local account messages into one single message which can be displayed to the user.
    • user_id: Set to local user_id if auth_status is ok.
    } { if { $username eq "" } { if { $email eq "" } { set result(auth_status) "auth_error" if { [auth::UseEmailForLoginP] } { set result(auth_message) [_ acs-subsite.Email_required] } else { set result(auth_message) [_ acs-subsite.Username_required] } return [array get result] } set user_id [cc_lookup_email_user $email] if { $user_id eq "" } { set result(auth_status) "no_account" set result(auth_message) [_ acs-subsite.Unknown_email] return [array get result] } acs_user::get -user_id $user_id -array user set authority_id $user(authority_id) set username $user(username) } else { # Default to local authority if { $authority_id eq "" } { set authority_id [auth::authority::local] } } with_catch errmsg { array set result [auth::authentication::Authenticate \ -username $username \ -authority_id $authority_id \ -password $password] # We do this so that if there aren't even the auth_status and account_status that need be # in the array, that gets caught below if {$result(auth_status) eq "ok"} { set dummy $result(account_status) } } { set result(auth_status) failed_to_connect set result(auth_message) $errmsg global errorInfo ns_log Error "auth::authenticate: error invoking authentication driver for authority_id = $authority_id: $errorInfo" } # Returns: # result(auth_status) # result(auth_message) # result(account_status) # result(account_message) # Verify result/auth_message return codes switch $result(auth_status) { ok { # Continue below } no_account - bad_password - auth_error - failed_to_connect { if { ![exists_and_not_null result(auth_message)] } { array set default_auth_message { no_account {Unknown username} bad_password {Bad password} auth_error {Invalid username/password} failed_to_connect {Error communicating with authentication server} } set result(auth_message) $default_auth_message($result(auth_status)) } return [array get result] } default { ns_log Error "auth::authenticate: Illegal auth_status code '$result(auth_status)' returned from authentication driver for authority_id $authority_id ([auth::authority::get_element -authority_id $authority_id -element pretty_name])" set result(auth_status) "failed_to_connect" set result(auth_message) [_ acs-subsite.Auth_internal_error] return [array get result] } } # Verify remote account_info/account_message return codes switch $result(account_status) { ok { # Continue below if { ![info exists result(account_message)] } { set result(account_message) {} } } closed { if { ![exists_and_not_null result(account_message)] } { set result(account_message) [_ acs-subsite.Account_not_avail_now] } } default { ns_log Error "auth::authenticate: Illegal account_status code '$result(account_status)' returned from authentication driver for authority_id $authority_id ([auth::authority::get_element -authority_id $authority_id -element pretty_name])" set result(account_status) "closed" set result(account_message) [_ acs-subsite.Auth_internal_error] } } # Save the remote account information for later set remote_account_status $result(account_status) set remote_account_message $result(account_message) # Clear out remote account_status and account_message array unset result account_status array unset result account_message set result(account_url) {} # Map to row in local users table array set result [auth::get_local_account \ -return_url $return_url \ -username $username \ -authority_id $authority_id \ -email $email \ -first_names $first_names \ -last_name $last_name] # Returns: # result(account_status) # result(account_message) # result(account_url) # result(user_id) # Verify local account_info/account_message return codes switch $result(account_status) { ok { # Continue below if { ![info exists result(account_message)] } { set result(account_message) {} } } closed { if { ![exists_and_not_null result(account_message)] } { set result(account_message) [_ acs-subsite.Account_not_avail_now] } } default { ns_log Error "auth::authenticate: Illegal account_status code '$result(account_status)' returned from auth::get_local_account for authority_id $authority_id ([auth::authority::get_element -authority_id $authority_id -element pretty_name])" set result(account_status) "closed" set result(account_message) [_ acs-subsite.Auth_internal_error] } } # If the remote account was closed, the whole account is closed, regardless of local account status if {$remote_account_status eq "closed"} { set result(account_status) closed } if { [exists_and_not_null remote_account_message] } { if { [exists_and_not_null result(account_message)] } { # Concatenate local and remote account messages set result(account_message) "

    [auth::authority::get_element -authority_id $authority_id -element pretty_name]: $remote_account_message

    [ad_system_name]: $result(account_message)

    " } else { set result(account_message) $remote_account_message } } # Issue login cookie if login was successful if { $result(auth_status) eq "ok" && !$no_cookie_p && [exists_and_not_null result(user_id)] } { auth::issue_login \ -user_id $result(user_id) \ -persistent=$persistent_p \ -account_status $result(account_status) } return [array get result] } ad_proc -private auth::issue_login { {-user_id:required} {-persistent:boolean} {-account_status "ok"} } { Issue the login cookie. } { ad_user_login \ -account_status $account_status \ -forever=$persistent_p \ $user_id } ad_proc -private auth::get_register_authority { } { Get the ID of the authority in which accounts get created. Is based on the RegisterAuthority parameter but will default to the local authority if that parameter has an invalid value. } { set parameter_value [parameter::get_from_package_key -parameter RegisterAuthority -package_key "acs-authentication"] # Catch the case where somebody has set the parameter to some non-existant authority if { [lsearch [auth::authority::get_short_names] $parameter_value] != -1} { # The authority exists set authority_id [auth::authority::get_id -short_name $parameter_value] # Check that the authority has a register implementation auth::authority::get -authority_id $authority_id -array authority if { $authority(register_impl_id) eq "" } { ns_log Error "auth::get_register_authority: parameter value for RegisterAuthority is an authority without registration driver, defaulting to local authority" set authority_id [auth::authority::local] } } else { # The authority doesn't exist - use the local authority ns_log Error "auth::get_register_authority: parameter RegisterAuthority has the invalid value $parameter_value. Defaulting to local authority" set authority_id [auth::authority::local] } return $authority_id } ad_proc -public auth::create_user { {-verify_password_confirm:boolean} {-user_id ""} {-username ""} {-email:required} {-first_names ""} {-last_name ""} {-screen_name ""} {-password ""} {-password_confirm ""} {-url ""} {-secret_question ""} {-secret_answer ""} {-email_verified_p ""} {-nologin:boolean} } { Create a user, and return creation status and account status. @param email_verified_p Whether the local account considers the email to be verified or not. @param verify_password_confirm Set this flag if you want the proc to verify that password and password_confirm match for you. @return Array list containing the following entries:
    • creation_status: ok, data_error, reg_error, failed_to_connect. Says whether user creation succeeded.
    • creation_message: Information about the problem, to be relayed to the user. If creation_status is not ok, then either creation_message or element_messages is guaranteed to be non-empty, and both are guaranteed to be in the array list. May contain HTML.
    • element_messages: list of (element_name, message, element_name, message, ...) of errors on the individual registration elements. to be relayed on to the user. If creation_status is not ok, then either creation_message or element_messages is guaranteed to be non-empty, and both are guaranteed to be in the array list. Cannot contain HTML.
    • account_status: ok, closed. Only set if creation_status was ok, this says whether the newly created account is ready for use or not. For example, we may require approval, in which case the account would be created but closed.
    • account_message: A human-readable explanation of why the account was closed. May include HTML, and thus shouldn't be quoted. Guaranteed to be non-empty if account_status is not ok.
    • user_id: The user_id of the created user. Only when creation_status is ok.
    @see auth::get_all_registration_elements } { set authority_id [auth::get_register_authority] # This holds element error messages array set element_messages [list] ##### # # Create local account # ##### if { $verify_password_confirm_p } { if { $password ne $password_confirm } { return [list \ creation_status data_error \ creation_message [_ acs-subsite.Passwords_dont_match] \ element_messages [list \ password_confirm [_ acs-subsite.Passwords_dont_match] ]] } } set email [string trim $email] set username [string trim $username] foreach elm [get_all_registration_elements] { if { [info exists $elm] } { set user_info($elm) [set $elm] } } # email_verified_p set user_info(email_verified_p) $email_verified_p db_transaction { array set creation_info [auth::create_local_account \ -user_id $user_id \ -authority_id $authority_id \ -username $username \ -array user_info] # Returns: # creation_info(creation_status) # creation_info(creation_message) # creation_info(element_messages) # creation_info(account_status) # creation_info(account_message) # creation_info(user_id) # We don't do any fancy error checking here, because create_local_account is not a service contract # so we control it 100% # Local account creation ok? if {$creation_info(creation_status) eq "ok"} { # Need to find out which username was set set username $creation_info(username) # Save the local account information for later set local_account_status $creation_info(account_status) set local_account_message $creation_info(account_message) # Clear out remote creation_info array for reuse array set creation_info { creation_status {} creation_message {} element_messages {} account_status {} account_message {} } ##### # # Create remote account # ##### array set creation_info [auth::registration::Register \ -authority_id $authority_id \ -username $username \ -password $password \ -first_names $first_names \ -last_name $last_name \ -screen_name $screen_name \ -email $email \ -url $url \ -secret_question $secret_question \ -secret_answer $secret_answer] # Returns: # creation_info(creation_status) # creation_info(creation_message) # creation_info(element_messages) # creation_info(account_status) # creation_info(account_message) # Verify creation_info/creation_message return codes array set default_creation_message { data_error {Problem with user data} reg_error {Unknown registration error} failed_to_connect {Error communicating with account server} } switch $creation_info(creation_status) { ok { # Continue below } data_error - reg_error - failed_to_connect { if { ![exists_and_not_null creation_info(creation_message)] } { set creation_info(creation_message) $default_creation_message($creation_info(creation_status)) } if { ![info exists creation_info(element_messages)] } { set creation_info(element_messages) {} } return [array get creation_info] } default { set creation_info(creation_status) "failed_to_connect" set creation_info(creation_message) "Illegal error code returned from account creation driver" return [array get creation_info] } } # Verify remote account_info/account_message return codes switch $creation_info(account_status) { ok { # Continue below set creation_info(account_message) {} } closed { if { ![exists_and_not_null creation_info(account_message)] } { set creation_info(account_message) [_ acs-subsite.Account_not_avail_now] } } default { set creation_info(account_status) "closed" set creation_info(account_message) "Illegal error code returned from creationentication driver" } } } } on_error { set creation_info(creation_status) failed_to_connect set creation_info(creation_message) $errmsg global errorInfo ns_log Error "auth::create_user: Error invoking account registration driver for authority_id = $authority_id: $errorInfo" } if { $creation_info(creation_status) ne "ok" } { return [array get creation_info] } ##### # # Clean up, concat account messages, issue login cookie # ##### # If the local account was closed, the whole account is closed, regardless of remote account status if {$local_account_status eq "closed"} { set creation_info(account_status) closed } if { [exists_and_not_null local_account_message] } { if { [exists_and_not_null creation_info(account_message)] } { # Concatenate local and remote account messages set creation_info(account_message) "

    [auth::authority::get_element -authority_id $authority_id -element pretty_name]: $creation_info(account_message)

    [ad_system_name]: $local_account_message

    " } else { set creation_info(account_message) $local_account_message } } # Issue login cookie if login was successful if { !$nologin_p && $creation_info(creation_status) eq "ok" && $creation_info(account_status) eq "ok" && [ad_conn user_id] == 0 } { auth::issue_login -user_id $creation_info(user_id) } return [array get creation_info] } ad_proc -public auth::get_registration_elements { } { Get the list of required/optional elements for user registration. @return Array-list with two entries
    • required: a list of required elements
    • optional: a list of optional elements
    @see auth::get_all_registration_elements } { set authority_id [auth::get_register_authority] array set element_info [auth::registration::GetElements -authority_id $authority_id] if { ![info exists element_info(required)] } { set element_info(required) {} } if { ![info exists element_info(optional)] } { set element_info(optional) {} } set local_required_elms { first_names last_name email } set local_optional_elms {} switch [acs_user::ScreenName] { require { lappend local_required_elms "screen_name" } solicit { lappend local_optional_elms "screen_name" } } # Handle required elements for local account foreach elm $local_required_elms { # Add to required if { [lsearch $element_info(required) $elm] == -1 } { lappend element_info(required) $elm } # Remove from optional set index [lsearch $element_info(optional) $elm] if { $index != -1 } { set element_info(optional) [lreplace $element_info(optional) $index $index] } } foreach elm $local_optional_elms { # Add to required if { [lsearch $element_info(required) $elm] == -1 && [lsearch $element_info(optional) $elm] == -1 } { lappend element_info(optional) $elm } } return [array get element_info] } ad_proc -public auth::get_all_registration_elements { {-include_password_confirm:boolean} } { Get the list of possible registration elements. } { if { $include_password_confirm_p } { return { email username first_names last_name password password_confirm screen_name url secret_question secret_answer } } else { return { email username first_names last_name password screen_name url secret_question secret_answer } } } ad_proc -public auth::get_registration_form_elements { } { Returns a list of elements to be included in the -form chunk of an ad_form form. All possible elements will always be present, but those that shouldn't be displayed will be hidden and have a hard-coded empty string value. } { array set data_types { username text email text first_names text last_name text screen_name text url text password text password_confirm text secret_question text secret_answer text } array set widgets { username text email text first_names text last_name text screen_name text url text password password password_confirm password secret_question text secret_answer text } array set labels [list \ username [_ acs-subsite.Username] \ email [_ acs-subsite.Email] \ first_names [_ acs-subsite.First_names] \ last_name [_ acs-subsite.Last_name] \ screen_name [_ acs-subsite.Screen_name] \ url [_ acs-subsite.lt_Personal_Home_Page_UR] \ password [_ acs-subsite.Password] \ password_confirm [_ acs-subsite.lt_Password_Confirmation] \ secret_question [_ acs-subsite.Question] \ secret_answer [_ acs-subsite.Answer]] array set html { username {size 30} email {size 30} first_names {size 30} last_name {size 30} screen_name {size 30} url {size 50 value "http://"} password {size 20} password_confirm {size 20} secret_question {size 30} secret_answer {size 30} } array set element_info [auth::get_registration_elements] if { [lsearch $element_info(required) password] != -1 } { lappend element_info(required) password_confirm } if { [lsearch $element_info(optional) password] != -1 } { lappend element_info(optional) password_confirm } # required_p will have 1 if required, 0 if optional, and unset if not in the form array set required_p [list] foreach element $element_info(required) { set required_p($element) 1 } foreach element $element_info(optional) { set required_p($element) 0 } set form_elements [list] foreach element [auth::get_all_registration_elements -include_password_confirm] { if { [info exists required_p($element)] } { set form_element [list] # The header with name, datatype, and widget set form_element_header "${element}:$data_types($element)($widgets($element))" if { !$required_p($element) } { append form_element_header ",optional" } lappend form_element $form_element_header # The label lappend form_element [list label $labels($element)] # HTML lappend form_element [list html $html($element)] # The form element is finished - add it to the list lappend form_elements $form_element } else { lappend form_elements "${element}:text(hidden),optional [list value {}]" } } return $form_elements } ad_proc -public auth::create_local_account { {-user_id ""} {-authority_id:required} {-username ""} {-array:required} } { Create the local account for a user. @param array Name of an array containing the registration elements to update. @return Array list containing the following entries:
    • creation_status: ok, data_error, reg_error, failed_to_connect. Says whether user creation succeeded.
    • creation_message: Information about the problem, to be relayed to the user. If creation_status is not ok, then either creation_message or element_messages is guaranteed to be non-empty, and both are guaranteed to be in the array list. May contain HTML.
    • element_messages: list of (element_name, message, element_name, message, ...) of errors on the individual registration elements. to be relayed on to the user. If creation_status is not ok, then either creation_message or element_messages is guaranteed to be non-empty, and both are guaranteed to be in the array list. Cannot contain HTML.
    • account_status: ok, closed. Only set if creation_status was ok, this says whether the newly created account is ready for use or not. For example, we may require approval, in which case the account would be created but closed.
    • account_message: A human-readable explanation of why the account was closed. May include HTML, and thus shouldn't be quoted. Guaranteed to be non-empty if account_status is not ok.
    All entries are guaranteed to always be set, but may be empty. } { upvar 1 $array user_info array set result { creation_status reg_error creation_message {} element_messages {} account_status ok account_message {} user_id {} } # Default all elements to the empty string foreach elm [get_all_registration_elements] { if { ![info exists user_info($elm)] } { set user_info($elm) {} } } # Validate data auth::validate_account_info \ -authority_id $authority_id \ -username $username \ -user_array user_info \ -message_array element_messages # Handle validation errors if { [llength [array names element_messages]] > 0 } { return [list \ creation_status "data_error" \ creation_message {} \ element_messages [array get element_messages] \ ] } # Admin approval set system_name [ad_system_name] if { [parameter::get -parameter RegistrationRequiresApprovalP -default 0] } { set member_state "needs approval" set result(account_status) "closed" set result(account_message) [_ acs-subsite.Registration_Approval_Notice] } else { set member_state "approved" } if { ![exists_and_not_null user_info(email_verified_p)] } { if { [parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0] } { set user_info(email_verified_p) "f" } else { set user_info(email_verified_p) "t" } } # Default a local account username if { $user_info(authority_id) == [auth::authority::local] \ && [auth::UseEmailForLoginP] \ && $username eq "" } { # Generate a username that's guaranteed to be unique # Rather much work, but that's the best I could think of # Default to email set username [string tolower $user_info(email)] # Check if it already exists set existing_user_id [acs_user::get_by_username -authority_id $authority_id -username $username] # If so, add -2 or -3 or ... to make it unique if { $existing_user_id ne "" } { set match "${username}-%" set existing_usernames [db_list select_existing_usernames { select username from users where authority_id = :authority_id and username like :match }] set number 2 foreach existing_username $existing_usernames { if { [regexp "^${username}-(\\d+)\$" $existing_username match existing_number] } { # matches the foo-123 pattern if { $existing_number >= $number } { set number [expr {$existing_number + 1}] } } } set username "$username-$number" ns_log Notice "auth::create_local_account: user's email was already used as someone else's username, setting username to $username" } } set error_p 0 with_catch errmsg { # We create the user without a password # If it's a local account, that'll get set later set user_id [ad_user_new \ $user_info(email) \ $user_info(first_names) \ $user_info(last_name) \ {} \ $user_info(secret_question) \ $user_info(secret_answer) \ $user_info(url) \ $user_info(email_verified_p) \ $member_state \ $user_id \ $username \ $user_info(authority_id) \ $user_info(screen_name)] # Update person.bio if { [info exists user_info(bio)] } { person::update_bio \ -person_id $user_id \ -bio $user_info(bio) } } { set error_p 1 } if { $error_p || $user_id == 0 } { set result(creation_status) "failed_to_connect" set result(creation_message) [_ acs-subsite.Error_trying_to_register] global errorInfo ns_log Error "auth::create_local_account: Error creating local account.\n$errorInfo" return [array get result] } set result(user_id) $user_id if { $username eq "" } { set username [acs_user::get_element -user_id $user_id -element username] } set result(username) $username # Creation succeeded set result(creation_status) "ok" if { [parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0] } { set email $user_info(email) set result(account_status) "closed" set result(account_message) "

    [_ acs-subsite.lt_Registration_informat_1]

    [_ acs-subsite.lt_Please_read_and_follo]

    " with_catch errmsg { auth::send_email_verification_email -user_id $user_id } { global errorInfo ns_log Error "auth::create_local_account: Error sending out email verification email to email $email:\n$errorInfo" set auth_info(account_message) [_ acs_subsite.Error_sending_verification_mail] } } return [array get result] } ad_proc -public auth::update_local_account { {-authority_id:required} {-username:required} {-array:required} } { Update the local account for a user. @param array Name of an array containing the registration elements to update. @return Array list containing the following entries:
    • update_status: ok, data_error, update_error, failed_to_connect. Says whether user update succeeded.
    • update_message: Information about the problem, to be relayed to the user. If update_status is not ok, then either update_message or element_messages is guaranteed to be non-empty, and both are guaranteed to be in the array list. May contain HTML.
    • element_messages: list of (element_name, message, element_name, message, ...) of errors on the individual registration elements. to be relayed on to the user. If update_status is not ok, then either udpate_message or element_messages is guaranteed to be non-empty, and both are guaranteed to be in the array list. Cannot contain HTML.
    All entries are guaranteed to always be set, but may be empty. } { upvar 1 $array user_info array set result { update_status update_error update_message {} element_messages {} user_id {} } # Validate data auth::validate_account_info \ -update \ -authority_id $authority_id \ -username $username \ -user_array user_info \ -message_array element_messages # Handle validation errors if { [llength [array names element_messages]] > 0 } { return [list \ update_status "data_error" \ update_message {} \ element_messages [array get element_messages] \ ] } # We get user_id from validate_account_info above, and set it in the result array so our caller can get it set user_id $user_info(user_id) set result(user_id) $user_id set error_p 0 with_catch errmsg { db_transaction { # Update persons: first_names, last_name if { [info exists user_info(first_names)] } { # We know that validate_account_info will not let us update only one of the two person::update \ -person_id $user_id \ -first_names $user_info(first_names) \ -last_name $user_info(last_name) } # Update person.bio if { [info exists user_info(bio)] } { person::update_bio \ -person_id $user_id \ -bio $user_info(bio) } # Update parties: email, url if { [info exists user_info(email)] } { party::update \ -party_id $user_id \ -email $user_info(email) } if { [info exists user_info(url)] } { party::update \ -party_id $user_id \ -url $user_info(url) } # Update users: email_verified_p if { [info exists user_info(email_verified_p)] } { acs_user::update \ -user_id $user_id \ -email_verified_p $user_info(email_verified_p) } # Update users: screen_name if { [info exists user_info(screen_name)] } { acs_user::update \ -user_id $user_id \ -screen_name $user_info(screen_name) } if { [info exists user_info(username)] } { acs_user::update \ -user_id $user_id \ -username $user_info(username) } if { [info exists user_info(authority_id)] } { acs_user::update \ -user_id $user_id \ -authority_id $user_info(authority_id) } # TODO: Portrait } } { set error_p 1 } if { $error_p } { set result(update_status) "failed_to_connect" set result(update_message) [_ acs-subsite.Error_update_account_info] global errorInfo ns_log Error "Error updating local account.\n$errorInfo" return [array get result] } # Update succeeded set result(update_status) "ok" return [array get result] } ad_proc -public auth::delete_local_account { {-authority_id:required} {-username:required} } { Delete the local account for a user. @return Array list containing the following entries:
    • delete_status: ok, delete_error, failed_to_connect. Says whether user deletion succeeded.
    • delete_message: Information about the problem, to be relayed to the user. If delete_status is not ok, then delete_message is guaranteed to be non-empty. May contain HTML.
    All entries are guaranteed to always be set, but may be empty. } { array set result { delete_status ok delete_message {} user_id {} } set user_id [acs_user::get_by_username \ -authority_id $authority_id \ -username $username] if { $user_id eq "" } { set result(delete_status) "delete_error" set result(delete_message) [_ acs-subsite.No_user_with_this_username] return [array get result] } # Mark the account banned acs_user::ban -user_id $user_id set result(user_id) $user_id return [array get result] } ad_proc -public auth::set_email_verified { {-user_id:required} } { Update an OpenACS record with the fact that the email address on record was verified. } { acs_user::update \ -user_id $user_id \ -email_verified_p "t" } ad_proc -private auth::verify_account_status {} { Verify the account status of the current user, and set [ad_conn account_status] appropriately. } { # Just recheck the authentication cookie, and it'll do the verification for us sec_login_handler } ##### # # auth namespace private procs # ##### ad_proc -private auth::get_local_account { {-return_url ""} {-username:required} {-authority_id ""} {-email ""} {-first_names ""} {-last_name ""} } { Get the user_id of the local account for the given username and domain combination. @param username The username to find @param authority_id The ID of the authority to ask to verify the user. Leave blank for local authority. } { array set auth_info [list] # Will return: # auth_info(account_status) # auth_info(account_message) # auth_info(user_id) if { $authority_id eq "" } { set authority_id [auth::authority::local] } ns_log notice "auth::get_local_account authority_id = '${authority_id}' local = [auth::authority::local]" with_catch errmsg { acs_user::get -authority_id $authority_id -username $username -array user set account_found_p 1 } { set account_found_p 0 } if { !$account_found_p } { # Try for an on-demand sync array set info_result [auth::user_info::GetUserInfo \ -authority_id $authority_id \ -username $username] if {$info_result(info_status) eq "ok"} { array set user $info_result(user_info) if {$email ne "" \ && (![info exists user(email)] || $user(email) eq "")} { set user(email) $email } if {$first_names ne "" \ && (![info exists user(first_names)] || $user(first_names) eq "")} { set user(first_names) $first_names } if {$last_name ne "" \ && (![info exists user(last_name)] || $user(last_name) eq "")} { set user(last_name) $last_name } array set creation_info [auth::create_local_account \ -authority_id $authority_id \ -username $username \ -array user] if {$creation_info(creation_status) eq "ok"} { acs_user::get -authority_id $authority_id -username $username -array user } else { set auth_info(account_status) "closed" # Used to get help contact info auth::authority::get -authority_id $authority_id -array authority set system_name [ad_system_name] set auth_info(account_message) "You have successfully authenticated, but we were unable to create an account for you on $system_name. " set auth_info(element_messages) $creation_info(element_messages) append auth_info(account_message) "The error was: $creation_info(element_messages). Please contact the system administrator." if { $authority(help_contact_text) ne "" } { append auth_info(account_message) "

    Help Information

    " append auth_info(account_message) [ad_html_text_convert \ -from $authority(help_contact_text_format) \ -to "text/html" -- $authority(help_contact_text)] } return [array get auth_info] } } else { # Local user account doesn't exist set auth_info(account_status) "closed" # Used to get help contact info auth::authority::get -authority_id $authority_id -array authority set system_name [ad_system_name] set auth_info(account_message) [_ acs-subsite.Success_but_no_account_yet] if { $authority(help_contact_text) ne "" } { append auth_info(account_message) [_ acs-subsite.Help_information] append auth_info(account_message) [ad_html_text_convert \ -from $authority(help_contact_text_format) \ -to "text/html" -- $authority(help_contact_text)] } return [array get auth_info] } } # Check local account status array set auth_info [auth::check_local_account_status \ -user_id $user(user_id) \ -return_url $return_url \ -member_state $user(member_state) \ -email_verified_p $user(email_verified_p) \ -screen_name $user(screen_name) \ -password_age_days $user(password_age_days)] # Return user_id set auth_info(user_id) $user(user_id) return [array get auth_info] } ad_proc -private auth::check_local_account_status { {-return_url ""} {-no_dialogue:boolean} {-user_id:required} {-member_state:required} {-email_verified_p:required} {-screen_name:required} {-password_age_days:required} } { Check the account status of a user with the given parameters. @param no_dialogue If specified, will not send out email or in other ways converse with the user @return An array-list with account_status, account_url and account_message } { # Initialize to 'closed', because most cases below mean the account is closed set result(account_status) "closed" # system_name and email is used in some of the I18N messages set system_name [ad_system_name] acs_user::get -user_id $user_id -array user set authority_id $user(authority_id) set email $user(email) switch $member_state { approved { set PasswordExpirationDays [parameter::get -parameter PasswordExpirationDays -package_id [ad_acs_kernel_id] -default 0] if { $email_verified_p eq "f" } { if { !$no_dialogue_p } { set result(account_message) "

    [_ acs-subsite.lt_Registration_informat]

    [_ acs-subsite.lt_Please_read_and_follo]

    " with_catch errmsg { auth::send_email_verification_email -user_id $user_id } { global errorInfo ns_log Error "auth::check_local_account_status: Error sending out email verification email to email $email:\n$errorInfo" set result(account_message) [_ acs-subsite.Error_sending_verification_mail] } } } elseif { [string equal [acs_user::ScreenName] "require"] && $screen_name eq "" } { set message "Please enter a screen name now." set result(account_url) [export_vars -no_empty -base "[subsite::get_element -element url]user/basic-info-update" { message return_url {edit_p 1} }] } elseif { $PasswordExpirationDays > 0 && \ ($password_age_days eq "" || $password_age_days > $PasswordExpirationDays) } { set message [_ acs-subsite.Password_regular_change_now] set result(account_url) [export_vars -base "[subsite::get_element -element url]user/password-update" { return_url message }] } else { set result(account_status) "ok" } } banned { set result(account_message) [_ acs-subsite.lt_Sorry_but_it_seems_th] } deleted { set restore_url [export_vars -base "restore-user" { return_url }] set result(account_message) [_ acs-subsite.Account_closed] } rejected - "needs approval" { set result(account_message) \ "

    [_ acs-subsite.lt_registration_request_submitted]

    [_ acs-subsite.Thank_you]

    " } default { set result(account_message) [_ acs-subsite.Problem_auth_no_memb] ns_log Error "auth::check_local_account_status: problem with registration state machine: user_id $user_id has member_state '$member_state'" } } return [array get result] } ad_proc -public auth::get_local_account_status { {-user_id:required} } { Return 'ok', 'closed', or 'no_account' } { set result no_account catch { acs_user::get -user_id $user_id -array user array set check_result [auth::check_local_account_status \ -user_id $user_id \ -member_state $user(member_state) \ -email_verified_p $user(email_verified_p) \ -screen_name $user(screen_name) \ -password_age_days $user(password_age_days)] set result $check_result(account_status) } return $result } ad_proc -private auth::get_user_secret_token { -user_id:required } { Get a secret token for the user. Can be used for email verification purposes. } { return [ns_sha1 "${user_id}[sec_get_token 1]"] } ad_proc -private auth::send_email_verification_email { -user_id:required } { Sends out an email to the user that lets them verify their email. Throws an error if we couldn't send out the email. } { # These are used in the messages below set token [auth::get_user_secret_token -user_id $user_id] acs_user::get -user_id $user_id -array user set confirmation_url [export_vars -base "[ad_url]/register/email-confirm" { token user_id }] set system_name [ad_system_name] acs_mail_lite::send -send_immediately \ -to_addr $user(email) \ -from_addr "\"$system_name\" <[parameter::get -parameter NewRegistrationEmailAddress -default [ad_system_owner]]>" \ -subject [_ acs-subsite.lt_Welcome_to_system_nam] \ -body [_ acs-subsite.lt_To_confirm_your_regis] } ad_proc -private auth::validate_account_info { {-update:boolean} {-authority_id:required} {-username:required} {-user_array:required} {-message_array:required} } { Validates user info and returns errors, if any. @param update Set this flag if you're updating an existing record, meaning we shouldn't check for duplicates. @param user_array Name of an array in the caller's namespace which contains the registration elements. @param message_array Name of an array where you want the validation errors stored, keyed by element name. } { upvar 1 $user_array user upvar 1 $message_array element_messages set required_elms { } if { !$update_p } { set required_elms [concat $required_elms { first_names last_name email }] } foreach elm $required_elms { if { ![exists_and_not_null user($elm)] } { set element_messages($elm) "Required" } } if { [info exists user(email)] } { set user(email) [string trim $user(email)] } if { [info exists user(username)] } { set user(username) [string trim $user(username)] } if { $update_p } { set user(user_id) [acs_user::get_by_username \ -authority_id $authority_id \ -username $username] if { $user(user_id) eq "" } { set this_authority [auth::authority::get_element -authority_id $authority_id -element pretty_name] set element_messages(username) [_ acs-subsite.Username_not_found_for_authority] } } else { set user(username) $username set user(authority_id) $authority_id } # TODO: When doing RBM's parameter, make sure that we still require both first_names and last_names, or none of them if { [exists_and_not_null user(first_names)] && [string first "<" $user(first_names)] != -1 } { set element_messages(first_names) [_ acs-subsite.lt_You_cant_have_a_lt_in] } if { [exists_and_not_null user(last_name)] && [string first "<" $user(last_name)] != -1 } { set element_messages(last_name) [_ acs-subsite.lt_You_cant_have_a_lt_in_1] } if { [exists_and_not_null user(email)] } { if { ![util_email_valid_p $user(email)] } { set element_messages(email) [_ acs-subsite.Not_valid_email_addr] } else { set user(email) [string tolower $user(email)] } } if { [info exists user(url)] } { if { $user(url) eq "" || $user(url) eq "http://" } { # The user left the default hint for the url set user(url) {} } elseif { ![util_url_valid_p $user(url)] } { set valid_url_example "http://openacs.org/" set element_messages(url) [_ acs-subsite.lt_Your_URL_doesnt_have_] } } if { [info exists user(screen_name)] } { set screen_name_user_id [acs_user::get_user_id_by_screen_name -screen_name $user(screen_name)] if { $screen_name_user_id ne "" && (!$update_p || $screen_name_user_id != $user(user_id)) } { set element_messages(screen_name) [_ acs-subsite.screen_name_already_taken] # We could do the same logic as below with 'stealing' the screen_name of an old, banned user. } } if { [exists_and_not_null user(email)] } { # Check that email is unique set email $user(email) set email_party_id [party::get_by_email -email $user(email)] if { $email_party_id ne "" && (!$update_p || $email_party_id != $user(user_id)) } { # We found a user with this email, and either we're not updating, # or it's not the same user_id as the one we're updating if { [acs_object_type $email_party_id] ne "user" } { set element_messages(email) [_ acs-subsite.Have_group_mail] } else { acs_user::get \ -user_id $email_party_id \ -array email_user switch $email_user(member_state) { banned { # A user with this email does exist, but he's banned, so we can 'steal' his email address # by setting it to something dummy party::update \ -party_id $email_party_id \ -email "dummy-email-$email_party_id" } default { set element_messages(email) [_ acs-subsite.Have_user_mail] } } } } } # They're trying to set the username if { [exists_and_not_null user(username)] } { # Check that username is unique set username_user_id [acs_user::get_by_username -authority_id $authority_id -username $user(username)] if { $username_user_id ne "" && (!$update_p || $username_user_id != $user(user_id)) } { # We already have a user with this username, and either we're not updating, or it's not the same user_id as the one we're updating set username_member_state [acs_user::get_element -user_id $username_user_id -element member_state] switch $username_member_state { banned { # A user with this username does exist, but he's banned, so we can 'steal' his username # by setting it to something dummy acs_user::update \ -user_id $username_user_id \ -username "dummy-username-$username_user_id" } default { set element_messages(username) [_ acs-subsite.Have_user_name] } } } } } ad_proc -private auth::can_admin_system_without_authority_p { {-authority_id:required} } { Before disabling or deleting an authority we need to check that there is at least one site-wide admin in a different authority that can administer the system. This proc returns 1 if there is such an admin and 0 otherwise. @author Peter Marklund } { set number_of_admins_left [db_string count_admins_left { select count(*) from cc_users u, acs_object_party_privilege_map pm, acs_magic_objects mo where authority_id <> :authority_id and pm.privilege = 'admin' and pm.object_id = mo.object_id and mo.name = 'security_context_root' and pm.party_id = u.user_id and u.member_state = 'approved' }] return [ad_decode $number_of_admins_left "0" "0" "1"] } ##### # # auth::authentication # ##### ad_proc -private auth::authentication::Authenticate { {-authority_id:required} {-username:required} {-password:required} } { Invoke the Authenticate service contract operation for the given authority. @param authority_id The ID of the authority to ask to verify the user. @param username Username of the user. @param passowrd The password as the user entered it. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "auth_impl_id"] if { $impl_id eq "" } { # No implementation of authentication set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support authentication" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] # See http://openacs.org/bugtracker/openacs/bug?format=table&f%5fstate=8&bug%5fnumber=2200 # Basically, we want upgrades to work, so we have to check for # version number -jfr set authentication_version [util_memoize [list apm_highest_version_name acs-authentication]] set old_version_p [util_memoize [list apm_version_names_compare 5.1.3 $authentication_version]] if {[string is true $old_version_p]} { return [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation Authenticate \ -call_args [list $username $password $parameters]] } else { return [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation Authenticate \ -call_args [list $username $password $parameters $authority_id]] } } ##### # # auth::registration # ##### ad_proc -private auth::registration::Register { {-authority_id:required} {-username ""} {-password ""} {-first_names ""} {-last_name ""} {-screen_name ""} {-email ""} {-url ""} {-secret_question ""} {-secret_answer ""} } { Invoke the Register service contract operation for the given authority. @authority_id Id of the authority. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "register_impl_id"] if { $impl_id eq "" } { # No implementation of authentication set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support account registration" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation Register \ -call_args [list $parameters \ $username \ $authority_id \ $first_names \ $last_name \ $screen_name \ $email \ $url \ $password \ $secret_question \ $secret_answer]] } ad_proc -private auth::registration::GetElements { {-authority_id:required} } { @author Peter Marklund } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "register_impl_id"] if { $impl_id eq "" } { # No implementation of authentication set authority_pretty_name [auth::authority::get_element -authority_id $authority_id -element "pretty_name"] error "The authority '$authority_pretty_name' doesn't support account registration" } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation GetElements \ -call_args [list $parameters]] } ##### # # auth::user_info # ##### ad_proc -private auth::user_info::GetUserInfo { {-authority_id:required} {-username:required} } { Invoke the Register service contract operation for the given authority. @authority_id Id of the authority. } { set impl_id [auth::authority::get_element -authority_id $authority_id -element "user_info_impl_id"] if { $impl_id eq "" } { # No implementation of authentication return { info_status no_account } } set parameters [auth::driver::get_parameter_values \ -authority_id $authority_id \ -impl_id $impl_id] return [acs_sc::invoke \ -error \ -impl_id $impl_id \ -operation GetUserInfo \ -call_args [list $username $parameters]] } openacs-5.7.0/packages/acs-authentication/sql/0000755000175000017500000000000011724401450021131 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/sql/oracle/0000755000175000017500000000000011724401450022376 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/sql/oracle/acs-authentication-drop.sql0000644000175000017500000000022707727123556027665 0ustar frankiefrankie-- -- Drop script for acs-authentication -- -- $Id: acs-authentication-drop.sql,v 1.1 2003/09/08 15:59:42 lars Exp $ -- @@ batch-job-tables-drop.sql openacs-5.7.0/packages/acs-authentication/sql/oracle/acs-authentication-create.sql0000644000175000017500000000023207727123556030160 0ustar frankiefrankie-- -- Data model for acs-authentication -- -- $Id: acs-authentication-create.sql,v 1.1 2003/09/08 15:59:42 lars Exp $ -- @@ batch-job-tables-create.sql openacs-5.7.0/packages/acs-authentication/sql/oracle/batch-job-tables-create.sql0000644000175000017500000000604410506237105027466 0ustar frankiefrankiecreate sequence auth_batch_jobs_job_id_seq; create table auth_batch_jobs ( job_id integer constraint auth_batch_jobs_job_id_pk primary key, job_start_time date default sysdate, job_end_time date, interactive_p char(1) constraint auth_batch_jobs_interactive_ck check (interactive_p in ('t', 'f')) constraint auth_batch_jobs_interactive_nn not null, snapshot_p char(1) constraint auth_batch_jobs_snapshot_ck check (snapshot_p in ('t', 'f')), authority_id integer constraint auth_batch_jobs_auth_fk references auth_authorities(authority_id) on delete cascade, message varchar2(4000), -- if interactive, by which user creation_user integer constraint auth_batch_job_user_fk references users(user_id) on delete set null, -- status information for the GetDocument operation doc_start_time date, doc_end_time date, doc_status varchar2(4000), doc_message varchar2(4000), document clob ); create index auth_batch_jobs_user_idx on auth_batch_jobs(creation_user); create index auth_batch_jobs_auth_idx on auth_batch_jobs(authority_id); create sequence auth_batch_job_entry_id_seq; create table auth_batch_job_entries ( entry_id integer constraint auth_batch_job_entries_pk primary key, job_id integer constraint auth_batch_job_entries_job_fk references auth_batch_jobs(job_id) on delete cascade, entry_time date default sysdate, operation varchar(100) constraint auth_batch_jobs_entries_op_ck check (operation in ('insert', 'update', 'delete')), username varchar(100), user_id integer constraint auth_batch_job_entries_user_fk references users(user_id) on delete set null, success_p char(1) constraint auth_batch_jobs_ent_success_ck check (success_p in ('t', 'f')) constraint auth_batch_jobs_ent_success_nn not null, message varchar2(4000), element_messages clob ); create index auth_batch_job_ent_job_idx on auth_batch_job_entries(job_id); create index auth_batch_job_ent_user_idx on auth_batch_job_entries(user_id); openacs-5.7.0/packages/acs-authentication/sql/oracle/batch-job-tables-drop.sql0000644000175000017500000000022607727123556027202 0ustar frankiefrankiedrop sequence auth_batch_jobs_job_id_seq; drop sequence auth_batch_job_entry_id_seq; drop table auth_batch_job_entries; drop table auth_batch_jobs; openacs-5.7.0/packages/acs-authentication/sql/postgresql/0000755000175000017500000000000011575225400023337 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/sql/postgresql/acs-authentication-drop.sql0000644000175000017500000000022707727123557030624 0ustar frankiefrankie-- -- Drop script for acs-authentication -- -- $Id: acs-authentication-drop.sql,v 1.1 2003/09/08 15:59:43 lars Exp $ -- \i batch-job-tables-drop.sql openacs-5.7.0/packages/acs-authentication/sql/postgresql/acs-authentication-create.sql0000644000175000017500000000023207727123557031117 0ustar frankiefrankie-- -- Data model for acs-authentication -- -- $Id: acs-authentication-create.sql,v 1.1 2003/09/08 15:59:43 lars Exp $ -- \i batch-job-tables-create.sql openacs-5.7.0/packages/acs-authentication/sql/postgresql/batch-job-tables-create.sql0000644000175000017500000000510510506034365030424 0ustar frankiefrankie create sequence auth_batch_jobs_job_id_seq; create table auth_batch_jobs ( job_id integer constraint auth_batch_jobs_job_id_pk primary key, job_start_time timestamptz default current_timestamp, job_end_time timestamptz, interactive_p boolean constraint auth_batch_jobs_interactive_nn not null, snapshot_p boolean, authority_id integer constraint auth_batch_jobs_auth_id_fk references auth_authorities(authority_id) on delete cascade, message text, -- if interactive, by which user creation_user integer constraint auth_batch_jobs_user_fk references users(user_id) on delete set null, -- status information for the GetDocument operation doc_start_time timestamptz, doc_end_time timestamptz, doc_status text, doc_message text, document text ); create index auth_batch_jobs_user_idx on auth_batch_jobs(creation_user); create index auth_batch_jobs_auth_idx on auth_batch_jobs(authority_id); create sequence auth_batch_job_entry_id_seq; create table auth_batch_job_entries ( entry_id integer constraint auth_batch_job_entries_pk primary key, job_id integer constraint auth_batch_job_entries_job_fk references auth_batch_jobs(job_id) on delete cascade, entry_time timestamptz default current_timestamp, operation varchar(100) constraint auth_batch_jobs_entries_op_ck check (operation in ('insert', 'update', 'delete')), username varchar(100), user_id integer constraint auth_batch_job_entries_user_fk references users(user_id) on delete set null, success_p boolean not null, message text, element_messages text ); create index auth_batch_job_ent_job_idx on auth_batch_job_entries(job_id); create index auth_batch_job_ent_user_idx on auth_batch_job_entries(user_id); openacs-5.7.0/packages/acs-authentication/sql/postgresql/batch-job-tables-drop.sql0000644000175000017500000000022607727123557030141 0ustar frankiefrankiedrop sequence auth_batch_jobs_job_id_seq; drop sequence auth_batch_job_entry_id_seq; drop table auth_batch_job_entries; drop table auth_batch_jobs; openacs-5.7.0/packages/acs-authentication/www/0000755000175000017500000000000011575225402021163 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/www/doc/0000755000175000017500000000000011575225402021730 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/www/doc/xml/0000755000175000017500000000000011575225402022530 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/www/doc/xml/Makefile0000644000175000017500000000111107740761014024165 0ustar frankiefrankie# A very simple Makefile to generate the HTML docs # @author Vinod Kurup (vinod@kurup.com) # @author Modified by Roberto Mello (rmello@fslc.usu.edu) # @author Joel Aufrecht # # @creation-date 2002-08-10 # @modified-date 2002-09-21 # @modified-date 2003-10-08 # # Simplified version of acs-core-docs makefile, intended for generating # documentation from standard location /www/doc/xml in # OpenACS packages # # Paths XSLTPROC=/usr/bin/xsltproc HTMLDOC=/usr/bin/htmldoc all: cd .. ; $(XSLTPROC) --nonet --novalid --xinclude ../../../acs-core-docs/www/xml/openacs.xsl xml/index.xmlopenacs-5.7.0/packages/acs-authentication/www/doc/xml/install.xml0000644000175000017500000004531410440426441024723 0ustar frankiefrankie
    Installation by Joel Aufrecht Using Pluggable Authentication Modules (PAM) with OpenACS OpenACS supports PAM authetication via the ns_pam module in AOLserver. Add PAM support to AOLserver OpenACS supports PAM support via the PAM AOLserver module. PAM is system of modular support, and can provide local (unix password), RADIUS, LDAP (more information), and other forms of authentication. Note that due to security issues, the AOLserver PAM module cannot be used for local password authentication. Compile and install ns_pam Download the tarball to /tmp. Debian users: first do apt-get install libpam-dev [root@yourserver root]# cd /usr/local/src/aolserver [root@yourserver aolserver]# tar xzf /tmp/ns_pam-0.1.tar.gz [root@yourserver aolserver]# cd nspam [root@yourserver nspam]# make gcc -I/usr/include/pam -I/usr/local/aolserver/include -D_REENTRANT=1 -DNDEBUG=1 -g -fPIC -Wall -Wno-unused -mcpu=i686 -DHAVE_CMMSG=1 -DUSE_FIONREAD=1 -DHAVE_COND_EINTR=1 -c -o nspam.o nspam.c nspam.c: In function `PamCmd': nspam.c:107: warning: implicit declaration of function `Tcl_SetObjResult' nspam.c:107: warning: implicit declaration of function `Tcl_NewIntObj' gcc -I/usr/include/pam -I/usr/local/aolserver/include -D_REENTRANT=1 -DNDEBUG=1 -g -fPIC -Wall -Wno-unused -mcpu=i686 -DHAVE_CMMSG=1 -DUSE_FIONREAD=1 -DHAVE_COND_EINTR=1 -c -o pam_support.o pam_support.c /bin/rm -f nspam.so gcc -shared -nostartfiles -o nspam.so nspam.o pam_support.o -lpam [root@yourserver nspam]# make install [root@yourserver nspam]# cd /usr/local/src/aolserver tar xzf /tmp/ns_pam-0.1.tar.gz cd nspam make make install Set up a PAM domain A PAM domain is a set of rules for granting privileges based on other programs. Each instance of AOLserver uses a domain; different aolserver instances can use the same domain but one AOLserver instance cannot use two domains. The domain describes which intermediate programs will be used to check permissions. You may need to install software to perform new types of authentication. RADIUS in PAM Untar the pam_radius tarball and compile and install. (more information) [root@yourserver root]# cd /usr/local/src/ [root@yourserver src]# tar xf /tmp/pam_radius-1.3.16.tar [root@yourserver src]# cd pam_radius-1.3.16 [root@yourserver pam_radius-1.3.16]# make cc -Wall -fPIC -c pam_radius_auth.c -o pam_radius_auth.o cc -Wall -fPIC -c -o md5.o md5.c ld -Bshareable pam_radius_auth.o md5.o -lpam -o pam_radius_auth.so [root@yourserver pam_radius-1.3.16]# cp pam_radius_auth.so /lib/security/pam_radius_auth.so [root@yourserver pam_radius-1.3.16]# cd /usr/local/src/ tar xf /tmp/pam_radius-1.3.16.tar cd pam_radius-1.3.16 make cp pam_radius_auth.so /lib/security/pam_radius_auth.so Debian users: apt-get install libpam-radius-auth Set up the PAM domain. Recent PAM distributions have a different file for each domain, all in /etc/pam.d. Previous PAM setups put all domain configuration lines into a single file, /etc/pam.conf. On Red Hat, create the file /etc/pam.d/service0 with these contents: auth sufficient /lib/security/pam_radius_auth.so Modify the AOLserver configuration file to use this PAM domain. Edit the line ns_param PamDomain "service0" So that the value of the parameter matches the name (just the file name, not the fully pathed name) of the domain file in /etc/pam.d/ LDAP in PAM more information Modify the AOLserver configuration file to support ns_pam. In /var/lib/aolserver/service0/etc/config.tcl, enable the nspam module by uncommenting this line: ns_param nspam ${bindir}/nspam.so Install auth-pam OpenACS service package Install auth-pam and restart the server. Create an OpenACS authority OpenACS supports multiple authentication authorities. The OpenACS server itself is the "Local Authority," used by default. Browse to the authentication administration page, http://yourserver/acs-admin/auth/. Create and name an authority (in the sitewide admin UI) Set Authentication to PAM. If the PAM domain defines a password command, you can set Password Management to PAM. If not, the PAM module cannot change the user's password and you should leave this option Disabled. Leave Account Registration disabed. Configure Batch Synchronization Using LDAP/Active Directory with OpenACS by John Sequeira, Michael Steigman, and Carl Blesius. ToDo: Add/verify information on on-demand sync, account registration, and batch synchronization. Add section on ldapsearch. Overview You do not want to make users remember yet another password and username. If you can avoid it you do not want to store their passwords either. This document should help you set your system up so your users can seamlessly log in to your OpenACS instance using the password they are accustomed to using for other things at your institution. Background The original OpenACS LDAP implementation (which has been depreciated by this package) treated the LDAP server as another data store similar to Oracle or Postgresql. It opened a connection using a priveleged account and read or stored an encrypted password for the user in question. This password was independent of the user's operating system or network account, and had to be synchronized if you wanted the same password for OpenACS. Save their passwords? Sync passwords? Deal with forgotten password requests? No Thanks. Using ldap bind, you can delegate authentication completely to LDAP. This way you can let the IT department (if you are lucky) worry about password storage/synchronization/etc. The bind operation takes a username and password and returns a true of false depending on whether they match up. This document takes the 'bind' approach so that your users LDAP/AD password (or whatever else you use) can be used to login to OpenACS. Note on Account Creation On the authentication driver configure screens, you will also see lots of options for synchronizing users between your directory and OpenACS. This document takes the approach of provisioning users on demand instead of ahead-of-time. This means that when they attempt to login to OpenACS, if they have a valid Windows account, we'll create an account for them in OpenACS and log them in. Installing AOLserver LDAP support (openldap and nsldap) Install openldap and nsldap using the document Malte created Next, modify your config.tcl file as directed in the nsldap README. Here's what the relevant additions should look like: # LDAP authentication ns_param nsldap ${bindir}/nsldap.so ... ns_section "ns/ldap/pool/ldap" ns_param user "cn=Administrator, cn=Users, dc=mydomain, dc=com" ns_param password "password" ns_param host "directory.mydomain.com" ns_param connections 1 ns_param verbose On ns_section "ns/ldap/pools" ns_param ldap ldap ns_section "ns/server/${server}/ldap" ns_param pools * ns_param defaultpool ldap To verify that this is all working, restart Aolserver and ensure that you see something like this in your error.log: [10/Jan/2006:11:11:07][22553.3076437088][-main-] Notice: modload: loading '/usr/local/aolserver/bin/nsldap.so' [10/Jan/2006:11:11:08][22553.3076437088][-main-] Debug: nsldap: allowing * -> pool ldap [10/Jan/2006:11:11:08][22553.3076437088][-main-] Debug: nsldap: adding pool ldap to the list of allowed pools [10/Jan/2006:11:11:08][22553.3076437088][-main-] Debug: nsldap: Registering LDAPCheckPools (600) auth-ldap + driver installation Next, visit the software installation page in acs-admin and install the auth-ldap package. Your OpenACS installation now has all the code required to authenticate using nsldap, so now you need to configure your site's authentication to take advantage of it. To add the authentication driver to your OpenACS instance, go to: Main Site, Site-Wide Administration, and then Authentication Here's some sample Authentication Driver values: Name=Active Directory, Short Name=AD, Enabled=Yes, Authentication=LDAP, Password Management=LDAP You may wish to push this new authority to the top of the list so it will become the default for users on the login screen. Next, you have to configure the authentication driver parameters by going to: Main Site, Site-Wide Administration, Authentication, Active Directory, and then Configure Parameters that match our example will look like: UsernameAttribute=sAMAccountNMame, BaseDN= cn=Users,dc=mydomain,dc=com, InfoAttributeMap=first_names=givenName;last_name=sn;email=mail, PasswordHash=N/A Code Tweaks for Bind Bind-style authentication is not supported via configuration parameters, so we will have to modify the tcl authentication routine to provide this behavior. You'll have to modify the existing ./packages/auth-ldap/tcl/auth-ldap-procs.tcl file to support bind authentication. First toggle ldap bind support. Change this: # LDAP bind based authentication ? set ldap_bind_p 0 if {$ldap_bind_p==1} { ... to this: # LDAP bind based authentication ? set ldap_bind_p 1 if {$ldap_bind_p==1} { ... Then change the bind to first do a search to resolve to account name provided by the user to a fully qualified domain name (FQDN), which the LDAP server uses as a primary key. Change this: set lh [ns_ldap gethandle] if {[ns_ldap bind $lh "cn=$cn" "$password"]} { set result(auth_status) ok } to this set lh [ns_ldap gethandle] set fdn [lindex [lindex [ns_ldap search $lh -scope subtree $params(BaseDN) "($params(UsernameAttribute)=$username)" dn] 0] 1] if {[ns_ldap bind $lh $fdn $password]} { set result(auth_status) ok } Troubleshooting If you're having trouble figuring out some the values for the ldapm, see this useful page on setting up Active Directory integration with Bugzilla. It explains how distinguished names are defined in Active Directory, and how to test that you have the correct values for connectivity and base DN using the OpenLDAP command-line utility ldapsearch. John had an issue where nsldap was not loading because AOLServer couldn't find the openldap client libraries, but he was able to fix it by adding the openldap libraries to his LD_LIBRARY_PATH (e.g. /usr/local/openldap/lib) Credits Thanks to Malte Sussdorf for his help and the Laboratory of Computer Science at Massachusetts General Hospital for underwriting this work. Configure Batch Synchronization Browse to the authentication administration page, http://yourserver/acs-admin/auth/ and choose an authority for batch sync. Set Batch sync enabled to Yes. Set GetDocument Implementation to HTTP GET. Set ProcessDocument Implementation to IMS Enterprise 1.1. These settings will cause OpenACS to attempt to retrieve via HTTP a list of users in XML format from a location we will specify in a few steps. Click OK. On the next page, click Configure on the GetDocument Implementation line. Enter either or both the IncrementalURL and SnapshotURL. These are the URLs which the external Authority will supply with XML files in IMS Enterprise 1.1 format. Configure your Authority (RADIUS server, etc) to supply XML files to the URLs IncrementalURL and SnapshotURL. A typical set of incremental file record looks like: example missing A snapshot file is similar but doesn't have recstatus, since it's not a delta but a list of valid records. See the larger example in the design document for more details. (More information: , The IMS 1.1 spec) ($Id: install.xml,v 1.5 2006/06/04 00:45:21 donb Exp $)
    openacs-5.7.0/packages/acs-authentication/www/doc/xml/example.xml0000644000175000017500000000134710011726063024703 0ustar frankiefrankie FOO dotLRN DB Increment 28-oct-2003#16:06:02 FOO karlf Karl Fritz karlf@example.net ... LL1 openacs-5.7.0/packages/acs-authentication/www/doc/xml/design.xml0000644000175000017500000002317107742743722024542 0ustar frankiefrankie
    Design by Joel Aufrecht IMS Sync driver design by Lars Pind TODO We need examples of how the communication would be done from our clients. The "GetDocument" communications service contract could be a generic system-wide service contract. We might need a source/ID column in the users table to identify where they're imported from for doing updates, particularly if importing from multiple sources (or when some users are local.) Execution Story We will parse a document in the IMS Enterprise Specification format (example XML document), and translate it into calls to the batch user sync API. The document will contain either the complete user listitemst (IMS: "snapshot"), or an incremental user listitemst (IMS: "Event Driven" -- contains only adds, edits, and deletes). You could for example do a complete transfer once a month, and incrementals every night. The invocation should decide which type is returned. The design should favor interoperability, reliability and robustness. <enterprise> <properties> <datasource>Dunelm Services Limited</datasource> <target>Telecommunications LMS</target> <type>DATABASE UPDATE</type> <datetime>2001-08-08</datetime> </properties> <person recstatus = "1"> <comments>Add a new Person record.</comments> <sourcedid> <source>Dunelm Services Limited</source> <id>CK1</id> </sourcedid> <name> <fn>Clark Kent</fn> <sort>Kent, C</sort> <nickname>Superman</nickname> </name> <demographics> <gender>2</gender> </demographics> <adr> <extadd>The Daily Planet</extadd> <locality>Metropolis</locality> <country>USA</country> </adr> </person> <person recstatus = "2"> <comments>Update a previously created record.</comments> <sourcedid> <source>Dunelm Services Limited</source> <id>CS1</id> </sourcedid> <name> <fn>Colin Smythe</fn> <sort>Smythe, C</sort> <nickname>Colin</nickname> <n> <family>Smythe</family> <given>Colin</given> <other>Manfred</other> <other>Wingarde</other> <prefix>Dr.</prefix> <suffix>C.Eng</suffix> <partname partnametype = "Initials">C.M.W.</partname> </n> </name> <demographics> <gender>2</gender> <bday>1958-02-18</bday> <disability>None.</disability> </demographics> <email>colin@dunelm.com</email> <url>http://www.dunelm.com</url> <tel teltype = "Mobile">4477932335019</tel> <adr> <extadd>Dunelm Services Limited</extadd> <street>34 Acorn Drive</street> <street>Stannington</street> <locality> Sheffield</locality> <region>S.Yorks</region> <pcode>S7 6WA</pcode> <country>UK</country> </adr> <photo imgtype = "gif"> <extref>http://www.dunelm.com/staff/colin2.gif</extref> </photo> <institutionrole primaryrole = "No" institutionroletype = "Alumni"/> <datasource>dunelm:colinsmythe:1</datasource> </person> <person recstatus = "3"> <comments>Delete this record.</comments> <sourcedid> <source>Dunelm Services Limited</source> <id>LL1</id> </sourcedid> <name> <fn>Lois Lane</fn> <sort>Lane, L</sort> </name> </person> </enterprise> Above would get translated into calls to the batch sync API as follows: for { ... loop over persons in the document ... } { auth::batch::transaction \ -job_id $job_id \ -operation [ad_decode $recstatus 2 "update" 3 "delete" "insert"] \ -authority_id $authority_id \ -username { $userid if present, otherwise $sourcedid.id } \ -first_names { $name.given if present, otherwise all except last part of $name.fn } \ -last_name { $name.family if present, otherwise last part of $name.fn } \ -email { $person.email ; we require this, even though the specification does not } \ -url { $url, if present } \ -portrait_url { $photo.imgtype/$photo.extref -- grab photo, store in DB } } } Mandatory fields which we can rely on are: sourcedid: ID as defined by the source system. Used for username. name.fn (formatted name). Used for first_names, last_name Note that we require 'email' attribute, but the IMS Enterprise spec does not. Hence, unless we change our data model to allow users without an email address, we will have to throw an error. Here's how we map IMS enterprise to OpenACS tables. username: <userid> ... </userid> if present. <sourcedid><id> ... </id></sourcedid> otherwise first_names: <name><given> ...</given></name> if present. <name><fn> ... ...</fn></name> otherwise last_name: <name><family> ...</family></name> if present. <name><fn>... ...</fn></name> otherwise email: <email> ...</email> if present. Blank/unchanged if not. url: <url> ...</url> if present. Blank/unchanged if not. portrait: <photo imgtype="gif"><extref>...</extref></photo> if present: HTTP GET the photo, insert it into the system. (Do we do this, then, with all users when doing a snapshot update?) Resources Consolidation before the leap; IMS Enterprise 1.1: This article says that IMS Enterprise 1.1 (current version) does not address the communication model, which is critically missing for real seamless interoperability. IMS Enterprise 2.0 will address this, but Blackboard, who's influential in the IMS committee, is adopting OKI's programming interrfaces for this. IMS and OKI, the wire and the socket
    openacs-5.7.0/packages/acs-authentication/www/doc/xml/index.xml0000644000175000017500000000110407742743722024370 0ustar frankiefrankie ]> External Authentication Section Missing Section Missing openacs-5.7.0/packages/acs-authentication/www/doc/index.html0000644000175000017500000000443710440426441023731 0ustar frankiefrankieExternal Authentication
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/www/doc/ims-sync-driver-design.html0000644000175000017500000002457610015147536027135 0ustar frankiefrankieIMS Sync driver design

    IMS Sync driver design

    by Lars Pind OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    TODO

    We need examples of how the communication would be done from our clients.

    The "GetDocument" communications service contract could be a generic system-wide service contract.

    We might need a source/ID column in the users table to identify where they're imported from for doing updates, particularly if importing from multiple sources (or when some users are local.)

    Execution Story

    1. We will parse a document in the IMS Enterprise Specification format (example XML document), and translate it into calls to the batch user sync API.

    2. The document will contain either the complete user listitemst (IMS: "snapshot"), or an incremental user listitemst (IMS: "Event Driven" -- contains only adds, edits, and deletes). You could for example do a complete transfer once a month, and incrementals every night. The invocation should decide which type is returned.

    The design should favor interoperability, reliability and robustness.

    <enterprise>
    
      <properties>
        <datasource>Dunelm Services Limited</datasource>
        <target>Telecommunications LMS</target>
        <type>DATABASE UPDATE</type>
    
        <datetime>2001-08-08</datetime>
      </properties>
      <person recstatus = "1">
        <comments>Add a new Person record.</comments>
        <sourcedid>
    
          <source>Dunelm Services Limited</source>
          <id>CK1</id>
        </sourcedid>
        <name>
          <fn>Clark Kent</fn>
    
          <sort>Kent, C</sort>
          <nickname>Superman</nickname>
        </name>
        <demographics>
          <gender>2</gender>
    
        </demographics>
        <adr>
          <extadd>The Daily Planet</extadd>
          <locality>Metropolis</locality>
          <country>USA</country>
    
        </adr>
      </person>
      <person recstatus = "2">
        <comments>Update a previously created record.</comments>
        <sourcedid>
    
          <source>Dunelm Services Limited</source>
          <id>CS1</id>
        </sourcedid>
        <name>
          <fn>Colin Smythe</fn>
    
          <sort>Smythe, C</sort>
          <nickname>Colin</nickname>
          <n>
            <family>Smythe</family>
    
            <given>Colin</given>
            <other>Manfred</other>
            <other>Wingarde</other>
            <prefix>Dr.</prefix>
    
            <suffix>C.Eng</suffix>
            <partname partnametype = "Initials">C.M.W.</partname>
          </n>
        </name>
        <demographics>
    
          <gender>2</gender>
          <bday>1958-02-18</bday>
          <disability>None.</disability>
        </demographics>
    
        <email>colin@dunelm.com</email>
        <url>http://www.dunelm.com</url>
        <tel teltype = "Mobile">4477932335019</tel>
        <adr>
    
          <extadd>Dunelm Services Limited</extadd>
          <street>34 Acorn Drive</street>
          <street>Stannington</street>
          <locality> Sheffield</locality>
    
          <region>S.Yorks</region>
          <pcode>S7 6WA</pcode>
          <country>UK</country>
        </adr>
    
        <photo imgtype = "gif">
          <extref>http://www.dunelm.com/staff/colin2.gif</extref>
        </photo>
        <institutionrole primaryrole = "No" institutionroletype = "Alumni"/>
        <datasource>dunelm:colinsmythe:1</datasource>
    
      </person>
      <person recstatus = "3">
        <comments>Delete this record.</comments>
        <sourcedid>
          <source>Dunelm Services Limited</source>
    
          <id>LL1</id>
        </sourcedid>
        <name>
          <fn>Lois Lane</fn>
          <sort>Lane, L</sort>
    
        </name>
      </person>
    </enterprise>
    

    Above would get translated into calls to the batch sync API as follows:

    for { ... loop over persons in the document ... } {
            auth::batch::transaction \
                -job_id $job_id \
                -operation [ad_decode $recstatus 2 "update" 3 "delete" "insert"] \
                -authority_id $authority_id \
                -username { $userid if present, otherwise $sourcedid.id } \
                -first_names { $name.given if present, otherwise all except last part of $name.fn } \
                -last_name { $name.family if present, otherwise last part of $name.fn } \
                -email { $person.email ; we require this, even though the specification does not } \
                -url { $url, if present } \
                -portrait_url { $photo.imgtype/$photo.extref -- grab photo, store in DB }
        }
    }
    

    Mandatory fields which we can rely on are:

    1. sourcedid: ID as defined by the source system. Used for username.

    2. name.fn (formatted name). Used for first_names, last_name

    Note that we require 'email' attribute, but the IMS Enterprise spec does not. Hence, unless we change our data model to allow users without an email address, we will have to throw an error.

    Here's how we map IMS enterprise to OpenACS tables.

    1. username:

      1. <userid> ... </userid> if present.

      2. <sourcedid><id> ... </id></sourcedid> otherwise

    2. first_names:

      1. <name><given> ...</given></name> if present.

      2. <name><fn> ... ...</fn></name> otherwise

    3. last_name:

      1. <name><family> ...</family></name> if present.

      2. <name><fn>... ...</fn></name> otherwise

    4. email:

      1. <email> ...</email> if present.

      2. Blank/unchanged if not.

    5. url:

      1. <url> ...</url> if present.

      2. Blank/unchanged if not.

    6. portrait:

      1. <photo imgtype="gif"><extref>...</extref></photo> if present: HTTP GET the photo, insert it into the system. (Do we do this, then, with all users when doing a snapshot update?)

    Resources

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/www/doc/acs-authentication.htm0000644000175000017500000001753610171476642026246 0ustar frankiefrankie OpenACS Authentication

    acs-authentication

    This document aims to help you understand how it works and how you can use it for your own purpouses. By Rocael Hernández R.

    Main functionality: It is used to authenticate any user in an openacs installations.

    So far, you can use it to authenticate against LDAP & PAM, and of course, locally. You can implement your own based on your needs, processes, etc.

    Definition: SC = service-contract

     

    Authorities

    acs-authentication can have multiple authorities, each one represent an specific configuration of authenticatication. For instance, in your openacs installation you can have users related to different authorities, some of them might authenticate locally since they are external or invited, others belongs to your corporate network and already have users, so might authenticate against LDAP and others in your own work office might use PAM for authentication because your local system authentication. Plus you might define an specific implementation (using the set of SC) to connect to your client DB, which is in another DB, and allow your clients login to certain parts of your website. Then, this is right way to handle all those set of users, that already might have an account in another place and you just want them to authenticate against that external system.

    The idea is: each user belongs to a given authority, and just one .

    To add an authority in your installation go to /acs-admin/auth/ and click on "Create new authority".

    When adding the authority you need to configure:

    • Authentication method (where to authenticate, i.e. check user/password)
    • Password Management (where to update passwords)
    • Account Registration (where to create new accounts)
    • On-Demand Sync (to get user info from the source in real time)

    Those configurations simply will perform the tcl proc that is defined in the SC above described for the given SC implementation that you choose. In other words:

    • For using LDAP, you need to install auth-ldap, on its installation, this package will create an implementation of the above mentioned SC definitions (look at "specs" that define which proc needs to be called for each alias).
    • PAM package is auth-pam.
    • Probably, for any new authentication method you'll need to create your own package in the same style of auth-ldap or auth-pam.

     

    Note: "Batch Synchronization" will not be administered there anymore in the future, everything will go to ims-ent.

    Also, depending on each implementation, it has a set of parameters that will require for the configuration to work. And those parameters are set independently by authority / authentication method, so for LDAP you'll be able to configure the next set of parameters:

    • DNPattern
    • UsernameAttribute
    • Elements
    • BaseDN
    • Attributes
    • PasswordHash

    Then you can enter your specific values for your server, is likely that the recomemded ones will work fine.

    Hint: nssha (SSHA) doesn't work well with LDAP use ns_passwd or another encription method (MD5...)

    You can make your users to loging using the email or username, by changing the paramenter at the kernel named: UseEmailForLoginP under Security section. If username is used for loging, it will ask for the authority to use, since username is unique by authority but not for the entire openacs installation (can exists several identic usernames but each one belongs to a different authority).

     

    acs-authentication defines a set of SC to interact with the different authentication implementations (LDAP or PAM):

    1. auth_authentication "Authenticate users and retrieve their account status.", with the operations:
      • Authenticate
      • GetParameters
    2. auth_password "Update, reset, and retrieve passwords for authentication.", with the operations:
      • CanChangePassword
      • ChangePassword
      • CanRetrievePassword
      • RetrievePassword
      • CanResetPassword
      • ResetPassword
      • GetParameters
    3. auth_registration "Registering accounts for authentication", with the operations:
      • GetElements
      • Register
      • GetParameters
    4. auth_sync_retrieve
    5. auth_sync_process
    6. auth_user_info
      • GetUserInfo
      • GetParameters

    Note: #4 & #5 will be taken out from authentication and moved to the package ims-ent.

    The SC definitions are quite straightforward, then worth to look at them for better understanding.

     

    Login process

    In an openacs site the login is managed through acs-authentication. It happens like this:

    1. The user enters the email/user & password
    2. It will search the user in the users table and return the authority_id
    3. With that authority_id it will find the respective SC implementation which contains the adecuate tcl proc for the authentication process
    4. That proc will check the identity of the user based on the password (right now could be locally, pam or ldap authenticated, though this model supports N methods of authentication)

     

    openacs-5.7.0/packages/acs-authentication/www/doc/ext-auth-ldap-install.html0000644000175000017500000002236410440426441026742 0ustar frankiefrankieUsing LDAP/Active Directory with OpenACS

    Using LDAP/Active Directory with OpenACS

    by John Sequeira, Michael Steigman, and Carl Blesius. OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.

    ToDo: Add/verify information on on-demand sync, account registration, and batch synchronization. Add section on ldapsearch.

    Overview. You do not want to make users remember yet another password and username. If you can avoid it you do not want to store their passwords either. This document should help you set your system up so your users can seamlessly log in to your OpenACS instance using the password they are accustomed to using for other things at your institution.

    Background. The original OpenACS LDAP implementation (which has been depreciated by this package) treated the LDAP server as another data store similar to Oracle or Postgresql. It opened a connection using a priveleged account and read or stored an encrypted password for the user in question. This password was independent of the user's operating system or network account, and had to be synchronized if you wanted the same password for OpenACS.Save their passwords? Sync passwords? Deal with forgotten password requests? No Thanks. Using ldap bind, you can delegate authentication completely to LDAP. This way you can let the IT department (if you are lucky) worry about password storage/synchronization/etc. The bind operation takes a username and password and returns a true of false depending on whether they match up. This document takes the 'bind' approach so that your users LDAP/AD password (or whatever else you use) can be used to login to OpenACS.

    Note on Account Creation. On the authentication driver configure screens, you will also see lots of options for synchronizing users between your directory and OpenACS. This document takes the approach of provisioning users on demand instead of ahead-of-time. This means that when they attempt to login to OpenACS, if they have a valid Windows account, we'll create an account for them in OpenACS and log them in.

    1. Installing AOLserver LDAP support (openldap and nsldap). Install openldap and nsldap using the document Malte created Next, modify your config.tcl file as directed in the nsldap README. Here's what the relevant additions should look like:

        
      # LDAP authentication
      ns_param   nsldap             ${bindir}/nsldap.so
      
      ...
      
      ns_section "ns/ldap/pool/ldap"
      ns_param user "cn=Administrator, cn=Users, dc=mydomain, dc=com"
      ns_param password "password"
      ns_param host "directory.mydomain.com"
      ns_param connections 1
      ns_param verbose On
      
      ns_section "ns/ldap/pools"
      ns_param ldap ldap
      
      ns_section "ns/server/${server}/ldap"
      ns_param pools *
      ns_param defaultpool ldap
         
        

      To verify that this is all working, restart Aolserver and ensure that you see something like this in your error.log:

          
      [10/Jan/2006:11:11:07][22553.3076437088][-main-] Notice: modload: loading '/usr/local/aolserver/bin/nsldap.so'
      [10/Jan/2006:11:11:08][22553.3076437088][-main-] Debug: nsldap: allowing * -> pool ldap
      [10/Jan/2006:11:11:08][22553.3076437088][-main-] Debug: nsldap: adding pool ldap to the list of allowed pools
      [10/Jan/2006:11:11:08][22553.3076437088][-main-] Debug: nsldap: Registering LDAPCheckPools (600)
          
         
    2. auth-ldap + driver installation. Next, visit the software installation page in acs-admin and install the auth-ldap package. Your OpenACS installation now has all the code required to authenticate using nsldap, so now you need to configure your site's authentication to take advantage of it. To add the authentication driver to your OpenACS instance, go to: Main Site, Site-Wide Administration, and then AuthenticationHere's some sample Authentication Driver values:Name=Active Directory, Short Name=AD, Enabled=Yes, Authentication=LDAP, Password Management=LDAPYou may wish to push this new authority to the top of the list so it will become the default for users on the login screen.Next, you have to configure the authentication driver parameters by going to: Main Site, Site-Wide Administration, Authentication, Active Directory, and then ConfigureParameters that match our example will look like:UsernameAttribute=sAMAccountNMame, BaseDN= cn=Users,dc=mydomain,dc=com, InfoAttributeMap=first_names=givenName;last_name=sn;email=mail, PasswordHash=N/A

    3. Code Tweaks for Bind. Bind-style authentication is not supported via configuration parameters, so we will have to modify the tcl authentication routine to provide this behavior.You'll have to modify the existing ./packages/auth-ldap/tcl/auth-ldap-procs.tcl file to support bind authentication.First toggle ldap bind support.Change this:

          
      # LDAP bind based authentication ?
      set ldap_bind_p 0
      if {$ldap_bind_p==1} {
      ...
          
         

      to this:

          
      # LDAP bind based authentication ?
      set ldap_bind_p 1
      
      if {$ldap_bind_p==1} {
      ...
          
         

      Then change the bind to first do a search to resolve to account name provided by the user to a fully qualified domain name (FQDN), which the LDAP server uses as a primary key.Change this:

          
      set lh [ns_ldap gethandle]
      
      if {[ns_ldap bind $lh "cn=$cn" "$password"]} {
          set result(auth_status) ok
      }    
          
         

      to this

      
      set lh [ns_ldap gethandle]
      
      set fdn [lindex [lindex [ns_ldap search $lh -scope subtree $params(BaseDN) "($params(UsernameAttribute)=$username)" dn] 0] 1]
      
      if {[ns_ldap bind $lh $fdn $password]} {
          set result(auth_status) ok
      }    
          
         

    Troubleshooting. If you're having trouble figuring out some the values for the ldapm, see this useful page on setting up Active Directory integration with Bugzilla. It explains how distinguished names are defined in Active Directory, and how to test that you have the correct values for connectivity and base DN using the OpenLDAP command-line utility ldapsearch.John had an issue where nsldap was not loading because AOLServer couldn't find the openldap client libraries, but he was able to fix it by adding the openldap libraries to his LD_LIBRARY_PATH (e.g. /usr/local/openldap/lib)

    Credits. Thanks to Malte Sussdorf for his help and the Laboratory of Computer Science at Massachusetts General Hospital for underwriting this work.

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/www/doc/configure-batch-sync.html0000644000175000017500000001132510015147536026631 0ustar frankiefrankieConfigure Batch Synchronization

    Configure Batch Synchronization

    1. Browse to the authentication administration page, http://yourserver/acs-admin/auth/ and choose an authority for batch sync.

    2. Set Batch sync enabled to Yes. Set GetDocument Implementation to HTTP GET. Set ProcessDocument Implementation to IMS Enterprise 1.1. These settings will cause OpenACS to attempt to retrieve via HTTP a list of users in XML format from a location we will specify in a few steps.

    3. Click OK.

    4. On the next page, click Configure on the GetDocument Implementation line.

    5. Enter either or both the IncrementalURL and SnapshotURL. These are the URLs which the external Authority will supply with XML files in IMS Enterprise 1.1 format.

    6. Configure your Authority (RADIUS server, etc) to supply XML files to the URLs IncrementalURL and SnapshotURL. A typical set of incremental file record looks like:

      <?xml version="1.0" encoding="ISO-8859-1"?>
      <enterprise>
        <properties>
          <datasource>FOO</datasource>
          <target>dotLRN</target>
          <type>DB Increment</type>
          <datetime>28-oct-2003#16:06:02</datetime>
        </properties>
        <person recstatus = "1">
          <sourcedid>
            <source>FOO</source>
            <id>karlf</id>
          </sourcedid>
          <name>
            <n>
              <given>Karl</given>
              <family>Fritz</family>
              <prefix></prefix>
            </n>
          </name>
          <email>karlf@example.net</email>
        </person>
        <person recstatus = "2">    <!--modified person-->
          ...
        </person>
        <person recstatus = "3">    <!--deleted person-->
        <sourcedid>
          <id>LL1</id>      <!--only requires username-->
        </sourcedid>
        </person>
      </enterprise>
      

      A snapshot file is similar but doesn't have recstatus, since it's not a delta but a list of valid records. See the larger example in the design document for more details.

      (More information: the section called “IMS Sync driver design”, The IMS 1.1 spec)

    ($Id: configure-batch-sync.html,v 1.2 2004/02/19 14:59:42 joela Exp $)
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/www/doc/ext-auth-pam-install.html0000644000175000017500000002216510440426441026576 0ustar frankiefrankieUsing Pluggable Authentication Modules (PAM) with OpenACS

    Using Pluggable Authentication Modules (PAM) with OpenACS

    OpenACS supports PAM authetication via the ns_pam module in AOLserver.

    1. Add PAM support to AOLserver. OpenACS supports PAM support via the PAM AOLserver module. PAM is system of modular support, and can provide local (unix password), RADIUS, LDAP (more information), and other forms of authentication. Note that due to security issues, the AOLserver PAM module cannot be used for local password authentication.

      1. Compile and install ns_pam. Download the tarball to /tmp.

        Debian users: first do apt-get install libpam-dev

        [root@yourserver root]# cd /usr/local/src/aolserver
        [root@yourserver aolserver]# tar xzf /tmp/ns_pam-0.1.tar.gz
        [root@yourserver aolserver]# cd nspam
        [root@yourserver nspam]# make
        gcc -I/usr/include/pam -I/usr/local/aolserver/include -D_REENTRANT=1 
          -DNDEBUG=1 -g -fPIC -Wall -Wno-unused -mcpu=i686 -DHAVE_CMMSG=1 
          -DUSE_FIONREAD=1 -DHAVE_COND_EINTR=1   -c -o nspam.o nspam.c
        nspam.c: In function `PamCmd':
        nspam.c:107: warning: implicit declaration of function `Tcl_SetObjResult'
        nspam.c:107: warning: implicit declaration of function `Tcl_NewIntObj'
        gcc -I/usr/include/pam -I/usr/local/aolserver/include -D_REENTRANT=1 
          -DNDEBUG=1 -g -fPIC -Wall -Wno-unused -mcpu=i686 -DHAVE_CMMSG=1 
          -DUSE_FIONREAD=1 -DHAVE_COND_EINTR=1   -c -o pam_support.o pam_support.c
        /bin/rm -f nspam.so
        gcc -shared -nostartfiles -o nspam.so nspam.o pam_support.o -lpam
        [root@yourserver nspam]# make install
        [root@yourserver nspam]#
        cd /usr/local/src/aolserver
        tar xzf /tmp/ns_pam-0.1.tar.gz
        cd nspam
        make
        make install
      2. Set up a PAM domain. A PAM domain is a set of rules for granting privileges based on other programs. Each instance of AOLserver uses a domain; different aolserver instances can use the same domain but one AOLserver instance cannot use two domains. The domain describes which intermediate programs will be used to check permissions. You may need to install software to perform new types of authentication.

        • RADIUS in PAM. 

          1. Untar the pam_radius tarball and compile and install. (more information)

            [root@yourserver root]# cd /usr/local/src/
            [root@yourserver src]# tar xf /tmp/pam_radius-1.3.16.tar
            [root@yourserver src]# cd pam_radius-1.3.16
            [root@yourserver pam_radius-1.3.16]# make
            cc -Wall -fPIC -c pam_radius_auth.c -o pam_radius_auth.o
            cc -Wall -fPIC   -c -o md5.o md5.c
            ld -Bshareable pam_radius_auth.o md5.o -lpam -o pam_radius_auth.so
            [root@yourserver pam_radius-1.3.16]# cp pam_radius_auth.so /lib/security/pam_radius_auth.so
            [root@yourserver pam_radius-1.3.16]#
            cd /usr/local/src/
            tar xf /tmp/pam_radius-1.3.16.tar
            cd pam_radius-1.3.16
            make
            cp pam_radius_auth.so /lib/security/pam_radius_auth.so

            Debian users: apt-get install libpam-radius-auth

          2. Set up the PAM domain. Recent PAM distributions have a different file for each domain, all in /etc/pam.d. Previous PAM setups put all domain configuration lines into a single file, /etc/pam.conf. On Red Hat, create the file /etc/pam.d/service0 with these contents:

            auth       sufficient   /lib/security/pam_radius_auth.so
            
          3. Modify the AOLserver configuration file to use this PAM domain. Edit the line

            ns_param   PamDomain             "service0"

            So that the value of the parameter matches the name (just the file name, not the fully pathed name) of the domain file in

            /etc/pam.d/
        • LDAP in PAM. more information

      3. Modify the AOLserver configuration file to support ns_pam. 

        In /var/lib/aolserver/service0/etc/config.tcl, enable the nspam module by uncommenting this line:

        ns_param   nspam           ${bindir}/nspam.so
    2. Install auth-pam OpenACS service package. Install auth-pam and restart the server.

    3. Create an OpenACS authority. OpenACS supports multiple authentication authorities. The OpenACS server itself is the "Local Authority," used by default.

      1. Browse to the authentication administration page, http://yourserver/acs-admin/auth/. Create and name an authority (in the sitewide admin UI)

      2. Set Authentication to PAM.

      3. If the PAM domain defines a password command, you can set Password Management to PAM. If not, the PAM module cannot change the user's password and you should leave this option Disabled.

      4. Leave Account Registration disabed.

      5. Configure Batch Synchronization

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/www/doc/ext-auth-design.html0000644000175000017500000000457210015147536025633 0ustar frankiefrankieDesign

    Design


    Table of Contents

    IMS Sync driver design
    by Joel Aufrecht OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/www/doc/ext-auth-install.html0000644000175000017500000000526610440426441026026 0ustar frankiefrankieInstallation

    Installation


    by Joel Aufrecht

    OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.
    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-authentication/acs-authentication.info0000644000175000017500000001056211575167336025016 0ustar frankiefrankie Authentication Authentication t t Lars Pind Authentication, account management, and related functionality. 2011-06-12 3 Collaboraid 3 GPL version 2 Implements authentication-related security functions for OpenACS, including password, account and session management, bulk account creation etc. Provides a contract based interface for different authentication methods such as PAM or LDAP based authentication. openacs-5.7.0/packages/acs-authentication/catalog/0000755000175000017500000000000011724401450021744 5ustar frankiefrankieopenacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.zh_TW.utf-8.xml0000644000175000017500000000033710727201370030251 0ustar frankiefrankie 無效的使用者å稱或密碼 openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.pa_IN.utf-8.xml0000644000175000017500000000060710727201370030204 0ustar frankiefrankie Batch edit these messages Message Key English (US) Message Punjabi Message acs-authentication.Invalid_username_or_password ਗਲਤ ਉਪਭੋਗੀ ਨਾਂ ਜਾਂ ਗà©à¨ªà¨¤-ਕੋਡ openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.en_AU.ISO-8859-1.xml0000644000175000017500000000037610440426441030450 0ustar frankiefrankie Invalid username or password openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.th_TH.utf-8.xml0000644000175000017500000000037310727201370030224 0ustar frankiefrankie username หรือ password ไม่ถูà¸à¸•้อง openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.zh_CN.utf-8.xml0000644000175000017500000000032610727201370030215 0ustar frankiefrankie ç”¨æˆ·åæˆ–密ç é”™è¯¯ openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.fr_FR.ISO-8859-1.xml0000644000175000017500000000036310727201370030453 0ustar frankiefrankie Nom d'utilisateur ou mot de passe incorrect openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.gl_ES.ISO-8859-1.xml0000644000175000017500000000034610727201370030447 0ustar frankiefrankie Usuario ou contrasinal erróneo openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.de_DE.ISO-8859-1.xml0000644000175000017500000000036710720127055030421 0ustar frankiefrankie Benutzeridentifikation oder Passwort ist falsch openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.nl_NL.ISO-8859-1.xml0000644000175000017500000000035610727201370030461 0ustar frankiefrankie Ongeldige gebruikersnaam of wachtwoord openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.el_GR.utf-8.xml0000644000175000017500000000043110720404625030202 0ustar frankiefrankie Το όνομα του χÏήστη ή ο κωδικός δεν είναι αποδεκτά openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.es_GT.ISO-8859-1.xml0000644000175000017500000000034510727201370030456 0ustar frankiefrankie Usuario o contraseña invalido openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.ms_MY.utf-8.xml0000644000175000017500000000034610727201370030242 0ustar frankiefrankie Nama pengguna atau kata laluan tidak sah openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.cs_CZ.utf-8.xml0000644000175000017500000000037710540362676030235 0ustar frankiefrankie Neplatné uživatelské jméno nebo heslo openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.nn_NO.ISO-8859-1.xml0000644000175000017500000000034410727201370030463 0ustar frankiefrankie Invalid username or password openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.ru_RU.utf-8.xml0000644000175000017500000000041210727201370030244 0ustar frankiefrankie Ðеправильное Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ пароль openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.ca_ES.ISO-8859-1.xml0000644000175000017500000000034410727201370030426 0ustar frankiefrankie Usuari o contrasenya erroni openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.fa_IR.utf-8.xml0000644000175000017500000000037210727201370030175 0ustar frankiefrankie نام کاربری یا کلمه عبور صحیح نیست openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.hu_HU.utf-8.xml0000644000175000017500000000035210727201370030223 0ustar frankiefrankie Érvénytelen felhasználónév vagy jelszó openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.tr_TR.utf-8.xml0000644000175000017500000000033710727201370030250 0ustar frankiefrankie Gecersiz kullanici adi veya sifre openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.nl_ZA.ISO-8859-1.xml0000644000175000017500000000040410540362676030466 0ustar frankiefrankie Ongeldige gebruikersnaam of wagwoord openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.ind_ID.utf-8.xml0000644000175000017500000000033310727201370030340 0ustar frankiefrankie Invalid username or password openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.en_US.ISO-8859-1.xml0000644000175000017500000000116711061303702030463 0ustar frankiefrankie Add to Community Add to %system_name% Does not have an account on %system_name% Has an account on %system_name% Invalid username or password Not getting the results you expected? Try searching: openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.ar_LB.utf-8.xml0000644000175000017500000000036110727201370030172 0ustar frankiefrankie الاسم او كلمة السر غير صحيحة openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.pt_BR.ISO-8859-1.xml0000644000175000017500000000033710727201370030464 0ustar frankiefrankie Nome ou senha inválidos openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.eu_ES.ISO-8859-1.xml0000644000175000017500000000034010727201370030450 0ustar frankiefrankie izen edo pasahitz okerra openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.da_DK.ISO-8859-1.xml0000644000175000017500000000035110727201370030414 0ustar frankiefrankie Ugyldigt brugernavn eller kodeord openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.no_NO.ISO-8859-1.xml0000644000175000017500000000034510727201370030465 0ustar frankiefrankie Feil brukernavn eller passord openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.hi_IN.utf-8.xml0000644000175000017500000000043510727201370030203 0ustar frankiefrankie नियम विरà¥à¤§à¥à¤¦ यूसरनेम या पासà¥à¤µà¤°à¥à¤¡à¥ । openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.es_CO.ISO-8859-1.xml0000644000175000017500000000034510727201370030445 0ustar frankiefrankie Usuario o contraseña invalido openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.es_ES.ISO-8859-1.xml0000644000175000017500000000116711126172057030461 0ustar frankiefrankie Añadir a comunidad Añadir a %system_name% No tiene cuenta en %system_name% Tiene cuenta en %system_name% Usuario o contraseña erroneo Si no ha obtenido los resultados esperados, intente buscar: openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.it_IT.ISO-8859-1.xml0000644000175000017500000000036010727201370030462 0ustar frankiefrankie Nome utente o password non sono corretti openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.ro_RO.utf-8.xml0000644000175000017500000000035610727201370030237 0ustar frankiefrankie parola sau numele de utilizator nu sunt valabile openacs-5.7.0/packages/acs-authentication/catalog/acs-authentication.pl_PL.utf-8.xml0000644000175000017500000000035210727201370030221 0ustar frankiefrankie NieprawidÅ‚owe hasÅ‚o lub nazwa użytkownika openacs-5.7.0/packages/acs-templating/0000755000175000017500000000000011724401447017465 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/tcl/0000755000175000017500000000000011724401447020247 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/tcl/test/0000755000175000017500000000000011724401447021226 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/tcl/test/spell-checker-procs.tcl0000644000175000017500000001534710551254405025606 0ustar frankiefrankiead_library { Automated tests for spell-checker @author Ola Hansson (ola@polyxena.net) @creation-date 28 September 2003 @cvs-id $Id: spell-checker-procs.tcl,v 1.7 2007/01/10 21:22:13 gustafn Exp $ } aa_register_case -cats { api } spellcheck__get_element_formtext { Test the spell-check proc that does the actual spell-checking. } { set base_command [list template::util::spellcheck::get_element_formtext \ -var_to_spellcheck var_to_spellcheck \ -error_num_ref error_num \ -formtext_to_display_ref formtext_to_display \ -just_the_errwords_ref just_the_errwords] ##### # # Plain text without spelling mistakes # ##### set command $base_command lappend command -text "This sentence does not contain any misspelled words. What we have here is plain text." aa_log "--- Correct text --- $command" eval $command aa_true "True statement: Text contains no misspelled words" [expr {$error_num == 0}] aa_log "Number of miss-spelled words found in text: $error_num" aa_false "False statement: Text contains misspelled word(s)" [expr {$error_num > 0}] aa_equals "Number of misspelled words found in text" $error_num 0 aa_log "Returned string: $formtext_to_display" aa_true "The returned string contains a hidden var named 'var_to_spellcheck.merge_text'" \ [regexp "var_to_spellcheck.merge_text" $formtext_to_display] aa_true "The returned string contains no hidden var(s) named 'var_to_spellcheck.error_N', where N is the error number." \ ![regexp "var_to_spellcheck.error_\[0-9\]*" $formtext_to_display] aa_true "just_the_errwords is empty" [expr {$just_the_errwords eq ""}] ##### # # Plain text with spelling mistakes # ##### set command $base_command lappend command -text "I obviosly can't spel very well ..." set errwords {obviosly spel} aa_log "--- Incorrect text --- $command" eval $command aa_true "True statement: Text contains misspelled words" [expr {$error_num > 0}] aa_log "Number of misspelled words found in text: $error_num" aa_false "False statement: Text contains no misspelled word(s)" [expr {$error_num == 0}] aa_log "Returned string: $formtext_to_display" aa_true "The returned string contains a hidden var named 'var_to_spellcheck.merge_text'" \ [regexp "var_to_spellcheck.merge_text" $formtext_to_display] aa_true "The returned string contains $error_num hidden var(s) named 'var_to_spellcheck.error_N', where N is a number between 0 and [expr {$error_num - 1}]." \ [regexp "var_to_spellcheck.error_\[0-9\]*" $formtext_to_display] aa_equals "The number of misspelled words matches the number of error placeholders in the merge_text" [regexp -all "var_to_spellcheck.error_\[0-9\]*" $formtext_to_display] [regexp -all "\#\[0-9\]*\#" $formtext_to_display] aa_true "just_the_errwords contains the errwords we expected: '[join $errwords ", "]'" [util_sets_equal_p $just_the_errwords $errwords] ##### # # HTML without spelling mistakes # ##### set command $base_command lappend command -text "This sentence does not contain any misspelled words. What we have here is HTML." lappend command -html aa_log "--- Correctly spelled HTML fragment --- $command" eval $command aa_true "True statement: HTML fragment contains no misspelled words" [expr {$error_num == 0}] aa_log "Number of miss-spelled words found in HTML fragment: $error_num" aa_false "False statement: HTML fragment contains misspelled word(s)" [expr {$error_num > 0}] aa_equals "Number of misspelled words found in HTML fragment" $error_num 0 aa_log "Returned string: $formtext_to_display" aa_true "The returned string contains a hidden var named 'var_to_spellcheck.merge_text'" \ [regexp "var_to_spellcheck.merge_text" $formtext_to_display] aa_true "The returned string contains no hidden var(s) named 'var_to_spellcheck.error_N', where N is the error number." \ ![regexp "var_to_spellcheck.error_\[0-9\]*" $formtext_to_display] aa_true "just_the_errwords is empty" [expr {$just_the_errwords eq ""}] ##### # # HTML with spelling mistakes # ##### set command $base_command lappend command -text "This sentence does contain mispelled worrds. What we have here is HTML." lappend command -html set errwords {mispelled worrds} aa_log "--- Incorrectly spelled HTML fragment --- $command" eval $command aa_true "True statement: HTML fragment contains misspelled words" [expr {$error_num > 0}] aa_log "Number of miss-spelled words found in HTML fragment: $error_num" aa_false "False statement: HTML fragment contains no misspelled word(s)" [expr {$error_num == 0}] aa_log "Returned string: $formtext_to_display" aa_true "The returned string contains a hidden var named 'var_to_spellcheck.merge_text'" \ [regexp "var_to_spellcheck.merge_text" $formtext_to_display] aa_true "The returned string contains hidden var(s) named 'var_to_spellcheck.error_N', where N is the error number." \ [regexp "var_to_spellcheck.error_\[0-9\]*" $formtext_to_display] aa_true "just_the_errwords contains the errwords we expected: '[join $errwords ", "]'" [util_sets_equal_p $just_the_errwords $errwords] } aa_register_case -cats { api } spellcheck__spellcheck_properties { Test the proc that knows if spell-checking is activated, if it should be performed, and which value the pull-down menu should default to. } { array set element { id test_element widget text mode edit } set command {template::util::spellcheck::spellcheck_properties -element_ref element} # text aa_log "--- Spell-checking enabled on widget \"$element(widget)\"? --- $command" array set spellcheck [eval $command] aa_false "Spell-checking disabled" $spellcheck(render_p) if { $spellcheck(render_p) } { aa_log "$spellcheck(selected_option) is the default" } # textarea set element(widget) textarea aa_log "--- Spell-checking enabled on widget \"$element(widget)\"? --- $command" array set spellcheck [eval $command] aa_true "Spell-checking enabled" $spellcheck(render_p) if { $spellcheck(render_p) } { aa_log "$spellcheck(selected_option) is the default" } # richtext set element(widget) richtext aa_log "--- Spell-checking enabled on widget \"$element(widget)\"? --- $command" array set spellcheck [eval $command] aa_true "Spell-checking enabled" $spellcheck(render_p) if { $spellcheck(render_p) } { aa_log "$spellcheck(selected_option) is the default" } } openacs-5.7.0/packages/acs-templating/tcl/test/multirow-procs.tcl0000644000175000017500000000045010021414653024727 0ustar frankiefrankiead_library { procs for testing the multiple and group tags } # til: removed the following test case because the bug won't fix 'by # design', so there seems to be no point in leaving the test case # here. Use CVS to restore it. #aa_register_case -cats { api } -bugs { 428 } group_tag openacs-5.7.0/packages/acs-templating/tcl/test/date-procs.tcl0000644000175000017500000000145110440426474023775 0ustar frankiefrankie# ad_library { Test date procs @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-10-13 @arch-tag: b5d458b6-bd22-4b87-8c4e-6a8c23fcca9e @cvs-id $Id: date-procs.tcl,v 1.2 2006/06/04 00:45:48 donb Exp $ } aa_register_case sql_date { test sql date transform } { aa_run_with_teardown \ -test_code { set date [template::util::date::now] set sql_date [template::util::date::get_property sql_date $date] if {[string equal [db_type] "oracle"] && [string match "8.*" [db_version]]} { aa_true "to_date for Oracle 8i" [string match "to_date*"] } else { aa_true "to_timestamp for Oracle 9i and PostgreSQL" [string match "to_timestamp*" $sql_date] } } }openacs-5.7.0/packages/acs-templating/tcl/test/parse-test-procs.tcl0000644000175000017500000001225110442136510025136 0ustar frankiefrankie# ad_library { Tests for adp parsing @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2005-01-01 @arch-tag: bc76f9ce-ed1c-49dd-a3be-617d5a78c838 @cvs-id $Id: parse-test-procs.tcl,v 1.6 2006/06/09 00:14:00 victorg Exp $ } aa_register_case template_variable { test adp variable parsing procedures } { aa_run_with_teardown \ -test_code { set code "=@test_array.test_key@" aa_true "Regular array var name detected" [regexp [template::adp_array_variable_regexp] $code discard pre arr var] aa_true "Preceding char is '${pre}'" [string equal "=" $pre] aa_true "Array name is '${arr}'" \ [string equal "test_array" $arr] aa_true "Variable name is '${var}'" \ [string equal "test_key" $var] set code "=@formerror.test_array.test_key@" aa_true "Formerror regular array var name detected" [regexp [template::adp_array_variable_regexp] $code discard pre arr var] aa_true "Preceding char is '${pre}'" [string equal "=" $pre] aa_true "Array name is '${arr}'" \ [string equal "formerror" $arr] aa_true "Variable name is '${var}'" \ [string equal "test_array.test_key" $var] set code "=@test_array.test_key;noquote@" aa_true "Noquote array var name detected" [regexp [template::adp_array_variable_regexp_noquote] $code discard pre arr var] aa_true "Preceding char is '${pre}'" [string equal "=" $pre] aa_true "Array name is '${arr}'" \ [string equal "test_array" $arr] aa_true "Variable name is '${var}'" \ [string equal "test_key" $var] set code "=@formerror.test_array.test_key;noquote@" aa_true "Noquote formerror array var name detected" [regexp [template::adp_array_variable_regexp_noquote] $code discard pre arr var] aa_true "Preceding char is '${pre}'" [string equal "=" $pre] aa_true "Array name is '${arr}'" \ [string equal "formerror" $arr] aa_true "Variable name is '${var}'" \ [string equal "test_array.test_key" $var] } } aa_register_case -cats {api smoke} tcl_to_sql_list { Tests the tcl_to_sql_list proc. @author Torben Brosten } { aa_equals "parses list of 0 items" [template::util::tcl_to_sql_list [list]] "" aa_equals "parses list of 2 or more" [template::util::tcl_to_sql_list [list isn't hess' 'bit 'trippy']] "'isn''t', 'hess''', '''bit', '''trippy'''" } aa_register_case -cats {api smoke} expand_percentage_signs { Test expand percentage signs to make sure it substitures correctly @author Dave Bauer @creation-date 2005-11-20 } { set orig_message "Test message %one%" set one "\[__does_not_exist__\]" set message $orig_message aa_false "Expanded square bracket text" [catch {set expanded_message [template::expand_percentage_signs $message]} errmsg] aa_log $errmsg aa_equals "square brackets safe" $expanded_message "Test message \[__does_not_exist__\]" set one "\$__does_not_exist" aa_false "Expanded dollar test" [catch {set expanded_message [template::expand_percentage_signs $message]} errmsg] aa_log $errmsg aa_equals "dollar sign safe" $expanded_message "Test message \$__does_not_exist" set one "\$two(\$three(\[__does_not_exist\]))" aa_false "Square bracket in array key test" [catch {set expanded_message [template::expand_percentage_signs $message]} errmsg] aa_log $errmsg aa_equals "square brackets in array key safe" $expanded_message "Test message \$two(\$three(\[__does_not_exist\]))" } aa_register_case -cats {api smoke} tcl_to_sql_list { Tests the tcl_to_sql_list proc. @author Torben Brosten } { aa_equals "parses list of 0 items" [template::util::tcl_to_sql_list [list]] "" aa_equals "parses list of 2 or more" [template::util::tcl_to_sql_list [list isn't hess' 'bit 'trippy']] "'isn''t', 'hess''', '''bit', '''trippy'''" } aa_register_case -cats {api smoke} expand_percentage_signs { Test expand percentage signs to make sure it substitures correctly @author Dave Bauer @creation-date 2005-11-20 } { set orig_message "Test message %one%" set one "\[__does_not_exist__\]" set message $orig_message aa_false "Expanded square bracket text" [catch {set expanded_message [template::expand_percentage_signs $message]} errmsg] aa_log $errmsg aa_equals "square brackets safe" $expanded_message "Test message \[__does_not_exist__\]" set one "\$__does_not_exist" aa_false "Expanded dollar test" [catch {set expanded_message [template::expand_percentage_signs $message]} errmsg] aa_log $errmsg aa_equals "dollar sign safe" $expanded_message "Test message \$__does_not_exist" set one "\$two(\$three(\[__does_not_exist\]))" aa_false "Square bracket in array key test" [catch {set expanded_message [template::expand_percentage_signs $message]} errmsg] aa_log $errmsg aa_equals "square brackets in array key safe" $expanded_message "Test message \$two(\$three(\[__does_not_exist\]))" } openacs-5.7.0/packages/acs-templating/tcl/test/multirow-test.adp0000644000175000017500000000030407766162055024562 0ustar frankiefrankie

    f1: @test.f1@

    f2: @test.f2@

    f3: @test.f3@
    openacs-5.7.0/packages/acs-templating/tcl/test/multirow-test.tcl0000644000175000017500000000116307766162055024604 0ustar frankiefrankie# used in multirow-procs.tcl template::multirow create test f1 f2 f3 template::multirow append test I 1 a template::multirow append test I 1 b template::multirow append test I 1 c if { $second_level_stays_p } { # the mode that fails - change in level f1 and f3 multirow append test I 2 a multirow append test I 1 a } else { # a mode that works, for testing the test case template::multirow append test I 3 a template::multirow append test I 2 b } template::multirow append test II 1 a template::multirow append test II 1 b template::multirow append test II 2 a template::multirow append test II 2 b openacs-5.7.0/packages/acs-templating/tcl/tag-procs.tcl0000644000175000017500000001271310551254404022652 0ustar frankiefrankie# Auxiliary Procs for Tag Handlers for the ArsDigita Templating System # Copyright (C) 1999-2000 ArsDigita Corporation # Authors: Karl Goldstein (karlg@arsdigita.com) # Stanislav Freidin (sfreidin@arsdigita.com) # Christian Brechbuehler (chrisitan@arsdigita.com) # $Id: tag-procs.tcl,v 1.15 2007/01/10 21:22:12 gustafn Exp $ # This is free software distributed under the terms of the GNU Public # License. Full text of the license is available from the GNU Project: # http://www.fsf.org/copyleft/gpl.html ad_proc -private template_tag_if_condition { chunk params condition_type } { set condition "$condition_type \{" # parse simplified conditional expression set args [template_tag_if_concat_params $params] if [catch { while { 1 } { # process the conditional expression template_tag_if_interp_expr # Stop when we run out of args if { [llength $args] == 0 } { break } set conjunction [lindex $args 0] switch $conjunction { and { append condition " && " } or { append condition " || " } default { error "Invalid conjunction $conjunction in $condition_type tag" } } set args [lrange $args 1 end] } } errorMsg] { set condition "$condition_type \{ 1 " set chunk $errorMsg } append condition "\} \{" switch $condition_type { if {template::adp_append_code $condition} elseif {template::adp_append_code $condition -nobreak} } # Done evaluating condition; evaluate body template::adp_compile_chunk $chunk # Add closing code template::adp_append_code "\}" } ad_proc -public template_tag_if_concat_params { params } { append all the tags together and then eval as a list to restore quotes } { set size [ns_set size $params] for { set i 0 } { $i < $size } { incr i } { set key [ns_set key $params $i] set value [ns_set value $params $i] if {$key eq $value} { lappend tokens $key } else { lappend tokens "$key=$value" } } # LARS: The 'eval' statement here breaks if any key or value above contains a semicolon, # since this causes eval to treat whatever comes after the semicolon as a new command. # I'm not sure why we need to eval here at all, there ought to be another solution, # but it's not clear what the intention of below statement is. set tokens [eval [concat list [join $tokens " "]]] return $tokens } ad_proc -public template_tag_if_interp_expr {} { Interpret an expression as part of the simplified IF syntax } { upvar args args condition condition # append condition "\[expr " set op [lindex $args 1] if { $op eq "not" } { append condition "! (" set close_paren ")" set op [lindex $args 2] set i 3 } else { set close_paren "" set i 2 } set arg1 "\"[lindex $args 0]\"" # build the conditional expression switch $op { gt { append condition "$arg1 > \"[lindex $args $i]\"" set next [expr {$i + 1}] } ge { append condition "$arg1 >= \"[lindex $args $i]\"" set next [expr {$i + 1}] } lt { append condition "$arg1 < \"[lindex $args $i]\"" set next [expr {$i + 1}] } le { append condition "$arg1 <= \"[lindex $args $i]\"" set next [expr {$i + 1}] } eq { append condition "\[string equal $arg1 \"[lindex $args $i]\"\]" set next [expr {$i + 1}] } ne { append condition "! \[string equal $arg1 \"[lindex $args $i]\"\]" set next [expr {$i + 1}] } in { set expr "^([join [lrange $args $i end] "|"])\$" append condition "\[regexp \"$expr\" $arg1\] " set next [llength $args] } between { set expr1 "$arg1 >= \"[lindex $args $i]\"" set expr2 "$arg1 <= \"[lindex $args [expr {$i + 1}]]\"" append condition "($expr1 && $expr2)" set next [expr {$i + 2}] } nil { if { [string first @ $arg1] == -1 } { # We're assuming this is a static string, not a variable append condition "\[empty_string_p $arg1\]" } else { # substitute array variables if {! ( [regsub {^"@([a-zA-Z0-9_]+)\.([a-zA-Z0-9_.]+)@"$} $arg1 {\1(\2)} arg1] || [regsub {^"@([a-zA-Z0-9_:]+)@"$} $arg1 {\1} arg1] ) } { error "IF tag nil test uses string not variable for $arg1" } append condition "\[template::util::is_nil $arg1\]" } set next $i } defined { # substitute variable references if { ! ( [regsub {^"@([a-zA-Z0-9_]+)\.([a-zA-Z0-9_.]+)@"$} $arg1 {\1(\2)} arg1] || [regsub {^"@([a-zA-Z0-9_:]+)@"$} $arg1 {\1} arg1] )} { error "IF tag defined test uses string not variable for $arg1" } append condition "\[info exists $arg1\]" set next $i } odd { append condition "\[expr {$arg1 % 2}\]" set next $i } even { append condition "! \[expr {$arg1 % 2}\]" set next $i } true { append condition "\[template::util::is_true $arg1\]" set next $i } false { append condition "!\[template::util::is_true $arg1\]" set next $i } default { # treat as a shortcut for append condition "\[template::util::is_true $arg1\]" set next [expr {$i - 1}] } } append condition $close_paren # append condition "]" set args [lrange $args $next end] } # Local Variables: # tcl-indent-level: 2 # End: openacs-5.7.0/packages/acs-templating/tcl/acs-templating-init.tcl0000644000175000017500000000567210171476760024643 0ustar frankiefrankie# Initialize namespaces, global macros and filters for ArsDigita Templating # System # Copyright (C) 1999-2000 ArsDigita Corporation # Author: Karl Goldstein (karlg@arsdigita.com) # $Id: acs-templating-init.tcl,v 1.4 2005/01/13 13:56:00 jeffd Exp $ # This is free software distributed under the terms of the GNU Public # License. Full text of the license is available from the GNU Project: # http://www.fsf.org/copyleft/gpl.html # Initialize namespaces used by template procs namespace eval template {} namespace eval template::form {} namespace eval template { namespace export query request form element # namespaces for cached datasource and template procedures namespace eval code { namespace eval tcl {} namespace eval adp {} } # namespaces for mtime checking procedures on datasource and # template files namespace eval mtimes { namespace eval tcl {} namespace eval adp {} } namespace eval query {} namespace eval util { namespace eval date {} namespace eval currency {} namespace eval file {} } namespace eval element { # default settings variable defaults set defaults [list widget text datatype integer values {} help_text {} before_html {} after_html {}] } namespace eval request {} namespace eval widget { namespace eval table {} } namespace eval form { # default settings variable defaults set defaults \ [list \ method post \ section {} \ mode edit \ edit_buttons [list [list [_ acs-kernel.common_OK] ok ]] \ display_buttons [list [list [_ acs-kernel.common_Edit] edit]] \ show_required_p t] } namespace eval wizard { # stack level at which wizard is created variable parse_level # An array of default buttons and their names variable default_button_labels array set default_button_labels \ [list back [_ acs-templating.Previous_with_arrow] \ repeat [_ acs-kernel.common_Repeat] \ next [_ acs-templating.Next_with_arrow] \ finish [_ acs-kernel.common_Finish]] } namespace eval paginator { # stack level at which paginator is created variable parse_level # Default values for paginator properties variable defaults set defaults [list pagesize 20 timeout 600 groupsize 10 page_offset 0] } namespace eval data { namespace eval validate {} namespace eval transform {} } # keep track of the stack frame in which a template is rendered at run-time variable parse_level # used for compiling Tcl code from ADP template variable parse_list # used to keep track of nested tags variable tag_stack # used to keep a list of filter procedures to execute variable filter_list set filter_list [list] # filters may set or modify the URL to replace ns_conn url variable url # specify what procs can be accessed directly namespace export form element request } openacs-5.7.0/packages/acs-templating/tcl/head-procs.tcl0000644000175000017500000005224711446726176023024 0ustar frankiefrankiead_library { The template::head::* api manipulates the head section of the document that will be returned to the users client. Packages should use this api to add package specific javascripts, CSS, link tags and meta tags to the HTML document. @author Lee Denison (lee@xarg.co.uk) @creation-date 2007-05-18 } namespace eval template {} namespace eval template::head {} ad_proc -private template::reset_request_vars {} { Resets all global datastructures used to manage the head section of the returned document. This should be called at the beginning of any request handled by the templating system. } { variable ::template::head::scripts array unset scripts array set scripts [list] variable ::template::head::links array unset links array set links [list] variable ::template::head::metas array unset metas array set metas [list] variable ::template::body_handlers array unset body_handlers array set body_handlers [list] variable ::template::body_scripts array unset body_scripts set body_scripts [list] variable ::template::headers set headers [list] variable ::template::footers set footers [list] } ad_proc -public template::head::add_script { {-type:required} {-defer:boolean} {-src ""} {-charset ""} {-script ""} {-order "0"} } { Add a script to the head section of the document to be returned to the users client. A script library in an external file may only be included once; subsequent calls to add_script will replace the existing entry. Anonymous script blocks will be added without checking for duplicates; the caller must ensure that anonymous script blocks are not inadvertantly added multiple times. You must supply either src or script. @param type the type attribute of the script tag, eg. 'text/javascript' @param defer whether execution of the script should be defered until after the page has been loaded @param src the src attribute of the script tag, ie. the source url of the script @param charset the charset attribute of the script tag, ie. the character set of the script if it differs from the main document @param script the inline script for the body of the script tag. This parameter will be ignored if a value has been supplied for src } { variable ::template::head::scripts if {$defer_p} { set defer defer } else { set defer "" } if {$src eq ""} { if {$script eq ""} { error "You must supply either -src or -script." } lappend scripts(anonymous) $type "" $charset $defer $script $order } else { set scripts($src) [list $type $src $charset $defer "" $order] } } ad_proc -public template::head::add_link { {-rel:required} {-href:required} {-type ""} {-media ""} {-title ""} {-lang ""} {-order "0"} } { Add a link tag to the head section of the document to be returned to the users client. A given target document may only be added once for a specified relation; subsequent calls to add_link will replace the existing entry. @param rel the rel attribute of the link tag defining the relationship of the linked document to the current one, eg. 'stylesheet' @param href the href attribute of the link tag, eg. the target document of the link @param type the type attribute of the link tag, eg. 'text/css' @param media the media attribute of the link tag describing which display media this link is relevant to. This may be a comma separated list of values, eg. 'screen,print,braille' @param title the title attribute of the link tag describing the target of this link @param lang the lang attribute of the link tag specifying the language of its attributes if they differ from the document language } { variable ::template::head::links set links($rel,$href) [list $rel $href $type $media $title $lang $order] } ad_proc -public template::head::add_meta { {-http_equiv ""} {-name ""} {-scheme ""} {-content ""} {-lang ""} } { Add a meta tag to the head section of the document to be returned to the users client. A meta tag with a given name or http-equiv may only be added once; subsequent calls to add_meta will replace the existing entry. You must supply either name or http_equiv. @param http_equiv the http-equiv attribute of the meta tag, ie. the HTTP header which this metadata is equivalent to eg. 'content-type' @param name the name attribute of the meta tag, ie. the metadata identifier @param scheme the scheme attribute of the meta tag defining which metadata scheme should be used to interpret the metadata, eg. 'DC' for Dublin Core (http://dublincore.org/) @param content the content attribute of the meta tag, ie the metadata value @param lang the lang attribute of the meta tag specifying the language of its attributes if they differ from the document language } { variable ::template::head::metas if {$http_equiv eq "" && $name eq ""} { error "You must supply either -http_equiv or -name." } set metas($http_equiv,$name) [list \ $http_equiv \ $name \ $scheme \ $content \ $lang \ ] } ad_proc -public template::head::add_style { {-style:required} {-title ""} {-lang ""} {-media ""} {-type "text/css"} } { Add an embedded css style declaration @author Dave Bauer (dave@thedesignexperience.org) @creation-date 2007-11-30 @param style CSS content to be included in the style tag @param type the type attribute of the link tag, eg. 'text/css' @param media the media attribute of the link tag describing which display media this link is relevant to. This may be a comma separated list of values, eg. 'screen,print,braille' @param title the title attribute of the link tag describing the target of this link @param lang the lang attribute of the link tag specifying the language of its attributes if they differ from the document language } { variable ::template::head::styles lappend styles(anonymous) $type $media $title $lang $style } ad_proc -public template::head::add_javascript { {-defer:boolean} {-src ""} {-charset ""} {-script ""} {-order "0"} } { Add a script of type 'text/javascript' to the head section of the document to be returned to the users client. This function is a wrapper around template::head::add_script. You must supply either src or script. @param defer whether execution of the script should be defered until after the page has been loaded @param src the src attribute of the script tag, ie. the source url of the script @param charset the charset attribute of the script tag, ie. the character set of the script if it differs from the main document @param script the inline script for the body of the script tag. This parameter will be ignored if a value has been supplied for src @see template::head::add_script } { template::head::add_script -defer=$defer_p \ -type text/javascript \ -src $src \ -charset $charset \ -script $script \ -order $order } ad_proc -public template::head::add_css { {-alternate:boolean} {-href:required} {-media "all"} {-title ""} {-lang ""} {-order "0"} } { Add a link tag with relation type 'stylesheet' or 'alternate stylesheet', and type 'text/css' to the head section of the document to be returned to the users client. A given target stylesheet may only be added once; subsequent calls to add_css will replace the existing entry. This function is a wrapper around template::head::add_link. @param href the href attribute of the link tag, eg. the target stylesheet @param alternate sets the rel attribute of the link tag defining to 'alternate stylesheet' if set, sets it to 'stylesheet' otherwise @param media the media attribute of the link tag describing which display media this link is relevant to. This may be a comma separated list of values, eg. 'screen,print,braille' @param title the title attribute of the link tag describing the target of this link @param lang the lang attribute of the link tag specifying the language of its attributes if they differ from the document language @see template::head::add_link } { if {$alternate_p} { set rel "alternate stylesheet" } else { set rel "stylesheet" } template::head::add_link -rel $rel \ -type text/css \ -href $href \ -media $media \ -title $title \ -lang $lang \ -order $order } ad_proc -public template::add_body_handler { {-event:required} {-script:required} {-identifier anonymous} } { Adds javascript code to an event handler in the body tag. Several javascript code blocks may be assigned to each handler by subsequent calls to template::add_body_handler.

    If your script may only be added once you may supply an identifier. Subsequent calls to template::add_body_handler with the same identifier will replace your script rather than appending to it.

    event may be one of:

    • onload
    • onunload
    • onclick
    • ondblclick
    • onmousedown
    • onmouseup
    • onmouseover
    • onmousemove
    • onmouseout
    • onkeypress
    • onkeydown
    • onkeyup
    @param event the event during which the supplied script should be executed @param script the javascript code to execute @param identifier a name, if supplied, used to ensure this javascript code is only added to the handler once } { variable ::template::body_handlers if {$identifier eq "anonymous"} { lappend body_handlers($event,anonymous) $script } else { # Even a one event handler needs to be added in a list # since all handlers, anonymous and specific are treated as a # list in blank-master.tcl set body_handlers($event,$identifier) [list $script] } } ad_proc -public template::add_body_script { {-type:required} {-defer:boolean} {-src ""} {-charset ""} {-script ""} } { Add a script to the start of the body section of the document to be returned to the users client. You must supply either src or script. @param type the type attribute of the script tag, eg. 'text/javascript' @param defer whether execution of the script should be defered until after the page has been loaded @param src the src attribute of the script tag, ie. the source url of the script @param charset the charset attribute of the script tag, ie. the character set of the script if it differs from the main document @param script the inline script for the body of the script tag. This parameter will be ignored if a value has been supplied for src } { variable ::template::body_scripts if {$defer_p} { set defer defer } else { set defer "" } if {$src eq "" && $script eq ""} { error "You must supply either -src or -script." } lappend body_scripts $type $src $charset $defer $script } ad_proc -public template::add_header { {-direction "outer"} {-src ""} {-params ""} {-html ""} } { Add a header include to the beginning of the document body. This function is used by site wide services to add functionality to the beginning of a page. Examples include the developer support toolbar, acs-lang translation interface and the acs-templating WYSIWYG editor textarea place holder. If you are not implementing a site wide service, you should not be using this function to add content to your page. You must supply either src or html. @param direction whether the header should be added as the outer most page content or the inner most @param src the path to the include @param params a list of name, value pairs to pass as parameter to the include @param html literal html to include in the page. This parameter will be ignored if a values has been supplied for src. @see template::add_footer } { variable ::template::headers if {$src eq ""} { if {$html eq ""} { error "You must supply either -src or -html." } set values [list literal $html ""] } else { set values [list include $src $params] } if {[info exists headers]} { switch $direction { outer {set headers [concat [list $values] $headers]} inner {lappend headers $values} default {error "unknown direction $direction"} } } else { set headers [list $values] } } ad_proc -public template::add_footer { {-direction "outer"} {-src ""} {-params ""} {-html ""} } { Add a footer include to the end of the document body. This function is used by site wide services to add functionality to the end of a page. Examples include the developer support toolbar, acs-lang translation interface and the acs-templating WYSIWYG editor textarea place holder. If you are not implementing a site wide service, you should not be using this function to add content to your page. You must supply either src or html. @param direction whether the footer should be added as the outer most page content or the inner most @param src the path to the include @param params a list of name, value pairs to pass as parameter to the include @param html literal html to include in the page. This parameter will be ignored if a values has been supplied for src. @see template::add_footer } { variable ::template::footers if {$src eq ""} { if {$html eq ""} { error "You must supply either -src or -html." } set values [list literal $html ""] } else { set values [list include $src $params] } if {[info exists footers]} { switch $direction { outer {lappend footers $values} inner {set footers [concat [list $values] $footers]} default {error "unknown direction $direction"} } } else { set footers [list $values] } } ad_proc template::head::prepare_multirows {} { Generate multirows for meta, css, scripts Called only from blank-master.tcl } { # Generate the tag multirow variable ::template::head::metas template::multirow create meta name content http_equiv scheme lang if {[array exists metas]} { foreach name [array names metas] { foreach {http_equiv name scheme content lang} $metas($name) { template::multirow append meta \ $name \ $content \ $http_equiv \ $scheme \ $lang } } unset metas } # Generate the tag multirow variable ::template::head::links template::multirow create link rel type href title lang media order if {[array exists links]} { # first non alternate stylesheet foreach name [array names links] { foreach {rel href type media title lang order} $links($name) { if {$rel ne "alternate stylesheet"} { template::multirow append link \ $rel \ $type \ $href \ $title \ $lang \ $media \ $order set links($name) "" } } } # order the stylesheets before adding alternate ones template::multirow sort link order # now alternate stylesheet foreach name [array names links] { foreach {rel href type media title lang order} $links($name) { if {$links($name) ne ""} { template::multirow append link \ $rel \ $type \ $href \ $title \ $lang \ $media \ $order set links($name) "" } } } unset links } # Generate the

    Make a Payment


    Are you sure you want to proceed?

    @confirm_data@

    openacs-5.7.0/packages/acs-templating/www/doc/demo/display-edit.adp0000644000175000017500000000050307605071304025054 0ustar frankiefrankie

    Customize a Sandwich



    openacs-5.7.0/packages/acs-templating/www/doc/demo/display-edit.tcl0000644000175000017500000000262710551254405025102 0ustar frankiefrankiead_page_contract { @cvs-id $Id$ } { {grid ""} } -properties {} if { [info exists cancel] } { ad_returnredirect [ad_conn url] ad_script_abort } form create sandwich -mode display -cancel_url [ad_conn url] element create sandwich grid \ -label "grid" -optional \ -datatype text -widget hidden element create sandwich nickname -html { size 30 } \ -label "Sandwich Name" -datatype text -section "Name" element create sandwich protein \ -label "Protein" -datatype text -widget radio \ -options { {Bacon bacon} {Chicken chicken} {Beef beef} } -section "Contents" element create sandwich vitamins \ -label "Vitamins" -datatype text -widget checkbox -optional \ -options { {Lettuce lettuce} {Tomato tomato} \ {Pickle pickle} {Sprouts sprouts} } -section "Contents" element create sandwich comments \ -label "Comments" -datatype text -widget textarea -optional -section "Details" -help_text "For your own sake." element create sandwich creation_date \ -label "Created date" -datatype date -widget date -optional -format {Month DD, YYYY} -section "Details" # Set defaults if { [form is_request sandwich] } { element set_properties sandwich vitamins -value {tomato} # or: element set_value sandwich vitamins tomato element set_properties sandwich grid -value $grid } # Choose standard or gridded output if {[element get_value sandwich grid] eq "t"} { ad_return_template sandwich-grid } openacs-5.7.0/packages/acs-templating/www/doc/demo/explicit_escape.adp0000644000175000017500000000030507253523117025630 0ustar frankiefrankie

    Hello

    <% foreach name [list Fred Ginger Mary Sarah Elmo] { template::adp_puts "

    Welcome to this page $name!

    " } %> openacs-5.7.0/packages/acs-templating/www/doc/demo/show.tcl0000644000175000017500000000070707253523117023473 0ustar frankiefrankieset file [ns_queryget file] if { [regexp {\.\.|^/} $file] } { set output "Only files within this directory may be shown." } else { # [ns_url2file [ns_conn url]] fails under request processor ! # the file for URL pkg/page may be in packages/pkg/www/page, not www/pkg/page set dir [file dirname [ad_conn file]] set text [ns_quotehtml [template::util::read_file $dir/$file]] set output "
    $text
    " } ns_return 200 text/html $output openacs-5.7.0/packages/acs-templating/www/doc/demo/list2/0000755000175000017500000000000011724401447023037 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list2/index-postgresql.xql0000644000175000017500000000145410371644725027106 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'HH12:MI Month DD, YYYY') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') openacs-5.7.0/packages/acs-templating/www/doc/demo/list2/index.adp0000644000175000017500000000006510371231647024635 0ustar frankiefrankie openacs-5.7.0/packages/acs-templating/www/doc/demo/list2/index.tcl0000644000175000017500000000161310371644725024660 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.2 2006/02/06 13:06:29 jiml Exp $ } -properties { notes:multirow } set package_id [ad_conn package_id] set user_id [ad_conn user_id] db_multirow template_demo_notes template_demo_notes {} # don't worry too much if you don't understand the query's details; # the point here is several columns can be displayed. # # Look at the query; notice how you can have a complex expression # come in as any name (like for creation_user_name and creation_date) # using " as " template::list::create -name notes \ -multirow template_demo_notes \ -elements { title { label "Title of Note" } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list2/index-oracle.xql0000644000175000017500000000303410372766645026153 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'HH12:MI Month DD, YYYY') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name, decode(acs_permission.permission_p(template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') order by creation_date openacs-5.7.0/packages/acs-templating/www/doc/demo/list3/0000755000175000017500000000000011724401447023040 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list3/index-postgresql.xql0000644000175000017500000000152310371645116027077 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list3/index.adp0000644000175000017500000000022410371645116024633 0ustar frankiefrankie Notes @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list3/index.tcl0000644000175000017500000000207610371645116024660 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/06 13:08:30 jiml Exp $ } -query { orderby:optional } -properties { notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] template::list::create -name notes \ -multirow template_demo_notes \ -elements { title { label "Title of Note" } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "Owner of Note" orderby creation_user_name } creation_date { label "When Note Created" orderby o.creation_date } color { label "Color" orderby n.color } } db_multirow template_demo_notes template_demo_notes {} ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list3/index-oracle.xql0000644000175000017500000000325110372765251026145 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list4/0000755000175000017500000000000011724401447023041 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list4/index-postgresql.xql0000644000175000017500000000152310372525612027077 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list4/index.adp0000644000175000017500000000022410372525612024633 0ustar frankiefrankie Notes @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list4/index.tcl0000644000175000017500000000377310372525612024665 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/09 02:40:10 jiml Exp $ } -query { orderby:optional } -properties { notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] # Here, we are adding a link for every row. The title of the note # will become a link to a page that will view the note in its entirety. # # Notice in the title element of this, where we add "link_url_col view_url" template::list::create -name notes \ -multirow template_demo_notes \ -elements { title { label "Title of Note" link_url_col view_url } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "User" orderby creation_user_name } creation_date { label "Date" orderby o.creation_date } color { label "Color" orderby n.color } } # how to get the variable per row, which will be the link target? # # first, we extend the multirow so that it contains an additional # column (other than the columns in the select list from the query). # # The name of that column is view_url, and we're using export_vars # to actually form the value. This invocation of db_multirow has an # extra parameter at the end, which is a block of code to execute. # In this block, we set the extra column variable we told it about # with the -extend {} parameter. # # This variable will then be available to anything that reads the # multirow, which for this case is the template::list::create call # above. db_multirow -extend { view_url } template_demo_notes template_demo_notes {} { set view_url [export_vars -base view-one { template_demo_note_id }] } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list4/index-oracle.xql0000644000175000017500000000325110372765251026146 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list4/view-one.adp0000644000175000017500000000021410372525612025254 0ustar frankiefrankie @title;noquote@ @context;noquote@ @body;noquote@
    @color@openacs-5.7.0/packages/acs-templating/www/doc/demo/list4/view-one.tcl0000644000175000017500000000070210372525612025274 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date 2001-09-02 } { template_demo_note_id:integer,notnull } -properties { context:onevalue title:onevalue body:onevalue } set context [list "One note"] db_1row note_select { select title, body, color from template_demo_notes where template_demo_note_id = :template_demo_note_id } set body [ad_text_to_html -- $body] ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/0000755000175000017500000000000011724401447023042 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list5/blank.gif0000644000175000017500000000011710372561673024625 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP!ù,„©Ëí£œ´Ú‹³®;openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/index-postgresql.xql0000644000175000017500000000152310372561673027107 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/index.adp0000644000175000017500000000022410372561673024643 0ustar frankiefrankie Notes @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/index.tcl0000644000175000017500000000270710372561673024671 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/09 06:39:55 jiml Exp $ } -query { orderby:optional } -properties { notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] # New here, is the use of -key to signify which column is the key field, # and the -bulk_actions to give us the ability to delete all the checked # notes at once. template::list::create -name notes \ -multirow template_demo_notes \ -key "template_demo_note_id" \ -bulk_actions { "Delete Checked Notes" "delete" "Delete Checked Notes" } \ -elements { title { label "Title of Note" link_url_col view_url } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "Owner of Note" orderby creation_user_name } creation_date { label "When Note Created" orderby o.creation_date } color { label "Color" orderby n.color } } db_multirow -extend { view_url } template_demo_notes template_demo_notes {} { set view_url [export_vars -base view-one { template_demo_note_id }] } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/add.gif0000644000175000017500000000016410372561673024270 0ustar frankiefrankieGIF89a‘ÿÿÿÝÝÝfff,@Mœ© kÞ4ÓœœººhaÝH–וêx¦ˆ|‡ÓÊÚ;oÜ õ= ‡Ä he»íŽ2޲ªÙpj•ÔU'Q&rÕˆÇä²Y<(;openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/add-disabled.gif0000644000175000017500000000016610372561673026037 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP,=œ© í# Ø‹³‚Êvd9X]ÈN•už—œ×¶ã¼¤±Ÿºår;'£ ‡¬Ýæ™Y1C½jµ;openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/add-edit.adp0000644000175000017500000000023410372561673025210 0ustar frankiefrankie @page_title@ @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/add-edit.tcl0000644000175000017500000000651110676223677025240 0ustar frankiefrankie# packages/notes/www/add-edit.tcl ad_page_contract { @author Don Baccus (dhogaza@pacifier.com) @creation-date 2000-10-23 @cvs-id $Id: add-edit.tcl,v 1.2 2007/09/25 15:22:39 donb Exp $ Example script that allows for the creation or editing of a simple note object type, using ad_form and package Tcl API tools. } -query { note_id:integer,notnull,optional } -properties { context:onevalue page_title:onevalue } # When using ad_form to generate or edit acs_objects, the object type's # key column must be specified in ad_page_contract as is done above, # and defined with the type "key" in ad_form. This enables the use of # the various request and submission code blocks. set package_id [ad_conn package_id] ad_form -form { # The "note" object type's key note_id:key # "title" is of type text and will use a "text" widget. {title:text \ {label Title} {html {size 20}} } # "body" is of type text and will use a "textarea" widget. {body:text(textarea) \ {label Body} {html {rows 10 cols 40}} } } -new_request { # By convention packages only allow a user to create new objects if the user has # the "create" privilege on the package instance itself. permission::require_permission -object_id $package_id -privilege create # Customize the page title to reflect the fact that this form is used to # create a new note. set page_title "New Note" } -edit_request { permission::require_permission -object_id $note_id -privilege write # Customize the page title to reflect the fact that this form is used to # edit an existing note. set page_title "Edit Note" # Fill the form with the values from the note we're editing. db_1row note_select {} } -on_validation_error { # There was an error in the form, let the page title reflect this. set page_title "Error in submission" } -new_data { # Create a new note. # Generate the new object automatically from the data set in the form. Standard # acs_object attributes like creation_user are set automatically. package_instantiate_object -var_list [list [list context_id $package_id]] \ -form_id add-edit \ note } -edit_data { # Currently we need to update our object manually ... set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml object_update {} db_dml note_update {} } } -after_submit { # We've successfully processed the submission, send the user back to the index page. ad_returnredirect "./" # ad_returnredirect returns after redirecting the user, so abort the script rather # than fall through to the display code. Failure to abort the script will burden # your server with needless template processing, though the user won't notice due to # having been redirected. ad_script_abort } # The following is only executed if we did not process a valid submission, in other # words on the initial "new" or "edit" form request or after a submission which # contained errors. Add the page title to the breadcrumb context bar. set context [list $page_title] # Display the form, blank if we're processing a "new" request, filled with data if we're # processing an "edit" request or a submitted form that contains errors. ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/add-edit.xql0000644000175000017500000000117610372561673025256 0ustar frankiefrankie select title, body from notes where note_id = :note_id update acs_objects set modifying_user = :modifying_user, modifying_ip = :modifying_ip where object_id = :note_id update notes set title = :title, body = :body where note_id = :note_id openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/index-oracle.xql0000644000175000017500000000325110372765251026147 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/delete.tcl0000644000175000017500000000203510372561673025016 0ustar frankiefrankie# packages/notes/www/delete.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: delete.tcl,v 1.1 2006/02/09 06:39:55 jiml Exp $ } { template_demo_note_id:integer,notnull,multiple } # Here, we delete all the notes being fed to us, which is all # the notes that were checked on the index page. This page doesn't # know/care about the fact they are the checked notes, all it knows # is there are a bunch of template_demo_note_id values coming in # through the url. So, this list is sorta becoming a form too :) # # so this loop runs thru all passed-in values of template_demo_note_id # and for each, deletes that note. foreach template_demo_note_id $template_demo_note_id { ad_require_permission $template_demo_note_id delete package_exec_plsql \ -var_list \ [list \ [list \ template_demo_note_id \ $template_demo_note_id \ ] \ ] \ template_demo_note \ del } ad_returnredirect "./" openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/view-one.adp0000644000175000017500000000021410372561673025264 0ustar frankiefrankie @title;noquote@ @context;noquote@ @body;noquote@
    @color@openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/view-one.tcl0000644000175000017500000000070210372561673025304 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date 2001-09-02 } { template_demo_note_id:integer,notnull } -properties { context:onevalue title:onevalue body:onevalue } set context [list "One note"] db_1row note_select { select title, body, color from template_demo_notes where template_demo_note_id = :template_demo_note_id } set body [ad_text_to_html -- $body] ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/delete-oracle.xql0000644000175000017500000000044010372561673026301 0ustar frankiefrankie oracle8.1.6 begin template_demo_note.del(:template_demo_note_id); end; openacs-5.7.0/packages/acs-templating/www/doc/demo/list5/delete-postgresql.xql0000644000175000017500000000044010372561673027237 0ustar frankiefrankie postgresql7.1 select template_demo_note__delete( :template_demo_note_id ); openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/0000755000175000017500000000000011724401447023043 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list6/blank.gif0000644000175000017500000000011710372761225024621 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP!ù,„©Ëí£œ´Ú‹³®;openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/x.gif0000644000175000017500000000014010372761225023775 0ustar frankiefrankieGIF89a‘ÿÿÿÝÝÝfff,@9œ‰Ýèš0ìhÜ5zM}b°uV•jÊ«òL×@8zêz,‰ÃôRA_ï·Ë¹‚¦ó ;openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/x-disabled.gif0000644000175000017500000000014710372761225025551 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP,.œyÀíß´Z+$ÜNVcTÆ•€inè§bZû¼"u³t7]þ8Û1ÄD;openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/index-postgresql.xql0000644000175000017500000000152310372761225027103 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/index.adp0000644000175000017500000000022410372761225024637 0ustar frankiefrankie Notes @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/index.tcl0000644000175000017500000000347510372761225024670 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/10 00:47:17 jiml Exp $ } -query { orderby:optional } -properties { template_demo_notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] set actions [list] if { $create_p } { lappend actions "Create Note" add-edit "Create Note" } # notice how -bulk_actions is different inside... # -bulk_actions { "text for button" "name of page" "tooltip text" } # weird, huh? # # anyway, here we are adding an action (not bulk, so doesn't respond # to the checkboxes) for adding a note. see the if test above? if # the user does not have permission to create, then the actions list # will be empty and the create-a-note button will not appear. template::list::create -name notes \ -multirow template_demo_notes \ -key "template_demo_note_id" \ -actions $actions \ -bulk_actions { "Delete Checked Notes" "delete" "Delete Checked Notes" } \ -elements { title { label "Title of Note" link_url_col view_url } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "Owner of Note" orderby creation_user_name } creation_date { label "When Note Created" orderby o.creation_date } color { label "Color" orderby n.color } } db_multirow -extend { view_url } template_demo_notes template_demo_notes {} { set view_url [export_vars -base view-one { template_demo_note_id }] } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/add.gif0000644000175000017500000000016410372761225024264 0ustar frankiefrankieGIF89a‘ÿÿÿÝÝÝfff,@Mœ© kÞ4ÓœœººhaÝH–וêx¦ˆ|‡ÓÊÚ;oÜ õ= ‡Ä he»íŽ2޲ªÙpj•ÔU'Q&rÕˆÇä²Y<(;openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/add-disabled.gif0000644000175000017500000000016610372761225026033 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP,=œ© í# Ø‹³‚Êvd9X]ÈN•už—œ×¶ã¼¤±Ÿºår;'£ ‡¬Ýæ™Y1C½jµ;openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/add-edit.adp0000644000175000017500000000023410372761225025204 0ustar frankiefrankie @page_title@ @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/add-edit.tcl0000644000175000017500000000705010676223677025240 0ustar frankiefrankie# packages/notes/www/add-edit.tcl ad_page_contract { @author Don Baccus (dhogaza@pacifier.com) @creation-date 2000-10-23 @cvs-id $Id: add-edit.tcl,v 1.3 2007/09/25 15:22:39 donb Exp $ Example script that allows for the creation or editing of a simple note object type, using ad_form and package Tcl API tools. } -query { template_demo_note_id:integer,notnull,optional } -properties { context:onevalue page_title:onevalue } # When using ad_form to generate or edit acs_objects, the object type's # key column must be specified in ad_page_contract as is done above, # and defined with the type "key" in ad_form. This enables the use of # the various request and submission code blocks. set package_id [ad_conn package_id] ad_form -form { # The "template_demo_note" object type's key template_demo_note_id:key # "title" is of type text and will use a "text" widget. {title:text \ {label Title} {html {size 20}} } # "body" is of type text and will use a "textarea" widget. {body:text(textarea) \ {label Body} {html {rows 10 cols 40}} } # "color" is of type text, using text widget {color:text \ {label Color} {html {size 20}} } } -new_request { # By convention packages only allow a user to create new objects if the user has # the "create" privilege on the package instance itself. permission::require_permission -object_id $package_id -privilege create # Customize the page title to reflect the fact that this form is used to # create a new note. set page_title "New Note" } -edit_request { permission::require_permission -object_id $template_demo_note_id -privilege write # Customize the page title to reflect the fact that this form is used to # edit an existing note. set page_title "Edit Note" # Fill the form with the values from the note we're editing. db_1row template_demo_note_select {} } -on_validation_error { # There was an error in the form, let the page title reflect this. set page_title "Error in submission" } -new_data { # Create a new note. # Generate the new object automatically from the data set in the form. Standard # acs_object attributes like creation_user are set automatically. package_instantiate_object \ -var_list [list [list context_id $package_id]] \ -form_id add-edit \ template_demo_note } -edit_data { # Currently we need to update our object manually ... set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml object_update {} db_dml template_demo_note_update {} } } -after_submit { # We've successfully processed the submission, send the user back to the index page. ad_returnredirect "./" # ad_returnredirect returns after redirecting the user, so abort the script rather # than fall through to the display code. Failure to abort the script will burden # your server with needless template processing, though the user won't notice due to # having been redirected. ad_script_abort } # The following is only executed if we did not process a valid submission, in other # words on the initial "new" or "edit" form request or after a submission which # contained errors. Add the page title to the breadcrumb context bar. set context [list $page_title] # Display the form, blank if we're processing a "new" request, filled with data if we're # processing an "edit" request or a submitted form that contains errors. ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/add-edit.xql0000644000175000017500000000143410373045462025246 0ustar frankiefrankie select title, body, color from template_demo_notes where template_demo_note_id = :template_demo_note_id update acs_objects set modifying_user = :modifying_user, modifying_ip = :modifying_ip where object_id = :template_demo_note_id update template_demo_notes set title = :title, body = :body color = :color where template_demo_note_id = :template_demo_note_id openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/index-oracle.xql0000644000175000017500000000325110372765252026151 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/delete.tcl0000644000175000017500000000073310373045773025021 0ustar frankiefrankie# packages/notes/www/delete.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: delete.tcl,v 1.2 2006/02/10 08:16:59 jiml Exp $ } { template_demo_note_id:integer,notnull,multiple } foreach template_demo_note_id $template_demo_note_id { ad_require_permission $template_demo_note_id delete package_exec_plsql -var_list [list [list template_demo_note_id $template_demo_note_id]] template_demo_note del } ad_returnredirect "./" openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/view-one.adp0000644000175000017500000000021410372761225025260 0ustar frankiefrankie @title;noquote@ @context;noquote@ @body;noquote@
    @color@openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/view-one.tcl0000644000175000017500000000070210372761225025300 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date 2001-09-02 } { template_demo_note_id:integer,notnull } -properties { context:onevalue title:onevalue body:onevalue } set context [list "One note"] db_1row note_select { select title, body, color from template_demo_notes where template_demo_note_id = :template_demo_note_id } set body [ad_text_to_html -- $body] ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/delete-oracle.xql0000644000175000017500000000044010372761225026275 0ustar frankiefrankie oracle8.1.6 begin template_demo_note.del(:template_demo_note_id); end; openacs-5.7.0/packages/acs-templating/www/doc/demo/list6/delete-postgresql.xql0000644000175000017500000000044010372761225027233 0ustar frankiefrankie postgresql7.1 select template_demo_note__delete( :template_demo_note_id ); openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/0000755000175000017500000000000011724401447023044 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list7/blank.gif0000644000175000017500000000011710373502202024607 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP!ù,„©Ëí£œ´Ú‹³®;openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/x.gif0000644000175000017500000000014010373502202023763 0ustar frankiefrankieGIF89a‘ÿÿÿÝÝÝfff,@9œ‰Ýèš0ìhÜ5zM}b°uV•jÊ«òL×@8zêz,‰ÃôRA_ï·Ë¹‚¦ó ;openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/x-disabled.gif0000644000175000017500000000014710373502202025537 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP,.œyÀíß´Z+$ÜNVcTÆ•€inè§bZû¼"u³t7]þ8Û1ÄD;openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/index-postgresql.xql0000644000175000017500000000161210373502202027070 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::filter_where_clauses -and -name notes] [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/index.adp0000644000175000017500000000060510373502202024630 0ustar frankiefrankie Notes @context;noquote@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/index.tcl0000644000175000017500000000705210374075646024673 0ustar frankiefrankie# main index page for notes. # Notice we have a new -query parameter, color_filter_value. If anything # wants to activate the filter (whose name is color_filter_value) defined # ahead in the template::list, then it can feed the page a parameter of # color_filter_value="something". When this happens, the filter will add # its where clause to template::list::filter_where_clause and therefore # to the query which has a call to that proc. In this case, the where claue # will be "n.color = 'something'". Look at the filter definition in the # list definition to see this. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.3 2006/02/13 12:29:26 jiml Exp $ } -query { orderby:optional color_filter_value:optional } -properties { notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] set actions [list] if { $create_p } { lappend actions "Create Note" add-edit "Create Note" } # the following structure is a "list of lists". Each list describes a # different choice value; the first item is the displayed name of the # choice and the second is the value passed back as the value of the # choice. # # Normally, you'd have a database query where the items in the select # list of the query will appear in each inner list in order; again, # the first would be a displayed name and the second would be the # value that the form would send back as the choice. Note that this # could be a primary key in a table, maybe an object ID. # # Since the colors column is a text column and not implemented as a # separate table with a numeric key column, the value will be the # name of the color. # # So, to activate the filter, say for Blue, this page is fed this: # color_filter_value="blue" # and notice, this is the lowercase version, the second item in each # inner list. The first item is displayed to the user for choosing # among possible filter values. set color_choices { {Blue blue} {Green green} {Purple purple} {Red red} {Orange orange} {Yellow yellow} } # Here's the list; notice the new -filters section. If the user chooses # to activate the filter (presumably by manipulating some user interface), # the filter will add its where clause to output of the call # template::list::filter_where_clause. Look at the query; you'll see the # call to filter_where_clause there near the bottom, in brackets. template::list::create -name notes \ -multirow template_demo_notes \ -key "template_demo_note_id" \ -actions $actions \ -bulk_actions { "Delete Checked Notes" "delete" "Delete Checked Notes" } \ -elements { title { label "Title of Note" link_url_col view_url } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -filters { color_filter_value { label "Color" where_clause { n.color = :color_filter_value } values $color_choices } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "Owner of Note" orderby creation_user_name } creation_date { label "When Note Created" orderby o.creation_date } color { label "Color" orderby n.color } } db_multirow -extend { view_url } template_demo_notes template_demo_notes {} { set view_url [export_vars -base view-one { template_demo_note_id }] } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/add.gif0000644000175000017500000000016410373502202024252 0ustar frankiefrankieGIF89a‘ÿÿÿÝÝÝfff,@Mœ© kÞ4ÓœœººhaÝH–וêx¦ˆ|‡ÓÊÚ;oÜ õ= ‡Ä he»íŽ2޲ªÙpj•ÔU'Q&rÕˆÇä²Y<(;openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/add-disabled.gif0000644000175000017500000000016610373502202026021 0ustar frankiefrankieGIF89a¡ÿÿÿÝÝÝfff!þMade with GIMP,=œ© í# Ø‹³‚Êvd9X]ÈN•už—œ×¶ã¼¤±Ÿºår;'£ ‡¬Ýæ™Y1C½jµ;openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/add-edit.adp0000644000175000017500000000023410373502202025172 0ustar frankiefrankie @page_title@ @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/add-edit.tcl0000644000175000017500000000651110676223700025225 0ustar frankiefrankie# packages/notes/www/add-edit.tcl ad_page_contract { @author Don Baccus (dhogaza@pacifier.com) @creation-date 2000-10-23 @cvs-id $Id: add-edit.tcl,v 1.2 2007/09/25 15:22:40 donb Exp $ Example script that allows for the creation or editing of a simple note object type, using ad_form and package Tcl API tools. } -query { note_id:integer,notnull,optional } -properties { context:onevalue page_title:onevalue } # When using ad_form to generate or edit acs_objects, the object type's # key column must be specified in ad_page_contract as is done above, # and defined with the type "key" in ad_form. This enables the use of # the various request and submission code blocks. set package_id [ad_conn package_id] ad_form -form { # The "note" object type's key note_id:key # "title" is of type text and will use a "text" widget. {title:text \ {label Title} {html {size 20}} } # "body" is of type text and will use a "textarea" widget. {body:text(textarea) \ {label Body} {html {rows 10 cols 40}} } } -new_request { # By convention packages only allow a user to create new objects if the user has # the "create" privilege on the package instance itself. permission::require_permission -object_id $package_id -privilege create # Customize the page title to reflect the fact that this form is used to # create a new note. set page_title "New Note" } -edit_request { permission::require_permission -object_id $note_id -privilege write # Customize the page title to reflect the fact that this form is used to # edit an existing note. set page_title "Edit Note" # Fill the form with the values from the note we're editing. db_1row note_select {} } -on_validation_error { # There was an error in the form, let the page title reflect this. set page_title "Error in submission" } -new_data { # Create a new note. # Generate the new object automatically from the data set in the form. Standard # acs_object attributes like creation_user are set automatically. package_instantiate_object -var_list [list [list context_id $package_id]] \ -form_id add-edit \ note } -edit_data { # Currently we need to update our object manually ... set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml object_update {} db_dml note_update {} } } -after_submit { # We've successfully processed the submission, send the user back to the index page. ad_returnredirect "./" # ad_returnredirect returns after redirecting the user, so abort the script rather # than fall through to the display code. Failure to abort the script will burden # your server with needless template processing, though the user won't notice due to # having been redirected. ad_script_abort } # The following is only executed if we did not process a valid submission, in other # words on the initial "new" or "edit" form request or after a submission which # contained errors. Add the page title to the breadcrumb context bar. set context [list $page_title] # Display the form, blank if we're processing a "new" request, filled with data if we're # processing an "edit" request or a submitted form that contains errors. ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/add-edit.xql0000644000175000017500000000117610373502202025240 0ustar frankiefrankie select title, body from notes where note_id = :note_id update acs_objects set modifying_user = :modifying_user, modifying_ip = :modifying_ip where object_id = :note_id update notes set title = :title, body = :body where note_id = :note_id openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/index-oracle.xql0000644000175000017500000000334210373502202026134 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and o.creation_user = p.person_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::filter_where_clauses -and -name notes] [template::list::orderby_clause -orderby -name notes] openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/delete.tcl0000644000175000017500000000074410374101420025003 0ustar frankiefrankie# packages/notes/www/delete.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: delete.tcl,v 1.3 2006/02/13 13:01:04 jiml Exp $ } { template_demo_note_id:integer,notnull,multiple } foreach template_demo_note_id $template_demo_note_id { ad_require_permission $template_demo_note_id delete package_exec_plsql \ -var_list [list [list template_demo_note_id $template_demo_note_id]] \ template_demo_note \ del } ad_returnredirect "./" openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/view-one.adp0000644000175000017500000000020010373502202025241 0ustar frankiefrankie @title;noquote@ @context;noquote@ @body;noquote@openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/view-one.tcl0000644000175000017500000000060310373502202025266 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date 2001-09-02 } { note_id:integer,notnull } -properties { context:onevalue title:onevalue body:onevalue } set context [list "One note"] db_1row note_select { select title, body from notes where note_id = :note_id } set body [ad_text_to_html -- $body] ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/delete-oracle.xql0000644000175000017500000000036610373502202026272 0ustar frankiefrankie oracle8.1.6 begin note.del(:note_id); end; openacs-5.7.0/packages/acs-templating/www/doc/demo/list7/delete-postgresql.xql0000644000175000017500000000036610373502202027230 0ustar frankiefrankie postgresql7.1 select note__delete( :note_id ); openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/0000755000175000017500000000000011724401447023045 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list8/index-postgresql.xql0000644000175000017500000000321110374076641027104 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and p.person_id = o.creation_user and exists (select 1 from acs_object_party_privilege_map where object_id = n.template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::filter_where_clauses -and -name notes] [template::list::orderby_clause -orderby -name notes] select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and p.person_id = o.creation_user and exists (select 1 from acs_object_party_privilege_map where object_id = n.template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::page_where_clause -and -name notes -key template_demo_note_id] openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/index.adp0000644000175000017500000000060510374076641024647 0ustar frankiefrankie Notes @context;noquote@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/index.tcl0000644000175000017500000000345710374102056024663 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.2 2006/02/13 13:05:50 jiml Exp $ } -query { orderby:optional color_filter_value:optional page:optional } -properties { notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] set actions [list] if { $create_p } { lappend actions "Create Note" add-edit "Create Note" } set color_choices { {Blue blue} {Green green} {Purple purple} {Red red} {Orange orange} {Yellow yellow} } template::list::create -name notes \ -multirow template_demo_notes \ -key "template_demo_note_id" \ -page_size 3 \ -page_query_name template_demo_notes_paginate \ -actions $actions \ -bulk_actions { "Delete Checked Notes" "delete" "Delete Checked Notes" } \ -elements { title { label "Title of Note" link_url_col view_url } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -filters { color_filter_value { label "Color" where_clause { n.color = :color_filter_value } values $color_choices } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "Owner of Note" orderby creation_user_name } creation_date { label "When Note Created" orderby o.creation_date } color { label "Color" orderby n.color } } db_multirow -extend { view_url } template_demo_notes template_demo_notes {} { set view_url [export_vars -base view-one { template_demo_note_id }] } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/add-edit.adp0000644000175000017500000000023410374076641025211 0ustar frankiefrankie @page_title@ @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/add-edit.tcl0000644000175000017500000000701410676223700025225 0ustar frankiefrankie# packages/acs-templating/www/doc/demo/list8/add-edit.tcl ad_page_contract { @author Don Baccus (dhogaza@pacifier.com) @creation-date 2000-10-23 @cvs-id $Id: add-edit.tcl,v 1.4 2007/09/25 15:22:40 donb Exp $ Example script that allows for the creation or editing of a simple note object type, using ad_form and package Tcl API tools. } -query { template_demo_note_id:integer,notnull,optional } -properties { context:onevalue page_title:onevalue } # When using ad_form to generate or edit acs_objects, the object type's # key column must be specified in ad_page_contract as is done above, # and defined with the type "key" in ad_form. This enables the use of # the various request and submission code blocks. set package_id [ad_conn package_id] ad_form -form { # The "note" object type's key template_demo_note_id:key # "title" is of type text and will use a "text" widget. {title:text \ {label Title} {html {size 20}} } # "body" is of type text and will use a "textarea" widget. {body:text(textarea) \ {label Body} {html {rows 10 cols 40}} } # 'color' is a text using a text widget {color:text \ {label "Color"} {htmo {size 20}} } } -new_request { # By convention packages only allow a user to create new objects if the user has # the "create" privilege on the package instance itself. permission::require_permission -object_id $package_id -privilege create # Customize the page title to reflect the fact that this form is used to # create a new note. set page_title "New Note" } -edit_request { permission::require_permission -object_id $note_id -privilege write # Customize the page title to reflect the fact that this form is used to # edit an existing note. set page_title "Edit Note" # Fill the form with the values from the note we're editing. db_1row note_select {} } -on_validation_error { # There was an error in the form, let the page title reflect this. set page_title "Error in submission" } -new_data { # Create a new note. # Generate the new object automatically from the data set in the form. Standard # acs_object attributes like creation_user are set automatically. package_instantiate_object \ -var_list [list [list context_id $package_id]] \ -form_id add-edit \ template_demo_note } -edit_data { # Currently we need to update our object manually ... set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml object_update {} db_dml template_demo_note_update {} } } -after_submit { # We've successfully processed the submission, send the user back to the index page. ad_returnredirect "./" # ad_returnredirect returns after redirecting the user, so abort the script rather # than fall through to the display code. Failure to abort the script will burden # your server with needless template processing, though the user won't notice due to # having been redirected. ad_script_abort } # The following is only executed if we did not process a valid submission, in other # words on the initial "new" or "edit" form request or after a submission which # contained errors. Add the page title to the breadcrumb context bar. set context [list $page_title] # Display the form, blank if we're processing a "new" request, filled with data if we're # processing an "edit" request or a submitted form that contains errors. ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/add-edit.xql0000644000175000017500000000117610374076641025257 0ustar frankiefrankie select title, body from notes where note_id = :note_id update acs_objects set modifying_user = :modifying_user, modifying_ip = :modifying_ip where object_id = :note_id update notes set title = :title, body = :body where note_id = :note_id openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/index-oracle.xql0000644000175000017500000000243610374076641026156 0ustar frankiefrankie oracle8.1.6 select note_id, title, body, decode(acs_permission.permission_p(note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from notes n, acs_objects o where n.note_id = o.object_id and o.context_id = :package_id and exists (select 1 from acs_object_party_privilege_map where object_id = note_id and party_id = :user_id and privilege = 'read') order by creation_date openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/delete.tcl0000644000175000017500000000074410374111464025015 0ustar frankiefrankie# packages/notes/www/delete.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: delete.tcl,v 1.5 2006/02/13 14:09:56 jiml Exp $ } { template_demo_note_id:integer,notnull,multiple } foreach template_demo_note_id $template_demo_note_id { ad_require_permission $template_demo_note_id delete package_exec_plsql \ -var_list [list [list template_demo_note_id $template_demo_note_id]] \ template_demo_note \ del } ad_returnredirect "./" openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/view-one.adp0000644000175000017500000000020010374076641025260 0ustar frankiefrankie @title;noquote@ @context;noquote@ @body;noquote@openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/view-one.tcl0000644000175000017500000000060310374076641025305 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date 2001-09-02 } { note_id:integer,notnull } -properties { context:onevalue title:onevalue body:onevalue } set context [list "One note"] db_1row note_select { select title, body from notes where note_id = :note_id } set body [ad_text_to_html -- $body] ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/delete-oracle.xql0000644000175000017500000000036610374076641026311 0ustar frankiefrankie oracle8.1.6 begin note.del(:note_id); end; openacs-5.7.0/packages/acs-templating/www/doc/demo/list8/delete-postgresql.xql0000644000175000017500000000036610374076641027247 0ustar frankiefrankie postgresql7.1 select note__delete( :note_id ); openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/0000755000175000017500000000000011724401447023046 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list9/index-postgresql.xql0000644000175000017500000000321110374102560027073 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and p.person_id = o.creation_user and exists (select 1 from acs_object_party_privilege_map where object_id = n.template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::filter_where_clauses -and -name notes] [template::list::orderby_clause -orderby -name notes] select n.template_demo_note_id, n.title, n.color, to_char(o.creation_date, 'YYYY-MM-DD HH24:MI:SS') as creation_date, p.first_names || ' ' || p.last_name as creation_user_name from template_demo_notes n, acs_objects o, persons p where n.template_demo_note_id = o.object_id and p.person_id = o.creation_user and exists (select 1 from acs_object_party_privilege_map where object_id = n.template_demo_note_id and party_id = :user_id and privilege = 'read') [template::list::page_where_clause -and -name notes -key template_demo_note_id] openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/index.adp0000644000175000017500000000060510374102560024636 0ustar frankiefrankie Notes @context;noquote@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/index.tcl0000644000175000017500000000345710374102560024664 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/13 13:11:12 jiml Exp $ } -query { orderby:optional color_filter_value:optional page:optional } -properties { notes:multirow context:onevalue create_p:onevalue } set package_id [ad_conn package_id] set user_id [ad_conn user_id] set context [list] set create_p [ad_permission_p $package_id create] set actions [list] if { $create_p } { lappend actions "Create Note" add-edit "Create Note" } set color_choices { {Blue blue} {Green green} {Purple purple} {Red red} {Orange orange} {Yellow yellow} } template::list::create -name notes \ -multirow template_demo_notes \ -key "template_demo_note_id" \ -page_size 3 \ -page_query_name template_demo_notes_paginate \ -actions $actions \ -bulk_actions { "Delete Checked Notes" "delete" "Delete Checked Notes" } \ -elements { title { label "Title of Note" link_url_col view_url } creation_user_name { label "Owner of Note" } creation_date { label "When Note Created" } color { label "Color" } } \ -filters { color_filter_value { label "Color" where_clause { n.color = :color_filter_value } values $color_choices } } \ -orderby { default_value title,asc title { label "Title of Note" orderby n.title } creation_user_name { label "Owner of Note" orderby creation_user_name } creation_date { label "When Note Created" orderby o.creation_date } color { label "Color" orderby n.color } } db_multirow -extend { view_url } template_demo_notes template_demo_notes {} { set view_url [export_vars -base view-one { template_demo_note_id }] } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/add-edit.adp0000644000175000017500000000023410374102560025200 0ustar frankiefrankie @page_title@ @context;noquote@ openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/add-edit.tcl0000644000175000017500000000773410676223700025237 0ustar frankiefrankie# packages/acs-templating/www/doc/demo/list8/add-edit.tcl ad_page_contract { @author Don Baccus (dhogaza@pacifier.com) @creation-date 2000-10-23 @cvs-id $Id: add-edit.tcl,v 1.2 2007/09/25 15:22:40 donb Exp $ Example script that allows for the creation or editing of a simple note object type, using ad_form and package Tcl API tools. } -query { template_demo_note_id:integer,notnull,optional } -properties { context:onevalue page_title:onevalue } # When using ad_form to generate or edit acs_objects, the object type's # key column must be specified in ad_page_contract as is done above, # and defined with the type "key" in ad_form. This enables the use of # the various request and submission code blocks. set package_id [ad_conn package_id] ad_form -form { # The "note" object type's key template_demo_note_id:key # "title" is of type text and will use a "text" widget. {title:text \ {label Title} {html {size 20}} } # "body" is of type text and will use a "textarea" widget. {body:text(textarea) \ {label Body} {html {rows 10 cols 40}} } # 'color' is a text using a text widget {color:text \ {label "Color"} {htmo {size 20}} } } -new_request { # By convention packages only allow a user to create new objects if the user has # the "create" privilege on the package instance itself. permission::require_permission -object_id $package_id -privilege create # Customize the page title to reflect the fact that this form is used to # create a new note. set page_title "New Note" } -edit_request { permission::require_permission -object_id $note_id -privilege write # Customize the page title to reflect the fact that this form is used to # edit an existing note. set page_title "Edit Note" # Fill the form with the values from the note we're editing. db_1row note_select {} } -on_validation_error { # There was an error in the form, let the page title reflect this. set page_title "Error in submission" } -new_data { # Create a new note. # Generate the new object automatically from the data set in the form. Standard # acs_object attributes like creation_user are set automatically. package_instantiate_object \ -var_list [list [list context_id $package_id]] \ -form_id add-edit \ template_demo_note } -edit_data { # Currently we need to update our object manually ... set modifying_user [ad_conn user_id] set modifying_ip [ad_conn peeraddr] db_transaction { db_dml object_update {} db_dml template_demo_note_update {} } } -after_submit { # We've successfully processed the submission. # Clear the pagination cache. cache flush notes* # send the user back to the index page ad_returnredirect "./" # NOTE! guess what, we wouldn't be done here; there is a problem: # notice that when you add a note when you have filters active, # it doesn't remember your filters when you come back from editing. # # we've decided this is beyond the scope of this tutorial and you # can learn more by studying the function export_vars (which would # be applied to the filter variables) # ad_returnredirect returns after redirecting the user, so abort the script rather # than fall through to the display code. Failure to abort the script will burden # your server with needless template processing, though the user won't notice due to # having been redirected. ad_script_abort } # The following is only executed if we did not process a valid submission, in other # words on the initial "new" or "edit" form request or after a submission which # contained errors. Add the page title to the breadcrumb context bar. set context [list $page_title] # Display the form, blank if we're processing a "new" request, filled with data if we're # processing an "edit" request or a submitted form that contains errors. ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/add-edit.xql0000644000175000017500000000117610374102560025246 0ustar frankiefrankie select title, body from notes where note_id = :note_id update acs_objects set modifying_user = :modifying_user, modifying_ip = :modifying_ip where object_id = :note_id update notes set title = :title, body = :body where note_id = :note_id openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/index-oracle.xql0000644000175000017500000000243610374102560026145 0ustar frankiefrankie oracle8.1.6 select note_id, title, body, decode(acs_permission.permission_p(note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from notes n, acs_objects o where n.note_id = o.object_id and o.context_id = :package_id and exists (select 1 from acs_object_party_privilege_map where object_id = note_id and party_id = :user_id and privilege = 'read') order by creation_date openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/delete.tcl0000644000175000017500000000110610374102560025004 0ustar frankiefrankie# packages/notes/www/delete.tcl ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: delete.tcl,v 1.1 2006/02/13 13:11:12 jiml Exp $ } { template_demo_note_id:integer,notnull,multiple } foreach template_demo_note_id $template_demo_note_id { ad_require_permission $template_demo_note_id delete package_exec_plsql \ -var_list [list [list template_demo_note_id $template_demo_note_id]] \ template_demo_note \ del } # We've successfully processed the submission. # Clear the pagination cache. cache flush notes* ad_returnredirect "./" openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/view-one.adp0000644000175000017500000000020010374102560025247 0ustar frankiefrankie @title;noquote@ @context;noquote@ @body;noquote@openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/view-one.tcl0000644000175000017500000000060310374102560025274 0ustar frankiefrankiead_page_contract { @author Neophytos Demetriou @creation-date 2001-09-02 } { note_id:integer,notnull } -properties { context:onevalue title:onevalue body:onevalue } set context [list "One note"] db_1row note_select { select title, body from notes where note_id = :note_id } set body [ad_text_to_html -- $body] ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/delete-oracle.xql0000644000175000017500000000036610374102560026300 0ustar frankiefrankie oracle8.1.6 begin note.del(:note_id); end; openacs-5.7.0/packages/acs-templating/www/doc/demo/list9/delete-postgresql.xql0000644000175000017500000000036610374102560027236 0ustar frankiefrankie postgresql7.1 select note__delete( :note_id ); openacs-5.7.0/packages/acs-templating/www/doc/demo/skin-plain.adp0000644000175000017500000000036007253523117024535 0ustar frankiefrankie

    Sample Users

    First NameLast Name
    @users.first_name@@users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/compile.tcl0000644000175000017500000000067607253523117024150 0ustar frankiefrankieset file [ns_queryget file] if { [regexp {\.\.|^/} $file] } { set compiled "Only files within this directory may be shown." } else { # [ns_url2file [ns_conn url]] fails under request processor ! # the file for URL pkg/page may be in packages/pkg/www/page, not www/pkg/page set dir [file dirname [ad_conn file]] set compiled [ns_quotehtml [template::adp_compile -file $dir/$file]] } ns_return 200 text/html "
    $compiled
    " openacs-5.7.0/packages/acs-templating/www/doc/demo/grid.adp0000644000175000017500000000145607253523117023424 0ustar frankiefrankie

    Sample Users

    @users.rownum@. @users.first_name@ @users.last_name@  
    openacs-5.7.0/packages/acs-templating/www/doc/demo/grid.tcl0000644000175000017500000000043507537470230023440 0ustar frankiefrankiead_page_contract { @cvs-id $Id: grid.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { users:multirow } set query "select first_name, last_name from ad_template_sample_users" db_multirow users users_query $query openacs-5.7.0/packages/acs-templating/www/doc/demo/date-test.adp0000644000175000017500000000052107253523117024361 0ustar frankiefrankie

    Happy Birthday


    Tomorrow's date in SQL: @tomorrow_sql@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/date-test.tcl0000644000175000017500000000424007253523117024401 0ustar frankiefrankietemplate::form create date_test template::element create date_test name \ -label "Name" -datatype text -widget text template::element create date_test date_simple \ -label "Simple Date" -datatype date -widget date \ -format "YYYY/MM/DD" -optional template::element create date_test date_simple_reqd \ -label "Simple Date (required)" -datatype date -widget date \ -format "YYYY/MM/DD" template::element create date_test date_long \ -label "Long Date" -datatype date -widget date \ -format long -optional template::element create date_test date_text \ -label "Textual Date" -datatype date -widget date \ -format "YYYYt/MMt/DDt HH24t:MIt:SSt" -optional template::element create date_test date_long_month \ -label "Long Month" -datatype date -widget date \ -format "YYYY/MONTH/DD" -optional template::element create date_test date_short_month \ -label "Short Month" -datatype date -widget date \ -format "YYYY/MON/DD" -optional template::element create date_test date_interval \ -label "Custom Intervals" -datatype date -widget date \ -format "YYYY/MM/DD HH24:MI:SS" -optional \ -year_interval { 2000 2005 1 } \ -month_interval { 1 5 1} \ -day_interval { 1 31 7 } \ -minutes_interval { 0 59 5 } \ -seconds_interval { 0 59 15 } template::element create date_test date_american \ -label "American Date" -datatype date -widget date \ -format american -optional template::element create date_test date_ampm \ -label "12 Hour Time" -datatype date -widget date \ -format "HH12:MI:SS AM" -optional template::element create date_test date_help \ -label "Context Help" -datatype date -widget date \ -format "YYYY/MM/DD HH12:MI:SS AM" -optional \ -help template::element create date_test date_exp \ -label "Expiration date" -datatype date -widget date \ -format expiration -optional # Set some example variables # Create a blank date set today_date [template::util::date create] # Get the tomorrow's date set clock_value [clock scan "1 day" -base [clock seconds]] set tomorrow_date [template::util::date set_property clock $today_date $clock_value] # Get the SQL value set tomorrow_sql [template::util::date::get_property sql_date $tomorrow_date] openacs-5.7.0/packages/acs-templating/www/doc/demo/fibo.adp0000644000175000017500000000033307663155705023420 0ustar frankiefrankie @n;noquote@
    *
    Description Data Template Compiled
    Template
    Output
    Simple variable substitution View View View View
    Using bind variables in your query View View View View
    A plain Tcl page that returns its own output View None None View
    Conditional Expressions View View View View
    Comments None View View View

    Combining templates

    Description Data Template Compiled
    Template
    Output
    Include a template within another template View include
    included
    include
    included
    View
    Wrap a page within a master template None Slave
    Master
    Slave
    Master
    View
    Using the default master None View View View
    Include with master and recursion.
    Remember Fibonacci from pset 1, exercise 1?
    Start
    Included
    Master
    Start
    Included
    Master
    Start
    Included
    Master
    View

    Embedded Tcl

    Description Data Template Compiled
    Template
    Output
    Tcl escape with implicit output View View View View
    Tcl escape with explicit output None View View View
    Template chunks within escaped Tcl code blocks View View View View
    Puts (if you absolutely must) View View View View

    Iteration

    To see the following examples with different data, you can enter additional users into the sample table with "a simple form" or change them with "editing: several pages in one" in section
    Using the Form Manager below.
    Description Data Template Compiled
    Template
    Output
    Repeating template chunks for each row of a query result View View View View
    Generating the multirow datasource in TCL View View View View
    Repeating template chunks for each row of a query result, with custom manipulation of data View View View View
    Repeating template chunks with grouping View View View View
    Repeating template chunks as cells of a grid View View View View
    Repeating template chunks for each element of a list View View View View

    Both Iteration and Composition

    Description Data Template Compiled
    Template
    Output
    Apply different skins to the same data View Plain
    Fancy
    Plain
    Fancy
    Plain
    Fancy
    Absolute
    Passing a multirow datasource to an included page View Outer
    Included
    Outer
    Included
    View
    Processing a template from a string (not file) View View View View

    Using ListBuilder

    Description Data Template Compiled
    Template
    Output
    Simplest (single-column) list, no features View .tcl
    postgres query
    oracle query
    No master
    W/ master
    No master
    W/ master
    No master
    W/ master
    Add some columns View .tcl
    postgres query
    oracle query
    View View View
    Add the ability to sort by any column View .tcl
    postgres query
    oracle query
    View View View
    Link the title to a one-note detail page index
    detail
    index
    detail
    index
    detail
    View
    Add a bulk action to delete all checked notes index
    delete
    postgres query
    oracle query
    index index View
    Add a single/non-bulk action to create a note index
    add-edit
    index
    add-edit
    index
    add-edit
    View
    Add a filter index
    postgres query
    oracle query
    index
    index
    View
    Add pagination with no page group cache index
    postgres query
    oracle query
    index
    index
    View
    Add page group caching to pagination (no looks difference) index
    add-edit
    delete
    index
    index
    View

    Forms

    Description Data Template Compiled
    Template
    Output
    Using ad_page_contract Target Form
    Target
    Error Page
    Form
    Target
    Error Page
    Form
    Target
     
    Report an error related to a request. View View Plain View

    Using the Form Manager.

    Description Data Template Compiled
    Template
    Output
    A simple form View View View View
    A form with button groups View Simple
    Gridded
    Simple
    Gridded
    Simple
    Gridded
    A form with Select widgets View View View View
    Custom validation of a request View View View Inline Error Message
    Sitewide Error Page
    Valid Request
    A form with the Date widget View View View View
    Editing: several pages in one View View View View
    A form with a custom confirmation page View Submit
    Confirm
    Submit
    Confirm
    View
    A form with display/edit modes View View View View
    A form with multiple submit buttons View View View View


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/demo/select.adp0000644000175000017500000000044707253523117023755 0ustar frankiefrankie

    Car Accessories



    openacs-5.7.0/packages/acs-templating/www/doc/demo/select.tcl0000644000175000017500000000063407253523117023771 0ustar frankiefrankieform create car_opts element create car_opts extras \ -label "Car Accessories" -datatype text -widget multiselect \ -options { {{Power Windows} windows} {{Anti-Lock Brakes} brakes} {{AI Alarm System} alarm} {{Rocket Laucnher} rocket} } element create car_opts payment \ -label "Payment Type" -datatype text -widget select \ -options {{Cash cash} {{ATM Card} atm} {{Credit Card} credit}} openacs-5.7.0/packages/acs-templating/www/doc/demo/string.adp0000644000175000017500000000034107253523117023775 0ustar frankiefrankie

    Food

    (@body:rownum@) @body:item@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/string.tcl0000644000175000017500000000101607253523117024013 0ustar frankiefrankie# suppose this template was obtained from a database query set template " @name@ ordered
    • @food:item@
    • \n
    " set code [adp_compile -string $template]; # compile the template set name John set food [list "potato salad" "penne all' arrabiata" "steak" "baked alaska"] adp_eval code; # running code sets __adp_ouput lappend body $__adp_output set name Jill set food [list "chilled sea food" "soup"] adp_eval code; # run compiled template again lappend body $__adp_output openacs-5.7.0/packages/acs-templating/www/doc/demo/multiple.adp0000644000175000017500000000145707253523117024333 0ustar frankiefrankie

    Sample Users

    Sorry, there are no users in the system at this time.

    Striped

    First NameLast Name
    @users.first_name@@users.last_name@

    Maximally 2 rows, starting after 1

    Row NumberFirst NameLast Name
    @users.rownum@ @users.first_name@ @users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/multiple.tcl0000644000175000017500000000064307537470230024347 0ustar frankiefrankiead_page_contract { @cvs-id $Id: multiple.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ @datasource users multirow Complete list of sample users @column first_name First name of the user. @column last_name Last name of the user. } -properties { users:multirow } set query "select first_name, last_name from ad_template_sample_users" db_multirow users users_query $query openacs-5.7.0/packages/acs-templating/www/doc/demo/skin.tcl0000644000175000017500000000102207537470230023450 0ustar frankiefrankiead_page_contract { @cvs-id $Id: skin.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } { skin } -properties { users:multirow } set query "select first_name, last_name from ad_template_sample_users order by last_name, first_name" db_multirow users users_query $query # Choose a skin switch $skin { plain { set file skin-plain } fancy { set file skin-fancy } default { set file /packages/acs-templating/www/doc/demo/skin-plain } } ad_return_template $file openacs-5.7.0/packages/acs-templating/www/doc/demo/fibo-master.adp0000644000175000017500000000026607253523117024705 0ustar frankiefrankie
    colspan=2 >@level@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/fibo-master.tcl0000644000175000017500000000011310551254405024706 0ustar frankiefrankieset color [format "%.6x" [expr {0xd53feb * $level & 0xffffff | 0x808080}]] openacs-5.7.0/packages/acs-templating/www/doc/demo/if.adp0000644000175000017500000000637007443753715023107 0ustar frankiefrankie

    Conditional Expressions

    The value of x is @x@
    The value of y is @y@
    The value of n is @n@
    The value of bool_t_p is @bool_t_p@
    The value of bool_1_p is @bool_1_p@
    The value of bool_f_p is @bool_f_p@
    The value of bool_0_p is @bool_0_p@

    Operator Test Result
    eq if \@x\@ eq 5 X is 5X is not 5
    eq if \@x\@ eq 6 X is 6X is not 6
    eq if \@n\@ eq "Fred's Flute" N is "Fred's Flute" N is not "Fred's Flute"
    eq if \@n\@ eq "Fred" N is "Fred" N is not "Fred"
    defined if \@x\@ defined x is defined x is undefined
    nil if \@x\@ nil x is nil x is nonnil
    defined if \@z\@ defined z is defined z is undefined
    nil if \@z\@ nil z is nil z is nonnil
    defined if \@w\@ defined w is defined w is undefined
    nil if \@w\@ nil w is nil w is nonnil
    nil if \@w\@ nil w is nil w is nonnil
    true if \@bool_t_p\@ true ok not ok
    true if \@bool_1_p\@ true ok not ok
    true short if \@bool_t_p\@ ok not ok
    true short if \@bool_1_p\@ ok not ok
    false if \@bool_f_p\@ false ok not ok
    false if \@bool_0_p\@ false ok not ok
    openacs-5.7.0/packages/acs-templating/www/doc/demo/if.tcl0000644000175000017500000000034407537470230023110 0ustar frankiefrankiead_page_contract { @cvs-id $Id: if.tcl,v 1.3 2002/09/10 22:22:16 jeffd Exp $ } -properties { users:multirow } set x 5 set y 10 set n "Fred's Flute" set z "" set bool_t_p t set bool_1_p 1 set bool_f_p f set bool_0_p 0 openacs-5.7.0/packages/acs-templating/www/doc/demo/included.adp0000644000175000017500000000015107253523117024255 0ustar frankiefrankie

    This is the included template fragment here.

    Hello @name@!

    openacs-5.7.0/packages/acs-templating/www/doc/demo/request.adp0000644000175000017500000000004107253523117024154 0ustar frankiefrankieThe ID is @id@. The key is @key@.openacs-5.7.0/packages/acs-templating/www/doc/demo/request.tcl0000644000175000017500000000021507253523117024175 0ustar frankiefrankierequest create -params { id -datatype integer -label "ID" key -datatype keyword -label "Key" } if { ! [request is_valid] } { return } openacs-5.7.0/packages/acs-templating/www/doc/demo/list1a/0000755000175000017500000000000011724401447023177 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list1a/index-postgresql.xql0000644000175000017500000000112110371175733027233 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title from template_demo_notes n, acs_objects o where n.template_demo_note_id = o.object_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') openacs-5.7.0/packages/acs-templating/www/doc/demo/list1a/index.adp0000644000175000017500000000006510371175733025000 0ustar frankiefrankie openacs-5.7.0/packages/acs-templating/www/doc/demo/list1a/index.tcl0000644000175000017500000000073610371175733025023 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/04 19:09:15 jiml Exp $ } -properties { notes:multirow } set package_id [ad_conn package_id] set user_id [ad_conn user_id] db_multirow template_demo_notes template_demo_notes {} template::list::create -name notes \ -multirow template_demo_notes \ -elements { title { label "Title of Note" } } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list1a/index-oracle.xql0000644000175000017500000000262110372765251026304 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o where n.template_demo_note_id = o.object_id and exists (select 1 from acs_object_party_privilege_map where object_id = n.template_demo_note_id and party_id = :user_id and privilege = 'read') order by creation_date openacs-5.7.0/packages/acs-templating/www/doc/demo/list1b/0000755000175000017500000000000011724401447023200 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/demo/list1b/index-postgresql.xql0000644000175000017500000000112110371175733027234 0ustar frankiefrankie postgresql7.1 select n.template_demo_note_id, n.title from template_demo_notes n, acs_objects o where n.template_demo_note_id = o.object_id and exists (select 1 from acs_object_party_privilege_map where object_id = template_demo_note_id and party_id = :user_id and privilege = 'read') openacs-5.7.0/packages/acs-templating/www/doc/demo/list1b/index.adp0000644000175000017500000000005410371175733024777 0ustar frankiefrankie openacs-5.7.0/packages/acs-templating/www/doc/demo/list1b/index.tcl0000644000175000017500000000073610371175733025024 0ustar frankiefrankie# main index page for notes. ad_page_contract { @author rhs@mit.edu @creation-date 2000-10-23 @cvs-id $Id: index.tcl,v 1.1 2006/02/04 19:09:15 jiml Exp $ } -properties { notes:multirow } set package_id [ad_conn package_id] set user_id [ad_conn user_id] db_multirow template_demo_notes template_demo_notes {} template::list::create -name notes \ -multirow template_demo_notes \ -elements { title { label "Title of Note" } } ad_return_template openacs-5.7.0/packages/acs-templating/www/doc/demo/list1b/index-oracle.xql0000644000175000017500000000262110372765251026305 0ustar frankiefrankie oracle8.1.6 select n.template_demo_note_id, n.title, n.body, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'write'), 't', 1, 'f', 0) as write_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'admin'), 't', 1, 'f', 0) as admin_p, decode(acs_permission.permission_p(n.template_demo_note_id, :user_id, 'delete'), 't', 1, 'f', 0) as delete_p from template_demo_notes n, acs_objects o where n.template_demo_note_id = o.object_id and exists (select 1 from acs_object_party_privilege_map where object_id = n.template_demo_note_id and party_id = :user_id and privilege = 'read') order by creation_date openacs-5.7.0/packages/acs-templating/www/doc/demo/reference.adp0000644000175000017500000000101507253523117024424 0ustar frankiefrankie

    Passing a Multirow Datasource

    Here are all sample users.
    The following have an "e" in their first names.
    This is the outer template again. openacs-5.7.0/packages/acs-templating/www/doc/demo/reference.tcl0000644000175000017500000000056507537470230024455 0ustar frankiefrankiead_page_contract { @cvs-id $Id: reference.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { users:multirow } set query "select first_name, last_name, state from ad_template_sample_users" set e_query "$query where first_name like '%e%'" db_multirow users users_query $query db_multirow e_people e_people_q $e_query openacs-5.7.0/packages/acs-templating/www/doc/demo/sandwich.adp0000644000175000017500000000045507253523117024275 0ustar frankiefrankie

    Customize a Sandwich



    openacs-5.7.0/packages/acs-templating/www/doc/demo/sandwich.tcl0000644000175000017500000000175410551254405024312 0ustar frankiefrankiead_page_contract { @cvs-id $Id: sandwich.tcl,v 1.3 2007/01/10 21:22:13 gustafn Exp $ } { {grid ""} } -properties {} form create sandwich element create sandwich grid \ -label "grid" -optional \ -datatype text -widget hidden element create sandwich nickname -html { size 30 } \ -label "Sandwich Name" -datatype text element create sandwich protein \ -label "Protein" -datatype text -widget radio \ -options { {Bacon bacon} {Chicken chicken} {Beef beef} } element create sandwich vitamins \ -label "Vitamins" -datatype text -widget checkbox -optional \ -options { {Lettuce lettuce} {Tomato tomato} \ {Pickle pickle} {Sprouts sprouts} } # Set defaults if { [form is_request sandwich] } { element set_properties sandwich vitamins -value {tomato} # or: element set_value sandwich vitamins tomato element set_properties sandwich grid -value $grid } # Choose standard or gridded output if {[element get_value sandwich grid] eq "t"} { ad_return_template sandwich-grid } openacs-5.7.0/packages/acs-templating/www/doc/demo/contract-err.adp0000644000175000017500000000040607253523117025074 0ustar frankiefrankie Problem with Your Input
    We had a problem some problems processing your entry:
    • @error_list:item@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/contract-err.tcl0000644000175000017500000000012107253523117025104 0ustar frankiefrankie# ad_return_template stays in the same scope set n_errors [llength $error_list] openacs-5.7.0/packages/acs-templating/www/doc/demo/skin-fancy.adp0000644000175000017500000000075207253523117024537 0ustar frankiefrankie

    Sample Users

    First NameLast Name
    @users.first_name@@users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/contract.adp0000644000175000017500000000074507253523117024314 0ustar frankiefrankie User Input Form
    How many? (not 13)
    Give me a noun:
    Any irregular plural? (optional)
    openacs-5.7.0/packages/acs-templating/www/doc/demo/contract.tcl0000644000175000017500000000014607537470230024327 0ustar frankiefrankiead_page_contract { @cvs-id $Id: contract.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties {} openacs-5.7.0/packages/acs-templating/www/doc/demo/group.adp0000644000175000017500000000124407253523117023626 0ustar frankiefrankie

    Sample Users by State

    @users.state@

    The @users.last_name@ Family

    • @users.first_name@ @users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/group.tcl0000644000175000017500000000046707537470230023654 0ustar frankiefrankiead_page_contract { @cvs-id $Id: group.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { users:multirow } set query "select first_name, last_name, state from ad_template_sample_users order by state, last_name" db_multirow users users_query $query openacs-5.7.0/packages/acs-templating/www/doc/demo/pay.adp0000644000175000017500000000044707253523117023267 0ustar frankiefrankie

    Make a Payment



    openacs-5.7.0/packages/acs-templating/www/doc/demo/pay.tcl0000644000175000017500000000151407540424417023303 0ustar frankiefrankieform create pay_bill -section required -elements { payee -label "Payee" -datatype text -widget text amount -label "Amount" -datatype integer -widget text } template::form::section pay_bill optional template::element::create pay_bill note -label "Note" -datatype text -widget text -optional # check if this is the initial submission or the confirmation page if { [ns_queryexists form:confirm] } { # do the dml and forward # ns_ora dml ... template::forward index.html } if { [form is_valid pay_bill] } { # use the form export proc (in form-procs.tcl) to capture all the form data # as hidden elements set confirm_data [form export] # add the form:confirm element append confirm_data "" template::set_file "[file dir $__adp_stub]/pay-confirm" } openacs-5.7.0/packages/acs-templating/www/doc/demo/comment.adp0000644000175000017500000000050707253523117024135 0ustar frankiefrankie The template system introduces no new mechanisms for comments. You can use HTML comments () and TCL comments (<%# but they can never look at that %>).
    Neither are visible on the HTML page. openacs-5.7.0/packages/acs-templating/www/doc/demo/state.adp0000644000175000017500000000144307253523117023613 0ustar frankiefrankie

    Sample Users by State

    Sorry, there was an error processing your request:
    @requesterror.state_abbrev@

    @state_abbrev@

    The @users.last_name@ Family

    • @users.first_name@ @users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/state.tcl0000644000175000017500000000122607253523117023630 0ustar frankiefrankiead_page_contract { $Id: state.tcl,v 1.1.1.1 2001/03/13 22:59:27 ben Exp $ } -query { state_abbrev } -properties {} request create request set_param state_abbrev -datatype keyword -validate { { regexp {CA|HI|NV} $value } { Invalid state abbreviation $value. } } # demonstrate the separate error page if { [ns_queryexists errorpage] } { if { [request is_valid] } { return } } else { request is_valid self } set query "select first_name, last_name, state from ad_template_sample_users where state = :state_abbrev order by last_name" db_multirow users state_query $queryopenacs-5.7.0/packages/acs-templating/www/doc/demo/multirow.adp0000644000175000017500000000072007253523117024352 0ustar frankiefrankie

    The Inner Solar System

    # NameDiameterMassOrbit Radius
    [km][kg][km]
    @body.rownum@ @body.name@ @body.diameter@ @body.mass@ @body.r_orbit@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/multirow.tcl0000644000175000017500000000136607537470230024401 0ustar frankiefrankiead_page_contract { @cvs-id $Id: multirow.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ @datasource body multirow The sun and planets of our solar system @column name "Sun" or name of the planet. @column diameter body diameter. @column mass mass of the celestial body. @column r_orbit orbit radius } -properties { users:multirow } template::multirow create body name diameter mass r_orbit template::multirow append body "Sun" 1391900 1.989e30 "N/A" template::multirow append body "Mercury" 4866 3.30e23 57950000 template::multirow append body "Venus" 12106 4.869e24 108110000 template::multirow append body "Earth" 12742 5.9736e24 149570000 template::multirow append body "Mars" 6760 6.4219e23 227840000 openacs-5.7.0/packages/acs-templating/www/doc/demo/sandwich-grid.adp0000644000175000017500000000463207253523117025221 0ustar frankiefrankie

    Customize a Sandwich


    Sandwich Name  
    @formerror.nickname@
    Protein  
    @formgroup.widget@ @formgroup.label@  

    @formerror.protein@
    Vitamins  
    @formgroup.widget@ @formgroup.label@  

    @formerror.vitamins@


    openacs-5.7.0/packages/acs-templating/www/doc/demo/contract-2.adp0000644000175000017500000000021307253523117024441 0ustar frankiefrankie Pluralized in datasource @phrase@. This uses ad_page_contract.

    openacs-5.7.0/packages/acs-templating/www/doc/demo/contract-2.tcl0000644000175000017500000000125510551254405024462 0ustar frankiefrankiead_page_contract { @cvs-id $Id: contract-2.tcl,v 1.3 2007/01/10 21:22:13 gustafn Exp $ } { count:naturalnum noun:notnull,nohtml { plural:nohtml "" } } -validate { supersticion -requires {count} { if {$count == 13} { ad_complain } } } -errors { supersticion {This number brings you no luck.} } -properties { phrase:onevalue } -return_errors error_list if {[info exists error_list]} { # divert to error-handling page ad_return_template "contract-err" } else { set phrase "You've got " if {$count == 1} { append phrase "one $noun" } else { if {$plural eq ""} { set plural "${noun}s" } append phrase "$count $plural" } } openacs-5.7.0/packages/acs-templating/www/doc/demo/include.adp0000644000175000017500000000041607663155705024126 0ustar frankiefrankie

    Included Template

    relative:
    absolute: This is the outer template. openacs-5.7.0/packages/acs-templating/www/doc/demo/include.tcl0000644000175000017500000000021207537470230024127 0ustar frankiefrankiead_page_contract { @cvs-id $Id: include.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { name:onevalue } set name "Barney" openacs-5.7.0/packages/acs-templating/www/doc/demo/embed_escape.adp0000644000175000017500000000072607253523117025072 0ustar frankiefrankie

    Welcome

    <% if { $x == 5 } { %> Yes, x is indeed 5. <% } else { %> No, x is not 5. <% } %>

    <% foreach creature [list giraffe lion antelope fly] { %> <% if [regexp {a} $creature] { %> <% } else { %> <% } %> <% } %>
    <%=$creature%>
    openacs-5.7.0/packages/acs-templating/www/doc/demo/embed_escape.tcl0000644000175000017500000000020207537470230025077 0ustar frankiefrankiead_page_contract { @cvs-id $Id: embed_escape.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { x:onevalue } set x 5 openacs-5.7.0/packages/acs-templating/www/doc/demo/hello.adp0000644000175000017500000000006707253523117023577 0ustar frankiefrankie

    @hello@

    openacs-5.7.0/packages/acs-templating/www/doc/demo/hello.tcl0000644000175000017500000000027607537470230023621 0ustar frankiefrankiead_page_contract { @cvs-id $Id: hello.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ @onevalue The greeting to print on the page. } -properties { hello:onevalue } set hello "Hello World" openacs-5.7.0/packages/acs-templating/www/doc/demo/fibo-start.adp0000644000175000017500000000011407663155705024550 0ustar frankiefrankie openacs-5.7.0/packages/acs-templating/www/doc/demo/fibo-start.tcl0000644000175000017500000000023607537470230024564 0ustar frankiefrankiead_page_contract { @cvs-id $Id: fibo-start.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } -properties { m:onevalue } -query { m:naturalnum,notnull } openacs-5.7.0/packages/acs-templating/www/doc/demo/slave-default.adp0000644000175000017500000000061507253523117025227 0ustar frankiefrankie Using the site-wide skin

    Using the site-wide skin

    This page will be wrapped in the default master, which expects the property title. It is specified by omitting the src attribute from the <master> tag.

    The procedures ad_header and ad_footer are deprecated.

    openacs-5.7.0/packages/acs-templating/www/doc/demo/user-edit.adp0000644000175000017500000000145407253523117024376 0ustar frankiefrankie

    Edit User Properties


    Please search for a user to edit by specifying any portion of a first or last name.


    @formerror.user_search@

    The following users match your search criteria. Choose one to edit their properties:

    @users.first_name@ @users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/user-edit.tcl0000644000175000017500000000712010551254405024404 0ustar frankiefrankierequest create -params { user_id -datatype integer -optional } if { ! [request is_valid] } { return } # use a single variable to control what is displayed on the page: # 1) user_edit a user edit form # 2) user_search user search form # 3) user_list results of a user search # instantiate the user search form. It may not be displayed but creating it # allows us to set error messages more easily. form create user_search -elements { user_search -datatype text -html { size 40 } -label "Search Text" submit -datatype text -widget submit -label "Go" } set user_search [element get_value user_search user_search] # the main logic depends on whether the request includes a user ID or not. if { $user_id ne {} } { # the request included a user ID set display "user_edit" } else { # handle a missing user ID if {$user_search eq {}} { # no user search string returned. set display "user_search" if { [form is_submission user_search] } { # the user submitted a blank search form element set_error user_search user_search " Please specify search criteria." } } else { # query for users (obviously not a very scalable query) set user_search [string tolower $user_search] query get_users users multirow " select user_id, first_name, last_name from ad_template_sample_users where lower(first_name) like '%' || :user_search || '%' or lower(last_name) like '%' || :user_search || '%'" set user_count [multirow size users] if { $user_count == 1 } { # if only one found, then set the user_id and proceed set user_id [multirow get users 1 user_id] set display "user_edit" } elseif { $user_count > 1 } { # multiple users found so display a list of choices set display "user_list" } else { # no results so search again set display "user_search" element set_error user_search user_search " No users were found matching your search criteria.
    Please try again." } # end handling user search } # end handling an empty user_id query parameter } # return without instantiating the edit form if we don't know the user_id yet if { $display ne "user_edit" } { return } form create user_edit -elements { user_id -datatype integer -widget hidden first_name -datatype text -widget text -html { size 25 maxlength 20 } \ -label "First Name" last_name -datatype text -widget text -html { size 25 maxlength 20 } \ -label "Last Name" address1 -datatype text -widget text -html { size 45 maxlength 40 } \ -label "Address 1" address2 -datatype text -widget text -html { size 45 maxlength 40 } \ -label "Address 2" city -datatype text -widget text -html { size 45 maxlength 40 } \ -label "City" state -datatype text -widget text -html { size 4 maxlength 2 } \ -label "State" } if { [form is_request user_edit] } { if { ! [query get_info info onerow " select user_id, first_name, last_name, address1, address2, city, state from ad_template_sample_users where user_id = :user_id"] } { request error invalid_user_id "Invalid User ID" } form set_values user_edit info } if { [form is_valid user_edit] } { form get_values user_edit first_name last_name address1 address2 city state db_dml update_sample_users "update ad_template_sample_users set first_name = :first_name, last_name = :last_name, address1 = :address1, address2 = :address2, city = :city, state = :state where user_id = :user_id" template::forward multiple } openacs-5.7.0/packages/acs-templating/www/doc/demo/user-edit.xql0000644000175000017500000000111207435010217024417 0ustar frankiefrankie select user_id, first_name, last_name from ad_template_sample_users where lower(first_name) like '%' || :user_search || '%' or lower(last_name) like '%' || :user_search || '%' select user_id, first_name, last_name, address1, address2, city, state from ad_template_sample_users where user_id = :user_id openacs-5.7.0/packages/acs-templating/www/doc/demo/slave.adp0000644000175000017500000000013207253523117023577 0ustar frankiefrankie My Page

    This is my page.

    openacs-5.7.0/packages/acs-templating/www/doc/demo/error.adp0000644000175000017500000000021107253523117023614 0ustar frankiefrankie

    Congratulations, you made it!

    This page is only accessible on even ticks of the clock.

    Reload

    openacs-5.7.0/packages/acs-templating/www/doc/demo/error.tcl0000644000175000017500000000055307774104724023652 0ustar frankiefrankie if { [clock clicks -milliseconds] % 2 } { lappend problems is_odd "You caught the page on an odd tick." lappend problems another_thing "This is just another error." } if { [info exists problems] } { eval request error $problems # Note that you must explicitly return from the tcl script following an error. return } # Set up some data sources... openacs-5.7.0/packages/acs-templating/www/doc/demo/submit-test.adp0000644000175000017500000000050407253523117024750 0ustar frankiefrankie

    Multiple Submit widgets



    @text@

    openacs-5.7.0/packages/acs-templating/www/doc/demo/submit-test.tcl0000644000175000017500000000115507253523117024771 0ustar frankiefrankieform create submit_test element create submit_test name -label "Name" \ -widget text -datatype text -size 20 element create submit_test over -label "I am over 18" \ -widget submit -datatype text element create submit_test under -label "I am young and impressionable" \ -widget submit -datatype text if { [form is_valid submit_test] } { form get_values submit_test over under name if { ![template::util::is_nil over] } { set text "Naughty-naughty, $name." } elseif { ![template::util::is_nil under] } { set text "Quick ! Close your eyes, young $name !" } } else { set text "SUBMIT already !" } openacs-5.7.0/packages/acs-templating/www/doc/demo/bind.adp0000644000175000017500000000030107253523117023377 0ustar frankiefrankie

    Sample User

    First NameLast Name
    @users.first_name@@users.last_name@
    openacs-5.7.0/packages/acs-templating/www/doc/demo/bind.tcl0000644000175000017500000000051407537470230023425 0ustar frankiefrankiead_page_contract { @cvs-id $Id: bind.tcl,v 1.2 2002/09/10 22:22:16 jeffd Exp $ } { user_id:integer } -properties { users:onerow } set query "select first_name, last_name from ad_template_sample_users where user_id = :user_id" db_1row users_query $query -column_array users openacs-5.7.0/packages/acs-templating/www/doc/developer-guide.html0000644000175000017500000001273110012145650025016 0ustar frankiefrankie Template System Guide

    Programmer / Developer Guide

    Templating System : Developer Guide

    Mini How To

    Start a Tcl page as usual with ad_page_contract. Be sure to pass a -properties block; this signals the use of templating. The tcl page should fill the data sources you promised in the contract, and not write to the connection. At the end of your tcl page, call ad_return_template. The template system will look for an adp page with the file name stub you indicate (defaulting to the same stub as the tcl page), process that, and deliver it to the client. The adp page can use the datasources defined in the tcl page.

    Guide

    1. User Guide
    2. Object and API Reference
    3. Template Markup Tag Reference
    4. Appendices

    API

    After the script for a page is executed, acs-templating processes the template, interpolating any data sources and executing the special tags. The resulting HTML page is written to the connection (i.e., returned to the user).
    ad_return_template
    Normally, does nothing at all. With the -string option you get the resulting HTML page returned as a string.

    The optional template argument is a path to a page (tcl/adp file pair). Note that you don't supply the ".tcl" or ".adp" extension. It is resolved by help of template::util::url_to_file (with the current file stub as reference path) and passed to template::set_file, to change the name of the page being served currently. If it starts with a "/", it is taken to be a path relative to the server root; otherwise it is a filename relative to the directory of the tcl script.

    ad_page_contract
    Normally, complaints about incorrect parameters are written directly to the connection, and the script is aborted. With the option -return_errors you can name a variable into which to put any error messages as a list, and ad_page_contract will return in any case. You can then present the errors to the user in a templated page, consistent with the look and feel of the rest of your service. If there's no complaint, ad_page_contract won't touch the variable; typically it will stay undefined.
    Christian Brechbühler
    Last modified: $Id: developer-guide.html,v 1.3 2004/02/10 12:16:40 joela Exp $ openacs-5.7.0/packages/acs-templating/www/doc/guide/0000755000175000017500000000000011724401447022153 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/guide/templates.html0000644000175000017500000001036407253523117025044 0ustar frankiefrankie Templating System User Guide: Writing Templates

    Writing Templates

    Templating System : User Guide

    Templates are the primary means for separating the work of developers and designers. A template is written by a designer and consists largely of static HTML (or other markup). The template author uses a small set of special markup tags to reference dynamic data prepared by the developer. A reasonably skilled template author should be able to implement a template without any assistance from the developer, other than assuring that the proper dynamic data is accessible.

    This document introduces the basic concepts underlying the use of template tags in ACS 4.0.

    Variable Substitution

    Much like the mail merge feature of a word processor, template authors must use special tags to position each piece of dynamic data within the layout. Each template is associated with a data dictionary that lists all available variables.

    See Variable Substitution.

    Use of Components

    To speed development and ensure consistency of design, template authors are encouraged to assemble pages from distinct component templates that may be recycled in different contexts. One typical practice is to build a "master" template for an entire section of a site, with a common header, footer and sidebar layout. For each page request, the "content" template is incorporated dynamically into a specified area of the master template, usually a table cell.

    (graphic)

    Another common practice is to build small reusable templates that may be included in other templates as logical components. This may be useful for common "widgets" such as search boxes or lists of related links, as well as for building configurable portal pages where users may assemble different types of content to their liking.

    (graphic)

    See include.

    Property Declarations

    Template authors need a simple mechanism for declaring properties within the templates. The most common use of such properties is for configuring elements of an enclosing master template, such as the title, navigation links, and whether to include a search box. The data dictionary specifies available properties as well as the set of valid values when appropriate.

    (graphic)

    See property.

    Conditional Insertion

    Designers often need to tailor the layout depending on the specific data being presented. For example, when presenting a list of library books that a user has checked out, the designer might want to highlight the overdue ones in red.

    See if..else.

    Iteration

    Dynamic pages often present lists of values or records, each of which typically represents the results of a database query. Template authors must have a way to iterate over each value or record in such a list and format it appropriately. In the simplest scenario, the exact HTML is repeated with each iteration. However, template authors often need to vary the design depending on the context. For example:

    1. First and last items may be formatted differently from items in between.

    2. Special breaks may be required when a particular value changes. For example, a query may return the name and office of all employees in a company, and the designer may wish to insert a subheading for each office.

    3. Colors or patterns may alternate between items. For example, the designer may want to have alternate between white and gray bands in a table.

    To accomodate these type of scenarios, the template parser sets some additional variables that the designer can reference to vary the layout from item to item.

    See multiple, group, list.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/data.html0000644000175000017500000000673507253523117023766 0ustar frankiefrankie Templating System User Guide: Data Sources

    Implementing Data Sources

    Templating System : Developer Guide : User Guide

    Data sources are implemented in a Tcl script using regular Tcl variables, lists and arrays. The templating system includes a set of procedures to simplify the construction of data sources from relational database queries.

    The Structure of Data Sources

    The templating system can manipulate four basic types of structures as data sources:

    onevalue A simple scalar, such as a user's first name or the total due on a purchase order.
    onelist A list of simple scalars.
    onerow A one-row data table, with values in one or more columns.
    multirow A multi-row, multi-column data table.

    onevalue

    onevalue data sources are implemented simply by setting a Tcl variable:

    set name "Walter Cronkite"

    The query procedure may be used to set a onevalue data source based on a database query:

    query name onevalue "select name from users where user_id = 123"

    You can embed a onevalue data source in a template with simple variable substitution.

    onerow

    onerow data sources are implemented as Tcl arrays:

    set name(first_name) Walter
    set name(last_name) Cronkite

    The query procedure may be used as a convenient way to store the result of a one-row database query into an array:

    query name onerow "
      select 
        first_name, last_name 
      from 
        users 
      where  
        user_id = 123"

    You can embed references to column values of a onerow data source in a template with simple variable substitution.

    onelist

    onelist data sources are implemented by creating a Tcl list:

    set names [list "Walter" "Fred" "Susy" "Frieda"]

    The query procedure may be used to set a onelist data source based on a one-column database query:

    query name onevalue "select name from users"

    You can iterate over a onelist data source in a template with the list tag.

    multirow

    multirow data sources are not represented by a single Tcl data structure. As such the templating system includes a special API for constructing and manipulating them.

    multirow create cars make model year
    multirow append cars "Toyota" "Camry" "1996"
    multirow append cars "Volvo" "960" "1995"

    The query procedure may be used as a convenient way to store the result of a multi-row, multi-column database query into a multirow data source:

    query name multirow "
      select 
        make, model, year
      from 
        cars"

    You can iterate over a multirow data source in a template with the multiple tag.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/down.gif0000644000175000017500000000165707253523117023623 0ustar frankiefrankieGIF89açÿÿÿÿÿÌÿÿ™ÿÿfÿÿ3ÿÿÿÌÿÿÌÌÿÌ™ÿÌfÿÌ3ÿÌÿ™ÿÿ™Ìÿ™™ÿ™fÿ™3ÿ™ÿfÿÿfÌÿf™ÿffÿf3ÿfÿ3ÿÿ3Ìÿ3™ÿ3fÿ33ÿ3ÿÿÿÌÿ™ÿfÿ3ÿÌÿÿÌÿÌÌÿ™ÌÿfÌÿ3ÌÿÌÌÿÌÌÌÌÌ™ÌÌfÌÌ3ÌÌÌ™ÿÌ™ÌÌ™™Ì™fÌ™3Ì™ÌfÿÌfÌÌf™ÌffÌf3ÌfÌ3ÿÌ3ÌÌ3™Ì3fÌ33Ì3ÌÿÌÌÌ™ÌfÌ3Ì™ÿÿ™ÿÌ™ÿ™™ÿf™ÿ3™ÿ™Ìÿ™Ì̙̙™Ìf™Ì3™Ì™™ÿ™™Ì™™™™™f™™3™™™fÿ™fÌ™f™™ff™f3™f™3ÿ™3Ì™3™™3f™33™3™ÿ™Ì™™™f™3™fÿÿfÿÌfÿ™fÿffÿ3fÿfÌÿfÌÌfÌ™fÌffÌ3fÌf™ÿf™Ìf™™f™ff™3f™ffÿffÌff™fffff3fff3ÿf3Ìf3™f3ff33f3fÿfÌf™fff3f3ÿÿ3ÿÌ3ÿ™3ÿf3ÿ33ÿ3Ìÿ3ÌÌ3Ì™3Ìf3Ì33Ì3™ÿ3™Ì3™™3™f3™33™3fÿ3fÌ3f™3ff3f33f33ÿ33Ì33™33f333333ÿ3Ì3™3f333ÿÿÿÌÿ™ÿfÿ3ÿÌÿÌÌÌ™ÌfÌ3Ì™ÿ™Ì™™™f™3™fÿfÌf™fff3f3ÿ3Ì3™3f333ÿÌ™f3ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ÿ NETSCAPE2.0!þMade with GIMP!ù ÿ,)ÿ ¼&°à?‚&T˜¡A‡#^#Hq¢E‹/Ô¸ÑaF  !ù ÿ,)ÿ ¼&°à?‚&T˜¡A‡#^#Hq¢E‹/Ô¸ÑaF  ;openacs-5.7.0/packages/acs-templating/www/doc/guide/index.html0000644000175000017500000001715210215351000024135 0ustar frankiefrankie Templating System User Guide: Overview

    Overview

    Templating System : Developer Guide : User Guide

    This document provides a brief introduction to the design of the templating system and the process of building dynamic pages with the templating system.

    Introduction

    The templating system solves a clear business need: providing a system for efficient collaboration between designers and developers on building a web site. Writing a dynamic web page requires writing application logic that retrieves data from a database and HTML markup that presents this data in a readable form for the user. In practice on production sites, this requires collaboration between designers sensitive to issues of usability and the user experience and developers who are sensitive to programming and performance requirements. Without a templating system, a single script containing the application logic and presentation markup is often authored by both a designer and a developer simultaneously. This is inefficient, error-prone, and difficult to maintain, as multiple people with different purposes in mind must change the same file. To solve this problem, the ACS Templating System, separates the responsibilities of writing the page into separate application logic and presentation layers.

    How the Templating System Works

    This separation is achieved through utilization of the Model-View-Controller (MVC) pattern. The MVC pattern is a classic design pattern that identifies clear roles for components in GUI application with persistent data originally developed for SmallTalk-80 by Steve Burbeck. The model represents the object, its data, and methods for updating the data. The view provides a user a UI to see and manipulate the data in the model. The controller provides the system necessary to connect the model and the view to the user's requests. This diagram summarizes how the process flow of the templating system using the MVC framework. The filename dynamic-page is simply an example.

    The model in the templating system is the representation in the database of the ACS Objects and their associated PL/SQL package methods. The view is the ADP template that formats the datasources retrieved through the controller into a presentation for a user. The controller is the combination of the Request Processor and the application logic pages implemented as .tcl scripts that prepare data sources for the templating system.

    This framework permits a clear separation between the logic that retrieves data from the database and the markup that prepares the data for display. The designer can focus on presentation and usability issues and need only write HTML markup. The developer can focus on the programming necessary to retrieve the data for the designer and does not need to write HTML markup. These tasks are separated into separate files so that the two tasks do not interfere with each other.

    The design of the templating system makes it easier to include reusable presentation components as included templates and master templates, as explained in "Composite Page". Moreover, the ACS Core pages are templated which enables users of the ACS who want to customize their look and feel to update a site-wide master or the individual templates without touching the application logic. If a bug is fixed in the application logic, the application logic script can be replaced without affecting the template.

    The rest of this document explains the steps necessary to write a templated page.

    Choose the data you wish to present

    The first step in building a dynamic page is to decide, at least to a first approximation, on the data you wish to present to the user. For example, a site that allows users to manage their car maintenance records might want to present the following data on the user's home page:

    • The user's name.
    • The user's city of residence.
    • A list of the user's cars, showing the year, make, and model.
    • A list of messages or alerts related to the user's cars.
    • A list of local events or special offers from mechanics or dealers.

    Note that our definition of data encompasses everything that is unique to a particular user's experience. It does not include text or other layout features that will appear the same for all users.

    Each of the items in the above list constitutes a data source which the system merges with a template to produce the finished page. The publisher typically describes the data to present on each page as part of the site specification.

    Implement the Data Sources

    Once the publishing team has described the data to present on a page, the developer writes a Tcl script to implement the data sources. The Tcl script should be located under the page root at the URL of the finished page. For example, a dynamic page that will be located at http://yoursite.com/cars.acs requires a Tcl script located on the server at /web/yoursite/www/cars.tcl (or wherever your pages happen to be located).

    In addition to setting data sources, the Tcl script may perform any other required tasks, such as checking permissions, performing database transactions or sending email. It may also redirect to another URL if necessary. The Tcl script may optionally use logic to change which page is being delivered, specified by ad_return_template <filename>. If no filename is supplied, ad_return_template does nothing. If the page as defined after the last call to ad_return_template differs from what it was at the beginning of the page, its datasource preparation script is run in the same scope, in fact accumulating datasources. By default the templating system looks for a file with the same name as the Tcl script, but for the template with the extension .adp.

    Document the Data Sources

    The developer should include comments in the Tcl code documenting each data source. A templating system specifies recognizes special documentation directives that allow the comments to be extracted from the code and accessed by the designer or publisher for reference.

    Write the Template

    The final step is to write a template specifying the layout of the page. Template files must have the adp extension. By default the system looks for the template at the same location as the associated Tcl script, such as /web/yoursite/www/cars.adp.

    The layout is mostly HTML, with a small number of additional custom tags to control the presentation of dynamic data on the page. In most cases, the initial draft of the template will be written by the developer in the course of testing the Tcl script. The designer may then enhance the layout as required.


    docs@openacs.org openacs-5.7.0/packages/acs-templating/www/doc/guide/document.html0000644000175000017500000000543107435251760024667 0ustar frankiefrankie Templating System User Guide: Documenting Data Sources

    Documenting Data Sources

    Templating System : Developer Guide : User Guide

    Effective coordination between the developer and designer is one of the major challenges of any publishing team. The templating system provides a set of simple documentation directives so that developer comments on data sources can be extracted from Tcl scripts and summarized for non-technical members of the publishing team automatically.

    To take advantage of this capability, the developer must structure comments on a datasource in the following way:

      # @datasource cars multirow
      # The cars owned by a user.
      # @column make The make of the car, i.e. Toyota
      # @column model The model of the car, i.e. Camry
      # @column year The year of manufacture
       
      # @datasource name onevalue
      # the name of the user
      
      # @data_input add_entry form
      # a form for adding entries to user's address book 
      # @input first_names text 
      # entry subject's first and middle names
      # @input last_name text
      # @input title text form of address for entry subject
      # @input birthday date birthdate w/ "MONTH DD YYYY" format
      # @input gender radio
      # either "m" for male or "f" for female
        

    A few formatting guidelines:

    • all datasources (onevalues, onelists, multilists, multirows) are documented with the datasource directive, their name, the type of datasource, and then necessary comments:
    • # @datasource name <type of datasource> comments
    • multirow datasources are followed with a series of column directives, column names, and associated explanations:
    • # @column name comments
    • forms are documented with the data_input directive, and are also followed with a series of input directives with the name and type of input widgets, and necessary comments:
    • # @data_input name form comments # @input name <type of form entry> comments
      Possible form entry types include text (or textentry), date, checkbox, radio, select, multiselect and textbox

    Once the templates have been enabled, the designer can simply visit the URL from which the page will be served, substituting acs with the dat extension.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/components.html0000644000175000017500000000312207253523117025225 0ustar frankiefrankie Templating System User Guide: Building Reusable Template Components

    Building Reusable Template Components

    Templating System : Developer Guide : User Guide

    Most page layouts can be separated into smaller components, many of which may appear in different contexts throughout a site. Examples include:

    • A box or section of the page listing contextual links related to the contents of the page.
    • A list of comments on the contents of the page.
    • A search box, user poll, or other small embedded form.
    • Reports and other administrative pages, where the employee may wish to assemble multiple panels of information on a single page.
    • Many popular portal sites allow users to customize their home pages by choosing and arranging a set of small layout components within a table grid.

    The templating system makes it easy to build reusable components for any of the above scenarios. The basic process is to build a container template, which delineates the skeletal layout of the page. Component templates may then be placed in the container template with the include tag. The container may pass arguments to the components as needed for personalization or any other purpose.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/master.html0000644000175000017500000001252507253523117024342 0ustar frankiefrankie Templating System User Guide: Using Master Templates

    Using Master Templates

    Templating System : Developer Guide : User Guide

    Master templates dramatically simplify the task of maintaining a consistent look and feel across all the pages of a site (or section of a site). This document gives a brief overview of how to implement a master template.

    Design a Content Frame

    Most web pages are laid out with a central content area where the actual unique content of the page is displayed. Surrounding the content area is a frame with common elements that are consistent from page to page:

    LogoAd Banner
    Navigation/Context Bar
    Section
    Links

     

     

    CONTENT
    AREA

     

     

    Footer

    Most sites use an HTML table to delineate the content area within the frame, allowing for the inclusion of a sidebar along with a header and footer. Sites that opt for a simpler layout may only have a header above and a footer below the content area.

    The master template is typically highly dynamic. Menus, context bars and other navigational controls must change depending on the section of the site the user is browsing. A "Related Links" box would have to reflect the specific contents of the page. The master template may also be personalized for registered users to include their name and access to restricted areas of the site. Special formatting preferences may also be applied for registered users.

    Write the Master Template

    A master template to implement the page layout shown above would have this basic structure:

    <html><body><table width=100% cellspacing=0 cellpadding=0 border=0>
    
    <tr>
      <td><!-- LOGO --></td>
      <td colspan=2><!-- AD BANNER --></td>
    </tr>
    
    <tr><td colspan=3><!-- NAVIGATION/CONTEXT BAR --></td></tr>
    
    <tr>
      <td><!-- SECTION LINKS --></td>
      <td colspan=2>
        <!-- CONTENT -->
        <slave>
      </td>
    </tr>
    
    <tr><td colspan=3><!-- FOOTER --></td></tr>
    
    </table></body></html>

    The only special feature of this master template is the slave tag, which marks the location of the content area. Note that the content is inserted into the master template as a single passage of HTML or plain text. The master template should always frame the content area within a td tag when using a table to specify the overall layout of the page. Page layouts that do not rely on tables often use hr tags to demarcate the content area from the header and footer.

    Write the Page Template(s)

    A page template must include a master tag to specify that its output should be enclosed in a master template:

    <master src="/templates/master">
    
    <!--Begin layout of page content-->
    <h3>@title@</h3>
    <p>by @name@</p>
    <p><b>@byline@</b>: @text</p>
    ...

    The master tag may be included anywhere in the body of the page template, although usually the top of the file is the best location for it.

    Adding Dynamic Elements to the Master Template

    The master template may be associated with its own Tcl script, which may set data sources to support dynamic elements outside the main content area. For example, you might wish to include the user's name on every page to indicate that the site has been personalized. The Tcl script associated with the master template would include code like this:

    set user_name [your_procedure_to_get_the_current_user_name]

    The template would have a section like this:

    <if @user_name@ nil>
      <a href="/register.acs">Register Now!</a>
    </if>
    <else>
      @user_name@ (<a href="/signout.acs">Sign Out</a>)
    </else>

    Passing Property Values from the Page Template to Master Template

    As mentioned above, in many cases the dynamic elements of the master template depend on whatever is appearing in the content area for a particular request. The property tag may be used in the page template to specify values that should be passed to the master template:

    <master src="/templates/master">
    <property name="title">@title@</property>
    
    <!--Begin layout of page content-->
    ...

    In this case, the property tag establishes title as a data source for the master template. Properties are set as regular Tcl variables prior to executing the Tcl script associated with the master template. This allows the page template to pass an ID which the Tcl script associated with the master template may use to query for additional information.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/skins.html0000644000175000017500000000100107253523117024161 0ustar frankiefrankie Templating System User Guide: Presenting Data in Multiple Styles and Formats

    Presenting Data in Multiple Styles and Formats

    Templating System : Developer Guide : User Guide

    (Discussion of how to do cobranding, syndication of data in XML, etc.).


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/form-widgets.html0000644000175000017500000000171011043666760025454 0ustar frankiefrankie Templating System User Guide: Custom Form Widgets

    Custom Form Widgets

    Templating System : Developer Guide : User Guide

    Form widgets are implemented as tcl procs that output the html to generate the form element. The tcl proc must be in the template::widget namespace. So the proc for the search widget is called template::widget::search. The code that generates the built in widgets is in packages/acs-templating/tcl/widget-procs.tcl.

    If the data from the form widget needs to be formatted or processed a tcl proc is created in the template::data::transform namespace. For example, templatete::data::transform::search. This takes the input from the user and processes it to be returned to the tcl code handling the form.


    openacs-5.7.0/packages/acs-templating/www/doc/guide/form-process.html0000644000175000017500000000375507572172151025475 0ustar frankiefrankie Templating System User Guide: Validating and Processing Form Submissions

    Validating and Processing Form Submissions

    Templating System : User Guide

    Important Note: The ad_form function has been written to be a more consistent, easier way to create and manage dynamic forms. Behind the scenes it uses the templating system's form builder, but it hides much of its complexity. You should definitely look at it and at the pages that use it in the survey package.

    The templating system provides a simple infrastructure for validating form submissions. The typical life-cycle of a form is as follows:

    1. The user makes the initial request for a page containing a form. The code associated with the page creates the form (with the form create command) and populates it with elements.
    2. The developer may use the form is_request command to encapsulate any special initialization (for example, setting a primary key value for an Add form, or retrieving current values for an Edit form).
    3. The formtemplate tag is used to enclose the form template. This tag is responsible for generating the appropriate HTML FORM tag in the final output. The formtemplate tag also embeds a special hidden variable in the form for the purpose of identifying incoming submissions.
    4. By default, the formtemplate tag sets the ACTION attribute of the FORM tag to the same URL as that of the form itself. The submission is therefor processed within the framework of the same code that was used to create the form.

    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/wizard-procs-doc.html0000644000175000017500000001720207736270506026242 0ustar frankiefrankie Using the Wizard

    Overview Of How To Make A Wizard

    1. Create a wizard file (ex. wizard.tcl) that contains the "template::wizard create" code.
      ex.
             template::wizard create -action "wizard" -name my_wizard -params {
                my_param1 my_param2
             } -steps {
      	  1 -label "Step 1" -url "step1"
      	  2 -label "Step 2" -url "step2"	
                3 -label "Step 3" -url "step3"
             }
          
      • action - the url where the wizard will always submit, normally its the same as your current wizard file. Has no effect for subwizards.
      • name - use to distinguish between the different wizards, since you can have 1 or more subwizard. name must be no spaces, alpanumeric similar to normal tcl variable naming convention
      • params - are used to keep values that you would like to pass on to the other steps
      • steps - are use to define what includes to use for each step of the wizard
    2. Add the "template::wizard get_current_step" on wizard.tcl. Make sure that you call any "template::wizard set_param" if needed before calling get_current_step. get_current_step will redirect to the wizard -action properly setting all -params value and its other needed http state vars

      Note: the wizard will rewrite the url always. Only self submitting forms are preserved. Once the form is finished processing the wizard will take over and rewrite the url.

    3. Create the wizard template file (ex. wizard.adp). This file will include the file based current step of the wizard
      ex.
             <include src="@wizard:current_url@">
          
    4. Create the individual steps, these are just normal tcl and/or adp files. So make a step1.tcl, step1.adp, step2.tcl, step2.adp, step3.tcl and step3.adp. Normally this files are self submitting forms
    5. Add "template:wizard forward" on each step (eg. step1.tcl, step2.tcl, step3.tcl) , usually the code where the step is processed and successful.
    6. On each step add the wizard buttons on the .tcl files. Ex. step1.tcl will include
          template::wizard submit myform -buttons {back next}
          
      On the last step you may want to use the following on step3.tcl
          template::wizard submit myform -buttons {back next}
          
      The following values are acceptable for the buttons: back, next and finish. Back buttons are not rendered if the step is the first step, like wise next buttons are not displayed if its the last step. Finish can appear on any step and will finish the current wizard even if not all steps are done.

    Tips And How To Use The Wizard

    • How do you display the steps in the wizard to serve as an indicator?

      On your adp file do the following:
             <multiple name="wizard">
                <if "@wizard.id@" eq "wizard:current_id">
                   @wizard.label@ - you are at this step <br>
                </if>
                <else>
                   @wizard.label@ <br>
                </else>
             </multiple>
          
    • How do you set the value of a wizard param?

      Use "template::wizard set_param myparam_name" to set it. Normally you place this in the steps of the wizard where the form has been processed. A param is normally used when you want to reuse a value across the steps.

      Note: if you are to use "template::wizard set_param" on a wizard file ex. (wizard.tcl). Make sure to do it before "template::wizard get_current_step". So when "template::wizard get_current_step" redirects it will properly set the correct values of the param to the new value.

    • How do you get the value of a wizard param?

      For example you wizard was created this way:
                 template::wizard create -action "wizard" -name my_wizard -params {
                    my_param1 my_param2
                 } -steps {
                    1 -label "Step 1" -url "step1"
                    2 -label "Step 2" -url "step2"	
                    3 -label "Step 3" -url "step3"
                 }
          
      You can access my_param1 and/or my_param2 on any step1.tcl, step2.tcl, or step3.tcl by using "ad_page_contract" or "template::wizard get_param"
      ex.
          ad_page_contract {
             gets the wizard params
          } {
             my_param1
             my_param2
          }
          
      or
          set my_param1 [template::wizard get_param my_param1]
          set my_param2 [template::wizard get_param my_param2]
          
      Note: "template::wizard get_param" has the advantage of getting the param value during the response time. What does this mean? It will properly get the current value of the param which was set by "template::wizard set_param", while ad_page_contract will not pick that up since it will get what is the request http var value. This is because "template::wizard get_param" gets the value from the tcl var while ad_page_contract gets the value from the http var. So while processing in tcl that value may change.
    • How can you get the url of a wizard that is not your current step?

      You can use the following on your wizard.adp
             <multiple name="wizard">
                   <a href="[template::wizard get_forward_url @wizard.id@">
                   @wizard.label@ <br>
                   </a>
             </multiple>
         
      Note: that this is not a very wise thing to do especially if the latter steps will depend on the inputs from the earlier steps. You can however do checking on each step.
    • How do you know if a step is already visited or not?

      There are situations where in you would like to build a wizard when you can go back several steps and jump back to the step furthest you have been.

      On your wizard.adp you can do the following

             <multiple name="wizard">
                <if "@wizard.id@" le "wizard:visited_step">
                   <a href="[template::wizard get_forward_url @wizard.id@">
                   @wizard.label@ <br>
                   </a>
                </if>
                <else>
                   @wizard.label@ <br>
                </else>
             </multiple>
         
      Note: that this is not a very wise thing to do especially if the latter steps will depend on the inputs from the earlier steps. You can however do checking on each step.
    • Can I use a wizard as a step?

      Yes you can use another wizard a step of a wizard. This will act as a subwizard.

      Note: That visited steps will loose its value when moving from one subwizard to another subwizard in the same level. In order to preserve this you must call "template::wizard load_last_visited_step -key $yourkey" before "template::wizard get_current_step", after "get_current_step" call "template::wizard save_last_visited_step -key $yourkey"

      Also the wizard params name is present across the curent wizards being used, so the developer has to be aware not to use the same names with different purpose. For example on main wizard with have a param called "name" for the user name. And on on sub wizard we have the param again called "name" but used for the file name.

    openacs-5.7.0/packages/acs-templating/www/doc/guide/composite.html0000644000175000017500000002541507253523117025053 0ustar frankiefrankie Templating System User Guide: Composite Page

    Assembling a Page from Components

    Templating System : Developer Guide : User Guide : Composite

    A typical page served to a browser is made up from several component pages. The idea is to have reusable parts (widgets, skins), a bit like in a programming language where code that may be used more than once makes up a procedure. The complete page may have the following structure.

    master
    top
    root (main)

     
    widget

    bottom

    The "root" page includes the "widget" and wraps itself in the "master". That page in turn includes the "top" and "bottom".

    Overall structure

    The parts are put together with the <include> tag (in the diagram below, black links going right) and the <master> tag (brown link going left); and the concept is similar to a procedure call. The structure of the composite page looks like this as a graph.

    root
     code   template 
    master  code   template   code   template  widget
     code   template   code   template 
    topbottom

    Any (sub)page can have 0 or 1 master and 0 or more included pages. Each page has its own separate scope for variables. Arguments can be passed to dependent pages as attributes to <inlcude>, or as properties to <master>. The directed graph of pages will often be be acyclic, as in the example, but this is not required.

    Evaluation Order

    Sometimes it is of interest in which order the different parts are evaluated. The "code" always runs first, followed by the template. The <inlcude> tag causes the subpage to be evaluated at this point of the template, and the rest of the including template is evaluated after that's done. This is like a procedure call. In contrast, the <master> tag is deferred until the whole slave page ("root" in the example) is done. For our example, the following order results.

    root.tcl
    root.adp (beginning and middle)
      widget.tcl
    widget.adp
    root.adp (end)
      master.tcl
    master.adp (beginning)
      top.tcl
    top.adp
    master.adp (middle, containing <slave> tag)
      bottom.tcl
    bottom.adp
    master.adp (end)

    Here we assume the ACS/Tcl situation, where the "code" is a tcl script in a .tcl file. The template is a .adp file.

    Variants of Page Nodes

    The graph of the overall structure has five nodes, shown as a code/template pair. This is the standard situation, where the "code" part sets up datasources and the template uses them. In some situations, the following facility can help to reduce duplication or to handle special situations more effectively.

    The "code" part can divert to another page by calling template::set_file to modify the file name stub of the page being processed. For convenience, ad_return_template can be used with the same effect; it is a wrapper for template::set_file, and it supplies the current file as the reference path. Neither affects the flow of control; the script runs to completion. If at the end the name is changed, the template of the original page is not used; instead the new page is processed, code first, then template. As that page's code can call set_file again, we get the following picure.

    code A (template A ignored)
    code B (template B ignored)
    ...
    code Z template Z

    This assumes page "A" was originally wanted. An arrow () exits from code which calls template::set_file (directly or through ad_return_template). All scripts and the template are executed in the same scope, i.e., they share variables.

    Furthermore either of the final files can be omitted if it is not needed, giving three basic possibilities.

    a) code template
     
    b) (no code) template
     
    c) code (no template)

    It is an error to omit both parts; this is a special case intended to speed up debugging.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/templating.jpg0000644000175000017500000033735607253523117025043 0ustar frankiefrankieÿØÿàJFIF``ÿÛ„      ÿÀð@!ÿÄ¢  }!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?ýü¢€ (¢€ (¢€ ñÿ¾~Îß 4ÿübñ_ü!þÕ5X´K[ÏìËýCÍ¿’§H¼»8ef+i›qP£f €@=CIÕ´­{ºf»¡jZ~µ¢kVßéú……Â\Ú_ÚL‚Hf†T%$‰Ñ••Ô•e ‚A¯¼ý¤> X~ÛZOìå?´÷øÑ­Z5忆­í.îdŽ5¶–ô¬÷DÖÖÒý–œE4±Èc10R%Œ¸‡Æ/ß¿gÿCâ/Œ?¼?àm>ïwØâ»‘æ¿ÔöI R}ŽÆ{«¯-® 2y?–®ö¦XyÃ?ÛãöBø»ñNÓÁ>øÛáû¿j>ZØÙê¶–‡ý¡4“GVöÒj6ðG=Ì’Í¥¼LÒ¾IT!X€ø£ñGÀŸ¾ëŸþ%ëŸðx#Ã_eþÒÔ¾Åuyöo´\Eiîm£’fÝ4ñ'ʇ²p ‘òü=öÿ¢çÿ–g‰ÿù_@oø[ÅžñÇ,S¶ù$‡ìö;£”Æ»cøCà>“ªëŸðSØ{ö‡ñ^™¨i¾1ý©|kñÓÇÏm«[»jz6€tHm4M,ßJ[Û,àZ>È¢ÞJ‡s€}_û0|;Ð~;ÿÁG?jÿÚKâÖ•áÿx›á×Å[Ï…°Ôle»¶ðE‡†^)#»°[™¥Ž+›‰e·¸gŽ(Úˆîd‰]ȃëÿÚ?öpøqûKþÎ:ÿ¼qáÿÜj×Uõ§†üIw¦-Õÿ„oçThîìÜ0|<Õ`ÿ‚¹ÿÁ>¯<à}B‡¿ m>%Ø_O¢èκ7…m%Ð-ítøehSȳ‰ÌbQ¶+Ø€ãåþ!ðïÇØÏöáøµñSáWÂ_|zýœ¾=j¶~'ñO…¼1¨\Ëâ?øçŠ FþÃNšY´~Ûö‰®^;tBLqG#Ù[Ù#Ì|Cý§ÿhïŽþÕ>þÍ¿²Çÿ‡^&ñ¦•w§_øû⾟'ì<mÿøñ÷þü%ñe~?üÿ„_ì?òS|!ÿÿö·Ú|ÿøñýôžw•öÞýÝžl=wñôPEPEPEPEP_?ÿÃFø'Ä»ø9¦xƒö‰š/šê_‡i—ºU’eÖï.ítr… -b/Mîˈ¥æePìßµ6»þ—ý³û?ü+ò¿sý“ý®xÿíù¾Ñý¡ö½ÊÝ»gÙþÇ&ß+žþo— ÿ âßúV£ûSü_±Ô.{uo¡x{ÁºU¼ÍË¥”7š%ÝÔVÊĈ’âîêU@¢Iæpd`þ§á×ý ÿðû|CÿåÍð˳íßï#µÇ޵[xz‹x¯õÉ.V.ën’,JòJáË#0ÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2ÇìûgûÏ |.ðÿÃ@ü²jŸãÀº­Ä=M¼·ú–—RÛ3v·y&xâr…â”ÿ†iøuÿCÇÿü>ßÿùs@ü)OÛ£èÿ´ÿÇýH·ý݇“àÝKì6ËÄPý¯QÐno®v Uó®î'¸“¥–Y ;Ù¿µ6‘ÿøL¿gÿˆgÿ˜ü!ºçƒþß»åÿ¿ö¶¯ö]™óäqæy~Wî¼Ï: þÝŸ…?uñ»Á¾ ø#_ºoë76w¾ ¹™>Y5»Y;c)‰-ßYJ–èÜB‘@fó!‹è ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ›ßL¶øçñ¿â‡†|c& >ü#ñŸ…ÿ᳿¸µ´ñ]ìú6›¬Os«´.†öÄÛêéb4©CZH«w%ÒÞyÖéaô…PEPEP_7ßé:Wìç>‡©xLÓô„!ñ‡á­GÁZuºZÚx{SÖ5}*ËQÑa@±[Å%å帾²!uw¾‡ËºK¨µ`¤( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Œ3ø}ã CKñ™ñ+K‚_ jw!ü/â¨âðW…Ý ¼V†iì%Ä× —¶\ŠïÜÅ©Ck¥zü4ƒáoô/^ñÁ]B׋½WY¶–ëÁ¡îÅÊxž:m½´Ó«Ãnš”š}ì„Âθ…$úŠ( Š( Šðý[ã~•yâ­KŸ 4=CãŒt«¹´ÝA4I’-×Ñ9†XµmÿÑ-e·˜Â.l 7Z¤qL³&Ÿ:Wˆ|mð/Šu† ñ׎SÃú߉´Š¿ ßÚ&‰mߢ€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€>ø7ÿ'ûXÿÙUÓõð¥}@?ÿÃ/ü³ý×…¼;â†:yù¤ÒþxÇ_ð.•q7Cq-†‡yik-Ë(Dk‡¥dŽ$.R(ÕOøU¿<7ó|>ý ¼A<ÿ¢Úèÿü;aâ­+N°q"–Ìéš¼÷1…Ž5¹¾ÔîÙÓÍ3­ÄÎ'Œÿ„sö¦ÿ¢Éû?ÿá›×?ù¬£þ?Ú›þˆßìÿÿ‡“\ÿæN€øHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“£þÏÚ›þ‹'ìÿÿ†o\ÿæ²€øV¿ xïHõú¾$x¯Åš ö9O´éZ¶£scs±ÂÈžt/åȑțd@=ÃIÒt­ºf…¡iš~‹¢h¶Øiú}…º[ZXZB‚8a†#‰UU¯ý¥¿äÝ|9ÿeWá7þ¦ú}EPEPYòjÚT>*²Ð¥Ô´øµ½FÒæþÓO{„[««Kg†;‰£„ïOujŽê £Ob ®@µm*o^hPêZ|ºÞ›imw§¥Â5Õ­¥ËͼÒBôŠWµºDv] ”)&6Á¤êÚV½á]3]е-?ZÑ5«HoôýBÂá.m/í&A$3C*’DèÊÊêJ²A ЦjÚVµ§Iy£jZ~­g ÝÝ„“ÙÜ$ñ¥Õ¬òZÝBY Xn!–üÉ$nŒ)Ó5m+ZÓ¤¼Ñµ-?V³†îîÂIìîxÒêÖy-n¡,„,7Ë ˆ~d’7F”€¡EPEPEP|Z¶•7Н4(u->]oM´¶¿»ÓÒáêÖÒåæŽÞi!zE+ÚÝ";®ÐJ“cŸñ'Ä/x3NÖï<_ãøRÏÃ6–7ú¼úƳkc•i{<–¶s\´Î¢§¸‚hbwÚ²I¢–e sþ øÝð_âWŠ®4/‡?~øÿ[´´kùôÿ ø«NÕn¡´WHÚg†ÞWuˆ<±!r6†‘rÃ>¦jÚVµ§Iy£jZ~­g ÝÝ„“ÙÜ$ñ¥Õ¬òZÝBY Xn!–üÉ$nŒ)BŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Ÿþ ÿÉÅ~Ö?öUtßýAü)_@PEPEPEóÿí-ÿ&ëáÏû*¿ ¿õ7Шè (¢€ (¢€ ùÿáŸüNÿm?ÚSÅ7_»ÔhŠä°ñWÆËËü ðM¯ÄˆðxûJñV«wãÿü4¼Ö¼U :õ…˜±›CƒN½ŽÃR2êQC¨\\Ø,PÍcyn,¬fº…l3ãø¡ñsÅšWÂï è^$ñ‡‚›XøÁwàñŸ‰>Ë£êÞ/ðÔ~ ÔµÃ~šF©in-o’â%¶ Ù^óN{jm%}4{Ç cÇ~ý‘4OøBücåøØø¯áï†#ñ»¤Úßý«ûGÄšV•u=帶†O:©üÔ·û/úÆòZÙ‚4~A㟈:ï…¾6EðKSø«ñþÓþO éž,¼ñ¯„þEâïøŠmRÿU¶‚Öétß]išuµ´zdl[³,%‹ì—?lè4‰ßþ(Úü-ð+Ëâƒþ ñΕã}oTñ >m;W6Ö,t˜%±Ò5Ëy¿³¿µ´­5·Ðݵµ¯™l²Ëôÿ…¾ üXÒ?iKx“Çÿð–ÚØþÐø ï[C°±šÿÃcáƒxŽn$ÛöŸí*âiá‰%ã¶¶u´ˆñÇÇøcÆÿ|3sªx‚ ]SãUÃUм+?ˆu_ éOà+\Ke¥ÙZÏ5ýËMúÄÓE:[½âÏ4wÖ­k!¥üQø§{ð‹ân‡á?ø[þ*ƒÂ?ð‰ÝYxóÅ ¯¼;â9´­KR–%¶—q¥ÚA©jZNmq}lÖ–“› f²»š) ðŸüE»Ô|kû.¶¦~ÐõI´¿Š¿nñW€4ï xÃLû_‹¬-RI-ot[HåÓZQÅœ£M\Þi·h÷W‰láôø«Ç~ø»â ?ƾ/ü>Óü)ý›…õˆ~Zë¾ñ•›i$úÏ‹5+má±Î¨uH¯=CEH¬íb•ÉnäúâŠo<ð'\ñ}áý3Pµû-½­Î³ åÕ´S\\El…,ìÔÝj;¦ßO·)-õÁ†Ò9ayÄ©ó‡Âˆ^7?¶†“à[Íoã‹ü âÿx‡Ä–:ïÅ h>ºžëI¾Ñ­6i¶6VZv¡ou‹…¸µŒm#Ci%£L0§øsþR›ñ“þÉWÃOý;øÎ¾pý¢o.4ßÚk⦡g¤êõÝ…§ìÅq™`öéu¨ÈŸ5vX!k‰b€K!Ë,q†a½ÑrÀÔ5Ïx‹ãÆÏü/¸øMñàω¼3ªè¿âñ‹¯<€¢€ (¢€ (¯ðï…µß ~Ù?uk; ø âf•¤krË Ñ7Ù|Yb­¦ßKp²0™~ץŠEÀ$€dÝ´‚ÞYU¯; /éV|KñAµ¿xCðÝÜèm#´Ò®u;«wB³ë7AË;)T„*¡ _ø/ámwAð'‰µÿXgøÛâ_Šõok0´ÑI5¼2È-t{[5²ÜÙèvz=„ßfg‰¥³‘Ä·,íq0~­ð^ôø«R¾ðƉÿ´ÝjîmNÿC𽿆®tÉõ9ÜÉux‘êÚUëÛËpçÍ™-Þ(d˜ËpÑ‹‹‰¦ÐÔ~YÅàOh^ñÇÄ„Ÿð}­b¼ðÝåäÚ‚]È'¼kèõ‹kë{Û™îT\É}*·ñ/‡üiã…Þ2ŽÑ4ËŸxYt¶ºÔôÄw–;;¸u+;ËIâŽi$–x Öí-À†H’êé'ÏÔ~ xTøÚW„oüAðãYðÚÿ±àGvù¼†ˆ¼ƒÁ¿³®£oª|X‡ZñWÄ +V?m¼wàÏié×úëÜ?„4­öÿ˹‚{ó]µË?²Ëf¶ðG&-mí£ŽÑ¢ïôoÙ׺7ƒ¼Ygÿ WÄ WÄ~+ñ\^;ÿ„»QÔàŸ]ѼLš]¦•öû | ¡³ÃZù-fc¹¹³û?ötŸb^ƒNø=gcàOZ\xãâ§ãoýµËygmâ6k) ºr¡µ¶†Æ;kW,RÅm”¦[£qop×·¦äÔ?fí?[ð_‰­üCñKâ~½ã]øRá¼mp¾‡YÓãðÞ«ýµ£Áúdzg•ûÜÊL¶RI º•$wE…bÐñOÀY|c£ßhšïÆO‹÷^ñ6•‘âÿ4ÚØxÆj¶W†áŸMk?í–È#š="m>%f’h#·žY&pPñß‚t¯ˆ? î¼1«\j1=ÞŸ©ÙßX:%Ö—©é÷pßé÷ùˆñ4¶÷–¶× “G,.Ñ–)bg¼ÿÂ_cð÷ÇÝ7âwˆ>'|Oø“ã+Ãú¯…í®|Is¥Åi™s§Ýȉc¦ØÚZ$«6™¤K4‹3¤Ï:Ej¶À~GâŸ[ø—Ãþ4ñ‡ÂïGhšeψ<,º[]jzb;ËÜ:•å¤ñG4’K ¼kv–àC$Iut“óëðÃ×^ žËÄ^%ñ‡‹¼I¨øƒÂþ!Õ<[ªI`ºÎ©'‡µX5m.ÕþÏk¤1MlìÖ¶ðG‰îå]]Os  xÁ:WˆüUá5Æ¡£x“Â~v«é®‘Ý-¤¯½°”º:McvÆ“Á"²îŽ ãò®­­n ñý?ö~×ô õ¸|!ûF|oð~‰­xƒ\ñ Ñì,|siau«j7¥ÚC%æ=ÁˆÝ^NÊ%šFU!w}•Ä~*¼ÔVÔ&³º´¶·‹Lt·–rDó3Ï,Bs,ÂhÑÄ’¼am¡òÒ62´ºQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@?üÿ“Šý¬ìªé¿úƒøR¾€ ?ât¯†¿¼qñ]·Ô.ôOxSñ&¡‚#ÝMicm%Ô© »¢4¥"`¡±²ŽG—ÿÂôÕ´¯ø˜x÷àGÅÿ†>µùµOk·~ºÒ´(z}¢ðišÕÝÔVÊÅ|ÛEn…¦á·ŠY£ú¹ûŸè6ôoÜ_y~&ñ•©ëv~L§í|ÖP]Ëæò×Ë—S±]¬Á›Îʆå@: ãüã]+ÇÞ ½×tk}BÚÎÃÄ!ð܉xˆ’­U»Ò.B;)®,ehÉ!Œl…•”PŠ( ¾ý¥¿äÝ|9ÿeWá7þ¦ú}EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE|ÿðoþN+ö±ÿ²«¦ÿêáJú€>ý¬å_´·ý’¯é¢ê½ƒÅ>)Ð|àKïx’ûû?HÓü¥wXe¸šy¥‘a‚ÞÞ•¦¸¹ži"‚xQåšYcŠ4yT€|áφZî½ð³àÇÀO|2øã|%ø+àüI¤|M¿Šÿ¾ ¿»†ïN]BÇH¶´¸\Ô’]ú9D÷v‹0ÃÔP¾ñÿ³¿ƒ¼ãŸÚösñ½£|/øw xãšxÄV:¬ºtVšÄ-* MH÷&ÖÆÊÞyWNŽ9ä[H&) ›IfÏÔ´ß;á×Àöžø?à«ßˆ¿>Ï¢xãY“ûgâÇÄk={\ÓYâŸSH4ôÑî[I’å.të?í;Cd×VVâÒÊÕ7ôøqkûþÑß¼+aáûÏÚÀß>/Áá¯C2Þø@ñ`ñF¬Ú‘bìÏ5·Ú¦¹ÓÔi‚øê’$–×R˜\z‡Äÿ é_>7ü[¹Õ¼ð?ÄøSwo¤ê¾1øÙkÚgÃæF±ÖîF“áÑo³XËkl÷7Ój¶w&i%ó|ë]:Êçþð«ñoàÀ_k¾øûMëwß¾ͨxwâçˆ\]xVê[k©¥Ö`ߥê¯$ºÃÈÑO+GlÎÚY’è®Û` ›‹ÏßþÙhß >ü`øE«üðw|á¿~-¼¶ò¦»šùoîÄo¦k «êPZ6ƒ ÍÌòI-—Û# /üMg3ý_û8ßx‡Rý|1{â]sOñÜ÷zɱÔ,5+ýVÒ]jwcIXu+ëkkR(ôágêRE›åAv$¸YÄò€{…|ÿûKɺøsþʯÂoýMô*úŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠùÿàßüœWícÿeWMÿÔ•ôgêÚN•¯xWRеÝ3OÖ´MjÒk CO¿·K›KûIÇ,3Bऑ:3##¬¤‚5åþýž¾xÇv)ðOÀïƒþñ6—æýWÑ<¥i÷öždm žUÄ0,‰¾)6ÚÃ*ì§‚Et:øMð¯â‡öWü,¿†Ÿþ"aùÿÙ¿ð“øzÇWþÏó¶yÞGÚc+Ìò¢Ý·¼´ÎvŒÂo…z¾±áÍGVøiðÿTÔ<ªÝëº Õ߇¬g›DÕnî…õÕ囼e­îf»U¹’hʻʌKŒÐ}—Á‚úoÄ-[ÅÚwÂ…ö+×®ÖÿSÖ­ü+§E¨j7K{¤³Or°‰%”_[[݇v,'†)s½†„? ¾Û|SÓ|uoðÓáý¿´o¶ýƒÄ1øzÅ5[¶Msqwä݈üèüù¯¯¥—k1îî²Ò¹`_øMð¯ÅôOx§á§ÃÿøÛÃ_fþÈñ«áëÍWJû<Íqoök¹ci¡ò¦w•62ìv,0ÄšÏñÁ‚þ1ð¯†4/|!ø_â­Á6Ÿ`ðxWN¾´Ð-6E“e в[E²dAWlQŒa~xâW…mô/ˆ¾ðôKK´¿ƒOñ&kªÚCt¨ñ¬É Â:,¡%•¸,Ž3†9ì(¯Ÿÿioù7_ÙUøMÿ©¾…@@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@?üÿ“Šý¬ìªé¿úƒøR¾€ Š( Š( Š+çÿÚ[þM×ßöU~êo¡PÐPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPÍþÔ­¾~Õ_-|i¡¦é¿ük¥ë¾×c°¸ŸF2 FгïoQ Z}ó^ij°¥ÙŠ;£e¬—7x-þ Š( Š( Š+æÿjÚWÆßY|4ð¥§ëv~ ñ¯‡µ¿øŽÎá.tï Ýx{Z´ÕFŽY jóÜiÉ–•¬ ‘înLlÖVÚ€ÒPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP~­¤éZ÷…u- ]Ó4ýkDÖ­&°Ô4ûût¹´¿´™ rÃ4. I£220*ÊH ƒ^ÿ W]ð‡ÍðWâˆ>iöÿ5§„5›(¼OàØþìªYÎÑjVvÑÁ²;{7S±²·0BRßgàü&´v•þŸ¯üø¬iÿëìüñFMK]›wÊŸe¶Õ´}*ÆL9V:þ ±‰<Ù!“?Rý©¾xsNŠOxwã„.Åݦ™umyðÅ÷qÚêw3ÇišßXé÷R½Ô±ÛFö—7Ï#§‘$ÊèÌ¡ÿ [û2Eû­GãÿÁÿêü·Z^»âÍ?GÕtÙ‡oyay,WVw1¶R[{ˆã–'VIJ@ð/Å…?µ?áYüKøñûÈþÒÿ„cÄ6:¿ö¿ÉóþÍ#ù^g•.ÝØÝå¾3´àÐ( ?ñ×Å… ÿ²¿áeüKøðïûsÏþÍÿ„ŸÄ6:Gö‡“³Îò>Ó"y¾_›í¹Ûæ&q¸gÏÿá¬eú9oÙÿÿ‡ÿÉ4äo_„?þ·µ ü_¸ÿ‰®™¦ÛØj¿ |WáŸí>áÊÛ]êºls’ÝݤMöSx÷o__ÿ„ïö‚ÖÿÒ¼-û?xÃú|º’ßâ?Ä{}Uy‡%â‡C±ÖíZØ« W{¸å.²ƒ"Ç$ ü*oüAÿIøçâÿí"›þï…^}3±ÆÜù”ÙÚöK‹Y–åàÓoa(dÒb‘s^á¤é:Vá]3BдÍ?EÑ4[Hl4ý>ÂÝ-­,-!A0à ‘ĈªŠŠª€P…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|ÿûKɺøsþʯÂoýMô*ú¼ÿÇ_ ¾üPþÊÿ…—ðÓáÿÄOì??û7þXêÿÙþvÏ;ÈûLoåyžT[¶ãw–™ÎÑ€?ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF @ð/Âo… ÿµ?áYü4øðïûsÈþÒÿ„cÃÖ:Gö‡“¿ÉóþÍy¾_›.ÝÙÛæ>1¸çÐ(àø(7ìëá_Ÿ³ÿÃøK|UñGÓü7ñÂzRiš§½…ÿöÿˆ4­{›˜e‚U’æÚÒîëì²qå4òäHŽÈ~¿øUðöÏá7ìã࿆Zf½âiÒ­ôM6ÿ[6fý¬-×˵ŠSk·• Ç °‰Y–5.^BîÀEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEóÿí-ÿ&ëáÏû*¿ ¿õ7Шè (¢€ (çÿÚ[þM×ßöU~êo¡WÐQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|ÿûKɺøsþʯÂoýMô*úŠ( Šùÿö–ÿ“uðçý•_„ßú›èUôPEPEPEPEPEPEPEPEPEPEPEPEPø§özøãßx§Æ¿¾øÃÄÚ§•öÍ_[ðn•¨_ÝùQ¬1ù·@Ò>È£Ž5ÜÇ Š£\ÿü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÕâ´ìÉû6è¿´ Íö|ø¤ÝÍñ+á„“ÙøG‚G´ºñŽku d·Å5¼ÒÃ"•ã‘ÑV €{ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#P˜|]ýŽþjß t›_~Í¿âÖâñ¯‚/.ZÏÁz”‡F¶ñ›q«©Â¢:dW¢H²LÑ—ˆ+—ÞŸÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhü_@PEPEPEPEPEPEPEPEPEPEPEP_?þÒßòn¾ÿ²«ð›ÿS} €>€¢€ ù½ßÆÿ~7üPÑt_Š0øE¢|"ñŸ…£ÂÖ ÝÖ¿u>¦ëS]ÝÍ«i÷¨‘*jÖöðÁQ24É5À¸Š+0 …¿á/¾ðÇ„üE§ù^6ÕáaC-Ö›—¥\ÿÂâ|7}p±É+Ímö©®mîa·-?”$o<É7?/íYàŸøUžñ®Ÿáˆ·†/~èß¼Iym˜ŸðxOS†yíoµ8潎Iÿuc¨³C¦-üãì2,™-Äà­ûExWGñßÄÍã¿$ÓþjºF•âß®™z&“ý¡“p—-w,è­m¦°×—r(?c·Ó¯%¸£Ù›ÏPðŸt¯j>0‹F·Ô Ÿƒ|A?†äÔ$Dû«uItöR£°š(.&–Âbv´wvW2†„ää|YñWDý•~0þÑ·_üa¯Eð»Ä/—À7šO‡#ðî¡£xo]ÕìãÓÖh4Øõ8¥{ 9R;“y!Žà¤ÒGu½¬¹úÿÄvïö»øë êÿÿiÿéþ ñ^™¤hšWÄx£J·°“Ãz.¢æ[Ôð¶¨ßik»û¶hä¹ ¨bÄh… }ð›ÄZïŒ?e†ž-ñL~‹ÄÞ(ð®«êé¡]Åy¥%ýÍœS\ )âšhæ¶»ˆ¤I¥VM¤I ! PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEóÿí-ÿ&ëáÏû*¿ ¿õ7Шè (¯›þ"üñn¹¨øÎO†¿´ÿÙüN»³Ôü]m}§kw2]jvZÚAy§ßiÖ“a+ÚØYÛ\"ÜÉ ±Úö(YîÚð>ÏàŠ|-kàÍ_À?|?§ø÷ÂðšZI«øÂ“êÖÕŸ‰µˆu­Fk›mFÍ—R{»+Ih'†Ð3Þ¬`ŠX!³ó ïØwÃמøc§]Þ|/ñ=߃~ø_á~©©øËá…‡‰®†¢¤ëæ‚·w &úS}vò˜µ(£±Ý­¼‹píþ#ð„<5ðÛöŒ¼ñúxƒÅþøßª‹½sFÑjðøÚÇû"Î[Y«Üø_U:Ýõ¤É"I n†vxŒÑ#½½Í¼Þ\,êêÿÙŸã~«ñ‡àÕîŸñCÓüñãáÕßöįE3™<=©‚þDñ¬œµõº¥å¬Ñ¼ð¼rK‹ƒ ½|áð»_ý¤ÿhŸ…Ÿ´~“áoÚþ?‰¾þÒ¾0𦑯 £ë¾W„ôèbK}+첬QœKr’ý¥ËÎ|­¥˜1ÀÿeþÝðôßøfønÏù¥_ð³á#ÿ…-áú ÿe}‡ìyÿ¶¾wþÏ—üUèo¿k¿²ÇÁ_ ÿÃSÿÂQñ7ãíá¿ÿÂyÿ ×B²þÉÐu[9áû/ö^$·›Ê¹·ûO™º9w—½d€v·ìùÿ‡Âº”ºü#OÔu¸­&}>Òÿà‡†ì­.®‚ s\!™á‰Ÿj´‹ ¬ŠKܤпoM+Lÿ‚øköÁø‹á>Ï[Ö-'°ƒÂÚf¨.»¯Å¨\i‹ ›Üé¯k-Û ÛÛ,í‹“2gøsáWü‡âŽþ-ñßí[ðÿö~Õµ³K¼ðËKñE†‰Ù`Ü’^ßÉç}§ÎóĨ³]Df)Ú6T ýž¿h_Œš?í“sû%~Ö–¿âøÇ…m­û@øWÀ¾0ð4²ÝÙˆu» N—M½Îó¾Óç}©’,±ŠÆêS¶5Fô?VÕ´­º–»®êZ~‹¢h¶“_ê…ýÂ[ZXZB†IfšW!#‰Y™Ø…U’¯ÀÞ\x«þ ˆý¸¾.C¤êO…>;üuÔ¼á5¿{µO£]x›E·Fš8eC*ÜZ]BÈÍÑ]ÈÈìúûExs]ø ûdøWöÉð+ø¼7Ø|-ñëÃzU¤Mgá4[…‡Å1à —SÜèí,læ(¦­#XÕímã¸2gÿÁ;õm+^ð¯íƒ®èZ–Ÿ­hš×í?ñÿOÔ,.æÒþÒd°’¡• I"teeu%YH hCþvšÿ»Uÿݺ¹ÿø)7‡ÿá+øYû(x[ûkÄÿ„—ö•ð.•ý¯¡^}UҾѣÚl®6·“sÿ2)6ŽªØ8Å|ûb|ñ·ìÉÿÄÝöý¯þ9þÊ·z¬ø³àÍKâ6§6ªö~jkˆV;WÓgR¶³C0·fw޹V¼Y->ý³´/|!ÿ‚hþË~7øMá­>o€ÿ³¿Æ‡ÿn"ð­Í­Äð‹Ä󨺴ygQ}-ÍÅý±y®óÉtf‘È2J?Oô[J×¼+¦kº¥§ëZ&µi þŸ¨X\%Í¥ý¤È$†heBRHY]IVR$üðø©â+?ˆðrì¥à? Gý±«~ÏÞñ׌ŸáoøYÿþ}ƒöj‹Uþ×øqâ?ìVçgŠ&‡ìÒÜyRn¶o?ÌhöŒ¼Q6~\µø7§|4ÿ‚Õø[àí‰ãï‹ÿ´gÂ/‰~^¿ð^ÿǾ5Ôn<7e®ÛK!KM^ÎéÒÖûR >Ä¢)9ýºÉfßÚ*–Ÿ»ÔQ@Q@Q@WÏÿ´·ü›¯‡?ìªü&ÿÔßB  ( Š( Ÿÿioù7_ÙUøMÿ©¾…_@PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP_7üoý–>üuñV‡âíf_xâ…-$°ðÿÄ?k“h>(Ñ-%|Í WQå$‰Ñ§‹dñʨ—W^X¦v €?a¯…þøËáïøßÇ_ÿh_ø"íoü#wñkÆ“xŠ?]D³X[„Š,„[¹yc•’KKi"17þÕÿü)¤ÝµúøOÇÿæ¿Ñ§ºò%‚9™ † ÒXÄîÈñMg*K#:7Óÿ?gï|jý‰uÙÿXMCÂ?ukM*Â8<*-l$Ó-4ë›{«Xmá’bSi aEDyU ÁÁ«i:V½á]KB×tÍ?ZÑ5«I¬5 >þÝ.m/í&C°Í ‚’DèÌŒŒ ²’ ׇþο³_ÃÙwágмð´ø‚/ x£ÅwÞ,û«z·ŸÙs\ÃoÙm¤Ø²hâ´‰SÎieê^Y Ítð¥<+ÿ õÿ öÿÂmÿ ÿþÇØ|ø?²¿²¿´´üß+Êó¾Óç|»¼Ý›8ò÷|Ô|^ø)á_ð«ÿá)¿ñ‡ü*oˆ'Ä}#û*x"ûN«¥ù¿gŠçÍŠMÖÍç¾õO-μäÐ Oâ_|Uð%¥¤úU½¿ä°Õd‹F–! ÒØÅk Mb©½)’B±Èa ä¤qÆó—üoá…uZ„ÿjÿ€þÕ®Öý¼'à‰sXhÐ]yA$Ê“Ã<ï,‚gyf‘³…QQèÿÙëöbø5û/|,¹ð·Â/ ÿdk}’MoW¼¸{½WÄðˆRk«‡ÿ¶’bX­ãy§h¢‹Ìp@<÷þ ñá_øZ|Ù_Ù_Ú?Ú~o•åyßió¾]ÞnÍœy{¾jÏøûðÁŸ´WÁ­/Áþ/Õ€¢€ (¢€>ý¥¿äÝ|9ÿeWá7þ¦ú}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Wæü§ö›ñOìóðëá­¿ü*?øLüâ_øo[ÿ„Ž~{?ìíWÃÚ冹ýqØ%…>Ù ŽØ$ûFó¶í¼’¶ß½ûàÄ­wã'ìmð÷⧈¼ÿ ëPñþ”šÜZöÄZ¿Ùl'f{~Õq«ùö†ÞçiDhüï-Àtjö ( Šùÿö–ÿ“uðçý•_„ßú›èUôPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^_ñ‡ÇÚ¯Ã_‚凴ÿëw^ ðφôý6ÿV}*Òk­gY²Ñáy®ÒÞåâŠ7¿YX¬±XÈ “ÇÿÂGûSÑýŸÿðòkŸüÉ×់´—мiñ BÓ¾ ü†ïᯈ ðÞ¦÷5…Ž{©t­?WW€¯…X´_gÕmЗÞbJ6• ìØÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ÃÏ‹´—į€^ø‹¡|øi¢xûÃúg‰4ø/þ0kÝCi}mÔ)2§…]P’¨`®Ê‡'°ð¿Ä¿ŠðÔúÃ?‰>ø_þ ëþ'Óu/ xîûÄò »Òm&‚xntk/öÔN®¯'ú§FA  ( ¾oŠ5ïÿ<5ðçágÂýkDøcâ ? Ï©x“âF£¢Ý_ÝM£iºÃ:Z[訑*jÑD œ³4nv¨ P‡ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌyÇ…ßÿhŸ-ðãâÀÙÿYðÃjºf¯²?ŒºÔW1Mgp“bÿá2[ùÑ,¶’É ŽSosp‰$e÷_ÿ„ö¦ÿ¢7û?ÿáä×?ù“£þ?Ú›þˆßìÿÿ‡“\ÿæN€øHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“£þ?Ú›þˆßìÿÿ‡“\ÿæN€8‰zGíMñáÖ›áÿøUÿ³þýŸâ¿ øŸÏÿ…·®\yŸØšå޳älÿ„Y1ç}ƒÈß“³Íßµöìnÿþ?Ú›þˆßìÿÿ‡“\ÿæN€øHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“®ƒá'Ä/øâëâV‘ã_øÁþ&øgâ¸ü1yo¢xŠ}vÂïÌÑôÍb9⹚ÆÊAû­Z8Ù†‰ˆfP°Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|ÿûKɺøsþʯÂoýMô*ú¾ø7ÿ'ûXÿÙUÓõð¥}EPEPEPEPE|ÿû'Ê,¿fŸû%^ ÿÓE­#ÿ”¦üÿ²Uñ/ÿNþ   ( ¾ø7ÿ'ûXÿÙUÓõð¥}EPEPEPEP_?üÿ“Šý¬ìªé¿úƒøR€>€¢€ (¢€ çÿá)ÐOÅ?øBc¾ó¼LšWöÜÖpÃ,¿c°3yKq"©ŽßΕfXVFŸì×f! µœÄçþøïðÏÇ¿âðw…õO^jךU滦Ü\øWZ°ÒµÝ*Ökh&¼Ó5;›Xìu+`÷öEf´šd‘."‘ FÁ«Ð<-âÆž°ñ'†¯¿´4CÍTv†[y š)íî •Vk{˜&ŽX&·™XeŠH¤D‘@‡ÉûV|%‡ÅVZºwÆøµ½FÒæþÓO‚>?[««Kg†;‰£„èûÞ(žêÕÔFžÄ\û„È£vÚŠÌq€ À /Òho†Ú·Š´Í!­þ'øvM^î kÏ|/ñ†ôÃu3ˆ­á}CRÓmí"–iž8!I%Všib†0òHˆÞá@Q@÷𶕦ê:Mž¡©iözõÛXi\\$Rj7K·M Äeö×@XG ¯¨Äqÿ¾'xCá~ Þx¶_ÅQªI´Ñ<7«x‚ÿP¿û-ÅéŠ+=6Þâá±meu+7—µV&$Ž2ŸàŸŒ>ñ÷Š®4-øÃJÖà´køôÿø3^ð­Õõ¢:G4ÖêÖ–Ïw/5ºLð ¸·3Å¿Ô(¢€ (¢€ ÏÓ5m+ZÓ¤¼Ñµ-?V³†îîÂIìîxÒêÖy-n¡,„,7Ë ˆ~d’7F”€¡EÏÛx§A»ø§¬ø&ÞûÌñ7‡ô­3[¿³òeg°Ô&½‚Î_0¯–ÞdºeòíV,¾NX(t,¡«jÚVá]K]×u-?EÑ4[I¯õ Bþá-­,-!C$³M+‘Ĉ¬ÌìBª‚IV…PEPEPEPEPEóÿí-ÿ&ëáÏû*¿ ¿õ7Шè ùÿàßüœWícÿeWMÿÔ”ôQ@Q@Q@Q@óÿìÿ(²ýšì•x7ÿM´xþR›ðoþÉWÄ¿ý;ø2€>€¢€ ùÿàßüœWícÿeWMÿÔ”ôQ@Q@Q@Q@|ÿðoþN+ö±ÿ²«¦ÿêáJúŠ( Š+æÿé:WŒÿiÚÁ¼Y¦iþ!ˆøƒEøu-µýºMisáx<1¦ê©§ÍnÃÊš/¶x—[‘ŒŠÎëxcvh£‰#кÿ‹­ûXø*ûGý÷€¾êºÎ£u¬Çò&§ã#gq¢-…£Ësmgi¨ë+|ʨ#½û ÌòÚê6ðŸ¿â_ñöðŸî|?኷?Ù6¿{ìŸÚúâMCç9wóumoS¹ùÙ¶}£ËM‘GhxþR›ðoþÉWÄ¿ý;ø2¾`ñþ‡y¦è_ðP‹ÚgŒ~ hþ&øWªÝëþ´Ò¼Gy¦iZ~¯aðó÷±ÝÜÙÚ¼qê›åŽÕ^ßRv»-•]} °ñgˆ¼oãÚ«âþ”žý£üCgð›Ä~á]Kᇌ´éÚLòèZV±%Åå¥þµf5[ï´jc1_Û^i {XÖ Ò_ žÃâLjµßÁþ%ø·Å1ø~/x£à³«êé¡]Åy¥%ýχ%šàYOÓG5°•ÜE"M*²m"I @3þ$êßøÁ¿´%¦µà»¯øÇÚˆ®­U´éîn¬mì¦Ð쀾¹Ó ÔÚÞâY>ÍnÖ¯$¢gX,¯yÿx‹Æþ8ýª¾/éIà/Ú?Ä6 ¼A§èÔ¾xËAðþ¤Ï.…¥k\^Z_ëVcU¾ûF¦3ýµæœ ·µ`Ý%ð¹è<©ø‡öñW‡¼=ñ'XÔ4;=/àÿÃïßYü8ñþ‹i}â/¾¯Û.«¤Þù÷66ãH jݵ¼‹w4’ý­–ÒKnà&¿ã&ý ~øw^ñߌ<_vŸ´M½õÖ±|MbM'â—§éóÜÅ GmæÁjòÃŽã†9^8R(ŽÀǧüw­Éàÿ‡2èßþ"è¾)ñ_Ç}WW·ð?Š-t_½·‡üsý›¦[ VóSÓä¶Óa‹RE1ÙÜÇpM­Œ*~Æ.¡—°²Œ>,ø«x~O|O>øyñ)tÍCÂvþ=Ò ø‘ªx8ø~+«[9õ­?XÃ}¯¨ÙN]NÖêãK²‰®d»šæO·€qú×…¼!ã¿þξ¸¾øÿ¡MáOZΪx{Ä?µd×|%4þÕõo²6¯¦jRÉyæEöèîP½–õ‹EžZ[½ÿö¹ñMŸÄÿÙrãÁ:7‡üAâhþ*ÞýŽÃ[ÖgÑì.3࿉<Û¸m.ä‹lEÙvÛɹ•Tì ]@: ?ÂÿüwñwÀž"ø­ ü?ðFŸð³U¹ñ‹cá?ßxŠmcU¸Óot×SÝišzÛ[Ci©^Ÿ*8¦yå–ómÒÙâ¼ùÃáD>!‹ö ý£¿ø‰ñ?^׿j;O éÞ7ñ©â»ùõ5²OêšóE¦0A¦K!Óâ²–îÒ(îå…äçmCeü`‡Š%ñº-Ÿü*/ìMW^Ôgñ·áÿøLüWyá½KɾÔZy.¾Ï§Ûm>ßö¿.âiüë5†Î¿â†ŸªþÏß²¯‰5_†šßÄýzïÄ> ðni¦êÞ&ê3êÚížsq¥]ø‚yJß=¾ ¾LW·-§G=­»´ ¯vn8¿Æ/x»áÏÃo|OøM'‹~ø¯Sðôÿ¼{¤x¶êËÆ¯ak¦Þiì5gPk:7É2KkC§ùQE%ÅÀ¼Ððݶ»eÿ ß‚~Ù|ø-ñwÅ¿üCwàÛ?‹>:‹ÆºV£köh"ÔÒFÕ5Ö´þλÔ,VHÃ[­Âjµ½ÿÙÔÚs÷9ÿ…-ð³ãˆ4 üøão|*ñw´O |Yñ×ü&ºWŠ?±!†G¹I[Õf´û×VpÉwVhML’—MIeë÷:çÁßÚàÄZ/Œ~ x£þÿŠï|/âÑâÏÞkß´~Ö5´Ô-m¥³éw"çI äé±ÚY¯'Cj|«3h~Èä°/Â?kÞ1øã|Føá=_[ÔüOâ;ÍKÌ™´èåA³¸µ¶Ú³ùm$¤·>ZKu%ÍÆùßæ|=‹Hð'Â_xoÇ_ü7eñö•ø£ x…í~ k—3_étž?u´G»¹›ìÞÙ"3Ü[®¤•VëÏ[Ø¡ºˆØ<_£ë.ø»âxKJø¿ñ†ßÙ¾°š×â¶±à øVátÛKé­õÍ^ÏQ“_Öu)ín­gû_د­ÀžÊöy¿´î¤ãþ ÃâÚÅ^Ô>$üDøŸ%ßìëð{Å×Úg†üWákKïjÏâ»Ô]´™-§ŽVá P˼ŠÉæÃ+[Ú5° ?Äÿ‰Ÿ¾üEñ·‡>7üZÑ ÙÇñ'â'Ž<)ãÿjv¾+ø+ð6-Å+¡ÙÏ­ø‰µwÄö–/oi2ZXÁ©_½ä1Â÷PÃemqs·}š)a ñ«Lñn•ðkワü=ñ?À|iû:üRñDzGо1k~,ñΧ Z½Ø{˸4ÈêJ`°ÔîaÔ-î‚Þ òź}ãDÕl¿iYþi^ ý£þ"|=ð‚´/@ž øžúv²u=cRÖáwÕµ½OÄ:¥ÜQÇ¥íµ‚+©!Q5ÏžåØ}œ/ñ‡âÁ†Úß‹<9ñ?Æ:&‘wãmÄ^øãÝ#þ+›S³ÖEŽ…}¨j^±abe‡O±ÔcÔ­-5 ßÞ¨[<@—Óÿµm+Xýž4iômKÆ•…Þ«¤H¾*¸K­gJº°¿¸±ºÓnîP°º–ÆâÞ[re¹iŨ•®¯Cs0¨Q@Q@Q@Q@Q@|ÿûKɺøsþʯÂoýMô*ú¾ø7ÿ'ûXÿÙUÓõð¥}EPEPEPEPE|ÿû'Ê,¿fŸû%^ ÿÓE­#ÿ”¦üÿ²Uñ/ÿNþ   ( ¾ø7ÿ'ûXÿÙUÓõð¥xÄÚ3öŽ×ÿà ž?ø9û3|*øâ­?ö}Ò´­_â-×u‰4é¼Cq©AõŽ‘¡<2·¹šÑgUº¼íÖPÂQ D†ïåÿø'ÏÆ¯ü2ý‘?bÏø§Oðý·Á/W4-#Ä+éy¦øújWöW×rÊ–‘[^ÙŠÎY.g»Ô(E&€=Çÿ·7Ç ]÷Çÿ >ü?ñßÃ/þÐø3ðÚ Ö¹³¿ñÜ"Öñ5‹»}H]<Û\jVñ[é÷ñ—‰Un>Ñ hð=CáçíûWèß¶‡Ä€Ÿ<ð?Ætïƒ÷|Ã]WSÓ-5Y!¾}:=*æmX0Ž[›gÂG®XMæ$Ãÿg?ÛçâÿŽà¤ÿ >üHÔ?eÿÂÄÒµo?áT^kW3x6þßK´iw3Ϧ_îŽ9­™4û‰Õ%W-:ùB9øÿþß¶f¡û0| øå©üø¯øâ÷GÃ]3Ãúf½}¥ëþ,×î%Ô"´¹³šgžÓL±Z¥«­ÙšV–Öy?u ÄOñóöˆø¯­Á:¿n…ß´Ãþ-ñìùwðÙîàðÝ߈¡ð¾¿i¯^Ù][Æê.mµ–ØÇææ%wdCȘÜ}Añ_öˆý¨üKûm|Rø-û$ü7ø_¬Ýüðý†©ãMSâ%ÜñǬjz²Þéšf‘­ÌDK%¸—÷×,™ÖGµXã’èêû/> Òÿá_øoâŠ>ü*ø»ã+J»ÿ„UñŽ™&« ýî"û°Þ}‹±-ªK ™â;aùàÏÛßö¸_ØOÁµ¿Ä/ƒ_åýœ¢ÕN‘ãðî£wŠ®m›P›O¾›oqrÖðÛErö¶ežIn&š Ÿ0[γ[zíûh|}ý~;x²ÇC?²ÿƒ<¡éZmLJ-üw©êº¿Š¾!\\[ÜÏ,š~™£Êf²¶I­¤°êÁnfŒ7ڊ˶@ñíkñÃâ/Žþ|2ý™þ|?·ø›ñcáV™ñ£Äÿµ+™|7áO ÞGåÅl¦É¢»»¹7¬™ ”Ë,¯håÿðñ?xcþ éñ[âwŇþðWÄã®§ðSBÒ~Ñuy£xZê;X®Æ»sjÓOy˜†wÓ¢Ýr`!Š/7ÌO ?aÏÛÿj_ üDÑuŸøCõ/|)»ÓSRñ‚àÕ-ü/¯ÚjI<¶’XêÇ¡±iíçŽx¶—…eŽGI‚Dó€þ%ü}ð7üsöúñ׌®þë?¾éZ.«ã+iu[nÓ¶z­©ø~ÛñM"ڥˬ-üs´p›‰î7?g?Œ¶¯Äïü4ñÇÄ/ƒŸô¯Ùï㕨ëz|Þצoø"ÁãZ,º¡žc ÷Úá1ÆÎ`fÌ- mnÀüãþPQð3þæoýH5:÷ÿƒòq_µý•]7ÿP PÐPEP^>~Þ'íñ \ŠóÈðGÅO ØišÕž©^iöZÝ“\Áý¡–»Y®o4û¸-¤¼Imî-×DÓ•u(lÀ3üû<|6øa¨øz_Oñ>ÂÏ–‹a¥i7Ÿ<_ªhÖv‹¶ŽÓ/5)lŒQÄBÆ XÊ£ VE+Ð|$ðN«à¯†z‚ø–ãO¾ñ‹|A¬ø§ÄVŽó¯Úµ ¹'†ÓíR"Kw…™³Ò žHâf¶Ó퀆Ý ˆ°¹ð¶ƒwñOFñ­Å‡™âoéZž‰ayçJ>Ïa¨Me=Ü^Xo-¼ÉtËÜÊY|œ)PîŸÔþøXðwÅê:Ú4hÿ„ʶÝ'öÏŸ¥ÛèÒüË h7iövÐ~àÇ/xÄŒÎ@3ükðkáßÄ/[ë*ѵ »´´M:ö;=sRÓmXü Ó~èÞÿ„_Áú«{­èÖÞÔïôKŸßÝÜ\ÜÜK¦ÞYMÖŸ½¯¯"Ûk,J-îf¶[»Dt/> |;½ø5¤ø´mBËDÐnÛQÓ®tísRÓõ›-BC)žú-^ÞtÔúàÜÝý¦è\y÷"îìO$¢âa ?yû:ü*¾ø{¤ør}?ÆÅ¢ø¼Uo«ÛøçÄvÞ"“Yk)tÓw>¹êêw2ý‚w²k—ÜE(£Dõ gÂÚˆÓý½ˆ¯n¼Asâ?>¶—ûJëQ’{‹ýÖÑÅkþ“$˜·Š"‰sü7ðká߆|+â}PñŸ-¯IâýsRñeÖ¯§•ÆâëWžæy,T\]µgò®®Yc <¥À üøw០øŸF‡FÔ\?h†-‰qäA欞L{4<ð{ÀþñUÆ»¢jºÜÖa¡âŸëÞ*º±´wI&†Ò]Zîåí"™á·i’ÌÖöæ@æ¶ ø5ðïá犮5 hÚ…¥ÛZ6e湩jVžÓ™ÑÚÇGµ»žX4›0Ûk`–ðµ´SÛhD`‡„ü- øág†|ákì¿ x?J²Ñ4‹?:YþÉai Ao™+4²(Ñw;3d’rkÏô ü7ã±â-+KñÔ"ñ]ÿ­¢»ñVµ{a§k·±êq^\ÙØÜ]=­§žºæ¨dŽ£Úà;!x¢hÀüøgã/ßxƒ]Òü@Ók>WöÖcâ­kMÑh4é&°ŽÇLÑ'¹ºÑÒÅmÝ„¶7³Ím=¨†hdòZL`|_²ÿÁQÿ —ÞñˆuxWXð6«ªx‡Æ:þ·ªÞxoTò æœ×÷·’Ý bÖÈñ¢È%ÃÃå=Äí/A¨ü øªøÚ ãü@?ð‰ý­tÍj/ˆ>&ƒÄpÃu –æÝõØï—SšÚY{yn^&6Ö¹Oôh<° üøwâo øcF›FÔ<7gà«OìíOkš—„î´8¤HÖ6÷ZDöÓÇbÂÞÔµª¸šÖÙš2ÐDS°ð·…´øÃÃ^°þÏÒ4ÿ5‘in&židi§¸¸žVi®.gšIgšâgyf–Y%‘ÞGf Q@Q@Q@Q@WÏÿ´·ü›¯‡?ìªü&ÿÔßB  +çÿƒòq_µý•]7ÿP PΟ‰þMûf~ÑzwÇ?ÚPð·¡x×J³Ð´Kšç‚£µÑ›ÂšÈ0iÖºµ¤^SÞ\_¹”E—‘¥Ë¸¿àŸŠ®ð–âÛN]Câ›â·…>Ýjz‹¬þ6Ó?²P[‹ÍRUwkwµ×vjRÇ$×zv›ÄCU¸¹†]@°OŽðxwÅv?¼-ÿÿÄ?Â?öøwRþÛ¶Öá ¾“LÐ?³oç†Í_íš„RئGeä\C3M²ÓɼŸ€ñ‡íñáü%¶Ÿ> ø~ÃPðç¯|R´¸ð÷Ž›UÒµX|=ýœ§NY§Ómn¢¹‘µdw´ò¢O³˜Þéäš;@_ñ÷Æ-á·Å;-'Å0ýƒÃ ðÿÆ_µ}{|²ÿdØxzm!.ì±DòM¾-]åÊËöm¡$2 ™úÄÿ[|LðÖ‡ñ?áÞŸðþÏâ5Üö^ šÏÄ£[º–ö+KE¬5x#¶Š+ãcis0û,ú…¦ë;¸ÍØo²ý´ŸðÅ‹Ÿ¾ø{Ç:?Â/|CðúëÞ¼ÿ„ú_íŽêÈßi‡]´}-Â)SÊ‚v±›T’ æŒ$W0‰.#Ðý–ücñâì ð§Æ¿méþ#ø[¦x‚ïÂÚ—ˆ$ñ(±Ö[P³½“MÔ&²Òd¶ò§±³¼ŽX¦’{ÛYÜZ^=½µÒ‹C|Ïë?5];NñWl|§ßüøyw«Øø§Å’kï³lÚDóZëVZ/Ù]XØÜ[ÜG3Iwos ²¼k[[°,þÝ¡¨|Sø¨|]ñÖðëá‡ücáÿ…º­¶‰âIo¼bÚ>·w~úm–°ñi&Â[KŸô-NÍbk»û{ƒ,r"Arà¡ñOâ>¡ñwÇZ?ï…þñ‡þê¶Ú'‰%¾ñ‹húÝÝûé¶ZÃŤX› m.е;5‰®ïìî ±È`‰ËèkŸüeqñ3ÄšÂÿ‡zÄ ?‡pYxÊkÏê+Ùm-õ°Ñà’ÚH¯¯…Õ´ÇíSéö›¯-#e¾Õö Eøñªøóãî‰á…~ Óü[àÝSÁ^ ø‰/Œu-}ô{Hô zçR‰Vmi-Ü—ÞNš·BñÅŠÓ¤óÙ€¢€>ø…ûSþÏ¿ ¿híá?ÄÏŠð¼K¥ n mn,ìÀµÂ,²êRF,`Üöw«,èÌʪg@ÇÁ¿ù8¯ÚÇþÊ®›ÿ¨?…(È>(þÇšï‰ÿlsãÂ/ÚâÀ-Câ~•k üR³Ð­b¿ÿ„¾ÂÙb‚Þk).n“©Eh’AìQÈÑnW‰#spn~?ý¢güÿ‚1üý“>x[âÿÆ¿‹º7ŠÎ»àx7BŸK°ðŽ»¸.Åæ¥qé]3ýX¼‚ ¥’HÃG$Ì`òƒÆöýŠtØÛöSø;áÏaiÿ³7Ä üB–óû*[ŸøJoôÖ¹žù|¹.ËYý¶îöâ|‰&X7ìDd ¯ø…û+i_¿m|Q×|a¨Zhž>ø©üÔ4+ ŽêKëé.åÔ!¾wtYBJÑ,MlÊ,Ãä ð{ö ø‡ðÃâgÀOêß´–Ÿã;?Ù¾îîhIð·MÑ4Ë=S´žÓ\‚Aet“Ï}tÚd½ši sE,’ÅvÓ¾ÞÃðÇü#Ÿ°Ÿì·ðSþÛ?ášþ*éÿ¶áòÿá#û.¡¨_ý‡ìÿk?eÝý£åùÞdØò·ygvÕ>/þÃðµ¿á±?âèÿ`ÃXÿ½ÿ™oí_ðŠÿÂ/åÓÚ}³í>Oý0ò·Ë\s¡ñ£ö7ñ—‹iÿü\ø ûFxÃöqñ_ÅO§‡¾ ­†’5ËOÇo[ØÝC·0>ú uhVæÝ„ˆ¤4&ÝÚw¸ú>Ëà?¿ø·úŠ|áÿ‰>6øk¥iZV‘ãi6:ÇŠ¿â_†·¹“S–;í>vû“"ýô’H³ü¡ý”¿aˆÿ¿à›?|)ñ›â×Åÿ|ŸU¿×¼gð+WÑLšöþÛT½[xEóo¬´ÙÒ+ ·²1º´¦k˜Þ)¦Žh>¯ø¯ûë^<ý¶¾)|UðÇCᾉñïÃöø“¡§´mcPÕôh­–ÂîÓMÕî—KŠæÎ(CŽSçÆ³1”$1Cò‡Çÿ…ÿ>|Sýš¥øw¦|ŸÆß ¾Gà5øÅðwÀ â»m{J³™à‡CÕ¼uzÐÃåBö׋}-áInM–ÎÑFÚx_û6~ÇÚ¯Åoø%ÏÅ |Bþë~!øë®üQøcâNö¾=Ñn¢†ÞÛLÖµ8’Dv¾/Ð$1´»ÞhZ2ö÷+öþƒð'ãnƒû0xãJOÚ§Æ·Ç]ØÜKñ#Tðå¥Ö™¢Gk,jiži³lâ{8äŠSï&šy.$w+q`jÿ²-Æ¡û~üTø¥Å=B/…¿´‡í´Š¿ î4y£ñdvÚEÖl ÕÒHîôè’„¬ ÈÒ,¹—k¢ÃÏü ý~'üøËàyu_Ú×â¾ü'´Ö,<ðúãN‡OŽK°a¶‡X½ŠV:¼V–çl ,1¬2G @-¢C€{ì·ð/þ¯öð/ÁOøJ?á4ÿ„/ûOþ'?Ù¿Ùßlû^¡sÿþtÛ6}«ËÿXÙÙ»ŒíÁ¿ù8¯ÚÇþÊ®›ÿ¨?…(è (¢€ (¯øO«jºÇŸÚnÏPÔµ ë=âVŸa¦AqpòǧZ7ƒ¼5tÐÀ¬HŠ#qsq1DL“JøÜìHÊ|g§[||×4߉Ù² …†ÞKÐ …?>.MðBòëâ/„ü©xÓÄÿ¼aàoXèþ(–UÖu g^G´½•ô›X¬ltûSöÀ.g¹¶³’_³›É#³ŸßüãíWÄ*ñ‚üiáí?Â?<#i§êz¦—¦jϬi’隃Ý%…åûÛÛ<±Hö°:Moo4sZN M[Ü\€yüß5[/ŠßUðVŸ¡|'ýŸ®æOøÞû_wÚ'‡,uó&Ÿ¥ÛZM=ı ß.â9ZÝV?&H$»‘å··è4/‰þ2¶ø™á­âý?áýŸÄk¹ì¼5Ÿ‰F·u-ìV—‹XjðGmV7ÆÆÒæaöYõ MÖwq›°ßeûhŸÞ~Ñ>2Oø3â>•ðŸOÖ~ üHñ„to ø‚?5—²×õ[-6ÓV½Òd³T·±‘/>Ñ EwqvÂ[$žÚÌÉtl;ø^ñŽ¿ðŸÂ-ÿ5Wþ—Ø?´¿êwÿ„7í¾o“ÿo¾NÏúcæËZÏÖ~$xÃþÔ,ü‰m.<=â†ñ•¨C&õ(³OgcuÌM2#Ú¶Mncžg3Gnó‡>#xÛCý¬i?|FÒ~Õáoø¯MøwáK]Ç:Ô×3j6~—HÓbÐdµµÒ~Ó{y¬#¶§s8–Þ[Ö´y¾Ã¹ÿ‰þ>x§á·Âψ×>øGñ·ƒþø—â>‰¤ø{ÅsëW‰ô­Úö%Ô&Ó­fµ¹Šk›$‘e³)²úÝá{¦[˜í@=ÃÁ:¯Œµ¯ Üj5ð†Ÿà‹¹îÙ´ý2pj·I§2#BoÙ!Ž/gI`¶–òd]Õ¶áóÿˆ?i-WÂ?¼þ-ð‡ƒü)àoŠ> Ó´ Á­xÍôÿëM{{m¦Ãq…§ÓÐyKq}kq4M~·6ÖRy³Á ÊµŠ€´OŒŸÁ~2øªü'Óô_‚ÿ üAâíÄž “ÅÂme,´ V÷MºÕ¬´˜ìÙ.,cK/´L’ÝÛݨŠñ ¶¼1Ú›þþ0|OÕ~7üPð×þ éþ$Ñ>ø‚ÏFÕõ+ÏC¦Ýkk>¦ë=ÐÚÈ’ß"j-Šú{ bßd"ð‰n˜j_´íGãÖ¹âÝQñŠþx§Â¿³Ö¡á»[]kQÑað’øÇX±PDdMñIa,ð:'Ú¢µ[YÇ–Ä/·ëŸüeqñ3ÄšÂÿ‡zÄ ?‡pYxÊkÏê+Ùm-õ°Ñà’ÚH¯¯…Õ´ÇíSéö›¯-#e¾Õö ÿŠ?|SàíËíÃìü%àß²Çâ/|Mñ¼þÐa¸ºò¾Ï ×ömïÚñçB²ÌVu’x`Š[‰Öê+Oœ5oÚKÇÚô+7òõ ¶ik ÔK,ÒB€WøÇâŠ`ø§/Ãÿ…þðÿ"“JþÄÔ-u]oÃÚ¥ŠÜýª}WGÔ®t‹õ·œ¤m=·Úìg0ÊñBòDcwŠf‰=€ (¢€ (¢€ (¢€ (¢€ (¢€ üý±¿à¨>¿ý¯þü3ø_'ü$?~|@ðψ¼â]6.æñoö>«m¨›-ÌeŒÛG-¢¿Úw§Úen–ªd»ýþ¯Ÿþ ÿÉÅ~Ö?öUtßýAü)@…¾ýÅ¿´ü%¶žñ†>2x®-U4É¢û\7Qð΋¢Om} ±ùmæK¦]f?Þ#E$y9fEòÿ~ÏÚ¯?f¯x'Ç)àÿŠ×|A«á_øMÃê¶^=´¶Ó'Ó¡_$ðÊRùíõ ¸Þîp¢î}H@U›KP ý™,àøEâë{ |ø!âj¾Öìto‡^³}H¿ðÞ¤š¶—-íÒYé÷zÇ›{½Â°³U·amn-å_ÝyÿÄ/|Sø»ûSÅðÿâ\_þÂÅøñwÂzl~Ô/¼Mý›öÛ¿ ÛM=Õ;çgí´[hö}™ØÜËö€– ¯|ø§ñ›âõ߯+_‡þ ðF­ð«Ç ®´Ÿø‚ûXÕbÿ„†mžö=BóOµ„æ:d›1äÆÞÕnÝ®,lÞ dxå&’ª(Oß9b ø!àWá¯ì_ð‡áλq§Ýë~ðVá½B{w´šêÆÆY^tGh‹ÄÅK"1R2ªx“àVÃöÐñ÷ÄYn4öÑ:|ñOÅë-eð×öÔu KJW†þ*jo=—Ž>n–;9r×w67rM©ZÉ¡¦~òTˆ#y7¨x;⟄>.øëWøSÃýSOø»ªÛkzÕÇ‹5 ëi¼'ªÃ¦Ùhÿjµ¶µ·uÕ­šÓN²“ì2O§8– ÇÛJ]§Ø@„ß?áS|S›û"ÿí¾Ò¾|=øq¢}²3UoøG&×7Ëu²(á;áÕ,ðÑãs¬ùŽ5 »è ùÿöNÿ”Y~Í?öJ¼ÿ¦‹Zãþ,|<ðįø)'Á= â/üãýÓá¯Ä‹ø4ÿhÖº­¤7KªxB5™!¸GE”$² p7‘ÆpÇ ‡ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5|¡ñSþ kû<üWý´<9ñòÃOð/ÃÝÃözlÿü ÙøzÓZÔ ¾–å®®î­À&)­æ6²$QE>Ô’å6¯ý—<àÏ…ž%ý¤>ü=ðöŸá_øWâV™g¦i–jDvñøU˜–b^I]Ùä’Y¤–Gy™Ù˜€}a_7øã~«¢þÛZ?€íô=>çáìz/‡üGâV™ü½#_ÖmµK«yg¸·–3¦é6ÆÖ\Ëq'‹4vFƒG¨v1øïðÏÀ¿åð.µªx‚÷ÆÐéVzëx{ÃÞÖ¼Eª*æk›xïÓMµ¸™­„ÖSE$ÁJBïn²˜ÚæÜJx£ã×ÂoÿºŠÿ´¦ø‘¥]k~·ðî™âŸX[}Í.›› ò^íŠþÚ}°+±·ó®0Á4‘€gêß­®µ¿€Sø*m?VðïůêÔ&»µ¸†êÆ;]]Ôe‹Ès–·ÐßhÑÛOÌ~d,·0És/îô,¾0xBÃöXøñZñ/ü$ZŽ4­*ëJ»ðï…õi.¯á™­4{­X‹½&=9‘"³hí&Šeµ»7±‰-¡w PÓþ&øfÛà†·ãkÅ:}þ‰¢øƒ\Ñ%½°Ñ¯m™®¬õ›%4èl˜Íqw|·P®ž¢Í{r¶ˆ ˆ¡ó|zøMcð'Qø“¬ø¯þèZ­–‰¬Üø‹L¿Ñ.|?wqmmo¥g{ WZ~ö¾²—uÔQ(·¹†ä‘në)è< ñ;µ"ðä¾ µÔ4O!¯´¿øoVðæ«o ûÄ a©ÛÛÝ}šV†á#¸ùR=½Â#³Ã*¦€×/ØÌjW…{øïÃ?|+q«xbëPx¬nÚÂúÏSÒ¯t}OKºTI|›Í>ö(ní%he‚tIâžà™CE,nÀ…|ÿðoþN+ö±ÿ²«¦ÿêáJúŠ( Š+çýCÂÿü ñwÇ^"øS ü?ñ¾ŸñOU¶ñµcâÏßxrmU·Ól´Ö³Úéš‚ÜÛMi¦Ù*H¡x%Šwónå"³çôÿ‚ž)?ü ãÝRÿÃéâi¾*ÜüMñ¤óµ…žÿÞøNÞÇKvˆIqäÄt°óN!óÚ;»…ŽÔIœ^¡‚u]öŸ¼ñdž.4ñ¢xêÒÚÏÆ:E˼ ·VQL,õ{!’ùÑ Óî–pkk}8¬ð5mï<à†‰ûI|5øð‡áv»ðïà}Þ‰àèÔ5Û‰ÚÃÝMicm ¤·pØ¿†ÑR‘4‹\¢–! Ê>qCÄ¿Ñòïòÿ{@ø;ñONðì‘\Úü?·Õ¾|UñoÄ߇·1x‚úæÛÄŸÛ—Þ!’kf§ÄÚn4ÿËn“[K}åÜl¸1ÏÒë×þx;Å0|SñoňxKñ·4­ÃÒhžÔ'Ôt­#JÒfÔ'µU½¸··šîæIµkéd”ÛÛ¢£ÛÀ±·{› }þ ÂAáÚŸÂÞ-¿ò¼1ûDê·$Ò'Ûe¥\øSHðôù2ÄcŽäK§ÝHŸ,©µ¡c’Z5à>þÎV~øí¡xªçàÇì¿ð¾o}§ìš×à YǪøºi­å³2ËçéÑÉ¡[yRË+YÛ\ÞÊï,Q›ï&ÞdÔ@<ÿ⃾)ü7ý—~|+Š/‡ó|"økñàþ‰¥ø…µ éüG­éVž.Э¬-n4Ño­Ìkäy×Éwp“›I YZý±VðԾ |h>‹á¾Œÿ âø{iñ‚Ó℞ ¼Ôõ5VÑüm‹î´ÕÓRÑ`²–#,°Çto.ÖqhŠÖößl2X€súÏì{á럈^*Ó-þ~Íúþ‰ãÏjþ$½øâ_ Xj^6ÐäÕofÔ/mã²¹Òç´Ô¥I§š;;«‹˜£¶Š[e–ÎøX¸Ô;ŽŸÞßÃüEà‹º­¯ˆl#ñ©}sý©·CÐô[½RÓE‡“ µÔ:Uòýµn.¼¯´BÍctªð¶‡À„گïx×W—Á þèž$´Ò,í<ðîñî´ [«7½{\¹Óôä׉ykk*­¦á•hZyAXíÀ ÿ‚®·ÇHo5Í?J“âį üDðÅÜ0½âé÷Zá±d/íÏ•æÄu?–¦F’Ù¤ðHû¢ä>!|ø§ñ›ágÄË¿Zü?ð_µo…^5øeá-'Dñö±¥Eÿ 6Ís{¨êiö³ͧiÉ0Ù!"¹v’í®cŽÐëúøDýœ~)èÿ¼9à}7³ÿ‡ÿ³üWðÿ]ñ—Äkkûë|Xÿ„o\±Ôe¼Ôà]2³êWg¹½i§½ÔöÍ,¶ä¿ÚZúá÷ƒ¾)üHý—~+ü+’/‡ðü"ø•ñ㉪x…u è1Ñ|C«Kf>eŠÚîÓYðÔr2²<ÒéAde­¼Ž÷ý|ÿðoþN+ö±ÿ²«¦ÿêáJúŠ( Š( Š( Š( ŠùÿöNÿ”Y~Í?öJ¼ÿ¦‹Z oŠš7…u=/Öšf‰¬ÚKmqàè5hfÑ&¿·–Æ×Hðäð$Ò5ÈÌûÙ¥ì4ŸŒšv‘û}x«Æ:×€~/éúGþ ü.ÔZÞÛÁZޱªøvâ]GųÇa©éšj\ß[Ü”’`Ì {xžÖXåš9Ýgãô;Wà¿íIðZÿÆžñ„í¯xãω5 ioâCÃVš÷4 jÕ.¬ôÿ:{‰b¶¶s9/'vug´ŽK´ì4ÿ ø§Pý¥< ñ!|3â = Çß´Ï­íîôéá¿Ñôþ^ørNÜ®ë´]Ø£¤sí‘úÒ)ÒÞ餶‹?á~‹â†¿¿c_ˆž&ð¯Œ?²¾ü ÿ„ÅV› _ê:þ‡¨jVÞš)%Òmâ{É"Š] {YÒ¥žn f„@—3ÛvüQ®êÚÇÂÿZØü_ø_á+í+İÏâ ü9‹Ä>8°™î´ã¦Ø¶œÚn«qe¦êVÐ]_N²ÙE,rXi±\µ”àÚÉóÿ…¬§ð?įÃÿö¾°ý¥eñ»kzŠ ’…´Å?kT:tï«Ýh:†¥ã->+›=¾eÞ"×-/Äq$ö©!¶K™ž'ÏñƋ∾.ñ?Å_øWÆxkÄ~ ø ¡ivš¦¦k7QøwǪjšƒé—%Ý­ŒPê¤oºŽ±»˜Æ-|‹‹€Ð4Vø)'Å}v]3P‹DÔ~ü=°´ÔÝÖÒêêÛTñd—Ç)X’êÕ–EžÀ\ù‡‡~#é ÿj/ÚNËžø¿ÿGÄ 7[ÒnôO…¾-ñ†¡aÿ‡lŒ±^iºuÅ»bæÊê_3r´Ld~÷ÄQx#ö§Õþ3jžø¨ø âŸÃÿèš|º'‚µÍ[UÒ¯ô˽nù¢Ôt{kGÔ­<ø5ÈŒlöÛc{K˜®M¬¦Ù.x xOÅ? ¼Oðó⯋¼3â t[?ø[¿ÛzVƒ§Oâ oÃÿð™ø®ÏÄšoc§,ò]}ž+O±]ýƒí~]ÄѺyÖk5ä †nu_|jø…ñoNð—Œ!ѾþÑPx³SÑn4·_O¡Ëð·OÑæ 1wNÒãU·Ô “„¾û:KÙø[ûÁ>2¶ñ×…n5Í?@ñ†…¥ ¶·²h—%Ö¥",nÖ;È"´°w¼ŽÐ<ˆÃ4À…|ÿðoþN+ö±ÿ²«¦ÿêáJúŠ( Š+Ëô?ŠUö·ñ­5ÕÓü+¢|ñhú†±¨¢ZIh4 /]–öguDµŠ$ÕZ6ÜÌ¡mÌ…Àm¨Øx[ÅžñÇ,ð·Šþøû?ûnÏWŠÃÄÐ\jºn«¦McŧØbWÏ“öôEåíž[$1¿ÚƒDxsâÇ¿xíü-á/‰üQâh´«muô#Ä67·é¥\GÐ^x¤i´‘]ÚÈ“mØËq DŠHŸø#ö¤øãÏ„^+ñÖ“ñ[áýŸ†< ªÝiZõõ÷‰´¨áÒ|½JãLµ¹¹‘.8m¯¥µ2ÙÉ#/Ú"–&Q–Ú=ƒÂÞ,ð¯Ž< aâŸø—Ãþ0ðÆ©æýWÑ55 ¿*F†O*âhßd±¼mµŽN"€ _xV÷Gð¶£eâ_Ýéþ8òÿẇQ‚H|AæZÉ}Ø\6ÛÖMr<¢ÙŠ)$"’9ýKâ7…t¯êmçŠþÙiþÒµ}KÄ’^xš {ý ì1é×.ÒÚÚ¶ÑÚjpÜ\O,±}g°%$K°ñ€x†?l‚þ-Ó¾øNñƒô3ðV¯âÝOÄZ¯‰ôëhüue?‡ ]'T #Áo|ÇÄÖë$o:´RF‰¶O9Y~ Òum+^ð®™®èZ–Ÿ­hšÕ¤7ú~¡ap—6—ö“ ’¡• I"teeu%YH hËüQñßá_‚ÿjüñOŒøð ]ø‹ñ]Óô]E´ºš&½µ¶ºÖî¡¶šél,âX’âúd·”EpÎÃH/>7|Ó~ i?u‹¿ ì>ë×ma¦xžãÅZtZ6£t¦Uh`½iDÊ µÀ(ŽXeù‹~!xÀs^xïÇðUšZI~ÓëÚÍ®›´Ž{kY&-; ò–âúʺ$º·BCJ³õÿ‹ ü'ð³Dñ׊~%ü?ðׂ0ÒµxN Yð~±¢x¿Ã÷ž ÓîíµÔ’ëR´‰ìD7茗v,—ÊÒÝ,ʱ4–jQsº"Ëâ€5Œº·Ã;Ǿøƒ Z-þ§á‹}fÖ]gN´a,ÓÙ+™âˆ‹›rÐ)EÏιχâÇ»Šzomþ%ü?ŸÆÚÇÛ~ÁáèüCbÚ­÷Øæ¹·»òmžtžDÖÑKµO–ö— ÛZ' èQ@Q@Q@Q@Q@Q@WÀÿÄÓþ ‰à¿ˆ/ûÙ¾3|jø}ñ+©¾kù´­kâ&‘}¢E|ü–¹´Ñ$Ò´ò¡äHVÊ8"w†}ÿ_?üÿ“Šý¬ìªé¿úƒøR€>€¢€ (¢€ (¢€ (¢€ (¢€>ý“¿å_³Oý’¯ÿé¢ÖÿÊS~ ÿÙ*ø—ÿ§PÐP_?üÿ“Šý¬ìªé¿úƒøR€>€¢€9ûo h6õŸÛØy~&ñ•¦h—÷žt§í|׳ÙÅå–ò×Ë—S¾mÊ¡›ÎÃKŸ h7ôoÜXyž&ðþ•©è–žt£ìö„ÖSÝÅå†òÛÌ—L±mÌ¥—É•á€: (¢€ (¢€ óÿ|0ð‡Ä_ì©Ã=ºßé—÷_f•¡·y-ÌžTonîŒðÄÈÐx[ÂÚ‚ü aᯠXgéšÈ4·O4²4ÓÜ\O+4×3Í$³Íq3¼³K,’Èï#³‚€ ùÿàßüœWícÿeWMÿÔ”ôQ@WÀ·úí)ñ3ĺÇËðãÁ_´®‘®øæi¾{ *†JY^_EÈkkMnMìÌÊRÍ­ã½Ã£Ïã/ø¹wßçìéqöĶþÌ_´Mjö‘yí-ãÿ„|UñKÄ? |Càÿ]ÛþÉ_tí[Äžhµ I£ô m¬_T€4Kšæcj&i-Öõ$xã[¸ÚP«üQâÏ ü0ý¾µï|[ñ/‡üà_áþ¡x?Ä>'Ô`²Ò­õXõZã]²‚îvÚ\ÜÂÞ•¡fïRÅuÓ¥6ÞâÏ øÅ°/‰|ý—â |2ñ/ÃûÍû;BðíÕž«¥h7sÁäYiekˆnb¶}‘Z}ÈŽ«Xytò…çÄ|Vð¯ÅO ü9øð?ãßįƒþ7O xÛá¨Ñ®¼¬Ê–pÙi³ßgQòê—Eq› ­ ÊøŸËßkÐ|jñßÀ_ÿÁ6þ?h_ k~øã2=?GÒ„W^Ó–#}&ö‰_C•žÚÙ?³n…´ÎÚ|€BMŒ¾@¯Þé:Vÿ$ø¡hZfŸ¢èš/Áÿˆ¶~Ÿan–Ö–êž Ža…HâDUEEU@+å‚~)øqâoø&ìð¿áE÷‡ÿánø_þwˆ'ðΕ Øk¾†+« ¯j—6ÅcšÆÚïK›Xß{(Ž-F=QcŽKŸíHè ðç‹~Kû?Ý]Œÿüãoÿ´ÄÍ]ﵤ]WHð¥þ£âXÀÄÇöµøCãvÿJÿ…©á_Ž~6²Õdæç\Ðuø^o\ÌÍûßùcÃsbK{xmíÙ"òQ€qÿ²ö­àj?°Mæ©x?Æwÿg_XI=Å®£'†uø`ð5­Ô%±´¾K{¹a‘ÉV;‡Fd ý_û4ÿɺøþʯÅýMõÚãü_ñ Àoüóà-æ¡ãØYëÞ ø›á=2{fÖ(õ}uï Z¶™3-𸶸„Û¦eC*mÜŒÙßÅ?-~ üøCâ«ïÞ~Ð~Ò ŸÄ¾š½ñâÁ§ÌºÞ¯}«Ímö©®u:¼»`¾:¤mÅÀÔ¡7ÿ4Ïk_ðoôo‡2jüAÕ¿g]2ÏÃX_‹ ¤ÖeðÔidaº/‚QpÑ”ºl6åÆGŸø/Ä–Ú—Æÿ…:”>ê~øi«ÜxƒNðÃk7Ãÿ®sm&âYï|A0ÐìRá,d:]ŪÜ5Ε}M¹šÌËüc¦ÿÂ#û~ÓgÅ^ñ…4üñþŸðv ~M±éšojè¶–Ïm¦\¶žºUð±qk Ómôë²¼ž¼º`ñÏÄ'ö¿‹ã†¾>þÏþ øEâ_‡úf…áOxËNÿ„—ÃwÚ¬®ªÚÝ–›©ÛëV¶2*hæx^F{áa_û*$øCà¯ì¯Úwö^´ñ=—ö¦¡á߇ÿµMO¿Ø-¡[]øÃ‚Å4í.k›©´‹ht»ï±ZÚÉ2Ü[Ù2[˳‰m£çô]KAðo‚4ˆ—~üñ6™ñãχ,5ˆ:<·¾¼°¿ñíÍÍݳÊ/´èâÔŒº]Œ–Êסžµ¶óˆÞ[P@øW¯ÿÂQûZü׿±|¼…um*óö=ýŸ¾ iÚ–Ÿ7í=àxSñw‡a¸OøJ4N×S³›Æzµþ›W–rk¾n¥+uDÕBÅ5ßö¬ tYi:V›ÿüÕ¯4í3O°»×¿kU¿Ôç··H¤Ôn—ãDV«4ì eöÖð‡|°Ž“;Q@ûþËVÒµGV³Óµ->úï@»[ N {„–M:é ŠéaT“¦ÞæÞ`Žæ‰ñµÔ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ÂÝ-­,-!ñ®ƒ0à ‘ĈªŠŠª€PÒóÿÁ¿ù8¯ÚÇþÊ®›ÿ¨?…(è (¢€ (¢€ (¢€ (¢€ (çÿÙ;þQeû4ÿÙ*ðoþš-hñü¥7àßý’¯‰úwðe}EóÿÁ¿ù8¯ÚÇþÊ®›ÿ¨?…(è (¢€ (¢€ (¢€ (¢€ ùÿàßüœWícÿeWMÿÔ”ôQ@Q@ÿŠ|?ÿ ?/´EÖ¼Aá¹®|©-õ]óì·úuÄR,ÐÍhßd±¡hgŽ[y”4SÅ42Iñþ øa…¼Uqâ_xÓÆŸawý‹â ;X’ na·¹’6+]`— êJã4ÏÿÂGûSÑýŸÿðòkŸüÉ×àÝ#ö¦ðÄ_‹ÿü*ÿÙÿPÿ…¡â»oùð¶õÈ¿³<­JѼßð‹7›Ÿì?~~ͧf÷ïÿá#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ þ?Ú›þˆßìÿÿ‡“\ÿæNøHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ þ?Ú›þˆßìÿÿ‡“\ÿæNøHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ þ?Ú›þˆßìÿÿ‡“\ÿæNøHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ þ?Ú›þˆßìÿÿ‡“\ÿæNøHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ á6‘ûS|/ý–>|3ÿ…_û?ëŸð®ü+£xcûKþÞ¹ký¡ö 8­<ÿ'þgò¼Ï+~Íï·v762zÿ øoãF½ûhxSâ/Ä_ |/ð~‰àÿx£ÃpAá¿ê>!º¿ºÕ¯´;¥w[Á!Š4Ñe‡‘™¦A´M}!Eòý·‡þ>øö€øÏ«ø'Áüa቞+±ñ=Æ·ñ UЯí<¯èú0k ÷RéZ~®¯_ ±h¾ÏªÛ¡.¼Ä”m*Û°ÿ„ö¦ÿ¢7û?ÿáä×?ù“ þ?Ú›þˆßìÿÿ‡“\ÿæNøHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ þ?Ú›þˆßìÿÿ‡“\ÿæNøHÿjoú#³ÿþMsÿ™:?á#ý©¿èþÏÿøy5ÏþdëCà¿„¼} k$ƒMðÞ¹u­ZXZC hú:£ÝÜXÙ;ÊϤË)ª² ÜÄ@áEPEPEPEPEPEPEPEPEPEPEPEPEPEPE|ÿàÏø©ÿà ŸŽFVGš](,‘ìµ·‘þ€ Š( Š( Š( Š( Š( Š( Š( Š( ŠùÿàßüœWícÿeWMÿÔ•ôPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEx~¹ûC|6Ð>&x“Â[üOÖµ¿ÝÁa¬ ü/ñˆm,.¦´·¾Ž»Ó´Ù팦ÖòÖR‹!eY“p⽃IÕ´­{ºf»¡jZ~µ¢kVßéú……Â\Ú_ÚL‚Hf†T%$‰Ñ••Ô•e ‚A  (¬ýKVÒ´]:+ÍcRÓô›9®í,#žòá î®§ŽÖÖg f¸šcAó<’"(,ÀÁ¾ Ò¼§kñi׆¡wâjž$Ôõ EÒ[ÛË«ÉÚEI%TS$VÖâÞÂØ>æŠÒÎÒ ÅaZì(Ïæø£àKo>.ø—6¹³Áÿ„ûwRûÑûö ÅÕ¦«û‘'‘5…Ò~íÌòóõe-Ç럴7Ãmâg‰ü,øáû/x_௄­¾ ø‡[ø­¬xûo]Oí+eºÓ´ÝO¹‡Ç7>M¯‡e“Lx¥Œù¶±ÅnWSuÐ>.øÚóOý©üGiñ;â…ü{gñ«á^‰áO éZµä6ÚÇÃ뻿 }º[20Ð6MRïY·}]£ŠG¸EÒÚñ¢°KÐxgâÇü_o‚¿ u‰ñsá >'ÿoøFãÄ?ñ=ÿ„Wìþ6»Ò>Ù§´ŸhþÍû7ö$ö¾by>_ö{Çòù&€<¿öyñ—ÅøW]¸ºø—§è^2›àþ¯{ãµÑüYâ/‰úÿ‡œ¶ž¾´™µŸø§¬äOµJd¶ŽÞtÓ³oÏø‡Zð?Šc?ÿjøßPðwį„:µïˆ<9ûAkÞ5ð‚Ïâ»K[Òž,¹û%üWÐÚþþêÆYZÚűïàÜÌò€ÐÿZ×ü#ß²wŠõF›Ä°Gö..4Wû­­§¼‚ ¥»ÔÄrI¥é©Ž÷ÚŒ ö‹+%ºº€¤ÐÆËä±Ïu|6ø³kyö½Áßá;*Ö­¥iÿ°í û7^êZ}¯Çˆ·m|-ài.uŸ/‰µ}fóG¹²ƒ9¸±’ßR·’kØ÷[ZïÔ¶æÆð[èj¿|;ñ?öÊñÂ_áýΟៈeý߆5?ê¾!Öõ#Á~’ðiÒZk‹-ËZ-lÌθD®!I¼È‡¾9øðö§—ÂÚÆ_‡ú‚-¾|"Ò¼«øŸÅºU§ü$ºU…ߊ¡Šæ †x¡ºÌ-m#Iì>r0 ®¢¾ïÒum+^ð®™®èZ–Ÿ­hšÕ¤7ú~¡ap—6—ö“ ’¡• I"teeu%YH hBŠ( Š( Š( Š( Š( Šóÿ|XøWð¿û+þ_Ä¿‡ÿÿ·<ÿìßøIüCc¤hy;<ï#í2'›åù±nÛ¾bg†z x³Â¾8ð%‡Š|â_øÃç›ö=_DÔ`Ô,.ü©<«ˆY£}’Æñ¶Ö8de8 Šè( Šãükñ À |+o®üEñǃü¢]Ý¥„‡‰5›]*Òk¦G‘aIn¥)¬ÅcsŒ)Ƈ…¼Yá_xÃÅ> ñ/‡üaáSÍû¯¢j0j~T žUÄ,ѾÉcxÛk22œEsþ ð/ü"?~,kÿÚŸÚð´°ÿ‚’|—áφ|â­m¾üHIí,ðÿÃoþÓ_¤›Ä±èP§‰-´=*ÛÀWvßg²º¾¶·ó®[þ‹KØ®$´!¸•c’ ÛxdK° ÿ‡_>3xö¸Òn¯í=øì~Î? þ xãão‡ü[§üEøâo‰zæ·'†-n4ê¾] ŒZYŠêãcj·‡R·{—y.¬ÊÚ®˜„Û(|>3Z§Åχºw‰¼a¤øÇÀþ ø/mo¨|K±ðf¯¬éw+ñGöeå­í¯…çK±:|VòG µµö/'“ÎD’ÒHû ÿ‰´ÿÚÇ^Ñ4»¿ˆç†>|@ð7ÃËVþ_ØxOX³Ô¬ü?6¡w¬´ò[jí­°×n¼zLpÚ<ë¦D–Òq ÿñ“þN+öNÿ²«©êâºóø’㟴¯í©øs[Ô¾ÕncÖ$Ò!¸Ó~Óój:fۃ˵ÒTñ ˆ}BÃ㇊âÿ‚Šü=ðÌ&ñ‡ˆ<)ñGƾ1ð”1ߨøWOðºÛèZ£ÞcZÇ9ñ+ßY_évÖ7WW¡ìey/$‰!KxÿÅŸÿádøƒÆÿØÚ¯Á Fß_ñ™¢¦«öoøÖ}U°aaekhm–ˆÛìßhG»¸o8â⟈?5oÚRûÀñÿü"6·¿´^KÕÐì/¦°ðÙø`¾#žu•6ý§ûC͸†y„Â9LbHîm‘­$ïþx‡ÅÞ'ñü'zÿůìí?[øãŸÙø ÷OÒWJº‡CÕ5}:ØiR¬Qj_ÚMŠ·Ó4×W‘ŽËhÂö`ðwãwÇ¿|,µñ®½?ü#p|@ø+¬|I²¼ø§¨x>úF·:dö¤Ç¢Üÿk¯†ãÃ^Kª¬·špi¢šIÿGüñ'Šî¼Uã_øß[øŸ?ˆ´+M#XGÄM3±ëö6WÏ{W"óÃ.t¹¬g“N¸Ž(Lkw ¶—o3<7¢0¤( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¾ðïüUðQψºùÿOÒ>xWHðN™?ú¯ì­wTvÖ|Ak³åi¼Ý=<?˜áãLl…ÖO¶%}EPEPEPEPEPEPEP|šN•7ЬµÙtÍ>]oM´¹°´ÔÝêÖÒåá’âå#zE+ÚÚ³¢®ÐBXà¼Òt­GQÒo5 3O¾»Ð.ÚÿLžâÝ%“Nºh%µi fÅ)·¹¸„ºaŒsJ™Úì?eðóÀoÆ][â.àØ|A×­ÃSñ=¾k³¨Ú(‰VïUòĵ¸îTbùÁ_ƒ>ø/ðOÂÞÒtïÜx›K𯆼1¯x¦ÓEƒO¿ñ_ö.ŸŸk=Û!idQ‘I,¾R¹Elr@: á7¿ xvß >èE·ö•c¦øzÆÒÚ/°_K©ØíŠ8ÕGÙõ ‹‹Èp?wq4’¦Ù˜è^|<ð£ñ—Iø‹¨xÁ÷ßt F°ÓvÈã_‡žø•á[} â/üãýÒí/àÓüI£Zê¶Ý*àw€qúƒþkwZ¯†4?|?Ÿþ7Šô–žÁ|/m:ˆìô}>M6âÝZAso¤Üi‘ÃqLQáW_(¢v|<ð?/ëåÿH¹øÑâ½oÆÐj_sûgAžàÚxfçÉnðÍž‚žYHä^gArÓ’ôQ@Q@Q@Q@Q@Q@Q@Q@Q@?üÿ“Šý¬ìªé¿úƒøR¾€ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( øýâwÁÿ±·Ä-[ÂßÙÞ=»ÒŸDð\¾LSoñf¦Ë¦èQm™Zæj—vQnœy ¿tÅbWaèð¶ƒào…žðO…¬?²ü1àý*ËDÒ,üégû%…¤)¼^d¬Ò>È£EÜìÌq’IÉ ‚Š( Š( Š( Š( Š( Š( Š( Š( Š+ŸñO‹<+ào_x§Æ¾%ðÿƒü1¥ù_lÕõ½F >ÂÓÌ‘a͸™–4ß,‘Æ»˜eTr@ ”?gïßüOûZ~Ñš†¾.ü/ñ·ã/‰V—þÓôÏi×wZí¤ ðäsMg r³ÜEÙ^#¼a•ZÚpH1¾ß³è¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (çÿŒñRüvø ðÎ?ôÛ]WÅrøÛÄZoú¿7Aðå»][Üùß)gñ5Ç„ßˉĒnÁI-…Ð@PEPEPEPEPEPEPEPEPEŸ«i:V½á]KB×tÍ?ZÑ5«I¬5 >þÝ.m/í&C°Í ‚’DèÌŒŒ ²’ Ðâü‹öUøWð¿þ 9ñ·Æ?>üDþÃûMŸÂ/°ëö:½æ¡áY>Ó¯G¶Ý<ß/̓F{Û&­ÜzÝ£µsû}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@?øwþ*¿ø(çÄ]|ÿ§é ¼+¤x'LŸýWöV»ª;k> µÙò´Þnžž ŸÌpñ¦6Bë'Û¾€ Š( Š( Š( Š( Š( Š( Š( Š( ŠçüSâÁ~¾ñ'‰/¿³ô?ÊWu†[‰§šY-íà‰Zk‹™æ’(!·…Y¥–8£G‘ÕOÿÂ-âé_¬Õ¿lñùö/ËýוæKæð˳íßï#µÇ޵[xz‹x¯õÉ.V.ën’,JòJáË#0ÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùøeÙ’/Þiß>øPæµÕ4/ éú>«¦Ì9K‹+û8¢º³¹°ñ\[ɱ:«Æèêhx'VÕ|ñ2ãá_5-BóMÔnÙ¾kšÃÝÏ­i‘Ú$ÓiW—Òóêöoë ˜y×:tpNe¾¸·Õ&‡Ü(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (çÿøXzïÅÏô/Z§‡æðÿ躗Å8/¢¼¶…2'†àMk«ÜĪÐÉs4‰eiq,cn§-­îŸ¨x'À~ø{á[#ú„q_]µýõ槪Þêúž©tÈ‘yך…ì³]ÝʰÃóÊìÁ*V(£Eì( Š+ÇüSðÞòÛÇwßþ^`üCŸÊ’þÂïR¼‹Ã~2HãXL¤{áŠæHb·…5h kÛqkh¤ÝZBö ø¡¥xÅWñéþø·£Z5æ¯àÙµžémÒ#¨Ø1XÞÿH‘äŒE|‘"îo&d¶»ŠâÖP Š( Š( Š+æÿ Y\xïöÂý¡5Á«jß‚-4¯…ZͲ[Ý]hR>™oâíVÀÝE$Ëtuí.`h$ŽFÐ,ä˜Î»!€Ì>øvÏÀðS[+á/ü)j~ñ‹ý±¨êr_üjñ8½³¹Šòym%¹kÛ›]>ÃQ»Ž}béu9×SÔdKr°j¯¯þÏßñ$Ñþ)ü/‹÷šÁ…¥Ê¿»…4­BÖÏĶVöã+mm§ZkÐi0ÂŒPE§FȰ£¬x†½û2~ͰÿÁI>èPþÏŸâÑ5†¿oîôôð.޶—WVÚ§„ã·šHE¾Ç–$ººDv‘g”)Û<úk~>ø7{ûgx»áÍÂýáoÁ?[ëÓøvmê[­rÓLøá©›J°û<öÖÚ,IkiQ\˜õ-sÿ±­¨[°@ø‹ûOéZ'íã?éß¿fÿ…— .ììõ=â~´–Z‡Œ®®,-uEŽÊE¾„év?g¼·€jo¨³N÷Cìal—íßGøO⟎?e üVð¶ƒâ SOñ‡…l¼Y¤h¸³ƒU»†îÍ/-í{:ڥˬ‰Ïp±<Ê ˜< ûJk×í1ðÛÿð°>üVðÿÅ-VûFÇÃkZWƒ¯"ÒoõŸ"_ý®}3S¹Š=7ìíiö}>îT»Š÷È·‰|™4>|føÑsû0|øáñ9>¿ƒ~,Zx&ÚçÃ~Ó5õ=ëÄ’ÙXØÞ&¡svÑ]Ä×—ÖÍ5™µ·khneÙwzöJ5Ûã7Æ‹_‚¾8k©ð¾?…¿ ¼AãûmCÃvf£&¿®hÖu+o!Ôím­/–ÖÅ™lÚÖâ+™m†nì–÷~~¯ÿc~Þ^,Ó¿±1|SøÍñNÆÏàåÏÃÿø#VøUàO‰¶º·Œ¼?}¬j±ÂC6²©c&Ÿg¨ZÂs™…àò)Gv·"KCâÇŽ¿áhÁþ%üKþÊþÃÿ…‰ðYñ?öoÚ~ÓýŸöÿKuäyÛÍòüÝ›ö&í¹Ú¹ÀïõüSñÅßi eø¥éÿu[mZ·ñfŸ}q7‹5Y´Û-cì¶·6·ºM²Új6QýºH52Ï9ûKDûw?¤übñOÆoøF,þÜøÁÚßü/ñ6óVñLJçÖ<­+Ä?l].Æ->ËPµÍÉþν{‰šð$T wiy-0>üYñO>=|7‡Æ¾ø¦xšÿJøÓg{s¥$÷“i?ðøÇJÐã´²¿˜G#ÛOŽK’ÐÅö‰mm¤Û„ÿáWŒ~)üHÑüñN)~Ãð‹âN•o­é~m>úèšUݯÚl.®5q-­åÌ‹äyÖ)il¹^Ý}Zøø—ãŠp~Ôÿ>|3—áþ—ÿ §…|YâK[ñ>Ÿ}¨ÿddÝèPBÐY[\[ý¯ÌþÖ–‰®-öïIħìæÚëÌ4ŸŒß€tψšê|/Oé¿¡øS¨h¶f¢ÚŸˆn¿á, —Z†õîÄZTFñÚítÆ·ÔXCŒß—¸ßlÏüký¨|CðÛQøªØø«á}´Ÿ ­/µÏ…±è7þ-ñ¶¯§Y@n¾Ý{6~SÃV7©å¬7W–WPZÅqeqs"Érl ôýOãWŠtÿÙŸâëiþ‡â·„~ \|8Ó4ù ´«MWWÕ­íƒk§é_ðxÃÆú¨ð÷…tv¹û:žªmn/JÜ]”uµ¶†ÒÊòêivHâ+i1\Ü46Ógø'á•·‡ ð%÷‰“ã|ð‡õ=oSø[nú5æ§âÝ:ÂÚK«µ×f†Yàx¤0‡N²½H&…]o溊ö[ 0Ãþߎßò:ÿÂØÿŠ·þ??á^}Kÿ„Óû;íÿÙŸÛê¾Oí?þ>Ò¾Áöø•×?¤þÔz7Šá·ðŸ‹þ>Õ¼SðÿÂÿà°Ò¬´{o²h:ïÛ±¹»¾Ô-ìb¹ìY^ÜÜÍVn#†éíÀ ÚQÔ?kÿ„ž ð7€üAã|Eð¯ˆu›ÝvÈiÖ“h÷šv«¥i³%Ä÷ö×VÿÙí{rš…«Ú5ÚK%¼QFòÃw]ñ«FÙcá‰tM?âÄ¿|Pð®›®øwBH4x¼U¯Y½½Ä÷—iæÚé–¾Tw0µÌÆ[{Ešx`ˆ™nm`˜Öh¯ èÞðçü"¿5_ø¯Årxþ;L‚}wFñ2iwz¯ö}ü>x† ÐÙü·^kY˜îm¯>Ñý'ÛWBË㿇§ø{«_ÞøgÆ7Œto/„eðÄvøŠKe¥m§Aök©lg–]>æÞôËÛ[ÛÛ´²ÝMl–×FÜÏüeñßZ—À3XXøgÆ > èž5øYo©hž$F¼ºoø‡Å–zA$°º¾²1]E¯j˜\DÐ;”‹t¿AðâõÇõ_ˆ×fÔ/¼Wà¯xšâkǵ·†ÐèÍã/hzLùD–4nZ0Jù.^Wy €vÿÂ+ñóàN›¯ØÂA¢ZǪÞÞøOÄVÞDÅÅÍ•®·¥Oûèd¶º„<öò0–ÞöÂô$ÑMmu,Ÿ¤ø×ÄÞñV™à¿Š–ú†£¦Þ]æhÕ,¡Ó5©îGcgªÃ£Øjò¾`.–é§\Íöq–÷Ðép€{…Q@Q@WÍëàT~Ðÿ´‚¾Ñã øS㟇ì¼Igâ½Þ CL×Í€ðæª–wÑ£Ec-µ‡‡.­ê%yî/d‰® #´è4/†2¸ø™á­sâÄ=?âŸÃ‹¹ï| Ÿ††‰uì¶—s_êóGs$W×ÂÆêæöX4ûM×—rBßeûð/IÕG…|{ãÍLÔ4]oâçuO=…Ý»Ú4d)¡¿Ùe{YgÐô&æx.14w3Ü«¥¹g„°Ô| ý¡ûSø7â_ö§“ÿ…|Káìß³nû_ö½ÞuçùÛÆÏ+ûfÍ¿íÜž^ÏüMð/þ/ƒ¿µ„ÿá(ûü4§ö‡úWöo™ÿçÚ¼1§øoý_œ>Õ·û;í?zù¾_|ÆÐ×>xÊÛâg‰5Ï…ÿôÿ‡ö®à½ñ”7žÝÔ·±Z[éË£Í%ÌQXßKhOÚ Ô-7YÚH-}«í½‡‹>è>0ý–xÊÛâg‰5Ï…ÿôÿ‡ö®à½ñ”7žÝÔ·±Z[éË£Í%ÌQXßKhOÚ Ô-7YÚH-}«í ø9 ü6ø§y«xZo°xa>ø7áî‘ ì–_ì›M«½»}ªY^I·Å«¤Xq¹~͸¼†C³Ÿÿ…ÿ²ÿ†hÿ„£þiWü+/øHÿ³êý•öß±ùßö×Éó¿Ùó?Š€45φ2¶ø™âMsáÄ=?áýŸÄk¸/|e 熆·u-ìV–úrßèóIsV7ÆÆÒÚö¨5 MÖv’ @ßjûoxëK±ø⯠CðžÛÆ’ÇÁZ'‚íîÓá_‰~(h¦¤=а±’ßG¸…öžndd¸¸š®"ÔåR5 " §oüø!âo'ÃßxÃ\ÔÄZ§Åº°Ôa²—P¹_ø¢×ÄQI}=ŽË$¾·ŠÊ8®c´­šy¥ò$òbC/ xᇌ¾j>ð¾•ñO_‚þ´[/ øb? Öa²Žoia{¬Is"\ØÚ£â*ÎÞí…µ—ŸwrVé¯@; GÀ¿Úµ?ƒ~%ÿjy?ðˆøWľþÍû6ïµÿkÝè×^¼lò¿±6lØÛþÑÉåáüÿþ_üc¯ü ð”ÍUÿ…›öÿìßúÿá2û•çÛ—»þ›yòÊ€8þÎ_üAð'â§Â|dðÿ„¾üOÿ„¾YWþV¿ñ5”Þ"¸¼Ô/“ûFMHYÉloµ …Ø4ä—ìmä¤ñÜ…¾[ú§­¼Wÿiðÿ‹ì´ÿ%Ÿ€!ñ_…|[¦|sñŽŸñ Ïž¿ð”ú7†ôËÿ è £_ KÍöÚ7sË}0ÄféîI†(Ñm’Õ¤»’ïŸñÁÿ‰þ8øñKáÏŽ>3iúƉãokž Ò'³ð\67P.£lÖ£QÕØ]2_ßD›H)¥[3Kw›|=¸´ìÕ|7á[„ñ‰õø“X»mKWÔf£]:$f+ #$‰acEq[£;m_2inn¥¸ºŸ° Š( Š( ŠçüSâÁ~¾ñ'‰/¿³ô?ÊWu†[‰§šY-íà‰Zk‹™æ’(!·…Y¥–8£G‘ÕOŸü3ð¶»söOŠì>ËñOÄšTqK¥4Ñ\[xÂ.y4;š7Ù,q}²ñNëûˆCåÛCcidìPEPEóÿÅ_ø þ6|9øÅcû¸'Õt¿‡.µ‹†Õ´­rþ&P‹´Msc­ÝY˜ši6[ÙjéŽ7šáúŠ( Š( Š( Š( Š( Š( ¼¿Æ¿-¼9â«xoFÔü8ñ‡Å x+àW "éºÎ¿o÷Ší즖=Bk9âx¡›Ï‘.#‘%òvÒ¤²=°Aá‡_þ~Ñ5É<¨xÚÎêÓâªø¦çÃz†š-<#¨xÃÅZGˆP9Ô.m'¼±µ_Bg·§•m’O²FÒˆTðïˆ þ~Êž+oj)ñ_Áσéðëľ Ó5 6-LÉ}m ´óYÜÜ\Åa4¶·Z qñoÆ ?Äšžááx‹ÅžÁ:V’©§_­í›Y˽go4ïlžK{ •Ý*L°\€y~•ð3ÅÏãÿˆß…¾«мQªü ¾·³½×t›Íw[›Ã¾5ºÕ5ýK[š ™–mHZ:Nó=Ýì·qùg’éæ¶·ÐñÇ‚~'ü6ý›´ŸxVãOð_Åo‰_|7¦êo ⦙ñÄú”: ù['·1róÁšœå͵•Êvilî>ï🅴|,ðÏ‚|-aý—áéVZ&‘gçK?Ù,-!H-âó%f‘öE.çfcŒ’NMhjÚN•¯xWRеÝ3OÖ´MjÒk CO¿·K›KûIÇ,3Bऑ:3##¬¤‚4áÿØž)ø)þ‘áá&ø%§ó/‚ì´©î5ßÛ7úÇÑ9ÚôÛm¡“Fæâ8ålft·±ÒØ<-âÆž°ñ'†¯¿´4CÍTv†[y š)íî •Vk{˜&ŽX&·™XeŠH¤D‘@AEPEP^?àoŽÿ þ"|vøðÓÂÞ0ðþ¡ão…ú¬šV¯¤G«XËy'•og5ÅÌ6ñLóhf¿KdtM—p\B@d€;üBðį Ük¿|qàÿè–—ma>¡á½f×U´†éQ$h^[wtYBK'pYã 2^øÃJÑüUâÈuÝgÁú6‰áÙxƒP»¹×R;­6ÒW¾Ü_Ûº*ZXªX³EtÓ2ÊÑÞ)X…¶é@3ôï‹ õ}cÄZv“ñ/áþ©¨x?U³Ðµë[OØÏ6‰ªÝÝ[+´I [ÜÍv¦Ú8d ï(1ª—®ÂM[J‡ÅVZº–Ÿ·¨Ú\ßÚiïp‹uuilðÇq4p“½â‰î­QÝATiá AuÈøãç€!ý‹þ)|høsâOü[Ñ>x\Ö'ñ­Ý¥ÕÖ›b×Íd÷vþrC+'•œ«2,¨Û `¼Õ´­7QÒlõ KO°»×®ÚÃL‚âá"“QºX%ºh`V Ë(·¶¸˜¢Â8e|mF ŸðßÄ/xÇÅ^'м!ãø«[ðMذñŸ£ë6·×ZÖùcÞà ³ÛK¾ Ód¡[tR e)ñg…| àKïø×ľð†4¿+íš¾·¨Á§ØZy’,1ù·2Æ›å’8×s ³ªŽHx[ÅžñÇ,Oï|Ûö|Ûvó@Œ~,|+øwæÿÂÀø—ðÿÀ¾GØüÏøH|Cc¦ykûOÙ7}¢DÇö ï/?ì—så>ÓQñ×öíOà߆Ù^oü%¾ñ/‰ÿ´¾Ó·ìŸÙz5§‘äì;üßí½û÷®Ï³ãkù™@ ûoßï.ü/°ø{¯]µ†™â{iÑhÚÒ™U¡‚õ¥K(6×¢9`a”cälz…x¾>xÁž “Ãw‰<âoˆ6 ð†©øBßÄV©¬éVšîµ¥èë{=¢ïž8¢ŽÀ߬¢Méæ«ŽÃ_ø±ð¯ÂôOø§â_Ãÿ xÛÄ¿fþÈðö«â=WUûDÍooökIdY¦ófG‰6)ÞêTeÏøã¿Â¿ˆŸ¾#|4ð·ŒüPþÔÿ…gñ/áÿÄOì?#ûKþØêÿÙþvÿ'Ïû4åyžT»wcw–øÎÓ€@¢€ (¢€ (¢€ (¢€>›þ.—퓨è÷éþý‹íö2sm¬xîámµ;?:#±öFžÖ7‘n[Kq­Ûʾ]Þ’ÐQ@?ðãW…hŸÙ;Ÿ¼§øƒKðÇŒ>Ýö;]n ¿‹ì—“ØÉæ¤2Ë̶ÎWl•*N@>üjð¯ÆøYÿð‹iþ °ÿ…MñZøq«ÿjÁ_iÕt¿+íÛyRɺټôØÏå¹ÁÌkÆ@=‚Š( ¾ý«uÿÊøÿ¨Åû½CÃÿüC®éwKÄÚn«§ÙK}aynãæŠæÚîÞ ˜fB)aŽD*è¤}EPE|þÿ´çµ^ÞK¿ˆéþÕuT×ÛῊdžôÛ>ê[;÷¸ÖÎý›µ´öó¬×Op-âÈÏ"¢3 (?LÕ´­kN’óFÔ´ýZλ» '³¸IãK«Y䵺„²°ÜC,2!ù’HÝR…çþ:øá‡_ÙQxŠ_\êמÖ:_‡¼7«xU¸† ‚{…°Ó-î.¾ÍMn’\ÄQ½Åº;«Í¸a¤êÚV½á]3]е-?ZÑ5«HoôýBÂá.m/í&A$3C*’DèÊÊêJ²A Ö…gÙjÚV£¨êÖzv¥§ß]èka©Áop’ɧ]4],3ª’b”ÛÜÛÌÀcÑ>6º“¡@òjÚT>*²Ð¥Ô´øµ½FÒæþÓO{„[««Kg†;‰£„ïOujŽê £Ob ®t(¢€ (¢€>ÿ…‡®ü\ÿBøªx~oOþ‹©|S‚ú+ËhXó"xnÖº½ÌJ­ —3H–V—Æ6êrÚÞéñz‡‚|ះ¾¸Ò<1k¨GõÛ_ß^jz­î¯©ê—L‰y¨^Ë5ÝÜ« 0@<®É B¥bŠ4PŠϼ¼¸µÔt˜ Òu F-Fí­î.-ÞÝcÒãK(žq,¨íx’!Ydó'ˆ” $Œ‹IÒ¡ñUæ»™§Å­ê6–Öz‚[¢Ý]Z[<Ò[Ã$ ox¢{«¦DbUyJ€]²¡Eqþñ®•ãïÞëº5¾¡mgaâønD¼DI ÖªÝéN¡‡”×2´dÆ6BÊŒJ/a@sú„ü+«øïÞ)Õ¼3áýSÄÞû_ö¯w§A=þ‰ö¸Ä7_c¸u2[ùÑ*Ç'–˽@VÈ ‚Š+ÇüSðÞòÛÇwßþ^`üCŸÊ’þÂïR¼‹Ã~2HãXL¤{áŠæHb·…5h kÛqkh¤ÝZBö ø¡¥xÅWñéþø·£Z5æ¯àÙµžémÒ#¨Ø1XÞÿH‘äŒE|‘"îo&d¶»ŠâÖP Š( Š+óÃĺ¶•­xÓöÀøm¦jZ~·â±ñƒÀ~(ñƒ,îïYÔüo¥xkît˜Ë\ÞØË§E¨ZÉE/Úýª¤Ï(…À=¿Âþ,ð¯ÄïÛëAñ×Â?øÆþÒ>ëúŒ!ðÆ£î•qªÉ Æ…e=Ü a»¹¶…|A*­#Ù%ó³¬ ¨Än{iŸ#ƒã–âY4öøßñGá®±cðoYÐ/åÓí4MB]:é§ð¦‘y; Kë{‹+=NMJCe>¨²y‚Þ}Ë²Ïøi}yãÚcཧ‡¾,üñnŸð“ûF CÃß þ^xfóÁÚCé7K¤kÍs¯Ü6mö±§‘¤Kh.¤»ÒíȶTÓ®f³ôÿÚ'ÆÞøËðžö÷Å þEmiâ+ë/ˆ¢¸¼ðÖ¨ ±µM>;Oí-:Øj÷–·—Ïor×x­lµX¢âº¹d¡û$êz¦©ûJjw޼Añ7O¹ø«nÖ¾*ÖlìínuØáðÈK„v––²Û2ö{‹x+‹q ѼÉ(šOŸãñö·ìÿ§Yø/Çßì&ø=ûJüC×~%Zßþ+éRxƒÆi—šöm{k8¶ME´«Øæ’HÒÕ ‹Qr°ØÉ,`ˆôßøOþ|Gñ6½ã/‡ÿ¼ñâÀ­æï¾ þËð7ˆ®-ügco¨šáŠ5íNëS¼›Ášµ†O›añÂÚî±ÿ‡1Xy?>8i^ÖüQoÑG­aáÇÖ½,°–òåûL·Ñ/–x¤kÍ6õ­Ô4vÏ%˜Ïúï…µßè>5ðÿÅKøM´†¾+ø/ðu&ñ4Ñk_BŸ⺟í†VMs«xfëÀ÷ú”Š«Ô²DŽ«%£[Úûíÿ7õÿf«£îû@Ž~#ù?µü_¼5ñ÷öðWÂ/ü?Ó4/ xãÆZwü$¾¾Õ`ÕuVÖì´ÝNßZ°µ°¹‘SG3Âò3ß ÌjÿÙSù?GþÎ:«áŸØ÷ÃF­6¡,‰w¬ÝY¥×‡ŸÃ‹i¦\êww:}µ¶‘%ÕÔºmŒrÛAke4¢k{h †X­¤íâøÂûÅ?-`ŸÙÇáН¼?yûAøâÁùüKṡ[ßè,(ÒW[Õï£Uy­¾Õ5ΠÇW—lÇT£¸¸”&ãøÿãý(þÈÿµ¯†§øÇàÿ…zÆ¡iñY¾èÚjj‘}§[Á|¿gÓlÚÇKk*ö 6@`ñOŽ<c­þÚþ¾¿ð~¯â+¯‰^¿Ôü;©ê„.Ÿá«ÁZ}Þ¹«XC ñoöŸŠ¼Qc÷±|U«ê:ž½¦ùGçƒìZµÝýŸÙæ-4gò¦g–7côPÀðL/ôø#Ã_ ^¡ø›ÀÚ¯Š´/i~îÿÃú¬zåôÏe}nq%µÊÅ<2eUp²ÆÅpÀŸ“þü<Ò¾-~Ì¥¼øƒàÿ x7Æ?¶ÿˆ|eá‹O]¤^øëi±›-. ¯,u Ëb¢X¡¿PöNÉmpðíP ‰^9¼øiûÁAüðáOü3÷Æß„ÿð…_x’ßáž»y¬xoì­½¡}KH„ÚÚ&ršLw¢òk}>Ù[Årg‘ãAèüÃßø)ÿìï§ü*Òÿgÿƒ~ñGÃýRøWá—ŒµÏÿÂÆðœ™Ðõ{ÓýƒogÙï¥ýÖ¯y:O{ö™ [‰ÎapÃþ WàXÁ#>|DƒÃÚ{øïZ´ñ&q¯Ü)¹Ô#Ó—_½ÅŒÊYí¬wÀ“XLp̳˜ÌÒÉ#þ—ÐE0?à©_#ÿ†Yø-à]+áÿÃ/xþ x‡S×u4?ð‘[YyvfóRžÚHt­6x|·•âµ–âÛËiw\Æ¿á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“£þ?Ú›þˆßìÿÿ‡“\ÿæN€øHÿjoú#³ÿþMsÿ™:è<-­|}»ñÝ…¿~|ðÿ†$ó~Ù¢|KÕu‹û|FÆ?*ÎoZG.éDjÛ®#Ú¬Ì7•ÀO¦üS¸ýˆ¾%Ùj>2øiû=øËâ¯Å/ øâÞ?ß7‰¼9á]SÆZ曩êPê­«-ˆû;Ü™n.,’+1qs"ÝO&ë ñ—Œ>!ø)þµáôño‡ü=«Xü@ðu§„,u‰ZõŽ«¨ø6KMmdXxÒÂkrÚW›ÄP6¯rsjâåÞkhô”’ ÿ…Úï†~üð-õ‡ÄCGð7„?iÿŠÖõ=gÆ÷·¶Z¦|]oeµw{s µŠ[‡ðü¡.]k»»[†sv%— øGâ=Wâ—íðfâŠ^0Õ<}wû@x‘?±|Jï§xªÓJø…¦A¡¤³ÆÌf±‚ÞdòD2"´ öbÏe=żà²ÝïŠtÿøewÕ~ |@ñ¥ÏÆo€ž2ñ\Þ'×gÔþÙªØÿÂ*–2A‡É´òaÖo¡f¶HžïrMx×w+çׯëþ,ð¯ÂOÛëÆþ:ø¡â_ü=ðGŽ~ø7BÑ øÕñ[ڵῈ¿Šµ»ëséöÚŒ`íü74«&"Ë2\j”Ö6-nÖÈ5?ÄÖ_µüjø•'>ÚüQð|[ xo⇈|g«[øÛÁ²GªÏoá‹[]&×Ã×RÇ–si ‘m;G¬Å¨+É Ãk‹€»þ;ë_س>¨é7ˆ!¹×5_øjÍtmWû"ææóWÕ¬ô»kwÔ9f±¶škÈḻ¶F»··’i­qs$|Áð›Âð­੾𭟆gÿ…ð”ü*ñ^»«xáföo²ý›WÐ-tûÍZð-¯ö®ï7SûϦY}›ÍÔ`Cq™%`¿è Šòÿ‹Ö^ —àÔÚ·ŒõmCÃQxjîßQѵý) ë:&²ÄÚÙÉ¥¢Å+Ï}+Üý’;E†qz.šÉຊêKyO„7Ÿï~ @ßôCJÖí®ç·´:«é£Y½Ó…‚}R2Y´øo˜n )ä‚P©:¥‘œØY€z…Q@Q@þ‰âÏ ø—Éÿ„sľ×þÑ¥iúì_ÙºŒ^n•}æý†ñ|¶9¶¸û=Ç“0ù$òdØ[cc  ŠÏÓ5m+ZÓ¤¼Ñµ-?V³†îîÂIìîxÒêÖy-n¡,„,7Ë ˆ~d’7F”¡@Ÿ&­¥Câ«- ]KO‹[Ôm.oí4÷¸Eºº´¶xc¸š8IÞñD÷V¨î ª4ð† ºçB€ (²ðN•añ÷Ä¿a¸Ô[ñW‡ô? ÝÀî†Ò;M*çSº·xÔ q+>³t³²•HBªÅû ( ³õm[JÐ<+©kºî¥§èº&‹i5þ¡¨_Ü%µ¥…¤(d–i¥r8‘™ˆUPI Т€ (¢€ (¢€ (¢€ (¢€ (¢€ (çÿÅ»ý©ükðšO“Ãþ5þÒø›à®þ_Ú.ãÿ„žÇî|ZþßSó§ußÿ Ùíãií·è ( ñOìõð Ç;¾ñO~|ñ‡‰µO+íš¾·àÝ+P¿»ò£Xcón&¤}‘Gk¹ŽF½Å>ð¯Ž< }áoøgÃþ0ðÆ©å}³HÖôè5 ¿*Eš?6Þehßd±Ç"îS†Ea‚  ÿü<ðÃ_ Üh_|àÿh—wm>Ÿá½×J´šé‘#ižtDiJE#qXÐg 1Ÿà_„ß þÿj³øiðÿáßöç‘ý¥ÿLJ¬tí'“çýš4ó|¿6]»³·Ì|cqÈAáo øWÀÞ°ð·‚|3áÿøcKó~Ǥhšt}…§™#M'•o ¬i¾YFÚ£,ìÇ’MtWþО)×| ûüpñ¯…¯¿²üMàÿ‡þ%Öô‹Ï&)þÉi§\Oo/—*´o²XѶº²œ`‚2(â +þ —ðãÀ·eßíðÞOǨxKû ãáïÃÍCJX¼3§M§éñØÌ5 £ö‹©în!u ˆ%´¼aw$Z‹¡ŽOÐÿx×Jø‹ðkÃÞ5Ñ­õ =zÑf“OÔQ"Ô4{¥&;« èQÜA}kp’ÚÜÀX´3Ã,mó! Š( Š( Š( Š( Š( ³õm'J×¼+©hZî™§ëZ&µi5†¡§ßۥͥý¤Èc–¡pRH‘‘VRAðÿìOüÿHð„?ð“|Óù—ÁvZT÷ïƒí›ýcè‡ízm¶ÐÉ£ sqrζ3:[Øé ìñNƒãOXx“ÃWßÚF¡æª;C-¼ÐM ö÷J«5½ÌG,[̉,2Å$R"HŒ  ¢€3ï4+QÔt›ÍCLÓï®ô ¶¿Ó'¸·IdÓ®š mZh1Jmîn!.˜cÒ¦v»ŸÿŸ…áþÇÿ„gÃÿÙÚ¿Û¿aþ΃ìßÚ¿nþÓûg•·oÚ´?Ó<ìoûGïsæ|Ô¡“¥Câ«Ív3O‹[Ôm-¬.õ·Eºº´¶y¤·†I@ÞñD÷WLˆÄª4ò•»gŸ²øyà 7ã.­ñNð?ƒì> ëÖ‹a©øžßFµ‹YÔmD« ÷ª‚ybÚÜw*1 |‹€ ðŸ…dð&¯ái<3áù<1âííM!´è †¥ý¡$³_ý¢Ü¯—/Úe¸žI·©óZi÷bsï>xQøË¤üEÔ<àûïˆ:£Xiž'¸Ñ­eÖtëF«Cë!ž(ˆ¹¸‘4£;d Õ´+^𮥡kºfŸ­hšÕ¤Ö†Ÿn—6—ö“!ŽXf…ÁI"tfFFYIkðwÂo…ü¯øWÿ >øÈûg—ÿ÷‡¬tÏ/ífûV߳Ƙó¾Ácæcïý’ßv|¤ÚèP^_ã_‰–ÞñU¿ƒ<7£j5ø—ªÚ%Ο ÙÃp¶–±Èï7:¾¢Ë“bÆ–\~òu³»K8onbû3gø[áVÏØ|@ø¡}áÿˆßô¿6=+[‹AþÏ°ð­³ÆÐ<:”ÓÝI§ùñ;©¾Ó-ÅÓ>Ù%û46–Ö¾Á@Q@WÍïwñâwÆÿŠø¨|/³ø3â ? ÙYÙèÚn«iâmB]MÖÚãWp´ícVÚÔZØMa8XnÜÞ¸„X€|¡ðãâŽü#ÿ²ñ/ü#Úçöü*ÿدá×¼3þ…k/öf».‘â?2ç÷‘·›Ÿì?÷rïŒy ß&ÿpøã|5ñW~ø“â‡ÄûíSâ]§ˆüW©x¿Áÿ Æ¿©èqé¤Àt½H°Òï…¥Œ—¢È·Zœz”Öï4ÓÜÁulh_|}¯xÃ^ „øÃEÔ¼_ñ*†Ú?Äx2ëÃÚµþ‘†îÔ±y‹t¼€|ðGîü+û éZOÆ_ik_³®¿ªK«¶ Üêz.˜ÉàBšf”ZÈZGL°âkûmBc ¸Œ¹’H®-½BããïŠ[Â^ð&·â_ˆ6¡¯j¿l/¼kà¿Ïâ¯ËgàÏ&m·M³Óo-`¹½Yígº¼{#h†+ˆa··{»g´ú?àGŽ…¥xƒÄÞ¿ð®¡ã 9l­.£Ô%Ó/-­žUî岕ãŠ8'žÆyáŽÞ)VÚÀ÷þ'ø‚÷â=‡Ä}CÂ:&…ã_øZÇ£i·º5þ¡ëWz-Ü×³É ê}tl®®!’ÚîÖ c%’=µà·¸kðÄ~!ÙãâÇí%aã=CMÑ>]øé`øqŸ¦É£kúw…/õ >ì^ÞÉlÚ€¾½:mÔ°Ïmq†k%{KÑmpoùÿˆ^4øÃa¥~Ù´¿Šº†¢~Í—w7Þ𭞤5¦¬Ö~ Ñõém5{›‹yn'±–êåÀ[G²¹g»jpÖÂÌø…ãOŒ6Wí‘ñKø«¨hú'ìÙws}á ÙèCZjÍgàÝ^–ÓW¹¸·–â{n®\´{+˜Ö{±ö§ l,ô$ø^ÇÆ?þ¢Õlt}>ßÁÿui^%¼ŸI°ÖmjæÛIºÅ°þÑ‚ÛìW:}Ú¤7µ×ú]·ØÀ:ýÆþ6x«Dð¼:ŸŒ?gk»/†¾ ø‰¯[é¶zmæ¿¡âÔ¡]"S«ØM¼V'Hºî³óç–h6µšÛË߈|P<ñÛöµø›añwÄÞ-ðìÕáß­ž›¡è°è7Z¬þ2XYm®­.n㶆öÕïቯd2æHæ–æÝc†0§üQ¨x»Çµ>½ð§Ãž:ñÂÍ?ÁІïM’]G§ùò½ÌÞTé|±ÛÝM2̰ßBïÿüS®ø·ö{Ï_jêÚŠücá7Ô¡›S‡Cñ£¢Áup‘*B.f†Â)fòcŠ#+ÈcŠÊÆžÁ@Q@Q@Q@Q@Q@ñ#À¿ðžxÎÒËTÿ„wÄÞÕl|Cá½mm¼öÒu[IÆÌã‘í§ˆÍewS@÷Ww–âX„åÁðÏÇ_ðŸü,´Õ/´¯øF<[§ùz‹<1%ÏÚ.|'®¬1Éu§Í&Äó|¿5)ÕwVòÛÝB^Þâ)Ð( Š( Š+çÿñSµø=ïáiø®Óûr4ýÿ—á]#þ&ú¯Úíúý6÷ì–šϘVý¿ Éæù‹opôxôWáþ£âŒ^Ó5 ZîCã?éÖï<ž9´µ€(šÆCo Elàm½Ž8¬nHU²»Ó=ƒIÕ´­{ºf»¡jZ~µ¢kVßéú……Â\Ú_ÚL‚Hf†T%$‰Ñ••Ô•e ‚A­ ( Š( Š( Š( Š( Š+ÇüSðÞòÛÇwßþ^`üCŸÊ’þÂïR¼‹Ã~2HãXL¤{áŠæHb·…5h kÛqkh¤ÝZBö ø¡¥xÅWñéþø·£Z5æ¯àÙµžémÒ#¨Ø1XÞÿH‘äŒE|‘"îo&d¶»ŠâÖP —üssñLÿÁS~ éñLJôO^ü?ñ~¥«è—úõ÷öØõ ¥Ã‹R·…nL7©¬ï¿eÍé)r·A òþÚ¾ñ±à/ÅñköÖ|1ñKUÐt}/ᦑ«@ÿ|?ýµu„×n5Žêæ9n {ë²·ûrÝlº¼6 öðþ5|}‹á†¯ñ6-?àýç†4ÿŠºÃ-/«m¯îñœ¾°½¸Ö„²G¥ì–H$šÓµ1mdt’#v°Ùhx·ã7Ƈiãoj ð¿Çÿ|;wð®çL¿·Ó5 è×öž/ñDÞk)àk½Jx%„XÜJ/IW7Q¢7ÙØ\€sÿ´'‹<}¡þÅÿ´'ÂïŠ:ƒüQ­ø£àWÄèZï…´;­Ñm4Ëm/­.ìn¯¯]%WÕ¬$†xî]fY.á¶6È÷ÿÅïŒþ!ðÇÆY¼£xÿáÃJÊÒ › YðÅÿ¼]ã¨æ½Î“á½R¶ÔÆØÇ,m1Žy$h/¡µ·³[›° ðwÇ^üLñÇÇýw\Óôÿ‚úìëà‹š‡€­´{­GS²´»´ñ-ì°X^¾£ ¾Y·›rÖj·0¥œ-Í¿Ú$ô‡_´þ•­þÐþ ð^¡ñ‹öoø§wñJîòÏLÑþkIy¨x6êÞÂëThï$k鎩cö{;ˆ –ús,éj>ÆVõ¾Âö}óÿü,=wâçúÀ­SÃóx ô]KâœÑ^[BÇ™Ãp&µÕîbUhd¹šD²´¸–1·S–Ö÷O‹Ô<à? ü=ð­Æ‘á‹]B8¯®ÚþúóSÕou}OTºdH¼ëÍBöY®îåXa‚yåvH`‚+Q¢€vPEPEãþ)ø=g¯øîû\Ñ|qñá×ü$¾Rø¶ÏÂw–vpøÁ#`Fº’[in-.E² o·i²Ù^˜–7ì–fزý—üað Ä¿aÕü`Ú'оè.ç{«Su¥[jv¶÷°·/™5›¢îÈÑHvÄ€0Pñ×ÃÛ?ÿejº÷ˆ<ãùë£ø«ÃÆÌjºd7ݺ‹¸.-g¶¸X¢ó-î`š"ðÛÌn-­¦„Ÿÿ…)á_øUŸØ_oñü$Ú¿ð“ÂoçÁÿ 7ü$ÞOÙÿ¶>Óåy?iòѼŸ'ìcÿ‰Ù¿³¿ÐëŸÖ~Ë­ø;Âp\üdø¾ž0ðŠäñ…§Œ¼í}UïßK»ÑŒeŸM“J‚Ûì²ÅäÛX¥Ǟsq$ÓJÀ|Vø g­ü"ð¯Â] ž ñ6‘¯|@× ÞÜéÚMõ¯Æ‰ú?Ä FÓ/¼wcoá¤Ö|C¦yòÜCg¨[6”Ú\ÑA$ÌmÜX¤Ð˜G"}®óí>¡áo h> ð%‡†¼5aýŸ¤iþk"4ÒÜM<ÒÈÓOqq<¬Ó\\Ï4’Ï5ÄÎòÍ,²K#¼ŽÌ@<áWì÷£|+ÿ…wäøïâ?áUøWRðO†¿á!::ý‡A»þÇÅ«}†Â×Íò°-<¹$Ý!ó®<Ç—1ùZà?‡­|—‡|Kãø“MñŠÂKå/‹lü'yggŒ8Ök©%¶–âÒä[ ¶ûv›-•é‰`Sp~Éfm€ àÖuý‰qà/øƒà¦­ éVÞ‚ÿÀöš<>nƒm¸Ûi²ÙßY]X½µ»³5¾müËmó¬CÍÒOÇøÃöhð÷‹µ+|@øŸ¢èž7øk¿éú……üzÎ ¬ÓÏy¨ÙÝj } Öîå‹ e‘b3‰Àpàã_†ø§ÅVþ%ðÿÙâßbÓ_ÑíæŠÖoølGqÿ³,̶âæÞæà_YI>вÇ=¯Ú,­õ+ÉÀaàŸé^9ð­Åõ…¾¡¥jZUÛi𿇩¢E©øwSDI$³¼Ñe ,R£ÆòC<3Aq“ÛÏ ÒvQ@Q@|ÿðSþ.Ûþ>êŸé¿ð°<ßø@|ïŸûÀäý‡ìÿwËþÕû4ZÔûâŠä}®ÒÎçÌþÌ·òÀ>€¢€>ÔâÉ|S×ü^ÿèß¼[²÷^Š–ÛÀZëMq-î·,g;4Ûÿ:}$F8ìî-ÚþX/µ;ë_ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€8ÿø'JñÏ…mì/®5 +RÒ®ÓSÐõÍ1Ò-Oúš#ÇåœŽŽ‹(Ie‰ÒD’áš{yâžÞy¡“ÏôŸø›À~*Ó<ñRßPÔtÛ˸tÍâZ¥”:fµ=ÈìlõXbt{ ^WÌÒÝ4뙾Π’Þâú. ü<ñN±ûSü2ø—áoøAÿ„+J×<=«éº¯‡gÕ?¶4­VïHº¸[i¢¾¶ûÊÿb¢$®—(<òLM´ÏøOàïŠ|)ÿσm>$y¼ö!០iÚLöì6Ö[>Á§_ë‰x~צÛmDX’ÒÞâxíí¢¼¹¼Cz/ÀøQñŽ¿ð€ÂQÿ5WþoÛÿ³êwÿ„Ëì>Wÿn^vïúmåÿË*à?h„Zî·'‰¼_á­_Ä «xÛUø%áô‹DÒ⸿Ð!Ð|ru)õHšTž<¸uifa5»EØ´’ #fTßñ?À/üIøYñÏâ‡Äë6ñ‡Ãÿü8Ñ5oxR}JðÆ•­ÃÞʺ|ÚÔ×W2Ímdò4·6XÛ¤1Ú³\ÉuÐj þ#éÿ|u¬|:ø¡áÿx⎫m­ø’+ï6¯­Ú_¦›e£¼ºE鿊ÒÛý L³h–îÂýRàK$‚xœ[ á/ÙjóÚ>“áKÆ~ñGÃ-Cெ> ø×C»ðÕå½ÿˆì4k]ZÙnlõ54þÏóÿ¶dó#0ܰX‚¤¨Íæ/¯ø[Àßí¼wa¨xÿâ·ü&:G…üÑ Yézx~kÖxÚ´ëòCu$:ÊÂÇjA…–Y¦û‘,͈ x§Å:‚ü }âO_gé”®ë ·O4²,0[ÛÁ´×3Í$PCo <³K,qF#ªŸÿ„[Åß?Ò¾%XxƒáïÆÿGo†sͤÜ\øžþ¸øŽæÕ®£6Ï* O°»ò¥·Yô·qÞɧـ}EPEPEPEPEPEPEPEPEPEPEPEPEPEP—ø×áV•âï[ø£LñŒ>xîÎÑ, ñ7…¯ÒÞéíÝ–»KˆçÓõ(Ot!MBÖåmšîâKqÒkÿ„ûâŸÃ¿Ý|XðWü&¾Où~h÷מ^yÿMðÆûNß2I ¼_ÙÒëöMqqýŸÚ ‡‚~5ü#ø‹â«ø+â7ƒõïØZ5æ¡á¸u8“_ÑãGH¥[ý)ÊÞYK²Ç ±\ÃÊÂ9å¯P Š+?VÕ´­º–»®êZ~‹¢h¶“_ê…ýÂ[ZXZB†IfšW!#‰Y™Ø…U’ ÿ’ÿÿfÿÿ«WÿÁ¿ý;ÿØ+þC?@PEóÿü›ÿý›ÿþª¯ÿÿôÑÿ`¯ù€}EPEPEPEPEPEŸ«i:V½á]KB×tÍ?ZÑ5«I¬5 >þÝ.m/í&C°Í ‚’DèÌŒŒ ²’ Їÿbx§à§úG„!ÿ„›à–ŸÌ¾ ²Ò§¸×|lßëDxä?kÓm¶†M[›ˆã–u±™ÒÞÇHo`ð·ŠtxÃÄž¾þÐÒ55QÚmæ‚h¤hg·¸‚UY­î`š9`šÞdIa–)"‘DeQ@y~&[xsÅVþ ðÞ¨x×â^«h—:~ƒg ÂÚZÇ#¼pÜêúŠC,M‹nXMqûÉÖÎí,á½¹‹ìÌŸáo…[öÏ@ðèvSOu&ŸçÄìn¦ûL·Lûd—ìÐÚ[ZûPEPEPEPEPEPEPEPEPEPEPEPEPEPEPã_‡žø•á[} â/üãýÒí/àÓüI£Zê¶Ý*üJ¾þÐÕµ5|%âÖ†+x|k Q´¯op‘*Ão­Á rI5¼j‘]E—–ˆ‘¥åž˜ìPEPEPEPEPEPEqþ5ðN•ãŸ ÛØ_\jV¥¥]¦§¡ëšc¤ZŸ‡u4GŽ;Ë9P’ˤ‰$3Ã4öóÅ=¼óC'Ÿé>5ñ7€üU¦x/⥾¡¨é·—péšĵK(tÍj{‡ØÙê°Äèö¼¯˜ ¥ºi×3}œA%½Åô:\ ¡âŸè> ð%÷‰ÂïÊ–ÝdÒÝÇ{&ŸfôQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@W?⟠h>4ð%÷†¼Iaý¡¤jS:,ÒÛÍÑH³AqoÎ>Û§\(µéekìQ@Q@Q@Q@Q@Q@gêÚN•¯xWRеÝ3OÖ´MjÒk CO¿·K›KûIÇ,3Bऑ:3##¬¤‚4òÿÁx1?iŒIáí>í¾xÖ ü;Šn—Àº5׆4}RâÓGYK žãZ¾Œ‹p‡ìÂÒÏ?d²³‚ßë ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Šãükà+Ç>·°¾¸Ô4­KJ»MOC×4ÇHµ?êhw–r::,¡%–'IHg†iíçŠ{yæ†NÀ>5ÕuOx‡áÿ-ôûO‰´ÓïuFÓ×LÖtË纊ÃT³îðEpú}ê=¤ÎÓ[Mm½k¨i_ðøÃÁ¯ü#Þ*ÑÖçí隨µ·½ ovêÚkKÛ;¨eÙ˜®cEmp³[CèQ@Q@Q@Q@Q@Q@?üÿ“Šý¬ìªé¿úƒøR¾€ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Šòÿø'U¸ñU¿þÜiúWÄ*Ñ,™o]âÓ<[¦#¼£JÕ hî±–g¶»HäšÂi¤’4ž ïl¯ºø×JñÏ…n/¬-õ +RÒ®ÛL×4=M-Oúš"I%ähî‹(Ib•7’áš ˆ$žÞxf°¢€ (¢€ (¢€ (¢€ (¢€ (¢€>ø7ÿ'ûXÿÙUÓõð¥}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ãþ)ýž¾xãÇwÞ)ñ¯Àïƒþ0ñ6©å}³WÖü¥j÷~Tk ~mÄÐ4²(ãw1¢¨ÀW?ÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Qÿ û,Ñ´þÏÿøo4?þF þ;öXÿ£iýŸÿðÞhüGü2wì±ÿFÓû?ÿá¼Ðÿù€ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#W˜x×ö;ø¥xªßÇÞý›~ë×v‰g¬ø2oèIiâM9äÀÏ Áe«Äe‘¢”´p]«}šñ‘~Ë{¦€uþýÿc¿xÃÄžýÿgýCHÔ<ÕGo†ÚE¼ÐM ö÷Kh³[ÜÁ4rÁ5¼È’Ã,RE"$ˆÊ:ødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#P˜xö;øañ[ãu׉ÿfßï¢k^5´¼ðŠÜx/B¹Ž=|9¢[ʰF!o³Eý§¨LDFL†Yv‘(wôÿødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF£þ;öXÿ£iýŸÿðÞhü@ü2wì±ÿFÓû?ÿá¼ÐÿùødïÙcþ§öÿÃy¡ÿò5ðÉß²ÇýOìÿÿ†óCÿäj?á“¿eú6ŸÙÿÿ æ‡ÿÈÔÃ'~Ëôm?³ÿþÍÿ‘¨ÿ†Ný–?èÚgÿü7šÿ#Pÿ û,Ñ´þÏÿøo4?þF®ƒÂß³×À/xîÃÅ> øðÁþ&Òüß±êú'ƒt­>þÓÌ¡“ʸ†‘7Å#ÆÛXe]”ðH `¢€ (¢€ (¢€ (¢€ (¢€ (¯?ø±ã¯øUÿ²ÇÄ¿‰Ù_ÛŸð®ü+¬øŸû7í?eþÐûœ·^G±ü¯3ÊÙ¿cíÝ­Œ?Óþ%üSÑ>.øß¾|?ðÞŸñ#U¹ðö‹}á?ßx†dÕbÓoum·P]hÚrÅlm4»ÑæÇ,®%òÊ)#ˇŒhï‚þ ø5ñoƳüCð~½gðBÒy¼]§èºöu¨iWHeŽ+ a3¨†ú{ˆÖ&hÚIÇ–>làÐ"ø…à ¼+y®ÃãË¢i¾¶ñeÞ šÍ«ZZè)4–úœ’‡Ø–2¥­Ó%ì•b#l_¼aâ©t+ïx>Ë[‚î; tùõ›X‘ì#HZpâV}gH@„n-©Y3qðÀz·€5ï†vºïÃKÁú׃u«½BþÛPð½Å­Î™u5ÜÒ_L’Û’½ã\´Î f˜Ê\—-^^ÿ¼S{¬jþ ð§ÃøJ~x[UÔt-g\´Õ§>#šóNº–ÇS“KÐ#³‘¯­­.áš uÜÆÒìÚZ^¡ý¸Ô/>!xMøË¤ü9Ô¡‘ÕÞ[§²¼HAiZÖpŒO´ŸðÆ|Jø™ñOÂ>×týW[ø;â¼7â( ½µ¡º{HnƒªÃ+ºÄYí •casc{ÜÀÄú…PEPE|añ@Ô"ý¡üg­|SÐ?hýÀ—vrxo]øaã/YéÞÑ……¬&ÊóDÐ5;}RòùµtÔf3Á¦ß‚ö×̸H`t³ÐÕ¾>ë¾øX¦ÏþÿÚÂ…ZĈž9M^-þ âìj: •¥µÕ­åÍÊèzȶ{‹+uó,Ñ.%w·ïõŸŽÙð±ÿâ–ûGü+ÿо øeÿ!-Ÿoÿ„ƒþ¿ôßõ'Ëò?á&ÿSóùŸdÿY›û®>Çö‰ñ–µ§mѾéðj^!ø•â/…þ Ç‹…­–¿¨hsë­ys5½Ì¶6?cðô¦"`šw»w ŽÝ#¿¸>'þÒ× 4ï‡zG‹t…þñߎ-5ËÉ ø…ñ*ßÃ~·HžÒÖémµ”³¹{™g}BÖ{8šÒ%µóälæˆÛŠ¿µÛÏø#¿>>ü!‡û?VÔ>\xóÃg[x­æÒá—Lû|sJ‚+¨^æÞ2¬^)e‰bi72¨!ñ›ö¾Ò¾x©4/Zü/Ò5¿x*ÃÇ,Óõ_ˆ‰¦]]ZN÷‘½Ÿ…!šÄ>¿|¥Þ Ša¦«4šx.¦åþÏ¿âŸÚGÄÞø™ñ"Òƒº†¿àß…Þ5ðï¯õK/YG©ëšž»i¢¾™•a:ÇÊ·šõ´?m»²†(LsE5Ó´¶öàçíã+'Ò|.¿ ôýWâÇĦø_¨èúw‹Ñ¬µð´¾+·¼‹S¸³†Y¬VÏì‚ä›8爵ߑëA w”4_‹šï‹i߆šµŽâä|?øÇk¬x;KÕ"–OÄ~ñ‡´yRÖK‡¶·¸ÅÌZ„Vw7BÔ˜®·H¶¾l¨€_­þÖÞ2ñwÂ^×áOü(ýwÇ~ñ¯ÂëmNïÂ_‡‰|4ú7ˆüFºZÚÿi®½/¥{Yí®!6`ÛZÞÅw ÓLÞ½Cŵׅ|+ûdÜü+¸‡ëý‘â¿x*þÊ÷ÇZxÊïUÖ×Ok9ô¯vûvšŸÛ>uË]Àè!ÔJÁ'Ù\}EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEãÿ´'…µß~À¿<ákíOxÃáÿ‰tM"ÏΊµßÝé×[ÅæJËo–D]ÎÊ£9$Myþð./~Ù>ñv„ÿünÑ?gÙW²Ð¾/ø?Äß~_ü8ñ6‰à{ßÜx/$] PúÜ“éi¬|?4…¢œ]ƒ=ˆ€n’- [öfñ6ð ã'‡4Oé÷ÚÜ¿²W‡~ ø:ñõK+Û©u;[oEy§G¨K£ùN÷+<òAg ì!sf&H@>Ÿø_¡x›Bý¤iuŸ jn‰âÿé$ðþ°÷6RZk6‡Ã.—2GsµÄRÁu¤Î®'†%+$-J ì÷ ( Š( Šðýsà½í×ÄÏx›Á>'ü)“ÆWpjzõ†íü5wiªjqZ[éëxÿÚúUô±Êlì¬mÊC$pí¶F Y$çõ¿ÙÀ…l|5¡êþ0ðOƒO‚´ß†Úï‡ô{«Y­ÿ†§ÿ…)ý¹ÿ7þ_øM¿±¾Åuÿ µýƒí?hòþÏÿ?»òüÏ3ø¶mù«Ïÿá¨þÿà ÿÃKÿÂsÿKþ†?ì]Sþ‚Ù_ñçöµÿÇïîÔÿµ÷>jðøz?ì'ÿEÏÿ,Ïÿò¾¾¿ðïÅx¯ã·Ä_†~×>ßão„ßÙð•é¿bº‹û+ûRÝ®¬}$k Þl(Ïû—}˜Ãín(ŸÑ¾=|&ñí“âÏÙûHñ_Úþ.øJ‹[ÖôìËøþÅa"Ú:Kö§„ZÉ•Ô,ÎØåfýï#å}½ü-ÃSÿ”þÜÿ‹›ÿ¯ü&ߨßbºÿÚþÁöŸ´ygÿŸÝù~g™ü[6üÔèPEPEP—ê^5Õ|!ñ–-7Ævú|>ñeÝ¥—†¼Ejzv§(ŽÒµ`ÎÂ9nn9³»]Í$ËbéÈ´mSÔ(¢€ (¢€ (¢€ (¢€ (¢€>ø7ÿ'ûXÿÙUÓõð¥}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|û7Å£ÿ‚«þÖÿ³íçú>ŸãÝVßã÷ƒZë÷÷ú½¶´ÏÄ<Ðþæ+kmRÞx •"¸ÚÌÄÜ'ïý‡âäxïöšý«:í ñéÞ¸µýÕ†­àß FÚ>‘~–ÒfêÞæf[Ñ:Ü,Ñ+,0¡þÿÏýýðŸí·ÿ _Å? ø[þößð×ü$º­–•ý¯®ü,û•¥}¢d‡í7—ko&Ú-þd²m;Y°qŠçÿäPÿƒš¿èWðÿÆ€õågãoiZ×ü5 JÏIúi4üøàÿüKáŽÿm_õßð½¿j¯ˆ?ñFýßì?øNüÝþB<ý£ì?Ø_hÿh¾ÑöŸ/÷^÷ûÿözÿНþ kûuxéÿâ¥Ò<5ÿ<5âÿL¶Ò¾Ï¦Iq®hÖ72Ãåj ·–‘2ì¸diPHA ¿è Š( Š( Å>Ð|iàKï x’ÃûCHÔ<¦tY¥·š ¢‘f‚âÞx™f·¹‚h➈]%†X£–7IXyÿ…¼S®øgÇv ~%_hjÚ‡š¾ñkC¼>5†(ÚW·¸H•a·Öà†9$šÞ5H®¢ŠKËDHÒòÏLö (¢€ (¢€ (¢€ (¢€ (çÿƒòq_µý•]7ÿP WÐQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@WæüWÂü?uðããßÀo ü@ñÄm7JñwÃ-VÃÀ:uðÖït­{GºW·v*óý›IÔ`Šò^6O´NŒ’[ɇ`»þ |/Ò¾ þÈÿ>èÇOšÏÀ>±Ñ仳ӓNSºŠ .¯Mº3幸óndË;&rÎìKÉøTßÿâ øU¿ð­> ÂÍÿ¡Gþëïíßù~×ÿ ÿ/íñíûÿ¹þ¯çû¼Ð×ÿðß_õe·ÿþþì¯/ÿ‚—|<ñö´ÿ>"ø3Àþ0ø‹gáŸüTð=ö‹á-ëWÖRëÅ~¸Ótû¿³B„ n!âVudÄ%fÚ=Ãã¿À¿ÙÿÁµO‚žñGˆ$ñ·Â¿‡þÿ„{YдÙ×UÕ5_ ‹;ûO±[Á7 ÍÔÚTqÅåHï̬¾k V?a ø§Føñ£Ç^)ðψ<ÿ ×ãW¾#éñ>›®èÚUíÄvöñjV’¨ò.[ìo.ÔiPÇ,,· oÑ@Q@Q@sþ)ð¶ƒãO_xkÄ–ÚF¡å3¢Í-¼ÐM‹4óÄË5½ÌGðÜBé,2űºHŠÀÏüâwDø§ÂOßlø™´«ÍoÃ~#Hb‹þíÎkk{™nà…V;MJÖ[ûîU;{´Ãqj#qe§{PEPEPEPE|ÿðoþN+ö±ÿ²«¦ÿêáJú€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€8ÿø'JñÏ…mì/®5 +RÒ®ÓSÐõÍ1Ò-Oúš#ÇåœŽŽ‹(Ie‰ÒD’áš{yâžÞy¡“Ÿøqã]W]Ô|UàïÛéö_~]ÛYêÿbG‚Ë[´¸g³Õì ™ÚxìnG×i»-FÑg»û¸”Ô( Š( Š( Š( ¸ÿø²ãÀ¿¼Câû_xÃÇÒxvÐÞ6á[k{­gQHóÒ æ…&•St‚!'™ B‘¬’2Fàš±Ïíéð¯ã‡ííñgÀ¾ ð/Åó¨|[ñYñ•õÞ‹cö J±ð¾¦I&§$7’5¾û½)âFU‘ ]Z)eyJ§êýPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEçþ:ð/ü%?ÙZÖ‰ªÂ+ñ¾{øwÄImöŸ²yÛ<ûK»}ñý³M¹òa[›Bé¿Ê†X¤·»·µº·>øëþÏ^]^i_ðŽø›Ãº­÷‡¼I¢5ÏžÚN«i!GUr‘ÈöÓÄa½´–X`{‹+»;ƒBpƒÐ(¢€>Oøyñcö’ø•ð Àÿt/‚í4OxLñ&ŸÿÆ b;¨m/­£º…&Tð«¢ÊU ÙC0äöð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÑÿ íMÿDoöÿÃÉ®ó'@ ~Îß²Å?Ù¯öŽøÙñ#Á?gùµ‹º¨¹³´“âõ´>Ò‹‰4Í<Ãàåd¶{¹Ê.Äò °ˆ¡{S4ß_ÿÂGûSÑýŸÿðòkŸüÉÐÿ íMÿDoöÿÃÉ®ó'Gü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÐÿ íMÿDoöÿÃÉ®ó'Gü$µ7ý¿Ùÿÿ&¹ÿÌð‘þÔßôFÿgÿü<šçÿ2tÂGûSÑýŸÿðòkŸüÉÐÿ íMÿDoöÿÃÉ®ó'Gü$µ7ý¿Ùÿÿ&¹ÿÌø—ñOþŸAøgñ/áÇÃÿ ÿÂQá]Äún¥áßxƒþAWzM¤ÐO ÎaåïþÚ‰ÕÕäÿTà¨È5ôPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP—ø×Á:­ÇŠ­üðþãOÒ¾$iV‰dËzï™âÝ1åV¨cGuˆ<³=µÚG$ÖM$‘¤ðO{e}Ðx'ƺWŽ|+q}ao¨iZ–•vÚf¹¡êh‘j~ÔÑI,ï#GtYBK¨ñ¼Ï Ð\A$öóÃ4€…óÿìÿ(²ýšì•x7ÿMµôP?ÿ g…áiÿ ÿ /‡ÿá6þÊþÝÿ„{ûFí_ì¯;ìÿlû&ï;ìÞwî¼í»7ü¹ÝÅtQ@ÏøÅžñ_ö×ü"Þ%ðÿ‰áÕnt-_û+Q‚óû+U·Ûö‹+Ÿ)›É¹‹zo…öºn\¨È®‚€ (¢€ (®Qñg…tøsÂÚ·‰|?¥ø›ÆkþÁÒ.õ ¿ÖþÉšëìvîÂK&"²Iå«lR°9 ‚Š( ŸüGÿ)Mø7ÿd«â_þü_@PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEãÿ¼-®ÚøïAø£à ¶x·Ã˜´×ô{y¢µ›Ç~ÜĬË3-¸¹·¹¸ÖRO´,±Ïkö‹+}JòpèñNƒãOXx“ÃWßÚF¡æª;C-¼ÐM ö÷J«5½ÌG,[̉,2Å$R"HŒ£  ŸÿdïùE—ìÓÿd«Á¿úhµ¯ (¯?m/Œ_þ~Î> Ó>Ãáø~&ümø¡ü-ðÞ±­» ßêë?—¨ËŠO;Êû9 …C:ÈÉ2Æ`”à OÁŸµîÿ~ø£ákñ‡ÇÍ/öU¸»ðôïéº}η ^+·¼ŽÎÿL¹c¦ÛÜÍ:ßi«*±‰-ÞÚᇜ$ôþƒûZk¿´Å?Ù ÂßõøE&øƒ¥7ÅŠ2ý–+ïì é³I¦ÝhÛoí¡?lÖÖm7ívŒ“ÃöO´,m ¡¨ã 'ãïíßüKLý·5_Ú/Áï¦øfî‹ÀËðëL™|ch¾#[ɪß(…í%g–X v ›k[v%IJȾŸûkþÒ´ÃßÚÇ⮉ðËö‡þÆÿ„¶:æ•ðëáÏ»jöV g,÷º·‹/¯£[}Ù.M¼eâšv[[›9¢ä¼à„kOŽ¿¶‡Á/‡_ þ-x?àÞ›ñ;ö`ð×ůÝ·„-µ¥Ñ5;«ìO>•oq—’Wv¶³]\4)m%Ä€5ÂFÇÌ>~Ó_¶N±ð'ö6ý¡|eñKáýÇ‚>4|UоÞxNðd)ý³g=Åõ…ι¨3‰ Ôšk9ÙmìÄvƒË¶}¡Zkr¿mûD|XðOìãûAéŸ l>ØüMøûjø‹à§„µ‰´K *ÃÃÓj ‘ª_Eeiÿ˜ü¦{”šWgŽIÊÃäIö‡„~Ý_´?coÛ[ÄâñÄ~Ï_ð„Ëá¥ø…àKk«7ˆ˜ÚÕ4«d- ”Eu+‰gß3Æ&Œ[û†üGûhü!ÿ‚œ~È¿þ5üxðÅ? |f´ñö¸ÚW„,t«¯í ;DûDš{H(’ÆÚà[MmsÛO;Mt·„HPx‡ÀÛwö«ø¯ûSü=ñí¯Ã¯‹þ$øEñ[Åiáû¿ Ûü( àßè’ݵˆÕ,üg’]_\Ú41It.mb·bú‚måÂÑýÿûmüJñO¿ØÚÇÄ^øÑðÿàÚ¼W£éº¿Œ|M¤O­\ØéR³µÂèúdPOöýI¼´+ÄPÛ­Û—ƒ`ž €>~Ý_´?coÛ[ÄâñÄ~Ï_ð„Ëá¥ø…àKk«7ˆ˜ÚÕ4«d- ”Eu+‰gß3Æ&Œ[õéáÚ_ÁŸðZïØNý¢þ-ø?ãÝí§Ä›ë OJðìz-Ö•¨?‡u==–Ž «ŠZ=µÉŠäi®¼ØãU‰@˜x3ö’ý¹´/ø$÷‚?n|\øãxwU6šïÉ<-i§\ø³Dmbm!îæÕ €5¶¤·s¤QEo[­½­¼òåóíçýÞ ŠùÿÄò”߃öJ¾%ÿéßÁ•ôP^?áßë¾'ý²~"é6wØðÃ-+HÑ%ŠbOµx²õ[R¾Šá¤S3}“K“@–€ÇþÖ»Y ı*Ù€yƒ~/xËÇ_·Oƒ#°›OÓþ ø¿Á^<¿Ð,Ũ’÷ÄhºÆc¸×y)ö¤Ô.žÂ;bÑËi$4¦ê;{Pø/âw]ð'‰¼?ã ïí|4ñ^­á=ff†(渆)Öup`U¶k›ÍïG¿›ìÊ‘,·’ ŠÙ‘­áñ [¬?m|9‡ö©øÞÚ'мâÿ]Îú'€ ÔwZU÷‡ímÒ6"dÖn‹†FbÉÖ@9¤ü}Ö¾xûãî‹ãm/âÄo |ñŸ«ã(tÞÓÂÞO hZÍíû†²Ò›‰õkÙ`Òíîî"R[Ä’ÙE(·ø§ã Ÿ‡üw}¡h¾øñþ¯)¼[yá;;;È|’F³¢ÝG-ÌWw&Ù…ÏØtدoDMqö»1sŸñ¯âÅÇàžŸ¾4ü;´Óü}'‡|}â­¬î-î´íF5µ7]™>Ñ Mb©¶æC Þd#ùI4póã=í¶¤ØÚüøŸ«üA¾´mNûÀ–7}gÃÚgŸ-¼7š…Ëj«¥Ãò@ÂÝóM8YŒq?Ù/>ÍŸ¬þÑ^µÖ<¥xG¿>'k?4­{UÑ4ÿ éG2ÿbÝXÚjV×ͨÏi™s·û$Žýíü¹m§µr—†i€3ôŸÚ[ÃÚ´úeÚü?øŸ§xRoCàÝ_Ä÷ú}„g‡|U&¢4s¤L¦ïíW’¦«$6 w¦Á{§‰¤8») ÃÂiÿ´·‡¯çÖõ#ðÿâ~Ÿð÷Â~ ×<5â?_éöÚƒ{¥j7mÌ“o»’؉m–F¿¶µšÒ¥-s5·Ùo… ¤ü^¸Ñ¼}ñößijj o üJÓü#ài–¶çSÕdŸÂZªºušf14­qw¨Ü¼·,pB'šy ´¶y!ä>!~Ó¾"ð×éΑð_â—Ä=+Å~Óµ/ë2øzKÈ´ë‹¥C~“[kÄý¡íõ+uûY’;µ†Kˆc´&béú—ÆØìu¬ì~|Oñ5Þ“iiuã84+m.þO‡Í<Ý mARû7—Éo'œÖZ@Ôn|¿%ÄL·vFèø×ñbãÀ¿ðOOˆß~Úiþ>“þ ¾ñV€Öw÷Zv£Ú›ˆ.ÌŸh…&±TÛs!†o2Hü$8?¡|N×ü-ðÏÃ^¼ð_ÆÿŠ^Ò}OTðýëx)øñ;Yø‘¥kÚ®‰§øoL‚9—ûêÆÓR¶¾mF{Hô˘%¿Ù$wïoåËm=«”¼0ÛLÏ¿íSáX-u}jãá×Åø|áßê> Õ|^ºØ[k¶ºÄºZÛÙCpú®¥ö›ô·Š4ë¸Ë]Æ’øƒÆÞÑ#þÑZü"^»ð…~ ZøcÅ<¡hßLÓ¯<7â;;ÿi–WÉnyo"¶¸±–ý!Ô.là´˜yoks!¹±{ŽÿÅŸ´&áoøIukü@ñWÿý³þÏèÃG:‡>Á¼ê›Öæþëß°¤r}£û:Öïl‘Íl»îàžÚ Âß´&£'ÅßÚLñÿ€üAàÿü!ñ\Z›âFuÄ:—™¦è³ÚÙ-­­ýÅýÖ¥{q«-!‚Ìy±Ogo´_·>àï‹rø‹âœ^ ñ?Ã_ˆ üM¨iWšÞ‘gâyt;Ÿí« )­ ¾– 4Fú8þÏ.¡§«-ÃBÏö¤1 BLbö (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€˜ao Ûßý¾×ÍK[(7\Ŷ;u k½^Rò¶…ûü+ðÿìðàå–¿ñO ~Îß,þ#ønêkë{ªÛ^^_Gó‹A–Æ]Be+q>ÕŒÀ­û|ñìãñ§á‰í|AâOümø¬üN¿¸¾¸¶7þñ¢¨¦ãHš8ìþG—û¯0JJ¼±ÊfŠWºÿÙÿöbðgìó¨øûXѼ]ñ?â7Œ¾']é÷#ñWüBu­gPŽÂocL#<¨åJ1!VvD‰cùÃãWì®üpÿ‚Ðiÿõ{¯ˆð…ðV-Dñÿ‚|W‰®è^,Mvi^+RŽÓ3K»»…ÚHÌŠ—aOP¹ýƒ~Ø3Â_³ÿ‡¡ñ‡ôOø‚ÃÆG‰ü7«‹Aâ‹PTk/z#)%ó£Igˆ¤hȰ¤ $Ëügûÿ û'|y? ¯|Añ÷â7Å éúV½¢|k×ÿ¶l<}q§Þ4ö·7w¨–÷jVö2Íee%½Ý¥¼Mœ’’/´¯Ì²ßìñÛÃÿðR€¼[ðsâï |Ò¼Ees®üAøÓ¥øöþ÷JŸK:n“¢iiöðÇemg-ÅÔé’‰¶âç2å ‰€>ïðOìðÀ´ýÇÄ_CãôHü@Þ0Ò>Í«†ð†üPÑ$#Y°ÑÄa#¾DYLîéoæâˆEn ßñÿì‡àω¿¼CàÿüIøß¨É¨üJ?4 þҺπuG‘…?•²ÖÆÝ ÑÁÇ(ˆO#©äŒÁ_°¿Â? ißlÖ5Øï/a°Ô¯´øŒÐMr4籌ù3,oÇ4ná%ý ŠùÿÄò”߃öJ¾%ÿéßÁ•ôP_ MðöÏÇ?kƒÞ½âÿÂÀÕ|ñê ³v%Þ›g¢¥”É{öóy×> Ô⻵žÞky¬®ãŒžt±ÄLø/ñ#Fÿ‚…ü2ñæ¡ñƒâÄ/ xwÁ^4Ó5 uë[Ç ÕõÖ„Ö¶e4ý*ÒvŠqiqrΙd“M·_24’H®{ñ5ñÇ¿[üšGŽþ*êß`†N.aþÁ±Óü!wç(Ê®ýC×Òŵ›u¼–ìÞ\ŒñFÐk^×nÿo¯†ž5·°ó<1áÿ‡þ8Ñ/ï<è‡Ùïõ GÃ3ÙÅå–óÌ‹L¾mÊ¥WÉÃ.¼ƒÇ? |w¬~Í¿·¯‡ôÝ í·ÆíøC`ûmªlùþÑ´h¾f,µ ;˜?~cÇ—¼â6W ÿŽ> kí1ñ'Äö>ø¿ñþî«c¬i÷øÅ¬xJðÕäM†ŽÐëVÖÚ­®möt?o²¶Ô.Ù&¸‰­GØí¾Ùéÿ¾ê°ÿÁ"#ðìÚ]þ«sÕÓi¾!µÓ5k˜õ9:ß¼¶†(E/Úî~Ç×ü5ø5âüsø7tº6Ÿk¢xkÁ_`Öå³×/õXìuŸøƒAÖ#€Þj“ɨj2¹·ÔL—²I Êb³El€?áVøïþÃþ?ì/ø¨?á ?á6û/Ûmäÿ OþO´ïó6È'ý'ËÝæË=žoîëËü)gñâ'ìgñ«àe‡ÃBâ‡~3xnˆë:lš6‰§j+×­nî/m$š=Cíк0ÚÛ[OäY¼µÜ5ˆ x³áïÄøñoÆ ?Äšžááx‹ÅžÁ:V’©§_­í›Y˽go4ïlžK{ •Ý*L°\øùø1ã{ W⟋<û9j Óu«¿‚µ†€¾ Ðn|QâÛ¯ xÊóW×.õ[ƒzm¤ÕÞÕ£Ïs¨\µÒw’èÜ<ööÀâ/„^!oþ6ñÂü8øßâ+¿—z_ˆ-­<=ñ–ÿÁž Ô#Ñ´í&KA¦ëQ@ñ!Óᙵ 6-RwY.b2ÚZ›ß_ø…ð§U‡þ ãÞ ÓôýG[‹àþ§àmÆÃ}•¥ÕÐÑdÓíb‡í·S<13ùj¿iº•‘Hó&rB¡â?ÅÞý©õïŠÞð'ˆ>)éþ7ð®á;íÃךMž«£Í¤]ê×]/öÝ¥­Å´ë­\G&.#–¶·ÙÊ\Jö|Ä>2ðgíðË\Õ`Óî¬í.Õ¿fÏãPÔt¡g/ü ÿtï øŽÏì÷Wm5¿°xŠÂÖæÙVE¸²1ß_ì7—ᣱvoµuÿ¼ñ?ÄÿðH|9×n4ÿ|hñÁýOÃz„ö ­¦»â‰ôY-exYÒÞ(¢šñØ©d…\ec ¡ðóOñv«û_ø÷âf½àOx Hñ_Ãÿè–¶Ýæ“=ü7úf«â‰.¢•tû»¨F!Ôl&VYYYnTgÌIR0˜<9û=ø§Áÿ > xƒÄ¾ø¿âý[Nø+à‡ï†>|NŸÂZ¯‡õ]¹YdƒZÓlu;iR¸…™®™ížÚ#wÞO%¯Ùÿ¼ÿ ¿g“Úéö7q]꺭ݽž«ªjñÃu¨ßÜj3©Ô59d¼¾”KtâK¹Œmq&ù„« ·ˆæ |ñ‡Jý•~~ÎÚ_ÂCV³øGâ…ö×¾;“_Ò-tmc@ðæ»¤\=å•·ÚÿíÍkb“MgqoQ¼Hnïo·ùÿÇ/ƒþ üøëá-sàOŒ>2üHñU§Œ"ðŸ‰5ßé§À\w&ìè3iúMÖ¤ÃOÕì´É-,–æ õ&ßx\Ϩ0°k>øÃmãOÚwEðß‚|aegãÏøwÆo‰4íoH³_Ð-ô¯ éºÖ‘c*ß%ý–¯sk¦k6öÓɤQÈÑJ/m[dÉŸð›áv£§~ß^ø¦üñÂßÚ|?ñ_‡µ¿øÇÅv½ã/j·:Žqdº•Ü7ú…ÅÝ´VÖW1ÚË=üïŽx V‘Gln€>ߢ€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¯ŸüEÿKÇqøËLÿEøEâVâZIòØx*âxç¸ÀFZÞÚkµŽ-J Ÿg vuW{?'Sšôý“¿å_³Oý’¯ÿé¢Ö¾€ Š( Šù⧇>(èß´Â;- ö“ø¿£i~ j:%æŸà‰aÑìÃúæ³V/6‚ó “ivІ¸’v1‰ÓïÂÛ@Ðot­FãM¹’m÷bò[-²È×öÖ³ZA¥®f¶û-ð´4Ÿ‹×7¾>Ûø–mCÄ á¿‰Z„|áí2ÖÜêz¬“øKBÕWN³LÆ&•®.õ—–âEŽDóO4–Ï$ ‡Ä/ÚwÄ^øu9Ò> ü@²ø‡¥x¯Àv¥áf_Iyƒâ=qt¨oÒkm`ØŸ´=¾£en¿k2Gv°Éq v„Ì}?RøÛŽ£Ã‰þ&»Òm-.¼g…m¥ßÉðù§‚;¡m¨*_fòù-äóšËHϗ三–îÈÝ{“«iZ÷…tÍwBÔ´ýkDÖ­!¿Óõ „¹´¿´™Í ¨JI£++©*ÊAƒZQ@Q@?øþR›ðoþÉWÄ¿ý;ø2¾€ Š+>M'J›ÅVZìºfŸ.·¦Ú\ØZjnukirðÉq r‘½"•ímYÑHWh!, p¡YúN“¥hÓ4- LÓô]E´†ÃOÓì-ÒÚÒÂÒà 0  HЍ¨ *¨sþñ®•ãïÞëº5¾¡mgaâønD¼DI ÖªÝéN¡‡”×2´dÆ6BÊŒJ/a@ÿ‰|S ø?öڷˆ¯¿³´û½WIÑ"—É–m÷úômŒ[cVaæ]ÝÛŸ«¿s•EfP^ªëþøaàOk:–‰ÿ€¼¥_xËVÖmlàûžd——ú¬‰olZéîQ£’îv6ãÍkÅ(ÓÊfXÀ=¹ûoè7õŸÛßyž&ðþ•¦kwö~L£ìö„×°YËæòÛÌ—L¾]ªÅ—ÉË…€: çî|S ÙüSѼq}åø›ÄV§­ØYù2Ÿ´XióYAw/˜Ë_.]NÅv³o;*#•Ïøyã]+âWÀ/üEЭõ MÇÞÓ^ï3þYìów@_áK?ˆ?c?_,>jèŸÂÓÌøiá› +tcMòÉ´0 gŽ4\•ŸñgÀ Ô¾ÁL> ê~Óõ_xvÓÄvz.§|¦êM 7ø_¢,çOY %”³¤íĶë—¤1ÌÒ$¬~ã߆^ ðÇÙü+ðûXÓþYüAøñRãÄÞ6³˜ÛÝ BÒçÃpÚx‡W¿i£žþúÄj:…À½¼¹3†¹»s:´ò»v|7 ü5ý©í|#qû?|øâoøWXÕìáf¹-Ε¬Øi—zd7cV€iZTmsº¥Øähn™]EVKQ#­×—þÔN•­iß·­ž±¦iúµœ?³†ïã‚öÝ'.­gñÍլʮÃq 3FànI#GRAwø[Â~ð7,<-àŸ øÁþÒüß±é&ŸaiæHÓIå[«o–G‘¶¨Ë;1ä“_|Oð}ž—ûdþÖ¿~ø Ã÷ü/ðú߃u«? Ùê:ì>#‘|eg¶›¡’InfŠÎÆÔ¨ fŽ!`誀Ð-¼-ðãÀ_´ìó©|°ðý—ü-mWQŸÅZ—‡æ[é¼sá4ðþ¡x5}Rä4©íÕ›B#W¹igêB1p?´æK›þ>øyàÿÁ]þë¾#ð?ƒõýoKøkã›û=CRÑ­n®­.´ík²ióE,ˆ]%µ{ÛÆÔ†‰®§(TÈû€<à7€<àoÙûþ Óâÿ x{OѼeñ ÓEÓ¼Qâ(Ô¾³â-:_‡ºÖ¡öÛ÷-qqcÕ•ŒÚÉ#A±²H£- Xùÿ†_®>üø§¨øàƒþ,xçıñOÄH|g«^ø÷Ä·­wñ.¥Eáàe”[Ûj¶òéRÝMìBEû,z4RÚ€}Ÿñ“þN+öNÿ²«©êâºùÂ÷DÒ¾)|Høóc£_|/ñÍ·í2x+ÅZÂEá߈·V_ô›K­îD‚ì4¶7Ë©˜Ó%ƆG Fg·Ï×î/4߃º'Âï|$øàí>ÃãU·‚¾$x?ÞY|;žß 6«ii¢šak=6öî÷ñËm›mö¡uqe,W ¨Í-ç?â? ë >#ü9Ô4‡ÿ ¼kñàUŒ øcâbêÃÂÚ­çŒì_R’ÚýtÍ-t«››It›±X0x­ùXeÔ„÷ £þðŸ…| àK x'Ã>ð†4¿7ìzF‰§A§ØZy’4ÒyVðªÆ›å‘ämª2ÎÌy$×A@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@?þÉßò‹/Ù§þÉWƒôÑk_@PEPEPEgéšN•¢éÒYèÚfŸ¤ÙÍww$véouu<—WS@–k‰¥šG#sÉ#»ÌIРŠ( Š( ŠùÿÄò”߃öJ¾%ÿéßÁ•ôP^¯ü&øW⿊z'޼SðÓáÿ‰|m᯳dx‡Uðõæ«¥}žf¸·û5ܱ´ÐùS;Ê›v;bMt'„ü+á¯'þÏ ø@û6•§èQféÐZyZU‡›ö%òÕqmoö‹&òGçI±W{gŸ×þ|+ñ_ÂÍÀ¾)øiðÿľð×Ù¿²<=ªøzÆóJÒ¾Ï [ÛýšÒXÚ|¨]âMŠ»ŠŒ)"€; 3IÒ´]:K=LÓô›9®îïä‚ÎÝ î®§’êêb¨2Íq4³Häny$wbY‰9ÿð‰øWþgü ¿ðŒøþì¯ì/øG¿³ þÊþÊò~Ïö/²mò~ÍäþëÉÛ³gË·oÏÿ¦øWÿ 'þoü+O‡ÿð¬¿èQÿ„zÇûþ>>×ÿ ÿ/ìÿñóûÿ¹þ³çûÜÖ}çÁ‚úŽ£¤Þj~ß]èo é“ÜxWN–M;@h%µm2hIŠÄÛÜÜBmÓæ•6ív°¹ðŸ…otéמðýÞŸã3þKY´è$‡Äe¬v/öä+¶çu¤Û46bŠ8ÏÈ  4*oYk²éš|ºÞ›isai¨=º5Õ­¥ËÃ%Ä1ÊFôŠWµµgE!] „°&5Àà_„ß þÿj³øiðÿáßöç‘ý¥ÿLJ¬tí'“çýš4ó|¿6]»³·Ì|cqÏA¨øOºÇöÿö¿†|?ªÿÂW¥&…­ý³N‚í)>ѲÊëzŸ>Ù~Ùwˆd܃í3áxù<-á? øÀ–ðO†|?àÿ i~oØôNƒO°´ó$i¤ò­áU7Ë#ÈÛTe˜òI¬ûχžÔ~2é?uø>ûâhÖg‰î4kYu:Ñ„ªÐÁzÈgŠ".nDp¤M(ÇÎÙ<7ðóÀ ñW‰õßxÁþÖümv/üE¨hú5­Ö¿tYײŠ÷2ïžvß)fÝ,‡9fÉâ?‡žñм1®ø»ÀþñV·à›¿·øwPÖ4k[ë­ë|RyÖRÌŒöÒï‚ßVÝg9EÀ…¯„ü+c£ø[N²ðχìôÿyðÚçA>òíd±ì(-¶ÛIæ¶P\E,‘‘ˆ9ö_<¦üeÕ¾"éÞð}‡ÄzÑl5?ÛèÖ±k:¢ˆ•ažõPO,@[[€Žå@†!‘p¡âŸ øWǾð·|3áÿxcTò¾Ù¤kzt……ß•"Í›o2´o²Xã‘w)Ã"°Á×?7Âo…w 5Ü|4ø?‚5±}¿ÃÒxzÅ´«ï±ÃmogçZü™<ˆl,b‹rŸ---Õv¬HCLøyà àÔŸtoø?Iø{5¥Ý„ž³Ñ­`ÑžÒèÈ×P›$AŠc4¦D)µÌ¸Ç&“ðóÀÃ=3ÁZü¢ø7E»†ÿOÐl4k[m2Âê± ÐÚ¢£•/n•ÕC,ÀHqº€: 4*oYk²éš|ºÞ›isai¨=º5Õ­¥ËÃ%Ä1ÊFôŠWµµgE!] „°&5Æ…PEPEPEPEPEPEPEPEPEPEPEPEPE|ÿû'Ê,¿fŸû%^ ÿÓE­}@Q@Q@Q@?ÿÃM|&Õ?wðûPñÆi¥ýͬ¿4 ÿéS_žÆ]nÎ'Ò,nI1–[ëÛe…&ŠYÚ\KGü,Ï:ßú'…¿f¿xP÷²\|Gñ¦£éOùJE6‡>·t×%™ £ÚGE”™ÑÖ8å>ÍûSk¿éÛ?³ÿ¿+÷?Ù?ØÚçþÑ›íÚkÐ|­Û¶}Ÿìrmò·ùïæùpŸðŽ~ÔßôY?gÿü3zçÿ5”Â9ûSÑdýŸÿðÍëŸüÖQÿçíMÿE“öÿÃ7®óY@Újmýûöø©æ~ûû[ûg\ðÙóòýŸû?ìš÷›·nÿ´}²=ÞnÏ!<¯2cþçÅ?ôMGöWø¿{¨ZþêêãBñ‚.´«‰—åw²šó[´º–Ù˜ÜZZÊÈTÉ.Lj¡¤þÑ¿µ/išÿ‰µëzõÜ6&Ÿãïêþ ºñÔ®#Xt¸u»kGÔeñ#¥ •£i Íÿp ŸüGÿ)Mø7ÿd«â_þü_@PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE|ŸðòçÇß³À/ü4ñß„µˆø{áý3ÃzŽü¥Ý_Ý5¥•´vо©á¤óµecöx骬Œ³Üκl#bú‡…¾?|ñ‡Žìò|¡i¨/†5m'Ãw‰q"ÛÙÜÛë7v©o©Û\\Íi)¢Röì\ÆÖ6wÙÛ@ŸsûAx›Ç~Òh?ÿœÒ>*}¦ÛCðßÂémÌÑßùw·÷×u›ˆî.šähÖ^lZ–ˆtÕꨖ)M’ã×ÿá–?gÛ¿Þx§áw‡þ&ê òǪ|Gkj¶ðõñ_ë’]ÝEl¬]ÖÝ$X•ä•–F` ( Š( ŠÏÕ´+^𮥡kºfŸ­hšÕ¤Ö†Ÿn—6—ö“!ŽXf…ÁI"tfFFYIkÃÿá–þÙÿȧà_øU~gü}²ֵOjcý_Û°n,þÛååü¯´yžW›7—³Í“páƒ~.Ñ?j}∾1øƒâFŸá¿ ëþ±¶ñƒ¤Ûê©6­w¤ÜÎíy¦CgjÖÑ®‡n±Âl|ÐóÜ3ÜȆ(¢ú€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (®Å>ð¯Ž< }áoøgÃþ0ðÆ©å}³HÖôè5 ¿*Eš?6Þehßd±Ç"îS†Ea‚ ÿ†rð†•ûÿx¿âÿÃB×åÒÛBñÞ­u¥hPýß³Ùhœ·zVË h"·:{En…|„…â‰ã?á]üvÐäSý¢¿á"ûWü}ÂÍð—­}Ÿoú¿°ÿ`¾ƒånÜþoÚ>Õ»l>_‘¶O8ûOíM ÿ¡ÿc~Ïÿ<Ïßklëžû>~_³ÿgý“^óvíßö¶G»ÍÙä'•æLÂWûMYÿ¥j?~Þéö¿½º·Ð¾-jZ­Ä+Ë¥”7ž´µ–å”\]ÚÄÎTI<(LŠÂÃøí®ÿȧû:Â9öOøúÿ…›ãí/EûFïõaþÁM{ÍÛµüß´}—nè|¿?tžIÿ íMÿDoöÿÃÉ®ó'@ü#Ÿ´Ö¯Î£ñSàÿƒôýSþ>¬´/‡Ú†¡ªèÉ÷â²Õ¯5qkqs ’±^\i"'tYd±M½ð¢5WýÇ_þ?øïHOÞCaý½§xKɸ,ßk𽎕}&ȾL·nÛ÷4M$q<`^ø%ð'NÕ¾#¯‡´ý/[[EÓµj+w¯ø»[ŽyâK{5;ƒq«jrË8´¶¶µ2Ï#²Ú[Á+ cCÂÞ×|M㻉_¬?³õm?Ío xI¦ŠâC,m Ü\ÙâßbÓ_ÑíæŠÖoølGqÿ³,̶âæÞæà_YI>вÇ=¯Ú,­õ+ÉÀ x[Å:< aâO _hi‡š¨í ¶óA4R43ÛÜA*¬Ö÷0M°Mo2$°Ë‘H‰"2Ž‚€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€<ÿÇ^:ÿ„Wû+DÑ4¯øJ~ x§ÏOøu.~Íö¿'`žîî}ö=6Û΄Üݘßg› QGqwqkkqŸàŸ†VÞñUÇŒüG¬j5ø—ªÚ5¶¡¯^Mp¶–±Èé$¶º>œóK“bÆe0Ûþòu³´{ɯnbûKz…Q@Q@®i:¯Ã‰ž$ø“ám3Pñ…¼ew£ãßÙ[½Þ§Ô–ö ­iQ in%ŽÎÎÒ 94ðÛG-š‹Èä¶Õ½ƒIÕ´­{ºf»¡jZ~µ¢kVßéú……Â\Ú_ÚL‚Hf†T%$‰Ñ••Ô•e ‚A  (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¯?ñ׎¿áþÊÑ4M+þŸˆ)óÓþKŸ³}¯ÉØ'»»ŸcýM¶ó¡77f7ÙæÃQÜ]ÜZÚÜð/ü"¿ÚšÖµªÂSñÅ>Cø‹ÄOmöoµù;þÏiio½þǦÛyÓ-µ wÙæÍ,²\]Ü]]\zPEPEóüña5#N‹÷ŸüAªéÚ—j¼ÍðóUÔ.¢±°²·AóK¢\ÝÜAm ( é²Íh­¦:è (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (Ïüuã¯øE²´MJÿ„§âŠ|ôðï‡Rçìßkòv îîçØÿcÓm¼èMÍÙöy°Åww¶·| ÿ¯ö¦µ­jŸð”ü@ñOþ"ñÛ}›í~Nÿ³ÚZ[ï±é¶ÞtËmhöy³K,—wWWEPEPEŸ«i:V½á]KB×tÍ?ZÑ5«I¬5 >þÝ.m/í&C°Í ‚’DèÌŒŒ ²’ ÐøkVÕ~|eÑ>ø“RÔ5ÿøžÒúãÀ¾#Ô®[Õk1Í¡j73Þ_%¼’\ÙÜn{›«K;ãr¦m>kíCÜ(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ òÿø×U·ñU¿Ãÿ‡öú~«ñ#U´KÖkÔytÏ iŽïÕ5A£´Eâ™-­ãšþhdŽ7‚/ol@4< à_øEµ5­kTÿ„§âŠ|‡ñˆžÛìßkòwýžÒÒß{ýM¶ó¦[k@ï³ÍšYd¸»¸ºº¸ô ( Š( Š( ŠçüSámÆž¾ð׉,?´4CÊgEš[y š)h.-牖k{˜&Ž)ḅÒXeŠ9ct‘‡Ÿü=ñN»kã½{áoï¾ÙâߥèÅÄ1ZÍã¿ ˆíÿâf"…VÜ\ÛÜÜØàÚXàºû=•¾¥gö (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (ç÷øé øçXÕüð3Yðÿ>!éZ®£¡k~h–K‡ÓXÝKeus®D­˶h%[[0ÑK©2æŽÑnu ?PðO‚t¯xVâÂÂãPÕu-Víµ=s\ÔÝ%ÔüE©º$r^^HˆˆÒ”Š(‘#Há‚`·‚(-à†À; (¢€ (¢€ (¢€ (®?ƾ Ò¼sá[{ ëCJÔ´«´Ôô=sLt‹SðñÇyg#£¢ÊYbt‘$†xfžÞx§·žhdðÿ~Ó¾¹ø»á€ÿ¼Oáýöœ»ûF•­øCK·ºšÕl´Øµ;«›W_5bÓn-%KË9.eG’'òœ-Ü6ðýA@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@yÿÄïˆV þKâÛÍÄ(ÿ‰®‰¢Zi: ³û~¡ªêVÚUœQ¹íí×77°†ifUwxÁóÿø\ŸèÓ¾?ÿàßáçÿ4´Âäø‹ÿFñÿÿÿ?ù¥ þ'Ä_ú4ïÿø7øyÿÍ-ð¹>"ÿѧ|ÿÁ¿ÃÏþihÿ…Éñþ;ãÿþ þóK\ÿ‹>2|nÿ…Yâ_øAdï‹ÿð›e^Â=ý»«øû+ûWɲ}³Èñ/öo;Ëó|¯Ÿfí¿6(ó‡öý•>1~ÈÞ;¿ñ®­à?Ú_Õ¼K¥YZëЮ~Ùøny–9L©rn"ÿѧ|ÿÁ¿ÃÏþihÿ…Éñþ;ãÿþ þóK@ü.Oˆ¿ôißÿðoðóÿšZÏ¿ý 5ý}_~Î_ü¢k^ Ðü6u‹ûï\ÚX]jÚ¾—hóGg¯Ïpb7W+¡‘•Im¤@HQ@Q@Ä/é_ ~xãâ.»o¨]èžðþ§âMB GºšÒÆÚK©RwDiJDÁC:)be/ÿ…Éñþ;ãÿþ þóK@ü.Oˆ¿ôißÿðoðóÿšZ?ár|Eÿ£Nøÿÿƒ‡ŸüÒÐÿ “â/ýwÇÿüü<ÿæ–³õoŠ><Ö¼+©hן²—í ž­i5œòXx›À¶I¨QŒ7Vþ)Žx%‰Ybt‘ Œ¬”/û|ZøkÿFðí)û?|(ý£í$´ñªë^-Ñ|q®xUº›L¾šçûoìz£øŠYg–[;“kwq´Å¤’g¾ó6‘úÝÿ “â/ýwÇÿüü<ÿæ–€ø\ŸèÓ¾?ÿàßáçÿ4´Âäø‹ÿFñÿÿÿ?ù¥ þ'Ä_ú4ïÿø7øyÿÍ-ð¹>"ÿѧ|ÿÁ¿ÃÏþihŸñgíâ|,ñ/|Sû.|Òü1àý*ó[Õï?´|?Ù,-!yî%òâñHû"Ûj+1Æ'¾  Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š+çÿÚ[þM×ßöU~êo¡PÐPEPEP_?þÒßòn¾ÿ²«ð›ÿS} €>€¢€ (¢€>ý¬å_´·ý’¯é¢ê¾€ Š( Š( Šùÿö±ÿ”Y~ÒßöJ¼eÿ¦‹ªú€ çÿá)ÐOÅ?øBc¾ó¼LšWöÜÖpÃ,¿c°3yKq"©ŽßΕfXVFŸì×f! µœÄåþý¡¾|NÔ|=ƒ-þ'ßYø®Ñoô­Zóá‹ô½òÑ 71̺曊H€hݦ !dT,Πú‡…¼S øÓÀ–$ðÕ÷ö†‘¨yªŽÐËo4E#C=½ÄªÍosÑËÖó"K ±Iˆ’#(ãükñ‡ÀþñU¾…¬ŸjºÜÖ‰&ŸáokÞ*º±´wxášî&Òåí"™á!yÄk3[ܢ%ÙØZø³Â·º?…µ/ø~ïOñÇ—ÿÝÔ:ŒCâ2ÖKèþÂá¶Üî´‚k‘åÌQI ùxgÅ:Œ<;s«xrûûGO³ÕumY|™aÙ¦_O¦ßE¶EV>]Ý¥Ä[€ÚÛ7!d*Ç  ³âÕ´©¼Uy¡C©iòëzm¥µýÞž—×V¶—/4vóI;Ò)^ÖéØv‚P¤˜ÛP\ÿ‰|S ø?öڷˆ¯¿³´û½WIÑ"—É–m÷úômŒ[cVaæ]ÝÛŸ«¿s•EfgÙjÚV£¨êÖzv¥§ß]èka©Áop’ɧ]4],3ª’b”ÛÜÛÌÀcÑ>6º’¡EPEs÷>)Ðlþ)èÞ ¸¾òüMâ +SÖì,ü™OÚ,4ù¬ »—Ì å¯—.§b»Yƒ7• ÊôQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@|ÿûKɺøsþʯÂoýMô*úŠùöÂðÿü%±x[ûkÄÿ„—âÃ=+û_B¼û«¥}£ÆZ,?i²¸ÚÞMÌ[üȤÚv:«`ã¨üKñOÄ?ÙÇß VïþŸŽ~:Õnüãì g²›ÁÿÙê?á$Ö¬¿x÷–6ÆÄ¤ú=äèÙ—ZðÓΊ—‚€<¿áïÅWÀŸðM¿Ù7ÃÖ7ø_ðºM_àÿ„o,u_Y¾¿u⻤ÒíbþÇÐ|=e¨Zjð/Èѱ`ÓØÁ²]HlºûPø‡Rø!ðÛZ»ñWÂÿ‚–~%»ñ¶ªx÷â&ƒk hxsY,V#L»¿Ó§°¾Õ»Ôbµ¹¼yíbÓîàhî™$¸„ ‡_øÑ¯þÝ?³Ãißþ·…ð·íKñCÃÿmüúßÅÚ*ÏÂÓÜø‘.¤´Ó-áN›ª5ÚGnèóK é‘8€´kp¡àó­L¢êþËã7 }[á¾ žÔþ,Gñ)~éž ·Ó.¬<;=Ôž‹Åí©O¦µÜ÷1Åo§IqµKÉêâÖ%óìcºi,ÏÅã댲µ§Ä[ÏêÚÝ¯Æ Q Õ<7gu§Zjv‡À¾(u‘ì.%¸{9UÚX bîé]aI¼ÈÌÆÞÜCÁÿ¼S‿±ŸŠo4ÿŨ~Ñ?Ùð’G ¬6_iðv©âû2–z|15¥ýÓH§.D‹ä|cñOâGì»ð£âœRü?‡áįˆõ½/ÃͧßAâ=J»ñv…sauq¨‹‰mo.d_#αKKd€ÝÈöëìj×À‹ÿm_ øoXñçŠäøµû?è¾øYªëÚ>©ðÓWÕ Oˆ> þźžÎþkG:‚Gks$¶Ó½ƒÙ\}²8­7ÝY›öû¿ê1ø§âÿ‹¾:Ò>ËðÿKÓþê¶Ú&µoâÍ>úâoj³i¶ZÇÙmnmnt›e´Ôl£ûtj.ežsö –‰öàöNÿ”Y~Í?öJ¼ÿ¦‹Zú€>ý¬å_´·ý’¯é¢ê¾€ ¾@’Çþ}Sö轿ñ×ü+mZÛÈ🎾ÑöOøC4oXêö×[–X~Ũx“Y¾óÚHäýöÖ™c†þ‹¦x‹à?Ä_ƒ~ÇÞ ø…àˆZ¬¾²Òõ½ÃÚ_ü"?bÐõZÒ];ûN±„[ty­$µ–3çZ¼RÛ­¼‘]ô¿â_ñöðŸî|?኷?Ù6¿{ìŸÚúâMCç9wóumoS¹ùÙ¶}£ËM‘Gh~οòN¾#hÈÛÿ WÇßÛÿhÿü‡.ÿ²>Ù»÷¿òþÄû/™ÿ.Ùþ_ú?“_(x‡Àú/kïÚÜ^øÂËÁ­ûOëöz xgŚχ켹>ÜÜk&ÎM2æYêÂâX˜·m«Äìâõ%Ðð·yáO€w?4¯ü@O7í+«h–ð‘ÞE ØéŸÅ™ôkûOìx,.¼ë{ÛçûEäQÉsº9ãö‹mŸâˆ¿u?üXø»¤|>øßsã‡þ ñÖá[ø÷Ú7Ã;;/jº†›o£¤Þx‚Ù%±‘,ê7w¶Ov­qy%¤öé µú?ᦇyâ/Ûwö„ñ>¹ãˆ„øe¤xo@ÿ„ŽòßAÒ!›Á¾žäý†Hî¼éo^O.ïÏŠηŽÞin%ŸÈ>'¤_¿lŸÚ×ã–‰/ˆ.|aðÇà‡|a¥XÞx§\þÁ¸¿|d‹Ö—äv³Ûm±„ˆJŽFžx¼«‰¥™À:j<-ûL|6´Àßü5§øÿU¾Óñ ×ì·ûk—þ7Þx“ö‚´Ñ4¯j×7¿šMSI—Ázž¹%¬îÆÓO•¦Òìá:”úŸ–²ÉöϵO5Ì€ä>!ŸãV“ðnÇâ'ÄýÁº7íÞŠ[ßϬÏáÙ~Ëâ+:}ZæIo§Š]BæáIJL×á¢6³[=µ«Ûè|J{Ï k¾#ø;k«øƒZð…|Wû=x³G“Ä:½æµªØÍ«üCû-Ý«j7rIuslEŠxþÓ$ÒÆ÷W%û:ÛAlÇürñ'¯¾ |uø³àO‰úÞ±ð¶ÓÆÚ?døƒuàßhËáãw ZYx~ÆòæMfúÊúÎU™u­9mµa¼ÿJŠÁ¬­F†¦—Ÿ ¼Eûb|Cð$¿/¼gª|jðwƒíí£ñMæ¡¶Øø"ÞæM?OÕo?²RŒês}Šk¨ü¨6[[¶,cû=vŒ6^*ñw߆ÞøŸðšOü5ñ^§áéþ1x÷HñmÕ—Œ-^Â×M¼ÓØkΠÖ*uo’d–Ö&‡Oò¢ŠK‹yßü}+@øúþ—ß´Ã]o^ðýö§iáÿ‰^=OZxŠÒÊæÎ+‹Ëiޱ¬=”¶Ok"Ïf³®¥–Šð۫ـ߄âGü“↼Aão‰úƒ|5ð×Àš·‡ü7ã-SÖ©Ýêž)ŠKÇ›Mš ±(†Î8Š$ë «°ÍÏojöþaðš÷Å1xö$ø§ªü@øâo~ÐßÙñøæmW]ô­BÚïÁZ¾»äÛh‘”Òl<«Í>ÃdÖv\€‰%•®.Zp>ãÄž>»Ñ>ükðŧÄû«ox×À {ãÏüAºÒth~ ×ôÝ9$ðÿí//¬EŒÚ}ë±ê±X_ZÅ5µÃIy¨¤Ó/¨xKÅž)Ô´‚ÿ³µÏ‰|A?Äox­´ˆºªê3®¯¨h>µ´Ô#ÕÚñ˜ÆÿÛßx1îí|Ë©>Ëâ;Ëf-$3Û€uÿ<mã¯ø)'Á=ÿ_ñ†…¥†¿./SÃzÝÆ‰u©Fš§„@÷Öä Z)‰´žÞGh7væ†o0ñOÄ_ø~;ïƒÚLi>ðÆm>mnÓÄ-Öu-KÅþ ‡U´×W\Önµƒ%Å¥…Öžñß@÷>RËo<6β\–³ËÀ-3ô€^)ð—ÄŸ…¾)ð×ÄǨxSþøJãÔü)=Ô>!ÿ„³]±ñ¯ýœ#Ôam3mÝ”±ÚùÍåE2,ŸixÌ’tø;⟠Â3àÛO‰GÁ/}ˆxgÃZv“=†» µ–ϰi×úâ^µé¶ÛQ$´·¸ž;{h¯.oÞ‹ð@øià_øWµÿjlhx¯Åž'óþÍö/ûo\¾Ö|›ß>OÛüùü­ûSvÅô +çÿÚ[þM×ßöU~êo¡PÐPEPÏÿµü¢Ëö–ÿ²Uã/ý4]WÐWÏÿð¢ÿã"¿á>ÿ„£þj¯ü,ß°fÿÔÿoØ|ß;þß|íŸôÇËÿ–´jüÿøëÅ:Š?³üa¬ü@¶øá]E´ß: ê°øfËÃ&+‹s0[ûií-o#™w@þV¡"Âö×Cvšü0ñ–±­ü.×¼yñOñˆ¾xÖïÅòÿfxhiZdÑË jZ XÙÛµÌóÛÄ£Rû[Éqsy#Ì'U1Ã$Q[yÿƒÿgoxs[ø§_üWÓõ‡¿³Ø_è~wZ†¨x~Üj÷ò^Ln/¢·½‰Äö‘Y@Ì.÷Ú7²/?go?‚üðãJø¯§è¿þøƒÂ:φü?„DÚÊYh­–£i¤Þê²^2\XÆ–_g…â´·»Q“ÏsxcºàƒüñMޱ«ø{Ÿ?áøEâWQ×uÓI|G æ£u-ö§—¯ÇyXÛ]ÝÍ4ÎZÖ{¸MÝØ´»³ÿCû†¹ðÃÆVßxþì±ðÓáŸö§öçü+¿ èÞþÒû7Ù´>Ág§Ÿäï+Ìò·ìÞûwcsc'Ð(çÿÚÇþQeûKÙ*ñ—þš.«è +ËôŸêºíqâÿé×xð§¼?¥C©éêïo%®¿¦Éx'UðWÃ=A|Kq§ßxÇž Ö|Sâ «Gy×íZ…Ü“Ãiö©%»ŠÂÌÙéPO$q3[iöÀCnŠDx×à÷ü}â«}wY0Òµ¸-ÂMCÂÞ3×¼+u}hŽòC ܺMݳÝÅ Í;B“™¸¸1„3˼ñgÁ¯‡~1ø{àï ê6¡¢èŸnà¼ðÌ>×5/ I I ”útKi6•=´°Ä¶wwâ$q—!]¸ð«| ÿ ëþ?ì/ø§ÿá+ÿ„Ûì¿mºÿïöçü$Ÿißæoÿ·úO—»Ëÿ–{<¯ÝÖ~¥ðkáÞ¯ñ–/ßèÚ„šÚÝÚj3ÛG®jPèÚ–¡h#—׺Ds®Ÿ{}‚×ɺ¹·’x‘IÚÛ˜€; ÂÚ‡üGâÍ[H°û¡ãV-o[—ΖO¶ßÇci¦¤»]ŠÇ‹M>Î-±…_Ýn#{;7?qðôu¯Åƒˆ-¼mm¥A¢<öž$Õ­,/¬ kÇ‚+½6+…±¼òŸQ½xÚâ 6˜²•eR þ ø5ðïá犮5 hÚ…¥ÛZ6e湩jVžÓ™ÑÚÇGµ»žX4›0Ûk`–ðµ´SÛhDzgÂßhÞø[áý7Bû6‘ð[ìÿð†ÁöÛ§þÆò4»/™¤->Ý>òæß™3æo9‘UÔËþ'~Ïñ÷¼|šVžºjüJoˆ>1j°Ý_]Gá+ïYÝXKßk}nçG–) {v…¬þѭ«? iÿ¾é¿ Ç„£Ñµ Ý)¼A¥øªæ}O\Ôµ-OQÖtë»[Û»ÍJæy/.å†]>ÅPÜM ÚÁo"5ˆqþ,ý—þ øãþ[øwĦ…ã¶6¯á¯øLuø<3w5Þö¸¸þÊñtÔ¹yä{Ï´%ºÊ/Û‹ &®Á> |;_‰ž?ñTº6¡}wñJѬüY¦_ëš•æ®FÖ–ÖfÑ&´ß5¬ìmmÚU¶4HQ˜«¸`þøg¾'ѡѵÙøÒÐiÚôž/×5/]júpIQln.µyîg’ÅEÅÑ[V!Zêå–0ÓÊ\ðOÁïøÅWîŠê+»t*kƱÓ>Îð$Q-œ0ª[´¶ª´²Âú øqªÙ~×~+ø“Gð~wâ+K=E´Ò.þCim$Æ}VââKksö£nº5µÍ´i*¬zœ¦êåb…mÀ:|øwñ3Å^×¼]£jø‹Â6š…ž…¬é𿥣jz$wÏj׆ÎòÆxg·–QeO,N²Lðîòn'Ž]øU¾ÿ…ÿ Ûû þ)/õžOÛn¾ÙöÏ´}³íÿoó>×ý¥ößôß·ùßkû_úOçþö€4<à? ü=ð­Æ‘á‹]B8¯®ÚþúóSÕou}OTºdH¼ëÍBöY®îåXa‚yåvH`‚+Q¢öQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@WÏÿ´·ü›¯‡?ìªü&ÿÔßB  +?VÔ­´_ êZÅäZ„ÖzM¤×“ÇaaqtñÄ…Ùaµ·GžyHR(‘äv¢³Ïÿ?i¿øÏö/ð?Æ-WLñ‡…âñ•¦˜"Ð[ºõÞ§s©ÝXÇ~öºUªØ­Þµp´² « yaxm®'E ­a¬üzøMáÿ…žñž¯â¿±è^8Õdðþˆ³/ä¼½Öã†îWÒþÄ›¨õ Ú}ݷؤ‰n>רÄjd…€9ÿøj‚£å“Ä^ ·šÏæÖíçðv¿ Ï‚á<¥Çˆá{1'‡­ž ÓÇq«-¤R[¤—í <‹¡®~Ñ¿¼9ñ3ÄžÔüM¨mø&î _ ?ê÷ÖžY­-ÕîíížÛL±{[¤”^ÝÉ ±X®ÿ{›K‘‡ü,¿ìÿÚŸâ…¼EwáýÁþø[ÆRê÷’ý—ìŸo»ñ 7Ò]\I …-¢‡D·1TÙºvve*ÏümûVü?ð·ìãñ;Ç~ñóVøuá]CÅ1xo]ð?‰¼3®Ãjª¬mc¿Ó’im£š[Xî®á†h¬Væ)nLQ²–ô Gã§Ãý+ÀžׯâÿÂWö¶Ó4X¾xšÍ ¬‚+›‡Ð£°mNh¤xUî%¶H”ÜÚåÿÒ`ó=CIÕ´­{ºf»¡jZ~µ¢kVßéú……Â\Ú_ÚL‚Hf†T%$‰Ñ••Ô•e ‚A  ùÿö–ÿ“uðçý•_„ßú›èTôQ@óÿícÿ(²ý¥¿ì•xËÿMUôóÃoÚoÀþ>ø!ãßéž0ðf›àÏjºÊk×­ù­õ›Í"Å,…ÍŒ/}}vö‘/ö}¢Ms ÍÌvN†àª8a7ǯ„Ö?u‰:ÏŠÿáð~…ªÙhšÍψ´ËýçÃ÷÷wÖÖñjVw°Åu§ïkë)w]E‹{˜nIþsáü{}¯âü$ë?áÿ…oâ¿øJ¾ÇÓíÿØ?ÙßÚÙ¾gî~ßöo²yß¹ó¼ß’€45¿Ú7àö‰â« .[ü´>/ð¶Ÿðç[‡âW»h/ü%ãu;SÓ¯üc¤Ú]Úý¢KK ´”ÂfŠâµ<qšr÷[€vð¼ÿãá>ÿ„[þj¯ü+/°iÔïÿoÛ|ß'þß|ŸôÇÌÿ–µä´GÆ_ˆ÷?°ïíâ_…žûO‚<%á_è­ã O¶‘â;-oM·¼±»¼Òôóní¬5]yo­. ²»’ÚÞåVÐß{~¹ñ?ÆWŸiºòÒ1v[í_bÏ—ã]çŒá´ø  xâF¡®xWFñä—!×/"Šó[ñgˆí|Lþ°†ÆÀ@–ñ[^܈¢ÞÞ[nD’1h‹'!¨üXñ÷„¿m ûã^‰§ü6ðo…>üGñ~¯/†üUuâ]úÒÂûÃ,n •Û_YÂפ¡±e^ ‚iž[ˆ õý ⌭¾&xkCøŸðïOøgñî{/ÍgâQ­ÝK{¥Æ¢Ö¼ÛEñ±´¹˜}–}BÓuÜfì7Ù~Ú|øŸã/Œ¼7ñ+Äôÿ‡~ñ¿‡ô]{Ãö§Ä£VÔæŽîÛΘÝE´pA-[²O4“C"¼ÑYLÙ<ƒáOÇ‹“|¼ºø‹á?ê^4ñ?įxÀV:?Š%•uBÃYבí/e}&Ö+>ÇG”ý° ™îm¬ä—ìæòHìç÷ÿøûUñмCà¿x{OðÄÚiúž©¥éš³ëdºf ÷Iayg~ööÏ,R=…ì“[ÛÍÖ“ƒ@Ö÷ 7ÇVËâ·Æ„Õ|§è_ ÿg빓Æ>7¾×Ýä6‰áË|ɧévÖ“Oq,B÷˸ŽV·UÉ’ .äymíú ⌭¾&xkCøŸðïOøgñî{/ÍgâQ­ÝK{¥Æ¢Ö¼ÛEñ±´¹˜}–}BÓuÜfì7Ù~ÚŸáŽð‘|ý–üYÿ·Øÿá¥?³ÿÑ´¼ÏøG>ÕáCÄŸÉjÛýöo»|ß3¾[ ¾)üGø“£ø/Ærü/ðþ›ð£âN•o­è½ŒZ÷[²°»µûmŒº¶™5…´6ÛáÙ«gy~Ñ\K(–6ê ýãÆ«¨éÞñíï‚´ý?à?Ä;½ÇÂÞ,_yõ›–Õç†×Gº½Ñ~È¢ÖÆúââÞ8Z;»‹˜Åí“]ZÚyö¤(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ùÿö–ÿ“uðçý•_„ßú›èTôùàmÅ2þ˲G-ïþ?ü-µø-𪆞5øs;ø«OÕnlü7 £ë-Ô×ÚjͤI—u¬î&’Ý•´w²Áêø}âk/‰<]$?üF¾,øë¨xÓPÖ<]ke²tÁðïUÐmoµ?N²ƒHŠCkevòÇç(šÛí& ¹ä³·Ðø‡á?ÞþÊŸðQí:ËÃ> »ÔøàíGÀ¿³>—¢kx‚Z÷Uñˆo—]Ô4ëíTÜjúµæ«#^I§[ÛØ­É{Ö2Åi[Â墊[˜ã[‰@=‚¾ý¥¿äÝ|9ÿeWá7þ¦ú}EPE|ÿûXÿÊ,¿ioû%^2ÿÓEÕ}@~pGáÿë´ë]%~/øYøû@|Cñ¶¿w¤ø.tÕßAÕµ/[ÛÜè#UÓg°Ö³o¬Û]Iª]Hm|Ñ =ãÚÃ(„þñ6¹á¯øþÒóãÄ&ñ7~é¶zŸŽô;-#YºÓ4C¨ÝË…g£iÓÙXÛ BñÚâö14¢+‰<¨­!·¹¼ú@ÒuXटõÙtÍB-QøkðöÂÓP{w[K««mSÅ’\C¤lybK«VtRYxKròì÷âçø=â¯é^7ðOÄø¤ƒö`ø¦jCGðn©®]hz³ø™ îa Ú„2±ûGÎmŒ1µ´‘Í$2<ÏÐ?Ão‰ú*ZÉkð×OñGˆµ†¿´f¯má½votgÔüOâ#\Ò4bQ ²2ÍÍmþ->y¹·žî%žÎ xÿh¾)—öXý’&|)]7ÆzoÂÿÝØø×À:õŽ™¢ëšŽµ´Ñ(Iâ ÍOQ“YÕmÆÑø¾ëM]5- )b2Ë wFòígˆ­omöÃ%‰ñ'àÇÆ‹ŸÙƒã7Àï†/ð½üñbÓÆ·6Þ$ñF§¨Ç©èw^$–öúúÉôëkFŠî&¼¾¹XoÕ»[CsûKײc¨eý+[ý¡ügãM;àçìßñNïâ•Ýæ§¬|OÑRóPðmÕ½…®–²YF¶3RÇìövó=î4æYÒèý°­êý‡¿ÿ…aã/†^*ÒüIðvÇÁþ-»ÿ„+ÿµ=Å:ˆð½¡Ó´7½—N¼´ŸJÒç‚ÞU:•ìsZG`H²Û˜ZÉmZ°Ãà_|Sðëöx×TðþµâkŸøÇÄ7—Ú%´ö¶Úþ ÔuhÚ(&y$ƒ÷W±†‰¥›Ë`È%˜(•üÿá7ÁOøþ‹û^ÿÃ÷𥾠ßü8ÖþÇ<ïö­VøFvKi¾%ßl?°nòÒyoûÈ1ÜþX¨|!ðN«à…:¶…¬\i÷7wÞ5ñ¿‰#{7wŒZk>#Ôµ{T%Ñš¶÷Ф€¢Ep¬ê·è_<}kðÏá÷ÀíQüÁ„×~¹ÑüIk©ÝIârÓÃwv—Ú5•Μ֋ii*Ícd·W‰up·)m?•idoPéàŸðCU›öKÖþêšæŸ¦ërüJ×>"hú¬/{ikt|kqâí\ÂÞKͿؒêx™ÔOSÆJN9 {àïÅ?Œßï®þ1Zü?ð_‚5o…^;øeu¤ø7ÄÚÆ«ü$3hÌ÷±êš}¬'0éÓ „Ù!âÌ—krc´>þÎV~øí¡xªçàÇì¿ð¾o}§ìš×à YǪøºi­å³2ËçéÑÉ¡[yRË+YÛ\ÞÊï,Q›ï&ÞdÔ}¿à‡‚u_†¿±Â‡:íÆŸw­øÁZ†õ ìÞÒk«mexYÑ¢/,ˆÅHÊ©àx‡‡þüSÓ¼;$W6¿íõo†Ÿ|[ñ7áíÌ^ ¾¹¶ñ'öå÷ˆdšÇY€éñ6›?Ä2Û¤ÖÒßyw. sÇ´ºõÿ‡žñLü[ñCâ^ÒümãM+Eðôš'‡µ õ+HÒ´™µ íUon-íæ»¹’mZúY%6öè¨öð,E­ÞæèŸ‚Ÿðxcö§ð·‹oü¯ ~Ñ:­ÆÉ4‰ößÙiW>Ò<=>L±ã¹é÷R'Ë*mhXä–x…¿³•Ÿ…~;h^*¹ø1û/ü/›Àßiû&µðãÂÖqê¾.škyl̲ùútrhVÞT²ÊÖv×7²»ËfûÉ·™5 ÿ|øÑ¢?ìÁá aþÚü=ý˜îâ¶ŽþÏSÔo5ŸZ[ø[Tðí­áí!ƒK—7Ë%˜’ùX\>Û´û Úø!â›/ÚÇÃþ<¼økû?ü4Ô4mWRÕ|Iã?‡Ï<ßÅ´ÙÝÚ½¶§dtèÖÚâîî]ã—RÔ¼»>Ù ¸|]ÄÇü<ý|=à_xÃÖ?fý/ÿ ®ô˽3âU¯†¬.¼{¯Ç§*Ô¼=ðçÃ>0øßâ-îk-jÏÀñØKi¡Ü@æ+›{½VþêÓKŠú<¥“O7nUš9>Íäî‘sÿár|Eÿ£Nøÿÿƒ‡ŸüÒÐÿ “â/ýwÇÿüü<ÿæ–º |jð®¹ã»xOñÂïˆÚ—›ö? xÊ,¯õO.6žOìÛ˜ešÃWò­ÕgŸû6êïì«,ksäHL`Ÿý¬å_´·ý’¯é¢ê¾€ ¾мðÅ¿µ§í‘®üOµð~¡­ø ƺF§&¡¬j¢+¯i‡Á^‘5k)ZU}V{k–þÒµ6Ó;iñ“161yÿ|'ÿ +ö§ð÷Œ~8øgûwânƒðà®»yoâ;ÉþÉñT—~(žæñ´ÆU··Ô ¹Äsy 5®ûˆá0¬Ó+ùà /‰W þüSÔ| ð?Áÿ3Õ¯|{â[Ö»Œx—F¿Ò¢ðð2Ê-íµ[yt©n¦‹ö!"ý–=)m@=CþÝÀß¿áfø‹áÇÁÿ‰}ïÅ_°Åñ‡Fñ$©ñÒÿVñ?ömŽšéžìÚeÝí¾ƒq Ö6>Æhž…´ÚòÿY|JÖ<ñ«âTžøkñGÂ>5ñnῊ!ñž­oãoÉ«=¿†-mt›_]KRYͤ4E´í³ ¯$7 ¬N.:ŠÞðeïßø(ÏÅ+ÿiúć·zŽ£ávñMÅ׃õ /‡>»·¾ÑÌ„6ùnR«AîÖÖ›äo³Aåtð‹øÁ>4ý²|c¢x7OÐüiâ/Œð]¾±á¨ítfñ¼C¥x1 ŒšÌVïuecyªêF[Ë‹ek˜…ÅÍݸûbÆôóÿƯ‡šWƒôïþ ½ð?ìßðúÏijÅ/j_~èÈ#²ºÒçц‹©ê—L–ÃT–;}6ŸpÚe“YÈo£‰§`ó¨OêƒWÕ.CHúžÝY´"5{––q.¤#ûNd¹ðÿ€Þðg¿gïø'O‹ü)áí?Fñ—Ä+MNñGˆ£Rúψ´é~ëZ‡ØooܵÅÅŒwVV2Ck$ÆÉ"Ž4¶cúâÆ“¥xÇö¸øEðóÇÚfŸ¯ü'ñ?‡ü]uy¡ëé.¯x¢ÎM"M*Úæ9•y*XɯÞEe.ôcf÷b#&ŸÖü†¹áo‡·ÆÏƒE‡‡üAû=Þi^>€ønêeÔ|7wâÍ.ÿN[-!㕞~Å ñ+A¤6`¶c4vÑ&hãúŸ…´|YðÃ;ûí/ƒ>ý¥u/øSJŽiF”tKo†š¤÷Ú\/q¦Ã­gO–É™íãHn4Æm`û$|ÿŽ~|8ÑfßÛ×]Ò|áý?Pøý°ß Dª–ß æ‡Àš6¶·¶¹Ñn[T¼žúK‹‚Yn<¹dwx¢(ê€þø·ö´ý²5߉ö¾Ô5¿x×HÔäÔ5TEuà-0ø+Ãò&­e+J¯¡ÊÏmrßÚV¦Úgm>2f&Æ/ øq¢Ü|hñWÃÿþÔ>Óücv>xÅVÞñ®n¶’øºáõ¼Uv4©¢X$¾¶#C†Ra-§­òǶ]BU¸ãüámãǯ€zÄëøXþ·ð¯Ç6Ðá׿—R°ñ†íOZ~ÑZΑ¤øKÂú橪è&‘iðÿ[ûN†š„ö6n±MN=J¬Ò9,àŠIt†M¬–pçê? ¾êÿµ¿‡>jß >êžðí+w¡h>»ðõŒúF‰¥]ü"ÍÕ•›Æa·¶›TUÔ$†4T{ 'e2ôèð†è>øÅÿ 7Ä_>üHÓï~*ý†/Œ:7‰%Oˆv—ú·‰ÿ³lt×HôðßfÓ.ïmôˆN±´éö3Dð-¦×ßôQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@xí ¤êº·ìÝnÚF™¨jòxwƾñEåµ…»Ý]3Gñ>—ªê ¼a¥¸–;;;‰Uæ™GI#¢0 x'Çþ ø‹á[cÁ^!Óõë; ¶Óµáb—Z> ˆ-ý«…žÊú!,b[[”ŽxY‚É7ØPEãþ)øÅ éÞ;¾ð‚áÿ…‰ñZÛʉü5¥¼¯‡4ѬÐ>¿Râ[<.nîÀ–â(¦p_N«nàÿü)OøXñ4øûÿ í¿¾ÿ„Ïó< ¢nÿ—°ùQmìÙnÿhÖã6ÿj´ƒLó>ÏÐQ@|àψ¾·Ñ¼káí?^³°»MGO’e)u£êŽßX]!Y쯢¹ŠêÙãžmÑÈÍ|áñáÆKo x[ÁÞÕáiø þ€uÛ‡ñf¸xÁúv‘âm3Pš;[k·Z¶[K<æþhïÔÃ×>Ñ«hGöÎ…¨Y]i:îƒçï6ÿÚUìpßYyéÉÚ!ÎG¾6V EP—ø×â÷ƒ<â« Ë6¡âˆ:…¢^éþ ðÝ©ÔõûËyá†áíâÎÅî#û9Ô/^ÚÆ)Yk˜sšãÿáWø§â_úwÇ=WÊÒ%ýßü+O ë“Éá_->LêW¿e³¾Öüôk…šÖåbÓ^Ò ,'’¶NîN“¥hÓ4- LÓô]E´†ÃOÓì-ÒÚÒÂÒà 0  HЍ¨ *¨hP\ÿŠ|'á_xûÂÞ5ðχüaáSÊûf‘­éÐj~T‹4~m¼ÊѾÉcŽEܧ ŠÃ@(|nø9ñrÏö/ø»àOƒZÖ¡ñ/Jñ÷‚µÿ Áá/xªWºÑ¤¼±š%¸ÒõÛˆ./.¥ye—}®­q,nÓ@"¼Ó`¶0Ïö}áöü'ÆÿøóÅÞð޵½kƶþ5ðíαáÛ[›¯]E£hºV,®&ó%gÐ`¹ó¢ò˜1pL*ììi:T>*¼×aÓ4øµ½FÒÚÂïPKt[««KgšKxd” ïOutÈŒJ£O)P ¶yû/‡žÓ~2êßtïø>Ãâ½h¶Ÿ‰íôkXµFÑDJ°Ïz¨'– -­ÀGr CÇȸÏÿ…Mð¯þ·ü-øVŸÿáfÿÐÝÿõöïü{ý“þ?ü¿´Ç·î>ÿú¿“îñZŸ<¨üeÒ~"êð}÷ÄѬ4ÏÜhÖ²ë:u£ U¡‚õÏD\܈áHšQ²¡sá? Þèþ)Ó¯<3áû½?Çgü$–³iÐIˆ<ËXì_íÈWmÎëH!¶>hlÅqŸ‘@ýÏÂo…w¾;ñOŠo>|?»ñ7Ž4©4/jóxzÆKÿiRG/e}pcó.mš(!ŒÃ+2Š5+…gèŸ> øg·Ú‡>ü/ðþ‰©ÚjVš~›á]:ÒÒîÓQKxõe†8U+¤²³IÑYVÖá„I· ð—ÃÏxN[?xÁþ ³KH¬ FµÓc‘Ïsu!`DRÜ_^Ì©¢K©ÜÒ¹`Ã<àßxŸ]ð‡üá]oÆ×bÿÄZ†£ZØÝk÷AåM{,(¯s.ùçmò–mÒÈs–lèZøO¶:?…´ë/ ø~ÏOð7—ÿݬ:tÃáÿ.ÖKþÂBÛm´žkaåÄRÉù‚x§Â~ñÇ/¼-ã_ øÆÕ<¯¶iÞ¡awåH³GæÛÌ­ì–8ä]ÊpȬ0@5Ÿ©|<ðµðj/‡:Çü«|=†ÒÒÂ? ^hÖ³èÉijckXVÉÐÀ"„à mCmhÀ…¯„ü+c£ø[N²ðχìôÿyðÚçA>òíd±ì(-¶ÛIæ¶P\E,‘‘ˆ%Ï„ü+{£ø§N¼ðχîôÿyŸð’ZͧA$> ó-c±·!]·;­ †Øù¡³QÆ~Ey}‡À?Iñ¿Æ><ñw†üã­oZñ­¿|;s¬xvÖæëÁ×QhÚ.•‹+‰¼ÇIYô.|輦 c\ »z~xâW…mô/ˆ¾ðôKK´¿ƒOñ&kªÚCt¨ñ¬É Â:,¡%•¸,Ž3†9è$Òt©¼Ue®Ë¦iòëzm¥Í…¦ öè×V¶—/ —Ç)Ò)^ÖÕ…v‚À˜×þ­ðóÀ÷Ã=KÁZïü­x7Z»šÿPÐoôk[2þêk³,ÓZº¤•ï®™ÙK4ÄÈIsº€4-|'á[ÂÚu—†|?g§øËÿ„nÖ:áðÿ—k%Œa@¡m¶ÚO5°ò‚â)dŒ|ŒAçüSð›á_Ž4{í;Æ¿ >øÃOÕ5XµÛË]oÃÖ:„7z¬V«cä©4l¯r–‘Çl³0."EŒ€ ?áS|+ÿ…íÿ Gþ§ÃÿøY¿ô7Â=cý»ÿÿdÿÿ/íñíû¿þ¯äû¼Wae¤éZn£«^iÚfŸaw¯]­þ§=½ºE&£t°Ej³NÊ–QomowËá‰3µ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€<¿Æ¿|ão[ø¦X5 üAÓ­ËOñ§†îŽ™¯ÙÛÆï46ïrƒ–)q'ÚŸz—62ʨÓ[M·ÇýŸöšð§ú&sðãFžukq®ÝjÕla‹åG¼šÎ×UµÔ®fR ¯oi¥EÆÆ8 L#¶?á#ý©¿èþÏÿøy5Ïþdèÿ„ö¦ÿ¢7û?ÿáä×?ù“ þÅ?ÿ¡üXøÏö¯Åÿ0Ÿ†Z-÷€ÿ´óó¦êÚwÚšùr$/öu柜L—kŠ_-=ƒÂÞ𯼠aáoøgÃþðÆ—æýHÑ4è4û O2FšO*ÞXÓ|²<µFYÙ$šè( Š( Š( Š+Ïüuð·ÀŸÿ²¦ñf…ö[@óÿ±µÝ>öëI×t?`¸þÏÕl¤†úËÏH’9¾Ï4~tyŽMñ³)óÿìoÚ;ÁŸ»ðÿ‹>ülÒ÷0ZøÚ<%®®ïÞ5Åγ¤Û\ØÜìpÑ%¼:%žcxÙçi stÂGûSÑýŸÿðòkŸüÉÐÿ íMÿDoöÿÃÉ®ó'Gü!ÿðgß ÜhÞ ðöŸ Yß]¶£¨I —ºÖ5DIo¯îœ´÷·Òˆ£2Ý\¼“ÌÊI¹®Â€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (ÿÙopenacs-5.7.0/packages/acs-templating/www/doc/guide/forms.html0000644000175000017500000000441707572172151024200 0ustar frankiefrankie Templating System User Guide: Creating and Populating Forms

    Creating and Populating Forms

    Templating System : Developer Guide : User Guide

    This document outlines the steps necessary to build a dynamic form in Tcl code.

    Important Note: The ad_form function has been written to be a more consistent, easier way to create and manage dynamic forms. Behind the scenes it uses the templating system's form builder, but it hides much of its complexity. You should definitely look at it and at the pages that use it in the survey package.

    Create a form

    Use the form create command to initialize a form:

    form create add_user

    See the form API for optional parameters to this command.

    Add elements

    Once the form is created, use the element create command to add elements to it:

    element create add_user first_name -datatype text \ 
                                       -label "First Name" \
                                       -html { size 30 }

    In auto-generated forms, elements appear in the order they were created. See the element API for optional parameters to this command.

    Set values

    Self-validating forms should check whether a request or submission is currently being processed. If a request is being processed, then form elements may need to be initialized with their appropriate values.

    if { [template::form is_request add_user] } {
    
      set db [ns_db gethandle]
    
      set query "select ad_template_sample_users_seq.nextval from dual"
      template::query user_id onevalue $query -db $db
    
      ns_db releasehandle $db
    
      template::element set_properties add_user user_id -value $user_id
    }

    This may also be done using the value option to element create. In this case the value is set separately to avoid the additional database query during a submission.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/wizards.html0000644000175000017500000000637007736270506024542 0ustar frankiefrankie Templating System User Guide: Integrating Forms into a Wizard

    Integrating Forms into a Wizard

    Templating System : User Guide

    This document outlines the steps necessary to build a dynamic form wizard in Tcl code.

    Updated documentation of wizards

    Create a wizard

    Use the wizard create command to initialize a wizard, declaring any wizard state variables in the -params option:

    wizard create make_sandwich -params { sandwich_id }

    See the wizard API for optional parameters to this command.

    Add steps

    Once the wizard is created, use the wizard create command to add steps to it:

    wizard add make_sandwich -label "Add the lettuce" -url "add-lettuce"

    In auto-generated wizards, the wizard steps appear in the order they were created. See the wizard API for optional parameters to this command. Alternatively, wizard steps can be created in the wizard create statement with the -steps option:

    wizard create make_sandwich -action "eat-sandwich.acs?sandwich_id=$sandwich_id" -params { 
      sandwich_id 
    } -steps { 
      1 -label "Add Meat"    -url "add-meat" -repeat
      2 -label "Add Lettuce" -url "add-lettuce"
      3 -label "Add Cheese"  -url "add-cheese" -repeat
    }
    

    Setting wizard state variables

    Most likely, a wizard will store one or more state variables using the -params option in the wizard create statement. At any point in the wizard process, a state variable's value can be updated using the wizard set_param command.

    # check to see if a sandwich_id has been passed in by the wizard
    request set_param sandwich_id -datatype integer -optional
    
    # if not, then set the sandwich_id
    if { [template::util::is_nil sandwich_id] } {
    
      set db [ns_db gethandle]
      query sandwich_id onevalue "select sandwich_id_seq.nextval from dual" -db $db
      ns_db releasehandle $db
    
      wizard set_param sandwich_id $sandwich_id
    }
    

    Integrating forms into the wizard

    Integrating forms into the wizard involves augmenting the standard ATS form by:
    • Adding wizard submit buttons to the form in place of the standard form submit button:

      In the .tcl file:

      if { [wizard exists] } {
        wizard submit form_name -buttons { 
          { previous "Back" } repeat { next "Continue" } { finish Save } 
        }
      } else {
        element create form_name submit -datatype keyword -widget submit
      }
      

      In the .adp file:

      <formtemplate id=@form_name@ style=wizard>
    • Advancing the wizard with the wizard forward command. The page the wizard forwards to depends on which wizard submit button was pressed (next, repeat, previous, finish):
      if { [wizard exists] } {
        # go to the next wizard step
        wizard forward
      } else {
        template::forward "http://cms.arsdigita.com"
      }
      

    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/search.html0000644000175000017500000000751507253523117024317 0ustar frankiefrankie Templating System User Guide: Search-and-Select Forms

    Implementing Search-and-Select Forms

    Templating System : User Guide

    Form designers are often confronted by the need to provide users with a way to choose from hundreds or even thousands of potential options, exceeding the practical capacity of a select list or set of checkboxes or radio buttons. One common solution is to allow the user to select from a search result:

    1. The user is prompted to enter or choose some search criteria. For example, travel sites typically begin the reservation process by prompting the user to enter a city of origin and destination.

    2. The search may return any number of results. Depending on the specific application, the system may require the user to make one choice, or allow multiple selections. If the search returns no results, the system returns the user to the search form to modify the search criteria and search again.

      To continue the travel site example, if an exact match is found for the cities entered by the user, the system immediately returns a list of flights. If several possible matches are found, the system prompts the user to choose a city before proceding. If no matches are found, the sytem prompts the user to search again.

    To illustrate how to implement this type of page flow using the templating system, we will build the framework for a simple user-management interface. Required actions for such an interface might include editing basic user properties, changing user permissions or adding users to roles or groups.

    The simplest way to implement this page flow using the templating system is to create a single page that conditionally includes two different forms:

    1. Say the administrator wishes to edit the name and screen name of a user. The administrator requests a page, user-edit.acs. The page looks for a query parameter named user_id to specify which user to edit.

    2. Initially, user_id is not specified. In this case, the page includes a user search form.

    3. The user enters part of a user name or screen name and submits the form, which returns to the same URL with the query parameter user_search. If this parameter is defined, the page queries the database for potential matches.

    4. If one match is found, the page sets a user_id variable and includes the actual user edit form.

    5. If multiple matches are found, the page includes a listing of users. The name of each each user is linked back to the same page, with the appropriate user_id. The page prompts the administrator to choose one. A link is also provided with no user_id so that the administrator may search again.

    6. If the administrator chooses a user, the page detects the user_id and displays the edit form.

    A working implementation of this example is provided in the files demo/user-edit.tcl and demo/user-edit.adp. You must execute the demo data file (demo/demo.sql) for the page to function.

    Try the following scenarios:

    1. Submit the search form without entering any search criteria.
    2. Submit the search form with obscure criteria that does not yield a match.(i.e. zzzzz).
    3. Submit the search form with criteria likely to produce multiple results (i.e. e).
    4. Submit the search form with criteria likely to product a single result (i.e. Sally).

    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/form-templates.html0000644000175000017500000000235607253523117026007 0ustar frankiefrankie Templating System User Guide: Customizing Form Templates

    Customizing Form Templates

    Templating System : Developer Guide : User Guide

    The templating system allows the designer to have full control over the layout of a dynamic form.

    Starting with an autogenerated form template

    In most cases, the simplest way for the designer to get started is to edit the autogenerated form template. This template will have all the necessary formwidget and formgroup tags.

    Using form metadata

    The designer must take care that all form elements created by the developer in the code file are also represented in the associated template. Checking the template against the form metadata is the best means to ensure that elements are not omitted.

    Viewing of form metadata is not implemented yet.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/tcl.html0000644000175000017500000000176407253523117023634 0ustar frankiefrankie Templating System User Guide: Embedding Code in Templates

    Embedding Code in Templates

    Templating System : Developer Guide : User Guide

    There are various ways to use Tcl in ADPs like ASP or JSP.

    You can use the <% ... %> and <%= ... %> tags just as in an ADP page handled by the AOLserver. For examples, see the section "embedded tcl" on the demonstration page.

    Generally, avoid putting escaped TCL code in adp files, or generating HTML fragments in tcl procedures. It subverts the separation of code and layout, one of the benefits of templating. Embedded Tcl makes templates non-portable to ACS/Java.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/guide/form-datatypes.html0000644000175000017500000000056707253523117026011 0ustar frankiefrankie Templating System User Guide: Custom Data Types

    Custom Data Types

    Templating System : Developer Guide : User Guide

    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/time1/0000755000175000017500000000000011724401447022075 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/time1/stage00.gif0000644000175000017500000003426507253523117024042 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡‡€‚ƒ€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠÿŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ†€‚ƒ„‚€‚ƒ„…††€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ€‚ƒ„…… € ‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ€‚ƒ„€‚ƒ„ € ‚ƒ„… €‚ƒ„…†‚ƒ‡‡‡‡‡ÿ‡‡„€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž’€‚ƒ„… € ‚ƒ„… € ‚ƒ„€‚ƒ„…†‡ˆ‰‰‰‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž„€ ‚ƒ„‚€ ‚ƒ„ €‚ƒ„…†‡ˆ‰Š…‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž…„„ € ‚ƒ„ƒ €‚ƒ„ƒ…………………………‚€‚ƒ„…†‡ˆ‰ŠŠ€ÿ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž…€ ‚ƒƒ €‚ƒ€ ‚ƒƒ€‚ƒ„……………………………‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ›€ ‚ƒ„‚  €‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ— †€‚ƒ€ ‚ƒ€ ‚ƒ ÿ€‚ƒ„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€ ‚ƒ €‚ƒƒ„ € ‚‚€‚‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŽ Ž € ‚ƒ€‚ƒƒ„‚‚„€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ÿ”•–—˜™š›œ Œ€ ‚‚ €‚ƒ‚ƒ„‚‚„€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒ ˆ ‡‰ƒ‚„„‚žžžž…žžžžžžžžžžžžžž™ †€ ‚‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ…Š †  ÿ…‰ …  ƒ€‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‚…‡ ‚ € ‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ„ƒƒ € ‚ƒ €‚ƒ„…†‡ˆ„„‰‰‰‰‰‡‰‰‰„‰‰‰…€‚ƒ„…†‡ˆÿ‰Š‹ŒŽ‘’“”•–—˜™š›œ €‚‚ €‚‚ƒ€‚ƒ„…†‡ˆ„„‰‰‰‰‰‡‰‰ˆ†‰‰‰„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ› ‚ƒ ‚ˆ‚‚ƒ‡ƒ‚‚ƒ„„—‡–€ ‚‚ €‚ƒƒ„„ƒ„ƒ‚ƒ‚„ƒ„ÿ„„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ” †‚ ‹Šƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‹‹‹€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’ ‚€ ‚ƒ„‚€‚ƒ„„„ƒƒ„ƒƒƒ„ƒƒ€‚ƒ„…†‡ˆ‰Š„‹‹†‚‹‹‰€‚ƒ„…†ÿ‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‘ ƒ ƒ‚ ˆ€‚‚€‚ƒ„„…ƒƒƒ…‚ƒ……………………………„……………ƒ‚………………€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ ƒ ‚ ‰”‰ƒ‚‚…ƒ‚‚œ‚‚ ‚ €‚‚ €‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‚ÿ‚ ‚… ‚‡ „… €€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽˆŽ „† …‚Œ„Œ ‚ƒ ‚€€‚‚ƒƒÿƒƒƒƒƒƒƒƒƒƒƒ€‚ƒ„…†‡‡‡‡‡‡‡‡ƒ‡‡‡‡„‡‡‡‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ„ ‚ ‚„ „˜ƒœ—š€‚ƒ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚ ‚ „ ƒ†™‚ƒˆ„ƒƒ‚‚ƒ‚ƒ—œ‡ ƒ …ÿ ‚„€€‚ƒ„…†‡ƒƒˆƒƒƒƒ…ƒƒˆ…€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ ‚ „€‚‚ €‚ƒ„…†‡…ƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›› ‚ ƒƒ ÿ…œ‡ƒ‡ƒƒƒƒ‚„œœ‚œ‰ˆƒ‡œœœœœœœœœœœœœœŒ  ƒ €‚‚‚€‚ƒ„…†‡ˆˆ‚ƒƒ‚‚ƒ‰‰‰‰‰‰ƒ‰‰‰‚‡ƒ‡ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›š  ‚… …œ‹Š‚ƒƒ…‚œœ‚œ‚‡ƒˆˆ€‚ÿƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘  „ ƒ…œœ–œœ€‚ƒƒ€‚ƒ„…†‡ƒˆƒ‡ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›˜  † ‚‚€‚‚€‚ƒ„…†‡ˆ‰Š‹ŠŒŒŒŒŒ…ŒŒŒ…ƒ‡ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›˜  † œœœœœ‰œ€‚‚€‚ƒ‚„‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹ŒÿŽ‘’“”•–—˜™š›–  … ‚œœœœœ‹œŽ…ƒˆœœœœœœœœœœœœœœ‡  „ ƒœ—„œŒœ˜œœ„œœœœœœœœœ8qâĉ“!@ € ‚‚ €‚ƒ„…†‡ˆ‰‡ƒŠŠŠŠŠŠŠŠŠ‚ŠŠˆŠŠŠ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›” „ƒ œ™‚‰ƒ‚ƒ‚‚ÿƒœ˜œ€‚ƒ€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š› ƒ œœ…‰‚ƒƒƒ‚€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‚ „‚ œœ‡ƒ€‚‚ƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›Ž‚ ÿ ƒ‚ ‚œœ‰‰ƒ†‚…œœ…œ…œƒœœœœœœœœœœœœœ› ‚ œœŠ‰ƒ†‚…œœ…€‚ƒ„…†…€‚ƒ€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›Œ‚ ƒ œœŠ€‚‚€‚ƒƒ‚„„‚€‚ƒ„…†‡ˆ‰Š†‹‹†„‹‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›Œ „ ÿœœœœœšœœ‰œœœœœœœœœœœœœ™ „ œœœœœœœœ‰œœœœœœœœœœœœœ™ „ œœœœœœœ„€   !#%')+-/1357  8999998889999999999991  89 8818889999999999991   ÿ    !#%')+-/1357  8981888999999999999/  89     !#%')+-/1357  89#ÿ   !#%')+-/1357  89% 89888999999999999-  89' 89 $,4<  8<<< $,4BFJNPRRPRRRRRRRRRRRRRRRRR&(( . PRRRRRRRR>P2P2PRRRRRRRRRRRRRRRRR"($ . PRRRRRRRR>P"P.PRRRRRRRRRRRR¢D‰%Jˆ($,"&*.26:>BFJNÿP"P.PRRRRRRRRRRRRRRRRR($ .PRRRRRRRRBP"&*.26:>BFJNRVZ^bfjB($ .lnnnnnnll&lnnnnnnnnnnnnB(($ .lnnnnnnln.lnnnnnnnnnnnn>($ .lnnnnnnln.lnnnnnnÚ´iÓ¦M›R80HX$,4BFJN&PRRPRRRRRRRRRRRRRRRRR(&$.PRRRRRRRRRPRRPRRRRRRRRRRRRRRRRR(&. PRRRRRRRRRPR>$PRR*PRR.PRR*"&*.02222.*& .022202222*02222* 0222 02222*02222.02222*02222*02222.*& .022202ÿ222*02222* "&" (******(******(******(******(****** *($ .,,(****(******(****** (**** "&*.26:>BFJNRVZ^bfj**$ . lnnnnnn:"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’ÿj"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?Ã$ "&*",....&$ "&*,...."  "&*,....  "&*",.....,.... ,.....,...."$,....& ,.... ,....& ÿ,.... ,.....,..... ,.... ,.... 8HXhxˆ˜¨x°¸¸¸¸¨°¸¸¸¸¨p°¸¸¸¸¨°¸¸¸¸˜p°¸¸¸¸x°¸¸¸¸¸0°¸¸¸¸X0p0°¸¸¸¸ˆ°¸¸¸¸˜0°¸¸¸¸ˆ°¸¸¸¸¨€0°¸¸¸hÑ!@€‚ƒ„…†‡ˆ‰Šˆˆƒ‹‹‹‹‹…‚‹‹‹‹‹‹ƒ‹‹‹‹‹…ƒ‹‹‹‹‹‹ˆ‹‹‹‹‹‰‹‚‹‹‹‹ÿ‹‡‹‹‹‹‹Š‹‚‹‹‹‹‹‰‹‹‹‹‹‰‹‹‹‹‹‹…‚‹‹‹‹‹‹ƒ‹‹‹‹‹…ƒ‹‹‹‹-B(@p°Ðð1Q11`Q0`qqqqÑ0`qqqqQ1`q0`qqqq11`qqqq11`1`qqqq±0@P@p°Ðð1Qq1 `qqqqñ0 €0 @0`0`qqqq1`qqqq11 0 @0`0`qqqq±0`qqqqQ1à0 @0`0`qqqq±0`0`qqqq±0`0`0 @0`0`qqqq1`qqqqqQ0`qqqq11 0 `0 @ÿp°Ðð1Qñ0@P@p°Ðð1Q±0@P@`@p°Ðð1QÑ0@P@p°Ðð1QÑ0@P@`@p°Ðð1Qñ0 `qqqqñ0 €0 `0 `qqqq11@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vv–¶Öö7Ww—·×÷8Xx˜¸Øø9Yy™¹Ùù:ZzšºÚú;[{›»Ûû<\|œ¼Üü=]}½Ýý>^~¾8`1 à1 €žž=z›ÿ"&*.26:>BFJNRVZ^bfjnrvz~‚†Š.$ ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2, ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2,ŒŽŽŽŽŽŽŽŽŽŽ5jÔ¨Q£ $  ( $,46@BBB@BBBBBBBBBBBBBBBBBBBBBBBBB ( ,, @BBBBBBB@B@B@BBBBBBBBBBBÿBBBBBBBBBBBBBB ((,,,$@BBBBBBB 8HXhx@pxxx8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÉXP€  @°°ph`°YP@XYPÀYPÐyÀ@Ð)ÐÙÙÙÙÙÙÙÙÙÙÙÙÙɈ  p°°@h```ÀYP0XPYÀYPÐy   8 8HXhxH 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹8 @pp°PhÐ9XP X0X€XPP@X0X0X XPP X0X XÿPP0XPÐyÀÐyÐÙÙÙÙÙÙÙÙÙÙÙÙÙ™80 €pp° ˜0h``ЙX0X°X0X0X0XPXPPPP 8H8X 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éy80P Ppp°````ÐÉX0XX (0XPPPP0XPP  8HXhxˆ˜¨H°¸x ( 88@H(@H 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éy8ÿP€ @p°``ÐùX0XpX0X0X0XPPP0XP XP@XÐÙÀ€0pÐÙÙÙÙÙÙÙÙÙÙÙÙÙY80PP pp°°``ÐYP€X XP X PPPP XP XPPP P 8HXhxˆ˜¨(°¸h p0p0p 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉI80€€ p°`Ð9Y XPP XPP0XP0XPPPX XPPÐÙÀ p0€€ 88 8HXhxˆÿ˜¨¸ÈØèø)9IYiy‰™©¹‰9P€ p°°`ÀÉÉ)XÀÉ  88 8HXhx8€0p0p 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É98P   °``ÐÙ™YPPÐÙyÐÉ0p0pÐÙÙÙÙÙÙÙÙÙÙÙÙÙ98PP €°``ÐÙÙÙÙyÐ  ( 8(@ 0@8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É98P  °°`ÐÙÙÙÙ™ÀàP0€ÐÙÙÙÙÙÙÙÙÿÙÙÙÙÙ9X €°°`Ðyi`@hйh`ÐyÐÐ9ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ)8P €¸`` 8HXhxˆ˜ˆh`0h` ¨¨¨h` ¨¨¨¨( ¨ˆ ¨¨h 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É 0  €°°`Йi` h`h``0h`` h0h h`` h``0h`ÐyÀ  8 8HXhx8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É90  €°`ÀÉihh` h`0h`0h`0hÿ`` hÐh 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9 p€°`ÀÉyh0h (``0(``0(` 8HXhxˆ˜¨h°¸¸¸¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9  °°`ÀÉyhh0h``h` hPhÀÉYÀYÀ9ÀÉÉÉÉÉÉÉÉÉÉÉÉÉéH p€°`Àɉhh0h``h` hPhÀÉY  8 8HXhx8 8HXhxˆÿ˜¨¸ÈØèø)9IYiy‰™©¹¹I pp°`ÀÉih ( 8`0h h``@h@h`` h 8HXhxˆ˜¨h°¸h@°¸˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹I °°``ÀÉÉÉÉIÀÉ™ÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉH p°°`ÀÉÉÉÉYÀÉ™ÀÉÉÉÉÉÉÉÉÉÉÉÉɹH@ P°€`ÀÉÉÉÉYÀIÀIÀÉÉÉÉÉÉÉÉɉ'NœR\HH0$,4BFJNRVZ^bfjnN*,$ pr*"  " " " "  " "&*,.,,"&*.26:>BFJNRVZ^bfjnJ(,$ prrV"pr"p:$(prrrrrrrrrrrrr(,ÿ prrJ" pr&p6 ,prrrrrrrrrrrrr(, prrrrrp6"&*.26:>BFJNRVZ^bfjn**(, prrrr^"  "&*.26:>BFJNRVZ^bfjnJ*,$ pr2&$ &$$p.&$pbp6  prrrrrrrrrrrrr(, pr2&$& &p*&$pbp: ÿprrrrrrrrrrâÄ‰Ó @  €‚ƒ„…†‡ˆ‰Š‹‚ † ‡ ƒ ‚ ƒ ‚ ‚ ƒ ŒŒŒŒ„ŒŒŒ‡…ƒˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘  œœ• ˆ ‚ ƒ ƒ ƒ ‚ € ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘  œœ” ƒ€ ‚‚ ƒ‚ ƒ‚ €‚ƒ„…†‡ˆÿ‰Š†‹‹„‹‹‹…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘ œœ“ Š ƒ † ‚ … œœ…š‚œ‡œœœœœœœœœœœœœœ‚  œœ’ ‹ ƒ † ‚ … œœ…š‚œ‡œœœœœœœœœœœœœœ"PHX@@$,4BFJNRVZ^bfjn:*$,prJ. .  .,,,, .,,ÿ"&*,.",.."&*.26:>BFJNRVZ^bfjn:* $,prF.(. . . .,,, .,.,.pr p pprrrrrrrrrrrrr*$,prB.,.., . .,,,.,.,,, .prp "&*.26:>BFJNRVZ^bfjn6($.prB.  .,,.,, ., .,,,.,,"&*,.",..ÿ"&*.26:>BFJNRVZ^bfjn6($,prrn.pr"p pprrrrrrrrrrrrn($,,prrb.,,pr&p>0 prrrrrrrrrrrrn($, prrrrr"p ,( "&*.26:>BFJNRVZ^bfjn6*($,prrrrr&p (   prrrrrrrrrrrrn*$,prrrrr&p (  "&*.26:>BFJNRVZ^bfjnÿ*$,prrrrr    "&*.26:>BFJNRVZ^bfjn6*$.prrrrr&p (  "&*.26:>BFJNRVZ^bfjn6*$.prrrrr&p: prrrrrrrrrrrrn*$.prrrrr&p> prrrrrrrrrrrrn*$.prrrrr&pr&prrrrrrrrrâĉ“&@  €‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’†“““ˆ““““““““““““““““““““Š   “““““““““†“““ˆ““““““““““““““““““““Š “““““““““†“““ˆ“““““““““““““““““&Mš¤BÀ €à a¡á!b¢â"c£ã#d¤¤aÀää$bÀäääääääääääääääääääd¢‚B‚àÂääääääää¤aÀää$bÀäääääääääääääääääääd¢A‚àÂäääääääääaÀdb@@@À¤cÀäääääääääääää¤Iÿ“&Mš4) ƒ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉÀIÄÂ€ÉÆ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉDƒÁ…ÉÉÉÉÉÉÉÉÉÀÉÃÀIÆ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉDƒÁ…ÉÉÉÉÉÉÉÉÉÀÉÉIÄ€ÉÉÉÉÉÉÉÉÉÉÉÉI“&Mš4iÒ$D€ !#%&''&''''''''''''''''''' &''''''''&&&'''''''''''''''''''ÿ&''''''''&&&''''''''''''Mš4iÒ¤I“R8H(X$,4BFJ.LNN"LNNNNNNNNNNNNNNNNNNN*$ .LNNNNNNNN.LNN"LNNNNNNNNNNNNNNNNNNN*& .LNNNNNNNN.LNN"LNNNNNNNNNNNNNš4iÒ¤I“)$ ,"&*.26:ÿ>BFJ.LNN"LNNNNNNNNNNNNNNNNNNN*& .,LNNNNNNNN2LNN"LNNNNNNNNNNNNNNNNNNN*$ . LNNNNNNNN2LNN"LNNNNNNNNNNNNNNš4iÒ$I€ !#%&''&''''''''''''''''''% &''''''''&''&''''''''''''''''''%  &''''''''&'#&'''%ÿ&'''% $,4FNV^fnv~† €v €n €f €v €^ $,4BFJLNN"LNNNÿNNNNNNNNNNNNNNNN>($.LNNNNNNNNLNN"LNNNNNNNNNNNNNNNNNNN>*$.LNNNNNNNNL&L:LNNNNNNNNNNNNNNš4iÒ¤I)$,"&*.26:>BFJL"L6LNNNNNNNNNNNNNNNNNNN:($.LNNNNNNNNLL2LNNNNNNNNNNNNNNNNNNN:($$.LNNNNNNNNLNN"LNNNNNNNNNNš4iÒ¤I“&MšäÐÿBÀ €à a¡á!b¢â"c£ã#d¤$@Àää$bÀääääääääääääääääääädã@ÂàÂääääääää$@ÀdcÀdcÀääääääääääääääääääädã@ÂàÂääääääää$@ÀdbaÀ$cÀääääääääääää¤I“&Mš4i#@   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰„“Œ““““““““““““““““““““Œ ‚ ‚ ““““““““““‡€‚ƒ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›Ž ƒ ‚ œœœœœœ„œœˆœœœœœœœœœœœœœœ ‚ ‚ œœœœœœ…œœ‰œœœœœœœœœœœœœ› ‚ ‚ œœœœœœ…œœ‰œœœœœœœœœœœœœ›€  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’‚“““ˆ““““““““““““““““““““‹ ƒ ‚ “““““““““‚“““ˆ““““““““““““““““““““‹ ƒ ‚ “““““““““‚“““ˆ“““““““““““““““““&Mš¤ÿ@BÀ €à a¡á!b¢â"c£ã#d¤¤`Àää$bÀäääääääääääääääääää¤âÂ`ÂàÂääääääää¤`Àää$bÀäääääääääääääääääää¤âÂ`ÂàÂääääääää¤`Àdb€`À¤cÀäääääääääääää¤I“&Mš4I €€@ÁAÂBÃCÄDÅEÆFÇGÈHIÁ€ÉÄÁ€IÇ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉIÅ…Á„Á…ÉÉÉÉÉÉÉÉIÁ€ÉÄÁ€IÇ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉIÿE„Á…ÉÉÉÉÉÉÉÉIÁ€ÉÄÁ€IÇ€ÉÉÉÉÉÉÉÉI“&Mš4iÒ¤I“&MRH `@p°Ðð1Qq‘±Ññ2RR0`21@0`Ò1`rrrrrrrrrrrrrrrrrrrRQap A°`arrrrrrrrR0`rr1`rrrrrrrrrrrrrrrrrrrRQaÐ A°`arrrrrrrrR0`Ò0à0`’1`rrrrrrrrÒ¤I“&Mš4iÒ¤I“R0H(X$,4FNV^fnv~ÿ† €† €v €v €~ €n $,4BFJNRVZ^bfjnr2$ (,t@pt^pt tvvvvvvvvvvvvv2$$ ((,,t @pt^h"&*.26:>BFJNRVZ^bfjnr.$$ (((,t"      t^pttvvvvvvvvvvvvv.&$ÿ ((,,t: ,    "&**"&*.26:>BFJNRVZ^bfjnr*$((( ,tB    "&*,.  "&*.26:>BFJNRVZ^bfjnr&(( ,tB     tvpÿ$  tvvvvvvvvvvvvv&$(  ,tN   "&* ,.  "&*.26:>BFJNRVZ^bfjnr"(( ,,tR(  tvp   "&*.26:>BFJNRVZ^bfjnr($ ,prrpr   ÿ"&*.26:>BFJNRVZ^bfjnr(( ,tvntvt2  tvvvvvvvvvvvvv($ ,,tvvvv"t   "&*.26:>BFJNRVZ^bfjnr(($ ,,tvvvv&p8  tvvvvvvvvvvvvv($ ,t^t.t^tttvvvvvvvvvvvvv*$ ,t^"ÿ$&&&&$&&$&&&"&*.26:>BFJNRVZ^bfjnr(&,tb$   t^p"&*.26:>BFJNRVZ^bfjnr*($ ,,tv $   4"&**"&*.26:>BFJNRVZ^bfjnr*$ ,tv  ÿ  "&*,....*"&*.26:>BFJNRVZ^bfjnr*$ ,tv$ tvtt tvvvvvvvvvvvvv*$ ,tv$ tvh"&*.26:>BFJNRVZ^bfjnr*$ ,,tv   "&*,.,.&"&ÿ*.26:>BFJNRVZ^bfjnr *($ ,tvvvv:tvtvvvvvvvvvvvvv *$$ ,tvvvv:tvtvvvvvvvvvvvvv(($ ,tvvvv:tttvvvvvvvvvvvvv¤@`p°° 8HXhxˆ˜¨¸ÈØèøi ©@ Ù )))))))))))))))))))))¹¨`p° )ùxp@x )Ixp@xp )  ©@ Ù )))))))))))))))))))))©¨@`0° )ùxp0xp )Yÿèàà@p°Ðð1ñ0@QÑ0@p0@p°Ðð0@p°Ðð1Qq‘±Ññ2Rr’²Òò3SssSAà !aaóòà@ðà ñàà`ðàà@ðàà@ðàà`ðàà€ð€ðà€3€3€1€“““““““““““““³Qà `¡€“Sð ñà@ðà`ðàà@ðàðà@Pð`ð`ppppð@p°Ðð°@p @p°Ðð1QQ1@p°Ðð1Qq‘±Ññ2Rr’²Òò3SssSAð a“sð`ð@Pÿààààà@Pðàà@ðààà`ð@p°Ðð1Q‘0`qñ0@0`qQ1@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsSSAÀà a“sð ñ`ðà`ðà ðààà`ð`ð€“s0€3@0 €s0€““““““““““““““QÀ a“sð ñ`ðà`ðà ðààà@ðà`ð€“s @ÁAÂBÃÀÁ€ÃÃÃÃÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMM€ƒ„„NNÀAA@ÁA€ƒÁÿÁƒƒÁB€ƒÁÁƒ€Áƒƒ@ÁAÂBÃCÄDÅÁ€ÅEÀÁ€ÅÅÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMMƒƒ„…NNNNÎÊN€ÁNÂNNNNNNNNNNNNNNF€€„…NNNNÎÊNÎÄNNNNNNNNNNNNNÎE…ƒ„„…NNNNÎÊN€€NÃNNNNNœ8qâĉ'NœR 80H@X$,4BFJL&L:LNNNNNNNNNNNNNNNNNNN"*&,LNNNNNNNNLNN"LNNNNNNNNNNNNNNNNNNN"*&,LNNNNNNNNLNN"LNNNNNNNNNNNNš4iÒ¤I“&¤pÿ (X° 8HXhxˆ˜¨¸ÈØèø) 0‰0 09999999999999999999y¨p@˜PX°099999999 0y00ù09999999999999999999y¨p@˜Pˆ°099999999 0y00ù099999iÒ¤I“&Mš4iÒ¤I“&M:Há @Pa@p°Ðð1Qq‘±Ññ2R `ò0`0`ò1`rrrrrrrrrrrrrrrrrrròP€0¡paarrrrrrrr `ò0@pP@p°Ððp0@p°ÿÐð1Qq‘±Ññ2Rr’²Òò3Ss3Q¡0¡p“““““³0€“31€““““““““““““óRÐ ¡p“““““³0€“31€““““““““““““óRÐ ¡p“““““³0€“31€““““““““““““óRÐ0@Pp@p°Ðð1Qq‘±Ññ2RR0`rr1`rrrrrrrrrrrrrrrrrrrÒPá€0ÁparrrrrrrrR0`rr1`rrrrrrrrrrrrrrrrrrrÒPá€0¡°`arrrrrrrrR0`rr1`rrrrrrrrrrrrrÿrrÒ¤I“&¤p (ˆ° 8HXhxˆ˜¨¸ÈØèø))099‰09999999999999999999i¨p@˜Pˆ°099999999)099‰09999999999999999999i¨@hPˆ°099999999)099‰099999999999999iÒ¤I“&¤ 8ˆ° 8HXhxˆ˜¨¸ÈØèø))099‰09999999999999999999i¨@˜`¸0999999999099‰0999999999999999ÿ9999Y¨ 08Pˆ°099999999909099©099©099©(@p°Ðð1QqQ0€‘‘‘‘ñ0€‘‘QÐ ¡a!1€‘‘‘‘ñ0€‘‘‘‘ñ0€‘‘0€‘‘‘Ñ0 1€‘‘‘‘ñ0€‘‘‘‘ñ0€‘‘‘‘ñ0€‘‘‘‘1€‘‘‘‘ñ0€‘‘Q0Ápa!1€‘‘‘‘ñ0€‘‘‘‘ñ0€‘‘0@p°Ðð11`0à0Ap°Ðð1Qq‘±Ññ2Rr’²Òò3SsQ¡@Ppaapp @p°Ðð1Qq €‘‘‘‘ñ0€‘‘0ÿ€‘‘‘±0`0à0@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsóPaÐÀp! €“““““@p°Ðð11`0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt´0`0€””””””””””””””””3 €””””””””””””””””T3@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vv–¶Öö7Ww—·×÷8Xx˜¸Øø9Yy™¹Ùù6 7 0@P@p°Ðð1Q‘0`qqqqÑ0ÿ 0@P@p°Ðð1Q‘0 `qqqq‘0 0@P@p°Ðð1Qq0 `qqqq‘0 0@P@p°Ðð1Q±0`qqqqqqq‘0 `qqqq‘0 1`qqqqñ0 `qqqq±0 1`qqqqñ0`0`qqqqQ0`0à0`qqqqÑ0`0`qqqqQ0`0à0`qqqq1 `qqqqqqqq0`0`qqqqQ0`0à0 0@p°Ðð1Qq0 `qqqq‘0 1 `qqqq1`qqqqÑ0à0 `qqqqñ0`qqqqÑ0àÿ0 `qqqq‘0 `qqqqqqqq0`0`qqqqQ0`0à0`0`qqqq‘0`qqqqÑ0 1`0`qqqqÑ0`qqÑ¢E†  "&*,....  ,.... ,....... ,....  ,,....,...., ,....,...., ,....,....,,.... ,......."&*  ,,....,...., ,....,..ÿ..,,....,....,,....  "&*.264666 46664666& 46664666& 4666 4666   4666"4666666 4666& 4666 "&*   "&* "&*   "&*,.... ÿ,...."&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏ{,<ÐÓÓ£Go @ÁAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑѯÑÑÑÑQƀŀ€Á€Ã€ÑÑÑÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚ˆ„ƒ„£££££££££££££££££‰‚ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage04.gif0000644000175000017500000003235207253523117024041 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ™€‚ƒ„…€‚ƒ€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠÿŠ‚ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠ€‚ƒ„…††€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠ€‚ƒ„€‚ƒ€‚ƒƒ€ ‚ƒ„…†‡ €‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠŠŠŠŠŠ‚ŠŠŠŠ„€ ‚ƒ„…†‡‡€ ‚ƒ€ ‚ƒ„…‚€ ‚ƒ€‚ƒÿ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ€‚‚€ ‚ƒƒ€ ‚ƒ € ‚ƒ„…†…€‚ƒ„…†‡‡‡‡‡‡‡‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž•€‚ƒƒ€ ‚ƒ€‚‚ € ‚ƒ„… €‚ƒ„…†‡ˆ‰ƒŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž…„€‚ƒ‚€ ‚ƒ €‚‚ €‚ƒ€‚ƒ„…†‡ˆÿ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž…€‚ƒ€ ‚ƒ€‚ƒ€ ‚ƒ €‚ƒ„ƒ…………………………‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžƒ€‚‚ €‚‚ € ‚ƒ„ €‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ˜€‚ƒƒ€‚ƒ € ‚ƒ„‚ÿ€‚ƒ„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ—€‚‚€‚‚  € ‚ƒ €‚‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’†€ ‚‚ €‚ƒƒ„‚‚„€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ÿˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚‚€‚ƒ  ‚ƒƒ‚ƒƒƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŽ‰ …‰ƒ‚„„‚žžžž…žžžžžžžžžžžžžž›‡ € ‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŒŽŽŽŽ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‹… ÿ žžž’žž…žžžžžžžžžžžžžž™ƒ žžž”žž…žžžžžžžžžžžžžž˜… žžž—€‚ƒ„…†‡‡‡‡‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‡ƒ †„žŠ„ž–›„ž‚žžžžžžžžžžžžžž•‚ ˆƒžŠ„ž–š†žžžžžžž&@BBB@BBBBBBBBBBBBBBBBBBBBBBBBBB ",(($$@BBBBBBB@B@B@BBBBBBBBBBBBBBBBBBBBBBBBBB ,($$@BBBBBBB@2"&*.26:>BFJNRVZ^bfjnrj" ,(\ÿ@pt^pt tvvvvvvvvvvvvvj".((` @pt^h"&*.26:>BFJNRVZ^bfjnrj",(d      t^pttvvvvvvvvvvvvvf ,((t ,     4"&**"&*.26:>BFJNRVZ^ÿbfjnrb,,,($t     "&*,.  "&*.26:>BFJNRVZ^bfjnrb., ((t     tvp$  tvvvvvvvvvvvvv^",(t   "&* ,. ÿ "&*.26:>BFJNRVZ^bfjnr^.,$(t(  tvp   "&*.26:>BFJNRVZ^bfjnr:.,$(tv:tn   "&*.26:>BFJNRVZ^bfjnrV, $$(tv2tvt2  tvvvvvvvvvvvvvR,$(tvvvZtÿ   "&*.26:>BFJNRVZ^bfjnrR,,$(tvvv^p8  tvvvvvvvvvvvvvR, &(tt.t^tttvvvvvvvvvvvvvN, $(t""$&&&&$&&$&&&"&*.26:>BFJNRVZ^bfjnrN,$(t&$   ÿt^p"&*.26:>BFJNRVZ^bfjnrN,,((tB$   4"&**"&*.26:>BFJNRVZ^bfjnrJ, ((tF    "&*,....*"&*.26:>BFJNRVZ^bfjnrJ,(tJ$ tvtÿt tvvvvvvvvvvvvvJ,((tJ$ tvh"&*.26:>BFJNRVZ^bfjnrJ, ($tB  "&*,.,.&"&*.26:>BFJNRVZ^bfjnrF,($tvvvrtvtvvvvvvvvvvvvvF,,($tvvvrtvtvvvvvvvvvvvvvF",($tvvvvtÿttvvvvvvvvvvvvvB ,*$"&*.26:>B&D.D:DFFFFFFFFFFFFFFFFFFFFFFF:,,($DFDFDFFD.D:DFFFFFFFFFFFFFFFFFFFFFFF:,((DF DF:88$,4BFH2(   HJJJJJJJJJJJJJJJJJJJJJ>*$,HJJJJJJJ:H2(  "&*.26:>BFJNRVZ^bfjnf*$,prrrr*    "&*.26:>BFJNRVZ^bfjnr*$,tvvvv6t(  ÿ"&*.26:>BFJNRVZ^bfjnr*$,tvvvv6t6 tvvvvvvvvvvvvv*$,tvvvv6t: tvvvvvvvvvvvvv*$$,tvvvv:tvtvvvvvvvêÔ©S§NRH8X$,4BFHJJ.HJJJJJJJJJJJJJJJJJJJJJ2*($,HJJJJJJJ>HJJ.HJJJJJJJJJJJJJJJJJJJJJ2*$,HJJJJJJJ>H*H>HJJJJJJJJJJJ’$I’$I’$I’$‰ ƒ€@ÁAÂBÃCÄDÅEÆFÇGÈHÃÉÄÂIÇIIIIIIIIIIIIIIIIIIIIIÉE€„„IIIIIIIÉÇIÄÃÉÆÿIIIIIIIIIIIIIIIIIIIIIÉE€„IIIIIIIÉÇIIÉÅIIIIIIII’$I’$I’$I’$I’$I’"@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘†’’’‹’’’’’’’’’’’’’’’’’’’’’’Š ‚  ’’’’’’’’’Ž’Ž’’’’’’’’’’’’’’’’’’’’’’‰ ‚ ’’’’’’’’’Š„’’’’’’’’’’$I’$I’$I’$I’$IR"@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‡’ÿŠ„’’’’’’’’’’’’’’’’’’’’’’’‰  ’’’’’’’’’ˆ€‚ƒ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›› ‚ œœœœœ”œœˆœœœœœœœœœœœœœœ ‚ œœœœœ”œœ‰œœœœœœœœœœœœœœŒ ‚ œœœœœ”œœ‰œœœœœœœœœœœœœœ"P80HX$,4BFJNRVZ^bf:*& ","&*.26:>BF:"&" "&*.26:>BFÿJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?Ã@3@+@+@3@' "&*.2.466666 4666662466666. 466666* 4666662466666.4666666466666ÿ 466666*4666666 4666666466666."&*.2.466666*466666 466666246666664666666466666.466666. 466666&466666  466666246666664666666"&*.2*4666666 466666& 466666 466666246666624666666466666* ÿ"&*.268::::: 8::::*8:::::8:::::8:::::" 8:::::8::::: 8::::: 8::::.8::::: "&*.2& "&*.2.46666664666662466666."&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSWÿ[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏO,<ÐÓÓ£Go @ÁAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€Á€Ã€ÑÑÑÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚Oˆ„ƒ„£££££££££££££££££‰‚ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage05.gif0000644000175000017500000003666607253523117024056 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹€ ‚‚€‚ƒ„… †††††††€‚ƒ„……€ ‚ƒ„€‚ƒ„…†‡‚€‚ƒ„…€‚ƒ„…†‡ˆ‰Š…€‚ƒ„…†‡ˆ‰Š‹ŒÿŽ‘’“”•–—˜…€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠƒ € ‚ƒ„…†‡„€ ‚ƒ„…†‡ˆ‰Š‹ €‚ƒ„…†‡ˆ‰Š€‚ƒ„…†‡ƒˆˆˆˆˆˆˆƒˆˆˆˆˆˆˆƒˆˆˆˆˆˆˆƒˆˆˆˆˆˆˆ„ˆˆˆˆˆˆˆƒˆˆˆ‡ˆˆˆˆˆˆ‡ˆˆˆˆˆ„€ ‚ƒ„…ƒ€ ‚ƒ€‚ƒ„…†ƒ€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡ˆ‰„ŠŠŠŠŠ‰ŠŠŠŠŠ‰ŠŠŠŠŠ‰ŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠ…‰ŠŠŠƒ ‚€ ‚ƒ€ÿ‚ƒ„ƒ€‚ƒ„„€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠ‰ŠŠŠŠŠ‰ŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠƒ€‚‚€‚ƒ„„„„„„„„  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ƒ¡    ¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡‡¡    ¡¡¡¡¡¡¡¡¡¡¡¡¡…„¡‡¡‰€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹Š €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•ÿ–—˜™š›œƒŠƒ€‚ƒ„…†‡ˆƒ€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‰ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚ƒ…€‚ƒ„…†‡ˆƒ€‚ƒ„…ƒ€‚ƒ„…†€‚ƒƒ€‚ƒ„…†‡ˆ‰ŠŠ‹‹‰ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‡‚€‚ƒ€‚ƒ„…†ƒ€‚ƒ„…„€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‰ ÿ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œš€‚ƒ„ƒ€‚‚‚€‚ƒ„…†ƒ€‚ƒ„…†‡ˆ‰‰ŠŠŠŠŠŠ…ŠŠŠ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚ƒ„…†‡ˆƒ€‚‚‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹‰ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘€‚ƒ„…†‡€‚ƒ„……†‚ƒ†‚…††††††††…€‚ƒƒ€‚ƒ„…†‡ˆ‰ŠŠ‹‹ÿ‰ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š€‚ƒ„…†‡€‚ƒ„…†‡ˆ‰‰ƒ‚„„‚‰ƒ€‚ƒ„…†‡ˆ…€‚ƒ‚€‚ƒ„…†‡ˆ‰ŠŠ‹‹‰ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™€‚ƒ„…†‡€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹Œ‚€‚ƒ„…†€‚ƒ„…†‡ˆ‰ƒŠŠŠŠŠŠ…ŠŠŠ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™…€‚ƒ‚€‚ƒ„…††‡‡‡‡‡‡‡‡‡‡ƒ€‚ƒÿ„…†‡€‚ƒ„…†‡ˆ‰Š‹„ŒŒŒŒŒ…ŒŒ‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜”€‚ƒ„€‚ƒ„…†‡€‚ƒ€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒˆŽŽŽŽ‰ŽŽƒ ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ‚€‚ƒ„€‚ƒ„€‚ƒ„…†‡€‚ƒ„…†‡ˆ‰‡€‚ƒ„…„€‚ƒ„…†‡ˆ‰Š‹ŒŽ†ƒ ‰€‚ƒ„…€‚ƒ„„€‚ƒ€‚ƒ„…†‡ÿˆ‰Šƒ€‚ƒ„…†€‚ƒ„…†„††††††„„††††††††„††††ƒ„†††††‚††††† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—„€‚ƒ„„€‚ƒ„…†‡‡‡‡‡‡‡‡‡…‡‡‡‡‡‡ƒ‡‡‡‡‡…„‡‡‡‡‡‡‡ƒ‡‡‡…†‡‡‡‡ƒ‡‡‡‡‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–•€‚ƒ€‚ƒ„…†‡ˆ€‚ƒ€‚ƒ„…†‡ˆ‰Š…‹‹‹‹ƒ‚ƒ‡ƒ‚ÿ‚ƒ„„‹‹‹‹ˆ‹‹‹‹‹Š‹‹ˆ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–’—Š€‚ƒƒ€‚ƒ„…†‡ˆ‰Šˆ‹‹‹‹‹ƒ‡‚ƒ‚…ƒ‹„€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹ˆ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‘—ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹„ŒŒŒŒ‰ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰ÿŠ„‹‹‡‹‹‹‹‹ˆ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–“€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‡€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰Š…ƒ‡ƒƒ…ƒƒ‹‹‹‹‹„‹‹†‚‹‹‰‹‹ˆ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–Œ‰€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Šˆ€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹Œˆƒƒ…‚ƒ‡‚‚…„ ÿ‚…€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ƒ€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŠ‰ƒ‚‚…ƒ‚‚†‚‚…„ …ƒ€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‡”‰”Œ”Š ””””””””””””“…”””†””””””””””„”””…”Š ””””””””””””‘†”””…””””””””””ˆ”Œ”Œ”Šÿ ””””(Q¢D‰%J”*$ $,4B DFFFFFFFFFFFFFFFFFFFFFFD& DFD**,DFFFFFFF DFFFFFFFFFFFFFFFFFFFFFFD& DFD**,DFFFFFFF"&*.26:>BFJNRVZ^bfjnJh pl*,prrrr prrrrrrrrrÿrrrrh  ""*, """""""""""""""" "&*.26:>BFJNRVZ^bfjnNpr&l*,prrrn prrrrrrrrrrrrrpr&l*,prrrj prrrrrrrrrrrrrpr&l*,prrrf  prrrrrrrrrrrrâtP €à a¡á!b¢¢bÀâb¡ÂÂâââââââââââ"!`AÀÀ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æfeÿ'gbÀ¦Â'''ç%Á`à''''''''''''''b'gbÀ¦Â'''ç%`AàÀ''''''''''''''b'gbÀ¦Â'''g%Á`àÀ'''''''''''Nœ8% 8HXhxˆ˜¨¨°¸X¨°°¸¸¸¸¸¸¸¸¸¸¸H@0X 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹™ÀÉ™°©°ÀÉÉÉIIPPP000ÀÉÉÉÉÉÉÉÉÉÉÉÉɹÀÉ™°©°ÀÉÉÉIIP000ÀÉÉÉÉÉÉÉÉÉÉÉÉÉéÀÉ™°©°ÀÉÉÉ9IÿPP0ÀÉÉÉÉÉÉÉÉÉÉɉ§H€    "&*,....,....,....,....,....,.&,...& ,&&$$$,,,, ,.",....,. ,.,...ÿ.,....,....,...."&*,....,.&,...& & ,,,("&*.26:2 <>>>>>>>>>>>>>>>>>>>>>>>>>>>"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvz~ÿ‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?ÃÜØØ Ðȼ¼À"& (********(**** (****  (**** (**** (***" (***  (*** (*** "&ÿ  $&&&&&&&& $&&&&&  $&&&& $&&&& $&&&&  $&&&&   $&&& $&&&""  $&&&   $&&&&&&&& $&&&&& $&&&& $&&&& $&&&& $&&&&   $&&&& ÿ"&  $&&&&  $&&&& $&&&&&&&& $&&&&&  $&&&& $&&&&  $&&&&  $&&&&   "&  $&&&&  $&&&&   $&&&&   $&&&&&&&& $&&&&" $&&&& "&  (***&  (***"ÿ   (*** (***  "&   (***   (*******"(****(**** (**** (**** (***& (*** (***"&   (***  (********(**** "&&(****(*ÿ*** (***"  "&  "& "&  "&  "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏs,<ÐÓÓ£Go @ÁÿAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€Á€Ã€ÑÑÑÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚ˆ„ƒ„£££££££££££££££££‰‚ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage06.gif0000644000175000017500000004203007253523117024035 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ…ŠŠŠŠÿŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠ…ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŠŒŒŒŒŒŒ„ŒŒŒŒŒŒ„ŒŒ‹ŒŒŒŒ‡‰ŒŒŒŒŒŒ„ŒŒŒŒŒŒ„ŒŒŒŒŒŒ„ŒŒŒŒŒŒƒŒŒŒŒŒŒ„ŒŒŒŒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ†€‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‚€‚ƒ„…†‡ˆ‰‡€‚ƒ„…†‡ˆ‰Š‹Œ‡€‚ÿƒ„……€‚ƒ„€ ‚ƒ„…†…€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™‡€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡ˆ‰Š‹‰€‚ƒ„€ ‚ƒ„…†‡ˆ‰Š‹ŒŽƒ€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜‰€‚ƒ„…†‚€‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ„…†‡†€ ‚ƒ„„€‚ƒ„…†…€ ‚ƒ„…†‡‡€‚ƒ„…†‡ˆ‰ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜‚€‚ƒ€‚ƒ„ÿ…†‡ˆ‰Š€‚ƒ„…†‡ˆ‰ˆ€‚ƒ„…‚€ ‚ƒ„…‚€ ‚ƒ„…†‡ˆ„ €‚ƒ„…†ƒ‡‡‡‡‡‡‡ƒ‡‡‡‡‡‡‡‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜‚™‹€‚ƒ„…†…€‚ƒ„…†ƒ€‚ƒ‚€ ‚ƒ„…†€ ‚ƒ„…‚€ ‚ƒ„‚€‚ƒ„€ ‚ƒ„… €‚ƒƒ‚ƒ‚‚€‚ƒ„…†‡ˆ‰Š‡€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–——˜€‚ƒ„€‚ƒ„…ÿ†„€ ‚ƒ„…†‡€ ‚ƒ„…†…€‚ƒ„…†‡…€ ‚ƒ€‚ƒ„…ƒƒ€‚ƒ„…†‡ƒ€‚ƒ„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—•Š€‚ƒ„…„€‚ƒ„……€‚ƒ„€ ‚‚€‚ƒ€‚ƒ„…€ ‚ƒ €‚ƒ„…†‡ˆ…€ ‚ƒ„…ƒ€‚ƒ„€‚ƒ„……€‚‚ƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š€‚ƒ€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—‡€‚ƒ„‚€‚ƒ„„€‚ƒ„……€‚ƒ„…„€‚‚€ ‚ƒ€‚ƒ„…‚€ ‚ƒƒ€‚ƒ„…†‡‚€ ‚ƒ„…ƒ€‚ƒ„…„€‚ƒ„€‚ƒ„ƒƒ…‚ƒ…‚………‚€‚ƒ„…†‡ˆˆ€‚‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–”€‚ƒ„€‚ƒ€‚‚€‚ƒ„…†‡ƒˆˆ…€ ‚ƒ„…†…€‚ƒ„…€ ‚ƒ„…†‚€‚ƒ„…††€‚ƒ„€‚ƒ„…†ƒ…€‚ƒ„…†‡ˆ„€‚ƒ„ÿ‚€‚ƒ„€‚ƒ„…††‡‡‡‡‡‡‡‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‹€‚ƒ„…†…€‚ƒ„…€‚ƒ„……€ ‚ƒ„…‚ €‚ƒ„…€ ‚ƒ„…†…€‚ƒ„…†…€‚ƒ„…†ƒ€‚ƒ„…†…€‚ƒ„…€‚ƒ„…€‚ƒƒ€‚ƒ„…†‡ˆ‰‰‰‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‰‚’€‚ƒ„…ƒ€‚ƒ„…† ‡€ ‚ƒƒ€‚ƒƒ€ ‚ƒÿ„ €‚ƒ„…†‡†€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‡€‚ƒ€‚ƒ„…†‡ˆˆ€‚ƒ„…€‚ƒ„…†‡ˆ‰ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–€‚ƒ‚€‚ƒ„ƒ€‚ƒƒ€‚ƒ„…†„€ ‚ƒ„‚€ ‚ƒ„‚€‚ƒ€ ‚ƒ„‚€‚ƒ„…†‡ˆƒ€‚ƒ€‚ƒ„…†‡ˆ‰…€‚ƒ„€‚ƒ„…†‡‡€‚ƒ„…€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‡€‚‚€‚ƒ„‚€‚ƒ€ÿ‚ƒ„…†‡„ ‡ …€ ‚ƒ„ƒ€‚ƒ„…†‡ˆ‰€‚‚€‚ƒ„…†‡ˆ‰…€‚ƒ€‚ƒ„…€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹‹ŒŒŒŒŒ…ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‡…‰€‚ƒ€‚ƒ„…†‡†€ ‚‚€ ‚ƒ € ‚ƒƒ€‚ƒ„…†‡ˆ‰…€‚ƒƒ€‚ƒ„…†‡€‚ƒ„…†…€‚ƒ„ƒ€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽƒƒƒ€‚‚€‚ƒ€‚‚€ÿ‚ƒ„…†‡‡€ ‚‚€ ‚ƒ €‚ƒ„…†‡ˆ‰Š‡‹‹‡€‚ƒƒ€‚ƒ„„€‚ƒ„…†„€‚ƒ„„„„„„„„„„„„€‚ƒ„…†‡ˆ‰‡ŠŠ‡„ŠŠŠ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•‰„‡– ƒ ––••€‚ƒƒ€‚ƒ„…€‚ƒ€‚ƒ„…†‡„ƒˆˆˆˆˆ„ˆˆˆˆˆˆ„ˆˆˆ‚†ˆˆˆ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•„€‚‚€‚ƒƒÿƒ‚€‚ƒ„…†‡ˆ€ ‚‚ €‚ƒ„…†‡ˆ‰Šˆ€‚‚€‚ƒ„…‚€‚ƒ€‚ƒ„„€‚ƒ„€‚ƒ„…†‡ˆƒ‚ƒ‡ƒ‚‚ƒ„„‰‰‰‰‰‡‰‰‰‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•‚ˆ‡–Ž ‚€ ‚ƒ €‚ƒ„…†‡ˆ‰Š‹‹‚€‚ƒƒ€‚ƒ„ƒ€‚ƒ€‚ƒ„…†‡ˆ‰Šƒ‡‚ƒ‚…ƒŠ…€‚ƒ„…†‡…€ÿ‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š€‚ƒ‚€‚ƒ„…†‡… € ‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹†ŠŒ„€‚ƒ€‚ƒ„…†‡ˆ‰Š‡ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‰‰‹‹‹„€ ‚ƒ €‚ƒ„…†‡ˆ‰Š‹†€‚ƒ€‚ƒ‚„„„‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹‚ƒÿ‡ƒƒ…ƒƒŒŒŒŒ‹ŒŒ„‚ŒŒ‡ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒˆ€‚‚€‚ƒƒ„„„„„„„„„‚ €‚ƒ„…†‡ˆ‰Š‹‡Œ„€‚ƒ„„€‚ƒ„…†‡ˆ‰Š‹‰ˆƒƒ…‚ƒŒŒŒŒ‹ŒŒ„‚ŒŒ‡ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‡ŒŒŒŒ‚ ŒŒŒŒŒŒ„‹€‚ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŒ‰ƒ‚‚…ƒ‚ÿ‚†‚‚…ŠŒ ‰†ƒ†€€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”ŠŠ•Œ€ ‚ƒ€‚ƒ„…†‡ˆ‰Š‹Œ‚ˆŠŠŠ… ‚†‹††ÿ5jÔ¨Q£D€                     ÿ    !#%')  * *++ *++++            *+***+++++++++ **++!! "&*.26:6 ,     4"&**,.................. ÿ,..*($,....." "&*.26:>     "&*,.  "&*.26:>BFJNRT".,,( &TVV&"TVVVVJ     TVBT$  TVVVVVVVVV T"., *(&TVVB@pÐÀÿààà@p°Ðð1Qq‘±ÑñѰ ±@° `°`°   @° @°   `°21’1 @0à0`0à0`0à0R°àp€€’qaaPa0!²ÁÐÀÀàà @±  @°°      @P°@°  @p°Ðð1Qq0`qÑ0 @0à0`01 0@pp@p°Ðð1Qq‘±Ññ2Rr’± p`€€€qaPA0!’’²APÀÀÀÀà@p°Ðð1ÿQq‘±Ññ2ò±@RRR0@pp@p°Ððp0 1`0à0`0à0@p°Ðð1Qq‘±Ññ2Rrr² `p`@€2qaPAA0!’’²!Ñ€ð€’’’’’’’Ò°  €’’²0€’ `0à0`0à0€’’’’’’’’’2±`p``€2qAPAa0’’²!Ñ`ðà€’’’’’’’’’’ò1€20@P@pP0 €0 @0`0€p0@p°Ðð1Qq‘±Ññ2Rrr²``€€2qaPA0!!’’’!Ñ`ð€’’’’’’’’’’2€1À1 0 `ÿ0 1€’’’’’’’’’±@p`€€qaaaP !’’²!ÑÀ@ðàà€’’’’’²ÑÀ€Ð€’ÒÀ@p°Ðð1ñ0@Q11 @QQQ0@QQQQQQQQQQQQQQQQQQQ±```@€@QqPA !AQQQQQ±ð@p@p°Ðð1Qq‘±ÑñÒÀ`ÐÀÑÀ’0’1’0ò±``€²qaaPA0RáðàÀrÑÀ@ÐÀ ÑÀÀ`ÐÀÀ@Ð`Ð@ÐÀÀ@ÐÀÀ`ÿÐÀ’0’P€à €à a¡áá` €à a¡á!b¢â"c£ã#d¤ä$dAÁ¥â‚ ‚‚BB%%¥!Âá€%%%%%%å¡A¢ €Á €Á €Á € A# à a¡áa! €à !@ €à a¡á!b¢¢bÀââââââââââââââââââaÀÁâ¢â‚ @BÂââââb"ÂáÁÁââââââââââââb¡Á    €€À  €€À  € €à a¡á!b¢¢aÀââââ¢bÀââââââââââââÿââââââaÀÁâ¢â‚ @Âââââb"‚âÁ€Áâââââââââââ⢡A¢Á €¡€ A¡Áââââ¢aÀââbÀâbbÀââââââââââââââââââ! €@ÁAÂBÃÀDDDDDDÄCDÁA@ÁAÂBÃCÄDÅEÆFÇGÈFƒDƒACAƒBƒÈÈHÅ€ÈÄÀÁA@ÁAÂBÃÃÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÇ‚‚ÊÆA€JJÊACÀAA@ÁAÂBÃCÄDÅEÆFÇGÈF@AÿA@ÁAƒAABBA@ÁAÂBÃCÄDEÀÅEÀÅÅÄ€ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ€‚ÅÅÅÁ„ÅÅÅÅÅC„ÃBƒÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅEÀÅÅÅÅEÅ€ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ€‚ÅÅÅA@€@ÁAÂBÃCÄDECăBƒÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÀÅÅÅÅEÅ€ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ‚‚ÅÅÅ€„ÅÅÅÅEC„ÃBƒÅÅÅÅÅÅÅÅÅÅÅÿÅÅÅÅÅÅÅÅÅÅEÄ€ÅEÅ€ÅEÅ€ÅÅÅÅE‹-Z´hÑ¢E‹-Z´¨ @ÁAÂBÃÃÂ…ÁDDDDDDDBăB@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊÊÉKÃÂËÄKKKKKKKKK‚KÆ€„KKHăBKKKKKKÅ€ÂKɃ€KKÄKÃÂËÄKKKKKKKKK‚ËÅ…ÁKËH„ƒƒƒBKKK–,YZèààà@p°Ðð±ð€ðà 1111ñ0 10@p0@p°Ðÿð0@p°Ðð1Qq‘±Ññ2Rr’±€€Òq@A !’’¡ðÀÐÀ€’’’’’’rðà@ðà ñàà`ðàà@ðàà@ðàà`ðàà€ð€ðà€’’1€1€2€’’’’’’’’’  €€²qAPA0’’¡ðÀÐÀ@p°Ðð1Qq‘±Ññòñ ñà@ðà`ðàà@ðààà ð`ðàð@p°Ðð°@p @p°Ðð1QQ1`qqqqqqqqqqqqqqqqqq°`€`qqq@a0aqqqqÑðÀÐ`qqqqqqqqqqÿqqQñ`ð@Pààààà@Pðàà@ðààà`ð@p°Ðð1Q‘0`qñ0@0`qQ1`qqqqqqqqqqqqqqqqqQ°`€`qqq@A0!aqqqq±ðà ÐÀ`qqqqqqqqqqqqQñ ñ`ðà`ðà ðààà`ð`ð`qqqq‘0`qÑ0@0 `q11`qqqqÑ¢E‹-Z´hÑ¢E‹-¨`€@p°Ððpa@A0±aðàÀÐ@p°Ðð1Qq‘±Ññ2à ñ`ðà`ðà ðààÿà@ðà`ð@RR²0@R1 @0@²1@RRRRRRRRRR  €@òqAPA0ARRÒaðÀÐÀ@RRRRRRRð@P@pà`ð@ðàà@ð€à`ð@ðàà@ðàà@p°Ðð1Qq0`qÑ0 @0`q11`qqqqqqqqqqqqqqqqq `€`qqq@A0!aqqqq±ðÀÐ`qqqqqqqqqqqqqqqqqqqqqq‘0`qñ0@0`qQ1`qqqqqqqqqqqqqqqqq± `€€`qq €@ÁAÂBÃCÄDÅB„ÁCƒÅÅÅÿÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅE€ÅÅÅÅEÅ€ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ€‚ÅÅÅ…Á„ÅÅÅÅÅA„ÂBƒÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ€ÅÅÀ€ÅÅE"&*.26:>BFJNP6.(&PRF"  PRRRRRRRRRRRRP"P.PRRRRRRRRF P:.( &PRJ"PRRRRRR2" "@" P"" PR2P"P. $,4BFJNRVZ^6`bF`bbbbbb6 `2.$`b"`bbbbbbbbbbb`bF`bbbbbb6 `..($`b""`bbbbbbbbbbb`"`"`bbbbbb6 .($ """"""""&*.26:>BFJNRVZ^:```bbbbbb6 `..($`b""`bbbbbbbbbbb ```bbbbbb6 `2.$`b"" `bbbbbbbÿbbbb ` "&*.26:>BFJ& LF.$LNF" LNNNNNNNNNNNNNNL&LFLNNNNNNNN& LF.$LNF" LNNNNNNNNNNNNNNLNN"LNNNNNNNN" LF.$$LNF""&*.26:>BFJNRVZ^:`bF`bbbbbb. `2.($`b"" `bbbbbbbbbbb`bF`bbbbbb. `2.$`b"" `bbbbbÿbbbbbb`bF`bbbbbb. `2.$`b"„` 8HXhxˆ˜¨¸ÈØèø)9IYiyù€‰€‰‰‰‰‰‰©H@P0€É¸€‰‰ˆ0h€‰‰‰‰‰‰‰‰‰‰‰9€‰€‰‰‰‰‰‰©HP0€É¸€‰‰ˆ€ h€‰‰‰‰‰‰‰‰‰‰‰I€‰€‰‰‰‰‰‰©HP0€É¸˜ 8HXhxˆ˜¨€0h 8HXhxˆ˜¨¸ÈØèø)9IYiy €I €™€‰‰‰‰‰‰™H@P0€É¨°€‰‰ˆ0h€‰‰‰‰‰‰‰‰‰‰‰I€Iÿ €™€‰‰‰‰‰‰™HP0€É¸€‰‰ˆ0h€‰‰‰‰‰‰‰‰‰‰‰I€I €™€‰‰‰‰ ¦D€    !#%')+-/!0 00111111 001 011111111111 0 00111111 001 011111111111 01#0111111    ÿ!#%')+-/!000111111  001 011111111111 0 00111111 001 011111111111 0 !#% &!&'% &''''''''''''''&&'''''''' &!&'% &''''''''''''''&&''''''''DÿP0 8HXhxx¨°€ˆˆˆˆˆxx€@h 8HXhxˆ˜¨¸ÈØèø)9IYiy€0 € 88 8HXhxˆ˜¨¸ÈØèøùHP0 ©° )))x€0h ))))))))))))))  88 8HXhxˆX0˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜XHP˜˜ˆ¨°°˜˜˜˜˜(x€ h` 8HXhxˆ˜¨¸ÈØèø)9IYiy)€0€ €‰‰‰‰‰‰yH@PP€¹¨°€‰‰x€ h€‰‰‰‰‰‰‰‰‰‰‰y€)ÿ@ °€‰‰‰‰‰‰yHP0€©¨ °€‰™x€ h€‰‰‰‰‰‰‰‰‰‰‰y€9P ( 8 8HXhxˆ˜¨¸ÈØèø)IHP00ù¨°09)y€0h099999999999999©099‰099999999IHP00ù¨°09)y€ h099999999999999¹099‰099999999IHPP0 ©°09) x€` 8HXhxˆ˜¨¸ÈØèø)9IYiyI€)€é€‰‰‰‰‰‰yHP0€©¨ ¸€‰‰x€ h€‰ÿ‰‰‰‰‰‰‰‰‰‰‰€)€é€‰‰‰‰‰‰yHP0€©¨ ¸€‰yxp€``€‰‰‰‰‰‰‰‰‰‰‰‰€) 8( 8HXhx8 8HXhxˆ˜¨¸ÈØèø)9H@P00ù¨°09)y€€`099999999999999É0y090999999999HP00ù¨°09)y€ h099999999999999É0y090999999999HP00ù¨¸ 8HXhxˆ˜¨x€` 8HXhxˆ˜¨¸ÈØèø)9IYiyi€‰€‰‰‰‰‰ÿ‰iHP0€™¨ °€‰yx€€`€‰‰‰‰‰‰‰‰‰‰‰©€‰€‰‰‰‰‰‰iHP€©¨ ¸€‰yx€``€‰‰‰‰‰‰‰‰‰‰‰©€)`€y€‰‰‰‰‰‰iˆ @p°ÐðÐP`!ÑðÀ@p°Ðð1Qq‘±Ññ2Rr’²Òòò2s0€01Ó  SQ`!³ðàÀs1“0 31Ó sQ`Óð@Às132&L…ÿ*(, """""""&*.26:>BFJNRVZ^^`bF`bbbbbb`**,,`b `bbbbbbbbbbb.``.`bbbbbb `&*(,$`b"`bbbbbbbbbbb2`  `*`bb„ ¦B€      !#%')+-/1000111111  001  011111ÿ111111000111111 001  0111111111110  !#%  $$%! $%%%%%%%%%%%%%%%$%%$%%%%%%%%  $$% $%%%%%%%%%%%%%%%$%%$%%%%%%%%  $    !#%')+-/12323333ÿ3+  223 23333333333323233333)  223 23333333333323233333)  2)$,"& ""&*.26:>BFJNRVZ^bdf>dfffffR d* .,df "dfffffffffffdf>dfffffN d* &,df" dfffffffffffdf>dfffffJ * ÿ. """"" "&*.26:>BFJNRVZ^bdf>dfffffJ d* .,df dfffffffffffdf>dfffffJ d*( .df"dfffffffffffdf>dfffffF  *(&, """""""&*.26:>BFJNRVZ^bdf$dffdff4 d*&,Xd " d:dffdffdÿffd*df dffdff0 d*&$,,Xd  "$&&&&&&&$&&&&&&&$&&&&&&&$&&"$&&&&" &"&*.26:>BFJN.* ,,"&" "$&&&&&&&$&&&&&&&$&&&&&&&$&&"$&&&&" "&&(*********"(**(.(****" ÿ"&*.26:>BFJNRVZ^b>"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?Ã$ "&*. 02222"ÿ "&*.268::::8:::. 8:::. 8:::2 8:::.8:::28::::8:::::. 8:::6  8:::: "&*. 02222 02222 02222 02222& 0222222* 02222.  02222& 02222" 02222ÿ 0222bdP@@@ €à a¡á!b¢âb@@@€`À`Àââââââ`€`À`Àâââââââ¢aÀ`ÀâââââbaÀ`À`Àâââââ¢`À`À`Àâââââ"a@À`Àââââ¢b€`€`À`Àâââââ"a@À`ÀâââââbÀ`@À`Àâââââ¢`À `@ €à a¡á!b¢â"cã`À`€££££#@À`À`€£££ãbaÀ`€££££c@À`€£££c"`€  @@ €à a¡á!b¢â"a@À`####£aÀ`@À`###ÿ##bÀ`À`######ãb@#####ca@####ãa€a@####ãaÀ`€`@####cbÀ`@####ãaÀ`€`@####ãaÀ`€`@####Fˆ "&*.268:::: "&*.  "&*.02222*02222&02222&02222&"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šžÿ¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏ,<ÐÓÓ£Go @ÁAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€Á€Ã€ÑÑÑÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„}„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚ˆ„ƒ„£££££££££££££££££‰‚ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage07.gif0000644000175000017500000003250607253523117024045 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ„ŠŠŠŠÿŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠŠ„ŠŠŠŠ‡ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ„ŠŠŠŠ)R¤H‘"B€                ÿ!#%')+-/13579;=      !#%')+-/13579;=      !#%')+-/13579;=        !ÿ#%')+-/13579;=       !#%')+-/13579;/      !#%')+-/13579;'  ÿ      !#%')+-/13579;#      !#%')+-/13579;     ÿ!#%')+-/13579;      !#%')+-/13579;     !#%')+-/13579;  <=='<= <=========ÿ====%                ÿ           !#%')+-/135795           :/:;:;;;;;;;;;;;;;/          ÿ     !#%')+-/13579/  0        !#%')+-/13579)  4        :;8::;;;;;;;;;;;;;)   :    ÿ     !#%')+-/13579'  :        :;8::;;;;;;;;;;;;;%  :;;;#:::;;;;;;;;;;;uê P‚ÁÂÂÀÀÀÀ €à a¡á!b¢â"c£ã#d$$$$@$$$$$$$$$$$$$$$$$$$$$$$$$¤a‚ÁÂBÂà$$$$ÿ$$$$c$d$d$$$$$$$$$$$$$$$$$$$$$$$$$d!‚ÂÂÂÀà$$$$$$$dc$c € @ €à a¡áá` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&§#À‚AÂÁÁÀ@'a@adAg@Açega@§`@gggggggggggggg#BAÁÂÁAÀÀ@§a@Á`@dg@Açe€&`€à` €à a¡á!a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'#BÁÂÂ@‚à@ça@`Á`bAAaÁÿ`Á``AA`Á``AAÁ`@Açeg@ça@gggggggggggggç"‚BBB‚àÀ@'cÁ`ÁbÁ`Á`Á`Aa@Á``@ €à á `à a¡áa! €à !@ €à a¡á!b¢¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'"BÁ‚Áà@§cÁ``  À`@@@@À`@@€ €à a¡á!b¢"aÀââ!`€  €àà`!¡`@@!a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æÿ&ç!‚àÂB‚àÀÀÀ@çcÁ`ÁaÁ`Á`Á`@@@Á`@`AaAggg@@@b@bÀ`Àa@ggggggggggggg§!‚àÂB‚ÀÀ@çd@b`AÁ`Á`@ @@@A@A@@@ €à a¡á!b¢¢`Àâ¢a@€`ÀaÀ`ÀaÀ`Àa €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g!@ÁÁBÂà@gebA@`AAÁ`@Á`A@Aa`AAAggg@€`ÀaÀ`b@@"`€àà €à a¡á!b¢â"c£ãÿ#d¤ä$e¥å%f¦æ&&‚`€à'''a''`€àà €à a¡áá`@bÀ`ÀaÀ`Àa €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&ç ‚`€À@g'gAAAgça@'cÀ`ÀaÀ`Àa@gggggggggggggç @€à@gggggb@'`€  €à `@a@€`À`á` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&§ @ÂÂÁÀ@gggg§bg€c@a@À`@@b@ggggggggggggg§ À‚€À@'¦ÿ€¡A碀Açe@g@@@@ç`@ggggggggggggg'‚ÂB À €à a¡á!bb¢€Á ¢¢¢¢€¢¢¢¢¢`€¢"b€¢¢¢a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'‚B‚ÀÀ@g¦€ €A¢€Á  Á   €Á €Açe'`€à €à a¡áá` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'B‚‚ÀÀ'§¡A¢ €Á €Á €Á € A# à a¡áa! €àÿ !@ €à a¡á!b¢¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'‚ÂÂBÀÀ'ç¡Á    €€À  €€À  € €à a¡á!b¢¢aÀââââ¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&§‚ÂBÁ'g¢A¢Á €¡€ A¡'gagaç`'''''''''''''g#‚ÂÂB'§¢A¢Á €¡€ A¡'ga€f`€à €à a¡áá` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ææ¦ÿÂÂAÁÀ''"   €à €Á  ¡¡  €à a¡á!b¢¢aÀâ¢aaÀâbb €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦¦‚‚AÁ''''çe'gb''''''''''''''£Â‚AÁ'''''f'gb'''''''''''''çbÂAÁ'''''f'a'a'''''''''''''§b`ÂA €à a¡á!b¢â"c£ã#d$c€¤ba€dc€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤a‚‚A¤¤äàÀá¤ÿ$áÁáÀ¤$d€¤ba€dc€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤da‚‚‚A¤¤äàÀÁàÁ¤d! €€@ÁAÂBÃCÄÄÃEECÀÁÁ@ÁAÂBÃCÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMË„………NNÁ€Á€ƒÄ€ƒƒÁƒƒÁ€ƒÁƒ€ƒÁƒƒÂ€NÌÎNÄNNNNNNNNNNNNNNÄ…NNŃăÁ€ƒÁ€ƒÁ€€€ƒBÀ€@ÁAÂBÀÁAÂBÃÃB@ÁAB€ÿ@ÁAÂBÃCÄDEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍʃ…NÎŃAÀAA€€€€€@AÁ€€ÁƒƒƒƒÁ@ÁAÂBÃCÄDE€ÅÅÃÁ€ÅEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍÊ€NÎŃăÁ€ƒÁ€ƒÂ€€€ƒÁƒÁNÎÁÎÁ€ÎÁNNNNNNNNNNNNNNÃ……NNƃăÁ€ƒÁ€ƒÂ€€€ÁƒƒÁNÎÁÎÀ€@ÁAÂBÃÃÁ@ÁÿAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÊ……NNEÀAA@ÁA€ƒÁÁƒƒÁB€ƒÁÁƒ€Áƒƒ@ÁAÂBÃCÄDÅÁ€ÅEÀÁ€ÅÅÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÊ………NNNNNNÁN€ÁNÂNNNNNNNNNNNNNNÃ…NNNNNÎÁNÎÄNNNNNNNNNNNNNNÄ…NNNNNÎÁN€€NÃNNNNNNNNNNNNNN…$,"&*.26:>BFJH*Hÿ6HJJJJJJJJJJJJJJJJJJJJJ$(,HJJ&" "@" H*" HJBH*H6HJJJJJJJJJJJJJJJJJJJJJ$(,HJJ&" " D"" "&*.26:>BFJNRVZ^bfjnN&(,pr" " (" " " "" " "" " pbppprrrrrrrrrrrrr&(,,pr:"4" " " "" " ÿ "4""&**"&*.26:>BFJNRVZ^bfjnJ&(,pr>" "  " " "&*,....*"&*.26:>BFJNRVZ^bfjnJ*(,pr>"$" " " " " " "pr hpprrrrrrrrrrrrr( ,pr>"$"" " " " " "prlÿ"&*.26:>BFJNRVZ^bfjnF*( ,pr6"  " " " "  " "&*,.,,"&*.26:>BFJNRVZ^bfjnB*$$,prrb"pr"p:$(prrrrrrrrrrrrr *$ ,prrV" pr&p6 ,prrrrrrrrrrrrr *$,,prrrrrp6 ÿ"&*.26:>BFJNRVZ^bfjn"*$,prrrrj"  "&*.26:>BFJNRVZ^bfjnB*$,pr>&$ &$$p.&$pbp6  prrrrrrrrrrrrr($,pr>&$& &p*&$pbp: prrrrrrrrrrrrâHA!Á` @p°Ðð1Qq±0 Á0á0 !a0!!A0a0A0!!A0 !a0 ‘‘‘‘0€‘‘ñ0ÿ 0 `0 1@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsÓQ Á`¡€“31!A0 a0 a0 a0 !A0¡0Ap°Ðð°@p @p°Ðð1QQ1@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsÓQ!!aa¡€“ó2a0AP  `P  `P @p°Ðð1QÑ0`q‘0`qq±0@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsÓQ!` €“Ó2A1a0 Á0 A0¡0“³0@3@0€ó0€““““ÿ“““““““““S!aa €“³2a1a0 Á0 A0¡0“³0@3@0€ó0€““““““““““““sPA!a¡@p°Ðð1Qq‘0AP@p a0A0!!00!!A0@p°Ðð1QÑ0`q‘0@0`qqQ0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss³Q!á`¡€“““““1@0@pP@p°Ððp0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss³Q!aa €“““““1€“31€““““““““““““sSá` €““ÿ“““1`0@p@p°Ðð0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss³Qá`¡€“““““31@3À0€s0€““““““““““““sSá`¡€““Q@aPAAsQAP@3@3À0€s0€““““““““““““SSAá`¡€““Q@APaPs€€ €à a¡á!bâa€¢¢a€a€¢¢"@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&£B‚ÁB''£€‚¡Â¡€‚ ‚‚‚ €‚‚ ‚€Â ‚‚¡¡€'fÿ€&`€à  €à a¡áá` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&£BÂÂBA''¥¢‚‚ €Â €‚‚ €€€B¡Â Â# ‚à a¡áa! €à !@ €à a¡á!b¢¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&£BÂB''¥Â  ‚  €€€€€ €  €€‚ ‚‚‚  €à a¡á!b¢"aÀâbaaÀâ¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&£ÂÁB'礂¢Â €Â €B¡ÿ€€€Â Â 'ç`€f€aç`''''''''''''§¦ÂÁB'§¤Â¢Â €Â €B¡€€€‚ ‚ 'ç`€f€aç ` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&£‚Á@'§$ ‚  €à €Â ‚ ‚‚‚ !€Â ‚ ‚€‚ ‚‚ €à a¡á!b¢â`Àâ"a€aÀâbb €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&£‚Á@'''''§bÀ&`€à €à a¡á!a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ÿæ&£Á@'''''§b'gb''''''''''''gf‚Á@'''''§b'gb''''''''''''gf‚ÂB'''''çb'gb''''''''''''g¦ÂÁ` €à a¡á!b¢â"áÀÂàÂÂãàÂ##áÀ####a####ca €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ææ¢‚ÁB'§ãÀ‚àÂàÂãçÀ'f'gb''''''''''''g¦‚ÁB'§ãÀ‚áâÂÂáÂàÂà‚à‚àÂà‚àÂÂÂàÀÿ'f'gb''''''''''''N™), "&*.2.0. . . .., ., .0."&**"&*.26:>BFJNRVZ^bfjn**$,prZ. .  .,,,, .,,"&*,.",.."&*.26:>BFJNRVZ^bfjn**$,prV.(. . . .,,, .,.,.pr p pÿprrrrrrrrrrrrb*$,prR.,.., . .,,,.,.,,, .prp "&*.26:>BFJNRVZ^bfjn**$, prR.  .,,.,, ., .,,,.,,"&*,.",.."&*.26:>BFJNRVZ^bfjn**, prrr.pr"p pprrrrrrrrrrrrb*, prrr.,,pr&p>0 prrrrrrÿrrrrrr^*$,prrrrr2p ,( "&*.26:>BFJNRVZ^bfjn&*$,prrrrr6p (   prrrrrrrrrrrr^*$,prrrrr6p (  "&*.26:>BFJNRVZ^bfjn($,prrrrr    "&*.26:>BFJNRVZ^bfjn"*($, prrrrr6p (  ÿ"&*.26:>BFJNRVZ^bfjn"*$,prrrrr6p: prrrrrrrrrrrrZ*$,prrrrr:p> prrrrrrrrrrrrZ*$,prrrrr:pr&prrrrrâĉ'Nœ8Y¤0°P 8HXhxˆ˜¨¸ÈØèø)¹099‰09999999999999999999i¨°P099999999¹099‰09999999999999999999i¨°P099999999¹0ÿ99‰0999999999999999999iR!@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’‹“““ˆ““““““““““““““““““““…  “““““““““‹“““ˆ““““““““““““““““““““…  “““““““““Œ“‰“Ž““““““““““““““&Mš4iÒ¤B€  !#%&&&'''''''''''''''''''  &''''''''& &&''''ÿ'''''''''''''''   &''''''''&''&''''''''''''Mš4iÒ¤I“ RHX($,4BFJ6L&L2LNNNNNNNNNNNNNNNNNNNÿ*$ ,LNNNNNNNN6L"&*.26:>BFJNRVZ^bfjn*( $ ,prrrrrBpp"prrrrrrrrrrrrN* $,prrrrrBpr&prrrrrrrrrrrrJ( $,prrrrrBpr&prrrrrrrrrrrrF($,"&*.26:>BFJ6LNN"LNNNNNNNNNNNNNNNNNNN( $,LNNNNNNNN6LNN"LNNNNNNNNNNNNNÿNNNNNN( $,LNNNNNNNN6LNN"LNNNNNNNNNNNNš4iÒ¤I“&¤pp0°P 8HXhxˆ˜¨¸ÈØèø)Ù099‰09999999999999999999I p`0°P099999999Ù099‰09999999999999999999I p`0°€P099999999Ù0™ 0é0999999999iÒ¤I“&Mš4iÒ$@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰‚“Ž“““““““““““““ÿ“““““““  ““““““““““‰‚“Ž““““““““““““““““““““  “““““““““Ž“‰‚“Ž“““““&Mš4iÒ¤I“&Mš4iÒ$I€   !#%&&&''''''''''''''''''%   &''''''''&''&''''''''''''''''''%   &''''''''& &&''''''Mš4iÒ¤I“&Mš4ÿi’$@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’Ž“‡…““““““““““““““““““““’  ‚ “““““““““Ž“ˆƒ‹Šˆ“““““““““““““““““““’  ‚ “““““““““Ž“‰‹€€‚ƒ‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›  œœœœœœ‘œ‹ƒ‹‡œœœœœœœœœœœœœŽ  œœœœœœ’œƒŠˆ€‚ƒƒÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š“  ‚ ››››››€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›  ‚ ››››››˜›ŽƒˆŠ››››››››››››››  ƒ ››››››˜›„‚‹››››››››››››››  ƒ ››››››˜›…€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›  ƒ ››››››˜››‹››ÿ››››››››››››  „ ››››››˜››‹›››››››››››››š  „ ››››››˜š›‹›››››››››››››š€  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‡“““““““““““““““““““““  ƒ ““““““““““‡€‚ƒ‚€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™šš  ƒ ››››››˜š›‹›››››››››››››™  „ ››››››˜š›‹ÿ›››››››››››››™  „ ››››››˜››‹›››››››››››6mÊHà `¡@p°Ðð1Qq‘±Ññ2R2`rr1`rrrrrrrrrrrrrrrrrròQá Á€p¡`rrrrrrrr2`ò0À0`’1`rrrrrrrrrrrrrrrrrròQá a€p¡`rrrrrrrr2`1€0`²1`rrrrrrrrrrÒ¤I“&Mš4iÒ#@ €‚‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰“Ž“““““““““““““““ÿ““““ … ““““““““““““ˆ“““““““““““““““““““ … “““““““““‘“““ˆ““““““““““““““““&MšäÂA‚À €à a¡á!b¢â"c£ã#d¤ddÀ$b@@À$dÀäääääääääääääääää䤣ÂA‚áBÁääääääääddÀäaÀ`ÀäcÀäääääääääääääääää䤣B‚AáBÁääääääääddÀäaÀ`ÀäcÀääääääää¤I“&Mš4iÒ¤I“RH0\(ÿ$,4BFJNRVZ^bfjnr&,(pr .  .,,.,, ., .,,,.,,"&*,.",.."&*.26:>BFJNRVZ^bfjnr& ,(prr:.pr"p pprrrrrrrrrrrrr:& ,prr..,,pr&p>0 prrrrrrrrrrrrr:&,prrrr^p ,( prrrrrâĉ'Nœ8qr(`á@p°Ðð1Qq‘±Ññ2R1@’1@1`01ÿ 1@RRRRRRRRRRRRRRRRRRRRRR1`ARRRRRRRRR0@’1@1`0à0@00@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3SssÒ `““““0@pp@p°ÐðP0Q0`0à0@01@p°Ðð1Qq‘±Ññ2Rr’²Òò3Sss3a`A““““3€S0@1`0à0@P@p @p°Ðð1Qq‘±Ññ2Rr’²Òò3Sss3a`A““““3€Ó1 €0  01€“““““““““““““³1a`“““ÿ“3€ó1 0  01€“““““““““““““³1a`““““3€“31€““““““““““'NœJX@$,4BFJNRVZ^bfjnb&(,prrrrjpr&prrrrrrrrrrrrr*&(,prrrrjpr&prrrrrrrrrrrrr*&(, prrrrjpr&prrrrrrrrrrrrr*&(, "&*.26:>BF6HJÿJ.HJJJJJJJJJJJJJJJJJJJJJ*,HJJJJJJJJH*H>HJJJJJJJJJJJJJJJJJJJJJ(,HJJJJJJJJH*H>HJJJJJJJJJJ’$I’$I’$I’$IR!@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘Ž’Š‚’’’’’’’’’’’’’’’’’’’’’’’…  ’’’’’’’’’…’Š‚’’’’’’’’’’’’’’’’’’’’’’’…  ’’’’’’’’’…’Š‚’’’’’’’ÿ’$I’$I’$I’$I’$I’$I…%(, "&*.26:>BF:HJJ.HJJJJJJJJJJJJJJJJJJJJJ*, HJJJJJJJJHH6HJJJJJJJJJJJJJJJJJJJJJ*, HJJJJJJJJH"H:HJJJJJJJJJ’$I’$I’$I’$I’¤B€ !#$$%%%%%%%%%%%%%%%%%%%%% $%%%%%%%% $ÿ$%%%%%%%%%%%%%%%%%%%%% $%%%%%%%%   !#%')+-/1357-8999998 !#%')+-/135789999)   !#%')+-/1357-899999889999999999999 ÿ8999998899999999999998999998  !#%')+-/1357+ 8999998989999999999999 8999998989999999999999  8999994889999999999999   !#$$%$%%%%%%%%%%%%%%%%%%%%% $%%ÿ%%%%%% $  !#%')+-/1357+89999948899999999999998999994889999999999999 8999998989999999999999  !#!$%%$%%%%%%%%%%%%%%%%%%%%% $%%%%%%%%$ $$%%%%%%%%%%%%%%%%%%%%%ÿ$%%%%%%%%$$$%%%%%%%I’$I’$I’$I’$I’$I‚), "&*.26:>BFBH*H>HJJJJJJJJJJJJJJJJJJJJJ * ,HJJJJJJJJ"HJJ.HJJJJJJJJJJJJJJJJJJJJJ *.HJJJJJJJJ"HJJ.HJJJJJJJJJJJJ’$I’$I’$I’P‚ÂÀ €à a¡á!b¢â"c£ã#ddd€db@@€dd€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤$€ÿÁÀ‚¤¤¤¤¤¤¤¤$b€$bÀ`€$d€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤$€ÂÁÀ‚¤¤¤¤¤¤¤¤$b€$bÀ`€$d€¤¤¤¤$I’$I’$I’$I’$I’$I’$I), "&*.26:>BFFH" HBHJJJJJJJJJJJJJJJJJJJJJ(. HJJJJJJJJ"H" "&*.26:>BFJNRVZ^bfjnN*.prrrrr pr&prrrrrrrrrrrrr&(.ÿprrrrrpr&prrrrrrrrrrrrr*( .prrrrrpr&prrrrrrrrrrrrr* ,"&*.26:>BFJHJJ.HJJJJJJJJJJJJJJJJJJJJF&(.HJJJJJJJJ&HJJ.HJJJJJJJJJJJJJJJJJJJJF&(.HJJJJJJJJ&HJJ.HJJJJJJJJJJJJJJJ’$I’$I‘%(,"&*.26:>BFJLNN"LNNNNNNNNNNNNNNNNNNNÿ>*( .LNNNNNNNNLNN"LNNNNNNNNNNNNNNNNNNN:&(.LNNNNNNNNLNN"LNNNNNNNNNNNNNNNNNNšäP‚ÀÂB €à a¡á!b¢â"c£ã#d¤$@Àää$bÀäääääääääääääääääääd£‚‚àBÁääääääää$@Àää$bÀääääääääääääääääääädc‚àBÁääääääää¤`Àädd@bÀää¤aÀäääaÀää¤! @ÁAÂBÃCÄDÅÄ€ÅÅÅÅEÄ€ÅÅÅÅÅÄC‚ÿ„…‚ÅÅÅEÀÅÅÅÅEÄ€ÅÅÅÅÅÁ€ÅÅÅEŀĀÅÅÅÅEÄ€ÅÅÅÅÅÄ€ÅÅÅÅEÄ€ÅÅÅÅÅÄ€ÅÅÅÅEÄ€ÅÅÅÅÅÄ€B…„…‚‚ÅÅÅEÀÅÅÅÅED@€‚ƒ„…†‡ˆ‰Šƒ‹‹‹‹‰ƒ‡‹‹‹‹‹ˆ‹‹‹‹‹‰‹‹‹‹‹ˆ‹‹‹‹‹‰‰€‚ƒ„…†‡ˆ„€ ‚ƒ„…†‡ˆ‰Š‹‰€ ‚ƒ„…€‚ƒ„…†‡ˆ‰†ŠŠŠŠŠŠƒŠŠŠŠŠˆŠŠŠŠŠƒƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”€ ‚ƒ„…†‡ˆ‰Š‹Œ…ÿ€‚ƒ„…†€‚ƒ„…†‡ˆ„€ ‚ƒ„„€‚ƒ „€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’„€‚ƒ„…†‡ˆ‰ˆƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£…ƒ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤˜¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎϰ¿¿½À¼€‚‚€‚ƒ„…†ÿ‡ˆ‰Š‡‹‹‹‹‹„€‚‚€‚ƒ„…†‡ˆ‰Š…‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†‹‹‹‹‹‡ƒ‹‹‹‹‹„ƒ‹‹‹‹‹‡‹‹‹‹‹…‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹„ƒ‹‹‹‹‹‹‹‹‹‹Šƒ‹‹‹‹‹„‹‹‹‹‹‹‹‹‹‹‹ $,4N^n~Žž®¾ÎÞîþ/?O°ð 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *ʰÿ00::::::::::::::::º@0P0::::::::::::::::ʰ@0@0::::::::::::::::Ê 8H@ P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *ʰ@@P0::::::::::::::::Ê €@0@0::::::::::::::::Ú 0 00::::::::jÔ¨Q£F5jÔ¨Q£F5jÔ$@;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage09.gif0000644000175000017500000003325507253523117024051 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠÿŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ€€‚ƒ„…†‡ˆ‰Š‹ŒŽ†‹€‚ƒ„…†‡ˆ„€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‚€‚ƒ„…†‡ˆ‰Š€‚ƒ„…†‡ƒ€‚ƒƒ€‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžÿމ€‚ƒ„…†‡ƒ€‚ƒ„„€ ‚ƒ‚€ ‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž‡€‚ƒ€‚ƒ„€ ‚ƒ„„€ ‚ƒ„…†‡„€ ‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžƒ€‚ƒ‚€‚‚€‚‚€ ‚‚€ ‚ƒ„ƒ€ ‚ƒ„€‚ƒ„…„€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜ÿ™š›œž€‚‚ € ‚ƒ„‚ €‚ƒ„„€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚€‚‚€ ‚‚€ ‚‚€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œœ‚€‚ƒ €‚ÿƒ„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ›‚  ƒ€‚‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ™ ‚ …ƒ†‚…žžžž…žžžžžžžžžžžžžžžˆ € ‚‚€‚ƒ‚ƒ„‚‚„ÿ€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ–‚‚ „‰ƒ‚„„‚žžžž…žžžžžžžžžžžžžžž‡ žžžžž…žžžžžžžžžžžžžžž„€ €‚ƒ„…†‡ˆ‰Š‹ŒŽŽŽŽŽ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‘ žžž‘žž…žžžžžžžžžžžžžž›€‚ÿ‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽƒƒŒ‚ „Š„‡Œ„‚)„€PPP`0pp@°°  @@@@ 8HXhxˆHH@H@˜˜˜˜x˜ˆ`˜˜H 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ©ˆP 80`@°° PH@ÿ H0HpH@@0H@@ H@@ H@@0H@@@H@H@àiàéYàéééééééééééé鉉€000°° ¨°H0HpH@ H@ H@@ H@@@ (@ @ 8HXH 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙyX€€00``@°°   ÀH0HH (@@@@@ (H@@ H@@@0H 8HXhxˆ˜¨H°¸x°¸¸ 8HXhxˆ˜¨ÿ¸ÈØèø)9IYiy‰™©¹ÉÙiX€00``pp°° ðH0HpH0H@0H@PH@@@0H0HàÙÀ à àéééééééééééééY‰€0``p°°  I@€H0H@0H@PH@H@@@@ 8HXhxˆ˜¨H°¸h °¸˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙYˆ€00`p   °PIH0H H@@ HPH0H H@@ H@@àÉÀ à àéééééééééééééI‰00`p @°ÿàéééIÐà)àééééééééééééÉÓ$@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ„† „ ŽŒ€€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ  ’„œ—œ„‚ÿ› ‚ “ƒœ—š€‚ƒ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ›  ”‚ƒˆ„ƒƒ‚‚ƒ‚ƒ—œ‡™ ›ƒ‹ƒƒƒ…ƒ€€‚ƒ„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ™ÿ‚ ƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ™‚ ƒ‡ƒƒƒƒ‚„œ‰ˆƒ‡—‚ ƒˆ‚ƒƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹†‚‡ƒ‡ƒ‡€‚ƒÿ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ– …Š‚ƒƒ…‚œ‚‡ƒˆˆ€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ ›€‚ƒƒ€‚ƒ„…†‡ƒˆƒ‡ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ“ ЇŒƒ‡ƒ‡“‚ ”€ÿ‚‚€‚ƒ‚„‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ“ •œŽ…ƒˆ’ †„‹—ƒ’€ €‚ƒ„…†‡ˆƒˆˆˆˆˆˆˆˆˆˆˆ„ˆˆˆ„ˆˆˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’ ˆ‚‰ƒ‚ÿƒ‚‚ƒ—œ€‚ƒ€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‘ ‰‚ƒƒƒ‚€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚ ‘ƒ€‚‚ƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ  ÿ’‰ƒ†‚…ƒ„‚  ’‰ƒ†‚…ƒš€‚ƒ€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ  ‘€‚‚€‚ƒƒ‚„„‚€‚ƒ„…†‡ˆ‰Š†‹‹†„‹‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ  œ‡Ž  ‡ÿŽ  ƒƒ:5d`Pp ° 8HXhxˆ˜¨¸ÈØèø™¹@é¹h HPp °)xp@xixp@xp ¹@é©8` ˜p °°)xppp 8HXhxˆXx@xp˜˜˜˜x˜ˆ 8 8HXhxH 8HXhxˆ˜¨¸ÈØèøÿ)9IYiy‰™©¹ÉÉ8`€p °Ð‰xp xpxpp0xpp xpp xpp0xpp@x@xpÐyÀÐyÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹8`€p  °Ðùxxp xp0xpp xppp (x0x08888x 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹8``p °Ð y0x (ppppp (xpp xppp0x 8HXhxˆ˜¨H°¸x °¸ÿ¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹8` °Ð yx0xp0xpPxppp0x0xÐÙ À Ð)ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ©8``@Pp °°Ð yx0xp0xpPxppp xp0x 8HXhxˆ˜¨H°¸h °¸˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É©8`@@p°°Ðùx ( 8p0x xpp x@p0x xpp xpp 8HXhxˆ˜¨8°¸h °¸˜ÿ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É©8`@p°°ÐÙÙÙÙIÐ Ð9ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ™8``@p°ÐÙÙÙÙYÐÙyÐÙÙÙÙÙÙÙÙÙÙÙÙÙ™8`@ °ÐÙÙÙÙYÐÐYÐÙÙÙÙÙÙ©S§N:uê„ÐÀ€A €à a¡á!b¢â"c£ã#¤c@äb@€`@¤c@ddddddddddddddddddddddd¤á€ABÁÁÂBdä!!$Bä"Bdd$@@äb@€`@¤c@dddddddddddddÿdddddddddddá€ABà €à a¡á!¢! B""Bbb"Bbbbbâa@bb"@@€`@bb"a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&çá€AÂÁÂBg#‚ ‚"!  ‚ ‚  ‚  Bçe@g@@@@ç`@gggggggggggggçá€@BÀBg%B#   B!  €  €à á ‚à a¡áa! €à !@ €à a¡á!b¢¢b €à a¡á!b¢â"c£ã#d¤ä$ÿe¥å%f¦æ&çá€ABB‚ÂBg% ‚  À À € €à a¡á!b¢"aÀââââ¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&§á€A‚ÂBg%B"    ‚ !Bgg€f€a@§`@ggggggggggggg§á€AÀ‚ÂB§%B"‚   ‚ ‚   €à a¡á!b¢¢`ÀâbaaÀâ¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&ÿ§á@Á‚ÂB'% ‚  €à  ‚   !‚  €à a¡á!b¢â`Àâ¢a@@@ÀbÀb@@Àa €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&gá€AÁ‚ÂBgg'Bg§a@gc@@b€b@ggggggggggggggá@‚`€ÂBgç&Bgça@'cÀ`ÀaÀb@ggggggggggggggá@‚`€ÂBgggg'" @ÁAÂBÃCÄ€Á€Ã€€€DÀÁÁA@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍÿLƒÁ…NNNNÎBÀÁÁA@ÁAÂBÃCÄ€Á€Ã€Á€Ã@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎBƒ‚………ÎÊ€„Á„„„NÅ€„ÎË€NÆ€Á€Ã€Á€Ã€ÎÎÎÎÎÎÎÎÎÎÎÎÎÎBƒ‚……NË€Á„Á„ÎÄ€„ÎË€ÎÆ€Â€Á€Á€Ã€ÎÎÎÎÎÎÎN:uêÔ©!@  €‚ƒ„…†‡ˆ‰† † ‡ ƒ ‚ ƒ ‚ ‚ ƒ ŠŠŠŠŠ‚ŠŠŠŠƒ…ƒˆ€‚ƒ„ÿ…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ„  ˆ ‚ ƒ ƒ ƒ ‚ € ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ„ ‚ ƒ€ ‚‚ ƒ‚ ƒ‚ €‚ƒ„…†‡ˆ‰Š†‹‹„‹‹‹…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ ‚ œ Š ƒ † ‚ … ƒš‚†ÿƒ  œ ‹ ƒ † ‚ … ƒš‚†:uêÔi ƒ€‚…@ÁAÂBÃCÄDEAÀAA@ÁA€„ÁÁ„„„„Á@ÁAÂBÃCÄDEÀÅEÂÁ€ÅÅEÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎA€€‚……ÎÎÎÎNÅMÀÁAA@ÁAÂBÃÃÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÁƒÁ„…ÎÎÎÎÎÅ€ÎÎÀÎÎÎÎÎÎÎÎÎÎÎÎÎNÁÿƒÁ……ÎÎÎÎÎÅ€MÀÁA@ÁAÂBÃCÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÁƒ€‚……ÎÎÎÎÎÅÍÀNÁ€ÎÎÎÎÎÎÎÎÎÎÎÎÎNAƒ€ƒ……NI…A…NEB…ÎËÍÀNÁ€ÎÎÎÎÎÎÎÎÎÎÎÎÎNA€€À@ÁAÂBÃCÄDAA…AEEÅDBEEEEEÁEEÃÃEEE€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNAƒÁ……NIC…C…AÿAA…ABB…ÎËMÀÁAA@ÁAÂBÃÃÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMN€ƒÁ„……NMDA…AA…B…A…G@ÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMN€ƒÁ……NM…A@AA@AAA…A@ÁAÂBÃCÄDE€ÅÅ€ÅEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉÿIÊJËKÌLÍMN€€ƒ……ÎLE…A…A…B…A…A…ÎN€ÍÀNÁ€ÎÎÎÎÎÎÎÎÎÎÎÎÎN€€ƒ……NL…E…A…A…BA…A…ÎN@€‚ƒ„…†…†‡‡‡‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ  ˜€ ‚‚€‚ƒ ƒ ‚ ‚ „ ƒ ‚ ‚ €‚ƒ„…†‡ˆ‰Šƒ‹‹„†‹‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œÿ  œœœœœ‘›€‚ƒ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ  œœœœœ‘œœ‰œœœœœœœœœœœœœœŽ ‚ œœœœœ‘œœ‰œœœœœœœœœœœœœœŽ ‚ œœœœœ’œœ‰œœœœœœœœœœ8qâÄÉ ƒ€…@ÁAÂBÃCÄD€…Á……ÅÂ…EEÄ€EEEEEÁEEEEEÅÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍÍ€Á…ÿÎÊ€Á…Á…Ç΀NÌNÎÄNNNNNNNNNNNNNÎÆ€€ƒ„ÎÊ€ÃÄ……Â…Á…ÁÁ……Á…ÁÁ………Á€NÌNÎÄNNNNœ8qâĉ'Nœ854`pP €° 8HXhxˆ˜¨(¸°°0¸0¸0¸P¸°0¸°0¸°(¸ 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹9`pP €°Àɹ0¸ (0¸°°°°0¸°° ÿ 8HXhxˆ˜¨H°¸ˆ°¸¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹9`pP °À¹¹ ¸0¸0¸0¸°°°0¸° ¸°@¸ÀÉ)À)ÀiÀÉÉÉÉÉÉÉÉÉÉÉÉÉÙ8`pP °À©¹°¸ ¸°0¸0¸°°° ¸° ¸°°¸° 8HXhxˆ˜¨(°¸ˆ°¸¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹9`p €°À© ¸ ( 8(¸°° ¸°°0¸°0¸°°@° ¸°° 8HÿXhxˆ˜¨8°¸ˆ°¸¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹i`@p €°ÀÉÉ™¸ÀɉÀ)ÀiÀÉÉÉÉÉÉÉÉÉÉÉÉÉÙh@p €°ÀÉÉi¸°°ÀÉ™ÀùÀ€ÀÉÉÉÉÉÉÉÉÉÉÉÉÉÉ8`pp €°ÀÉÉÉÉ) P €à a¡á¡`â`@¢`@b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦æ€@ÀÂ''''çd§`€bÀ`b@b''''''''''''''ã€@ÀÂ'ÿ'''çd§`€bÀ`Àa€`"`€àà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦ä€@ÀÂ''''ç"`€àà €à a¡á¡`¢`À`Àa€`b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æfæÀ€@ÁÂ''''çd§`€bÀ`À!`€  €à @ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æfæ€@BÀ''''çd§c@a@@ab'''''''''''''çâ€@ÂBÀ''''çdçc@aÿ@@ab'''''''''''''çâ€@ÂBà €à a¡á!b¢â"c£ã#d¤a€¤¤äb€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤äá€AÁBÀ‚¤¤¤¤¤¤¤äc€¤¤äb€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤äá€AÁB‚¤¤¤¤¤¤¤$d€¤¤äb€¤¤¤¤¤¤$I’$I’$I’$I’$I’$IÒ!@   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‡’’’‹’’’’’’’’’’’’’’’’’’’’’’‡   ’’’’’’ÿ’’’’’‹’’’’’’’’’’’’’’’’’’’’’’†  ’’’’’’’’’’’‹’’’’’’’$I’$I’$I’$I’$I’$I† $(( ,"&*.26:>BFH*H>HJJJJJJJJJJJJJJJJJJJJJ$( ,HJJJJJJJBH&H:HJJJJJJJJJJJJJJJJJJJJJ$( ,HJJJJJJJBH""&*.26:>ÿBFJNRVZ^bfjnb$( ,prrrrRpr&prrrrrrrrrrrrr*$( ,prrrrRpr&prrrrrrrrrrrrr*$(( ,prrrrRpp"&*.26:>BFJNRVZ^bfjnb(( ,prrrrRppprrrrrrrrrrrrr*(  ,prrrrRppprrrrrrrrrrrrr*((  ,,prrrrRhÿ"&*.26:>BFJNRVZ^bfjnb($  ,prrrrVpp"prrrrrrrrrrrrr&( ,prrrrVpr&prrrrrrrrrrrrr&( ,prrrrVpr&prrrrrrrrrrrâÄ) ‚€„@ÁAÂBÃCÄDÅEÆFÇGÈHÄIIÉÅIIIIIIIIIIIIIIIIIIIIIÉ„IIIIIIIÉÈIIÉÅIIIIIIIIIIIIIIIIIIIIIÉ…„IIIIIIIÉÈIIÉÅÿIIIIIIIIIIII’$I’$I’$I’$Dp P€° 8HXhxˆ˜¨¸ÈØèø‰ ))¹ )))))))))))))))))))))YHp 0X€€° ))))))) ))¹ )))))))))))))))))))))YHp 0X€° ))))))) ©  ù ))))))I’$I’$I’$I’$I’$I’TÐB@ €à a¡á!b¢â"c£ã#ddb€¤b€`€äc€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤$!Á‚BÂ`Âÿ‚¤¤¤¤¤¤¤¤d€¤b€`€äc€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤$!ÁBa‚¤¤¤¤¤¤¤¤d€¤b€`€äc €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦%ÁBaÂ''''§eg€`ga''''''''''''''"‚BaÂ''''§e'gb''''''''''''''"‚AaÂ''''§e@fÀaç`'''''''Nœ8qâĉ"@  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‰’ˆ…’Ž’’’’’’’’’ÿ’’’’’’’’’’’’’„ „ ’’’’’’’’’’‰ƒ‹Šˆ’’’’’’’’’’’’’’’’’’’’’’ƒ „ ’’’’’’’’’’Š€€‚ƒ„…ƒƒ…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›• „ œœœœœ–œ‹ƒ‹‡œœœœœœœœœœœœœœ‡ „ œœœœœ–œƒŠˆ€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š› ƒ œœœœœŽÿ€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›• ƒ œœœœœ–œƒˆŠœœœœœœœœœœœœœœ‡  „ œœœœœ–œŽ„‚‹œœœœœœœœœœœœœœ‡  „ œœœœœ–€   !#%')+-/1357+  89999/8989999999999999  89999/ÿ8989999999999999  89999/4889999999999qâÄÉ ‚€€@ÁAÂBÃCÄDÅEÆFÇGÈHÅIÄIIÁIIIIIIIIIIIIIIIIIIIIIIA‚…„B€IIIIIIIII€IDÀÁAA@ÁAÂBÃÃÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMJƒ„B€NNNNÎËÍNÅNNNNNNNNNNNNNNCƒ„B€NNNNÎËÍNÅNNNNNNNNNNNNNNCÿƒ„B€NNNNÎËNÎÄNNNNNNNNNNNœ8q2ˆ@Á @P`@p°Ðð1Qq‘±Ññ2R1@RRr1@RRRRRRRRRRRRRRRRRRRRRRð@Á ¡`ARRRRRRRR @1À0@²1@RRRRRRRRRRRRRRRRRRRRR€à@Á °aARRRRRRRRR0@21€0@Ò1@RR’$I’$I’$I’$I’$I’$I’$I’"8P0H(@X$,4BFJNR* "&*.22&$ * 4".46666666$   4666ÿ46 "&*.26:>BFJNR" "&*.2. &$*(( 4.,,46666666$   4"&**,.................." $,....... & *( ,*.,.........    "&*,....*,.....ÿ............." $,.......&$ *( ,*.,.........$ ,....,..,.&,..................2h ``@pp@p°Ðð1Qq‘‘ñÀ0QAA¡ñpa¡±±±±±±±QÑ Ñ`ÐÀÀÐÀ@РР±±±11 ±10@p@p°Ððp0@p°Ðð1Qq‘±Ññ2Rr’’° `‘€ ²²²’ÐÀà 0!áP¡r¡²²²²Ð@P@pÀ`Ð@ÐÀÿÀ€Ð€ÐÀÀ@Ð@p°Ðð1QÑ0`qÑ0€0`q11`qqqqqqqqqqqqqqqqqq‘°`‘€`qqqqqqqÀÀà 0!ÁPAaqaaqqqqqqqqqqqqqqqqqqq0`qqqqQ1`qqqqqqqqqqqqqqqqqqQ° ` ‘€€@p°Ðð1Qq‘qÑÀàà€0!ÁPA¡¡ñp¡±±±±±±±±±±±±±±±±0 ±±±±1 ±±±±±±±±±±±±±±±Q°`` ‘ ±±±±±±Ñàà€0!ÁPÁ¡ñpa¡±±±±±±±±±±±±±±±±0 ±Ñ0ÿ ±Ñ0 ±±±±±Q£F5jÔ¨Q£F€            5 8HXhx@pxxx8 8HXhxˆ˜¨¸ÈØèø)9 YP H@@@III¹h`p`¨  `ˆ€¹@IIII™xp0xp@I p@xp@IÉ@ÿi 8 8HXhxH 8HXhxˆ˜¨¸ÈØèø)9Ù80P°H@@IIIÉh` xP¨  €ˆ€¹°@IIII™xp xpxpp0xpp xpp xpp0xpp@x@xp@IÉ@‰@ @IIIIIIIII98P°H@IIIÙh` x@¨  8Hˆ@HHH8¸ 8HXhxˆ˜¨¸ÈØèÈxxp xp0xpp xpppPx0xðx 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸H8PP€H@@ÿ@°¸¸¸¸¸¸¸Xh xp ¨ °€°x¸°°¸¸¸¸¸¸¸¸¸xx0x (ppppp (xpp xppp0x 8HXhxˆ˜¨H°¸x °¸¨°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸88PPpH@@°¸¸¸¸¸¸¸xh0x0¨°(ˆ°ˆ¸°¸¸¸¸¸¸¸¸¸ˆxx0xp0xpPxppp0x0x°¸¸¸¸H°¸h °¸˜°¸¸¸¸¸hÑ¢E‹-Z´hÑ¢E‹( $,4B: 4DFFFF*$D"@.DFFFFFFFFFFFFFF.D&DFDFFFFFFF: 8DFFFF*$D"@.DFFFFFFFFFFFFFF.D&DFDFFFFFFF6($$$$,4FNV^fnv~† h $,4B@BBB:@BBB  "&*.   ÿ"&*.   "&*.   "&*. "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏÓ[,<"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2,LŒŽŽŽŽŽŽŽŽŽŽŽ÷ŽŽŽŽŽ.$ ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2, ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2,ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ6$  ŒŽŽŽŽŽŽŽŽ5jÔ¨Q£F5jÔ¨Q£F5 P ;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage11.gif0000644000175000017500000003632707253523117024045 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ƒ ‰€‚ƒ„…†€‚ƒ„€ ‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹Œ‹€‚ƒ„…†‡ˆ‰Š‹ŒŽŒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“””ÿ€‚ƒ„…†‡ˆ‰Š‰ŠŠŠ„€‚ƒ„…†‚€ ‚ƒ„ € ‚ƒ„…ƒ€ ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž—€‚ƒ„…†‡ˆ‰Š‰ŠŠŠ‰ € ‚ƒ„…†‡ˆ‚€‚ƒ„…†‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‚‡‡‡‡‡‡‡†‡‚‡‡‡‡‡€ ‚ƒ„€‚ƒ„€‚ƒ„…†‡ˆ‰Šƒ‹‹‹‹‹‚‹‹‹‹‹ƒÿ‹‹‹‹‹ƒ‹‹‹‹‹ƒ‹‹‹‹‹‚‹‹‹‹‹ƒ‹‹‹‹‹ƒ‹‹‹‹‹‹‹‹‰€‚‚€‚ƒ„„„„„„„„ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ   œ‚                 —  ›               “„ ˆ Œ€‚ƒƒ€‚ƒ„…†‡ˆ‰ŠŠ‹‹…‚  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒž†€‚ƒ„…ÿ†‚€‚ƒ„…††€‚ƒƒ€‚ƒ„…†‡ˆ‰ŠŠ‹‹… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ‚ƒ‡€‚ƒ„…†‚€‚ƒ€‚ƒ„€‚ƒ„…†‡‡ˆˆˆˆˆˆˆˆˆˆˆƒ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œˆ‚€‚ƒ„„€‚ƒ„…„€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•ÿ–—˜™š›œ†€‚ƒ€‚‚ƒ‚€‚ƒ€‚ƒ„…†‡ˆ‰Šƒ‹‹‹‹‹Š‹‹… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‘€‚ƒ„…†‡ˆ‰‚€‚‚ƒƒƒƒ‚€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰ŠŠ‹‹… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚ƒ„…‚€‚ƒ‚€‚ƒ„„…ƒƒ…‚€‚ƒ„…†€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠ…ŠŠ‡ÿ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›–€‚ƒ€‚ƒ€‚ƒ€‚ƒ„…†…‡‚ƒ‚‚€‚ƒƒ€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›ˆ€‚ƒ„„€‚ƒ„„€‚ƒ„…†…€‚ƒ„…†‡€‚ƒ„…†‡ˆ‰Š‹ˆŒŒŒŒŒ…ŒŒƒ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š˜€‚ƒ‚€‚ƒ„€‚ƒ„…†ƒ€‚ƒ„…„€‚ƒ„…†‡ˆ‰Š‹ŒÿŒŽŽŽŽ‰Ž ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽƒ€‚ƒ‚€‚ƒ„…†‡ˆ‚€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‚‹ ˆ€‚ƒ‚€‚ƒ„…†…€‚ƒ„……€‚ƒ„…†‡ˆ‰Š‹ŒŽ‡ŒŠ €‚ƒ€‚ƒ„…†‡‚ˆˆˆˆ†„ˆˆˆˆˆ„ˆˆˆˆˆˆ„ˆˆˆƒ„ˆˆˆˆÿˆˆˆ‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™’€‚ƒ„€‚ƒ„…†‡€‚‚€‚ƒ„…†‡ˆ†ƒ‰‰‰‰„„‰‰‰‰‰‡‰‰ˆ†‰‰‰„‰‰ˆ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™Œ€‚ƒ€‚ƒ€‚ƒ€‚ƒ„…††€‚ƒ€‚ƒ„…†‡ˆ‰‚ƒ‡ƒ‚‚ƒ„„ŠŠŠŠŠ‚ŠŠŠŠŠŠ…ŠŠ† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™‰ÿ‚€‚ƒ„€‚ƒ„…„€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‚ƒ‡‚ƒ‚…ƒ‹„€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹„ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™†€‚ƒ€‚ƒ„…€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹†ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‹‹‹‹‹„ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜€‚ƒƒÿ€‚ƒ„„€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹Œ‡ƒ‡ƒƒ…ƒƒ‡‚‚… †€‚ƒ€‚ƒ„……€‚ƒ„…†‡ˆ‰Š‹Œƒˆƒƒ…‚ƒŽŽŽŽƒŽŽ‚ŽŽƒŽ‹ ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ…€‚‚€‚ƒ„…€‚ƒ€‚ƒ„…†‡ˆ‰Š‹Œ…‰ƒ‚‚…ƒ‚ÿ‚ŽŽŽŽ‚ŽŽ‚ŽŽƒŽ‹ ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽƒ€‚ƒ‚€‚ƒ„€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“Ž”‰”Œ”… ”””””””””””””””Š‚”””””””””””””…”… ”””””””””””””””ˆ‰€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”…•‹•‹•„ ••••••••••••••Ž‚ˆ••••••••••Œ•‡„•Š•„ ÿ••••••••••••••‹†•••••‹„•‡••Š€   !#%')+-/1 2333'  2 232   !#%')+-/1 01111            01 0 00011111111111 ÿ01111               !#%')+-/              !#%')+-/  ÿ          !!   !!!!!!!!!!!!!!!!   !!!!!!!          !#%')+-/  011111      010 ÿ  !#%')+-/  0111111 01  !#%')+--    !#% &''&'& &'''''''''''''  &'''''''''''' & ÿ !#%')+-#   !#%')+-.  ..//////////  ./////#  .# ./ . ...//////////    !#  $% $%!$$%$ $%%%%%%%%%%%%%   !# ÿ         $%!$  !#%')+-    !#%                   ÿ        D (PP (8 88 8HXhxˆ˜¨¸ÈØèø)©hh0h``h` hPh099I0y 8 8HXhx8€ˆˆˆ° 8HXhxˆ˜¨¸ÈØèø)9IY™H 8( 8XP0000 8HXhxˆÿ˜¨¸ÈØèø)ùh ( 8`0h h``@h@h`` h 8HXhxˆ˜¨h°¸h@°¸˜°¸(ˆ°°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸XH@@@°(XP080 8HXhxˆ˜¨¸ÈØèø)9IYiy¹€‰€‰°€‰‰‰‰‰‰‰‰)I@@ÐXPP080€‰‰‰‰‰‰‰‰‰‰‰ €‰€‰°€‰‰‰‰‰‰‰‰ I@ÐXPPP080€‰‰‰‰‰‰‰‰‰‰‰9€‰€‰€¹°€‰‰‰‰‰‰‰‰ H 88X ( (80 8HXhxˆ˜¨¸ÈØèÿø)9IYiy€I@€y€¹ €‰‰‰‰‰‰‰‰éH@`XPPPp800€‰‰‰‰‰‰)yp@x€ yp@xp€‰I€I@€y€¹ €‰‰‰‰‰‰‰‰ÉH@@`X€8000€‰‰‰‰‰‰Iyp0xx 8HXhxˆXx@xp˜˜˜˜x˜ˆ 8 8HXhxH€ˆˆ¸ 8HXhxˆ˜¨¸ÈØèø)9I)I@pXp80PYYYYYYYY9xp xpxpp0xpp xpp xpp0xpp@x@xpPY©PyPùP9¸PYYYYYYYYÿYI€Xp80PYYYYYYYY¹xxp xp0xpxpppp (x0x08888x 8HXhxX 8H 8HXhxˆ˜¨¨°¸(¸°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸hH@`XPPP800°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸8x0x (ppppp (xpp xppp0x 8HXhxˆ˜¨H°¸x °¸¨°¸(¸°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸HH@PXPPP@800°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸hxx0xÿp0xpPxppp0x0x°¸¸¸¸H°¸h °¸˜°¸(¸°¸¸¸¸hÑ¢E‹-Z´hÑ¢E‹-Z4@AA €à À €à a¡á!b¢â"c£ã#d¤ädäAâÁàÀÁàÀAáÀÀÀàÁÁà%åd%b@€`åb%á%%%%%%%%%%%`AAAâÀ%%%%%%%%%e!à  €à ÀÁààÁÁà!ÀÁààÁÀàÁÁ €à a¡á!b¢â`Àâ¢a@€`ÀâbbÀâ¢àÂââââââââââââââââââ¢"ÿ`AAÁ"À €à a¡á!b¢â"c£ã#d¤ä$e¥å%¦b@&a€`@æaæBfffffff¦$AAAAÁâÀÀ@fffffffffffæb@fæcæBfffffffæ#AAãÀ@fffffffffff¦c@&a@@fbæBfffffff¦#` €à ¡à €à a¡á!b¢â"c£ã#d¤ä$e¥å%&d@æ`@€`@¦aæBfffffff¦#`AAâÀÀ@fffffff&"!$Bæ Bf¦`@æ`@€`@¦aæBffffffff#`AAâÀ@fffÿffff¦" B$ €à a¡á!Âááááááá`Àáááa@€`Àáááá`Àáááà €à a¡á!b¢â"c£ã#d¤ä$%AAAAáÀÀÀ@eeeeeeeee¥ ‚ ‚"!  ‚ ‚  ‚  Be¥b@%b@@@@åb@åàBeeeeeeeee%@AÁáÀ@eeeeeeeeee#B#   €    Âààà ‚à a¡áa! €à !@ €à a¡á!b¢¢bÀâ¢àÂâââââââââââââââââÿ¢"@AÁáÀâââââââââââââââââââb! ‚  À À € €à a¡á!b¢"aÀââââ¢bÀâ¢àÂâââââââââââââââââb"@AÁáÀÀâââââââââââââââââââ¢!B"    ‚ !Ââââââ`Àâ"a€aÀâbbÀâ¢àÂââââââââââââ¢E‹-ZtAAAA €à à €à a¡á!b¢â"c£ã#d¤ä$e$B"‚   ‚ ‚ ÿ Beåc@¥aa@åb@åàBeeeeeeeeåcAAâÀÀ@eeeeeeeee%$ ‚  €à  ‚   !‚  €à a¡á!b¢â`Àâ¢a@@@ÀbÀb@@ÀaÀâ¢àÂâââââââââââââââââ"aAÁâ €à a¡á!b¢â"c£ã#d¤ä$e¥¥#Âå¥dÀåd@@b€bÀ%ÀÂååååååå¥dÁâÀÀååååååååååå"ÂåådÀ¥dÀ`ÀaÀbÀ%ÀÂååååååå%dAAâÀÀååååååååååååå%cÀ¥ÿdÀ`Àa@@@"`€àà €à a!À €à a¡á!b¢â"c£ã#d¤ädbAâÀ%%%%%%%%%%%%%%%å!`€àà €à a¡á!baÀ`ÀaÀ`Àa@b¢á €à a¡á!b¢â"c£ã#d¤ä$"AÁâ%%%%%%%%%%ec@Â`BBåd@%%c%%@À`ÀaÀ`Àa%á%%%%%%%%¥dÁ!à€  €à a¡á!b¢â"c£ã#d¤ä$eå`@‚`Â`‚%d@‚¥%b€%e@a@€`À`Àa€¥à‚¥¥¥¥¥¥¥%eAáÀ€¥¥¥¥¥¥¥ÿ¥¥åd@‚aÂa@BÂ`BB‚`Â`‚`BB‚`@BÂ`@‚¥%b€ee@a@À`@@"` €à a¡áà €à a¡á!b¢â"c£ã#d¤ädaAáÀÀ%%%%%%%%%%%%bbB‚`@Â`@Â`@Â`@B‚`B#`‚à a¡áa! €à !@ €à a¡á!b¢¢bÀâ¢àÂâââââââââââââââââaAáÀâââââââââââââââââââââ"b `‚  @@À  @@À  @ €à a¡á!b¢¢aÀâ"aÀââbaÀâ¢àÿÂââââââââââââââââ¢aAáÀâââââââââââââââââââââ"b‚bÂ`@‚a@‚`BaÂââââ¢aÀâ"a€`Àââ¢`Àâ¢àÂâââââââââââââââââ``A € à €à a¡á!b¢â"c£ã#d¤ä$e¥dÂbÂ`@‚a@‚`Ba‚¥ed€%a€`€ec€¥à‚¥¥¥¥¥¥¥ec!ÁàÀ€¥¥¥¥¥¥¥¥¥¥%"`‚  €à @Â`‚`BBaaBB‚` €à a¡á!b¢¢aÀâ"a€`Àââ¢`Àâ¢àÂâââââââââââÿâââââ"@AÁ á €à a¡á!b¢â"c£ã#d¤ä$e¥å%f&f€&`€à  €à a¡áá`""â €à a¡á!b¢â"c£ã#d¤äcAAÁ ÁàÀÀÀääääääääääääääääääaÀää$bÀdáÂääääääää¤c!ÁàÀääääääääääääääääädbÀ$"`€à €à a¡á!a""â €à a¡á!b¢â"c£ã#d¤dcA!ÁàÀäääääääääääääääää¤bÀäa€aÀ$cÀdáÂääääääää$c!ÁàÀÀääääääääÿäää䣀 ‚‚Âä$€‚¡€Âä¤cÀäa€aÀ$cÀdáÂääääääää¤" ‚@AAÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJGA…AËHBKKÄKÂÃËÄKÁKKKKKKKK‚C‚ÁKKKKKKKKKKËAC…C…AAA…ABBKKÄKBÀÁAA@ÁAÂBÃÃÁDÄÃ@ÁAÂBÃCÄDÅEÆFÇGÈHIÄ‚CÂÉÉÉÉÉÉÉÉÉÉÉÉÉCDA…AAÿ…B…A…G@ÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ€ÅE€ƒ…ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅEÁD‚ÁÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅE…A@AA@AAA…A@ÁAÂBÃCÄDE€ÅÅ€ÅEÅ€ÅE€ƒ…ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅEÁ‚CÁÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅEE…A…A…B…A…A…ÅÅÅÅE€ÅEÂÀÅÅÄ€ÅE……ÅÅÅÅÅÅÅÅE‹ÿ-Z´hÑ"A€   !#%')+- ,-,  ,,,------- ,----------     !#%')+-/1356   ÿ!#% &'''''''''''''''''#&''& &'''''''' &'''''''''''''''''%&''& &''''''''  &'''''''''Mš4iÒ¤I“&M 8HXhxˆ˜¨¨°¸ °°¸¸¸¸¸¸¸¸¸¸¸¸¸¸ˆXPPH080°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸°0¸°°°H¸°°¸h¸°°¸¸¸ˆ°¸¸¸¸¨°¸ °°¸¸¸¸¸¸¸¸¸¸¸¸¸¸xXpH08°¸¸¸¸¸¸¸¸ÿhÑ¢E‹-Z´hÑ¢E‹-h```@p°p¡°°°°pp`¡°°°°°°°°°P0@p°Ðð1QQ1`q@aaqqqqqqqqqqqqqqѰà`p`qqqqqqqqqqqqqqqqqqqqqqQp`ÁpqaapapapApaaApapApaaap`aqqq1`qqqqQ1`q@aaqqqqqqqqqqqqqq±P €à  àÀ €à a¡á!b¢â"c£ã#d¤ä$e¥¥âãÂàÂàÂàBáÀÂàÀÂàB#à‚à a¡áa! €à !@ÿ €à a¡á!b¢¢bÀâ"€ÂÂââââââââââââââ"aAÁ!àÀââââââââââââââââââââââ¢âÂ à‚  ÀàÀÀÀÀÀàÀÀ€ €à a¡á!b¢"aÀâ"bÀââ"@Àâ"€ÂÂâââââââââââââââ`AÁ!ÁàÀââââââââââââââââââââââ¢â‚âÂàÂàÂàÀÀÀÂàÀ‚àÂáÂâââââ`Àâ"bÀââ"@Àâ"€ÂÂââââââââââ¢E‹-¨@pP`p@p°Ðð1ÿQq‘±Ññ2Rr’²ÒRqaqApaapap```ApaApa``apáòr1àò0àr1àRaáòòòòòò’° à€`pàòòòòòòòòòòrpAP@pPpa`Apaaap`apa``Apaa@p°Ðð1Qq0`q1`qq `q@aaqqqqqqqqqqqqqq±À€€p`@p°Ðð1Qq‘±Ññ2Rr’²Òòsp!3Ó1 ³0 31àRa!33333Ó±ÀÀp 33333333333`aa!3ó1 S2€11àRa!33333³± ÿ € p` 3333333333333s2 ³0`1 @1 1àRp@p°Ðð1Qq‘±Ññ2R± `p```@RRRRRRRRRRRRRRRRRRRr1@’1@1`01 1@²PaARRRRRRRR €€p@RRRRRRRRRRRRRRRRRRRÒ1@’1@1`0à0@00@pp@p°Pa@p°Ðð1Qq‘±Ññ22±€€p`@RRRRRRRRRRRRRRRRRRRÒ0@pp@p°ÐðP0Q0`0à0@01ñPa@p°Ðð1Qqÿ‘±Ññ2± €`p@RRRRRRRRRRRRRRRRRRR2@’1@1`0à0@P@p €pPa@p°Ðð1Qq‘±Ññ2ò° €@p@RRRRRRRRRRRRRRRRRRR22@RÒ0 €0  01@²PaARRRRRRRò± €€@p`@RRRRRRRRRRRRRRRRRRR22@Rò0 0  01@²PaARRRRRRRÒ°@P`p`@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss3`ss1àRaassssó²@€€`p`sssssssÿssssssS0`ss1àRaassssó²€€€p``sssssssssssssS0`ss1àRaassssÓ²€ p`sssssssssÓ¦M›6 8HXhxˆ˜¨¨°¸ °°¸¸¸¸¸¸¸¸¸¸¸¸¸(XP@@8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹YÀÉ™p¹ÀÉÉÉÉùXPP@@ 800ÀÉÉÉÉÉÉÉÉÉÉÉÉ9ÀÉ™p¹ÀÉÉÉÉéX0H@ 8ÀÉÉÉÉÉÉÉÉÉÉÉÉiÀÀYp¹ÀÉÉÉÉéX0H 8ÀÉÉÉÉÉÉɉ'Nœ8]ÿ 8HXhh@pxxxHpxx(¸ 8HXhxˆ˜¨¸ÈØèøY0H 8é™`éi¸ Y@H000ééi¸ùX@H@)R¤H‘"EŠ)R¤H‘"&**,.,,............ "&*.26:>BFJNRVZ^bfjn:pp\.prrrr* prrÿrrrrrrrrrrrpp\.prrrr& prrrrrrrrrrrrrpp\.prrrr& prrrrrrrrrrâĉ“ @€‚ƒ„…†…€‚ƒ€‚ƒ„…†‡„ˆˆ‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‹ƒ‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘ƒ‘‹‘‘‚‘† ‘‘‘‘‘‘‘‘‹‚‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘„‘‘‘Ž‘† ‘‘‘‘‘‘‘‘Š‚‘‘‘‘‘‘‘"EŠ)R¤H‘"EŠ)ÿR¤H‘  $,46 @BBBBBBBBBBBBBBBBBBBBBÿBBB2@*@B@.@BBBBBBB @BBBBBBBBBBBBBBBBBBBBBBBB2@*  ". """"""""""""""" "&*.26:>BFJNRVZ^bfjnrht&\.tvvv> tvvvvvvvvvvvvvht&\.tvvv> tvvvvvvvvvvvvv"tv\.tvvv: tvvvvvvvvvvvvv""&**,.,,..........ÿ& "&*.26:>BFJNRVZ^bfjnr"ht \.tvvv:tvvvvvvvvvvvvv&lt\.tvvv* tvvvvvvvvvvvvv*pt\.tvvv&tvvvvvêÔ©S§N:uZ(@p°Ðð1QQ1`q`aqqqqqqqqqqq°`€@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³1 ³ó0ÀRa¡³³³ó°€€€€` ³³³³³³³³³³³³³Ó1`3  Ó0ÀRaÿ¡³³³Ó°€@p` ³³³³³³³³³³³³³ó1@3`0 ³0ÀRa¡³³³Ó°€` ³³³³³³³³S§N:uŠ(@p°Ð°0`0àðððÐ0àðð@a@p°Ðð1Qq‘±ÑñQ°@pò0R1`0R0ÒPa‘ €@pò0R0@pP@p°Ððp0ÑPa± ```@p°Ðð1Qq‘±Ññ2Rr’²Òòÿ3Ss“S2 ³ó0ÀRa¡³³³s° ` ³³³³³³³³³³³³³“2 ³ó0ÀRa¡³³³S° €` ³³³³³³³³³³³³³³2 ³ó0ÀRa¡³³³S°€` ³³³³³³³³³³³³³Ó2 ³ó @ÁAÂBC…@ÁAÂBÃCÄDÅEÆFGE‚‚ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÄ€ÇÇÇÇ€ÇC……ÇÇÇÇÇÇGD€‚ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇGÅ€ÇÇÇÇ€ÇC……ÇÇÇÇÇÇÇCÁ‚À@ÁAÂBÃCÿÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÌ€ÎÎÃK……ÎÎNK‚‚‚‚ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÌ€ÎÎÃK……ÎÎNI‚Á‚ÎÎÎÎÎÎÎÎÎÎÎÎÎÎ΀ÎÎÃK……ÎÎÎHÂÎÎÎÎÎÎÎÎÎÎÎN:u 8HXhxˆ˜¨¨°¸¨°°¸¸¸¸¸¸¸¸HH@@8PP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ)àéY`©°àééÉH 800PPàééééééééééééé9à™`©°àIàÉPH@@00 XPàÉàÉÿàÉàÉà¹àÉàÉàéà‰€0i`` ° 8HXhxh€ˆˆˆˆˆˆ( 8@X 88 8HXhxˆˆ˜˜˜˜˜H˜˜˜˜˜H˜˜˜˜˜H˜˜˜˜˜8˜˜˜˜˜H˜˜˜˜˜H˜˜˜ˆ˜˜˜˜ˆ0ph 8HXXˆ€€ °8 8HXhxˆhX 8HXhxˆ˜¨X 8HXhxˆ˜ˆ ¨¨¨¨ˆ ¨¨¨¨ˆ ¨¨¨¨ˆ ¨¨¨¨x ¨¨¨¨ˆ ¨¨¨¨ˆ ¨¨¨H ¨¨¨¨80p 8HXˆ (XPP °X ÿ8HXhxˆh 8HXhxˆˆH@@@ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ™  8HXhxˆ˜ˆ0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:Z0@JJJJJJJJJJJJJJJJŠ@JJJJJJJJJJJJJJJJª 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêú +;K[k{‹›«»ËÛëû ,BFJNRVZ^bfjnV",,, &( p^$   pbp"&*.26:>BFJNRVZÿ^bfjnN" ,,&$(( pr$   4"&**"&*.26:>BFJNRVZ^bfjnN".&(( pr    "&*,....*"&*.26:>BFJNRVZ^bfjnF" ., &$(  pr$ prppprrrrrrrrrrrrrÿ" . &( pr$ prh"&*.26:>BFJNRVZ^bfjnB" . &( pr  "&*,.,.&"&*.26:>BFJNRVZ^bfjnB" .,&( prrrrNpr&prrrrrrrrrrrrr " . &((prrrrVpr&prrrrrrrrrÿrrrr " .&(( prrrrZ 8HXhxH€ˆˆˆ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ùˆ@¸ ˜p  X@00ÀÉÉÉÉiÀ@À9ÀÉÉÉÉÉÉÉÉÉÉÉÉɉ€0¸ ˜p`  X 8À©yp@xÀÉxp@xpÀ‰À@À9ÀÉÉÉÉÉÉÉÉÉÉÉÉɉ@¸`˜p  P0 8HXhxˆ˜˜xp0xp ¨¨¨p@xp ¨¨¨¨( ¨h 8 8HXhxH 8HXhxˆ˜¨¸ÈØèø)9IYiyÿ‰™©¹Ùˆ€0¸°`  X@ 80À©yp xpxpp0xpp xpp xpp0xpp@x@xpÀ‰ÀÀ‰ÀÉÉÉÉÉÉÉÉÉÉÉɹ‰@¸p PP@ 80ÀÉixxp xpppppppp (x0x08888x 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Ùˆ@¸`p P@ 8ÀÉyx0x (ppppp (xpp xppp0x 8HXhxˆ˜¨ÿH°¸x °¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Ùˆ0¸p  X@ 80ÀÉyxx0xp0xpPxppp0x0xÀÉ9À À9ÀÉÉÉÉÉÉÉÉÉÉÉɹ‰0¸   X 80Àɉxx0xp0xpPxpppppp 8HXhxˆ˜¨H°¸h °¸˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Ùˆ0¸p  X@ 8ÀÉyx ( 8p0x xpp x@p0x xpp xpp 8HÿXhxˆ˜¨8°¸h °¸˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Ùˆ ¸°p  X@ 8ÀÉÉÉɹÀ  ÀIÀÉÉÉÉÉÉÉÉÉÉÉÉ©‰0¸ 0X@ 8ÀÉÉÉɹÀÉ™ÀÉÉÉÉÉÉÉÉÉÉÉÉ©‰0¸  XP 8ÀÉÉÉÉÉÀ  8HXhxh 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éˆ ¸° p X@ 8ÀÉÉÉÉÉÀ À9ÀÉÉÉÉÉÉÉÉÉÉÉÉ©‰ ¸  p X 80ÀÉ9ˆ€@ˆ‰€À‰ÿ€À‰À À9ÀÉÉÉÉÉÉÉÉÉÉÉÉ©‰ ¸ pPP0 8HXhxˆ˜¨Xˆ€0ˆ€°hˆ°¸hˆ€°¸¸¸ˆ°¸h °¸˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éˆ°`  0X@00ÀÉIˆ€ ˆ€ ˆ€€@ˆ0ˆ0ˆ ˆ€€ ˆ0ˆ ˆ€€0ˆ€À‰À ÀIÀÉÉÉÉÉÉÉÉÉÉÉÉ©‰° p0X 8ÀÉɈЈ0ˆ0ˆ0ˆPˆ€€€€ 8H8ˆ 8HXhxX 8H 8HXÿhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éˆ° p HP00ÀÉɈ0ˆ (0ˆ€€€€0ˆ€€  8HXhxˆ˜¨H°¸¸¸¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹ˆ€° pp X0ÀÉ鈈0ˆ0ˆ0ˆ€€€0ˆ€ ˆ€@ˆÀÉ) `À9ÀÉÉÉÉÉÉÉÉÉÉÉÉ™‰°° p0X0ÀÉ鈈 ˆ€0ˆ0ˆ€€€ ˆ€ ˆ€€€€ 8HXhxˆ˜¨(ÿ°¸X@°¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹ˆ° p0X0ÀÉÙˆ ( 8(ˆ€€ ˆ€€0ˆ€0ˆ€€@€ ˆ€€ 8HXhxˆ˜¨8°¸h°°p 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹ˆ° p0XP0ÀÉɉ‰ÀɉÀé ÀÉÉÉÉÉÉÉÉÉÉÉÉ™‰° p0X@0ÀÉÉY‰€€ÀÉ™ÀÙ0p°ÀÉÉÉÉÉÉÉÉÉÉÉÉ™‰°p0X0ÀÉÉÉÉÉi(@p°Ðð±0`0ÿà0 0@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsS!aáà`°`€““““S0@pp@p°Ðð±0`0à0`0à0@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsS!Aaူ`€“ó1 a0!!s1 3€³1`0à0`0à0€““““““““““““3!aaá`°€€“2 A0a0S1 3€Ó1 €0 @0`0à0€““““““““'Nœ8a” °pP@ 8HXhxˆ˜¨¸h˜`˜p˜0˜ ˜0ÿ˜ ˜ ˜0˜ÀÈÈÈHÀÈÈxP0€ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹©˜ °@X@ÀÉ™™€˜ ˜0˜0˜0˜ ˜Ð˜ 8HXhxX 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹©˜°°@X@Àɉ™0˜ (0(0( 8HXhxˆ˜¨h°¸H°¸¸X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹™˜°PX@ÀÉy™ ˜0˜ÿ`˜ ˜P˜ÀÉY  ÀyÀÉÉÉÉÉÉÉÉÉÉÉÉy™`°PX@ÀÉi™°˜0˜`˜ ˜P˜ÀÉY  ÀyÀÉÉÉÉÉÉÉÉÉÉÉÉy ˜p° (X@ 8HXhxˆ˜¨¸È˜ ( 80˜ ˜@˜@˜ ˜ 8HXhxˆ˜¨h°¸H °¸¸( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹™˜ °PX@ÀÉÉÉÉɉ   8( 8HXhx8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹‰˜°°PXÀÉÉÉÉÉ™ÿÀÉ™ÀÉÉÉÉÉÉÉÉÉÉÉÉi™€°PX@ÀÉÉÉÉÉ™°  8 8HXhxH 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹‰˜€°PX@ÀÉÉÉÉÉ™ `À9ÀÉÉÉÉÉÉÉÉÉÉÉÉi™ °PXÀÉÙ¨ 0¨  À¹¨ @¨ À‰ `À9ÀÉÉÉÉÉÉÉÉÉÉÉÉY™€°`XÀÉÙ¨  ¨0¨À¹H@@@p°Ðð1ñ0@QÑ0À0@QQ @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ssó0aÁ°€“³Q@ÁPáP@AÿaPAAAP@AAPA@aPAAPP@3@0@pP@p°Ððp0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ssó0aÁ°€“³RQAAP@aP@AAP@@@¡PaPáPAp°Ðð°@p @p°Ðð1QQ1@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ssó0aA¡ €““RaPAP@@@@@@PP@@APAAAaP@p°Ðð1Q‘0`q±0€0`qQ1@p°Ðð1Qq‘±Ññ2Rr’²Òÿò3Ssó0aA¡°`€“sRAQaP@aP@¡P@@@aPaP“s0@3À0€s0€““““““““““““³2aA¡°€“sRaQaP@aP@¡P@@@APAaP“s0@3À0€sP €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ææa‚a'ç$ ‚  €à €Â ‚ ‚‚‚ !€Â ‚ ‚€‚ ‚‚ €à a¡á!b¢â`Àâ"a€aÀâbb €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ææaÂB!A'''''çbÀ&`€à €à a¡á!aÿ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ææaÂBa''''''c'gb'''''''''''''e‚a''''''c'gb'''''''''''''e‚a''''''c'gb'''''''''''''eÂBá@'ç#àÀÀ €à aáÂBaaaaáàÀBaaaaaaaaa¡` €à a¡á!b¢¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦aÂBa'çãÀ‚àÂàÂãçÀ'f'gb'''''''''''''eÂBaÿ''äÀ‚áâÂÂáÂàÂà‚à‚àÂà‚àÂÂÂàÀ'f'gb''''''''''''§I€        !#%')+-/1357  89/   !#%')+-/1357  ÿ 89-8988 8999999999999' 89+898"&*.26:>BFJNRVZ^bfjn&,prZ.  .,,.,, ., .,,,.,,"&*,.",.."&*.26:>BFJNRVZ^bfjn&,prrr.pr"p pprrrrrrÿrrrrrrN&,prrr .,,pr&p>0 prrrrrrrrrrrrJ&(,prrrrr:p ,( "&*.26:>BFJNRVZ^bfjn&(,prrrrr:p (   prrrrrrrrrrrrJ&(, prrrrr:p (  "&*.26:>BFJNRVZ^bfj^&(,  lnnnnn2    "&*.2ÿ6:>BFJNRVZ^bfjn* , prrrrr:p (  "&*.26:>BFJNRVZ^bfjn* , prrrrr>p: prrrrrrrrrrrrJ* , prrrrr>p> prrrrrrrrrrrrJ*,,prrrrr>pr&prrâĉ'Nœ8qâÄ) …‚‚@ÁAÂBÃCÄDÅEÆFÇGÈHIÆ€ÉÉIÄ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉI€……A‚‚ÉÿÉÉÉÉÉÉÉÉÆ€ÉÉIÄ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉIƒ…A‚‚ÉÉÉÉÉÉÉÉÉÆ€ÉÉIÄ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉI“&MHá`€ @p°Ðð1Qq‘±Ññ2R²1`rr1`rrrrrrrrrrrrrrrrrrrRAá`a `rrrrrrrr²1`rr1`rrrrrrrrrrrrrrrrrrrR!aA€ `rrrrrrrr²1`21 `Ò1`rrrrrrrrrrrÒ¤I“&Mš4i „‚‚@ÁAÂBÃCÄDÅEÆFÇGÈHÿÉÆ€IÄÂ€ÉÆ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉI„A‚‚ÉÉÉÉÉÉÉÉIÇ€ÉÃÀIÆ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉII…„„A‚‚ÉÉÉÉÉÉÉÉIÇ€ÉÉIÄ€ÉÉÉÉÉÉÉÉÉI“&Mš4iÒ¤I“$RH8@X ($,4N^n~Žž®¾ÎÞîþ/?¿°ð@OO½M€   !#%')+-/13579;=?ACE FGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGG© FGGGGGGGGGG5jÔ¨QŒ"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ6$  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽN;openacs-5.7.0/packages/acs-templating/www/doc/time1/stage13.gif0000644000175000017500000003302107253523117024033 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠÿŠŠ…ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠ)R¤¨ @ÁAÂBÃCÄDÅEÆÆÁGGGAÀÁAÂBÃCÄDD@ÁAÂBÃCÄDÅ€ÄEEEEEEEEEÂEEEEEEEEÅÂEEEEEEEEEÂEEEEEEEEÅÂEEEEEEEEEÂECÀÁAÂBBÀÁÁAÀÁAÂBAÀÁAÂA@ÁAÂBCA@ÁAÂBÃCÄDDÀAA@ÁA€@ÁAÂBÃCÄDÅEÆFÇGÿÈHÉIÊJËKÌLÍMÎNOHÀÁABAÀÁAÂÂA@ÁAÂBÃCD@ÁAÂBCA@ÁAÂBÃCÄDEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏEÀÁAÂÂA@AA@ÁAÂB…@AAÀÁAÂBB@ÁAÂBCC€@ÁAÂBÃCÄDEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏBÀÁÁ@ÁÁAÀÁA@ÁA@AAÀÁAÂBA@ÁAÂBC@ÁAÂBÃC€DDDDDDDD€@ÁAÂBÃCÄDÅÿEÆFÇGÈHÉIÊJËKÌLÍMÎÎNÀÁAÀAAÀÁA€@AAÀÁAA@ÁAÂBB@ÁAÂBÃCÄÄÂEEEEEÅÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎLÀAAÀAA‚€€@ÁA…ÀÁÁ€€€€€€€@ÁAÂBÃCÄÄÃEEEEEÅÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNË……ÀAAÀÁÁ@ÁA…ƒƒƒƒ€€€ÿ€€€€€@ÁAÂAÀÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÊ……„„‚‚B€€ÀÁAA€€ÀAA€€€AA€@ÁAÂBÃCÄDEÀÅÅÅÅEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎFÀÁAAÀAA@ÁÁÁÀÁÁ€@ÁA€Á€BÁ€ÁB€@ÁAÂBÃCÄDEÀÅÅÅÅEÅ@ÁAÂBÃCÄDÅEÆFÇÿGÈHÉIÊJËKÌLÍMÎÎÅ……B@ÁA€ÀÁA€€@ÁAÁÁ€BÁ€ÁB€@ÁAÂBÃCÄDEÀÅÅÅÅEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎÄ…€A…€ÀAA@ÁAÂBB€ÁÁÂÂÁ@ÁAÂBÃCÄDEÀÅÅÅÅEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎÃ…€„‚ƒƒOOOÊOÏÂOOOOOOOOOOOOOOÊ…ÿ…€„‚ƒƒOOOÍOÏÂOOOOOOOOOOOOOÏÉA…ÀÁ@ÁAÂBÃCÄDÅEÆFGÆ€ÇÇÇÇ€ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇGÁ……„„…‚‚ƒƒÇÇÇÇÇÇGÇ€ÇÆ€€€€ÇÇÁ€ÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇ…€„…@Áƒ@ÁABBB‚ÂÂÂÂÂÂÂBB‚ÂÂÂÂÂÂÂÂÂBÁ€ÂÂÂÂBÁ€ÂÂÂÂÂBÁ@ÁAÂBÃCÄDÅEÿÆFÇGÈHÉIÊJËKÌLÍMNÎÁ„€€ƒƒH‚A‚ÎEB‚ÎËÍÀNÁ€ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÍÁ€‚ƒIA‚A‚C‚AAA‚AB@@ÁAÂBÃCÄÄÃEEEEEÅÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÍ€„…‚‚ƒƒƒL‚A‚CA‚AA‚B‚A‚G@ÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ@ÁAÂBÃCÄDÿÅEÆFÇGÈHÉIÊJËKÌLÍMNÍ…€‚‚ƒƒƒL‚A@AA@AAA‚A@ÁAÂBÃCÄDE€ÅÅÀ€ÅÅE€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÌ…€‚ƒM‚A‚C‚A‚A‚B‚A‚A‚ÎN€Î€Á€NÁ€ÎÎÎÎÎÎÎÎÎÎÎÎÎÎJ…€‚‚ƒND‚A‚A‚B@@ÁAÂBÃCÄDE€ÅEÀÁÿ€ÅÅÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNJ€„…€‚ÁƒNB‚D‚AAA‚B‚AAA‚ÎÎ΀Á€NÁ€ÎÎÎÎÎÎÎÎÎÎÎÎÎNI„„„…€€ƒÎÎÎÎɀ΀€€€ÎÁ€ÎÎÎÎÎÎN:uêÔ©S§H€   ! !!! !!!!!!!!!!!!!!!!!!!!!!!!!   !!!!!!! ! ! !!!!!!!!!!!!!!!!ÿ!!!!!!!!!    !!!!!!! $,4< 8<<< $,4BFJNRVZ^bfjn>&( ,pr:.  .,,.,, ., .,,,.,,ÿ"&*,.",.."&*.26:>BFJNRVZ^bfjn>&( ,prrf.pr"p pprrrrrrrrrrrrr$( ,prrZ.,,pr&p>0 prrrrrrrrrrrrr$( ,prrrrrp ,( "&*.26:>BFJNRVZ^bfjn>&(,,prrrrrp (   prrrrrrrrrrrrr$(,prrrrrp (  ÿ"&*.26:>BFJNRVZ^bfjn&(,prrrrj    "&*.26:>BFJNRVZ^bfjn:&$(,prrrrrp (  "&*.26:>BFJNRVZ^bfjn:&((,prrrrrp: prrrrrrrrrrrrr&(.prrrrrp> prrrrrrrrrrrrr&(.prrrrrpr&pÿrrrrrâĉ'Nœ8q”  ° 8HXhxˆ˜¨¸ÈØèø)I099‰09999999999999999999ɘ 0¸099999999I099‰09999999999999999999ɘ  ˆ°099999999I099‰09999999999999999999‰ „@ÁAÂBÃCÄDÅEÆFÇGÈHI€ÉÉIÄ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅA„…ÉÉÉÉÉÉÉÉI€ÉÉIÄ€ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÅ…A„…ÉÿÉÉÉÉÉÉÉI€ÉÄ€€€€IÇ€ÉÉÉÉÉÉÉÉÉÉÉÉÉI“&Mš4iÒ"@ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’„“ˆ„“““““““““““““““““““““‹ ƒ “““““““““„“‡†“Œ““““““““““““““““““““‹ ƒ “““““““““„“““ˆ“““““““““““““&Mš4iÒ¤IŠ(,"&*.26:>BFJLNN"LNNNNNNNNNNNNNNNNNNN**$.LNNNNNNNNÿL6L6LNNNNNNNNNNNNNNNNNNN&*$.LNNNNNNNNL&L2LNNNNNNNNNNNNNNNš4iÒ¤D€  !#% &&&''''''''''''''''''' &'''''''' &   !#%')+-/1357 899999888999999999999/  8999998989ÿ99999999999- 8999998989999999999qâd Â@‚ÀB €à a¡á!b¢â"c£ã#d¤daÀää$bÀääääääääääääääääää䤡Â@‚áBÁäääääääädaÀää$bÀääääääääääääääääää䤡Â@‚áBÁäääääääädaÀää$bÀääääääääääää¤I“&Mš4i’!@   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’…“““ˆ““““““““““““““““““““ÿ…  … “““““““““…“““ˆ““““““““““““““““““““…  … “““““““““†“‰‚“Ž“““““““““““&Mš4iÒ¤I“&¤p` (¸ 8HXhxˆ˜¨¸ÈØèø)i0™ 0é09999999999999999999Y¨p`P¸099999999i0™ 0é09999999999999999999Y¨p`P¸099999999i0™ 0é099999iÒ¤I“&Mš4iÒ¤I“&M*Háÿ Áa@p°Ðð1Qq‘±Ññ2RÒ0`21@0`Ò1`rrrrrrrrrrrrrrrrrrr²Pá !Á€aarrrrrrrrÒ0`rr1`rrrrrrrrrrrrrrrrrrr’@ aÀ€aarrrrrrrrÒ0`Ò0à0`’1`rrrrrÒ¤I“&Mš4iÒ¤I“&MšD@‚ €   €à a¡á!b¢â"c£ã#d¤¤aÀäa@aÀdcÀäääääääääääääääääää$!@‚A!ÂÂääääääää¤aÀ$bÀ`Àb€b@@bÀääääääÿäääääääääääää$¡Â@‚A!ÂÂääääääää¤aÀdb@ €à !@@@á`À`@¡` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦¡Â@‚AáB'''''gb'@ÀbÀ`ÀbÀa'''''''''''''¥Â@‚Aá'''''§bgcÀ`€b"`€àà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦f¦Â@‚áÂæææææ&"`€àà €à a¡á!baÀ`@b@b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦¡ÂA‚á'''ÿ''§bgcÀ`b€b'''''''''''''¥@‚A!Â'''''§b§c@a@€`Àb'''''''''''''¥@‚A!Â'''''§bçc@a``€  €à @ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦¡@‚A!Â'''''§b'gb''''''''''''ç$@‚A!Â'''''§b'gb''''''''''''ç$BB‚AáÂ'''''§b€f§b''''''''''''N“)($  ."ÿ&*.26:>BFJLLNLNNNNNNNNNNNNNNNNNNN*$ .LNNNNNNNNL "&*.26:>BFJNRVZ^bfjn*$.prrrrr*hp*prrrrrrrrrrrrN*$.prrrrr*hp*prrrrrrrrrrrrN*$.prrrrr*pr&prrrrrrrrrrrršH Á@pp@p°Ðð1Qq‘±Ññ2R1`rr1`rrrrrrrrrrrrrÿrrrrrrrP ÁÀparrrrrrrr1`ò0À0`’1`rrrrrrrrrrrrrrrrrrrrP Á aarrrrrrrr1`1€0`²1`rrrrrrrrrÒ¤I“&Mš4iÒ¤Iƒ)$ ","&*.26:>BFJ"L&L:LNNNNNNNNNNNNNNNNNNN *$.,LNNNNNNNN"LNN"LNNNNNNNNNNNNNNNNNNN *&.LNNNNNNNN"LNN"LNNNNNNNNNNNš4iÒ¤I“&MHÿ @pp¡@p°Ðð1Qq‘±Ññ2R1`1 `2`rrrrrrrrrrrrrrrrrrrRPA0Áp¡`rrrrrrrr1`ò0`0`ò1`rrrrrrrrrrrrrrrrrrrRP ÁÀp¡`rrrrrrrr1`ò0`0`ò1`rrrrrrÒ¤I“&Mš4iÒ¤I“&MH Á@pp¡@p°Ðð1Qq‘±Ññ2R1`ò0`0`ò1`rrrrrrrrrrrrrrrrrrrRP áp¡`rrrrrrrr1`ò0@pP@p°Ððp0@p°Ðÿð1Qq‘±Ññ2Rr’²Òò3Ss“P áp¡€“““““s1€“31€““““““““““““3ò@ áp““““““1€“31€““““““““““““3RA áp““““““1€“31€““““““““““““3R @pp@p°Ðð1Qq‘±Ññ2R21`rr1`rrrrrrrrrrrrrrrrrrr@ ÁÀparrrrrrrr21`rr1`rrrrrrrrrrrrrrrrrrr@ ÁÀp¡`rrrrrrrr21`rr1`rrrrrrrrrrrÿrrrÒ¤I“&MH Á@pp¡@p°Ðð1Qq‘±Ññ2R21`rr1`rrrrrrrrrrrrrrrrrrr@ áp¡`rrrrrrrr21`rr1`rrrrrrrrrrrrrrrrrrr@ áparrrrrrrrR1`rr1`rrrrrrrrrrrrrrrrrÒ¤I€ !#%&''&''''''''''''''''''' &''''''''&''&'''''''''''''''''''ÿ   &''''''''&'#&'''%&''''&'''I 8HXhxˆ˜¨¸ÈØ8¨p¸Pàèèèèèàèèèèè¨àèèÈ€àèèèèè¨àèèèèè¸àèèèèè¨àèèèèè˜x 0`ˆ°àèèèèèàèèèèè¨àèè¸0pàèèèèè¨àèèèèè¸ 8HXhxˆ˜¨¸ÈØ8àèèèè蘨 0`¸Pàèèèèèàèèèèè¨àèè¸0p 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÿ `p¸PÀÉÉÉÉÉ  8HXhxˆ˜ˆ0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:Z0@JJJJJJJJJJJJJJJJŠ@JJJJJJJJJJJJJJJJª 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêú +;K[k{‹›«»ËÛëû ,BFJNR.,,TVV TV0 TVVVVVVVVVVV*$@" ,TVVVVVVVVVVVV6T&,(ÿ TVVVVVVVVVVV*D",, TVVVVVVVVVVVªÔP €à a¡á¡`¢`À`b@b €à a¡á!b¢â"c£ã#d¤ä$e¥%¡‚ ÁÁdÀÀÁååååååååååå¥bÀåa€bÀ`Àa€`"`€àà €à a¡á!b¢â"c£ã#d¤ä$e¥¤‚ ÁAdÀÂÀ¥¥¥¥¥¥¥¥¥¥¥å#`€àà €à a¡á¡`¢`À`Àa€`b €à a¡á!b¢â"c£ã#d¤ä$e¥å B‚ ÁAdÀÂÁååååååååÿååååbÀåa€bÀ`À!`€  €à @ €à a¡á!b¢â"c£ã#d¤ä$e¥å ‚ ÀdÀÀÁååååååååååå%cÀåd@a@@abÀååååååååååå ‚ ÀdÀÂÁååååååååååå%cÀ%e@a@@abÀååååååååååå € À €à a¡`À €à a¡á!b¢â"c£ã#d¤ä$e¥åec&fd&&&&&&&&&棂 ÀAdÂÂ&&&&&&&&&&&¦`&fd&&&&&&&&&棂 Á$Âÿ&&&&&&&&&&&æ`&fd&&&&&&&&&棂 ÁAdà €à a¡á!b¢â"c£ã#d¤ä$e¥ååc&fd&&&&&&&&&检ÀdAÁÂ&&&&&&&&&&&æ`&fd&&&&&&&&&¦£‚€ÁÁÁcAÂÂ&&&&&&&&&&&&a&fd&&&&&&&&&¦£B Á €à a!@ €à a¡á!b¢â"c£ã#d¤ä$e¥åed&a@@@fb&&&&&&&&&¦£€ÁdÂ&&&&&&&&&&&¦aæÿ`a&b&&&&&&&&&¦£€ÀÁcAÂ&&&&&&&&&&&¦a¦`€aæa&&&&&&&L˜09¤`p 8HHXP€0° 8HXhxˆ˜¨¸ÈØèø)9IYiy)€‰€‰‰‰‰‰‰‰‰‰Ù¨ hppàX ˆ@°€‰‰‰‰‰‰‰‰‰‰‰i€‰€‰‰‰‰‰‰‰‰‰Ù¨``pàXP€€°°€‰‰‰‰‰‰‰‰‰‰‰i€‰€‰€‰‰‰‰‰‰‰‰‰Ù¨hp 8HHX ˆ° 8HXhxˆ˜¨¸ÈØèø)9IYiy9€I@€yÿ€‰‰‰‰‰‰‰‰‰É¨`pðX0€@°€‰‰‰‰‰‰‰‰‰‰‰y€I@€y€‰‰‰‰‰‰‰‰‰É¨`pàX0€€@°€‰‰‰‰‰‰‰‰‰‰‰y€) 8 8HXhxH 8HXhxˆ˜¨¸ÈØèø)9IYY© hpàX0€@°`iiiiiiiiiiii™`i`é`iiiiiiiiii™˜ ``pÐXP ˆ@°°`iiiiiiiiiiii™`iY`iiiiiiiiii™¨ `ppÐX0 ˆ°`iiÉ’%K–,Y²dÉ’%E€ ÿ   !#%')+-/)01#0111111111   01111111111101#0111111111  01111111111101#0111111111    !#%')+-/+01#0111111111  01111111111101#ÿ0111111111  0111111111110 00111111111    !#%')+-/+0 00111111111   0111111111110 00111111111  0111111111110 0011a„ &L˜R08$, @\$,46 @BBBB*   @BBBB  @BBBB  @BBBB  ÿ"&*.2"  46666666664666666 466666 466666  466666"  466666  46666666jÔÈ @ÁAÂBÃCÄDÅEFFÀAA€@AÁ@ÁAÂBÃCÄDÅEFCÀAA€@AÁ@ÁAÂBÃCÄDÅEFÄ€€Â€Â€ÆÆÆÆÆÆÄÂ€Â€ÆÆÆÆÆÆÃ€€Â€Â@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÿÌLÍMÎNÏOÐPÑQÒRÓSÔTÕUÖV×WØXÙYÚZÛ[Ü\Ý]Þ^ß_à`áaâbãcädåeæfçgèhéiêjëkìlímînïoðpñqòrósôtõuöv÷wøxùyzˀŀ€€Ç€€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPQƀŀɀÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQFÀ@ÁAB€Â€€Á€€B€@ÁA”ÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPQƀŀ€Â€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQÆÁÄ€€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÆ€€Ä€€Á€ÁÁ€€€Á€€€ÑÑÑÑÑÑÑÑQ£F5jÔ¨Q£F5jÔ¨Q£& ;openacs-5.7.0/packages/acs-templating/www/doc/time2/0000755000175000017500000000000011724401447022076 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/time2/stage00.gif0000644000175000017500000004011007253523117024025 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ЇŠŠŠŠŠŠˆŠŠŠŠŠŠ‰ŠŠŠŠŠŠˆŠŠŠŠŠŠ‰ŠŠŠŠŠÿŠˆŠŠŠŠŠŠˆ‡€‚ƒ„…†‡ˆ‰Š‹Œ†€ ‚ƒ‚€ ‚ƒ„€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‰ЇŠŠŠŠŠŠˆŠŠŠŠŠŠ‰ŠŠŠŠŠŠˆ€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘€ ‚ƒ„…†‡ˆ‰Š‹Œ‡€ ‚ƒ„ €‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‰ЇŠŠŠŠŠŠˆŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘†€‚ƒ„…†ƒ‡‡‡‡‡‡…€ ‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ„€‚ƒ„„€‚ƒ„…†‡ƒ€ ‚ƒ„…†ÿ‡ €‚ƒ„…†‡ˆƒ€‚ƒ €‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŠ€‚ƒ„€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’€ ‚ƒ„…†‡ €‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ„€‚ƒ„…€ ‚ƒ„…†‡‚€‚ƒ„…ƒ€‚ƒ„…†‡ˆ…€‚ƒ„ €‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹†€‚ƒ‚€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘€ ‚ƒ„…†‡ˆ‰†€‚ƒ„…†‡ˆ‰Š‹ŒŽˆ€‚ƒ„…†€ ‚ƒ„ÿ…‚€‚ƒ„…†„€‚ƒ„…†‡ˆ‰ˆ€‚ƒ„€‚ƒ€ ‚ƒ€‚‚€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‰€‚ƒ‚€‚‚€‚ƒ„…†‡ˆ‰Š„€ ‚ƒ„…†‡ˆ‰Š‹ŒŠ€‚ƒ„…†‡ˆ‰Š‡€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ƒ€‚ƒ„…‚€ ‚‚€‚ƒ„…†„††††††„††ƒ€‚ƒ‚€‚ƒ€ ‚ƒ‚€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹ˆƒ€ ‚ƒ„…†‡ˆ‰Š‹‡€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡ˆ‰Šÿ‹ŒŽ‡€‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰Š‹Œƒ€ ‚‚€‚ƒ„…†…ƒ‡‡‡‡‡„‚€‚ƒ€‚ƒ€‚ƒ‚€ ‚ƒ‚€‚ƒ„…„††††††††††…†††††††††††††…ƒ ‚†††††††††††€‚ƒ„…†‡ˆ‰†€‚ƒ„…†‡ˆ‰„€‚ƒ„…†‡ˆ‰Šˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‰ ‚ƒ‡ƒ‚ƒ‚€‚ƒ„ƒ€‚‚€ ‚ƒ„… €‚ƒ„…††‡‡‡‡‡‡‡‡‡‚‡‡‡‡ÿ‡‡‡‡‡‡‡…„ ƒ‡‡‡‡€‚ƒ„…†‡ˆ€‚ƒ„…†‡†€‚ƒ„…†‡ˆ‰Š‹€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’… ““ƒ‡‚ƒ‚€‚ƒ‚€ ‚ƒ„…„€‚ƒ„…†‡„€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹„ƒ ƒ‹ˆ€‚ƒ„€‚ƒ„…†‡ˆ‰‰€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•‡ –“ƒ€‚‚ƒƒƒ€ ‚ƒƒ€‚ƒ„ƒ………………………‚€‚ƒ„…†‡ˆ‰ŠŠÿ‹‹‹‹‹‹‹€ ‚ƒ€‚ƒ€‚ƒ„„€‚ƒ„…†‚€‚ƒ„…†‡ˆ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”„€ ‚ƒ„…†‡ˆ…€‚ƒ„…†‡ˆ‰ƒ‡ƒ€‚ƒ€ ‚‚€‚‚€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰ƒŠŠŠŠŠŠ…ŠŠŠŠŠŠŠ‡‚ ƒ…€‚‚€‚ƒ€‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”‚€ ‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹Œ‰…€‚ƒ‚ €‚‚€‚ƒ„…†‡ˆ‰Šÿ†‹‹‹‹‹Š‹‹‹‹‹‹‹ …‡€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ˆ€ ‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‡€‚ƒ„‚ ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹‹‹‹‹‹ ˆ„‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‰€ ‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ€‚ƒ„…„€‚ƒ„…‚ ††††††††††††…††††††††††…††††††††††††„ †‚ÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘ˆ€ ‚ƒ„…†‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘…€‚ƒ„‚€‚ƒ„…†‡ƒ€ ‚ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ƒŒŒŒŒŒ…ŒŒŒŒŒŒƒ ‡‚ŒŒŒŒŒŒŒŒŒŒ‹€ ‚ƒ„…†‡†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’„€‚ƒ„€‚ƒ„…†‡ˆ€ ‚ƒ€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹Œ‚Š ‡‚ˆ€ ‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰ÿ€‚ƒ„€‚ƒ„…†‡ˆ‰ ƒ‰‰‰‰‰‰‰‰‰ˆ‰‰‰‰‰‰†‰‰‰‰‰‰‰‰‚ ‡‰‰‰‰‰‰‰‰‚€ ‚ƒ„…††€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”€‚‚€‚ƒ„…†‡ˆˆ„‚ …‰‰‰„„‰‰‰‰‰‡‰‰‰„‰‰‰…‰‰‰‰‰‰‰‰‚ ‡‰‰‰‰‰‰†€ ‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•‘€‚‚€‚ƒ„…†‡ˆ‰„€ ‚ƒ €‚ƒ„…†‡…„ˆˆˆˆˆˆ„ÿˆˆˆ‚†ˆˆˆ‡ˆˆˆˆˆˆˆˆˆ‚ †ˆˆˆˆˆˆ‚€ ‚ƒ„ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–ˆ——ƒ€ ‚ƒƒ€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…ŠŠŠŠŠŠŠƒ …ŠŠŠ‡€ ‚ƒ„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–’——‚€ ‚‚€‚ƒ„€‚‚€‚‚‚ƒ‚ƒ‚ƒƒƒƒƒƒ€‚ƒ„…ÿ†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‡ „‚‹‹‡€ ‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—‡˜˜ Š€‚ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‹‹‹‹‹‹‹‹‹‡ „‹‹… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—‹˜˜ ‰…ƒ‡ƒƒ…ƒƒ˜˜‹˜„‚˜‡˜˜˜ ƒ˜„ ˜˜˜˜˜˜˜ÿ˜˜˜˜’€‚ƒ‚€‚ƒ„…†‡ˆ‰… ‰‡ˆƒƒ…‚ƒŠŠŠŠŠ‰ŠŠˆ‚ŠŠŠŠŠŠŠŠŠŠ‚ ƒŠŠ…€ ‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–Ž€‚ƒ„…€‚ƒ„…†‡ˆ‰Š ‡‹‰ƒ‚‚…ƒ‚‚‹‹‹‹‹ƒ‹‹†‚‹‹‰‹‹‹‹‹‹† ‚‹…€ ‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‡€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹‚ ‡ÿŒŒŒŒŒŒŒŒŒ‰ŒŒ…ŒŒˆŒŒŒŒŒ‹ Œ‚ ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŠ€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ˆ€ ‚ƒ€‚‚€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ…‹  €‚ƒ„€‚ƒ„…†‡ˆ‰Š‹Š€ ‚‚€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ„† ‚ ‡€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹Œ‚€ ‚ƒ€ÿ‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽŠŒ„† ‹ €‚ƒ„€‚ƒ„…†‡ˆ‰Š‹Œˆ Œ‹„ƒ‚‚„…… ˆ €‚ƒ€‚ƒ„…†‡ˆ‰Š‹Œ„ ‚€‚ƒ„ƒ€‚ƒ„…†„ƒ‡‡‚‡‡‡‡‡‡‡‡‡‡‡ƒ‡‡‡…€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆ… … €‚ÿƒ„…†‡ˆ‰Š‹ŒŽ‘’‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹Œ‡€‚ƒ„‚€ ‚ƒ€‚ƒ„…†‡ˆ‚‚ƒˆ„ƒƒ‚‚ƒ‚ƒ‰‰‰‰‰‡‰‰‰‰‰‰‰‰‰‰‰‰‰‰† … ‰‰‰‰‰‰‰‰‰‰‰‰‰„€‚ƒ„…†‡ˆ‰Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ†€‚ƒ‚€‚ƒ„ …………………………ƒ……ƒƒƒ…ƒƒ……ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹ÿ‹‹ƒ „ ‹‹‹‹‹‹‹ƒ€‚ƒ„…†‡ˆ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“„‘ ””Œƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰Š‹ƒ ƒ ŒŒŒŒŒ€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”‹€‚ƒ„„€‚ƒ„…‚ †††††††††ƒ†ƒƒƒƒ‚„†††††††††„††††„ÿ†ƒ†‚ƒ††††††††††††ƒ ‚ †††††…€‚ƒ„…††€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“””€‚ƒ„ƒ€‚ƒ„…†† ‡‡‡‡‡‡‡‡‚‡‚ƒƒ‚‚ƒ‡‡‡‡‡‡‡‡‡‡‡‡‚‡ƒ‡ƒ‡‡‡‡‡‡‡‡‡‡† ‚ ‡‡‡‡€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•Š€‚ƒ„…€‚ƒ„…†‡ˆ ‰‰‰‰‰‰‰‰‚ƒƒ…ÿ‚‰‰‰‰‰‰„‰‰‰‚‡ƒˆˆ€‚ƒƒ€‚ƒ„…†‡ˆ‰Š… ‚ ‹‹„‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‡€‚ƒ„……€‚ƒ„…†‡ˆ‰„ ŠŠŠŠŠŠŠŠŠŠƒŠŠŠŠŠ†€‚ƒƒ€‚ƒ„…†‡ƒˆƒ‡ƒ‡ˆˆˆˆˆˆˆˆ„ ‚ ˆˆ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’Ž€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ‰Š‚€ ‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽŽŽŽ‰ŽŽƒ‡ƒ‡ŽÿŽŽŽŒ ‚ ŽˆŽŽŽŽŽŽŽŽŽŽˆ€‚ƒ„…†‡ˆ…€‚ƒ„…†‡ˆ‰Š‹Œ‡€ ‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“Š€‚‚€‚ƒ‚„‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹‚  Œ‰ŒŒŒŒŒŒŒŒŒŒŒ†€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‰€ ‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‹”ˆŽ…ƒˆ”””ˆ  “””””””ˆ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ€ ‚ƒ€‚ƒ„…†‡ˆ‰ÿŠ‹ŒŽ…„Їނˆ ‚ ‚‚€‚ƒ„…†‚€‚ƒ„…†‡ˆ‰Š‹ŒŽŒ€ ‚ƒ„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‹ƒŠ‡†ˆ  ‚‰€‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‡€ ‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽŠ‚‰ƒ‚ƒ‚‚ƒ„Œ€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆƒÿ  ˆˆ‚ˆˆˆˆˆ„€‚ƒ„…†‡ˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ ‘‘‘‘‘‘‘‘މ‚ƒƒƒ‚€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹  ‹†‡€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘Œ€ ‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹ŒŽƒ€‚‚ƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹‹‹‹‹  ‹…‚€‚‚€‚ƒ„…†‡ˆ‰Šÿ‹ŒŽ‘’†€ ‚ƒ„…†…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’†‰ƒ†‚…“““„“Ž“Œ“““Š ‚ Žƒ““““““““€ ‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰ƒ†‚…””””†€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆ‚  ˆ†…€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ€ ‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”†€‚‚€‚ƒƒ‚„„‚€‚ƒ„…†‡ˆ‰Š†‹‹ÿ†„‹‹‰‹‹‹‹‹‹  ‹ƒƒ‹‹‹‹‹‹‹‹‹‹‹‹€ ‚ƒ„…„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™†ššššŽ  ššš•€ ‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™™ššššŽ  Œ‚šš”€ ‚ƒ„…†‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›ˆœ„œ„œœŠ  ‹œ‰€ ‚ƒ„…†‡‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰œ„‚ÿˆ  Š‚›€ ‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™„šŽ„ššš‚„š…šš  Ђހ ‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™šƒƒ›Ž„›™š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆ  ˆˆƒ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‚‰ƒ‚‚ƒ„„›™››‰››‹  ‰Œÿ ››››››››››››››‰‚ƒ‚…ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹Š  ‰‰ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‚‹‹Š‹‹‹‹‹Š  ‰‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›„‰ƒƒ…ƒƒœœƒœ‚œƒÿœœ‰  ‰† œœœœœœœœœœœœœ•‰ƒƒ…‚ƒœœƒœ‚œƒ€‚ƒ„…†‡ˆ‰ŠŠ  ‰… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›…€‚‚€‚ƒƒ‚‚„ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚‹‹‰‹‹‹‹‹‰  ˆƒ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž˜‚ŸŸŸ‚  ˆ„ ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ™ÿŸŸƒŸŸ‚  ˆ„ ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ™ŸƒŸŸ‚ ˆƒ ŸŸŸŸŸŸŸŸŸ>}úôéÓ'M€   !#%')+-/1357  8818889 8999999999999)"8818889 8999999999999Q„€€€ 8Hÿˆ€€@ˆ0ˆ0ˆ ˆ€€ ˆ0ˆ ˆ€€0ˆ€ 8HXhxˆ˜x ¨˜ ¨¨( ¨¨¨¨¨8ˆ°p p8` ˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÙˆÐˆ0ˆ0ˆ0ˆPˆ€0ˆ€0ˆÐˆ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸ˆˆ° €8` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹éˆ0ˆ (0ˆ€€€€0ˆ€€  8HXhxˆ˜¨H°¸¸¸¸¨°¸¸¸¸ˆˆ° p8ÿ` ˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹éˆˆ0ˆ0ˆ0ˆ€€€0ˆ€ ˆ€@ˆÀÉ) `À9ÀÉyˆ° p8` ˜ÀÉÉÉÉÉÉÉÉÉÉÉÉɉˆ ˆ€0ˆ0ˆ€€€ ˆ€ ˆ€€€0ˆÀÉ °@ÀI(@p°Ðð1QqAqÀ @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss³AP@pPAaaA@p°Ðð1Qq0`qÑ0 `1`1 à0`qqqqñaAqÿÀ @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“¡³Ó0 ³1 1@1 ³“aAqÀ@0¡³³³³³³³³³³³³³³¡³ó0 “1`0à0`1 ³“aAqÀ@0¡³³³³³³³³³³³³³³³³S0 “1`0à0 0@pp@p°Ðð11q@ápÀ@0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó0@pp@p°Ðð±0`0à0`0à0 11111ñaAáàpÀ @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ssÿ2 a0!!s1 3€³1`0à0`0à0€“³aAáàpÀ “““““““““““““S0 A0a0S1 3€Ó1 €0 @0`0à0€“³aAáàpÀ ““““““'Nœ8qâÄi €@ÁÁ„ÁA€€„„Á„„Á„ÁÁ„„Á€„„Á€@ÁAÂBÃCÄÄÃEEEÅÁ€Â€€Á€€ÄEEEEEE„ă@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍÌÄ„Á€„Á€„Á€„Á€„Á„FÀÁAÂBÃÃB@ÁABÿ€@ÁAÂBÃCÄDEÅ€ÅÅÅÅEC„…À@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÌ„AÀAA€€€AA€€€AA€@ÁAÂBÃCÄDEÀÅE€ÅÅÅ€ÅÅÅÅEC„…À@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍËÅ„Á€Ã€Á„ÂNÎÂÍÁÎÃNÎB„…CÁNNNNNNNNNNNNNNĄńÁ€Ã€Á„ÂNÎÂÍÁÎÃNNB„‚…C€NNNNNNNNNNNNœ8%” ÿ( 80˜ ˜@˜@˜ ˜ 8HXhxˆ˜¨h°¸H °¸¸(°¸¸¸¸Xˆ° ph 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù9   8( 8HXhx8€ˆˆˆˆˆˆHˆ° pph 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù9 ʉ° ph ˜ :°  8 8HXhxH€ˆˆˆˆˆˆ8ˆ@° ph ˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù9 ÿ`𺉰 ph ˜ j¨ 0¨  z¨ @¨ J `𺉰 `h0 z¨  ¨0¨z¨@¨ J  8HXhX`pxxx8pxxxxxxx8ˆ° `h0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Ù¨ `¨p¨  0¨   ¨   ¨  0¨  @¨@¨ À‰   8( 8HXhx8€ˆˆˆˆˆˆ8ˆ°ph0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÿY©€¨  ¨ 0¨   ¨   P¨0¨ð¨ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸HˆP°ph0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹I©0¨ (      (¨   ¨   0¨ 8HXhxˆ˜¨H°¸X@°¸¨°¸¸¸¸HˆP°`h0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹9© ¨0¨ 0¨ P¨   0¨0¨ÀÉ9 `À9ÀÉ)H€°°`h0ÀÉÉÉÉÉÉÿÉÉÉÉÉÉÉY¨°¨0¨ 0¨ P¨    ¨ 0¨ÀÉ9 `À9ÀÉ)ˆaA@pÐ` @p°Ðð1Qq‘±Ññ2Rr’²Òò3SssPAP@p@aPAPAAAP@aPAPA@APAA@p°Ðð1Qq0`q‘0À0`q11`qqqqqaAÁÐ @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóÓ0`0@p@p°Ðð0Q`A¡Ð` @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóÿÓ0 T`A¡Ð` Ô2 T¡`ÁÐ` Ô2 T¡`ÁÐ` 4q`@paa@p°pa¡°°°°pp`¡°°°°°°°°°P0@p°Ðð1QQ1`qqqqq¡`ÁÐ` @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ssóq`Apapáqs`3€“31€“S¡`ÁÐ` “““““““““““““``ÁpqaapapapApaaApapÿApaaap`3€“31€“S¡`ÁÐ` ““““'Nœ8qâĉ§D€          !#%')+-/1357-     !#%')+-/1357+ÿ8988 89 89999999999999 8988     !#%')+-/1357)    !#%')+-/13579;<= << <7  ÿ<=============<= <<7  <===============/<<7  !#%')+-/13579;=?<@3 @AAAAAAAAAAAAAA1<    !#%')+-/13579;=?  ÿ !#%')+-/13579;=?<   !#%')+-/13579;=?@ @1  @AAAAAAAAAAAAAA1@  @1  @AAAAAAAAAAAAAA3@A@1  @AAAAAAA (P 2 $,4BFJNRVZ^bfjnrvz~‚†:ÿ"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?ð$Ü,Ø(Ø$øø$ä,à"&*." 0222*  0ÿ222 $0222  0222"  0222202222  0222(0222$022222&02222 ,0222& 022b”P €à @ €à a¡á!b¢¢aÀaÀ`Àââââ"a@Àââââba@À"@Àâââ¢b@@b@Àâââ¢b@bÀâââââââ`@Àââââ¢a@ÀbÀââââ"@@b€`Àââââb@b@@@Àââââ"@@@b@@Àââââ"a€`Àâââ¢E„ÿ"&*.24666*$46664666 4666 46664666(4666 4666  4666664666* 4666" "&* ,....  ,.... "&*  "&*  "&ÿ  "&*." 0222*  0222&  0222   0222   0222202222 022220222" 0222220222b(@@@P0@p°Ðð111 €0  0@QQQQ‘0 €0 `0 @QQQQ±0 €0 `0 @QQQQQQ0@QQQQQQ0€0 @0@P@p°Ðð1Q €0  0`qqqq ÿ€0 `0 @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vv–¶Öö7Ww—·×÷8Xx˜¸Øø9Yy™¹Ùù:ZzšºÚú;[{›»Ûû<\|œ¼Üü=]}½Ýý>^~ž7`1 à1 €žž=z›"&*.26:>BFJNRVZ^bfjnrvz~‚†Š.$ ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2, ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽ­ŽŽ2,ŒŽŽŽŽŽŽŽŽŽŽ5jÔ¨Q£ $  ( $,4BFJNRVZ^bfjnrvz~bx(  "*,$"&*.26:>BFJNRVZ^bfjnrvz~B     """""(,$"&*.26:>BFJNRVZ^bfjnrvz~bx(  "&*,ÿ$"&*.26:>BFJNRVZ^bfjnrvz~b€* €F*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚"€. €F*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚"€‚€F*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚…P €à a¡á!b¢¢bÀâââb¡Â‚A €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'f((@h¤Â‚A((((((((((((((((b((@h¤ÂB(((((((((((((((hb((@h¤ÂBÿ(((((((((((((((hb((@h¤ÂB((((P @ (P @J(@p°Ðð0 àððð°0àððððððPa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó33`3€044Ra!41@3À0à34r!41 4r!41 4r0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó33444r¡ ÿ41€3€0à34r¡ 41€3€0à34r¡ 41@0@p0@p°Ðð0`a @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó33€3”04ra 41 4ra 41 4ra 41 4ra (P @ (P @% 8HXhxˆ˜¨¨°¸ÿ¸¸X¸0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù™ ¹0 š ¹0 š ¹0 šÀ   ©°0˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù™À   ©°0 šÀ   ©°0 šÀ   ©°0 ÿ š 8HXhx pxxxXpxxxxxh¨°0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù™  ©°` špð ©°` š P ©°` š°0° 8H@H 8HXhxˆ˜8¨°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù™À°€0p ©°` ÿ šÐ°0°p ©°` šš0 € 88 8HXhxˆH¨°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù  88 8HXhxˆX0˜˜˜˜8¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù©š0€  ©° ªª@ ° ©° ªºP  ( 8 8HÿXhxˆ˜8¸€ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù©  ¹€ ª  ¹P ª j ¹0 ª j ¹0 (P @ (P @) 8HXhX 8( 8HXhx8€ˆˆˆˆˆ¸0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù© j ¹0 ª jÿ ¹0 ª  ¹0 ª  ¹0 (P @ (P @) 8HXhX`pxxx8pxxxxxh¸0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù©°@úH°0 ªÀ úH°` JppJàРð p à°Ð €pÐ 8HX(`hhhhhhhhhh(ÿ`hhhhhhhhhX`hhhhhhXH°` 8HXhxˆ˜¨¸ÈØèøÈ Y€  9àÙ ð ‰ à°y  €pé  9  ùH° Y`0  000P (((    (((  (((     ((((     ( (ÿ   (      ( 00 0(0 000088000 8HXhxˆ˜X ¨x ¨¨X ¨¨¨xx° ¨¨¨¨¨¨¨¨¨¨¨¨8P00P0 0€@0 p 0 0€@0pP @0  0 0 0ÿ08 00008 00 00000 08 0 0(00 08(0 0(0 8HXhxˆ˜H ¨h0 ¨¨H ¨¨¨x¨° ¨¨¨¨¨¨¨¨¨¨¨¨8P00`000p 0 000 ( 8(@0@8  @@0@H@@ (0ÿ0(00(  800(0 000 (0 80( ( 8HXhxˆx˜ˆ0˜˜x˜˜˜˜(¨°˜˜˜˜˜˜˜˜˜˜˜˜˜xP00P00 @0(0008@0p0 @P0€P@Pÿ 8000000 0(008(00(00(0000008(00(0 8HXhxˆ˜ˆ ¨h0 ¨¨H ¨¨¨x¨° ¨¨¨¨¨¨¨¨¨¨¨¨8P00 @00 (@0 00  ( 0p   00€P (       (( (ÿ       (  (     (       ((( ( (  88@@@HHHHH(@HHHHH( 8( 8HXhx8€ˆˆˆˆx¨°€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆX (0000 88@ @H80 0 @H(0@H0 00 0ÿ@8@80 00000 @( 0  0@8    8 0   008(008 08800 8HXhXpxxxxxxxx(pxxxxxX¨° 8HXhxˆ˜¨¸ÈØèø 0 )))))y Y ¹  ¹ )))))Y ))¹ )¹¨° ))))))))‰ ))))))éÿ ))))))))))¹ ))¹ )¹¨° )))))))))))))))))))))I’$I’$I’P €à a¡á!b¢¢bÀââââàÂB €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ççf((@èã‚A(((((((((((((((èb((@èã‚A(((((((((((((((èb((@èãB((((((((((((((((c((@èãB(((((((P @ (PŒ"&**,....$"&*.26ÿ:>BFJNRVZ^bfjnrvz~r€‚€>.$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚2€‚€:*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚2€^$€&*,$t€‚&€‚&€‚&€‚&€‚&€‚&€J"&& (***(,(**(******(******(******(******(******(******(****(**** (****,(**(******(******(@p°Ððÿ1Qqñ0€‘‘‘‘‘ €‘‘‘‘‘ €‘‘‘‘‘ €‘‘‘Q0€‘‘‘±0`0à0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Ô@p°Ðð11`0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt´0`0€””””””””””””””””3 €””””””””””””””””T3@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vv–¶Öö7Ww—·×÷8Xx˜¸Øø9Yy™¹ÙùÙÿ6À0@P@p°Ðð1Qq±0 €‘‘‘‘10@P@p°Ðð1Qq‘0 €‘‘‘‘q1 €‘‘‘‘11 0€‘‘‘‘ñ0 0€‘‘‘‘‘‘‘‘Q1 €‘‘‘‘Q1€‘‘‘‘‘Q0€‘‘‘‘‘‘0€‘‘‘‘11`0€‘‘‘‘11`0€‘‘‘‘ñ0 €0 €‘‘‘‘±0 €0 €‘‘‘‘‘‘‘‘1 €@ÁAÂBÃCÄDÅE€€€FFFFFÅFFFFFFÂFFFFFÅ€ÁFFFFÆÄ€ÁFFFFFÀ€Á€ÁFFFFÆÁ€€Á€FFFFFFFFFÄÁÿFFFFFÅ€ÁFFFFÆÄ€€€FFFFFF€FFFFÆÅ€€FFFFŒ $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GÿOW_gow‡—Ÿ‡X x  §§GÞ&@€‚ƒ„………„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢‹‰„ƒ…£££££££££££££££££Œ‹„ƒ„£££££££££££££££££Œ‹„‚†£££££££££££F5jÔ(F€   !#%')+-/13579;=?ACEFGGG=GGGGGGGGGGGGGFGGGGGGGGGGGGGGGGGGGGGGGGG';openacs-5.7.0/packages/acs-templating/www/doc/time2/stage02.gif0000644000175000017500000003222207253523117024034 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠ…ŠŠÿŠŠŠŠŠ†ŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠ…ŠŠŠ†ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ…ŠŠŠŠŠŠ 8HXhxˆ˜¨¸¨ÀÈÈÈÈÈ8ÀÈÈÈÈÈ8 ˆ 8HXhxh¸° 8HXhxˆ˜¨ ¨¨¨¨¨¨X ¨¨¨¨¨¨h ¨¨¨¨¨¨X ¨¨¨¨¨¨X ¨¨¨¨¨¨h ¨¨¨¨¨¨X ¨¨Hˆ 8HXhH¨ 8HXhxˆ˜¨¸ 8¸   8HXhxˆ˜ˆ ( 8 8HXhxˆ˜¨¸ÈÿØèø)9IYiy‰™©¹ÉÙéùˆ 8HH 8HXh(¨ p(8 8Hh 8H8PPP¸ 8˜ 88 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ陈 8 8HXhxh¨  p8000pH``@˜ 8HX˜°°°°x 8HX 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙy ˆ 8HXˆ0 8HXh(¨ 8H8Hx 8HX8˜¸ 8HXX 8HX8`hhhhhhhÿhhX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ‰ˆ 8HX 8H8 8HX(¨ 8HXx 8H¸ 8HXh8 8(X ( 8HXhHpxxxxxxxx( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙYˆ€€8 8HXh¨ 8HXhH@¸ 8HXh¸```00˜ 8( 8X 8( 8HXhx(€ˆˆˆˆˆˆˆ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ8 8H8€¨ 8HXhxhH ÿ8H¸ 8HX¸˜ 8HXhx8 8(X 8X8 8HXhh 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Y 8 88¨ 8HXh( 8HX˜ 8HXh(¸°°px(h``8 (000(0X 8HXX 8HXhxˆ˜˜˜˜˜˜˜( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©i8 8HXh8˜ 8HXX¨ 88˜ 8HXhxˆ˜¸ 8HXhXhX 8HXhxˆH 8HXhxˆ˜¨hÿ°¸¸¸¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™ 8 8H8˜ 8HXhX 88¨ 8H¨ 8HHX 8HH¸ 8HX8H@ 8HXhx00€8080`80 8P8€ˆˆˆˆˆˆX€ˆˆˆˆˆˆˆ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™)˜ 8HXhX 8HX¨ 8HXHˆ 8HH (X 8(H 8x¸ 8(x 8 8HXhxˆx8808 800@8@800 8˜˜˜˜˜x˜˜˜˜˜˜( 8HXÿhxˆ˜¨¸ÈØèø)9IYiyÙ˜ 8HXhxˆ(8 8H (ˆ 8ˆ¨ 8HXXˆ 8H(H 88XPPPppp¸ 8HXh¸h ( 8HXhxˆ˜¨¸ÈØèøÉéɘ 8HXhxˆ8 8H8ˆ 8HXhH¨ 8HXh¨ 8HXhHX (¸ 8HXHh 88 8HXhxˆ˜¨¸ÈØèøÙ ))¹ ))))))))))i˜ 8HXhxˆ˜˜ 8HXˆ 8HXhx8¨ 8HXhx( 8HXÿhXX 8(xpp¸ 8HXx`` 8HXhxˆ˜¨¸ÈØèø)9 @IIY@IIIIIIIÙ˜ 8HXhx8 8HXhxˆˆ 8HXhH8 8H8¨ 8HXX 8HHh 8HXhhpp¸ 8HXhx¸h 8( 8HXhxˆ˜¨¸ÈØèø)9¹@‰@Ù@IIIII™˜ 8HXhxˆˆ0000¨ 8HXhxˆ˜¨¸ÈØXh 8HXhxhx 8H(¸ 8HX(H 8( 8HXhxˆ˜¨¸ÈØèø@@@H ‰H@@H@ÿ I¹@  Ù¨ 8HXhxˆ˜¨¸ÈØØˆ ( 8HXhxˆ˜¨¸ÈH@x 8HXhxh¸ 8HX8XPPH 8H8 8HXhxˆ˜¨¸ÈØèø¨H@0H@ ‰H@H@ I©`ù ù8 (¨ 88˜`ˆ 8HXhxx 8HXhxˆ˜¨X 8HXhxˆ˜¨xx (¸ 8HXhxˆ˜¨x 8HXhxˆ˜¨¸ÈØèø¹H@ H0HpH@@0H@@ H@@ H@@0H@@@H@H@ )  ))¹ ))y8ÿ0 h  €ˆ€ÀX 8HXhxˆ˜X¸ 8HXhxˆ˜¨¸Èؘ 8HXhxˆ˜¨¸ÈØèø)9IYI0HpH@ H@0H@@ H@@@PH0HðH 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸H80`` `¸ 8HXhxˆ˜¨¨x 8HX8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰ÙH0HH (@@@@@ (H@@ H@@@0H 8HXhxˆ˜¨H°¸x°¸¸°¸¸¸¸Hh``¸ 8HxppÿpX ( 8HXhxXH 8HX( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™ÉH0HpH0H@0H@PH@@@0H0H ©y )  Y ©ih0°°°€€€XPP H 8HXhx 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©IH@€H0H@0H@PH@@@ H@0H°¹Y°  °I°¹I˜°° XPPH 8H8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹iHH0H H@@ HPH0H H@@ H@@ÀÉ)Àÿ À9ÀÉ© °°PX 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùiÐй°ppPPPP Ê z©°p XP@ êz¹pPP@  8HXhx@pxxx8pxxxxxxX¨°@P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹YP@XYPÀYPÀ‰À@À9À©©°@PÀÉÉÉÉÉÉÉÉÉÉÉÉÉÙXP0XÿPYÀYPÀ‰   8 8HXhxH€ˆˆˆˆˆX¨ °P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉYP X0X€XPP@X0X0X XPP X0X XPP0XPÀ‰ÀÀ‰À™©°`ÀÉÉÉÉÉÉÉÉÉÉÉÉÉIY0X°X0X0X0XPXP0XP0XÐX 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸˜¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉyX0XX (0XPPPP0XPPÿ  8HXhxˆ˜¨H°¸x ( 88@H(@H 8HXhxˆ˜ˆ¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉyX0XpX0X0X0XPPP0XP XP@XÐÙÀ€0pЉ©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ‰XP€X XP0X0XPPP XP XPPP0XÐÉ  8HXhx p0p0ppxxxxxx8¨€° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É™X XPP XPP0ÿXP0XPPPX XPPÐÙÀ p0€€ 88 8HXhxˆˆ¨°P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙYà©  88 8HXhx8€0p0p€ˆˆˆˆˆH¨°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéXPPàéYà¹0p0pài©°`àééééééééééééééééyÐ  ( 8(@ 0@8 8HXhxˆ˜x¨°` 8HXhxˆ˜¨¸ÈØèø)9IÿYiy‰™©¹ÉÙéùYÀàP0€J©°` êi`@hŠh`JÐJ©°` êi`0h`Šh`JÀJJ©¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É™h` h`h``0h`` h0h h`` h``0h`ÐyÀ  8 8HXhx8€ˆˆˆˆˆH¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É ih` h`0h`0h`0h`` hÐÿh 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸ˆ¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É i0h (``0(``0(` 8HXhxˆ˜¨h°¸¸¸¸¨°¸¸¸ˆ¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É ih0h``h` hPhÐÙ9ÐIÐ)Ðy©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ ih0h``h` hPhÐÙ9  8 8HXhx8€ˆˆˆˆˆH¨° 8HXhxˆ˜¨¸ÈØÿèø)9IYiy‰™©¹Ééh ( 8`0h h``@h@h`` h 8HXhxˆ˜¨h°¸h@°¸˜°¸¸¸ˆ¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùi :©€° j :©°P j:©°` jÀ@ð:©¸` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9xp@xйxp@xpÐyÀ@Ð)ÿÐi©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙIxp0xpÐÉx@xpÐy   8 8HXhxH€ˆˆˆˆˆ8¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉIxp xpxpp0xpp xpp xpp0xpp@x@xpÐyÀÐyÐi©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹xxp xp0xpp xpppPx0xðx 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸x¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹x0x (ÿppppp (xpp xppp0x 8HXhxˆ˜¨H°¸x °¸¨°¸¸¸x¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹xx0xp0xpPxppp0x0xÐÙ À Ð)Ði©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹xx0xp0xpPxppp xp0xÐÙ À Ð)Ði©°˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É™x ( 8p0x xpp x@p0x xpp xpp ÿ8HXhxˆ˜¨8°¸h °¸˜°¸¸¸h¨€° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùyÐ *©°P z *©°P zÐ**©°P zÀ  8HXhx8€ˆˆˆˆˆ(¨°P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉIˆ€@ˆ‰€À‰€ÐyÀ Ð)ÐY©°PÐÙÙÙÙÙÙÙÙÙÙÙÙÙÿIˆ€0ˆ€‰À‰€ÐyÀ Ð)ÐY©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙIˆ€ ˆ€ 8Hˆ€€@ˆ0ˆ0ˆ ˆ€€ ˆ0ˆ ˆ€€0ˆ€ 8HXhxˆ˜x ¨˜ ¨¨( ¨¨¨¨¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹ˆÐˆ0ˆ0ˆ0ˆPˆ€0ˆ€0ˆÐˆ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸h¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹ˆ0ˆ (0ˆ€€€ÿ€0ˆ€€  8HXhxˆ˜¨H°¸¸¸¸¨°¸¸¸h¨°0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹ˆˆ0ˆ0ˆ0ˆ€€€0ˆ€ ˆ€@ˆÐÙ `Ð)ÐY©°`ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹ˆˆ ˆ€0ˆ0ˆ€€€ ˆ€ ˆ€€€0ˆÐɰ@Ð9ÐY©°˜ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É©ˆ ( 8(ˆ€€ ˆ€€0ˆ€0ˆ€€@€ ˆ€€ 8HXhxˆ˜¨8°¸hÿ°°p°¸¸¸h¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙI‰àéIàÉ àI©°àéééééééééééééé)ˆ€€àéYà¹0p°àI©°àéééééééééééééééé©à¹0p€ 88 8HXhxˆh¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù  88 8HXhxˆX0p0p˜˜˜˜X¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹˜0˜Ðÿ©˜ÐyÐÉ0p0pÐY¹PÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹˜ ˜0˜Ð™˜ÐyÐÙ@ 0pÐY¹PÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹˜˜ 8˜080˜ ˜0˜ ˜ ˜0˜ 8HXhxˆ˜x ¨¨¨8P0€ ¨¨¨¨¸P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9™€˜ ˜0˜0˜0˜ ˜Ð˜ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸h¸P 8HÿXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É)™0˜ (0(0( 8HXhxˆ˜¨h°¸H°¸¸X°¸¸¸h¸P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É™ ˜0˜`˜ ˜P˜ÐÙ9  ÐiÐY¹ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ ™°˜0˜`˜ ˜P˜ÐÙ9  ÐiÐY¹ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ ˜ ( 80˜ ˜@˜@˜ ˜ 8HXhxˆ˜¨h°¸H °¸¸(°¸¸¸ÿh¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù‰   8( 8HXhx8€ˆˆˆˆˆ(¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù‰ *¹ а  8 8HXhxH€ˆˆˆˆˆ(¸ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù‰ `ð*¹ º© 0¨  z¨ @¨ J `ð*¹ º©  ¨ÿ0¨z¨@¨ J `ðy° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉY¨ `¨p¨  0¨   ¨   ¨  0¨  @¨@¨ Ðy   8( 8HXhx8€ˆˆˆˆˆp°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ¨€¨  ¨ 0¨   ¨   P¨0¨ð¨ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸Xx°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éɨ0¨ (  ÿ    (¨   ¨   0¨ 8HXhxˆ˜¨H°¸X@°¸¨°¸¸¸Xx°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É¹¨ ¨0¨ 0¨ P¨   0¨0¨ÐÙ  `Ð)ÐI©°`ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ©¨°¨0¨ 0¨ P¨    ¨ 0¨ÐÙ  `Ð)ÐI©°ÐÙÙÙ©S§N:uêÔ©S§E€   ÿ  !#%')+-/13579;=?36   !#%')+-/13579;=?3@A@#@AAAAAAAAAAAAAAA@A@#@AAAAAAAAAAAAAAA@A@#@AAAAAAAAAAA98@)   !#%')+-/13579 8ÿ:/:;:):;;;;;;;;;;;;;  :/:;:):;;;;;;;;;;;;;- . . . .., ., .."&**,...*,$"&*.26:>BFJNRVZ^bfjnr6. .  .,,,, .,,"&*,.",..,...*,$"ÿ&*.26:>BFJNRVZ^bfjnr2.(. . . .,,, .,.,.tvtttR*,$tvvvvvvvvvvvvv..,.., . .,,,.,.,,, .trtttR*,$tvvvêÔ©S§N:uêÔi AA@ÁAÁ…€Á………Á€…Á…€B€Á……@ÁAÂBÃCÄDÅÁ€ÅEÄ€ÅÅE€€ÅÅÅÅ„@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎÊOOÂÏOÂÏÉ„OOOOOOOOOOOOOÿOÏÁ……OÏÂÏÆÆÄÏÉ„OOOOOOOOOOOOOOOOÏÅπŀŀÄÏÉ„OOOOOOOOOOOOOžN^n~Žž®¾ÎÞîþ/??°ð@OO½M€   !#%')+-/135÷79;=?ACE FGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGG FGGGGGGGGGG5jÔ¨QŒ"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ6$  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽN;openacs-5.7.0/packages/acs-templating/www/doc/time2/stage03.gif0000644000175000017500000003353307253523117024043 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠ‰ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ÿŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠŠŠŠŠŠ…‰ŠŠŠ‰ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠ 8HXhxˆ˜¨¸¨ÀÈÈÈÈÈHÀÈÈÈȸÀÈÈÈxÀÈÈ8ÀÈÈÈÈÈHÀÈÈÈÈÈHÀÈÈÈÈÈHÀÈÈÈÈÈHÀÈÈÈÈÈHÀÈÈÈÈÈHÀÈÈÈÈHx 8( 8HXhxˆ˜ˆ ( 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù š ˜ 8HX(¨    8HXhxˆÿ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùé ˜ 8HXhhPPPP0000€¨ 8¨€€@@ 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéY80@8𙘠8( 8(800x 8H¨ 8HX¨h 8Hh 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéY80080ð ˜ 8(8 88p¨ 8HXhˆ 8h```¸ 8HX( 8HXhxˆ˜¨¨ 8HXhxˆÿ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéY80 808p88 8(˜ 8H8h (¨ 8H¨ˆ 88¸ 8HXh¸ 8HX`hhhhhhhhhX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™h 8HH˜ 88h 8h0¸ 8HXhX8 8HXhh 8H 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙù˜ 8HXhxH¸ 8HXhh¨ˆ 8 8(H@ 8HXhxˆ˜( ¨¨¨¨¨Xÿ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É˜ 8HXhxˆ˜¨Xh 8h (¨¸ 8HXH¨ 8HXhˆ€pH 8HX8 8HXhxˆ˜H ¨¨¨¨¨X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹)˜ 8H8 8HXh 8Hh 8HX 8ˆ (¨ (¸ (ˆ (x 8HX(H 8H(000 (8 8HXhxˆ˜¨h°¸¸¸¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©É˜ 8HXÿ(8 8H( 8HXhh 8HhX 88¨ 8HX8¸ (x 88 8H8 H 80000000000 8HXhxˆ˜¨h°¸¸¸¸¨ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™¹˜ 8HXhh8 8HX 8HXhh (¨ 8HXhXˆ 8ˆ 8(¸°°@HHHHH 8H 8HXhxˆ˜¨¸ÈØ(àèèè˜àèèèèèèèèèèèèèèèèèèèèH˜ 8HXhxˆ( 8HX8 8HXÿ 8HXhh¨ 8HXxppˆ 8H8¸ 8HXhH 8HH 8H( 8HXhxˆ˜¨¸Èؘàèèè˜àèèèèèèèèèèèèèè(˜ 8HXhxˆ˜¨¸Èˆ 8HXhx(8 8HXh8 8(x 8HXh(¨ 8H¨ppp€€€€¸ 8HXh8 8HXh8H 8H( 8HXhxˆ˜¨¸ÈØèxðøøøXðøøøøøøø˜ 8HXhxˆ˜¨¸Èؘ 8HXhxˆ˜¨¸(8 8HXhxˆ˜8x 8HXhx8 88ˆ 8ˆ¸ 8HÿXhH 8HH 8HXhxˆH 8HXhxˆ˜¨¸ÈØèøHÉ  ‰˜ 8HXhxH 8HXhxˆ˜¨¸ÈØè88 8HXhxˆ˜x 8HXhhx 8HHˆ 8HXhx¸ 8HXhh¨h 88H 8HXhX 8HXhxˆ˜xH@@H ¨¨¨H@@H@ ¨¨¨¨( ¨x@ ¨¨( ¨¨¨¨¨¨¨˜ 8˜ 8HXhxˆ˜h8 8HXhxˆ˜¨¸È¸ 8HXhhˆ 8HXhxˆ˜¨¸h 8HX8¨ ¸ 8(¨ 8Hÿ(H ( 8HXhxˆ˜¨¸ÈØxH@0H@àèÈH@H@àèè¨àÈ`àè8àèèèèH8008 8HXhxˆ˜¨8ˆ 8HXhxˆ˜¨¸ÈØèˆxpph 8H 8H(X 8HX8¸ 8HXhxˆx 8HXhxˆ˜¨¸ÈØèø8H@ H0HpH@@0H@@ H@@ H@@0H@@@H@H@ I  ™8€€ˆ 8HXhxˆ˜¨¨h 8HXhH¸ 8HXhxˆ˜¨¸ÈØèø¸¨ 8HXhx 8HXhxˆ˜¨¸ÈÿØèøyH0HpH@ H@0H@@ H@@@PH0HðH 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸¸h8¸ 8HXhxˆ˜¨¸ÈØ8¨ 8HXhxˆHX 8HXhxˆ˜¨X 8HXH 8HXH 8HXhxˆ˜¨¸ÈØèø)I0HH (@@@@@ (H@@ H@@@0H 8HXhxˆ˜¨H°¸x°¸¸°¸¸¸¸¸H80°0xp¨ 88x 8HXhxˆX 8HXhxˆ˜¨¸8 8HXhxˆ˜¨¨ÿH 8HXX 8HXhxˆ˜¨¸ÈØèø)9I0HpH0H@0H@PH@@@0H0H099)0™ 0É099Ù8°¨ 8hX 8HXhxX 8HXhxˆ˜¨¸ÈØèøØH 8HX 8HXhxˆ˜¨¸ÈØèø)9I @@€H0H@0H@PH@@@ H@0HPYPy P©PYYi8° `ppppPPPPYYY¹H 8HXhxˆ˜¨¸H 8HXhxˆ˜¨¸ÈØèø)9IIH0H H@@ HPH0H H@@ H@ÿ@PY Py P©PYYi8p° pPPPPP9H 8HXhxˆ˜¨¸ˆ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹)À ÀIÀÉÉ8° PPðH 8H8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéYðù9ðùi8€°°H 8H 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé)ð ð ðùY8`°p`H ( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™À@ððùYhp°@H@@ðùùÿùùùùùùùùùéXP@XYPÀYPðYÀ@ððù9xpp° 0HðùùùùùùùùùùùYP0XPYÀYPðY   8 8HXhxH€ˆˆˆˆˆˆxxp`°° H@@ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹XP X0X€XPP@X0X0X XPP X0X XPP0XPÀ‰ÀÀ‰ÀÉyx`€° @ÀÉÉÉÉÉÉÉÉÉÉÉÉÉYX0X°X0X0X0XPXP0XP0XÐX 8HXhxX 8H 8HXhxˆ˜¨¨°ÿ¸¸¸¸ˆx ˆ°@ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹IY0XX (0XPPPP0XPP  8HXhxˆ˜¨H°¸x ( 88@H(@H 8HXhxˆ˜¨ˆx ¸ @ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹IY0XpX0X0X0XPPP0XP XP@XÀÉ)À€0pÀÉyx ¸ @ÀÉÉÉÉÉÉÉÉÉÉÉÉɉXP€X XP0X0XPPP XP XPÿPP X 8HXhxˆ˜¨(°¸h p0p0p°¸¸¸¸xx0°  @ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹yY XPP XPP0XP0XPPPX XPPÀÉ)À p0€€ 88 8HXhxˆ˜ˆx`€° H 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ9Xà©  88 8HXhx8€0p0p€ˆˆˆˆˆˆXx`€° H 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÿÙYPPÐÙyÐÉ0p0pÐÙ9x`°0HÐÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙ©Ð  ( 8(@ 0@8 8HXhxˆ˜¨hx` °@@@ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù‰ÀàP0€Úy` °@ Ji`@hŠh`JÐÚy` ° Zi`0h`Šh`JÀJÚ x` ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹¹i`ÿ h`h``0h`` h0h h`` h``0h`À‰À  8 8HXhx8€ˆˆˆˆˆˆXx ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éihh` h`0h`0h`0h`` hÐh 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸hx ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éih0h (``0(``0(` 8HXhxˆ˜¨h°¸¸¸¸¨°¸¸¸¸h¨° 8HXhxˆ˜¨¸ÈØèøÿ)9IYiy‰™©¹Éihh0h``h` hPhÐÙ9ÐIÐ)ÐÙ)x °ÐÙÙÙÙÙÙÙÙÙÙÙÙÙihh0h``h` hPhÐÙ9  8 8HXhx8€ˆˆˆˆˆˆHx ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉYh ( 8`0h h``@h@h`` h 8HXhxˆ˜¨h°¸h@°¸˜°¸¸¸¸Hx €° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùÙ ºy €° ÿ Ú ºy ° Úªy` ° êÀ@ðªyh ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹yyp@xÀÉxp@xpÀ‰À@À9ÀÉ)x` °ÀÉÉÉÉÉÉÉÉÉÉÉÉÉ™xp0xpÀÙx@xpÀ‰   8 8HXhxH€ˆˆˆˆˆˆ(x ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹yyp xpxpp0xpp xpp xpp0xpp@ÿx@xpÀ‰ÀÀ‰ÀÉ pP °ÀÉÉÉÉÉÉÉÉÉÉÉÉÉ yxp xp0xpp xpppPx0xðx 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸(xP ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9x0x (ppppp (xpp xppp0x 8HXhxˆ˜¨H°¸x °¸¨°¸¸¸¸(x` ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9xx0xp0xpPxppp0x0ÿxÐÙ À Ð)ÐÉy` °ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ9xx0xp0xpPxppp xp0xÐÙ À Ð)ÐÉ x` ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É x ( 8p0x xpp x@p0x xpp xpp 8HXhxˆ˜¨8°¸h °¸˜°¸¸¸¸(x0 ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùùÐ šy0 °  šy ° ÿ Ð*ŠYp ° À ð  8HXhxˆ˜¨Pp ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹™‰€@ˆ‰€À‰€À‰À À9ÀÉy °ÀÉÉÉÉÉÉÉÉÉÉÉÉɹˆ€0ˆ€‰À‰€À‰À À9ÀÉy@ °ÀÉÉÉÉÉÉÉÉÉÉÉÉɹˆ€ ˆˆ 8Hˆ€€@ˆ0ˆ0ˆ ˆ€€ ˆ0ˆ ˆ€€0ˆ€ 8HXhxˆ˜x ¨˜ ¨¨( ¨ÿ¨¨¨hx@ ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉYˆÐˆ0ˆ0ˆ0ˆPˆ€0ˆ€0ˆÐˆ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸p €° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉYˆ0ˆ (0ˆ€€€€0ˆ€€  8HXhxˆ˜¨H°¸¸¸¸¨°¸¸¸¸p €° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉYˆˆ0ˆ0ˆ0ˆ€€€0ˆ€ ˆ€@ˆÐÙ `Ð)ÿйy °ÐÙÙÙÙÙÙÙÙÙÙÙÙÙYˆˆ ˆ€0ˆ0ˆ€€€ ˆ€ ˆ€€€0ˆÐɰ@Ð9йy ˜° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É9ˆ ( 8(ˆ€€ ˆ€€0ˆ€0ˆ€€@€ ˆ€€ 8HXhxˆ˜¨8°¸h°°p°¸¸¸¸p ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙÙˆàéIàÉ à™y€ °àéééééééééééé陉€€àéYà¹0p°à™y€ÿ °àééééééééééééééééIà¹0p€ 88 8HXhxˆ˜p` ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù© 88 8HXhxˆX0p0p˜˜˜˜˜x€ ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉY˜0˜Ð©˜ÐyÐÉ0p0pЙy€ °ÐÙÙÙÙÙÙÙÙÙÙÙÙÙY˜ ˜0˜Ð™˜ÐyÐÙ@ 0pЙy€ °ÐÙÙÙÙÙÙÙÙÙÙÙÙÙYP@ÿ €à`Âà @@BÂ`BB‚`Â`‚`BB‚`@BÂ`@ €à a¡á!bâa€¢¢¢â`@a@À`@@b€¢¢¢¢"!‚ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&§cbB‚`@Â`@Â`@Â`@B‚`B#`‚à a¡áa! €à !@ €à a¡á!b¢¢bÀâââ¢"‚ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&gc `‚  @@À  @@À  @ €à a¡á!b¢¢aÀâ"aÀââbaÀâââ¢"‚À €à a¡ÿá!b¢â"c£ã#d¤ä$e¥å%f¦æ&'c‚bÂ`@‚a@‚`BaBgç`€f€`@§a@g&‚ÀBgggggggggggggçbÂbÂ`@‚a@‚`BaBgç`€f€`@§a@'æ‚ÀBgggggggggggggç"`‚  €à @Â`‚`BBaaBB‚` €à a¡á!b¢¢aÀâ"a€`Àââ¢`Àâââbâ‚À €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ççd€&`€à  €à a¡áá`"""""bá‚ €à a¡á!b¢â"c£ã#dÿ¤ä$e¥å%f¦æ&g§ç'e((@hå‚Â((((((((((((((((aÀ&`€à €à a¡á!a"""""b!‚ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'e€f€aÀgh%‚ÁB(((((((((((襀 ‚‚è¡‚¡€(e€f€aÀgh%‚ÁB(((((((((((襀‚ Â è¡¡€(e€f€aÀgh% ‚ÂB €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'€€‚¡Â¡€‚ ‚‚‚ €‚‚ ‚ÿ€Â ‚‚¡¡€Bçe€&`€à  €à a¡áá`"""""b!‚ÂB €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g¢¢‚‚ €Â €‚‚ €€€B¡Â Â# ‚à a¡áa! €à !@ €à a¡á!b¢¢bÀâââb"‚ÂB €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'¢Â  ‚  €€€€€ €  €€‚ ‚‚‚  €à a¡á!b¢"aÀâbaaÀâ¢bÀâââ""ÂÂB €à a¡á!b¢â"c£ã#d¤ä$ÿe¥å%f¦æ&ç¡‚¢Â €Â €B¡€€€Â Â Bg'@€f€a@§`@ç%ÂÂBgggggggggggggç¡Â¢Â €Â €B¡€€€‚ ‚ Bg'@€f€a@§`@ç%‚ÂBgg§N:uêÔ©S§N:¤ ( 8 0¨ ¨   ¨@ 0¨ ¨   ¨   8HXhxˆ˜¨8°¸H`°¸˜°¸¸¸ˆˆ ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùY°  8 8HXhxH€ˆˆˆˆˆHˆ ° 8HXhxˆÿ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùY J‰ ° Z J‰ ° Z J‰ ° й°0¸°°ð¸°À¹° 8HXhxˆ˜x ¨¨¨¨¨X ¨¨¨¨(ˆ ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É)¸° ¸0¸ð¸À¹°ÐyÐÙyÐy‰ °ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ)¸°`¸€¸°°@¸0¸0¸ ¸°° ¸0¸ ¸°°0¸°ÐyÐÙÿyÐi‰p°ÐÙÙÙÙÙÙÙÙÙÙÙÙ©“"@ €‚ƒ„‚ ƒ ƒ ƒ … ƒ ƒ ……ƒ€ ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŠ ƒ€ ‚‚ƒ ƒ ‚€‚ƒ„…†‡ˆ‰Š„‹‹ˆ‹‹‹‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰ Š ƒ ƒ ƒ ƒ ‚ „ …– ÿ ˆ ‹ ‚ ƒ ƒ ‚ ‚ ƒ œ…– €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œˆ€ ‚‚€‚ƒ‚ ‚ ƒ ƒ „ ‚ €‚ƒ„…†‡ˆ‰Šƒ‹‹ˆ‹‹‹‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’ žž„žž„ž• žžžžžžžžžžžžžžž žž…žŒˆž•  žžžžžžžžžžžžžžžžžˆžÿ‹Šˆž• žžžžžžžžžžžžFNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GOW_gow‡—Ÿ§Ÿ X x $,4BFJNRVZ^bfjnrvz~f€‚€F. $€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&€‚€F. $€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&€‚€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&p€€B*,&"&*.26:>BFJNRVZ^bfjnrvz~fp€€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&p€€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&pÿ€€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&*,$"&*.26:>BFJNRVZ^bfjnrvz~f€‚€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&d|€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&h€€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*l ,"&*,$"&*.26:>BFJNRVZ^bfjnrvz~jp,  ÿ€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*t, ,€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€& ( "*,$"&*.26:>BFJNRVZ^bfjnrvz~J" $$$&&&&*,$"&*.26:>BFJNRVZ^bfjnrvz~j€&  (€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€*,€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€.ÿ "&*,$"&*.26:>BFJNRVZ^bfjnrvz~j€‚€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*h€€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*h€€B*,$€‚‚ (P @ (PŠ  """""*,$"&*.26:>BFJNRVZ^bfjnrvz~jh€€B*,$€‚‚‚‚‚‚‚ÿ‚‚‚‚‚‚‚‚*h€€B*,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€B*,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€B*,€‚‚ (P @ (PŠ*,"&*.26:>BFJNRVZ^bfjnrvz~jl€€B*,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*p€€>*,€‚‚‚‚‚‚‚‚~D\h€  d€€‚€>* ,€‚‚ ÿ(P < $, 044 0  0444044 0, 0 0 0444444444, 0444444444, 0444444,T@X0$,4^~žÞ1`1 à1 @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4T”1`1`2`ttttttttttttttttt1 1€0 `0  0`tttttttttttttttt”1`1€0 `0€0`tttttttttttttttt”0@p €0 @0   @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4T”1`1€0 €k0 0`tttttttttttttttt”1@01€0 `0€0`tttttttttttttttt´1 1 @0`0@0 `0 `ttttttttÔ¨Q£F5jÔ¨Q£F5jÔ¨I€;openacs-5.7.0/packages/acs-templating/www/doc/time2/stage05.gif0000644000175000017500000003213007253523117024035 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠƒŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠÿІŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠ ŠŠŠŠŠŠ…‰ŠŠŠŠŠƒŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡€‚ƒ„…†‡ˆ‰Š‹ŠŒŒŒŒŒŒ…ŒŒŒŒŒŒ…ŒŒ€ ‚ƒ„„€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠƒŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠƒ€‚ƒ„…€ ‚ƒ„…€‚ƒ„ƒ€‚ƒ„…€‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›œžŸŠ€‚ƒ„€ ‚ƒ„…€‚ƒ„…€‚ƒ„ƒ€‚ƒ‚ €‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ™€‚ƒ„…†‡ˆ‡€ ‚ƒ„ƒ€‚ƒ„…†€‚ƒ € ‚ƒ„… €‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚ƒƒ€‚ƒ€‚ƒ„…†… €‚ƒ„…†€ ‚ƒ„…€ ‚ƒ„„€‚ƒ„€‚ƒ€‚ƒÿ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚ƒ„…€‚ƒ„…ƒ€‚ƒ„€ ‚ƒ„…€ ‚ƒ„…†„€‚ƒ„ …‚€‚ƒ‚€‚ƒ„…‚††††††††††…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œˆ€‚ƒ„…†€‚ƒ€‚ƒ„„€‚ƒ„€ ‚ƒ„…‚€ ‚ƒ„ƒ€‚ƒ„€ ‚‚€‚ƒ€‚ƒ„…†„‡‡‡‡‡‡‡‡‡‚€‚ƒ„…†‡ˆÿ‰Š‹ŒŽ‘’“”•–—˜™š›€‚ƒ„…†‡ˆ€‚ƒ„€‚ƒ„€‚ƒ‚€ ‚ƒ„…†‚€ ‚ƒ„…ƒ€ ‚ƒ„…„€‚ƒƒ€‚ƒ„…†€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™˜€‚ƒ„…†‡€‚ƒ€‚ƒ„€‚ƒ„…†…€ ‚ƒ„…†‚€ ‚ƒ„…† €‚ƒƒ€ ‚ƒ„…†‡†€‚ƒ„…ƒ€‚ƒ„…†‡ˆ†‰‰‰‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒÿŽ‘’“”•€‚ƒ„…†‡ˆ‰Š…€‚ƒ„…†‡ˆ‰Š‹ŒŒ€ ‚ƒ„…††€ ‚ƒ„…‚€‚ƒ„…€ ‚ƒ„…†‚€‚‚ƒƒƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‰€‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ€‚ƒ„…†‡ˆ‡€ ‚ƒ„…†‡ˆ‰Š‹ŒŽ…€ ‚ƒ„ƒ€‚ƒ„…†‡„€ ‚ƒ„…€‚ƒ„……†‚ƒ†‚…††††††††††††††††††††…€‚ƒ„…†‡ˆ‰Š‹ŒŠ€‚ƒÿ„…†‡ˆ‰Š‰€‚‚€ ‚ƒ„…†‡ˆ‰Š‹ŒŽˆ€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š€ ‚ƒ„…€‚ƒ„…€ ‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆˆƒ‚„„‚ˆˆˆˆˆˆˆ…ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€‚ƒ‚€‚ƒ„…†„€ ‚ƒ„…†‡ˆ‰Š…€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ‰‡€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹‚€ ‚ƒ„…†‡ˆ…€‚ƒ€ ‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘Š’’’‹’’’†€‚ƒ€‚‚€ ÿ‚ƒ„…†…€‚ƒ„…†‚€‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰Š‹€ ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’‘“““ˆ“““‚‚‚€ ‚ƒ € ‚ƒ„…†‡ˆ‰Š‹ŒŽ€‚ƒ„…†‡ˆ…€ ‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—‡˜˜‘˜˜Šƒ ˜˜˜˜˜€ ‚ƒ„…†‡ˆ‰Š‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜ˆ™ƒ™ˆ™™‡ƒ  ™…€ ‚ƒ„…†‡ˆ‰Š‹Œƒ€ÿ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–•„—‘„——†—„„—‰——‹ € ‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‘ƒ›„›™š†›„››‚ ƒ ››››››››››››››”‚ƒ‡ƒ‚‚ƒ„„›™››‹›› € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š››ƒ‡‚ƒ‚ÿ…ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹ ‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‹‹‹‹‹‹‹‹ ƒ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ‡ƒƒ…ƒƒœ‚‚š ‚ „ˆƒƒ…ÿ‚ƒœ‚‚€€‚ƒ„…†‡ˆ‰‰  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ†‰ƒ‚‚…ƒ‚‚œ‚‚™  –ƒ™  –‡€€‚ƒ„…†‡ˆ‰ˆ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ”   •                  „œ„Ÿ •   ÿ          ˜„œ ”œ„Ÿ •              ˜€€‚ƒ„…††††„††††††††„††††‚€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ„  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚‚ƒˆ„ƒƒ‚‚ƒ‚ƒ—œ‡—  ‡ƒ‹ƒƒƒ…ƒƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ÿˆ‰ŠŠ‹‹‹‹ˆ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œˆƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œˆƒ‡ƒƒƒƒ‚„œ‰ˆƒ‡— ‰ˆ‚ƒƒ‚‚ƒÿœ€€‚ƒ„…†‡‚‡ƒ‡ƒ‡‡‡‡‡‡‡‡‚  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŠŠ‚ƒƒ…‚œ‚‡ƒˆˆ€‚ƒƒ€‚ƒ„…†‡ˆ‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’žš€‚ƒƒ€‚ƒ„…†‡ƒˆƒ‡ƒ‡ˆˆˆˆˆˆƒ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžž…ž‹ƒ‡ƒ‡ž•  ÿ žžžžžžžžžžžžžžžžžˆ€‚‚€‚ƒ‚„‚ƒ„ƒ€‚ƒ„…†‡ˆ‰†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ–œŽ…ƒˆ “              Ÿ„ ˆ ”  “              Ÿƒ ˆ ”œ „ “ €  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰‚‰ƒ‚ƒ‚‚ƒ—ÿœ€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆƒ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰‚ƒƒƒ‚€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ€‚‚ƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Š‹‹‹‹‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰ƒ†‚…ƒ„ÿ‚–  ‰ƒ†‚…ƒš€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆƒ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŽ€‚‚€‚ƒƒ‚„„‚€‚ƒ„…†‡ˆ‰Š†‹‹†„‹‹‰‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ–   ’                  ‡   ’                  ‡   ’ ÿ                 ‡œ„Ÿ ’ € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ„„‹„—œ„‚•  „ƒŒ„—š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ‚  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ„‚‰ƒ‚‚ƒ„„—œ‡•  ‹‰‚ƒÿ‚…ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‹ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‚‹‹Š‹‹‹‹†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‹‰ƒƒ…ƒƒœ‚‚•  ‹‰ƒƒ…ÿ‚ƒœ‚‚• € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰€‚‚€‚ƒƒ‚‚„ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚‹‹‰‹‹‹‹†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ—‚  ’                 ˆ   ’                 ˆ ‚ ’                 ˆœ‚Ÿ€‚ƒÿ„…†‡ˆ‰… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ…„œ—œ‚‚• …ƒ‘œ—œ‚‚• …‚Š€€‚ƒ„…†‡ˆ‰‡ŠŠ‰ŠŠŠ‚ŠŠŠŠŠ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒƒƒƒ…ƒÿƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‹‹‹Š‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒ‰ƒƒƒƒ‚„š†‚• Œ‰‚ƒƒ‚‚ƒœ›„ƒÿ• €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŠ€‚‚€‚ƒ‚‚ƒƒ„‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‹‹‡‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ”žž„žŒ‰Šž” žžžžžžžžžžžžžžž‚žž…ž‹ƒ‡‹ž” žžžžžžžžžžžžžžžžžŠž‹ƒ‡ˆ€‚ƒƒ€‚ƒ„…†‡ˆ† €‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›œžŸ€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‡ƒ‡‰‰‰‰‰… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‹ ƒ Š —Œƒ‡ƒ‡• ‹ ‚ ƒ ‰ —„‚ƒ‡• ‹ € €‚ƒ ƒƒ ƒ ‚ ƒ ‚ ‚ ƒ €‚ƒ„…†‡ˆ‰‡ŠŠŠŠƒ…ƒˆŠŠŠŠŠ €‚ƒ„…†‡ÿˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ“ ˆ ‚ ƒ ƒ ƒ ‚ € ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’ ƒ€ ‚‚ ƒ‚ ƒ‚ €‚ƒ„…†‡ˆ‰Š†‹‹„‹‹‹…‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‘ Š ƒ † ‚ … ƒš‚†• ‹ ƒ † ÿ ‚ … ƒš‚†• € ‚‚€‚ƒ ƒ ‚ „ „ ‚ €‚ƒ„…†‡ˆ‰Š†‹‹„‚‹‹‹‚‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ˜š€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆ‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ˜   ’                 ˆ›€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ‚  €‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›œžŸ˜š†Ÿ ’              › ƒ  ‡ „  ”š†Ÿ ’              › ‚ ƒ  ‡ „  ”š†Ÿ ’ € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ… † ‡ ƒ ‚ ‚ ƒ „ „ —š€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ ˆ ‚ ƒ ‚ ÿ … ƒ € ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒ ƒ€ ‚‚ €‚‚ ‚ ƒ €‚ƒ„…†‡ˆ‰Š„‹‹…„‹‹Š‹‹‹‹…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‹ Š ƒ ƒ … ƒ ƒ š†‚” ‹ ‹ ƒ ƒ … ‚ ƒ ÿš†‚” :uêÔ©S§N:-¤ ( 8 0¨ ¨   ¨@ 0¨ ¨   ¨   8HXhxˆ˜¨8°¸H`°¸˜°¸¸¸X¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù™°  8 8HXhxH€ˆˆˆˆˆ ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù™ ©° š ©° š ©° ÿ ʹ°0¸°°ð¸°À¹°J 8HXhxˆ˜¨¨°¸¸¸X¨° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Éi¸° ¸0¸ð¸À¹°ÐyÐÙyÐI©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙi¸°`¸€¸°°@¸0¸0¸ ¸°° ¸0¸ ¸°°0¸°ÐyÐÙyÐI©°ÐÙÙÙÙÙÙÙÙÙÙÙÙÙéh@pPpapapap¡p`ap`ap¡°ppAp°Ðð°@p @p°Ðð1QQ1`qqq±Pa!@p°Ðð1Qq‘±Ññ2Rÿr’²Òò3Ss“³qapAP`p`````p``@@p°Ðð1Q‘0`q1`qq `qqq±Pa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss““qAqapapap```ap`Apap¡³3   ³0 “Ra!¡³³³³³³³³³³³³³sqaqApaapap```ApaApa``ap¡“3   ³0 “Ra!¡³³³S§N:uêÔ©S§N‹-  .,,.,, ., .,,,.,,ÿ"&*,.",..,...*,$"&*.26:>BFJNRVZ^bfjnrvV.xzxxxN*,$xzzzzzzzzzzzzzz.,,xzx60 xN*,$xzzzzzzzzzzzzzzzz.x,( xN*,$xzzzzzzzzzzzzòäÉ“§E€  !#%')+-/13579;=?3<  ÿ !#%')+-/13579;=?#  !#%')+-/13579;=?3<   !#%')+-/13579;=?3@ @#@AAAAAAAAAAAAAAA@  @#@AAAAAAAAAAAAAAA@A@#@AAAAAAAÿAAAAAAAA"&**,....$"&*.26:>BFJNRVZ^bfjnrvz~f€‚€F.$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚&€‚€F.$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€F.$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€F.$€‚‚‚‚‚‚‚ (P @R(@p°Ðð0 àððð°0àððððððp!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóS3`3€044r!ÿT1@3À0à34r!T1 4r!T1 4r!(P @ (P  $,4<$ @DDD @DDDDDXH$,4BFJNRVZ^bfjnrvz~rl€€B.€‚‚‚‚ÿ‚‚‚‚‚‚‚‚‚‚‚2p€€>,€‚‚‚‚‚‚‚‚‚‚DXDH(T€€‚€>,€‚‚‚‚‚‚‚‚‚‚ 8HX(`hh8`(@`hX`hh`H`hh8`hhhhh`hhhhhhhhhX`hhhhhhXH° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©YP00  000€ 0€00 €00ÿ0   °°‰°I è`@p°Ðð1Qq‘±Ññ2Rr’²Òò3S³0 0 @0 `0 `0  0`0 @0 `01€0 @0 `0à0 @0 `0 `0@0@1 @0 `0 0 @0 `0 @0 3@3`0`ó0`“ò`asssssssÓ¦M›6m*(@P0`00@P @P0 `p0`0`0 `0`pP0` `00@P@p `0 `0@0 €0€P0`00@P`0 `P ÿ@p°Ðð Q0`0Q0ñð`@p°Ðð1Qq‘±Ññ2Rr’²Òò3S³0 0`0  0 0  0`0`0@0 1€0`0 `1`0 `0€0`0@1`0  0`0 `0  0`S0@3`0`ó0`“ò`assssssssssss³0`0 `0  0 @pP0@0 `0  ° `0 `0 `0@0@0 P0`0  0@0 @0  0 °°°°0 °°°°0@pÿP@p°Ððp0ñð`@p°Ðð1Qq‘±Ññ2Rr’²Òò3SÓ0 @0`0@0 `0 @0`0@0 @0`0@0 @1 @0`0@0 1`0@0 `0 €0 1`0@0 `0 @0 @0 @0`S0`ss1`“ò`assssssssÓ¦M›6m¢( @p°Ðð1Qq‘±Ññ  òñ`ò1 R1 òñ`ÿ’1 òQa$H A‚ $H A‚ $H A‚ $F€  !#%')+-/13579;=?9@A@@AAAAAAAAAAAAAAA@A@@AAAAAAAAAAAAAAA@A@@AAAAAAAAAAAAAAA@A@@AAAAAAAA (P  $,4FNV^fnv~†¾ H $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GOW_gow‡—Ÿ§X x $,4BFÿJNRVZ^bfjnrvz~J*  &.."&**"&*.26:>BFJNRVZ^bfjnrvzZ*" & .  "&**"&*.26:>BFJNRVZ^bfjnrvv* ". "&**"&*.26:>BFJNRVZ^bfjnÿrv**"..$ "&*.26:>BFJNRVZ^bfjnr*."&    """"""""&*.26:>BFJNRVZ^bfjn*. & ÿ"&**"&*.26:>BFJNRVZ:""&*.26*"". &     "$&&&&&& $&&&&&&&&&&""&*.26:>BF"**."&*.26& ÿ  "&*,....*,........"""&"*"&*.2 ."&*"&*    &     """""" """"""" """"""""""" *"&."&*.26 "&*.*ÿ&&"$   $&&&&&$&&&&&& $&&&&&&&&&*((."&""&*"&*.2 &"&*.26:>BF:HJJ.HJJJ:(((,,HJJJ""""&*.2& ÿ"&*.26:>BFJNPRRPRRR*((( ,,P6"""&*.2&"&*.""&*.26:>BFJNR"TVV TVVJ*(" . &"&*.2"&*.26:>BFJNRVZ\\*\^^" *((,, ÿ"&*&"&*."&*.26:>BFFHJHJBH&H:HJJJ "((( ., , &"""&*.2"&*.26:>BFJN PRPR2PP.PRR6"(.,, &"""&*.2.ÿ"&*.26:>BFJNR   PR2PRRPRR6"(($$$$,&"&"&*.2"&*.26:>BFJNRVJ   <"&**,.....*($,,"&"&*.26:>BFJNRVZ^bf ÿ   "&*,.,..,.....* $,,"&*.26:>BFJNRVZ^bfjn      prpppr:*( $, "&*.26:>BFJNRVZ^bfjn&    prpppr6*",prrrrrrrrrrrrr$ÿ  pr p """""""* $,"&*.26:>BFJNRVZ^bfjnrvzzt||~*"$,|~~~~~~~~~~~~~~~|~|~* ,|~~~~~~~~~~~~~~~|||~*( , |~~~~~~~~~~~úôéÓ'@€‚ƒ„…†‡„‡‡‡‡ƒ‡‡‡‡‡‡‡‡‡ƒ ‚ ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—ÿ˜™š›Š„œœ˜œ„œƒœœŠ ‚ ‚œœœœœœœœœœœœœ˜ƒœœ˜š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆ‚  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›Š‚ƒˆ„ƒƒ‚‚ƒ‚ƒœ˜œœˆœœŠ  ‚œœœœœœœœœœœœœœƒƒ‹ƒƒƒ…ƒƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹Šÿ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›’ƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰ŠŠ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›’ƒ‡ƒƒƒƒ‚„œœ‚œ‰ˆƒ‡œœˆ  œœœœœœœœœœœœœœ†ˆ‚ƒƒ‚‚ÿ€€‚ƒ„…†‡ˆ‰Š‚‹‹†‚‡ƒ‡ƒ‡‹‹‹‹‹‰   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›–Š‚ƒƒ…‚œœ‚œ‚‡ƒˆˆ€‚ƒƒ€‚ƒ„…†‡ˆ‰Š   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚žš€‚ƒƒ€‚ƒ„…†‡ƒˆƒ‡ƒ‡ˆˆˆˆˆˆˆˆ   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œœÿ‡Œƒ‡ƒ‡†  ‰€‚‚€‚ƒ‚„‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Šˆ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ†œŽ…ƒˆ Ÿ              „ ˆ ”  ž              ƒ ˆ ”œ€€‚ƒ„…†‡ˆˆˆˆˆˆˆˆ†   €‚ƒ„…†‡ˆ‰Š‹ÿŒŽ‘’“”•–—˜™š›—‚‰ƒ‚ƒ‚‚ƒœ˜œ€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆˆ†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚‰‚ƒƒƒ‚€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚ƒ€‚‚ƒ‚ƒ‚€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹Šÿ‹‹‹‹‹‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚‰ƒ†‚…ƒ„‚„  ‚‰ƒ†‚…ƒš€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆˆ†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚‚€‚ƒƒ‚„„‚€‚ƒ„…†‡ˆ‰Š†‹‹†„‹‹‰‹‹‹‹‹‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–ÿ—˜™š›œžŸ‰                    ™                    ™                    šœ„€‚ƒ„…†‡ƒˆˆˆˆˆˆˆ…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›“„œŒ„œ˜œ„œƒœœ„  œœœœœœœœœœœœœœ…ƒœ„œ˜š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆ„  €‚ÿƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›“‚‰ƒ‚‚ƒ„„œ˜œœˆœœ„  œœœœœœœœœœœœœœŒ‰‚ƒ‚…ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›šƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‚‹‹Š‹‹‹‹ÿ‹…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›š‰ƒƒ…ƒƒœœƒœ‚œƒœœ„  œœœœœœœœœœœœœœ‰ƒƒ…‚ƒœœƒœ‚œƒœœ„) ,$"&*.26:>BFJNRVZ^bfjnf   "&*,.,.&,....* ,$"&*.ÿ26:>BFJNRVZ^bfjnrvz~.t€€r* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚n€‚€r* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚nt€ €n* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚np """"""* ,$"&*.26:>BFJNRVZ^bfjnR" "@" p" pbpppr* ,$prrrrrrrrrrrrr" " D"p" pbpppr* ÿ,$prrrrrrrrrrrrr" " " " "" " "" " "&(*&(** (****&* ,$"&*.26:>BFJNRVZ^bfjnn"4" " " "" " "4""&**,....* ,$"&*.26:>BFJNRVZ^bfjnn" "  " " ÿ"&*,....*,....* ,$"&*.26:>BFJNRVZ^bfjnr"$" " " " " " "pr hppr* ,$prrrrrrrrrrrrr:"$"" " " " " "prlp"&** ,$"&*.26:>BFJNRVZ^bfjnj"  " " " "  " "&*,.,ÿ,,....* ,$"&*.26:>BFJNRVZ^bfjnrv""xzx2$(xr* ,,$xzzzzzzzzzzzzzR" xzx. ,xr* ,$ xzzzzzzzzzzzzzzzrx.  "&* ,$ "&*.26:>BFJNRVZ^bfjnrvz~"  $&&&&&* ,$ "&*.26:>BFÿJNRVZ^bfjnn&$ &$$p.&$pbp6  pr * ,$prrrrrrrrrrrrr:&$& &p*&$pbp: pr * ,$prrrrrrrrrrrâÄÉ €@ÁÁ„ÁA€€„„Á„„Á„ÁÁ„„Á€„„Á€@ÁAÂBÃCÄÄÃEEEÅÁ€Â€€Á€€ÄEEEEED„…‚@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÄÄ„Á€„Á€„Á€„Á€„Á„FÀÁAÂBÃÃB@ÿÁAB€@ÁAÂBÃCÄDEÅ€ÅÅÅÅÅA„…„@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÄAÀAA€€€AA€€€AA€@ÁAÂBÃCÄDEÀÅE€ÅÅÅ€ÅÅÅÅÅA„…„@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÃÅ„Á€Ã€Á„„ÎÎÁÍÁ€NÀÎN„€„ÎÎÎÎÎÎÎÎÎÎÎÎÎ΄ńÁ€Ã€Á„„ÎÎÁÍÁ€NÀNN…„€„ÎÎÎÎÎÎÎÎÎÎÎÎÎÎB€ÿ    !#%')+-/13579;=?4   !#%')+-/13579;=?@A@3 @AAAAAAAAAAAAAA=6    !#%')+-/13579;=?4 >@3ÿ @AAAAAAAAAAA#@@)4 >@1 @AAAAAAAAAAA#@@)4    !#%')+-/1357/ 814   !#%')+-/13579ÿ       !#%')+-/13579     !#%')+-/13579 :;4 ::7 :;;;;;;;;;;;;; ÿ:;4 ::7  !#%')+-/13579    !#%')+-/13579;=?6   !#%')+-/13579;=?@A@/@AAAAAAAAAAAAAA?@Aÿ@/@AAAAAAAAAAAAAA?@A@/@AAAAAAAAAAA%      !#%')+-/135718818987 89999999999999 818987 8999999999qâĉÓ$@ €‚ƒÿ„‚ ƒ ƒ ƒ … ƒ ƒ ……ƒ€ ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ„ ƒ€ ‚‚ƒ ƒ ‚€‚ƒ„…†‡ˆ‰Š„‹‹ˆ‹‹‹‹‹‹‹‹   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ Š ƒ ƒ ƒ ƒ ‚ „ …š   ‚ ‹ ‚ ƒ ƒÿ ‚ ‚ ƒ œ…š € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚€ ‚‚€‚ƒ‚ ‚ ƒ ƒ „ ‚ €‚ƒ„…†‡ˆ‰Šƒ‹‹ˆ‹‹‹‹‹‹‹‹  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒ žž„žž„ž™  žžžžžžžžžžžžžž˜ žž…žŒˆž™  žžžžžžžžžžžžžžžžž‚ž‹Šˆž™  ÿ žžžžž@+@AAAAAAAAAAA @€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‰  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™ÿš›œžŸ‘   •                  ‚   •                  ‚œ„Ÿ •                  ‚œ€€‚ƒ„…†‡ƒˆˆˆˆˆˆ…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ’š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ’œ „ ”               ÿ   ‚   ”                  ƒ   ”                  ƒ  "&* ,$"&*.26:>BFJNRVZ^bfjnrvz~N€‚€R* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€‚€R* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€‚€R* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€‚"&* ,$ "&*.26:>BFJNRVÿZ^bfjnrvz~Np€€R* ,$ €‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚p€€R* ,$ €‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚p€€R* ,$ €‚‚‚‚‚‚‚‚‚‚‚‚‚j @ÁAÂBÃÃÁ€ÃÃÃÀÃÃÃÃÃÃÃA„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÊÎÁP€PJ„…PPPPPPPPPPPPPPPPÂPP€PJ„…PPPPPPPPPPPPPPPP€̀ÀÏÐÉ€ƒPPPÿPPPPPPPPPPPPPÂ@ÁAÂBÀ€ÃÃÃC€ÃÃÃÃÃÃCÁ„ƒ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOʀ̀Á€ÅÅ€€ÄÐÉ„…PPPPPPPPPPPPPPPÐÂ΀€Å€Ä€Á€ÃÐÉ„…PPPPPPPPPPPPPPPЀ΀ŀÁ€Å€ÃÐÉ„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÊÐÄ€ÁÅDÀÁÁA@ÁAÂBÃCÄÄ…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÿÊJËKÌLÍMÎNÏÏFÀÁÁA@ÁAÂBÃCÄ€Á€Ä€Ä€ÄÄÄÄDC„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÊÐÄ€ÁÄÅÐI„…PPPPPPPPPPPPPPPÐÂPŀ€Á€ÅÐI„…PPPPPPPPPPPPPPPÐÂÐŀ€AÀAA@ÁA€@ÁAÂBÃCÄDC„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÊPP€PÉ„…PPPPPPPPPPPPPPPÐÂPP€PIÿ…„…PPPPPPPPPPPPPPPÐÂÍPÃPI€PPPPPPPPPPPPPPPPÃÍPC@€‚ƒ„…†‡ˆ‰…  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ–š€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆ‚  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ–š † ’                  †š † ’                  ‡   ’                 ÿ ‡   ’€  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ—š†Ÿ ‘                  ‡›„  ‘                  ‡œ  ‘             …ƒ‘€€‚‚€‚ƒ„…†‡†„ˆˆ‚†ˆˆ†ˆˆˆˆ‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š†ƒ‘ƒ“”„’—›“››‹ÿ›–  ›››››››››››››†ƒ‚‚ƒƒ„ƒƒ‰‚ƒ‚ƒ‚€€‚ƒ„…†…‡‡‡†‡‡‡‡‡‡‡‡‡‡‡†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š†€‚‚€‚‚‚‚ƒƒ‚ƒ‚ƒƒƒƒ‚ƒ‚ƒ‚ƒ‚‚ƒƒÿƒƒƒ‚‚ƒƒƒƒ‚€‚ƒ„…†„‡‡‡…ƒ‡‡‡‡†‡‡‡‡‡‡†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‡ƒ‚ƒƒƒ…ƒƒƒˆƒ‚„ƒ€‚‚€‚ƒƒƒƒ‚ƒƒƒƒƒ€‚ƒ„…†„‡‡‡…ƒ‡‡‡‡†‡‡‡‡‡‡†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‡ƒƒƒƒƒ…ƒƒ‚ÿˆƒƒ‚„ƒ…ƒ‚†ƒ…ƒ‚†ƒƒƒ™šƒ›‡›•  ›››››››››››››‡€€‚‚ƒƒƒƒƒ‚‚‚‚‚ƒƒ‚ƒ‚‚ƒƒƒ‚‚‚ƒƒƒƒ€‚ƒ„…†„‡‡‡…€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‡ƒ‚ƒ‚‚ÿƒ‚ƒ‚‰‚ƒ‚ƒ‚‚ƒƒƒƒƒƒƒƒ‚ƒ™››‹›• € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›–ƒœœœœƒœœ‰œ“  œœœœœœœœœœœœœœ‰œœœœ„œœ‰œ“  œœœœœœœœœœœœœœœœœœ‘œœ‰œ“  œœœœœœœœœœœœœ8qâĉS$@€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹ƒ  €‚ƒ„…†‡ˆ‰Šÿ‹ŒŽ‘’“”•–—˜™š›œžŸ™                     Š                     Š   Ž                  Š   Ž € €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ›                    ‹   Œ                  ‹ —‰ Œ  –  “  ”  “  “  “€€‚ƒ„…†ÿ‡ˆ‰Š‹Œ‚ˆƒ  Š…†………ƒ‡  ‹…†€€‚ƒ„…†‡ˆ‰Š‹Œ………ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰ˆƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£ÿ…ƒ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤˜¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏЦ„Ì†Íƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹‰…ŒŒŒŒŒŒƒƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹‰„ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ†ƒƒŒŒŒŒŒŒ‚…ŒŒŒŒŒŒ„ƒŒŒŒŒŒŒ†„ŒŒŒŒŒŒÿ…‡ŒŒŒŒŒŒ‚ƒƒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ„‡ŒŒŒŒŒŒ $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GOW_gow‡—Ÿ§× X x $,4?>?  >??????????????16     !#%')+-/13579;=34 >>? >???????????>>+4 >>? >???????????ÿ>>+     !#%')+-/1357  814   !#%')+-/1357          ÿ !#%')+-/1357     !#%')+-/1357 894 889 89999999999991 894 889 !#%'ÿ)+-/1357      !#%')+-/13579;=96     !#%')+-/13579;=;>?>? >??????????????;>?>?>??????????????=>?>? ÿ >???????????ZXXXX$,\X(,,,,\X(,,,,,,,,, $,4@)  @AAAAAAAAAAAAÿAA?6@@)  @AAAAAAAAAAAAAAA8@@) @AAAAAA !@€‚ƒ„…‚‚…†††††„„†††††„†††††††ƒ††††††††††…††††††††„   €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š…ƒ‘ƒ“”„›‰›“››‹›˜   ›››››››››››››…ƒ‚‚ƒƒ„ƒƒÿ‰‚ƒ‚ƒ€‚‚‚‚‚‚‚‚‚‚‚€‚ƒ„…†…‡‡‡†‡‡‡‡‡‡‡‡‡‡‡‡‚   ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š…€‚‚€‚‚‚‚ƒƒ‚ƒ‚ƒƒƒƒ‚ƒ‚ƒ‚ƒ‚ƒƒƒƒƒ‚ƒƒƒƒ‚€‚ƒ„…†„‡‡‡…ƒ‡‡‡‡†‡‡‡‡‡‡‡‚  ‚€‚ƒ„…†‡ÿˆ‰Š‹ŒŽ‘’“”•–—˜™š…ƒ‚ƒƒƒ…ƒƒƒˆƒ‚„ƒƒ‡…„‚†ƒƒƒ™šƒ›‡›—   ››››››››››6mÚdP@@@@@@@@ € `À`À`€`@@Àà `À`@À`€`À @À`@À`@Àà @À @À @À`€`Àà`À`À`@À` €à a¡!aÀááaaÀ`Àááá¡aÀáááááá!€‚`ÀÂ@ €ÿà a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æaÀ`@€`@@À`@€`@À`@aÀ`À`@Àb€`@@€`@€`€`@À`@À`@ÀaÀ`@a€`@€`€`À`À`À`@À`@f€&`€à  €à a¡áá`"""""¢ @BÀÂ@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æaÀ`€`@@@À`€`@@€`@@À`@@€`À`€`@@@b@@€`@@À`@€`À`€`@@€`€a@@€ `€  € @€ À À @@ €à ÿa¡!aÀáááááááá¡`ÀáááááááB‚Á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦eÀ`''gf'gbgåB€`'''''''''''''gb@@''§f'gb'åB‚Á€`'''''''''''''''''§b'gbçä€B‚ÂÀÂ`A €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§d((@èã€BÂÀ@((((((((((((((((a((@èãAÂÀ@((((((((ÿ((((((((a((@¨ã€BÂÀ@(((((((((((P @UP €à a¡á!b¢¢bÀâââ"À€@ÂÀB €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§e((@hã‚`ÂÂBA(((((((((((((((¨a((@(£‚`Â@((((((((((((((((b((@è¢ÂÁàÂ@((((((((((((((((D€   ÿ       )R¤HQ!@€‚ƒ„…†‡ˆ‰Š‹‰ŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒˆŒŒŒŒ…ƒ‡ˆŒŒ… ŒŒŒŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒŒŒŒŒƒŒŒŒŒŒŒƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ…ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’ÿ“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰ˆƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£…ƒ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤˜¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎϵ„ăÃÅ€‚‚€‚ƒ„…†‡ˆ‰Š‹„‹‹‹‹‹‹ÿ‚€‚‚€‚ƒ„…†‡ˆ‰Š‹ƒ‹‹‹‹‹‹‹‹Šƒ‚‹‹‹‹‹‹ƒƒ‹‹‹‹‹Šƒƒ‹‹‹‹‹Šƒƒ‹‹‹‹‹‹ƒ‹‹‹‹‹‹ƒƒ‚‹‹‹‹‹‹‚ƒ…‹‹‹‹‹Šƒƒ‹‹‹‹‹‹‹‹  8HXhxˆ˜¨¸XPÀÈÈÈȘPÀÈÈÈȘ ÀÈÈÈȨÀÈÈÈȨÀÈÈÈÈÈ@ÀÈÈÈȨ0ÀÈÈÈÈÈÈÈH@ÀÈÈÈȨPÀÈÈÈȘ@ÀÈÈÈÿȘ  ÀÈÈÈȘ  8HXhxˆ˜¨¸( ÀÈÈÈȘPÀÈÈÈȘ0ÀÈÈÈÈÈÈÈHPÀÈÈÈȘPÀÈÈÈȘpÀÈÈÈÈx0 ÀÈÈÈȈpÀÈÈÈÈx00ÀÈÈÈÈxPÀÈÈÈȘ00ÀÈÈÈÈÈÈÈ(P €à` €à a¡á!b¢â¢`@a####cbb####£a!`€  €à a¡á!b¢âbbÀâââââbaÀ`Àâââââb€aÀâââââ¢`aÀ`ÀâââââââbbÀaÀâÿââââ"@@aÀââââââ`@aÀ`Àââââ¢bbÀâââââb@aÀ`Àââââ¢b@aÀ`Àââââ¢b€aÀââââ⢠ @AÁ€Á@ÁAÂBÃCÄDÅEÆFCÀAA€AA@ÁAÂBÃCÄDEEÀAA€AA@ÁAÂBÃCÄDEEÀAA€A@ÁAÂBÃCÄDÅEÀAA€@ÁAÂBÃCÄDÅEÀAA€A@ÁAÂBÃCÄDÅEÀAA€A@ÁAÂBÃCÄDÅEÀAA€@ÁAÂBÃCÄDÅEAÀAA€A@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÿÊJËKÌLÍMÎNÏOÐPÑQÒRÓSÔTÕUÖV×WØXÙYÚZÛ[Ü\Ý]Þ^ß_à`áaâbãcädåeæfçgèhéiêjëkìlímînïoðpñqòrósôtõuöv÷wøxùùï€Å€€€Ç€€zzzôèm 8HPXXH 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *º@0P0::::::::::::::::ʰ@0@0::::::::::::::::ʰ@ `0::::::::::‘jÔ¨Q£Fb(@p €0 €0 0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4T”1@01€0 `0€0`tttttttttttttttt´1 1 @0`0@0 `0 `tttttttttttttttttttttttttt2;openacs-5.7.0/packages/acs-templating/www/doc/time2/stage08.gif0000644000175000017500000003473607253523117024056 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠ…ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠÿ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠˆŠŠˆ€ ‚ƒ„‚€ ‚ƒ„… €‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠ…ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠ†€ ‚ƒ„…†‡‚€ ‚ƒ„‚ €‚ƒƒ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠ…ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠˆ€ ‚ƒ„…†‡€‚ƒ„‚ƒ€‚ƒ‚€ ‚ƒ€‚ƒ„…€‚ƒ„‚€‚‚€ÿ‚ƒ€‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž„€ ‚ƒ €‚ƒ„…†‡€‚ƒ„€ ‚ƒ„ƒ€‚ƒ‚€ ‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ†€ ‚ƒ„…†‡€‚ƒ„‚€‚ƒ„…†ƒ€ ‚ƒ„€‚ƒ„€‚ƒ€ ‚ƒƒ€‚ƒƒ€‚ƒ„€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›™€ ‚ƒ„…†‡ˆ‚ÿ€‚ƒ„…†€‚ƒ„„€ ‚ƒ„…††€‚ƒ€‚‚€ ‚ƒ„‚€‚ƒ„„€‚ƒ„…†‚‡‡‡‡‡‡‡‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›ˆ€ ‚ƒ„…‚€‚ƒ„…†‡ˆˆ€ ‚ƒ„…†‡ƒ€‚ƒ€‚ƒ„…ƒ€ ‚ƒ„…‚€‚ƒ„…€‚‚€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‚€ ‚ƒ€‚ƒ„…†‡ˆ‰‡€ ‚ƒƒ€‚ƒ„€‚ƒ„€ ‚ƒ„…†‡ƒ€‚ƒ„…ÿ€‚ƒƒ€‚ƒ€‚ƒ„…†‡ˆ‰‰‰‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š™€ ‚‚€‚ƒ„…†ƒ€ ‚ƒ„…†‡€ ‚‚€ ‚ƒ„…†‡†€‚ƒ„……€‚ƒ„€‚ƒ„€‚ƒ„…†‡„€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‡€ ‚ƒ„…†‡ˆ‰‚€‚ƒ„€‚ƒ€ ‚ƒ„‚€‚ƒ„ƒ€‚ƒ€‚ƒ„„€‚ƒƒ€‚ƒƒ€‚‚ÿƒ‚€‚ƒ€‚ƒ‚€‚ƒ„…†‡ˆ‰ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™ƒ€‚‚€ ‚ƒ„…†„€ ‚ƒ„ƒ€‚ƒ„…†‡‚€ ‚ƒ„…ƒ€‚‚€‚‚€‚ƒ„„€‚ƒ„…†‡‡€‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰‰ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–€‚ƒ„…†‡ˆ‰Šˆ€ ‚ƒ„…‚€‚ƒ‚€ ‚ƒ €‚ƒ„…†‡ˆˆ€‚‚€ ‚ƒ€‚ƒ„…‚€‚ƒ„ƒ€‚ƒ„€‚ƒ„…†‡ÿˆƒ†‚…ˆˆˆˆˆˆˆ…ˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”€‚ƒ„…†‡‚€‚ƒ„…†‡ˆƒ€ ‚ƒ„…†ƒ€‚ƒ„…ƒ€ ‚ƒ €‚ƒ„…†‡€‚‚€‚ƒ„…ƒ€ ‚‚€‚ƒ„…€‚ƒ‚€‚ƒ€‚ƒ„…†‡ˆ‡ƒ‰ƒ‚„„‚‰‰‰‰‰‰‡‰‰‰‰‰‰‰‚‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰…€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡ˆ‰…€ ‚ƒ„…„€‚‚€ ‚ƒ„…†‡ˆ €‚ƒ„ƒ€ÿ‚ƒ„…‚€‚ƒ„……€ ‚ƒ‚€‚ƒ„……………………€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‹Œ‹ŽŽŽŽ‰ŽŽŽŽŽŽŽŽŽ€‚ƒ„…†‡ˆ‰…€ ‚ƒ„…†‡ˆ‰Š‹Œ‚ ŽŠ€‚ƒ„…†‡€‚ƒ€‚ƒ„„€‚ƒ„…„€‚ƒ€ ‚ƒ„ƒ€‚ƒ„…„€‚ƒ‚€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ„€ ‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ„…†‡ˆ‰Š‹†€ ‚ƒ„…†€‚ƒ„…†ƒ€‚ƒ„…†‡€‚ƒ„……ÿ€ ‚ƒ„…†‡ €‚ƒƒ€‚ƒ€‚ƒ„…€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‰’’’‹’’’Œ€ ‚ƒ„ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ€ ‚ƒ„…†„€‚ƒƒ€‚ƒ„…†‡ˆ€‚ƒ„‚€‚ƒ€ ‚ƒ„…†‡ €‚ƒ„…†‡†€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰“Ž“““‡ ‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽŒ€‚ƒ„‚€‚ƒ€ ‚ƒ„„€‚ƒ„…†‡ˆ‰Š€‚‚€ ‚ƒ„…†‡ €‚ƒ„ƒ€‚ƒ„ÿ…†‡ˆ‰‚ŠŠŠŠŠŠŠŠˆ„ŠŠŠŠ„ŠŠŠŠŠ‚ŠŠ‡„ŠŠŠ‚ŠŠŠŠŠŠƒ ŠŠŠ‚€‚ƒ„…†‡ˆƒ€ ‚ƒ„…†‡ˆ‰Š‹„€‚ƒ„…†‚€‚ƒ„…††€ ‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹Œ„€‚ƒ€‚ƒ„…†‡ˆ‰Š‹Œƒ„†…‰ Œ€ ‚ƒ„…†‡ˆ‰Šˆ€‚ƒ„…†‡ˆ‰Š…€‚ƒ„…†‡…€‚ƒ‚€ ‚ƒ„…„€‚ƒ„…†‡ˆ‰Š‹Š€‚ƒ„…†ÿ†€‚ƒ„…†‡ˆ‰Š‹Œ‡‚ƒ‡ƒ‚‚ƒ„„ŽŽŽŠŽŽŽŽ‰ŽŽŽŽ„ ‚„€ ‚ƒ €‚ƒ„…†‡ˆ‰Š‹‚€‚ƒ„…†‡ˆ‰‡€‚ƒ‚€ ‚ƒ„…†‡…€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡†€‚ƒ„…†‡ˆ‰Š‹ŒŽŠƒ‡‚ƒ‚…ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹… € ‚‚€‚ƒ„…€‚ƒ„…†‡ˆ‰Š…ÿ€‚ƒ„‚€ ‚ƒ„…†‡ˆ‰ƒ€‚ƒ€‚ƒ„…†ƒ€‚ƒ„…†ƒ€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‹ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‹‹‹‹‹‹‹‹…  €‚ƒ„…‚€‚ƒ„ƒ€ ‚ƒ„…†‡ˆ‰Š„€‚ƒ„…†‡ˆ‰Š‹Œ‹€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“’ƒ‡ƒƒ…ƒƒ””“”ˆ‚”‹””“ ƒ € ‚ƒÿ„…†‡†€‚ƒ„…†‡ˆ‰…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜“ˆƒƒ…‚ƒ™™‰™ƒ‚™†™™ˆ ‚ ˆ€‚ƒ„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›„‰ƒ‚‚…ƒ‚‚œœ‚œ‚œƒœœ‚  ‚€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ‚  ™ ‚                ›  ÿ ™                 ›   ™                 ž€  !#%')+-/1357/  8 818889 89999999999999  8 814   !#%')+-/13575       ÿ     81888789999999999999'               !#%')+-/13579           !#%')+-/13579    ÿ     :;8:3:;;;;;;;;;;;;;        :9   !#%')+-/13579      :;8  !#%')+-/13579;# <5ÿ   !#%')+-/13579; <= <BFJNRVZ^bfjn>$  pr pppr", (prrrrrrrrrrrrrrrr^pppr",((prrrrrrrrrâĉ'Nœ8a 8HXhxˆ˜¨¨°¸¸ÿ¸¸hx€°°    @ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùYÊy0°   `@@@ ZÀ@ðÊy° `@@@ ºXP@XYPÀYPJÀ@ðºy° Ph@ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹IYP0XPYÀYPÀ‰   8 8HXhxH€ˆˆˆˆˆˆ(x°°  `@@ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹IYP Xÿ0X€XPP@X0X0X XPP X0X XPP0XPÀ‰ÀÀ‰ÀÉ)x° €ÀÉÉÉÉÉÉÉÉÉÉÉÉÉéX0X°X0X0X0XPXP0XP0XÐX 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸8x° 0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉY0XX (0XPPPP0XPP  8HXhxˆ˜¨H°¸x ( 88@H(@H 8HXhxˆ˜¨8x°  8HXhxˆ˜¨¸ÈØèøÿ)9IYiy‰™©¹É P0XpX0X0X0XPPP0XP XP@XÐÙÀ€0pÐÙy° ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ)XP€X XP0X0XPPP XP XPPP0XÐÉ (@p°Ðð0 @0à0`0à0`0à0àðððððððà`AÁ@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“s°@±  @°  `° `°   °@°   ³3€3 @0à0`01 0@pp@p°Ðð1‘ð `!@p°Ðð1Qqÿ‘±Ññ2Rr’²Òò3Ss“³“±ÀS0@pp@p°Ððp0 1`0à0`0à0à `!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³3±  ÀÓ³0Às1`0à0`0à0Àsó`Á ÁÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓS0 0@P@pP0 €0 @0`0€p0@p°Ðð1QQð`!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó32€3À1 0 `0 1ó@a!TÓÀ€ÐÑÀ”2 3 ÿ 4ó@a!TÓÀ`ÐÀÑÀ”2€3”0Sa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss““ÐÀ@ÐÀ ÑÀÀ`ÐÀÀ@Ð`Ð@ÐÀÀ@ÐÀÀ`ÐÀ ó2€0@p@p°Ððp0Qa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“sÑ ÑÀ@ÐÀ`ÐÀ`ÐÀ`ÐÀÀ@РÐ@p°Ðð°@p @p°Ðð1QQ1`qqqq@a @p°Ðð1Qq‘±Ññ2Rr’²ÿÒò3Ss“sÑ`Ð@PÀÀ`PÀÀ`PÀ@p°Ðð1QÑ0`qqqqQ1`qqqqñ@aÁ @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“sÑ Ñ`ÐÀÀÐÀ@РР³s0 “0 S0 Só@aÁ ¡³³³³³³³³³³³³³sÑ Ñ`ÐÀÀÐÀ@РР³s0@30@p@p°Ððp0ñð@a!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“SÐ@P@pÀ`Ð@ÐÀÀ€Ð€ÐÀÀ@Ð@p°Ðð1QÑ0ÿ`qÑ0€0`q11`qqqqñ@a!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóS2 ôò@a!T0 ôRa!T044ôRa!T0€3€0à3ôRa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Sssóà€ð€“ñà€ðà€3€3€0€s0€sSa!“““““““““““““³ñà`ðà€³ñ€ðà€3@0@p0@p°Ðð0ÿÑPa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Sssóà@ðà ñàà`ðàà@ðàà@ðàà`ðàà€ð€ðà€3€3€1€SS`Á ““““““““““““““ò ñà@ðà`ðàà@ðààà ð`ðàð@p°Ðð°@p @p°Ðð1QQ1`qqqQQ`Á @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“Óð`ð@Pààààà@Pðàà@ðààà`ð@p°Ðð1Q‘0`qñ0ÿ@0`qQ1`qqqQQ`!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“óð ñ`ðà`ðà ðààà`ð`ð ³ €3@0  S0 3S`!¡³³³³³³³³³³³³³óð ñ`ðà`ðà ðààà@ðà`ð ³ €3 @0 S0 3S`!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ð@P@pà`ð@ðàà@ð€à`ð@ðàà@ðàà@p°Ðð1Qq0`qÑ0 @0`q11`qqqQQa!@p°Ðð1Qq‘ÿ±Ññ2Rr’²Òò3Ss“³Óós2 3@04ÔRa!t0 ´ò@a!t0 3 T0´Ra!t0€30 @p°Ððp0±Pa!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“3€3 @0€s0€3S`Á “““““““““““““Óa!3€3 @0€s0€3S`Á “““““““ÿ““““““ÓA@paaAAaAa@p°Ðð1ñ0@Q11 @QQQ0@QQQQqP`Á @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“ó¡aaa¡aa¡Ap°Ðð°@p @p°Ðð1QQ1`qqq1Q`Á @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“óaAP``@@p°Ðð1Q‘0`qqqqQ1`ÿqqq1Q`Á @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“ó!aaaaA¡³3@3À0 S0 S`!a ³³³³³³³³³³³³³ó!AaaAAa¡“3`3€0 s0 S`!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“ÓAP@pPAaaA@p°Ðð1Qq0`qÑ0 `1`1 à0`qqq1Q`!@p°Ðð1Qq‘±Ñÿñ2Rr’²Òò3Ss“³ÁÓ“0À“1 1@1ÀóR`!ÁÓÓÓÓÓÓÓÓÓÓÓÓÓ“ÁÓ³0Às1`0à0`1ÀóRa!ÁÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓ0Às1`0à0 0@pp@p°Ððñ@a!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó“0@pp@p°Ðð±0`0à0`0à0 1111ñð@a!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“ó0 a0!!¡S1 ¡ó2 “1`0à0`0à0 óò@a!¡ÿ³³³³³³³³³³³³³ó0 A0a0¡31 ¡ó2 ³1 €0 @0`0à0 óò@aa ³³³³³³³³³³³³³ó €@ÁÁ„ÁA€€„„Á„„Á„ÁÁ„„Á€„„Á€@ÁAÂBÃCÄÄÃEEEÅÁ€Â€€Á€€ÄEEEEEÁ„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÇÄ„Á€„Á€„Á€„Á€„Á„FÀÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ€ÅÅÅEÄ……„@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊÿJËKÌLÍMNÇ„AÀAA€€€AA€€€AA€@ÁAÂBÃCÄDEÀÅE€ÅÅÅ€ÅÅÅEÄ……@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÇÅ„Á€Ã€Á„„ÎÎÁÍÁ€NÀÎË……„ÎÎÎÎÎÎÎÎÎÎÎÎÎÎÆ„Å„Á€Ã€Á„„ÎÎÁÍÁ€NÀÎË……„ÎÎÎÎÎÎÎÎÎÎÎÎÎÎFÀAA@ÁA€„ÁÁ„„„„Á@ÁAÂBÃCÄDEÀÅEÂÁ€ÅÅEÁ€ÅÅÅED€…@ÁAÂBÃCÿÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÊMÀÁAA@ÁAÂBÃÃÁDDDDDDB€…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÊPP€PJ€…PPPPPPPPPPPPPPPЀMÀÁA@ÁAÂBÃCÂDDDDDDB€…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÊÍÀÏPJ‚…PPPPPPPPPPPPL…AÐCBPÊÍÀÏPJ„…PPPPPPPPPPPPLA…AÐCBÿPÊÍÀÏPJ@„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNAC…C…AAA…ABB…ÎËMÀÁAA@ÁAÂBÃÃÁDDDDDDB„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNEDA…AA…B…A…G@ÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ€ÅÅÅED„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎD…A@AAÿ@AAA…A@ÁAÂBÃCÄDE€ÅÅ€ÅEÅ€ÅÅÅED„…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNDE…A…A…B…A…A…ÎN€ÍÀNÁ€ÎK„…„ÎÎÎÎÎÎÎÎÎÎÎÎÎÎC…E…A…A…BA…A…ÎN€ÍÀNÁ€ÎK„…ÎÎN:uêÔ©S§N:u:HAP@p@aPAPAAAP@aPAPA@APAA@p°Ðð1Qq0`q‘0À0`q11`qqqñð@a!ÿa@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó³2`0@p@p°Ðð0qð@a!a@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó³2 tò@a!a´0 tò@a!Ô0 tò@a!4s`apaaáqasp@p°Ðð1ñ0@QQQQQ±0@QQQQ@`!@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“sp`Aÿpapáqs`¡ó2 ³ó0 ÓR`!¡³³³³³³³³³³³³³sp`ÁpqaapapapApaaApapApaaap`¡ó2 ³ó0 ÓR`!¡³³³³³³³³³³³³³Ó"@ €‚ƒ„‚ ƒ ƒ ƒ … ƒ ƒ ……ƒ€ ‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŠ ƒ€ ‚‚ƒ ƒ ‚€‚ƒ„…†‡ˆ‰Š„‹‹ˆ‹‹‹‹‹‹‹‡ÿ  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰ Š ƒ ƒ ƒ ƒ ‚ „ …–  ˆ ‹ ‚ ƒ ƒ ‚ ‚ ƒ œ…–  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œˆ€ ‚‚€‚ƒ‚ ‚ ƒ ƒ „ ‚ €‚ƒ„…†‡ˆ‰Šƒ‹‹ˆ‹‹‹‹‹‹‹†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œÿ’ žž„žž„ž”  žžžžžžžžžžžžžžž žž…žŒˆž”  žžžžžžžžžžžžžžžžžˆž‹Šˆž”  žžžžžžžžBFJNRVZ^bfjnrvz~^€‚€J* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€€€J* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚p|€J* ,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚p|€JR@X$,4@!@AAAAAAAAAAAAAAA6ÿ@@!@AAAAAAAAAAAAAAA8@@!@AAAAAAA(@     !#%')+-**...%.)*.!./'././/////////ÿ       !#%')+- ÿ      !#%')+-  ÿ   !#%')+-               !#%')+-ÿ            !#%')+-   ÿ      !#%')+-/1&0101#       ÿ!#%')+-/13579;=?7@A@@AAAAAAAAAAAAAAA@A@ @AAAAAAAAAAAAAAA@A@ @AAAAAAAAAAAAAAA@A@ @AAAA (P @j @ÁAÂBÃCÄDEÅ€ÅÅÅÅA…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÍPP€ÐG…PPPPPPPPPPPPPPPÐÅPP€PÇ…PPPPPPPPPPPPPPPPÆPP€PǃPPPPPÿPPPPPPPPPPPÆÐˀĀPƃ…@ÁAÂBÃCÃDDDDDDDDDD€DDDDDDDDDD€DDDDDDDDDÄDDDDDDDDDD€DDDDDDDDDD€DDDDDDDDDÄDDDDDDÀĀDDDDD„DDDÄÁDDDDDDDDDD€DDDDDDDDDˆ $,4FNV^fnv~– h $,4^~Þ7`1 à1 €žž=z›"&*.26:>BFJNRVZ^bfjnrvz~‚†Š.$ ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2, ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2,ŒŽŽŽŽŽŽŽŽŽŽ5jÔ¨Q£ $  ( $,4     !#%')+-/13579;=     !#%')+-/13579-    ÿ       !#%')+-/135              !#%')+-/13          ÿ    !#%')+-/         !#%')             ÿ  !#%'                        ÿ!#%&''&'''          !#%'()) ())#            !#%')*++*++  ÿ         !#%')***++       !  "#  "##"""###        ÿ  !#%'  ()  ()(  (())      !#%')!          *+*++*++        !#%')+)    ÿ             !#%')+-/1          !#%')+-/135!        67 6ÿ6 67   !#%')+-/1357       898889  !#%')+-/1357        898889    !#%')+-/13579;=1:>>? ÿ >??????????????;>?>=  >???????????????>>>;   !#%')+-/13579;=? 8>@9  @AAAAAAAAAAA  8 @)8>@7 @AAAAAAAAAAA  8 @)4     !#%')+-/1357)ÿ            818889  89999999999999                !#%')+-/13573           ÿ !#%')+-/13575         89889 89999999999999            !#%')+-/13579      898 ÿ   !#%')+-/13579; <5   !#%')+-/13579; <= <<7   <===============9:   !#%')+-/13579;=?8 @3 ÿ@AAAAAAAAAAA-  @ @):@@3 @AAAAAAAAAAA-  @ @)8  !#%')+-/13579         818   !#%')+-/13579         ÿ     !#%')+-/13579        !#%')+-/13579    :;: ::7 :;;;;;;;;;;;;;    :;4  ÿ !#%')+-/13579            !#%')+-/13579;=?@A@1 @AAAAAAAAAAAAAA=@A@1 @AAAAAAAAAAAAAA=@@@1 @AAAAAAAAAAAAAA=8    ÿ!#%')+-/1357/8818889  899999999999998814     !#%')+-/1357/818887 89999999999999#     ÿ  !#%')+-/13579    !#%')+-/13579 :;8::5 :;;;;;;;;;;;;; :;8: ÿ  !#%')+-/13579    !#%')+-/13579;=?:@@/ @AAAAAAAAAAAAAA?@A@/ @AAAAAAAAAAAAAA?:@@- @AAAAAAAAAAAAAA?ÿ(,$"&*.26:>BFJNRVZ^bfjnb" "@" p" pbpppj(,$prrrrrrrrrrrrr*" " D"p" pbpppj(,$prrrrrrrrrrrrr*" " " " "" " "" " "&(*&(** (****( ,$"&*.26:>BFJNRVZ^bfjnr"4"ÿ " " "" " "4""&**,...*( ,$"&*.26:>BFJNRVZ^bfjnr" "  " " "&*,....*,...*( ,$"&*.26:>BFJNRVZ^bfjnr"$" " " " " " "tvht tf( ,$tvvvvvvvvvvvvv"$"" " " ÿ " " "trlttf"(P@XH$,4@' @AAAAAAAAAAA Ô @€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹†  €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ“   ’                  ƒ   ’                  ƒœ„Ÿ ’                @ ÿ 8HXhx@pxxx8pxxxxxx@Pp ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù9   8 8HXhxH€ˆˆˆˆˆ(HPp ° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùIÀJ*IPp ° J *IPp ° J *IPp0 ° J 8HXhxˆ˜¨¨°¸¸¸hHPp0 ° ÿ8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùI *IPp0 ° J *IPp0 ° J *IPp0 ° J 8HXhxˆ˜¨¨°¸¸¸hHPp €° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùIÀ  *IPp €° JÀ  *IPp €° JÀ ÿ *IPp €° (P @ 8HXhx pxxxXpxxxxxx@Pp €° 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùIÀ  IPp €° J IPp €° JpðIPp ° (P  $,4, ( 8<<<$ 8<<<<<<$(8PXH$,4BFJNRVZ^B &*`bbZ"$"4" " " "" ," "4""&**,... "&*.26:>BFJNRVZ^B &*`bbZ"$" "  " " , "&*,....*,... "&*.26:>BFJNRVZ^B &*`bbZ"$"$" " " " "," "`b*`ÿ ``b  `bbbbbbbbbbb &*`bbV"("$"" " " " , "&* ,.,.*,... "&*.26:>BFJNRVZ^B &*`bbV" "  " " " " , "" "&*,.,,,... "&*.26:>BFJNRVZ^B &*`bbV"`Rÿ."`bB`J$(`b  `bbbbbbbbbbb &*`bbV"`R. `bF`F ,`b  `bbbbbbbbbbb$*"&*.26 "8:: .8:::.8:6  " "&*.26:>BFJNRVZ^B &*`bbV"`R.`b."  $&&&& "&*.26ÿ:>BFJNRVZ^>&*`bbV"$&$ &$$` .0&$`b`F  `b  `bbbbbbbbbbb&*`bbV"$&$& &`,0&$`b`J "& "&*.26:>BFJNRVZ^>&*`bbV"$&$&&$$ &$$& &,$$$&$$ &$`b`N  `b  `bbbbbbbbbbb&*ÿ`bbV"D& &$&&$$$,$$$$&"&**,... "&*.26:>BFJNRVZ^>&*`bbZ"@& & $$ $$, &$"&*,.,..,... "&*.26:>BFJNRVZ^> &*`bbZ"<&(& &$&$.&`b6` `.`b  `bbÿbbbbbbbbb &*`bbZ"8&,& &$&$.&`b6` `.`b 4@P 8HXhxˆ˜¨¸ÈØèø)9IYiyùh@x0˜`¨€‰‰i‰à˜ ( 80˜ ˜@˜0¸ ˜ 8HXhxˆ˜¨h°¸H °¸¸(°¸¸¸h8 H0X 8HXhxˆ˜¨¸ÈØèø)9IYiyùh@x0˜`¨€‰‰i‰€I¹€‰9€) 8( 8HXhx8€ˆˆˆˆˆ(8 H0X 8HXhxˆ˜¨¸ÈØèø)9IYiÿyùh@x0˜`¨€‰‰Y‰€I¹€‰I€‰€‰ 00H0X€‰‰‰‰‰‰‰‰‰‰‰9h0x@˜`¨€‰‰Y‰€I¹€‰I€9 8 8HXhxH€ˆˆˆˆˆ0 H@X 8HXhxˆ˜¨¸ÈØèø)9IYiyùh0x@˜`¨€‰‰Y‰€I¹€‰I€)`€y€‰ 0 H0X€‰‰‰‰‰‰‰‰‰‰‰Ih0x@˜`¨€‰‰Y‰@¨ 0¨  €y¸p¨ @¨ €‰I€)`€y€‰ 0 H0X€‰‰‰‰‰ &L˜0a"Èà @pP@p°Ððÿ1Qq‘±QP@APaPÁÑQpQP@ÁÑÑQ1À‘1À0ÀÑq0ÀÑÑñp@`°ÀÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ‘Ñ`ð€0¡PÁÑÑÑÑÑQP@ÁPáP@AaPAAAP@AAPA@`@AAPP@@p°Ðð1ñ0@QÑ0@pP@p°Ððp0`@`°@p°Ðð1Qq‘±Ññ2Rr’²ÒòÒ`ð€0¡PÓQQAAP@aP@AAP@@@aPaPáPAp°Ðð°@p @p°Ðð1ÿQQ1`qqq±p@`°@p°Ðð1Qq‘±Ññ2Rr’²ÒòÒ`ð€0¡PÓaQaPAP@@@@@@PP@@a@AAAaP@p°Ðð1Q‘0`q±0€0`qQ1`qqq±p@`°@p°Ðð1Qq‘±Ññ2Rr’²ÒòÒ`ð€0¡PÓAQAQaP@aP@¡P@@aAaPaPs1S0À0ó0`@`°“Ð`ð€0¡PÓ!QaQaP@aP@¡P@@aAAPA@ÿ@p°Ðð1Q‘0`q‘0À0`q11`qqq±p@`°@p°Ðð1Qq‘±Ññ2Rr’²ÒòÒ`ð€0¡PÓ!PAP@p@aPAPAAAP@aPa@A@APAA@p°Ðð1Qq0`q‘0À0`q11`qqq±p@`°@p°Ðð1Qq‘±Ññ2Rr’²ÒòÒ`ð`0ÁPÓ“r“2s0@p@p°Ðð0`@`°@p°Ðð1Qq‘±Ññ2Rr’²ÒòÒ`ð`0ÁPÓ“r“2ÿ32`@`°“Ð`ð`0ÁPÓsr³232`@`°“Ð`ð`0ÁPÓsp@p°Ðð1Qqq0€‘‘‘‘±0€‘‘‘`@`°€‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘Ð`ð`0ÁP‘‘‘‘‘‘Qp`apaaqpa`Qp`‘‘‘‘0€‘‘‘‘±0€‘‘‘`@`°€‘‘‘‘‘‘‘‘‘‘‘‘‘#FŒ1bĈ#F„$*"&*.26ÿ".,. .8,4.8.,8::*8:::&8:: 8:::::::::::::::::::2  &*8:::::*".,. .,,. . ..,,,, ..,, .,8::*"&**,... "&*.26:>BFJNRVZ^B  &*`bbZ"0.0. . . .., ., .4."&**,... "&*.26:>BFJNRVZÿ^> &*`bbZ",. .  .,,,, .,,"&*,.",..,... "&*.26:>BFJNRVZ^> &*`bbZ"(.(. . . .,,, .,.,.`b*``*`b  `bbbbbbbbbbb &*`bbZ"$.,.., . .,,,.,..,,,"&* ,.",..,... ÿ"&*.26:>BFJNRVZ^> &*`bbZ"$.  .,,.,, ., .,,,.,,"&*,.",..,... "&*.26:>BFJNRVZ^> &*`bbZ"`N..`bB``*`b  `bbbbbbbbbbb &*`bb^"`N.,,,`bF`N0 `b  `bbbbbbbbbbb $ *"&*.26"8::,ÿ8:::68: ,( 8:: 8:::::::::::::::::::. &*8:::::."8::,8:::68: (   8::8:::::::::räÈ‘#GŽ9räˆ €€@AA@ÁAÂBÃCÄDÅEÆFBGGG€GGGÇÆGGÁÅ€Á€ÃÁDÀÁÁA@ÁAÂBÃCÄÂAÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKHƒÁ„BLLÌKÌÉLÌFÀÁÁA@ÁAÂBÃCÁÿDÁ€Á€ÃÁÄDDDDDD€AÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKHƒÁ„BLLÌKÌÉLÌÊLÃÅ€Á€CÀAA@ÁA€@ÁAÂBÃCÄDÂAÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKHƒÁƒÁ„„BLLÌKÌÉLÌÊLɀ€€ÂÄLL€AÁLLLLLLLLLLLLBƒÁƒÁCLLÌKÌÉLÌÊÌɀ€€ÂÄLL€‚ÁLLLLLLLLLLLLB@ €‚ƒ €‚ƒ„…†‡ˆ‰Šÿ‹Œ„ŽŽŽ ŽŽŽŽŽŽŽŽ‰ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒƒƒ † ŽŽŽŽŽŽ‹ŽŽŽ ŽŽŽŽŽŽŽŽ‰ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒƒ€ €‚ƒ €‚ƒ„…†‡ˆ‰Š‹Œ„ŽŽŽ ŽŽŽŽŽŽŽŽ‰ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒƒƒ † ŽŽŽŽŽŽŠŽŽŽ‚ ŽŽŽŽŽŽŽŽ‰ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŒƒ€ÿ €‚ƒ €‚ƒ„…†‡ˆ‰Š‹ŒƒŽŽŽ‚ ŽŽŽŽŽŽŽŽ‰ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ‹„ƒ † ŽŽŽŽŽŽŠŽŽŽ‚ ŽŽŽŽŽŽŽŽ‰ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ‹„€ €‚ƒ €‚ƒ„…†‡ˆ‰Š‹ŒƒŽŽŽ ŽŽŽŽŽŽŽŽŽ…ŽŽŽ‡ƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ‹„ƒ † ŽŽŽŽŽŽŠŽŽŽ ŽŽŽŽŽŽ„ŽŽ„ŽŽŽ‡ÿƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ9ZÈà @pP@p°Ðð1Qq‘±qÁÑÑ`ÁÑÑÑÑ1À‘1À0ÀÑq0ÀÑÑñp€`°ÀÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑqÑ€ð`0ÁPÁÑÑÑÑÑQÁÑÑ`ÁÑÑÑÑ1ÀÑÑÑ11ÀÑÑñp€`°ÀÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑqÀ@ €à  €à a¡á!b¢â"cã ‚££#À‚££££c€£££cb€££ãáÁ`£££££££££££££££££££ã¢áÁ`‚¡ÿ‚££££££"‚££#À‚££££c€£#a€£#a€££ãáÁ`£££££££££££££££££££ã" À@ €à  €à a¡á!b¢â"cã ‚££#À‚££££c€£ca€£ã`€££ãáÁ`£££££££££££££££££££ã¢Áàa‚¡‚££££££"‚££#À‚££££c€£ca€£ã`€££ãáÁ`££££££££££££££££££#G‹$*"&*.26"8::,8::::82ÿ """""  "&*.26:>BFJNRVZ^> &*`bbZ"`N.`bZ``2`b  `bbbbbbbbbbb &*`bbZ"`N.`bZ`bF`b  `bbbbbbbbbbb &*`bbZ"".$&&&&&&$&&&&&& $&&&& "&*.26:>BFJNRVZ^> &*`bb^"`N.`bZ`bF`b  `bbbbbbbbbÿbb &*`bb^"`N.`bZ`bF`b  `bbbbbbbbbbb &*`bb^"`N."&*.022220222 022222222222222222222222 &*0222222*"022".02222*022220222 022222222222222222222222 $ *"&*.26"8:: .8::::8:::&8:: 8::::::::::::::ÿ:::::. &*8:::::*"8:: .8::::8:8:8:: 8:::::::::::::::::::*28HT$,4N^n~Žž®¾ÎÞîþ/?°ð@OO½M€   !#%')+-/13579;=?ACE FGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGG FGGGGGGGGGG5jÔ¨QŒ"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ6$  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽN;openacs-5.7.0/packages/acs-templating/www/doc/time2/stage12.gif0000644000175000017500000003521507253523117024042 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠÿŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ІŠŠŠŠŠ…‰ŠŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠ‡€              !#%')+-/ÿ13573         !#%')+-/1357          !#%')+-/1355       ÿ   !#%')+-/135!           !#%')+-/13'           ÿ !#%')+-/13              !#%')+-/1           !#%')+-ÿ                         ÿ                   !        !!! !!! ÿ   !#%'         !"##"##  !#%'       !#$%%$%%   ÿ      !#%&&&'' &'                       ÿ                               !!  !!! !!         ÿ                             !        ÿ       !#%')+-        ./. ../       !#%')+-/13       4544 45     ÿ !#%')+-/135        67 66 67   !#%')+-/13579;=:>>/   !#%')+-/13579;=#>?>/   !#%')+-/13579;=ÿ3>>>/  >??????????????78>>/   >???????????  8 >+8    !#%')+-/1357  8 814      !#%')+-/1357    ÿ         818885   89999999999999                 !#%')+-/1357'             ÿ!#%')+-/1357'         89885  89999999999999            !#%')+-/1357-      898ÿ    !#%')+-/13579; <5    !#%')+-/13579; :;::1  :;;;;;;;;;;;;;;;;:    !#%')+-/1357ÿ9;=?8 @+  @AAAAAAAAAAA#  @ @):@@)  @AAAAAAAAAAA%  @       !#%')+-/13571         818    ÿ!#%')+-/13579               !#%')+-/13579          !#%')+-/13579    :;: ::/  :;;;;;ÿ;;;;;;;;    :;4    !#%')+-/13579              !#%')+-/13579;=?@A@)  @AAAAAAAAAAAAAA;@A@) @AAAAAAAAAAAAAA=ÿ@@@' @AAAAAAAAAA ”'@€‚ƒ„…†‡„‡‡‡‡ƒ‡‡‡‡‡‡‡‚‚ ‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›™„œŒ„œ˜œ„œƒœ—‚ ‚ œœœœœœœœœœœœœœŒƒœ„œ˜š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆƒ‚ ‚ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›š‚‰ƒ‚‚ƒ„„ÿœ˜œœˆœ— ‚ œœœœœœœœœœœœœœ“‰‚ƒ‚…ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ†ƒ€‚‚€‚‚‚ƒ€‚ƒ„…†‡ˆ‰Š„‹‹‡‚‹‹Š‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ†‰ƒƒ…ÿƒƒœ‚‚–  †‰ƒƒ…‚ƒœ‚‚€€‚ƒ„…†‡ˆ‰† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ…€‚‚€‚ƒƒ‚‚„ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚‹‹‰‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ“‚  “           ÿ      „   “                 … ‚ “                 …œ€€‚ƒ„…†‡ƒˆˆˆˆˆˆƒ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚„œ—œ‚‚– ‚ƒ‘œ—œ‚‚– ‚‚€€‚ƒ„„ƒƒ‚‚ƒ‚ƒÿ€‚ƒ„…†‡ˆ‰‡ŠŠ‰ŠŠŠ‚ŠŠŠŠŠ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰ƒƒƒ…ƒƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰ƒ€‚‚ƒƒ‚€‚ƒ„…†‡ˆ‰Š„‹‹‹‹‹Š‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰‰ÿƒƒƒƒ‚„š†‚• ‰‰‚ƒƒ‚‚ƒœ›„ƒ•€ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‡€‚‚€‚ƒ‚‚ƒƒ„‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‹‹‡‹‹‹‹† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ’žž„žŒ‰Šž” ÿžžžžžžžžžžžžžžžžž…ž‹ƒ‡‹ž” žžžžžžžžžžžžžžžžžˆž‹ƒ‡ˆ€‚ƒƒ€‚ƒ„…†‡ˆ† €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸŽ€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‡ƒ‡‰‰‰‰‰… €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‰ ƒ Š —Œƒ‡ƒ‡• ‰ ‚ ƒ ‰ —„ÿ‚ƒ‡• ‰%$& $$$ &$$& &&$$&$$ &$"&(***  (****,$"&*.26:>BFJNRVZ^bfjnrF& &$&$ &$ &$ &$$&4&"&**,...,$"&*.26:>BFJNRVZ^bfjnrB& & $$ $$ $ÿ"&*,.,..,...,$"&*.26:>BFJNRVZ^bfjnr>&(& &$&$&&tvhttV,$tvvvvvvvvvvvvv:&,& &$&$&&tvhttV,$tvvvvvvvvvvvvv:& $ &&$$&&$$&"&*,.,.. ,... ,$"&*.26:>BFJNRVZ^bfjnrvz~Zh ÿ """""  ,$"&*.26:>BFJNRVZ^bfjnrvz~Z€‚€J(,$€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚l """"" (,$"&*.26:>BFJNRVZ^bfjnrvz~Zh|€J(,$€‚‚‚‚‚‚‚‚‚‚‚f*( *((€*(*(€Rh|€J(,$€‚‚‚‚‚‚‚‚‚‚‚f*(* *€**(€Rh|"&(,ÿ"&*.26:>BFJNRVZ^bfjnr*(**(( *((*((*(( *((**(t^h  """"" (,"&*.26:>BFJNRVZ^bfjnr2* *(*( *((*(((* *<*"&**,...(,"&*.26:>BFJNRVZ^bfjnr.* * ((((( *((*((( *ÿ"&*,.,.*,...(,"&*.26:>BFJNRVZ^bfjnr**(* *( *(*((( * *tvht tR(,tvvvvvvvvvvvvv&*,* *( *(*(((*( *tvht tR(,"&*.26:>BFJNRVZ^bfjnr&* ( **((*( **((*(("&*,.,.&,...(,ÿ"&*.26:>BFJNRVZ^bfjnrvz~^l """""(,"&*.26:>BFJNRVZ^bfjnrvz~^€‚€F(,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€‚€F(,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚€‚€F(,€‚‚‚‚‚‚‚‚‚‚‚j., .,,<.,p.,"&(*****(***&(,"&*.26:>BFJNRVZ^bfjnr.,ÿ. .<.p.,t^tvtR(,tvvvvvvvvvvvvv.,. .,,. . ..,,. ..,, .,t^tvtR(,tvvvvvvvvvvvêÔ‰ @ÁABÁ…Á…Á…Á…€…Á€…Á…ÂÂAÀÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ€ÅÅÅÅB‚…@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÅ…AÀAA€Á€€€€€Á€€A@ÁAÂBÃCÄDE€ÅEÄ€ÅÅE€€ÅÿÅÅÅB……@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNÅÅ…Á…Á…Á€€€…Á€Á…Â…Î΀N€€Î€NJ……„ÎÎÎÎÎÎÎÎÎÎÎÎÎNÅ…ÅÁ……Á…Á€€€Á…Á…€€…Á…N΀N€€Î€NJ……@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNEÀAA@ÁAÁ…€Á………Á€…Á…€B€Á……@ÁAÂBÃCÄDÅÁ€ÅEÄ€ÅÅE€€ÅÅÅÅB……@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌÿLÍMÎNÊOOÂÏOÂÏI……OOOOOOOOOOOOOOOÁ……OÏÂÏÆÆÄÏÉ……OOOOOOOOOOOOOOOOOÅπŀŀÄÏÉ…OOOOOOOOOOžBFJNRVZ^bfjnrvz~J" $$$&&&&(,"&*.26ÿ:>BFJNRVZ^bfjnrvz~j€&  (€B(,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€*,€B(,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€. "&(,"&*.26:>BFJNRVZ^bfjnrvz~j€‚€B* ,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€B* ,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*h€€B* ,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*h€€B* ,€‚‚ (P @ÿ (PŠ  """""* ,"&*.26:>BFJNRVZ^bfjnrvz~jh€€B* ,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*h€€B* ,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€B* ,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*€‚€B*$,€‚‚ (P @ (PŠ($,"&*.26:>BFJNRVZ^bfjnrvz~jlÿ€€>($,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚*p€€>(,€‚‚‚‚‚‚JPX€€$€$x, l€‚"& (,"&*.26:>BFJNRV2TT X6$X*XZ X,$XXZVXZ(,XZZZZZZZZZZ         ÿ       "Dˆ!Bƒ"& (,"&*.26:>BFJNRV2          ,$     ÿ      "& (,"&*.26:>BFJNRV2                      ÿ     "& (,"&*.26:>BFJNRV2     $ 0,  $ ,    X $,4,  8<<<4 8<<<<<,BFJNRVZ^bfjnrvz~r€‚€>*,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚2€‚€>*,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚2€‚€:(,€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚2€‚€:(,€‚‚‚‚‚‚ (P @ÅP €à a¡á!b¢¢bÀâââ¢à €à a¡á!b¢ÿâ"c£ã#d¤ä$e¥å%f¦æ&g§ç'gèe@b€bèàÂèa(hc(hc(hc(hc(hc(hcd¨e@b€bèàÂèa(hc(hc(hc(hc(hc(hcdheÀ`Àa€b €à a¡á¡áÂ""""b""""""""ba""""""""ba""""""""ba""""""""ba""""""""ba""""""""ba"b"""""baÀ`À!`€à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h¨# €à aÿ¡á!b"bÀ` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h¨èhaÀ`)))))))))))))))))f@))))))))))))))))©f €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h¨è(i©é)jªê*k«ë+l¬ì,m­í-n®î.o¯ï/p°ð0q±ñ1r²ò2s³ó3o€2`€  €à a¡á!b¢âbb@@######`€  €à a¡á!b¢â"b@@#####ã`@@######@@a####ãb@a######£ÿa@#####£`#####£a######b######@À`######@À`####ãb@a@####cb@a@######£B€     ÿ         1bP@@ €à a¡á!b¢â"a@a######ãa#####ÿã`@@#####ã`@@#####ã`#####ca@@#####£`@@######`€  @ €à a¡á!b¢ââ `€  À  €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h¨è(i©é)jªê*k«ë+l¬ì,m­í-n®î.o¯ï/p°ð0q±ñ1r²ò2s³ó3t´ô4uµõ5v¶ö6w·÷7x¸ø8y¹ù9zºú:{»û;|¼ü¼sÀb@@Àc@@===zô6 $(,,$ $,4BFJNRVZ^bfjnrvz~v€^$€:,€‚*€‚&€‚*€‚*€‚&€‚*€‚*€Z €6$,€‚*€‚&€‚*€‚*€‚&€‚*€‚*€V €2,("&*."022222022222 022222 022222022222 022222 0222 "&*.26:>BFJNRVZ^bfjnrÿvz~‚†:"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CK "&*.02222* "&*.02222.02222*02222"ÿ02222222202222.022222 02222202222* 02222& 02222"02222022222222 8HXhxˆ˜¨¸XÀÈÈÈȨÀÈÈÈÈÈXÀÈÈÈȸ0ÀÈÈÈȘ0ÀÈÈÈÈx00ÀÈÈÈÈH0ÀÈÈÈÈÈÈÈÈ8 ÀÈÈÈȸ0ÀÈÈÈȘÀÈÈÈÈÈ(ÀÈÈÈÈÈÀÈÈȈ‘"@€‚ƒ„…†‡ˆ‰Š‹ƒƒƒŒŒŒŒŒ†ÿ…ŒŒŒŒŒŒŒŒŒƒ‚ŒŒŒŒŒŒƒŒŒŒŒŒ‰ƒŒŒŒŒŒŒŒŒŒŒŒŒƒŒŒŒŒŒŠŒŒŒŒŒ‰ƒƒŒŒŒŒŒ†…ŒŒŒŒŒŒŒŒŒƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹ˆŒŒŒŒŒ‰ƒŒŒŒŒŒŒŒŒŒŒŒŒƒŒŒŒŒŒŒŒŒŒŒŒ‰ƒƒŒŒŒŒŒ†…ŒŒŒŒŒŒŒŒŒ†ŒŒŒŒŒ‹ƒŒŒŒŒŒ‰ƒŒŒŒŒŒ‹ŒŒŒŒŒŒƒŒŒŒŒŒŒŒŒŒŒŒŠ€‚€‚ƒ„…†‡ˆ‰Š‹…ŒŒŒŒŒŒŒŒŒ†ŒŒÿŒŒŒŒŒŒŒŒŒ‹ŒŒŒŒŒŒŒŒŒŒŒŒ‚ŒŒŒŒŒŠŒŒŒŒŒ‰€‚‚€‚ƒ„…†‡ˆ‰Š‹€‚‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòó¿‹ôôôèÑÛ(@p  °°0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4ðTt1 1€0 `0  0`tttttttttttttttt”1`1€0 `0€0`tttttttttttttttt”1`1€0 @0 À0`ttttttttttÔ¨Q£FÅP €à !@a@@a@a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h¨(c€`ba@@@À`aÀèèèèèèèèèèèèèèèèhc@@b@@€`À`€`@@À`@@Àèèèèèèèèèèèèèèèèèèèèèèèèèèd ;openacs-5.7.0/packages/acs-templating/www/doc/time2/stage14.gif0000644000175000017500000003764607253523117024056 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠˆŠŠŠŠŠˆŠŠŠŠŠ‰ŠŠŠŠŠˆŠŠŠŠŠ‰ŠŠŠŠŠˆŠŠÿŠŠŠ‰ŠŠŠŠŠˆŠŠŠŠŠˆŠŠŠŠŠ‰ЉŠŠŠŠŠ…‰ŠˆŠŠŠŠŠˆŠŠŠŠŠ‰ŠŠŠŠŠˆŠŠŠŠŠ‰ŠŠŠŠŠˆ"&*,....,....,...."&*$("(****"(****&(****"(****&(****"(****&(****"(**** ."&&&"&" "&*.26:>BFJNÿRVZ^bfjnrvZ. &" *"&**"&*.26:>BFJNRVZ^bfjnrv.&"*"&**"&*.26:>BFJNRVZ^bfjnrV. & "*  ÿ"&**"&*.26:>BFJNRVZ^bfjnr.  &"   *   "&**"&*.26:>BFJNRVZ^bfjn6..  &*     ÿ"&**"&*.26:>BFJNRVZ^bfjb.. **     "&**"&*.26:>BFJNRVZ^bfj"..*& "& "$&&&&&& "ÿ&*.26:>BFJNRVZ^bf*.* &" "&(*****"&*.26:>BFJNRVZ^bf. *(((&            "&*,....*"&*.26ÿ:>BFJNRVZ^bf. *&&  " "    "&*,....*"&*.26:>BFJNRVZ^b^.,**&"""  "&*.2.46666466666666666666666666&ÿ*.*((& ""&" ""&*.26:<>>><>>>>>>>>>>>>>>& *."  " "&*.26:>B*DFF:DFFFFFFFFF2&"&*."ÿ  "&*.26:>BF6H*H>HJJJJJJJ&"* ..""& "&*,..,...",.,.*,...........*& "*" .,,, ÿ ""&*.2 022022202 0202222222222*"&".,,""&*"&*.26   8::*8:::&8::::::::*  ÿ"&"". "  "&*."&*.26:   <"&**,...........*(&, "."&"&*.2 "&*.26:>     ÿ"&*,.,..,.........."*((."&&""&*.2"&*.26:>2     @BB.@2@>@BBBBBB".$""&  "&*.2"&*.26:>B    ÿDFF"D.D:DFFFFF.  *( & ""&*.26:>BFJNR>$  TVBTT*TVVV.*  $ "&*.26:>BFJNRVZ^bfjnbppprn.*(""$ÿ "&*.26:>BFJNRVZ^bfjnrNtvtvN.(((" & "&*.26:>BFJNRVZ^bfjnrVtttvJ.p (((  & "&*.26:>BFJNRVZ^bfjnrZpt tvF.p" * $ "&*.26:>BFJNRVZ^bR@ÿddf dddfZ.,,d * &"&*.26:>BFJNRVZ^bR @ddf d """"""".,,, "* &$"&*.26:>BFJNRVZ^bV      df dd.df>.,,@" *ÿ&$ "&*.26:>BFJNRVZ^bf  ,     4"&**,.....,,  " * &"&*.26:>BFJNRVZ^bf    "&*,.  "&*.ÿ" *($$"&*.26:>BFJNRVZ^bf     hjh $  hj".,T"*(d&hjjjjjjjjjjjJ   "&* ,.  ,.....,*& "&*.26:>BFJNRVZ^ÿbf(  hjh    "&.(*" &"&*.26:>BFJNRVZ^bfjJln     """""" . *( "" &$"&*.26:>BFJNRVZ^bfj>ln.l:  ln.,*( l$& lnnÿnnnnnnnnnnnnnl    "&*,,( ,."$&"&*.26:>BFJNRVZ^bfjnrvp8  tj,,*( d  &  "&*.26:>BFJNRVZ^bf"h:hjhhhj,$*( \40&hjjjjjjjjjjjV h:hjh h*hÿj.*(("X4,&"&*.26:>BFJNRVZ^bf&$   hjh  """"",*" "  &$"&*.26:>BFJNRVZ^bfB$   4"&**,...*,*(" ,&, , &  ÿ"&*.26:>BFJNRVZ^bfF    "&*,....*,...*,*",",$&  "&*.26:>BFJNRVZ^bfF$ hj&hhhj , * " H0$&0$hjjjjjjjjjjjj$ hj&h """"". * " " ÿ&$$$ "&*.26:>BFJNRVZ^bfF  "&*,.,.&,...&,* ",$(&   "&*.26:>BFJNRVZ^bfjnrvxzx^,( "00(&$T xzzzzzzzzzzzzzVxzx^,( "$8$&$X xzzzzzzzzzzzzzZx x xZÿ,((""&&"&*.26:>BFJNRVZ^bfjnrvpxxZ,( $$0&xxzzzzzzzzzzx*xZpxxZ,(  4&$txzzzzzzzzzz "$&&&&$&" """"",(  & "" "&*.26:>ÿBFJNRVZ^bf*$  hjh h*hj,(08&h  hjjjjjjjjjjjj$ "&**,...". (, ,&$,."&*.26:>BFJNRVZ^bfN    "&*,.ÿ,.*,...". (, , &$,.""&*.26:>BFJNRVZ^bfV$    hjh hhj.(08&hhjjjjjjjjjjjj&$   hjh  """"".(  & "" "&*.26:>BFJNRVZ^bfR   ÿ"&*,.,.&,...".((,&,. "&*.26:>BFJNRVZ^bfjnrv:tx xZ.($H&p$xzzzzzzzzzzzzzzxzxV,((D&l $xzzzzzzzzzzzzzztxxV",($H&h,xzzzzzzòäÉ“'OžBFJNRVZ^bfjnrvzh  """"" .( & "" "&*.26:>BFJNRVZ^bfjnrvz |~|N.(0&d0|~~~~~~~~~~~~~~ l """"" .( & "" "&*.26:>BFJNRVZ^bfjnrvzh||N.(4&\4|~~~~~~~~~~J*( *((|"*(*(|Vh||ÿN.0&`0|~~~~~~~~~~J*(* *|"**(|V,&"&*.26:>BFJNRVZ^bfj**(**(( *((*((*(( *((**(lfh  """"" . & "" "&*.26:>BFJNRVZ^bfjJ* *(*( *((*(((* *<*ÿ"&**,....(&,.("&*.26:>BFJNRVZ^bfjJ* * ((((( *((*((( *"&*,.,.*,....(&,.,"&*.26:>BFJNRVZ^bfjF*(* *( *(*((( * *lnhll^. &$$`0lnnnnnnnnnnnnB*,* *( *(*(((*( *lnhll^.ÿ & "&*.26:>BFJNRVZ^bfjF* ( **((*( **((*(("&*,.,.&,.... &,.,"&*.26:>BFJNRVZ^bfjnrvz"l """"" . & ""  "&*.26:>BFJNRVZ^bfjnrvz"|~|J,&l,|~~~~~~~~~~~~~~"|~ÿ|J,&h (|~~~~~~~~~~~~~~"|~|J,&d,|~~~~~~~~~~f.,,,,.,., "&**,...,&,. ,"&*.26:>BFJNRVZ^bfj>.,. .<.l,,lfln.lZ,&`0lnnnnnnnnnnnnB.,. .,,. . ..,,. ..,, .,lfln.lZ",&`,lnnnnnÿÚ´iÓ¦M›6e´ 8H(¸0¸0¸0¸P¸°0¸°0¸PX8¸ 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸Xˆ°p`˜°¸0°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©‰¹0¸ (0¸°°°°0¸°°  8HXhxˆ˜¨H°¸ˆ°¸¸°¸¸¸Xˆ°p`˜°¸8°` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©‰¹ ¸0¸0¸0¸°°°0¸° ¸°@¸°¹I°9°y°i‰°p`˜`9ÿ°h°¹¹¹¹¹¹¹¹¹¹¹¹‰¹°¸ ¸°0¸0¸°°° ¸° ¸°°°0¸°¹9°9°y°i ˆ°p (˜08888880088(h 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©™ ¸ ( 8(¸°° ¸°°0¸°0¸°°@° ¸°° 8HXhxˆ˜¨8°¸ˆ°¸¸°¸¸¸Xˆ°pP˜°¸8°h 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É™¸ÐÙiÐ ÐYÐI‰°`˜P9°h`ÐÙÙÙÙÙÙÙÙÙÙÙÙÙi¸°°ÐÙyÐéÀÿ€ÐI¹ P˜`9h`ÐÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙ)Ð ° €ÐI¹ P˜ 8HXh0p` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé9à 0€€ð)¹ P˜`9€hðùùùùùùùùùùùùùù9à 0p € 88 8HXhxˆX¸ P˜˜88€h` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé¹ 88 8HXhx(€(0p €€ˆˆˆˆˆ°pP˜€ˆH8€h 8HXhxÿˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéYà 0p ( 8 8HXhxˆ˜H¸pP˜ ˜80ph` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéYð¹@P€ð)¹pP˜09phðùùùùùùùùùùùùùùyðÉPP€ð)¹pP˜ 9€hðùùùùùùùùùùùùùùyðù9ð)¹pP˜90phðùùùùéÓ§OŸ>}úôéÓ'L€     !#%'ÿ)+-/13579;=1>?>%  >??????????????1>?>%  >??????????????3>?>%  >??????????????5>? $,4BFJNRVZ^bfjnrvzr|~|J.&<|~~~~~~~~~~~~~~r|||J.&8 |~~~~~~~~~~~~~~rp||F,&4 |~~~~~~~~~~~~~~v,&"&*.26:>BFJNRVZ^bfjnrvzvh """ÿ"",& "&*.26:>BFJNRVZ^bfjnrvzzp||F,&0 |~~~~~~~~~~~~~~z|~|F,&0|~~~~~~~~~~~~~~~|~|F,&, |~~~~~~~~~~~~~~~"&**,...,&,$"&*.26:>BFJNRVZ^bfjnrvz~|~|F,&( |~~~~~~~~~~~~~~~|~|F*,&($|~~~~~~~~~~ÿ~~~~~|~|F*,&( |~~~~~~~~~~~~~~~  8HXhxˆ˜¨¨°¸¸¸H¨°@˜8h 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù)À   ©°@˜8h *À   ©°@˜€8 h *À   ©°@˜€8 h (P @I 8HXhx pxxxXpxxxxxh¨°@˜p8p8h 8HXhxˆ˜¨¸ÈØèøÿ)9IYiy‰™©¹ÉÙéù9À   ©°0˜€8 h :  ©°0˜€8 h :pð ©°0˜p8 h %@€‚ƒ„…†……‡‡‡‡„‡‡‡‡‡‡† „ ‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ…›ƒ‹Šˆ  „ †‰               –œ‹ˆƒ‡  „ †ˆ            ÿ   —‹ƒ‹‡  „ €‚‚ƒƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ‡ ‰ƒŠˆ€‚ƒƒ€‚ƒ„…†‡ˆ„ „ …‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžž€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‰‰‰‰‰‰‰ƒ „ …ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸˆ ‰ƒˆŠ  „ …‡               ™ Š„‚‹  „ …‡     ÿ          ™ ‹…‚€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰ƒ „ „ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ‰    „ „‡               š    ƒ „‡               šš †  ƒ „ˆ               šš€€‚ƒ„…†‡ˆ‚‰‰‰‰‰ƒ ƒ ƒ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸŠš€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆÿˆ ƒ ƒˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸŠš †  ƒ ƒˆ               ›š †  ƒ ƒ‡               ›    ƒ ƒ…               €€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹„ ƒ ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸš†Ÿ  ƒ ‚ƒ                ›„   ƒ ‚ƒ       ÿ         œ   ƒ ‚ƒ        Œ  , &"&*.26:>BFJNRVZFTT \2$\8\2$\F\^N\^(,& \^^^^^^^^^^J      ÿ         "& *,& "&*.26:>BFJNRVZJ            ÿ     *,& "&*.26:>BFJNRVZJ              ""   """  """"*,& "&ÿ*.26:>BFJNRVZJ     $ 0, $ 0\\ \.\^(,& \^^ºtéÒ¥K—.]š( @pP0@0  0@0 `0  °P0   0€0@0  0 ° @0 `0 p0@0  0@0 `0  °P0   0€0@0  ÿ0 °°°°0 °°°°0@pP@p°Ððp0ñPaA0ApÀ@p°Ðð1Qq‘±Ññ2Rr’²ÒR2 @0`0`0€0 @0`0@0 @0`0@0 @1 @0À0 @0 `0 1 0 `0 €0 `0 @0€1 @0 @1 @0À0 @0 `0 1 0 `0 @ `0 @0@p°Ðð  ñPaA0ApÀ@p°Ðð1Qq‘±Ññ2Rr’²Òò“1`0 33Ó0@Pÿ@p°Ððp0@P@p°Ðð1QÑ0`qqqqQ1`qqqqPaA0ApÀ@p°Ðð1Qq‘±Ññ2Rr’²Òò³1 33333333 3ó1 ÓRaA0ApÀ 33333333333333333332 3ó1 ÓRa apÀ 333333333333333333332 3ó1 ÓrA0ApÀ 3333333S¦L™2eÊ”)S¦L™2I 8HXhxˆ˜¨¨°¸¸¸8¸ ˜ 8` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùi ú¸ÿ ˜ h z ꨰ ˜ h z ꨰ ˜ h z  8HXhxˆ˜ ° 8` 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùy ꨰ h Šz °©°0`€ºªºªºªªº0j€ °©°``º  8HXhxˆ˜¨8°¸¸¸¸H°¸ÿ¸¸¸8°¸¸¸¸H°¸¸¸¸8°¸¸¸¸8°¸¸¸¸H°ˆ°¸¸¸˜0p°x°¸H¨°`0°¸H°¸¸¸¸H°¸¸¸¸8°¸¸¸¸H°¸¸¸¸8°¸¸¸¸H°¸¸¸¸8°¸¸hÑ¢A€   !#%')+-/13579;=?AC  !#%')+-/13579;=?ACEG HIIIIIIIIIIIIIIII1HIIIIIIÿIIIIIIIIII5 !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}ƒ…‡‰‹‘“•—™›Ÿ‰n       ÿ           ÿ          ÿ         !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}ƒ…‡‰‹‘“•—™›Ÿ¡£¥§©«­¯±³µ·¹»½¿ÁÃÅÇÉËÍÏÑÓÕ×ÙÛÝßáãåç¥èééÑ£· P €à !@@aa!a €à a¡áÿ!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h¨èb@@@@ba@@À`@@@aÀèèèèèèèèèèèèèèèè(cÀba@@@À`aÀèèèèèèèèèèèèèèèè(cÀba@@€`@€aÀèèèèèèèèèè¨Q£F5Š @ÁAB€Â€€Â€Â@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPQÆÁÄ€€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÆ€€Ä€€Á€ÁÁ€€€Á€€€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ ÑÑÑÑÑÑÑÑÑÉ@;openacs-5.7.0/packages/acs-templating/www/doc/time2/stage15.gif0000644000175000017500000004133307253523117024043 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@=Šÿ$§§ ÄO™b×€€€f(õ;°ÛXXÂu`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠƒŠŠŠŠŠŠŠ€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹Œ‡ÿ†‹€‚ƒ„€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹…ŒŒŒŒŒƒŒŒŒŒ‡‰ŒŒŒŒŒŒ‹ŒŒŒŒ…€‚ƒ„…ƒ€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š‹Œ‡‹€‚ƒ„…†‡ˆ‰Š‹‰€‚ƒ„…†‚€‚ƒ‚€‚ƒ„…†…‡‡‡‡‡‡‡‡‡‡ƒ€ ‚ƒ„…†‡ˆ‰Š‹Š€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠƒŠŠŠŠƒ€‚ƒ„€‚ƒ„…†‡ƒˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽˆ€‚ƒ„…†‡ˆ‰‚Š€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‚ÿ€ ‚ƒ„…†‡ˆ‰ˆ€ ‚ƒ„…… €‚ƒ„…†ƒ€‚ƒ„…†‡‚€‚‚€‚ƒ„ €‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ€‚ƒ€‚ƒ„…†‡ˆ‰„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‰€‚ƒ„…†‡ˆ‰Š‚€‚ƒ„…†‡ˆ‰Š‹… Œ†€‚ƒ„…ƒ€‚ƒ‚€ ‚ƒ€‚ƒ„„€‚ƒ„…†‡ˆ‰€‚ƒ„…†€‚ƒ€ ‚‚€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹ƒ€‚ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ÿŒˆ€‚ƒ„…†‡ˆ‰Š‹‹€‚ƒ„…†‡ˆ‰Š‹ŒŽ† Ž€‚ƒ‚€‚ƒ€‚ƒ„€ ‚ƒ„‚€‚ƒ„…†‡ˆ‰Š€‚ƒ„€‚ƒ„…†€ ‚ƒ€‚ƒ€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹€‚ƒƒ€‚ƒ„…†‡ˆ‰Šˆ€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‹ „€‚ƒ„…ƒ€ ‚ƒ„…„€‚ƒ„„„„„„„„„„„„€‚ƒ„€‚ƒ„…†‡ ‡†‡‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‚‡‡‡‡‡ÿ„€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”€‚‚€ ‚ƒ€‚ƒ€ ‚ƒ„…‚€‚ƒ„…†‡ƒˆˆ†€‚ƒ„…‚€‚ƒ„…††€ ‚ƒ‚€‚ƒ„…‚††††††††††…€‚ƒ„…†‡ˆ‰Š‹ŒŽƒ€‚ƒ„…†…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–€ ‚ƒ‚€‚‚€ ‚ƒ‚€‚ƒ„…†‡ˆ‰‚ƒ‡‚€‚ƒ‚€‚ƒ„…€ ‚ƒ„‚€‚ƒ„…†„‡‡‡‡‡‡ÿ‡‡‡‚‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–•€ ‚‚€‚ƒƒ €‚ƒ€‚ƒ„…†‡ˆ‰ˆƒ‡‚ƒƒƒ‚Š‚€ ‚ƒ‚€‚ƒ„…†…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‡Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–• €‚‚€ ‚‚€‚ƒ„…†‡ˆ‰Šˆƒ€‚‚ƒ‚ƒ‚€‚ƒ„‚ ……………………ÿ…€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹„€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–Œ€‚ƒ„ € ‚ƒ„ €‚ƒ„…†‡ˆ‰Š‹‚ƒ€‚ƒƒ€‚ƒ‚ƒ‚ƒƒƒ €‚ƒ„…†‡ˆ‰„ŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ‚€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‚… ———‹‡ƒ†‚…‡ ——†——“————‰‚———————————”… ÿ ———އƒ‚„„‚… ——ˆ€   !#%')+-- .//.#././'./// .//////////+ .//.'././'./// .//////////-.//    !ÿ#%')+-/ .//.     !#%')+-/ .// .  ./ . ../// .//////////- .//  .  ./ . ..///* $,4BFJNRVZN&*\^^R"\.. \^N\J  \^^F \^^^^^^^^^^N&((\^^N"\2.\^^\   "&*.2" 466666666666666666662$(466666."ÿ46&.46666246 4  466666" 46666666666666666666.(4666662"(  . "&(*&(** (*******"&*.26:>BFJNRVZF$(\^^R", @.\\^\\6\^^B\^^^^^^^^^^F$(\^^R",$ .  ÿ\^\ $,4< @DDDDDDDDD$, $,4BFJNRVZB&(\^^R"\6.\^^F\\"\^^  \^^^^^^^^^^B&(\^^N"<" "4." \" \^\\"\^^ \^^^^^^ºtéÒ¥H€  ÿ        !#%')+-# .//%.        !#%')+-# ÿ.//#.     !#%')+-! .//!../. ..//  .//////////! .//!.     ÿ !#%')+-! .//#.     !#%')+- .//%.../%.'.//  .////////// .//'.*./'.%.// ./////////]rèÀ@p A@p°Ðÿð1Qq‘1¡±qq¡±±±±±‘1 ±±Q0`0à0 0@pp@p°Ðð1Qñ`@°@p°Ðð1Qq‘±Ññ2Rr’²Òòñ@ÐàPáòòráÒqáòò²0@pp@p°Ðð±0`0à0`0à0 111111ñ`@°@p°Ðð1Qq‘±Ññ2Rr’²ÒòñÀàPáòòrár0 a0!!apá’1 áòÒ0àR2`0à0`0à0àòò€`@°àòòòòòòòòòòòñÀàPáòòrár0 A0a0Apá’1 áòÒ0àr2 €ÿ0 @0`0@p @p°Ðð1Qqq``°€‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘ðÀQ‘‘‘‘‘‘‘‘Q0 Á0Ap0 !a0!!A0a0A0!!A0 !a0 ‘‘‘‘0€‘‘ñ0 0 `0 1€‘‘‘‘1‘``°€‘‘‘‘‘‘‘#FŒ1bĈ#FŒ1b4Ѐ €à   €à a¡á!b¢â"c"BccbÂàaB‚`@Â`@Â`@Â`@B‚`B#`‚à a¡áa! €à !@ €à a¡á!b¢¢bÀââââââ ÁÀ€`ÿ €à a¡á!b¢â"c£ã#d¤ä$e¥åã€Áa‚Âåå¥$ÂåbÂ`ÂBBB@Â``‚  @@À  @ €à a¡á!b¢¢aÀâ"aÀââbaÀââââââ a €à a¡á!b¢â"c£ã#d¤ä$e¥åã€Áa‚Âååe$ÂåbáBaÂ`@‚a@‚`BaÂååcÀå`€`À%cÀåå%Á`Áåååååååååå%äb‚Âååe$Â¥bBáBaÂ`@‚a@‚`BaÂååcÀå`€`À%cÀåå% €@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÿD…ËËKI„KEÀAA€@AÁ„ÁÁ„„„A€„A€„„Á@ÁAÂBÃCÄDEÀÅEÂÁ€ÅÅEÁ€ÅÅÅÅÅÅA‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈD…ËËËH„ËÈ…ËËKË€ËAÀÁAA@ÁAÂBÃÃÁDDDDDDDDB‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈD…ËËËH„KÈ…ËËËË€ËËÉ€ËKK‚ËËËËËËËËËËËǃÅËËËH„KÈ…ËËËË€KBÀÁA@ÁAÂBÃCÂDDDDDDDDBÂ@ÁÿAÂBÃCÄDÅEÆFÇGÈHÉIÊJËÇÄ…ËËËH„KÈ…ËËËË€ËÁÀKÄ€ËKK‚Á‚ËËËËËËËËËËKÈÄ…ËËKH„K…A…Ã…KDB…ËKÀËÁÀKÄ€ËKK‚Á‚ËËËËËËËËËËKHÀ@ÁÁÁ@ÁAÂBÃCÄDÅEÆC„ÆEA…AÃ…ÆFCB…ÆÆÆÆ€ÆÆÃ€ÆÆÂ€ÆÆÆÆFA‚Á‚ÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÄÄ…ÆÆÆÆÆFD„ÆECÃ…AAA…AÿBB@@ÁAÂBÃCÄÄÃEECÀÁAA@ÁAÂBÃÃÁDDDDDDDÄA‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÄ…ËËËH„ËD…ÃA…AA…B…A…G@ÁAÂBÃÃB@ÁAB€@ÁAÂBÃCÄDEÅ€ÅÅÅÅÅE‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÄ…ËËËH„KD…A@AÁ@AAA…A@ÁAÂBÃCÄDE€ÅÅ€ÅEÅ€ÅÅÅÅÅE‚Áÿ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÄ…ËËËH„ËC…Ä…A…A…B…A…A…ËËÆ€ËÁÀKÄ€ËKJ‚Á‚ËËËËËËËËËËËÇÄ…ËËËH„KC…Ä…A…A…BA@@ÁAÂBÃCÄDE€ÅEÂÀÅÅÄ€ÅÅÅÅÅE‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÄ…ËËKI„KC@AA@AÁ…AAA…AA…AAA@ÁAÂBÃCÄDÅÁ€ÅEÂÀÿÅÅÄ€ÅÅÅÅÅE‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÄ…ËËËH„ËÈ…ËËËK€€KBÀÁA@ÁAÂBÃCÂDDDDDDDD‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÈÄ…ËËËH„ËÈ…ËËËK€€ËËÉ€ËËI‚Á‚ËËËËËËËËËËËǃÅËËËH„ËÈ…ËËËK€€ËËÉ€ËËI‚Á‚ËËËËËËËËËËËǃÅËËKH„KÉ…ËËËK"&**,....* "&*.26:ÿ>BFJNRVZB&(\^^B"\., .,,. .,\.,\^\^N\^N \^^^^^^^^^^>&(\^^F"\.,. ..$.\.,\^\^N\^N "&*.26:>BFJNRVZB&(\^^B"\.,...,,. . ..,,. ..,, .,\^\^N\^J \^^^^^^^^^^B&(\^^B"\2... . . ...,,,ÿ."&**,....& "&*.26:>BFJNRVZB&(\^^B"\.. .  .,,,, .,,"&*,.",..,....""&*.26:>BFJNRVZB&(\^^F"\*... . . .,,, .,.,.\^2\\.\^F \^^^^^^^^^^B&(\^^F"\&.ÿ ..., . .,,,.,,,,,,"&* ,.",..,...." "&*.26:>BFJNRVZB&(\^^F"\&. ,, ,,, ..,,"&*,.",..,...." "&*.26:>BFJNRVZB&(\^^F"\J.\.\^J\\.\^F \^^^^^^^^^^>&(\^^ÿB"\J.\.,,\^N\R0 \^B\^^^^^^^^^^B&("&*.2""466 .466666646,( 4666*46666666666666666666&&(466666""466 .466666646(   4666*466666jÔ¨Q£F5jÔ¨Q£F:0LP$,4BFJNRVZB&(\^^N"\B.\^^^*\\&\^2 \^^^^^^^^^^B&(\^^N"\B.\^^^*\ ,( \^2 \^^^^^^^^^^B&("&*.2*"466.4666666.46ÿ ,  4666 46666666666666666666"&(466666*"462.4666666246, ,4666 46666666jÔ¨Q£F5jÔ¨Q#D€      !#%')+- .//'.!.///   ÿ  !#%')+- .//'..///.%./ .////////// .//'..///.'./  .//////////       !#%')+- .//%..///./'./  .ÿ////////// .//%..///./'./  .////////// .//%.            ÿ !#%')+- .//#..///.../  .//////////.//%..///.../  .//////////!.//#.!.///9 8HXhxˆ˜¨¨°¸¸¸¨H0P 8HXhxˆ˜¨¸ÈØèø)9IYiùx`€˜ ¨pyy‰p ¹pyyyépy9pyyH0 Xpyyyyyyyyyyùx`€˜ ¨pyy‰p ¹pyyyép9`p‰pyyH0Ppyyyÿyyyyyyy y`€˜ ¨pyy‰pù¸ 8HXhxˆ˜¨¸ÈØè(ðÈ@ðø(ðøøˆH0Pðøøøøøøøøøøøøøøøøèx`€˜ ¨ðøøøø¸ˆðøˆ¸ðøøøøøø(ðØðø8ðøøˆH0Pðøøøøøøøøøøøøøøøøèx€˜ ¨ðøøøøÈˆ  ( 8(@H8@H°@HHHHH(@(@HHHH ( 8HXhxˆ8˜˜˜˜˜˜(˜˜˜˜ˆH0P 8HXhxˆ˜¨¸ÈØèø)9IYi y€˜ÿ pyy)‰P À€¸pypypipy9pyyHPpyyyyyyyyyyyp˜ ¨pyy)‰P@ 0@€¸P0 0 00 8H@00@HHHHH(@HHHHH8@HHHHHHH8 8HXhxˆ˜ˆHP 8HXhxˆ˜¨¸ÈØèø)9IYi ip`˜0¨pyy)‰P00 €0€¸0 000 `00ÿ P00p)p90p¹pyyHPpyyyyyyyyyyy`˜   8HXhxˆ˜¨¸È˜ˆP00 P0€¸p0 ( (0 080000880(0 ( 8HXhHpxxX0pxxxhpxxxxxx88@P 8HXhxˆ˜¨¸ÈØèø)9IYiy`˜@¨pyy)‰P00 @00p¸p0PP0 `000P0pipÿ90p¹pyiHPpyyyyyyyyyyyP˜@¨pyy9‰P       ((° ((  (         ((( (  8HXhx€ˆˆ( 8( 8HXhx8€ˆˆˆˆˆHHP 8HXhxˆ˜¨¸ÈØèø)9IYi y`@˜P¨pyy)‰`@@0 `¸ (00  00ÿ 88@ 0 @HHHHH( 8HXhxˆ˜¨¨°¸¸¸xH0P 8HXhxˆ˜¨¸ÈØèø)9IYi yP˜P¨pyy)‰pé¸pyyy)py9pyYH Xpyyyyyyyyyy yP˜P¨pyy‰pù¸pyyy)py9pyI8@ Xpyyyyyyyyyyùx`˜@¨pyy)‰pù¸pyyy)py9 P €à a¡á!b"á@ €à a¡á!b¢â"c£ã#d¤ä$e¥åãÁAa ‚Âååå$Â¥ãÂÂååå¥dÀåådÀå%ÀÀÿ@Áåååååååååå%äa Âååå$Â¥ãÂååå%eÀåådÀå%À€ AÁåååååååååå%äÁa Âååå$Âeã €à a¡á!b¢â"c£#bÀãããcaÀãã#À@Áããããããããããããããããcãa¡Âãããã##ÂããáÂãããããã#bÀãããcaÀããã`Áãããããããããããããããã£ãÁa Âãããã##Âã#âÂããã£G! 8HXhxˆ˜¨¨°¸¸¸@0X 8HXhxˆ˜¨¸ÈØèø)9IYiyp˜ ¨ÿpyy)‰pù¸pyyyipy9piI XPpyyyyyyyyyy y`˜ ¨ pyy)‰pù¸pyyyipy9pY9@PPpyyyyyyyyyyùxppp@˜0¨pyy9‰p鸰° 8HXhxˆ˜¨¸ÈØè˜ðøø¨ðøØH@PPðøhðøøøø˜ðøøøø¨ðøøÈxppp`@˜P¨ðøøøø(ˆ`ðè¸°ðøøˆðøøø8ðøø˜€ðø˜H@@@PPðøˆðøøøø˜ðøøøø¨ðøøh €@AA…ÁÁÁ@ÁÿAÂBÃCÄDÅÅEÃFÆÂFFFFÃFFFFÆÁFFFÆÂ€Á€ÃFFF‚€FFFÂFFFFFFÆFFFFFFF€FFFFÄAÂBÆFFFFFFB„ÃFÆÂFFFFÃFFFFÆÁFFFÆÂ€Á€CÀÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPG@ÁAÂBÃCÄDÄ€Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÑ€ÁRRRRRRRRRRRRRRRRRÌ€RRRRRRRRRRRRRRRRRÍ@ÿÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑQÒRÓSÔTÕUÖV×WØXÙYÚZÛ[Ü\Ý]Þ^ß_à`áaâbãcädåeæfçgh׀€€€Á䀀Â䀀€€ €Á€€Â€ã€€€Â€ @A€€€€Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIŀ€€JJJÅ€€Á€ÁÁ€JJJÅ€ÁÁ€€Á€JJÊÄ€Á€€ÁÁ€JJÊÄ€Á€Á€€Á€JJÊÄ€ÁÁ€Â€JJJJJJJJJÉ€€Á€Â€ÁJJÿJÄ€€AÀ€€€@ÁAÂBÃCÄDÅÅÀ€Á€€ÁFFFFFƀ€€ÁFFFFFÆÁ€Á€ÁFFFFFÆ€€Â€ÁFFFFFFFFFFFFFFFÆÃ€Á€€€Á€ÁFFFFFÅ€€Á€ÁFFFFFÆÁ€Á€€ÁFFFFÆÅ@AÁÁ€Á@ÁAÂBÃCÄDÅÅÂÁÁÁ€ÁFFFFÆÅÁ€€€Á€ÁFFFFFFFFFFFFFFFÆÃ€Á€Á€€ÁFFFFFÅ€Á€Á€€ÁFFFFÆÅ€Á€Á€€ÁFFFFFÅ€ÿ€Á€ÁFFFFFÅ€ÁÁÁ€ÁFFFFFE@€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰ƒƒƒ”””Šƒƒƒ”””Š„ƒƒ”””‰…„ƒ”””‰„€‚‚€‚ƒ„…†‡ˆ‰Š‹ƒ„ƒƒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‡ƒƒ‚ŒŒŒŒŒ‹ƒƒ‚ŒŒŒŒŒŠ†ƒŒŒŒŒŒ‰…†ŒŒŒŒŒ‰ˆƒŒŒŒŒŒ‰…ƒ‚ŒŒŒŒŒŒŒŒŒŒÿ1bĈ#C€           !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}ƒ…‡‰‹‘“•—™›Ÿ¡£¥§©«­¯±³µ·¹»½¿ÁÃÅÇÉËÍÏÑÓÕ×ÿÙÛÝßáãåçé !#%')+-/13579;=?ACE&FGGGGGGGGGGGGGGGG FGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGG   !#%')+-/13579;=?ACE FGGGGGGGGGGGGGGGGFGGG@GGGGGGGGGGGGGFGGGGGGGG5jÔ¨Q£F5jÔ¨Q£Fš(;openacs-5.7.0/packages/acs-templating/www/doc/time3/0000755000175000017500000000000011724401447022077 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/time3/stage00.gif0000644000175000017500000003117607253523117024042 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠŠÿŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠ€‚ƒ„…†‡ˆ‰Š‹‡€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠˆ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰„ŠŠ‚ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠ‰ŠŠŠŠ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ†€‚ƒ„…†‡ˆ‰Š‹Œ‰€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•––€‚ƒ„…†‡ˆ‰Šÿ‹Œ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”„•••‚•••••••••Ž€‚ƒ„…†‡ˆ‰Š‹†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—‚€‚ƒ„…„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹€‚ƒ„…††€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—‰„ˆ–€‚ƒ„€‚ƒ„€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜ŒƒŒˆˆ€ÿ‚ƒ„„€‚ƒ„……€‚ƒƒ€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜‚ƒˆ‚ƒ†…€‚ƒ„€‚ƒ„…†‡ˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™ˆƒ‡‚ƒ€‚ƒ„€‚ƒ„…†‡‡€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘ÿ’“”•–—˜™ƒ€‚ƒ„„€‚ƒ„…†‡ˆ‰‰ŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ„€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™€‚ƒ„€‚ƒ€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹„€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™–‚„€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™ÿš„€‚ƒ€‚‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‹€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŒŒŒŒŒ…ŒŒŒŒŒŒŒŒŒ†€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‚€‚ƒ„€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹Œ‚‡ƒ€‚‚€‚ƒ„…‚†††††††††††††ÿƒ††††††††††…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‚…€‚ƒ€‚ƒ„…‚€‚‚€‚ƒ„…†‡ˆ‰Š‹Œ…‚‡‚‡ƒ„ˆ„†Œ5jÔ¨Q£F*$, $ $$ $$ $ÿ,4BFJNRVZ^bf:hjjjjjh  """""""&*ÿ.26:>BFJNRVZ^bf2 hjjjjjhj6hj*hjjjjjjjjjjjj hjjjjjhj6hj*hjjjjjjjjjjjb hjjjjj"hhhj&hjjjjjjjjjҤɠ€‚‚‚@ÁAÂBÃCÄDÅEÆFÇGÈÈÆIÄÀÁA@ÁAÂBÃÃÁDDDDDDÄB@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÅÂMMMMMMÇMÁÂÍÂMÍDMMMMMMMMMMMMÊÁ‚MMMMMÍÿÇMÍÆMÍDMMMMMMMMMMMÍÉÂMMMMMMÈMÍÆMÍDMMMMMMMMMMMš",($,4BFJNRVZ^bV dffffff&dddf*dfffffffffffR dffffff2df>df&dfffffffffffR dffffff6dd&df&dfffÊ”)S¦L™2e¢h @p°Ðð1Qq‘±Ññ2Rr2`21 @0`’1`rrR`rrrrrrrrrrrrrrròq`  `rrrrrrrrr2`21 @0`’1`rrR`rrrÿrrrrrrrrrrrròq `rrrrrrrrr `21 @0`’1`rrR @ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌÈ€‚ÌÌÌÌÌÌÌÈ€L€€€€ÌÀÌLD‚ÌÌÌÌÌÌÌÌÌÌÌLÈÁ‚ÌÌÌÌÌÌLÉ€ÌÌÇ€ÌLD‚ÌÌÌÌÌÌÌÌÌÌÌLÈÁ‚ÌÌÌÌÌÌÌÉ€ÌÌÇ€ÌLD‚ÌÌÌÌÌÌÌÌÌL™2=4P 8HXhxˆ˜¨¸ÈØèø)9Y@i`@¹@I)I@IIIIIIIIIIIIIIé80PP@IIIIIIIIù@y@@Éÿ@II@IIIIIIIIIIIIIIé8 X@IIIIIIII@‰°°p@II@II‰%J”(Q¢D‰%J”($,4BFJNRV&XZVXZ&XZZZZZZZZZZZ XZZZZZZZZZVXZVXZ&XZZZZZZZZZZZ XZZZZZZZZZÿZ XX.XZ&XZZZZZZZZZZV"&*.26:>BFJNRV6XX*XZ&XZZZZZZZZZZV$XZZZZZZZZZZXX&XZ"XZZZZZZZZZZVXZZZZZZZZZZXZVXZ"XZZZZZZZZZZV"&*.26:>BFJNRVFXZVXZ"XZZZZZZZZZZR XZZZZZZZZZZX*X*XZ"XZZZZZZZZZZN ÿXZZZZZZZZZZXX&XZ"XZZZZZZZZZZJ$"&*.26:>BFJNRVJXX&XZ"XZZZZZZZZZZF$XZZZZZZZZZZX """"""&*.26:>BFJNRVZ \^^^^^^^^^V\\6\^\^^^^^^^^^^ \^^^^^^^^^^\^N\^\^^^^^^^^^^  $\^^^^^^^^^^\^N\^\ÿ^^^^^^ºtéÒ%A€  !#%')+-,-+,- ,---------- ,----------,-+,- ,---------- ,----------,-+,- ,---------- ,------Y²dÉ’#@€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹ˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‰Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ƒ‹‹‹‹‹Š‹‹‹‹‡‹‹‹‹‹‹‹‹‹‹‹‹‹ÿ‹‹‹‹‹‹‹‹‹ˆˆ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹-Z´hÑ¢E… "&*.26:>BFJNRVRXZZZZZZZZZZNXX.XZXZZZZZZZZZZ""&*.26:>BFJNRVZ&\\*\^\^^^^^^^^^N\^^^^^^^^^^>\\*\^\^^^^^^^^^N\^^^^^^^^^^B\\*\^\ÿ^^^^^^^^^B"&*.26:>BFJNRVZF\^N\^\^^^^^^^^^>\^^^^^^^^^^N\ \"\^\^^^^^^^^^6 \^^^^^^^^^^N\\&\^\^^^^^^^^^. "&*.26:>BFJNRVZN\ ,( \^\^^^^^^^^^* \^^^^^^^^^^R\,  \^\^^^^^^^^^& \^^^^^ÿ^^^^^^\,  "&*.26:>BFJNRVXZZZZZZZZZZZ2XN ( ""&*.26:>BFJNRVXZZZZZZZZZZZ" $$$&&&&"&*.26:>BFJNRV XZZZZZZZZZZZ6XN  (XZXZZZZZZZZZ: XZZZZZZZZZZZBXRÿ,XZXZZZZZZZZZ6XZZZZZZZZZZZF $,4FNV^fnv~† X H $,4BFJNRVZ^bfjnrvVtxx^xÿz xzzzzzzzzzzzzzzpxx^xz xzzzzzzzzzzzzzzpxx^xzxzzzzzzzzzzzzzz 8HXhx pxxx8pxxxxxxHHpxxxxxxxXX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙiÐà)àiIàé)XàééééééééééééééyàéYàiIàé PPàééééééééééééééyàéYàiIàé Pàééééééééééééé鉠`à ÿ 8HXhxˆ˜xH ¨¨¨¨¨P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙy°@à)àiIàé Pàéééééééééééééé‰À°°pàiIàé Pàéééééééééééééé‰àÉ àiIàé PàééééééééééééÉ“'D€     !#%')+-/13579;/<  ÿ  !#%')+-/13579;     !#%')+-/13579;1<<- <= <==============<<- <= <==============< <- <= <=======yòäÉ“'Ož $,4BFJNRVZ^bfjnrvrx,( xRxjxzzzzzzzzzzzzzz:x(   xRxjxzzzzzzzzzzzzzz:x(  "$&&&&& ÿ"&*.26:>BFJNRVZ^bfjnrvV     """""  """""""&*.26:>BFJNRVZ^bfjnrvvx(  "&(****"&*.26:>BFJNRVZ^bfjnrvvx2 xRxjxzzzzzzzzzzzzzz:x6 xRxjxzzzzzzzzzzzzzz:xzxRxjxzzzÿzzzzzzzzzzz: 8HXhxˆ˜¨¨°¸¸¸XH°¸¸¸¸(8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙÙàéYà9Ià©9PàééééééééééééééùàéYà9Ià©9PàééééééééééééééùàéYà9Ià©9PàééééééééééééééùàéYà9Ià©9P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÀà9à9Ià©YPàééééééééééééééù°@à)à9Ià©Yàéééééééééÿééééé  `à à9Ià©Yàéééééééééééééé àéY 8HXhxˆ˜HH ¨¨¨¨hX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé ðù9ð)Ið‰9Pðùùùùùùùùùùùùùù ð ð ð)Ið‰9Pðùùùùùùùùùùùùùù À@ðð)Ið‰Yðùùùùùùùùùùùùùù)À@ðð) ˆ@p°Ðð1Q±@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS0@0@p0@p°Ðð0ÿ€ñ°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS0€3à³0àS’à³àóóóóóóóóóóóóóóS0àós0àS’àór àóóóóóóóóóóóóóóS0àós0àS’àór àóóóóóóóóóóóóóóS0àós0àS’àór°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS0àós0àS’àó²àóóóóóóóóóóóóóós0àós0àS’àó²àóóóóóóóóóóóóóós0àós0àS’àó²àóóóóóóóóóóóóóósÿ0àós0àS’àÓ² àóóóÓ§OŸ>}úôéÓ§OŸ $,4<  8<<<, 8<<<<<<$8<<<<<<$,$,4BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏ,<ÐÓÓ£Go @ÁAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€ß€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€Á€Ã€ÑÑÑÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚ˆ„ƒ„£££££££££££££££££‰‚ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time3/stage02.gif0000644000175000017500000002703707253523117024045 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠ†ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆÿŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‚ŠŠŠŠŠ…‰ŠŠ†ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆ"&*.202222202222*0222$02 022222022222022222022222022222022222"&*."&" "&*.26:>BFJNRVZ^bfjnrvzv"&*.ÿ 02222"&*.26:>BFJNRVZ^bfjnrvz"&*.246666"&*.26:>BFJNRVZ^bfjnrvJ      "&**"&*.26:>BFJNRVZ^bfjnrJ    "&**"ÿ&*.26:>BFJNRVZ^bfjnr"&*&"&"&*.26:>BFJNRVZ^bfjnB"&*.       "&**"&*.26:>BFJNRVZ^bfjn"&*. ÿ  "&(*****"&*.26:>BFJNRVZ^bf6"&"&*. "&*,....*"&*.26:>BFJNRVZB"&*.""&*.   "&**,...ÿ............""&*.2"&&"&* "&*     "&*.26:>B&""&*.26""&*.26:"&*.26:>:@BBB@BBBBBBB"&*.2&"&ÿ"&*.26"&"&*.26:>BDFF:DFFFFFFDFB"&""&*.26:>B"DFFFFFFFFFFDFF:DFFFFFF"&""&*.26:>BFJN "&*.26:>BFJNP"P6PRRRR> PRRRRRRRRRRN "&*.26:.4 <>><2ÿ<> <>>>>>><>>>>>>>>>>>>>"&*.26:>" 4 @BB@*@>@BBBBB>@BBBBBBBBBBB"&*.26:>BF( DFFDFF:DFFFFF DFFFFFFFFF"&*.26:>BFJ&$ 4"&**,...ÿ.....&,.............."&*.26:>BFJN2  "&* ,.,..,........""&*.26:>BFJ"&*.26:>BFJNN$  PRFP"P.PRRR" "&*.26:>BFJNRVZ^bfjn$ prppprNÿ "&*.26:>BFJNRVZ^bfjn  "&*,.,.&,.....,." "&*.26:>BFJNRVZ^bfjnrvvtx xz "&*.26:>BFJNRVZ^bfjnrvzxzxz x& xzzzzzzzzzzzzzzFx x xz x& xzzzzzzzzzzzzzzFpxxÿz x& xzzzzzzzzzzz^  "&*,.. "&*.26:>BFJNRVZ^bfjn , pbh """""" """ "&*.26:>BFJNRVZ^bfjn  pbpp"prp. prrrrrrrrrrrrr ÿ 4"&**,....,.." "&*.26:>BFJNRVZ^bfjn:  "&* ,.  "&* ,.." "&*.26:>BFJNRVZ^bfjn:(  prp$  prp: prrrrrrrrrrrrn, prp ÿ pnp> prrrrrrrrrrâÄi AA@ÁAÁ‚€Á‚‚@ÁAÂBÃCÄDÅÁ€ÅEÀÁ€Ã€ÁÄ€€DÀÁÁA@ÁAÂBÃCÄDAEEEEÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNNÀÁÁA@ÁAÂBÃÃÁ€Ä€Á€Ã€Á€ÃDDDDDDCDDDDDÁ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÀOÅ€Á€Ã€Á€Ã€ÏK‚ÏÅÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÀNÀAA@ÁAÁÿ€Â€Á€ÁÂÁ@ÁAÂBÃCÄÄDEEEEÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÃÎǀ€€Á€€Ä€ÏK‚ÏÅ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOĀ΀€€€O€€ÏK‚ÏÅ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÄ΀Ï€ÏK‚OÅÁÏÏÏÏÏÏÏÏÏÏÏOŸ>}B(@p°Ðð0@p@p°Ððp0±Q°@p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó1àós0àÓ’às±@pàóóÿóóóóóóóóóóóó1àós0àÓ’às±``àóóóóóóóóóóóóóó1àS0à3àÓ’às±`àóóóóóóóóóóóóóóS1@30@p@p°Ððp0±Q°`@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS1€3€0à3à³’€às±`àóóóóóóóóóóóóóóS1àós0à³’à“±àóóóóóóóóóóóóóós1àós0à³’às±`àóóóóóóóóóóóóóós1à à à³@p°ÐðѰ`@p°Ððÿ1Qq‘±Ññ2Rr’²Òò3Ss“³Ós1€3€0à3à³’às±`àóóóóóóóóóóóóóós1€3€0à3à³’às±`àóóóóóóóóóóóóóós1@0@p0@p°Ðð0‘  `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ós1€3à³0à“’às±`àóóóóóóóóóóóóóós1àós0à“’às±`àóóóóóóóóóóóóóó“1 3@0à à“’às±`àóóóóóóóóóóóóóó“1€3@00@p°Ððÿp0q  `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“1€3 @0à3à“’àS±`àóóóóóóóóóóóóóó“1€3 @0à3à“’àS±`àóóóóóóóóóóóóóó“1 3@0à à“’àS±`àóóóóóóóóóóóóóó³ @ÁAÂBÃCÄDEÅ€ÅÅÅÅC‚ÅÅÅÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÆ€Î€€ÏÁ€ÏI‚OÅ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆÎ€Á€Ï€ÏI‚OÅÿ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆÎ€Á€Ï€ÏI‚OÅ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏF€   !#%')+-/13579;=:>>' > >??????????????>?>' > >??????????????>?>' > >??????????????4     ÿ!#%')+-/13579;=6>>' > >??????????????8>' > >??????????????>>' > >?????????}úôéÓ§G€     !#%')+-/13579;=>    !#%')+-/1357ÿ9;=     !#%')+-/13579;=>>' > >??????????????>>' > >??????????????> >' >  !#%')+-/13579;=!>?>' > >??????????????!4>>' > >????????????ÿ??!4> >% > >??????????????!4> "&(*** "&*.26:>BFJNRVZ^bfjnrvzBh||J|& |~~~~~~~~~~~~~~Bh  """"" """" "&*.26:>BFJNRVZ^bfjnrvzB|~|J|&|~~~~~~~~~~~~~~Fl """"" """""ÿ&*.26:>BFJNRVZ^bfjnrvzFh||J|&|~~~~~~~~~~~~~~Fh||J|" |~~~~~~~~~~~~~~Fh||J|" |~~~~~~~~~~~~~~Fh  """"" """ "&*.26:>BFJNRVZ^bfjnrvzF|~|J|" |~~~~~~~~~~~~~~Fl||J|" |~~~~~~~~~~~~~~Fh||J|" |~~~~~ÿ~~~~~~~~~Fh|"&(**& "&*.26:>BFJNRVZ^bfjnrvzFh||J| |~~~~~~~~~~~~~~Jl """"" """ "&*.26:>BFJNRVZ^bfjnrvzJ|~|J| |~~~~~~~~~~~~~~J|~|J| |~~~~~~~~~~~~~~J|~|J| |~~~~~~~~~~~~~~J|~|J|ÿ "&*.26:>BFJNRVZ^bfjnrvzJ|~|J| |~~~~~~~~~~~~~~J|~|J| |~~~~~~~~~~~~~~J|~|J| |~~~~~~~~~~~~~~Jx||J" "&*.26:>BFJNRVZ^bfjnrvzJx||J| |~~~~~~~~~~~~~~Jx||J| |~~~~~~~~~~~~~~Nx||J| |~~~~ÿ~~~~~~~~~~Nx||J"$,4BFJNRVZ^bfjnrvz2ÿ     """"" """ "&*.26:>BFJNRVZ^bfjnrvzRx(  "&(** "&*.26:>BFJNRVZ^bfjnrvzR|. |J| |~~~~~~~~~~~~~~R|2 |J| |~~~~~~~~~~~~~~R|~|J| |~~~~~~~~~~~~~~¢(@p°Ðð1QQ1`qqq±`qqq°ÿ@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³2àós0àS’à³°àóóóóóóóóóóóóóó³2àós0àS’à“°`àóóóóóóóóóóóóóó³2àós0àS’à“°`àóóóóóóóóóóóóóó³2àós0àS’à“°`@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³2€3 àS0àS’à“°`àóóóóóóóóóóóóóó³2`3€0à àS’à“°àóóóóóóóóóóóóóóÓ2@3À0à3àS’à“°àóóóóóóóóóóóóóóÓ2àós0ÿ@p°Ðð1‘@QQ±°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓÓ2àós0à3’à³°àóóóóóóóóóóóóóóÓ2à à à3’à³°àóóóóóóóóóóóóóóÓ2€3€0à3à3’à³°àóóóóóóóóóóóóóóÓ2€3€0à3à3’@p°Ðð±@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓÓ2@0@p0@p°Ðð0‘q°`@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓÓ2€3à³0ÿà3’à“°`àóóóóóóóóóóóóóóÓ2àós0à3’à“°àóóóóóóóóóóóóóóó2àós0à3’à“°àóóóóóóóóóóóóóóó2àós0à3’à“°àóóÓ§OŸ>}úôéÓ§OŸ>] 8HXhxˆ˜¨¨°¸¸¸HH°¸¸(X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéyðù9ðIðIXðùùùùùùùùùùùùùùyðù9ðIðIXðùùùùùùùùùùùùùùyðù9ðIð9XPðùùùùùùùùùùùùùùyÀ ð)ðÿIð9X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé‰À ð)ðIð9Xðùùùùùùùùùùùùùù‰À ð)ðIð9Xðùùùùùùùùùùùùùù‰À ð)ðIð9Xðùùùùùùùùùùùùùù‰À  8HXhxX€ˆˆˆˆˆH€ˆˆˆPP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé‰ðù9ðIð)X0ðùùùùùùùùùùùùùù‰pððIð)X0ðùùùùùùùùùùùùùù‰ Pð ÿðIð)Xðùùùùùùùùùùùùùù™°0° 8H@H 8HXhxˆ˜8H ¨¨8X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™À°€0pðIð)Xðùùùùùùùùùùùùùù™Ð°0°pðIð)Xðùùùùùùùùùùùùùù™ð©0 € 88 8HXhxˆHH˜˜X8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé  88 8HXhxˆX0˜˜˜˜8H˜˜XÿXP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™ð©0€ ðIð Pðùùùùùùùùùùùùùù©ð¹@ °ðIð Pðùùùùùùùùùùùùùù©ðÉP  ( 8 8HXhxˆ˜8H ¨¨0P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé©ðù9ðIð9Pðùùùùùùùùùùùùùù©ðù9ðIðYðùùùùùùùùùùùùùù¹ ðyðIðYðùùùùùùùùùùùùùù¹ ðyÿðIðYðùùùùùéÓ§OŸ>}úôéÓ&@€‚ƒ„…†…€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆˆ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž›šŸ‡Ÿ‘žŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ›šŸ‡Ÿ‘žŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ›ŸŸƒŸ‘žŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ›ŸŸƒŸ‘€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž›š†ŸŸ‘ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ››„ÿŸŸžŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸœœŸ‚ŸžŸŸŸŸŸŸŸŸŸ‹‚‘‡—€€‚ƒ„…†…‡‡‡‡…‡…ƒ‡‡‡„‡‡‡‡‡„‡‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡…‡‡‡‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—ƒ‘•ˆ‚˜•‹‰‰˜˜‘˜˜‘˜—˜…˜˜˜˜˜˜˜˜˜˜˜˜…ƒƒ‚‚ƒƒƒ‰…‚‰‚€ÿ€‚ƒƒ„ƒ‚ƒ‚ƒ„ƒ„„„„„„‚„„„„„„ƒ„„„„„„„„ƒ€‚ƒ„…†‡ˆ‰‚ŠŠ‚€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—…‚ƒƒ…ƒ‚ƒˆ„ƒ‚‡ƒ‚…‚ƒƒ‚‰…ƒ‚‚…‚ƒƒƒƒ˜€€‚ƒ„…†ÿ…ƒ‡‡‡‡†‡‡‡‡‡‡…‡‡„€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—Ž…ƒ€‚‚€‚‚ƒƒƒƒƒƒƒ‚ƒƒƒƒ‚ƒ‚ƒ‚ƒƒ€‚‚€‚ƒƒ„ƒƒ„‚„ƒƒ€‚‚‚€‚ƒ„…††‡‡‡…ƒ‡‡‡‡†‡‡‡‡‡‡…‡…€‚ƒ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—Ž…ƒ………ƒƒ‚ÿ‰„ƒ‹…ƒƒƒ‚‚…ƒ‰…ƒƒ…ƒ‡ƒˆ˜‚˜‚ƒ˜Š˜—Š’˜˜˜˜˜˜˜˜0a„I €€€€@AÁ€Á€Á€A€€Á€Á€€ÁÁÁÁ€A€€Á€€ÁÁAÁ€Á€€Á€Á€€€Á€€AÁ€AÁÁ€€ÁÁÁ€AÁ€Á€Á€€AÁÁ€€€ÁA€€Á€AÁ€Á@ÁAÂBC€ÃÃÃBÀÁAA@ÁAÂBÃÃÁDDDDÄCÃDÄÁ@ÁAÂBÃCÄDÅEÿÆFÇGÈHÉIÊJËKÈ€€Á€ÁÁ€€€Á€€Á€ÁÁ€€Á€ÁÁ€€€Ä€Â€€ÁÆ€€Á€ÁÁ€€€€ÁÁ€€€Á€€€Á€€Ä€€€Á€€Á€€ÁÀ€€Ã€€€Á€€€Á€À@ÁAÂBÀÃÃÃÃÃÃÃÃCÁ€ÃÃÃÃÃÃBÂÃCAÀÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌÌÄ€ÁMÍÁ€ÁMMÍÉMÍÆÍJÁAÀÁAÂB@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌÌÈ€€MÍ€€MMMÊÿMÍÆÍJÁ€‚‚MMMMMMMMMMMMMMMMMMMÌMÍÆÍJÁ€MMMMMMMMMMMMMMMMMMMÍMÍÆÍJ€€MMMMMMMMMMMš4iÒ¤I“&Mš $,4FNV^fnv~^h`pX $,4BFJNRVZ^bfj  lfll&lnn lV lnnnnnnnnnnnn*  4ÿ"&**,......,..."&*.26:>BFJNRVZ^bfj&  "&* ,.  "&*.2466& 466666666666666666666666666"(  466646 $  466666466"466666666666666666666666666*ÿ       "&*.2466&466666666666666666666666666*  "&*,.   "&*.022."&*.26:>BFJNRVZ^bfjnrn    """"""""" """""&*.ÿ26:>BFJNRVZ^bfjnrvx.  xzRxJxzzzzzzzzzzzzz^t   "&*.2466*"&*.26:>BFJNRVZ^bfjnrv"p8  xzJxRxzzzzzzzzzzzzz^tx xzJxNxzzzzzzzzzzzzz^pxxzJxNxzzzzzzzzzzzzz^ $,4< $,4< @DDDDDÿDDD,$ @DDDDD($,4>% > >?????????????? >?>% > >?????????????? 2>>% > >???ÿ??????????? 4     !#%')+-/13579;= 6>% > >?????????????? 8>% > >?????????????? :>% >  !#%')+-/13579;= >    ÿ!#%')+-/13579;;     !#%')+-/13579;=>>% > >??????????????>># > >??????????????>     !#%')+-/13579;=>?># > >?????????ÿ?????>?># > >??????????????4>># > >??????????????4>    !#%')+-/13579;=4    !#%')+-/13579;=4>># > >??????????????4>># > >??????????????>ÿ?># > >??????????????>? $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GOW_gow‡—ŸçX x  §§GÞ&@€‚ƒ„………„ÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢‹‰„ƒ…£££££££££££££££££Œ‹„ƒ„£££££££££££££££££Œ‹„‚†£££££££££££F5jÔ(F€   !#%')+-/13579;=?ACEFGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGGGGGGGGGGG';openacs-5.7.0/packages/acs-templating/www/doc/time3/stage04.gif0000644000175000017500000002670207253523117024045 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠÿŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠˆŠŠŠŠŠ…‰ŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ€€‚ƒ„…†‡ˆ‰Š‹„ŒŒŒŒŒ‰ŒŒŒŒ‡€‚ƒ„…†‡‡€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠ…ŠˆŠŠŠŠŠƒ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸž€‚ƒƒ€‚ƒ„…ÿ†‡ˆ‰‰‰‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ‚€‚ƒ„…†‡€‚ƒ„…†…€‚ƒ„……€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž—ƒ‹ˆ‰€‚ƒ„ƒ€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž—€‚‚€‚ƒ„‚…ƒ€‚ƒ„…€‚ƒ„…†…€‚ƒ„‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›œž•‚ƒ‚€‚ƒ„…†€‚ƒ„„„„„„„„„„‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŒ€‚ƒƒ€‚ƒ„„€‚‚‚ƒƒƒ€‚ƒ‚€‚ƒ„…†‡ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ˜€‚ƒ‚€‚ƒ„€‚ƒ€‚ƒƒƒ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰…ŠŠŠŠŠŠ…ÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ€‚ƒ„€‚ƒ„…†‡†€‚ƒ„…€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š››€‚ƒ„…†‡€‚ƒ„…†‡ˆ€‚ƒ„ƒ€‚ƒ„…ƒ‚ƒ……………………………‚€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™‚€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡‚€‚ƒ€‚ƒ„…†‡ˆ‰…€‚ƒ‚€‚ƒ„…†„ÿ‡ƒ‚‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜…€‚ƒ„…†€‚ƒ„…†‡ˆƒ€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹‡€‚ƒ„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ†…‡€‚ƒ„…†‡€‚ƒ„…†‡…€‚ƒ„…†‡€‚ƒ„…†‡ˆ‰Š†€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‹ŒŽ…‡€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ‡€‚ƒ„…ƒ€ÿ‚ƒ„…†‡ˆ‰Š‹Œ‚€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽŠ‘‘‘Ž‘‘‘‘‘‘‘‘‘‘€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ…€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡ˆ‰Š‹Š€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‚’Š’’’’’’’’’’‰€‚ƒ„…†‡ˆ‰Š‹ŒŠ€‚ƒ„…†‡ˆ‰Š‹Œ‹€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‹Œ„ˆŽŽŽŠŽ„ŽŽ„ŽŽŽŽŽ€‚ƒ„…†‡ˆ‰Š‹Œ‰€‚ƒ€‚ƒ„…†‡ÿˆ‰„€‚ƒ„…†‡ˆ‰Š‹ŒŽŒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‰ƒˆ‡‹†Š‹‡€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‰‚Š‚ƒ——†——“——”———Š€‚ƒ‚€‚ƒ‚€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜Ž‰‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹Š‹‹‹‹‹‹‰€‚ƒ€ÿ‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™„ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡‹‹‹‹‹‹‹‹‰‹‹‹‹‹‡€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™–‰ƒƒšš…š‚‚š…ššŒšš‰‚šššššššššššššš‰‚ƒšš…š‚‚š…šš‹šš‡ššššššššššššš™€‚‚€‚ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹ÿ‹†‚‹‹‰‹‹‹‹‹‡‹‹‹‹‹€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒž‚žžž—€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžž…žžž˜žžžžžžžžžžžžžžž…ž‚ž‚žžž–žžžžžžžžžžžžžžž†œ„žžžž•žžžžžžžžžžžž‹ƒ€‚€‚ƒ„‚…ƒ…………………………‚……………ƒ„………………ÿ…………………………………………………………€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š–‚ƒ‹ˆ›™š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆ„ˆˆˆˆˆˆ‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š–†ˆ‚ƒ›™››‰››†›–››››››››››››››ƒˆ‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹„‹‹‹‹†‚€‚ƒ„…†‡ˆ‰Š‹ŒÿŽ‘’“”•–—˜™š›ƒƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰Š„‹‹‹‹†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›ƒŠƒƒœœœ‰ˆƒ‡œœ‚œ—œœœœœœœœœœœœœ‹‚ƒœœœ‚‡ƒ‡ƒ‡œœ‚œ—œœœœœœœœœœ8qâ P  €à `A@`AA €à a¡á!b¢â`Àâÿ¢a@€`ÀaÀ`b@@"`€àà €à a¡á!bb!¢¢¢¢â@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§$`€àà €à a¡áá`@bÀ`ÀaÀ`Àa""""""¢ """""¢à@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§f€çbÀ`ÀaÀ`Àa€''çä@§§§§§§§§§§§§§§'c@'`€  €à `@a@€`À`á` €à a¡á!b¢¢ Áâââ¢á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦ÿæ&gçfg€c@a@À`@@b€ç&'å@§§§§§§§§§§§§§§'c@g@@@€§`€§&'å@A§§§§§§§§§§§§§§'cg€§a€§&'å@§§§§§§§§§§§'Ož<5 8HXhx 8 8HXhx8€ˆˆˆˆˆxH@€ˆˆˆˆˆ00P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙÉàéYà™IàI9PPàééééééééééééééÙàéYà™Ià99PPàééééééééééééééùà9à à‰I@à99ÿPàéééééééééééééé   8 8HXhx8€ˆˆˆˆˆhH€ˆˆˆˆˆ0P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé À@ððiIð)90PPðùùùùùùùùùùùùùù ðù9ðiIð)9Pðùùùùùùùùùùùùùù)ðù9ðiIð)9Pðùùùùùùùùùùùùùù)ð ð (@p°Ðð1‘@QQQ1q @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS0€3€0à3àÓ’à3r` àóóóóÿóóóóóóóóóós0€3€0à3àÓ’à3r àóóóóóóóóóóóóóós0@0@p0@p°Ðð0±q @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ós0€3à³0àÓ’à3r àóóóóóóóóóóóóóós0àós0àÓ’àr  àóóóóóóóóóóóóóós0 3@0à àÓ’àr àóóóóóóóóóóóóóó“0€3 @p°Ððp0±ñp @p°Ðð1Qq‘±Ññ2Rÿr’²Òò3Ss“³Ó“0€3 @0à3àÓ’àr àóóóóóóóóóóóóóó“0€3 @0à3à³’à3r àóóóóóóóóóóóóóó³0 3@0à à³’àr àóóóóóóóóóóóóóó³ @ÁAÂBÃCÄDEÅ€ÅÅÅED‚ÅÅÅÅÁ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏ€΀€ÏÁ€ÏJ‚OÈ€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÂ΀Á€Ï€ÏJ‚OÈ‚‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÂ΀Á€Ï€ÏJ‚OÈ‚ÏÏÏÿÏÏÏÏÏÏÏÏÏÏÏOC@€‚ƒ„…†‡‚‡‡‡‡ƒ‡‡‡‡‡‡‡ƒ‡‡‡‡‡‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž†ŸŸ•ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ†ŸŸƒŸ•ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ†ŸŸƒŸ•ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ‡š†€‚ƒ„…†‡ƒˆˆˆˆˆˆ„ˆˆˆˆˆ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž‡›„ŸŸ•ŸŸŸÿŸŸŸŸŸŸŸŸŸŸŸŸŸ‡œ‹‹‡Ÿ•ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ‡Ÿ‹‰ŠŸ•ŸŸŸŸŸŸŸŸŸŸŸŸŸ>}útP €à a¡á!baÀ`Àa@¢`@bbbbâ!AbbbbâÀ@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çaÀ§bÀ`Àa@@@"`€àà €à a¡á!""Abbbbâ@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&gg'`€àà €à a¡á!baÀ`ÀaÀ`Àa@bbbbâ!Abbbbâÿ@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§'bÀ§bÀ`ÀaÀ`ÀaÀg%Á§ã@Áçççççççççççççç'bÀçb@a@€`À`ÀaÀ'%Áçã@Áçççççççççççççç'bÀ'c@a@À`@@bÀ'%Áçã@Áççç§OŸ>}úôéÓ§OŸ>! 8HXhxˆ˜¨¨°¸¸¸xH°¸¸¸(8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ鉠ðyðIIðù8Pðùùùùùùùùùùùùùù‰  ðIðIIðù8Pðùùùùùùÿùùùùùùùù‰  ðIðIIðù8Pðùùùùùùùùùùùùùù‰   8HXhxx€ˆˆˆˆˆ8H€ˆˆˆˆX8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™   8( 8HXhx8€ˆˆˆˆˆ8H€ˆˆˆˆX8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™ðù9ðIIðé8Pðùùùùùùùùùùùùùù™°  8 8HXhxH€ˆˆˆˆˆ8H€ˆˆˆˆX8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™ÿ©¹ÉÙé™ `ððIIðéXPðùùùùùùùùùùùùùù™ `ððIIðéXðùùùùùùùùùùùùùù© `ððIIðéXðùùùùùùùùùùùùùù©   8( 8HXhx8€ˆˆˆˆˆ8H€ˆˆˆˆXX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé©ðù9ð9IðùXðùùùùùùùùùùùùùù©°@ð ð9Iðé8Pðùùùùùùùùùùùùùù© `ðð9Iðé8Pðùùùùùùùùùùùùùù© `ðÿ 8HXhxˆ˜XH ¨¨¨XX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé¹ `ðð9IðéXðùùùùùùùùùùùùùù¹°  8 8HXhxH€ˆˆˆˆˆ(H€ˆˆˆˆXX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé¹ðù9ð9IðéXðùùùùùùùùùùùùùù¹ðù9ð9IðÙ8Pðùùùùùùùùùùùùùù¹ðù9ð9IðÙXPðùùùùùùùùùùùùùù¹ðù9ð9IðÙXðùùéÓ§OŸ>}úôéÓ§OŸ ÿ$,4}úôéÓ§OŸ $,4< 8<<<, 8<<<<<<$8<<<<<,$,4}úôéÓ$@€‚ƒ„…†‡ˆ…ƒ‰ˆ€‚ƒƒ€‚ƒ„…†‡ˆ„‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž‹€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‰‰‰‰‰‰‰ƒ‰‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œÿž“ŸŠƒˆŠŸ‘Ÿ‡ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ“Ÿ‹„‚‹Ÿ‘Ÿ†ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ“ŸŒ…‚€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰ƒŠŠŠ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž”ŸŸƒŸ‘Ÿ†ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ”ŸŸƒŸ‘Ÿ†ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ”šŸ‡Ÿ‘Ÿ…ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ”šŸ‡Ÿ‘€‚ƒ„…†‡ˆ€‚ƒ„…†ÿ‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž”š€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž”šŸ‡Ÿ‘Ÿ…ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ•šŸ‡Ÿ‘ŸƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ•ŸŸƒŸ‘Ÿƒ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ•ŸŸƒŸ€    !#%')+-/13579;=+4 >>! > >???????ÿ???????+6>>! > >??????????????-8>>! > >?????????            !#%')+-/1'"*"$*2232-    !#%')+-/1) ÿ2222- "&*.26:>BFJNRVZ^bR        (  dd d&dZ$ `dffffÊ”)S¦L™2Uÿ (0 ( (0800008(00 ( 800 @@H(0 (00( 8HXhx€ˆˆ(0€ˆˆˆ(€ˆˆˆˆxHP8000€ˆˆ(X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰YP0PPP00 @0°00@0 0P00PI 0™iI@8IX™™™™™™™™™™™i00ÿ (0 0000888 0088(000  0800(  0( 8HXhx€ˆˆ( 8( 8HXhx8€ˆˆˆˆxH@8€ˆˆX 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰y 0 0 0  0   0 €0 0@€0 0   I™ùiI08@ X ( 8HXhÿxˆ˜¨¸ÈØèø)9IYiy‰™©90°¹¹¹Ù°¹¹°II08ÀX 8( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©™°¹¹¹é°¹¹°II08pX ( 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéùÙ úH 8@XPPP * úH 80X j úH 8PP z (@p°Ðð1Q@p @p°Ðð1Qq‘±ÿÑñ2Rr’²Òò3Ss“³Óó33 ô‘@p 41 ô‘@p 41 ô‘`` 41 Ô‘@p @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóS3ô2 1Ô‘@° 1Ô0´0Ô0Ô0Ô0´0Ô0@2Ô2 1Ô‘ ` 1Ô0´0Ô0Ô0Ô0´0Ô0@2´2`0à0@p°Ðð1ÿ€ @1@QQQQQQ1@QQQQQ11@QQQQQQ1@QQQQQQ1@QQQQQQ1@QQQQQ11@QQQQQQ1@1@QQQQq0`0à0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Ô@p°Ðð11`0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt´0`0€””””””””””””””””3 €””””””””””””””””T3@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vÿv–¶Öö7Ww—·×÷8Xx˜¸Øø9Yy™¹Ùùz3 €8  8`0@P@p°Ðð1QqQ0 €‘‘‘‘Ñ0@P@p°Ðð1Qq1 `qqqqqQ0 `qqqqqqqqqqq11`0`qqqqq1`0`qqqqq `qqqqq `qqqqq±0`qqqqqñ0`qqqqQ1`0`qqqqq1`0`qqqqqqqqqqqq `qqqqq‘0`qqqqÑ"@€‚ƒ„…†‡ˆ‰Š‹ŒŒŒŒŒ‡ŒŒŒŒŒŒŒŒŒŒŒ†ƒŒŒŒŒŒ†ƒÿŒŒŒŒŒŒŒŒŒŒŒ‹ŒŒŒŒŒ‰ŒŒŒŒŒ†‚ŒŒŒŒŒ‡ƒŒŒŒŒŒ†ŒŒŒŒŒŠŒŒŒŒŒ‡ŒŒŒŒŒ‡ƒŒŒŒŒŒ1bĈ#E€        ÿ  "&*.02222&02222"02222"02222"02222&02222"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏW,<ÿÐÓÓ£Go @ÁAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€Á€Ã€ÑÑÑÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚ˆ„ƒ„£££££££££££££££££‰‚'ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time3/stage05.gif0000644000175000017500000002574307253523117024052 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠƒŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ†ÿŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ…ŠˆŠŠŠŠŠ…‰ŠŠƒŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠ†"&*.26:8::::::88::6$8&8::::::8::::::8::::::"8::::::8::::::88::. "&*.26:>BFJNRVZ^bfjnrvz~‚†2ˆ~ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠvˆ~ˆŠŠŠŠŠŠŠŠŠŠŠŠŠ2 ÿ4  ˆJˆ~ˆŠŠŠŠŠŠŠŠŠŠŠŠŠ2  0  ˆJˆ~ˆŠŠ%J”(Q¢DQD 8HXhxˆ˜¨¸ÈØèø)9II 8HXhxˆ˜¨¨ 8HXhxˆ˜¨¸ÈØèø)9IYi9 H 8HXhxˆ˜¨¸È¨ 8HXhxˆ˜¨¸ÈØ(8 8HXhHX 8HXhxˆ˜¨¸ÈØX 8HXhxˆ˜¨¨°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸˜H 8HXhxˆ˜˜ 8HXhxˆ˜¨¸ÈØèX 8HXhxˆ˜¨¸Èب 8HX808ÿ8 (0000 8HXhxˆ˜¨(°¸¸¸¸¨°¸¸¸¸¸¸¸¸¸¸¸¸HH 8HXhxˆ˜¨¸X 8HXhX8 8HXhxˆ˜¨¨X 8HXhxˆ˜¨¸(800 8HXhxˆ˜¨¸ÈØèˆ808p808008ðøøÈðøøøXðøøøøøøø¸H 8HXH 8HXh88 8HXhxˆ˜¨¸x 8HXhxˆ˜ˆX 8H( 8HXhxˆ˜¨¸ÈØèø)é80€8 80008099099‰099999ÙH@@@ 8 8HHX 8HÿXhxˆ˜¨¸ÈØèøø 8HXhxˆ˜¨¸ÈØèø)9‰8 800 800@I)@IIY@IIIIIiH090ÐX@IIIIIIIIIIIIIIIIIII¹@IIY@IIIIIYH900X 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉiÐÙyÐÙÙÙyH@9 XPPÐÙÙÙÙÙÙÙÙÙÙÙÙÙ¹ÐÙyÐÙÙÙiHð8000@X 8X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉéÀÐIÐÙÙÙIH@à80pXÐÙÙÙÙÙÙÙÙÙÿÙyI@@HÐH€H@Ðy°@Ð9ÐÙÙÙI@@@ð8`XPPPÐÙÙÙÙÙÙÙÙÙÙyI@0H@ÐH€H@Ðy   8 8HXhx8€ˆˆˆˆˆˆˆˆˆˆˆˆˆH@@@€ˆ(8pX 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™II@ H@ H@@ H@@0H@ © ©Ù ©©© H 8H 8HXH800PXPP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©)HH H@@0HÐH 8HXhxX 8H 8HXhxˆ˜¨¨°¸ÿ¸¸¸¸¸¸¸(H@@@°¸880`X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©YH0H (@@@@ 8HXhxˆ˜¨(°¸x°¸¸°¸¸¸¸¸¸¸¨H@@@°¸H80 X 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©iHH0H@0H°¹9°  °I°¹¹ I 8 (P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹HH H@@0H°¹9°  °I°¹¹¹H ( 8HXh0000 X 8Xÿ 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©©H ( 8(H@@ H@@ 8HXhxˆ˜¨8°¸h °¸˜°¸¸¸¸¸¸¸(H@°¸H8`X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙÉÐà)àé¹I@@°90@XPPàééééééééééééé¹àéYàé™I@à9@Xàééééééééééééééà)à)àééH 8HH 8HXhx880 XP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙ À@à àéÿéHà¹80XàéééééééééééyXP0XPPÀX€XPàiÀ@à àé¹H@@@à©80PPàééééééééééé‰XP X0X°X€XPài 8HXhX 8 8HXhxH€ˆˆˆˆˆˆˆXH@€ˆˆˆˆ88 XP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©)YP`X€XPP XPP0XP°™° °™°¹ùH°9PP°¹¹¹¹¹¹¹¹¹¹¹¹¹ P€X XPP0XÐX 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸¸ÿ(H°¸¸¸0P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ P0X (PPPP 8HXhxˆ˜¨(°¸x ( 88@H(@H 8HXhxˆ˜¨¸H@°¸¸¸0P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹Y X0XP0X°¹9° €0p°¹ÉH°)9P°¹¹¹¹¹¹¹¹¹¹¹¹¹Y°X XPP0X°¹9°  p0p0p°¹¹H@°)9PP°¹¹¹¹¹¹iÓ¦M›6mÚ¨@Pÿ@pP°  @°  @p°Ðð1Qq0`qÑ0 @0à0`01 0@pp@p°Ðð1QQ`qqq`` @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³0@pp@p°Ððp0 1`0à0`0à0ñ€‘p` @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³33Às1`0à0`0à0ÀÓSÀóq`°ÀÓÓÓÓÓÓÓÓÓÓÓÓÓÓS1 0@P@pP0 €0 @0`0€p0@p°Ðð1Qñ`qqqÿ``°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³33€3À1 0 `0 1ÀÓSÀóq`°ÀÓÓÓÓÓÓÓÓÓÓÓÓÓÓS1 3 ÀS0ÀÓ€€ÀÓq`  ÀÓÓÓÓÓÓÓÓÓÓÓÓÓÓs1€3ÀÓ0ÀÓ“Àr ÀÓÓÓÓÓÓÓ“'OžBFJNRVZ^bfjnrvzt||f|*|~~~~~~~~~~~~~~"p||f|" |~ÿ~~~~~~~~~~~~~"p||f|"|~~~~~~~~~~~~~~" 8HXhx pxxx8pxxxxxxxHpxxxxH8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé‰Ðð ð™Ið‰8Pðùùùùùùùùùùùùùù™ðù9ð™Iðy8PPðùùùùùùùùùùùùùù™ðù9ð™Iðy8Pðùùùùùùùùùùùùùù©  8 8HXhx8€ˆˆˆˆˆˆH€ˆˆˆX80P 8HXhxˆ˜ÿ¨¸ÈØèø)9IYiy‰™©¹ÉÙé©°@ð ð™Iði8 Xðùùùùùùùùùùùùùù©À°°pð‰I@ði8PPðùùùùùùùùùùùùùù©ð¹ ð‰Iðy8PðùùùùùùéÓ§OŸ>}úôi @ÁAÂBÃCÄ€Á€Ã€DÁ€ÄÄÄÄÄD‚ÄÄÄDÁ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÅ€OÅ€Á€Ã€€€DÀÁÁA@ÁAÂBÃCÄDAEEÅÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊÿJËKÌLÍMÎNOBÀÁÁA@ÁAÂBÃCÄ€Á€Ã€Á€Ã€ÄÄÄÄÄD‚ÄÄÄD€€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÆ€OÅ€Á€Ã€Á€Ã€ÏK‚ÏÂÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆ€Ïŀ€Á€Á€Ã€ÏK‚OÂÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆ€Oƀ€€Á€€Ä€ÏK‚OÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÆ€ÏÏÁ€ÏK‚OÀ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆÍ€ÏÀÏK‚OÀ‚ÏÏÿÏÏÏÏÏÏÏÏÏÏÏÏÏÆÍÁ€O€ÏK‚OÀ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆÍAÀ@ÁAÂBÃÃÃDDDDDDCDDDÄ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÆÍÁ€O€ÏK‚O‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆMÀÁAA@ÁAÂBÃÃÁDDDDDDCDDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÇ€ÏÏÁ€ÏK‚Ï€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÇ€MÀÁA@ÁAÂBÃCÂDDDÿDDDCDDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÇÍÀπOK‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÇÍÀπOK‚ÏÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÇÍÀπOK‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÇ@ÁAÂBÃBÀÁAA@ÁAÂBÃÃÁDDDDDÄBDDDÄÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÇ€ÏÏÁ€OK‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏǀ̀O€€OK‚OÂÁÿ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÇÍÀπOK‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÇÍ@ÁÁ@ÁAÂBÃÃÁDDDDDÄBDDDDÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÇÍÀπOK‚ÏÁÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÇ€MÀÁA@ÁAÂBÃCÂDDDDDÄBDDDDÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÈ€ÏÏÁ€OK‚ÏÁÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÈ€ÏÏÁ€OK‚ÏÁÁ‚ÏÏÏÏÿÏÏÏÏÏÏÏÏÏÏOÈ€ÏÏÁ€OK‚ÏÁ€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÈ€ÏÏÁ€ÏJ@ÁAÂBÃÃÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÈ€ÏÏÁ€ÏJ‚ÏÁÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÈ€ÏÏÁ€ÏJ‚ÏÁÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÈ€ÏÏÁ€ÏJ‚ÏÁ€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÉÏ€ÏÁ€ÏJ@@ÁAÂBÃCÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÉÏ€ÏÁ€ÏJ‚OÁ€‚ÏÏÏÏÏÏÿÏÏÏÏÏÏÏÏOÉÏ€ÏÁ€ÏJ‚OÁÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÉÏ€ÏÁ€ÏJ‚OÁÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÉÏ€ÏA@€‚ƒ„…†‡ˆ‰‡ŠŠŠƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž“ŸŒŒˆŸ•ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ“ž‹ŠˆŸ•Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ“žŠƒˆˆŸ”ŸŸŸŸŸŸŸ>}úôéÓ§OŸ>Q 8HXhx(€(0pÿ € 88 8HXhxˆxH˜˜X8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÉ 88 8HXhx(€(0p €€ˆˆˆˆˆ8H€ˆˆˆ8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéIà 0p ( 8 8HXhxˆ˜hH ¨¨(8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéIð¹@P€ðIIð 0PPðùùùùùùùùùùùùùùIðÉPP€ðIIð 0ÿPðùùùùùùùùùùùùùùYðù9ðIIð9 XðùùùùùùùùùùùéÓ§O•"&**,...,.&"&*.26:>BFJNRVZ^bfjnrvzV|~|Rx |~~~~~~~~~~~~~~V|~|Rx|~~~~~~~~~~~~~~Z|~|Rx|~~~~~~~~~~~~~~Z|~|Rx"&*.26:>BFJNRVZ^bfjnrvzZp| |Rxÿ|~~~~~~~~~~~~~~Zl||Rx|~~~~~~~~~~~~~~^h||Nt|~~~~~~~~~~~~~~^"&**,...,.""&*.26:>BFJNRVZ^bfjnrvz^|~|Nx|~~~~~~~~~~~~~~^|||Nx|~~~~~~~~~~~~~~bp||Nt|~~~~~~~~~~~~~~bp|"&(*&ÿ"&*.26:>BFJNRVZ^bfjnrvzbh """""  """&*.26:>BFJNRVZ^bfjnrvzbp||Np|~~~~~~~~~~~~~~f|~|Np|~~~~~~~~~~~~~~f|~|Np|~~~~~~~~~~~~~~f|~|Np"&*.26:>BFJNRVZ^bfjnrvzf|~|Np|~~~~~~~~~~~~~~f|ÿ~|Nl|~~~~~~~~~~~~~~f|~|Nl|~~~~~~~~~~~~~~j|~|Jl"&*.26:>BFJNRVZ^bfjnrvzjp| |Jp|~~~~~~~~~~~~~~jp| |Jp|~~~~~~~~~~~~~~jp| |Jp|~~~~~~~~~~~~~~jp """"" """&*.26:>BFJNRVZ^bfjnÿrvznp| |Jl|~~~~~~~~~~~~~~n|~|Jl|~~~~~~~~~~~~~~nd||Jl|~~~~~~~~~~~~~~nh| $,4}úôéÓ'N€      !#%')+-/13579;=+     !#%')+-/13579;=;>>% 2 >??????????????;>>% 2 >??????????????;>     ÿ !#%')+-/13579;=;>?># 4 >??????????????;>?># 2 >???????????????4>># 2 >???????????????4>>#    !#%')+-/13579;=?4    !#%')+-/13579;=?4@ @! 0 @AAAAAAAAAAÿAAAA#4@ @! . @AAAAAAAAAAAAAA%@A@! , @AAAAAAAAAAAAAA%@A@!    !#%')+-/13579;=?4 >@! * @AAAAAAAAAAAAAA'6@@! & @AAAAAAAAAAAAAA'8@@! & @AAAAAAAAAA-"     ÿ  !#%')+-/135/"&6#6676+  6777777777777/     !#%')+-/1351ÿ      !#%')+-/1351        !#%')+-/1351   24ÿ66)  67777777777773       !#%')+-/1353  2676)  6777777777777ÿ7763467 $,4^~^:`1 à1 €žž=z›"&*.26:>BFJNRVZ^bfjnrvz~‚†Š.$ ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2, ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2,ŒŽŽŽŽŽŽŽŽŽŽ5jÔ¨Q£ $  ( $,4BFJNRVZ^bfjnrvz~     """""" "&*.26:>BÿFJNRVZ^bfjnrvz~&x(  "&*"&*.26:>BFJNRVZ^bfjnrvz~*€* €n €‚‚‚‚‚‚‚‚‚‚‚‚‚‚j€. €j€‚‚‚‚‚‚‚‚‚‚‚‚‚‚j€‚€j€‚‚‚‚‚‚‚‚‚‚‚‚J @ÁAÂBÃCÄDEÅ€ÅÅÅÅÅA€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÅPP€PM‚Á€ÿPPPPPPPPPPPPPPÐÍPP€PM‚Á€PPPPPPPPPPPPPPPÎPP€ÐL€PPPPPPPPPPPPPPPÎPP€ÐLBÀ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÆÎ€€€P€ÐL‚Á€‚PPPPPPPPPPPPPPP΀ÍÂÐÐL‚Á€PPPPPPPPPPPPPPÐÎÍÀÏÐL‚Á‚PPPPPPPPPPPPPPÐÎ@ÁAÂBÃCÄDEÅ€ÅÅÅÅEA‚Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉÿIÊJËKÌLÍMÎNÏOÇPP€ÐL‚ÁPPPPPPPPPPPPPPPÏÐÐÐLÁ€PPPPPPPPPPPPPPPÏ΀ÏPLÁ€PPPPPPPPPPPPPPPÏ΀ÏPL@€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸŽš€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸŽœ „ —„               Ÿ   —„   ÿ            Ÿ   —„               Ÿ   —ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ   —ƒ                   —ƒ                   —ƒ                   –„    @ (P @ P €à a¡áa€`ÀáááaaÀááááááa!á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&gÿ§ç'dg€`(@h%á@(((((((((((((((hg€`(@h%á@A(((((((((((((((hg€`(@h%á@((((((((((((((((@ €à a¡áa€`ÀáááaaÀáááááá!!á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çgd((@(%Aá@((((((((((((((((@@fÀaÀg(%Aá@((((((((((((((((@€f@ah(%Aá@((((((((((((((((@ÀfÀ`À"`ÿ €à a@@!a €à a¡á!bâ!AaA €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çgdg@Àb@bÀ`Àa(%á@(((((((((((((((¨`@gÀbÀ`ÀbÀaè$á@(((((((((((((((¨`hbÀ`€b"`€àà €à a¡á!â!Aá@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§"`€àà €à a¡á!baÀ`@b@b@bbbb¢!Aá@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&gÿ§ç§dhbÀ`b€bè$Aá@(((((((((((((((¨`¨b@a@€`Àb¨$AaA(((((((((((((((¨`èb@a@€ `€  €à @ €à a¡á!bb!a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ççd((@¨$Aá@(((((((((((((((è`((@¨$Aá@(((((((((((((((è`€f¨a¨$Aá@(((((((((((((((è`€f¨a¨$ € à@ €à a¡á!b¢â"c£ã#ÿd¤ä$e¥å%f¦æ&g§ççd€&`€à  €à a¡áá`"""""¢ Aá@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ççd€f¨a¨$Aa((((((((((((((((a€f¨ah$Aá@((((((((((((((((a((@h$Aá@((((((((((((((((a((@h$A!à@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'e€f€aÀgh$Aá@((((((((((((((((aÀfahh$áÀ@(((ÿ(((((((((((((ag@@@(@h$á@((((((((((è`@@@b`@@ € ` €à a¡á!bâaa€â`@aa@a€¢¢¢¢a€¢¢¢¢¢ba€¢¢¢b"á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦&aÀ`@b@aÀdÀæbac€`@baÀædÀææbÀ¦%Áà@Áææææææææææææfa€a@@a@aa@À`@@À`@@b@@€`@@À`@@À`@@€`À`@@@@€` @@ €àà`!@@!@À`@@ÿ@À`@@€`@@À`@@!!!!!¡`!!!!!á`@@!!!!!!!á` €à a¡á!bâ á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦fa@bÀ`@a@aÀ`@€`@À`Àa@€`@@€`@À`@a@À`€`a@€`b€a@aaaÀ`@@€`@À`@f€fÀ`ÀæaÀf%á@Áææææææææææææfa€a@`@@ € `À `À`À`@À`Àà @À`@À  `€  À`@@@@@ €à @@@@aÿ!@a!`€  @ €à`@ €à a¡¡aÀááaaÀ`Àááá¡aÀááááá¡!a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦¦a@aÀ`À`@a@aÀ`À`€`@@bÀ`@@a@aÀ`@À`€`aÀ`b€a@aaa@ab€f€fÀ`ÀæaÀf%aÁææææææææææææ¦aÀ`@€`@À`@a@aÀ` €`@€     @@€`@€  @€  @€`@@€`@€`€`@€ @€   `€  `€  @€ `€`@€  @€  @€ @ €à ÿa¡!aÀááa!`€à  €à a¡áá`""""""Áà@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æa@@À`@@€`@@À`@@À`@@€`À`€`@@b@@€`€a@@À`@@€`@@À`@€`À`b@a@@À`@@a@À`@@€`€a@@€fÀææbÀ&%á@Áæææææææææ¦M›6mz( @p @p°Ðð1Qq‘±Ñ1àñññ±0àññQ€° àñññññññññññññññññññññññññ‘0 1àññññññ1àññÿñ±0àññQ€°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó3 ô‘€°1 ô‘`p 1 Ô‘€`° 1 Ô‘€°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó33 Ô‘`p 41 ´‘€°T1 t‘€€° T1ÿ t‘€°p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óós3ô2 1t‘`p `3T141T141T141t2Ô2 1t‘`p  3T141T141T141t2´2`0à0T‘    @p°Ð0àððððððððð0àðððððððððp0àððððððððð0àðððððððððp0àððððððððð0àðððððððððp0àððððððP0àðððððð0`0à0@p°Ððÿ1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Ô@p°Ðð11`0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt´0`0€””””””””””””””””3 €””””””””””””””””T3@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vv–¶Öö7Ww—·×÷8Xx˜¸Øø9Yy™¹Ùù6 À0@P@p°Ðð1Qq±0 €‘‘‘‘q1 €‘‘‘‘Q1 0€‘‘‘‘ñ0 0€‘ÿ‘‘‘1€0 €‘‘‘‘Ñ0€0 €‘‘‘‘‘‘‘‘‘0€‘‘‘‘‘±0€‘‘‘‘Q1`0€‘‘‘‘11`0€‘‘‘‘1 €0 €‘‘‘‘±0 €0 €‘‘‘£C€    ÿ         $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GOW_gow‡—Ÿÿ—X x  §§GÞ&@€‚ƒ„………„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢‹‰„ƒ…£££££££££££££££££Œ‹„ƒ„£££££££££££££££££Œ‹„‚†£££££££££££F5jÔ(F€   !#%')+-/13579;=?ACEFGGGGGGGGGGGGGG2GGFGGGGGGGGGGGGGGGGGGGGGGGGG';openacs-5.7.0/packages/acs-templating/www/doc/time3/stage07.gif0000644000175000017500000002664107253523117024052 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰Š„ŠŠŠŠŠŠŠŠŠ†ŠŠ€‚ƒ„…†‡ˆ‰Š‚€‚ƒ„…„€‚ÿƒ„…†‡ˆ‰Š‹Œ…ŽŽŽŽŽŽŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽ‰ŽŽŽŽŽŽŽŒ€‚ƒ„…†€‚ƒ„…†‡ˆ‰Š‹ŠŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‰Š„ŠŠŠŠŠŠŠŠ†€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹Œ†ŽŽŽŽŽŽŒŽŽŽŽŽŽŒŽŽŽŽŽŽŽŽŽ„€‚ƒ„…€‚ƒ‚€‚ƒ„…†‡ˆ‰ˆ€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ„…†‡ˆ‰Šÿ‹ŒŽ‘’“”•–—˜™š›œ„€‚ƒ‚€‚ƒƒ€‚ƒ„„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹ˆ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŽ€‚ƒ„…†‚€‚ƒ„…€‚ƒ„…††††††††††…†††††††††††††„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›™„†€‚‚€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™ÿš›œƒŒ€‚ƒ€‚ƒ„€‚ƒ€‚ƒ„…†‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ‚ƒˆ‚ƒ‡‡’ˆƒ…ƒˆ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŠƒƒƒ‡”ÿ‡‘‹ƒƒƒƒ†•‡Œ‚…‚€€‚ƒ€‚ƒ„…†‡ˆ‰…ŠŠŠŠŠŠ…ŠŠŠŠŠŠŠƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‚†‚†–‡Ž’–—‡‘–—‡:ID 8HXÿhPpxxxxxxHpxxxxxxxx(pxxxxxxxxx8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É)I`YPЉÀÐIÐÙ¹8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙÉH@0H@ÐH€X@Ðy°@Ð9ÐÙ©80ÐÙÙÙÙÙÙÙÙÙÙÙÙÙÉH@0H@ÐH`XP@@Ðy ` 8HXhx8€ˆˆˆˆˆˆˆH8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙH@ H@@ H@@ H@@P@@ÐyÐÙyÐÙ™8ÐÙÙÙÙÙÙÙÙÙÙÿÙÙÙII@H H@@0XPÀH 8HXhxX 8H 8HXhxˆ˜¨¨°¸¸¸¸¸0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉII@0H (@@@P 8HXhxˆ˜¨(°¸x°¸¸°¸¸¸¸¸8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉII@@H0H@ XPÐÉÀ Ð)ÐÙ‰8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙII@H H@@ X@ÐÉÀ Ð)ÐÙ‰8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙI H (ÿ 8(H@@ HP@ 8HXhxˆ˜¨8°¸h °¸˜°¸¸¸¸¨8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉYI0YÐÙ ÐÐ9ÐÙy8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙYIYPÐÙ)ÐÙyÐÙy8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙII YÐÙ9Ð9Ð9ÐÙi80ÐÙÙÙÙÙÙÙÙÙÙÙÙÙI ˆ@p°P°ÀÐÐÐÐÐÐÐÐÐP0ÀÐÐÐ0€0ÀÐÐÐÐ ÀÐÐÐÐÐÐÐÐÐp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“3² ÿ€   €± à°  ó2€3€0 S0 ³Óp ³³³³³³³³³³³³³3² € `°`± à°  ó2@0@p0@p°Ðð0q@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“3² € °±      `°  ó2€3 ó0 ³Óp ³³³³³³³³³³³³³“’€°±@°   `° °@p°Ðð°@p @p°Ðð1QQ1`qqqq1q@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss““’`°`°@P  ÿ  @p°Ðð1QQ0`qñ0@P@pp0€P0 €0@p°Ðð1Qq@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³’@°@±`° `° “3€3 1 1`0à0 ³³p ³³³³³³³³³³³³³³’ `±@°  `° “3€3 @0à0`0à0`0à0 ³³p ³³³³³³³³³³³³³“ ÀAA@ÁAÁ‚€Á‚‚@ÁAÂBÃCÄDÅÁ€ÅEÀÁ€Ã€ÁÄ€€DÀÁÁA@ÁAÂBÃCÄDÅ@ÁAÿÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNJÉ‚NMÀÁÁA@ÁAÂBÃÃÁ€Ä€Á€Ã€Á€ÃDDDDDDÄÃ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNJÉ‚Î΀NÆ€Á€Ã€Á€Ã€ÎÎÂÎÎÎÎÎÎÎÎÎÎÎÎÎNJÉ‚Î΀NÀAA@ÁAÁ€Â€Á€ÁÂÁ@ÁAÂBÃCÄDEÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎI‚È‚ÎNÃÎǀ€€Á€€Ä€ÎÎÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎIÉ‚ÎNÀ΀ÿ€€€ÎÁ€ÎNÂÎÎÎÎÎÎÎÎÎÎÎÎÎNJÉ‚ÎNÃ΀ÎÀÎNÂÎÎÎÎÎÎÎÎN:uêÔ‰ @ÁAÂÂÁCCCCCCCCCCÂCCCCBÀÁA@ÁAÂBÃÃÁDDDDDDDÃ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMNJÉ‚ÎNÀÎÎÀÎNÂÎÎÎÎÎÎÎÎÎÎÎÎÎÎI‚É‚ÎNÀÎÎÀÎÎÁÎÎÎÎÎÎÎÎÎÎÎÎÎNJÉ‚ÎÎÀN€NÁ€ÎÎÁÎÎÎÎÎÎÎÎÎÎÎÎÎNJÉ‚ÎÎC@€‚ƒ„…†…€‚ƒ€‚ƒÿ„…†‡ƒˆˆˆˆˆˆˆ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ”’‡œ„‚ƒ“‘ˆ‡ƒ“’ˆ‡ƒ“’€‚ƒ„…†‡ˆ‰Š‹‹‹Š‹‹Š‹‹‹‹‹†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ“’ˆœ„‚‚“’ˆœ„‚‚ÿ”’ˆš€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ”’ˆœ‡‚”‘‰‡‚”‘‰‚ƒ•‘€‚ƒ„…†‡ˆ‰Š‹ŒŒ„‚ŒŒ‡ŒŒŒŒ‹€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ•‘‰œ‚‚ÿ”’‰œ‚‚”’‰‚ƒ:uêD  €à aá`¡¡¡¡¡¡¡¡¡¡!@€¡¡¡¡¡¡¡¡¡aa€¡¡¡¡¡¡¡¡aá €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&'%AdAg§b@g@@ga@g'À@ggggggggggggg'%AdAg§bg@€`@§`@g'À@ggggggggggggg'%AdAg§bg@€`@§`@g'À@ggggggggggÿg§N("$,,04444444444 0444$  04444044444444$$,4FNV^fnv~Öÿ $,4}Ú(@p°Ðð0@p@p°Ððp0q Qp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ós3àós0à“’ @sàóóóóóóóóóóóóóós3àós0às’@°@sàóóóóóóóóóóóóóós3àS0à3às’@°@sàóóóóóóóóóóóóóós3@30@p@p°Ððp0Q@°`@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3€3€0à3às’@° sàóóóóóóóóóÿóóóóó“3àós0às’@° sàóóóóóóóóóóóóóó“3àós0às’ @sàóóóóóóóóóóóóóó“3à à às @p°Ð°p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3€3€0à3às’ @sàóóóóóóóóóóóóóó“3€3€0à3àS’@°@sàóóóóóóóóóóóóóó“3@0@p0@p°Ðð0€@°Qp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3€3à³0àS’@°@sàóÿóóóóóóóóóóóóó“3àós0àS’@° sàóóóóóóóóóóóóóó³3 3@0à àS’@° sàóóóóóóóóóóóóóó³3€3@0 @p°Ððp0€ Qp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³3€3 @0à3àS’ @sàóóóóóóóóóóóóóó³3€3 @0à3àS’ @sàóóóóóóóóóóóóóó³3 3@0à àS’  sàóóóóóóóóóóóóóóÓ0@p°Ðð1QQ1`qqq± ÿ`qqp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓÓ3 3 às0àS’ @sàóóóóóóóóóóóóóóÓ3€3 @0à3àS’ @sàóóóóóóóóóóóóóóÓ3€3 @0à3àS’ @sàóóóóóóóóóóóóóóÓ3€30 @p°Ððp0‘€ Qp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓÓ3 3 à à3’ @sàóóóóóóóóóóóóóóÓ3àós0à3’  sàóóóóóóóóóóóóóóó3àóÿs0à3’  sàóóóóóóóóóóóóóóó3@3À0à3@p°Ðð1q @Q±p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó3`3€0à à3’  sàóóóóóóóóóóóóóóó3€3 `1`1 à0à3’   sàóóóóóóóóóóóóóóó3às1 1@1à3’ @sàóóóóóóóóóóóóÓ§OŸ" $ $&&&&$&""&*.26:>BFJNRVZ^bfjnrvz~|* ÿ "$&""&*.26:>BFJNRVZ^bfjnrvz^"  $&&&&$&"&*.26:>BFJNRVZ^bfjnrvz~€&  €Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€* €Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€.  €Bd€‚‚‚‚‚ (P @ P €à a¡á!b¢¢bÀâââ"!AÿÁââà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'@€f¨a($AAæ((((((((((((((hd€f€`è`($AAæ((((((((((((((hd€f€`è`($AAæ((((((((((((((hd€f€`è  @ÁAÂBÃCÄÄA‚EÅÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏO€MÀÁAA@ÁAÂBÃÃÁDDDDDD‚DDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏO€PP€PÈÿ‚‚ÌPPPPPPPPPPPPPPÐÈ€MÀÁA@ÁAÂBÃCÂDDDDDÄDDDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏO€ÍÀÏPÈÍPPPPPPPPPPPPPPÐÈÍÀÏPÈÍPPPPPPPPPPPPPPÐÈÍÀÏPÈÍPPPPPPPPPPPPPPÐÈMÀÁAA@ÁAÂBÃÃÁDDDDDÄDDDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏO€PP€PÈÍPPPPPPPPPPPPPPÐÈ€ÍÿÂÐPÈÍPPPPPPPPPPPPPPÐÈÍÀÏPÈÍPPPPPPPPPPPPPPÐÈÍÀÏPÈÍ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏO€ÍÀÏPÈÍPPPPPPPPPPPPPPÐÈ€MÀÁA@ÁAÂBÃCÂDDDDDÄDDDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏO€PP€PÈÍPPPPPPPPPPPPPPÐÈPP€PÈÍPPPPPPPPPPPPPPÐÈPP€PÈÍPPPPPÿPPPPPPPPPÐÈPP€PÈÍPPPPPPPP @ ¨H€    !#%')+-/13579;=?@A@! 4@AAAAAAAAAAAAAA#@A@! 4@AAAAAAAAAAAAAA#<@@! 4@AAAAAAAAAAAAAA#<@@! 4@AAAAA (P @Š(@p°ÐðP0Q0±Qp@p°Ðð1Qq‘±Ññ2Rr’²ÿÒò3Ss“³Óó À3T0²@s42À3T0²@s42t1€11²@s42À3`1 @1 0@p°Ðð1q°@QÑp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó À3@1`01 1²@s42À3@1`0à0@00@pp@p°Ðð‘° 1q@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óÿ0@pp@p°ÐðP0Q0`0à0@01±Qp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó À3@1`0à0@P@p @p°Ðð1q°@Q±p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóS0T1 €0  01² sT2t1 0  01² sT2 ² sT2 @ÁAÂBÃCÄÄÁEÅÂ@ÁÿAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁPP€PÈ‚ÌPPPPPPPPPPPPPPPÉPP€PÈ‚ÌPPPPPPPPPPPPPPPÉPP€PÈ‚ÌPPPPPPPPPPPPPPPÉPP€PÈ‚ÌPPPPPPPP @ (I€     !#%')+-/13579;=?6@@! 2@AAAAAAAAAAAAAA%4 >@! 2@AAAAAAAAAAAAAÿA%@A@! 2@AAAAAAAAAAAAAA%@A@! 2@AAA (P @J @ÁAÂBÃCÂDDDÄDDDDDÄDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁ΀ÏPÈ‚ÌPPPPPPPPPPPPPPPÉ΀ÏPÈ‚ÌPPPPPPPPPPPPPPPÉMÀÁÁ@ÁAÂBÃCÂDDDDDÄDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁÎPÂÐG‚‚ÌPPPPPPPÿPPPPPPPPÉPP€ÐG‚‚ÌPPPPPPPPPPPPPPPÉPP€ÐG‚‚ÌPPPPPPPPPPPPPPPÉPP€ÐG‚‚ÌPPP @ (P @% P €à a¡á!b¢¢bÀââââ AÁââà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§`((@è#AAæ((((((((((((((¨d((@è#AAæ((((((((((((((¨d((@è#AAæ((((((((((((((¨dg€`(@è#AA&à €à a¡á!ÿb¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§`g€`(@è#AAæ((((((((((((((¨dg€`(@è#AAæ((((((((((((((¨dg€`(@è#AAæ((((((((((((((¨dg€ ` €à a¡áaa""""â!A"""À €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§`((@è#AAæ((((((((((((((¨d@fÀaÀgècæ((((((((((((((¨d€f@ahècæ(((((((((((ÿ(((¨dÀfÀ`Àb€b@@ €à ` €à a¡á!b¢`¢¢á €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§`g@Àb@bÀ`Àaècæ((((((((((((((¨d@gÀbÀ`ÀbÀaècæ((((((((((((((¨dhbÀ`€b"`€àà €à a¡á!â`Ab"â €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§g&`€àà €à a¡á!baÀ`@b@b@bbbb¢`Ab"â €à a¡á!b¢â"c£ã#d¤ä$e¥ÿå%f¦æ&g§ç§`hbÀ`b€bècæ((((((((((((((¨d¨b@a@€`Àbècæ((((((((((((((¨dèb@a@€ `€  €à @ €à a¡á!b¢`¢¢á €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§`((@ècæ((((((((((((((¨d((@ècæ((((((((((((((¨d€f¨aècæ((((((((((((((¨d€f¨aècæ((((((P @ (P’ÿ  """" "" "&*.26:>BFJNRVZ^bfjnrvz~ h€€>d€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Nh€€>d€‚‚‚‚‚‚‚‚‚‚‚‚‚‚N€‚€>d€‚‚‚‚‚‚‚‚‚‚‚‚‚‚N€‚€>d€‚‚‚‚‚ (P @5 P €à a¡aa€aÀáááá`ÀáááááaaÁáá!á €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çç`ÀfahècAæ(((((ÿ(((((((((èdg@@@(@ècAæ((è$`€  €àà`a¡` €à a¡á!b¢â`Àââââââ"@@À`Àâââââ¢bÀâ"@Àââââ¢aa@aÀâââaÀââââ¢bÀââââ`ÁââàÀâââââââââbaÀâaÀbbÀâââbÀââââââb€`€`Àâââââ¢bÀâ"@Àâââââb@aÀââ¢C€    ÿ           ÿ       ÿ            ÿ                         ÿ                      ÿ        ÿ       !#%')+-/13579;=?@A@ 2@AAAAAAAAAAAAAA'@A@ 2@AAAAAAAAAAAAAA'@A@ 2@AAAAAAAAAAAAAA'@A@ 2@AAAAAAA (P & ÿ$,4FNV^fnv~Æ ø ø ð à ( Ð Ð 0 È ( €ö è  ø $,4BF H"H6HJJ HJJJJJJJJJJJJJJJJJ&H"HJJJJJJJ.H"H6HJJ HJJJJJJJJJJJJJJJJÿJ"H"HJJJJJJJ.H& """""""&*.26:>BFJNRVZ^bfhhjjjjfhj6hjhjjjjjjjjjjjRhhjjjjfhj6hjhjjjjjjjjjjjRhhjjjjfhj6hjhjjjjjjjjjjjRhhjjÒ¤I @ÁAÂBÃCÄDEÅ€ÅÅÅÅÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLDÍMMMMMÍMÍÆMÍÁMMMMMMMMMMMÍJÍÿMMMMMÍMÍÆMÍÁMMMMMMMMMMMÍJÍMMMMMÍMÍÆMÍÁMMMMMMMMMMMÍJÍMMMMMM€  !#%')+-/13 4 4555554 445455555555555) 4 4555554 445455555555555) 4 4555554 445455555555555QD 8HXhXX 8HXhxˆ˜¨¸ÈØèøIÿ É  ))9 )))))))))))))))))™H ‰X )))))))Ù )yÀ€ ))9 )))))))))))))))))™H ‰X )))))))٠ɰ € ))9 ))))I’$I’$I’$I’$I’$%D 8HXhXX 8HXhxˆ˜¨¸ÈØèøI É 0€€ ))9 )))))))))))))))))™H ‰X )))))))Ù É 0p € 88 8HXhxˆ˜0 8HXhxˆ˜¨¸ÈØèø)ÿ9IYiy‰™‰H Y ©©©©9  88 8HXhx(€(0p €€ˆˆˆˆˆh8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™yH@Y ©©©©©) I 0p ( 8 8HXhxˆ˜˜8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™yH Y ©©©©©)  @P€ ©)8 ©©©©©©©©©©©II Y ©©©©©) PP€ ©)8 ©©©©©©©©©©©IIY ©©©©©9 ©Ù ©)8 ©©©©I“&Mš4ÿiÒD  €à a¡!a €à a¡á!b¢â"c£ã#d¤a€¤¤äb€¤¤ä€¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤$"äa¤¤¤¤¤¤¤äc€¤¤äb€¤d䀤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤d"äa¤¤¤¤¤¤¤äc€¤¤äb€¤d䀤¤¤¤¤¤¤¤¤¤¤¤¤¤¤$I’"$,4$,$,4 HTMLQuoting as Part of the Templating System - Requirements

    HTMLQuoting as Part of the Templating System - Requirements


    The Templating System.

    Templating systems, as deployed by most web software, serve to distinguish the programming logic of the system from the presentation that is output to the user.

    Before introduction of a templating systems to ACS, pages were built by outputting HTML text directly from Tcl code. Therefore it was hard for a designer or a later reviewer to change the appearance of the page. "Change the color of the table? How do I do that when I cannot even find the body tag?" At this point some suggest to embed Tcl code in the document rather than the other way around, like PHP does. But it doesn't solve the problem, because the code is still tightly coupled with the markup, requiring programmer-level understanding for every change. The only workable solution is to try to uncouple the presentation from the design as much as possible.

    ACS 4.0 addressed the problem by introducing a custom-written templating system loosely based on the already-present capabilities of the AolServer, the ADP pages. Unlike the ADP system, which allowed the coder to register his own tags to encapsulate often-used functionality, the new templating system came with a pre-programmed set of tags that performed the basic transformations needed to process the page, and some additional value.

    Comparing ACS templating to other templating systems, it is my impression that the former was designed to be useful in real life rather than minimalistic -- which is only makes sense given the tight deadlines most ArsDigita projects have to face. Besides the if tag, multiple tag and @variable@ variable substitution, which are sufficient to implement any template-based page, it also includes features like including one template in another, customizing site- or module-wide look using the master templates, directly importing query results to the template, facilities for building grid-tables, and more. This utilitarian approach to templating urges us to consider the quoting issues as integral part of the system.

    Quoting.

    In the context of HTML, we define quoting as transforming text in such a way that the HTML-rendered version of the transformed text is identical to the original text. Thus one way to quote the text "<i>" is to transform it to "&lt;i&gt;". When a browser renders the transformed text, entities &lt; and &gt; are converted back to < and >, which makes the rendered version of the transformation equal to the original.

    The easiest way to guarantee correct transformation in all cases is to "escape" ("quote") all the characters that HTML considers special. In the minimalistic case, it is enough to transform &, <, and > into their quoted equivalents, &amp;, &lt;, and &gt; respectively. For additional usefulness in quoted fields, it's a good idea to also quote double and single quotes into &quot; and &#39; respectively.

    All of this assumes that the text to be quoted is not meant to be rendered as HTML in the first place. So if your text contains "<i>word</i>", and you expect the word to show up in italic, you should not quote that entire string. However, if word in fact comes from the database and you don't want it to, for instance, close the <i> behind your back, you should quote it, and then enclose it between <i> and </i>.

    The ACS has a procedure that performs HTML quoting, ad_quotehtml. It accepts the string that needs to be quoted, and returns the quoted string. In ACS 3.x, properly written code was expected to call ad_quotehtml every time it published a string to a web page. For example:

    doc_body_append "<ul>\n" set db [ns_db gethandle] set selection
    [ns_db select $db {SELECT name FROM bboard_forums}] while {[ns_db
    getrow $db $selection]} { set_variables_after_query doc_body_append
    "<li>Forum: <tt>[ad_quotehtml $name]</tt>\n" }
    doc_body_append "</ul>\n"
    

    Obviously, this was very error-prone, and more often than not, the programmers would forget to quote the variables that come from the database or from the user. This would "usually" work, but in some cases it would lead to broken pages and even pose a security problem. For instance, one could imagine a mathematicians' forum being named "0 < 1", or an HTML designers' forum being named "The Woes of <h1>".

    In some cases the published variable must not be quoted. Examples for that are the bboard postings that are posted in HTML, or variables containing the result of export_form_vars. All in all, the decision about when to quote had to be made by the programmer on a case-by-case basis, and many programmers simply enjoyed the issue because the resulting code happened to work in 95% of the cases.

    Then came ACS 4. One hoped that ACS 4, with its advanced templating system, would provide an easy and obvious solution for the (lack of) quoting problem. It turned out that this did not happen, partly because no easy solution exists, and partly because the issue was ignored or postponed.

    Let's review the ACS 3.x code from above. The most important change is that it comes in two parts: the presentation template, and the programming logic code. The template will look like this:

    <ul> <multiple name=forums> <li>Forum:
      <tt>@forums.name@</tt> </multiple> </ul>
    

    Once you understand the (simple) workings of the multiple tag, this version strikes you as much more readable than the old one. But we're not done yet: we need to write the Tcl code that grabs forum names from the database. The db_multirow proc is designed exactly for this; it retrieves rows from the database and assigns variables from each row to template variables in each pass of a multiple of our choice.

    db_multirow forums get_forum_names { SELECT name FROM forums }
    

    At this point the careful reader will wonder at which point the forum name gets quoted, and if so, how does the templating system know whether the forum name needs to be quoted or not? The answer is amazingly blunt: no quoting happens anywhere in the process. If a forum name contains HTML special characters, you have a problem.

    There are two remedies for this situation, and neither is particularly appealing. One can rewrite the nice db_multirow with a db_foreach loop, manually create a multirow, and feed it the quoted data in the loop. That is ugly and error-prone because it is more typing and it requires you to explicitly name the variables you wish to export at several points. It is exactly the kind of ugly code that db_multirow was designed to avoid.

    The alternative approach means less typing, but it's even uglier in its own subtle way. The trick is to remember that our templating still supports all the ADP features, including embedding Tcl code in the template. Thus instead of referring to the multirow variable with the @forums.name@ variable substitutions, we use <%= [ad_quotehtml @forums.name@] %>. This works correctly, but obviously breaks the abstraction barrier between ADP and Tcl syntaxes. The practical result of breaking the abstraction is that every occurrence of Tcl code in an ADP template will have to be painstakingly reviewed and converted once ADPs start being invoked by Java code rather than Tcl.

    At this point, most programmers simply give up and don't quote their variables at all . Quoting is handled only in the areas where it is really crucial and where not handling it would quote immediate and visible breakage, such as in the case of displaying the bodies of bboard articles. This is not exaggeration; it has been proven by auditing the ACS 4.0, both manually and through grepping for ad_quotehtml. Strangely, this otherwise sad fact allows us to deploy a very radical but much more robust solution to the problem.

    Quote Always, Except When Told Not to.

    At the time when we came to realize how serious the quoting deficiencies of ACS 4.0 were, we were about two weeks away from the release of a project for the German Bank. There was simply no time to hunt all the places where a variable needs to be quoted and implement one of the above quoting tricks.

    While examining the ADPs, we noticed that most substituted variable fall into one of three categories:

    1. Those that need to be quoted -- names and descriptions of objects, and in general stuff that ultimately comes from the user.

    2. Those for which it doesn't make a difference whether they are quoted or not -- e.g. all the database IDs.

    3. Those that must not be quoted -- e.g. exported form vars stored to a variable.

    4. Finally we also remembered the fact that almost none of the variables are quoted in the current source base.

    Our reasoning went further: if it is a fact that most variables are not quoted, and if the majority of variables either require quoting or are not harmed by it, then we are in a much better position if we make the templating system quote all variables by default! That way the variables from the first and the second category will be handled correctly, and the variables from the third category will need to be marked as noquote to function correctly. But even those should not be a problem, because HTML code that ends up quoted in the page is immediately visible, and all you need to do to fix it is add the marker.

    We decided to test whether the idea will work by attempting to convert our system to work that way. I spent several minutes making the change to the templating system. Then we went through all the ADPs and replaced the instances of @foo@ where foo contained HTML code with @foo;noquote@.

    The change took two people less than one day for the system that consisted of core ACS 4.0.1, and modules bboard, news, chat, and bookmarks. (We were also doing other things, so it's hard to measure correctly.) During two of the following days, we would find a broken page from time to time, typically by spotting the obviously visible HTML markup. Such a page would get fixed it in a matter of seconds by appending ;noquote to the name of the offending variable.

    We launched successfully within schedule.

    Porting the quoting changes to the ACS.

    After some discussion, it was decided that these changes will be included into the next ACS release. Since the change is incompatible, it will be announced to module owners and the general public. Explanation on how to port your existing modules and the "gotchas" that one can expect follows in a separate document .

    The discussion about speed, i.e. benchmarking results before and after the change, is also available .

    Hrvoje Niksic

    View comments on this page at openacs.org
    openacs-5.7.0/packages/acs-templating/www/doc/timing-1.html0000644000175000017500000000676307253523117023406 0ustar frankiefrankie Template Timing Results

    Results

    The measurements were taken on dev0103-001 on 5 October 2000, probably with acs-4-0-beta-R20001001. Here are the graphs for the 14 stages, titled by the log message of their beginning.

    Invoking preauth filter rp_filter

    No difference; all take about 2.6 ms. The same is the case for the few following stages: Short times and apparently independent of the kind of page.

    Looking for node to match /acs-templating/admin/test/chain-frac-0.

    Found /acs-templating/.

    Performing developer support logging

    Checking for changed libraries

    Handling authentication

    For some reason, this seems to take much longer on the TCL only page. Maybe because it's the first in a triple of pages that e-Tester requests? There may be a little longer time gap between chain-frac-2 and the next request of chain-frac-0

    Handling authorization

    An unexplained but clear distinction here: 0 is faster than 2, and 1 is slowest.

    Done invoking preauth filter rp_filter (returning filter_ok)

    Invoking registered procedure rp_handler

    Searching for /webroot/web/brech/acs/packages/acs-templating/www/admin/test/chain-frac-0.*

    Serving /webroot/web/brech/acs/packages/acs-templating/www/admin/test/chain-frac-0.tcl with rp_handle_tcl_request

    Here the actual work supposedly happens. The TCL only page is clearly fastest. Always reparsing pages expectedly affects the templated page, and -2, which compiles two ADP pages, is affected more than -1. The benefit of -2, wrapping -1 in another include, isn't apparent; on the contrary, -1 is in all cases a bit faster than -2. The benefit of cacheing seems more than offset by the extra complexity of nesting several templates.

    Invoking trace filter ad_issue_deferred_dml

    For some reason, the TCL-only page takes significantly longer.

    Done invoking trace filter ad_issue_deferred_dml (returning filter_ok)

    Invoking trace filter ds_trace_filter

    That last phase is ended by Done invoking trace filter ds_trace_filter (returning filter_ok)

    Total time

    Overall, the templated pages are delivered faster. Forcing the template system to always reread all files and to recompile the ADP part slows them down, as expected, but overall they are still faster than the TCL only page.


    Christian Brechbuehler
    Last modified: Tue Oct 17 20:04:29 EDT 2000 openacs-5.7.0/packages/acs-templating/www/doc/timing-2.html0000644000175000017500000000374607253523117023405 0ustar frankiefrankie Template Timing Results

    Results

    The measurements were taken on reusia.boston on 13 October 2000, with approximately acs-4-0-beta-2-R20001009.

    Here are the graphs for the 15 stages, and the log message of their beginning is written in the lower right of the graphs. In comparison with the first measurement, the steeper slopes indicate much less variation in the measurements, which reflects the more reproducible conditions (essentially no other activity) on reusia.boston in comparison with dev0103-001.

    Individual Stages

    Total Time (Sum of all Stages)

    Overall, the templated pages are delivered markedly slower, by about 65ms. Forcing the template system to always reread all files and to recompile the ADP part slows them down, as expected, but overall they are still faster than the TCL only page.


    Christian Brechbuehler
    Last modified: Wed Oct 18 16:45:17 EDT 2000 openacs-5.7.0/packages/acs-templating/www/doc/design.html0000644000175000017500000004642407540413146023227 0ustar frankiefrankie Template System

    The Template System -- Design Document

    by Christian Brechbühler Templating System : Design

    I. Essentials

    • User directory -- none; www exists only for documentation.
    • ACS administrator directory -- none.
    • Subsite administrator directory -- none.
    • Tcl script directory. Almost no procedures show up here. To minimize dependencies across packages, in particular on ad_proc from acs-kernel, this package uses proc.
    • PL/SQL API -- none.
    • Data model -- none. Templating does not depend on a database system at all. There's the one table ad_template_sample_users that some of the demonstrations use.
    • Requirements document
    • ER diagram -- none.
    • Transaction flow diagram -- none.

    II. Introduction

    • What this package is intended to allow the user to accomplish.

      The overall goal of the templating system is to provide the publishing team with a set of tools for simplifying the development and maintenance of the user interface. In particular:

      • A common solution. Programmers and designers should only have to learn a single system that serves as a UI substrate for all the functionally specific modules used on a site. The system should not make any assumptions about how pages should look or function. Designers should be able to change the default presentation of any module using a single metholodogy with minimal exposure to code.

      • Separation of code (Tcl, Java and SQL) and layout (HTML). Programmers should be able to specify the data sources and other properties of the template independently of the HTML template used to present the data. HTML authors should be to able to write templates that reference the data sources and properties without further intervention from the programmer to produce a finished page.

      • Separation of page components. There should be provisions so that pages can be broken into discrete components to simplify maintenance of the HTML code and allow for reuse in different contexts. Examples of common page components include a navigation bar, a search box, or a section of a report or story. Another common example is a portal page that allows the user to choose from a palette of features to display.

      • Global control over presentation. There should be a way to define one or more standard master templates used by most pages on a site, so that changes to the overall look and feel of a site can be made in one place.

      • Dynamic selection of presentation style. Given that the same data may be presented in many different ways, there should be a general mechanism for selecting a specific presentation (including file format, layout, character set and language) for each page request, depending on characteristics such as user preference, location, browser type and/or device.

      • Usability. Programmers should be able to develop template specifications using their standard tools for writing and maintaining code on the server. HTML authors should be able to access information about template specifications and work on templates remotely without needing shell access to the server.

    • What this package is not intended to allow users to accomplish.

      • Tcl "pages" that do not return anything visible to the user. Such pages may be, e.g., the action= target of a form. They typically call ad_returnredirect after completing their job.
      • Tcl scripts that are scheduled to run in the server without a connection to a user.

    • The application domains where this package is most likely to be of use.

      User interface. Any application that delivers visible pages to a user. Any page that returns content (HTML or other) in response to an HTTP[S] request.

    • How the package meets its requirements.

      • It supplies a set of custom markup tags.
      • The proc ad_page_contract (from the acs kernel) should be used to specify what makes the dynamic part of the page. There's also an API for creating forms and for creating and manipulating multirow data sources.
      • The mechanism for dynamically generating pages combines data and layout. It also allows coposition of modular pages from reusable widges and skins. It is not limited to HTML.
      • The <master> tag specifies a master template. Its src attribute defaults to the site-wide master template.

    III. Historical Considerations

    Karl Goldstein designed the templating system. First it was called "Karl's Templates" or "The New Templating System" to distinguish it from the obsolescent templates or "Styles" by Philip Greenspun. An extended and improved version was named "Dynamic Publishing System". It wasn't part of the ACS yet, but client projects like iluvCAMP used it successfully. Newcomers were consistently puzzled by the .data files, which specified the datasources in an apparently unfamiliar XML syntax. (The .form files specified elements in an HTML form similarly.) To mitigate this initial shock, Karl redesigned templates to let the programmer specify datasources and forms in a .tcl script. The system is present as packages templates and form-manager in ACS 3.4. Both these packages are now merged and appear as acs-templating starting in ACS 4.0. The architecture of the package was changed several times to meet the emerging coding/style constraints of ACS 4.0.

    V. Design Tradeoffs

    As indicated above, the primary attribute that the page tries to achieve is the separation of code and layout. The primary sacrifice is simplicity; in the typical case there will be two files (a .adp templage and a .tcl script) instead of a single .tcl page.

    Management of data sources. Through the various past versions of the package, it evolved that data sources should be set as Tcl variables and arrays. Earlier they were kept as lists of ns_sets, which was significantly less efficient. The datasources are not being copied around; they reside in a specific stack frame. Using the uplevel Tcl command, we make sure that the data file (tcl part of a page) executes in the same stack frame as the compiled template (the adp part), so the latter can make use of the data sources prepared by the former.
            Thus, we decided for performance, simplicity, and ease of use at the cost of using the (standard Tcl) commands upvar and uplevel, which is considered confusing and error-prone by reviewers (of 4.0). The use of these constructs has been reduced in 4.01, and the code is clearer now.

    Other attributes are affected as follows. In parentheses the estimated priorities are listed, not the degree to which the attributes are being achieved:

    • Performance (high): Early versions of the templating system were a compuational burden. This has been fixed. Thanks to compilation of .adp pages and caching of both .adp and .tcl parts as procs, templated pages are much faster now; the caching can in fact make a templated page faster than an old-style .tcl page, which is sourced and parsed on every request.
    • Flexibility (high): the recursive composition of pages allows for a big deal of flexibility.
    • Interoperability (low): The templating system must tie in with the request processor for delivery of pages and with ad_page_contract for the specification of the expected parameters (called query) and the datasources it will supply (called properties). The templating system is registered with the request processor as the handler for both adp and tcl extensions.
    • Reliability and robustness (medium): Considering how many parts have to play together, one might not predict a very reliable system. In practice, the package works reliably. It is robust to user errors in the sense that it won't error out if a file is missing or such; rather it quietly proceeds. Error reporting to the user is not very sophisticated.
    • Usability (high): Emphasis has been put on the easy use of the system. In particular, a graphics designer should only have to learn a small number of special markup tags.
    • Maintainability (medium): The code is well structured in reasonably sized procedures, and well commented.
    • Portability (high): Unlike most other parts of the ACS, the templating system can work standalone. It doesn't need the database nor the acs-kernel or any other part of the ACS. All you need is AOLserver with the fancy ADP parser.
    • Reusability (low): Many parts of the templating system are actually generally reusable, and probably should be extracted into a common set of utility procs used by this package and the ACS; this would reduce code duplication. The API lets programmers call into the system at different level. The templating system will probably mostly deliver HTML pages, but it has also been used to format mass mailings (spam), and any other formal (e.g., XML) could be used.
    • Testability(low): A demonstration sample page exercises most mechanisms of the templating system.

    VI. API

    Details are in the developer guide. Here we give an overview, and then the more obscure aspects of the current implementation.

    The most important abstraction is the data source, of which there are several kinds:

    • onevalue (string)
    • onerow
    • multirow
    • onelist
    • multilist

    Currently ad_page_contract does not allow specifying the latter two.

    Process Flow

    In a simple case, the following is the sequence of steps that serving a templated page involves.
    1. The request processor gets a url and maps it to a .adp or .tcl file. As both invoke the same handler, it doesn't matter that adp take precendence.
    2. If a .tcl file is present, its ad_page_contract in the -properties block indicates a set of data sources that will be made available to the template.
    3. The rest of the tcl script executes, defining these data sources. It may change the name of the page being served by calling template::set_file directly or through the wrapper ad_return_template.
    4. The corresponding template (file stub.adp) is interpreted and the data sources from the .tcl script are interpolated into the template.
    5. The HTML is streamed to the client by the handler.
    Less simple cases involve dependent templated pages. They are requested with the <include> and <master> tags. In these cases, TCL and/or ADP parsing happens recursively.

    Tcl Call Stack

    Below is a diagram of the typical call stack when processing a page without dependent pages. To conform to the Tcl notion of what's up and down (as in upvar), the stack grows down.

    Level Procedure Arguments
    #1rp_handler
    #2rp_serve_abstract_file /web/service/www/page
    #3rp_serve_concrete_file /web/service/www/page.adp
    #4adp_parse_ad_conn_file
    #5template::adp_parse /web/service/www/page {}
    (6) template::adp_prepare
    #5 template::code::tcl::/web/service/www/page

    Levels #1 to #3 exposed here are request processor internals. In the case shown, datasources reside in level #5. Due to the uplevel command, the frame of the sixth procedure is not accessible in the call stack at this moment, and the seventh runs in stack frame #5. If the <include> or <master> tags are used, adp_parse will be invoked recursively. Datasources always reside in the stack frame of an instance of adp_parse.

    To keep track of data sources of several page components, the templating system maintains a stack of their stack levels in the variable template::parse_level. In our case, it just contains 5. But if this page included another page or designated is as its master, the level of the next adp_parse would be pushed to the list, and popped when that proc returned. This next level will appear as #6, due to the repeated upleveling.

    Caching and Template Compilation

    To improve performance, adp pages are compiled into a tcl proc, and thus cached for future use. Tcl pages are also cached in a proc; this saves the trouble of reading and parsing the file the next time. The template system remembers the modification times of the adp and tcl sources, and re-processes any requested file if the cached version is no longer current. Consequently, this cacheing is transparent in normal use.

    To emphasize that "normal" use essentially always applies, here's a scenario for abnormal use: Save version n of a file at 11:36:05.1; request a page that uses it at 11:36:05.3; modify and save version n+1 of the file at 11:36:05.9. If you work that fast (!), the new version will have the same modification time -- kept with 1 second resolution in Unix --, and will not be refreshed.

    For timing measurements and performance tuning, you can set the parameter RefreshCache in section template to never or always. The former suppresses checking mtime and may improve performance on a production server, where the content pages don't change. The latter is only inteded for testing.

    VII. Data Model Discussion

    This packages doesn't need a data model.

    It comes with its own database interfaces, one for using ns_ora, the Oracle driver from ArsDigita, and one for ns_db, the builtin database interface of the AOL server. If you are programming under the ACS, you should use neither of these, but rather the db_* interface, in particular db_multirow.

    VIII. User Interface

    This packages doesn't have a user interface. It is the substrate of all user interfaces, be it user or admin pages.

    IX. Configuration/Parameters

    There are two parameters.
          [ns/server/yourservername/acs/template]
          ; the site-wide Master template
          DefaultMaster=/www/default-master
          ; anything other than "never" or "always" means normal operation
          RefreshCache=as necessary
        

    X. Future Improvements/Areas of Likely Change

    Passing datasources by reference is new. The acs-templating syntax &formal="actual" is different from the independent ATS, which used formal="@actual.*@". The latter is phased out.

    We intend to add a <which>, <switch>, or <case> tag, to complement sequential nested <if>/<else> constructs.

    Authors

    XII. Revision History

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Brought into the form suggested by Finkler, McLoghlin and Wu 18 Jul 2000 Christian Brechbühler
    0.2 Adapted to acs-templating as distributed with ACS/Tcl 4.01 22 Nov 2000 Christian Brechbühler


    Christian Brechbuehler
    Last modified: $Id: design.html,v 1.2 2002/09/13 16:46:30 jeffd Exp $ openacs-5.7.0/packages/acs-templating/www/doc/timing-3.html0000644000175000017500000000435207253523117023400 0ustar frankiefrankie Template Timing Results

    Results

    The measurements were taken on reusia.boston on 17 October 2000, with tarball acs-3-4-6-R20001008. Templating under 3.4 is quite different; instead of a .tcl script, datasources are defined in a .data file that has a different XML syntax.

    We have graphs for 9 stages only. While TCL pages generate four more entries, these lack from templated pages, and hence I suppressed them. The log message that marks the beginning of each phase is written in the lower right of the graphs. Each curve curve plots 288 page requests. As I didn't back port of the configurable cache refreshing stragegy ('never' or 'always'), I show all graphs in the 'normal' colors. The label is 'do', though.

    Individual Stages

    Total Time (Sum of all Stages)

    To show off the graphing method, compare the graph above with the one below, which only uses the first 32 measurements. The curves are less smooth, but the message is the same.

    In ACS 3.4.6, TCL only pages are sereved faster than in 4.0 beta-2. The templated pages are delivered much slower. The first time the template system reads a templated page, it takes about 3 seconds! The result is cached, mitigating the problem a lot.


    Christian Brechbuehler
    Last modified: Tue Oct 17 20:26:14 EDT 2000 openacs-5.7.0/packages/acs-templating/www/doc/index.html0000644000175000017500000000410610012145650023042 0ustar frankiefrankie Templates

    Templating System

    Templating System

    Document overview

    Requirements What the template system should do for you.
    Noquote A revision in 5.0 that escapes all html codes by default.
    Design Gets more specific and discusses the way the templating system integrates with ACS. Gory details.
    Designer Guide Writing a Template, the ADP part of a page
              Tags Template markup tag reference
    Using Noquote Upgrading and writing new pages with noquote.
    Developer Guide   API for programming the TCL part of a page
    API, TclDoc API Viewer     Object and API Reference
    Migration Bringing legacy tcl pages to use the template system.
    Demonstration Samples of the various mechanisms, with both TCL and ADP parts.

    Christian Brechbühler
    Last modified: $Id: index.html,v 1.4 2004/02/10 12:16:40 joela Exp $ openacs-5.7.0/packages/acs-templating/www/doc/install.html0000644000175000017500000001151307253523117023414 0ustar frankiefrankie Templating System: Installation

    Installation

    Templating System

    The templating system may be used alone or in conjunction with version 4.0 or greater of the ArsDigita Community System (ACS). The following instructions apply to a standalone installation only.

    Requirements

    The templating system requires version 3.1 or greater of AOLserver for Unix or Windows. Until version 3.1 is officially released, you must use the ArsDigita distribution of AOLserver 3.0, which includes some required patches to the ADP parser. These patches have been integrated into AOLserver 3.1.

    To use the database interface for merging dynamic data with your templates, you will also need to have installed any AOLserver-compatible RDBMS.

    Obtaining the distribution

    To install the templating system, download and unpack the tar file under your page root:

    $ wget http://bob.sf.arsdigita.com:8089/ats/ats.tar.gz
    $ cd /web/myserver/www
    $ gunzip -c ats.tar.gz | tar xvf -

    The distribution consists of four subdirectories:

    1. demo: A set of sample templates and supporting files.
    2. doc: Documentation and tutorials.
    3. tcl: The Tcl module.
    4. resources: Sitewide style templates for forms and error messages and associated assets.

    You can also untar (or check out) the distribution somewhere else and symlink it under your page root. (If you do not wish to install the distribution under your page root, see the configuration options below).

    Installing the Tcl module

    The templating system code is a Tcl-only module for AOLserver. For AOLserver to load the module source code, you must move, copy or symlink the tcl directory in the templating system distribution to the private Tcl library of your AOLserver installation (as indicated by the Library parameter in the ns/server/myserver/tcl section of the AOLserver configuration file):

    $ cd /web/myserver/tcl
    $ ln -s <path_to_distribution>/ats/tcl/ ats

    Configuring AOLserver

    The last step is to modify your AOLserver configuration file. You will need to register the templating system as a Tcl-only module:

    [ns/server/myserver/modules]
    nssock=nssock.so
    nslog=nslog.so
    ats=Tcl

    or if you are using the new configuration file format:

    ns_section "ns/server/${server}/modules"
    ns_param   nssock          nssock.so
    ns_param   nslog           nslog.so
    ns_param   ats          Tcl

    Note that you should replace ats with whatever you named the directory or symlink for the templating code within your private Tcl library.

    You will also need to ensure that the "fancy" ADP parser is the default:

    [ns/server/yourserver/adp]
    Map=/*.adp
    DefaultParser=fancy
    
    [ns/server/yourserver/adp/parsers]
    fancy=.adp

    Optional Configuration

    The templating system recognizes two optional parameters in the AOLserver configuration file in the ns/server/yourserver/ats section:

    DatabaseInterface Specifies the set of procedures to use for accessing a relational database from the templating system. Two interfaces are supplied with the system: oracle (uses the ns_ora API in conjunction with the AOLserver Oracle driver) and generic (uses the ns_db API in conjunction with any AOLserver RDBMS driver). The default is Oracle.
    ShowCompiledTemplatesP Enables a filter on the cmp extension so that the compiled Tcl code for any template may be viewed in a browser for debugging purposes. The default is 0 (disabled).
    ShowDataDictionariesP Enables a filter on the dat extension so that documentation directives in Tcl scripts may be extracted and viewed in a browser. The default is 1 (enabled).
    ResourcePath Specifies the absolute path to the system templates directory, containing sitewide styles for forms, system messages, etc. Defaults to [ns_info pageroot]/ats/resources.

    Testing the System

    To test the system, run the script demo/demo.sql to create and populate a simple table in your database.

    Save the configuration file and restart the server. Use the samples included in the distribution to test whether the system is working properly.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/timing.html0000644000175000017500000002367607253523117023252 0ustar frankiefrankie Timing a Templated Page

    Timing a Templated Page

    by Christian Brechbühler

    I. Introduction

    One of the requirements for the template system asks for efficiency:
    This page documents the attempt to verify this requirement.

    II. Methods

    I wrote a sample page for this test. It expands four real numbers into continued fractions. I created three versions:

    The reason for creating chain-frac-2.adp is that in this way, the script chain-frac-1.tcl is handled inside the templating system, and hence loaded once and cached. There is hope that this might be faster.

    Normally, the templating system re-reads a file whenever the version on disk is out of date. ADP pages are compiled to TCL, and both ADP and TCL pages are cached as TCL procs. The parameter RefreshCache in section template can be set to always or never to affect the cacheing strategy; the latter may be useful for a production site. All timing is carried out for the three settings always, normal, and never; the associated variable is called check.

    I created a script in e-Tester that requests the three pages from my development server on dev0103-001. One timing of requesting a page isn't very expressive. A lot of factors affect the page load time. To offset these and get better results, I repeatedly request the pages. For the timing, I have e-Tester iterate this script 200 times. To compesate for varying load on the machine, i ran the iteration twice for each setting of RefreshCache at different times of the day.

    The timing information is taken from the error log file entries that the request processor produces with parameter LogDebugP=1. For finer granularity I changed rp_debug to divide the clock clicks (microsecond) difference by 1000.0 instead of 1000. Delivering a page gives us 15 log file entries with timestamps. I treat the first one (? ms) as 0. There must be no other page requests from this AOLserver during the measurement. I note the length of the error log before and after one run of the script. Afterwards I cut out the error log sections indicated by these positions into files never, normal, and always.

    The following steps extract the relevant information and bring it in a form suitable for gnuplot.

    • Extract time from log file sections. This is done in tcsh.
      foreach i ( never normal always )
        fgrep '] Notice: RP (' $i                        >  $i-0
        echo                                             >  $i-1
        foreach conn (`cut -d- -f2 always-0 | sort -u`)
          echo "$i '$conn'"
          fgrep "[-$conn-]" $i-0 | cut -d: -f5-          >> $i-1
        end
        cut -d" " -f3 $i-1| cut -c2-| tr \? 0            >  $i-2
      end
      	
      The three resulting files, ending in -2, contain 18000 numbers, for 2 runs * 200 tries * 3 pages * 15 stages.
    • Group and sort times. The time one stage of processing takes is given by the difference of two time adjacent entries. This defines stage00 to stage13; I keep the total time in stage14. This is done by the TCL script dev0103-001:/home/brech/prog/tcl/timing.tcl, which generates the directories stage00 to stage14 and the ten files {0,1,2}-{never,normal,always}, and t_max in each of them. Each of the former files contains the 2*200 samples, ordered for graphing.

      III. Presentation

      Color Codes

      The different experiments are color coded as follows.
      nevernormalalways
      chain-frac-0      
      chain-frac-1      
      chain-frac-2      
      (They lie in the isoluminant plane in the middle of the RGB color space.)

      Presenting Distributions

      A number of statistic measures can summarize an ensemble of data, in our case, the 400 timings. The average is affected by outliers; the median is much more robust. Maybe some dispersion measure would be of interest, too. Some people plot histograms, but that approach is frought with its own problems. I chose to use all the data and plot estimated distribution functions. Our random variable being time T, its distribution function is defined as

      FT(t) = P[T <= t]   .
      It is sometimes referred to as cumulative density function. Its deriviative p(t) = F'(t) is the distribution density of the random variable T, which histograms approximate.

      The curve always increases monotonically from 0 to 1. In case of a normal distribution, you get the erf shape; for a uniform distribution it is a ramp. This form of presentation throws away no information, and it shows all about the distribution of a single variable. I am pretty sure the times that different stages of one request take are statistically dependent, but I don't consider that for the time being. The median is the abscissa t at which the ordinate F(t)=1/2.

      The curves for all nine experiments are drawn in the same graph for comparison. Note that the abscissa is scaled very differently for various stages.

      Steps

      • I scp the stage?? directories to my linux box, where gnuplot is installed. Another approach would be to install gnuplot on the machine that runs the server, i.e., dev0103-001.
      • The csh script plot-all goes into each stage?? subdirectory and runs the gnuplot script distrib.gplt:
           #! /bin/csh
           foreach i (stage[01][0-9])
             (cd $i; gnuplot ../distrib.gplt > $i.gif)
             echo $i done.
           end
        	

      IV. Results

      • graphs from dev0103-001, approximately acs-4-0-beta-R20001001.
      • graphs from reusia.boston, approximately acs-4-0-beta-2-R20001009.
      • graphs from reusia.boston, from ACS 3.4.6 tarball. This comparison is not completely fair.

      V. Conclusion

      Currently, the template system doesn't meet the performance requirement.

      Earlier on dev0103-001, templated pages loaded fast enough. Although the processing stage seems to a lot be more than 10% slower, the overall performance is rather increased than slowed by templating.

      On reusia.boston, we had a much better performance of the request processor. The processing times of the pages proper (stage 10 before, 11 now) didn't change much; we just got clearer results. The total processing time of TCL-only pages is around 155ms, while templated pages take around 220ms, that is 42% longer (or TCL-only pages take 30% less).

      Relative times depend on the other components of the pipeline. The difference of 65ms is a large percentage of a total serving time of 155ms; when other parts of the system (e.g., the request processor) were slower, this wasn't that noticeable.

      For ACS 3.4, TCL-only chain-frac-0 pages take 115ms, where the templated versisons are much slower, 320ms for chain-frac-1 and 340 for -2.

      VI. Further Work

      Tune templating in ACS 4.0.


      Christian Brechbühler
      Last modified: Tue Oct 17 20:11:49 EDT 2000 openacs-5.7.0/packages/acs-templating/www/doc/no-quote-upgrade.html0000644000175000017500000003525007723135514025150 0ustar frankiefrankie Upgrading existing ADPs to noquote templating

      Upgrading existing ADPs to noquote templating

      Introduction.

      The variable substitution in the templating has been changed to become more friendly towards quoting. The rationale for the change and the definition of terms like quoting are present in the quoting article. As it discusses these concepts in some depths, we see no reason to repeat them here. Instead, we will assume that you have read the previous article and focus on the topic of this one: the changes you need to apply to make your module conformant to the new quoting rules.

      This text is written as a result of our efforts to make the ACS installation for the German Bank project work, therefore it is based on field experience rather than academic discussion. We hope you will find it useful.

      Recap of the Theory.

      The change to the templating system can be expressed in one sentence:
      All variables are now quoted by default, except those explicitly protected by ;noquote.
      This means that the only way your code can fail is if the new code quotes a variable which is not meant to be quoted. Which is where ;noquote needs to be added. That's all porting effort that is required.

      This is not hard because most variables will not be affected by this change. Most variables either need to be quoted (those containing textual data that comes from the database or from the user) or are unaffected by quoting (numerical database IDs, etc.) The variables where this behavior is undesired are those that contain HTML which is expected to be included as part of the page, and those that are already quoted by Tcl code. Such variables should be protected from quoting by the ;noquote modifier.

      The Most Common Cases.

      The most common cases where you need to add ;noquote to the variable name are easy to recognize and identify.

      Hidden form variables.
      Also known as "hidden input fields", hidden form variables are form fields with pre-defined values which are not shown to the user. These days they are used for transferring internal state across several form pages. In HTML, hidden form variables look like this:

      <form>
        <input name=var1 value="value1">
        <input name=var2 value="value2">
        ... real form stuff ...
      </form>
            
      ACS has a convenience function for creating hidden form variables, export_form_vars. It accepts a list of variables and returns the HTML code containing the hidden input tags that map variable names to variable values, as found in the Tcl environment. In that case, the Tcl code would set the HTML code to a variable:
      set form_vars [export_form_vars var1 var2]
            
      The ADP will simply refer to the form_vars variable:
      <form>
        @form_vars@              <!-- WRONG!  Needs noquote -->
        ... real form stuff ...
      </form>
            
      This will no longer work as intended because form_vars will be, like any other variable, quoted, and the user will end up seeing raw HTML text of the hidden variables. Even worse, the browser will not be aware of these form fields, and the page will not work. After protecting the variable with ;noquote, everything works as expected:
      <form>
        @form_vars;noquote@
        ... real form stuff ...
      </form>
            

      Snippets of HTML produced by Tcl code, aka widgets.
      Normally we try to fit all HTML code into the ADP template and have the Tcl code handle the "logic" of the program. And yet, sometimes pieces of relatively convoluted HTML need to be included in many templates. In such cases, it makes sense to generate the widget programmatically and include it into the template as a variable. A typical widget is a date entry widget which provides the user the input and selection boxes for year, month, and day, all of which default to the current date.

      Another example of widgets is the context bar often found on top of ACS pgages.

      Obviously, all widgets should be treated as HTML and therefore adorned with the ;noquote qualifier. This also assumes that the routines that build the widget are correctly written and that they will quote the components used to build the widget.

      Pieces of text that are already quoted.
      This quoting is usually part of a more general preparation for HTML rendering of the text. For instance, a bboard posting can be either HTML or text. If it is HTML, we transmit it as is; if not, we perform quoting, word-wrapping, etc. In both cases it is obvious that quoting performed by the templating system would be redundant, so we must be careful to add ;noquote to the ADP.

      The property and include Gotchas.

      Transfer of parameters between included ADPs often requires manual addition of ;noquote. Let's review why.

      The property tag is used to pass a piece of information to the master template. This is used by the ADP whose writer consciously chose to let the master template handle a variable given by the Tcl code. Typically page titles, headings, and context bars are handled this way. For example:

      master:
      <head>
        <title>@title@</title>
      </head>
      <body bgcolor="#ffffff">
        <h1>@heading@</h1>
        <slave>
      </body>
            
      slave:
      <master>
      <property name="title">@title@</property>
      <property name="heading">@title@</property>
      ...
            
      The obvious intention of the master is to allow its slave templates to provide a "title" and a "heading" of the page in a standardized fashion. The obvious intention of our slave template is to allow its corresponding Tcl code to set a single variable, title, which will be used for both title and heading. What's wrong with this code?

      The problem is that title gets quoted twice, once by the slave template, and once by the master template. This is the result of how the templating system works: every occurrence of @variable@ is converted to [ad_quotehtml $variable], even when it is used only to set a property and you would expect the quoting to be suppressed.

      Implementation note: Ideally, the templating system should avoid this pitfall by quoting the variable (or not) only once, at the point where the value is passed from the Tcl code to the templating system. However, no such point in time exists because what in fact happens is that the template gets compiled into code that simply takes what it needs from the environment and then does the quoting. Properties are passed to the master so that all the property variables are shoved into an environment; by the time the master template is executed, all information on which variable came from where and whether it might have already been quoted is lost.

      This occurrence is often referred to as over-quoting. Over-quoting is sometimes hard to detect because things seem to work fine in most cases. To notice the problem in the example above (and in any other over-quoting example), the title needs to contain one of the characters <, > or &. If it does, they will appear quoted to the user instead of appearing as-is.

      Over-quoting is resolved by adding ;noquote to one of the variables. We strongly recommend that you add ;noquote inside the property tag rather than in the master. The reason is that, first, it makes sense to do so because conceptually the master is the one that "shows" the variable, so it makes sense that it gets to quote it. Secondly, a property tag is supposed to merely transfer a piece of text to the master; it is much cleaner and more maintainable if this transfer is defined to be non-lossy. This becomes important in practice when there is a hierarchy of master templates -- e.g. one for the package and one for the whole site.

      To reiterate, a bug-free version of the slave template looks like this:

      slave sans over-quoting:
      <master>
      <property name="title">@title;noquote@</property>
      <property name="heading">@title;noquote@</property>
      ...
            

      The exact same problems when the include statement passes some text. Here is an example:

      Including template:
      <include src="user-kick-form" id=@kicked_id@ reason=@default_reason@>
            
      Included template:
      <form action="do-kick" method=POST>
        Kick user @name@.<br>
        Reason: <textarea name=reason>@reason@</textarea><br>
        <input type=submit value="Kick">
      </form>
            
      Here an include statement is used to include an HTML form widget parts of which are defined with Tcl variables $id and $default_reason whose values presumably come from the database.

      What happens is that reason that prefills the textarea is over-quoted. The reasons are the same as in the last example: it gets quoted once by the includer, and the second time by the included page. The fix is also similar: when you transfer non-constant text to an included page, make sure to add ;noquote.

      Including template, sans over-quoting:
      <include src="user-kick-form" id=@kicked_id@ reason=@default_reason;noquote@>
            

      Upgrade Overview.

      Upgrading a module to handle the new quoting rules consists of applying the process mentioned above to every ADP in the module. Using the knowledge gained above, we can specify exactly what needs to be done for each template. The items are sorted approximately by frequency of occurrence of the problem.
      1. Audit the template for variables that export form variables and add ;noquote to them.

      2. More generally, audit the template for variables that are known to contain HTML, e.g. those that contain widgets or HTML content provided by the user. Add ;noquote to them.

      3. Add ;noquote to variables used inside the property tag.

      4. Add ;noquote to textual variables whose values are attributes to the include tag.

      5. Audit the template for occurrences of <%= [ad_quotehtml @variable@] => and replace them with @variable@.

      6. Audit the Tcl code for occurrences of ad_quotehtml. If it is used to build an HTML component, leave it, but take note of the variable the result gets saved to. Otherwise, remove the quoting.

      7. Add ;noquote to the "HTML component" variables noted in the previous step.
      After that, test that the template behaves as it should, and you're done.

      Testing.

      Fortunately, most of the problems with automatic quoting are very easy to diagnose. The most important point for testing is that it covers as many cases as possible: ideally testing should cover all the branches in all the templates. But regardless of the quality of your coverage, it is important to know how to conduct proper testing for the quoting changes. Here are the cases you need to watch out for.
      • HTML junk appearing in the page.
        Literal HTML visible to the user typically comes from an "export_form_vars" or a widget variable that lacks ;noquote. To fix the problem, simply add ;noquote to the variable.

      • Over-quoting and under-quoting.
        To detect quoting defects, you need to assume an active role in naming your objects. The best way to do it is to create objects (bboard forums, messages, news items, etc.) with names that contain the representation of an entity, e.g. "&copy;". This looks like the copyright SGML entity, and intentionally so. The testing consists of checking that the browser prints exactly what you typed in as the name. Thus if your forum/message/etc. is listed as "&copy;", everything is OK. If it is listed as "&amp;copy;", it means that the string was quoted twice, i.e. over-quoted. Finally, if the entity is interpreted (shown as ©), it means that the string lacks quoting, i.e. it is under-quoted.

        To get rid of over-quoting, make sure that the variables don't get quoted in transport, such as in the property tag or as an attribute of the include tag. Also, make sure that your Tcl code is not quoting the variable name.

        To get rid of under-quoting, make sure that your variable gets quoted exactly once. This can be achieved either by removing a (presumably overzealous) ;noquote or by quoting the string from Tcl. The latter is necessary when building HTML components, such as a context bar, from strings that come from the database or from the user.


      Hrvoje Niksic
      Last modified: Mon Oct 7 12:27:47 CEST 2002 openacs-5.7.0/packages/acs-templating/www/doc/introduction.html0000644000175000017500000000512707253523117024473 0ustar frankiefrankie Templating System: Goals

      Goals

      Templating System

      The overall goal of the templating system is to provide the publishing team with a set of tools for simplifying the development and maintenance of the user interface. In particular:

      • A common solution. Programmers and designers should only have to learn a single system that serves as a UI substrate for all the functionally specific modules used on a site. The system should not make any assumptions about how pages should look or function. Designers should be able to change the default presentation of any module using a single metholodogy with minimal exposure to code.

      • Separation of code (Tcl, Java and SQL) and layout (HTML). Programmers should be able to specify the data sources and other properties of the template independently of the HTML template used to present the data. HTML authors should be able to write templates that reference the data sources and properties without further intervention from the programmer to produce a finished page.

      • Separation of page components. There should be provisions so that pages can be broken into discrete components to simplify maintenance of the HTML code and allow for reuse in different contexts. Examples of common page components include a navigation bar, a search box, or a section of a report or story. Another common example is a portal page that allows the user to choose from a palette of features to display.

      • Global control over presentation. There should be a way to define one or more standard master templates used by most pages on a site, so that changes to the overall look and feel of a site can be made in one place.

      • Dynamic selection of presentation style. Given that the same data may be presented in many different ways, there should be a general mechanism for selecting a specific presentation (including file format, layout, character set and language) for each page request, depending on characteristics such as user preference, location, browser type and/or device.

      • Usability. Programmers should be able to develop template specifications using their standard tools for writing and maintaining code on the server. HTML authors should be able to access information about template specifications and work on templates remotely without needing shell access to the server.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/todo.html0000644000175000017500000000053107253523117022711 0ustar frankiefrankie

      Data Source API

      We need to resolve how onerow and multirow data sources are represented internally, and plug in the proper API. I originally used ns_sets to represent rows in a data source (and continue to do so for the time being). jsalz instead uses arrays and lists to represent rows. Task: look at jsalz's data source code. openacs-5.7.0/packages/acs-templating/www/doc/tagref/0000755000175000017500000000000011724401447022326 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/tagref/include-optional.html0000644000175000017500000000277710016631220026462 0ustar frankiefrankie Templating System Tag Reference: include-optional

      Include

      Templating System : Designer Guide : Tag Reference : include-optional

      Summary

      The include-optional tag is used to include another template in the current template, but make some other chunk dependent on whether or not the included template returned something.

      This is useful if, say, you want to wrap the template with some HTML, for example, a frame in a portal, but if there's nothing to show, you don't want to show the frame either.

      Usage

      <include-optional src="blog-months">
        <tr>
          <th bgcolor="@header_background_color@">
            Archive
          </th>
        </tr>
        <tr>
          <td nowrap align="center">
            <include-output>
          </td>
        </tr>
        <tr>
          <td height="16">
            <table><tr><td></td></tr></table>
          </td>
        </tr>
      </include-optional>
      

      Notes

      • The output of the included template will be put where the <include-output> appears.

      Tag added by: Lars Pinds (lars@collaboraid.net)
      Documentation added from sources on Nov 2002, Roberto Mello.
      openacs-5.7.0/packages/acs-templating/www/doc/tagref/group.html0000644000175000017500000000611210021414164024335 0ustar frankiefrankie Templating System Tag Reference: Group

      Group

      Templating System : Designer Guide : Tag Reference : Group

      Summary

      The group tag is used only within the body of a multiple tag to provide additional formatting control between subsets of a multirow data source. The tag takes a column name from the enclosing multiple tag as its only attribute. It repeats a template section as long as the value of the column does not change from row to row.

      The group tag also sets two additional values in your multirow:

      • groupnum is the rownum within the innermost group tag, starting from 1, 2, 3, etc.
      • groupnum_last_p is a boolean saying whether this is the last row inside the current group tag, before the value of column changes. Note, however, that this only works inside the inner-most group if you have multiple group tags nested within each other.

      Usage

      <table>
      
      <multiple name="shirts">
      
        <!-- Start a new row if the style changes -->
      
        <tr>
          <td>
            @shirts.style@
          </td>
          <td>
      
        <!-- List colors for the same style in a single cell -->
      
        <group column="style">
          @shirts.color@
      
          <!-- @shirts.groupnum@ will be the number of the color within the style -->
      
          <if @shirts.groupnum_last_p@ false>, </if>
          <else>, or </if>
      
        </group>
      
        <!-- End the row if the style is going to change on the next row
      
          </td>
        </tr>
      
      </multiple>
      
      </table>

      [Note: Carsten added this feature during the Berlin Hackaton 2004-02-14]

      The delimiter attribute will add a string after each row except the last row in the group:

        <group delimiter=" | ">
        ...
      

      This attribute will cause the rows within the group to appear to be sepparated by vertical bars. This is much more convenient than using the <groupnum_last_p> tags to check whether we are on the last row.

      Notes

      • Group tags may be nested to perform even more complex formatting.

      • Be careful when nesting several group tags. The group tag works very narrowly - it only looks at the column you provide it with and so long as that column doesn't change, it keeps looping. E.g. if you have 3 levels and the value of the outermost column changes but the value of the middle column doesn't, the inner group tag won't notice and will continue to loop. A workaround would be to create a derived column, which contains e.g. "$f1,$f2", and use that as the column for the inner group tag. (See also this bug).


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/switch.html0000644000175000017500000000427410016631220024507 0ustar frankiefrankie Templating System Tag Reference: Switch

      Switch

      Templating System : Designer Guide : Tag Reference : Switch

      Summary

      The switch tag is used to output one of n-sections when the switch variable matches one of the n-case statements. A default section can also be output if none of the n-case statements matches the switch variable.

      Usage Examples

      <switch @x@>
          <case value="Fred">
               Hello Fred.
          </case>
          <case value="Greta">
               Hello Greta.
          </case>
          <case value="Sam">
               Hello Sam
          </case>
          <default>
               I don't recognize your name.
          </default>
      </switch>
      

      Tcl-equivalent flags have the same meaning as in the tcl-switch statement. Supported flags include exact, glob, and regexp.

      <switch flag=glob @x@>
          <case value="F*">
               Hello Fred.
          </case>
          <case value="G*">
               Hello Greta.
          </case>
          <case value="H*">
               Hello Sam
          </case>
          <default>
               You are in the section for people whose names start with F, G, or H.
          </default>
      </switch>
      

      Case tags also have an alternative form for matching a list of items.

      <switch @x@>
          <case in "Fred" "Greta" "Sam">
               Your must be Fred Greta or Sam, but I'm not sure which one.
          </case>
          <default>
               I don't recognize your name.
          </default>
      </switch>
      

      Notes

      • Any legal variables that may be referenced in the template may also be used in switch statements.

      • Phrases with spaces in them must be enclosed in double quotes and curly braces to be matched correctly. Failure to quote words with spaces correctly results in an error.

          <case "{blue sky}">
            <td bgcolor=#0000ff>
          </case>

      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/formgroup.html0000644000175000017500000000504010016631220025216 0ustar frankiefrankie Templating System Tag Reference: Formgroup

      Formgroup

      Templating System : Designer Guide : Tag Reference : Formgroup

      Summary

      The formgroup tag is used to lay out a set of check boxes or radio buttons in a dynamic form template. All the check boxes or radio buttons in a group share the same name. A button group must be created as an element in the Tcl script associated with the template.

      Usage

        <formtemplate id="choose_services">
          <table>
            <formgroup id=services>
               <tr><td>@formgroup.widget@</td><td>@formgroup.label@</td></tr>
            </formgroup>
          </table><br>
        <input type=submit value="Submit">
        </formtemplate>
      

      Notes

      • The formgroup tag contains a template for formatting each check box or radio button in the group. The tag makes a special multirow data source named formgroup available in the body of the tag. The formgroup data source includes two columns. The first is widget, containing an HTML input tag for one of the buttons in the group. The second is label, containing a corresponding label for the button.

      • The formgroup tag may emulate either the multiple or grid tags in repeating the template section within the tag. By default it emulates the multiple tag. If the cols attribute is specified, the formgroup tag will emulate the grid tag.

      • HTML attributes, including JavaScript event handlers, may be specified as attributes to the formgroup tag. The system will include all such attributes in the input tags of each radio button or check box in the group.

        <formgroup id="services" onChange="validate();">
      • See the formtemplate and formwidget tags for more information on writing the body of a dynamic form template.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/multiple.html0000644000175000017500000000561110016631220025035 0ustar frankiefrankie Templating System Tag Reference: Multiple

      Multiple

      Templating System : Designer Guide : Tag Reference : Multiple

      Summary

      The multiple tag is used to repeat a template section for each row of a multirow data source. Column variables are reset with each repetition to the values of the next row of the data source.

      Usage

      <!-- Begin multiple layout, i.e. <table> -->
      <table>
      
      <multiple name="users">
      
        <!-- Row layout, i.e. <tr>...</tr> -->
        <tr>
      
          <td>
           @users.first_name@
          </td>
      
          <td>
            @users.last_name@
          </td>
      
          <td>
            @users.state@
          </td>
      
        </tr>
      
      </multiple>
      
      <!-- End multiple layout, i.e. </table> -->
      </table>

      Notes

      • The special variable datasource:rowcount may be used to check for no rows in a data source (or any other special condition related to the number of rows in the data source).

      • The special column datasource.rownum is set implicitly for each repetition and can be used in conjunction with the if tag to do row banding:

          <multiple>
        
          <if @datasource.rownum@ odd>
            <tr bgcolor=#eeeeee>
          </if>
        
          <if @datasource.rownum@ even>
            <tr bgcolor=#ffffff>
          </if>
        
          ...
        
      • The maxrows attribute may be used to limit the number of rows that are output from the data source:

          <multiple maxrows="n">
          ...
        

        This attribute will cause processing to stop after n rows have been output.

      • The startrow attribute may be used to skip a number of rows at the beginning of the data source:

          <multiple startrow="n">
          ...
        

        This attribute will cause processing of the data source to begin at row n + 1.

      • [Note: Carsten added this feature during the Berlin Hackaton 2004-02-14]

        The delimiter attribute will add a string after each row except the last row:

          <multiple delimiter=" | ">
          ...
        

        This attribute will cause the rows to appear to be sepparated by vertical bars. This is much more convenient than using the <if> tags to check whether we are on the last row.

      • The startrow and maxrows attributes may be used together to output any range from the data source.

      • See the group tag for formatting subsets of a multirow data source. In the current implementation, the <multiple> tag does not nest.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/slave.html0000644000175000017500000000164110016631220024313 0ustar frankiefrankie Templating System Tag Reference: Slave

      Slave

      Templating System : Designer Guide : Tag Reference : Slave

      Summary

      The slave tag is used to mark the position in the master template where the body template should be inserted.

      Usage

      <html>
      <head><title>@title@</title></head>
      <body>
      <h2>@title@</h2>
      <hr>
      <blockquote>
        <slave>
      </blockquote>
      <hr>

      Note(s)

      • See property and master for more information related to master templates.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/noparse.html0000644000175000017500000000207607253523117024671 0ustar frankiefrankie Templating System Tag Reference: Noparse

      Noparse

      Templating System : Tag Reference

      Summary

      The noparse tag is used to protect template tags that should not be parsed. It is useful when templates are generated dynamically. For example, the templating system uses the noparse tag in the "style" templates used for auto-generated forms.

      Usage

      <noparse>
        <multiple name=cars>
          \@cars.make\@
          \@cars.model\@
        </multiple>
      </noparse>
      

      Note(s)

      • Normal variable references are interpreted, even within a noparse tag. This is useful for generating templates where the attributes of the output template (such as references to component templates in an include tag or to form elements in a formwidget tag) must be


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/index.html0000644000175000017500000000760707610666757024355 0ustar frankiefrankie Template Markup Tag Reference

      Template Markup Tag Reference

      Templating System : Designer Guide : Tag Reference

      Overview

      The publishing system implements a small number of special markup tags that allow template authors to add dynamic features to their work. The tags allow authors to accomplish four basic tasks that are not possible with standard HTML:

      • Embed a dynamic variable in a template (variables).
      • Repeat a template section for each object in a dynamic list of objects (multiple, grid).
      • Output different template sections depending on the value of one or more dynamic variables (if).
      • Provide a mechanism for building complete pages from multiple component templates (include).

      Available Tags

      Notes

      • Template tags are processed by the server each time a page is requested. The end result of this processing is a standard HTML page that is delivered to the user. Users do not see template tags in the HTML source code of the delivered page.

      • With normal usage, the use of dynamic tags tends to increase the amount of whitespace in the final HTML as compared to the template. This usually does not affect how browsers display the page. However, if a page layout depends on the presence or absence of whitespace between HTML tags for proper display, then special care must be taken with dynamic tags to avoid adding whitespace.

        When placed on a line by themselves, tags that are containers for template sections (grid, if, and multiple) will cause newlines to be added to the page at the beginning and end of the section. This can be avoided by crowding the start and end tags like so:

        <td><if %x% eq 5><img src="five.gif"></if>
        <else><img src="notfive.gif"></else></td>
        	

        Note that this should not be done unless necessary, since it reduces the legibility of the template to others who need to edit the template later.


      Christian Brechbühler
      Last modified: $Id: index.html,v 1.4 2003/01/14 01:54:55 danw Exp $ openacs-5.7.0/packages/acs-templating/www/doc/tagref/master.html0000644000175000017500000000206610016631220024476 0ustar frankiefrankie Templating System Tag Reference: Master

      Master

      Templating System : Designer Guide : Tag Reference : Master

      Summary

      The master tag is used to specify the relative or absolute URL of another template to serve as a frame for the current template. The entire contents of the current template are inserted into the master template at a position designated by the slave tag in the master template.

      Usage

      <master src="master">
      
      <property name="title">My Home Page</property>
      
      <p>Welcome to my home page!</p>
      
      ...
      

      Note(s)

      • See property and slave for more information related to master templates.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/include.html0000644000175000017500000000616410041311144024627 0ustar frankiefrankie Templating System Tag Reference: Include

      Include

      Templating System : Designer Guide : Tag Reference : Include

      Summary

      The include tag is used to include a dynamic subtemplate into the current template. Subtemplates are evaluated in the same fashion as any other dynamic template; the developer may associate data sources and other properties to them.

      Usage

      <include src="subtemplate" attribute=value ...>
      or
      <include src="/packages/packagename/www/lib/subtemplate" attribute=value ...>

      Notes

      • Arguments may be passed to the subtemplate by specifying additional attributes to the include tag. All attributes except for src are assumed to be arguments and are set as variables which the subtemplate may reference using the var tag. To pass a dynamic variable to the subtemplate, specify the variable name surrounded by at signs as the value:
        <include src="subtemplate" source_id="@source_id@" ...>
        To pass a datasource, e.g. users, by reference, use this notation:
        <include src="subtemplate" &persons="users" ...>
        This is particularly useful for passing onerow and multirow data sourced. Note that in this case, if the subtemplate modifies the value this will affect the includer. When the datasource in the included page has the same name (&users="users"), you can use the shorthand &="users".
      • It is important to note that variables passed through include become available to the .tcl and .adp files being include'd, but it does not make them settable through ad_page_contract.

        So if you'd like to have a template that will return a fragment of a page that you'd like to include in other pages, make sure its .tcl component does not call ad_page_contract.

        If you'd like to include a full page (that is, one which calls ad_page_contract) then instead of passing a parameter through <include>, you could use rp_form_put to add the variable to that page's form. For additional references, see how message-chunk is used throughout the forums package.

      • If the src attribute begins with a slash, the path is assumed to be relative to the server root, the parent directory of the tcl library. If not, the path is assumed to be relative to the current template, not the URL of the page request.
      • If the page layout is sensitive to additional whitespace surrounding the subtemplate, then care must be taken that the subtemplate does not contain any blank lines at the beginning or end of the file.

      openacs-5.7.0/packages/acs-templating/www/doc/tagref/formtemplate.html0000644000175000017500000000461610016631220025705 0ustar frankiefrankie Templating System Tag Reference: Formtemplate

      Formtemplate

      Templating System : Designer Guide : Tag Reference : Formtemplate

      Summary

      The formtemplate tag is used to embed a dynamic form in a template. The elements of the form must be created in the Tcl script associated with the template.

      Usage

        <formtemplate id="add_user">
        <table>
        <tr>
          <td>First Name</td><td><formwidget id="first_name"></td>
        </tr>
        <tr>
          <td>Last Name</td><td><formwidget id="last_name"></td>
        </tr>
        </table><br>
        <input type=submit value="Submit">
        </formtemplate>
      

      Notes

      • The formtemplate tag takes the place of the form tag in a static HTML form. Explicit form tags in the template should not be used to enclose dynamic forms.

      • If the body of the formtemplate is empty, the templating system will generate a form automatically based on the list of elements created in the Tcl script associated with the template:

        <formtemplate id="add_user" style="standard"></formtemplate>

        The style attribute is optional. It may be used to select a style template from /ats/templates/forms for determining the layout of the auto-generated form. The default style is defined in the DefaultFormStyle parameter on the acs-templating package, and is by default set to standard, which is included in the distribution.

      • HTML attributes, including JavaScript event handlers, may be specified as attributes to the formtemplate tag. The system will include all such attributes in the form tag of the rendered HTML form.

        <formtemplate id="add_user" onSubmit="validate();">

        This will work for both autogenerated and explicitly formatted forms.

      • See the formwidget and formgroup tags for more information on writing the body of a dynamic form template.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/grid.html0000644000175000017500000000443610016631220024133 0ustar frankiefrankie Templating System Tag Reference: Grid

      Grid

      Templating System : Designer Guide : Tag Reference : Grid

      Summary

      The grid tag is used to output each row of a multirow datasource as a cell of an n column grid.

      Usage

      <!-- Begid grid layout, i.e. <table> -->
      <table>
      
      <grid name="datasource" cols="n">
      
        <if @datasource.col@ eq 1>
          <!-- Begin row, i.e. <tr> -->
          <tr>
        </if>
      
        <!-- Cell layout, i.e. <td>...</td> -->
        <td>
      
          <!-- Cells may be unoccupied at the end. -->
          <if @datasource.rownum@ le @datasource:rowcount@>
            ...
            @datasource.variable@
            ...
          </if>
      
          <else>
            <!-- Placeholder to retain cell formatting -->
             
          </else>
      
        </td>
      
        <if @datasource.col@ eq "n">
          <!-- End row, i.e. </tr> -->
          </tr>
        </if>
      
      </grid>
      

      Notes

      • Rows from the data source are output in column-first order. For example, if a datsource has 10 datasources and the grid has 3 columns, the rows from the datasource will appear in the following order:

        1 5 9
        2 6 10
        3 7  
        4 8  

      • The @datasource.row@ variable can be used to band grid rows:

          <if @datasource.col@ eq 1 and @datasource.row@ odd>
            <tr bgcolor=#eeeeee>
          </if>
        
          <if @datasource.col@ eq 1 and @datasource.row@ even>
            <tr bgcolor=#ffffff>
          </if>
        

        Note that this is different from the multiple tag, where the @datasource.rownum@ is used for this effect.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/list.html0000644000175000017500000000207510016631220024156 0ustar frankiefrankie Templating System Tag Reference: List

      List

      Templating System : Designer Guide : Tag Reference : List

      Summary

      The list tag is used to repeat a template section for each item in a list data source.

      Usage

      <list name="datasource">
      
        <if @datasource:rownum@ ne @datasource:rowcount@>
          @datasource:item@ :
        </if>
        <else>
          <b>@datasource:item@</b>
        </else>
      
      </list>

      Notes

      • The special variable datasource:rownum has the same meaning as the special column datasource.rownum in the body of a multiple tag.

      • The special variable datasource:rowcount has the same meaning in the list context as it does for multirow data sources.


      templating@arsdigita.comopenacs-5.7.0/packages/acs-templating/www/doc/tagref/formerror.html0000644000175000017500000000604410016631220025220 0ustar frankiefrankie Templating System Tag Reference: formerror

      formerror

      Templating System : Designer Guide : Tag Reference : formerror

      Summary

      The formerror tag is used to specify the presentation of a form validation error.

      Usage

        <formtemplate id="add_user">
        <table>
        <tr>
          <td>First Name</td>
          <td>
            <formwidget id="first_name">
            <formerror id="first_name" type="no_special_characters">
            The first name may not not contain special characters such as 
            @, $, !, %, & or #.
            </formerror>
          </td>
        </tr>
        </table><br>
        <input type=submit value="Submit">
        </formtemplate>
      

      Another example:

        <formtemplate id="add_user">
        <table>
        <tr>
          <td>First Name</td>
          <td>
            <formwidget id="first_name">
          </td>
        </tr>
        <formerror id="first_name">
        <tr>
          <td colspan="2"><font color="red">@formerror.first_name@</font></td>
        </tr>
        </formerror>
        </table><br>
        <input type=submit value="Submit">
        </formtemplate>
      

      This adds another table row which contains the error message for that widget in red color. If there is no error then the table row will not be added.

      Notes

      • The contents of the formerror tag may appear on the form when a submission is returned to the user for correction.

      • The contents of the tag may use the special variables label and value to refer to the element label and submitted value.

      • You can use the variable @formerror.element_id@ to refer to the automatically generated error message within the formerror tags.

      • The type attribute is optional and is used to distinguish messages for specific types of validation errors. Each element may have any number of error messages associated with it, corresponding to each of the validation checks performed by the developer in the script associated with template.

      • If the contents of the tag are empty (<formerror></formerror>), the message specified by the developer in the script are inserted when appropriate. This is particularly useful for international sites, where locale-dependent messages may be stored in the database.

      • If the type attribute is not specified and the contents of the tag are empty, all appropriate messages are inserted (separated by <,br> tags).

      • See the formwidget and formgroup tags for more information on writing the body of a dynamic form template.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/if.html0000644000175000017500000001147310016631220023603 0ustar frankiefrankie Templating System Tag Reference: If

      If

      Templating System : Designer Guide : Tag Reference : If

      Summary

      The if tag is used to output a template section only when certain conditions are met.

      Usage Examples

      <if @x@ eq 5>True</if>
      <if @x@ eq "Greta">True</if>
      
      <if @x@ ne 5>True</if>
      <if @x@ ne "Greta">True</if>
      
      <if @x@ lt 5>True</if>
      <if @x@ le 5>True</if>
      
      <if @x@ gt 5>True</if>
      <if @x@ ge 5>True</if>
      
      <if @x@ odd>True</if>
      <if @x@ even>True</if>
      
      <if @x@ between 3 6>True</if>
      <if @x@ not between 3 6>True</if>
      
      <if @x@ eq 5 and @y@ eq 2>True</if>
      <if @x@ ge 5 or @y@ le 2>True</if>
      
      <if @s@ nil>True</if>
      <if @s@ not nil>True</if>
      
      <if @z@ in "Greta" "Fred" "Sam">True</if>
      <if @z@ not in "Greta" "Fred" "Sam">True</if>

      Expression Syntax

      The condition of the <if> tag is built from terms of the form
      x0 [not] op x1 x2 ...
      The operator op determines the number operands (x0, ... xn-1).

      The following operators are available:

      • binary
        • x0 gt  x1
        • x0 ge  x1
        • x0 lt  x1
        • x0 le  x1
        • x0 eq  x1
        • x0 ne  x1
      • n-ary
        • x0 in  x1 x2 x3 ...
      • ternary
        • x0 between  x1 x2
      • unary
        • x0 nil
        • x0 defined
        • x0 odd
        • x0 even
        • x0 true
        • x0 false

      Any of these operators can be prefixed with not to invert the outcome.

      Notes

      • Any legal variables that may be referenced in the template may also be used in if statements. Words not surrounded with the commerical at sign (@) are interpreted literally.

      • Phrases with spaces in them must be enclosed in quotes to be grouped correctly:

          <if @datasource.variable@ eq "blue sky">
            <td bgcolor=#0000ff>
          </if>
      • The elseif tag may be used following an if block to specify an alternate conditional template section.

          <if @datasource.variable@ eq "blue">
            <td bgcolor=#0000ff>
          </if>
          <elseif @datasource.variable@ eq "red">
            <td bgcolor=red>
          </elseif>
          <else>
            <td bgcolor=#ffffff>
          </else>
      • The else tag may be used following an if block to specify an alternate template section when a condition is not true:

          <if @datasource.variable@ eq "blue">
            <td bgcolor=#0000ff>
          </if>
          <else>
            <td bgcolor=#ffffff>
          </else>
      • Compound expressions can be created by combining terms with the and and or keywords, as illustrated above. Any number of statements may be connected in this fashion. There is no way to group statements to change the order of evaluation.

      • When a variable is tested using the nil operator, it will return true if the variable is undefined or if the value of the variable is an empty string.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/formwidget.html0000644000175000017500000000364410016631220025355 0ustar frankiefrankie Templating System Tag Reference: Formwidget

      Formwidget

      Templating System : Designer Guide : Tag Reference : Formwidget

      Summary

      The formwidget tag is used to position a form element in a dynamic form template. The element itself must be created in the Tcl script associated with the template.

      Usage

        <formtemplate id="add_user">
        <table>
        <tr>
          <td>First Name</td><td><formwidget id="first_name"></td>
        </tr>
        <tr>
          <td>First Name</td><td><formwidget id="first_name"></td>
        </tr>
        </table><br>
        <input type=submit value="Submit">
        </formtemplate>
      

      Notes

      • The formwidget tag takes the place of input and select tags in static HTML forms. The system substitutes these tags with the appropriate HTML tags, complete with their proper values, options and other attributes, while rendering the template. Explicit form tags in the template may be used in special circumstances, but should be avoided wherever possible.

      • HTML attributes, including JavaScript event handlers, may be specified as attributes to the formwidget tag. The system will include all such attributes in the input or select tag of the rendered HTML form.

        <formwidget id="cc_number" onChange="validate();">
      • See the formtemplate and formgroup tags for more information on writing the body of a dynamic form template.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/property.html0000644000175000017500000000202510016631220025062 0ustar frankiefrankie Templating System Tag Reference: Property

      Property

      Templating System : Designer Guide : Tag Reference : Property

      Summary

      The property tag is used to set display attributes of the page. The contents of the tag may be plain text, static HTML, or a dynamic template that references local data sources. Properties are most commonly used to pass information to a master template, such as a title or logo.

      Usage

      <master src="master">
      
      <property name="title">My Home Page</property>
      
      <p>Welcome to my home page!</p>
      
      ...
      

      Note(s)

      • See master and slave for more information about master templates.


      templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/tagref/variable.html0000644000175000017500000000243110016631220024764 0ustar frankiefrankie Templating System Tag Reference: Variables

      Variables

      Templating System : Designer Guide : Tag Reference : Variables

      Summary

      Variables are used in templates as placeholders for dynamic data.

      Usage

      Simple variables are referenced by surrounding the variable name with "commercial at" (@) signs:

      <!-- simple variables -->
      <b><i>@first_name@ @last_name@</b></i>

      When processing this template, the server will look for variables named first_name and last_name and substitute their values in the output:

      <b><i>Fred Finkel</b></i>

      The columns of a row variable are referenced by separating the data source name and column with a period:

      <!-- onerow or multirow data sources -->
      <b><i>@user.first_name@ @user.last_name@</b></i>

    Note(s)

    • An attempt to reference a variable that does not exist will cause an error message to appear in the browser.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/time3a/0000755000175000017500000000000011724401447022240 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/time3a/stage00.gif0000644000175000017500000003021407253523117024173 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠ„ŠÿŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠŠŠŠ…‰ŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠ„"&*.2466666466664666$46666&466666466666466666466666466666466664666 "&*.26:>BFJNRVZ^bfjnrvz~‚†2ˆ~ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠvˆ~ˆŠŠŠŠŠŠŠŠŠŠÿB"&*, ,    ,...,....*"&*.26:>BFJNRVZ^bf""&* "&*.24  0  "&(*****"&*.26:>BFJNRVZ^"&*"&*.26:>B@     "&(*****(***********ÿ**********"&* "&*.26:>BFJNL  "&**,.............&"&* "&*.26:>BFJNRV6X    "&* ,....*,........""&*"&*.26:>BFJNRVZ^^`   `b&`ÿbF`bb"&*.26:>BFJNRVZ^bfjh   hjhj6hjfhjjjjjjjjjjjjj*"   $&&&&&$&&&&&& $&&&&&&&"&*.26:>BFJNRVZ^bfjF"& (******(*****(******"&*.26:>BFJNRVZ^bfj2ÿ"&(******(*****(******"&*.26:>BFJNRVZ^bfj"&* ,.....&,....*,.....&"&*.26:>BFJNRVZ^bfjln"lnZlllnRlnnnnnnnnnnnnln 4 lflllnRlnnnnnnnnnnnnln4 "&(*(**(******ÿ"&*.26:>BFJNRVZ^bfjln ( lfln.lnNlnnnnnnnnnnnnln $ 4"&**,....."&*.26:>BFJNRVZ^bfjln  "&* ,.,..,....."&*.26:>BFJNRVZ^bfjln$ÿ  lnlllnJlnnnnnnnnnnnn ln $ lnlllnFlnnnnnnnnnnnnln$$ $ $,4BFJL&L2LNNLNNNNNNNNNNNNNNNN  $LNNNNNNNNL&L2LNNLNNNNNNNNNNNNNNNN (LNNNNNNNNL&L2LNNˆ@p°Ðð1Qq‘±Ññ2Rr’²Òò³r`€± 333333s0 “0 ÿ ó0 3‘ 33333333333sr` ± 333333“0 3ó1 3‘ 33333333333SrÀ± 333333³0 3ó1 3‘ 333333333S¦L‘ "&*.26:>BFJ*LL2LNNLNNNNNNNNNNNNNNN68LNNNNNNNN*L"L6LNNLNNNNNNNNNNNNNNN28LNNNNNNNN.L&,,LNN"&*.26:>BFJNRVZ^bB8ÿdffffffdF$(df"dfffffffffff>8dffffff"dB ,df"dfffffffffff>8dffffff"dB  "&"&*.26:>BFJNRVZ^b:4dffffff"  $&&&&&"&*.26:>BFJNRVZ^b:0dffffff.dB  dfdfffffffffff:0dfÿfffff2dF dfdfffffffffff:(dffffff6dJ "&* "&*.26:>BFJNRVZ^b2 (dffffff>df>dfdfffffffffff* 0dffffff>dd6dfdfffffffffff" 8dffffff>dd*dfdfffffffÊ”)S&C€  !#%'( ÿ(()# ()))))))))))))) " ())))))))( (()# ())))))))))))))& ())))))))(   !#%')+-/1* 2333333!2323 233333333333& 2333333#2   !#%')+-/1" 2333333'2 2 23 ÿ233333333333" 2333333+2 2 23 233333333333 2333333-2 2 23 233eÊ”)S¦L™2eh@pp° @p°Ðð1Qq‘±Ññ2Rr21€Ò0@pP@p°Ððp0‘@p°Ðð1Qq‘±Ññ2Rr’²Òò`€± 3333333 3ó1 3Ó 3333333333s`€± 3333333S0 S0€0 ó0 3Ó 3333333333órÀ± 3333333Sÿ0  À0 Ó0 3Ó 333333S¦L™2Y4 8HHX 8HXhxˆ˜¨¸ÈØèø)9Ù@i`@¹@I I@IIIIIIIIIIIIIù80ðX@IIIIIIIII9@i`@¹@I I@IIIIIIIIIIIIIé8Y@IIIIIIIIII@y 8 8HXhxH€ˆˆˆˆˆˆH 8HXhxˆ˜¨¸ÈØèø)9IYiy9Y€‰‰‰‰‰‰‰É€‰€‰‰H€‰‰‰‰‰‰‰‰‰‰‰Y8Y€‰‰‰‰‰‰‰Ù€‰€‰‰H€‰‰‰‰‰‰‰‰ÿ‰‰‰I8Y€‰‰‰‰‰‰‰Ù€‰€‰yH€‰‰‰‰‰‰‰‰‰‰‰Y8 8HXP 8HXhxˆ˜¨¸ÈØèø)9 @IIY@IùH@IIIIIIIIIIIIIÙ8Y@IIIIIIIIIi@IIY@IùH@IIIIIIIIIIIIIÉ8Y@IIIIIIIIIy@IIY@IùH@IIIIIIIIIIIII¹80 X 8HXhxˆ˜¨¸ÈØèø)9@IIY@IùH@IIIIIIIIIIIII‰800 Y@IIIIIIIIIy@©@é@IùH@IIIIÿIIIIIIIIIY800@Y@IIIIIIIII‰@©@é@IùH@IIIIIIIIIIIIII A@ÁAÂBCÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÉJÅJÇJÊGJJJJJJJJJJJJÊÉJÃJJJJJJJJJJÄJÅJÇJÊGJJJJJJJJJJJJJÈJÄJJJJJJJJJÊÄJÅJÇJÊGJJJJJJJJJJJJJŽ "&*.26:>BFJNNPR0 PR>PRRRRRRRRRRRRÿ:P.PRRRRRRRRR*P*,( PR>PRRRRRRRRRRRR:P*PRRRRRRRRR.P*(   PR>"&*.26:>BFJNRVZV\\^^^^^^^^\(  "& "&*.26:>BFJNRVZV\\^^^^^^^R     """"""&*.26:>BFJNRVZV\\^^^^^^^ÿ^\(  "&*"&*.26:>BFJNRVZV\\^^^^^^^^\N \^&\^^^^^^^^^^R\\^^^^^^^^\R \^&\^^^^^^^^^^R\\^^^^^^^^\^N"&*"&*.26:>BFJNRVZR\\^^^^^^^^\^N\^&\^^^^^^^^^^N\\^^^^^^^^"\^N\^&\ÿ^^^^^^^^^^N\\^^^^^^^^"\^N\^&\^^^^^^^^^^N4 8HXhxX 8HXhxˆ˜¨¸ÈØèø)9IYPYY)PYÙHPYYYYYYYYYYYI9PiXPYYYYYYYYYiPYY)PYÙHPYYYYYYYYYYYI9PiXPYYYYYYYYYiPyPÉPYÙHPYYYYYYYYYYYI9Pi¨@p°Ðð1Qq‘±Ññ2Rr’Ò0 Ò0€0 r1 ²²‘ ²²²²²²²²²²²’r ²° ²²²²²²²²²ò0 ²0Àÿ0 R1 ²²‘ ²²²²²²²²²²²’r ’°  ²²²²²²²²²ò0 ²²R0 ²²‘ ²²²²²²²²²²²RÐÀ €à a¡á`A €à a¡á!b¢â"c£ã#d¤ä$eb@ee¥`@ee#Aeeeeeeeeeeeeä@¥`AAAeeeeeeeeeåb@åb@åb@ee#Aeeeeeeeeeee%ä@%@AAeeeeeeeee¥c@åaa@¥b@ee#Aeeeeeeeeeee¥# @ÁA‚‚@ÁAÂBÃCÄDÅEÆFÇGÈHÉIJÈ€ÊÀJÅ€ÊÊF‚ÊÊÊÊÊÿÊÊÊÊÊÊÊÆÊ‚‚ÊÊÊÊÊÊÊÊÊÊÉ€ÊBÀÁÁ@ÁAÂBÃCÂDDDDDÄC@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËÅÉ‚‚ËËËËËËËËËK€€ËÂ€ËÆ€ËËD‚ËËËËËËËËËËKÅÊ‚ËËËËËËËËËKÁ€ËËÉ€ËËD‚ËËËËËËËËËËKÅÊ‚ËËËËËËËËËKÁ€ËËÉ€ËKD‚ËËËËËËËËK—.)4 8HXXX 8HXhxˆ˜¨¸ÈØèø)9IY)`iY`i©H`iiiiiiiiiiI9PY`iiiiiiiiiÙ`iY`ÿi©H`iiiiiiiiiiI9PY`iiiiiiiiiÙ`iY`i©H`iiiiiiiiii99@YPP`iiiiiiiii© @ÁAÂBÃCÄDEÅ€ÅÅÅEE‚ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÃE‚‚‚ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅ€ÅÅÅÅEÅ€ÅÅÅEE‚ÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÃEÀAA@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊÊÄKÃÁËÅKKEKKKKKKKKKKËÈDÀAA@ÁAÂBÃCÄDÅEÆFÇÿGÈHÉIÊJÇKÃÁËÅKKEKKKKKKKKKKËÈ‚‚‚KKKKKKKKKKKÄKÃÁËÅKKEKKKKKKKKKKKÈÁ‚‚KKKKKKKKKKKÆKÃÁËÅKKEKKKKKKKK–,Y‚h @p°Ðð1Qq‘±Ññ2Rr’²Òr0à²0@0àR1àò‘àòòòòòòòòòò’p`°àòòòòòòòòòòr0àòr2àò‘àòòòòòòòòòò’p@°àòòòòòòòòòò’0àR0à0à1àò‘àòòòòòòòòòò’p@°@ÿp°Ðð1Qq‘±Ññ2Rr’²Ò’0àr0 0à21àò‘àòòòòòòòòòòrp`°àòòòòòòòòòò’0à’0`0`1@1 1àò‘àòòòòòòòòòòrp`°àòòòòòòòòòò’0à²0 `1 1`0à0àò €à a¡á!b¢â"c£ã#d¤ä$e¥åàÀ`Áåååååååååå%aÀ¥aÀbÀ`ÀbÀaÀå%"ÁåååååååååååàÀ`Áåååååååååå%aÀ¥dÀ`€b"`€àà €à a¡á!b" €à a¡á!b¢â"c£ã#d¤ä$ÿe¥åàÀ`Áååååååååå%%`€àà €à a¡á!baÀ`@b@b@bbbb"" €à a¡á!b¢â"c£ã#d¤ä$e¥åàÀ`ÁååååååååååeaÀ¥dÀ`b€bÀåå!ÁåååååååååååàÀ`ÁååååååååååeaÀåd@a@€`ÀbÀåå!Áåååååååååååà€`AÁååååååååååeaÀ%% @AÁ€AÀAA@ÁA€@ÁAÂBÃCÄDD@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËÁ‚‚ËËËËËËËËËËËÀËËÉ€ËËC‚ËÿËËËËËËËËËK€‚‚‚ËËËËËËËËËËËÄ€ËËÉ€ËËC‚ËËËËËËËËËKË‚€ËËËËËËËËËËKÅ€ËÁ€ËÇ€ËËC‚ËËËËËËK—.]š¨@`@p°Ðð1Qq‘±Ññ2Rr’²ÒR1àr0àò1àòòàòòòòòòòòò2²  pàòòòòòòòòòòr1àr0@pP@p°Ððp0±@p°Ðð1Qq‘±Ññ2Rr’²²±  àpÀÒÒÒÒÒÒÒÒÒÒÒ2À’0À2ÀÒ2‘ÀÒÒÒÒÒÒÒÒÒÒ² @qÀÒÒÒÒÒÒÒÒÒÿÒÒ2À’0À2ÀÒ2‘ÀÒÒÒÒÒÒÒÒÒr²  €qÀÒÒÒÒÒÒÒÒÒÒÒ2ÀÒ²2ÀÒ2‘ÀÒÒ’%K–,Y²d) ‚@ÁABÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKÆ€ËËÉ€ËËC‚ËËËËËËËËËK‚‚ÈËËËËËËËËËËKÆ€ËÁÀKÄ€ËËC‚ËËËËËËËËËKÁ‚‚ÉËËËËËËËËËËKÆ€K€ËÄ€ËËC‚ËËËËËËËËËË‚‚JÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJKƀˀ€€€KÅ€ËKC‚ËËËËËËËËËK€ËËÿËËËËËËÇ€€€Á€ÈÀËËÅ€ËËÉ€ËKC‚ËËËËËËËËËK€‚ÊËËËËËËËÇ€ÁÁ€ÈÊ€KÊ€ËËÉ€ËËB‚ËËËËËK—.]ºP €à a¡!À €à a¡á!b¢â"c£ã#d¤da@a@@@À`@@€`@@€`@@@À`@À`@@À`@@bÀ`@@@ÀäaÀ$b@@À$dÀäd#Áääääääääääää`ÁäàÀääääääää¤a@ab@@€`€`€aÀ`@€`@À` €à @À`@@€`!!!!!!@!!!!!¡`À`!!!!ÿ!!!¡` €à a¡á!bb! €à a¡á!b¢â"c£ã#d¤ä$e%@A倥¥¥¥¥¥¥%aÀ`@a@@@@€a€aÀ`À`@À`ÀaÀ`@À`€å`€%aÀ`€%c€¥¥!¥¥¥¥¥¥¥¥¥%cäÀÀÀ€¥¥¥¥¥¥¥ea€`aÀ`@€a€aÀ`À`€`@@ €à `À`@À`!!!!!!@!!!!!¡`À`!!!!!!!¡` €à a¡á!bb! €à a¡á!b¢â"c£ã#d¤ä$e%@"à€à  €à a¡á!b¢â"c£ã#d¤¤bÀ`€`€`@ÿ€`@@€a€`À`À`À`@Àb€`@@@€`À¤aÀä!`€à  €à a¡áá`"""""¢  €à a¡á!b¢â"c£ã#d¤ä$eeÁ à€à  €à a¡á!b¢â"c£ã#d¤äd@@a@À`@@@Àa@À`@@€`À`€`@@@b@@@@@ÀäaÀää$bÀä$#ÁääääääääääääÀÀ@ÁÀÀÀääääääääääääbÀ`@cÀ¤bÀää$bÀä$#Áäääääääää¤I‹  "&*.26:>BFJNRV68XÿXZVXZXZZZZZZZZ  "&*.26:>BFJNRVZ^>`bF`b`bbbbbb"&*.26:>BFJNRVZ^J`bF`b`bbbbF"&"&*.26:>BFJNRVZ^Z`bF`b`bbb*"&*.2 "&*.26:>BFJNRVZ^b df>ÿd^dfb"&*.26: <>>>>>>>>>>>>>>>>>>><>>><>> <>6"&*.26:>>@BBBBBBBBBBBBBBBBBB@BBB@B>@."&*.26:>BF.HJJJJJJJJJJJJJJJJ&HJJ.HJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ>HJJ.HJJJJJJJJJJJJJJJJJJJJJJJJJJJJÿJJ>HJJ$HJJJ  8HXhxˆ˜¨¸ÈxÐØØØØØhÐØØØØØhÐØØØØØxÐØØØØØhÐØØØØhÐØØØ(€ÐØØØØ˜ÐØØØØØxÐØØØØØhÐØØØØØhÐØØØØØxÐØØØØØhÐØØØØhÐØØØ0p 8HXhxˆ˜¨¸ˆÀÈÈÈÈÈÈÀÈÈÈÈÈÈÀÈÈÈÈÈÈÀÈÈÈÈÈÈÀÈÈÈÈÈÈÀÈÈÈȸÀÈÈÈX0p 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù êÿ 8HXhxˆ˜ˆ0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:Z0@JJJJJJJJJJJJJJJJŠ@JJJJJJJJJJJJJJJJª 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÊÚêú +;K[k{‹›«»ËÛëû ,^~žÞ1`1 à1 @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4T”1`1`2`ttttttttttttttttt1ñ 1€0 `0  0`tttttttttttttttt”1`1€0 `0€0`tttttttttttttttt”0@p €0 @0   @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4T”1`1€0 €0 0`tttttttttttttttt”1@01€0 `0€0`tttttttttttttttt´1 1 @0`0@0 `0 `ttttttttÔ¨Q£F5jÔ¨Q£F5jÔ¨I€;openacs-5.7.0/packages/acs-templating/www/doc/time3a/stage01.gif0000644000175000017500000002716707253523117024211 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠˆŠŠÿŠŠŠŠŠŠˆŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠˆŠŠŠŠŠ…‰ŠŠŠŠŠŠ‡ŠŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠŠ‰ŠŠŠŠŠŠŠŠˆŠŠŠ)R¤H"@€‚ƒ„…†‡ˆ‰Š‹Œ‹†ƒ‰‚Š‹ŠŠ‹†€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Œ¢Ÿ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢Ÿ¢¢›¢¢¢¢¢¢¢¢†ÿ¢¢¢Š„€‚ƒ„…†‡€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜‘€‚ƒ„…†‡ˆ‰Šƒ€‚ƒ„‚…ƒ…………………………‚€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—Š€‚ƒ„…†‡ˆ‰Š‚€‚ƒ„…†‡ˆ‰„‚ƒˆ‚ƒŠŠŠŠŠ‚ŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’ÿ“”•€‚ƒ„…†‡ˆ‰Šƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ†ƒ‡‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹ƒ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‚€‚ƒ„…†‡ˆ…‰‰‰‰‰‰‰‰‰‰‰‰‰‰ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‚‹‹‹‹‹‹‹‹‹‹ˆ€‚ƒ„…†‡ˆ‰Šƒ€‚ƒ„…†‡ˆ‰Š‹Œ…ŽŽŽŽŽŽŽŽŽ‚ƒ‡ƒƒŽŽŽŽŽÿŽŽŽ‰ŽŽŽŽŽŽ…ŽŽŽŽŽŒ€‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‹€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‹ˆ‚ƒ‰‰‚€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽƒŠ‚‘‘‘‡‘‘‘Ž‘‘‘‘‘„‘‘€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’…€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”“•••‚••••„•€ÿ‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’Š€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•Š––•––––’€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’Ž€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–––•––––†€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“…€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–Œ—…—Š———’€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”””””””””†„ˆ””Œÿ”‡„”Œ””””€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”ƒ••••••••’ƒˆ••Š•…†•Š•••Š€‚ƒ€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”‚••••••••“‚Š‚ƒ••Š•••‚•••‚€‚ƒ‚€‚ƒ„„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•••••••••†‰‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹ƒ€‚ƒ€‚ƒ„ÿ…†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”‚•••••••••†ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡‹‹‹‹‹‹‹Š‹‹†‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‰‰ƒƒ‹‹‹‹‹‚‹‹†‚‹‹‰‹‹‹‹Š‹‹‰‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹-Z¤ÐÀ €à a¡á!b¢â"c£ã#d¤ä$"A" Á %ed%b@€`åb%e#%c%%%%%%%%%¥áÀÿ%%%%%%%%¥$   €à    €à a¡á!b¢â`Àâ¢a@€`ÀâbbÀâââb"Áâ¢bÁâââââââââââââââââ¢áÀ €à a¡á!b¢â"c£ã#d¤ä$e¥å%afa@@@&b&f!&b&&&&&&&¦âÀ&&&&&&&&&&¦d&fd&&!fb&&&&&&&&âÀ&&&&&&&&&&&e&b&b&&!fb&&&&&&&fáÀÀ&&&L˜0a„ &K€  ÿ  !#%'()))))))))    ()((() ( ())))))))()))))))))     ()(      !#%&''''''''''    &'&&#&' & &''''''''&''''''''''     ÿ                 !#%'))    *+**+ * *+++++  ÿ!#%')+    ,-, ,- , ,---!  !#%')+-+          !#%')+-/1351     ÿ  !#%')+-/13579::- :   !#%')+-/13579;:     !#%')+-/13579;= 8 >) > >??????????????):>>) > >??????????????)8> >' >ÿ >???????????}úô© @ÁAÂBÃCÀÁA@ÁAÂBÃÃÁDDDDDDADDDD€€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÊ€ÏÏÁ€ÏI‚OÁ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊ€ÏÏÁ€ÏI‚OÁ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊ€OÁ€Ï€ÏI‚OÁ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊÍÀÁA@ÁAÂBÃÃÁDDDDDDADDDD€€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÊ΀πÏIÿ‚OÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË€ÏÏÁ€ÏI‚OÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË€ÏÏÁ€ÏI‚OÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË€O€€O€€ÏI@@ÁAÂBÃÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOË΀πÏI‚OÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË΀πÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOËMÀÁÁ@ÁAÂBÃCÂDDDDDDADDDÄ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÿË΀Ï€ÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË€ÏÏÁ€ÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË€ÎÁ€O€€ÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOËÎAÀ€@ÁAÂBÃÃÁDDDDDDADDDÄ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOË΀Á€Ï€ÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË΀Á€Ï€ÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOË€ÎÁ€O€€ÏI‚O€€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏO–ÿ"&**,...,.* "&*.26:>BFJNRVZ^bfjnrvzZt||N| |~~~~~~~~~~~~~~Zp||N| |~~~~~~~~~~~~~~Zp||N| |~~~~~~~~~~~~~~^ $,4<  8<<< 8<<<<<< 8<<<,$,4    !#%')+-/13579;=     !#%')+-/13579;=/>>' > >??????????????/>>' > >??????????????/> >' ÿ> >???}úôéÓ§OŸ>}úôé @ÁAÂBÃCÄDEÅ€ÅÅÅEC‚ÅÅÄ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏËÍ€ÏÀÏI‚Ï€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËÍÁ€O€ÏI‚Ï€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËÍÁ€O€ÏI‚Ï€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËÍAÀ@ÁAÂBÃÃÃDDDDDDADDÄÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏËMÀÁAA@ÁAÂBÃÃÁDDDÿDDDADDÄÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏË€ÏÏÁ€ÏI‚Ï€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏË€MÀÁA@ÁAÂBÃCÂDDDDDDADDÄÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏËÍÀπÏIÏÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËÍÀπÏIÏÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËÍÀπÏIÏÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËMÀÁAA@ÁAÂBÃÃÁDDDDDDADDDÃÿÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏË€ÏÏÁ€ÏIÏÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏˀ̀O€€ÏIÏ€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÌÍÀπOI‚Ï€ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÌÍÀOÀ@ÁAÂBÃCÄDBEEE€€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÌÍÀπOI‚Ï‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÌ€MÀÁA@ÁAÂBÃCÂDDDDDDDDÄÂ@ÁAÂBÃCÄDÅEÆFÿÇGÈHÉIÊJËKÌLÍMÎNÏÌ€ÏÏÁ€OI‚Ï‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÌ€ÏÏÁ€OI‚Ï‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÌ€ÏÏÁ€OI‚Ï‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÍ€ÏÏÁ€OI‚Ï‚ÏÏÏÏÏÏOŸ>}úôéÓ§Oš"&**,...,.&"&*.26:>BFJNRVZ^bfjnrvzj|~|J||~~~~~~~~~~~~~~j|~|J||~~~~~~~~~~~~~~jx||J||~~~~~~~~~ÿ~~~~~jx||Jx|~~~~~úôéÓ§OŸ>}ú¤ P €à a¡á¡`"""¢`""""""""¢á@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§§f€gÀç`À§$ç@Áçççççççççççççç§f€gÀç`À§$ç@Áçççççççççççççç§fÀ'ccbÀ§$ç@Áçççççççççççççç§f€gÀb@€b` €à ` €à a¡á!b"!¢¢â@ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§§f€g€ÿbÀ`b@bÀ§$gÁçççççççççççççççf€g€bÀ`Àa€`"`€àà €à a¡á!b!Abbâ` €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç$`€àà €à a¡á¡`¢`À`Àa€`b""""""""¢a €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çf€g€bÀ`À!`€  €à @ €à a¡á!b"!¢¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çfÀçb@a@@abÀ§$gÁççççÿçççççççççççfÀ'c@a@@abÀ§$gÁçççççççççççççççfÀçç`À§$gÁçççççççççççççççfÀçç  @ÁAÂBÃCÄDBEEÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÍ€ÏÏÁ€OIÏ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÍ€ÏÏÁ€OIÏ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÍ€ÏÏÁ€OIÏ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÍ€ÏÏÁ€OIÏ‚ÏÏÏÏÏÏÏÏOŸ>}úôéÓ&@€‚ƒ„…†‡‡‡‡‡…‡‡‡‡‡‡ÿ‡‡‡‡‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž››„ŸŸ’žŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ›š†ŸŸ’žŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ›ŸŸƒŸ’žŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ›ŸŸƒŸ’žŸŸŸŸ>}úôéÓ§OŸ>}ú´ P €à a¡á!a"""b""""""""ba €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§'ggaÀgÀ§$AgÁçççççççççççççç'ggaÀgÀ§$AgÁççÿçççççççççççç'g€&`€à` €à a¡á!a""""""""ba €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§'ggÀgaÀ§$AgÁçççççççççççççç'gÀçç`À§$AgÁçççççççççççççç'gÀçç`À§$AgÁçççççççççççççç'gÀçç`À§$AgÁççççççç§OŸ>}úôé'@€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹…‹‹‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžœŸŸƒŸ’ŸŸŸŸŸŸÿŸŸŸŸŸŸŸŸŸœŸŸƒŸ’ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸœŸŸƒŸ’ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸœœ‚Ÿ‚Ÿ’ŸŸŸŸŸŸ>}úôéÓ§OŸ>q 8HXhx pxxxXpxxxxxxHpxxxP 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÉÀ ð)ð)IÐYðùùùùùùùùùùùùùùÉÀ ð)ð)IÐYðùùùùùùùùùùùùùùÉÀ ð)ð)IÐYðùùùùùùùùùùùùùùÉðù9ð)I ÿ8HXhxX0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÉpðð)IÀY0ðùùùùùùùùùùùùùùÉ Pð ð)IÀY0ðùùùùùùùùùùùùùùɰ0° €ð)IÀY0ðùùùùùùùùùùùùùùÉ 8HXhxpHp0ppxxxxxxHpxxxX0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÉа0°pð)IÀY0ðùùùùùùùùùùùùùùÉð©0 € 88 8HÿXhxˆHH˜˜(X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéY  88 8HXhxˆX0˜˜˜˜8H˜˜(X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÙð©0€ ðIÐYðùùùùùùùùùùùùùùÙð¹@ °ðIÐYðùùùùùùùùùùùùùùÙðÉP  ( 8 8HXhxˆ˜8H ¨˜X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéÙðù9ðIÐYðùùùùÿùùùùùùùùùùÙðù9ðIÀ9PðùùùùùùùùùùùùùùÙ ðyðIÀ9PðùùùùùùùùùùùùùùÙ ðyðIÀ9PðùùùéÓ§OŸ>}úôéÓ§O  """"" """&*.26:>BFJNRVZ^bfjnrvzvh||Fp|~~~~~~~~~~~~~~vh||Fp|~~~~~~~~~~~~~~v|~|Fp|~~~~~~~~~~~~~~z|~|Fÿp|~~~~úôéÓ§OŸ>}úôÉ @ÁAÂBÃÂÀÃÃÃÃÁ€ÃÃÃÃÃCC‚ÃÃÃÃ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOπ̀O€€ÏH΂ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ΀€€€OÁ€ÏH΂ÏÏÏÏÏOÅ€€Ë€ÏÍÊÁ€Ë€Å€È€ÈĀÀƀȀ€ÏOÀÏÏÁ€ÏH΂ÏÏÏOŸ>% 8HXhxx€ˆˆˆˆH€ˆH €ˆˆ€(€ˆ€ˆ€p€ˆˆh €ˆˆˆˆˆˆˆ8€ˆˆˆˆÿˆˆˆ€ˆˆˆˆˆH€ˆˆ8X0 8HXhxˆ˜¨¸ÈØèø)9Y`  0 00€000 0 @° 0  @@ 0€00  ( (0 000088000 8HXhxˆ˜X ¨x ¨¨X ¨¨¨ˆH ¨xX0 ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨h00ÿ 000 0p 0 000 ` 0@0 8 @0@H@00 @8 0 @00 @H@ @0 8HXhxˆ˜H ¨h0 ¨¨H ¨¨¨ˆH ¨xX0 ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ˆ  ( (00000080( (0(  ÿ8HX8@@ (00(0(0(  800(0 000 (0 80( ( 8HXhxˆx˜ˆ0˜˜x˜˜˜˜8H˜˜X0 8HXhxˆ˜¨¸ÈØèø)9™P`@00 €PP00€0P@P0000 @À@€0P@P0000ÿ0€@P0@IÙ@i  8HXhxh€ˆˆˆˆˆH€ˆˆ(8P 8HXhxˆ˜¨¸ÈØèø)9i0P`@00°PP  P0  0P P 00   À P0   @00  8(@@ 0@H@@@HHHHH(@HHHHH( 8( 8HXhx8€ˆˆˆˆˆH€ˆÿˆ80P 8HXhxˆ˜¨¸ÈØèø)9y0 p@ 0 €`0  0@@€p0 00000 00@ ` 8(@@( @H(@@@HHHHH( 8HXhxˆ˜¨¨°¸¸¸8H°¸000X°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸0°¸°¸¸Hÿ°¸°¸¸¸¸H°¸¸¸¸¸¸¸¸¸8°¸¸¸¸¨°¸¸¸8H°¨80PX°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸( 8HXh8pxxxxxxxX 8HXhxˆ˜¨¸ÈØèø))099‰09™H090pX09999999999999999999999999)099‰09™H90€X099999999999999999999999999099‰09™Hð80 X0999999999iÒ¤I“&Mš4iÒ¤I“&Mš4i @ÁAÂBÃCÄDEÅ€ÅÅÅÅÿA‚EÁÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁPP€ÐG‚ÅÆPPPPPPPPPPPPPPÐÉPP€ÐG‚ÄÇPPPPPPPPPPPPPPÐÉPP€ÐGÄÇPPPPPPPPPPPPPPPÊPP€PPPPP @ (P @Õ P €à a¡á!b¢¢b €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'h(c€he@b€hh€¨(e€¨he€¨(e€¨(e€¨he€(f€(e@b€hh€¨(e€¨he€¨(eÿ€¨(e€¨he€(f€èdÀ`Àa€hh€¨(e€¨he€¨(e€¨(e€¨h%@€‚ƒ„…†‡ˆ‰Šƒ‹‹‹‹‰ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰ˆƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£…ƒ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤˜¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼ÿ½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏУччÑ„у…Ñ‚„ÑјƒÑ…ццƒ€€‚ƒ„…†‡ˆ‰Š‹Œ„„ƒƒƒ‡‡ˆŠƒƒƒƒ‡†‡€€‚ƒ„…†‡ˆ‰Š‹Œˆˆ†ƒƒƒ†ÿ†ˆ‚ˆƒ†ƒ…ƒƒƒ…5jdP €à a¡á!b¢â"c"`€  €à a¡á!b¢â"ãaÀ`@ccccc£aÀ`@ccccccaÀ`À`@cccccã`a@ccccccccccccc£a@ccccccc@ccccc#bÀ`@ccccc£aÀ`@ccccccaa@@ccccc#aÀ`@ccccccccccccc£C€ ÿ   !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}ƒ…‡‰‹‘“•—™›Ÿ¡£¥§©«­¯±³µ·¹»½¿ÁÃÅÇÉËÍÏÑÓÕ×ÙÛÝßáãåçé  !#%')+-/13579;=?ACE&FGGGGGGGGGGGGGGGG FGGGÜGGGGGGGGGGGGGFGGGGGGGGGGGGGGGG   !#%')+-/13579;=?ACE FGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGGFGGGGGGGG5jÔ¨Q£F5jÔ¨Q£Fš(;openacs-5.7.0/packages/acs-templating/www/doc/time3a/stage02.gif0000644000175000017500000002674207253523117024210 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠˆŠŠŠŠŠŠˆŠŠŠŠŠŠ‡ŠŠŠŠÿŠŠˆŠŠŠŠŠŠˆŠŠŠŠŠŠ‡ŠŠŠŠŠŠ‚ŠŠŠŠŠ…‰ŠŠŠŠŠŠŠŠŠ‡ŠŠŠŠŠŠˆŠŠŠŠŠŠˆŠŠŠŠŠŠ‡€‚ƒ„…†‡ˆ‰Š‹‚ŒŒŒŒŒˆŒŒŒŒŒ‡ŒŒŒŒŒ‚ŒŒŒŒ‡‰ŒŒ†ŒŒŒŒŒ‡ŒŒŒŒŒˆŒŒŒŒŒˆŒŒŒŒŒ‡ŒŒŒŒŒˆŒŒŒŒŒˆŒŒŒŒŒ‡ŒŒŒŒŒ‚ŒŒŒŒ…€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Œ¢Ÿ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢Ÿ¢¢¢¢ÿ¢¢¢¢¢¢¢¢¢¢Œ€‚ƒ„‚€‚‚€‚ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œŒ€‚ƒ„…†‡ˆ…€‚ƒ„…†‡ˆ‚€‚ƒ„€‚ƒ‚€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™–€‚ƒ„…†‡ˆ‰Š‹„€‚ƒ„…†‡ˆ†€‚ƒ„…††€‚ƒ„€‚ƒ‚‚ƒ€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ÿŒŽ‘’“”•––€‚ƒ„…†‡ˆ‰Š‹†€‚ƒ„…††€‚ƒ„…†‡ˆ‡€‚ƒ„…†‡ˆ‰Š„€‚ƒ„€‚ƒƒ„ƒ‚ƒ„„„€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹†€‚ƒ„…†‡ˆ‰Š‹…€‚ƒ„…†‡ˆ‰Š€‚ƒ„…†‡ˆ‡€‚ƒ„…†‡ˆ‰Š‹Œ€‚ƒ„€‚ƒ„…‚ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹€‚ƒ„…†‡ˆ‰Šÿ‹†€‚ƒ„…†‡ˆ‰Š‹Œ‡€‚ƒ„…†‡ˆ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ„€‚ƒ„€‚ƒ„…†‡ƒ‡ƒƒ‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‚‡‡‡‡‡‡‡‡‡‡‡‡‡…€‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ€‚ƒ„…†‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ€‚ƒ„„€‚ƒ„…†‡ˆƒˆ‚ƒ‰‰‰‰‰‰ƒ‰‰‰‰‰‰‰‚‰‰‰‰‰‰‰‰‰‰…‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰†‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰…€‚ƒ„ÿ…‚€‚ƒ„…†‡ˆ‰‰Š‚ŠŠŠŠŠˆŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠŠŠŠŠŠŠŠƒ€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‘‘Ž‘‘‘‘‘ˆ‘‘‘‘‘‘‘‘‘‹‘‘‘‘‘‘‘‹€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’’’‹’’’’’‚’’’’’’’’’’’’’’’ˆ€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’‹“““ˆ“““““““““““€‚ƒ„…ƒÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‰”ˆ”””””‹”””””€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‹€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ†„ˆ„‹„‹€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ†€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽŽƒˆ„І‹Ž€‚ƒ„…†‡†€‚ƒ„…†‡ˆ‰Š‹ŒÿŽ‘€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ…‚Š‚ƒ‘‘‘‘‘‘Ž‘‘‘‘‘†€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“„€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‚‰‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹†€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”Š€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘Šƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹ÿ‡‹‹‹‹‹‹‹‹€‚ƒ„…‚€‚ƒ„…„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”€‚ƒ„…†‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‘‰ƒƒ’’’ƒ’Š‚’’’’’‘’’’’’’’’’‹€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ƒ‰‚ƒ””‘”ˆ‚”‹””Ž”””””””€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”“€‚‚€‚ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚ÿ‹‹‰‹‹‹‹‰‹‹‹‚‹‹‹‹‹‹‹‹Š€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™–šƒš†šššŠššˆ€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‡œœ‰œ˜œ‡—€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ‘ƒƒ–‡„€‚ƒ„…„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œšœ„žž•ž†„žžžžžžžžžžžžž„ÿƒŒˆž–œ„žž•ž†ƒžžžžžžžžžžžžž…‚ƒ‹ˆž–š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆƒˆˆˆˆƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘†ˆ‚ƒœ˜œœˆœ—œ‡„œœœœœœœœœœœœœœ‹ˆ‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡‹‹‹‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›™ƒ€ÿ‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰†ŠŠŠ…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›˜Šƒƒœœœ‰ˆƒ‡œ—œ‡ƒœœœœœœœœœœœœœœ‰‹‚ƒœœœ‚‡ƒ‡ƒ‡œ—œ‡ƒœœœœœœœœœœ8qâÄ) AA@ÁAÁ‚€Á‚‚@ÁAÂBÃCÄDÅÁ€ÅEÀÁ€Ã€ÁÄ€€DÀÁÁÿA@ÁAÂBÃCÄC‚ÄÄDÄÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏDÀÁÁA@ÁAÂBÃÃÁ€Ä€Á€Ã€Á€ÃDDDDDÄADDDÄÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÈ€OÅ€Á€Ã€Á€Ã€OJ‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÈ€NÀAA@ÁAÁ€Â€Á€ÁÂÁ@ÁAÂBÃCÄDCEEÅÂÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÈÎǀ€€Á€€Ä€OJ‚OÂÿÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏȀ΀€€€O€€OJ‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÈ΀Ï€ÏI‚OÂÁ‚ÏÏÏÏÏÏÏÏÏÏÏOŸ>}’(@p°Ðð0@p@p°Ððp0Qqp@°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS2àós0às’à“p@°àóóóóóóóóóóóóóóS2àós0às’à“p@°àóóóóóóóóóóóóóóS2àS0à3às’à“p àóóóóóóóóóóóóóós2@30@p@pÿ°Ððp0Qqp @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ós2€3€0à3às’à“p àóóóóóóóóóóóóóó“2àós0às’à“p àóóóóóóóóóóóóóó“2àós0às’à“°àóóóóóóóóóóóóóó³2à à às’@p°Ððð°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³2€3€0à3às’à“°àóóóóóóóóóóóóóó³2€3€0à3às’à“°àóóóóóóóóóóóóóó³2@0@p0ÿ@p°Ðð0Qq°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³2€3à³0às’à“°àóóóóóóóóóóóóóó³2àós0às’à“°àóóóóóóóóóóóóóó³2 3@0à às’à“°àóóóóóóóóóóóóóó³2€3@0 à3às €à a¡ááa €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§geg@€`ÀgÀç$Áç`ÁÀççççççççççççççgeg@€`ÀgÀç$Áç`ÁÀççççççççççÿççççge@g€`À'@Àç$Áç`ÁÀççççççççççççççg%` €à a¡á!b¢¢bÀâââ¢!Áââ"@Á €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ge@g@Àç`Àç$Áç`ÁÀççççççççççççççgeg@€`ÀgÀç$Á§`ÀÀççççççççççççççgeg@€`ÀgÀç$Á§`ÀÀççççççççççççççg% @ÁAÂBÃÀÁ€ÃÃÃÃÁ€ÃÃÃÃÃÃC‚ÃÃÃÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌÿLÍMÎNÏʀ΀€€€O€€ÏI‚O€ÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊ€ÏÏÁ€ÏI‚O€ÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊ€ÏÏÁ€ÏI‚O€ÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊÍCÀ@ÁAÂBÃÃÁDDDDDDADDDÄÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏʀ̀O€€ÏI‚O€ÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊ΀€€€Å€Å€€€Ã€ÏI‚O€ÁÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÊ€ÏÅ€€ÄÅ€ÏI‚O€ÁÏÏÏÏÏÏÿÏÏOŸ>}úôéS%@€‚ƒ„…†‡ˆ…ƒ‡‰‚‰‰‰‰‰…‰‰‰…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž•ŸŠƒ‡ˆ€‚ƒƒ€‚ƒ„…†‡ˆ†‰‰‰…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‡ƒ‡‰‰‰‰‰…‰‰‰…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž•ŸŠƒ‡ƒ‡Ÿ“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–Ÿ‹ÿ„‚ƒ‡Ÿ“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–ŸŒ…ƒˆŸ“Ÿ€€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž–ŸŸƒŸ“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–šŸ‡Ÿ“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–š‚Ÿ„Ÿ’Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–š‚€€‚ƒ„…†‡‡ˆˆˆˆˆˆˆˆˆˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž–š‚Ÿ„Ÿ’Ÿÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–š€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆˆˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž–ŸŸƒŸ’Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–›€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆˆˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž–š†ŸŸ’Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–š†ŸŸ’Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–š†ŸŸ’Ÿ‚ŸŸŸÿŸŸŸŸŸŸŸŸŸŸŸŸ–š€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆˆˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž–ŸŸƒŸ’Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–›„ŸŸ’Ÿ‚ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ–š†ŸŸ’ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ—š€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž—š†ŸŸ’ŸŸŸŸŸŸŸÿŸŸŸŸŸŸŸŸŸ—›€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž—ŸŸƒŸ’ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ—ŸŸƒŸ’ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ—ŸŸƒŸ’ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ˜ŸŸƒŸ’Ÿ€  !#%')+-/13579;=1>?>% > >??????????????1>?>% > >??????????ÿ????1>?>% > >??????????????1<>>% >  !#%')+-/13579;=1<>>% > >??????????????3<>>% > >??????????????3<>>% > >??????????????3<>>% >  !#%')+-/13579;=3>>% > >??????????????3<>% >ÿ >??????????????3<>% > >?????????????}Ê(@p°ÐðP0Q0`0à0@00@pp@p°Ðð± 11‘p @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó30@pp@p°ÐðP0Q0`0à0@01€ñp @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó33À3@1`0à0@P@p @p°Ðð1‘@QQ` @p°Ðð1Qq‘±Ññ2Rÿr’²Òò3Ss“³Ó33às1 €0  01àS’às àóóóóóóóóóóóóóó33à“1 0  01àS’Às àóóóóóóóóóóóóóóS3àós0àS’Às àóóóóóóóóóóóóóóS0@p°Ðð1QQ1`qqq±`qq @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓS3àós0àS’Às àóóóóóóóóóóóóóóS3àós0àS’Às àóóóóóóóóóóóóóóS3àós0àS’Às àóóóóóóóóóóóóóóS3àós0àS’ÿÀs àóóóóÓ§OŸ>}úôéÓ§Oš "&*.26:>BFJNRVZ^bfjnrvzjl||Jx|~~~~~~~~~~~~~~jh||Jx|~~~~~~~~~~~~~~j|~|Jx|~~~~~~~~~~~~~~j|~|Jx"&*.26:>BFJNRVZ^bfjnrvzj|||Jt|~~~~~~~~~~~~~~jp|ÿ|Jt|~~~~~~~~~~~~~~jp||Jt|~~~~~~~~~~~~~~jh """"" """&*.26:>BFJNRVZ^bfjnrvzjp||Jt|~~~~~~~~~~~~~~j|~|Jt|~~~~~~~~~~~~~~j|~|Fx|~~~~~~~~~~~~~~j|~|Fx"&*.26:>BFJNRVZ^bfjnrvzj|~|Fÿx|~~~~~~~~~~~~~~j|~|Fx|~~~~~~~~~~~~~~j|~|Fx|~~~~~~~~~~~~~~j|~|Fx"&*.26:>BFJNRVZ^bfjnrvzjp| |Fx|~~~~~~~~~~~~~~jp| |Fx|~~~~~~~~~~~~~~jp| |Fx|~~~~~~~~~~~~~~jp """"" """&ÿ*.26:>BFJNRVZ^bfjnrvzjp| |Fx|~~~~~~~~~~~~~~j|~|Ft|~~~~~~~~~~~~~~nd||Ft|~~~~~~~~~~~~~~nh| $,4}úôéÓ&@€‚ƒ„…†‡ˆ…ƒ‰ˆ€‚ƒƒ€‚ƒ„…†‡ˆ„‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž”€‚ƒƒ€‚ƒ„…†‡ˆ…ƒ‰‰‰‰‰‰‰ƒ‰‰‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžœŸŠƒˆŠŸ‘ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸœŸ‹„‚‹Ÿ‘ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸœŸŒ…‚€‚‚€‚ƒ€‚ƒ„ÿ…†‡ˆ‰ƒŠŠ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžœŸŸƒŸ‘œŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸƒŸ‘œŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸšŸ‡Ÿ‘œŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸšŸ‡Ÿ‘›ŸŸŸ>}úôéÓ§OŸ>}úôÉ @ÁAÂBÃBÀÁAA@ÁAÂBÃÃÁDDDDDDDDÄÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÏÍ€ÏÀÏH‚Í‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏÿÍ€ÏÀÏH‚Í‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ€ÏÏÁ€ÏHÍ€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ€ÏÏÁ€ÏHÍÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÏÍÀπÏHÍ€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOπ̀O€€ÏHÍ€‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ΀€€€OÁ€ÏHÍ€‚ÏÏÏÏÏÏÏÏÏÆ€€Á€È€CÀ@ÁAÂBCÁ€€ÃÃÀÃÃÃÀC€€€Â€Á€ÃÃC€ÃÃÃÃC€ÃÃÃÃÃÃÃÃCÁ€ÃÃÃÃÃCÿC‚ÃÃÀ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËËÇ€Á€€È€ÊÄÁL€€Ê€Å€Ä€ÄLÌÈLÌÈLLLÁLLLLLLLLLLLL€€€€Á€€€Á€€ÁÁ€Á€€Á€€€Á€€€Ä€Â€€Á€€€Ä€€Á€€@Á€€Á€€A€€€A€€€A€€€AAAA€AÁ€A€€€Á€€A€€€Á€€A€€AÁ€€A€€€@ÁAÂBÀÃÃCÀ€€ÃÃÃÃÀÃÃÃÃÃCC‚ÃÃÃÂ@ÁAÂBÃCÄDÅÿEÆFÇGÈHÉIÊJËKȀ€Á€€Á€€Á€€€Â€Á€Á€€ÁÄ€Á€€Á€Ã€Á€€Á€Â€€Á€€Á€€Á€Á€€Ä€Â€Á€Á€€Á€Â€€Á€Á€Á€Á€€ÁLÀ@ÁAÂBÀÁ€ÃÃÃCÀÃÃÃÃÃCC‚ÃÃÃÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKȀ€ÁÀAA€@AÁ€€ÁÁ€Á€Á€€Á€ÁA€€€€Á€Á€€ÁÁAÁ€AÁ€ÁÁ€€€€€Á€€ÁÀAA€€@ÁÁÁÿB€€Á€Á€BÁ€€€€ÂÁ€AÀAAA@ÁAÂBCÀÃÃÀÁ€ÃÃÃCÀÃÃÃÃÃCC‚ÃÃÃÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKȀ€Á€€Â€Â€€Â€Á€ÁÁ€€€Ä€Á€€Å€Â€Á€€Á€€ÁÁ€€Á€Â€Á€Ä€Â€Á€Á€€Â€Á€€Ã€ÁÄLÁLÁ€ÁLÅLLLÁLLLLLLLLL˜0a"( @P0`0 @0` `0`0 `ppp0` `0 `ppP0`0 `0ÿ @0 `0 `P0`P0@0 `pp0`P0`0 @0 `P0@0 `p `0`P0`0@p°Ð0àðð°0@pP@p°Ððp0‘Qp @p°Ðð1Qq‘±Ññ2Rr’²Òò22 @0`0@0 `0 @0`0@0 @0`0@0 1 0 @0€1 @0`0@0 `0@0 `0 `0 1 `0 @0 @0À0 À0 `0 `0 0@p°Ð°0àððððððððP0àðððððÐàðð°ÿ°@p°Ðð1Qq‘±Ññ2Rr’²Òò3S1`0@Ss0`0@SSs2@S³1@Ó’@³@SSSSSSSSSSS3 @S³0 @SS“2@S³1@Ó’s` @SSSSSSSSSSSSSSSSSSs0@S³1@Ó’€r```@°@SSSSS“&Mš4iÒ¤I“&Mš4i(@p°Ðð1QQ1`qqq‘`±p```À°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó  ô‘ q``` ±T2 ô‘ q``` ±ÿT2 ô‘ p``` ²T2@p°Ðð1QQ1`qqqq@p```Q±@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓóS0 ´3 ´3ô2 1À3t0”0”0t0”0”0t0Ô3Ô2 1À3@p°Ðð1Qq €‘‘‘‘1€‘‘‘‘1€‘‘‘‘ñ0€‘‘‘‘1€‘‘‘‘1€‘‘‘‘ñÿ0€‘‘‘‘Q0€‘‘‘±0`0à0€‘Ñ0€‘‘‘‘ñ0€‘‘‘‘1€‘‘‘‘1€‘‘‘‘ñ0€‘‘‘‘1€‘‘‘‘1€‘‘‘‘ñ0€‘‘#F‚"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†:"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvzÿ~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?? "&*.,....& "&*&,.............,....* ,....& ,.....,....&,.....,.....,...." ,.............,.....,..... ,....R( @p°Ðð1Q11 `qqqqQ1`qqqqq±ÿ0`qqqq11`0`qqqqqqqqqqqqqq0`qqqqqQ0`qqqqq `qqqqQ1@0`qqqq11`0`qqqq11 `qqqqqQ0`qqqqQ1 `qqqqqqqqqqÑ¢E‹ $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'ÿ/7?GOW_gow‡—Ÿ§g X x $,4BFJNRVZ^bfjnrvz~‚†2ˆ~ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠvÿˆ~ˆŠŠŠŠŠŠŠŠŠŠŠB  "& (*****"&*.26:>BFJNRVZ^bfjnr"&**    "&**"&*.26:>BFJNRVZ^bfj2"&**"&      (**** (**ÿ***"&*.26:>BFJNRVZ^Z"&**"&*."  0"&**,.................... "&**"&*. "&*.26   "&* ,....*,..............ÿ"&**"&*.26:>"&*.26:&   <>>2<>>><>>>>>>>>"&*.26:>BF  "&*.26:>>  @BB&@BBB@BBBBBBB@BBBBBBBB"& "&*.26:>B6(  DFFDFF:DFFFFFFÿ>DFFFF:"&"&*,...................*,....*,...........,...*"&"&*.26.8:::::::::::::::*8:::&8:::::::: "&"&*.26:>B&DFFFFFFFFFFFFBDFF:DFFFFFF"&*.26:>BF> "&*.ÿ26:>BFJNRV&XX.XZZZZ&0XZZZZZ ""&*.26:>BFJ4 LN:L"L6LNNNNN,LNNNB""&*.26:>BFJNR. 4 TV*TT*TVVVV60TV"""&*.26:>BFJNRVZ.( \^\^N\^^^^0"ÿ"&*.26:>BFJNRVZ^b>$ 4"&**,.......""&*.26:>BFJNRVZ^bfj  "&* ,.,..,....."&*.26:>BFJNRVZ^bfj6$  lnlllnJlF0lnnnnnnnnnnnnÿ6$ lnlllnFlF4lnnnnnnnnnnnn.  "&*,.,.&,.....,..*, "&*.26:>BFJNRVZ^bfjnrv"tx xz.x64xzzzzzzzzzzzzz^xzxz*x68xzzzzzzzzzzzzz^x x xz*x2<xzzzzzzzzzzzzz^p """"""ÿ" """" "&*.26:>BFJNRVZ^bfj" 0 lfllln>lB4lnnnnnnnnnnnn& , lfh """"""" """" "&*.26:>BFJNRVZ^bfj*  lfll&ln6lF0lnnnnnnnnnnnnN  4"&ÿ**,.....,...,"&*.26:>BFJNRVZ^bfjN  "&* ,.  "&*.,... ("&*.26:>BFJNRVZ^bfjN(  lnl$  ln2lF,lnnnnnnnnnnnnJ, lnl  ln.lJ,lnnnnnnnÚ´iÓ¦Mÿ’  "&*,.   "&* ,...,"&*.26:>BFJNRVZ^bfjnrv    """"""" """" "&*.26:>BFJNRVZ^bfjnrv:x.  xzx:4xzzzzzzzzzzzzzvt   "&*&ÿ,..., "&*.26:>BFJNRVZ^bfjnrv:p8  xzx68xzzzzzzzzzzzzzvtx xzx68xzzzzzzzzzzzzzvpxxzx28xzzzzzzzzzzzòäÉ @ÁAÂBÃCÀÁA@ÁAÂBÃÃÁDDDDDDDDDDDDD€ÄÃ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎÇOÏÂOOBÏÅÇOOOOOOOOOOOOOOÏOÏÂOOBOÅÿÈOOOOOOOOOOOOOOÏÏÁO€OOBÏÄÈOOOOOOOOOOOOOOO€ÍÀÁA@ÁAÂBÃÃÁDDDDDDDDDDDÄÃÄÃ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎÈÎÂO€OÏAÏÄÇOOOOOOOOOOOOOOÏÁOÏÂOÏAÏÄÇOOOOOOOOOOOOOOOÂOÏÂOÏAOÄÇOOOOOOOOOOOOOOÏÂOAÀ@ÁAÂBÃCÂDDDDDDÄCDDDDÃÄÂ@ÁAÂBÃCÄDÅEÿÆFÇGÈHÉIÊJËKÌLÍMÎÎÊÎÂO€OÏAOÄÆOOOOOOOOOOOOOOOÃÎÂO€OOAÏÄÆOOOOOOOOOOOOOOÏÃMÀÁÁ@ÁAÂBÃCÂDDDDDDDCDDDÄÃÄÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎÎËÎOÃOOAÏÄÅOOOOOOOOOOOOOOOÄOÏÂOOAÏÄÅOOOOOOOOOOOOOOÏÄ€ÎÁOÁOOAÏÄÅOOOOOOOOOOOOOOÏÄNÀ€€@ÿÁAÂBÃÃÁDDDDDDÄBDDDDÄDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÌ΀ÁO€OOOÅÄOOOOOOOOOOOOOOOÅ΀ÁO€OOOÅÄOOOOOOOOOOOOOOOÅ€ÎÁOÁOOÏÅÄOOOOOOOOOOOOž}úôéÓ§ÿO‡    "$&&&"&*.26:>BFJNRVZ^bfjnrvz     """""  """" "&*.26:>BFJNRVZ^bfjnrvz"x(  "&(*** "&*.26:>BFJNRVZ^bfjnrvz&|. |N|*|~~~~~~~~~ÿ~~~~~&|2 |N|*|~~~~~~~~~~~~~~*|~|N|* |~~~~~~~~~~~úôéÓ"@€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹†‹‹‹‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œž‹ŸŸƒŸ“Ÿ‰ƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŒŸŸƒŸ“Ÿ‰ƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŒŸŸƒŸ“Ÿ‰ƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŒŸŸƒŸ’€‚ƒ„…†‡ˆ…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›œžŒœŸ‚Ÿ’ŸŠƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŒ›„ŸŸ’ŸŠƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŒš†ŸŸ’ŸŠƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŒ€    !#%')+-/13579;=>?>% > >??????????????>>>% > >??????????????8>>% > >???????ÿ???????8   !#%')+-/13579;=4    !#%')+-/13579;=8> >% > >??????????????>?>% > >??????????????>?>% > >??????????????>?>%     ÿ!#%')+-/13579;=>?>% > >??????????????!>?>% > >??????????????!>?>% > >??????????????!>?>% >  !#%')+-/13579;=#8>>% > >??????????????#8>>% > >??????????????#8>>% > >??????????????#8 ÿ    !#%')+-/13579;=#8>>% > >??????????????#>?>% > >??????????????%2>>% > >??????????????%4 >    !#%')+-/13579;=%6>% > >??????????????%8>% > >??ÿ????????????%:>% > >???????}úôéÓ§OŸ$ $,4}úôéÓ§O“  """"" """"&*.26:>BFJNRVZ^bfjnrvzNh||ÿF||~~~~~~~~~~~~~~Nh||F||~~~~~~~~~~~~~~N|~|F||~~~~~~~~~~~~~~R|~|F|($,4?>! > >??????????????3>?>! > >??????????????5>?>! > >??????????????5>?>! > >ÿ??}úôéÓ§OŸ>}úôé“&@€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹ƒ‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžšŸŸƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸƒŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ˜‰•ŸŸƒŸŸ„ŸŸ„ŸŸƒŸŸ„ŸŸ„ŸŸƒŸŸ„’Ÿ—€‚ƒ‚„„„„„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š‹‹‹‹‹‹‹‡‹‹‹‹‰ƒÿ‡‹Š‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹‹‡‹‹‹‹‰ƒ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰ˆƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£…ƒ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤˜¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­ÿ®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏſ¿€‚‚€‚ƒ„…†‡ˆ‰Šˆ‹‹‹‹‹‡€‚‚€‚ƒ„…†‡ˆ‰Šˆ‹‹‹‹‹ˆ‹‹‹‹‹‡…‹‹‹‹‹‹‹‹‹‚ƒ‹‹‹‹‹†ƒ‹‹‹‹‹‰‹‹‹‹‹ˆ‹‹‹‹‹‹‹‹‹‹‹‹ƒ‹‹‹‹‹‡ƒ‹‹‹‹‹†ƒ‹‹‹‹‹…„‹‹‹‹‹‹‹‹‹…‹‹‹-R(@p°Ðð1Q1 `qqqq1 `qqqqñ0`qqqqqq0`qqqq1ÿ`0`qqqqÑ0`0`qqqq‘0 `0`0`qqqqqqqqq0`qqqq11 `qqqq1@0`qqqq1`0`qqqqÑ0 `qqqqq1`qqqÑ¢D€       ÿ   $,4FNV^fnv~†Ž–ž¦®¶¾ÆÎÖÞæîöþ'/7?GOW_gow‡—Ÿ—X x  §§GÞ&@€‚ƒ„………„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢‹‰„ƒ…£££££££££££££££££Œ‹„ƒ„£££££££££££££££££Œ‹„‚†£££££££££££F5jÔ(F€ {  !#%')+-/13579;=?ACEFGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGGGGGGGGGGG';openacs-5.7.0/packages/acs-templating/www/doc/time3a/stage04.gif0000644000175000017500000002644707253523117024214 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠÿŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ…‰ŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŒŒ‰ƒ‰ƒŒŒŒŒ‰€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Œ¢Ÿ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢Ÿ¢¢¢¢¢¢¢¢¢¢œÿ¢¢¢Š„‚€‚ƒ„„€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š‹€‚ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽˆ€‚ƒ„…†…€‚ƒ€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š…€‚ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹Œ€‚ƒ„…††€‚ƒ‚‚ƒ€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”ÿ•–—˜™˜€‚ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹…€‚ƒ„…†…€‚ƒ„…†‡†ƒ‡‚ƒˆ…€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™’€‚ƒ€‚ƒ€‚ƒ„…†‡ˆ‰„€‚ƒ„…††€‚ƒ„…†‡ˆ‰Š…ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™Œ€‚ƒ€‚‚€‚ƒ„…†‡€‚ƒ„…†…€‚ÿƒ„…†‡ˆ‰Š‹Œ‰ƒ‡ƒƒ…‡€‚‚€‚ƒ„…†‡ˆ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‰ˆ‚ƒŒ…ƒ€‚ƒ„…†‡ˆ‰Šƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘…Š‚’’’„’’’‹’’’’’’’’’’’€‚ƒ„…†‡ˆ‰Š‡€‚ƒ„…†‡ˆƒ€‚ƒ„‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•ÿŽ––•––––––‘€‚ƒ„…†‡ˆ‰Š‡€‚ƒ„…†‡ˆ‰Š‹Œ‹€‚ƒ„‚€‚ƒƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•’––•–––•€‚ƒ„…†‡ˆ‰Š‡€‚ƒ„…†‡ˆ‰Š‹ŒŽƒ€‚ƒ„‚€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”••––•––Œ€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’‡€‚ƒ„…†‚€‚ƒ„…†…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–ƒ—…—Š——‰——————ÿ—€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ„„ŠƒˆŠŠŠŠŠ‚ŠŠ‡„ŠŠŠ‚ŠŠŠŠŠ„ŠŠŠŠŠŠŠŠŠŠŠŠŠŠ†€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹‰ŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‰ƒŒˆŒŒŒŒ„ŒŒ‚†ŒŒ‡ŒŒŒŒ…ŒŒŒŒŒŒŒŒŒ†€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽŽŽŽŽŽŽŽŽŽŽŽŒ‚Š‚ƒŽŽŽŠŽŽŽŽ‰ŽŽŽŠÿŽŽŽŽŽ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽŽŽ‰‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‡‹‹‹‹ˆ€‚ƒ„…†‡„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘Š’’’’’’’’’’ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡‹‹‹‹‹‹‹†‹‹‹ƒ€‚ƒ„…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ƒ”””””””””‰ƒƒ””‘”ˆ‚”‹ÿ””Š”””””””””””ˆ”””””””””’‰‚ƒ””‘”ˆ‚”‹””Дޔ”””””””””ˆ€  !#%'        !#%')+-/0 001 001111111 01111111111#01#01 001111111 ÿ01111111111%0001 001111111 011111a„ &J€  !#%' ()))))))))    ()((() (())))))))) ()))))))))     ()(      !#%' ())))))))) ÿ   ()((!() (())))))))) ()))))))))                       !#%ÿ''    ()#(() (())))))    !#%')    *+**+ **++++    !#%')+-             ÿ!#%')+-/135        !#%')+-/1357788- 8*    !#%')+-/13579;:     !#%')+-/13579;= 8 >' ÿ: >??????????????-:>>' : >??????????????-8> >% < >??????????????Y 8HXhx 8 8HXhx8€ˆˆˆˆˆ@€ˆˆh8@X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéiðù9ð)Ià9@Xðùùùùùùùùùùùùùùiðù9ð)Ià9@Xðùùùùùùùùùùùùùùið)ðð)Ià9@Xðùùùùùùùùùùùùùùi  8 8HXhx8ÿ€ˆˆˆˆˆ@€ˆˆh8@X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéiÀ@ðð)Ià90Xðùùùùùùùùùùùùùùyðù9ð)Ià90Xðùùùùùùùùùùùùùùyðù9ð)Ià90Xðùùùùùùùùùùùùùùyð ð ð) H 8HXhx(80X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéyÀ@ðð)Ià90XðùùùùùùùùùùùùùùyÀ@ðð)Ià9 Xðùùùùùùùùùùùùùù‰   8ÿ 8HXhxH€ˆˆˆˆˆ@€ˆˆh8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé‰ÀðYð)Ià9 Xðùùùùùùùùùùùùùù‰ðù9ð)Ià9 Xðùùùùùùùùùùùùùù‰Ð ð ð)Ià9 Xðùùùùùùùùùùùùùù‰À  8HXhx8€ˆˆˆˆˆ@€ˆˆh8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé‰À ðð)Ià9Pðùùùùùùùùùùùùùù™À ðð)Ià9ÿPðùùùùùùùùùùùùùù™Ð ð ð)Ià9Pðùùùùùùùùùùùùùù™  8HXhxˆ˜¨¨°¸¸¸XH°¸ˆ8P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé™Ðð9ð)Ià9Pðùùùùùùùùùùùùùù™À ðð)Ià9Pðùùùùùùùùùùùùùù©À ðð)IÐ9Pðùùùùùùùùùùùùùù©À  8HXhx8€ˆˆˆˆˆ@€ˆˆX8P 8HXhxˆ˜¨¸ÈØèø)9ÿIYiy‰™©¹ÉÙé©Ðð ð)IÐ9Pðùùùùùùùùùùùùùù¹ðù9ð)IÐ9Pðùùùùùùùùùùùùùù¹ðù9ð)IÐ9Pðùùùùùùùùùùùùùù¹ `ðð)I 8HXhx0P 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙé¹°@ð ð)IÐ9Pðùùùùùùùùùùùùùù¹À°°pð)IÐ9Pðùùùùùùùùùùùùùù¹ð¹ ð)IÐ9Pðùùùùùùùùùùùùùùi @ÁAÿÂBÃCÄ€Á€Ã€DÁ€ÄÄÄÄDB‚ÄÄDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÍ€OÅ€Á€Ã€€€DÀÁÁA@ÁAÂBÃCÄB‚ÄÄDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏIÀÁÁA@ÁAÂBÃCÄ€Á€Ã€Á€Ã€ÄÄÄÄDB‚ÄÄDÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÍ€OÅ€Á€Ã€Á€Ã€OI΀‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÍ€Ïŀ€Á€Á€Ã€OI΀‚ÏÏÏÏÿÏÏÏÏÏÏÏÏÏÏÏÍ€Oƀ€€Á€€Ä€OI΀‚ÏÏÏOŸ>}úôéÓ§OŸ>}Ú(@p°Ðð1QQ1`qqq±`qÑp @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ós3@3àó0àS’€s àóóóóóóóóóóóóóós3@3@0à“0àS’`s àóóóóóóóóóóóóóó“3@3@0à“0àS’`s àóóóóóóóóóóóóóó“3@3@0@p°Ððð0€qp @p°Ðð1Qq‘±Ññ2Rr’²Òòÿ3Ss“³Ó“3@0@pP@p°Ððp0€qp @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3àós0àS’`s àóóóóóóóóóóóóóó“3`0@p@p°Ðð0€Qp@°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3@3À0à3àS’@s@°àóóóóóóóóóóóóóó“3@3À0à3àS’@s@°àóóóóóóóóóóóóóó“3@3À0à3àS’ s`°àóóóóóóóóóóóóóó“3@ÿ0@pP@p°Ððp0€``°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3àós0àS’ s`°àóóóóóóóóóóóóóó“3`3€0à àS’ s`°àóóóóóóóóóóóóóó“3@3À0à3àS’ s@°àóóóóóóóóóóóóóó³3@3À0à0@p°Ðð1‘@Q±p@°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³3@3À0à3àS’ s@°àóóóóóóóóóóóóóó³3`0@p@p°Ðð0ÿ€`@°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³3àós0àS’ s@°àóóóóóóóóóóóóóó³3àós0àS’ s@°àóóóóóóóóóóóóóó³3àós0àS’s`°àóóóóóóóóóóóóóó³3àós0àS’s`°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³3àós0àS’s`°àóóóóóóóóóóóóóó³3àós0àS’s`°àóóóóóóóóóóóóóó³3àós0àS’s`°àóóóóóóóóóóóÿóóó³3À3às0àS’s@°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³3À3às0à3’ s`°àóóóóóóóóóóóóóó³3À3às0à3’ s`°àóóóóóóóóóóóóóó³3À3às0à3’ s`°àóóóóóóóóóóóóóó³3À3às0à3@p°Ðp`°@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó³3à“1€11à3’ s`°àóóóóóóóóóóóóóó³3À3`1 @1 1à3’ s`°àóóóóóóóóóóóóóÿó³3À3@1`01 1à3’ s@°àóóóóóóóóóóÓ§OŸ>y 8HXhx(€(0p € 88 8HXhxˆHH˜x8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéi  88 8HXhx(€(0p €€ˆˆˆˆˆH€ˆˆ0 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙééà 0p ( 8 8HXhxˆ˜8H ¨X8 X 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙééÿð¹@P€ðI9 XðùùùùùùùùùùùùùùéðÉPP€ðI9 Xðùùùùùùùùùùùùùùéðù9ðI9 XðùùùùùùùùùùùùùùÉ @ÁAÂBÃCÄDEÅ€ÅÅÅEB‚ÅÅÁÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÏ€ÏÏÁ€ÏH‚ÌÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ€ÏÏÁ€ÏH‚ÌÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ€ÏÏÁ€ÏH‚ÌÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ€ÏÏÁ€ÏH‚ÌAÀÿ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNOÏ΀€€€OÁ€ÏH‚ÌÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOπ̀O€€ÏH‚ÌÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏÍÀπÏH‚ÌÁ‚ÏÏÏÏÏÏÏÏÏÏÏÏÏÏOÏ€ÏÏA€     !#%')+-/13579;==>?># 2 >??????????????=>>># 0 >???????????????8>># 0 >?ÿ??????????????8>     !#%')+-/13579;=?4     !#%')+-/13579;=?8> ># 0 >???????????????>?># 0 >???????????????>?># 0 >???????????????>?># 0  !#%')+-ÿ/13579;=?@A@! 0 @AAAAAAAAAAAAAA#@A@! 0 @AAAAAAAAAAAAAA#@A@! 0 @AAAAAAAAAAAAAA#@A@! 0  !#%')+-/13579;=?8@@! 0 @AAAAAAAAAAAAAA#8@@! 0 @AAAAAAAAAAAAAA#8@@! 0 @AAAAAAAAAAAAAA#  ÿ   !#%')+-/13579;=?8@@! 0 @AAAAAAAAAAAAAA#@A@! 0 @AAAAAAAAAAAAAA#2>@! 0 @AAAAAAAAAAAAAA#4      !#%')+-/13579;=?6@! 0 @AAAAAAAAAAAAAA#8@! 0 @AAÿAAAAAAAAAAAA#:@! 0 @AAA (P @* @ÁAÂBÃCÄ€Á€D€DÀÁÁA@ÁAÂBÃCDB‚ÄÄ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏLÀÁÁA@ÁAÂBÃCÄ€Á€Ä€Ä€ÄÄÄÄÄA‚ÄÄ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁÐÄ€ÁÄÅPH‚Ë€PPPPPPPPPPPPPPPÉPŀ€Á€ÅPH‚Ë€PPPPPPPPPPPPÿPPPÉÐŀ€AÀAA@ÁA€@ÁAÂBÃCÄÄAEÅÁ€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁPP€PHËÁPPPPPPPPPPPPPPPÉPP€ÐG‚ËÁPPPPPPPPPPPPPPPÉÍPÃÐG‚ËÁPPPPPPPPPPPPPPPÉÍPÃÐG@ÁAÂBC€Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÁMÀÁAA@ÁAÂBÃÃÁDDDDÄCDDÃÁ@ÁAÂBÃCÄDÅEÆFÿÇGÈHÉIÊJËKÌLÍMÎNÏOÁÍPÃÐGËÁPPPPPPPPPPPPPPPÉÍPÃÐGËÁPPPPPPPPPPPPPPPÉPP€ÐGËÁPPPPPPPPPPPPPPÐÉPP€ÐG@ÁAÂBC€Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏÏÁÍÀÏÐGËÁPPPPPPPPPPPPPPÐÉ€ÍÂÐÐGËÁPPPPPPPPPPPPPPÐÉ΀€€P€ÐGËÁPPPPPPPPPPÆ€€Á€È@ÁAÿ€BBBBBÁÂBBBB€BBBBÁBBÁBBBBB€BBBBBBBBB€@ÁAÂBÃCÄDEÅ€ÅÅÅÅA‚ÅÅÁ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÀÁ€€È€ÊÄ€ÈÉÅ€ÊÍÅMÍÆÍJ‚ÊÁMMMMMMMMMMMMʀ€€€Á€€€Á€€ÁÁ€Á€€Á€€€Á€€Ä€€€Á€€€Á€€Ä€€€Á€À€€€€€€€@ÁAÁ€€€Á€€€Á€€€Á€€Á€€Á€€BBBBBBÁBBBBBÂÿÁ€€BBBBBBBÂÁ@ÁAÂBÃCÄDAEE€Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌÌÁ€€Á€€Á€€€Â€Á€Á€€ÁÄ€Á€€Á€Ã€Á€€Á€€ÁÁÅ€Á€€Á€Â€Á€€€Á€€Á€ÌÍ€ÁMÄÍJ‚ÊÁMMMMMMš4iÒ¤I%@€‚‚ƒ€‚‚€‚‚ƒƒƒƒƒƒƒ‚ƒƒ€‚‚€‚ƒƒƒ‚„„„‚ƒ€‚‚ƒÿƒ‚€‚ƒ„…†‡ˆˆˆ‚ƒˆˆˆˆ‚ˆˆˆˆˆ‡ˆˆ…‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™‡…ƒ………ƒƒ‚‰„ƒ‹ƒƒ„ƒŠƒ…ƒƒ…šƒšƒšˆš••‚šššššššššššš”ƒƒ€‚‚ƒ‚ƒƒƒƒƒƒƒ‚ƒƒƒƒ‚ƒƒƒ‚‚ƒƒƒƒ‚‚‚ƒ‚€‚ƒ„…†‡ˆˆÿˆ‚€‚ƒ‚€‚ƒ„…†‡ƒˆˆˆˆˆ‡ˆˆ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™‰‚ƒ‚ƒ‚ƒ‚‚ƒ‚Š‚ƒ‚ˆƒ‚ƒ„ˆƒ‚ƒ‚‚‚šƒššš••ššššššš4iÒ¤I“&M‹"&*.26:>@BBB@B>@@BBBBBBBBBBBBBBBBBBBBBB&@BBBBBB*@BBB@B>@ÿ @BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@BBB@B>@($,4^~žþ0`1 à1 @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4T”1`1`2`ttttttttttttttttt1 1€0 `0  0`tttttttttttttttt”1`1€0 `0€0`tttttttttttttttt”0@p €0 @0   @p°Ðð1Qq‘Œ±Ññ2Rr’²Òò3Ss“³Óó4T”1`1€0 €0 0`tttttttttttttttt”1@01€0 `0€0`tttttttttttttttt´1 1 @0`0@0 `0 `ttttttttÔ¨Q£F5jÔ¨Q£F5jÔ¨I€;openacs-5.7.0/packages/acs-templating/www/doc/time3a/stage05.gif0000644000175000017500000002737407253523117024215 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰„ŠŠŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ†ŠŠŠŠŠÿŠŠŠŠ†ŠŠŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠŠ„ŠŠŠŠŠ…‰„ŠŠŠŠŠŠŠŠŠ†ŠŠŠŠŠŠŠŠŠ…ŠŠŠŠŠŠŠŠŠ†ŠŠŠŠ)R¤H‘!@€‚ƒ„…†‡ˆ‰Š‹Œ…ŽŽŽŽŽŽŽŽŽ‰„ŽŽŽŽŽŽŒŽŽŽŽŽŽ‹ŽŽŽŽŽŽŒŽŽŽŽŽŽŒŽŽŽŽŽŽŒŽŽŽŽŽŽŽŽŽ‹€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Œ¢Ÿ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢Ÿ¢¢¢¢¢¢¢¢¢¢¢¢¢¢‰ÿ€‚ƒ€‚ƒ„„€‚ƒ‚€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œƒ€‚ƒ„…†‡ˆƒ€‚ƒ„‚€‚ƒ„‚…€‚ƒ€‚ƒ„…†‡ˆ‰†ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›Ž€‚ƒ„…†‡ˆ‰€‚ƒ„…††€‚ƒ„‚€‚ƒ„‚ƒ…ƒ€‚ƒ€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ÿ”•–—˜™”€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡ˆ‰Š†€‚ƒ„‚€‚ƒ„…†‡ƒ‚€‚ƒ‚€‚ƒ„ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—–€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡ˆ‰Š‹Œ…€‚ƒ„‚€‚ƒ„…†‡ˆ„€‚ƒ€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‹ÿ€‚ƒ„‚€‚ƒ„…†‡ˆ‰€‚ƒ€‚ƒƒƒ€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆ€‚ƒ„…†ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ…€‚ƒ„…†‡ˆ€‚ƒ„…†‡‚€‚ƒ„…††€‚ƒ‚„„‚ƒ€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆ‹‹‹‹‹‹‹‹‹…€‚ƒ„…†‡ˆ‰Š…€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡ˆˆ‚‚ˆˆˆˆÿˆˆˆ‚ˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”’••ƒ€‚ƒ„…†‡ˆ‰Š„€‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘‰’’’‹’’’’’’’’’’’‘€‚ƒ„…†‡ˆ‰Š„€‚ƒ„…†‡ˆ†€‚ƒ„…†‡ˆ‰‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“””””…”””””””€‚ƒ„…†‡ˆ‰Š…€‚ƒ„‚……………………€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–„——“—————‰€‚ƒÿ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹‚€‚‚€‚ƒ„…€‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜…™ƒ™ˆ™™™™–™™™€‚ƒƒ€‚ƒ„…ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•Ž„ˆ––ˆ–…„–Š–––––Š–––’€‚ƒ‚€‚ƒ„…†„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•ƒˆ––ˆ–„†–‰–––––ˆ–––‹€‚ƒƒ€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰ÿŠ‹ŒŽ‘’“”•’‚Š‚ƒ––ˆ––•–––––†–––„€‚ƒƒ€‚ƒ„…†‡ˆ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–…‰‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹„‹‹‹‹‹‰€‚ƒ‚€‚ƒ„…†‡ˆ‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‡ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡‹‹‹‹‹‹‹‹‹‹‹‹Š€‚‚€‚ƒ„…ÿ†‡ˆ‰Š†€‚‚€‚ƒ„…†‡ˆ‰‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‰‰ƒƒ——‹—…‚—ˆ————‰€‚ƒ‚€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‰€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‰‚ƒ——‹—…‚—ˆ————€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹†ŒŒ‰€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—€‚‚€‚ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚‹‹‰‹‹‹‹‹ÿ‹‹ˆ€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŒŒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‚›…››—€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹Œ‡ƒ€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š™››‹››€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹Œ‡€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›ˆœ„œ„œœ‰œœœƒ€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›’œ„œƒœœˆÿœœœ’„œœœœœœœœœœœ‡ƒŒˆœ˜œ„œƒœœˆœœœ‘„œœœœœœœœœœœˆ‚ƒ‹ˆœ˜š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆ‡ˆˆˆˆˆˆˆˆˆˆˆˆ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜†ˆ‚ƒ™™‚™ƒ™‹™™Œ™™™™‡™™™™™™™™™™™™˜ˆ‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‡‹‹‹‹‹‹‹ÿ‹‹‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰Š†‹‹‹‹‹‹‹‹‹ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜—Šƒƒ™™‡™ƒ‰ˆƒ‡™™‹™™™˜‡™™™™™™™™™™™™—‹‚ƒ™™‡™ƒ‚‡ƒ‡ƒ‡™™‹™™™˜‡™™™™™™™2eÊ”)Ó%@‚‚€‚ƒ‚ÿ‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚‡ƒˆˆ€‚ƒƒ€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠŠŠŠ‰‡€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›’€‚ƒƒ€‚ƒ„…†‡ƒˆƒ‡ƒ‡ˆˆˆˆˆˆˆ„ˆˆˆˆˆˆˆˆˆˆˆˆƒ†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š››œƒ‡ƒ‡œœ„œœœ†œœœœœœœœœœœœœœœ€‚‚€‚ƒ‚„‚ƒ„ƒ€‚ƒ„…†‡ˆ‰Š…‹‹‹ÿ‹‹‹‹‹‹„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œœŽ…ƒˆœœ„œœœœœœœœœœœœœœœœœœœ„œœƒœœœœœœœœœœœœœœœœœ“œœˆœœƒœœœœœœœœ8qâĉ'Nœ8U 8HXhx 8 8HXhx8€ˆˆˆˆˆˆ8H€ˆˆˆˆˆˆˆˆˆˆhXPP 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉyÐÙyÐÙIÐÙÙYXPPP8ÐÙÙÙÙÙÙÙÿÙÙÙÙÙÙyÐÙyÐÙIÐÙÙ9XP€8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙyÐIÐ)ÐÙIÐÙÙ9Xp80ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ‰ 8HXhX 8 8HXhx8€ˆˆˆˆˆˆ@€ˆˆˆˆˆˆˆˆˆˆ(X`80 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É©À@Ð)ÐÉIÐÙÙ9XP8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙÉÐÙyйIÐÙÙ9X@80ÐÙÙÙÙÙÙÙÙÙÙÙÙÙÙÐÙyйIÐÙÙ9X08ÐÙÙÙÙÙÙÙÙÙÙÙÙÙùÐ9 8HÿXhxH€ˆˆˆˆˆˆH€ˆˆˆˆˆˆˆˆˆˆP08 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É À@Ð)ЩIÐÙÙ9X 8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙÀ@Ð)ЩIÐÙÙ)X 8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ)   8 8HXhxH€ˆˆˆˆˆxH€ˆˆˆˆˆˆˆˆˆˆP 8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹É)ÀÐyЙIÐÙÙ)X 8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙ9ÐÙyЙIÐÙÙ)X0ÐÙÙÙÙÙÙÙÙÙÙÙÙÙIÿÐ Ð9ЙIÐÙÙ)X0ÐÙÙÙÙÙÙÙÙÙÙÙÙÙIÀ 8HXhx8€ˆˆˆˆˆhH€ˆˆˆˆˆˆˆˆˆˆP0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉIÀ Ð)ЙIÐÙÙ P 8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙIÀ Ð)ЙIÐÙÙ P 8ÐÙÙÙÙÙÙÙÙÙÙÙÙÙIÐ Ð9ЙIÐÙÙ P 8ÐÙÙÙÙÙÙÙÙÙÙ©S§N”"&**,...*,......."&*.26ÿ:>BFJNRVZ^bfjnrRtttftvv tvvvvvvvvvvvvvVpt tftvv tvvvvvvvvvvvvv^pt tbtvvtvvvvvvvvvvvvvb $,4<  8<<< 8<<<<<<$$8<<<<<<<<<<<($,4?>! >  !#%')+-/13579;=>?>! 8   !#%')+-/13579;=>?>! .  !#%')+-/13579;=>?>! "ÿ   !#%')+-/13579;=>?>! < >??????????????>?>?????????????????>?>?????????????????>1>??>??  ÿ9b(@p°Ðð1Qq‘±±0ÀÑÑÑÑÑ‘1ÀÑÑÑÑÑ1ÀÑÑq1`0à0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Ô@p°Ðð11`0@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt´0`0€””””””””””””””””3 €””””””””””””””””T3@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó4Tt”´Ôô5Uu•µÕõ6Vv–¶Öö7Ww—·×÷8Xÿx˜¸Øø9Yy™¹ÙùY6 0Z1`0@P@p°Ðð1Qq‘1 €0 ±±±±±q1 @0@P@p°Ðð1Qq‘11 €0 ±±±±±q1 @0@P@p°Ðð1Qq‘±ÑñR1 €0 2222r0 `0 2222’0`0@0 2222R0`0 2222²0`0@0 2222R0`0 2222222²1 `0`0 2222 `0 2222²0 `0 2222² €€€€@ÁAÂBÃCÄDÅEÆÆ€€Á€ÆÆÆÆÆFÿÆ€€€€€ÆÆÆÆÆÆÆÆÆÆÆÂ€Á€Á€ÆÆÆÆÆFÅ€Á€Á€ÆÆÆÆÆFÅÁ€Á€ÆÆÆÆÆÆÅÁ€Á€ÆÆÆÆÆFÅ€Á€Á€ÆÆÆÆÆFÅ€Á€Á€ÆÆÆÆÆÆÆÆÆÆF€Á€AÀ@ÁAÂBÃCÄDÅEFÅ€Ã€ÆÆÆÆÆÆÄ€Á€Á€ÆÆÆÆÆFÅ€Ã€ÆÆÆÆÆFÆ€€Á€ÆÆÆÆÆFÆ€Â€ÆÆÆÆÆÆÆÆÆÆF€Á€Á€ÆÆÆÆÆFÅ€Ã€ÆÆÆÆÆFÄ€Á€ÆÆÆÆÆÆÄÄ€ÆÆÆÆÆFÆ€€Á€ÆÆÆÆÆFF€ ÿ!"#### "#### "#### "####"####"#######     !#%')+-/13579;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}ƒ…‡‰‹‘“•ÿ—™›Ÿ¡£¥§©«­¯±³µ·¹»½¿ÁÃÅÇÉËÍÏÑÓÕ×ÙÛÝßáãåçé? !#%')+-/13579;=?ACE&FGGGGGGGGGGGGGGGG FGGGGGGGGGGGGGGGGFGGGGGGGGGGGGGGGG   !#%')+-/13579;=?ACE FGGGGGaGGGGGGGGGGGFGGGGGGGGGGGGGGGGFGGGGGGGG5jÔ¨Q£F5jÔ¨Q£Fš(;openacs-5.7.0/packages/acs-templating/www/doc/time3a/stage06.gif0000644000175000017500000002736707253523117024220 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰ŠŠ„ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‰ÿŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠƒŠŠŠŠŠ…‰ŠŠ„ŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠˆŠŠŠŠŠŠŠ‰"&*.20222220222220222$020222220222220222220222220222220222220222220222 "&*.26:>BFJNRVZ^bfjnrvz~‚†2ˆ~ˆŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠvˆ~ˆŠŠŠŠŠÿŠŠŠ2   "&*.26:>BF  "& (*****"&*.26:>BFJNRVZ^b&  "&*.26:>2""    "&(*****"&*.26:>BFJNRVZ^b  "&*.22""     ÿ "&*.26:>BFJNRVZ^B ""&*..  0"&**"&*.26:>BFJNRVZ^ """&*.26:>   "&* ,....*"&*.ÿ26:>BFJNRVZZ """&*.26:>BF.   HJJHJJ.HJJJJJJJJJJJJJ& "&*.26:>BFJ  LNNLNN"LNNNNNNNNNNNN*" "&*.26:>BFJ*(  LNNLNN"LNNNNNNNNNNNNLN LNNNNÿNNNNNNNNBLNN"LNNNNNNNNNNNN LN* LNNNNNNNNNNNNN(@p°Ðð1QQ1`qqqqqqqqqqqqqqqqqqqqq€€    `qqqÑp```@p°Ðð1Qq‘±Ññ2Rr’²Ò22àòr2àòòòòòòòòò2°@p@p°Ðð1‘p@P@p°Ðð1Qq‘±Ññ2Rr’²Ò²2à²0 àR1àòòòòòòòòòr°@p@p°Ðð1p@pP@p°Ðð1Qq‘±Ññ2Rr’ÿ€€ ‘‘€€’’1€ò0€0€’1€’’’’’’’’’’ò°@p@p@p°Ððqp@pp@p°Ðð1Qq‘±Ññ2Rr’‘€`€ ‘‘€€’’1€Ò0À0€r1€’’’’’’’’’’°@p@p€ °°°°°Pp@pP@p°Ðð1Qq‘±Ññ2Rrr’€@€@‘€€@€€`€€’’1€’’²0€’’’’’’’’’ò°@p@p°PÀÐÐÐp@pp@p°Ðð1Qq‘±Ññ2Rr’Ò‘ ‘@€€` ÿ@p°Ðð°@p @p°Ðð1QQ1`qqqqqqqqqqqqqqqqqq°@p@p°ÐPàðpp@pP@p°Ðð1Qq‘±Ññ2Rr’²’`@P€€€€@p°Ðð1QQ0`qñ0 `qq `qqqqqqqqqqqqqqqqq±  `q±€€`Qp````qqqqqqqqqqqqqqqqqqqq‘ ‘`€``qqqqQ0`qÑ0 @0`q11`qqqqqqqqqqqqqqqqqѰ°@p°Ðp@p@pÿ°p@p°Ðð1Qq‘±Ññ2Rr’²’‘ ‘@€€`ÀÒ²1ÀÒ0 @0À21ÀÒÒÒÒÒÒÒÒ’°  @P@p°Ðp@p°Ðð1Qq‘±Ññ2Rr’²R@P@pP€€@€€@p°Ðð1Qq0`qÑ0 @0`q11`qqqqqqqqqqqqqqqqqq°`Ñ@p@p°Ðp@p°Ðð1Qq‘±Ññ2Rr’²ÒòÓ2 “0 ó0 333333³  @P@p°ÐðPp@p°Ðð1Qq‘±Ññ2Rrÿ’²Òòó2 3ó1 333333Ó²  @p@p°Ðððp@p°Ðð1Qq‘±Ññ2Rr’²Òòó2 ó0 ó0 333333ó°@p°@p€€€€€pp`@p°Ðð1Qq‘±Ññ2Rr’²Òò3 s0€0 Ó0 333333°@p@p€€€€p``@p°Ðð1Qq‘±Ññ2Rr’²R± `°  €±± ÀÒ1ÀÒ0€0À21ÀÒÒÒÒÒÒ°@p@p°°€€€ÀÐÐÐÐаpÿ``@p°Ðð1Qq‘±Ññ2Rr’²²± @°`°`±± ÀÒ1À’0@p0@p°Ðð0@p°Ðð1Qq‘±Ññ²°@pp@p°ÐðP€€€qp`@p°Ðð1Qq‘±Ññ2Rr’²² À°±  @°  `° ÀÒ1ÀÒ0ÀÒ1ÀÒÒÒÒÒr°@p@p°Ððq€€€ 111q``@p°Ðð1Qq‘±Ññ2Rr’²Ò’°±@°  `° °@p°Ðð°@p @p°Ðð1QQ1`ÿqqqqqqqqqq°@p@p°Ðð1‘€€€@QQQ±p``@p°Ðð1Qq‘±Ññ2Rr’²ÒÒ°`°@P    @p°Ðð1QQ0`qñ0@P@pp0€P0 €0@p°Ðð1Qq‘±Ñ°@pP@p°Ðð1ñ@p@p°Ðð1q```@p°Ðð1Qq‘±Ññ2Rr’²Ò±@±`° `°àòr1à²0 1 1`0à0àòòòr² à2@p°°@p°Ðð1Ñp@Pÿ@p°Ðð1Qq‘±Ññ2Rr’²Òr±`±@°  `°àòr1à²0 @0à0`0à0`0à0àòòò2² À@p°°@p°Ðð1Qq````€‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘±°@P@pP°  @°  @p°Ðð1Qq0`qÑ0 @0à0`01 0@pp@p°Ðð1Qq‘±± €@p°°@p°Ðð1Qq‘‘p@P@p°Ðð1Qq‘±Ññ2Rr’²Òò3“0@pp@p°Ððp0 1`0à0`0àÿ0±@pP°  @p°Ðð1Qq‘±Ñp@P@p°Ðð1Qq‘±Ññ2Rr’²Òò3Só0`Ó1`0à0`0à0`ss@p°°@p° @p°Ðð1Qq‘±Qq```ÀÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑѱ1ÀÑ0@P@pP0 €0 @0`0€p0@p°Ðð1Q@p@p°Ðð° àððððððððððððð````@p°Ðð1Qq‘±Ññ2Rr’²Òò3S2` À1 0 `0ÿ 1`s‘`±  `ssSr``ssssssssssss“2`S0 `³0`s‘`³°  `ssSr```ssssssssssssÓ2` `31`só`S° ° @p°Ðð1Qq‘±1q`ÀÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ‘1ÀÑ0@p@p°Ððp0‘q°  ±p``@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss3`ss1`sÓ³  `ss³r``ssssssssssssss0`ss1`s³ÿಠ`sssp@P@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss³0€³0€s0€“Sಀ““Sp@pP@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsS1@30@p@p°Ððp0QѰp@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsS2€3€0€s0€“€À²€“Sp@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss33€“31€“€ ²€“sp@pP@p°Ðð1Qq‘±Ññ2ÿRr’²Òò3Ss““0 ³ó0 s“ ² ³Óq``` ³³³³³³³³³³³³³“1 s0 s0 s“€² ³Óq ³³³³³³³³³³³³³2€3€0 S0 s“`² ³óq ³³³³³³³³³³³³³2€0 @p°Ððp0ñQ° `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“32@0@p0@p°Ðð0ñ Qp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“S2€3 óÿ0 S“² ³3r ³³³³³³³³³³³³³S2 ³ó0 S“À±  ³“p@p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“s2 3@0 s0 S“€±  ³sp@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“33€3@0  S0 S“@±  p@p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ó0€3 @0À À3“± ÀÓp@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³32€3 @0À À3“À° À³pÿ@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³“3 3@0ÀS0À3“€° `p@p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó31àós0à“@° Àp@pp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ós2 3 às0à“@°€r``àóóóóóóóóóóóóóóS3€3 @0à3à“@°@r`àóóóóóóóóóóóóóó³3€3 @0à3à“ r``àóóóóóóóóóóóóóÓ§O€ ÿ   !#%')+-/13579;=?:@@/ @AAAAAAAAAAAAAA-@A@/ @AAAAAAAAAAAAAA1@A@/ @AAAAAAAAAAAAAA54    !#%')+-/13579;=?6@@/ @AAAAAAAAAAAAAA;8@/ @AAÿAAAAAAAAAAAA?@@/ @AAAAAAAAAAAA P €à a¡á!baÀ`Àa@¢`@bbbbb"AÀ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§dhbÀ`Àa@@@"`€àà €à a¡á!b¢ AÀ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§"`€àà €à a¡á!baÀ`ÀaÀ`Àa@bbbbb"AÀ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§dhbÀ`ÀaÀ`Àaÿ¨%@Á(((((((((((((((è`¨b@a@€`À`Àa¨%@Á(((((((((((((((è`èb@a@À`@@b¨%@Á((((P @ (P @(@p°Ðð1QQ1`qqqQ‘ `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óós2@3Ô0Ô’ `t0@3@0t0Ô’ `”0@3@0t0Ô’ `”0@3@0@pÿ°Ððð0Ñ `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó“2@0@pP@p°Ððp0Ñ `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó“2 Ô’ `”0`0@p@p°Ðð0Ñ `@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó“2@3À0à3´’ ´0@3À0à3´’ ´0@3ÿÀ0à3´’ ´0@0@pP@p°Ððp0± @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó³2 ´’ ´0`3€04´’ ´0@3À0à3´’` ´0@3À0à3´` @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó³2@3À0à3´’` ´0`0@p@ÿp°Ðð0±` @p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó³2 ´’` ´0 ´’` ´0 ”’ Ô0 ”’ (P @ (P   $,4BFJNRVZ^bfjnrvz~n€‚€> €‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚.€‚€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚v€‚€‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚v€^$`€‚:€‚:€‚:€‚> 8HXhxˆ˜¨¸ÈÀÈÈÈÈÈhÀÈÈÈÈÈÀÈÈÈh€ÀÈÀÈÈÈÈÈhÀÈÈÈÈÈhÀÈÈÈÈÈhÀÈÈÈÈÈxÀÈÈÈÈÈhÀÈÈÈÈÈhÀÈÈÈÈÈÀÈÈÿÈX0pÀÈÀÈÈÈÈÈhÀÈÈÈÈÈh 8HXhxˆ˜¨¸ÈÀÈÈÈÈÈxÀÈÈÈÈÈhÀÈÈÈÈÈhÀÈÈÈÈÈÀÈÈÈX0p 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù ê 8HXhxˆ˜ˆ0 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:Z0@JJJJJJJJJJJJJJJJŠ@JJJJJJJJJJJJJJJJª 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù *:JZjzŠšªºÿÊÚêú +;K[k{‹›«»ËÛëû ,<6 """""" "&*.26:>BFJNRVZ^bfjj<lnnn2ln.lnlnnnnnnnnnnÿnnj<lnnn2ln.lnlnnnnnnnnnnnnj<lnnn2lllnlnnnnnnnnnnnnj<lnnÚÄP €à a¡aa`€à €à a¡áá`""""""¢à €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦¦&ÁcÁæææ&cÀ&@aÀ&aÀæ&áÀææææææææææææ¦&ÁcÁæææ&cÀææbÀæ&áÀææææææææææææ¦&ÁcÁæææ&cÀææbÀæ&áÀææææææææææææ¦&Á#` €à a¡á!b¢â"c£ãÿcÀã£`Àã£`Àãã#ãÀããããããããããããããããããããããããã ÁcÁãããããããcÀccaÀã#@Àãã#ãÀããããããããããããããããããããããããã ÁcÁãããããããcÀccaÀã# @ÁAÂBÃCÄDE€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÈ‚ÍÍÍMÆMÀÁÁ@ÁAÂBÃCÂDDDDDDÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÈ‚ÍÍÍMÆ€M€€ÍÄ€ÍM€ÍÍÍÍÍÍÍÍÍÍÍÍÍMÈ‚ÍÿÍÍMÆ€ÍÍÅ€ÍM€ÍÍÍÍÍÍÍÍÍÍÍÍÍMÈ‚ÍÍÍMÆ€MÁÁ€Í€ÍM€ÍÍÍÍÍÍÍÍÍÍÍÍÍM"&*.26:><6<><>>*<>>>>>>>>>>>>>>>>>>>>>>>><<>>>>>>><6<><>>*<>>>>>>>>>>>>>>>>>>>>>>>><<>>>>>>>"&*.26:>BFJNRVZ^bfÿjn<prrr&pppnprrrrrrrrrrrr><prrr&pr&pnprrrrrrrrrrrr><prrr&pppnprrrrrrrrrrrr>"&*.26:>@2@>@BB@BBBBBBBBBBBBBBBBBBBBBB.<@BBBBBB&@2@>@BB@BBBBBBBBBBBBBBBBBBBBBB.<@BBBBBB&@2 """""ÿ"&*.26:>BFJNRVZ^bfjn<prrr&pppnprrrrrrrrrrrr><prrr&pr&pnprrrrrrrrrrrr><prrr&pr&pnprrrrrrrrrrrr><"&*.26:>@*@>@BB@BBBBBBBBBBBBBBBBBBBBBB.<@BBBBBB&@.@B@BB@BBBBBBBBBBBBBBBBBBBBBB*@@BBBBBB&@2,,ÿ"&*"&*.26:>BFJNRVZ^bfjn@lnnn6l>$(ln lnnnnnnnnnnnnn@lnnn6l: ,ln lnnnnnnnnnnnnn@lnnn6l:  "& "&*.26:>BFJNRVZ^bfjn@lnnn"  $&&&&&"&*.26:>BFJNRVZ^bfjn@prÿrr&p6  pjprrrrrrrrrrrr><prrr*p: pfprrrrrrrrrrrrB<prrr*p>  "&""&*.26:>BFJNRVZ^bfjn <prrr*pr&pbprrrrrrrrrrrrF<prrr*hp*pbprrrrrrrrrrrrF<prrr*hpp^prrrrrrrrrrrrJ<prrâ¤P €à a¡aa€`ÀááááaÿÀáááááá!À €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æf!Ác'''§b€f€`ça§å''''''''''''ç$Ác'''§b€&`€à  €à a¡áá`""""""À €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦!Ác'''§b'gbgå'''''''''''''%Ác'''§bÀ&`€à €à a¡á!a""""""À €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ¦!Ác'''§b€f€aç`'å'''''''''''ÿ'g%Ác'''§b€f€aç`'å''''''''''''g%Ác'''§b€f€aç`'å''''''''''''g% @ÁAÂÂ@ÁAÂBÃCÄDÅEÆFÇGÁHEÀÁAA@ÁAÂBÃÃÁDDDDDÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍC‚ÇNNNNÅNÎÄNÊNNNNNNNNNNNNÎJ‚ÇNNNNÅ€ÍÂNÂNÊNNNNNNNNNNNNÎJÇNNNÎÅÍÃÎÁNÊNNNNNNNNNNNNNJ‚GÀ@ÁAÂBÿÃCÄDÅEÆFÇÇÁHÅÃÈÇHHÈHHHHHHHHHHHHHHHHHHHHHHHH‚ÇHHHHHHÈÅHÅÃÈÇHHÈHHHHHHHHHHHHHHHHHHHHHHHHÇHHHHHHHÆÈEÀÁA@ÁAÂBÃCÂDDDDDÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMCÇNNNNÆNÎÄNÊNNNNNNNNNNNNNJÇNNNNÆNÎÄNÊNNNNNNNNNNNNNJÇNNNNÆNÎÄNÊNNNNNNNNNNNNÎIÇNNÿNÎFÀ@ÁAÂBÃCÄDEÅ€ÅÅÅEÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍBÇNNNÎÆNÎÄNÊNNNNNNNNNNNNÎIÇNNNÎÆNÎÄNÊNNNNNNNNNNNNÎIÇNNNÎÆNÎÄNÊNNNNNNNNNNNNÎIÇNNNÎFÀ@ÁAÂBÃCÁDDDDÁDDDDDÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍÍBÇNNNÎÆNÁNÃNÊNNNNNNNNNNNNÎIÇNNNÎÆNÁNÃNÊÿNNNNNNNNNNNNÎIÇNNNÎÆNÁNÃNÊNNNNNNNNNNNNÎIGÀ@ÁAÂBÃCÄDÅEÆFÇÇÂHÇHHÁHHÈHHHHHHHHHHHHHHHHHHHHHHÈGÇHHHHHHÈÆHÈÅÆÄHHÈHHHHHHHHHHHHHHHHHHHHHHÈGÇHHHHHHÈÆHǀŀŀÄHHH@€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›…Žœœœœœ‚Šƒˆˆœ”œœœœœœœœœœœœœ“Žœœœœÿœ‚Šƒ‡‚ˆ€‚ƒƒ€‚ƒ„…†‡ˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›…Žœœœœ…€‚ƒƒ€‚ƒ„…†‡‚ˆ‚ƒ‡‚ˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›…Žœœœœœ‚Šƒ‡€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›…ŽœœœœœŽ„…ˆœ”œœœœœœœœœœœœœ“Žœœœœœ……ˆœÿ”œœœœœœœœœœœœœ“Žœœœœœœ‰œ”œœœœœœœœœœ8qâ4  €à !a €à a¡á!b¢â"c£ãca$$$$@$$ä$$$$$$$$$$$$$$$$$$$$$$ä#c$$$$$$dc$$$$@$$ä$$$$$$$$$$$$$$$$$$$$$$ä#c$$$$$$dc$$$$@$$ä$$$$$$$$$H A‚ $H A‚é @ÁABÂ@ÁAÂBÃCÄDÅEÆFÇÇÂHHHH€HHÈHHHHHHHHHHHHHHHHÿHHHHHHÈGÇHHHHHHÈÆHHHH€HHÈHHHHHHHHHHHHHHHHHHHHHHHG‚ÇHHHHHHÈÆHÆ€€€HH€HHÈHHHHH A‚ $H A‚ $H 9D 8HXX 8HXhxˆ˜¨¸ÈØèøX¹@  9 éHðX Ù©`ù 9 éHðX Ù  9 $H A‚ ÿ$H A‚ $G€    !!! !! !!!!!!!!!!!!!!!!!!!!!!  !!!!!! ! ! !! !!!!!!!!!!!!!!!!!!!!!!  !!!!!!   !! !!!!!!A‚ $H A‚ $H 9D 8HHX 8HXhxˆ˜¨¸ÈØèøhÉ@ù 9 éHàX é© 8 8HÿXhxH€ˆˆˆˆˆ8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹IHàXÀÉÉÉéÀÀ‰ÀI9ÀÉÉÉÉÉÉÉÉÉÉÉÉ)IàXÀÉÉÉéÀÉ™ÀI9ÀÉÉÉÉÉÉÉÉÉÉÉÉ)IàXÀÉÉÉéÀÉ™ÀI9ÀÉÉÉÉÉÉÉÉÉÉÉÉIðXÀÉÉÉé(@p°Ðð1QQ1`qqq‘p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Sssà±€“““Ó1€“31€“r€““““““““““““3’à±€“““Ó1€“31€“r€““““““““““““3’à±€“ÿ““Ó1€“31€“r€““““““““““““’²€“““Ó0@p°Ðð1QQ1`qqq‘p@p°Ðð1Qq‘±Ññ2Rr’²Òò3SsS²€“““Ó1€3@0€³0€sr€““““““““““““’ ²€“““Ó1€3@0€³0€sr€““““““““““““’ ²€“““Ó1€3@0€³0€sr€““““““““““““ó €à aá` €à a¡á!b¢â"c£ã£a$c€`$$@$äã$$$$$$$$$$$$$$$$$$$$$$ä"¤`$$$ÿ$$$¤c$c€`$$@$äã$$$$$$$$$$$$$$$$$$$$$$ä"¤`$$$$$$¤c$$$$@$ä#à €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&d'''§c@fÀaç`çä''''''''''''ç#d'''§c€f@a'açä''''''''''''ç#d'''§cÀfÀ`Àb€b@@bçä''''''''''Nœ8=D 8HX8X 8HXhxˆ˜¨¸ÈØèøhɰ€0p ù8 ÿ ¹H)X éÙ°0°p ù8 ¹H)X é ™P@ €à a!!`€àà €à a¡á!âà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&Ad'''ç!`€àà €à a¡á!baÀ`@b@b@bbbb¢à €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&Ad'''çcgcÀ`b€bçä''''''''''''ç#Ad'''çc§ÿc@a@€`Àbçä''''''''''''ç#Ad'''çcçc@a@€ `€  €à @ €à a¡á!b¢à €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&Ad'''çc'gbçä''''''''''''§#d'''çc'gbçä''''''''''''§#d'''çc€f§bçä''''''''''''§#d'''ç# @ÁAÂBÀÃÃÃÃÃÁ€ÃÃÃÃÃÃÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLMM‚É‚ÍÍÍÍÿÉMÀÁAA@ÁAÂBÃÃÁDDDDÄÃ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLMM‚É‚ÍÍÍÍÉÍ€ÍÅ€MÊÍÍÍÍÍÍÍÍÍÍÍÍMM‚É‚ÍÍÍÍÉÍ€ÍÅ€MÊÍÍÍÍÍÍÍÍÍÍÍÍMM‚É‚ÍÍÍÍÉ€ÍÍÅ€MÊÍÍÍÍÍÍÍÍÍÍÍÍMM‚É‚ÍÍÍÍI@€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™šš“››››“š†›„›”›››››››››››››š“››››“›„›…›”›ÿ››››››››››››š“››››“››†›”›››››››››››››‡ "&(*****(***"&*.26:>BFJNRVZ^bfj $LhD0$lNln.lRlnnnnnnnnnnnn       ÿ   "&*.26:>BFJNRVZ^bfj$         dh llRlnnnnnnnnnnnn             ÿ      "&*.26:>BFJNRVZ^bfj             hh llRlnnnnnnnnnnnn       ÿ    """""&*.26:>BFJNRVZ^bfj             hln.lRlnnnnnnnÚ´iÓ¦M™"&*.26::<>>><>> <>>>>>>>>>>>>>>>>>>>>>>>>ÿ<  <>>>>>>:<>>><>> <>>>>>>>>>>>>>>>>>>>>>>>><<>>>>>>>&<>>>"& "&*.26:>BFJNRVZ^bfjfHlnnnVln.lRlnnnnnnnnnnnnfHlnnnVln.lRlnnnnnnnnnnnnfHlnnnVln.lRlnnnnnnnnnnnnfHlnnnV"&**,..."&*.26:>BFJNRVZÿ^bfjfHlnnnVln.lRlnnnnnnnnnnnnfHlnnnVln.lnnnnnnnnnnnnnnnnnnnnln.lnnnnnnnnnnnnnnnnnnnnln$"&*.2&466666&466666*466666&466666*466666&4.4666  4466666&466666&466666*466666&466666*466666&4.4666ÿ "&*.2&466666&466666*466666&466666*466666&4.4666 "&*.26:>BFJNRVZ^bfjnrvz~‚†:"&" "&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ ’’’’’’’’’’’’’’’’b’’’’’’’’’’’’’’’’j"&*.26:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâÿæêîòöúþ #'+/37;?û "&*.2022222  "&*.&022222  "&*.&022222  "&*.268:::: 8:::: 8::::  8::::  8::::  8::::  ÿ8:::::6"&*."   02222.  022222  022222 022222  022222 02222222  022222"( @p°Ðð1Qqñ0`0`0 `0€‘‘‘‘‘q0@0`0 `0€‘‘‘‘‘Q0@0`0 `0€‘‘‘‘‘Q0 @0`0 `0€‘‘‘‘‘ @0`0 `0ÿ€‘‘‘‘‘‘‘‘0 `0€‘‘‘‘‘‘0`0`0 `0€‘‘‘‘‘ à0 @p°Ðð1Qq1`0`0 `0€‘‘‘‘‘ à0 `0€‘‘‘‘‘‘0 `0 `0€‘‘‘‘‘q0 0 `0€‘‘‘‘‘‘‘‘0 `0€‘‘‘‘‘‘0`0`0 `0€‘‘‘‘‘ à0 `0€‘‘‘‘‘ €0`0 `0€‘‘#FŒ  "&*.*  022222 02222222 022222ÿ 022222   022222 022222 022222 "&*.  02222222 022222  "&*.  "&*."  "&*.  "&*.&022222  "&*.2ÿ6:>BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏW,<ÐÓÓ£Go @ÁAB€€ÂÂBÂ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÅ€€€€Ä€€€Á€€€Â€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€€€Á€ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑQƀŀ€Á€Ã€ÑÑјÑÑÑÑÑÑÑQ£F5j#@€‚ƒ„„„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢Œ‚ˆ„ƒ„£££££££££££££££££‰‚ƒ‚ƒ££££££££££££££££££££££££££“;openacs-5.7.0/packages/acs-templating/www/doc/time3a/stage08.gif0000644000175000017500000003046107253523117024207 0ustar frankiefrankieGIF87a€ðæÿÿÿ@@@$§§€€€ÛXXÀÿÀÿ@À@@ÿ€ À€À`€€€@€€À`ÀÀÿ € 0`€@@@@€€€`€`€``€`€Àÿ`@À€` À`À`À €€€` €```ÿÿ @@ @€`€ `€``€€€€@€€€    ÐàÀ À`€ÀàÀ`ÀÀ€À€`ÿ@ÿ@@€Àÿÿ€`ÿ€€À ÀÀÀÀÿÀÿÿÿÿ€ ÿ€ÿÀÀ ÿ``ÿ€ÿ €àà àà ÿ ÀÀÀ    ÿ€ € €@€@ €@€€`À€`ÿ€€ €ÿÀ`€ÀÀÿ€@ÿ @ÿ `ÿ pÿÀ ÿÀÀÿÿÿÿ€ÿÿÀ,€ðÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêë”ìììììâìììììဂƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£‰‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Ž€‚ƒ„…†‡ˆ‰Š‰†ŠŠŠŠŠŠ‡ŠŠŠŠŠŠ†ŠŠŠŠŠŠ‡ŠŠŠŠŠŠ‡ŠŠŠŠŠŠÿ‡ŠŠŠŠŠŠ‡ŠŠŠŠŠŠ‡ŠŠŠŠŠŠ‡ŠŠƒŠŠŠŠŠ…‰†ŠŠŠŠŠŠ‡ŠŠŠŠŠŠ†ŠŠŠŠŠŠ‡ŠŠŠŠŠŠ‡€‚ƒ„…†‡ˆ‰Š‹ŒŒŒŒŒ‡ŒŒŒŒŒ‡ŒŒŒŒŒ‡Œ‹ŒŒŒŒ‡‰†ŒŒŒŒŒ‡ŒŒŒŒŒ†ŒŒŒŒŒ‡ŒŒŒŒŒ‡ŒŒŒŒŒ‡ŒŒŒŒŒ‡ŒŒŒŒŒ‡ŒŒŒŒŒ‡Œ‹ŒŒŒŒ…€‚‚€‚ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡Œ¢Ÿ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢Ÿÿ¢¢¢¢¢¢¢˜€‚ƒ€‚ƒ„…††€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“‚„‡€‚ƒ„…†‚€‚ƒ„…†‡ˆ‰‚ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•”€‚ƒ„€‚ƒ„…†‡…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘Š€‚ƒ„…†‡ˆˆ€‚ƒƒƒ‚€‚ƒ„…†‡ˆ‰‡ŠŠŠŠŠŠ…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•Š€‚ƒ„€‚ƒ„…†‡ˆ‡‰‰‰‰‰‰‰‰‰‰‰‰‰ƒ€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡‚ƒˆÿ‚ƒˆˆˆˆˆˆ„ˆˆˆˆˆˆˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“””€‚ƒ„€‚ƒ„…†‡ˆ‰ˆŠŠŠŠŠŠŠ†€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹Œƒ‡‚ƒŒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹Š€‚ƒ„€‚ƒ„…†‡ˆ‰Š‰‹‹Š€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‚ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‹‹‹Š‹‹ÿ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹€‚ƒ„€‚ƒ„…†‡ˆ‰Š‰€‚ƒ„…†‡ˆˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘ƒ‡ƒƒ’’’ƒ’’’‹’’’’’’’’’’ˆ€‚ƒ„…†€‚ƒ„…†‡ˆ‰‚€‚ƒ„…††€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“Šˆ‚ƒ””‘”””…”””””””’€‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰Š‚€‚ƒ„€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“ŽŠ‚””’”ÿ””…””””””‡€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹Š€‚ƒ„€‚ƒ„…†‡ˆ€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—Š˜˜‘˜˜˜˜€‚ƒ„…†‡ƒ€‚ƒ„…†‡ˆ‰Š‹Œ†€‚ƒ„€‚ƒ„…†‡ˆ‡€‚‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜‘˜˜’€‚ƒ„…†‡‚€‚ƒ„…†‡ˆ‰Š‹ŒŽŒ€‚ƒ„€‚ƒ„…†‡ˆ‰„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—”˜˜‘˜˜‚€‚ƒ„…€‚ƒ„…ÿ†‡ˆ‰Š‹ŒŽ€‚ƒ„€‚ƒ„…†‡ˆ‰…€‚ƒ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜˜„˜‰˜˜‚˜˜˜˜˜–€‚ƒ„€‚ƒ„…†‡ˆ‰€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”„ˆ••Š•†„•‹••ˆ••••••‡€‚ƒƒ€‚ƒ„…†‡ˆ„€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•‰ƒˆ––ˆ–„†–‰––…–––––Ž€‚ƒ„€‚ƒ„…†‡†€‚ƒ„…€ÿ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–‚‚Š‚ƒ——†——“——ƒ—————€‚ƒƒ€‚ƒ„…†‡€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—‰‚ƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹…‹‹‹‹‹‹‹‹‹†€‚ƒ„€‚ƒ„…†‚€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡‹‹‹‹‹‹‹…‹‹‹‹ÿ‹‹‹‹…€‚ƒ„‚€‚ƒ„…†„€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜‡‰ƒƒ™™‡™ƒ‚™†™˜™™™ƒ€‚ƒ„…€‚ƒ„…†‡ˆ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜‰‚ƒ™™‡™ƒ‚™†™˜™™€‚ƒ„…€‚ƒ„…†‡ˆ‰…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜Ž€‚‚€‚ƒ‚‚€‚ƒ„…†‡ˆ‰Šƒ‹‹†‚‹‹‰‹‹‹‹…‹‹‹‹ƒ€‚ƒ„…ÿ€‚ƒ„…†‡ˆ‰Š‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘œœ„œ•œ„€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹Œ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‘œœ‰œ•‘€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒƒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ„ŽŽ„ŽŽ„ŽŽŽ‡‰€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŠ€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›“œ„œƒœ•‰œœœˆ€ÿ‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜”ƒŒˆ™™‚™ƒ„™†™˜ˆ™™™ƒ€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™‹‚ƒ‹ˆššš€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ†€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š†ˆ‚ƒššš‚šŠš—ˆš•€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š˜ˆ‚ÿƒ€‚ƒ„…†‡…€‚ƒ„€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹…‡‹‹Š€‚ƒ„…€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›‹ƒ€‚‚€‚ƒ„…†‡ˆ‰Š‚‹‹‡€‚‚€‚ƒƒ„„‚„„€‚ƒ„…†‡ˆ‰„‡ŠŠ„€‚ƒ‚€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›šŠƒƒœœœ‰ˆƒ‡œ•‡—œœœœœœœœœœœœœœ“‹‚ƒœœœÿ‚‡ƒ‡ƒ‡œ•†—œœœœœœœœœœœœ8q¢¨@P@pP°  @°  @p°Ðð1Qq0`qÑ0 @0à0`01 0@pp@p°Ðð±À° 1‘p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“0@pp@p°Ððp0 1`0à0`0à0€À°Ñp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Ó“3àS1`0à0`0à0àS’ °Àràóóóóóóóóóóóóóó³3 0@P@pP0ÿ €0 @0`0€p0@p°Ðð1‘ °@Q`@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³ÓÓ3€3À1 0 `0 1àS’ ° ràóóóóóóóóóóóóóóÓ3 3 à àS’ ° ràóóóóóóóóóóóóóóÓ3€3à³0àS’ °€ràóóóóóóóóóóóóóóÓ'@€‚ƒ„…†‡€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆ…ˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸŸŸƒŸ’…”ŸŸŸŸŸŸŸŸŸŸŸŸÿŸŸŸŸŸŸƒŸ’…”ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ‚ŸŸ’…”ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸš€‚ƒ€‚ƒ„…†‡ƒˆˆˆˆˆˆ…ˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸœ„ŸŸ’…“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸƒŸ’…“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸƒŸ’…“ŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ€€‚ƒ„…†‡ˆ‰„…Љ€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š›œžŸœ„Ÿ ‘…“               ‘œ„Ÿ ‘„”               ‘š€‚ƒ€‚ƒ„…†‡„ˆˆˆˆˆˆ„ˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸœ „ ‘„”               ‘   ‘„”               ‘‚  ‘„”               ‘œ‚€‚ƒ„…†‡ƒˆˆˆˆˆˆ„ÿˆˆ„€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸœ‚Ÿ ‘„”               ‘œ‚Ÿ ‘„”               ‘‚  ‘„”               ‘€€‚ƒ„…†‡ˆ‰ŠŠ‹‹‹‹…„‹‰€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ‚ ‘„”               ‘œ‚Ÿ ‘„”               ‘œÿ‚Ÿ ‘„”               ‘€€‚ƒ„…†‡‚‡‡‡‡ƒ‡‡‡‡‡‡‡„‡‡†€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ  ‘„”               ‘   ‘„”               ‘   ‘„”               ‘š†Ÿ€‚ƒ„…†‡ˆ‰„„ŠŠ€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ›„  „•ÿ               ‘œ‹‹‡ „•               ‘ Š‰Š „•            @ P €à a¡á!baÀ`Àa@¢`@bbbbâ aAbâà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'@hbÀ`Àa@@@"`€àà €à a¡á!"!aAbâà €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§'&`€àà €à a¡á!baÀ`ÀaÀ`Àa@bbbbâ aAbâàÿ €à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç'@hbÀ`ÀaÀ`Àa($aAå((((((((((((((hd¨b@a@€`À`Àa($aAå((((((((((((((hdèb@a@À`@@b($aAå(((P @ (P @Š(@p°Ðð1QQ1`qqq‘€°`Qq@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó @3Ô0’€° r42@3@0t0’€° rÿ42@3@0t0’€° r42@3 @p°Ððð0‘€°±p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó @0@pP@p°Ððp0‘€°±p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó  ’€° r42`0@p@p°Ðð0‘€°±p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óóÿ @3À0à3’€° r42@3À0à3’€° r42@3À0à3’€° r42@0@pP@p°Ððp0‘€°±p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó  ’`°Àr42`3€04’`°Àr42@3À0à3’@°àr42@3À0à0@p°ÿÐð1q@°@Qqp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó @3À0à3’ s42`0@p@p°Ðð0‘ q@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó  ’ s42 ’ s42 ’ s42 ’ @p°Ðpp@p°Ðð1Qq‘±Ñÿñ2Rr’²Òò3Ss“³Óó  ’ s42 ’ s42 ’ s42À3T0’°@p°Ðpp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó À3T0’  s42À3T0’  s42À3T0’  s42À3T0’ @pÿ°Ðp@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó t1€11’  s42À3`1 @1 1’  s42À3@1`01 1’  s(P‘    "$&"&*.26:>BFJNRVZ^bfjnrvzb     """"" "" ÿ"&*.26:>BFJNRVZ^bfjnrvz~x(  "&(*"&*.26:>BFJNRVZ^bfjnrvz~€* €Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€. €Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F"&**,...,."&*.26:>BFJNRVZ^bfjnrvz~€‚€Bÿh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€Bh€‚‚‚‚‚‚‚ (P @E 8HXhxpxxxXpxxxxxhXpxxX8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù °@ Y 9  `ð Y 9   Y 9   Y 9ÿ (P @ (P‘ """ """"" "" "&*.26:>BFJNRVZ^bfjnrvz~p|€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fp|€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fh """"" "" "&*.26:>BFJNRVZ^bfjnrvz~p€€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚ÿ€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€Bh€‚‚‚‚‚‚ (P @Š(@p°Ðð1QQ1`qqq‘°`q‘p@p°Ðð1Qq‘±Ññ2Rr’²Òò3Ss“³Óó  ²@s42 ²@s42 ²@s42€3@0 ²@s(P @ (P‘ÿ"&*.26:>BFJNRVZ^bfjnrvz~p€€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fp€€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fp€€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€‚€B"&*.26:>BFJNRVZ^bfjnrvz~d|€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fh€€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fl ,( €Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Fÿp   "&*.26:>BFJNRVZ^bfjnrvz~t, ,€Bh€‚‚‚‚‚‚‚‚‚‚‚‚‚‚F€& ( "$&"&*.26:>BFJNRVZ^bfjnrvzf" $$$&&&&$&"&*.26:>BFJNRVZ^bfjnrvz~ €&  (€Bd€‚‚‚‚‚‚‚ÿ‚‚‚‚‚‚‚J€*,€Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚J€. "&(*"&*.26:>BFJNRVZ^bfjnrvz~ €‚€Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚J€‚€Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Jh€€Bd€‚‚‚‚‚‚‚‚‚‚‚‚‚‚Jh€€Bd€‚‚‚‚‚ (P @% P €à a¡a!`€à  €à a¡áá`"""""b"""À ÿ€à a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§ç§`€f¨a(dAæ((((((((((((((¨d€f¨a(dAæ((((((((((((((¨d((@è#AAæ((((((((((((((¨d((@è#AAæ((((P @ (P @I 8HXhX`pxxx8pxxxxxXHPpxxH8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù)°@úHP9 *À úHP9 *ÿ  ( 88@@( 8HXhxˆ˜¨8°¸¸¸¸¸¸0°¸¸¸¸¸¨°¸°¸¸¸¸h@P°¸¸x°¸¸¸¸¨°¸¸¸8HP°¸88°¸¸¸¸¸¸¸¸¸H°x°˜°¸¸¸°¸¸¸¸¸¸  °¸¸¸¸¸¨°¸°¸¸¸¸¸P 8HXhxˆH˜˜˜˜˜˜(˜˜˜˜(X˜ˆ8˜˜˜˜˜˜˜˜˜˜˜hP0 0000€000 0 € 0ÿ0000    880@0 @H000 000@H00@H00 @H0@H000 0 8HXhXpxxhpxxxxpxxxxxXXpxxX8 8HXhxˆ˜¨¸ÈØè˜0@@`0 0p 0 0ÿ00    000000 ° P@0 p  8 @0@8 00 @8 0@80 0@@@0 @HHHHH@HHHHH(0@HHHHHHH( 8HXhxˆ˜(X ¨h8 ¨¨¨¨¨¨¨¨¨¨HpP@`000ÿpP (0(  8H0@0@ (   8H(0@ ( 8HP (  (0( ( 80  @H0 (0( 80 @H@8@@@ ( 8HXhHpxxX0pxxxhpxxxxxXXpxxX8 8HXÿhxˆ˜¨¸ÈØè˜pP@`00 €PP00€0 0P0P€P 0°0 P@P°P€ 00PP°00@€0PP  ((  ( ((( (( ( ( ( (  8HXhHpxxX0pxxxhpxxxxxXXpxxX8 8HXhxˆ˜¨¸ÈØè˜`@@ 000°PP  ÿP0  p P00P000°  P P°PP00 P0 8H0 0P( PP0P(00P(P(@   P0PXXXXPXXXX 8( 8HXhx8€ˆˆˆˆxX€ˆˆ(8€ˆˆˆˆˆˆˆˆˆˆˆˆˆ( (0 00 8(@(0  ÿ0@@H @(00000 @HH @(0 @H8@(000@(0@H0  8(00 0@80 @H @(@@0 0@HHHHH 8HXhxˆ˜¨¨°¸¸¸8X°¸H8°¸¸¸¸¸¸¸¸¸¸¸¸x0°¸°¸˜°¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸h ( 8HÿXhxˆ˜¨¸ÀÈÈÈÈXÀÈȸXÀÈ(8ÀÈÈÈÈÈÈÈÈÈÈÈxÀÈÀÈxÀÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈȸÀÈÈÈÈXÀÈȸXÀÈ(8 8HXhxˆ˜¨¸ÈØèø)9IYiy‰™©¹ÉÙéù) úX 9 * úX 9 * úX9 : úX9 (P @5 P €à a¡á!b¢¢bÀââââ`Áââà €ÿà a¡á!b¢â"c£ã#d¤ä$e¥å%f¦æ&g§çç`((@ècAæ((((((((((((((èd((@((((((((((((((((hg((@((((((((((((((((hgèe@b€a(è`(¨`(è`(è  @ÁAÂBÃCÄDÅE€FFFFÆÃFFFFÆÃFFFFÆÃÆÅFFFFÀÄÃFFFFÆÃFFFFFÃFFFFÆÃFFFFÆÃFFFFÆÃFFFFÆÃFFFFÆÃFFFFÆÃÆÅFFFÆÂ€Á€ÃÃFFFFÆCÿÀ@ÁAÂBÃCÄDÅÅ€ÅÅÅÅÅE€€ÅÅÅÅÅE€€ÅÅÅÅÅE€€ÅÅÅÅÅE€€ÅÅÅÅÅE€€ÅÅÅÅÅE€€ÅE€€ÅÅÅÅÄ€Á€CÀÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPG@ÁAÂBÃCÄDÄ€Á@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑÑ€ÁRRRRRRRRRRRRRRRRRÌ€RRRRRRRRRRRRRRRRRÍ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍMÎNÏOÐPÑQÒRÓSÔTÕUÖV×WØXÿÙYÚZÛ[Ü\Ý]Þ^ß_à`áaâbãcädåeæfççÛကáá€€à€€€ß€Â€Þ€€ÞÃހ€€hÅ€à€ÁàÀ@ÁAÂBÃCÄDEÅ€ÅÅÅÅÅÅ€Á€ÅÅÅÅE€ÅÅÅÅE€€Á€Á€ÅÅÅÅÅÁ€€Â€€ÅÅÅÅE€€ÅÅÅÅÅÅÅE€Á€ÅÅÅÅÅE€€ÅÅÅÅEÄ€€ÅÅÅÅÅÄ€ÅÅÅÅÅE€€Á€ÅÅÅÅÅ€€Á€Á€ÅÅE‹  8 8HXhxˆ˜¨(@°¸¸¸¸80°¸¸¸ÿ¸¸¸¸X0°¸¸¸¸¸°¸¸¸¸ˆ °¸¸¸¸˜°¸¸¸¸¨°¸¸¸¸ˆ00°¸¸¸¸H`°¸¸¸¸X0 °¸¸¸¸X0°¸¸¸¸¸¸¸(P@ €à a¡á!b¢¢bÀââââbb€`ÀââââbbÀ`Àââââ"bÀ`ÀâââââaÀ`À`Àââââ"a@aÀââââ¢aÀ`€`ÀââââbaÀ`À`Àâââââââ"@À`ÀââââbbÀââââ¢"`€  €à a¡á!b¢"bÀ`Àââââ"bÀ`ÀâââââaÀ`À`Àââââ"aÿaÀâââââaÀ `€  €à a¡á!b¢"aÀ`À`Àâââââââ¢`@ÀââââbbÀââââââ`ÀââââbbÀ`Àââââ"bÀ`Àâââââaa@ÀââââbaÀ`Àââââ"b€aÀââââbaÀ`À`Àââââââââ`Àââââ¢"`€  €à a¡á!b¢¢bÀââââ¢b@@Àââââ¢b@@Àââââ¢!`€  @ €à a¡á!b¢"!`€  À  €à a¡á!b¢¢ `€  @ €à a¡á!b¢â `€  À €à a¡á!b¢â"c£ãÿ#d¤ä$e¥å%f¦æ&g§ç'h¨è(i©é)jªê*k«ë+l¬ì,m­í-n®î.o¯ï/p°ð0q±ñ1r²ò2s³ó3t´ô4uµõ5v¶ö6w·÷7x¸ø8y¹ù9zºú:{»û;|¼ü¼uÀb@@Àc@@===zô6 $(,,$ $,4BFJNRVZ^bfj^llnnjÿlllnlnnnnnnnnnnnn^llnnjlllnlnnnnnnnnnnnn^llnnjhllnlnnnnnnnnnnÚ´é @ÁAÂBÃCÂDDDDDDDDDDDDÄÁDDDDDDDD€DDDDDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍK‚Í‚ÍÍMÍ€ÍÍÅ€ÍÍÁÍÍÍÍÍÍÍÍÍÍÍÍÍK‚M‚ÍÍÍ̀̀̀ÍÍÁÍÍÍÍÍÍÍÍÍÍÍÍMK‚Í‚ÍÍÍÍ€M€Â€M€ÍÍÁÿÍÍÍÍÍÍÍÍÍÍÍÍMK@@ÁAÂBÃCÂDDDDDDDDDDDDDÂDDDÂÂDDÄÃDDDDDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLMK‚M‚ÍÍÍM€MÀÁÁ@ÁAÂBÃCÂDDDDDDD€@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLMK‚M‚ÍÍÍM€€M€€ÍÄ€ÍÍÁÍÍÍÍÍÍÍÍÍÍÍÍMK‚M‚ÍÍÍM€€ÍÍÅ€ÍÍÁÍÍÍÍÍÍÍÍÍÍÍÍMK‚M‚ÍÍÍM€€ÍÍÅ€ÍMÁÍÍÍÍÍÍÍÍÍÍÍÍMK@ÿÁAÂBÃCÂDDDDDDDDDDDDÄÂDDDDDDDD€DDDDDDÄ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLMK‚Í‚ÍÍÍM€€ÍÍÅ€ÍMÁÍÍÍÍÍÍÍÍÍÍÍÍMK‚Í‚ÍÍÍM€€ÍÍÅ€ÍMÁÍÍÍÍÍÍÍÍÍÍÍÍMK‚Í‚ÍÍÍM€€ÍÍÅ€ÍMÁÍÍÍÍÍÍÍÍÍÍÍÍMK‚MBÀ@ÁAÂBÃCÄDÅEÆFÇ€ÇÇÇÇ€ÇÇÇÅÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇF‚ÇG€‚ÇÇÇÇÇÇÇÂ€ÇÆÁ€ÇÇÁ€ÇÇGÅÇÇÇÇÿÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇGG‚ÇÇ‚ÇÇÇÇÇÇGÃ€ÇÆÁ€ÇÇAÀ@ÁAÂBÃCÄDÅ@ÁAÂBÃCÄDÅEÆFÇGÈHÉIÊJËKÌLÍK‚ÍÁ‚ÍÍÍÍÁ€M€Á€MÀÍM€ÍÍÍÍÍÍÍÍÍÍÍÍÍK‚MÁ‚ÍÍÍM€M€Á€MÀÍM€ÍÍÍÍÍÍÍÍÍÍÍÍÍK‚MÁ‚ÍÍÍM€M€Á€MÀÍM€ÍÍÍÍÍÍM›6mÚ´iÓ%@€‚ƒ„…†‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‡€‚ƒ„…†‡ˆ‰Š‹ŒŽÿ‘’“”•–—˜™š—›‚››››„™‡›„›››››››››››››››—›‚››››„š…›…›››››››››››››››—›‚››››„›ƒ‹Šˆ›››››››6mÚ´iÓ¦M›."$,4<(@DDDDDDDDDDDDD @DD$ @ @  8 @DDDDD<$,4BFJNRVZ^bfjnrvz~‚†ŠŽ’–šž¢¦ª®²¶º¾ÂÆÊÎÒÖÚÞâæêîòöúþ #'+/37;?CÿGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§«¯³·»¿ÃÇËÏÓO,<"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2,LŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ.$ ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2, ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ2"&*.26:>BFJNRVZ^bfjnrvz~‚†Š2,ŒŽŽŽŽŽŽŽŽŽŽŽ[ŽŽŽŽŽ2  ŒŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ6$  ŒŽŽŽŽŽŽŽŽ5jÔ¨Q£F5jÔ¨Q£F5 P ;openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/0000755000175000017500000000000011724401447022411 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/TclDocs/pagination.html0000644000175000017500000000673007253523117025437 0ustar frankiefrankie

    Namespace pagination

    Procedures for paginating a datasource

    Method Summary

    Listing of public methods:
    pagination::get_total_pages
    pagination::page_number_links
    pagination::paginate_query

    Method Detail

    * indicates required

    Public Methods:
    pagination::get_total_pages
      by Michael Pih
    Gets the number of pages returned by a query PRE: requires {$sql}
    Parameters:
    db * A database handle

    pagination::page_number_links
      by Michael Pih
    Generate HTML for navigating pages of a datasource
    Parameters:
    page * The current page number
    total_pages * The total pages returned by the query

    pagination::paginate_query
      by Michael Pih
    Paginates a query
    Parameters:
    sql * The sql query to paginate
    page * The current page number

    Private Methods:
    pagination::get_rows_per_page
    Returns the number of rows per page

    pagination::ns_set_to_url_vars
      by Michael Pih
    Converts an ns_set into a list of url variables
    Parameters:
    set_id * The set id

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/cms_rel.html0000644000175000017500000000415007253523117024724 0ustar frankiefrankie

    Namespace cms_rel

    Procedures for managing relation items and child items

    Method Summary

    Listing of public methods:
    cms_rel::sort_child_item_order
    cms_rel::sort_related_item_order

    Method Detail

    * indicates required

    Public Methods:
    cms_rel::sort_child_item_order
      by Michael Pih
    Resort the child items order for a given content item, ensuring that order_n is unique for an item_id. Chooses new order based on the old order_n and then rel_id (the order the item was related)
    Parameters:
    item_id * The item for which to resort child items

    cms_rel::sort_related_item_order
      by Michael Pih
    Resort the related items order for a given content item, ensuring that order_n is unique for an item_id. Chooses new order based on the old order_n and then rel_id (the order the item was related)
    Parameters:
    item_id * The item for which to resort related items

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/doc__util.html0000644000175000017500000001167007422402452025242 0ustar frankiefrankie

    Namespace doc::util

    Method Summary

    Listing of public methods:
    The namespace doc::util currently contains no public methods.

    Method Detail

    * indicates required

    Private Methods:
    set split_name $see_name doc::util::text_divider split_name :: set name_length [llength $split_name] set see_namespace [join [lrange $split_name 0 [expr $name_length - 2]] \"\"] set url \"[doc::util::dbl_colon_fix $see_namespace].html#[set see_name]\"
    procedure to deal with @see comments

    divides a string variable into a list of strings, all but the first element beginning with the indicated text {marker;} the first element of the created list contains all of the string preceding the first occurrence of the text marker
    Parameters:
    text * name of string variable (not the string value itself)
    marker * the string indicating text division
    See Also:
    proc - doc::util::find_marker_indices

    escapes out all square brackets

    given a body of text and a text marker, returns a list of position indices for each occurrence of the text marker
    Parameters:
    text * body of text to be searched through
    marker * the text-divider mark
    Returns:
    list of indices of the position immediately preceding each occurrence of the text marker; if there are no occurrences of the text marker, returns a zero-element list
    See Also:
    namespace - doc
    proc - doc::parse_file
    doc::parse_namespace
    doc::util::text_divider

    puts a space after all closing curly brackets, does not add a space when brackets are already followed by a space

    used to sort the see list, which has structure {[name} name type type url url \]
    Parameters:
    element1 * the first of the two list elements to be compared
    element2 * the second of the two elements to be compared

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/widget.html0000644000175000017500000002327007253523117024567 0ustar frankiefrankie

    Namespace widget

    Procedures for generating and processing metadata form widgets, editing attribute widgets

    Method Summary

    Listing of public methods:
    widget::param_element_create

    Method Detail

    * indicates required

    Public Methods:
    widget::param_element_create
    Dipatches subprocs to generate the form elements for setting an attribute widget param
    Parameters:
    form * Name of the form in which to generate the form elements
    param * Name of the form widget param for which to generate a form element
    order * The order that the param form widget will appear in the form
    param_id * The ID of the form widget param
    default * The default value of the form widget param
    is_required * Flag indicating whether the form widget param is optional or required
    param_source * The default source of the value of the form widget param. One of literal, eval, query

    Private Methods:
    widget::create_options_param
      by Michael Pih
    Create the options param form widget for adding/editing metadata form widgets
    Parameters:
    form * The name of the form
    order * The order of placement of the form widget within the form
    default * The default value of the form widget param value
    is_required * A flag indicating whether the form widget param value is mandatory
    param_source * The default param source for the form widget param value (literal, query, eval)

    widget::create_param_source
      by Michael Pih
    Create default param_source form widget for adding/editing metadata form widgets
    Parameters:
    form *
    order * The order of placement of the form widget within the form
    param_source * The default param source of the metadata widget (literal, query, eval)

    widget::create_param_type
      by Michael Pih
    Create default param_type form widget for adding/editing metadata form widgets
    Parameters:
    form * The name of the form
    order * The order of placement of the form widget within the form

    widget::create_param_value
      by Michael Pih
    Create default param_value form widget for adding/editing metadata form widgets
    Parameters:
    form * The name of the form
    order * The order of placement of the form widget within the form
    is_required * A flag indicating whether the value of the form widget param is mandatory

    widget::create_text_param
      by Michael Pih
    Create default text param form widget for adding/editing metadata form widgets
    Parameters:
    form * The name of the form
    default * The default value for the form widget param value
    is_required * A flag indicating whether the value of the form widget param is mandatory
    param_source * The deafult param source for the form widget param value (literal, query, eval)

    widget::create_values_param
      by Michael Pih
    Create the values param form widget for adding/editing metadata widgets
    Parameters:
    form * The name of the form
    order * The order of placement of the form widget within the metadata form
    default * The default value of the form widget param value
    is_required * A flag indicating whether the form widget param value is mandatory
    param_source * The default param_source for the form widget param value (literal, query, eval)

    widget::process_param
      by Michael Pih
    Edits a metadata form widget parameter from the form
    Parameters:
    db * A database handle
    form * The name of the form
    order * The order of placement of the param form widgets within the form
    content_type * The content type to which the attribute belongs
    attribute_name * The name of the attribute

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/stylesheet.css0000644000175000017500000000052307253523117025315 0ustar frankiefrankie BODY { color:black; background: white; font-family: NamespaceListHeader, NamespaceListFont } h1, h2, h3 { font-family: sans-serif } .NamespaceListHeader { font-weight: bold; font-size: large } .title { text-align: center } .TableHead { bgcolor: "#CCCCFF"; font-size: "+2" } .TableRow { bgcolor: white } openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/tcl-procs.html0000644000175000017500000000041607253523117025207 0ustar frankiefrankie ArsDigita Templating System, Content Management Tcl Procedure Specifications openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/content_method.html0000644000175000017500000001026407253523117026315 0ustar frankiefrankie

    Namespace content_method

    Procedures regarding content methods

    Method Summary

    Listing of public methods:
    content_method::flush_content_methods_cache
    content_method::get_content_methods

    Method Detail

    * indicates required

    Public Methods:
    content_method::flush_content_methods_cache
      by Michael Pih
    Flushes the cache for content_method_types for a given content type. If no content type is specified, the entire content_method_types cache is flushed
    Parameters:
    content_type * The content type, default null

    content_method::get_content_methods
      by Michael Pih
    Returns a list of content_methods that are associated with a content type, first checking for a default method, then for registered content methods, and then for all content methods
    Parameters:
    content_type * The content type
    Returns:
    A list of content methods or a list of label-value pairs of content methods if the " -get_labels" option is specified
    Options:
    get_labels Instead of a list of content methods, return a list of label-value pairs of associated content methods.
    See Also:
    content_method::get_content_method_options, content_method::text_entry_filter_sql -

    Private Methods:
    content_method::get_content_method_options
      by Michael Pih
    Returns a list of label, content_method pairs that are associated with a content type, first checking for a default method, then for registered content methods, and then for all content methods
    Parameters:
    content_type * The content type
    Returns:
    A list of label, value pairs of content methods
    See Also:
    content_method::get_content_methods, content_method::text_entry_filter_sql -

    content_method::text_entry_filter_sql
      by Michael Pih
    Generate a SQL stub that filters out the text_entry content method
    Parameters:
    content_type *
    Returns:
    SQL stub that possibly filters out the text_entry content method

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/item.html0000644000175000017500000004070607253523117024245 0ustar frankiefrankie

    Namespace item

    The item commands allow easy access to properties of the content_item object. In the future, a unified API for caching item properties will be developed here.

    Also see:

    namespace
    publish

    Method Summary

    Listing of public methods:
    item::content_is_null
    item::content_methods_by_type
    item::get_best_revision
    item::get_content_type
    item::get_extended_url
    item::get_id
    item::get_item_from_revision
    item::get_live_revision
    item::get_mime_info
    item::get_publish_status
    item::get_revision_content
    item::get_template_id
    item::get_template_url
    item::get_title
    item::get_url
    item::is_publishable

    Method Detail

    * indicates required

    Public Methods:
    item::content_is_null
    Determines if the content for the revision is null (not mereley zero-length)
    Parameters:
    revision_id * The revision id
    Returns:
    1 if the content is null, 0 otherwise

    item::content_methods_by_type
    Determines all the valid content methods for instantiating a content type. Possible choices are text_entry, file_upload, no_content and xml_import. Currently, this proc merely removes the text_entry method if the item does not have a text mime type registered to it. In the future, a more sophisticated mechanism will be implemented.
    Parameters:
    content_type * The content type
    Returns:
    A TCL list of all possible content methods
    Options:
    get_labels Return not just a list of types, but a list of name-value pairs, as in the -options ATS switch for form widgets

    item::get_best_revision
    Attempts to retrieve the live revision for the item. If no live revision exists, attempts to retrieve the latest revision. If the item has no revisions, returns an empty string.
    Parameters:
    item_id * The item id
    Returns:
    The best revision id for the item, or an empty string if no revisions exist
    See Also:
    proc - item::get_item_from_revision
    item::get_live_revision

    item::get_content_type
    Retrieves the content type of tyhe item. If the item does not exist, returns an empty string.
    Parameters:
    item_id * The item id
    Returns:
    The content type of the item, or an empty string if no such item exists

    item::get_extended_url
    Retrieves the relative URL of the item with a file extension based on the item's mime_type (Example: { /foo/bar/baz.html} ).
    Parameters:
    item_id * The item id
    Returns:
    The relative URL of the item with the appropriate file extension or an empty string on failure
    Options:
    template_extension Signifies that the file extension should be retrieved using the mime_type of the template assigned to the item, not from the item itself. The live revision of the template is used. If there is no template which could be used to render the item, or if the template has no live revision, the extension defaults to { .html}
    revision_id default the live revision; Specifies the revision_id which will be used to retrieve the item's mime_type. This option is ignored if the -template_extension option is specified.
    See Also:
    proc - item::get_mime_info
    item::get_template_id
    item::get_url

    item::get_id
    Looks up the URL and gets the item id at that URL, if any.
    Parameters:
    url * The URL
    root_folder default The Sitemap; The ID of the root folder to use for resolving the URL
    Returns:
    The item ID of the item at that URL, or the empty string on failure
    See Also:
    proc - item::get_url

    item::get_item_from_revision
    Gets the item_id of the item to which the revision belongs.
    Parameters:
    revision_id * The revision id
    Returns:
    The item_id of the item to which this revision belongs
    See Also:
    proc - item::get_best_revision
    item::get_live_revision

    item::get_live_revision
    Retrieves the live revision for the item. If the item has no live revision, returns an empty string.
    Parameters:
    item_id * The item id
    Returns:
    The live revision id for the item, or an empty string if no live revision exists
    See Also:
    proc - item::get_best_revision
    item::get_item_from_revision

    item::get_mime_info
    Creates a onerow datasource in the calling frame which holds the mime_type and file_extension of the specified revision. If the revision does not exist, does not create the datasource.
    Parameters:
    revision_id * The revision id
    datasource_ref default mime_info; The name of the datasource to be created. The datasource will have two columns, mime_type and file_extension. return 1 (one) if the revision exists, 0 (zero) otherwise.
    See Also:
    proc - item::get_extended_url

    item::get_publish_status
    Get the publish status of the item. The publish status will be one of the following:
    • production - The item is still in production. The workflow (if any) is not finished, and the item has no live revision.
    • ready - The item is ready for publishing
    • live - The item has been published
    • expired - The item has been published in the past, but its publication has expired
    Parameters:
    item_id * The item id
    Returns:
    The publish status of the item, or the empty string on failure
    See Also:
    proc - item::is_publishable

    item::get_revision_content
    Create a onerow datasource called content in the calling frame which contains all attributes for the revision (including inherited ones).

    The datasource will contain a column called { text} , representing the main content (blob) of the revision, but only if the revision has a textual mime-type.

    Parameters:
    revision_id * The revision whose attributes are to be retrieved
    Returns:
    1 on success (and create a content array in the calling frame), 0 on failure
    Options:
    item_id default auto-generated; The item_id of the corresponding item.
    See Also:
    proc - item::get_content_type
    item::get_mime_info

    item::get_template_id
    Retrieves the template which can be used to render the item. If there is a template registered directly to the item, returns the id of that template. Otherwise, returns the id of the default template registered to the item's content_type. Returns an empty string on failure.
    Parameters:
    item_id * The item id
    context default 'public'; The context in which the template will be used.
    Returns:
    The template_id of the template which can be used to render the item, or an empty string on failure
    See Also:
    proc - item::get_template_url

    item::get_template_url
    Retrieves the relative URL of the template which can be used to render the item. The URL is relative to the TemplateRoot as it is specified in the ini file.
    Parameters:
    item_id * The item id
    context default 'public'; The context in which the template will be used.
    Returns:
    The template_id of the template which can be used to render the item, or an empty string on failure
    See Also:
    proc - item::get_template_id

    item::get_title
    Get the title for the item. If a live revision for the item exists, use the live revision. Otherwise, use the latest revision.
    Parameters:
    item_id * The item id
    Returns:
    The title of the item
    See Also:
    proc - item::get_best_revision

    item::get_url
    Retrieves the relative URL stub to th item. The URL is relative to the page root, and has no extension (Example: { /foo/bar/baz} ).
    Parameters:
    item_id * The item id
    Returns:
    The relative URL to the item, or an empty string on failure
    See Also:
    proc - item::get_extended_url

    item::is_publishable
    Determine if the item is publishable. The item is publishable only if:
    • All child relations, as well as item relations, are satisfied (according to min_n and max_n)
    • The workflow (if any) for the item is finished
    Parameters:
    item_id * The item id
    Returns:
    1 if the item is publishable, 0 otherwise

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/publish.html0000644000175000017500000010612007253523117024746 0ustar frankiefrankie

    Namespace publish

      by Stanislav Freidin The procs in this namespace are useful for publishing items, including items inside other items, and writing items to the filesystem.

    Specifically, the content, child and relation tags are defined here.

    Also see:

    namespace
    item

    Method Summary

    Listing of public methods:
    publish::get_html_body
    publish::get_mime_handler
    publish::get_page_root
    publish::get_publish_roots
    publish::get_template_root
    publish::handle_binary_file
    publish::item_include_tag
    publish::mkdirs
    publish::proc_exists
    publish::publish_revision
    publish::schedule_status_sweep
    publish::set_publish_status
    publish::unpublish_item
    publish::unschedule_status_sweep
    publish::write_content

    Method Detail

    * indicates required

    Public Methods:
    publish::get_html_body
    Strip the {<body>} tags from the HTML, leaving just the body itself. Useful for including templates in each other.
    Parameters:
    html * The html to be processed
    Returns:
    Everything between the <body> and the </body> tags if they exist; the unchanged HTML if they do not

    publish::get_mime_handler
    Return the name of a proc that should be used to render items with the given mime-type. The mime type handlers should all follow the naming convention
    proc publish::handle::mime_prefix::mime_suffix
    If the specific mime handler could not be found, get_mime_handler looks for a generic procedure with the name
    proc publish::handle::mime_prefix
    If the generic mime handler does not exist either, get_mime_handler returns { }
    Parameters:
    mime_type * The full mime type, such as { text/html} or { image/jpg}
    Returns:
    The name of the proc which should be used to handle the mime-type, or an empty string on failure.
    See Also:
    proc - publish::handle_item

    publish::get_page_root
    Get the page root. All items will be published to the filesystem with their URLs relative to this root. The page root is controlled by the PageRoot parameter in CMS. A relative path is relative to {[ns_info} pageroot\] The default is {[ns_info} pageroot\]
    Returns:
    The page root
    See Also:
    proc - publish::get_publish_roots
    publish::get_template_root

    publish::get_publish_roots
    Get a list of all page roots to which files may be published. The publish roots are controlled by the PublishRoots parameter in CMS, which should be a space-separated list of all the roots. Relative paths are relative to publish::get_page_root. The default is {[list} {[publish::get_page_root]]}
    Returns:
    A list of all the publish roots
    See Also:
    proc - publish::get_page_root
    publish::get_template_root

    publish::get_template_root
    Get the template root. All templates are assumed to exist in the filesystem with their URLs relative to this root. The page root is controlled by the TemplateRoot parameter in CMS. The default is /web/yourserver/templates
    Returns:
    The template root
    See Also:
    proc - content::get_template_root,

    publish::handle_binary_file
    Helper procedure for writing handlers for binary files. It will write the blob of the item to the filesystem, but only if -embed is specified. Then, it will attempt to merge the image with its template.
    This proc accepts exactly the same options a typical handler.
    Parameters:
    item_id * The id of the item to handle
    revision_id_ref * required The name of the variable in the calling frame that will recieve the revision_id whose content blob was written to the filesystem.
    url_ref * The name of the variable in the calling frame that will recieve the relative URL of the file in the file system which contains the content blob
    error_ref * The name of the variable in the calling frame that will recieve an error message. If no error has ocurred, this variable will be set to the empty string { }
    Returns:
    The HTML resulting from merging the item with its template, or " " if no template exists or the -no_merge flag was specified
    Options:
    embed Signifies that the content should be embedded directly in the parent item. -embed is required for this proc, since it makes no sense to handle the binary file in any other way.
    revision_id default The live revision for the item; The revision whose content is to be used
    no_merge If present, do NOT merge with the template, in order to prevent infinite recursion in the {<content>} tag. In this case, the proc will return the empty string { }
    See Also:
    proc - publish::handle::image

    publish::item_include_tag
    Create an include tag to include an item, in the form
    include src=/foo/bar/baz item_id=item_id param=value param=value ...
    Parameters:
    item_id * The item id
    extra_args * {} A list of extra parameters to be passed to the include tag, in form {name value name value ...}
    Returns:
    The HTML for the include tag
    See Also:
    proc - item::item_url
    publish::html_args

    publish::mkdirs
    Create all the directories neccessary to save the specified file
    Parameters:
    path * The path to the file that is about to be saved

    publish::proc_exists
    Determine if a procedure exists in the given namespace
    Parameters:
    namespace_name * The fully qualified namespace name, such as { template::util}
    proc_name * The proc name, such as { is_nil}
    Returns:
    1 if the proc exists in the given namespace, 0 otherwise

    publish::publish_revision
    Render a revision for an item and write it to the filesystem. The revision is always rendered with the -embed option turned on.
    Parameters:
    revision_id * The revision id
    Options:
    root_path default All paths in the PublishPaths parameter; Write the content to this path only.
    See Also:
    proc - item::get_extended_url
    publish::get_publish_paths
    publish::handle_item

    publish::schedule_status_sweep
    Schedule a proc to keep track of the publish status. Resets the publish status to { expired} if the expiration date has passed. Publishes the item and sets the publish status to { live} if the current status is { ready} and the scheduled publication time has passed.
    Parameters:
    interval default 3600; The interval, in seconds, between the sweeps of all items in the content repository. Lower values increase the precision of the publishing/expiration dates but decrease performance. If this parameter is not specified, the value of the StatusSweepInterval parameter in the server's INI file is used (if it exists).
    See Also:
    proc - publish::set_publish_status
    publish::track_publish_status
    publish::unschedule_status_sweep

    publish::set_publish_status
    Set the publish status of the item. If the status is live, publish the live revision of the item to the filesystem. Otherwise, unpublish the item from the filesystem.
    Parameters:
    db * The database handle
    item_id * The item id
    new_status * The new publish status. Must be { production} , { expired} , { ready} or { live}
    revision_id default The live revision; The revision id to be used when publishing the item to the filesystem.
    See Also:
    proc - publish::publish_revision
    publish::unpublish_item

    publish::unpublish_item
    Delete files which were created by publish_revision
    Parameters:
    item_id * The item id
    Options:
    revision_id default The live revision; The revision which is to be used for determining the item filename
    root_path default All paths in the PublishPaths parameter; Write the content to this path only.
    See Also:
    proc - publish::publish_revision

    publish::unschedule_status_sweep
    Unschedule the proc which keeps track of the publish status.
    See Also:
    proc - publish::schedule_status_sweep

    publish::write_content
    Write the content (blob) of a revision into a binary file in the filesystem. The file will be published at the relative URL under each publish root listed under the PublishRoots parameter in the server's INI file (the value returnded by publish::get_page_root is used as the default). The file extension will be based on the revision's mime-type.
    For example, an revision whose mime-type is { image/jpeg} for an item at { Sitemap/foo/bar} may be written as /web/your_server_name/www/foo/bar.jpg
    Parameters:
    revision_id * The id of the revision to write
    Returns:
    The relative URL of the file that was written, or an empty string on failure
    Options:
    item_id default The item_id of the revision; Specifies the item to which this revision belongs (mereley for optimization purposes)
    text If specified, indicates that the content of the revision is readable text (clob), not a binary file
    root_path default All paths in the PublishPaths parameter; Write the content to this path only.
    See Also:
    proc - content::get_content_value
    publish::get_publish_roots

    Private Methods:
    publish::delete_multiple_files
    Delete the specified URL from the filesystem, for all revisions
    Parameters:
    url * Relative URL of the file to write
    See Also:
    proc - publish::get_publish_roots
    publish::write_multiple_blobs
    publish::write_multiple_files

    publish::foreach_publish_path
    Execute some TCL code for each root path in the PublishRoots parameter
    Parameters:
    url * Relative URL to append to the roots
    code * Execute this code
    root_path default The empty string; Use this root path instead of the paths specified in the INI file
    See Also:
    proc - publish::get_publish_roots

    publish::get_main_item_id
    Get the main item id from the top of the stack
    Returns:
    the main item id
    See Also:
    proc - publish::get_main_revision_id
    publish::pop_id
    publish::push_id

    publish::get_main_revision_id
    Get the main item revision from the top of the stack
    Returns:
    the main item id
    See Also:
    proc - publish::get_main_item_id
    publish::pop_id
    publish::push_id

    publish::handle_item
    Render an item either by looking it up in the the temporary cache, or by using the appropriate mime handler. Once the item is rendered, it is stored in the temporary cache under a key which combines the item_id, any extra HTML parameters, and a flag which specifies whether the item was merged with its template.
    This proc takes the same arguments as the individual mime handlers.
    Parameters:
    item_id * The id of the item to be rendered
    context * The context for the item (default public)
    Returns:
    The rendered HTML for the item, or an empty string on failure
    Options:
    revision_id default The live revision; The revision which is to be used when rendering the item
    no_merge Indicates that the item should NOT be merged with its template. This option is used to avoid infinite recursion.
    refresh Re-render the item even if it exists in the cache. Use with caution - circular dependencies may cause infinite recursion if this option is specified
    embed Signifies that the content should be statically embedded directly in the HTML. If this option is not specified, the item may be dynamically referenced, f.ex. using the {<include>} tag
    html Extra HTML parameters to be passed to the item handler, in format {name value name value ...}
    See Also:
    proc - publish::handle::image
    publish::handle::text
    publish::handle_binary_file

    publish::html_args
    Concatenate a list of name-value pairs as returned by set_to_pairs into a list of { name=value} pairs
    Parameters:
    argv * The list of name-value pairs
    Returns:
    An HTML string in format " name=value name=value ..."
    See Also:
    proc - publish::set_to_pairs

    publish::merge_with_template
    Merge the item with its template and return the resulting HTML. This proc is simlar to content::init
    Parameters:
    item_id * The item id
    Returns:
    The rendered HTML, or the empty string on failure
    Options:
    revision_id default The live revision; The revision which is to be used when rendering the item
    html Extra HTML parameters to be passed to the ADP parser, in format {name value name value ...}
    See Also:
    proc - publish::handle_item

    publish::pop_id
    Pop the item_id and the revision_id off the top of the stack. Clear the temporary item cache if the stack becomes empty.
    Returns:
    The popped item id, or the empty string if the string is already empty
    See Also:
    proc - publish::get_main_item_id
    publish::get_main_revision_id
    publish::push_id

    publish::process_tag
    Process a child or relation tag. This is a helper proc for the tags, which acts as a wrapper for render_subitem.
    Parameters:
    relation_type * Either child or relation
    params * The ns_set id for extra HTML parameters
    See Also:
    proc - publish::render_subitem

    publish::push_id
    Push an item id on top of stack. This proc is used to store state between child, relation and content tags.
    Parameters:
    item_id * The id to be put on stack
    revision_id default { }; The id of the revision to use. If missing, live revision will most likely be used
    See Also:
    proc - publish::get_main_item_id
    publish::get_main_revision_id
    publish::pop_id

    publish::render_subitem
    Render a child/related item and return the resulting HTML, stripping off the headers.
    Parameters:
    main_item_id * The id of the parent item
    relation_type * Either child or relation. Determines which tables are searched for subitems.
    relation_tag * The relation tag to look for
    index * The relative index of the subitem. The subitem with lowest order_n has index 1, the second lowest order_n has index 2, and so on.
    is_embed * If { t} , the child item may be embedded directly in the HTML. Otherwise, it may be dynamically included. The proc does not process this parameter directly, but passes it to handle_item
    extra_args * Any additional HTML arguments to be used when rendering the item, in form {name value name value ...}
    is_merge default t; If { t} , merge_with_template may be used to render the subitem. Otherwise, merge_with_template should not be used, in order to prevent infinite recursion.
    context default public;
    Returns:
    The rendered HTML for the child item
    See Also:
    proc - publish::handle_item
    publish::merge_with_template

    publish::set_to_pairs
    Convert an ns_set into a list of name-value pairs, in form {name value name value ...}
    Parameters:
    params * The ns_set id
    exclusion_list * {} A list of keys to be ignored
    Returns:
    A list of name-value pairs representing the data in the ns_set

    publish::track_publish_status
    Scheduled proc which keeps the publish status updated
    See Also:
    proc - publish::schedule_status_sweep

    publish::write_multiple_blobs
    Write the content of some revision to multiple publishing roots.
    Parameters:
    db * A valid database handle
    url * Relative URL of the file to write
    revision_id * Write the blob for this revision
    See Also:
    proc - publish::get_publish_roots
    publish::write_multiple_files

    publish::write_multiple_files
    Write a relative URL to the multiple publishing roots.
    Parameters:
    url * Relative URL of the file to write
    text * A string of text to be written to the URL
    See Also:
    proc - publish::get_publish_roots
    publish::write_multiple_blobs
    template::util::write_file

    Implements the child tag which renders a child item. See the Developer Guide for more information.
    The child tag format is
    {<child} tag=tag index=n embed {args>}
    Parameters:
    params * The ns_set id for extra HTML parameters

    Implements the content tag which renders the content of the current item. See the Developer Guide for more information.
    The content tag format is simply {<content>.} The embed and no_merge parameters are implicit to the tag.
    Parameters:
    params * The ns_set id for extra HTML parameters

    Implements the relation tag which renders a related item. See the Developer Guide for more information.
    The relation tag format is
    {<relation} tag=tag index=n embed {args>}
    Parameters:
    params * The ns_set id for extra HTML parameters

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/namespaces.html0000644000175000017500000000276407422402452025424 0ustar frankiefrankie

    ATS and CMS Tcl Procedure Specifications

    Namespaces
    doc
    doc::util
    form
    Commands for managing dynamic templated forms.
    request
    The request commands provide a mechanism for managing the query parameters to a page. The request is simply a special instance of a form object, and is useful for the frequent cases when data must be passed from page to page to determine display or page flow, rather than perform a transaction based on user input via a form.

    See: form element

    util
    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/content_add.html0000644000175000017500000000270207253523117025563 0ustar frankiefrankie

    Namespace content_add

    Procedures regarding content methods

    Method Summary

    Listing of public methods:
    content_add::content_method_html

    Method Detail

    * indicates required

    Public Methods:
    content_add::content_method_html
      by Michael Pih
    Generates HTML stub for revision content method choices for a content item
    Parameters:
    db * A database handle
    content_type * The content type of the item
    item_id * The item id

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/form.html0000644000175000017500000002717407422402452024252 0ustar frankiefrankie

    Namespace form

    Commands for managing dynamic templated forms.

    Method Summary

    Listing of public methods:











    Method Detail

    * indicates required

    Public Methods:
    Convenience procedure to set individual values of a form (useful for simple update forms). Typical usage is to query a onerow data source from database and pass the resulting array reference to set_values for setting default values in an update form.
    Parameters:
    id * The form identifier
    array_ref * The name of a local array variable whose keys correspond to element identifiers in the form

    Determine whether a form exists by checking for its data structures.
    Parameters:
    id * The ID of an ATS form object.
    Returns:
    1 if a form with the specified ID exists. 0 if it does not.

    Generates hidden input tags for all values in a form submission. Typically used to create a confirmation page following an initial submission.
    Returns:
    A string containing hidden input tags for inclusion in a form.

    Initialize the data structures for a form.
    Parameters:
    id * A keyword identifier for the form, such as { add_user} or { edit_item} . The ID must be unique in the context of a single page.
    Options:
    method The standard METHOD attribute to specify in the HTML FORM tag at the beginning of the rendered form. Defaults to POST.
    html A list of additional name-value attribute pairs to include in the HTML FORM tag at the beginning of the rendered form. Common attributes include JavaScript event handlers and multipart form encoding. For example, { -html { enctype multipart/form-data onSubmit validate() } }
    elements A block of element specifications.

    Return a list which represents the result of getting combined values from multiple form elements
    Parameters:
    id * The form identifier
    args * A list of element identifiers. Each identifier may be a regexp. For example, form get_combined_values { foo.*} will combine the values of all elements starting with { foo}
    return * The combined list of values

    Return the number of elements in a form
    Parameters:
    id * The form identifier

    Return true if a submission in progress. The submission may or may not be valid.
    Parameters:
    id * The form identifier
    Returns:
    1 if true or 0 if false

    Return true if preparing a form for an initial request (as opposed to repreparing a form that is returned to the user due to validation problems). This command is used to conditionally set default values for form elements.
    Parameters:
    id * The form identifier
    Returns:
    1 if true or 0 if false

    Return true if submission in progress and submission was valid. Typically used to conditionally execute DML and redirect to the next page, as opposed to returning the form back to the user to report validation errors.
    Parameters:
    id * The form identifier
    Returns:
    1 if true or 0 if false

    Set local variables for form variables (assume they are all single values). Typically used when processing the form submission to prepare for DML or other type of transaction.
    Parameters:
    id * The form identifier
    args * A list of element identifiers. If the list is empty, retreive all form elements

    Set the name of the current section of the form. A form may be divided into any number of sections for layout purposes. Elements are tagged with the current section name as they are added to the form. A form style template may insert a divider in the form whenever the section name changes.
    Parameters:
    id * The form identifier.
    section * The name of the current section.

    Private Methods:
    Auto-generate the template for a form
    Parameters:
    id * The form identifier
    style * The style template to use when generating the form. Form style templates must be placed in the forms subdirectory of the ATS resources directory.
    Returns:
    A string containing a template for the body of the form.

    Helper procedure used to access the basic data structures of a form object. Called by several of the form commands.

    Iterates over all declared elements, checking for hidden widgets and rendering those that have not been rendered yet. Called after rendering a custom form template as a debugging aid.
    Parameters:
    id * The form identifier

    Render the HTML FORM tag along with a hidden element that identifies the form object.
    Parameters:
    id * The form identifier
    tag_attributes * A name-value list of special attributes to add to the FORM tag, such as JavaScript event handlers.
    Returns:
    A string containing the rendered tags.

    Render the finished HTML output for a dynamic form.
    Parameters:
    id * The form identifier
    style * The style template to use when generating the form. Form style templates must be placed in the forms subdirectory of the ATS resources directory.
    Returns:
    A string containing the HTML for the body of the form.

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/request.html0000644000175000017500000001275207422402452024773 0ustar frankiefrankie

    Namespace request

    The request commands provide a mechanism for managing the query parameters to a page. The request is simply a special instance of a form object, and is useful for the frequent cases when data must be passed from page to page to determine display or page flow, rather than perform a transaction based on user input via a form.

    Also see:

    form
    element

    Method Summary

    Listing of public methods:





    Method Detail

    * indicates required

    Public Methods:
    Checks for any param errors. If errors are found, sets the display template to the specified URL (a system-wide request error page by default).
    Parameters:
    url * The URL of the template to use to display error messages. The special value { self} may be used to indicate that the template for the requested page itself will handle reporting error conditions.
    Returns:
    1 if no error conditions exist, 0 otherwise.

    Create the request data structure. Typically called at the beginning of the code for any page that accepts query parameters.
    Options:
    params A block of parameter declarations, separated by newlines. Equivalent to calling set_param for each parameter, but requiring slightly less typing.

    Declares a query parameter as part of the page request. Validates the values associated with the parameter, in the same fashion as for form elements.
    Parameters:
    name * The name of the parameter to declare.
    Options:
    name The name of parameter in the query (may be different from the reference name).
    multiple A flag indicating that multiple values may be specified for this parameter.
    datatype The name of a datatype for the element values. Valid datatypes must have a validation procedure defined in the template::data::validate namespace.
    optional A flag indicating that no value is required for this element. If a default value is specified, the default is used instead.
    validate A list of custom validation blocks in the form { name { expression } { message } \ name { expression } { message } ...} where name is a unique identifier for the validation step, expression is a block to Tcl code that evaluates to 1 or 0, and message is to be displayed to the user when the validation step fails.
    See Also:
    element::create -

    Manually report request error(s) by setting error messages and then calling is_valid to handle display. Useful for conditions not tied to a single query parameter. The arguments to the procedure may be any number of name-message combinations.
    Parameters:
    name * A unique identifier for the error condition, which may be used for layout purposes.
    msg * The message text associated with the condition.

    Retrieves the value(s) of the specified parameter.
    Parameters:
    name * The name of the parameter.
    Returns:
    The value of the specified parameter.

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/doc.html0000644000175000017500000000762307422402452024051 0ustar frankiefrankie

    Namespace doc

    Method Summary

    Listing of public methods:
    The namespace doc currently contains no public methods.

    Method Detail

    * indicates required

    Private Methods:

      by simon
    called by parse_file, this procedure is given the body of text between two namespace markers in a tcl library file and parses out procedure source and comments
    Parameters:
    text_lines * namespace text body

    Parse API documentation from a Tcl page API documentation is parsed as follows: Document is scanned until a @namespace directive is encountered. The remainder of the file is scanned for @private or @public directives. When one of these directives is encountered, the file is scanned up to a proc declaration and the text in between is parsed as documentation for a single procedure. The text between the initial @private or @public directive and the next directive is considered a general comment on the procedure Valid directives in a procedure doc include: - @author - @param (for hard parameters) - @see (should have the form namespace::procedure. A reference to an entire namespace should be namespace::. By convention the API for each namespace should be in a file of the same name, so that a link can be generated automatically). - @option (for switches such as -foo) - @return

    called by parse_comment_text
    Parameters:
    comment_text * this should include the source text

    called by parse_namespace
    Parameters:
    comment_text * body of comment text to be parsed through
    source_text * source text of the procedure

    takes the absolute path of the tcl library directory and parses through it
    Returns:
    a long lists of lists of lists, each list element contains a three-element list of the format { {info} {public procedures listing } {private procedures listing} }
    See Also:
    namespace - util
    proc - doc::parse_file
    template::util::comment_text_normalize

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/namespace-list.html0000644000175000017500000000150307422402452026200 0ustar frankiefrankie All Namespaces
      doc
      doc::util
      form
      request
      util
    Regenerate these pages.

    If you have not regenerated these pages before, you may have to reset permissions on all files to be written as well as your /doc/acs-templating/TclDocs directory. openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/content.html0000644000175000017500000007075507253523117024770 0ustar frankiefrankie

    Namespace content

    Procedures for generating and processing content content creation and editing forms..

    Method Summary

    Listing of public methods:
    content::add_attribute_element
    content::add_attribute_elements
    content::add_basic_revision
    content::add_child_relation_element
    content::add_content
    content::add_content_element
    content::add_revision
    content::add_revision_form
    content::copy_content
    content::get_attribute_enum_values
    content::get_latest_revision
    content::get_object_id
    content::new_item
    content::new_item_form
    content::validate_name

    Method Detail

    * indicates required

    Public Methods:
    content::add_attribute_element
    Add a form element (possibly a compound widget) to an ATS form object. for entering or editing an attribute value.
    Parameters:
    form_name * The name of the ATS form object to which the element should be added.
    content_type * The content type keyword to which this attribute belongs.
    attribute * The name of the attribute, as represented in the attribute_name column of the acs_attributes table.
    attribute_data * Optional nested list of parameter data for the the attribute (generated by get_attribute_params).

    content::add_attribute_elements
    Add form elements to an ATS form object for all attributes of a content type.
    Parameters:
    form_name * The name of the ATS form object to which objects should be added.
    content_type * The content type keyword for which attribute widgets should be added.
    revision_id * The revision from which default values should be queried
    Returns:
    The list of attributes that were added.

    content::add_basic_revision
    Create a basic new revision using the content_revision PL/SQL API.
    Parameters:
    item_id *
    revision_id *
    title *
    Options:
    description
    mime_type
    text
    tmpfile

    content::add_child_relation_element
    Add a select box listing all valid child relation tags. The form must contain a parent_id element and a content_type element. If the elements do not exist, or if there are no valid relation tags, this proc does nothing.
    Parameters:
    form_name * The name of the form
    Options:
    section none If present, creates a new form section for the element.
    label {Child relation tag} The label for the element

    content::add_content
    Update the BLOB column of a revision with content submitted in a form
    Parameters:
    revision_id * The object ID of the revision to be updated.

    content::add_content_element
    Adds a content input element to an ATS form object.
    Parameters:
    form_name * The name of the form to which the object should be added.
    content_method * One of no_content, text_entry or file_upload

    content::add_revision
    Create a new revision for an existing item based on a valid form submission. Queries for attribute names and inserts a row into the attribute input view for the appropriate content type. Inserts the contents of a file into the content column of the cr_revisions table for the revision as well.
    Parameters:
    form_name * Name of the form from which to obtain attribute values. The form should include an item_id and revision_id.
    tmpfile * Name of the temporary file containing the content to upload.

    content::add_revision_form
    Adds elements to an ATS form object for adding a revision to an existing item. If the item already exists, element values default a previous revision (the latest one by default). If the form does not already exist, creates the form object and sets its enctype to multipart/form-data to allow for text entries greater than 4000 characters.
    Options:
    form_name The name of the ATS form object. Defaults to { new_item} .
    content_type The content_type of the item. Defaults to { content_revision} .
    content_method The method to use for uploading the content body. If the content type is text, defaults to text entry, otherwise defaults to file upload.
    item_id The item ID of the revision. Defaults to null (item_id must be set by the calling code).
    revision_id The revision ID from which to draw default values. Defaults to the latest revision
    attributes A list of attribute names for which to create form elements.
    action The URL to which the form should redirect following a successful form submission.

    content::copy_content
    Update the BLOB column of one revision with the content of another revision
    Parameters:
    revision_id_src * The object ID of the revision with the content to be copied.
    revision_id_dest * The object ID of the revision to be updated. copied.

    content::get_attribute_enum_values
    Returns a list of { pretty_name enum_value } for an attribute of datatype enumeration.
    Parameters:
    attribute_id * The primary key of the attribute as in the attribute_id column of the acs_attributes table.

    content::get_latest_revision
    Get the ID of the latest revision for the specified content item.
    Parameters:
    item_id * The ID of the content item.

    content::get_object_id
    Grab an object ID for creating a new ACS object.

    content::new_item
    Create a new item, including the initial revision, based on a valid form submission.
    Parameters:
    form_name * Name of the form from which to obtain item attributes, as well as attributes of the initial revision. The form should include an item_id, name and revision_id.
    tmpfile * Name of the temporary file containing the content to upload for the initial revision.
    See Also:
    add_revision -

    content::new_item_form
    Adds elements to an ATS form object for creating an item and its initial revision. If the form does not already exist, creates the form object and sets its enctype to multipart/form-data to allow for text entries greater than 4000 characters.
    Options:
    form_name The name of the ATS form object. Defaults to { new_item} .
    content_type The content_type of the item. Defaults to { content_revision} .
    content_method The method to use for uploading the content body. Valid values are { no_content} , { text_entry} , and { file_upload} . If the content type allows text, defaults to text entry, otherwise defaults to file upload.
    parent_id The item ID of the parent. Defaults to null (Parent is the root folder).
    name The default name of the item. Default is an empty string (User must supply name).
    attributes A list of attribute names for which to create form elements.
    action The URL to which the form should redirect following a successful form submission.

    content::validate_name
    Make sure that name is unique for the folder
    Parameters:
    form_name * The name of the form (containing name and parent_id)
    Returns:
    0 if there are items with the same name, 1 otherwise

    Private Methods:
    content::add_revision_dml
    Perform the DML to insert a revision into the appropriate input view.
    Parameters:
    statement * The DML for the insert statement, specifying a bind variable for each column value.
    bind_vars * An ns_set containing the values for all bind variables.
    tmpfile * The server-side name of the file containing the body of the revision to upload into the content BLOB column of cr_revisions.
    filename * The client-side name of the file containing the body of the revision to upload into the content BLOB column of cr_revisions
    See Also:
    add_revision -

    content::attribute_insert_statement
    Prepare the insert statement into the attribute input view for a new revision (see the content repository documentation for details about the view).
    Parameters:
    content_type * The content type of the item for which a new revision is being prepared.
    table_name * The storage table of the content type.
    bind_vars * The name of an ns_set in which to store the attribute values for the revision. (Typically duplicates the contents of {[ns_getform].}
    form_name * The name of the ATS form object used to process the submission.

    content::get_attribute_params
    Query for parameters associated with a particular attribute
    Parameters:
    content_type * The content type keyword to which this attribute belongs.
    attribute_name * The name of the attribute, as represented in the attribute_name column of the acs_attributes table.

    content::get_attributes
    Returns columns from the acs_attributes table for all attributes associated with a content type.
    Parameters:
    content_type * The name of the content type (ACS Object Type) for which to obtain the list of attributes.
    args * Names of columns to query. If no columns are specified, returns a simple list of attribute names.

    content::get_default_content_method
    Gets the content input method most appropriate for an content type, based on the MIME types that are registered for that content type.
    Parameters:
    content_type * The content type for which an input method is needed.

    content::get_sql_value
    Return the sql statement for a column value in an insert or update statement, using a bind variable for the actual value and wrapping it in a conversion function where appropriate.
    Parameters:
    name * The name of the column and bind variable (they should be the same).
    datatype * The datatype of the column.

    content::get_type_attribute_params
    Query for attribute form metadata
    Parameters:
    args * Any number of object types
    Returns:
    A list of attribute parameters nested by object_type, attribute_name and the is_html flag. For attributes with no parameters, there is a single entry with is_html as null.

    content::get_type_info
    Return specified columns from the acs_object_types table.
    Parameters:
    object_type * Object type key for which info is required.
    ref * If no further arguments, name of the column value to return. If further arguments are specified, name of the array in which to store info in the calling
    args * Column names to query.

    content::get_widget_param_value
    Utility procedure to return the value of a widget parameter
    Parameters:
    array_ref * The name of an array in the calling frame containing parameter data selected from the form metadata.
    content_type * The current content {type;} defaults to content_revision

    content::prepare_content_file
    Looks for an element named { content} in a form and prepares a temporarily file in UTF-8 for uploading to the content repository. Checks for a query variable named { content.tmpfile} to distinguish between file uploads and text entry. If the type of the file is text, then ensures that is in UTF-8. Does nothing if the uploaded file is in binary format.
    Parameters:
    form_name * The name of the form object in which content was submitted.
    Returns:
    The path of the temporary file containing the content, or an empty string if the form does not include a content element or the value of the element is null.

    content::set_attribute_values
    Set the default values for attribute elements in ATS form object based on a previous revision
    Parameters:
    form_name * The name of the ATS form object containing the attribute elements.
    content_type * The type of item being revised in the form.
    revision_id * The revision ID from where to get the default values
    attributes * The list of attributes whose values should be set.

    content::set_content_value
    Set the default value for the content text area in an ATS form object based on a previous revision
    Parameters:
    form_name * The name of the ATS form object containing the content element.
    revision_id * The revision ID of the content to revise

    content::string_to_file
    Write a string in UTF-8 encoding to of temp file so it can be uploaded into a BLOB (which is blind to character encodings). Returns the name of the temp file.
    Parameters:
    s * The string to write to the file.

    content::update_content_from_file
    Update the BLOB column of a revision with the contents of a file
    Parameters:
    revision_id * The object ID of the revision to update.
    tmpfile * The name of a temporary file containing the content. The file is deleted following the update.

    content::upload_content
    Inserts content into the database from an uploaded file. Does automatic mime_type updating Parses text/html content and removes tags
    Parameters:
    db * A db handle
    revision_id * The revision to which the content belongs
    tmpfile * The server-side name of the file containing the body of the revision to upload into the content BLOB column of cr_revisions.
    filename * The client-side name of the file containing the body of the revision to upload into the content BLOB column of cr_revisions

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/util.html0000644000175000017500000001106507422402452024254 0ustar frankiefrankie

    Namespace util

    Method Summary

    Listing of public methods:
    The namespace util currently contains no public methods.

    Method Detail

    * indicates required

    Private Methods:
    a proc used for debugging, just prints out a value to the error log

    capitalizes the first letter of a string
    Returns:
    returns formatted string

    escapes quotes and removes comment tags from a body of commented text
    Parameters:
    text *
    Returns:
    text

    just takes a body of text and puts a space behind every double {quote;} this is done so that the text body can be treated as a list without causing problems resulting from list elements being separated by characters other than a space
    Parameters:
    text * req/none the body of text to be worked on
    Returns:
    same text but with a space behind each quote; double quotes that are already trailed by a space are unaffected

    takes a .adp template name and the name of the file to be written and creates the {file;} also puts out a notice before
    Parameters:
    template * the name of the template to be used in making the file
    file_name * the name of the file to be created

    takes an alphabetized list and an entry
    Parameters:
    list * {let's see how this parses out} the alphabetized list
    entry * req the value to be inserted
    Returns:
    either the proper list index for an alphabetized insertion or -1 if the entry is already in the list

    used to compare two different elements in a list of parsed data for public or private procs

    uses ns_library to find the server root, may not always be accurate because it essentially asks for the tcl library path and strips off the last /tcl directory

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/TclDocs/cm_widget.html0000644000175000017500000000226207253523117025244 0ustar frankiefrankie

    Namespace cm_widget

    Procedures associated with custom metadata widgets for basic CR content types

    Method Summary

    Listing of public methods:
    The namespace cm_widget currently contains no public methods.

    Method Detail

    * indicates required

    Private Methods:
    cm_widget::validate_description
      by Michael Pih
    Make sure that description <= 4000 bytes
    Parameters:
    value * The submitted value of the description form element

    * indicates required

    openacs-5.7.0/packages/acs-templating/www/doc/designer-guide.html0000644000175000017500000001557007253523117024650 0ustar frankiefrankie Template Designer Guide

    Designer Guide

    Templating System : Designer Guide

    Overview

    Templates are the primary means for separating the work of developers and designers. A template is written by a designer and consists largely of static HTML (or other markup). The template author uses a small set of special markup tags to reference dynamic data prepared by the developer.The tags allow authors to accomplish four basic tasks that are not possible with standard HTML:

    • Embed a dynamic variable in a template (var).
    • Repeat a template section for each object in a dynamic list of objects (multiple, grid).
    • Output different template sections depending on the value of one or more dynamic variables (if).
    • Provide a mechanism for building complete pages from multiple component templates (include).

    A reasonably skilled template author should be able to implement a template without any assistance from the developer, other than assuring that the proper dynamic data is accessible.

    Concepts

    This section introduces the basic concepts underlying the use of template tags in ACS 4.0.

    Variable Substitution

    Much like the mail merge feature of a word processor, template authors must use special tags to position each piece of dynamic data within the layout. Each template is associated with a data dictionary that lists all available data sources.

    See Variable Substitution.

    Use of Components

    To speed development and ensure consistency of design, template authors are encouraged to assemble pages from distinct component templates that may be recycled in different contexts. One typical practice is to build a "master" template for an entire section of a site, with a common header, footer and sidebar layout. For each page request, the "content" template is incorporated dynamically into a specified area of the master template, usually a table cell.

    (graphic)

    Another common practice is to build small reusable templates that may be included in other templates as logical components. This may be useful for common "widgets" such as search boxes or lists of related links, as well as for building configurable portal pages where users may assemble different types of content to their liking.

    (graphic)

    See include and master. See also Building reusable layout components and Using master templates.

    Property Declarations

    Template authors need a simple mechanism for declaring properties within the templates. The most common use of such properties is for configuring elements of an enclosing master template, such as the title, navigation links, and whether to include a search box. The data dictionary specifies available properties as well as the set of valid values when appropriate.

    (graphic)

    See property.

    Conditional Insertion

    Designers often need to tailor the layout depending on the specific data being presented. For example, when presenting a list of library books that a user has checked out, the designer might want to highlight the overdue ones in red.

    See if..else.

    Iteration

    Dynamic pages often present lists of values or records, each of which typically represents the results of a database query. Template authors must have a way to iterate over each value or record in such a list and format it appropriately. In the simplest scenario, the exact HTML is repeated with each iteration. However, template authors often need to vary the design depending on the context. For example:

    1. First and last items may be formatted differently from items in between.

    2. Special breaks may be required when a particular value changes. For example, a query may return the name and office of all employees in a company, and the designer may wish to insert a subheading for each office.

    3. Colors or patterns may alternate between items. For example, the designer may want to have alternate between white and gray bands in a table.

    To accomodate these type of scenarios, the template parser sets some additional variables that the designer can reference to vary the layout from item to item.

    See multiple, group, grid.

    Notes

    • Template tags are processed by the server each time a page is requested. The end result of this processing is a standard HTML page that is delivered to the user. Users do not see template tags in the HTML source code of the delivered page.

    • With normal usage, the use of dynamic tags tends to increase the amount of whitespace in the final HTML as compared to the template. This usually does not affect how browsers display the page. However, if a page layout depends on the presence or absence of whitespace between HTML tags for proper display, then special care must be taken with dynamic tags to avoid adding whitespace.

      When placed on a line by themselves, tags that are containers for template sections (grid, if, and multiple) will cause newlines to be added to the page at the beginning and end of the section. This can be avoided by crowding the start and end tags like so:

      <td><if %x% eq 5><img src="five.gif"></if>
      <else><img src="notfive.gif"></else></td>
      

      Note that this should not be done unless necessary, since it reduces the legibility of the template to others who need to edit the template later.

    • Caution:   Do not write to the connection. Specifically, if you must use the <% %> tag, do not call ns_puts, because it will not work the same way as in AOLserver's ADP pages.


    Christian Brechbuehler
    Last modified: Mon Oct 2 14:12:08 EDT 2000 openacs-5.7.0/packages/acs-templating/www/doc/requirements.html0000644000175000017500000003306007253523117024472 0ustar frankiefrankie ACS Templating Requirements

    ACS Templating Requirements

    by Karl Goldstein, Christian Brechbühler, Peter Su, and Yonatan Feldman

    I. Introduction

    The following is a requirements document for the ACS Templating System version 0.5. It has also been called Karl's Templates, the Dynamic Publishing System (DPS), and Stencil. The official package name for the system is now acs-templating.

    II. Vision Statement

    On websites of sufficient size, a consistent look and feel (the UI, or user interface) for users is important, while for site publishers and administrators, de-coupling the UI from programming allows for easier maintenance and more efficient workflow. Thus the ACS 4 Templating system provides mechanisms that allow programmers and graphic designers to work independently of each other. Templates specify the layout of the page separately from the dynamic content of the page. Graphic designers work primarily on the layout, that is the template, while programmers work primarily on a script or program that generates the dynamic content that fills the blanks in the template. In addition, the templating system provides a way to use a single layout specification for the majority - if not all - of a website's pages, so the overall layout of a site can be more easily administered.

    III. System Overview

    The templating system provides:
    • A set of custom markup tags (using ADP, AOLserver Dynamic Pages) that are used to specify page layout, and to declare where dynamically generated content belongs in the layout.

    • An API for specifying the content part of the page. This API is used by programmers to specify the script that generates the content in a page.

    • A mechanism for combining the data (from a data source) with the layout (from a layout template) into a single dynamically generated HTML page.

    • A mechanism for specifying a single master template to be used for multiple pages.

    IV. Use-cases and User-scenarios

    The template system is designed to be used by two classes of users: programmers and designers. In bulding a web site, programmers are generally responsible for defining and implementing the application logic of the site, while designers are more responsible for the presentation. Generally speaking, the application logic generates data for the presentation to display to the user. The template system must provide mechanisms that supports both of these tasks and allows the designer and programmer to work seperately, but for their work to be combined at runtime into something that the user sees as a single page.

    Thus, pages are naturally split into two parts. The logic part executes application logic and generates data, and the presentation part that specifies the layout of the page and so on.

    What is needed is:

    1. A notation and API for the programmer specify the application logic and to generate the data to be displayed. In ACS, we call the data that we wish to display a data source or page property. Application logic is driven by the inputs the page gathers from the user request (e.g. the HTTP request), and the computation that the page must perform on this input. This computation will generally create and populate the data sources and page properties. Data sources tend to be connected to database queries, while page properties can be defined by any arbitrary computation.
    2. A notation and API for the designer to specify how the data sources and page properties will be presented to the user. This notation will generally take the form of some kind extended HTML.
    3. A mechanism for communicating the data sources and page properties from the logic part of the page

    Jane Programmer writes a page contract and a draft template, that uses the promised page properties. Joe Designer takes that template and makes it look nice, using his design skills and HTML literacy. Meanwhile Jane Programmer writes code to generate the page properties, typically by querying the database. When both are done, the page is ready for Jim User, who requests it using his web browser.

    Alternate scenario: Judy Designer is familiar with the template system. She starts directly from a defined page contract, so Jane Programmer doesn't need to write the draft template.

    V. Related Links

    • Design document

    VI.A Functional Requirements

    VI.B Non-functional Requirements

    VII. Revision History

    Document Revision # Action Taken, Notes When? By Whom?
    0.1 Creation 8/23/2000 Yonatan Feldman
    0.2 Merge with previous docs 8/25/2000 Christian Brechbühler
    0.3 Edited, reviewed, pending freeze 8/28/2000 Kai Wu

    yon@arsdigita.com
    Last modified: $Id: requirements.html,v 1.1.1.1 2001/03/13 22:59:27 ben Exp $ openacs-5.7.0/packages/acs-templating/www/doc/migration.html0000644000175000017500000003701407572172113023743 0ustar frankiefrankie Templating an Existing Tcl Page

    Templating an Existing Tcl Page

    Templating System : Migration

    In a Nutshell

    When templatizing a legacy tcl page, your task is to separate code and graphical presentation. The latter goes into an ADP file; it contains essentially HTML, augmented by a few special tags and the @variable@ construct. The code goes into a TCL script. In other words, a templated page consists of two files, a TCL part that puts its results in data sources, and an ADP page (the template), into which these data sources will be interpolated to yield a complete HTML page.

    General

    As usual, the TCL page should start with a call to ad_page_contract. In its -properties block you promise the data sources that your script will provide; they were earlier called page properties, hence the name of the option. Then your script performs all the computations and queries needed to define these data sources. There are special mechanisms for handling multirow data sources; see below.

    At the end of the TCL script, you should call ad_return_template. The template runs after the tcl script, and can use these data sources.

    Make sure that the fancy adp parser is enabled in your AOL ini file.

          [ns/server/myserver/adp]
          DefaultParser=fancy

    A few more hints

    • Do not write to the connection directly. Avoid ns_puts, ns_write etc., which don't wait till the headers are written or the page is completed; they may act differently than you expect.
    • If you can, put code in the tcl file, not between <% %> in the adp page.
    • Put HTML in the adp page, not int the tcl program. Put reusable HTML fragments in a separate adp file (think of it as a widget) that will be <include>d from several pages. Prefer this to writing a tcl proc that returns HTML.
    • Remember to remove backslashes where you had to escape special characters, as in
      Nuts  \$2.70 \[<a href=\"shoppe\">buy</a>\]
      	  

    Forms

    There is nothing special about building forms; just use the <form> tag as always. All HTML tags can be used in the ADP file (template).

    A simple page

    First I take a page from the news package as an example. For simplicity, I pick item-view, which does not use a <form>. I reformatted it a bit to make three panes fit next to each other and to line up corresponding code.

    old tcl code new
    packages/news/www/item-view.tcl packages/news/www/item-view.adp
    # /packages/news/admin/index.tcl
    ad_page_contract {
    
        View a news item.
    
        @author Jon Salz (jsalz@arsdigita.com)
        @creation-date 11 Aug 2000
        @cvs-id $Id$
    
    } {
        news_item_id:integer,notnull
    }
    
    
    
    
    
    
    
    
    db_1row news_item_select {
        select *
        from news_items
        where news_item_id = :news_item_id
    }
    
    set body "
    [ad_header $title]
    <h2>$title</h2>
    [ad_context_bar [list "" "News"] $title]
    
    <hr>
    
    <p>Released $release_date:
    
    <blockquote>
    $body
    </blockquote>
    
    [ad_footer]
    "
    
    doc_return 200 text/html $body
    return
    	  
    
    ad_page_contract {
    
        View a news item.
    
        @author Jon Salz (jsalz@arsdigita.com)
        @creation-date 11 Aug 2000
        @cvs-id $Id$
    
    } {
        news_item_id:integer,notnull
    } -properties {
      body:onevalue
      release_date:onevalue
      title:onevalue
      header:onevalue
      context_bar:onevalue
      footer:onevalue
    }
    
    db_1row news_item_select {
        select *
        from news_items
        where news_item_id = :news_item_id
    }
    
    
    set header [ad_header $title]
    
    set context_bar [ad_context_bar \
        [list "" "News"] $title]
    
    
    
    
    
    
    
    
    set footer [ad_footer]
    
    
    ad_return_template
    	  
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    @header@
    <h2>@title@</h2>
    @context-bar@
    
    <hr>
    
    <p>Released @release_date@:
    
    <blockquote>
    @body@
    </blockquote>
    
    @footer@
    	  

    Multi-Row Data Sources

    Technically, the result of a query that may return multiple rows is stored in several arrays. This datasource is filled by a call to db_multirow, and the repeating part of the HTML output is produced by the <multiple> tag. The following example shows the part of the index page of the News module that uses the mechanism, not a whole page.
    old tcl code new
    packages/news/www/index.tcl packages/news/www/index.adp
    ad_page_contract {
    
        Displays a list of 
        available news items.
    
        @param archive_p show archived
                          news items?
        @author Jon Salz (jsalz@mit.edu)
        @creation-date 11 Aug 2000
        @cvs-id $Id$
    } {
    }
    	  
    ad_page_contract {
    
        Displays a list of available
        news items.
    
        @param archive_p show archived
                          news items?
        @author Jon Salz (jsalz@mit.edu)
        @creation-date 11 Aug 2000
        @cvs-id $Id$
    } {
    } -properties {
      header:onevalue
      context_bar:onevalue
      subsite_id:onevalue
      subsite:multirow
      item:multirow
      footer:onevalue
    }
    	  
     
    ... ... ...
    append body "
    <ul>
    "
    
    db_foreach news_items_select {
        select news_item_id, title
        from news_items_obj
        where context_id = :subsite_id
        and sysdate >= release_date
        and (   expiration_date is null
             or expiration_date > sysdate)
    } {
        append body "<li><a href=
    	\"item-view?news_item_id="\
    	"$news_item_id\"
    	>$title</a>\n"
    
    
    } if_no_rows {
        append body "<li>There are 
            currently no news items
            available.\n"
    }
    
    append body "
    <p><li>You can use the <a href=
        \"admin/\">administration
        interface</a> to post a new
        item (there's currently no
        security in place).
    
    </ul>
    "
    
    
    
    
    db_multirow item news_items_select {
        select news_item_id, title
        from news_items_obj
        where context_id = :subsite_id
        and sysdate >= release_date
        and (   expiration_date is null
             or expiration_date > sysdate)
    }
    	  
    
    <ul>
    
    
    <multiple name=item>
    
    
    
    
    
    
    
      <li><a href=
          "item-view?news_item_id=<%
          %>@item.news_item_id@"
          >@item.title@</a>
    </multiple>
    
    <if @item:rowcount@ eq 0>
      <li>There are
      currently no news items
      available.
    </if>
    
    
    <p><li>You can use the <a href=
      "admin/">administration
      interface</a> to post a new
      item (there's currently no
      security in place).
    
    </ul>
    	  
    Notes:
    • I use the general <if> construct to handle the case when no lines are returned. (The <multiple> loop just executes zero times.)
    • For a list of the available tags, refer to the templating documentation.
    • Blue color marks additional syntax necessary to wrap lines short.
    • The proc db_multirow does have a code block and an optional if_no_rows block, just like db_foreach. They aren't used in the example, though.

    If you have a more complicated db_foreach, where logic is performed inside the body, then it might be helpful to build your own multirow variable. In the excert below, taken from /pvt/alerts.tcl and /pvt/alerts.adp, the foreach logic made it hard to use the db_multirow because it needed a combination of the output from sql and also the output of tcl procedures using that value.
    old tcl code new
    packages/acs-core-ui/www/pvt/alerts.tcl packages/acs-core-ui/www/pvt/alerts.adp
    ad_page_contract {
        @cvs-id $Id: migration.html,v 1.2 2002/11/30 17:24:27 jeffd Exp $
    } {
    }	  
    	  
    ad_page_contract {
        @cvs-id $Id: migration.html,v 1.2 2002/11/30 17:24:27 jeffd Exp $
    } {
    } -properties {
        header:onevalue
        decorate_top:onevalue
        ad_footer:onevalue
        discussion_forum_alert_p:onevalue
        bboard_keyword_p:onevalue
        bboard_rows:multirow
        classified_email_alert_p:onevalue
        classified_rows:multirow
        gc_system_name:onevalue
    }	  
    	  
     
    ... ... ...
    
    
    if { [db_table_exists "bboard_email_alerts"] } {
     
     set counter 0
    
    
    
    
    
    
    
    
     db_foreach alerts_list "
     select bea.valid_p, bea.frequency,
            bea.keywords, bt.topic, bea.rowid
     from bboard_email_alerts bea, bboard_topics bt
     where bea.user_id = :user_id
     and bea.topic_id = bt.topic_id
     order by bea.frequency" {
       incr counter
    
       if { $valid_p == "f" } {
         # alert has been disabled 
         set status "Disabled"
         set action "
         <a href=\"/bboard/alert-reenable\">
         Re-enable</a>"
       } else {
         # alert is enabled
         set status "
         <font color=red>Enabled</font>"
         set action "
         <a href=\"/bboard/alert-disable\">
         Disable</a>"
       }
    
       append existing_alert_rows "<tr>
       <td>$status</td>
       <td>$action</td>
       <td>$topic</td>
       <td>$frequency</td>"
    
       if { [bboard_pls_blade_installed_p] == 1 } {
         append existing_alert_rows "
         <td>\"$keywords\"</td>"
       }
       append existing_alert_rows "</tr>\n"
    
     }
    
     if  { $counter > 0 } {
       set wrote_something_p 1
       set keyword_header ""
       if { [bboard_pls_blade_installed_p] == 1 } {
         set keyword_header "<th>Keywords</th>"
       }
       append page_content "
       <h3>Your discussion forum alerts</h3>
    
       <blockquote>
       <table>
       <tr>
       <th>Status</th>
       <th>Action</th>
       <th>Topic</th>
       <th>Frequency</th>
       $keyword_header
       </tr>
    
       $existing_alert_rows
       </table>
       </blockquote>
       "
     }
    }
    	  
    set discussion_forum_alert_p 0
    
    if { [db_table_exists "bboard_email_alerts"] } {
      set discussion_forum_alert_p 1
    
      set rownum 0
    
      if { [bboard_pls_blade_installed_p] == 1 } {
        set bboard_keyword_p 1
      } else {
        set bboard_keyword_p 0
      }
    	
      db_foreach alerts_list "
      select bea.valid_p, bea.frequency,
             bea.keywords, bt.topic, bea.rowid
      from bboard_email_alerts bea, bboard_topics bt
      where bea.user_id = :user_id
      and bea.topic_id = bt.topic_id
      order by bea.frequency" {
      incr rownum
    
      if { $valid_p == "f" } {
        # alert has been disabled for some reason
        set bboard_rows:[set rownum](status) "disable"
        set bboard_rows:[set rownum](action_url) "
        /bboard/alert-reenable"
      } else {
        # alert is enabled
        set bboard_rows:[set rownum](status) "enable"
        set bboard_rows:[set rownum](action_url) "
        /bboard/alert-disable"
      }
    
      set bboard_rows:[set rownum](topic) $topic
      set bboard_rows:[set rownum](frequency) $frequency
      set bboard_rows:[set rownum](keywords) $keywords
    	
      } if_no_rows {
        set discussion_forum_alert_p 0
      }
      set bboard_rows:rowcount $rownum
      
    }
    
    	  
    	  
    
    
    
    
    
    
    
    
    
    
    
    
    
    <if @discussion_forum_alert_p@ eq 1>
    
    <h3>Your discussion forum alerts</h3>
    
    <blockquote>
       <table>
       <tr><th>Status</th>
           <th>Action</th>
           <th>Topic</th>
           <th>Frequency</th>
         <if @bboard_keyword_p@ eq 1>
           <th>Keyword</th>
         </if>
       </tr>
     <multiple name=bboard_rows>
    
       <tr>
          <if @bboard_rows.status@ eq "enabled">
           <td><font color=red>Enabled</font></td>
           <td><a href="@bboard_rows.action_url@">
           Disable</a></td>
          </if>
          <else>
           <td>Disabled</td>
           <td><a href="@bboard_rows.action_url@">
           Re-enable</a></td>
          </else>
           <td>@bboard_rows.topic@</td>
           <td>@bboard_rows.frequency@</td>
         <if @bboard_rows.bboard_keyword_p@ eq 1>
           <td>@keyword</td>
         </if>
       </tr>
     
     </multiple>
       </table>
    </blockquote> 
    
    </if>
    	  


    Christian Brechbühler, Hiro Iwashima
    Last modified: $Id: migration.html,v 1.2 2002/11/30 17:24:27 jeffd Exp $ openacs-5.7.0/packages/acs-templating/www/doc/appendices/0000755000175000017500000000000011724401447023171 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/appendices/memory.html0000644000175000017500000001036707253523117025377 0ustar frankiefrankie Templating System Appendix D: Parsing templates in memory

    Parsing Templates in Memory

    Templating System

    The templating system code is oriented towards parsing templates stored in the file system, in conjunction with a Tcl script that is also stored as a file. However, when the template is not actually stored in the file system, you will need to parse it as a string in memory. Two common situations in which this occurs are:

    • Templates are stored in the database.
    • Templates are generated dynamically, possibly based in turn on a "style" template. This is how ATS auto-generates forms.

    The Parsing Process

    Whether the template is ultimately stored in a file or not, the templating system follows the same basic process during the parsing process:

    1. Prepare data sources. Some Tcl code is evaluated to prepare data sources (scalars, lists, multirow data structures) for merging with the template. (For file-based templates the interpreted code is cached in a procedure after the first time).
    2. Compile the template.. The template markup is compiled into a chunk of Tcl code that builds the page into a single output string. (For file-based templates the resulting code is cached in a procedure after the first time).
    3. Evaluate the compiled template. The template code is evaluated in the same stack frame as the data source code, so that all variables declared as data sources are directly available to the template. The result of the evaluation step is a single string, which normally is written to the connection.

    How to Parse Templates in Memory

    The templating system provides a low-level API that allows you to perform the three steps described above in the context of your own code:

    # set up any number of data sources:
    
    set first_name George
    
    query cars multirow "
      select make, model from cars where first_name = :first_name"
    
    # get the template.  This may be a static string, be queried from the
    # database, generated dynamically, etc.
    
    set template "
    Hello @first_name@!
    
    <multiple name=cars>
      @cars.rownum@. @cars.make@ @cars.model@<br>
    </multiple>
    "
    
    # compile the template.  The templating system takes the
    # result of this step and wraps it in a proc so that it is 
    # bytecode-cached in the interpreter.  You may wish to implement
    # some sort of simple caching here as well.
    
    set code [template::adp_compile -string $template]
    
    # evaluate the template code.  Note that you pass a reference
    # to the variable containing the code, not the value itself.  The code
    # is evaluated in the calling stack frame (by uplevel) so that
    # the above data sources are directly accessible.
    
    set output [template::adp_eval code]
    
    # now use the output however you wish
          
    Also see the "string" demo.

    Generating Templates from Other Templates

    In some cases, the template itself may be based on yet another base template. For example, the templating system itself generates form templates based on a generic "style" template. The generic template primarily depends on a single data source, elements, which references the element list for a particular form object. A single multipleloop is used to lay out the specific formwidget and formgroup tags, along with labels and validation text, for the form. The output of this first step is then rendered into HTML and returned to the user.

    Note that the generic "style" template contains templating tags (formwidget, formgroup, if etc.) that must be "protected" during the first step. The templating system provides the noparse tag to do this.


    templating@arsdigita.com
    Last modified: $Id: memory.html,v 1.1.1.1 2001/03/13 22:59:27 ben Exp $ openacs-5.7.0/packages/acs-templating/www/doc/widgets/0000755000175000017500000000000011575225607022532 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/widgets/date.html0000644000175000017500000002341307253523117024333 0ustar frankiefrankie Templating System Widget Reference: Date

    The Date Widget

    Templating System : Widget Reference : Date

    Overview

    The date widget provides a versatile HTML control for entering dates in a variety of formats. The widget operates in conjunction with various template::util::date functions in order to validate and manipulate the user's input. Please see the demo pages for some examples of the widget's behavior.

    The Date Object

    The widget's value is a Date object, defined in template::util::date. The date object stores 7 fields: the year, month, day, hours, minutes, seconds, and the format in which these values should be displayed. The function template::util::date::create can be used to instantiate a blank date:

    proc template::util::date::create {
      {year {}} {month {}} {day {}} {hours {}} 
      {minutes {}} {seconds {}} {format "YYYY/MM/DD"}
    } {
      return [list $year $month $day $hours $minutes $seconds $format]
    }
    

    The two functions template::util::date::get_property and template::util::date::set_property are used to get or set the fields of a Date object. The get_property function accepts the desired field and the Date object, and returns the value of the field:

    proc template::util::date::get_property { what date } {
    ...
    }
    

    The set_property function accepts the field, the Date object and the new value, and returns the modified Date object:

    proc template::util::date::set_property { what date value } {
    ...
    }
    

    The fields which can be accessed or changed are summarized below:

    FieldGet ?Set ? MeaningSample Value
    yearYesYes The 4-digit year2000
    monthYesYes The month, January = 18
    dayYesYes The day of month21
    hoursYesYes The hour, in 24-hour format 23
    minutesYesYes The minute59
    secondsYesYes The second59
    formatYesYes The format (see below for a detailed explanation)YYYY/MM/DD
    long_month_nameYes  The symbolic month nameJanuary
    short_month_nameYes  The abbreviated month nameJan
    days_in_monthYes  The number of days in the month stored in the Date object; will return an empty string if the month or the year are undefiend. Takes into account the leap years. 29
    short_yearYesYes The 2-digit year. When mutating, 2000 is added to the year if it is less than 69; otherwise, 1900 is added to the year. 99
    short_hoursYesYes The hour, in 12-hour format. When mutating, the hour is always assumed to be in the "a.m." range; the ampm field may be used to change this. 3
    ampmYesYes The meridian indicator: either am or pm. Can be used in conjunction with the short_hour field in order to completely specify the hour. am
    not_nullYes  This field will be 1 if and only if at least one of the date fields (year, month, date, hours, minutes or seconds) is present in the Date object. Otherwise, this field will be 0. 1
    sql_dateYes  The SQL code fragment representing the date stored in the Date object. to_date('2000/08/12 11:15:00', 'YYYY/MM/DD HH24:MI:SS')
    clockYesYes The value of the date in the same format as the value returned by the clock seconds function. The clock function appears to be locale-dependent and therefore unreliable; however, manipulating the clock value with clock scan is currently the only way to perform arithmetic operations on dates, such as adding a day, comparing two dates, etc. (An integer representing the number of elapsed seconds)

    For example, the following code produces the tomorrow's date in SQL:

    
    # Create a blank date
    set today_date [template::util::date::create]
    
    # Get the tomorrow's date
    set clock_value [clock scan "1 day" -base [clock seconds]]
    set tomorrow_date [template::util::date::set_property \
      clock $today_date $clock_value]
    
    # Get the SQL value
    set tomorrow_sql [template::util::date::get_property \
      sql_date $tomorrow_date]
    
    

    The Date Element

    The widget is created with the usual template::element create statement, with the datatype and widget set to date. In addition, the element requires a -format switch, which specifies the format for the date, as follows:

    OptionFormatMeaning
    -format long YYYY/MM/DD HH24:MI:SS The full widget including the date and the time
    -format short YYYY/MM/DD The widget capable of entering the date only, without the time
    -format time HH24/MI/SS The widget capable of entering the time only, without the date
    -format american MM/DD/YY The widget representing the more familiar American date
    -format expiration DD/YY An expiration date, as it may appear on a credit card
    -format custom string Custom format See below

    Any other value for the format flag is interpreted as a custom format string. The custom format string should consist of format specifiers separated by any of /\-.: or spaces. The valid format specifiers are as follows:
    Format SpecifierFieldDefault Widget
    YYYYyearInput box, 4 characters
    YYshort_yearInput box, 2 characters
    MMmonthSelection list
    MONmonth Selection list of abbreviated month names
    MONTHmonth Selection list of full month names
    DDdaySelection list
    HH12short_hours Selection list from 1 to 12
    HH24hours Selection list from 0 to 23
    MIminutes Selection list from 0 to 60, skipping every 5 minutes
    SSseconds Selection list from 0 to 60, skipping every 5 seconds
    AMampm Selection list of "A.M." and "P.M."

    Any format specifier may be followed by a lowercase t, in order to force the widget to use an input box (instead of a selection list) for entering the specified date fragment.

    The -format switch is required, but the date widget also supports the following optional switches:

    SwitchMeaningExample
    -field_interval interval Specifies a custom interval for the given field, as a list of three values: the starting value, the ending value, and the step -minute_interval {0 59 5}
    -help Causes the date widget to display a description of each date fragment widget showing the purpose of the widget, such as "Year" or "24-Hour" -help

    Examples of various Date widgets can be found on the demo pages.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/widgets/select.html0000644000175000017500000000567507253523117024707 0ustar frankiefrankie Templating System Widget Reference: Select

    The Input Widgets

    Templating System : Widget Reference : Select

    Overview

    These widgets provide the single-selection and multiple-selection HTML controls; their usage is demonstrated in the acs-templating demo.

    The Select Widget

    This widget creates a list of choices, only one of which may be selected at any given time, using the HTML <select> control. Similarly to the button group widgets, the Select widget has one required parameter, -option option_list, which specifies all the possible choices. The option_list is a list of label-value pairs. For example,

    template::element create pizza_form topping \
     -label "Pizza Topping" -datatype keyword -widget select \
     -options { 
        {Pepperoni pepperoni} 
        {Sausage sausage} 
        {{Canadian Bacon} cbacon} 
      }
    
    will create a widget with 3 choices: "Pepperoni", "Sausage" and "Canadian Bacon". By default, the widget looks like a drop-down "picklist", however, it can be forced to look like a scrollable vertical list of n elements by using the -html { size n } parameter.

    The value of the Select widget is the value of the currently selected choice. If no choice is selected, the value will be the empty string. However, if the widget happens to look like a picklist, most Web browsers automatically select the first option on the list. This behavior may be changed by supplying an extra "null" option. For example, the options for the pizza topic selection widget shown above could be changed to

    template::element create pizza_form topping \
     -label "Pizza Topping" -datatype keyword -widget select \
     -options { 
        {{No Topping} {}}
        {Pepperoni pepperoni} 
        {Sausage sausage} 
        {{Canadian Bacon} cbacon} 
      }
    

    The Multiselect Widget

    This widget is similar to the Select widget, but it allows multiple values to be selected. Because of this, the Multiselect widget cannot look like a picklist. By default, the widget looks like a scrollable list of items, which grows up to 8 items in size (in other words, up to 8 items will be shown without the need to scroll). This size can be overwritten with the -html { size n } parameter.

    The values (plural) property of the corresponding element contains a list of all the selected choices; the value (singular) property contains the first selected choice.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/widgets/index.html0000644000175000017500000000102607253523117024521 0ustar frankiefrankie Templating System Widget Reference

    Slave

    Templating System : Widget Reference

    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/widgets/table.html0000644000175000017500000000107507253523117024505 0ustar frankiefrankie Templating System Widget Reference: Table

    Table Widget

    Templating System : Widget Reference : Table

    Overview

    The table widget facilitates the creation of a dynamic table with controls for sorting on any number of columns. The table layout may be based on a standard sitewide style, or on a custom template.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/widgets/input.html0000644000175000017500000000573207253523117024561 0ustar frankiefrankie Templating System Widget Reference: Input

    The Input Widgets

    Templating System : Widget Reference : Input

    Overview

    These widgets provide a variety of HTML controls, all of which are based on <input type=...>. In particular, the hidden, text, radio and checkbox widgets are currently implemented; their use is demonstrated in the acs-templating demo.

    The Hidden Widget

    This is simply an <input type=hidden> widget, which is used for passing pre-set variables along with the form.

    The Text Widget

    This widget allows the user to enter one line of text. It is completely identical to the <input type=text>. The -html parameter can be used to set its properties (such as size, maxlength, etc.), as described in the general widgets reference. The value of this widget is the text string.

    The Radio Group Widget

    This widget actually represents a group of radio buttons, at most one of which can be selected at any given time. The widget has one required parameter, -option option_list, which specifies the radio buttons to display. The option_list is a list of label-value pairs. For example,

    template::element create test_form cost \
     -label "Car Cost" -datatype number -widget radio \
     -options { {Cheap 1000} {Medium 50000} {Expensive 999999} }
    
    will create a radio button group with 3 options: "Cheap", whose value is 1000, "Medium", whose value is 50000, and "Expensive", whose value is 999999. The value of the entire widget is either the empty string (if the user did not select any of the radio buttons), or a the value of the currently selected radio button. For instance, if the user selects "Medium" in the example above, the value of cost will be 50000.

    The default form template renders the Radio Group widget as a column of radio buttons. Since the Radio Group can consist of many HTML controls, the usual formwidget tag cannot be used to position the widget; instead, the formgroup tag must be used.

    The Checkbox Group Widget

    This widget is identical in use to the Radio Group widget, but instead of radio buttons it generates a group of checkboxes, any number of which can be checked at any given time. The values (plural) property of the corresponding element contains a list of all the checked values; the value (singular) property contains the first element in the list.


    templating@arsdigita.com openacs-5.7.0/packages/acs-templating/www/doc/exercise/0000755000175000017500000000000011724401447022665 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/doc/exercise/slave-sample.adp0000644000175000017500000000067507253523117025755 0ustar frankiefrankie <master> and <slave> Demo: Master P

    The point of all this clicking about is just to show how this text area can be varied...

    next openacs-5.7.0/packages/acs-templating/www/doc/exercise/slave-sample.tcl0000644000175000017500000000001207253523117025754 0ustar frankiefrankieset foo 1 openacs-5.7.0/packages/acs-templating/www/doc/exercise/slave-sample-2.adp0000644000175000017500000000036107253523117026104 0ustar frankiefrankie <master> and <slave> Demo:

    while the rest of the page stays the same.

    next openacs-5.7.0/packages/acs-templating/www/doc/exercise/slave-sample-3.adp0000644000175000017500000000061007253523117026102 0ustar frankiefrankie <master> and <slave> Demo:

    Be sure to note how the url has changed to reflect the slave's file name, and not the master's.
    (In this case the master file is the same one you've been working with all along, of course)

    next openacs-5.7.0/packages/acs-templating/www/doc/exercise/slave-sample-4.adp0000644000175000017500000000037607253523117026114 0ustar frankiefrankie <master> and <slave> Demo:

    Okay, I think you get the point.

    back to the problem set openacs-5.7.0/packages/acs-templating/www/doc/exercise/master-sample.adp0000644000175000017500000000101707253523117026125 0ustar frankiefrankie @title@


    your_name@here.com
    @closing_text@

    Last modified: Tue Nov 14 18:03:19 EST 2000 openacs-5.7.0/packages/acs-templating/www/doc/exercise/list-and-var-sample.adp0000644000175000017500000000252507663155741027151 0ustar frankiefrankie @name;noquote@'s Personal Home Page It's been a pleasure to serve you this page

    @name@'s Personal Web Page

    This web page is the uniquely conceived brainchild of @name@, a product of long @time_periods@ of assiduous labor and the creative genius of @name@. Esoteric, unforeseen, and unforgettable, this web page stands as a monument to the singular and inimitable mind that is @name@.

    Now, for some basic contact information:
    Name:@name@
    Address:@address@
    Email:@email

    These are my best friends! Email them!

    • @friends.first_names@, a @friends.age@ year old gal guy who lives at @friends.address@ and doesn't like likes chocolate

    • also, @friends.extra_column@
      and one more thing: @friends.another_column@

    @header@
    openacs-5.7.0/packages/acs-templating/www/doc/exercise/list-and-var-sample.tcl0000644000175000017500000000527111145351655027160 0ustar frankiefrankie # @datasource name onevalue # your name # @datasource address onevalue # @datasource home_number onevalue # @datasource work_number onevalue # @datasource people onevalue # @datasource email onevalue # your email address # @datasource time_periods onevalue # units by which you measure the period of time required to make this page # @datasource friends multirow # a list of friends and their vital stats # @column first_names friend's first and middle names # @column last_name this is straightforward enough # @column age # @column gender column will contain one of three values: "m" for male, "f" # for female or an empty string # @column address # @column likes_chocolate_p either "t" for chocolate-lovers, "f" for choco-phobes # and an empty string if I don't know # @column email friend's email address # @datasource movies multirow # information and comments on movies you've recently seen # @column title # @column director # @column cast a text string listing cast members # @column year release year # @column comments a short blurb reviewing the movie # This is a simple, sample .tcl page that sets the variables you'll be using # in your template. If you wish, you can change the values of those variables # in this page. # First, let's set the name variable, which can be displayed in your template using # the @name@ marker #if {![info exists name] || $name eq ""} { set name "(Your Name)" #} set title "$name" append title "'s Personal Web Page" # And here are a few other variables to play with: set address "2311 LeConte Berkeley, California 94709" set home_number "510-555-5555" set work_number "510-555-5556" set email "youremail@you.com" set time_periods "months" # create the multirow variables # Now, let's set a list variable containing a few dummy values set hobbies [list "listening to Ricky Martin 'cuz he's awsome!" \ "hanging out with my best buds" \ "telling jokes -- my friends say I've got a great sense of humor!"] db_multirow friends get_friends "" #template::multirow create foo_multirow columns1 columns2 columns3 template::multirow extend friends extra_column for {set i 1} {$i <= ${friends:rowcount}} {incr i} { set row friends:$i set ${row}(extra_column) "hey there" } set friends:1(extra_column) "${friends:1(first_names)} is da bomb totally" template::multirow foreach friends { set friends.extra_column "@friends.first_names@ is a good person" } template::multirow extend friends another_column template::multirow foreach friends { if {[info exists friends.extra_column]} { set friends.another_column "there is stuff in dere" } else { set friends.another_column "no stuff in dere" } } if {![info exists header]} { set header "" } openacs-5.7.0/packages/acs-templating/www/doc/exercise/list-and-var-sample.txt0000644000175000017500000000424007253523117027207 0ustar frankiefrankie # @datasource name onevalue # your name # @datasource address onevalue # @datasource home_number onevalue # @datasource work_number onevalue # @datasource people onevalue # @datasource email onevalue # your email address # @datasource time_periods onevalue # units by which you measure the period of time required to make this page # @datasource friends multirow # a list of friends and their vital stats # @column first_names friend's first and middle names # @column last_name this is straightforward enough # @column age # @column gender column will contain one of three values: "m" for male, "f" # for female or an empty string # @column address # @column likes_chocolate_p either "t" for chocolate-lovers, "f" for choco-phobes # and an empty string if I don't know # @column email friend's email address # @datasource movies multirow # information and comments on movies you've recently seen # @column title # @column director # @column cast a text string listing cast members # @column year release year # @column comments a short blurb reviewing the movie # This is a simple, sample .tcl page that sets the variables you'll be using # in your template. If you wish, you can change the values of those variables # in this page. # First, let's set the name variable, which can be displayed in your template using # the @name@ marker #if {![info exists name] || $name == ""} { set name "(Your Name)" #} set title "$name" append title "'s Personal Web Page" # And here are a few other variables to play with: set address "2311 LeConte Berkeley, California 94709" set home_number "510-555-5555" set work_number "510-555-5556" set email "youremail@you.com" set time_periods "months" # create the multirow variables # Now, let's set a list variable containing a few dummy values set hobbies [list "listening to Ricky Martin 'cuz he's awsome!" \ "hanging out with my best buds" \ "telling jokes -- my friends say I've got a great sense of humor!"] template::query friends multirow "select first_names, last_name, age, gender, address, likes_chocolate_p from best_friends" #template::form create add_friend \ # -html {} if {![info exists header]} { set header "" } openacs-5.7.0/packages/acs-templating/www/doc/exercise/form-sample-revised.adp0000644000175000017500000000026207253523117027235 0ustar frankiefrankie My address book Add an entry to your address book openacs-5.7.0/packages/acs-templating/www/doc/exercise/form-sample-revised.tcl0000644000175000017500000000423707272154375027270 0ustar frankiefrankie form create add_entry -elements { first_names -html { size 30 } -label "First Name" -datatype text last_name -html { size 30 } -label "Last Name" -datatype text title -label "Title" -datatype text -widget select -optional -options {{Mr. Mr.} {Mrs. Mrs.} {Ms. Ms.} {Dr. Dr.}} birthday -label "Birthday" -datatype date -widget date -format "MONTH DD, YYYY" -optional gender -label "Gender" -datatype text -widget radio -options { {male m} {female f}} address -html { size 40 } -label "Address" -optional -datatype text city -html { size 30 } -label "City" -optional -datatype text state -html { size 3 maxlength 2 } -label "State" -optional -datatype keyword \ -validate { {expr [string length $value ] ==2 } {Entry for tate must be two characters in length } } zip -html { size 10 } -label "Zip" -optional -datatype text country -html { size 30 } -label "Country" -optional -datatype text email -html { size 30 } -label "Email" -optional -datatype text relationship -label "Type of acquaintance" -datatype text -widget checkbox -optional \ -options { {relative relative} {friend friend} {{business acquaintance} business} {paramour paramour}} home -html { size 12 } -label "Home phone" -optional -datatype text work -html { size 12 } -label "Work" -optional -datatype text cell -html { size 12 } -label "Cell" -optional -datatype text pager -html { size 12 } -label "Pager" -optional -datatype text fax -html { size 12 } -label "Fax" -optional -datatype text primary_phone -label "Primary phone" -datatype text -widget radio -options { {home home}\ {work work} {cell cell} {pager pager} {fax fax}} -optional } if {[form is_request add_entry]} { ns_log error "this is a request for add_entry" } if { [form is_valid add_entry] } { ns_log error "now we've gotten past the if statement" db_dml insert_address -bind [ns_getform] " insert into address_book values ( :first_names, :last_name, :title, null, :gender, :address, :city, :state, :zip, :country, :email, :relationship, :primary_phone, :home, :work, :cell, :pager, :fax )" template::forward index.html } openacs-5.7.0/packages/acs-templating/www/doc/exercise/templating-exercise.sql0000644000175000017500000000442007253523117027360 0ustar frankiefrankie create table best_friends ( first_names varchar2(40), last_name varchar2(40), age integer, gender char(1) check (gender in ('m', 'f')), address varchar2(300), likes_chocolate_p char(1) check (likes_chocolate_p in ('t','f')), email varchar(100)); insert into best_friends (first_names, last_name, age, gender, address, likes_chocolate_p, email) values ('Antonio', 'Davis', 24, 'm', '452 Hawkins Rd', 'f', 'antonio@nobody.com'); insert into best_friends (first_names, last_name, age, gender, address, likes_chocolate_p, email) values ('Matt', 'Carrier', 23, 'm', '345 Crystal City', null, 'matt@nobodoy.com'); insert into best_friends (first_names, last_name, age, gender, address, likes_chocolate_p, email) values ('Nobuko', 'Asakai', 23, 'f', '401 Boradway', 't', 'nobuko@nobody.com'); insert into best_friends (first_names, last_name, age, gender, address, likes_chocolate_p, email) values ('Grandma', null, 83, 'f', '1320 Dreiser Ct.', null, 'grandma@nobody.com'); create table movies ( title varchar2(100), director varchar2(100), cast varchar2(500), year integer, comments varchar2(2000) ); insert into movies (title, director, cast, year, comments) values ('2001: Space Odyssey', 'Stanley Kubrick', 'A big space fetus', null, 'Neat! This movie had cool spaceships and a crazy computer!'); insert into movies (title, director, cast, year, comments) values ('Dancer in the Dark', 'Lars von Trier', 'Bjork',2000, 'This movie was very sad. It made me cry'); insert into movies (title, director, cast, year, comments) values ('Charlie"s Angel',null, 'Drew Barrymore, Bill Murray', 2000, 'This movie was very sad. It also made me cry'); create table address_book ( -- entry_id integer, first_names varchar2(40), last_name varchar2(40), title varchar2(40), birthday date, gender char(1) check (gender in ('m', 'f')), address varchar2(300), city varchar2(100), state varchar2(40), zip varchar2(10), country varchar2(100), email varchar2(100), relation_types varchar2(400), primary_phone varchar2(40), home_phone varchar2(40), work_phone varchar2(40), cell_phone varchar2(40), pager varchar2(40), fax varchar2(40) ); openacs-5.7.0/packages/acs-templating/www/doc/exercise/ats-for-designers.html0000644000175000017500000004166207253523117027121 0ustar frankiefrankie The ACS Templating System for Web Designers

    The ACS Templating System for Web Designers

    Templating System : Templating Exercise

    Reading

    Sections

    1. Overview
    2. Exercises

    Overview

    This series of exercises is meant as a learning tool for any web graphic designer wanting or needing to understand how the ACS Templating System, or ATS, works, and how to use it in building web pages.

    First, perhaps an explanation of what the templating system does will help us understand how it works. An ATS template itself serves as a reusable, unchanging framework that delivers dynamic data. The advantage to this is something you probably already realize: you need only build and edit a few pages to maintain a consistent presentation style while accomodating numerous permutaions of changing data.

    This training module will teach largely by exercise and example, but you should also refer regularly to the ATS documents provided and more specific pointers will be given to help you out along the way.

    Okay, let's get to the nitty gritty.

    Exercises

    The basic building block of dynamic data in a template is the onevalue variable. A variable is simply a tag used in your .adp file that holds data supplied by another source file; that source will probably be another file of the same name with a .tcl extension. Variable tags come in three basic formats, as lists, multiples and onevalues.

    Exercise 1: Onevalues, onelists, multilists and multirows
    (nestedlists, too?)

    Let's first take a look at some list and variable tags in action. Open up another browser and look at this page, which is a text rendition of the /ats/doc/exercise/list-and-var-sample.tcl page we'll be sourcing our data from; at the top of the page you'll find a block of commented text describing the variables generated by this page, followed by the actual code itself. Now, using your preferred text editor, open the file list-and-var-sample.adp located in the same directory and compare the html script that you see there with the final user-viewed page, list-and-var-sample.acs. Almost every .acs page the user sees is supported by one .tcl file which supplies the data to be shown, and one .adp file specifying the format of it's presentation. Compare what you see in list-and-var-sample.acs with its supporting .adp file and make note of the textual and structural differences between the two, specifically:

    • variables in the .adp file are designated with "@" markers, like the @name@ variable that litters the opening text block of list-and-var-sample.adp; here, @name@ is used as a place-marker for the value set in list-and-var.sample.tcl
    • the variables within the <multiple> tag, though only appearing once in the .adp file, are cycled repeatedly to show multiple sets of information when displayed in list-and-var-sample.acs; example:
          <multiple name="your_multirow">
          <tr><td>@your_multirow.first_names@ @your_multirow.last_name@ </td> </tr>
          </multiple>
          
      The user will see one table row filled with a different person's name for each row contained in the multirow your_multirow.
    • multirow variables are identified with this format: @<name of the multirow>.<name of a field in the multirow>@, and can only be called within their respective <multiple> tags

    You probably noticed some other funky looking tags, too, but ignore those for now.

    Now since the variable marker @name@ is set in list-and-var-sample.tcl, you can go ahead and edit that file to replace "(Your Name)" with whatever your name really is (be sure to leave the quotes); if you wish,edit some of the other values to personalize the page. You'll see your changes take effect upon saving the .tcl file and reloading list-and-var-sample.acs. In general, though, you should probably not be editing .tcl files unless you have a pretty good sense of their innerworkings.

    Okay, now go back to the web browser in which you are viewing list-and-var-sample.acs and change the ".acs" extension to ".dat". This page displays a view of datasources generated in the .tcl file that can be used in your .adp template (actually, the information is generated from commented text parsed from the top of the .tcl file, so you can view this information in either the .dat page or straight from the .tcl file). Go ahead and make use of the datasource variables not already included in the .adp file; specifically, change list-and-var-sample.adp so that:

    • your personal phone number information is included
    • each of your friends' names serves as a hyperlink that allows the viewer to email your friend
    • a listing of recently watched movies and your reactions to them follows after the information about your friends
    • also, note that the use of any variable tags referring to variables not declared in the .tcl file will break the .acs page

    Congratulations! You've just created a personalized web page describing friends you've never met and movies you've possibly never seen.

    Exercise Two: <if> and <else>, the conditional tags

    Dynamic data implies a changing page, and also changing presentation. The <if> and <else> tags allow you to alter the format of your page to accomodate data changes. The function of <if> is straightforward enough: given a condition -- such as @x@ equals 5 -- all the text/html/dynamic data between the the opening and closing <if> tags will be displayed if and only if @x@ does in fact equal 5. A complete listing of currently supported conditions and some brief explanatory notes can be found here. Also, a few more things to keep in mind:

    • in Tcl all variables, even numbers, are stored as text strings with quantitative values, so conditions like less than, greater than, and (not) between can also be used with text to determine alphabetical order: a < b < ... < z, lower-case letters are greater than upper-case, and numbers less than letters. Example: "you" are greater than "me", and "I" am less than "you"
    • the "between" conditions checks inclusively, so <if 2 between 2 6> will test true
    • <if @a@ between @b@ @c@> requires that @a@ is greater than or equal to @b@ and less than or equal to @c@; so <if @x@ between 4 2> will always test false
    • the "in" condition uses a regular expression check (or will it? come back here and revise)

    Now, alter a few of the <if> tags in list-and-var-samle.adp and add a few of your own. Specifically, add one <if> and <else> combination so that the friend description reads "likes chocolate" when likes_chocolate_p is "t", "doesn't like chocolate" when likes_chocolate_p is "f", or "probably like chocolate" if likes_chocolate_p is an empty string. Also, add one <if>, and one <if> only, so that a is appropriately changed to an for any 11-, 18- or 80- to 89-year olds.

    Exercise Three: The <master> and <slave> tags -- a call to the dominatrix in you

    The <master> and <slave> tags allow you to maintain a consistent style and format among pages without having to edit each page individually. To get a sense of what these tags do and how they work, go ahead and run through this short demonstration, and then use a text editor to view the related .adp files. Also, read this discussion on the use of master pages.

    One thing you may have noticed earlier about list-and-var-sample.adp is that it lacks the standard <html>, <head>, <title> and <body> tags. This is because list-and-var-sample.adp is, as indicated by the <master> tag at the top of the file, also a slave section, contained within master-sample.adp.

    Let me stress a few key points you might have already picked up on from the demonstration and upon examining the .adp files, and add a few pointers:

    • the <slave> tag indicates where on the master page the slave section is inserted
    • slave pages indicate the source of the master file with the <master> tag, referring by the file name only, and not including its ".adp" extension
    • as mentioned earlier, slave sections do not require <html>, <head>, and <body> tags when contained within a master tag already formatted for HTML
    • as the demonstration points out, pages are browsed at the .acs page sharing the same file name as the slave, not master
    • the master page can be viewed at its own .acs page, but shows nothing in place of the <slave> tag
    • you can have nested slave sections, that is, a slave section within another slave
    • you cannot have two different slave sections within the same master (go ahead and try adding an extra <slave> tag to a master page to see what happens)
    • <property> tags are used within a slave section to pass text, HTML and references to local datasources up to the master page; these values are placed in the master page in the same fashion as onevalues
    • data and HTML can be passed from a nested slave section to its uber-master by using one <property> tag on each intermediate page
    • if a variable set in the Tcl file of a master page shares the same name as a variable declared within the slave section's <property> tag, the master value overrides the slave's (unless the Tcl code checks for pre-existing information)

    Now that the secrets of <master> and <slave> have been revealed, it's time to put a little of your newfound knowledge to use. Open up form-sample.adp, a standalone, independently formatted html page, and enslave it to the mastery of of your personal web page. It would also be nice if you were to label the newly inserted form with some slave-specific title.

    Exercise Four: The functions of <formtemplate>

    Creating forms with ATS can be as simple as inserting two tags into a page. Try this: open form-sample.adp and add the two following ATS tags:

    <formtemplate id="add_entry"></formtemplate>

    Save the page and reload it. You should see now see a big baby-blue form block; this is the ATS default style for form presentation. Aside from requiring no HTML code, the <formtemplate> default has the added convenience of automated entry validation with appropriate correction requests. Test this out by trying to submit a form without including first or last name or gender information.

    However, if ever you wish to build a form according to the mandates of your own taste, <formtemplate> also leaves you this option. Manually stylizing forms with ATS requires you to learn only two more tags, <formwidget> and <formgroup>. Browse through the ATS demo for examples of <formwidget> and <formwidget> usage. For the most part <formwidget> should be used in most places you might have used <select> or <input> in plain HTML, save for <input> checkboxes and radio buttons, which should be replaced with the <formgroup> tag. When working with ATS you should probably refrain from using plain <input> and <select> tags altogether.

    You may have already noticed a few <formwidget> and <formgroup> in use within the block of HTML and ATS text commented out in form-sample.adp. Go ahead and put that block of HTML/ATS code into action by removing the comment tag wrapper and deleting the </formtemplate> tag; you should now see a hand-built version of the same form.

    There are noticeable differences between the two form templates, most obviously the lack of background color and a few missing entry fields in the manually constructed one. Maybe not so noticeable is the grouping of entry widgets into one HTML table row (check out the Name field) and the multi-input combination of text entry boxes and radio buttons for entering telephone number information. Take a look at how the phone information entry section is constructed in form-sample.adp. Note specifically: <formgroup> is somewhat similar to the <multiple> tag in that the block of ATS code contained within the <formgroup> tags will be parsed into plain HTML once for each <formgroup> value option.

    Practice using <formwidget> and <formgroup> by adding the missing entry fields manually into the form. Make free use of any HTML properties to streamline the form to your liking. If you can't remember what those fields were you can replace the closing </formtemplate> tag to recover the default format, or make use of the .dat datasource page to view your developer's description and comments about the form.

    Also, try customizing your form's error response/correction request text. You'll need to use the <formerror> tag, an example of which can be found under the gender formwidget.

    Exercise Five: more fun with multirows

    Now that you've confidently added the conditional <if> and <else> tags to your ATS toolbelt, it's time to put those tools to good use in formatting multirow data. First, read the docs to learn about the automatcally generated @your_multirow.rownum@ column, the @your_multirow:rowcount@ onevalue which contains the total number of rows contained in your multirow, and the <multiple> startrow and maxrows attributes. Possible point of confusion: the variable @your_multirow:rowcount@ is a onevalue and not a column of the multirow your_multirow, so it need not be used within <multiple> tags and in many cases should not be used within <multiple> tags. Why is this? (Take a look at how @address:rowcount@ is used.) Now make the following improvements to the address book listing you found in form-sample.acs:

    • stripe the table with banded rows of alternating grey and white, or some other color scheme of your preference
    • use the startrow attribute so that the address book listing begins at a rownumber determined by the Tcl file code (check the .dat page)
    • add navigation links to the address book so that users can move forward or back between row listings, or jump to the beginning or end of their address book
      • each link should set the url variable that determines the first row of the set to be displayed
      • the links should only appear when necessary, that is, a link pointing towards the next set of rows should not appear if the user is already viewing rows 1-5 of 5 total rows.

    shuynh@arsdigita.com
    Last modified: Fri Nov 17 10:14:44 EST 2000 openacs-5.7.0/packages/acs-templating/www/doc/exercise/form-sample.adp0000644000175000017500000000535607572172130025606 0ustar frankiefrankie My address book Add an entry to your address book
    Name:
    Gender: @formgroup.label@ @formgroup.widget@
    Please include gender information about your entry subject
    Birthday:
    Address:
    City: State:
    Zip: Country:
    Email:
    Relation: @formgroup.widget@ @formgroup.label@
    Telephones:
    @formgroup.widget@@formgroup.label@
    please indicate your primary telephone

    Address Book:

    NameAddressEmailTelephone contact
    @address.first_names@ @address.last_name@ @address.address@
    @address.city@, @address.state@ @address.zip@
    @address.country@
    @address.email@ phone stuff
    You currently have no entries in your addressbook

    YES! NO!


    templating@arsdigita.com Last modified: Sun Oct 6 02:38:25 EDT 2002 openacs-5.7.0/packages/acs-templating/www/doc/exercise/form-sample.tcl0000644000175000017500000001146310551254405025615 0ustar frankiefrankie# @datasource address multirow # a listing of address book entries # @column first_names # @column last_name # @column title # title by which this person is to be addressed # @column birthday # birthdate, actually # @column gender # again, "m" for lads "f" for lassies # @column address # street address of residence or work # @column city # @column state # @column zip # @column country # @column email # @column relation_types # a space-separated list of keywords indicating types of relation; # values include "relative" "friend" "business" and "paramour" # @column home_phone # @column work_phone # @column cell_phone # @column pager # @column fax # @column primary_phone # a text string indicating which type of phone serves as the entry # subject's primary mode of telephone contact # @data_input add_entry form # a form for entering address book entries # @input first_names text # @input last_name text # @input title text form of address for entry subject # @input birthday date birthdate w/ "MONTH DD YYYY" format # @input gender radio # @datasource num_rows onevalue # the maximum number of rows to show on the page, default value is 10 # @datasource start_row onevalue # the rownumber on which the address listing should start; default 1 # @datasource next_set onevalue # the rownumber at which the following set of unlisted rows begins; # if there are no unlisted rows, next_set is an empty string # @datasource previous_set onevalue # the rownumber at which the previous set of unlisted rows begins; # if start_row already equals 1, than this is an empty string # @datasource last_set onevalue # the rownumber at which the last set of unlisted rows begins; # if the last row is already in display, than contains an empty string set start_row [ns_queryget start_row] if { $start_row eq "" } { set start_row 1 } if {![info exists num_rows] || [string trim $num_rows] ne ""} { set num_rows 5 } form create add_entry -elements { first_names -html { size 30 } -label "First Name" -datatype text last_name -html { size 30 } -label "Last Name" -datatype text title -label "Title" -datatype text -widget select -optional -options {{Mr. Mr.} {Mrs. Mrs.} {Ms. Ms.} {Dr. Dr.} } birthday -label "Birthday" -datatype date -widget date -format "MONTH DD, YYYY" -optional gender -label "Gender" -datatype text -widget radio -options { {male m} {female f}} address -html { size 40 } -label "Address" -optional -datatype text city -html { size 30 } -label "City" -optional -datatype text state -html { size 3 maxlength 2 } -label "State" -optional -datatype keyword \ -validate { {expr [string length $value ] ==2 } {Entry for tate must be two characters in length } } zip -html { size 10 } -label "Zip" -optional -datatype text country -html { size 30 } -label "Country" -optional -datatype text email -html { size 30 } -label "Email" -optional -datatype text relationship -label "Type of acquaintance" -datatype text -widget checkbox -optional \ -options { {relative relative} {friend friend} {{business acquaintance} business} {paramour paramour}} home -html { size 12 } -label "Home phone" -optional -datatype text work -html { size 12 } -label "Work" -optional -datatype text cell -html { size 12 } -label "Cell" -optional -datatype text pager -html { size 12 } -label "Pager" -optional -datatype text fax -html { size 12 } -label "Fax" -optional -datatype text primary_phone -label "Primary phone" -datatype text -widget radio -options { {home home}\ {work work} {cell cell} {pager pager} {fax fax}} -optional } if {[form is_request add_entry]} { ns_log error "this is a request for add_entry" } if { [form is_valid add_entry] } { [template::form get_values add_entry birthday] db_dml insert_form -bind [ns_getform] " insert into address_book values ( :first_names, :last_name, :title, '[template::util::date get_property sql_date $birthday]', :gender, :address, :city, :state, :zip, :country, :email, :relationship, :primary_phone, :home, :work, :cell, :pager, :fax )" # can't seem to get orable to bind array variables birthday.day, birthday.month and birthday.year # okay, turns out oracle doesn't support arrays, will have to do this in tcl first template::forward form-sample.acs } db_multirow address get_address "" set rowcount [set address:rowcount] if { $rowcount > [expr {$start_row + $num_rows}] } { set next_set [expr {$start_row + $num_rows}] } else { set next_set "" } if { $start_row > 1 } { set previous_set [expr {$start_row - $num_rows}] } else { set previous_set "" } if { $previous_set < 1} { set previous_set 1 } if {$rowcount > [expr {$next_set + $num_rows}]} { set last_set [expr {$rowcount - ($rowcount % $num_rows)}] } else { set last_set "" } openacs-5.7.0/packages/acs-templating/www/admin/0000755000175000017500000000000011724401447021401 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/admin/test/0000755000175000017500000000000011575225575022372 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/admin/test/include-0.adp0000644000175000017500000000247607663155640024647 0ustar frankiefrankie

    Testcase for recursive include and if

    This pages does two things:

    1. It exercises include recursively, passing changing args.
    2. The result is the test case for if and else, nesting them deeply and exercising all predicates, with and without "not"

    @lt@multiple name=v> @lt@/multiple>

    openacs-5.7.0/packages/acs-templating/www/admin/test/include-0.tcl0000644000175000017500000000032307253523117024643 0ustar frankiefrankiead_page_contract { test (simple) and recursive , generating more demanding testcase for } -properties { } -query { {indent ""} } set at @ set lt < set quot \" ad_return_template openacs-5.7.0/packages/acs-templating/www/admin/test/if.readme0000644000175000017500000000022007253523117024130 0ustar frankiefrankiebecome site-wide admin get /acs-templating/admin/test/include-0 save the result as if.adp provoke failing by supplying values like ?x=30 or ?z= openacs-5.7.0/packages/acs-templating/www/admin/test/chain-frac-0.tcl0000644000175000017500000003124410551254405025215 0ustar frankiefrankiead_page_contract { transform a real number into a chain fraction } -query { x } set page "" append page "

    Chain Fraction

    " set e [expr {exp(1)}] set e0 [expr {int ( $e ) }]; # keep the integer part in e0 set xf [expr {1 / ($e - $e0) }]; # invert the fractional part set e1 [expr {int ( $xf ) }]; # keep the integer part in e1 set xf [expr {1 / ($xf - $e1) }]; # invert the fractional part set e2 [expr {int ( $xf ) }]; # keep the integer part in e2 set xf [expr {1 / ($xf - $e2) }]; # invert the fractional part set e3 [expr {int ( $xf ) }]; # keep the integer part in e3 set xf [expr {1 / ($xf - $e3) }]; # invert the fractional part set e4 [expr {int ( $xf ) }]; # keep the integer part in e4 set xf [expr {1 / ($xf - $e4) }]; # invert the fractional part set e5 [expr {int ( $xf ) }]; # keep the integer part in e5 set xf [expr {1 / ($xf - $e5) }]; # invert the fractional part set e6 [expr {int ( $xf ) }]; # keep the integer part in e6 set xf [expr {1 / ($xf - $e6) }]; # invert the fractional part set e7 [expr {int ( $xf ) }]; # keep the integer part in e7 set xf [expr {1 / ($xf - $e7) }]; # invert the fractional part set e8 [expr {int ( $xf ) }]; # keep the integer part in e8 set xf [expr {1 / ($xf - $e8) }]; # invert the fractional part set e9 [expr {int ( $xf ) }]; # keep the integer part in e9 set xf [expr {1 / ($xf - $e9) }]; # invert the fractional part set e10 [expr {int ( $xf ) }]; # keep the integer part in e10 set xf [expr {1 / ($xf - $e10) }]; # invert the fractional part set e11 [expr {int ( $xf ) }]; # keep the integer part in e11 set xf [expr {1 / ($xf - $e11) }]; # invert the fractional part set e12 [expr {int ( $xf ) }]; # keep the integer part in e12 set xf [expr {1 / ($xf - $e12) }]; # invert the fractional part set e13 [expr {int ( $xf ) }]; # keep the integer part in e13 set xf [expr {1 / ($xf - $e13) }]; # invert the fractional part set e14 [expr {int ( $xf ) }]; # keep the integer part in e14 set xf [expr {1 / ($xf - $e14) }]; # invert the fractional part set e15 [expr {int ( $xf ) }]; # keep the integer part in e15 set xf [expr {1 / ($xf - $e15) }]; # invert the fractional part set e16 [expr {int ( $xf ) }]; # keep the integer part in e16 set xf [expr {1 / ($xf - $e16) }]; # invert the fractional part set e17 [expr {int ( $xf ) }]; # keep the integer part in e17 set xf [expr {1 / ($xf - $e17) }]; # invert the fractional part set e18 [expr {int ( $xf ) }]; # keep the integer part in e18 set xf [expr {1 / ($xf - $e18) }]; # invert the fractional part set e19 [expr {int ( $xf ) }]; # keep the integer part in e19 set xf [expr {1 / ($xf - $e19) }]; # invert the fractional part append page "

    Natural e

    $e = $e0 + 1/( $e1 + 1/( $e2 + 1/( $e3 + 1/( $e4 + 1/( $e5 + 1/( $e6 + 1/( $e7 + 1/( $e8 + 1/( $e9 + 1/( $e10 + 1/( $e11 + 1/( $e12 + 1/( $e13 + 1/( $e14 + 1/( $e15 + 1/( $e16 + 1/( $e17 + 1/( $e18 + 1/( $e19 + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    " # golden ratio set g [expr (sqrt(5)+1)/2] set g0 [expr {int ( $g ) }]; # keep the integer part in g0 set xf [expr {1 / ($g - $g0) }]; # invert the fractional part set g1 [expr {int ( $xf ) }]; # keep the integer part in g1 set xf [expr {1 / ($xf - $g1) }]; # invert the fractional part set g2 [expr {int ( $xf ) }]; # keep the integer part in g2 set xf [expr {1 / ($xf - $g2) }]; # invert the fractional part set g3 [expr {int ( $xf ) }]; # keep the integer part in g3 set xf [expr {1 / ($xf - $g3) }]; # invert the fractional part set g4 [expr {int ( $xf ) }]; # keep the integer part in g4 set xf [expr {1 / ($xf - $g4) }]; # invert the fractional part set g5 [expr {int ( $xf ) }]; # keep the integer part in g5 set xf [expr {1 / ($xf - $g5) }]; # invert the fractional part set g6 [expr {int ( $xf ) }]; # keep the integer part in g6 set xf [expr {1 / ($xf - $g6) }]; # invert the fractional part set g7 [expr {int ( $xf ) }]; # keep the integer part in g7 set xf [expr {1 / ($xf - $g7) }]; # invert the fractional part set g8 [expr {int ( $xf ) }]; # keep the integer part in g8 set xf [expr {1 / ($xf - $g8) }]; # invert the fractional part set g9 [expr {int ( $xf ) }]; # keep the integer part in g9 set xf [expr {1 / ($xf - $g9) }]; # invert the fractional part set g10 [expr {int ( $xf ) }]; # keep the integer part in g10 set xf [expr {1 / ($xf - $g10) }]; # invert the fractional part set g11 [expr {int ( $xf ) }]; # keep the integer part in g11 set xf [expr {1 / ($xf - $g11) }]; # invert the fractional part set g12 [expr {int ( $xf ) }]; # keep the integer part in g12 set xf [expr {1 / ($xf - $g12) }]; # invert the fractional part set g13 [expr {int ( $xf ) }]; # keep the integer part in g13 set xf [expr {1 / ($xf - $g13) }]; # invert the fractional part set g14 [expr {int ( $xf ) }]; # keep the integer part in g14 set xf [expr {1 / ($xf - $g14) }]; # invert the fractional part set g15 [expr {int ( $xf ) }]; # keep the integer part in g15 set xf [expr {1 / ($xf - $g15) }]; # invert the fractional part set g16 [expr {int ( $xf ) }]; # keep the integer part in g16 set xf [expr {1 / ($xf - $g16) }]; # invert the fractional part set g17 [expr {int ( $xf ) }]; # keep the integer part in g17 set xf [expr {1 / ($xf - $g17) }]; # invert the fractional part set g18 [expr {int ( $xf ) }]; # keep the integer part in g18 set xf [expr {1 / ($xf - $g18) }]; # invert the fractional part set g19 [expr {int ( $xf ) }]; # keep the integer part in g19 set xf [expr {1 / ($xf - $g19) }]; # invert the fractional part append page "

    Golden Ratio

    $g = $g0 + 1/( $g1 + 1/( $g2 + 1/( $g3 + 1/( $g4 + 1/( $g5 + 1/( $g6 + 1/( $g7 + 1/( $g8 + 1/( $g9 + 1/( $g10 + 1/( $g11 + 1/( $g12 + 1/( $g13 + 1/( $g14 + 1/( $g15 + 1/( $g16 + 1/( $g17 + 1/( $g18 + 1/( $g19 + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    " # Square root of 3 set r [expr {sqrt(3)}] set r0 [expr {int ( $r ) }]; # keep the integer part in r0 set xf [expr {1 / ($r - $r0) }]; # invert the fractional part set r1 [expr {int ( $xf ) }]; # keep the integer part in r1 set xf [expr {1 / ($xf - $r1) }]; # invert the fractional part set r2 [expr {int ( $xf ) }]; # keep the integer part in r2 set xf [expr {1 / ($xf - $r2) }]; # invert the fractional part set r3 [expr {int ( $xf ) }]; # keep the integer part in r3 set xf [expr {1 / ($xf - $r3) }]; # invert the fractional part set r4 [expr {int ( $xf ) }]; # keep the integer part in r4 set xf [expr {1 / ($xf - $r4) }]; # invert the fractional part set r5 [expr {int ( $xf ) }]; # keep the integer part in r5 set xf [expr {1 / ($xf - $r5) }]; # invert the fractional part set r6 [expr {int ( $xf ) }]; # keep the integer part in r6 set xf [expr {1 / ($xf - $r6) }]; # invert the fractional part set r7 [expr {int ( $xf ) }]; # keep the integer part in r7 set xf [expr {1 / ($xf - $r7) }]; # invert the fractional part set r8 [expr {int ( $xf ) }]; # keep the integer part in r8 set xf [expr {1 / ($xf - $r8) }]; # invert the fractional part set r9 [expr {int ( $xf ) }]; # keep the integer part in r9 set xf [expr {1 / ($xf - $r9) }]; # invert the fractional part set r10 [expr {int ( $xf ) }]; # keep the integer part in r10 set xf [expr {1 / ($xf - $r10) }]; # invert the fractional part set r11 [expr {int ( $xf ) }]; # keep the integer part in r11 set xf [expr {1 / ($xf - $r11) }]; # invert the fractional part set r12 [expr {int ( $xf ) }]; # keep the integer part in r12 set xf [expr {1 / ($xf - $r12) }]; # invert the fractional part set r13 [expr {int ( $xf ) }]; # keep the integer part in r13 set xf [expr {1 / ($xf - $r13) }]; # invert the fractional part set r14 [expr {int ( $xf ) }]; # keep the integer part in r14 set xf [expr {1 / ($xf - $r14) }]; # invert the fractional part set r15 [expr {int ( $xf ) }]; # keep the integer part in r15 set xf [expr {1 / ($xf - $r15) }]; # invert the fractional part set r16 [expr {int ( $xf ) }]; # keep the integer part in r16 set xf [expr {1 / ($xf - $r16) }]; # invert the fractional part set r17 [expr {int ( $xf ) }]; # keep the integer part in r17 set xf [expr {1 / ($xf - $r17) }]; # invert the fractional part set r18 [expr {int ( $xf ) }]; # keep the integer part in r18 set xf [expr {1 / ($xf - $r18) }]; # invert the fractional part set r19 [expr {int ( $xf ) }]; # keep the integer part in r19 set xf [expr {1 / ($xf - $r19) }]; # invert the fractional part append page "

    Square root of 3

    $r = $r0 + 1/( $r1 + 1/( $r2 + 1/( $r3 + 1/( $r4 + 1/( $r5 + 1/( $r6 + 1/( $r7 + 1/( $r8 + 1/( $r9 + 1/( $r10 + 1/( $r11 + 1/( $r12 + 1/( $r13 + 1/( $r14 + 1/( $r15 + 1/( $r16 + 1/( $r17 + 1/( $r18 + 1/( $r19 + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    " # the user's x set n0 [expr {int ( $x ) }]; # keep the integer part in n0 set xf [expr {1 / ($x - $n0) }]; # invert the fractional part set n1 [expr {int ( $xf ) }]; # keep the integer part in n1 set xf [expr {1 / ($xf - $n1) }]; # invert the fractional part set n2 [expr {int ( $xf ) }]; # keep the integer part in n2 set xf [expr {1 / ($xf - $n2) }]; # invert the fractional part set n3 [expr {int ( $xf ) }]; # keep the integer part in n3 set xf [expr {1 / ($xf - $n3) }]; # invert the fractional part set n4 [expr {int ( $xf ) }]; # keep the integer part in n4 set xf [expr {1 / ($xf - $n4) }]; # invert the fractional part set n5 [expr {int ( $xf ) }]; # keep the integer part in n5 set xf [expr {1 / ($xf - $n5) }]; # invert the fractional part set n6 [expr {int ( $xf ) }]; # keep the integer part in n6 set xf [expr {1 / ($xf - $n6) }]; # invert the fractional part set n7 [expr {int ( $xf ) }]; # keep the integer part in n7 set xf [expr {1 / ($xf - $n7) }]; # invert the fractional part set n8 [expr {int ( $xf ) }]; # keep the integer part in n8 set xf [expr {1 / ($xf - $n8) }]; # invert the fractional part set n9 [expr {int ( $xf ) }]; # keep the integer part in n9 set xf [expr {1 / ($xf - $n9) }]; # invert the fractional part set n10 [expr {int ( $xf ) }]; # keep the integer part in n10 set xf [expr {1 / ($xf - $n10) }]; # invert the fractional part set n11 [expr {int ( $xf ) }]; # keep the integer part in n11 set xf [expr {1 / ($xf - $n11) }]; # invert the fractional part set n12 [expr {int ( $xf ) }]; # keep the integer part in n12 set xf [expr {1 / ($xf - $n12) }]; # invert the fractional part set n13 [expr {int ( $xf ) }]; # keep the integer part in n13 set xf [expr {1 / ($xf - $n13) }]; # invert the fractional part set n14 [expr {int ( $xf ) }]; # keep the integer part in n14 set xf [expr {1 / ($xf - $n14) }]; # invert the fractional part set n15 [expr {int ( $xf ) }]; # keep the integer part in n15 set xf [expr {1 / ($xf - $n15) }]; # invert the fractional part set n16 [expr {int ( $xf ) }]; # keep the integer part in n16 set xf [expr {1 / ($xf - $n16) }]; # invert the fractional part set n17 [expr {int ( $xf ) }]; # keep the integer part in n17 set xf [expr {1 / ($xf - $n17) }]; # invert the fractional part set n18 [expr {int ( $xf ) }]; # keep the integer part in n18 set xf [expr {1 / ($xf - $n18) }]; # invert the fractional part set n19 [expr {int ( $xf ) }]; # keep the integer part in n19 set xf [expr {1 / ($xf - $n19) }]; # invert the fractional part append page "

    Your x

    $x = $n0 + 1/( $n1 + 1/( $n2 + 1/( $n3 + 1/( $n4 + 1/( $n5 + 1/( $n6 + 1/( $n7 + 1/( $n8 + 1/( $n9 + 1/( $n10 + 1/( $n11 + 1/( $n12 + 1/( $n13 + 1/( $n14 + 1/( $n15 + 1/( $n16 + 1/( $n17 + 1/( $n18 + 1/( $n19 + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    " doc_return 200 text/html $page openacs-5.7.0/packages/acs-templating/www/admin/test/chain-frac-1.adp0000644000175000017500000000440307253523117025201 0ustar frankiefrankie

    Chain Fraction

    Natural e

    @e@ = @e0@ + 1/( @e1@ + 1/( @e2@ + 1/( @e3@ + 1/( @e4@ + 1/( @e5@ + 1/( @e6@ + 1/( @e7@ + 1/( @e8@ + 1/( @e9@ + 1/( @e10@ + 1/( @e11@ + 1/( @e12@ + 1/( @e13@ + 1/( @e14@ + 1/( @e15@ + 1/( @e16@ + 1/( @e17@ + 1/( @e18@ + 1/( @e19@ + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    Golden Ratio

    @g@ = @g0@ + 1/( @g1@ + 1/( @g2@ + 1/( @g3@ + 1/( @g4@ + 1/( @g5@ + 1/( @g6@ + 1/( @g7@ + 1/( @g8@ + 1/( @g9@ + 1/( @g10@ + 1/( @g11@ + 1/( @g12@ + 1/( @g13@ + 1/( @g14@ + 1/( @g15@ + 1/( @g16@ + 1/( @g17@ + 1/( @g18@ + 1/( @g19@ + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    Square root of 3

    @r@ = @r0@ + 1/( @r1@ + 1/( @r2@ + 1/( @r3@ + 1/( @r4@ + 1/( @r5@ + 1/( @r6@ + 1/( @r7@ + 1/( @r8@ + 1/( @r9@ + 1/( @r10@ + 1/( @r11@ + 1/( @r12@ + 1/( @r13@ + 1/( @r14@ + 1/( @r15@ + 1/( @r16@ + 1/( @r17@ + 1/( @r18@ + 1/( @r19@ + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    Your x

    @x@ = @n0@ + 1/( @n1@ + 1/( @n2@ + 1/( @n3@ + 1/( @n4@ + 1/( @n5@ + 1/( @n6@ + 1/( @n7@ + 1/( @n8@ + 1/( @n9@ + 1/( @n10@ + 1/( @n11@ + 1/( @n12@ + 1/( @n13@ + 1/( @n14@ + 1/( @n15@ + 1/( @n16@ + 1/( @n17@ + 1/( @n18@ + 1/( @n19@ + ... ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

    openacs-5.7.0/packages/acs-templating/www/admin/test/chain-frac-1.tcl0000644000175000017500000002736610551254405025230 0ustar frankiefrankiead_page_contract { transform a real number into a chain fraction } -properties { n0:onevalue n1:onevalue n2:onevalue n3:onevalue n4:onevalue n5:onevalue n6:onevalue n7:onevalue n8:onevalue n9:onevalue n10:onevalue n11:onevalue n12:onevalue n13:onevalue n14:onevalue n15:onevalue n16:onevalue n17:onevalue n18:onevalue n19:onevalue x:onevalue e:onevalue e0:onevalue e1:onevalue e2:onevalue e3:onevalue e4:onevalue e5:onevalue e6:onevalue e7:onevalue e8:onevalue e9:onevalue e10:onevalue e11:onevalue e12:onevalue e13:onevalue e14:onevalue e15:onevalue e16:onevalue e17:onevalue e18:onevalue e19:onevalue g:onevalue g0:onevalue g1:onevalue g2:onevalue g3:onevalue g4:onevalue g5:onevalue g6:onevalue g7:onevalue g8:onevalue g9:onevalue g10:onevalue g11:onevalue g12:onevalue g13:onevalue g14:onevalue g15:onevalue g16:onevalue g17:onevalue g18:onevalue g19:onevalue r:onevalue r0:onevalue r1:onevalue r2:onevalue r3:onevalue r4:onevalue r5:onevalue r6:onevalue r7:onevalue r8:onevalue r9:onevalue r10:onevalue r11:onevalue r12:onevalue r13:onevalue r14:onevalue r15:onevalue r16:onevalue r17:onevalue r18:onevalue r19:onevalue } -query { x } # the user's x set n0 [expr {int ( $x ) }]; # keep the integer part in n0 set xf [expr {1 / ($x - $n0) }]; # invert the fractional part set n1 [expr {int ( $xf ) }]; # keep the integer part in n1 set xf [expr {1 / ($xf - $n1) }]; # invert the fractional part set n2 [expr {int ( $xf ) }]; # keep the integer part in n2 set xf [expr {1 / ($xf - $n2) }]; # invert the fractional part set n3 [expr {int ( $xf ) }]; # keep the integer part in n3 set xf [expr {1 / ($xf - $n3) }]; # invert the fractional part set n4 [expr {int ( $xf ) }]; # keep the integer part in n4 set xf [expr {1 / ($xf - $n4) }]; # invert the fractional part set n5 [expr {int ( $xf ) }]; # keep the integer part in n5 set xf [expr {1 / ($xf - $n5) }]; # invert the fractional part set n6 [expr {int ( $xf ) }]; # keep the integer part in n6 set xf [expr {1 / ($xf - $n6) }]; # invert the fractional part set n7 [expr {int ( $xf ) }]; # keep the integer part in n7 set xf [expr {1 / ($xf - $n7) }]; # invert the fractional part set n8 [expr {int ( $xf ) }]; # keep the integer part in n8 set xf [expr {1 / ($xf - $n8) }]; # invert the fractional part set n9 [expr {int ( $xf ) }]; # keep the integer part in n9 set xf [expr {1 / ($xf - $n9) }]; # invert the fractional part set n10 [expr {int ( $xf ) }]; # keep the integer part in n10 set xf [expr {1 / ($xf - $n10) }]; # invert the fractional part set n11 [expr {int ( $xf ) }]; # keep the integer part in n11 set xf [expr {1 / ($xf - $n11) }]; # invert the fractional part set n12 [expr {int ( $xf ) }]; # keep the integer part in n12 set xf [expr {1 / ($xf - $n12) }]; # invert the fractional part set n13 [expr {int ( $xf ) }]; # keep the integer part in n13 set xf [expr {1 / ($xf - $n13) }]; # invert the fractional part set n14 [expr {int ( $xf ) }]; # keep the integer part in n14 set xf [expr {1 / ($xf - $n14) }]; # invert the fractional part set n15 [expr {int ( $xf ) }]; # keep the integer part in n15 set xf [expr {1 / ($xf - $n15) }]; # invert the fractional part set n16 [expr {int ( $xf ) }]; # keep the integer part in n16 set xf [expr {1 / ($xf - $n16) }]; # invert the fractional part set n17 [expr {int ( $xf ) }]; # keep the integer part in n17 set xf [expr {1 / ($xf - $n17) }]; # invert the fractional part set n18 [expr {int ( $xf ) }]; # keep the integer part in n18 set xf [expr {1 / ($xf - $n18) }]; # invert the fractional part set n19 [expr {int ( $xf ) }]; # keep the integer part in n19 set xf [expr {1 / ($xf - $n19) }]; # invert the fractional part # e set e [expr {exp(1)}] set e0 [expr {int ( $e ) }]; # keep the integer part in e0 set xf [expr {1 / ($e - $e0) }]; # invert the fractional part set e1 [expr {int ( $xf ) }]; # keep the integer part in e1 set xf [expr {1 / ($xf - $e1) }]; # invert the fractional part set e2 [expr {int ( $xf ) }]; # keep the integer part in e2 set xf [expr {1 / ($xf - $e2) }]; # invert the fractional part set e3 [expr {int ( $xf ) }]; # keep the integer part in e3 set xf [expr {1 / ($xf - $e3) }]; # invert the fractional part set e4 [expr {int ( $xf ) }]; # keep the integer part in e4 set xf [expr {1 / ($xf - $e4) }]; # invert the fractional part set e5 [expr {int ( $xf ) }]; # keep the integer part in e5 set xf [expr {1 / ($xf - $e5) }]; # invert the fractional part set e6 [expr {int ( $xf ) }]; # keep the integer part in e6 set xf [expr {1 / ($xf - $e6) }]; # invert the fractional part set e7 [expr {int ( $xf ) }]; # keep the integer part in e7 set xf [expr {1 / ($xf - $e7) }]; # invert the fractional part set e8 [expr {int ( $xf ) }]; # keep the integer part in e8 set xf [expr {1 / ($xf - $e8) }]; # invert the fractional part set e9 [expr {int ( $xf ) }]; # keep the integer part in e9 set xf [expr {1 / ($xf - $e9) }]; # invert the fractional part set e10 [expr {int ( $xf ) }]; # keep the integer part in e10 set xf [expr {1 / ($xf - $e10) }]; # invert the fractional part set e11 [expr {int ( $xf ) }]; # keep the integer part in e11 set xf [expr {1 / ($xf - $e11) }]; # invert the fractional part set e12 [expr {int ( $xf ) }]; # keep the integer part in e12 set xf [expr {1 / ($xf - $e12) }]; # invert the fractional part set e13 [expr {int ( $xf ) }]; # keep the integer part in e13 set xf [expr {1 / ($xf - $e13) }]; # invert the fractional part set e14 [expr {int ( $xf ) }]; # keep the integer part in e14 set xf [expr {1 / ($xf - $e14) }]; # invert the fractional part set e15 [expr {int ( $xf ) }]; # keep the integer part in e15 set xf [expr {1 / ($xf - $e15) }]; # invert the fractional part set e16 [expr {int ( $xf ) }]; # keep the integer part in e16 set xf [expr {1 / ($xf - $e16) }]; # invert the fractional part set e17 [expr {int ( $xf ) }]; # keep the integer part in e17 set xf [expr {1 / ($xf - $e17) }]; # invert the fractional part set e18 [expr {int ( $xf ) }]; # keep the integer part in e18 set xf [expr {1 / ($xf - $e18) }]; # invert the fractional part set e19 [expr {int ( $xf ) }]; # keep the integer part in e19 set xf [expr {1 / ($xf - $e19) }]; # invert the fractional part # golden ratio set g [expr (sqrt(5)+1)/2] set g0 [expr {int ( $g ) }]; # keep the integer part in g0 set xf [expr {1 / ($g - $g0) }]; # invert the fractional part set g1 [expr {int ( $xf ) }]; # keep the integer part in g1 set xf [expr {1 / ($xf - $g1) }]; # invert the fractional part set g2 [expr {int ( $xf ) }]; # keep the integer part in g2 set xf [expr {1 / ($xf - $g2) }]; # invert the fractional part set g3 [expr {int ( $xf ) }]; # keep the integer part in g3 set xf [expr {1 / ($xf - $g3) }]; # invert the fractional part set g4 [expr {int ( $xf ) }]; # keep the integer part in g4 set xf [expr {1 / ($xf - $g4) }]; # invert the fractional part set g5 [expr {int ( $xf ) }]; # keep the integer part in g5 set xf [expr {1 / ($xf - $g5) }]; # invert the fractional part set g6 [expr {int ( $xf ) }]; # keep the integer part in g6 set xf [expr {1 / ($xf - $g6) }]; # invert the fractional part set g7 [expr {int ( $xf ) }]; # keep the integer part in g7 set xf [expr {1 / ($xf - $g7) }]; # invert the fractional part set g8 [expr {int ( $xf ) }]; # keep the integer part in g8 set xf [expr {1 / ($xf - $g8) }]; # invert the fractional part set g9 [expr {int ( $xf ) }]; # keep the integer part in g9 set xf [expr {1 / ($xf - $g9) }]; # invert the fractional part set g10 [expr {int ( $xf ) }]; # keep the integer part in g10 set xf [expr {1 / ($xf - $g10) }]; # invert the fractional part set g11 [expr {int ( $xf ) }]; # keep the integer part in g11 set xf [expr {1 / ($xf - $g11) }]; # invert the fractional part set g12 [expr {int ( $xf ) }]; # keep the integer part in g12 set xf [expr {1 / ($xf - $g12) }]; # invert the fractional part set g13 [expr {int ( $xf ) }]; # keep the integer part in g13 set xf [expr {1 / ($xf - $g13) }]; # invert the fractional part set g14 [expr {int ( $xf ) }]; # keep the integer part in g14 set xf [expr {1 / ($xf - $g14) }]; # invert the fractional part set g15 [expr {int ( $xf ) }]; # keep the integer part in g15 set xf [expr {1 / ($xf - $g15) }]; # invert the fractional part set g16 [expr {int ( $xf ) }]; # keep the integer part in g16 set xf [expr {1 / ($xf - $g16) }]; # invert the fractional part set g17 [expr {int ( $xf ) }]; # keep the integer part in g17 set xf [expr {1 / ($xf - $g17) }]; # invert the fractional part set g18 [expr {int ( $xf ) }]; # keep the integer part in g18 set xf [expr {1 / ($xf - $g18) }]; # invert the fractional part set g19 [expr {int ( $xf ) }]; # keep the integer part in g19 set xf [expr {1 / ($xf - $g19) }]; # invert the fractional part # Square root of 3 set r [expr {sqrt(3)}] set r0 [expr {int ( $r ) }]; # keep the integer part in r0 set xf [expr {1 / ($r - $r0) }]; # invert the fractional part set r1 [expr {int ( $xf ) }]; # keep the integer part in r1 set xf [expr {1 / ($xf - $r1) }]; # invert the fractional part set r2 [expr {int ( $xf ) }]; # keep the integer part in r2 set xf [expr {1 / ($xf - $r2) }]; # invert the fractional part set r3 [expr {int ( $xf ) }]; # keep the integer part in r3 set xf [expr {1 / ($xf - $r3) }]; # invert the fractional part set r4 [expr {int ( $xf ) }]; # keep the integer part in r4 set xf [expr {1 / ($xf - $r4) }]; # invert the fractional part set r5 [expr {int ( $xf ) }]; # keep the integer part in r5 set xf [expr {1 / ($xf - $r5) }]; # invert the fractional part set r6 [expr {int ( $xf ) }]; # keep the integer part in r6 set xf [expr {1 / ($xf - $r6) }]; # invert the fractional part set r7 [expr {int ( $xf ) }]; # keep the integer part in r7 set xf [expr {1 / ($xf - $r7) }]; # invert the fractional part set r8 [expr {int ( $xf ) }]; # keep the integer part in r8 set xf [expr {1 / ($xf - $r8) }]; # invert the fractional part set r9 [expr {int ( $xf ) }]; # keep the integer part in r9 set xf [expr {1 / ($xf - $r9) }]; # invert the fractional part set r10 [expr {int ( $xf ) }]; # keep the integer part in r10 set xf [expr {1 / ($xf - $r10) }]; # invert the fractional part set r11 [expr {int ( $xf ) }]; # keep the integer part in r11 set xf [expr {1 / ($xf - $r11) }]; # invert the fractional part set r12 [expr {int ( $xf ) }]; # keep the integer part in r12 set xf [expr {1 / ($xf - $r12) }]; # invert the fractional part set r13 [expr {int ( $xf ) }]; # keep the integer part in r13 set xf [expr {1 / ($xf - $r13) }]; # invert the fractional part set r14 [expr {int ( $xf ) }]; # keep the integer part in r14 set xf [expr {1 / ($xf - $r14) }]; # invert the fractional part set r15 [expr {int ( $xf ) }]; # keep the integer part in r15 set xf [expr {1 / ($xf - $r15) }]; # invert the fractional part set r16 [expr {int ( $xf ) }]; # keep the integer part in r16 set xf [expr {1 / ($xf - $r16) }]; # invert the fractional part set r17 [expr {int ( $xf ) }]; # keep the integer part in r17 set xf [expr {1 / ($xf - $r17) }]; # invert the fractional part set r18 [expr {int ( $xf ) }]; # keep the integer part in r18 set xf [expr {1 / ($xf - $r18) }]; # invert the fractional part set r19 [expr {int ( $xf ) }]; # keep the integer part in r19 set xf [expr {1 / ($xf - $r19) }]; # invert the fractional part openacs-5.7.0/packages/acs-templating/www/admin/test/chain-frac-2.adp0000644000175000017500000000003307253523117025175 0ustar frankiefrankie openacs-5.7.0/packages/acs-templating/www/admin/test/index.html0000644000175000017500000000131307253523117024354 0ustar frankiefrankie Index of acs-templating/admin/test

    Index of acs-templating/admin/test

    include-0
    if
    chain_frac-0
    chain_frac-1
    chain_frac-2

    Christian Brechbuehler
    Last modified: Tue Oct 10 13:10:31 EDT 2000 openacs-5.7.0/packages/acs-templating/www/admin/test/if.adp0000644000175000017500000002772307253523117023460 0ustar frankiefrankie

    Testcase for recursive include and if

    This pages does two things:

    1. It exercises include recursively, passing changing args.
    2. The result is the test case for if and else, nesting them deeply and exercising all predicates, with and without "not"

    fail '@<%%>x@ nil' should be false fail '@<%%>y@ not nil' should be false fail '@<%%>z@ not nil' should be false fail '@<%%>x@ not defined' should be false fail '@<%%>y@ not defined' should be false fail '@<%%>z@ defined' should be false fail '@<%%>x@ lt 3' should be false fail '"yes" not true' should be false fail '0 true' should be false fail 't false' should be false fail 'oFf not false' should be false fail '@<%%>x@ not true' should be false fail '@<%%>x@ not gt @<%%>v.five@' should be false fail '@<%%>x@ ge 20' should be false fail '@<%%>x@ not le 13' should be false fail '@<%%>v.five@ not eq 5' should be false fail '@<%%>x@ eq 5' should be false fail '@<%%>x@ odd' should be false fail '@<%%>x@ not even' should be false fail '@<%%>v.rownum@ not odd' should be false fail '@<%%>v.five@ even' should be false fail '@<%%>x@ in fo {ob 10} ar' should be false fail '@<%%>x@ not in fie 6 10 28' should be false fail '@<%%>v.five@ not between 3 30' should be false fail '@<%%>v.five@ between 30 300' should be false fail '@<%%>x@ not ne @<%%>v.five@ or 8 le @<%%>v.five@ or @<%%>x@ not defined' should be false fail '@<%%>x@ not ne 10 and 6 eq @<%%>v.five@' should be false pass the test. fail '@<%%>x@ ne 10 or 6 not eq @<%%>v.five@' should be true fail '@<%%>x@ ne @<%%>v.five@ and 8 not le @<%%>v.five@ and @<%%>x@ defined' should be true fail '@<%%>v.five@ not between 30 300' should be true fail '@<%%>v.five@ between 3 30' should be true fail '@<%%>x@ in fie 6 10 28' should be true fail '@<%%>x@ not in fo {ob 10} ar' should be true fail '@<%%>v.five@ not even' should be true fail '@<%%>v.rownum@ odd' should be true fail '@<%%>x@ even' should be true fail '@<%%>x@ not odd' should be true fail '@<%%>x@ not eq 5' should be true fail '@<%%>v.five@ eq 5' should be true fail '@<%%>x@ le 13' should be true fail '@<%%>x@ not ge 20' should be true fail '@<%%>x@ gt @<%%>v.five@' should be true fail '@<%%>x@ true' should be true fail 'oFf false' should be true fail 't not false' should be true fail '0 not true' should be true fail '"yes" true' should be true fail '@<%%>x@ not lt 3' should be true fail '@<%%>z@ not defined' should be true fail '@<%%>y@ defined' should be true fail '@<%%>x@ defined' should be true fail '@<%%>z@ nil' should be true fail '@<%%>y@ nil' should be true fail '@<%%>x@ not nil' should be true

    openacs-5.7.0/packages/acs-templating/www/admin/test/if.tcl0000644000175000017500000000041607253523117023464 0ustar frankiefrankiead_page_contract { test the tag } -properties { x:onevalue y:onevalue } -query { {x:integer 10} {y ""} {z:optional} } # manually construct a multirow datasource v set v:rowcount 1 set v:1(rownum) 1 set v:1(five) 5 # don't define z ad_return_template openacs-5.7.0/packages/acs-templating/www/admin/test/include.adp0000644000175000017500000000060707663155640024504 0ustar frankiefrankie@indent@ pass the test.@indent@@lt@if @true_condition@> @indent@ @lt@if @false_condition@> @indent@ fail '@false_label@' should be false @indent@ @lt@/if>@lt@else> @indent;noquote@ @lt;noquote@/else> @indent@@lt@/if>@lt@else> @indent@ fail '@true_label@' should be true @indent@@lt@/else> openacs-5.7.0/packages/acs-templating/www/admin/test/include.tcl0000644000175000017500000000114210551254405024502 0ustar frankiefrankieif {[llength $l]} { set car [lindex $l 0] set cdr [lrange $l 1 end] regsub -all {%([a-zA-Z0-9.:_]+)%} $car {@\1@} condition foreach {name rules} { true {"TRUE " "" FALSE not } false { TRUE not "FALSE " "" and %AND% or and %AND% or} } { # note that this cannot correctly reverse and/or mixes (no grouping) set ${name}_condition $condition foreach {from to} $rules { regsub -all $from [set ${name}_condition] $to ${name}_condition } regsub -all \ {@([^@ ]+@)} [set ${name}_condition] {@<%%>\1} ${name}_label } set lt "<" } openacs-5.7.0/packages/acs-templating/www/admin/index.html0000644000175000017500000000071407253523117023401 0ustar frankiefrankie Index of acs-templating/admin

    Index of acs-templating/admin

    test

    Christian Brechbühler
    Last modified: Tue Oct 10 13:08:14 EDT 2000 openacs-5.7.0/packages/acs-templating/www/scripts/0000755000175000017500000000000011575225762022010 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/scripts/xinha/0000755000175000017500000000000011575225762023117 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/scripts/xinha/insert-file-orig.adp0000644000175000017500000002116410471407067026762 0ustar frankiefrankie #acs-templating.HTMLArea_InsertImageTitle#
    #acs-templating.HTMLArea_InsertImageTitle#
    #acs-templating.HTMLArea_ImageURL#
    #acs-templating.HTMLArea_ImageAlternateText#
    @HTML_Preview@
    @HTML_UploadTitle@
    @formerror.upload_file@

    Layout
    #acs-templating.HTMLArea_ImageAlignment#
    #acs-templating.HTMLArea_ImageBorderSize#
    #acs-templating.HTMLArea_ImageSpacing#
    #acs-templating.HTMLArea_ImageSpacingHorizontal#
    #acs-templating.HTMLArea_ImageSpacingVertical#
    Image Preview:

    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/Makefile0000644000175000017500000000050410471407067024550 0ustar frankiefrankieFILES = *.adp *.tcl blank.html SOURCE = /usr/local/openacs-4/packages/acs-templating/www/resources/xinha-nightly/plugins/OacsFs/popups/ unlink: rm -f ${FILES} cp -p ${SOURCE}/*.html . cp -p ${SOURCE}/*.adp . cp -p ${SOURCE}/*.tcl . link: ln -sf ${SOURCE}/*.html . ln -sf ${SOURCE}/*.adp . ln -sf ${SOURCE}/*.tcl . openacs-5.7.0/packages/acs-templating/www/scripts/xinha/attach-image.adp0000644000175000017500000000562611202044112026111 0ustar frankiefrankie
    #acs-templating.Choose_Image#
     
    #acs-templating.Upload_a_New_Image#
    @formerror.upload_file@

    #acs-templating.This_image_can_be_reused_by#
    @formgroup.widget;noquote@ @formgroup.label@
    [i] #acs-templating.This_image_can_be_reused_help#
    @formerror.share@

     
    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/attach-image.tcl0000644000175000017500000003235411202044112026125 0ustar frankiefrankiead_page_contract { Simple image upload, attach image to object_id passed in, if no object_id, use the current package_id @author Guenter Ernst guenter.ernst@wu-wien.ac.at, @author Gustaf Neumann neumann@wu-wien.ac.at @author Dave Bauer (dave@solutiongrove.com) @creation-date 13.07.2004 @cvs-id $Id: attach-image.tcl,v 1.11 2009/05/11 15:46:18 daveb Exp $ } { {parent_id:integer,optional} {package_id ""} {selector_type "image"} } set f_url "" set user_id [auth::require_login] # if user has write permission, create image upload form, if {![info exists parent_id]} { set parent_id $user_id set write_p 1 } else { set write_p [permission::permission_p \ -party_id $user_id \ -object_id $parent_id \ -privilege "write"] } if {!$write_p} { # if parent_id does not exist yet, let's use the pacakage_id if { ![db_0or1row "check_parent" "select object_id from acs_objects where object_id=:parent_id"] } { set parent_id $package_id } # item might not exist! set write_p [permission::permission_p \ -party_id $user_id \ -object_id $package_id \ -privilege "write"] } set recent_images_options [list] if {$write_p} { # set recent images # db_multirow -unclobber recent_images recent_images \ # { # select ci.item_id, ci.name # from cr_items ci, cr_revisionsx cr, cr_child_rels ccr # where ci.live_revision=cr.revision_id # and ci.content_type='image' # and cr.creation_user=:user_id # and ccr.parent_id=ci.item_id # and ccr.relation_tag='image-thumbnail' # order by creation_date desc # limit 6 # } { # set name [regsub "${item_id}_" $name ""] # lappend recent_images_options [list $name $item_id] # } set share_options [list [list "[_ acs-templating.Only_myself]" private] [list "[_ acs-templating.This_Group]" group] [list "[_ acs-templating.Anyone_on_this_system]" site] [list "[_ acs-templating.Anyone_on_the_internet]" public]] ad_form \ -name upload_form \ -mode edit \ -export {selector_type file_types parent_id} \ -html { enctype multipart/form-data } \ -form { item_id:key {package_id:text(hidden),optional} {choose_file:text(radio),optional {options $recent_images_options}} {upload_file:file(file),optional {html {size 30}} } {share:text(radio),optional {label "[_ acs-templating.This_image_can_be_reused_by]"} {options $share_options} {help_text "[_ acs-templating.This_image_can_be_reused_help]"}} {select_btn:text(submit) {label "[_ acs-templating.Add_the_selected_image]"}} {upload_btn:text(submit) {label "[_ acs-templating.HTMLArea_SelectUploadBtn]"} } } \ -on_request { set share site set package_id $package_id } \ -on_submit { # check file name if {$choose_file eq "" && $upload_file eq ""} { template::form::set_error upload_form upload_file \ [_ acs-templating.HTMLArea_SpecifyUploadFilename] break } if {$upload_file ne "" } { if {[info exists folder_size]} { # check per folder quota set maximum_folder_size [parameter::get -parameter "MaximumFolderSize"] if { $maximum_folder_size ne "" } { if { $folder_size+[file size ${upload_file.tmpfile}] > $maximum_folder_size } { template::form::set_error upload_form upload_file \ [_ file-storage.out_of_space] break } } } set file_name [template::util::file::get_property filename $upload_file] set upload_tmpfile [template::util::file::get_property tmp_filename $upload_file] set mime_type [template::util::file::get_property mime_type $upload_file] if {$mime_type eq ""} { set mime_type [ns_guesstype $file_name] } if {![string match "image/*" $mime_type]} { template::form::set_error upload_form upload_file \ [_ acs-templating.HTMLArea_SelectImageUploadNoImage] break } image::new \ -item_id $item_id \ -name ${item_id}_$file_name \ -parent_id $parent_id \ -tmp_filename $upload_tmpfile \ -creation_user $user_id \ -creation_ip [ad_conn peeraddr] \ -package_id [ad_conn package_id] \ -mime_type $mime_type # create thumbnail image::resize -item_id $item_id file delete $upload_tmpfile permission::grant \ -object_id $item_id \ -party_id $user_id \ -privilege admin switch -- $share { private { permission::set_not_inherit -object_id $item_id set f_url "/image/${item_id}/private/${parent_id}/${file_name}" } group { # Find the closest application group # either dotlrn or acs-subsite permission::grant \ -party_id [acs_magic_object "registered_users"] \ -object_id $item_id \ -privilege "read" } public { permission::grant \ -party_id [acs_magic_object "the_public"] \ -object_id $item_id \ -privilege "read" } site - default { permission::grant \ -party_id [acs_magic_object "registered_users"] \ -object_id $item_id \ -privilege "read" } } } else { # user chose an existing file set item_id $choose_file set file_name [lindex [lindex $recent_images_options [util_search_list_of_lists $recent_images_options $item_id 1]] 0] } set f_url "/image/${item_id}/${file_name}" } } else { set write_p 0 } # default to xinha but tinymce will work too. no plugins for rte set richtextEditor [parameter::get \ -package_id [ad_conn package_id] \ -parameter "RichTextEditor" \ -default "xinha"] set HTML_Preview "Preview" set HTML_UploadTitle "" ################################################################################ set ajaxhelper_p [apm_package_installed_p ajaxhelper] if {$ajaxhelper_p} { ah::requires -sources "prototype,scriptaculous" } if {$richtextEditor eq "xinha"} { template::head::add_javascript \ -order "Z0" \ -src "/resources/acs-templating/xinha-nightly/popups/popup.js" template::head::add_javascript \ -order "Z1" \ -script " var selector_window; // window.resizeTo(415, 300); function Init() { __dlg_init(); var param = window.dialogArguments; if (param) { document.getElementById('f_url').value = param\['f_url'\]; document.getElementById('f_alt').value = param\['f_alt'\]; document.getElementById('f_border').value = param\['f_border'\]; document.getElementById('f_align').value = param\['f_align'\]; document.getElementById('f_vert').value = param\['f_vert'\]; document.getElementById('f_horiz').value = param\['f_horiz'\]; window.ipreview.location.replace(param.f_url); } // document.getElementById('f_url').focus(); var f_url = document.getElementById('f_url'); var url = f_url.value; if (url) { onOK(); __dlg_close(null); } }; function onOK() { var required = { 'f_url': '#acs-templating.HTMLArea_NoURL#' }; for (var i in required) { var el = document.getElementById(i); if (!el.value) { alert(required\[i\]); el.focus(); return false; } } // pass data back to the calling window var param = new Object(); /* var fields = \['f_url'\]; for (var i in fields) { var id = fields\[i\]; var el = document.getElementById(id); param\[id\] = el.value; } */ param\['f_url'\] = document.getElementById('f_url').value; if (selector_window) { selector_window.close(); } __dlg_close(param); return false; }; function onCancel() { if (selector_window) { selector_window.close(); } __dlg_close(null); return false; }; function onPreview() { var f_url = document.getElementById('f_url'); var url = f_url.value; if (!url) { alert('You have to enter an URL first'); f_url.focus(); return false; } if (document.getElementById('preview_div').style.display == 'none') { document.getElementById('showpreview').click(); } window.ipreview.location.replace(url); return false; }; function resizeWindow(formname) { var w, h; if (formname == 'url') { w = 415; h = 330; } if (formname == 'upload') { w = 415; h = 310; } if (document.getElementById('showpreview').checked == true) { h = h + 200; } window.resizeTo(w, h); } function togglePreview() { var w = window.clientWidth; var h = window.clientHeight; if (document.getElementById('preview_div').style.display == 'none') { document.getElementById('preview_div').style.display=''; } else { document.getElementById('preview_div').style.display='none'; } if (document.getElementById('insert_image_url').style.display == 'none') { resizeWindow('upload'); } else { resizeWindow('url'); } } " } if {$richtextEditor eq "tinymce"} { template::head::add_javascript \ -order "Z1" \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/tiny_mce_popup.js" template::head::add_javascript \ -order "Z2" \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/plugins/oacsimage/js/image.js" template::head::add_style \ -style " html, body { background: ButtonFace; color: ButtonText; font: 11px Tahoma,Verdana,sans-serif; margin: 0px; padding: 0px; } body { padding: 5px; } table { font: 11px Tahoma,Verdana,sans-serif; } form p { margin-top: 5px; margin-bottom: 5px; } .fl { width: 9em; float: left; padding: 2px 5px; text-align: right; } .fr { width: 6em; float: left; padding: 2px 5px; text-align: right; } fieldset { padding: 0px 10px 5px 5px; } select, input, button { font: 11px Tahoma,Verdana,sans-serif; } .space { padding: 2px; } .title { background: #ddf; color: #000; font-weight: bold; font-size: 120%; padding: 3px 10px; margin-bottom: 10px; border-bottom: 1px solid black; letter-spacing: 2px; } form { padding: 0px; margin: 0px; } .form-error { color : red} #html-carousel { background: #f5f4e4; } #html-carousel .carousel-list li { margin:4px 0px 0px 0px; } #html-carousel .carousel-list li { width: 106px; border: 0px solid green; padding: 2px; padding-top: 15px; margin: 0; color: #3F3F3F; } #html-carousel .carousel-list li img { border:1px solid #999; display:block; width:100px; } #html-carousel { margin-bottom: 10px; float: left; width: 330px;; height: 155px; } /* BUTTONS */ #prev-arrow-container, #next-arrow-container { float:left; margin: 1px; padding: 0px; } #next-arrow { cursor:pointer; float:right; } #prev-arrow { cursor:pointer; } /* Overlay */ #overlay { width: 200px; height: 80px; background-color: #FFF; position: absolute; top: 25px; left: 80px; padding-top: 10px; z-index: 100; color: #000; border:1px dotted #000; text-align: center; font-size: 24px; filter:alpha(opacity=80); -moz-opacity: 0.8; opacity: 0.8; } " if {$ajaxhelper_p} { template::head::add_css \ -href "/resources/ajaxhelper/carousel/carousel.css" template::head::add_javascript \ -order "Z4" \ -src "/resources/ajaxhelper/carousel/carousel.js" template::head::add_javascript \ -order "Z5" \ -script " var carousel; var buttonStateHandler = function (button, enabled) { if (button == 'prev-arrow') { \$('prev-arrow').src = enabled ? '/resources/ajaxhelper/carousel/left-enabled.gif' : '/resources/ajaxhelper/carousel/left-disabled.gif' } else { \$('next-arrow').src = enabled ? '/resources/ajaxhelper/carousel/right-enabled.gif' : '/resources/ajaxhelper/carousel/right-disabled.gif' } } var ajaxHandler = function (carousel, status) { var overlay = \$('overlay'); if (status == 'before') { if (overlay) { overlay.setOpacity(0); overlay.show(); Effect.Fade(overlay, {from: 0, to: 0.8, duration: 0.2}) } else { new Insertion.Top('html-carousel', \"

    Loading...
    \"); } } else { Effect.Fade(overlay, {from: 0.8, to: 0.0, duration: 0.2}) } } function initCarousel_html_carousel() { carousel = new Carousel('html-carousel', {ajaxHandler:ajaxHandler, animParameters:{duration:0.5}, buttonStateHandler:buttonStateHandler, nextElementID:'next-arrow', prevElementID:'prev-arrow', url:'/ajax/xmlhttp/carousel-images'}) } " } template::head::add_javascript \ -order "Z3" \ -script " function attachImageInit() { var param = window.dialogArguments; var f_url = document.getElementById('f_url'); var url = f_url.value; if (url) { ImageDialog.insertAndClose(); } else { if (${ajaxhelper_p}) { initCarousel_html_carousel(); } tinyMCEPopup.executeOnLoad('init();'); } } function onCancel() { tinyMCEPopup.close(); } " template::add_body_handler \ -event onload \ -script "attachImageInit()" } openacs-5.7.0/packages/acs-templating/www/scripts/xinha/attach-file.adp0000644000175000017500000000564011202041207025744 0ustar frankiefrankie #acs-templating.HTMLArea_InsertLink#
    #acs-templating.Title#
    @formerror.f_title@
    You can link to the above text to a file. Select one of the options below.

    #acs-templating.Choose_File#
    @formgroup.widget;noquote@
    @formerror.choose_file@

     
    #acs-templating.Upload_a_New_File#
    @formerror.upload_file@

    #acs-templating.This_file_can_be_reused_by#
    @formgroup.widget;noquote@ @formgroup.label@
    [i] #acs-templating.This_file_can_be_reused_help#
    @formerror.share@
     
    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/attach-file.tcl0000644000175000017500000002775611267425062026016 0ustar frankiefrankiead_page_contract { Simple file upload, attach image to object_id passed in, if no object_id, use the current package_id @author Guenter Ernst guenter.ernst@wu-wien.ac.at, @author Gustaf Neumann neumann@wu-wien.ac.at @author Dave Bauer (dave@solutiongrove.com) @creation-date 13.07.2004 @cvs-id $Id: attach-file.tcl,v 1.17 2009/10/20 21:22:58 daveb Exp $ } { {parent_id:integer,optional} {package_id ""} {selector_type "file"} {f_href ""} } #HAM : ajax sources #ah::requires -sources "prototype,scriptaculous" set f_url "" set user_id [auth::require_login] # if user has write permission, create image upload form, if {![info exists parent_id] || $parent_id eq ""} { set parent_id $user_id set write_p 1 } else { set write_p [permission::permission_p \ -party_id $user_id \ -object_id $parent_id \ -privilege "write"] } if {!$write_p} { # if parent_id does not exist yet, let's use the pacakage_id if { ![db_0or1row "check_parent" "select object_id from acs_objects where object_id=:parent_id"] } { set parent_id $package_id } # item might not exist! set write_p [permission::permission_p \ -party_id $user_id \ -object_id $package_id \ -privilege "write"] } if {$write_p} { # set recent files set recent_files_options [list] db_multirow -extend {mime_icon} -unclobber recent_files recent_files \ { select ci.item_id, ci.name, cr.mime_type from cr_items ci, cr_revisionsx cr where ci.live_revision=cr.revision_id and ci.content_type='content_revision' and storage_type='file' and cr.creation_user=:user_id and cr.mime_type is not null order by creation_date desc limit 6 } { set mime_icon "/resources/acs-templating/mimetypes/gnome-mime-[string map {/ -} $mime_type].png" set name [regsub "${item_id}_" $name ""] set name " $name" lappend recent_files_options [list $name $item_id] } # ns_log notice "HAM : recent_files_options : $recent_files_options ********************" set share_options [list [list "[_ acs-templating.Only_myself]" private] [list "[_ acs-templating.This_Group]" group] [list "[_ acs-templating.Anyone_on_this_system]" site] [list "[_ acs-templating.Anyone_on_the_internet]" public]] ad_form \ -name upload_form \ -mode edit \ -export {selector_type file_types parent_id} \ -html { enctype multipart/form-data } \ -form { item_id:key {package_id:text(hidden),optional} {f_href:text(hidden),optional {html {id f_href}}} {f_title:text,optional {label "[_ acs-templating.Link_Title]"} {html {size 50 id f_title} } } {f_url:url,optional {label "[_ acs-templating.Link_Url]"} {html {size 50 id f_url } } } {url_ok_btn:text(submit) {label "[_ acs-templating.Link_Url_Btn]"} } {choose_file:text(radio),optional {options $recent_files_options}} {upload_file:file(file),optional {html {size 30}} } {share:text(radio),optional {label "[_ acs-templating.This_file_can_be_reused_by]"} {options $share_options} {help_text "[_ acs-templating.This_file_can_be_reused_help]"}} {select_btn:text(submit) {label "[_ acs-templating.Add_the_selected_file]"}} {ok_btn:text(submit) {label "[_ acs-templating.HTMLArea_SelectUploadBtn]"} } } \ -on_request { set share site if {$f_href ne ""} { set f_url $f_href } } \ -on_submit { if {$f_href eq ""} { set f_href $f_url element set_value upload_form f_href $f_href } # ensure that Link Title is specified if { ![exists_and_not_null f_title] && [exists_and_not_null url_ok_btn] } { template::form::set_error upload_form f_title "Specify a [_ acs-templating.Link_Title]" } set error_p 0 # check file name if { [info exists f_url] && $f_url eq "" && $url_ok_btn ne ""} { template::form::set_error upload_form f_url "Specify a [_ acs-templating.Link_Url]" set error_p 1 } if {[info exists ok_btn] && $ok_btn ne "" && $upload_file eq ""} { template::form::set_error upload_form upload_file \ [_ acs-templating.HTMLArea_SpecifyUploadFilename] set error_p 1 } if {[info exists select_btn] && $select_btn ne "" && $choose_file eq ""} { template::form::set_error upload_form choose_file \ [_ acs-templating.Attach_File_Choose_a_file] set error_p 1 } set share site # set f_title "" # set f_href "" if { !$error_p } { if {$upload_file ne ""} { if {[info exists folder_size]} { # check per folder quota set maximum_folder_size [parameter::get -parameter "MaximumFolderSize"] if { $maximum_folder_size ne "" } { if { $folder_size+[file size ${upload_file.tmpfile}] > $maximum_folder_size } { template::form::set_error upload_form upload_file \ [_ file-storage.out_of_space] break } } } set file_name [template::util::file::get_property filename $upload_file] set upload_tmpfile [template::util::file::get_property tmp_filename $upload_file] set mime_type [template::util::file::get_property mime_type $upload_file] if {$mime_type eq ""} { set mime_type [ns_guesstype $file_name] } if {[string match "image/*" $mime_type]} { image::new \ -item_id $item_id \ -name ${item_id}_$file_name \ -parent_id $parent_id \ -title $f_title \ -tmp_filename $upload_tmpfile \ -creation_user $user_id \ -creation_ip [ad_conn peeraddr] \ -package_id [ad_conn package_id] } else { content::item::new \ -item_id $item_id \ -name ${item_id}_$file_name \ -title $f_title \ -parent_id $parent_id \ -tmp_filename $upload_tmpfile \ -creation_user $user_id \ -creation_ip [ad_conn peeraddr] \ -package_id [ad_conn package_id] \ -mime_type $mime_type } file delete $upload_tmpfile permission::grant \ -object_id $item_id \ -party_id $user_id \ -privilege admin switch -- $share { private { permission::set_not_inherit -object_id $item_id } group { # Find the closest application group # either dotlrn or acs-subsite permission::grant \ -party_id [acs_magic_object "registered_users"] \ -object_id $item_id \ -privilege "read" } public { permission::grant \ -party_id [acs_magic_object "the_public"] \ -object_id $item_id \ -privilege "read" } site - default { permission::grant \ -party_id [acs_magic_object "registered_users"] \ -object_id $item_id \ -privilege "read" } } } else { if {$choose_file ne ""} { set item_id $choose_file set file_name [lindex [lindex $recent_files_options [util_search_list_of_lists $recent_files_options $item_id 1]] 0] # we have to get rid of the icon from the form. set file_name [regsub -all {<.*?>} $file_name {}] } } set file_name [string trim $file_name] if {$f_title eq "" && [info exists file_name]} { set f_title $file_name } if {$share eq "private" && [string match "image/*" $mime_type]} { # need a private URL that allows viewers of this # object to see the image # this isn't totally secure, because of course # you need to be able to see the image somehow # but we only allow read on the image if you can # see the parent object set f_href "/image/${item_id}/private/${parent_id}/${file_name}" } else { if { [exists_and_not_null f_url] && $url_ok_btn ne "" } { set f_href $f_url } else { set f_href "/file/${item_id}/${file_name}" } } element set_value upload_form f_href $f_href element set_value upload_form f_title $f_title } } } else { set write_p 0 } # default to xinha but tinymce will work too. no plugins for rte set richtextEditor [parameter::get \ -package_id $package_id \ -parameter "RichTextEditor" \ -default "xinha"] set HTML_UploadTitle "" if {$richtextEditor eq "xinha"} { template::head::add_javascript \ -src "/resources/acs-templating/xinha-nightly/popups/popup.js" template::head::add_javascript \ -script " var selector_window; // window.resizeTo(450, 300); function attachFileInit() { __dlg_init(); var f_href = document.getElementById('f_href'); var url = f_href.value; if (url) { onOK(); __dlg_close(null); } var param = window.dialogArguments; if (param) { if ( typeof param\['f_href'\] != 'undefined' ) { document.getElementById('f_href').value = param\['f_href'\]; document.getElementById('f_url').value = param\['f_href'\]; document.getElementById('f_title').value = param\['f_title'\]; } } }; function onOK() { var required = { 'f_href': '#acs-templating.HTMLArea_NoURL#' }; for (var i in required) { var el = document.getElementById(i); if (!el.value) { alert(required\[i\]); el.focus(); return false; } } // pass data back to the calling window var fields = \['f_href','f_title', 'f_target'\]; var param = new Object(); for (var i in fields) { var id = fields\[i\]; var el = document.getElementById(id); param\[id\] = el.value; } __dlg_close(param); return false; }; function onCancel() { if (selector_window) { selector_window.close(); } __dlg_close(null); return false; }; " } if {$richtextEditor eq "tinymce"} { template::head::add_javascript \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/tiny_mce_popup.js" \ -order "Z1" template::head::add_javascript \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/utils/mctabs.js" \ -order "Z2" template::head::add_javascript \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/utils/form_utils.js" \ -order "Z3" template::head::add_javascript \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/utils/validate.js" \ -order "Z4" template::head::add_javascript \ -src "/resources/acs-templating/tinymce/jscripts/tiny_mce/plugins/oacslink/js/link.js" \ -order "Z5" template::head::add_javascript \ -order "Z6" \ -script " function attachFileInit() { var param = window.dialogArguments; // document.getElementById('f_href').focus(); var f_href = document.getElementById('f_href'); var url = f_href.value; if (url !='') { insertAction(); } tinyMCEPopup.executeOnLoad('init();'); } function onCancel() { tinyMCEPopup.close(); } " template::head::add_style \ -style " html, body { background: ButtonFace; color: ButtonText; font: 11px Tahoma,Verdana,sans-serif; margin: 0px; padding: 0px; } body { padding: 5px; } table { font: 11px Tahoma,Verdana,sans-serif; } form p { margin-top: 5px; margin-bottom: 5px; } .fl { width: 9em; float: left; padding: 2px 5px; text-align: right; } .fr { width: 6em; float: left; padding: 2px 5px; text-align: right; } fieldset { padding: 0px 10px 5px 5px; } select, input, button { font: 11px Tahoma,Verdana,sans-serif; } .space { padding: 2px; } .title { background: #ddf; color: #000; font-weight: bold; font-size: 120%; padding: 3px 10px; margin-bottom: 10px; border-bottom: 1px solid black; letter-spacing: 2px; } form { padding: 0px; margin: 0px; } .form-error { color : red} " } template::add_body_handler \ -event onload \ -script "attachFileInit()" openacs-5.7.0/packages/acs-templating/www/scripts/xinha/insert-ilink.adp0000644000175000017500000001434310471407067026214 0ustar frankiefrankie #acs-templating.HTMLArea_InsertModifyLink#
    #acs-templating.HTMLArea_InsertModifyLink#
    URL:
    Title (tooltip):
    Target: #acs-templating.HTMLArea_OpenFileStorage#
     
    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/insert-ilink.tcl0000644000175000017500000000116710471407067026232 0ustar frankiefrankiead_page_contract { @author Guenter Ernst guenter.ernst@wu-wien.ac.at, @author Gustaf Neumann neumann@wu-wien.ac.at @creation-date 13.07.2004 @cvs-id $Id: insert-ilink.tcl,v 1.1 2006/08/18 19:00:07 daveb Exp $ } { {fs_package_id:integer,optional} {folder_id:integer,optional} {file_types *} } set selector_type "file" set file_selector_link [export_vars -base file-selector \ {fs_package_id folder_id selector_type file_types}] set fs_found 1 #set user_id [ad_verify_and_get_user_id] #permission::require_permission -party_id $user_id -object_id $fs_package_id \ # -privilege "admin" ad_return_template openacs-5.7.0/packages/acs-templating/www/scripts/xinha/insert_image.html0000644000175000017500000001125010471407067026444 0ustar frankiefrankie Insert Image
    Insert Image
    Image URL:
    Alternate text:

    Layout
    Alignment:

    Border thickness:
    Spacing
    Horizontal:

    Vertical:

    Image Preview:

    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/insert-image.adp0000644000175000017500000001741310471407067026171 0ustar frankiefrankie #acs-templating.HTMLArea_InsertImageTitle#
    #acs-templating.HTMLArea_InsertImageTitle#
    #acs-templating.HTMLArea_ImageURL#
    #acs-templating.HTMLArea_ImageAlternateText#
    #acs-templating.HTMLArea_OpenFileStorage#

    Layout
    #acs-templating.HTMLArea_ImageAlignment#
    #acs-templating.HTMLArea_ImageBorderSize#
    #acs-templating.HTMLArea_ImageSpacing#
    #acs-templating.HTMLArea_ImageSpacingHorizontal#
    #acs-templating.HTMLArea_ImageSpacingVertical#
    Image Preview:

    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/insert-image.tcl0000644000175000017500000000066710471407067026212 0ustar frankiefrankiead_page_contract { @author Guenter Ernst guenter.ernst@wu-wien.ac.at, @author Gustaf Neumann neumann@wu-wien.ac.at @creation-date 13.07.2004 @cvs-id $Id: insert-image.tcl,v 1.1 2006/08/18 19:00:07 daveb Exp $ } { {fs_package_id:integer,optional} {folder_id:integer,optional} } set selector_type "image" set file_selector_link [export_vars -base file-selector \ {fs_package_id folder_id selector_type}] set fs_found 1 openacs-5.7.0/packages/acs-templating/www/scripts/xinha/file-selector.adp0000644000175000017500000001211210471407067026331 0ustar frankiefrankie @HTML_Title@
    @HTML_Title@
    @HTML_Context@
    @HTML_Legend@
    @folder_name@
    @HTML_Preview@
    @HTML_UploadTitle@
    @formerror.upload_file@
    openacs-5.7.0/packages/acs-templating/www/scripts/xinha/file-selector.tcl0000644000175000017500000002243511126243276026356 0ustar frankiefrankiead_page_contract { @author Guenter Ernst guenter.ernst@wu-wien.ac.at @author Gustaf Neumann neumann@wu-wien.ac.at @creation-date 13.10.2005 @cvs-id $Id: file-selector.tcl,v 1.2 2008/12/29 21:53:02 gustafn Exp $ } { {fs_package_id:integer,notnull,optional} {folder_id:integer,optional} {orderby:optional} {selector_type "image"} {file_types "*"} } if {![info exists fs_package_id]} { # we have not filestore package_id. This must be the first call. if {[info exists folder_id]} { # get package_id from folder_id foreach {fs_package_id root_folder_id} \ [fs::get_folder_package_and_root $folder_id] break } else { # get package_id from package name set key file-storage set id [apm_version_id_from_package_key $key] set mount_url [site_node::get_children -all -package_key $key -node_id $id] array set site_node [site_node::get -url $mount_url] set fs_package_id $site_node(package_id) } } if {![info exists folder_id]} { set folder_id [fs_get_root_folder -package_id $fs_package_id] set root_folder_id $folder_id } if {![fs_folder_p $folder_id]} { ad_complain [_ file-storage.lt_The_specified_folder__1] return } # now we have at least a valid folder_id and a valid fs_package_id if {![info exists root_folder_id]} { set root_folder_id [fs_get_root_folder -package_id $fs_package_id] } set fs_url [site_node::get_url_from_object_id -object_id $fs_package_id] # # Don't allow delete if root folder set root_folder_p [expr {$folder_id == $root_folder_id}] set user_id [ad_conn user_id] permission::require_permission \ -party_id $user_id -object_id $folder_id \ -privilege "read" set up_url {} if { !$root_folder_p} { set parent_folder_id [fs::get_parent -item_id $folder_id] set up_name [fs::get_object_name -object_id $parent_folder_id] set up_url [export_vars -base file-selector \ {fs_package_id {folder_id $parent_folder_id} selector_type file_types}] } # if user has write permission, create image upload form, if {[permission::permission_p -party_id $user_id -object_id $folder_id \ -privilege "write"]} { set write_p 1 ad_form \ -name upload_form \ -mode edit \ -export {fs_package_id folder_id orderby selector_type file_types} \ -html { enctype multipart/form-data } \ -form { {upload_file:file(file) {html {size 30}} } {ok_btn:text(submit) {label "[_ acs-templating.HTMLArea_SelectUploadBtn]"} } } \ -on_submit { # check file name if {$upload_file eq ""} { template::form::set_error upload_form upload_file \ [_ acs-templating.HTMLArea_SpecifyUploadFilename] break } # check quota set maximum_folder_size [parameter::get -parameter "MaximumFolderSize"] if { $maximum_folder_size ne "" } { if { $folder_size+[file size ${upload_file.tmpfile}] > $maximum_folder_size } { template::form::set_error upload_form upload_file \ [_ file-storage.out_of_space] break } } set file_name [template::util::file::get_property filename $upload_file] set upload_tmpfile [template::util::file::get_property tmp_filename $upload_file] set mime_type [template::util::file::get_property mime_type $upload_file] if {$selector_type eq "image" && ![string match "image/*" $mime_type]} { template::form::set_error upload_form upload_file \ [_ acs-templating.HTMLArea_SelectImageUploadNoImage] break } set existing_file_id [fs::get_item_id -name $file_name -folder_id $folder_id] if {$existing_file_id ne ""} { # write new revision fs::add_file \ -name $file_name \ -item_id $existing_file_id \ -parent_id $folder_id \ -tmp_filename $upload_tmpfile \ -creation_user $user_id \ -creation_ip [ad_conn peeraddr] \ -package_id $fs_package_id } else { # write file fs::add_file \ -name $file_name \ -parent_id $folder_id \ -tmp_filename $upload_tmpfile \ -creation_user $user_id \ -creation_ip [ad_conn peeraddr] \ -package_id $fs_package_id } } } else { set write_p 0 } # display the contents set folder_name [lang::util::localize [fs::get_object_name -object_id $folder_id]] set content_size_total 0 set folder_path [db_exec_plsql get_folder_path { select content_item__get_path(:folder_id, :root_folder_id) }] # -pass_to_urls {c} template::list::create \ -name contents \ -multirow contents \ -pass_properties {fs_package_id selector_type folder_id} \ -key object_id \ -html {width 100%}\ -filters {folder_id {} file_types {} selector_type {} fs_package_id {}} \ -elements { name { label "[_ file-storage.Name]" display_template { #file-storage.@contents.type@# onclick="selectImage('@contents.object_id@','@contents.file_url@','@contents.type@');return false;">@contents.name@ } orderby_desc {name desc} orderby_asc {name asc} html {nowrap ""} } content_size_pretty { label "[_ file-storage.Size]" orderby_desc {content_size desc} orderby_asc {content_size asc} } type { label "[_ file-storage.Type]" orderby_desc {type desc} orderby_asc {type asc} } last_modified_pretty { label "[_ file-storage.Last_Modified]" orderby_desc {last_modified_ansi desc} orderby_asc {last_modified_ansi asc} html {nowrap ""} } } set order_by_clause [expr {[exists_and_not_null orderby] ? [template::list::orderby_clause -orderby -name contents] : " order by fs_objects.sort_key, fs_objects.name asc"}] if {$selector_type eq "image"} { set file_types "image/%" } set filter_clause [expr {$file_types eq "*" ? "" : "and (type like '$file_types' or type = 'folder')" }] set fs_sql "select object_id, name, live_revision, type, title, to_char(last_modified, 'YYYY-MM-DD HH24:MI:SS') as last_modified_ansi, content_size, url, sort_key, file_upload_name, case when :folder_path is null then fs_objects.name else :folder_path || '/' || name end as file_url, case when last_modified >= (now() - cast('99999' as interval)) then 1 else 0 end as new_p from fs_objects where parent_id = :folder_id and exists (select 1 from acs_object_party_privilege_map m where m.object_id = fs_objects.object_id and m.party_id = :user_id and m.privilege = 'read') $filter_clause $order_by_clause" db_multirow -extend { icon last_modified_pretty content_size_pretty properties_link properties_url folder_p title } contents get_fs_contents $fs_sql { set last_modified_ansi [lc_time_system_to_conn $last_modified_ansi] set last_modified_pretty [lc_time_fmt $last_modified_ansi "%x %X"] set content_size_pretty [lc_numeric $content_size] if {$type eq "folder"} { # append content_size_pretty " [_ file-storage.items]" set content_size_pretty "" } else { append content_size_pretty " [_ file-storage.bytes]" } if {$title eq ""} {set title $name} set file_upload_name [fs::remove_special_file_system_characters \ -string $file_upload_name] if { $content_size ne "" } { incr content_size_total $content_size } set name [lang::util::localize $name] switch -- $type { folder { set folder_p 1 set icon /resources/file-storage/folder.gif set file_url [export_vars -base file-selector \ {fs_package_id {folder_id $object_id} selector_type file_types}] } url { set folder_p 1 set icon /resources/url-button.gif set file_url $fs_url/$url } default { set folder_p 0 set icon /resources/file-storage/file.gif set file_url ${fs_url}view/$file_url } } # We need to encode the hashes in any i18n message keys (.LRN plays # this trick on some of its folders). If we don't, the hashes will cause # the path to be chopped off (by ns_conn url) at the leftmost hash. regsub -all {\#} $file_url {%23} file_url } set HTML_NothingSelected [_ acs-templating.HTMLArea_SelectImageNothingSelected] switch $selector_type { "image" { set HTML_Title [_ acs-templating.HTMLArea_SelectImageTitle] set HTML_Legend [_ acs-templating.HTMLArea_SelectImage] set HTML_Preview [_ acs-templating.HTMLArea_SelectImagePreview] set HTML_UploadTitle [_ acs-templating.HTMLArea_SelectImageUploadTitle] set HTML_Context "COMMUNITY NAME" } "file" { set HTML_Title [_ acs-templating.HTMLArea_SelectFileTitle] set HTML_Legend [_ acs-templating.HTMLArea_SelectFile] set HTML_Preview [_ acs-templating.HTMLArea_SelectImagePreview] set HTML_UploadTitle [_ acs-templating.HTMLArea_SelectFileUploadTitle] set HTML_Context "COMMUNITY NAME" } } ad_return_template openacs-5.7.0/packages/acs-templating/www/scripts/xinha/blank.html0000644000175000017500000000000010471407067025054 0ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/0000755000175000017500000000000011724401447022323 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/plus.gif0000644000175000017500000000013110226756425023775 0ustar frankiefrankieGIF89a‘ÿÿÿ€€€îîî!ù,*œ©Ëíc ´V€Þ à-lÞŠŸ€¢Ý§…ÚÈd­Ir/fYÒÎ÷þ?(;openacs-5.7.0/packages/acs-templating/www/resources/mktree.css0000644000175000017500000000265510622143344024327 0ustar frankiefrankie/* Put this inside a @media qualifier so Netscape 4 ignores it */ @media screen { /* reduce the amount of UL padding*/ ul.mktree {padding-left: 5px;} /* Turn off list bullets */ ul.mktree li { list-style: none; } ul.mktree li h1 {display: inline; margin-top: 5px;} /* Control how "spaced out" the tree is */ ul.mktree, ul.mktree ul , ul.mktree li { margin-left:5px; } /* Provide space for our own "bullet" inside the LI */ ul.mktree li .bullet { padding-left: 15px; } /* Show "bullets" in the links, depending on the class of the LI that the link's in */ ul.mktree li.liOpen .bullet { cursor: pointer; background: url(/resources/acs-templating/minus.gif) center left no-repeat; } ul.mktree li.liClosed .bullet { cursor: pointer; background: url(/resources/acs-templating/plus.gif) center left no-repeat; } ul.mktree li.liBullet .bullet { cursor: default; background: url(/resources/acs-templating/bullet.gif) center left no-repeat; } /* Sublists are visible or not based on class of parent LI */ ul.mktree li.liOpen ul { display: block; } ul.mktree li.liClosed ul { display: none; } /* Format menu items differently depending on what level of the tree they are in ul.mktree li { font-size: 12pt; } ul.mktree li ul li { font-size: 10pt; } ul.mktree li ul li ul li { font-size: 8pt; } ul.mktree ul li ul li ul li li { font-size: 6pt; } */ } openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/0000755000175000017500000000000011724401447024337 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-txt.png0000644000175000017500000000107110512722433031135 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¯IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† €z•áúõë ÖÖÖpˆYHsGGCEE˜‹¿~ý L—–– ‚€‚»Ú ÀcÀ@jnܸÁ`kk w@1¡;d3Ì%sæÎkš3g.8pAòè^ ¼{÷¬¹ÀÁÁî€bAwÁ¢E‹âã㺻»Áb p…ˆ¨(C|\FŠ ^¿~3`ܼy“ÁÉÉ î€ÂƒÞÞ^°+@Ä^¸hX|áÂEˆä‹Å/_¾DQc#‹ÂÀÕÕ‡ÁÑ£G€é¯fxúô)ˆº ãLA6‘Ù†S`Þ0鼎ÆMèŠIEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-compressed-tar.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-compressed-ta0000644000175000017500000000177210512722433033630 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-genesis-rom.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-genesis-rom.p0000644000175000017500000000113310512722433033537 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @´   ƒ±¹\ÑÙ“7€šßÙׯ_g°¶¶†» €XMÙ Íîž® Þeøúõ XLHHL9rÅÄ„ìTxùh98¨²3ò~üø–{ûlŠ: Œ0h™¶†™™Œ­˜×Ð8bÈ‹È €0 ¨É … Xcdp:Ãß¿ u9¡X]@´ÍXÇÀÂÂ6dö‚ @63X¼yêj¬†UÁ þüaxúì1Ã÷o?áj³±» €0 —‹`øõëÃû÷o>}ø × "ŽÕ€B‰ÆgÏžHKK£(:wê&8‚À7PänÀÑ£G€éÌÞ»w/Ü& ÓøôéSu¦ €` ²‰ÌÎ0œËL…ž?æפIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-troff-man.png0000644000175000017500000000111110512722433032202 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¿IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡ÈŠ €N ÚÛÛ£(úLëêê2\¿~ÁÚÚî€ÂpHóë)ý Ÿ€NcÞ{J©-„€L˜fBf†LHFPìIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-patch.png0000644000175000017500000000105210512722433031414 0ustar frankiefrankie‰PNG  IHDRóÿabKGDèÂM{¡Hb pHYs  šœtIMEÕ 66ávª·IDAT8Ë“¿kZQÇ?-1…>ÇB›I ]ì`éÐ`J,T:¢ùSÚ´] Ýú#doqqrj$c'­5)­ƒ¨/ˆä!âbQññÞé ÏúâSrà —Ã9ßó=ß{/Œckà BÇñ…mÛÒl6¥P(¸$ ”R’ÉdD)%½^oŠb±(–eI6›Src†€t:M8f8’L&Éår4M£\.Ón·1M“|>?í]™•‰D¨T*D£QR©"B¿ßÇ0 jµ*õzÝ#Ý£`0à8Ž¿I"4 b±˜¿‚w_޹øyÌúÎ>·tÝ…ç‘ÛžÔÍÙ —ê„`0È¥:àúišü>-Pýu:¾Ë‰7< îmïqQüÆúÎ>ˆ}ü€µ»k“)Ì­8õÀ¶mºÝ.¶m³, à û{ð·þ·Gç||¹‰®ëŒF#V«“á2Yuwñ ŸÏ…B¼útÆ×÷øž¯" ¦i<Û}°ÜƒÃƒ-Þsøú>/ù_?~„W <t:O{žÍ†A"‘˜÷ T*aYÖÒf€V«P»jîÓk~gÛnã?aª¾Z' IEND®B`‚././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-presentation-template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-presentation-template0000644000175000017500000000045710512722433033651 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~üÏIDATxÚµUQ £>ïEVnÖž¬~`eÃED!?¬mICJDDDÜÓfT"0áîîž’»ªªêºº²´ ØÛù‹þ³;Ð;pGJ‰ˆ.ô-Ç MõëÙ1P³ðÎ@(åÚæJsÎ9×÷JÿoZ@õâׂöã ¨23·1pôe&;_;`ff†PU5‹ç³gK0Ÿ;^…á t÷©Žz´¦ ctÆÙþ zô]ðÁ DèzDhl˜ý×ñ“žj«7 Ç IEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-drawing-template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-drawing-templat0000644000175000017500000000172210512722433033534 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<dIDATxÚbüÿÿ?ƒgvµÖ¿¿/üøñõÿïß ¿~|eø¤ÿÿûË’gddd`bfa`cçd`áà``fbb`úó“ÁJO£ €X€€‰õ?û!>QgKME†ÿD„¾}ûÎ`inÆ &*ÊÀÁÁÎpú܆7>3ðñó a`xøða@ Ø6­ñeXaííŸ?þ9»;90HIˆ3üýû—™™™¡¢®‘áɳç <|ü b’`Ì÷å+#Pþˇ¼Ät£¤¤$çϯŸ>ð 2,^µžaËÎ] ¿~þ`z ètf° b££N\¼Êpáæ=Nn.†ÿ@ùïÞ°A¾ÿ"""øøøïèçìæçÂÂÁ÷öõþüû»¯ª(%$õööàäæÊ¥­óúþûôñ÷òúˆåׯ_b@_¨‡z»Yg¦$‚ˆëY2°rr30ŒYÙÀâ¿>½cfgø@,²3fÌhTVVVØäÃÓç/.\¾ÂÐY_Í ªkÁÀÔü—™á?3Ãß?ÿýÇΟßøD…Ïã©S§Úÿýû§¼ d20Hþ£îù ˆŸþùóçÙ“'O^²°°À]õÅ«W¯fxûö­ @1P~ÅŠù·nÝúõêÕÿ úÞÖ°ÿ‹ü¹”íÿïMlÿÿ_/þ Þ¼yóêÔ©Ai €@ƾöððÐäââG( noz^€ÏŽáÓ%†{“¤b|}° €0üüùs7ˆ @,Ïž=9Ud€i•Z…lˆ{O¹Ýü(–„w@@=L4’(A¯\ÉÀðý!ÃQKˆf![p /_¾€\úÄ h °Á\w' j–Šf`ÐlÆÛ/¸0`A.k °ß¾}ûJ(㙤‡Û ¨ƒˆ@Äÿÿc`ú÷Ä’3àÐ x¬``8— Ô™ ,¼@C€M·0pñI]ñD¤ €X ~ºÈÊÊêò010ÈÏd`|< ˜΂ÃäÅ×àØ·)0iÚiv¢TIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-kword.png0000644000175000017500000000106610512722433032767 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¬IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿCÖ­[‡ˆ:$@.ŠÎdàxwŒAløóçCmm X3ÈÈ €àÑŒo` ½cÑøÀ7À1ÔÇâ ²dCC=ÃÕ«×´µµÀüÚÚ:p¼Ãø55µ^ ¼~ýÉȤöæÍ› NNNpJ€lÆÐÚÚÆ ¢A£¢¢°"@¡¸àåË—( `ld1P¸ººÂ]@ð08zô(Ãïß¿ñj§OŸ‚¨«0>@Ád™a8æ€×ùA‚ƒ4IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-reject.png0000644000175000017500000000075110512722433033115 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF_IDATxÚbøÿÿ?ÿ'K1@H@1 ðÿß¿Xñß¿ÿ?xðàÿÁƒa†(Á  >~üˆ>|øÿïß¿ÿ¯X±î>€b„jf`ddÀðùógl`Ïž= 'Oždxþü9ÃãÇ8²˜ €˜ˆ KLMMøùùÞ½{ÃpíÚ5¸@auˆÆe\¿~ÁÚÚì€ÂpLó‡`}0i‚±aò0ƒ@ €XÐm@–! øÔ6g‚lá]uEœ{ņ?þÀåa €°z¤ðs˜Šø×°º« ˜˜œËNa8Ù€bÁæf_r·±±@,Ø\ŒRE06: „Õ|š‘£Å€£G2Ó;^Í ðôéSuD²ŽDfg¶é0"âNrhdf1IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-formula.png0000644000175000017500000000037410512722433031553 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~üœIDATxÚå•A„0-ÿÅÓàið2ö`qÉÃæä\R&Ê4c¢8‰ˆˆ¸›tÕ+àÌndffþŸ±™™Ùïü¹ú`UDDDùú`V «)@€çîîw;êÓ-ó1ªªªÖËȘL¼²YçËUm d†ÕŽÛ3ã8¶ÕDÚ§`5úÇ«·Þû%ìv^U²}öýŽ{|…+kŸËxÚIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-vcard.png0000644000175000017500000000113010512722433031411 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÎIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡ÈÜ ÄàwïÞý?zô船/Èù{÷î… .¼xñb!!!˜…p@, ÂÉɉáçÏŸ ÷,f8ºwÃÏ¿ ÆÎ! ®~Qp…î®È.†€‚‡0”î߼̟Çpýê-†#»·ÅÃÂÂP4€ 2Ç-(Ž_ŠABZŠáë·o`±U«Va 38 ¸ ØÙÙÚ7>b8[QÂpî¯CJIX|ݺux  ¸ù * íÿÔÞ~þÍпdX<((¯öÂ’%Kæ×'€| ’à’¯_>Óß¾~fظq=Vˆ”¢@QÉ@¥Â7n ˆ<:Ž t§"ÛÒüôéSó*L €` ²‰MPœK`@-LþÜ;|¯IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-tar.png0000644000175000017500000000177210512722433032433 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-extension-nfo.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-extension-nfo0000644000175000017500000000107110512722433033646 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¯IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† €z•áúõë ÖÖÖpˆYHsGGCEE˜‹¿~ý L—–– ‚€‚»Ú ÀcÀ@jnܸÁ`kk w@1¡;d3Ì%sæÎkš3g.8pAòè^ ¼{÷¬¹ÀÁÁî€bAwÁ¢E‹âã㺻»Áb p…ˆ¨(C|\FŠ ^¿~3`ܼy“ÁÉÉ î€ÂƒÞÞ^°+@Ä^¸hX|áÂEˆä‹Å/_¾DQc#‹ÂÀÕÕ‡ÁÑ£G€é¯fxúô)ˆº ãLA6‘Ù†S`Þ0鼎ÆMèŠIEND®B`‚././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-bittorrent.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-bittorrent.pn0000644000175000017500000000104410512722433033662 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFšIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üøßÛÛƒÄ>üÿ÷ïßÿW¬Xw Ì€bbÀŠ‹ªº:ûáüW¯^1TWW3lݺ•ÁÁÁ$´&@X øó÷7XÌ©¦¦¦ üüü ïÞ½a¸víŠZ€Â0¤ABB_€îO^^^iii†Å‹—2¬_¿E=@± s€á¦+**P D–Gæƒ@1‚A¡Í 0|¤æÆ ¶¶¶ ƒAbÄ‚îü72øùùù±±±(®X´hÜ•0@Lè^á?þ€1H£ŸŸ?8Vpy €0\ôÀ€?Ðé¿QS €ü òˆ)aÆ ˆÍ„á___E=== é †È æÎ‹ˆ0W €‚pôèQ`zLjtŸ>} ¢®ÂøSMdv†á˜k 1ƒ=<¦3½{IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-s3m.png0000644000175000017500000000072510512722433031142 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ ,ã²I$bIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-csrc.png0000644000175000017500000000120310512722433031245 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFùIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† ᆼÿæU†ëׯ3X[[à  &dÛ@šAašê«à† åaÁ@±`D ,Z0›áë×/`§÷õ´2|ýò™¡¶¡E Š @¶€ÀÍ›7.\¸À°}Ç.†[·î0üüõ ,.** ÷" z ååf3È+È3¼yûèß› |üB òòŠ !A>p—"€Â0`Òä© =a06Òghnnbpttò1¬Y·«Ä‚Ìyñ⃄„ƒ0Ðîß¿Ïðéã{†cG2|ýö,ÿôéS ÷n¢@ð”J²À„‚’ömPøOž<ù¿wïÞÿ‡@ €XÐ ÙÒÒÒ ûö³A©&ˆ7àèÑ£ Àô—%_˜¦7nÀÅ¡\…ñæ…l"³3 §À¼`†P{€+mlïIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-midi.png0000644000175000017500000000072510512722433031362 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ !5™bIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-shockwave-flash.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-shockwave-fla0000644000175000017500000000106210512722433033604 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ ;Ü|÷c¿IDAT8Ë“=‹Q†EÄFÖ&ƒ… ‚¬øM—ÍOP«,DIa#‚…?ÁÖÎÒBÂBb1/FFgQˆ…ΚÂ&ÙYgUb2Þ9“wLF÷À{/÷}Î{Ͻ‚Ȳ‹¼DBˆïûsS)%–eI½^!ÙDÀšeɳ••¨âªùN\וf³)žçI¡P˜q²'‹E²Ù¾~%ÃöúNë]\×¥R©Ðn·éõzt»]jµÚNm¸}lA†÷îÈÖÃû2î˜ò!st¦ËËK¢iZ8aôöµLì5Ù¸›t³%ºÙ’ §Ìu=ØÇ"sn)—ËeDâÅ÷F¤ÃGÑ~ Ø Úà8N”étz9øöü1jk“ÍÑÍéóõ—€R*&ò}¾ƒï/ž¢=†ŸÉ§Ñ†T*…¦ihš†aÉ’B7[œ9~ŠC¨V«ó×ÚŸy¢>0^5LÔLK¥R²ƒ›qáúUÞœ0ÙžöÀ¶íàž§ÂN§3Ëå8¹¸ÈpÐçü勼z\Û¿š=åF£çy^ÖTô·eÛ¶Éçóï³;×oíò;‡y#þÚu0m„5hòIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-blender.png0000644000175000017500000000151010512722433033246 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¾IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ ]ñË—/Ümœí­dåÀ¶˜šš2ðóó3¼{÷†áÚµk(êÃg`x~šÁ×€aÑw esnܺ ó*Ãõë׬­­á. Væ“Â| NÖÆ ’ÀÀøÍ`o¬Áð‰õCœ'O±ƒŒ¼"ÃÝ[7XXXàÁ@±ÈŠñ›n˜Å !ÅÃðîù}†ØØŸ0p«Ø20üüÌÄ÷޵6„AGW¡©±AWWÅ€b”’)+Â-&.*ÄОlÍ üïÃK•t†=78þüedpÔúÇ úq-CϦ =ë/0¬ZµŠÁÞÞî€bjlíh}ù‹“ÁN_–Aöû5v%k†í×x¶®ÝͰkãn†µG¿10H2¸©³3h*É`x €˜æNëŸØ®Åm#Ãð›M€á×›{ Úʼ ²2 ÂÀ01Ðgø÷ö>+ †ÄòéÍ f6C†îSL ÜÌB ¹ª·LX–2hçø3ücdfàz²éù9†+o>ƒa@±„%fO_rîRæí›§î=`nCós®—m l, ŸùvÝçc(_xŠ!)%À‚§`š'"Ww†ÿ?¿0ðs21pqr1|üöƒáÃw†éÓ¦2hhh0ܸqƒÁÕÕˆ7àСC Àô΀œÛixúô)CBBÂU ¸ˆ@0ÙDfgNe&€Ðü|ÆôÆ$IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-ogg.png0000644000175000017500000000072510512722433032151 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ Ñj%ÇbIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-n64-rom.png0000644000175000017500000000113310512722433033036 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @´   ƒ±¹\ÑÙ“7€šßÙׯ_g°¶¶†» €XMÙ Íîž® Þeøúõ XLHHL9rÅÄ„ìTxùh98¨²3ò~üø–{ûlŠ: Œ0h™¶†™™Œ­˜×Ð8bÈ‹È €0 ¨É … Xcdp:Ãß¿ u9¡X]@´ÍXÇÀÂÂ6dö‚ @63X¼yêj¬†UÁ þüaxúì1Ã÷o?áj³±» €0 —‹`øõëÃû÷o>}ø × "ŽÕ€B‰ÆgÏžHKK£(:wê&8‚À7PänÀÑ£G€éÌÞ»w/Ü& ÓøôéSu¦ €` ²‰ÌÎ0œËL…ž?æפIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-sql.png0000644000175000017500000000066310512722433032442 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ +%­ÐÅú@IDAT8Ë•“=KÄ@†_!­ÿA-<+HiwÝr½Ü•X]'V'ø´´+L‘‚¦öÒ!]‘âŠ%;’dÃ2;;Ͼ³ÀMп@ç¼Ó‹¢ 0 ɲ¬2él·ÛN·m›c¤iš d¯@žçò ÀëºH’QÁ4ͪVj/^ŽÇøf½†¢(‚ž÷ ß÷ñk U¥$ÑN’h¡ª”eeYFišRš¦ä8NÙœs‘LÔÈ×〈ªäƒ,ôýSè—·Õâ·×û~@ ™­VU¬Oï°9xŒÂ9ˆHP)´°yŸÖfÑÎÿ©Ô³ŒÂ9ºÚtˆ³/Ë/ÿWðá sí±ptö,Hn_e'Àq0Æzw.-ŽcðÚïåzàw.ýª,ü¾ƒ˜öC[IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-tex.png0000644000175000017500000000107110512722433032435 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¯IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† €z•áúõë ÖÖÖpˆYHsGGCEE˜‹¿~ý L—–– ‚€‚»Ú ÀcÀ@jnܸÁ`kk w@1¡;d3Ì%sæÎkš3g.8pAòè^ ¼{÷¬¹ÀÁÁî€bAwÁ¢E‹âã㺻»Áb p…ˆ¨(C|\FŠ ^¿~3`ܼy“ÁÉÉ î€ÂƒÞÞ^°+@Ä^¸hX|áÂEˆä‹Å/_¾DQc#‹ÂÀÕÕ‡ÁÑ£G€é¯fxúô)ˆº ãLA6‘Ù†S`Þ0鼎ÆMèŠIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gnumeric.png0000644000175000017500000000104110512722433033443 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ÖIDATxÚ“M‹RQÇêM!§f¢Vͬb$4‹†!!"jSËv}ž¾À]„}€Ú´H37há )c¾”Žz-¹Þ—§E(×FøsçüüŸçœÿêôˆ%%Žã,”mÛR«Õ$NO!GKªªŠªª¢ëºèº.…BAt]—L&#¦iJ2™<—ÄãP*•Æ+—ËäóyZ­õzT*5ózÝ5MCÓ4¢Ñ(Ñh€H$B,# Ñëu)‹sð•¸k0Çg^Žù9—C¯W wëX­c&¿ÞKx®o±}ø˜Ýø>ý~8ˆ×a­ò…ucˆxŒË~Nm›ÑÏïÔ×üj·Ù¹ŸÌÍàÇÇ÷lCLËblZôðÑði+Aμ>rÞá8Îâãш 0¶l&'»7xÃ?‚5㯖y!²<¹ÁX sjÙØÜ1XéxlGPL¹°½À§‘‡nà*£+ p‡*[ Ê×<Ïîß;˜kAŸá¿u›oÇUNš†oKLÌ ›ÊMž<ÊáÁšÍær@"‘@ä!î›q¯Àò!f³YLӼРÐh4 ÿ?°W+~ç©^N™4$ê ¨íIEND®B`‚././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-bzip-compressed-tar.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-bzip-compress0000644000175000017500000000177210512722433033657 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-presentation.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-presentation.pn0000644000175000017500000000174610512722433033572 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<xIDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññÿüü÷÷÷ÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=TätuuØØØΜ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™fÍšÅðáÃ!!!†§OŸ2$&&2øøx346·˜ÊHI &í’’’œß¿~ø ÀÍÁ0qî"^YU%-=†òòr†‡‚m·±±a:n_ksÓ§OmˆEII‰ïÇï_<—ýôõ;ã'OþýùÍÀðŸ…!??¬éׯ_ _¾|a¸sçØþþcpvrdxõòå€bJŠ Tõq³ÎLNd`fbb@Ó¦Mc••egHOOgZÆðöí[†={ö0(((œ  Ù3f4*+++/((¸@ h|-¡ ªùáËw†ß XuÐUa/b@_·Î`øûèÃ}`ÌÓÏ@1={öì;—þ¯?~ÿþ Œ? Š"ü øÀãÇAÔm@ +Xâ÷ï? ÿÿýc1>. ÿC1(JÉç$H €XV¯^ÍúïßÖÿÿÿeÿCðû Ÿ·LÇ0àßëG ~Ù o½eø÷ïß7@±“(/#ÃýwÀø—»ÚÏîßaø¼é†Ìâr ¬.É bî2¼{÷Î(t €Xœß.Øwæ3 ‹.È}L,, Õl¸j˱úÿ ¾yQ Ä p°øüe÷«çOc¼{ÉðçÇW†½1,’—dàåå'tÊÚÀtàb†NíKyIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-archive.png0000644000175000017500000000177210512722433033266 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.ms-excel.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.ms-excel.pn0000644000175000017500000000150210512722433033523 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC» pHYs  ÒÝ~ütIMEÓ  !« ‚˜ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ IDATxÚ?hSQ‡?“XÁRhC2HK)UB©©‹É"ŠKq*U\ºè"¤ “8èÒ‚CÄ1–jAQò¡fxÉ IÞ ‰mÄhä“ôåý¹’GI!.Üç|÷»?ø_ €à\á–eõ=¦iŠr¹,$Iê@Äb1‹Å„ªªBUUQ(„ªª"N ]×E"‘è19Ò T*õÕS…l6KµZ¥R©J¥ì]W÷ ,ËȲL  à÷û ƒx½^êõ_‹EÜaÏåøö)Omç=üÜCoìÓÂ9æÃ?a28‡n„B!{×ÓMû°ùß—<§¬Âm¡¢eš4þ|g÷uœ¶vÀäì¼ÃÀþ‚‚‘½Ïø¬ºaÐÔ ê¸ÙuóÃ3ÌËÍÎÛ-„€Ã ÑhК†IÁï3'xÎ µ¿£Ýdè«Â’eõ7ÐÇýh#£´ íøNkŒîSsy0-ÁQ]ë1°C4M“äÆ+>nÆy§dÐrœ›;Ïìµ%rÉuü¾qrÉu»ïÔÃèM»wd I’}¿¼|Ÿ­g¸xýnÏ«—.œeqe­× ‰‡xtçO_¼áñ½åÀâÊñÕ¨Éd(•J(ŠÀôÔÛi¦§&ìÅŽv|5Êv:çñð¤38sõöÀ!þõuŠƒšƒIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-x-directory-smb-server.png0000644000175000017500000000072610512722433033431 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFLIDATxÚbüÿÿ?% €˜(D±„ÓFFFY þ†eÑÕ#ƒ!‰ÉÃå1HÃþC‡$$$^¼xÁðíÛ7o #²Ä$//ÿè\U:Crr2Ãû»Û@|d Í ðùóg¬. ñíÀf†¹Çž1T~A‘ÙŠO3Ø€?ÿ`““:ùºº"€b:ùÿÇá@>ÃAapùòeźºº–HÃïfoPjú¿wçéÿ >4q5Ä10Pÿ_¿u Loݱ,@àh¼öìظ§^ÃR¥‘C=P>CÂàÍÛW°4€5}c T€ÂæÔ& ÞøÄ–E÷H €ñe&t—` T€b€Ù@c T@1Rš ˜½ÄaóZ)ýIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-ruby.png0000644000175000017500000000117110512722433032617 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ,…0etIDAT8Ë“1hSQ†?_b¦úÔ †P[Á–*¶’!DA“b¡‚sÁE´`u­©-Š›s']Bv§FMû´ÄÅ JäQClyFˆáåÝãPÞ³©ôÀážáþÿýνçÂVL²‡¼F—¥Ô®é8ŽT*YZZrM&ºX–%–eÉúúºW[–%†aˆmÛ’N§ÿ!Ù·Í€F£A¡P “É099‰RŠááa²Ù,«««T«ULÓ$—ËyZm'Šiš¬±XŒx<Ž®ëœ@×uêõ ŠÅb÷;0–—ç÷îHêìiy<2$Fìâ¢ÔëuÉçónøÝbss“±D‚WÓS\¿Aí€jZØŽâL8Ä•d’r¹ŒˆtœìµÐn·8ÖßOððFúø[6‡|[ÛZ­VwƒP(Ä‹…®NMóíÝ[ªor4¾|çç× n¾6xúh†p8ŒRªÃÀkÁçóq>àó‡÷MÚ&?~·898„Rª;@$áÉü<ã/3øö"=~n­|äYj†±Dù¿RŠs££ü î‡P/.]Æ4Í] üo)B4evv–ëss¤Þ§ïø z] ¼It‡Z­†ˆ ”BÓ4DÇqд¿ ¥R‰d2éi=‚|>mÛ4ÛW7ÖÖÖ>íœÄ»{üÎnÞv…Ãà<–G£ˆÄIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-par.png0000644000175000017500000000170210512722433032153 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF8IDATxÚbüÿÿ?% €˜)`aaáâææ^ÀÎÁ¾›<@±`dddÔàoäããWÐÓ×Ô02Ñäúû÷·à—/_ÝÕ#Ì @M,ÌÌÌY::ZùiiñòzÌ—¯^b¸s÷:+ 77ÃÝ»V,ݲêÛ·á0èBE..® ©©Iááþ|æff OŸ=cX¹z)˗ϸ¹8˜YØ€600˜™ë0üøñ#Œ••åÚïßA‹¢¢üò »Íµµ4Þ½Åpáâ†ÓgN1<ñŒˆÙ88Ù˜™˜^¾xË #-ÆÀËËíÔ 6 €Xdd¤xÌÌt>þÌðüùS†ë7¯3üúõ‹ÁÌÔŒáÞýÛ ììl ¿~þføðáÐÿA ò0<ðˆåãÇO߀,¡§§Ã (/ÃðýÛw†?ÿÿ1È+È3lÙ²™áË—Ï ìl@ïpà ¬—f@1ýþýûÓŸ?€f22¼÷ŽáÛǯ ¼\‚ œ,¬ ,LÌ Ÿ?}dd``ffZÄÌ3ˆåû÷Ïýú ô+Ð^†o@¯üùó‹‡áÍÛ ÎvŽ ì\À}ÊðíÇw&&6†ÿÿþ1à  ¦ÏŸ¿|üúõ0ÁÞ“–fxüôËçOt´Œ”U>üÀ ((Ä` o VÄ"RRÒ¦êêêÄòóçO¦ÿþ1°°²0|ýö•áÝ«W b² ¼<ü@/½fx÷æ''ƒœ’ËWOnßz ä?Ì<㿹¥þo ø ¶GV ÃÄ€Mj˜7;;û ŠK F¿»ƒYIEND®B`‚././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-spreadsheet-template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-spreadsheet-template.0000644000175000017500000000043710512722433033521 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~ü¿IDATxÚµUKà „¾Ü n¦Þ OF–¦Ï„ªQg‡¿D„ 1Æ£*lFáAt&TUUTEDDÖÅ…å¼ zöÞüK‡·0„BXGœsÎ9_ǧW¡)ÀPryÆÌÌÌ×ñ¶nZ€wP‹`»DDDþ¾V §ð˜™EŠð%)èu %Ä”zOx:P;a Þtµ•Ì;'Ì'¦k@DÄjàWØ¿§9$ Uå½î„»; ÁÉÚþïøCoíF¿œ±kµ¶IEND®B`‚././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-master-document.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-master-document0000644000175000017500000000176410512722433033552 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<†IDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññïðñÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=Tätttøøø¸¸8Μ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™f͚ŰóÈ)yYi~6&†ÄÄDo†ÆæS)ÉIJ]RR’óû׸9&Î]ÄÀ+«Ê ¤¥ÇP^^ÎððáCqa!oO Óáöµ671î œœœ  _¿~e8r䈽 €XÚÚÚ\ß¼ys3©¬^÷Å›÷Ì@6ïÏï4U”¬-ÍV<ÃèÅŒ2¸«€QÉ ÀðçÏŸ] @y-;×vá wŸ½`xL,¿¿1Ä%§2°°²201³`xë÷Ï Oo\þ5or/;@¢ñµ„‚ªæ‡/ß~3@b5ÀÓ¡=/™áõ‡O ÓVoe¨K‰@1àЋ½_ bÓ³gϾ±spéÿúó—á÷ïßÀøÃ ¬ V¸tÇAE tðøñcuDÈmŒ@,ñû÷†ÿÿþ‚±¸ˆ(…~üü…A_UÌFÆ_¾|¥Þ“ ˆeõêÕ¬ÿþýgýÿÿ0îÿƒ1##ÿÿÀ˜è @©(ö Ä &!!!^F†¿ïÀr ##Ë—¯€éƒáßß? _¿³‘±˜˜“È€brvv~ûûïÿ Ì,À:€ H_¿}œ`Ì´TÎ_¿ f#cAAAW´@8Ø?|þ²ûÕó§±?Þ½døóã+ÃÞ‡ÉK2|þù›áüí ¼¿>£xá;ÐUÀtàbd¨ƒCä¤IEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.draw.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.dra0000644000175000017500000000111410512722433033542 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÂIDATxÚbøÿÿ?ñ"°€ô0@1@ ø üû÷ïÿƒþüÿ÷ïßÿW¬Xw Ì€bŒŒ`ý?þ;ƒƒƒ¨Ìþû÷/ÃŽ;Nž<Éðüùs†Ç38p¤™$@LÈ~Ò€¬™™™™ÁÅÅ…ÁÔÔ”áÝ»7 ×®]c@÷ȯ?~üÿýûw¸óÑÙïÞ½ûôèÑÿP/ƒõ ²a@CÀ¶ƒùœœœpöŸ?ÀòP á €XУåׯ_`>+++X3H#0Q£ Ü @›‰Iðè„@, hàäí×@¿üaøöóÃ÷Ÿ¿~½ôñÛ/y1#eQ º‡n¼bX~ò?/7¿ Ú=§úVdøüý²‹á €0\ðîów†_¿ÿ2tm¼È ÈÉÂÀ),Ç Ïü•áÙ»¯X  ’Ã`ïÞ½(a@(.xöìŠ 06²Ø7P@p€ ]¸4ƒÀÓ§OAÔU €` ²‰ÌÎ0œó@€®*Š”%ÐBIEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-shellscript.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-shellscript.p0000644000175000017500000000103410512722433033643 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC»ÑIDATxÚ“½kSQÆI½H]®]z›Bœ4·±:œ‹·‚`'qqqrrrtü*’N.NMLÃC›*FZ ¹p—æ¦7Ä 1žæ¹Á4öÀ³÷÷>ÏÃ9ð÷¬ê ºÍ„£¤”cÕï÷•mÛ*—˵‰€v»=Vù|^ !T2™qú@§Ók/NS(p]ÇqÈf³ƒÙð¤L^£‰®ët»]‰º®ãûMªÕ*S#´Z-upðEªúÑV€r]Wù¾¯|ßW–e1q ¥ÄóšÄbW¨6ùjÿ ¹±E$¡÷«‡”¥ÔÐæs JÑhx˜fŒÃý#¶·Êü=¡67RD#8Ž38B`š1vÞæÍë⤇'„gÂ\˜ãù³WD£Q¤”㚦‘y›#q#Îâ¥9}Ž=GߨûPâÑãu*•½É®]³yÇõUô‹çi÷©î—xòôårØŸRb.]&•Êp÷Þ-~v[¼Ü|A±XÂ0æ§— …X^^"Êpsu…ÝÝ" Æ ûÁ…øU“Z­†¦iCÅ.q°, !ÄlÜÆz½ðéôK|xÆïè~0øÍÐJÍTZAIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-nes-rom.png0000644000175000017500000000113310512722433033214 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @´   ƒ±¹\ÑÙ“7€šßÙׯ_g°¶¶†» €XMÙ Íîž® Þeøúõ XLHHL9rÅÄ„ìTxùh98¨²3ò~üø–{ûlŠ: Œ0h™¶†™™Œ­˜×Ð8bÈ‹È €0 ¨É … Xcdp:Ãß¿ u9¡X]@´ÍXÇÀÂÂ6dö‚ @63X¼yêj¬†UÁ þüaxúì1Ã÷o?áj³±» €0 —‹`øõëÃû÷o>}ø × "ŽÕ€B‰ÆgÏžHKK£(:wê&8‚À7PänÀÑ£G€éÌÞ»w/Ü& ÓøôéSu¦ €` ²‰ÌÎ0œËL…ž?æפIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-html.png0000644000175000017500000000100710512722433031014 0ustar frankiefrankie‰PNG  IHDRóÿabKGD.;* åò¼IDATxÚ“ÍkQŦK!«]Tn "â`!]ÖEÅ]PZJ‘ú‹âBÜhý ÄÚ]‘.Tè*ˆàJ ˜é4J*TA’,D35Æ)Cc ¦ÎÌ».dBÌ›`.œÕ»çÜs.÷ÁßJÒÎÒ¡D) ß÷Ŷm1M3It¨Õj¡°,K\וd2©9ÙÓ"@½^µ—J¥Èf³T*J¥étºÉðŸ à ‹á8[äóùÞ5J©ŽB…Bx<Þäö¶6äìûÜ{ô˜FÃcw·Á­kŒF)ÕÒø¾/ŽãÈêÛu9=}EJÎOyùnSn,>—³òôÅ+©V«bYV°H´ˆ·–8Ÿ˜¤¶Ó íáÀ>ÅÐÁ!î܈ˆhµžç10pˆâ·-ê¿~S,WÜËï^h„Þv‘ž¯×ßàl»ìöc¶93v”ÜÇ<"¢ DÚܼz5ó_¿äØÙÞdtä0KV˜›9׃“Ç1i†ù»Ë?mÐ××Ïõ‹SŒ†:ÐD„ø)ó‰Ñln%v\b&“Áu]ípÚ'–Ëe€\ûÌuù\ˆ¢áN ZõdIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-pdf.png0000644000175000017500000000076610512722433032153 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC» pHYs  šœtIMEÕ ö§²¨ƒIDAT8Ë“½JÃP†ŸÖÄAçnnN²8ÔAºhïÀÍ+èèU¸ôŠxi,ØR:$‹ô¤P(¥uJ¬IÎç 9ô/ê / œó>çÍÇ |ëø„‰Rj¥ƒ ~¿/µZ-„œF&“ÉJ×ëuñ‡i¹¬÷¬„ÏÇGÖR)|ß×Nð|y‰ˆ ”šÌ 1ü^€7Û`zsCr_ Рñ˜§\€uÃ`óìŒlöo€l_]-\1!±–Àÿi÷{îì[üØü\Be2™¿?áð(³ž}F±Ñhày^d8Ôp8h-|ñÏß9ôyü‹20‘æ4IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-install.png0000644000175000017500000000124710512722433031771 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚb`@% þO–‚iøÿÿ?@!égøÿïß?¬øïß¿ÿ|€Û¶~ýúÿ?~ãÇÿÿýû÷ÿ+VÀ]2 sj@04HpÔAÿî ,3tA”°§ŒÈ“ººU%"Ø]ÜÅÌ8çPU_Ï ™ùŽr &d?˜˜˜€5#ƒ¯_¿‚jjjÊÀÏÏÏðî݆k×®Áåê•ÿÿ6¢`“Ar‡‚‹½{÷Œ=úær€b2Œ€Î?âý6óÊ•+ ¶¶¶ ))) Ož<{ øøø„……QB €@œbO !ÛAGŽkÎËËc°··g066k„`Œ @,PzL@GGLKII1ˆˆˆ0¼xñŒAš@‰ŠŠ2£n@±0 óA@VV–›››AFFE¤Ù3ÀÝÀÀcÆ;0Ôß1ððð€ÅØØØ¤¥¥Q  Î@¼ˆ c øgeeePQQaàààÀꀰ9`.€ÒÕÕÅpá°+@^’——G1 €àaJuÈ”Am¼¼¼à¨„99%›ššäääàbŸ>}§< €yOŸ>I]Od`Kk FÊF™ZOãIEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-linux-psf.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-linux-ps0000644000175000017500000000106610512722433033601 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¬IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖpŠ `šûúú´µµTTT,--€a—‡Ä„- Èpúôi†»wï2$''3äçç£F tg‚ðÏŸ?RRRΜ9ÃÀÌÌÌðúõk†?þ ¸à …ÞÞÞ VVV`ÿnذl(H›ÃLLLÀÐ~ÇÂÀÉÉÉpâÄ ”@D7 €°º ´´”ÁÜÜœAGG‡áÍ›7 pW @ðh&Y†W¯^aØ‚nóÍ›7œáÑ@X—fl@pŽ=ÊLïx5ƒÀÓ§OAÔU €` ²‰ÌÎ0œs-@€dkLŸÇEŸIEND®B`‚././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.impress.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.imp0000644000175000017500000000071010512722433033562 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“}IDATxÚ“=k"Q†Ÿ]·Ÿn' ´ën“.Øh³°EÒ ‚‚Èþ€ÛJbmga+²°í‚Ÿ‹ˆÍv‚Š3²ƒ)ÃÜ“"̠ɘ.çã¹/çž /v H ÿÎ ­u¤û¾/‹ÅBúý~¹> p]7҇áxž'Nç’öû}Hìv»4›MÊå2‰D‚ÉdÂf³a¹\ÒëõÂÞQrÚí6¹\ŽL&C6›e6›a»Ý?¦ÓééÄäx<Î|:¤T«UŠÅ"®ë""8Žƒiš8ŽÃh4BDŽnA"•JÑh40 €›/÷|NgÀüqT© 0¥TXüXúÅS%æ µþ? V«…/rysÇŸßÜV.â)X­VäóylÛÆ4M®¾žcÛv<@«Õâ={ É÷}¶ÛíQ‘RŠz½~›ÏçX–½H"‚ÖA)…eY$“É0ä# <Ï{#õµäõzM¡Pø |;ŒÿŒù/Ï2gØ`çV»IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-trash.png0000644000175000017500000000076310512722433032765 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFiIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Äxû´È@Lí.˜Þ³gÃÉ“'ž?Îðøñc†€43‚äˆ D¨š¾aØ|¸ŠaÍžb8iÓ¦m155eàççgx÷î õk×P, ° @½Àðùóg†W·”á’«w1dff ®_¿Î`mm w@±¨˜¼2Á² CDTn3LŸ>ªá?\#L™Ä‚-@‘‘5LÕÀ@±àSc£»Š I`¼3àè. 011aµ›† ÐH( ÃŒŒŒxmF7 €(D€‚pôèQ`z'èç§OŸ‚¨«0>@Ád™a8æZ€†¶EóÿêRIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-compress.png0000644000175000017500000000177210512722433033500 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-makefile.png0000644000175000017500000000137210512722433032077 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™ðòþg8´y3ÃÛ?\ 'Oždxþü9ÃãÇ8ÒÌR@8]‡VMøßf/ðÙÔúÿ/^¾ÿ¿eË–ÿbbbÿ!>€¸ €0\¢AàÖÂ`†gwÏ2˜ˆþb¸}ÿ;ÚÇ, =›>1œ?žÁÚÚî€bAv2L³€#éãÇî½eeà2cXsç Ãå¬ Oï]…¹ˆ 9ZÀxbIƒ— C]üg`ˆ]fXr˜A˜ó?Ãǯ?0  ¸ ˜˜˜vÍOdxø–ƒa÷Î ¯10(ÿd`øòâC­7Ã×ï?._»Ã ¤¤„b@Á]ðêõGeᣠff0$…02|FÈ×÷ V– Úš ‚Š w,Æp@Á]pdÇTwuE&öÛ ¯ÿ3üýÈÀpí"ÃG }“áê3cwg î3Ç(†Å;Ù}aWg°·b`8ñ˜aá†{ ž Á9;Ò2ò0  ¸ ¤¤äÓ3lZÞÉpõÞ<†{wÄ,Ã’RŠLLt¸99€šÿa@ð„Jó ÄôíÇïÿ‹/þŸŸôÿáÇ`qþóç×ÿŸ?¿ýß½{7JB xB:tè0½£ŒaãÓ§O®Åu@|€‚)È&2;Ãp ÌÒ‰­WœDvóIEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.calc.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.cal0000644000175000017500000000115510512722433033540 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFãIDATxÚbøÿÿ?ñ"°€ô0@1@ ø üû÷ïÿƒþ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ]q{{; ¿¢¢‚ÁÔÔ”áÆ W¯^f¸víŠ<@a¸DcP¯2\¿~ÁÚÚî€bBVÒÜÑÑÁ ((Ö¢çÎ× ’‡±a €à.†60À„„„Þ½{W€Ì©yÅÖÖî€bÂæLM Òþüa˜3g.X݋Ăî˜tñ¸¸X¬^ ”––2HHH€¼¦KJJÀrÝÝ݈ă% ^¿~3`ܼy“ÁÉÉ „á‚ÞÞ^†E‹ƒù öÂE‹Àâ .Âê€BqÁË—/QÀØÈb Xpuu…» €àxôèQ`zÇ«ž>} ¢®ÂøSMdv†á˜w BRrÆ@.}òIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-dv.png0000644000175000017500000000116710512722433032254 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFíIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿüÿ÷ïßÿW¬Xw Ì€bŒŒ nݺs!ƒß?ÀøôéÓ 'OždÌðøñc†€43‚Ôxÿþ=ƒ¤¤$˜¾{÷.ÃÇž>}Ê`jjÊÀÏÏÏðî݆k×®!ka lÙ²…DcP¯2ˆ‰‰1X[[Ã]@(.øþý;ƒ‹‹ ƒ››»»»3üøñ,¢aÁ@1!ÛÀÊÊÊÀÃÃÃàååÅÀÄÄÆœœœ`yyyÁ4º„₟?‚éåË—3pppÀƒl†É£{ €˜°ù¦èÓ§O(âð¸GÄ„-À¢££Q ñi‚˜60  x,SÃŒ3ÀÑæææ /_¾d& pT‚4ƒøŽŽŽ NNNðX €üíìì ö30é2ܸqƒáÎ;àØ `““Ãp@¡¸`ÇŽXãYÈWWW¸ ˆ&qôèQ°$>Í ò\…ñ¦ ›Èì Ã)°0.>_Ùu_¢æIEND®B`‚././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.stardivision.writer.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.stardivisio0000644000175000017500000000120110512722433033726 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF÷IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿQWa|€‚)È&2;Ãp Ì;o'Y¤ýË«IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-pgp.png0000644000175000017500000000114110512722433032154 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF×IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈛a!þÝ{÷nܸÁpõêe†k×®¡È†Þ¿ÿŸ•…L#³ß½{ÆGý ˆÅ o ŒÂÉ#‹ƒ@1!+Zºt)ƒ–†*ƒ´¤$ƒ¸˜(ƒ¼œ4ƒ²’"ƒŽª,XòH €àŒ.fff†¥Ë¬Œu~ÿúÎðçÏ/†ïo1lÙ²•¡~ÙU†W¯^1\¿~ÁÞÞˆ„ˆ¶&Ú /ne¸ûø5ߟ?$yÿ1h‹3ãô@aðÿïo†Çïþ0¨k0üûõƒáÍÍà ŒL,¨© †ïŸÝ`dxÃðþþ+PÔ00±q2|ÿ÷§ Å€ &0D`MLUUUX]@(øòåK¬Ñ‡,JP®®®ð@ ¸ € „˜Þñj§OŸ‚¨«0>@Ád™a8æ€éOzæh̹IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text.png0000644000175000017500000000122310512722433030052 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ6ÊfâÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ RIDAT8Ë“¹ŠA@_IŽb`` F“8ˆ¿°Ù¦ûûc~„Gd`$á ‚`&â],#êÌìZP4tU=Õ4üÆ' oä)¡Î¹Ä¼Ýn†¡‡Ãò™ 8‰9ÕZ«½^/f"ŽÇ#Óé”Ëå‚çy šÍ&ý~ŸÉdÂn·c³Ù0 î³æU%‚g5UÚí6«ÕŠù|Æb±xªÇ F£•J…ÓéÄù|Æ÷}J¥ª Àr¹¤Ûí&8çb‘ET¼¨*ªÊl6£^¯†!žçÏçh4é€Òét¨V«÷æÇÓ9— Œ1±Ôj5ŠÅ"Ûíß÷1Ƥ¤í \.¿¿ƒl6Ëõz½ï@D°ÖA:@DZ­¹\.ÖŠÈ߯¬µ‰€L&“n°^¯Ùï÷ü¯¯Å÷›ß9ʯhðiG`À,IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-c++src.png0000644000175000017500000000120310512722433031373 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFùIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† ᆼÿæU†ëׯ3X[[à  &dÛ@šAašê«à† åaÁ@±`D ,Z0›áë×/`§÷õ´2|ýò™¡¶¡E Š @¶€ÀÍ›7.\¸À°}Ç.†[·î0üüõ ,.** ÷" z ååf3È+È3¼yûèß› |üB òòŠ !A>p—"€Â0`Òä© =a06Òghnnbpttò1¬Y·«Ä‚Ìyñ⃄„ƒ0Ðîß¿Ïðéã{†cG2|ýö,ÿôéS ÷n¢@ð”J²À„‚’ömPøOž<ù¿wïÞÿ‡@ €XÐ ÙÒÒÒ ûö³A©&ˆ7àèÑ£ Àô—%_˜¦7nÀÅ¡\…ñæ…l"³3 §À¼`†P{€+mlïIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-wav.png0000644000175000017500000000072510512722433031235 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ &uªbIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-database.png0000644000175000017500000000211510512722433032761 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ßIDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññÿüü÷÷÷ÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=TätuuØØØΜ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™fÍšÅðáÃ!!!†§OŸ2$&&2øøx346·˜ÊHI &í’’’œß¿~ø ÀÍÁ0qî"^YU%-=†òòr†‡‚m·±±a:n_ksÓ§OmˆEII‰ïÇï_<—ýôõ;ã'OþýùÍÀðŸ…!??¬éׯ_ _¾|a¸sçØþþcpvrdxõòå€bJŠ Tõq³ÎLNd`fbb@Ó¦Mc••egHOOgZÆðöí[†={ö0(((œA¾ÿ(((˜˜˜### ÁÆÈãäæÍÎΆ‚ˆpe ôêòÜ5<LõõõÄÄÄ­A¾ÿÊÊʇþþþ!vŠ“Tèìïìììúóï[ûì " òáÛ!&G‹ªœœœüüü'ˆ€òÎáqù^É…ÿÕ=#ÿ‹;þ—UÓüßoÈõÿñùÿÿþýžœÞÿ¦Ïÿss;ÿ-ùßßßÿ ”¯%T5?|ùÎð›«êl¿¸ÙYžÙÊðÿÇg†ÿÿþ2<9¾‡‰…•áÏïŸà˜jÞR @,Ïž=û–ÜЧÿëàmÀøÃ ÆþlÐõ Î/ìe`fec`ã`ø÷û0m°0<~ü$}DÈJF –øýûØ&æcþÏ ªiÄàØ8—á÷ÏoÀ”ÊÄÀÊÅð»<ŠáÏ·/à(&Ÿ“ ˆeõêÕ¬ÿþýgýÿÿ0îÿC00þýû‡GJ%JÿÓÇ_ <(•þH €˜€I”—‘áï;püƒÜÂÈÈð›_œáÙ¥Ó —WNgxqíó˧Î,è‹q˨0ˆ‰‰1011Ù  ggç· ö¹ÀÌ¢˴œ‰……á—¼6ƒ¢¹þ v^A`¸üdø Ìj¡ fΠߟ½¢È€û‡Ï_v¿zþ4öÇ»— ~É…+ Æñá |Y6 Ä÷ Þsø(8k ¸ƒÄ •i–î5åHIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-x-directory-nfs-server.png0000644000175000017500000000106610512722433033434 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÓ  ÍÉ»Ú>tEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3ïXyIDATxÚ¥’»ŠÛ@†?Ëcˆ+Ûep!l+Kòjò~ŒÔiR§Ýq•G.ŒÉ¨1òx _0AH3¶5'ÍJYÅ— äÀ0s†9ßüÿ™f<òƸ€¬V+)ËRʲk­c¤( )ŠBf³Yù| išÖÅçóY¬µb­­yžËt:m(Q¯ žç±ÙlêÜ9÷‡.‚çyø¾ß¸Uý-ãp8Üôx<ɲì> Ë2Œ1—þDèt:”eyàû>§Ó©aAD”Rh­/Iµ±ÛínZ0Æçy•~~¨8Ž¢(B)Åv»½÷Ô´Ûmâ8~|PQ%À§Jòr¹DkÍh4" ÃZ¾ˆàœc½^órá/ QÀÏ—ñUDHÓ”0 Y,ôz=œs5 ÛíÒjµ*1ß/š("ŒÇcæó9“É„Á`P(¥H’äæ+<ïƒ D„ý~­ ÏÏwí„Öš~¿1_ ÿŒ×ž†Ãá—¬{ª¿8ùã´ÙåÇIEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gameboy-rom.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gameboy-rom.p0000644000175000017500000000112110512722433033522 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÇIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äÃ-ݱúß# ü¿··ç11±ÿ@\@.àççgˆ©™†áŠ%-Y ïÞ½c¸~ý:ƒµµ5ÜÄ‚¬dY;‘AMGž“‹“áçŸ ×Î=‚ËC] Ä‚-@ÀÌþAßV‰AX@áãûO g]ÄP„â˜äËçÏnÜ½Í )"ÆðõóW` Àåa®„€bÂæ%e†8î]þÆpïÊ7;œ^ ¬.ÐÖÒc—gøÌÈÅÀüýÃ?fV†#;Öaõ@a D^Y†? Œ ÿþføÆÈ 4™ § þ¡Q ³êÓ1¢QËÀ« ž€ižáåË—( `ld±7n0¸ººÂÓ@Á]pôèQxhãÒ OŸ>QWa|€‚)È&2;Ãp Ì;+PpK÷Ü IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-voc.png0000644000175000017500000000072510512722433031227 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ :füubIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.ms-powerpoint.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.ms-powerpoi0000644000175000017500000000124110512722433033653 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC» pHYs  ÒÝ~ütIMEÓ  2³9{®ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ `IDATxÚ’¿KBQ†Ÿ²ýn݇ÖÜ”&çÐ%´ÐµÉ@$¥ÑU ü¬Åµ@$ˆj ¤Eoàø'r!„‹ œû5ĽhÛ¯>Îù8ç<çå=>”äµK€Äu]m)¥d4I§Óñ ™@€ã8Úêv»2ŸÏ¥Ùl~q²²`6›ùÄV«E½^'ŸÏ …è÷ûL&Æã1ívÛ?»ª³Óh4H&“Äãq‰ÃáÃ0˜N_ Áü&H˲¼9k‹”J¥B.—ÃqDÛ¶1MÛ¶éõzˆÈÒÍ>À[‡ÃÔj5 à »õÄz$fziŸÖ§r¹ìo~=¼â­Am(\×ýP­Vý‰fO¹¿~椰©uà?£RŠíýcþ+QJI4UO7ßö""ÑTQ´ÿ –.q°·£ícéÒÒ¨ îθ¼} ìµ!Z–µtãgGAòB<Σ©âŸÃ{¶Zˆ®ëIEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-text-template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-text-template.p0000644000175000017500000000164710512722433033476 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<9IDATxÚbüÿÿ?ƒgvµÖ¿¿/üøñõÿïß ¿~|eø¤ÿÿûË’gddd`bfa`cçd`áà``fbb`úó“ÁJO£ €X€€‰õ?û!>QgKME†ÿD„¾}ûÎ`inÆ &*ÊÀÁÁÎpú܆7>3ðñó a`xøða@ Ø6­ñeXaííŸ?þ9»;90HIˆ3üýû—™™™¡¢®‘áɳç <|ü b’`Ì÷å+#Pþˇ¼Ät£¤¤$çϯŸ>ð 2,^µžaËÎ] ¿~þ`z ètf° b££N\¼Êpáæ=Nn.†ÿ@ùïÞ°A¾ÿ"""øøøïèçìæçÂÂÁ÷öõþüû»¯ª(%$õööàäæÊ¥­óúþûôñ÷òúˆåׯ_b@_¨‡z»Yg¦$‚ˆëY2°rr30ŒYÙÀâ¿>½cfgø@,²3fÌhTVVVØäÃÓç/.\¾ÂÐY_Í ªkÁÀÔü—™á?3Ãß?ÿýÇΟßøD…Ïã©S§Úÿýû§¼ d²Š™³+ ;»«½u¨ˆƒ 7/8@AÀVG‘…ñ?ÃêÕ«Þ¾}k@ ”ïïï022šð÷S·b``å``j`:ˆLLÌp/ú[3p0üfX¹r哬¬,Y€EãkM...°-Sµ´›7o2üüùs7ˆ @,Ïž=û¤õA)_½Ïðýç M6Ú œlàdÃðæÍuDX’0vœ½Åðý¦2" ÒÂ|`ö—/_@Iü5ˆ @`€QÉ3 &Ô§ÓêÀôŸ?XXXAl€ðíÛ·  b¿ñˆá/€30XiÊ• äj)@ øüùó+ ‰š ö®3×~üÆn;ƒ¶Œ(ÀyE$@`>~üx›››Ûä·D;MM ¬ °l Ì2àØ’’’²‰<à+cr`ãˆIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-chdr.png0000644000175000017500000000112110512722433031232 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÇIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ]1#33ƒ¹Š ŠØª;nܸÁpõêe†k×®¡È† ,ÔÕ ²³T´u~þùÍ ÅÅÅ™’Âpªñúõë ÖÖÖp²i C@€ èŠ?0ü¾ïÐ!yh˜Á@±`D (Ê+2|~÷žñÛW†§GŽ0`S„â˜äóÇL]\dø8¹¹ÁbþüËÃ\ Ä‚Í Ÿ=døùî-ÃËÓg899QäÐ]@,Ø\À" Œ&†_ïß1¼¾zEÝ€Âê‚\ L ÿ$%> ÙŒ- À$ËðêÕ+° “¡!jB:{®ñæÍ› ÎÎÎðh /€0H²s‘=nÀÑ£G€é#<ÐüôéSuÆ ˜‚l"³3 §À\ `$Æ]L?B°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gzip.png0000644000175000017500000000177210512722433032616 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-stuffit.png0000644000175000017500000000067110512722433033326 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ•¤9FIDAT8Ë“½NA€¿»Ø_b%´6VF *ckeÇ+Øù>„>€±‚{ŠK —+(LhJ4æ€Æxì±CAvÃÁ­0Édwgv¿ùÙ]ØJ ô‡ˆÖºP×뵌F#ét:Rs\‘£(¥”4ƒL¼¾ï³\.sä h6›t»]f³ãñ˜v»mÏú‘ÅbAµZ%’ä‡~¿Ï¿%Ìçsg)I’HÇf À™+r+úâ³#"¤¿|¼<£µFDrû,À8̘®J)D„ÕJYŸ`Dk Àýí ×—¤iJ¯×£þ¶¿eƒÁ€×zÀÝÕ¹…ÍÀ÷·S©T¬í}§Ì£€,˘N§…-Êààxž—[—Ëe[ûI”J%\ÝŸçq†!E×:­}2™|ïy:ñ;}47XÁ#؃æIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-master-document.png0000644000175000017500000000046610512722433033217 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~üÖIDATxÚÅTA!”¦ógÀÏôeô`ÉºŠŠ[“Î…ìfF`Cø3 ýADD$â= ðžêÞ#""â¤rø]÷ZZô¥Ûél>³×G"ÅV6clýª Ø ˜™™Ë]×ß-†3Ð:à…ˆÈlÊðUåŽÙKª^쨊Â!Ñ;î­.öéï†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gnome-saved-search.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gnome-saved-s0000644000175000017500000000106510512722433033522 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs × ×B(›xtIMEÕ 07b:ÔIDAT8Ë¥“OHQÇ?³;êìÔ¶vèu iIŒ0‡(0Â^:H§Àé¸lPÒµ‹ÛêA¼ª`,t[,Š:vÒ‹®Dr)aYˆ%A­Ýu\Ù÷<˜³Ž¢Kô==~ïûûð{ß÷ž²ô¬eJ;1ŽH@âNŠ74²<€¼útQ-¹E©¨l|ÃH¡4¨‹Bþ‡[ÔBX@žÒûÖHñÜ”ÿüFŠ}©PàŒÑ‡Ú¬Ø½›ž‰Á!;ª‰¯R@qv?Ù¥±T€õ÷Ch€?tíRçôsöúÝS×^w×í£óØ¥u„mQLá×»W®9ØyŸà­{sîæ“ã!–33€Ä\McmƳ®ÉšŽâÏe\»Grõ¹WW³5ó[=’¤:;™S@$).|E )œÂölØsã\î=7~èÕøù|ÎÖæ>ÝÙv7šzÙø0ISÏ`ý(¹UdÍÆÙÚôf`óðw4½£k:ŠI¢=|Y2ž¥œ#E7+y/@Q[êÆöÛ°¶‚™{F Ƴ¢Ÿ1“ u=òŠKŸÐÛ:Üb«ÑK«Ñ @ͪ`å2`åû¼ç3M1þ]CFŠþW{Ð-±ÓùžýIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-haskell.png0000644000175000017500000000111210512722433031735 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÀIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ ]ñ… øùùÁ4ƒ,055‹½{÷†áÚµk(êà ïß¿ÿ v*ˆ ÃïÞ½ã£Gþ‡Ä Ä‚lÈ [“’’À|AAA†ãÇ3¨««Ãå¡Â@ÁÃÚ @À%„„„àl Í`¤æÆ ¶¶¶ð0 &tï€lÉÏÏó_¿~ ¦ÿüùƒÉ#€‚‡(¾àþñâƒØÈbÀ@ €bA7lñâÅ Àxy‹áâÅ‹ »víbpsscعs'"ñ €ÂÄgÏžÁý«££fÃİ"@a„ÁåË—nݾ æ_ºt‰áÖ­[`ñ›7obu@axf+2d³ŠŠ Ö@ ¸ÀÂLïè‹aãÓ§OAÔU €` ²‰ÌÎ0œó@€ì&Ÿi1$šIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-spreadsheet.png0000644000175000017500000000041710512722433032413 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~ü¯IDATxÚÝ•QÄ DMï7o'ë~4¤‰]£VýÙùÓ(LžA*¤ªªzži“®ú±ŽÚA‘uÝÝÝŸûÇÛ‹«Ô4233»×ÌÌÌÏýRqnÚ@­P«ÁvDDDõ{­'œ&0›‘ÿ%ÀÌlv_Â^99÷VMé3J $èoËðêÕ+óAr¨ C€‚eCiP–r8¹’O^ŸïÀÝénÌ IdæsfˆªŠ+¸ƒ@(.¨¬¬„ÛêèèˆáZ^^^¸ ˆ YÂÂÂÀ´™™V¦ˆ݆•+W‚Ù'Ož„Ó ñ'N€ù —"€bB7 $$¬äL ·µµE$$@ð0&`  rrrÓ—/_†ÛnaaÁ`nnXV€h0}ïÞ=%%%°&Aè. V­Zf£Lƒâ€É«Å  $‹¬xÀt滹¹10¸ººÂ½@ðX&†ß¿3 G+???~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™\½z•A[[›aÏž= 'Oždxþü9ÃãÇ8ÒÌR@L 8H³••Õ+WLMMøùùÞ½{ÃpíÚ5u„á…÷ïßÿ?r䨩'–õ€iÿÝ»w`|ôèÑÿ €x €P\òÈf f†çï2tfù q<ÔB8 &d—€œ Ó,¬bW“bkk 6Ý€BqHÌæ+{WƒÅtœCá†ØÛÛƒ] Å`\3XD•0HÊ+Ã5ƒ ºõø%Cù´u ûöíÃp@¡ ©© Ž"˜!Èš÷îÝ –G7 €à±Jq/^¼øÿìÙ³ÿ@Åà:Lƒø ñ§OŸþº%ˆÝ0`¢Û²ÑÙÙœˆ444à~Gw@aSÒ´{÷nͰ¨F7˜@€éÃ5ׯ_GÑô8¡Âø³1›Èì Ã)0×øe†lkikIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.ms-word.png0000644000175000017500000000125010512722433033545 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC» pHYs  ÒÝ~ütIMEÓ  /¥6²‡ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ gIDATxÚ¥­kBa‡Ÿ•‹‚É`3ˆ&ƒ8ƒöLaØlK×—LK6×f04Ü*?0´ˆ^ãƒYD rß³0îÅëUPvàÇË{>~<çÀ_ä¹BÏ\QJ•eYbš¦ôz=Û$Ñ`½^ŸÕ`0Ãá FÃCrwdÀf³a<³ßïÑ4 ¿ßO,£Óé0X­V,—KºÝ®3ûpŠ’L&Ýh"¤R)‹³Ù”ù|îª{úý>Á`ívËn·# à “Éœ'PJyl »~œwˆ"Ât:%cš&š¦àóùˆD"— l“t: @(rš_¥Ôe¥†aF)ý¸šËŸo爖eñøòÁ­qš˜èU&z•×ì¥B–‰^¥TȺþv#IäŠ""W½¶îùg8ÃáеF¥Ö Rk2Ñ«Ô[mê­¶kûˆïÀw"W¼™à‹‡ê!bÏcIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-abiword.png0000644000175000017500000000120110512722433033257 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF÷IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿQWa|€‚)È&2;Ãp Ì;o'Y¤ýË«IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-ulaw.png0000644000175000017500000000072510512722433031410 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ 6а^bIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.stardivision.impress.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.stardivisio0000644000175000017500000000071010512722433033732 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“}IDATxÚ“=k"Q†Ÿ]·Ÿn' ´ën“.Øh³°EÒ ‚‚Èþ€ÛJbmga+²°í‚Ÿ‹ˆÍv‚Š3²ƒ)ÃÜ“"̠ɘ.çã¹/çž /v H ÿÎ ­u¤û¾/‹ÅBúý~¹> p]7҇áxž'Nç’öû}Hìv»4›MÊå2‰D‚ÉdÂf³a¹\ÒëõÂÞQrÚí6¹\ŽL&C6›e6›a»Ý?¦ÓééÄäx<Î|:¤T«UŠÅ"®ë""8Žƒiš8ŽÃh4BDŽnA"•JÑh40 €›/÷|NgÀüqT© 0¥TXüXúÅS%æ µþ? V«…/rysÇŸßÜV.â)X­VäóylÛÆ4M®¾žcÛv<@«Õâ={ É÷}¶ÛíQ‘RŠz½~›ÏçX–½H"‚ÖA)…eY$“É0ä# <Ï{#õµäõzM¡Pø |;ŒÿŒù/Ï2gØ`çV»IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-sharedlib.png0000644000175000017500000000113210512722433033570 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÐIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉¸|ù2Cqq1ƒ¶¶6???ûwo®]»†¢ €XÐ5\t2Ã?€Îf¸sçÃÛ·o\]]233®_¿Î`mm W@,èšAàøñã`C` ¼¼œÁÙÙ™!77fp@,ÈÑrrCCß?à Áš¿ÿŽy$@(.PTTd(**bX¼x1ÃÓ§OÁb çFEEÁ-¹Å†ýû÷à 8qâ333Cxx8† %@’LLL(^xóæ ÃÆqz €0„ÝÝÝ‚ƒƒ€ ‡ABB‚ÁÉɉAHH,‡n@± »˜¨ àbâââà°ÙŽn@a€¬ ªª %zÑÙ @pŽ= N8Ȇ!Ó0 Ü«0>@Ád™a8æZ€É¢HiAê°IEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-extension-par2.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-extension-par0000644000175000017500000000170210512722433033647 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF8IDATxÚbüÿÿ?% €˜)`aaáâææ^ÀÎÁ¾›<@±`dddÔàoäããWÐÓ×Ô02Ñäúû÷·à—/_ÝÕ#Ì @M,ÌÌÌY::ZùiiñòzÌ—¯^b¸s÷:+ 77ÃÝ»V,ݲêÛ·á0èBE..® ©©Iááþ|æff OŸ=cX¹z)˗ϸ¹8˜YØ€600˜™ë0üøñ#Œ••åÚïßA‹¢¢üò »Íµµ4Þ½Åpáâ†ÓgN1<ñŒˆÙ88Ù˜™˜^¾xË #-ÆÀËËíÔ 6 €Xdd¤xÌÌt>þÌðüùS†ë7¯3üúõ‹ÁÌÔŒáÞýÛ ììl ¿~þføðáÐÿA ò0<ðˆåãÇO߀,¡§§Ã (/ÃðýÛw†?ÿÿ1È+È3lÙ²™áË—Ï ìl@ïpà ¬—f@1ýþýûÓŸ?€f22¼÷ŽáÛǯ ¼\‚ œ,¬ ,LÌ Ÿ?}dd``ffZÄÌ3ˆåû÷Ïýú ô+Ð^†o@¯üùó‹‡áÍÛ ÎvŽ ì\À}ÊðíÇw&&6†ÿÿþ1à  ¦ÏŸ¿|üúõ0ÁÞ“–fxüôËçOt´Œ”U>üÀ ((Ä` o VÄ"RRÒ¦êêêÄòóçO¦ÿþ1°°²0|ýö•áÝ«W b² ¼<ü@/½fx÷æ''ƒœ’ËWOnßz ä?Ì<㿹¥þo ø ¶GV ÃÄ€Mj˜7;;û ŠK F¿»ƒYIEND®B`‚././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-kpresenter.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-kpresenter.pn0000644000175000017500000000101610512722433033647 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF„IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜hc¢Š• MHacE0ðÃ%·¼©mž|#rv÷HDàJU13t7™y²÷°lÙ2www+++777† .0ðóó3¼{÷†áܹs(jÅ ÄäÑ£GÿC‚â€bA6ÌÁÁá‡t(Ãñ%Y –1ÓÀbÈlާ«aÂ@1¡¹ kÆ¥ €°†.Í ld@8 i‚Ð]@8 ÀeºÄ‚® PŽŽ«8 |d66Å€åË—£(*//gèèè@»yó&ŠÄ„î

    ˜{èß«5ÚE±ÅÛ x%Œ^¿ã`-­€el­ì=ÎÀã4€HucËzωcÛ8Å(“ j«kÜ×1†¼­ÀjxN2Ö|B2ÏÀʉ¶C5zWœøtêg Cï–ïYÆW@tb¨_‰ Û¬"•û æRÆ—.>Di2Q`·ÀÜÆ·_\üß½O½Ì_aÄw„ÀºuIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-qif.png0000644000175000017500000000105710512722433032153 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¥IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖp ²"dÍ0 èòèâDPh• …˜ D€bA·åçÿß ¿ÿýb¸óù!ÃÆƒ˜€.µÕ°e8öQWa|€‚)È&2;Ãp ,F4F"J£Ê\IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-core.png0000644000175000017500000000115110512722433032564 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFßIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þüæB!!†ïÞÙ{öìa8yò$ÃóçÏ?~ÌpàÀfF@11à Íüüü`[LMMÁìwïÞ0\»v E@a¸DÀ   Ãû÷ïáׯ_g°¶¶†» €P\Ó ô+CXX///˜^¾|9\f <A¡ýîÝ»ÿÓ¦MûÏÅÅõßÛÛû¿««ëqqq0$þúõkp€B D€bB7lýúõ žžž`?¿yóì 666†uëÖ命„á…'N€5~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖp ²"dÍ0 èòèâDPh• …˜ D€bA·åçÿß ¿ÿýb¸óù!ÃÆƒ˜€.µÕ°e8öQWa|€‚)È&2;Ãp ,F4F"J£Ê\IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-credits.png0000644000175000017500000000114410512722433031754 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÚIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉ص{???ÃÇ÷LMMÁìwïÞ0\»v E@axáýû÷ÿ6ú‰½{÷Œ=ú/Ü?þdØ»oƒ   ƒ¤¤$ë¶ LLŒ g.[Å„„„€®Z ³ÀÐf`ffføðë—~þøÇ .p˜  ¶¶¶ð0 ”08þ ƒÇA Í_¿ük~òä (°‘@¡ ##¦ü@UtüèW0Í‚á€b  L ~ÿ»$¤¤ÊŠšú@¡sÞ±#?Dx1lÞ¼žAhÈ?„<ºÄ‚î‚iÓz¼\Šž={{úô)ƒ´´4Ãê5˱º €PbáåË—( `ld±7n0¸ººÂc €à.&`zÇ«æ" ¸ ãLA6‘Ù†S`Þ0)jµËAØIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-csh.png0000644000175000017500000000113610512722433031075 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÔIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™\½z•A[[›aÏž= 'Oždxþü9ÃãÇ8ÒÌR@L 8H³••Õ+WLMMøùùÞ½{ÃpíÚ5u„á…÷ïßÿ?r䨩'–õ€iÿÝ»w`|ôèÑÿ €x €P\òÈf f†çï2tfù q<ÔB8 &d—€œ Ó,¬bW“bkk 6Ý€BqHÌæ+{WƒÅtœCá†ØÛÛƒ] Å`\3XD•0HÊ+Ã5ƒ ºõø%Cù´u ûöíÃp@¡ ©© Ž"˜!Èš÷îÝ –G7 €à±Jq/^¼øÿìÙ³ÿ@Åà:Lƒø ñ§OŸþº%ˆÝ0`¢Û²ÑÙÙœˆ444à~Gw@aSÒ´{÷nͰ¨F7˜@€éÃ5ׯ_GÑô8¡Âø³1›Èì Ã)0×øe†lkikIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-x-directory-smb-share.png0000644000175000017500000000112310512722433033215 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ +RL"ítEXtCommentCreated with The GIMPïd%n·IDAT8Ë“MkQ@OBBƒÈ…Mi EÁÑPÜucŸ…þ“ø\¸t§!Àl7ÜTQ’˜ºPƒ$NÒHtZ2wòîu‘1mtR¼py÷½ÃáqÄáyÞ]Àò&ÇDêÈÜî?¸7Wl5?ñèá3€ð6 þ{£ÝÚ¥ÝÚåc³M åö; f—þ1X¤ùäéc66J„"˜*¾ßçúÖ-€TæèÁFóM" ›ÍÒûþ•q¢Nô÷fµ9€ˆ0Gs—ƒ`ÿPQmšfÉ€¥¥£_>ªŠsŠ©¡Îaf8U$œSö’‘D36Õ ç"ÂÄ9$”ÅAUÓ)jÊÄ)‘ÈtœDÉßÐïf_>css‹/ŸS,®I„SÃL{;©«Õª-èÐmþ#¬V«Ùq=’^T¸r¹t òù¼¯ÿBÈ+Àp8\ô}ÿj“áp˜)—Ë{Ààðè’üz½¾ üü“½^/Ýh4¼N§3êv»'€I¥RÉ‹«¹ÂrµõõQ 8œV³Àiàp>6òbÛ±Ákà=àòp«L{Š‹CIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-kspread.png0000644000175000017500000000104110512722433033263 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF—IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ@Ád™a8 ͇fyTZIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-text.png0000644000175000017500000000036510512722433031072 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~ü•IDATxÚí”KÀ D¥ñ`Ü 8'£‹Æ¤ÕPÿé¦oc$Æq"„ fff³°‰«ÚDï ѺÁªªªe=ö·zGDD¤¬#""–õcµ€D«ƒUZš=sã9Ñ- oÜ|‘LR·‚8 F­‚ƒ¸Ø^’Ó¡&š4/¸Üÿœÿ|ç&þVÂ"a‰çy±áº®Ìçs‡¾I3Ñ`¿ßÇÆh4­µôûýD’À ÓéÄâ[–%­VKjµš€º0àp8ÍfÑú‡ÕjêP,i4^?Øn·Am*éRîóyÇÀ0Mz½wƒA(/dày^æ,T«Uv»JκˆÄˆÈY(—ˬ¿ÖT*ä4r('ŽàRœÍf L&P*ÐÏ”×FPðøôˆmÛär9ÔÉøê!%Pz.Õ£F,AJa˜&™t†ô]šãñ;‘Àˆvèv»˜†ñï³¶ÛíX‚àGr]—ÍfJð÷—gÓé”z½Ô­lÛFk}µ`¹\|F ßn|Î~¼ú…¿!½‰PgÃIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-cpio.png0000644000175000017500000000177210512722433032577 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-package.png0000644000175000017500000000177210512722433027545 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-plain.png0000644000175000017500000000122310512722433031153 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ6ÊfâÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ RIDAT8Ë“¹ŠA@_IŽb`` F“8ˆ¿°Ù¦ûûc~„Gd`$á ‚`&â],#êÌìZP4tU=Õ4üÆ' oä)¡Î¹Ä¼Ýn†¡‡Ãò™ 8‰9ÕZ«½^/f"ŽÇ#Óé”Ëå‚çy šÍ&ý~ŸÉdÂn·c³Ù0 î³æU%‚g5UÚí6«ÕŠù|Æb±xªÇ F£•J…ÓéÄù|Æ÷}J¥ª Àr¹¤Ûí&8çb‘ET¼¨*ªÊl6£^¯†!žçÏçh4é€Òét¨V«÷æÇÓ9— Œ1±Ôj5ŠÅ"Ûíß÷1Ƥ¤í \.¿¿ƒl6Ëõz½ï@D°ÖA:@DZ­¹\.ÖŠÈ߯¬µ‰€L&“n°^¯Ùï÷ü¯¯Å÷›ß9ʯhðiG`À,IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-arj.png0000644000175000017500000000177210512722433032421 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-text.png0000644000175000017500000000174510512722433032211 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<wIDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññÿüü÷÷÷ÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=TätuuØØØΜ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™fÍšÅðáÃ!!!†§OŸ2$&&2øøx346·˜ÊHI &í’’’œß¿~ø ÀÍÁ0qî"^YU%-=†òòr†‡‚m·±±a:n_ksÓ§OmˆEII‰ïÇï_<—ýôõ;ã'OþýùÍÀðŸ…!??¬éׯ_ _¾|a¸sçØþþcpvrdxõòå€bJŠ Tõq³ÎLNd`fbb@Ó¦Mc••egHOOgZÆðöí[†={ö0(((œA¾ÿ(((ÂÂÂlec ÄÈʤª®qx|þþþs€ˆõ ìþ àóÿÔçó!"... ­ˆ¥­­ÍõÍ›77“Êêu_¼yÏ d3üúüžáÚëï RŠª@Ùž¿þÁÀôö7ØEÆŠ b|\  þüÙ@ ”ײs `çžp÷Ù †÷Àt ÈúŸáø¶u`[XYYXXXP¼òÂâÅ‹ŸHH浄‚ªæ‡/ß~3@jêè3œ¾ÿE“­Ž"'D3Àô³Ä –gÏž}KnèÓÿõá Ãïß¿1ð‡áË6†]î  -/Î -Ìf?~üDÝ2’ˆ%~ÿþÃðÿß_0Nð°bˆ ö`@ T  (&Ÿ“ 6@±¬^½šõß¿ÿ¬ÿÿÿ©ã«^1ì~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™aÑ¢E È ..ŽaÏž= 'Oždxþü9ÃãÇ8ÒÌ’ ÐHþÓ§O ‹/f8vìÃéÓg^½z7 €P øñë'ÃûkÎ:ÌðáÇ)A%%CK˜W®_¿Î`mm 7 €Xm{võÃü¸0Í/Ï™™Îûǰ€•Á*5‡á¯¨ CTTÜ  d§nj®apa|Ï ¥(Áðôç¥ïx>üdØ;g Ãì«O€1‚a@1!sÞݸ .ÀÃð¨ñå¿ /~ÿexࢮËðøÉc°fW‘@¡xáÓ_&†ß~1¼e`bxýë/Ã; +>ýagxÏÈÊ &*ÖŒî€Bq‚wÃ×ß>}ý Ä? ì¬ü Ÿ„ÄxøÞ¼z‰H~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉¸|ù2Cqq1ƒ¶¶6???ûwo®]»†¢ €XÐ5\t2Ã?€Îf¸sçÃÛ·o\]]233®_¿Î`mm W@,èšAàøñã`C` ¼¼œÁÙÙ™!77fp@,ÈÑrrCCß?à Áš¿ÿŽy$@(.PTTd(**bX¼x1ÃÓ§OÁb çFEEÁ-¹Å†ýû÷à 8qâ333Cxx8† %@’LLL(^xóæ ÃÆqz €0„ÝÝÝ‚ƒƒ€ ‡ABB‚ÁÉɉAHH,‡n@± »˜¨ àbâââà°ÙŽn@a€¬ ªª %zÑÙ @pŽ= N8Ȇ!Ó0 Ü«0>@Ád™a8æZ€É¢HiAê°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-xml.png0000644000175000017500000000106010512722433030647 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¦IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à†Þ¿ÿ¿¼¼N÷ôö‚ÙïÞ½ã£Gþ‡˜ ñ@¡¸hŠÍè¤æÆ 666pz´€pGGX¬³³“aÞ¼ù`6ˆ†‡< ¸ €ÑÅðáÃ06²Øõë×ìííá. t'‚ Z¸pC||COOX\TTŒáõëW %%%. ¼}û§Í06( á. €0.€- ˆ ]Aoo/âE‹Á|{á¢E`q·°@(^xùò%Á@yÁÕÕ{˜@€é¯fxúô)ˆº ãLA6‘Ù†S`Þ0|H¦}^ˆTŽIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-video.png0000644000175000017500000000113310512722433030174 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿüÿ÷ïßÿW¬Xw Ì€4Ž¡0ÄÂ*ì?–FÙÒ»š¨äïåAd¸âˆª23t7»SUd&f¶±¬wÚÌ```¦wïÞ 6ðôéÓ ¦¦¦ üüü ïÞ½a¸ví²€BqAII ÌK8AHHƒµµ5Ü„vvv`¿ƒhŸaÄ÷îÝ[[ÛÿGŽù CH r´ÁÊÊ â4FF¸­ q­HÂ@¡„Á›7oÀþÑ @€ >0Á4È«È €˜Ðý¨©© gߺu ŒA@[[« À«W¯¢h¾qã˜éÒ%¬ º0›nÞ¼ Ç  §§‡Õ€Bq0”Á6èE‹χÀüóçÏ3ØØØ`@ðtLó ( °¥ WWWx: ¸Ž= –D׌nÈÓ§OÁAãLA6‘Ù†S` À·jÓû€IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-pgp-keys.png0000644000175000017500000000106410512722433033131 0ustar frankiefrankie‰PNG  IHDRÉV% pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFªIDATxÚb`€% þO–‚ªgøÿÿ?@ÁÙÿþýÊÿþýûÿÁƒÿ<3@ ¦ €P4üø+>|øðÿß¿ÿ_±bÜ ÍĈ¤™áóçÏ ØÀž={Nž<Éðüùs†Ç38pd3#@11 LMMøùùÞ½{ÃpíÚ5¸@P"zÀL™2åÿû÷ïQð»wïÀøèÑ£ÿ!fþg ³ÿ¿»Ö7éì¥' ®spºäÈ‘# 666`g LpÁª3 a& Æz2 Ȇ!!­†+W®Àù× Òˆ¬ì^‘vMdd$ƒ°°0\ €XÐM9ºººäååÁäÑÖÃÀÍÍ W @ŒÐ›‡lÀ„ tttÀ|SEDDŒŒŒnܸÁàèèö3@lžÒ LI ¯_¿fÅ7:””Ó 9ä”@,èqÊÈȈšô ltC3>0Ûa €àš‘ÏL¿x5‚ÀÓ§OAÔU@0äHd–„aK¡1d!«ä½™IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-library.png0000644000175000017500000000113210512722433027604 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÐIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉¸|ù2Cqq1ƒ¶¶6???ûwo®]»†¢ €XÐ5\t2Ã?€Îf¸sçÃÛ·o\]]233®_¿Î`mm W@,èšAàøñã`C` ¼¼œÁÙÙ™!77fp@,ÈÑrrCCß?à Áš¿ÿŽy$@(.PTTd(**bX¼x1ÃÓ§OÁb çFEEÁ-¹Å†ýû÷à 8qâ333Cxx8† %@’LLL(^xóæ ÃÆqz €0„ÝÝÝ‚ƒƒ€ ‡ABB‚ÁÉɉAHH,‡n@± »˜¨ àbâââà°ÙŽn@a€¬ ªª %zÑÙ @pŽ= N8Ȇ!Ó0 Ü«0>@Ád™a8æZ€É¢HiAê°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-css.png0000644000175000017500000000100710512722433030640 0ustar frankiefrankie‰PNG  IHDRóÿabKGD.;* åò¼IDATxÚ“ÍkQŦK!«]Tn "â`!]ÖEÅ]PZJ‘ú‹âBÜhý ÄÚ]‘.Tè*ˆàJ ˜é4J*TA’,D35Æ)Cc ¦ÎÌ».dBÌ›`.œÕ»çÜs.÷ÁßJÒÎÒ¡D) ß÷Ŷm1M3It¨Õj¡°,K\וd2©9ÙÓ"@½^µ—J¥Èf³T*J¥étºÉðŸ à ‹á8[äóùÞ5J©ŽB…Bx<Þäö¶6äìûÜ{ô˜FÃcw·Á­kŒF)ÕÒø¾/ŽãÈêÛu9=}EJÎOyùnSn,>—³òôÅ+©V«bYV°H´ˆ·–8Ÿ˜¤¶Ó íáÀ>ÅÐÁ!î܈ˆhµžç10pˆâ·-ê¿~S,WÜËï^h„Þv‘ž¯×ßàl»ìöc¶93v”ÜÇ<"¢ DÚܼz5ó_¿äØÙÞdtä0KV˜›9׃“Ç1i†ù»Ë?mÐ××Ïõ‹SŒ†:ÐD„ø)ó‰Ñln%v\b&“Áu]ípÚ'–Ëe€\ûÌuù\ˆ¢áN ZõdIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-bla.png0000644000175000017500000000120710512722433032374 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFýIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þüæB~~~8{íÚµ 'Oždxþü9ÃãÇ8ÒÌ’ <h;Ø–OŸ>1ܸqƒáêÕË ×®]CQ@^xÿþ=ƒÄ222PñÝ»wÿ=ú/²a o ‚11|x÷žá×_ ¿þËC-„€bˆ$ ñ—™áþá Ÿ¼gøôú V5„â‚Í›7ÃÙ¡nž gøùéÃßߘ˜ÁšA®@„ˆ7nd8r胺Œ2÷×ï^ݹÎð÷ß/F¶ÿ ,\Ì ?`z €P\°nÝ:Y9Y†o5ð0Hé0Üúõ•!»¼€AÏP«ˆ =êù…þ³³2ügee``X´|ƒ¼¼<Ãþýû±"@a¤&f6nPâb`åfe¸{÷.ÃìÙ³XXX°º €P xöìÃÇOïX ÿùË7`2Fшˆ7˜@€é=aØøôéSuÆ ˜‚l"³3 §À\`UQo`oÙ€ IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-desktop.png0000644000175000017500000000111510512722433033305 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÃIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È1÷þýûÿïÞ½ã£Gþ‡˜ ñ@±€L˜0g=Öm»*rLÁf~ýö…aò¼ë >^® )°pbyƆ€{¤¦ÙÅ)‘áä‰K fZ¿ÁâèÞA7 €X@ Dq1E]°-LLL U5©`¯_¿føóç\H ŒñëÏo¸-Ș0\ ˆ d;ˆñþ݆=ûæ3033Ãm ç£@à0Moaè˜ršá÷ï_ [¶OgPS—a8u¸È‡-ˆUxÁÓ§OáoÞ¼Éàìì OHD__¾|‰brôá D€‚"0½ðC3º“A®‚«0>@Ád™a8 ûð`ÿþäçIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-blf.png0000644000175000017500000000122510512722433032401 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È†Þ¿Æû÷ïÿŸ‘‘ˆïÞ½ûôèÑÿs!^ €¼••• ŽŽŽ AAA Þ½gøõãÃÁòP á €˜Ð£¤YDX˜áã»w ™î¾ÀðñÉ{†O¯¿ B  2góæÍ 3fÌ`øüñ#Ãíž^¹Ä ªªÍð÷÷.v†¿@Í0WÂ@¡°qãF†#‡Ž0üxûAX^¨ñ7Ãß¿Ùþ `føùÓ „ëÖ­c•“eøöñ'Pƒ”ží__²Ë ô õ°z €0¢Q_˜á?;+ÃVVv!†EË—1ÈËË3ck  ºL,Ì lÜ ÄÅÀÊÍÊp÷î]†Ù³g3°°°`u@¡ðìÙ3†ŸÞ10°@"þó—o ÀdŒ¢=n00Ó;zðñéÓ§ ê*Œ@0ÙDfgN¹ ÀË'tÐZ©§IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-php.png0000644000175000017500000000120310512722433032421 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFùIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† ᆼÿæU†ëׯ3X[[à  &dÛ@šAašê«à† åaÁ@±`D ,Z0›áë×/`§÷õ´2|ýò™¡¶¡E Š @¶€ÀÍ›7.\¸À°}Ç.†[·î0üüõ ,.** ÷" z ååf3È+È3¼yûèß› |üB òòŠ !A>p—"€Â0`Òä© =a06Òghnnbpttò1¬Y·«Ä‚Ìyñ⃄„ƒ0Ðîß¿Ïðéã{†cG2|ýö,ÿôéS ÷n¢@ð”J²À„‚’ömPøOž<ù¿wïÞÿ‡@ €XÐ ÙÒÒÒ ûö³A©&ˆ7àèÑ£ Àô—%_˜¦7nÀÅ¡\…ñæ…l"³3 §À¼`†P{€+mlïIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-dc-rom.png0000644000175000017500000000113310512722433033015 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @´   ƒ±¹\ÑÙ“7€šßÙׯ_g°¶¶†» €XMÙ Íîž® Þeøúõ XLHHL9rÅÄ„ìTxùh98¨²3ò~üø–{ûlŠ: Œ0h™¶†™™Œ­˜×Ð8bÈ‹È €0 ¨É … Xcdp:Ãß¿ u9¡X]@´ÍXÇÀÂÂ6dö‚ @63X¼yêj¬†UÁ þüaxúì1Ã÷o?áj³±» €0 —‹`øõëÃû÷o>}ø × "ŽÕ€B‰ÆgÏžHKK£(:wê&8‚À7PänÀÑ£G€éÌÞ»w/Ü& ÓøôéSu¦ €` ²‰ÌÎ0œËL…ž?æפIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-authors.png0000644000175000017500000000114410512722433032004 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÚIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉ص{???ÃÇ÷LMMÁìwïÞ0\»v E@axáýû÷ÿ6ú‰½{÷Œ=ú/Ü?þdØ»oƒ   ƒ¤¤$ë¶ LLŒ g.[Å„„„€®Z ³ÀÐf`ffføðë—~þøÇ .p˜  ¶¶¶ð0 ”08þ ƒÇA Í_¿ük~òä (°‘@¡ ##¦ü@UtüèW0Í‚á€b  L ~ÿ»$¤¤ÊŠšú@¡sÞ±#?Dx1lÞ¼žAhÈ?„<ºÄ‚î‚iÓz¼\Šž={{úô)ƒ´´4Ãê5˱º €PbáåË—( `ld±7n0¸ººÂc €à.&`zÇ«æ" ¸ ãLA6‘Ù†S`Þ0)jµËAØIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-blv.png0000644000175000017500000000122510512722433032421 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È†Þ¿Æû÷ïÿŸ‘‘ˆïÞ½ûôèÑÿs!^ €¼••• ŽŽŽ AAA Þ½gøõãÃÁòP á €˜Ð£¤YDX˜áã»w ™î¾ÀðñÉ{†O¯¿ B  2góæÍ 3fÌ`øüñ#Ãíž^¹Ä ªªÍð÷÷.v†¿@Í0WÂ@¡°qãF†#‡Ž0üxûAX^¨ñ7Ãß¿Ùþ `føùÓ „ëÖ­c•“eøöñ'Pƒ”ží__²Ë ô õ°z €0¢Q_˜á?;+ÃVVv!†EË—1ÈËË3ck  ºL,Ì lÜ ÄÅÀÊÍÊp÷î]†Ù³g3°°°`u@¡ðìÙ3†ŸÞ10°@"þó—o ÀdŒ¢=n00Ó;zðñéÓ§ ê*Œ@0ÙDfgN¹ ÀË'tÐZ©§IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-jar.png0000644000175000017500000000120410512722433032407 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFúIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È†Þ¿ÿͬiÿõþ‡*ˆý÷“ýßäÿÿöíÛÿß½{÷ÿèÑ£ÿ!æB¼@(.yÖÍŸÍ0ÝHŠ¡Yš“¡R•a?Ð ·oÜËC-„€bA–’’i†²ÇÏÞ½üÇðáÛFeU†Ùsç2˜ZX`@,èÞaaaa˜º|à ÿÓ§Ï Ï_¾d`eŠõ÷ƒåa®„€ÂðãžáÛ7 7¯^føûãË¿ÿ þüÁê€ÂpHáÍëW–.œÉðìÙsaaa=# °8<ñ €bAwÈöî3ܼvuOÜ`xóîÃf.¬. &t„…†2,^º’á'“ ÃíÇŸž¼g`øòãCPPV†ŒŒÁ) Ðè@p€ „˜ÞцOŸ>QWa|€‚)È&2;Ãp Ì;ÅÅ‹”ÐÁo*IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-e-theme.png0000644000175000017500000000067610512722433033173 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ0ëûaåKIDAT8Ë“¿jÂPÅ÷ÖÁMt:}»ø¥S]òÝú}Ÿ¡³¯H‹"´T§BÀ¦ikD(¥Ñûu°7hþ¸|çû\;µ9—äHŒ1™Þn·âû¾ôû}ÒÎ X­V™ E‘t»Ý‰Ú `½^gâyžÇh4" Cæó9½^/žÕHDh6›T*–Ë/¦ÓéÁyŠÀ“0›ÍhµZÙÆ\×¥Z­¦lÏmUiƒëº8ŽÃxòÀ>Áë'W·Ôj5‹E*à€ÀqÆO÷”iP¦ÁÙé9®w/IV,%»>N<Þ?^ˆ6†Íæ!|û.®#)J¡ôîÝ'ZÇ…J)´R(4(uб Cêõ:ZCò6;N1ˆAêî÷Ÿ¹q8EQî°Õÿ‚çdõ›#gëk;ø&¶ %ü yïIEND®B`‚././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.lotus-1-2-3.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.lotus-1-2-30000644000175000017500000000112310512722433033174 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÉIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿËðêÕ+óAr¨ C€‚eCiP–r8¹’O^ŸïÀÝénÌ IdæsfˆªŠ+¸ƒ@(.¨¬¬„ÛêèèˆáZ^^^¸ ˆ YÂÂÂÀ´™™V¦ˆ݆•+W‚Ù'Ož„Ó ñ'N€ù —"€bB7 $$¬äL ·µµE$$@ð0&`  rrrÓ—/_†ÛnaaÁ`nnXV€h0}ïÞ=%%%°&Aè. V­Zf£Lƒâ€É«Å  $‹¬xÀt滹¹10¸ººÂ½@ðX&†ß¿3 G+???~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ ›†û÷ï3 2HJJ2¼yó†ÁÔÔ”ŸŸŸáÝ»7 ×®]CQ @^xÿþýÿÊÊJxÀuuuÅÞ½{ÆGý ˆÅ o€ÀòåËlll/^ ³,cÃ@1¡GËþýû€¡ÎÌÊpùòe†óçÏ£F &tï,]º”!66l,\¸áÏŸ?`y˜+a €àaŠïÛ·oÿgggÇH@ÜÜÜÿŸ={öÿÅ‹ÿ1€„₵k×2üüùì—/_25€Å¾~ýʰzõj¬^ @Η——gPWWgºì\KKKQQQ†ùóçc D€bAæìÚµ Ù[pö… à¶£@,èá®Ý@ô@ ¸ÀÂLïx5ƒÀÓ§OAÔU €` ²‰ÌÎ0œs-@€DÛÛ@i‹–IEND®B`‚././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.writer.template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.wri0000644000175000017500000000103710512722433033601 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF•IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ²+‘@axáСC`Û¾}û @âGŽÁê€bBw 8:aQŠîEtˆÝèND—G7 €0Âàøñã6ãs@a`aaU3ŒFw!@Á 8zô(8¡àÒ OŸ>QWa|€‚)È&2;Ãp Ì;Gzj þ@¯ IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-text-template.png0000644000175000017500000000036010512722433032676 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~üIDATxÚí•Á!D¥ñ¿?ƒ/›Ü´WÒj1ÙC禇y!J¥“ˆˆP6«ùJÌÌÌòÖÍå¢ö&ÙS233ç»»»_÷ëüUc©ªªÎyäeüÎpšÑ`ROjÃõ™Är½AVò4¿H#°ª?4«Þ—@ôtf+À»ÿ;>ìé =˜p[.ñœIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-x-font-afm.png0000644000175000017500000000113510512722433031044 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÓIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ ›†÷ïß3ttt0ôôô0|ýú•ÁÔÔ”ŸŸŸáÝ»7 ×®]CQ @.ÑGe:¬ÀÕÕ•ÁØØæU†ëׯ3X[[Ã]@(.iË—/3ÈÉÉ10\¼x®$cÃ@1¡GËýû÷>|øÀ ©©É ¥¥ÅðêÕ+°ßQB Š @’ ™˜˜ôôôÀ†€l=þ<ß?Àò0WÂ@± s¾}ûÆpãÆ `܃®^½Êàìì + Š ÙÀ ** VüèÑ#†U«V ÑÖÖÆ0 €P¼r>///ƒØ Ãddd899ÁÞÀˆFP€ÁÂ9\é›7o‚½‹F€bAD|š‘£n(ñÓ;^Í ðôéSp¸ÂøSMdv†á˜k .ft¬™„ŒðIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-basic.png0000644000175000017500000000114210512722433031246 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÓ 5ª(ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ !IDATxÚS;Š…@¬•—x½„¡‘éf^a³½„'1ñ‚Šx€ÌAE Õé –üŒO ‡¢?U=#ðz€O\1ƤXוªª¢$Ixç²Á8ŽR¤iJó<“ïû'%›˜¦I*/ Cäy޶mQ×5â8µ n‚ˆ`š&4MCßÿ¢( ¼µ0 Ã|APß÷”eçpRÀÛM&ypŒ±¯«‚mA€(Ф9¯£ßm?[–˲@D;•R ˲Àó<èºÃ0Ïq«@Qxž'½í÷­×u¡ª*TU…ëºb²LxH뺢ëºÓ”ãä²,aÛ¶¨}´Ä-w\¢heæy¾õÜ4 üwôýðwæøâ…û[7Úr¤²IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gnucash.png0000644000175000017500000000105710512722433033271 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¥IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖp ²"dÍ0 èòèâDPh• …˜ D€bA·åçÿß ¿ÿýb¸óù!ÃÆƒ˜€.µÕ°e8öQWa|€‚)È&2;Ãp ,F4F"J£Ê\IEND®B`‚././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-presentation-template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-presentation-te0000644000175000017500000000171210512722433033555 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<\IDATxÚbüÿÿ?ƒgvµÖ¿¿/üøñõÿïß ¿~|eø¤ÿÿûË’gddd`bfa`cçd`áà``fbb`úó“ÁJO£ €X€€‰õ?û!>QgKME†ÿD„¾}ûÎ`inÆ &*ÊÀÁÁÎpú܆7>3ðñó a`xøða@ Ø6­ñeXaííŸ?þ9»;90HIˆ3üýû—™™™¡¢®‘áɳç <|ü b’`Ì÷å+#Pþˇ¼Ät£¤¤$çϯŸ>ð 2,^µžaËÎ] ¿~þ`z ètf° b££N\¼Êpáæ=Nn.†ÿ@ùïÞ°A¾ÿ"""øøøïèçìæçÂÂÁ÷öõþüû»¯ª(%$õööàäæÊ¥­óúþûôñ÷òúˆåׯ_b@_¨‡z»Yg¦$‚ˆëY2°rr30ŒYÙÀâ¿>½cfgø@,²3fÌhTVVVØäÃÓç/.\¾ÂÐY_Í ªkÁÀÔü—™á?3Ãß?ÿýÇΟßøD…Ïã©S§Úÿýû§¼ d20Hþ£îùmçÎ[ÄÅÅXXXà®ú ŒâÕ«W3¼}ûÖ €@(ßßß`dd4áÛé] ¿÷Ìg`úù•Ÿ…ƒ™‘ˆ™é€‘“—;´”ÝÒ¤‘aåÊ•O²²²ddìkM...†½³ØÍœ˜eÕÐÁßÇ·¾,ªðæÍ†Ÿ?î‰˳gϾi}HŠ&* f.¯t ¾n›ÉÀøè8e‚ ‚;  €À&Iý( 0Fqˆü—/_˜˜˜^ƒÄˆ(l “ÿ†50¤Q‹aÀo øo  ¹?þ€\ò$@`¾}ûö” ²£ìþ †›¦cºàÍ6d`¢Ù’3àÐ F÷4†Ï[f0ü¿pÃfQÛH†?ÀT p +ô@â6è§‹¬¬¬N_ä²g¡heep8]üž‘á?0A™ ˜>¬@âòõ^2aIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-afm.png0000644000175000017500000000110010512722433033335 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¶IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖp ²"˜æãÇ3œ;wŽáÏŸ? ÜÜÜ ®®® rrr`y˜A0@,Ñ ÆÆÆ lll gÏžeؾ};Czz:Š tg‚00Ä6nÜÈðìÙ3÷¾~ý v ²+a €˜Ð½R¸dÉiii†¬¬,†ððp°¡ 9l^ 0111|ÿþA[[›•••áÉ“'(ˆn@a"[ZZ2Ìš5‹“““AOOAXXî=tÀ$ËðêÕ+ [Ðm¾yó&ƒ³³3<k âÒŒ-nÀÑ£GÁ¡O3<}úD]…ñ¦ ›Èì Ã)0×ãg}ßiéêIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-python.png0000644000175000017500000000134310512722433033160 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFYIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡ÈŠ ¾|ùÂô3Ã×/_ÎÝ=ʰéÌ<†‡Ïî1ø$1„¸&0°³³3\¿~ÁÚÚî€B1àÝÛw Çoíf8üt%Ãÿ'>3¾d`|-Ìðáñ/ö7Ò S‹×€ÕØØØÀ  &d§<³ƒaëën†w3<¼üžå;ç‡ÿ¾Ÿdøò÷ÃÄ%Ͱ@‡€B ƒU·º~1}axõõ 7ÃËc¬ \Ÿ%ózôÄ,î>¹Êr)2 $ë1|½ÁËðù3ÃËSÿDÿª1äûµ1‰òÃç7† Å€Š˜^†`Éþk¬ 6šž © /_½dX½¹•áé{ ’üê 2çäþÝ fˆKoeRPcàfg`zp›A@\šAžÙšÁRËÀ‚Ç(úŽ:À +¯ÈðûÏ_&FV 8ÿ¿ÿ~üüÁðôÙYY†/^08;;Ãc €P\ ¢® ¶3 ÀÁÅÅ ¨f?{ö Å7àèÑ£ ÀôŽ’‘ixúô)ˆº ãLA6‘Ù†S`™ Àer§Ó‡žåIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-smil.png0000644000175000017500000000076110512722433032341 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ 1«›~IDAT8Ë“±ŠÂ@Eï.ˤ ••66Û‰XZ Ûéˆl¡ì/ø–)ÅOP°Z/Š   ""*)4dÞn²Q3«n3Ì»ç¾Ç p©<zB !å8- ê÷û®I^j°ßïeÙ¶Mívû.É‹ÏÇã10^¯×Ãp8Äz½Ær¹çÜë}ó_ ‡ÃW¥R ¹\™L“É£Ñ7Æã±|§Ó‰Îç3Y–Eóùœ4M#T.—i»ÝÒn·#Ó4Ý1¯~EQÀC¥RçÉdº®#£Z­B" Nà8ιP(iš4 u»]2 Cžà–œN§Q¯×FQ«ÕÐjµ „'‘;Ž7;ç\žà?r"‘¸nvpe „c ÙlÍfÓé©T F‡Ãá±c ¡P(¼ÙlÄb1D"¨ªzGžÍf^JyOY×uضý·Õ_Ò-qµZ¡X,޼ûÏ¿žüή>ÝÆ 5F<Ó+IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-c.png0000644000175000017500000000120310512722433030535 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFùIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† ᆼÿæU†ëׯ3X[[à  &dÛ@šAašê«à† åaÁ@±`D ,Z0›áë×/`§÷õ´2|ýò™¡¶¡E Š @¶€ÀÍ›7.\¸À°}Ç.†[·î0üüõ ,.** ÷" z ååf3È+È3¼yûèß› |üB òòŠ !A>p—"€Â0`Òä© =a06Òghnnbpttò1¬Y·«Ä‚Ìyñ⃄„ƒ0Ðîß¿Ïðéã{†cG2|ýö,ÿôéS ÷n¢@ð”J²À„‚’ömPøOž<ù¿wïÞÿ‡@ €XÐ ÙÒÒÒ ûö³A©&ˆ7àèÑ£ Àô—%_˜¦7nÀÅ¡\…ñæ…l"³3 §À¼`†P{€+mlïIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-drawing.png0000644000175000017500000000205610512722433032654 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<ÀIDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññÿüü÷÷÷ÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=TätuuØØØΜ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™fÍšÅðáÃ!!!†§OŸ2$&&2øøx346·˜ÊHI &í’’’œß¿~ø ÀÍÁ0qî"^YU%-=†òòr†‡‚m·±±a:n_ksÓ§OmˆEII‰ïÇï_<—ýôõ;ã'OþýùÍÀðŸ…!??¬éׯ_ _¾|a¸sçØþþcpvrdxõòå€bJŠ Tõq³ÎLNd`fbb@Ó¦Mc••egHOOgZÆðöí[†={ö0(((œ  Ù3f4*+++QWa|€‚)È&2;Ãp Ì;o'Y¤ýË«IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-spreadsheet.png0000644000175000017500000000175210512722433033532 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<|IDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññÿüü÷÷÷ÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=TätuuØØØΜ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™fÍšÅðáÃ!!!†§OŸ2$&&2øøx346·˜ÊHI &í’’’œß¿~ø ÀÍÁ0qî"^YU%-=†òòr†‡‚m·±±a:n_ksÓ§OmˆEII‰ïÇï_<—ýôõ;ã'OþýùÍÀðŸ…!??¬éׯ_ _¾|a¸sçØþþcpvrdxõòå€bJŠ Tõq³ÎLNd`fbb@Ó¦Mc••egHOOgZÆðöí[†={ö0(((œ  Ù3f4*+++{Áð˜Xÿ½dH­ýÆÀÂÊÈÀÌÂÈÀÄŒðR¸ñ2žÿ* ‹/~^PP @ ¿–PPÕdäàdøÍ±EIç?C‚ý †jŸ{`Í Me®wᆀb˜~v€ØÄôìÙ³oì\ú¿þüeøýû70þ0‰þcÀ?~ ¢nƒ€YÉÄ¿ÿaøÿï/óðÿgXy6 ®™ÍÌÄŽR`ò9 âÓêÕ«YÿýûÏúÿ?ÐV`²aF†ÿ !‹Šn1ü #³9˜yÁ©ôß¿ß@0‰ò22ü}Ž[>`d¹”€þþùgÿûËÄðÿ/3ƒ˜˜“È€bqvv~»`ß™ Ì,,º@‹˜€Ñõú9Ê“ñpgÃØœ¬Â ÿ~3‚30µ@böŸ¿ì~õüiìw/þüøÊðü¦ ƒÀ£p^^^pƒï {wgm`:p âM[™úƒµIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-it.png0000644000175000017500000000072510512722433031054 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ R¹ bIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-midi.png0000644000175000017500000000114210512722433031107 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÓ 5ª(ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ !IDATxÚS;Š…@¬•—x½„¡‘éf^a³½„'1ñ‚Šx€ÌAE Õé –üŒO ‡¢?U=#ðz€O\1ƤXוªª¢$Ixç²Á8ŽR¤iJó<“ïû'%›˜¦I*/ Cäy޶mQ×5â8µ n‚ˆ`š&4MCßÿ¢( ¼µ0 Ã|APß÷”eçpRÀÛM&ypŒ±¯«‚mA€(Ф9¯£ßm?[–˲@D;•R ˲Àó<èºÃ0Ïq«@Qxž'½í÷­×u¡ª*TU…ëºb²LxH뺢ëºÓ”ãä²,aÛ¶¨}´Ä-w\¢heæy¾õÜ4 üwôýðwæøâ…û[7Úr¤²IEND®B`‚././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-rhythmbox-effect.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-rhythmbox-effec0000644000175000017500000000120110512722433033672 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ &9ÊOIDAT8Ë“?hQÇ¿é½ju)X\MݳT¤ƒÒDAÎÍ1Eê¤"R”$à .Á$Æ2øg°TbR¢½óî¼Ëõ‹^îýÂ9“B|—÷ø~~ßï08‹hZÀ6‡ž U1ˆsÈóàGL¥R¸vãÖß[?påñ2Òé4tÍÂZKI,Ñó<Ò44M#QIDQ$UUéÞí§´ò¥A¥R)´ÄȺ®D€Â³7ˆF'prá’ÉdàÝŠA„H$Äüel k9˜?5‡èÞÁ’›«j>î8g˜Œ³àþó‡¯h5õñY–áºnæll¡·ùv÷7š«?15Å‘c1Xù¿æå~g_—|ã?êÉf~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ]1???VCZ[[®^½ÌpíÚ5q€ÂpÈ€÷ïߣ(dx÷î˜}ýúukkk¸ Å C`š¡a0Í ydq ähÙ„ € ‡< Œ0¸¿” C³bô7†?þÀ] ŀׯ_3ãÀ/Ñ]@(€$™˜˜ÄÄÄpzeÿþý(|€ÂD˜M¸¼‚î€Âp0Jž={†"£Ÿ›(¥”½PŽ€»»û€ )‰ˆ\)V¨ªªÖu)õ÷&€F-Ðô6§ß¼÷ê ŒÀ^—+…+€T0ÜÝ‘šãüo+ÿM`V*ºWÀÜݺu/ ÃÇÀ[ÀPáL¼îýw[x'FüPzå(0ËtÇ}…%vÞsÜœ_¾L?¬ã„IEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-dia-diagram.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-dia-diagram.p0000644000175000017500000000103410512722433033446 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF’IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™aáÂ… è@ZZšáäÉ“ ÏŸ?gxüø1Ã@šArÄ€l½&*pí/ƒ,?ÃÕ«—®]»†"@.ÑØÔ« ׯ_g°¶¶†» €P\€¬Ù+qqqpy˜A0@LèÑ ÍÚ§Î3dÔv€éE‹¡F tg‚pLL Ãb }ÅÔ,ÅðçÏ W‚@axï`vdd$V¯¡» €0\ÀÄĦ—,YŽŽ†kD7 €˜Ð]rêâÅ‹´…O3d6€ia Ø €0\ŒR†( Ÿ—-c`¸òÆ, ÷º„5aac#‡z Ü€£G2Ó;F`¡ÛøôéSuÆ ˜‚l"³3 §À\ `ø%Tõ8ga‹IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-formula.png0000644000175000017500000000205310512722433032663 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<½IDATxÚA¾ÿÿÿÿJk|*þþýÐåèêìêèúñí‚mcþüïññÿüü÷÷÷ÿ ýk&&&žÿˆd#D”6í~ôä™óÛ·Ô$¢ý=TätuuØØØΜ9à !!ÁpêÔinn®Ó ÄÂþÞæaguÞ»dƒŽº Ãß¿˜™™fÍšÅðáÃ!!!†§OŸ2$&&2øøx346·˜ÊHI &í’’’œß¿~ø ÀÍÁ0qî"^YU%-=†òòr†‡‚m·±±a:n_ksÓ§OmˆEII‰ïÇï_<—ýôõ;ã'OþýùÍÀðŸ…!??¬éׯ_ _¾|a¸sçØþþcpvrdxõòå€bJŠ Tõq³ÎLNd`fbb@Ó¦Mc••egHOOgZÆðöí[†={ö0(((œ & ÙC‡5æ¤&+9qŠaɪu …5 ÿþýchééeàa``øÅÊÎðáÏ_1ii===`Œ¬ –¶¶6×7oÞÜL*«×}ñæ=3Íðëó{†×?2HJ2|þð…áÉÿWÀ˜zÍŠ1}Ey#} ¡þüÙ@,þþþ3´ì\xÅ¿ÿc`†ƒ(CfB,þ+7$…¬ÍX˜˜þüûËÀËÉÅðéÓG†Ÿ?>/((¸@ ¿–PPÕdäàdøÍ‰Ug{;k}=w#†?1\{ø„—‹“A„•3@×ì© ¦gÏž}cçàÒÿôßïß¿1ð‡AYAl6æ|âÖm†7Ÿ>ÃöñãÇ ê6ˆ Xâ÷ï? ÿNaq†@ÿ^yøˆá0 «(1ˆñóÄAQ L>'AËêÕ«YÿýûÏúÿÿ?`ÜÿcF&F†[Ÿ2ì={™Aˆ—¬ùÚ£' 1ÃÍÁN¥ÀXú2 €X€I”—‘áþ;`üKƒÝÂÈÈðâå+†}.1|ÿùŒW8ÂÀ4ŸFªŠ bbb ïÞ½³ª>@,ÎÎÎoì;s™…E—è&†ë·ï2tE„0à·þüyE Ä p°øüe÷«çOc¼{ÉðçÇW†½1,’—dàåå'tÊÚÀtàb5¿v–dmi™IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-ac3.png0000644000175000017500000000106310512722433030635 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ %Œƒ‰bÀIDAT8Ë“½‹AÆ,Ô&r]þ2M$¤ÑM%j—ÿ@ÄÆæ"vÂa$W[Hl wX‰Å’’Ť²8Ì"—¸!FÈ:É^ÊÍîkqì^6p;3¼Ïï}f˜…ËQäzÌ–!¾ïo”çy2 ¤ÙlÂV€ã8¡:Žâ8Ž´Z-q]WªÕêZ’%óùÓ4Éf³8Žƒ®ët»]Æã1ÃáF£zc«QóÉÑá%Y„L&C<G)›^¯·?P¹\@NŽåìשR,e:ŠRJ”RbFPxÿî@^ï¿ÍÖï3¹¸˜ ‰D"4Û¶-ív;ˆ|üL©Tâɳ—LgNXÏç#ñ7aÏó˜L&är94McÿÕ•J%L°õ–ã¥R)êõ:š¦E"¯~#GXø¾O2™¤V«Eö‚î/À0 \×Àt]Ç4͈a4ü\}ϯù;zÿ¡úSÀ副…IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-rtf.png0000644000175000017500000000065610512722433032173 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“cIDATxÚ“¿jÂP‡?K—  ¤H) E¢‹“8ˆ¯ÐÍ'(´S÷¥ƒS_¢/àC8ÅAŠSÐd)D„ÒE$J ¹§ƒD“ îùßýî?ØG3òŒ¥TjA ®ëŠiš¡I'Ó`½^§æh4ß÷¥×ë%Hr6› Óé”Ýn‡¦i ªÕ*ý~ŸÉdÂjµb±X0 ½—Ç(F#Ž&B³ÙÄqf3‹ù|«'†Ã!¥R ÏóØn·ÔëuŠÅ""€mÛ´Ûít¥T¢!¤ëÑù˜ˆ "X–…®ë¸®‹¦iäóy*•J¶AhÒjµ(—ËqtTJe(¥°mÃ0è~|ÆÄÝ·çÓµZ-&º»½ÇûSüþ¸‡mFã"Àq‚ @¿Îqs¥NbH`FLd~}ïkH*A *x}<ÿÇã1¾ï'îþxÅår 0;~Á/g~ç0ŸÂÆ3ê+ÂÆòâ°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-gtktalog.png0000644000175000017500000000130010512722433033444 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF6IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈅PÖPƒ³Ï<ÍpãÆ †«W/3\»v E@axáýû÷ÿœÌÿ¯ÞÖõÿÆÃ=ÿëÛ2þGGGþ÷î=zô?$ ^ &dÃ@ÞX·~CESƒµ­Ãý·Ê+J$Xîß¿–‡ZÄ„-Óº:xþ3ôWOaˆh`¸q냅•äI“!% |}¶ÎÏÀÎÉà[Π(­Ç "$Èðä ;Óïnݺv2 /䤤0üùý‡!½ ‡áöý[ ‘ή í ] ׯ|fèê›Í˜œ†á€B1€KHˆáó §€!þüõk â ËdUgààcøøá†PŠË ÿÿÿÖ­ÿÿî?øÿÿáÃÿk'NùæÂÿ¿ŠŠ«»þ§¤¤þß·oJ,J˜ÃÀ?)‰ÁH_Ÿáæ•+ ß|bpyü†áNÃ}†§.1lݲ™áæÍ›( œœœÑ]‡B£"@Á &`zÇ©ž>} ¢®ÂøSMdv†áXöª”O~HêÒIEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-pgp-encrypted.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-pgp-encrypted.p0000644000175000017500000000107710512722433033632 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFµIDATxÚb`€% þO–b@Cÿÿýû‡ÿýû÷ÿƒþ}b˜Ô$jgÇðîÿ˜0ÈõŒÄ„ìT¸ºp!X Ÿ«©aøµ±AVP€bB÷/¿;{–át^XìxRÃßïß–Bå@^…‚¿ -ĄͯzÍÍ Œ,, ;¬¬ø45´ššÀâ Íh.` &\fÜÛË È UR‚â:t/ ºFPZøñã(](de1|ûöáÑ£G8]@,èa`aa3Ñ\„bÀþýûQÀØÈ4R ‚ˆÆ8zô(Ãïß¿qj†§OŸ‚cw"2;ð5,Ü&±Œýd,IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-zip.png0000644000175000017500000000177210512722433032202 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-deb.png0000644000175000017500000000177210512722433032377 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-sql.png0000644000175000017500000000066310512722433031123 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ +‚¿¹}@IDAT8Ë•“=KÄ@†_!­ÿA-<+HiwÝr½Ü•X]'V'ø´´+L‘‚¦öÒ!]‘âŠ%;’dÃ2;;Ͼ³ÀMп@ç¼Ó‹¢ 0 ɲ¬2él·ÛN·m›c¤iš d¯@žçò ÀëºH’QÁ4ͪVj/^ŽÇøf½†¢(‚ž÷ ß÷ñk U¥$ÑN’h¡ª”eeYFišRš¦ä8NÙœs‘LÔÈ×〈ªäƒ,ôýSè—·Õâ·×û~@ ™­VU¬Oï°9xŒÂ9ˆHP)´°yŸÖfÑÎÿ©Ô³ŒÂ9ºÚtˆ³/Ë/ÿWðá sí±ptö,Hn_e'Àq0Æzw.-ŽcðÚïåzàw.ýª,ü¾ƒ˜öC[IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-tex.png0000644000175000017500000000107110512722433031116 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¯IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† €z•áúõë ÖÖÖpˆYHsGGCEE˜‹¿~ý L—–– ‚€‚»Ú ÀcÀ@jnܸÁ`kk w@1¡;d3Ì%sæÎkš3g.8pAòè^ ¼{÷¬¹ÀÁÁî€bAwÁ¢E‹âã㺻»Áb p…ˆ¨(C|\FŠ ^¿~3`ܼy“ÁÉÉ î€ÂƒÞÞ^°+@Ä^¸hX|áÂEˆä‹Å/_¾DQc#‹ÂÀÕÕ‡ÁÑ£G€é¯fxúô)ˆº ãLA6‘Ù†S`Þ0鼎ÆMèŠIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-sms-rom.png0000644000175000017500000000113310512722433033231 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @´   ƒ±¹\ÑÙ“7€šßÙׯ_g°¶¶†» €XMÙ Íîž® Þeøúõ XLHHL9rÅÄ„ìTxùh98¨²3ò~üø–{ûlŠ: Œ0h™¶†™™Œ­˜×Ð8bÈ‹È €0 ¨É … Xcdp:Ãß¿ u9¡X]@´ÍXÇÀÂÂ6dö‚ @63X¼yêj¬†UÁ þüaxúì1Ã÷o?áj³±» €0 —‹`øõëÃû÷o>}ø × "ŽÕ€B‰ÆgÏžHKK£(:wê&8‚À7PänÀÑ£G€éÌÞ»w/Ü& ÓøôéSu¦ €` ²‰ÌÎ0œËL…ž?æפIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-rar.png0000644000175000017500000000177210512722433032431 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-x-directory-smb-workgroup.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-x-directory-smb-workgroup.p0000644000175000017500000000041610512722433033631 0ustar frankiefrankie‰PNG  IHDRóÿaÕIDATxÚÅ“1 „0EŸ‹‡°Ñ9Aî!x¦ÝÂ=ŒÇX°ñVbe¶I/ÄÒ­”$Ùb’ óø™üÀ¿#‘½0MÓ5‚Ûìs` 2)ÈED; à ¬¯¶%Ë2Œ1Xk©ÊrW½ÅMDt×uŒãHÓ4¸0c ó~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ ]ñ… øùùÁ4ƒ,055‹½{÷†áÚµk(êà ïß¿ÿ v*ˆ ÃïÞ½ã£Gþ‡Ä Ä‚lÈ [“’’À|AAA†ãÇ3¨««Ãå¡Â@ÁÃÚ @À%„„„àl Í`¤æÆ ¶¶¶ð0 &tï€lÉÏÏó_¿~ ¦ÿüùƒÉ#€‚‡(¾àþñâƒØÈbÀ@ €bA7lñâÅ Àxy‹áâÅ‹ »víbpsscعs'"ñ €ÂÄgÏžÁý«££fÃİ"@a„ÁåË—nݾ æ_ºt‰áÖ­[`ñ›7obu@axf+2d³ŠŠ Ö@ ¸ÀÂLïè‹aãÓ§OAÔU €` ²‰ÌÎ0œó@€ì&Ÿi1$šIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-bdf.png0000644000175000017500000000106610512722433033340 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¬IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖpŠ `šûúú´µµTTT,--€a—‡Ä„- Èpúôi†»wï2$''3äçç£F tg‚ðÏŸ?RRRΜ9ÃÀÌÌÌðúõk†?þ ¸à …ÞÞÞ VVV`ÿnذl(H›ÃLLLÀÐ~ÇÂÀÉÉÉpâÄ ”@D7 €°º ´´”ÁÜÜœAGG‡áÍ›7 pW @ðh&Y†W¯^aØ‚nóÍ›7œáÑ@X—fl@pŽ=ÊLïx5ƒÀÓ§OAÔU €` ²‰ÌÎ0œs-@€dkLŸÇEŸIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-postscript.png0000644000175000017500000000115210512722433033602 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFàIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ@Ád™a8 ëÈ–~s­fÿIEND®B`‚././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-applix-word.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-applix-word.p0000644000175000017500000000065610512722433033566 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“cIDATxÚ“¿jÂP‡?K—  ¤H) E¢‹“8ˆ¯ÐÍ'(´S÷¥ƒS_¢/àC8ÅAŠSÐd)D„ÒE$J ¹§ƒD“ îùßýî?ØG3òŒ¥TjA ®ëŠiš¡I'Ó`½^§æh4ß÷¥×ë%Hr6› Óé”Ýn‡¦i ªÕ*ý~ŸÉdÂjµb±X0 ½—Ç(F#Ž&B³ÙÄqf3‹ù|«'†Ã!¥R ÏóØn·ÔëuŠÅ""€mÛ´Ûít¥T¢!¤ëÑù˜ˆ "X–…®ë¸®‹¦iäóy*•J¶AhÒjµ(—ËqtTJe(¥°mÃ0è~|ÆÄÝ·çÓµZ-&º»½ÇûSüþ¸‡mFã"Àq‚ @¿Îqs¥NbH`FLd~}ïkH*A *x}<ÿÇã1¾ï'îþxÅår 0;~Á/g~ç0ŸÂÆ3ê+ÂÆòâ°IEND®B`‚././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-x509-ca-cert.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-x509-ca-cert.0000644000175000017500000000140310512722433033150 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFyIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™aÑ¢E È ..ŽaÏž= 'Oždxþü9ÃãÇ8ÒÌ’ ÐHþÓ§O ‹/f8vìÃéÓg^½z7 €P øñë'ÃûkÎ:ÌðáÇ)A%%CK˜W®_¿Î`mm 7 €Xm{võÃü¸0Í/Ï™™Îûǰ€•Á*5‡á¯¨ CTTÜ  d§nj®apa|Ï ¥(Áðôç¥ïx>üdØ;g Ãì«O€1‚a@1!sÞݸ .ÀÃð¨ñå¿ /~ÿexࢮËðøÉc°fW‘@¡xáÓ_&†ß~1¼e`bxýë/Ã; +>ýagxÏÈÊ &*ÖŒî€Bq‚wÃ×ß>}ý Ä? ì¬ü Ÿ„ÄxøÞ¼z‰HÙýêùÓØï^2üùñ•aïÁC ‹$xL,()óÕ¡cଠLî >@€ôStð¢…FdIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-zsh.png0000644000175000017500000000120210512722433031116 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFøIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜hC¢Š•é‘,„À2‚Ë?\ræ©¶yòÈØ]TõÉÌ`f¸;™IwSUDÄÉrÌ@8]pìØ1°mGýÿèÑ£ÿ­­­ÿ½½=ÿ‹‰‰ý‡øâ€Â0àýû÷ÿ9VtbY˜ñß½{Æ ‘  &$òFqq1ƒ P3Ãó‡w:³‚Àü’’°<ÔB8 &äh¹rå üyóÀš…UŒÀâj²â`C@âW¯^Å0 €P\`kk ·ùÊÞÕ`1çP¸!ööö`W €B1× Q% ’òÊpÍ ƒn=~ÉP>mþ}û0\@(hjj2Á AÖœ_P–G7 €à±Jq/^¼øÿìÙ³ÿ{÷î‡4ÐÙ`ĉ?}úô?Ð(±@Lè†õöö2œ>}†¨ bs~>ƒ††ÃÂ…‹É <%]ÀðòåK×®]Ãpö7\]]á) €X`ÀÂLï(®ÌpýúuÞQWa|€‚™žMdv†á˜w ÚÕ¶‘7¹fIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-pcf.png0000644000175000017500000000106610512722433033355 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¬IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖpŠ `šûúú´µµTTT,--€a—‡Ä„- Èpúôi†»wï2$''3äçç£F tg‚ðÏŸ?RRRΜ9ÃÀÌÌÌðúõk†?þ ¸à …ÞÞÞ VVV`ÿnذl(H›ÃLLLÀÐ~ÇÂÀÉÉÉpâÄ ”@D7 €°º ´´”ÁÜÜœAGG‡áÍ›7 pW @ðh&Y†W¯^aØ‚nóÍ›7œáÑ@X—fl@pŽ=ÊLïx5ƒÀÓ§OAÔU €` ²‰ÌÎ0œs-@€dkLŸÇEŸIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-c-header.png0000644000175000017500000000112110512722433031762 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÇIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ]1#33ƒ¹Š ŠØª;nܸÁpõêe†k×®¡È† ,ÔÕ ²³T´u~þùÍ ÅÅÅ™’Âpªñúõë ÖÖÖp²i C@€ èŠ?0ü¾ïÐ!yh˜Á@±`D (Ê+2|~÷žñÛW†§GŽ0`S„â˜äóÇL]\dø8¹¹ÁbþüËÃ\ Ä‚Í Ÿ=døùî-ÃËÓg899QäÐ]@,Ø\À" Œ&†_ïß1¼¾zEÝ€Âê‚\ L ÿ$%> ÙŒ- À$ËðêÕ+° “¡!jB:{®ñæÍ› ÎÎÎðh /€0H²s‘=nÀÑ£G€é#<ÐüôéSuÆ ˜‚l"³3 §À\ `$Æ]L?B°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio.png0000644000175000017500000000114210512722433030167 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÓ 5ª(ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ !IDATxÚS;Š…@¬•—x½„¡‘éf^a³½„'1ñ‚Šx€ÌAE Õé –üŒO ‡¢?U=#ðz€O\1ƤXוªª¢$Ixç²Á8ŽR¤iJó<“ïû'%›˜¦I*/ Cäy޶mQ×5â8µ n‚ˆ`š&4MCßÿ¢( ¼µ0 Ã|APß÷”eçpRÀÛM&ypŒ±¯«‚mA€(Ф9¯£ßm?[–˲@D;•R ˲Àó<èºÃ0Ïq«@Qxž'½í÷­×u¡ª*TU…ëºb²LxH뺢ëºÓ”ãä²,aÛ¶¨}´Ä-w\¢heæy¾õÜ4 üwôýðwæøâ…û[7Úr¤²IEND®B`‚././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-rhythmbox-playlist.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-rhythmbox-playl0000644000175000017500000000105010512722433033745 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC» pHYs  ÒÝ~ütIMEÕ ' q~yµIDAT8Ë“½nA€¿;~nI8dx kº4†'°ìW ò‰†¤§Ï DAC$:¢4NÙü˜[nÙÑ]âð#4Ò3Ÿ¾™Ý…?q Èò#gB~>þ’ße¯qÎei­•år)£Ñ(…\Ÿ¬ž7²Z­Næx<cŒ ‡Ã#?=„•÷(¥(Šø~žB¡ˆR ¥FƒétJµZ¥Õj|Mûòÿjè8á¦sC©üUÁÃb±àþþŽù|þJÝKëŒ9ð²Ý¡JEÖë5Zk”RT*D€ÙlF³ÙÌz3c ªT¤Ýn“CPA€8!ÖÉåÃ(Š2ÐѾç#âèõzÔ®®Èv·ÅË“ÖÔëuDä< PÌ“$ N‡•œ€sXgyÖ{jµιӀtaƒÁŒáRˆ³lcMN)Êå2ÖÚóiÜÞÞ²Ùl²%A@†èxÏç/ƒË!Š¢£W¦ã=žïe5Ýn7+rNqxžçA¿ß'Þ%—G8e]ur@ÇûÓ€Éd‚1æ•=8¬µ¬CdžB!Çæå àÛÿðî¿sšŸÒÆß­¿Î†ËIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-readme.png0000644000175000017500000000117210512722433031555 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFðIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È 2çüùó µµ5 <<¼@ÿ ¾c`bdbøñóÃÚµë®_¿Î`mm ×@(Ô××14Ô×0 øóç/Ãß¿€00ÔÖ50€¼ 38 d§~ûö•áõóÇ ož?døùë'Ãß?¿†üjüËÀÃ͉y$@(.… + +ýá70„˜ÖÿûÇ·ä d@,èöë×o Í¿~ýüç7È¿Ášþ‚]‚é€BuÐ ~ÿdøÏ̤Âÿ^€iF7 €XP#æŒ`[)€ÿþ"lÆæ€BI¿ÿa`gcc`úbÔPc`¢Æê€BqAJj CWÿ4 ­Å` „ÌÌ,X €àIùСC@üF Pdž>}Êp(®âLA6‘Ù†S`®0ÇÉ„œh·IYIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-lyx.png0000644000175000017500000000107610512722433031137 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ-Þ§ªºËIDAT8Ë“½‹QÅÎì)ö6“JÄR Ø„ÅÆÊ- %#›QPA­ÄjÅB´"BÚ€¤µË×d‹„EDF$n2“ÙIv0ûé:Ì<‹%ÃN&YöÂiÞ}çÜsÏãÁq­â ¸Áœ¾ïÏ„çy¢ÛíŠz½>Y™+0g¢Ñh×uE±XŒ89wBI’fÚ+•J´Z-ƒ½^Z­p#}5"Ÿ/”PUÛ¶ØØø‚mÛwazšû»q 7¿ríÊeÇ¡Ýn“L&ƒžÄ)µîü%Óú1 Z­"„Ý &¢¹ÇrÓäBe“߆ÜY½‡íì¢>}K>ŸDV¨-þù1±E™Ýр܋7¸Å¥«ËÊeR©pFAˆžç!Ë2VóòHG쀛Ö××¶¸ûì#«Gaíaˆq[”8:Ü„±™í­>¯Ýœ™S(ÄD"ÁþŸ!xÇd÷H0Üþ‡¢(˜¦‰aT*•ùš¦¡>ùÈ/cŸ¾uÈÏþ/?uÑ4 ß÷Bœb&“AÁí÷èt:(ŠB.÷œt:}ߟ¢®ë¸®Ëô³NO4 ƒl6û¸xòüþ¿ó«â¨g%Òe#¿IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-database.png0000644000175000017500000000044310512722433031647 0ustar frankiefrankie‰PNG  IHDRóÿagAMA± üabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÔš‹ê IDATxœÅ’KÄ CM/GóÜÌœÌ]ô´4‹±d!Aò€•&ûþ¶6Ú4ô§ÖÇ€¹^õ[TE’`’@²‡_ž@Ò°ín>!S@)eX©ù1Á0Öl‚ R?–&iÛ&i’÷·ã——‘ਵžQÒ™ó‚„?í^ÝæœoÐBá¡X’%ù)ICþ)ë׸êûƒvÛ‚oŸÿüIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-perl.png0000644000175000017500000000122110512722433032574 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚äˆ ]1ÈÀ?þ0mã_¿~12ðòò2¼{÷†áÚµk(êÅÿ€ìcG2…‡buÉ‚Ùó¬­­á. &d›wmß Ö<«&Š¡(̆AG‚ƒ!ØB,ßßÙÁ`jj 38 äì¸ÔT†xo3>..EI#m%¸BY9E†oß¿b@(.q^`@=gøþ냜„(ƒš¬X<$2œ¤äUd@,èþlœ·Î.‹°gø÷3³§ÏðÃ7`:64€AKKŸáÎå ]+v2ä¸k‚Å988À¶£@p˜™™¶mÜL%Œ B‚‚ ÒòŠ s×ídxùñ+Xž‹“‹ƒÀBq¬¬,˜þúõ;ƒ¶–X\PLH>bË¡@haÀv&70ýa8wò4X4½ê?\3z Ü€£ÀJy豂nãÓ§OAÔU €` ²‰ÌÎ0œËLÜ·>2Ë~‡IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-xi.png0000644000175000017500000000072510512722433031060 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  _£ÍbIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-xm.png0000644000175000017500000000072510512722433031064 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ /É9bIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-sunos-news.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-font-sunos-ne0000644000175000017500000000110010512722433033556 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¶IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖp ²"˜æãÇ3œ;wŽáÏŸ? ÜÜÜ ®®® rrr`y˜A0@,Ñ ÆÆÆ lll gÏžeؾ};Czz:Š tg‚00Ä6nÜÈðìÙ3÷¾~ý v ²+a €˜Ð½R¸dÉiii†¬¬,†ððp°¡ 9l^ 0111|ÿþA[[›•••áÉ“'(ˆn@a"[ZZ2Ìš5‹“““AOOAXXî=tÀ$ËðêÕ+ [Ðm¾yó&ƒ³³3<k âÒŒ-nÀÑ£GÁ¡O3<}úD]…ñ¦ ›Èì Ã)0×ãg}ßiéêIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-vcalendar.png0000644000175000017500000000077510512722433032267 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÕ 7.ÜuA/ŠIDAT8Ë“½ªâP…¿\- ÀÖ·ð¦ïˆ#–¦°²±±÷l¬íüCb1þDE¢Mˆ9ûw"ÉU7,çg­½ö>çÀw|ò~ñ"D)õ¾ï‹eY2‘Ïò;ð/»ÝNúý¾â8ŽœN'ÇAøg+‹†A½^§Ûí¢”Šv[‰¬ÅæiR(8”Ëeb±ØýàívxýO2™ ³ÙŒf³I«ÕÂ÷ýûžR ¥Ôkº®3™Lp]—R©D"‘ˆØõzÍõzE×õÈUn6¶Ûm¤þ§½^ïN `>ŸGj*P©Tø_ÄŸMŒi4áyÞËšMÓJZüLðçÝOõ¿âØVŠÆ~±?IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-glade.png0000644000175000017500000000113310512722433032710 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿËðêÕ+óArÄ‚®8,,ŒaåÊ• SÖždxĤÊðôéwUccc^^^kkk¸z€BñÈ5 Í ŸdÌpü'û—{ Jü¿fî¸y$@LÈša.xÿh3CÚm‘ó‰ JJJ`qq u0@.˜Ù Ö  úÂ\W†»ïYî‚åAa… Å€·À5È/z!‰!+Ы# g©b‰C‡aõ@¡À'íÅʰjÕ*†ââb†sçÎ1iCCC0n@± ‡H3€#ÓgÏžÅꀂ'$`š'Yd06²Ø7\]]á €à.8zô(Ãïß¿ñj§OŸ‚¨«0>@Ád™a8#± %U\$®IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-wordperfect.png0000644000175000017500000000065610512722433033724 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“cIDATxÚ“¿jÂP‡?K—  ¤H) E¢‹“8ˆ¯ÐÍ'(´S÷¥ƒS_¢/àC8ÅAŠSÐd)D„ÒE$J ¹§ƒD“ îùßýî?ØG3òŒ¥TjA ®ëŠiš¡I'Ó`½^§æh4ß÷¥×ë%Hr6› Óé”Ýn‡¦i ªÕ*ý~ŸÉdÂjµb±X0 ½—Ç(F#Ž&B³ÙÄqf3‹ù|«'†Ã!¥R ÏóØn·ÔëuŠÅ""€mÛ´Ûít¥T¢!¤ëÑù˜ˆ "X–…®ë¸®‹¦iäóy*•J¶AhÒjµ(—ËqtTJe(¥°mÃ0è~|ÆÄÝ·çÓµZ-&º»½ÇûSüþ¸‡mFã"Àq‚ @¿Îqs¥NbH`FLd~}ïkH*A *x}<ÿÇã1¾ï'îþxÅår 0;~Á/g~ç0ŸÂÆ3ê+ÂÆòâ°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-msx-rom.png0000644000175000017500000000113310512722433033236 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÑIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @´   ƒ±¹\ÑÙ“7€šßÙׯ_g°¶¶†» €XMÙ Íîž® Þeøúõ XLHHL9rÅÄ„ìTxùh98¨²3ò~üø–{ûlŠ: Œ0h™¶†™™Œ­˜×Ð8bÈ‹È €0 ¨É … Xcdp:Ãß¿ u9¡X]@´ÍXÇÀÂÂ6dö‚ @63X¼yêj¬†UÁ þüaxúì1Ã÷o?áj³±» €0 —‹`øõëÃû÷o>}ø × "ŽÕ€B‰ÆgÏžHKK£(:wê&8‚À7PänÀÑ£G€éÌÞ»w/Ü& ÓøôéSu¦ €` ²‰ÌÎ0œËL…ž?æפIEND®B`‚././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-class-file.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-class-file.pn0000644000175000017500000000101310512722433033504 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡È† @4.ƒ@àúõë ÖÖÖp ²"dÍ0 èòèâÄ„- Ë $$„‚ãââ!Å E °eˆ%K–0hii1ððð0<{öŒÁÁÁ¬Ý‹Ä„îÏ9sæÀ ÂÀt·›#˜˜ BÀ€Åè† pÀ0.<%‚’,0¡€1¶|àååõÿÉ“'ÿ÷îÝûâˆkˆ›Ÿ>}Š•È4z Ü€£G2Ó;F:@w2Ôð«0>@Ád™a8æZ€Ob&TL®IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-csharp.png0000644000175000017500000000121110512722433031572 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÿIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAòÄÄ@€,055eàççgx÷î õk×Päà —A pýúukkk¸ ˆ%..î!Ø)L¨Ž)..f””³_¿~¦KKKáÁ@ ¿qãÆÿ_¿~ýÿóç0Ð>ý?zä8°Þ½{‡‚_¿~ Pˆƒ @`kŸ>}ÊÀÊÊÊÀÌÌÌÀÄÈÈpúäy°ÙsæÎeF#Ü9sÁ Ò€îE€bööö`ο>ùÊðìÙ{0?.6l@\\,Tþ†lÈæû÷2ˆŠ 3|úø•áï?6°dOOPL "¢¢ ñqqØ€»wî1Ì™µˆAIY…››‡›,YTT„¢› ˆ¥  à«Šª27zÈ&&&2ôöö‚myeѢб±1<€üúòåK06²0Æ\]]áé €X`Ge¦w¼ša1Wa|€‚)È&2;Ãp ,Îv´±ùþnIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-text-x-objcsrc.png0000644000175000017500000000120310512722433031740 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFùIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† ᆼÿæU†ëׯ3X[[à  &dÛ@šAašê«à† åaÁ@±`D ,Z0›áë×/`§÷õ´2|ýò™¡¶¡E Š @¶€ÀÍ›7.\¸À°}Ç.†[·î0üüõ ,.** ÷" z ååf3È+È3¼yûèß› |üB òòŠ !A>p—"€Â0`Òä© =a06Òghnnbpttò1¬Y·«Ä‚Ìyñ⃄„ƒ0Ðîß¿Ïðéã{†cG2|ýö,ÿôéS ÷n¢@ð”J²À„‚’ömPøOž<ù¿wïÞÿ‡@ €XÐ ÙÒÒÒ ûö³A©&ˆ7àèÑ£ Àô—%_˜¦7nÀÅ¡\…ñæ…l"³3 §À¼`†P{€+mlïIEND®B`‚././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-spreadsheet-template.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-oasis-spreadsheet-tem0000644000175000017500000000164110512722433033527 0ustar frankiefrankie‰PNG  IHDRóÿagAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe<3IDATxÚbüÿÿ?ƒgvµÖ¿¿/üøñõÿïß ¿~|eø¤ÿÿûË’gddd`bfa`cçd`áà``fbb`úó“ÁJO£ €X€€‰õ?û!>QgKME†ÿD„¾}ûÎ`inÆ &*ÊÀÁÁÎpú܆7>3ðñó a`xøða@ Ø6­ñeXaííŸ?þ9»;90HIˆ3üýû—™™™¡¢®‘áɳç <|ü b’`Ì÷å+#Pþˇ¼Ät£¤¤$çϯŸ>ð 2,^µžaËÎ] ¿~þ`z ètf° b££N\¼Êpáæ=Nn.†ÿ@ùïÞ°A¾ÿ"""øøøïèçìæçÂÂÁ÷öõþüû»¯ª(%$õööàäæÊ¥­óúþûôñ÷òúˆåׯ_b@_¨‡z»Yg¦$‚ˆëY2°rr30ŒYÙÀâ¿>½cfgø@,²3fÌhTVVVØäÃÓç/.\¾ÂÐY_Í ªkÁÀÔü—™á?3Ãß?ÿýÇΟßøD…Ïã©S§Úÿýû§¼ d20Hþ£îùmçÎ[ÄÅÅXXXà®ú ŒâÕ«W3¼}ûÖ €@(ßßß`dd4$ÁÊÊÊ0÷„3'3 +#п 4€ðR¸ñ2žÿ* +W®|’••% @ c_{xxhrqq£ BXÁ å…̺v+£°AàÍ›7 ?þÜ b˳gϾi}PŠ› 2{ ˜h$‘C˜Vœ‰‚ó‘ÙLŒÌ _¾|¹ô5ˆ@LÐ@aF' ÿýóŸ!Pw>C¾Ý 6+7ß?@.; €À.øöíÛGP‚„Ùòç׆Ÿ?~1 ûïoF ŸN@ "fÀ3 ðhúùaÕ©d¸³alNVa° ºB$@`¾|ùr}N@¬0Ts\3(+ÃÄþôþ8¶€éà $`âa2EÆËIEND®B`‚././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-python-bytecode.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-python-byteco0000644000175000017500000000134310512722433033660 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFYIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™سgÃÉ“'ž?Îðøñc†€43‚䈉Y`jjÊÀÏÏÏðî݆k×®¡ÈŠ ¾|ùÂô3Ã×/_ÎÝ=ʰéÌ<†‡Ïî1ø$1„¸&0°³³3\¿~ÁÚÚî€B1àÝÛw Çoíf8üt%Ãÿ'>3¾d`|-Ìðáñ/ö7Ò S‹×€ÕØØØÀ  &d§<³ƒaëën†w3<¼üžå;ç‡ÿ¾Ÿdøò÷ÃÄ%Ͱ@‡€B ƒU·º~1}axõõ 7ÃËc¬ \Ÿ%ózôÄ,î>¹Êr)2 $ë1|½ÁËðù3ÃËSÿDÿª1äûµ1‰òÃç7† Å€Š˜^†`Éþk¬ 6šž © /_½dX½¹•áé{ ’üê 2çäþÝ fˆKoeRPcàfg`zp›A@\šAžÙšÁRËÀ‚Ç(úŽ:À +¯ÈðûÏ_&FV 8ÿ¿ÿ~üüÁðôÙYY†/^08;;Ãc €P\ ¢® ¶3 ÀÁÅÅ ¨f?{ö Å7àèÑ£ ÀôŽ’‘ixúô)ˆº ãLA6‘Ù†S`™ Àer§Ó‡žåIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-msword.png0000644000175000017500000000125010512722433032702 0ustar frankiefrankie‰PNG  IHDRóÿabKGDùC» pHYs  ÒÝ~ütIMEÓ  /¥6²‡ÂtEXtComment(c) 2000 Jakub 'Jimmac' Steiner This image was created using Gimp. Gimp is free software as defined by the Free Software Foundation and is available for download at http://www.gimp.orgFZ gIDATxÚ¥­kBa‡Ÿ•‹‚É`3ˆ&ƒ8ƒöLaØlK×—LK6×f04Ü*?0´ˆ^ãƒYD rß³0îÅëUPvàÇË{>~<çÀ_ä¹BÏ\QJ•eYbš¦ôz=Û$Ñ`½^ŸÕ`0Ãá FÃCrwdÀf³a<³ßïÑ4 ¿ßO,£Óé0X­V,—KºÝ®3ûpŠ’L&Ýh"¤R)‹³Ù”ù|îª{úý>Á`ívËn·# à “Éœ'PJyl »~œwˆ"Ât:%cš&š¦àóùˆD"— l“t: @(rš_¥Ôe¥†aF)ý¸šËŸo爖eñøòÁ­qš˜èU&z•×ì¥B–‰^¥TȺþv#IäŠ""W½¶îùg8ÃáеF¥Ö Rk2Ñ«Ô[mê­¶kûˆïÀw"W¼™à‹‡ê!bÏcIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-mp3.png0000644000175000017500000000072510512722433031137 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ ,ÈŸçbIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-stm.png0000644000175000017500000000072510512722433031243 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ 2½tGbIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-aiff.png0000644000175000017500000000072510512722433031345 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ  F¸üObIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-lha.png0000644000175000017500000000177210512722433032411 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-rpm.png0000644000175000017500000000177210512722433032443 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-killustrator.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-killustrator.0000644000175000017500000000104610512722433033671 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFœIDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿF €P\2 ×@Ö¬YƒÑ«W¯Æê€BqÁëׯ1œˆnÁÍ›7œœœà. ¬. rHF£» €P\ðòåK06²( \]]á. ˜ÄÑ£G~ÿþW3<}úD]…ñ¦ ›Èì Ã)0ï''Ѽ¢ÆIEND®B`‚././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-cpio-compressed.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-cpio-compress0000644000175000017500000000177210512722433033645 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.writer.pngopenacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-vnd.sun.xml.wri0000644000175000017500000000065610512722433033607 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“cIDATxÚ“¿jÂP‡?K—  ¤H) E¢‹“8ˆ¯ÐÍ'(´S÷¥ƒS_¢/àC8ÅAŠSÐd)D„ÒE$J ¹§ƒD“ îùßýî?ØG3òŒ¥TjA ®ëŠiš¡I'Ó`½^§æh4ß÷¥×ë%Hr6› Óé”Ýn‡¦i ªÕ*ý~ŸÉdÂjµb±X0 ½—Ç(F#Ž&B³ÙÄqf3‹ù|«'†Ã!¥R ÏóØn·ÔëuŠÅ""€mÛ´Ûít¥T¢!¤ëÑù˜ˆ "X–…®ë¸®‹¦iäóy*•J¶AhÒjµ(—ËqtTJe(¥°mÃ0è~|ÆÄÝ·çÓµZ-&º»½ÇûSüþ¸‡mFã"Àq‚ @¿Îqs¥NbH`FLd~}ïkH*A *x}<ÿÇã1¾ï'îþxÅår 0;~Á/g~ç0ŸÂÆ3ê+ÂÆòâ°IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-lhz.png0000644000175000017500000000177210512722433032442 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFpIDATxÚbàææf`ggg```d`bbbÓH@KPP`·ˆˆÐe [Œ  2çß¿ ?þÑQÊÊ I¢¢bâ¿ÿüTÔ7TåææbgX¶dëþ·o?è‚”Âô#Èß¿iâÚœjbb˜)çà`Ãtæìi†Ë×.0°±23ððp2<}öšaá¼õ»¾~ùî3 €˜ÿÿÿ¯ÊËË[çîî6«¡¡6°­­^@JZœqýƵ W¯_b`eaa`aca`bffPV’Ä¥|íÊ–ÿþï@ŒºzÚW›šjµ”•€ŠX¾~ýÁpäÈ>†+×Î0ðóó1prq2pqr0°±±½÷‹áó—Ï óçl¸øæõ{ÄÔ(áéiÇpíúM†ËN2\¾zèd6c#3†ûo1prr‚øåË7 þüZ df˜ˆåå«×?Þ¼yÇ .&Ê áêÊ`kkËðüùS†_¿3ˆ‰ 3œ?áÇ ŒŒÿ¸y¸˜1ôŸn@1õdòŸ?Á ŠByyEm-iI9`À=gÙÇô;;+++Ð0FxìÓ¯Ÿ?߀ ‚1RT2|þü‰èdP:aj…(P ™@ÉÈÈ0Ó?Þ€‡‰‰%üþóäuv6°­ XX˜˜äv~~~€bùöíÛß_@@ªQÃðïÿ?†ÿ‚]ó¤èlv¨f.`Œüý Jpÿù89¹œÿþý{ €˜¾}ûñãó—¯ <¼Ü`›ýú À?@¨òÿˆ³Ù˜xù¸Áá´ß)`Xý|t/P9/@1ÿþõçí•«×Ü¡Î#.* ÈÏðè’¿ÿ1|øøžáÍÛ— |¼¼ 7¯?`X»zÏÿ+—ïÜ\ÆÊÊzhÀ-€†/ョOžÍܵsÿÇŽ(|øðI—QXD ׯ_cسë$ÖŸ}ÿúsž˜˜H-PóF` ¾Tð €€^eûóÇŸ°ð .òðp6ÓÒVaŸ2yΧgÏ^MŠw „„Ð{ @p@1…2(ZÀŽ™™ÙPì hiF7 ÀÀÊJçà75IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-cd-image.png0000644000175000017500000000100710512722433033302 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF}IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üøßÆÆŽA|>|øðÿß¿ÿ_±bÜ%0ˆ‰ غu+ ÿÕ«W ÕÕÕ`qÐf˜@a5ÀÛÛ›Ù¯¦¦¦ üüü ïÞ½a¸víŠZ€b)`ddyáóçÏ €z•áúõë ÖÖÖ >#ˆ@(.iöõõ³A4 ƒ4ûùùåaÁ@1aD ’m›6mÂpºÄ‚MÌ&˜kþüùƒ"‡ ÀøÒ;ܸq°0 &tƒ d ‚cÑØ¼@RsÅš5kàâÈòÈ €˜°E „„„ÀmEÆÈ €PÂàåË—( Ðc®®®ð0 x,=z”˜Þñj§OŸ‚¨«0>@Ád™a8怌ÊRºœ¹.YIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-x-dvi.png0000644000175000017500000000107110512722433032417 0ustar frankiefrankie‰PNG  IHDRóÿa pHYs  šœgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¯IDATxÚbøÿÿ?ñ"°€ô0@1@ øÿïß?¬øïß¿ÿ~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þü™¡½½TVV2ìÙ³‡áäÉ“ ÏŸ?gxüø1Ã@šAò„a:Éúô‰añâÅ ÇŽa8}ú,ëW¯à† €z•áúõë ÖÖÖpˆYHsGGCEE˜‹¿~ý L—–– ‚€‚»Ú ÀcÀ@jnܸÁ`kk w@1¡;d3Ì%sæÎkš3g.8pAòè^ ¼{÷¬¹ÀÁÁî€bAwÁ¢E‹âã㺻»Áb p…ˆ¨(C|\FŠ ^¿~3`ܼy“ÁÉÉ î€ÂƒÞÞ^°+@Ä^¸hX|áÂEˆä‹Å/_¾DQc#‹ÂÀÕÕ‡ÁÑ£G€é¯fxúô)ˆº ãLA6‘Ù†S`Þ0鼎ÆMèŠIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-application-magicpoint.png0000644000175000017500000000071010512722433033521 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“}IDATxÚ“=k"Q†Ÿ]·Ÿn' ´ën“.Øh³°EÒ ‚‚Èþ€ÛJbmga+²°í‚Ÿ‹ˆÍv‚Š3²ƒ)ÃÜ“"̠ɘ.çã¹/çž /v H ÿÎ ­u¤û¾/‹ÅBúý~¹> p]7҇áxž'Nç’öû}Hìv»4›MÊå2‰D‚ÉdÂf³a¹\ÒëõÂÞQrÚí6¹\ŽL&C6›e6›a»Ý?¦ÓééÄäx<Î|:¤T«UŠÅ"®ë""8Žƒiš8ŽÃh4BDŽnA"•JÑh40 €›/÷|NgÀüqT© 0¥TXüXúÅS%æ µþ? V«…/rysÇŸßÜV.â)X­VäóylÛÆ4M®¾žcÛv<@«Õâ={ É÷}¶ÛíQ‘RŠz½~›ÏçX–½H"‚ÖA)…eY$“É0ä# <Ï{#õµäõzM¡Pø |;ŒÿŒù/Ï2gØ`çV»IEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/openofficeorg-20-drawing.png0000644000175000017500000000054210512722433031536 0ustar frankiefrankie‰PNG  IHDROc#"bKGDÿÿÿÿÿÿ X÷Ü pHYs  ÒÝ~üIDATxÚµUQà å-½W¹™r3=û D‹uu™{IÓ ÊúTP@Î9ç¬J‚Å÷pÌ&¦”RJûˆk­µÖÑ~<-€¨”RJýÌÌÌ£ßíªªŸúù˜€f>Ïó$R%ìQ5K”¨÷Ç„f¼V[‰[‡®cŸëi¿ôª…D¢±ö‰™™½bגȘÀÏˆÄ 2'Ž ðmèh½MØZ{Ç1‘ªi ·Ø;ñ¬Tl lØw¤¼ß®#ž©>bY3˜Æ×+ޒЈ]Pß;ÁÝIgs›AT+sÔn; ŸÌü«™&0»~üˆ>|øÿïß¿ÿ¯X±î˜Ä&A0|þüæBÿÞýû òrr ëÖ¯g¸sû6ÃóçÏ?~ÌpàÀfF:€bbÀ.\ºÈðòÕ+†=û0¼}÷Žá݇ üüü ïÞ½a¸víŠZ€Â0àÙ³g ÷>búÁÝÅ™A@@€ŸŸÁÜÒ’aÞ¼ ë®A„bÈÙg/\`ðrsc`aaaøòõ+Ã…‹—ÌLŒ ˜™™aaÄ‚-vv §Ïže¸tù Ã_  ÀÊÊÊÈÀÃÃa@± s@’>d8wá"Š")I 666°ü?¨¡0@,è^xõú \ƒ¡¾ƒžŽ\ÝÄ„îi)IP´‚ÃÀÃÕ…ASCƒáÄ©S ïß¿G$$@(-%Å ¦ªÂðë÷o k^3:|­—ÁáÍ„LLL Ö œœœ`LLŒ Növ Àt€Í„aÌCCc`Ô¡¤{¨+‘@Á 8zô(0½£†LÃÀÓ§OAÔU €` ²‰ÌÎ0œs@€¬ñXåmÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/mimetypes/gnome-mime-audio-x-mod.png0000644000175000017500000000072510512722433031217 0ustar frankiefrankie‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ &g :bIDAT8Ë“1nÂ0…?ªn,1pŽÀÖ-WèD'†pÀX|D@((bDBUFcdÿªXIU-=éÉúßóûÛð³b@þ7ž,ñÞ?„sNŽÇ£l6›Ú$~jP–eøv»•ªªd±Xt’ôÜï÷ਔ ,K–Ë%»ÝŽ<Ï9N¬×ë }iÆðÞh­QJ1QJaíûýþù n·›XkÅZ+€XkEk-€E!ÖZɲ¬nƒNi¹öûýÀƒÞûNÍkS\G¯‹´ÖÄqø#ƒ wÎÉt:•(Š$Š¢‡-EѼÎv€ÙlÖrMÓ´{Ò_ ’$ šcŒc$MÓV‚–1F.—‹$IÒyÆÆÉó\V«ÕóD„^¯Çd2`>Ÿ0;î¼Dç×ëµUPóæÞáp`4mHeUUý)8ŸÏŸ¿gðñÏï\ã½~À"UƇ@êÑIEND®B`‚openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/0000755000175000017500000000000011724401447024120 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/0000755000175000017500000000000011724401447025041 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/b5.js0000644000175000017500000000200410177203647025704 0ustar frankiefrankie// I18N constants -- Chinese Big-5 // by Dave Lo -- dlo@interactivetools.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "b5", tooltips: { bold: "²ÊÅé", italic: "±×Åé", underline: "©³½u", strikethrough: "§R°£½u", subscript: "¤U¼Ð", superscript: "¤W¼Ð", justifyleft: "¦ì¸m¾a¥ª", justifycenter: "¦ì¸m©~¤¤", justifyright: "¦ì¸m¾a¥k", justifyfull: "¦ì¸m¥ª¥k¥­µ¥", orderedlist: "¶¶§Ç²M³æ", unorderedlist: "µL§Ç²M³æ", outdent: "´î¤p¦æ«eªÅ¥Õ", indent: "¥[¼e¦æ«eªÅ¥Õ", forecolor: "¤å¦rÃC¦â", backcolor: "­I´ºÃC¦â", horizontalrule: "¤ô¥­½u", createlink: "´¡¤J³sµ²", insertimage: "´¡¤J¹Ï§Î", inserttable: "´¡¤Jªí®æ", htmlmode: "¤Á´«HTML­ì©l½X", popupeditor: "©ñ¤j", about: "Ãö©ó HTMLArea", help: "»¡©ú", textindicator: "¦rÅé¨Ò¤l" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ch.js0000644000175000017500000000570410177203647026002 0ustar frankiefrankie// I18N constants // LANG: "ch", ENCODING: UTF-8 // Samuel Stone, http://stonemicro.com/ HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ch", tooltips: { bold: "ç²—é«”", italic: "斜體", underline: "底線", strikethrough: "刪線", subscript: "下標", superscript: "上標", justifyleft: "é å·¦", justifycenter: "居中", justifyright: "é å³", justifyfull: "整齊", orderedlist: "é †åºæ¸…å–®", unorderedlist: "ç„¡åºæ¸…å–®", outdent: "伸排", indent: "縮排", forecolor: "文字é¡è‰²", backcolor: "背景é¡è‰²", horizontalrule: "水平線", createlink: "æ’入連çµ", insertimage: "æ’入圖åƒ", inserttable: "æ’入表格", htmlmode: "切æ›HTML原始碼", popupeditor: "伸出編輯系統", about: "關於 HTMLArea", help: "說明", textindicator: "字體例å­", undo: "回原", redo: "釿¥", cut: "剪制选项", copy: "å¤åˆ¶é€‰é¡¹", paste: "贴上", lefttoright: "从左到å³", righttoleft: "从å³åˆ°å·¦" }, buttons: { "ok": "好", "cancel": "å–æ¶ˆ" }, msg: { "Path": "途徑", "TEXT_MODE": "你在用純字編輯方å¼. 用 [<>] 按鈕轉回 æ‰€è¦‹å³æ‰€å¾— 編輯方å¼.", "IE-sucks-full-screen" : // translate here "æ•´é å¼åœ¨Internet Explorer 上常出å•題, " + "因為這是 Internet Explorer 的無åå•題,我們無法解決。" + "ä½ å¯èƒ½çœ‹è¦‹ä¸€äº›åžƒåœ¾ï¼Œæˆ–é‡åˆ°å…¶ä»–å•題。" + "我們已警告了你. 如果è¦è½‰åˆ° æ­£é å¼ 請按 好.", "Moz-Clipboard" : "Unprivileged scripts cannot access Cut/Copy/Paste programatically " + "for security reasons. Click OK to see a technical note at mozilla.org " + "which shows you how to allow a script to access the clipboard." }, dialogs: { "Cancel" : "å–æ¶ˆ", "Insert/Modify Link" : "æ’å…¥/改寫連çµ", "New window (_blank)" : "新窗户(_blank)", "None (use implicit)" : "ç„¡(use implicit)", "OK" : "好", "Other" : "å…¶ä»–", "Same frame (_self)" : "本匡 (_self)", "Target:" : "目標匡:", "Title (tooltip):" : "主題 (tooltip):", "Top frame (_top)" : "上匡 (_top)", "URL:" : "ç¶²å€:", "You must enter the URL where this link points to" : "你必須輸入你è¦è¿žç»“的網å€" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/da.js0000644000175000017500000000231310177203647025765 0ustar frankiefrankie// danish version for htmlArea v3.0 - Alpha Release // - translated by rene // term´s and licenses are equal to htmlarea! HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "da", tooltips: { bold: "Fed", italic: "Kursiv", underline: "Understregning", strikethrough: "Overstregning ", subscript: "Sænket skrift", superscript: "Hævet skrift", justifyleft: "Venstrejuster", justifycenter: "Centrer", justifyright: "Højrejuster", justifyfull: "Lige margener", orderedlist: "Opstilling med tal", unorderedlist: "Opstilling med punkttegn", outdent: "Formindsk indrykning", indent: "Forøg indrykning", forecolor: "Skriftfarve", backcolor: "Baggrundsfarve", horizontalrule: "Horisontal linie", createlink: "Indsæt hyperlink", insertimage: "Indsæt billede", inserttable: "Indsæt tabel", htmlmode: "HTML visning", popupeditor: "Vis editor i popup", about: "Om htmlarea", help: "Hjælp", textindicator: "Anvendt stil" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/de.js0000644000175000017500000000622710177203647026001 0ustar frankiefrankie// I18N constants // LANG: "de", ENCODING: ISO-8859-1 for the german umlaut! HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "de", tooltips: { bold: "Fett", italic: "Kursiv", underline: "Unterstrichen", strikethrough: "Durchgestrichen", subscript: "Hochgestellt", superscript: "Tiefgestellt", justifyleft: "Linksbündig", justifycenter: "Zentriert", justifyright: "Rechtsbündig", justifyfull: "Blocksatz", orderedlist: "Nummerierung", unorderedlist: "Aufzählungszeichen", outdent: "Einzug verkleinern", indent: "Einzug vergrößern", forecolor: "Schriftfarbe", backcolor: "Hindergrundfarbe", hilitecolor: "Hintergrundfarbe", horizontalrule: "Horizontale Linie", inserthorizontalrule: "Horizontale Linie", createlink: "Hyperlink einfügen", insertimage: "Bild einfügen", inserttable: "Tabelle einfügen", htmlmode: "HTML Modus", popupeditor: "Editor im Popup öffnen", about: "Über htmlarea", help: "Hilfe", showhelp: "Hilfe", textindicator: "Derzeitiger Stil", undo: "Rückgängig", redo: "Wiederholen", cut: "Ausschneiden", copy: "Kopieren", paste: "Einfügen aus der Zwischenablage", lefttoright: "Textrichtung von Links nach Rechts", righttoleft: "Textrichtung von Rechts nach Links", removeformat: "Formatierung entfernen" }, buttons: { "ok": "OK", "cancel": "Abbrechen" }, msg: { "Path": "Pfad", "TEXT_MODE": "Sie sind im Text-Modus. Benutzen Sie den [<>] Knopf um in den visuellen Modus (WYSIWIG) zu gelangen.", "Moz-Clipboard" : "Aus Sicherheitsgründen dürfen Skripte normalerweise nicht programmtechnisch auf " + "Ausschneiden/Kopieren/Einfügen zugreifen. Bitte klicken Sie OK um die technische " + "Erläuterung auf mozilla.org zu öffnen, in der erklärt wird, wie einem Skript Zugriff " + "gewährt werden kann." }, dialogs: { "OK": "OK", "Cancel": "Abbrechen", "Insert/Modify Link": "Verknüpfung hinzufügen/ändern", "None (use implicit)": "k.A. (implizit)", "New window (_blank)": "Neues Fenster (_blank)", "Same frame (_self)": "Selber Rahmen (_self)", "Top frame (_top)": "Oberster Rahmen (_top)", "Other": "Anderes", "Target:": "Ziel:", "Title (tooltip):": "Titel (Tooltip):", "URL:": "URL:", "You must enter the URL where this link points to": "Sie müssen eine Ziel-URL angeben für die Verknüpfung angeben" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/cz.js0000644000175000017500000000363110177203647026021 0ustar frankiefrankie// I18N constants // LANG: "cz", ENCODING: UTF-8 | ISO-8859-2 // Author: Jiri Löw, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "cz", tooltips: { bold: "TuÄnÄ›", italic: "Kurzíva", underline: "Podtržení", strikethrough: "PÅ™eÅ¡krtnutí", subscript: "Dolní index", superscript: "Horní index", justifyleft: "Zarovnat doleva", justifycenter: "Na stÅ™ed", justifyright: "Zarovnat doprava", justifyfull: "Zarovnat do stran", orderedlist: "Seznam", unorderedlist: "Odrážky", outdent: "PÅ™edsadit", indent: "Odsadit", forecolor: "Barva písma", hilitecolor: "Barva pozadí", horizontalrule: "Vodorovná Äára", createlink: "Vložit odkaz", insertimage: "Vložit obrázek", inserttable: "Vložit tabulku", htmlmode: "PÅ™epnout HTML", popupeditor: "Nové okno editoru", about: "O této aplikaci", showhelp: "NápovÄ›da aplikace", textindicator: "Zvolený styl", undo: "Vrátí poslední akci", redo: "Opakuje poslední akci", cut: "Vyjmout", copy: "Kopírovat", paste: "Vložit" }, buttons: { "ok": "OK", "cancel": "ZruÅ¡it" }, msg: { "Path": "Cesta", "TEXT_MODE": "Jste v TEXTOVÉM REŽIMU. Použijte tlaÄítko [<>] pro pÅ™epnutí do WYSIWIG." } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ee.js0000644000175000017500000000345210177203647025777 0ustar frankiefrankie// I18N constants // LANG: "ee", ENCODING: UTF-8 | ISO-8859-1 // Author: Martin Raie, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ee", tooltips: { bold: "Paks", italic: "Kursiiv", underline: "Allakriipsutatud", strikethrough: "Läbikriipsutatud", subscript: "Allindeks", superscript: "Ülaindeks", justifyleft: "Joonda vasakule", justifycenter: "Joonda keskele", justifyright: "Joonda paremale", justifyfull: "Rööpjoonda", orderedlist: "Nummerdus", unorderedlist: "Täpploend", outdent: "Vähenda taanet", indent: "Suurenda taanet", forecolor: "Fondi värv", hilitecolor: "Tausta värv", inserthorizontalrule: "Horisontaaljoon", createlink: "Lisa viit", insertimage: "Lisa pilt", inserttable: "Lisa tabel", htmlmode: "HTML/tavaline vaade", popupeditor: "Suurenda toimeti aken", about: "Teave toimeti kohta", showhelp: "Spikker", textindicator: "Kirjastiil", undo: "Võta tagasi", redo: "Tee uuesti", cut: "Lõika", copy: "Kopeeri", paste: "Kleebi" }, buttons: { "ok": "OK", "cancel": "Loobu" }, msg: { "Path": "Path", "TEXT_MODE": "Sa oled tekstireziimis. Kasuta nuppu [<>] lülitamaks tagasi WYSIWIG reziimi." } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/el.js0000644000175000017500000000754010177203647026010 0ustar frankiefrankie// I18N constants // LANG: "el", ENCODING: UTF-8 | ISO-8859-7 // Author: Dimitris Glezos, dimitris@glezos.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "el", tooltips: { bold: "Έντονα", italic: "Πλάγια", underline: "ΥπογÏαμμισμένα", strikethrough: "ΔιαγÏαμμένα", subscript: "Δείκτης", superscript: "Δείκτης", justifyleft: "Στοίχιση ΑÏιστεÏά", justifycenter: "Στοίχιση ΚέντÏο", justifyright: "Στοίχιση Δεξιά", justifyfull: "ΠλήÏης Στοίχιση", orderedlist: "ΑÏίθμηση", unorderedlist: "Κουκκίδες", outdent: "Μείωση Εσοχής", indent: "ΑÏξηση Εσοχής", forecolor: "ΧÏώμα ΓÏαμματοσειÏάς", hilitecolor: "ΧÏώμα Φόντου", horizontalrule: "ΟÏιζόντια ΓÏαμμή", createlink: "Εισαγωγή Συνδέσμου", insertimage: "Εισαγωγή/ΤÏοποποίηση Εικόνας", inserttable: "Εισαγωγή Πίνακα", htmlmode: "Εναλλαγή σε/από HTML", popupeditor: "Μεγένθυνση επεξεÏγαστή", about: "ΠληÏοφοÏίες", showhelp: "Βοήθεια", textindicator: "ΠαÏών στυλ", undo: "ΑναίÏεση τελευταίας ενέÏγειας", redo: "ΕπαναφοÏά από αναίÏεση", cut: "Αποκοπή", copy: "ΑντιγÏαφή", paste: "Επικόλληση", lefttoright: "ΚατεÏθυνση αÏιστεÏά Ï€Ïος δεξιά", righttoleft: "ΚατεÏθυνση από δεξιά Ï€Ïος τα αÏιστεÏά" }, buttons: { "ok": "OK", "cancel": "ΑκÏÏωση" }, msg: { "Path": "ΔιαδÏομή", "TEXT_MODE": "Είστε σε TEXT MODE. ΧÏησιμοποιήστε το κουμπί [<>] για να επανέÏθετε στο WYSIWIG.", "IE-sucks-full-screen": "Η κατάσταση πλήÏης οθόνης έχει Ï€Ïοβλήματα με τον Internet Explorer, " + "λόγω σφαλμάτων στον ίδιο τον browser. Αν το σÏστημα σας είναι Windows 9x " + "μποÏεί και να χÏειαστείτε reboot. Αν είστε σίγουÏοι, πατήστε ΟΚ." }, dialogs: { "Cancel" : "ΑκÏÏωση", "Insert/Modify Link" : "Εισαγωγή/ΤÏοποποίηση σÏνδεσμου", "New window (_blank)" : "Îέο παÏάθυÏο (_blank)", "None (use implicit)" : "Κανένα (χÏήση απόλυτου)", "OK" : "Εντάξει", "Other" : "Αλλο", "Same frame (_self)" : "Ίδιο frame (_self)", "Target:" : "Target:", "Title (tooltip):" : "Τίτλος (tooltip):", "Top frame (_top)" : "Πάνω frame (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "ΠÏέπει να εισάγετε το URL που οδηγεί αυτός ο σÏνδεσμος" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/en.js0000644000175000017500000001575010177203647026014 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "en", tooltips: { bold: "Bold", italic: "Italic", underline: "Underline", strikethrough: "Strikethrough", subscript: "Subscript", superscript: "Superscript", justifyleft: "Justify Left", justifycenter: "Justify Center", justifyright: "Justify Right", justifyfull: "Justify Full", orderedlist: "Ordered List", unorderedlist: "Bulleted List", outdent: "Decrease Indent", indent: "Increase Indent", forecolor: "Font Color", hilitecolor: "Background Color", horizontalrule: "Horizontal Rule", createlink: "Insert Web Link", insertimage: "Insert/Modify Image", inserttable: "Insert Table", htmlmode: "Toggle HTML Source", popupeditor: "Enlarge Editor", about: "About this editor", showhelp: "Help using editor", textindicator: "Current style", undo: "Undoes your last action", redo: "Redoes your last action", cut: "Cut selection", copy: "Copy selection", paste: "Paste from clipboard", lefttoright: "Direction left to right", righttoleft: "Direction right to left", removeformat: "Remove formatting", print: "Print document", killword: "Clear MSOffice tags" }, buttons: { "ok": "OK", "cancel": "Cancel" }, msg: { "Path": "Path", "TEXT_MODE": "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.", "IE-sucks-full-screen" : // translate here "The full screen mode is known to cause problems with Internet Explorer, " + "due to browser bugs that we weren't able to workaround. You might experience garbage " + "display, lack of editor functions and/or random browser crashes. If your system is Windows 9x " + "it's very likely that you'll get a 'General Protection Fault' and need to reboot.\n\n" + "You have been warned. Please press OK if you still want to try the full screen editor.", "Moz-Clipboard" : "Unprivileged scripts cannot access Cut/Copy/Paste programatically " + "for security reasons. Click OK to see a technical note at mozilla.org " + "which shows you how to allow a script to access the clipboard." }, dialogs: { // Common "OK" : "OK", "Cancel" : "Cancel", "Alignment:" : "Alignment:", "Not set" : "Not set", "Left" : "Left", "Right" : "Right", "Texttop" : "Texttop", "Absmiddle" : "Absmiddle", "Baseline" : "Baseline", "Absbottom" : "Absbottom", "Bottom" : "Bottom", "Middle" : "Middle", "Top" : "Top", "Layout" : "Layout", "Spacing" : "Spacing", "Horizontal:" : "Horizontal:", "Horizontal padding" : "Horizontal padding", "Vertical:" : "Vertical:", "Vertical padding" : "Vertical padding", "Border thickness:" : "Border thickness:", "Leave empty for no border" : "Leave empty for no border", // Insert Link "Insert/Modify Link" : "Insert/Modify Link", "None (use implicit)" : "None (use implicit)", "New window (_blank)" : "New window (_blank)", "Same frame (_self)" : "Same frame (_self)", "Top frame (_top)" : "Top frame (_top)", "Other" : "Other", "Target:" : "Target:", "Title (tooltip):" : "Title (tooltip):", "URL:" : "URL:", "You must enter the URL where this link points to" : "You must enter the URL where this link points to", // Insert Table "Insert Table" : "Insert Table", "Rows:" : "Rows:", "Number of rows" : "Number of rows", "Cols:" : "Cols:", "Number of columns" : "Number of columns", "Width:" : "Width:", "Width of the table" : "Width of the table", "Percent" : "Percent", "Pixels" : "Pixels", "Em" : "Em", "Width unit" : "Width unit", "Positioning of this table" : "Positioning of this table", "Cell spacing:" : "Cell spacing:", "Space between adjacent cells" : "Space between adjacent cells", "Cell padding:" : "Cell padding:", "Space between content and border in cell" : "Space between content and border in cell", // Insert Image "Insert Image" : "Insert Image", "Image URL:" : "Image URL:", "Enter the image URL here" : "Enter the image URL here", "Preview" : "Preview", "Preview the image in a new window" : "Preview the image in a new window", "Alternate text:" : "Alternate text:", "For browsers that don't support images" : "For browsers that don't support images", "Positioning of this image" : "Positioning of this image", "Image Preview:" : "Image Preview:" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/es.js0000644000175000017500000000275110177203647026016 0ustar frankiefrankie// I18N constants HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "es", tooltips: { bold: "Negrita", italic: "Cursiva", underline: "Subrayado", strikethrough: "Tachado", subscript: "Subíndice", superscript: "Superíndice", justifyleft: "Alinear a la Izquierda", justifycenter: "Centrar", justifyright: "Alinear a la Derecha", justifyfull: "Justificar", orderedlist: "Lista Ordenada", unorderedlist: "Lista No Ordenada", outdent: "Aumentar Sangría", indent: "Disminuir Sangría", forecolor: "Color del Texto", hilitecolor: "Color del Fondo", inserthorizontalrule: "Línea Horizontal", createlink: "Insertar Enlace", insertimage: "Insertar Imagen", inserttable: "Insertar Tabla", htmlmode: "Ver Documento en HTML", popupeditor: "Ampliar Editor", about: "Acerca del Editor", showhelp: "Ayuda", textindicator: "Estilo Actual", undo: "Deshacer", redo: "Rehacer", cut: "Cortar selección", copy: "Copiar selección", paste: "Pegar desde el portapapeles" }, buttons: { "ok": "Aceptar", "cancel": "Cancelar" }, msg: { "Path": "Ruta", "TEXT_MODE": "Esta en modo TEXTO. Use el boton [<>] para cambiar a WYSIWIG", } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/fi.js0000644000175000017500000000265210177203647026005 0ustar frankiefrankie// I18N constants HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "en", tooltips: { bold: "Lihavoitu", italic: "Kursivoitu", underline: "Alleviivattu", strikethrough: "Yliviivattu", subscript: "Alaindeksi", superscript: "Yläindeksi", justifyleft: "Tasaa vasemmat reunat", justifycenter: "Keskitä", justifyright: "Tasaa oikeat reunat", justifyfull: "Tasaa molemmat reunat", orderedlist: "Numerointi", unorderedlist: "Luettelomerkit", outdent: "Lisää sisennystä", indent: "Pienennä sisennystä", forecolor: "Fontin väri", hilitecolor: "Taustaväri", inserthorizontalrule: "Vaakaviiva", createlink: "Lisää Linkki", insertimage: "Lisää Kuva", inserttable: "Lisää Taulu", htmlmode: "HTML Lähdekoodi vs WYSIWYG", popupeditor: "Suurenna Editori", about: "Tietoja Editorista", showhelp: "Näytä Ohje", textindicator: "Nykyinen tyyli", undo: "Peruuta viimeinen toiminto", redo: "Palauta viimeinen toiminto", cut: "Leikkaa maalattu", copy: "Kopioi maalattu", paste: "Liitä leikepyödältä" }, buttons: { "ok": "Hyväksy", "cancel": "Peruuta" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/gb.js0000644000175000017500000000200110177203647025763 0ustar frankiefrankie// I18N constants -- Chinese GB // by Dave Lo -- dlo@interactivetools.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "gb", tooltips: { bold: "´ÖÌå", italic: "бÌå", underline: "µ×Ïß", strikethrough: "ɾ³ýÏß", subscript: "ϱê", superscript: "Éϱê", justifyleft: "λÖÿ¿×ó", justifycenter: "λÖþÓÖÐ", justifyright: "λÖÿ¿ÓÒ", justifyfull: "λÖÃ×óÓÒÆ½µÈ", orderedlist: "˳ÐòÇåµ¥", unorderedlist: "ÎÞÐòÇåµ¥", outdent: "¼õСÐÐǰ¿Õ°×", indent: "¼Ó¿íÐÐǰ¿Õ°×", forecolor: "ÎÄ×ÖÑÕÉ«", backcolor: "±³¾°ÑÕÉ«", horizontalrule: "ˮƽÏß", createlink: "²åÈëÁ¬½á", insertimage: "²åÈëͼÐÎ", inserttable: "²åÈë±í¸ñ", htmlmode: "Çл»HTMLԭʼÂë", popupeditor: "·Å´ó", about: "¹Øì¶ HTMLArea", help: "˵Ã÷", textindicator: "×ÖÌåÀý×Ó" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/fr.js0000644000175000017500000000760610177203647026022 0ustar frankiefrankie// I18N constants // LANG: "fr", ENCODING: UTF-8 | ISO-8859-1 // Author: Simon Richard, s.rich@sympatico.ca // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) // All technical terms used in this document are the ones approved // by the Office québécois de la langue française. // Tous les termes techniques utilisés dans ce document sont ceux // approuvés par l'Office québécois de la langue française. // http://www.oqlf.gouv.qc.ca/ HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "fr", tooltips: { bold: "Gras", italic: "Italique", underline: "Souligné", strikethrough: "Barré", subscript: "Indice", superscript: "Exposant", justifyleft: "Aligné à gauche", justifycenter: "Centré", justifyright: "Aligné à droite", justifyfull: "Justifier", orderedlist: "Numérotation", unorderedlist: "Puces", outdent: "Diminuer le retrait", indent: "Augmenter le retrait", forecolor: "Couleur de police", hilitecolor: "Surlignage", horizontalrule: "Ligne horizontale", createlink: "Insérer un hyperlien", insertimage: "Insérer/Modifier une image", inserttable: "Insérer un tableau", htmlmode: "Passer au code source", popupeditor: "Agrandir l'éditeur", about: "À propos de cet éditeur", showhelp: "Aide sur l'éditeur", textindicator: "Style courant", undo: "Annuler la dernière action", redo: "Répéter la dernière action", cut: "Couper la sélection", copy: "Copier la sélection", paste: "Coller depuis le presse-papier", lefttoright: "Direction de gauche à droite", righttoleft: "Direction de droite à gauche" }, buttons: { "ok": "OK", "cancel": "Annuler" }, msg: { "Path": "Chemin", "TEXT_MODE": "Vous êtes en MODE TEXTE. Appuyez sur le bouton [<>] pour retourner au mode tel-tel.", "IE-sucks-full-screen" : // translate here "Le mode plein écran peut causer des problèmes sous Internet Explorer, " + "ceci dû à des bogues du navigateur qui ont été impossible à contourner. " + "Les différents symptômes peuvent être un affichage déficient, le manque de " + "fonctions dans l'éditeur et/ou pannes aléatoires du navigateur. Si votre " + "système est Windows 9x, il est possible que vous subissiez une erreur de type " + "«General Protection Fault» et que vous ayez à redémarrer votre ordinateur." + "\n\nConsidérez-vous comme ayant été avisé. Appuyez sur OK si vous désirez tout " + "de même essayer le mode plein écran de l'éditeur." }, dialogs: { "Cancel" : "Annuler", "Insert/Modify Link" : "Insérer/Modifier Lien", "New window (_blank)" : "Nouvelle fenêtre (_blank)", "None (use implicit)" : "Aucun (par défaut)", "OK" : "OK", "Other" : "Autre", "Same frame (_self)" : "Même cadre (_self)", "Target:" : "Cible:", "Title (tooltip):" : "Titre (infobulle):", "Top frame (_top)" : "Cadre du haut (_top)", "URL:" : "Adresse Web:", "You must enter the URL where this link points to" : "Vous devez entrer l'adresse Web du lien" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/he.js0000644000175000017500000000775210177203647026011 0ustar frankiefrankie// I18N constants // LANG: "he", ENCODING: UTF-8 // Author: Liron Newman, http://www.eesh.net, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "he", tooltips: { bold: "מודגש", italic: "נטוי", underline: "קו תחתי", strikethrough: "קו ×מצע", subscript: "כתב עילי", superscript: "כתב תחתי", justifyleft: " ישור לשמ×ל", justifycenter: "ישור למרכז", justifyright: "ישור לימין", justifyfull: "ישור לשורה מל××”", orderedlist: "רשימה ממוספרת", unorderedlist: "רשימה ×œ× ×ž×ž×•×¡×¤×¨×ª", outdent: "הקטן כניסה", indent: "הגדל כניסה", forecolor: "צבע גופן", hilitecolor: "צבע רקע", horizontalrule: "קו ×× ×›×™", createlink: "הכנס היפר-קישור", insertimage: "הכנס/שנה תמונה", inserttable: "הכנס טבלה", htmlmode: "שנה מצב קוד HTML", popupeditor: "הגדל ×ת העורך", about: "×ודות עורך ×–×”", showhelp: "עזרה לשימוש בעורך", textindicator: "סגנון נוכחי", undo: "מבטל ×ת פעולתך ×”×חרונה", redo: "מבצע מחדש ×ת הפעולה ×”×חרונה שביטלת", cut: "גזור בחירה", copy: "העתק בחירה", paste: "הדבק מהלוח", lefttoright: "כיוון משמ×ל לימין", righttoleft: "כיוון מימין לשמ×ל" }, buttons: { "ok": "×ישור", "cancel": "ביטול" }, msg: { "Path": "נתיב עיצוב", "TEXT_MODE": "×תה במצב טקסט × ×§×™ (קוד). השתמש בכפתור [<>] כדי לחזור למצב WYSIWYG (תצוגת עיצוב).", "IE-sucks-full-screen" : // translate here "מצב מסך ×ž×œ× ×™×•×¦×¨ בעיות בדפדפן Internet Explorer, " + "עקב ב××’×™× ×‘×“×¤×“×¤×Ÿ ×œ× ×™×›×•×œ× ×• לפתור ×ת ×–×”. ×ת/×” עלול/×” לחוות תצוגת זבל, " + "בעיות בתפקוד העורך ו/×ו קריסה של הדפדפן. ×× ×”×ž×¢×¨×›×ª שלך ×”×™× Windows 9x " + "סביר להניח שתקבל/×™ 'General Protection Fault' ות×לצ/×™ ל×תחל ×ת המחשב.\n\n" + "ר××”/×™ הוזהרת. ×× × ×œ×—×¥/×™ ×ישור ×× ×ת/×” עדיין רוצה לנסות ×ת העורך במסך מל×." }, dialogs: { "Cancel" : "ביטול", "Insert/Modify Link" : "הוסף/שנה קישור", "New window (_blank)" : "חלון חדש (_blank)", "None (use implicit)" : "×œ×œ× (השתמש ב-frame ×”×§×™×™×)", "OK" : "OK", "Other" : "×חר", "Same frame (_self)" : "×ותו frame (_self)", "Target:" : "יעד:", "Title (tooltip):" : "כותרת (tooltip):", "Top frame (_top)" : "Frame עליון (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "חובה לכתוב URL ש×ליו קישור ×–×” מצביע" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/hu.js0000644000175000017500000000677610177203647026036 0ustar frankiefrankie// I18N constants // LANG: "hu", ENCODING: UTF-8 // Author: Miklós Somogyi, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "hu", tooltips: { bold: "Félkövér", italic: "DÅ‘lt", underline: "Aláhúzott", strikethrough: "Ãthúzott", subscript: "Alsó index", superscript: "FelsÅ‘ index", justifyleft: "Balra zárt", justifycenter: "Középre zárt", justifyright: "Jobbra zárt", justifyfull: "Sorkizárt", orderedlist: "Számozott lista", unorderedlist: "Számozatlan lista", outdent: "Behúzás csökkentése", indent: "Behúzás növelése", forecolor: "Karakterszín", hilitecolor: "Háttérszín", horizontalrule: "Elválasztó vonal", createlink: "Hiperhivatkozás beszúrása", insertimage: "Kép beszúrása", inserttable: "Táblázat beszúrása", htmlmode: "HTML forrás be/ki", popupeditor: "SzerkesztÅ‘ külön ablakban", about: "Névjegy", showhelp: "Súgó", textindicator: "Aktuális stílus", undo: "Visszavonás", redo: "Újra végrehajtás", cut: "Kivágás", copy: "Másolás", paste: "Beillesztés", lefttoright: "Irány balról jobbra", righttoleft: "Irány jobbról balra" }, buttons: { "ok": "Rendben", "cancel": "Mégsem" }, msg: { "Path": "Hierarchia", "TEXT_MODE": "Forrás mód. Visszaváltás [<>] gomb", "IE-sucks-full-screen" : // translate here "A teljesképrenyÅ‘s szerkesztés hibát okozhat Internet Explorer használata esetén, " + "ez a böngészÅ‘ a hibája, amit nem tudunk kikerülni. Szemetet észlelhet a képrenyÅ‘n, " + "illetve néhány funkció hiányozhat és/vagy véletlenszerűen lefagyhat a böngészÅ‘. " + "Windows 9x operaciós futtatása esetén elég valószínű, hogy 'General Protection Fault' " + "hibát okoz és újra kell indítania a számítógépet.\n\n" + "Figyelmeztettük. Kérjük nyomja meg a Rendben gombot, ha mégis szeretné megnyitni a " + "szerkesztÅ‘t külön ablakban." }, dialogs: { "Cancel" : "Mégsem", "Insert/Modify Link" : "Hivatkozás Beszúrása/Módosítása", "New window (_blank)" : "Új ablak (_blank)", "None (use implicit)" : "Nincs (use implicit)", "OK" : "OK", "Other" : "Más", "Same frame (_self)" : "Ugyanabba a keretbe (_self)", "Target:" : "Cél:", "Title (tooltip):" : "Cím (tooltip):", "Top frame (_top)" : "FelsÅ‘ keret (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "Be kell írnia az URL-t, ahova a hivatkozás mutasson" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/it.js0000644000175000017500000001003210177203647026012 0ustar frankiefrankie// I18N constants // LANG: "it", ENCODING: UTF-8 | ISO-8859-1 // Author: Fabio Rotondo // Update for 3.0 rc1: Giovanni Premuda HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "it", tooltips: { bold: "Grassetto", italic: "Corsivo", underline: "Sottolineato", strikethrough: "Barrato", subscript: "Pedice", superscript: "Apice", justifyleft: "Allinea a sinistra", justifycenter: "Allinea in centro", justifyright: "Allinea a destra", justifyfull: "Giustifica", insertorderedlist: "Lista ordinata", insertunorderedlist: "Lista puntata", outdent: "Decrementa indentazione", indent: "Incrementa indentazione", forecolor: "Colore del carattere", hilitecolor: "Colore di sfondo", inserthorizontalrule: "Linea orizzontale", createlink: "Inserisci un link", insertimage: "Inserisci un'immagine", inserttable: "Inserisci una tabella", htmlmode: "Visualizzazione HTML", popupeditor: "Editor a pieno schermo", about: "Info sull'editor", showhelp: "Aiuto sull'editor", textindicator: "Stile corrente", undo: "Annulla", redo: "Ripristina", cut: "Taglia", copy: "Copia", paste: "Incolla", lefttoright: "Scrivi da sinistra a destra", righttoleft: "Scrivi da destra a sinistra" }, buttons: { "ok": "OK", "cancel": "Annulla" }, msg: { "Path": "Percorso", "TEXT_MODE": "Sei in MODALITA' TESTO. Usa il bottone [<>] per tornare alla modalità WYSIWYG.", "IE-sucks-full-screen" : // translate here "The full screen mode is known to cause problems with Internet Explorer, " + "due to browser bugs that we weren't able to workaround. You might experience garbage " + "display, lack of editor functions and/or random browser crashes. If your system is Windows 9x " + "it's very likely that you'll get a 'General Protection Fault' and need to reboot.\n\n" + "You have been warned. Please press OK if you still want to try the full screen editor." }, dialogs: { "Annulla" : "Cancel", "Inserisci/modifica Link" : "Insert/Modify Link", "Nuova finestra (_blank)" : "New window (_blank)", "Nessuno (usa predefinito)" : "None (use implicit)", "OK" : "OK", "Altro" : "Other", "Stessa finestra (_self)" : "Same frame (_self)", "Target:" : "Target:", "Title (suggerimento):" : "Title (tooltip):", "Frame principale (_top)" : "Top frame (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "Devi inserire un indirizzo per questo link" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/lt.js0000644000175000017500000000625110177203647026025 0ustar frankiefrankie// I18N constants // LANG: "lt", ENCODING: UTF-8 // Author: Jaroslav Å atkeviÄ, HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "en", tooltips: { bold: "ParyÅ¡kinti", italic: "Kursyvas", underline: "Pabraukti", strikethrough: "Perbraukti", subscript: "Apatinis indeksas", superscript: "VirÅ¡utinis indeksas", justifyleft: "Lygiavimas pagal kairÄ™", justifycenter: "Lygiavimas pagal centrÄ…", justifyright: "Lygiavimas pagal deÅ¡inÄ™", justifyfull: "Lygiuoti pastraipÄ…", orderedlist: "Numeruotas sÄ…raÅ¡as", unorderedlist: "Suženklintas sÄ…raÅ¡as", outdent: "Sumažinti paraÅ¡tÄ™", indent: "Padidinti paraÅ¡tÄ™", forecolor: "Å rifto spalva", hilitecolor: "Fono spalva", horizontalrule: "Horizontali linija", createlink: "Ä®terpti nuorodÄ…", insertimage: "Ä®terpti paveiksliukÄ…", inserttable: "Ä®terpti lentelÄ™", htmlmode: "Perjungti į HTML/WYSIWYG", popupeditor: "IÅ¡plÄ—stas redagavimo ekranas/Enlarge Editor", about: "Apie redaktorių", showhelp: "Pagalba naudojant redaktorių", textindicator: "Dabartinis stilius", undo: "AtÅ¡aukia paskutini jÅ«sų veiksmÄ…", redo: "Pakartoja paskutinį atÅ¡auktÄ… jÅ«sų veiksmÄ…", cut: "IÅ¡kirpti", copy: "Kopijuoti", paste: "Ä®terpti" }, buttons: { "ok": "OK", "cancel": "AtÅ¡aukti" }, msg: { "Path": "Kelias", "TEXT_MODE": "JÅ«s esete teksto režime. Naudokite [<>] mygtukÄ… grįžimui į WYSIWYG.", "IE-sucks-full-screen" : // translate here "The full screen mode is known to cause problems with Internet Explorer, " + "due to browser bugs that we weren't able to workaround. You might experience garbage " + "display, lack of editor functions and/or random browser crashes. If your system is Windows 9x " + "it's very likely that you'll get a 'General Protection Fault' and need to reboot.\n\n" + "You have been warned. Please press OK if you still want to try the full screen editor." }, dialogs: { "Cancel" : "AtÅ¡aukti", "Insert/Modify Link" : "IdÄ—ti/Modifikuoti", "New window (_blank)" : "Naujas langas (_blank)", "None (use implicit)" : "None (use implicit)", "OK" : "OK", "Other" : "Kitas", "Same frame (_self)" : "Same frame (_self)", "Target:" : "Target:", "Title (tooltip):" : "Pavadinimas (tooltip):", "Top frame (_top)" : "Top frame (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "Jus privalote nurodyti URL į kuri rodo Å¡itÄ… nuoroda" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/lv.js0000644000175000017500000000347510177203647026034 0ustar frankiefrankie// I18N constants // LANG: "lv", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // Translated by: Janis Klavins, HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "lv", tooltips: { bold: "Trekniem burtiem", italic: "Kursîvâ", underline: "Pasvîtrots", strikethrough: "Pârsvîtrots", subscript: "Novietot zem rindas", superscript: "Novietot virs rindas", justifyleft: "Izlîdzinât pa kreisi", justifycenter: "Izlîdzinât centrâ", justifyright: "Izlîdzinât pa labi", justifyfull: "Izlîdzinât pa visu lapu", orderedlist: "Numurçts saraksts", unorderedlist: "Saraksts", outdent: "Samazinât atkâpi", indent: "Palielinât atkâpi", forecolor: "Burtu krâsa", hilitecolor: "Fona krâsa", horizontalrule: "Horizontâla atdalîtâjsvîtra", createlink: "Ievietot hipersaiti", insertimage: "Ievietot attçlu", inserttable: "Ievietot tabulu", htmlmode: "Skatît HTML kodu", popupeditor: "Palielinât Rediìçtâju", about: "Par ðo rediìçtâju", showhelp: "Rediìçtâja palîgs", textindicator: "Patreizçjais stils", undo: "Atcelt pçdçjo darbîbu", redo: "Atkârtot pçdçjo darbîbu", cut: "Izgriezt iezîmçto", copy: "Kopçt iezîmçto", paste: "Ievietot iezîmçto" }, buttons: { "ok": "Labi", "cancel": "Atcelt" }, msg: { "Path": "Ceïð", "TEXT_MODE": "Jûs patlaban darbojaties TEKSTA REÞÎMÂ. Lai pârietu atpakaï uz GRAFISKO REÞÎMU (WYSIWIG), lietojiet [<>] pogu." } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/nb.js0000644000175000017500000000206110177203647026000 0ustar frankiefrankie// I18N constants HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "nb", tooltips: { bold: "Fet", italic: "Kursiv", underline: "Understreket", strikethrough: "Gjennomstreket", subscript: "Senket", superscript: "Hevet", justifyleft: "Venstrejuster", justifycenter: "Midtjuster", justifyright: "Høyrejuster", justifyfull: "Blokkjuster", orderedlist: "Nummerert liste", unorderedlist: "Punktmerket liste", outdent: "Øke innrykk", indent: "Reduser innrykk", forecolor: "Skriftfarge", backcolor: "Bakgrunnsfarge", horizontalrule: "Horisontal linje", createlink: "Sett inn lenke", insertimage: "Sett inn bilde", inserttable: "Sett inn tabell", htmlmode: "Vis HTML kode", popupeditor: "Forstørr redigeringsvindu", about: "Om..", help: "Hjelp", textindicator: "Gjeldende stil" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/nl.js0000644000175000017500000000700510177203647026015 0ustar frankiefrankie// I18N constants // LANG: "nl", ENCODING: UTF-8 | ISO-8859-1 // Author: Michel Weegeerink (info@mmc-shop.nl), http://mmc-shop.nl // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "nl", tooltips: { bold: "Vet", italic: "Cursief", underline: "Onderstrepen", strikethrough: "Doorhalen", subscript: "Subscript", superscript: "Superscript", justifyleft: "Links uitlijnen", justifycenter: "Centreren", justifyright: "Rechts uitlijnen", justifyfull: "Uitvullen", orderedlist: "Nummering", unorderedlist: "Opsommingstekens", outdent: "Inspringing verkleinen", indent: "Inspringing vergroten", forecolor: "Tekstkleur", hilitecolor: "Achtergrondkleur", inserthorizontalrule: "Horizontale lijn", createlink: "Hyperlink invoegen/aanpassen", insertimage: "Afbeelding invoegen/aanpassen", inserttable: "Tabel invoegen", htmlmode: "HTML broncode", popupeditor: "Vergroot Editor", about: "Over deze editor", showhelp: "HTMLArea help", textindicator: "Huidige stijl", undo: "Ongedaan maken", redo: "Herhalen", cut: "Knippen", copy: "Kopiëren", paste: "Plakken", lefttoright: "Tekstrichting links naar rechts", righttoleft: "Tekstrichting rechts naar links" }, buttons: { "ok": "OK", "cancel": "Annuleren" }, msg: { "Path": "Pad", "TEXT_MODE": "Je bent in TEKST-mode. Gebruik de [<>] knop om terug te keren naar WYSIWYG-mode.", "IE-sucks-full-screen" : // translate here "Fullscreen-mode veroorzaakt problemen met Internet Explorer door bugs in de webbrowser " + "die we niet kunnen omzeilen. Hierdoor kunnen de volgende effecten optreden: verknoeide teksten, " + "een verlies aan editor-functionaliteit en/of willekeurig vastlopen van de webbrowser. " + "Als u Windows 95 of 98 gebruikt, is het zeer waarschijnlijk dat u een algemene beschermingsfout " + "('General Protection Fault') krijgt en de computer opnieuw zal moeten opstarten.\n\n" + "U bent gewaarschuwd. Druk OK als u toch nog de Fullscreen-editor wil gebruiken." }, dialogs: { "Cancel" : "Annuleren", "Insert/Modify Link" : "Hyperlink invoegen/aanpassen", "New window (_blank)" : "Nieuw venster (_blank)", "None (use implicit)" : "Geen", "OK" : "OK", "Other" : "Ander", "Same frame (_self)" : "Zelfde frame (_self)", "Target:" : "Doel:", "Title (tooltip):" : "Titel (tooltip):", "Top frame (_top)" : "Bovenste frame (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "Geef de URL in waar de link naar verwijst" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/no.js0000644000175000017500000000671010177203647026022 0ustar frankiefrankie// Norwegian version for htmlArea v3.0 - pre1 // - translated by ses // Additional translations by Håvard Wigtil // term´s and licenses are equal to htmlarea! HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "no", tooltips: { bold: "Fet", italic: "Kursiv", underline: "Understreket", strikethrough: "Gjennomstreket", subscript: "Nedsenket", superscript: "Opphøyet", justifyleft: "Venstrejuster", justifycenter: "Midtjuster", justifyright: "Høyrejuster", justifyfull: "Blokkjuster", orderedlist: "Nummerert liste", unorderedlist: "Punktliste", outdent: "Reduser innrykk", indent: "Øke innrykk", forecolor: "Tekstfarge", hilitecolor: "Bakgrundsfarge", inserthorizontalrule: "Vannrett linje", createlink: "Lag lenke", insertimage: "Sett inn bilde", inserttable: "Sett inn tabell", htmlmode: "Vis kildekode", popupeditor: "Vis i eget vindu", about: "Om denne editor", showhelp: "Hjelp", textindicator: "Nåværende stil", undo: "Angrer siste redigering", redo: "Gjør om siste angring", cut: "Klipp ut område", copy: "Kopier område", paste: "Lim inn", lefttoright: "Fra venstre mot høyre", righttoleft: "Fra høyre mot venstre" }, buttons: { "ok": "OK", "cancel": "Avbryt" }, msg: { "Path": "Tekstvelger", "TEXT_MODE": "Du er i tekstmodus Klikk på [<>] for å gå tilbake til WYSIWIG.", "IE-sucks-full-screen" : // translate here "Visning i eget vindu har kjente problemer med Internet Explorer, " + "på grunn av problemer med denne nettleseren. Mulige problemer er et uryddig " + "skjermbilde, manglende editorfunksjoner og/eller at nettleseren crasher. Hvis du bruker Windows 95 eller Windows 98 " + "er det også muligheter for at Windows will crashe.\n\n" + "Trykk 'OK' hvis du vil bruke visning i eget vindu på tross av denne advarselen." }, dialogs: { "Cancel" : "Avbryt", "Insert/Modify Link" : "Rediger lenke", "New window (_blank)" : "Eget vindu (_blank)", "None (use implicit)" : "Ingen (bruk standardinnstilling)", "OK" : "OK", "Other" : "Annen", "Same frame (_self)" : "Samme ramme (_self)", "Target:" : "Mål:", "Title (tooltip):" : "Tittel (tooltip):", "Top frame (_top)" : "Toppramme (_top)", "URL:" : "Adresse:", "You must enter the URL where this link points to" : "Du må skrive inn en adresse som denne lenken skal peke til" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/pl.js0000644000175000017500000000217510177203647026022 0ustar frankiefrankie// I18N constants HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "pl", tooltips: { bold: "Pogrubienie", italic: "Pochylenie", underline: "Podkreœlenie", strikethrough: "Przekreœlenie", subscript: "Indeks dolny", superscript: "Indeks górny", justifyleft: "Wyrównaj do lewej", justifycenter: "Wyœrodkuj", justifyright: "Wyrównaj do prawej", justifyfull: "Wyjustuj", orderedlist: "Numerowanie", unorderedlist: "Wypunktowanie", outdent: "Zmniejsz wciêcie", indent: "Zwiêksz wciêcie", forecolor: "Kolor czcionki", backcolor: "Kolor t³a", horizontalrule: "Linia pozioma", createlink: "Wstaw adres sieci Web", insertimage: "Wstaw obraz", inserttable: "Wstaw tabelê", htmlmode: "Edycja WYSIWYG/w Ÿródle strony", popupeditor: "Pe³ny ekran", about: "Informacje o tym edytorze", help: "Pomoc", textindicator: "Obecny styl" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ro.js0000644000175000017500000000605510177203647026030 0ustar frankiefrankie// I18N constants // LANG: "ro", ENCODING: UTF-8 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ro", tooltips: { bold: "ÃŽngroÅŸat", italic: "Italic", underline: "Subliniat", strikethrough: "Tăiat", subscript: "Indice jos", superscript: "Indice sus", justifyleft: "Aliniere la stânga", justifycenter: "Aliniere pe centru", justifyright: "Aliniere la dreapta", justifyfull: "Aliniere în ambele părÅ£i", orderedlist: "Listă ordonată", unorderedlist: "Listă marcată", outdent: "MicÅŸorează alineatul", indent: "MăreÅŸte alineatul", forecolor: "Culoarea textului", hilitecolor: "Culoare de fundal", horizontalrule: "Linie orizontală", createlink: "Inserează/modifică link", insertimage: "Inserează/modifică imagine", inserttable: "Inserează un tabel", htmlmode: "Sursa HTML / WYSIWYG", popupeditor: "Maximizează editorul", about: "Despre editor", showhelp: "DocumentaÅ£ie (devel)", textindicator: "Stilul curent", undo: "Anulează ultima acÅ£iune", redo: "Reface ultima acÅ£iune anulată", cut: "Taie în clipboard", copy: "Copie în clipboard", paste: "Aduce din clipboard", lefttoright: "DirecÅ£ia de scriere: stânga - dreapta", righttoleft: "DirecÅ£ia de scriere: dreapta - stânga" }, buttons: { "ok": "OK", "cancel": "Anulează" }, msg: { "Path": "Calea", "TEXT_MODE": "EÅŸti în modul TEXT. Apasă butonul [<>] pentru a te întoarce în modul WYSIWYG." }, dialogs: { "Cancel" : "Renunţă", "Insert/Modify Link" : "Inserează/modifcă link", "New window (_blank)" : "Fereastră nouă (_blank)", "None (use implicit)" : "Nimic (foloseÅŸte ce-i implicit)", "OK" : "Acceptă", "Other" : "Alt target", "Same frame (_self)" : "AceeaÅŸi fereastră (_self)", "Target:" : "Å¢inta:", "Title (tooltip):" : "Titlul (tooltip):", "Top frame (_top)" : "Fereastra principală (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "Trebuie să introduceÅ£i un URL" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/se.js0000644000175000017500000000227310177203647026015 0ustar frankiefrankie// Swedish version for htmlArea v3.0 - Alpha Release // - translated by pat // term´s and licenses are equal to htmlarea! HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "se", tooltips: { bold: "Fet", italic: "Kursiv", underline: "Understruken", strikethrough: "Genomstruken", subscript: "Nedsänkt", superscript: "Upphöjd", justifyleft: "Vänsterjustera", justifycenter: "Centrera", justifyright: "Högerjustera", justifyfull: "Marginaljustera", orderedlist: "Numrerad lista", unorderedlist: "Punktlista", outdent: "Minska indrag", indent: "Öka indrag", forecolor: "Textfärg", backcolor: "Bakgrundsfärg", horizontalrule: "Vågrät linje", createlink: "Infoga länk", insertimage: "Infoga bild", inserttable: "Infoga tabell", htmlmode: "Visa källkod", popupeditor: "Visa i eget fönster", about: "Om denna editor", help: "Hjälp", textindicator: "Nuvarande stil" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/si.js0000644000175000017500000000362210177203647026020 0ustar frankiefrankie// I18N constants // LANG: "si", ENCODING: ISO-8859-2 // Author: Tomaz Kregar, x_tomo_x@email.si // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "si", tooltips: { bold: "Krepko", italic: "Le¾eèe", underline: "Podèrtano", strikethrough: "Preèrtano", subscript: "Podpisano", superscript: "Nadpisano", justifyleft: "Poravnaj levo", justifycenter: "Na sredino", justifyright: "Poravnaj desno", justifyfull: "Porazdeli vsebino", orderedlist: "O¹tevilèevanje", unorderedlist: "Oznaèevanje", outdent: "Zmanj¹aj zamik", indent: "Poveèaj zamik", forecolor: "Barva pisave", hilitecolor: "Barva ozadja", horizontalrule: "Vodoravna èrta", createlink: "Vstavi hiperpovezavo", insertimage: "Vstavi sliko", inserttable: "Vstavi tabelo", htmlmode: "Preklopi na HTML kodo", popupeditor: "Poveèaj urejevalnik", about: "Vizitka za urejevalnik", showhelp: "Pomoè za urejevalnik", textindicator: "Trenutni slog", undo: "Razveljavi zadnjo akcijo", redo: "Uveljavi zadnjo akcijo", cut: "Izre¾i", copy: "Kopiraj", paste: "Prilepi" }, buttons: { "ok": "V redu", "cancel": "Preklièi" }, msg: { "Path": "Pot", "TEXT_MODE": "Si v tekstovnem naèinu. Uporabi [<>] gumb za prklop nazaj na WYSIWYG." } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ru.js0000644000175000017500000000456310177203647026040 0ustar frankiefrankie// I18N constants // LANG: "ru", ENCODING: UTF-8 | ISO-8859-1 // Author: Yulya Shtyryakova, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ru", tooltips: { bold: "Полужирный", italic: "Ðаклонный", underline: "Подчеркнутый", strikethrough: "Перечеркнутый", subscript: "Ðижний индекÑ", superscript: "Верхний индекÑ", justifyleft: "По левому краю", justifycenter: "По центру", justifyright: "По правому краю", justifyfull: "По ширине", orderedlist: "Ðумерованный лиÑÑ‚", unorderedlist: "Маркированный лиÑÑ‚", outdent: "Уменьшить отÑтуп", indent: "Увеличить отÑтуп", forecolor: "Цвет шрифта", hilitecolor: "Цвет фона", horizontalrule: "Горизонтальный разделитель", createlink: "Ð’Ñтавить гиперÑÑылку", insertimage: "Ð’Ñтавить изображение", inserttable: "Ð’Ñтавить таблицу", htmlmode: "Показать Html-код", popupeditor: "Увеличить редактор", about: "О редакторе", showhelp: "Помощь", textindicator: "Текущий Ñтиль", undo: "Отменить", redo: "Повторить", cut: "Вырезать", copy: "Копировать", paste: "Ð’Ñтавить" }, buttons: { "ok": "OK", "cancel": "Отмена" }, msg: { "Path": "Путь", "TEXT_MODE": "Ð’Ñ‹ в режиме Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Html-кода. нажмите кнопку [<>], чтобы переключитьÑÑ Ð² визуальный режим." } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/vn.js0000644000175000017500000000732410177203647026033 0ustar frankiefrankie// I18N constants : Vietnamese // LANG: "en", ENCODING: UTF-8 // Author: Nguyá»…n Äình Nam, // Modified 21/07/2004 by Phạm Mai Quân HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "vn", tooltips: { bold: "Äậm", italic: "Nghiêng", underline: "Gạch Chân", strikethrough: "Gạch Xóa", subscript: "Viết Xuống Dưới", superscript: "Viết Lên Trên", justifyleft: "Căn Trái", justifycenter: "Căn Giữa", justifyright: "Căn Phải", justifyfull: "Căn Äá»u", insertorderedlist: "Danh Sách Có Thứ Tá»± (1, 2, 3)", insertunorderedlist: "Danh Sách Phi Thứ Tá»± (Chấm đầu dòng)", outdent: "Lùi Ra Ngoài", indent: "Thụt Vào Trong", forecolor: "Màu Chữ", hilitecolor: "Màu Ná»n", inserthorizontalrule: "Dòng Kẻ Ngang", createlink: "Tạo Liên Kết", insertimage: "Chèn Ảnh", inserttable: "Chèn Bảng", htmlmode: "Chế Äá»™ Mã HTML", popupeditor: "Phóng To Ô Soạn Thảo", about: "Tá»± Giá»›i Thiệu", showhelp: "Giúp Äỡ", textindicator: "Äịnh Dạng Hiện Thá»i", undo: "Há»§y thao tác trước", redo: "Lấy lại thao tác vừa bá»", cut: "Cắt", copy: "Sao chép", paste: "Dán", lefttoright: "Viết từ trái sang phải", righttoleft: "Viết từ phải sang trái" }, buttons: { "ok": "Äồng ý", "cancel": "Há»§y", "IE-sucks-full-screen" : // translate here "Chế độ phóng to ô soạn thảo có thể gây lá»—i vá»›i Internet Explorer vì má»™t số lá»—i cá»§a trình duyệt này," + " vì thế chế độ này có thể sẽ không chạy. Hiển thị không đúng, lá»™n xá»™n, không có đầy đủ chức năng," + " và cÅ©ng có thể làm trình duyệt cá»§a bạn bị tắt ngang. Nếu bạn Ä‘ang sá»­ dụng Windows 9x " + "bạn có thể bị báo lá»—i 'General Protection Fault' và máy tính cá»§a bạn buá»™c phải khởi động lại.\n\n" + "Chúng tôi đã cảnh báo bạn. Nhấn nút 'Äồng ý' nếu bạn vẫn muốn sá»­ dụng tính năng này." }, msg: { "Path": "ÄÆ°á»ng Dẫn", "TEXT_MODE": "Bạn Ä‘ang ở chế độ text. Sá»­ dụng nút [<>] để chuyển lại chế độ WYSIWIG." }, dialogs: { "Cancel" : "Há»§y", "Insert/Modify Link" : "Thêm/Chỉnh sá»­a đưá»ng dẫn", "New window (_blank)" : "Cá»­a sổ má»›i (_blank)", "None (use implicit)" : "Không (sá»­ dụng implicit)", "OK" : "Äồng ý", "Other" : "Khác", "Same frame (_self)" : "Trên cùng khung (_self)", "Target:" : "NÆ¡i hiện thị:", "Title (tooltip):" : "Tiêu đỠ(cá»§a hướng dẫn):", "Top frame (_top)" : "Khung trên cùng (_top)", "URL:" : "URL:", "You must enter the URL where this link points to" : "Bạn phải Ä‘iá»n địa chỉ (URL) mà đưá»ng dẫn sẽ liên kết tá»›i" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ja-utf8.js0000644000175000017500000000226610177203647026666 0ustar frankiefrankie// I18N constants -- Japanese UTF-8 // by Manabu Onoue -- tmocsys@tmocsys.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ja-utf8", tooltips: { bold: "太字", italic: "斜体", underline: "下線", strikethrough: "æ‰“ã¡æ¶ˆã—ç·š", subscript: "ä¸‹ä»˜ãæ·»ãˆå­—", superscript: "ä¸Šä»˜ãæ·»ãˆå­—", justifyleft: "左寄ã›", justifycenter: "中央寄ã›", justifyright: "å³å¯„ã›", justifyfull: "å‡ç­‰å‰²ä»˜", orderedlist: "番å·ä»˜ãç®‡æ¡æ›¸ã", unorderedlist: "記å·ä»˜ãç®‡æ¡æ›¸ã", outdent: "インデント解除", indent: "インデント設定", forecolor: "文字色", backcolor: "背景色", horizontalrule: "水平線", createlink: "リンク作æˆ", insertimage: "ç”»åƒæŒ¿å…¥", inserttable: "テーブル挿入", htmlmode: "HTML表示切替", popupeditor: "エディタ拡大", about: "ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…å ±", help: "ヘルプ", textindicator: "ç¾åœ¨ã®ã‚¹ã‚¿ã‚¤ãƒ«" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ja-euc.js0000644000175000017500000000207210177203647026547 0ustar frankiefrankie// I18N constants -- Japanese EUC // by Manabu Onoue -- tmocsys@tmocsys.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ja-euc", tooltips: { bold: "ÂÀ»ú", italic: "¼ÐÂÎ", underline: "²¼Àþ", strikethrough: "ÂǤÁ¾Ã¤·Àþ", subscript: "²¼ÉÕ¤­Åº¤¨»ú", superscript: "¾åÉÕ¤­Åº¤¨»ú", justifyleft: "º¸´ó¤»", justifycenter: "Ãæ±û´ó¤»", justifyright: "±¦´ó¤»", justifyfull: "¶ÑÅù³äÉÕ", orderedlist: "ÈÖ¹æÉÕ¤­²Õ¾ò½ñ¤­", unorderedlist: "µ­¹æÉÕ¤­²Õ¾ò½ñ¤­", outdent: "¥¤¥ó¥Ç¥ó¥È²ò½ü", indent: "¥¤¥ó¥Ç¥ó¥ÈÀßÄê", forecolor: "ʸ»ú¿§", backcolor: "ÇØ·Ê¿§", horizontalrule: "¿åÊ¿Àþ", createlink: "¥ê¥ó¥¯ºîÀ®", insertimage: "²èÁüÁÞÆþ", inserttable: "¥Æ¡¼¥Ö¥ëÁÞÆþ", htmlmode: "HTMLɽ¼¨ÀÚÂØ", popupeditor: "¥¨¥Ç¥£¥¿³ÈÂç", about: "¥Ð¡¼¥¸¥ç¥ó¾ðÊó", help: "¥Ø¥ë¥×", textindicator: "¸½ºß¤Î¥¹¥¿¥¤¥ë" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ja-jis.js0000644000175000017500000000232010177203647026554 0ustar frankiefrankie// I18N constants -- Japanese JIS // by Manabu Onoue -- tmocsys@tmocsys.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ja-jis", tooltips: { bold: "$BB@;z(B", italic: "$BC$7@~(B", subscript: "$B2eIU$-E:$(;z(B", justifyleft: "$B:84s$;(B", justifycenter: "$BCf1{4s$;(B", justifyright: "$B1&4s$;(B", justifyfull: "$B6QEy3dIU(B", orderedlist: "$BHV9fIU$-2U>r=q$-(B", unorderedlist: "$B5-9fIU$-2U>r=q$-(B", outdent: "$B%$%s%G%s%H2r=|(B", indent: "$B%$%s%G%s%H@_Dj(B", forecolor: "$BJ8;z?'(B", backcolor: "$BGX7J?'(B", horizontalrule: "$B?eJ?@~(B", createlink: "$B%j%s%/:n@.(B", insertimage: "$B2hA|A^F~(B", inserttable: "$B%F!<%V%kA^F~(B", htmlmode: "HTML$BI=<(@ZBX(B", popupeditor: "$B%(%G%#%?3HBg(B", about: "$B%P!<%8%g%s>pJs(B", help: "$B%X%k%W(B", textindicator: "$B8=:_$N%9%?%$%k(B" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/pt_br.js0000644000175000017500000000225710177203647026516 0ustar frankiefrankie// I18N constants // Brazilian Portuguese Translation by Alex Piaz HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "pt_br", tooltips: { bold: "Negrito", italic: "Itálico", underline: "Sublinhado", strikethrough: "Tachado", subscript: "Subescrito", superscript: "Sobrescrito", justifyleft: "Alinhar à Esquerda", justifycenter: "Centralizar", justifyright: "Alinhar à Direita", justifyfull: "Justificar", orderedlist: "Lista Numerada", unorderedlist: "Lista Marcadores", outdent: "Diminuir Indentação", indent: "Aumentar Indentação", forecolor: "Cor da Fonte", backcolor: "Cor do Fundo", horizontalrule: "Linha Horizontal", createlink: "Inserir Link", insertimage: "Inserir Imagem", inserttable: "Inserir Tabela", htmlmode: "Ver Código-Fonte", popupeditor: "Expandir Editor", about: "Sobre", help: "Ajuda", textindicator: "Estilo Atual" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/lang/ja-sjis.js0000644000175000017500000000210110177203647026734 0ustar frankiefrankie// I18N constants -- Japanese Shift-JIS // by Manabu Onoue -- tmocsys@tmocsys.com HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "ja-sjis", tooltips: { bold: "‘¾Žš", italic: "ŽÎ‘Ì", underline: "‰ºü", strikethrough: "‘Å‚¿Á‚µü", subscript: "‰º•t‚«“Y‚¦Žš", superscript: "ã•t‚«“Y‚¦Žš", justifyleft: "¶Šñ‚¹", justifycenter: "’†‰›Šñ‚¹", justifyright: "‰EŠñ‚¹", justifyfull: "‹Ï“™Š„•t", orderedlist: "”Ô†•t‚«‰Óð‘‚«", unorderedlist: "‹L†•t‚«‰Óð‘‚«", outdent: "ƒCƒ“ƒfƒ“ƒg‰ðœ", indent: "ƒCƒ“ƒfƒ“ƒgÝ’è", forecolor: "•¶ŽšF", backcolor: "”wŒiF", horizontalrule: "…•½ü", createlink: "ƒŠƒ“ƒNì¬", insertimage: "‰æ‘œ‘}“ü", inserttable: "ƒe[ƒuƒ‹‘}“ü", htmlmode: "HTML•\Ž¦Ø‘Ö", popupeditor: "ƒGƒfƒBƒ^Šg‘å", about: "ƒo[ƒWƒ‡ƒ“î•ñ", help: "ƒwƒ‹ƒv", textindicator: "Œ»Ý‚̃Xƒ^ƒCƒ‹" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/htmlarea.css0000644000175000017500000001035610177203646026436 0ustar frankiefrankie.htmlarea { background: #fff; } .htmlarea .toolbar { cursor: default; background: ButtonFace; padding: 3px; border: 1px solid; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; } .htmlarea .toolbar table { font-family: tahoma,verdana,sans-serif; font-size: 11px; } .htmlarea .toolbar img { border: none; } .htmlarea .toolbar .label { padding: 0px 3px; } .htmlarea .toolbar .button { background: ButtonFace; color: ButtonText; border: 1px solid ButtonFace; padding: 1px; margin: 0px; width: 18px; height: 18px; } .htmlarea .toolbar .buttonHover { border: 1px solid; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; } .htmlarea .toolbar .buttonActive, .htmlarea .toolbar .buttonPressed { padding: 2px 0px 0px 2px; border: 1px solid; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; } .htmlarea .toolbar .buttonPressed { background: ButtonHighlight; } .htmlarea .toolbar .indicator { padding: 0px 3px; overflow: hidden; width: 20px; text-align: center; cursor: default; border: 1px solid ButtonShadow; } .htmlarea .toolbar .buttonDisabled img { filter: gray() alpha(opacity = 25); -moz-opacity: 0.25; } .htmlarea .toolbar .separator { position: relative; margin: 3px; border-left: 1px solid ButtonShadow; border-right: 1px solid ButtonHighlight; width: 0px; height: 16px; padding: 0px; } .htmlarea .toolbar .space { width: 5px; } .htmlarea .toolbar select { font: 11px Tahoma,Verdana,sans-serif; } .htmlarea .toolbar select, .htmlarea .toolbar select:hover, .htmlarea .toolbar select:active { background: FieldFace; color: ButtonText; } .htmlarea .statusBar { border: 1px solid; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; padding: 2px 4px; background-color: ButtonFace; color: ButtonText; font: 11px Tahoma,Verdana,sans-serif; } .htmlarea .statusBar .statusBarTree a { padding: 2px 5px; color: #00f; } .htmlarea .statusBar .statusBarTree a:visited { color: #00f; } .htmlarea .statusBar .statusBarTree a:hover { background-color: Highlight; color: HighlightText; padding: 1px 4px; border: 1px solid HighlightText; } /* Hidden DIV popup dialogs (PopupDiv) */ .dialog { color: ButtonText; background: ButtonFace; } .dialog .content { padding: 2px; } .dialog, .dialog button, .dialog input, .dialog select, .dialog textarea, .dialog table { font: 11px Tahoma,Verdana,sans-serif; } .dialog table { border-collapse: collapse; } .dialog .title { background: #008; color: #ff8; border-bottom: 1px solid #000; padding: 1px 0px 2px 5px; font-size: 12px; font-weight: bold; cursor: default; } .dialog .title .button { float: right; border: 1px solid #66a; padding: 0px 1px 0px 2px; margin-right: 1px; color: #fff; text-align: center; } .dialog .title .button-hilite { border-color: #88f; background: #44c; } .dialog button { width: 5em; padding: 0px; } .dialog .buttonColor { padding: 1px; cursor: default; border: 1px solid; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; } .dialog .buttonColor-hilite { border-color: #000; } .dialog .buttonColor .chooser, .dialog .buttonColor .nocolor { height: 0.6em; border: 1px solid; padding: 0px 1em; border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; } .dialog .buttonColor .nocolor { padding: 0px; } .dialog .buttonColor .nocolor-hilite { background-color: #fff; color: #f00; } .dialog .label { text-align: right; width: 6em; } .dialog .value input { width: 100%; } .dialog .buttons { text-align: right; padding: 2px 4px 0px 4px; } .dialog legend { font-weight: bold; } .dialog fieldset table { margin: 2px 0px; } .popupdiv { border: 2px solid; border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; } .popupwin { padding: 0px; margin: 0px; } .popupwin .title { background: #fff; color: #000; font-weight: bold; font-size: 120%; padding: 3px 10px; margin-bottom: 10px; border-bottom: 1px solid black; letter-spacing: 2px; } form { margin: 0px; border: none; } openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/index.html0000644000175000017500000001676410657773140026141 0ustar frankiefrankie HTMLArea -- the free, customizable online editor

    Version:3.0
    Release:RC3 (release notes)
    Compiled at:Jan , 2005 [23:43] GMT
    SourceForge page:http://sf.net/projects/itools-htmlarea/

    HTMLArea -- the free
    customizable online editor

    HTMLArea is a free, customizable online editor. It works inside your browser. It uses a non-standard feature implemented in Internet Explorer 5.5 or better for Windows and Mozilla 1.3 or better (any platform), therefore it will only work in one of these browsers.

    HTMLArea is copyright InteractiveTools.com and Dynarch.com and it is released under a BSD-style license. HTMLArea is created and developed upto version 2.03 by InteractiveTools.com. Version 3.0 developed by Mihai Bazon for InteractiveTools. It contains code sponsored by third-party companies as well. Please see our About Box for details about who sponsored what plugins.

    Online demos

    Installation

    Installation is (or should be) easy. You need to unpack the ZIP file in a directory accessible through your webserver. Supposing you unpack in your DocumentRoot and your DocumentRoot is /var/www/html as in a standard RedHat installation, you need to acomplish the following steps: (the example is for a Unix-like operating system)

    cd /var/www/html
    unzip /path/to/archive/HTMLArea-3.0-RC3.zip
    mv HTMLArea-3.0-RC3 htmlarea
    find htmlarea/ -type f -exec chmod 644 {} \;
    find htmlarea/ -type d -exec chmod 755 {} \;
    find htmlarea/ -name "*.cgi" -exec chmod 755 {} \;

    Notes. You may chose to symlink "htmlarea" to "HTMLArea-3.0-RC3", in which case your server needs to be configured to "FollowSymLinks". You need to make sure that *.cgi files are interpreted as CGI scripts. If you want to use the SpellChecker plugin you need to have a recent version of Perl installed (I recommend 5.8.0) on the server, and the module Text::Aspell, available from CPAN. More info in "plugins/SpellChecker/readme-tech.html".

    About how to setup your pages to use the editor, please read the [outdated yet generally valid] documentation.

    Status and links

    HTMLArea has reached version 3.0. As of this version, it supports:

    • Customizable toolbar
    • Easy internationalization
    • Plugin-based infrastructure
    • Delivers W3-compliant HTML (with few exceptions)
    • Has a subset of Microsoft Word's keyboard shortcuts
    • Full-screen editor
    • Advanced table operations (by external plugin "TableOperations")
    • Spell checker (by external plugin "SpellChecker")
    • probably more... ;-)

    We have a project page at SourceForge.net. There you can also find out how to retrieve the code from CVS, or you can browse the CVS online. We also have a bug system, a patch tracking system and a feature request page.

    We invite you to say everything you want about HTMLArea on the forums at InteractiveTools.com. There you should also find the latest news.

    "It doesn't work, what's wrong?"

    If it doesn't work, you have several options:

    • Post a message to the forum. Describe your problem in as much detail as possible. Include errors you might find in the JavaScript console (if you are a Mozilla user), or errors displayed by IE (though they're most of the times useless).
    • If you're positive that you discovered a bug in HTMLArea then feel free to fill a bug report in our bug system. If you have the time you should check to see if a similar bug was reported or not; it might be fixed already in the CVS ;-) If you're positive that a similar bug was not yet reported, do fill a bug report and please include as much detail as possible, such as your browser, OS, errors from JavaScript console, etc.
    • If you want a new feature to be implemented, post it on the features request and someone will hopefully take care of it.

    Last modified: Wed Jul 14 13:20:53 CEST 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popupdiv.js0000644000175000017500000002345710177203646026341 0ustar frankiefrankie/** This file is derived from PopupDiv, developed by Mihai Bazon for * SamWare.net. Modifications were needed to make it usable in HTMLArea. * HTMLArea is a free WYSIWYG online HTML editor from InteractiveTools.com. * * This file does not function standalone. It is dependent of global functions * defined in HTMLArea-3.0 (htmlarea.js). * * Please see file htmlarea.js for further details. **/ var is_ie = ( (navigator.userAgent.toLowerCase().indexOf("msie") != -1) && (navigator.userAgent.toLowerCase().indexOf("opera") == -1) ); var is_compat = (document.compatMode == "BackCompat"); function PopupDiv(editor, titleText, handler, initFunction) { var self = this; this.editor = editor; this.doc = editor._mdoc; this.handler = handler; var el = this.doc.createElement("div"); el.className = "content"; var popup = this.doc.createElement("div"); popup.className = "dialog popupdiv"; this.element = popup; var s = popup.style; s.position = "absolute"; s.left = "0px"; s.top = "0px"; var title = this.doc.createElement("div"); title.className = "title"; this.title = title; popup.appendChild(title); HTMLArea._addEvent(title, "mousedown", function(ev) { self._dragStart(is_ie ? window.event : ev); }); var button = this.doc.createElement("div"); button.className = "button"; title.appendChild(button); button.innerHTML = "×"; title.appendChild(this.doc.createTextNode(titleText)); this.titleText = titleText; button.onmouseover = function() { this.className += " button-hilite"; }; button.onmouseout = function() { this.className = this.className.replace(/\s*button-hilite\s*/g, " "); }; button.onclick = function() { this.className = this.className.replace(/\s*button-hilite\s*/g, " "); self.close(); }; popup.appendChild(el); this.content = el; this.doc.body.appendChild(popup); this.dragging = false; this.onShow = null; this.onClose = null; this.modal = false; initFunction(this); }; PopupDiv.currentPopup = null; PopupDiv.prototype.showAtElement = function(el, mode) { this.defaultSize(); var pos, ew, eh; var popup = this.element; popup.style.display = "block"; var w = popup.offsetWidth; var h = popup.offsetHeight; popup.style.display = "none"; if (el != window) { pos = PopupDiv.getAbsolutePos(el); ew = el.offsetWidth; eh = el.offsetHeight; } else { pos = {x:0, y:0}; var size = PopupDiv.getWindowSize(); ew = size.x; eh = size.y; } var FX = false, FY = false; if (mode.indexOf("l") != -1) { pos.x -= w; FX = true; } if (mode.indexOf("r") != -1) { pos.x += ew; FX = true; } if (mode.indexOf("t") != -1) { pos.y -= h; FY = true; } if (mode.indexOf("b") != -1) { pos.y += eh; FY = true; } if (mode.indexOf("c") != -1) { FX || (pos.x += Math.round((ew - w) / 2)); FY || (pos.y += Math.round((eh - h) / 2)); } this.showAt(pos.x, pos.y); }; PopupDiv.prototype.defaultSize = function() { var s = this.element.style; var cs = this.element.currentStyle; var addX = (is_ie && is_compat) ? (parseInt(cs.borderLeftWidth) + parseInt(cs.borderRightWidth) + parseInt(cs.paddingLeft) + parseInt(cs.paddingRight)) : 0; var addY = (is_ie && is_compat) ? (parseInt(cs.borderTopWidth) + parseInt(cs.borderBottomWidth) + parseInt(cs.paddingTop) + parseInt(cs.paddingBottom)) : 0; s.display = "block"; s.width = (this.content.offsetWidth + addX) + "px"; s.height = (this.content.offsetHeight + this.title.offsetHeight) + "px"; s.display = "none"; }; PopupDiv.prototype.showAt = function(x, y) { this.defaultSize(); var s = this.element.style; s.display = "block"; s.left = x + "px"; s.top = y + "px"; this.hideShowCovered(); PopupDiv.currentPopup = this; HTMLArea._addEvents(this.doc.body, ["mousedown", "click"], PopupDiv.checkPopup); HTMLArea._addEvents(this.editor._doc.body, ["mousedown", "click"], PopupDiv.checkPopup); if (is_ie && this.modal) { this.doc.body.setCapture(false); this.doc.body.onlosecapture = function() { (PopupDiv.currentPopup) && (this.doc.body.setCapture(false)); }; } window.event && HTMLArea._stopEvent(window.event); if (typeof this.onShow == "function") { this.onShow(); } else if (typeof this.onShow == "string") { eval(this.onShow); } var field = this.element.getElementsByTagName("input")[0]; if (!field) { field = this.element.getElementsByTagName("select")[0]; } if (!field) { field = this.element.getElementsByTagName("textarea")[0]; } if (field) { field.focus(); } }; PopupDiv.prototype.close = function() { this.element.style.display = "none"; PopupDiv.currentPopup = null; this.hideShowCovered(); HTMLArea._removeEvents(this.doc.body, ["mousedown", "click"], PopupDiv.checkPopup); HTMLArea._removeEvents(this.editor._doc.body, ["mousedown", "click"], PopupDiv.checkPopup); is_ie && this.modal && this.doc.body.releaseCapture(); if (typeof this.onClose == "function") { this.onClose(); } else if (typeof this.onClose == "string") { eval(this.onClose); } this.element.parentNode.removeChild(this.element); }; PopupDiv.prototype.getForm = function() { var forms = this.content.getElementsByTagName("form"); return (forms.length > 0) ? forms[0] : null; }; PopupDiv.prototype.callHandler = function() { var tags = ["input", "textarea", "select"]; var params = new Object(); for (var ti = tags.length; --ti >= 0;) { var tag = tags[ti]; var els = this.content.getElementsByTagName(tag); for (var j = 0; j < els.length; ++j) { var el = els[j]; params[el.name] = el.value; } } this.handler(this, params); return false; }; PopupDiv.getAbsolutePos = function(el) { var r = { x: el.offsetLeft, y: el.offsetTop }; if (el.offsetParent) { var tmp = PopupDiv.getAbsolutePos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; PopupDiv.getWindowSize = function() { if (window.innerHeight) { return { y: window.innerHeight, x: window.innerWidth }; } if (this.doc.body.clientHeight) { return { y: this.doc.body.clientHeight, x: this.doc.body.clientWidth }; } return { y: this.doc.documentElement.clientHeight, x: this.doc.documentElement.clientWidth }; }; PopupDiv.prototype.hideShowCovered = function () { var self = this; function isContained(el) { while (el) { if (el == self.element) { return true; } el = el.parentNode; } return false; }; var tags = new Array("applet", "select"); var el = this.element; var p = PopupDiv.getAbsolutePos(el); var EX1 = p.x; var EX2 = el.offsetWidth + EX1; var EY1 = p.y; var EY2 = el.offsetHeight + EY1; if (el.style.display == "none") { EX1 = EX2 = EY1 = EY2 = 0; } for (var k = tags.length; k > 0; ) { var ar = this.doc.getElementsByTagName(tags[--k]); var cc = null; for (var i = ar.length; i > 0;) { cc = ar[--i]; if (isContained(cc)) { cc.style.visibility = "visible"; continue; } p = PopupDiv.getAbsolutePos(cc); var CX1 = p.x; var CX2 = cc.offsetWidth + CX1; var CY1 = p.y; var CY2 = cc.offsetHeight + CY1; if ((CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) { cc.style.visibility = "visible"; } else { cc.style.visibility = "hidden"; } } } }; PopupDiv.prototype._dragStart = function (ev) { if (this.dragging) { return false; } this.dragging = true; PopupDiv.currentPopup = this; var posX = ev.clientX; var posY = ev.clientY; if (is_ie) { posY += this.doc.body.scrollTop; posX += this.doc.body.scrollLeft; } else { posY += window.scrollY; posX += window.scrollX; } var st = this.element.style; this.xOffs = posX - parseInt(st.left); this.yOffs = posY - parseInt(st.top); HTMLArea._addEvent(this.doc, "mousemove", PopupDiv.dragIt); HTMLArea._addEvent(this.doc, "mouseover", HTMLArea._stopEvent); HTMLArea._addEvent(this.doc, "mouseup", PopupDiv.dragEnd); HTMLArea._stopEvent(ev); }; PopupDiv.dragIt = function (ev) { var popup = PopupDiv.currentPopup; if (!(popup && popup.dragging)) { return false; } is_ie && (ev = window.event); var posX = ev.clientX; var posY = ev.clientY; if (is_ie) { posY += this.doc.body.scrollTop; posX += this.doc.body.scrollLeft; } else { posY += window.scrollY; posX += window.scrollX; } popup.hideShowCovered(); var st = popup.element.style; st.left = (posX - popup.xOffs) + "px"; st.top = (posY - popup.yOffs) + "px"; HTMLArea._stopEvent(ev); }; PopupDiv.dragEnd = function () { var popup = PopupDiv.currentPopup; if (!popup) { return false; } popup.dragging = false; HTMLArea._removeEvent(popup.doc, "mouseup", PopupDiv.dragEnd); HTMLArea._removeEvent(popup.doc, "mouseover", HTMLArea._stopEvent); HTMLArea._removeEvent(popup.doc, "mousemove", PopupDiv.dragIt); popup.hideShowCovered(); }; PopupDiv.checkPopup = function (ev) { is_ie && (ev = window.event); var el = is_ie ? ev.srcElement : ev.target; var cp = PopupDiv.currentPopup; for (; (el != null) && (el != cp.element); el = el.parentNode); if (el == null) { cp.modal || ev.type == "mouseover" || cp.close(); HTMLArea._stopEvent(ev); } }; PopupDiv.prototype.addButtons = function() { var self = this; var div = this.doc.createElement("div"); this.content.appendChild(div); div.className = "buttons"; for (var i = 0; i < arguments.length; ++i) { var btn = arguments[i]; var button = this.doc.createElement("button"); div.appendChild(button); button.innerHTML = HTMLArea.I18N.buttons[btn]; switch (btn) { case "ok": button.onclick = function() { self.callHandler(); self.close(); }; break; case "cancel": button.onclick = function() { self.close(); }; break; } } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/dialog.js0000644000175000017500000000470510177203646025725 0ustar frankiefrankie// htmlArea v3.0 - Copyright (c) 2003-2005 dynarch.com // 2002-2003 interactivetools.com, inc. // This copyright notice MUST stay intact for use (see license.txt). // // Portions (c) dynarch.com, 2003-2004 // // A free WYSIWYG editor replacement for

    Where can I find out more info, download the latest version and talk to other HTMLArea users?

    You can find out more about HTMLArea and download the latest version on the HTMLArea homepage and you can talk to other HTMLArea users and post any comments or suggestions you have in the HTMLArea forum.

    Keyboard shortcuts

    The editor provides the following key combinations:

    • CTRL-A -- select all
    • CTRL-B -- bold
    • CTRL-I -- italic
    • CTRL-U -- underline
    • CTRL-S -- strikethrough
    • CTRL-L -- justify left
    • CTRL-E -- justify center
    • CTRL-R -- justify right
    • CTRL-J -- justify full
    • CTRL-1 .. CTRL-6 -- headings (<h1> .. <h6>)
    • CTRL-0 (zero) -- clean content pasted from Word

    Installation

    How do I add HTMLArea to my web page?

    It's easy. First you need to upload HTMLArea files to your website. Just follow these steps.

    1. Download the latest version from the htmlArea homepage.
    2. Unzip the files onto your local computer (making sure to maintain the directory structure contained in the zip).
    3. Create a new folder on your website called /htmlarea/ (make sure it's NOT inside the cgi-bin).
    4. Transfer all the HTMLArea files from your local computer into the /htmlarea/ folder on your website.
    5. Open the example page /htmlarea/examples/core.html with your browser to make sure everything works.

    Once htmlArea is on your website all you need to do is add some JavaScript to any pages that you want to add WYSIWYG editors to. Here's how to do that.

    1. Define some global variables. "_editor_url" has to be the absolute URL where HTMLArea resides within your website; as we discussed, this would be “/htmlarea/â€. "_editor_lang" must be the language code in which you want HTMLArea to appear. This defaults to "en" (English); for a list of supported languages, please look into the "lang" subdirectory in the distribution.
      <script type="text/javascript">
         _editor_url = "/htmlarea/";
         _editor_lang = "en";
      </script>
    2. Include the "htmlarea.js" script:
      <script type="text/javascript" src="/htmlarea/htmlarea.js"></script>
    3. If you want to change all your <textarea>-s into HTMLArea-s then you can use the simplest way to create HTMLArea:

      <script type="text/javascript" defer="1">
          HTMLArea.replaceAll();
      </script>

      Note: you can also add the HTMLArea.replaceAll() code to the onload event handler for the body element, if you find it more appropriate.

      A different approach, if you have more than one textarea and only want to change one of them, is to use HTMLArea.replace("id") -- pass the id of your textarea. Do not use the name attribute anymore, it's not a standard solution!

    This section applies to HTMLArea-3.0 release candidate 1 or later; prior to this version, one needed to include more files; however, now HTMLArea is able to include other files too (such as stylesheet, language definition file, etc.) so you only need to define the editor path and load "htmlarea.js". Nice, eh? ;-)

    I want to change the editor settings, how do I do that?

    While it's true that all you need is one line of JavaScript to create an htmlArea WYSIWYG editor, you can also specify more config settings in the code to control how the editor works and looks. Here's an example of some of the available settings:

    var config = new HTMLArea.Config(); // create a new configuration object
                                        // having all the default values
    config.width = '90%';
    config.height = '200px';
    
    // the following sets a style for the page body (black text on yellow page)
    // and makes all paragraphs be bold by default
    config.pageStyle =
      'body { background-color: yellow; color: black; font-family: verdana,sans-serif } ' +
      'p { font-width: bold; } ';
    
    // the following replaces the textarea with the given id with a new
    // HTMLArea object having the specified configuration
    HTMLArea.replace('id', config);

    Important: It's recommended that you add custom features and configuration to a separate file. This will ensure you that when we release a new official version of HTMLArea you'll have less trouble upgrading it.

    How do I customize the toolbar?

    Using the configuration object introduced above allows you to completely control what the toolbar contains. Following is an example of a one-line, customized toolbar, much simpler than the default one:

    var config = new HTMLArea.Config();
    config.toolbar = [
      ['fontname', 'space',
       'fontsize', 'space',
       'formatblock', 'space',
       'bold', 'italic', 'underline']
    ];
    HTMLArea.replace('id', config);

    The toolbar is an Array of Array objects. Each array in the toolbar defines a new line. The default toolbar looks like this:

    config.toolbar = [
    [ "fontname", "space",
      "fontsize", "space",
      "formatblock", "space",
      "bold", "italic", "underline", "separator",
      "strikethrough", "subscript", "superscript", "separator",
      "copy", "cut", "paste", "space", "undo", "redo" ],
    
    [ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator",
      "insertorderedlist", "insertunorderedlist", "outdent", "indent", "separator",
      "forecolor", "hilitecolor", "textindicator", "separator",
      "inserthorizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator",
      "popupeditor", "separator", "showhelp", "about" ]
    ];

    Except three strings, all others in the examples above need to be defined in the config.btnList object (detailed a bit later in this document). The three exceptions are: 'space', 'separator' and 'linebreak'. These three have the following meaning, and need not be present in btnList:

    • 'space' -- Inserts a space of 5 pixels (the width is configurable by external CSS) at the current position in the toolbar.
    • 'separator' -- Inserts a small vertical separator, for visually grouping related buttons.
    • 'linebreak' -- Starts a new line in the toolbar. Subsequent controls will be inserted on the new line.

    Important: It's recommended that you add custom features and configuration to a separate file. This will ensure you that when we release a new official version of HTMLArea you'll have less trouble upgrading it.

    How do I create custom buttons?

    By design, the toolbar is easily extensible. For adding a custom button one needs to follow two steps.

    1. Register the button in config.btnList.

    For each button in the toolbar, HTMLArea needs to know the following information:

    • a name for it (we call it the ID of the button);
    • the path to an image to be displayed in the toolbar;
    • a tooltip for it;
    • whether the button is enabled or not in text mode;
    • what to do when the button is clicked;

    You need to provide all this information for registering a new button too. The button ID can be any string identifier and it's used when defining the toolbar, as you saw above. We recommend starting it with "my-" so that it won't clash with the standard ID-s (those from the default toolbar).

    Register button example #1

    // get a default configuration
    var config = new HTMLArea.Config();
    // register the new button using Config.registerButton.
    // parameters:        button ID,   tooltip,          image,           textMode,
    config.registerButton("my-hilite", "Highlight text", "my-hilite.gif", false,
    // function that gets called when the button is clicked
      function(editor, id) {
        editor.surroundHTML('<span class="hilite">', '</span>');
      }
    );

    An alternate way of calling registerButton is exemplified above. Though the code might be a little bit larger, using this form makes your code more maintainable. It doesn't even needs comments as it's pretty clear.

    Register button example #2

    var config = new HTMLArea.Config();
    config.registerButton({
      id        : "my-hilite",
      tooltip   : "Highlight text",
      image     : "my-hilite.gif",
      textMode  : false,
      action    : function(editor, id) {
                    editor.surroundHTML('<span class="hilite">', '</span>');
                  }
    });

    You might notice that the "action" function receives two parameters: editor and id. In the examples above we only used the editor parameter. But it could be helpful for you to understand both:

    • editor is a reference to the HTMLArea object. Since our entire code now has an OOP-like design, you need to have a reference to the editor object in order to do things with it. In previous versions of HTMLArea, in order to identify the object an ID was used -- the ID of the HTML element. In this version ID-s are no longer necessary.
    • id is the button ID. Wondering why is this useful? Well, you could use the same handler function (presuming that it's not an anonymous function like in the examples above) for more buttons. You can see an example a bit later in this document.

    2. Inserting it into the toolbar

    At this step you need to specify where in the toolbar to insert the button, or just create the whole toolbar again as you saw in the previous section. You use the button ID, as shown in the examples of customizing the toolbar in the previous section.

    For the sake of completion, following there are another examples.

    Append your button to the default toolbar

    config.toolbar.push([ "my-hilite" ]);

    Customized toolbar

    config.toolbar = [
      ['fontname', 'space',
       'fontsize', 'space',
       'formatblock', 'space',
       'separator', 'my-hilite', 'separator', 'space', // here's your button
       'bold', 'italic', 'underline', 'space']
    ];

    Note: in the example above our new button is between two vertical separators. But this is by no means required. You can put it wherever you like. Once registered in the btnList (step 1) your custom button behaves just like a default button.

    Important: It's recommended that you add custom features and configuration to a separate file. This will ensure you that when we release a new official version of HTMLArea you'll have less trouble upgrading it.

    A complete example

    Please note that it is by no means necessary to include the following code into the htmlarea.js file. On the contrary, it might not work there. The configuration system is designed such that you can always customize the editor from outside files, thus keeping the htmlarea.js file intact. This will make it easy for you to upgrade your HTMLArea when we release a new official version. OK, I promise it's the last time I said this. ;)

    // All our custom buttons will call this function when clicked.
    // We use the buttonId parameter to determine what button
    // triggered the call.
    function clickHandler(editor, buttonId) {
      switch (buttonId) {
        case "my-toc":
          editor.insertHTML("<h1>Table Of Contents</h1>");
          break;
        case "my-date":
          editor.insertHTML((new Date()).toString());
          break;
        case "my-bold":
          editor.execCommand("bold");
          editor.execCommand("italic");
          break;
        case "my-hilite":
          editor.surroundHTML("<span class=\"hilite\">", "</span>");
          break;
      }
    };
    
    // Create a new configuration object
    var config = new HTMLArea.Config();
    
    // Register our custom buttons
    config.registerButton("my-toc",  "Insert TOC", "my-toc.gif", false, clickHandler);
    config.registerButton("my-date", "Insert date/time", "my-date.gif", false, clickHandler);
    config.registerButton("my-bold", "Toggle bold/italic", "my-bold.gif", false, clickHandler);
    config.registerButton("my-hilite", "Hilite selection", "my-hilite.gif", false, clickHandler);
    
    // Append the buttons to the default toolbar
    config.toolbar.push(["linebreak", "my-toc", "my-date", "my-bold", "my-hilite"]);
    
    // Replace an existing textarea with an HTMLArea object having the above config.
    HTMLArea.replace("textAreaID", config);

    © InteractiveTools.com 2002-2004.
    © dynarch.com 2003-2004
    HTMLArea v3.0 developed by Mihai Bazon.
    Documentation written by Mihai Bazon.
    Last modified: Wed Jan 28 12:18:23 EET 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popupwin.js0000644000175000017500000000756610177203646026357 0ustar frankiefrankie// (c) dynarch.com 2003-2005 // Distributed under the same terms as HTMLArea itself. function PopupWin(editor, title, handler, initFunction) { this.editor = editor; this.handler = handler; var dlg = window.open("", "__ha_dialog", "toolbar=no,menubar=no,personalbar=no,width=600,height=600,left=20,top=40" + "scrollbars=no,resizable=no"); this.window = dlg; var doc = dlg.document; this.doc = doc; var self = this; var base = document.baseURI || document.URL; if (base && base.match(/(.*)\/([^\/]+)/)) { base = RegExp.$1 + "/"; } if (typeof _editor_url != "undefined" && !/^\//.test(_editor_url) && !/http:\/\//.test(_editor_url)) { // _editor_url doesn't start with '/' which means it's relative // FIXME: there's a problem here, it could be http:// which // doesn't start with slash but it's not relative either. base += _editor_url; } else base = _editor_url; if (!/\/$/.test(base)) { // base does not end in slash, add it now base += '/'; } this.baseURL = base; doc.open(); var html = "" + title + "\n"; // html += "\n"; html += "\n"; html += ""; doc.write(html); doc.close(); // sometimes I Hate Mozilla... ;-( function init2() { var body = doc.body; if (!body) { setTimeout(init2, 25); return false; } dlg.title = title; doc.documentElement.style.padding = "0px"; doc.documentElement.style.margin = "0px"; var content = doc.createElement("div"); content.className = "content"; self.content = content; body.appendChild(content); self.element = body; initFunction(self); dlg.focus(); }; init2(); }; PopupWin.prototype.callHandler = function() { var tags = ["input", "textarea", "select"]; var params = new Object(); for (var ti = tags.length; --ti >= 0;) { var tag = tags[ti]; var els = this.content.getElementsByTagName(tag); for (var j = 0; j < els.length; ++j) { var el = els[j]; var val = el.value; if (el.tagName.toLowerCase() == "input") { if (el.type == "checkbox") { val = el.checked; } } params[el.name] = val; } } this.handler(this, params); return false; }; PopupWin.prototype.close = function() { this.window.close(); }; PopupWin.prototype.addButtons = function() { var self = this; var div = this.doc.createElement("div"); this.content.appendChild(div); div.className = "buttons"; for (var i = 0; i < arguments.length; ++i) { var btn = arguments[i]; var button = this.doc.createElement("button"); div.appendChild(button); button.innerHTML = HTMLArea.I18N.buttons[btn]; switch (btn) { case "ok": button.onclick = function() { self.callHandler(); self.close(); return false; }; break; case "cancel": button.onclick = function() { self.close(); return false; }; break; } } }; PopupWin.prototype.showAtElement = function() { var self = this; // Mozilla needs some time to realize what's goin' on.. setTimeout(function() { var w = self.content.offsetWidth + 4; var h = self.content.offsetHeight + 4; // size to content -- that's fuckin' buggy in all fuckin' browsers!!! // so that we set a larger size for the dialog window and then center // the element inside... phuck! // center... var el = self.content; var s = el.style; // s.width = el.offsetWidth + "px"; // s.height = el.offsetHeight + "px"; s.position = "absolute"; s.left = (w - el.offsetWidth) / 2 + "px"; s.top = (h - el.offsetHeight) / 2 + "px"; if (HTMLArea.is_gecko) { self.window.innerWidth = w; self.window.innerHeight = h; } else { self.window.resizeTo(w + 8, h + 35); } }, 25); }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popups/0000755000175000017500000000000011724401447025446 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popups/editor_help.html0000644000175000017500000000034410177203654030634 0ustar frankiefrankie Editor Help

    Editor Help

    Todo... openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popups/insert_image.html0000644000175000017500000001264710177203654031015 0ustar frankiefrankie Insert Image
    Insert Image
    Image URL:
    Alternate text:

    Layout
    Alignment:

    Border thickness:
    Spacing
    Horizontal:

    Vertical:

    Image Preview:

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popups/popup.js0000644000175000017500000000640510177203654027155 0ustar frankiefrankie// htmlArea v3.0 - Copyright (c) 2002, 2003 interactivetools.com, inc. // This copyright notice MUST stay intact for use (see license.txt). // // Portions (c) dynarch.com, 2003 // // A free WYSIWYG editor replacement for
    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/popups/fullscreen.html0000644000175000017500000001234310177203654030502 0ustar frankiefrankie Fullscreen HTMLArea
    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/htmlarea.js0000644000175000017500000024427310177203646026271 0ustar frankiefrankie// htmlArea v3.0 - Copyright (c) 2003-2005 dynarch.com // 2002-2003 interactivetools.com, inc. // This copyright notice MUST stay intact for use (see license.txt). // // A free WYSIWYG editor replacement for
    Mihai Bazon
    Last modified: Wed Jan 28 11:10:16 EET 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/custom.css0000644000175000017500000000216510177203646027770 0ustar frankiefrankiebody { background-color: #234; color: #dd8; font-family: tahoma; font-size: 12px; } a:link, a:visited { color: #8cf; } a:hover { color: #ff8; } h1 { background-color: #456; color: #ff8; padding: 2px 5px; border: 1px solid; border-color: #678 #012 #012 #678; } /* syntax highlighting (used by the first combo defined for the CSS plugin) */ pre { margin: 0px 1em; padding: 5px 1em; background-color: #000; border: 1px dotted #02d; border-left: 2px solid #04f; } .code { color: #f5deb3; } .string { color: #00ffff; } .comment { color: #8fbc8f; } .variable-name { color: #fa8072; } .type { color: #90ee90; font-weight: bold; } .reference { color: #ee82ee; } .preprocessor { color: #faf; } .keyword { color: #ffffff; font-weight: bold; } .function-name { color: #ace; } .html-tag { font-weight: bold; } .html-helper-italic { font-style: italic; } .warning { color: #ffa500; font-weight: bold; } .html-helper-bold { font-weight: bold; } /* info combo */ .quote { font-style: italic; color: #ee9; } .highlight { background-color: yellow; color: #000; } .deprecated { text-decoration: line-through; color: #aaa; } openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/remove-font-tags.html0000644000175000017500000000244710177203646032032 0ustar frankiefrankie The "htmlRemoveTags" feature

    Remove FONT tags


    Mihai Bazon
    Last modified: Wed Apr 28 15:09:09 EEST 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/full-page.html0000644000175000017500000000641210177203646030505 0ustar frankiefrankie Test of FullPage plugin

    Test of FullPage plugin


    Mihai Bazon
    Last modified: Wed Aug 11 13:59:07 CEST 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/empty.html0000644000175000017500000000124710177203646027770 0ustar frankiefrankie HTMLArea 3.0 core test openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/fully-loaded.html0000644000175000017500000002506010177203646031212 0ustar frankiefrankie Example of HTMLArea 3.0

    HTMLArea 3.0

    A replacement for TEXTAREA elements. © InteractiveTools.com, 2003-2004.

    submit

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/test.cgi0000644000175000017500000000036610177203646027410 0ustar frankiefrankie#! /usr/bin/perl -w # # # use CGI; print "Content-type: text/html\n\n"; $c = new CGI; $ta = $c->param('ta'); print < $ta EOF openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/index.html0000644000175000017500000000163710177203646027744 0ustar frankiefrankie HTMLArea examples index

    HTMLArea: auto-generated examples index


    mihai_bazon@yahoo.com
    Last modified: Sun Feb 1 13:30:39 EET 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/context-menu.html0000644000175000017500000001140610177203646031256 0ustar frankiefrankie Test of ContextMenu plugin

    Test of ContextMenu plugin


    Mihai Bazon
    Last modified: Wed Jan 28 11:10:29 EET 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/2-areas.cgi0000644000175000017500000000065610177203646027665 0ustar frankiefrankie#! /usr/bin/perl -w use strict; use CGI; my $cgi = new CGI; my $text1 = $cgi->param('text1'); my $text2 = $cgi->param('text2'); print "Content-type: text/html\n\n"; print "

    You submitted:

    "; print ""; print ""; print ""; print "
    text1text2
    $text1$text2
    "; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/dynamic_css.html0000644000175000017500000000246510177203646031131 0ustar frankiefrankie Test of CSS plugin

    Test of DynamicCSS plugin

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/dynamic.css0000644000175000017500000000146710177203646030106 0ustar frankiefrankiep { FONT-FAMILY: Arial, Helvetica; FONT-SIZE: 9pt; FONT-WEIGHT: normal; COLOR: #000000; } p.p1 { FONT-FAMILY: Arial, Helvetica; FONT-SIZE: 11pt; FONT-WEIGHT: normal; COLOR: #000000; } p.p2 { FONT-FAMILY: Arial, Helvetica; FONT-SIZE: 13pt; FONT-WEIGHT: normal; COLOR: #000000; } div { FONT-FAMILY: Arial, Helvetica; FONT-SIZE: 9pt; FONT-WEIGHT: bold; COLOR: #000000; } div.div1 { FONT-FAMILY: Arial, Helvetica; FONT-SIZE: 11pt; FONT-WEIGHT: bold; COLOR: #000000; } div.div2 { FONT-FAMILY: Arial, Helvetica; FONT-SIZE: 13pt; FONT-WEIGHT: bold; COLOR: #000000; } .quote { font-style: italic; color: #ee9; } .highlight { background-color: yellow; color: #000; } .deprecated { text-decoration: line-through; color: #aaa; } openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/2-areas.html0000644000175000017500000001476510177203646030075 0ustar frankiefrankie Example with 2 HTMLAreas in the same form

    Example with 2 HTMLAreas in the same form





    Mihai Bazon
    Last modified: Wed Jan 28 11:10:40 EET 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/table-operations.html0000644000175000017500000001004010177203646032071 0ustar frankiefrankie Example of HTMLArea 3.0

    HTMLArea 3.0

    A replacement for TEXTAREA elements. © InteractiveTools.com, 2003-2004.

    Page that demonstrates the additional features of the TableOperations plugin (sponsored by Zapatec Inc.).

    submit

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/character_map.html0000644000175000017500000000146510177203646031425 0ustar frankiefrankie Test of CharacterMap plugin

    Test of DynamicCSS plugin

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/core.html0000644000175000017500000001436510177203646027567 0ustar frankiefrankie Example of HTMLArea 3.0

    HTMLArea 3.0

    A replacement for TEXTAREA elements. © InteractiveTools.com, 2003-2004.

    submit

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/list-type.html0000644000175000017500000000365710177203646030573 0ustar frankiefrankie Example of HTMLArea 3.0 -- ListType plugin

    HTMLArea :: the ListType plugin

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/examples/spell-checker.html0000644000175000017500000000753110177203646031355 0ustar frankiefrankie Example of HTMLArea 3.0

    HTMLArea 3.0

    A replacement for TEXTAREA elements. © InteractiveTools.com, 2003-2004.

    Plugins: SpellChecker (sponsored by American Bible Society).

    submit

    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/license.txt0000644000175000017500000000317210177203646026310 0ustar frankiefrankiehtmlArea License (based on BSD license) Copyright (c) 2002-2004, interactivetools.com, inc. Copyright (c) 2003-2005 dynarch.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the name of interactivetools.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/release-notes.html0000644000175000017500000001415410177203646027563 0ustar frankiefrankie HTMLArea-3.0-RC3 release notes

    HTMLArea-3.0-RC3 release notes

    This release was compiled on Jan , 2005 [23:43] GMT.

    Changes since 3.0-RC2b:

    • Restored broken images and re-committed ALL images back to CVS in binary mode.
    • Added error with instructions for when HTMLArea.init() isn't called first.
    • Fixed examples to call HTMLArea.init() first:
      • 2-areas.html
      • character_map.html
      • css.html
      • dynamic_css.html
      • list-type.html
      • remove-font-tags.html

    Changes since 3.0-Beta:

    • New plugins
      • ContextMenu plugin (provides a nice context menu with common operations, including table ops, link ops, etc.)
      • CSS plugin (provides an easy way to insert/change CSS classes)
      • FullPage plugin (allows HTMLArea to edit a whole HTML file, not only the content within <body>.)
    • Changes in the SpellChecker plugin
      • Many bugfixes: now it works ;-) Fully Unicode-safe.
      • Speed and bandwidth optimization: reports the list of suggestions only once for each mispelled word; this helps in cases where you have, for instance, the word “HTMLArea†in 10 places all over the document; the list of suggestions for it--which is kind of huge--will only be included once.
      • User interface improvements: the highlighted word will remain in view; in cases where it's normally outside, the window will be scrolled to it.
      • Added a "Revert" button for those that change their minds ;-)
      • Added a "Info" button which reports information about the document, retrieved by the server-side spell checker: total number of words, total number of mispelled words, number of suggestions made, spell check time, etc. More can be easily added. FIXME: this part is not yet internationalized.
      • The server-side spell checker now uses XML::DOM instead of HTML::Parser, which means that it will be unable to parse “tag-soup†HTML. It needs valid code. Usually HTMLArea generates valid code, but on rare occasions it might fail and the spell checker will report a gross error message. This gonna have to be fixed, but instead of making the spell checker accept invalid HTML I prefer to make HTMLArea generate valid code, so changes are to be done in other places ;-)
    • Changes in the core editor
      • Easier to setup: you only need to load htmlarea.js; other scripts will be loaded automatically. Documentation and examples updated.
      • Better plugin support (they register information about themselves with the editor; can register event handlers for the editor, etc.)
      • New about box; check it out, it's cool ;-)
      • Word cleaner (can be enabled to automatically kill Word crap on paste (see Config.killWordOnPaste); otherwise accessible by pressing CTRL-0 in the editor; a toolbar button will come up soon)
      • Image preview in "insert image" dialog. Also allows modification of current image, if selected.
      • New "insert link" dialog, allows target and title specification, allows editing links.
      • Implemented support for text direction (left-to-right or right-to-left).
      • Lots of bug fixes! ... and more, I guess ;-) an automatically generated change log is now available.

    I don't have the power to go through the bug system at SourceForge now. Some of the bugs reported there may be fixed; I'll update their status, some other time. If you reported bugs there and now find them to be fixed, please let me know.

    3.0-Beta

    Changes since 3.0-Alpha:

    • Performance improvements.
    • Many bugs fixed.
    • Plugin infrastructure.
    • TableOperations plugin.
    • SpellChecker plugin.
    • Status bar.
    • API for registering custom buttons and drop-down boxes in the toolbar.
    • Toolbar can contain text labels.
    • Cut, copy, paste, undo, redo buttons.

    Mihai Bazon
    Last modified: Wed Mar 31 19:18:26 EEST 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/0000755000175000017500000000000011724401447025601 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CSS/0000755000175000017500000000000011724401447026231 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CSS/lang/0000755000175000017500000000000011575225612027154 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CSS/lang/en.js0000644000175000017500000000006310177203650030106 0ustar frankiefrankie// none yet; this file is a stub. CSS.I18N = {}; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CSS/css.js0000644000175000017500000000673710177203650027371 0ustar frankiefrankie// Simple CSS (className) plugin for the editor // Sponsored by http://www.miro.com.au // Implementation by Mihai Bazon, http://dynarch.com/mishoo. // // (c) dynarch.com 2003-2005. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // $Id: css.js,v 1.1 2005/01/30 16:13:28 jeffd Exp $ function CSS(editor, params) { this.editor = editor; var cfg = editor.config; var toolbar = cfg.toolbar; var self = this; var i18n = CSS.I18N; var plugin_config = params[0]; var combos = plugin_config.combos; var first = true; for (var i = combos.length; --i >= 0;) { var combo = combos[i]; var id = "CSS-class" + i; var css_class = { id : id, options : combo.options, action : function(editor) { self.onSelect(editor, this, combo.context, combo.updatecontextclass); }, refresh : function(editor) { self.updateValue(editor, this); }, context : combo.context }; cfg.registerDropdown(css_class); // prepend to the toolbar toolbar[1].splice(0, 0, first ? "separator" : "space"); toolbar[1].splice(0, 0, id); if (combo.label) toolbar[1].splice(0, 0, "T[" + combo.label + "]"); first = false; } }; CSS._pluginInfo = { name : "CSS", version : "1.0", developer : "Mihai Bazon", developer_url : "http://dynarch.com/mishoo/", c_owner : "Mihai Bazon", sponsor : "Miro International", sponsor_url : "http://www.miro.com.au", license : "htmlArea" }; CSS.prototype.onSelect = function(editor, obj, context, updatecontextclass) { var tbobj = editor._toolbarObjects[obj.id]; var index = tbobj.element.selectedIndex; var className = tbobj.element.value; // retrieve parent element of the selection var parent = editor.getParentElement(); var surround = true; var is_span = (parent && parent.tagName.toLowerCase() == "span"); var update_parent = (context && updatecontextclass && parent && parent.tagName.toLowerCase() == context); if (update_parent) { parent.className = className; editor.updateToolbar(); return; } if (is_span && index == 0 && !/\S/.test(parent.style.cssText)) { while (parent.firstChild) { parent.parentNode.insertBefore(parent.firstChild, parent); } parent.parentNode.removeChild(parent); editor.updateToolbar(); return; } if (is_span) { // maybe we could simply change the class of the parent node? if (parent.childNodes.length == 1) { parent.className = className; surround = false; // in this case we should handle the toolbar updation // ourselves. editor.updateToolbar(); } } // Other possibilities could be checked but require a lot of code. We // can't afford to do that now. if (surround) { // shit happens ;-) most of the time. this method works, but // it's dangerous when selection spans multiple block-level // elements. editor.surroundHTML("", ""); } }; CSS.prototype.updateValue = function(editor, obj) { var select = editor._toolbarObjects[obj.id].element; var parent = editor.getParentElement(); if (typeof parent.className != "undefined" && /\S/.test(parent.className)) { var options = select.options; var value = parent.className; for (var i = options.length; --i >= 0;) { var option = options[i]; if (value == option.value) { select.selectedIndex = i; return; } } } select.selectedIndex = 0; }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/0000755000175000017500000000000011724401447030145 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/img/0000755000175000017500000000000011724401447030721 5ustar frankiefrankie././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/img/spell-check.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/img/spell-check.gi0000644000175000017500000000015310021673054033425 0ustar frankiefrankieGIF89a¡ÿÿÿƒÿÿÿ!ù ,<œ©ËŒ#z ¡à.MAµ›ÈYV×jlÛ 2"ä‡9ú"Hü€Ã¡"‡È¥#éF§TG;././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/img/he-spell-check.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/img/he-spell-check0000644000175000017500000000160310177203653033430 0ustar frankiefrankieGIF89a÷ÿÿÿƒÿÿÿ!ù,`H° Áƒ ÃÐáÃ… Ìh‘â@:¤ÈQ£ÀŠ%NiòäÄŒ,)¶t9`eC‚r~ // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Vil du følge dette link?", "Cancel" : "Anuler", "Dictionary" : "Ordbog", "Finished list of mispelled words" : "Listen med stavefejl er gennemgÃ¥et", "I will open it in a new page." : "Jeg vil Ã¥bne det i en ny side.", "Ignore all" : "Ignorer alle", "Ignore" : "Ignorer", "NO_ERRORS" : "Der blev ikke fundet nogle stavefejl med den valgte ordbog.", "NO_ERRORS_CLOSING" : "Stavekontrollen er gennemført, der blev ikke fundet nogle stavefejl. Lukker...", "OK" : "OK", "Original word" : "Oprindeligt ord", "Please wait. Calling spell checker." : "Vent venligst. Henter stavekontrol.", "Please wait: changing dictionary to" : "Vent venligst: skifter ordbog til", "QUIT_CONFIRMATION" : "Alle dine ændringer vil gÃ¥ tabt, vil du fortsætte?", "Re-check" : "Tjek igen", "Replace all" : "Erstat alle", "Replace with" : "Erstat med", "Replace" : "Erstat", "SC-spell-check" : "Stavekontrol", "Suggestions" : "Forslag", "pliz weit ;-)" : "Vent venligst" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/de.js0000644000175000017500000000317110177203653032016 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Broxx, SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Wollen Sie diesen Link oeffnen", "Cancel" : "Abbrechen", "Dictionary" : "Woerterbuch", "Finished list of mispelled words" : "Liste der nicht bekannten Woerter", "I will open it in a new page." : "Wird auf neuer Seite geoeffnet", "Ignore all" : "Alle ignorieren", "Ignore" : "Ignorieren", "NO_ERRORS" : "Keine falschen Woerter mit gewaehlten Woerterbuch gefunden", "NO_ERRORS_CLOSING" : "Rechtsschreibpruefung wurde ohne Fehler fertiggestellt. Wird nun geschlossen...", "OK" : "OK", "Original word" : "Original Wort", "Please wait. Calling spell checker." : "Bitte warten. Woerterbuch wird durchsucht.", "Please wait: changing dictionary to" : "Bitte warten: Woerterbuch wechseln zu", "QUIT_CONFIRMATION" : "Aenderungen werden nicht uebernommen. Bitte bestaettigen.", "Re-check" : "Neuueberpruefung", "Replace all" : "Alle ersetzen", "Replace with" : "Ersetzen mit", "Replace" : "Ersetzen", "SC-spell-check" : "Ueberpruefung", "Suggestions" : "Vorschlag", "pliz weit ;-)" : "bittsche wartn ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/cz.js0000644000175000017500000000404210177203653032040 0ustar frankiefrankie// I18N constants // LANG: "cz", ENCODING: UTF-8 | ISO-8859-2 // Author: Jiri Löw, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Prosím potvrÄte otevÅ™ení tohoto odkazu", "Cancel" : "ZruÅ¡it", "Dictionary" : "Slovník", "Finished list of mispelled words" : "DokonÄen seznam chybných slov", "I will open it in a new page." : "Bude otevÅ™en jej v nové stránce.", "Ignore all" : "Ignorovat vÅ¡e", "Ignore" : "Ignorovat", "NO_ERRORS" : "Podle zvoleného slovníku nebyla nalezena žádná chybná slova.", "NO_ERRORS_CLOSING" : "Kontrola správnosti slov dokonÄena, nebyla nalezena žádná chybná slova. UkonÄování ...", "OK" : "OK", "Original word" : "Původní slovo", "Please wait. Calling spell checker." : "Prosím Äekejte. Komunikuace s kontrolou správnosti slov.", "Please wait: changing dictionary to" : "Prosím Äekejte: zmÄ›na adresáře na", "QUIT_CONFIRMATION" : "ZmÄ›ny budou zruÅ¡eny a kontrola správnosti slov ukonÄena. Prosím potvrÄte.", "Re-check" : "PÅ™ekontrolovat", "Replace all" : "ZamÄ›nit vÅ¡echno", "Replace with" : "ZamÄ›nit za", "Replace" : "ZamÄ›nit", "SC-spell-check" : "Kontrola správnosti slov", "Suggestions" : "DoporuÄení", "pliz weit ;-)" : "strpení prosím ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/en.js0000644000175000017500000000367310177203653032037 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Please confirm that you want to open this link", "Cancel" : "Cancel", "Dictionary" : "Dictionary", "Finished list of mispelled words" : "Finished list of mispelled words", "I will open it in a new page." : "I will open it in a new page.", "Ignore all" : "Ignore all", "Ignore" : "Ignore", "NO_ERRORS" : "No mispelled words found with the selected dictionary.", "NO_ERRORS_CLOSING" : "Spell check complete, didn't find any mispelled words. Closing now...", "OK" : "OK", "Original word" : "Original word", "Please wait. Calling spell checker." : "Please wait. Calling spell checker.", "Please wait: changing dictionary to" : "Please wait: changing dictionary to", "QUIT_CONFIRMATION" : "This will drop changes and quit spell checker. Please confirm.", "Re-check" : "Re-check", "Replace all" : "Replace all", "Replace with" : "Replace with", "Replace" : "Replace", "Revert" : "Revert", "SC-spell-check" : "Spell-check", "Suggestions" : "Suggestions", "pliz weit ;-)" : "pliz weit ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/he.js0000644000175000017500000000436210177203653032025 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "×× × ×שר שברצונך לפתוח קישור ×–×”", "Cancel" : "ביטול", "Dictionary" : "מילון", "Finished list of mispelled words" : "הסתיימה רשימת ×”×ž×™×œ×™× ×”×ž×ויתות ב×ופן שגוי", "I will open it in a new page." : "×× ×™ ×פתח ×ת ×–×” בחלון חדש.", "Ignore all" : "×”×ª×¢×œ× ×ž×”×›×œ", "Ignore" : "התעל×", "NO_ERRORS" : "×œ× × ×ž×¦×ו ×ž×™×œ×™× ×ž×ויתות ב×ופן שגוי ×¢× ×”×ž×™×œ×•×Ÿ הנבחר.", "NO_ERRORS_CLOSING" : "בדיקת ×”×יות נסתיימה, ×œ× × ×ž×¦×ו ×ž×™×œ×™× ×ž×ויתות ב×ופן שגוי. נסגר כעת...", "OK" : "×ישור", "Original word" : "המילה המקורית", "Please wait. Calling spell checker." : "×× × ×”×ž×ª×Ÿ. ×§×•×¨× ×œ×‘×•×“×§ ×יות.", "Please wait: changing dictionary to" : "×× × ×”×ž×ª×Ÿ: מחליף מילון ל-", "QUIT_CONFIRMATION" : "×–×” יבטל ×ת ×”×©×™× ×•×™×™× ×•×™×¦× ×ž×‘×•×“×§ ×”×יות. ×× × ×שר.", "Re-check" : "בדוק מחדש", "Replace all" : "החלף הכל", "Replace with" : "החלף ב-", "Replace" : "החלף", "Revert" : "החזר שינויי×", "SC-spell-check" : "בדיקת ×יות", "Suggestions" : "הצעות", "pliz weit ;-)" : "×¢× × ×”×ž×˜×Ÿ ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/hu.js0000644000175000017500000000362610177203653032047 0ustar frankiefrankie// I18N constants // LANG: "hu", ENCODING: UTF-8 // Author: Miklós Somogyi, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "MegerÅ‘sítés", "Cancel" : "Mégsem", "Dictionary" : "Szótár", "Finished list of mispelled words" : "A tévesztett szavak listájának vége", "I will open it in a new page." : "Megnyitás új lapon", "Ignore all" : "Minden elvetése", "Ignore" : "Elvetés", "NO_ERRORS" : "A választott szótár szerint nincs tévesztett szó.", "NO_ERRORS_CLOSING" : "A helyesírásellenÅ‘rzés kész, tévesztett szó nem fordult elÅ‘. Bezárás...", "OK" : "Rendben", "Original word" : "Eredeti szó", "Please wait. Calling spell checker." : "Kis türelmet, a helyesírásellenÅ‘rzÅ‘ hívása folyamatban.", "Please wait: changing dictionary to" : "Kis türelmet, szótár cseréje", "QUIT_CONFIRMATION" : "Kilépés a változások eldobásával. Jóváhagyja?", "Re-check" : "ÚjraellenÅ‘rzés", "Replace all" : "Mind cseréje", "Replace with" : "Csere a következÅ‘re:", "Replace" : "Csere", "SC-spell-check" : "HelyesírásellenÅ‘rzés", "Suggestions" : "Tippek", "pliz weit ;-)" : "Kis türelmet ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/it.js0000644000175000017500000000327110177203653032043 0ustar frankiefrankie// I18N constants // LANG: "it", ENCODING: UTF-8 | ISO-8859-1 // Author: Fabio Rotondo, SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Devi confermare l'apertura di questo link", "Cancel" : "Annulla", "Dictionary" : "Dizionario", "Finished list of mispelled words" : "La lista delle parole scritte male è terminata", "I will open it in a new page." : "Lo aprirò in una nuova pagina.", "Ignore all" : "Ignora sempre", "Ignore" : "Ignora", "NO_ERRORS" : "Non sono state trovate parole scritte male con il dizionario selezionato.", "NO_ERRORS_CLOSING" : "Controllo completato, non sono state trovate parole scritte male. Sto chiudendo...", "OK" : "OK", "Original word" : "Parola originale", "Please wait. Calling spell checker." : "Attendere. Sto invocando lo Spell Checker.", "Please wait: changing dictionary to" : "Attendere. Cambio il dizionario in", "QUIT_CONFIRMATION" : "Questo annullerà le modifiche e chiuderà lo Spell Checker. Conferma.", "Re-check" : "Ricontrolla", "Replace all" : "Sostituisci sempre", "Replace with" : "Stostituisci con", "Replace" : "Sostituisci", "SC-spell-check" : "Spell-check", "Suggestions" : "Suggerimenti", "pliz weit ;-)" : "Attendere Prego ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/nl.js0000644000175000017500000000404210177203653032035 0ustar frankiefrankie// I18N constants // LANG: "nl", ENCODING: UTF-8 | ISO-8859-1 // Author: A.H van den Broek http://www.kontaktfm.nl // Email : tonbroek@kontaktfm.nl // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Weet u zeker dat u deze link wilt openen?", "Cancel" : "Annuleer", "Dictionary" : "Woordenboek", "Finished list of mispelled words" : "klaar met de lijst van fouten woorden", "I will open it in a new page." : "Ik zal het in een nieuwe pagina openen.", "Ignore all" : "alles overslaan", "Ignore" : "Overslaan", "NO_ERRORS" : "Geen fouten gevonden met dit woordenboek.", "NO_ERRORS_CLOSING" : "Spell checking is klaar, geen fouten gevonden. spell checking word gesloten...", "OK" : "OK", "Original word" : "Originele woord", "Please wait. Calling spell checker." : "Even wachten. spell checker wordt geladen.", "Please wait: changing dictionary to" : "even wachten: woordenboek wordt veranderd naar", "QUIT_CONFIRMATION" : "Dit zal alle veranderingen annuleren en de spell checker sluiten. Weet u het zeker?", "Re-check" : "Opnieuw", "Replace all" : "Alles vervangen", "Replace with" : "Vervangen met", "Replace" : "Vervangen", "Revert" : "Omkeren", "SC-spell-check" : "Spell-check", "Suggestions" : "Suggestie", "pliz weit ;-)" : "Even wachten ;-)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/lang/ro.js0000644000175000017500000000374310177203653032053 0ustar frankiefrankie// I18N constants // LANG: "ro", ENCODING: UTF-8 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) SpellChecker.I18N = { "CONFIRM_LINK_CLICK" : "Vă rog confirmaÅ£i că vreÅ£i să deschideÅ£i acest link", "Cancel" : "Anulează", "Dictionary" : "DicÅ£ionar", "Finished list of mispelled words" : "Am terminat lista de cuvinte greÅŸite", "I will open it in a new page." : "O voi deschide într-o altă fereastră.", "Ignore all" : "Ignoră toate", "Ignore" : "Ignoră", "NO_ERRORS" : "Nu am găsit nici un cuvânt greÅŸit cu acest dicÅ£ionar.", "NO_ERRORS_CLOSING" : "Am terminat, nu am detectat nici o greÅŸeală. Acum închid fereastra...", "OK" : "OK", "Original word" : "Cuvântul original", "Please wait. Calling spell checker." : "Vă rog aÅŸteptaÅ£i. Apelez spell-checker-ul.", "Please wait: changing dictionary to" : "Vă rog aÅŸteptaÅ£i. Schimb dicÅ£ionarul cu", "QUIT_CONFIRMATION" : "DoriÅ£i să renunÅ£aÅ£i la modificări ÅŸi să închid spell-checker-ul?", "Re-check" : "Scanează", "Replace all" : "ÃŽnlocuieÅŸte toate", "Replace with" : "ÃŽnlocuieÅŸte cu", "Replace" : "ÃŽnlocuieÅŸte", "SC-spell-check" : "Detectează greÅŸeli", "Suggestions" : "Sugestii", "pliz weit ;-)" : "va rog ashteptatzi ;-)" }; ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-ui.htmlopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-ui.htm0000644000175000017500000001101010177203653033455 0ustar frankiefrankie Spell Checker
    Dictionary
    Please wait. Calling spell checker.
    Original word
    pliz weit ;-)
    Replace with


    Suggestions
    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-checker.js0000644000175000017500000000435210177203653033230 0ustar frankiefrankie// Spell Checker Plugin for HTMLArea-3.0 // Sponsored by www.americanbible.org // Implementation by Mihai Bazon, http://dynarch.com/mishoo/ // // (c) dynarch.com 2003-2005. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // $Id: spell-checker.js,v 1.2 2005/01/30 16:13:31 jeffd Exp $ function SpellChecker(editor) { this.editor = editor; var cfg = editor.config; var tt = SpellChecker.I18N; var bl = SpellChecker.btnList; var self = this; // register the toolbar buttons provided by this plugin var toolbar = []; for (var i = 0; i < bl.length; ++i) { var btn = bl[i]; if (!btn) { toolbar.push("separator"); } else { var id = "SC-" + btn[0]; cfg.registerButton(id, tt[id], editor.imgURL(btn[0] + ".gif", "SpellChecker"), false, function(editor, id) { // dispatch button press event self.buttonPress(editor, id); }, btn[1]); toolbar.push(id); } } for (var i = 0; i < toolbar.length; ++i) { cfg.toolbar[0].push(toolbar[i]); } }; SpellChecker._pluginInfo = { name : "SpellChecker", version : "1.0", developer : "Mihai Bazon", developer_url : "http://dynarch.com/mishoo/", c_owner : "Mihai Bazon", sponsor : "American Bible Society", sponsor_url : "http://www.americanbible.org", license : "htmlArea" }; SpellChecker.btnList = [ null, // separator ["spell-check"] ]; SpellChecker.prototype.buttonPress = function(editor, id) { switch (id) { case "SC-spell-check": SpellChecker.editor = editor; SpellChecker.init = true; var uiurl = _editor_url + "plugins/SpellChecker/spell-check-ui.html"; var win; if (HTMLArea.is_ie) { win = window.open(uiurl, "SC_spell_checker", "toolbar=no,location=no,directories=no,status=no,menubar=no," + "scrollbars=no,resizable=yes,width=600,height=450"); } else { win = window.open(uiurl, "SC_spell_checker", "toolbar=no,menubar=no,personalbar=no,width=600,height=450," + "scrollbars=no,resizable=yes"); } win.focus(); break; } }; // this needs to be global, it's accessed from spell-check-ui.html SpellChecker.editor = null; ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-style.cssopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-style.0000644000175000017500000000071310177203653033477 0ustar frankiefrankie.HA-spellcheck-error { border-bottom: 1px dashed #f00; cursor: default; } .HA-spellcheck-same { background-color: #cef; color: #000; } .HA-spellcheck-hover { background-color: #433; color: white; } .HA-spellcheck-fixed { border-bottom: 1px dashed #0b8; } .HA-spellcheck-current { background-color: #9be; color: #000; } .HA-spellcheck-suggestions { display: none; } #HA-spellcheck-dictionaries { display: none; } a:link, a:visited { color: #55e; } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-logic.cgiopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-logic.0000755000175000017500000001436310177203653033445 0ustar frankiefrankie#! /usr/bin/perl -w # Spell Checker Plugin for HTMLArea-3.0 # Sponsored by www.americanbible.org # Implementation by Mihai Bazon, http://dynarch.com/mishoo/ # # (c) dynarch.com 2003. # Distributed under the same terms as HTMLArea itself. # This notice MUST stay intact for use (see license.txt). # # $Id: spell-check-logic.cgi,v 1.2 2005/01/30 16:13:31 jeffd Exp $ use strict; use utf8; use Encode; use Text::Aspell; use XML::DOM; use CGI; my $TIMER_start = undef; eval { use Time::HiRes qw( gettimeofday tv_interval ); $TIMER_start = [gettimeofday()]; }; # use POSIX qw( locale_h ); binmode STDIN, ':utf8'; binmode STDOUT, ':utf8'; my $debug = 0; my $speller = new Text::Aspell; my $cgi = new CGI; my $total_words = 0; my $total_mispelled = 0; my $total_suggestions = 0; my $total_words_suggested = 0; # FIXME: report a nice error... die "Can't create speller!" unless $speller; my $dict = $cgi->param('dictionary') || $cgi->cookie('dictionary') || 'en'; # add configurable option for this $speller->set_option('lang', $dict); $speller->set_option('encoding', 'UTF-8'); #setlocale(LC_CTYPE, $dict); # ultra, fast, normal, bad-spellers # bad-spellers seems to cause segmentation fault $speller->set_option('sug-mode', 'normal'); my %suggested_words = (); keys %suggested_words = 128; my $file_content = decode('UTF-8', $cgi->param('content')); $file_content = parse_with_dom($file_content); my $ck_dictionary = $cgi->cookie(-name => 'dictionary', -value => $dict, -expires => '+30d'); print $cgi->header(-type => 'text/html; charset: utf-8', -cookie => $ck_dictionary); my $js_suggested_words = make_js_hash(\%suggested_words); my $js_spellcheck_info = make_js_hash_from_array ([ [ 'Total words' , $total_words ], [ 'Mispelled words' , $total_mispelled . ' in dictionary \"'.$dict.'\"' ], [ 'Total suggestions' , $total_suggestions ], [ 'Total words suggested' , $total_words_suggested ], [ 'Spell-checked in' , defined $TIMER_start ? (tv_interval($TIMER_start) . ' seconds') : 'n/a' ] ]); print qq^ ^; print $file_content; if ($cgi->param('init') eq '1') { my @dicts = $speller->dictionary_info(); my $dictionaries = ''; foreach my $i (@dicts) { next if $i->{jargon}; my $name = $i->{name}; if ($name eq $dict) { $name = '@'.$name; } $dictionaries .= ',' . $name; } $dictionaries =~ s/^,//; print qq^
    $dictionaries
    ^; } print ''; # Perl is beautiful. sub spellcheck { my $node = shift; my $doc = $node->getOwnerDocument; my $check = sub { # called for each word in the text # input is in UTF-8 my $word = shift; my $already_suggested = defined $suggested_words{$word}; ++$total_words; if (!$already_suggested && $speller->check($word)) { return undef; } else { # we should have suggestions; give them back to browser in UTF-8 ++$total_mispelled; if (!$already_suggested) { # compute suggestions for this word my @suggestions = $speller->suggest($word); my $suggestions = decode($speller->get_option('encoding'), join(',', @suggestions)); $suggested_words{$word} = $suggestions; ++$total_suggestions; $total_words_suggested += scalar @suggestions; } # HA-spellcheck-error my $err = $doc->createElement('span'); $err->setAttribute('class', 'HA-spellcheck-error'); my $tmp = $doc->createTextNode; $tmp->setNodeValue($word); $err->appendChild($tmp); return $err; } }; while ($node->getNodeValue =~ /([\p{IsWord}']+)/) { my $word = $1; my $before = $`; my $after = $'; my $df = &$check($word); if (!$df) { $before .= $word; } { my $parent = $node->getParentNode; my $n1 = $doc->createTextNode; $n1->setNodeValue($before); $parent->insertBefore($n1, $node); $parent->insertBefore($df, $node) if $df; $node->setNodeValue($after); } } }; sub check_inner_text { my $node = shift; my $text = ''; for (my $i = $node->getFirstChild; defined $i; $i = $i->getNextSibling) { if ($i->getNodeType == TEXT_NODE) { spellcheck($i); } } }; sub parse_with_dom { my ($text) = @_; $text = ''.$text.''; my $parser = new XML::DOM::Parser; if ($debug) { open(FOO, '>:utf8', '/tmp/foo'); print FOO $text; close FOO; } my $doc = $parser->parse($text); my $nodes = $doc->getElementsByTagName('*'); my $n = $nodes->getLength; for (my $i = 0; $i < $n; ++$i) { my $node = $nodes->item($i); if ($node->getNodeType == ELEMENT_NODE) { check_inner_text($node); } } my $ret = $doc->toString; $ret =~ s{(.*)}{$1}sg; return $ret; }; sub make_js_hash { my ($hash) = @_; my $js_hash = ''; while (my ($key, $val) = each %$hash) { $js_hash .= ',' if $js_hash; $js_hash .= '"'.$key.'":"'.$val.'"'; } return $js_hash; }; sub make_js_hash_from_array { my ($array) = @_; my $js_hash = ''; foreach my $i (@$array) { $js_hash .= ',' if $js_hash; $js_hash .= '"'.$i->[0].'":"'.$i->[1].'"'; } return $js_hash; }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/readme-tech.html0000644000175000017500000001116610177203653033216 0ustar frankiefrankie HTMLArea Spell Checker

    HTMLArea Spell Checker

    The HTMLArea Spell Checker subsystem consists of the following files:

    • spell-checker.js — the spell checker plugin interface for HTMLArea
    • spell-checker-ui.html — the HTML code for the user interface
    • spell-checker-ui.js — functionality of the user interface
    • spell-checker-logic.cgi — Perl CGI script that checks a text given through POST for spelling errors
    • spell-checker-style.css — style for mispelled words
    • lang/en.js — main language file (English).

    Process overview

    When an end-user clicks the "spell-check" button in the HTMLArea editor, a new window is opened with the URL of "spell-check-ui.html". This window initializes itself with the text found in the editor (uses window.opener.SpellChecker.editor global variable) and it submits the text to the server-side script "spell-check-logic.cgi". The target of the FORM is an inline frame which is used both to display the text and correcting.

    Further, spell-check-logic.cgi calls Aspell for each portion of plain text found in the given HTML. It rebuilds an HTML file that contains clear marks of which words are incorrect, along with suggestions for each of them. This file is then loaded in the inline frame. Upon loading, a JavaScript function from "spell-check-ui.js" is called. This function will retrieve all mispelled words from the HTML of the iframe and will setup the user interface so that it allows correction.

    The server-side script (spell-check-logic.cgi)

    Unicode safety — the program is Unicode safe. HTML entities are expanded into their corresponding Unicode characters. These characters will be matched as part of the word passed to Aspell. All texts passed to Aspell are in Unicode (when appropriate). However, Aspell seems to not support Unicode yet (thread concerning Aspell and Unicode). This mean that words containing Unicode characters that are not in 0..255 are likely to be reported as "mispelled" by Aspell.

    Update: though I've never seen it mentioned anywhere, it looks that Aspell does, in fact, speak Unicode. Or else, maybe Text::Aspell does transparent conversion; anyway, this new version of our SpellChecker plugin is, as tests show so far, fully Unicode-safe... well, probably the only freeware Web-based spell-checker which happens to have Unicode support.

    The Perl Unicode manual (man perluniintro) states:

    Starting from Perl 5.6.0, Perl has had the capacity to handle Unicode natively. Perl 5.8.0, however, is the first recommended release for serious Unicode work. The maintenance release 5.6.1 fixed many of the problems of the initial Unicode implementation, but for example regular expressions still do not work with Unicode in 5.6.1.

    In other words, do not assume that this script is Unicode-safe on Perl interpreters older than 5.8.0.

    The following Perl modules are required:

    Of these, only Text::Aspell might need to be installed manually. The others are likely to be available by default in most Perl distributions.


    Mihai Bazon
    Last modified: Fri Jan 30 19:14:11 EET 2004 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/SpellChecker/spell-check-ui.js0000644000175000017500000002730510177203653033317 0ustar frankiefrankie// Spell Checker Plugin for HTMLArea-3.0 // Sponsored by www.americanbible.org // Implementation by Mihai Bazon, http://dynarch.com/mishoo/ // // (c) dynarch.com 2003-2005. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // $Id: spell-check-ui.js,v 1.2 2005/01/30 16:13:31 jeffd Exp $ // internationalization file was already loaded in parent ;-) var SpellChecker = window.opener.SpellChecker; var i18n = SpellChecker.I18N; var HTMLArea = window.opener.HTMLArea; var is_ie = HTMLArea.is_ie; var editor = SpellChecker.editor; var frame = null; var currentElement = null; var wrongWords = null; var modified = false; var allWords = {}; var fixedWords = []; var suggested_words = {}; function makeCleanDoc(leaveFixed) { // document.getElementById("status").innerHTML = 'Please wait: rendering valid HTML'; var words = wrongWords.concat(fixedWords); for (var i = words.length; --i >= 0;) { var el = words[i]; if (!(leaveFixed && /HA-spellcheck-fixed/.test(el.className))) { el.parentNode.insertBefore(el.firstChild, el); el.parentNode.removeChild(el); } else el.className = "HA-spellcheck-fixed"; } // we should use innerHTML here, but IE6's implementation fucks up the // HTML to such extent that our poor Perl parser doesn't understand it // anymore. return window.opener.HTMLArea.getHTML(frame.contentWindow.document.body, false, editor); }; function recheckClicked() { document.getElementById("status").innerHTML = i18n["Please wait: changing dictionary to"] + ': "' + document.getElementById("f_dictionary").value + '".'; var field = document.getElementById("f_content"); field.value = makeCleanDoc(true); field.form.submit(); }; function saveClicked() { if (modified) { editor.setHTML(makeCleanDoc(false)); } window.close(); return false; }; function cancelClicked() { var ok = true; if (modified) { ok = confirm(i18n["QUIT_CONFIRMATION"]); } if (ok) { window.close(); } return false; }; function replaceWord(el) { var replacement = document.getElementById("v_replacement").value; var this_word_modified = (el.innerHTML != replacement); if (this_word_modified) modified = true; if (el) { el.className = el.className.replace(/\s*HA-spellcheck-(hover|fixed)\s*/g, " "); } el.className += " HA-spellcheck-fixed"; el.__msh_fixed = true; if (!this_word_modified) { return false; } el.innerHTML = replacement; }; function replaceClicked() { replaceWord(currentElement); var start = currentElement.__msh_id; var index = start; do { ++index; if (index == wrongWords.length) { index = 0; } } while ((index != start) && wrongWords[index].__msh_fixed); if (index == start) { index = 0; alert(i18n["Finished list of mispelled words"]); } wrongWords[index].__msh_wordClicked(true); return false; }; function revertClicked() { document.getElementById("v_replacement").value = currentElement.__msh_origWord; replaceWord(currentElement); currentElement.className = "HA-spellcheck-error HA-spellcheck-current"; return false; }; function replaceAllClicked() { var replacement = document.getElementById("v_replacement").value; var ok = true; var spans = allWords[currentElement.__msh_origWord]; if (spans.length == 0) { alert("An impossible condition just happened. Call FBI. ;-)"); } else if (spans.length == 1) { replaceClicked(); return false; } /* var message = "The word \"" + currentElement.__msh_origWord + "\" occurs " + spans.length + " times.\n"; if (replacement == currentElement.__msh_origWord) { ok = confirm(message + "Ignore all occurrences?"); } else { ok = confirm(message + "Replace all occurrences with \"" + replacement + "\"?"); } */ if (ok) { for (var i = 0; i < spans.length; ++i) { if (spans[i] != currentElement) { replaceWord(spans[i]); } } // replace current element the last, so that we jump to the next word ;-) replaceClicked(); } return false; }; function ignoreClicked() { document.getElementById("v_replacement").value = currentElement.__msh_origWord; replaceClicked(); return false; }; function ignoreAllClicked() { document.getElementById("v_replacement").value = currentElement.__msh_origWord; replaceAllClicked(); return false; }; function learnClicked() { alert("Not [yet] implemented"); return false; }; function internationalizeWindow() { var types = ["div", "span", "button"]; for (var i = 0; i < types.length; ++i) { var tag = types[i]; var els = document.getElementsByTagName(tag); for (var j = els.length; --j >= 0;) { var el = els[j]; if (el.childNodes.length == 1 && /\S/.test(el.innerHTML)) { var txt = el.innerHTML; if (typeof i18n[txt] != "undefined") { el.innerHTML = i18n[txt]; } } } } }; function initDocument() { internationalizeWindow(); modified = false; frame = document.getElementById("i_framecontent"); var field = document.getElementById("f_content"); field.value = HTMLArea.getHTML(editor._doc.body, false, editor); field.form.submit(); document.getElementById("f_init").value = "0"; // assign some global event handlers var select = document.getElementById("v_suggestions"); select.onchange = function() { document.getElementById("v_replacement").value = this.value; }; if (is_ie) { select.attachEvent("ondblclick", replaceClicked); } else { select.addEventListener("dblclick", replaceClicked, true); } document.getElementById("b_replace").onclick = replaceClicked; // document.getElementById("b_learn").onclick = learnClicked; document.getElementById("b_replall").onclick = replaceAllClicked; document.getElementById("b_ignore").onclick = ignoreClicked; document.getElementById("b_ignall").onclick = ignoreAllClicked; document.getElementById("b_recheck").onclick = recheckClicked; document.getElementById("b_revert").onclick = revertClicked; document.getElementById("b_info").onclick = displayInfo; document.getElementById("b_ok").onclick = saveClicked; document.getElementById("b_cancel").onclick = cancelClicked; select = document.getElementById("v_dictionaries"); select.onchange = function() { document.getElementById("f_dictionary").value = this.value; }; }; function getAbsolutePos(el) { var r = { x: el.offsetLeft, y: el.offsetTop }; if (el.offsetParent) { var tmp = getAbsolutePos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; function wordClicked(scroll) { var self = this; if (scroll) (function() { var pos = getAbsolutePos(self); var ws = { x: frame.offsetWidth - 4, y: frame.offsetHeight - 4 }; var wp = { x: frame.contentWindow.document.body.scrollLeft, y: frame.contentWindow.document.body.scrollTop }; pos.x -= Math.round(ws.x/2); if (pos.x < 0) pos.x = 0; pos.y -= Math.round(ws.y/2); if (pos.y < 0) pos.y = 0; frame.contentWindow.scrollTo(pos.x, pos.y); })(); if (currentElement) { var a = allWords[currentElement.__msh_origWord]; currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " "); for (var i = 0; i < a.length; ++i) { var el = a[i]; if (el != currentElement) { el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " "); } } } currentElement = this; this.className += " HA-spellcheck-current"; var a = allWords[currentElement.__msh_origWord]; for (var i = 0; i < a.length; ++i) { var el = a[i]; if (el != currentElement) { el.className += " HA-spellcheck-same"; } } // document.getElementById("b_replall").disabled = (a.length <= 1); // document.getElementById("b_ignall").disabled = (a.length <= 1); var txt; if (a.length == 1) { txt = "one occurrence"; } else if (a.length == 2) { txt = "two occurrences"; } else { txt = a.length + " occurrences"; } var suggestions = suggested_words[this.__msh_origWord]; if (suggestions) suggestions = suggestions.split(/,/); else suggestions = []; var select = document.getElementById("v_suggestions"); document.getElementById("statusbar").innerHTML = "Found " + txt + ' for word "' + currentElement.__msh_origWord + '"'; for (var i = select.length; --i >= 0;) { select.remove(i); } for (var i = 0; i < suggestions.length; ++i) { var txt = suggestions[i]; var option = document.createElement("option"); option.value = txt; option.appendChild(document.createTextNode(txt)); select.appendChild(option); } document.getElementById("v_currentWord").innerHTML = this.__msh_origWord; if (suggestions.length > 0) { select.selectedIndex = 0; select.onchange(); } else { document.getElementById("v_replacement").value = this.innerHTML; } select.style.display = "none"; select.style.display = "block"; return false; }; function wordMouseOver() { this.className += " HA-spellcheck-hover"; }; function wordMouseOut() { this.className = this.className.replace(/\s*HA-spellcheck-hover\s*/g, " "); }; function displayInfo() { var info = frame.contentWindow.spellcheck_info; if (!info) alert("No information available"); else { var txt = "** Document information **"; for (var i in info) { txt += "\n" + i + " : " + info[i]; } alert(txt); } return false; }; function finishedSpellChecking() { // initialization of global variables currentElement = null; wrongWords = null; allWords = {}; fixedWords = []; suggested_words = frame.contentWindow.suggested_words; document.getElementById("status").innerHTML = "HTMLArea Spell Checker (info)"; var doc = frame.contentWindow.document; var spans = doc.getElementsByTagName("span"); var sps = []; var id = 0; for (var i = 0; i < spans.length; ++i) { var el = spans[i]; if (/HA-spellcheck-error/.test(el.className)) { sps.push(el); el.__msh_wordClicked = wordClicked; el.onclick = function(ev) { ev || (ev = window.event); ev && HTMLArea._stopEvent(ev); return this.__msh_wordClicked(false); }; el.onmouseover = wordMouseOver; el.onmouseout = wordMouseOut; el.__msh_id = id++; var txt = (el.__msh_origWord = el.firstChild.data); el.__msh_fixed = false; if (typeof allWords[txt] == "undefined") { allWords[txt] = [el]; } else { allWords[txt].push(el); } } else if (/HA-spellcheck-fixed/.test(el.className)) { fixedWords.push(el); } } wrongWords = sps; if (sps.length == 0) { if (!modified) { alert(i18n["NO_ERRORS_CLOSING"]); window.close(); } else { alert(i18n["NO_ERRORS"]); } return false; } (currentElement = sps[0]).__msh_wordClicked(true); var as = doc.getElementsByTagName("a"); for (var i = as.length; --i >= 0;) { var a = as[i]; a.onclick = function() { if (confirm(i18n["CONFIRM_LINK_CLICK"] + ":\n" + this.href + "\n" + i18n["I will open it in a new page."])) { window.open(this.href); } return false; }; } var dicts = doc.getElementById("HA-spellcheck-dictionaries"); if (dicts) { dicts.parentNode.removeChild(dicts); dicts = dicts.innerHTML.split(/,/); var select = document.getElementById("v_dictionaries"); for (var i = select.length; --i >= 0;) { select.remove(i); } for (var i = 0; i < dicts.length; ++i) { var txt = dicts[i]; var option = document.createElement("option"); if (/^@(.*)$/.test(txt)) { txt = RegExp.$1; option.selected = true; } option.value = txt; option.appendChild(document.createTextNode(txt)); select.appendChild(option); } } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/0000755000175000017500000000000011724401447030052 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/menu.css0000644000175000017500000000256010177203651031531 0ustar frankiefrankie/* styles for the ContextMenu /HTMLArea */ /* The ContextMenu plugin is (c) dynarch.com 2003. */ /* Distributed under the same terms as HTMLArea itself */ div.htmlarea-context-menu { position: absolute; border: 1px solid #aca899; padding: 2px; background-color: #fff; color: #000; cursor: default; z-index: 1000; } div.htmlarea-context-menu table { font: 11px tahoma,verdana,sans-serif; border-collapse: collapse; } div.htmlarea-context-menu tr.item td.icon img { width: 18px; height: 18px; } div.htmlarea-context-menu tr.item td.icon { padding: 0px 3px; height: 18px; background-color: #cdf; } div.htmlarea-context-menu tr.item td.label { padding: 1px 10px 1px 3px; } div.htmlarea-context-menu tr.separator td { padding: 2px 0px; } div.htmlarea-context-menu tr.separator td div { border-top: 1px solid #aca899; overflow: hidden; position: relative; } div.htmlarea-context-menu tr.separator td.icon { background-color: #cdf; } div.htmlarea-context-menu tr.separator td.icon div { /* margin-left: 3px; */ border-color: #fff; } div.htmlarea-context-menu tr.separator td.label div { margin-right: 3px; } div.htmlarea-context-menu tr.item.hover { background-color: #316ac5; color: #fff; } div.htmlarea-context-menu tr.item.hover td.icon { background-color: #619af5; } openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/0000755000175000017500000000000011724401447030773 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/de.js0000644000175000017500000001015610177203651031722 0ustar frankiefrankie// I18N constants // LANG: "de", ENCODING: UTF-8 | ISO-8859-1 // translated: <]{MJ}[> i@student.ethz.ch ContextMenu.I18N = { // Items that appear in menu. Please note that an underscore (_) // character in the translation (right column) will cause the following // letter to become underlined and be shortcut for that menu option. "Cut" : "Ausschneiden", "Copy" : "Kopieren", "Paste" : "Einfügen", "Image Properties" : "_Bild Einstellungen...", "Modify Link" : "_Link ändern...", "Check Link" : "Link testen...", "Remove Link" : "Link entfernen...", "Cell Properties" : "Z_ellen Einstellungen...", "Row Properties" : "Ze_ilen Einstellungen...", "Insert Row Before" : "Zeile einfügen v_or Position", "Insert Row After" : "Zeile einfügen n_ach Position", "Delete Row" : "Zeile löschen", "Table Properties" : "_Tabellen Einstellungen...", "Insert Column Before" : "Spalte einfügen vo_r Position", "Insert Column After" : "Spalte einfügen na_ch Position", "Delete Column" : "Spalte löschen", "Justify Left" : "Links ausrichten", "Justify Center" : "Zentriert", "Justify Right" : "Rechts ausrichten", "Justify Full" : "Blocksatz", "Make link" : "Lin_k erstellen...", "Remove the" : "", "Element" : "Element entfernen...", // Other labels (tooltips and alert/confirm box messages) "Please confirm that you want to remove this element:" : "Wollen sie dieses Element wirklich entfernen ?", "Remove this node from the document" : "Dieses Element aus dem Dokument entfernen", "How did you get here? (Please report!)" : "How did you get here? (Please report!)", "Show the image properties dialog" : "Fenster für die Bild-Einstellungen anzeigen", "Modify URL" : "URL ändern", "Current URL is" : "Aktuelle URL ist", "Opens this link in a new window" : "Diesen Link in neuem Fenster öffnen", "Please confirm that you want to unlink this element." : "Wollen sie diesen Link wirklich entfernen ?", "Link points to:" : "Link zeigt auf:", "Unlink the current element" : "Link auf Element entfernen", "Show the Table Cell Properties dialog" : "Zellen-Einstellungen anzeigen", "Show the Table Row Properties dialog" : "Zeilen-Einstellungen anzeigen", "Insert a new row before the current one" : "Zeile einfügen vor der aktuellen Position", "Insert a new row after the current one" : "Zeile einfügen nach der aktuellen Position", "Delete the current row" : "Zeile löschen", "Show the Table Properties dialog" : "Show the Table Properties dialog", "Insert a new column before the current one" : "Spalte einfügen vor der aktuellen Position", "Insert a new column after the current one" : "Spalte einfügen nach der aktuellen Position", "Delete the current column" : "Spalte löschen", "Create a link" : "Link erstellen" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/el.js0000644000175000017500000001234310177203651031732 0ustar frankiefrankie// I18N constants // LANG: "el", ENCODING: UTF-8 | ISO-8859-7 // Author: Dimitris Glezos, dimitris@glezos.com ContextMenu.I18N = { // Items that appear in menu. Please note that an underscore (_) // character in the translation (right column) will cause the following // letter to become underlined and be shortcut for that menu option. "Cut" : "Αποκοπή", "Copy" : "ΑντιγÏαφή", "Paste" : "Επικόλληση", "Image Properties" : "Ιδιότητες Εικόνας...", "Modify Link" : "ΤÏοποποίηση συνδέσμου...", "Check Link" : "Έλεγχος συνδέσμων...", "Remove Link" : "ΔιαγÏαφή συνδέσμου...", "Cell Properties" : "Ιδιότητες κελιοÏ...", "Row Properties" : "Ιδιότητες γÏαμμής...", "Insert Row Before" : "Εισαγωγή γÏαμμής Ï€Ïιν", "Insert Row After" : "Εισαγωγή γÏαμμής μετά", "Delete Row" : "ΔιαγÏαφή γÏαμμής", "Table Properties" : "Ιδιότητες πίνακα...", "Insert Column Before" : "Εισαγωγή στήλης Ï€Ïιν", "Insert Column After" : "Εισαγωγή στήλης μετά", "Delete Column" : "ΔιαγÏαφή στήλης", "Justify Left" : "Στοίχηση ΑÏιστεÏά", "Justify Center" : "Στοίχηση ΚέντÏο", "Justify Right" : "Στοίχηση Δεξιά", "Justify Full" : "ΠλήÏης Στοίχηση", "Make link" : "ΔημιουÏγία συνδέσμου...", "Remove the" : "ΑφαίÏεση", "Element" : "στοιχείου...", // Other labels (tooltips and alert/confirm box messages) "Please confirm that you want to remove this element:" : "Είστε βέβαιος πως θέλετε να αφαιÏέσετε το στοιχείο ", "Remove this node from the document" : "ΑφαίÏεση Î±Ï…Ï„Î¿Ï Ï„Î¿Ï… κόμβου από το έγγÏαφο", "How did you get here? (Please report!)" : "Πώς ήÏθατε μέχÏι εδώ; (ΠαÏακαλοÏμε αναφέÏετε το!)", "Show the image properties dialog" : "Εμφάνιση διαλόγου με τις Ιδιότητες εικόνας", "Modify URL" : "ΤÏοποποίηση URL", "Current URL is" : "Το Ï„Ïέχων URL είναι", "Opens this link in a new window" : "Ανοίγει αυτό τον σÏνδεσμο σε ένα νέο παÏάθυÏο", "Please confirm that you want to unlink this element." : "Είστε βέβαιος πως θέλετε να αφαιÏέσετε τον σÏνδεσμο από αυτό το στοιχείο:", "Link points to:" : "Ο σÏνδεμος οδηγεί εδώ:", "Unlink the current element" : "ΑφαίÏεση συνδέσμου από το παÏών στοιχείο", "Show the Table Cell Properties dialog" : "Εμφάνιση διαλόγου με τις Ιδιότητες ÎºÎµÎ»Î¹Î¿Ï Î Î¯Î½Î±ÎºÎ±", "Show the Table Row Properties dialog" : "Εμφάνιση διαλόγου με τις Ιδιότητες γÏαμμής Πίνακα", "Insert a new row before the current one" : "Εισαγωγή μιας νέας γÏαμμής Ï€Ïιν την επιλεγμένη", "Insert a new row after the current one" : "Εισαγωγή μιας νέας γÏαμμής μετά την επιλεγμένη", "Delete the current row" : "ΔιαγÏαφή επιλεγμένης γÏαμμής", "Show the Table Properties dialog" : "Εμφάνιση διαλόγου με τις Ιδιότητες Πίνακα", "Insert a new column before the current one" : "Εισαγωγή νέας στήλης Ï€Ïιν την επιλεγμένη", "Insert a new column after the current one" : "Εισαγωγή νέας στήλης μετά την επιλεγμένη", "Delete the current column" : "ΔιαγÏαφή επιλεγμένης στήλης", "Create a link" : "ΔημιουÏγία συνδέσμου" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/en.js0000644000175000017500000001140410177203651031731 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) ContextMenu.I18N = { // Items that appear in menu. Please note that an underscore (_) // character in the translation (right column) will cause the following // letter to become underlined and be shortcut for that menu option. "Cut" : "Cut", "Copy" : "Copy", "Paste" : "Paste", "Image Properties" : "_Image Properties...", "Modify Link" : "_Modify Link...", "Check Link" : "Chec_k Link...", "Remove Link" : "_Remove Link...", "Cell Properties" : "C_ell Properties...", "Row Properties" : "Ro_w Properties...", "Insert Row Before" : "I_nsert Row Before", "Insert Row After" : "In_sert Row After", "Delete Row" : "_Delete Row", "Delete Cell" : "Delete Cell", "Table Properties" : "_Table Properties...", "Insert Column Before" : "Insert _Column Before", "Insert Column After" : "Insert C_olumn After", "Delete Column" : "De_lete Column", "Justify Left" : "Justify Left", "Justify Center" : "Justify Center", "Justify Right" : "Justify Right", "Justify Full" : "Justify Full", "Make link" : "Make lin_k...", "Remove the" : "Remove the", "Element" : "Element...", "Insert paragraph before" : "Insert paragraph before", "Insert paragraph after" : "Insert paragraph after", // Other labels (tooltips and alert/confirm box messages) "Please confirm that you want to remove this element:" : "Please confirm that you want to remove this element:", "Remove this node from the document" : "Remove this node from the document", "How did you get here? (Please report!)" : "How did you get here? (Please report!)", "Show the image properties dialog" : "Show the image properties dialog", "Modify URL" : "Modify URL", "Current URL is" : "Current URL is", "Opens this link in a new window" : "Opens this link in a new window", "Please confirm that you want to unlink this element." : "Please confirm that you want to unlink this element.", "Link points to:" : "Link points to:", "Unlink the current element" : "Unlink the current element", "Show the Table Cell Properties dialog" : "Show the Table Cell Properties dialog", "Show the Table Row Properties dialog" : "Show the Table Row Properties dialog", "Insert a new row before the current one" : "Insert a new row before the current one", "Insert a new row after the current one" : "Insert a new row after the current one", "Delete the current row" : "Delete the current row", "Show the Table Properties dialog" : "Show the Table Properties dialog", "Insert a new column before the current one" : "Insert a new column before the current one", "Insert a new column after the current one" : "Insert a new column after the current one", "Delete the current column" : "Delete the current column", "Create a link" : "Create a link", "Insert a paragraph before the current node" : "Insert a paragraph before the current node", "Insert a paragraph after the current node" : "Insert a paragraph after the current node" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/fr.js0000644000175000017500000001110010177203651031727 0ustar frankiefrankie// I18N constants // LANG: "fr", ENCODING: UTF-8 | ISO-8859-1 // Author: Cédric Guillemette, http://www.ebdata.com // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) ContextMenu.I18N = { // Items that appear in menu. Please note that an underscore (_) // character in the translation (right column) will cause the following // letter to become underlined and be shortcut for that menu option. "Cut" : "Couper", "Copy" : "Copier", "Paste" : "Coller", "Image Properties" : "_Propriétés de l'image...", "Modify Link" : "_Modifier le lien...", "Check Link" : "_Vérifier le lien...", "Remove Link" : "_Supprimer le lien...", "Cell Properties" : "P_ropriétés de la cellule...", "Row Properties" : "Pr_opriétés de la rangée...", "Insert Row Before" : "Insérer une rangée a_vant", "Insert Row After" : "Insér_er une rangée après", "Delete Row" : "Suppr_imer une rangée", "Table Properties" : "Proprié_tés de la table...", "Insert Column Before" : "I_nsérer une colonne avant", "Insert Column After" : "Insérer une colonne _après", "Delete Column" : "_Supprimer la colonne", "Justify Left" : "Justifier _gauche", "Justify Center" : "Justifier _centre", "Justify Right" : "Justifier _droit", "Justify Full" : "Justifier p_lein", "Make link" : "Convertir en lien...", "Remove the" : "Supprimer", "Element" : "Élément...", // Other labels (tooltips and alert/confirm box messages) "Please confirm that you want to remove this element:" : "Confirmer la suppression de cet élément:", "Remove this node from the document" : "Supprimer ce noeud du document", "How did you get here? (Please report!)" : "Comment êtes-vous arrivé ici? (Please report!)", "Show the image properties dialog" : "Afficher le dialogue des propriétés d'image", "Modify URL" : "Modifier le URL", "Current URL is" : "Le URL courant est", "Opens this link in a new window" : "Ouvrir ce lien dans une nouvelle fenêtre", "Please confirm that you want to unlink this element." : "Voulez-vous vraiment enlever le lien présent sur cet élément.", "Link points to:" : "Lier les points jusqu'à:", "Unlink the current element" : "Enlever le lien sur cet élément", "Show the Table Cell Properties dialog" : "Afficher le dialogue des propriétés des cellules", "Show the Table Row Properties dialog" : "Afficher le dialogue des propriétés des rangées", "Insert a new row before the current one" : "Insérer une nouvelle rangée avant celle-ci", "Insert a new row after the current one" : "Insérer une nouvelle rangée après celle-ci", "Delete the current row" : "Supprimer la rangée courante", "Show the Table Properties dialog" : "Afficher le dialogue des propriétés de table", "Insert a new column before the current one" : "Insérer une nouvelle rangée avant celle-ci", "Insert a new column after the current one" : "Insérer une nouvelle colonne après celle-ci", "Delete the current column" : "Supprimer cette colonne", "Create a link" : "Créer un lien" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/he.js0000644000175000017500000001150410177203651031724 0ustar frankiefrankie// I18N constants // LANG: "he", ENCODING: UTF-8 // Author: Liron Newman, http://www.eesh.net, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) ContextMenu.I18N = { // Items that appear in menu. Please note that an underscore (_) // character in the translation (right column) will cause the following // letter to become underlined and be shortcut for that menu option. "Cut" : "גזור", "Copy" : "העתק", "Paste" : "הדבק", "Image Properties" : "_מ×פייני תמונה...", "Modify Link" : "_שנה קישור...", "Check Link" : "בדו_×§ קישור...", "Remove Link" : "_הסר קישור...", "Cell Properties" : "מ×פייני ת_×...", "Row Properties" : "מ×פייני _טור...", "Insert Row Before" : "×”_כנס שורה לפני", "Insert Row After" : "×”×›× _ס שורה ×חרי", "Delete Row" : "_מחק שורה", "Table Properties" : "מ×פייני ט_בלה...", "Insert Column Before" : "הכנס _טור לפני", "Insert Column After" : "הכנס ט_ור ×חרי", "Delete Column" : "מח_×§ טור", "Justify Left" : "ישור לשמ×ל", "Justify Center" : "ישור למרכז", "Justify Right" : "ישור לימין", "Justify Full" : "ישור לשורה מל××”", "Make link" : "צור ×§×™_שור...", "Remove the" : "הסר ×ת ×למנט ×”-", "Element" : "...", // Other labels (tooltips and alert/confirm box messages) "Please confirm that you want to remove this element:" : "×× × ×שר שברצונך להסיר ×ת ×”×למנט ×”×–×”:", "Remove this node from the document" : "הסרה של node ×–×” מהמסמך", "How did you get here? (Please report!)" : "×יך הגעת ×”× ×”? (×× × ×“×•×•×—!)", "Show the image properties dialog" : "מציג ×ת חלון הדו-שיח של מ×פייני תמונה", "Modify URL" : "שינוי URL", "Current URL is" : "URL נוכחי הו×", "Opens this link in a new window" : "פתיחת קישור ×–×” בחלון חדש", "Please confirm that you want to unlink this element." : "×× × ×שר ש×תה רוצה לנתק ×ת ×למנט ×–×”.", "Link points to:" : "הקישור מצביע ×ל:", "Unlink the current element" : "ניתוק ×ת ×”×למנט הנוכחי", "Show the Table Cell Properties dialog" : "מציג ×ת חלון הדו-שיח של מ×פייני ×ª× ×‘×˜×‘×œ×”", "Show the Table Row Properties dialog" : "מציג ×ת חלון הדו-שיח של מ×פייני שורה בטבלה", "Insert a new row before the current one" : "הוספת שורה חדשה לפני הנוכחית", "Insert a new row after the current one" : "הוספת שורה חדשה ×חרי הנוכחית", "Delete the current row" : "מחיקת ×ת השורה הנוכחית", "Show the Table Properties dialog" : "מציג ×ת חלון הדו-שיח של מ×פייני טבלה", "Insert a new column before the current one" : "הוספת טור חדש לפני הנוכחי", "Insert a new column after the current one" : "הוספת טור חדש ×חרי הנוכחי", "Delete the current column" : "מחיקת ×ת הטור הנוכחי", "Create a link" : "יצירת קישור" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/lang/nl.js0000644000175000017500000001100610177203651031736 0ustar frankiefrankie// I18N constants // LANG: "nl", ENCODING: UTF-8 | ISO-8859-1 // Author: Michel Weegeerink (info@mmc-shop.nl), http://mmc-shop.nl // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) ContextMenu.I18N = { // Items that appear in menu. Please note that an underscore (_) // character in the translation (right column) will cause the following // letter to become underlined and be shortcut for that menu option. "Cut" : "Knippen", "Copy" : "Kopiëren", "Paste" : "Plakken", "Image Properties" : "Eigenschappen afbeelding...", "Modify Link" : "Hyperlin_k aanpassen...", "Check Link" : "Controleer hyperlin_k...", "Remove Link" : "Ve_rwijder hyperlink...", "Cell Properties" : "C_eleigenschappen...", "Row Properties" : "Rijeigenscha_ppen...", "Insert Row Before" : "Rij invoegen boven", "Insert Row After" : "Rij invoegen onder", "Delete Row" : "Rij _verwijderen", "Table Properties" : "_Tabeleigenschappen...", "Insert Column Before" : "Kolom invoegen voor", "Insert Column After" : "Kolom invoegen na", "Delete Column" : "Kolom verwijderen", "Justify Left" : "Links uitlijnen", "Justify Center" : "Centreren", "Justify Right" : "Rechts uitlijnen", "Justify Full" : "Uitvullen", "Make link" : "Maak hyperlin_k...", "Remove the" : "Verwijder het", "Element" : "element...", // Other labels (tooltips and alert/confirm box messages) "Please confirm that you want to remove this element:" : "Is het werkelijk de bedoeling dit element te verwijderen:", "Remove this node from the document" : "Verwijder dit punt van het document", "How did you get here? (Please report!)" : "Hoe kwam je hier? (A.U.B. doorgeven!)", "Show the image properties dialog" : "Laat het afbeeldingseigenschappen dialog zien", "Modify URL" : "Aanpassen URL", "Current URL is" : "Huidig URL is", "Opens this link in a new window" : "Opend deze hyperlink in een nieuw venster", "Please confirm that you want to unlink this element." : "Is het werkelijk de bedoeling dit element te unlinken.", "Link points to:" : "Hyperlink verwijst naar:", "Unlink the current element" : "Unlink het huidige element", "Show the Table Cell Properties dialog" : "Laat de tabel celeigenschappen dialog zien", "Show the Table Row Properties dialog" : "Laat de tabel rijeigenschappen dialog zien", "Insert a new row before the current one" : "Voeg een nieuwe rij in boven de huidige", "Insert a new row after the current one" : "Voeg een nieuwe rij in onder de huidige", "Delete the current row" : "Verwijder de huidige rij", "Show the Table Properties dialog" : "Laat de tabel eigenschappen dialog zien", "Insert a new column before the current one" : "Voeg een nieuwe kolom in voor de huidige", "Insert a new column after the current one" : "Voeg een nieuwe kolom in na de huidige", "Delete the current column" : "Verwijder de huidige kolom", "Create a link" : "Maak een hyperlink" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ContextMenu/context-menu.js0000644000175000017500000003446010177203651033043 0ustar frankiefrankie// Context Menu Plugin for HTMLArea-3.0 // Sponsored by www.americanbible.org // Implementation by Mihai Bazon, http://dynarch.com/mishoo/ // // (c) dynarch.com 2003-2005. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // $Id: context-menu.js,v 1.1 2005/01/30 16:13:29 jeffd Exp $ HTMLArea.loadStyle("menu.css", "ContextMenu"); function ContextMenu(editor) { this.editor = editor; }; ContextMenu._pluginInfo = { name : "ContextMenu", version : "1.0", developer : "Mihai Bazon", developer_url : "http://dynarch.com/mishoo/", c_owner : "dynarch.com", sponsor : "American Bible Society", sponsor_url : "http://www.americanbible.org", license : "htmlArea" }; ContextMenu.prototype.onGenerate = function() { var self = this; var doc = this.editordoc = this.editor._iframe.contentWindow.document; HTMLArea._addEvents(doc, ["contextmenu"], function (event) { return self.popupMenu(HTMLArea.is_ie ? self.editor._iframe.contentWindow.event : event); }); this.currentMenu = null; }; ContextMenu.prototype.getContextMenu = function(target) { var self = this; var editor = this.editor; var config = editor.config; var menu = []; var tbo = this.editor.plugins.TableOperations; if (tbo) tbo = tbo.instance; var i18n = ContextMenu.I18N; var selection = editor.hasSelectedText(); if (selection) menu.push([ i18n["Cut"], function() { editor.execCommand("cut"); }, null, config.btnList["cut"][1] ], [ i18n["Copy"], function() { editor.execCommand("copy"); }, null, config.btnList["copy"][1] ]); menu.push([ i18n["Paste"], function() { editor.execCommand("paste"); }, null, config.btnList["paste"][1] ]); var currentTarget = target; var elmenus = []; var tmp; var link = null; var table = null; var tr = null; var td = null; var img = null; function tableOperation(opcode) { tbo.buttonPress(editor, opcode); }; function insertPara(currentTarget, after) { var el = currentTarget; var par = el.parentNode; var p = editor._doc.createElement("p"); p.appendChild(editor._doc.createElement("br")); par.insertBefore(p, after ? el.nextSibling : el); var sel = editor._getSelection(); var range = editor._createRange(sel); if (!HTMLArea.is_ie) { sel.removeAllRanges(); range.selectNodeContents(p); range.collapse(true); sel.addRange(range); } else { range.moveToElementText(p); range.collapse(true); range.select(); } }; for (; target; target = target.parentNode) { var tag = target.tagName; if (!tag) continue; tag = tag.toLowerCase(); switch (tag) { case "img": img = target; elmenus.push(null, [ i18n["Image Properties"], function() { editor._insertImage(img); }, i18n["Show the image properties dialog"], config.btnList["insertimage"][1] ] ); break; case "a": link = target; elmenus.push(null, [ i18n["Modify Link"], function() { editor.execCommand("createlink", true); }, i18n["Current URL is"] + ': ' + link.href, config.btnList["createlink"][1] ], [ i18n["Check Link"], function() { window.open(link.href); }, i18n["Opens this link in a new window"] ], [ i18n["Remove Link"], function() { if (confirm(i18n["Please confirm that you want to unlink this element."] + "\n" + i18n["Link points to:"] + " " + link.href)) { while (link.firstChild) link.parentNode.insertBefore(link.firstChild, link); link.parentNode.removeChild(link); } }, i18n["Unlink the current element"] ] ); break; case "td": td = target; if (!tbo) break; elmenus.push(null, [ i18n["Cell Properties"], function() { tableOperation("TO-cell-prop"); }, i18n["Show the Table Cell Properties dialog"], config.btnList["TO-cell-prop"][1] ], [ i18n["Delete Cell"], function() { tableOperation("TO-cell-delete"); }, null, config.btnList["TO-cell-delete"][1] ] ); break; case "tr": tr = target; if (!tbo) break; elmenus.push(null, [ i18n["Row Properties"], function() { tableOperation("TO-row-prop"); }, i18n["Show the Table Row Properties dialog"], config.btnList["TO-row-prop"][1] ], [ i18n["Insert Row Before"], function() { tableOperation("TO-row-insert-above"); }, i18n["Insert a new row before the current one"], config.btnList["TO-row-insert-above"][1] ], [ i18n["Insert Row After"], function() { tableOperation("TO-row-insert-under"); }, i18n["Insert a new row after the current one"], config.btnList["TO-row-insert-under"][1] ], [ i18n["Delete Row"], function() { tableOperation("TO-row-delete"); }, i18n["Delete the current row"], config.btnList["TO-row-delete"][1] ] ); break; case "table": table = target; if (!tbo) break; elmenus.push(null, [ i18n["Table Properties"], function() { tableOperation("TO-table-prop"); }, i18n["Show the Table Properties dialog"], config.btnList["TO-table-prop"][1] ], [ i18n["Insert Column Before"], function() { tableOperation("TO-col-insert-before"); }, i18n["Insert a new column before the current one"], config.btnList["TO-col-insert-before"][1] ], [ i18n["Insert Column After"], function() { tableOperation("TO-col-insert-after"); }, i18n["Insert a new column after the current one"], config.btnList["TO-col-insert-after"][1] ], [ i18n["Delete Column"], function() { tableOperation("TO-col-delete"); }, i18n["Delete the current column"], config.btnList["TO-col-delete"][1] ] ); break; case "body": elmenus.push(null, [ i18n["Justify Left"], function() { editor.execCommand("justifyleft"); }, null, config.btnList["justifyleft"][1] ], [ i18n["Justify Center"], function() { editor.execCommand("justifycenter"); }, null, config.btnList["justifycenter"][1] ], [ i18n["Justify Right"], function() { editor.execCommand("justifyright"); }, null, config.btnList["justifyright"][1] ], [ i18n["Justify Full"], function() { editor.execCommand("justifyfull"); }, null, config.btnList["justifyfull"][1] ] ); break; } } if (selection && !link) menu.push(null, [ i18n["Make link"], function() { editor.execCommand("createlink", true); }, i18n["Create a link"], config.btnList["createlink"][1] ]); for (var i = 0; i < elmenus.length; ++i) menu.push(elmenus[i]); if (!/html|body/i.test(currentTarget.tagName)) { table ? (tmp = table, table = null) : (tmp = currentTarget); menu.push(null, [ i18n["Remove the"] + " <" + tmp.tagName + "> " + i18n["Element"], function() { if (confirm(i18n["Please confirm that you want to remove this element:"] + " " + tmp.tagName)) { var el = tmp; var p = el.parentNode; p.removeChild(el); if (HTMLArea.is_gecko) { if (p.tagName.toLowerCase() == "td" && !p.hasChildNodes()) p.appendChild(editor._doc.createElement("br")); editor.forceRedraw(); editor.focusEditor(); editor.updateToolbar(); if (table) { var save_collapse = table.style.borderCollapse; table.style.borderCollapse = "collapse"; table.style.borderCollapse = "separate"; table.style.borderCollapse = save_collapse; } } } }, i18n["Remove this node from the document"] ], [ i18n["Insert paragraph before"], function() { insertPara(tmp, false); }, i18n["Insert a paragraph before the current node"] ], [ i18n["Insert paragraph after"], function() { insertPara(tmp, true); }, i18n["Insert a paragraph after the current node"] ] ); } return menu; }; ContextMenu.prototype.popupMenu = function(ev) { var self = this; var i18n = ContextMenu.I18N; if (this.currentMenu) this.currentMenu.parentNode.removeChild(this.currentMenu); function getPos(el) { var r = { x: el.offsetLeft, y: el.offsetTop }; if (el.offsetParent) { var tmp = getPos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; function documentClick(ev) { ev || (ev = window.event); if (!self.currentMenu) { alert(i18n["How did you get here? (Please report!)"]); return false; } var el = HTMLArea.is_ie ? ev.srcElement : ev.target; for (; el != null && el != self.currentMenu; el = el.parentNode); if (el == null) self.closeMenu(); //HTMLArea._stopEvent(ev); //return false; }; var keys = []; function keyPress(ev) { ev || (ev = window.event); HTMLArea._stopEvent(ev); if (ev.keyCode == 27) { self.closeMenu(); return false; } var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase(); for (var i = keys.length; --i >= 0;) { var k = keys[i]; if (k[0].toLowerCase() == key) k[1].__msh.activate(); } }; self.closeMenu = function() { self.currentMenu.parentNode.removeChild(self.currentMenu); self.currentMenu = null; HTMLArea._removeEvent(document, "mousedown", documentClick); HTMLArea._removeEvent(self.editordoc, "mousedown", documentClick); if (keys.length > 0) HTMLArea._removeEvent(self.editordoc, "keypress", keyPress); if (HTMLArea.is_ie) self.iePopup.hide(); }; var target = HTMLArea.is_ie ? ev.srcElement : ev.target; var ifpos = getPos(self.editor._iframe); var x = ev.clientX + ifpos.x; var y = ev.clientY + ifpos.y; var div; var doc; if (!HTMLArea.is_ie) { doc = document; } else { // IE stinks var popup = this.iePopup = window.createPopup(); doc = popup.document; doc.open(); doc.write(""); doc.close(); } div = doc.createElement("div"); if (HTMLArea.is_ie) div.unselectable = "on"; div.oncontextmenu = function() { return false; }; div.className = "htmlarea-context-menu"; if (!HTMLArea.is_ie) div.style.left = div.style.top = "0px"; doc.body.appendChild(div); var table = doc.createElement("table"); div.appendChild(table); table.cellSpacing = 0; table.cellPadding = 0; var parent = doc.createElement("tbody"); table.appendChild(parent); var options = this.getContextMenu(target); for (var i = 0; i < options.length; ++i) { var option = options[i]; var item = doc.createElement("tr"); parent.appendChild(item); if (HTMLArea.is_ie) item.unselectable = "on"; else item.onmousedown = function(ev) { HTMLArea._stopEvent(ev); return false; }; if (!option) { item.className = "separator"; var td = doc.createElement("td"); td.className = "icon"; var IE_IS_A_FUCKING_SHIT = '>'; if (HTMLArea.is_ie) { td.unselectable = "on"; IE_IS_A_FUCKING_SHIT = " unselectable='on' style='height=1px'> "; } td.innerHTML = ""; var td1 = td.cloneNode(true); td1.className = "label"; item.appendChild(td); item.appendChild(td1); } else { var label = option[0]; item.className = "item"; item.__msh = { item: item, label: label, action: option[1], tooltip: option[2] || null, icon: option[3] || null, activate: function() { self.closeMenu(); self.editor.focusEditor(); this.action(); } }; label = label.replace(/_([a-zA-Z0-9])/, "$1"); if (label != option[0]) keys.push([ RegExp.$1, item ]); label = label.replace(/__/, "_"); var td1 = doc.createElement("td"); if (HTMLArea.is_ie) td1.unselectable = "on"; item.appendChild(td1); td1.className = "icon"; if (item.__msh.icon) td1.innerHTML = ""; var td2 = doc.createElement("td"); if (HTMLArea.is_ie) td2.unselectable = "on"; item.appendChild(td2); td2.className = "label"; td2.innerHTML = label; item.onmouseover = function() { this.className += " hover"; self.editor._statusBarTree.innerHTML = this.__msh.tooltip || ' '; }; item.onmouseout = function() { this.className = "item"; }; item.oncontextmenu = function(ev) { this.__msh.activate(); if (!HTMLArea.is_ie) HTMLArea._stopEvent(ev); return false; }; item.onmouseup = function(ev) { var timeStamp = (new Date()).getTime(); if (timeStamp - self.timeStamp > 500) this.__msh.activate(); if (!HTMLArea.is_ie) HTMLArea._stopEvent(ev); return false; }; //if (typeof option[2] == "string") //item.title = option[2]; } } if (!HTMLArea.is_ie) { var dx = x + div.offsetWidth - window.innerWidth + 4; var dy = y + div.offsetHeight - window.innerHeight + 4; if (dx > 0) x -= dx; if (dy > 0) y -= dy; div.style.left = x + "px"; div.style.top = y + "px"; } else { // determine the size (did I mention that IE stinks?) var foobar = document.createElement("div"); foobar.className = "htmlarea-context-menu"; foobar.innerHTML = div.innerHTML; document.body.appendChild(foobar); var w = foobar.offsetWidth; var h = foobar.offsetHeight; document.body.removeChild(foobar); this.iePopup.show(ev.screenX, ev.screenY, w, h); } this.currentMenu = div; this.timeStamp = (new Date()).getTime(); HTMLArea._addEvent(document, "mousedown", documentClick); HTMLArea._addEvent(this.editordoc, "mousedown", documentClick); if (keys.length > 0) HTMLArea._addEvent(this.editordoc, "keypress", keyPress); HTMLArea._stopEvent(ev); return false; }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/0000755000175000017500000000000011575225613030677 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/0000755000175000017500000000000011724401447031450 5ustar frankiefrankie././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-insert-under.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-insert-0000644000175000017500000000016310021673055033554 0ustar frankiefrankieGIF89aÂÿÿ„ကÿÿÿÿÿÿÿÿÿÿÿÿ!ù,8xºÜþðIIT#k{õ¾‡—qQEBª’º¢®À>æBbFA. ®×#ƒ<(äé*·è-;././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-split.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-split.g0000644000175000017500000000161410021673055033523 0ustar frankiefrankieGIF89a瀀€€€€€€€ÀÀÀÀÜÀ¦Êð@ ` €   À à @ @@@`@€@ @À@à@` `@```€` `À`à`€ €@€`€€€ €À€à€   @ ` €   À à À À@À`À€À ÀÀÀàÀà à@à`à€à àÀààà@ @@@`@€@ @À@à@ @ @@ @` @€ @  @À @à @@@ @@@@@`@@€@@ @@À@@à@@`@ `@@`@``@€`@ `@À`@à`@€@ €@@€@`€@€€@ €@À€@à€@ @  @@ @` @€ @  @À @à @À@ À@@À@`À@€À@ À@ÀÀ@àÀ@à@ à@@à@`à@€à@ à@Àà@àà@€ €@€`€€€ €À€à€ € €@ €` €€ €  €À €à €@€ @€@@€`@€€@€ @€À@€à@€`€ `€@`€``€€`€ `€À`€à`€€€ €€@€€`€€€€€ €€À€€à€€ €  €@ €` €€ €  €À €à €À€ À€@À€`À€€À€ À€ÀÀ€àÀ€à€ à€@à€`à€€à€ à€Àà€àà€À À@À`À€À ÀÀÀàÀ À À@ À` À€ À  ÀÀ Àà À@À @À@@À`@À€@À @ÀÀ@Àà@À`À `À@`À``À€`À `ÀÀ`Àà`À€À €À@€À`€À€€À €ÀÀ€Àà€À À  À@ À` À€ À  ÀÀ Àà ÀÀÀ ÀÀ@ÀÀ`ÀÀ€ÀÀ ÀÀÿûð  ¤€€€ÿÿÿÿÿÿÿÿÿÿÿÿ!ùý,iû H° ÁƒûXȰ¡Cüû'qâÄŠ!*¼h‘cGC2ŒxÑß?L¢T ’£I'ÿÁ4Ù’¢Ê”'qúÉ0æL™1k¸Iô¤PŸHi’´™³èÎ¥_&¥QdÈ„X³jÝ;././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-merge.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-merge.0000644000175000017500000000160010021673055033455 0ustar frankiefrankieGIF89a瀀€€€€€€€ÀÀÀÀÜÀ¦Êð@ ` €   À à @ @@@`@€@ @À@à@` `@```€` `À`à`€ €@€`€€€ €À€à€   @ ` €   À à À À@À`À€À ÀÀÀàÀà à@à`à€à àÀààà@ @@@`@€@ @À@à@ @ @@ @` @€ @  @À @à @@@ @@@@@`@@€@@ @@À@@à@@`@ `@@`@``@€`@ `@À`@à`@€@ €@@€@`€@€€@ €@À€@à€@ @  @@ @` @€ @  @À @à @À@ À@@À@`À@€À@ À@ÀÀ@àÀ@à@ à@@à@`à@€à@ à@Àà@àà@€ €@€`€€€ €À€à€ € €@ €` €€ €  €À €à €@€ @€@@€`@€€@€ @€À@€à@€`€ `€@`€``€€`€ `€À`€à`€€€ €€@€€`€€€€€ €€À€€à€€ €  €@ €` €€ €  €À €à €À€ À€@À€`À€€À€ À€ÀÀ€àÀ€à€ à€@à€`à€€à€ à€Àà€àà€À À@À`À€À ÀÀÀàÀ À À@ À` À€ À  ÀÀ Àà À@À @À@@À`@À€@À @ÀÀ@Àà@À`À `À@`À``À€`À `ÀÀ`Àà`À€À €À@€À`€À€€À €ÀÀ€Àà€À À  À@ À` À€ À  ÀÀ Àà ÀÀÀ ÀÀ@ÀÀ`ÀÀ€ÀÀ ÀÀÿûð  ¤€€€ÿÿÿÿÿÿÿÿÿÿÿÿ!ùý,]û H° ÁƒûXȰ¡Cüû'qâÄŠ!*¼h‘cGC2ŒxÑß?“(OžÉ1¥KŠ$)¾tÉ’¢Ê™02ĉ²¦Dž9+êÏçÍ£&AŠ ™°©Ó§P;././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-insert-above.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-insert-0000644000175000017500000000016410021673055033555 0ustar frankiefrankieGIF89aÂÿÿ„ကÿÿÿÿÿÿÿÿÿÿÿÿ!ù,9xºÜþ0Ej•ó08 HtFqžDYÄʶÑ!Ì4Ñu,ã‚ ½—Ø`Hô=ˆErht›º¨”‘;././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-delete.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-delete.0000644000175000017500000000015010021673055033507 0ustar frankiefrankieGIF89a¡ÿÿÿÿÿÿÿ!ù,9œ©Ë_¡Úæµ¹íÚ1Ñ( "éªb†p-»ðýÎzäøB|\žOh1<*~ʉó };././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-insert-before.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-insert0000644000175000017500000000016610021673055033612 0ustar frankiefrankieGIF89a€ကÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,;xºÜîàÉ"¹XÖJ†ðÄTÄ÷…"‰]ÊÊNm (LÌ4ܺ:9üƒÚ¤J\Æñ—t,ƒ=doJ•$;././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-insert-after.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-insert0000644000175000017500000000016610021673055033612 0ustar frankiefrankieGIF89a€ကÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,;xºÜþðIã"#bÖ\GUb`¡Eœh'!à2€ §M]c à9[¯º)l0fãúd€ãlJe$;././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-split.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-split.0000644000175000017500000000161310021673055033515 0ustar frankiefrankieGIF89a瀀€€€€€€€ÀÀÀÀÜÀ¦Êð@ ` €   À à @ @@@`@€@ @À@à@` `@```€` `À`à`€ €@€`€€€ €À€à€   @ ` €   À à À À@À`À€À ÀÀÀàÀà à@à`à€à àÀààà@ @@@`@€@ @À@à@ @ @@ @` @€ @  @À @à @@@ @@@@@`@@€@@ @@À@@à@@`@ `@@`@``@€`@ `@À`@à`@€@ €@@€@`€@€€@ €@À€@à€@ @  @@ @` @€ @  @À @à @À@ À@@À@`À@€À@ À@ÀÀ@àÀ@à@ à@@à@`à@€à@ à@Àà@àà@€ €@€`€€€ €À€à€ € €@ €` €€ €  €À €à €@€ @€@@€`@€€@€ @€À@€à@€`€ `€@`€``€€`€ `€À`€à`€€€ €€@€€`€€€€€ €€À€€à€€ €  €@ €` €€ €  €À €à €À€ À€@À€`À€€À€ À€ÀÀ€àÀ€à€ à€@à€`à€€à€ à€Àà€àà€À À@À`À€À ÀÀÀàÀ À À@ À` À€ À  ÀÀ Àà À@À @À@@À`@À€@À @ÀÀ@Àà@À`À `À@`À``À€`À `ÀÀ`Àà`À€À €À@€À`€À€€À €ÀÀ€Àà€À À  À@ À` À€ À  ÀÀ Àà ÀÀÀ ÀÀ@ÀÀ`ÀÀ€ÀÀ ÀÀÿûð  ¤€€€ÿÿÿÿÿÿÿÿÿÿÿÿ!ùý,hû H° ÁƒûXȰ¡Cüû'qâÄŠ!*¼h‘cGC2ŒxÑß?L¢T ’£I'ÿÁ4Ù’"›8sÉ0æL™1kP™òdQBu*J´éI¡>£ÒŒ(2d«X³j ;././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-insert-after.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-insert-0000644000175000017500000000015710021673055033525 0ustar frankiefrankieGIF89aÂက€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù,4xºÜþP‘A ¸$ÎzA†D(ŠQyf¬©²¾­/h<~&! ^N;Ÿf×kB19k;././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-insert-before.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-insert-0000644000175000017500000000015610021673055033524 0ustar frankiefrankieGIF89aÂကÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿ!ù,3xºÜþð@¸ ÎzE†@(ŠÎ=Cz2i»²ocÆÇø­!÷ié=ŽûyŠÃ mK;././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-prop.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-prop.gi0000644000175000017500000000022510021673055033550 0ustar frankiefrankieGIF89a¢€á€€ÀÀÀ3™ÌÌÌÿÿÿÿÿÿ!ù,ZxºÜî&ÊÀ;FèmêËÙ¦y („›'Eg‹v–1 íFƒ:ãûIﱡ@‰BƒÂ D›E%fE]¤†€vËÝ^—ݰö;­VȨ́ډ…ºÕX‚|N§cÍøC;././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-delete.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/col-delete.0000644000175000017500000000014410021673055033460 0ustar frankiefrankieGIF89a¡ÿÿÿÿÿÿÿ!ù,5œ©ËŸ/¦J§ÀàBLÜ”€f–D5Èv®¶óo7žî†à;}‚b‘x ƒÌ[;././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-prop.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-prop.g0000644000175000017500000000023310021673055033506 0ustar frankiefrankieGIF89a¢က€ÀÀÀ3™ÌÌÌÿÿÿÿÿÿ!ù,`xºÜî&ÊÂ;FèmêËÙ¦y („›'Eg‹v–1 íFƒ:ãûIﱡ@‰ÂFˆ42‹Ja%%X¯S…¡`x·G¨–뀟Iít…ÅÆÎx󽔇Ә¶þJ§ú© ;././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/table-prop.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/table-prop.0000644000175000017500000000022110021673055033504 0ustar frankiefrankieGIF89a¢€ÀÀÀ3™ÿÿÿÌÌÌÿÿÿ!ù,VhºÜî%JÀ3%è]êËÙ¦y „›'Eg‹vV! íF‚:ãûIï±a@‰Â‚¢ D›E%†@­Z­RæsëÌB¿Ûìu\õrÑ%ØÙ]’ÉÙ•|nH;././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-split.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/row-split.g0000644000175000017500000000157710021673055033565 0ustar frankiefrankieGIF89a瀀€€€€€€€ÀÀÀÀÜÀ¦Êð@ ` €   À à @ @@@`@€@ @À@à@` `@```€` `À`à`€ €@€`€€€ €À€à€   @ ` €   À à À À@À`À€À ÀÀÀàÀà à@à`à€à àÀààà@ @@@`@€@ @À@à@ @ @@ @` @€ @  @À @à @@@ @@@@@`@@€@@ @@À@@à@@`@ `@@`@``@€`@ `@À`@à`@€@ €@@€@`€@€€@ €@À€@à€@ @  @@ @` @€ @  @À @à @À@ À@@À@`À@€À@ À@ÀÀ@àÀ@à@ à@@à@`à@€à@ à@Àà@àà@€ €@€`€€€ €À€à€ € €@ €` €€ €  €À €à €@€ @€@@€`@€€@€ @€À@€à@€`€ `€@`€``€€`€ `€À`€à`€€€ €€@€€`€€€€€ €€À€€à€€ €  €@ €` €€ €  €À €à €À€ À€@À€`À€€À€ À€ÀÀ€àÀ€à€ à€@à€`à€€à€ à€Àà€àà€À À@À`À€À ÀÀÀàÀ À À@ À` À€ À  ÀÀ Àà À@À @À@@À`@À€@À @ÀÀ@Àà@À`À `À@`À``À€`À `ÀÀ`Àà`À€À €À@€À`€À€€À €ÀÀ€Àà€À À  À@ À` À€ À  ÀÀ Àà ÀÀÀ ÀÀ@ÀÀ`ÀÀ€ÀÀ ÀÀÿûð  ¤€€€ÿÿÿÿÿÿÿÿÿÿÿÿ!ùý,\û H° ÁƒûXȰ¡Cü›8Q"Å!*¼ˆ‘cƈC.Œèï_É“&M~܈²eGŒ ÈœI“ÀJ‰.Q6$™2çÍš@oæìy³§Ñ’7E†LÈ´©Ó§;././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-delete.gifopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/img/cell-delete0000644000175000017500000000014510021673055033545 0ustar frankiefrankieGIF89a¡ÿÿÿÿÿÿÿ!ù,6œ©ËÛ¡ µ8‰…Ñ | )Z–§ªvî$††9YWæèTãm*¿Æp— ò–̦¤;openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/0000755000175000017500000000000011724401447031615 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/da.js0000644000175000017500000000740110177203654032542 0ustar frankiefrankie// I18N constants // LANG: "da", ENCODING: UTF-8 | ISO-8859-1 // Author: Steen Sønderup, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Placer", "All four sides": "Alle fire sider", "Background": "Baggrund", "Baseline": "Bundlinie", "Border": "Kant", "Borders": "Kanter", "Bottom": "Bund", "CSS Style": "Stil [CSS]", "Caption": "Titel", "Cell Properties": "Celle egenskaber", "Center": "Centrer", "Char": "Plads", "Collapsed borders": "Sammensmelt rammer", "Color": "Farve", "Description": "Beskrivelse", "FG Color": "Font farve", "Float": "Justering", "Frames": "Udvendig", "Height": "Højde", "How many columns would you like to merge?": "Hvor mange kollonner vil du samle?", "How many rows would you like to merge?": "Hvor mange rækker vil du samle?", "Image URL": "Billede URL", "Justify": "Lige margener", "Layout": "Opsætning", "Left": "Venstre", "Margin": "Margen", "Middle": "Centrer", "No rules": "Ingen rammer", "No sides": "Ingen sider", "None": "Ingen", "Padding": "Margen", "Please click into some cell": "Klik pÃ¥ en celle", "Right": "Højre", "Row Properties": "Række egenskaber", "Rules will appear between all rows and columns": "Rammer mellem rækker og kolonner", "Rules will appear between columns only": "Kun rammer mellem kolonner", "Rules will appear between rows only": "Kun rammer mellem rækker", "Rules": "Invendig", "Spacing and padding": "Afstand og margen", "Spacing": "Afstand", "Summary": "Beskrivelse", "TO-cell-delete": "Slet celle", "TO-cell-insert-after": "Indsæt celle efter", "TO-cell-insert-before": "Indsæt celle før", "TO-cell-merge": "Sammensæt celler", "TO-cell-prop": "Celle egenskaber", "TO-cell-split": "Opdel celle", "TO-col-delete": "Slet kollonne", "TO-col-insert-after": "Indsæt kolonne efter", "TO-col-insert-before": "Indsæt kolonne før", "TO-col-split": "Opdel kolonne", "TO-row-delete": "Slet række", "TO-row-insert-above": "Indsæt række før", "TO-row-insert-under": "Indsæt række efter", "TO-row-prop": "Række egenskaber", "TO-row-split": "Opdel række", "TO-table-prop": "Tabel egenskaber", "Table Properties": "Tabel egenskaber", "Text align": "Tekst", "The bottom side only": "Kun i bunden", "The left-hand side only": "Kun i højre side", "The right and left sides only": "Kun i siderne", "The right-hand side only": "Kun i venstre side", "The top and bottom sides only": "Kun i top og bund", "The top side only": "Kun i toppen", "Top": "Top", "Unset color": "Farve ikke valgt", "Vertical align": "Vertikal placering", "Width": "Bredde", "not-del-last-cell": "Du kan ikke slette den sidste celle i en række.", "not-del-last-col": "Du kan ikke slette den sidste kolonne i en tabel.", "not-del-last-row": "Du kan ikke slette den sidste række i en tabel.", "percent": "procent", "pixels": "pixel" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/de.js0000644000175000017500000000736010177203654032552 0ustar frankiefrankie// I18N constants // LANG: "de", ENCODING: UTF-8 | ISO-8859-1 // Author: broxx, TableOperations.I18N = { "Align": "Ausrichten", "All four sides": "Alle 4 Seiten", "Background": "Hintergrund", "Baseline": "Basislinie", "Border": "Rand", "Borders": "Raender", "Bottom": "Unten", "CSS Style": "Style [CSS]", "Caption": "Ueberschrift", "Cell Properties": "Zellen", "Center": "Zentrieren", "Char": "Zeichen", "Collapsed borders": "Collapsed borders", "Color": "Farbe", "Description": "Beschreibung", "FG Color": "FG Farbe", "Float": "Ausrichtung", "Frames": "Rahmen", "Height": "Hoehe", "How many columns would you like to merge?": "Wieviele Spalten willst du verbinden?", "How many rows would you like to merge?": "Wieviele Zeilen willst du verbinden?", "Image URL": "Bild URL", "Justify": "Justieren", "Layout": "Layout", "Left": "Links", "Margin": "Rand", "Middle": "Mitte", "No rules": "Keine Balken", "No sides": "Keine Seiten", "None": "Keine", "Padding": "Auffuellung", "Please click into some cell": "Waehle eine Zelle", "Right": "Rechts", "Row Properties": "Reihen", "Rules will appear between all rows and columns": "Balken zwischen Reihen und Spalten", "Rules will appear between columns only": "Balken zwischen Spalten", "Rules will appear between rows only": "Balken zwischen Reihen", "Rules": "Balken", "Spacing and padding": "Abstaende", "Spacing": "Abstand", "Summary": "Zusammenfassung", "TO-cell-delete": "Zelle loeschen", "TO-cell-insert-after": "Zelle einfuegen nach", "TO-cell-insert-before": "Zelle einfuegen bevor", "TO-cell-merge": "Zellen zusammenfuegen", "TO-cell-prop": "Zelleinstellungen", "TO-cell-split": "Zellen aufteilen", "TO-col-delete": "Spalte loeschen", "TO-col-insert-after": "Spalte einfuegen nach", "TO-col-insert-before": "Spalte einfuegen bevor", "TO-col-split": "Spalte aufteilen", "TO-row-delete": "Reihe loeschen", "TO-row-insert-above": "Reihe einfuegen vor", "TO-row-insert-under": "Reihe einfuegen nach", "TO-row-prop": "Reiheneinstellungen", "TO-row-split": "Reihen aufteilen", "TO-table-prop": "Tabelle", "Table Properties": "Tabelle", "Text align": "Ausrichtung", "The bottom side only": "Nur untere Seite", "The left-hand side only": "Nur linke Seite", "The right and left sides only": "Nur linke und rechte Seite", "The right-hand side only": "Nur rechte Seite", "The top and bottom sides only": "Nur obere und untere Seite", "The top side only": "Nur obere Seite", "Top": "Oben", "Unset color": "Farbe", "Vertical align": "Ausrichtung", "Width": "Breite", "not-del-last-cell": "Letzte Zelle in dieser Reihe!", "not-del-last-col": "Letzte Spalte in dieser Tabelle!", "not-del-last-row": "Letzte Reihe in dieser Tabelle", "percent": "%", "pixels": "pixels" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/cz.js0000644000175000017500000001054610177203654032576 0ustar frankiefrankie// I18N constants // LANG: "cz", ENCODING: UTF-8 | ISO-8859-2 // Author: Jiri Löw, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Zarovnání", "All four sides": "VÅ¡echny ÄtyÅ™i strany", "Background": "Pozadí", "Baseline": "Základní linka", "Border": "Obrys", "Borders": "Obrysy", "Bottom": "Dolů", "CSS Style": "Kaskádové styly (CSS)", "Caption": "Titulek", "Cell Properties": "Vlastnosti buňky", "Center": "Na stÅ™ed", "Char": "Znak", "Collapsed borders": "StlaÄené okraje", "Color": "Barva", "Description": "Popis", "FG Color": "Barva popÅ™edí", "Float": "Obtékání", "Frames": "RámeÄky", "Height": "Výška", "How many columns would you like to merge?": "Kolik sloupců si pÅ™ejete spojit?", "How many rows would you like to merge?": "Kolik řádků si pÅ™ejete spojit?", "Image URL": "Adresa obrázku", "Justify": "Do stran", "Layout": "Rozložení", "Left": "Vlevo", "Margin": "Okraj", "Middle": "Na stÅ™ed", "No rules": "Žádné Äáry", "No sides": "Žádné strany", "None": "Žádné", "Padding": "Odsazování", "Please click into some cell": "Prosím kliknÄ›te do nÄ›které buňky", "Right": "Vpravo", "Row Properties": "Vlastnosti řádku", "Rules will appear between all rows and columns": "Čáry mezi vÅ¡emi řádky i sloupci", "Rules will appear between columns only": "Čáry pouze mezi sloupci", "Rules will appear between rows only": "Čáry pouze mezi řádky", "Rules": "Čáry", "Spacing and padding": "Mezery a odsazování", "Spacing": "Mezery", "Summary": "Shrnutí", "TO-cell-delete": "Smazat buňku", "TO-cell-insert-after": "Vložit buňku za", "TO-cell-insert-before": "Vložit buňku pÅ™ed", "TO-cell-merge": "Spojit buňky", "TO-cell-prop": "Vlastnosti buňky", "TO-cell-split": "RozdÄ›lit buňku", "TO-col-delete": "Smazat sloupec", "TO-col-insert-after": "Vložit sloupec za", "TO-col-insert-before": "Vložit sloupec pÅ™ed", "TO-col-split": "RozdÄ›lit sloupec", "TO-row-delete": "Smazat řádek", "TO-row-insert-above": "Smazat řádek nad", "TO-row-insert-under": "Smazat řádek pod", "TO-row-prop": "Vlastnosti řádku", "TO-row-split": "RozdÄ›lit řádek", "TO-table-prop": "Vlastnosti tabulky", "Table Properties": "Vlastnosti tabulky", "Text align": "Zarovnání textu", "The bottom side only": "Pouze spodní strana", "The left-hand side only": "Pouze levá strana", "The right and left sides only": "Pouze levá a pravá strana", "The right-hand side only": "Pouze pravá strana", "The top and bottom sides only": "Pouze horní a dolní strana", "The top side only": "Pouze horní strana", "Top": "Nahoru", "Unset color": "ZruÅ¡it barvu", "Vertical align": "Svislé zarovnání", "Width": "Šířka", "not-del-last-cell": "HTMLArea zbabÄ›le odmítá smazat poslední buňku v řádku.", "not-del-last-col": "HTMLArea zbabÄ›le odmítá smazat poslední sloupec v tabulce.", "not-del-last-row": "HTMLArea zbabÄ›le odmítá smazat poslední řádek v tabulce.", "percent": "procent", "pixels": "pixelů" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/el.js0000644000175000017500000001212110177203654032551 0ustar frankiefrankie// I18N constants // LANG: "el", ENCODING: UTF-8 | ISO-8859-7 // Author: Dimitris Glezos, dimitris@glezos.com TableOperations.I18N = { "Align": "Στοίχηση", "All four sides": "Και οι 4 πλευÏές", "Background": "Φόντο", "Baseline": "Baseline", "Border": "ΠεÏίγÏαμμα", "Borders": "ΠεÏιγÏάμματα", "Bottom": "Κάτω μέÏος", "CSS Style": "Στυλ [CSS]", "Caption": "Λεζάντα", "Cell Properties": "Ιδιότητες ΚελιοÏ", "Center": "ΚέντÏο", "Char": "ΧαÏακτήÏας", "Collapsed borders": "Συμπτυγμένα πεÏιγÏάμματα", "Color": "ΧÏώμα", "Description": "ΠεÏιγÏαφή", "FG Color": "ΧÏώμα αντικειμένων", "Float": "Float", "Frames": "Frames", "Height": "Ύψος", "How many columns would you like to merge?": "Πόσες στήλες θέλετε να ενώσετε;", "How many rows would you like to merge?": "Πόσες γÏαμμές θέλετε να ενώσετε;", "Image URL": "URL εικόνας", "Justify": "ΠλήÏης στοίχηση", "Layout": "Διάταξη", "Left": "ΑÏιστεÏά", "Margin": "ΠεÏιθώÏιο", "Middle": "ΚέντÏο", "No rules": "ΧωÏίς ΓÏαμμές", "No sides": "No sides", "None": "Τίποτα", "Padding": "Εσοχή", "Please click into some cell": "Κάντε κλικ μέσα σε κάποιο κελί", "Right": "Δεξιά", "Row Properties": "Ιδιότητες ΓÏαμμής", "Rules will appear between all rows and columns": "ΓÏαμμές θα εμφανίζονται Î¼ÎµÏ„Î±Î¾Ï ÏŒÎ»Ï‰Î½ των γÏαμμών και στηλών", "Rules will appear between columns only": "ΓÏαμμές θα εμφανίζονται μόνο Î¼ÎµÏ„Î±Î¾Ï ÏƒÏ„Î·Î»ÏŽÎ½", "Rules will appear between rows only": "ΓÏαμμές θα εμφανίζονται μόνο Î¼ÎµÏ„Î±Î¾Ï Î³Ïαμμών", "Rules": "ΓÏαμμές", "Spacing and padding": "Αποστάσεις και εσοχές", "Spacing": "Αποστάσεις", "Summary": "ΣÏνοψη", "TO-cell-delete": "ΔιαγÏαφή κελιοÏ", "TO-cell-insert-after": "Εισαγωγή ÎºÎµÎ»Î¹Î¿Ï Î¼ÎµÏ„Î¬", "TO-cell-insert-before": "Εισαγωγή ÎºÎµÎ»Î¹Î¿Ï Ï€Ïιν", "TO-cell-merge": "Συγχώνευση κελιών", "TO-cell-prop": "Ιδιότητες κελιοÏ", "TO-cell-split": "ΔιαίÏεση κελιοÏ", "TO-col-delete": "ΔιαγÏαφή στήλης", "TO-col-insert-after": "Εισαγωγή στήλης μετά", "TO-col-insert-before": "Εισαγωγή στήλης Ï€Ïιν", "TO-col-split": "ΔιαίÏεση στήλης", "TO-row-delete": "ΔιαγÏαφή γÏαμμής", "TO-row-insert-above": "Εισαγωγή γÏαμμής μετά", "TO-row-insert-under": "Εισαγωγή γÏαμμής Ï€Ïιν", "TO-row-prop": "Ιδιότητες γÏαμμής", "TO-row-split": "ΔιαίÏεση γÏαμμής", "TO-table-prop": "Ιδιότητες πίνακα", "Table Properties": "Ιδιότητες πίνακα", "Text align": "Στοίχηση κειμένου", "The bottom side only": "Η κάτω πλευÏά μόνο", "The left-hand side only": "Η αÏιστεÏή πλευÏά μόνο", "The right and left sides only": "Οι δεξιές και αÏιστεÏές πλευÏές μόνο", "The right-hand side only": "Η δεξιά πλευÏά μόνο", "The top and bottom sides only": "Οι πάνω και κάτω πλευÏές μόνο", "The top side only": "Η πάνω πλευÏά μόνο", "Top": "Πάνω", "Unset color": "ΑναίÏεση χÏώματος", "Vertical align": "ΚατακόÏυφη στοίχηση", "Width": "Πλάτος", "not-del-last-cell": "Δεν μποÏεί να διαγÏαφεί το τελευταίο κελί σε μια γÏαμμή.", "not-del-last-col": "Δεν μποÏεί να διαγÏαφεί η τελευταία στήλη σε ένα πίνακα.", "not-del-last-row": "Δεν μποÏεί να διαγÏαφεί η τελευταία γÏαμμή σε ένα πίνακα.", "percent": "τοις εκατόν", "pixels": "pixels" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/en.js0000644000175000017500000001023010177203654032552 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Align", "All four sides": "All four sides", "Background": "Background", "Baseline": "Baseline", "Border": "Border", "Borders": "Borders", "Bottom": "Bottom", "CSS Style": "Style [CSS]", "Caption": "Caption", "Cell Properties": "Cell Properties", "Center": "Center", "Char": "Char", "Collapsed borders": "Collapsed borders", "Color": "Color", "Description": "Description", "FG Color": "FG Color", "Float": "Float", "Frames": "Frames", "Height": "Height", "How many columns would you like to merge?": "How many columns would you like to merge?", "How many rows would you like to merge?": "How many rows would you like to merge?", "Image URL": "Image URL", "Justify": "Justify", "Layout": "Layout", "Left": "Left", "Margin": "Margin", "Middle": "Middle", "No rules": "No rules", "No sides": "No sides", "None": "None", "Padding": "Padding", "Please click into some cell": "Please click into some cell", "Right": "Right", "Row Properties": "Row Properties", "Rules will appear between all rows and columns": "Rules will appear between all rows and columns", "Rules will appear between columns only": "Rules will appear between columns only", "Rules will appear between rows only": "Rules will appear between rows only", "Rules": "Rules", "Spacing and padding": "Spacing and padding", "Spacing": "Spacing", "Summary": "Summary", "TO-cell-delete": "Delete cell", "TO-cell-insert-after": "Insert cell after", "TO-cell-insert-before": "Insert cell before", "TO-cell-merge": "Merge cells", "TO-cell-prop": "Cell properties", "TO-cell-split": "Split cell", "TO-col-delete": "Delete column", "TO-col-insert-after": "Insert column after", "TO-col-insert-before": "Insert column before", "TO-col-split": "Split column", "TO-row-delete": "Delete row", "TO-row-insert-above": "Insert row before", "TO-row-insert-under": "Insert row after", "TO-row-prop": "Row properties", "TO-row-split": "Split row", "TO-table-prop": "Table properties", "Table Properties": "Table Properties", "Text align": "Text align", "The bottom side only": "The bottom side only", "The left-hand side only": "The left-hand side only", "The right and left sides only": "The right and left sides only", "The right-hand side only": "The right-hand side only", "The top and bottom sides only": "The top and bottom sides only", "The top side only": "The top side only", "Top": "Top", "Unset color": "Unset color", "Vertical align": "Vertical align", "Width": "Width", "not-del-last-cell": "HTMLArea cowardly refuses to delete the last cell in row.", "not-del-last-col": "HTMLArea cowardly refuses to delete the last column in table.", "not-del-last-row": "HTMLArea cowardly refuses to delete the last row in table.", "percent": "percent", "pixels": "pixels" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/fi.js0000644000175000017500000000602110177203654032551 0ustar frankiefrankieTableOperations.I18N = { "Align": "Kohdistus", "All four sides": "Kaikki neljä sivua", "Background": "Tausta", "Baseline": "Takaraja", "Border": "Reuna", "Borders": "Reunat", "Bottom": "Alle", "CSS Style": "Tyyli [CSS]", "Caption": "Otsikko", "Cell Properties": "Solun asetukset", "Center": "Keskelle", "Char": "Merkki", "Collapsed borders": "Luhistetut reunat", "Color": "Väri", "Description": "Kuvaus", "FG Color": "FG Väri", "Frames": "Kehykset", "Image URL": "Kuvan osoite", "Layout": "Sommittelu", "Left": "Vasen", "Margin": "Marginaali", "Middle": "Keskelle", "No rules": "Ei viivoja", "No sides": "Ei sivuja", "Padding": "Palstantäyte", "Right": "Oikea", "Row Properties": "Rivin asetukset", "Rules will appear between all rows and columns": "Viivat jokaisen rivin ja sarakkeen välillä", "Rules will appear between columns only": "Viivat ainoastaan sarakkeiden välillä", "Rules will appear between rows only": "Viivat ainoastaan rivien välillä", "Rules": "Viivat", "Spacing": "Palstatila", "Summary": "Yhteenveto", "TO-cell-delete": "Poista solu", "TO-cell-insert-after": "Lisää solu perään", "TO-cell-insert-before": "Lisää solu ennen", "TO-cell-merge": "Yhdistä solut", "TO-cell-prop": "Solun asetukset", "TO-cell-split": "Jaa solu", "TO-col-delete": "Poista sarake", "TO-col-insert-after": "Lisää sarake perään", "TO-col-insert-before": "Lisää sarake ennen", "TO-col-split": "Jaa sarake", "TO-row-delete": "Poista rivi", "TO-row-insert-above": "Lisää rivi yläpuolelle", "TO-row-insert-under": "Lisää rivi alapuolelle", "TO-row-prop": "Rivin asetukset", "TO-row-split": "Jaa rivi", "TO-table-prop": "Taulukon asetukset", "Top": "Ylös", "Table Properties": "Taulukon asetukset", "The bottom side only": "Ainoastaan alapuolelle", "The left-hand side only": "Ainoastaan vasenreuna", "The right and left sides only": "Oikea- ja vasenreuna", "The right-hand side only": "Ainoastaan oikeareuna", "The top and bottom sides only": "Ylä- ja alapuoli.", "The top side only": "Ainoastaan yläpuoli", "Vertical align": "Vertikaali kohdistus", "Width": "Leveys", "not-del-last-cell": "Ei voida poistaa viimeistä solua rivistä.", "not-del-last-col": "Ei voida poistaa viimeistä saraketta taulusta.", "not-del-last-row": "Ei voida poistaa viimeistä riviä taulusta.", "percent": "prosenttia", "pixels": "pikseliä" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/fr.js0000644000175000017500000001075010177203654032566 0ustar frankiefrankie// I18N constants // LANG: "fr", ENCODING: UTF-8 | ISO-8859-1 // Author: Cédric Guillemette, http://www.ebdata.com // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Aligner", "All four sides": "Quatre cotés", "Background": "Arrière plan", "Baseline": "Ligne de base", "Border": "Bordure", "Borders": "Bordures", "Bottom": "Bas", "CSS Style": "Style [CSS]", "Caption": "Étiquette", "Cell Properties": "Propriétés de cellule", "Center": "Centre", "Char": "Charactère", "Collapsed borders": "Bordure effondrés", "Color": "Couleur", "Description": "Description", "FG Color": "Couleur de face", "Float": "Flotteur", "Frames": "Vues", "Height": "Largeur", "How many columns would you like to merge?": "Combien de colonnes voulez-vous fusionner?", "How many rows would you like to merge?": "Combien de rangées voulez-vous fusionner?", "Image URL": "URL pour l'image", "Justify": "Justifié", "Layout": "Arrangement", "Left": "Gauche", "Margin": "Marge", "Middle": "Milieu", "No rules": "Aucun règlement", "No sides": "Aucun côtés", "None": "Aucun", "Padding": "Remplissage", "Please click into some cell": "Cliquer sur une cellule", "Right": "Droit", "Row Properties": "Propriétés de rangée", "Rules will appear between all rows and columns": "Les règles vont apparaître entre les rangées et les cellules", "Rules will appear between columns only": "Les règles vont apparaître entre les colonnes seulement", "Rules will appear between rows only": "Les règles vont apparaître entre les rangées seulement", "Rules": "Les règles", "Spacing and padding": "Espacement et remplissage", "Spacing": "Espacement", "Summary": "Sommaire", "TO-cell-delete": "Supprimer une cellule", "TO-cell-insert-after": "Insérer une cellule après", "TO-cell-insert-before": "Insérer une cellule avant", "TO-cell-merge": "Fusionner les cellules", "TO-cell-prop": "Cell properties", "TO-cell-split": "Diviser la cellule", "TO-col-delete": "Supprimer la colonne", "TO-col-insert-after": "Insérer une colonne après", "TO-col-insert-before": "Insérer une colonne avant", "TO-col-split": "Diviser une colonne", "TO-row-delete": "Supprimer une rangée", "TO-row-insert-above": "Insérer une rangée avant", "TO-row-insert-under": "Insérer une rangée après", "TO-row-prop": "Propriétés de rangée", "TO-row-split": "Diviser la rangée", "TO-table-prop": "Propriétés de table", "Table Properties": "Propriétés de table", "Text align": "Aligner le texte", "The bottom side only": "Côté du bas seulement", "The left-hand side only": "Côté gauche seulement", "The right and left sides only": "Côté gauche et droit seulement", "The right-hand side only": "Côté droit seulement", "The top and bottom sides only": "Côté haut et bas seulement", "The top side only": "Côté haut seulement", "Top": "Haut", "Unset color": "Enlever la couleur", "Vertical align": "Alignement vertical", "Width": "Longeur", "not-del-last-cell": "HTMLArea refuse de supprimer la dernière cellule de la rangée.", "not-del-last-col": "HTMLArea refuse de supprimer la dernière colonne de la table.", "not-del-last-row": "HTMLArea refuse de supprimer la dernière rangée de la table", "percent": "pourcentage", "pixels": "pixels" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/he.js0000644000175000017500000001132610177203654032553 0ustar frankiefrankie// I18N constants // LANG: "he", ENCODING: UTF-8 // Author: Liron Newman, http://www.eesh.net, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "ישור", "All four sides": "כל ×רבעת הצדדי×", "Background": "רקע", "Baseline": "קו בסיס", "Border": "גבול", "Borders": "גבולות", "Bottom": "תחתון", "CSS Style": "סגנון [CSS]", "Caption": "כותרת", "Cell Properties": "מ×פייני ת×", "Center": "מרכז", "Char": "תו", "Collapsed borders": "גבולות קורסי×", "Color": "צבע", "Description": "תי×ור", "FG Color": "צבע קידמה", "Float": "מרחף", "Frames": "מסגרות", "Height": "גובה", "How many columns would you like to merge?": "כמה ×˜×•×¨×™× ×‘×¨×¦×•× ×š למזג?", "How many rows would you like to merge?": "כמה שורות ברצונך למזג?", "Image URL": "URL התמונה", "Justify": "ישור", "Layout": "פריסה", "Left": "שמ×ל", "Margin": "שוליי×", "Middle": "×מצע", "No rules": "×œ×œ× ×§×•×•×™×", "No sides": "×œ×œ× ×¦×“×“×™×", "None": "×ין", "Padding": "ריווח בשוליי×", "Please click into some cell": "×× × ×œ×—×¥ על ×ª× ×›×œ×©×”×•", "Right": "ימין", "Row Properties": "מ×פייני שורה", "Rules will appear between all rows and columns": "×§×•×•×™× ×™×•×¤×™×¢×• בין כל השורות והטורי×", "Rules will appear between columns only": "×§×•×•×™× ×™×•×¤×™×¢×• בין ×˜×•×¨×™× ×‘×œ×‘×“", "Rules will appear between rows only": "×§×•×•×™× ×™×•×¤×™×¢×• בין שורות בלבד", "Rules": "קווי×", "Spacing and padding": "ריווח ושוליי×", "Spacing": "ריווח", "Summary": "סיכו×", "TO-cell-delete": "מחק ת×", "TO-cell-insert-after": "הכנס ×ª× ×חרי", "TO-cell-insert-before": "הכנס ×ª× ×œ×¤× ×™", "TO-cell-merge": "מזג ת××™×", "TO-cell-prop": "מ×פייני ת×", "TO-cell-split": "פצל ת×", "TO-col-delete": "מחק טור", "TO-col-insert-after": "הכנס טור ×חרי", "TO-col-insert-before": "הכנס טור לפני", "TO-col-split": "פצל טור", "TO-row-delete": "מחק שורה", "TO-row-insert-above": "הכנס שורה לפני", "TO-row-insert-under": "הכנס שורה ×חרי", "TO-row-prop": "מ×פייני שורה", "TO-row-split": "פצל שורה", "TO-table-prop": "מ×פייני טבלה", "Table Properties": "מ×פייני טבלה", "Text align": "ישור טקסט", "The bottom side only": "הצד התחתון בלבד", "The left-hand side only": "הצד השמ×לי בלבד", "The right and left sides only": "×”×¦×“×“×™× ×”×™×ž× ×™ והשמ×לי בלבד", "The right-hand side only": "הצד הימני בלבד", "The top and bottom sides only": "×”×¦×“×“×™× ×”×¢×œ×™×•×Ÿ והתחתון בלבד", "The top side only": "הצד העליון בלבד", "Top": "עליון", "Unset color": "צבע ×œ× × ×‘×—×¨", "Vertical align": "יישור ×× ×›×™", "Width": "רוחב", "not-del-last-cell": "HTMLArea מסרב בפחדנות למחוק ×ת ×”×ª× ×”×חרון בשורה.", "not-del-last-col": "HTMLArea מסרב בפחדנות למחוק ×ת הטור ×”×חרון בטבלה.", "not-del-last-row": "HTMLArea מסרב בפחדנות למחוק ×ת השורה ×”×חרונה בטבלה.", "percent": "×חוז", "pixels": "פיקסלי×" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/hu.js0000644000175000017500000000353510177203654032576 0ustar frankiefrankie// I18N constants // LANG: "hu", ENCODING: UTF-8 // Author: Miklós Somogyi, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HTMLArea.I18N = { // the following should be the filename without .js extension // it will be used for automatically load plugin language. lang: "hu", tooltips: { bold: "Félkövér", italic: "DÅ‘lt", underline: "Aláhúzott", strikethrough: "Ãthúzott", subscript: "Alsó index", superscript: "FelsÅ‘ index", justifyleft: "Balra zárt", justifycenter: "Középre zárt", justifyright: "Jobbra zárt", justifyfull: "Sorkizárt", orderedlist: "Számozott lista", unorderedlist: "Számozatlan lista", outdent: "Behúzás csökkentése", indent: "Behúzás növelése", forecolor: "Karakterszín", hilitecolor: "Háttérszín", horizontalrule: "Elválasztó vonal", createlink: "Hiperhivatkozás beszúrása", insertimage: "Kép beszúrása", inserttable: "Táblázat beszúrása", htmlmode: "HTML forrás be/ki", popupeditor: "SzerkesztÅ‘ külön ablakban", about: "Névjegy", showhelp: "Súgó", textindicator: "Aktuális stílus", undo: "Visszavonás", redo: "Újra végrehajtás", cut: "Kivágás", copy: "Másolás", paste: "Beillesztés" }, buttons: { "ok": "Rendben", "cancel": "Mégsem" }, msg: { "Path": "Hierarchia", "TEXT_MODE": "Forrás mód. Visszaváltás [<>] gomb" } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/it.js0000644000175000017500000001004410177203654032567 0ustar frankiefrankie// I18N constants // LANG: "it", ENCODING: UTF-8 | ISO-8859-1 // Author: Fabio Rotondo TableOperations.I18N = { "Align": "Allinea", "All four sides": "Tutti e quattro i lati", "Background": "Sfondo", "Baseline": "Allineamento", "Border": "Bordo", "Borders": "Bordi", "Bottom": "Basso", "CSS Style": "Stile [CSS]", "Caption": "Titolo", "Cell Properties": "Proprietà della Cella", "Center": "Centra", "Char": "Carattere", "Collapsed borders": "Bordi chiusi", "Color": "Colore", "Description": "Descrizione", "FG Color": "Colore Principale", "Float": "Fluttuante", "Frames": "Frames", "Height": "Altezza", "How many columns would you like to merge?": "Quante colonne vuoi unire?", "How many rows would you like to merge?": "Quante righe vuoi unire?", "Image URL": "URL dell'Immagine", "Justify": "Justifica", "Layout": "Layout", "Left": "Sinistra", "Margin": "Margine", "Middle": "Centrale", "No rules": "Nessun righello", "No sides": "Nessun lato", "None": "Nulla", "Padding": "Padding", "Please click into some cell": "Per favore, clicca in una cella", "Right": "Destra", "Row Properties": "Proprietà della Riga", "Rules will appear between all rows and columns": "Le linee appariranno tra tutte le righe e colonne", "Rules will appear between columns only": "Le linee appariranno solo tra le colonne", "Rules will appear between rows only": "Le linee appariranno solo tra le righe", "Rules": "Linee", "Spacing and padding": "Spaziatura e Padding", "Spacing": "Spaziatura", "Summary": "Sommario", "TO-cell-delete": "Cancella cella", "TO-cell-insert-after": "Inserisci cella dopo", "TO-cell-insert-before": "Inserisci cella prima", "TO-cell-merge": "Unisci celle", "TO-cell-prop": "Proprietà della cella", "TO-cell-split": "Dividi cella", "TO-col-delete": "Cancella colonna", "TO-col-insert-after": "Inserisci colonna dopo", "TO-col-insert-before": "Inserisci colonna prima", "TO-col-split": "Dividi colonna", "TO-row-delete": "Cancella riga", "TO-row-insert-above": "Inserisci riga prima", "TO-row-insert-under": "Inserisci riga dopo", "TO-row-prop": "Proprietà della riga", "TO-row-split": "Dividi riga", "TO-table-prop": "Proprietà della Tabella", "Table Properties": "Proprietà della Tabella", "Text align": "Allineamento del Testo", "The bottom side only": "Solo la parte inferiore", "The left-hand side only": "Solo la parte sinistra", "The right and left sides only": "Solo destra e sinistra", "The right-hand side only": "Solo la parte destra", "The top and bottom sides only": "Solo sopra e sotto", "The top side only": "Solo la parte sopra", "Top": "Alto", "Unset color": "Rimuovi colore", "Vertical align": "Allineamento verticale", "Width": "Larghezza", "not-del-last-cell": "HTMLArea si rifiuta codardamente di cancellare l'ultima cella nella riga.", "not-del-last-col": "HTMLArea si rifiuta codardamente di cancellare l'ultima colonna nella tabella.", "not-del-last-row": "HTMLArea si rifiuta codardamente di cancellare l'ultima riga nella tabella.", "percent": "percento", "pixels": "pixels" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/nl.js0000644000175000017500000001014310177203654032564 0ustar frankiefrankie// I18N constants // LANG: "nl", ENCODING: UTF-8 | ISO-8859-1 // Author: Michel Weegeerink (info@mmc-shop.nl), http://mmc-shop.nl // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Uitlijning", "All four sides": "Alle 4 zijden", "Background": "Achtergrond", "Baseline": "Basis", "Border": "Rand", "Borders": "Randen", "Bottom": "Onder", "CSS Style": "CSS Style", "Caption": "Opmerking", "Cell Properties": "Celeigenschappen", "Center": "Centreren", "Char": "Karakter", "Collapsed borders": "Geen randen", "Color": "Kleur", "Description": "Omschrijving", "FG Color": "Voorgrond", "Float": "Zwevend", "Frames": "Frames", "Height": "Hoogte", "How many columns would you like to merge?": "Hoeveel kolommen wilt u samenvoegen?", "How many rows would you like to merge?": "Hoeveel rijen wilt u samenvoegen?", "Image URL": "Afbeelding URL", "Justify": "Uitvullen", "Layout": "Opmaak", "Left": "Links", "Margin": "Marge", "Middle": "Midden", "No rules": "Geen regels", "No sides": "Geen zijlijnen", "None": "Geen", "Padding": "Celmarge", "Please click into some cell": "Klik in een cel a.u.b.", "Right": "Rechts", "Row Properties": "Rijeigenschappen", "Rules will appear between all rows and columns": "Regels verschijnen tussen alle rijen en kolommen", "Rules will appear between columns only": "Regels verschijnen enkel tussen de kolommen", "Rules will appear between rows only": "Regels verschijnen enkel tussen de rijen", "Rules": "Regels", "Spacing and padding": "Celmarge en afstand tussen cellen", "Spacing": "marge", "Summary": "Overzicht", "TO-cell-delete": "Cel verwijderen", "TO-cell-insert-after": "Voeg cel toe achter", "TO-cell-insert-before": "Voeg cel toe voor", "TO-cell-merge": "Cellen samenvoegen", "TO-cell-prop": "Celeigenschappen", "TO-cell-split": "Cel splitsen", "TO-col-delete": "Kolom verwijderen", "TO-col-insert-after": "Kolom invoegen achter", "TO-col-insert-before": "Kolom invoegen voor", "TO-col-split": "Kolom splitsen", "TO-row-delete": "Rij verwijderen", "TO-row-insert-above": "Rij invoegen boven", "TO-row-insert-under": "Rij invoegen onder", "TO-row-prop": "Rij eigenschappen", "TO-row-split": "Rij splitsen", "TO-table-prop": "Tabel eigenschappen", "Table Properties": "Tabel eigenschappen", "Text align": "Text uitlijning", "The bottom side only": "Enkel aan de onderkant", "The left-hand side only": "Enkel aan de linkerkant", "The right and left sides only": "Enkel aan de linker en rechterkant", "The right-hand side only": "Enkel aan de rechterkant", "The top and bottom sides only": "Enkel aan de bovenen onderkant", "The top side only": "Enkel aan de bovenkant", "Top": "Boven", "Unset color": "Wis kleur", "Vertical align": "Vertikale uitlijning", "Width": "Breedte", "not-del-last-cell": "HTMLArea kan de laatste cel in deze tabel niet verwijderen.", "not-del-last-col": "HTMLArea kan de laatste kolom in deze tabel niet verwijderen.", "not-del-last-row": "HTMLArea kan de laatste rij in deze tabel niet verwijderen.", "percent": "procent", "pixels": "pixels" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/no.js0000644000175000017500000000763610177203654032604 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, // translated into Norwegia: ses@online.no 11.11.03 // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Juster", "All four sides": "Alle fire sider", "Background": "Bakgrund", "Baseline": "Grunnlinje", "Border": "Kantlinje", "Borders": "Kantlinjer", "Bottom": "Bunn", "CSS Style": "Stil [CSS]", "Caption": "Overskrift", "Cell Properties": "Celleegenskaper", "Center": "Sentrer", "Char": "Tegn", "Collapsed borders": "Fjern kantlinjer", "Color": "Farge", "Description": "Beskrivelse", "FG Color": "FG farge", "Float": "Flytende", "Frames": "rammer", "Height": "Høyde", "How many columns would you like to merge?": "Hvor mange kolonner vil du slå sammen?", "How many rows would you like to merge?": "Hvor mange rader vil du slå sammen?", "Image URL": "Bildets URL", "Justify": "Juster", "Layout": "Layout", "Left": "Venstre", "Margin": "Marg", "Middle": "Midten", "No rules": "Ingen linjal", "No sides": "Ingen sider", "None": "Ingen", "Padding": "Luft", "Please click into some cell": "Klikk i en eller annen celle", "Right": "Høyre", "Row Properties": "Egenskaper for rad", "Rules will appear between all rows and columns": "Linjer vil synes mellom alle rader og kolonner", "Rules will appear between columns only": "Linjer vil synes kun mellom kolonner", "Rules will appear between rows only": "Linjer vil synes kun mellom rader", "Rules": "Linjer", "Spacing and padding": "Luft", "Spacing": "Luft", "Summary": "Sammendrag", "TO-cell-delete": "Slett celle", "TO-cell-insert-after": "Sett inn celle etter", "TO-cell-insert-before": "Sett inn celle foran", "TO-cell-merge": "Slå sammen celler", "TO-cell-prop": "Egenskaper for celle", "TO-cell-split": "Del celle", "TO-col-delete": "Slett kolonne", "TO-col-insert-after": "Skyt inn kolonne etter", "TO-col-insert-before": "Skyt inn kolonne før", "TO-col-split": "Del kolonne", "TO-row-delete": "Slett rad", "TO-row-insert-above": "Skyt inn rad foran", "TO-row-insert-under": "Skyt inn rad etter", "TO-row-prop": "Egenskaper for rad", "TO-row-split": "Del rad", "TO-table-prop": "Tabellegenskaper", "Table Properties": "Tabellegenskaper", "Text align": "Juster tekst", "The bottom side only": "Bunnen kun", "The left-hand side only": "Venstresiden kun", "The right and left sides only": "Høyre- og venstresiden kun", "The right-hand side only": "Høyresiden kun", "The top and bottom sides only": "The top and bottom sides only", "The top side only": "Overkanten kun", "Top": "Overkant", "Unset color": "Ikke-bestemt farge", "Vertical align": "Vertikal justering", "Width": "Bredde", "not-del-last-cell": "HTMLArea nekter å slette siste cellen i tabellen.", "not-del-last-col": "HTMLArea nekter å slette siste kolonnen i tabellen.", "not-del-last-row": "HTMLArea nekter å slette siste raden i tabellen.", "percent": "prosent", "pixels": "billedpunkter" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/lang/ro.js0000644000175000017500000001060510177203654032576 0ustar frankiefrankie// I18N constants // LANG: "ro", ENCODING: UTF-8 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) TableOperations.I18N = { "Align": "Aliniere", "All four sides": "Toate părÅ£ile", "Background": "Fundal", "Baseline": "Baseline", "Border": "Chenar", "Borders": "Chenare", "Bottom": "Jos", "CSS Style": "Stil [CSS]", "Caption": "Titlu de tabel", "Cell Properties": "Proprietăţile celulei", "Center": "Centru", "Char": "Caracter", "Collapsed borders": "Chenare asimilate", "Color": "Culoare", "Description": "Descriere", "FG Color": "Culoare text", "Float": "PoziÅ£ie", "Frames": "Chenare", "Height": "ÃŽnălÅ£imea", "How many columns would you like to merge?": "Câte coloane vrei să uneÅŸti?", "How many rows would you like to merge?": "Câte linii vrei să uneÅŸti?", "Image URL": "URL-ul imaginii", "Justify": "Justify", "Layout": "Aranjament", "Left": "Stânga", "Margin": "Margine", "Middle": "Mijloc", "No rules": "Fără linii", "No sides": "Fără părÅ£i", "None": "Nimic", "Padding": "SpaÅ£iere", "Please click into some cell": "Vă rog să daÅ£i click într-o celulă", "Right": "Dreapta", "Row Properties": "Proprietăţile liniei", "Rules will appear between all rows and columns": "Vor apărea linii între toate rândurile ÅŸi coloanele", "Rules will appear between columns only": "Vor apărea doar linii verticale", "Rules will appear between rows only": "Vor apărea doar linii orizontale", "Rules": "Linii", "Spacing and padding": "SpaÅ£ierea", "Spacing": "ÃŽntre celule", "Summary": "Sumar", "TO-cell-delete": "Åžterge celula", "TO-cell-insert-after": "Inserează o celulă la dreapta", "TO-cell-insert-before": "Inserează o celulă la stânga", "TO-cell-merge": "UneÅŸte celulele", "TO-cell-prop": "Proprietăţile celulei", "TO-cell-split": "ÃŽmparte celula", "TO-col-delete": "Åžterge coloana", "TO-col-insert-after": "Inserează o coloană la dreapta", "TO-col-insert-before": "Inserează o coloană la stânga", "TO-col-split": "ÃŽmparte coloana", "TO-row-delete": "Åžterge rândul", "TO-row-insert-above": "Inserează un rând înainte", "TO-row-insert-under": "Inserează un rând după", "TO-row-prop": "Proprietăţile rândului", "TO-row-split": "ÃŽmparte rândul", "TO-table-prop": "Proprietăţile tabelei", "Table Properties": "Proprietăţile tabelei", "Text align": "Aliniere", "The bottom side only": "Doar partea de jos", "The left-hand side only": "Doar partea din stânga", "The right and left sides only": "Partea din stânga ÅŸi cea din dreapta", "The right-hand side only": "Doar partea din dreapta", "The top and bottom sides only": "Partea de sus si cea de jos", "The top side only": "Doar partea de sus", "Top": "Sus", "Unset color": "Dezactivează culoarea", "Vertical align": "Aliniere pe verticală", "Width": "Lăţime", "not-del-last-cell": "HTMLArea refuză cu laÅŸitate să ÅŸteargă ultima celulă din rând.", "not-del-last-col": "HTMLArea refuză cu laÅŸitate să ÅŸteargă ultima coloamă din tabela.", "not-del-last-row": "HTMLArea refuză cu laÅŸitate să ÅŸteargă ultimul rând din tabela.", "percent": "procente", "pixels": "pixeli" }; ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/table-operations.jsopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/TableOperations/table-operation0000644000175000017500000010235010177203654033706 0ustar frankiefrankie// Table Operations Plugin for HTMLArea-3.0 // Implementation by Mihai Bazon. Sponsored by http://www.zapatec.com // // Copyright (c) dynarch.com 2003-2005 // This copyright notice must stay intact for use. // // $Id: table-operations.js,v 1.2 2005/01/30 16:13:32 jeffd Exp $ // Object that will encapsulate all the table operations provided by // HTMLArea-3.0 (except "insert table" which is included in the main file) function TableOperations(editor) { this.editor = editor; var cfg = editor.config; var tt = TableOperations.I18N; var bl = TableOperations.btnList; var self = this; // register the toolbar buttons provided by this plugin var toolbar = ["linebreak"]; for (var i = 0; i < bl.length; ++i) { var btn = bl[i]; if (!btn) { toolbar.push("separator"); } else { var id = "TO-" + btn[0]; cfg.registerButton(id, tt[id], editor.imgURL(btn[0] + ".gif", "TableOperations"), false, function(editor, id) { // dispatch button press event self.buttonPress(editor, id); }, btn[1]); toolbar.push(id); } } // add a new line in the toolbar cfg.toolbar.push(toolbar); }; TableOperations._pluginInfo = { name : "TableOperations", version : "1.0", developer : "Mihai Bazon", developer_url : "http://dynarch.com/mishoo/", c_owner : "Mihai Bazon", sponsor : "Zapatec Inc.", sponsor_url : "http://www.bloki.com", license : "htmlArea" }; /************************ * UTILITIES ************************/ // retrieves the closest element having the specified tagName in the list of // ancestors of the current selection/caret. TableOperations.prototype.getClosest = function(tagName) { var editor = this.editor; var ancestors = editor.getAllAncestors(); var ret = null; tagName = ("" + tagName).toLowerCase(); for (var i = 0; i < ancestors.length; ++i) { var el = ancestors[i]; if (el.tagName.toLowerCase() == tagName) { ret = el; break; } } return ret; }; // this function requires the file PopupDiv/PopupWin to be loaded from browser TableOperations.prototype.dialogTableProperties = function() { var i18n = TableOperations.I18N; // retrieve existing values var table = this.getClosest("table"); // this.editor.selectNodeContents(table); // this.editor.updateToolbar(); var dialog = new PopupWin(this.editor, i18n["Table Properties"], function(dialog, params) { TableOperations.processStyle(params, table); for (var i in params) { var val = params[i]; switch (i) { case "f_caption": if (/\S/.test(val)) { // contains non white-space characters var caption = table.getElementsByTagName("caption")[0]; if (!caption) { caption = dialog.editor._doc.createElement("caption"); table.insertBefore(caption, table.firstChild); } caption.innerHTML = val; } else { // search for caption and delete it if found var caption = table.getElementsByTagName("caption")[0]; if (caption) { caption.parentNode.removeChild(caption); } } break; case "f_summary": table.summary = val; break; case "f_width": table.style.width = ("" + val) + params.f_unit; break; case "f_align": table.align = val; break; case "f_spacing": table.cellSpacing = val; break; case "f_padding": table.cellPadding = val; break; case "f_borders": table.border = val; break; case "f_frames": table.frame = val; break; case "f_rules": table.rules = val; break; } } // various workarounds to refresh the table display (Gecko, // what's going on?! do not disappoint me!) dialog.editor.forceRedraw(); dialog.editor.focusEditor(); dialog.editor.updateToolbar(); var save_collapse = table.style.borderCollapse; table.style.borderCollapse = "collapse"; table.style.borderCollapse = "separate"; table.style.borderCollapse = save_collapse; }, // this function gets called when the dialog needs to be initialized function (dialog) { var f_caption = ""; var capel = table.getElementsByTagName("caption")[0]; if (capel) { f_caption = capel.innerHTML; } var f_summary = table.summary; var f_width = parseInt(table.style.width); isNaN(f_width) && (f_width = ""); var f_unit = /%/.test(table.style.width) ? 'percent' : 'pixels'; var f_align = table.align; var f_spacing = table.cellSpacing; var f_padding = table.cellPadding; var f_borders = table.border; var f_frames = table.frame; var f_rules = table.rules; function selected(val) { return val ? " selected" : ""; }; // dialog contents dialog.content.style.width = "400px"; dialog.content.innerHTML = " \
    " + i18n["Table Properties"] + "\
    \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
    \
    " + i18n["Description"] + " \ \ \ \ \ \ \ \ \
    " + i18n["Caption"] + ":
    " + i18n["Summary"] + ":
    \
    \
    \
    " + i18n["Spacing and padding"] + " \ \ \ \ \ \
    " + i18n["Spacing"] + ":  " + i18n["Padding"] + ":\   " + i18n["pixels"] + "\
    \
    \
    \
    Frame and borders \ \ \ \ \ \ \ \ \ \ \ \ \ \
    " + i18n["Borders"] + ":   " + i18n["pixels"] + "
    " + i18n["Frames"] + ": \ \
    " + i18n["Rules"] + ": \ \
    \
    \
    \ "; var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, table); var p = dialog.doc.getElementById("--HA-style"); p.appendChild(st_prop); var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, table); p = dialog.doc.getElementById("--HA-layout"); p.appendChild(st_layout); dialog.modal = true; dialog.addButtons("ok", "cancel"); dialog.showAtElement(dialog.editor._iframe, "c"); }); }; // this function requires the file PopupDiv/PopupWin to be loaded from browser TableOperations.prototype.dialogRowCellProperties = function(cell) { var i18n = TableOperations.I18N; // retrieve existing values var element = this.getClosest(cell ? "td" : "tr"); var table = this.getClosest("table"); // this.editor.selectNodeContents(element); // this.editor.updateToolbar(); var dialog = new PopupWin(this.editor, i18n[cell ? "Cell Properties" : "Row Properties"], function(dialog, params) { TableOperations.processStyle(params, element); for (var i in params) { var val = params[i]; switch (i) { case "f_align": element.align = val; break; case "f_char": element.ch = val; break; case "f_valign": element.vAlign = val; break; } } // various workarounds to refresh the table display (Gecko, // what's going on?! do not disappoint me!) dialog.editor.forceRedraw(); dialog.editor.focusEditor(); dialog.editor.updateToolbar(); var save_collapse = table.style.borderCollapse; table.style.borderCollapse = "collapse"; table.style.borderCollapse = "separate"; table.style.borderCollapse = save_collapse; }, // this function gets called when the dialog needs to be initialized function (dialog) { var f_align = element.align; var f_valign = element.vAlign; var f_char = element.ch; function selected(val) { return val ? " selected" : ""; }; // dialog contents dialog.content.style.width = "400px"; dialog.content.innerHTML = " \
    " + i18n[cell ? "Cell Properties" : "Row Properties"] + "
    \ \ \ \ \ \ \ \
    \
    \ "; var st_prop = TableOperations.createStyleFieldset(dialog.doc, dialog.editor, element); var p = dialog.doc.getElementById("--HA-style"); p.appendChild(st_prop); var st_layout = TableOperations.createStyleLayoutFieldset(dialog.doc, dialog.editor, element); p = dialog.doc.getElementById("--HA-layout"); p.appendChild(st_layout); dialog.modal = true; dialog.addButtons("ok", "cancel"); dialog.showAtElement(dialog.editor._iframe, "c"); }); }; // this function gets called when some button from the TableOperations toolbar // was pressed. TableOperations.prototype.buttonPress = function(editor, button_id) { this.editor = editor; var mozbr = HTMLArea.is_gecko ? "
    " : ""; var i18n = TableOperations.I18N; // helper function that clears the content in a table row function clearRow(tr) { var tds = tr.getElementsByTagName("td"); for (var i = tds.length; --i >= 0;) { var td = tds[i]; td.rowSpan = 1; td.innerHTML = mozbr; } }; function splitRow(td) { var n = parseInt("" + td.rowSpan); var nc = parseInt("" + td.colSpan); td.rowSpan = 1; tr = td.parentNode; var itr = tr.rowIndex; var trs = tr.parentNode.rows; var index = td.cellIndex; while (--n > 0) { tr = trs[++itr]; var otd = editor._doc.createElement("td"); otd.colSpan = td.colSpan; otd.innerHTML = mozbr; tr.insertBefore(otd, tr.cells[index]); } editor.forceRedraw(); editor.updateToolbar(); }; function splitCol(td) { var nc = parseInt("" + td.colSpan); td.colSpan = 1; tr = td.parentNode; var ref = td.nextSibling; while (--nc > 0) { var otd = editor._doc.createElement("td"); otd.rowSpan = td.rowSpan; otd.innerHTML = mozbr; tr.insertBefore(otd, ref); } editor.forceRedraw(); editor.updateToolbar(); }; function splitCell(td) { var nc = parseInt("" + td.colSpan); splitCol(td); var items = td.parentNode.cells; var index = td.cellIndex; while (nc-- > 0) { splitRow(items[index++]); } }; function selectNextNode(el) { var node = el.nextSibling; while (node && node.nodeType != 1) { node = node.nextSibling; } if (!node) { node = el.previousSibling; while (node && node.nodeType != 1) { node = node.previousSibling; } } if (!node) { node = el.parentNode; } editor.selectNodeContents(node); }; switch (button_id) { // ROWS case "TO-row-insert-above": case "TO-row-insert-under": var tr = this.getClosest("tr"); if (!tr) { break; } var otr = tr.cloneNode(true); clearRow(otr); tr.parentNode.insertBefore(otr, /under/.test(button_id) ? tr.nextSibling : tr); editor.forceRedraw(); editor.focusEditor(); break; case "TO-row-delete": var tr = this.getClosest("tr"); if (!tr) { break; } var par = tr.parentNode; if (par.rows.length == 1) { alert(i18n["not-del-last-row"]); break; } // set the caret first to a position that doesn't // disappear. selectNextNode(tr); par.removeChild(tr); editor.forceRedraw(); editor.focusEditor(); editor.updateToolbar(); break; case "TO-row-split": var td = this.getClosest("td"); if (!td) { break; } splitRow(td); break; // COLUMNS case "TO-col-insert-before": case "TO-col-insert-after": var td = this.getClosest("td"); if (!td) { break; } var rows = td.parentNode.parentNode.rows; var index = td.cellIndex; for (var i = rows.length; --i >= 0;) { var tr = rows[i]; var ref = tr.cells[index + (/after/.test(button_id) ? 1 : 0)]; var otd = editor._doc.createElement("td"); otd.innerHTML = mozbr; tr.insertBefore(otd, ref); } editor.focusEditor(); break; case "TO-col-split": var td = this.getClosest("td"); if (!td) { break; } splitCol(td); break; case "TO-col-delete": var td = this.getClosest("td"); if (!td) { break; } var index = td.cellIndex; if (td.parentNode.cells.length == 1) { alert(i18n["not-del-last-col"]); break; } // set the caret first to a position that doesn't disappear selectNextNode(td); var rows = td.parentNode.parentNode.rows; for (var i = rows.length; --i >= 0;) { var tr = rows[i]; tr.removeChild(tr.cells[index]); } editor.forceRedraw(); editor.focusEditor(); editor.updateToolbar(); break; // CELLS case "TO-cell-split": var td = this.getClosest("td"); if (!td) { break; } splitCell(td); break; case "TO-cell-insert-before": case "TO-cell-insert-after": var td = this.getClosest("td"); if (!td) { break; } var tr = td.parentNode; var otd = editor._doc.createElement("td"); otd.innerHTML = mozbr; tr.insertBefore(otd, /after/.test(button_id) ? td.nextSibling : td); editor.forceRedraw(); editor.focusEditor(); break; case "TO-cell-delete": var td = this.getClosest("td"); if (!td) { break; } if (td.parentNode.cells.length == 1) { alert(i18n["not-del-last-cell"]); break; } // set the caret first to a position that doesn't disappear selectNextNode(td); td.parentNode.removeChild(td); editor.forceRedraw(); editor.updateToolbar(); break; case "TO-cell-merge": // !! FIXME: Mozilla specific !! var sel = editor._getSelection(); var range, i = 0; var rows = []; var row = null; var cells = null; if (!HTMLArea.is_ie) { try { while (range = sel.getRangeAt(i++)) { var td = range.startContainer.childNodes[range.startOffset]; if (td.parentNode != row) { row = td.parentNode; (cells) && rows.push(cells); cells = []; } cells.push(td); } } catch(e) {/* finished walking through selection */} rows.push(cells); } else { // Internet Explorer "browser" var td = this.getClosest("td"); if (!td) { alert(i18n["Please click into some cell"]); break; } var tr = td.parentElement; var no_cols = prompt(i18n["How many columns would you like to merge?"], 2); if (!no_cols) { // cancelled break; } var no_rows = prompt(i18n["How many rows would you like to merge?"], 2); if (!no_rows) { // cancelled break; } var cell_index = td.cellIndex; while (no_rows-- > 0) { td = tr.cells[cell_index]; cells = [td]; for (var i = 1; i < no_cols; ++i) { td = td.nextSibling; if (!td) { break; } cells.push(td); } rows.push(cells); tr = tr.nextSibling; if (!tr) { break; } } } var HTML = ""; for (i = 0; i < rows.length; ++i) { // i && (HTML += "
    "); var cells = rows[i]; for (var j = 0; j < cells.length; ++j) { // j && (HTML += " "); var cell = cells[j]; HTML += cell.innerHTML; (i || j) && (cell.parentNode.removeChild(cell)); } } var td = rows[0][0]; td.innerHTML = HTML; td.rowSpan = rows.length; td.colSpan = rows[0].length; editor.selectNodeContents(td); editor.forceRedraw(); editor.focusEditor(); break; // PROPERTIES case "TO-table-prop": this.dialogTableProperties(); break; case "TO-row-prop": this.dialogRowCellProperties(false); break; case "TO-cell-prop": this.dialogRowCellProperties(true); break; default: alert("Button [" + button_id + "] not yet implemented"); } }; // the list of buttons added by this plugin TableOperations.btnList = [ // table properties button ["table-prop", "table"], null, // separator // ROWS ["row-prop", "tr"], ["row-insert-above", "tr"], ["row-insert-under", "tr"], ["row-delete", "tr"], ["row-split", "td[rowSpan!=1]"], null, // COLS ["col-insert-before", "td"], ["col-insert-after", "td"], ["col-delete", "td"], ["col-split", "td[colSpan!=1]"], null, // CELLS ["cell-prop", "td"], ["cell-insert-before", "td"], ["cell-insert-after", "td"], ["cell-delete", "td"], ["cell-merge", "tr"], ["cell-split", "td[colSpan!=1,rowSpan!=1]"] ]; //// GENERIC CODE [style of any element; this should be moved into a separate //// file as it'll be very useful] //// BEGIN GENERIC CODE ----------------------------------------------------- TableOperations.getLength = function(value) { var len = parseInt(value); if (isNaN(len)) { len = ""; } return len; }; // Applies the style found in "params" to the given element. TableOperations.processStyle = function(params, element) { var style = element.style; for (var i in params) { var val = params[i]; switch (i) { case "f_st_backgroundColor": style.backgroundColor = val; break; case "f_st_color": style.color = val; break; case "f_st_backgroundImage": if (/\S/.test(val)) { style.backgroundImage = "url(" + val + ")"; } else { style.backgroundImage = "none"; } break; case "f_st_borderWidth": style.borderWidth = val; break; case "f_st_borderStyle": style.borderStyle = val; break; case "f_st_borderColor": style.borderColor = val; break; case "f_st_borderCollapse": style.borderCollapse = val ? "collapse" : ""; break; case "f_st_width": if (/\S/.test(val)) { style.width = val + params["f_st_widthUnit"]; } else { style.width = ""; } break; case "f_st_height": if (/\S/.test(val)) { style.height = val + params["f_st_heightUnit"]; } else { style.height = ""; } break; case "f_st_textAlign": if (val == "char") { var ch = params["f_st_textAlignChar"]; if (ch == '"') { ch = '\\"'; } style.textAlign = '"' + ch + '"'; } else { style.textAlign = val; } break; case "f_st_verticalAlign": style.verticalAlign = val; break; case "f_st_float": style.cssFloat = val; break; // case "f_st_margin": // style.margin = val + "px"; // break; // case "f_st_padding": // style.padding = val + "px"; // break; } } }; // Returns an HTML element for a widget that allows color selection. That is, // a button that contains the given color, if any, and when pressed will popup // the sooner-or-later-to-be-rewritten select_color.html dialog allowing user // to select some color. If a color is selected, an input field with the name // "f_st_"+name will be updated with the color value in #123456 format. TableOperations.createColorButton = function(doc, editor, color, name) { if (!color) { color = ""; } else if (!/#/.test(color)) { color = HTMLArea._colorToRgb(color); } var df = doc.createElement("span"); var field = doc.createElement("input"); field.type = "hidden"; df.appendChild(field); field.name = "f_st_" + name; field.value = color; var button = doc.createElement("span"); button.className = "buttonColor"; df.appendChild(button); var span = doc.createElement("span"); span.className = "chooser"; // span.innerHTML = "       "; span.style.backgroundColor = color; button.appendChild(span); button.onmouseover = function() { if (!this.disabled) { this.className += " buttonColor-hilite"; }}; button.onmouseout = function() { if (!this.disabled) { this.className = "buttonColor"; }}; span.onclick = function() { if (this.parentNode.disabled) { return false; } editor._popupDialog("select_color.html", function(color) { if (color) { span.style.backgroundColor = "#" + color; field.value = "#" + color; } }, color); }; var span2 = doc.createElement("span"); span2.innerHTML = "×"; span2.className = "nocolor"; span2.title = TableOperations.I18N["Unset color"]; button.appendChild(span2); span2.onmouseover = function() { if (!this.parentNode.disabled) { this.className += " nocolor-hilite"; }}; span2.onmouseout = function() { if (!this.parentNode.disabled) { this.className = "nocolor"; }}; span2.onclick = function() { span.style.backgroundColor = ""; field.value = ""; }; return df; }; TableOperations.createStyleLayoutFieldset = function(doc, editor, el) { var i18n = TableOperations.I18N; var fieldset = doc.createElement("fieldset"); var legend = doc.createElement("legend"); fieldset.appendChild(legend); legend.innerHTML = i18n["Layout"]; var table = doc.createElement("table"); fieldset.appendChild(table); table.style.width = "100%"; var tbody = doc.createElement("tbody"); table.appendChild(tbody); var tagname = el.tagName.toLowerCase(); var tr, td, input, select, option, options, i; if (tagname != "td" && tagname != "tr" && tagname != "th") { tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); td.className = "label"; tr.appendChild(td); td.innerHTML = i18n["Float"] + ":"; td = doc.createElement("td"); tr.appendChild(td); select = doc.createElement("select"); td.appendChild(select); select.name = "f_st_float"; options = ["None", "Left", "Right"]; for (var i = 0; i < options.length; ++i) { var Val = options[i]; var val = options[i].toLowerCase(); option = doc.createElement("option"); option.innerHTML = i18n[Val]; option.value = val; option.selected = (("" + el.style.cssFloat).toLowerCase() == val); select.appendChild(option); } } tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); td.className = "label"; tr.appendChild(td); td.innerHTML = i18n["Width"] + ":"; td = doc.createElement("td"); tr.appendChild(td); input = doc.createElement("input"); input.type = "text"; input.value = TableOperations.getLength(el.style.width); input.size = "5"; input.name = "f_st_width"; input.style.marginRight = "0.5em"; td.appendChild(input); select = doc.createElement("select"); select.name = "f_st_widthUnit"; option = doc.createElement("option"); option.innerHTML = i18n["percent"]; option.value = "%"; option.selected = /%/.test(el.style.width); select.appendChild(option); option = doc.createElement("option"); option.innerHTML = i18n["pixels"]; option.value = "px"; option.selected = /px/.test(el.style.width); select.appendChild(option); td.appendChild(select); select.style.marginRight = "0.5em"; td.appendChild(doc.createTextNode(i18n["Text align"] + ":")); select = doc.createElement("select"); select.style.marginLeft = select.style.marginRight = "0.5em"; td.appendChild(select); select.name = "f_st_textAlign"; options = ["Left", "Center", "Right", "Justify"]; if (tagname == "td") { options.push("Char"); } input = doc.createElement("input"); input.name = "f_st_textAlignChar"; input.size = "1"; input.style.fontFamily = "monospace"; td.appendChild(input); for (var i = 0; i < options.length; ++i) { var Val = options[i]; var val = Val.toLowerCase(); option = doc.createElement("option"); option.value = val; option.innerHTML = i18n[Val]; option.selected = (el.style.textAlign.toLowerCase() == val); select.appendChild(option); } function setCharVisibility(value) { input.style.visibility = value ? "visible" : "hidden"; if (value) { input.focus(); input.select(); } }; select.onchange = function() { setCharVisibility(this.value == "char"); }; setCharVisibility(select.value == "char"); tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); td.className = "label"; tr.appendChild(td); td.innerHTML = i18n["Height"] + ":"; td = doc.createElement("td"); tr.appendChild(td); input = doc.createElement("input"); input.type = "text"; input.value = TableOperations.getLength(el.style.height); input.size = "5"; input.name = "f_st_height"; input.style.marginRight = "0.5em"; td.appendChild(input); select = doc.createElement("select"); select.name = "f_st_heightUnit"; option = doc.createElement("option"); option.innerHTML = i18n["percent"]; option.value = "%"; option.selected = /%/.test(el.style.height); select.appendChild(option); option = doc.createElement("option"); option.innerHTML = i18n["pixels"]; option.value = "px"; option.selected = /px/.test(el.style.height); select.appendChild(option); td.appendChild(select); select.style.marginRight = "0.5em"; td.appendChild(doc.createTextNode(i18n["Vertical align"] + ":")); select = doc.createElement("select"); select.name = "f_st_verticalAlign"; select.style.marginLeft = "0.5em"; td.appendChild(select); options = ["Top", "Middle", "Bottom", "Baseline"]; for (var i = 0; i < options.length; ++i) { var Val = options[i]; var val = Val.toLowerCase(); option = doc.createElement("option"); option.value = val; option.innerHTML = i18n[Val]; option.selected = (el.style.verticalAlign.toLowerCase() == val); select.appendChild(option); } return fieldset; }; // Returns an HTML element containing the style attributes for the given // element. This can be easily embedded into any dialog; the functionality is // also provided. TableOperations.createStyleFieldset = function(doc, editor, el) { var i18n = TableOperations.I18N; var fieldset = doc.createElement("fieldset"); var legend = doc.createElement("legend"); fieldset.appendChild(legend); legend.innerHTML = i18n["CSS Style"]; var table = doc.createElement("table"); fieldset.appendChild(table); table.style.width = "100%"; var tbody = doc.createElement("tbody"); table.appendChild(tbody); var tr, td, input, select, option, options, i; tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); tr.appendChild(td); td.className = "label"; td.innerHTML = i18n["Background"] + ":"; td = doc.createElement("td"); tr.appendChild(td); var df = TableOperations.createColorButton(doc, editor, el.style.backgroundColor, "backgroundColor"); df.firstChild.nextSibling.style.marginRight = "0.5em"; td.appendChild(df); td.appendChild(doc.createTextNode(i18n["Image URL"] + ": ")); input = doc.createElement("input"); input.type = "text"; input.name = "f_st_backgroundImage"; if (el.style.backgroundImage.match(/url\(\s*(.*?)\s*\)/)) { input.value = RegExp.$1; } // input.style.width = "100%"; td.appendChild(input); tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); tr.appendChild(td); td.className = "label"; td.innerHTML = i18n["FG Color"] + ":"; td = doc.createElement("td"); tr.appendChild(td); td.appendChild(TableOperations.createColorButton(doc, editor, el.style.color, "color")); // for better alignment we include an invisible field. input = doc.createElement("input"); input.style.visibility = "hidden"; input.type = "text"; td.appendChild(input); tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); tr.appendChild(td); td.className = "label"; td.innerHTML = i18n["Border"] + ":"; td = doc.createElement("td"); tr.appendChild(td); var colorButton = TableOperations.createColorButton(doc, editor, el.style.borderColor, "borderColor"); var btn = colorButton.firstChild.nextSibling; td.appendChild(colorButton); // borderFields.push(btn); btn.style.marginRight = "0.5em"; select = doc.createElement("select"); var borderFields = []; td.appendChild(select); select.name = "f_st_borderStyle"; options = ["none", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset"]; var currentBorderStyle = el.style.borderStyle; // Gecko reports "solid solid solid solid" for "border-style: solid". // That is, "top right bottom left" -- we only consider the first // value. (currentBorderStyle.match(/([^\s]*)\s/)) && (currentBorderStyle = RegExp.$1); for (var i in options) { var val = options[i]; option = doc.createElement("option"); option.value = val; option.innerHTML = val; (val == currentBorderStyle) && (option.selected = true); select.appendChild(option); } select.style.marginRight = "0.5em"; function setBorderFieldsStatus(value) { for (var i = 0; i < borderFields.length; ++i) { var el = borderFields[i]; el.style.visibility = value ? "hidden" : "visible"; if (!value && (el.tagName.toLowerCase() == "input")) { el.focus(); el.select(); } } }; select.onchange = function() { setBorderFieldsStatus(this.value == "none"); }; input = doc.createElement("input"); borderFields.push(input); input.type = "text"; input.name = "f_st_borderWidth"; input.value = TableOperations.getLength(el.style.borderWidth); input.size = "5"; td.appendChild(input); input.style.marginRight = "0.5em"; var span = doc.createElement("span"); span.innerHTML = i18n["pixels"]; td.appendChild(span); borderFields.push(span); setBorderFieldsStatus(select.value == "none"); if (el.tagName.toLowerCase() == "table") { // the border-collapse style is only for tables tr = doc.createElement("tr"); tbody.appendChild(tr); td = doc.createElement("td"); td.className = "label"; tr.appendChild(td); input = doc.createElement("input"); input.type = "checkbox"; input.name = "f_st_borderCollapse"; input.id = "f_st_borderCollapse"; var val = (/collapse/i.test(el.style.borderCollapse)); input.checked = val ? 1 : 0; td.appendChild(input); td = doc.createElement("td"); tr.appendChild(td); var label = doc.createElement("label"); label.htmlFor = "f_st_borderCollapse"; label.innerHTML = i18n["Collapsed borders"]; td.appendChild(label); } // tr = doc.createElement("tr"); // tbody.appendChild(tr); // td = doc.createElement("td"); // td.className = "label"; // tr.appendChild(td); // td.innerHTML = i18n["Margin"] + ":"; // td = doc.createElement("td"); // tr.appendChild(td); // input = doc.createElement("input"); // input.type = "text"; // input.size = "5"; // input.name = "f_st_margin"; // td.appendChild(input); // input.style.marginRight = "0.5em"; // td.appendChild(doc.createTextNode(i18n["Padding"] + ":")); // input = doc.createElement("input"); // input.type = "text"; // input.size = "5"; // input.name = "f_st_padding"; // td.appendChild(input); // input.style.marginLeft = "0.5em"; // input.style.marginRight = "0.5em"; // td.appendChild(doc.createTextNode(i18n["pixels"])); return fieldset; }; //// END GENERIC CODE ------------------------------------------------------- openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/DynamicCSS/0000755000175000017500000000000011724401447027536 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/DynamicCSS/lang/0000755000175000017500000000000011575225612030461 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/DynamicCSS/lang/de.js0000644000175000017500000000077510177203651031414 0ustar frankiefrankie// I18N constants // LANG: "de", ENCODING: UTF-8 | ISO-8859-1 // Sponsored by http://www.systemconcept.de // Author: Holger Hees, // // (c) systemconcept.de 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). DynamicCSS.I18N = { "Default" : "Standard", "Undefined" : "Nicht definiert", "DynamicCSSStyleTooltip" : "Wählen Sie einen StyleSheet aus" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/DynamicCSS/lang/en.js0000644000175000017500000000075010177203651031417 0ustar frankiefrankie// I18N constants // LANG: "de", ENCODING: UTF-8 | ISO-8859-1 // Sponsored by http://www.systemconcept.de // Author: Holger Hees, // // (c) systemconcept.de 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). DynamicCSS.I18N = { "Default" : "Default", "Undefined" : "Undefined", "DynamicCSSStyleTooltip" : "Choose stylesheet" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/DynamicCSS/lang/fr.js0000644000175000017500000000076210177203651031427 0ustar frankiefrankie// I18N constants // LANG: "fr", ENCODING: UTF-8 | ISO-8859-1 // Sponsored by http://www.ebdata.com // Author: Cédric Guillemette, // // (c) www.ebdata.com 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). DynamicCSS.I18N = { "Default" : "Défaut", "Undefined" : "Non défini", "DynamicCSSStyleTooltip" : "Choisir feuille de style" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/DynamicCSS/dynamiccss.js0000644000175000017500000002134410177203651032233 0ustar frankiefrankie// Dynamic CSS (className) plugin for HTMLArea // Sponsored by http://www.systemconcept.de // Implementation by Holger Hees // // (c) systemconcept.de 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). function DynamicCSS(editor, args) { this.editor = editor; var cfg = editor.config; var toolbar = cfg.toolbar; var self = this; var i18n = DynamicCSS.I18N; /*var cssArray=null; var cssLength=0; var lastTag=null; var lastClass=null;*/ var css_class = { id : "DynamicCSS-class", tooltip : i18n["DynamicCSSStyleTooltip"], options : {"":""}, action : function(editor) { self.onSelect(editor, this); }, refresh : function(editor) { self.updateValue(editor, this); } }; cfg.registerDropdown(css_class); toolbar[0].splice(0, 0, "separator"); toolbar[0].splice(0, 0, "DynamicCSS-class"); toolbar[0].splice(0, 0, "T[CSS]"); }; DynamicCSS.parseStyleSheet=function(editor){ var i18n = DynamicCSS.I18N; iframe = editor._iframe.contentWindow.document; cssArray=DynamicCSS.cssArray; if(!cssArray) cssArray=new Array(); for(i=0;i'; } else{ className='none'; if(tagName=='all') cssName=i18n["Default"]; else cssName='<'+i18n["Default"]+'>'; } cssArray[tagName][className]=cssName; DynamicCSS.cssLength++; } } } // ImportRule (Mozilla) else if(cssRules[rule].styleSheet){ cssArray=DynamicCSS.applyCSSRule(i18n,cssRules[rule].styleSheet.cssRules,cssArray); } } return cssArray; } DynamicCSS._pluginInfo = { name : "DynamicCSS", version : "1.5.2", developer : "Holger Hees", developer_url : "http://www.systemconcept.de/", c_owner : "Holger Hees", sponsor : "System Concept GmbH", sponsor_url : "http://www.systemconcept.de/", license : "htmlArea" }; DynamicCSS.prototype.onSelect = function(editor, obj) { var tbobj = editor._toolbarObjects[obj.id]; var index = tbobj.element.selectedIndex; var className = tbobj.element.value; var parent = editor.getParentElement(); if(className!='none'){ parent.className=className; DynamicCSS.lastClass=className; } else{ if(HTMLArea.is_gecko) parent.removeAttribute('class'); else parent.removeAttribute('className'); } editor.updateToolbar(); }; /*DynamicCSS.prototype.onMode = function(mode) { if(mode=='wysiwyg'){ // reparse possible changed css files DynamicCSS.cssArray=null; this.updateValue(this.editor,this.editor.config.customSelects["DynamicCSS-class"]); } }*/ DynamicCSS.prototype.reparseTimer = function(editor, obj, instance) { // new attempt of rescan stylesheets in 1,2,4 and 8 second (e.g. for external css-files with longer initialisation) if(DynamicCSS.parseCount<9){ setTimeout(function () { DynamicCSS.cssLength=0; DynamicCSS.parseStyleSheet(editor); if(DynamicCSS.cssOldLength!=DynamicCSS.cssLength){ DynamicCSS.cssOldLength=DynamicCSS.cssLength; DynamicCSS.lastClass=null; instance.updateValue(editor, obj); } instance.reparseTimer(editor, obj, instance); },DynamicCSS.parseCount*1000); DynamicCSS.parseCount=DynamicCSS.parseCount*2; } } DynamicCSS.prototype.updateValue = function(editor, obj) { cssArray=DynamicCSS.cssArray; // initial style init if(!cssArray){ DynamicCSS.cssLength=0; DynamicCSS.parseStyleSheet(editor); cssArray=DynamicCSS.cssArray; DynamicCSS.cssOldLength=DynamicCSS.cssLength; DynamicCSS.parseCount=1; this.reparseTimer(editor,obj,this); } var parent = editor.getParentElement(); var tagName = parent.tagName.toLowerCase(); var className = parent.className; if(DynamicCSS.lastTag!=tagName || DynamicCSS.lastClass!=className){ DynamicCSS.lastTag=tagName; DynamicCSS.lastClass=className; var i18n = DynamicCSS.I18N; var select = editor._toolbarObjects[obj.id].element; while(select.length>0){ select.options[select.length-1] = null; } select.options[0]=new Option(i18n["Default"],'none'); if(cssArray){ // style class only allowed if parent tag is not body or editor is in fullpage mode if(tagName!='body' || editor.config.fullPage){ if(cssArray[tagName]){ for(cssClass in cssArray[tagName]){ if(cssClass=='none') select.options[0]=new Option(cssArray[tagName][cssClass],cssClass); else select.options[select.length]=new Option(cssArray[tagName][cssClass],cssClass); } } if(cssArray['all']){ for(cssClass in cssArray['all']){ select.options[select.length]=new Option(cssArray['all'][cssClass],cssClass); } } } else if(cssArray[tagName] && cssArray[tagName]['none']) select.options[0]=new Option(cssArray[tagName]['none'],'none'); } select.selectedIndex = 0; if (typeof className != "undefined" && /\S/.test(className)) { var options = select.options; for (var i = options.length; --i >= 0;) { var option = options[i]; if (className == option.value) { select.selectedIndex = i; break; } } if(select.selectedIndex == 0){ select.options[select.length]=new Option(i18n["Undefined"],className); select.selectedIndex=select.length-1; } } if(select.length>1) select.disabled=false; else select.disabled=true; } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ListType/0000755000175000017500000000000011724401447027356 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ListType/list-type.js0000644000175000017500000000531310177203653031650 0ustar frankiefrankie// ListType Plugin for HTMLArea-3.0 // Sponsored by MEdTech Unit - Queen's University // Implementation by Mihai Bazon, http://dynarch.com/mishoo/ // // (c) dynarch.com 2003-2005. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // $Id: list-type.js,v 1.1 2005/01/30 16:13:31 jeffd Exp $ function ListType(editor) { this.editor = editor; var cfg = editor.config; var toolbar = cfg.toolbar; var self = this; var i18n = ListType.I18N; var options = {}; options[i18n["Decimal"]] = "decimal"; options[i18n["Lower roman"]] = "lower-roman"; options[i18n["Upper roman"]] = "upper-roman"; options[i18n["Lower latin"]] = "lower-alpha"; options[i18n["Upper latin"]] = "upper-alpha"; if (!HTMLArea.is_ie) // IE doesn't support this property; even worse, it complains // with a gross error message when we tried to select it, // therefore let's hide it from the damn "browser". options[i18n["Lower greek"]] = "lower-greek"; var obj = { id : "ListType", tooltip : i18n["ListStyleTooltip"], options : options, action : function(editor) { self.onSelect(editor, this); }, refresh : function(editor) { self.updateValue(editor, this); }, context : "ol" }; cfg.registerDropdown(obj); var a, i, j, found = false; for (i = 0; !found && i < toolbar.length; ++i) { a = toolbar[i]; for (j = 0; j < a.length; ++j) { if (a[j] == "unorderedlist") { found = true; break; } } } if (found) a.splice(j, 0, "space", "ListType", "space"); }; ListType._pluginInfo = { name : "ListType", version : "1.0", developer : "Mihai Bazon", developer_url : "http://dynarch.com/mishoo/", c_owner : "dynarch.com", sponsor : "MEdTech Unit - Queen's University", sponsor_url : "http://www.queensu.ca/", license : "htmlArea" }; ListType.prototype.onSelect = function(editor, combo) { var tbobj = editor._toolbarObjects[combo.id].element; var parent = editor.getParentElement(); while (!/^ol$/i.test(parent.tagName)) { parent = parent.parentNode; } parent.style.listStyleType = tbobj.value; }; ListType.prototype.updateValue = function(editor, combo) { var tbobj = editor._toolbarObjects[combo.id].element; var parent = editor.getParentElement(); while (parent && !/^ol$/i.test(parent.tagName)) { parent = parent.parentNode; } if (!parent) { tbobj.selectedIndex = 0; return; } var type = parent.style.listStyleType; if (!type) { tbobj.selectedIndex = 0; } else { for (var i = tbobj.firstChild; i; i = i.nextSibling) { i.selected = (type.indexOf(i.value) != -1); } } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ListType/lang/0000755000175000017500000000000011724401447030277 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ListType/lang/de.js0000644000175000017500000000141710177203653031230 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Holger Hees, http://www.systemconcept.de // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) ListType.I18N = { "Decimal" : "1-Zahlen", "Lower roman" : "i-Roemisch", "Upper roman" : "I-Roemisch", "Lower latin" : "a-Zeichen", "Upper latin" : "A-Zeichen", "Lower greek" : "Griechisch", "ListStyleTooltip" : "Wählen Sie einen Typ für die Nummerierung aus" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/ListType/lang/en.js0000644000175000017500000000150010177203653031233 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) ListType.I18N = { "Decimal" : "Decimal numbers", "Lower roman" : "Lower roman numbers", "Upper roman" : "Upper roman numbers", "Lower latin" : "Lower latin letters", "Upper latin" : "Upper latin letters", "Lower greek" : "Lower greek letters", "ListStyleTooltip" : "Choose list style type (for ordered lists)" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/0000755000175000017500000000000011724401447027300 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/img/0000755000175000017500000000000011724401447030054 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/img/docprop.gif0000644000175000017500000000045610177203652032215 0ustar frankiefrankieGIF89aó €ÿÿ€ÿ€€€   ÀÀÀîîæÿÿÿÿÿÿ!ù ,ÛP)¥”RJ)¥”‚J)¥B!„ !„”R!„`!„BF©C!„B!h”)¥RJ)Á”0JtžsÎI ¥@°ˆR@J)¥Œ‚ €’R9œsLÀ(€H¢ˆ`J)%`”àˆËIàœs0JÊ%RJ @£H œRÀž”€Q ¤¤RJÀ(R‚)”H %`T€ F)eŒ1Æ Æ£”RJ)¨”RÊ£”RJA¥”RJ)¥”R *;openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/lang/0000755000175000017500000000000011724401447030221 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/lang/de.js0000644000175000017500000000143010177203652031144 0ustar frankiefrankie// I18N for the FullPage plugin // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Holger Hees, http://www.systemconcept.de // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) FullPage.I18N = { "Alternate style-sheet:": "Alternativer Stylesheet:", "Background color:": "Hintergrundfarbe:", "Cancel": "Abbrechen", "DOCTYPE:": "DOCTYPE:", "Document properties": "Dokumenteigenschaften", "Document title:": "Dokumenttitel:", "OK": "OK", "Primary style-sheet:": "Stylesheet:", "Text color:": "Textfarbe:" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/lang/en.js0000644000175000017500000000143210177203652031160 0ustar frankiefrankie// I18N for the FullPage plugin // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) FullPage.I18N = { "Alternate style-sheet:": "Alternate style-sheet:", "Background color:": "Background color:", "Cancel": "Cancel", "DOCTYPE:": "DOCTYPE:", "Document properties": "Document properties", "Document title:": "Document title:", "OK": "OK", "Primary style-sheet:": "Primary style-sheet:", "Text color:": "Text color:" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/lang/fr.js0000644000175000017500000000150110177203652031162 0ustar frankiefrankie// I18N for the FullPage plugin // LANG: "fr", ENCODING: UTF-8 | ISO-8859-1 // Author: Cédric Guillemette, http://www.ebdata.com // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) FullPage.I18N = { "Alternate style-sheet:": "Feuille de style alternative:", "Background color:": "Couleur d'arrière plan:", "Cancel": "Annuler", "DOCTYPE:": "DOCTYPE:", "Document properties": "Propriétés de document", "Document title:": "Titre du document:", "OK": "OK", "Primary style-sheet:": "Feuille de style primaire:", "Text color:": "Couleur de texte:" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/lang/he.js0000644000175000017500000000155510177203652031160 0ustar frankiefrankie// I18N for the FullPage plugin // LANG: "he", ENCODING: UTF-8 // Author: Liron Newman, http://www.eesh.net, // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) FullPage.I18N = { "Alternate style-sheet:": "גיליון סגנון ×חר:", "Background color:": "צבע רקע:", "Cancel": "ביטול", "DOCTYPE:": "DOCTYPE:", "Document properties": "מ×פייני מסמך", "Document title:": "כותרת מסמך:", "OK": "×ישור", "Primary style-sheet:": "גיליון סגנון ר×שי:", "Text color:": "צבע טקסט:" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/lang/ro.js0000644000175000017500000000147110177203652031201 0ustar frankiefrankie// I18N for the FullPage plugin // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Mihai Bazon, http://dynarch.com/mishoo // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) FullPage.I18N = { "Alternate style-sheet:": "Template CSS alternativ:", "Background color:": "Culoare de fundal:", "Cancel": "Renunţă", "DOCTYPE:": "DOCTYPE:", "Document properties": "Proprietăţile documentului", "Document title:": "Titlul documentului:", "OK": "Acceptă", "Primary style-sheet:": "Template CSS principal:", "Text color:": "Culoare text:" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/popups/0000755000175000017500000000000011724401447030626 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/popups/docprop.html0000644000175000017500000000756310177203652033174 0ustar frankiefrankie Document properties
    Document properties
    Document title:
    DOCTYPE:
    Primary style-sheet:
    Alternate style-sheet:
    Background color:
    Text color:
    Character set:
    openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/full-page.js0000644000175000017500000001124310177203651031511 0ustar frankiefrankie// FullPage Plugin for HTMLArea-3.0 // Implementation by Mihai Bazon. Sponsored by http://thycotic.com // // (c) dynarch.com 2003-2005. // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // $Id: full-page.js,v 1.1 2005/01/30 16:13:29 jeffd Exp $ function FullPage(editor) { this.editor = editor; var cfg = editor.config; cfg.fullPage = true; var tt = FullPage.I18N; var self = this; cfg.registerButton("FP-docprop", tt["Document properties"], editor.imgURL("docprop.gif", "FullPage"), false, function(editor, id) { self.buttonPress(editor, id); }); // add a new line in the toolbar cfg.toolbar[0].splice(0, 0, "separator"); cfg.toolbar[0].splice(0, 0, "FP-docprop"); }; FullPage._pluginInfo = { name : "FullPage", version : "1.0", developer : "Mihai Bazon", developer_url : "http://dynarch.com/mishoo/", c_owner : "Mihai Bazon", sponsor : "Thycotic Software Ltd.", sponsor_url : "http://thycotic.com", license : "htmlArea" }; FullPage.prototype.buttonPress = function(editor, id) { var self = this; switch (id) { case "FP-docprop": var doc = editor._doc; var links = doc.getElementsByTagName("link"); var style1 = ''; var style2 = ''; var charset = ''; for (var i = links.length; --i >= 0;) { var link = links[i]; if (/stylesheet/i.test(link.rel)) { if (/alternate/i.test(link.rel)) style2 = link.href; else style1 = link.href; } } var metas = doc.getElementsByTagName("meta"); for (var i = metas.length; --i >= 0;) { var meta = metas[i]; if (/content-type/i.test(meta.httpEquiv)) { r = /^text\/html; *charset=(.*)$/i.exec(meta.content); charset = r[1]; } } var title = doc.getElementsByTagName("title")[0]; title = title ? title.innerHTML : ''; var init = { f_doctype : editor.doctype, f_title : title, f_body_bgcolor : HTMLArea._colorToRgb(doc.body.style.backgroundColor), f_body_fgcolor : HTMLArea._colorToRgb(doc.body.style.color), f_base_style : style1, f_alt_style : style2, f_charset : charset, editor : editor }; editor._popupDialog("plugin://FullPage/docprop", function(params) { self.setDocProp(params); }, init); break; } }; FullPage.prototype.setDocProp = function(params) { var txt = ""; var doc = this.editor._doc; var head = doc.getElementsByTagName("head")[0]; var links = doc.getElementsByTagName("link"); var metas = doc.getElementsByTagName("meta"); var style1 = null; var style2 = null; var charset = null; var charset_meta = null; for (var i = links.length; --i >= 0;) { var link = links[i]; if (/stylesheet/i.test(link.rel)) { if (/alternate/i.test(link.rel)) style2 = link; else style1 = link; } } for (var i = metas.length; --i >= 0;) { var meta = metas[i]; if (/content-type/i.test(meta.httpEquiv)) { r = /^text\/html; *charset=(.*)$/i.exec(meta.content); charset = r[1]; charset_meta = meta; } } function createLink(alt) { var link = doc.createElement("link"); link.rel = alt ? "alternate stylesheet" : "stylesheet"; head.appendChild(link); return link; }; function createMeta(name, content) { var meta = doc.createElement("meta"); meta.httpEquiv = name; meta.content = content; head.appendChild(meta); return meta; }; if (!style1 && params.f_base_style) style1 = createLink(false); if (params.f_base_style) style1.href = params.f_base_style; else if (style1) head.removeChild(style1); if (!style2 && params.f_alt_style) style2 = createLink(true); if (params.f_alt_style) style2.href = params.f_alt_style; else if (style2) head.removeChild(style2); if (charset_meta) { head.removeChild(charset_meta); charset_meta = null; } if (!charset_meta && params.f_charset) charset_meta = createMeta("Content-Type", "text/html; charset="+params.f_charset); for (var i in params) { var val = params[i]; switch (i) { case "f_title": var title = doc.getElementsByTagName("title")[0]; if (!title) { title = doc.createElement("title"); head.appendChild(title); } else while (node = title.lastChild) title.removeChild(node); if (!HTMLArea.is_ie) title.appendChild(doc.createTextNode(val)); else doc.title = val; break; case "f_doctype": this.editor.setDoctype(val); break; case "f_body_bgcolor": doc.body.style.backgroundColor = val; break; case "f_body_fgcolor": doc.body.style.color = val; break; } } }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/FullPage/test.html0000644000175000017500000000736210177203651031153 0ustar frankiefrankie Test of FullPage plugin

    Test of FullPage plugin


    Mihai Bazon
    Last modified on Sat Oct 25 01:06:59 2003 openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/0000755000175000017500000000000011724401447027337 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/img/0000755000175000017500000000000011724401447030113 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/img/html-tidy.gif0000644000175000017500000000015310177203652032513 0ustar frankiefrankieGIF89a¡¡¡"bõ„ÿÿÿÿÿÿÿÿÿÿÿÿ!ù,0HºÌ!-ª¥ÕN¬í[¶Á%*F_´ïÉÌ.VjøÛõº-ÈÚ³c;openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/lang/0000755000175000017500000000000011724401447030260 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/lang/en.js0000644000175000017500000000110110177203653031211 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Author: Adam Wright, http://blog.hipikat.org/ // FOR TRANSLATORS: // // 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE // (at least a valid email address) // // 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; // (if this is not possible, please include a comment // that states what encoding is necessary.) HtmlTidy.I18N = { "tidying" : "\n Tidying up the HTML source, please wait...", "HT-html-tidy" : "HTML Tidy" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/html-tidy-logic.php0000644000175000017500000000452110177203652033057 0ustar frankiefrankie array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("file", "/dev/null", "a") ); $process = proc_open("tidy -config html-tidy-config.cfg", $descriptorspec, $pipes); // Make sure the program started and we got the hooks... // Either way, get some source code into $source if (is_resource($process)) { // Feed untidy source into the stdin fwrite($pipes[0], $source); fclose($pipes[0]); // Read clean source out to the browser while (!feof($pipes[1])) { //echo fgets($pipes[1], 1024); $newsrc .= fgets($pipes[1], 1024); } fclose($pipes[1]); // Clean up after ourselves proc_close($process); } else { // Better give them back what they came with, so they don't lose it all... $newsrc = "\n" .$source. "\n"; } // Split our source into an array by lines $srcLines = explode("\n",$newsrc); // Get only the lines between the body tags $startLn = 0; while ( strpos( $srcLines[$startLn++], ' openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/html-tidy.js0000644000175000017500000000707010177203652031613 0ustar frankiefrankie// Plugin for htmlArea to run code through the server's HTML Tidy // By Adam Wright, for The University of Western Australia // // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). function HtmlTidy(editor) { this.editor = editor; var cfg = editor.config; var tt = HtmlTidy.I18N; var bl = HtmlTidy.btnList; var self = this; this.onMode = this.__onMode; // register the toolbar buttons provided by this plugin var toolbar = []; for (var i = 0; i < bl.length; ++i) { var btn = bl[i]; if (btn == "html-tidy") { var id = "HT-html-tidy"; cfg.registerButton(id, tt[id], editor.imgURL(btn[0] + ".gif", "HtmlTidy"), true, function(editor, id) { // dispatch button press event self.buttonPress(editor, id); }, btn[1]); toolbar.push(id); } else if (btn == "html-auto-tidy") { var ht_class = { id : "HT-auto-tidy", options : { "Auto-Tidy" : "auto", "Don't Tidy" : "noauto" }, action : function (editor) { self.__onSelect(editor, this); }, refresh : function (editor) { }, context : "body" }; cfg.registerDropdown(ht_class); } } for (var i in toolbar) { cfg.toolbar[0].push(toolbar[i]); } }; HtmlTidy._pluginInfo = { name : "HtmlTidy", version : "1.0", developer : "Adam Wright", developer_url : "http://blog.hipikat.org/", sponsor : "The University of Western Australia", sponsor_url : "http://www.uwa.edu.au/", license : "htmlArea" }; HtmlTidy.prototype.__onSelect = function(editor, obj) { // Get the toolbar element object var elem = editor._toolbarObjects[obj.id].element; // Set our onMode event appropriately if (elem.value == "auto") this.onMode = this.__onMode; else this.onMode = null; }; HtmlTidy.prototype.__onMode = function(mode) { if ( mode == "textmode" ) { this.buttonPress(this.editor, "HT-html-tidy"); } }; HtmlTidy.btnList = [ null, // separator ["html-tidy"], ["html-auto-tidy"] ]; HtmlTidy.prototype.onGenerateOnce = function() { var editor = this.editor; var ifr = document.createElement("iframe"); ifr.name = "htiframe_name"; var s = ifr.style; s.position = "absolute"; s.width = s.height = s.border = s.left = s.top = s.padding = s.margin = "0px"; document.body.appendChild(ifr); var frm = '
    '; var newdiv = document.createElement('div'); newdiv.style.display = "none"; newdiv.innerHTML = frm; document.body.appendChild(newdiv); }; HtmlTidy.prototype.buttonPress = function(editor, id) { var i18n = HtmlTidy.I18N; switch (id) { case "HT-html-tidy": var oldhtml = editor.getHTML(); // Ask the server for some nice new html, based on the old... var myform = document.getElementById('htiform_id'); var txtarea = document.getElementById('htisource_id'); txtarea.value = editor.getHTML(); // Apply the 'meanwhile' text, e.g. "Tidying HTML, please wait..." editor.setHTML(i18n['tidying']); // The returning tidying processing script needs to find the editor window._editorRef = editor; // ...And send our old source off for processing! myform.submit(); break; } }; HtmlTidy.prototype.processTidied = function(newSrc) { editor = this.editor; editor.setHTML(newSrc); }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/README0000644000175000017500000000722210177203652030221 0ustar frankiefrankie// Plugin for htmlArea to run code through the server's HTML Tidy // By Adam Wright, for The University of Western Australia // // Email: zeno@ucc.gu.uwa.edu.au // Homepage: http://blog.hipikat.org/ // // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). // // Version: 0.5 // Released to the outside world: 04/03/04 HtmlTidy is a plugin for the popular cross-browser TTY WYSIWYG editor, htmlArea (http://www.htmlarea.com/). HtmlTidy basically queries HTML Tidy (http://tidy.sourceforge.net/) on the server side, getting it to make-html-nice, instead of relying on masses of javascript, which the client would have to download. Hi, this is a quick explanation of how to install HtmlTidy. Much better documentation is probably required, and you're welcome to write it :) * The HtmlTidy directory you should have found this file in should include the following: - README This file, providing help installing the plugin. - html-tidy-config.cfg This file contains the configuration options HTML Tidy uses to clean html, and can be modified to suit your organizations requirements. - html-tidy-logic.php This is the php script, which is queried with dirty html and is responsible for invoking HTML Tidy, getting nice new html and returning it to the client. - html-tidy.js The main htmlArea plugin, providing functionality to tidy html through the htmlArea interface. - htmlarea.js.onmode_event.diff At the time of publishing, an extra event handler was required inside the main htmlarea.js file. htmlarea.js may be patched against this file to make the changes reuquired, but be aware that the event handler may either now be in the core or htmlarea.js may have changed enough to invalidate the patch. UPDATE: now it exists in the official htmlarea.js; applying this patch is thus no longer necessary. - img/html-tidy.gif The HtmlTidy icon, for the htmlArea toolbar. Created by Dan Petty for The University of Western Australia. - lang/en.js English language file. Add your own language files here and please contribute back into the htmlArea community! The HtmlArea directory should be extracted to your htmlarea/plugins/ directory. * Make sure the onMode event handler mentioned above, regarding htmlarea.js.onmode_event.diff, exists in your htmlarea.js * html-tidy-logic.php should be executable, and your web server should be configured to execute php scripts in the directory html-tidy-logic.php exists in. * HTML Tidy needs to be installed on your server, and 'tidy' should be an alias to it, lying in the PATH known to the user executing such web scripts. * In your htmlArea configuration, do something like this: HTMLArea.loadPlugin("HtmlTidy"); editor = new HTMLArea("doc"); editor.registerPlugin("HtmlTidy"); * Then, in your htmlArea toolbar configuration, use: - "HT-html-tidy" This will create the 'tidy broom' icon on the toolbar, which will attempt to tidy html source when clicked, and; - "HT-auto-tidy" This will create an "Auto Tidy" / "Don't Tidy" dropdown, to select whether the source should be tidied automatically when entering source view. On by default, if you'd like it otherwise you can do so programatically after generating the toolbar :) (Or just hack it to be otherwise...) Thank you. Any bugs you find can be emailed to zeno@ucc.gu.uwa.edu.au openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/HtmlTidy/html-tidy-config.cfg0000644000175000017500000000145310177203652033200 0ustar frankiefrankie// Default configuration file for the htmlArea, HtmlTidy plugin // By Adam Wright, for The University of Western Australia // // Evertything you always wanted to know about HTML Tidy * // can be found at http://tidy.sourceforge.net/, and a // quick reference to the configuration options exists at // http://tidy.sourceforge.net/docs/quickref.html // // * But were afraid to ask // // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). word-2000: yes clean: no drop-font-tags: yes doctype: auto drop-empty-paras: yes drop-proprietary-attributes: yes enclose-block-text: yes enclose-text: yes escape-cdata: yes logical-emphasis: yes indent: auto indent-spaces: 2 break-before-br: yes output-xhtml: yes force-output: yes openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/0000755000175000017500000000000011724401447030133 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/img/0000755000175000017500000000000011724401447030707 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/img/ed_charmap.gif0000644000175000017500000000021710177203650033456 0ustar frankiefrankieGIF89a¢ÿÿÿÀÀÀ€€€ÿ€€ÿÿÿÿ!ù,TxºÜÞ">ƒ•³†Á¯ ÀÅ ‚|Œz¥èѾ¦ ÆRE@¿B$'3f‘ ¸;ö|‚§hYŽÐèPgíÝ’"×ô Od%˜ù̳ßð8<;openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/lang/0000755000175000017500000000000011724401447031054 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/lang/de.js0000644000175000017500000000104310177203650031775 0ustar frankiefrankie// I18N constants // LANG: "de", ENCODING: UTF-8 | ISO-8859-1 // Sponsored by http://www.systemconcept.de // Author: Holger Hees, // // (c) systemconcept.de 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). CharacterMap.I18N = { "CharacterMapTooltip" : "Sonderzeichen einfügen", "Insert special character" : "Sonderzeichen einfügen", "HTML value:" : "HTML Wert:", "Cancel" : "Abbrechen" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/lang/en.js0000644000175000017500000000104510177203650032011 0ustar frankiefrankie// I18N constants // LANG: "en", ENCODING: UTF-8 | ISO-8859-1 // Sponsored by http://www.systemconcept.de // Author: Holger Hees, // // (c) systemconcept.de 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). CharacterMap.I18N = { "CharacterMapTooltip" : "Insert special character", "Insert special character" : "Insert special character", "HTML value:" : "HTML value:", "Cancel" : "Cancel" }; openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/character-map.js0000644000175000017500000000416410177203650033202 0ustar frankiefrankie// Character Map plugin for HTMLArea // Sponsored by http://www.systemconcept.de // Implementation by Holger Hees based on HTMLArea XTD 1.5 (http://mosforge.net/projects/htmlarea3xtd/) // Original Author - Bernhard Pfeifer novocaine@gmx.net // // (c) systemconcept.de 2004 // Distributed under the same terms as HTMLArea itself. // This notice MUST stay intact for use (see license.txt). function CharacterMap(editor) { this.editor = editor; var cfg = editor.config; var toolbar = cfg.toolbar; var self = this; var i18n = CharacterMap.I18N; cfg.registerButton({ id : "insertcharacter", tooltip : i18n["CharacterMapTooltip"], image : editor.imgURL("ed_charmap.gif", "CharacterMap"), textMode : false, action : function(editor) { self.buttonPress(editor); } }) var a, i, j, found = false; for (i = 0; !found && i < toolbar.length; ++i) { a = toolbar[i]; for (j = 0; j < a.length; ++j) { if (a[j] == "inserthorizontalrule") { found = true; break; } } } if (found) a.splice(j, 0, "insertcharacter"); else{ toolbar[1].splice(0, 0, "separator"); toolbar[1].splice(0, 0, "insertcharacter"); } }; CharacterMap._pluginInfo = { name : "CharacterMap", version : "1.0", developer : "Holger Hees & Bernhard Pfeifer", developer_url : "http://www.systemconcept.de/", c_owner : "Holger Hees & Bernhard Pfeifer", sponsor : "System Concept GmbH & Bernhard Pfeifer", sponsor_url : "http://www.systemconcept.de/", license : "htmlArea" }; CharacterMap.prototype.buttonPress = function(editor) { editor._popupDialog( "plugin://CharacterMap/select_character", function( entity ) { if ( !entity ) { //user must have pressed Cancel return false; } editor.insertHTML( entity ); }, null); } openacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/popups/0000755000175000017500000000000011575225612031463 5ustar frankiefrankie././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/popups/select_character.htmlopenacs-5.7.0/packages/acs-templating/www/resources/htmlarea/plugins/CharacterMap/popups/select_char0000644000175000017500000004057310177203651033667 0ustar frankiefrankie Insert special character
    HTML value:
    Ÿ š @ " ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬
    ¯ ° ± ² ³ ´ µ · ¸ ¹ º » ¼ ½ ¾
    ¿ × Ø ÷ ø ƒ ˆ ˜
    À Á Â Ã Ä Å Æ
    Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö
    ® × Ù Ú Û Ü Ý Þ ß à á â ã ä å æ
    ç è é ê ë ì í î ï ð ñ ò ó ô õ ö
    ÷ ø ù ú û ü ý þ ÿ Œ œ Š        

    openacs-5.7.0/packages/acs-templating/www/resources/calendar.gif0000644000175000017500000000034410440426474024565 0ustar frankiefrankieGIF89a³ÒÒÔ¦¦«nptõõõ––èèè,,,N†¿Ëẹ¹4]zcª‡‡‡YYY»»»ÿÿÿ!ù,‘ðÉIkm*ëÛ=K(ŽG“P&áI¬+a¢ÎSßv>O ãøÀŸp'iàŽ@Ap⃄€Àðµ„Á%0œÂàÀ0 Eì@à@8f@±A¯ ²ðM€ot= phˆL gIrx €*‹KyJV- ‹ŸV±²;openacs-5.7.0/packages/acs-templating/www/resources/bullet.gif0000644000175000017500000000007610226756425024311 0ustar frankiefrankieGIF89a€îîî!ù,Œ©Ëí£œ´.€):Û†âHB;openacs-5.7.0/packages/acs-templating/www/resources/tinymce/0000755000175000017500000000000011724401447023773 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/0000755000175000017500000000000011575225620025635 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/0000755000175000017500000000000011575225665027455 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/0000755000175000017500000000000011724401447030547 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/be.js0000644000175000017500000003572211526350525031504 0ustar frankiefrankietinyMCE.addI18n({be:{common:{more_colors:"\u0411\u043e\u043b\u044c\u0448 \u043a\u043e\u043b\u0435\u0440\u0430\u045e",invalid_data:"\u041f\u0430\u043c\u044b\u043b\u043a\u0430: \u0410\u0434\u0437\u043d\u0430\u0447\u0430\u043d\u044b\u044f \u0447\u044b\u0440\u0432\u043e\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u044d\u043d\u043d\u0456 \u045e\u0432\u0435\u0434\u0437\u0435\u043d\u044b\u044f \u043d\u044f\u043f\u0440\u0430\u0432\u0456\u043b\u044c\u043d\u0430.",popup_blocked:"\u0412\u044b\u0431\u0430\u0447\u044b\u0446\u0435, \u0430\u043b\u0435 \u0432\u0430\u0448 \u0431\u043b\u0430\u043a\u0430\u0432\u0430\u043b\u044c\u043d\u0456\u043a \u0443\u0441\u043f\u043b\u044b\u0432\u0430\u043b\u044c\u043d\u044b\u0445 \u0432\u043e\u043a\u043d\u0430\u045e \u0437\u0430\u0431\u043b\u0430\u043a\u0430\u0432\u0430\u045e \u0430\u043a\u043d\u043e, \u044f\u043a\u043e\u0435 \u043f\u0440\u0430\u0434\u0441\u0442\u0430\u045e\u043b\u044f\u0435 \u0444\u0443\u043d\u043a\u0446\u044b\u0456 \u043f\u0440\u044b\u043a\u043b\u0430\u0434\u0430\u043d\u043d\u044f. \u0412\u0430\u043c \u0442\u0440\u044d\u0431\u0430 \u0430\u0434\u043a\u043b\u044e\u0447\u044b\u0446\u044c \u0431\u043b\u0430\u043a\u0430\u0432\u0430\u043d\u043d\u0435 \u045e\u0441\u043f\u043b\u044b\u0432\u0430\u043b\u044c\u043d\u044b\u0445 \u0432\u043e\u043a\u043d\u0430\u045e \u043d\u0430 \u0433\u044d\u0442\u044b\u043c \u0441\u0430\u0439\u0446\u0435, \u043a\u0430\u0431 \u043f\u0430\u045e\u043d\u0430\u0432\u0430\u0440\u0442\u0430\u0441\u043d\u0430 \u0441\u043a\u0430\u0440\u044b\u0441\u0442\u0430\u0446\u0446\u0430 \u0433\u044d\u0442\u0430\u0439 \u043f\u0440\u044b\u043b\u0430\u0434\u0430\u0439.",clipboard_no_support:"\u041d\u0435 \u043f\u0430\u0434\u0442\u0440\u044b\u043c\u043b\u0456\u0432\u0430\u0435\u0446\u0446\u0430 \u0432\u0430\u0448\u044b\u043c \u0431\u0440\u0430\u045e\u0437\u044d\u0440\u0430\u043c \u0443 \u0441\u0430\u043f\u0440\u0430\u045e\u0434\u043d\u044b \u043c\u043e\u043c\u0430\u043d\u0442, \u0432\u044b\u043a\u0430\u0440\u044b\u0441\u0442\u0430\u0439\u0446\u0435 \u043a\u043b\u0430\u0432\u0456\u044f\u0442\u0443\u0440\u043d\u044b\u044f \u0441\u043a\u0430\u0440\u0430\u0447\u044d\u043d\u043d\u0456.",clipboard_msg:"\u041a\u0430\u043f\u0456\u044f\u0432\u0430\u043d\u043d\u0435/\u0423\u0441\u0442\u0430\u045e\u043a\u0430 \u043d\u0435 \u043f\u0440\u0430\u0446\u0443\u0435 \u045e Mozilla \u0456 Firefox.\\n\u0416\u0430\u0434\u0430\u0435\u0446\u0435 \u043f\u0430\u0434\u0440\u0430\u0431\u044f\u0437\u043d\u0435\u0439 \u043f\u0430\u0437\u043d\u0430\u0446\u044c, \u0443 \u0447\u044b\u043c \u0441\u043f\u0440\u0430\u0432\u0430?",not_set:"-- \u041d\u0435 \u045e\u0441\u0442\u0430\u043b\u044f\u0432\u0430\u043d\u0430 --",class_name:"\u041a\u043b\u0430\u0441",browse:"\u041f\u0440\u0430\u0433\u043b\u0435\u0434\u0437\u0435\u0446\u044c",close:"\u0417\u0430\u0447\u044b\u043d\u0456\u0446\u044c",cancel:"\u0410\u0434\u043c\u044f\u043d\u0456\u0446\u044c",update:"\u0410\u0431\u043d\u0430\u0432\u0456\u0446\u044c",insert:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c",apply:"\u0423\u0436\u044b\u0446\u044c",edit_confirm:"\u0412\u044b \u0436\u0430\u0434\u0430\u0435\u0446\u0435 \u0432\u044b\u043a\u0430\u0440\u044b\u0441\u0442\u0430\u0446\u044c \u0434\u043b\u044f \u0433\u044d\u0442\u0430\u0439 \u0442\u044d\u043a\u0441\u0442\u0430\u0432\u0430\u0439 \u0432\u043e\u0431\u043b\u0430\u0441\u0446\u0456 \u0440\u044d\u0436\u044b\u043c WYSIWYG?"},contextmenu:{full:"\u0426\u0430\u043b\u043a\u0430\u043c",right:"\u041d\u0430\u043f\u0440\u0430\u0432\u0430",center:"\u041f\u0430 \u0446\u044d\u043d\u0442\u0440\u044b",left:"\u041d\u0430\u043b\u0435\u0432\u0430",align:"\u0412\u044b\u0440\u0430\u045e\u043d\u043e\u045e\u0432\u0430\u043d\u043d\u0435"},insertdatetime:{day_short:"\u041d\u0434,\u041f\u043d,\u0410\u0442,\u0410\u0441,\u0427\u0446,\u041f\u0442,\u0421\u0431,\u041d\u0434",day_long:"\u041d\u044f\u0434\u0437\u0435\u043b\u044f,\u041f\u0430\u043d\u044f\u0434\u0437\u0435\u043b\u0430\u043a,\u0410\u045e\u0442\u043e\u0440\u0430\u043a,\u0410\u0441\u044f\u0440\u043e\u0434\u0434\u0437\u0435,\u0427\u0430\u0446\u0432\u0435\u0440,\u041f\u044f\u0442\u043d\u0456\u0446\u0430,\u0421\u0443\u0431\u043e\u0442\u0430,\u041d\u044f\u0434\u0437\u0435\u043b\u044f",months_short:"\u0421\u0442\u0443,\u041b\u044e\u0442,\u0421\u0430\u043a,\u041a\u0440\u0430,\u0422\u0440\u0430,\u0427\u044d\u0440,\u041b\u0456\u043f,\u0410\u045e\u0433,\u0412\u0435\u0440,\u041a\u0430\u0441,\u041b\u0456\u0441,\u0421\u043d\u0435",months_long:"\u0421\u0442\u0443\u0434\u0437\u0435\u043d\u044c,\u041b\u044e\u0442\u044b,\u0421\u0430\u043a\u0430\u0432\u0456\u043a,\u041a\u0440\u0430\u0441\u0430\u0432\u0456\u043a,\u0422\u0440\u0430\u0432\u0435\u043d\u044c,\u0427\u044d\u0440\u0432\u0435\u043d\u044c,\u041b\u0456\u043f\u0435\u043d\u044c,\u0410\u045e\u0433\u0443\u0441\u0442,\u0412\u0435\u0440\u0430\u0441\u0435\u043d\u044c,\u041a\u0430\u0441\u0442\u0440\u044b\u0447\u043d\u0456\u043a,\u041b\u0456\u0441\u0442\u0430\u043f\u0430\u0434,\u0421\u043d\u0435\u0436\u0430\u043d\u044c",inserttime_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0447\u0430\u0441",insertdate_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0434\u0430\u0442\u0443",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"\u0414\u0440\u0443\u043a"},preview:{preview_desc:"\u041f\u0430\u043f\u044f\u0440\u044d\u0434\u043d\u0456 \u043f\u0440\u0430\u0433\u043b\u044f\u0434"},directionality:{rtl_desc:"\u041a\u0456\u0440\u0443\u043d\u0430\u043a \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u0430",ltr_desc:"\u041a\u0456\u0440\u0443\u043d\u0430\u043a \u0437\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u0430"},layer:{content:"\u041d\u043e\u0432\u044b \u043f\u043b\u0430\u0441\u0442\u2026",absolute_desc:"\u0423\u043b\u0443\u0447\u044b\u0446\u044c/\u0432\u044b\u043a\u043b\u044e\u0447\u044b\u0446\u044c \u0430\u0431\u0441\u0430\u043b\u044e\u0442\u043d\u0430\u0435 \u043f\u0430\u0437\u0456\u0446\u044b\u044f\u043d\u0430\u0432\u0430\u043d\u043d\u0435",backward_desc:"\u041f\u0435\u0440\u0430\u043d\u0435\u0441\u0446\u0456 \u043d\u0430\u0437\u0430\u0434",forward_desc:"\u041f\u0435\u0440\u0430\u043d\u0435\u0441\u0446\u0456 \u043d\u0430\u043f\u0435\u0440\u0430\u0434",insertlayer_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u043d\u043e\u0432\u044b \u043f\u043b\u0430\u0441\u0442"},save:{save_desc:"\u0417\u0430\u0445\u0430\u0432\u0430\u0446\u044c",cancel_desc:"\u0410\u0434\u043c\u044f\u043d\u0456\u0446\u044c \u0443\u0441\u0435 \u0437\u043c\u0435\u043d\u044b"},nonbreaking:{nonbreaking_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u043d\u0435\u043f\u0430\u0440\u044b\u045e\u043d\u044b \u043f\u0440\u0430\u0431\u0435\u043b"},iespell:{download:"ieSpell \u043d\u0435 \u0432\u044b\u044f\u045e\u043b\u0435\u043d\u044b. \u0423\u0441\u0442\u0430\u043b\u044f\u0432\u0430\u0446\u044c?",iespell_desc:"\u041f\u0440\u0430\u0432\u0435\u0440\u044b\u0446\u044c \u0430\u0440\u0444\u0430\u0433\u0440\u0430\u0444\u0456\u044e"},advhr:{advhr_desc:"\u0413\u0430\u0440\u044b\u0437\u0430\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u0456\u043d\u0456\u044f",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0421\u043c\u0430\u0439\u043b\u0456\u043a\u0456",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0417\u043d\u0430\u0439\u0441\u0446\u0456/\u0417\u0430\u043c\u044f\u043d\u0456\u0446\u044c",search_desc:"\u0417\u043d\u0430\u0439\u0441\u0446\u0456",delta_width:"",delta_height:""},advimage:{image_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c/\u0440\u044d\u0434\u0430\u0433\u0430\u0432\u0430\u0446\u044c \u043c\u0430\u043b\u044e\u043d\u0430\u043a",delta_width:"",delta_height:""},advlink:{link_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c/\u0440\u044d\u0434\u0430\u0433\u0430\u0432\u0430\u0446\u044c \u0441\u043f\u0430\u0441\u044b\u043b\u043a\u0443",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c/\u0440\u044d\u0434\u0430\u0433\u0430\u0432\u0430\u0446\u044c \u0430\u0442\u0440\u044b\u0431\u0443\u0442\u044b",ins_desc:"\u0414\u0430\u0434\u0430\u0434\u0437\u0435\u043d\u044b \u0442\u044d\u043a\u0441\u0442",del_desc:"\u0412\u044b\u0434\u0430\u043b\u0435\u043d\u044b \u0442\u044d\u043a\u0441\u0442",acronym_desc:"\u0410\u043a\u0440\u043e\u043d\u0456\u043c",abbr_desc:"\u0410\u0431\u0440\u044d\u0432\u0456\u044f\u0442\u0443\u0440\u0430",cite_desc:"\u0412\u044b\u043d\u044f\u0442\u043a\u0430",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{delta_width:"35",desc:"\u0420\u044d\u0434\u0430\u0433\u0430\u0432\u0430\u0446\u044c \u0441\u0442\u044b\u043b\u044c CSS",delta_height:""},paste:{selectall_desc:"\u0412\u044b\u043b\u0443\u0447\u044b\u0446\u044c \u0443\u0441\u0451",paste_word_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0437 Word",paste_text_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u044f\u043a \u043f\u0440\u043e\u0441\u0442\u044b \u0442\u044d\u043a\u0441\u0442",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u0412\u044b\u043a\u0430\u0440\u044b\u0441\u0442\u0430\u0439\u0446\u0435 \u0441\u043f\u0430\u043b\u0443\u0447\u044d\u043d\u043d\u0435 \u043a\u043b\u0430\u0432\u0456\u0448 CTRL+V \u043a\u0430\u0431 \u0443\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0442\u044d\u043a\u0441\u0442 \u0443 \u0430\u043a\u043d\u043e.",text_linebreaks:"\u0417\u0430\u0445\u043e\u045e\u0432\u0430\u0446\u044c \u043f\u0430\u0440\u044b\u0432\u044b \u0440\u0430\u0434\u043a\u043e\u045e",text_title:"\u0412\u044b\u043a\u0430\u0440\u044b\u0441\u0442\u0430\u0439\u0446\u0435 \u0441\u043f\u0430\u043b\u0443\u0447\u044d\u043d\u043d\u0435 \u043a\u043b\u0430\u0432\u0456\u0448 CTRL+V \u043a\u0430\u0431 \u0443\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0442\u044d\u043a\u0441\u0442 \u0443 \u0430\u043a\u043d\u043e."},table:{cell:"\u0412\u043e\u0447\u043a\u0430",col:"\u0421\u043b\u0443\u043f\u043e\u043a",row:"\u0420\u0430\u0434\u043e\u043a",del:"\u0412\u044b\u0434\u0430\u043b\u0456\u0446\u044c \u0442\u0430\u0431\u043b\u0456\u0446\u0443",copy_row_desc:"\u041a\u0430\u043f\u0456\u044f\u0432\u0430\u0446\u044c \u0440\u0430\u0434\u043e\u043a",cut_row_desc:"\u0412\u044b\u0440\u0430\u0437\u0430\u0446\u044c \u0440\u0430\u0434\u043e\u043a",paste_row_after_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0440\u0430\u0434\u043e\u043a \u0442\u0430\u0431\u043b\u0456\u0446\u044b \u043f\u0430\u0441\u043b\u044f",paste_row_before_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0440\u0430\u0434\u043e\u043a \u0442\u0430\u0431\u043b\u0456\u0446\u044b \u043f\u0435\u0440\u0430\u0434",props_desc:"\u0423\u043b\u0430\u0441\u0446\u0456\u0432\u0430\u0441\u0446\u0456 \u0442\u0430\u0431\u043b\u0456\u0446\u044b",cell_desc:"\u0423\u043b\u0430\u0441\u0446\u0456\u0432\u0430\u0441\u0446\u0456 \u0432\u043e\u0447\u043a\u0430",row_desc:"\u0423\u043b\u0430\u0441\u0446\u0456\u0432\u0430\u0441\u0446\u0456 \u0440\u0430\u0434\u043a\u0430",merge_cells_desc:"\u0421\u043a\u043b\u0435\u0456\u0446\u044c \u0432\u043e\u0447\u043a\u0456",split_cells_desc:"\u041f\u0430\u0434\u0437\u044f\u043b\u0456\u0446\u044c \u0437\u043b\u0435\u043f\u043b\u0435\u043d\u044b\u044f \u0432\u043e\u0447\u043a\u0456",delete_col_desc:"\u0412\u044b\u0434\u0430\u043b\u0456\u0446\u044c \u0441\u043b\u0443\u043f\u043e\u043a",col_after_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0441\u043b\u0443\u043f\u043e\u043a \u043f\u0430\u0441\u043b\u044f",col_before_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0441\u043b\u0443\u043f\u043e\u043a \u043f\u0435\u0440\u0430\u0434",delete_row_desc:"\u0412\u044b\u0434\u0430\u043b\u0456\u0446\u044c \u0440\u0430\u0434\u043e\u043a",row_after_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0440\u0430\u0434\u043e\u043a \u043f\u0430\u0441\u043b\u044f",row_before_desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u0440\u0430\u0434\u043e\u043a \u043f\u0435\u0440\u0430\u0434",desc:"\u0423\u0441\u0442\u0430\u045e\u043b\u044f\u0435 \u043d\u043e\u0432\u0443\u044e \u0442\u0430\u0431\u043b\u0456\u0446\u0443",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u0417\u0430\u043d\u0435\u0441\u0435\u043d\u044b\u044f \u0437\u043c\u0435\u043d\u044b \u0431\u0443\u0434\u0443\u0446\u044c \u0441\u0442\u0440\u0430\u0447\u0430\u043d\u044b\u044f, \u043a\u0430\u043b\u0456 \u0432\u044b \u0441\u044b\u0434\u0437\u0435\u0446\u0435 \u0437 \u0433\u044d\u0442\u0430\u0439 \u0441\u0442\u0430\u0440\u043e\u043d\u043a\u0456.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u0423\u043b\u0443\u0447\u044b\u0446\u044c/\u0432\u044b\u043a\u043b\u044e\u0447\u044b\u0446\u044c \u043f\u043e\u045e\u043d\u0430\u044d\u043a\u0440\u0430\u043d\u043d\u044b \u0440\u044d\u0436\u044b\u043c"},media:{edit:"\u0420\u044d\u0434\u0430\u0433\u0430\u0432\u0430\u0446\u044c \u043c\u0435\u0434\u044b\u044f-\u0430\u0431\'\u0435\u043a\u0442",desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c/\u0440\u044d\u0434\u0430\u0433\u0430\u0432\u0430\u0446\u044c \u043c\u0435\u0434\u044b\u044f-\u0430\u0431\'\u0435\u043a\u0442",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"\u041f\u0440\u0430\u0432\u0435\u0440\u044b\u0446\u044c \u0430\u0440\u0444\u0430\u0433\u0440\u0430\u0444\u0456\u044e",menu:"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u0440\u0430\u0432\u0435\u0440\u043a\u0456 \u0430\u0440\u0444\u0430\u0433\u0440\u0430\u0444\u0456\u0456",ignore_word:"\u0406\u0433\u043d\u0430\u0440\u0430\u0432\u0430\u0446\u044c \u0441\u043b\u043e\u0432\u0430",ignore_words:"\u0406\u0433\u043d\u0430\u0440\u0430\u0432\u0430\u0446\u044c \u0443\u0441\u0451",langs:"\u041c\u043e\u0432\u044b",wait:"\u041a\u0430\u043b\u0456 \u043b\u0430\u0441\u043a\u0430, \u043f\u0430\u0447\u0430\u043a\u0430\u0439\u0446\u0435...",sug:"\u0412\u0430\u0440\u044b\u044f\u043d\u0442\u044b",no_sug:"\u041d\u044f\u043c\u0430 \u0432\u0430\u0440\u044b\u044f\u043d\u0442\u0430\u045e",no_mpell:"\u041f\u0430\u043c\u044b\u043b\u0430\u043a \u043d\u0435 \u0432\u044b\u044f\u045e\u043b\u0435\u043d\u0430."},pagebreak:{desc:"\u0423\u0441\u0442\u0430\u0432\u0456\u0446\u044c \u043f\u0430\u0434\u0437\u0435\u043b\u044c\u043d\u0456\u043a \u0441\u0442\u0430\u0440\u043e\u043d\u043a\u0456."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/bg.js0000644000175000017500000004106611526350525031504 0ustar frankiefrankietinyMCE.addI18n({bg:{common:{more_colors:"\u041e\u0449\u0435 \u0446\u0432\u0435\u0442\u043e\u0432\u0435",invalid_data:"\u0413\u0440\u0435\u0448\u043a\u0430: \u0412\u044a\u0432\u0435\u0434\u0435\u043d\u0438 \u0441\u0430 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u0438 \u0441\u0442\u043e\u0439\u043d\u043e\u0441\u0442\u0438, \u0442\u0435 \u0441\u0430 \u043c\u0430\u0440\u043a\u0438\u0440\u0430\u043d\u0438 \u0432 \u0447\u0435\u0440\u0432\u0435\u043d\u043e.",popup_blocked:"\u0421\u044a\u0436\u0430\u043b\u044f\u0432\u0430\u043c\u0435, \u043d\u043e \u0437\u0430\u0431\u0435\u043b\u044f\u0437\u0430\u0445\u043c\u0435, \u0447\u0435 \u0432\u0430\u0448\u0438\u044f\u0442 popup-blocker \u0435 \u0441\u043f\u0440\u044f\u043b \u043f\u0440\u043e\u0437\u043e\u0440\u0435\u0446 \u043a\u043e\u0439\u0442\u043e \u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u043e\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430\u0442\u0430. \u0429\u0435 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0438\u0437\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u043f\u043e\u043f\u044a\u043f\u0438 \u0437\u0430 \u0442\u043e\u0437\u0438 \u0441\u0430\u0439\u0442 \u0437\u0430 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u043f\u044a\u043b\u043d\u0430\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043d\u043e\u0441\u0442.",clipboard_no_support:"\u041d\u0435 \u0441\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u043e\u0442 \u0432\u0430\u0448\u0438\u044f\u0442 \u0431\u0440\u0430\u0443\u0437\u044a\u0440, \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043d\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u0438.",clipboard_msg:"\u041a\u043e\u043f\u0438\u0440\u0430\u043d\u0435/\u041e\u0442\u0440\u044f\u0437\u0432\u0430\u043d\u0435/\u041f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435 \u043d\u0435 \u0435 \u0434\u043e\u0441\u0442\u044a\u043f\u043d\u043e \u043f\u043e\u0434 Mozilla \u0438 Firefox.\\n\u0416\u0435\u043b\u0430\u0435\u0442\u0435 \u043b\u0438 \u043f\u043e\u0432\u0435\u0447\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430?",not_set:"-- \u041d\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u043e --",class_name:"\u041a\u043b\u0430\u0441",browse:"Browse",close:"\u0417\u0430\u0442\u0432\u043e\u0440\u0438",cancel:"\u041e\u0442\u043a\u0430\u0436\u0438",update:"\u041e\u0431\u043d\u043e\u0432\u0438",insert:"\u0412\u043c\u044a\u043a\u043d\u0438",apply:"\u041f\u043e\u0442\u0432\u044a\u0440\u0434\u0438",edit_confirm:"\u0418\u0441\u043a\u0430\u0442\u0435 \u043b\u0438 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 WYSIWYG \u0440\u0435\u0436\u0438\u043c \u0437\u0430 \u0442\u043e\u0432\u0430 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e \u043f\u043e\u043b\u0435?"},contextmenu:{full:"\u0414\u0432\u0443\u0441\u0442\u0440\u0430\u043d\u043d\u043e",right:"\u0414\u044f\u0441\u043d\u043e",center:"\u0426\u0435\u043d\u0442\u044a\u0440",left:"\u041b\u044f\u0432\u043e",align:"\u041f\u043e\u0434\u0440\u0430\u0432\u043d\u044f\u0432\u0430\u043d\u0435"},insertdatetime:{day_short:"\u041d\u0434,\u041f\u043d,\u0412\u0442,\u0421\u0440,\u0427\u0442,\u041f\u0442,\u0421\u0431,\u041d\u0434",day_long:"\u041d\u0435\u0434\u0435\u043b\u044f,\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u043d\u0438\u043a,\u0412\u0442\u043e\u0440\u043d\u0438\u043a,\u0421\u0440\u044f\u0434\u0430,\u0427\u0435\u0442\u0432\u044a\u0440\u0442\u044a\u043a,\u041f\u0435\u0442\u044a\u043a,\u0421\u044a\u0431\u043e\u0442\u0430,\u041d\u0435\u0434\u0435\u043b\u044f",months_short:"\u042f\u043d\u0443,\u0424\u0435\u0432,\u041c\u0430\u0440,\u0410\u043f\u0440,\u041c\u0430\u0439,\u042e\u043d\u0438,\u042e\u043b\u0438,\u0410\u0432\u0433,\u0421\u0435\u043f,\u041e\u043a\u0442,\u041d\u043e\u0435,\u0414\u0435\u043a",months_long:"\u042f\u043d\u0443\u0430\u0440\u0438,\u0424\u0435\u0432\u0440\u0443\u0430\u0440\u0438,\u041c\u0430\u0440\u0442,\u0410\u043f\u0440\u0438\u043b,\u041c\u0430\u0439,\u042e\u043d\u0438,\u042e\u043b\u0438,\u0410\u0432\u0433\u0443\u0441\u0442,\u0421\u0435\u043f\u0442\u0435\u043c\u0432\u0440\u0438,\u041e\u043a\u0442\u043e\u043c\u0432\u0440\u0438,\u041d\u043e\u0435\u043c\u0432\u0440\u0438,\u0414\u0435\u043a\u0435\u043c\u0432\u0440\u0438",inserttime_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u0432\u0440\u0435\u043c\u0435",insertdate_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u0434\u0430\u0442\u0430",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u041e\u0442\u043f\u0435\u0447\u0430\u0442\u0430\u0439"},preview:{preview_desc:"\u041f\u0440\u0435\u0433\u043b\u0435\u0434"},directionality:{rtl_desc:"\u041f\u043e\u0441\u043e\u043a\u0430 \u043e\u0442\u0434\u044f\u0441\u043d\u043e \u043d\u0430 \u043b\u044f\u0432\u043e",ltr_desc:"\u041f\u043e\u0441\u043e\u043a\u0430 \u043e\u0442\u043b\u044f\u0432\u043e \u043d\u0430 \u0434\u044f\u0441\u043d\u043e"},layer:{content:"\u041d\u043e\u0432 \u0441\u043b\u043e\u0439...",absolute_desc:"\u0412\u043a\u043b\u044e\u0447\u0438 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u0430\u043d\u0435",backward_desc:"\u041f\u043e\u043a\u0430\u0436\u0438 \u043e\u0442\u0437\u0430\u0434",forward_desc:"\u041f\u043e\u043a\u0430\u0436\u0438 \u043e\u0442\u043f\u0440\u0435\u0434",insertlayer_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u043d\u043e\u0432 \u0441\u043b\u043e\u0439"},save:{save_desc:"\u0417\u0430\u043f\u0438\u0448\u0438",cancel_desc:"\u041e\u0442\u043a\u0430\u0436\u0438 \u0432\u0441\u0438\u0447\u043a\u0438 \u043f\u0440\u043e\u043c\u0435\u043d\u0438"},nonbreaking:{nonbreaking_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u043d\u0435\u043f\u0440\u0435\u043a\u044a\u0441\u0432\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b"},iespell:{download:"ieSpell \u043d\u0435 \u0435 \u043e\u0442\u043a\u0440\u0438\u0442. \u0416\u0435\u043b\u0430\u0435\u0442\u0435 \u043b\u0438 \u0434\u0430 \u0433\u043e \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u0442\u0435 \u0441\u0435\u0433\u0430?",iespell_desc:"\u041f\u0440\u043e\u0432\u0435\u0440\u0438 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430"},advhr:{advhr_desc:"\u0425\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u043d\u0430 \u043b\u0438\u043d\u0438\u044f",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0415\u043c\u043e\u0442\u0438\u043a\u043e\u043d\u0438",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0422\u044a\u0440\u0441\u0438/\u0417\u0430\u043c\u0435\u0441\u0442\u0438",search_desc:"\u0422\u044a\u0440\u0441\u0438",delta_width:"",delta_height:""},advimage:{image_desc:"\u0412\u043c\u044a\u043a\u043d\u0438/\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430",delta_width:"",delta_height:""},advlink:{link_desc:"\u0412\u043c\u044a\u043a\u043d\u0438/\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0430",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u0412\u043c\u044a\u043a\u043d\u0438/\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0438",ins_desc:"\u0412\u043c\u044a\u043a\u0432\u0430\u043d\u0435",del_desc:"\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435",acronym_desc:"\u0410\u043a\u0440\u043e\u043d\u0438\u043c",abbr_desc:"\u0421\u044a\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435",cite_desc:"\u0426\u0438\u0442\u0430\u0442",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439 CSS \u0441\u0442\u0438\u043b",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u041f\u043e\u0441\u0442\u0430\u0432\u0435\u043d\u043e\u0442\u043e \u0435 \u0432 \u0438\u0437\u0447\u0438\u0441\u0442\u0435\u043d \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0440\u0435\u0436\u0438\u043c. \u0429\u0440\u0430\u043a\u043d\u0435\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e \u0434\u0430 \u043f\u0440\u0435\u043c\u0438\u043d\u0435\u0442\u0435 \u0432 \u043e\u0431\u0438\u043a\u043d\u043e\u0432\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043d\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435.",plaintext_mode_sticky:"\u041f\u043e\u0441\u0442\u0430\u0432\u0435\u043d\u043e\u0442\u043e \u0435 \u0432 \u0438\u0437\u0447\u0438\u0441\u0442\u0435\u043d \u0442\u0435\u043a\u0441\u0442\u043e\u0432 \u0440\u0435\u0436\u0438\u043c. \u0429\u0440\u0430\u043a\u043d\u0435\u0442\u0435 \u043e\u0442\u043d\u043e\u0432\u043e \u0434\u0430 \u043f\u0440\u0435\u043c\u0438\u043d\u0435\u0442\u0435 \u0432 \u043e\u0431\u0438\u043a\u043d\u043e\u0432\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043d\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435. \u0421\u043b\u0435\u0434 \u043a\u0430\u0442\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u0435 \u0435\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0449\u0435 \u0441\u0435 \u0432\u044a\u0440\u043d\u0435\u0442\u0435 \u0432 \u043d\u043e\u0440\u043c\u0430\u043b\u0435\u043d \u0440\u0435\u0436\u0438\u043c.",selectall_desc:"\u0418\u0437\u0431\u0435\u0440\u0438 \u0432\u0441\u0438\u0447\u043a\u0438",paste_word_desc:"\u041f\u043e\u0441\u0442\u0430\u0432\u0438 \u043e\u0442 Word",paste_text_desc:"\u041f\u043e\u0441\u0442\u0430\u0432\u0438 \u043a\u0430\u0442\u043e \u0442\u0435\u043a\u0441\u0442"},paste_dlg:{word_title:"\u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 CTRL+V \u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430\u0442\u0430 \u0437\u0430 \u0434\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043f\u0440\u043e\u0437\u043e\u0440\u0435\u0446\u0430.",text_linebreaks:"\u0417\u0430\u043f\u0430\u0437\u0438 \u043d\u043e\u0432\u0438\u0442\u0435 \u0440\u0435\u0434\u043e\u0432\u0435",text_title:"\u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 CTRL+V \u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430\u0442\u0430 \u0437\u0430 \u0434\u0430 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043f\u0440\u043e\u0437\u043e\u0440\u0435\u0446\u0430."},table:{cell:"\u041a\u043b\u0435\u0442\u043a\u0430",col:"\u041a\u043e\u043b\u043e\u043d\u0430",row:"\u0420\u0435\u0434",del:"\u0418\u0437\u0442\u0440\u0438\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0430",copy_row_desc:"\u041a\u043e\u043f\u0438\u0440\u0430\u0439 \u0440\u0435\u0434",cut_row_desc:"\u041e\u0442\u0440\u0435\u0436\u0438 \u0440\u0435\u0434",paste_row_after_desc:"\u041f\u043e\u0441\u0442\u0430\u0432\u0438 \u0440\u0435\u0434 \u0441\u043b\u0435\u0434",paste_row_before_desc:"\u041f\u043e\u0441\u0442\u0430\u0432\u0438 \u0440\u0435\u0434 \u043f\u0440\u0435\u0434\u0438",props_desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0442\u0430",cell_desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u043a\u043b\u0435\u0442\u043a\u0430\u0442\u0430",row_desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0440\u0435\u0434\u0430",merge_cells_desc:"\u0421\u043b\u0435\u0439 \u043a\u043b\u0435\u0442\u043a\u0438",split_cells_desc:"\u0420\u0430\u0437\u0434\u0435\u043b\u0438 \u0441\u043b\u0435\u0442\u0438 \u043a\u043b\u0435\u0442\u043a\u0438",delete_col_desc:"\u0418\u0437\u0442\u0440\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0430",col_after_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u043a\u043e\u043b\u043e\u043d\u0430 \u0441\u043b\u0435\u0434",col_before_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u043a\u043e\u043b\u043e\u043d\u0430 \u043f\u0440\u0435\u0434\u0438",delete_row_desc:"\u0418\u0437\u0442\u0440\u0438\u0439 \u0440\u0435\u0434",row_after_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u0440\u0435\u0434 \u0441\u043b\u0435\u0434",row_before_desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u0440\u0435\u0434 \u043f\u0440\u0435\u0434\u0438",desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u043d\u043e\u0432\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u0412\u0441\u0438\u0447\u043a\u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u0435\u043d\u0438 \u043f\u0440\u043e\u043c\u0435\u043d\u0438 \u0449\u0435 \u0431\u044a\u0434\u0430\u0442 \u0437\u0430\u0433\u0443\u0431\u0435\u043d\u0438.\\n\\n\u0421\u0438\u0433\u0443\u0440\u043d\u0438 \u043b\u0438 \u0441\u0442\u0435, \u0447\u0435 \u0438\u0441\u043a\u0430\u0442\u0435 \u0434\u0430 \u0432\u044a\u0437\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u043e\u0442\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435?.",restore_content:"\u0412\u044a\u0437\u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u043e\u0442\u043e.",unload_msg:"\u041f\u0440\u043e\u043c\u0435\u043d\u0438\u0442\u0435 \u043a\u043e\u0438\u0442\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u0438\u0445\u0442\u0435 \u0449\u0435 \u0441\u0435 \u0437\u0430\u0433\u0443\u0431\u044f\u0442 \u0430\u043a\u043e \u043e\u0442\u0438\u0434\u0435\u0442\u0435 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430."},fullscreen:{desc:"\u0412\u043a\u043b./\u0418\u0437\u043a\u043b. \u0446\u044f\u043b \u0435\u043a\u0440\u0430\u043d"},media:{edit:"\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u043a \u043c\u0435\u0434\u0438\u0430",desc:"\u0412\u043c\u044a\u043a\u043d\u0438/\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0430\u0439 \u043c\u0435\u0434\u0438\u0430\u0442\u0430",delta_height:"",delta_width:""},fullpage:{desc:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",delta_width:"",delta_height:""},template:{desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442"},visualchars:{desc:"\u0412\u043a\u043b./\u0418\u0437\u043a\u043b. \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u0438."},spellchecker:{desc:"\u0412\u043a\u043b./\u0418\u0437\u043a\u043b. \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430",menu:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u0442\u0430 \u043d\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441",ignore_word:"\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0430\u0439 \u0434\u0443\u043c\u0430",ignore_words:"\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0430\u0439 \u0432\u0441\u0438\u0447\u043a\u0438",langs:"\u0415\u0437\u0438\u0446\u0438",wait:"\u041c\u043e\u043b\u044f \u0438\u0437\u0447\u0430\u043a\u0430\u0439\u0442\u0435...",sug:"\u041f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f",no_sug:"\u041d\u044f\u043c\u0430 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f",no_mpell:"\u041d\u044f\u043c\u0430 \u0433\u0440\u0435\u0448\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438 \u0434\u0443\u043c\u0438."},pagebreak:{desc:"\u0412\u043c\u044a\u043a\u043d\u0438 \u043d\u043e\u0432\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430."},advlist:{types:"\u0421\u0438\u043c\u0432\u043e\u043b\u0438",def:"\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438",lower_alpha:"\u041c\u0430\u043b\u043a\u0438 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438 \u0431\u0443\u043a\u0432\u0438",lower_greek:"\u041c\u0430\u043b\u043a\u0438 \u0433\u0440\u044a\u0446\u043a\u0438 \u0431\u0443\u043a\u0432\u0438",lower_roman:"\u041c\u0430\u043b\u043a\u0438 \u0440\u0438\u043c\u0441\u043a\u0438 \u0446\u0438\u0444\u0440\u0438",upper_alpha:"\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u0438 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438 \u0431\u0443\u043a\u0432\u0438",upper_roman:"\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u0438 \u0440\u0438\u043c\u0441\u043a\u0438 \u0446\u0438\u0444\u0440\u0438",circle:"\u041a\u0440\u044a\u0433",disc:"\u041e\u043a\u0440\u044a\u0436\u043d\u043e\u0441\u0442",square:"\u041a\u0432\u0430\u0434\u0440\u0430\u0442"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ar.js0000644000175000017500000003011711526350525031511 0ustar frankiefrankietinyMCE.addI18n({ar:{common:{more_colors:"\u0627\u0644\u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u0623\u0644\u0648\u0627\u0646",invalid_data:"\u062e\u0637\u0623.: \u062f\u062e\u0644 \u0635\u0627\u0644\u062d \u0627\u0644\u0642\u064a\u0645 \u060c \u0648\u0647\u0630\u0647 \u0647\u064a \u0645\u0639\u0644\u0645\u0629 \u0628\u0627\u0644\u0644\u0648\u0646 \u0627\u0644\u0627\u062d\u0645\u0631",popup_blocked:"\u0639\u0630\u0631\u0627 \u060c \u0644\u0643\u0646 \u0644\u0627\u062d\u0638\u0646\u0627 \u0628\u0623\u0646 \u0645\u0627 \u062a\u062a\u0645\u062a\u0639\u0648\u0646 \u0628\u0647 \u0627\u0644\u0645\u0646\u0628\u062b\u0642\u0629 \u0645\u062d\u0635\u0631 \u0648\u062a\u0639\u0637\u064a\u0644 \u0627\u0644\u0625\u0637\u0627\u0631 \u0627\u0644\u0630\u064a \u064a\u0648\u0641\u0631 \u0648\u0638\u0627\u0626\u0641 \u0627\u0644\u062a\u0637\u0628\u064a\u0642. \u0633\u0648\u0641 \u062a\u062d\u062a\u0627\u062c \u0625\u0644\u0649 \u062a\u0639\u0637\u064a\u0644 \u0627\u0644\u0645\u0646\u0628\u062b\u0642\u0629 \u062d\u0638\u0631 \u0639\u0644\u0649 \u0647\u0630\u0627 \u0627\u0644\u0645\u0648\u0642\u0639 \u0645\u0646 \u0623\u062c\u0644 \u0627\u0644\u0627\u0633\u062a\u0641\u0627\u062f\u0629 \u0627\u0644\u0643\u0627\u0645\u0644\u0629 \u0645\u0646 \u0647\u0630\u0647 \u0627\u0644\u0623\u062f\u0627\u0629",clipboard_no_support:"\u062d\u0627\u0644\u064a\u0627 \u063a\u064a\u0631 \u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 \u0642\u0628\u0644 \u0627\u0644\u0645\u062a\u0635\u0641\u062d \u0627\u0644\u062e\u0627\u0635 \u0628\u0643 \u060c \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u062e\u062a\u0635\u0627\u0631\u0627\u062a \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0628\u062f\u0644\u0627 \u0645\u0646 \u0630\u0644\u0643.",clipboard_msg:"\u0646\u0633\u062e / \u0642\u0635 / \u0644\u0635\u0642 \u063a\u064a\u0631 \u0645\u062a\u0648\u0641\u0631 \u0641\u064a \u0645\u0648\u0632\u064a\u0644\u0627 \u0648\u0641\u0627\u064a\u0631\u0641\u0648\u0643\u0633.\\n\u062a\u0631\u064a\u062f \u0627\u0644\u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u062d\u0648\u0644 \u0647\u0630\u0647 \u0627\u0644\u0645\u0634\u0643\u0644\u0629\u061f",not_set:"-- Not set --",class_name:"\u0627\u0644\u062f\u0631\u062c\u0629",browse:"\u062a\u0635\u0641\u062d",close:"\u0625\u063a\u0644\u0627\u0642",cancel:"\u0625\u0644\u063a\u0627\u0621",update:"\u062a\u062d\u062f\u064a\u062b",insert:"\u0625\u062f\u0631\u0627\u062c",apply:"\u062a\u062a\u0637\u0628\u064a\u0642\u0637\u0628\u064a\u0642",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"\u0643\u0627\u0645\u0644",right:"\u0627\u0644\u062d\u0642",center:"\u0645\u0631\u0643\u0632",left:"\u0628\u0642\u064a",align:"\u0645\u062d\u0627\u0630\u0627\u0629"},insertdatetime:{day_short:"\u0623\u062d\u062f \u060c \u0627\u0644\u0627\u062b\u0646\u064a\u0646 \u060c \u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621 \u060c \u0627\u0644\u0627\u0631\u0628\u0639\u0627\u0621 \u060c \u0627\u0644\u062e\u0645\u064a\u0633 \u060c \u0627\u0644\u062c\u0645\u0639\u0629 \u060c \u0627\u0644\u0633\u0628\u062a \u0648\u0627\u0644\u0623\u062d\u062f",day_long:"\u0627\u0644\u0623\u062d\u062f \u060c \u0627\u0644\u0627\u062b\u0646\u064a\u0646 \u060c \u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621 \u060c \u0627\u0644\u0627\u0631\u0628\u0639\u0627\u0621 \u060c \u0627\u0644\u062e\u0645\u064a\u0633 \u060c \u0627\u0644\u062c\u0645\u0639\u0629 \u060c \u0627\u0644\u0633\u0628\u062a \u060c \u0627\u0644\u0623\u062d\u062f",months_short:"\u064a\u0646\u0627\u064a\u0631 \u060c \u0641\u0628\u0631\u0627\u064a\u0631 \u060c \u0645\u0627\u0631\u0633 \u060c \u0623\u0628\u0631\u064a\u0644 \u0648\u0645\u0627\u064a\u0648 \u0648\u064a\u0648\u0646\u064a\u0648 \u060c \u064a\u0648\u0644\u064a\u0648 \u060c \u0623\u063a\u0633\u0637\u0633 \u060c \u0633\u0628\u062a\u0645\u0628\u0631 \u060c \u0623\u0643\u062a\u0648\u0628\u0631 \u060c \u0646\u0648\u0641\u0645\u0628\u0631 \u060c \u062f\u064a\u0633\u0645\u0628\u0631",months_long:"\u064a\u0646\u0627\u064a\u0631 \u060c \u0641\u0628\u0631\u0627\u064a\u0631 \u060c \u0622\u0630\u0627\u0631 \u060c \u0646\u064a\u0633\u0627\u0646 \u060c \u0623\u064a\u0627\u0631 \u060c \u062d\u0632\u064a\u0631\u0627\u0646 \u060c \u062a\u0645\u0648\u0632 \u060c \u0622\u0628 \u060c \u0623\u064a\u0644\u0648\u0644 / \u0633\u0628\u062a\u0645\u0628\u0631 \u060c \u0623\u0643\u062a\u0648\u0628\u0631 \u060c \u0646\u0648\u0641\u0645\u0628\u0631 \u060c \u062f\u064a\u0633\u0645\u0628\u0631",inserttime_desc:"\u0627\u062f\u0631\u0627\u062c \u0627\u0644\u0648\u0642\u062a",insertdate_desc:"\u0627\u062f\u0631\u0627\u062c \u0627\u0644\u062a\u0627\u0631\u064a\u062e",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u0637\u0628\u0627\u0639\u0629"},preview:{preview_desc:"\u0645\u0639\u0627\u064a\u0646\u0629"},directionality:{rtl_desc:"\u0627\u0644\u0627\u062a\u062c\u0627\u0647 \u0645\u0646 \u0627\u0644\u064a\u0645\u064a\u0646 \u0644\u0644\u064a\u0633\u0627\u0631",ltr_desc:"\u0627\u0644\u0627\u062a\u062c\u0627\u0647 \u0645\u0646 \u0627\u0644\u064a\u0633\u0627\u0631 \u0627\u0644\u0649 \u0627\u0644\u064a\u0645\u064a\u0646"},layer:{content:"\u0637\u0628\u0642\u0647 \u062c\u062f\u064a\u062f\u0647 ...",absolute_desc:"\u062c\u0639\u0644 \u0627\u0644\u0637\u0628\u0642\u0647 \u062d\u0631\u0647",backward_desc:"\u0646\u0642\u0644 \u0644\u0644\u062e\u0644\u0641",forward_desc:"\u0646\u0642\u0644 \u0644\u0644\u0627\u0645\u0627\u0645",insertlayer_desc:"\u0625\u062f\u0631\u0627\u062c \u0637\u0628\u0642\u0629 \u062c\u062f\u064a\u062f\u0629"},save:{save_desc:"\u062d\u0641\u0638",cancel_desc:"\u0625\u0644\u063a\u0627\u0621 \u0643\u0627\u0641\u0629 \u0627\u0644\u062a\u063a\u064a\u064a\u0631\u0627\u062a"},nonbreaking:{nonbreaking_desc:"\u0625\u062f\u0631\u0627\u062c \u062d\u0631\u0641 \u0645\u0633\u0627\u0641\u0629 \u063a\u064a\u0631 \u0645\u0646\u0642\u0633\u0645\u0629"},iespell:{download:"\u0627\u0644\u0645\u062f\u0642\u0642 \u0627\u0644\u0627\u0645\u0644\u0627\u0626\u0649 \u063a\u064a\u0631 \u0645\u0631\u0643\u0628 \u0647\u0644 \u062a\u0631\u064a\u062f \u062a\u0631\u0643\u064a\u0628\u0647 \u0627\u0644\u0627\u0646",iespell_desc:"\u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0645\u062f\u0642\u0642 \u0627\u0644\u0627\u0645\u0644\u0627\u0626\u0649"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0627\u0644\u0631\u0633\u0648\u0645 \u0627\u0644\u062a\u0639\u0628\u064a\u0631\u064a\u0647",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0628\u062d\u062b/\u0627\u0633\u062a\u0628\u062f\u0627\u0644",search_desc:"\u0628\u062d\u062b",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"\u0627\u062f\u062e\u0627\u0644 -\u062a\u0639\u062f\u064a\u0644 \u0631\u0627\u0628\u0637",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u0644\u0635\u0642 \u0627\u0644\u0622\u0646 \u0641\u064a \u0648\u0636\u0639 \u0627\u0644\u0646\u0635 \u0627\u0644\u0639\u0627\u062f\u064a. \u0627\u0646\u0642\u0631 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649 \u0644\u0644\u062a\u0628\u062f\u064a\u0644 \u0625\u0644\u0649 \u0627\u0644\u0648\u0636\u0639 \u0644\u0635\u0642 \u0627\u0644\u0639\u0627\u062f\u064a\u0629.",plaintext_mode_sticky:"\u0644\u0635\u0642 \u0627\u0644\u0622\u0646 \u0641\u064a \u0648\u0636\u0639 \u0627\u0644\u0646\u0635 \u0627\u0644\u0639\u0627\u062f\u064a. \u0627\u0646\u0642\u0631 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649 \u0644\u0644\u062a\u0628\u062f\u064a\u0644 \u0625\u0644\u0649 \u0627\u0644\u0648\u0636\u0639 \u0644\u0635\u0642 \u0627\u0644\u0639\u0627\u062f\u064a\u0629. \u0648\u0628\u0639\u062f \u0644\u0635\u0642 \u0634\u064a\u0621 \u064a\u062a\u0645 \u0625\u0631\u062c\u0627\u0639 \u0625\u0644\u0649 \u0648\u0636\u0639 \u0644\u0635\u0642 \u0627\u0644\u0639\u0627\u062f\u064a\u0629",selectall_desc:"\u062d\u062f\u062f \u0643\u0627\u0641\u0629",paste_word_desc:"\u0644\u0635\u0642 \u0645\u0646 \u0648\u0648\u0631\u062f",paste_text_desc:"\u0644\u0635\u0642 \u0643\u0646\u0635 \u0639\u0627\u062f\u064a"},paste_dlg:{word_title:"\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0639\u0644\u0649 \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0644\u0644\u0635\u0642 \u0627\u0644\u0646\u0635 \u0641\u064a \u0627\u0644\u0625\u0637\u0627\u0631.( CTRL+V )",text_linebreaks:"\u0627\u062d\u062a\u0641\u0638 \u0628\u0641\u0648\u0627\u0635\u0644 \u0627\u0644\u0623\u0633\u0637\u0631",text_title:"\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0639\u0644\u0649 \u0644\u0648\u062d\u0629 \u0627\u0644\u0645\u0641\u0627\u062a\u064a\u062d \u0644\u0644\u0635\u0642 \u0627\u0644\u0646\u0635 \u0641\u064a \u0627\u0644\u0625\u0637\u0627\u0631.( CTRL+V )"},table:{cell:"\u0627\u0644\u062e\u0644\u064a\u0629",col:"\u0627\u0644\u0639\u0645\u0648\u062f",row:"\u0627\u0644\u0635\u0641",del:"\u062d\u0630\u0641 \u062c\u062f\u0648\u0644",copy_row_desc:"\u0646\u0633\u062e\u0629 \u0627\u0644\u062c\u062f\u0648\u0644 \u0627\u0644\u0635\u0641",cut_row_desc:"\u0642\u0635 \u0627\u0644\u062c\u062f\u0648\u0644 \u0627\u0644\u0635\u0641",paste_row_after_desc:"\u0644\u0635\u0642 \u0635\u0641 \u0627\u0644\u062c\u062f\u0648\u0644 \u0628\u0639\u062f",paste_row_before_desc:"\u0644\u0635\u0642 \u0635\u0641 \u0627\u0644\u062c\u062f\u0648\u0644 \u0642\u0628\u0644",props_desc:"\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u062c\u062f\u0648\u0644",cell_desc:"\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u062c\u062f\u0648\u0644 \u0627\u0644\u062e\u0644\u064a\u0629",row_desc:"\u062e\u0635\u0627\u0626\u0635 \u0627\u0644\u062c\u062f\u0648\u0644 \u0627\u0644\u0635\u0641",merge_cells_desc:"\u062f\u0645\u062c \u0627\u0644\u062e\u0644\u0627\u064a\u0627 \u0627\u0644\u062c\u062f\u0648\u0644",split_cells_desc:"\u0627\u0646\u0642\u0633\u0627\u0645 \u062e\u0644\u0627\u064a\u0627 \u0627\u0644\u062c\u062f\u0648\u0644 \u0627\u0644\u0645\u062f\u0645\u062c\u0629",delete_col_desc:"\u0625\u0632\u0627\u0644\u0629 \u0639\u0645\u0648\u062f",col_after_desc:"\u0625\u062f\u0631\u0627\u062c \u0639\u0645\u0648\u062f \u0628\u0639\u062f",col_before_desc:"\u0625\u062f\u0631\u0627\u062c \u0639\u0645\u0648\u062f \u0642\u0628\u0644",delete_row_desc:"\u062d\u0630\u0641 \u0635\u0641",row_after_desc:"\u0625\u062f\u0631\u0627\u062c \u0635\u0641 \u0628\u0639\u062f",row_before_desc:"\u0625\u062f\u0631\u0627\u062c \u0635\u0641 \u0642\u0628\u0644",desc:"\u0625\u062f\u0631\u0627\u062c \u062c\u062f\u0648\u0644 \u062c\u062f\u064a\u062f",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"\u062a\u0628\u062f\u064a\u0644 \u0648\u0636\u0639 \u0645\u0644\u0621 \u0627\u0644\u0634\u0627\u0634\u0629"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ca.js0000644000175000017500000001335711526350525031501 0ustar frankiefrankietinyMCE.addI18n({ca:{common:{more_colors:"M\u00e9s colors",invalid_data:"Error: heu introdu\u00eft valors no v\u00e0lids, els marcats en vermell.",popup_blocked:"El bloqueig de finestres emergents ha inhabilitat una finestra que proporciona funcionalitat a l\\\'aplicaci\u00f3. Cal que desactiveu el bloqueig de finestres emergents en aquest lloc per tal de poder utilitzar de forma completa aquesta eina.",clipboard_no_support:"El vostre navegador actualment no ho admet, utilitzeu les dreceres de teclat.",clipboard_msg:"Copia/Retalla/Enganxa no es troba disponible al Mozilla ni al Firefox.\\nVoleu m\u00e9s informaci\u00f3 sobre aquesta q\u00fcesti\u00f3?",not_set:"-- No definit --",class_name:"Classe",browse:"Explora",close:"Tanca",cancel:"Cancel\u00b7la",update:"Actualitza",insert:"Insereix",apply:"Aplica",edit_confirm:"Voleu utilitzar el mode WYSIWYG?"},contextmenu:{full:"Justificat",right:"Dreta",center:"Centre",left:"Esquerra",align:"Alineaci\u00f3"},insertdatetime:{day_short:"dg.,dl.,dt.,dc.,dj.,dv.,ds.,dg.",day_long:"diumenge,dilluns,dimarts,dimecres,dijous,divendres,dissabte,diumenge",months_short:"gen.,febr.,mar\u00e7,abr.,maig,juny,jul.,ag.,set.,oct.,nov.,des.",months_long:"Jgener,febrer,mar\u00e7,abril,maig,juny,juliol,agost,setembre,octubre,novembre,desembre",inserttime_desc:"Insereix l\\\'hora",insertdate_desc:"Insereix la data",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Imprimeix"},preview:{preview_desc:"Previsualitzaci\u00f3"},directionality:{rtl_desc:"Direcci\u00f3 dreta a esquerra",ltr_desc:"Direcci\u00f3 esquerra a dreta"},layer:{content:"Nova Capa...",absolute_desc:"Conmuta el posicionament absolut",backward_desc:"Mou endarrera",forward_desc:"Mou endavant",insertlayer_desc:"Insereix una nova capa"},save:{save_desc:"Desa",cancel_desc:"Cancel\u00b7la tots els canvis"},nonbreaking:{nonbreaking_desc:"Insereix un car\u00e0cter espai en blanc"},iespell:{download:"no he detectat l\\\'ieSpell. Voleu instal\u00b7lar-ho?",iespell_desc:"Executa la correcci\u00f3 ortogr\u00e0fica"},advhr:{advhr_desc:"Filet horitzontal",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emoticones",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Cerca/Reempla\u00e7a",search_desc:"Cerca",delta_width:"",delta_height:""},advimage:{image_desc:"Insereix/edita imatge",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insereix/edita atributs",ins_desc:"Inserci\u00f3",del_desc:"Eliminaci\u00f3",acronym_desc:"Acr\u00f2nim",abbr_desc:"Abreviaci\u00f3",cite_desc:"Citaci\u00f3",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edita l\\\'estil CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Enganxa est\u00e0 ara configurat en mode text pla. Clica de nou per tornar al mode normal d\'enganxar.",plaintext_mode_sticky:"Enganxa est\u00e0 ara configurat en mode text pla. Clica de nou per tornar al mode normal d\'enganxar. Despr\u00e9s d\'enganxar quelcom ser\u00e0s retornat al mode normal d\'enganxar.",selectall_desc:"Selecciona-ho tot",paste_word_desc:"Enganxa des del Word",paste_text_desc:"Enganxa com a text pla"},paste_dlg:{word_title:"Amb el teclat utilitzeu CTRL+V per a enganxar el text dins la finestra.",text_linebreaks:"Conserva els salts de l\u00ednia",text_title:"Amb el teclat utilitzeu CTRL+V per a enganxar el text dins la finestra."},table:{cell:"Cel\u00b7la",col:"Columna",row:"Fila",del:"Elimina la taula",copy_row_desc:"Copia la fila",cut_row_desc:"Retalla la fila",paste_row_after_desc:"Enganxa la fila despr\u00e9s",paste_row_before_desc:"Enganxa la fila abans",props_desc:"Propietats de la taula",cell_desc:"Propietats de la cel\u00b7la",row_desc:"Propietats de la fila",merge_cells_desc:"Fusiona les cel\u00b7les",split_cells_desc:"Divideix les cel\u00b7les fusionades",delete_col_desc:"Elimina la columna",col_after_desc:"Insereix una columna despr\u00e9s",col_before_desc:"Insereix una columna abans",delete_row_desc:"Elimina la fila",row_after_desc:"Insereix una fila despr\u00e9s",row_before_desc:"Insereix una fila abans",desc:"Insereix una nova taula",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Si restaures el contingut guardat, perdr\u00e0s tot el contingut actual de l\'editor. Est\u00e0s segur de voler continuar?",restore_content:"Restaura el contingut guardat autom\u00e0ticament.",unload_msg:"Els canvis que heu fet es perdran si navegueu a fora d\\\'aquesta p\u00e0gina."},fullscreen:{desc:"Commuta a mode de pantalla completa"},media:{edit:"Edita multim\u00e8dia incrustat",desc:"Insereix / edita multim\u00e8dia incrustat",delta_height:"",delta_width:""},fullpage:{desc:"Propietats del document",delta_width:"",delta_height:""},template:{desc:"Insereix un contingut predefinit"},visualchars:{desc:"Activa/desactiva els car\u00e0cters de control visual."},spellchecker:{desc:"Corrector ortogr\u00e0fic",menu:"Configuraci\u00f3 del corrector",ignore_word:"Ignora el mot",ignore_words:"Ignora\\\'ls tots",langs:"Idiomes",wait:"Espereu...",sug:"Suggeriments",no_sug:"Cap suggeriment",no_mpell:"No s\\\'ha trobat cap falta d\\\'ortografia."},pagebreak:{desc:"Insereix un salt de p\u00e0gina."},advlist:{types:"Tipus",def:"Per defecte",lower_alpha:"Lletres",lower_greek:"Lletres gregues (min\u00fascules)",lower_roman:"Nombres romans (min\u00fascules)",upper_alpha:"Lletres (maj\u00fascules)",upper_roman:"Nombres romans (maj\u00fascules)",circle:"Cercle",disc:"Disc",square:"Quadrat"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/bn.js0000644000175000017500000001660211526350525031511 0ustar frankiefrankietinyMCE.addI18n({bn:{common:{more_colors:"\u0986\u09b0\u0993 \u09ac\u09c7\u09b6\u09bf \u09b0\u0982",invalid_data:"\u09a4\u09cd\u09b0\u09c1\u099f\u09bf: \u09ac\u09c7\u09a0\u09bf\u0995 \u09ae\u09be\u09a8 \u09a2\u09c1\u0995\u09be\u09a8\u09cb \u09b9\u09df\u09c7\u099b\u09c7, \u098f\u0987\u0997\u09c1\u09b2\u09bf \u09b2\u09be\u09b2 \u099a\u09bf\u09b9\u09cd\u09a8\u09bf\u09a4 \u0995\u09b0\u09be \u09b9\u09b2\u0964",popup_blocked:"\u09a6\u09c1\u0983\u0996\u09bf\u09a4, \u0995\u09bf\u09a8\u09cd\u09a4\u09c1 \u0986\u09ae\u09b0\u09be \u09b2\u0995\u09cd\u09b7\u09cd\u09af \u0995\u09b0\u09c7\u099b\u09bf \u09af\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u09aa\u09aa-\u0986\u09aa \u09ac\u09cd\u09b2\u0995\u09be\u09b0 \u098f\u0995\u099f\u09bf \u0989\u0987\u09a8\u09cd\u09a1\u09cb \u09a8\u09bf\u09b7\u09cd\u0995\u09cd\u09b0\u09bf\u09df \u0995\u09b0\u09c7\u099b\u09c7 \u09af\u09be \u0985\u09cd\u09af\u09be\u09aa\u09b2\u09bf\u0995\u09c7\u09b6\u09a8 \u098f\u09b0 \u09ab\u09be\u0982\u09b6\u09a8\u09be\u09b2\u09bf\u099f\u09bf\u09b0 \u099c\u09a8\u09cd\u09af \u09aa\u09cd\u09b0\u09df\u09cb\u099c\u09a8\u09c0\u09df\u0964\u0986\u09aa\u09a8\u09bf \u098f\u0987 \u099f\u09c1\u09b2\u099f\u09bf \u09b8\u09ae\u09cd\u09aa\u09c2\u09b0\u09cd\u09a3\u09ad\u09be\u09ac\u09c7 \u09ac\u09cd\u09af\u09be\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u099a\u09be\u0987\u09b2\u09c7 \u098f\u0987 \u09b8\u09be\u0987\u099f\u099f\u09bf \u09a5\u09c7\u0995\u09c7 \u09aa\u09aa-\u0986\u09aa \u09ac\u09cd\u09b2\u0995\u09bf\u0982 \u09a8\u09bf\u09b7\u09cd\u0995\u09cd\u09b0\u09bf\u09df \u0995\u09b0\u09a4\u09c7 \u09b9\u09ac\u09c7\u0964",clipboard_no_support:"\u0986\u09aa\u09a8\u09be\u09b0 \u09ac\u09cd\u09b0\u09be\u0989\u099c\u09be\u09b0\u09c7\u09b0 \u09a6\u09cd\u09ac\u09be\u09b0\u09be \u09ac\u09b0\u09cd\u09a4\u09ae\u09be\u09a8\u09c7 \u09b8\u09ae\u09b0\u09cd\u09a5\u09bf\u09a4 \u09a8\u09be, \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09c7 \u0995\u09c0\u09ac\u09cb\u09b0\u09cd\u09a1 \u09b6\u09b0\u09cd\u099f\u0995\u09be\u099f \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09c1\u09a8\u0964",clipboard_msg:"\u0995\u09aa\u09bf/\u0995\u09be\u099f/\u09aa\u09c7\u09b7\u09cd\u099f \u09ae\u099c\u09bf\u09b2\u09be \u098f\u09ac\u0982 \u09ab\u09be\u09df\u09be\u09b0\u09ab\u0995\u09cd\u09b8 \u098f \u09b8\u09ae\u09cd\u09ad\u09ac \u09a8\u09df\\n\u0986\u09aa\u09a8\u09bf \u0995\u09bf \u098f\u0987 \u09ac\u09bf\u09b7\u09df\u099f\u09bf\u09b0 \u09b8\u09ae\u09cd\u09ac\u09a8\u09cd\u09a7\u09c7 \u0986\u09b0\u0993 \u09ac\u09c7\u09b6\u09bf \u09a4\u09a5\u09cd\u09af \u099a\u09be\u09a8",not_set:"-- \u09b8\u09c7\u099f \u09a8\u09df --",class_name:"\u0995\u09cd\u09b2\u09be\u09b8",browse:"\u09ac\u09cd\u09b0\u09be\u0989\u099c",close:"\u09ac\u09a8\u09cd\u09a7",cancel:"\u0995\u09cd\u09af\u09be\u09a8\u09b8\u09c7\u09b2",update:"\u0986\u09aa\u09a1\u09c7\u099f",insert:"\u0987\u09a8\u09b8\u09be\u09b0\u09cd\u099f",apply:"\u098f\u09aa\u09cd\u09b2\u09cd\u09af\u09be\u0987",edit_confirm:"\u0986\u09aa\u09a8\u09bf \u0995\u09bf \u098f\u0987 textarea\u099f\u09bf\u09b0 \u099c\u09a8\u09cd\u09af WYSIWYG \u09ae\u09cb\u09a1 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u099a\u09be\u09a8?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/az.js0000644000175000017500000001610311526350525031520 0ustar frankiefrankietinyMCE.addI18n({az:{common:{more_colors:"Daha \u00e7ox r\u0259ng",invalid_data:"X\u0259ta: Q\u0131rm\u0131z\u0131 il\u0259 qeyd edilmi\u015fl\u0259r s\u0259hv daxil edilib.",popup_blocked:"Ba\u011f\u0131\u015flay\u0131n, lakin sizin \u00fcz\u0259 \u00e7\u0131xan p\u0259nc\u0259r\u0259l\u0259riniz funksiya p\u0259nc\u0259r\u0259sinin qar\u015f\u0131s\u0131n\u0131 ald\u0131. G\u0259r\u0259k \u00fcz\u0259 \u00e7\u0131xan p\u0259nc\u0259r\u0259l\u0259rin bloklama nizamlamas\u0131n\u0131 l\u0259\u011fv ed\u0259siniz ki, al\u0259td\u0259n tam istifad\u0259 ed\u0259 bil\u0259siniz.",clipboard_no_support:"Hal-haz\u0131rda b\u0259l\u0259d\u00e7iniz t\u0259r\u0259find\u0259n d\u0259st\u0259kl\u0259nmir. Klaviatura q\u0131saldmas\u0131ndan istifad\u0259 edin.",clipboard_msg:"Kopyalama/\u018flav\u0259 et Mozilla v\u0259 Firefox-da i\u015fl\u0259mir.\\nN\u0259 ba\u015f verdiyi haqda daha \u0259trafl\u0131 \u00f6yr\u0259nm\u0259k ist\u0259yirsiniz?",not_set:"-- M\u00fc\u0259yy\u0259n edilm\u0259yib --",class_name:"Sinif",browse:"G\u00f6zd\u0259n ke\u00e7ir",close:"Ba\u011fla",cancel:"L\u0259\u011fv et",update:"Yenil\u0259",insert:"\u018flav\u0259 et",apply:"T\u0259tbiq et",edit_confirm:"Siz haz\u0131rki m\u0259tn sah\u0259si \u00fc\u00e7\u00fcn WYSIWYG rejimi istifad\u0259 etm\u0259k ist\u0259yirsiniz?"},contextmenu:{full:"Tam",right:"Sa\u011fa",center:"M\u0259rk\u0259z il\u0259",left:"Sola",align:"Tarazla\u015fd\u0131r"},insertdatetime:{day_short:"B,Be,\u00c7a,\u00c7,Ca,C,\u015e,B",day_long:"Bazar,Bazar ert\u0259si,\u00c7\u0259r\u015f\u0259nb\u0259 ax\u015fam\u0131,\u00c7\u0259r\u015f\u0259nb\u0259,C\u00fcm\u0259 ax\u015fam\u0131,C\u00fcm\u0259,\u015e\u0259nb\u0259,Bazar",months_short:"Yan,Fev,Mar,Apr,May,\u0130yu,\u0130yl,Avq,Sen,Okt,Noy,Dek",months_long:"Yanvar,Fevral,Mart,Aprel,May,\u0130yun,\u0130yul,Avqust,Sentyabr,Oktyabr,Noyabr,Dekabr",inserttime_desc:"Vaxt \u0259lav\u0259 et",insertdate_desc:"Tarix \u0259lav\u0259 et",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"\u00c7ap et"},preview:{preview_desc:"\u0130lkin bax\u0131\u015f"},directionality:{rtl_desc:"\u0130stiqam\u0259t sa\u011fdan-sola",ltr_desc:"\u0130stiqam\u0259t soldan-sa\u011fa"},layer:{content:"Yeni qat...",absolute_desc:"M\u00fctl\u0259q m\u00f6vqeni yand\u0131r/s\u00f6nd\u00fcr",backward_desc:"Geri k\u00f6\u00e7\u00fcr",forward_desc:"\u0130r\u0259li k\u00f6\u00e7\u00fcr",insertlayer_desc:"Yeni qat \u0259lav\u0259 et"},save:{save_desc:"Yadda saxla",cancel_desc:"B\u00fct\u00fcn d\u0259yi\u015fiklikl\u0259ri l\u0259\u011fv et"},nonbreaking:{nonbreaking_desc:"Q\u0131r\u0131lmaz bo\u015fluq \u0259lav\u0259 et"},iespell:{download:"ieSpell a\u015fkar edilm\u0259yib. Y\u00fckl\u0259nilsin?",iespell_desc:"Orfoqrafiyan\u0131 yoxla"},advhr:{advhr_desc:"\u00dcf\u00fcqi x\u0259tt",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smayllar",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Axtar/D\u0259yi\u015f",search_desc:"Axtar",delta_width:"",delta_height:""},advimage:{image_desc:"\u015e\u0259kli \u0259lav\u0259/redakt\u0259 et",delta_width:"",delta_height:""},advlink:{link_desc:"Ke\u00e7idi \u0259lav\u0259/redakt\u0259 et",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Atribut \u0259lav\u0259/redakt\u0259 et",ins_desc:"\u018flav\u0259 edilmi\u015f m\u0259tn",del_desc:"Silinmi\u015f m\u0259tn",acronym_desc:"Akronim",abbr_desc:"Abbreviatura",cite_desc:"Sitat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{delta_width:"35",desc:"CSS stili redakt\u0259 et",delta_height:""},paste:{selectall_desc:"Ham\u0131s\u0131n\u0131 se\u00e7",paste_word_desc:"Word-d\u0259n \u0259lav\u0259 et",paste_text_desc:"Sad\u0259 m\u0259tn kimi \u0259lav\u0259 et",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"P\u0259nc\u0259r\u0259y\u0259 s\u00f6z \u0259lav\u0259 etm\u0259k \u00fc\u00e7\u00fcn CTRL+V klavi\u015f birl\u0259\u015fm\u0259sini istifad\u0259 edin.",text_linebreaks:"S\u0259tr s\u0131nmalar\u0131n\u0131 saxla",text_title:"P\u0259nc\u0259r\u0259y\u0259 m\u0259tn \u0259lav\u0259 etm\u0259k \u00fc\u00e7\u00fcn CTRL+V klavi\u015f birl\u0259\u015fm\u0259sini istifad\u0259 edin."},table:{cell:"\u00d6z\u0259k",col:"S\u00fctun",row:"S\u0259tr",del:"C\u0259dv\u0259li sil",copy_row_desc:"S\u0259tri kopyala",cut_row_desc:"S\u0259tri k\u0259s",paste_row_after_desc:"S\u0259tr c\u0259dv\u0259lini sonra \u0259lav\u0259 et:",paste_row_before_desc:"S\u0259tr c\u0259dv\u0259lini \u0259vv\u0259l \u0259lav\u0259 et:",props_desc:"C\u0259dv\u0259l x\u00fcsusiyy\u0259tl\u0259ri",cell_desc:"\u00d6z\u0259k x\u00fcsusiyy\u0259tl\u0259ri",row_desc:"S\u0259tr x\u00fcsusiyy\u0259tl\u0259ri",merge_cells_desc:"\u00d6z\u0259kl\u0259ri s\u00fcz",split_cells_desc:"S\u00fcz\u00fclm\u00fc\u015f \u00f6z\u0259kl\u0259ri ay\u0131r",delete_col_desc:"S\u00fctunu sil",col_after_desc:"S\u00fctunu sonra \u0259lav\u0259 et:",col_before_desc:"S\u00fctunu \u0259vv\u0259l \u0259lav\u0259 et:",delete_row_desc:"S\u0259tri sil",row_after_desc:"S\u0259tri sonra \u0259vv\u0259l et:",row_before_desc:"S\u0259tri \u0259vv\u0259l \u0259lav\u0259 et:",desc:"Yeni c\u0259dv\u0259l \u0259lav\u0259 et",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u018fg\u0259r s\u0259hif\u0259d\u0259n gets\u0259niz b\u00fct\u00fcn d\u0259yi\u015fiklikl\u0259r itiril\u0259c\u0259k.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Tamekran rejimini yand\u0131r/s\u00f6nd\u00fcr"},media:{edit:"Mediya-obyekti redakt\u0259 et",desc:"mediya-obyekti \u0259lav\u0259/redakt\u0259 et",delta_height:"",delta_width:""},fullpage:{desc:"S\u0259n\u0259d nizamlamalar\u0131",delta_width:"",delta_height:""},template:{desc:"\u018fvv\u0259ld\u0259n m\u00fc\u0259yy\u0259n edil\u0259n \u015fablon daxil et"},visualchars:{desc:"Vizual idar\u0259 xarakterl\u0259rini yand\u0131r/s\u00f6nd\u00fcr."},spellchecker:{desc:"Orfoqraf\u0131 yoxla",menu:"Orfoqrafiya nizamlamas\u0131n\u0131",ignore_word:"S\u00f6zl\u00fc iqnor et",ignore_words:"H\u0259r \u015feyi iqnor et",langs:"Dill\u0259r",wait:"Z\u0259hm\u0259t olmasa, g\u00f6zl\u0259yin...",sug:"Variantlar",no_sug:"Variantlar yoxdur",no_mpell:"X\u0259ta a\u015fkar edilm\u0259di."},pagebreak:{desc:"S\u0259hif\u0259 b\u00f6l\u0259nini \u0259lav\u0259 et."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/br.js0000644000175000017500000001265411526350525031520 0ustar frankiefrankietinyMCE.addI18n({br:{common:{more_colors:"Mais Cores",invalid_data:"Erro: Valores inv\u00e1lidos est\u00e3o marcados em vermelho.",popup_blocked:"Detectamos que o seu bloqueador de popups bloqueou uma janela que \u00e9 essencial para o aplicativo. Voc\u00ea precisa desativar o bloqueador de popups para utilizar esta ferramenta.",clipboard_no_support:"O seu navegador n\u00e3o tem suporte para esta fun\u00e7\u00e3o, use os atalhos do teclado.",clipboard_msg:"Copiar/cortar/colar n\u00e3o est\u00e1 dispon\u00edvel no Mozilla/Firefox.\\nDeseja mais informa\u00e7\u00f5es sobre este problema?",not_set:"-- N\u00e3o especificado --",class_name:"Classe",browse:"Procurar",close:"Fechar",cancel:"Cancelar",update:"Atualizar",insert:"Inserir",apply:"Aplicar",edit_confirm:"Deseja usar o modo de edi\u00e7\u00e3o avan\u00e7ado neste campo de texto?"},contextmenu:{full:"Justificar",right:"Direita",center:"Centro",left:"Esquerda",align:"Alinhamento"},insertdatetime:{day_short:"Dom,Seg,Ter,Qua,Qui,Sex,Sab,Dom",day_long:"Domingo,Segunda-Feira,Ter\u00e7a-Feira,Quarta-Feira,Quinta-Feira,Sexta-Feira,S\u00e1bado,Domingo",months_short:"Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez",months_long:"Janeiro,Fevereiro,Mar\u00e7o,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro",inserttime_desc:"Inserir hora",insertdate_desc:"Inserir data",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Imprimir"},preview:{preview_desc:"Pr\u00e9-Visualizar"},directionality:{rtl_desc:"Da direita para esquerda",ltr_desc:"Da esquerda para direita"},layer:{content:"Nova camada...",absolute_desc:"Alternar posicionamento absoluto",backward_desc:"Mover para tr\u00e1s",forward_desc:"Mover para frente",insertlayer_desc:"Inserir nova camada"},save:{save_desc:"Salvar",cancel_desc:"Cancelar todas as altera\u00e7\u00f5es"},nonbreaking:{nonbreaking_desc:"Inserir um espa\u00e7o"},iespell:{download:"Aplicativo de ortografia n\u00e3o-detectado. Deseja instal\u00e1-lo agora?",iespell_desc:"Verificar ortografia"},advhr:{advhr_desc:"Separador horizontal",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emoticons",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Localizar/substituir",search_desc:"Localizar",delta_width:"",delta_height:""},advimage:{image_desc:"Inserir/editar imagem",delta_width:"",delta_height:""},advlink:{link_desc:"Inserir/editar hyperlink",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Inserir/Editar atributos",ins_desc:"Inserir",del_desc:"Apagar",acronym_desc:"Acr\u00f4nimo",abbr_desc:"Abrevia\u00e7\u00e3o",cite_desc:"Cita\u00e7\u00e3o",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Editar CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Selecionar tudo",paste_word_desc:"Colar (copiado do WORD)",paste_text_desc:"Colar como texto simples",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V para colar o texto na janela.",text_linebreaks:"Manter quebras de linha",text_title:"Use CTRL+V para colar o texto na janela."},table:{cell:"C\u00e9lula",col:"Coluna",row:"Linha",del:"Apagar tabela",copy_row_desc:"Copiar linha",cut_row_desc:"Cortar linha",paste_row_after_desc:"Colar linha depois",paste_row_before_desc:"Colar linha antes",props_desc:"Propriedades da tabela",cell_desc:"Propriedades das c\u00e9lulas",row_desc:"Propriedades das linhas",merge_cells_desc:"Unir c\u00e9lulas",split_cells_desc:"Dividir c\u00e9lulas",delete_col_desc:"Remover coluna",col_after_desc:"Inserir coluna depois",col_before_desc:"Inserir coluna antes",delete_row_desc:"Apagar linha",row_after_desc:"Inserir linha depois",row_before_desc:"Inserir linha antes",desc:"Inserir nova tabela",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"As mudan\u00e7as efetuadas ser\u00e3o perdidas se sair desta p\u00e1gina.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Tela Inteira"},media:{edit:"Editar m\u00eddia incorporada",desc:"Inserir/Editar m\u00eddia incorporada",delta_height:"",delta_width:""},fullpage:{desc:"Propriedades do Documento",delta_width:"",delta_height:""},template:{desc:"Inserir template"},visualchars:{desc:"Caracteres de controle visual ligado/desligado"},spellchecker:{desc:"Alternar verifica\u00e7\u00e3o ortogr\u00e1fica",menu:"Configura\u00e7\u00f5es de ortografia",ignore_word:"Ignorar palavra",ignore_words:"Ignorar tudo",langs:"Linguagens",wait:"Aguarde...",sug:"Sugest\u00f5es",no_sug:"Sem sugest\u00f5es",no_mpell:"N\u00e3o foram detectados erros de ortografia."},pagebreak:{desc:"Inserir quebra de p\u00e1gina."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ch.js0000644000175000017500000001550011526350525031500 0ustar frankiefrankietinyMCE.addI18n({ch:{common:{more_colors:"\u66f4\u591a\u989c\u8272\u2026",invalid_data:"\u4f60\u8f93\u5165\u7684\u8d44\u6599\u6709\u8bef\uff08\u7ea2\u8272\u90e8\u5206\uff09",popup_blocked:"\u4f60\u7684\u6d4f\u89c8\u5668\u7981\u6b62\u4e86\u5f39\u51fa\u89c6\u7a97\u3002",clipboard_no_support:"\u60a8\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u63f4\u8be5\u529f\u80fd\uff0c\u8bf7\u4f7f\u7528Ctrl + C\u952e\u4ee3\u66ff\u3002",clipboard_msg:"\u5f88\u62b1\u6b49\uff0c\u60a8\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u63f4\u590d\u5236\u529f\u80fd\u3002",not_set:"--\u5c1a\u672a\u8bbe\u5b9a--",class_name:"\u7c7b\u522b",browse:"\u9884\u89c8",close:"\u5173\u95ed",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5957\u7528",edit_confirm:"\u662f\u5426\u9700\u8981\u5f00\u542f\u6587\u5b57\u7f16\u8f91\u5668\uff1f"},contextmenu:{full:"\u5de6\u53f3\u5bf9\u9f50",right:"\u9760\u53f3\u5bf9\u9f50",center:"\u7f6e\u4e2d\u5bf9\u9f50",left:"\u9760\u5de6\u5bf9\u9f50",align:"\u5bf9\u9f50"},insertdatetime:{day_short:"\u5468\u65e5\uff0c\u5468\u4e00\uff0c\u5468\u4e8c\uff0c\u5468\u53c1\uff0c\u5468\u56db\uff0c\u5468\u4e94\uff0c\u5468\u516d\uff0c\u5468\u65e5",day_long:"\u661f\u671f\u65e5\uff0c\u661f\u671f\u4e00\uff0c\u661f\u671f\u4e8c\uff0c\u661f\u671f\u53c1\uff0c\u661f\u671f\u56db\uff0c\u661f\u671f\u4e94\uff0c\u661f\u671f\u516d\uff0c\u661f\u671f\u65e5",months_short:"1\u6708\uff0c2\u6708\uff0c3\u6708\uff0c4\u6708\uff0c5\u6708\uff0c6\u6708\uff0c7\u6708\uff0c8\u6708\uff0c9\u6708\uff0c10\u6708\uff0c11\u6708\uff0c12\u6708",months_long:"\u4e00\u6708\uff0c\u4e8c\u6708\uff0c\u53c1\u6708\uff0c\u56db\u6708\uff0c\u4e94\u6708\uff0c\u516d\u6708\uff0c\u4e03\u6708\uff0c\u516b\u6708\uff0c\u4e5d\u6708\uff0c\u5341\u6708\uff0c\u5341\u4e00\u6708\uff0c\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u76ee\u524d\u65f6\u95f4",insertdate_desc:"\u63d2\u5165\u76ee\u524d\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y/%m/%d"},print:{print_desc:"\u5217\u5370"},preview:{preview_desc:"\u9884\u89c8"},directionality:{rtl_desc:"\u4ece\u53f3\u5230\u5de6",ltr_desc:"\u4ece\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u5efa\u56fe\u5c42\u2026",absolute_desc:"\u5207\u6362\u5230\u7edd\u5bf9\u4f4d\u7f6e",backward_desc:"\u7f6e\u540e",forward_desc:"\u7f6e\u524d",insertlayer_desc:"\u63d2\u5165\u56fe\u5c42"},save:{save_desc:"\u5b58\u6863",cancel_desc:"\u53d6\u6d88\u6240\u6709\u53d8\u66f4"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u683c"},iespell:{download:"\u68c0\u67e5\u4e0d\u5230ieSpell\u63d2\u4ef6\u7a0b\u5e8f\uff0c\u662f\u5426\u7acb\u5373\u5b89\u88c5\uff1f",iespell_desc:"\u62fc\u5b57\u68c0\u67e5"},advhr:{advhr_desc:"\u6c34\u5e73\u7ebf",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u8868\u60c5",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u641c\u5bfb/\u53d6\u4ee3",search_desc:"\u641c\u5bfb",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7f16\u8f91\u56fe\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7f16\u8f91\u8d85\u8fde\u7ed3",delta_height:"",delta_width:""},xhtmlxtras:{attribs_delta_height:"60",attribs_delta_width:"40",attribs_desc:"\u63d2\u5165/\u7f16\u8f91\u5c5e\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u5220\u9664",acronym_desc:"\u9996\u5b57\u6bcd\u7f29\u5199",abbr_desc:"\u7f29\u5199",cite_desc:"\u5f15\u7528",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7f16\u8f91 CSS \u6837\u5f0f\u8868",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u76ee\u524d\u4e3a\u4e00\u822c\u8d34\u4e0a\u6a21\u5f0f\uff0c\u518d\u70b9\u70b9\u51fb\u4e00\u6b21\u5207\u6362\u56de\u7eaf\u6587\u672c\u8d34\u4e0a\u6a21\u5f0f\u3002",plaintext_mode_sticky:"\u76ee\u524d\u4e3a\u7eaf\u6587\u672c\u8d34\u4e0a\u6a21\u5f0f\uff0c\u518d\u70b9\u51fb\u4e00\u6b21\u5207\u6362\u56de\u4e00\u822c\u6a21\u5f0f\u3002",selectall_desc:"\u5168\u9009",paste_word_desc:"\u4ee5Word\u683c\u5f0f\u8d34\u4e0a",paste_text_desc:"\u4ee5\u7eaf\u6587\u672c\u8d34\u4e0a"},paste_dlg:{word_title:"\u7528 Ctrl+V \u5c06\u5185\u5bb9\u8d34\u4e0a\u3002",text_linebreaks:"\u4fdd\u7559\u5206\u884c\u7b26\u53f7",text_title:"\u7528 Ctrl+V \u5c06\u5185\u5bb9\u8d34\u4e0a\u3002"},table:{merge_cells_delta_height:"40",merge_cells_delta_width:"40",table_delta_height:"60",table_delta_width:"40",cellprops_delta_height:"10",cellprops_delta_width:"10",cell:"\u50a8\u5b58\u683c",col:"\u680f",row:"\u884c",del:"\u5220\u9664\u8868\u683c",copy_row_desc:"\u590d\u5236\u9009\u62e9\u884c",cut_row_desc:"\u526a\u4e0b\u9009\u62e9\u884c",paste_row_after_desc:"\u5728\u4e0b\u65b9\u8d34\u4e0a\u884c",paste_row_before_desc:"\u5728\u4e0a\u65b9\u8d34\u4e0a\u884c",props_desc:"\u8868\u683c\u5c5e\u6027",cell_desc:"\u50a8\u5b58\u683c\u5c5e\u6027",row_desc:"\u884c\u5c5e\u6027",merge_cells_desc:"\u5408\u5e76\u50a8\u5b58\u683c",split_cells_desc:"\u5206\u5272\u50a8\u5b58\u683c",delete_col_desc:"\u5220\u9664\u76ee\u524d\u680f",col_after_desc:"\u5728\u53f3\u4fa7\u63d2\u5165\u680f",col_before_desc:"\u5728\u5de6\u4fa7\u63d2\u5165\u680f",delete_row_desc:"\u5220\u9664\u76ee\u524d\u884c",row_after_desc:"\u5728\u4e0b\u65b9\u63d2\u5165\u884c",row_before_desc:"\u5728\u4e0a\u65b9\u63d2\u5165\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u5982\u679c\u6062\u590d\u5148\u524d\u50a8\u5b58\u7684\u5185\u5bb9\uff0c\u60a8\u5c06\u5931\u53bb\u7f16\u8f91\u5668\u4e2d\u73b0\u6709\u7684\u5185\u5bb9\u3002 \\n\\n\u60a8\u786e\u5b9a\u8981\u6062\u590d\u5148\u524d\u50a8\u5b58\u7684\u5185\u5bb9\u5417\uff1f",restore_content:"\u6062\u590d\u81ea\u52a8\u50a8\u5b58\u7684\u5185\u5bb9\u3002",unload_msg:"\u60a8\u5c1a\u672a\u50a8\u5b58\u5185\u5bb9\uff0c\u60a8\u8f93\u5165\u7684\u5185\u5bb9\u53ef\u80fd\u4f1a\u4e22\u5931\u2026"},fullscreen:{desc:"\u5168\u8424\u5e55\u7f16\u8f91"},media:{edit:"\u7f16\u8f91\u5f71\u7247",desc:"\u63d2\u5165/\u7f16\u8f91\u5f71\u7247",delta_height:"",delta_width:""},fullpage:{desc:"\u6863\u6848\u5c5e\u6027",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9884\u8bbe\u6a21\u677f"},visualchars:{desc:"\u663e\u793a/\u9690\u85cf\u975e\u53ef\u89c1\u5b57\u7b26"},spellchecker:{desc:"\u5f00\u5173\u62fc\u5199\u68c0\u67e5",menu:"\u62fc\u5b57\u68c0\u67e5\u8bbe\u5b9a",ignore_word:"\u5ffd\u7565",ignore_words:"\u5168\u90e8\u5ffd\u7565",langs:"\u8bed\u8a00",wait:"\u8bf7\u7a0d\u5019\u2026",sug:"\u5efa\u8bae",no_sug:"\u65e0\u5efa\u8bae",no_mpell:"\u65e0\u62fc\u5199\u9519\u8bef"},pagebreak:{desc:"\u63d2\u5165\u5206\u9875\u7b26\u53f7"},advlist:{types:"\u6837\u5f0f",def:"\u9884\u8bbe",lower_alpha:"\u5c0f\u5199\u7684\u82f1\u6587\u5b57",lower_greek:"\u5c0f\u5199\u7684\u5e0c\u814a\u6587\u5b57",lower_roman:"\u5c0f\u5199\u7684\u7f57\u9a6c\u6570\u5b57",upper_alpha:"\u5927\u5199\u7684\u82f1\u6587\u5b57",upper_roman:"\u5927\u5199\u7684\u7f57\u9a6c\u6570\u5b57",circle:"\u5706\u5708",disc:"\u5706\u70b9",square:"\u65b9\u5f62"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/bs.js0000644000175000017500000001260111526350525031511 0ustar frankiefrankietinyMCE.addI18n({bs:{common:{more_colors:"Vi\u0161e boja",invalid_data:"Gre\u0161ka: Une\u0161ene su nevaljane vrijednosti, ozna\u010dene su crvenom bojom.",popup_blocked:"Oprostite, izgleda da je va\u0161 popup-blocker onemogu\u0107io prozor u sklopu ovog programa. Morate onemogu\u0107iti blokiranje popup prozora da bi u potpunosti iskoristili ovaj alat.",clipboard_no_support:"Trenuta\u010dno va\u0161 preglednik ne podr\u017eava ovu opciju, poku\u0161ajte koristiti tipkovni\u010dku kraticu.",clipboard_msg:"Kopiraj/Izre\u017ei/Zalijepi nije dostupno Mozilla i Firefox preglednicima.\\nVi\u0161e informacija?",not_set:"-- Nije postavljeno --",class_name:"Klasa",browse:"Pregled",close:"Zatvori",cancel:"Odustani",update:"Obnovi",insert:"Umetni",apply:"Primjeni",edit_confirm:"\u017delite li koristiti WYSIWYG na\u010din rada za ovo tekstualno polje?"},contextmenu:{full:"Puno",right:"Desno",center:"Sredina",left:"Lijevo",align:"Poravnavanje"},insertdatetime:{day_short:"ned,pon,uto,sri,\u010det,pet,sub,ned",day_long:"nedjelja,ponedjeljak,utorak,srijeda,\u010detvrtak,petak,subota,nedjelja",months_short:"sij,velj,o\u017eu,tra,svi,lip,srp,kol,ruj,lis,stu,pro",months_long:"sije\u010danj,velja\u010da,o\u017eujak,travanj,svibanj,lipanj,srpanj,kolovoz,rujan,listopad,studeni,prosinac",inserttime_desc:"Umetni vrijeme",insertdate_desc:"Umetni datum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y."},print:{print_desc:"Ispis"},preview:{preview_desc:"Prikaz"},directionality:{rtl_desc:"S desna na lijevo",ltr_desc:"S lijeva na desno"},layer:{content:"Novi sloj...",absolute_desc:"Uklju\u010di/isklju\u010di apsolutno pozicioniranje",backward_desc:"Pomakni natrag",forward_desc:"Pomakni naprijed",insertlayer_desc:"Umetni novi sloj"},save:{save_desc:"Spremi",cancel_desc:"Odustani od svih promjena"},nonbreaking:{nonbreaking_desc:"Umetni razmak"},iespell:{download:"Provjera pravopisa nije postaljena. Postaviti sada?",iespell_desc:"Pokreni provjeru pravopisa"},advhr:{advhr_desc:"Vodoravna crta",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emocije",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Prona\u0111i/Zamijeni",search_desc:"Prona\u0111i",delta_width:"",delta_height:""},advimage:{image_desc:"Umetni/uredi sliku",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Umetni/uredi atribute",ins_desc:"Unos",del_desc:"Brisanje",acronym_desc:"Akronim",abbr_desc:"Kratica",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Uredi CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Odaberi sve",paste_word_desc:"Zalijepi iz Worda",paste_text_desc:"Zalijepi kao obi\u010dni tekst",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Koristite CTRL+V na tipkovnici da zalijepite tekst u prozor.",text_linebreaks:"Zadr\u017ei prijelome",text_title:"Koristite CTRL+V na tipkovnici da zalijepite tekst u prozor."},table:{cell:"\u0106elija",col:"Stupac",row:"Redak",del:"Izbri\u0161i tablicu",copy_row_desc:"Kopiraj redak",cut_row_desc:"Izre\u017ei redak",paste_row_after_desc:"Zalijepi redak ispod",paste_row_before_desc:"Zalijepi redak iznad",props_desc:"Svojstva tablice",cell_desc:"Svojstva \u0107elije",row_desc:"Svojstva retka",merge_cells_desc:"Spoji \u0107elije",split_cells_desc:"Razdvoji spojene \u0107elije",delete_col_desc:"Ukloni stupac",col_after_desc:"Umetni stupac desno",col_before_desc:"Umetni stupac lijevo",delete_row_desc:"Izbri\u0161i redak",row_after_desc:"Umetni redak ispod",row_before_desc:"Umetni redak iznad",desc:"Nova tablica",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Promjene u dokumentu \u0107e biti izgubljene ako iza\u0111ete s ove stranice.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Uklju\u010di/isklju\u010di prikaz preko cijelog ekrana"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Svojstva dokumenta",delta_width:"",delta_height:""},template:{desc:"Umetni sadr\u017eaj iz predlo\u017eak"},visualchars:{desc:"Vizualni kontrolni znakovi uklju\u010deni/isklju\u010deni."},spellchecker:{desc:"Uklju\u010di/isklju\u010di provjeru pravopisa",menu:"Postavke provjere pravopisa",ignore_word:"Zanemari rije\u010d",ignore_words:"Zanemari sver",langs:"Jezici",wait:"Pri\u010dekajte...",sug:"Prijedlozi",no_sug:"Nema prijedloga",no_mpell:"Nije prona\u0111ena nijedna pravopisna gre\u0161ke."},pagebreak:{desc:"Umetni prijelom."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/da.js0000644000175000017500000001304111526350525031470 0ustar frankiefrankietinyMCE.addI18n({da:{common:{more_colors:"Flere farver",invalid_data:"Fejl: Forkerte v\u00e6rdier indtastet i felter markeret med r\u00f8d.",popup_blocked:"Undskyld, men vi har noteret os, at din popup-blocker har forhindret et vindue, der giver programmet funktionalitet, at \u00e5bne op. Hvis du vil have den fulde funktionalitet, m\u00e5 du sl\u00e5 popup-blockeren fra for dette websted.",clipboard_no_support:"P\u00e5 nuv\u00e6rende tidspunkt ikke supporteret af din browser. Anvend i stedet genvejene p\u00e5 tastaturet.",clipboard_msg:"Kopier/Klip/inds\u00e6t er ikke muligt i Mozilla eller Firefox.\\nVil du have mere information om dette emne?",not_set:"-- Ikke sat --",class_name:"Klasse",browse:"Gennemse",close:"Luk",cancel:"Annuller",update:"Opdater",insert:"Inds\u00e6t",apply:"Anvend",edit_confirm:"Vil du bruge den avancerede tekstredigering?"},contextmenu:{full:"Lige marginer",right:"H\u00f8jre",center:"Centreret",left:"Venstre",align:"Justering"},insertdatetime:{day_short:"S\u00f8n,Man,Tir,Ons,Tors,Fre,L\u00f8r,S\u00f8n",day_long:"S\u00f8ndag,Mandag,Tirsdag,Onsdag,Torsdag,Fredag,L\u00f8rdag,S\u00f8ndag",months_short:"Jan,Feb,Mar,Apr,Maj,Jun,Jul,Aug,Sep,Okt,Nov,Dec",months_long:"Januar,Februar,Marts,April,Maj,Juni,Juli,August,September,Oktober,November,December",inserttime_desc:"Inds\u00e6t klokkeslet",insertdate_desc:"Inds\u00e6t dato",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Udskriv"},preview:{preview_desc:"Vis udskrift"},directionality:{rtl_desc:"Retning h\u00f8jre mod venstre",ltr_desc:"Retning venstre mod h\u00f8jre"},layer:{content:"Nyt lag...",absolute_desc:"Sl\u00e5 absolut positionering til/fra",backward_desc:"Flyt bagud",forward_desc:"Flyt fremad",insertlayer_desc:"Inds\u00e6t nyt lag"},save:{save_desc:"Gem",cancel_desc:"Annuller alle \u00e6ndringer"},nonbreaking:{nonbreaking_desc:"Inds\u00e6t et blanktegn"},iespell:{download:"ieSpell blev ikke fundet. Vil du installere det nu?",iespell_desc:"Udf\u00f8r stavekontrol"},advhr:{advhr_desc:"Horisontal linie",delta_height:"",delta_width:""},emotions:{emotions_desc:"Hum\u00f8rikoner",delta_height:"",delta_width:""},searchreplace:{replace_desc:"S\u00f8g/erstat",search_desc:"S\u00f8g",delta_width:"",delta_height:""},advimage:{image_desc:"Inds\u00e6t/rediger billede",delta_width:"",delta_height:""},advlink:{delta_width:"40",link_desc:"Inds\u00e6t/rediger link",delta_height:""},xhtmlxtras:{attribs_desc:"Inds\u00e6t/rediger attributter",ins_desc:"Inds\u00e6ttelse",del_desc:"Sletning",acronym_desc:"Akronym",abbr_desc:"Forkortelse",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Rediger CSS stil",delta_height:"",delta_width:""},paste:{plaintext_mode:"Inds\u00e6t er nu i ikke-formateret modus. Klik igen for at skfite tilbage til almindelig inds\u00e6t modus.",plaintext_mode_sticky:"Inds\u00e6t er nu i ikke-formateret modus. Klik igen for at skfite tilbage til almindelig inds\u00e6t modus. Efter du har indsat noget s\u00e6ttes du automatisk tilbaeg til alminde inds\u00e6t modus.",selectall_desc:"V\u00e6lg alle",paste_word_desc:"Inds\u00e6t fra Word",paste_text_desc:"Inds\u00e6t ikke-formatteret tekst"},paste_dlg:{word_title:"Anvend CTRL+V p\u00e5 tastaturet for at inds\u00e6tte teksten.",text_linebreaks:"Bevar linieskift",text_title:"Anvend CTRL+V p\u00e5 tastaturet for at inds\u00e6tte teksten."},table:{cell:"Celle",col:"Kolonne",row:"R\u00e6kke",del:"Slet tabel",copy_row_desc:"Kopier r\u00e6kke",cut_row_desc:"Klip r\u00e6kke",paste_row_after_desc:"Inds\u00e6t r\u00e6kke efter",paste_row_before_desc:"Inds\u00e6t r\u00e6kke f\u00f8r",props_desc:"Tabelegenskaber",cell_desc:"Celleegenskaber",row_desc:"R\u00e6kkeegenskaber",merge_cells_desc:"Flet celler",split_cells_desc:"Opdel flettede celler",delete_col_desc:"Slet kolonne",col_after_desc:"Inds\u00e6t kolonne efter",col_before_desc:"Inds\u00e6t kolonne f\u00f8r",delete_row_desc:"Slet r\u00e6kke",row_after_desc:"Inds\u00e6t r\u00e6kke efter",row_before_desc:"Inds\u00e6t r\u00e6kke f\u00f8r",desc:"Inds\u00e6t tabel",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Hvis du genskaber det gemte indhold vil du miste al det indhold der lige nu er i editoren.nnEr du sikker p\u00e5 du vil genskabe det gemte indhold?",restore_content:"Genskab det gemte indhold.",unload_msg:"Har du foretaget nogle \u00e6ndringer, vil de g\u00e5 tabt, hvis du navigerer v\u00e6k fra denne side."},fullscreen:{desc:"Vis/skjul fuldsk\u00e6rmstilstand"},media:{edit:"Rediger indlejret mediefil",desc:"Inds\u00e6t/rediger indlejret mediefil",delta_height:"",delta_width:""},fullpage:{desc:"Dokumentegenskaber",delta_width:"",delta_height:""},template:{desc:"Inds\u00e6t pr\u00e6defineret skabelonindhold"},visualchars:{desc:"Vis/Skjul visuelle kontroltegn."},spellchecker:{desc:"Vis/skjul stavekontrol",menu:"Indstillinger for stavekontrol",ignore_word:"Ignorer ord",ignore_words:"Ignorer alle",langs:"Sprog",wait:"Vent venligst...",sug:"Forslag",no_sug:"Ingen forslag",no_mpell:"Ingen stavefejl fundet."},pagebreak:{desc:"Inds\u00e6t sideskift."},advlist:{types:"Typer",def:"Standard",lower_alpha:"Sm\u00e5 alfa",lower_greek:"Sm\u00e5 gr\u00e6ske",lower_roman:"Sm\u00e5 romertal",upper_alpha:"Store alfa",upper_roman:"Store romertal",circle:"Cirkel",disc:"Prik",square:"Firkant"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/de.js0000644000175000017500000001327011526350525031500 0ustar frankiefrankietinyMCE.addI18n({de:{common:{more_colors:"Weitere Farben",invalid_data:"Fehler: Sie haben ung\u00fcltige Werte eingegeben (rot markiert).",popup_blocked:"Leider hat Ihr Popup-Blocker ein Fenster unterbunden, das f\u00fcr den Betrieb dieses Programms n\u00f6tig ist. Bitte deaktivieren Sie den Popup-Blocker f\u00fcr diese Seite.",clipboard_no_support:"Wird derzeit in Ihrem Browser nicht unterst\u00fctzt. Bitte benutzen Sie stattdessen die Tastenk\u00fcrzel.",clipboard_msg:"Kopieren, Ausschneiden und Einf\u00fcgen sind im Mozilla Firefox nicht m\u00f6glich.\\nM\u00f6chten Sie mehr \u00fcber dieses Problem erfahren?",not_set:"- unbestimmt -",class_name:"CSS-Klasse",browse:"Durchsuchen",close:"Schlie\u00dfen",cancel:"Abbrechen",update:"Aktualisieren",insert:"Einf\u00fcgen",apply:"\u00dcbernehmen",edit_confirm:"M\u00f6chten Sie diesen Text jetzt bearbeiten?"},contextmenu:{full:"Blocksatz",right:"Rechtsb\u00fcndig",center:"Zentriert",left:"Linksb\u00fcndig",align:"Ausrichtung"},insertdatetime:{day_short:"So,Mo,Di,Mi,Do,Fr,Sa,So",day_long:"Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag,Sonntag",months_short:"Jan,Feb,M\u00e4r,Apr,Mai,Juni,Juli,Aug,Sept,Okt,Nov,Dez",months_long:"Januar,Februar,M\u00e4rz,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",inserttime_desc:"Zeit einf\u00fcgen",insertdate_desc:"Datum einf\u00fcgen",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"Drucken"},preview:{preview_desc:"Vorschau"},directionality:{rtl_desc:"Schrift von rechts nach links",ltr_desc:"Schrift von links nach rechts"},layer:{content:"Neue Ebene...",absolute_desc:"Absolute Positionierung",backward_desc:"Nach hinten legen",forward_desc:"Nach vorne holen",insertlayer_desc:"Neue Ebene einf\u00fcgen"},save:{save_desc:"Speichern",cancel_desc:"Alle \u00c4nderungen verwerfen"},nonbreaking:{nonbreaking_desc:"Gesch\u00fctztes Leerzeichen einf\u00fcgen"},iespell:{download:"ieSpell konnte nicht gefunden werden. Wollen Sie es installieren?",iespell_desc:"Rechtschreibpr\u00fcfung"},advhr:{advhr_desc:"Trennlinie",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smilies",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Suchen/Ersetzen",search_desc:"Suchen",delta_width:"",delta_height:""},advimage:{image_desc:"Bild einf\u00fcgen/ersetzen",delta_width:"",delta_height:""},advlink:{link_desc:"Link einf\u00fcgen/bearbeiten",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Attribute einf\u00fcgen/bearbeiten",ins_desc:"Eingef\u00fcgter Text",del_desc:"Entfernter Text",acronym_desc:"Akronym",abbr_desc:"Abk\u00fcrzung",cite_desc:"Quellenangabe",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS-Styles bearbeiten",delta_height:"",delta_width:""},paste:{plaintext_mode:"Einf\u00fcgemodus ist nun \"Nur Text\". Erneut klicken stellt den Normalmodus wieder her.",plaintext_mode_sticky:"Einf\u00fcgemodus ist nun \"Nur Text\". Erneut klicken (oder das Einf\u00fcgen aus der Zwischenablage) stellt den Normalmodus wieder her.",selectall_desc:"Alles ausw\u00e4hlen",paste_word_desc:"Mit Formatierungen (aus Word) einf\u00fcgen",paste_text_desc:"Als einfachen Text einf\u00fcgen"},paste_dlg:{word_title:"Dr\u00fccken Sie auf Ihrer Tastatur Strg+V, um den Text einzuf\u00fcgen.",text_linebreaks:"Zeilenumbr\u00fcche beibehalten",text_title:"Dr\u00fccken Sie auf Ihrer Tastatur Strg+V, um den Text einzuf\u00fcgen."},table:{cellprops_delta_width:"150",cell:"Zelle",col:"Spalte",row:"Zeile",del:"Tabelle l\u00f6schen",copy_row_desc:"Zeile kopieren",cut_row_desc:"Zeile ausschneiden",paste_row_after_desc:"Zeile unterhalb aus der Zwischenablage einf\u00fcgen",paste_row_before_desc:"Zeile oberhalb aus der Zwischenablage einf\u00fcgen",props_desc:"Eigenschaften der Tabelle",cell_desc:"Eigenschaften der Zelle",row_desc:"Eigenschaften der Zeile",merge_cells_desc:"Zellen verbinden",split_cells_desc:"Verbundene Zellen trennen",delete_col_desc:"Spalte l\u00f6schen",col_after_desc:"Spalte rechts einf\u00fcgen",col_before_desc:"Spalte links einf\u00fcgen",delete_row_desc:"Zeile l\u00f6schen",row_after_desc:"Zeile unterhalb einf\u00fcgen",row_before_desc:"Zeile oberhalb einf\u00fcgen",desc:"Tabelle erstellen/bearbeiten",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Wenn Sie den Inhalt wiederherstellen, gehen die aktuellen Daten im Editor verloren.\\n\\nSind sie sicher, dass Sie den Inhalt wiederherstellen m\u00f6chten?",restore_content:"Automatisch gespeicherten Inhalt wiederherstellen.",unload_msg:"Ihre \u00c4nderungen werden verloren gehen, wenn Sie die Seite verlassen."},fullscreen:{desc:"Vollbildschirm"},media:{edit:"Multimediaeinbettung bearbeiten",desc:"Multimedia einbetten/bearbeiten",delta_height:"",delta_width:""},fullpage:{desc:"Dokument-Eigenschaften",delta_width:"",delta_height:""},template:{desc:"Inhalt aus Vorlage einf\u00fcgen"},visualchars:{desc:"Sichtbarkeit der Steuerzeichen an/aus"},spellchecker:{desc:"Rechtschreibpr\u00fcfung an/aus",menu:"Einstellungen der Rechtschreibpr\u00fcfung",ignore_word:"Wort ignorieren",ignore_words:"Alle ignorieren",langs:"Sprachen",wait:"Bitte warten...",sug:"Vorschl\u00e4ge",no_sug:"Keine Vorschl\u00e4ge",no_mpell:"Keine Rechtschreibfehler gefunden."},pagebreak:{desc:"Seitenumbruch einf\u00fcgen"},advlist:{types:"Typen",def:"Standard",lower_alpha:"a. b. c.",lower_greek:"1. 2. 3.",lower_roman:"i. ii. iii.",upper_alpha:"A. B. C.",upper_roman:"I. II. III.",circle:"Kreis",disc:"Punkt",square:"Quadrat"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/cs.js0000644000175000017500000001522011526350525031512 0ustar frankiefrankietinyMCE.addI18n({cs:{common:{more_colors:"Dal\u0161\u00ed barvy",invalid_data:"Chyba: Byly zad\u00e1ny neplatn\u00e9 hodnoty a tyto byly ozna\u010deny \u010derven\u011b.",popup_blocked:"Omlouv\u00e1me se, ale blokov\u00e1n\u00ed vyskakovac\u00edch oken neumo\u017enilo otev\u0159\u00edt okno, kter\u00e9 poskytuje funk\u010dnost aplikace. Pro pln\u00e9 vyu\u017eit\u00ed mo\u017enost\u00ed aplikace mus\u00edte vypnout blokov\u00e1n\u00ed vyskakovac\u00edch oken pro tento web.",clipboard_no_support:"Tato funkce nen\u00ed va\u0161\u00edm prohl\u00ed\u017ee\u010dem podporov\u00e1na. Pou\u017eijte m\u00edsto toho kl\u00e1vesov\u00e9 zkratky.",clipboard_msg:"Funkce kop\u00edrovat/vyjmout/vlo\u017eit nejsou podporovan\u00e9 v prohl\u00ed\u017ee\u010d\u00edch Mozilla a Firefox.\\nChcete v\u00edce informac\u00ed o tomto probl\u00e9mu?",not_set:"- Nenastaveno -",class_name:"T\u0159\u00edda",browse:"Proch\u00e1zet",close:"Zav\u0159\u00edt",cancel:"Storno",update:"Aktualizovat",insert:"Vlo\u017eit",apply:"Pou\u017e\u00edt",edit_confirm:"Chcete pou\u017e\u00edt WYSIWYG re\u017eim pro tento text?"},contextmenu:{full:"Do bloku",right:"Doprava",center:"Na st\u0159ed",left:"Doleva",align:"Zarovn\u00e1n\u00ed"},insertdatetime:{day_short:"Ne,Po,\u00dat,St,\u010ct,P\u00e1,So,Ne",day_long:"Ned\u011ble,Pond\u011bl\u00ed,\u00dater\u00fd,St\u0159eda,\u010ctvrtek,P\u00e1tek,Sobota,Ned\u011ble",months_short:"Led,\u00dano,B\u0159e,Dub,Kv\u011b,\u010cer,\u010cvc,Srp,Z\u00e1\u0159,\u0158\u00edj,Lis,Pro",months_long:"Leden,\u00danor,B\u0159ezen,Duben,Kv\u011bten,\u010cerven,\u010cervenec,Srpen,Z\u00e1\u0159\u00ed,\u0158\u00edjen,Listopad,Prosinec",inserttime_desc:"Vlo\u017eit \u010das",insertdate_desc:"Vlo\u017eit datum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"Tisk"},preview:{preview_desc:"N\u00e1hled"},directionality:{rtl_desc:"Sm\u011br zprava doleva",ltr_desc:"Sm\u011br zleva doprava"},layer:{content:"Nov\u00e1 vrstva...",absolute_desc:"P\u0159epnout na absolutn\u00ed pozicov\u00e1n\u00ed",backward_desc:"P\u0159esunout dozadu",forward_desc:"P\u0159esunout dop\u0159edu",insertlayer_desc:"Vlo\u017eit novou vrstvu"},save:{save_desc:"Ulo\u017eit",cancel_desc:"Zru\u0161it v\u0161echny zm\u011bny"},nonbreaking:{nonbreaking_desc:"Vlo\u017eit ned\u011blitelnou mezeru"},iespell:{download:"Slovn\u00edk ieSpell nebyl detekov\u00e1n. Chcete ho nainstalovat?",iespell_desc:"Spustit kontrolu pravopisu"},advhr:{advhr_desc:"Vodorovn\u00fd odd\u011blova\u010d",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotikony",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Naj\u00edt/nahradit",search_desc:"Naj\u00edt",delta_width:"",delta_height:""},advimage:{delta_width:"20",image_desc:"Vlo\u017eit/upravit obr\u00e1zek",delta_height:""},advlink:{link_desc:"Vlo\u017eit/upravit odkaz",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Vlo\u017eit/upravit atributy",ins_desc:"P\u0159idan\u00fd text",del_desc:"Odstran\u011bn\u00fd text",acronym_desc:"Akronym",abbr_desc:"Zkratka",cite_desc:"Citace",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{delta_width:"25",desc:"Upravit CSS styl",delta_height:""},paste:{plaintext_mode:"Funkce vlo\u017eit je nyn\u00ed v re\u017eimu prost\u00fd text. Op\u011btovn\u00e9 kliknut\u00ed p\u0159epne tuto funkci zp\u011bt do norm\u00e1ln\u00edho re\u017eimu.",plaintext_mode_sticky:"Funkce vlo\u017eit je nyn\u00ed v re\u017eimu prost\u00fd text. Op\u011btovn\u00e9 kliknut\u00ed p\u0159epne tuto funkci zp\u011bt do norm\u00e1ln\u00edho re\u017eimu. Po vlo\u017een\u00ed \u010dehokoli bude tato funkce vr\u00e1cena zp\u011bt do norm\u00e1ln\u00edho re\u017eimu.",selectall_desc:"Vybrat v\u0161e",paste_word_desc:"Vlo\u017eit z Wordu",paste_text_desc:"Vlo\u017eit jako prost\u00fd text"},paste_dlg:{word_title:"Pou\u017eijte CTRL+V pro vlo\u017een\u00ed textu do okna.",text_linebreaks:"Zachovat zalamov\u00e1n\u00ed \u0159\u00e1dk\u016f",text_title:"Pou\u017eijte CTRL+V pro vlo\u017een\u00ed textu do okna."},table:{table_delta_width:"50",cellprops_delta_width:"100",cell:"Bu\u0148ka",col:"Sloupec",row:"\u0158\u00e1dek",del:"Odstranit tabulku",copy_row_desc:"Kop\u00edrovat \u0159\u00e1dek tabulky",cut_row_desc:"Vyjmout \u0159\u00e1dek tabulky",paste_row_after_desc:"Vlo\u017eit \u0159\u00e1dek za",paste_row_before_desc:"Vlo\u017eit \u0159\u00e1dek p\u0159ed",props_desc:"Vlastnosti tabulky",cell_desc:"Vlastnosti bu\u0148ky",row_desc:"Vlastnosti \u0159\u00e1dku tabulky",merge_cells_desc:"Slou\u010dit bu\u0148ky",split_cells_desc:"Rozd\u011blit bu\u0148ky",delete_col_desc:"Odstranit sloupec tabulky",col_after_desc:"Vlo\u017eit sloupec za",col_before_desc:"Vlo\u017eit sloupec p\u0159ed",delete_row_desc:"Odstranit \u0159\u00e1dek tabulky",row_after_desc:"Vlo\u017eit \u0159\u00e1dek za",row_before_desc:"Vlo\u017eit \u0159\u00e1dek p\u0159ed",desc:"Vlo\u017eit novou tabulku",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Pokud obnov\u00edte ulo\u017een\u00fd obsah, ztrat\u00edte t\u00edm ve\u0161ker\u00fd obsah, kter\u00fd je pr\u00e1v\u011b v okn\u011b editoru.\\n\\nOpravdu chcete obnovit ulo\u017een\u00fd obsah?.",restore_content:"Obnovit automaticky ulo\u017een\u00fd obsah.",unload_msg:"Proveden\u00e9 zm\u011bny mohou b\u00fdt ztraceny, jestli\u017ee opust\u00edte tuto str\u00e1nku."},fullscreen:{desc:"P\u0159epnout na celostr\u00e1nkov\u00e9 zobrazen\u00ed"},media:{delta_width:"130",edit:"Upravit m\u00e9dia",desc:"Vlo\u017eit/upravit m\u00e9dia",delta_height:""},fullpage:{desc:"Vlastnosti dokumentu",delta_width:"110",delta_height:""},template:{desc:"Vlo\u017eit p\u0159eddefinovan\u00fd obsah ze \u0161ablony"},visualchars:{desc:"Zobrazen\u00ed skryt\u00fdch znak\u016f zap/vyp"},spellchecker:{desc:"P\u0159epnout kontrolu pravopisu",menu:"Nastaven\u00ed kontroly pravopisu",ignore_word:"Ignorovat slovo",ignore_words:"Ignorovat v\u0161e",langs:"Jazyky",wait:"\u010cekejte pros\u00edm...",sug:"N\u00e1pov\u011bda",no_sug:"\u017d\u00e1dn\u00e1 n\u00e1pov\u011bda",no_mpell:"Nebyly nalezeny \u017e\u00e1dn\u00e9 chyby."},pagebreak:{desc:"Vlo\u017eit konec str\u00e1nky"},advlist:{types:"Typ",def:"V\u00fdchoz\u00ed",lower_alpha:"Mal\u00e1 p\u00edsmena",lower_greek:"Mal\u00e1 \u0159eck\u00e1 p\u00edsmena",lower_roman:"Mal\u00e9 \u0159\u00edmsk\u00e9 \u010d\u00edslice",upper_alpha:"Velk\u00e1 p\u00edsmena",upper_roman:"Velk\u00e9 \u0159\u00edmsk\u00e9 \u010d\u00edslice",circle:"Kole\u010dko",disc:"Punt\u00edk",square:"\u010ctvere\u010dek"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/cy.js0000644000175000017500000001256611526350525031532 0ustar frankiefrankietinyMCE.addI18n({cy:{common:{more_colors:"Mwy o liwiau",invalid_data:"Gwall: Gwerthau allilys wedi mewnbynnu, mae\'r gwerthau yma wedi eu marcio mewn coch.",popup_blocked:"Rydym wedi sylwi fod eich popup-blocker wedi analluogi ffenest sy\'n darparu swyddogaeth cymhwysiad. Bydd rhaid i chi analluogi blocio popups ar gyfer y safle yma i ddefnyddio\'r offeryn yma.",clipboard_no_support:"Dim wedi\'i gynnal gan eich porwr, defnyddiwch Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Nid yw Cop\u00efo/Torri/Gludo ar gael mewn Mozilla a Firefox.\\nYdych chi eisiau mwy o wybodaeth am y mater yma?",not_set:"-- Nid wedi osod --",class_name:"Dosbarth",browse:"Pori",close:"Cau",cancel:"Diddymu",update:"Diweddaru",insert:"Mewnosod",apply:"Gosod",edit_confirm:"Ydych chi eisiau defnyddio\'r modd WYSIWYG ar gyfer y textarea yma?"},contextmenu:{full:"Llawn",right:"De",center:"Canol",left:"Chwith",align:"Aliniad"},insertdatetime:{day_short:"Sul,Llu,Maw,Mer,Iau,Gwe,Sad,Sul",day_long:"Sul,Llun,Mawrth,Mercher,Iau,Gwener,Sadwrn,Sul",months_short:"Ion,Chw,Maw,Ebr,Mai,Meh,Gor,Aws,Med,Hyd,Tac,Rha",months_long:"Ionawr,Chwefror,Mawrth,Ebrill,Mai,Mehefin,Goffennaf,Awst,Medi,Hydref,Tachwedd,Rhagfyr",inserttime_desc:"Mewnosod amser",insertdate_desc:"Mewnosod dyddiad",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Argraffu"},preview:{preview_desc:"Rhagolygu"},directionality:{rtl_desc:"Cyfeiriad de i\'r chwith",ltr_desc:"Cyfeiriad chwith i\'r dde"},layer:{content:"Haen newydd...",absolute_desc:"Toglu lleoli absoliwt",backward_desc:"Symud n\u00f4l",forward_desc:"Symud ymlaen",insertlayer_desc:"Mewnosod haen newydd"},save:{save_desc:"Cadw",cancel_desc:"Cadw pob newidiad"},nonbreaking:{nonbreaking_desc:"Mewnosod n\u00f4d bwlch do-doriad"},iespell:{download:"ieSpell dim wedi\'i canfod. A ydych eisiau ei gosod rwan?",iespell_desc:"Rhedeg gwirio sillafu"},advhr:{advhr_desc:"Mesurydd llorweddol",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emosiwn",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Canfod/Amnewid",search_desc:"Canfod",delta_width:"",delta_height:""},advimage:{image_desc:"Mewnosod/golygu delwedd",delta_width:"",delta_height:""},advlink:{link_desc:"Mewnosod/Golygu cyswllt",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Mewnosod/Golygu Priodoleddau",ins_desc:"Mewnosodiad",del_desc:"Dilead",acronym_desc:"Acronym",abbr_desc:"Talfyriad",cite_desc:"Dyfyniad",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Golygu Arddull CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Gludo rwan mewn modd testun plaen. Cliciwch eto i doglu n\u00f4l i fodd gludo normal.",plaintext_mode_sticky:"Gludo rwan mewn modd testun plaen. Cliciwch eto i doglu n\u00f4l i fodd gludo normal. Byddwch yn cael eich dychwelyd i fodd gludo normal ar \u00f4l gludo rhywbeth.",selectall_desc:"Dewis Pobpeth",paste_word_desc:"Gludo o Word",paste_text_desc:"Gludo fel Testun Plaen"},paste_dlg:{word_title:"Defnyddiwch CTRL+V ar eich bysellfwrdd i ludo\'r testun i fewn i\'r ffenest.",text_linebreaks:"Cadw toriadau llinell",text_title:"Defnyddiwch CTRL+V ar eich bysellfwrdd i ludo\'r testun i fewn i\'r ffenest."},table:{cell:"Cell",col:"Colofn",row:"Rhes",del:"Dileu tabl",copy_row_desc:"Cop\u00efo rhes tabl",cut_row_desc:"Torri rhes tabl",paste_row_after_desc:"Gludo rhes tabl ar \u00f4l",paste_row_before_desc:"Gludo rhes tabl cyn",props_desc:"Priodweddau tabl",cell_desc:"Priodweddau cell tabl",row_desc:"Priodweddau rhes tabl",merge_cells_desc:"Cyfuno celloedd tabl",split_cells_desc:"Hollti celloedd tabl cyfuniedig",delete_col_desc:"Tynnu colofn",col_after_desc:"Mewnosod colofn ar \u00f4l",col_before_desc:"Mewnosod colofn cyn",delete_row_desc:"Dileu rhes",row_after_desc:"Mewnosod rhes ar \u00f4l",row_before_desc:"Mewnosod rhes cyn",desc:"Mewnosod tabl newydd",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Os adferwch chi\'r cynnwys cadwedig, byddwch yn colli\'r holl cynnwys sydd yn bresennol yn y golygydd.\\n\\nA ydych chi\'n si\u0175r eich bod eisiau adfer y cynnwys cadwedig?.",restore_content:"Adfer cynnwys awto-cadwedig.",unload_msg:"Bydd eich newidiadau yn cael eu colli os byddwch yn llywio i ffwrdd o\'r tudalen yma."},fullscreen:{desc:"Toglu modd sgrin llawn"},media:{edit:"Golygu cyfrwng planedig",desc:"Mewnosod / golygu cyfrwng planedig",delta_height:"",delta_width:""},fullpage:{desc:"Priodweddau dogfen",delta_width:"",delta_height:""},template:{desc:"Mewnosod cynnwys templed rhagosodol"},visualchars:{desc:"Nodau rheolaeth ymlaen/i ffwrdd."},spellchecker:{desc:"Toglu cywiriadau",menu:"Gosodiadau cywiriadau",ignore_word:"Anwybyddu gair",ignore_words:"Anwybyddu pob un",langs:"Ieithoedd",wait:"Aroswch, os gwelwch yn dda...",sug:"Awgrymiadau",no_sug:"Dim awgrymiadau",no_mpell:"Dim camsillafiadau wedi\'i canfod."},pagebreak:{desc:"Mewnosod toriad tudalen."},advlist:{types:"Mathau",def:"Rhagosodedig",lower_alpha:"Alffa is",lower_greek:"Groegaiddd is",lower_roman:"Rhufeinig is",upper_alpha:"Alffa uwch",upper_roman:"Rhufeinig uwch",circle:"Cylch",disc:"Disg",square:"Sgw\u00e2r"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/dv.js0000644000175000017500000001510511526350525031520 0ustar frankiefrankietinyMCE.addI18n({dv:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"\u0789\u07a8\u0788\u07a6\u078e\u07aa\u078c\u07aa \u078c\u07a8\u0794\u07a6\u0784\u07ad\u078a\u07aa\u0785\u07a7\u078e\u07ac \u0784\u07b0\u0783\u07a6\u0787\u07aa\u0792\u07a6\u0783\u07aa \u0790\u07a6\u0795\u07af\u0793\u07b0 \u0782\u07aa\u0786\u07aa\u0783\u07a7\u078c\u07a9\u0788\u07ac \u0786\u07a9\u0784\u07af\u0791\u07b0\u078e\u07ac \u0786\u07a9\u078c\u07a6\u0787\u07b0 \u0784\u07ad\u0782\u07aa\u0782\u07b0\u0786\u07aa\u0783\u07a6\u0787\u07b0\u0788\u07a7.",clipboard_msg:"\u0789\u07ae\u0792\u07a8\u0787\u07b0\u078d\u07a7 \u0787\u07a6\u078b\u07a8 \u078a\u07a6\u0794\u07a7\u0783\u078a\u07ae\u0786\u07b0\u0790\u07b0\u078e\u07a6\u0787\u07a8 \u0786\u07ae\u0795\u07a9/\u0786\u07a6\u0793\u07b0/\u0795\u07ad\u0790\u07b0\u0793\u07b0 \u0782\u07aa\u0786\u07aa\u0783\u07ac\u0788\u07ac.\\n \u0789\u07a8\u0789\u07a6\u0787\u07b0\u0790\u07a6\u078d\u07a6 \u0787\u07a8\u078c\u07aa\u0783\u07a6\u0781\u07b0 \u0787\u07ae\u0785\u07aa\u0782\u07b0\u078a\u07a8\u078d\u07aa\u0788\u07aa\u0789\u07a6\u0781\u07b0 \u0784\u07ad\u0782\u07aa\u0782\u07b0\u078a\u07aa\u0785\u07aa\u0788\u07ad\u078c\u07a6\u061f",not_set:"-- \u0780\u07a6\u0789\u07a6\u0787\u07ac\u0787\u07b0 \u0782\u07aa\u0796\u07ac\u0780\u07ac --",class_name:"\u0786\u07b0\u078d\u07a7\u0790\u07b0",browse:"\u0784\u07a6\u0787\u07b0\u078d\u07a6\u0788\u07a7",close:"\u0782\u07a8\u0789\u07aa\u0782\u07a9",cancel:"\u0786\u07ac\u0782\u07b0\u0790\u07a6\u078d\u07b0",update:"\u0784\u07a6\u078b\u07a6\u078d\u07aa\u0786\u07aa\u0783\u07a6\u0787\u07b0\u0788\u07a7",insert:"\u0787\u07a8\u078c\u07aa\u0783\u07aa\u0786\u07aa\u0783\u07a6\u0787\u07b0\u0788\u07a7",apply:"\u0790\u07ad\u0788\u07b0",edit_confirm:"\u0789\u07a8\u0793\u07ac\u0786\u07b0\u0793\u07b0\u0790\u07b0\u0784\u07ae\u0786\u07b0\u0790\u07b0\u078e\u07a6\u0787\u07a8 \u0787\u07ac\u0791\u07a8\u0793\u07a7\u0783 \u0784\u07ad\u0782\u07aa\u0782\u07b0\u0786\u07aa\u0783\u07a6\u0782\u07b0 \u0784\u07ad\u0782\u07aa\u0782\u07b0\u078a\u07aa\u0785\u07aa\u078c\u07af\u061f"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/el.js0000644000175000017500000004077411526350525031521 0ustar frankiefrankietinyMCE.addI18n({el:{common:{more_colors:"\u03a0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1 \u03c7\u03c1\u03ce\u03bc\u03b1\u03c4\u03b1",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"\u0388\u03bd\u03b1 popup-blocker \u03c0\u03c1\u03cc\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1 \u03ad\u03c7\u03b5\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9 \u03ad\u03bd\u03b1 \u03c0\u03b1\u03c1\u03ac\u03b8\u03c5\u03c1\u03bf \u03b1\u03c0\u03b1\u03c1\u03b1\u03af\u03c4\u03b7\u03c4\u03bf \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae. \u03a0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03c4\u03bf \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03b9\u03c3\u03c4\u03bf\u03c3\u03b5\u03bb\u03af\u03b4\u03b1 \u03b1\u03c5\u03c4\u03ae \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c0\u03bb\u03ae\u03c1\u03c9\u03c2 \u03c4\u03b7\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae.",clipboard_no_support:"\u0394\u03b5\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03b7\u03c1\u03af\u03b6\u03b5\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03bf\u03bd \u03c6\u03c5\u03bb\u03bb\u03bf\u03bc\u03b5\u03c4\u03c1\u03b7\u03c4\u03ae \u03c3\u03b1\u03c2, \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b9\u03c2 \u03c3\u03c5\u03bd\u03c4\u03bf\u03bc\u03b5\u03cd\u03c3\u03b5\u03b9\u03c2 \u03c0\u03bb\u03b7\u03ba\u03c4\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03bf\u03c5.",clipboard_msg:"\u039f\u03b9 \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b5\u03c2 \u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae/\u0391\u03c0\u03bf\u03ba\u03bf\u03c0\u03ae/\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b4\u03b5\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03b5\u03c2 \u03c3\u03b5 Mozilla \u03ba\u03b1\u03b9 Firefox.\\n\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b5\u03c2 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 ;",not_set:"-- \u039c\u03b7 \u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf --",class_name:"\u039a\u03bb\u03ac\u03c3\u03b7",browse:"\u0395\u03cd\u03c1\u03b5\u03c3\u03b7",close:"\u039a\u03bb\u03b5\u03af\u03c3\u03b9\u03bc\u03bf",cancel:"\u0386\u03ba\u03c5\u03c1\u03bf",update:"\u0395\u03bd\u03b7\u03bc\u03ad\u03c1\u03c9\u03c3\u03b7",insert:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae",apply:"\u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae",edit_confirm:"\u0398\u03ad\u03bb\u03b5\u03c4\u03b5 \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03bb\u03b5\u03b9\u03c4\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 WYSIWYG ;"},contextmenu:{full:"\u03a0\u03bb\u03ae\u03c1\u03b7\u03c2",right:"\u0394\u03b5\u03be\u03b9\u03ac",center:"\u039a\u03ad\u03bd\u03c4\u03c1\u03bf",left:"\u0391\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac",align:"\u03a3\u03c4\u03bf\u03af\u03c7\u03b9\u03c3\u03b7"},insertdatetime:{day_short:"\u039a\u03c5,\u0394\u03b5,\u03a4\u03c1,\u03a4\u03b5\u03c4,\u03a0\u03ad\u03bc,\u03a0\u03b1\u03c1,\u03a3\u03b1\u03b2",day_long:"\u039a\u03c5\u03c1\u03b9\u03b1\u03ba\u03ae,\u0394\u03b5\u03c5\u03c4\u03ad\u03c1\u03b1,\u03a4\u03c1\u03af\u03c4\u03b7,\u03a4\u03b5\u03c4\u03ac\u03c1\u03c4\u03b7,\u03a0\u03ad\u03bc\u03c0\u03c4\u03b7,\u03a0\u03b1\u03c1\u03b1\u03c3\u03ba\u03b5\u03c5\u03ae,\u03a3\u03ac\u03b2\u03b2\u03b1\u03c4\u03bf",months_short:"\u0399\u03b1\u03bd,\u03a6\u03b5\u03b2,\u039c\u03ac\u03c1,\u0391\u03c0\u03c1,\u039c\u03ac\u03b9,\u0399\u03bf\u03cd\u03bd,\u0399\u03bf\u03cd\u03bb,\u0391\u03cd\u03b3,\u03a3\u03b5\u03c0,\u039f\u03ba\u03c4,\u039d\u03bf\u03ad,\u0394\u03b5\u03ba",months_long:"\u0399\u03b1\u03bd\u03bf\u03c5\u03ac\u03c1\u03b9\u03bf\u03c2,\u03a6\u03b5\u03b2\u03c1\u03bf\u03c5\u03ac\u03c1\u03b9\u03bf\u03c2,\u039c\u03ac\u03c1\u03c4\u03b9\u03bf\u03c2,\u0391\u03c0\u03c1\u03af\u03bb\u03b9\u03bf\u03c2,\u039c\u03ac\u03b9\u03bf\u03c2,\u0399\u03bf\u03cd\u03bd\u03b9\u03bf\u03c2,\u0399\u03bf\u03cd\u03bb\u03b9\u03bf\u03c2,\u0391\u03cd\u03b3\u03bf\u03c5\u03c3\u03c4\u03bf\u03c2,\u03a3\u03b5\u03c0\u03c4\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2,\u039f\u03ba\u03c4\u03ce\u03b2\u03c1\u03b9\u03bf\u03c2,\u039d\u03bf\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2,\u0394\u03b5\u03ba\u03ad\u03bc\u03b2\u03c1\u03b9\u03bf\u03c2",inserttime_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03ce\u03c1\u03b1\u03c2",insertdate_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b7\u03bc\u03ad\u03c1\u03b1\u03c2",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u0395\u03ba\u03c4\u03cd\u03c0\u03c9\u03c3\u03b7"},preview:{preview_desc:"\u03a0\u03c1\u03bf\u03b5\u03c0\u03b9\u03c3\u03ba\u03cc\u03c0\u03b7\u03c3\u03b7"},directionality:{rtl_desc:"\u039a\u03b1\u03c4\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 \u03b4\u03b5\u03be\u03b9\u03ac \u03c0\u03c1\u03bf\u03c2 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac",ltr_desc:"\u039a\u03b1\u03c4\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac \u03c0\u03c1\u03bf\u03c2 \u03b4\u03b5\u03be\u03b9\u03ac"},layer:{content:"\u039d\u03ad\u03bf layer...",absolute_desc:"\u0391\u03c0\u03cc\u03bb\u03c5\u03c4\u03b7/\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ae \u03c4\u03bf\u03c0\u03bf\u03b8\u03ad\u03c4\u03b7\u03c3\u03b7",backward_desc:"\u039c\u03b5\u03c4\u03b1\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf \u03c0\u03b1\u03c1\u03b1\u03c3\u03ba\u03ae\u03bd\u03b9\u03bf",forward_desc:"\u039c\u03b5\u03c4\u03b1\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03c3\u03c4\u03bf \u03c0\u03c1\u03bf\u03c3\u03ba\u03ae\u03bd\u03b9\u03bf",insertlayer_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03bd\u03ad\u03bf\u03c5 layer"},save:{save_desc:"\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7",cancel_desc:"\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03cc\u03bb\u03c9\u03bd \u03c4\u03c9\u03bd \u03b1\u03bb\u03bb\u03b1\u03b3\u03ce\u03bd"},nonbreaking:{nonbreaking_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae non-breaking \u03ba\u03b5\u03bd\u03bf\u03cd \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03b1"},iespell:{download:"\u03a4\u03bf ieSpell \u03b4\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5. \u039d\u03b1 \u03ba\u03b1\u03c4\u03ad\u03b2\u03b5\u03b9 \u03c4\u03ce\u03c1\u03b1 ;",iespell_desc:"\u0395\u03ba\u03c4\u03ad\u03bb\u03b5\u03c3\u03b7 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 \u03bf\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b1\u03c2"},advhr:{advhr_desc:"\u039f\u03c1\u03b9\u03b6\u03cc\u03bd\u03c4\u03b9\u03b1 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u03a3\u03c5\u03bd\u03b1\u03b9\u03c3\u03b8\u03ae\u03bc\u03b1\u03c4\u03b1",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0395\u03cd\u03c1\u03b5\u03c3\u03b7/\u0391\u03bd\u03c4\u03b9\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7",search_desc:"\u0395\u03cd\u03c1\u03b5\u03c3\u03b7",delta_width:"",delta_height:""},advimage:{image_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b5\u03b9\u03ba\u03cc\u03bd\u03b1\u03c2",delta_width:"",delta_height:""},advlink:{delta_width:"50",link_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",delta_height:""},xhtmlxtras:{attribs_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b9\u03b4\u03b9\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd",ins_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae",del_desc:"\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae",acronym_desc:"\u0391\u03ba\u03c1\u03bf\u03bd\u03cd\u03bc\u03b9\u03bf",abbr_desc:"\u03a3\u03c5\u03bd\u03c4\u03bf\u03bc\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b1",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03a3\u03c4\u03c5\u03bb CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"\u0395\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03cc\u03bb\u03c9\u03bd",paste_word_desc:"\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b1\u03c0\u03cc \u03c4\u03bf Word",paste_text_desc:"\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03c9\u03c2 \u03b1\u03c0\u03bb\u03cc \u03ba\u03b5\u03af\u03bc\u03b5\u03bd\u03bf",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u03a7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 CTRL+V \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03ba\u03ac\u03bd\u03b5\u03c4\u03b5 \u03b5\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c3\u03c4\u03bf \u03c0\u03b1\u03c1\u03ac\u03b8\u03c5\u03c1\u03bf.",text_linebreaks:"\u039d\u03b1 \u03ba\u03c1\u03b1\u03c4\u03b7\u03b8\u03bf\u03cd\u03bd \u03c4\u03b1 linebreaks",text_title:"\u03a7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 CTRL+V \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03ba\u03ac\u03bd\u03b5\u03c4\u03b5 \u03b5\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c3\u03c4\u03bf \u03c0\u03b1\u03c1\u03ac\u03b8\u03c5\u03c1\u03bf."},table:{cellprops_delta_width:"60",cell:"\u039a\u03b5\u03bb\u03af",col:"\u03a3\u03c4\u03ae\u03bb\u03b7",row:"\u0393\u03c1\u03b1\u03bc\u03bc\u03ae",del:"\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",copy_row_desc:"\u0391\u03bd\u03c4\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",cut_row_desc:"\u0391\u03c0\u03bf\u03ba\u03bf\u03c0\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",paste_row_after_desc:"\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03bc\u03b5\u03c4\u03ac",paste_row_before_desc:"\u0395\u03c0\u03b9\u03ba\u03cc\u03bb\u03bb\u03b7\u03c3\u03b7 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1 \u03c0\u03c1\u03b9\u03bd",props_desc:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",cell_desc:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03ba\u03b5\u03bb\u03b9\u03bf\u03cd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",row_desc:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",merge_cells_desc:"\u03a3\u03c5\u03b3\u03c7\u03ce\u03bd\u03b5\u03c5\u03c3\u03b7 \u03ba\u03b5\u03bb\u03b9\u03ce\u03bd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",split_cells_desc:"\u0394\u03b9\u03b1\u03c7\u03c9\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2 \u03c3\u03c5\u03b3\u03c7\u03c9\u03bd\u03b5\u03c5\u03bc\u03ad\u03bd\u03c9\u03bd \u03ba\u03b5\u03bb\u03b9\u03ce\u03bd \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",delete_col_desc:"\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03c3\u03c4\u03ae\u03bb\u03b7\u03c2",col_after_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c3\u03c4\u03ae\u03bb\u03b7\u03c2 \u03bc\u03b5\u03c4\u03ac",col_before_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c3\u03c4\u03ae\u03bb\u03b7\u03c2 \u03c0\u03c1\u03b9\u03bd",delete_row_desc:"\u0394\u03b9\u03b1\u03b3\u03c1\u03b1\u03c6\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2",row_after_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03bc\u03b5\u03c4\u03ac",row_before_desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b3\u03c1\u03b1\u03bc\u03bc\u03ae\u03c2 \u03c0\u03c1\u03b9\u03bd",desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03bd\u03ad\u03bf\u03c5 \u03c0\u03af\u03bd\u03b1\u03ba\u03b1",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u0395\u03ac\u03bd \u03b5\u03c0\u03b1\u03bd\u03b1\u03c6\u03ad\u03c1\u03b5\u03c4\u03b5 \u03c4\u03bf \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03bc\u03ad\u03bd\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf, \u03b8\u03b1 \u03c7\u03ac\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf \u03c0\u03bf\u03c5 \u03b2\u03c1\u03af\u03c3\u03ba\u03b5\u03c4\u03b1\u03b9 \u03b1\u03c5\u03c4\u03ae \u03c4\u03b7 \u03c3\u03c4\u03b9\u03b3\u03bc\u03ae \u03c3\u03c4\u03bf\u03bd editor.nn\u03a3\u03af\u03b3\u03bf\u03c5\u03c1\u03b1 \u03bd\u03b1 \u03b3\u03af\u03bd\u03b5\u03b9 \u03b5\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac \u03c4\u03bf\u03c5 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5;.",restore_content:"\u0395\u03c0\u03b1\u03bd\u03b1\u03c6\u03bf\u03c1\u03ac \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c0\u03bf\u03c5 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03b8\u03b7\u03ba\u03b5 \u03b1\u03c5\u03c4\u03cc\u03bc\u03b1\u03c4\u03b1.",unload_msg:"\u039f\u03b9 \u03b1\u03bb\u03bb\u03b1\u03b3\u03ad\u03c2 \u03c0\u03bf\u03c5 \u03ba\u03ac\u03bd\u03b1\u03c4\u03b5 \u03b8\u03b1 \u03c7\u03b1\u03b8\u03bf\u03cd\u03bd \u03b1\u03bd \u03c6\u03cd\u03b3\u03b5\u03c4\u03b5 \u03c3\u03b5 \u03ac\u03bb\u03bb\u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1."},fullscreen:{desc:"\u0395\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03c0\u03bb\u03ae\u03c1\u03bf\u03c5\u03c2 \u03bf\u03b8\u03cc\u03bd\u03b7\u03c2"},media:{delta_width:"50",edit:"\u0395\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b5\u03bd\u03c3\u03c9\u03bc\u03b1\u03c4\u03c9\u03bc\u03ad\u03bd\u03c9\u03bd media",desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae/\u03b5\u03c0\u03b5\u03be\u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1 \u03b5\u03bd\u03c3\u03c9\u03bc\u03b1\u03c4\u03c9\u03bc\u03ad\u03bd\u03c9\u03bd media",delta_height:""},fullpage:{desc:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c6\u03bf\u03c5",delta_width:"140",delta_height:""},template:{desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03bf\u03bc\u03ad\u03bd\u03bf\u03c5 \u03b3\u03b9\u03b1 \u03c0\u03c1\u03bf\u03ba\u03b1\u03b8\u03bf\u03c1\u03b9\u03c3\u03bc\u03ad\u03bd\u03bf \u03c0\u03c1\u03cc\u03c4\u03c5\u03c0\u03bf"},visualchars:{desc:"\u039f\u03c0\u03c4\u03b9\u03ba\u03bf\u03af \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03b5\u03c2 \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5 \u03bd\u03b1\u03b9/\u03cc\u03c7\u03b9."},spellchecker:{desc:"\u0395\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae \u03bf\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03bf\u03cd \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5",menu:"\u03a1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03bf\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03bf\u03cd \u03b5\u03bb\u03ad\u03b3\u03c7\u03bf\u03c5",ignore_word:"\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03bb\u03ad\u03be\u03b7\u03c2",ignore_words:"\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03cc\u03bb\u03c9\u03bd",langs:"\u0393\u03bb\u03ce\u03c3\u03c3\u03b5\u03c2",wait:"\u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03c0\u03b5\u03c1\u03b9\u03bc\u03ad\u03bd\u03b5\u03c4\u03b5...",sug:"\u03a0\u03c1\u03bf\u03c4\u03ac\u03c3\u03b5\u03b9\u03c2",no_sug:"\u03a7\u03c9\u03c1\u03af\u03c2 \u03c0\u03c1\u03bf\u03c4\u03ac\u03c3\u03b5\u03b9\u03c2",no_mpell:"\u0394\u03b5 \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b1\u03bd \u03bf\u03c1\u03b8\u03bf\u03b3\u03c1\u03b1\u03c6\u03b9\u03ba\u03ac \u03bb\u03ac\u03b8\u03b7."},pagebreak:{desc:"\u0395\u03b9\u03c3\u03b1\u03b3\u03c9\u03b3\u03ae \u03b1\u03bb\u03bb\u03b1\u03b3\u03ae\u03c2 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1\u03c2."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/fa.js0000644000175000017500000003752211526350525031504 0ustar frankiefrankietinyMCE.addI18n({fa:{common:{more_colors:"\u0631\u0646\u06af \u0647\u0627\u06cc \u0628\u06cc\u0634\u062a\u0631",invalid_data:"\u062e\u0637\u0627: \u0645\u0642\u0627\u062f\u06cc\u0631 \u0646\u0627\u0645\u0639\u062a\u0628\u0631 \u0648\u0627\u0631\u062f \u0634\u062f \u060c \u0622\u0646\u0647\u0627 \u0628\u0647 \u0631\u0646\u06af \u0642\u0631\u0645\u0632 \u0639\u0644\u0627\u0645\u062a \u062e\u0648\u0631\u062f\u0647 \u0627\u0646\u062f.",popup_blocked:"\u0628\u0627 \u0639\u0631\u0636 \u067e\u0648\u0632\u0634 \u060c \u0645\u0627 \u0627\u0637\u0644\u0627\u0639 \u062f\u0627\u062f\u0647 \u0628\u0648\u062f\u06cc\u0645 \u06a9\u0647 \u0645\u062f\u0627\u0641\u0639 \u067e\u0646\u062c\u0631\u0647 \u0628\u0627\u0632 \u0634\u0648\u06cc (Popup) \u0634\u0645\u0627 \u060c \u067e\u0646\u062c\u0631\u0647 \u0627\u06cc \u0631\u0627 \u06a9\u0647 \u0642\u0627\u0628\u0644\u06cc\u062a \u0628\u0631\u0646\u0627\u0645\u0647 \u06a9\u0627\u0631\u0628\u0631\u062f\u06cc \u0631\u0627 \u0627\u0631\u0627\u0626\u0647 \u0645\u06cc \u06a9\u0631\u062f \u060c \u063a\u06cc\u0631 \u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0647 \u0627\u0633\u062a. \u0634\u0645\u0627 \u0646\u06cc\u0627\u0632 \u0628\u0647 \u063a\u06cc\u0631 \u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0646 \u0645\u062f\u0627\u0641\u0639 \u067e\u0646\u062c\u0631\u0647 \u0628\u0627\u0632 \u0634\u0648 (Popup) \u062f\u0631 \u0627\u06cc\u0646 \u0633\u0627\u06cc\u062a \u0631\u0627 \u062f\u0627\u0631\u06cc\u062f \u062a\u0627 \u0627\u0632 \u0627\u06cc\u0646 \u0627\u0628\u0632\u0627\u0631 \u0628\u0647 \u0635\u0648\u0631\u062a \u06a9\u0627\u0645\u0644 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u0626\u06cc\u062f.",clipboard_no_support:"\u062f\u0631 \u062d\u0627\u0644 \u062d\u0627\u0636\u0631 \u062a\u0648\u0633\u0637 \u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc \u0646\u0645\u06cc \u0634\u0648\u062f \u060c \u0628\u0647 \u062c\u0627\u06cc \u0622\u0646 \u0627\u0632 \u0645\u06cc\u0627\u0646\u0628\u0631\u0647\u0627\u06cc (Shortcut) \u0635\u0641\u062d\u0647 \u06a9\u0644\u06cc\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u0626\u06cc\u062f.",clipboard_msg:"\u0628\u0631\u0634/\u06a9\u067e\u06cc/\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0628\u0631\u0627\u06cc \u0645\u0631\u0648\u0631\u06af\u0631 \u0641\u0627\u06cc\u0631\u0641\u0627\u06a9\u0633 \u0641\u0639\u0627\u0644 \u0646\u0645\u06cc \u0628\u0627\u0634\u062f. \\n\u0622\u06cc\u0627 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0628\u06cc\u0634\u062a\u0631\u06cc \u0631\u0627\u062c\u0639 \u0628\u0647 \u0627\u06cc\u0646 \u0645\u0648\u0636\u0648\u0639 \u0645\u06cc \u062e\u0648\u0627\u0647\u06cc\u062f\u061f",not_set:"-- \u062a\u0646\u0638\u06cc\u0645 \u0646\u0634\u062f\u0647 --",class_name:"\u06a9\u0644\u0627\u0633",browse:"\u0627\u0646\u062a\u062e\u0627\u0628 \u0627\u0632 \u0633\u0631\u0648\u0631",close:"\u0628\u0633\u062a\u0646",cancel:"\u0627\u0646\u0635\u0631\u0627\u0641",update:"\u0628\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc",insert:"\u062f\u0631\u062c",apply:"\u0628\u06a9\u0627\u0631\u06af\u06cc\u0631\u06cc",edit_confirm:"\u0622\u06cc\u0627 \u0634\u0645\u0627 \u0645\u0627\u06cc\u0644\u06cc\u062f \u062a\u0627 \u0627\u0632 \u062d\u0627\u0644\u062a \u0648\u06cc\u0631\u0627\u06cc\u0634\u06af\u0631 \u0648\u06cc\u0632\u06cc\u200c\u0648\u06cc\u06af(\u0646\u0645\u0627\u06cc\u0634 \u0627\u0637\u0644\u0627\u0639\u0627\u062a \u062f\u0631 \u062d\u0627\u0644\u062a \u0686\u0627\u067e \u0634\u062f\u0646\u06cc) \u0628\u0631\u0627\u06cc \u0627\u06cc\u0646 \u0646\u0627\u062d\u06cc\u0647 \u0645\u062a\u0646\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u0626\u06cc\u062f\u061f"},contextmenu:{full:"\u06a9\u0627\u0645\u0644",right:"\u0631\u0627\u0633\u062a",center:"\u0648\u0633\u0637",left:"\u0686\u067e",align:"\u062a\u0631\u0627\u0632"},insertdatetime:{day_short:"\u06cc\u06a9\u0634\u0646\u0628\u0647,\u062f\u0648\u0634\u0646\u0628\u0647,\u0633\u0647 \u0634\u0646\u0628\u0647,\u0686\u0647\u0627\u0631\u0634\u0646\u0628\u0647,\u067e\u0646\u062c \u0634\u0646\u0628\u0647,\u062c\u0645\u0639\u0647,\u0634\u0646\u0628\u0647,\u06cc\u06a9\u0634\u0646\u0628\u0647",day_long:"\u06cc\u06a9\u0634\u0646\u0628\u0647,\u062f\u0648\u0634\u0646\u0628\u0647,\u0633\u0647 \u0634\u0646\u0628\u0647,\u0686\u0647\u0627\u0631\u0634\u0646\u0628\u0647,\u067e\u0646\u062c \u0634\u0646\u0628\u0647,\u062c\u0645\u0639\u0647,\u0634\u0646\u0628\u0647,\u06cc\u06a9\u0634\u0646\u0628\u0647",months_short:"\u0698\u0627\u0646\u0648\u06cc\u0647,\u0641\u0648\u0631\u06cc\u0647,\u0645\u0627\u0631\u0633,\u0622\u0648\u0631\u06cc\u0644,\u0645\u0647,\u0698\u0648\u0626\u0646,\u0698\u0648\u0626\u06cc\u0647,\u0627\u0648\u062a,\u0633\u067e\u062a\u0627\u0645\u0628\u0631,\u0627\u06a9\u062a\u0628\u0631,\u0646\u0648\u0627\u0645\u0628\u0631,\u062f\u0633\u0627\u0645\u0628\u0631",months_long:"\u0698\u0627\u0646\u0648\u06cc\u0647,\u0641\u0648\u0631\u06cc\u0647,\u0645\u0627\u0631\u0633,\u0622\u0648\u0631\u06cc\u0644,\u0645\u0647,\u0698\u0648\u0626\u0646,\u0698\u0648\u0626\u06cc\u0647,\u0627\u0648\u062a,\u0633\u067e\u062a\u0627\u0645\u0628\u0631,\u0627\u06a9\u062a\u0628\u0631,\u0646\u0648\u0627\u0645\u0628\u0631,\u062f\u0633\u0627\u0645\u0628\u0631",inserttime_desc:"\u062f\u0631\u062c \u0632\u0645\u0627\u0646",insertdate_desc:"\u062f\u0631\u062c \u062a\u0627\u0631\u06cc\u062e",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u0686\u0627\u067e"},preview:{preview_desc:"\u067e\u06cc\u0634 \u0646\u0645\u0627\u06cc\u0634"},directionality:{rtl_desc:"\u062c\u0647\u062a \u0631\u0627\u0633\u062a \u0628\u0647 \u0686\u067e",ltr_desc:"\u062c\u0647\u062a \u0686\u067e \u0628\u0647 \u0631\u0627\u0633\u062a"},layer:{content:"\u0644\u0627\u06cc\u0647 \u062c\u062f\u06cc\u062f...",absolute_desc:"\u062a\u0639\u0648\u06cc\u0636 \u0645\u0648\u0642\u0639\u06cc\u062a \u0645\u0637\u0644\u0642",backward_desc:"\u0627\u0646\u062a\u0642\u0627\u0644 \u0628\u0647 \u067e\u0634\u062a",forward_desc:"\u0627\u0646\u062a\u0642\u0627\u0644 \u0628\u0647 \u062c\u0644\u0648",insertlayer_desc:"\u062f\u0631\u062c \u0644\u0627\u06cc\u0647 \u062c\u062f\u06cc\u062f"},save:{save_desc:"\u0630\u062e\u06cc\u0631\u0647",cancel_desc:"\u0644\u063a\u0648 \u062a\u0645\u0627\u0645\u06cc \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a"},nonbreaking:{nonbreaking_desc:"\u062f\u0631\u062c \u06a9\u0627\u0631\u0627\u06a9\u062a\u0631 \u0641\u0627\u0635\u0644\u0647 \u0628\u062f\u0648\u0646 \u0642\u0637\u0639 \u0634\u062f\u06af\u06cc"},iespell:{download:"ieSpell \u062a\u0634\u062e\u06cc\u0635 \u062f\u0627\u062f\u0647 \u0646\u0634\u062f. \u0622\u06cc\u0627 \u0634\u0645\u0627 \u0645\u0627\u06cc\u0644 \u0628\u0647 \u0646\u0635\u0628 \u0622\u0646 \u0647\u0633\u062a\u06cc\u062f\u061f",iespell_desc:"\u0627\u062c\u0631\u0627\u06cc \u0628\u0631\u0631\u0633\u06cc \u0627\u0645\u0644\u0627\u0621"},advhr:{advhr_desc:"\u062e\u0637 \u0627\u0641\u0642\u06cc",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0634\u06a9\u0644\u06a9",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u062c\u0633\u062a\u062c\u0648/\u062a\u0639\u0648\u06cc\u0636",search_desc:"\u062c\u0633\u062a\u062c\u0648",delta_width:"",delta_height:""},advimage:{image_desc:"\u062f\u0631\u062c/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u062a\u0635\u0648\u06cc\u0631",delta_width:"",delta_height:""},advlink:{link_desc:"\u062f\u0631\u062c/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0644\u06cc\u0646\u06a9",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u062f\u0631\u062c/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0635\u0641\u0627\u062a",ins_desc:"\u062f\u0631\u062c",del_desc:"\u062d\u0630\u0641",acronym_desc:"\u0645\u062e\u0641\u0641",abbr_desc:"\u0627\u062e\u062a\u0635\u0627\u0631",cite_desc:"\u0646\u0642\u0644 \u0642\u0648\u0644",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0627\u0633\u062a\u06cc\u0644 CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0645\u062a\u0646 \u062f\u0631 \u062d\u0627\u0644\u062a \u0633\u0627\u062f\u0647 \u0627\u0633\u062a. \u0628\u0631\u0627\u06cc \u0628\u0631\u06af\u0634\u062a \u0628\u0647 \u062d\u0627\u0644\u062a \u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0628\u0627\u0642\u0627\u0639\u062f\u0647 \u062f\u0648\u0628\u0627\u0631\u0647 \u06a9\u0644\u06cc\u06a9 \u06a9\u0646\u06cc\u062f.",plaintext_mode_sticky:"\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0645\u062a\u0646 \u062f\u0631 \u062d\u0627\u0644\u062a \u0633\u0627\u062f\u0647 \u0627\u0633\u062a. \u0628\u0631\u0627\u06cc \u0628\u0631\u06af\u0634\u062a \u0628\u0647 \u062d\u0627\u0644\u062a \u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0628\u0627\u0642\u0627\u0639\u062f\u0647 \u062f\u0648\u0628\u0627\u0631\u0647 \u06a9\u0644\u06cc\u06a9 \u06a9\u0646\u06cc\u062f. \u0628\u0639\u062f \u0627\u0632 \u0627\u06cc\u0646\u06a9\u0647 \u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0631\u0627 \u0627\u0646\u062c\u0627\u0645 \u062f\u0627\u062f\u06cc\u062f \u0628\u0647 \u062d\u0627\u0644\u062a \u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0628\u0627\u0642\u0627\u0639\u062f\u0647 \u0628\u0627\u0632 \u0645\u06cc \u06af\u0631\u062f\u06cc\u062f.",selectall_desc:"\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u0645\u0647",paste_word_desc:"\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0627\u0632 \u0648\u064f\u0631\u062f",paste_text_desc:"\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 \u0645\u062a\u0646 \u0633\u0627\u062f\u0647"},paste_dlg:{word_title:"\u062c\u0647\u062a \u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0645\u062a\u0646 \u062f\u0631 \u067e\u0646\u062c\u0631\u0647 \u0627\u0632 CTRL+V \u0628\u0631 \u0631\u0648\u06cc \u0635\u0641\u062d\u0647 \u06a9\u0644\u06cc\u062f \u062e\u0648\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u0626\u06cc\u062f.",text_linebreaks:"\u062d\u0641\u0638 \u0642\u0637\u0639 \u062e\u0637\u0648\u0637",text_title:"\u062c\u0647\u062a \u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0645\u062a\u0646 \u062f\u0631 \u067e\u0646\u062c\u0631\u0647 \u0627\u0632 CTRL+V \u0628\u0631 \u0631\u0648\u06cc \u0635\u0641\u062d\u0647 \u06a9\u0644\u06cc\u062f \u062e\u0648\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u0626\u06cc\u062f."},table:{cell:"\u0633\u0644\u0648\u0644",col:"\u0633\u062a\u0648\u0646",row:"\u0633\u0637\u0631",del:"\u062d\u0630\u0641 \u062c\u062f\u0648\u0644",copy_row_desc:"\u06a9\u067e\u06cc \u0633\u0637\u0631 \u062c\u062f\u0648\u0644",cut_row_desc:"\u0628\u0631\u0634 (Cut) \u0633\u0637\u0631 \u062c\u062f\u0648\u0644",paste_row_after_desc:"\u0686\u0633\u0628\u0627\u0646\u062f\u0646 (Paste) \u0633\u0637\u0631 \u062c\u062f\u0648\u0644 \u062f\u0631 \u0628\u0639\u062f",paste_row_before_desc:"\u0686\u0633\u0628\u0627\u0646\u062f\u0646 (Paste) \u0633\u0637\u0631 \u062c\u062f\u0648\u0644 \u062f\u0631 \u0642\u0628\u0644",props_desc:"\u0645\u0634\u062e\u0635\u0627\u062a \u062c\u062f\u0648\u0644",cell_desc:"\u0645\u0634\u062e\u0635\u0627\u062a \u0633\u0644\u0648\u0644 \u062c\u062f\u0648\u0644",row_desc:"\u0645\u0634\u062e\u0635\u0627\u062a \u0633\u0637\u0631 \u062c\u062f\u0648\u0644",merge_cells_desc:"\u0627\u062f\u063a\u0627\u0645 \u0633\u0644\u0648\u0644 \u0647\u0627\u06cc \u062c\u062f\u0648\u0644",split_cells_desc:"\u062a\u0642\u0633\u06cc\u0645 \u0633\u0644\u0648\u0644 \u0647\u0627\u06cc \u062c\u062f\u0648\u0644 \u0627\u062f\u063a\u0627\u0645 \u0634\u062f\u0647",delete_col_desc:"\u062d\u0630\u0641 \u0633\u062a\u0648\u0646",col_after_desc:"\u062f\u0631\u062c \u0633\u062a\u0648\u0646 \u062f\u0631 \u0628\u0639\u062f",col_before_desc:"\u062f\u0631\u062c \u0633\u062a\u0648\u0646 \u062f\u0631 \u0642\u0628\u0644",delete_row_desc:"\u062d\u0630\u0641 \u0633\u0637\u0631",row_after_desc:"\u062f\u0631\u062c \u0633\u0637\u0631 \u062f\u0631 \u0628\u0639\u062f",row_before_desc:"\u062f\u0631\u062c \u0633\u0637\u0631 \u062f\u0631 \u0642\u0628\u0644",desc:"\u06cc\u06a9 \u062c\u062f\u0648\u0644 \u062c\u062f\u06cc\u062f \u062f\u0631\u062c \u0645\u06cc \u06a9\u0646\u062f",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u0627\u06af\u0631 \u0645\u062d\u062a\u0648\u0627\u06cc \u0630\u062e\u06cc\u0631\u0647 \u0634\u062f\u0647 \u0631\u0627 \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u06a9\u0646\u06cc\u062f\u060c \u0645\u062d\u062a\u0648\u0627\u06cc \u0645\u0648\u062c\u0648\u062f \u062f\u0631 \u0648\u06cc\u0631\u0627\u06cc\u0634\u06af\u0631 \u0627\u0632 \u0628\u06cc\u0646 \u0645\u06cc\u200c\u0631\u0648\u062f.\u0628\u0631\u0627\u06cc \u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0645\u062d\u062a\u0648\u0627\u06cc \u0630\u062e\u06cc\u0631\u0647 \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062f\u0627\u0631\u06cc\u062f\u061f.",restore_content:"\u0628\u0627\u0632\u06af\u0631\u062f\u0627\u0646\u06cc \u0645\u062d\u062a\u0648\u0627 \u0627\u0632 \u0630\u062e\u06cc\u0631\u0647\u200c\u06cc \u062e\u0648\u062f\u06a9\u0627\u0631",unload_msg:"\u0627\u06af\u0631 \u0627\u0632 \u0627\u06cc\u0646 \u0635\u0641\u062d\u0647 \u0628\u0647 \u062c\u0627\u06cc \u062f\u06cc\u06af\u0631\u06cc \u0628\u0631\u0648\u06cc\u062f \u060c \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u062f\u0631 \u0645\u062d\u062a\u0648\u0627 \u0627\u0632 \u062f\u0633\u062a \u062e\u0648\u0627\u0647\u062f \u0631\u0641\u062a."},fullscreen:{desc:"\u062a\u0639\u0648\u06cc\u0636 \u0628\u0647 \u062d\u0627\u0644\u062a \u0635\u0641\u062d\u0647 \u06a9\u0627\u0645\u0644"},media:{edit:"\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0633\u0627\u0646\u0647 \u062c\u0627\u0633\u0627\u0632\u06cc \u0634\u062f\u0647 (Embeded Media)",desc:"\u062f\u0631\u062c / \u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0633\u0627\u0646\u0647 \u062c\u0627\u0633\u0627\u0632\u06cc \u0634\u062f\u0647 (Embeded Media)",delta_height:"",delta_width:""},fullpage:{desc:"\u0645\u0634\u062e\u0635\u0627\u062a \u0633\u0646\u062f",delta_width:"",delta_height:""},template:{desc:"\u062f\u0631\u062c \u0645\u062d\u062a\u0648\u0627\u06cc \u0642\u0627\u0644\u0628 \u0627\u0632 \u067e\u06cc\u0634 \u062a\u0639\u0631\u06cc\u0641 \u0634\u062f\u0647"},visualchars:{desc:"\u0631\u0648\u0634\u0646/\u062e\u0627\u0645\u0648\u0634 \u06a9\u0631\u062f\u0646 \u06a9\u0627\u0631\u0627\u06a9\u062a\u0631 \u0647\u0627\u06cc \u06a9\u0646\u062a\u0631\u0644 \u0628\u0635\u0631\u06cc (Visual)."},spellchecker:{desc:"\u062a\u0639\u0648\u06cc\u0636 \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u0646\u062f\u0647 \u0627\u0645\u0644\u0627\u0621",menu:"\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0628\u0631\u0631\u0633\u06cc \u06a9\u0646\u0646\u062f\u0647 \u0627\u0645\u0644\u0627\u0621",ignore_word:"\u0686\u0634\u0645 \u067e\u0648\u0634\u06cc \u0627\u0632 \u06a9\u0644\u0645\u0647",ignore_words:"\u0686\u0634\u0645 \u067e\u0648\u0634\u06cc \u0627\u0632 \u0647\u0645\u0647",langs:"\u0632\u0628\u0627\u0646 \u0647\u0627",wait:"\u0644\u0637\u0641\u0627 \u0645\u0646\u062a\u0638\u0631 \u0628\u0645\u0627\u0646\u06cc\u062f...",sug:"\u067e\u06cc\u0634\u0646\u0647\u0627\u062f\u0627\u062a",no_sug:"\u0628\u062f\u0648\u0646 \u067e\u06cc\u0634\u0646\u0647\u0627\u062f",no_mpell:"\u0647\u06cc\u0686 \u062e\u0637\u0627\u06cc \u0627\u0645\u0644\u0627\u0626\u06cc \u06cc\u0627\u0641\u062a\u0647 \u0646\u0634\u062f."},pagebreak:{desc:"\u062f\u0631\u062c \u0642\u0637\u0639 \u0635\u0641\u062d\u0647."},advlist:{types:"\u0627\u0646\u0648\u0627\u0639",def:"\u067e\u06cc\u0634\u200c\u0641\u0631\u0636",lower_alpha:"\u067e\u0627\u06cc\u06cc\u0646\u200c\u062a\u0631 (alpha)",lower_greek:"\u067e\u0627\u06cc\u06cc\u0646\u200c\u062a\u0631 (greek)",lower_roman:"\u067e\u0627\u06cc\u06cc\u0646\u200c\u062a\u0631 (roman)",upper_alpha:"\u0628\u0627\u0644\u0627\u062a\u0631 (alpha)",upper_roman:"\u0628\u0627\u0644\u0627\u062a\u0631 (roman)",circle:"\u062f\u0627\u06cc\u0631\u0647",disc:"\u0642\u0631\u0635 \u0645\u0627\u0646\u0646\u062f",square:"\u0645\u0631\u0628\u0639"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/en.js0000644000175000017500000001210211526350525031503 0ustar frankiefrankietinyMCE.addI18n({en:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{delta_height:"",delta_width:"",advhr_desc:"Horizontal rule"},emotions:{delta_height:"",delta_width:"",emotions_desc:"Emotions"},searchreplace:{replace_desc:"Find/Replace",delta_width:"",delta_height:"",search_desc:"Find"},advimage:{delta_width:"",image_desc:"Insert/edit image",delta_height:""},advlink:{delta_height:"",delta_width:"",link_desc:"Insert/edit link"},xhtmlxtras:{attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:"",attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation"},style:{delta_height:"",delta_width:"",desc:"Edit CSS Style"},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text"},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:"",cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table"},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"Toggle fullscreen mode"},media:{delta_height:"",delta_width:"",edit:"Edit embedded media",desc:"Insert / edit embedded media"},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/es.js0000644000175000017500000001276411526350525031526 0ustar frankiefrankietinyMCE.addI18n({es:{common:{more_colors:"M\u00e1s colores",invalid_data:"Error: Introdujo un valor no v\u00e1lido, est\u00e1n marcados en rojo.",popup_blocked:"Lo sentimos, su bloqueo de ventanas emergentes ha deshabilitado una ventana que provee funcionalidades a la aplicaci\u00f3n. Necesita deshabilitar este bloqueo en este sitio para poder utilizar todas las funciones.",clipboard_no_support:"Su navegador no soporta las funciones de cortapapeles, use los accesos por teclado.",clipboard_msg:"Copiar/Cortar/Pegar no se encuentra disponible en Mozilla y Firefox.\\n \u00bfDesea obtener m\u00e1s informaci\u00f3n acerca de este tema?",not_set:"-- Ninguno --",class_name:"Clase",browse:"Examinar",close:"Cerrar",cancel:"Cancelar",update:"Actualizar",insert:"Insertar",apply:"Aplicar",edit_confirm:" \u00bfDesea utilizar el modo WYSIWYG para esta caja de texto?"},contextmenu:{full:"Justificado",right:"Derecha",center:"Centrado",left:"Izquierda",align:"Alineaci\u00f3n"},insertdatetime:{day_short:"Dom,Lun,Mar,Mie,Jue,Vie,Sab,Dom",day_long:"Domingo,Lunes,Martes,Mi\u00e9rcoles,Jueves,Viernes,S\u00e1bado,Domingo",months_short:"Ene,Feb,Mar,Abr,May,Jun,Jul,Ago,Sep,Oct,Nov,Dic",months_long:"Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,Octubre,Noviembre,Diciembre",inserttime_desc:"Insertar hora",insertdate_desc:"Insertar fecha",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Imprimir"},preview:{preview_desc:"Vista previa"},directionality:{rtl_desc:"Direcci\u00f3n derecha a izquierda",ltr_desc:"Direcci\u00f3n izquierda a derecha"},layer:{content:"Nueva capa...",absolute_desc:"Cambiar a posici\u00f3n absoluta",backward_desc:"Retroceder",forward_desc:"Avanzar",insertlayer_desc:"Insertar nueva capa"},save:{save_desc:"Guardar",cancel_desc:"Cancelar todos los cambios"},nonbreaking:{nonbreaking_desc:"Insertar caracter de espacio \'non-breaking\'"},iespell:{download:"No se detect\u00f3 \'ieSpell\'. \u00bfDesea instalarlo ahora?",iespell_desc:"Corrector ortogr\u00e1fico"},advhr:{advhr_desc:"Regla horizontal",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emoticones",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Buscar/Reemplazar",search_desc:"Buscar",delta_width:"",delta_height:""},advimage:{image_desc:"Insertar/editar imagen",delta_width:"",delta_height:""},advlink:{link_desc:"Insertar/editar hiperv\u00ednculo",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insertar/Editar atributos",ins_desc:"Inserci\u00f3n",del_desc:"Borrado",acronym_desc:"Acr\u00f3nimo",abbr_desc:"Abreviatura",cite_desc:"Cita",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Editar Estilo CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Elegir todo",paste_word_desc:"Pegar desde Word",paste_text_desc:"Pegar como texto plano"},paste_dlg:{word_title:"Use CTRL+V en su teclado para pegar el texto en la ventana.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V en su teclado para pegar el texto en la ventana."},table:{cell:"Celda",col:"Columna",row:"Fila",del:"Eliminar tabla",copy_row_desc:"Copiar fila",cut_row_desc:"Cortar fila",paste_row_after_desc:"Pegar filas (despu\u00e9s)",paste_row_before_desc:"Pegar filas (antes)",props_desc:"Propiedades de la tabla",cell_desc:"Propiedades de la celda",row_desc:"Propiedades de la fila",merge_cells_desc:"Vincular celdas",split_cells_desc:"Dividir celdas",delete_col_desc:"Suprimir columna",col_after_desc:"Insertar columna (despu\u00e9s)",col_before_desc:"Insertar columna (antes)",delete_row_desc:"Suprimir fila",row_after_desc:"Insertar fila (despu\u00e9s)",row_before_desc:"Insertar fila (antes)",desc:"Inserta una nueva tabla",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Se reestablece en contenido guardado, perder\u00e1 todo el contenido que est\u00e1 actualmente en el editor.\\n\\nEst\u00e1 seguro de que quiere reestablecer el contenido guardado.",restore_content:"Reestablecer contenido guardado autom\u00e1ticamente",unload_msg:"Los cambios realizados se perder\u00e1n si sale de esta p\u00e1gina."},fullscreen:{desc:"Cambiar a modo Pantalla Completa"},media:{edit:"Editar medio embebido",desc:"Insertar/editar medio embebido",delta_height:"",delta_width:""},fullpage:{desc:"Propiedades del documento",delta_width:"Ancho",delta_height:"Alto"},template:{desc:"Insertar contenido de plantilla predefinida"},visualchars:{desc:"Caracteres de control ON/OFF."},spellchecker:{desc:"Cambiar a corrector ortogr\u00e1fico",menu:"Configuraci\u00f3n de corrector ortogr\u00e1fico",ignore_word:"Ignorar",ignore_words:"Ignorar todo",langs:"Idiomas",wait:"Espere...",sug:"Sugerencias",no_sug:"Sin sugerencias",no_mpell:"No se encontraron errores."},pagebreak:{desc:"Insertar fin de p\u00e1gina"},advlist:{types:"Tipo",def:"Preestablecido",lower_alpha:"Menos opaco",lower_greek:"Menos greek",lower_roman:"Menos roman",upper_alpha:"M\u00e1s opaco",upper_roman:"M\u00e1s roman",circle:"Circulo",disc:"Disc",square:"Cuadro"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/fi.js0000644000175000017500000001412111526350525031502 0ustar frankiefrankietinyMCE.addI18n({fi:{common:{more_colors:"Enemm\u00e4n v\u00e4rej\u00e4",invalid_data:"Virhe: Sy\u00f6tit virheellisi\u00e4 arvoja, ne n\u00e4kyv\u00e4t punaisina.",popup_blocked:"Sinulla on k\u00e4yt\u00f6ss\u00e4si ohjelma, joka est\u00e4\u00e4 ponnahdusikkunoiden n\u00e4yt\u00f6n. Sinun t\u00e4ytyy kytke\u00e4 ponnahdusikkunoiden esto pois p\u00e4\u00e4lt\u00e4 voidaksesi hy\u00f6dynt\u00e4\u00e4 t\u00e4ysin t\u00e4t\u00e4 ty\u00f6kalua.",clipboard_no_support:"Selaimesi ei ole tuettu, k\u00e4yt\u00e4 sen sijaan n\u00e4pp\u00e4inoikoteit\u00e4.",clipboard_msg:"Kopioi/Leikkaa/Liit\u00e4 ei ole k\u00e4ytett\u00e4viss\u00e4 Mozilla ja Firefox -selaimilla.\\nHaluatko lis\u00e4tietoa t\u00e4st\u00e4 ongelmasta?",not_set:"-- Ei m\u00e4\u00e4ritetty --",class_name:"Luokka",browse:"Selaa",close:"Sulje",cancel:"Peru",update:"P\u00e4ivit\u00e4",insert:"Lis\u00e4\u00e4",apply:"K\u00e4yt\u00e4",edit_confirm:"Haluatko k\u00e4ytt\u00e4\u00e4 WYSIWYG-tilaa t\u00e4ss\u00e4 tekstikent\u00e4ss\u00e4?"},contextmenu:{full:"Molemmille puolille",right:"Oikealle",center:"Keskelle",left:"Vasemmalle",align:"Tasaus"},insertdatetime:{day_short:"su,ma,ti,ke,to,pe,la,su",day_long:"sunnuntai,maanantai,tiistai,keskiviikko,torstai,perjantai,lauantai,sunnuntai",months_short:"tammi,helmi,maalis,huhti,touko,kes\u00e4,hein\u00e4,elo,syys,loka,marras,joulu",months_long:"tammikuu,helmikuu,maaliskuu,huhtikuu,toukokuu,kes\u00e4kuu,hein\u00e4kuu,elokuu,syyskuu,lokakuu,marraskuu,joulukuu",inserttime_desc:"Lis\u00e4\u00e4 kellonaika",insertdate_desc:"Lis\u00e4\u00e4 p\u00e4iv\u00e4m\u00e4\u00e4r\u00e4",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"Tulosta"},preview:{preview_desc:"Esikatselu"},directionality:{rtl_desc:"Suunta oikealta vasemmalle",ltr_desc:"Suunta vasemmalta oikealle"},layer:{content:"Uusi taso...",absolute_desc:"Absoluuttinen sijainti",backward_desc:"Siirr\u00e4 taaksep\u00e4in",forward_desc:"Siirr\u00e4 eteenp\u00e4in",insertlayer_desc:"Lis\u00e4\u00e4 uusi taso"},save:{save_desc:"Tallenna",cancel_desc:"Peru kaikki muutokset"},nonbreaking:{nonbreaking_desc:"Lis\u00e4\u00e4 tyhj\u00e4 merkki (nbsp)"},iespell:{download:"ieSpell-ohjelmaa ei havaittu. Haluatko asentaa sen nyt?",iespell_desc:"Oikeinkirjoituksen tarkistus"},advhr:{advhr_desc:"Vaakatasoviivain",delta_height:"",delta_width:""},emotions:{emotions_desc:"Hymi\u00f6t",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Etsi ja korvaa",search_desc:"Etsi",delta_width:"",delta_height:""},advimage:{image_desc:"Lis\u00e4\u00e4/muokkaa kuvaa",delta_width:"",delta_height:""},advlink:{link_desc:"Lis\u00e4\u00e4/muokkaa linkki\u00e4",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Lis\u00e4\u00e4/muokkaa attribuutteja",ins_desc:"Lis\u00e4ys",del_desc:"Poisto",acronym_desc:"Kirjainlyhenne",abbr_desc:"Lyhenne",cite_desc:"Sitaatti",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Muokkaa CSS-tyylej\u00e4",delta_height:"",delta_width:""},paste:{plaintext_mode:"Liitt\u00e4minen on nyt pelkk\u00e4n\u00e4 tekstin\u00e4. Klikkaa uudelleen vaihtaaksesi takaisin tavalliseen tilaan.",plaintext_mode_sticky:"Liitt\u00e4minen on nyt pelkk\u00e4n\u00e4 tekstin\u00e4. Klikkaa uudelleen vaihtaaksesi takaisin tavalliseen tilaan. Palaat takaisin tavalliseen tilaan liitetty\u00e4si jotakin.",selectall_desc:"Valitse kaikki",paste_word_desc:"Liit\u00e4 Wordist\u00e4",paste_text_desc:"Liit\u00e4 pelkk\u00e4n\u00e4 tekstin\u00e4"},paste_dlg:{word_title:"Paina Ctrl+V liitt\u00e4\u00e4ksesi sis\u00e4ll\u00f6n ikkunaan.",text_linebreaks:"S\u00e4ilyt\u00e4 rivinvaihdot",text_title:"Paina Ctrl+V liitt\u00e4\u00e4ksesi sis\u00e4ll\u00f6n ikkunaan."},table:{cellprops_delta_width:"80",cell:"Solu",col:"Sarake",row:"Rivi",del:"Poista taulukko",copy_row_desc:"Kopioi taulukon rivi",cut_row_desc:"Leikkaa taulukon rivi",paste_row_after_desc:"Liit\u00e4 taulukon rivi j\u00e4lkeen",paste_row_before_desc:"Liit\u00e4 taulukon rivi ennen",props_desc:"Taulukon asetukset",cell_desc:"Taulukon solun asetukset",row_desc:"Taulukon rivin asetukset",merge_cells_desc:"Yhdist\u00e4 taulukon solut",split_cells_desc:"Jaa yhdistetyt taulukon solut",delete_col_desc:"Poista sarake",col_after_desc:"Lis\u00e4\u00e4 sarake j\u00e4lkeen",col_before_desc:"Lis\u00e4\u00e4 sarake ennen",delete_row_desc:"Poista rivi",row_after_desc:"Lis\u00e4\u00e4 rivi j\u00e4lkeen",row_before_desc:"Lis\u00e4\u00e4 rivi ennen",desc:"Lis\u00e4\u00e4 uusi taulukko",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Jos palautat automaattisesti tallennetun sis\u00e4ll\u00f6n, menet\u00e4t t\u00e4ll\u00e4 hetkell\u00e4 editorissa olevan sis\u00e4ll\u00f6n.\\n\\nHaluatko varmasti palauttaa tallennetun sis\u00e4ll\u00f6n?",restore_content:"Palauta automaattisesti tallennettu sis\u00e4lt\u00f6.",unload_msg:"Tekem\u00e4si muutokset menetet\u00e4\u00e4n jos poistut t\u00e4lt\u00e4 sivulta."},fullscreen:{desc:"Kokoruututila"},media:{edit:"Muokkaa upotettua mediaa",desc:"Lis\u00e4\u00e4/muokkaa upotettua mediaa",delta_height:"",delta_width:""},fullpage:{desc:"Tiedoston asetukset",delta_width:"",delta_height:""},template:{desc:"Lis\u00e4\u00e4 esim\u00e4\u00e4ritetty\u00e4 sivupohjasis\u00e4lt\u00f6\u00e4"},visualchars:{desc:"N\u00e4yt\u00e4/piilota muotoilumerkit."},spellchecker:{desc:"Oikeinkirjoituksen tarkistus",menu:"Oikeinkirjoituksen asetukset",ignore_word:"Ohita sana",ignore_words:"Ohita kaikki",langs:"Kielet",wait:"Odota ole hyv\u00e4...",sug:"Ehdotukset",no_sug:"Ei ehdotuksia",no_mpell:"Virheit\u00e4 ei l\u00f6ytynyt."},pagebreak:{desc:"Lis\u00e4\u00e4 sivunvaihto."},advlist:{types:"Tyypit",def:"Oletus",lower_alpha:"pienet kirjaimet: a, b, c",lower_greek:"pienet kirjaimet: \u03b1, \u03b2, \u03b3",lower_roman:"pienet kirjaimet: i, ii, iii",upper_alpha:"isot kirjaimet: A, B, C",upper_roman:"isot kirjaimet: I, II, III",circle:"Pallo",disc:"Ympyr\u00e4",square:"Neli\u00f6"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/et.js0000644000175000017500000001276411526350525031527 0ustar frankiefrankietinyMCE.addI18n({et:{common:{more_colors:"Rohkem v\u00e4rve",invalid_data:"Viga: Kehtetud v\u00e4\u00e4rtused sisestatud, need on m\u00e4rgitud punasega.",popup_blocked:"Vabandust, aga Teie h\u00fcpikakna t\u00f5kestaja on blokeerinud akna, mis varustab rakenduse funktsionaalsust. Palun lubage h\u00fcpikaknad sellel kodulehel, et t\u00e4ielikult kasutada seda vahendit.",clipboard_no_support:"Hetkel ei ole toetatud Teie lehitseja poolt, kasutage klaviatuuri otseteid selle asemel.",clipboard_msg:"Kopeeri/L\u00f5ika/Kleebi ei ole saadaval Mozillas ja Firefoxis.\\nKas soovite rohkem infot selle probleemi kohta?",not_set:"-- Seadmata --",class_name:"Klass",browse:"Sirvi",close:"Sule",cancel:"T\u00fchista",update:"Uuenda",insert:"Sisesta",apply:"Rakenda",edit_confirm:"Kas soovite kasutada WYSIWYG re\u017eiimi sellel tekstialal?"},contextmenu:{full:"T\u00e4is",right:"Parem",center:"Kesk",left:"Vasak",align:"Joondus"},insertdatetime:{day_short:"P,E,T,K,N,R,L,P",day_long:"P\u00fchap\u00e4ev,Esmasp\u00e4ev,Teisip\u00e4ev,Kolmap\u00e4ev,Neljap\u00e4ev,Reede,Laup\u00e4ev,P\u00fchap\u00e4ev",months_short:"Jaan,Veeb,M\u00e4rts,Apr,Mai,Juuni,Juuli,Aug,Sept,Okt,Nov,Dets",months_long:"Jaanuar,Veebruar,M\u00e4rts,Aprill,Mai,Juuni,Juuli,August,September,Oktoober,November,Detsember",inserttime_desc:"Sisesta aeg",insertdate_desc:"Sisesta kuup\u00e4ev",time_fmt:"%T:%M:%S",date_fmt:"%A-%k-%p"},print:{print_desc:"Print"},preview:{preview_desc:"Eelvaade"},directionality:{rtl_desc:"Suund paremalt vasakule",ltr_desc:"Suund vasakult paremale"},layer:{content:"Uus kiht...",absolute_desc:"L\u00fclita \u00fcmber absoluutne positsioneerimine",backward_desc:"Liiguta tagasi",forward_desc:"Liiguta edasi",insertlayer_desc:"Sisesta uus kiht"},save:{save_desc:"Salvesta",cancel_desc:"T\u00fchista k\u00f5ik muudatused"},nonbreaking:{nonbreaking_desc:"Sisesta mittekatkestav t\u00fchik"},iespell:{download:"ie\u00d5igekiri tuvastamata. Kas soovite paigaldada n\u00fc\u00fcd?",iespell_desc:"\u00d5igekirja kontroll"},advhr:{advhr_desc:"Horisontaalne joonlaud",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotsioonid",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Otsi/Asenda",search_desc:"Otsi",delta_width:"",delta_height:""},advimage:{image_desc:"Sisesta/redigeeri pilt",delta_width:"",delta_height:""},advlink:{link_desc:"Sisesta/redigeeri link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Sisesta muuda atribuute",ins_desc:"Lisandus",del_desc:"Kustutus",acronym_desc:"Akron\u00fc\u00fcm",abbr_desc:"L\u00fchend",cite_desc:"Tsitaat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Redigeeri CSS stiili",delta_height:"",delta_width:""},paste:{selectall_desc:"Vali k\u00f5ik",paste_word_desc:"Kleebi Wordist",paste_text_desc:"Kleebi tavalise tekstina",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Vajuta CTRL+V oma klaviatuuril teksti aknasse kleepimiseks.",text_linebreaks:"J\u00e4ta reavahetused",text_title:"Vajuta CTRL+V oma klaviatuuril teksti aknasse kleepimiseks."},table:{cell:"Lahter",col:"Veerg",row:"Rida",del:"Kustuta tabel",copy_row_desc:"Kopeeri tabeli rida",cut_row_desc:"L\u00f5ika tabeli rida",paste_row_after_desc:"Kleebi tabeli rida j\u00e4rgi",paste_row_before_desc:"Kleebi tabeli rida ette",props_desc:"Tabeli omadused",cell_desc:"Tabeli lahtri omadused",row_desc:"Tabeli rea omadused",merge_cells_desc:"\u00dchenda tabeli lahtrid",split_cells_desc:"Eralda \u00fchendatud tabeli lahtrid",delete_col_desc:"Kustuta veerg",col_after_desc:"Sisesta veerg j\u00e4rgi",col_before_desc:"Sisesta veerg ette",delete_row_desc:"Kustuta rida",row_after_desc:"Sisesta rida j\u00e4rgi",row_before_desc:"Sisesta rida ette",desc:"Sisestab uue tabeli",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Tehtud muudatused kaovad, kui lahkute siit lehelt.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"L\u00fclita \u00fcmber t\u00e4isekraani re\u017eiim"},media:{edit:"Redigeeri manustatud meedia",desc:"Sisesta / redigeeri manustatud meedia",delta_height:"",delta_width:""},fullpage:{desc:"Dokumendi omadused",delta_width:"",delta_height:""},template:{desc:"Sisesta eeldefineeritud \u0161ablooni sisu"},visualchars:{desc:"Visuaalsed kontrollt\u00e4hem\u00e4rgid sisse/v\u00e4lja"},spellchecker:{desc:"L\u00fclita \u00fcmber \u00f5igekirja kontroll",menu:"\u00d5igekirja kontrolli seaded",ignore_word:"J\u00e4ta s\u00f5na vahele",ignore_words:"J\u00e4ra k\u00f5ik vahele",langs:"Keeled",wait:"Palun oota...",sug:"Soovitused",no_sug:"Soovitusi pole",no_mpell:"Valesti kirjutamisi ei leitud."},pagebreak:{desc:"Sisesta lehevahetus."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/eu.js0000644000175000017500000001343311526350525031522 0ustar frankiefrankietinyMCE.addI18n({eu:{common:{more_colors:"Kolore gehiago",invalid_data:"Errorea: baliogabeak diren aukerak sartu dituzu, gorriz agertzen dira.",popup_blocked:"Ups, zure popup blokeatzaileak funtzionalitate bat eskaintzen duen leihoa blokeatu du. Blokeatzailea desgaitu beharko duzu tresna hau erabiltzeko.",clipboard_no_support:"Zure nabigatzailean ez dabil, erabili teklatuko laster-teklak honetarako..",clipboard_msg:"Kopiatu/Ebaki/Itsatsi ez dago Mozilla eta Firefoxen.\\nHonen inguruko informazioa nahi duzu??",not_set:"-- Bat ere ez --",class_name:"Klasea",browse:"Arakatu",close:"Itxi",cancel:"Utzi",update:"Eguneratu",insert:"Txertatu",apply:"Aplikatu",edit_confirm:"Testu-kutxa hau WYSIWYG editorea izatea nahi duzu?"},contextmenu:{full:"Justifikatuta",right:"Eskuinean",center:"Zentratuta",left:"Ezkerrean",align:"Alineazioa"},insertdatetime:{day_short:"Ig,Al,As,Az,Og,Or,Lr,Ig",day_long:"Igandea,Astelehena,Asteartea,Asteazkena,Osteguna,Ostirala,Larunbata,Igandea",months_short:"Urt,Ots,Mar,Api,Mai,Eka,Uzt,Abu,Ira,Urr,Aza,Abe",months_long:"Urtarrila,Otsaila,Martxoa,Apirila,Maiatza,Ekaina,Uztaila,Abuztua,Iraila,Urria,Azaroa,Abendua",inserttime_desc:"Ordua txertatu",insertdate_desc:"Data txertatu",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Inprimatu"},preview:{preview_desc:"Aurreikusi"},directionality:{rtl_desc:"Eskuinatik ezkerrera",ltr_desc:"Ezkerretik eskumara"},layer:{content:"Kapa berria...",absolute_desc:"Posizionatze-absolutua aktibatu/desaktibatu",backward_desc:"Atzera joan",forward_desc:"Aurrera joan",insertlayer_desc:"Kapa berria txertatu"},save:{save_desc:"Gorde",cancel_desc:"Aldaketak bertan behera utzi"},nonbreaking:{nonbreaking_desc:"Espazioa txertatu"},iespell:{download:"ieSpell ez da aurkitu. Instalatu egin nahi duzu?",iespell_desc:"Hizkuntza zuzendu"},advhr:{delta_height:"Altuera",delta_width:"Zabalera",advhr_desc:"Marra horizontala"},emotions:{delta_height:"Altuera",delta_width:"Zabalera",emotions_desc:"Ikonotxoak"},searchreplace:{replace_desc:"Bilatu/Ordeztu",delta_width:"Zabalera",delta_height:"Altuera",search_desc:"Bilatu"},advimage:{delta_width:"Zabalera",image_desc:"Irudia txertatu/editatu",delta_height:"Altuera"},advlink:{delta_height:"Altuera",delta_width:"Zabalera",link_desc:"Lotura txertatu/editatu"},xhtmlxtras:{attribs_delta_height:"Atributuen altuera",attribs_delta_width:"Atributuen zabalera",ins_delta_height:"Txertaketaren altuera",ins_delta_width:"Txertaketaren zabalera",del_delta_height:"Ezabaketaren altuera",del_delta_width:"Ezabaketaren zabalera",acronym_delta_height:"Akronimoen altuera",acronym_delta_width:"Akronimoen zabalera",abbr_delta_height:"Laburduren altuera",abbr_delta_width:"Laburduren zabalera",cite_delta_height:"Ziten altuera",cite_delta_width:"Ziten zabalera",attribs_desc:"Atributuak txertatu/editatu",ins_desc:"Txertaketa",del_desc:"Ezabaketa",acronym_desc:"Akronimoa",abbr_desc:"Laburdura",cite_desc:"Zita"},style:{delta_height:"Altuera",delta_width:"Zabalera",desc:"Aldatu CSS estiloa"},paste:{plaintext_mode:"Itsasketa testu moduan dago orain. Egin klik itsasketa arruntera itzultzeko.",plaintext_mode_sticky:"Itsasketa testu moduan dago orain. Egin klik itsasketa arruntera itzultzeko. Zerbait itsatsi ostean, modu arruntera pasatuko zara automatikoki.",selectall_desc:"Aukeratu guztia",paste_word_desc:"Word-etik itsatsi",paste_text_desc:"Testu gisa itsatsi"},paste_dlg:{word_title:"Erabili CTRL+V testua lehioan itsasteko.",text_linebreaks:"Mantendu lerro-jauziak",text_title:"Erabili CTRL+V testua lehioan itsasteko."},table:{merge_cells_delta_height:"Gelaxkak batzearen altuera",merge_cells_delta_width:"Gelaxkak batzearen zabalera",table_delta_height:"Taularen altuera",table_delta_width:"Taularen zabalera",cellprops_delta_height:"Gelaxken propietateen altuera",cellprops_delta_width:"Gelaxken propietateen zabalera",rowprops_delta_height:"Lerroen propietateen altuera",rowprops_delta_width:"Lerroen propietateen zabalera",cell:"Gelaxka",col:"Zutabea",row:"Lerroa",del:"Ezabatu taula",copy_row_desc:"Kopiatu lerroa",cut_row_desc:"Moztu lerroa",paste_row_after_desc:"Itsatsi lerroa ondoren",paste_row_before_desc:"Itsatsi lerroa aurretik",props_desc:"Taula ezaugarriak",cell_desc:"Gelaxka ezaugarriak",row_desc:"Lerro ezaugarriak",merge_cells_desc:"Bateratu gelaxkak",split_cells_desc:"Banatu bateratutako gelaxkak",delete_col_desc:"Ezabatu zutabea",col_after_desc:"Txertatu zutabea ondoren",col_before_desc:"Txertatu zutabea aurretik",delete_row_desc:"Ezabatu lerroa",row_after_desc:"Txertatu lerroa ondoren",row_before_desc:"Txertatu lerroa aurretik",desc:"Taula berri bat txertatu"},autosave:{warning_message:"Gordetako edukia errekuperatzen baduzu, orain editorean dagoena galdu egingo duzu.\\n\\nZiur zaude gordetakoa errekuperatzea nahi duzula?",restore_content:"Automatikoki gordetako edukia errekuperatu.",unload_msg:"Egindako aldaketak galdu egingo dira orri honetatik kanpona nabigatzen baldin baduzu."},fullscreen:{desc:"Aldatu pantaila osoko modura"},media:{delta_height:"Altuera",delta_width:"Zabalera",edit:"Editatu ahokatutako euskarria",desc:"Sartu / editatu ahokatutako euskarria"},fullpage:{desc:"Dokumentuaren ezaugarriak",delta_width:"Zabalera",delta_height:"Altuera"},template:{desc:"Txertatu aurredefinitutako txantiloiaren edukia"},visualchars:{desc:"Begi kontrol karaktereak gaitu/ezgaitu."},spellchecker:{desc:"Ortografia zuzentzaile modura aldatu",menu:"Ortografia zuzentzailearen doikuntza",ignore_word:"Ezikusi hitza",ignore_words:"Ezikusi guztiak",langs:"Hizkuntzak",wait:"Itxaron mesedez...",sug:"Gomendioa",no_sug:"Gomendiorik ez",no_mpell:"Ez da akatsik aurkitu"},pagebreak:{desc:"Txertatu orri jauzia."},advlist:{types:"Motak",def:"Lehenetsiak",lower_alpha:"Hizki xeheak",lower_greek:"Hizki greko xeheak",lower_roman:"Zenbaki erromatar xeheak",upper_alpha:"Hizki larriak",upper_roman:"Zenbaki erromatar larriak",circle:"Borobila",disc:"Diskoa",square:"Karratua"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/fr.js0000644000175000017500000001435311526350525031522 0ustar frankiefrankietinyMCE.addI18n({fr:{common:{more_colors:"Plus de couleurs",invalid_data:"Erreur : saisie de valeurs incorrectes. Elles sont mises en \u00e9vidence en rouge.",popup_blocked:"D\u00e9sol\u00e9, nous avons d\u00e9tect\u00e9 que votre bloqueur de popup a bloqu\u00e9 une fen\u00eatre dont l\'application a besoin. Vous devez d\u00e9sactiver votre bloqueur de popup pour pouvoir utiliser cet outil.",clipboard_no_support:"Actuellement non support\u00e9 par votre navigateur.\\n Veuillez utiliser les raccourcis clavier \u00e0 la place.",clipboard_msg:"Les fonctions Copier/Couper/Coller ne sont pas valables sur Mozilla et Firefox.\\nSouhaitez-vous avoir plus d\'informations sur ce sujet ?",not_set:"-- non d\u00e9fini --",class_name:"Classe",browse:"parcourir",close:"Fermer",cancel:"Annuler",update:"Mettre \u00e0 jour",insert:"Ins\u00e9rer",apply:"Appliquer",edit_confirm:"Souhaitez-vous utiliser le mode WYSIWYG pour cette zone de texte ?"},contextmenu:{full:"Justifi\u00e9",right:"Droite",center:"Centr\u00e9",left:"Gauche",align:"Alignement"},insertdatetime:{day_short:"Dim,Lun,Mar,Mer,Jeu,Ven,Sam,Dim",day_long:"Dimanche,Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche",months_short:"Jan,F\u00e9v,Mar,Avr,Mai,Juin,Juil,Ao\u00fbt,Sep,Oct,Nov,D\u00e9c",months_long:"Janvier,F\u00e9vrier,Mars,Avril,Mai,Juin,Juillet,Ao\u00fbt,Septembre,Octobre,Novembre,D\u00e9cembre",inserttime_desc:"Ins\u00e9rer l\'heure",insertdate_desc:"Ins\u00e9rer la date",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Imprimer"},preview:{preview_desc:"Pr\u00e9visualiser"},directionality:{rtl_desc:"\u00c9criture de droite \u00e0 gauche",ltr_desc:"\u00c9criture de gauche \u00e0 droite"},layer:{content:"Nouvelle couche\u2026",absolute_desc:"Activer le positionnement absolu",backward_desc:"D\u00e9placer vers l\'arri\u00e8re",forward_desc:"D\u00e9placer vers l\'avant",insertlayer_desc:"Ins\u00e9rer une nouvelle couche"},save:{save_desc:"Enregistrer",cancel_desc:"Annuler toutes les modifications"},nonbreaking:{nonbreaking_desc:"Ins\u00e9rer une espace ins\u00e9cable"},iespell:{download:"ieSpell n\'est pas install\u00e9. Souhaitez-vous l\'installer maintenant ?",iespell_desc:"Lancer le v\u00e9rificateur d\'orthographe"},advhr:{delta_height:"Ecart de hauteur",delta_width:"Ecart de largeur",advhr_desc:"Ins\u00e9rer un trait horizontal"},emotions:{emotions_desc:"\u00c9motic\u00f4nes",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Rechercher / remplacer",search_desc:"Rechercher",delta_width:"",delta_height:""},advimage:{image_desc:"Ins\u00e9rer / \u00e9diter une image",delta_width:"",delta_height:""},advlink:{link_desc:"Ins\u00e9rer / \u00e9diter un lien",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Ins\u00e9rer / \u00e9diter les attributs",ins_desc:"Ins\u00e9r\u00e9",del_desc:"Barr\u00e9",acronym_desc:"Acronyme",abbr_desc:"Abr\u00e9viation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u00c9diter la feuille de style (CSS)",delta_height:"",delta_width:""},paste:{plaintext_mode:"Le collage est actuellement en mode texte non format\u00e9. Cliquez \u00e0 nouveau pour revenir en mode de collage ordinaire.",plaintext_mode_sticky:"Le collage est actuellement en mode texte non format\u00e9. Cliquez \u00e0 nouveau pour revenir en mode de collage ordinaire. Apr\u00e8s avoir coll\u00e9 quelque chose, vous retournerez en mode de collage ordinaire.",selectall_desc:"Tout s\u00e9lectionner",paste_word_desc:"Coller un texte cr\u00e9\u00e9 sous Word",paste_text_desc:"Coller comme texte brut"},paste_dlg:{word_title:"Utilisez CTRL+V sur votre clavier pour coller le texte dans la fen\u00eatre.",text_linebreaks:"Conserver les retours \u00e0 la ligne",text_title:"Utilisez CTRL+V sur votre clavier pour coller le texte dans la fen\u00eatre."},table:{cell:"Cellule",col:"Colonne",row:"Ligne",del:"Effacer le tableau",copy_row_desc:"Copier la ligne",cut_row_desc:"Couper la ligne",paste_row_after_desc:"Coller la ligne apr\u00e8s",paste_row_before_desc:"Coller la ligne avant",props_desc:"Propri\u00e9t\u00e9s du tableau",cell_desc:"Propri\u00e9t\u00e9s de la cellule",row_desc:"Propri\u00e9t\u00e9s de la ligne",merge_cells_desc:"Fusionner les cellules",split_cells_desc:"Scinder les cellules fusionn\u00e9es",delete_col_desc:"Effacer la colonne",col_after_desc:"Ins\u00e9rer une colonne apr\u00e8s",col_before_desc:"Ins\u00e9rer une colonne avant",delete_row_desc:"Effacer la ligne",row_after_desc:"Ins\u00e9rer une ligne apr\u00e8s",row_before_desc:"Ins\u00e9rer une ligne avant",desc:"Ins\u00e9rer un nouveau tableau",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Si vous restaurez le contenu sauv\u00e9, vous perdrez le contenu qui est actuellement dans l\'\u00e9diteur.\\n\\n\u00cates-vous s\u00fbr de vouloir restaurer le contenu sauv\u00e9 ?",restore_content:"Restaurer le contenu auto-sauvegard\u00e9.",unload_msg:"Les modifications apport\u00e9es seront perdus si vous quittez cette page."},fullscreen:{desc:"Passer en mode plein \u00e9cran"},media:{edit:"\u00c9diter un m\u00e9dia incorpor\u00e9",desc:"Ins\u00e9rer / \u00e9diter un m\u00e9dia incorpor\u00e9",delta_height:"",delta_width:""},fullpage:{desc:"Propri\u00e9t\u00e9s du document",delta_width:"",delta_height:""},template:{desc:"Ins\u00e9rer un mod\u00e8le pr\u00e9d\u00e9fini."},visualchars:{desc:"Activer les caract\u00e8res de mise en page."},spellchecker:{desc:"Activer le v\u00e9rificateur d\'orthographe",menu:"Param\u00e8tres du v\u00e9rificateur d\'orthographe",ignore_word:"Ignorer le mot",ignore_words:"Tout ignorer",langs:"Langues",wait:"Veuillez patienter\u2026",sug:"Suggestions",no_sug:"Aucune suggestion",no_mpell:"Aucune erreur trouv\u00e9e."},pagebreak:{desc:"Ins\u00e9rer un saut de page."},advlist:{types:"Types",def:"D\u00e9faut",lower_alpha:"Alpha minuscule",lower_greek:"Grec minuscule",lower_roman:"Romain minuscule",upper_alpha:"Alpha majuscule",upper_roman:"Romain majuscule",circle:"Cercle",disc:"Disque",square:"Carr\u00e9"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/gl.js0000644000175000017500000001262511526350525031515 0ustar frankiefrankietinyMCE.addI18n({gl:{common:{more_colors:"Mais cores",invalid_data:"Error: Introducidos valores non v\u00e1lidos, est\u00e1n marcados en vermello.",popup_blocked:"O seu bloqueador de vent\u00e1s emerxentes deshabilitou unha vent\u00e1 que precisa pra o funcionamento da aplicaci\u00f3n. Precisa deshabilita-lo bloqueo de `popups` neste sitio pra utilizar \u00f3 m\u00e1ximo esta ferramenta.",clipboard_no_support:"O seu navegador non soporta estas funci\u00f3ns, use os atallos de teclado.",clipboard_msg:"Copiar/Cortar/Pegar non est\u00e1 disponible en Mozilla e Firefox.\\n\u00bfDesexa obter mais informaci\u00f3n sobre de este asunto?",not_set:"-- Ning\u00fan --",class_name:"Clase",browse:"Examinar",close:"Cerrar",cancel:"Cancelar",update:"Actualizar",insert:"Insertar",apply:"Apricar",edit_confirm:"\u00bfDesexa utiliza-lo modo WYSIWYG pra esta caixa de texto?"},contextmenu:{full:"Xustificado",right:"Dereita",center:"Centrado",left:"Esquerda",align:"Ali\u00f1amento"},insertdatetime:{day_short:"Dom,Lun,Mar,M\u00e9r,Xov,Ver,S\u00e1b,Dom",day_long:"Domingo,Luns,Martes,M\u00e9rcores,Xoves,Venres,S\u00e1bado,Domingo",months_short:"Xan,Feb,Mar,Abr,Mai,Xu\u00f1,Xul,Ago,Set,Out,Nov,Dec",months_long:"Xaneito,Febreiro,Marzo,Abril,Maio,Xu\u00f1o,Xullo,Agosto,Setembro,Outubro,Novembro,Decembro",inserttime_desc:"Insertar hora",insertdate_desc:"Insertar data",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Imprimir"},preview:{preview_desc:"Vista previa"},directionality:{rtl_desc:"Direcci\u00f3n dereita a esquerda",ltr_desc:"Direcci\u00f3n esquerda a dereita"},layer:{content:"Nova capa...",absolute_desc:"Posici\u00f3n absoluta",backward_desc:"Recuar",forward_desc:"Avanzar",insertlayer_desc:"Insertar nova capa"},save:{save_desc:"Gardar",cancel_desc:"Cancelar todo-los cambios"},nonbreaking:{nonbreaking_desc:"Insertar espacio non colapsable"},iespell:{download:"Non se detectou \'ieSpell\'. \u00bfDesexa instala-lo agora?",iespell_desc:"Corrector ortogr\u00e1fico"},advhr:{advhr_desc:"Regra horizontal",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emoticones",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Buscar/Reemplazar",search_desc:"Buscar",delta_width:"",delta_height:""},advimage:{image_desc:"Insertar/editar imaxe",delta_width:"",delta_height:""},advlink:{link_desc:"Insertar/editar hiperv\u00ednculo",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insertar/Editar atributos",ins_desc:"Inserci\u00f3n",del_desc:"Borrado",acronym_desc:"Acr\u00f3nimo",abbr_desc:"Abreviatura",cite_desc:"Cita",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Editar Estilo CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Seleccionar todo",paste_word_desc:"Pegar desde Word",paste_text_desc:"Pegar como texto simple",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V no teclado pra pega-lo texto na vent\u00e1.",text_linebreaks:"Manter salto de li\u00f1as",text_title:"Use CTRL+V no teclado pra pega-lo texto na vent\u00e1."},table:{cell:"Celda",col:"Columna",row:"Fila",del:"Eliminar t\u00e1boa",copy_row_desc:"Copiar fila",cut_row_desc:"Cortar fila",paste_row_after_desc:"Pegar filas (desp\u00f3is)",paste_row_before_desc:"Pegar filas (antes)",props_desc:"Propiedades da t\u00e1boa",cell_desc:"Propiedades da celda",row_desc:"Propiedades da fila",merge_cells_desc:"Vincular celdas",split_cells_desc:"Dividir celdas",delete_col_desc:"Suprimir columna",col_after_desc:"Insertar columna (desp\u00f3is)",col_before_desc:"Insertar columna (antes)",delete_row_desc:"Suprimir fila",row_after_desc:"Insertar fila (desp\u00f3is)",row_before_desc:"Insertar fila (antes)",desc:"Inserta unha nova t\u00e1boa",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Os cambios realizados perderanse se sae desta p\u00e1xina.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Cambiar a modo Pantalla Completa"},media:{edit:"Editar medio embebido",desc:"Insertar/editar medio embebido",delta_height:"",delta_width:""},fullpage:{desc:"Propiedades do documento",delta_width:"",delta_height:""},template:{desc:"Insertar contido de plantilla predefinida"},visualchars:{desc:"Caracteres de control ON/OFF."},spellchecker:{desc:"Conmutar corrector ortogr\u00e1fico",menu:"Configuraci\u00f3n de corrector ortogr\u00e1fico",ignore_word:"Ignorar verba",ignore_words:"Ignorar todo",langs:"Idiomas",wait:"Agarde...",sug:"Suxerencias",no_sug:"Sen suxerencias",no_mpell:"Non se atoparon erros."},pagebreak:{desc:"Insertar fin de p\u00e1xina"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/he.js0000644000175000017500000003005111526350525031500 0ustar frankiefrankietinyMCE.addI18n({he:{common:{more_colors:"\u05e2\u05d5\u05d3 \u05e6\u05d1\u05e2\u05d9\u05dd",invalid_data:"\u05e9\u05d2\u05d9\u05d0\u05d4: \u05d4\u05d5\u05e7\u05dc\u05d3 \u05de\u05d9\u05d3\u05e2 \u05dc\u05d0 \u05ea\u05e7\u05e0\u05d9. \u05d4\u05de\u05d9\u05d3\u05e2 \u05e1\u05d5\u05de\u05df \u05d1\u05d0\u05d3\u05d5\u05dd.",popup_blocked:"\u05d7\u05d5\u05e1\u05dd \u05e4\u05e8\u05d9\u05d8\u05d9\u05dd \u05de\u05d5\u05e7\u05e4\u05e6\u05d9\u05dd \u05de\u05e0\u05e2 \u05de\u05d7\u05dc\u05d5\u05df \u05d7\u05e9\u05d5\u05d1 \u05de\u05dc\u05d4\u05e4\u05ea\u05d7,\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05db\u05dc\u05d9 \u05d6\u05d4 \u05e2\u05dc\u05d9\u05da \u05dc\u05d1\u05d8\u05dc \u05d0\u05ea \u05d7\u05d5\u05e1\u05dd \u05d4\u05e4\u05e8\u05d9\u05d8\u05d9\u05dd",clipboard_no_support:"\u05db\u05e8\u05d2\u05e2 \u05dc\u05d0 \u05e0\u05ea\u05de\u05da \u05e2\u05dc \u05d9\u05d3\u05d9 \u05d4\u05d3\u05e4\u05d3\u05e4\u05df \u05e9\u05dc\u05da. \u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05e7\u05d9\u05e6\u05d5\u05e8\u05d9 \u05d4\u05de\u05e7\u05dc\u05d3\u05ea.",clipboard_msg:"\n \u05d4\u05e2\u05ea\u05e7\u05d4/\u05d2\u05d6\u05d9\u05e8\u05d4 \u05d5\u05d4\u05d3\u05d1\u05e7\u05d4 \u05d0\u05d9\u05e0\u05dd \u05d6\u05de\u05d9\u05e0\u05d9\u05dd \u05d1 Mozilla \u05d5\u05d1-Firefox.\n \u05d4\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05e7\u05d1\u05dc \u05de\u05d9\u05d3\u05e2 \u05e0\u05d5\u05e1\u05e3 \u05e2\u05dc \u05d4\u05e0\u05d5\u05e9\u05d0?\n ",not_set:"-- \u05dc\u05d0 \u05d4\u05d5\u05d2\u05d3\u05e8 --",class_name:"\u05de\u05d7\u05dc\u05e7\u05d4",browse:"\u05e2\u05d9\u05d5\u05df",close:"\u05e1\u05d2\u05d9\u05e8\u05d4",cancel:"\u05d1\u05d9\u05d8\u05d5\u05dc",update:"\u05e2\u05d3\u05db\u05d5\u05df",insert:"\u05d4\u05d5\u05e1\u05e4\u05d4",apply:"\u05d0\u05d9\u05e9\u05d5\u05e8",edit_confirm:"\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05e2\u05d5\u05e8\u05da \u05d4\u05de\u05ea\u05e7\u05d3\u05dd?"},contextmenu:{full:"\u05e9\u05e0\u05d9 \u05d4\u05e6\u05d3\u05d3\u05d9\u05dd",right:"\u05d9\u05de\u05d9\u05df",center:"\u05d0\u05de\u05e6\u05e2",left:"\u05e9\u05de\u05d0\u05dc",align:"\u05d9\u05d9\u05e9\u05d5\u05e8"},insertdatetime:{day_short:"\u05d9\u05d5\u05dd \u05d0\',\u05d9\u05d5\u05dd \u05d1\',\u05d9\u05d5\u05dd \u05d2\',\u05d9\u05d5\u05dd \u05d3\',\u05d9\u05d5\u05dd \u05d4\',\u05d9\u05d5\u05dd \u05d5\',\u05e9\u05d1\u05ea,\u05d9\u05d5\u05dd \u05d0\'",day_long:"\u05d9\u05d5\u05dd \u05e8\u05d0\u05e9\u05d5\u05df,\u05d9\u05d5\u05dd \u05e9\u05e0\u05d9,\u05d9\u05d5\u05dd \u05e9\u05dc\u05d9\u05e9\u05d9,\u05d9\u05d5\u05dd \u05e8\u05d1\u05d9\u05e2\u05d9,\u05d9\u05d5\u05dd \u05d7\u05de\u05d9\u05e9\u05d9,\u05d9\u05d5\u05dd \u05e9\u05d9\u05e9,\u05d9\u05d5\u05dd \u05e9\u05d1\u05ea,\u05d9\u05d5\u05dd \u05e8\u05d0\u05e9\u05d5\u05df",months_short:"\u05d9\u05e0\u05d5\u05d0\u05e8,\u05e4\u05d1\u05e8\u05d5\u05d0\u05e8,\u05de\u05e8\u05e5,\u05d0\u05e4\u05e8\u05d9\u05dc,\u05de\u05d0\u05d9,\u05d9\u05d5\u05e0\u05e2,\u05d9\u05d5\u05dc\u05d9,\u05d0\u05d5\u05d2\u05d5\u05e1\u05d8,\u05e1\u05e4\u05d8\u05de\u05d1\u05e8,\u05d0\u05d5\u05e7\u05d8\u05d5\u05d1\u05e8,\u05e0\u05d5\u05d1\u05de\u05d1\u05e8,\u05d3\u05e6\u05de\u05d1\u05e8",months_long:"\u05d9\u05e0\u05d5\u05d0\u05e8,\u05e4\u05d1\u05e8\u05d5\u05d0\u05e8,\u05de\u05e8\u05e5,\u05d0\u05e4\u05e8\u05d9\u05dc,\u05de\u05d0\u05d9,\u05d9\u05d5\u05e0\u05e2,\u05d9\u05d5\u05dc\u05d9,\u05d0\u05d5\u05d2\u05d5\u05e1\u05d8,\u05e1\u05e4\u05d8\u05de\u05d1\u05e8,\u05d0\u05d5\u05e7\u05d8\u05d5\u05d1\u05e8,\u05e0\u05d5\u05d1\u05de\u05d1\u05e8,\u05d3\u05e6\u05de\u05d1\u05e8",inserttime_desc:"\u05d4\u05d5\u05e1\u05e4\u05ea \u05d6\u05de\u05df",insertdate_desc:"\u05d4\u05d5\u05e1\u05e4\u05ea \u05ea\u05d0\u05e8\u05d9\u05da",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"\u05d4\u05d3\u05e4\u05e1\u05d4"},preview:{preview_desc:"\u05ea\u05e6\u05d5\u05d2\u05d4 \u05de\u05e7\u05d3\u05d9\u05de\u05d4"},directionality:{rtl_desc:"\u05db\u05d9\u05d5\u05d5\u05df \u05d8\u05e7\u05e1\u05d8 \u05de\u05d9\u05de\u05d9\u05df \u05dc\u05e9\u05de\u05d0\u05dc",ltr_desc:"\u05db\u05d9\u05d5\u05d5\u05df \u05d8\u05e7\u05e1\u05d8 \u05de\u05e9\u05de\u05d0\u05dc \u05dc\u05d9\u05de\u05d9\u05df"},layer:{content:"\u05e9\u05db\u05d1\u05d4 \u05d7\u05d3\u05e9\u05d4...",absolute_desc:"\u05d1\u05d7\u05d9\u05e8\u05ea \u05de\u05d9\u05e7\u05d5\u05dd \u05de\u05d5\u05d7\u05dc\u05d8",backward_desc:"\u05d4\u05e2\u05d1\u05e8\u05d4 \u05d0\u05d7\u05d5\u05e8\u05d4",forward_desc:"\u05d4\u05e2\u05d1\u05e8\u05d4 \u05e7\u05d3\u05d9\u05de\u05d4",insertlayer_desc:"\u05d4\u05d5\u05e1\u05e4\u05ea \u05e9\u05db\u05d1\u05d4 \u05d7\u05d3\u05e9\u05d4"},save:{save_desc:"\u05e9\u05de\u05d9\u05e8\u05d4",cancel_desc:"\u05d1\u05d9\u05d8\u05d5\u05dc \u05db\u05dc \u05d4\u05e9\u05d9\u05e0\u05d5\u05d9\u05dd"},nonbreaking:{nonbreaking_desc:"\u05d4\u05d5\u05e1\u05e4\u05ea \u05e8\u05d5\u05d5\u05d7"},iespell:{download:" \u05dc\u05d0 \u05e0\u05de\u05e6\u05d0 ieSpell. \u05d4\u05d0\u05dd \u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05ea\u05e7\u05d9\u05df?",iespell_desc:"\u05d1\u05d3\u05d9\u05e7\u05ea \u05d0\u05d9\u05d5\u05ea \u05d1\u05d0\u05e0\u05d2\u05dc\u05d9\u05ea"},advhr:{advhr_desc:"\u05e7\u05d5 \u05d0\u05d5\u05e4\u05e7\u05d9",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u05e1\u05de\u05d9\u05d9\u05dc\u05d9\u05dd",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u05d4\u05d7\u05dc\u05e4\u05d4",search_desc:"\u05d7\u05d9\u05e4\u05d5\u05e9",delta_width:"",delta_height:""},advimage:{image_desc:"\u05d4\u05d5\u05e1\u05e4\u05d4/\u05e2\u05e8\u05d9\u05db\u05ea \u05ea\u05de\u05d5\u05e0\u05d4",delta_width:"",delta_height:""},advlink:{link_desc:"\u05d4\u05d5\u05e1\u05e4\u05ea/\u05e2\u05e8\u05d9\u05db\u05ea \u05e7\u05d9\u05e9\u05d5\u05e8",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u05d4\u05db\u05e0\u05e1/\u05e2\u05e8\u05d5\u05da \u05ea\u05db\u05d5\u05e0\u05d5\u05ea",ins_desc:"\u05d4\u05db\u05e0\u05e1\u05d4",del_desc:"\u05de\u05d7\u05d9\u05e7\u05d4",acronym_desc:"\u05e8\u05d0\u05e9\u05d9 \u05ea\u05d9\u05d1\u05d5\u05ea",abbr_desc:"\u05e7\u05d9\u05e6\u05d5\u05e8",cite_desc:"\u05e6\u05d9\u05d8\u05d5\u05d8",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u05e2\u05d3\u05db\u05d5\u05df \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"\u05d1\u05d7\u05e8 \u05d4\u05db\u05dc",paste_word_desc:"\u05d4\u05d3\u05d1\u05e7\u05d4 \u05de-WORD",paste_text_desc:"\u05d4\u05d3\u05d1\u05e7\u05d4 \u05db\u05d8\u05e7\u05e1\u05d8 \u05d1\u05dc\u05d1\u05d3"},paste_dlg:{word_title:"\u05d4\u05d3\u05d1\u05d9\u05e7\u05d5 \u05d1\u05d7\u05dc\u05d5\u05df \u05d6\u05d4 \u05d0\u05ea \u05d4\u05d8\u05e7\u05e1\u05d8 \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea \u05d4\u05de\u05e7\u05e9\u05d9\u05dd CTRL+V.",text_linebreaks:"\u05d4\u05e9\u05d0\u05e8 \u05d0\u05ea \u05e9\u05d5\u05e8\u05d5\u05ea \u05d4\u05e8\u05d5\u05d5\u05d7",text_title:"\u05d4\u05d3\u05d1\u05d9\u05e7\u05d5 \u05d1\u05d7\u05dc\u05d5\u05df \u05d6\u05d4 \u05d0\u05ea \u05d4\u05d8\u05e7\u05e1\u05d8 \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea \u05d4\u05de\u05e7\u05e9\u05d9\u05dd CTRL+V."},table:{cell:"\u05ea\u05d0",col:"\u05e2\u05de\u05d5\u05d3\u05d4",row:"\u05e9\u05d5\u05e8\u05d4",del:"\u05de\u05d7\u05d9\u05e7\u05ea \u05d8\u05d1\u05dc\u05d4",copy_row_desc:"\u05d4\u05e2\u05ea\u05e7\u05ea \u05e9\u05d5\u05e8\u05d4 \u05d1\u05d8\u05d1\u05dc\u05d4",cut_row_desc:"\u05d2\u05d6\u05d9\u05e8\u05ea \u05e9\u05d5\u05e8\u05d4 \u05d1\u05d8\u05d1\u05dc\u05d4",paste_row_after_desc:"\u05d4\u05d3\u05d1\u05e7\u05ea \u05e9\u05d5\u05e8\u05d4 \u05d1\u05d8\u05d1\u05dc\u05d4 \u05d0\u05d7\u05e8\u05d9",paste_row_before_desc:"\u05d4\u05d3\u05d1\u05e7\u05ea \u05e9\u05d5\u05e8\u05d4 \u05d1\u05d8\u05d1\u05dc\u05d4 \u05dc\u05e4\u05e0\u05d9",props_desc:"\u05ea\u05db\u05d5\u05e0\u05d5\u05ea \u05d4\u05d8\u05d1\u05dc\u05d4",cell_desc:"\u05ea\u05db\u05d5\u05e0\u05d5\u05ea \u05ea\u05d0 \u05d1\u05d8\u05d1\u05dc\u05d4",row_desc:"\u05ea\u05db\u05d5\u05e0\u05d5\u05ea \u05e9\u05d5\u05e8\u05d4 \u05d1\u05d8\u05d1\u05dc\u05d4",merge_cells_desc:"\u05d0\u05d9\u05d7\u05d5\u05d3 \u05ea\u05d0\u05d9\u05dd \u05d1\u05d8\u05d1\u05dc\u05d4",split_cells_desc:"\u05e4\u05d9\u05e6\u05d5\u05dc \u05ea\u05d0\u05d9\u05dd \u05d1\u05d8\u05d1\u05dc\u05d4",delete_col_desc:"\u05d4\u05e1\u05e8\u05ea \u05e2\u05de\u05d5\u05d3\u05d4",col_after_desc:"\u05d4\u05db\u05e0\u05e1\u05ea \u05e2\u05de\u05d5\u05d3\u05d4 \u05de\u05e9\u05de\u05d0\u05dc",col_before_desc:"\u05d4\u05db\u05e0\u05e1\u05ea \u05e2\u05de\u05d5\u05d3\u05d4 \u05de\u05d9\u05de\u05d9\u05df",delete_row_desc:"\u05de\u05d7\u05d9\u05e7\u05ea \u05e9\u05d5\u05e8\u05d4",row_after_desc:"\u05d4\u05db\u05e0\u05e1\u05ea \u05e9\u05d5\u05e8\u05d4 \u05de\u05ea\u05d7\u05ea",row_before_desc:"\u05d4\u05db\u05e0\u05e1\u05ea \u05e9\u05d5\u05e8\u05d4 \u05de\u05e2\u05dc",desc:"\u05d4\u05db\u05e0\u05e1\u05ea \u05d0\u05d5 \u05e2\u05e8\u05d9\u05db\u05ea \u05d8\u05d1\u05dc\u05d4",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u05d0\u05dd \u05ea\u05e9\u05d7\u05d6\u05e8 \u05d0\u05ea \u05d4\u05ea\u05d5\u05db\u05df \u05dc\u05d2\u05e8\u05d9\u05e1\u05d0 \u05d4\u05e9\u05de\u05d5\u05e8\u05d4, \u05ea\u05d0\u05d1\u05d3 \u05d0\u05ea \u05db\u05dc \u05d4\u05ea\u05d5\u05db\u05df \u05e9\u05e0\u05de\u05e6\u05d0 \u05db\u05e2\u05ea \u05d1\u05e2\u05d5\u05e8\u05da. \u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d0\u05ea\u05d4 \u05e8\u05d5\u05e6\u05d4 \u05dc\u05e9\u05d7\u05d6\u05e8 \u05d0\u05ea \u05d4\u05ea\u05d5\u05db\u05df \u05dc\u05d2\u05d9\u05e8\u05e1\u05d0 \u05d4\u05e9\u05de\u05d5\u05e8\u05d4?.",restore_content:"\u05e9\u05d7\u05d6\u05d5\u05e8 \u05dc\u05d2\u05d9\u05e8\u05e1\u05d0 \u05e9\u05de\u05d5\u05e8\u05d4 \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9\u05ea",unload_msg:"\u05d4\u05e9\u05d9\u05e0\u05d5\u05d9\u05d9\u05dd \u05e9\u05d1\u05d9\u05e6\u05e2\u05ea \u05dc\u05d0 \u05d9\u05e9\u05de\u05e8\u05d5 \u05d0\u05dd \u05ea\u05e2\u05d1\u05d5\u05e8 \u05de\u05d3\u05e3 \u05d6\u05d4"},fullscreen:{desc:"\u05de\u05e2\u05d1\u05e8 \u05dc\u05de\u05e1\u05da \u05de\u05dc\u05d0/\u05d7\u05dc\u05e7\u05d9"},media:{edit:"\u05e2\u05e8\u05d9\u05db\u05ea \u05e1\u05e8\u05d8\u05d5\u05df",desc:"\u05d4\u05d5\u05e1\u05e4\u05ea/\u05e2\u05e8\u05d9\u05db\u05ea \u05e1\u05e8\u05d8\u05d5\u05df",delta_height:"",delta_width:""},fullpage:{desc:"\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05e2\u05de\u05d5\u05d3",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"\u05d4\u05e6\u05d2/\u05d4\u05e1\u05ea\u05e8 \u05ea\u05d5\u05d5\u05d9 \u05d1\u05e7\u05e8\u05d4"},spellchecker:{desc:"\u05d4\u05e4\u05e2\u05dc\u05ea \u05d1\u05d5\u05d3\u05e7 \u05d0\u05d9\u05d5\u05ea",menu:"\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05d1\u05d5\u05d3\u05e7 \u05d0\u05d9\u05d5\u05ea",ignore_word:"\u05dc\u05d4\u05ea\u05e2\u05dc\u05dd \u05de\u05d4\u05de\u05d9\u05dc\u05d4",ignore_words:"\u05dc\u05d4\u05ea\u05e2\u05dc\u05dd \u05de\u05d4\u05db\u05dc",langs:"\u05e9\u05e4\u05d5\u05ea",wait:"\u05e0\u05d0 \u05dc\u05d4\u05de\u05ea\u05d9\u05df..",sug:"\u05d4\u05e6\u05e2\u05d5\u05ea",no_sug:"\u05d0\u05d9\u05df \u05d4\u05e6\u05e2\u05d5\u05ea",no_mpell:"\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05e9\u05d2\u05d9\u05d0\u05d5\u05ea \u05d0\u05d9\u05d5\u05ea"},pagebreak:{desc:"\u05d4\u05d5\u05e1\u05e4\u05ea \u05de\u05e2\u05d1\u05e8 \u05d3\u05e3"},advlist:{types:"\u05e1\u05d5\u05d2\u05d9\u05dd",def:"\u05d1\u05e8\u05d9\u05e8\u05ea \u05de\u05d7\u05d3\u05dc",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"\u05e2\u05d2\u05d5\u05dc",disc:"\u05d3\u05d9\u05e1\u05e7",square:"\u05de\u05e8\u05d5\u05d1\u05e2"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/hi.js0000644000175000017500000001210211526350525031501 0ustar frankiefrankietinyMCE.addI18n({hi:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text"},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/gu.js0000644000175000017500000001210211526350525031514 0ustar frankiefrankietinyMCE.addI18n({gu:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ia.js0000644000175000017500000001517211526350525031504 0ustar frankiefrankietinyMCE.addI18n({ia:{common:{more_colors:"\u66f4\u591a\u989c\u8272",invalid_data:"\u9519\u8bef\uff1a\u8f93\u5165\u4e86\u65e0\u6548\u7684\u503c\uff0c\u5df2\u6807\u8bb0\u4e3a\u7ea2\u8272\u3002",popup_blocked:"\u5bf9\u4e0d\u8d77\uff0c\u60a8\u7684\u5feb\u663e\u7a97\u53e3\u963b\u6b62\u7a0b\u5e8f\u5df2\u7ecf\u963b\u6b62\u4e86\u672c\u5feb\u663e\u7a97\u53e3\uff0c\u8bf7\u8c03\u6574\u4f60\u7684\u6d4f\u89c8\u5668\u8bbe\u7f6e\uff0c\u5141\u8bb8\u672c\u7f51\u7ad9\u5f39\u51fa\u65b0\u7a97\u53e3\uff0c\u4ee5\u4fbf\u4f7f\u7528\u6b64\u529f\u80fd",clipboard_no_support:"\u5c1a\u4e0d\u652f\u6301\u60a8\u6240\u4f7f\u7528\u7684\u6d4f\u89c8\u5668\uff0c\u8bf7\u4f7f\u7528\u952e\u76d8\u65b9\u5f0f\u64cd\u4f5c",clipboard_msg:"\u590d\u5236\u3001\u526a\u5207\u548c\u7c98\u8d34\u529f\u80fd\u5728Mozilla \u548c Firefox\u4e2d\u65e0\u6cd5\u4f7f\u7528",not_set:"-- \u672a\u8bbe\u7f6e --",class_name:"\u6837\u5f0f\u7c7b\u540d",browse:"\u6d4f\u89c8",close:"\u5173\u95ed",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5e94\u7528",edit_confirm:"\u662f\u5426\u5728\u8be5text area\u5185\u542f\u7528\u6240\u89c1\u5373\u6240\u5f97\u6a21\u5f0f\uff1f"},contextmenu:{full:"\u4e24\u7aef\u5bf9\u9f50",right:"\u53f3\u5bf9\u9f50",center:"\u5c45\u4e2d",left:"\u5de6\u5bf9\u9f50",align:"\u5bf9\u9f50\u65b9\u5f0f"},insertdatetime:{day_short:"\u5468\u65e5,\u5468\u4e00,\u5468\u4e8c,\u5468\u4e09,\u5468\u56db,\u5468\u4e94,\u5468\u516d,\u5468\u65e5",day_long:"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u4e09,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5",months_short:"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708",months_long:"\u4e00\u6708,\u4e8c\u6708,\u4e09\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u73b0\u5728\u65f6\u95f4",insertdate_desc:"\u63d2\u5165\u4eca\u5929\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u6253\u5370"},preview:{preview_desc:"\u9884\u89c8"},directionality:{rtl_desc:"\u6587\u5b57\u4ece\u53f3\u5230\u5de6",ltr_desc:"\u6587\u5b57\u4ece\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u589e\u5c42...",absolute_desc:"\u7edd\u5bf9\u4f4d\u7f6e",backward_desc:"\u540e\u7f6e",forward_desc:"\u524d\u7f6e",insertlayer_desc:"\u63d2\u5165\u5c42"},save:{save_desc:"\u4fdd\u5b58",cancel_desc:"\u653e\u5f03\u6240\u6709\u66f4\u6539"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u683c\u7b26"},iespell:{download:"\u672a\u68c0\u6d4b\u5230ieSpell\u7ec4\u4ef6\uff0c\u662f\u5426\u73b0\u5728\u5b89\u88c5 ?",iespell_desc:"\u6267\u884c\u62fc\u5199\u68c0\u67e5"},advhr:{advhr_desc:"\u5206\u9694\u7ebf",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u8868\u60c5",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u67e5\u627e/\u66ff\u6362",search_desc:"\u67e5\u627e",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7f16\u8f91 \u56fe\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7f16\u8f91 \u8fde\u7ed3",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u63d2\u5165/\u7f16\u8f91 \u5c5e\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u5220\u9664",acronym_desc:"\u9996\u5b57\u6bcd\u7f29\u5199",abbr_desc:"\u7f29\u5199",cite_desc:"\u5f15\u7528",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7f16\u8f91 CSS \u6837\u5f0f\u8868",delta_height:"",delta_width:""},paste:{selectall_desc:"\u5168\u9009",paste_word_desc:"\u7c98\u8d34\u4e3aWord\u683c\u5f0f",paste_text_desc:"\u7c98\u8d34\u4e3a\u7eaf\u6587\u5b57",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u5c06\u590d\u5236(CTRL + C)\u7684\u5185\u5bb9\u7c98\u8d34(CTRL + V)\u5230\u7a97\u53e3\u3002",text_linebreaks:"\u4fdd\u7559\u5206\u884c\u7b26\u53f7\u53f7",text_title:"\u5c06\u590d\u5236(CTRL + C)\u7684\u5185\u5bb9\u7c98\u8d34(CTRL + V)\u5230\u7a97\u53e3\u3002"},table:{cell:"\u50a8\u5b58\u683c",col:"\u5217",row:"\u884c",del:"\u5220\u9664\u8868\u683c",copy_row_desc:"\u590d\u5236\u5f53\u524d\u5217",cut_row_desc:"\u526a\u5207\u5f53\u524d\u5217",paste_row_after_desc:"\u7c98\u8d34\u884c\u5230\u4e0b\u65b9",paste_row_before_desc:"\u7c98\u8d34\u884c\u5230\u4e0a\u65b9",props_desc:"\u8868\u683c \u5c5e\u6027",cell_desc:"\u50a8\u5b58\u683c \u5c5e\u6027",row_desc:"\u5217 \u5c5e\u6027",merge_cells_desc:"\u5408\u5e76\u50a8\u5b58\u683c",split_cells_desc:"\u62c6\u5206\u50a8\u5b58\u683c",delete_col_desc:"\u5220\u9664\u5f53\u524d\u5217",col_after_desc:"\u5728\u53f3\u4fa7\u63d2\u5165\u5217",col_before_desc:"\u5728\u5de6\u4fa7\u63d2\u5165\u5217",delete_row_desc:"\u5220\u9664\u5f53\u524d\u884c",row_after_desc:"\u5728\u4e0b\u65b9\u63d2\u5165\u884c",row_before_desc:"\u5728\u4e0a\u65b9\u63d2\u5165\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u5982\u679c\u79bb\u5f00\u8be5\u9875\u5c06\u5bfc\u81f4\u6240\u6709\u4fee\u6539\u5168\u90e8\u4e22\u5931\u3002",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u5168\u5c4f\u6a21\u5f0f"},media:{edit:"\u7f16\u8f91 \u5a92\u4f53",desc:"\u63d2\u5165/\u7f16\u8f91 \u5a92\u4f53",delta_height:"",delta_width:""},fullpage:{desc:"\u6587\u4ef6",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9009\u5b9a\u7684\u8303\u672c"},visualchars:{desc:"\u663e\u793a\u63a7\u5236\u7b26\u53f7\u3002"},spellchecker:{desc:"\u62fc\u5199\u68c0\u67e5",menu:"\u62fc\u5199\u68c0\u67e5 \u8bbe\u7f6e",ignore_word:"\u5ffd\u7565",ignore_words:"\u5168\u90e8\u5ffd\u7565",langs:"\u8bed\u8a00\u6e05\u5355",wait:"\u8bf7\u7a0d\u5019...",sug:"\u5efa\u8bae\u8bcd",no_sug:"\u65e0\u62fc\u5199\u5efa\u8bae",no_mpell:"\u65e0\u62fc\u5199\u9519\u8bef"},pagebreak:{desc:"\u63d2\u5165\u5206\u9875\u7b26\u53f7"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/id.js0000644000175000017500000001174011526350525031504 0ustar frankiefrankietinyMCE.addI18n({id:{common:{more_colors:"More colors",invalid_data:"Error: nilai invalid, ditandai dengan dengan warna merah",popup_blocked:"Maaf, popup-blocker anda telah menonaktifkan jendela aplikasi yang menyediakan fungsionalitas. Nonaktifkan popup-blocker untuk sepenuhnya memanfaatkan alat ini.",clipboard_no_support:"Tidak didukung Browser, gunakan shortcut dari keyboard.",clipboard_msg:"Copy/Cut/Paste tidak tersedia pada Mozilla dan Firefox.\\nButuh info selengkapnya?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Gunakan mode WYSIWYG untuk textarea ini?"},contextmenu:{full:"Penuh",right:"Kanan",center:"Tengah",left:"Kiri",align:"Alignment"},insertdatetime:{day_short:"Min,Sen,Sel,Rab,Kam,Jum,Sab,Min",day_long:"Minggu,Senin,Selasa,Rabu,Kamis,Jumat,Sabtu,Minggu",months_short:"Jan,Feb,Mar,Apr,Mei,Jun,Jul,Ags,Sep,Okt,Nov,Des",months_long:"Januari,Februari,Maren,April,Mei,Juni,Juli,Agustus,September,Oktober,November,Desember",inserttime_desc:"sisipkan waktu",insertdate_desc:"sisipkan tanggal",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Cetak"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Arah kanan ke kiri",ltr_desc:"Arah kiri ke kanan"},layer:{content:"Layer baru...",absolute_desc:"Beralih posisi absolut",backward_desc:"Pindah ke belakang",forward_desc:"Pindah ke depan",insertlayer_desc:"sisipkan layer Baru"},save:{save_desc:"Simpan",cancel_desc:"Batalkan semua perubahan"},nonbreaking:{nonbreaking_desc:"sisipkan karakter non-breaking space"},iespell:{download:"ieSpell tidak terdeteksi. Instal sekarang?",iespell_desc:"Jalankan spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Cari/Ganti",search_desc:"Cari",delta_width:"",delta_height:""},advimage:{image_desc:"sisipkan/Ubah Gambar",delta_width:"",delta_height:""},advlink:{link_desc:"Sisipkan/Ubah link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Sisip/Ubah Atribut",ins_desc:"Penyisipan",del_desc:"Penghapusan",acronym_desc:"Akronim",abbr_desc:"Singkatan/Kependekan Kata",cite_desc:"Kutipan",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Ubah CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Gunakan CTRL+V pada keyboard untuk paste.",text_linebreaks:"Keep linebreaks",text_title:"Gunakan CTRL+V pada keyboard untuk paste."},table:{cell:"Cell",col:"Column",row:"Row",del:"Hapus Tabel",copy_row_desc:"Copy row tabel",cut_row_desc:"Cut row tabel",paste_row_after_desc:"Paste row tabel sesudah",paste_row_before_desc:"Paste row tabel sebelum",props_desc:"Properti tabel",cell_desc:"Properti cell tabel",row_desc:"Properti row tabel",merge_cells_desc:"Merge cell tabel",split_cells_desc:"Pisahkan cell tabel yang di-merge",delete_col_desc:"Hapus column",col_after_desc:"Sisipkan column setelah",col_before_desc:"Sisipkan column sebelum",delete_row_desc:"Hapus row",row_after_desc:"Sisipkan row sesudah",row_before_desc:"Sisipkan row sebelum",desc:"Sisipkan tabel baru",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Perubahan yang dilakukan akan hilang jika Anda pindah dari halaman ini.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Properti Dokumen",delta_width:"",delta_height:""},template:{desc:"Menyisipkan template standar isi"},visualchars:{desc:"Pengendalian visual karakter on/off"},spellchecker:{desc:"Toggle spellchecker",menu:"Pengaturan Spellchecker ",ignore_word:"Abaikan kata",ignore_words:"Abaikan semua",langs:"Bahasa",wait:"Harap tunggu...",sug:"Saran",no_sug:"Tidak ada saran",no_mpell:"Tidak ada misspellings ditemukan."},pagebreak:{desc:"Sisipkan page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/hr.js0000644000175000017500000001260411526350525031521 0ustar frankiefrankietinyMCE.addI18n({hr:{common:{more_colors:"Vi\u0161e boja",invalid_data:"Gre\u0161ka: Une\u0161ene su nevaljane vrijednosti, ozna\u010dene su crvenom bojom.",popup_blocked:"Oprostite, izgleda da je va\u0161 popup-blocker onemogu\u0107io prozor u sklopu ovog programa. Morate onemogu\u0107iti blokiranje popup prozora da bi u potpunosti iskoristili ovaj alat.",clipboard_no_support:"Trenuta\u010dno va\u0161 preglednik ne podr\u017eava ovu opciju, poku\u0161ajte koristiti tipkovni\u010dku kraticu.",clipboard_msg:"Kopiraj/Izre\u017ei/Zalijepi nije dostupno Mozilla i Firefox preglednicima.\\nVi\u0161e informacija?",not_set:"-- Nije postavljeno --",class_name:"Klasa",browse:"Pregled",close:"Zatvori",cancel:"Odustani",update:"Obnovi",insert:"Umetni",apply:"Primjeni",edit_confirm:"\u017delite li koristiti WYSIWYG na\u010din rada za ovo tekstualno polje?"},contextmenu:{full:"Puno",right:"Desno",center:"Sredina",left:"Lijevo",align:"Poravnavanje"},insertdatetime:{day_short:"ned,pon,uto,sri,\u010det,pet,sub,ned",day_long:"nedjelja,ponedjeljak,utorak,srijeda,\u010detvrtak,petak,subota,nedjelja",months_short:"sij,velj,o\u017eu,tra,svi,lip,srp,kol,ruj,lis,stu,pro",months_long:"sije\u010danj,velja\u010da,o\u017eujak,travanj,svibanj,lipanj,srpanj,kolovoz,rujan,listopad,studeni,prosinac",inserttime_desc:"Umetni vrijeme",insertdate_desc:"Umetni datum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y."},print:{print_desc:"Ispis"},preview:{preview_desc:"Prikaz"},directionality:{rtl_desc:"S desna na lijevo",ltr_desc:"S lijeva na desno"},layer:{content:"Novi sloj...",absolute_desc:"Uklju\u010di/isklju\u010di apsolutno pozicioniranje",backward_desc:"Pomakni natrag",forward_desc:"Pomakni naprijed",insertlayer_desc:"Umetni novi sloj"},save:{save_desc:"Spremi",cancel_desc:"Odustani od svih promjena"},nonbreaking:{nonbreaking_desc:"Umetni razmak"},iespell:{download:"Provjera pravopisa nije postaljena. Postaviti sada?",iespell_desc:"Pokreni provjeru pravopisa"},advhr:{advhr_desc:"Vodoravna crta",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emocije",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Prona\u0111i/Zamijeni",search_desc:"Prona\u0111i",delta_width:"",delta_height:""},advimage:{image_desc:"Umetni/uredi sliku",delta_width:"",delta_height:""},advlink:{delta_width:"100",link_desc:"Insert/edit link",delta_height:""},xhtmlxtras:{attribs_desc:"Umetni/uredi atribute",ins_desc:"Unos",del_desc:"Brisanje",acronym_desc:"Akronim",abbr_desc:"Kratica",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Uredi CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Odaberi sve",paste_word_desc:"Zalijepi iz Worda",paste_text_desc:"Zalijepi kao obi\u010dni tekst"},paste_dlg:{word_title:"Koristite CTRL+V na tipkovnici da zalijepite tekst u prozor.",text_linebreaks:"Zadr\u017ei prijelome",text_title:"Koristite CTRL+V na tipkovnici da zalijepite tekst u prozor."},table:{cell:"\u0106elija",col:"Stupac",row:"Redak",del:"Izbri\u0161i tablicu",copy_row_desc:"Kopiraj redak",cut_row_desc:"Izre\u017ei redak",paste_row_after_desc:"Zalijepi redak ispod",paste_row_before_desc:"Zalijepi redak iznad",props_desc:"Svojstva tablice",cell_desc:"Svojstva \u0107elije",row_desc:"Svojstva retka",merge_cells_desc:"Spoji \u0107elije",split_cells_desc:"Razdvoji spojene \u0107elije",delete_col_desc:"Ukloni stupac",col_after_desc:"Umetni stupac desno",col_before_desc:"Umetni stupac lijevo",delete_row_desc:"Izbri\u0161i redak",row_after_desc:"Umetni redak ispod",row_before_desc:"Umetni redak iznad",desc:"Nova tablica",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"Promjene u dokumentu \u0107e biti izgubljene ako iza\u0111ete s ove stranice."},fullscreen:{desc:"Uklju\u010di/isklju\u010di prikaz preko cijelog ekrana"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Svojstva dokumenta",delta_width:"",delta_height:""},template:{desc:"Umetni sadr\u017eaj iz predlo\u017eak"},visualchars:{desc:"Vizualni kontrolni znakovi uklju\u010deni/isklju\u010deni."},spellchecker:{desc:"Uklju\u010di/isklju\u010di provjeru pravopisa",menu:"Postavke provjere pravopisa",ignore_word:"Zanemari rije\u010d",ignore_words:"Zanemari sver",langs:"Jezici",wait:"Pri\u010dekajte...",sug:"Prijedlozi",no_sug:"Nema prijedloga",no_mpell:"Nije prona\u0111ena nijedna pravopisna gre\u0161ke."},pagebreak:{desc:"Umetni prijelom."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/hu.js0000644000175000017500000001502511526350525031524 0ustar frankiefrankietinyMCE.addI18n({hu:{common:{more_colors:"T\u00f6bb sz\u00edn",invalid_data:"Hiba: \u00c9rv\u00e9nytelen adatok, pirossal jel\u00f6lve.",popup_blocked:"A felugr\u00f3 ablakok tilt\u00e1sa miatt nem siker\u00fclt megjelen\u00edteni egy, az alkalmaz\u00e1shoz sz\u00fcks\u00e9ges ablakot. Enged\u00e9lyezze a b\u00f6ng\u00e9sz\u0151j\u00e9ben a felugr\u00f3 ablakokat, hogy minden funkci\u00f3t haszn\u00e1lhasson.",clipboard_no_support:"Jelenleg nem t\u00e1mogatja a b\u00f6ng\u00e9sz\u0151je, haszn\u00e1lja a billenty\u0171kombin\u00e1ci\u00f3kat helyette.",clipboard_msg:"A M\u00e1sol\u00e1s/Kiv\u00e1g\u00e1s/Besz\u00far\u00e1s funkci\u00f3k nem \u00e9rhet\u0151ek el Mozilla \u00e9s Firefox alatt.\\nK\u00edv\u00e1n t\u00f6bbet tudni err\u0151l a t\u00e9m\u00e1r\u00f3l?",not_set:"-- Nincs megadva --",class_name:"Oszt\u00e1ly",browse:"Tall\u00f3z\u00e1s",close:"Bez\u00e1r\u00e1s",cancel:"M\u00e9gsem",update:"Friss\u00edt\u00e9s",insert:"Besz\u00far\u00e1s",apply:"Alkalmaz\u00e1s",edit_confirm:"Haszn\u00e1lni k\u00edv\u00e1nja a sz\u00f6vegszerkeszt\u0151 m\u00f3dot ebben a sz\u00f6vegdobozban?"},contextmenu:{full:"Sorkiz\u00e1r\u00e1s",right:"Jobbra",center:"K\u00f6z\u00e9pre",left:"Balra",align:"Igaz\u00edt\u00e1s"},insertdatetime:{day_short:"V,H,K,Sze,Cs,P,Szo,V",day_long:"vas\u00e1rnap,h\u00e9tf\u0151,kedd,szerda,cs\u00fct\u00f6rt\u00f6k,p\u00e9ntek,szombat,vas\u00e1rnap",months_short:"jan,feb,m\u00e1r,\u00e1pr,m\u00e1j,j\u00fan,j\u00fal,aug,szept,okt,nov,dec",months_long:"janu\u00e1r,febru\u00e1r,m\u00e1rcius,\u00e1prilis,m\u00e1jus,j\u00fanius,j\u00falius,augusztus,szeptember,okt\u00f3ber,november,december",inserttime_desc:"Id\u0151 besz\u00far\u00e1sa",insertdate_desc:"D\u00e1tum besz\u00far\u00e1sa",time_fmt:"%H:%M:%S",date_fmt:"%Y.%m.%d."},print:{print_desc:"Nyomtat\u00e1s"},preview:{preview_desc:"El\u0151n\u00e9zet"},directionality:{rtl_desc:"Jobbr\u00f3l balra",ltr_desc:"Balr\u00f3l jobbra"},layer:{content:"\u00daj r\u00e9teg...",absolute_desc:"Abszol\u00fat poz\u00edci\u00f3 ki-/bekapcsol\u00e1sa",backward_desc:"Mozgat\u00e1s h\u00e1tra",forward_desc:"Mozgat\u00e1s el\u0151re",insertlayer_desc:"\u00daj r\u00e9teg besz\u00far\u00e1sa"},save:{save_desc:"Ment\u00e9s",cancel_desc:"\u00d6sszes v\u00e1ltoz\u00e1s visszavon\u00e1sa"},nonbreaking:{nonbreaking_desc:"Nemsort\u00f6r\u0151 sz\u00f3k\u00f6z besz\u00far\u00e1sa"},iespell:{download:"ieSpell nem tal\u00e1lhat\u00f3. Telep\u00edti most?",iespell_desc:"Helyes\u00edr\u00e1s-ellen\u0151rz\u00e9s futtat\u00e1sa"},advhr:{advhr_desc:"V\u00edzszintes vonal",delta_height:"",delta_width:""},emotions:{emotions_desc:"Hangulatjelek",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Keres\u00e9s/Csere",search_desc:"Keres\u00e9s",delta_width:"",delta_height:""},advimage:{image_desc:"K\u00e9p besz\u00far\u00e1sa/szerkeszt\u00e9se",delta_width:"",delta_height:""},advlink:{link_desc:"Link besz\u00far\u00e1sa/szerkeszt\u00e9s",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Tulajdons\u00e1gok besz\u00far\u00e1sa/szerkeszt\u00e9se",ins_desc:"Besz\u00fart",del_desc:"T\u00f6r\u00f6lt",acronym_desc:"Bet\u0171sz\u00f3",abbr_desc:"R\u00f6vid\u00edt\u00e9s",cite_desc:"Id\u00e9zet",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS st\u00edlus szerkeszt\u00e9se",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Mindent kijel\u00f6l",paste_word_desc:"Besz\u00far\u00e1s Wordb\u0151l",paste_text_desc:"Besz\u00far\u00e1s sz\u00f6vegk\u00e9nt"},paste_dlg:{word_title:"Haszn\u00e1lja a Ctrl+V-t a billenty\u0171zet\u00e9n a beilleszt\u00e9shez.",text_linebreaks:"Sort\u00f6r\u00e9sek megtart\u00e1sa",text_title:"Haszn\u00e1lja a Ctrl+V-t a billenty\u0171zet\u00e9n a beilleszt\u00e9shez."},table:{cell:"Cella",col:"Oszlop",row:"Sor",del:"T\u00e1bl\u00e1zat t\u00f6rl\u00e9se",copy_row_desc:"Sor m\u00e1sol\u00e1sa",cut_row_desc:"Sor kiv\u00e1g\u00e1sa",paste_row_after_desc:"Sor bem\u00e1sol\u00e1sa ut\u00e1na",paste_row_before_desc:"Sor bem\u00e1sol\u00e1sa el\u00e9",props_desc:"T\u00e1bl\u00e1zat tulajdons\u00e1gai",cell_desc:"Cella tulajdons\u00e1gai",row_desc:"Sor tulajdons\u00e1gai",merge_cells_desc:"Cell\u00e1k \u00f6sszevon\u00e1sa",split_cells_desc:"Cell\u00e1k feloszt\u00e1sa",delete_col_desc:"Oszlop t\u00f6rl\u00e9se",col_after_desc:"Oszlop besz\u00far\u00e1sa ut\u00e1na",col_before_desc:"Oszlop besz\u00far\u00e1sa el\u00e9",delete_row_desc:"Sor t\u00f6rl\u00e9se",row_after_desc:"Sor besz\u00far\u00e1sa ut\u00e1na",row_before_desc:"Sor besz\u00far\u00e1sa el\u00e9",desc:"T\u00e1bl\u00e1zat besz\u00far\u00e1sa/szerkeszt\u00e9se",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"A m\u00f3dos\u00edt\u00e1sok nem lesznek mentve, ha elhagyja az oldalt."},fullscreen:{desc:"Teljesk\u00e9perny\u0151s m\u00f3d ki-/bekapcsol\u00e1sa"},media:{edit:"Be\u00e1gyazott m\u00e9dia szerkeszt\u00e9se",desc:"Be\u00e1gyazott m\u00e9dia besz\u00far\u00e1sa/szerkeszt\u00e9se",delta_height:"",delta_width:""},fullpage:{desc:"Dokumentum tulajdons\u00e1gai",delta_width:"",delta_height:""},template:{desc:"Sablon beilleszt\u00e9se"},visualchars:{desc:"Vizu\u00e1lis vez\u00e9rl\u0151karakterek be/ki."},spellchecker:{desc:"Helyes\u00edr\u00e1s-ellen\u0151rz\u0151 ki-/bekapcsol\u00e1sa",menu:"Helyes\u00edr\u00e1s-ellen\u0151rz\u0151 tulajdons\u00e1gai",ignore_word:"Sz\u00f3 kihagy\u00e1sa",ignore_words:"Mindet kihagy",langs:"Nyelvek",wait:"K\u00e9rem, v\u00e1rjon...",sug:"Aj\u00e1nl\u00e1sok",no_sug:"Nincs aj\u00e1nl\u00e1s",no_mpell:"Nem tal\u00e1ltam helyes\u00edr\u00e1si hib\u00e1t."},pagebreak:{desc:"Oldalt\u00f6r\u00e9s besz\u00far\u00e1sa."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"K\u00f6r",disc:"Lemez",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ja.js0000644000175000017500000001717311526350525031510 0ustar frankiefrankietinyMCE.addI18n({ja:{common:{more_colors:"\u305d\u306e\u4ed6\u306e\u8272",invalid_data:"\u30a8\u30e9\u30fc: \u5165\u529b\u306b\u8aa4\u308a\u304c\u3042\u308a\u307e\u3059\u3002\uff08\u8d64\u5b57\u306e\u9805\u76ee\uff09",popup_blocked:"\u30dd\u30c3\u30d7\u30a2\u30c3\u30d7\u304c\u30d6\u30ed\u30c3\u30af\u3055\u308c\u307e\u3057\u305f\u3002\u3059\u3079\u3066\u306e\u6a5f\u80fd\u3092\u3054\u5229\u7528\u306b\u306a\u308b\u306b\u306f\u30dd\u30c3\u30d7\u30a2\u30c3\u30d7\u3092\u8a31\u53ef\u3057\u3066\u4e0b\u3055\u3044\u3002",clipboard_no_support:"\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u64cd\u4f5c\u306f\u304a\u4f7f\u3044\u306e\u30d6\u30e9\u30a6\u30b6\u306b\u306f\u5bfe\u5fdc\u3057\u3066\u304a\u308a\u307e\u305b\u3093\u3002\u4ee3\u308f\u308a\u306b\u30ad\u30fc\u30dc\u30fc\u30c9\u306e\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\u30ad\u30fc\u3092\u304a\u4f7f\u3044\u4e0b\u3055\u3044\u3002",clipboard_msg:"\u3053\u306e\u30b3\u30de\u30f3\u30c9\u306fFirefox\u3067\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\u3002",not_set:"-- \u672a\u8a2d\u5b9a --",class_name:"class\u5c5e\u6027",browse:"\u53c2\u7167",close:"\u9589\u3058\u308b",cancel:"\u30ad\u30e3\u30f3\u30bb\u30eb",update:"\u66f4\u65b0",insert:"\u633f\u5165",apply:"\u9069\u7528",edit_confirm:"WYSIWYG\u30e2\u30fc\u30c9\u306b\u5207\u308a\u66ff\u3048\u307e\u3059\u304b\uff1f"},contextmenu:{full:"\u5747\u7b49\u5272\u4ed8",right:"\u53f3\u63c3\u3048",center:"\u4e2d\u592e\u63c3\u3048",left:"\u5de6\u63c3\u3048",align:"\u914d\u7f6e"},insertdatetime:{day_short:"(\u65e5),(\u6708),(\u706b),(\u6c34),(\u6728),(\u91d1),(\u571f),(\u65e5)",day_long:"\u65e5\u66dc\u65e5,\u6708\u66dc\u65e5,\u706b\u66dc\u65e5,\u6c34\u66dc\u65e5,\u6728\u66dc\u65e5,\u91d1\u66dc\u65e5,\u571f\u66dc\u65e5,\u65e5\u66dc\u65e5",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"\u6642\u523b\u306e\u633f\u5165",insertdate_desc:"\u65e5\u4ed8\u306e\u633f\u5165",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u5370\u5237"},preview:{preview_desc:"\u30d7\u30ec\u30d3\u30e5\u30fc"},directionality:{rtl_desc:"\u53f3\u304b\u3089\u5de6",ltr_desc:"\u5de6\u304b\u3089\u53f3"},layer:{content:"\u65b0\u898f\u30ec\u30a4\u30e4\u30fc",absolute_desc:"\u7d76\u5bfe\u4f4d\u7f6e\u6307\u5b9a\u306e\u5207\u66ff",backward_desc:"\u80cc\u9762\u3078\u79fb\u52d5",forward_desc:"\u524d\u9762\u3078\u79fb\u52d5",insertlayer_desc:"\u65b0\u898f\u30ec\u30a4\u30e4\u30fc\u306e\u633f\u5165"},save:{save_desc:"\u4fdd\u5b58",cancel_desc:"\u5168\u3066\u306e\u5909\u66f4\u3092\u7834\u68c4"},nonbreaking:{nonbreaking_desc:"\u6539\u884c\u306a\u3057\u30b9\u30da\u30fc\u30b9\u306e\u633f\u5165"},iespell:{download:"ieSpell\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u4eca\u3059\u3050\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059\u304b\uff1f",iespell_desc:"\u30b9\u30da\u30eb\u30c1\u30a7\u30c3\u30af"},advhr:{advhr_desc:"\u6c34\u5e73\u7dda",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u8868\u60c5\u30a2\u30a4\u30b3\u30f3",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u691c\u7d22/\u7f6e\u63db",search_desc:"\u691c\u7d22",delta_width:"",delta_height:""},advimage:{image_desc:"\u753b\u50cf\u306e\u633f\u5165/\u7de8\u96c6",delta_width:"",delta_height:""},advlink:{link_desc:"\u30ea\u30f3\u30af\u306e\u633f\u5165/\u7de8\u96c6",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u5c5e\u6027\u306e\u633f\u5165/\u7de8\u96c6",ins_desc:"\u633f\u5165",del_desc:"\u524a\u9664",acronym_desc:"\u982d\u5b57\u8a9e",abbr_desc:"\u7565\u8a9e",cite_desc:"\u5f15\u7528",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS\u7de8\u96c6",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8\u30e2\u30fc\u30c9\u306b\u5909\u66f4\u3057\u307e\u3057\u305f\u3002\u8cbc\u308a\u4ed8\u3051\u5f8c\u306f\u66f8\u5f0f\u4ed8\u304d\u30e2\u30fc\u30c9\u306b\u623b\u308a\u307e\u3059\u3002",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"\u5168\u3066\u9078\u629e",paste_word_desc:"Word\u304b\u3089\u8cbc\u308a\u4ed8\u3051",paste_text_desc:"\u30c6\u30ad\u30b9\u30c8\u3068\u3057\u3066\u8cbc\u308a\u4ed8\u3051"},paste_dlg:{word_title:"\u30ad\u30fc\u30dc\u30fc\u30c9\u3067CTRL+V\u3092\u62bc\u3057\u3066\u30c6\u30ad\u30b9\u30c8\u3092\u8cbc\u308a\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002",text_linebreaks:"\u6539\u884c\u3092\u4fdd\u6301\u3059\u308b",text_title:"\u30ad\u30fc\u30dc\u30fc\u30c9\u3067CTRL+V\u3092\u62bc\u3057\u3066\u30c6\u30ad\u30b9\u30c8\u3092\u8cbc\u308a\u4ed8\u3051\u3066\u304f\u3060\u3055\u3044\u3002"},table:{cell:"\u30bb\u30eb",col:"\u5217",row:"\u884c",del:"\u8868\u3092\u524a\u9664",copy_row_desc:"\u884c\u306e\u30b3\u30d4\u30fc",cut_row_desc:"\u884c\u306e\u5207\u308a\u53d6\u308a",paste_row_after_desc:"\u884c\u3092\u4e0b\u306b\u8cbc\u308a\u4ed8\u3051",paste_row_before_desc:"\u884c\u3092\u4e0a\u306b\u8cbc\u308a\u4ed8\u3051",props_desc:"\u8868\u306e\u30d7\u30ed\u30d1\u30c6\u30a3",cell_desc:"\u30bb\u30eb\u306e\u30d7\u30ed\u30d1\u30c6\u30a3",row_desc:"\u884c\u306e\u30d7\u30ed\u30d1\u30c6\u30a3",merge_cells_desc:"\u30bb\u30eb\u3092\u7d50\u5408",split_cells_desc:"\u30bb\u30eb\u306e\u7d50\u5408\u3092\u89e3\u9664",delete_col_desc:"\u5217\u3092\u524a\u9664",col_after_desc:"\u5217\u3092\u53f3\u306b\u633f\u5165",col_before_desc:"\u5217\u3092\u5de6\u306b\u633f\u5165",delete_row_desc:"\u884c\u3092\u524a\u9664",row_after_desc:"\u884c\u3092\u4e0b\u306b\u633f\u5165",row_before_desc:"\u884c\u3092\u4e0a\u306b\u633f\u5165",desc:"\u8868\u3092\u633f\u5165",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"\u4ed6\u306e\u30da\u30fc\u30b8\u3078\u79fb\u52d5\u3059\u308b\u3068\u7de8\u96c6\u30c7\u30fc\u30bf\u306f\u3059\u3079\u3066\u7834\u68c4\u3055\u308c\u307e\u3059\u3002"},fullscreen:{desc:"\u30d5\u30eb\u30b9\u30af\u30ea\u30fc\u30f3"},media:{edit:"\u57cb\u3081\u8fbc\u307f\u30e1\u30c7\u30a3\u30a2\u306e\u7de8\u96c6",desc:"\u57cb\u3081\u8fbc\u307f\u30e1\u30c7\u30a3\u30a2\u306e\u633f\u5165/\u7de8\u96c6",delta_height:"",delta_width:""},fullpage:{desc:"\u30da\u30fc\u30b8\u8a2d\u5b9a",delta_width:"",delta_height:""},template:{desc:"\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u306e\u633f\u5165"},visualchars:{desc:"\u5236\u5fa1\u6587\u5b57\u306e\u8868\u793a"},spellchecker:{desc:"\u30b9\u30da\u30eb\u30c1\u30a7\u30c3\u30afOn/Off",menu:"\u30b9\u30da\u30eb\u30c1\u30a7\u30c3\u30af\u8a2d\u5b9a",ignore_word:"\u3053\u306e\u5358\u8a9e\u3092\u7121\u8996",ignore_words:"\u5168\u3066\u7121\u8996",langs:"\u8a00\u8a9e",wait:"\u3057\u3070\u3089\u304f\u304a\u5f85\u3061\u304f\u3060\u3055\u3044...",sug:"\u5019\u88dc",no_sug:"\u5019\u88dc\u306f\u6709\u308a\u307e\u305b\u3093\u3002",no_mpell:"\u30b9\u30da\u30eb\u30df\u30b9\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002"},pagebreak:{desc:"\u6539\u30da\u30fc\u30b8\u633f\u5165"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/hy.js0000644000175000017500000003302311526350525031526 0ustar frankiefrankietinyMCE.addI18n({hy:{common:{more_colors:"\u0547\u0561\u057f \u0563\u0578\u0582\u0575\u0576\u0565\u0580",invalid_data:"\u054d\u056d\u0561\u056c: \u0546\u0565\u0580\u0561\u056e\u057e\u0561\u056e \u0567 \u057d\u056d\u0561\u056c \u0561\u0580\u056a\u0565\u0584, \u0563\u0578\u0582\u0576\u0561\u0576\u0577\u057e\u0561\u056e \u0567 \u056f\u0561\u0580\u0574\u056b\u0580\u0578\u057e",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool",clipboard_no_support:"\u054f\u057e\u0575\u0561\u056c \u057a\u0561\u0570\u056b\u0576 \u0579\u056b \u0568\u0576\u0564\u0578\u0582\u0576\u057e\u0578\u0582\u0574 \u0541\u0565\u0580 \u0562\u0580\u0561\u0578\u0582\u0566\u0565\u0580\u056b \u056f\u0578\u0572\u0574\u056b\u0581, \u0585\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u0584 \u0570\u0561\u057a\u0561\u057e\u0578\u0582\u0574\u0576\u0565\u0580",clipboard_msg:"\u054a\u0561\u057f\u0573\u0565\u0576\u0565\u056c / \u053f\u057f\u0580\u0565\u056c / \u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c (\u0574\u0561\u057f\u0579\u0565\u056c\u056b \u0579\u0567 Mozilla \u0587 Firefox \u0562\u0580\u0561\u0578\u0582\u0566\u0565\u0580\u0576\u0565\u0580\u0578\u0582\u0574) \\ n \u0541\u0565\u0566 \u0570\u0565\u057f\u0561\u0584\u0580\u0584\u056b\u055e\u0580 \u0567 \u0561\u0575\u0564 \u056b\u0576\u0586\u0578\u0580\u0574\u0561\u0581\u056b\u0561\u0576",not_set:"- \u0568\u0576\u057f\u0580\u0565\u056c -",class_name:"\u0534\u0561\u057d",browse:"\u0534\u056b\u057f\u0565\u056c",close:"\u0553\u0561\u056f\u0565\u056c",cancel:"\u0549\u0565\u0572\u0575\u0561\u056c",update:"\u0539\u0561\u0580\u0574\u0561\u0581\u0576\u0565\u056c",insert:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c",apply:"\u0540\u0561\u057d\u057f\u0561\u057f\u0565\u056c",edit_confirm:"\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WYSIWYG \u0440\u0435\u0436\u0438\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f?"},contextmenu:{full:"\u0538\u057d\u057f \u056c\u0561\u0575\u0576\u0578\u0582\u0569\u0575\u0561\u0576",right:"\u0538\u057d\u057f \u0561\u057b \u0565\u0566\u0580\u056b",center:"\u053f\u0565\u0576\u057f\u0580\u0578\u0576\u0561\u0581\u0576\u0565\u056c",left:"\u0538\u057d\u057f \u0571\u0561\u056d \u0565\u0566\u0580\u056b",align:"\u0540\u0561\u057e\u0561\u057d\u0561\u0580\u0565\u0581\u0578\u0582\u0574"},insertdatetime:{day_short:"\u053f\u056b\u0580, \u0535\u0580\u056f, \u0535\u0580\u0584, \u0549\u0580\u0584, \u0540\u0576\u0563, \u0548\u0582\u0580\u0562, \u0547\u0562\u0569, \u053f\u056b\u0580",day_long:"\u056f\u056b\u0580\u0561\u056f\u056b, \u0565\u0580\u056f\u0578\u0582\u0577\u0561\u0562\u0569\u056b, \u0565\u0580\u0565\u0584\u0577\u0561\u0562\u0569\u056b, \u0579\u0578\u0580\u0565\u0584\u0577\u0561\u0562\u0569\u056b, \u0570\u056b\u0576\u0563\u0577\u0561\u0562\u0569\u056b, \u0578\u0582\u0580\u0562\u0561\u0569, \u0577\u0561\u0562\u0561\u0569, \u056f\u056b\u0580\u0561\u056f\u056b",months_short:"\u0570\u0578\u0582\u0576, \u0583\u0565\u057f, \u0574\u0561\u0580\u057f, \u0561\u057a\u0580, \u0574\u0561\u0575\u056b\u057d, \u0570\u0578\u0582\u0576, \u0570\u0578\u0582\u056c, \u0585\u0563\u057d\u057f, \u057d\u0565\u057a\u057f, \u0570\u0578\u056f\u057f, \u0576\u0578\u0575, \u0564\u0565\u056f",months_long:"\u0570\u0578\u0582\u0576\u057e\u0561\u0580, \u0583\u0565\u057f\u0580\u057e\u0561\u0580, \u0574\u0561\u0580\u057f, \u0561\u057a\u0580\u056b\u056c, \u0574\u0561\u0575\u056b\u057d, \u0570\u0578\u0582\u0576\u056b\u057d, \u0570\u0578\u0582\u056c\u056b\u057d, \u0585\u0563\u0578\u057d\u057f\u0578\u057d, \u057d\u0565\u057a\u057f\u0565\u0574\u0562\u0565\u0580, \u0570\u0578\u056f\u057f\u0565\u0574\u0562\u0565\u0580, \u0576\u0578\u0575\u0565\u0574\u0562\u0565\u0580, \u0564\u0565\u056f\u057f\u0565\u0574\u0562\u0565\u0580",inserttime_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c \u056a\u0561\u0574\u0561\u0576\u0561\u056f",insertdate_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c \u0561\u0574\u057d\u0561\u0569\u056b\u057e",time_fmt:"% H:% M:% S",date_fmt:"% d.% m.% Y"},print:{print_desc:"\u054f\u057a\u0565\u056c"},preview:{preview_desc:"\u0534\u056b\u057f\u0565\u056c"},directionality:{rtl_desc:"\u0548\u0582\u0572\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568\u055d \u0561\u057b\u056b\u0581 \u0571\u0561\u056d",ltr_desc:"\u0548\u0582\u0572\u0572\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0568\u055d \u0571\u0561\u056d\u056b\u0581 \u0561\u057b"},layer:{content:"\u0546\u0578\u0580 \u0577\u0565\u0580\u057f ...",absolute_desc:"\u053f\u056b\u0580\u0561\u057c\u0565\u056c \u0562\u0561\u0581\u0561\u0580\u0571\u0561\u056f \u057f\u0565\u0572\u0561\u056f\u0561\u0575\u0578\u0582\u0574",backward_desc:"\u054f\u0565\u0572\u0561\u0583\u0578\u056d\u0565\u056c \u0565\u057f",forward_desc:"\u054e\u0565\u0580\u0587",insertlayer_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c \u0576\u0578\u0580 \u0577\u0565\u0580\u057f"},save:{save_desc:"\u054a\u0561\u0570\u057a\u0561\u0576\u0565\u056c",cancel_desc:"\u0549\u0565\u0572\u0561\u0580\u056f\u0565\u056c \u0562\u0561\u056c\u0561\u0580 \u0583\u0578\u0583\u0578\u056d\u0578\u0582\u0569\u0575\u0578\u0582\u0576\u0576\u0565\u0580\u0568"},nonbreaking:{nonbreaking_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c \u0562\u0561\u0581\u0561\u0580\u056f"},iespell:{download:"ieSpell \u057a\u056c\u0561\u0563\u056b\u0576\u0568 \u0579\u056b \u0563\u057f\u0576\u057e\u0565\u056c\u0589 \u0551\u0561\u0576\u056f\u0561\u0576\u0578\u0582\u055e\u0574 \u0565\u0584 \u057f\u0565\u0572\u0561\u0564\u0580\u0565\u056c",iespell_desc:"\u054f\u0561\u057c\u0561\u057d\u056d\u0561\u056c\u0576\u0565\u0580\u056b \u057d\u057f\u0578\u0582\u0563\u0578\u0582\u0574"},advhr:{advhr_desc:"\u0540\u0561\u0580\u056b\u0566\u0578\u0576\u0561\u056f\u0561\u0576 \u0562\u0561\u056a\u0561\u0576\u056b\u0579",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u054d\u0574\u0561\u0575\u056c\u056b\u056f\u0576\u0565\u0580",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0548\u0580\u0578\u0576\u0565\u056c / \u0553\u0578\u0583\u0578\u056d\u0565\u056c",search_desc:"\u0548\u0580\u0578\u0576\u0565\u056c",delta_width:"",delta_height:""},advimage:{delta_width:"200",image_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c / \u0583\u0578\u0583\u0578\u056d\u0565\u056c \u0576\u056f\u0561\u0580",delta_height:""},advlink:{delta_width:"200",link_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c / \u0583\u0578\u0583\u0578\u056d\u0565\u056c \u0570\u0572\u0578\u0582\u0574",delta_height:""},xhtmlxtras:{attribs_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c / \u0583\u0578\u0583\u0578\u056d\u0565\u056c \u0561\u057f\u0580\u056b\u0562\u0578\u0582\u057f\u0576\u0565\u0580\u0568",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u053d\u0574\u0562\u0561\u0563\u0580\u0565\u056c CSS \u0578\u0573\u0565\u0580\u0568",delta_height:"",delta_width:""},paste:{selectall_desc:"\u0538\u0576\u057f\u0580\u0565\u056c \u0562\u0578\u056c\u0578\u0580\u0568",paste_word_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c Word \u056e\u0580\u0561\u0563\u0580\u056b\u0581",paste_text_desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c \u0578\u0580\u057a\u0565\u057d \u057f\u0565\u0584\u057d\u057f",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u0555\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u0584 CTRL + V \u057a\u0561\u057f\u0573\u0565\u0576\u057e\u0561\u056e \u057f\u0565\u0584\u057d\u057f\u056b \u057f\u0565\u0572\u0561\u0564\u0580\u0574\u0561\u0576 \u0570\u0561\u0574\u0561\u0580",text_linebreaks:"\u054a\u0561\u0570\u057a\u0561\u0576\u0565\u056c \u057f\u0578\u0572\u0561\u0564\u0561\u0580\u0571\u0565\u0580\u0568",text_title:"\u0555\u0563\u057f\u0561\u0563\u0578\u0580\u056e\u0565\u0584 CTRL + V \u057a\u0561\u057f\u0573\u0565\u0576\u057e\u0561\u056e \u057f\u0565\u0584\u057d\u057f\u056b \u057f\u0565\u0572\u0561\u0564\u0580\u0574\u0561\u0576 \u0570\u0561\u0574\u0561\u0580"},table:{cellprops_delta_width:"30",cell:"\u042f\u0447\u0435\u0439\u043a\u0430",col:"\u041f\u043e\u043b\u0435",row:"\u0421\u0442\u0440\u043e\u043a\u0430",del:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443",copy_row_desc:"\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",cut_row_desc:"\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",paste_row_after_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0441\u043b\u0435",paste_row_before_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0434\u043e",props_desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",cell_desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u044f\u0447\u0435\u0439\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",row_desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",merge_cells_desc:"\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438",split_cells_desc:"\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438",delete_col_desc:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446",col_after_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u043f\u043e\u0441\u043b\u0435",col_before_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0434\u043e",delete_row_desc:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",row_after_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0441\u043b\u0435",row_before_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0434\u043e",desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c \u0576\u0578\u0580 \u0561\u0572\u0575\u0578\u0582\u057d\u0561\u056f",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438, \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0442\u0435\u0440\u044f\u043d\u044b, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442\u0435 \u0441 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d"},media:{edit:"\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c embedded media",desc:"\u054f\u0565\u0572\u0561\u0564\u0580\u0565\u056c / \u0583\u0578\u0583\u0578\u056d\u0565\u056c \u0574\u0565\u0564\u056b\u0561",delta_height:"",delta_width:""},fullpage:{desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",delta_width:"",delta_height:""},template:{desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442"},visualchars:{desc:"Visual control characters on / off"},spellchecker:{desc:"\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443",menu:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438",ignore_word:"\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u043e",ignore_words:"\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435",langs:"\u042f\u0437\u044b\u043a\u0438",wait:"\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435 ...",sug:"\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b",no_sug:"\u041d\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432",no_mpell:"\u041e\u0448\u0438\u0431\u043e\u043a \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e"},pagebreak:{desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/is.js0000644000175000017500000001443011526350525031522 0ustar frankiefrankietinyMCE.addI18n({is:{common:{more_colors:"Fleiri litir",invalid_data:"Villa: Vitlaus gildi slegin inn, \u00feau eru merkt me\u00f0 rau\u00f0u.",popup_blocked:"Afsaki\u00f0, uppsprettuv\u00f6rnin \u00fe\u00edn (popup blocker) hefur loka\u00f0 \u00e1 glugga sem er hluti af ritlinum. \u00de\u00fa ver\u00f0ur a\u00f0 sl\u00f6kkva \u00e1 uppsprettuv\u00f6rn til a\u00f0 geta nota\u00f0 \u00feennan ritil.",clipboard_no_support:"Ekki stutt \u00ed \u00fe\u00ednum vefsko\u00f0ara, nota\u00f0ur fl\u00fdtilykla \u00ed sta\u00f0inn.",clipboard_msg:"Afrita/Klippa/L\u00edma er ekki a\u00f0gengilegt \u00ed Mozilla og Firefox eins og er.\\nViltu f\u00e1 n\u00e1nari uppl\u00fdsingar?",not_set:"-- Ekki skilgreint --",class_name:"Klasi",browse:"Gramsa",close:"Loka",cancel:"H\u00e6tta vi\u00f0",update:"Uppf\u00e6ra",insert:"Setja inn",apply:"Sta\u00f0festa",edit_confirm:"Viltu nota WYSIWYG ritil fyrir \u00feetta textasv\u00e6\u00f0i?"},contextmenu:{full:"Full",right:"H\u00e6gri",center:"Mi\u00f0ja",left:"Vinstri",align:"J\u00f6fnun"},insertdatetime:{day_short:"Sun,M\u00e1n,\u00deri,Mi\u00f0,Fim,F\u00f6s,Lau,Sun",day_long:"Sunnudagur,M\u00e1nudagur,\u00deri\u00f0judagur,Mi\u00f0vikudagur,Fimmtudagur,F\u00f6studagur,Laugardagur,Sunnudagur",months_short:"Jan,Feb,Mar,Apr,Ma\u00ed,J\u00fan,J\u00fal,\u00c1gs,Sep,Okt,N\u00f3v,Des",months_long:"Jan\u00faar,Febr\u00faar,Mars,Apr\u00edl,Ma\u00ed,J\u00fan\u00ed,J\u00fal\u00ed,\u00c1g\u00fast,September,Okt\u00f3ber,N\u00f3vember,Desember",inserttime_desc:"Setja inn t\u00edmasetningu",insertdate_desc:"Setja inn dagsetningu",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Prenta"},preview:{preview_desc:"Forsko\u00f0a"},directionality:{rtl_desc:"Fr\u00e1 h\u00e6gri til vinstri",ltr_desc:"Fr\u00e1 vinstri til h\u00e6gri"},layer:{content:"N\u00fdtt lag...",absolute_desc:"Taka af/setja \u00e1 algj\u00f6ra j\u00f6fnun",backward_desc:"F\u00e6ra afturfyrir",forward_desc:"F\u00e6ra framfyrir",insertlayer_desc:"Setja inn n\u00fdtt lag"},save:{save_desc:"Vista",cancel_desc:"H\u00e6tta vi\u00f0 allar breytingar"},nonbreaking:{nonbreaking_desc:"Setja inn bil staf"},iespell:{download:"ieSpell fannst ekki. Viltu setja \u00fea\u00f0 inn n\u00fana?",iespell_desc:"Lesa yfir"},advhr:{delta_height:"H\u00e6\u00f0",delta_width:"Breidd",advhr_desc:"L\u00e1r\u00e9tt l\u00edna"},emotions:{delta_height:"H\u00e6\u00f0",delta_width:"Breidd",emotions_desc:"Broskarlar"},searchreplace:{replace_desc:"Finna/Skipta \u00fat",delta_width:"Breidd",delta_height:"H\u00e6\u00f0",search_desc:"Finna"},advimage:{delta_width:"Breidd",image_desc:"Setja inn/breyta mynd",delta_height:"H\u00e6\u00f0"},advlink:{delta_height:"H\u00e6\u00f0",delta_width:"Breidd",link_desc:"Setja inn/breyta hlekk"},xhtmlxtras:{attribs_desc:"Skr\u00e1/breyta gildum",ins_desc:"Vi\u00f0b\u00f3t",del_desc:"Ey\u00f0a",acronym_desc:"Acronym",abbr_desc:"Skammst\u00f6fun",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{delta_height:"H\u00e6\u00f0",delta_width:"Breidd",desc:"Breyta st\u00edlsni\u00f0i"},paste:{plaintext_mode:"L\u00edma er n\u00fa \u00ed venjulegum textaham. Smelltu aftur til a\u00f0 skipta aftur \u00ed venjulegan ham",plaintext_mode_sticky:"L\u00edma er n\u00fa \u00ed venjulegum textaham. Smelltu aftur til a\u00f0 skipta yfir \u00ed venjulegan l\u00edma ham. Eftir a\u00f0 \u00fe\u00fa l\u00edmir eitthva\u00f0 f\u00e6rist \u00fe\u00fa sj\u00e1lfvirkt aftur \u00ed venjulegan ham.",selectall_desc:"Velja allt",paste_word_desc:"L\u00edma \u00far Word",paste_text_desc:"L\u00edma sem hreinn texti"},paste_dlg:{word_title:"Nota\u00f0u CTRL+V \u00e1 lyklabo\u00f0rinu til a\u00f0 l\u00edma textanum \u00ed ritilinn.",text_linebreaks:"Halda endingu l\u00edna",text_title:"Nota\u00f0u CTRL+V \u00e1 lyklabor\u00f0inu til a\u00f0 l\u00edma textanum \u00ed ritilinn."},table:{cell:"Reitur",col:"D\u00e1lkur",row:"R\u00f6\u00f0",del:"Ey\u00f0a t\u00f6flu",copy_row_desc:"Afrita r\u00f6\u00f0ina",cut_row_desc:"Klippa r\u00f6\u00f0ina",paste_row_after_desc:"L\u00edma t\u00f6flur\u00f6\u00f0 fyrir ne\u00f0an",paste_row_before_desc:"L\u00edma t\u00f6flur\u00f6\u00f0 fyrir ofan",props_desc:"Eiginleikar t\u00f6flu",cell_desc:"Eiginleikar d\u00e1lka",row_desc:"Eiginleikar ra\u00f0ar",merge_cells_desc:"Sameina t\u00f6flureiti",split_cells_desc:"Sundra sameinu\u00f0um t\u00f6flureitum",delete_col_desc:"Ey\u00f0a d\u00e1lk",col_after_desc:"Setja inn n\u00fdjan d\u00e1lk fyrir aftan",col_before_desc:"Setja inn n\u00fdjan d\u00e1lk fyrir framan",delete_row_desc:"Ey\u00f0a r\u00f6\u00f0",row_after_desc:"Setja inn n\u00fdja r\u00f6\u00f0 fyrir ne\u00f0an",row_before_desc:"Setja inn n\u00fdja r\u00f6\u00f0 fyrir ofan",desc:"Setja inn n\u00fdja t\u00f6flu",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Ef \u00fe\u00fa n\u00e6r\u00f0 \u00ed vistu\u00f0u g\u00f6gnin \u00fe\u00e1 missir \u00fe\u00fa allt innihald sem er n\u00fa \u00feegar \u00ed ritlinum.\\n\\nErtu viss um a\u00f0 \u00fe\u00fa viljir keyra vistu\u00f0u g\u00f6gnin yfir?",restore_content:"N\u00e1 \u00ed vistu\u00f0 g\u00f6gn",unload_msg:"Breytingar sem \u00fe\u00fa ger\u00f0ir hafa ekki veri\u00f0 vista\u00f0ar"},fullscreen:{desc:"Skipta \u00e1 milli heilskj\u00e1s"},media:{edit:"Breyta birtanlegri margmi\u00f0lun",desc:"Setja inn / Breyta birtingu margmi\u00f0lunar",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Setja inn tilb\u00fai\u00f0 sni\u00f0"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Virka/\u00f3virkja villup\u00faka",menu:"Stillingar villup\u00faka",ignore_word:"Sleppa or\u00f0i",ignore_words:"Sleppa \u00f6llu",langs:"Tungum\u00e1l",wait:"Augnablik...",sug:"Till\u00f6gur",no_sug:"Engar till\u00f6gur",no_mpell:"Fann engar stafsetningavillur."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/it.js0000644000175000017500000001303511526350525031523 0ustar frankiefrankietinyMCE.addI18n({it:{common:{more_colors:"Colori aggiuntivi",invalid_data:"Errore: valori inseriti non validi, sono marcati in rosso.",popup_blocked:"Spiacente, ma il blocco popup ha disabilitato una finestra che fornisce funzionalit\u00e0 dell\'applicazione. Si deve disabilitare il blocco popup per questo sito per poter utlizzare appieno questo strumento.",clipboard_no_support:"Attualmente non supportato dal browser in uso, usare le scorciatoie da tastiera.",clipboard_msg:"Copia/Taglia/Incolla non \u00e8 disponibile in Mozilla e Firefox.\\nSi desidera avere maggiori informazioni su questo problema?",not_set:"-- Non impostato --",class_name:"Classe",browse:"Sfoglia",close:"Chiudi",cancel:"Annulla",update:"Aggiorna",insert:"Inserisci",apply:"Applica",edit_confirm:"Usare la modalit\u00e0 WYSIWYG per questa textarea?"},contextmenu:{full:"Giustifica",right:"Allinea a destra",center:"Centra",left:"Allinea a sinistra",align:"Allineamento"},insertdatetime:{day_short:"Dom,Lun,Mar,Mer,Gio,Ven,Sab,Dom",day_long:"Domenica,Luned\u00ec,Marted\u00ec,Mercoled\u00ec,Gioved\u00ec,Venerd\u00ec,Sabato,Domenica",months_short:"Gen,Feb,Mar,Apr,Mag,Giu,Lug,Ago,Set,Ott,Nov,Dic",months_long:"Gennaio,Febbraio,Marzo,Aprile,Maggio,Giugno,Luglio,Agosto,Settembre,Ottobre,Novembre,Dicembre",inserttime_desc:"Inserisci ora",insertdate_desc:"Inserisci data",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Stampa"},preview:{preview_desc:"Anteprima"},directionality:{rtl_desc:"Direzione da destra a sinistra",ltr_desc:"Direzione da sinistra a destra"},layer:{content:"Nuovo layer...",absolute_desc:"Attiva/Disattiva posizionamento assoluto",backward_desc:"Porta in sfondo",forward_desc:"Porta in rilievo",insertlayer_desc:"Inserisci nuovo layer"},save:{save_desc:"Salva",cancel_desc:"Cancella tutte le modifiche"},nonbreaking:{nonbreaking_desc:"Inserisci uno spazio"},iespell:{download:"ieSpell non rilevato. Installarlo ora?",iespell_desc:"Esegui controllo ortografico"},advhr:{advhr_desc:"Riga orizzontale",delta_height:"",delta_width:""},emotions:{emotions_desc:"Faccine",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Trova/Sostituisci",search_desc:"Trova",delta_width:"",delta_height:""},advimage:{image_desc:"Inserisci/modifica immagine",delta_width:"",delta_height:""},advlink:{link_desc:"Inserisci/modifica collegamento",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Inserisci/modifica attributi",ins_desc:"Inserimento",del_desc:"Cancellamento",acronym_desc:"Acronimo",abbr_desc:"Abbreviazione",cite_desc:"Citazione",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Modifica stile CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Incolla adesso e in modalit\u00e0 testo. Clicca nuovamente per tornare alla modalit\u00e0 normale.",plaintext_mode_sticky:"Incolla adesso e in modalit\u00e0 testo. Clicca nuovamente per tornare alla modalit\u00e0 normale. Dopo che avrai incollato qualcosa tornerai alla modalit\u00e0 normale",selectall_desc:"Seleziona tutto",paste_word_desc:"Incolla da Word",paste_text_desc:"Incolla come testo semplice"},paste_dlg:{word_title:"Premere CTRL+V sulla tastiera per incollare il testo nella finestra.",text_linebreaks:"Mantieni interruzioni di riga",text_title:"Premere CTRL+V sulla tastiera per incollare il testo nella finestra."},table:{cell:"Cella",col:"Colonna",row:"Riga",del:"Elimina tabella",copy_row_desc:"Copia riga",cut_row_desc:"Taglia riga",paste_row_after_desc:"Incolla riga dopo",paste_row_before_desc:"Incolla riga prima",props_desc:"Propriet\u00e0 tabella",cell_desc:"Propriet\u00e0 cella",row_desc:"Propriet\u00e0 riga",merge_cells_desc:"Unisci celle",split_cells_desc:"Separa celle",delete_col_desc:"Elimina colonna",col_after_desc:"Inserisci colonna dopo",col_before_desc:"Inserisci colonna prima",delete_row_desc:"Elimina riga",row_after_desc:"Inserisci riga dopo",row_before_desc:"Inserisci riga prima",desc:"Inserisci una nuova tabella",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Se ripristini i dati salvati automaticamente perderai i dati attuali dell\'editor\\n\\nSei sicuro di voler ripristinare i dati?.",restore_content:"Ripristina i dati salvati automaticamente",unload_msg:"I cambiamenti effettuati saranno persi se si abbandona la pagina corrente."},fullscreen:{desc:"Attiva/disattiva modalit\u00e0 a tutto schermo"},media:{edit:"Modifica file multimediale",desc:"Inserisci/modifica file multimediale",delta_height:"",delta_width:""},fullpage:{desc:"Propriet\u00e0 Documento",delta_width:"",delta_height:""},template:{desc:"Inserisci contenuto da modello predefinito"},visualchars:{desc:"Attiva/disattiva caratteri di controllo visuale."},spellchecker:{desc:"Attiva/disattiva controllo ortografico",menu:"Impostazioni controllo ortografico",ignore_word:"Ignora parola",ignore_words:"Ignora tutto",langs:"Lingue",wait:"Attendere prego...",sug:"Suggerimenti",no_sug:"Nessun suggerimento",no_mpell:"Nessun errore rilevato."},pagebreak:{desc:"Inserisci intterruzione di pagina."},advlist:{types:"Tipi",def:"Default",lower_alpha:"Minuscolo alfanumerico",lower_greek:"Minuscolo lettera greca",lower_roman:"Minuscolo lettere romane",upper_alpha:"Maiuscolo alfanumerico",upper_roman:"Maiuscolo lettere romane",circle:"Cerchio",disc:"Punto",square:"Quadrato"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ka.js0000644000175000017500000003726611526350525031516 0ustar frankiefrankietinyMCE.addI18n({ka:{common:{more_colors:"\u10e1\u10ee\u10d5\u10d0 \u10e4\u10d4\u10e0\u10d4\u10d1\u10d8...",invalid_data:"\u10e8\u10d4\u10ea\u10d3\u10dd\u10db\u10d0: \u10e8\u10d4\u10e7\u10d5\u10d0\u10dc\u10d8\u10da\u10d8\u10d0 \u10d0\u10e0\u10d0 \u10e1\u10ec\u10dd\u10e0\u10d8 \u10db\u10dc\u10d8\u10e8\u10d5\u10dc\u10da\u10d4\u10dd\u10d1\u10d0, \u10d8\u10e1 \u10db\u10dd\u10dc\u10d8\u10e1\u10dc\u10e3\u10da\u10d8\u10d0 \u10ec\u10d8\u10d7\u10da\u10d0\u10d3.",popup_blocked:"\u0411\u043b\u043e\u043a\u0438\u0440\u0430\u0442\u043e\u0440 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u043e\u043a\u043e\u043d \u0437\u0430\u043a\u0440\u044b\u043b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u043e\u043a\u043d\u043e. \u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b, \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u0441\u0430\u0439\u0442\u0435.",clipboard_no_support:"\u10d0\u10e0 \u10d0\u10e5\u10d5\u10e1 \u10d7\u10e5\u10d5\u10d4\u10dc\u10d8 \u10d1\u10e0\u10d0\u10e3\u10d6\u10d4\u10e0\u10d8\u10e1 \u10db\u10ee\u10d0\u10e0\u10d3\u10d0\u10ed\u10d4\u10e0\u10d0. \u10d2\u10d0\u10db\u10dd\u10d8\u10e7\u10d4\u10dc\u10d4\u10d7 \u10d9\u10da\u10d0\u10d5\u10d8\u10d0\u10e2\u10e3\u10e0\u10e3\u10da\u10d8 \u10e8\u10d4\u10db\u10dd\u10d9\u10da\u10d4\u10d1\u10d4\u10d1\u10d8.",clipboard_msg:"\u10d9\u10dd\u10de\u10d8\u10e0\u10d4\u10d1\u10d0, \u10d0\u10db\u10dd\u10ed\u10e0\u10d0 \u10d3\u10d0 \u10e9\u10d0\u10e1\u10db\u10d0 Firefox-\u10e8\u10d8 \u10d0\u10e0 \u10db\u10e3\u10e8\u10d0\u10dd\u10d1\u10e1.\\r\\n\u10d2\u10e1\u10e3\u10e0\u10d7 \u10db\u10d8\u10d8\u10e6\u10dd\u10d7 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d8\u10d7\u10d8 \u10d8\u10dc\u10e4\u10dd\u10e0\u10db\u10d0\u10ea\u10d8\u10d0?",not_set:"- \u10d0\u10e0 \u10d0\u10e0\u10d8\u10e1 \u10d3\u10d0\u10e7\u10d4\u10dc\u10d4\u10d1\u10e3\u10da\u10d8 -",class_name:"\u10d9\u10da\u10d0\u10e1\u10d8",browse:"\u10d3\u10d0\u10d7\u10d5\u10d0\u10da\u10d8\u10d4\u10e0\u10d4\u10d1\u10d0",close:"\u10d3\u10d0\u10ee\u10e3\u10e0\u10d5\u10d0",cancel:"\u10d2\u10d0\u10e3\u10e5\u10db\u10d4\u10d1\u10d0",update:"\u10d2\u10d0\u10dc\u10d0\u10ee\u10da\u10d4\u10d1\u10d0",insert:"\u10e9\u10d0\u10e1\u10db\u10d0",apply:"\u10d2\u10d0\u10db\u10dd\u10e7\u10d4\u10dc\u10d4\u10d1\u10d0",edit_confirm:"\u10d2\u10d0\u10db\u10dd\u10d5\u10d8\u10e7\u10d4\u10dc\u10dd\u10d7 \u10d0\u10db \u10d5\u10d4\u10da\u10d8\u10e1\u10d7\u10d5\u10d8\u10e1 WYSIWYG \u10e0\u10d4\u10df\u10d8\u10db\u10d8?"},contextmenu:{full:"\u10e1\u10d8\u10d2\u10d0\u10dc\u10d4\u10d6\u10d4",right:"\u10db\u10d0\u10e0\u10ef\u10d5\u10d4\u10dc\u10d0 \u10d9\u10d8\u10d3\u10d4\u10d6\u10d4",center:"\u10ea\u10d4\u10dc\u10e2\u10e0\u10d6\u10d4",left:"\u10db\u10d0\u10e0\u10ea\u10ee\u10d4\u10dc\u10d0 \u10d9\u10d8\u10d3\u10d4\u10d6\u10d4",align:"\u10d2\u10d0\u10e1\u10ec\u10dd\u10e0\u10d4\u10d1\u10d0"},insertdatetime:{day_short:"\u10d9\u10d5,\u10dd\u10e0\u10e8,\u10e1\u10d0\u10db\u10e8,\u10dd\u10d7\u10ee\u10e8,\u10ee\u10e3\u10d7,\u10de\u10d0\u10e0,\u10e8\u10d0\u10d1,\u10d9\u10d5",day_long:"\u10d9\u10d5\u10d8\u10e0\u10d0,\u10dd\u10e0\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8,\u10e1\u10d0\u10db\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8,\u10dd\u10d7\u10ee\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8,\u10ee\u10e3\u10d7\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8,\u10de\u10d0\u10e0\u10d0\u10e1\u10d9\u10d4\u10d5\u10d8,\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8,\u10d9\u10d5\u10d8\u10e0\u10d0",months_short:"\u10d8\u10d0\u10dc,\u10d7\u10d4\u10d1,\u10db\u10d0\u10e0\u10e2,\u10d0\u10de\u10e0,\u10db\u10d0\u10d8\u10e1\u10d8,\u10d8\u10d5\u10dc,\u10d8\u10d5\u10da,\u10d0\u10d2\u10d5,\u10e1\u10d4\u10e5,\u10dd\u10e5\u10e2,\u10dc\u10dd\u10d4\u10db,\u10d3\u10d4\u10d9",months_long:"\u10d8\u10d0\u10dc\u10d5\u10d0\u10e0\u10d8,\u10d7\u10d4\u10d1\u10d4\u10e0\u10d5\u10d0\u10da\u10d8,\u10db\u10d0\u10e0\u10e2\u10d8,\u10d0\u10de\u10e0\u10d8\u10da\u10d8,\u10db\u10d0\u10d8\u10e1\u10d8,\u10d8\u10d5\u10dc\u10d8\u10e1\u10d8,\u10d8\u10d5\u10da\u10d8\u10e1\u10d8,\u10d0\u10d2\u10d5\u10d8\u10e1\u10e2\u10dd,\u10e1\u10d4\u10e5\u10e2\u10d4\u10db\u10d1\u10d4\u10e0\u10d8,\u10dd\u10e5\u10e2\u10dd\u10db\u10d1\u10d4\u10e0\u10d8,\u10dc\u10dd\u10d4\u10db\u10d1\u10d4\u10e0\u10d8,\u10d3\u10d4\u10d9\u10d4\u10db\u10d1\u10d4\u10e0\u10d8",inserttime_desc:"\u10d3\u10e0\u10dd\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",insertdate_desc:"\u10d7\u10d0\u10e0\u10d8\u10e6\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"\u10d1\u10d4\u10ed\u10d3\u10d5\u10d0"},preview:{preview_desc:"\u10ec\u10d8\u10dc\u10d0\u10e1\u10ec\u10d0\u10e0\u10d8 \u10d3\u10d0\u10d7\u10d5\u10d0\u10da\u10d8\u10d4\u10e0\u10d4\u10d1\u10d0"},directionality:{rtl_desc:"\u10db\u10d8\u10db\u10d0\u10e0\u10d7\u10e3\u10da\u10d4\u10d1\u10d0 \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d3\u10d0\u10dc \u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d5",ltr_desc:"\u10db\u10d8\u10db\u10d0\u10e0\u10d7\u10e3\u10da\u10d4\u10d1\u10d0 \u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d3\u10d0\u10dc \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d5"},layer:{content:"\u10d0\u10ee\u10d0\u10da\u10d8 \u10e8\u10e0\u10d4",absolute_desc:"\u10d0\u10d1\u10e1\u10dd\u10da\u10e3\u10e2\u10e3\u10e0\u10d8 \u10de\u10dd\u10d6\u10d8\u10ea\u10d8\u10e0\u10d4\u10d1\u10d0",backward_desc:"\u10e3\u10d9\u10d0\u10dc\u10d0 \u10de\u10da\u10d0\u10dc\u10d6\u10d4",forward_desc:"\u10ec\u10d8\u10dc\u10d0 \u10de\u10da\u10d0\u10dc\u10d6\u10d4",insertlayer_desc:"\u10e8\u10e0\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0"},save:{save_desc:"\u10e8\u10d4\u10dc\u10d0\u10ee\u10d5\u10d0",cancel_desc:"\u10e7\u10d5\u10d4\u10da\u10d0 \u10ea\u10d5\u10da\u10d8\u10da\u10d4\u10d1\u10d8\u10e1 \u10d2\u10d0\u10e3\u10e5\u10db\u10d4\u10d1\u10d0"},nonbreaking:{nonbreaking_desc:"\u10e3\u10ec\u10e7\u10d5\u10d4\u10e2\u10d8 \u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0"},iespell:{download:"ieSpell \u10d0\u10e0 \u10d0\u10e0\u10d8\u10e1 \u10dc\u10d0\u10de\u10dd\u10d5\u10dc\u10d8. \u10d2\u10e1\u10e3\u10e0\u10d7 \u10d3\u10d0\u10e7\u10d4\u10dc\u10d4\u10d1\u10d0?",iespell_desc:"\u10dd\u10e0\u10d7\u10dd\u10d2\u10e0\u10d0\u10e4\u10d8\u10d8\u10e1 \u10e8\u10d4\u10db\u10dd\u10ec\u10db\u10d4\u10d1\u10d0"},advhr:{advhr_desc:"\u10d2\u10d0\u10db\u10e7\u10dd\u10e4\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u10e1\u10db\u10d0\u10d8\u10da\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u10e8\u10d4\u10ea\u10d5\u10da\u10d0",search_desc:"\u10de\u10dd\u10d5\u10dc\u10d0",delta_width:"",delta_height:""},advimage:{delta_width:"200",image_desc:"\u10d2\u10d0\u10db\u10dd\u10e1\u10d0\u10ee\u10e3\u10da\u10d4\u10d1\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0/\u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",delta_height:""},advlink:{delta_width:"200",link_desc:"\u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0/\u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",delta_height:""},xhtmlxtras:{attribs_desc:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0/\u10e8\u10d4\u10ea\u10d5\u10da\u10d0",ins_desc:"\u10e8\u10d4\u10ea\u10d5\u10da\u10d0",del_desc:"\u10ec\u10d0\u10e8\u10da\u10d0",acronym_desc:"\u10d0\u10d1\u10e0\u10d4\u10d5\u10d8\u10d0\u10ea\u10d8\u10d0",abbr_desc:"\u10e8\u10d4\u10db\u10dd\u10d9\u10da\u10d4\u10d1\u10d0",cite_desc:"\u10ea\u10d8\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS \u10e1\u10e2\u10d8\u10da\u10d8\u10e1 \u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"\u10e2\u10d5\u10d4\u10da\u10d0\u10e4\u10e0\u10d8\u10e1 \u10db\u10dd\u10dc\u10d8\u10e8\u10d5\u10dc\u10d0",paste_word_desc:"Word-\u10d8\u10d3\u10dc \u10e9\u10d0\u10e1\u10db\u10d0",paste_text_desc:"\u10e9\u10d0\u10e1\u10d5\u10d8 \u10e0\u10dd\u10d2\u10dd\u10e0\u10ea \u10e2\u10d4\u10e5\u10e1\u10e2\u10d8"},paste_dlg:{word_title:"\u0418\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10e9\u10d0\u10e1\u10d0\u10e1\u10db\u10d4\u10da\u10d0\u10d3 \u10d2\u10d0\u10db\u10dd\u10d8\u10e7\u10d4\u10dc\u10d4\u10d7 \u10d9\u10da\u10d0\u10d5\u10d8\u10d0\u10e2\u10e3\u10e0\u10e3\u10da\u10d8 \u10d9\u10dd\u10db\u10d1\u10d8\u10dc\u10d0\u10ea\u10d8\u10d0 CTRL+V.",text_linebreaks:"\u10d2\u10d0\u10d3\u10d0\u10e2\u10d0\u10dc\u10d8\u10da\u10d8 \u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d4\u10d1\u10d8\u10e1 \u10e8\u10d4\u10dc\u10d0\u10ee\u10d5\u10d0",text_title:"\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10e9\u10d0\u10e1\u10d0\u10e1\u10db\u10d4\u10da\u10d0\u10d3 \u10d2\u10d0\u10db\u10dd\u10d8\u10e7\u10d4\u10dc\u10d4\u10d7 \u10d9\u10da\u10d0\u10d5\u10d8\u10d0\u10e2\u10e3\u10e0\u10e3\u10da\u10d8 \u10d9\u10dd\u10db\u10d1\u10d8\u10dc\u10d0\u10ea\u10d8\u10d0 CTRL+V."},table:{cellprops_delta_width:"30",cell:"\u10e3\u10ef\u10e0\u10d0",col:"\u10e1\u10d5\u10d4\u10e2\u10d8",row:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8",del:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",copy_row_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d9\u10dd\u10de\u10d8\u10e0\u10d4\u10d1\u10d0",cut_row_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d0\u10db\u10dd\u10ed\u10e0\u10d0",paste_row_after_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10e5\u10d5\u10d4\u10db\u10dd\u10d7 \u10d3\u10d0\u10db\u10d4\u10e2\u10d4\u10d1\u10d0",paste_row_before_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d6\u10d4\u10db\u10dd\u10d7 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",props_desc:"\u10ea\u10ee\u10e0\u10d8\u10da\u10d8\u10e1 \u10de\u10d0\u10e0\u10d0\u10db\u10d4\u10e2\u10e0\u10d8\u10d4\u10d1\u10d8",cell_desc:"\u10e3\u10ef\u10e0\u10d8\u10e1 \u10de\u10d0\u10e0\u10d0\u10db\u10d4\u10e2\u10e0\u10d4\u10d1\u10d8",row_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10de\u10d0\u10e0\u10d0\u10db\u10d4\u10e2\u10e0\u10d4\u10d1\u10d8",merge_cells_desc:"\u10e3\u10ef\u10e0\u10d4\u10d1\u10d8\u10e1 \u10d2\u10d0\u10d4\u10e0\u10d7\u10d8\u10d0\u10dc\u10d4\u10d1\u10d0",split_cells_desc:"\u10e3\u10ef\u10e0\u10d8\u10e1 \u10d2\u10d0\u10e7\u10dd\u10e4\u10d0",delete_col_desc:"\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",col_after_desc:"\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0 \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d5",col_before_desc:"\u10e1\u10d5\u10d4\u10e2\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0 \u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d5",delete_row_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",row_after_desc:"\u10e1\u10e2\u10e0\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0 \u10e5\u10d5\u10d4\u10db\u10dd\u10d7",row_before_desc:"\u10e1\u10e2\u10d8\u10e5\u10dd\u10dc\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0 \u10d6\u10d4\u10db\u10dd\u10d7",desc:"\u10ea\u10ee\u10e0\u10d8\u10da\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0/\u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u10e7\u10d5\u10d4\u10da\u10d0 \u10ea\u10d5\u10da\u10d8\u10da\u10d4\u10d1\u10d0 \u10d8\u10e5\u10dc\u10d4\u10d1\u10d0 \u10d3\u10d0\u10d9\u10d0\u10e0\u10d2\u10e3\u10da\u10d8.\\n\\n\u10d2\u10d0\u10dc\u10d5\u10d0\u10d2\u10e0\u10eb\u10dd\u10d7 \u10d0\u10d5\u10e0\u10dd\u10db\u10d0\u10e2\u10e3\u10e0\u10d0\u10d3 \u10d3\u10d0\u10db\u10d0\u10ee\u10e1\u10dd\u10d5\u10e0\u10d4\u10d1\u10e3\u10da\u10d8\u10e1 \u10d0\u10e6\u10d3\u10d2\u10d4\u10dc\u10d0?",restore_content:"\u10d0\u10d5\u10e2\u10dd\u10db\u10d0\u10e2\u10e3\u10e0\u10d0\u10d3 \u10d3\u10d0\u10db\u10d0\u10ee\u10e1\u10dd\u10d5\u10e0\u10d4\u10d1\u10e3\u10da\u10d8\u10e1 \u10d0\u10e6\u10d3\u10d2\u10d4\u10dc\u10d0",unload_msg:"\u10d7\u10e3 \u10d7\u10e5\u10d5\u10d4\u10dc \u10d3\u10d0\u10e2\u10dd\u10d5\u10d4\u10d1\u10d7 \u10db\u10dd\u10ea\u10d4\u10db\u10e3\u10da \u10d2\u10d5\u10d4\u10e0\u10d3\u10e1, \u10e7\u10d5\u10d4\u10da\u10d0 \u10ea\u10d5\u10da\u10d8\u10da\u10d4\u10d1\u10d0 \u10d8\u10e5\u10dc\u10d4\u10d1\u10d0 \u10d3\u10d0\u10d9\u10d0\u10e0\u10d2\u10e3\u10da\u10d8."},fullscreen:{desc:"\u10e1\u10e0\u10e3\u10da\u10d4\u10d9\u10e0\u10d0\u10dc\u10d8\u10d0\u10dc\u10d8 \u10e0\u10d4\u10df\u10d8\u10db\u10d8"},media:{edit:"\u10d9\u10da\u10d8\u10d9\u10d8\u10e1 \u10db\u10d0\u10ee\u10d0\u10e1\u10d8\u10d0\u10d7\u10d4\u10d1\u10da\u10d4\u10d1\u10d8",desc:"\u10d9\u10da\u10d8\u10de\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0/\u10e0\u10d4\u10d3\u10d0\u10e5\u10e2\u10d8\u10e0\u10d4\u10d1\u10d0",delta_height:"",delta_width:""},fullpage:{desc:"\u10d3\u10dd\u10d9\u10e3\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10db\u10d0\u10ee\u10d0\u10e1\u10d8\u10d0\u10d7\u10d4\u10d1\u10da\u10d4\u10d1\u10d8",delta_width:"",delta_height:""},template:{desc:"\u10e8\u10d0\u10d1\u10da\u10dd\u10dc\u10d8\u10e1 \u10d2\u10d0\u10db\u10dd\u10e7\u10d4\u10dc\u10d4\u10d1\u10d0"},visualchars:{desc:"\u10e7\u10d5\u10d4\u10da\u10d0 \u10dc\u10d8\u10e8\u10d0\u10dc\u10d8"},spellchecker:{desc:"\u10db\u10d0\u10e0\u10d7\u10da\u10ec\u10d4\u10e0\u10d0",menu:"\u10db\u10d0\u10e0\u10d7\u10da\u10ec\u10d4\u10e0\u10d8\u10e1 \u10de\u10d0\u10e0\u10d0\u10db\u10d4\u10e2\u10e0\u10d4\u10d1\u10d8",ignore_word:"\u10d2\u10d0\u10db\u10dd\u10d5\u10e2\u10dd\u10d5\u10dd\u10d7",ignore_words:"\u10d2\u10d0\u10db\u10dd\u10d5\u10e2\u10dd\u10d5\u10dd\u10d7 \u10e7\u10d5\u10d4\u10da\u10d0",langs:"\u10d4\u10dc\u10d4\u10d1\u10d8",wait:"\u10d2\u10d7\u10ee\u10dd\u10d5\u10d7, \u10d3\u10d0\u10d8\u10ea\u10d0\u10d3\u10dd\u10d7...",sug:"\u10d5\u10d0\u10e0\u10d8\u10d0\u10dc\u10e2\u10d4\u10d1\u10d8",no_sug:"\u10e3\u10d5\u10d0\u10e0\u10d8\u10d0\u10dc\u10e2\u10dd\u10d7",no_mpell:"\u10e8\u10d4\u10ea\u10d3\u10dd\u10db\u10d4\u10d1\u10d8 \u10d0\u10e6\u10db\u10dd\u10e9\u10d4\u10dc\u10d8\u10da\u10d8 \u10d0\u10e0 \u10d8\u10e7\u10dd."},pagebreak:{desc:"\u10d2\u10d5\u10d4\u10e0\u10d3\u10d8\u10e1 \u10d2\u10d0\u10db\u10e7\u10dd\u10e4\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0"},advlist:{types:"\u10e1\u10d8\u10db\u10d1\u10dd\u10da\u10dd\u10d4\u10d1\u10d8",def:"\u10e1\u10e2\u10d0\u10dc\u10d3\u10d0\u10e0\u10e2\u10e3\u10da\u10d8",lower_alpha:"\u10dc\u10e3\u10e1\u10ee\u10e3\u10e0\u10d8 \u10d0\u10e1\u10dd\u10d4\u10d1\u10d8",lower_greek:"\u10dc\u10e3\u10e1\u10ee\u10e3\u10e0\u10d8 \u10d1\u10d4\u10e0\u10eb\u10dc\u10e3\u10da\u10d8 \u10d0\u10e1\u10dd\u10d4\u10d1\u10d8",lower_roman:"\u10dc\u10e3\u10e1\u10ee\u10e3\u10e0\u10d8 \u10da\u10d0\u10d7\u10d8\u10dc\u10e3\u10e0\u10d8 \u10d0\u10e1\u10dd\u10d4\u10d1\u10d8",upper_alpha:"\u10d0\u10e1\u10dd\u10db\u10d7\u10d0\u10d5\u10e0\u10e3\u10da\u10d8 \u10d0\u10e1\u10dd\u10d4\u10d1\u10d8",upper_roman:"\u10d0\u10e1\u10dd\u10db\u10d7\u10d0\u10d5\u10e0\u10e3\u10da\u10d8 \u10da\u10d0\u10d7\u10d8\u10dc\u10e3\u10e0\u10d8 \u10d0\u10e1\u10dd\u10d4\u10d1\u10d8",circle:"\u10ec\u10e0\u10d4\u10d4\u10d1\u10d8",disc:"\u10d3\u10d8\u10e1\u10d9\u10d4\u10d1\u10d8",square:"\u10d9\u10d5\u10d0\u10d3\u10e0\u10d0\u10e2\u10d4\u10d1\u10d8"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/kl.js0000644000175000017500000001210211526350525031507 0ustar frankiefrankietinyMCE.addI18n({kl:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text"},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/km.js0000644000175000017500000004467211526350525031531 0ustar frankiefrankietinyMCE.addI18n({km:{common:{more_colors:"\u1796\u178e\u17cc\u1795\u17d2\u179f\u17c1\u1784\u1791\u17c0\u178f",invalid_data:"\u1780\u17c6\u17a0\u17bb\u179f\u17d6 \u1794\u17b6\u1793\u1794\u1789\u17d2\u1785\u17bc\u179b\u178f\u1798\u17d2\u179b\u17c3\u1798\u17b7\u1793\u178f\u17d2\u179a\u17b9\u1798\u178f\u17d2\u179a\u17bc\u179c\u178a\u17c2\u179b\u178f\u17d2\u179a\u17bc\u179c\u1794\u17b6\u1793\u178a\u17b6\u1780\u17cb\u179f\u17c6\u1782\u17b6\u179b\u17cb\u178a\u17c4\u1799\u1796\u178e\u17cc\u1780\u17d2\u179a\u17a0\u1798\u00a0\u17d4",popup_blocked:"\u17a2\u178f\u17cb\u1791\u17c4\u179f! \u1799\u17be\u1784\u1781\u17d2\u1789\u17bb\u17c6\u179f\u17c6\u1782\u17b6\u179b\u17cb\u1783\u17be\u1789\u1790\u17b6\u1794\u1784\u17d2\u17a2\u17bd\u1785\u179b\u17c1\u1785\u17a1\u17be\u1784\u178f\u17d2\u179a\u17bc\u179c\u1794\u17b6\u1793\u1791\u1794\u17cb\u179f\u17d2\u1780\u17b6\u178f\u17cb\u17d4 \u17a2\u17d2\u1793\u1780\u178f\u17d2\u179a\u17bc\u179c\u1798\u17b7\u1793\u17a2\u1793\u17bb\u1789\u17d2\u1789\u17b6\u178f\u179a\u17b6\u179b\u17cb\u1780\u17b6\u179a\u1791\u1794\u17cb\u179f\u17d2\u1780\u17b6\u178f\u17cb\u1794\u1784\u17d2\u17a2\u17bd\u1785\u179b\u17c1\u1785\u17a1\u17be\u1784\u1790\u17d2\u1798\u17b8\u1785\u17c6\u1796\u17c4\u17c7\u1794\u178e\u17d2\u178f\u17b6\u1789\u1798\u17bd\u1799\u1793\u17c1\u17c7\u1791\u17c1 \u178a\u17be\u1798\u17d2\u1794\u17b8\u1794\u17d2\u179a\u17be\u17a7\u1794\u1780\u179a\u178e\u17cd\u1793\u17c1\u17c7\u17b2\u17d2\u1799\u1798\u17b6\u1793\u1794\u17d2\u179a\u179f\u17b7\u1791\u17d2\u1792\u17b7\u1797\u17b6\u1796\u17d4",clipboard_no_support:"\u1794\u1785\u17d2\u1785\u17bb\u1794\u17d2\u1794\u1793\u17d2\u1793\u1780\u1798\u17d2\u1798\u179c\u17b7\u1792\u17b8\u179a\u17bb\u1780\u179a\u1780\u179a\u1794\u179f\u17cb\u17a2\u17d2\u1793\u1780\u1798\u17b7\u1793\u1791\u17b6\u1793\u17cb\u1782\u17b6\u17c6\u1791\u17d2\u179a \u179f\u17bc\u1798\u1794\u17d2\u179a\u17be\u1780\u17d2\u178f\u17b6\u179a\u1785\u17bb\u1785\u1795\u17d2\u179b\u17bc\u179c\u1780\u17b6\u178f\u17cb\u1787\u17c6\u1793\u17bd\u179f\u179c\u17b7\u1789\u17d4",clipboard_msg:"\u1785\u1798\u17d2\u179b\u1784 / \u1780\u17b6\u178f\u17cb / \u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb \u1798\u17b7\u1793\u17a2\u17b6\u1785\u1792\u17d2\u179c\u17be\u1794\u17b6\u1793\u1780\u17d2\u1793\u17bb\u1784 Mozilla \u1793\u17b7\u1784 Firefox\u17d4 n\u178f\u17be\u17a2\u17d2\u1793\u1780\u1785\u1784\u17cb\u1794\u17b6\u1793\u1796\u17d0\u178f\u17cc\u1798\u17b6\u1793\u1794\u1793\u17d2\u1790\u17c2\u1798\u17a2\u17c6\u1796\u17b8\u1794\u1789\u17d2\u17a0\u17b6\u1793\u17c1\u17c7\u1791\u17c1?",not_set:"-- \u1796\u17bb\u17c6\u1794\u17b6\u1793\u1780\u17c6\u178e\u178f\u17cb --",class_name:"\u1790\u17d2\u1793\u17b6\u1780\u17cb",browse:"\u179a\u1780\u1798\u17be\u179b",close:"\u1794\u17b7\u1791",cancel:"\u1794\u17c4\u17c7\u1794\u1784\u17cb",update:"\u1794\u1793\u17d2\u1791\u17b6\u1793\u17cb\u179f\u1798\u17d0\u1799",insert:"\u1794\u1789\u17d2\u1785\u17bc\u179b",apply:"\u17a2\u1793\u17bb\u179c\u178f\u17d2\u178f",edit_confirm:"\u178f\u17be\u17a2\u17d2\u1793\u1780\u1785\u1784\u17cb\u1794\u17d2\u179a\u17be\u1798\u17c9\u17bc\u178a\u17a2\u17d2\u179c\u17b8\u178a\u17c2\u179b\u1783\u17be\u1789\u1787\u17b6\u17a2\u17d2\u179c\u17b8\u178a\u17c2\u179b\u1791\u1791\u17bd\u179b\u1794\u17b6\u1793\u1787\u17b6\u1798\u17bd\u1799\u1793\u17b9\u1784\u178f\u17c6\u1794\u1793\u17cb\u17a2\u178f\u17d2\u1790\u1794\u1791\u1793\u17c1\u17c7\u17ac?"},contextmenu:{full:"\u179f\u1784\u1781\u17b6\u1784",right:"\u1786\u17d2\u179c\u17c1\u1784",center:"\u1780\u178e\u17d2\u178f\u17b6\u179b",left:"\u1786\u17d2\u179c\u17c1\u1784",align:"\u1780\u17b6\u179a\u178f\u1798\u17d2\u179a\u17b9\u1798"},insertdatetime:{day_short:"\u17a2\u17b6\u1791\u17b7\u178f\u17d2\u1799,\u1785\u1793\u17d2\u1791,\u17a2\u1784\u17d2\u1782\u17b6\u179a,\u1796\u17bb\u1792,\u1796\u17d2\u179a\u17a0\u179f\u17d2\u1794\u178f\u17b7\u17cd,\u179f\u17bb\u1780\u17d2\u179a,\u179f\u17c5\u179a\u17cd,\u17a2\u17b6\u1791\u17b7\u178f\u17d2\u1799",day_long:"\u1790\u17d2\u1784\u17c3\u17a2\u17b6\u1791\u17b7\u178f\u17d2\u1799,\u1790\u17d2\u1784\u17c3\u1785\u1793\u17d2\u1791,\u1790\u17d2\u1784\u17c3\u17a2\u1784\u17d2\u1782\u17b6\u179a,\u1790\u17d2\u1784\u17c3\u1796\u17bb\u1792,\u1790\u17d2\u1784\u17c3\u1796\u17d2\u179a\u17a0\u179f\u17d2\u1794\u178f\u17b7\u17cd,\u1790\u17d2\u1784\u17c3\u179f\u17bb\u1780\u17d2\u179a,\u1790\u17d2\u1784\u17c3\u179f\u17c5\u179a\u17cd,\u1790\u17d2\u1784\u17c3\u17a2\u17b6\u1791\u17b7\u178f\u17d2\u1799",months_short:"\u1798\u1780\u179a\u17b6,\u1780\u17bb\u1798\u17d2\u1797\u17c8,\u1798\u17b7\u1793\u17b6,\u1798\u17c1\u179f\u17b6,\u17a7\u179f\u1797\u17b6,\u1798\u17b7\u1790\u17bb\u1793\u17b6,\u1780\u1780\u17d2\u1780\u178a\u17b6,\u179f\u17b8\u17a0\u17b6,\u1780\u1789\u17d2\u1789\u17b6,\u178f\u17bb\u179b\u17b6,\u179c\u17b7\u1785\u17d2\u1786\u17b7\u1780\u17b6,\u1792\u17d2\u1793\u17bc",months_long:"\u1781\u17c2\u1798\u1780\u179a\u17b6,\u1781\u17c2\u1780\u17bb\u1798\u17d2\u1797\u17c8,\u1781\u17c2\u1798\u17b7\u1793\u17b6,\u1781\u17c2\u1798\u17c1\u179f\u17b6,\u1781\u17c2\u17a7\u179f\u1797\u17b6,\u1781\u17c2\u1798\u17b7\u1790\u17bb\u1793\u17b6,\u1781\u17c2\u1780\u1780\u17d2\u1780\u178a\u17b6,\u1781\u17c2\u179f\u17b8\u17a0\u17b6,\u1781\u17c2\u1780\u1789\u17d2\u1789\u17b6,\u1781\u17c2\u178f\u17bb\u179b\u17b6,\u1781\u17c2\u179c\u17b7\u1785\u17d2\u1786\u17b7\u1780\u17b6,\u1781\u17c2\u1792\u17d2\u1793\u17bc",inserttime_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1798\u17c9\u17c4\u1784",insertdate_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1780\u17b6\u179b\u1794\u179a\u1785\u17d2\u1786\u17c1\u1791",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u1794\u17c4\u17c7\u1796\u17bb\u1798\u17d2\u1796"},preview:{preview_desc:"\u1798\u17be\u179b\u1787\u17b6\u1798\u17bb\u1793"},directionality:{rtl_desc:"\u1791\u17b7\u179f\u1796\u17b8\u179f\u17d2\u178f\u17b6\u17c6\u1791\u17c5\u1786\u17d2\u179c\u17c1\u1784",ltr_desc:"\u1791\u17b7\u179f\u1786\u17d2\u179c\u17c1\u1784\u1791\u17c5\u179f\u17d2\u178f\u17b6\u17c6"},layer:{content:"\u179f\u17d2\u179a\u1791\u17b6\u1794\u17cb\u1790\u17d2\u1798\u17b8...",absolute_desc:"\u1794\u17be\u1780\u1794\u17b7\u1791\u1791\u17b8\u178f\u17b6\u17c6\u1784\u178a\u17b6\u1785\u17cb\u1781\u17b6\u178f",backward_desc:"\u1795\u17d2\u179b\u17b6\u179f\u17cb\u1791\u17b8\u1791\u17c5\u1780\u17d2\u179a\u17c4\u1799",forward_desc:"\u1795\u17d2\u179b\u17b6\u179f\u17cb\u1791\u17b8\u1791\u17c5\u1798\u17bb\u1781",insertlayer_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u179f\u17d2\u179a\u1791\u17b6\u1794\u17cb\u1790\u17d2\u1798\u17b8"},save:{save_desc:"\u179a\u1780\u17d2\u179f\u17b6\u1791\u17bb\u1780",cancel_desc:"\u1794\u17c4\u17c7\u1794\u1784\u17cb\u1794\u17c6\u179b\u17b6\u179f\u17cb\u1794\u17d2\u178f\u17bc\u179a\u1791\u17b6\u17c6\u1784\u17a1\u17b6\u1799"},nonbreaking:{nonbreaking_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u178f\u17bd\u17a2\u1780\u17d2\u179f\u179a\u1782\u1798\u17d2\u179b\u17b6\u178f\u1798\u17b7\u1793\u1794\u17c6\u1794\u17c2\u1780"},iespell:{download:"\u1798\u17b7\u1793\u1794\u17b6\u1793\u179a\u1780\u1783\u17be\u1789 ieSpell \u17d4 \u178f\u17be\u178f\u17d2\u179a\u17bc\u179c\u178a\u17c6\u17a1\u17be\u1784\u17a5\u17a1\u17bc\u179c\u17ac?",iespell_desc:"\u178f\u17c6\u178e\u17be\u1780\u17b6\u179a\u1796\u17b7\u1793\u17b7\u178f\u17d2\u1799\u17a2\u1780\u17d2\u1781\u179a\u17b6\u179c\u17b7\u179a\u17bb\u1791\u17d2\u1792"},advhr:{advhr_desc:"\u1794\u1793\u17d2\u1791\u17b6\u178f\u17cb\u1795\u17d2\u178a\u17c1\u1780",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u17a2\u17b6\u179a\u1798\u17d2\u1798\u178e\u17cd",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u179f\u17d2\u179c\u17c2\u1784\u179a\u1780/\u1787\u17c6\u1793\u17bd\u179f",search_desc:"\u179f\u17d2\u179c\u17c2\u1784\u179a\u1780",delta_width:"",delta_height:""},advimage:{image_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b/\u1780\u17c2\u179f\u1798\u17d2\u179a\u17bd\u179b\u179a\u17bc\u1794\u1797\u17b6\u1796",delta_width:"",delta_height:""},advlink:{link_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b/\u1780\u17c2\u179f\u1798\u17d2\u179a\u17bd\u179b\u178f\u17c6\u178e",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b/\u1780\u17c2\u179f\u1798\u17d2\u179a\u17bd\u179b\u1794\u178e\u17d2\u178f\u17b6\u1782\u17bb\u178e\u179b\u1780\u17d2\u1781\u178e\u17c8",ins_desc:"\u1780\u17b6\u179a\u1794\u1789\u17d2\u1785\u17bc\u179b",del_desc:"\u1780\u17b6\u179a\u179b\u17bb\u1794\u1785\u17c4\u179b",acronym_desc:"\u1796\u17b6\u1780\u17d2\u1799\u1780\u17b6\u178f\u17cb\u1799\u1780\u178f\u17c2\u17a2\u1780\u17d2\u179f\u179a\u178a\u17be\u1798",abbr_desc:"\u17a2\u1780\u17d2\u179f\u179a\u179f\u1784\u17d2\u1781\u17c1\u1794",cite_desc:"\u179f\u17c1\u1785\u1780\u17d2\u178f\u17b8\u179f\u17d2\u179a\u1784\u17cb",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u1780\u17c2\u179f\u1798\u17d2\u179a\u17bd\u179b\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798 CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u17a5\u17a1\u17bc\u179c\u1793\u17c1\u17c7\u179f\u17d2\u1790\u17b7\u178f\u1780\u17d2\u1793\u17bb\u1784\u1798\u17c9\u17bc\u178a\u17a2\u178f\u17d2\u1790\u1794\u1791\u1792\u1798\u17d2\u1798\u178f\u17b6\u00a0\u17d4 \u1785\u17bb\u1785\u1798\u17d2\u178f\u1784\u1791\u17c0\u178f\u178a\u17be\u1798\u17d2\u1794\u17b8\u1794\u17b7\u1791\u1794\u17be\u1780\u178f\u17d2\u179a\u17a1\u1794\u17cb\u1791\u17c5\u179a\u1780\u1798\u17c9\u17bc\u178a\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u1792\u1798\u17d2\u1798\u178f\u17b6\u179c\u17b7\u1789\u00a0\u17d4",plaintext_mode_sticky:"\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u17a5\u17a1\u17bc\u179c\u1793\u17c1\u17c7\u179f\u17d2\u1790\u17b7\u178f\u1780\u17d2\u1793\u17bb\u1784\u1798\u17c9\u17bc\u178a\u17a2\u178f\u17d2\u1790\u1794\u1791\u1792\u1798\u17d2\u1798\u178f\u17b6\u00a0\u17d4 \u1785\u17bb\u1785\u1798\u17d2\u178f\u1784\u1791\u17c0\u178f\u178a\u17be\u1798\u17d2\u1794\u17b8\u1794\u17b7\u1791\u1794\u17be\u1780\u178f\u17d2\u179a\u17a1\u1794\u17cb\u1791\u17c5\u179a\u1780\u1798\u17c9\u17bc\u178a\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u1792\u1798\u17d2\u1798\u178f\u17b6\u179c\u17b7\u1789\u00a0\u17d4 \u1794\u1793\u17d2\u1791\u17b6\u1794\u17cb\u1796\u17b8\u17a2\u17d2\u1793\u1780\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u17a2\u17d2\u179c\u17b8\u17d7\u179a\u17bd\u1785\u17a2\u17d2\u1793\u1780\u1793\u17b9\u1784\u178f\u17d2\u179a\u17bc\u179c\u178f\u17d2\u179a\u17a1\u1794\u17cb\u1791\u17c5\u1798\u17c9\u17bc\u178a\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u1792\u1798\u17d2\u1798\u178f\u17b6\u179c\u17b7\u1789\u00a0\u17d4",selectall_desc:"\u1787\u17d2\u179a\u17be\u179f\u1791\u17b6\u17c6\u1784\u17a2\u179f\u17cb",paste_word_desc:"\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u1780\u1798\u17d2\u1798\u179c\u17b7\u1792\u17b8 Word",paste_text_desc:"\u1794\u17b7\u1791\u1797\u17b6\u17d2\u1787\u1794\u17cb\u1787\u17b6\u17a2\u178f\u17d2\u1790\u1794\u1791\u1792\u1798\u17d2\u1798\u178f\u17b6"},paste_dlg:{word_title:"\u1794\u17d2\u179a\u17be CTRL V \u1793\u17c5\u179b\u17be\u1780\u17d2\u178a\u17b6\u179a\u1785\u17bb\u1785\u178a\u17be\u1798\u17d2\u1794\u17b8\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u17a2\u178f\u17d2\u1790\u1794\u1791\u1791\u17c5\u1793\u17b9\u1784\u1794\u1784\u17d2\u17a2\u17bd\u1785\u1793\u17c1\u17c7\u00a0\u17d4",text_linebreaks:"\u179a\u1780\u17d2\u179f\u17b6\u179f\u1789\u17d2\u1789\u17b6\u1785\u17bb\u17c7\u1794\u1793\u17d2\u1791\u17b6\u178f\u17cb",text_title:"\u1794\u17d2\u179a\u17be CTRL V \u1793\u17c5\u179b\u17be\u1780\u17d2\u178a\u17b6\u179a\u1785\u17bb\u1785\u178a\u17be\u1798\u17d2\u1794\u17b8\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u17a2\u178f\u17d2\u1790\u1794\u1791\u1791\u17c5\u1793\u17b9\u1784\u1794\u1784\u17d2\u17a2\u17bd\u1785\u1793\u17c1\u17c7\u00a0\u17d4"},table:{merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"30",table_delta_width:"0",cellprops_delta_height:"20",cellprops_delta_width:"30",rowprops_delta_height:"10",rowprops_delta_width:"0",cell:"\u1780\u17d2\u179a\u17a1\u17b6",col:"\u1787\u17bd\u179a\u1788\u179a",row:"\u1787\u17bd\u179a\u178a\u17c1\u1780",del:"\u179b\u17bb\u1794\u178f\u17b6\u179a\u17b6\u1784",copy_row_desc:"\u1785\u1798\u17d2\u179b\u1784\u1787\u17bd\u179a\u178a\u17c1\u1780\u178f\u17b6\u179a\u17b6\u1784",cut_row_desc:"\u1780\u17b6\u178f\u17cb\u1787\u17bd\u179a\u178a\u17c1\u1780\u178f\u17b6\u179a\u17b6\u1784",paste_row_after_desc:"\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u1787\u17bd\u179a\u178a\u17c1\u1780\u178f\u17b6\u179a\u17b6\u1784\u1781\u17b6\u1784\u179f\u17d2\u178a\u17b6\u17c6",paste_row_before_desc:"\u1794\u17b7\u1791\u1797\u17d2\u1787\u17b6\u1794\u17cb\u1787\u17bd\u179a\u178a\u17c1\u1780\u178f\u17b6\u179a\u17b6\u1784\u1781\u17b6\u1784\u1786\u17d2\u179c\u17c1\u1784",props_desc:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u178f\u17b6\u179a\u17b6\u1784",cell_desc:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u1780\u17d2\u179a\u17a1\u17b6\u178f\u17b6\u179a\u17b6\u1784",row_desc:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u1787\u17bd\u179a\u178a\u17c1\u1780\u178f\u17b6\u179a\u17b6\u1784",merge_cells_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1780\u17d2\u179a\u17a1\u17b6\u178f\u17b6\u179a\u17b6\u1784\u1785\u17bc\u179b\u1782\u17d2\u1793\u17b6",split_cells_desc:"\u1796\u17bb\u17c6\u1789\u17c2\u1780\u1780\u17d2\u179a\u17a1\u17b6\u178f\u17b6\u179a\u17b6\u1784",delete_col_desc:"\u179b\u17bb\u1794\u1787\u17bd\u179a\u1788\u179a\u1785\u17c1\u1789",col_after_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1787\u17bd\u179a\u1788\u179a\u1781\u17b6\u1784\u179f\u17d2\u178a\u17b6\u17c6",col_before_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1787\u17bd\u179a\u1788\u179a\u1781\u17b6\u1784\u1786\u17d2\u179c\u17c1\u1784",delete_row_desc:"\u179b\u17bb\u1794\u1787\u17bd\u179a\u178a\u17c1\u1780",row_after_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1787\u17bd\u179a\u178a\u17c1\u1780\u1781\u17b6\u1784\u179f\u17d2\u178a\u17b6\u17c6",row_before_desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1787\u17bd\u179a\u178a\u17c1\u1780\u1781\u17b6\u1784\u1786\u17d2\u179c\u17c1\u1784",desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u178f\u17b6\u179a\u17b6\u1784\u1790\u17d2\u1798\u17b8\u1798\u1799\u1799"},autosave:{warning_message:"\u1794\u17be\u17a2\u17d2\u1793\u1780\u179f\u17d2\u178a\u17b6\u179a\u1798\u17b6\u178f\u17b7\u1780\u17b6\u179f\u17d2\u179c\u17d0\u1799\u179a\u1780\u17d2\u179f\u17b6\u1791\u17bb\u1780 \u17a2\u17d2\u1793\u1780\u1793\u17b9\u1784\u1794\u17b6\u178f\u17cb\u1794\u1784\u17cb\u1798\u17b6\u178f\u17b7\u1780\u17b6\u1791\u17b6\u17c6\u1784\u17a2\u179f\u17cb\u178a\u17c2\u179b\u1798\u17b6\u1793\u1780\u17d2\u1793\u17bb\u1784\u1780\u1798\u17d2\u1798\u179c\u17b7\u1792\u17b8\u1793\u17b7\u1796\u1793\u17d2\u1792\u1793\u17c1\u17c7\u00a0\u17d4nn\u178f\u17be\u17a2\u17d2\u1793\u1780\u1794\u17d2\u179a\u17b6\u1780\u178a\u1787\u17b6\u1785\u1784\u17cb\u179f\u17d2\u178a\u17b6\u179a\u1798\u17b6\u178f\u17b7\u1780\u17b6\u1794\u17b6\u1793\u179a\u1780\u17d2\u179f\u17b6\u1791\u17bb\u1780\u17ac?",restore_content:"\u179f\u17d2\u178a\u17b6\u179a\u1798\u17b6\u178f\u17b7\u1780\u17b6\u179f\u17d2\u179c\u17d0\u1799\u179a\u1780\u17d2\u179f\u17b6\u1791\u17bb\u1780\u00a0\u17d4",unload_msg:"\u1794\u178e\u17d2\u178a\u17b6\u1794\u17c6\u179b\u17b6\u179f\u17cb\u1794\u17d2\u178a\u17bc\u179a\u1793\u17b9\u1784\u178f\u17d2\u179a\u17bc\u179c\u1794\u17b6\u178f\u17cb\u1794\u1784\u17cb\u1794\u17d2\u179a\u179f\u17b7\u1793\u1794\u17be\u17a2\u17d2\u1793\u1780\u1793\u17b6\u17c6\u1795\u17d2\u179b\u17bc\u179c\u1785\u17c1\u1789\u1796\u17b8\u1791\u17c6\u1796\u17d0\u179a\u1793\u17c1\u17c7\u00a0\u17d4"},fullscreen:{desc:"\u1794\u17b7\u1791\u1794\u17be\u1780\u1798\u17c9\u17bc\u178a\u1796\u17c1\u1789\u17a2\u17c1\u1780\u17d2\u179a\u1784\u17cb"},media:{delta_height:"20",delta_width:"10",edit:"\u1780\u17c2\u179f\u1798\u17d2\u179a\u17bd\u179b\u1798\u17c1\u178c\u17c0\u1794\u1784\u17d2\u1780\u1794\u17cb",desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b / \u1780\u17c2\u179f\u1798\u17d2\u179a\u17bd\u179b\u1798\u17c1\u178c\u17c0\u1794\u1784\u17d2\u1780\u1794\u17cb"},fullpage:{desc:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u17af\u1780\u179f\u17b6\u179a",delta_width:"",delta_height:""},template:{desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u1798\u17b6\u178f\u17b7\u1780\u17b6\u1796\u17bb\u1798\u17d2\u1796\u178a\u17c2\u179b\u1794\u17b6\u1793\u1780\u17c6\u178e\u178f\u17cb\u1787\u17b6\u1798\u17bb\u1793"},visualchars:{desc:"\u1794\u17b7\u1791/\u1794\u17be\u1780\u1782\u17d2\u179a\u1794\u17cb\u1782\u17d2\u179a\u1784\u1794\u178e\u17d2\u178a\u17b6\u178f\u17bd\u17a2\u1780\u17d2\u179f\u179a\u1787\u17b6\u179a\u17bc\u1794\u1797\u17b6\u1796\u00a0\u17d4"},spellchecker:{desc:"\u1794\u17b7\u1791\u1794\u17be\u1780\u1780\u1798\u17d2\u1798\u179c\u17b7\u1792\u17b8\u1796\u17b7\u1793\u17b7\u178f\u17d2\u1799\u17a2\u1780\u17d2\u1781\u179a\u17b6\u179c\u17b7\u179a\u17bb\u1791\u17d2\u1792",menu:"\u1780\u17b6\u179a\u1780\u17c6\u178e\u178f\u17cb\u1780\u1798\u17d2\u1798\u179c\u17b7\u1792\u17b8\u1796\u17b7\u1793\u17b7\u178f\u17d2\u1799\u17a2\u1780\u17d2\u1781\u179a\u17b6\u179c\u17b7\u179a\u17bb\u1791\u17d2\u1792",ignore_word:"\u1796\u17b6\u1780\u17d2\u1799\u1798\u17b7\u1793\u17a2\u17be\u1796\u17be",ignore_words:"\u1798\u17b7\u1793\u17a2\u17be\u1796\u17be\u1791\u17b6\u17c6\u1784\u17a2\u179f\u17cb",langs:"\u1797\u17b6\u179f\u17b6\u1795\u17d2\u179f\u17c1\u1784\u17d7",wait:"\u179f\u17bc\u1798\u179a\u1784\u17cb\u1785\u17b6\u17c6...",sug:"\u1780\u17b6\u179a\u1795\u17d2\u178a\u179b\u17cb\u1799\u17c4\u1794\u179b\u17cb",no_sug:"\u1782\u17d2\u1798\u17b6\u1793\u1780\u17b6\u179a\u1795\u17d2\u178a\u179b\u17cb\u1799\u17c4\u1794\u179b\u17cb",no_mpell:"\u1782\u17d2\u1798\u17b6\u1793\u1780\u17c6\u17a0\u17bb\u179f\u17a2\u1780\u17d2\u1781\u179a\u17b6\u179c\u17b7\u179a\u17bb\u1791\u17d2\u1792\u00a0\u17d4"},pagebreak:{desc:"\u1794\u1789\u17d2\u1785\u17bc\u179b\u179f\u1789\u17d2\u1789\u17b6\u1794\u17c6\u1794\u17c2\u1780\u1791\u17c6\u1796\u17d0\u179a\u00a0\u17d4"},advlist:{types:"\u1794\u17d2\u179a\u1797\u17c1\u1791",def:"\u179b\u17c6\u1793\u17b6\u17c6\u178a\u17be\u1798",lower_alpha:"\u17a2\u17b6\u179b\u17cb\u17a0\u17d2\u179c\u17b6\u178f\u17bc\u1785",lower_greek:"\u1780\u17d2\u179a\u17b7\u1780\u178f\u17bc\u1785",lower_roman:"\u179a\u17c9\u17bc\u1798\u17c9\u17b6\u17c6\u1784\u178f\u17bc\u1785",upper_alpha:"\u17a2\u17b6\u179b\u17cb\u17a0\u17d2\u179c\u17b6\u1792\u17c6",upper_roman:"\u179a\u17c9\u17bc\u1798\u17c9\u17b6\u17c6\u1784\u1792\u17c6",circle:"\u179a\u1784\u17d2\u179c\u1784\u17cb",disc:"\u1790\u17b6\u179f",square:"\u1780\u17b6\u179a\u17c9\u17c1"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/lb.js0000644000175000017500000001434611526350525031512 0ustar frankiefrankietinyMCE.addI18n({lb:{common:{more_colors:"Weider Fuerwen",invalid_data:"Feeler: Dir hutt ong\u00fclteg W\u00e4erter uginn (rout mark\u00e9iert).",popup_blocked:"Leider huet \u00c4re Popup-Blocker eng F\u00ebnster \u00ebnnerdr\u00e9ckt, d\u00e9i fir d\'Funktion\u00e9iere vun d\u00ebsem Programm n\u00e9ideg ass. Deaktiv\u00e9iert wann ech gelift de Popup-Blocker fir d\u00ebs S\u00e4it.",clipboard_no_support:"G\u00ebtt momentan net an \u00c4rem Browser \u00ebnnerst\u00ebtzt. Benotzt wann ech gelift d\'Tastekombinatiounen.",clipboard_msg:"Kop\u00e9ieren, Ausschneiden an Af\u00fcgen sinn am Mozilla Firefox net m\u00e9iglech.\\nW\u00ebllt Dir m\u00e9i iwwert d\u00ebse Problem gewuer ginn?",not_set:"- ondefin\u00e9iert -",class_name:"CSS-Klass",browse:"Duerchsichen",close:"Zoumaachen",cancel:"Ofbriechen",update:"Aktualis\u00e9ieren",insert:"Af\u00fcgen",apply:"Iwwerhuelen",edit_confirm:"D\u00ebsen Textber\u00e4ich mat WYSIWYG beaarbechten?"},contextmenu:{full:"B\u00e9ids\u00e4iteg align\u00e9iert",right:"Riets align\u00e9iert",center:"Zentr\u00e9iert",left:"L\u00e9nks align\u00e9iert",align:"Ausriichtung"},insertdatetime:{day_short:"So,M\u00e9,D\u00eb,M\u00eb,Do,Fr,Sa,So",day_long:"Sonndeg,M\u00e9indeg,D\u00ebnschdeg,M\u00ebttwoch,Donneschdeg,Freideg,Samschdeg,Sonndeg",months_short:"Jan,Feb,M\u00e4erz,Abr,Mee,Juni,Juli,Aug,Sept,Okt,Nov,Dez",months_long:"Januar,Februar,M\u00e4erz,Abr\u00ebll,Mee,Juni,Juli,August,September,Oktober,November,Dezember",inserttime_desc:"Z\u00e4it af\u00fcgen",insertdate_desc:"Datum af\u00fcgen",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"Dr\u00e9cken"},preview:{preview_desc:"Virschau"},directionality:{rtl_desc:"Schr\u00ebft vu riets no l\u00e9nks",ltr_desc:"Schr\u00ebft vu l\u00e9nks no riets"},layer:{content:"Neie Layer...",absolute_desc:"Absolut Position\u00e9ierung",backward_desc:"No hanne r\u00e9ckelen",forward_desc:"No vir r\u00e9ckelen",insertlayer_desc:"Neie Layer af\u00fcgen"},save:{save_desc:"Sp\u00e4icheren",cancel_desc:"All d\'\u00c4nnerungen ewechpuchen"},nonbreaking:{nonbreaking_desc:"Gesch\u00fctzt Leerzeechen af\u00fcgen"},iespell:{download:"ieSpell konnt net fonnt ginn. W\u00ebllt Dir en install\u00e9ieren?",iespell_desc:"Spellchecker"},advhr:{advhr_desc:"Trennlinn",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smileyen",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Sichen/Ersetzen",search_desc:"Sichen",delta_width:"",delta_height:""},advimage:{image_desc:"Bild af\u00fcgen/ersetzen",delta_width:"",delta_height:""},advlink:{link_desc:"Link af\u00fcgen/beaarbechten",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Attributer af\u00fcgen/beaarbechten",ins_desc:"Agef\u00fcgtenen Text",del_desc:"Gel\u00e4schten Text",acronym_desc:"Akronym",abbr_desc:"Ofkierzung",cite_desc:"Quellenzit\u00e9ierung",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS-Styles beaarbechten",delta_height:"",delta_width:""},paste:{plaintext_mode:"Beim Af\u00fcge g\u00ebtt elo just den Text ouni Format\u00e9ierungen iwwerholl. Nach eng K\u00e9ier klicken, fir an den normale Modus zer\u00e9ckzewiesselen.",plaintext_mode_sticky:"Beim Af\u00fcge g\u00ebtt elo just den Text ouni Format\u00e9ierungen iwwerholl. Nach eng K\u00e9ier klicken, fir an den normale Modus zer\u00e9ckzewiesselen. Nodeem s Dir eppes agef\u00fcgt hutt, g\u00ebtt automatesch nees an den normale Modus gewiesselt.",selectall_desc:"Alles auswielen",paste_word_desc:"Mat Format\u00e9ierungen (aus dem Word) af\u00fcgen",paste_text_desc:"Als normalen Text af\u00fcgen"},paste_dlg:{word_title:"Dr\u00e9ckt op \u00c4rer Tastatur Ctrl+V, um den Text an ze f\u00fcgen.",text_linebreaks:"Zeilen\u00ebmbr\u00ebch b\u00e4ibehalen",text_title:"Dr\u00e9ckt op \u00c4rer Tastatur Ctrl+V, fir den Text an ze f\u00fcgen."},table:{cellprops_delta_width:"150",cell:"Zell",col:"Spalt",row:"Zeil",del:"Tabelle l\u00e4schen",copy_row_desc:"Zeil kop\u00e9ieren",cut_row_desc:"Zeil ausschneiden",paste_row_after_desc:"Zeil \u00ebnnerhalb aus der Zw\u00ebschenoflag af\u00fcgen",paste_row_before_desc:"Zeil uewerhalb aus der Zw\u00ebschenoflag af\u00fcgen",props_desc:"Eegeschaften vun der Tabelle",cell_desc:"Eegeschaften vun der Zell",row_desc:"Eegeschaften vun der Zeil",merge_cells_desc:"Zellen verbannen",split_cells_desc:"Verbonnen Zellen trennen",delete_col_desc:"Spalt l\u00e4schen",col_after_desc:"Spalt riets af\u00fcgen",col_before_desc:"Spalt l\u00e9nks af\u00fcgen",delete_row_desc:"Zeil l\u00e4schen",row_after_desc:"Zeil \u00ebnnerhalb af\u00fcgen",row_before_desc:"Zeil uewerhalb af\u00fcgen",desc:"Tabell erstellen/beaarbechten",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Wann Dir dee gesp\u00e4icherten Inhalt recuper\u00e9iert, verl\u00e9iert Dir de ganzen Inhalt dee grad am Editor ass.\\n\\nW\u00ebllt Dir de gesp\u00e4icherten Inhalt s\u00e9cher recuper\u00e9ieren?.",restore_content:"Automatesch gesp\u00e4icherten Inhalt recuper\u00e9ieren.",unload_msg:"\u00c4r \u00c4nnerungen gi verluer, wann Dir d\'S\u00e4it verloosst."},fullscreen:{desc:"Vollbildschierm"},media:{edit:"Multimedia-Abettung beaarbechten",desc:"Multimedia-Inhalt abannen/beaarbechten",delta_height:"",delta_width:""},fullpage:{desc:"Dokument-Eegeschaften",delta_width:"",delta_height:""},template:{desc:"Virgef\u00e4erdegte Virlageninhalt af\u00fcgen"},visualchars:{desc:"Siichtbarkeet vun de Steierzeechen un/aus"},spellchecker:{desc:"Spellchecker un/aus",menu:"Konfiguratioun vum Spellchecker",ignore_word:"Wuert ignor\u00e9ieren",ignore_words:"All ignor\u00e9ieren",langs:"Sproochen",wait:"Wann ech gelift waarden...",sug:"Virschl\u00e9i",no_sug:"Keng Virschl\u00e9i",no_mpell:"Keng Orthographiefeeler fonnt."},pagebreak:{desc:"S\u00e4iten\u00ebmbroch af\u00fcgen"},advlist:{types:"Typen",def:"Standard",lower_alpha:"Kleng Buschtawen",lower_greek:"Kleng griichesch Buschtawen",lower_roman:"Kleng r\u00e9imech Zuelen",upper_alpha:"Grouss Buschtawen",upper_roman:"Grouss r\u00e9imech Zuelen",circle:"Krees",disc:"Scheif",square:"Quadrat"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ko.js0000644000175000017500000001707711526350525031532 0ustar frankiefrankietinyMCE.addI18n({ko:{common:{more_colors:"\uadf8 \uc678\uc758 \uc0c9",invalid_data:"\uc5d0\ub7ec: \uc720\ud6a8\ud558\uc9c0 \uc54a\ub294 \uae00\uc790\uac00 \uc788\uc2b5\ub2c8\ub2e4. \ube68\uac04\uc0c9\uc73c\ub85c \ud45c\uc2dc\ub429\ub2c8\ub2e4.",popup_blocked:"\ud31d\uc5c5\uc774 \ucc28\ub2e8\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \ubaa8\ub4e0 \uae30\ub2a5\uc744 \uc774\uc6a9\ud558\uc2dc\uae30 \uc704\ud574\uc11c\ub294 \ud31d\uc5c5\ucc28\ub2e8\uc744 \ud574\uc81c\ud574 \uc8fc\uc138\uc694.",clipboard_no_support:"\uc774 \uae30\ub2a5\uc740 \ube0c\ub77c\uc6b0\uc800\uc5d0 \uc758\ud574 \uc81c\ud55c\ub418\uace0 \uc788\uc2b5\ub2c8\ub2e4. \ub2e8\ucd95\ud0a4\uc744 \uc774\uc6a9\ud558\uc2ed\uc2dc\uc624.",clipboard_msg:"\ubcf5\uc0ac/\uc798\ub77c\ub0b4\uae30/\ubd99\uc774\uae30\ub294 Mozilla \ubc0fFirefox \uc5d0\uc11c \uc0ac\uc6a9\ub418\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.\\n\uc0c1\uc138\uc815\ubcf4\ub97c \ud45c\uc2dc\ud569\ub2c8\uae4c?",not_set:"-- \uc5c6\uc74c --",class_name:"\ud074\ub798\uc2a4",browse:"\ube0c\ub77c\uc6b0\uc988",close:"\ub2eb\uae30",cancel:"\ucde8\uc18c",update:"\uac31\uc2e0",insert:"\uc0bd\uc785",apply:"\uc801\uc6a9",edit_confirm:"WYSIWYG\ubaa8\ub4dc\ub85c \uc804\ud658\ud569\ub2c8\uae4c?"},contextmenu:{full:"\ubc30\ubd84 \uc815\ub82c",right:"\uc624\ub978\ucabd \uc815\ub82c",center:"\uac00\uc6b4\ub370 \uc815\ub82c",left:"\uc67c\ucabd \uc815\ub82c",align:"\uc815\ub82c"},insertdatetime:{day_short:"\uc77c,\uc6d4,\ud654,\uc218,\ubaa9,\uae08,\ud1a0,\uc77c",day_long:"\uc77c\uc694\uc77c,\uc6d4\uc694\uc77c,\ud654\uc694\uc77c,\uc218\uc694\uc77c,\ubaa9\uc694\uc77c,\uae08\uc694\uc77c,\ud1a0\uc694\uc77c,\uc77c\uc694\uc77c",months_short:"1,2,3,4,5,6,7,8,9,10,11,12",months_long:"1\uc6d4,2\uc6d4,3\uc6d4,4\uc6d4,5\uc6d4,6\uc6d4,7\uc6d4,8\uc6d4,9\uc6d4,10\uc6d4,11\uc6d4,12\uc6d4",inserttime_desc:"\uc2dc\uac04 \uc0bd\uc785",insertdate_desc:"\ub0a0\uc9dc \uc0bd\uc785",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\uc778\uc1c4"},preview:{preview_desc:"\ubbf8\ub9ac\ubcf4\uae30"},directionality:{rtl_desc:"\ubb38\uc790\ubc29\ud5a5\uc744 \uc624\ub978\ucabd\uc5d0\uc11c \uc67c\ucabd\uc73c\ub85c",ltr_desc:"\ubb38\uc790\ubc29\ud5a5\uc744 \uc67c\ucabd\uc5d0\uc11c \uc624\ub978\ucabd\uc73c\ub85c"},layer:{content:"\uc0c8 \ub808\uc774\uc5b4...",absolute_desc:"\uc808\ub300\uc704\uce58\ub85c \uc804\ud658",backward_desc:"\ub4a4\ub85c \uc774\ub3d9",forward_desc:"\uc55e\uc73c\ub85c \uc774\ub3d9",insertlayer_desc:"\uc0c8 \ub808\uc774\uc5b4"},save:{save_desc:"\uc800\uc7a5",cancel_desc:"\ubaa8\ub450 \ucde8\uc18c"},nonbreaking:{nonbreaking_desc:"\ube48\uce78 \uc0bd\uc785"},iespell:{download:"ieSpell\uc774 \ubc1c\uacac\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.\\n\uc778\uc2a4\ud1a8 \ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?",iespell_desc:"\ucca0\uc790 \uac80\uc0ac"},advhr:{advhr_desc:"\uad6c\ubd84\uc120",delta_height:"",delta_width:""},emotions:{emotions_desc:"\uc774\ubaa8\ud2f0\ucf58",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\uac80\uc0c9/\uce58\ud658",search_desc:"\uac80\uc0c9",delta_width:"",delta_height:""},advimage:{image_desc:"\uc774\ubbf8\uc9c0\uc758 \uc0bd\uc785/\ud3b8\uc9d1",delta_width:"",delta_height:""},advlink:{link_desc:"\ub9c1\ud06c\uc758 \uc0bd\uc785/\ud3b8\uc9d1",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\uc18d\uc131 \uc0bd\uc785/\ud3b8\uc9d1",ins_desc:"\uc0bd\uc785",del_desc:"\uc0ad\uc81c",acronym_desc:"\uba38\ub9ac \uae00\uc790\uc5b4",abbr_desc:"\uc57d\uae30",cite_desc:"\uc778\uc6a9\ucc98",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS\ud3b8\uc9d1",delta_height:"",delta_width:""},paste:{plaintext_mode:"\uc77c\ubc18 \ud14d\uc2a4\ud2b8 \ubaa8\ub4dc\uc5d0\uc11c \ubd99\uc5ec\ub123\uae30. \ud074\ub9ad\ud558\uba74 \uc77c\ubc18 \ubd99\uc5ec\ub123\uae30 \ubaa8\ub4dc\ub85c \ub2e4\uc2dc \ubcc0\uacbd\ub429\ub2c8\ub2e4.",plaintext_mode_sticky:"\uc77c\ubc18 \ud14d\uc2a4\ud2b8 \ubaa8\ub4dc\uc5d0\uc11c \ubd99\uc5ec\ub123\uae30. \ud074\ub9ad\ud558\uba74 \uc77c\ubc18 \ubd99\uc5ec\ub123\uae30 \ubaa8\ub4dc\ub85c \ub2e4\uc2dc \ubcc0\uacbd\ub429\ub2c8\ub2e4. After you paste something you will be returned to regular paste mode.",selectall_desc:"\ubaa8\ub450 \uc120\ud0dd",paste_word_desc:"Word\ub85c\ubd80\ud130 \ubd99\uc5ec\ub123\uae30",paste_text_desc:"\ud14d\uc2a4\ud2b8\ucc98\ub7fc \ubd99\uc5ec\ub123\uae30"},paste_dlg:{word_title:"\uc708\ub3c4\uc6b0\uc5d0 \ud14d\uc2a4\ud2b8\ub97c \ubd99\uc774\ub824\uba74 \ud0a4\ubcf4\ub4dc\ub85cCtrl+V\ub97c \uc785\ub825\ud574 \uc8fc\uc138\uc694.",text_linebreaks:"\uac1c\ud589\uc744 \ubcf4\uad00 \uc720\uc9c0",text_title:"\uc708\ub3c4\uc6b0\uc5d0 \ud14d\uc2a4\ud2b8\ub97c \ubd99\uc774\ub824\uba74 \ud0a4\ubcf4\ub4dc\ub85c Ctrl+V\ub97c \uc785\ub825\ud574 \uc8fc\uc138\uc694."},table:{cell:"\uc140",col:"\uc5f4",row:"\ud589",del:"\ud14c\uc774\ube14 \uc0ad\uc81c",copy_row_desc:"\ud589\uc744 \ubcf5\uc0ac",cut_row_desc:"\ud589\uc744 \uc798\ub77c\ub0b4\uae30",paste_row_after_desc:"\ub4a4\ub85c \ud589\uc744 \ubd99\uc5ec\ub123\uae30",paste_row_before_desc:"\uc55e\uc5d0 \ud589\uc744 \ubd99\uc5ec\ub123\uae30",props_desc:"\ud14c\uc774\ube14 \uc18d\uc131",cell_desc:"\uc140\uc758 \uc18d\uc131",row_desc:"\ud589\uc758 \uc18d\uc131",merge_cells_desc:"\uc140\uc744 \uacb0\ud569",split_cells_desc:"\uacb0\ud569\ub41c \uc140\uc744 \ubd84\ud560",delete_col_desc:"\uc5f4\uc0ad\uc81c",col_after_desc:"\ub4a4\uc5d0 \uc5f4\uc0bd\uc785",col_before_desc:"\uc55e\uc5d0 \uc5f4\uc0bd\uc785",delete_row_desc:"\ud589 \uc0ad\uc81c",row_after_desc:"\ub4a4\uc5d0 \ud589 \uc0bd\uc785",row_before_desc:"\uc55e\uc5d0 \ud589 \uc0bd\uc785",desc:"\uc0c8 \ud14c\uc774\ube14 \uc0bd\uc785",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\uc800\uc7a5\ub41c \ub0b4\uc6a9\uc744 \ubcf5\uad6c\ud558\uba74 \ud604\uc7ac\uc758 \ub0b4\uc6a9\uc740 \uc0ad\uc81c\ub429\ub2c8\ub2e4.\\n\\n\uc815\ub9d0 \uc800\uc7a5\ub41c \ub0b4\uc6a9\uc744 \ubcf5\uad6c\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?",restore_content:"\uc790\ub3d9 \uc800\uc7a5\ub41c \ub0b4\uc6a9 \ubcf5\uad6c",unload_msg:"\ub2e4\ub978 \ud398\uc774\uc9c0\ub85c \uc774\ub3d9\ud558\uba74 \ud3b8\uc9d1\ud55c \ub0b4\uc6a9\uc774 \ucde8\uc18c\ub429\ub2c8\ub2e4."},fullscreen:{desc:"\uc804\uccb4\ud654\uba74"},media:{edit:"\ubbf8\ub514\uc5b4\uc758 \ud3b8\uc9d1",desc:"\ubbf8\ub514\uc5b4\uc758 \uc0bd\uc785/\ud3b8\uc9d1",delta_height:"",delta_width:""},fullpage:{desc:"\ud398\uc774\uc9c0\uc758 \uc18d\uc131",delta_width:"",delta_height:""},template:{desc:"\uc815\uc758\uac00 \ub05d\ub09c \ud15c\ud50c\ub9bf\uc758 \uc0bd\uc785"},visualchars:{desc:"\uc81c\uc5b4 \ubb38\uc790\uc758 \ud45c\uc2dc \uc804\ud658"},spellchecker:{desc:"\uc2a4\ud3a0\ub9c1 \uc804\ud658",menu:"\uc2a4\ud3a0\ub9c1 \uc124\uc815",ignore_word:"\uc774 \uc5b4\uad6c\ub97c \ubb34\uc2dc",ignore_words:"\ubaa8\ub450 \ubb34\uc2dc",langs:"\uc5b8\uc5b4",wait:"\uae30\ub2e4\ub824 \uc8fc\uc138\uc694...",sug:"\ud6c4\ubcf4",no_sug:"\ud6c4\ubcf4 \uc5c6\uc74c",no_mpell:"\uc624\ud0c8\uc790\uac00 \ubc1c\uacac\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4."},pagebreak:{desc:"\uc0c8\ud398\uc774\uc9c0 \uc0bd\uc785"},advlist:{types:"\ud0c0\uc785",def:"\uae30\ubcf8",lower_alpha:"\uc54c\ud30c\ubcb3 \uc18c\ubb38\uc790",lower_greek:"\uadf8\ub9ac\uc2a4\uc5b4 \uc18c\ubb38\uc790",lower_roman:"\ub85c\ub9c8 \uc18c\ubb38\uc790",upper_alpha:"\ub300\ubb38\uc790 \uc54c\ud30c\ubcb3",upper_roman:"\ub300\ubb38\uc790 \ub85c\ub9c8",circle:"\uc6d0",disc:"\uc6d0\ud615",square:"\uc0ac\uaca9\ud615"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/lt.js0000644000175000017500000001553111526350525031531 0ustar frankiefrankietinyMCE.addI18n({lt:{common:{more_colors:"Daugiau spalv\u0173",invalid_data:"Klaida: Blogai \u012fvestos reik\u0161m\u0117s, kurios pa\u017eym\u0117tos raudonai.",popup_blocked:"Atsipra\u0161ome, ta\u010diau pasteb\u0117jome, kad j\u016bs\u0173 i\u0161kylan\u010di\u0173 lang\u0173 blokavimo programa i\u0161jung\u0117 lang\u0105, kuris teikia aplikacijai funkcionalum\u0105. Tur\u0117tum\u0117te atjungti i\u0161kylan\u010di\u0173 lang\u0173 blokavim\u0105 \u0161iam tinklalapiui, kad i\u0161naudotum\u0117te visas galimybes.",clipboard_no_support:"\u0160i nar\u0161ykl\u0117 nepalaiko \u0161io veikimo, tod\u0117l naudokite klaviat\u016bros spar\u010diuosius klavi\u0161us.",clipboard_msg:"Kopijavimas/i\u0161kirpimas/\u012fd\u0117jimas paspaudus \u0161\u012f mygtuk\u0105 negalimas Mozilla ir Firefox nar\u0161ykl\u0117se.\\nNukopijuoti galima paspaudus: Ctrl + C, i\u0161kirpti: Ctrl + X, \u012fd\u0117ti: Ctrl + V.\\nAr norite daugiau informacijos apie \u0161i\u0105 problem\u0105?",not_set:"-- Nenurodyta --",class_name:"Klas\u0117",browse:"Nar\u0161yti",close:"U\u017everti",cancel:"Atsisakyti",update:"Atnaujinti",insert:"\u012eterpti",apply:"Taikyti",edit_confirm:"Ar norite naudoti tekst\u0173 redaktoriaus re\u017eim\u0105 \u0161iam teksto redagavimo langui?"},contextmenu:{full:"I\u0161 abiej\u0173 pusi\u0173",right:"De\u0161in\u0117je",center:"Centre",left:"Kair\u0117je",align:"Lygiavimas"},insertdatetime:{day_short:"Sekm,Pirm,Antr,Tre\u010d,Ketv,Penk,\u0160e\u0161t,Sekm",day_long:"Sekmadienis,Pirmadienis,Antradienis,Tre\u010diadienis,Ketvirtadienis,Penktadienis,\u0160e\u0161tadienis,Sekmadienis",months_short:"Sau,Vas,Kov,Bal,Geg,Bir,Lie,Rugpj,Rugs,Spa,Lapkr,Gruo",months_long:"Sausis,Vasaris,Kovas,Balandis,Gegu\u017e\u0117,Bir\u017eelis,Liepa,Rugpj\u016btis,Rugs\u0117jis,Spalis,Lapkritis,Gruodis",inserttime_desc:"\u012eterpti laik\u0105",insertdate_desc:"\u012eterpti dat\u0105",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Spausdinti"},preview:{preview_desc:"Per\u017ei\u016bra"},directionality:{rtl_desc:"Kryptis i\u0161 de\u0161in\u0117s \u012f kair\u0119",ltr_desc:"Kryptis i\u0161 kair\u0117s \u012f de\u0161in\u0119"},layer:{content:"Naujas sluoksnis...",absolute_desc:"Perjungti absoliut\u0173 pozicionavim\u0105",backward_desc:"Perkelti atgal",forward_desc:"Perkelti \u012f priek\u012f",insertlayer_desc:"\u012eterpti nauj\u0105 sluoksn\u012f"},save:{save_desc:"I\u0161saugoti",cancel_desc:"Atsisakyti vis\u0173 pakeitim\u0173"},nonbreaking:{nonbreaking_desc:"\u012eterpti jungiamojo tarpo simbol\u012f"},iespell:{download:"ieSpell neaptiktas. Ar norite dabar j\u012f \u012fdiegti?",iespell_desc:"Paleisti ra\u0161ybos tikrintuv\u0119"},advhr:{delta_width:"10",advhr_desc:"Horizontali linija",delta_height:""},emotions:{emotions_desc:"Jaustukai",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Ie\u0161koti/Pakeisti",delta_width:"10",delta_height:"20",search_desc:"Ie\u0161koti"},advimage:{delta_width:"10",image_desc:"\u012eterpti/Redaguoti paveiksl\u0117l\u012f",delta_height:""},advlink:{delta_width:"10",link_desc:"\u012eterpti/Redaguoti nuorod\u0105",delta_height:""},xhtmlxtras:{attribs_delta_width:"10",ins_delta_width:"10",del_delta_width:"10",acronym_delta_width:"10",abbr_delta_width:"10",cite_delta_width:"10",attribs_desc:"\u012eterpti/Redaguoti atributus",ins_desc:"\u012eterpimas",del_desc:"Panaikinimas",acronym_desc:"Akronimas",abbr_desc:"Santrumpa",cite_desc:"Citavimas",attribs_delta_height:"",ins_delta_height:"",del_delta_height:"",acronym_delta_height:"",abbr_delta_height:"",cite_delta_height:""},style:{delta_width:"40",desc:"Redaguoti CSS stili\u0173",delta_height:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Visk\u0105 pa\u017eym\u0117ti",paste_word_desc:"\u012ed\u0117ti i\u0161 Word",paste_text_desc:"\u012ed\u0117ti kaip paprast\u0105 tekst\u0105"},paste_dlg:{word_title:"Naudokite CTRL+V tekstui \u012fd\u0117ti \u012f \u0161\u012f lang\u0105.",text_linebreaks:"Palikti eilu\u010di\u0173 l\u016b\u017eius",text_title:"Naudokite CTRL+V tekstui \u012fd\u0117ti \u012f \u0161\u012f lang\u0105."},table:{merge_cells_delta_width:"10",table_delta_width:"10",cellprops_delta_width:"10",rowprops_delta_width:"10",cell:"Langelis",col:"Stulpelis",row:"Eilut\u0117",del:"\u0160alinti lentel\u0119",copy_row_desc:"Kopijuoti lentel\u0117s eilut\u0119",cut_row_desc:"I\u0161kirpti lentel\u0117s eilut\u0119",paste_row_after_desc:"\u012ed\u0117ti lentel\u0117s eilut\u0119 po",paste_row_before_desc:"\u012ed\u0117ti lentel\u0117s eilut\u0119 prie\u0161",props_desc:"Lentel\u0117s nustatymai",cell_desc:"Lentel\u0117s langelio nustatymai",row_desc:"Lentel\u0117s eilut\u0117s nustatymai",merge_cells_desc:"Sujungti lentel\u0117s langelius",split_cells_desc:"Skaidyti sulietus lentel\u0117s langelius",delete_col_desc:"\u0160alinti stulpel\u012f",col_after_desc:"\u012eterpti stulpel\u012f po",col_before_desc:"\u012eterpti stulpel\u012f prie\u0161",delete_row_desc:"\u0160alinti eilut\u0119",row_after_desc:"\u012eterpti eilut\u0119 po",row_before_desc:"\u012eterpti eilut\u0119 prie\u0161",desc:"\u012eterpti/Redaguoti lentel\u0119",merge_cells_delta_height:"",table_delta_height:"",cellprops_delta_height:"",rowprops_delta_height:""},autosave:{warning_message:"Jei atstatysite i\u0161saugot\u0105 turin\u012f, prarasite esam\u0105 turin\u012f redaktoriaus lange.\\n\\nAr tikrai norite atstatyti i\u0161saugot\u0105 turin\u012f?",restore_content:"Atstatyti automati\u0161kai i\u0161saugot\u0105 turin\u012f.",unload_msg:"Visi pakeitimai bus prarasti, jei i\u0161eisite i\u0161 \u0161io puslapio."},fullscreen:{desc:"Perjungti viso ekrano re\u017eim\u0105"},media:{delta_width:"10",edit:"Redaguoti integruot\u0105 daugialyp\u0119 terp\u0119",desc:"\u012eterpti/redaguoti integruot\u0105 daugialyp\u0119 terp\u0119",delta_height:""},fullpage:{desc:"Dokumento nustatymai",delta_width:"10",delta_height:""},template:{desc:"\u012eterpti numatyt\u0105 \u0161ablono turin\u012f"},visualchars:{desc:"Vizualiniai valdymo simboliai \u012fjungti/i\u0161jungti."},spellchecker:{desc:"Perjungti ra\u0161ybos tikrintuv\u0119",menu:"Ra\u0161ybos tikrintuv\u0117s nustatymai",ignore_word:"Ignoruoti \u017eod\u012f",ignore_words:"Ignoruoti visk\u0105",langs:"Kalbos",wait:"Pra\u0161ome palaukti...",sug:"Pasi\u016blymai",no_sug:"Pasi\u016blym\u0173 nerasta",no_mpell:"Klaid\u0173 nerasta."},pagebreak:{desc:"\u012eterpti puslapio pabaigos \u017eym\u0119."},advlist:{types:"Tipai",def:"Numatytasis",lower_alpha:"Ma\u017eosiomis raid\u0117mis",lower_greek:"Ma\u017eaisiais graik\u0173",lower_roman:"Ma\u017eaisiais rom\u0117n\u0173",upper_alpha:"Did\u017eiosiomis raid\u0117mis",upper_roman:"Did\u017eiaisiais rom\u0117n\u0173",circle:"Apskritimas",disc:"Diskas",square:"Kvadratas"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/mk.js0000644000175000017500000001426511526350525031524 0ustar frankiefrankietinyMCE.addI18n({mk:{common:{more_colors:"Vi\u0161e boja",invalid_data:"Gre\u0161ka: Une\u0161ene su nevaljane vrednosti, ozna\u010dene su crvenom bojom.",popup_blocked:"Oprostite, izgleda da je va\u0161 popup-blocker onemogu\u0107io prozor u sklopu ovog programa. Morate onemogu\u0107iti blokiranje popup prozora da bi u potpunosti iskoristili ovaj alat.",clipboard_no_support:"Trenuta\u010dno va\u0161 preglednik ne podr\u017eava ovu opciju, poku\u0161ajte koristiti tipkovni\u010dku kraticu.",clipboard_msg:"\u041a\u043e\u043f\u0438\u0440\u0430\u0458/\u0421\u043d\u0438\u043c\u0438/\u0417\u0430\u043b\u0435\u043f\u0438 \u043d\u0435 \u0435 \u0434\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u043e \u043d\u0430 Mozilla \u0438 Firefox \u043f\u0440\u0435\u0431\u0430\u0440\u0443\u0432\u0430\u0447\u0438.\\n\u041f\u043e\u0432\u0435\u045c\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438?",not_set:"-- \u041d\u0435 \u0435 \u043f\u043e\u0441\u0442\u0430\u0432\u0435\u043d\u043e --",class_name:"\u041a\u043b\u0430\u0441\u0430",browse:"\u041f\u0440\u0435\u0432\u0437\u0435\u043c\u0438",close:"\u0417\u0430\u0442\u0432\u043e\u0440\u0438",cancel:"\u041e\u0442\u043a\u0430\u0436\u0438",update:"\u041e\u0431\u043d\u043e\u0432\u0438",insert:"\u0412\u043c\u0435\u0442\u043d\u0438",apply:"Primjeni",edit_confirm:"\u017delite li koristiti WYSIWYG na\u010din rada za ovo tekstualno polje?"},contextmenu:{full:"Puno",right:"Desno",center:"Sredina",left:"Levo",align:"Poravnavanje"},insertdatetime:{day_short:"ned,pon,uto,sre,\u010det,pet,sub,ned",day_long:"nedelja,ponedjeljak,utorak,sreda,\u010detvrtak,petak,subota,nedelja",months_short:"jan,feb,mar,apr,maj,jun,jul,avg,sep,okt,nov,dec",months_long:"januar,februar,mart,april,maj,juni,juli,avgust,septembar,oktobar,novembar,decembar",inserttime_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 vreme",insertdate_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 datum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y."},print:{print_desc:"Ispis"},preview:{preview_desc:"Prikaz"},directionality:{rtl_desc:"S desna na levo",ltr_desc:"S leva na desno"},layer:{content:"Novi sloj...",absolute_desc:"Uklju\u010di/isklju\u010di apsolutno pozicioniranje",backward_desc:"Pomakni natrag",forward_desc:"Pomakni napred",insertlayer_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 novi sloj"},save:{save_desc:"Spremi",cancel_desc:"Odustani od svih promjena"},nonbreaking:{nonbreaking_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 razmak"},iespell:{download:"Provjera pravopisa nije postavljena. Postaviti sada?",iespell_desc:"Pokreni provjeru pravopisa"},advhr:{advhr_desc:"Vodoravna crta",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emocije",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Prona\u0111i/Zameni",search_desc:"Prona\u0111i",delta_width:"",delta_height:""},advimage:{image_desc:"\u0412\u043c\u0435\u0442\u043d\u0438/uredi sliku",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u0412\u043c\u0435\u0442\u043d\u0438/uredi atribute",ins_desc:"Unos",del_desc:"Brisanje",acronym_desc:"Akronim",abbr_desc:"Kratica",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Uredi CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Odaberi sve",paste_word_desc:"Zalepi iz Worda",paste_text_desc:"Zalepi kao obi\u010dni tekst",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Koristite CTRL+V na tipkovnici da zalepite tekst u prozor.",text_linebreaks:"Zadr\u017ei prelome",text_title:"Koristite CTRL+V na tipkovnici da zalepite tekst u prozor."},table:{cell:"\u0106elija",col:"Stupac",row:"Redak",del:"Izbri\u0161i tablicu",copy_row_desc:"Kopiraj redak",cut_row_desc:"Izre\u017ei redak",paste_row_after_desc:"Zalepi redak ispod",paste_row_before_desc:"Zalepi redak iznad",props_desc:"Svojstva tablice",cell_desc:"Svojstva \u0107elije",row_desc:"Svojstva retka",merge_cells_desc:"Spoji \u0107elije",split_cells_desc:"Razdvoji spojene \u0107elije",delete_col_desc:"Ukloni stupac",col_after_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 stupac desno",col_before_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 stupac levo",delete_row_desc:"Izbri\u0161i redak",row_after_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 redak ispod",row_before_desc:"\u0412\u043c\u0435\u0442\u043d\u0438 redak iznad",desc:"Nova tablica",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Promjene u dokumentu \u0107e biti izgubljene ako iza\u0111ete s ove stranice.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Uklju\u010di/isklju\u010di prikaz preko celog ekrana"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Svojstva dokumenta",delta_width:"",delta_height:""},template:{desc:"\u0412\u043c\u0435\u0442\u043d\u0438 sadr\u017eaj iz predlo\u017eak"},visualchars:{desc:"Vizuelni kontrolni znakovi uklju\u010deni/isklju\u010deni."},spellchecker:{desc:"Uklju\u010di/isklju\u010di provjeru pravopisa",menu:"Postavke provere pravopisa",ignore_word:"Zanemari re\u010d",ignore_words:"Zanemari sve",langs:"Jezici",wait:"Pri\u010dekajte...",sug:"Predlozi",no_sug:"Nema predloga",no_mpell:"Nije prona\u0111ena nijedna pravopisna gre\u0161ka."},pagebreak:{desc:"\u0412\u043c\u0435\u0442\u043d\u0438 prelom."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/lv.js0000644000175000017500000001420711526350525031532 0ustar frankiefrankietinyMCE.addI18n({lv:{common:{more_colors:"Vair\u0101k kr\u0101su",invalid_data:"K\u013c\u016bda: Ievad\u012btas neder\u012bgas v\u0113rt\u012bbas. T\u0101s ir atz\u012bm\u0113tas sarkan\u0101 kr\u0101s\u0101.",popup_blocked:"Atvainojiet, bet m\u0113s esam konstat\u0113ju\u0161i, ka J\u016bsu uzleco\u0161o logu blo\u0137\u0113t\u0101js ir atsp\u0113jojis logu, kas nodro\u0161ina programmas funkcionalit\u0101ti. Lai piln\u012bb\u0101 izmantotu \u0161o r\u012bku, Jums ir j\u0101atsl\u0113dz uzleco\u0161o logu blo\u0137\u0113tajs \u0161ai vietnei. ",clipboard_no_support:"\u0160obr\u012bd J\u016bsu p\u0101rl\u016bks neatbalsta \u0161o iesp\u0113ju, t\u0101 viet\u0101 l\u016bdzu izmantotjiet tastat\u016bras sa\u012bsin\u0101jumtausti\u0146us.",clipboard_msg:"Iesp\u0113ja Kop\u0113t/Izgriezt/Iekop\u0113t nav pieejama p\u0101rl\u016bkiem Mozilla and Firefox.\\nVai J\u016bs v\u0113laties uzzin\u0101t vair\u0101k par \u0161o probl\u0113mu?",not_set:"-- Nav nor\u0101d\u012bts --",class_name:"Klase",browse:"P\u0101rl\u016bkot",close:"Aizv\u0113rt",cancel:"Atcelt",update:"Atjaunin\u0101t",insert:"Ievietot",apply:"Apstiprin\u0101t",edit_confirm:"Vai tu v\u0113lies izmantot WYSIWYG \u0161im teksta laukam?"},contextmenu:{full:"Pilns",right:"Pa labi",center:"Centr\u0113ts",left:"Pa kreisi",align:"Novietojums"},insertdatetime:{day_short:"Sv\u0113,Pir,Otr,Tre,Cet,Pie,Ses,Sv\u0113",day_long:"Sv\u0113tdiena,Pirmdiena,Otrdiena,Tre\u0161diena,Ceturtdiena,Piektdiena,Sestdiena,Sv\u0113tdiena",months_short:"Jan,Feb,Mar,Apr,Mai,J\u016bn,J\u016bl,Aug,Sep,Okt,Nov,Dec",months_long:"Janv\u0101ris,Febru\u0101ris,Marts,Apr\u012blis,Maijs,J\u016bnijs,J\u016blijs,Augusts,Seprembris,Oktobris,Novembris,Decembris",inserttime_desc:"Ievietot laiku",insertdate_desc:"Ievietot datumu",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Druk\u0101t"},preview:{preview_desc:"Priek\u0161skat\u012bt"},directionality:{rtl_desc:"Virziens no lab\u0101s uz kreiso",ltr_desc:"Virziens no kreis\u0101s uz labo"},layer:{content:"Jauns sl\u0101nis...",absolute_desc:"Iestat\u012bt/Nov\u0101kt absol\u016bto novietojumu ",backward_desc:"Atpaka\u013c",forward_desc:"Uz priek\u0161u",insertlayer_desc:"Ievietot jaunu sl\u0101ni"},save:{save_desc:"Saglab\u0101t",cancel_desc:"Atcelt visas izmai\u0146as"},nonbreaking:{nonbreaking_desc:"Ievietot tuk\u0161uma simbolu"},iespell:{download:"ieSpell netika atrasts. Vai J\u016bs v\u0113laties to uzst\u0101d\u012bt?",iespell_desc:"Uzs\u0101kt pareizrakst\u012bbas p\u0101rbaudi"},advhr:{advhr_desc:"Horizont\u0101la sv\u012btra",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smaidi\u0146i",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Mekl\u0113t/Aizvietot",search_desc:"Mekl\u0113t",delta_width:"",delta_height:""},advimage:{image_desc:"Ievietot/Redi\u0123\u0113t att\u0113lu",delta_width:"",delta_height:""},advlink:{link_desc:"Ievietot/Redi\u0123\u0113t saiti",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Pielikt/redi\u0123\u0113t \u012bpa\u0161\u012bbas",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Sa\u012bsin\u0101jums",cite_desc:"Cit\u0101ts",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Iez\u012bm\u0113t visu",paste_word_desc:"Iekop\u0113t no Word",paste_text_desc:"Iekop\u0113t ka parasto tekstu",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Izmantojiet CTRL+V uz j\u016bsu tastat\u016bras lai iekop\u0113t tekstu log\u0101.",text_linebreaks:"Sagl\u0101b\u0101t l\u012bniju sadal\u012bt\u0101jus",text_title:"Izmantojiet CTRL+V uz j\u016bsu tastat\u016bras lai iekop\u0113t tekstu log\u0101."},table:{cell:"Aile",col:"St\u0101bs",row:"Rinda",del:"Izdz\u0113st tabulu",copy_row_desc:"Kop\u0113t tabulas rindu",cut_row_desc:"Izgriezt tabulas rindu",paste_row_after_desc:"Ielikt tabulas rindu aiz",paste_row_before_desc:"Ielikt tabulas rindu priek\u0161\u0101",props_desc:"Tabulas \u012bpa\u0161\u012bbas",cell_desc:"Tabulas ailes \u012bpa\u0161\u012bbas",row_desc:"Tabulas rindas \u012bpa\u0161\u012bbas",merge_cells_desc:"Apvienot tabulas ailes",split_cells_desc:"Sadal\u012bt apvienotas tabules ailes",delete_col_desc:"Izdz\u0113st stabu",col_after_desc:"Ielikt jaunu stabu aiz",col_before_desc:"Ielikt jaunu stabu priek\u0161\u0101",delete_row_desc:"Izdz\u0113st rindu",row_after_desc:"Ielikt jaunu rindu aiz",row_before_desc:"Ielikt jaunu rindu priek\u0161\u0101",desc:"Ielikt jaunu tabulu",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ml.js0000644000175000017500000002041311526350525031515 0ustar frankiefrankietinyMCE.addI18n({ml:{common:{more_colors:"\u0d15\u0d42\u0d1f\u0d41\u0d24\u0d32\u0d4d\u200d \u0d28\u0d3f\u0d31\u0d19\u0d4d\u0d19\u0d33\u0d4d\u200d",invalid_data:"\u0d2a\u0d3f\u0d34\u0d35\u0d41\u0d4d: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"\u0d2e\u0d41\u0d31\u0d3f\u0d15\u0d4d\u0d15\u0d32\u0d4d\u200d/\u0d2a\u0d15\u0d30\u0d4d\u200d\u0d24\u0d4d\u0d24\u0d32\u0d4d\u200d/\u0d12\u0d1f\u0d4d\u0d1f\u0d3f\u0d15\u0d4d\u0d15\u0d32\u0d4d\u200d \u0d0e\u0d28\u0d4d\u0d28\u0d3f\u0d35 \'\u0d2e\u0d4b\u0d38\u0d3f\u0d32\u0d4d\u0d32\'\u0d2f\u0d3f\u0d32\u0d41\u0d02 \'\u0d2b\u0d2f\u0d30\u0d4d\u200d\u0d2b\u0d4b\u0d15\u0d4d\u0d38\u0d4d\'\u0d32\u0d41\u0d02 \u0d32\u0d2d\u0d4d\u0d2f\u0d2e\u0d32\u0d4d\u0d32. \u200c\\n\u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d4d\u200d\u0d15\u0d4d\u0d15\u0d41 \u0d07\u0d24\u0d3f\u0d28\u0d46 \u0d15\u0d41\u0d31\u0d3f\u0d1a\u0d4d\u0d1a\u0d41\u0d4d \u0d15\u0d42\u0d1f\u0d41\u0d24\u0d32\u0d4d\u200d \u0d05\u0d31\u0d3f\u0d2f\u0d23\u0d4b ?",not_set:"-- Not set --",class_name:"\u0d24\u0d30\u0d02",browse:"\u0d2e\u0d47\u0d2f\u0d41\u0d15",close:"\u0d05\u0d1f\u0d15\u0d4d\u0d15\u0d41\u0d15",cancel:"\u0d35\u0d47\u0d23\u0d4d\u0d1f\u0d46\u0d28\u0d4d\u0d28\u0d41\u0d35\u0d46\u0d15\u0d4d\u0d15\u0d15",update:"\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d02 \u0d35\u0d30\u0d41\u0d24\u0d4d\u0d24\u0d41\u0d15",insert:"\u0d24\u0d3f\u0d30\u0d41\u0d15\u0d41\u0d15",apply:"\u0d2a\u0d4d\u0d30\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",edit_confirm:"\u0d08 \u0d0e\u0d34\u0d41\u0d24\u0d4d\u0d24\u0d3f\u0d1f\u0d02 \u0d15\u0d3e\u0d23\u0d41\u0d02\u0d35\u0d3f\u0d27\u0d02 \u0d0e\u0d34\u0d41\u0d24\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d23\u0d4b ?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"\u0d1e\u0d3e, \u0d24\u0d3f, \u0d1a\u0d4a, \u0d2c\u0d41, \u0d35\u0d4d\u0d2f\u0d3e, \u0d35\u0d46, \u0d36, \u0d1e\u0d3e",day_long:"\u0d1e\u0d3e\u0d2f\u0d30\u0d4d\u200d, \u0d24\u0d3f\u0d19\u0d4d\u0d15\u0d33\u0d4d\u200d, \u0d1a\u0d4a\u0d35\u0d4d\u0d35, \u0d2c\u0d41\u0d27\u0d28\u0d4d\u200d, \u0d35\u0d4d\u0d2f\u0d3e\u0d34\u0d02, \u0d35\u0d46\u0d33\u0d4d\u0d33\u0d3f, \u0d36\u0d28\u0d3f, \u0d1e\u0d3e\u0d2f\u0d30\u0d4d\u200d",months_short:"\u0d1c\u0d28\u0d41, \u0d2b\u0d46\u0d2c\u0d4d\u0d30\u0d41, \u0d2e\u0d3e\u0d30\u0d4d\u200d, \u0d0f\u0d2a\u0d4d\u0d30\u0d3f, \u0d2e\u0d46, \u0d1c\u0d41\u0d23\u0d4d\u200d, \u0d1c\u0d42\u0d32\u0d3e, \u0d06\u0d17, \u0d38\u0d46\u0d2a\u0d4d\u0d24\u0d02, \u0d12\u0d15\u0d4d\u0d1f\u0d4b, \u0d28\u0d35\u0d02, \u0d21\u0d3f\u0d38\u0d02",months_long:"\u0d1c\u0d28\u0d41\u0d35\u0d30\u0d3f, \u0d2b\u0d46\u0d2c\u0d4d\u0d30\u0d41\u0d35\u0d30\u0d3f, \u0d2e\u0d3e\u0d30\u0d4d\u200d\u0d1a\u0d4d\u0d1a\u0d41\u0d4d, \u0d0f\u0d2a\u0d4d\u0d30\u0d3f\u0d32\u0d4d\u200d, \u0d2e\u0d46\u0d2f\u0d4d, \u0d1c\u0d41\u0d23\u0d4d\u200d, \u0d1c\u0d42\u0d32\u0d3e\u0d2f\u0d4d, \u0d06\u0d17\u0d38\u0d4d\u0d24\u0d4d, \u0d38\u0d46\u0d2a\u0d4d\u0d24\u0d02\u0d2c\u0d30\u0d4d\u200d, \u0d12\u0d15\u0d4d\u0d1f\u0d4b\u0d2c\u0d30\u0d4d\u200d, \u0d28\u0d35\u0d02\u0d2c\u0d30\u0d4d\u200d, \u0d21\u0d3f\u0d38\u0d02\u0d2c\u0d30\u0d4d\u200d",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"\u0d26\u0d43\u0d36\u0d4d\u0d2f \u0d28\u0d3f\u0d2f\u0d28\u0d4d\u0d24\u0d4d\u0d30\u0d23 \u0d05\u0d15\u0d4d\u0d37\u0d30\u0d19\u0d4d\u0d19\u0d33\u0d4d\u200d \u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d41\u0d15."},spellchecker:{desc:"\u0d05\u0d15\u0d4d\u0d37\u0d30\u0d2a\u0d30\u0d3f\u0d36\u0d4b\u0d27\u0d28 \u0d28\u0d3f\u0d2f\u0d28\u0d4d\u0d24\u0d4d\u0d30\u0d23\u0d02",menu:"\u0d05\u0d15\u0d4d\u0d37\u0d30\u0d2a\u0d30\u0d3f\u0d36\u0d4b\u0d27\u0d28\u0d3e \u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d33\u0d4d\u200d",ignore_word:"\u0d35\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d4d \u0d05\u0d35\u0d17\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d42",ignore_words:"\u0d0e\u0d32\u0d4d\u0d32\u0d3e\u0d02 \u0d05\u0d35\u0d17\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d42",langs:"\u0d2d\u0d3e\u0d37\u0d15\u0d33\u0d4d\u200d",wait:"\u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d15\u0d3e\u0d24\u0d4d\u0d24\u0d41\u0d28\u0d3f\u0d32\u0d4d\u0d15\u0d41...",sug:"\u0d05\u0d2d\u0d3f\u0d2a\u0d4d\u0d30\u0d3e\u0d2f\u0d19\u0d4d\u0d19\u0d33\u0d4d\u200d",no_sug:"\u0d05\u0d2d\u0d3f\u0d2a\u0d4d\u0d30\u0d3e\u0d2f\u0d2e\u0d3f\u0d32\u0d4d\u0d32",no_mpell:"\u0d05\u0d15\u0d4d\u0d37\u0d30\u0d24\u0d4d\u0d24\u0d46\u0d31\u0d4d\u0d31\u0d3f\u0d32\u0d4d\u0d32."},pagebreak:{desc:"\u0d2a\u0d47\u0d1c\u0d41\u0d4d \u0d24\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/nb.js0000644000175000017500000001233411526350525031507 0ustar frankiefrankietinyMCE.addI18n({nb:{common:{more_colors:"Flere farger",invalid_data:"Feil: Ugyldige verdier er skrevet inn, disse er merket med r\u00f8dt.",popup_blocked:"Beklager, det er registrert at du har en popup-sperre aktivert i nettleseren. Du m\u00e5 oppheve popup-sperren for nettstedet for \u00e5 f\u00e5 tilgang til dette verkt\u00f8yet",clipboard_no_support:"For tiden ikke st\u00f8ttet av din nettleser, benytt tastatursnarveier i stedet.",clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikke i Mozilla og Firefox. Vil du vite mer om dette?",not_set:"--ikke satt--",class_name:"Klasse",browse:"Bla gjennom",close:"Stop",cancel:"Avbryt",update:"Oppdater",insert:"Sett inn",apply:"Legg til",edit_confirm:"Vil du benytte WYSIWYG-editoren for dette tekstfeltet?"},contextmenu:{full:"Full",right:"H\u00f8yre",center:"Midtstill",left:"Venstre",align:"Justering"},insertdatetime:{day_short:"s\u00f8n,man,tir,ons,tor,fre,l\u00f8r,s\u00f8n",day_long:"s\u00f8ndag,mandag,tirsdag,onsdag,torsdag,fredag,l\u00f8rdag,s\u00f8ndag",months_short:"jan,feb,mar,apr,mai,jun,jul,aug,sep,oct,nov,des",months_long:"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember",inserttime_desc:"Sett inn tidspunkt",insertdate_desc:"Sett inn dato",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Skriv u"},preview:{preview_desc:"Forh\u00e5ndsvisning"},directionality:{rtl_desc:"Retning h\u00f8yre mot venstre",ltr_desc:"Retning venstre mot h\u00f8yre"},layer:{content:"Nytt lag...",absolute_desc:"Sl\u00e5 p\u00e5/av absolutt plassering",backward_desc:"Flytt bakover",forward_desc:"Flytt framover",insertlayer_desc:"Sett inn nytt lag"},save:{save_desc:"Lagre",cancel_desc:"Kanseller alle endringer"},nonbreaking:{nonbreaking_desc:"Sett inn hardt mellomrom"},iespell:{download:"ieSpell ikke funnet. \u00d8nsker du \u00e5 installere ieSpell n\u00e5?",iespell_desc:"Kj\u00f8rer rettskrivningskontroll"},advhr:{advhr_desc:"Horisontal linje",delta_height:"",delta_width:""},emotions:{emotions_desc:"Hum\u00f8rfjes",delta_height:"",delta_width:""},searchreplace:{replace_desc:"S\u00f8k/Erstatt",search_desc:"S\u00f8k",delta_width:"",delta_height:""},advimage:{image_desc:"Sett inn / endre bilde",delta_width:"",delta_height:""},advlink:{link_desc:"Sett inn / endre lenke",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Sett inn / endre Egenskaper",ins_desc:"Innsetting",del_desc:"Sletting",acronym_desc:"Akronym",abbr_desc:"Forkortelse",cite_desc:"Sitat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Rediger CSS-stil",delta_height:"",delta_width:""},paste:{selectall_desc:"Marker al",paste_word_desc:"Lim inn fra Word",paste_text_desc:"Lim inn som vanlig tekst",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Bruk CTRL+V p\u00e5 tastaturet for \u00e5 lime inn i dette vinduet.",text_linebreaks:"Behold tekstbryting",text_title:"Bruk CTRL+V p\u00e5 tastaturet for \u00e5 lime inn i dette vinduet."},table:{cell:"Celle",col:"Kolonne",row:"Rad",del:"Slett tabell",copy_row_desc:"Kopier rad",cut_row_desc:"Fjern rad",paste_row_after_desc:"Lim inn rad etter",paste_row_before_desc:"Lim inn rad foran",props_desc:"Tabellegenskaper",cell_desc:"Celleegenskaper",row_desc:"Radegenskaper",merge_cells_desc:"Sl\u00e5 sammen celler",split_cells_desc:"Del celler",delete_col_desc:"Fjern kolonne",col_after_desc:"Sett inn kolonne etter",col_before_desc:"Sett inn kolonne foran",delete_row_desc:"Fjern rad",row_after_desc:"Sett inn rad etter etter",row_before_desc:"Sett inn rad foran",desc:"Sett inn ny tabell",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Endringene du gjorde g\u00e5r tapt dersom du velger \u00e5 forlate denne siden!",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Skift til/fra fullskjermmodus"},media:{edit:"Endre inkludert objekt",desc:"Sett inn / rediger inkludert objekt",delta_height:"",delta_width:""},fullpage:{desc:"Dokumentegenskaper",delta_width:"",delta_height:""},template:{desc:"Sett inn forh\u00e5ndsdefinert malinnhold"},visualchars:{desc:"Visuelle kontrolltegn p\u00e5/av"},spellchecker:{desc:"Stavekontroll p\u00e5/av",menu:"Vis meny",ignore_word:"Ignorer ord",ignore_words:"Ignorer alt",langs:"Spr\u00e5k",wait:"Vennligst vent...",sug:"Forslag",no_sug:"Ingen forslag",no_mpell:"Ingen stavefeil funnet"},pagebreak:{desc:"Sett inn sideskift"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/mn.js0000644000175000017500000003413211526350525031522 0ustar frankiefrankietinyMCE.addI18n({mn:{common:{more_colors:"\u0411\u0443\u0441\u0430\u0434 \u04e9\u043d\u0433\u04e9",invalid_data:"\u0410\u043b\u0434\u0430\u0430: \u0422\u0430 \u0445\u04af\u0447\u0438\u043d\u0433\u04af\u0439 \u0443\u0442\u0433\u0430 \u043e\u0440\u0443\u0443\u043b\u0441\u0430\u043d. (\u0443\u043b\u0430\u0430\u043d\u0430\u0430\u0440 \u0442\u044d\u043c\u0434\u044d\u0433\u043b\u044d\u0441\u044d\u043d).",popup_blocked:"\u0425\u0430\u0440\u0430\u043c\u0441\u0430\u043b\u0442\u0430\u0439 \u043d\u044c \u0442\u0430\u043d\u044b \u043f\u043e\u043f\u0430\u043f \u0445\u0430\u0430\u043b\u0442 \u044d\u043d\u044d \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0434 \u0448\u0430\u0430\u0440\u0434\u043b\u0430\u0433\u0430\u0442\u0430\u0439 \u0446\u043e\u043d\u0445\u044b\u0433 \u0445\u0430\u0430\u043b\u0430\u0430. \u0411\u04af\u0440\u044d\u043d \u0434\u04af\u04af\u0440\u044d\u043d \u0430\u0436\u0438\u043b\u043b\u0430\u0433\u0430\u0430\u0433 \u0445\u0430\u043d\u0433\u0430\u0445\u044b\u0433 \u0445\u04af\u0441\u0432\u044d\u043b \u043f\u043e\u043f\u0430\u043f \u0445\u0430\u0430\u043b\u0442\u0430\u0430 \u0438\u0434\u044d\u0432\u0445\u0433\u04af\u0439\u0436\u04af\u04af\u043b\u043d\u044d \u04af\u04af.",clipboard_no_support:"\u041e\u0434\u043e\u043e\u0433\u043e\u043e\u0440 \u0442\u0430\u043d\u044b \u0445\u04e9\u0442\u04e9\u0447 \u0434\u044d\u044d\u0440 \u0434\u044d\u043c\u0436\u0438\u0433\u0434\u044d\u044d\u0433\u04af\u0439 \u0431\u0430\u0439\u043d\u0430. \u0422\u0430 \u04af\u04af\u043d\u0438\u0439 \u043e\u0440\u043e\u043d\u0434 \u0442\u043e\u0432\u0447\u0438\u043b\u0431\u043e\u0440 \u0445\u044d\u0440\u044d\u0433\u043b\u044d\u043d\u044d \u04af\u04af.",clipboard_msg:"\u0425\u0443\u0443\u043b\u0430\u0445, \u0442\u0430\u0441\u043b\u0430\u043d \u0430\u0432\u0430\u0445 \u0431\u0443\u0443\u043b\u0433\u0430\u0445 \u043d\u044c \u041c\u043e\u0437\u0438\u043b\u043b\u0430 \u0424\u0430\u0439\u0440\u0444\u043e\u043a\u0441 \u0434\u044d\u044d\u0440 \u0431\u043e\u043b\u043e\u043c\u0436\u0433\u04af\u0439.\\n\u0422\u0430 \u044d\u043d\u044d \u0430\u0441\u0443\u0443\u0434\u043b\u044b\u043d \u0442\u0430\u043b\u0430\u0430\u0440 \u0434\u044d\u043b\u0433\u044d\u0440\u044d\u043d\u0433\u04af\u0439 \u043c\u044d\u0434\u044d\u0445\u0438\u0439\u0433 \u0445\u04af\u0441\u044d\u0436 \u0431\u0430\u0439\u043d\u0430 \u0443\u0443?",not_set:"-- \u041e\u043b\u0433\u043e\u0433\u0434\u043e\u043e\u0433\u04af\u0439 --",class_name:"\u0410\u043d\u0433\u0438",browse:"\u0413\u04af\u0439\u043b\u0433\u044d\u043d \u04af\u0437\u044d\u0445",close:"\u0425\u0430\u0430\u0445",cancel:"\u0426\u0443\u0446\u043b\u0430\u0445",update:"\u0428\u0438\u043d\u044d\u0447\u043b\u044d\u0445",insert:"\u041e\u0440\u0443\u0443\u043b\u0430\u0445",apply:"\u0425\u044d\u0440\u044d\u0433\u043b\u044d\u0445",edit_confirm:"\u0422\u0430 \u044d\u043d\u044d \u0431\u0438\u0447\u0432\u044d\u0440\u0438\u0439\u043d \u043c\u0443\u0436\u0438\u0439\u0433 WYSIWYG \u0437\u0430\u0441\u0432\u0430\u0440\u043b\u0430\u0445\u044b\u0433 \u0445\u04af\u0441\u044d\u0436 \u0431\u0430\u0439\u043d\u0430 \u0443\u0443?"},contextmenu:{full:"\u0422\u044d\u0433\u0448\u0438\u043b\u0441\u044d\u043d",right:"\u0411\u0430\u0440\u0443\u0443\u043d",center:"\u0414\u0443\u043d\u0434",left:"\u0417\u04af\u04af\u043d",align:"\u0416\u0438\u0433\u0434\u0440\u04af\u04af\u043b\u044d\u043b\u0442"},insertdatetime:{day_short:"\u041d\u044f,\u0414\u0430,\u041c\u044f,\u041b\u0445,\u041f\u04af,\u0411\u0430,\u0411\u044f,\u041d\u044f",day_long:"\u041d\u044f\u043c,\u0414\u0430\u0432\u0430\u0430,\u041c\u044f\u0433\u043c\u0430\u0440,\u041b\u0445\u0430\u0433\u0432\u0430,\u041f\u04af\u0440\u044d\u0432,\u0411\u0430\u0430\u0441\u0430\u043d,\u0411\u044f\u043c\u0431\u0430,\u041d\u044f\u043c",months_short:"\u0425\u0443\u043b,\u04ae\u0445\u044d,\u0411\u0430\u0440,\u0422\u0443\u0443,\u041b\u0443\u0443,\u041c\u043e\u0433,\u041c\u043e\u0440,\u0425\u043e\u043d,\u0411\u0438\u0447,\u0422\u0430\u0445,\u041d\u043e\u0445,\u0413\u0430\u0445",months_long:"\u0425\u0443\u043b\u0433\u0430\u043d\u0430,\u04ae\u0445\u044d\u0440,\u0411\u0430\u0440,\u0422\u0443\u0443\u043b\u0430\u0439,\u041b\u0443\u0443,\u041c\u043e\u0433\u043e\u0439,\u041c\u043e\u0440\u044c,\u0425\u043e\u043d\u044c,\u0411\u0438\u0447,\u0422\u0430\u0445\u0438\u0430,\u041d\u043e\u0445\u043e\u0439,\u0413\u0430\u0445\u0430\u0439",inserttime_desc:"\u0425\u0443\u0433\u0430\u0446\u0430\u0430 \u043e\u0440\u0443\u0443\u043b\u0430\u0445",insertdate_desc:"\u041e\u0433\u043d\u043e\u043e \u043e\u0440\u0443\u0443\u043b\u0430\u0445",time_fmt:"%H:%M:%S",date_fmt:"%Y.%m.%d"},print:{print_desc:"\u0425\u044d\u0432\u043b\u044d\u0445"},preview:{preview_desc:"\u041d\u044f\u0433\u0442\u043b\u0430\u0445"},directionality:{rtl_desc:"\u0411\u0430\u0440\u0443\u0443\u043d \u0437\u04af\u04af\u043d \u0431\u0438\u0447\u0438\u043b\u0442",ltr_desc:"\u0417\u04af\u04af\u043d\u044d\u044d\u0441 \u0431\u0430\u0440\u0443\u0443\u043d \u0431\u0438\u0447\u0438\u043b\u0442"},layer:{content:"\u0428\u0438\u043d\u044d \u0434\u0430\u0432\u0445\u0430\u0440\u0433\u0430...",absolute_desc:"\u0410\u0431\u0441\u043e\u043b\u044e\u0442 \u0431\u0430\u0439\u0440\u0448\u0443\u0443\u043b\u0430\u043b\u0442",backward_desc:"\u0426\u0430\u0430\u0448\u043b\u0443\u0443\u043b\u0430\u0445",forward_desc:"\u041d\u0430\u0430\u0448\u043b\u0443\u0443\u043b\u0430\u0445",insertlayer_desc:"\u0428\u0438\u043d\u044d \u0434\u0430\u0432\u0445\u0430\u0440\u0433\u0430 \u043e\u0440\u0443\u0443\u043b\u0430\u0445"},save:{save_desc:"\u0425\u0430\u0434\u0433\u0430\u043b\u0430\u0445",cancel_desc:"\u0411\u04af\u0445 \u04e9\u04e9\u0440\u0447\u043b\u04e9\u043b\u0442\u0438\u0439\u0433 \u0445\u0430\u044f\u0445"},nonbreaking:{nonbreaking_desc:"\u0425\u0430\u043c\u0433\u0430\u0430\u043b\u0430\u043b\u0442\u0442\u0430\u0439 \u0445\u043e\u043e\u0441\u043e\u043d \u0437\u0430\u0439 \u043e\u0440\u0443\u0443\u043b\u0430\u0445"},iespell:{download:"ieSpell \u043e\u043b\u0434\u0441\u043e\u043d\u0433\u04af\u0439. \u0422\u0430 \u0441\u0443\u0443\u043b\u0433\u0430\u0445\u044b\u0433 \u0445\u04af\u0441\u044d\u0436 \u0431\u0430\u0439\u043d\u0430 \u0443\u0443?",iespell_desc:"\u0414\u04af\u0440\u043c\u0438\u0439\u043d \u0430\u043b\u0434\u0430\u0430 \u0448\u0430\u043b\u0433\u0430\u043b\u0442"},advhr:{advhr_desc:"\u0422\u0443\u0441\u0433\u0430\u0430\u0440\u043b\u0430\u0433\u0447",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0421\u044d\u0442\u0433\u044d\u043b \u0445\u04e9\u0434\u043b\u04e9\u043b",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0425\u0430\u0439\u0445/\u043e\u0440\u043b\u0443\u0443\u043b\u0430\u0445",search_desc:"\u0425\u0430\u0439\u0445",delta_width:"",delta_height:""},advimage:{image_desc:"\u0417\u0443\u0440\u0430\u0433 \u043e\u0440\u0443\u0443\u043b\u0430\u0445/\u043e\u0440\u043b\u0443\u0443\u043b\u0430\u0445",delta_width:"",delta_height:""},advlink:{link_desc:"\u0425\u043e\u043b\u0431\u043e\u043e\u0441 \u043e\u0440\u0443\u0443\u043b\u0430\u0445/\u0437\u0430\u0441\u0430\u0445",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u0410\u0442\u0440\u0438\u0431\u0443\u0442 \u043e\u0440\u0443\u0443\u043b\u0430\u0445/\u0437\u0430\u0441\u0430\u0445",ins_desc:"\u041e\u0440\u0441\u043e\u043d \u0431\u0438\u0447\u0432\u044d\u0440",del_desc:"\u0423\u0441\u0442\u0441\u0430\u043d \u0431\u0438\u0447\u0432\u044d\u0440 Text",acronym_desc:"\u0422\u043e\u0432\u0447\u0438\u043b\u0441\u043e\u043d \u04af\u0433",abbr_desc:"\u0422\u043e\u0432\u0447\u043b\u043e\u043b",cite_desc:"\u0418\u0448\u043b\u044d\u043b",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS-Styles \u0437\u0430\u0441\u0430\u0445",delta_height:"",delta_width:""},paste:{selectall_desc:"\u0411\u04af\u0433\u0434\u0438\u0439\u0433 \u0441\u043e\u043d\u0433\u043e\u0445",paste_word_desc:"\u0425\u044d\u043b\u0431\u044d\u0440\u0436\u04af\u04af\u043b\u044d\u043b\u0442\u0442\u044d\u0439 \u0431\u0443\u0443\u043b\u0433\u0430\u0445 (Word-\u0441)",paste_text_desc:"\u042d\u043d\u0433\u0438\u0439\u043d \u0431\u0438\u0447\u0432\u044d\u0440\u044d\u044d\u0440 \u0431\u0443\u0443\u043b\u0433\u0430\u0445",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u0422\u0430 \u0431\u0438\u0447\u0432\u044d\u0440 \u043e\u0440\u0443\u0443\u043b\u0430\u0445\u044b\u0433 \u0445\u04af\u0441\u0432\u044d\u043b Ctrl+V \u0434\u044d\u044d\u0440 \u0434\u0430\u0440\u043d\u0430 \u0443\u0443.",text_linebreaks:"\u041c\u04e9\u0440 \u0442\u0430\u0441\u043b\u0430\u043b\u0442\u044b\u0433 \u04af\u043b\u0434\u044d\u044d\u043d\u044d",text_title:"\u0422\u0430 \u0431\u0438\u0447\u0432\u044d\u0440 \u043e\u0440\u0443\u0443\u043b\u0430\u0445\u044b\u0433 \u0445\u04af\u0441\u0432\u044d\u043b Ctrl+V \u0434\u044d\u044d\u0440 \u0434\u0430\u0440\u043d\u0430 \u0443\u0443."},table:{cell:"\u041d\u04af\u0434",col:"\u0411\u0430\u0433\u0430\u043d\u0430",row:"\u041c\u04e9\u0440",del:"\u0425\u04af\u0441\u043d\u044d\u0433\u0442 \u0443\u0441\u0442\u0433\u0430\u0445",copy_row_desc:"\u041c\u04e9\u0440 \u0445\u0443\u0443\u043b\u0430\u0445",cut_row_desc:"\u041c\u04e9\u0440 \u0442\u0430\u0441\u0434\u0430\u0436 \u0430\u0432\u0430\u0445 \u0443\u0443?",paste_row_after_desc:"\u0417\u0430\u0432\u0441\u0440\u044b\u043d \u0445\u0430\u0434\u0433\u0430\u043b\u0430\u0433\u0447\u0430\u0430\u0441 \u043c\u04e9\u0440\u0438\u0439\u0433 \u0434\u043e\u043e\u0440 \u043d\u044c \u0431\u0443\u0443\u043b\u0433\u0430\u0445",paste_row_before_desc:"\u0417\u0430\u0432\u0441\u0440\u044b\u043d \u0445\u0430\u0434\u0433\u0430\u043b\u0430\u0433\u0447\u0430\u0430\u0441 \u043c\u04e9\u0440\u0438\u0439\u0433 \u0434\u044d\u044d\u0440 \u043d\u044c \u0431\u0443\u0443\u043b\u0433\u0430\u0445",props_desc:"\u0425\u04af\u0441\u043d\u044d\u0433\u0442\u0438\u0439\u043d \u0448\u0438\u043d\u0436\u04af\u04af\u0434",cell_desc:"\u041d\u04af\u0434\u043d\u0438\u0439 \u0448\u0438\u043d\u0436\u04af\u04af\u0434",row_desc:"\u041c\u04e9\u0440\u0438\u0439\u043d \u0448\u0438\u043d\u0436\u04af\u04af\u0434",merge_cells_desc:"\u041d\u04af\u0434 \u043d\u044d\u0433\u0442\u0433\u044d\u0445",split_cells_desc:"\u041d\u044d\u0433\u0442\u0433\u044d\u0441\u044d\u043d \u043d\u04af\u0434\u0438\u0439\u0433 \u0441\u0430\u043b\u0433\u0430\u0445",delete_col_desc:"\u0411\u0430\u0433\u0430\u043d\u0430 \u0443\u0441\u0442\u0433\u0430\u0445",col_after_desc:"\u0411\u0430\u0440\u0443\u0443\u043d \u0442\u0430\u043b\u0434 \u043d\u044c \u0431\u0430\u0433\u0430\u043d\u0430 \u043e\u0440\u0443\u0443\u043b\u0430\u0445",col_before_desc:"\u0417\u04af\u04af\u043d \u0442\u0430\u043b\u0434 \u043d\u044c \u0431\u0430\u0433\u0430\u043d\u0430 \u043e\u0440\u0443\u0443\u043b\u0430\u0445",delete_row_desc:"\u041c\u04e9\u0440 \u0443\u0441\u0442\u0433\u0430\u0445",row_after_desc:"\u0414\u043e\u043e\u0440 \u043d\u044c \u043c\u04e9\u0440 \u043e\u0440\u0443\u0443\u043b\u0430\u0445",row_before_desc:"\u0414\u044d\u044d\u0440 \u043d\u044c \u043c\u04e9\u0440 \u043e\u0440\u0443\u0443\u043b\u0430\u0445",desc:"\u0425\u04af\u0441\u043d\u044d\u0433\u0442 \u04af\u04af\u0441\u0433\u044d\u0445",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u0425\u044d\u0440\u044d\u0432 \u0442\u0430 \u0445\u0443\u0443\u0434\u0441\u044b\u0433 \u043e\u0440\u0445\u0438\u0432\u043e\u043b \u0442\u0430\u043d\u044b \u04e9\u04e9\u0440\u0447\u043b\u04e9\u043b\u0442\u04af\u04af\u0434 \u0445\u0430\u044f\u0433\u0434\u0430\u043d\u0430.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u0414\u044d\u043b\u0433\u044d\u0446 \u0434\u04af\u04af\u0440\u044d\u043d"},media:{edit:"\u041c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0434\u0438\u0430 \u0448\u0438\u0433\u0442\u0433\u044d\u044d \u0437\u0430\u0441\u0430\u0445",desc:"\u041c\u0443\u043b\u044c\u0442\u0438\u043c\u0435\u0434\u0438\u0430 \u0448\u0438\u0433\u0442\u0433\u044d\u0445/\u0437\u0430\u0441\u0430\u0445",delta_height:"",delta_width:""},fullpage:{desc:"\u0411\u0430\u0440\u0438\u043c\u0442\u044b\u043d \u0442\u043e\u0434\u0440\u0443\u0443\u043b\u0433\u0430",delta_width:"",delta_height:""},template:{desc:"\u04e8\u043c\u043d\u04e9 \u0431\u044d\u043b\u0442\u0433\u044d\u0441\u044d\u043d \u0445\u044d\u0432\u0438\u0439\u043d \u0430\u0433\u0443\u0443\u043b\u0433\u044b\u0433 \u0431\u0443\u0443\u043b\u0433\u0430\u0445"},visualchars:{desc:"\u0423\u0434\u0438\u0440\u0434\u0430\u0445 \u0442\u044d\u043c\u0434\u044d\u0433\u0442 \u0445\u0430\u0440\u0443\u0443\u043b\u0430\u0445/\u044d\u0441 \u0445\u0430\u0440\u0443\u0443\u043b\u0430\u0445."},spellchecker:{desc:"\u0414\u04af\u0440\u043c\u0438\u0439\u043d \u0430\u043b\u0434\u0430\u0430 \u0448\u0430\u043b\u0433\u0430\u0433\u0447 \u043d\u044d\u044d\u043b\u0442\u0442\u044d\u0439/\u0445\u0430\u0430\u043b\u0442\u0442\u0430\u0439",menu:"\u0414\u04af\u0440\u043c\u0438\u0439\u043d \u0430\u043b\u0434\u0430\u0430 \u0448\u0430\u043b\u0433\u0430\u0433\u0447\u0438\u0439\u043d \u0442\u043e\u0445\u0438\u0440\u0433\u043e\u043e",ignore_word:"\u04ae\u0433 \u04af\u043b \u0445\u044d\u0440\u044d\u0433\u0441\u044d\u0445",ignore_words:"\u0411\u04af\u0433\u0434\u0438\u0439\u0433 \u04af\u043b \u0445\u044d\u0440\u044d\u0433\u0441\u044d\u0445",langs:"\u0425\u044d\u043b",wait:"\u0422\u04af\u0440 \u0445\u04af\u043b\u044d\u044d\u043d\u044d \u04af\u04af...",sug:"\u0421\u0430\u043d\u0430\u043b",no_sug:"\u0421\u0430\u043d\u0430\u043b \u0430\u043b\u0433\u0430",no_mpell:"\u0414\u04af\u0440\u043c\u0438\u0439\u043d \u0430\u043b\u0434\u0430\u0430 \u043e\u043b\u0434\u0441\u043e\u043d\u0433\u04af\u0439."},pagebreak:{desc:"\u0425\u0443\u0443\u0434\u0430\u0441 \u0442\u0430\u0441\u043b\u0430\u043b\u0442 \u043e\u0440\u0443\u0443\u043b\u0430\u0445."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ms.js0000644000175000017500000001215411526350525031527 0ustar frankiefrankietinyMCE.addI18n({ms:{common:{more_colors:"Warna lain-lain",invalid_data:"Ralat: Nilai dimasukkan tidak sah, lihat tanda merah.",popup_blocked:"Maaf, kami dapati \"popup-blocker\" telah melumpuhkan tetingkap yang memberikan fungsi kepada perisian anda. Anda perlu mematikan \"popup-blocker\" untuk laman web ini bagi menggunakan semua alatan.",clipboard_no_support:"Perisian browser anda tidak disokong pada masa ini, sila guna papan kekunci.",clipboard_msg:"Salin/Potong/Tempel tidak disediakan untuk Mozilla dan Firefox.\\nAdakah anda mahu informasi lanjut tentang isu ini?",not_set:"-- Tidak set --",class_name:"Kelas",browse:"Semak seimbas",close:"Tutup",cancel:"Batal",update:"Kemaskini",insert:"Sisip",apply:"Guna",edit_confirm:"Guna WYSIWYG mod untuk \"textarea\" ini?"},contextmenu:{full:"Penuh",right:"Kanan",center:"Tengah",left:"Kiri",align:"Penyelarian"},insertdatetime:{day_short:"Aha,Isn,Sel,Rab,Kha,Jum,Sab,Aha",day_long:"Ahad,Isnin,Selasa,Rabu,Khamis,Jumaat,Sabtu,Ahad",months_short:"Jan,Feb,Mac,Apr,Mei,Jun,Jul,Ogo,Sep,Okt,Nov,Dis",months_long:"Januari,Febuari,Mac,April,Mei,Jun,Julai,Ogos,September,Oktober,November,Disember",inserttime_desc:"Sisip masa",insertdate_desc:"Sisip tarikh",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Cetak"},preview:{preview_desc:"Pratonton"},directionality:{rtl_desc:"Arah kanan ke kiri",ltr_desc:"Arah kiri ke kanan"},layer:{content:"Lapisan baru...",absolute_desc:"Alih posisi mutlak",backward_desc:"Gerak kebelakang",forward_desc:"Gerak kehadapan",insertlayer_desc:"Sisip lapisan baru"},save:{save_desc:"Simpan",cancel_desc:"Batal semua pertukaran"},nonbreaking:{nonbreaking_desc:"Masukkan aksara ruang [nbsp]"},iespell:{download:"ieSpell tiada. Pasang sekarang?",iespell_desc:"Larikan pembetulan ejaan"},advhr:{advhr_desc:"Garis mengufuk",delta_height:"",delta_width:""},emotions:{emotions_desc:"Simbol Emosi",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Cari/Ganti",search_desc:"Cari",delta_width:"",delta_height:""},advimage:{image_desc:"Sisip/sunting imej",delta_width:"",delta_height:""},advlink:{link_desc:"Sisip/sunting pautan",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Masukkan/Sunting Ciri-ciri",ins_desc:"Kemasukan",del_desc:"Pemadaman",acronym_desc:"Akronim",abbr_desc:"Singkatan",cite_desc:"Kutipan",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Sunting Gaya CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Pilih semua",paste_word_desc:"Tempel dari Word",paste_text_desc:"Tempel sebagai teks",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Guna CTRL+V pada papan kekunci anda untuk teks ke dalam tetingkap.",text_linebreaks:"Biarkan garisan pemisah",text_title:"Guna CTRL+V pada papan kekunci anda untuk Tempel teks ke dalam tetingkap."},table:{cell:"Sel",col:"Kolum",row:"Row",del:"Padam jadual",copy_row_desc:"Salin jadual row",cut_row_desc:"Potong jadual row",paste_row_after_desc:"Tempel jadual row selepasnya",paste_row_before_desc:"Tempel jadual row sebelumnya",props_desc:"Alatan jadual",cell_desc:"Alatan jadual sel",row_desc:"Alatan jadual row",merge_cells_desc:"Gabung sel jadual",split_cells_desc:"Bahagi sel jadual",delete_col_desc:"Alih kolum",col_after_desc:"Masukkan kolum selepasnya",col_before_desc:"Masukkan kolum sebelumnya",delete_row_desc:"Padam row",row_after_desc:"Masukkan row selepasnya",row_before_desc:"Masukkan row sebelumnya",desc:"Masukkan jadual baru",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Pertukaran akan terbatal sekiranya anda meninggalkan halaman ini.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Alih mod skrin penuh"},media:{edit:"Sunting media",desc:"Masukkan / sunting media",delta_height:"",delta_width:""},fullpage:{desc:"Alatan dokumen",delta_width:"",delta_height:""},template:{desc:"Masukkan pra takrifan kandungan templet"},visualchars:{desc:"Pengendali grafik huruf Buka/Tutup."},spellchecker:{desc:"Alih pembetul perkataan",menu:"Alatan pembetul perkataan",ignore_word:"Endahkan perkataan",ignore_words:"Endahkan kesemuanya",langs:"Bahasa-bahasa",wait:"Sila tunggu...",sug:"Cadangan",no_sug:"Tiada cadangan",no_mpell:"Tiada kesalahan ejaan."},pagebreak:{desc:"Masukkan penghenti-halaman."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/nl.js0000644000175000017500000001226711526350525031526 0ustar frankiefrankietinyMCE.addI18n({nl:{common:{more_colors:"Meer kleuren",invalid_data:"Fout: Er zijn ongeldige waardes ingevoerd, deze zijn rood gemarkeerd.",popup_blocked:"U zult uw popup-blocker tijdelijk moeten uitschakelen voor deze website om gebruik te kunnen maken van alle functies van deze teksteditor.",clipboard_no_support:"Kopi\u00ebren/knippen/plakken wordt niet ondersteund door uw browser, gebruik hiervoor de sneltoetsen.",clipboard_msg:"Kopi\u00ebren/knippen/plakken is niet beschikbaar in Mozilla en Firefox.\\nWilt u meer informatie over deze beperking?",not_set:"- Standaard -",class_name:"Klasse",browse:"Bladeren",close:"Sluiten",cancel:"Annuleren",update:"Bijwerken",insert:"Invoegen",apply:"Toepassen",edit_confirm:"Weet u zeker dat u tekst in WYSIWYG mode wilt bewerken in dit tekstveld?"},contextmenu:{full:"Uitvullen",right:"Rechts",center:"Centreren",left:"Links",align:"Uitlijning"},insertdatetime:{day_short:"zo,ma,di,wo,do,vr,za,zo",day_long:"Zondag,Maandag,Dinsdag,Woensdag,Donderdag,Vrijdag,Zaterdag,Zondag",months_short:"Jan,Feb,Mar,Apr,Mei,Jun,Jul,Aug,Sep,Okt,Nov,Dec",months_long:"Januari,Februari,Maart,April,Mei,Juni,Juli,Augustus,September,Oktober,November,December",inserttime_desc:"Tijd invoegen",insertdate_desc:"Datum invoegen",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Afdrukken"},preview:{preview_desc:"Voorbeeld"},directionality:{rtl_desc:"Van rechts naar links",ltr_desc:"Van links naar rechts"},layer:{content:"Nieuwe laag...",absolute_desc:"Absoluut positioneren inschakelen",backward_desc:"Vorige laag",forward_desc:"Volgende laag",insertlayer_desc:"Nieuwe laag invoegen"},save:{save_desc:"Opslaan",cancel_desc:"Alle wijzigingen annuleren"},nonbreaking:{nonbreaking_desc:"Open ruimte invoegen"},iespell:{download:"ieSpell niet gevonden. Wilt u deze nu installeren?",iespell_desc:"Spellingcontrole"},advhr:{advhr_desc:"Scheidingslijn",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emoties",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Zoeken/Vervangen",search_desc:"Zoeken",delta_width:"",delta_height:""},advimage:{image_desc:"Afbeelding invoegen/bewerken",delta_width:"",delta_height:""},advlink:{link_desc:"Link invoegen/bewerken",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Attributen invoegen/bewerken",ins_desc:"Ingevoegd",del_desc:"Verwijderd",acronym_desc:"Synoniem",abbr_desc:"Afkorting",cite_desc:"Citaat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS Stijl bewerken",delta_height:"",delta_width:""},paste:{plaintext_mode:"Plakken is nu in plattetekstmoduse. Klik nog een keer om terug te gaan naar normaal plakken.",plaintext_mode_sticky:"Plakken is nu in plattetekstmodus. Klik nog een keer om terug te gaan naar normaal plakken. Nadat u iets plakt, keert u terug naar normaal plakken.",selectall_desc:"Alles selecteren",paste_word_desc:"Vanuit Word plakken",paste_text_desc:"Als platte tekst plakken"},paste_dlg:{word_title:"Gebruik Ctrl+V om tekst in het venster te plakken.",text_linebreaks:"Regelafbreking bewaren",text_title:"Gebruik Ctrl+V om tekst in het venster te plakken."},table:{cell:"Cel",col:"Kolom",row:"Rij",del:"Tabel verwijderen",copy_row_desc:"Rij kopi\u00ebren",cut_row_desc:"Rij knippen",paste_row_after_desc:"Rij onder plakken",paste_row_before_desc:"Rij boven plakken",props_desc:"Tabeleigenschappen",cell_desc:"Cel-eigenschappen",row_desc:"Rij-eigenschappen",merge_cells_desc:"Cellen samenvoegen",split_cells_desc:"Cellen splitsen",delete_col_desc:"Kolom verwijderen",col_after_desc:"Kolom rechts invoegen",col_before_desc:"Kolom links invoegen",delete_row_desc:"Rij verwijderen",row_after_desc:"Rij onder invoegen",row_before_desc:"Rij boven invoegen",desc:"Nieuwe tabel invoegen",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Als u de opgeslagen inhoud laadt, verliest u de inhoud die zich momenteel in de editor bevindt.\\n\\nWeet u zeker dat u de opgeslagen inhoud wilt laden?",restore_content:"Automatisch opgeslagen inhoud laden.",unload_msg:"De wijzigingen zullen verloren gaan als u nu deze pagina verlaat."},fullscreen:{desc:"Volledig scherm"},media:{edit:"Media bewerken",desc:"Media invoegen/bewerken",delta_height:"",delta_width:""},fullpage:{desc:"Documenteigenschappen",delta_width:"",delta_height:""},template:{desc:"Voorgedefinieerd sjabloon invoegen"},visualchars:{desc:"Zichtbare symbolen"},spellchecker:{desc:"Spellingcontrole",menu:"Instellingen spellingcontrole",ignore_word:"Woord negeren",ignore_words:"Alles negeren",langs:"Talen",wait:"Een ogenblik geduld\u2026",sug:"Suggesties",no_sug:"Geen suggesties",no_mpell:"Geen spelfouten gevonden."},pagebreak:{desc:"Pagina-einde invoegen"},advlist:{types:"Types",def:"Standaard",lower_alpha:"Alfa (klein)",lower_greek:"Griekse letters (klein)",lower_roman:"Romeinse letters (klein)",upper_alpha:"Alfa (groot)",upper_roman:"Romeinse letters (groot)",circle:"Cirkel",disc:"Schijf",square:"Vierkant"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/nn.js0000644000175000017500000001224211526350525031521 0ustar frankiefrankietinyMCE.addI18n({nn:{common:{more_colors:"Fleire fargar",invalid_data:"Feil: Ugyldige verdiar er skrivne inn, desse er merka med raudt",popup_blocked:"Orsak, det er registrert at du har popup-sperre aktivert i nettlesaren. Du m\u00e5 oppheve popup-sperra for nettstaden for \u00e5 f\u00e5 tilgang til dette verktyet",clipboard_no_support:"For tida ikkje st\u00f8tta av nettlesaren din, bruk tastatursnarveger i staden.",clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikkje i Mozilla og Firefox. Vil du vite meir om dette?",not_set:"--ikkje sett--",class_name:"Klasse",browse:"Bla gjennom",close:"Stopp",cancel:"Avbryt",update:"Oppdater",insert:"Set inn",apply:"Legg til",edit_confirm:"Vil du bruke WYSIWYG-editoren for dette tekstfeltet?"},contextmenu:{full:"Full",right:"H\u00f8gre",center:"Midtstill",left:"Venstre",align:"Justering"},insertdatetime:{day_short:"sun,man,tir,ons,tor,fre,lau,sun",day_long:"sundag,mandag,tirsdag,onsdag,torsdag,fredag,laurdag,sundag",months_short:"jan,feb,mar,apr,mai,jun,jul,aug,sep,oct,nov,des",months_long:"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember",inserttime_desc:"Lim inn tid",insertdate_desc:"Lim inn dato",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Skriv u"},preview:{preview_desc:"F\u00f8rehandsvisni"},directionality:{rtl_desc:"Retning h\u00f8gre mot venstre",ltr_desc:"Retning venstre mot h\u00f8gre"},layer:{content:"Nytt lag...",absolute_desc:"Sl\u00e5 p\u00e5/av absolutt plassering",backward_desc:"Flytt bakover",forward_desc:"Flytt framover",insertlayer_desc:"Set inn nytt lag"},save:{save_desc:"Lagre",cancel_desc:"Kanseller alle endringar"},nonbreaking:{nonbreaking_desc:"Set inn hardt mellomrom"},iespell:{download:"ieSpell ikkje funnen. \u00d8nskjer du \u00e5 installere ieSpell no?",iespell_desc:"K\u00f8yrer kontroll av rettskriving"},advhr:{advhr_desc:"Horisontal linje",delta_height:"",delta_width:""},emotions:{emotions_desc:"Hum\u00f8rfjes",delta_height:"",delta_width:""},searchreplace:{replace_desc:"S\u00f8k/Erstatt",search_desc:"S\u00f8k",delta_width:"",delta_height:""},advimage:{image_desc:"Set inn / endre bilete",delta_width:"",delta_height:""},advlink:{link_desc:"Set inn / endre lenkje",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Set inn / Endre eigenskapar",ins_desc:"Innsetjing",del_desc:"Sletting",acronym_desc:"Akronym",abbr_desc:"Forkorting",cite_desc:"Sitat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Rediger CSS-stil",delta_height:"",delta_width:""},paste:{selectall_desc:"Marker al",paste_word_desc:"Lim inn fr\u00e5 Word",paste_text_desc:"Lim inn som vanleg tekst",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Bruk CTRL+V p\u00e5 tastaturet for \u00e5 lime inn i dette vindauget.",text_linebreaks:"Behald tekstbryting",text_title:"Bruk CTRL+V p\u00e5 tastaturet for \u00e5 lime inn i dette vindauget."},table:{cell:"Celle",col:"Kolonne",row:"Rad",del:"Slett tabell",copy_row_desc:"Kopier rad",cut_row_desc:"Fjern rad",paste_row_after_desc:"Lim inn rad etter",paste_row_before_desc:"Lim inn rad framfor",props_desc:"Tabelleigenskapar",cell_desc:"Celleegenskapar",row_desc:"Radeigenskapar",merge_cells_desc:"Sl\u00e5 saman celler",split_cells_desc:"Del celler",delete_col_desc:"Fjern kolonne",col_after_desc:"Set inn kolonne etter",col_before_desc:"Set inn kolonne framfor",delete_row_desc:"Fjern rad",row_after_desc:"Set inn rad etter",row_before_desc:"Set inn rad framfor",desc:"Set inn ein ny tabell",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Endringane du gjorde g\u00e5r tapt om du forl\u00e8t denne sida!",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Skift til/fr\u00e5 fullskjermmodus"},media:{edit:"Endre innsett objekt",desc:"Set inn / rediger inkludert objekt",delta_height:"",delta_width:""},fullpage:{desc:"Dokumenteigenskapar",delta_width:"",delta_height:""},template:{desc:"Set inn f\u00f8rehandsdefinert malinnhald"},visualchars:{desc:"Visuelle konktrollteikn p\u00e5/av"},spellchecker:{desc:"Stavekontroll p\u00e5/av",menu:"Vis meny",ignore_word:"Ignorer ord",ignore_words:"Ignorer alt",langs:"Spr\u00e5k",wait:"Ver venleg og vent...",sug:"Framlegg",no_sug:"Inga framlegg",no_mpell:"Inga stavefeil funne."},pagebreak:{desc:"Set inn sideskift"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/my.js0000644000175000017500000003630311526350525031537 0ustar frankiefrankietinyMCE.addI18n({my:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"\u1021\u103c\u1015\u100a\u103a\u1037",right:"\u100a\u102c",center:"\u1021\u101c\u101a\u103a",left:"\u1018\u101a\u103a",align:"\u1001\u103b\u102d\u1014\u103a\u100a\u102d\u103e\u1019\u103e\u102f"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"\u1010\u1014\u1002\u1004\u103a\u1039\u1031\u1014\u103d,\u1010\u1014\u101c\u1004\u103a\u1039\u102c,\u1021\u1002\u1004\u103a\u1039\u102b,\u1017\u102f\u1012\u1039\u1013\u101f\u1030\u1038,\u103c\u1000\u102c\u101e\u1015\u1031\u1010\u1038,\u1031\u101e\u102c\u103c\u1000\u102c,\u1005\u1031\u1014,\u1010\u1014\u1002\u1004\u103a\u1039\u1031\u1014\u103d",months_short:"\u1007\u1014\u103a,\u1031\u1016,\u1019\u1010\u103a,\u1027\u103c\u1015\u102e,\u1031\u1019,\u1007\u103d\u1014\u103a,\u1007\u1030,\u1029,\u1005\u1000\u103a,\u1031\u1021\u102c\u1000\u103a,\u1014\u102d\u102f\u101d\u1004\u103a,\u1012\u102e\u1007\u1004\u103a",months_long:"\u1007\u1014\u103a\u1014\u101d\u102b\u101b\u102e,\u1031\u1016\u1031\u1016\u102c\u103a\u101d\u102b\u101b\u102e,\u1019\u1010\u103a,\u1027\u103c\u1015\u102e,\u1031\u1019,\u1007\u103d\u1014\u103a,\u1007\u1030\u101c\u102d\u102f\u1004\u103a,\u1029\u1002\u102f\u1010\u103a,\u1005\u1000\u103a\u1010\u1004\u103a\u1018\u102c,\u1031\u1021\u102c\u1000\u103a\u1010\u102d\u102f\u1018\u102c,\u1014\u102d\u102f\u101d\u1004\u103a\u1018\u102c,\u1012\u102e\u1007\u1004\u103a\u1018\u102c",inserttime_desc:"\u1021\u1001\u103b\u102d\u1014\u103a\u1014\u102c\u101b\u102e \u1011\u100a\u103a\u1037\u1015\u102b",insertdate_desc:"\u1031\u1014\u1037\u1005\u103d\u1032\u1011\u100a\u103a\u1037\u101e\u103d\u1004\u103a\u1038\u1015\u102b",time_fmt:"%H \u1014\u102c\u101b\u102e : %M \u1019\u102d\u1014\u1005\u103a : %S \u1005\u1000\u1039\u1000\u1014\u103a\u1037",date_fmt:"%Y-\u1001\u102f\u1014\u103e\u1005\u103a\u104a %B\u101c\u104a %d-\u101b\u1000\u103a\u1031\u1014\u1037"},print:{print_desc:"\u1015\u1036\u102f\u1014\u103e\u102d\u1015\u103a"},preview:{preview_desc:"\u1021\u1005\u1019\u103a\u1038\u103c\u1000\u100a\u103a\u1037"},directionality:{rtl_desc:"\u100a\u102c\u1019\u103e \u1018\u101a\u103a\u101e\u102d\u102f\u1037 \u1025\u102e\u1038\u1010\u100a\u103a",ltr_desc:"\u1018\u101a\u103a\u1019\u103e \u100a\u102c\u101e\u102d\u102f\u1037 \u1025\u102e\u1038\u1010\u100a\u103a"},layer:{content:"\u1031\u101c\u101a\u102c \u1021\u101c\u103d\u103e\u102c\u101e\u1005\u103a...",absolute_desc:"Absolute positioning \u1000\u102d\u102f \u1016\u103d\u1004\u103a\u1037/\u1015\u102d\u1010\u103a",backward_desc:"\u1031\u1014\u102c\u1000\u103a\u1015\u102d\u102f\u1004\u103a\u1038\u101e\u102d\u102f\u1037\u1031\u101b\u103d\u103e\u1037\u1015\u102b",forward_desc:"\u1019\u103b\u1000\u103a\u1014\u103e\u102c\u1005\u102c\u101e\u102d\u102f\u1037\u1031\u101b\u103d\u103e\u1037\u1015\u102b",insertlayer_desc:"\u1031\u101c\u101a\u102c\u1021\u101c\u103d\u103e\u102c\u101e\u1005\u103a\u1011\u100a\u103a\u1037\u101e\u103d\u1004\u103a\u1038\u1015\u102b"},save:{save_desc:"\u101e\u102d\u1019\u103a\u1038",cancel_desc:"\u1021\u1031\u103c\u1015\u102c\u1004\u103a\u1038\u1021\u101c\u1032\u1021\u102c\u1038\u101c\u1036\u102f\u1038\u1000\u102d\u102f \u1015\u101a\u103a\u1016\u103b\u1000\u103a"},nonbreaking:{nonbreaking_desc:"Non-breaking Space \u1021\u1000\u1039\u1001\u101b\u102c\u1000\u102d\u102f \u1011\u100a\u103a\u1037\u1015\u102b"},iespell:{download:"ieSpell \u1000\u102d\u102f \u1019\u1031\u1010\u103d\u1037\u1015\u102b\u104b \u101a\u1001\u102f \u1011\u100a\u103a\u1037\u101e\u103d\u1004\u103a\u1038\u101c\u102d\u102f\u1015\u102b\u101e\u101c\u102c\u1038?",iespell_desc:"\u1005\u1000\u102c\u1038\u101c\u1036\u102f\u1038 \u1005\u1005\u103a\u1031\u1006\u1038\u1015\u102b"},advhr:{advhr_desc:"\u1031\u101b\u103c\u1015\u1004\u103a\u100a\u102e \u1019\u103b\u1009\u103a\u1038\u1031\u103c\u1000\u102c\u1004\u103a\u1038",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u1005\u102d\u1010\u103a\u1001\u1036\u1005\u102c\u1038\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u101b\u103e\u102c/\u1021\u1005\u102c\u1038\u1011\u102d\u102f\u1038",search_desc:"\u101b\u103e\u102c\u1015\u102b",delta_width:"",delta_height:""},advimage:{image_desc:"\u101b\u102f\u1015\u103a\u1015\u1036\u102f \u1011\u100a\u103a\u1037/\u103c\u1015\u1004\u103a",delta_width:"",delta_height:""},advlink:{link_desc:"\u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c \u1011\u100a\u103a\u1037/\u103c\u1015\u1004\u103a",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u1021\u1011\u1030\u1038\u103c\u1015\u102f\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038 \u1011\u100a\u103a\u1037/\u103c\u1015\u1004\u103a",ins_desc:"\u1011\u100a\u103a\u1037\u101e\u103d\u1004\u103a\u1038\u103c\u1001\u1004\u103a\u1038",del_desc:"\u1015\u101a\u103a\u1016\u103b\u1000\u103a\u103c\u1001\u1004\u103a\u1038",acronym_desc:"\u1021\u1010\u102d\u102f\u1031\u1000\u102c\u1000\u103a",abbr_desc:"\u1021\u1000\u103b\u1009\u103a\u1038\u1001\u103b\u102f\u1015\u103a",cite_desc:"\u1000\u102d\u102f\u1038\u1000\u102c\u1038\u103c\u1001\u1004\u103a\u1038",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS \u1005\u1010\u102d\u102f\u1004\u103a \u103c\u1015\u102f\u103c\u1015\u1004\u103a\u101b\u1014\u103a",delta_height:"",delta_width:""},paste:{selectall_desc:"\u1021\u102c\u1038\u101c\u1036\u102f\u1038\u1031\u101b\u103d\u1038",paste_word_desc:"MS Word \u1019\u103e \u1000\u1030\u1038\u103c\u1016\u100a\u103a\u1037\u1015\u102b",paste_text_desc:"\u101b\u102d\u102f\u1038\u101b\u102d\u102f\u1038\u1005\u102c\u101e\u102c\u1038\u1021\u1031\u1014\u103c\u1016\u1004\u103a\u1037 \u1000\u1030\u1038\u103c\u1016\u100a\u103a\u1037\u1015\u102b",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u101d\u1004\u103a\u1038\u1012\u102d\u102f\u1038\u1011\u1032\u101e\u102d\u102f\u1037 \u1005\u102c\u101e\u102c\u1038\u1000\u102d\u102f \u1000\u1030\u1038\u103c\u1016\u100a\u103a\u1037\u101b\u1014\u103a \u101e\u1004\u103a\u1037 \u1000\u102e\u1038\u1018\u102f\u1010\u103a\u101c\u1000\u103a\u1000\u103d\u1000\u103a\u101b\u103e\u102d CTRL V \u1000\u102d\u102f \u101e\u1036\u102f\u1038\u1015\u102b",text_linebreaks:"\u1005\u102c\u1031\u103c\u1000\u102c\u1004\u103a\u1038\u1001\u103d\u1032\u1019\u103b\u102c\u1038\u1000\u102d\u102f \u1001\u103d\u1032\u101c\u103b\u103e\u1000\u103a\u1011\u102c\u1038\u1015\u102b",text_title:"\u101d\u1004\u103a\u1038\u1012\u102d\u102f\u1038\u1011\u1032\u101e\u102d\u102f\u1037 \u1005\u102c\u101e\u102c\u1038\u1000\u102d\u102f \u1000\u1030\u1038\u103c\u1016\u100a\u103a\u1037\u101b\u1014\u103a \u101e\u1004\u103a\u1037 \u1000\u102e\u1038\u1018\u102f\u1010\u103a\u101c\u1000\u103a\u1000\u103d\u1000\u103a\u101b\u103e\u102d CTRL V \u1000\u102d\u102f \u101e\u1036\u102f\u1038\u1015\u102b"},table:{cell:"\u1021\u1000\u103d\u1000\u103a",col:"\u1031\u1000\u102c\u103a\u101c\u1036",row:"\u1021\u1010\u1014\u103a\u1038",del:"\u1007\u101a\u102c\u1038\u1000\u102d\u102f \u1016\u103b\u1000\u103a",copy_row_desc:"\u1007\u101a\u102c\u1038 \u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u1019\u102d\u1010\u1039\u1010\u1030\u1000\u1030\u1038",cut_row_desc:"\u1007\u101a\u102c\u1038 \u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u103c\u1016\u1010\u103a",paste_row_after_desc:"\u1007\u101a\u102c\u1038 \u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u1031\u1014\u102c\u1000\u103a\u1010\u103d\u1004\u103a \u1000\u1030\u1038\u103c\u1016\u100a\u103a\u1037",paste_row_before_desc:"\u1007\u101a\u102c\u1038 \u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u1031\u101b\u103e\u1037\u1010\u103d\u1004\u103a \u1000\u1030\u1038\u103c\u1016\u100a\u103a\u1037",props_desc:"\u1007\u101a\u102c\u1038 \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",cell_desc:"\u1007\u101a\u102c\u1038\u1000\u103d\u1000\u103a \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",row_desc:"\u1007\u101a\u102c\u1038 \u1021\u1010\u1014\u103a\u1038 \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",merge_cells_desc:"\u1007\u101a\u102c\u1038\u1000\u103d\u1000\u103a\u1019\u103b\u102c\u1038\u1000\u102d\u102f \u1031\u1015\u102b\u1004\u103a\u1038\u1015\u102b",split_cells_desc:"\u1031\u1015\u102b\u1004\u103a\u1038\u1011\u102c\u1038\u1031\u101e\u102c \u1007\u101a\u102c\u1038\u1000\u103d\u1000\u103a\u1019\u103b\u102c\u1038\u1000\u102d\u102f \u1001\u103d\u1032\u1015\u102b",delete_col_desc:"\u1031\u1000\u102c\u103a\u101c\u1036\u1000\u102d\u102f \u1016\u101a\u103a\u101b\u103e\u102c\u1038\u1015\u102b",col_after_desc:"\u1031\u1000\u102c\u103a\u101c\u1036\u1000\u102d\u102f \u1031\u1014\u102c\u1000\u103a\u1010\u103d\u1004\u103a \u103c\u1016\u100a\u103a\u1037\u1015\u102b",col_before_desc:"\u1031\u1000\u102c\u103a\u101c\u1036\u1000\u102d\u102f \u1031\u101b\u103e\u1037\u1010\u103d\u1004\u103a \u103c\u1016\u100a\u103a\u1037\u1015\u102b",delete_row_desc:"\u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u1016\u103b\u1000\u103a\u1015\u102b",row_after_desc:"\u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u1031\u1014\u102c\u1000\u103a\u1010\u103d\u1004\u103a \u103c\u1016\u100a\u103a\u1037\u1015\u102b",row_before_desc:"\u1021\u1010\u1014\u103a\u1038\u1000\u102d\u102f \u1031\u101b\u103e\u1037\u1010\u103d\u1004\u103a \u103c\u1016\u100a\u103a\u1037\u1015\u102b",desc:"\u1007\u101a\u102c\u1038 \u1021\u101e\u1005\u103a\u1011\u100a\u103a\u1037\u1015\u102b",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u101e\u102d\u1019\u103a\u1038\u1006\u100a\u103a\u1038\u1011\u102c\u1038\u101e\u100a\u103a\u1019\u103b\u102c\u1038\u1000\u102d\u102f \u103c\u1015\u1014\u103a\u101c\u100a\u103a\u1011\u102c\u1038\u101e\u102d\u102f\u1015\u102b\u1000\u104a \u101c\u1000\u103a\u101b\u103e\u102d \u1021\u101a\u103a\u1012\u102e\u1010\u102c\u1011\u1032\u1010\u103d\u1004\u103a \u101b\u103e\u102d\u1031\u101e\u102c \u1031\u101b\u1038\u101e\u102c\u1038\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038\u1021\u102c\u1038\u101c\u1036\u102f\u1038\u1000\u102d\u102f \u1006\u1036\u102f\u1038\u101b\u103e\u1036\u102f\u1038\u101b\u1015\u102b\u1019\u100a\u103a\u104bnn\u101e\u102d\u1019\u103a\u1038\u1006\u100a\u103a\u1038\u1011\u102c\u1038\u101e\u100a\u103a\u1019\u103b\u102c\u1038\u1000\u102d\u102f \u103c\u1015\u1014\u103a\u101c\u100a\u103a\u1011\u102c\u1038\u101e\u102d\u102f\u101c\u102d\u102f\u1010\u102c \u1031\u101e\u1001\u103b\u102c\u101b\u1032\u1037\u101c\u102c\u1038?",restore_content:"\u1021\u101c\u102d\u102f\u101c\u102d\u102f\u101e\u102d\u1019\u103a\u1038\u1011\u102c\u1038\u101e\u100a\u103a\u1019\u103b\u102c\u1038\u1000\u102d\u102f \u103c\u1015\u1014\u103a\u101c\u100a\u103a\u1011\u102c\u1038\u101e\u102d\u102f\u1015\u102b\u104b",unload_msg:"\u1012\u102e\u1005\u102c\u1019\u103b\u1000\u103a\u1014\u103e\u102c\u1019\u103e \u1021\u103c\u1001\u102c\u1038\u1000\u102d\u102f \u1031\u101b\u103d\u103e\u1037\u101c\u102d\u102f\u1000\u103a\u101c\u103b\u103e\u1004\u103a \u101e\u1004\u103a\u103c\u1015\u102f\u101c\u102f\u1015\u103a\u1011\u102c\u1038\u1031\u101e\u102c \u1021\u1031\u103c\u1015\u102c\u1004\u103a\u1038\u1021\u101c\u1032 \u1021\u102c\u1038\u101c\u1036\u102f\u1038\u1000\u102d\u102f \u1006\u1036\u102f\u1038\u101b\u103e\u1036\u102f\u1038\u101b\u1015\u102b\u1019\u100a\u103a\u104b"},fullscreen:{desc:"\u1005\u1000\u101b\u1004\u103a\u1021\u103c\u1015\u100a\u103a\u1037\u1019\u102f\u1012\u103a \u1016\u103d\u1004\u103a\u1037/\u1015\u102d\u1010\u103a"},media:{edit:"\u1019\u102e\u1012\u102e\u101a\u102c \u103c\u1019\u103e\u102f\u1015\u103a\u1011\u100a\u103a\u1037\u1019\u103e\u102f\u1000\u102d\u102f \u103c\u1015\u102f\u103c\u1015\u1004\u103a\u101b\u1014\u103a",desc:"\u1019\u102e\u1012\u102e\u101a\u102c \u103c\u1019\u103e\u102f\u1015\u103a\u1011\u100a\u103a\u1037/\u103c\u1015\u102f\u103c\u1015\u1004\u103a\u101b\u1014\u103a",delta_height:"",delta_width:""},fullpage:{desc:"\u1005\u102c\u101b\u103d\u1000\u103a\u1005\u102c\u1010\u1019\u103a\u1038 \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"\u1005\u102c\u101c\u1036\u102f\u1031\u1015\u102b\u1004\u103a\u1038\u101e\u1010\u103a\u1015\u1036\u102f\u1005\u1005\u103a\u101b\u1014\u103a \u1016\u103d\u1004\u103a\u1037/\u1015\u102d\u1010\u103a",menu:"\u1005\u102c\u101c\u1036\u102f\u1038\u1031\u1015\u102b\u1004\u103a\u1038\u101e\u1010\u103a\u1015\u1036\u102f \u1021\u103c\u1015\u1004\u103a\u1021\u1006\u1004\u103a\u1019\u103b\u102c\u1038",ignore_word:"\u1012\u102e\u1005\u1000\u102c\u1038\u101c\u1036\u102f\u1038\u1000\u102d\u102f \u101c\u103e\u1005\u103a\u101c\u103b\u1030\u101b\u103e\u102f",ignore_words:"\u1021\u102c\u1038\u101c\u1036\u102f\u1038 \u101c\u103e\u1005\u103a\u101c\u103b\u1030\u101b\u103e\u102f",langs:"\u1018\u102c\u101e\u102c\u1005\u1000\u102c\u1038\u1019\u103b\u102c\u1038",wait:"\u1031\u1000\u103b\u1038\u1007\u1030\u1038\u103c\u1015\u102f\u104d \u1031\u1005\u102c\u1004\u103a\u1037\u1015\u102b...",sug:"\u1021\u103c\u1000\u1036\u103c\u1015\u102f\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038",no_sug:"\u1021\u103c\u1000\u1036\u103c\u1015\u102f\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038 \u1019\u101b\u103e\u102d\u1015\u102b",no_mpell:"\u1005\u102c\u101c\u1036\u102f\u1038\u1031\u1015\u102b\u1004\u103a\u1038 \u101e\u1010\u103a\u1015\u1036\u102f \u1021\u1019\u103e\u102c\u1038\u1019\u1031\u1010\u103d\u1037\u1015\u102b"},pagebreak:{desc:"\u1005\u102c\u1019\u103b\u1000\u103a\u1014\u103e\u102c\u1001\u103d\u1032 \u1011\u100a\u103a\u1037\u1015\u102b\u104b"},advlist:{types:"\u1021\u1019\u103b\u102d\u102f\u1038\u1021\u1005\u102c\u1038\u1019\u103b\u102c\u1038",def:"\u1019\u1030\u101c",lower_alpha:"Alpha \u1021\u1031\u101e\u1038",lower_greek:"\u1002\u101b\u102d \u1021\u1031\u101e\u1038",lower_roman:"\u101b\u102d\u102f\u1019\u1014\u103a \u1021\u1031\u101e\u1038",upper_alpha:"Alpha \u1021\u103c\u1000\u102e\u1038",upper_roman:"\u101b\u102d\u102f\u1019\u1014\u103a \u1021\u103c\u1000\u102e\u1038",circle:"\u1005\u1000\u103a\u101d\u1014\u103a\u1038",disc:"\u1021\u101d\u102d\u102f\u1004\u103a\u1038\u103c\u1015\u102c\u1038",square:"\u1031\u101c\u1038\u1031\u1011\u102c\u1004\u103a\u1037"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/no.js0000644000175000017500000001253311526350525031525 0ustar frankiefrankietinyMCE.addI18n({no:{common:{more_colors:"Flere farger",invalid_data:"Feil: Ugyldig verdi er skrevet inn, disse er merket med r\u00f8dt",popup_blocked:"Beklager, men vi har registrert at din popup-sperrer har blokkert et vindu i nettleseren. Du m\u00e5 oppheve popup-sperren for at nettstedet skal f\u00e5 tilgang til dette verkt\u00f8yet",clipboard_no_support:"For tiden ikke st\u00f8ttet av din nettleser, bruk tastatursnarveier i stedet.",clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikke i Mozilla og Firefox. Vil du vite mer om dette?",not_set:"--Ikke satt--",class_name:"Klasse",browse:"Bla gjennom",close:"Lukk",cancel:"Avbryt",update:"Oppdater",insert:"Sett inn",apply:"Bruk",edit_confirm:"Vil du bruke WYSIWYG-editoren for dette tekstfeltet?"},contextmenu:{full:"Full",right:"H\u00f8yre",center:"Midtstilt",left:"Venstre",align:"Justering"},insertdatetime:{day_short:"S\u00f8n,Man,Tir,Ons,Tor,Fre,L\u00f8r,S\u00f8n",day_long:"s\u00f8ndag,mandag,tirsdag,onsdag,torsdag,fredag,l\u00f8rdag,s\u00f8ndag",months_short:"jan,feb,mar,apr,mai,jun,jul,aug,sep,okt,nov,des",months_long:"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember",inserttime_desc:"Sett inn tid",insertdate_desc:"Sett inn dato",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Skriv ut"},preview:{preview_desc:"Forh\u00e5ndsvisning"},directionality:{rtl_desc:"Retning h\u00f8yre mot venstre",ltr_desc:"Retning venstre mot h\u00f8yre"},layer:{content:"Nytt lag ...",absolute_desc:"Sl\u00e5 p\u00e5/av absolutt plassering",backward_desc:"Flytt bakover",forward_desc:"Flytt fremover",insertlayer_desc:"Sett inn nytt lag"},save:{save_desc:"Lagre",cancel_desc:"Kanseller alle endringer"},nonbreaking:{nonbreaking_desc:"Sett inn karakter for hardt mellomrom"},iespell:{download:"ieSpell ikke funnet. \u00d8nsker du \u00e5 installere ieSpell?",iespell_desc:"Stavekontroll"},advhr:{advhr_desc:"Horisontal linje",delta_height:"",delta_width:""},emotions:{emotions_desc:"Hum\u00f8rfjes",delta_height:"",delta_width:""},searchreplace:{replace_desc:"S\u00f8k/Erstatt",search_desc:"S\u00f8k",delta_width:"",delta_height:""},advimage:{image_desc:"Sett inn/editer bilde",delta_width:"",delta_height:""},advlink:{link_desc:"Sett inn/editer lenke",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Sett inn/Editer egenskaper",ins_desc:"Innsetting",del_desc:"Sletting",acronym_desc:"Akronym",abbr_desc:"Forkortelse",cite_desc:"Sitat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Rediger CSS-stil",delta_height:"",delta_width:""},paste:{plaintext_mode:"Lim inn er n\u00e5 i vanlig tekst modus. Klikk igjen for \u00e5 bytte til vanlig innlimings modus.",plaintext_mode_sticky:"Lim inn er n\u00e5 i vanlig tekst modus. Klikk igjen for \u00e5 bytte til vanlig innlimings modus. Etter at du limer inn noe vil du g\u00e5 tilbake til ordin\u00e6r innliming.",selectall_desc:"Marker alt",paste_word_desc:"Lim inn fra Word",paste_text_desc:"Lim inn som vanlig tekst"},paste_dlg:{word_title:"Bruk CTRL+V p\u00e5 tastaturet for \u00e5 lime inn teksten i dette vinduet.",text_linebreaks:"Behold tekstbryting",text_title:"Bruk CTRL+V p\u00e5 tastaturet for \u00e5 lime inn teksten i dette vinduet."},table:{cell:"Celle",col:"Kolonne",row:"Rad",del:"Slett tabell",copy_row_desc:"Kopier rad",cut_row_desc:"Slett rad",paste_row_after_desc:"Lime inn rad etter",paste_row_before_desc:"Lime inn rad foran",props_desc:"Tabell egenskaper",cell_desc:"Celle egenskaper",row_desc:"Rad egenskaper",merge_cells_desc:"Sl\u00e5 sammen celler",split_cells_desc:"Splitte sammensl\u00e5tte celler",delete_col_desc:"Slett kolonne",col_after_desc:"Sett inn kolonne etter",col_before_desc:"Sett inn kolonne forand",delete_row_desc:"Slett rad",row_after_desc:"Sett inn rad etter",row_before_desc:"Sett inn rad foran",desc:"Setter inn ny tabell",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Hvis du gjenoppretter tidligere lagret innhold s\u00e5 vil du miste alt n\u00e5v\u00e6rende innhold i editoren.\\n\\nEr du sikker du vil gjenopprette tidligere lagret innhold?.",restore_content:"Gjenopprette autolagret innhold.",unload_msg:"Utf\u00f8rte endringer g\u00e5r tapt hvis du navigerer vekk fra denne siden!"},fullscreen:{desc:"Sl\u00e5 fullskjermmodus av/p\u00e5"},media:{edit:"Editer innebygget objekt",desc:"Sett inn/editer innebygget objekt",delta_height:"",delta_width:""},fullpage:{desc:"Dokument egenskaper",delta_width:"",delta_height:""},template:{desc:"Sett inn forh\u00e5ndsdefinert malinnhold"},visualchars:{desc:"Visuelle konktrolltegn p\u00e5/av"},spellchecker:{desc:"Stavekontroll p\u00e5/av",menu:"Oppsett stavekontroll",ignore_word:"Ignorer ord",ignore_words:"Ignorer alt",langs:"Spr\u00e5k",wait:"Vennligst vent ...",sug:"Forslag",no_sug:"Ingen forslag",no_mpell:"Ingen stavefeil funnet."},pagebreak:{desc:"Sett inn sideskift"},advlist:{types:"Types",def:"Standard",lower_alpha:"Sm\u00e5 alfanumerisk",lower_greek:"Sm\u00e5 gresk",lower_roman:"Sm\u00e5 roman",upper_alpha:"Store alfanumerisk",upper_roman:"Store roman",circle:"Sirkel",disc:"Plate",square:"Firkant"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/pl.js0000644000175000017500000001432611526350525031526 0ustar frankiefrankietinyMCE.addI18n({pl:{common:{more_colors:"Wi\u0119cej kolor\u00f3w",invalid_data:"B\u0142\u0105d: Zosta\u0142y wprowadzone b\u0142\u0119dne dane, s\u0105 zaznaczone na czerwono.",popup_blocked:"Zauwa\u017cyli\u015bmy, \u017ce Twoje blokowanie wyskakuj\u0105cych okienek wy\u0142\u0105czy\u0142o okno, kt\u00f3re dostarcza funkcjonalno\u015b\u0107 aplikacji. B\u0119dziesz potrzebowa\u0142 wy\u0142\u0105czy\u0107 blokowanie wyskakuj\u0105cych okienek na tej stronie aby w pe\u0142ni wykorzysta\u0107 to narz\u0119dzie.",clipboard_no_support:"Aktualnie nie jest wspomagany przez Twoj\u0105 przegl\u0105dark\u0119, u\u017cyj skr\u00f3t\u00f3w klawiaturowych w zamian.",clipboard_msg:"Akcje Kopiuj/Wytnij/Wklej nie s\u0105 dost\u0119pne w Mozilli i Firefox.\\nCzy chcesz wi\u0119cej informacji o tym problemie?",not_set:"-- Brak --",class_name:"Klasa",browse:"Przegl\u0105daj",close:"Zamknij",cancel:"Anuluj",update:"Aktualizuj",insert:"Wstaw",apply:"Zastosuj",edit_confirm:"Czy chcesz u\u017cy\u0107 trybu WYSIWYG dla tego pola formularza?"},contextmenu:{full:"Wyjustuj",right:"Prawy",center:"\u015arodkowy",left:"Lewy",align:"Wyr\u00f3wnanie"},insertdatetime:{day_short:"N,Pn,Wt,\u015ar,Cz,Pt,So,N",day_long:"Niedziela, Poniedzia\u0142ek, Wtorek, \u015aroda, Czwartek, Pi\u0105tek, Sobota, Niedziela",months_short:"Sty,Lut,Mar,Kwi,Maj,Cze,Lip,Sie,Wrz,Pa\u017a,Lis,Gru",months_long:"Stycze\u0144, Luty, Marzec, Kwiecie\u0144, Maj, Czerwiec, Lipiec, Sierpie\u0144, Wrzesie\u0144, Pa\u017adziernik, Listopad, Grudzie\u0144",inserttime_desc:"Wstaw czas",insertdate_desc:"Wstaw dat\u0119",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Drukuj"},preview:{preview_desc:"Podgl\u0105d"},directionality:{rtl_desc:"Kierunek od prawej do lewej",ltr_desc:"Kierunek od lewej do prawej"},layer:{content:"Nowa warstwa...",absolute_desc:"Prze\u0142\u0105cz pozycjonowanie absolutne",backward_desc:"Przesu\u0144 w ty\u0142",forward_desc:"Przesu\u0144 do przodu",insertlayer_desc:"Wklej now\u0105 warstw\u0119"},save:{save_desc:"Zachowaj",cancel_desc:"Anuluj wszystkie zmiany"},nonbreaking:{nonbreaking_desc:"Wstaw tward\u0105 spacj\u0119"},iespell:{download:"ieSpell nie wykryte. Czy przeprowadzi\u0107 instalacj\u0119 tego komponentu?",iespell_desc:"Sprawd\u017a pisowni\u0119"},advhr:{advhr_desc:"Pozioma linia",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotikony",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Znajd\u017a/Zamie\u0144",search_desc:"Znajd\u017a",delta_width:"",delta_height:""},advimage:{image_desc:"Wstaw/edytuj obraz",delta_width:"",delta_height:""},advlink:{link_desc:"Wstaw/edytuj link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Wstaw / Edytuj atrybuty",ins_desc:"Wstawienie",del_desc:"Usuni\u0119cie",acronym_desc:"Akronim",abbr_desc:"Skr\u00f3t",cite_desc:"Cytat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edytuj Style CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Wklejanie jest teraz dost\u0119pne w trybie tekstowym. Kliknij ponownie, aby prze\u0142\u0105czy\u0107 si\u0119 z powrotem do trybu wklejania sformatowanego tekstu.",plaintext_mode_sticky:"Wklejanie jest teraz dost\u0119pne w trybie tekstowym. Kliknij ponownie, aby prze\u0142\u0105czy\u0107 si\u0119 z powrotem do trybu wklejania sformatowanego tekstu. Po wklejeniu tekstu nast\u0105pi powr\u00f3t do trybu wklejania zformatowanego tekstu.",selectall_desc:"Zaznacz wszystko",paste_word_desc:"Wklej z Worda",paste_text_desc:"Wklej jako zwyk\u0142y tekst"},paste_dlg:{word_title:"U\u017cyj CTRL+V na swojej klawiaturze \u017ceby wklei\u0107 tekst do okna.",text_linebreaks:"Zachowaj ko\u0144ce linii.",text_title:"U\u017cyj CTRL+V na swojej klawiaturze \u017ceby wklei\u0107 tekst do okna."},table:{cell:"Kom\u00f3rka",col:"Kolumna",row:"Wiersz",del:"Usu\u0144 tabel\u0119",copy_row_desc:"Kopiuj wiersz...",cut_row_desc:"Wytnij wiersz...",paste_row_after_desc:"Wklej wiersz po...",paste_row_before_desc:"Wklej wiersz przed...",props_desc:"W\u0142a\u015bciwo\u015bci tabeli",cell_desc:"W\u0142a\u015bciwo\u015bci kom\u00f3rki",row_desc:"W\u0142a\u015bciwo\u015bci wiersza",merge_cells_desc:"Po\u0142\u0105cz kom\u00f3rki",split_cells_desc:"Podziel kom\u00f3rk\u0119",delete_col_desc:"Usu\u0144 kolumn\u0119",col_after_desc:"Wstaw kolumn\u0119 po...",col_before_desc:"Wstaw kolumn\u0119 przed...",delete_row_desc:"Usu\u0144 wiersz",row_after_desc:"Wstaw nowy wiersz po...",row_before_desc:"Wstaw nowy wiersz przed...",desc:"Wstaw now\u0105 tabel\u0119",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Je\u015bli przywr\u00f3cisz zapisan\u0105 tre\u015b\u0107, stracisz ca\u0142\u0105 tre\u015b\u0107, kt\u00f3ra teraz si\u0119 znajduje w edytorze.\\n\\nJeste\u015b pewien, \u017ce chcesz przywr\u00f3ci\u0107 zapisan\u0105 tre\u015b\u0107?.",restore_content:"Przywr\u00f3\u0107 automatycznie zapisan\u0105 tre\u015b\u0107.",unload_msg:"Zmiany, kt\u00f3re zrobi\u0142e\u015b zostan\u0105 utracone je\u015bli opu\u015bcisz t\u0119 stron\u0119."},fullscreen:{desc:"Prze\u0142\u0105cz tryb pe\u0142noekranowy"},media:{delta_height:"",edit:"Edytuj wbudowane media",desc:"Wstaw/Edytuj wbudowane media",delta_width:""},fullpage:{desc:"W\u0142a\u015bciwo\u015bci dokumentu",delta_width:"",delta_height:""},template:{desc:"Wstaw szablon dokumentu"},visualchars:{desc:"Graficzna kontrola pisma w\u0142\u0105cz/wy\u0142\u0105cz."},spellchecker:{desc:"Sprawdzanie pisowni",menu:"Ustawienia sprawdzania pisowni",ignore_word:"Ignoruj s\u0142owo",ignore_words:"Ignoruj wszystkie",langs:"J\u0119zyki",wait:"Prosz\u0119 poczeka\u0107...",sug:"Sugestie",no_sug:"Brak sugestii",no_mpell:"\u017badnych brakuj\u0105cych nie znaleziono."},pagebreak:{desc:"Wstaw lini\u0119."},advlist:{types:"Typy",def:"Domy\u015blny",lower_alpha:"Ma\u0142e alfabetu",lower_greek:"Ma\u0142e greckie",lower_roman:"Ma\u0142e rzymskie",upper_alpha:"Du\u017ce alfabetu",upper_roman:"Du\u017ce rzymskie",circle:"Ko\u0142o",disc:"Elipsa",square:"Kwadrat"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ps.js0000644000175000017500000001210211526350525031523 0ustar frankiefrankietinyMCE.addI18n({ps:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/pt.js0000644000175000017500000001302711526350525031533 0ustar frankiefrankietinyMCE.addI18n({pt:{common:{more_colors:"Mais Cores",invalid_data:"Erro: Valores inv\u00e1lidos marcados em vermelho.",popup_blocked:"Detectamos que o seu bloqueador de popups bloqueou uma janela que \u00e9 essencial para a aplica\u00e7\u00e3o. Voc\u00ea precisa desativar o bloqueador de janelas de popups para utilizar esta ferramenta.",clipboard_no_support:"O seu browser n\u00e3o suporta esta fun\u00e7\u00e3o, use os atalhos do teclado.",clipboard_msg:"Copiar/recortar/colar n\u00e3o est\u00e1 dispon\u00edvel no Mozilla e Firefox.\\nDeseja mais informa\u00e7\u00f5es sobre este problema?",not_set:"-- N/A --",class_name:"Classe",browse:"Procurar",close:"Fechar",cancel:"Cancelar",update:"Atualizar",insert:"Inserir",apply:"Aplicar",edit_confirm:"Deseja usar o modo de edi\u00e7\u00e3o avan\u00e7ado neste campo de texto?"},contextmenu:{full:"Justificado",right:"Direita",center:"Centro",left:"Esquerda",align:"Alinhamento"},insertdatetime:{day_short:"Dom,Seg,Ter,Qua,Qui,Sex,Sab,Dom",day_long:"Domingo,Segunda-feira,Ter\u00e7a-feira,Quarta-feira,Quinta-feira,Sexta-feira,S\u00e1bado,Domingo",months_short:"Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez",months_long:"Janeiro,Fevereiro,Mar\u00e7o,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro",inserttime_desc:"Inserir hora",insertdate_desc:"Inserir data",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Imprimir"},preview:{preview_desc:"Pr\u00e9-visualizar"},directionality:{rtl_desc:"Da direita para esquerda",ltr_desc:"Da esquerda para direita"},layer:{content:"Nova camada...",absolute_desc:"Alternar o posicionamento absoluto",backward_desc:"Mover para tr\u00e1s",forward_desc:"Mover para frente",insertlayer_desc:"Inserir nova camada"},save:{save_desc:"Salvar",cancel_desc:"Cancelar todas as altera\u00e7\u00f5es"},nonbreaking:{nonbreaking_desc:"Inserir um espa\u00e7o \"sem quebra\""},iespell:{download:"Plugin de ortografia n\u00e3o-detectado. Deseja instalar agora?",iespell_desc:"Verificar ortografia"},advhr:{advhr_desc:"Separador horizontal",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emoticons",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Localizar/substituir",search_desc:"Localizar",delta_width:"",delta_height:""},advimage:{image_desc:"Inserir/editar imagem",delta_width:"",delta_height:""},advlink:{link_desc:"Inserir/editar hyperlink",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Inserir/Editar atributos",ins_desc:"Inserir",del_desc:"Apagar",acronym_desc:"Acr\u00f4nimo",abbr_desc:"Abrevia\u00e7\u00e3o",cite_desc:"Cita\u00e7\u00e3o",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Editar CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Comando colar est\u00e1 em modo texto simples. Clique novamente para voltar para o modo normal.",plaintext_mode_sticky:"Comando colar est\u00e1 em modo texto simples. Clique novamente para voltar para o modo normal. Depois de colar alguma coisa retornar\u00e1 para o modo normal.",selectall_desc:"Selecionar tudo",paste_word_desc:"Colar (copiado do WORD)",paste_text_desc:"Colar como texto simples"},paste_dlg:{word_title:"Use CTRL+V para colar o texto na janela.",text_linebreaks:"Manter quebras de linha",text_title:"Use CTRL+V para colar o texto na janela."},table:{cell:"C\u00e9lula",col:"Coluna",row:"Linha",del:"Apagar tabela",copy_row_desc:"Copiar linha",cut_row_desc:"Recortar linha",paste_row_after_desc:"Colar linha depois",paste_row_before_desc:"Colar linha antes",props_desc:"Propriedades da tabela",cell_desc:"Propriedades das c\u00e9lulas",row_desc:"Propriedades das linhas",merge_cells_desc:"Unir c\u00e9lulas",split_cells_desc:"Dividir c\u00e9lulas",delete_col_desc:"Remover coluna",col_after_desc:"Inserir coluna depois",col_before_desc:"Inserir coluna antes",delete_row_desc:"Apagar linha",row_after_desc:"Inserir linha depois",row_before_desc:"Inserir linha antes",desc:"Inserir nova tabela",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Se restaurar o conte\u00fado, voc\u00ea ir\u00e1 perder tudo que est\u00e1 atualmente no editor.\\n\\nTem certeza que quer restaurar o conte\u00fado salvo?",restore_content:"Restaura conte\u00fado salvo automaticamente.",unload_msg:"As mudan\u00e7as efetuadas ser\u00e3o perdidas se sair desta p\u00e1gina."},fullscreen:{desc:"Tela Inteira"},media:{edit:"Editar m\u00eddia incorporada",desc:"Inserir/Editar m\u00eddia incorporada",delta_height:"",delta_width:""},fullpage:{desc:"Propriedades do Documento",delta_width:"",delta_height:""},template:{desc:"Inserir template"},visualchars:{desc:"Caracteres de controle visual ligado/desligado"},spellchecker:{desc:"Alternar verifica\u00e7\u00e3o ortogr\u00e1fica",menu:"Configura\u00e7\u00f5es de ortografia",ignore_word:"Ignorar palavra",ignore_words:"Ignorar tudo",langs:"Linguagens",wait:"Aguarde...",sug:"Sugest\u00f5es",no_sug:"Sem sugest\u00f5es",no_mpell:"N\u00e3o foram detectados erros de ortografia."},pagebreak:{desc:"Inserir quebra de p\u00e1gina."},advlist:{types:"Tipos",def:"Padr\u00e3o",lower_alpha:"Alfabeto min\u00fasculo",lower_greek:"Alfabeto grego",lower_roman:"Num. romanos min\u00fasculos",upper_alpha:"Alfabeto mai\u00fasculos",upper_roman:"Num. romanos mai\u00fasculos",circle:"C\u00edrculo",disc:"Disco",square:"Quadrado"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/sc.js0000644000175000017500000001541211526350525031515 0ustar frankiefrankietinyMCE.addI18n({sc:{common:{more_colors:"\u66f4\u591a\u989c\u8272",invalid_data:"\u9519\u8bef:\u65e0\u6548\u8f93\u5165\u503c\uff0c\u5df2\u6807\u8bb0\u4e3a\u7ea2\u8272\u3002 ",popup_blocked:"\u62b1\u6b49\uff01\u5f39\u51fa\u89c6\u7a97\u5df2\u88ab\u963b\u6b62\uff0c\u8bf7\u8c03\u6574\u6d41\u89c8\u5668\u8bbe\u7f6e\uff0c\u5141\u8bb8\u6b64\u7f51\u7ad9\u53ef\u5f39\u51fa\u65b0\u89c6\u7a97\uff0c\u4ee5\u4fbf\u4f7f\u7528\u6b64\u5de5\u5177",clipboard_no_support:"\u8fd8\u4e0d\u652f\u63f4\u60a8\u7684\u6d41\u89c8\u5668\uff0c\u8bf7\u4f7f\u7528\u952e\u76d8\u5feb\u6377\u65b9\u5f0f",clipboard_msg:"\u590d\u5236\u3001\u526a\u4e0b\u3001\u8d34\u4e0a\u529f\u80fd\u5728Mozilla\u548cFirefox\u4e2d\u4e0d\u80fd\u4f7f\u7528\u3002 \\n\u662f\u5426\u9700\u8981\u4e86\u89e3\u66f4\u591a\u6709\u5173\u6b64\u95ee\u9898\u7684\u8d44\u8baf\uff1f ",not_set:"--\u672a\u8bbe\u7f6e--",class_name:"\u6837\u5f0f",browse:"\u6d41\u89c8",close:"\u5173\u95ed",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5e94\u7528",edit_confirm:"\u662f\u5426\u5728\u6b64textarea\u6807\u7b7e\u5185\u4f7f\u7528\u300c\u6240\u89c1\u5373\u6240\u5f97\u300d\u6a21\u5f0f\uff1f "},contextmenu:{full:"\u4e24\u7aef\u5bf9\u9f50",right:"\u9760\u53f3\u5bf9\u9f50",center:"\u5c45\u4e2d\u5bf9\u9f50",left:"\u9760\u5de6\u5bf9\u9f50",align:"\u5bf9\u9f50\u65b9\u5f0f"},insertdatetime:{day_short:"\u5468\u65e5,\u5468\u4e00,\u5468\u4e8c,\u5468\u4e09,\u5468\u56db,\u5468\u4e94,\u5468\u516d,\u5468\u65e5",day_long:"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u4e09,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5",months_short:"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708",months_long:"\u4e00\u6708,\u4e8c\u6708,\u4e09\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u73b0\u5728\u65f6\u95f4",insertdate_desc:"\u63d2\u5165\u4eca\u5929\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u5217\u5370"},preview:{preview_desc:"\u9884\u89c8"},directionality:{rtl_desc:"\u6587\u5b57\u4ece\u53f3\u5230\u5de6",ltr_desc:"\u6587\u5b57\u4ece\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u589e\u5c42...",absolute_desc:"\u5f00\u5173\u7edd\u5bf9\u4f4d\u7f6e",backward_desc:"\u7f6e\u540e",forward_desc:"\u7f6e\u524d",insertlayer_desc:"\u63d2\u5165\u5c42"},save:{save_desc:"\u4fdd\u5b58",cancel_desc:"\u53d6\u6d88\u6240\u6709\u66f4\u6539"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u767d\u683c"},iespell:{download:"\u672a\u68c0\u6d4b\u5230ieSpell\u7684\u5b58\u5728\u3002\u662f\u5426\u73b0\u5728\u7acb\u5373\u5b89\u88c5\uff1f ",iespell_desc:"\u62fc\u5199\u68c0\u67e5"},advhr:{advhr_desc:"\u6c34\u5e73\u7ebf",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u56fe\u91ca",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u67e5\u627e/\u66ff\u6362",search_desc:"\u67e5\u627e",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7f16\u8f91\u56fe\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7f16\u8f91\u8fde\u7ed3",delta_height:"",delta_width:""},xhtmlxtras:{attribs_delta_height:"60",attribs_delta_width:"40",attribs_desc:"\u63d2\u5165/\u7f16\u8f91\u5c5e\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u5220\u9664",acronym_desc:"\u9996\u5b57\u7f29\u5199",abbr_desc:"\u7f29\u5199",cite_desc:"\u5f15\u6587",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7f16\u8f91CSS\u6837\u5f0f\u8868\u5355",delta_height:"",delta_width:""},paste:{selectall_desc:"\u5168\u9009",paste_word_desc:"\u4eceWord\u8d34\u4e0a",paste_text_desc:"\u4ee5\u7eaf\u6587\u672c\u8d34\u4e0a",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u5728\u952e\u76d8\u4e0a\u540c\u65f6\u6309\u4e0bCTRL\u548cV\u952e\uff0c\u4ee5\u8d34\u4e0a\u6587\u5b57\u5230\u6b64\u89c6\u7a97\u3002 ",text_linebreaks:"\u4fdd\u7559\u6362\u884c\u7b26\u53f7",text_title:"\u5728\u952e\u76d8\u4e0a\u540c\u65f6\u6309\u4e0bCTRL\u548cV\u952e\uff0c\u4ee5\u8d34\u4e0a\u6587\u5b57\u5230\u6b64\u89c6\u7a97\u3002 "},table:{merge_cells_delta_height:"40",merge_cells_delta_width:"40",table_delta_height:"60",table_delta_width:"40",cellprops_delta_height:"10",cellprops_delta_width:"10",cell:"\u5355\u683c",col:"\u5217",row:"\u884c",del:"\u5220\u9664\u8868\u683c",copy_row_desc:"\u590d\u5236\u9009\u62e9\u884c",cut_row_desc:"\u526a\u4e0b\u9009\u62e9\u884c",paste_row_after_desc:"\u8d34\u5728\u4e0b\u884c",paste_row_before_desc:"\u8d34\u5728\u4e0a\u884c",props_desc:"\u8868\u683c\u5c5e\u6027",cell_desc:"\u5355\u683c\u5c5e\u6027",row_desc:"\u884c\u5c5e\u6027",merge_cells_desc:"\u5408\u5e76\u5355\u683c",split_cells_desc:"\u5206\u5272\u5355\u683c",delete_col_desc:"\u5220\u9664\u6240\u5728\u5217",col_after_desc:"\u63d2\u5165\u53f3\u65b9\u5217",col_before_desc:"\u63d2\u5165\u5de6\u65b9\u5217",delete_row_desc:"\u5220\u9664\u6240\u5728\u884c",row_after_desc:"\u63d2\u5165\u4e0b\u65b9\u884c",row_before_desc:"\u63d2\u5165\u4e0a\u65b9\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u5982\u679c\u79bb\u5f00\u6b64\u9875\u9762\u5c06\u5bfc\u81f4\u6240\u505a\u7684\u66f4\u6539\u5168\u90e8\u4e22\u5931\u3002 ",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u5f00\u5173\u5168\u5c4f\u6a21\u5f0f"},media:{edit:"\u7f16\u8f91\u5d4c\u5165\u5a92\u4f53",desc:"\u63d2\u5165/\u7f16\u8f91\u5d4c\u5165\u5a92\u4f53",delta_height:"",delta_width:""},fullpage:{desc:"\u6863\u5c5e\u6027",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9884\u5b9a\u7684\u8303\u672c\u5185\u5bb9"},visualchars:{desc:"\u663e\u793a\u63a7\u5236\u7b26\u53f7\u5f00/\u5173\u3002 "},spellchecker:{desc:"\u5f00\u5173\u62fc\u5199\u68c0\u67e5",menu:"\u62fc\u5199\u68c0\u67e5\u8bbe\u7f6e",ignore_word:"\u7565\u8fc7",ignore_words:"\u5168\u90e8\u7565\u8fc7",langs:"\u8bed\u8a00",wait:"\u8bf7\u7a0d\u5019...",sug:"\u63a8\u8350\u5b57\u8bcd",no_sug:"\u65e0\u62fc\u5199\u63a8\u8350",no_mpell:"\u672a\u53d1\u73b0\u62fc\u5199\u9519\u8bef"},pagebreak:{desc:"\u63d2\u5165\u5206\u9875\u7b26\u53f7"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ro.js0000644000175000017500000001374511526350525031537 0ustar frankiefrankietinyMCE.addI18n({ro:{common:{more_colors:"Mai multe culori",invalid_data:"Ave\u0163i erori. Datele gre\u015fite sunt \u00een ro\u015fu.",popup_blocked:"Ne pare r\u0103u, dar un popup-blocker a dezativat o fereastr\u0103 care d\u0103 func\u0163ionalitate aplica\u0163iei.Trebuie s\u0103 dezactiva\u0163i acel popup-blocker pentru acest site pentru a folosi aplica\u0163ia la capacitate maxim\u0103.",clipboard_no_support:"Deocamdat\u0103 nu este suportat\u0103 de browser. V\u0103 rug\u0103m s\u0103 folosi\u0163i combina\u0163ii de taste.",clipboard_msg:"Copiere/T\u0103iere/Lipire nu sunt disponibile \u00een Mozilla \u015fi Firefox.\\nDori\u0163i mai multe informa\u0163ii despre aceast\u0103 problem\u0103?",not_set:"-- Nestat\u0103 --",class_name:"Clas\u0103",browse:"R\u0103sfoie\u015fte",close:"\u00cenchide",cancel:"Anulare",update:"Actualizeaz\u0103",insert:"Insereaz\u0103",apply:"Aplic\u0103",edit_confirm:"Dori\u0163i s\u0103 folosi\u0163i un editor avansat pentru aceast\u0103 zon\u0103 de text?"},contextmenu:{full:"Justify",right:"Dreapta",center:"Centru",left:"St\u00e2nga",align:"Aliniere"},insertdatetime:{day_short:"Dum,Lun,Mar,Mie,Joi,Vin,S\u00e2m,Dum",day_long:"Duminic\u0103,Luni,Mar\u0163i,Miercuri,Joi,Vineri,S\u00e2mb\u0103t\u0103,Duminic\u0103",months_short:"Ian,Feb,Mar,Apr,Mai,Iun,Iul,Aug,Sep,Oct,Noi,Dec",months_long:"Ianuarie,Februarie,Martie,Aprilie,Mai,Iunie,Iulie,August,Septembrie,Octombrie,Noiembrie,Decembrie ",inserttime_desc:"Insereaz\u0103 or\u0103",insertdate_desc:"Insereaz\u0103 dat\u0103",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Imprimare"},preview:{preview_desc:"Previzualizare"},directionality:{rtl_desc:"Direc\u0163ia de la dreapta la st\u00e2nga",ltr_desc:"Direc\u0163ia de la st\u00e2nga la dreapta"},layer:{content:"Strat nou ...",absolute_desc:"Pozi\u0163ionare absolut\u0103",backward_desc:"Mut\u0103 \u00eenapoi",forward_desc:"Mut\u0103 \u00eenainte",insertlayer_desc:"Insereaz\u0103 stat nou"},save:{save_desc:"Salveaz\u0103",cancel_desc:"Anuleaz\u0103 toate schimb\u0103rile"},nonbreaking:{nonbreaking_desc:"Insereaz\u0103 caracterul spa\u0163iu"},iespell:{download:"ieSpell nu a fost detectat. Dori\u0163i s\u0103-l instala\u0163i?",iespell_desc:"Ruleaz\u0103 corectorul de limb\u0103"},advhr:{advhr_desc:"Linie orizontal\u0103",delta_height:"",delta_width:""},emotions:{emotions_desc:"Figurine",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Caut\u0103/\u00cenlocuie\u015fte",search_desc:"Caut\u0103",delta_width:"",delta_height:""},advimage:{image_desc:"Inserare/editare imagine",delta_width:"",delta_height:""},advlink:{link_desc:"Inserare/editare leg\u0103tur\u0103",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insereaz\u0103/editeaz\u0103 atribute",ins_desc:"Inserare",del_desc:"\u015etergere",acronym_desc:"Acronim",abbr_desc:"Abreviere",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Editare CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Lipirea este acum \u00een modul text simplu. Ap\u0103sa\u0163i din nou pentru comutarea la modul normal de lipire.",plaintext_mode_sticky:"Lipirea este acum \u00een modul text simplu. Ap\u0103sa\u0163i aici pentru comutarea la modul normal de lipire. Dup\u0103 ce ve\u0163i lipi ceva ve\u0163i reveni la modul normal de lipire.",selectall_desc:"Selecteaz\u0103 tot",paste_word_desc:"Lipire din Word",paste_text_desc:"Lipire ca text simplu"},paste_dlg:{word_title:"Folosi\u0163i CTRL+V pentru a lipi \u00een aceast\u0103 zon\u0103.",text_linebreaks:"P\u0103streaz\u0103 separatoarele de linii.",text_title:"Folosi\u0163i CTRL+V pentru a lipi \u00een aceast\u0103 zon\u0103."},table:{cell:"Celul\u0103",col:"Coloan\u0103",row:"R\u00e2nd",del:"\u015eterge tabel",copy_row_desc:"Copiaz\u0103 r\u00e2nd",cut_row_desc:"Taie r\u00e2nd",paste_row_after_desc:"Lipe\u015fte r\u00e2nd dup\u0103",paste_row_before_desc:"Lipe\u015fte r\u00e2nd \u00eenainte",props_desc:"Propriet\u0103\u0163i tabel",cell_desc:"Propriet\u0103\u0163i celul\u0103",row_desc:"Propriet\u0103\u0163i r\u00e2nd",merge_cells_desc:"Uni\u0163i celule",split_cells_desc:"Separa\u0163i celule unite",delete_col_desc:"\u015eterge coloan\u0103",col_after_desc:"Inserare coloan\u0103 dup\u0103",col_before_desc:"Inserare coloan\u0103 \u00eenainte",delete_row_desc:"\u015eterge r\u00e2nd",row_after_desc:"Inserare r\u00e2nd dup\u0103",row_before_desc:"Inserare r\u00e2nd \u00eenainte",desc:"Insereaz\u0103 tabel nou",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Daca restaurati continutul salvat vei pierde tot continutul existent din editor.\\n\\nSigur doriti sa restaurati continutul salvat?.",restore_content:"Restaureaz\u0103 con\u0163inutul salvat automat.",unload_msg:"Modific\u0103rile nu vor fi salvate."},fullscreen:{desc:"Mod ecran complet"},media:{edit:"Editeaz\u0103 media",desc:"Insereaz\u0103 / editeaz\u0103 media",delta_height:"",delta_width:""},fullpage:{desc:"Propriet\u0103\u0163i document",delta_width:"",delta_height:""},template:{desc:"Insereaz\u0103 un \u015fablon predefinit"},visualchars:{desc:"Comut\u0103 caracterele vizuale de control"},spellchecker:{desc:"Activare/dezactivare dic\u0163ionar",menu:"Set\u0103ri dic\u0163ionar",ignore_word:"Ignor\u0103 cuv\u00e2nt",ignore_words:"Ignor\u0103 toate",langs:"Limbi",wait:"V\u0103 rog a\u015ftepta\u0163i...",sug:"Sugestii",no_sug:"Nu sunt sugestii.",no_mpell:"Nu sunt gre\u015feli."},pagebreak:{desc:"Insereaz\u0103 un separator de pagin\u0103"},advlist:{types:"Tipuri",def:"Implicit",lower_alpha:"Minuscule alfabetice",lower_greek:"Minuscule grece\u015fti",lower_roman:"Minuscule romane",upper_alpha:"Majuscule alfabetice",upper_roman:"Majuscule romane",circle:"Cerc",disc:"Disc",square:"P\u0103trat"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/se.js0000644000175000017500000001303111526350525031512 0ustar frankiefrankietinyMCE.addI18n({se:{common:{more_colors:"Fler f\u00e4rger",invalid_data:"Fel: Inkorrekta v\u00e4rden har matats in, dessa \u00e4r markerade i r\u00f6tt.",popup_blocked:"Popup blockerare detekterad. St\u00e4ng av den s\u00e5 att dialogerna kan \u00f6ppnas.",clipboard_no_support:"Funktionen \u00e4r inte tillg\u00e4nglig i din webbl\u00e4sare, anv\u00e4nd tangentbordsgenv\u00e4garna i st\u00e4llet.",clipboard_msg:"Kopiera/klipp ut/klistra in \u00e4r inte tillg\u00e4ngligt i din webbl\u00e4sare.\\nVill du veta mer?",not_set:"-- Inte satt --",class_name:"Klass",browse:"Bl\u00e4ddra",close:"St\u00e4ng",cancel:"Avbryt",update:"Uppdatera",insert:"Infoga",apply:"Applicera",edit_confirm:"Vill du anv\u00e4nda WYSIWYG l\u00e4get f\u00f6r denna textarea."},contextmenu:{full:"Utfyllnad",right:"H\u00f6ger",center:"Centrerad",left:"V\u00e4nster",align:"Justering"},insertdatetime:{day_short:"S\u00f6n,M\u00e5n,Tis,Ons,Tors,Fre,L\u00f6r,S\u00f6n",day_long:"S\u00f6ndag,M\u00e5ndag,Tisdag,Onsdag,Torsdag,Fredag,L\u00f6rdag,S\u00f6ndag",months_short:"Jan,Feb,Mar,Apr,Maj,Jun,Jul,Aug,Sep,Okt,Nov,Dec",months_long:"Januari,Februari,Mars,April,Maj,Juni,Juli,Augusti,September,Oktober,November,December",inserttime_desc:"Infoga tid",insertdate_desc:"Infoga datum",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d "},print:{print_desc:"Skriv ut"},preview:{preview_desc:"F\u00f6rhandsgranska"},directionality:{rtl_desc:"Skriftl\u00e4ge - h\u00f6ger till v\u00e4nster",ltr_desc:"Skriftl\u00e4ge - v\u00e4nster till h\u00f6ger"},layer:{content:"Nytt lager...",absolute_desc:"Sl\u00e5 av/p\u00e5 absolut positionering",backward_desc:"Flytta bak\u00e5t",forward_desc:"Flytta fram\u00e5t",insertlayer_desc:"Infoga nytt lager"},save:{save_desc:"Spara",cancel_desc:"Hoppa \u00f6ver alla f\u00f6r\u00e4ndringar"},nonbreaking:{nonbreaking_desc:"Infoga icke radbrytande mellanslag"},iespell:{download:"ieSpell kunde inte hittas, vill du installera denna nu?",iespell_desc:"R\u00e4ttstava"},advhr:{advhr_desc:"Horisontell skiljelinje",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smileys",delta_height:"",delta_width:""},searchreplace:{replace_desc:"S\u00f6k/ers\u00e4tt",search_desc:"S\u00f6k",delta_width:"",delta_height:""},advimage:{image_desc:"Infoga/redigera bild",delta_width:"",delta_height:""},advlink:{link_desc:"Infoga/redigera l\u00e4nk",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Redigera attribut",ins_desc:"Markera som tillagt",del_desc:"Markera som struket",acronym_desc:"Akronym",abbr_desc:"F\u00f6rkortning",cite_desc:"citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Redigera inline CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Markera allt",paste_word_desc:"Klistra in fr\u00e5n Word",paste_text_desc:"Klistra in som text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Anv\u00e4nd ctrl-v p\u00e5 ditt tangentbord f\u00f6r att klistra in i detta f\u00f6nster.",text_linebreaks:"Spara radbrytningar",text_title:"Anv\u00e4nd ctrl-v p\u00e5 ditt tangentbord f\u00f6r att klistra in i detta f\u00f6nster."},table:{cell:"Cell",col:"Kolumn",row:"Rad",del:"Radera tabell",copy_row_desc:"Klistra in rad",cut_row_desc:"Klipp ut rad",paste_row_after_desc:"Klistra in rad efter",paste_row_before_desc:"Klistra in rad ovanf\u00f6r",props_desc:"Tabellinst\u00e4llningar",cell_desc:"Tabellcellsinst\u00e4llningar",row_desc:"Tabellradsinst\u00e4llningar",merge_cells_desc:"Sammanfoga celler",split_cells_desc:"Separera sammansatta celler",delete_col_desc:"Radera kolumn",col_after_desc:"Infoga kolumn efter",col_before_desc:"Infoga kolumn f\u00f6re",delete_row_desc:"Radera rad",row_after_desc:"Infoga ny rad efter",row_before_desc:"Infoga ny rad f\u00f6re",desc:"Infoga/redigera ny tabell",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"F\u00f6r\u00e4ndringarna du gjorde kommer att g\u00e5 f\u00f6rlorade om du v\u00e4ljer att l\u00e4mna denna sida.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Sl\u00e5 av/p\u00e5 fullsk\u00e4rmsl\u00e4ge"},media:{edit:"Redigera inb\u00e4ddad media",desc:"Infoga/redigera inb\u00e4ddad media",delta_height:"",delta_width:""},fullpage:{desc:"Dokumentinst\u00e4llningar",delta_width:"",delta_height:""},template:{desc:"Infoga en f\u00e4rdig mall"},visualchars:{desc:"Visa osynliga tecken"},spellchecker:{desc:"Sl\u00e5 av/p\u00e5 r\u00e4ttstavningskontroll",menu:"R\u00e4ttstavningsinst\u00e4llningar",ignore_word:"Ignorera ord",ignore_words:"Ignorera alla",langs:"Spr\u00e5k",wait:"Var god v\u00e4nta...",sug:"F\u00f6rslag",no_sug:"Inga f\u00f6rslag",no_mpell:"Kunde inte finna n\u00e5gra felstavningar."},pagebreak:{desc:"Infoga sidbrytning"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/si.js0000644000175000017500000002242311526350525031523 0ustar frankiefrankietinyMCE.addI18n({si:{common:{more_colors:"\u0dad\u0dc0\u0dad\u0dca \u0dc0\u0dbb\u0dca\u0dab",invalid_data:"\u0dc0\u0dbb\u0daf: \u0dc0\u0dbd\u0d82\u0d9c\u0dd4 \u0db1\u0ddc\u0db8\u0dd0\u0dad\u0dd2 \u0d85\u0d9c\u0dba\u0db1\u0dca \u0d87\u0dad\u0dd4\u0dc5\u0dad\u0dca \u0d9a\u0dbb \u0d87\u0dad,\u0d91\u0db8 \u0d85\u0d9c\u0dba\u0db1\u0dca \u0dbb\u0dad\u0dd4 \u0db4\u0dcf\u0da7\u0dd2\u0db1\u0dca \u0dc3\u0dc5\u0d9a\u0dd4\u0dab\u0dd4 \u0d9a\u0dbb \u0d87\u0dad.",popup_blocked:"\u0d94\u0db6\u0d9c\u0dda popup-blocker \u0db8\u0d9f\u0dd2\u0db1\u0dca \u0d8b\u0db4\u0dba\u0ddd\u0d9c\u0dd2 \u0dc3\u0dda\u0dc0\u0dcf\u0dc0\u0db1\u0dca \u0dc3\u0db4\u0dba\u0db1 \u0d9a\u0dc0\u0dd4\u0dbd\u0dd4\u0dc0\u0d9a\u0dca \u0d85\u0db6\u0dbd \u0d9a\u0dbb \u0d87\u0dad.\u0d91\u0db6\u0dd0\u0dc0\u0dd2\u0db1\u0dca \u0d94\u0db6\u0da7 popup-blocker \u0dba \u0d85\u0d9a\u0dca\u200d\u0dbb\u0dd3\u0dba \u0d9a\u0dd2\u0dbb\u0dd3\u0db8\u0da7 \u0dc3\u0dd2\u0daf\u0dd4\u0dc0\u0dda. ",clipboard_no_support:"\u0daf\u0dd0\u0db1\u0da7 \u0db4\u0dca\u200d\u0dbb\u0daf\u0dbb\u0dca\u0dc1\u0d9a\u0dba \u0db8\u0d9f\u0dd2\u0db1\u0dca \u0db8\u0dd9\u0db8 \u0dc3\u0dda\u0dc0\u0dba \u0dc3\u0db4\u0dba\u0dcf \u0db1\u0dd0\u0dad,\u0d91\u0db6\u0dd0\u0dc0\u0dd2\u0db1\u0dca \u0dba\u0dad\u0dd4\u0dbb\u0dd4\u0db4\u0dd4\u0dc0\u0dbb\u0dd4\u0dc0 \u0db7\u0dcf\u0dc0\u0dd2\u0dad\u0dcf \u0d9a\u0dbb\u0db1\u0dca\u0db1.",clipboard_msg:"\u0db4\u0dd2\u0da7\u0db4\u0dad\u0dca \u0d9a\u0dd2\u0dbb\u0dd3\u0db8/\u0d89\u0dc0\u0dad\u0dca \u0d9a\u0dd2\u0dbb\u0dd3\u0db8/\u0d87\u0dbd\u0dc0\u0dd3\u0db8 \u0db8\u0ddc\u0dc3\u0dd2\u0dbd\u0dca\u0dbd\u0dcf \u0dc4\u0dcf \u0dc6\u0dba\u0dbb\u0dca \u0dc6\u0ddc\u0d9a\u0dca\u0dc3\u0dca \u0dc4\u0dd2 \u0d87\u0dad\u0dd4\u0dc5\u0dad\u0dca \u0db1\u0ddc\u0dc0\u0dda.\\n\u0d94\u0db6\u0da7 \u0db8\u0dda \u0db4\u0dd2\u0dc5\u0dd2\u0db6\u0db3\u0dc0 \u0dad\u0da0\u0daf\u0dd4\u0dbb\u0da7\u0dad\u0dca \u0dad\u0ddc\u0dbb\u0dad\u0dd4\u0dbb\u0dd4 \u0d85\u0dc0\u0dc1\u0dca\u200d\u0dba \u0dc0\u0dda\u0daf?",not_set:"-- Not set --",class_name:"\u0dc3\u0db8\u0dd6\u0dc4\u0dba",browse:"Browse",close:"\u0d89\u0dc0\u0dad\u0dca\u0dc0\u0db1\u0dca\u0db1",cancel:"\u0d85\u0dc0\u0dbd\u0d82\u0d9c\u0dd4 \u0d9a\u0dbb\u0db1\u0dca\u0db1",update:"\u0d85\u0dbd\u0dd4\u0dad\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",insert:"\u0d87\u0dad\u0dd4\u0dc5\u0dad\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",apply:"\u0dba\u0ddc\u0daf\u0db1\u0dca\u0db1",edit_confirm:"\u0d94\u0db6\u0da7 \u0db8\u0dd9\u0db8 \u0db4\u0dcf\u0da8\u0dba\u0db1\u0dca \u0dc3\u0db3\u0dc4\u0dcf WYSIWYG \u0d86\u0d9a\u0dcf\u0dbb\u0dba?"},contextmenu:{full:"\u0db4\u0dd6\u0dbb\u0dca\u0dab\u0dc0",right:"\u0daf\u0d9a\u0dd4\u0dab\u0da7",center:"\u0db8\u0dd0\u0daf\u0da7",left:"\u0dc0\u0db8\u0da7",align:"\u0db4\u0dd9\u0dc5 \u0d9c\u0dd0\u0db1\u0dca\u0dc0\u0dd4\u0db8"},insertdatetime:{day_short:"\u0d89\u0dbb\u0dd2\u0daf\u0dcf,\u0dc3\u0db3\u0dd4\u0daf\u0dcf,\u0d85\u0d9f.,\u0db6\u0daf\u0dcf\u0daf\u0dcf,\u0db6\u0dca\u200d\u0dbb\u0dc4\u0dc3\u0dca.,\u0dc3\u0dd2\u0d9a\u0dd4.,\u0dc3\u0dd9\u0db1.",day_long:"\u0d89\u0dbb\u0dd2\u0daf\u0dcf,\u0dc3\u0db3\u0dd4\u0daf\u0dcf,\u0d85\u0d9f\u0dc4\u0dbb\u0dd0\u0dc0\u0dcf\u0daf\u0dcf,\u0db6\u0daf\u0dcf\u0daf\u0dcf,\u0db6\u0dca\u200d\u0dbb\u0dc4\u0dc3\u0dca\u0db4\u0dad\u0dd2\u0db1\u0dca\u0daf\u0dcf,\u0dc3\u0dd2\u0d9a\u0dd4\u0dbb\u0dcf\u0daf\u0dcf,\u0dc3\u0dd9\u0db1\u0dc3\u0dd4\u0dbb\u0dcf\u0daf\u0dcf",months_short:"\u0da2\u0db1.,\u0db4\u0dd9\u0db6.,\u0db8\u0dcf\u0dbb\u0dca\u0dad\u0dd4,\u0d85\u0db4\u0dca\u200d\u0dbb\u0dda\u0dbd\u0dca,\u0db8\u0dd0\u0dba\u0dd2,\u0da2\u0dd6\u0db1\u0dd2,\u0da2\u0dd6\u0dbd\u0dd2,\u0d85\u0d9c\u0ddd.,\u0dc3\u0dd0\u0dca.,\u0d94\u0d9a\u0dca.,\u200d\u0db1\u0ddc\u0dc0\u0dd0.,\u0daf\u0dd9\u0dc3\u0dd0.",months_long:"\u0da2\u0db1\u0dc0\u0dcf\u0dbb\u0dd2,\u0db4\u0dd9\u0db6\u0dbb\u0dc0\u0dcf\u0dbb\u0dd2,\u0db8\u0dcf\u0dbb\u0dca\u0dad\u0dd4,\u0d85\u0db4\u0dca\u200d\u0dbb\u0dda\u0dbd\u0dca,\u0db8\u0dd0\u0dba\u0dd2,\u0da2\u0dd6\u0db1\u0dd2,\u0da2\u0dd6\u0dbd\u0dd2,\u0d85\u0d9c\u0ddd\u0dc3\u0dca\u0dad\u0dd4,\u0dc3\u0dd0\u0dca\u0dad\u0dd0\u0db8\u0dca\u0db6\u0dbb\u0dca,\u0d94\u0d9a\u0dca\u0dad\u0ddd\u0db6\u0dbb\u0dca,\u200d\u0db1\u0ddc\u0dc0\u0dd0\u0db8\u0dca\u0db6\u0dbb\u0dca,\u0daf\u0dd9\u0dc3\u0dd0\u0db8\u0dca\u0db6\u0dbb\u0dca",inserttime_desc:"\u0dc0\u0dda\u0dbd\u0dcf\u0dc0 \u0d87\u0dad\u0dd4\u0dc5\u0dad\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",insertdate_desc:"\u0daf\u0dd2\u0db1\u0dba \u0d87\u0dad\u0dd4\u0dc5\u0dad\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1",time_fmt:"%\u0db4\u0dd0\u0dba:%\u0db8\u0dd2\u0dc3:%\u0dad\u0dad\u0dca",date_fmt:"%\u0d85\u0dc0\u0dd4-%\u0db8\u0dcf\u0dc3-%\u0daf\u0dd2\u0db1"},print:{print_desc:"\u0db8\u0dd4\u0daf\u0dca\u200d\u0dbb\u0dab\u0dba \u0d9a\u0dbb\u0db1\u0dc0\u0dcf"},preview:{preview_desc:"\u0db4\u0dd6\u0dbb\u0dca\u0dc0 \u0daf\u0dbb\u0dca\u0dc1\u0db1\u0dba"},directionality:{rtl_desc:"\u0daf\u0d9a\u0dd4\u0dab\u0dda \u0dc3\u0dd2\u0da7 \u0dc0\u0db8\u0da7 \u0daf\u0dd2\u0dc1\u0dcf\u0dc0",ltr_desc:"\u0dc0\u0db8\u0dda \u0dc3\u0dd2\u0da7 \u0daf\u0d9a\u0dd4\u0dab\u0da7 \u0daf\u0dd2\u0dc1\u0dcf\u0dc0"},layer:{content:"\u0d85\u0dbd\u0dd4\u0dad\u0dca \u0dc3\u0dca\u0dae\u0dbb\u0dba\u0d9a\u0dca...",absolute_desc:"Toggle absolute positioning",backward_desc:"\u0db4\u0dc3\u0dd4\u0db4\u0dc3\u0da7 \u0d9c\u0dd9\u0db1\u0dba\u0db1\u0dca\u0db1",forward_desc:"\u0d89\u0daf\u0dd2\u0dbb\u0dd2\u0dba\u0da7 \u0d9c\u0dd9\u0db1\u0dba\u0db1\u0dca\u0db1",insertlayer_desc:"\u0d85\u0db5\u0dad\u0dca \u0dc3\u0dca\u0dae\u0dbb\u0dba\u0d9a\u0dca \u0d87\u0dad\u0dd4\u0dc5\u0dad\u0dca \u0d9a\u0dbb\u0db1\u0dca\u0db1"},save:{save_desc:"\u0dc3\u0dd4\u0dbb\u0d9a\u0dd2\u0db1\u0dca\u0db1",cancel_desc:"\u0d85\u0dc0\u0dbd\u0d82\u0d9c\u0dd4 \u0d9a\u0dbb\u0db1\u0dca\u0db1"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell \u0d85\u0db1\u0dcf\u0dc0\u0dbb\u0db1\u0dba \u0dc0\u0dd6\u0dba\u0dda \u0db1\u0dd0\u0dad. \u0d94\u0db6\u0da7 \u0d91\u0dba \u0db4\u0dd2\u0dc4\u0dd2\u0da7\u0dd4\u0dc0\u0dd3\u0db8\u0da7 \u0d85\u0dc0\u0dc1\u0dca\u200d\u0dba \u0daf?",iespell_desc:"\u0d85\u0d9a\u0dca\u0dc2\u0dbb \u0dc0\u0dd2\u0db1\u0dca\u200d\u0dba\u0dcf\u0dc3\u0dba \u0db4\u0dbb\u0dd3\u0d9a\u0dc2\u0dcf \u0d9a\u0dbb\u0db1\u0dca\u0db1"},advhr:{advhr_desc:"Horizontale rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ru.js0000644000175000017500000003627511526350525031550 0ustar frankiefrankietinyMCE.addI18n({ru:{common:{more_colors:"\u0414\u0440\u0443\u0433\u0438\u0435 \u0446\u0432\u0435\u0442\u0430...",invalid_data:"\u041e\u0448\u0438\u0431\u043a\u0430: \u0412\u0432\u0435\u0434\u0435\u043d\u043e \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043e\u043d\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043e \u043a\u0440\u0430\u0441\u043d\u044b\u043c.",popup_blocked:"\u0411\u043b\u043e\u043a\u0438\u0440\u0430\u0442\u043e\u0440 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u043e\u043a\u043e\u043d \u0437\u0430\u043a\u0440\u044b\u043b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u043e\u043a\u043d\u043e. \u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b, \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u0441\u0430\u0439\u0442\u0435.",clipboard_no_support:"\u041d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0412\u0430\u0448\u0438\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0433\u043e\u0440\u044f\u0447\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438.",clipboard_msg:"\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0432\u044b\u0440\u0435\u0437\u043a\u0430 \u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0430 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 Firefox.\\r\\n\u0425\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e?",not_set:"- \u041d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e -",class_name:"\u041a\u043b\u0430\u0441\u0441",browse:"\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440",close:"\u0417\u0430\u043a\u0440\u044b\u0442\u044c",cancel:"\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",update:"\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c",insert:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c",apply:"\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c",edit_confirm:"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WYSIWYG \u0440\u0435\u0436\u0438\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f?"},contextmenu:{full:"\u041f\u043e \u0448\u0438\u0440\u0438\u043d\u0435",right:"\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",center:"\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",left:"\u041f\u043e \u043b\u0435\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",align:"\u0412\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435"},insertdatetime:{day_short:"\u0432\u0441,\u043f\u043d,\u0432\u0442,\u0441\u0440,\u0447\u0442,\u043f\u0442,\u0441\u0431,\u0432\u0441",day_long:"\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435,\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a,\u0432\u0442\u043e\u0440\u043d\u0438\u043a,\u0441\u0440\u0435\u0434\u0430,\u0447\u0435\u0442\u0432\u0435\u0440\u0433,\u043f\u044f\u0442\u043d\u0438\u0446\u0430,\u0441\u0443\u0431\u0431\u043e\u0442\u0430,\u0432\u043e\u0441\u043a\u0440\u0435\u0441\u0435\u043d\u044c\u0435",months_short:"\u044f\u043d\u0432,\u0444\u0435\u0432,\u043c\u0430\u0440\u0442,\u0430\u043f\u0440,\u043c\u0430\u0439,\u0438\u044e\u043d\u044c,\u0438\u044e\u043b\u044c,\u0430\u0432\u0433,\u0441\u0435\u043d,\u043e\u043a\u0442,\u043d\u043e\u044f,\u0434\u0435\u043a",months_long:"\u044f\u043d\u0432\u0430\u0440\u044c,\u0444\u0435\u0432\u0440\u0430\u043b\u044c,\u043c\u0430\u0440\u0442,\u0430\u043f\u0440\u0435\u043b\u044c,\u043c\u0430\u0439,\u0438\u044e\u043d\u044c,\u0438\u044e\u043b\u044c,\u0430\u0432\u0433\u0443\u0441\u0442,\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044c,\u043e\u043a\u0442\u044f\u0431\u0440\u044c,\u043d\u043e\u044f\u0431\u0440\u044c,\u0434\u0435\u043a\u0430\u0431\u0440\u044c",inserttime_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f",insertdate_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u0442\u0443",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"\u041f\u0435\u0447\u0430\u0442\u044c"},preview:{preview_desc:"\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440"},directionality:{rtl_desc:"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e",ltr_desc:"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e"},layer:{content:"\u041d\u043e\u0432\u044b\u0439 \u0441\u043b\u043e\u0439",absolute_desc:"\u0410\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435",backward_desc:"\u041d\u0430 \u0437\u0430\u0434\u043d\u0438\u0439 \u043f\u043b\u0430\u043d",forward_desc:"\u041d\u0430 \u043f\u0435\u0440\u0435\u0434\u043d\u0438\u0439 \u043f\u043b\u0430\u043d",insertlayer_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u043e\u0439"},save:{save_desc:"\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c",cancel_desc:"\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f"},nonbreaking:{nonbreaking_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u0440\u0430\u0437\u0440\u044b\u0432\u043d\u044b\u0439 \u043f\u0440\u043e\u0431\u0435\u043b"},iespell:{download:"ieSpell \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d. \u0416\u0435\u043b\u0430\u0435\u0442\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c?",iespell_desc:"\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u044e"},advhr:{advhr_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043c\u0430\u0439\u043b",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c",search_desc:"\u041d\u0430\u0439\u0442\u0438",delta_width:"",delta_height:""},advimage:{delta_width:"200",image_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c/\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",delta_height:""},advlink:{delta_width:"200",link_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c/\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443",delta_height:""},xhtmlxtras:{attribs_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c/\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442",ins_desc:"\u0417\u0430\u043c\u0435\u043d\u0430",del_desc:"\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435",acronym_desc:"\u0410\u0431\u0431\u0440\u0435\u0432\u0438\u0430\u0446\u0438\u044f",abbr_desc:"\u0421\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0435",cite_desc:"\u0426\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c CSS \u0441\u0442\u0438\u043b\u044c",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"\u0412\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0432\u0441\u0435",paste_word_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u0437 Word",paste_text_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442"},paste_dlg:{word_title:"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 CTRL+V \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043e\u043a\u043d\u043e.",text_linebreaks:"\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u044b \u0441\u0442\u0440\u043e\u043a",text_title:"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 CTRL+V \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043e\u043a\u043d\u043e."},table:{cellprops_delta_width:"30",cell:"\u042f\u0447\u0435\u0439\u043a\u0430",col:"\u0421\u0442\u043e\u043b\u0431\u0435\u0446",row:"\u0421\u0442\u0440\u043e\u043a\u0430",del:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443",copy_row_desc:"\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",cut_row_desc:"\u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",paste_row_after_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443",paste_row_before_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443",props_desc:"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0442\u0430\u0431\u043b\u0438\u0446\u044b",cell_desc:"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u044f\u0447\u0435\u0439\u043a\u0438",row_desc:"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0440\u043e\u043a\u0438",merge_cells_desc:"\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0438",split_cells_desc:"\u0420\u0430\u0437\u0431\u0438\u0442\u044c \u044f\u0447\u0435\u0439\u043a\u0443",delete_col_desc:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446",col_after_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043f\u0440\u0430\u0432\u0430",col_before_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u0441\u043b\u0435\u0432\u0430",delete_row_desc:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443",row_after_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u043d\u0438\u0437\u0443",row_before_desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441\u0432\u0435\u0440\u0445\u0443",desc:"\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435/\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u0412\u0441\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0443\u0442\u0435\u0440\u044f\u043d\u044b.\\n\\n\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f?",restore_content:"\u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435",unload_msg:"\u041f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0443\u0442\u0435\u0440\u044f\u043d\u044b, \u0435\u0441\u043b\u0438 \u0412\u044b \u0443\u0439\u0434\u0435\u0442\u0435 \u0441 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b."},fullscreen:{desc:"\u041f\u043e\u043b\u043d\u043e\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c"},media:{edit:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043a\u043b\u0438\u043f\u0430",desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c/\u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043b\u0438",delta_height:"",delta_width:""},fullpage:{desc:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",delta_width:"",delta_height:""},template:{desc:"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d"},visualchars:{desc:"\u0412\u0441\u0435 \u0437\u043d\u0430\u043a\u0438"},spellchecker:{desc:"\u041f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",menu:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f",ignore_word:"\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c",ignore_words:"\u041f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432\u0441\u0435",langs:"\u042f\u0437\u044b\u043a\u0438",wait:"\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435...",sug:"\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b",no_sug:"\u041d\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432",no_mpell:"\u041e\u0448\u0438\u0431\u043e\u043a \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e."},pagebreak:{desc:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u044b\u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b"},advlist:{types:"\u0421\u0438\u043c\u0432\u043e\u043b\u044b",def:"\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435",lower_alpha:"\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b",lower_greek:"\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u0433\u0440\u0435\u0447\u0435\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b",lower_roman:"\u0421\u0442\u0440\u043e\u0447\u043d\u044b\u0435 \u0440\u0438\u043c\u0441\u043a\u0438\u0435 \u0446\u0438\u0444\u0440\u044b",upper_alpha:"\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u043b\u0430\u0442\u0438\u043d\u0441\u043a\u0438\u0435 \u0431\u0443\u043a\u0432\u044b",upper_roman:"\u0417\u0430\u0433\u043b\u0430\u0432\u043d\u044b\u0435 \u0440\u0438\u043c\u0441\u043a\u0438\u0435 \u0446\u0438\u0444\u0440\u044b",circle:"\u041a\u0440\u0443\u0433\u0438",disc:"\u041e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438",square:"\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u044b"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/sk.js0000644000175000017500000001540611526350525031530 0ustar frankiefrankietinyMCE.addI18n({sk:{common:{more_colors:"\u010eal\u0161ie farby",invalid_data:"Chyba: Boli zadan\u00e9 neplatn\u00e9 hodnoty a tieto boli ozna\u010den\u00e9 \u010dervenou farbou.",popup_blocked:"Blokovanie vyskakovac\u00edch okien neumo\u017enilo otvori\u0165 okno, ktor\u00e9 poskytuje funk\u010dnos\u0165 aplik\u00e1cie. Pre pln\u00e9 vyu\u017eitie mo\u017enost\u00ed aplik\u00e1cie mus\u00edte vypn\u00fa\u0165 blokovanie vyskakovac\u00edch okien pre tento web.",clipboard_no_support:"T\u00e1to funkcia nie je va\u0161\u00edm prehliada\u010dom podporovan\u00e1. Pou\u017eite namiesto toho kl\u00e1vesov\u00fa skratku.",clipboard_msg:"Funkcie kop\u00edrova\u0165/vystrihn\u00fa\u0165/vlo\u017ei\u0165 nie s\u00fa podporovan\u00e9 v prehliada\u010doch Mozilla a Firefox.\\nChcete viac inform\u00e1ci\u00ed o tomto probl\u00e9me?",not_set:"-- Nezadan\u00e9 --",class_name:"Trieda",browse:"Prech\u00e1dza\u0165",close:"Zavrie\u0165",cancel:"Storno",update:"Aktualizova\u0165",insert:"Vlo\u017ei\u0165",apply:"Pou\u017ei\u0165",edit_confirm:"Chcete pou\u017ei\u0165 WYSIWYG re\u017eim pre tento text?"},contextmenu:{full:"Do bloku",right:"Doprava",center:"Na stred",left:"Do\u013eava",align:"Zarovnanie"},insertdatetime:{day_short:"Ne,Po,Ut,St,\u0160t,Pi,So,Ne",day_long:"Nede\u013ea,Pondelok,Utorok,Streda,\u0160tvrtok,Piatok,Sobota,Nede\u013ea",months_short:"Jan,Feb,Mar,Apr,M\u00e1j,J\u00fan,J\u00fal,Aug,Sep,Okt,Nov,Dec",months_long:"Janu\u00e1r,Febru\u00e1r,Marec,Apr\u00edl,M\u00e1j,J\u00fan,J\u00fal,August,September,Okt\u00f3ber,November,December",inserttime_desc:"Vlo\u017ei\u0165 \u010das",insertdate_desc:"Vlo\u017ei\u0165 d\u00e1tum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"Tla\u010d"},preview:{preview_desc:"N\u00e1h\u013ead"},directionality:{rtl_desc:"Smer sprava do\u013eava",ltr_desc:"Smer z\u013eava doprava"},layer:{content:"Nov\u00e1 vrstva...",absolute_desc:"Prepn\u00fa\u0165 na absol\u00fatne poziciovanie",backward_desc:"Presun\u00fa\u0165 dozadu",forward_desc:"Presun\u00fa\u0165 dopredu",insertlayer_desc:"Vlo\u017ei\u0165 nov\u00fa vrstvu"},save:{save_desc:"Ulo\u017ei\u0165",cancel_desc:"Zru\u0161i\u0165 v\u0161etky zmeny"},nonbreaking:{nonbreaking_desc:"Vlo\u017ei\u0165 nerozdelite\u013en\u00fa medzeru"},iespell:{download:"Slovn\u00edk ieSpell nebol detekovan\u00fd. Chcete ho nain\u0161talova\u0165?",iespell_desc:"Spusti\u0165 kontrolu pravopisu"},advhr:{advhr_desc:"Vodorovn\u00fd odde\u013eova\u010d",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotikony",delta_height:"",delta_width:""},searchreplace:{replace_desc:"H\u013eada\u0165 a nahradi\u0165",search_desc:"H\u013eada\u0165",delta_width:"",delta_height:""},advimage:{delta_width:"40",image_desc:"Vlo\u017ei\u0165/upravi\u0165 obr\u00e1zok",delta_height:""},advlink:{link_desc:"Vlo\u017ei\u0165/upravi\u0165 odkaz",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Vlo\u017ei\u0165/upravi\u0165 atrib\u00faty",ins_desc:"Pridan\u00fd text",del_desc:"Odstr\u00e1nen\u00fd text",acronym_desc:"Akronym",abbr_desc:"Skratka",cite_desc:"Cit\u00e1cia",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{delta_width:"35",desc:"Upravi\u0165 CSS \u0161t\u00fdl",delta_height:""},paste:{plaintext_mode:"Funkcia vlo\u017ei\u0165 je teraz v re\u017eime prost\u00fd text. Op\u00e4tovn\u00e9 kliknutie prepne t\u00fato funkciu nasp\u00e4\u0165 do norm\u00e1lneho re\u017eimu.",plaintext_mode_sticky:"Funkcia vlo\u017ei\u0165 je teraz v re\u017eime prost\u00fd text. Op\u00e4tovn\u00e9 kliknutie prepne t\u00fato funkciu nasp\u00e4\u0165 do norm\u00e1lneho re\u017eimu. Po vlo\u017een\u00ed \u010dohoko\u013evek bude t\u00e1to funkcia navr\u00e1ten\u00e1 sp\u00e4\u0165 do norm\u00e1lneho re\u017eimu.",selectall_desc:"Ozna\u010di\u0165 v\u0161etko",paste_word_desc:"Vlo\u017ei\u0165 z Wordu",paste_text_desc:"Vlo\u017ei\u0165 ako prost\u00fd text"},paste_dlg:{word_title:"Pou\u017eite CTRL+V pre vlo\u017eenie textu do okna.",text_linebreaks:"Zachova\u0165 zalamovanie riadkov",text_title:"Pou\u017eite CTRL+V pre vlo\u017eenie textu do okna."},table:{table_delta_width:"50",cellprops_delta_width:"105",cell:"Bunka",col:"St\u013apec",row:"Riadok",del:"Odstr\u00e1ni\u0165 tabu\u013eku",copy_row_desc:"Kop\u00edrova\u0165 riadok tabu\u013eky",cut_row_desc:"Vystrihn\u00fa\u0165 riadok tabu\u013eky",paste_row_after_desc:"Vlo\u017ei\u0165 riadok za",paste_row_before_desc:"Vlo\u017ei\u0165 riadok pred",props_desc:"Vlastnosti tabu\u013eky",cell_desc:"Vlastnosti bunky",row_desc:"Vlastnosti riadky tabu\u013eky",merge_cells_desc:"Zl\u00fa\u010di\u0165 bunky",split_cells_desc:"Rozdeli\u0165 bunky",delete_col_desc:"Odstr\u00e1ni\u0165 st\u013apec tabu\u013eky",col_after_desc:"Vlo\u017ei\u0165 st\u013apec za",col_before_desc:"Vlo\u017ei\u0165 st\u013apec pred",delete_row_desc:"Odstr\u00e1ni\u0165 riadok tabu\u013eky",row_after_desc:"Vlo\u017ei\u0165 riadok za",row_before_desc:"Vlo\u017ei\u0165 riadok pred",desc:"Vlo\u017ei\u0165 nov\u00fa tabu\u013eku",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Pokia\u013e obnov\u00edte ulo\u017een\u00fd obsah, strat\u00edte t\u00fdm v\u0161etok obsah, ktor\u00fd je pr\u00e1ve v okne editora.\\n\\nSkuto\u010dne chcete obnovi\u0165 ulo\u017een\u00fd obsah?.",restore_content:"Obnovi\u0165 automaticky ulo\u017een\u00fd obsah.",unload_msg:"Preveden\u00e9 zmeny m\u00f4\u017eu by\u0165 straten\u00e9, ak opust\u00edte t\u00fato str\u00e1nku."},fullscreen:{desc:"Prepn\u00fa\u0165 na celostr\u00e1nkov\u00e9 zobrazenie"},media:{delta_width:"180",edit:"Upravi\u0165 m\u00e9di\u00e1",desc:"Vlo\u017ei\u0165/upravi\u0165 m\u00e9di\u00e1",delta_height:""},fullpage:{desc:"Vlastnosti dokumentu",delta_width:"115",delta_height:""},template:{desc:"Vlo\u017ei\u0165 preddefinovan\u00fd obsah zo \u0161abl\u00f3ny"},visualchars:{desc:"Zobrazenie skryt\u00fdch znakov zap/vyp"},spellchecker:{desc:"Prepn\u00fa\u0165 kontrolu pravopisu",menu:"Nastavenie kontroly pravopisu",ignore_word:"Vynecha\u0165 slovo",ignore_words:"Vynecha\u0165 v\u0161etky",langs:"Jazyky",wait:"\u010cakajte pros\u00edm...",sug:"Ponuky",no_sug:"\u017diadne ponuky",no_mpell:"Bez pravopisn\u00fdch ch\u00fdb."},pagebreak:{desc:"Vlo\u017ei\u0165 zalomenie str\u00e1nky."},advlist:{types:"Typ",def:"Predvolen\u00fd",lower_alpha:"Mal\u00e9 p\u00edsmen\u00e1",lower_greek:"Mal\u00e9 gr\u00e9cke p\u00edsmen\u00e1",lower_roman:"Mal\u00e9 r\u00edmske \u010d\u00edslice",upper_alpha:"Ve\u013ek\u00e9 p\u00edsmen\u00e1",upper_roman:"Ve\u013ek\u00e9 r\u00edmske \u010d\u00edslice",circle:"Kr\u00fa\u017eok",disc:"Pln\u00e9 koliesko",square:"\u0160tvor\u010dek"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/sl.js0000644000175000017500000001311111526350525031520 0ustar frankiefrankietinyMCE.addI18n({sl:{common:{more_colors:"Ve\u010d barv",invalid_data:"Napaka: vne\u0161ene so bile nepravilne vrednosti, ozna\u010dene so z rde\u010do.",popup_blocked:"\u017dal va\u0161e orodje za prepre\u010devanje odpiranja neza\u017eelenih oken (popup-blocker) ne omogo\u010da prikaza pomo\u017enega okna izbranega orodja. Prepre\u010devanje odpiranja oken morate onemogo\u010diti.",clipboard_no_support:"Trenutno ni podporto v va\u0161em brskalniku. Uporabite bli\u017enjice tipkovnice.",clipboard_msg:"Delo z odlo\u017ei\u0161\u010dem ni mogo\u010de v tem brskalniku. Lahko uporabljate kombinacije tipk Ctrl+X, Ctrl+C, Ctrl+V.\\n\u017delite ve\u010d informacij o tem?",not_set:"-- ni nastavljeno --",class_name:"Razred",browse:"Prebrskaj",close:"Zapri",cancel:"Prekli\u010di",update:"Posodobi",insert:"Vstavi",apply:"Uporabi",edit_confirm:"\u017delite uporabiti na\u010din \\\'videz ne vara\\\' (WYSIWYG) za to vnosno polje?"},contextmenu:{full:"Polno",right:"Desno",center:"Sredina",left:"Levo",align:"Poravnava"},insertdatetime:{day_short:"ned,pon,tor,sre,\u010det,pet,sob,ned",day_long:"nedelja,ponedeljek,torek,sreda,\u010detrtek,petek,sobota,nedelja",months_short:"jan,feb,mar,apr,maj,jun,jul,avg,sep,okt,nov,dec",months_long:"januar,februar,marec,april,maj,junij,julij,avgust,september,oktober,november,december",inserttime_desc:"Vstavi \u010das",insertdate_desc:"Vstavi datum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"Natisni"},preview:{preview_desc:"Predogled"},directionality:{rtl_desc:"Smer od desne proti levi",ltr_desc:"Smer od leve proti desni"},layer:{content:"Nov sloj...",absolute_desc:"Preklop absolutnega polo\u017eaja",backward_desc:"Premakni v ozadje",forward_desc:"Premakni v ospredje",insertlayer_desc:"Vstavi nov sloj"},save:{save_desc:"Shrani",cancel_desc:"Prekli\u010di vse spremembe"},nonbreaking:{nonbreaking_desc:"Vstavi nedeljivi presledek"},iespell:{download:"ieSpell ni zaznan. \u017delite, da ga namestim?",iespell_desc:"Za\u017eeni preverjanje \u010drkovanja"},advhr:{advhr_desc:"Vodoravna \u010drta",delta_height:"",delta_width:""},emotions:{delta_height:"delta_vi\u0161ina",delta_width:"delta_\u0161irina",emotions_desc:"Sme\u0161ki"},searchreplace:{replace_desc:"Najdi/zamenjaj",search_desc:"Najdi",delta_width:"",delta_height:""},advimage:{image_desc:"Vstavi/uredi sliko",delta_width:"",delta_height:""},advlink:{link_desc:"Vstavi/uredi povezavo",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Vstavi/uredi atribute",ins_desc:"Vstavljeno",del_desc:"Izbrisano",acronym_desc:"Kratica",abbr_desc:"Okraj\u0161ava",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Uredi sloge CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Operacija prilepi je sedaj v na\u010dinu \"golo besedilo\". \u010ce jo \u017eelite vrniti v obi\u010dajen na\u010din, kliknite \u0161e enkrat.",plaintext_mode_sticky:"Operacija prilepi je sedaj v na\u010dinu \"golo besedilo\". \u010ce jo \u017eelite vrniti v obi\u010dajen na\u010din, kliknite \u0161e enkrat. Po izvedbi lepljenja se bo nastavitev povrnila v obi\u010dajen na\u010din.",selectall_desc:"Izberi vse",paste_word_desc:"Prilepi iz Word-a",paste_text_desc:"Prilepi kot golo besedilo"},paste_dlg:{word_title:"Uporabite kombinacijo tipk CTRL+V, da prilepite vsebino v okno.",text_linebreaks:"Obdr\u017ei prelome vrstic",text_title:"Uporabite kombinacijo tipk CTRL+V, da prilepite vsebino v okno."},table:{cellprops_delta_width:"100",cell:"Celica",col:"Stolpec",row:"Vrstica",del:"Odstrani tabelo",copy_row_desc:"Kopiraj vrstico",cut_row_desc:"Izre\u017ei vrstico",paste_row_after_desc:"Prilepi vrstico po",paste_row_before_desc:"Prilepi vrstico pred",props_desc:"Lastnosti tabele",cell_desc:"Lastnosti celice",row_desc:"Lastnosti vrstice",merge_cells_desc:"Spoji celice",split_cells_desc:"Razcepi celico",delete_col_desc:"Odstrani stolpec",col_after_desc:"Vstavi stolpec po",col_before_desc:"Vstavi stolpec pred",delete_row_desc:"Odstrani vrstico",row_after_desc:"Vstavi vrstico pod",row_before_desc:"Vstavi vrstico nad",desc:"Vstavi/posodobi tabelo",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u010ce povrnete shranjeno vsebino, boste prepisali trenutno vsebino urejevalnika.nnSte prepri\u010dani, da \u017eelite nadaljevati?",restore_content:"Povrni na zadnje shranjeno vsebino.",unload_msg:"\u010ce nadaljujete, bodo spremembe izgubljene."},fullscreen:{desc:"Preklopi celozaslonski na\u010din"},media:{delta_height:"delta_\u0161irina",delta_width:"delta_\u0161irina",edit:"Uredi multimedijsko vsebino",desc:"Vstavi / uredi multimedijsko vsebino"},fullpage:{desc:"Lastnosti dokumenta",delta_width:"",delta_height:""},template:{desc:"Vstavi pripravljeno vsebino predloge"},visualchars:{desc:"Preklopi prikaz nadzornih znakov."},spellchecker:{desc:"Preklopi \u010drkovalnik",menu:"Nastavitve \u010drkovalnika",ignore_word:"Prezri besedo",ignore_words:"Prezri vse",langs:"Jeziki",wait:"Prosim po\u010dakaj...",sug:"Predlogi",no_sug:"Ni predlogov",no_mpell:"Napa\u010dnega \u010drkovanja nisem na\u0161el."},pagebreak:{desc:"Vstavi lom strani."},advlist:{types:"Tipi",def:"Privzeto",lower_alpha:"Mali znaki",lower_greek:"Male gr\u0161ke \u010drke",lower_roman:"Male latinske \u010drke",upper_alpha:"Veliki znaki",upper_roman:"Velike latinske \u010drke",circle:"Krog",disc:"Disk",square:"Kvadrat"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ta.js0000644000175000017500000001210211526350525031505 0ustar frankiefrankietinyMCE.addI18n({ta:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text"},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/te.js0000644000175000017500000001210211526350525031511 0ustar frankiefrankietinyMCE.addI18n({te:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- Not set --",class_name:"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/sq.js0000644000175000017500000001312211526350525031527 0ustar frankiefrankietinyMCE.addI18n({sq:{common:{more_colors:"M\u00eb shum\u00eb ngjyra",invalid_data:"Gabim: Keni futur vlera t\u00eb pavlefshme, t\u00eb cilat jan\u00eb sh\u00ebnuar me t\u00eb kuqe.",popup_blocked:"Ju k\u00ebrkojm\u00eb ndjes\u00eb, por bllokuesi i popup-eve ka bllokuar nj\u00eb dritare q\u00eb ofron funksjonalitet p\u00ebr programin. Duhet t\'a \u00e7aktivizoni bllokuesin e popup-eve n\u00eb m\u00ebnyr\u00eb q\u00eb t\'i p\u00ebrdorni opsionet.",clipboard_no_support:"Aktualisht nuk suportohet nga Shfletuesi juaj, p\u00ebrdorni tastjer\u00ebn.",clipboard_msg:"Kopja/Prerja/Ngjitja nuk suportohen n\u00eb Mozilla dhe Firefox.\\nD\u00ebshironi m\u00eb shum\u00eb informacione p\u00ebr k\u00ebt\u00eb \u00e7\u00ebshtje?",not_set:"-- pa v\u00ebn\u00eb --",class_name:"Klasa",browse:"Shfleto",close:"Mbyll",cancel:"Anulo",update:"Rifresko",insert:"Fut",apply:"Zbato",edit_confirm:"Doni t\u00eb p\u00ebrdorni m\u00ebnyr\u00ebn WYSIWYG p\u00ebr k\u00ebt\u00eb tekst?"},contextmenu:{full:"I Plot\u00eb",right:"Djathtas",center:"Qend\u00ebr",left:"Majtas",align:"Drejtimi"},insertdatetime:{day_short:"Dje,H\u00ebn,Mar,M\u00ebr,Enj,Pre,Sht,Dje",day_long:"E Djel\u00eb,E H\u00ebn\u00eb,E Mart\u00eb,E M\u00ebrkur\u00eb,E Enjte,E Premte,E Shtun\u00eb,E Djel\u00eb",months_short:"Jan,Shk,Mar,Pri,Maj,Qer,Kor,Gus,Sht,Tet,N\u00ebn,Dhj",months_long:"Janar,Shkurt,Mars,Prill,Maj,Qershor,Korrik,Gusht,Shtator,Tetor,N\u00ebntor,Dhjetor",inserttime_desc:"Fut or\u00ebn",insertdate_desc:"Fut dat\u00ebn",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%y"},print:{print_desc:"Printo"},preview:{preview_desc:"Paraqitje"},directionality:{rtl_desc:"Drejtimi djathtas-majtas",ltr_desc:"Drejtimi majtas-djathtas"},layer:{content:"Shtres\u00eb e re...",absolute_desc:"Aktivizo/\u00e7aktivizo pozicionimin absolut",backward_desc:"L\u00ebviz prapa",forward_desc:"L\u00ebviz para",insertlayer_desc:"Fut shtres\u00eb t\u00eb re"},save:{save_desc:"Ruaj",cancel_desc:"Anuloji t\u00eb gjitha ndryshimet"},nonbreaking:{nonbreaking_desc:"Fut hap\u00ebsir\u00eb"},iespell:{download:"ieSpell nuk u detektua. D\u00ebshironi ta instaloni?",iespell_desc:"Kontrollo p\u00ebr gabime drejt\u00ebshkrimore"},advhr:{advhr_desc:"Linj\u00eb horizontale",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emocionet",delta_height:"",delta_width:""},searchreplace:{replace_desc:"K\u00ebrko/Z\u00ebvend\u00ebso",search_desc:"K\u00ebrko",delta_width:"",delta_height:""},advimage:{image_desc:"Fut/edito foto",delta_width:"",delta_height:""},advlink:{link_desc:"Fut/edito lidhje",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Fut/Edito Tipare",ins_desc:"Futje",del_desc:"Fshirje",acronym_desc:"Akronim",abbr_desc:"Shkurtim",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edito Stilet CSS",delta_height:"",delta_width:""},paste:{selectall_desc:"Zgjidhi t\u00eb gjitha",paste_word_desc:"Ngjit nga Word",paste_text_desc:"Ngjit si Tekst",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"P\u00ebrdor CTRL+V p\u00ebr t\u00eb ngjitur tekstin.",text_linebreaks:"Ruaj linjat e reja",text_title:"P\u00ebrdor CTRL+V p\u00ebr t\u00eb ngjitur tekstin."},table:{cell:"Qeliz\u00eb",col:"Kolon\u00eb",row:"Rresht",del:"Fshi tabel\u00ebn",copy_row_desc:"Kopjo rreshtin",cut_row_desc:"Prit rreshtin",paste_row_after_desc:"Ngjite rreshtin pas",paste_row_before_desc:"Ngjite rreshtin p\u00ebrpara",props_desc:"Tiparet e tabel\u00ebs",cell_desc:"Tiparet e qeliz\u00ebs",row_desc:"Tiparet e rreshtit",merge_cells_desc:"Bashkoji qelizat",split_cells_desc:"Ndaji qelizat e bashkuara",delete_col_desc:"Fshi kolon\u00ebn",col_after_desc:"Fut kolon\u00eb pas",col_before_desc:"Fut kolon\u00eb p\u00ebrpara",delete_row_desc:"Fshi rreshtin",row_after_desc:"Fut rresht pas",row_before_desc:"Fut rresht p\u00ebrpara",desc:"Fut nj\u00eb tabel\u00eb t\u00eb re",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"Ndryshimet q\u00eb keni b\u00ebr\u00eb do t\u00eb humbasin n\u00ebse largoheni nga kjo faqe.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Aktivizo/\u00e7aktivizo pamjen e plot\u00eb"},media:{edit:"Edito media",desc:"Fut / edito media",delta_height:"",delta_width:""},fullpage:{desc:"Tiparet e dokumentit",delta_width:"",delta_height:""},template:{desc:"Fut p\u00ebrmbajtje shabllon"},visualchars:{desc:"Karakteret e kontrollit vizual: on/off."},spellchecker:{desc:"Aktivizo/\u00e7aktivizo kontrolluesin e gabimeve",menu:"Tiparet e kontrolluesit t\u00eb gabimeve",ignore_word:"Injoro fjal\u00ebn",ignore_words:"Injoroji t\u00eb gjitha",langs:"Gjuh\u00ebt",wait:"Ju lutem prisni...",sug:"Sygjerimet",no_sug:"Asnj\u00eb sygjerim",no_mpell:"Nuk u gjet asnj\u00eb gabim."},pagebreak:{desc:"Fut thyerje faqeje."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/sr.js0000644000175000017500000001244111526350525031533 0ustar frankiefrankietinyMCE.addI18n({sr:{common:{more_colors:"Vi\u0161e boja",invalid_data:"Gre\u0161ka: Une\u0161ene su pogre\u0161ne vrednosti, ozna\u010dene su crvenom bojom.",popup_blocked:"Oprostite, izgleda da je va\u0161 popup-blocker onemogu\u0107io prozor u sklopu ovog programa. Morate isklju\u010diti blokiranje popup prozora da bi u potpunosti iskoristili ovaj alat.",clipboard_no_support:"Trenuta\u010dno va\u0161 pretra\u017eiva\u010d ne podr\u017eava ovu opciju, poku\u0161ajte preko pre\u010dice na tastaturi.",clipboard_msg:"Kopiraj/Iseci/Zalepi nije dostupno Mozilla i Firefox preglednicima.\\nVi\u0161e informacija?",not_set:"-- Nije postavljeno --",class_name:"Klasa",browse:"Potra\u017ei",close:"Zatvori",cancel:"Odustani",update:"A\u017euriraj",insert:"Ubaci",apply:"Primeni",edit_confirm:"Da li \u017eelite da koristite WYSIWYG na\u010din rada za ovo tekstualno polje?"},contextmenu:{full:"Poravnato",right:"Desno",center:"Centrirano",left:"Levo",align:"Poravnanje"},insertdatetime:{day_short:"ned,pon,uto,sre,\u010det,pet,sub,ned",day_long:"nedelja,ponedjeljak,utorak,sreda,\u010detvrtak,petak,subota,nedelja",months_short:"jan,feb,mar,apr,maj,jun,jul,avg,sep,okt,nov,dec",months_long:"januar,februar,mart,april,maj,juni,juli,avgust,septembar,oktobar,novembar,decembar",inserttime_desc:"Ubaci vreme",insertdate_desc:"Ubaci datum",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y."},print:{print_desc:"\u0160tampaj"},preview:{preview_desc:"Pregled"},directionality:{rtl_desc:"S desna na levo",ltr_desc:"S leva na desno"},layer:{content:"Novi sloj...",absolute_desc:"Uklju\u010di/isklju\u010di apsolutno pozicioniranje",backward_desc:"Pomeri nazad",forward_desc:"Pomeri napred",insertlayer_desc:"Ubaci novi sloj"},save:{save_desc:"Sa\u010duvaj",cancel_desc:"Odustani od svih promena"},nonbreaking:{nonbreaking_desc:"Ubaci razmak"},iespell:{download:"Provera pravopisa nije instalirana. Sada instalirati?",iespell_desc:"Proveri pravopis"},advhr:{advhr_desc:"Horizontalna crta",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smajli",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Prona\u0111i/Zameni",search_desc:"Prona\u0111i",delta_width:"",delta_height:""},advimage:{image_desc:"Ubaci/uredi sliku",delta_width:"",delta_height:""},advlink:{link_desc:"Ubaci/izmeni link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Ubaci/izmeni atribute",ins_desc:"Unos",del_desc:"Brisanje",acronym_desc:"Akronim",abbr_desc:"Skra\u0107enica",cite_desc:"Citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Uredi CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Odaberi sve",paste_word_desc:"Zalepi iz Worda",paste_text_desc:"Zalepi kao obi\u010dni tekst"},paste_dlg:{word_title:"Koristite CTRL+V na tastaturi da zalepite tekst u prozor.",text_linebreaks:"Zadr\u017ei prelome",text_title:"Koristite CTRL+V na tastaturi da zalepite tekst u prozor."},table:{cell:"\u0106elija",col:"Kolona",row:"Red",del:"Obri\u0161i tabelu",copy_row_desc:"Kopiraj red",cut_row_desc:"Iseci red",paste_row_after_desc:"Zalepi red ispod",paste_row_before_desc:"Zalepi red iznad",props_desc:"Svojstva tabelee",cell_desc:"Svojstva \u0107elije",row_desc:"Svojstva reda",merge_cells_desc:"Spoji \u0107elije",split_cells_desc:"Razdvoji spojene \u0107elije",delete_col_desc:"Obri\u0161i kolonu",col_after_desc:"Ubaci kolonu desno",col_before_desc:"Ubaci kolonu levo",delete_row_desc:"Obri\u0161i red",row_after_desc:"Ubaci red ispod",row_before_desc:"Ubaci red iznad",desc:"Nova tabela",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"Izmene u dokumentu \u0107e biti izgubljene ako iza\u0111ete s ove stranice."},fullscreen:{desc:"Uklju\u010di/isklju\u010di prikaz preko celog ekrana"},media:{edit:"Uredi medije",desc:"Ubaci / uredi medije",delta_height:"",delta_width:""},fullpage:{desc:"Svojstva dokumenta",delta_width:"",delta_height:""},template:{desc:"Ubaci sadr\u017eaj iz \u0161ablona"},visualchars:{desc:"Vizuelni kontrolni znakovi uklju\u010deni/isklju\u010deni."},spellchecker:{desc:"Uklju\u010di/isklju\u010di proveru pravopisa",menu:"Postavke provere pravopisa",ignore_word:"Zanemari re\u010d",ignore_words:"Zanemari sve",langs:"Jezici",wait:"Sa\u010dekajte...",sug:"Predlozi",no_sug:"Nema predloga",no_mpell:"Nije prona\u0111ena nijedna pravopisna gre\u0161ka."},pagebreak:{desc:"Ubaci prelom."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/th.js0000644000175000017500000002665511526350525031536 0ustar frankiefrankietinyMCE.addI18n({th:{common:{more_colors:"\u0e2a\u0e35\u0e2d\u0e37\u0e48\u0e19\u0e46",invalid_data:"\u0e02\u0e49\u0e2d\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14: \u0e1b\u0e49\u0e2d\u0e19\u0e04\u0e48\u0e32\u0e43\u0e19\u0e0a\u0e49\u0e2d\u0e07\u0e2a\u0e35\u0e41\u0e14\u0e07\u0e43\u0e2b\u0e49\u0e16\u0e39\u0e01\u0e15\u0e49\u0e2d\u0e07",popup_blocked:"\u0e02\u0e2d\u0e2d\u0e20\u0e31\u0e22\u0e41\u0e15\u0e48\u0e40\u0e23\u0e32\u0e1e\u0e1a\u0e27\u0e48\u0e32\u0e04\u0e38\u0e13\u0e21\u0e35\u0e23\u0e30\u0e1a\u0e1a\u0e1b\u0e49\u0e2d\u0e07\u0e01\u0e31\u0e19\u0e1b\u0e4a\u0e2d\u0e1b\u0e2d\u0e31\u0e1b \u0e04\u0e38\u0e13\u0e08\u0e30\u0e15\u0e49\u0e2d\u0e07\u0e1b\u0e34\u0e14\u0e01\u0e32\u0e23\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19\u0e01\u0e32\u0e23\u0e1a\u0e25\u0e47\u0e2d\u0e04\u0e1b\u0e4a\u0e2d\u0e1b\u0e2d\u0e31\u0e1b",clipboard_no_support:"\u0e02\u0e13\u0e30\u0e19\u0e35\u0e49\u0e22\u0e31\u0e07\u0e44\u0e21\u0e48\u0e2a\u0e19\u0e31\u0e1a\u0e2a\u0e19\u0e38\u0e19\u0e40\u0e1a\u0e23\u0e32\u0e40\u0e0b\u0e2d\u0e23\u0e4c\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13 \u0e43\u0e2b\u0e49\u0e43\u0e0a\u0e49\u0e41\u0e1b\u0e49\u0e19\u0e1e\u0e34\u0e21\u0e1e\u0e4c\u0e25\u0e31\u0e14\u0e41\u0e17\u0e19",clipboard_msg:"\u0e04\u0e31\u0e14\u0e25\u0e2d\u0e01 / \u0e15\u0e31\u0e14 / \u0e27\u0e32\u0e07\u0e22\u0e31\u0e07\u0e44\u0e21\u0e48\u0e21\u0e35\u0e43\u0e2b\u0e49\u0e1a\u0e23\u0e34\u0e01\u0e32\u0e23\u0e43\u0e19 Mozilla \u0e41\u0e25\u0e30 Firefox.\\nDo \u0e04\u0e38\u0e13\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e40\u0e15\u0e34\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e1b\u0e31\u0e0d\u0e2b\u0e32\u0e19\u0e35\u0e49\u0e2b\u0e23\u0e37\u0e2d\u0e44\u0e21\u0e48?",not_set:"-- \u0e44\u0e21\u0e48\u0e44\u0e14\u0e49\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32 --",class_name:"css \u0e04\u0e25\u0e32\u0e2a",browse:"\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e44\u0e1f\u0e25\u0e4c",close:"\u0e1b\u0e34\u0e14",cancel:"\u0e22\u0e01\u0e40\u0e25\u0e34\u0e01",update:"\u0e2d\u0e31\u0e1e\u0e40\u0e14\u0e15",insert:"\u0e40\u0e1e\u0e34\u0e48\u0e21",apply:"\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19",edit_confirm:"\u0e04\u0e38\u0e13\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u0e43\u0e0a\u0e49\u0e42\u0e2b\u0e21\u0e14 WYSIWYG \u0e43\u0e19\u0e01\u0e32\u0e23\u0e40\u0e02\u0e35\u0e22\u0e19\u0e1a\u0e17\u0e04\u0e27\u0e32\u0e21\u0e2b\u0e23\u0e37\u0e2d\u0e44\u0e21\u0e48 ?"},contextmenu:{full:"\u0e40\u0e15\u0e47\u0e21",right:"\u0e02\u0e27\u0e32",center:"\u0e01\u0e25\u0e32\u0e07",left:"\u0e0b\u0e49\u0e32\u0e22",align:"\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e08\u0e31\u0e14\u0e27\u0e32\u0e07"},insertdatetime:{day_short:"\u0e2d\u0e32,\u0e08,\u0e2d\u0e31\u0e07,\u0e1e,\u0e1e\u0e24,\u0e28,\u0e2a,\u0e2d",day_long:"\u0e27\u0e31\u0e19\u0e2d\u0e32\u0e17\u0e34\u0e15\u0e22\u0e4c,\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c,\u0e27\u0e31\u0e19\u0e2d\u0e31\u0e07\u0e04\u0e32\u0e23,\u0e27\u0e31\u0e19\u0e1e\u0e38\u0e18,\u0e27\u0e31\u0e19\u0e1e\u0e24\u0e2b\u0e31\u0e2a\u0e1a\u0e14\u0e35,\u0e27\u0e31\u0e19\u0e28\u0e38\u0e01\u0e23\u0e4c,\u0e27\u0e31\u0e19\u0e40\u0e2a\u0e32\u0e23\u0e4c,\u0e2d\u0e32\u0e17\u0e34\u0e15\u0e22\u0e4c",months_short:"\u0e21.\u0e04.,\u0e01.\u0e1e.,\u0e21\u0e35.\u0e04.,\u0e40\u0e21.\u0e22.,\u0e1e.\u0e04.,\u0e21\u0e34.\u0e22.,\u0e01.\u0e04.,\u0e2a.\u0e04.,\u0e01.\u0e22.,\u0e15.\u0e04.,\u0e1e.\u0e22.,\u0e18.\u0e04.",months_long:"\u0e21\u0e01\u0e23\u0e32\u0e04\u0e21,\u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c,\u0e21\u0e35\u0e19\u0e32\u0e04\u0e21,\u0e40\u0e21\u0e29\u0e32\u0e22\u0e19,\u0e1e\u0e24\u0e29\u0e20\u0e32\u0e04\u0e21,\u0e21\u0e34\u0e16\u0e38\u0e19\u0e32\u0e22\u0e19,\u0e01\u0e23\u0e01\u0e0e\u0e32\u0e04\u0e21,\u0e2a\u0e34\u0e07\u0e2b\u0e32\u0e04\u0e21,\u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19,\u0e15\u0e38\u0e25\u0e32\u0e04\u0e21,\u0e1e\u0e24\u0e28\u0e08\u0e34\u0e01\u0e32\u0e22\u0e19,\u0e18\u0e31\u0e19\u0e27\u0e32\u0e04\u0e21",inserttime_desc:"\u0e41\u0e17\u0e23\u0e01\u0e40\u0e27\u0e25\u0e32",insertdate_desc:"\u0e41\u0e17\u0e23\u0e01\u0e27\u0e31\u0e19\u0e17\u0e35\u0e48",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u0e1e\u0e34\u0e21\u0e1e\u0e4c"},preview:{preview_desc:"\u0e14\u0e39\u0e15\u0e31\u0e27\u0e2d\u0e22\u0e48\u0e32\u0e07"},directionality:{rtl_desc:"\u0e2d\u0e48\u0e32\u0e19\u0e08\u0e32\u0e01\u0e02\u0e27\u0e32\u0e44\u0e1b\u0e0b\u0e49\u0e32\u0e22",ltr_desc:"\u0e2d\u0e48\u0e32\u0e19\u0e08\u0e32\u0e01\u0e0b\u0e49\u0e32\u0e22\u0e44\u0e1b\u0e02\u0e27\u0e32"},layer:{content:"\u0e40\u0e25\u0e40\u0e22\u0e2d\u0e23\u0e4c\u0e43\u0e2b\u0e21\u0e48...",absolute_desc:"\u0e2a\u0e25\u0e31\u0e1a\u0e01\u0e32\u0e23\u0e27\u0e32\u0e07",backward_desc:"\u0e22\u0e49\u0e32\u0e22\u0e44\u0e1b\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e25\u0e31\u0e07",forward_desc:"\u0e22\u0e49\u0e32\u0e22\u0e44\u0e1b\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e19\u0e49\u0e32",insertlayer_desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e40\u0e25\u0e40\u0e22\u0e2d\u0e23\u0e4c\u0e43\u0e2b\u0e21\u0e48"},save:{save_desc:"\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01",cancel_desc:"\u0e22\u0e01\u0e40\u0e25\u0e34\u0e01\u0e17\u0e38\u0e01\u0e2d\u0e22\u0e48\u0e32\u0e07"},nonbreaking:{nonbreaking_desc:"\u0e41\u0e17\u0e23\u0e01\u0e2d\u0e31\u0e01\u0e02\u0e23\u0e30\u0e27\u0e48\u0e32\u0e07"},iespell:{download:"\u0e2b\u0e32\u0e01\u0e23\u0e30\u0e1a\u0e1a\u0e15\u0e23\u0e27\u0e08\u0e2a\u0e2d\u0e1a\u0e04\u0e33\u0e1c\u0e34\u0e14\u0e44\u0e21\u0e48\u0e1e\u0e1a \u0e04\u0e38\u0e13\u0e15\u0e49\u0e2d\u0e07\u0e01\u0e32\u0e23\u0e15\u0e34\u0e14\u0e15\u0e31\u0e49\u0e07\u0e40\u0e14\u0e35\u0e4b\u0e22\u0e27\u0e19\u0e35\u0e49 ?",iespell_desc:"\u0e40\u0e23\u0e35\u0e22\u0e01\u0e43\u0e0a\u0e49\u0e15\u0e23\u0e27\u0e08\u0e01\u0e32\u0e23\u0e2a\u0e30\u0e01\u0e14"},advhr:{advhr_desc:"\u0e40\u0e2a\u0e49\u0e19\u0e1a\u0e23\u0e23\u0e17\u0e31\u0e14",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0e44\u0e2d\u0e04\u0e2d\u0e19\u0e41\u0e2a\u0e14\u0e07\u0e2d\u0e32\u0e23\u0e21\u0e13\u0e4c",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0e04\u0e49\u0e19\u0e2b\u0e32/\u0e41\u0e17\u0e19\u0e17\u0e35\u0e48",search_desc:"\u0e04\u0e49\u0e19\u0e2b\u0e32",delta_width:"",delta_height:""},advimage:{image_desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21/\u0e41\u0e01\u0e49\u0e44\u0e02 \u0e23\u0e39\u0e1b",delta_width:"",delta_height:""},advlink:{link_desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21/\u0e41\u0e01\u0e49\u0e44\u0e02 \u0e25\u0e34\u0e49\u0e07\u0e04\u0e4c",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21/\u0e41\u0e01\u0e49\u0e44\u0e02 \u0e41\u0e2d\u0e17\u0e17\u0e23\u0e34\u0e1a\u0e34\u0e27",ins_desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21",del_desc:"\u0e25\u0e1a",acronym_desc:"\u0e2d\u0e31\u0e01\u0e29\u0e23\u0e22\u0e48\u0e2d",abbr_desc:"\u0e15\u0e31\u0e27\u0e22\u0e48\u0e2d",cite_desc:"\u0e01\u0e32\u0e23\u0e2d\u0e49\u0e32\u0e07\u0e2d\u0e34\u0e07",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u0e41\u0e01\u0e49\u0e44\u0e02 CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14",paste_word_desc:"\u0e27\u0e32\u0e07\u0e08\u0e32\u0e01\u0e42\u0e1b\u0e23\u0e41\u0e01\u0e23\u0e21 Word",paste_text_desc:"\u0e27\u0e32\u0e07\u0e42\u0e14\u0e22\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e18\u0e23\u0e23\u0e21\u0e14\u0e32"},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"\u0e40\u0e0b\u0e25\u0e25\u0e4c",col:"\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c",row:"\u0e41\u0e16\u0e27",del:"\u0e25\u0e1a\u0e15\u0e32\u0e23\u0e32\u0e07",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"\u0e25\u0e1a\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c",col_after_desc:"\u0e41\u0e17\u0e23\u0e01\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c\u0e08\u0e32\u0e01\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e25\u0e31\u0e07",col_before_desc:"\u0e41\u0e17\u0e23\u0e01\u0e04\u0e2d\u0e25\u0e31\u0e21\u0e19\u0e4c\u0e08\u0e32\u0e01\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e19\u0e49\u0e32",delete_row_desc:"\u0e25\u0e1a\u0e41\u0e16\u0e27",row_after_desc:"\u0e41\u0e17\u0e23\u0e01\u0e41\u0e16\u0e27\u0e08\u0e32\u0e01\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e25\u0e31\u0e07",row_before_desc:"\u0e41\u0e17\u0e23\u0e01\u0e41\u0e16\u0e27\u0e08\u0e32\u0e01\u0e02\u0e49\u0e32\u0e07\u0e2b\u0e19\u0e49\u0e32",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"\u0e01\u0e32\u0e23\u0e40\u0e1b\u0e25\u0e35\u0e48\u0e22\u0e19\u0e41\u0e1b\u0e25\u0e07\u0e17\u0e35\u0e48\u0e04\u0e38\u0e13\u0e17\u0e33\u0e08\u0e30\u0e2b\u0e32\u0e22\u0e44\u0e1b\u0e2b\u0e32\u0e01\u0e04\u0e38\u0e13\u0e2d\u0e2d\u0e01\u0e08\u0e32\u0e01\u0e2b\u0e19\u0e49\u0e32\u0e19\u0e35\u0e49"},fullscreen:{desc:"\u0e2a\u0e25\u0e31\u0e1a\u0e44\u0e1b\u0e41\u0e2a\u0e14\u0e07\u0e41\u0e1a\u0e1a\u0e40\u0e15\u0e47\u0e21\u0e2b\u0e19\u0e49\u0e32"},media:{edit:"\u0e41\u0e01\u0e49\u0e44\u0e02\u0e21\u0e35\u0e40\u0e14\u0e35\u0e22",desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21 / \u0e41\u0e01\u0e49\u0e44\u0e02 \u0e21\u0e35\u0e40\u0e14\u0e35\u0e22",delta_height:"",delta_width:""},fullpage:{desc:"\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23",delta_width:"",delta_height:""},template:{desc:"\u0e40\u0e1e\u0e34\u0e48\u0e21\u0e41\u0e21\u0e48\u0e41\u0e1a\u0e1a\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23"},visualchars:{desc:"\u0e01\u0e32\u0e23\u0e04\u0e27\u0e1a\u0e04\u0e38\u0e21\u0e15\u0e31\u0e27\u0e2d\u0e31\u0e01\u0e29\u0e23 \u0e40\u0e1b\u0e34\u0e14/\u0e1b\u0e34\u0e14"},spellchecker:{desc:"\u0e1b\u0e34\u0e14\u0e01\u0e32\u0e23\u0e2a\u0e30\u0e01\u0e14\u0e04\u0e33",menu:"\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e01\u0e32\u0e23\u0e2a\u0e30\u0e01\u0e14\u0e04\u0e33",ignore_word:"\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19\u0e1a\u0e32\u0e07\u0e04\u0e33",ignore_words:"\u0e25\u0e30\u0e40\u0e27\u0e49\u0e19\u0e17\u0e31\u0e49\u0e07\u0e2b\u0e21\u0e14",langs:"\u0e20\u0e32\u0e29\u0e32",wait:"\u0e42\u0e1b\u0e23\u0e14\u0e23\u0e2d...",sug:"\u0e04\u0e33\u0e41\u0e19\u0e30\u0e19\u0e33",no_sug:"\u0e44\u0e21\u0e48\u0e21\u0e35\u0e04\u0e33\u0e41\u0e19\u0e30\u0e19\u0e33",no_mpell:"\u0e44\u0e21\u0e48\u0e1e\u0e1a\u0e23\u0e30\u0e1a\u0e1a\u0e2a\u0e30\u0e01\u0e14\u0e04\u0e33\u0e1c\u0e34\u0e14"},pagebreak:{desc:"\u0e43\u0e2a\u0e48\u0e40\u0e2a\u0e49\u0e19\u0e41\u0e1a\u0e48\u0e07\u0e2b\u0e19\u0e49\u0e32"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/sv.js0000644000175000017500000001270711526350525031544 0ustar frankiefrankietinyMCE.addI18n({sv:{common:{more_colors:"Fler f\u00e4rger",invalid_data:"Fel: Inkorrekta v\u00e4rden har matats in, dessa \u00e4r markerade i r\u00f6tt.",popup_blocked:"Popup blockerare detekterad. St\u00e4ng av den s\u00e5 att dialogerna kan \u00f6ppnas.",clipboard_no_support:"Funktionen \u00e4r inte tillg\u00e4nglig i din webbl\u00e4sare, anv\u00e4nd tangentbordsgenv\u00e4garna i st\u00e4llet.",clipboard_msg:"Kopiera/klipp ut/klistra in \u00e4r inte tillg\u00e4ngligt i din webbl\u00e4sare.\\nVill du veta mer?",not_set:"-- Inte satt --",class_name:"Klass",browse:"Bl\u00e4ddra",close:"St\u00e4ng",cancel:"Avbryt",update:"Uppdatera",insert:"Infoga",apply:"Applicera",edit_confirm:"Vill du anv\u00e4nda WYSIWYG f\u00f6r denna textarea?"},contextmenu:{full:"Utfyllnad",right:"H\u00f6ger",center:"Centrerad",left:"V\u00e4nster",align:"Justering"},insertdatetime:{day_short:"S\u00f6n,M\u00e5n,Tis,Ons,Tors,Fre,L\u00f6r,S\u00f6n",day_long:"S\u00f6ndag,M\u00e5ndag,Tisdag,Onsdag,Torsdag,Fredag,L\u00f6rdag,S\u00f6ndag",months_short:"Jan,Feb,Mar,Apr,Maj,Jun,Jul,Aug,Sep,Okt,Nov,Dec",months_long:"Januari,Februari,Mars,April,Maj,Juni,Juli,Augusti,September,Oktober,November,December",inserttime_desc:"Infoga tid",insertdate_desc:"Infoga datum",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d "},print:{print_desc:"Skriv ut"},preview:{preview_desc:"F\u00f6rhandsgranska"},directionality:{rtl_desc:"Skriftl\u00e4ge - h\u00f6ger till v\u00e4nster",ltr_desc:"Skriftl\u00e4ge - v\u00e4nster till h\u00f6ger"},layer:{content:"Nytt lager...",absolute_desc:"Sl\u00e5 av/p\u00e5 absolut positionering",backward_desc:"Flytta bak\u00e5t",forward_desc:"Flytta fram\u00e5t",insertlayer_desc:"Infoga nytt lager"},save:{save_desc:"Spara",cancel_desc:"Hoppa \u00f6ver alla f\u00f6r\u00e4ndringar"},nonbreaking:{nonbreaking_desc:"Infoga icke radbrytande mellanslag"},iespell:{download:"ieSpell kunde inte hittas, vill du installera denna nu?",iespell_desc:"R\u00e4ttstava"},advhr:{advhr_desc:"Horisontell skiljelinje",delta_height:"",delta_width:""},emotions:{emotions_desc:"Smileys",delta_height:"",delta_width:""},searchreplace:{replace_desc:"S\u00f6k/ers\u00e4tt",search_desc:"S\u00f6k",delta_width:"",delta_height:""},advimage:{image_desc:"Infoga/redigera bild",delta_width:"",delta_height:""},advlink:{link_desc:"Infoga/redigera l\u00e4nk",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Redigera attribut",ins_desc:"Markera som tillagt",del_desc:"Markera som struket",acronym_desc:"Akronym",abbr_desc:"F\u00f6rkortning",cite_desc:"citat",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Redigera inline CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Inklistring \u00e4r nu i textl\u00e4ge.",plaintext_mode_sticky:"Inklistring \u00e4r nu i textl\u00e4ge. Efter att du klistrat in kommer den att \u00e5terg\u00e5 till normall\u00e4ge.",selectall_desc:"Markera allt",paste_word_desc:"Klistra in fr\u00e5n Word",paste_text_desc:"Klistra in som text"},paste_dlg:{word_title:"Anv\u00e4nd ctrl-v p\u00e5 ditt tangentbord f\u00f6r att klistra in i detta f\u00f6nster.",text_linebreaks:"Spara radbrytningar",text_title:"Anv\u00e4nd ctrl-v p\u00e5 ditt tangentbord f\u00f6r att klistra in i detta f\u00f6nster."},table:{cell:"Cell",col:"Kolumn",row:"Rad",del:"Radera tabell",copy_row_desc:"Klistra in rad",cut_row_desc:"Klipp ut rad",paste_row_after_desc:"Klistra in rad efter",paste_row_before_desc:"Klistra in rad ovanf\u00f6r",props_desc:"Tabellinst\u00e4llningar",cell_desc:"Tabellcellsinst\u00e4llningar",row_desc:"Tabellradsinst\u00e4llningar",merge_cells_desc:"Sammanfoga celler",split_cells_desc:"Separera sammansatta celler",delete_col_desc:"Radera kolumn",col_after_desc:"Infoga kolumn efter",col_before_desc:"Infoga kolumn f\u00f6re",delete_row_desc:"Radera rad",row_after_desc:"Infoga ny rad efter",row_before_desc:"Infoga ny rad f\u00f6re",desc:"Infoga/redigera ny tabell",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"Om du \u00e5terskapar inneh\u00e5ll s\u00e5 kommer det nuvarande inneh\u00e5llet i f\u00e4ltet att raderas.\\n\\n\u00c4r du s\u00e4ker p\u00e5 att du vill g\u00f6ra detta?",restore_content:"\u00c5terskapa automatiskt sparat inneh\u00e5ll.",unload_msg:"De f\u00f6r\u00e4ndringar som du gjort kommer att g\u00e5 f\u00f6rlorade om du l\u00e4mnar sidan."},fullscreen:{desc:"Sl\u00e5 av/p\u00e5 fullsk\u00e4rmsl\u00e4ge"},media:{edit:"Redigera inb\u00e4ddad media",desc:"Infoga/redigera inb\u00e4ddad media",delta_height:"",delta_width:""},fullpage:{desc:"Dokumentinst\u00e4llningar",delta_width:"",delta_height:""},template:{desc:"Infoga en f\u00e4rdig mall"},visualchars:{desc:"Visa osynliga tecken"},spellchecker:{desc:"Sl\u00e5 av/p\u00e5 r\u00e4ttstavningskontroll",menu:"R\u00e4ttstavningsinst\u00e4llningar",ignore_word:"Ignorera ord",ignore_words:"Ignorera alla",langs:"Spr\u00e5k",wait:"Var god v\u00e4nta...",sug:"F\u00f6rslag",no_sug:"Inga f\u00f6rslag",no_mpell:"Inga felstavningar funna."},pagebreak:{desc:"Infoga sidbrytning"},advlist:{types:"Typer",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Cirkel",disc:"Disc",square:"Fyrkant"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/tn.js0000644000175000017500000001207411526350525031532 0ustar frankiefrankietinyMCE.addI18n({tn:{common:{more_colors:"Mebala e mentsi",invalid_data:"Phoso: Gase-gone mo go tsentsweng, mo go tswailwe ka botshibidu.",popup_blocked:"Maitswarelo,mme re lemogile gore popup-blocker e tila gore window e fang pereko ya porokereme. O tla thoka go tila sekganedi sa popup mo saeteng gore o kgone go sologela-mosola thuloso e",clipboard_no_support:"Ga e letelelwe ke boraosara jwa gago gompieno, dirisa dikhutswe tsa kiboto.",clipboard_msg:"Kopa/Sega/Kgomaretsa ga e yo mo Mozila Firefox.\\nA o batla molaetsa ka lebaka le?",not_set:"-- Ga ya Baakangwa --",class_name:"Tlase",browse:"Boraose",close:"Tswala",cancel:"Khansela",update:"Tokafatsa",insert:"Tsenya",apply:"Apolaya",edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text"},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content.",unload_msg:"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/tr.js0000644000175000017500000001470411526350525031540 0ustar frankiefrankietinyMCE.addI18n({tr:{common:{more_colors:"Daha fazla renk",invalid_data:"Hata: Ge\u00e7ersiz de\u011fer girildi, bunlar k\u0131rm\u0131z\u0131yla i\u015faretlenmi\u015ftir.",popup_blocked:"\u00dczg\u00fcn\u00fcz, a\u00e7\u0131l\u0131r pencere engelleyiciniz uygulama i\u00e7in gerekli bir pencereyi engelledi. Bu arac\u0131 tam olarak kullanabilmek i\u00e7in a\u00e7\u0131l\u0131r pencere engelleyicisini kapat\u0131n\u0131z.",clipboard_no_support:"\u015eu an kulland\u0131\u011f\u0131n\u0131z taray\u0131c\u0131n\u0131z klavye k\u0131sayollar\u0131n\u0131 desteklememektedir.",clipboard_msg:"Mozilla Firefox da Kes/Kopyala/Yap\u0131\u015ft\u0131r \u00f6zelli\u011fi kullan\u0131lmamaktad\u0131r. \\nBu konu hakk\u0131nda bilgi almak ister misiniz?",not_set:"-- Ayarlanmad\u0131 --",class_name:"S\u0131n\u0131f",browse:"G\u00f6zat",close:"Kapat",cancel:"\u0130ptal",update:"G\u00fcncelle",insert:"Ekle",apply:"Uygula",edit_confirm:"Metin giri\u015fi i\u00e7in WYSIWYG modunu kullanmak ister misiniz?"},contextmenu:{full:"Tam",right:"Sa\u011f",center:"Orta",left:"Sol",align:"Hizalama"},insertdatetime:{day_short:"Paz,Pzt,Sal,\u00c7r\u015f,Per,Cum,Cts",day_long:"Pazar,Pazartesi,Sal\u0131,\u00c7ar\u015famba,Per\u015fembe,Cuma,Cumartesi",months_short:"Oca,\u015eub,Mar,Nis,May,Haz,Tem,A\u011fu,Eyl,Eki,Kas,Ara",months_long:"Ocak,\u015eubat,Mart,Nisan,May\u0131s,Haziran,Temmuz,A\u011fustos,Eyl\u00fcl,Ekim,Kas\u0131m,Aral\u0131k",inserttime_desc:"Saat ekle",insertdate_desc:"Tarih ekle",time_fmt:"%H:%M:%S",date_fmt:"%d-%m-%Y"},print:{print_desc:"Yazd\u0131r"},preview:{preview_desc:"\u00d6nizleme"},directionality:{rtl_desc:"Soldan sa\u011fa y\u00f6nlendir",ltr_desc:"Sa\u011fdan sola y\u00f6nlendir"},layer:{content:"Yeni katman...",absolute_desc:"Mutlaka konumu de\u011fi\u015ftir",backward_desc:"Arkaya al",forward_desc:"\u00d6ne getir",insertlayer_desc:"Yeni katman ekle"},save:{save_desc:"Kaydet",cancel_desc:"T\u00fcm de\u011fi\u015fiklikleri iptal et"},nonbreaking:{nonbreaking_desc:"B\u00f6l\u00fcnemez bo\u015fluk karakteri ekle"},iespell:{download:"ieSpell bulunamad\u0131. \u015eimdi kurmak ister misiniz?",iespell_desc:"\u0130mla kontrol\u00fcn\u00fc ba\u015flat"},advhr:{advhr_desc:"Yatay \u00e7izgi",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0130fadeler",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Bul/De\u011fi\u015ftir",search_desc:"Bul",delta_width:"",delta_height:""},advimage:{image_desc:"Resim ekle/d\u00fczenle",delta_width:"",delta_height:""},advlink:{link_desc:"Ba\u011flant\u0131 ekle/d\u00fczenle",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Nitelik ekle/d\u00fczenle",ins_desc:"Ekleme",del_desc:"Silme",acronym_desc:"K\u0131sa ad",abbr_desc:"K\u0131saltma",cite_desc:"Al\u0131nt\u0131",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"CSS Stilini D\u00fczenle",delta_height:"",delta_width:""},paste:{plaintext_mode:"D\u00fcz metin modunda yap\u0131\u015ft\u0131r. Normal yap\u0131\u015ft\u0131rma moduna ge\u00e7mek i\u00e7in tekrar t\u0131klay\u0131n.",plaintext_mode_sticky:"D\u00fcz metin modunda yap\u0131\u015ft\u0131r. Normal yap\u0131\u015ft\u0131rma moduna ge\u00e7mek i\u00e7in tekrar t\u0131klay\u0131n. Yap\u0131\u015ft\u0131rma i\u015fleminden sonra normal yap\u0131\u015ft\u0131rma moduna ge\u00e7ilecektir.",selectall_desc:"T\u00fcm\u00fcn\u00fc se\u00e7",paste_word_desc:"Word\'den yap\u0131\u015ft\u0131r",paste_text_desc:"D\u00fcz metin olarak yap\u0131\u015ft\u0131r"},paste_dlg:{word_title:"Pencereye metin yap\u0131\u015ft\u0131rmak i\u00e7in klavyeden CTRL+V i kullan\u0131n.",text_linebreaks:"Sat\u0131r kesmelerini tut",text_title:"Pencereye metin yap\u0131\u015ft\u0131rmak i\u00e7in klavyeden CTRL+V i kullan\u0131n."},table:{cell:"H\u00fccre",col:"S\u00fctun",row:"Sat\u0131r",del:"Tablo sil",copy_row_desc:"Tablo sat\u0131r\u0131n\u0131 kopyala",cut_row_desc:"Tablo sat\u0131r\u0131n\u0131 kes",paste_row_after_desc:"Alt\u0131na tablo sat\u0131r\u0131 yap\u0131\u015ft\u0131r",paste_row_before_desc:"\u00dcst\u00fcne tablo sat\u0131r\u0131 yap\u0131\u015ft\u0131r",props_desc:"Tablo \u00f6zellikleri",cell_desc:"Tablo h\u00fccre \u00f6zellikleri",row_desc:"Tablo sat\u0131r \u00f6zellikleri",merge_cells_desc:"Tablo h\u00fccrelerini birle\u015ftir",split_cells_desc:"Birle\u015ftirilmi\u015f tablo h\u00fccrelerini b\u00f6l",delete_col_desc:"S\u00fctun sil",col_after_desc:"Sa\u011f\u0131na s\u00fctun ekle",col_before_desc:"Soluna s\u00fctun ekle",delete_row_desc:"Sat\u0131r sil",row_after_desc:"Alt\u0131na sat\u0131r ekle",row_before_desc:"\u00dcst\u00fcne sat\u0131r ekle",desc:"Yeni tablo ekle",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"E\u011fer geri y\u00fckleme i\u00e7eri\u011fe otomatik kay\u0131t edilirse, edit\u00f6rde varolan t\u00fcm i\u00e7eri\u011fi kaybedebilirsiniz.\\n\\nGeri y\u00fcklemenin i\u00e7eri\u011fe kaydedilmesini istedi\u011finizden emin misiniz?",restore_content:"Geri y\u00fckleme i\u00e7eri\u011fe otomatik kaydedildi.",unload_msg:"Bu sayfadan \u00e7\u0131karsan\u0131z yapt\u0131\u011f\u0131n\u0131z de\u011fi\u015fiklikler kaybolabilir."},fullscreen:{desc:"Tam ekran modunu a\u00e7/kapat"},media:{edit:"T\u00fcmle\u015fik medya d\u00fczenle",desc:"T\u00fcmle\u015fik medya ekle / d\u00fczenle",delta_height:"",delta_width:""},fullpage:{desc:"Belge \u00f6zellikleri",delta_width:"",delta_height:""},template:{desc:"\u00d6ntan\u0131ml\u0131 i\u00e7erik \u015fablonu kullan"},visualchars:{desc:"G\u00f6rsel karakter kontrol\u00fc a\u00e7\u0131k/kapal\u0131."},spellchecker:{desc:"\u0130mla kontrol\u00fcn\u00fc a\u00e7/kapat",menu:"\u0130mla kontrol\u00fc ayarlar\u0131",ignore_word:"S\u00f6zc\u00fc\u011f\u00fc yoksay",ignore_words:"T\u00fcm\u00fcn\u00fc yoksay",langs:"Diller",wait:"L\u00fctfen bekleyin...",sug:"\u00d6neriler",no_sug:"\u00d6neri yok",no_mpell:"\u0130mla hatas\u0131 bulunamad\u0131."},pagebreak:{desc:"Sayfa sonu ekle."},advlist:{types:"Tipler",def:"Varsay\u0131lan",lower_alpha:"K\u00fc\u00e7\u00fck harf alfa",lower_greek:"K\u00fc\u00e7\u00fck harf grek",lower_roman:"K\u00fc\u00e7\u00fck harf roman",upper_alpha:"B\u00fcy\u00fck harf alfa",upper_roman:"B\u00fcy\u00fck harf roman",circle:"\u00c7ember",disc:"Daire",square:"Kare"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/tt.js0000644000175000017500000001522211526350525031536 0ustar frankiefrankietinyMCE.addI18n({tt:{common:{more_colors:"\u66f4\u591a\u9854\u8272",invalid_data:"\u932f\u8aa4\uff1a\u8f38\u5165\u4e86\u7121\u6548\u7684\u503c\uff0c\u5df2\u6a19\u8a18\u7232\u7d05\u8272\u3002",popup_blocked:"\u5c0d\u4e0d\u8d77\uff0c\u60a8\u7684\u5feb\u986f\u8996\u7a97\u963b\u6b62\u7a0b\u5f0f\u5df2\u7d93\u963b\u6b62\u4e86\u672c\u5feb\u986f\u8996\u7a97\uff0c\u8acb\u8abf\u6574\u4f60\u7684\u700f\u89bd\u5668\u8a2d\u5b9a\uff0c\u5141\u8a31\u672c\u7db2\u7ad9\u5f48\u51fa\u65b0\u7a97\u53e3\uff0c\u4ee5\u4fbf\u4f7f\u7528\u6b64\u529f\u80fd",clipboard_no_support:"\u5c1a\u4e0d\u652f\u63f4\u60a8\u6240\u4f7f\u7528\u7684\u700f\u89bd\u5668\uff0c\u8acb\u4f7f\u7528\u9375\u76e4\u65b9\u5f0f\u64cd\u4f5c",clipboard_msg:"\u8907\u88fd\u3001\u526a\u4e0b\u548c\u8cbc\u4e0a\u529f\u80fd\u5728Mozilla \u548c Firefox\u4e2d\u7121\u6cd5\u4f7f\u7528",not_set:"-- \u672a\u8a2d\u5b9a --",class_name:"\u6a23\u5f0f\u985e\u540d",browse:"\u700f\u89bd",close:"\u95dc\u9589",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u61c9\u7528",edit_confirm:"\u662f\u5426\u5728\u8a72text area\u5167\u5553\u7528\u6240\u898b\u5373\u6240\u5f97\u6a21\u5f0f\uff1f"},contextmenu:{full:"\u5169\u7aef\u5c0d\u9f4a",right:"\u9760\u53f3\u5c0d\u9f4a",center:"\u7f6e\u4e2d",left:"\u9760\u5de6\u5c0d\u9f4a",align:"\u5c0d\u9f4a\u65b9\u5f0f"},insertdatetime:{day_short:"\u9031\u65e5,\u9031\u4e00,\u9031\u4e8c,\u9031\u4e09,\u9031\u56db,\u9031\u4e94,\u9031\u516d,\u9031\u65e5",day_long:"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u4e09,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5",months_short:"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708",months_long:"\u4e00\u6708,\u4e8c\u6708,\u4e09\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u73fe\u5728\u6642\u9593",insertdate_desc:"\u63d2\u5165\u4eca\u5929\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u5217\u5370"},preview:{preview_desc:"\u9810\u89bd"},directionality:{rtl_desc:"\u6587\u5b57\u5f9e\u53f3\u5230\u5de6",ltr_desc:"\u6587\u5b57\u5f9e\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u589e\u5c64...",absolute_desc:"\u7d55\u5c0d\u4f4d\u7f6e",backward_desc:"\u5f8c\u7f6e",forward_desc:"\u524d\u7f6e",insertlayer_desc:"\u63d2\u5165\u5c64"},save:{save_desc:"\u5b58\u6a94",cancel_desc:"\u653e\u68c4\u6240\u6709\u66f4\u6539"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u767d\u5b57\u5143"},iespell:{download:"\u672a\u6aa2\u6e2c\u5230ieSpell\u5143\u4ef6\uff0c\u662f\u5426\u73fe\u5728\u5b89\u88dd ?",iespell_desc:"\u57f7\u884c\u62fc\u5b57\u6aa2\u67e5"},advhr:{advhr_desc:"\u5206\u9694\u7dda",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u8868\u60c5",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u641c\u5c0b/\u53d6\u4ee3",search_desc:"\u641c\u5c0b",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7de8\u8f2f \u5716\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7de8\u8f2f \u9023\u7d50",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"\u63d2\u5165/\u7de8\u8f2f \u5c6c\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u522a\u9664",acronym_desc:"\u9996\u5b57\u6bcd\u7e2e\u5beb",abbr_desc:"\u7e2e\u5beb",cite_desc:"\u5f15\u7528",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7de8\u8f2f CSS \u6a23\u5f0f\u8868",delta_height:"",delta_width:""},paste:{selectall_desc:"\u5168\u9078",paste_word_desc:"\u8cbc\u4e0a\u7232Word\u683c\u5f0f",paste_text_desc:"\u8cbc\u4e0a\u7232\u7d14\u6587\u5b57",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u5c07\u8907\u88fd(CTRL + C)\u7684\u5167\u5bb9\u8cbc\u4e0a(CTRL + V)\u5230\u8996\u7a97\u3002",text_linebreaks:"\u4fdd\u7559\u5206\u884c\u7b26\u865f\u865f",text_title:"\u5c07\u8907\u88fd(CTRL + C)\u7684\u5167\u5bb9\u8cbc\u4e0a(CTRL + V)\u5230\u8996\u7a97\u3002"},table:{cell:"\u5132\u5b58\u683c",col:"\u5217",row:"\u884c",del:"\u522a\u9664\u8868\u683c",copy_row_desc:"\u8907\u88fd\u7576\u524d\u5217",cut_row_desc:"\u526a\u4e0b\u7576\u524d\u5217",paste_row_after_desc:"\u8cbc\u4e0a\u884c\u5230\u4e0b\u65b9",paste_row_before_desc:"\u8cbc\u4e0a\u884c\u5230\u4e0a\u65b9",props_desc:"\u8868\u683c \u5c6c\u6027",cell_desc:"\u5132\u5b58\u683c \u5c6c\u6027",row_desc:"\u5217 \u5c6c\u6027",merge_cells_desc:"\u5408\u4f75\u5132\u5b58\u683c",split_cells_desc:"\u62c6\u5206\u5132\u5b58\u683c",delete_col_desc:"\u522a\u9664\u7576\u524d\u5217",col_after_desc:"\u5728\u53f3\u5074\u63d2\u5165\u5217",col_before_desc:"\u5728\u5de6\u5074\u63d2\u5165\u5217",delete_row_desc:"\u522a\u9664\u7576\u524d\u884c",row_after_desc:"\u5728\u4e0b\u65b9\u63d2\u5165\u884c",row_before_desc:"\u5728\u4e0a\u65b9\u63d2\u5165\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u5982\u679c\u96e2\u958b\u8a72\u9801\u5c07\u5c0e\u81f4\u6240\u6709\u4fee\u6539\u5168\u90e8\u907a\u5931\u3002",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u5168\u87a2\u5e55\u6a21\u5f0f"},media:{edit:"\u7de8\u8f2f \u5a92\u9ad4",desc:"\u63d2\u5165/\u7de8\u8f2f \u5a92\u9ad4",delta_height:"",delta_width:""},fullpage:{desc:"\u6587\u4ef6",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9078\u5b9a\u7684\u7bc4\u672c"},visualchars:{desc:"\u986f\u793a\u63a7\u5236\u7b26\u865f\u3002"},spellchecker:{desc:"\u62fc\u5b57\u6aa2\u67e5",menu:"\u62fc\u5b57\u6aa2\u67e5 \u8a2d\u5b9a",ignore_word:"\u5ffd\u7565",ignore_words:"\u5168\u90e8\u5ffd\u7565",langs:"\u8a9e\u8a00\u6e05\u55ae",wait:"\u8acb\u7a0d\u5019...",sug:"\u5efa\u8b70\u8a5e",no_sug:"\u7121\u62fc\u5b57\u5efa\u8b70",no_mpell:"\u7121\u62fc\u5b57\u932f\u8aa4"},pagebreak:{desc:"\u63d2\u5165\u5206\u9801\u7b26\u865f"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/uk.js0000644000175000017500000004221211526350525031525 0ustar frankiefrankietinyMCE.addI18n({uk:{common:{more_colors:"\u0411\u0456\u043b\u044c\u0448\u0435 \u043a\u043e\u043b\u044c\u043e\u0440\u0456\u0432",invalid_data:"\u041f\u043e\u043c\u0438\u043b\u043a\u0430: \u0412\u0432\u0435\u0434\u0435\u043d\u043e \u043f\u043e\u043c\u0438\u043b\u043a\u043e\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044f, \u0432\u0456\u0434\u043c\u0456\u0447\u0435\u043d\u0435 \u0447\u0435\u0440\u0432\u043e\u043d\u0438\u043c.",popup_blocked:"\u0414\u0443\u0436\u0435 \u043f\u0440\u0438\u043a\u0440\u043e, \u0430\u043b\u0435 \u0432\u0430\u0448 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0437\u0430\u0431\u043b\u043e\u043a\u0443\u0432\u0430\u0432 \u0432\u0438\u0440\u0438\u043d\u0430\u044e\u0447\u0435 \u0432\u0456\u043a\u043d\u043e. \u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u043d\u0430\u043b\u0430\u0448\u0442\u0443\u0439\u0442\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0442\u0430\u043a, \u0449\u043e\u0431 \u0432\u0456\u043d \u0434\u043e\u0437\u0432\u043e\u043b\u044f\u0432 \u0432\u0438\u0440\u0438\u043d\u0430\u044e\u0447\u0456 \u0432\u0456\u043a\u043d\u0430 \u0437 \u0446\u044c\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0443.",clipboard_no_support:"\u041d\u0430\u0440\u0430\u0437\u0456 \u0446\u044f \u0444\u0443\u043d\u043a\u0446\u0456\u044f \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0432 \u0432\u0430\u0448\u043e\u043c\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0456, \u0430\u043b\u0435 \u0432\u0438 \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 \u043a\u043b\u0430\u0432\u0456\u0430\u0442\u0443\u0440\u0443 \u0437\u0430\u043c\u0456\u0441\u0442\u044c \u0446\u044c\u043e\u0433\u043e.",clipboard_msg:"\u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438/\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438/\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0432 Mozilla \u0442\u0430 Firefox.\\n\u0412\u0430\u043c \u0446\u0456\u043a\u0430\u0432\u0430 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044f \u043f\u0440\u043e \u0446\u0435?",not_set:"-- \u043d\u0435 \u0432\u0438\u0431\u0440\u0430\u043d\u043e --",class_name:"\u041a\u043b\u0430\u0441",browse:"\u041f\u0435\u0440\u0435\u0433\u043b\u044f\u0434",close:"\u0417\u0430\u043a\u0440\u0438\u0442\u0438",cancel:"\u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438",update:"\u041e\u043d\u043e\u0432\u0438\u0442\u0438",insert:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438",apply:"\u0417\u0430\u0441\u0442\u043e\u0441\u0443\u0432\u0430\u0442\u0438",edit_confirm:"\u0412\u0438 \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0432\u0430\u0442\u0438 WYSIWYG \u0440\u0435\u0436\u0438\u043c \u0434\u043b\u044f \u0446\u044c\u043e\u0433\u043e \u043f\u043e\u043b\u044f?"},contextmenu:{full:"\u041f\u043e \u0448\u0438\u0440\u0438\u043d\u0456",right:"\u041f\u043e \u043f\u0440\u0430\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",center:"\u041f\u043e \u0446\u0435\u043d\u0442\u0440\u0443",left:"\u041f\u043e \u043b\u0456\u0432\u043e\u043c\u0443 \u043a\u0440\u0430\u044e",align:"\u0412\u0438\u0440\u0456\u0432\u043d\u044e\u0432\u0430\u043d\u043d\u044f"},insertdatetime:{day_short:"\u041d\u0434,\u041f\u043d,\u0412\u0442,\u0421\u0440,\u0427\u0442,\u041f\u0442,\u0421\u0431,\u041d\u0434",day_long:"\u041d\u0435\u0434\u0456\u043b\u044f,\u041f\u043e\u043d\u0435\u0434\u0456\u043b\u043e\u043a,\u0412\u0456\u0432\u0442\u043e\u0440\u043e\u043a,\u0421\u0435\u0440\u0435\u0434\u0430,\u0427\u0435\u0442\u0432\u0435\u0440,\u041f\'\u044f\u0442\u043d\u0438\u0446\u044f,\u0421\u0443\u0431\u043e\u0442\u0430,\u041d\u0435\u0434\u0456\u043b\u044f",months_short:"\u0421\u0456\u0447,\u041b\u044e\u0442,\u0411\u0435\u0440,\u041a\u0432\u0456,\u0422\u0440\u0430,\u0427\u0435\u0440,\u041b\u0438\u043f,\u0421\u0435\u0440,\u0412\u0435\u0440,\u0416\u043e\u0432,\u041b\u0438\u0441,\u0413\u0440\u0443",months_long:"\u0421\u0456\u0447\u0435\u043d\u044c,\u041b\u044e\u0442\u0438\u0439,\u0411\u0435\u0440\u0435\u0437\u0435\u043d\u044c,\u041a\u0432\u0456\u0442\u0435\u043d\u044c,\u0422\u0440\u0430\u0432\u0435\u043d\u044c,\u0427\u0435\u0440\u0432\u0435\u043d\u044c,\u041b\u0438\u043f\u0435\u043d\u044c,\u0421\u0435\u0440\u043f\u0435\u043d\u044c,\u0412\u0435\u0440\u0435\u0441\u0435\u043d\u044c,\u0416\u043e\u0432\u0442\u0435\u043d\u044c,\u041b\u0438\u0441\u0442\u043e\u043f\u0430\u0434,\u0413\u0440\u0443\u0434\u0435\u043d\u044c",inserttime_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0447\u0430\u0441",insertdate_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0434\u0430\u0442\u0443",time_fmt:"%H:%M:%S",date_fmt:"%d.%m.%Y"},print:{print_desc:"\u0414\u0440\u0443\u043a\u0443\u0432\u0430\u0442\u0438"},preview:{preview_desc:"\u041f\u0435\u0440\u0435\u0433\u043b\u044f\u0434"},directionality:{rtl_desc:"\u041d\u0430\u043f\u0440\u044f\u043c \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0456\u0432\u043e",ltr_desc:"\u041d\u0430\u043f\u0440\u044f\u043c \u0437\u043b\u0456\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e"},layer:{content:"\u041d\u043e\u0432\u0438\u0439 \u043f\u0440\u043e\u0448\u0430\u0440\u043e\u043a...",absolute_desc:"\u041f\u0435\u0440\u0435\u043c\u0438\u043a\u043d\u0443\u0442\u0438 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0435 \u043f\u043e\u0437\u0438\u0446\u0456\u044e\u0432\u0430\u043d\u043d\u044f",backward_desc:"\u041f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0438\u0442\u0438 \u043d\u0430\u0437\u0430\u0434",forward_desc:"\u041f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0438\u0442\u0438 \u0432\u043f\u0435\u0440\u0435\u0434",insertlayer_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043d\u043e\u0432\u0438\u0439 \u043f\u0440\u043e\u0448\u0430\u0440\u043e\u043a"},save:{save_desc:"\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438",cancel_desc:"\u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043c\u0456\u043d\u0438"},nonbreaking:{nonbreaking_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043d\u0435\u0440\u043e\u0437\u0440\u0438\u0432\u043d\u0438\u0439 \u043f\u0440\u043e\u043c\u0456\u0436\u043e\u043a"},iespell:{download:"\u0414\u043e\u0434\u0430\u0442\u043e\u043a ieSpell \u043d\u0435 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u0411\u0430\u0436\u0430\u0454\u0442\u0435 \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0438?",iespell_desc:"\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0438 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0443 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0456\u0457"},advhr:{advhr_desc:"\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0438\u0439 \u0440\u043e\u0437\u0434\u0456\u043b\u044c\u043d\u0438\u043a",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u0421\u043c\u0430\u0439\u043b\u0438",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u0428\u0443\u043a\u0430\u0442\u0438/\u0417\u0430\u043c\u0456\u043d\u0438\u0442\u0438",search_desc:"\u0428\u0443\u043a\u0430\u0442\u0438",delta_width:"",delta_height:""},advimage:{delta_width:"200",image_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438/\u0437\u043c\u0456\u043d\u0438\u0442\u0438 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",delta_height:""},advlink:{delta_width:"200",link_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438/\u0437\u043c\u0456\u043d\u0438\u0442\u0438 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",delta_height:""},xhtmlxtras:{attribs_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438/\u0437\u043c\u0456\u043d\u0438\u0442\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0438",ins_desc:"\u0412\u0441\u0442\u0430\u0432\u043a\u0430",del_desc:"\u0412\u0438\u0434\u0430\u043b\u0435\u043d\u043d\u044f",acronym_desc:"\u0410\u043a\u0440\u043e\u043d\u0456\u043c",abbr_desc:"\u0410\u0431\u0440\u0435\u0432\u0456\u0430\u0442\u0443\u0440\u0430",cite_desc:"\u0426\u0438\u0442\u0430\u0442\u0430",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 CSS \u0441\u0442\u0438\u043b\u044c",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u0412 \u0434\u0430\u043d\u0438\u0439 \u0447\u0430\u0441 \u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u0432 \u0440\u0435\u0436\u0438\u043c\u0456 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0443. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c \u0437\u043d\u043e\u0432\u0443 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0438\u043a\u0430\u043d\u043d\u044f \u043d\u0430\u0437\u0430\u0434 \u0432 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u0438\u0439 \u0440\u0435\u0436\u0438\u043c \u0412\u0441\u0442\u0430\u0432\u043a\u0438.",plaintext_mode_sticky:"\u0412 \u0434\u0430\u043d\u0438\u0439 \u0447\u0430\u0441 \u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u0432 \u0440\u0435\u0436\u0438\u043c\u0456 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0443. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c \u0437\u043d\u043e\u0432\u0443 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0438\u043a\u0430\u043d\u043d\u044f \u043d\u0430\u0437\u0430\u0434 \u0432 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u0438\u0439 \u0440\u0435\u0436\u0438\u043c \u0412\u0441\u0442\u0430\u0432\u043a\u0438.. \u041f\u0456\u0441\u043b\u044f \u0442\u043e\u0433\u043e, \u044f\u043a \u0412\u0438 \u0449\u043e-\u043d\u0435\u0431\u0443\u0434\u044c \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u0435, \u0412\u0438 \u043f\u043e\u0432\u0435\u0440\u043d\u0435\u0442\u0435\u0441\u044c \u0432 \u0437\u0432\u0438\u0447\u0430\u0439\u043d\u043c\u0439 \u0440\u0435\u0436\u0438\u043c \u0412\u0441\u0442\u0430\u0432\u043a\u0438.",selectall_desc:"\u0412\u0438\u0434\u0456\u043b\u0438\u0442\u0438 \u0432\u0441\u0435",paste_word_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0437 Word",paste_text_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u044f\u043a \u0442\u0435\u043a\u0441\u0442"},paste_dlg:{word_title:"\u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0439\u0442\u0435 CTRL+V \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0443 \u0443 \u0432\u0456\u043a\u043d\u043e.",text_linebreaks:"\u0417\u0431\u0435\u0440\u0456\u0433\u0430\u0442\u0438 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438 \u0440\u044f\u0434\u043a\u0456\u0432",text_title:"\u0412\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0439\u0442\u0435 CTRL+V \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0443 \u0443 \u0432\u0456\u043a\u043d\u043e."},table:{cellprops_delta_width:"30",cell:"\u041a\u043e\u043c\u0456\u0440\u043a\u0430",col:"\u0421\u0442\u043e\u0432\u043f\u0435\u0446\u044c",row:"\u0420\u044f\u0434\u043e\u043a",del:"\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044e",copy_row_desc:"\u041a\u043e\u043f\u0456\u044e\u0432\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0456",cut_row_desc:"\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0456",paste_row_after_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u043f\u0456\u0441\u043b\u044f",paste_row_before_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u0434\u043e",props_desc:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0442\u0430\u0431\u043b\u0438\u0446\u0456",cell_desc:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u043a\u043e\u043c\u0456\u0440\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0456",row_desc:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0440\u044f\u0434\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0456",merge_cells_desc:"\u041e\u0431\'\u0454\u0434\u043d\u0430\u0442\u0438 \u043a\u043e\u043c\u0456\u0440\u043a\u0438",split_cells_desc:"\u0420\u043e\u0437\u0434\u0456\u043b\u0438\u0442\u0438 \u043a\u043e\u043c\u0456\u0440\u043a\u0438",delete_col_desc:"\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c",col_after_desc:"\u0414\u043e\u0434\u0430\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u043f\u0456\u0441\u043b\u044f",col_before_desc:"\u0414\u043e\u0434\u0430\u0442\u0438 \u0441\u0442\u043e\u0432\u043f\u0435\u0446\u044c \u0434\u043e",delete_row_desc:"\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0440\u044f\u0434\u043e\u043a",row_after_desc:"\u0414\u043e\u0434\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u043f\u0456\u0441\u043b\u044f",row_before_desc:"\u0414\u043e\u0434\u0430\u0442\u0438 \u0440\u044f\u0434\u043e\u043a \u0434\u043e",desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043d\u043e\u0432\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044e",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u042f\u043a\u0449\u043e \u0432\u0456\u0434\u043d\u043e\u0432\u0438\u0442\u0438 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0438\u0439 \u0432\u043c\u0456\u0441\u0442, \u0442\u043e \u0432\u0438 \u0432\u0442\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u0435\u0441\u044c \u0432\u043c\u0456\u0441\u0442, \u044f\u043a\u0438\u0439 \u0432 \u0434\u0430\u043d\u0438\u0439 \u0447\u0430\u0441 \u0437\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0456. \\n\\n\u0412\u0438 \u0432\u043f\u0435\u0432\u043d\u0435\u043d\u0456, \u0449\u043e \u0445\u043e\u0447\u0435\u0442\u0435 \u0432\u0456\u0434\u043d\u043e\u0432\u0438\u0442\u0438 \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u0438\u0439 \u0437\u043c\u0456\u0441\u0442?.",restore_content:"\u0412\u0456\u0434\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u043e\u0433\u043e \u0432\u043c\u0456\u0441\u0442\u0443.",unload_msg:"\u0417\u043c\u0456\u043d\u0438, \u044f\u043a\u0456 \u0432\u0438 \u0437\u0440\u043e\u0431\u0438\u043b\u0438, \u0431\u0443\u0434\u0443\u0442\u044c \u0432\u0442\u0440\u0430\u0447\u0435\u043d\u0456, \u044f\u043a\u0449\u043e \u0432\u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u0442\u0435 \u0437 \u0446\u0456\u0454\u0457 \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0438."},fullscreen:{desc:"\u041f\u0435\u0440\u0435\u043c\u043a\u043d\u0443\u0442\u0438 \u043d\u0430 \u0432\u0435\u0441\u044c \u0435\u043a\u0440\u0430\u043d"},media:{edit:"\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u0432\u0431\u0443\u0434\u043e\u0432\u0430\u043d\u0456 \u043c\u0435\u0434\u0456\u0430",desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 / \u0440\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u0432\u0431\u0443\u0434\u043e\u0432\u0430\u043d\u0456 \u043c\u0435\u0434\u0456\u0430",delta_height:"",delta_width:""},fullpage:{desc:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",delta_width:"",delta_height:""},template:{desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442"},visualchars:{desc:"\u0412\u0456\u0437\u0443\u0430\u043b\u044c\u043d\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0441\u0438\u043c\u0432\u043e\u043b\u0456\u0432 \u0432\u0432\u0456\u043c\u043a\u043d\u0435\u043d\u043d\u044f / \u0432\u0438\u043c\u043a\u043d\u0435\u043d\u043d\u044f."},spellchecker:{desc:"\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u0438 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0443",menu:"\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0438",ignore_word:"\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0441\u043b\u043e\u0432\u043e",ignore_words:"\u0406\u0433\u043d\u043e\u0440\u0443\u0432\u0430\u0442\u0438 \u0432\u0441\u0435",langs:"\u041c\u043e\u0432\u0438",wait:"\u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430, \u0437\u0430\u0447\u0435\u043a\u0430\u0439\u0442\u0435...",sug:"\u0412\u0430\u0440\u0456\u0430\u043d\u0442\u0438",no_sug:"\u041d\u0435\u043c\u0430\u0454 \u0432\u0430\u0440\u0456\u0430\u043d\u0442\u0456\u0432",no_mpell:"\u041f\u043e\u043c\u0438\u043b\u043e\u043a \u043d\u0435 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u043e."},pagebreak:{desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0440\u043e\u0437\u0434\u0456\u043b\u044c\u043d\u0438\u043a \u0441\u0442\u043e\u0440\u0456\u043d\u043a\u0438."},advlist:{types:"\u0422\u0438\u043f\u0438",def:"\u0417\u0430 \u0437\u0430\u043c\u043e\u0432\u0447\u0430\u043d\u043d\u044f\u043c",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"\u041a\u043e\u043b\u043e",disc:"\u0414\u0438\u0441\u043a",square:"\u041a\u0432\u0430\u0434\u0440\u0430\u0442"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/tw.js0000644000175000017500000001521411526350525031542 0ustar frankiefrankietinyMCE.addI18n({tw:{common:{more_colors:"\u66f4\u591a\u984f\u8272...",invalid_data:"\u60a8\u8f38\u5165\u7684\u8cc7\u6599\u6709\u932f\u8aa4\uff08\u7d05\u8272\u90e8\u5206\uff09",popup_blocked:"\u60a8\u7684\u700f\u89bd\u5668\u7981\u6b62\u5f48\u51fa\u8996\u7a97\u3002",clipboard_no_support:"\u60a8\u7684\u700f\u89bd\u5668\u4e0d\u652f\u63f4\u8a72\u529f\u80fd\uff0c\u8acb\u4f7f\u7528Ctrl + C\u9375\u4ee3\u66ff\u3002",clipboard_msg:"\u5f88\u62b1\u6b49\uff0c\u60a8\u7684\u700f\u89bd\u5668\u4e0d\u652f\u63f4\u8907\u88fd\u529f\u80fd\u3002",not_set:"--\u5c1a\u672a\u8a2d\u5b9a--",class_name:"\u985e\u5225",browse:"\u9810\u89bd",close:"\u95dc\u9589",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5957\u7528",edit_confirm:"\u662f\u5426\u9700\u8981\u958b\u555f\u6587\u5b57\u7de8\u8f2f\u5668\uff1f"},contextmenu:{full:"\u5de6\u53f3\u5c0d\u9f4a",right:"\u9760\u53f3\u5c0d\u9f4a",center:"\u7f6e\u4e2d\u5c0d\u9f4a",left:"\u9760\u5de6\u5c0d\u9f4a",align:"\u5c0d\u9f4a"},insertdatetime:{day_short:"\u9031\u65e5,\u9031\u4e00,\u9031\u4e8c,\u9031\u4e09,\u9031\u56db,\u9031\u4e94,\u9031\u516d,\u9031\u65e5",day_long:"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u4e09,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5",months_short:"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708",months_long:"\u4e00\u6708,\u4e8c\u6708,\u4e09\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u76ee\u524d\u6642\u9593",insertdate_desc:"\u63d2\u5165\u76ee\u524d\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y/%m/%d"},print:{print_desc:"\u5217\u5370"},preview:{preview_desc:"\u9810\u89bd"},directionality:{rtl_desc:"\u5f9e\u53f3\u5230\u5de6",ltr_desc:"\u5f9e\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u5efa\u5716\u5c64...",absolute_desc:"\u5207\u63db\u5230\u7d55\u5c0d\u4f4d\u7f6e",backward_desc:"\u7f6e\u5f8c",forward_desc:"\u7f6e\u524d",insertlayer_desc:"\u63d2\u5165\u5716\u5c64"},save:{save_desc:"\u5b58\u6a94",cancel_desc:"\u53d6\u6d88\u6240\u6709\u8b8a\u66f4"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u683c"},iespell:{download:"\u6aa2\u67e5\u4e0d\u5230ieSpell\u5916\u639b\u7a0b\u5f0f\u7a0b\u5f0f\uff0c\u662f\u5426\u7acb\u5373\u5b89\u88dd\uff1f",iespell_desc:"\u62fc\u5b57\u6aa2\u67e5"},advhr:{advhr_desc:"\u6c34\u5e73\u7dda",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u8868\u60c5",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u641c\u5c0b/\u53d6\u4ee3",search_desc:"\u641c\u5c0b",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7de8\u8f2f\u5716\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7de8\u8f2f\u8d85\u9023\u7d50",delta_height:"",delta_width:""},xhtmlxtras:{attribs_delta_height:"60",attribs_delta_width:"40",attribs_desc:"\u63d2\u5165/\u7de8\u8f2f\u5c6c\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u522a\u9664",acronym_desc:"\u9996\u5b57\u6bcd\u7e2e\u5beb",abbr_desc:"\u7e2e\u5beb",cite_desc:"\u5f15\u7528",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7de8\u8f2f CSS \u6a23\u5f0f\u8868",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u76ee\u524d\u70ba\u4e00\u822c\u8cbc\u4e0a\u6a21\u5f0f\uff0c\u518d\u9ede\u9ede\u95b1\u4e00\u6b21\u5207\u63db\u56de\u7d14\u6587\u5b57\u8cbc\u4e0a\u6a21\u5f0f\u3002",plaintext_mode_sticky:"\u76ee\u524d\u70ba\u7d14\u6587\u5b57\u8cbc\u4e0a\u6a21\u5f0f\uff0c\u518d\u9ede\u95b1\u4e00\u6b21\u5207\u63db\u56de\u4e00\u822c\u6a21\u5f0f\u3002",selectall_desc:"\u5168\u9078",paste_word_desc:"\u4ee5Word\u683c\u5f0f\u8cbc\u4e0a",paste_text_desc:"\u4ee5\u7d14\u6587\u5b57\u8cbc\u4e0a"},paste_dlg:{word_title:"\u7528 Ctrl+V \u5c07\u5167\u5bb9\u8cbc\u4e0a\u3002",text_linebreaks:"\u4fdd\u7559\u63db\u884c\u7b26\u865f",text_title:"\u7528 Ctrl+V \u5c07\u5167\u5bb9\u8cbc\u4e0a\u3002"},table:{merge_cells_delta_height:"40",merge_cells_delta_width:"40",table_delta_height:"60",table_delta_width:"40",cellprops_delta_height:"10",cellprops_delta_width:"10",cell:"\u5132\u5b58\u683c",col:"\u6b04",row:"\u884c",del:"\u522a\u9664\u8868\u683c",copy_row_desc:"\u8907\u88fd\u9078\u64c7\u884c",cut_row_desc:"\u526a\u4e0b\u9078\u64c7\u884c",paste_row_after_desc:"\u5728\u4e0b\u65b9\u8cbc\u4e0a\u884c",paste_row_before_desc:"\u5728\u4e0a\u65b9\u8cbc\u4e0a\u884c",props_desc:"\u8868\u683c\u5c6c\u6027",cell_desc:"\u5132\u5b58\u683c\u5c6c\u6027",row_desc:"\u884c\u5c6c\u6027",merge_cells_desc:"\u5408\u4f75\u5132\u5b58\u683c",split_cells_desc:"\u5206\u5272\u5132\u5b58\u683c",delete_col_desc:"\u522a\u9664\u76ee\u524d\u6b04",col_after_desc:"\u5728\u53f3\u5074\u63d2\u5165\u6b04",col_before_desc:"\u5728\u5de6\u5074\u63d2\u5165\u6b04",delete_row_desc:"\u522a\u9664\u76ee\u524d\u884c",row_after_desc:"\u5728\u4e0b\u65b9\u63d2\u5165\u884c",row_before_desc:"\u5728\u4e0a\u65b9\u63d2\u5165\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u5982\u679c\u6062\u5fa9\u5148\u524d\u5132\u5b58\u7684\u5167\u5bb9\uff0c\u60a8\u5c07\u5931\u53bb\u7de8\u8f2f\u5668\u4e2d\u73fe\u6709\u7684\u5167\u5bb9\u3002 \\n\\n\u60a8\u78ba\u5b9a\u8981\u6062\u5fa9\u5148\u524d\u5132\u5b58\u7684\u5167\u5bb9\u55ce\uff1f",restore_content:"\u6062\u5fa9\u81ea\u52d5\u5132\u5b58\u7684\u5167\u5bb9\u3002",unload_msg:"\u60a8\u5c1a\u672a\u5132\u5b58\u8cc7\u6599\uff0c\u60a8\u8f38\u5165\u7684\u8cc7\u6599\u53ef\u80fd\u6703\u907a\u5931..."},fullscreen:{desc:"\u5168\u87a2\u5e55\u7de8\u8f2f"},media:{edit:"\u7de8\u8f2f\u5f71\u7247",desc:"\u63d2\u5165/\u7de8\u8f2f\u5f71\u7247",delta_height:"",delta_width:""},fullpage:{desc:"\u6a94\u6848\u5c6c\u6027",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9810\u8a2d\u6a21\u677f"},visualchars:{desc:"\u986f\u793a/\u96b1\u85cf\u4e0d\u53ef\u898b\u5b57\u5143"},spellchecker:{desc:"\u958b\u95dc\u62fc\u5b57\u6aa2\u67e5",menu:"\u62fc\u5b57\u6aa2\u67e5\u8a2d\u5b9a",ignore_word:"\u5ffd\u7565",ignore_words:"\u5168\u90e8\u5ffd\u7565",langs:"\u8a9e\u8a00",wait:"\u8acb\u7a0d\u5019...",sug:"\u5efa\u8b70",no_sug:"\u7121\u5efa\u8b70",no_mpell:"\u7121\u62fc\u5b57\u932f\u8aa4"},pagebreak:{desc:"\u63d2\u5165\u5206\u9801\u7b26\u865f"},advlist:{types:"\u6a23\u5f0f",def:"\u9810\u8a2d",lower_alpha:"\u5c0f\u5beb\u7684\u82f1\u6587\u5b57",lower_greek:"\u5c0f\u5beb\u7684\u5e0c\u81d8\u6587\u5b57",lower_roman:"\u5c0f\u5beb\u7684\u7f85\u99ac\u6578\u5b57",upper_alpha:"\u5927\u5beb\u7684\u82f1\u6587\u5b57",upper_roman:"\u5927\u5beb\u7684\u7f85\u99ac\u6578\u5b57",circle:"\u5713\u5708",disc:"\u5713\u9ede",square:"\u65b9\u584a"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/ur.js0000644000175000017500000001342211526350525031535 0ustar frankiefrankietinyMCE.addI18n({ur:{common:{more_colors:"More colors",invalid_data:"Error: Invalid values entered, these are marked in red.",popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",clipboard_no_support:"\u0627\u0653\u067e \u06a9\u06d2 \u0628\u0631\u0627\u0624\u0632\u0631 \u0645\u06cc\u06ba \u06cc\u06c1 \u0633\u06c1\u0648\u0644\u062a \u0645\u06cc\u0633\u0631 \u0646\u06c1\u06cc\u06ba\u06d4 \u06a9\u06cc \u0628\u0648\u0631\u0688 \u0634\u0627\u0631\u0679 \u06a9\u0679 \u0645\u0646\u062a\u062e\u0628 \u06a9\u0631\u06cc\u06ba",clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\\nDo you want more information about this issue?",not_set:"-- \u0646\u0627\u0679 \u0633\u06cc\u0679 --",class_name:"\u06a9\u0644\u0627\u0633",browse:"\u0628\u0631\u0627\u0624\u0632",close:"\u0628\u0646\u062f",cancel:"\u06a9\u06cc\u0646\u0633\u0644",update:"\u0627\u067e \u0688\u06cc\u0679",insert:"\u062f\u0627\u062e\u0644 \u06a9\u0631\u06cc\u06ba",apply:"\u0627\u067e\u0644\u0627\u0626\u06cc",edit_confirm:"\u06a9\u06cc\u0627 \u0627\u0653\u067e \u0627\u0633 \u0679\u06cc\u06a9\u0633\u0679 \u0627\u06cc\u0631\u06cc\u0627 \u06a9\u06cc\u0644\u0626\u06d2 \u0648\u0632\u06cc \u0648\u06af \u0645\u0648\u0688 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u061f"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun",day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",months_long:"January,February,March,April,May,June,July,August,September,October,November,December",inserttime_desc:"Insert time",insertdate_desc:"Insert date",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"Print"},preview:{preview_desc:"Preview"},directionality:{rtl_desc:"Direction right to left",ltr_desc:"Direction left to right"},layer:{content:"New layer...",absolute_desc:"Toggle absolute positioning",backward_desc:"Move backward",forward_desc:"Move forward",insertlayer_desc:"Insert new layer"},save:{save_desc:"Save",cancel_desc:"Cancel all changes"},nonbreaking:{nonbreaking_desc:"Insert non-breaking space character"},iespell:{download:"ieSpell not detected. Do you want to install it now?",iespell_desc:"Run spell checking"},advhr:{advhr_desc:"Horizontal rule",delta_height:"",delta_width:""},emotions:{emotions_desc:"Emotions",delta_height:"",delta_width:""},searchreplace:{replace_desc:"Find/Replace",search_desc:"Find",delta_width:"",delta_height:""},advimage:{image_desc:"Insert/edit image",delta_width:"",delta_height:""},advlink:{link_desc:"Insert/edit link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Insert/Edit Attributes",ins_desc:"Insertion",del_desc:"Deletion",acronym_desc:"Acronym",abbr_desc:"Abbreviation",cite_desc:"Citation",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"Edit CSS Style",delta_height:"",delta_width:""},paste:{selectall_desc:"Select All",paste_word_desc:"Paste from Word",paste_text_desc:"Paste as Plain Text",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"Use CTRL+V on your keyboard to paste the text into the window.",text_linebreaks:"Keep linebreaks",text_title:"Use CTRL+V on your keyboard to paste the text into the window."},table:{cell:"Cell",col:"Column",row:"Row",del:"Delete table",copy_row_desc:"Copy table row",cut_row_desc:"Cut table row",paste_row_after_desc:"Paste table row after",paste_row_before_desc:"Paste table row before",props_desc:"Table properties",cell_desc:"Table cell properties",row_desc:"Table row properties",merge_cells_desc:"Merge table cells",split_cells_desc:"Split merged table cells",delete_col_desc:"Remove column",col_after_desc:"Insert column after",col_before_desc:"Insert column before",delete_row_desc:"Delete row",row_after_desc:"Insert row after",row_before_desc:"Insert row before",desc:"Inserts a new table",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"The changes you made will be lost if you navigate away from this page.",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"Toggle fullscreen mode"},media:{edit:"Edit embedded media",desc:"Insert / edit embedded media",delta_height:"",delta_width:""},fullpage:{desc:"Document properties",delta_width:"",delta_height:""},template:{desc:"Insert predefined template content"},visualchars:{desc:"Visual control characters on/off."},spellchecker:{desc:"Toggle spellchecker",menu:"Spellchecker settings",ignore_word:"Ignore word",ignore_words:"Ignore all",langs:"Languages",wait:"Please wait...",sug:"Suggestions",no_sug:"No suggestions",no_mpell:"No misspellings found."},pagebreak:{desc:"Insert page break."},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/vi.js0000644000175000017500000001730411526350525031530 0ustar frankiefrankietinyMCE.addI18n({vi:{common:{more_colors:"M\u00e0u kh\u00e1c",invalid_data:"L\u1ed7i: Gi\u00e1 tr\u1ecb nh\u1eadp v\u00e0o kh\u00f4ng h\u1ee3p l\u1ec7. (\u0110\u01b0\u1ee3c \u0111\u00e1nh d\u1ea5u \u0111\u1ecf)",popup_blocked:"Xin l\u1ed7i, Nh\u01b0ng ch\u1ebf \u0111\u1ed9 c\u1eeda s\u1ed5 popup \u0111\u00e3 b\u1ecb v\u00f4 hi\u1ec7u ho\u00e1. B\u1ea1n s\u1ebd c\u1ea7n ph\u1ea3i t\u1eaft ch\u1ee9c n\u0103ng ch\u1eb7n popup tr\u00ean trang web n\u00e0y \u0111\u1ec3 s\u1eed d\u1ee5ng c\u00f4ng c\u1ee5 n\u00e0y ho\u00e0n to\u00e0n.",clipboard_no_support:"S\u1eed d\u1ee5ng ph\u00edm t\u1eaft kh\u00f4ng \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng trong tr\u00ecnh duy\u1ec7t hi\u1ec7n t\u1ea1i.",clipboard_msg:"Copy/Cut/Paste kh\u00f4ng \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 trong tr\u00ecnh duy\u1ec7t web n\u00e0y.\\nB\u1ea1n c\u00f3 mu\u1ed1n bi\u1ebft th\u00eam th\u00f4ng tin v\u1ec1 v\u1ea5n \u0111\u1ec1 n\u00e0y kh\u00f4ng??",not_set:"-- Ch\u01b0a \u0111\u1eb7t --",class_name:"L\u1edbp",browse:"T\u00ecm",close:"Tho\u00e1t",cancel:"H\u1ee7y b\u1ecf",update:"C\u1eadp nh\u1eadt",insert:"Th\u00eam",apply:"Thay \u0111\u1ed5i",edit_confirm:"B\u1ea1n c\u00f3 mu\u1ed1n s\u1eed d\u1ee5ng ch\u1ebf \u0111\u1ed9 WYSIWYG cho textarea n\u00e0y?"},contextmenu:{full:"\u0110\u1ea7y",right:"Ph\u1ea3i",center:"Gi\u1eefa",left:"Tr\u00e1i",align:"Canh l\u1ec1"},insertdatetime:{day_short:"CN,T2,T3,T4,T5,T6,T7,CN",day_long:"Ch\u1ee7 Nh\u1eadt,Th\u1ee9 Hai,Th\u1ee9 Ba,Th\u1ee9 T\u01b0,Th\u1ee9 N\u0103m,Th\u1ee9 S\u00e1u,Th\u1ee9 B\u1ea3y,Ch\u1ee7 Nh\u1eadt",months_short:"Thg1,Thg2,Thg3,Thg4,Thg5,Thg6,Thg7,Thg8,Thg9,Th10,Th11,Th12",months_long:"Th\u00e1ng M\u1ed9t,Th\u00e1ng Hai,Th\u00e1ng Ba,Th\u00e1ng T\u01b0,Th\u00e1ng N\u0103m,Th\u00e1ng S\u00e1u,Th\u00e1ng B\u1ea3y,Th\u00e1ng T\u00e1m,Th\u00e1ng Ch\u00edn,Th\u00e1ng M\u01b0\u1eddi,Th\u00e1ng M\u01b0\u1eddi M\u1ed9t,Th\u00e1ng M\u01b0\u1eddi Hai",inserttime_desc:"Ch\u00e8n gi\u1edd",insertdate_desc:"Ch\u00e8n ng\u00e0y",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"In"},preview:{preview_desc:"Xem tr\u01b0\u1edbc"},directionality:{rtl_desc:"H\u01b0\u1edbng ph\u1ea3i qua tr\u00e1i",ltr_desc:"H\u01b0\u1edbng tr\u00e1i qua ph\u1ea3i"},layer:{content:"L\u1edbp m\u1edbi...",absolute_desc:"\u0110\u1ea3o v\u1ecb tr\u00ed c\u1ed1 \u0111\u1ecbnh",backward_desc:"Di chuy\u1ec3n v\u1ec1 sau",forward_desc:"Di chuy\u1ec3n v\u1ec1 tr\u01b0\u1edbc",insertlayer_desc:"Ch\u00e8n l\u1edbp m\u1edbi"},save:{save_desc:"L\u01b0u",cancel_desc:"H\u1ee7y b\u1ecf t\u1ea5t c\u1ea3 thay \u0111\u1ed5i"},nonbreaking:{nonbreaking_desc:"Ch\u00e8n k\u00fd t\u1ef1 kho\u1ea3ng c\u00e1ch kh\u00f4ng b\u1ecb ng\u1eaft"},iespell:{download:"ieSpell kh\u00f4ng \u0111\u01b0\u1ee3c ph\u00e1t hi\u1ec7n. B\u1ea1n c\u00f3 mu\u1ed1n c\u00e0i \u0111\u1eb7t n\u00f3 b\u00e2y gi\u1edd?",iespell_desc:"Ch\u1ea1y tr\u00ecnh ki\u1ec3m tra ch\u00ednh t\u1ea3"},advhr:{advhr_desc:"Th\u01b0\u1edbc ngang",delta_height:"",delta_width:""},emotions:{emotions_desc:"Bi\u1ec3u T\u01b0\u1ee3ng C\u1ea3m X\u00fac",delta_height:"",delta_width:""},searchreplace:{replace_desc:"T\u00ecm/Thay th\u1ebf",search_desc:"T\u00ecm",delta_width:"",delta_height:""},advimage:{image_desc:"Ch\u00e8n/s\u1eeda \u1ea3nh",delta_width:"",delta_height:""},advlink:{link_desc:"Th\u00eam/S\u1eeda Link",delta_height:"",delta_width:""},xhtmlxtras:{attribs_desc:"Ch\u00e8n/S\u1eeda c\u00e1c thu\u1ed9c t\u00ednh",ins_desc:"Ch\u00e8n",del_desc:"X\u00f3a",acronym_desc:"T\u1eeb vi\u1ebft t\u1eaft",abbr_desc:"T\u00ean vi\u1ebft t\u1eaft",cite_desc:"Bi\u00ea\u0309u ch\u01b0\u01a1ng",attribs_delta_height:"",attribs_delta_width:"",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"S\u1eeda ki\u1ec3u d\u00e1ng CSS",delta_height:"",delta_width:""},paste:{plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",selectall_desc:"Ch\u1ecdn t\u1ea5t",paste_word_desc:"D\u00e1n t\u1eeb Word",paste_text_desc:"D\u00e1nh nh\u01b0 Plain Text"},paste_dlg:{word_title:"S\u1eed d\u1ee5ng CTRL+V tr\u00ean b\u00e0n ph\u00edm \u0111\u1ec3 d\u00e1n v\u0103n b\u1ea3n v\u00e0o c\u1eeda s\u1ed5.",text_linebreaks:"Gi\u1eef ng\u1eaft d\u00f2ng",text_title:"S\u1eed d\u1ee5ng CTRL+V tr\u00ean b\u00e0n ph\u00edm \u0111\u1ec3 d\u00e1n v\u0103n b\u1ea3n v\u00e0o c\u1eeda s\u1ed5."},table:{cell:"\u00d4",col:"C\u1ed9t",row:"H\u00e0ng",del:"X\u00f3a b\u1ea3ng",copy_row_desc:"Sao ch\u00e9p h\u00e0ng",cut_row_desc:"C\u1eaft h\u00e0ng",paste_row_after_desc:"D\u00e1n hang v\u00e0o sau",paste_row_before_desc:"D\u00e1n hang v\u00e0o tr\u01b0\u1edbc",props_desc:"Thu\u1ed9c t\u00ednh b\u1ea3ng",cell_desc:"Thu\u1ed9c t\u00ednh \u00f4",row_desc:"Thu\u1ed9c t\u00ednh h\u00e0ng",merge_cells_desc:"K\u1ebft h\u1ee3p c\u00e1c \u00f4 c\u1ee7a b\u1ea3ng",split_cells_desc:"T\u00e1ch c\u00e1c \u00f4 \u0111\u00e3 k\u1ebft h\u1ee3p c\u1ee7a b\u1ea3ng",delete_col_desc:"Lo\u1ea1i b\u1ecf c\u1ed9t",col_after_desc:"Ch\u00e8n c\u1ed9t v\u00e0o sau",col_before_desc:"Ch\u00e8n c\u1ed9t v\u00e0o tr\u01b0\u1edbc",delete_row_desc:"X\u00f3a d\u00f2ng",row_after_desc:"Ch\u00e8n h\u00e0ng v\u00e0o sau",row_before_desc:"Ch\u00e8n h\u00e0ng v\u00e0o tr\u01b0\u1edbc",desc:"Ch\u00e8n m\u1ed9t b\u1ea3ng m\u1edbi",merge_cells_delta_height:"",merge_cells_delta_width:"",table_delta_height:"",table_delta_width:"",cellprops_delta_height:"",cellprops_delta_width:"",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"N\u1ebfu b\u1ea1n kh\u00f4i ph\u1ee5c l\u1ea1i n\u1ed9i dung \u0111\u00e3 l\u01b0u, b\u1ea1n s\u1ebd m\u1ea5t t\u1ea5t c\u1ea3 c\u00e1c n\u1ed9i dung m\u00e0 hi\u1ec7n \u0111ang trong tr\u00ecnh so\u1ea1n th\u1ea3o.\\n\\nB\u1ea1n c\u00f3 ch\u1eafc l\u00e0 b\u1ea1n mu\u1ed1n kh\u00f4i ph\u1ee5c l\u1ea1i n\u1ed9i dung \u0111\u00e3 l\u01b0u?.",restore_content:"Kh\u00f4i ph\u1ee5c n\u1ed9i dung t\u1ef1 \u0111\u1ed9ng l\u01b0u l\u1ea1i.",unload_msg:"Nh\u1eefng thay \u0111\u1ed5i b\u1ea1n \u0111\u00e3 th\u1ef1c hi\u1ec7n s\u1ebd b\u1ecb m\u1ea5t n\u1ebfu b\u1ea1n \u0111i\u1ec1u h\u01b0\u1edbng \u0111i t\u1eeb trang n\u00e0y."},fullscreen:{desc:"B\u1eadt/t\u1eaft ch\u1ebf \u0111\u1ed9 to\u00e0n m\u00e0n h\u00ecnh"},media:{edit:"S\u1eeda ph\u01b0\u01a1ng ti\u1ec7n truy\u1ec1n th\u00f4ng nh\u00fang",desc:"Ch\u00e8n / s\u1eeda ph\u01b0\u01a1ng ti\u1ec7n truy\u1ec1n th\u00f4ng nh\u00fang",delta_height:"",delta_width:""},fullpage:{desc:"Thu\u1ed9c t\u00ednh v\u0103n b\u1ea3n",delta_width:"",delta_height:""},template:{desc:"Ch\u00e8n m\u1ed9t n\u1ed9i dung m\u1eabu \u0111\u1ecbnh ngh\u0129a tr\u01b0\u1edbc"},visualchars:{desc:"B\u1eb7t/T\u1eaft c\u00e1c k\u00fd t\u1ef1 \u0111i\u1ec1u khi\u1ec3n tr\u1ef1c quan."},spellchecker:{desc:"B\u1eadt/T\u1eaft ki\u1ec3m tra ch\u00ednh t\u1ea3",menu:"Thi\u1ebft l\u1eadp ki\u1ec3m tra ch\u00ednh t\u1ea3",ignore_word:"B\u1ecf qua t\u1eeb ng\u1eef",ignore_words:"B\u1ecf qua t\u1ea5t c\u1ea3",langs:"Ng\u00f4n ng\u1eef",wait:"Vui l\u00f2ng ch\u1edd...",sug:"G\u1ee3i \u00fd",no_sug:"Kh\u00f4ng c\u00f3 g\u1ee3i \u00fd",no_mpell:"Kh\u00f4ng c\u00f3 l\u1ed7i ch\u00ednh t\u1ea3 \u0111\u01b0\u1ee3c t\u00ecm th\u1ea5y."},pagebreak:{desc:"Ch\u00e8n ng\u1eaft trang."},advlist:{types:"Ki\u1ec3u",def:"M\u1eb7c \u0111\u1ecbnh",lower_alpha:"K\u00fd hi\u1ec7u alpha th\u01b0\u1eddng",lower_greek:"K\u00fd hi\u1ec7u Hy-l\u1ea1p th\u01b0\u1eddng",lower_roman:"K\u00fd hi\u1ec7u La m\u00e3 th\u01b0\u1eddng",upper_alpha:"K\u00fd hi\u1ec7u alpha cao",upper_roman:"K\u00fd hi\u1ec7u La m\u00e3 hoa",circle:"Tr\u00f2ng",disc:"\u0110\u0129a",square:"Vu\u00f4ng"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/zh.js0000644000175000017500000001520011526350525031524 0ustar frankiefrankietinyMCE.addI18n({zh:{common:{more_colors:"\u66f4\u591a\u989c\u8272...",invalid_data:"\u4f60\u8f93\u5165\u7684\u8d44\u6599\u6709\u8bef\uff08\u7ea2\u8272\u90e8\u5206\uff09",popup_blocked:"\u4f60\u7684\u6d4f\u89c8\u5668\u7981\u6b62\u4e86\u5f39\u51fa\u89c6\u7a97\u3002",clipboard_no_support:"\u60a8\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u63f4\u8be5\u529f\u80fd\uff0c\u8bf7\u4f7f\u7528Ctrl + C\u952e\u4ee3\u66ff\u3002",clipboard_msg:"\u5f88\u62b1\u6b49\uff0c\u60a8\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u63f4\u590d\u88fd\u529f\u80fd\u3002",not_set:"--\u5c1a\u672a\u8bbe\u5b9a--",class_name:"\u7c7b\u522b",browse:"\u9884\u89c8",close:"\u5173\u95ed",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5957\u7528",edit_confirm:"\u662f\u5426\u9700\u8981\u5f00\u542f\u6587\u5b57\u7f16\u8f91\u5668\uff1f"},contextmenu:{full:"\u5de6\u53f3\u5bf9\u9f50",right:"\u9760\u53f3\u5bf9\u9f50",center:"\u7f6e\u4e2d\u5bf9\u9f50",left:"\u9760\u5de6\u5bf9\u9f50",align:"\u5bf9\u9f50"},insertdatetime:{day_short:"\u5468\u65e5,\u5468\u4e00,\u5468\u4e8c,\u5468\u53c1,\u5468\u56db,\u5468\u4e94,\u5468\u516d,\u5468\u65e5",day_long:"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u53c1,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5",months_short:"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708",months_long:"\u4e00\u6708,\u4e8c\u6708,\u53c1\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u76ee\u524d\u65f6\u95f4",insertdate_desc:"\u63d2\u5165\u76ee\u524d\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y/%m/%d"},print:{print_desc:"\u5217\u5370"},preview:{preview_desc:"\u9884\u89c8"},directionality:{rtl_desc:"\u4ece\u53f3\u5230\u5de6",ltr_desc:"\u4ece\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u5efa\u56fe\u5c42...",absolute_desc:"\u5207\u6362\u5230\u7edd\u5bf9\u4f4d\u7f6e",backward_desc:"\u7f6e\u540e",forward_desc:"\u7f6e\u524d",insertlayer_desc:"\u63d2\u5165\u56fe\u5c42"},save:{save_desc:"\u5b58\u6863",cancel_desc:"\u53d6\u6d88\u6240\u6709\u53d8\u66f4"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u683c"},iespell:{download:"\u68c0\u67e5\u4e0d\u5230ieSpell\u63d2\u4ef6\u7a0b\u5e8f\uff0c\u662f\u5426\u7acb\u5373\u5b89\u88c5\uff1f",iespell_desc:"\u62fc\u5b57\u68c0\u67e5"},advhr:{advhr_desc:"\u6c34\u5e73\u7ebf",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u8868\u60c5",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u641c\u5bfb/\u53d6\u4ee3",search_desc:"\u641c\u5bfb",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7f16\u8f91\u56fe\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7f16\u8f91\u8d85\u8fde\u7ed3",delta_height:"",delta_width:""},xhtmlxtras:{attribs_delta_height:"60",attribs_delta_width:"40",attribs_desc:"\u63d2\u5165/\u7f16\u8f91\u5c5e\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u5220\u9664",acronym_desc:"\u9996\u5b57\u6bcd\u7f29\u5199",abbr_desc:"\u7f29\u5199",cite_desc:"\u5f15\u7528",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7f16\u8f91 CSS \u6837\u5f0f\u8868",delta_height:"",delta_width:""},paste:{plaintext_mode:"\u76ee\u524d\u4e3a\u4e00\u822c\u8d34\u4e0a\u6a21\u5f0f\uff0c\u518d\u70b9\u70b9\u51fb\u4e00\u6b21\u5207\u6362\u56de\u7eaf\u6587\u672c\u8d34\u4e0a\u6a21\u5f0f\u3002",plaintext_mode_sticky:"\u76ee\u524d\u4e3a\u7eaf\u6587\u672c\u8d34\u4e0a\u6a21\u5f0f\uff0c\u518d\u70b9\u51fb\u4e00\u6b21\u5207\u6362\u56de\u4e00\u822c\u6a21\u5f0f\u3002",selectall_desc:"\u5168\u9009",paste_word_desc:"\u4ee5Word\u683c\u5f0f\u8d34\u4e0a",paste_text_desc:"\u4ee5\u7eaf\u6587\u672c\u8d34\u4e0a"},paste_dlg:{word_title:"\u7528 Ctrl+V \u5c06\u5185\u5bb9\u8d34\u4e0a\u3002",text_linebreaks:"\u4fdd\u7559\u5206\u884c\u7b26\u53f7",text_title:"\u7528 Ctrl+V \u5c06\u5185\u5bb9\u8d34\u4e0a\u3002"},table:{merge_cells_delta_height:"40",merge_cells_delta_width:"40",table_delta_height:"60",table_delta_width:"40",cellprops_delta_height:"10",cellprops_delta_width:"10",cell:"\u50a8\u5b58\u683c",col:"\u680f",row:"\u884c",del:"\u5220\u9664\u8868\u683c",copy_row_desc:"\u590d\u88fd\u9009\u62e9\u884c",cut_row_desc:"\u526a\u4e0b\u9009\u62e9\u884c",paste_row_after_desc:"\u5728\u4e0b\u65b9\u8d34\u4e0a\u884c",paste_row_before_desc:"\u5728\u4e0a\u65b9\u8d34\u4e0a\u884c",props_desc:"\u8868\u683c\u5c5e\u6027",cell_desc:"\u50a8\u5b58\u683c\u5c5e\u6027",row_desc:"\u884c\u5c5e\u6027",merge_cells_desc:"\u5408\u4f75\u50a8\u5b58\u683c",split_cells_desc:"\u5206\u5272\u50a8\u5b58\u683c",delete_col_desc:"\u5220\u9664\u76ee\u524d\u680f",col_after_desc:"\u5728\u53f3\u4fa7\u63d2\u5165\u680f",col_before_desc:"\u5728\u5de6\u4fa7\u63d2\u5165\u680f",delete_row_desc:"\u5220\u9664\u76ee\u524d\u884c",row_after_desc:"\u5728\u4e0b\u65b9\u63d2\u5165\u884c",row_before_desc:"\u5728\u4e0a\u65b9\u63d2\u5165\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{warning_message:"\u5982\u679c\u6062\u5fa9\u5148\u524d\u50a8\u5b58\u7684\u5185\u5bb9\uff0c\u60a8\u5c06\u5931\u53bb\u7f16\u8f91\u5668\u4e2d\u73b0\u6709\u7684\u5185\u5bb9\u3002 \\n\\n\u60a8\u786e\u5b9a\u8981\u6062\u5fa9\u5148\u524d\u50a8\u5b58\u7684\u5185\u5bb9\u5417\uff1f",restore_content:"\u6062\u5fa9\u81ea\u52a8\u50a8\u5b58\u7684\u5185\u5bb9\u3002",unload_msg:"\u60a8\u5c1a\u672a\u50a8\u5b58\u5185\u5bb9\uff0c\u60a8\u8f93\u5165\u7684\u5185\u5bb9\u53ef\u80fd\u4f1a\u4e22\u5931..."},fullscreen:{desc:"\u5168\u8424\u5e55\u7f16\u8f91"},media:{edit:"\u7f16\u8f91\u5f71\u7247",desc:"\u63d2\u5165/\u7f16\u8f91\u5f71\u7247",delta_height:"",delta_width:""},fullpage:{desc:"\u6863\u6848\u5c5e\u6027",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9884\u8bbe\u6a21\u677f"},visualchars:{desc:"\u663e\u793a/\u9690\u85cf\u975e\u53ef\u89c1\u5b57\u7b26"},spellchecker:{desc:"\u5f00\u5173\u62fc\u5199\u68c0\u67e5",menu:"\u62fc\u5b57\u68c0\u67e5\u8bbe\u5b9a",ignore_word:"\u5ffd\u7565",ignore_words:"\u5168\u90e8\u5ffd\u7565",langs:"\u8bed\u8a00",wait:"\u8bf7\u7a0d\u5019...",sug:"\u5efa\u8bae",no_sug:"\u65e0\u5efa\u8bae",no_mpell:"\u65e0\u62fc\u5199\u9519\u8bef"},pagebreak:{desc:"\u63d2\u5165\u5206\u9875\u7b26\u53f7"},advlist:{types:"\u6837\u5f0f",def:"\u9884\u8bbe",lower_alpha:"\u5c0f\u5199\u7684\u82f1\u6587\u5b57",lower_greek:"\u5c0f\u5199\u7684\u5e0c\u814a\u6587\u5b57",lower_roman:"\u5c0f\u5199\u7684\u7f57\u9a6c\u6570\u5b57",upper_alpha:"\u5927\u5199\u7684\u82f1\u6587\u5b57",upper_roman:"\u5927\u5199\u7684\u7f57\u9a6c\u6570\u5b57",circle:"\u5706\u5708",disc:"\u5706\u70b9",square:"\u65b9\u5f62"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/zu.js0000644000175000017500000001542211526350525031547 0ustar frankiefrankietinyMCE.addI18n({zu:{common:{more_colors:"\u66f4\u591a\u989c\u8272",invalid_data:"\u9519\u8bef:\u65e0\u6548\u8f93\u5165\u503c\uff0c\u5df2\u6807\u8bb0\u4e3a\u7ea2\u8272\u3002",popup_blocked:"\u62b1\u6b49\uff01\u5feb\u663e\u89c6\u7a97\u5df2\u88ab\u963b\u6b62\uff0c\u8bf7\u8c03\u6574\u6d41\u89c8\u5668\u8bbe\u7f6e\uff0c\u5141\u8bb8\u6b64\u7f51\u7ad9\u53ef\u5f39\u51fa\u65b0\u89c6\u7a97\uff0c\u4ee5\u4fbf\u4f7f\u7528\u6b64\u5de5\u5177",clipboard_no_support:"\u8fd8\u4e0d\u652f\u63f4\u60a8\u7684\u6d41\u89c8\u5668\uff0c\u8bf7\u4f7f\u7528\u952e\u76d8\u5feb\u901f\u952e",clipboard_msg:"\u590d\u5236\u3001\u526a\u4e0b\u3001\u8d34\u4e0a\u529f\u80fd\u5728Mozilla\u548cFirefox\u4e2d\u4e0d\u80fd\u4f7f\u7528\u3002 \\n\u662f\u5426\u9700\u8981\u4e86\u89e3\u66f4\u591a\u6709\u5173\u6b64\u95ee\u9898\u7684\u8d44\u8baf\uff1f",not_set:"--\u672a\u8bbe\u7f6e--",class_name:"\u6837\u5f0f",browse:"\u6d41\u89c8",close:"\u5173\u95ed",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5e94\u7528",edit_confirm:"\u662f\u5426\u5728\u6b64textarea\u6807\u7b7e\u5185\u4f7f\u7528\"\u6240\u89c1\u5373\u6240\u5f97\"\u6a21\u5f0f\uff1f"},contextmenu:{full:"\u4e24\u7aef\u5bf9\u9f50",right:"\u9760\u53f3\u5bf9\u9f50",center:"\u5c45\u4e2d\u5bf9\u9f50",left:"\u9760\u5de6\u5bf9\u9f50",align:"\u5bf9\u9f50\u65b9\u5f0f"},insertdatetime:{day_short:"\u5468\u65e5,\u5468\u4e00,\u5468\u4e8c,\u5468\u4e09,\u5468\u56db,\u5468\u4e94,\u5468\u516d,\u5468\u65e5",day_long:"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u4e09,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5",months_short:"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708",months_long:"\u4e00\u6708,\u4e8c\u6708,\u4e09\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708",inserttime_desc:"\u63d2\u5165\u73b0\u5728\u65f6\u95f4",insertdate_desc:"\u63d2\u5165\u4eca\u5929\u65e5\u671f",time_fmt:"%H:%M:%S",date_fmt:"%Y-%m-%d"},print:{print_desc:"\u5217\u5370"},preview:{preview_desc:"\u9884\u89c8"},directionality:{rtl_desc:"\u6587\u5b57\u4ece\u53f3\u5230\u5de6",ltr_desc:"\u6587\u5b57\u4ece\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u589e\u5c42...",absolute_desc:"\u5f00\u5173\u7edd\u5bf9\u4f4d\u7f6e",backward_desc:"\u7f6e\u540e",forward_desc:"\u7f6e\u524d",insertlayer_desc:"\u63d2\u5165\u5c42"},save:{save_desc:"\u4fdd\u5b58",cancel_desc:"\u53d6\u6d88\u6240\u6709\u66f4\u6539"},nonbreaking:{nonbreaking_desc:"\u63d2\u5165\u7a7a\u767d\u683c"},iespell:{download:"\u672a\u68c0\u6d4b\u5230ieSpell\u7684\u5b58\u5728\u3002\u662f\u5426\u73b0\u5728\u7acb\u5373\u5b89\u88c5\uff1f",iespell_desc:"\u62fc\u5199\u68c0\u67e5"},advhr:{advhr_desc:"\u6c34\u5e73\u7ebf",delta_height:"",delta_width:""},emotions:{emotions_desc:"\u56fe\u91ca",delta_height:"",delta_width:""},searchreplace:{replace_desc:"\u67e5\u627e/\u66ff\u6362",search_desc:"\u67e5\u627e",delta_width:"",delta_height:""},advimage:{image_desc:"\u63d2\u5165/\u7f16\u8f91\u56fe\u7247",delta_width:"",delta_height:""},advlink:{link_desc:"\u63d2\u5165/\u7f16\u8f91\u8fde\u7ed3",delta_height:"",delta_width:""},xhtmlxtras:{attribs_delta_height:"60",attribs_delta_width:"40",attribs_desc:"\u63d2\u5165/\u7f16\u8f91\u5c5e\u6027",ins_desc:"\u63d2\u5165",del_desc:"\u5220\u9664",acronym_desc:"\u9996\u5b57\u7f29\u5199",abbr_desc:"\u7f29\u5199",cite_desc:"\u5f15\u6587",ins_delta_height:"",ins_delta_width:"",del_delta_height:"",del_delta_width:"",acronym_delta_height:"",acronym_delta_width:"",abbr_delta_height:"",abbr_delta_width:"",cite_delta_height:"",cite_delta_width:""},style:{desc:"\u7f16\u8f91CSS\u6837\u5f0f\u8868",delta_height:"",delta_width:""},paste:{selectall_desc:"\u5168\u9009",paste_word_desc:"\u4eceWord\u8d34\u4e0a",paste_text_desc:"\u4ee5\u7eaf\u6587\u5b57\u8d34\u4e0a",plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode.",plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode."},paste_dlg:{word_title:"\u5728\u952e\u76d8\u4e0a\u540c\u65f6\u6309\u4e0bCTRL\u548cV\u952e\uff0c\u4ee5\u8d34\u4e0a\u6587\u5b57\u5230\u6b64\u89c6\u7a97\u3002",text_linebreaks:"\u4fdd\u7559\u5206\u884c\u7b26\u53f7\u53f7",text_title:"\u5728\u952e\u76d8\u4e0a\u540c\u65f6\u6309\u4e0bCTRL\u548cV\u952e\uff0c\u4ee5\u8d34\u4e0a\u6587\u5b57\u5230\u6b64\u89c6\u7a97\u3002"},table:{merge_cells_delta_height:"40",merge_cells_delta_width:"40",table_delta_height:"60",table_delta_width:"40",cellprops_delta_height:"10",cellprops_delta_width:"10",cell:"\u50a8\u5b58\u683c",col:"\u5217",row:"\u884c",del:"\u5220\u9664\u8868\u683c",copy_row_desc:"\u590d\u5236\u9009\u62e9\u884c",cut_row_desc:"\u526a\u4e0b\u9009\u62e9\u884c",paste_row_after_desc:"\u8d34\u5728\u4e0b\u884c",paste_row_before_desc:"\u8d34\u5728\u4e0a\u884c",props_desc:"\u8868\u683c\u5c5e\u6027",cell_desc:"\u50a8\u5b58\u683c\u5c5e\u6027",row_desc:"\u884c\u5c5e\u6027",merge_cells_desc:"\u5408\u5e76\u50a8\u5b58\u683c",split_cells_desc:"\u5206\u5272\u50a8\u5b58\u683c",delete_col_desc:"\u5220\u9664\u6240\u5728\u5217",col_after_desc:"\u63d2\u5165\u53f3\u65b9\u5217",col_before_desc:"\u63d2\u5165\u5de6\u65b9\u5217",delete_row_desc:"\u5220\u9664\u6240\u5728\u884c",row_after_desc:"\u63d2\u5165\u4e0b\u65b9\u884c",row_before_desc:"\u63d2\u5165\u4e0a\u65b9\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c",rowprops_delta_height:"",rowprops_delta_width:""},autosave:{unload_msg:"\u5982\u679c\u79bb\u5f00\u6b64\u9875\u9762\u5c06\u5bfc\u81f4\u6240\u505a\u7684\u66f4\u6539\u5168\u90e8\u4e22\u5931\u3002",warning_message:"If you restore the saved content, you will lose all the content that is currently in the editor.\\n\\nAre you sure you want to restore the saved content?.",restore_content:"Restore auto-saved content."},fullscreen:{desc:"\u5f00\u5173\u5168\u5c4f\u6a21\u5f0f"},media:{edit:"\u7f16\u8f91\u5d4c\u5165\u5a92\u4f53",desc:"\u63d2\u5165/\u7f16\u8f91\u5d4c\u5165\u5a92\u4f53",delta_height:"",delta_width:""},fullpage:{desc:"\u6863\u6848\u5c5e\u6027",delta_width:"",delta_height:""},template:{desc:"\u63d2\u5165\u9884\u5b9a\u7684\u8303\u672c\u5185\u5bb9"},visualchars:{desc:"\u663e\u793a\u63a7\u5236\u7b26\u53f7\u5f00/\u5173\u3002"},spellchecker:{desc:"\u5f00\u5173\u62fc\u5199\u68c0\u67e5",menu:"\u62fc\u5199\u68c0\u67e5\u8bbe\u7f6e",ignore_word:"\u7565\u8fc7",ignore_words:"\u5168\u90e8\u7565\u8fc7",langs:"\u8bed\u8a00",wait:"\u8bf7\u7a0d\u5019...",sug:"\u63a8\u8350\u5b57\u8bcd",no_sug:"\u65e0\u62fc\u5199\u63a8\u8350",no_mpell:"\u672a\u53d1\u73b0\u62fc\u5199\u9519\u8bef"},pagebreak:{desc:"\u63d2\u5165\u5206\u9875\u7b26\u53f7"},advlist:{types:"Types",def:"Default",lower_alpha:"Lower alpha",lower_greek:"Lower greek",lower_roman:"Lower roman",upper_alpha:"Upper alpha",upper_roman:"Upper roman",circle:"Circle",disc:"Disc",square:"Square"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/langs/zh-cn.js0000644000175000017500000001623311526350525032131 0ustar frankiefrankietinyMCE.addI18n({"zh-cn":{common:{"more_colors":"\u66f4\u591a\u989c\u8272","invalid_data":"\u9519\u8bef\uff1a\u6807\u8bb0\u4e3a\u7ea2\u8272\u7684\u90e8\u5206\u6709\u8bef\u3002","popup_blocked":"\u62b1\u6b49\uff0c\u60a8\u7981\u7528\u4e86\u5f39\u51fa\u7a97\u53e3\u529f\u80fd\u3002\u4e3a\u4e86\u4f7f\u7528\u8be5\u5de5\u5177\u7684\u5168\u90e8\u529f\u80fd\uff0c\u60a8\u9700\u8981\u5141\u8bb8\u5f39\u51fa\u7a97\u53e3\u3002","clipboard_no_support":"\u60a8\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\uff0c\u4f7f\u7528\u5feb\u6377\u952e\u4ee3\u66ff\u3002","clipboard_msg":"\u5728Mozilla\u548cFirefox\u4e2d\u4e0d\u80fd\u4f7f\u7528\u590d\u5236/\u7c98\u8d34/\u526a\u5207\u3002\u60a8\u8981\u67e5\u770b\u8be5\u95ee\u9898\u66f4\u591a\u7684\u4fe1\u606f\u5417\uff1f","not_set":"-- \u672a\u8bbe\u7f6e --","class_name":"\u7c7b\u522b",browse:"\u6d4f\u89c8",close:"\u5173\u95ed",cancel:"\u53d6\u6d88",update:"\u66f4\u65b0",insert:"\u63d2\u5165",apply:"\u5e94\u7528","edit_confirm":"\u8be5\u6587\u672c\u57df\u662f\u5426\u9700\u8981\u4f7f\u7528\u6240\u89c1\u5373\u6240\u5f97\u6a21\u5f0f\uff1f"},contextmenu:{full:"\u4e24\u7aef\u5bf9\u9f50",right:"\u53f3\u5bf9\u9f50",center:"\u5c45\u4e2d",left:"\u5de6\u5bf9\u9f50",align:"\u5bf9\u9f50"},insertdatetime:{"day_short":"\u5468\u65e5,\u5468\u4e00,\u5468\u4e8c,\u5468\u4e09,\u5468\u56db,\u5468\u4e94,\u5468\u516d,\u5468\u65e5","day_long":"\u661f\u671f\u65e5,\u661f\u671f\u4e00,\u661f\u671f\u4e8c,\u661f\u671f\u4e09,\u661f\u671f\u56db,\u661f\u671f\u4e94,\u661f\u671f\u516d,\u661f\u671f\u65e5","months_short":"1\u6708,2\u6708,3\u6708,4\u6708,5\u6708,6\u6708,7\u6708,8\u6708,9\u6708,10\u6708,11\u6708,12\u6708","months_long":"\u4e00\u6708,\u4e8c\u6708,\u4e09\u6708,\u56db\u6708,\u4e94\u6708,\u516d\u6708,\u4e03\u6708,\u516b\u6708,\u4e5d\u6708,\u5341\u6708,\u5341\u4e00\u6708,\u5341\u4e8c\u6708","inserttime_desc":"\u63d2\u5165\u65f6\u95f4","insertdate_desc":"\u63d2\u5165\u65e5\u671f","time_fmt":"%H:%M:%S","date_fmt":"%Y-%m-%d"},print:{"print_desc":"\u6253\u5370"},preview:{"preview_desc":"\u9884\u89c8"},directionality:{"rtl_desc":"\u6587\u5b57\u65b9\u5411\u4e3a\u4ece\u53f3\u5230\u5de6","ltr_desc":"\u6587\u5b57\u65b9\u5411\u4e3a\u4ece\u5de6\u5230\u53f3"},layer:{content:"\u65b0\u5efa\u5c42...","absolute_desc":"\u5207\u6362\u5230\u7edd\u5bf9\u4f4d\u7f6e","backward_desc":"\u7f6e\u540e","forward_desc":"\u7f6e\u524d","insertlayer_desc":"\u63d2\u5165\u65b0\u5c42"},save:{"save_desc":"\u4fdd\u5b58","cancel_desc":"\u53d6\u6d88\u6240\u6709\u66f4\u6539"},nonbreaking:{"nonbreaking_desc":"\u63d2\u5165\u4e0d\u95f4\u65ad\u7a7a\u683c\u7b26"},iespell:{download:"\u62fc\u5199\u68c0\u67e5\u672a\u5b89\u88c5\uff0c\u662f\u5426\u9a6c\u4e0a\u5b89\u88c5\uff1f","iespell_desc":"\u62fc\u5199\u68c0\u67e5"},advhr:{"delta_height":"\u9ad8\u5ea6","delta_width":"\u5bbd\u5ea6","advhr_desc":"\u6c34\u5e73\u7ebf"},emotions:{"emotions_desc":"\u8868\u60c5","delta_height":"","delta_width":""},searchreplace:{"replace_desc":"\u67e5\u627e/\u66ff\u6362","search_desc":"\u67e5\u627e","delta_width":"","delta_height":""},advimage:{"image_desc":"\u63d2\u5165/\u7f16\u8f91 \u56fe\u7247","delta_width":"","delta_height":""},advlink:{"link_desc":"\u63d2\u5165/\u7f16\u8f91 \u8d85\u94fe\u63a5","delta_height":"","delta_width":""},xhtmlxtras:{"attribs_desc":"\u63d2\u5165/\u7f16\u8f91\u5c5e\u6027","ins_desc":"\u63d2\u5165","del_desc":"\u5220\u9664","acronym_desc":"\u9996\u5b57\u6bcd\u7f29\u5199","abbr_desc":"\u7f29\u5199","cite_desc":"\u5f15\u7528","attribs_delta_height":"","attribs_delta_width":"","ins_delta_height":"","ins_delta_width":"","del_delta_height":"","del_delta_width":"","acronym_delta_height":"","acronym_delta_width":"","abbr_delta_height":"","abbr_delta_width":"","cite_delta_height":"","cite_delta_width":""},style:{desc:"\u7f16\u8f91CSS\u6837\u5f0f","delta_height":"","delta_width":""},paste:{"plaintext_mode":"\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u6a21\u5f0f\u7c98\u8d34\uff0c\u518d\u6b21\u70b9\u51fb\u8fd4\u56de\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002","plaintext_mode_sticky":"\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u6a21\u5f0f\u7c98\u8d34\u3002\u518d\u6b21\u70b9\u51fb\u8fd4\u56de\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\uff0c\u5728\u60a8\u7c98\u8d34\u5185\u5bb9\u540e\u5c06\u8fd4\u56de\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002","selectall_desc":"\u5168\u9009","paste_word_desc":"\u4eceWord\u7c98\u8d34","paste_text_desc":"\u4ee5\u7eaf\u6587\u672c\u7c98\u8d34"},"paste_dlg":{"word_title":"\u4f7f\u7528CTRL V\u7c98\u8d34\u6587\u672c\u5230\u7a97\u53e3\u4e2d\u3002","text_linebreaks":"\u4fdd\u7559\u65ad\u884c","text_title":"\u4f7f\u7528CTRL V\u7c98\u8d34\u6587\u672c\u5230\u7a97\u53e3\u4e2d\u3002"},table:{cell:"\u5355\u5143\u683c",col:"\u5217",row:"\u884c",del:"\u5220\u9664\u8868\u683c","copy_row_desc":"\u590d\u5236\u884c","cut_row_desc":"\u526a\u5207\u884c","paste_row_after_desc":"\u5728\u4e0b\u65b9\u7c98\u8d34\u884c","paste_row_before_desc":"\u5728\u4e0a\u65b9\u7c98\u8d34\u884c","props_desc":"\u8868\u683c\u5c5e\u6027","cell_desc":"\u5355\u5143\u683c\u5c5e\u6027","row_desc":"\u884c\u5c5e\u6027","merge_cells_desc":"\u5408\u5e76\u5355\u5143\u683c","split_cells_desc":"\u5206\u5272\u5355\u5143\u683c","delete_col_desc":"\u5220\u9664\u5217","col_after_desc":"\u5728\u53f3\u4fa7\u63d2\u5165\u5217","col_before_desc":"\u5728\u5de6\u4fa7\u63d2\u5165\u5217","delete_row_desc":"\u5220\u9664\u884c","row_after_desc":"\u5728\u4e0b\u65b9\u63d2\u5165\u884c","row_before_desc":"\u5728\u4e0a\u65b9\u63d2\u5165\u884c",desc:"\u63d2\u5165\u65b0\u8868\u683c","merge_cells_delta_height":"","merge_cells_delta_width":"","table_delta_height":"","table_delta_width":"","cellprops_delta_height":"","cellprops_delta_width":"","rowprops_delta_height":"","rowprops_delta_width":""},autosave:{"warning_message":"\u5982\u679c\u6062\u590d\u4fdd\u5b58\u7684\u5185\u5bb9\uff0c\u60a8\u5f53\u524d\u7f16\u8f91\u7684\u6240\u6709\u7684\u5185\u5bb9\u5c06\u4e22\u5931\u3002nn\u60a8\u786e\u5b9a\u8981\u6062\u590d\u4fdd\u5b58\u7684\u5185\u5bb9\u5417\uff1f","restore_content":"\u6062\u590d\u81ea\u52a8\u4fdd\u5b58\u7684\u5185\u5bb9\u3002","unload_msg":"\u5982\u679c\u9000\u51fa\u8be5\u9875\uff0c\u60a8\u6240\u505a\u7684\u66f4\u6539\u5c06\u4e22\u5931\u3002"},fullscreen:{desc:"\u5207\u6362\u5168\u5c4f\u6a21\u5f0f"},media:{edit:"\u7f16\u8f91\u5d4c\u5165\u5f0f\u5a92\u4f53",desc:"\u63d2\u5165/\u7f16\u8f91 \u5d4c\u5165\u5f0f\u5a92\u4f53","delta_height":"","delta_width":""},fullpage:{desc:"\u6587\u4ef6\u5c5e\u6027","delta_width":"\u5bbd\u5ea6","delta_height":"\u9ad8\u5ea6"},template:{desc:"\u63d2\u5165\u9884\u8bbe\u7684\u6a21\u677f\u5185\u5bb9"},visualchars:{desc:"\u663e\u793a/\u9690\u85cf \u975e\u53ef\u89c1\u5b57\u7b26"},spellchecker:{desc:"\u62fc\u5199\u68c0\u67e5",menu:"\u62fc\u5199\u68c0\u67e5\u8bbe\u7f6e","ignore_word":"\u5ffd\u7565","ignore_words":"\u5168\u90e8\u5ffd\u7565",langs:"\u8bed\u8a00",wait:"\u8bf7\u7a0d\u5019...",sug:"\u5efa\u8bae","no_sug":"\u65e0\u5efa\u8bae","no_mpell":"\u65e0\u62fc\u5199\u9519\u8bef\u3002"},pagebreak:{desc:"\u63d2\u5165\u5206\u9875\u7b26\u3002"},advlist:{types:"\u6837\u5f0f",def:"\u9ed8\u8ba4","lower_alpha":"\u5c0f\u5199\u5b57\u6bcd","lower_greek":"\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd","lower_roman":"\u5c0f\u5199\u7f57\u9a6c\u6570\u5b57","upper_alpha":"\u5927\u5199\u5b57\u6bcd","upper_roman":"\u5927\u5199\u7f57\u9a6c\u6570\u5b57",circle:"\u5706\u5708",disc:"\u5706\u70b9",square:"\u65b9\u5757"}}});openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/utils/0000755000175000017500000000000011575225665030615 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/utils/form_utils.js0000644000175000017500000001254511201066423033322 0ustar frankiefrankie/** * $Id: form_utils.js,v 1.2 2009/05/08 17:34:11 daveb Exp $ * * Various form utilitiy functions. * * @author Moxiecode * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. */ var themeBaseURL = tinyMCEPopup.editor.baseURI.toAbsolute('themes/' + tinyMCEPopup.getParam("theme")); function getColorPickerHTML(id, target_form_element) { var h = ""; h += ''; h += ' '; return h; } function updateColor(img_id, form_element_id) { document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value; } function setBrowserDisabled(id, state) { var img = document.getElementById(id); var lnk = document.getElementById(id + "_link"); if (lnk) { if (state) { lnk.setAttribute("realhref", lnk.getAttribute("href")); lnk.removeAttribute("href"); tinyMCEPopup.dom.addClass(img, 'disabled'); } else { if (lnk.getAttribute("realhref")) lnk.setAttribute("href", lnk.getAttribute("realhref")); tinyMCEPopup.dom.removeClass(img, 'disabled'); } } } function getBrowserHTML(id, target_form_element, type, prefix) { var option = prefix + "_" + type + "_browser_callback", cb, html; cb = tinyMCEPopup.getParam(option, tinyMCEPopup.getParam("file_browser_callback")); if (!cb) return ""; html = ""; html += ''; html += ' '; return html; } function openBrowser(img_id, target_form_element, type, option) { var img = document.getElementById(img_id); if (img.className != "mceButtonDisabled") tinyMCEPopup.openBrowser(target_form_element, type, option); } function selectByValue(form_obj, field_name, value, add_custom, ignore_case) { if (!form_obj || !form_obj.elements[field_name]) return; var sel = form_obj.elements[field_name]; var found = false; for (var i=0; i x && mx < x + w && my > y && my < y + h)) { MCLayer.visibleLayer = null; if (l.autoHideCallback && l.autoHideCallback(l, e, mx, my)) return true; l.hide(); } } }, addCSSClass : function(e, c) { this.removeCSSClass(e, c); var a = this.explode(' ', e.className); a[a.length] = c; e.className = a.join(' '); }, removeCSSClass : function(e, c) { var a = this.explode(' ', e.className), i; for (i=0; i parseInt(v)) st = this.mark(f, n); } } return st; }, hasClass : function(n, c, d) { return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className); }, getNum : function(n, c) { c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0]; c = c.replace(/[^0-9]/g, ''); return c; }, addClass : function(n, c, b) { var o = this.removeClass(n, c); n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c; }, removeClass : function(n, c) { c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' '); return n.className = c != ' ' ? c : ''; }, tags : function(f, s) { return f.getElementsByTagName(s); }, mark : function(f, n) { var s = this.settings; this.addClass(n, s.invalid_cls); this.markLabels(f, n, s.invalid_cls); return false; }, markLabels : function(f, n, ic) { var nl, i; nl = this.tags(f, "label"); for (i=0; i : s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s); cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name // Create namespace for new class ns = t.createNS(s[3].replace(/\.\w+$/, '')); // Class already exists if (ns[cn]) return; // Make pure static class if (s[2] == 'static') { ns[cn] = p; if (this.onCreate) this.onCreate(s[2], s[3], ns[cn]); return; } // Create default constructor if (!p[cn]) { p[cn] = function() {}; de = 1; } // Add constructor and methods ns[cn] = p[cn]; t.extend(ns[cn].prototype, p); // Extend if (s[5]) { sp = t.resolve(s[5]).prototype; scn = s[5].match(/\.(\w+)$/i)[1]; // Class name // Extend constructor c = ns[cn]; if (de) { // Add passthrough constructor ns[cn] = function() { return sp[scn].apply(this, arguments); }; } else { // Add inherit constructor ns[cn] = function() { this.parent = sp[scn]; return c.apply(this, arguments); }; } ns[cn].prototype[cn] = ns[cn]; // Add super methods t.each(sp, function(f, n) { ns[cn].prototype[n] = sp[n]; }); // Add overridden methods t.each(p, function(f, n) { // Extend methods if needed if (sp[n]) { ns[cn].prototype[n] = function() { this.parent = sp[n]; return f.apply(this, arguments); }; } else { if (n != cn) ns[cn].prototype[n] = f; } }); } // Add static methods t.each(p['static'], function(f, n) { ns[cn][n] = f; }); if (this.onCreate) this.onCreate(s[2], s[3], ns[cn].prototype); }, walk : function(o, f, n, s) { s = s || this; if (o) { if (n) o = o[n]; tinymce.each(o, function(o, i) { if (f.call(s, o, i, n) === false) return false; tinymce.walk(o, f, n, s); }); } }, createNS : function(n, o) { var i, v; o = o || win; n = n.split('.'); for (i=0; i= items.length) { for (i = 0, l = base.length; i < l; i++) { if (i >= items.length || base[i] != items[i]) { bp = i + 1; break; } } } if (base.length < items.length) { for (i = 0, l = items.length; i < l; i++) { if (i >= base.length || base[i] != items[i]) { bp = i + 1; break; } } } if (bp == 1) return path; for (i = 0, l = base.length - (bp - 1); i < l; i++) out += "../"; for (i = bp - 1, l = items.length; i < l; i++) { if (i != bp - 1) out += "/" + items[i]; else out += items[i]; } return out; }, toAbsPath : function(base, path) { var i, nb = 0, o = [], tr, outPath; // Split paths tr = /\/$/.test(path) ? '/' : ''; base = base.split('/'); path = path.split('/'); // Remove empty chunks each(base, function(k) { if (k) o.push(k); }); base = o; // Merge relURLParts chunks for (i = path.length - 1, o = []; i >= 0; i--) { // Ignore empty or . if (path[i].length == 0 || path[i] == ".") continue; // Is parent if (path[i] == '..') { nb++; continue; } // Move up if (nb > 0) { nb--; continue; } o.push(path[i]); } i = base.length - nb; // If /a/b/c or / if (i <= 0) outPath = o.reverse().join('/'); else outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/'); // Add front / if it's needed if (outPath.indexOf('/') !== 0) outPath = '/' + outPath; // Add traling / if it's needed if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) outPath += tr; return outPath; }, getURI : function(nh) { var s, t = this; // Rebuild source if (!t.source || nh) { s = ''; if (!nh) { if (t.protocol) s += t.protocol + '://'; if (t.userInfo) s += t.userInfo + '@'; if (t.host) s += t.host; if (t.port) s += ':' + t.port; } if (t.path) s += t.path; if (t.query) s += '?' + t.query; if (t.anchor) s += '#' + t.anchor; t.source = s; } return t.source; } }); })(); (function() { var each = tinymce.each; tinymce.create('static tinymce.util.Cookie', { getHash : function(n) { var v = this.get(n), h; if (v) { each(v.split('&'), function(v) { v = v.split('='); h = h || {}; h[unescape(v[0])] = unescape(v[1]); }); } return h; }, setHash : function(n, v, e, p, d, s) { var o = ''; each(v, function(v, k) { o += (!o ? '' : '&') + escape(k) + '=' + escape(v); }); this.set(n, o, e, p, d, s); }, get : function(n) { var c = document.cookie, e, p = n + "=", b; // Strict mode if (!c) return; b = c.indexOf("; " + p); if (b == -1) { b = c.indexOf(p); if (b != 0) return null; } else b += 2; e = c.indexOf(";", b); if (e == -1) e = c.length; return unescape(c.substring(b + p.length, e)); }, set : function(n, v, e, p, d, s) { document.cookie = n + "=" + escape(v) + ((e) ? "; expires=" + e.toGMTString() : "") + ((p) ? "; path=" + escape(p) : "") + ((d) ? "; domain=" + d : "") + ((s) ? "; secure" : ""); }, remove : function(n, p) { var d = new Date(); d.setTime(d.getTime() - 1000); this.set(n, '', d, p, d); } }); })(); tinymce.create('static tinymce.util.JSON', { serialize : function(o) { var i, v, s = tinymce.util.JSON.serialize, t; if (o == null) return 'null'; t = typeof o; if (t == 'string') { v = '\bb\tt\nn\ff\rr\""\'\'\\\\'; return '"' + o.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g, function(a, b) { i = v.indexOf(b); if (i + 1) return '\\' + v.charAt(i + 1); a = b.charCodeAt().toString(16); return '\\u' + '0000'.substring(a.length) + a; }) + '"'; } if (t == 'object') { if (o.hasOwnProperty && o instanceof Array) { for (i=0, v = '['; i 0 ? ',' : '') + s(o[i]); return v + ']'; } v = '{'; for (i in o) v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : ''; return v + '}'; } return '' + o; }, parse : function(s) { try { return eval('(' + s + ')'); } catch (ex) { // Ignore } } }); tinymce.create('static tinymce.util.XHR', { send : function(o) { var x, t, w = window, c = 0; // Default settings o.scope = o.scope || this; o.success_scope = o.success_scope || o.scope; o.error_scope = o.error_scope || o.scope; o.async = o.async === false ? false : true; o.data = o.data || ''; function get(s) { x = 0; try { x = new ActiveXObject(s); } catch (ex) { } return x; }; x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP'); if (x) { if (x.overrideMimeType) x.overrideMimeType(o.content_type); x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async); if (o.content_type) x.setRequestHeader('Content-Type', o.content_type); x.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); x.send(o.data); function ready() { if (!o.async || x.readyState == 4 || c++ > 10000) { if (o.success && c < 10000 && x.status == 200) o.success.call(o.success_scope, '' + x.responseText, x, o); else if (o.error) o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o); x = null; } else w.setTimeout(ready, 10); }; // Syncronous request if (!o.async) return ready(); // Wait for response, onReadyStateChange can not be used since it leaks memory in IE t = w.setTimeout(ready, 10); } } }); (function() { var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR; tinymce.create('tinymce.util.JSONRequest', { JSONRequest : function(s) { this.settings = extend({ }, s); this.count = 0; }, send : function(o) { var ecb = o.error, scb = o.success; o = extend(this.settings, o); o.success = function(c, x) { c = JSON.parse(c); if (typeof(c) == 'undefined') { c = { error : 'JSON Parse error.' }; } if (c.error) ecb.call(o.error_scope || o.scope, c.error, x); else scb.call(o.success_scope || o.scope, c.result); }; o.error = function(ty, x) { ecb.call(o.error_scope || o.scope, ty, x); }; o.data = JSON.serialize({ id : o.id || 'c' + (this.count++), method : o.method, params : o.params }); // JSON content type for Ruby on rails. Bug: #1883287 o.content_type = 'application/json'; XHR.send(o); }, 'static' : { sendRPC : function(o) { return new tinymce.util.JSONRequest().send(o); } } }); }()); (function(tinymce) { // Shorten names var each = tinymce.each, is = tinymce.is, isWebKit = tinymce.isWebKit, isIE = tinymce.isIE, blockRe = /^(H[1-6R]|P|DIV|ADDRESS|PRE|FORM|T(ABLE|BODY|HEAD|FOOT|H|R|D)|LI|OL|UL|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|MENU|ISINDEX|SAMP)$/, boolAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'), mceAttribs = makeMap('src,href,style,coords,shape'), encodedChars = {'&' : '&', '"' : '"', '<' : '<', '>' : '>'}, encodeCharsRe = /[<>&\"]/g, simpleSelectorRe = /^([a-z0-9],?)+$/i, tagRegExp = /<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)(\s*\/?)>/g, attrRegExp = /(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; function makeMap(str) { var map = {}, i; str = str.split(','); for (i = str.length; i >= 0; i--) map[str[i]] = 1; return map; }; tinymce.create('tinymce.dom.DOMUtils', { doc : null, root : null, files : null, pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/, props : { "for" : "htmlFor", "class" : "className", className : "className", checked : "checked", disabled : "disabled", maxlength : "maxLength", readonly : "readOnly", selected : "selected", value : "value", id : "id", name : "name", type : "type" }, DOMUtils : function(d, s) { var t = this, globalStyle; t.doc = d; t.win = window; t.files = {}; t.cssFlicker = false; t.counter = 0; t.stdMode = d.documentMode >= 8; t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat" || t.stdMode; t.settings = s = tinymce.extend({ keep_values : false, hex_colors : 1, process_html : 1 }, s); // Fix IE6SP2 flicker and check it failed for pre SP2 if (tinymce.isIE6) { try { d.execCommand('BackgroundImageCache', false, true); } catch (e) { t.cssFlicker = true; } } // Build styles list if (s.valid_styles) { t._styles = {}; // Convert styles into a rule list each(s.valid_styles, function(value, key) { t._styles[key] = tinymce.explode(value); }); } tinymce.addUnload(t.destroy, t); }, getRoot : function() { var t = this, s = t.settings; return (s && t.get(s.root_element)) || t.doc.body; }, getViewPort : function(w) { var d, b; w = !w ? this.win : w; d = w.document; b = this.boxModel ? d.documentElement : d.body; // Returns viewport size excluding scrollbars return { x : w.pageXOffset || b.scrollLeft, y : w.pageYOffset || b.scrollTop, w : w.innerWidth || b.clientWidth, h : w.innerHeight || b.clientHeight }; }, getRect : function(e) { var p, t = this, sr; e = t.get(e); p = t.getPos(e); sr = t.getSize(e); return { x : p.x, y : p.y, w : sr.w, h : sr.h }; }, getSize : function(e) { var t = this, w, h; e = t.get(e); w = t.getStyle(e, 'width'); h = t.getStyle(e, 'height'); // Non pixel value, then force offset/clientWidth if (w.indexOf('px') === -1) w = 0; // Non pixel value, then force offset/clientWidth if (h.indexOf('px') === -1) h = 0; return { w : parseInt(w) || e.offsetWidth || e.clientWidth, h : parseInt(h) || e.offsetHeight || e.clientHeight }; }, getParent : function(n, f, r) { return this.getParents(n, f, r, false); }, getParents : function(n, f, r, c) { var t = this, na, se = t.settings, o = []; n = t.get(n); c = c === undefined; if (se.strict_root) r = r || t.getRoot(); // Wrap node name as func if (is(f, 'string')) { na = f; if (f === '*') { f = function(n) {return n.nodeType == 1;}; } else { f = function(n) { return t.is(n, na); }; } } while (n) { if (n == r || !n.nodeType || n.nodeType === 9) break; if (!f || f(n)) { if (c) o.push(n); else return n; } n = n.parentNode; } return c ? o : null; }, get : function(e) { var n; if (e && this.doc && typeof(e) == 'string') { n = e; e = this.doc.getElementById(e); // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick if (e && e.id !== n) return this.doc.getElementsByName(n)[1]; } return e; }, getNext : function(node, selector) { return this._findSib(node, selector, 'nextSibling'); }, getPrev : function(node, selector) { return this._findSib(node, selector, 'previousSibling'); }, select : function(pa, s) { var t = this; return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []); }, is : function(n, selector) { var i; // If it isn't an array then try to do some simple selectors instead of Sizzle for to boost performance if (n.length === undefined) { // Simple all selector if (selector === '*') return n.nodeType == 1; // Simple selector just elements if (simpleSelectorRe.test(selector)) { selector = selector.toLowerCase().split(/,/); n = n.nodeName.toLowerCase(); for (i = selector.length - 1; i >= 0; i--) { if (selector[i] == n) return true; } return false; } } return tinymce.dom.Sizzle.matches(selector, n.nodeType ? [n] : n).length > 0; }, add : function(p, n, a, h, c) { var t = this; return this.run(p, function(p) { var e, k; e = is(n, 'string') ? t.doc.createElement(n) : n; t.setAttribs(e, a); if (h) { if (h.nodeType) e.appendChild(h); else t.setHTML(e, h); } return !c ? p.appendChild(e) : e; }); }, create : function(n, a, h) { return this.add(this.doc.createElement(n), n, a, h, 1); }, createHTML : function(n, a, h) { var o = '', t = this, k; o += '<' + n; for (k in a) { if (a.hasOwnProperty(k)) o += ' ' + k + '="' + t.encode(a[k]) + '"'; } // A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime if (typeof(h) != "undefined") return o + '>' + h + ''; return o + ' />'; }, remove : function(node, keep_children) { return this.run(node, function(node) { var parent, child; parent = node.parentNode; if (!parent) return null; if (keep_children) { while (child = node.firstChild) { // IE 8 will crash if you don't remove completely empty text nodes if (!tinymce.isIE || child.nodeType !== 3 || child.nodeValue) parent.insertBefore(child, node); else node.removeChild(child); } } return parent.removeChild(node); }); }, setStyle : function(n, na, v) { var t = this; return t.run(n, function(e) { var s, i; s = e.style; // Camelcase it, if needed na = na.replace(/-(\D)/g, function(a, b){ return b.toUpperCase(); }); // Default px suffix on these if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v))) v += 'px'; switch (na) { case 'opacity': // IE specific opacity if (isIE) { s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")"; if (!n.currentStyle || !n.currentStyle.hasLayout) s.display = 'inline-block'; } // Fix for older browsers s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || ''; break; case 'float': isIE ? s.styleFloat = v : s.cssFloat = v; break; default: s[na] = v || ''; } // Force update of the style data if (t.settings.update_styles) t.setAttrib(e, '_mce_style'); }); }, getStyle : function(n, na, c) { n = this.get(n); if (!n) return false; // Gecko if (this.doc.defaultView && c) { // Remove camelcase na = na.replace(/[A-Z]/g, function(a){ return '-' + a; }); try { return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na); } catch (ex) { // Old safari might fail return null; } } // Camelcase it, if needed na = na.replace(/-(\D)/g, function(a, b){ return b.toUpperCase(); }); if (na == 'float') na = isIE ? 'styleFloat' : 'cssFloat'; // IE & Opera if (n.currentStyle && c) return n.currentStyle[na]; return n.style[na]; }, setStyles : function(e, o) { var t = this, s = t.settings, ol; ol = s.update_styles; s.update_styles = 0; each(o, function(v, n) { t.setStyle(e, n, v); }); // Update style info s.update_styles = ol; if (s.update_styles) t.setAttrib(e, s.cssText); }, setAttrib : function(e, n, v) { var t = this; // Whats the point if (!e || !n) return; // Strict XML mode if (t.settings.strict) n = n.toLowerCase(); return this.run(e, function(e) { var s = t.settings; switch (n) { case "style": if (!is(v, 'string')) { each(v, function(v, n) { t.setStyle(e, n, v); }); return; } // No mce_style for elements with these since they might get resized by the user if (s.keep_values) { if (v && !t._isRes(v)) e.setAttribute('_mce_style', v, 2); else e.removeAttribute('_mce_style', 2); } e.style.cssText = v; break; case "class": e.className = v || ''; // Fix IE null bug break; case "src": case "href": if (s.keep_values) { if (s.url_converter) v = s.url_converter.call(s.url_converter_scope || t, v, n, e); t.setAttrib(e, '_mce_' + n, v, 2); } break; case "shape": e.setAttribute('_mce_style', v); break; } if (is(v) && v !== null && v.length !== 0) e.setAttribute(n, '' + v, 2); else e.removeAttribute(n, 2); }); }, setAttribs : function(e, o) { var t = this; return this.run(e, function(e) { each(o, function(v, n) { t.setAttrib(e, n, v); }); }); }, getAttrib : function(e, n, dv) { var v, t = this; e = t.get(e); if (!e || e.nodeType !== 1) return false; if (!is(dv)) dv = ''; // Try the mce variant for these if (/^(src|href|style|coords|shape)$/.test(n)) { v = e.getAttribute("_mce_" + n); if (v) return v; } if (isIE && t.props[n]) { v = e[t.props[n]]; v = v && v.nodeValue ? v.nodeValue : v; } if (!v) v = e.getAttribute(n, 2); // Check boolean attribs if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(n)) { if (e[t.props[n]] === true && v === '') return n; return v ? n : ''; } // Inner input elements will override attributes on form elements if (e.nodeName === "FORM" && e.getAttributeNode(n)) return e.getAttributeNode(n).nodeValue; if (n === 'style') { v = v || e.style.cssText; if (v) { v = t.serializeStyle(t.parseStyle(v), e.nodeName); if (t.settings.keep_values && !t._isRes(v)) e.setAttribute('_mce_style', v); } } // Remove Apple and WebKit stuff if (isWebKit && n === "class" && v) v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, ''); // Handle IE issues if (isIE) { switch (n) { case 'rowspan': case 'colspan': // IE returns 1 as default value if (v === 1) v = ''; break; case 'size': // IE returns +0 as default value for size if (v === '+0' || v === 20 || v === 0) v = ''; break; case 'width': case 'height': case 'vspace': case 'checked': case 'disabled': case 'readonly': if (v === 0) v = ''; break; case 'hspace': // IE returns -1 as default value if (v === -1) v = ''; break; case 'maxlength': case 'tabindex': // IE returns default value if (v === 32768 || v === 2147483647 || v === '32768') v = ''; break; case 'multiple': case 'compact': case 'noshade': case 'nowrap': if (v === 65535) return n; return dv; case 'shape': v = v.toLowerCase(); break; default: // IE has odd anonymous function for event attributes if (n.indexOf('on') === 0 && v) v = tinymce._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1', '' + v); } } return (v !== undefined && v !== null && v !== '') ? '' + v : dv; }, getPos : function(n, ro) { var t = this, x = 0, y = 0, e, d = t.doc, r; n = t.get(n); ro = ro || d.body; if (n) { // Use getBoundingClientRect on IE, Opera has it but it's not perfect if (isIE && !t.stdMode) { n = n.getBoundingClientRect(); e = t.boxModel ? d.documentElement : d.body; x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x; return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x}; } r = n; while (r && r != ro && r.nodeType) { x += r.offsetLeft || 0; y += r.offsetTop || 0; r = r.offsetParent; } r = n.parentNode; while (r && r != ro && r.nodeType) { x -= r.scrollLeft || 0; y -= r.scrollTop || 0; r = r.parentNode; } } return {x : x, y : y}; }, parseStyle : function(st) { var t = this, s = t.settings, o = {}; if (!st) return o; function compress(p, s, ot) { var t, r, b, l; // Get values and check it it needs compressing t = o[p + '-top' + s]; if (!t) return; r = o[p + '-right' + s]; if (t != r) return; b = o[p + '-bottom' + s]; if (r != b) return; l = o[p + '-left' + s]; if (b != l) return; // Compress o[ot] = l; delete o[p + '-top' + s]; delete o[p + '-right' + s]; delete o[p + '-bottom' + s]; delete o[p + '-left' + s]; }; function compress2(ta, a, b, c) { var t; t = o[a]; if (!t) return; t = o[b]; if (!t) return; t = o[c]; if (!t) return; // Compress o[ta] = o[a] + ' ' + o[b] + ' ' + o[c]; delete o[a]; delete o[b]; delete o[c]; }; st = st.replace(/&(#?[a-z0-9]+);/g, '&$1_MCE_SEMI_'); // Protect entities each(st.split(';'), function(v) { var sv, ur = []; if (v) { v = v.replace(/_MCE_SEMI_/g, ';'); // Restore entities v = v.replace(/url\([^\)]+\)/g, function(v) {ur.push(v);return 'url(' + ur.length + ')';}); v = v.split(':'); sv = tinymce.trim(v[1]); sv = sv.replace(/url\(([^\)]+)\)/g, function(a, b) {return ur[parseInt(b) - 1];}); sv = sv.replace(/rgb\([^\)]+\)/g, function(v) { return t.toHex(v); }); if (s.url_converter) { sv = sv.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g, function(x, c) { return 'url(' + s.url_converter.call(s.url_converter_scope || t, t.decode(c), 'style', null) + ')'; }); } o[tinymce.trim(v[0]).toLowerCase()] = sv; } }); compress("border", "", "border"); compress("border", "-width", "border-width"); compress("border", "-color", "border-color"); compress("border", "-style", "border-style"); compress("padding", "", "padding"); compress("margin", "", "margin"); compress2('border', 'border-width', 'border-style', 'border-color'); if (isIE) { // Remove pointless border if (o.border == 'medium none') o.border = ''; } return o; }, serializeStyle : function(o, name) { var t = this, s = ''; function add(v, k) { if (k && v) { // Remove browser specific styles like -moz- or -webkit- if (k.indexOf('-') === 0) return; switch (k) { case 'font-weight': // Opera will output bold as 700 if (v == 700) v = 'bold'; break; case 'color': case 'background-color': v = v.toLowerCase(); break; } s += (s ? ' ' : '') + k + ': ' + v + ';'; } }; // Validate style output if (name && t._styles) { each(t._styles['*'], function(name) { add(o[name], name); }); each(t._styles[name.toLowerCase()], function(name) { add(o[name], name); }); } else each(o, add); return s; }, loadCSS : function(u) { var t = this, d = t.doc, head; if (!u) u = ''; head = t.select('head')[0]; each(u.split(','), function(u) { var link; if (t.files[u]) return; t.files[u] = true; link = t.create('link', {rel : 'stylesheet', href : tinymce._addVer(u)}); // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug // This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading // It's ugly but it seems to work fine. if (isIE && d.documentMode && d.recalc) { link.onload = function() { d.recalc(); link.onload = null; }; } head.appendChild(link); }); }, addClass : function(e, c) { return this.run(e, function(e) { var o; if (!c) return 0; if (this.hasClass(e, c)) return e.className; o = this.removeClass(e, c); return e.className = (o != '' ? (o + ' ') : '') + c; }); }, removeClass : function(e, c) { var t = this, re; return t.run(e, function(e) { var v; if (t.hasClass(e, c)) { if (!re) re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g"); v = e.className.replace(re, ' '); v = tinymce.trim(v != ' ' ? v : ''); e.className = v; // Empty class attr if (!v) { e.removeAttribute('class'); e.removeAttribute('className'); } return v; } return e.className; }); }, hasClass : function(n, c) { n = this.get(n); if (!n || !c) return false; return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1; }, show : function(e) { return this.setStyle(e, 'display', 'block'); }, hide : function(e) { return this.setStyle(e, 'display', 'none'); }, isHidden : function(e) { e = this.get(e); return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none'; }, uniqueId : function(p) { return (!p ? 'mce_' : p) + (this.counter++); }, setHTML : function(e, h) { var t = this; return this.run(e, function(e) { var x, i, nl, n, p, x; h = t.processHTML(h); if (isIE) { function set() { // Remove all child nodes while (e.firstChild) e.firstChild.removeNode(); try { // IE will remove comments from the beginning // unless you padd the contents with something e.innerHTML = '
    ' + h; e.removeChild(e.firstChild); } catch (ex) { // IE sometimes produces an unknown runtime error on innerHTML if it's an block element within a block element for example a div inside a p // This seems to fix this problem // Create new div with HTML contents and a BR infront to keep comments x = t.create('div'); x.innerHTML = '
    ' + h; // Add all children from div to target each (x.childNodes, function(n, i) { // Skip br element if (i) e.appendChild(n); }); } }; // IE has a serious bug when it comes to paragraphs it can produce an invalid // DOM tree if contents like this

    • Item 1

    is inserted // It seems to be that IE doesn't like a root block element placed inside another root block element if (t.settings.fix_ie_paragraphs) h = h.replace(/

    <\/p>|]+)><\/p>|/gi, ' 

    '); set(); if (t.settings.fix_ie_paragraphs) { // Check for odd paragraphs this is a sign of a broken DOM nl = e.getElementsByTagName("p"); for (i = nl.length - 1, x = 0; i >= 0; i--) { n = nl[i]; if (!n.hasChildNodes()) { if (!n._mce_keep) { x = 1; // Is broken break; } n.removeAttribute('_mce_keep'); } } } // Time to fix the madness IE left us if (x) { // So if we replace the p elements with divs and mark them and then replace them back to paragraphs // after we use innerHTML we can fix the DOM tree h = h.replace(/

    ]+)>|

    /ig, '

    '); h = h.replace(/<\/p>/gi, '
    '); // Set the new HTML with DIVs set(); // Replace all DIV elements with the _mce_tmp attibute back to paragraphs // This is needed since IE has a annoying bug see above for details // This is a slow process but it has to be done. :( if (t.settings.fix_ie_paragraphs) { nl = e.getElementsByTagName("DIV"); for (i = nl.length - 1; i >= 0; i--) { n = nl[i]; // Is it a temp div if (n._mce_tmp) { // Create new paragraph p = t.doc.createElement('p'); // Copy all attributes n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi, function(a, b) { var v; if (b !== '_mce_tmp') { v = n.getAttribute(b); if (!v && b === 'class') v = n.className; p.setAttribute(b, v); } }); // Append all children to new paragraph for (x = 0; x]+)\/>|/gi, '', h); // Force open // Store away src and href in _mce_src and mce_href since browsers mess them up if (s.keep_values) { // Wrap scripts and styles in comments for serialization purposes if (/)/g, '\n'); s = s.replace(/^[\r\n]*|[\r\n]*$/g, ''); s = s.replace(/^\s*(\/\/\s*|\]\]>|-->|\]\]-->)\s*$/g, ''); return s; }; // Wrap the script contents in CDATA and keep them from executing h = h.replace(/]+|)>([\s\S]*?)<\/script>/gi, function(v, attribs, text) { // Force type attribute if (!attribs) attribs = ' type="text/javascript"'; // Convert the src attribute of the scripts attribs = attribs.replace(/src=\"([^\"]+)\"?/i, function(a, url) { if (s.url_converter) url = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(url), 'src', 'script')); return '_mce_src="' + url + '"'; }); // Wrap text contents if (tinymce.trim(text)) { codeBlocks.push(trim(text)); text = ''; } return '' + text + ''; }); // Wrap style elements h = h.replace(/]+|)>([\s\S]*?)<\/style>/gi, function(v, attribs, text) { // Wrap text contents if (text) { codeBlocks.push(trim(text)); text = ''; } return '' + text + ''; }); // Wrap noscript elements h = h.replace(/]+|)>([\s\S]*?)<\/noscript>/g, function(v, attribs, text) { return ''; }); } h = tinymce._replace(//g, '', h); // This function processes the attributes in the HTML string to force boolean // attributes to the attr="attr" format and convert style, src and href to _mce_ versions function processTags(html) { return html.replace(tagRegExp, function(match, elm_name, attrs, end) { return '<' + elm_name + attrs.replace(attrRegExp, function(match, name, value, val2, val3) { var mceValue; name = name.toLowerCase(); value = value || val2 || val3 || ""; // Treat boolean attributes if (boolAttrs[name]) { // false or 0 is treated as a missing attribute if (value === 'false' || value === '0') return; return name + '="' + name + '"'; } // Is attribute one that needs special treatment if (mceAttribs[name] && attrs.indexOf('_mce_' + name) == -1) { mceValue = t.decode(value); // Convert URLs to relative/absolute ones if (s.url_converter && (name == "src" || name == "href")) mceValue = s.url_converter.call(s.url_converter_scope || t, mceValue, name, elm_name); // Process styles lowercases them and compresses them if (name == 'style') mceValue = t.serializeStyle(t.parseStyle(mceValue), name); return name + '="' + value + '"' + ' _mce_' + name + '="' + t.encode(mceValue) + '"'; } return match; }) + end + '>'; }); }; h = processTags(h); // Restore script blocks h = h.replace(/MCE_SCRIPT:([0-9]+)/g, function(val, idx) { return codeBlocks[idx]; }); } return h; }, getOuterHTML : function(e) { var d; e = this.get(e); if (!e) return null; if (e.outerHTML !== undefined) return e.outerHTML; d = (e.ownerDocument || this.doc).createElement("body"); d.appendChild(e.cloneNode(true)); return d.innerHTML; }, setOuterHTML : function(e, h, d) { var t = this; function setHTML(e, h, d) { var n, tp; tp = d.createElement("body"); tp.innerHTML = h; n = tp.lastChild; while (n) { t.insertAfter(n.cloneNode(true), e); n = n.previousSibling; } t.remove(e); }; return this.run(e, function(e) { e = t.get(e); // Only set HTML on elements if (e.nodeType == 1) { d = d || e.ownerDocument || t.doc; if (isIE) { try { // Try outerHTML for IE it sometimes produces an unknown runtime error if (isIE && e.nodeType == 1) e.outerHTML = h; else setHTML(e, h, d); } catch (ex) { // Fix for unknown runtime error setHTML(e, h, d); } } else setHTML(e, h, d); } }); }, decode : function(s) { var e, n, v; // Look for entities to decode if (/&[\w#]+;/.test(s)) { // Decode the entities using a div element not super efficient but less code e = this.doc.createElement("div"); e.innerHTML = s; n = e.firstChild; v = ''; if (n) { do { v += n.nodeValue; } while (n = n.nextSibling); } return v || s; } return s; }, encode : function(str) { return ('' + str).replace(encodeCharsRe, function(chr) { return encodedChars[chr]; }); }, insertAfter : function(node, reference_node) { reference_node = this.get(reference_node); return this.run(node, function(node) { var parent, nextSibling; parent = reference_node.parentNode; nextSibling = reference_node.nextSibling; if (nextSibling) parent.insertBefore(node, nextSibling); else parent.appendChild(node); return node; }); }, isBlock : function(n) { if (n.nodeType && n.nodeType !== 1) return false; n = n.nodeName || n; return blockRe.test(n); }, replace : function(n, o, k) { var t = this; if (is(o, 'array')) n = n.cloneNode(true); return t.run(o, function(o) { if (k) { each(tinymce.grep(o.childNodes), function(c) { n.appendChild(c); }); } return o.parentNode.replaceChild(n, o); }); }, rename : function(elm, name) { var t = this, newElm; if (elm.nodeName != name.toUpperCase()) { // Rename block element newElm = t.create(name); // Copy attribs to new block each(t.getAttribs(elm), function(attr_node) { t.setAttrib(newElm, attr_node.nodeName, t.getAttrib(elm, attr_node.nodeName)); }); // Replace block t.replace(newElm, elm, 1); } return newElm || elm; }, findCommonAncestor : function(a, b) { var ps = a, pe; while (ps) { pe = b; while (pe && ps != pe) pe = pe.parentNode; if (ps == pe) break; ps = ps.parentNode; } if (!ps && a.ownerDocument) return a.ownerDocument.documentElement; return ps; }, toHex : function(s) { var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s); function hex(s) { s = parseInt(s).toString(16); return s.length > 1 ? s : '0' + s; // 0 -> 00 }; if (c) { s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]); return s; } return s; }, getClasses : function() { var t = this, cl = [], i, lo = {}, f = t.settings.class_filter, ov; if (t.classes) return t.classes; function addClasses(s) { // IE style imports each(s.imports, function(r) { addClasses(r); }); each(s.cssRules || s.rules, function(r) { // Real type or fake it on IE switch (r.type || 1) { // Rule case 1: if (r.selectorText) { each(r.selectorText.split(','), function(v) { v = v.replace(/^\s*|\s*$|^\s\./g, ""); // Is internal or it doesn't contain a class if (/\.mce/.test(v) || !/\.[\w\-]+$/.test(v)) return; // Remove everything but class name ov = v; v = tinymce._replace(/.*\.([a-z0-9_\-]+).*/i, '$1', v); // Filter classes if (f && !(v = f(v, ov))) return; if (!lo[v]) { cl.push({'class' : v}); lo[v] = 1; } }); } break; // Import case 3: addClasses(r.styleSheet); break; } }); }; try { each(t.doc.styleSheets, addClasses); } catch (ex) { // Ignore } if (cl.length > 0) t.classes = cl; return cl; }, run : function(e, f, s) { var t = this, o; if (t.doc && typeof(e) === 'string') e = t.get(e); if (!e) return false; s = s || this; if (!e.nodeType && (e.length || e.length === 0)) { o = []; each(e, function(e, i) { if (e) { if (typeof(e) == 'string') e = t.doc.getElementById(e); o.push(f.call(s, e, i)); } }); return o; } return f.call(s, e); }, getAttribs : function(n) { var o; n = this.get(n); if (!n) return []; if (isIE) { o = []; // Object will throw exception in IE if (n.nodeName == 'OBJECT') return n.attributes; // IE doesn't keep the selected attribute if you clone option elements if (n.nodeName === 'OPTION' && this.getAttrib(n, 'selected')) o.push({specified : 1, nodeName : 'selected'}); // It's crazy that this is faster in IE but it's because it returns all attributes all the time n.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi, '').replace(/[\w:\-]+/gi, function(a) { o.push({specified : 1, nodeName : a}); }); return o; } return n.attributes; }, destroy : function(s) { var t = this; if (t.events) t.events.destroy(); t.win = t.doc = t.root = t.events = null; // Manual destroy then remove unload handler if (!s) tinymce.removeUnload(t.destroy); }, createRng : function() { var d = this.doc; return d.createRange ? d.createRange() : new tinymce.dom.Range(this); }, nodeIndex : function(node, normalized) { var idx = 0, lastNodeType, lastNode, nodeType; if (node) { for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) { nodeType = node.nodeType; // Normalize text nodes if (normalized && nodeType == 3) { if (nodeType == lastNodeType || !node.nodeValue.length) continue; } idx++; lastNodeType = nodeType; } } return idx; }, split : function(pe, e, re) { var t = this, r = t.createRng(), bef, aft, pa; // W3C valid browsers tend to leave empty nodes to the left/right side of the contents, this makes sense // but we don't want that in our code since it serves no purpose for the end user // For example if this is chopped: //

    text 1CHOPtext 2

    // would produce: //

    text 1

    CHOP

    text 2

    // this function will then trim of empty edges and produce: //

    text 1

    CHOP

    text 2

    function trim(node) { var i, children = node.childNodes; if (node.nodeType == 1 && node.getAttribute('_mce_type') == 'bookmark') return; for (i = children.length - 1; i >= 0; i--) trim(children[i]); if (node.nodeType != 9) { // Keep non whitespace text nodes if (node.nodeType == 3 && node.nodeValue.length > 0) { // If parent element isn't a block or there isn't any useful contents for example "

    " if (!t.isBlock(node.parentNode) || tinymce.trim(node.nodeValue).length > 0) return; } if (node.nodeType == 1) { // If the only child is a bookmark then move it up children = node.childNodes; if (children.length == 1 && children[0] && children[0].nodeType == 1 && children[0].getAttribute('_mce_type') == 'bookmark') node.parentNode.insertBefore(children[0], node); // Keep non empty elements or img, hr etc if (children.length || /^(br|hr|input|img)$/i.test(node.nodeName)) return; } t.remove(node); } return node; }; if (pe && e) { // Get before chunk r.setStart(pe.parentNode, t.nodeIndex(pe)); r.setEnd(e.parentNode, t.nodeIndex(e)); bef = r.extractContents(); // Get after chunk r = t.createRng(); r.setStart(e.parentNode, t.nodeIndex(e) + 1); r.setEnd(pe.parentNode, t.nodeIndex(pe) + 1); aft = r.extractContents(); // Insert before chunk pa = pe.parentNode; pa.insertBefore(trim(bef), pe); // Insert middle chunk if (re) pa.replaceChild(re, e); else pa.insertBefore(e, pe); // Insert after chunk pa.insertBefore(trim(aft), pe); t.remove(pe); return re || e; } }, bind : function(target, name, func, scope) { var t = this; if (!t.events) t.events = new tinymce.dom.EventUtils(); return t.events.add(target, name, func, scope || this); }, unbind : function(target, name, func) { var t = this; if (!t.events) t.events = new tinymce.dom.EventUtils(); return t.events.remove(target, name, func); }, _findSib : function(node, selector, name) { var t = this, f = selector; if (node) { // If expression make a function of it using is if (is(f, 'string')) { f = function(node) { return t.is(node, selector); }; } // Loop all siblings for (node = node[name]; node; node = node[name]) { if (f(node)) return node; } } return null; }, _isRes : function(c) { // Is live resizble element return /^(top|left|bottom|right|width|height)/i.test(c) || /;\s*(top|left|bottom|right|width|height)/i.test(c); } /* walk : function(n, f, s) { var d = this.doc, w; if (d.createTreeWalker) { w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); while ((n = w.nextNode()) != null) f.call(s || this, n); } else tinymce.walk(n, f, 'childNodes', s); } */ /* toRGB : function(s) { var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s); if (c) { // #FFF -> #FFFFFF if (!is(c[3])) c[3] = c[2] = c[1]; return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")"; } return s; } */ }); tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0}); })(tinymce); (function(ns) { // Range constructor function Range(dom) { var t = this, doc = dom.doc, EXTRACT = 0, CLONE = 1, DELETE = 2, TRUE = true, FALSE = false, START_OFFSET = 'startOffset', START_CONTAINER = 'startContainer', END_CONTAINER = 'endContainer', END_OFFSET = 'endOffset', extend = tinymce.extend, nodeIndex = dom.nodeIndex; extend(t, { // Inital states startContainer : doc, startOffset : 0, endContainer : doc, endOffset : 0, collapsed : TRUE, commonAncestorContainer : doc, // Range constants START_TO_START : 0, START_TO_END : 1, END_TO_END : 2, END_TO_START : 3, // Public methods setStart : setStart, setEnd : setEnd, setStartBefore : setStartBefore, setStartAfter : setStartAfter, setEndBefore : setEndBefore, setEndAfter : setEndAfter, collapse : collapse, selectNode : selectNode, selectNodeContents : selectNodeContents, compareBoundaryPoints : compareBoundaryPoints, deleteContents : deleteContents, extractContents : extractContents, cloneContents : cloneContents, insertNode : insertNode, surroundContents : surroundContents, cloneRange : cloneRange }); function setStart(n, o) { _setEndPoint(TRUE, n, o); }; function setEnd(n, o) { _setEndPoint(FALSE, n, o); }; function setStartBefore(n) { setStart(n.parentNode, nodeIndex(n)); }; function setStartAfter(n) { setStart(n.parentNode, nodeIndex(n) + 1); }; function setEndBefore(n) { setEnd(n.parentNode, nodeIndex(n)); }; function setEndAfter(n) { setEnd(n.parentNode, nodeIndex(n) + 1); }; function collapse(ts) { if (ts) { t[END_CONTAINER] = t[START_CONTAINER]; t[END_OFFSET] = t[START_OFFSET]; } else { t[START_CONTAINER] = t[END_CONTAINER]; t[START_OFFSET] = t[END_OFFSET]; } t.collapsed = TRUE; }; function selectNode(n) { setStartBefore(n); setEndAfter(n); }; function selectNodeContents(n) { setStart(n, 0); setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length); }; function compareBoundaryPoints(h, r) { var sc = t[START_CONTAINER], so = t[START_OFFSET], ec = t[END_CONTAINER], eo = t[END_OFFSET]; // Check START_TO_START if (h === 0) return _compareBoundaryPoints(sc, so, sc, so); // Check START_TO_END if (h === 1) return _compareBoundaryPoints(sc, so, ec, eo); // Check END_TO_END if (h === 2) return _compareBoundaryPoints(ec, eo, ec, eo); // Check END_TO_START if (h === 3) return _compareBoundaryPoints(ec, eo, sc, so); }; function deleteContents() { _traverse(DELETE); }; function extractContents() { return _traverse(EXTRACT); }; function cloneContents() { return _traverse(CLONE); }; function insertNode(n) { var startContainer = this[START_CONTAINER], startOffset = this[START_OFFSET], nn, o; // Node is TEXT_NODE or CDATA if ((startContainer.nodeType === 3 || startContainer.nodeType === 4) && startContainer.nodeValue) { if (!startOffset) { // At the start of text startContainer.parentNode.insertBefore(n, startContainer); } else if (startOffset >= startContainer.nodeValue.length) { // At the end of text dom.insertAfter(n, startContainer); } else { // Middle, need to split nn = startContainer.splitText(startOffset); startContainer.parentNode.insertBefore(n, nn); } } else { // Insert element node if (startContainer.childNodes.length > 0) o = startContainer.childNodes[startOffset]; if (o) startContainer.insertBefore(n, o); else startContainer.appendChild(n); } }; function surroundContents(n) { var f = t.extractContents(); t.insertNode(n); n.appendChild(f); t.selectNode(n); }; function cloneRange() { return extend(new Range(dom), { startContainer : t[START_CONTAINER], startOffset : t[START_OFFSET], endContainer : t[END_CONTAINER], endOffset : t[END_OFFSET], collapsed : t.collapsed, commonAncestorContainer : t.commonAncestorContainer }); }; // Private methods function _getSelectedNode(container, offset) { var child; if (container.nodeType == 3 /* TEXT_NODE */) return container; if (offset < 0) return container; child = container.firstChild; while (child && offset > 0) { --offset; child = child.nextSibling; } if (child) return child; return container; }; function _isCollapsed() { return (t[START_CONTAINER] == t[END_CONTAINER] && t[START_OFFSET] == t[END_OFFSET]); }; function _compareBoundaryPoints(containerA, offsetA, containerB, offsetB) { var c, offsetC, n, cmnRoot, childA, childB; // In the first case the boundary-points have the same container. A is before B // if its offset is less than the offset of B, A is equal to B if its offset is // equal to the offset of B, and A is after B if its offset is greater than the // offset of B. if (containerA == containerB) { if (offsetA == offsetB) return 0; // equal if (offsetA < offsetB) return -1; // before return 1; // after } // In the second case a child node C of the container of A is an ancestor // container of B. In this case, A is before B if the offset of A is less than or // equal to the index of the child node C and A is after B otherwise. c = containerB; while (c && c.parentNode != containerA) c = c.parentNode; if (c) { offsetC = 0; n = containerA.firstChild; while (n != c && offsetC < offsetA) { offsetC++; n = n.nextSibling; } if (offsetA <= offsetC) return -1; // before return 1; // after } // In the third case a child node C of the container of B is an ancestor container // of A. In this case, A is before B if the index of the child node C is less than // the offset of B and A is after B otherwise. c = containerA; while (c && c.parentNode != containerB) { c = c.parentNode; } if (c) { offsetC = 0; n = containerB.firstChild; while (n != c && offsetC < offsetB) { offsetC++; n = n.nextSibling; } if (offsetC < offsetB) return -1; // before return 1; // after } // In the fourth case, none of three other cases hold: the containers of A and B // are siblings or descendants of sibling nodes. In this case, A is before B if // the container of A is before the container of B in a pre-order traversal of the // Ranges' context tree and A is after B otherwise. cmnRoot = dom.findCommonAncestor(containerA, containerB); childA = containerA; while (childA && childA.parentNode != cmnRoot) childA = childA.parentNode; if (!childA) childA = cmnRoot; childB = containerB; while (childB && childB.parentNode != cmnRoot) childB = childB.parentNode; if (!childB) childB = cmnRoot; if (childA == childB) return 0; // equal n = cmnRoot.firstChild; while (n) { if (n == childA) return -1; // before if (n == childB) return 1; // after n = n.nextSibling; } }; function _setEndPoint(st, n, o) { var ec, sc; if (st) { t[START_CONTAINER] = n; t[START_OFFSET] = o; } else { t[END_CONTAINER] = n; t[END_OFFSET] = o; } // If one boundary-point of a Range is set to have a root container // other than the current one for the Range, the Range is collapsed to // the new position. This enforces the restriction that both boundary- // points of a Range must have the same root container. ec = t[END_CONTAINER]; while (ec.parentNode) ec = ec.parentNode; sc = t[START_CONTAINER]; while (sc.parentNode) sc = sc.parentNode; if (sc == ec) { // The start position of a Range is guaranteed to never be after the // end position. To enforce this restriction, if the start is set to // be at a position after the end, the Range is collapsed to that // position. if (_compareBoundaryPoints(t[START_CONTAINER], t[START_OFFSET], t[END_CONTAINER], t[END_OFFSET]) > 0) t.collapse(st); } else t.collapse(st); t.collapsed = _isCollapsed(); t.commonAncestorContainer = dom.findCommonAncestor(t[START_CONTAINER], t[END_CONTAINER]); }; function _traverse(how) { var c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep; if (t[START_CONTAINER] == t[END_CONTAINER]) return _traverseSameContainer(how); for (c = t[END_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) { if (p == t[START_CONTAINER]) return _traverseCommonStartContainer(c, how); ++endContainerDepth; } for (c = t[START_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) { if (p == t[END_CONTAINER]) return _traverseCommonEndContainer(c, how); ++startContainerDepth; } depthDiff = startContainerDepth - endContainerDepth; startNode = t[START_CONTAINER]; while (depthDiff > 0) { startNode = startNode.parentNode; depthDiff--; } endNode = t[END_CONTAINER]; while (depthDiff < 0) { endNode = endNode.parentNode; depthDiff++; } // ascend the ancestor hierarchy until we have a common parent. for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) { startNode = sp; endNode = ep; } return _traverseCommonAncestors(startNode, endNode, how); }; function _traverseSameContainer(how) { var frag, s, sub, n, cnt, sibling, xferNode; if (how != DELETE) frag = doc.createDocumentFragment(); // If selection is empty, just return the fragment if (t[START_OFFSET] == t[END_OFFSET]) return frag; // Text node needs special case handling if (t[START_CONTAINER].nodeType == 3 /* TEXT_NODE */) { // get the substring s = t[START_CONTAINER].nodeValue; sub = s.substring(t[START_OFFSET], t[END_OFFSET]); // set the original text node to its new value if (how != CLONE) { t[START_CONTAINER].deleteData(t[START_OFFSET], t[END_OFFSET] - t[START_OFFSET]); // Nothing is partially selected, so collapse to start point t.collapse(TRUE); } if (how == DELETE) return; frag.appendChild(doc.createTextNode(sub)); return frag; } // Copy nodes between the start/end offsets. n = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]); cnt = t[END_OFFSET] - t[START_OFFSET]; while (cnt > 0) { sibling = n.nextSibling; xferNode = _traverseFullySelected(n, how); if (frag) frag.appendChild( xferNode ); --cnt; n = sibling; } // Nothing is partially selected, so collapse to start point if (how != CLONE) t.collapse(TRUE); return frag; }; function _traverseCommonStartContainer(endAncestor, how) { var frag, n, endIdx, cnt, sibling, xferNode; if (how != DELETE) frag = doc.createDocumentFragment(); n = _traverseRightBoundary(endAncestor, how); if (frag) frag.appendChild(n); endIdx = nodeIndex(endAncestor); cnt = endIdx - t[START_OFFSET]; if (cnt <= 0) { // Collapse to just before the endAncestor, which // is partially selected. if (how != CLONE) { t.setEndBefore(endAncestor); t.collapse(FALSE); } return frag; } n = endAncestor.previousSibling; while (cnt > 0) { sibling = n.previousSibling; xferNode = _traverseFullySelected(n, how); if (frag) frag.insertBefore(xferNode, frag.firstChild); --cnt; n = sibling; } // Collapse to just before the endAncestor, which // is partially selected. if (how != CLONE) { t.setEndBefore(endAncestor); t.collapse(FALSE); } return frag; }; function _traverseCommonEndContainer(startAncestor, how) { var frag, startIdx, n, cnt, sibling, xferNode; if (how != DELETE) frag = doc.createDocumentFragment(); n = _traverseLeftBoundary(startAncestor, how); if (frag) frag.appendChild(n); startIdx = nodeIndex(startAncestor); ++startIdx; // Because we already traversed it.... cnt = t[END_OFFSET] - startIdx; n = startAncestor.nextSibling; while (cnt > 0) { sibling = n.nextSibling; xferNode = _traverseFullySelected(n, how); if (frag) frag.appendChild(xferNode); --cnt; n = sibling; } if (how != CLONE) { t.setStartAfter(startAncestor); t.collapse(TRUE); } return frag; }; function _traverseCommonAncestors(startAncestor, endAncestor, how) { var n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling; if (how != DELETE) frag = doc.createDocumentFragment(); n = _traverseLeftBoundary(startAncestor, how); if (frag) frag.appendChild(n); commonParent = startAncestor.parentNode; startOffset = nodeIndex(startAncestor); endOffset = nodeIndex(endAncestor); ++startOffset; cnt = endOffset - startOffset; sibling = startAncestor.nextSibling; while (cnt > 0) { nextSibling = sibling.nextSibling; n = _traverseFullySelected(sibling, how); if (frag) frag.appendChild(n); sibling = nextSibling; --cnt; } n = _traverseRightBoundary(endAncestor, how); if (frag) frag.appendChild(n); if (how != CLONE) { t.setStartAfter(startAncestor); t.collapse(TRUE); } return frag; }; function _traverseRightBoundary(root, how) { var next = _getSelectedNode(t[END_CONTAINER], t[END_OFFSET] - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != t[END_CONTAINER]; if (next == root) return _traverseNode(next, isFullySelected, FALSE, how); parent = next.parentNode; clonedParent = _traverseNode(parent, FALSE, FALSE, how); while (parent) { while (next) { prevSibling = next.previousSibling; clonedChild = _traverseNode(next, isFullySelected, FALSE, how); if (how != DELETE) clonedParent.insertBefore(clonedChild, clonedParent.firstChild); isFullySelected = TRUE; next = prevSibling; } if (parent == root) return clonedParent; next = parent.previousSibling; parent = parent.parentNode; clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how); if (how != DELETE) clonedGrandParent.appendChild(clonedParent); clonedParent = clonedGrandParent; } }; function _traverseLeftBoundary(root, how) { var next = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]), isFullySelected = next != t[START_CONTAINER], parent, clonedParent, nextSibling, clonedChild, clonedGrandParent; if (next == root) return _traverseNode(next, isFullySelected, TRUE, how); parent = next.parentNode; clonedParent = _traverseNode(parent, FALSE, TRUE, how); while (parent) { while (next) { nextSibling = next.nextSibling; clonedChild = _traverseNode(next, isFullySelected, TRUE, how); if (how != DELETE) clonedParent.appendChild(clonedChild); isFullySelected = TRUE; next = nextSibling; } if (parent == root) return clonedParent; next = parent.nextSibling; parent = parent.parentNode; clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how); if (how != DELETE) clonedGrandParent.appendChild(clonedParent); clonedParent = clonedGrandParent; } }; function _traverseNode(n, isFullySelected, isLeft, how) { var txtValue, newNodeValue, oldNodeValue, offset, newNode; if (isFullySelected) return _traverseFullySelected(n, how); if (n.nodeType == 3 /* TEXT_NODE */) { txtValue = n.nodeValue; if (isLeft) { offset = t[START_OFFSET]; newNodeValue = txtValue.substring(offset); oldNodeValue = txtValue.substring(0, offset); } else { offset = t[END_OFFSET]; newNodeValue = txtValue.substring(0, offset); oldNodeValue = txtValue.substring(offset); } if (how != CLONE) n.nodeValue = oldNodeValue; if (how == DELETE) return; newNode = n.cloneNode(FALSE); newNode.nodeValue = newNodeValue; return newNode; } if (how == DELETE) return; return n.cloneNode(FALSE); }; function _traverseFullySelected(n, how) { if (how != DELETE) return how == CLONE ? n.cloneNode(TRUE) : n; n.parentNode.removeChild(n); }; }; ns.Range = Range; })(tinymce.dom); (function() { function Selection(selection) { var t = this, invisibleChar = '\uFEFF', range, lastIERng, dom = selection.dom, TRUE = true, FALSE = false; // Returns a W3C DOM compatible range object by using the IE Range API function getRange() { var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed; // If selection is outside the current document just return an empty range element = ieRange.item ? ieRange.item(0) : ieRange.parentElement(); if (element.ownerDocument != dom.doc) return domRange; // Handle control selection or text selection of a image if (ieRange.item || !element.hasChildNodes()) { domRange.setStart(element.parentNode, dom.nodeIndex(element)); domRange.setEnd(domRange.startContainer, domRange.startOffset + 1); return domRange; } collapsed = selection.isCollapsed(); function findEndPoint(start) { var marker, container, offset, nodes, startIndex = 0, endIndex, index, parent, checkRng, position; // Setup temp range and collapse it checkRng = ieRange.duplicate(); checkRng.collapse(start); // Create marker and insert it at the end of the endpoints parent marker = dom.create('a'); parent = checkRng.parentElement(); // If parent doesn't have any children then set the container to that parent and the index to 0 if (!parent.hasChildNodes()) { domRange[start ? 'setStart' : 'setEnd'](parent, 0); return; } parent.appendChild(marker); checkRng.moveToElementText(marker); position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng); if (position > 0) { // The position is after the end of the parent element. // This is the case where IE puts the caret to the left edge of a table. domRange[start ? 'setStartAfter' : 'setEndAfter'](parent); dom.remove(marker); return; } // Setup node list and endIndex nodes = tinymce.grep(parent.childNodes); endIndex = nodes.length - 1; // Perform a binary search for the position while (startIndex <= endIndex) { index = Math.floor((startIndex + endIndex) / 2); // Insert marker and check it's position relative to the selection parent.insertBefore(marker, nodes[index]); checkRng.moveToElementText(marker); position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng); if (position > 0) { // Marker is to the right startIndex = index + 1; } else if (position < 0) { // Marker is to the left endIndex = index - 1; } else { // Maker is where we are found = true; break; } } // Setup container container = position > 0 || index == 0 ? marker.nextSibling : marker.previousSibling; // Handle element selection if (container.nodeType == 1) { dom.remove(marker); // Find offset and container offset = dom.nodeIndex(container); container = container.parentNode; // Move the offset if we are setting the end or the position is after an element if (!start || index > 0) offset++; } else { // Calculate offset within text node if (position > 0 || index == 0) { checkRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', ieRange); offset = checkRng.text.length; } else { checkRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', ieRange); offset = container.nodeValue.length - checkRng.text.length; } dom.remove(marker); } domRange[start ? 'setStart' : 'setEnd'](container, offset); }; // Find start point findEndPoint(true); // Find end point if needed if (!collapsed) findEndPoint(); return domRange; }; this.addRange = function(rng) { var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, doc = selection.dom.doc, body = doc.body; function setEndPoint(start) { var container, offset, marker, tmpRng, nodes; marker = dom.create('a'); container = start ? startContainer : endContainer; offset = start ? startOffset : endOffset; tmpRng = ieRng.duplicate(); if (container == doc) { container = body; offset = 0; } if (container.nodeType == 3) { container.parentNode.insertBefore(marker, container); tmpRng.moveToElementText(marker); tmpRng.moveStart('character', offset); dom.remove(marker); ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng); } else { nodes = container.childNodes; if (nodes.length) { if (offset >= nodes.length) { dom.insertAfter(marker, nodes[nodes.length - 1]); } else { container.insertBefore(marker, nodes[offset]); } tmpRng.moveToElementText(marker); } else { // Empty node selection for example
    |
    marker = doc.createTextNode(invisibleChar); container.appendChild(marker); tmpRng.moveToElementText(marker.parentNode); tmpRng.collapse(TRUE); } ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng); dom.remove(marker); } } // Destroy cached range this.destroy(); // Setup some shorter versions startContainer = rng.startContainer; startOffset = rng.startOffset; endContainer = rng.endContainer; endOffset = rng.endOffset; ieRng = body.createTextRange(); // If single element selection then try making a control selection out of it if (startContainer == endContainer && startContainer.nodeType == 1 && startOffset == endOffset - 1) { if (startOffset == endOffset - 1) { try { ctrlRng = body.createControlRange(); ctrlRng.addElement(startContainer.childNodes[startOffset]); ctrlRng.select(); ctrlRng.scrollIntoView(); return; } catch (ex) { // Ignore } } } // Set start/end point of selection setEndPoint(true); setEndPoint(); // Select the new range and scroll it into view ieRng.select(); ieRng.scrollIntoView(); }; this.getRangeAt = function() { // Setup new range if the cache is empty if (!range || !tinymce.dom.RangeUtils.compareRanges(lastIERng, selection.getRng())) { range = getRange(); // Store away text range for next call lastIERng = selection.getRng(); } // IE will say that the range is equal then produce an invalid argument exception // if you perform specific operations in a keyup event. For example Ctrl+Del. // This hack will invalidate the range cache if the exception occurs try { range.startContainer.nextSibling; } catch (ex) { range = getRange(); lastIERng = null; } // Return cached range return range; }; this.destroy = function() { // Destroy cached range and last IE range to avoid memory leaks lastIERng = range = null; }; }; // Expose the selection object tinymce.dom.TridentSelection = Selection; })(); /* * Sizzle CSS Selector Engine - v1.0 * Copyright 2009, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true; // Here we check if the JavaScript engine is using some sort of // optimization where it does not always call our comparision // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. [0, 0].sort(function(){ baseHasDuplicate = false; return 0; }); var Sizzle = function(selector, context, results, seed) { results = results || []; context = context || document; var origContext = context; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context), soFar = selector, ret, cur, pop, i; // Reset the position of the chunker regexp (start from head) do { chunker.exec(""); m = chunker.exec(soFar); if ( m ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } } while ( m ); if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set ); } } } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray(set); } else { prune = false; } while ( parts.length ) { cur = parts.pop(); pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { Sizzle.error( cur || selector ); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function(results){ if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort(sortOrder); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[i-1] ) { results.splice(i--, 1); } } } } return results; }; Sizzle.matches = function(expr, set){ return Sizzle(expr, null, null, set); }; Sizzle.find = function(expr, context, isXML){ var set; if ( !expr ) { return []; } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var type = Expr.order[i], match; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; match.splice(1,1); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace(/\\/g, ""); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = context.getElementsByTagName("*"); } return {set: set, expr: expr}; }; Sizzle.filter = function(expr, set, inplace, not){ var old = expr, result = [], curLoop = set, match, anyFound, isXMLFilter = set && set[0] && Sizzle.isXML(set[0]); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { var filter = Expr.filter[ type ], found, item, left = match[1]; anyFound = false; match.splice(1,1); if ( left.substr( left.length - 1 ) === "\\" ) { continue; } if ( curLoop === result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( var i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); var pass = not ^ !!found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } // Improper expression if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); } else { break; } } old = expr; } return curLoop; }; Sizzle.error = function( msg ) { throw "Syntax error, unrecognized expression: " + msg; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function(elem){ return elem.getAttribute("href"); } }, relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", isTag = isPartStr && !/\W/.test(part), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { part = part.toLowerCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function(checkSet, part){ var isPartStr = typeof part === "string", elem, i = 0, l = checkSet.length; if ( isPartStr && !/\W/.test(part) ) { part = part.toLowerCase(); for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } } else { for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck, nodeCheck; if ( typeof part === "string" && !/\W/.test(part) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); }, "~": function(checkSet, part, isXML){ var doneName = done++, checkFn = dirCheck, nodeCheck; if ( typeof part === "string" && !/\W/.test(part) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); } }, find: { ID: function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? [m] : []; } }, NAME: function(match, context){ if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName(match[1]); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function(match, context){ return context.getElementsByTagName(match[1]); } }, preFilter: { CLASS: function(match, curLoop, inplace, result, not, isXML){ match = " " + match[1].replace(/\\/g, "") + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { if ( !inplace ) { result.push( elem ); } } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function(match){ return match[1].replace(/\\/g, ""); }, TAG: function(match, curLoop){ return match[1].toLowerCase(); }, CHILD: function(match){ if ( match[1] === "nth" ) { // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); // calculate the numbers (first)n+(last) including if they are negative match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } // TODO: Move to normal caching system match[0] = done++; return match; }, ATTR: function(match, curLoop, inplace, result, not, isXML){ var name = match[1].replace(/\\/g, ""); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function(match, curLoop, inplace, result, not){ if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function(match){ match.unshift( true ); return match; } }, filters: { enabled: function(elem){ return elem.disabled === false && elem.type !== "hidden"; }, disabled: function(elem){ return elem.disabled === true; }, checked: function(elem){ return elem.checked === true; }, selected: function(elem){ // Accessing this property makes selected-by-default // options in Safari work properly elem.parentNode.selectedIndex; return elem.selected === true; }, parent: function(elem){ return !!elem.firstChild; }, empty: function(elem){ return !elem.firstChild; }, has: function(elem, i, match){ return !!Sizzle( match[3], elem ).length; }, header: function(elem){ return (/h\d/i).test( elem.nodeName ); }, text: function(elem){ return "text" === elem.type; }, radio: function(elem){ return "radio" === elem.type; }, checkbox: function(elem){ return "checkbox" === elem.type; }, file: function(elem){ return "file" === elem.type; }, password: function(elem){ return "password" === elem.type; }, submit: function(elem){ return "submit" === elem.type; }, image: function(elem){ return "image" === elem.type; }, reset: function(elem){ return "reset" === elem.type; }, button: function(elem){ return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; }, input: function(elem){ return (/input|select|textarea|button/i).test(elem.nodeName); } }, setFilters: { first: function(elem, i){ return i === 0; }, last: function(elem, i, match, array){ return i === array.length - 1; }, even: function(elem, i){ return i % 2 === 0; }, odd: function(elem, i){ return i % 2 === 1; }, lt: function(elem, i, match){ return i < match[3] - 0; }, gt: function(elem, i, match){ return i > match[3] - 0; }, nth: function(elem, i, match){ return match[3] - 0 === i; }, eq: function(elem, i, match){ return match[3] - 0 === i; } }, filter: { PSEUDO: function(elem, match, i, array){ var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var j = 0, l = not.length; j < l; j++ ) { if ( not[j] === elem ) { return false; } } return true; } else { Sizzle.error( "Syntax error, unrecognized expression: " + name ); } }, CHILD: function(elem, match){ var type = match[1], node = elem; switch (type) { case 'only': case 'first': while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } if ( type === "first" ) { return true; } node = elem; case 'last': while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } return true; case 'nth': var first = match[2], last = match[3]; if ( first === 1 && last === 0 ) { return true; } var doneName = match[0], parent = elem.parentNode; if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent.sizcache = doneName; } var diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, ID: function(elem, match){ return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function(elem, match){ return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; }, CLASS: function(elem, match){ return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function(elem, match){ var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value !== check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function(elem, match, i, array){ var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS, fescape = function(all, num){ return "\\" + (num - 0 + 1); }; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } var makeArray = function(array, results) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; // Perform a simple check to determine if the browser is capable of // converting a NodeList to an array using builtin methods. // Also verifies that the returned array holds DOM nodes // (which is not the case in the Blackberry browser) try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work } catch(e){ makeArray = function(array, results) { var ret = results || [], i = 0; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( ; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { if ( a == b ) { hasDuplicate = true; } return a.compareDocumentPosition ? -1 : 1; } var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( "sourceIndex" in document.documentElement ) { sortOrder = function( a, b ) { if ( !a.sourceIndex || !b.sourceIndex ) { if ( a == b ) { hasDuplicate = true; } return a.sourceIndex ? -1 : 1; } var ret = a.sourceIndex - b.sourceIndex; if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } else if ( document.createRange ) { sortOrder = function( a, b ) { if ( !a.ownerDocument || !b.ownerDocument ) { if ( a == b ) { hasDuplicate = true; } return a.ownerDocument ? -1 : 1; } var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.setStart(a, 0); aRange.setEnd(a, 0); bRange.setStart(b, 0); bRange.setEnd(b, 0); var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); if ( ret === 0 ) { hasDuplicate = true; } return ret; }; } // Utility function for retreiving the text value of an array of DOM nodes Sizzle.getText = function( elems ) { var ret = "", elem; for ( var i = 0; elems[i]; i++ ) { elem = elems[i]; // Get the text from text nodes and CDATA nodes if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; // Traverse everything else, except comment nodes } else if ( elem.nodeType !== 8 ) { ret += Sizzle.getText( elem.childNodes ); } } return ret; }; // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), id = "script" + (new Date()).getTime(); form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly var root = document.documentElement; root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function(match, context, isXML){ if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function(elem, match){ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); root = form = null; // release memory in IE })(); (function(){ // Check to see if the browser returns only elements // when doing getElementsByTagName("*") // Create a fake element var div = document.createElement("div"); div.appendChild( document.createComment("") ); // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function(match, context){ var results = context.getElementsByTagName(match[1]); // Filter out possible comments if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function(elem){ return elem.getAttribute("href", 2); }; } div = null; // release memory in IE })(); if ( document.querySelectorAll ) { (function(){ var oldSizzle = Sizzle, div = document.createElement("div"); div.innerHTML = "

    "; // Safari can't handle uppercase or unicode characters when // in quirks mode. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function(query, context, extra, seed){ context = context || document; // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && context.nodeType === 9 && !Sizzle.isXML(context) ) { try { return makeArray( context.querySelectorAll(query), extra ); } catch(e){} } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } div = null; // release memory in IE })(); } (function(){ var div = document.createElement("div"); div.innerHTML = "
    "; // Opera can't find a second classname (in 9.6) // Also, make sure that getElementsByClassName actually exists if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { return; } // Safari caches class attributes, doesn't catch changes (in 3.2) div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) { return; } Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function(match, context, isXML) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; div = null; // release memory in IE })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem.sizcache = doneName; elem.sizset = i; } if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { elem = elem[dir]; var match = false; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem.sizcache = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } Sizzle.contains = document.compareDocumentPosition ? function(a, b){ return !!(a.compareDocumentPosition(b) & 16); } : function(a, b){ return a !== b && (a.contains ? a.contains(b) : true); }; Sizzle.isXML = function(elem){ // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; var posProcess = function(selector, context){ var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context; // Position selectors must be done after the filter // And so must :not(positional) so we move all PSEUDOs to the end while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE window.tinymce.dom.Sizzle = Sizzle; })(); (function(tinymce) { // Shorten names var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event; tinymce.create('tinymce.dom.EventUtils', { EventUtils : function() { this.inits = []; this.events = []; }, add : function(o, n, f, s) { var cb, t = this, el = t.events, r; if (n instanceof Array) { r = []; each(n, function(n) { r.push(t.add(o, n, f, s)); }); return r; } // Handle array if (o && o.hasOwnProperty && o instanceof Array) { r = []; each(o, function(o) { o = DOM.get(o); r.push(t.add(o, n, f, s)); }); return r; } o = DOM.get(o); if (!o) return; // Setup event callback cb = function(e) { // Is all events disabled if (t.disabled) return; e = e || window.event; // Patch in target, preventDefault and stopPropagation in IE it's W3C valid if (e && isIE) { if (!e.target) e.target = e.srcElement; // Patch in preventDefault, stopPropagation methods for W3C compatibility tinymce.extend(e, t._stoppers); } if (!s) return f(e); return f.call(s, e); }; if (n == 'unload') { tinymce.unloads.unshift({func : cb}); return cb; } if (n == 'init') { if (t.domLoaded) cb(); else t.inits.push(cb); return cb; } // Store away listener reference el.push({ obj : o, name : n, func : f, cfunc : cb, scope : s }); t._add(o, n, cb); return f; }, remove : function(o, n, f) { var t = this, a = t.events, s = false, r; // Handle array if (o && o.hasOwnProperty && o instanceof Array) { r = []; each(o, function(o) { o = DOM.get(o); r.push(t.remove(o, n, f)); }); return r; } o = DOM.get(o); each(a, function(e, i) { if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) { a.splice(i, 1); t._remove(o, n, e.cfunc); s = true; return false; } }); return s; }, clear : function(o) { var t = this, a = t.events, i, e; if (o) { o = DOM.get(o); for (i = a.length - 1; i >= 0; i--) { e = a[i]; if (e.obj === o) { t._remove(e.obj, e.name, e.cfunc); e.obj = e.cfunc = null; a.splice(i, 1); } } } }, cancel : function(e) { if (!e) return false; this.stop(e); return this.prevent(e); }, stop : function(e) { if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; return false; }, prevent : function(e) { if (e.preventDefault) e.preventDefault(); else e.returnValue = false; return false; }, destroy : function() { var t = this; each(t.events, function(e, i) { t._remove(e.obj, e.name, e.cfunc); e.obj = e.cfunc = null; }); t.events = []; t = null; }, _add : function(o, n, f) { if (o.attachEvent) o.attachEvent('on' + n, f); else if (o.addEventListener) o.addEventListener(n, f, false); else o['on' + n] = f; }, _remove : function(o, n, f) { if (o) { try { if (o.detachEvent) o.detachEvent('on' + n, f); else if (o.removeEventListener) o.removeEventListener(n, f, false); else o['on' + n] = null; } catch (ex) { // Might fail with permission denined on IE so we just ignore that } } }, _pageInit : function(win) { var t = this; // Keep it from running more than once if (t.domLoaded) return; t.domLoaded = true; each(t.inits, function(c) { c(); }); t.inits = []; }, _wait : function(win) { var t = this, doc = win.document; // No need since the document is already loaded if (win.tinyMCE_GZ && tinyMCE_GZ.loaded) { t.domLoaded = 1; return; } // Use IE method if (doc.attachEvent) { doc.attachEvent("onreadystatechange", function() { if (doc.readyState === "complete") { doc.detachEvent("onreadystatechange", arguments.callee); t._pageInit(win); } }); if (doc.documentElement.doScroll && win == win.top) { (function() { if (t.domLoaded) return; try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ doc.documentElement.doScroll("left"); } catch (ex) { setTimeout(arguments.callee, 0); return; } t._pageInit(win); })(); } } else if (doc.addEventListener) { t._add(win, 'DOMContentLoaded', function() { t._pageInit(win); }); } t._add(win, 'load', function() { t._pageInit(win); }); }, _stoppers : { preventDefault : function() { this.returnValue = false; }, stopPropagation : function() { this.cancelBubble = true; } } }); Event = tinymce.dom.Event = new tinymce.dom.EventUtils(); // Dispatch DOM content loaded event for IE and Safari Event._wait(window); tinymce.addUnload(function() { Event.destroy(); }); })(tinymce); (function(tinymce) { tinymce.dom.Element = function(id, settings) { var t = this, dom, el; t.settings = settings = settings || {}; t.id = id; t.dom = dom = settings.dom || tinymce.DOM; // Only IE leaks DOM references, this is a lot faster if (!tinymce.isIE) el = dom.get(t.id); tinymce.each( ('getPos,getRect,getParent,add,setStyle,getStyle,setStyles,' + 'setAttrib,setAttribs,getAttrib,addClass,removeClass,' + 'hasClass,getOuterHTML,setOuterHTML,remove,show,hide,' + 'isHidden,setHTML,get').split(/,/) , function(k) { t[k] = function() { var a = [id], i; for (i = 0; i < arguments.length; i++) a.push(arguments[i]); a = dom[k].apply(dom, a); t.update(k); return a; }; }); tinymce.extend(t, { on : function(n, f, s) { return tinymce.dom.Event.add(t.id, n, f, s); }, getXY : function() { return { x : parseInt(t.getStyle('left')), y : parseInt(t.getStyle('top')) }; }, getSize : function() { var n = dom.get(t.id); return { w : parseInt(t.getStyle('width') || n.clientWidth), h : parseInt(t.getStyle('height') || n.clientHeight) }; }, moveTo : function(x, y) { t.setStyles({left : x, top : y}); }, moveBy : function(x, y) { var p = t.getXY(); t.moveTo(p.x + x, p.y + y); }, resizeTo : function(w, h) { t.setStyles({width : w, height : h}); }, resizeBy : function(w, h) { var s = t.getSize(); t.resizeTo(s.w + w, s.h + h); }, update : function(k) { var b; if (tinymce.isIE6 && settings.blocker) { k = k || ''; // Ignore getters if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0) return; // Remove blocker on remove if (k == 'remove') { dom.remove(t.blocker); return; } if (!t.blocker) { t.blocker = dom.uniqueId(); b = dom.add(settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'}); dom.setStyle(b, 'opacity', 0); } else b = dom.get(t.blocker); dom.setStyles(b, { left : t.getStyle('left', 1), top : t.getStyle('top', 1), width : t.getStyle('width', 1), height : t.getStyle('height', 1), display : t.getStyle('display', 1), zIndex : parseInt(t.getStyle('zIndex', 1) || 0) - 1 }); } } }); }; })(tinymce); (function(tinymce) { function trimNl(s) { return s.replace(/[\n\r]+/g, ''); }; // Shorten names var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each; tinymce.create('tinymce.dom.Selection', { Selection : function(dom, win, serializer) { var t = this; t.dom = dom; t.win = win; t.serializer = serializer; // Add events each([ 'onBeforeSetContent', 'onBeforeGetContent', 'onSetContent', 'onGetContent' ], function(e) { t[e] = new tinymce.util.Dispatcher(t); }); // No W3C Range support if (!t.win.getSelection) t.tridentSel = new tinymce.dom.TridentSelection(t); if (tinymce.isIE && dom.boxModel) this._fixIESelection(); // Prevent leaks tinymce.addUnload(t.destroy, t); }, getContent : function(s) { var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n; s = s || {}; wb = wa = ''; s.get = true; s.format = s.format || 'html'; t.onBeforeGetContent.dispatch(t, s); if (s.format == 'text') return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : '')); if (r.cloneContents) { n = r.cloneContents(); if (n) e.appendChild(n); } else if (is(r.item) || is(r.htmlText)) e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText; else e.innerHTML = r.toString(); // Keep whitespace before and after if (/^\s/.test(e.innerHTML)) wb = ' '; if (/\s+$/.test(e.innerHTML)) wa = ' '; s.getInner = true; s.content = t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa; t.onGetContent.dispatch(t, s); return s.content; }, setContent : function(h, s) { var t = this, r = t.getRng(), c, d = t.win.document; s = s || {format : 'html'}; s.set = true; h = s.content = t.dom.processHTML(h); // Dispatch before set content event t.onBeforeSetContent.dispatch(t, s); h = s.content; if (r.insertNode) { // Make caret marker since insertNode places the caret in the beginning of text after insert h += '_'; // Delete and insert new node if (r.startContainer == d && r.endContainer == d) { // WebKit will fail if the body is empty since the range is then invalid and it can't insert contents d.body.innerHTML = h; } else { r.deleteContents(); if (d.body.childNodes.length == 0) { d.body.innerHTML = h; } else { // createContextualFragment doesn't exists in IE 9 DOMRanges if (r.createContextualFragment) { r.insertNode(r.createContextualFragment(h)); } else { // Fake createContextualFragment call in IE 9 var frag = d.createDocumentFragment(), temp = d.createElement('div'); frag.appendChild(temp); temp.outerHTML = h; r.insertNode(frag); } } } // Move to caret marker c = t.dom.get('__caret'); // Make sure we wrap it compleatly, Opera fails with a simple select call r = d.createRange(); r.setStartBefore(c); r.setEndBefore(c); t.setRng(r); // Remove the caret position t.dom.remove('__caret'); } else { if (r.item) { // Delete content and get caret text selection d.execCommand('Delete', false, null); r = t.getRng(); } r.pasteHTML(h); } // Dispatch set content event t.onSetContent.dispatch(t, s); }, getStart : function() { var rng = this.getRng(), startElement, parentElement, checkRng, node; if (rng.duplicate || rng.item) { // Control selection, return first item if (rng.item) return rng.item(0); // Get start element checkRng = rng.duplicate(); checkRng.collapse(1); startElement = checkRng.parentElement(); // Check if range parent is inside the start element, then return the inner parent element // This will fix issues when a single element is selected, IE would otherwise return the wrong start element parentElement = node = rng.parentElement(); while (node = node.parentNode) { if (node == startElement) { startElement = parentElement; break; } } // If start element is body element try to move to the first child if it exists if (startElement && startElement.nodeName == 'BODY') return startElement.firstChild || startElement; return startElement; } else { startElement = rng.startContainer; if (startElement.nodeType == 1 && startElement.hasChildNodes()) startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)]; if (startElement && startElement.nodeType == 3) return startElement.parentNode; return startElement; } }, getEnd : function() { var t = this, r = t.getRng(), e, eo; if (r.duplicate || r.item) { if (r.item) return r.item(0); r = r.duplicate(); r.collapse(0); e = r.parentElement(); if (e && e.nodeName == 'BODY') return e.lastChild || e; return e; } else { e = r.endContainer; eo = r.endOffset; if (e.nodeType == 1 && e.hasChildNodes()) e = e.childNodes[eo > 0 ? eo - 1 : eo]; if (e && e.nodeType == 3) return e.parentNode; return e; } }, getBookmark : function(type, normalized) { var t = this, dom = t.dom, rng, rng2, id, collapsed, name, element, index, chr = '\uFEFF', styles; function findIndex(name, element) { var index = 0; each(dom.select(name), function(node, i) { if (node == element) index = i; }); return index; }; if (type == 2) { function getLocation() { var rng = t.getRng(true), root = dom.getRoot(), bookmark = {}; function getPoint(rng, start) { var container = rng[start ? 'startContainer' : 'endContainer'], offset = rng[start ? 'startOffset' : 'endOffset'], point = [], node, childNodes, after = 0; if (container.nodeType == 3) { if (normalized) { for (node = container.previousSibling; node && node.nodeType == 3; node = node.previousSibling) offset += node.nodeValue.length; } point.push(offset); } else { childNodes = container.childNodes; if (offset >= childNodes.length && childNodes.length) { after = 1; offset = Math.max(0, childNodes.length - 1); } point.push(t.dom.nodeIndex(childNodes[offset], normalized) + after); } for (; container && container != root; container = container.parentNode) point.push(t.dom.nodeIndex(container, normalized)); return point; }; bookmark.start = getPoint(rng, true); if (!t.isCollapsed()) bookmark.end = getPoint(rng); return bookmark; }; return getLocation(); } // Handle simple range if (type) return {rng : t.getRng()}; rng = t.getRng(); id = dom.uniqueId(); collapsed = tinyMCE.activeEditor.selection.isCollapsed(); styles = 'overflow:hidden;line-height:0px'; // Explorer method if (rng.duplicate || rng.item) { // Text selection if (!rng.item) { rng2 = rng.duplicate(); // Insert start marker rng.collapse(); rng.pasteHTML('' + chr + ''); // Insert end marker if (!collapsed) { rng2.collapse(false); rng2.pasteHTML('' + chr + ''); } } else { // Control selection element = rng.item(0); name = element.nodeName; return {name : name, index : findIndex(name, element)}; } } else { element = t.getNode(); name = element.nodeName; if (name == 'IMG') return {name : name, index : findIndex(name, element)}; // W3C method rng2 = rng.cloneRange(); // Insert end marker if (!collapsed) { rng2.collapse(false); rng2.insertNode(dom.create('span', {_mce_type : "bookmark", id : id + '_end', style : styles}, chr)); } rng.collapse(true); rng.insertNode(dom.create('span', {_mce_type : "bookmark", id : id + '_start', style : styles}, chr)); } t.moveToBookmark({id : id, keep : 1}); return {id : id}; }, moveToBookmark : function(bookmark) { var t = this, dom = t.dom, marker1, marker2, rng, root, startContainer, endContainer, startOffset, endOffset; // Clear selection cache if (t.tridentSel) t.tridentSel.destroy(); if (bookmark) { if (bookmark.start) { rng = dom.createRng(); root = dom.getRoot(); function setEndPoint(start) { var point = bookmark[start ? 'start' : 'end'], i, node, offset, children; if (point) { // Find container node for (node = root, i = point.length - 1; i >= 1; i--) { children = node.childNodes; if (children.length) node = children[point[i]]; } // Set offset within container node if (start) rng.setStart(node, point[0]); else rng.setEnd(node, point[0]); } }; setEndPoint(true); setEndPoint(); t.setRng(rng); } else if (bookmark.id) { function restoreEndPoint(suffix) { var marker = dom.get(bookmark.id + '_' + suffix), node, idx, next, prev, keep = bookmark.keep; if (marker) { node = marker.parentNode; if (suffix == 'start') { if (!keep) { idx = dom.nodeIndex(marker); } else { node = marker.firstChild; idx = 1; } startContainer = endContainer = node; startOffset = endOffset = idx; } else { if (!keep) { idx = dom.nodeIndex(marker); } else { node = marker.firstChild; idx = 1; } endContainer = node; endOffset = idx; } if (!keep) { prev = marker.previousSibling; next = marker.nextSibling; // Remove all marker text nodes each(tinymce.grep(marker.childNodes), function(node) { if (node.nodeType == 3) node.nodeValue = node.nodeValue.replace(/\uFEFF/g, ''); }); // Remove marker but keep children if for example contents where inserted into the marker // Also remove duplicated instances of the marker for example by a split operation or by WebKit auto split on paste feature while (marker = dom.get(bookmark.id + '_' + suffix)) dom.remove(marker, 1); // If siblings are text nodes then merge them unless it's Opera since it some how removes the node // and we are sniffing since adding a lot of detection code for a browser with 3% of the market isn't worth the effort. Sorry, Opera but it's just a fact if (prev && next && prev.nodeType == next.nodeType && prev.nodeType == 3 && !tinymce.isOpera) { idx = prev.nodeValue.length; prev.appendData(next.nodeValue); dom.remove(next); if (suffix == 'start') { startContainer = endContainer = prev; startOffset = endOffset = idx; } else { endContainer = prev; endOffset = idx; } } } } }; function addBogus(node) { // Adds a bogus BR element for empty block elements // on non IE browsers just to have a place to put the caret if (!isIE && dom.isBlock(node) && !node.innerHTML) node.innerHTML = '
    '; return node; }; // Restore start/end points restoreEndPoint('start'); restoreEndPoint('end'); if (startContainer) { rng = dom.createRng(); rng.setStart(addBogus(startContainer), startOffset); rng.setEnd(addBogus(endContainer), endOffset); t.setRng(rng); } } else if (bookmark.name) { t.select(dom.select(bookmark.name)[bookmark.index]); } else if (bookmark.rng) t.setRng(bookmark.rng); } }, select : function(node, content) { var t = this, dom = t.dom, rng = dom.createRng(), idx; idx = dom.nodeIndex(node); rng.setStart(node.parentNode, idx); rng.setEnd(node.parentNode, idx + 1); // Find first/last text node or BR element if (content) { function setPoint(node, start) { var walker = new tinymce.dom.TreeWalker(node, node); do { // Text node if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) { if (start) rng.setStart(node, 0); else rng.setEnd(node, node.nodeValue.length); return; } // BR element if (node.nodeName == 'BR') { if (start) rng.setStartBefore(node); else rng.setEndBefore(node); return; } } while (node = (start ? walker.next() : walker.prev())); }; setPoint(node, 1); setPoint(node); } t.setRng(rng); return node; }, isCollapsed : function() { var t = this, r = t.getRng(), s = t.getSel(); if (!r || r.item) return false; if (r.compareEndPoints) return r.compareEndPoints('StartToEnd', r) === 0; return !s || r.collapsed; }, collapse : function(b) { var t = this, r = t.getRng(), n; // Control range on IE if (r.item) { n = r.item(0); r = this.win.document.body.createTextRange(); r.moveToElementText(n); } r.collapse(!!b); t.setRng(r); }, getSel : function() { var t = this, w = this.win; return w.getSelection ? w.getSelection() : w.document.selection; }, getRng : function(w3c) { var t = this, s, r, elm, doc = t.win.document; // Found tridentSel object then we need to use that one if (w3c && t.tridentSel) return t.tridentSel.getRangeAt(0); try { if (s = t.getSel()) r = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : doc.createRange()); } catch (ex) { // IE throws unspecified error here if TinyMCE is placed in a frame/iframe } // We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet if (tinymce.isIE && r.setStart && doc.selection.createRange().item) { elm = doc.selection.createRange().item(0); r = doc.createRange(); r.setStartBefore(elm); r.setEndAfter(elm); } // No range found then create an empty one // This can occur when the editor is placed in a hidden container element on Gecko // Or on IE when there was an exception if (!r) r = doc.createRange ? doc.createRange() : doc.body.createTextRange(); if (t.selectedRange && t.explicitRange) { if (r.compareBoundaryPoints(r.START_TO_START, t.selectedRange) === 0 && r.compareBoundaryPoints(r.END_TO_END, t.selectedRange) === 0) { // Safari, Opera and Chrome only ever select text which causes the range to change. // This lets us use the originally set range if the selection hasn't been changed by the user. r = t.explicitRange; } else { t.selectedRange = null; t.explicitRange = null; } } return r; }, setRng : function(r) { var s, t = this; if (!t.tridentSel) { s = t.getSel(); if (s) { t.explicitRange = r; s.removeAllRanges(); s.addRange(r); t.selectedRange = s.getRangeAt(0); } } else { // Is W3C Range if (r.cloneRange) { t.tridentSel.addRange(r); return; } // Is IE specific range try { r.select(); } catch (ex) { // Needed for some odd IE bug #1843306 } } }, setNode : function(n) { var t = this; t.setContent(t.dom.getOuterHTML(n)); return n; }, getNode : function() { var t = this, rng = t.getRng(), sel = t.getSel(), elm; if (rng.setStart) { // Range maybe lost after the editor is made visible again if (!rng) return t.dom.getRoot(); elm = rng.commonAncestorContainer; // Handle selection a image or other control like element such as anchors if (!rng.collapsed) { if (rng.startContainer == rng.endContainer) { if (rng.startOffset - rng.endOffset < 2) { if (rng.startContainer.hasChildNodes()) elm = rng.startContainer.childNodes[rng.startOffset]; } } // If the anchor node is a element instead of a text node then return this element if (tinymce.isWebKit && sel.anchorNode && sel.anchorNode.nodeType == 1) return sel.anchorNode.childNodes[sel.anchorOffset]; } if (elm && elm.nodeType == 3) return elm.parentNode; return elm; } return rng.item ? rng.item(0) : rng.parentElement(); }, getSelectedBlocks : function(st, en) { var t = this, dom = t.dom, sb, eb, n, bl = []; sb = dom.getParent(st || t.getStart(), dom.isBlock); eb = dom.getParent(en || t.getEnd(), dom.isBlock); if (sb) bl.push(sb); if (sb && eb && sb != eb) { n = sb; while ((n = n.nextSibling) && n != eb) { if (dom.isBlock(n)) bl.push(n); } } if (eb && sb != eb) bl.push(eb); return bl; }, destroy : function(s) { var t = this; t.win = null; if (t.tridentSel) t.tridentSel.destroy(); // Manual destroy then remove unload handler if (!s) tinymce.removeUnload(t.destroy); }, // IE has an issue where you can't select/move the caret by clicking outside the body if the document is in standards mode _fixIESelection : function() { var dom = this.dom, doc = dom.doc, body = doc.body, started, startRng; // Make HTML element unselectable since we are going to handle selection by hand doc.documentElement.unselectable = true; // Return range from point or null if it failed function rngFromPoint(x, y) { var rng = body.createTextRange(); try { rng.moveToPoint(x, y); } catch (ex) { // IE sometimes throws and exception, so lets just ignore it rng = null; } return rng; }; // Fires while the selection is changing function selectionChange(e) { var pointRng; // Check if the button is down or not if (e.button) { // Create range from mouse position pointRng = rngFromPoint(e.x, e.y); if (pointRng) { // Check if pointRange is before/after selection then change the endPoint if (pointRng.compareEndPoints('StartToStart', startRng) > 0) pointRng.setEndPoint('StartToStart', startRng); else pointRng.setEndPoint('EndToEnd', startRng); pointRng.select(); } } else endSelection(); } // Removes listeners function endSelection() { dom.unbind(doc, 'mouseup', endSelection); dom.unbind(doc, 'mousemove', selectionChange); started = 0; }; // Detect when user selects outside BODY dom.bind(doc, 'mousedown', function(e) { if (e.target.nodeName === 'HTML') { if (started) endSelection(); started = 1; // Setup start position startRng = rngFromPoint(e.x, e.y); if (startRng) { // Listen for selection change events dom.bind(doc, 'mouseup', endSelection); dom.bind(doc, 'mousemove', selectionChange); dom.win.focus(); startRng.select(); } } }); } }); })(tinymce); (function(tinymce) { tinymce.create('tinymce.dom.XMLWriter', { node : null, XMLWriter : function(s) { // Get XML document function getXML() { var i = document.implementation; if (!i || !i.createDocument) { // Try IE objects try {return new ActiveXObject('MSXML2.DOMDocument');} catch (ex) {} try {return new ActiveXObject('Microsoft.XmlDom');} catch (ex) {} } else return i.createDocument('', '', null); }; this.doc = getXML(); // Since Opera and WebKit doesn't escape > into > we need to do it our self to normalize the output for all browsers this.valid = tinymce.isOpera || tinymce.isWebKit; this.reset(); }, reset : function() { var t = this, d = t.doc; if (d.firstChild) d.removeChild(d.firstChild); t.node = d.appendChild(d.createElement("html")); }, writeStartElement : function(n) { var t = this; t.node = t.node.appendChild(t.doc.createElement(n)); }, writeAttribute : function(n, v) { if (this.valid) v = v.replace(/>/g, '%MCGT%'); this.node.setAttribute(n, v); }, writeEndElement : function() { this.node = this.node.parentNode; }, writeFullEndElement : function() { var t = this, n = t.node; n.appendChild(t.doc.createTextNode("")); t.node = n.parentNode; }, writeText : function(v) { if (this.valid) v = v.replace(/>/g, '%MCGT%'); this.node.appendChild(this.doc.createTextNode(v)); }, writeCDATA : function(v) { this.node.appendChild(this.doc.createCDATASection(v)); }, writeComment : function(v) { // Fix for bug #2035694 if (tinymce.isIE) v = v.replace(/^\-|\-$/g, ' '); this.node.appendChild(this.doc.createComment(v.replace(/\-\-/g, ' '))); }, getContent : function() { var h; h = this.doc.xml || new XMLSerializer().serializeToString(this.doc); h = h.replace(/<\?[^?]+\?>|]*>|<\/html>||]+>/g, ''); h = h.replace(/ ?\/>/g, ' />'); if (this.valid) h = h.replace(/\%MCGT%/g, '>'); return h; } }); })(tinymce); (function(tinymce) { var attrsCharsRegExp = /[&\"<>]/g, textCharsRegExp = /[<>&]/g, encodedChars = {'&' : '&', '"' : '"', '<' : '<', '>' : '>'}; tinymce.create('tinymce.dom.StringWriter', { str : null, tags : null, count : 0, settings : null, indent : null, StringWriter : function(s) { this.settings = tinymce.extend({ indent_char : ' ', indentation : 0 }, s); this.reset(); }, reset : function() { this.indent = ''; this.str = ""; this.tags = []; this.count = 0; }, writeStartElement : function(n) { this._writeAttributesEnd(); this.writeRaw('<' + n); this.tags.push(n); this.inAttr = true; this.count++; this.elementCount = this.count; this.attrs = {}; }, writeAttribute : function(n, v) { var t = this; if (!t.attrs[n]) { t.writeRaw(" " + t.encode(n, true) + '="' + t.encode(v, true) + '"'); t.attrs[n] = v; } }, writeEndElement : function() { var n; if (this.tags.length > 0) { n = this.tags.pop(); if (this._writeAttributesEnd(1)) this.writeRaw(''); if (this.settings.indentation > 0) this.writeRaw('\n'); } }, writeFullEndElement : function() { if (this.tags.length > 0) { this._writeAttributesEnd(); this.writeRaw(''); if (this.settings.indentation > 0) this.writeRaw('\n'); } }, writeText : function(v) { this._writeAttributesEnd(); this.writeRaw(this.encode(v)); this.count++; }, writeCDATA : function(v) { this._writeAttributesEnd(); this.writeRaw(''); this.count++; }, writeComment : function(v) { this._writeAttributesEnd(); this.writeRaw(''); this.count++; }, writeRaw : function(v) { this.str += v; }, encode : function(s, attr) { return s.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(v) { return encodedChars[v]; }); }, getContent : function() { return this.str; }, _writeAttributesEnd : function(s) { if (!this.inAttr) return; this.inAttr = false; if (s && this.elementCount == this.count) { this.writeRaw(' />'); return false; } this.writeRaw('>'); return true; } }); })(tinymce); (function(tinymce) { // Shorten names var extend = tinymce.extend, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, isIE = tinymce.isIE, isGecko = tinymce.isGecko; function wildcardToRE(s) { return s.replace(/([?+*])/g, '.$1'); }; tinymce.create('tinymce.dom.Serializer', { Serializer : function(s) { var t = this; t.key = 0; t.onPreProcess = new Dispatcher(t); t.onPostProcess = new Dispatcher(t); try { t.writer = new tinymce.dom.XMLWriter(); } catch (ex) { // IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter t.writer = new tinymce.dom.StringWriter(); } // IE9 broke the XML attributes order so it can't be used anymore if (tinymce.isIE && document.documentMode > 8) { t.writer = new tinymce.dom.StringWriter(); } // Default settings t.settings = s = extend({ dom : tinymce.DOM, valid_nodes : 0, node_filter : 0, attr_filter : 0, invalid_attrs : /^(_mce_|_moz_|sizset|sizcache)/, closed : /^(br|hr|input|meta|img|link|param|area)$/, entity_encoding : 'named', entities : '160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro', valid_elements : '*[*]', extended_valid_elements : 0, invalid_elements : 0, fix_table_elements : 1, fix_list_elements : true, fix_content_duplication : true, convert_fonts_to_spans : false, font_size_classes : 0, apply_source_formatting : 0, indent_mode : 'simple', indent_char : '\t', indent_levels : 1, remove_linebreaks : 1, remove_redundant_brs : 1, element_format : 'xhtml' }, s); t.dom = s.dom; t.schema = s.schema; // Use raw entities if no entities are defined if (s.entity_encoding == 'named' && !s.entities) s.entity_encoding = 'raw'; if (s.remove_redundant_brs) { t.onPostProcess.add(function(se, o) { // Remove single BR at end of block elements since they get rendered o.content = o.content.replace(/(
    \s*)+<\/(p|h[1-6]|div|li)>/gi, function(a, b, c) { // Check if it's a single element if (/^
    \s*<\//.test(a)) return ''; return a; }); }); } // Remove XHTML element endings i.e. produce crap :) XHTML is better if (s.element_format == 'html') { t.onPostProcess.add(function(se, o) { o.content = o.content.replace(/<([^>]+) \/>/g, '<$1>'); }); } if (s.fix_list_elements) { t.onPreProcess.add(function(se, o) { var nl, x, a = ['ol', 'ul'], i, n, p, r = /^(OL|UL)$/, np; function prevNode(e, n) { var a = n.split(','), i; while ((e = e.previousSibling) != null) { for (i=0; i 1) { each(p[1].split('|'), function(s) { var ar = {}, i; at = at || []; // Parse attribute rule s = s.replace(/::/g, '~'); s = /^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/.exec(s); s[2] = s[2].replace(/~/g, ':'); // Add required attributes if (s[1] == '!') { ra = ra || []; ra.push(s[2]); } // Remove inherited attributes if (s[1] == '-') { for (i = 0; i ]*>)(.*?)(<\/script>)/g}, {pattern : /(]*>)(.*?)(<\/noscript>)/g}, {pattern : /(]*>)(.*?)(<\/style>)/g}, {pattern : /(]*>)(.*?)(<\/pre>)/g, encode : 1}, {pattern : /()/g} ] }); h = p.content; // Entity encode if (s.entity_encoding !== 'raw') h = t._encode(h); // Use BR instead of   padded P elements inside editor and use

     

    outside editor /* if (o.set) h = h.replace(/

    \s+( | |\u00a0|
    )\s+<\/p>/g, '


    '); else h = h.replace(/

    \s+( | |\u00a0|
    )\s+<\/p>/g, '

    $1

    ');*/ // Since Gecko and Safari keeps whitespace in the DOM we need to // remove it inorder to match other browsers. But I think Gecko and Safari is right. // This process is only done when getting contents out from the editor. if (!o.set) { // We need to replace paragraph whitespace with an nbsp before indentation to keep the \u00a0 char h = tinymce._replace(/

    \s+<\/p>|]+)>\s+<\/p>/g, s.entity_encoding == 'numeric' ? ' 

    ' : ' 

    ', h); if (s.remove_linebreaks) { h = h.replace(/\r?\n|\r/g, ' '); h = tinymce._replace(/(<[^>]+>)\s+/g, '$1 ', h); h = tinymce._replace(/\s+(<\/[^>]+>)/g, ' $1', h); h = tinymce._replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g, '<$1 $2>', h); // Trim block start h = tinymce._replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g, '<$1>', h); // Trim block start h = tinymce._replace(/\s+<\/(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g, '', h); // Trim block end } // Simple indentation if (s.apply_source_formatting && s.indent_mode == 'simple') { // Add line breaks before and after block elements h = tinymce._replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g, '\n<$1$2$3>\n', h); h = tinymce._replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>', h); h = tinymce._replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g, '\n', h); h = h.replace(/\n\n/g, '\n'); } } h = t._unprotect(h, p); // Restore CDATA sections h = tinymce._replace(//g, '', h); // Restore the \u00a0 character if raw mode is enabled if (s.entity_encoding == 'raw') h = tinymce._replace(/

     <\/p>|]+)> <\/p>/g, '\u00a0

    ', h); // Restore noscript elements h = h.replace(/]+|)>([\s\S]*?)<\/noscript>/g, function(v, attribs, text) { return '' + t.dom.decode(text.replace(//g, '')) + ''; }); } o.content = h; }, _serializeNode : function(n, inner) { var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv, closed, keep, type, scopeName; if (!s.node_filter || s.node_filter(n)) { switch (n.nodeType) { case 1: // Element if (n.hasAttribute ? n.hasAttribute('_mce_bogus') : n.getAttribute('_mce_bogus')) return; iv = keep = false; hc = n.hasChildNodes(); nn = n.getAttribute('_mce_name') || n.nodeName.toLowerCase(); // Get internal type type = n.getAttribute('_mce_type'); if (type) { if (!t._info.cleanup) { iv = true; return; } else keep = 1; } // Add correct prefix on IE if (isIE) { scopeName = n.scopeName; if (scopeName && scopeName !== 'HTML' && scopeName !== 'html') nn = scopeName + ':' + nn; } // Remove mce prefix on IE needed for the abbr element if (nn.indexOf('mce:') === 0) nn = nn.substring(4); // Check if valid if (!keep) { if (!t.validElementsRE || !t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inner) { iv = true; break; } } if (isIE) { // Fix IE content duplication (DOM can have multiple copies of the same node) if (s.fix_content_duplication) { if (n._mce_serialized == t.key) return; n._mce_serialized = t.key; } // IE sometimes adds a / infront of the node name if (nn.charAt(0) == '/') nn = nn.substring(1); } else if (isGecko) { // Ignore br elements if (n.nodeName === 'BR' && n.getAttribute('type') == '_moz') return; } // Check if valid child if (s.validate_children) { if (t.elementName && !t.schema.isValid(t.elementName, nn)) { iv = true; break; } t.elementName = nn; } ru = t.findRule(nn); // No valid rule for this element could be found then skip it if (!ru) { iv = true; break; } nn = ru.name || nn; closed = s.closed.test(nn); // Skip empty nodes or empty node name in IE if ((!hc && ru.noEmpty) || (isIE && !nn)) { iv = true; break; } // Check required if (ru.requiredAttribs) { a = ru.requiredAttribs; for (i = a.length - 1; i >= 0; i--) { if (this.dom.getAttrib(n, a[i]) !== '') break; } // None of the required was there if (i == -1) { iv = true; break; } } w.writeStartElement(nn); // Add ordered attributes if (ru.attribs) { for (i=0, at = ru.attribs, l = at.length; i-1; i--) { no = at[i]; if (no.specified) { a = no.nodeName.toLowerCase(); if (s.invalid_attrs.test(a) || !ru.validAttribsRE.test(a)) continue; ar = t.findAttribRule(ru, a); v = t._getAttrib(n, ar, a); if (v !== null) w.writeAttribute(a, v); } } } // Keep type attribute if (type && keep) w.writeAttribute('_mce_type', type); // Write text from script if (nn === 'script' && tinymce.trim(n.innerHTML)) { w.writeText('// '); // Padd it with a comment so it will parse on older browsers w.writeCDATA(n.innerHTML.replace(/|<\[CDATA\[|\]\]>/g, '')); // Remove comments and cdata stuctures hc = false; break; } // Padd empty nodes with a   if (ru.padd) { // If it has only one bogus child, padd it anyway workaround for
    bug if (hc && (cn = n.firstChild) && cn.nodeType === 1 && n.childNodes.length === 1) { if (cn.hasAttribute ? cn.hasAttribute('_mce_bogus') : cn.getAttribute('_mce_bogus')) w.writeText('\u00a0'); } else if (!hc) w.writeText('\u00a0'); // No children then padd it } break; case 3: // Text // Check if valid child if (s.validate_children && t.elementName && !t.schema.isValid(t.elementName, '#text')) return; return w.writeText(n.nodeValue); case 4: // CDATA return w.writeCDATA(n.nodeValue); case 8: // Comment return w.writeComment(n.nodeValue); } } else if (n.nodeType == 1) hc = n.hasChildNodes(); if (hc && !closed) { cn = n.firstChild; while (cn) { t._serializeNode(cn); t.elementName = nn; cn = cn.nextSibling; } } // Write element end if (!iv) { if (!closed) w.writeFullEndElement(); else w.writeEndElement(); } }, _protect : function(o) { var t = this; o.items = o.items || []; function enc(s) { return s.replace(/[\r\n\\]/g, function(c) { if (c === '\n') return '\\n'; else if (c === '\\') return '\\\\'; return '\\r'; }); }; function dec(s) { return s.replace(/\\[\\rn]/g, function(c) { if (c === '\\n') return '\n'; else if (c === '\\\\') return '\\'; return '\r'; }); }; each(o.patterns, function(p) { o.content = dec(enc(o.content).replace(p.pattern, function(x, a, b, c) { b = dec(b); if (p.encode) b = t._encode(b); o.items.push(b); return a + '' + c; })); }); return o; }, _unprotect : function(h, o) { h = h.replace(/\')); } // Add toolbar end before list box and after the previous button // This is to fix the o2k7 editor skins if (pr && co.ListBox) { if (pr.Button || pr.SplitButton) h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '')); } // Render control HTML // IE 8 quick fix, needed to propertly generate a hit area for anchors if (dom.stdMode) h += '' + co.renderHTML() + ''; else h += '' + co.renderHTML() + ''; // Add toolbar start after list box and before the next button // This is to fix the o2k7 editor skins if (nx && co.ListBox) { if (nx.Button || nx.SplitButton) h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '')); } } c = 'mceToolbarEnd'; if (co.Button) c += ' mceToolbarEndButton'; else if (co.SplitButton) c += ' mceToolbarEndSplitButton'; else if (co.ListBox) c += ' mceToolbarEndListBox'; h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '')); return dom.createHTML('table', {id : t.id, 'class' : 'mceToolbar' + (s['class'] ? ' ' + s['class'] : ''), cellpadding : '0', cellspacing : '0', align : t.settings.align || ''}, '' + h + ''); } }); (function(tinymce) { var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each; tinymce.create('tinymce.AddOnManager', { AddOnManager : function() { var self = this; self.items = []; self.urls = {}; self.lookup = {}; self.onAdd = new Dispatcher(self); }, get : function(n) { return this.lookup[n]; }, requireLangPack : function(n) { var s = tinymce.settings; if (s && s.language) tinymce.ScriptLoader.add(this.urls[n] + '/langs/' + s.language + '.js'); }, add : function(id, o) { this.items.push(o); this.lookup[id] = o; this.onAdd.dispatch(this, id, o); return o; }, load : function(n, u, cb, s) { var t = this; if (t.urls[n]) return; if (u.indexOf('/') != 0 && u.indexOf('://') == -1) u = tinymce.baseURL + '/' + u; t.urls[n] = u.substring(0, u.lastIndexOf('/')); if (!t.lookup[n]) tinymce.ScriptLoader.add(u, cb, s); } }); // Create plugin and theme managers tinymce.PluginManager = new tinymce.AddOnManager(); tinymce.ThemeManager = new tinymce.AddOnManager(); }(tinymce)); (function(tinymce) { // Shorten names var each = tinymce.each, extend = tinymce.extend, DOM = tinymce.DOM, Event = tinymce.dom.Event, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, explode = tinymce.explode, Dispatcher = tinymce.util.Dispatcher, undefined, instanceCounter = 0; // Setup some URLs where the editor API is located and where the document is tinymce.documentBaseURL = window.location.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, ''); if (!/[\/\\]$/.test(tinymce.documentBaseURL)) tinymce.documentBaseURL += '/'; tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL); tinymce.baseURI = new tinymce.util.URI(tinymce.baseURL); // Add before unload listener // This was required since IE was leaking memory if you added and removed beforeunload listeners // with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event tinymce.onBeforeUnload = new Dispatcher(tinymce); // Must be on window or IE will leak if the editor is placed in frame or iframe Event.add(window, 'beforeunload', function(e) { tinymce.onBeforeUnload.dispatch(tinymce, e); }); tinymce.onAddEditor = new Dispatcher(tinymce); tinymce.onRemoveEditor = new Dispatcher(tinymce); tinymce.EditorManager = extend(tinymce, { editors : [], i18n : {}, activeEditor : null, init : function(s) { var t = this, pl, sl = tinymce.ScriptLoader, e, el = [], ed; function execCallback(se, n, s) { var f = se[n]; if (!f) return; if (tinymce.is(f, 'string')) { s = f.replace(/\.\w+$/, ''); s = s ? tinymce.resolve(s) : 0; f = tinymce.resolve(f); } return f.apply(s || this, Array.prototype.slice.call(arguments, 2)); }; s = extend({ theme : "simple", language : "en" }, s); t.settings = s; // Legacy call Event.add(document, 'init', function() { var l, co; execCallback(s, 'onpageload'); switch (s.mode) { case "exact": l = s.elements || ''; if(l.length > 0) { each(explode(l), function(v) { if (DOM.get(v)) { ed = new tinymce.Editor(v, s); el.push(ed); ed.render(1); } else { each(document.forms, function(f) { each(f.elements, function(e) { if (e.name === v) { v = 'mce_editor_' + instanceCounter++; DOM.setAttrib(e, 'id', v); ed = new tinymce.Editor(v, s); el.push(ed); ed.render(1); } }); }); } }); } break; case "textareas": case "specific_textareas": function hasClass(n, c) { return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c); }; each(DOM.select('textarea'), function(v) { if (s.editor_deselector && hasClass(v, s.editor_deselector)) return; if (!s.editor_selector || hasClass(v, s.editor_selector)) { // Can we use the name e = DOM.get(v.name); if (!v.id && !e) v.id = v.name; // Generate unique name if missing or already exists if (!v.id || t.get(v.id)) v.id = DOM.uniqueId(); ed = new tinymce.Editor(v.id, s); el.push(ed); ed.render(1); } }); break; } // Call onInit when all editors are initialized if (s.oninit) { l = co = 0; each(el, function(ed) { co++; if (!ed.initialized) { // Wait for it ed.onInit.add(function() { l++; // All done if (l == co) execCallback(s, 'oninit'); }); } else l++; // All done if (l == co) execCallback(s, 'oninit'); }); } }); }, get : function(id) { if (id === undefined) return this.editors; return this.editors[id]; }, getInstanceById : function(id) { return this.get(id); }, add : function(editor) { var self = this, editors = self.editors; // Add named and index editor instance editors[editor.id] = editor; editors.push(editor); self._setActive(editor); self.onAddEditor.dispatch(self, editor); return editor; }, remove : function(editor) { var t = this, i, editors = t.editors; // Not in the collection if (!editors[editor.id]) return null; delete editors[editor.id]; for (i = 0; i < editors.length; i++) { if (editors[i] == editor) { editors.splice(i, 1); break; } } // Select another editor since the active one was removed if (t.activeEditor == editor) t._setActive(editors[0]); editor.destroy(); t.onRemoveEditor.dispatch(t, editor); return editor; }, execCommand : function(c, u, v) { var t = this, ed = t.get(v), w; // Manager commands switch (c) { case "mceFocus": ed.focus(); return true; case "mceAddEditor": case "mceAddControl": if (!t.get(v)) new tinymce.Editor(v, t.settings).render(); return true; case "mceAddFrameControl": w = v.window; // Add tinyMCE global instance and tinymce namespace to specified window w.tinyMCE = tinyMCE; w.tinymce = tinymce; tinymce.DOM.doc = w.document; tinymce.DOM.win = w; ed = new tinymce.Editor(v.element_id, v); ed.render(); // Fix IE memory leaks if (tinymce.isIE) { function clr() { ed.destroy(); w.detachEvent('onunload', clr); w = w.tinyMCE = w.tinymce = null; // IE leak }; w.attachEvent('onunload', clr); } v.page_window = null; return true; case "mceRemoveEditor": case "mceRemoveControl": if (ed) ed.remove(); return true; case 'mceToggleEditor': if (!ed) { t.execCommand('mceAddControl', 0, v); return true; } if (ed.isHidden()) ed.show(); else ed.hide(); return true; } // Run command on active editor if (t.activeEditor) return t.activeEditor.execCommand(c, u, v); return false; }, execInstanceCommand : function(id, c, u, v) { var ed = this.get(id); if (ed) return ed.execCommand(c, u, v); return false; }, triggerSave : function() { each(this.editors, function(e) { e.save(); }); }, addI18n : function(p, o) { var lo, i18n = this.i18n; if (!tinymce.is(p, 'string')) { each(p, function(o, lc) { each(o, function(o, g) { each(o, function(o, k) { if (g === 'common') i18n[lc + '.' + k] = o; else i18n[lc + '.' + g + '.' + k] = o; }); }); }); } else { each(o, function(o, k) { i18n[p + '.' + k] = o; }); } }, // Private methods _setActive : function(editor) { this.selectedInstance = this.activeEditor = editor; } }); })(tinymce); (function(tinymce) { // Shorten these names var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isGecko = tinymce.isGecko, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, is = tinymce.is, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, inArray = tinymce.inArray, grep = tinymce.grep, explode = tinymce.explode; tinymce.create('tinymce.Editor', { Editor : function(id, s) { var t = this; t.id = t.editorId = id; t.execCommands = {}; t.queryStateCommands = {}; t.queryValueCommands = {}; t.isNotDirty = false; t.plugins = {}; // Add events to the editor each([ 'onPreInit', 'onBeforeRenderUI', 'onPostRender', 'onInit', 'onRemove', 'onActivate', 'onDeactivate', 'onClick', 'onEvent', 'onMouseUp', 'onMouseDown', 'onDblClick', 'onKeyDown', 'onKeyUp', 'onKeyPress', 'onContextMenu', 'onSubmit', 'onReset', 'onPaste', 'onPreProcess', 'onPostProcess', 'onBeforeSetContent', 'onBeforeGetContent', 'onSetContent', 'onGetContent', 'onLoadContent', 'onSaveContent', 'onNodeChange', 'onChange', 'onBeforeExecCommand', 'onExecCommand', 'onUndo', 'onRedo', 'onVisualAid', 'onSetProgressState' ], function(e) { t[e] = new Dispatcher(t); }); t.settings = s = extend({ id : id, language : 'en', docs_language : 'en', theme : 'simple', skin : 'default', delta_width : 0, delta_height : 0, popup_css : '', plugins : '', document_base_url : tinymce.documentBaseURL, add_form_submit_trigger : 1, submit_patch : 1, add_unload_trigger : 1, convert_urls : 1, relative_urls : 1, remove_script_host : 1, table_inline_editing : 0, object_resizing : 1, cleanup : 1, accessibility_focus : 1, custom_shortcuts : 1, custom_undo_redo_keyboard_shortcuts : 1, custom_undo_redo_restore_selection : 1, custom_undo_redo : 1, doctype : tinymce.isIE6 ? '' : '', // Use old doctype on IE 6 to avoid horizontal scroll visual_table_class : 'mceItemTable', visual : 1, font_size_style_values : 'xx-small,x-small,small,medium,large,x-large,xx-large', apply_source_formatting : 1, directionality : 'ltr', forced_root_block : 'p', valid_elements : '@[id|class|style|title|dir
    '; } el.innerHTML = h; } function generateWebColors() { var el = document.getElementById('webcolors'), h = '', i; if (el.className == 'generated') return; h += '' + ''; for (i=0; i' + '' + '' + colors[i] +  ''; if ((i+1) % 18 == 0) h += ''; } h += '
    '; el.innerHTML = h; el.className = 'generated'; } function generateNamedColors() { var el = document.getElementById('namedcolors'), h = '', n, v, i = 0; if (el.className == 'generated') return; for (n in named) { v = named[n]; h += '' } el.innerHTML = h; el.className = 'generated'; } function selectColor() { var color = document.getElementById("color").value; if(window.opener) window.opener.tinyMCE.execInstanceCommand(tinyMCE.getWindowArg('editor_id'),tinyMCE.getWindowArg('command'),false,color); window.close(); } function dechex(n) { return strhex.charAt(Math.floor(n / 16)) + strhex.charAt(n % 16); } function computeColor(e) { var x, y, partWidth, partDetail, imHeight, r, g, b, coef, i, finalCoef, finalR, finalG, finalB; x = e.offsetX ? e.offsetX : (e.target ? e.clientX - e.target.x : 0); y = e.offsetY ? e.offsetY : (e.target ? e.clientY - e.target.y : 0); partWidth = document.getElementById('colorpicker').width / 6; partDetail = detail / 2; imHeight = document.getElementById('colorpicker').height; r = (x >= 0)*(x < partWidth)*255 + (x >= partWidth)*(x < 2*partWidth)*(2*255 - x * 255 / partWidth) + (x >= 4*partWidth)*(x < 5*partWidth)*(-4*255 + x * 255 / partWidth) + (x >= 5*partWidth)*(x < 6*partWidth)*255; g = (x >= 0)*(x < partWidth)*(x * 255 / partWidth) + (x >= partWidth)*(x < 3*partWidth)*255 + (x >= 3*partWidth)*(x < 4*partWidth)*(4*255 - x * 255 / partWidth); b = (x >= 2*partWidth)*(x < 3*partWidth)*(-2*255 + x * 255 / partWidth) + (x >= 3*partWidth)*(x < 5*partWidth)*255 + (x >= 5*partWidth)*(x < 6*partWidth)*(6*255 - x * 255 / partWidth); coef = (imHeight - y) / imHeight; r = 128 + (r - 128) * coef; g = 128 + (g - 128) * coef; b = 128 + (b - 128) * coef; changeFinalColor('#' + dechex(r) + dechex(g) + dechex(b)); updateLight(r, g, b); } function updateLight(r, g, b) { var i, partDetail = detail / 2, finalCoef, finalR, finalG, finalB, color; for (i=0; i=0) && (i/g, '>'); // Fix for bug #1447335 if (tinyMCE.isGecko) html = ''; else html = ''; tinyMCEPopup.execCommand("mceInsertContent", false, html); // Fix for bug #1447335 force cursor after the anchor element if (tinyMCE.isGecko) { e = inst.getDoc().getElementById('mceNewAnchor'); if (e) { inst.selection.selectNode(e, true, false, false); e.removeAttribute('id'); } } tinyMCE.handleVisualAid(inst.getBody(), true, inst.visualAid, inst); } tinyMCEPopup.execCommand("mceEndUndoLevel"); tinyMCE.triggerNodeChange(); tinyMCEPopup.close(); } openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/0000755000175000017500000000000011724401447033464 5ustar frankiefrankie././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/sr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/s0000644000175000017500000000334111226234200033636 0ustar frankiefrankietinyMCE.addI18n('sr.openacs_dlg',{ about_title:"TinyMCE", about_general:"O programu", about_help:"Pomo\u0107", about_license:"Licenca", about_plugins:"Dodaci", about_plugin:"Dodatak", about_author:"Autor", about_version:"Verzija", about_loaded:"Postoje\u0107i dodaci", anchor_title:"Umetni/uredi sidro", anchor_name:"Ime sidra", code_title:"HTML ure\u0111iva\u010D", code_wordwrap:"Omatanje teksta", colorpicker_title:"Izbor boje", colorpicker_picker_tab:"Odabir", colorpicker_picker_title:"Odabir boje", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Paleta boja", colorpicker_named_tab:"Imenovano", colorpicker_named_title:"Imenovane boje", colorpicker_color:"Boja:", colorpicker_name:"Naziv:", charmap_title:"Odaberite znak", image_title:"Umetni/uredi sliku", image_src:"URL slike", image_alt:"Opis slike", image_list:"Lista slika", image_border:"Obrub", image_dimensions:"Dimenzije", image_vspace:"Okomiti razmak", image_hspace:"Vodoravni razmak", image_align:"Poravnavanje", image_align_baseline:"Osnovna linija", image_align_top:"Vrh", image_align_middle:"Sredina", image_align_bottom:"Dno", image_align_texttop:"Vrh teksta", image_align_textbottom:"Dno teksta", image_align_left:"Levo", image_align_right:"Desno", link_title:"Umetni/uredi poveznicu", link_url:"URL poveznice", link_target:"Meta", link_target_same:"Otvori poveznicu u istom prozoru", link_target_blank:"Otvori poveznicu u novom prozoru", link_titlefield:"Naslov", link_is_email:"URL koji ste uneli izgleda kao e-mail adresa, \u017Eelite li dodati potrebni mailto: prefiks?", link_is_external:"URL koji ste uneli izgleda kao vanjska poveznica, \u017Eelite li dodati potrebni http:// prefiks?", link_list:"Lista poveznica" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/bg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/b0000644000175000017500000001556711226234177033647 0ustar frankiefrankietinyMCE.addI18n('bg.openacs',{ style_select:"\u0421\u0442\u0438\u043B\u043E\u0432\u0435", font_size:"\u0420\u0430\u0437\u043C\u0435\u0440 \u043D\u0430 \u0448\u0440\u0438\u0444\u0442\u0430", fontdefault:"\u0428\u0440\u0438\u0444\u0442", block:"\u0424\u043E\u0440\u043C\u0430\u0442", paragraph:"\u041F\u0430\u0440\u0430\u0433\u0440\u0430\u0444", div:"Div", address:"\u0410\u0434\u0440\u0435\u0441", pre:"\u041F\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043B\u043D\u043E \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u0430\u043D", h1:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435 1", h2:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435 2", h3:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435 3", h4:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435 4", h5:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435 5", h6:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435 6", blockquote:"\u0426\u0438\u0442\u0430\u0442", code:"\u041A\u043E\u0434", samp:"\u041F\u0440\u043E\u043C\u0435\u0440\u0435\u043D \u043A\u043E\u0434", dt:"\u0414\u0435\u0444\u0438\u043D\u0438\u0446\u0438\u044F ", dd:"\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043D\u0430 \u0434\u0435\u0444\u0438\u043D\u0438\u0446\u0438\u044F", bold_desc:"\u041F\u043E\u043B\u0443\u0447\u0435\u0440 (Ctrl+B)", italic_desc:"\u041A\u0443\u0440\u0441\u0438\u0432 (Ctrl+I)", underline_desc:"\u041F\u043E\u0434\u0447\u0435\u0440\u0442\u0430\u043D (Ctrl+U)", striketrough_desc:"\u0417\u0430\u0447\u0435\u0440\u0442\u0430\u043D", justifyleft_desc:"\u041F\u043E\u0434\u0440\u0430\u0432\u043D\u044F\u0432\u0430\u043D\u0435 \u043E\u0442\u043B\u044F\u0432\u043E", justifycenter_desc:"\u0426\u0435\u043D\u0442\u0440\u0438\u0440\u0430\u043D\u043E", justifyright_desc:"\u041F\u043E\u0434\u0440\u0430\u0432\u043D\u044F\u0432\u0430\u043D\u0435 \u043E\u0442\u0434\u044F\u0441\u043D\u043E", justifyfull_desc:"\u0414\u0432\u0443\u0441\u0442\u0440\u0430\u043D\u043D\u043E", bullist_desc:"\u0412\u043E\u0434\u0430\u0447\u0438", numlist_desc:"\u041D\u043E\u043C\u0435\u0440\u0430", outdent_desc:"\u041D\u0430\u043C\u0430\u043B\u044F\u0432\u0430\u043D\u0435 \u043D\u0430 \u043E\u0442\u0441\u0442\u044A\u043F\u0430", indent_desc:"\u0423\u0432\u0435\u043B\u0438\u0447\u0430\u0432\u0430\u043D\u0435 \u043D\u0430 \u043E\u0442\u0441\u0442\u044A\u043F\u0430", undo_desc:"\u041E\u0442\u043C\u044F\u043D\u0430 (Ctrl+Z)", redo_desc:"\u0412\u044A\u0437\u0441\u0442\u0430\u043D\u043E\u0432\u044F\u0432\u0430\u043D\u0435 (Ctrl+Y)", link_desc:"\u0412\u043C\u044A\u043A\u0432\u0430\u043D\u0435/\u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F \u043D\u0430 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430", unlink_desc:"\u041F\u0440\u0435\u043C\u0430\u0445\u043D\u0438 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430", image_desc:"\u0412\u043C\u044A\u043A\u0432\u0430\u043D\u0435/\u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F \u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430", cleanup_desc:"\u0418\u0437\u0447\u0438\u0441\u0442\u0438 \u043A\u043E\u0434\u0430", code_desc:"\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u0430\u0439 HTML", sub_desc:"\u0414\u043E\u043B\u0435\u043D \u0438\u043D\u0434\u0435\u043A\u0441", sup_desc:"\u0413\u043E\u0440\u0435\u043D \u0438\u043D\u0434\u0435\u043A\u0441", hr_desc:"\u0412\u043C\u044A\u043A\u043D\u0438 \u0445\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u043D\u0430 \u043B\u0438\u043D\u0438\u044F", removeformat_desc:"\u041F\u0440\u0435\u043C\u0430\u0445\u043D\u0438 \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u0430\u043D\u0435\u0442\u043E", custom1_desc:"\u0412\u0430\u0448\u0435\u0442\u043E \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0442\u0443\u043A", forecolor_desc:"\u0418\u0437\u0431\u0435\u0440\u0438 \u0446\u0432\u044F\u0442 \u043D\u0430 \u0442\u0435\u043A\u0441\u0442\u0430", backcolor_desc:"\u0418\u0437\u0431\u0435\u0440\u0438 \u0446\u0432\u044F\u0442 \u043D\u0430 \u0444\u043E\u043D\u0430", charmap_desc:"\u0412\u043C\u044A\u043A\u043D\u0438 \u0441\u0438\u043C\u0432\u043E\u043B", visualaid_desc:"\u0412\u043A\u043B./\u0438\u0437\u043A\u043B. \u043D\u0435\u0432\u0438\u0434\u0438\u043C\u0438\u0442\u0435 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438", anchor_desc:"\u0412\u043C\u044A\u043A\u043D\u0438/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u0430\u0439 \u043A\u043E\u0442\u0432\u0430", cut_desc:"\u0418\u0437\u0440\u044F\u0437\u0432\u0430\u043D\u0435", copy_desc:"\u041A\u043E\u043F\u0438\u0440\u0430\u043D\u0435", paste_desc:"\u041F\u043E\u0441\u0442\u0430\u0432\u044F\u043D\u0435", image_props_desc:"\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u0430 \u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430\u0442\u0430", newdocument_desc:"\u041D\u043E\u0432 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442", help_desc:"\u041F\u043E\u043C\u043E\u0449", blockquote_desc:"\u0426\u0438\u0442\u0430\u0442", clipboard_msg:"\u041A\u043E\u043F\u0438\u0440\u0430\u043D\u0435/\u041E\u0442\u0440\u044F\u0437\u0432\u0430\u043D\u0435/\u041F\u043E\u0441\u0442\u0430\u0432\u044F\u043D\u0435 \u043D\u0435 \u0435 \u0434\u043E\u0441\u0442\u044A\u043F\u043D\u043E \u043F\u043E\u0434 Mozilla \u0438 Firefox.\r\n\u0416\u0435\u043B\u0430\u0435\u0442\u0435 \u043B\u0438 \u043F\u043E\u0432\u0435\u0447\u0435 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u0437\u0430 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430?", path:"\u041F\u044A\u0442", newdocument:"\u0421\u0438\u0433\u0443\u0440\u0435\u043D \u043B\u0438 \u0441\u0442\u0435, \u0447\u0435 \u0438\u0441\u043A\u0430\u0442\u0435 \u0434\u0430 \u0438\u0437\u0447\u0438\u0441\u0442\u0438\u0442\u0435 \u0446\u044F\u043B\u043E\u0442\u043E \u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435?", toolbar_focus:"\u041E\u0442\u0438\u0434\u0438 \u043F\u0440\u0438 \u0431\u0443\u0442\u043E\u043D\u0438\u0442\u0435 - Alt+Q, \u041E\u0442\u0438\u0434\u0438 \u043F\u0440\u0438 \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0430 - Alt-Z, \u041E\u0442\u0438\u0434\u0438 \u043F\u0440\u0438 \u043F\u044A\u0442\u0435\u043A\u0430\u0442\u0430 \u043D\u0430 \u0435\u043B\u0435\u043C\u0435\u043D\u0442\u0438\u0442\u0435 - Alt-X", more_colors:"\u041E\u0449\u0435 \u0446\u0432\u0435\u0442\u043E\u0432\u0435" }); tinyMCE.addI18n('bg.advanced',{ cut_desc:"\u0418\u0437\u0440\u044F\u0437\u0432\u0430\u043D\u0435", copy_desc:"\u041A\u043E\u043F\u0438\u0440\u0430\u043D\u0435", paste_desc:"\u041F\u043E\u0441\u0442\u0430\u0432\u044F\u043D\u0435", link_desc:"\u0412\u043C\u044A\u043A\u0432\u0430\u043D\u0435/\u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F \u043D\u0430 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430", unlink_desc:"\u041F\u0440\u0435\u043C\u0430\u0445\u043D\u0438 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430", image_desc:"\u0412\u043C\u044A\u043A\u0432\u0430\u043D\u0435/\u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F \u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ca.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/c0000644000175000017500000000453511226234177033641 0ustar frankiefrankietinyMCE.addI18n('ca.openacs',{ style_select:"Estils", font_size:"Mida de lletra", fontdefault:"Tipografia", block:"Format", paragraph:"Par\u00E0graf", div:"Div", address:"Adre\u00E7a", pre:"Preformatat", h1:"Cap\u00E7alera 1", h2:"Cap\u00E7alera 2", h3:"Cap\u00E7alera 3", h4:"Cap\u00E7alera 4", h5:"Cap\u00E7alera 5", h6:"Cap\u00E7alera 6", blockquote:"Cita", code:"Codi", samp:"Mostra de codi", dt:"Terme de la definici\u00F3", dd:"Descripci\u00F3 de la definici\u00F3", bold_desc:"Negreta (Ctrl+B)", italic_desc:"Cursiva (Ctrl+I)", underline_desc:"Subratllat (Ctrl+U)", striketrough_desc:"Tatxat", justifyleft_desc:"Alinea a l'esquerra", justifycenter_desc:"Centra", justifyright_desc:"Alinea a la dreta", justifyfull_desc:"Justifica", bullist_desc:"Llista no ordenada", numlist_desc:"Llista ordenada", outdent_desc:"Redueix el sagnat", indent_desc:"Augmenta el sagnat", undo_desc:"Desf\u00E9s (Ctrl+Z)", redo_desc:"Ref\u00E9s (Ctrl+Y)", link_desc:"Insereix/edita enlla\u00E7", unlink_desc:"Desenlla\u00E7a", image_desc:"Insereix/edita imatge", cleanup_desc:"Neteja el codi no correcte", code_desc:"Edita la font HTML", sub_desc:"Sub\u00EDndex", sup_desc:"Super\u00EDndex", hr_desc:"Insereix regle horitzontal", removeformat_desc:"Elimina el format", custom1_desc:"Aqu\u00ED la teva descripci\u00F3 personalitzada", forecolor_desc:"Selecciona el color del text", backcolor_desc:"Selecciona el color de fons", charmap_desc:"Insereix car\u00E0cter personalitzat", visualaid_desc:"Canvia els elements guies/invisibles", anchor_desc:"Insereix/edita \u00E0ncora", cut_desc:"Retalla", copy_desc:"Copia", paste_desc:"Enganxa", image_props_desc:"Propietats de la imatge", newdocument_desc:"Nou document", help_desc:"Ajuda", blockquote_desc:"Descripci\u00F3 de la cita", clipboard_msg:"Copia/Retalla/Enganxa no est\u00E0 disponible en Mozilla/Firefox.\r\nVols m\u00E9s informaci\u00F3 sobre aquest tema?", path:"Cam\u00ED", newdocument:"Segur que vols esborrar tot el contingut?", toolbar_focus:"Salta als botons d'eines - Alt+Q, Salta a l'editor - Alt-Z, Salta al cam\u00ED de l'element - Alt-X", more_colors:"M\u00E9s colors" }); tinyMCE.addI18n('ca.advanced',{ cut_desc:"Retalla", copy_desc:"Copia", paste_desc:"Enganxa", link_desc:"Insereix/edita enlla\u00E7", unlink_desc:"Desenlla\u00E7a", image_desc:"Insereix/edita imatge" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/fi_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/f0000644000175000017500000000366311226234177033645 0ustar frankiefrankietinyMCE.addI18n('fi.openacs_dlg',{ about_title:"Tietoja TinyMCE:st\u00E4", about_general:"Tietoja", about_help:"Ohje", about_license:"Lisenssi", about_plugins:"Lis\u00E4osat", about_plugin:"Lis\u00E4osa", about_author:"Kirjoittaja", about_version:"Versio", about_loaded:"Ladatut lis\u00E4osat", anchor_title:"Liit\u00E4/muokkaa ankkuria", anchor_name:"Ankkurin nimi", code_title:"HTML-koodin muokkaus", code_wordwrap:"Automaattinen rivinvaihto", colorpicker_title:"Valitse v\u00E4ri", colorpicker_picker_tab:"Valitsin", colorpicker_picker_title:"V\u00E4rin valitsin", colorpicker_palette_tab:"Paletti", colorpicker_palette_title:"V\u00E4ripaletti", colorpicker_named_tab:"Nimetty", colorpicker_named_title:"Nimetyt v\u00E4rit", colorpicker_color:"V\u00E4ri:", colorpicker_name:"Nimi:", charmap_title:"Valitse erikoismerkki", image_title:"Lis\u00E4\u00E4/muokkaa kuvaa", image_src:"Kuvan osoite", image_alt:"Kuvan kuvaus", image_list:"Kuvalista", image_border:"Reunus", image_dimensions:"Mitat", image_vspace:"Pystysuuntainen tila", image_hspace:"Vaakasuuntainen tila", image_align:"Tasaus", image_align_baseline:"Tekstin tasossa", image_align_top:"Yl\u00F6s", image_align_middle:"Keskelle", image_align_bottom:"Alas", image_align_texttop:"Tekstin yl\u00E4osaan", image_align_textbottom:"Tekstin alaosaan", image_align_left:"Vasemmalle", image_align_right:"Oikealle", link_title:"Lis\u00E4\u00E4/muuta linkki", link_url:"Linkin osoite", link_target:"Kohde", link_target_same:"Avaa linkki samassa ikkunassa", link_target_blank:"Avaa linkki uuteen ikkunaan", link_titlefield:"Otsikko", link_is_email:"Antamasi osoite n\u00E4ytt\u00E4\u00E4 olevan s\u00E4hk\u00F6postiosoite. Haluatko lis\u00E4t\u00E4 siihen mailto:-etuliitteen?", link_is_external:"Antamasi osoite n\u00E4ytt\u00E4\u00E4 johtavan ulkopuoliselle sivustolle. Haluatko lis\u00E4t\u00E4 linkin eteen http://-etuliitteen? (suositus)", link_list:"Linkkilista" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/da.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/d0000644000175000017500000000442111226234177033634 0ustar frankiefrankietinyMCE.addI18n('da.openacs',{ style_select:"Typografier", font_size:"Skriftst\u00F8rrelse", fontdefault:"Skrifttype", block:"Format", paragraph:"Afsnit", div:"Div", address:"Adresse", pre:"Pr\u00E6formatteret", h1:"Overskrift 1", h2:"Overskrift 2", h3:"Overskrift 3", h4:"Overskrift 4", h5:"Overskrift 5", h6:"Overskrift 6", blockquote:"Blokcitat", code:"Kode", samp:"Kodeeksempel", dt:"Definitionsterm ", dd:"Definitionsbeskrivelse", bold_desc:"Fed (Ctrl+B)", italic_desc:"Kursiv (Ctrl+I)", underline_desc:"Understreget (Ctrl+U)", striketrough_desc:"Gennemstreget", justifyleft_desc:"Venstrejusteret", justifycenter_desc:"Centreret", justifyright_desc:"H\u00F8jrejusteret", justifyfull_desc:"Lige marginer", bullist_desc:"Unummereret punktopstilling", numlist_desc:"Nummereret punktopstilling", outdent_desc:"Formindsk indrykning", indent_desc:"\u00D8g indrykning", undo_desc:"Fortryd (Ctrl+Z)", redo_desc:"Gendan (Ctrl+Y)", link_desc:"Inds\u00E6t/rediger link", unlink_desc:"Fjern link", image_desc:"Inds\u00E6t/rediger billede", cleanup_desc:"Ryd op i uordentlig kode", code_desc:"Rediger HTML-kilde", sub_desc:"S\u00E6nket skrift", sup_desc:"H\u00E6vet skrift", hr_desc:"Inds\u00E6t horisontal linie", removeformat_desc:"Fjern formatering", custom1_desc:"Din egen beskrivelse her", forecolor_desc:"V\u00E6lg tekstfarve", backcolor_desc:"V\u00E6lg baggrundsfarve", charmap_desc:"Inds\u00E6t specialtegn", visualaid_desc:"Sl\u00E5 hj\u00E6lp/synlige elementer til/fra", anchor_desc:"Inds\u00E6t/rediger anker", cut_desc:"Klip", copy_desc:"Kopier", paste_desc:"Inds\u00E6t", image_props_desc:"Billedegenskaber", newdocument_desc:"Nyt dokument", help_desc:"Hj\u00E6lp", blockquote_desc:"Blokcitat", clipboard_msg:"Kopier/Klip/inds\u00E6t er ikke muligt i Mozilla og Firefox.\nVil du have mere information om dette emne?", path:"Sti", newdocument:"Er du sikker p\u00E5 du vil slette alt indhold?", toolbar_focus:"Hop til v\u00E6rkt\u00F8jsknapper - Alt+Q, Skift til redigering - Alt-Z, Skift til element sti - Alt-X", more_colors:"Flere farver" }); tinyMCE.addI18n('da.advanced',{ cut_desc:"Klip", copy_desc:"Kopier", paste_desc:"Inds\u00E6t", link_desc:"Inds\u00E6t/rediger link", unlink_desc:"Fjern link", image_desc:"Inds\u00E6t/rediger billede" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/de.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/d0000644000175000017500000000471411226234177033641 0ustar frankiefrankietinyMCE.addI18n('de.openacs',{ style_select:"Format", font_size:"Schriftgr\u00F6\u00DFe", fontdefault:"Schriftart", block:"Vorlage", paragraph:"Absatz", div:"Zusammenh\u00E4ngender Bereich", address:"Addresse", pre:"Rohdaten", h1:"\u00DCberschrift 1", h2:"\u00DCberschrift 2", h3:"\u00DCberschrift 3", h4:"\u00DCberschrift 4", h5:"\u00DCberschrift 5", h6:"\u00DCberschrift 6", blockquote:"Zitatblock", code:"Code", samp:"Beispiel", dt:"Definitionsbegriff", dd:"Definitionsbeschreibung", bold_desc:"Fett (Strg+B)", italic_desc:"Kursiv (Strg+I)", underline_desc:"Unterstrichen (Strg+U)", striketrough_desc:"Durchgestrichen", justifyleft_desc:"Links ausgerichtet", justifycenter_desc:"Mittig ausgerichtet", justifyright_desc:"Rechts ausgerichtet", justifyfull_desc:"Blocksatz", bullist_desc:"Unsortierte Liste", numlist_desc:"Sortierte Liste", outdent_desc:"Ausr\u00FCcken", indent_desc:"Einr\u00FCcken", undo_desc:"R\u00FCckg\u00E4ngig (Strg+Z)", redo_desc:"Wiederholen (Strg+Y)", link_desc:"Link einf\u00FCgen/ver\u00E4ndern", unlink_desc:"Link entfernen", image_desc:"Bild einf\u00FCgen/ver\u00E4ndern", cleanup_desc:"Quellcode aufr\u00E4umen", code_desc:"HTML-Quellcode bearbeiten", sub_desc:"Tiefgestellt", sup_desc:"Hochgestellt", hr_desc:"Trennlinie einf\u00FCgen", removeformat_desc:"Formatierungen zur\u00FCcksetzen", custom1_desc:"Benutzerdefinierte Beschreibung", forecolor_desc:"Textfarbe", backcolor_desc:"Hintergrundfarbe", charmap_desc:"Sonderzeichen einf\u00FCgen", visualaid_desc:"Hilfslinien und unsichtbare Elemente ein-/ausblenden", anchor_desc:"Anker einf\u00FCgen/ver\u00E4ndern", cut_desc:"Ausschneiden", copy_desc:"Kopieren", paste_desc:"Einf\u00FCgen", image_props_desc:"Bildeigenschaften", newdocument_desc:"Neues Dokument", help_desc:"Hilfe", blockquote_desc:"Zitatblock", clipboard_msg:"Kopieren, Ausschneiden und Einf\u00FCgen sind im Mozilla Firefox nicht m\u00F6glich.\r\nWollen Sie mehr \u00FCber dieses Problem erfahren?", path:"Pfad", newdocument:"Wollen Sie wirklich den ganzen Inhalt l\u00F6schen?", toolbar_focus:"Zur Werkzeugleiste springen: Alt+Q; Zum Editor springen: Alt-Z; Zum Elementpfad springen: Alt-X", more_colors:"Weitere Farben", anchor_delta_width:"13" }); tinyMCE.addI18n('de.advanced',{ cut_desc:"Ausschneiden", copy_desc:"Kopieren", paste_desc:"Einf\u00FCgen", link_desc:"Link einf\u00FCgen/ver\u00E4ndern", unlink_desc:"Link entfernen", image_desc:"Bild einf\u00FCgen/ver\u00E4ndern" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/el.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000001672711226234177033651 0ustar frankiefrankietinyMCE.addI18n('el.openacs',{ style_select:"\u03A3\u03C4\u03C5\u03BB", font_size:"\u039C\u03AD\u03B3\u03B5\u03B8\u03BF\u03C2 \u0393\u03C1\u03B1\u03BC\u03BC\u03AC\u03C4\u03C9\u03BD", fontdefault:"\u0393\u03C1\u03B1\u03BC\u03BC\u03B1\u03C4\u03BF\u03C3\u03B5\u03B9\u03C1\u03AC", block:"\u039C\u03BF\u03C1\u03C6\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7", paragraph:"\u03A0\u03B1\u03C1\u03AC\u03B3\u03C1\u03B1\u03C6\u03BF\u03C2", div:"Div", address:"\u0394\u03B9\u03B5\u03CD\u03B8\u03C5\u03BD\u03C3\u03B7", pre:"Pre", h1:"\u0395\u03C0\u03B9\u03BA\u03B5\u03C6\u03B1\u03BB\u03AF\u03B4\u03B1 1", h2:"\u0395\u03C0\u03B9\u03BA\u03B5\u03C6\u03B1\u03BB\u03AF\u03B4\u03B1 2", h3:"\u0395\u03C0\u03B9\u03BA\u03B5\u03C6\u03B1\u03BB\u03AF\u03B4\u03B1 3", h4:"\u0395\u03C0\u03B9\u03BA\u03B5\u03C6\u03B1\u03BB\u03AF\u03B4\u03B1 4", h5:"\u0395\u03C0\u03B9\u03BA\u03B5\u03C6\u03B1\u03BB\u03AF\u03B4\u03B1 5", h6:"\u0395\u03C0\u03B9\u03BA\u03B5\u03C6\u03B1\u03BB\u03AF\u03B4\u03B1 6", blockquote:"Blockquote", code:"\u039A\u03CE\u03B4\u03B9\u03BA\u03B1\u03C2", samp:"\u0394\u03B5\u03AF\u03B3\u03BC\u03B1 \u039A\u03CE\u03B4\u03B9\u03BA\u03B1", dt:"\u039F\u03C1\u03B9\u03C3\u03BC\u03CC\u03C2", dd:"\u03A0\u03B5\u03C1\u03B9\u03B3\u03C1\u03B1\u03C6\u03AE \u039F\u03C1\u03B9\u03C3\u03BC\u03BF\u03CD", bold_desc:"\u039C\u03B1\u03CD\u03C1\u03B1 (Ctrl+B)", italic_desc:"\u03A0\u03BB\u03AC\u03B3\u03B9\u03B1 (Ctrl+I)", underline_desc:"\u03A5\u03C0\u03BF\u03B3\u03C1\u03B1\u03BC\u03BC\u03B9\u03C3\u03BC\u03AD\u03BD\u03B1 (Ctrl+U)", striketrough_desc:"\u0394\u03B9\u03B1\u03B3\u03C1\u03B1\u03BC\u03BC\u03B9\u03C3\u03BC\u03AD\u03BD\u03B1", justifyleft_desc:"\u03A3\u03C4\u03BF\u03AF\u03C7\u03B9\u03C3\u03B7 \u03B1\u03C1\u03B9\u03C3\u03C4\u03B5\u03C1\u03AC", justifycenter_desc:"\u03A3\u03C4\u03BF\u03AF\u03C7\u03B9\u03C3\u03B7 \u03BA\u03AD\u03BD\u03C4\u03C1\u03BF", justifyright_desc:"\u03A3\u03C4\u03BF\u03AF\u03C7\u03B9\u03C3\u03B7 \u03B4\u03B5\u03BE\u03B9\u03AC", justifyfull_desc:"\u03A3\u03C4\u03BF\u03AF\u03C7\u03B9\u03C3\u03B7 \u03C0\u03BB\u03AE\u03C1\u03B7\u03C2", bullist_desc:"\u039B\u03AF\u03C3\u03C4\u03B1 \u03C7\u03C9\u03C1\u03AF\u03C2 \u03C3\u03B5\u03B9\u03C1\u03AC", numlist_desc:"\u039B\u03AF\u03C3\u03C4\u03B1 \u03BC\u03B5 \u03C3\u03B5\u03B9\u03C1\u03AC", outdent_desc:"\u03A0\u03C1\u03BF\u03B5\u03BE\u03BF\u03C7\u03AE", indent_desc:"\u0395\u03C3\u03BF\u03C7\u03AE", undo_desc:"\u0391\u03BD\u03B1\u03AF\u03C1\u03B5\u03C3\u03B7 (Ctrl+Z)", redo_desc:"\u0395\u03C0\u03B1\u03BD\u03AC\u03BB\u03B7\u03C8\u03B7 (Ctrl+Y)", link_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03BF\u03C5", unlink_desc:"\u039A\u03B1\u03C4\u03AC\u03C1\u03B3\u03B7\u03C3\u03B7 \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03BF\u03C5", image_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03B5\u03B9\u03BA\u03CC\u03BD\u03B1\u03C2", cleanup_desc:"\u039A\u03B1\u03B8\u03B1\u03C1\u03B9\u03C3\u03BC\u03CC\u03C2 \u03BC\u03C0\u03B5\u03C1\u03B4\u03B5\u03BC\u03AD\u03BD\u03BF\u03C5 \u03BA\u03CE\u03B4\u03B9\u03BA\u03B1", code_desc:"\u0395\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 HTML \u039A\u03CE\u03B4\u03B9\u03BA\u03B1", sub_desc:"\u0394\u03B5\u03AF\u03BA\u03C4\u03B7\u03C2", sup_desc:"\u0395\u03BA\u03B8\u03AD\u03C4\u03B7\u03C2", hr_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE \u03BF\u03C1\u03B9\u03B6\u03CC\u03BD\u03C4\u03B9\u03B1\u03C2 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AE\u03C2", removeformat_desc:"\u0391\u03C6\u03B1\u03AF\u03C1\u03B5\u03C3\u03B7 \u03BC\u03BF\u03C1\u03C6\u03BF\u03C0\u03BF\u03AF\u03B7\u03C3\u03B7\u03C2", custom1_desc:"\u0397 \u03C0\u03B5\u03C1\u03B9\u03B3\u03C1\u03B1\u03C6\u03AE \u03C3\u03B1\u03C2 \u03B5\u03B4\u03CE", forecolor_desc:"\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u03C7\u03C1\u03CE\u03BC\u03B1\u03C4\u03BF\u03C2 \u03BA\u03B5\u03B9\u03BC\u03AD\u03BD\u03BF\u03C5", backcolor_desc:"\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u03C7\u03C1\u03CE\u03BC\u03B1\u03C4\u03BF\u03C2 \u03C6\u03CC\u03BD\u03C4\u03BF\u03C5", charmap_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B1", visualaid_desc:"\u0395\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7/\u0391\u03C0\u03CC\u03BA\u03C1\u03C5\u03C8\u03B7 \u03B2\u03BF\u03B7\u03B8\u03B7\u03C4\u03B9\u03BA\u03CE\u03BD \u03B3\u03C1\u03B1\u03BC\u03BC\u03CE\u03BD \u03BA\u03B1\u03B9 \u03B1\u03CC\u03C1\u03B1\u03C4\u03C9\u03BD \u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03C9\u03BD", anchor_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 anchor", cut_desc:"\u0391\u03C0\u03BF\u03BA\u03BF\u03C0\u03AE", copy_desc:"\u0391\u03BD\u03C4\u03B9\u03B3\u03C1\u03B1\u03C6\u03AE", paste_desc:"\u0395\u03C0\u03B9\u03BA\u03CC\u03BB\u03BB\u03B7\u03C3\u03B7", image_props_desc:"\u0399\u03B4\u03B9\u03CC\u03C4\u03B7\u03C4\u03B5\u03C2 \u03B5\u03B9\u03BA\u03CC\u03BD\u03B1\u03C2", newdocument_desc:"\u039D\u03AD\u03BF \u03AD\u03B3\u03B3\u03C1\u03B1\u03C6\u03BF", help_desc:"\u0392\u03BF\u03AE\u03B8\u03B5\u03B9\u03B1", blockquote_desc:"Blockquote", clipboard_msg:"\u039F\u03B9 \u03BB\u03B5\u03B9\u03C4\u03BF\u03C5\u03C1\u03B3\u03AF\u03B5\u03C2 \u0391\u03BD\u03C4\u03B9\u03B3\u03C1\u03B1\u03C6\u03AE/\u0391\u03C0\u03BF\u03BA\u03BF\u03C0\u03AE/\u0395\u03C0\u03B9\u03BA\u03CC\u03BB\u03BB\u03B7\u03C3\u03B7 \u03B4\u03B5\u03BD \u03B5\u03AF\u03BD\u03B1\u03B9 \u03B4\u03B9\u03B1\u03B8\u03AD\u03C3\u03B9\u03BC\u03B5\u03C2 \u03C3\u03B5 Mozilla \u03BA\u03B1\u03B9 Firefox.\n\u0398\u03AD\u03BB\u03B5\u03C4\u03B5 \u03C0\u03B5\u03C1\u03B9\u03C3\u03C3\u03CC\u03C4\u03B5\u03C1\u03B5\u03C2 \u03C0\u03BB\u03B7\u03C1\u03BF\u03C6\u03BF\u03C1\u03AF\u03B5\u03C2 ;", path:"\u0394\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE", newdocument:"\u03A3\u03B9\u03AF\u03B3\u03BF\u03C5\u03C1\u03B1 \u03B8\u03AD\u03BB\u03B5\u03C4\u03B5 \u03BD\u03B1 \u03BA\u03B1\u03B8\u03B1\u03C1\u03AF\u03C3\u03B5\u03C4\u03B5 \u03CC\u03BB\u03BF \u03C4\u03BF \u03C0\u03B5\u03C1\u03B9\u03B5\u03C7\u03CC\u03BC\u03B5\u03BD\u03BF ;", toolbar_focus:"\u039C\u03B5\u03C4\u03AC\u03B2\u03B1\u03C3\u03B7 \u03C3\u03C4\u03B1 \u03BA\u03BF\u03C5\u03BC\u03C0\u03B9\u03AC \u03B5\u03C1\u03B3\u03B1\u03BB\u03B5\u03AF\u03C9\u03BD - Alt+Q, \u039C\u03B5\u03C4\u03AC\u03B2\u03B1\u03C3\u03B7 \u03C3\u03C4\u03BF\u03BD \u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03C4\u03AE \u03BA\u03B5\u03B9\u03BC\u03AD\u03BD\u03BF\u03C5 - Alt-Z, \u039C\u03B5\u03C4\u03AC\u03B2\u03B1\u03C3\u03B7 \u03C3\u03C4\u03B7\u03BD \u03B4\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE \u03C4\u03BF\u03C5 \u03C3\u03C4\u03BF\u03B9\u03C7\u03B5\u03AF\u03BF\u03C5 - Alt-X", more_colors:"\u03A0\u03B5\u03C1\u03B9\u03C3\u03C3\u03CC\u03C4\u03B5\u03C1\u03B1 \u03C7\u03C1\u03CE\u03BC\u03B1\u03C4\u03B1" }); tinyMCE.addI18n('el.advanced',{ cut_desc:"\u0391\u03C0\u03BF\u03BA\u03BF\u03C0\u03AE", copy_desc:"\u0391\u03BD\u03C4\u03B9\u03B3\u03C1\u03B1\u03C6\u03AE", paste_desc:"\u0395\u03C0\u03B9\u03BA\u03CC\u03BB\u03BB\u03B7\u03C3\u03B7", link_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03BF\u03C5", unlink_desc:"\u039A\u03B1\u03C4\u03AC\u03C1\u03B3\u03B7\u03C3\u03B7 \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03BF\u03C5", image_desc:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03B5\u03B9\u03BA\u03CC\u03BD\u03B1\u03C2" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/fa.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/f0000644000175000017500000001330711226234177033641 0ustar frankiefrankietinyMCE.addI18n('fa.openacs',{ style_select:"\u0627\u0633\u062A\u06CC\u0644 \u0647\u0627", font_size:"\u0627\u0646\u062F\u0627\u0632\u0647 \u0642\u0644\u0645", fontdefault:"\u062E\u0627\u0646\u0648\u0627\u062F\u0647 \u0642\u0644\u0645", block:"\u0642\u0627\u0644\u0628", paragraph:"\u067E\u0627\u0631\u0627\u06AF\u0631\u0627\u0641", div:"Div", address:"\u0622\u062F\u0631\u0633", pre:"\u0642\u0627\u0644\u0628 \u0628\u0646\u062F\u06CC \u0634\u062F\u0647 \u0627\u0632 \u0642\u0628\u0644", h1:"\u0639\u0646\u0648\u0627\u0646 \u06AF\u0630\u0627\u0631\u06CC \u06F1", h2:"\u0639\u0646\u0648\u0627\u0646 \u06AF\u0630\u0627\u0631\u06CC 2", h3:"\u0639\u0646\u0648\u0627\u0646 \u06AF\u0630\u0627\u0631\u06CC 3", h4:"\u0639\u0646\u0648\u0627\u0646 \u06AF\u0630\u0627\u0631\u06CC 4", h5:"\u0639\u0646\u0648\u0627\u0646 \u06AF\u0630\u0627\u0631\u06CC 5", h6:"\u0639\u0646\u0648\u0627\u0646 \u06AF\u0630\u0627\u0631\u06CC 6", blockquote:"\u0628\u0644\u0648\u0643 \u0646\u0642\u0644 \u0642\u0648\u0644", code:"\u0643\u062F", samp:"\u0646\u0645\u0648\u0646\u0647 \u0643\u062F", dt:"\u062A\u0639\u0631\u06CC\u0641 \u0648\u0627\u0698\u0647 ", dd:"\u062A\u0639\u0631\u06CC\u0641 \u062A\u0648\u0636\u06CC\u062D", bold_desc:"\u0636\u062E\u06CC\u0645 (Ctrl+B)", italic_desc:"\u0643\u062C (Ctrl+I)", underline_desc:"\u0632\u06CC\u0631 \u062E\u0637 (Ctrl+U)", striketrough_desc:"\u062E\u0637 \u0648\u0633\u0637", justifyleft_desc:"\u062A\u0631\u0627\u0632 \u0686\u067E", justifycenter_desc:"\u062A\u0631\u0627\u0632 \u0648\u0633\u0637", justifyright_desc:"\u062A\u0631\u0627\u0632 \u0631\u0627\u0633\u062A", justifyfull_desc:"\u062A\u0631\u0627\u0632 \u0643\u0627\u0645\u0644", bullist_desc:"\u0644\u06CC\u0633\u062A \u0646\u0627\u0645\u0631\u062A\u0628", numlist_desc:"\u0644\u06CC\u0633\u062A \u0645\u0631\u062A\u0628", outdent_desc:"\u0628\u06CC\u0631\u0648\u0646 \u0622\u0645\u062F\u06AF\u06CC", indent_desc:"\u062A\u0648\u0631\u0641\u062A\u06AF\u06CC", undo_desc:"\u0627\u0646\u062C\u0627\u0645 \u0639\u0645\u0644 \u0642\u0628\u0644 (Ctrl+Z)", redo_desc:"\u0627\u0646\u062C\u0627\u0645 \u0639\u0645\u0644 \u0628\u0639\u062F (Ctrl+Y)", link_desc:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0644\u06CC\u0646\u0643", unlink_desc:"\u063A\u06CC\u0631 \u0644\u06CC\u0646\u0643 \u0643\u0631\u062F\u0646", image_desc:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u062A\u0635\u0648\u06CC\u0631", cleanup_desc:"\u067E\u0627\u0643 \u0633\u0627\u0632\u06CC \u0643\u062F \u0647\u0627\u06CC \u0628\u0647\u0645 \u062E\u0648\u0631\u062F\u0647", code_desc:"\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0633\u0648\u0631\u0633 HTML", sub_desc:"\u067E\u0627\u06CC\u06CC\u0646 \u0646\u0648\u06CC\u0633", sup_desc:"\u0628\u0627\u0644\u0627 \u0646\u0648\u06CC\u0633", hr_desc:"\u062F\u0631\u062C \u062E\u0637 \u0627\u0641\u0642\u06CC", removeformat_desc:"\u062D\u0630\u0641 \u0642\u0627\u0644\u0628 \u0628\u0646\u062F\u06CC", custom1_desc:"\u062A\u0648\u0636\u06CC\u062D \u0633\u0641\u0627\u0631\u0634\u06CC \u0634\u0645\u0627 \u062F\u0631 \u0627\u06CC\u0646\u062C\u0627", forecolor_desc:"\u0627\u0646\u062A\u062E\u0627\u0628 \u0631\u0646\u06AF \u0645\u062A\u0646", backcolor_desc:"\u0627\u0646\u062A\u062E\u0627\u0628 \u0631\u0646\u06AF \u0632\u0645\u06CC\u0646\u0647", charmap_desc:"\u062F\u0631\u062C \u0643\u0627\u0631\u0627\u0643\u062A\u0631 \u0633\u0641\u0627\u0631\u0634\u06CC", visualaid_desc:"\u062A\u0639\u0648\u06CC\u0636 \u0639\u0646\u0627\u0635\u0631 \u062E\u0637\u0648\u0637 \u0631\u0627\u0647\u0646\u0645\u0627/\u063A\u06CC\u0631 \u0642\u0627\u0628\u0644 \u0646\u0645\u0627\u06CC\u0627\u0646", anchor_desc:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0644\u0646\u06AF\u0631", cut_desc:"\u0628\u0631\u0634 (Cut)", copy_desc:"\u0643\u067E\u06CC", paste_desc:"\u0686\u0633\u0628\u0627\u0646\u062F\u0646 (Paste)", image_props_desc:"\u0645\u0634\u062E\u0635\u0627\u062A \u062A\u0635\u0648\u06CC\u0631", newdocument_desc:"\u0633\u0646\u062F \u062C\u062F\u06CC\u062F", help_desc:"\u0631\u0627\u0647\u0646\u0645\u0627\u06CC\u06CC", blockquote_desc:"\u0628\u0644\u0648\u0643 \u0646\u0642\u0644 \u0642\u0648\u0644", clipboard_msg:"\u0643\u067E\u06CC/\u0628\u0631\u0634 (Cut)/\u0686\u0633\u0628\u0627\u0646\u062F\u0646 (Paste) \u062F\u0631 Mozilla \u0648 Firefox \u0642\u0627\u0628\u0644 \u062F\u0633\u062A\u0631\u0633 \u0646\u0645\u06CC \u0628\u0627\u0634\u062F.\r\n\u0622\u06CC\u0627 \u0634\u0645\u0627 \u0627\u0637\u0644\u0627\u0639\u0627\u062A \u0628\u06CC\u0634\u062A\u0631\u06CC \u062F\u0631\u0628\u0627\u0631\u0647 \u0627\u06CC\u0646 \u0645\u0648\u0636\u0648\u0639 \u0645\u06CC \u062E\u0648\u0627\u0647\u06CC\u062F\u061F", path:"\u0645\u0633\u06CC\u0631", newdocument:"\u0622\u06CC\u0627 \u0634\u0645\u0627 \u0645\u06CC \u062E\u0648\u0627\u0647\u06CC\u062F \u062A\u0627 \u062A\u0645\u0627\u0645\u06CC \u0645\u062D\u062A\u0648\u0627 \u0631\u0627 \u067E\u0627\u0643 \u0643\u0646\u06CC\u062F\u061F", toolbar_focus:"\u067E\u0631\u0634 \u0628\u0647 \u062F\u0643\u0645\u0647 \u0647\u0627\u06CC \u0627\u0628\u0632\u0627\u0631 - Alt+Q \u060C \u067E\u0631\u0634 \u0628\u0647 \u0648\u06CC\u0631\u0627\u06CC\u0634\u06AF\u0631 - Alt-Z \u060C \u067E\u0631\u0634 \u0628\u0647 \u0645\u0633\u06CC\u0631 \u0639\u0646\u0635\u0631 - Alt-X", more_colors:"\u0631\u0646\u06AF\u0647\u0627\u06CC \u0628\u06CC\u0634\u062A\u0631" }); tinyMCE.addI18n('fa.advanced',{ cut_desc:"\u0628\u0631\u0634 (Cut)", copy_desc:"\u0643\u067E\u06CC", paste_desc:"\u0686\u0633\u0628\u0627\u0646\u062F\u0646 (Paste)", link_desc:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0644\u06CC\u0646\u0643", unlink_desc:"\u063A\u06CC\u0631 \u0644\u06CC\u0646\u0643 \u0643\u0631\u062F\u0646", image_desc:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u062A\u0635\u0648\u06CC\u0631" }); ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/en.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000000402711226234177033637 0ustar frankiefrankietinyMCE.addI18n('en.openacs',{ style_select:"Styles", font_size:"Font size", fontdefault:"Font family", block:"Format", paragraph:"Paragraph", div:"Div", address:"Address", pre:"Preformatted", h1:"Heading 1", h2:"Heading 2", h3:"Heading 3", h4:"Heading 4", h5:"Heading 5", h6:"Heading 6", blockquote:"Blockquote", code:"Code", samp:"Code sample", dt:"Definition term ", dd:"Definition description", bold_desc:"Bold (Ctrl+B)", italic_desc:"Italic (Ctrl+I)", underline_desc:"Underline (Ctrl+U)", striketrough_desc:"Strikethrough", justifyleft_desc:"Align left", justifycenter_desc:"Align center", justifyright_desc:"Align right", justifyfull_desc:"Align full", bullist_desc:"Unordered list", numlist_desc:"Ordered list", outdent_desc:"Outdent", indent_desc:"Indent", undo_desc:"Undo (Ctrl+Z)", redo_desc:"Redo (Ctrl+Y)", link_desc:"Insert/edit link", unlink_desc:"Unlink", image_desc:"Insert/edit image", cleanup_desc:"Cleanup messy code", code_desc:"Edit HTML Source", sub_desc:"Subscript", sup_desc:"Superscript", hr_desc:"Insert horizontal ruler", removeformat_desc:"Remove formatting", custom1_desc:"Your custom description here", forecolor_desc:"Select text color", backcolor_desc:"Select background color", charmap_desc:"Insert custom character", visualaid_desc:"Toggle guidelines/invisible elements", anchor_desc:"Insert/edit anchor", cut_desc:"Cut", copy_desc:"Copy", paste_desc:"Paste", image_props_desc:"Image properties", newdocument_desc:"New document", help_desc:"Help", blockquote_desc:"Blockquote", clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\r\nDo you want more information about this issue?", path:"Path", newdocument:"Are you sure you want clear all contents?", toolbar_focus:"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X", more_colors:"More colors" }); tinyMCE.addI18n('en.advanced',{ cut_desc:"Cut", copy_desc:"Copy", paste_desc:"Paste", link_desc:"Insert/edit link", unlink_desc:"Unlink", image_desc:"Insert image" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/es.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000000463211226234177033641 0ustar frankiefrankietinyMCE.addI18n('es.openacs',{ style_select:"Estilos", font_size:"Tama\u00F1o", fontdefault:"Fuente", block:"Formato", paragraph:"P\u00E1rrafo", div:"Div", address:"Direcci\u00F3n", pre:"Preformateado", h1:"Encabezado 1", h2:"Encabezado 2", h3:"Encabezado 3", h4:"Encabezado 4", h5:"Encabezado 5", h6:"Encabezado 6", blockquote:"Cita", code:"C\u00F3digo", samp:"Ejemplo de c\u00F3digo", dt:"T\u00E9rmino de definici\u00F3n", dd:"Descripci\u00F3n de definici\u00F3n", bold_desc:"Negrita (Ctrl+B)", italic_desc:"Cursiva (Ctrl+I)", underline_desc:"Subrayado (Ctrl+U)", striketrough_desc:"Tachado", justifyleft_desc:"Alinear a la izquierda", justifycenter_desc:"Alinear al centro", justifyright_desc:"Alinear a la derecha", justifyfull_desc:"Justificar", bullist_desc:"Lista desordenada", numlist_desc:"Lista ordenada", outdent_desc:"Reducir sangr\u00EDa", indent_desc:"Aumentar sangr\u00EDa", undo_desc:"Deshacer (Ctrl+Z)", redo_desc:"Rehacer (Ctrl+Y)", link_desc:"Insertar/editar hiperv\u00EDnculo", unlink_desc:"Quitar hiperv\u00EDnculo", image_desc:"Insertar/editar imagen", cleanup_desc:"Limpiar c\u00F3digo basura", code_desc:"Editar c\u00F3digo HTML", sub_desc:"Sub\u00EDndice", sup_desc:"Super\u00EDndice", hr_desc:"Insertar regla horizontal", removeformat_desc:"Limpiar formato", custom1_desc:"Su descripci\u00F3n personal aqu\u00ED", forecolor_desc:"Seleccionar color del texto", backcolor_desc:"Seleccionar color de fondo", charmap_desc:"Insertar caracteres personalizados", visualaid_desc:"Mostrar/ocultar l\u00EDnea de gu\u00EDa/elementos invisibles", anchor_desc:"Insertar/editar ancla", cut_desc:"Cortar", copy_desc:"Copiar", paste_desc:"Pegar", image_props_desc:"Propiedades de imagen", newdocument_desc:"Nuevo documento", help_desc:"Ayuda", blockquote_desc:"Cita", clipboard_msg:"Copiar/Cortar/Pegar no se encuentra disponible en Mozilla y Firefox.\n \u00BFDesea obtener m\u00E1s informaci\u00F3n acerca de este tema?", path:"Ruta", newdocument:" \u00BFEst\u00E1 seguro que desea limpiar todo el contenido?", toolbar_focus:"Ir a los botones de herramientas - Alt+Q, Ir al editor - Alt-Z, Ir a la ruta del elemento - Alt-X", more_colors:"M\u00E1s colores" }); tinyMCE.addI18n('es.advanced',{ cut_desc:"Cortar", copy_desc:"Copiar", paste_desc:"Pegar", link_desc:"Insertar/editar hiperv\u00EDnculo", unlink_desc:"Quitar hiperv\u00EDnculo", image_desc:"Insertar/editar imagen" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/fi.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/f0000644000175000017500000000477411226234177033651 0ustar frankiefrankietinyMCE.addI18n('fi.openacs',{ style_select:"Tyylit", font_size:"Kirjasinkoko", fontdefault:"Kirjasin", block:"Muotoilu", paragraph:"Kappale", div:"Div", address:"Osoite", pre:"Esimuotoiltu (pre)", h1:"Otsikko 1", h2:"Otsikko 2", h3:"Otsikko 3", h4:"Otsikko 4", h5:"Otsikko 5", h6:"Otsikko 6", blockquote:"Pitk\u00E4 lainaus", code:"Koodi", samp:"Koodiesimerkki", dt:"M\u00E4\u00E4rittelyn ehto ", dd:"M\u00E4\u00E4rittelyn kuvaus", bold_desc:"Lihavoitu (Ctrl+B)", italic_desc:"Kursivoitu (Ctrl+I)", underline_desc:"Alleviivattu (Ctrl+U)", striketrough_desc:"Yliviivattu", justifyleft_desc:"Tasaus vasemmalle", justifycenter_desc:"Keskitetty", justifyright_desc:"Tasaus oikealle", justifyfull_desc:"Tasattu", bullist_desc:"J\u00E4rjest\u00E4m\u00E4t\u00F6n lista", numlist_desc:"J\u00E4rjestetty lista", outdent_desc:"Loitonna", indent_desc:"Sisenn\u00E4", undo_desc:"Peru (Ctrl+Z)", redo_desc:"Tee uudelleen (Ctrl+Y)", link_desc:"Lis\u00E4\u00E4/muuta linkki", unlink_desc:"Poista linkki", image_desc:"Lis\u00E4\u00E4/muuta kuva", cleanup_desc:"Siisti sekainen koodi", code_desc:"Muokkaa HTML-koodia", sub_desc:"Alaindeksi", sup_desc:"Yl\u00E4indeksi", hr_desc:"Lis\u00E4\u00E4 vaakasuora viivain", removeformat_desc:"Poista muotoilu", custom1_desc:"Oma kuvauksesi t\u00E4h\u00E4n", forecolor_desc:"Valitse tekstin v\u00E4ri", backcolor_desc:"Valitse taustan v\u00E4ri", charmap_desc:"Lis\u00E4\u00E4 erikoismerkki", visualaid_desc:"Suuntaviivat/N\u00E4kym\u00E4tt\u00F6m\u00E4t elementit", anchor_desc:"Lis\u00E4\u00E4/Muokkaa ankkuri", cut_desc:"Leikkaa", copy_desc:"Kopioi", paste_desc:"Liit\u00E4", image_props_desc:"Kuvan ominaisuudet", newdocument_desc:"Uusi tiedosto", help_desc:"Ohje", blockquote_desc:"Pitk\u00E4 lainaus", clipboard_msg:"Kopioi/Leikkaa/Liit\u00E4 -painikkeet eiv\u00E4t toimi Mozilla ja Firefox -selaimilla. Voit kuitenkin k\u00E4ytt\u00E4\u00E4 n\u00E4pp\u00E4inyhdistelmi\u00E4 kopioimiseen (ctrl+c), leikkaamiseen (ctrl+x) ja liitt\u00E4miseen (ctrl+v). Haluatko lis\u00E4\u00E4 tietoa?", path:"Polku", newdocument:"Haluatko varmasti tyhjent\u00E4\u00E4 kaiken sis\u00E4ll\u00F6n?", toolbar_focus:"Siirry ty\u00F6kaluihin - Alt+Q, Siirry tekstieditoriin - Alt-Z, Siirry elementin polkuun - Alt-X", more_colors:"Enemm\u00E4n v\u00E4rej\u00E4" }); tinyMCE.addI18n('fi.advanced',{ cut_desc:"Leikkaa", copy_desc:"Kopioi", paste_desc:"Liit\u00E4", link_desc:"Lis\u00E4\u00E4/muuta linkki", unlink_desc:"Poista linkki", image_desc:"Lis\u00E4\u00E4/muuta kuva" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/et.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000000445111226234177033640 0ustar frankiefrankietinyMCE.addI18n('et.openacs',{ style_select:"Stiilid", font_size:"Fondi suurus", fontdefault:"Font", block:"Formaat", paragraph:"Paragraaf", div:"Div", address:"Aadress", pre:"Eelformeeritud", h1:"Heading 1", h2:"Heading 2", h3:"Heading 3", h4:"Heading 4", h5:"Heading 5", h6:"Heading 6", blockquote:"Plokkviide", code:"Kood", samp:"Koodi n\u00E4ide", dt:"Defineeringu tingimus", dd:"Defineeringu kirjeldus", bold_desc:"Rasvane (Ctrl+B)", italic_desc:"Kursiiv (Ctrl+I)", underline_desc:"Allajoonitud (Ctrl+U)", striketrough_desc:"L\u00E4bijoonitud", justifyleft_desc:"Vasak joondus", justifycenter_desc:"Keskjoondus", justifyright_desc:"Parem joondus", justifyfull_desc:"T\u00E4isjoondus", bullist_desc:"Ebakorrap\u00E4rane loetelu", numlist_desc:"Korrap\u00E4rane loetelu", outdent_desc:"Taanda v\u00E4lja", indent_desc:"Taanda sisse", undo_desc:"V\u00F5ta tagasi (Ctrl+Z)", redo_desc:"Tee uuesti (Ctrl+Y)", link_desc:"Sisesta/redigeeri link", unlink_desc:"Eemalda link", image_desc:"Sisesta/redigeeri pilt", cleanup_desc:"Puhasta segane kood", code_desc:"Redigeeri HTML l\u00E4htekoodi", sub_desc:"Alaindeks", sup_desc:"\u00DClaindeks", hr_desc:"Sisesta horisontaalne joonlaud", removeformat_desc:"Eemalda vormindus", custom1_desc:"Teie kohandatud kirjeldus siia", forecolor_desc:"Vali teksti v\u00E4rv", backcolor_desc:"Vali tausta v\u00E4rv", charmap_desc:"Sisesta kohandatud kirjam\u00E4rk", visualaid_desc:"L\u00FClita \u00FCmber juhtjooned/n\u00E4htamatud elemendid", anchor_desc:"Sisesta/redigeeri ankur", cut_desc:"L\u00F5ika", copy_desc:"Kopeeri", paste_desc:"Kleebi", image_props_desc:"Pildi kirjeldus", newdocument_desc:"Uus dokument", help_desc:"Abi", blockquote_desc:"Plokkviide", clipboard_msg:"Kopeeri/L\u00F5ika/Kleebi ei ole Mozillas ja Firefoxis saadaval. Kas soovid rohkem infot selle probleemi kohta?", path:"Tee", newdocument:"Oled sa kindel, et tahad kustutada k\u00F5ik sisud?", toolbar_focus:"H\u00FCppa t\u00F6\u00F6riista nuppudele - Alt+Q, H\u00FCppa redigeerijale - Alt-Z, H\u00FCppa elemendi teele - Alt-X", more_colors:"Rohkem v\u00E4rve" }); tinyMCE.addI18n('et.advanced',{ cut_desc:"L\u00F5ika", copy_desc:"Kopeeri", paste_desc:"Kleebi", link_desc:"Sisesta/redigeeri link", unlink_desc:"Eemalda link", image_desc:"Sisesta/redigeeri pilt" }); ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/fr.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/f0000644000175000017500000000474011226234177033642 0ustar frankiefrankietinyMCE.addI18n('fr.openacs',{ style_select:"Styles", font_size:"Taille police", fontdefault:"Famille de police", block:"Format", paragraph:"Paragraphe", div:"Div", address:"Adresse", pre:"Preformatt\u00E9", h1:"Titre 1", h2:"Titre 2", h3:"Titre 3", h4:"Titre 4", h5:"Titre 5", h6:"Titre 6", blockquote:"Citation", code:"Code", samp:"Exemple de code", dt:"Terme \u00E0 d\u00E9finir", dd:"D\u00E9finition du terme", bold_desc:"Gras (Ctrl+B)", italic_desc:"Italique (Ctrl+I)", underline_desc:"Soulign\u00E9 (Ctrl+U)", striketrough_desc:"Barr\u00E9", justifyleft_desc:"Align\u00E9 \u00E0 gauche", justifycenter_desc:"Centr\u00E9", justifyright_desc:"Align\u00E9 \u00E0 droite", justifyfull_desc:"Justifi\u00E9", bullist_desc:"Liste non-num\u00E9rot\u00E9e", numlist_desc:"Liste num\u00E9rot\u00E9e", outdent_desc:"Retirer l'indentation", indent_desc:"Indenter", undo_desc:"Annuler (Ctrl+Z)", redo_desc:"R\u00E9tablir (Ctrl+Y)", link_desc:"Ins\u00E9rer/\u00C9diter le lien", unlink_desc:"D\u00E9lier", image_desc:"Ins\u00E9rer/\u00C9diter l'image", cleanup_desc:"Nettoyer le code non propre", code_desc:"\u00C9diter source HTML", sub_desc:"Indice", sup_desc:"Exposant", hr_desc:"Ins\u00E9rer trait horizontal", removeformat_desc:"Enlever formattage", custom1_desc:"Votre description personnalis\u00E9e ici", forecolor_desc:"Choisir la couleur du texte", backcolor_desc:"Choisir la couleur de surlignage", charmap_desc:"Ins\u00E9rer caract\u00E8res sp\u00E9ciaux", visualaid_desc:"Activer/d\u00E9sactiver les guides et les \u00E9l\u00E9ments invisibles", anchor_desc:"Ins\u00E9rer/\u00C9diter ancre", cut_desc:"Couper", copy_desc:"Copier", paste_desc:"Coller", image_props_desc:"Propri\u00E9t\u00E9s de l'image", newdocument_desc:"Nouveau document", help_desc:"Aide", blockquote_desc:"Citation", clipboard_msg:"Copier/Couper/Coller n'est pas disponible sous Mozilla et sous Firefox.\n\r\n Voulez-vous plus d'information sur ce probl\u00E8me\u00A0?", path:"Chemin", newdocument:"\u00CAtes-vous s\u00FBr de vouloir effacer l'enti\u00E8ret\u00E9 du document\u00A0?", toolbar_focus:"Aller aux boutons de l'\u00E9diteur - Alt+Q, Aller \u00E0 l'\u00E9diteur - Alt-Z, Aller au chemin de l'\u00E9l\u00E9ment - Alt-X", more_colors:"Plus de couleurs" }); tinyMCE.addI18n('fr.advanced',{ cut_desc:"Couper", copy_desc:"Copier", paste_desc:"Coller", link_desc:"Ins\u00E9rer/\u00C9diter le lien", unlink_desc:"D\u00E9lier", image_desc:"Ins\u00E9rer/\u00C9diter l'image" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/gl.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/g0000644000175000017500000000467111226234177033646 0ustar frankiefrankietinyMCE.addI18n('gl.openacs',{ style_select:"Estilos", font_size:"Tama\u00F1o", fontdefault:"Fonte", block:"Formato", paragraph:"P\u00E1rrafo", div:"Div", address:"Enderezo", pre:"Pre-formateado", h1:"Encabezamento 1", h2:"Encabezamento 2", h3:"Encabezamento 3", h4:"Encabezamento 4", h5:"Encabezamento 5", h6:"Encabezamento 6", blockquote:"Bloque de cita", code:"C\u00F3digo", samp:"Mostra de c\u00F3digo", dt:"Termo de definici\u00F3n", dd:"Descripci\u00F3n de definici\u00F3n", bold_desc:"Negrita (Ctrl+B)", italic_desc:"Cursiva (Ctrl+I)", underline_desc:"Subli\u00F1ado (Ctrl+U)", striketrough_desc:"Tachado", justifyleft_desc:"Ali\u00F1ar \u00E1 esquerda", justifycenter_desc:"Ali\u00F1ar \u00F3 centro", justifyright_desc:"Ali\u00F1ar \u00E1 dereita", justifyfull_desc:"Xustificar", bullist_desc:"Lista desordenada", numlist_desc:"Lista ordenada", outdent_desc:"Reducir sangr\u00EDa", indent_desc:"Aumentar sangr\u00EDa", undo_desc:"Desfacer (Ctrl+Z)", redo_desc:"Re-facer (Ctrl+Y)", link_desc:"Insertar/editar hiperv\u00EDnculo", unlink_desc:"Quitar hiperv\u00EDnculo", image_desc:"Insertar/editar imaxe", cleanup_desc:"Limpiar lixo no c\u00F3digo", code_desc:"Editar c\u00F3digo HTML", sub_desc:"Sub\u00EDndice", sup_desc:"Super\u00EDndice", hr_desc:"Insertar regra horizontal", removeformat_desc:"quitar formato", custom1_desc:"A s\u00FAa descripci\u00F3n persoal aqu\u00ED", forecolor_desc:"Seleccionar cor do texto", backcolor_desc:"Seleccionar cor do fondo", charmap_desc:"Insertar caracteres persoalizados", visualaid_desc:"Mostrar/ocultar li\u00F1a de gu\u00EDa/elementos invisibres", anchor_desc:"Insertar/editar \u00E1ncora", cut_desc:"Cortar", copy_desc:"Copiar", paste_desc:"Pegar", image_props_desc:"Propiedades de imaxe", newdocument_desc:"Novo documento", help_desc:"Axuda", blockquote_desc:"Cita", clipboard_msg:"Copiar/Cortar/Pegar non est\u00E1 disponible en Mozilla e Firefox.\r\n\u00BFDesexa obter mais informaci\u00F3n sobre de este asunto?", path:"Ruta", newdocument:"\u00BFSeguro que desexa limpar todo o contido?", toolbar_focus:"Ir \u00F3s bot\u00F3ns de ferramentas - Alt+Q, Ir \u00F3 editor - Alt-Z, Ir \u00E1 ruta do elemento - Alt-X", more_colors:"M\u00E1is cores" }); tinyMCE.addI18n('gl.advanced',{ cut_desc:"Cortar", copy_desc:"Copiar", paste_desc:"Pegar", link_desc:"Insertar/editar hiperv\u00EDnculo", unlink_desc:"Quitar hiperv\u00EDnculo", image_desc:"Insertar/editar imaxe" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/hr.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/h0000644000175000017500000000424111226234177033640 0ustar frankiefrankietinyMCE.addI18n('hr.openacs',{ style_select:"Stilovi", font_size:"Veli\u010Dina pisma", fontdefault:"Vrsta pisma", block:"Format", paragraph:"Paragraf", div:"Div", address:"Adresa", pre:"Oblikovano", h1:"Naslov 1", h2:"Naslov 2", h3:"Naslov 3", h4:"Naslov 4", h5:"Naslov 5", h6:"Naslov 6", blockquote:"Citat", code:"Kod", samp:"Primjer koda", dt:"Definicija pojma", dd:"Opis definicije", bold_desc:"Podebljaj (Ctrl+B)", italic_desc:"Kurziv (Ctrl+I)", underline_desc:"Podcrtaj (Ctrl+U)", striketrough_desc:"Precrtaj", justifyleft_desc:"Poravnaj lijevo", justifycenter_desc:"Centriraj", justifyright_desc:"Poravnaj desno", justifyfull_desc:"Poravnaj potpuno", bullist_desc:"Neure\u0111ena lista", numlist_desc:"Ure\u0111ena lista", outdent_desc:"Uvuci", indent_desc:"Izvuci", undo_desc:"Poni\u0161ti (Ctrl+Z)", redo_desc:"Ponovi (Ctrl+Y)", link_desc:"Umetni/uredi poveznicu", unlink_desc:"Poni\u0161ti poveznicu", image_desc:"Umetni/uredi sliku", cleanup_desc:"Po\u010Disti kod", code_desc:"Uredi HTML izvor", sub_desc:"Indeks", sup_desc:"Eksponent", hr_desc:"Umetni vodoravnu crtu", removeformat_desc:"Poni\u0161ti oblikovanje", custom1_desc:"Vlastiti opis ovdje", forecolor_desc:"Odaberite boju teksta", backcolor_desc:"Odaberite boju pozadine", charmap_desc:"Umetni vlastiti znak", visualaid_desc:"Vodilice/nevidljivi elementi", anchor_desc:"Umetni/uredi sidro", cut_desc:"Izre\u017Ei", copy_desc:"Kopiraj", paste_desc:"Zalijepi", image_props_desc:"Svojstva slike", newdocument_desc:"Novi dokument", help_desc:"Pomo\u0107", blockquote_desc:"Citiraj", clipboard_msg:"Kopiraj/Izre\u017Ei/Zalijepi nije dostupno u Mozilla i Firefox preglednicima. Vi\u0161e informacija?", path:"Staza", newdocument:"Jeste li sigurni da \u017Eelite izbrisati cijeli sadr\u017Eaj?", toolbar_focus:"Prije\u0111i na alatnu traku - Alt+Q, prije\u0111i na ure\u0111iva\u010D - Alt-Z, prije\u0111i na element path - Alt-X", more_colors:"Vi\u0161e boja" }); tinyMCE.addI18n('hr.advanced',{ cut_desc:"Izre\u017Ei", copy_desc:"Kopiraj", paste_desc:"Zalijepi", link_desc:"Umetni/uredi poveznicu", unlink_desc:"Poni\u0161ti poveznicu", image_desc:"Umetni/uredi sliku" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/hu.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/h0000644000175000017500000000576111226234177033650 0ustar frankiefrankietinyMCE.addI18n('hu.openacs',{ style_select:"St\u00EDlusok", font_size:"Bet\u0171m\u00E9ret", fontdefault:"Bet\u0171t\u00EDpus", block:"Form\u00E1tum", paragraph:"Bekezd\u00E9s", div:"Div", address:"C\u00EDm", pre:"El\u0151form\u00E1zott", h1:"C\u00EDmsor 1", h2:"C\u00EDmsor 2", h3:"C\u00EDmsor 3", h4:"C\u00EDmsor 4", h5:"C\u00EDmsor 5", h6:"C\u00EDmsor 6", blockquote:"Id\u00E9zet", code:"K\u00F3d", samp:"K\u00F3d minta", dt:"Defini\u00E1lt kifejez\u00E9s a defin\u00EDci\u00F3s list\u00E1ban", dd:"Defin\u00EDci\u00F3 a defin\u00EDci\u00F3s list\u00E1ban", bold_desc:"F\u00E9lk\u00F6v\u00E9r (Ctrl+B)", italic_desc:"D\u0151lt (Ctrl+I)", underline_desc:"Al\u00E1h\u00FAzott (Ctrl+U)", striketrough_desc:"\u00C1th\u00FAzott", justifyleft_desc:"Balra z\u00E1rt", justifycenter_desc:"K\u00F6z\u00E9pre z\u00E1rt", justifyright_desc:"Jobbra z\u00E1rt", justifyfull_desc:"Sorkiz\u00E1rt", bullist_desc:"Rendezetlen lista", numlist_desc:"Rendezett lista", outdent_desc:"Beh\u00FAz\u00E1s cs\u00F6kkent\u00E9se", indent_desc:"Beh\u00FAz\u00E1s n\u00F6vel\u00E9se", undo_desc:"Visszavon (Ctrl+Z)", redo_desc:"M\u00E9gis v\u00E9grehajt (Ctrl+Y)", link_desc:"Link besz\u00FAr\u00E1sa/szerkeszt\u00E9se", unlink_desc:"Link megsz\u00FCntet\u00E9se", image_desc:"K\u00E9p besz\u00FAr\u00E1sa/szerkeszt\u00E9se", cleanup_desc:"Rendetlen k\u00F3d takar\u00EDt\u00E1sa", code_desc:"HTML forr\u00E1s szerkeszt\u00E9se", sub_desc:"Als\u00F3 index", sup_desc:"Fels\u0151 index", hr_desc:"V\u00EDzszintes elv\u00E1laszt\u00F3 besz\u00FAr\u00E1sa", removeformat_desc:"Form\u00E1z\u00E1s elt\u00E1vol\u00EDt\u00E1sa", custom1_desc:"Az \u00F6n egyedi le\u00EDr\u00E1sa", forecolor_desc:"Sz\u00F6vegsz\u00EDn v\u00E1laszt\u00E1sa", backcolor_desc:"H\u00E1tt\u00E9rsz\u00EDn v\u00E1laszt\u00E1sa", charmap_desc:"Speci\u00E1lis karakter besz\u00FAr\u00E1sa", visualaid_desc:"Vezet\u0151vonalak/nem l\u00E1that\u00F3 elemek ki-/bekapcsol\u00E1sa", anchor_desc:"Horgony besz\u00FAr\u00E1sa/szerkeszt\u00E9se", cut_desc:"Kiv\u00E1g\u00E1s", copy_desc:"M\u00E1sol\u00E1s", paste_desc:"Besz\u00FAr\u00E1s", image_props_desc:"K\u00E9p tulajdons\u00E1gai", newdocument_desc:"\u00DAj dokumentum", help_desc:"Seg\u00EDts\u00E9g", blockquote_desc:"Id\u00E9zet", clipboard_msg:"A M\u00E1sol\u00E1s/Kiv\u00E1g\u00E1s/Besz\u00FAr\u00E1s funkci\u00F3k nem el\u00E9rhet\u0151k Mozilla \u00E9s Firefox alatt. K\u00EDv\u00E1n t\u00F6bbet tudni err\u0151l a t\u00E9m\u00E1r\u00F3l?", path:"\u00DAtvonal", newdocument:"Biztosan t\u00F6rli az eddigi tartalmat?", toolbar_focus:"Eszk\u00F6zgombokra ugr\u00E1s - Alt+Q, Szerkeszt\u0151h\u00F6z ugr\u00E1s - Alt-Z, Elem\u00FAtvonalhoz ugr\u00E1s - Alt-X", more_colors:"T\u00F6bb sz\u00EDn" }); tinyMCE.addI18n('hu.advanced',{ cut_desc:"Kiv\u00E1g\u00E1s", copy_desc:"M\u00E1sol\u00E1s", paste_desc:"Besz\u00FAr\u00E1s", link_desc:"Link besz\u00FAr\u00E1sa/szerkeszt\u00E9se", unlink_desc:"Link megsz\u00FCntet\u00E9se", image_desc:"K\u00E9p besz\u00FAr\u00E1sa/szerkeszt\u00E9se" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ja.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/j0000644000175000017500000000660011226234177033643 0ustar frankiefrankietinyMCE.addI18n('ja.openacs',{ style_select:"\u30B9\u30BF\u30A4\u30EB", font_size:"\u30D5\u30A9\u30F3\u30C8\u30B5\u30A4\u30BA", fontdefault:"\u30D5\u30A9\u30F3\u30C8", block:"\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8", paragraph:"\u6BB5\u843D", div:"Div", address:"\u9023\u7D61\u5148", pre:"\u6574\u5F62\u6E08\u307F", h1:"\u898B\u51FA\u30571", h2:"\u898B\u51FA\u30572", h3:"\u898B\u51FA\u30573", h4:"\u898B\u51FA\u30574", h5:"\u898B\u51FA\u30575", h6:"\u898B\u51FA\u30576", blockquote:"\u5F15\u7528", code:"\u30BD\u30FC\u30B9\u30B3\u30FC\u30C9", samp:"\u30B3\u30FC\u30C9\u30B5\u30F3\u30D7\u30EB", dt:"\u8A9E\u53E5\u5B9A\u7FA9", dd:"\u8A9E\u53E5\u8AAC\u660E", bold_desc:"\u592A\u5B57 (Ctrl+B)", italic_desc:"\u659C\u4F53 (Ctrl+I)", underline_desc:"\u4E0B\u7DDA (Ctrl+U)", striketrough_desc:"\u6253\u6D88\u3057\u7DDA", justifyleft_desc:"\u5DE6\u63C3\u3048", justifycenter_desc:"\u4E2D\u592E\u63C3\u3048", justifyright_desc:"\u53F3\u63C3\u3048", justifyfull_desc:"\u5747\u7B49\u5272\u4ED8", bullist_desc:"\u756A\u53F7\u306A\u3057\u30EA\u30B9\u30C8", numlist_desc:"\u756A\u53F7\u3064\u304D\u30EA\u30B9\u30C8", outdent_desc:"\u30A4\u30F3\u30C7\u30F3\u30C8\u89E3\u9664", indent_desc:"\u30A4\u30F3\u30C7\u30F3\u30C8", undo_desc:"\u5143\u306B\u623B\u3059 (Ctrl+Z)", redo_desc:"\u3084\u308A\u76F4\u3059 (Ctrl+Y)", link_desc:"\u30EA\u30F3\u30AF\u306E\u633F\u5165/\u7DE8\u96C6", unlink_desc:"\u30EA\u30F3\u30AF\u89E3\u9664", image_desc:"\u753B\u50CF\u306E\u633F\u5165/\u7DE8\u96C6", cleanup_desc:"\u30B3\u30FC\u30C9\u6574\u5F62", code_desc:"HTML\u30BD\u30FC\u30B9\u7DE8\u96C6", sub_desc:"\u4E0B\u4ED8\u304D", sup_desc:"\u4E0A\u4ED8\u304D", hr_desc:"\u6C34\u5E73\u7DDA", removeformat_desc:"\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8\u89E3\u9664", custom1_desc:"\u8AAC\u660E\u6587\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002", forecolor_desc:"\u6587\u5B57\u8272", backcolor_desc:"\u80CC\u666F\u8272", charmap_desc:"\u7279\u6B8A\u6587\u5B57", visualaid_desc:"\u30AC\u30A4\u30C9\u30E9\u30A4\u30F3\u3068\u975E\u8868\u793A\u9805\u76EE\u306E\u8868\u793A\u5207\u66FF", anchor_desc:"\u30A2\u30F3\u30AB\u30FC\u306E\u633F\u5165/\u7DE8\u96C6", cut_desc:"\u5207\u308A\u53D6\u308A", copy_desc:"\u30B3\u30D4\u30FC", paste_desc:"\u8CBC\u308A\u4ED8\u3051", image_props_desc:"\u753B\u50CF\u306E\u30D7\u30ED\u30D1\u30C6\u30A3", newdocument_desc:"\u65B0\u898F\u4F5C\u6210", help_desc:"\u30D8\u30EB\u30D7", blockquote_desc:"\u5F15\u7528", clipboard_msg:"\u30B3\u30D4\u30FC/\u5207\u308A\u53D6\u308A/\u8CBC\u308A\u4ED8\u3051\u306FMozilla\u53CA\u3073Firefox\u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\n\u8A73\u7D30\u306F\u3053\u3061\u3089", path:"\u30D1\u30B9", newdocument:"\u7DE8\u96C6\u4E2D\u306E\u30C7\u30FC\u30BF\u3092\u7834\u68C4\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F", toolbar_focus:"\u30C4\u30FC\u30EB\u30DC\u30BF\u30F3\u3078\u30B8\u30E3\u30F3\u30D7 - Alt+Q, \u30A8\u30C7\u30A3\u30BF\u306B\u30B8\u30E3\u30F3\u30D7 - Alt-Z, \u30A8\u30EC\u30E1\u30F3\u30C8\u30D1\u30B9\u3078\u30B8\u30E3\u30F3\u30D7 - Alt-X", more_colors:"\u305D\u306E\u4ED6\u306E\u8272" }); tinyMCE.addI18n('ja.advanced',{ cut_desc:"\u5207\u308A\u53D6\u308A", copy_desc:"\u30B3\u30D4\u30FC", paste_desc:"\u8CBC\u308A\u4ED8\u3051", link_desc:"\u30EA\u30F3\u30AF\u306E\u633F\u5165/\u7DE8\u96C6", unlink_desc:"\u30EA\u30F3\u30AF\u89E3\u9664", image_desc:"\u753B\u50CF\u306E\u633F\u5165/\u7DE8\u96C6" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/is.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/i0000644000175000017500000000454011226234177033643 0ustar frankiefrankietinyMCE.addI18n('is.openacs',{ style_select:"St\u00EDlsni\u00F0", font_size:"Leturst\u00E6r\u00F0", fontdefault:"Leturger\u00F0", block:"Format", paragraph:"M\u00E1lsgrein", div:"Div", address:"Heimilisfang", pre:"Forsni\u00F0i\u00F0", h1:"Fyrirs\u00F6gn 1", h2:"Fyrirs\u00F6gn 2", h3:"Fyrirs\u00F6gn 3", h4:"Fyrirs\u00F6gn 4", h5:"Fyrirs\u00F6gn 5", h6:"Fyrirs\u00F6gn 6", blockquote:"Blockquote", code:"K\u00F3\u00F0i", samp:"K\u00F3\u00F0ad\u00E6mi", dt:"Definition term ", dd:"Definition description", bold_desc:"Feitletra (Ctrl+B)", italic_desc:"Sk\u00E1letra (Ctrl+I)", underline_desc:"Undirstrika (Ctrl+U)", striketrough_desc:"Yfirstrika", justifyleft_desc:"Vinstrijafna", justifycenter_desc:"Mi\u00F0jujafna", justifyright_desc:"H\u00E6grijafna", justifyfull_desc:"Jafna", bullist_desc:"B\u00F3lulisti", numlist_desc:"N\u00FAmera\u00F0ur listi", outdent_desc:"Draga \u00FAt", indent_desc:"Draga inn", undo_desc:"Taka til baka (Ctrl+Z)", redo_desc:"Endurtaka (Ctrl+Y)", link_desc:"Setja inn/breyta hlekk", unlink_desc:"Afhlekkja", image_desc:"Setja inn/breyta mynd", cleanup_desc:"Hreinsa sk\u00EDtugan k\u00F3\u00F0a", code_desc:"Breyta HTML k\u00F3\u00F0a", sub_desc:"Subscript", sup_desc:"Superscript", hr_desc:"Setja inn l\u00E1r\u00E9tta l\u00EDnu", removeformat_desc:"Hreinsa sni\u00F0", custom1_desc:"L\u00FDsingin \u00FE\u00EDn h\u00E9r", forecolor_desc:"Veldu lit texta", backcolor_desc:"Veldu bakgrunnslit", charmap_desc:"Setja inn t\u00E1kn", visualaid_desc:"Toggle guidelines/invisible elements", anchor_desc:"Setja inn/breyta akkeri", cut_desc:"Klippa", copy_desc:"Afrita", paste_desc:"L\u00EDma", image_props_desc:"Stillingar myndar", newdocument_desc:"N\u00FDtt skjal", help_desc:"Hj\u00E1lp", blockquote_desc:"Blockquote", clipboard_msg:"Afrita/Klippa/L\u00EDma er ekki a\u00F0gengilegt \u00ED Mozilla og Firefox eins og er.\nViltu f\u00E1 n\u00E1nari uppl\u00FDsingar?", path:"Sl\u00F3\u00F0", newdocument:"Ertu viss um a\u00F0 \u00FE\u00FA viljir hreinsa allt?", toolbar_focus:"Hoppa \u00ED t\u00F3lastiku - Alt+Q, Hoppa \u00ED ritil - Alt-Z, Hoppa \u00ED sl\u00F3\u00F0 - Alt-X", more_colors:"Fleiri litir" }); tinyMCE.addI18n('is.advanced',{ cut_desc:"Klippa", copy_desc:"Afrita", paste_desc:"L\u00EDma", link_desc:"Setja inn/breyta hlekk", unlink_desc:"Afhlekkja", image_desc:"Setja inn/breyta mynd" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/it.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/i0000644000175000017500000000453311226234177033645 0ustar frankiefrankietinyMCE.addI18n('it.openacs',{ style_select:"Stili", font_size:"Grandezza carattere", fontdefault:"Famiglia carattere", block:"Formato", paragraph:"Paragrafo", div:"Div", address:"Indirizzo", pre:"Preformattato", h1:"Intestazione 1", h2:"Intestazione 2", h3:"Intestazione 3", h4:"Intestazione 4", h5:"Intestazione 5", h6:"Intestazione 6", blockquote:"Testo quotato", code:"Codice", samp:"Esempio codice", dt:"Termine definizione", dd:"Descrizione definizione", bold_desc:"Grassetto (Ctrl+B)", italic_desc:"Corsivo (Ctrl+I)", underline_desc:"Sottolineato (Ctrl+U)", striketrough_desc:"Barrato", justifyleft_desc:"Allinea a sinistra", justifycenter_desc:"Centra", justifyright_desc:"Allinea a destra", justifyfull_desc:"Giustifica", bullist_desc:"Lista non ordinata", numlist_desc:"Lista ordinata", outdent_desc:"Sposta verso esterno", indent_desc:"Sposta verso interno", undo_desc:"Annulla (Ctrl+Z)", redo_desc:"Ripristina (Ctrl+Y)", link_desc:"Inserisci/modifica collegamento", unlink_desc:"Togli collegamento", image_desc:"Inserisci/modifica immagine", cleanup_desc:"Pulisci codice disordinato", code_desc:"Modifica sorgente HTML", sub_desc:"Pedice", sup_desc:"Apice", hr_desc:"Inserisci riga orizzontale", removeformat_desc:"Rimuovi formattazione", custom1_desc:"La tua descrizione personalizzata qui", forecolor_desc:"Seleziona colore testo", backcolor_desc:"Seleziona colore sfondo", charmap_desc:"Inserisci carattere speciale", visualaid_desc:"Mostra/nascondi linee guida/elementi invisibili", anchor_desc:"Inserisci/modifica ancora", cut_desc:"Taglia", copy_desc:"Copia", paste_desc:"Incolla", image_props_desc:"Propriet\u00E0 immagine", newdocument_desc:"Nuovo documento", help_desc:"Aiuto", blockquote_desc:"Testo quotato", clipboard_msg:"Copia/Taglia/Incolla non \u00E8 disponibile in Mozilla e Firefox..\r\nSi desidera avere maggiori informazioni su questo problema?", path:"Percorso", newdocument:"Sei sicuro di voler cancellare tutti i contenuti?", toolbar_focus:"Vai ai pulsanti strumento - Alt+Q, Vai all'editor - Alt-Z, Vai al percorso dell'elemento - Alt-X", more_colors:"Colori aggiuntivi" }); tinyMCE.addI18n('it.advanced',{ cut_desc:"Taglia", copy_desc:"Copia", paste_desc:"Incolla", link_desc:"Inserisci/modifica collegamento", unlink_desc:"Togli collegamento", image_desc:"Inserisci/modifica immagine" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ko.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/k0000644000175000017500000000570111226234177033645 0ustar frankiefrankietinyMCE.addI18n('ko.openacs',{ style_select:"\uC2A4\uD0C0\uC77C", font_size:"\uAE00\uAF34 \uD06C\uAE30", fontdefault:"\uAE00\uAF34", block:"\uD3EC\uB9F7", paragraph:"\uB2E8\uB77D", div:"Div", address:"\uC8FC\uC18C", pre:"pre", h1:"\uD45C\uC81C1", h2:"\uD45C\uC81C2", h3:"\uD45C\uC81C3", h4:"\uD45C\uC81C4", h5:"\uD45C\uC81C5", h6:"\uD45C\uC81C6", blockquote:"\uC778\uC6A9\uBB38", code:"\uCF54\uB4DC", samp:"\uC0D8\uD50C\uCF54\uB4DC", dt:"\uC5B4\uAD6C \uC815\uC758", dd:"\uC815\uC758 \uC124\uBA85", bold_desc:"\uAD75\uC740 \uAE00\uC528(Ctrl+B)", italic_desc:"\uC774\uD0E4\uB9AD(Ctrl+I)", underline_desc:"\uBC11\uC904(Ctrl+U)", striketrough_desc:"\uCDE8\uC18C\uC120", justifyleft_desc:"\uC67C\uCABD \uC815\uB82C", justifycenter_desc:"\uAC00\uC6B4\uB370 \uC815\uB82C", justifyright_desc:"\uC624\uB978\uCABD \uC815\uB82C", justifyfull_desc:"\uBC30\uBD84 \uC815\uB82C", bullist_desc:"\uBE44\uC21C\uCC28\uBAA9\uB85D", numlist_desc:"\uC21C\uCC28\uBAA9\uB85D", outdent_desc:"\uB0B4\uC5B4\uC4F0\uAE30", indent_desc:"\uB4E4\uC5EC\uC4F0\uAE30", undo_desc:"\uC2E4\uD589\uCDE8\uC18C(Ctrl+Z)", redo_desc:"\uB2E4\uC2DC\uC2E4\uD589(Ctrl+Y)", link_desc:"\uB9C1\uD06C\uC758 \uC0BD\uC785/\uD3B8\uC9D1", unlink_desc:"\uB9C1\uD06C \uC0AD\uC81C", image_desc:"\uC774\uBBF8\uC9C0 \uC0BD\uC785/\uD3B8\uC9D1", cleanup_desc:"\uC9C0\uC800\uBD84\uD55C \uCF54\uB4DC \uC0AD\uC81C", code_desc:"HTML \uD3B8\uC9D1", sub_desc:"\uC544\uB798\uCCA8\uC790", sup_desc:"\uC704\uCCA8\uC790", hr_desc:"\uAD6C\uBD84\uC120", removeformat_desc:"\uC11C\uC2DD \uD574\uC81C", custom1_desc:"\uCEE4\uC2A4\uD140 \uC124\uBA85", forecolor_desc:"\uAE00\uC790\uC0C9", backcolor_desc:"\uBC30\uACBD\uC0C9", charmap_desc:"\uD2B9\uC218 \uBB38\uC790", visualaid_desc:"\uAC00\uC774\uB4DC\uB77C\uC778 \uD45C\uC2DC/\uBE44\uD45C\uC2DC", anchor_desc:"\uC5E5\uCEE4 \uC0BD\uC785/\uD3B8\uC9D1", cut_desc:"\uC798\uB77C\uB0B4\uAE30", copy_desc:"\uBCF5\uC0AC", paste_desc:"\uBD99\uC774\uAE30", image_props_desc:"\uC774\uBBF8\uC9C0\uC18D\uC131", newdocument_desc:"\uC2E0\uADDC\uAE00 \uC791\uC131", help_desc:"\uB3C4\uC6C0\uB9D0", blockquote_desc:"\uC778\uC6A9\uBB38", clipboard_msg:"\uBCF5\uC0AC/\uC798\uB77C\uB0B4\uAE30/\uBD99\uC774\uAE30\uB294 Mozilla \uBC0FFirefox \uC5D0\uC11C \uC0AC\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.\n\uC0C1\uC138\uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uAE4C?", path:"Path", newdocument:"\uD3B8\uC9D1\uC911\uC758 \uB370\uC774\uD130\uB97C \uBAA8\uB450 \uC783\uC5B4\uB3C4 \uAD1C\uCC2E\uC2B5\uB2C8\uAE4C?", toolbar_focus:"\uBC84\uD2BC\uC73C\uB85C \uC810\uD504 - Alt+Q, \uC5D0\uB514\uD130\uB85C \uC810\uD504 - Alt-Z, Jump to element path - Alt-X", more_colors:"\uADF8 \uC678\uC758 \uC0C9" }); tinyMCE.addI18n('ko.advanced',{ cut_desc:"\uC798\uB77C\uB0B4\uAE30", copy_desc:"\uBCF5\uC0AC", paste_desc:"\uBD99\uC774\uAE30", link_desc:"\uB9C1\uD06C\uC758 \uC0BD\uC785/\uD3B8\uC9D1", unlink_desc:"\uB9C1\uD06C \uC0AD\uC81C", image_desc:"\uC774\uBBF8\uC9C0 \uC0BD\uC785/\uD3B8\uC9D1" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/lt.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/l0000644000175000017500000000563511226234177033654 0ustar frankiefrankietinyMCE.addI18n('lt.openacs',{ style_select:"Stiliai", font_size:"\u0160rifto dydis", fontdefault:"\u0160rifto \u0161eima", block:"Formatas", paragraph:"Paragrafas", div:"Div \u017Eym\u0117", address:"Adresas", pre:"Preformatuotas tekstas", h1:"Antra\u0161t\u0117 1", h2:"Antra\u0161t\u0117 2", h3:"Antra\u0161t\u0117 3", h4:"Antra\u0161t\u0117 4", h5:"Antra\u0161t\u0117 5", h6:"Antra\u0161t\u0117 6", blockquote:"Citatos blokas", code:"Kodas", samp:"Kodo pavyzdys", dt:"Apibr\u0117\u017Eimo terminas", dd:"Apibr\u0117\u017Eimo apra\u0161ymas", bold_desc:"Storas (Ctrl+B)", italic_desc:"Pasvir\u0119s (Ctrl+I)", underline_desc:"Pabrauktas (Ctrl+U)", striketrough_desc:"Perbrauktas", justifyleft_desc:"Lygiuoti pagal kair\u0119", justifycenter_desc:"Centruoti", justifyright_desc:"Lygiuoti pagal de\u0161in\u0119", justifyfull_desc:"Lygiuoti pagal abu kra\u0161tus", bullist_desc:"Ner\u016B\u0161uotas s\u0105ra\u0161as", numlist_desc:"R\u016B\u0161uotas skai\u010Diais s\u0105ra\u0161as", outdent_desc:"Stumti prie kairiojo kra\u0161to", indent_desc:"Stumti nuo kairiojo kra\u0161to", undo_desc:"Atstatyti (Ctrl+Z)", redo_desc:"Perdaryti (Ctrl+Y)", link_desc:"\u012Eterpti/redaguoti nuorod\u0105", unlink_desc:"Pa\u0161alinti nuorod\u0105", image_desc:"\u012Eterpti/redaguoti paveiksl\u0117l\u012F", cleanup_desc:"I\u0161valyti netvarking\u0105 kod\u0105", code_desc:"Redaguoti HTML i\u0161eities kod\u0105", sub_desc:"Apatinis indeksas", sup_desc:"Vir\u0161utinis indeksas", hr_desc:"\u012Eterpti horizontali\u0105 linij\u0105", removeformat_desc:"Pa\u0161alinti formatavim\u0105", custom1_desc:"J\u016Bs\u0173 apra\u0161ymas \u010Dia", forecolor_desc:"Parinkti teksto spalv\u0105", backcolor_desc:"Parinkti fono spalv\u0105", charmap_desc:"\u012Eterpti nestandartin\u012F simbol\u012F", visualaid_desc:"Kaitalioti gaires/nematom\u0173 element\u0173 rodym\u0105", anchor_desc:"\u012Eterpti/redaguoti inkar\u0105", cut_desc:"I\u0161kirpti", copy_desc:"Kopijuoti", paste_desc:"\u012Eklijuoti", image_props_desc:"Paveiksl\u0117lio nustatymai", newdocument_desc:"Naujas dokumentas", help_desc:"Pagalba", blockquote_desc:"Citatos blokas", clipboard_msg:"Kopijavimas/I\u0161kirpimas/\u012Eklijavimas negalimas Mozilla ir Firefox nar\u0161ykl\u0117se.\r\nAr norite daugiau informacijos apie \u0161i\u0105 problem\u0105?", path:"Kelias", newdocument:"Ar tikrai norite i\u0161trinti vis\u0105 turin\u012F?", toolbar_focus:"Per\u0161okimas prie \u012Franki\u0173 juostos mygtuk\u0173 - Alt+Q, Per\u0161okimas prie redaktoriaus - Alt-Z, Per\u0161okimas prie element\u0173 kelio - Alt-X", more_colors:"Daugiau spalv\u0173", link_delta_width:"70" }); tinyMCE.addI18n('lt.advanced',{ cut_desc:"I\u0161kirpti", copy_desc:"Kopijuoti", paste_desc:"\u012Eklijuoti", link_desc:"\u012Eterpti/redaguoti nuorod\u0105", unlink_desc:"Pa\u0161alinti nuorod\u0105", image_desc:"\u012Eterpti/redaguoti paveiksl\u0117l\u012F" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/lv.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/l0000644000175000017500000000524011226234177033644 0ustar frankiefrankietinyMCE.addI18n('lv.openacs',{ style_select:"Stili", font_size:"Fonta lielums", fontdefault:"Fonta veids", block:"Form\u0101ts", paragraph:"Rindkopa", div:"Div\u012Bzija", address:"Adrese", pre:"Priek\u0161format\u0113ts", h1:"Virsraksts 1", h2:"Virsraksts 2", h3:"Virsraksts 3", h4:"Virsraksts 4", h5:"Virsraksts 5", h6:"Virsraksts 6", blockquote:"Cit\u0101ts", code:"Kods", samp:"Koda piem\u0113rs", dt:"Defin\u012Bcijas termins ", dd:"Defin\u012Bcijas apraksts", bold_desc:"Treknraksts (Ctrl+B)", italic_desc:"Sl\u012Bpraksts (Ctrl+I)", underline_desc:"Pasv\u012Btrojums (Ctrl+U)", striketrough_desc:"P\u0101rsv\u012Btrojums", justifyleft_desc:"Novietot pa kreisi", justifycenter_desc:"Centr\u0113t", justifyright_desc:"Novietot pa labi", justifyfull_desc:"Nol\u012Bdzin\u0101t malas", bullist_desc:"Nenumur\u0113ts saraksts", numlist_desc:"Numur\u0113ts saraksts", outdent_desc:"Uzk\u0101pe", indent_desc:"Atk\u0101pe", undo_desc:"Atsaukt (Ctrl+Z)", redo_desc:"Atatsaukt (Ctrl+Y)", link_desc:"Ievietot/Redi\u0123\u0113t saiti", unlink_desc:"Atsait\u0113t", image_desc:"Ievietot/Redi\u0123\u0113t att\u0113lu", cleanup_desc:"Izt\u012Br\u012Bt nek\u0101rt\u012Bgu kodu", code_desc:"Redi\u0123\u0113t HTML kodu", sub_desc:"Apak\u0161raksts", sup_desc:"Aug\u0161raksts", hr_desc:"Ievietot horizont\u0101lu sv\u012Btru", removeformat_desc:"Izdz\u0113st format\u0113to", custom1_desc:"Tevis izdom\u0101ts apraksts \u0161eit", forecolor_desc:"Uzst\u0101d\u012Bt teksta kr\u0101su", backcolor_desc:"Uzst\u0101d\u012Bt fona kr\u0101su", charmap_desc:"Ievietot simbolu", visualaid_desc:"Uzlikt/Nov\u0101kt pal\u012Bgsv\u012Btras/neredzamos elementus", anchor_desc:"Ievietot/Redi\u0123\u0113t enkursaiti", cut_desc:"Izgriezt", copy_desc:"Kop\u0113t", paste_desc:"Iekop\u0113t", image_props_desc:"Bildes iestat\u012Bjumi", newdocument_desc:"Jauns dokuments", help_desc:"Pal\u012Bdz\u012Bba", blockquote_desc:"Cit\u0101ts", clipboard_msg:"Iesp\u0113ja Kop\u0113t/Izgriezt/Iekop\u0113t nav pieejama p\u0101rl\u016Bkiem Mozilla and Firefox.\r\nVai J\u016Bs v\u0113laties uzzin\u0101t vair\u0101k par \u0161o probl\u0113mu?", path:"Atra\u0161an\u0101s vieta", newdocument:"Vai J\u016Bs esat p\u0101rliecin\u0101ti, ka v\u0113laties izdz\u0113st visu saturu?", toolbar_focus:"Iet uz r\u012Bkpog\u0101m - Alt+Q, Iet uz redaktoru - Alt-Z, Iet uz elementa atra\u0161an\u0101s vietu - Alt-X", more_colors:"Vair\u0101k kr\u0101su" }); tinyMCE.addI18n('lv.advanced',{ cut_desc:"Izgriezt", copy_desc:"Kop\u0113t", paste_desc:"Iekop\u0113t", link_desc:"Ievietot/Redi\u0123\u0113t saiti", unlink_desc:"Atsait\u0113t", image_desc:"Ievietot/Redi\u0123\u0113t att\u0113lu" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ms.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/m0000644000175000017500000000406011226234177033644 0ustar frankiefrankietinyMCE.addI18n('ms.openacs',{ style_select:"Gaya", font_size:"Saiz Huruf", fontdefault:"Jenis Huruf", block:"Format", paragraph:"Perenggan", div:"Div", address:"Alamat", pre:"Telah diformatkan", h1:"Tajuk 1", h2:"Tajuk 2", h3:"Tajuk 3", h4:"Tajuk 4", h5:"Tajuk 5", h6:"Tajuk 6", blockquote:"Petikan blok", code:"Kod", samp:"Contoh kod", dt:"Maksud terma", dd:"Maksud huraian", bold_desc:"Tebal (Ctrl+B)", italic_desc:"Condong (Ctrl+I)", underline_desc:"Garis bawah (Ctrl+U)", striketrough_desc:"Garis tengah", justifyleft_desc:"Selari kekiri", justifycenter_desc:"Selari ketengah", justifyright_desc:"Selari kekanan", justifyfull_desc:"Selari penuh", bullist_desc:"Senarai tidak tertib", numlist_desc:"Senarai tertib", outdent_desc:"Lekuk kebelakang", indent_desc:"Lekuk kedepan", undo_desc:"Undur (Ctrl+Z)", redo_desc:"Maju (Ctrl+Y)", link_desc:"Sisip/sunting pautan", unlink_desc:"Tiada pautan", image_desc:"Sisip/sunting imej", cleanup_desc:"Bersihkan kod", code_desc:"Sunting kod HTML", sub_desc:"Subskrip", sup_desc:"Superskrip", hr_desc:"Sisip pembaris mengufuk", removeformat_desc:"Alih format", custom1_desc:"Huraian anda di sini", forecolor_desc:"Pilih warna teks", backcolor_desc:"Pilih warna latar belakang", charmap_desc:"Sisip aksara", visualaid_desc:"Alih garis panduan/unsur tak nampak", anchor_desc:"Sisip/sunting anchor", cut_desc:"Potong", copy_desc:"Salin", paste_desc:"Tempel", image_props_desc:"Alatan imej", newdocument_desc:"Dokumen baru", help_desc:"Bantuan", blockquote_desc:"Petikan blok", clipboard_msg:"Salin/Potong/Tempel tidak disokong dalam Mozilla dan Firefox.\r\nAdakah anda mahu informasi lanjut tentang isu ini?", path:"Laluan", newdocument:"Hapus semua kandungan?", toolbar_focus:"Lompat ke butang alatan - Alt+Q, Lompat ke editor - Alt-Z, Lompat ke unsur laluan - Alt-X", more_colors:"Warna lain" }); tinyMCE.addI18n('ms.advanced',{ cut_desc:"Potong", copy_desc:"Salin", paste_desc:"Tempel", link_desc:"Sisip/sunting pautan", unlink_desc:"Tiada pautan", image_desc:"Sisip/sunting imej" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/nl.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/n0000644000175000017500000000417111226234177033650 0ustar frankiefrankietinyMCE.addI18n('nl.openacs',{ style_select:"Stijlen", font_size:"Tekengrootte", fontdefault:"Lettertype", block:"Opmaak", paragraph:"Alinea", div:"Div", address:"Adres", pre:"Vaste opmaak", h1:"Kop 1", h2:"Kop 2", h3:"Kop 3", h4:"Kop 4", h5:"Kop 5", h6:"Kop 6", blockquote:"Citaat", code:"Code", samp:"Codevoorbeeld", dt:"Definitieterm", dd:"Definitiebeschrijving", bold_desc:"Vet (Ctrl+B)", italic_desc:"Cursief (Ctrl+I)", underline_desc:"Onderstrepen (Ctrl+U)", striketrough_desc:"Doorhalen", justifyleft_desc:"Links uitlijnen", justifycenter_desc:"Centreren", justifyright_desc:"Rechts uitlijnen", justifyfull_desc:"Uitvullen", bullist_desc:"Opsommingstekens", numlist_desc:"Nummering", outdent_desc:"Inspringing verkleinen", indent_desc:"Inspringing vergroten", undo_desc:"Ongedaan maken (Ctrl+Z)", redo_desc:"Herhalen (Ctrl+Y)", link_desc:"Link invoegen/bewerken", unlink_desc:"Link verwijderen", image_desc:"Afbeelding invoegen/bewerken", cleanup_desc:"Code opruimen", code_desc:"HTML bron bewerken", sub_desc:"Subscript", sup_desc:"Superscript", hr_desc:"Scheidingslijn invoegen", removeformat_desc:"Opmaak verwijderen", custom1_desc:"Uw eigen beschrijving hier", forecolor_desc:"Tekstkleur", backcolor_desc:"Tekstmarkeringskleur", charmap_desc:"Symbool invoegen", visualaid_desc:"Hulplijnen weergeven", anchor_desc:"Anker invoegen/bewerken", cut_desc:"Knippen", copy_desc:"Kopi\u00EBren", paste_desc:"Plakken", image_props_desc:"Afbeeldingseigenschappen", newdocument_desc:"Nieuw document", help_desc:"Help", blockquote_desc:"Citaat", clipboard_msg:"Kopi\u00EBren/knippen/plakken is niet beschikbaar in Mozilla en Firefox.\nWilt u meer informatie over deze beperking?", path:"Pad", newdocument:"Weet u zeker dat u alle inhoud wilt wissen?", toolbar_focus:"Spring naar werkbalk - Alt+Q, Spring naar tekst - Alt-Z, Spring naar elementpad - Alt-X", more_colors:"Meer kleuren" }); tinyMCE.addI18n('nl.advanced',{ cut_desc:"Knippen", copy_desc:"Kopi\u00EBren", paste_desc:"Plakken", link_desc:"Link invoegen/bewerken", unlink_desc:"Link verwijderen", image_desc:"Afbeelding invoegen/bewerken" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/nn.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/n0000644000175000017500000000414411226234177033650 0ustar frankiefrankietinyMCE.addI18n('nn.openacs',{ style_select:"Stilar", font_size:"Skriftstorleik", fontdefault:"Skriftfamilie", block:"Format", paragraph:"Avsnitt", div:"Div", address:"Adresse", pre:"Pre-formatert", h1:"Overskrift 1", h2:"Overskrift 2", h3:"Overskrift 3", h4:"Overskrift 4", h5:"Overskrift 5", h6:"Overskrift 6", blockquote:"Innrykk", code:"Kode", samp:"Kodeeksempel", dt:"Definisjonsuttrykk", dd:"Definisjonsbeskrivelse", bold_desc:"Feit", italic_desc:"Kursiv", underline_desc:"Understreking", striketrough_desc:"Gjennomstreking", justifyleft_desc:"Venstrejustert", justifycenter_desc:"Midtstilt", justifyright_desc:"H\u00F8grejustert", justifyfull_desc:"Blokkjustert", bullist_desc:"Punktliste", numlist_desc:"Nummerliste", outdent_desc:"Reduser innrykk", indent_desc:"Auk innrykk", undo_desc:"Angre", redo_desc:"Gjer om", link_desc:"Set inn / endre lenkje", unlink_desc:"Fjern lenkje", image_desc:"Set inn / endre bilete", cleanup_desc:"Rens grisete kode", code_desc:"Redigere HTML-koden", sub_desc:"Senka skrift", sup_desc:"Heva skrift", hr_desc:"Set inn horisontal linje", removeformat_desc:"Fjern formatering", custom1_desc:"Din spesialfunksjondefinisjon her", forecolor_desc:"Vel skriftfarge", backcolor_desc:"Vel bakgrunnsfarge", charmap_desc:"Set inn spesialteikn", visualaid_desc:"Sl\u00E5 av/p\u00E5 usynlige element", anchor_desc:"Set inn / endre anker", cut_desc:"Klipp ut", copy_desc:"Kopier", paste_desc:"Lim inn", image_props_desc:"Eigenskaper for bilete", newdocument_desc:"Nytt dokument", help_desc:"Hjelp", blockquote_desc:"Innrykk", clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikkje i Mozilla og Firefox. \r\n Vil du vite meir om dette?", path:"Sti", newdocument:"Er du sikker p\u00E5 at du vil slette alt innhald?", toolbar_focus:"Skift til verktyknappar - Alt+Q, Skift til editor - Alt-Z, Skift til elementsti - Alt-", more_colors:"Fleire fargar" }); tinyMCE.addI18n('nn.advanced',{ cut_desc:"Klipp ut", copy_desc:"Kopier", paste_desc:"Lim inn", link_desc:"Set inn / endre lenkje", unlink_desc:"Fjern lenkje", image_desc:"Set inn / endre bilete" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/no.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/n0000644000175000017500000000415211226234177033647 0ustar frankiefrankietinyMCE.addI18n('no.openacs',{ style_select:"Stiler", font_size:"Skriftst\u00F8rrelse", fontdefault:"Skriftfamilie", block:"Format", paragraph:"Avsnitt", div:"Div", address:"Adresse", pre:"Pre-formatert", h1:"Overskrift 1", h2:"Overskrift 2", h3:"Overskrift 3", h4:"Overskrift 4", h5:"Overskrift 5", h6:"Overskrift 6", blockquote:"Innrykk", code:"Kode", samp:"Kodeeksempel", dt:"Definisjonsuttrykk", dd:"Definisjonsbeskrivelse", bold_desc:"Fet", italic_desc:"Kursiv", underline_desc:"Understrek", striketrough_desc:"Gjennomstrek", justifyleft_desc:"Venstrejustert", justifycenter_desc:"Midtstilt", justifyright_desc:"H\u00F8yrejustert", justifyfull_desc:"Blokkjustert", bullist_desc:"Punktliste", numlist_desc:"Nummerliste", outdent_desc:"Reduser innrykk", indent_desc:"\u00D8k innrykk", undo_desc:"Angre", redo_desc:"Gj\u00F8r om", link_desc:"Sett inn / endre lenke", unlink_desc:"Fjern lenke", image_desc:"Sett inn / endre bilde", cleanup_desc:"Rens grisete kode", code_desc:"Redigere HTML-kode", sub_desc:"Senk skrift", sup_desc:"Hev skrift", hr_desc:"Sett inn horisontal linje", removeformat_desc:"Fjern formatering", custom1_desc:"Din spesialfunksjondefinisjon her", forecolor_desc:"Vel skriftfarge", backcolor_desc:"Vel bakgrunnsfarge", charmap_desc:"Sett inn spesialtegn", visualaid_desc:"Sl\u00E5 av/p\u00E5 usynlige element", anchor_desc:"Sett inn / endre anker", cut_desc:"Klipp ut", copy_desc:"Kopier", paste_desc:"Lim inn", image_props_desc:"Egenskaper for bilde", newdocument_desc:"Nytt dokument", help_desc:"Hjelp", blockquote_desc:"Innrykk", clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikke i Mozilla og Firefox. \r\n Vil du vite mer om dette?", path:"Sti", newdocument:"Er du sikker p\u00E5 at du vil slette alt innhold?", toolbar_focus:"Skift til verkt\u00F8yknapper - Alt+Q, Skift til editor - Alt-Z, Skift til elementsti - Alt-", more_colors:"Flere farger" }); tinyMCE.addI18n('no.advanced',{ cut_desc:"Klipp ut", copy_desc:"Kopier", paste_desc:"Lim inn", link_desc:"Sett inn / endre lenke", unlink_desc:"Fjern lenke", image_desc:"Sett inn / endre bilde" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/pl.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/p0000644000175000017500000000505011226234200033632 0ustar frankiefrankietinyMCE.addI18n('pl.openacs',{ style_select:"Styl", font_size:"Rozmiar czcionki", fontdefault:"Rodzaj czcionki", block:"Format", paragraph:"Paragraf", div:"Div", address:"Adres", pre:"Czcionka o sta\u0142ej szeroko\u015Bci", h1:"Nag\u0142\u00F3wek 1", h2:"Nag\u0142\u00F3wek 2", h3:"Nag\u0142\u00F3wek 3", h4:"Nag\u0142\u00F3wek 4", h5:"Nag\u0142\u00F3wek 5", h6:"Nag\u0142\u00F3wek 6", blockquote:"Wydzielony blok", code:"Kod", samp:"Pr\u00F3bka kodu", dt:"Definicja terminu ", dd:"Opis terminu", bold_desc:"Pogrubienie (Ctrl+B)", italic_desc:"Kursywa (Ctrl+I)", underline_desc:"Podkre\u015Blenie (Ctrl+U)", striketrough_desc:"Przekre\u015Blenia", justifyleft_desc:"Wyr\u00F3wnaj do lewej", justifycenter_desc:"Wycentruj", justifyright_desc:"Wyr\u00F3wnaj do prawej", justifyfull_desc:"R\u00F3wnanie do prawej i lewej", bullist_desc:"Lista nienumerowana", numlist_desc:"Lista numerowana", outdent_desc:"Cofnij wci\u0119cie", indent_desc:"Wci\u0119cie", undo_desc:"Cofnij (Ctrl+Z)", redo_desc:"Pon\u00F3w (Ctrl+Y)", link_desc:"Wstaw/edytuj link", unlink_desc:"Usu\u0144 link", image_desc:"Wstaw/edytuj obraz", cleanup_desc:"Wyczy\u015B\u0107 nieuporz\u0105dkowany kod", code_desc:"Edytuj \u017Ar\u00F3d\u0142o HTML", sub_desc:"Indeks dolny", sup_desc:"Indeks g\u00F3rny", hr_desc:"Wstaw poziom\u0105 lini\u0119", removeformat_desc:"Usu\u0144 formatowanie", custom1_desc:"Tw\u00F3j niestandardowy opis tutaj", forecolor_desc:"Wybierz kolor tekstu", backcolor_desc:"Wybierz kolor t\u0142a", charmap_desc:"Wstaw niestandardowy znak", visualaid_desc:"Prze\u0142\u0105cz widoczno\u015B\u0107 wska\u017Anik\u00F3w i niewidocznych element\u00F3w", anchor_desc:"Wstaw/edytuj kotwic\u0119", cut_desc:"Wytnij", copy_desc:"Kopiuj", paste_desc:"Wklej", image_props_desc:"W\u0142a\u015Bciwo\u015Bci obrazka", newdocument_desc:"Nowy dokument", help_desc:"Pomoc", blockquote_desc:"Blok cytatu", clipboard_msg:"Akcje Kopiuj/Wytnij/Wklej nie s\u0105 dost\u0119pne w Mozilli i Firefox.\nCzy chcesz wi\u0119cej informacji o tym problemie?", path:"\u015Acie\u017Cka", newdocument:"Czy jeste\u015B pewnien, ze chcesz wyczy\u015Bci\u0107 ca\u0142\u0105 zawarto\u015B\u0107?", toolbar_focus:"Przeskocz do przycisk\u00F3w narz\u0119dzi - Alt+Q, Przeskocz do edytora - Alt-Z, Przeskocz do elementu \u015Bcie\u017Cki - Alt-X", more_colors:"Wi\u0119cej kolor\u00F3w" }); tinyMCE.addI18n('pl.advanced',{ cut_desc:"Wytnij", copy_desc:"Kopiuj", paste_desc:"Wklej", link_desc:"Wstaw/edytuj link", unlink_desc:"Usu\u0144 link", image_desc:"Wstaw/edytuj obraz" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/pt.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/p0000644000175000017500000000467611226234200033647 0ustar frankiefrankietinyMCE.addI18n('pt.openacs',{ style_select:"Estilos", font_size:"Tamanho", fontdefault:"Tipo de fonte", block:"Formata\u00E7\u00E3o", paragraph:"Par\u00E1grafo", div:"Div", address:"Endere\u00E7o", pre:"Pr\u00E9-formatado", h1:"T\u00EDtulo 1", h2:"T\u00EDtulo 2", h3:"T\u00EDtulo 3", h4:"T\u00EDtulo 4", h5:"T\u00EDtulo 5", h6:"T\u00EDtulo 6", blockquote:"Cita\u00E7\u00E3o em bloco", code:"C\u00F3digo", samp:"Amostra de c\u00F3digo", dt:"Termo da defini\u00E7\u00E3o", dd:"Descri\u00E7\u00E3o da defini\u00E7\u00E3o", bold_desc:"Negrito (Ctrl+B)", italic_desc:"It\u00E1lico (Ctrl+I)", underline_desc:"Sublinhado (Ctrl+U)", striketrough_desc:"Riscado", justifyleft_desc:"Alinhar \u00E0 esquerda", justifycenter_desc:"Centrar", justifyright_desc:"Alinhar \u00E0 direita", justifyfull_desc:"Justificar", bullist_desc:"Marcadores", numlist_desc:"Numera\u00E7\u00E3o", outdent_desc:"Diminuir avan\u00E7o", indent_desc:"Aumentar avan\u00E7o", undo_desc:"Desfazer (Ctrl+Z)", redo_desc:"Refazer (Ctrl+Y)", link_desc:"Inserir/editar hyperlink", unlink_desc:"Remover hyperlink", image_desc:"Inserir/editar imagem", cleanup_desc:"Limpar c\u00F3digo incorreto", code_desc:"Editar c\u00F3digo fonte", sub_desc:"Inferior \u00E0 linha", sup_desc:"Superior \u00E0 linha", hr_desc:"Inserir separador horizontal", removeformat_desc:"Remover formata\u00E7\u00E3o", custom1_desc:"Insira aqui a sua descri\u00E7\u00E3o personalizada", forecolor_desc:"Selecionar a cor do texto", backcolor_desc:"Selecionar a cor de fundo", charmap_desc:"Inserir caracteres especiais", visualaid_desc:"Alternar guias/elementos invis\u00EDveis", anchor_desc:"Inserir/editar \u00E2ncora", cut_desc:"Cortar", copy_desc:"Copiar", paste_desc:"Colar", image_props_desc:"Propriedades da imagem", newdocument_desc:"Novo documento", help_desc:"Ajuda", blockquote_desc:"Cita\u00E7\u00E3o em bloco", clipboard_msg:"Copiar/cortar/colar n\u00E3o est\u00E1 dispon\u00EDvel no Mozilla e Firefox. Deseja mais informa\u00E7\u00F5es sobre este problema?", path:"Endere\u00E7o", newdocument:"Tem a certeza que deseja apagar tudo?", toolbar_focus:"Ir para as ferramentas - Alt+Q, Ir para o editor - Alt-Z, Ir para o endere\u00E7o do elemento - Alt-X", more_colors:"Mais cores" }); tinyMCE.addI18n('pt.advanced',{ cut_desc:"Cortar", copy_desc:"Copiar", paste_desc:"Colar", link_desc:"Inserir/editar hyperlink", unlink_desc:"Remover hyperlink", image_desc:"Inserir/editar imagem" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ro.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/r0000644000175000017500000000453311226234200033641 0ustar frankiefrankietinyMCE.addI18n('ro.openacs',{ style_select:"Stiluri", font_size:"M\u0103rime font", fontdefault:"Font", block:"Format", paragraph:"Paragraf", div:"Div", address:"Adres\u0103", pre:"Preformatat", h1:"Titlu 1", h2:"Titlu 2", h3:"Titlu 3", h4:"Titlu 4", h5:"Titlu 5", h6:"Titlu 6", blockquote:"Citat", code:"Cod", samp:"Mostr\u0103 de cod", dt:"Termen definit ", dd:"Defini\u0163ie", bold_desc:"\u00CEngro\u015Fat (Ctrl+B)", italic_desc:"Italic (Ctrl+I)", underline_desc:"Subliniat (Ctrl+U)", striketrough_desc:"T\u0103iat", justifyleft_desc:"Aliniere la st\u00E2nga", justifycenter_desc:"Centrare", justifyright_desc:"Aliniere la dreapta", justifyfull_desc:"Aliniere pe toat\u0103 l\u0103\u0163imea", bullist_desc:"List\u0103 neordonat\u0103", numlist_desc:"List\u0103 ordonat\u0103", outdent_desc:"De-indenteaz\u0103", indent_desc:"Indenteaz\u0103", undo_desc:"Undo (Ctrl+Z)", redo_desc:"Ref\u0103 (Ctrl+Y)", link_desc:"Inserare/editare leg\u0103tur\u0103", unlink_desc:"\u015Eterge leg\u0103tura", image_desc:"Inserare/editare imagine", cleanup_desc:"Cur\u0103\u0163are cod", code_desc:"Editare surs\u0103 HTML", sub_desc:"Subscript", sup_desc:"Superscript", hr_desc:"Insereaz\u0103 linie orizontal\u0103", removeformat_desc:"Anuleaz\u0103 formatarea", custom1_desc:"Descriere ...", forecolor_desc:"Culoare text", backcolor_desc:"Culoare fundal", charmap_desc:"Inserare caracter special", visualaid_desc:"Comut\u0103 ghidajele/elementele invizibile", anchor_desc:"Inserare/editare ancor\u0103", cut_desc:"Taie", copy_desc:"Copiaz\u0103", paste_desc:"Lipe\u015Fte", image_props_desc:"Detalii imagine", newdocument_desc:"Document nou", help_desc:"Autor", blockquote_desc:"Citat", clipboard_msg:"Copierea/T\u0103ierea/Lipirea nu sunt disponibile \u00EEn Mozilla \u015Fi Firefox.\nDori\u0163i mai multe informa\u0163ii despre aceast\u0103 problem\u0103?", path:"Cale", newdocument:"Sigur dori\u0163i s\u0103 \u015Fterge\u0163i tot?", toolbar_focus:"S\u0103ri\u0163i la instrumente - Alt+Q, S\u0103ri\u0163i la editor - Alt-Z, S\u0103ri\u0163i la cale - Alt-X", more_colors:"Mai multe culori" }); tinyMCE.addI18n('ro.advanced',{ cut_desc:"Taie", copy_desc:"Copiaz\u0103", paste_desc:"Lipe\u015Fte", link_desc:"Inserare/editare leg\u0103tur\u0103", unlink_desc:"\u015Eterge leg\u0103tura", image_desc:"Inserare/editare imagine" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/si.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/s0000644000175000017500000001362411226234200033643 0ustar frankiefrankietinyMCE.addI18n('si.openacs',{ style_select:"\u0DC1\u0DDB\u0DBD\u0DD2\u0DBA", font_size:"\u0DB4\u0DB1\u0DCA\u0DAF \u0DB4\u0DCA\u200D\u0DBB\u0DB8\u0DCF\u0DAB\u0DBA", fontdefault:"\u0DB4\u0DB1\u0DCA\u0DAF \u0DC3\u0DB8\u0DD6\u0DC4\u0DBA", block:"\u0D86\u0D9A\u0DD8\u0DAD\u0DD2\u0DBA", paragraph:"\u200D\u0DA1\u0DDA\u0DAF\u0DBA", div:"Div", address:"\u0DBD\u0DD2\u0DB4\u0DD2\u0DB1\u0DBA", pre:"\u0DB4\u0DD6\u0DBB\u0DCA\u0DC0 \u0DB1\u0DD2\u0DBB\u0DCA\u0DB8\u0DCF\u0DAB\u0DBA", h1:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0 1", h2:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0 2", h3:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0 3", h4:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0 4", h5:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0 5", h6:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0 6", blockquote:"Blockquote", code:"\u0D9A\u0DDA\u0DAD\u0DBA", samp:"\u0D9A\u0DDA\u0DAD \u0DC3\u0DCF\u0DB8\u0DCA\u0DB4\u0DBD", dt:"\u0DB1\u0DD2\u0DBB\u0DCA\u0DC0\u0DA0\u0DB1\u0DBA ", dd:"\u0DB1\u0DD2\u0DBB\u0DCA\u0DC0\u0DA0\u0DB1 \u0DC0\u0DD2\u0DC3\u0DCA\u0DAD\u0DBB\u0DBA", bold_desc:"Bold (Ctrl+B)", italic_desc:"Italic (Ctrl+I)", underline_desc:"Underline (Ctrl+U)", striketrough_desc:"Strikethrough", justifyleft_desc:"\u0DC0\u0DB8\u0DCA \u0DB4\u0DD9\u0DC5\u0DA7 \u0D9C\u0DB1\u0DCA\u0DB1\u0DC0\u0DCF", justifycenter_desc:"\u0DB8\u0DD0\u0DAF \u0DB4\u0DD9\u0DC5\u0DA7 \u0D9C\u0DB1\u0DCA\u0DB1\u0DC0\u0DCF", justifyright_desc:"\u0DAF\u0D9A\u0DD4\u0DAB\u0DD4 \u0DB4\u0DD9\u0DC5\u0DA7 \u0D9C\u0DB1\u0DCA\u0DB1\u0DC0\u0DCF", justifyfull_desc:"\u0DB4\u0DD9\u0DC5\u0DA7 \u0D9C\u0DB1\u0DCA\u0DB1\u0DC0\u0DCF", bullist_desc:"\u0D85\u0D9A\u0DCA\u200D\u0DBB\u0DB8\u0DCF\u0DB1\u0DD4\u0D9A\u0DD6\u0DBD \u0DBD\u0DD0\u0DBA\u0DD2\u0DC3\u0DCA\u0DAD\u0DD4\u0DC0", numlist_desc:"\u0D9A\u0DCA\u200D\u0DBB\u0DB8\u0DCF\u0DB1\u0DD4\u0D9A\u0DD6\u0DBD \u0DBD\u0DD0\u0DBA\u0DD2\u0DC3\u0DCA\u0DAD\u0DD4\u0DC0", outdent_desc:"Outdent", indent_desc:"Indent", undo_desc:"\u0DB1\u0DD2\u0DC1\u0DCA\u0DB4\u0DCA\u200D\u0DBB\u0DB7 \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1(Ctrl+Z)", redo_desc:"\u0DB1\u0DD0\u0DC0\u0DAD \u0D9A\u0DBB\u0DB1\u0DC0\u0DCF (Ctrl+Y)", link_desc:"\u0DC3\u0DB8\u0DCA\u0DB6\u0DB1\u0DCA\u0DB0\u0D9A\u0DBA \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", unlink_desc:"Unlink", image_desc:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DBA \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1 ", cleanup_desc:"\u0DC0\u0DD0\u0DBB\u0DAF\u0DD2 \u0D9A\u0DDA\u0DAD \u0D89\u0DC0\u0DAD\u0DCA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", code_desc:" HTML \u0DB8\u0DD6\u0DBD\u0DCF\u0DC1\u0DCA\u200D\u0DBB\u0DBA \u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", sub_desc:"\u0DBA\u0DA7\u0DD2\u0DBD\u0D9A\u0DD4\u0DAB\u0DD4", sup_desc:"\u0D8B\u0DA9\u0DD4\u0DBD\u0D9A\u0DD4\u0DAB", hr_desc:"\u0DAD\u0DD2\u0DBB\u0DC3\u0DCA \u0DBB\u0DD6\u0DBD \u0D87\u0DAD\u0DD4\u0DBD\u0DCA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", removeformat_desc:"\u0D86\u0D9A\u0DD8\u0DAD\u0DD2\u0D9A\u0DBB\u0DAB\u0DBA \u0D89\u0DC0\u0DAD\u0DCA\u0D9A\u0DBB\u0DB1\u0DC0\u0DCF", custom1_desc:"\u0D94\u0DB6\u0DDA \u0DC0\u0DCA\u200D\u0DBA\u0DC0\u0DC4\u0DCF\u0DBB\u0DD2\u0D9A \u0DC0\u0DD2\u0DC3\u0DCA\u0DAD\u0DBB\u0DBA", forecolor_desc:" \u0DB4\u0DCF\u0DAA\u0DBA\u0DD9\u0DC4\u0DD2 \u0DC0\u0DBB\u0DCA\u0DAB\u0DBA \u0DAD\u0DDD\u0DBB\u0DCF\u0D9C\u0DB1\u0DCA\u0DB1\u0DC0\u0DCF", backcolor_desc:"\u0DB4\u0DC3\u0DD4\u0DB6\u0DD2\u0DB8 \u0DC0\u0DBB\u0DCA\u0DAB\u0DBA \u0DAD\u0DDD\u0DBB\u0DCF\u0D9C\u0DB1\u0DCA\u0DB1\u0DC0\u0DCF", charmap_desc:" \u0DB7\u0DCF\u0DC0\u0DD2\u0DAD \u0D85\u0D9A\u0DCA\u0DC2\u0DBB\u0DBA \u0D87\u0DAD\u0DD4\u0DBD\u0DD4 \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", visualaid_desc:"\u0DB8\u0DCF\u0DBB\u0DCA\u0D9C\u0DC3\u0DD6\u0DA0\u0D9A/\u0D85\u0DAF\u0DD8\u0DC1\u0DCA\u200D\u0DBA \u0DB8\u0DD6\u0DBD\u0DD2\u0D9A\u0DCF\u0D82\u0D9C", anchor_desc:"\u0D86\u0DB0\u0DCF\u0DBB\u0DBA \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1 ", cut_desc:"Cut", copy_desc:"\t\u0DB4\u0DD2\u0DA7\u0DB4\u0DAD\u0DCA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", image_props_desc:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DD2 \u0DBD\u0D9A\u0DCA\u0DC2\u0DAB\u0DBA", newdocument_desc:"\u0DB1\u0DC0 \u0DBD\u0DDA\u0D9B\u0DB1\u0DBA", help_desc:"\u0D8B\u0DB4\u0D9A\u0DCF\u0DBB\u0DBA", blockquote_desc:"Blockquote", clipboard_msg:"\u0DB4\u0DD2\u0DA7\u0DB4\u0DAD\u0DCA \u0D9A\u0DD2\u0DBB\u0DD3\u0DB8/\u0D89\u0DC0\u0DAD\u0DCA \u0D9A\u0DD2\u0DBB\u0DD3\u0DB8/\u0D87\u0DBD\u0DC0\u0DD3\u0DB8 \u0DB8\u0DDC\u0DC3\u0DD2\u0DBD\u0DCA\u0DBD\u0DCF \u0DC4\u0DCF \u0DC6\u0DBA\u0DBB\u0DCA \u0DC6\u0DDC\u0D9A\u0DCA\u0DC3\u0DCA \u0DC4\u0DD2 \u0D87\u0DAD\u0DD4\u0DC5\u0DAD\u0DCA \u0DB1\u0DDC\u0DC0\u0DDA.\r\n\u0D94\u0DB6\u0DA7 \u0DB8\u0DDA \u0DB4\u0DD2\u0DC5\u0DD2\u0DB6\u0DB3\u0DC0 \u0DAD\u0DA0\u0DAF\u0DD4\u0DBB\u0DA7\u0DAD\u0DCA \u0DAD\u0DDC\u0DBB\u0DAD\u0DD4\u0DBB\u0DD4 \u0D85\u0DC0\u0DC1\u0DCA\u200D\u0DBA \u0DC0\u0DDA\u0DAF?", path:"\u0DB8\u0D9F", newdocument:"\u0D94\u0DB6\u0DA7 \u0DB8\u0DD9\u0DB8 \u0D85\u0DB1\u0DCA\u0DAD\u0DBB\u0DCA\u0D9C\u0DAD\u0DBA \u0DB8\u0D9A\u0DCF \u0DAF\u0DD0\u0DB8\u0DD3\u0DB8\u0DA7 \u0D85\u0DC0\u0DC1\u0DCA\u200D\u0DBA \u0DB8 \u0DAF?", toolbar_focus:"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X", more_colors:"\u0DAD\u0DC0\u0DAD\u0DCA \u0DC0\u0DBB\u0DCA\u0DAB" }); tinyMCE.addI18n('si.advanced',{ cut_desc:"Cut", copy_desc:"\t\u0DB4\u0DD2\u0DA7\u0DB4\u0DAD\u0DCA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", image_props_desc:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DD2 \u0DBD\u0D9A\u0DCA\u0DC2\u0DAB\u0DBA", link_desc:"\u0DC3\u0DB8\u0DCA\u0DB6\u0DB1\u0DCA\u0DB0\u0D9A\u0DBA \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", unlink_desc:"Unlink", image_desc:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DBA \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1 " });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ru.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/r0000644000175000017500000001565511226234200033650 0ustar frankiefrankietinyMCE.addI18n('ru.openacs',{ style_select:"\u0421\u0442\u0438\u043B\u0438", font_size:"\u0420\u0430\u0437\u043C\u0435\u0440", fontdefault:"\u0428\u0440\u0438\u0444\u0442", block:"\u0424\u043E\u0440\u043C\u0430\u0442", paragraph:"\u0410\u0431\u0437\u0430\u0446", div:"\u0420\u0430\u0437\u0434\u0435\u043B", address:"\u0410\u0434\u0440\u0435\u0441", pre:"\u0424\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439", h1:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 1", h2:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 2", h3:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 3", h4:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 4", h5:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 5", h6:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 6", blockquote:"\u0426\u0438\u0442\u0430\u0442\u0430", code:"\u041A\u043E\u0434", samp:"\u041F\u0440\u0438\u043C\u0435\u0440 \u043A\u043E\u0434\u0430", dt:"\u0422\u0435\u0440\u043C\u0438\u043D", dd:"\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435", bold_desc:"\u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439 (Ctrl+B)", italic_desc:"\u041A\u0443\u0440\u0441\u0438\u0432 (Ctrl+I)", underline_desc:"\u041F\u043E\u0434\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044B\u0439 (Ctrl+U)", striketrough_desc:"\u0417\u0430\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044B\u0439", justifyleft_desc:"\u041F\u043E \u043B\u0435\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", justifycenter_desc:"\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443", justifyright_desc:"\u041F\u043E \u043F\u0440\u0430\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", justifyfull_desc:"\u041F\u043E \u0448\u0438\u0440\u0438\u043D\u0435", bullist_desc:"\u041C\u0430\u0440\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A", numlist_desc:"\u041D\u0443\u043C\u0435\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441\u043F\u0438\u0441\u043E\u043A", outdent_desc:"\u0423\u043C\u0435\u043D\u044C\u0448\u0438\u0442\u044C \u043E\u0442\u0441\u0442\u0443\u043F", indent_desc:"\u0423\u0432\u0435\u043B\u0438\u0447\u0438\u0442\u044C \u043E\u0442\u0441\u0442\u0443\u043F", undo_desc:"\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C (Ctrl+Z)", redo_desc:"\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C (Ctrl+Y)", link_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443", unlink_desc:"\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443", image_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435", cleanup_desc:"\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C", code_desc:"\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C HTML-\u043A\u043E\u0434", sub_desc:"\u041D\u0438\u0436\u043D\u0438\u0439 \u0438\u043D\u0434\u0435\u043A\u0441", sup_desc:"\u0412\u0435\u0440\u0445\u043D\u0438\u0439 \u0438\u043D\u0434\u0435\u043A\u0441", hr_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0433\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u044C\u043D\u0443\u044E \u043B\u0438\u043D\u0438\u044E", removeformat_desc:"\u0423\u0431\u0440\u0430\u0442\u044C \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435", custom1_desc:"\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435", forecolor_desc:"\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0446\u0432\u0435\u0442 \u0442\u0435\u043A\u0441\u0442\u0430", backcolor_desc:"\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0446\u0432\u0435\u0442 \u0444\u043E\u043D\u0430", charmap_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0439 \u0441\u0438\u043C\u0432\u043E\u043B", visualaid_desc:"\u0412\u043A\u043B./\u0432\u044B\u043A\u043B. \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0438 \u043D\u0435\u0432\u0438\u0434\u0438\u043C\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B", anchor_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044F\u043A\u043E\u0440\u044C", cut_desc:"\u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C", copy_desc:"\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C", paste_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C", image_props_desc:"\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u0430 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F", newdocument_desc:"\u041D\u043E\u0432\u044B\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442", help_desc:"\u041F\u043E\u043C\u043E\u0449\u044C", blockquote_desc:"\u0426\u0438\u0442\u0430\u0442\u0430", clipboard_msg:"\u041A\u043E\u043C\u0430\u043D\u0434\u044B \u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C/\u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C/\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442 \u0432 Firefox.\n\u0425\u043E\u0442\u0438\u0442\u0435 \u0443\u0437\u043D\u0430\u0442\u044C \u043E\u0431 \u044D\u0442\u043E\u043C \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u0435\u0435?", path:"\u041F\u0443\u0442\u044C", newdocument:"\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B, \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0435?", toolbar_focus:"\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u043A\u043D\u043E\u043F\u043A\u0430\u043C \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432 - Alt+Q, \u043F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0443 - Alt-Z, \u043F\u0435\u0440\u0435\u0439\u0442\u0438 \u043A \u043F\u0443\u0442\u0438 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430 - Alt-X", more_colors:"\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0446\u0432\u0435\u0442", image_delta_width:"65" }); tinyMCE.addI18n('ru.advanced',{ cut_desc:"\u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C", copy_desc:"\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C", paste_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C", link_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443", unlink_desc:"\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443", image_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/sr.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/s0000644000175000017500000000422111226234200033634 0ustar frankiefrankietinyMCE.addI18n('sr.openacs',{ style_select:"Stilovi", font_size:"Veli\u010Dina pisma", fontdefault:"Vrsta pisma", block:"Format", paragraph:"Paragraf", div:"Div", address:"Adresa", pre:"Oblikovano", h1:"Naslov 1", h2:"Naslov 2", h3:"Naslov 3", h4:"Naslov 4", h5:"Naslov 5", h6:"Naslov 6", blockquote:"Citat", code:"Kod", samp:"Primjer koda", dt:"Definicija pojma", dd:"Opis definicije", bold_desc:"Podebljaj (Ctrl+B)", italic_desc:"Kurziv (Ctrl+I)", underline_desc:"Podcrtaj (Ctrl+U)", striketrough_desc:"Precrtaj", justifyleft_desc:"Poravnaj levo", justifycenter_desc:"Centriraj", justifyright_desc:"Poravnaj desno", justifyfull_desc:"Poravnaj potpuno", bullist_desc:"Neure\u0111ena lista", numlist_desc:"Ure\u0111ena lista", outdent_desc:"Uvuci", indent_desc:"Izvuci", undo_desc:"Poni\u0161ti (Ctrl+Z)", redo_desc:"Ponovi (Ctrl+Y)", link_desc:"Umetni/uredi poveznicu", unlink_desc:"Poni\u0161ti poveznicu", image_desc:"Umetni/uredi sliku", cleanup_desc:"Po\u010Disti kod", code_desc:"Uredi HTML izvor", sub_desc:"Indeks", sup_desc:"Eksponent", hr_desc:"Umetni vodoravnu crtu", removeformat_desc:"Poni\u0161ti oblikovanje", custom1_desc:"Vlastiti opis ovdje", forecolor_desc:"Odaberite boju teksta", backcolor_desc:"Odaberite boju pozadine", charmap_desc:"Umetni vlastiti znak", visualaid_desc:"Vodilice/nevidljivi elementi", anchor_desc:"Umetni/uredi sidro", cut_desc:"Izre\u017Ei", copy_desc:"Kopiraj", paste_desc:"Zalepi", image_props_desc:"Svojstva slike", newdocument_desc:"Novi dokument", help_desc:"Pomo\u0107", blockquote_desc:"Citiraj", clipboard_msg:"Kopiraj/Izre\u017Ei/Zalepi nije dostupno u Mozilla i Firefox preglednicima. Vi\u0161e informacija?", path:"Staza", newdocument:"Jeste li sigurni da \u017Eelite izbrisati celi sadr\u017Eaj?", toolbar_focus:"Pre\u0111i na alatnu traku - Alt+Q, pre\u0111i na ure\u0111iva\u010D - Alt-Z, pre\u0111i na element path - Alt-X", more_colors:"Vi\u0161e boja" }); tinyMCE.addI18n('sr.advanced',{ cut_desc:"Izre\u017Ei", copy_desc:"Kopiraj", paste_desc:"Zalepi", link_desc:"Umetni/uredi poveznicu", unlink_desc:"Poni\u0161ti poveznicu", image_desc:"Umetni/uredi sliku" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/th.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/t0000644000175000017500000001225711226234200033645 0ustar frankiefrankietinyMCE.addI18n('th.openacs',{ style_select:"\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A", font_size:"\u0E02\u0E19\u0E32\u0E14\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", fontdefault:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", block:"\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A", paragraph:"\u0E22\u0E48\u0E2D\u0E2B\u0E19\u0E49\u0E32", div:"Div", address:"\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48", pre:"\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A\u0E1E\u0E37\u0E49\u0E19\u0E10\u0E32\u0E19", h1:"Heading 1", h2:"Heading 2", h3:"Heading 3", h4:"Heading 4", h5:"Heading 5", h6:"Heading 6", blockquote:"\u0E2D\u0E49\u0E32\u0E07\u0E2D\u0E34\u0E07", code:"\u0E42\u0E04\u0E4A\u0E14", samp:"\u0E42\u0E04\u0E4A\u0E14\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07", dt:"\u0E04\u0E33\u0E19\u0E34\u0E22\u0E32\u0E21", dd:"\u0E23\u0E32\u0E22\u0E25\u0E30\u0E40\u0E2D\u0E35\u0E22\u0E14\u0E04\u0E33\u0E19\u0E34\u0E22\u0E32\u0E21", bold_desc:"\u0E15\u0E31\u0E27\u0E2B\u0E19\u0E32 (Ctrl+B)", italic_desc:"\u0E15\u0E31\u0E27\u0E40\u0E2D\u0E35\u0E22\u0E07 (Ctrl+I)", underline_desc:"\u0E15\u0E31\u0E27\u0E02\u0E35\u0E14\u0E40\u0E2A\u0E49\u0E19\u0E43\u0E15\u0E49(Ctrl+U)", striketrough_desc:"\u0E02\u0E35\u0E14\u0E06\u0E48\u0E32", justifyleft_desc:"\u0E08\u0E31\u0E14\u0E0B\u0E49\u0E32\u0E22", justifycenter_desc:"\u0E08\u0E31\u0E14\u0E01\u0E25\u0E32\u0E07", justifyright_desc:"\u0E08\u0E31\u0E14\u0E02\u0E27\u0E32", justifyfull_desc:"\u0E08\u0E31\u0E14\u0E40\u0E15\u0E47\u0E21\u0E2B\u0E19\u0E49\u0E32", bullist_desc:"\u0E25\u0E33\u0E14\u0E31\u0E1A\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23", numlist_desc:"\u0E25\u0E33\u0E14\u0E31\u0E1A\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02", outdent_desc:"\u0E25\u0E14\u0E01\u0E32\u0E23\u0E40\u0E22\u0E37\u0E49\u0E2D\u0E07", indent_desc:"\u0E40\u0E22\u0E37\u0E49\u0E2D\u0E07\u0E02\u0E27\u0E32", undo_desc:"\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01 (Ctrl+Z)", redo_desc:"\u0E22\u0E49\u0E2D\u0E19\u0E01\u0E25\u0E31\u0E1A (Ctrl+Y)", link_desc:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", unlink_desc:"\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", image_desc:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E23\u0E39\u0E1B", cleanup_desc:"\u0E25\u0E49\u0E32\u0E07\u0E42\u0E04\u0E4A\u0E14", code_desc:"\u0E41\u0E01\u0E49\u0E44\u0E02 HTML", sub_desc:"\u0E15\u0E31\u0E27\u0E2B\u0E49\u0E2D\u0E22", sup_desc:"\u0E15\u0E31\u0E27\u0E22\u0E01", hr_desc:"\u0E43\u0E2A\u0E48\u0E40\u0E2A\u0E49\u0E19\u0E1A\u0E31\u0E19\u0E17\u0E31\u0E14", removeformat_desc:"\u0E25\u0E49\u0E32\u0E07\u0E23\u0E39\u0E1B\u0E41\u0E1A\u0E1A", custom1_desc:"\u0E43\u0E2A\u0E48\u0E23\u0E32\u0E22\u0E25\u0E30\u0E40\u0E2D\u0E35\u0E22\u0E14\u0E40\u0E2D\u0E07\u0E44\u0E14\u0E49\u0E17\u0E35\u0E48\u0E19\u0E35\u0E48", forecolor_desc:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2A\u0E35\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21", backcolor_desc:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2A\u0E35\u0E1E\u0E37\u0E49\u0E19\u0E2B\u0E25\u0E31\u0E07", charmap_desc:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23", visualaid_desc:"\u0E2A\u0E25\u0E31\u0E1A guidelines/\u0E0B\u0E48\u0E2D\u0E19 elements", anchor_desc:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", cut_desc:"\u0E15\u0E31\u0E14", copy_desc:"\u0E04\u0E31\u0E14\u0E25\u0E2D\u0E01", paste_desc:"\u0E27\u0E32\u0E07", image_props_desc:"\u0E04\u0E38\u0E13\u0E2A\u0E21\u0E1A\u0E31\u0E15\u0E34\u0E23\u0E39\u0E1B", newdocument_desc:"\u0E40\u0E2D\u0E01\u0E2A\u0E32\u0E23\u0E43\u0E2B\u0E21\u0E48", help_desc:"\u0E0A\u0E48\u0E27\u0E22\u0E40\u0E2B\u0E25\u0E37\u0E2D", blockquote_desc:"\u0E2D\u0E49\u0E32\u0E07\u0E16\u0E36\u0E07", clipboard_msg:"\u0E04\u0E31\u0E14\u0E25\u0E2D\u0E01 / \u0E15\u0E31\u0E14 / \u0E27\u0E32\u0E07\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E43\u0E2B\u0E49\u0E1A\u0E23\u0E34\u0E01\u0E32\u0E23\u0E43\u0E19 Mozilla \u0E41\u0E25\u0E30 Firefox.\nDo \u0E04\u0E38\u0E13\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E40\u0E15\u0E34\u0E21\u0E40\u0E01\u0E35\u0E48\u0E22\u0E27\u0E01\u0E31\u0E1A\u0E1B\u0E31\u0E0D\u0E2B\u0E32\u0E19\u0E35\u0E49\u0E2B\u0E23\u0E37\u0E2D\u0E44\u0E21\u0E48?", path:"\u0E1E\u0E32\u0E17", newdocument:"\u0E04\u0E38\u0E13\u0E41\u0E19\u0E48\u0E43\u0E08\u0E2B\u0E23\u0E37\u0E2D\u0E44\u0E21\u0E48\u0E27\u0E48\u0E32\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E25\u0E49\u0E32\u0E07\u0E40\u0E19\u0E37\u0E49\u0E2D\u0E2B\u0E32\u0E17\u0E31\u0E49\u0E07\u0E2B\u0E21\u0E14?", toolbar_focus:"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X", more_colors:"\u0E2A\u0E35\u0E2D\u0E37\u0E48\u0E19\u0E46" }); tinyMCE.addI18n('th.advanced',{ cut_desc:"\u0E15\u0E31\u0E14", copy_desc:"\u0E04\u0E31\u0E14\u0E25\u0E2D\u0E01", paste_desc:"\u0E27\u0E32\u0E07", link_desc:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", unlink_desc:"\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", image_desc:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E23\u0E39\u0E1B" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/sv.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/s0000644000175000017500000000426511226234200033644 0ustar frankiefrankietinyMCE.addI18n('sv.openacs',{ style_select:"Stilar", font_size:"Fontstorlek", fontdefault:"Fontfamilj", block:"Format", paragraph:"Stycke", div:"Div", address:"Adress", pre:"F\u00F6rformaterad", h1:"Rubrik 1", h2:"Rubrik 2", h3:"Rubrik 3", h4:"Rubrik 4", h5:"Rubrik 5", h6:"Rubrik 6", blockquote:"Blockcitat", code:"Kodblock", samp:"Kodexempel", dt:"Definitionsterm", dd:"Definitionsbeskrivning", bold_desc:"Fet (Ctrl+B)", italic_desc:"Kursiv (Ctrl+I)", underline_desc:"Understruken (Ctrl+U)", striketrough_desc:"Genomstruken", justifyleft_desc:"V\u00E4nsterst\u00E4lld", justifycenter_desc:"Centrera", justifyright_desc:"H\u00F6gerst\u00E4lld", justifyfull_desc:"Justera", bullist_desc:"Punktlista", numlist_desc:"Nummerlista", outdent_desc:"Drag tillbaka", indent_desc:"Indrag", undo_desc:"\u00C5ngra (Ctrl+Z)", redo_desc:"G\u00F6r om (Ctrl+Y)", link_desc:"Infoga/redigera l\u00E4nk", unlink_desc:"Ta bort l\u00E4nk", image_desc:"Infoga/redigera bild", cleanup_desc:"St\u00E4da upp i k\u00E4llkoden", code_desc:"Redigera HTML k\u00E4llkoden", sub_desc:"Subscript", sup_desc:"Superscript", hr_desc:"Infoga horisontell skiljelinje", removeformat_desc:"Ta bort formatering", forecolor_desc:"V\u00E4lj textf\u00E4rg", backcolor_desc:"V\u00E4lj bakgrundsf\u00E4rg", charmap_desc:"Infoga specialtecken", visualaid_desc:"Visa/d\u00F6lj visuella hj\u00E4lpmedel", anchor_desc:"Infoga/redigera bokm\u00E4rke", cut_desc:"Klipp ut", copy_desc:"Kopiera", paste_desc:"Klistra in", image_props_desc:"Bildinst\u00E4llningar", newdocument_desc:"Nytt dokument", help_desc:"Hj\u00E4lp", blockquote_desc:"Blockcitat", clipboard_msg:"Kopiera/klipp ut/klistra in \u00E4r inte tillg\u00E4ngligt i din webbl\u00E4sare.\nVill du veta mer om detta?", path:"Element", newdocument:"\u00C4r du s\u00E4ker p\u00E5 att du vill radera allt inneh\u00E5ll?", toolbar_focus:"Hoppa till verktygsf\u00E4ltet - Alt+Q, Hoppa till redigeraren - Alt-Z, Hoppa till elementlistan - Alt-X" }); tinyMCE.addI18n('sv.advanced',{ cut_desc:"Klipp ut", copy_desc:"Kopiera", paste_desc:"Klistra in", link_desc:"Infoga/redigera l\u00E4nk", unlink_desc:"Ta bort l\u00E4nk", image_desc:"Infoga/redigera bild" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/tr.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/t0000644000175000017500000000512411226234200033640 0ustar frankiefrankietinyMCE.addI18n('tr.openacs',{ style_select:"Stiller", font_size:"Yaz\u0131 boyutu", fontdefault:"Yaz\u0131 tipi", block:"Bi\u00E7im", paragraph:"Paragraf", div:"B\u00F6l\u00FCm", address:"Adres", pre:"\u00D6nformatl\u0131", h1:"Ba\u015Fl\u0131k 1", h2:"Ba\u015Fl\u0131k 2", h3:"Ba\u015Fl\u0131k 3", h4:"Ba\u015Fl\u0131k 4", h5:"Ba\u015Fl\u0131k 5", h6:"Ba\u015Fl\u0131k 6", blockquote:"Al\u0131nt\u0131", code:"Kod", samp:"Kod \u00F6rne\u011Fi", dt:"Tan\u0131m terimi ", dd:"Tan\u0131m a\u00E7\u0131klamas\u0131", bold_desc:"Kal\u0131n (Ctrl+B)", italic_desc:"E\u011Fik (Ctrl+I)", underline_desc:"Alt\u0131 \u00E7izgili (Ctrl+U)", striketrough_desc:"Ortas\u0131 \u00E7izgili", justifyleft_desc:"Sola yasla", justifycenter_desc:"Ortala", justifyright_desc:"Sa\u011Fa yasla", justifyfull_desc:"\u0130ki yana yasla", bullist_desc:"S\u0131ras\u0131z liste", numlist_desc:"S\u0131ral\u0131 liste", outdent_desc:"D\u0131\u015Fa kayd\u0131r", indent_desc:"\u0130\u00E7e kayd\u0131r", undo_desc:"Geri al (Ctrl+Z)", redo_desc:"Tekrarla (Ctrl+Y)", link_desc:"Ba\u011Flant\u0131 ekle/d\u00FCzenle", unlink_desc:"Ba\u011Flant\u0131y\u0131 sil", image_desc:"Resim ekle/d\u00FCzenle", cleanup_desc:"Da\u011F\u0131n\u0131k kodu temizle", code_desc:"HTML Kayna\u011F\u0131n\u0131 D\u00FCzenle", sub_desc:"Altsimge", sup_desc:"\u00DCstsimge", hr_desc:"Yatay \u00E7izgi ekle", removeformat_desc:"Bi\u00E7imi kald\u0131r", custom1_desc:"\u00D6zel a\u00E7\u0131klaman\u0131z\u0131 buraya girin", forecolor_desc:"Metin rengi se\u00E7", backcolor_desc:"Arkaplan rengi se\u00E7", charmap_desc:"\u00D6zel karakter ekle", visualaid_desc:"Y\u00F6nergeleri ve g\u00F6r\u00FCnmez elemanlar\u0131 a\u00E7/kapa", anchor_desc:"\u00C7engel noktas\u0131 ekle", cut_desc:"Kes", copy_desc:"Kopyala", paste_desc:"Yap\u0131\u015Ft\u0131r", image_props_desc:"Resim \u00F6zellikleri", newdocument_desc:"Yeni belge", help_desc:"Yard\u0131m", blockquote_desc:"Al\u0131nt\u0131", clipboard_msg:"Kopyala/Kes/Yap\u0131\u015Ft\u0131r Mozilla ve Firefox'ta kullan\u0131lamaz.\r\nBu konuda daha fazla bilgi edinmek ister misiniz?", path:"Yol", newdocument:"T\u00FCm i\u00E7eri\u011Fi bo\u015Faltmak istedinizden emin misiniz?", toolbar_focus:"Ara\u00E7 d\u00FC\u011Fmelerine atla - Alt+Q, Edit\u00F6re atla - Alt-Z, Eleman yoluna atla - Alt-X", more_colors:"Daha fazla renk" }); tinyMCE.addI18n('tr.advanced',{ cut_desc:"Kes", copy_desc:"Kopyala", paste_desc:"Yap\u0131\u015Ft\u0131r", link_desc:"Ba\u011Flant\u0131 ekle/d\u00FCzenle", unlink_desc:"Ba\u011Flant\u0131y\u0131 sil", image_desc:"Resim ekle/d\u00FCzenle" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/uk.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/u0000644000175000017500000001507211226234200033644 0ustar frankiefrankietinyMCE.addI18n('uk.openacs',{ style_select:"\u0421\u0442\u0438\u043B\u0456", font_size:"\u0420\u043E\u0437\u043C\u0456\u0440 \u0448\u0440\u0438\u0444\u0442\u0443", fontdefault:"\u0428\u0440\u0438\u0444\u0442", block:"\u0424\u043E\u0440\u043C\u0430\u0442", paragraph:"\u0410\u0431\u0437\u0430\u0446", div:"Div", address:"\u0421\u0442\u0438\u043B\u044C \u0430\u0434\u0440\u0435\u0441\u0438", pre:"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0444\u043E\u0440\u043C\u0430\u0442\u043E\u0432\u0430\u043D\u0438\u0439", h1:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 1", h2:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 2", h3:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 3", h4:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 4", h5:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 5", h6:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A 6", blockquote:"\u0426\u0438\u0442\u0430\u0442\u0430", code:"\u041A\u043E\u0434", samp:"\u041F\u0440\u0438\u043A\u043B\u0430\u0434 \u043A\u043E\u0434\u0443", dt:"\u0414\u043E\u0432\u0456\u0434\u043D\u0438\u043A \u0442\u0435\u0440\u043C\u0456\u043D ", dd:"\u0414\u043E\u0432\u0456\u0434\u043D\u0438\u043A \u043E\u043F\u0438\u0441 ", bold_desc:"\u0416\u0438\u0440\u043D\u0438\u0439 (Ctrl+B)", italic_desc:"\u041A\u0443\u0440\u0441\u0438\u0432 (Ctrl+I)", underline_desc:"\u041F\u0456\u0434\u043A\u0440\u0435\u0441\u043B\u0435\u043D\u0438\u0439 (Ctrl+U)", striketrough_desc:"\u0417\u0430\u043A\u0440\u0435\u0441\u043B\u0435\u043D\u0438\u0439", justifyleft_desc:"\u041F\u043E \u043B\u0456\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", justifycenter_desc:"\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443", justifyright_desc:"\u041F\u043E \u043F\u0440\u0430\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", justifyfull_desc:"\u041F\u043E \u0448\u0438\u0440\u0438\u043D\u0456", bullist_desc:"\u0421\u043F\u0438\u0441\u043E\u043A", numlist_desc:"\u041D\u0443\u043C\u0435\u0440\u043E\u0432\u0430\u043D\u0438\u0439 \u0441\u043F\u0438\u0441\u043E\u043A", outdent_desc:"\u0417\u043C\u0435\u043D\u0448\u0442\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043F", indent_desc:"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0432\u0456\u0434\u0441\u0442\u0443\u043F", undo_desc:"\u0412\u0456\u0434\u043C\u0456\u043D\u0438\u0442\u0438 (Ctrl+Z)", redo_desc:"\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u0438 (Ctrl+Y)", link_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F", unlink_desc:"\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F", image_desc:"\u0414\u043E\u0434\u0430\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u043D\u044F", cleanup_desc:"\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0437\u0430\u0439\u0432\u044B\u0439 \u043A\u043E\u0434", code_desc:"\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 HTML \u043A\u043E\u0434", sub_desc:"\u041D\u0438\u0436\u043D\u0456\u0439 \u0456\u043D\u0434\u0435\u043A\u0441", sup_desc:"\u0412\u0435\u0440\u0445\u043D\u0456\u0439 \u0456\u043D\u0434\u0435\u043A\u0441", hr_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0433\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u044C\u043D\u0438\u0439 \u0440\u043E\u0437\u0434\u0456\u043B\u044C\u043D\u0438\u043A", removeformat_desc:"\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0444\u043E\u0440\u043C\u0430\u0442\u0443\u0432\u0430\u043D\u043D\u044F", custom1_desc:"\u0412\u0430\u0448 \u0434\u043E\u0432\u0456\u043B\u044C\u043D\u0438\u0439 \u043E\u043F\u0438\u0441 \u0442\u0443\u0442", forecolor_desc:"\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u043A\u043E\u043B\u0456\u0440 \u0442\u0435\u043A\u0441\u0442\u0443", backcolor_desc:"\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u043A\u043E\u043B\u0456\u0440 \u0444\u043E\u043D\u0443", charmap_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u0441\u0438\u043C\u0432\u043E\u043B", visualaid_desc:"Toggle guidelines/invisible elements", anchor_desc:"\u0414\u043E\u0434\u0430\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u044F\u043A\u0456\u0440", cut_desc:"\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438", copy_desc:"\u041A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438", paste_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438", image_props_desc:"\u0412\u043B\u0430\u0441\u0442\u0438\u0432\u043E\u0441\u0442\u0456 \u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u043D\u044F", newdocument_desc:"\u041D\u043E\u0432\u0438\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442", help_desc:"\u0414\u043E\u043F\u043E\u043C\u043E\u0433\u0430", blockquote_desc:"\u0426\u0438\u0442\u0430\u0442\u0430", clipboard_msg:"\u041A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438/\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438/\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 \u043D\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0456 \u0432 Mozilla \u0438 Firefox.\n\u0412\u0430\u043C \u0446\u0456\u043A\u0430\u0432\u0430 \u0456\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0456\u044F \u043F\u0440\u043E \u0446\u0435?", path:"\u0428\u043B\u044F\u0445", newdocument:"\u0412\u0438 \u043F\u0435\u0432\u043D\u0456, \u0449\u043E \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0432\u0441\u0435 \u0432\u0438\u0434\u0430\u043B\u0438\u0442\u0438?", toolbar_focus:"\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043D\u0430 \u043F\u0430\u043D\u0435\u043B\u044C \u043A\u043D\u043E\u043F\u043E\u043A - Alt+Q, \u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043E \u0440\u0435\u0434\u0430\u043A\u0442\u043E\u0440\u0443 - Alt-Z, \u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043D\u0430 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0448\u043B\u044F\u0445\u0443 - Alt-X", more_colors:"\u0411\u0456\u043B\u044C\u0448\u0435 \u043A\u043E\u043B\u044C\u043E\u0440\u0456\u0432" }); tinyMCE.addI18n('uk.advanced',{ cut_desc:"\u0412\u0438\u0440\u0456\u0437\u0430\u0442\u0438", copy_desc:"\u041A\u043E\u043F\u0456\u044E\u0432\u0430\u0442\u0438", paste_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438", link_desc:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F", unlink_desc:"\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F", image_desc:"\u0414\u043E\u0434\u0430\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u043D\u044F" });././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/zh.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/z0000644000175000017500000000533611226234200033653 0ustar frankiefrankietinyMCE.addI18n('zh.openacs',{ style_select:"\u6837\u5F0F", font_size:"\u6587\u5B57\u5927\u5C0F", fontdefault:"\u5B57\u4F53", block:"\u683C\u5F0F", paragraph:"\u6BB5\u843D", div:"DIV\u5C42", address:"\u5730\u5740", pre:"\u9884\u6392\u683C\u5F0F", h1:"\u6807\u98981", h2:"\u6807\u98982", h3:"\u6807\u98983", h4:"\u6807\u98984", h5:"\u6807\u98985", h6:"\u6807\u98986", blockquote:"\u5F15\u7528", code:"\u4EE3\u7801", samp:"\u4EE3\u7801\u6837\u5F0F", dt:"\u540D\u8BCD\u5B9A\u4E49", dd:"\u540D\u8BCD\u89E3\u91CA", bold_desc:"\u7C97\u4F53(Ctrl+B)", italic_desc:"\u659C\u4F53(Ctrl+I)", underline_desc:"\u4E0B\u5212\u7EBF(Ctrl+U)", striketrough_desc:"\u5220\u9664\u7EBF", justifyleft_desc:"\u5DE6\u5BF9\u9F50", justifycenter_desc:"\u5C45\u4E2D", justifyright_desc:"\u53F3\u5BF9\u9F50", justifyfull_desc:"\u4E24\u7AEF\u5BF9\u9F50", bullist_desc:"\u9879\u76EE\u7B26\u53F7", numlist_desc:"\u7F16\u53F7", outdent_desc:"\u51CF\u5C11\u7F29\u8FDB", indent_desc:"\u589E\u52A0\u7F29\u8FDB", undo_desc:"\u64A4\u9500(Ctrl+Z)", redo_desc:"\u91CD\u505A(Ctrl+Y)", link_desc:"\u63D2\u5165/\u7F16\u8F91\u8D85\u94FE\u63A5", unlink_desc:"\u53D6\u6D88\u8D85\u94FE\u63A5", image_desc:"\u63D2\u5165/\u7F16\u8F91\u56FE\u50CF", cleanup_desc:"\u6E05\u7406\u4EE3\u7801", code_desc:"\u7F16\u8F91\u6E90\u4EE3\u7801", sub_desc:"\u4E0B\u6807", sup_desc:"\u4E0A\u6807", hr_desc:"\u63D2\u5165\u6C34\u5E73\u7EBF", removeformat_desc:"\u6E05\u9664\u6837\u5F0F", custom1_desc:"\u81EA\u5B9A\u4E49\u63CF\u8FF0", forecolor_desc:"\u524D\u666F\u8272", backcolor_desc:"\u80CC\u666F\u8272", charmap_desc:"\u63D2\u5165\u7279\u6B8A\u5B57\u7B26", visualaid_desc:"\u663E\u793A/\u9690\u85CF\u4E0D\u53EF\u89C1\u5143\u7D20", anchor_desc:"\u63D2\u5165/\u7F16\u8F91\u951A\u70B9", cut_desc:"\u526A\u5207", copy_desc:"\u590D\u5236", paste_desc:"\u7C98\u8D34", image_props_desc:"\u56FE\u50CF\u5C5E\u6027", newdocument_desc:"\u65B0\u6587\u4EF6", help_desc:"\u8BF4\u660E", blockquote_desc:"\u5F15\u7528", clipboard_msg:"\u590D\u5236\u3001\u526A\u5207\u53CA\u7C98\u8D34\u529F\u80FD\u5728Mozilla\u548CFirefox\u4E2D\u65E0\u6CD5\u4F7F\u7528\u3002 \n\u662F\u5426\u9700\u8981\u4E86\u89E3\u66F4\u591A\u6709\u5173\u6B64\u95EE\u9898\u7684\u4FE1\u606F\uFF1F", path:"\u4F4D\u7F6E", newdocument:"\u60A8\u786E\u8BA4\u8981\u6E05\u9664\u6240\u6709\u5185\u5BB9\u5417\uFF1F", toolbar_focus:"\u5DE5\u5177\u6309\u94AE- Alt+Q,\u7F16\u8F91\u5668- Alt-Z,\u7EC4\u4EF6\u4F4D\u7F6E- Alt-X", more_colors:"\u66F4\u591A\u989C\u8272" }); tinyMCE.addI18n('zh.advanced',{ cut_desc:"\u526A\u5207", copy_desc:"\u590D\u5236", paste_desc:"\u7C98\u8D34", link_desc:"\u63D2\u5165/\u7F16\u8F91\u8D85\u94FE\u63A5", unlink_desc:"\u53D6\u6D88\u8D85\u94FE\u63A5", image_desc:"\u63D2\u5165/\u7F16\u8F91\u56FE\u50CF" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ms_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/m0000644000175000017500000000327311226234177033651 0ustar frankiefrankietinyMCE.addI18n('ms.openacs_dlg',{ about_title:"Perihal TinyMCE", about_general:"Perihal", about_help:"Bantuan", about_license:"Lesen", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"Pengarang", about_version:"Versi", about_loaded:"Muatan plugins", anchor_title:"Sisip/sunting sauh", anchor_name:"Nama sauh", code_title:"Penyunting HTML", code_wordwrap:"Sisip perkataan", colorpicker_title:"Pilih warna", colorpicker_picker_tab:"Pemungut", colorpicker_picker_title:"Pemungut warna", colorpicker_palette_tab:"Palet", colorpicker_palette_title:"Palet warna", colorpicker_named_tab:"Dinamakan", colorpicker_named_title:"Warna telah dinamakan", colorpicker_color:"Warna:", colorpicker_name:"Nama:", charmap_title:"Pilih aksara sendiri", image_title:"Sisip/sunting imej", image_src:"Imej URL", image_alt:"Huraian imej", image_list:"Senarai imej", image_border:"Sempadan", image_dimensions:"Dimensi", image_vspace:"Ruangan tegak", image_hspace:"Ruangan ufuk", image_align:"Penyelarian", image_align_baseline:"Garis pangkal", image_align_top:"Atas", image_align_middle:"Tengah", image_align_bottom:"Bawah", image_align_texttop:"Teks atas", image_align_textbottom:"Teks bawah", image_align_left:"Kiri", image_align_right:"Kanan", link_title:"Sisip/sunting pautan", link_url:"Pautan URL", link_target:"Sasaran", link_target_same:"Buka pautan dalam tetingkap yang sama", link_target_blank:"Buka pautan dalam tetingkap yang sama", link_titlefield:"Tajuk", link_is_email:"URL yang anda masukkan adalah alamat emel, tambah \"mailto\": di awalan?", link_is_external:"URL yang anda masukkan adalah pautan luar, tambah \"http://\" di awalan?", link_list:"Senarai pautan" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/lt_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/l0000644000175000017500000000426111226234177033646 0ustar frankiefrankietinyMCE.addI18n('lt.openacs_dlg',{ about_title:"Apie TinyMCE", about_general:"Apie", about_help:"Pagalba", about_license:"Licenzija", about_plugins:"\u012Eskiepiai", about_plugin:"\u012Eskiepis", about_author:"Autorius", about_version:"Versija", about_loaded:"U\u017Ekrauti \u012Fskiepiai", anchor_title:"\u012Eterpti/redaguoti inkar\u0105", anchor_name:"Inkaro vardas", code_title:"HTML i\u0161eities kodo redaktorius", code_wordwrap:"\u017Dod\u017Eio lau\u017Eymas", colorpicker_title:"Pasirinkti spalv\u0105", colorpicker_picker_tab:"Parink\u0117jas", colorpicker_picker_title:"Spalvos parink\u0117jas", colorpicker_palette_tab:"Palet\u0117", colorpicker_palette_title:"Paletin\u0117s spalvos", colorpicker_named_tab:"\u012Evardintosios", colorpicker_named_title:"\u012Evardintosios spalvos", colorpicker_color:"Spalva:", colorpicker_name:"Pavadinimas:", charmap_title:"Pasirinkti nestandartin\u012F simbol\u012F", image_title:"\u012Eterpti/redaguoti paveiksl\u0117l\u012F", image_src:"Paveiksl\u0117lio URL adresas", image_alt:"Paveiksl\u0117lio apra\u0161ymas", image_list:"Paveiksl\u0117li\u0173 s\u0105ra\u0161as", image_border:"R\u0117melis", image_dimensions:"I\u0161matavimai", image_vspace:"Vertikalus tarpas", image_hspace:"Horizontalus tarpas", image_align:"Lygiavimas", image_align_baseline:"Pradiniame ta\u0161ke", image_align_top:"Vir\u0161uje", image_align_middle:"Viduryje", image_align_bottom:"Apa\u010Dioje", image_align_texttop:"Teksto vir\u0161uje", image_align_textbottom:"Teksto apa\u010Dioje", image_align_left:"Kair\u0117je", image_align_right:"De\u0161in\u0117je", link_title:"\u012Eterpti/redaguoti nuorod\u0105", link_url:"Nuorodos URL adresas", link_target:"Taikinys", link_target_same:"Atidaryti tame pa\u010Diame lange", link_target_blank:"Atidaryti naujame lange", link_titlefield:"Pavadinimas", link_is_email:"URL adresas, kur\u012F \u012Fved\u0117te yra e-pa\u0161to adresas, ar norite prid\u0117ti reikaling\u0105 mailto: prefiks\u0105?", link_is_external:"URL adresas, kur\u012F \u012Fved\u0117te yra i\u0161orin\u0117 nuoroda, ar norite prid\u0117ti reikaling\u0105 http:// prefiks\u0105?", link_list:"Nuorod\u0173 s\u0105ra\u0161as" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/da_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/d0000644000175000017500000000360611226234177033640 0ustar frankiefrankietinyMCE.addI18n('da.openacs_dlg',{ about_title:"Om TinyMCE", about_general:"Om", about_help:"Hj\u00E6lp", about_license:"Licens", about_plugins:"Udvidelser", about_plugin:"Udvidelse", about_author:"Forfatter", about_version:"Version", about_loaded:"Indl\u00E6ste udvidelser", anchor_title:"Inds\u00E6t/rediger anker", anchor_name:"Navn p\u00E5 anker", code_title:"HTML kildekode-redigering", code_wordwrap:"Tekstombrydning", colorpicker_title:"V\u00E6lg en farve", colorpicker_picker_tab:"V\u00E6lger", colorpicker_picker_title:"Farvev\u00E6lger", colorpicker_palette_tab:"Palette", colorpicker_palette_title:"Palette-farver", colorpicker_named_tab:"Navngivet", colorpicker_named_title:"Navngivet farve", colorpicker_color:"Farve:", colorpicker_name:"Navn:", charmap_title:"V\u00E6lg specialtegn", image_title:"Inds\u00E6t/rediger billede", image_src:"Billede URL", image_alt:"Billedbeskrivelse", image_list:"Liste over billeder", image_border:"Kant", image_dimensions:"Dimensioner", image_vspace:"Vertikal afstand", image_hspace:"Horisontal afstand", image_align:"Justering", image_align_baseline:"Grundlinie", image_align_top:"Toppen", image_align_middle:"Centreret", image_align_bottom:"Bunden", image_align_texttop:"Tekst toppen", image_align_textbottom:"Tekst bunden", image_align_left:"Venstre", image_align_right:"H\u00F8jre", link_title:"Inds\u00E6t/rediger link", link_url:"Link URL", link_target:"Target", link_target_same:"\u00C5ben link i samme vindue", link_target_blank:"\u00C5ben link i nyt vindue", link_titlefield:"Titel", link_is_email:"Den URL, der er indtastet, ser ud til at v\u00E6re en emailadresse. Vil du have tilf\u00F8jet det p\u00E5kr\u00E6vede mailto: foran?", link_is_external:"Den URL, der er indtastet, ser ud til at v\u00E6re et eksternt link. Vil du have tilf\u00F8jet det p\u00E5kr\u00E6vede http:// foran?", link_list:"Liste over links" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/et_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000000342711226234177033642 0ustar frankiefrankietinyMCE.addI18n('et.openacs_dlg',{ about_title:"Teave TinyMCE kohta", about_general:"Teave", about_help:"Abi", about_license:"Litsents", about_plugins:"Lisad", about_plugin:"Lisa", about_author:"Autor", about_version:"Versioon", about_loaded:"Laetud lisad", anchor_title:"Sisesta/redigeeri ankur", anchor_name:"Ankru nimi", code_title:"HTML koodi redaktor", code_wordwrap:"S\u00F5na pakkimine", colorpicker_title:"Vali v\u00E4rv", colorpicker_picker_tab:"Korjaja", colorpicker_picker_title:"V\u00E4rvi korjaja", colorpicker_palette_tab:"Palett", colorpicker_palette_title:"Palett v\u00E4rvid", colorpicker_named_tab:"Nimetatud", colorpicker_named_title:"Nimetatud v\u00E4rvid", colorpicker_color:"V\u00E4rv:", colorpicker_name:"Nimi:", charmap_title:"Vali kohandatud t\u00E4hem\u00E4rk", image_title:"Sisestal/redigeeri pilt", image_src:"Pildi URL", image_alt:"Pildi kirjeldus", image_list:"Pildi loend", image_border:"Raam", image_dimensions:"Dimensioonid", image_vspace:"Vertikaalne vahe", image_hspace:"Horisontaalne vahe", image_align:"Reastus", image_align_baseline:"Kirjajoondus", image_align_top:"\u00DClemine", image_align_middle:"Keskmine", image_align_bottom:"Alumine", image_align_texttop:"Teksti tipp", image_align_textbottom:"Teksti p\u00F5hi", image_align_left:"Vasak", image_align_right:"Parem", link_title:"Sisesta/redigeeri link", link_url:"Link URL", link_target:"Sihtala", link_target_same:"Ava link samas aknas", link_target_blank:"Ava link uues aknas", link_titlefield:"Tiitel", link_is_email:"URL, mille te sisestasite, tundub olevat emaili aadress, kas soovite, et lisataks mailto: eesliite?", link_is_external:"URL, mille sisestasite, tundub olevat v\u00E4line link, kas soovite, et lisataks http:// eesliite?", link_list:"Lingi loetelu" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/no_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/n0000644000175000017500000000346611226234177033656 0ustar frankiefrankietinyMCE.addI18n('no.openacs_dlg',{ about_title:"Om TinyMCE", about_general:"Om", about_help:"Hjelp", about_license:"Lisens", about_plugins:"Programtillegg", about_plugin:"Programtillegg", about_author:"Utvikler", about_version:"Versjon", about_loaded:"Last programtillegg", anchor_title:"Sett inn / endre anker", anchor_name:"Ankernavn", code_title:"HTML-editor", code_wordwrap:"Tekstbryting", colorpicker_title:"Velg en farge", colorpicker_picker_tab:"Velg farge", colorpicker_picker_title:"Fargevalg", colorpicker_palette_tab:"Palett", colorpicker_palette_title:"Palettfarger", colorpicker_named_tab:"Navnevalg", colorpicker_named_title:"Fargenavn", colorpicker_color:"Farge:", colorpicker_name:"Navn:", charmap_title:"Velg spesialtegn", image_title:"Sett inn / endre bilde", image_src:"Bilde-URL", image_alt:"Bildeomtale", image_list:"Liste med bilde", image_border:"Ramme", image_dimensions:"Dimensjoner", image_vspace:"Vertikal avstand", image_hspace:"Horisontal avstand", image_align:"Justering", image_align_baseline:"Bunnlinje", image_align_top:"Topp", image_align_middle:"Midtstilt", image_align_bottom:"Bunn", image_align_texttop:"Teksttopp", image_align_textbottom:"Tekstbunn", image_align_left:"Venstre", image_align_right:"H\u00F8yre", link_title:"Sett inn / endre lenke", link_url:"Lenke-URL", link_target:"Vindu", link_target_same:"\u00C5pne i dette vinduet", link_target_blank:"\u00C5pne i nytt vindu", link_titlefield:"Tittel", link_is_email:"Nettadressen du skrev inn ser ut til \u00E5 v\u00E6re en e-postadresse. \u00D8nsker du \u00E5 legge til det obligatoriske mailto:-prefikset?", link_is_external:"Nettadressen du skrev inn ser ut til \u00E5 v\u00E6re en ekstern nettadresse. \u00D8nsker du \u00E5 legge til det obligatoriske http://-prefikset?", link_list:"Lenkeliste" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ru_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/r0000644000175000017500000001224211226234200033635 0ustar frankiefrankietinyMCE.addI18n('ru.openacs_dlg',{ about_title:"\u041E TinyMCE", about_general:"\u041E \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0435", about_help:"\u041F\u043E\u043C\u043E\u0449\u044C", about_license:"\u041B\u0438\u0446\u0435\u043D\u0437\u0438\u044F", about_plugins:"\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F", about_plugin:"\u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435", about_author:"\u0410\u0432\u0442\u043E\u0440", about_version:"\u0412\u0435\u0440\u0441\u0438\u044F", about_loaded:"\u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u043D\u044B\u0435 \u0434\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F", anchor_title:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044F\u043A\u043E\u0440\u044C", anchor_name:"\u0418\u043C\u044F \u044F\u043A\u043E\u0440\u044F", code_title:"\u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440 HTML-\u043A\u043E\u0434\u0430", code_wordwrap:"\u041F\u0435\u0440\u0435\u043D\u043E\u0441\u0438\u0442\u044C \u043F\u043E \u0441\u043B\u043E\u0432\u0430\u043C", colorpicker_title:"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0446\u0432\u0435\u0442", colorpicker_picker_tab:"\u0412\u044B\u0431\u043E\u0440", colorpicker_picker_title:"\u0412\u044B\u0431\u043E\u0440 \u0446\u0432\u0435\u0442\u0430", colorpicker_palette_tab:"\u041F\u0430\u043B\u0438\u0442\u0440\u0430", colorpicker_palette_title:"\u0426\u0432\u0435\u0442\u0430 \u043F\u0430\u043B\u0438\u0442\u0440\u044B", colorpicker_named_tab:"\u0421\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0435", colorpicker_named_title:"\u0421\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0435 \u0446\u0432\u0435\u0442\u0430", colorpicker_color:"\u0426\u0432\u0435\u0442", colorpicker_name:"\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435", charmap_title:"\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0439 \u0441\u0438\u043C\u0432\u043E\u043B", image_title:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435", image_src:"\u0410\u0434\u0440\u0435\u0441 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F", image_alt:"\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F", image_list:"\u0421\u043F\u0438\u0441\u043E\u043A \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439", image_border:"\u0413\u0440\u0430\u043D\u0438\u0446\u0430", image_dimensions:"\u0420\u0430\u0437\u043C\u0435\u0440\u044B", image_vspace:"\u041E\u0442\u0441\u0442\u0443\u043F \u043F\u043E \u0432\u0435\u0440\u0442\u0438\u043A\u0430\u043B\u0438", image_hspace:"\u041E\u0442\u0441\u0442\u0443\u043F \u043F\u043E \u0433\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u0438", image_align:"\u0412\u044B\u0440\u0430\u0432\u043D\u0438\u0432\u0430\u043D\u0438\u0435", image_align_baseline:"\u041F\u043E \u0431\u0430\u0437\u043E\u0432\u043E\u0439 \u043B\u0438\u043D\u0438\u0438", image_align_top:"\u041F\u043E \u0432\u0435\u0440\u0445\u0443", image_align_middle:"\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443", image_align_bottom:"\u041F\u043E \u043D\u0438\u0437\u0443", image_align_texttop:"\u041F\u043E \u0432\u0435\u0440\u0445\u0443 \u0442\u0435\u043A\u0441\u0442\u0430", image_align_textbottom:"\u041F\u043E \u043D\u0438\u0437\u0443 \u0442\u0435\u043A\u0441\u0442\u0430", image_align_left:"\u0412\u043B\u0435\u0432\u043E", image_align_right:"\u0412\u043F\u0440\u0430\u0432\u043E", link_title:"\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C/\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443", link_url:"\u0410\u0434\u0440\u0435\u0441 \u0441\u0441\u044B\u043B\u043A\u0438", link_target:"\u0426\u0435\u043B\u044C", link_target_same:"\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u0432 \u0442\u043E\u043C \u0436\u0435 \u043E\u043A\u043D\u0435", link_target_blank:"\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u0432 \u043D\u043E\u0432\u043E\u043C \u043E\u043A\u043D\u0435", link_titlefield:"\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435", link_is_email:"\u0412\u0432\u0435\u0434\u0435\u043D\u043D\u044B\u0439 \u0430\u0434\u0440\u0435\u0441 \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0430\u0434\u0440\u0435\u0441 \u044D\u043B. \u043F\u043E\u0447\u0442\u044B, \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u0440\u0435\u0444\u0438\u043A\u0441 mailto:?", link_is_external:"\u0412\u0432\u0435\u0434\u0435\u043D\u043D\u044B\u0439 \u0430\u0434\u0440\u0435\u0441 \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0432\u043D\u0435\u0448\u043D\u044E\u044E \u0441\u0441\u044B\u043B\u043A\u0443, \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u0440\u0435\u0444\u0438\u043A\u0441 http://?", link_list:"\u0421\u043F\u0438\u0441\u043E\u043A \u0441\u0441\u044B\u043B\u043E\u043A" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/el_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000001253311226234177033640 0ustar frankiefrankietinyMCE.addI18n('el.openacs_dlg',{ about_title:"\u03A3\u03C7\u03B5\u03C4\u03B9\u03BA\u03AC \u03BC\u03B5 \u03C4\u03BF TinyMCE", about_general:"\u03A3\u03C7\u03B5\u03C4\u03B9\u03BA\u03AC", about_help:"\u0392\u03BF\u03AE\u03B8\u03B5\u03B9\u03B1", about_license:"\u0386\u03B4\u03B5\u03B9\u03B1", about_plugins:"\u03A3\u03C7\u03B5\u03C4\u03B9\u03BA\u03AC \u03BC\u03B5 \u03C4\u03B1 \u03C0\u03C1\u03CC\u03C3\u03B8\u03B5\u03C4\u03B1", about_plugin:"\u03A3\u03C7\u03B5\u03C4\u03B9\u03BA\u03AC \u03BC\u03B5 \u03C4\u03BF \u03C0\u03C1\u03CC\u03C3\u03B8\u03B5\u03C4\u03BF", about_author:"\u03A3\u03C5\u03B3\u03B3\u03C1\u03B1\u03C6\u03AD\u03B1\u03C2", about_version:"\u0388\u03BA\u03B4\u03BF\u03C3\u03B7", about_loaded:"\u03A6\u03BF\u03C1\u03C4\u03C9\u03BC\u03AD\u03BD\u03B1 \u03C0\u03C1\u03CC\u03C3\u03B8\u03B5\u03C4\u03B1", anchor_title:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 anchor", anchor_name:"\u038C\u03BD\u03BF\u03BC\u03B1 anchor", code_title:"\u0395\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03C4\u03AE\u03C2 \u03BA\u03CE\u03B4\u03B9\u03BA\u03B1 HTML", code_wordwrap:"\u0391\u03BD\u03B1\u03B4\u03AF\u03C0\u03BB\u03C9\u03C3\u03B7 \u03BA\u03B5\u03B9\u03BC\u03AD\u03BD\u03BF\u03C5", colorpicker_title:"\u0394\u03B9\u03B1\u03BB\u03AD\u03BE\u03C4\u03B5 \u03C7\u03C1\u03CE\u03BC\u03B1", colorpicker_picker_tab:"\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE", colorpicker_picker_title:"\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u03C7\u03C1\u03CE\u03BC\u03B1\u03C4\u03BF\u03C2", colorpicker_palette_tab:"\u03A0\u03B1\u03BB\u03AD\u03C4\u03B1", colorpicker_palette_title:"\u03A7\u03C1\u03CE\u03BC\u03B1\u03C4\u03B1 \u03C0\u03B1\u03BB\u03AD\u03C4\u03B1\u03C2", colorpicker_named_tab:"\u039F\u03BD\u03BF\u03BC\u03B1\u03C3\u03C4\u03B9\u03BA\u03AC", colorpicker_named_title:"\u039F\u03BD\u03BF\u03BC\u03B1\u03C3\u03C4\u03B9\u03BA\u03AC \u03C7\u03C1\u03CE\u03BC\u03B1\u03C4\u03B1", colorpicker_color:"\u03A7\u03C1\u03CE\u03BC\u03B1:", colorpicker_name:"\u038C\u03BD\u03BF\u03BC\u03B1:", charmap_title:"\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE \u03C7\u03B1\u03C1\u03B1\u03BA\u03C4\u03AE\u03C1\u03B1", image_title:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03B5\u03B9\u03BA\u03CC\u03BD\u03B1\u03C2", image_src:"\u0394\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE URL \u0395\u03B9\u03BA\u03CC\u03BD\u03B1\u03C2", image_alt:"\u03A0\u03B5\u03C1\u03B9\u03B3\u03C1\u03B1\u03C6\u03AE \u03B5\u03B9\u03BA\u03CC\u03BD\u03B1\u03C2", image_list:"\u039B\u03AF\u03C3\u03C4\u03B1 \u03B5\u03B9\u03BA\u03CC\u03BD\u03C9\u03BD", image_border:"\u03A0\u03BB\u03B1\u03AF\u03C3\u03B9\u03BF", image_dimensions:"\u0394\u03B9\u03B1\u03C3\u03C4\u03AC\u03C3\u03B5\u03B9\u03C2", image_vspace:"\u0391\u03C0\u03CC\u03C3\u03C4\u03B1\u03C3\u03B7 \u03BA\u03AC\u03B8\u03B5\u03C4\u03B7", image_hspace:"\u0391\u03C0\u03CC\u03C3\u03C4\u03B1\u03C3\u03B7 \u03BF\u03C1\u03B9\u03B6\u03CC\u03BD\u03C4\u03B9\u03B1", image_align:"\u03A3\u03C4\u03BF\u03AF\u03C7\u03B9\u03C3\u03B7", image_align_baseline:"\u0393\u03C1\u03B1\u03BC\u03BC\u03AE \u03C3\u03C4\u03BF\u03AF\u03C7\u03B9\u03C3\u03B7\u03C2 \u03B3\u03C1\u03B1\u03BC\u03BC\u03AC\u03C4\u03C9\u03BD", image_align_top:"\u0395\u03C0\u03AC\u03BD\u03C9", image_align_middle:"\u039C\u03AD\u03C3\u03B7", image_align_bottom:"\u039A\u03AC\u03C4\u03C9", image_align_texttop:"\u039A\u03AD\u03B9\u03BC\u03B5\u03BD\u03BF \u03C0\u03AC\u03BD\u03C9", image_align_textbottom:"\u039A\u03B5\u03AF\u03BC\u03B5\u03BD\u03BF \u03BA\u03AC\u03C4\u03C9", image_align_left:"\u0391\u03C1\u03B9\u03C3\u03C4\u03B5\u03C1\u03AC", image_align_right:"\u0394\u03B5\u03BE\u03B9\u03AC", link_title:"\u0395\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE/\u03B5\u03C0\u03B5\u03BE\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1 \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03BF\u03C5", link_url:"\u0394\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE URL \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03BF\u03C5", link_target:"\u03A3\u03C4\u03CC\u03C7\u03BF\u03C2", link_target_same:"\u0386\u03BD\u03BF\u03B9\u03B3\u03BC\u03B1 \u03C3\u03C4\u03BF \u03AF\u03B4\u03B9\u03BF \u03C0\u03B1\u03C1\u03AC\u03B8\u03C5\u03C1\u03BF", link_target_blank:"\u0386\u03BD\u03BF\u03B9\u03B3\u03BC\u03B1 \u03C3\u03B5 \u03BD\u03AD\u03BF \u03C0\u03B1\u03C1\u03AC\u03B8\u03C5\u03C1\u03BF", link_titlefield:"\u03A4\u03AF\u03C4\u03BB\u03BF\u03C2", link_is_email:"\u0397 \u03B4\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE URL \u03C0\u03BF\u03C5 \u03B5\u03B9\u03C3\u03AC\u03B3\u03B1\u03C4\u03B5 \u03C6\u03B1\u03AF\u03BD\u03B5\u03C4\u03B1\u03B9 \u03BD\u03B1 \u03B5\u03AF\u03BD\u03B1\u03B9 email, \u03BD\u03B1 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF \u03C4\u03BF \u03B1\u03C0\u03B1\u03C1\u03B1\u03AF\u03C4\u03B7\u03C4\u03BF mailto: ;", link_is_external:"\u0397 \u03B4\u03B9\u03B1\u03B4\u03C1\u03BF\u03BC\u03AE URL \u03C0\u03BF\u03C5 \u03B5\u03B9\u03C3\u03AC\u03B3\u03B1\u03C4\u03B5 \u03C6\u03B1\u03AF\u03BD\u03B5\u03C4\u03B1\u03B9 \u03BD\u03B1 \u03B5\u03AF\u03BD\u03B1\u03B9 \u03B5\u03BE\u03C9\u03C4\u03B5\u03C1\u03B9\u03BA\u03CC\u03C2 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03BC\u03BF\u03C2, \u03BD\u03B1 \u03C0\u03C1\u03BF\u03C3\u03C4\u03B5\u03B8\u03B5\u03AF \u03C4\u03BF \u03B1\u03C0\u03B1\u03C1\u03B1\u03AF\u03C4\u03B7\u03C4\u03BF http:// ;", link_list:"\u039B\u03AF\u03C3\u03C4\u03B1 \u03C3\u03C5\u03BD\u03B4\u03AD\u03C3\u03BC\u03C9\u03BD" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/fa_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/f0000644000175000017500000001072211226234177033637 0ustar frankiefrankietinyMCE.addI18n('fa.openacs_dlg',{ about_title:"\u062F\u0631\u0628\u0627\u0631\u0647 TinyMCE", about_general:"\u062F\u0631\u0628\u0627\u0631\u0647", about_help:"\u0631\u0627\u0647\u0646\u0645\u0627\u06CC\u06CC", about_license:"\u0644\u06CC\u0633\u0627\u0646\u0633", about_plugins:"\u0627\u0644\u062D\u0627\u0642\u0627\u062A", about_plugin:"\u0627\u0644\u062D\u0627\u0642\u0647", about_author:"\u0645\u0648\u0654\u0644\u0641", about_version:"\u0646\u0633\u062E\u0647", about_loaded:"\u0627\u0644\u062D\u0627\u0642\u0627\u062A \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0634\u062F\u0647", anchor_title:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0644\u0646\u06AF\u0631 (Anchor)", anchor_name:"\u0646\u0627\u0645 \u0644\u0646\u06AF\u0631 (Anchor)", code_title:"\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0633\u0648\u0631\u0633 HTML", code_wordwrap:"\u0634\u0643\u0633\u062A\u0646 \u062E\u0637\u0648\u0637", colorpicker_title:"\u0627\u0646\u062A\u062E\u0627\u0628 \u06CC\u0643 \u0631\u0646\u06AF", colorpicker_picker_tab:"\u0627\u0646\u062A\u062E\u0627\u0628 \u0643\u0646\u0646\u062F\u0647", colorpicker_picker_title:"\u0627\u0646\u062A\u062E\u0627\u0628 \u0643\u0646\u0646\u062F\u0647 \u0631\u0646\u06AF", colorpicker_palette_tab:"\u0627\u0644\u06AF\u0648", colorpicker_palette_title:"\u0631\u0646\u06AF \u0647\u0627\u06CC \u0627\u0644\u06AF\u0648", colorpicker_named_tab:"\u0646\u0627\u0645 \u062F\u0627\u0631", colorpicker_named_title:"\u0631\u0646\u06AF \u0647\u0627\u06CC \u0646\u0627\u0645 \u062F\u0627\u0631", colorpicker_color:"\u0631\u0646\u06AF:", colorpicker_name:"\u0646\u0627\u0645:", charmap_title:"\u0627\u0646\u062A\u062E\u0627\u0628 \u0643\u0627\u0631\u0627\u0643\u062A\u0631 \u0633\u0641\u0627\u0631\u0634\u06CC", image_title:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u062A\u0635\u0648\u06CC\u0631", image_src:"URL \u062A\u0635\u0648\u06CC\u0631", image_alt:"\u062A\u0648\u0636\u06CC\u062D \u062A\u0635\u0648\u06CC\u0631", image_list:"\u0644\u06CC\u0633\u062A \u062A\u0635\u0648\u06CC\u0631", image_border:"\u062D\u0627\u0634\u06CC\u0647", image_dimensions:"\u0627\u0628\u0639\u0627\u062F", image_vspace:"\u0641\u0627\u0635\u0644\u0647 \u0639\u0645\u0648\u062F\u06CC", image_hspace:"\u0641\u0627\u0635\u0644\u0647 \u0627\u0641\u0642\u06CC", image_align:"\u062A\u0631\u0627\u0632", image_align_baseline:"\u062E\u0637 \u067E\u0627\u06CC\u0647", image_align_top:"\u0628\u0627\u0644\u0627", image_align_middle:"\u0648\u0633\u0637", image_align_bottom:"\u067E\u0627\u06CC\u06CC\u0646", image_align_texttop:"\u0628\u0627\u0644\u0627 \u0645\u062A\u0646", image_align_textbottom:"\u067E\u0627\u06CC\u06CC\u0646 \u0645\u062A\u0646", image_align_left:"\u0686\u067E", image_align_right:"\u0631\u0627\u0633\u062A", link_title:"\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0644\u06CC\u0646\u0643", link_url:"URL \u0644\u06CC\u0646\u0643", link_target:"\u0645\u0642\u0635\u062F (Target)", link_target_same:"\u0628\u0627\u0632\u0634\u062F\u0646 \u0644\u06CC\u0646\u0643 \u062F\u0631 \u0647\u0645\u0627\u0646 \u067E\u0646\u062C\u0631\u0647", link_target_blank:"\u0628\u0627\u0632 \u0634\u062F\u0646 \u0644\u06CC\u0646\u0643 \u062F\u0631 \u06CC\u0643 \u067E\u0646\u062C\u0631\u0647 \u062C\u062F\u06CC\u062F", link_titlefield:"\u0639\u0646\u0648\u0627\u0646", link_is_email:"URL \u06CC \u0643\u0647 \u0634\u0645\u0627 \u0648\u0627\u0631\u062F \u0646\u0645\u0648\u062F\u0647 \u0627\u06CC\u062F \u0628\u0647 \u0646\u0638\u0631 \u0645\u06CC \u0622\u06CC\u062F \u0643\u0647 \u06CC\u0643 \u0622\u062F\u0631\u0633 \u0627\u06CC\u0645\u06CC\u0644 \u0645\u06CC \u0628\u0627\u0634\u062F \u060C \u0622\u06CC\u0627 \u0645\u0627\u06CC\u0644\u06CC\u062F \u062A\u0627 \u067E\u06CC\u0634\u0648\u0646\u062F \u0627\u062C\u0628\u0627\u0631\u06CC \u0644\u0627\u0632\u0645\u0647 :mailto \u0631\u0627 \u0627\u0636\u0627\u0641\u0647 \u0646\u0645\u0627\u0626\u06CC\u062F\u061F", link_is_external:"URL \u06CC \u0643\u0647 \u0634\u0645\u0627 \u0648\u0627\u0631\u062F \u0646\u0645\u0648\u062F\u0647 \u0627\u06CC\u062F \u0628\u0647 \u0646\u0638\u0631 \u0645\u06CC \u0622\u06CC\u062F \u0643\u0647 \u0644\u06CC\u0646\u0643 \u062E\u0627\u0631\u062C\u06CC \u0645\u06CC \u0628\u0627\u0634\u062F \u060C \u0622\u06CC\u0627 \u0645\u0627\u06CC\u0644\u06CC\u062F \u062A\u0627 \u067E\u06CC\u0634\u0648\u0646\u062F \u0644\u0627\u0632\u0645\u0647 //:http \u0631\u0627 \u0627\u0636\u0627\u0641\u0647 \u0646\u0645\u0627\u0626\u06CC\u062F\u061F", link_list:"\u0644\u06CC\u0633\u062A \u0644\u06CC\u0646\u0643" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/lv_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/l0000644000175000017500000000416611226234177033652 0ustar frankiefrankietinyMCE.addI18n('lv.openacs_dlg',{ about_title:"Par TinyMCE", about_general:"Par", about_help:"Pal\u012Bdz\u012Bba", about_license:"Licence", about_plugins:"Papildmodu\u013Ci", about_plugin:"Papildmodulis", about_author:"Autors", about_version:"Versija", about_loaded:"Iestat\u012Btie papildmodu\u013Ci", anchor_title:"Ievietot/Redi\u0123\u0113t enkursaiti", anchor_name:"Enkursaites nosaukums", code_title:"HTML koda redaktors", code_wordwrap:"V\u0101rdu p\u0101rne\u0161ana jaun\u0101 rind\u0101", colorpicker_title:"Izv\u0113l\u0113ties kr\u0101su", colorpicker_picker_tab:"Izv\u0113lnis", colorpicker_picker_title:"Kr\u0101su izv\u0113lnis", colorpicker_palette_tab:"Palete", colorpicker_palette_title:"Kr\u0101su palete", colorpicker_named_tab:"Nosaukts", colorpicker_named_title:"Nosaukt\u0101s kr\u0101sas", colorpicker_color:"Kr\u0101sa:", colorpicker_name:"Nosaukums:", charmap_title:"Izv\u0113lies simbolu", image_title:"Ievietot/Redi\u0123\u0113t att\u0113lu", image_src:"Att\u0113la URL", image_alt:"Att\u0113la apraksts", image_list:"Att\u0113lu saraksts", image_border:"Apmale", image_dimensions:"Izm\u0113ri", image_vspace:"Vertik\u0101l\u0101 atstarpe", image_hspace:"Horizont\u0101l\u0101 atstarpe", image_align:"Novietojums", image_align_baseline:"Pati apak\u0161a", image_align_top:"Aug\u0161a", image_align_middle:"Vidus", image_align_bottom:"Apak\u0161a", image_align_texttop:"Teksta aug\u0161a", image_align_textbottom:"Teksta apak\u0161a", image_align_left:"Pa kreisi", image_align_right:"Pa labi", link_title:"Ievietot/Redi\u0123\u0113t saiti", link_url:"Saites URL", link_target:"M\u0113r\u0137is", link_target_same:"Atv\u0113rt saiti \u0161ai pa\u0161\u0101 log\u0101", link_target_blank:"Atv\u0113rt saiti jaun\u0101 log\u0101", link_titlefield:"Nosaukums", link_is_email:"Ievad\u012Btais URL \u0161\u0137iet ir e-pasta adrese, vai tu v\u0113lies pirms t\u0101s pievienot mailto: pried\u0113kli? ", link_is_external:"Ievad\u012Btais URL \u0161\u0137iet ir \u0101r\u0113j\u0101 saite, vai tu v\u0113lies pirms t\u0101s pievienot http:// pried\u0113kli?", link_list:"Sai\u0161u saraksts" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/nl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/n0000644000175000017500000000335011226234177033646 0ustar frankiefrankietinyMCE.addI18n('nl.openacs_dlg',{ about_title:"Over TinyMCE", about_general:"Info", about_help:"Help", about_license:"Licentie", about_plugins:"Invoegtoepassingen", about_plugin:"Invoegtoepassing", about_author:"Auteur", about_version:"Versie", about_loaded:"Geladen Invoegtoepassingen", anchor_title:"Anker invoegen/bewerken", anchor_name:"Ankernaam", code_title:"HTML Bron", code_wordwrap:"Automatische terugloop", colorpicker_title:"Kleuren", colorpicker_picker_tab:"Alle kleuren", colorpicker_picker_title:"Alle kleuren", colorpicker_palette_tab:"Palet", colorpicker_palette_title:"Paletkleuren", colorpicker_named_tab:"Benoemd", colorpicker_named_title:"Benoemde kleuren", colorpicker_color:"Kleur:", colorpicker_name:"Naam:", charmap_title:"Symbolen", image_title:"Afbeelding invoegen/bewerken", image_src:"Bestand/URL", image_alt:"Beschrijving", image_list:"Lijst", image_border:"Rand", image_dimensions:"Afmetingen", image_vspace:"Verticale ruimte", image_hspace:"Horizontale ruimte", image_align:"Uitlijning", image_align_baseline:"Basislijn", image_align_top:"Boven", image_align_middle:"Midden", image_align_bottom:"Onder", image_align_texttop:"Bovenkant tekst", image_align_textbottom:"Onderkant tekst", image_align_left:"Links", image_align_right:"Rechts", link_title:"Link invoegen/bewerken", link_url:"URL", link_target:"Doel", link_target_same:"Link in hetzelfde venster openen", link_target_blank:"Link in een nieuw venster openen", link_titlefield:"Titel", link_is_email:"De ingevoerde URL lijkt op een e-mailadres. Wilt u de vereiste mailto: tekst voorvoegen?", link_is_external:"De ingevoerde URL lijkt op een externe link. Wilt u de vereiste http:// tekst voorvoegen?", link_list:"Link lijst" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/sv_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/s0000644000175000017500000000357011226234200033642 0ustar frankiefrankietinyMCE.addI18n('sv.openacs_dlg',{ about_title:"Om TinyMCE", about_general:"Om", about_help:"Hj\u00E4lp", about_license:"Licens", about_plugins:"Om plug-in", about_plugin:"Om plug-in", about_author:"Utvecklare", about_version:"Version", about_loaded:"Laddade plug-ins", anchor_title:"Infoga/redigera bokm\u00E4rke", anchor_name:"Namn", code_title:"HTML k\u00E4llkodsl\u00E4ge", code_wordwrap:"Bryt ord", colorpicker_title:"V\u00E4lj en f\u00E4rg", colorpicker_picker_tab:"V\u00E4ljare", colorpicker_picker_title:"F\u00E4rgv\u00E4ljare", colorpicker_palette_tab:"Palett", colorpicker_palette_title:"Palettf\u00E4rger", colorpicker_named_tab:"Namngivna", colorpicker_named_title:"Namngivna f\u00E4rger", colorpicker_color:"F\u00E4rg:", colorpicker_name:"Namn:", charmap_title:"V\u00E4lj ett specialtecken", image_title:"Infoga/redigera bild", image_src:"Bildens URL", image_alt:"Bildens beskrivning", image_list:"Bildlista", image_border:"Ram", image_dimensions:"Dimensioner", image_vspace:"Vertikalrymd", image_hspace:"Horisontalrymd", image_align:"Justering", image_align_baseline:"Baslinje", image_align_top:"Toppen", image_align_middle:"Mitten", image_align_bottom:"Botten", image_align_texttop:"Toppen av texten", image_align_textbottom:"Botten av texten", image_align_left:"V\u00E4nster", image_align_right:"H\u00F6ger", link_title:"Infoga/redigera l\u00E4nk", link_url:"L\u00E4nkens URL", link_target:"M\u00E5l", link_target_same:"\u00D6\u0096ppna l\u00E4nken i samma f\u00F6nster", link_target_blank:"\u00D6\u0096ppna l\u00E4nken i ett nytt f\u00F6nster", link_titlefield:"Titel", link_is_email:"L\u00E4nken du angav verkar vara en e-post adress. Vill du infoga mailto: prefixet p\u00E5 l\u00E4nken?", link_is_external:"L\u00E4nken du angav verkar vara en extern adress. Vill du infoga http:// prefixet p\u00E5 l\u00E4nken?", link_list:"L\u00E4nklista" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/gl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/g0000644000175000017500000000362711226234177033646 0ustar frankiefrankietinyMCE.addI18n('gl.openacs_dlg',{ about_title:"Sobre TinyMCE", about_general:"Sobre", about_help:"Axuda", about_license:"Licencia", about_plugins:"Comprementos", about_plugin:"Compremento", about_author:"Autor", about_version:"Versi\u00F3n", about_loaded:"Comprementos cargados", anchor_title:"Insertar/editar \u00E1ncora", anchor_name:"Nome da \u00E1ncora", code_title:"Editor HTML", code_wordwrap:"Cortar li\u00F1as autom\u00E1ticamente", colorpicker_title:"Seleccionar cor", colorpicker_picker_tab:"Selector", colorpicker_picker_title:"Selector de cores", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Paleta de cores", colorpicker_named_tab:"Nomeados", colorpicker_named_title:"Cores nomeados", colorpicker_color:"Cor:", colorpicker_name:"Nome:", charmap_title:"Seleccionar caracter personalizado", image_title:"Insertar/editar imaxe", image_src:"URL da imaxe", image_alt:"Descripci\u00F3n da imaxe", image_list:"Lista de Imaxes", image_border:"Borde", image_dimensions:"Dimensi\u00F3n", image_vspace:"Espacio vertical", image_hspace:"Espacio horizontal", image_align:"Ali\u00F1aci\u00F3n", image_align_baseline:"Li\u00F1a base", image_align_top:"Arriba", image_align_middle:"Medio", image_align_bottom:"Abaixo", image_align_texttop:"Texto arriba", image_align_textbottom:"Texto abaixo", image_align_left:"Esquerda", image_align_right:"Dereita", link_title:"Insertar/editar enlace", link_url:"URL do enlace", link_target:"Obxetivo", link_target_same:"Abrir v\u00EDnculo na mesma vent\u00E1", link_target_blank:"Abrir v\u00EDnculo nunha vent\u00E1 nova", link_titlefield:"T\u00EDtulo", link_is_email:"A URL introducida semella ser un enderezo de e-mail, \u00BFDesexa engadi-lo prefixo necesario mailto:?", link_is_external:"A URL introducida semella ser un v\u00EDnculo externo, \u00BFDesexa engadi-lo prefixo necesario http://?", link_list:"Lista de hiperv\u00EDnculos" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/it_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/i0000644000175000017500000000354611226234177033650 0ustar frankiefrankietinyMCE.addI18n('it.openacs_dlg',{ about_title:"Informazioni su TinyMCE", about_general:"Informazioni", about_help:"Aiuto", about_license:"Licenza", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"Autore", about_version:"Versione", about_loaded:"Plugin caricati", anchor_title:"Inserisci/modifica ancora", anchor_name:"Nome ancora", code_title:"Editor sorgente HTML", code_wordwrap:"A capo automatico", colorpicker_title:"Seleziona un colore", colorpicker_picker_tab:"Selettore", colorpicker_picker_title:"Selettore colori", colorpicker_palette_tab:"Tavolozza", colorpicker_palette_title:"Tavolozza dei colori", colorpicker_named_tab:"Per nome", colorpicker_named_title:"Colori per nome", colorpicker_color:"Colore:", colorpicker_name:"Nome:", charmap_title:"Seleziona carattere speciale", image_title:"Inserisci/modifica immagine", image_src:"URL immagine", image_alt:"Descrizione immagine", image_list:"Lista immagini", image_border:"Bordo", image_dimensions:"Dimensioni", image_vspace:"Spaziatura verticale", image_hspace:"Spaziatura orizzontale", image_align:"Allineamentot", image_align_baseline:"Alla base", image_align_top:"In alto", image_align_middle:"In mezzo", image_align_bottom:"In basso", image_align_texttop:"In alto al testo", image_align_textbottom:"In basso al testo", image_align_left:"A sinistra", image_align_right:"A destra", link_title:"Inserisci/modifica collegamento", link_url:"URL collegamento", link_target:"Target", link_target_same:"Apri link nella stessa finestra", link_target_blank:"Apri link in una nuova finestra", link_titlefield:"Titolo", link_is_email:"L'URL inserito sembra essere un indirizzo email. Aggiungere il necessario prefisso mailto: ?", link_is_external:"L'URL inserito sembra essere un link esterno. Aggiungere il necessario prefisso http:// ?", link_list:"Lista collegamenti" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/hu_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/h0000644000175000017500000000414711226234177033645 0ustar frankiefrankietinyMCE.addI18n('hu.openacs_dlg',{ about_title:"A TinyMCE-r\u0151l", about_general:"R\u00F3lunk", about_help:"Seg\u00EDts\u00E9g", about_license:"Licensz", about_plugins:"Pluginok", about_plugin:"Plugin", about_author:"Szerz\u0151", about_version:"Verzi\u00F3", about_loaded:"Bet\u00F6lt\u00F6tt pluginok", anchor_title:"Horgony besz\u00FAr\u00E1sa/szerkeszt\u00E9se", anchor_name:"Horgonyn\u00E9v", code_title:"HTML forr\u00E1s szerkeszt\u00E9se", code_wordwrap:"Sz\u00F6veg t\u00F6rdel\u00E9se", colorpicker_title:"Sz\u00EDnv\u00E1laszt\u00E1s", colorpicker_picker_tab:"V\u00E1laszt\u00F3", colorpicker_picker_title:"Sz\u00EDnv\u00E1laszt\u00F3", colorpicker_palette_tab:"Paletta", colorpicker_palette_title:"Paletta sz\u00EDnek", colorpicker_named_tab:"Elnevezettek", colorpicker_named_title:"Elnevezett sz\u00EDnek", colorpicker_color:"Sz\u00EDn:", colorpicker_name:"N\u00E9v:", charmap_title:"Egyedi karakter v\u00E1laszt\u00E1sa", image_title:"K\u00E9p besz\u00FAr\u00E1sa/szerkeszt\u00E9se", image_src:"K\u00E9p URL", image_alt:"K\u00E9p le\u00EDr\u00E1s", image_list:"K\u00E9p lista", image_border:"Keret", image_dimensions:"Dimenzi\u00F3k", image_vspace:"F\u00FCgg\u0151leges t\u00E1v", image_hspace:"V\u00EDzszintes t\u00E1v", image_align:"Igaz\u00EDt\u00E1s", image_align_baseline:"Alapvonalhoz", image_align_top:"Fentre", image_align_middle:"K\u00F6z\u00E9pre", image_align_bottom:"Lentre", image_align_texttop:"Sz\u00F6veg tetej\u00E9hez", image_align_textbottom:"Sz\u00F6veg alj\u00E1hoz", image_align_left:"Balra", image_align_right:"Jobbra", link_title:"Link besz\u00FAr\u00E1sa/szerkeszt\u00E9se", link_url:"Link URL", link_target:"Target", link_target_same:"Link azonos ablakba nyit\u00E1sa", link_target_blank:"Link \u00FAj ablakba nyit\u00E1sa", link_titlefield:"C\u00EDm", link_is_email:"A be\u00EDrt URL e-mail c\u00EDmnek t\u0171nik, k\u00EDv\u00E1nja a sz\u00FCks\u00E9ges mailto:-t el\u00E9 tenni?", link_is_external:"A be\u00EDrt URL k\u00FCls\u0151 hivatkoz\u00E1snak t\u0171nik, k\u00EDv\u00E1nja a sz\u00FCks\u00E9ges http://-t el\u00E9 tenni?", link_list:"Link lista" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/en_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000000327311201070601033620 0ustar frankiefrankietinyMCE.addI18n('en.openacs_dlg',{ about_title:"About TinyMCE", about_general:"About", about_help:"Help", about_license:"License", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"Author", about_version:"Version", about_loaded:"Loaded plugins", anchor_title:"Insert/edit anchor", anchor_name:"Anchor name", code_title:"HTML Source Editor", code_wordwrap:"Word wrap", colorpicker_title:"Select a color", colorpicker_picker_tab:"Picker", colorpicker_picker_title:"Color picker", colorpicker_palette_tab:"Palette", colorpicker_palette_title:"Palette colors", colorpicker_named_tab:"Named", colorpicker_named_title:"Named colors", colorpicker_color:"Color:", colorpicker_name:"Name:", charmap_title:"Select custom character", image_title:"Insert/edit image", image_src:"Image URL", image_alt:"Image description", image_list:"Image list", image_border:"Border", image_dimensions:"Dimensions", image_vspace:"Vertical space", image_hspace:"Horizontal space", image_align:"Alignment", image_align_baseline:"Baseline", image_align_top:"Top", image_align_middle:"Middle", image_align_bottom:"Bottom", image_align_texttop:"Text top", image_align_textbottom:"Text bottom", image_align_left:"Left", image_align_right:"Right", link_title:"Insert/edit link", link_url:"Link URL", link_target:"Target", link_target_same:"Open link in the same window", link_target_blank:"Open link in a new window", link_titlefield:"Title", link_is_email:"The URL you entered seems to be an email address, do you want to add the required mailto: prefix?", link_is_external:"The URL you entered seems to external link, do you want to add the required http:// prefix?", link_list:"Link list" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ko_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/k0000644000175000017500000000430411226234177033643 0ustar frankiefrankietinyMCE.addI18n('ko.openacs_dlg',{ about_title:"TinyMCE\uC5D0 \uB300\uD558\uC5EC", about_general:"About", about_help:"\uB3C4\uC6C0\uB9D0", about_license:"\uB77C\uC774\uC13C\uC2A4", about_plugins:"\uD50C\uB7EC\uADF8\uC778", about_plugin:"\uD50C\uB7EC\uADF8\uC778", about_author:"\uC81C\uC791\uC790", about_version:"\uBC84\uC83C", about_loaded:"\uC2E4\uD589\uB41C \uD50C\uB7EC\uADF8\uC778", anchor_title:"\uC5E5\uCEE4 \uC0BD\uC785/\uD3B8\uC9D1", anchor_name:"\uC5E5\uCEE4\uBA85", code_title:"\uC18C\uC2A4 \uD3B8\uC9D1", code_wordwrap:"\uC6CC\uB4DC\uB7A9", colorpicker_title:"\uC0C9\uC744 \uC120\uD0DD", colorpicker_picker_tab:"\uD53D\uCEE4", colorpicker_picker_title:"\uCEEC\uB7EC \uD53D\uCEE4", colorpicker_palette_tab:"\uD314\uB808\uD2B8", colorpicker_palette_title:"\uD314\uB808\uD2B8 \uC0C9", colorpicker_named_tab:"\uC0C9 \uC774\uB984", colorpicker_named_title:"\uC0C9", colorpicker_color:"Color:", colorpicker_name:"\uC0C9 \uC774\uB984:", charmap_title:"\uD2B9\uC218 \uBB38\uC790", image_title:"\uC774\uBBF8\uC9C0\uC758 \uC0BD\uC785/\uD3B8\uC9D1", image_src:"\uC774\uBBF8\uC9C0 URL", image_alt:"\uC774\uBBF8\uC9C0 \uC124\uBA85", image_list:"\uC774\uBBF8\uC9C0 \uBAA9\uB85D", image_border:"\uD14C\uB450\uB9AC\uC120", image_dimensions:"\uD06C\uAE30", image_vspace:"\uC0C1\uD558 \uC5EC\uBC31", image_hspace:"\uC88C\uC6B0 \uC5EC\uBC31", image_align:"\uC815\uB82C", image_align_baseline:"\uAE30\uC900\uC120", image_align_top:"Top", image_align_middle:"Middle", image_align_bottom:"Bottom", image_align_texttop:"Text top", image_align_textbottom:"Text bottom", image_align_left:"Left", image_align_right:"Right", link_title:"\uB9C1\uD06C\uC758 \uC0BD\uC785/\uD3B8\uC9D1", link_url:"\uB9C1\uD06C URL", link_target:"Target", link_target_same:"\uAC19\uC740\uCC3D", link_target_blank:"\uC0C8\uCC3D", link_titlefield:"\uC81C\uBAA9", link_is_email:"\uBA54\uC77C\uC8FC\uC18C\uAC00 \uC785\uB825\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\n\uBA54\uC77C\uC8FC\uC18C\uC758 \uC55E\uC5D0 mailto:\uB97C \uBD99\uC785\uB2C8\uAE4C?", link_is_external:"\uC678\uBD80URL\uC774 \uC785\uB825\uB418\uC5C8\uC2B5\uB2C8\uB2E4.\nURL\uC758 \uC55E\uC5D0 http://\uB97C \uBD99\uC785\uB2C8\uAE4C?", link_list:"\uB9C1\uD06C \uBAA9\uB85D" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/pt_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/p0000644000175000017500000000360211226234200033633 0ustar frankiefrankietinyMCE.addI18n('pt.openacs_dlg',{ about_title:"Sobre o TinyMCE", about_general:"Sobre", about_help:"Ajuda", about_license:"Licen\u00E7a", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"Autor", about_version:"Vers\u00E3o", about_loaded:"Plugins Instalados", anchor_title:"Inserir/editar \u00E2ncora", anchor_name:"Nome", code_title:"Editor HTML", code_wordwrap:"Quebra autom\u00E1tica de linha", colorpicker_title:"Selecione uma cor", colorpicker_picker_tab:"Editor", colorpicker_picker_title:"Editor de Cores", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Paleta de Cores", colorpicker_named_tab:"Personalizadas", colorpicker_named_title:"Cores Personalizadas", colorpicker_color:"Cor:", colorpicker_name:"Nome:", charmap_title:"Selecionar caracteres personalizados", image_title:"Inserir/editar imagem", image_src:"Endere\u00E7 da imagem", image_alt:"Descri\u00E7\u00E3o da imagem", image_list:"Lista de imagens", image_border:"Limites", image_dimensions:"Dimens\u00F5es", image_vspace:"Espa\u00E7o Vertical", image_hspace:"Espa\u00E7o Horizontal", image_align:"Alinhamento", image_align_baseline:"Sobre a linha de texto", image_align_top:"Topo", image_align_middle:"Meio", image_align_bottom:"Abaixo", image_align_texttop:"Topo do texto", image_align_textbottom:"Base do texto", image_align_left:"Esquerda", image_align_right:"Direita", link_title:"Inserir/editar hyperlink", link_url:"URL do hyperink", link_target:"Alvo", link_target_same:"Abrir hyperlink na mesma janela", link_target_blank:"Abrir hyperlink em nova janela", link_titlefield:"T\u00EDtulo", link_is_email:"A URL digitada parece ser um endere\u00E7o de e-mail. Deseja acrescentar o prefixo necess\u00E1rio mailto:?", link_is_external:"A URL digitada parece conduzir a um link externo. Deseja acrescentar o prefixo necess\u00E1rio http://?", link_list:"Lista de Links" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/th_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/t0000644000175000017500000001045611226234200033644 0ustar frankiefrankietinyMCE.addI18n('th.openacs_dlg',{ about_title:"\u0E40\u0E01\u0E35\u0E48\u0E22\u0E27\u0E01\u0E31\u0E1A TinyMCE", about_general:"\u0E40\u0E01\u0E35\u0E48\u0E22\u0E27\u0E01\u0E31\u0E1A\u0E40\u0E23\u0E32", about_help:"\u0E0A\u0E48\u0E27\u0E22\u0E40\u0E25\u0E2B\u0E37\u0E2D", about_license:"\u0E25\u0E34\u0E02\u0E2A\u0E34\u0E17\u0E18\u0E34", about_plugins:"\u0E1B\u0E25\u0E31\u0E4A\u0E01\u0E2D\u0E34\u0E19", about_plugin:"\u0E1B\u0E25\u0E31\u0E4A\u0E01\u0E2D\u0E34\u0E19", about_author:"\u0E1C\u0E39\u0E49\u0E40\u0E02\u0E35\u0E22\u0E19", about_version:"\u0E23\u0E38\u0E48\u0E19", about_loaded:"\u0E42\u0E2B\u0E25\u0E14\u0E1B\u0E25\u0E31\u0E4A\u0E01\u0E2D\u0E34\u0E19", anchor_title:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", anchor_name:"\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", code_title:"\u0E41\u0E01\u0E49\u0E44\u0E02 HTML", code_wordwrap:"\u0E15\u0E31\u0E14\u0E04\u0E33", colorpicker_title:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2A\u0E35", colorpicker_picker_tab:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E2A\u0E35", colorpicker_picker_title:"\u0E08\u0E32\u0E19\u0E2A\u0E35", colorpicker_palette_tab:"\u0E08\u0E32\u0E19\u0E2A\u0E35", colorpicker_palette_title:"\u0E08\u0E32\u0E19\u0E2A\u0E35", colorpicker_named_tab:"\u0E0A\u0E37\u0E48\u0E2D", colorpicker_named_title:"\u0E0A\u0E37\u0E48\u0E2D\u0E2A\u0E35", colorpicker_color:"\u0E2A\u0E35:", colorpicker_name:"\u0E0A\u0E37\u0E48\u0E2D:", charmap_title:"\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E15\u0E31\u0E27\u0E2D\u0E31\u0E01\u0E29\u0E23\u0E17\u0E35\u0E48\u0E01\u0E33\u0E2B\u0E19\u0E14\u0E40\u0E2D\u0E07", image_title:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E23\u0E39\u0E1B", image_src:"URL \u0E23\u0E39\u0E1B", image_alt:"\u0E23\u0E32\u0E22\u0E25\u0E30\u0E2D\u0E35\u0E22\u0E14\u0E23\u0E39\u0E1B", image_list:"\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E23\u0E39\u0E1B", image_border:"\u0E01\u0E23\u0E2D\u0E1A", image_dimensions:"\u0E02\u0E19\u0E32\u0E14", image_vspace:"\u0E23\u0E30\u0E22\u0E30\u0E2B\u0E48\u0E32\u0E07\u0E41\u0E19\u0E27\u0E15\u0E31\u0E49\u0E07", image_hspace:"\u0E23\u0E30\u0E22\u0E30\u0E2B\u0E48\u0E32\u0E07\u0E41\u0E19\u0E27\u0E19\u0E2D\u0E19", image_align:"\u0E15\u0E33\u0E41\u0E2B\u0E19\u0E48\u0E07\u0E08\u0E31\u0E14\u0E27\u0E32\u0E07", image_align_baseline:"\u0E40\u0E2A\u0E49\u0E19\u0E1E\u0E37\u0E49\u0E19", image_align_top:"\u0E1A\u0E19", image_align_middle:"\u0E01\u0E25\u0E32\u0E07", image_align_bottom:"\u0E25\u0E48\u0E32\u0E07", image_align_texttop:"\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E2D\u0E22\u0E39\u0E48\u0E1A\u0E19", image_align_textbottom:"\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E2D\u0E22\u0E39\u0E48\u0E25\u0E48\u0E32\u0E07", image_align_left:"\u0E0B\u0E49\u0E32\u0E22", image_align_right:"\u0E02\u0E27\u0E32", link_title:"\u0E40\u0E1E\u0E34\u0E48\u0E21/\u0E41\u0E01\u0E49\u0E44\u0E02 \u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C", link_url:"\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C URL", link_target:"\u0E40\u0E1B\u0E49\u0E32\u0E2B\u0E21\u0E32\u0E22", link_target_same:"\u0E40\u0E1B\u0E34\u0E14\u0E25\u0E34\u0E07\u0E01\u0E4C\u0E43\u0E19\u0E2B\u0E19\u0E49\u0E32\u0E15\u0E48\u0E32\u0E07\u0E40\u0E14\u0E35\u0E22\u0E27\u0E01\u0E31\u0E19", link_target_blank:"\u0E40\u0E1B\u0E34\u0E14\u0E25\u0E34\u0E07\u0E01\u0E4C\u0E43\u0E19\u0E2B\u0E19\u0E49\u0E32\u0E15\u0E48\u0E32\u0E07\u0E43\u0E2B\u0E21\u0E48", link_titlefield:"\u0E0A\u0E37\u0E48\u0E2D", link_is_email:"URL \u0E17\u0E35\u0E48\u0E04\u0E38\u0E13\u0E1B\u0E49\u0E2D\u0E19\u0E14\u0E39\u0E40\u0E2B\u0E21\u0E37\u0E2D\u0E19\u0E27\u0E48\u0E32\u0E08\u0E30\u0E21\u0E35\u0E17\u0E35\u0E48\u0E2D\u0E22\u0E39\u0E48\u0E2D\u0E35\u0E40\u0E21\u0E25\u0E2D\u0E22\u0E39\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1E\u0E34\u0E48\u0E21 mailto: \u0E19\u0E33\u0E2B\u0E19\u0E49\u0E32\u0E2B\u0E23\u0E37\u0E2D\u0E44\u0E21\u0E48 ?", link_is_external:"URL \u0E17\u0E35\u0E48\u0E04\u0E38\u0E13\u0E1B\u0E49\u0E2D\u0E19\u0E14\u0E39\u0E40\u0E2B\u0E21\u0E37\u0E2D\u0E19\u0E27\u0E48\u0E32\u0E20\u0E32\u0E22\u0E19\u0E2D\u0E01\u0E25\u0E34\u0E07\u0E04\u0E04\u0E38\u0E13\u0E15\u0E49\u0E2D\u0E07\u0E01\u0E32\u0E23\u0E40\u0E1E\u0E34\u0E48\u0E21 http:// \u0E2B\u0E23\u0E37\u0E2D\u0E44\u0E21\u0E48 ?", link_list:"\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E25\u0E34\u0E49\u0E07\u0E04\u0E4C" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/fr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/f0000644000175000017500000000365411226234177033645 0ustar frankiefrankietinyMCE.addI18n('fr.openacs_dlg',{ about_title:"\u00C0 propos de TinyMCE", about_general:"\u00C0 propos", about_help:"Aide", about_license:"Licence", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"Auteur", about_version:"Version", about_loaded:"Plugins charg\u00E9s", anchor_title:"Ins\u00E9rer/\u00C9diter ancre", anchor_name:"Nom de l'ancre", code_title:"\u00C9diteur de la source HTML", code_wordwrap:"Rupture de ligne", colorpicker_title:"Choisir une couleur", colorpicker_picker_tab:"Nuancier", colorpicker_picker_title:"Nuancier", colorpicker_palette_tab:"Palette", colorpicker_palette_title:"Couleurs de la palette", colorpicker_named_tab:"Noms", colorpicker_named_title:"Couleurs nomm\u00E9es", colorpicker_color:"Couleur :", colorpicker_name:"Nom :", charmap_title:"Choisir le caract\u00E8re \u00E0 ins\u00E9rer", image_title:"Ins\u00E9rer/\u00C9diter image", image_src:"URL de l'image", image_alt:"Description de l'image", image_list:"Liste d'images", image_border:"Bordure", image_dimensions:"Dimensions", image_vspace:"Espacement vertical", image_hspace:"Espacement horizontal", image_align:"Alignement", image_align_baseline:"Base", image_align_top:"Sommet", image_align_middle:"Milieu", image_align_bottom:"Bas", image_align_texttop:"Haut du texte", image_align_textbottom:"Bas du texte", image_align_left:"Gauche", image_align_right:"Droite", link_title:"Ins\u00E9rer/\u00C9diter lien", link_url:"URL du lien", link_target:"Cible", link_target_same:"Ouvrir dans la m\u00EAme fen\u00EAtre", link_target_blank:"Ouvrir dans une nouvelle fen\u00EAtre", link_titlefield:"Titre", link_is_email:"L'url que vous avez entr\u00E9 semble \u00EAtre une adresse e-mail, voulez-vous ajouter le pr\u00E9fixe mailto:\u00A0?", link_is_external:"L'url que vous avez entr\u00E9 semble \u00EAtre une adresse web externe, voulez-vous ajouter le pr\u00E9fixe http://\u00A0?", link_list:"Liste de liens" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/de_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/d0000644000175000017500000000350411226234177033635 0ustar frankiefrankietinyMCE.addI18n('de.openacs_dlg',{ about_title:"\u00DCber TinyMCE", about_general:"\u00DCber\u2026", about_help:"Hilfe", about_license:"Lizenzbedingungen", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"Urheber", about_version:"Version", about_loaded:"Geladene Plugins", anchor_title:"Anker einf\u00FCgen/ver\u00E4ndern", anchor_name:"Name des Ankers", code_title:"HTML-Quellcode bearbeiten", code_wordwrap:"Automatischer Zeilenumbruch", colorpicker_title:"Farbe", colorpicker_picker_tab:"Farbwahl", colorpicker_picker_title:"Farbwahl", colorpicker_palette_tab:"Palette", colorpicker_palette_title:"Farbpalette", colorpicker_named_tab:"Benannte Farben", colorpicker_named_title:"Benannte Farben", colorpicker_color:"Farbe:", colorpicker_name:"Name:", charmap_title:"Sonderzeichen", image_title:"Bild einf\u00FCgen/bearbeiten", image_src:"Adresse", image_alt:"Alternativtext", image_list:"Bilderliste", image_border:"Rahmen", image_dimensions:"Ausma\u00DFe", image_vspace:"Vertikaler Abstand", image_hspace:"Horizontaler Abstand", image_align:"Ausrichtung", image_align_baseline:"Zeile", image_align_top:"Oben", image_align_middle:"Mittig", image_align_bottom:"Unten", image_align_texttop:"Oben im Text", image_align_textbottom:"Unten im Text", image_align_left:"Links", image_align_right:"Rechts", link_title:"Link einf\u00FCgen/bearbeiten", link_url:"Adresse", link_target:"Fenster", link_target_same:"Im selben Fenster \u00F6ffnen", link_target_blank:"Neues Fenster \u00F6ffnen", link_titlefield:"Titel", link_is_email:"Diese Adresse scheint eine E-Mail-Adresse zu sein. M\u00F6chten Sie das dazu ben\u00F6tigte mailto: voranstellen?", link_is_external:"Diese Adresse scheint ein externer Link zu sein. M\u00F6chten Sie das dazu ben\u00F6tigte http:// voranstellen?", link_list:"Linkliste" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/si_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/s0000644000175000017500000001064511226234200033643 0ustar frankiefrankietinyMCE.addI18n('si.openacs_dlg',{ about_title:" TinyMCE \u0DB4\u0DD2\u0DC5\u0DD2\u0DB6\u0DB3", about_general:"\u0DC3\u0DC0\u0DD2\u0DC3\u0DCA\u0DAD\u0DBB\u0DCF\u0DAD\u0DCA\u0DB8\u0D9A\u0DC0", about_help:"\u0D8B\u0DB4\u0D9A\u0DCF\u0DBB\u0DBA", about_license:"\u0DB6\u0DBD\u0DB4\u0DAD\u0DCA\u200D\u0DBB\u0DBA", about_plugins:"Plugins", about_plugin:"Plugin", about_author:"\u0D9A\u0DAD\u0DD8", about_version:"\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA", about_loaded:"Loaded plugins", anchor_title:"\u0D86\u0DB0\u0DCF\u0DBB\u0DBA \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", anchor_name:"\u0D86\u0DB0\u0DCF\u0DBB\u0D9A \u0DB1\u0DCF\u0DB8\u0DBA", code_title:"HTML \u0D9A\u0DDA\u0DAD \u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DCF\u0DBB\u0D9A\u0DBA", code_wordwrap:"\u0DC0\u0DCF\u0D9C\u0DCA \u0DC0\u0DD9\u0DBD\u0DD4\u0DB8", colorpicker_title:"\u0DC0\u0DBB\u0DCA\u0DAB\u0DBA \u0DAD\u0DDD\u0DBB\u0DB1\u0DCA\u0DB1", colorpicker_picker_tab:"\t\u0D87\u0DC4\u0DD4\u0DC5\u0DD4\u0DB8\u0DCA \u0D9A\u0DD6\u0DBB ", colorpicker_picker_title:"\u0DC0\u0DBB\u0DCA\u0DAB \u0D87\u0DC4\u0DD4\u0DC5\u0DD4\u0DB8\u0DCA \u0D9A\u0DD6\u0DBB", colorpicker_palette_tab:"\t\u0DC0\u0DBB\u0DCA\u0DAB \u0D91\u0DBD\u0D9A\u0DBA", colorpicker_palette_title:"\t\u0DC0\u0DBB\u0DCA\u0DAB \u0D91\u0DBD\u0D9A \u0DC0\u0DBB\u0DCA\u0DAB", colorpicker_named_tab:"\u0DB1\u0DB8\u0DD0\u0DAD\u0DD2", colorpicker_named_title:"\u0DB1\u0DB8\u0DD0\u0DAD\u0DD2 \u0DC0\u0DBB\u0DCA\u0DAB", colorpicker_color:"\u0DC0\u0DBB\u0DCA\u0DAB:", colorpicker_name:"\u0DB1\u0DCF\u0DB8\u0DBA", charmap_title:"\u0DB7\u0DCF\u0DC0\u0DD2\u0DAD\u0DCF\u0DC0\u0DB1 \u0D9C\u0DD4\u0DAB\u0DCF\u0D82\u0D9C\u0DBA \u0DAD\u0DDD\u0DBB\u0DB1\u0DCA\u0DB1", image_title:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DBA\u0DD9\u0DC4\u0DD2 \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", image_src:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DBA\u0DD9\u0DC4\u0DD2 URL", image_alt:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4\u0DBA\u0DD9\u0DC4\u0DD2 \u0DC0\u0DD2\u0DC3\u0DCA\u0DAD\u0DBB", image_list:"\u0D85\u0DB1\u0DD4\u0DBB\u0DD6\u0DB4 \u0DBD\u0DD0\u0DBA\u0DD2\u0DC3\u0DCA\u0DAD\u0DD4\u0DC0", image_border:"\u0DB6\u0DDD\u0DA9\u0DBB\u0DBA", image_dimensions:"\u0DB8\u0DCF\u0DB1", image_vspace:"\u0DC3\u0DD2\u0DBB\u0DC3\u0DCA \u0D85\u0DC0\u0D9A\u0DCF\u0DC1\u0DBA", image_hspace:"\u0DAD\u0DD2\u0DBB\u0DC3\u0DCA \u0D85\u0DC0\u0D9A\u0DCF\u0DC1\u0DBA", image_align:"\u0DB4\u0DD9\u0DBD \u0D9C\u0DD0\u0DB1\u0DCA\u0DC0\u0DD4\u0DB8", image_align_baseline:"\u0DB8\u0DD6\u0DBD\u0DD2\u0D9A\u0DBA", image_align_top:"\u0D89\u0DC4\u0DC5", image_align_middle:"\u0DB8\u0DD0\u0DAF", image_align_bottom:"\u0DBA\u0DA7", image_align_texttop:"\u0DB4\u0DCF\u0DA8\u0DBA \u0D89\u0DC4\u0DC5", image_align_textbottom:"\u0DB4\u0DCF\u0DA8\u0DBA \u0DB4\u0DC4\u0DC5", image_align_left:"\u0DC0\u0DB8\u0DA7", image_align_right:"\u0DAF\u0D9A\u0DD4\u0DAB\u0DA7", link_title:"\u0D87\u0DB8\u0DD4\u0DB1\u0DD4\u0DB8 \u0D87\u0DAD\u0DD4\u0DC5\u0DD4/\u0DC3\u0D82\u0DC3\u0DCA\u0D9A\u0DBB\u0DAB\u0DBA \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", link_url:"\u0D87\u0DB8\u0DD4\u0DB1\u0DD4\u0DB8 URL", link_target:"\u0D89\u0DBD\u0D9A\u0DCA\u0D9A\u0DBA", link_target_same:"\u0D87\u0DB8\u0DD4\u0DB1\u0DD4\u0DB8 \u0DC0\u0DD9\u0DB1\u0DB8 \u0D9A\u0DC0\u0DD4\u0DBD\u0DD4\u0DC0\u0D9A \u0DC0\u0DD2\u0DC0\u0DD8\u0DAD \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", link_target_blank:"\u0D87\u0DB8\u0DD4\u0DB1\u0DD4\u0DB8 \u0DC0\u0DD9\u0DB1\u0DB8 \u0D9A\u0DC0\u0DD4\u0DBD\u0DD4\u0DC0\u0D9A \u0DC0\u0DD2\u0DC0\u0DD8\u0DAD \u0D9A\u0DBB\u0DB1\u0DCA\u0DB1", link_titlefield:"\u0DB8\u0DCF\u0DAD\u0DD8\u0D9A\u0DCF\u0DC0", link_is_email:"\u0D94\u0DB6 \u0D87\u0DAD\u0DD4\u0DC5\u0DAD\u0DCA \u0D9A\u0DC5 URL \u0DBA \u0DC0\u0DD2\u0DAF\u0DCA\u200D\u0DBA\u0DD4\u0DAD\u0DCA \u0DAD\u0DD0\u0DB4\u0DD0\u0DBD \u0D9A\u0DCA \u0DB1\u0DB8\u0DCA \u0D94\u0DB6\u0DA7 \u0D91\u0DBA\u0DA7 \u0DB4\u0DCA\u200D\u0DBB\u0DC0\u0DDA\u0DC1 \u0DC0\u0DD3\u0DB8\u0DA7 \u0D85\u0DC0\u0DC1\u0DCA\u200D\u0DBA \u0DAF?", link_is_external:"\u0D94\u0DB6 \u0D87\u0DAD\u0DD4\u0DC5\u0DAD\u0DCA \u0D9A\u0DC5 URL \u0DBA \u0DB6\u0DCF\u0DC4\u0DD2\u0DBB \u0D87\u0DB8\u0DD2\u0DAB\u0DD4\u0DB8\u0D9A\u0DCA \u0DB1\u0DB8\u0DCA,\u0D94\u0DB6\u0DA7 \u0D91\u0DBA\u0DA7 \u0DB4\u0DCA\u200D\u0DBB\u0DC0\u0DDA\u0DC1 \u0DC0\u0DD3\u0DB8\u0DA7 \u0D85\u0DC0\u0DC1\u0DCA\u200D\u0DBA \u0DAF??", link_list:"\u0D87\u0DB8\u0DD4\u0DAB\u0DD4\u0DB8\u0DCA \u0DBD\u0DBA\u0DD2\u0DC3\u0DCA\u0DAD\u0DD4\u0DC0" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ja_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/j0000644000175000017500000000516411226234177033647 0ustar frankiefrankietinyMCE.addI18n('ja.openacs_dlg',{ about_title:"TinyMCE\u306B\u3064\u3044\u3066", about_general:"\u8A73\u7D30", about_help:"\u30D8\u30EB\u30D7", about_license:"\u30E9\u30A4\u30BB\u30F3\u30B9", about_plugins:"\u30D7\u30E9\u30B0\u30A4\u30F3", about_plugin:"\u30D7\u30E9\u30B0\u30A4\u30F3", about_author:"\u4F5C\u8005", about_version:"\u30D0\u30FC\u30B8\u30E7\u30F3", about_loaded:"\u8AAD\u8FBC\u6E08\u307F\u30D7\u30E9\u30B0\u30A4\u30F3", anchor_title:"\u30A2\u30F3\u30AB\u30FC\u306E\u633F\u5165/\u7DE8\u96C6", anchor_name:"\u30A2\u30F3\u30AB\u30FC\u540D", code_title:"HTML\u30BD\u30FC\u30B9\u30A8\u30C7\u30A3\u30BF", code_wordwrap:"\u6298\u308A\u8FD4\u3057", colorpicker_title:"\u8272\u306E\u9078\u629E", colorpicker_picker_tab:"\u30AB\u30E9\u30FC\u30D4\u30C3\u30AB\u30FC", colorpicker_picker_title:"\u30AB\u30E9\u30FC\u30D4\u30C3\u30AB\u30FC", colorpicker_palette_tab:"\u30D1\u30EC\u30C3\u30C8", colorpicker_palette_title:"\u30D1\u30EC\u30C3\u30C8", colorpicker_named_tab:"\u65E2\u5B9A\u8272", colorpicker_named_title:"\u65E2\u5B9A\u8272", colorpicker_color:"\u30AB\u30E9\u30FC:", colorpicker_name:"\u540D\u524D:", charmap_title:"\u7279\u6B8A\u6587\u5B57", image_title:"\u753B\u50CF\u306E\u633F\u5165/\u7DE8\u96C6", image_src:"\u753B\u50CFURL", image_alt:"\u753B\u50CF\u306E\u8AAC\u660E", image_list:"\u4E00\u89A7\u304B\u3089\u9078\u3076", image_border:"\u67A0\u7DDA", image_dimensions:"\u30B5\u30A4\u30BA", image_vspace:"\u4E0A\u4E0B\u4F59\u767D", image_hspace:"\u5DE6\u53F3\u4F59\u767D", image_align:"\u914D\u7F6E", image_align_baseline:"\u30D9\u30FC\u30B9\u30E9\u30A4\u30F3", image_align_top:"\u4E0A\u7AEF\u63C3\u3048", image_align_middle:"\u4E2D\u592E\u63C3\u3048", image_align_bottom:"\u4E0B\u63C3\u3048", image_align_texttop:"\u30C6\u30AD\u30B9\u30C8\u306E\u4E0A\u7AEF", image_align_textbottom:"\u30C6\u30AD\u30B9\u30C8\u306E\u4E0B\u7AEF", image_align_left:"\u5DE6\u5BC4\u305B", image_align_right:"\u53F3\u5BC4\u305B", link_title:"\u30EA\u30F3\u30AF\u306E\u633F\u5165/\u7DE8\u96C6", link_url:"\u30EA\u30F3\u30AFURL", link_target:"\u30BF\u30FC\u30B2\u30C3\u30C8", link_target_same:"\u540C\u3058\u30A6\u30A4\u30F3\u30C9\u30A6\u3067\u958B\u304F", link_target_blank:"\u65B0\u3057\u3044\u30A6\u30A4\u30F3\u30C9\u30A6\u3067\u958B\u304F", link_titlefield:"\u30BF\u30A4\u30C8\u30EB", link_is_email:"\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u5165\u529B\u3055\u308C\u307E\u3057\u305F\u3002\u30EA\u30F3\u30AF\u306Bmailto:\u3092\u4ED8\u52A0\u3057\u307E\u3059\u304B\uFF1F", link_is_external:"\u30EA\u30F3\u30AF\u306Bhttp://\u3092\u4ED8\u52A0\u3057\u307E\u3059\u304B\uFF1F", link_list:"\u4E00\u89A7\u304B\u3089\u9078\u3076" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ro_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/r0000644000175000017500000000404111226234200033633 0ustar frankiefrankietinyMCE.addI18n('ro.openacs_dlg',{ about_title:"Despre TinyMCE", about_general:"Despre", about_help:"Ajutor", about_license:"Licen\u0163\u0103", about_plugins:"Module", about_plugin:"Modul", about_author:"Autor", about_version:"Versiune", about_loaded:"Module \u00EEnc\u0103rcate", anchor_title:"Inserare/editare ancor\u0103", anchor_name:"Nume ancor\u0103", code_title:"Editor surs\u0103 HTML", code_wordwrap:"Word wrap", colorpicker_title:"Alege\u0163i o culoare", colorpicker_picker_tab:"Pipet\u0103", colorpicker_picker_title:"Pipet\u0103 de culori", colorpicker_palette_tab:"Palet\u0103", colorpicker_palette_title:"Palet\u0103 de culori", colorpicker_named_tab:"Denumite", colorpicker_named_title:"Culori denumite", colorpicker_color:"Culoare:", colorpicker_name:"Nume:", charmap_title:"Alege\u0163i un caracter special", image_title:"Insereaz\u0103/editeaz\u0103 o imagine", image_src:"URL imagine", image_alt:"Descriere imagine", image_list:"List\u0103 de imagini", image_border:"Bordur\u0103", image_dimensions:"Dimensiuni", image_vspace:"Spa\u0163iu vertical", image_hspace:"Spa\u0163iu orizontal", image_align:"Aliniere", image_align_baseline:"Baseline", image_align_top:"Sus", image_align_middle:"La mijloc", image_align_bottom:"Jos", image_align_texttop:"Textul sus", image_align_textbottom:"Textul la mijloc", image_align_left:"St\u00E2nga", image_align_right:"Dreapta", link_title:"Inserare/editare leg\u0103tur\u0103", link_url:"URL leg\u0103tur\u0103", link_target:"\u0162int\u0103", link_target_same:"Deschide leg\u0103tura \u00EEn aceea\u015Fi fereastr\u0103", link_target_blank:"Deschide leg\u0103tura \u00EEntr-o fereastr\u0103 nou\u0103", link_titlefield:"Titlu", link_is_email:"URL-ul pe care l-a\u0163i introdus pare a fi o adres\u0103 de e-mail. Dori\u0163i s\u0103 adaug \u015Fi prefixul mailto: necesar?", link_is_external:"URL-ul pe care l-a\u0163i introdus pare a fi o leg\u0103tur\u0103 extern\u0103. Dori\u0163i s\u0103 adaug \u015Fi prefixul http:// necesar?", link_list:"Lista de leg\u0103turi" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/es_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/e0000644000175000017500000000371611226234177033643 0ustar frankiefrankietinyMCE.addI18n('es.openacs_dlg',{ about_title:"Acerca de TinyMCE", about_general:"Acerca de ", about_help:"Ayuda", about_license:"Licencia", about_plugins:"Complementos", about_plugin:"Complemento", about_author:"Autor", about_version:"Versi\u00F3n", about_loaded:"Complementos cargados", anchor_title:"Insertar/editar ancla", anchor_name:"Nombre del ancla", code_title:"Editor del c\u00F3digo fuente HTML", code_wordwrap:"Ajustar al margen", colorpicker_title:"Seleccionar color", colorpicker_picker_tab:"Selector", colorpicker_picker_title:"Paleta de color", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Paleta de colores", colorpicker_named_tab:"Nombrados", colorpicker_named_title:"Colores nombrados", colorpicker_color:"Color:", colorpicker_name:"Nombre:", charmap_title:"Seleccionar caracter personalizado", image_title:"Insertar/editar imagen", image_src:"URL de la Imagen", image_alt:"Descripci\u00F3n de la Imagen", image_list:"Lista de la Imagen", image_border:"Borde", image_dimensions:"Dimensi\u00F3n", image_vspace:"Espacio vertical", image_hspace:"Espacio horizontal", image_align:"Alineaci\u00F3n", image_align_baseline:"L\u00EDnea base", image_align_top:"Arriba", image_align_middle:"Medio", image_align_bottom:"Debajo", image_align_texttop:"Texto arriba", image_align_textbottom:"Texto debajo", image_align_left:"Izquierda", image_align_right:"Derecha", link_title:"Insertar/editar hiperv\u00EDnculo", link_url:"URL del hiperv\u00EDnculo", link_target:"Destino", link_target_same:"Abrir v\u00EDnculo en la misma ventana", link_target_blank:"Abrir v\u00EDnculo en una ventana nueva", link_titlefield:"T\u00EDtulo", link_is_email:"La URL que introdujo parece ser una direcci\u00F3n de email, \u00BFdesea agregar el prefijo mailto: necesario?", link_is_external:"La URL que introdujo parece ser un v\u00EDnculo externo, \u00BFdesea agregar el prefijo http:// necesario?", link_list:"Lista de hiperv\u00EDnculos" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/ca_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/c0000644000175000017500000000362211226234177033635 0ustar frankiefrankietinyMCE.addI18n('ca.openacs_dlg',{ about_title:"Quant a TinyMCE", about_general:"Quant a", about_help:"Ajuda", about_license:"Llic\u00E8ncia", about_plugins:"Extensions", about_plugin:"Extensi\u00F3", about_author:"Autor", about_version:"Versi\u00F3", about_loaded:"Extensions carregades", anchor_title:"Insereix/edita \u00E0ncora", anchor_name:"Nom de l'\u00E0ncora", code_title:"Editor de Font HTML", code_wordwrap:"Salt de paraula", colorpicker_title:"Selecciona un color", colorpicker_picker_tab:"Triador", colorpicker_picker_title:"Triador de color", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Colors de la paleta", colorpicker_named_tab:"Amb nom", colorpicker_named_title:"Colors amb nom", colorpicker_color:"Color:", colorpicker_name:"Nom:", charmap_title:"Selecciona el car\u00E0cter personalitzat", image_title:"Insereix/edita imatge", image_src:"URL de la imatge", image_alt:"Descripci\u00F3 de la imatge", image_list:"Llista d'imatges", image_border:"Vora", image_dimensions:"Dimensions", image_vspace:"Espaiat vertical", image_hspace:"Espaiat horitzontal", image_align:"Alineaci\u00F3", image_align_baseline:"L\u00EDnia base", image_align_top:"Dalt", image_align_middle:"Mig", image_align_bottom:"Baix", image_align_texttop:"A dalt del text", image_align_textbottom:"A baix del text", image_align_left:"Esquerra", image_align_right:"Dreta", link_title:"Insereix/edita enlla\u00E7", link_url:"URL de l'enlla\u00E7", link_target:"Objectiu", link_target_same:"Obre l'enlla\u00E7 a la mateixa finestra", link_target_blank:"Obre l'enlla\u00E7 en una finestra nova", link_titlefield:"T\u00EDtol", link_is_email:"L'URL que has introdu\u00EFt sembla una adre\u00E7a de correu, vols afegir-hi el prefix mailto://?", link_is_external:"L'URL que has introdu\u00EFt sembla un enlla\u00E7 extern, vols afegir-hi el prefix http://?", link_list:"Llista d'enlla\u00E7os" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/tr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/t0000644000175000017500000000411011226234200033632 0ustar frankiefrankietinyMCE.addI18n('tr.openacs_dlg',{ about_title:"TinyMCE Hakk\u0131nda", about_general:"Hakk\u0131nda", about_help:"Yard\u0131m", about_license:"Lisans", about_plugins:"Eklentiler", about_plugin:"Eklenti", about_author:"Yazar", about_version:"S\u00FCr\u00FCm", about_loaded:"Y\u00FCkl\u00FC eklentiler", anchor_title:"\u00C7engel noktas\u0131 ekle/d\u00FCzenle", anchor_name:"\u00C7engel noktas\u0131 ad\u0131", code_title:"HTML Kaynak Edit\u00F6r\u00FC", code_wordwrap:"S\u00F6zc\u00FCk kayd\u0131r", colorpicker_title:"Bir renk se\u00E7", colorpicker_picker_tab:"Se\u00E7ici", colorpicker_picker_title:"Renk se\u00E7ici", colorpicker_palette_tab:"Palet", colorpicker_palette_title:"Palet renkleri", colorpicker_named_tab:"\u0130simli", colorpicker_named_title:"\u0130simli renkler", colorpicker_color:"Renk:", colorpicker_name:"\u0130sim:", charmap_title:"\u00D6zel karakter se\u00E7", image_title:"Resim ekle/d\u00FCzenle", image_src:"Resim URL", image_alt:"Resim tan\u0131m\u0131", image_list:"Resim listesi", image_border:"Kenarl\u0131k", image_dimensions:"Boyutlar", image_vspace:"Dikey bo\u015Fluk", image_hspace:"Yatay bo\u015Fluk", image_align:"Hizalama", image_align_baseline:"Taban \u00E7izgisi", image_align_top:"\u00DCst", image_align_middle:"Orta", image_align_bottom:"Alt", image_align_texttop:"Metin \u00FCstte", image_align_textbottom:"Metin altta", image_align_left:"Sola", image_align_right:"Sa\u011Fa", link_title:"Ba\u011Flant\u0131 ekle/d\u00FCzenle", link_url:"Ba\u011Flant\u0131 URL", link_target:"Hedef", link_target_same:"Ba\u011Flant\u0131y\u0131 ayn\u0131 pencerede a\u00E7", link_target_blank:"Ba\u011Flant\u0131y\u0131 yeni pencerede a\u00E7", link_titlefield:"Ba\u015Fl\u0131k", link_is_email:"Girdi\u011Finiz URL bir e-posta adresi gibi g\u00F6z\u00FCk\u00FCyor, gerekli olan mailto: \u00F6nekinin eklenmesini ister misiniz?", link_is_external:"Girdi\u011Finiz URL d\u0131\u015F bir ba\u011Flant\u0131 gibi g\u00F6z\u00FCk\u00FCyor, gerekli olan http:// \u00F6nekinin eklenmesini ister misiniz?", link_list:"Ba\u011Flant\u0131 listesi" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/nn_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/n0000644000175000017500000000346311226234177033653 0ustar frankiefrankietinyMCE.addI18n('nn.openacs_dlg',{ about_title:"Om TinyMCE", about_general:"Om", about_help:"Hjelp", about_license:"Lisens", about_plugins:"Programtillegg", about_plugin:"Programtillegg", about_author:"Utviklar", about_version:"Versjon", about_loaded:"Lasta programtillegg", anchor_title:"Set inn / endre anker", anchor_name:"Ankernamn", code_title:"HTML-editor", code_wordwrap:"Tekstbryting", colorpicker_title:"Vel ein farge", colorpicker_picker_tab:"Vel farge", colorpicker_picker_title:"Fargeval", colorpicker_palette_tab:"Palett", colorpicker_palette_title:"Palettfargar", colorpicker_named_tab:"Namneval", colorpicker_named_title:"Fargenamn", colorpicker_color:"Farge:", colorpicker_name:"Namn:", charmap_title:"Vel spesialteikn", image_title:"Set inn / endre bilete", image_src:"Bilete-URL", image_alt:"Bileteomtale", image_list:"Liste med bilete", image_border:"Ramme", image_dimensions:"Dimensjonar", image_vspace:"Vertikal avstand", image_hspace:"Horisontal avstand", image_align:"Justering", image_align_baseline:"Botnlinje", image_align_top:"Topp", image_align_middle:"Midtstilt", image_align_bottom:"Botn", image_align_texttop:"Teksttopp", image_align_textbottom:"Tekstbotn", image_align_left:"Venstre", image_align_right:"H\u00F8gre", link_title:"Set inn / endre lenkje", link_url:"Lenkje-URL", link_target:"Vindauge", link_target_same:"Opne i dette vindauget", link_target_blank:"Opne i nytt vindauget", link_titlefield:"Tittel", link_is_email:"Nettadressa du skreiv inn ser ut til \u00E5 vere ein e-postadresse. \u00D8nskjer du \u00E5 leggje til det obligatoriske mailto:-prefikset?", link_is_external:"Nettadressa du skreiv inn ser ut til \u00E5 vere ein ekstern nettadresse. \u00D8nskjer du \u00E5 leggje til det obligatoriske http://-prefikset?", link_list:"Lenkjeliste" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/bg_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/b0000644000175000017500000001174111226234177033635 0ustar frankiefrankietinyMCE.addI18n('bg.openacs_dlg',{ about_title:"\u041E\u0442\u043D\u043E\u0441\u043D\u043E TinyMCE", about_general:"\u041E\u0442\u043D\u043E\u0441\u043D\u043E", about_help:"\u041F\u043E\u043C\u043E\u0449", about_license:"\u041B\u0438\u0446\u0435\u043D\u0437", about_plugins:"\u0414\u043E\u0431\u0430\u0432\u043A\u0438", about_plugin:"\u0414\u043E\u0431\u0430\u0432\u043A\u0430", about_author:"\u0410\u0432\u0442\u043E\u0440", about_version:"\u0412\u0435\u0440\u0441\u0438\u044F", about_loaded:"\u0417\u0430\u0440\u0435\u0434\u0435\u043D\u0438 \u0434\u043E\u0431\u0430\u0432\u043A\u0438", anchor_title:"\u0412\u043C\u044A\u043A\u043D\u0438/\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u0430\u0439 \u043A\u043E\u0442\u0432\u0430", anchor_name:"\u0418\u043C\u0435 \u043D\u0430 \u043A\u043E\u0442\u0432\u0430\u0442\u0430", code_title:"\u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440 \u043D\u0430 HTML", code_wordwrap:"\u041F\u0440\u0435\u043D\u043E\u0441 \u043D\u0430 \u0434\u0443\u043C\u0438", colorpicker_title:"\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0446\u0432\u044F\u0442", colorpicker_picker_tab:"\u0418\u0437\u0431\u043E\u0440", colorpicker_picker_title:"\u0418\u0437\u0431\u043E\u0440 \u043D\u0430 \u0446\u0432\u044F\u0442", colorpicker_palette_tab:"\u041F\u0430\u043B\u0438\u0442\u0440\u0430", colorpicker_palette_title:"\u0426\u0432\u0435\u0442\u043E\u0432\u0430 \u043F\u0430\u043B\u0438\u0442\u0440\u0430", colorpicker_named_tab:"\u0418\u043C\u0435\u043D\u0443\u0432\u0430\u043D\u0438", colorpicker_named_title:"\u0418\u043C\u0435\u043D\u0443\u0432\u0430\u043D\u0438 \u0446\u0432\u0435\u0442\u043E\u0432\u0435", colorpicker_color:"\u0426\u0432\u044F\u0442:", colorpicker_name:"\u0418\u043C\u0435:", charmap_title:"\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0441\u0438\u043C\u0432\u043E\u043B", image_title:"\u0412\u043C\u044A\u043A\u043D\u0438/\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u0430\u0439 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430", image_src:"URL \u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430", image_alt:"\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043D\u0430 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430", image_list:"\u0421\u043F\u0438\u0441\u044A\u043A \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438", image_border:"\u0420\u0430\u043C\u043A\u0430", image_dimensions:"\u0420\u0430\u0437\u043C\u0435\u0440\u0438", image_vspace:"\u0412\u0435\u0440\u0442\u0438\u043A\u0430\u043B\u043D\u043E \u0440\u0430\u0437\u0441\u0442\u043E\u044F\u043D\u0438\u0435", image_hspace:"\u0425\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u043D\u043E \u0440\u0430\u0437\u0441\u0442\u043E\u044F\u043D\u0438\u0435", image_align:"\u041F\u043E\u0434\u0440\u0430\u0432\u043D\u044F\u0432\u0430\u043D\u0435", image_align_baseline:"\u0411\u0430\u0437\u043E\u0432\u0430 \u043B\u0438\u043D\u0438\u044F", image_align_top:"\u0413\u043E\u0440\u0435", image_align_middle:"\u0426\u0435\u043D\u0442\u0440\u0438\u0440\u0430\u043D\u0435", image_align_bottom:"\u0414\u043E\u043B\u0443", image_align_texttop:"\u0422\u0435\u043A\u0441\u0442 \u0433\u043E\u0440\u0435", image_align_textbottom:"\u0422\u0435\u043A\u0441\u0442 \u0434\u043E\u043B\u0443", image_align_left:"\u041B\u044F\u0432\u043E", image_align_right:"\u0414\u044F\u0441\u043D\u043E", link_title:"\u0412\u043C\u044A\u043A\u043D\u0438/\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u0430\u0439 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430", link_url:"URL \u043D\u0430 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430", link_target:"\u0426\u0435\u043B", link_target_same:"\u041E\u0442\u0432\u043E\u0440\u0438 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430\u0442\u0430 \u0432 \u0441\u044A\u0449\u0438\u044F\u0442 \u043F\u0440\u043E\u0437\u043E\u0440\u0435\u0446", link_target_blank:"\u041E\u0442\u0432\u043E\u0440\u0438 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430\u0442\u0430 \u0432 \u043D\u043E\u0432 \u043F\u0440\u043E\u0437\u043E\u0440\u0435\u0446", link_titlefield:"\u0417\u0430\u0433\u043B\u0430\u0432\u0438\u0435", link_is_email:"URL-\u0442\u043E \u043A\u043E\u0435\u0442\u043E \u0432\u044A\u0432\u0435\u0434\u043E\u0445\u0442\u0435 \u0435 email \u0430\u0434\u0440\u0435\u0441, \u0436\u0435\u043B\u0430\u0435\u0442\u0435 \u043B\u0438 \u0434\u0430 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u0435 \u043D\u0443\u0436\u043D\u0438\u044F\u0442 mailto: \u043F\u0440\u0435\u0444\u0438\u043A\u0441?", link_is_external:"URL-\u0442\u043E \u043A\u043E\u0435\u0442\u043E \u0432\u044A\u0432\u0435\u0434\u043E\u0445\u0442\u0435 \u0435 \u0432\u044A\u043D\u0448\u043D\u0430 \u0445\u0438\u043F\u0435\u0440\u0432\u0440\u044A\u0437\u043A\u0430, \u0436\u0435\u043B\u0430\u0435\u0442\u0435 \u043B\u0438 \u0434\u0430 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u0435 \u043D\u0443\u0436\u043D\u0438\u044F\u0442 http:// \u043F\u0440\u0435\u0444\u0438\u043A\u0441?", link_list:"\u0421\u043F\u0438\u0441\u044A\u043A \u043B\u0438\u043D\u043A\u043E\u0432\u0435" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/pl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/p0000644000175000017500000000362611226234200033641 0ustar frankiefrankietinyMCE.addI18n('pl.openacs_dlg',{ about_title:"O TinyMCE", about_general:"O TinyMCE", about_help:"Pomoc", about_license:"Licencja", about_plugins:"Wtyczki", about_plugin:"Wtyczka", about_author:"Autor", about_version:"Wersja", about_loaded:"Za\u0142adowane wtyczki", anchor_title:"Wstaw/Edytuj zakotwiczenie", anchor_name:"Nazwa zakotwiczenia", code_title:"Edytor \u017Ar\u00F3d\u0142a HTML", code_wordwrap:"Zawijanie s\u0142\u00F3w", colorpicker_title:"Wybierz kolor", colorpicker_picker_tab:"Wybieranie", colorpicker_picker_title:"Wybieranie kolor\u00F3w", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Paleta kolor\u00F3w", colorpicker_named_tab:"Nazwane", colorpicker_named_title:"Nazwane kolory", colorpicker_color:"Kolor:", colorpicker_name:"Nazwa:", charmap_title:"Wybierz niestandardowy znak", image_title:"Wstaw/Edytuj obraz", image_src:"URL obrazka", image_alt:"Opis obrazka", image_list:"Lista obrazk\u00F3w", image_border:"Ramka", image_dimensions:"Rozmiary", image_vspace:"Pionowy odst\u0119p", image_hspace:"Poziomy odst\u0119p", image_align:"Wyr\u00F3wnanie", image_align_baseline:"Linia bazowa", image_align_top:"G\u00F3ra", image_align_middle:"\u015Arodek", image_align_bottom:"Dolny", image_align_texttop:"G\u00F3rny tekst", image_align_textbottom:"Dolny tekst", image_align_left:"Lewy", image_align_right:"Prawy", link_title:"Wstaw/edytuj link", link_url:"Link URL", link_target:"Cel", link_target_same:"Otw\u00F3rz link w tym samym oknie", link_target_blank:"Otw\u00F3rz link w nowym oknie", link_titlefield:"Tytu\u0142", link_is_email:"URL kt\u00F3ry otworzy\u0142e\u015B wydaje si\u0119 by\u0107 adresem mailowym, czy chcesz doda\u0107 odpowiedni prefix mailto: ?", link_is_external:"URL kt\u00F3ry otworzy\u0142e\u015B wydaje si\u0119 by\u0107 zewn\u0119trznym linkiem, czy chcesz doda\u0107 wymagany prefix http:// ?", link_list:"Lista link\u00F3w" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/hr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/h0000644000175000017500000000334711226234177033646 0ustar frankiefrankietinyMCE.addI18n('hr.openacs_dlg',{ about_title:"TinyMCE", about_general:"O programu", about_help:"Pomo\u0107", about_license:"Licenca", about_plugins:"Dodaci", about_plugin:"Dodatak", about_author:"Autor", about_version:"Verzija", about_loaded:"Postoje\u0107i dodaci", anchor_title:"Umetni/uredi sidro", anchor_name:"Ime sidra", code_title:"HTML ure\u0111iva\u010D", code_wordwrap:"Omatanje teksta", colorpicker_title:"Izbor boje", colorpicker_picker_tab:"Odabir", colorpicker_picker_title:"Odabir boje", colorpicker_palette_tab:"Paleta", colorpicker_palette_title:"Paleta boja", colorpicker_named_tab:"Imenovano", colorpicker_named_title:"Imenovane boje", colorpicker_color:"Boja:", colorpicker_name:"Naziv:", charmap_title:"Odaberite znak", image_title:"Umetni/uredi sliku", image_src:"URL slike", image_alt:"Opis slike", image_list:"Lista slika", image_border:"Obrub", image_dimensions:"Dimenzije", image_vspace:"Okomiti razmak", image_hspace:"Vodoravni razmak", image_align:"Poravnavanje", image_align_baseline:"Osnovna linija", image_align_top:"Vrh", image_align_middle:"Sredina", image_align_bottom:"Dno", image_align_texttop:"Vrh teksta", image_align_textbottom:"Dno teksta", image_align_left:"Lijevo", image_align_right:"Desno", link_title:"Umetni/uredi poveznicu", link_url:"URL poveznice", link_target:"Meta", link_target_same:"Otvori poveznicu u istom prozoru", link_target_blank:"Otvori poveznicu u novom prozoru", link_titlefield:"Naslov", link_is_email:"URL koji ste unijeli izgleda kao e-mail adresa, \u017Eelite li dodati potrebni mailto: prefiks?", link_is_external:"URL koji ste unijeli izgleda kao vanjska poveznica, \u017Eelite li dodati potrebni http:// prefiks?", link_list:"Lista poveznica" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/is_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/i0000644000175000017500000000363611226234177033650 0ustar frankiefrankietinyMCE.addI18n('is.openacs_dlg',{ about_title:"Um TinyMCE", about_general:"Um", about_help:"Hj\u00E1lp", about_license:"Leyfi", about_plugins:"Vi\u00F0b\u00E6tur", about_plugin:"Vi\u00F0b\u00E6tur", about_author:"H\u00F6fundur", about_version:"\u00DAtg\u00E1fa", about_loaded:"Vi\u00F0b\u00E6tur \u00ED notkun", anchor_title:"Setja inn/breyta akkeri", anchor_name:"Nafn akkeris", code_title:"HTML k\u00F3\u00F0a ritill", code_wordwrap:"Word wrap", colorpicker_title:"Veldu lit", colorpicker_picker_tab:"Veljari", colorpicker_picker_title:"Litaveljari", colorpicker_palette_tab:"Litaspjald", colorpicker_palette_title:"Litir litaspjalds", colorpicker_named_tab:"Nefndir", colorpicker_named_title:"Nefndir litir", colorpicker_color:"Litur:", colorpicker_name:"Nafn:", charmap_title:"Veldu t\u00E1kn", image_title:"Setja inn/breyta mynd", image_src:"Sl\u00F3\u00F0 myndar", image_alt:"L\u00FDsing myndar", image_list:"Myndalisti", image_border:"Rammi", image_dimensions:"St\u00E6r\u00F0ir", image_vspace:"L\u00F3\u00F0r\u00E9tt loftun", image_hspace:"L\u00E1r\u00E9tt loftun", image_align:"J\u00F6fnun", image_align_baseline:"Baseline", image_align_top:"Toppur", image_align_middle:"Mi\u00F0ja", image_align_bottom:"Botn", image_align_texttop:"Toppur texta", image_align_textbottom:"Botn texta", image_align_left:"Vinstri", image_align_right:"H\u00E6gri", link_title:"Setja inn/breyta hlekk", link_url:"Sl\u00F3\u00F0 hlekks", link_target:"Target", link_target_same:"Opna hlekk \u00ED sama glugga", link_target_blank:"Opna hlekk \u00ED n\u00FDjum glugga", link_titlefield:"Titill", link_is_email:"Sl\u00F3\u00F0in sem \u00FE\u00FA sl\u00F3st inn vir\u00F0ist vera netfang, viltu b\u00E6ta vi\u00F0 mailto: forskeytinu?", link_is_external:"Sl\u00F3\u00F0in sem \u00FE\u00FA sl\u00F3st inn vir\u00F0ist vera utana\u00F0komandi, viltu b\u00E6ta vi\u00F0 http:// forskeytinu?", link_list:"Hlekkjalisti" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/uk_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/u0000644000175000017500000001206311226234200033641 0ustar frankiefrankietinyMCE.addI18n('uk.openacs_dlg',{ about_title:"\u041F\u0440\u043E \u043F\u0440\u043E\u0434\u0443\u043A\u0442 TinyMCE", about_general:"\u041F\u0440\u043E \u043F\u0440\u043E\u0434\u0443\u043A\u0442...", about_help:"\u0414\u043E\u043F\u043E\u043C\u043E\u0433\u0430", about_license:"\u041B\u0456\u0446\u0435\u043D\u0437\u0456\u044F", about_plugins:"\u041F\u043B\u0430\u0433\u0456\u043D\u0438", about_plugin:"\u041F\u043B\u0430\u0433\u0456\u043D", about_author:"\u0410\u0432\u0442\u043E\u0440", about_version:"\u0412\u0435\u0440\u0441\u0456\u044F", about_loaded:"\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u0456 \u043F\u043B\u0430\u0433\u0456\u043D\u0438", anchor_title:"\u0414\u043E\u0434\u0430\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u044F\u043A\u0456\u0440", anchor_name:"\u041D\u0430\u0437\u0432\u0430 \u044F\u043A\u043E\u0440\u044F", code_title:"\u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440 HTML \u043A\u043E\u0434\u0443", code_wordwrap:"\u041F\u0435\u0440\u0435\u043D\u043E\u0441\u0438\u0442\u0438 \u0441\u043B\u043E\u0432\u0430", colorpicker_title:"\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u043A\u043E\u043B\u0456\u0440", colorpicker_picker_tab:"\u041F\u0456\u043F\u0435\u0442\u043A\u0430", colorpicker_picker_title:"\u041F\u0456\u043F\u0435\u0442\u043A\u0430 \u043A\u043E\u043B\u044C\u043E\u0440\u0443", colorpicker_palette_tab:"\u041F\u0430\u043B\u0456\u0442\u0440\u0430", colorpicker_palette_title:"\u041F\u0430\u043B\u0456\u0442\u0440\u0430 \u043A\u043E\u043B\u044C\u043E\u0440\u0456\u0432", colorpicker_named_tab:"\u0417\u0430 \u043D\u0430\u0437\u0432\u043E\u044E", colorpicker_named_title:"\u0417\u0430 \u043D\u0430\u0437\u0432\u043E\u044E", colorpicker_color:"\u041A\u043E\u043B\u0456\u0440:", colorpicker_name:"\u041D\u0430\u0439\u043C\u0435\u043D\u0443\u0432\u0430\u043D\u043D\u044F:", charmap_title:"\u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0434\u043E\u0432\u0456\u043B\u044C\u043D\u0438\u0439 \u0441\u0438\u043C\u0432\u043E\u043B", image_title:"\u0414\u043E\u0434\u0430\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u043D\u044F", image_src:"\u0410\u0434\u0440\u0435\u0441\u0430", image_alt:"\u041E\u043F\u0438\u0441", image_list:"\u0421\u043F\u0438\u0441\u043E\u043A \u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u044C", image_border:"\u0413\u0440\u0430\u043D\u0438\u0446\u044F", image_dimensions:"\u0420\u043E\u0437\u043C\u0456\u0440\u0438", image_vspace:"\u0412\u0435\u0440\u0442. \u0432\u0456\u0434\u0441\u0442\u0443\u043F", image_hspace:"\u0413\u043E\u0440\u0438\u0437. \u0432\u0456\u0434\u0441\u0442\u0443\u043F", image_align:"\u0412\u0438\u0440\u0456\u0432\u043D\u044E\u0432\u0430\u043D\u043D\u044F", image_align_baseline:"\u041F\u043E \u0431\u0430\u0437\u043E\u0432\u0456\u0439 \u043B\u0438\u043D\u0456\u0457", image_align_top:"\u041F\u043E \u0432\u0435\u0440\u0445\u043D\u044C\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", image_align_middle:"\u041F\u043E \u0446\u0435\u043D\u0442\u0440\u0443", image_align_bottom:"\u041F\u043E \u043D\u0438\u0436\u043D\u044C\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", image_align_texttop:"\u041F\u043E \u0432\u0435\u0440\u0445\u043D\u044C\u043E\u043C\u0443 \u043A\u0440\u0430\u044E \u0442\u0435\u043A\u0441\u0442\u0443", image_align_textbottom:"\u041F\u043E \u043D\u0438\u0436\u043D\u044C\u043E\u043C\u0443 \u043A\u0440\u0430\u044E \u0442\u0435\u043A\u0441\u0442\u0443", image_align_left:"\u041F\u043E \u043B\u0456\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", image_align_right:"\u041F\u043E \u043F\u0440\u0430\u0432\u043E\u043C\u0443 \u043A\u0440\u0430\u044E", link_title:"\u0414\u043E\u0434\u0430\u0442\u0438/\u0437\u043C\u0456\u043D\u0438\u0442\u0438 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F", link_url:"\u0410\u0434\u0440\u0435\u0441\u0430 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F", link_target:"\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0432...", link_target_same:"\u0446\u044C\u043E\u043C\u0443 \u0436\u0435 \u0432\u0456\u043A\u043D\u0456", link_target_blank:"\u043D\u043E\u0432\u043E\u043C\u0443 \u0432\u0456\u043A\u043D\u0456", link_titlefield:"\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A", link_is_email:"\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0439 URL \u0441\u0445\u043E\u0436\u0438\u0439 \u043D\u0430 email \u0430\u0434\u0440\u0435\u0441\u0443, \u0432\u0438 \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0434\u043E\u0434\u0430\u0442\u0438 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u0438\u0439 \u043F\u0440\u0435\u0444\u0456\u043A\u0441 mailto:?", link_is_external:"\u0412\u0432\u0435\u0434\u0435\u043D\u0438\u0439 URL \u0441\u0445\u043E\u0436\u0438\u0439 \u043D\u0430 \u0437\u043E\u0432\u043D\u0456\u0448\u043D\u0454 \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u043D\u044F, \u0432\u0438 \u0431\u0430\u0436\u0430\u0454\u0442\u0435 \u0434\u043E\u0434\u0430\u0442\u0438 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u0438\u0439 \u043F\u0440\u0435\u0444\u0456\u043A\u0441 http://?", link_list:"\u0421\u043F\u0438\u0441\u043E\u043A \u043F\u043E\u0441\u0438\u043B\u0430\u043D\u044C" });././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/zh_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/langs/z0000644000175000017500000000440611226234200033650 0ustar frankiefrankietinyMCE.addI18n('zh.openacs_dlg',{ about_title:"\u5173\u4E8ETinyMCE", about_general:"\u5173\u4E8E", about_help:"\u8BF4\u660E", about_license:"\u6388\u6743", about_plugins:"\u6240\u6709\u63D2\u4EF6", about_plugin:"\u63D2\u4EF6", about_author:"\u4F5C\u8005", about_version:"\u7248\u672C", about_loaded:"\u5DF2\u52A0\u8F7D\u7684\u63D2\u4EF6", anchor_title:"\u63D2\u5165/\u7F16\u8F91\u951A\u70B9", anchor_name:"\u951A\u70B9\u540D\u79F0", code_title:"HTML\u6E90\u4EE3\u7801\u7F16\u8F91\u5668", code_wordwrap:"\u81EA\u52A8\u6362\u884C", colorpicker_title:"\u9009\u62E9\u989C\u8272", colorpicker_picker_tab:"\u62FE\u8272\u5668", colorpicker_picker_title:"\u62FE\u8272\u5668", colorpicker_palette_tab:"\u5B89\u5168\u8272", colorpicker_palette_title:"\u5B89\u5168\u8272", colorpicker_named_tab:"\u547D\u540D\u8272", colorpicker_named_title:"\u547D\u540D\u8272", colorpicker_color:"\u989C\u8272:", colorpicker_name:"\u540D\u79F0:", charmap_title:"\u63D2\u5165\u7279\u6B8A\u5B57\u7B26", image_title:"\u63D2\u5165/\u7F16\u8F91\u56FE\u50CF", image_src:"\u56FE\u50CF\u5730\u5740", image_alt:"\u56FE\u50CF\u8BF4\u660E", image_list:"\u56FE\u50CF\u5217\u8868", image_border:"\u8FB9\u6846", image_dimensions:"\u5C3A\u5BF8", image_vspace:"\u5782\u76F4\u95F4\u8DDD", image_hspace:"\u6C34\u5E73\u95F4\u8DDD", image_align:"\u5BF9\u9F50\u65B9\u5F0F", image_align_baseline:"\u57FA\u7EBF", image_align_top:"\u9876\u7AEF", image_align_middle:"\u5C45\u4E2D", image_align_bottom:"\u5E95\u90E8", image_align_texttop:"\u6587\u5B57\u4E0A\u65B9", image_align_textbottom:"\u6587\u5B57\u4E0B\u65B9", image_align_left:"\u5C45\u5DE6", image_align_right:"\u5C45\u53F3", link_title:"\u63D2\u5165/\u7F16\u8F91\u94FE\u63A5", link_url:"\u94FE\u63A5\u5730\u5740", link_target:"\u76EE\u6807", link_target_same:"\u540C\u4E00\u7A97\u53E3", link_target_blank:"\u65B0\u7A97\u53E3", link_titlefield:"\u6807\u9898", link_is_email:"\u60A8\u8F93\u5165\u7684\u662F\u4E00\u4E2A\u7535\u5B50\u90AE\u4EF6\u5730\u5740\uFF0C\u662F\u5426\u9700\u8981\u5728\u5730\u5740\u5F00\u5934\u52A0\u5165mailto:\uFF1F", link_is_external:"\u60A8\u8F93\u5165\u7684\u662F\u4E00\u4E2A\u5916\u90E8\u94FE\u63A5\uFF0C\u662F\u5426\u9700\u8981\u5728\u7F51\u5740\u5F00\u5934\u52A0\u5165http://\uFF1F", link_list:"\u94FE\u63A5\u5217\u8868" });openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/0000755000175000017500000000000011724401447033507 5ustar frankiefrankie././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000755000175000017500000000000011575225664033677 5ustar frankiefrankie././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/img/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000755000175000017500000000000011724401447033666 5ustar frankiefrankie././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/img/button_bg_black.pngopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000000723011201070601033652 0ustar frankiefrankie‰PNG  IHDRXBÓØÉ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-ÛgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF³IDATxÚì[ÏkA~ö^J±¯)4P…R"Ƴ^½ˆXJЂø§ˆP5‡€í±ä"ŠfÅ´„jQ±ˆEVh1ô¦XëÌfÇCŠM&“dfw¾M6¼{˜ôÍ›÷¾~y3³q^½}/`•õ2UÖŸÿOÏ\ ;·ç¨q_omk回wqå›kº{oAÈ5ºAÁ—¦g2À+qQù¦'Æ­Ô,›+DI¸^—Çu+qQùm¾y§í;5y¶­&U0£˜‡Ì×4¶ì¯šï"&€-­ƒÌ×4¶ì¯šïŠ ˆ`[ë ó5-û«æ3ƒÑ æ îÁÈ]±û#ó5-û«æ3ƒñ 11XXs)s¾ío¥ò k9êÄ—kRÕ˜"„{Z–·õ¯""A¥ò†TüF—µÍbëÇï]cÊ÷B=Í&ÃZsüU¯BDD«^¥ëÚabëÄשѵu…í}u®Câ¬?ù®§f}“lø” jÀØÑpP¾†'(€£ÅVjr6¾ñ ü¶EÄA©*3ƒã`0÷`pæa§EnØÑ™Á~âì\|ÐΠg7#2øçTûÝ@ì/õ`°RU&ªɠo³fdp%Äþ¢î¢F|»šÁG(Í5Ê*ÍÙY_ªCTWaQ-hÕ©T•·É‰Öë¨xz£í3››œøòPŸÎWe>EX9EøßE$—ÁƒtŠ`£ìÀHã^W2ƒmàà×™Á}bðî·äü÷``VªÊù½ $× ¦çy#;‡·pëïFÊO¥*;¨ß*›þVX×P¿UF™«­ÒšZUW8müþ@t´FÖQjM,¬ª«c: 8RÕ0Ó`[gÕ>œ Vˆ3˜Ì=˜[·nÃÊà#U9„êÛKQâLGõe[ÙäDµ@Îèì±ê;°-BÔDàÖl¢ú2ƒ‡ö‘$ó)‚ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-ÛgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFPLTEÿÿÿÛΙÊÜñ¯Ä߃”ÓĔĄ”۷࠼䕯ՠ»â–¯Ô¸ËçØäõàéöV}±Ÿ»âŸ»á ¼â »ÞÁÔî¾Ñê½Ðé¼ÏèÃÖïÂÕîÁÔí¾ÐéÁÓìÅ×ðÊÜõÐá÷ÍÝòÑàôÕãöÚçùÙæ÷×äõÝêûÜéúßëûÝéùãíûßéöèñýäíùãìøœ¹ÜŸ»Þ ¼ÞŸ»Ý´Éâ¾Ôî¾Óí½Ñê¾ÒêÉÝöÄ×ïÂÕíÈÛóÅØðËÞöÆÙðÅØïÍßöÍÞòÎßóÖåøÕä÷ÒáôÖäöÏÝîãïþâîýáíüáìúäïüËÞôÈÛñÇÚðËÞóÉÜñËÝòÊÛîÒâôÑáóÐßïÎÝíÍÜì×äóÚçõäðþßëøÈÛîÊÜïÑâôÕãñÞéôÈÛíÑáðÐàïÏßîêòùÿÿùÿÿûÿÿýÿüÕÿüÚÿúÅÿüÝÿüâÿþõÿùÌÿüåÿýíÿþ÷ÿõ·ÿøËþöÊÿüêþõÉþõÊýêýêžüéûéÿï§þõÐÿ÷ÔýõÓþùåÿûéýùèÿûëÿüïÿüðÿýôÿä€þäþãÿè–ýòÊÿöÓþõÓÿûìùé¶ûì»ûì¼üïÃûîÃýõÚÿøâÿùæþùèÿûîÿÐIÿÒMÿÑMÿÒNÿÑNÿÓVÿÕ`þÕdÿÖeÿÖfÿ×jÿÚvýßÿâýáÿâ”ýá”ýâ”ÿä˜ÿåœþåŸþå ÿç¥ùä§úå¨ÿê²úè²ûê·úé¶ÿî»ÿî¿ÿïÁÿïÃÿðÇÿñÊüïÊÿòÏÿóÓüñÐÿôÖýóÕÿöÝÿ÷ßÿ÷áÿüóÿÙuÿÙxÿÚ|ÿÜÿ܃ýÙƒþÚ„ýÚ„ÿß‹þßÿá”ÿè«ÿë¸ÿñÌÿôÙÿõÛÿûñÿÖyÿÕyýÔxÿÖzýÙ„ÿùëþÉuüÇtþÉvüÈuü»_ý¼`þÃhþÃjýÂiÿ·þ͆ÿψû´Uû´Vü¶WüµWý»`ÿÔ˜ýبÿڪʴ—É´˜ÿÙ©úÛ¶ùڵʴ˜É³˜ìÓµëÓµúÚµÿÿÿ¿õ8DtRNSÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿS÷%æIDATxÚ”×\gÀñ®§-BZ}X¸]ÉIum³Xn®3A¢Òr\Á_c“æoœzY ‚$27J®`™2“(Õdªu•à¯ÕÁ™ž"àâ)@´l\îò¤¹óº¯<É+¼y^w÷}±C§×ߪÏÕé²u¹ú\}®>[§Óér+++ë>úâ½*ôí+Ò’¾Ýq‹‘¢ŽR÷[)Š¢(im êêêˆ ø¹»aøP)ø®©ûÄ·š†††Ûr*++÷dÀ÷Ƀá÷C¥à×Ô×××$_õ5âZoÈ©«¬ËÉ€¹Áð RpqM}M}="ÂÒï@sêê*ÿüqþ #$‰ ‚$‰$‰ ‰à{ꔎâˆÜ0ü¨Ü„ y„$I„DHAHAH<«ÖfÛ•Dî“0ü&¨`AªIGŽ $‰ïj´Õî΀ß%w†ß ÃGÈjAD•ãž,›ÒŽß!w§6\ŒPƒÍÇqƒÅQŠâ8¾w—íXm&Œã8Oûã(***JÁŸº Û‡a†a‡°×b‡°}û0 Û›ekTØ1†aM€& {† i]XXXíØ€â¸Gq5 ¸Á`@qºw—­Ñ–yÆM ©  à.¶X,ЋÅbnÇ (Š¢8ŽæpE (¾7«±öXV\ZZZZÚTZZZšvƒF£‘6F£‚Mf“ɼßd6•›÷›ËËMfSù~,ËÖh{eœ/÷j¦ `Ø”o2ç›Ìærs¹Ùd2å›Ì¦C»km¶Ìï—{# ¿ ‚͇Íe‡ËÊÊÌÉWY™¹ Û­x¹•ÉÞ\Uu¸ª*¹T_oÏ¡ŒTæ³ârï…á7@AÍj„D!«„$«ÅÛïž=¥¿N.mÇw@A;®°TTX**,– Ëí‹År»Å‚ï±­™¡wË¥íøCPÐŽ­”ÕJQGï§(+u”¢(«ÕJ™rŒJ;~½Ü{`øÃPÐh*....>P,¾—£9ŠGq§Ão…JÁAä ‚ ˆ¢„8HD AX)Š¢2à·¥Ò¦z}®N¯ËÍÖé³õ¹¹·êuÙÙzþEŲSAßîL+un·»ßýp¿Ûíîïw»¿îv÷»ûÝÊðg¾"O韆JÁî~ãa¦·½—ée†a˜v†Q†›;“57§Á_”ƒà~ÆÓÎx<íž^¦—igÆãa<ø´Ô7aøÁ/È=˜‚n9~ü¸½Ån·Ûi{K Ýb··´Ø•á©SRSiðçä ØÓ÷hß =Ú×§ wº¥:ÓàÏÊApo0ôH( ƒƒÁ`( C!øq©nþ¼\3´ãP( …‚É5 …B¡ 2Üñ˜Ô©4ø«rÜ76666v^\ÏKŸUàI©ohÃOz½¬×ëõzY/ëeY/Ëz½gX•£‡„ÃÏÀðT[€¶¶¶©üC–É3,ëõ²^/˲¬ ÜÓ:¾ Ã==4€îéééHÁVÖ¼¬W¤½*ðäøø8 èñññ4øÊôô4 èéééé+)ØÇžIñX–õªîøÒÄÄÄ=111ñ—4xfff†ž™™™™àÑáá³g‡‡‡Ï?1,¥ _¾ u) þ\:<œ?qV ¾ø3©I>õ;¹S)xŒ›ç¸ùyŽãþÊqÇq ó œ2üì/¤~­ ‡æææf#³ÑÙH4™›D¢‘¹HD¾pQê Ÿþ½Üéùƒ¼$Wexü©ÇÓ.7Ÿt¹õ|¿?à÷@Àðûü>¿__–ê‡áÎËuBpߨØ9q9wntttT~úR²+W`ø¹§äžƒFÓq»½…¶ÓöÚÞ"=–÷*Ã}YêÞ´[j'4¥‘—GˆåååD^ž2|0•ö0M$ÿI$þ›H$ÄO/$‰Ä /gJ+·ãzFÿ»~]P™Òò¹[ÞÞÜÜÚÞÜÜÞÜÚÞÞÞÞÞÜÜÜÚÚR›™d'NhÃëëë×Ö×ׯm\Û¸¶¾±±¾¾±±¡Mê1møßJ©ÀSß’šÔ†×V×ÖV×Öþ±º*~X]][[U;åAþ]mx‘çy~ñ*Ïó‹<ÏÿçyžçÕào'ûί´áx\AˆÿS„ç!âBüy•ÑôS©_Þ B\„xêG>/õsm8 Š‹ Äã‚ ÄUàÎOjÃËKËKKËKËKËÉþµ¼´¬¶ã@ß[Y‰ÅVbÅb±••ØJ,¶²SùãMÒ€ôiÃWyžçyq]\äyþ*Uíª¸4444D ýHçÜÇq Ü<7Ï-Ìs§_þžÔ¨6‹D#s‘ÙHdv6D¢³ÑhT¾ø}©§´á‘´Ä‰7¢?û©?iÀ?à |âÌóû}¿? _ø­ÔO´aW«Ëéhu¸\.§Ãálu8]®V‡Êå6.ù?kÃN—Ãår9.‡Óépº\N—ÓáTÙqøRᛀN§ÓÙêr9œ.G«Ëåt:Tá§“}tbB¾ådWwW×É®®®“Ý'»»»»»»ººTà‡¾$u¯6LDI AäD‰øo4‘G”/gJ+÷Òâ6rÍæ>wIEND®B`‚././@LongLink0000000000000000000000000000020100000000000011556 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/img/button_bg_silver.pngopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000001235611201070601033657 0ustar frankiefrankie‰PNG  IHDRXBÓØÉ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-ÛgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF IDATxÚì\MŒGþ^uÏÎîÚØ;1`„"$NÉ!LDh57.Ì™S’Hœ|AÎæ N$á7GòóŽŽ1(↰‚wv#нò¬I´ÛÕ3SCuuWõôlW·§Ömä’z§»ºúuÕׯÞoÕÒíÛ·Y)…U—ápH“É„Íõ`0 UнsçŽw‡Ã¡÷;G£ !ЋÚwp ²³³Ã=Êff¬àhZ¼èfýk<Æ Ýx2™¬œ{ƒB•&ým:kÒöj'ž6Ïjñ£Àó´<øYøàÁƒ¯ÿŠÏkæç,ø„%fæ%À’²]SWB~fnÔ—¦´«1x€“$G„²? å¯ 0d€&LGˆ².0˜©ø$à$Itÿ˜ðáï/Üóí·ÁÌ }8NŽõxÁøýû,Ò~ë-°³' )%¤”H¥„L$R"M$¤L!“I’ •Iv¤‰„LSýL’@&I’"M$2A’&RXšþ¤7¶·{7¶·‘Hýþ¤ER)!e‚4YB;ÍÆœaå§äØp+kÆÌ¦ 3âœC ‹31qçÜÊ9SÙÔ"fìîîæ@ÜØÞÆî‰ÜFD˜1Æ ´w šÌÞCŒ)›Kù'€ÌÃD¹˜é·“%Hdƒ%²„JØBTˆ"°7ãÆö6öÆc-Ì}jGÛºÀ8£=Þ;÷šÐ…ˆ–P/=L`‰XQ¡Š÷SPDÖË´¶ØÛß Qè j§ž„%&!ìïïCœ”½€ &ô¸Œ–«?møõÈRncs`阬OK¿¥`°¨zÜze3+BDàLw.ÃÆ– VƒÅæáÅ„ÑÒw N 0"WÜÿ8"¡M/ÒSŸ¹Ð€™2¹¬?¡± &†`ÃÓœÿ‚€._v^T¾n[¢¨˜q–µ0!몫˜›|¼Hä&`N²k*„@ ö£æ`cëRµfE•Lã%¾`(/ 4ÁËýж]X— °(Þö‰B¾28Z2ÑZháS°# Vß‹zÚ¥×4SrËŸf¶j¨ŠMØ%—.] °­_ÙµÈà¨Êò<¯³Æ|ñâE?€}v¥„ìoÚ"é)„ÀÖÖÖÊ“ž£Ñè<€Ã&}h@ûKg›ˆ¥TmÒS„È(šƒÁ€Ì± ºÃáðqÓ>4(g›Ðö¥‡C`VŠY1Hho‰çJŸ[÷´‹LÙ‹";7ϱbÐÚ׃Mãáp à´¶ÝÝOþÖ‚öΨ?—g—9:ÆìnöP§Tè³9çUdB•Š MJAÍ¿N¿2'€šÖÌá®þàÕvôçÿñ4È¿éÇÁ¬¤ÀGN5JSP®š"‡sm΂À³‡º2 ƒk¦ç\b­…1¬L´õ‰¦E<;*<7…<¨AdùŒBdí("ð¼°áòqt4 ”ßàZœæ«u•Y~•ÊÖÁŒe‘h#ÂsOÚ5]-ÀDO¿3CU0Ÿ‰ƒ*f*te Î~M;ˆBÃʼ¨MÄ}¨C¿¶b¶PU•UŽ™‹dŸ°‚9\¡hG¥vž (€5µÍZrðô¿ž¬éÙL¥‡àéã…øåÜX®g P.}Œvq¬¦Ïý>DJ}ù)¢ÃÛ'‡¡x™s^:7'ÌÀ·~¨Ëï®ýv‘Ûnþâ\aÅÄ/4W ©×~³¹Hû—GÅEßÏŠ*ÏôU||SoR%U± *µåМSпyýŠ €sÝF Ì9䤚vvr¢Ûú êUƒÆ&OÇ®¦S0Ñ`z¨³­$€ã£ˆ›×¯ÇGŽVÊ x<ÖÇþG.íýŠ{Ǻ­Wܢ̊eN¥% —9ý´D«Ì‡ÌŽã$7qëÛ‚Œ¨8öoeàÞrëÌŽ˜£3 Þ7KÀ¶ll9Ò§XÔ  ’ O*êÚ\¦óùŸëš(¹²ÍË­e(Y6Ñ =äÁAmˆ¾[€§¼ŽX]‚:Æà8&&Á:º,D'²¤©IW)æpëb•D®7jÔK'Ì4êÖÎÞ=3Øpr”­ƒ ‚âb¦pÖ®ðÞ¬5¡õO½¸ŒEÜ¢ˆÖýÛ–JeV™ˆ€ÞF­a´LÇÑ}GOYDP»µSþAOQSï,õ!LŒŠÍz-®ø~ʈ+Œ¬NÅŠ¨˜!Z@L 8Ø`௽ >úç ,òo¾ÈÄúËèÂ+ž¢F«GçÚÍ &@lø·õr•/¼>ú Ð%Ÿã‘“²ë–ɧíækáð=÷2@õ\v÷î=\}½¡«Lxñ'«Ur£Ñ( # ‡ÃÕSÕYå`eôñ'Oô|U†9>/ïW+­ðU«/[¬àápø8 C4Û×܈ƒ¿óÒ·WãÊ¥Çàó?x3[Àì ^Düõ~7ìàó}Xkm³-y2®XQI5¦ ó)¹Ïœ&±ºÔàûß{©÷ø«ÜcÓÑ5WÎu./ò¬²ÒÞ)";4±ª‰d©‡ ¨KÂbL' >I“)ž¦Cªx^¿ð„ļ³|äyœsý%1Pn¿,¦ÌÁóú-Z*šv"«éÄ 1ŒWFÎrzkÁ»H¥Â~.†çu{Ô¤¦áàƒ}Ì+8O¥' ?Y×)P œ—8ºàì ›iÁ³ãúV½Žìtªjš³{ŸH8Aø2¸ú7´”8òÕi7.s®³¢¼ò¨;l!ôþpíÖ¢­}ó§ê“‹?.¼Ö€ûH¥(¦ÎÞ]YO2Kú³Õ?*9 *"r0¯_Áµwÿí\ãèTÔ_õ7µ ˆu}˜sêof¿ëù5}ßœS´nÎ7õuHKbz¨3Ôî½ãf~ï½SÜCÜ µs Ší„Ë’›öÞ4{÷.9aù€ÿ‰ ¬hÚgïáæõ_Ÿ½çÖ‹ŽÌgD[» ùLbF”åî(û5ù8ÛÄAÀ« J«nîÿn¡Ž©|‰†÷Îæ Kãç«,+VM*!ßU©Ìâá蔆Ãé"À•žÜZWDĆ£:–ýž¬nNÓU–@ä±_…ºpÔw,<7—ÅÔ’Fz*ry®iŠƒ§€8㡾ûÝXõ7rùJ0û[´²š±«øÜ(¦n3·²H"« j s D›ÏÌêuÍ­œÉT²l‘™Èv–Cå»îmÆe üV„Gb2êÃJ*¯bÏ9¹´O¾¿Ã¿ÌÀñÉ"‚6¿ÛG#Ž.ÿü¯_CÀu‡ŒØÉ¼±³eaþiÜϽ :SÿŸOï~šâêëX'ßX-ÕµHyê2úøïx–ÊÿŸ™ µÿ¢»šIEND®B`‚././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/dialog.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000001276011201070601033656 0ustar frankiefrankie/* Generic */ body { font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; scrollbar-3dlight-color:#F0F0EE; scrollbar-arrow-color:#676662; scrollbar-base-color:#F0F0EE; scrollbar-darkshadow-color:#DDDDDD; scrollbar-face-color:#E0E0DD; scrollbar-highlight-color:#F0F0EE; scrollbar-shadow-color:#F0F0EE; scrollbar-track-color:#F5F5F5; background:#F0F0EE; padding:0; margin:8px 8px 0 8px; } html {background:#F0F0EE;} td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} textarea {resize:none;outline:none;} a:link, a:visited {color:black;} a:hover {color:#2B6FB6;} .nowrap {white-space: nowrap} /* Forms */ fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} legend {color:#2B6FB6; font-weight:bold;} label.msg {display:none;} label.invalid {color:#EE0000; display:inline;} input.invalid {border:1px solid #EE0000;} input {background:#FFF; border:1px solid #CCC;} input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} input, select, textarea {border:1px solid #808080;} input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} .input_noborder {border:0;} /* Buttons */ #insert, #cancel, input.button, .updateButton { border:0; margin:0; padding:0; font-weight:bold; width:94px; height:26px; background:url(../default/img/buttons.png) 0 -26px; cursor:pointer; padding-bottom:2px; } #insert {background:url(../default/img/buttons.png) 0 -52px;} #cancel {background:url(../default/img/buttons.png) 0 0;} /* Browse */ a.pickcolor, a.browse {text-decoration:none} a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;} .mceOldBoxModel a.browse span {width:22px; height:20px;} a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;} a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} a.browse:hover span.disabled {border:1px solid white; background-color:transparent;} a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;} .mceOldBoxModel a.pickcolor span {width:21px; height:17px;} a.pickcolor:hover span {background-color:#B2BBD0;} a.pickcolor:hover span.disabled {} /* Charmap */ table.charmap {border:1px solid #AAA; text-align:center} td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;} #charmap a {display:block; color:#000; text-decoration:none; border:0} #charmap a:hover {background:#CCC;color:#2B6FB6} #charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center} #charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center} /* Source */ .wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;} .mceActionPanel {margin-top:5px;} /* Tabs classes */ .tabs {width:100%; height:18px; line-height:normal; background:url(../default/img/tabs.gif) repeat-x 0 -72px;} .tabs ul {margin:0; padding:0; list-style:none;} .tabs li {float:left; background:url(../default/img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;} .tabs li.current {background:url(../default/img/tabs.gif) no-repeat 0 -18px; margin-right:2px;} .tabs span {float:left; display:block; background:url(../default/img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;} .tabs .current span {background:url(../default/img/tabs.gif) no-repeat right -54px;} .tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} .tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} /* Panels */ .panel_wrapper div.panel {display:none;} .panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} .panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;} /* Columns */ .column {float:left;} .properties {width:100%;} .properties .column1 {} .properties .column2 {text-align:left;} /* Titles */ h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} h3 {font-size:14px;} .title {font-size:12px; font-weight:bold; color:#2B6FB6;} /* Dialog specific */ #link .panel_wrapper, #link div.current {height:125px;} #image .panel_wrapper, #image div.current {height:200px;} #plugintable thead {font-weight:bold; background:#DDD;} #plugintable, #about #plugintable td {border:1px solid #919B9C;} #plugintable {width:96%; margin-top:10px;} #pluginscontainer {height:290px; overflow:auto;} #colorpicker #preview {float:right; width:50px; height:14px;line-height:1px; border:1px solid black; margin-left:5px;} #colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;} #colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;} #colorpicker #light div {overflow:hidden;} #colorpicker #previewblock {float:right; padding-left:10px; height:20px;} #colorpicker .panel_wrapper div.current {height:175px;} #colorpicker #namedcolors {width:150px;} #colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} #colorpicker #colornamecontainer {margin-top:5px;} ././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/ui_silver.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000000146311201070601033654 0ustar frankiefrankie/* Silver */ .o2k7SkinSilver .mceToolbar .mceToolbarStart span, .o2k7SkinSilver .mceButton, .o2k7SkinSilver .mceSplitButton, .o2k7SkinSilver .mceSeparator, .o2k7SkinSilver .mceSplitButton a.mceOpen, .o2k7SkinSilver .mceListBox a.mceOpen {background-image:url(img/button_bg_silver.png)} .o2k7SkinSilver table, .o2k7SkinSilver .mceMenuItemTitle a {background:#eee} .o2k7SkinSilver .mceListBox .mceText {background:#FFF} .o2k7SkinSilver .mceExternalToolbar, .o2k7SkinSilver .mceListBox .mceText, .o2k7SkinSilver div.mceMenu, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceFirst td, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceLast td, .o2k7SkinSilver .mceIframeContainer {border-color: #bbb} ././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/content.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000000246111201070601033653 0ustar frankiefrankiebody, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;} body {background:#FFF;} body.mceForceColors {background:#FFF; color:#000;} h1 {font-size: 2em} h2 {font-size: 1.5em} h3 {font-size: 1.17em} h4 {font-size: 1em} h5 {font-size: .83em} h6 {font-size: .75em} .mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;} a.mceItemAnchor {width:12px; line-height:6px; overflow:hidden; padding-left:12px; background:url(../default/img/items.gif) no-repeat bottom left;} img.mceItemAnchor {width:12px; height:12px; background:url(../default/img/items.gif) no-repeat;} img {border:0;} table {cursor:default} table td, table th {cursor:text} ins {border-bottom:1px solid green; text-decoration: none; color:green} del {color:red; text-decoration:line-through} cite {border-bottom:1px dashed blue} acronym {border-bottom:1px dotted #CCC; cursor:help} abbr, html\:abbr {border-bottom:1px dashed #CCC; cursor:help} /* IE */ * html body { scrollbar-3dlight-color:#F0F0EE; scrollbar-arrow-color:#676662; scrollbar-base-color:#F0F0EE; scrollbar-darkshadow-color:#DDD; scrollbar-face-color:#E0E0DD; scrollbar-highlight-color:#F0F0EE; scrollbar-shadow-color:#F0F0EE; scrollbar-track-color:#F5F5F5; } ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/ui.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000003524511201070601033661 0ustar frankiefrankie/* Reset */ .o2k7Skin table, .o2k7Skin tbody, .o2k7Skin a, .o2k7Skin img, .o2k7Skin tr, .o2k7Skin div, .o2k7Skin td, .o2k7Skin iframe, .o2k7Skin span, .o2k7Skin *, .o2k7Skin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left} .o2k7Skin a:hover, .o2k7Skin a:link, .o2k7Skin a:visited, .o2k7Skin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000} .o2k7Skin table td {vertical-align:middle} /* Containers */ .o2k7Skin table {background:#E5EFFD} .o2k7Skin iframe {display:block; background:#FFF} .o2k7Skin .mceToolbar {height:26px} /* External */ .o2k7Skin .mceExternalToolbar {position:absolute; border:1px solid #ABC6DD; border-bottom:0; display:none} .o2k7Skin .mceExternalToolbar td.mceToolbar {padding-right:13px;} .o2k7Skin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0} /* Layout */ .o2k7Skin table.mceLayout {border:0; border-left:1px solid #ABC6DD; border-right:1px solid #ABC6DD} .o2k7Skin table.mceLayout tr.mceFirst td {border-top:1px solid #ABC6DD} .o2k7Skin table.mceLayout tr.mceLast td {border-bottom:1px solid #ABC6DD} .o2k7Skin table.mceToolbar, .o2k7Skin tr.mceFirst .mceToolbar tr td, .o2k7Skin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0} .o2k7Skin .mceIframeContainer {border-top:1px solid #ABC6DD; border-bottom:1px solid #ABC6DD} .o2k7Skin .mceStatusbar {display:block; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; height:20px} .o2k7Skin .mceStatusbar div {float:left; padding:2px} .o2k7Skin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize} .o2k7Skin .mceStatusbar a:hover {text-decoration:underline} .o2k7Skin table.mceToolbar {margin-left:3px} .o2k7Skin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; margin-left:3px;} .o2k7Skin .mceToolbar td.mceFirst span {margin:0} .o2k7Skin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px} .o2k7Skin .mceToolbar .mceToolbarEndListBox span, .o2k7Skin .mceToolbar .mceToolbarStartListBox span {display:none} .o2k7Skin span.mceIcon, .o2k7Skin img.mceIcon {display:block; width:20px; height:20px} .o2k7Skin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} .o2k7Skin td.mceCenter {text-align:center;} .o2k7Skin td.mceCenter table {margin:0 auto; text-align:left;} .o2k7Skin td.mceRight table {margin:0 0 0 auto;} /* Button */ .o2k7Skin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px} .o2k7Skin a.mceButton span, .o2k7Skin a.mceButton img {margin-left:1px} .o2k7Skin .mceOldBoxModel a.mceButton span, .o2k7Skin .mceOldBoxModel a.mceButton img {margin:0 0 0 1px} .o2k7Skin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px} .o2k7Skin a.mceButtonActive, .o2k7Skin a.mceButtonSelected {background-position:0 -44px} .o2k7Skin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} .o2k7Skin .mceButtonLabeled {width:auto} .o2k7Skin .mceButtonLabeled span.mceIcon {float:left} .o2k7Skin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica} .o2k7Skin .mceButtonDisabled .mceButtonLabel {color:#888} /* Separator */ .o2k7Skin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px} /* ListBox */ .o2k7Skin .mceListBox {margin-left:3px} .o2k7Skin .mceListBox, .o2k7Skin .mceListBox a {display:block} .o2k7Skin .mceListBox .mceText {padding-left:4px; text-align:left; width:70px; border:1px solid #b3c7e1; border-right:0; background:#eaf2fb; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden} .o2k7Skin .mceListBox .mceOpen {width:14px; height:22px; background:url(img/button_bg.png) -66px 0} .o2k7Skin table.mceListBoxEnabled:hover .mceText, .o2k7Skin .mceListBoxHover .mceText, .o2k7Skin .mceListBoxSelected .mceText {background:#FFF} .o2k7Skin table.mceListBoxEnabled:hover .mceOpen, .o2k7Skin .mceListBoxHover .mceOpen, .o2k7Skin .mceListBoxSelected .mceOpen {background-position:-66px -22px} .o2k7Skin .mceListBoxDisabled .mceText {color:gray} .o2k7Skin .mceListBoxMenu {overflow:auto; overflow-x:hidden} .o2k7Skin .mceOldBoxModel .mceListBox .mceText {height:22px} .o2k7Skin select.mceListBox {font-family:Tahoma,Verdana,Arial,Helvetica; font-size:12px; border:1px solid #b3c7e1; background:#FFF;} /* SplitButton */ .o2k7Skin .mceSplitButton, .o2k7Skin .mceSplitButton a, .o2k7Skin .mceSplitButton span {display:block; height:22px} .o2k7Skin .mceSplitButton {background:url(img/button_bg.png)} .o2k7Skin .mceSplitButton a.mceAction {width:22px} .o2k7Skin .mceSplitButton span.mceAction {width:22px; background:url(../../img/icons.gif) 20px 20px} .o2k7Skin .mceSplitButton a.mceOpen {width:10px; background:url(img/button_bg.png) -44px 0} .o2k7Skin .mceSplitButton span.mceOpen {display:none} .o2k7Skin table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background:url(img/button_bg.png) 0 -22px} .o2k7Skin table.mceSplitButtonEnabled:hover a.mceOpen, .o2k7Skin .mceSplitButtonHover a.mceOpen, .o2k7Skin .mceSplitButtonSelected a.mceOpen {background-position:-44px -44px} .o2k7Skin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} .o2k7Skin .mceSplitButtonActive {background-position:0 -44px} /* ColorSplitButton */ .o2k7Skin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray} .o2k7Skin .mceColorSplitMenu td {padding:2px} .o2k7Skin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080} .o2k7Skin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} .o2k7Skin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} .o2k7Skin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2} .o2k7Skin a.mceMoreColors:hover {border:1px solid #0A246A} .o2k7Skin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a;overflow:hidden} .o2k7Skin .mce_forecolor span.mceAction, .o2k7Skin .mce_backcolor span.mceAction {height:15px;overflow:hidden} /* Menu */ .o2k7Skin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #ABC6DD} .o2k7Skin .mceNoIcons span.mceIcon {width:0;} .o2k7Skin .mceNoIcons a .mceText {padding-left:10px} .o2k7Skin .mceMenu table {background:#FFF} .o2k7Skin .mceMenu a, .o2k7Skin .mceMenu span, .o2k7Skin .mceMenu {display:block} .o2k7Skin .mceMenu td {height:20px} .o2k7Skin .mceMenu a {position:relative;padding:3px 0 4px 0} .o2k7Skin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block} .o2k7Skin .mceMenu span.mceText, .o2k7Skin .mceMenu .mcePreview {font-size:11px} .o2k7Skin .mceMenu pre.mceText {font-family:Monospace} .o2k7Skin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;} .o2k7Skin .mceMenu .mceMenuItemEnabled a:hover, .o2k7Skin .mceMenu .mceMenuItemActive {background-color:#dbecf3} .o2k7Skin td.mceMenuItemSeparator {background:#DDD; height:1px} .o2k7Skin .mceMenuItemTitle a {border:0; background:#E5EFFD; border-bottom:1px solid #ABC6DD} .o2k7Skin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px} .o2k7Skin .mceMenuItemDisabled .mceText {color:#888} .o2k7Skin .mceMenuItemSelected .mceIcon {background:url(../default/img/menu_check.gif)} .o2k7Skin .mceNoIcons .mceMenuItemSelected a {background:url(../default/img/menu_arrow.gif) no-repeat -6px center} .o2k7Skin .mceMenu span.mceMenuLine {display:none} .o2k7Skin .mceMenuItemSub a {background:url(../default/img/menu_arrow.gif) no-repeat top right;} /* Progress,Resize */ .o2k7Skin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF} .o2k7Skin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} .o2k7Skin .mcePlaceHolder {border:1px dotted gray} /* Formats */ .o2k7Skin .mce_formatPreview a {font-size:10px} .o2k7Skin .mce_p span.mceText {} .o2k7Skin .mce_address span.mceText {font-style:italic} .o2k7Skin .mce_pre span.mceText {font-family:monospace} .o2k7Skin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} .o2k7Skin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} .o2k7Skin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} .o2k7Skin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} .o2k7Skin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} .o2k7Skin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} /* Theme */ .o2k7Skin span.mce_bold {background-position:0 0} .o2k7Skin span.mce_italic {background-position:-60px 0} .o2k7Skin span.mce_underline {background-position:-140px 0} .o2k7Skin span.mce_strikethrough {background-position:-120px 0} .o2k7Skin span.mce_undo {background-position:-160px 0} .o2k7Skin span.mce_redo {background-position:-100px 0} .o2k7Skin span.mce_cleanup {background-position:-40px 0} .o2k7Skin span.mce_bullist {background-position:-20px 0} .o2k7Skin span.mce_numlist {background-position:-80px 0} .o2k7Skin span.mce_justifyleft {background-position:-460px 0} .o2k7Skin span.mce_justifyright {background-position:-480px 0} .o2k7Skin span.mce_justifycenter {background-position:-420px 0} .o2k7Skin span.mce_justifyfull {background-position:-440px 0} .o2k7Skin span.mce_anchor {background-position:-200px 0} .o2k7Skin span.mce_indent {background-position:-400px 0} .o2k7Skin span.mce_outdent {background-position:-540px 0} .o2k7Skin span.mce_link {background-position:-500px 0} .o2k7Skin span.mce_unlink {background-position:-640px 0} .o2k7Skin span.mce_sub {background-position:-600px 0} .o2k7Skin span.mce_sup {background-position:-620px 0} .o2k7Skin span.mce_removeformat {background-position:-580px 0} .o2k7Skin span.mce_newdocument {background-position:-520px 0} .o2k7Skin span.mce_image {background-position:-380px 0} .o2k7Skin span.mce_help {background-position:-340px 0} .o2k7Skin span.mce_code {background-position:-260px 0} .o2k7Skin span.mce_hr {background-position:-360px 0} .o2k7Skin span.mce_visualaid {background-position:-660px 0} .o2k7Skin span.mce_charmap {background-position:-240px 0} .o2k7Skin span.mce_paste {background-position:-560px 0} .o2k7Skin span.mce_copy {background-position:-700px 0} .o2k7Skin span.mce_cut {background-position:-680px 0} .o2k7Skin span.mce_blockquote {background-position:-220px 0} .o2k7Skin .mce_forecolor span.mceAction {background-position:-720px 0} .o2k7Skin .mce_backcolor span.mceAction {background-position:-760px 0} .o2k7Skin span.mce_forecolorpicker {background-position:-720px 0} .o2k7Skin span.mce_backcolorpicker {background-position:-760px 0} /* Plugins */ .o2k7Skin span.mce_advhr {background-position:-0px -20px} .o2k7Skin span.mce_ltr {background-position:-20px -20px} .o2k7Skin span.mce_rtl {background-position:-40px -20px} .o2k7Skin span.mce_emotions {background-position:-60px -20px} .o2k7Skin span.mce_fullpage {background-position:-80px -20px} .o2k7Skin span.mce_fullscreen {background-position:-100px -20px} .o2k7Skin span.mce_iespell {background-position:-120px -20px} .o2k7Skin span.mce_insertdate {background-position:-140px -20px} .o2k7Skin span.mce_inserttime {background-position:-160px -20px} .o2k7Skin span.mce_absolute {background-position:-180px -20px} .o2k7Skin span.mce_backward {background-position:-200px -20px} .o2k7Skin span.mce_forward {background-position:-220px -20px} .o2k7Skin span.mce_insert_layer {background-position:-240px -20px} .o2k7Skin span.mce_insertlayer {background-position:-260px -20px} .o2k7Skin span.mce_movebackward {background-position:-280px -20px} .o2k7Skin span.mce_moveforward {background-position:-300px -20px} .o2k7Skin span.mce_media {background-position:-320px -20px} .o2k7Skin span.mce_nonbreaking {background-position:-340px -20px} .o2k7Skin span.mce_pastetext {background-position:-360px -20px} .o2k7Skin span.mce_pasteword {background-position:-380px -20px} .o2k7Skin span.mce_selectall {background-position:-400px -20px} .o2k7Skin span.mce_preview {background-position:-420px -20px} .o2k7Skin span.mce_print {background-position:-440px -20px} .o2k7Skin span.mce_cancel {background-position:-460px -20px} .o2k7Skin span.mce_save {background-position:-480px -20px} .o2k7Skin span.mce_replace {background-position:-500px -20px} .o2k7Skin span.mce_search {background-position:-520px -20px} .o2k7Skin span.mce_styleprops {background-position:-560px -20px} .o2k7Skin span.mce_table {background-position:-580px -20px} .o2k7Skin span.mce_cell_props {background-position:-600px -20px} .o2k7Skin span.mce_delete_table {background-position:-620px -20px} .o2k7Skin span.mce_delete_col {background-position:-640px -20px} .o2k7Skin span.mce_delete_row {background-position:-660px -20px} .o2k7Skin span.mce_col_after {background-position:-680px -20px} .o2k7Skin span.mce_col_before {background-position:-700px -20px} .o2k7Skin span.mce_row_after {background-position:-720px -20px} .o2k7Skin span.mce_row_before {background-position:-740px -20px} .o2k7Skin span.mce_merge_cells {background-position:-760px -20px} .o2k7Skin span.mce_table_props {background-position:-980px -20px} .o2k7Skin span.mce_row_props {background-position:-780px -20px} .o2k7Skin span.mce_split_cells {background-position:-800px -20px} .o2k7Skin span.mce_template {background-position:-820px -20px} .o2k7Skin span.mce_visualchars {background-position:-840px -20px} .o2k7Skin span.mce_abbr {background-position:-860px -20px} .o2k7Skin span.mce_acronym {background-position:-880px -20px} .o2k7Skin span.mce_attribs {background-position:-900px -20px} .o2k7Skin span.mce_cite {background-position:-920px -20px} .o2k7Skin span.mce_del {background-position:-940px -20px} .o2k7Skin span.mce_ins {background-position:-960px -20px} .o2k7Skin span.mce_pagebreak {background-position:0 -40px} .o2k7Skin .mce_spellchecker span.mceAction {background-position:-540px -20px} ././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o2k7/ui_black.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/o0000644000175000017500000000316711201070601033657 0ustar frankiefrankie/* Black */ .o2k7SkinBlack .mceToolbar .mceToolbarStart span, .o2k7SkinBlack .mceToolbar .mceToolbarEnd span, .o2k7SkinBlack .mceButton, .o2k7SkinBlack .mceSplitButton, .o2k7SkinBlack .mceSeparator, .o2k7SkinBlack .mceSplitButton a.mceOpen, .o2k7SkinBlack .mceListBox a.mceOpen {background-image:url(img/button_bg_black.png)} .o2k7SkinBlack table, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack .mceMenuItemTitle span.mceText, .o2k7SkinBlack .mceStatusbar div, .o2k7SkinBlack .mceStatusbar span, .o2k7SkinBlack .mceStatusbar a {background:#535353; color:#FFF} .o2k7SkinBlack table.mceListBoxEnabled .mceText, o2k7SkinBlack .mceListBox .mceText {background:#FFF; border:1px solid #CBCFD4; border-bottom-color:#989FA9; border-right:0} .o2k7SkinBlack table.mceListBoxEnabled:hover .mceText, .o2k7SkinBlack .mceListBoxHover .mceText, .o2k7SkinBlack .mceListBoxSelected .mceText {background:#FFF; border:1px solid #FFBD69; border-right:0} .o2k7SkinBlack .mceExternalToolbar, .o2k7SkinBlack .mceListBox .mceText, .o2k7SkinBlack div.mceMenu, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceFirst td, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceLast td, .o2k7SkinBlack .mceIframeContainer {border-color: #535353;} .o2k7SkinBlack table.mceSplitButtonEnabled:hover a.mceAction, .o2k7SkinBlack .mceSplitButtonHover a.mceAction, .o2k7SkinBlack .mceSplitButtonSelected {background-image:url(img/button_bg_black.png)} .o2k7SkinBlack .mceMenu .mceMenuItemEnabled a:hover, .o2k7SkinBlack .mceMenu .mceMenuItemActive {background-color:#FFE7A1}././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000755000175000017500000000000011724401447033653 5ustar frankiefrankie././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000755000175000017500000000000011724401447033653 5ustar frankiefrankie././@LongLink0000000000000000000000000000017400000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/progress.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000644000175000017500000000337311201070601033643 0ustar frankiefrankieGIF89a ³ÿÿÿ³³³ûûûÖÖÖáááòòòººº444ÄÄÄ———ýýýTTT!ÿ NETSCAPE2.0!ù, çÈI)K¬êͧJJ5U¢RK”¡(¥&á05+/Émbp z“à 1;$1Cœ®I* üHCh`Ao"3qT5º\Ñ8a¨ŽàBÁî´²dwxG=YgƒwHb†vA=’0V\œ\ˆ; ¤¥œŸ;¥ª›H¨Š¢«¬³˜0¶µt%‘Hs‰‹rYË™Š»à,bLv|?ä4B¬v„ßÊ›¡PÀëuÄ9éÀ+Ü& 2x& k†&Š U]‚ vo Šo‘pŠraT&!ù,{È ¡¯²'œáe7ŒÔ¢\lÅ-)S7@”&»¹4”+`ÈyTSL¢\:=‡¨”„J¯¨k”úì:Ã;žeĈ¡ 8ÊcÊA¡8OÆj@b/¡+:{ ty‚t#ˆ„‹‡|- mN qK!ù,lÈI+8bûÌ áy ¶hŠ*º‡ØZp=ÌÁÔ3ˆ`À“‰C¨`B"‘pX ³9bP¬BÂ`Z= ªòš•8˜>u,S¶t"ΦO˜T\um|; ƒ8~*!ù,xÈI«ãÒá´A]G’e„APbš)µ°Á"!s‚èžÅá ¬Bƒ’IÁ ˜–ÀáМ V† 5q((„X2=Œ,ÄIì» åÚÁn#&Œ©AøÞíVq5t sny\)_‡g†Ž|r5!ù,g©D+¸8ë[{Ú`&y_hžèI)ª(L "ï+gN­8èl5Äï"Üø‹LÀ¦A .‡è%@% œO@”8NgL+½¨ƒÃɃ–êp–us/ jÈ©ÙjVj c7 I!ù,\0¤t€½øž™Ë €p ²„£h¶Qm6Tqmßx®ï(ƒ 6ƒã÷«ƒ–ïç¸'Ðïsa@`‹š]-Ûlèz0€¹ ù_“g± ‹iƒr‹!`¾ !ù,sÈ Ø¡X’”PÆ\|ÓÁ)ä¤pWÊ„ƒêQ稊‚ŒÀ’´G.çˆ}ˆ!*È1˜”p ®Ø v;£T¹Ý©˜—2 ÒàÌþXØ )Æ|f¤%9`}0PFdƒ~ezGw)‹;././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/menu_check.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000644000175000017500000000010611201070601033632 0ustar frankiefrankieGIF89a€ÿÿÿ!ù,Œ©Ëí£œ´‚À…;ëøiÝ#~“ˆØÊ¶î{;././@LongLink0000000000000000000000000000017600000000000011571 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/menu_arrow.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000644000175000017500000000010411201070601033630 0ustar frankiefrankieGIF89a€ÿÿÿ!ù,Œ©Ëí£œ ÐìÍzòq(‘׉¦êÊ*;././@LongLink0000000000000000000000000000017300000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/buttons.pngopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000644000175000017500000000631211201070601033637 0ustar frankiefrankie‰PNG  IHDR^NžÚQÇgAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<OPLTEïîíäääðÏÅðïîôôóùùøñðïõõôíìë! ññð´³²òÐÆæÆÀ[[[õÓÈøøö¦´^åžòòñ×××uˆôÑÇôóò¤³\ˆ ap”“’ìëéíÍÅùùùéèæêéçìëêèÉÂìÌÄ«' xxxøø÷ƒƒƒêÊÂçÇÁ÷÷ölllööõøøøHHHäãáóòòÝÛØêËÄâ»èÈÁâàÞ***ðððòñðìËÃkkkÜ»´úúúäĽçÈÁóóòóòñçÇ¿áÁºÞ¾¶éÊÃ444÷÷÷çæäàÞÛèçåJJJíìê×·¯äĻٹ±yyyzzzKKKõõõîÌÂß¿¸]]]„™ÞÜÙëêèÎÍËÜÚ×éÈ¿æåãäâàvvvãüªº^†˜0}#àÞÜõôóõôôöõõ999UUUBBB111ððKôôôÛÙÖôóóYYYðîíåãá‘¢9ôôòññïèæä```÷öönnnŽDööôãããéééÇÆÅÀ¿½¡°YÅÄÃ>>>ÜÜÜÈÇÆêèçìÌÃrrr·¶µêÊÀMMMãáßéçåïðîòòðÓÓÓ¿¾¼ttt©¨§ððî™™—ìêéëéèæäâïíìýýýÌËÉgggáàÝìËċЉÈÈÈõöõÜÚØö÷ö%%%ñðîåäáììêåäââàßçåãbq˜˜—êèæ……ƒîîì‘ÁÁ¿îìëóóóæåâííë÷÷õïîîèçæêÈÀçåäöööîíìÍÍÍÃÃÁÉ1òòòÝÝÝïïïÌMÎó IDATxÚ´–û_WÆG2É„PÌTâîf"‘ Y„I$ %Wˆæ.ÈUåZ©RWE@Áâµ^«m]ë­÷ë¶Ý["ؾ眙ɤ৿o>™99ç9ÏsÎÌÀ¼TQQÑZ†kªhíþA`_Þ¾ƒiìË#ì;øçßGV+ÄÞ_û¹C¯3DÞ\µ¶#sö;ÖDû‚‚ÜÜ‚‚‚·ÐWzrᔋ;·@½„ÒF²²¿©' ñ†„‚ÜÔ 4ÞJó—ìÍHÓ…2¹ÝÝäœ ­îîMé8ˆ?R-Ìëׇ°}Ùw×f¥S_ÓàUX\‘ÂáJâk sàC<É"r˜•ö…õW¯d¥X ‡\”eŠ»Ëͺrõªåj·Ô…$¢–`6Ëö=õÅ·¥¸¸°}Ezz,YèLR‹-=€¼Eøù_(TxµGþ“À¾†\{³Y¯wëuz \Å·®GVXhqëtz»¶Ñƒäzw½b´°Øí¾"5”}¶¾¡³Hü¨×uêÐ/–©ww*©.Ns·tvZˆŒ °¯ÖU!ª÷ˆ@è«:Å$‰âê¾*‰Î=ÅJêë««ª`Zß–씽ۭU¦jÄHê WIIÒž,M¤óx¢U ‹ÞãAbi…Õ {½^çñ¡Ñç »« {dô^L¸ô€Œ8òj‰Ò¦¦>…½K¯wy¯ QÕР+uã¤Òj9ǃd }{4a< a¢u:OƒdŸgÎîs¹\a<¯Á£—{—r7¸è±ª´I ó†¼D¬G+ …öp«ú<¡7 Ý^È"ö¡˜%†èкÀ& —ʸñb†WW ¯ÂÞƒu„«< ¡0ÚŒËUÕÑ‘ÚJ*ÅÓÑÑѧK†:¼DF!O_ÊžøÃ8ì ³ªúú°½×%‘J€î×o¬¬\ÈŒ²öæì?l3Ùf³ÂÞœ½Ý˜¥i÷Å×𡚚T«¦æ:îÛLÞÖÝHMæ‰&55÷Á¾hîí?|;€ë*Dævdˆ9Tˆd¶Œú¸qÒ¹‘œ“SÎï?N¼óî~‘¿cN¼C8üÁ;Ù»÷¯[#«÷cÝ; ~t6R“Ænß^Í·oŸ¼0I9×Ç~º[ZÜ^ïÅ¥ØÅŸN®;©Ëc?‰•—wu•Ë!|]]‰¢¢òDàÃ=[! Á¡«(Eì“‹'/oPëc±˜ÏWFÓe%JÊ¡'²Ê°–«¢ßRn%ƒÐT34£Aób±KëØ~iÞjµÒ“H$ÊdJÊš¹ó>Ÿ¯Äç;ßÌqmE¡jqÄ¡œîtY9ü*)iæhqi0«¤l~é8¶o_\aººšÙŸ­ „•e'QD&~f5«/}ƒ ½ƒÛe>Ç6Ãr¤åYWLjýjÎy†for̺Œ óÔú”±Z»Æor +|ÿzž`Ø›*Õ8 é> ÃÝÜ¿Yù›ùÊÎ&ØñÓgŸ—‰Ë{:š³úÛ®æP\³&©2LOO£‹92<<ÄR¶E\%"׺/zgAÌâåßS)ìƒAíìQ`î^òÑ£GB8:C©/_jDLG13TŒ8²|ô¡¨V‚Ù¼Âþɽîf¢Z ‰Yv|¥Å9Ô©SÒDæHæ4 ÈЬãËSDþ(™Ô~íPØF¿ =žEÏD…ðCCQ”¤DÀ%¢!‡´-³ Íñ?µÚ密’ý¥Õœï¾[f#‘ëŸà D ‰ÜƒònÄ”ë‘H¤—J >ŽÌ€1L0™>ÉŒl¿¸ÒÖvãF[$þ ßö8ü‚6òñx/Î •)_Çãñ’éÀ )Ÿ bù@<˜VEû¥ù»èQ‹LÍð<4>5õ˜ aùÙ”ìƒD  ök2ÉOM=3¥œEÝ0}6õt¢60¸Î/ß_"µ—b±Õ»ßþi[ùöîj,†í/_‚×ÉüJζ²2¯“ð:q®ÿx’0Ö>HÞÇ׎¶·޽€Ã »ÀaÂû× ûðû˜Ã0<Ýh^ûصk×Ë`û÷ð2œ¼ðê³Ï^ep…Wy£óÂúåõ pyý".£Ôj:Sö´ZM©OPi–W‘·?¼ BÞþ½¿¬VŠ÷?qª)ÚÖº°°3,,TØhx0[wïìïß¹{[ÁލJ[o…v~>ÃäËàR(Á0 µ:?Þ¤ õ‘àÀ(úÁ¿ÿShíï‡Êj²ü4¤ž®Òùo0O *ª44¯¿_´ß=ìq•–"?aàÎãsâ¼Ui8K-ïŸH•– ÝŽ–VÚÄÄîVl_»0û2°†D:,KKMªÒ8¦D¬ÒDÇ—îpnA´Ÿ8‡ª´ v‡1ø2Î NÖ2¬S¥rrÊé öF¥b9ÎÓÊás²=ÅP•f iô*M*’àöIUš´R¥Ñ);а a¡ç&jɵŸ8g4jF#[I Œ!i¤a4Ti 1&)'ªÒPS˦ª4X˜ÑȉJ<]¶Ti¬ºc•ZA›ÊBlªÒRÑP¥±‚ÀbY#wì=Ù^¥å”FãÄ¥Î0ò‚˜Yd[/#Ui"••0FÄâöÉŒ~€—«4Jã4úy§˜$í‰UùmðARéJr"¬ÖïGb¼<'\@…=¼ý6À¯¬8›’«' £@¥RÅÞfK«ÒdûcèFáêËfLUi¼Ã±E•æS•æwØNÉUÖï8&Û `o ~üLà*-0n®Ò´XµU•°ÉEïdû#èVùív‡-”…àívç¤Wi»ÝîߢJsØmD +µÛ¶#J{Üü<@“Éo…ìENeØ…ÍUš1ödxü‚Â~²‡q8B²ÝÁ ¶·%R Ðm7¦[ã5KjbÀïJÙ9²ë›?n+ßìSb_­]Û̘¢iÎõ'âk¸µ¶6Õª­mEǼÍTlÝÔdžhR[û^†´íUÆ€W¹Úi[Ï6(D2[Fý_€¬l¬Ä0ù[’IEND®B`‚././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/items.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000644000175000017500000000010611201070601033632 0ustar frankiefrankieGIF89a ‘ÿÿÿÿÿÌÿÿÿ!ù, @„Œw&ËÛÚƒq‚¤ÔÕ|Æÿa 4’bù;././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/default/img/tabs.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/skins/d0000644000175000017500000000245611201070601033644 0ustar frankiefrankieGIF89a,ZÕÿÿÿüüþ2Jb’¢²¶ÄÍ‘§´äéìãéìíñó¡³»©¹¿ãéë‘›œúûûÈÑÍÐÖÐððêôôïóóîòòíññìððëööòõõñôôðóóïòòîññíööóõõòûûùøøöööôýýüüüûúúùøø÷ñïßîíæëêãïîèìëåñðëðïêåâÚçäÝëèáæãÝéæàèåßóñîöôòþþþüüüúúúÿÿÿ!ù8,,Zÿ@da(ȤrÉl:ŸÐ¨tJ­Z¯Ø¬ )à°xL.›Ïè´zÍn»ßð¸|N¯Ïˆš~Ïïûÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽŽ""6#–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¨7$°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÄ% ÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßÞ!!åæçèéêëìíîïðñòóôõö÷øùúøåÿ H° Áƒ*\Ȱ¡Ã‡#JœHQ¢ 0hÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—- hÌ@³¦Í›8sêÜɳ§ÏÿŸ@ƒ J´¨Ñ£H“5@SƒÓ§P£JJµªÕ«X³jÝʵ«×¯`ÊÖ€ Òª]˶­Û·pãÊK·®Ý»xóêÝË·¯_¾ÒRL¸°áÈ+^̸±ãÇ#KžL¹²å˘-ذƒçÏ C‹Mº´éÓ¨S«^ͺµë×°cËžÛÀà ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μùr¸-HŸN½ºõëØ³kßν»÷ïàËO¾¼ùóå XˆÀ¾½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿàhà&¨à‚ JáD(á„Vhá…f¨á†vèÿᇠ†(âˆ$–hb‰ âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã>äDiä‘H&©ä’6 À“PF)å”TJiÇ•Xf©å–\vé%NV)æ˜V~iæ™h¦©æšk„Iæ›U²)çœtÖign©'”wöé矀b™çžzj衈&À „¾©è£FŠ&£Ž)饘f*¥•Ʃ駠†§N)ꩨFJj©Q¦êê«€®Êê“°Öj«œ²Îz뮼z™+«½+l¿Îjì±È&«ì²Ì6ë,«Å>+í´ÔVkíµØ €Ã¶Üvëí·à†+î¸ä–kî¹è¦«ÿîºì¶ëî»ðº«À&Äkï½øæ«ï¾üöëo¹ Á¿lðÁ'|p , ðÃG,ñÄ@ƒg¬ñÆwL w,òÈ$—|ï *„lòÊ,·ìò /¨ìòÌ4×1Ì2Û¬óÎ<ãËB 9÷,ôÐD›ÐE'­´Ò'ÈôÒPGÝrÓOKmõÕ«àBÕXwíuÂ*ÀÀõ×d—½oØc›­öÚí¢ÐBÚlÇ-÷¸/¼=÷Ýxç­÷Þë|Ž7~ nxÜ*Â}øâK?©8ãíxä”[=yå˜+}yæœ ½yç Ûüy褷 {#openacs_dlg.anchor_title}
    {#openacs_dlg.anchor_title}
    {#openacs_dlg.anchor_name}:
    ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/charmap.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/charmap0000644000175000017500000000456411226234176033727 0ustar frankiefrankie {#openacs_dlg.charmap_title}
    {#openacs_dlg.charmap_title}
     
     
    HTML-Code
     
     
    NUM-Code
     
    ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/editor_template.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/editor_0000644000175000017500000010170511267605465033744 0ustar frankiefrankie/** * $Id: editor_template.js,v 1.5 2009/10/21 13:23:01 daveb Exp $ * * @author Moxiecode * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. */ (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode; // Tell it to load theme specific language pack(s) tinymce.ThemeManager.requireLangPack('openacs'); tinymce.create('tinymce.themes.OpenacsTheme', { sizes : [8, 10, 12, 14, 18, 24, 36], // Control name lookup, format: title, command controls : { bold : ['bold_desc', 'Bold'], italic : ['italic_desc', 'Italic'], underline : ['underline_desc', 'Underline'], strikethrough : ['striketrough_desc', 'Strikethrough'], justifyleft : ['justifyleft_desc', 'JustifyLeft'], justifycenter : ['justifycenter_desc', 'JustifyCenter'], justifyright : ['justifyright_desc', 'JustifyRight'], justifyfull : ['justifyfull_desc', 'JustifyFull'], bullist : ['bullist_desc', 'InsertUnorderedList'], numlist : ['numlist_desc', 'InsertOrderedList'], outdent : ['outdent_desc', 'Outdent'], indent : ['indent_desc', 'Indent'], cut : ['cut_desc', 'Cut'], copy : ['copy_desc', 'Copy'], paste : ['paste_desc', 'Paste'], undo : ['undo_desc', 'Undo'], redo : ['redo_desc', 'Redo'], link : ['link_desc', 'mceLink'], unlink : ['unlink_desc', 'unlink'], image : ['image_desc', 'mceImage'], cleanup : ['cleanup_desc', 'mceCleanup'], help : ['help_desc', 'mceHelp'], code : ['code_desc', 'mceCodeEditor'], hr : ['hr_desc', 'InsertHorizontalRule'], removeformat : ['removeformat_desc', 'RemoveFormat'], sub : ['sub_desc', 'subscript'], sup : ['sup_desc', 'superscript'], forecolor : ['forecolor_desc', 'ForeColor'], forecolorpicker : ['forecolor_desc', 'mceForeColor'], backcolor : ['backcolor_desc', 'HiliteColor'], backcolorpicker : ['backcolor_desc', 'mceBackColor'], charmap : ['charmap_desc', 'mceCharMap'], visualaid : ['visualaid_desc', 'mceToggleVisualAid'], anchor : ['anchor_desc', 'mceInsertAnchor'], newdocument : ['newdocument_desc', 'mceNewDocument'], blockquote : ['blockquote_desc', 'mceBlockQuote'] }, stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'], init : function(ed, url) { var t = this, s, v, o; t.editor = ed; t.url = url; t.onResolveName = new tinymce.util.Dispatcher(this); // Default settings t.settings = s = extend({ theme_openacs_path : true, theme_openacs_toolbar_location : 'bottom', theme_openacs_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect", theme_openacs_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code", theme_openacs_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap", theme_openacs_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6", theme_openacs_toolbar_align : "center", theme_openacs_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats", theme_openacs_more_colors : 1, theme_openacs_row_height : 23, theme_openacs_resize_horizontal : 1, theme_openacs_resizing_use_cookie : 1, theme_openacs_font_sizes : "1,2,3,4,5,6,7", readonly : ed.settings.readonly }, ed.settings); // Setup default font_size_style_values if (!s.font_size_style_values) s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt"; if (tinymce.is(s.theme_openacs_font_sizes, 'string')) { s.font_size_style_values = tinymce.explode(s.font_size_style_values); s.font_size_classes = tinymce.explode(s.font_size_classes || ''); // Parse string value o = {}; ed.settings.theme_openacs_font_sizes = s.theme_openacs_font_sizes; each(ed.getParam('theme_openacs_font_sizes', '', 'hash'), function(v, k) { var cl; if (k == v && v >= 1 && v <= 7) { k = v + ' (' + t.sizes[v - 1] + 'pt)'; if (ed.settings.convert_fonts_to_spans) { cl = s.font_size_classes[v - 1]; v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt'); } } if (/^\s*\./.test(v)) cl = v.replace(/\./g, ''); o[k] = cl ? {'class' : cl} : {fontSize : v}; }); s.theme_openacs_font_sizes = o; } if ((v = s.theme_openacs_path_location) && v != 'none') s.theme_openacs_statusbar_location = s.theme_openacs_path_location; if (s.theme_openacs_statusbar_location == 'none') s.theme_openacs_statusbar_location = 0; // Init editor ed.onInit.add(function() { ed.onNodeChange.add(t._nodeChanged, t); if (ed.settings.content_css !== false) ed.dom.loadCSS(ed.baseURI.toAbsolute("themes/openacs/skins/" + ed.settings.skin + "/content.css")); }); ed.onSetProgressState.add(function(ed, b, ti) { var co, id = ed.id, tb; if (b) { t.progressTimer = setTimeout(function() { co = ed.getContainer(); co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild); tb = DOM.get(ed.id + '_tbl'); DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}}); DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}}); }, ti || 0); } else { DOM.remove(id + '_blocker'); DOM.remove(id + '_progress'); clearTimeout(t.progressTimer); } }); DOM.loadCSS(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css"); if (s.skin_variant) DOM.loadCSS(url + "/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css"); }, createControl : function(n, cf) { var cd, c; if (c = cf.createControl(n)) return c; switch (n) { case "styleselect": return this._createStyleSelect(); case "formatselect": return this._createBlockFormats(); case "fontselect": return this._createFontSelect(); case "fontsizeselect": return this._createFontSizeSelect(); case "forecolor": return this._createForeColorMenu(); case "backcolor": return this._createBackColorMenu(); } if ((cd = this.controls[n])) return cf.createButton(n, {title : "openacs." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]}); }, execCommand : function(cmd, ui, val) { var f = this['_' + cmd]; if (f) { f.call(this, ui, val); return true; } return false; }, _importClasses : function(e) { var ed = this.editor, c = ed.controlManager.get('styleselect'); if (c.getLength() == 0) { each(ed.dom.getClasses(), function(o) { c.add(o['class'], o['class']); }); } }, _createStyleSelect : function(n) { var t = this, ed = t.editor, cf = ed.controlManager, c = cf.createListBox('styleselect', { title : 'openacs.style_select', onselect : function(v) { if (c.selectedValue === v) { ed.execCommand('mceSetStyleInfo', 0, {command : 'removeformat'}); c.select(); return false; } else ed.execCommand('mceSetCSSClass', 0, v); } }); if (c) { each(ed.getParam('theme_openacs_styles', '', 'hash'), function(v, k) { if (v) c.add(t.editor.translate(k), v); }); c.onPostRender.add(function(ed, n) { if (!c.NativeListBox) { Event.add(n.id + '_text', 'focus', t._importClasses, t); Event.add(n.id + '_text', 'mousedown', t._importClasses, t); Event.add(n.id + '_open', 'focus', t._importClasses, t); Event.add(n.id + '_open', 'mousedown', t._importClasses, t); } else Event.add(n.id, 'focus', t._importClasses, t); }); } return c; }, _createFontSelect : function() { var c, t = this, ed = t.editor; c = ed.controlManager.createListBox('fontselect', {title : 'openacs.fontdefault', cmd : 'FontName'}); if (c) { each(ed.getParam('theme_openacs_fonts', t.settings.theme_openacs_fonts, 'hash'), function(v, k) { c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''}); }); } return c; }, _createFontSizeSelect : function() { var t = this, ed = t.editor, c, i = 0, cl = []; c = ed.controlManager.createListBox('fontsizeselect', {title : 'openacs.font_size', onselect : function(v) { if (v.fontSize) ed.execCommand('FontSize', false, v.fontSize); else { each(t.settings.theme_openacs_font_sizes, function(v, k) { if (v['class']) cl.push(v['class']); }); ed.editorCommands._applyInlineStyle('span', {'class' : v['class']}, {check_classes : cl}); } }}); if (c) { each(t.settings.theme_openacs_font_sizes, function(v, k) { var fz = v.fontSize; if (fz >= 1 && fz <= 7) fz = t.sizes[parseInt(fz) - 1] + 'pt'; c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))}); }); } return c; }, _createBlockFormats : function() { var c, fmts = { p : 'openacs.paragraph', address : 'openacs.address', pre : 'openacs.pre', h1 : 'openacs.h1', h2 : 'openacs.h2', h3 : 'openacs.h3', h4 : 'openacs.h4', h5 : 'openacs.h5', h6 : 'openacs.h6', div : 'openacs.div', blockquote : 'openacs.blockquote', code : 'openacs.code', dt : 'openacs.dt', dd : 'openacs.dd', samp : 'openacs.samp' }, t = this; c = t.editor.controlManager.createListBox('formatselect', {title : 'openacs.block', cmd : 'FormatBlock'}); if (c) { each(t.editor.getParam('theme_openacs_blockformats', t.settings.theme_openacs_blockformats, 'hash'), function(v, k) { c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v}); }); } return c; }, _createForeColorMenu : function() { var c, t = this, s = t.settings, o = {}, v; if (s.theme_openacs_more_colors) { o.more_colors_func = function() { t._mceColorPicker(0, { color : c.value, func : function(co) { c.setColor(co); } }); }; } if (v = s.theme_openacs_text_colors) o.colors = v; if (s.theme_openacs_default_foreground_color) o.default_color = s.theme_openacs_default_foreground_color; o.title = 'openacs.forecolor_desc'; o.cmd = 'ForeColor'; o.scope = this; c = t.editor.controlManager.createColorSplitButton('forecolor', o); return c; }, _createBackColorMenu : function() { var c, t = this, s = t.settings, o = {}, v; if (s.theme_openacs_more_colors) { o.more_colors_func = function() { t._mceColorPicker(0, { color : c.value, func : function(co) { c.setColor(co); } }); }; } if (v = s.theme_openacs_background_colors) o.colors = v; if (s.theme_openacs_default_background_color) o.default_color = s.theme_openacs_default_background_color; o.title = 'openacs.backcolor_desc'; o.cmd = 'HiliteColor'; o.scope = this; c = t.editor.controlManager.createColorSplitButton('backcolor', o); return c; }, renderUI : function(o) { var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl; n = p = DOM.create('span', {id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '')}); if (!DOM.boxModel) n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'}); n = sc = DOM.add(n, 'table', {id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0}); n = tb = DOM.add(n, 'tbody'); switch ((s.theme_openacs_layout_manager || '').toLowerCase()) { case "rowlayout": ic = t._rowLayout(s, tb, o); break; case "customlayout": ic = ed.execCallback("theme_openacs_custom_layout", s, tb, o, p); break; default: ic = t._simpleLayout(s, tb, o, p); } n = o.targetNode; // Add classes to first and last TRs nl = DOM.stdMode ? sc.getElementsByTagName('tr') : sc.rows; // Quick fix for IE 8 DOM.addClass(nl[0], 'mceFirst'); DOM.addClass(nl[nl.length - 1], 'mceLast'); // Add classes to first and last TDs each(DOM.select('tr', tb), function(n) { DOM.addClass(n.firstChild, 'mceFirst'); DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast'); }); if (DOM.get(s.theme_openacs_toolbar_container)) DOM.get(s.theme_openacs_toolbar_container).appendChild(p); else DOM.insertAfter(p, n); Event.add(ed.id + '_path_row', 'click', function(e) { e = e.target; if (e.nodeName == 'A') { t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1')); return Event.cancel(e); } }); /* if (DOM.get(ed.id + '_path_row')) { Event.add(ed.id + '_tbl', 'mouseover', function(e) { var re; e = e.target; if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) { re = DOM.get(ed.id + '_path_row'); t.lastPath = re.innerHTML; DOM.setHTML(re, e.parentNode.title); } }); Event.add(ed.id + '_tbl', 'mouseout', function(e) { if (t.lastPath) { DOM.setHTML(ed.id + '_path_row', t.lastPath); t.lastPath = 0; } }); } */ if (!ed.getParam('accessibility_focus')) Event.add(DOM.add(p, 'a', {href : '#'}, ''), 'focus', function() {tinyMCE.get(ed.id).focus();}); if (s.theme_openacs_toolbar_location == 'external') o.deltaHeight = 0; t.deltaHeight = o.deltaHeight; o.targetNode = null; return { iframeContainer : ic, editorContainer : ed.id + '_parent', sizeContainer : sc, deltaHeight : o.deltaHeight }; }, getInfo : function() { return { longname : 'Openacs theme', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', version : tinymce.majorVersion + "." + tinymce.minorVersion } }, resizeBy : function(dw, dh) { var e = DOM.get(this.editor.id + '_tbl'); this.resizeTo(e.clientWidth + dw, e.clientHeight + dh); }, resizeTo : function(w, h) { var ed = this.editor, s = ed.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr'), dh; // Boundery fix box w = Math.max(s.theme_openacs_resizing_min_width || 100, w); h = Math.max(s.theme_openacs_resizing_min_height || 100, h); w = Math.min(s.theme_openacs_resizing_max_width || 0xFFFF, w); h = Math.min(s.theme_openacs_resizing_max_height || 0xFFFF, h); // Calc difference between iframe and container dh = e.clientHeight - ifr.clientHeight; // Resize iframe and container DOM.setStyle(ifr, 'height', h - dh); DOM.setStyles(e, {width : w, height : h}); }, destroy : function() { var id = this.editor.id; Event.clear(id + '_resize'); Event.clear(id + '_path_row'); Event.clear(id + '_external_close'); }, // Internal functions _simpleLayout : function(s, tb, o, p) { var t = this, ed = t.editor, lo = s.theme_openacs_toolbar_location, sl = s.theme_openacs_statusbar_location, n, ic, etb, c; if (s.readonly) { n = DOM.add(tb, 'tr'); n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); return ic; } // Create toolbar container at top if (lo == 'top') t._addToolbars(tb, o); // Create external toolbar if (lo == 'external') { n = c = DOM.create('div', {style : 'position:relative'}); n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'}); DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'}); n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0}); etb = DOM.add(n, 'tbody'); if (p.firstChild.className == 'mceOldBoxModel') p.firstChild.appendChild(c); else p.insertBefore(c, p.firstChild); t._addToolbars(etb, o); ed.onMouseUp.add(function() { var e = DOM.get(ed.id + '_external'); DOM.show(e); DOM.hide(lastExtID); var f = Event.add(ed.id + '_external_close', 'click', function() { DOM.hide(ed.id + '_external'); Event.remove(ed.id + '_external_close', 'click', f); }); DOM.show(e); DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1); // Fixes IE rendering bug DOM.hide(e); DOM.show(e); e.style.filter = ''; lastExtID = ed.id + '_external'; e = null; }); } if (sl == 'top') t._addStatusBar(tb, o); // Create iframe container if (!s.theme_openacs_toolbar_container) { n = DOM.add(tb, 'tr'); n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); } // Create toolbar container at bottom if (lo == 'bottom') t._addToolbars(tb, o); if (sl == 'bottom') t._addStatusBar(tb, o); return ic; }, _rowLayout : function(s, tb, o) { var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a; dc = s.theme_openacs_containers_default_class || ''; da = s.theme_openacs_containers_default_align || 'center'; each(explode(s.theme_openacs_containers || ''), function(c, i) { var v = s['theme_openacs_container_' + c] || ''; switch (v.toLowerCase()) { case 'mceeditor': n = DOM.add(tb, 'tr'); n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); break; case 'mceelementpath': t._addStatusBar(tb, o); break; default: a = (s['theme_openacs_container_' + c + '_align'] || da).toLowerCase(); a = 'mce' + t._ufirst(a); n = DOM.add(DOM.add(tb, 'tr'), 'td', { 'class' : 'mceToolbar ' + (s['theme_openacs_container_' + c + '_class'] || dc) + ' ' + a || da }); to = cf.createToolbar("toolbar" + i); t._addControls(v, to); DOM.setHTML(n, to.renderHTML()); o.deltaHeight -= s.theme_openacs_row_height; } }); return ic; }, _addControls : function(v, tb) { var t = this, s = t.settings, di, cf = t.editor.controlManager; if (s.theme_openacs_disable && !t._disabled) { di = {}; each(explode(s.theme_openacs_disable), function(v) { di[v] = 1; }); t._disabled = di; } else di = t._disabled; each(explode(v), function(n) { var c; if (di && di[n]) return; // Compatiblity with 2.x if (n == 'tablecontrols') { each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) { n = t.createControl(n, cf); if (n) tb.add(n); }); return; } c = t.createControl(n, cf); if (c) tb.add(c); }); }, _addToolbars : function(c, o) { var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, h = [], a; a = s.theme_openacs_toolbar_align.toLowerCase(); a = 'mce' + t._ufirst(a); n = DOM.add(DOM.add(c, 'tr'), 'td', {'class' : 'mceToolbar ' + a}); if (!ed.getParam('accessibility_focus')) h.push(DOM.createHTML('a', {href : '#', onfocus : 'tinyMCE.get(\'' + ed.id + '\').focus();'}, '')); h.push(DOM.createHTML('a', {href : '#', accesskey : 'q', title : ed.getLang("openacs.toolbar_focus")}, '')); // Create toolbar and add the controls for (i=1; (v = s['theme_openacs_buttons' + i]); i++) { tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i}); if (s['theme_openacs_buttons' + i + '_add']) v += ',' + s['theme_openacs_buttons' + i + '_add']; if (s['theme_openacs_buttons' + i + '_add_before']) v = s['theme_openacs_buttons' + i + '_add_before'] + ',' + v; t._addControls(v, tb); //n.appendChild(n = tb.render()); h.push(tb.renderHTML()); o.deltaHeight -= s.theme_openacs_row_height; } h.push(DOM.createHTML('a', {href : '#', accesskey : 'z', title : ed.getLang("openacs.toolbar_focus"), onfocus : 'tinyMCE.getInstanceById(\'' + ed.id + '\').focus();'}, '')); DOM.setHTML(n, h.join('')); }, _addStatusBar : function(tb, o) { var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td; n = DOM.add(tb, 'tr'); n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'}); n = DOM.add(n, 'div', {id : ed.id + '_path_row'}, s.theme_openacs_path ? ed.translate('openacs.path') + ': ' : ' '); DOM.add(n, 'a', {href : '#', accesskey : 'x'}); if (s.theme_openacs_resizing) { DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize'}); if (s.theme_openacs_resizing_use_cookie) { ed.onPostRender.add(function() { var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl'); if (!o) return; if (s.theme_openacs_resize_horizontal) c.style.width = Math.max(10, o.cw) + 'px'; c.style.height = Math.max(10, o.ch) + 'px'; DOM.get(ed.id + '_ifr').style.height = Math.max(10, parseInt(o.ch) + t.deltaHeight) + 'px'; }); } ed.onPostRender.add(function() { Event.add(ed.id + '_resize', 'mousedown', function(e) { var c, p, w, h, n, pa; // Measure container c = DOM.get(ed.id + '_tbl'); w = c.clientWidth; h = c.clientHeight; miw = s.theme_openacs_resizing_min_width || 100; mih = s.theme_openacs_resizing_min_height || 100; maw = s.theme_openacs_resizing_max_width || 0xFFFF; mah = s.theme_openacs_resizing_max_height || 0xFFFF; // Setup placeholder p = DOM.add(DOM.get(ed.id + '_parent'), 'div', {'class' : 'mcePlaceHolder'}); DOM.setStyles(p, {width : w, height : h}); // Replace with placeholder DOM.hide(c); DOM.show(p); // Create internal resize obj r = { x : e.screenX, y : e.screenY, w : w, h : h, dx : null, dy : null }; // Start listening mf = Event.add(DOM.doc, 'mousemove', function(e) { var w, h; // Calc delta values r.dx = e.screenX - r.x; r.dy = e.screenY - r.y; // Boundery fix box w = Math.max(miw, r.w + r.dx); h = Math.max(mih, r.h + r.dy); w = Math.min(maw, w); h = Math.min(mah, h); // Resize placeholder if (s.theme_openacs_resize_horizontal) p.style.width = w + 'px'; p.style.height = h + 'px'; return Event.cancel(e); }); me = Event.add(DOM.doc, 'mouseup', function(e) { var ifr; // Stop listening Event.remove(DOM.doc, 'mousemove', mf); Event.remove(DOM.doc, 'mouseup', me); c.style.display = ''; DOM.remove(p); if (r.dx === null) return; ifr = DOM.get(ed.id + '_ifr'); if (s.theme_openacs_resize_horizontal) c.style.width = Math.max(10, r.w + r.dx) + 'px'; c.style.height = Math.max(10, r.h + r.dy) + 'px'; ifr.style.height = Math.max(10, ifr.clientHeight + r.dy) + 'px'; if (s.theme_openacs_resizing_use_cookie) { Cookie.setHash("TinyMCE_" + ed.id + "_size", { cw : r.w + r.dx, ch : r.h + r.dy }); } }); return Event.cancel(e); }); }); } o.deltaHeight -= 21; n = tb = null; }, _nodeChanged : function(ed, cm, n, co) { var t = this, p, de = 0, v, c, s = t.settings, cl, fz, fn; if (s.readonly) return; tinymce.each(t.stateControls, function(c) { cm.setActive(c, ed.queryCommandState(t.controls[c][1])); }); cm.setActive('visualaid', ed.hasVisual); cm.setDisabled('undo', !ed.undoManager.hasUndo() && !ed.typing); cm.setDisabled('redo', !ed.undoManager.hasRedo()); cm.setDisabled('outdent', !ed.queryCommandState('Outdent')); p = DOM.getParent(n, 'A'); if (c = cm.get('link')) { if (!p || !p.name) { c.setDisabled(!p && co); c.setActive(!!p); } } if (c = cm.get('unlink')) { c.setDisabled(!p && co); c.setActive(!!p && !p.name); } if (c = cm.get('anchor')) { c.setActive(!!p && p.name); if (tinymce.isWebKit) { p = DOM.getParent(n, 'IMG'); c.setActive(!!p && DOM.getAttrib(p, 'mce_name') == 'a'); } } p = DOM.getParent(n, 'IMG'); if (c = cm.get('image')) c.setActive(!!p && n.className.indexOf('mceItem') == -1); if (c = cm.get('styleselect')) { if (n.className) { t._importClasses(); c.select(n.className); } else c.select(); } if (c = cm.get('formatselect')) { p = DOM.getParent(n, DOM.isBlock); if (p) c.select(p.nodeName.toLowerCase()); } if (ed.settings.convert_fonts_to_spans) { ed.dom.getParent(n, function(n) { if (n.nodeName === 'SPAN') { if (!cl && n.className) cl = n.className; if (!fz && n.style.fontSize) fz = n.style.fontSize; if (!fn && n.style.fontFamily) fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase(); } return false; }); if (c = cm.get('fontselect')) { c.select(function(v) { return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn; }); } if (c = cm.get('fontsizeselect')) { c.select(function(v) { if (v.fontSize && v.fontSize === fz) return true; if (v['class'] && v['class'] === cl) return true; }); } } else { if (c = cm.get('fontselect')) c.select(ed.queryCommandValue('FontName')); if (c = cm.get('fontsizeselect')) { v = ed.queryCommandValue('FontSize'); c.select(function(iv) { return iv.fontSize == v; }); } } if (s.theme_openacs_path && s.theme_openacs_statusbar_location) { p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'}); DOM.setHTML(p, ''); ed.dom.getParent(n, function(n) { var na = n.nodeName.toLowerCase(), u, pi, ti = ''; // Ignore non element and hidden elements if (n.nodeType != 1 || n.nodeName === 'BR' || (DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved'))) return; // Fake name if (v = DOM.getAttrib(n, 'mce_name')) na = v; // Handle prefix if (tinymce.isIE && n.scopeName !== 'HTML') na = n.scopeName + ':' + na; // Remove internal prefix na = na.replace(/mce\:/g, ''); // Handle node name switch (na) { case 'b': na = 'strong'; break; case 'i': na = 'em'; break; case 'img': if (v = DOM.getAttrib(n, 'src')) ti += 'src: ' + v + ' '; break; case 'a': if (v = DOM.getAttrib(n, 'name')) { ti += 'name: ' + v + ' '; na += '#' + v; } if (v = DOM.getAttrib(n, 'href')) ti += 'href: ' + v + ' '; break; case 'font': if (s.convert_fonts_to_spans) na = 'span'; if (v = DOM.getAttrib(n, 'face')) ti += 'font: ' + v + ' '; if (v = DOM.getAttrib(n, 'size')) ti += 'size: ' + v + ' '; if (v = DOM.getAttrib(n, 'color')) ti += 'color: ' + v + ' '; break; case 'span': if (v = DOM.getAttrib(n, 'style')) ti += 'style: ' + v + ' '; break; } if (v = DOM.getAttrib(n, 'id')) ti += 'id: ' + v + ' '; if (v = n.className) { v = v.replace(/(webkit-[\w\-]+|Apple-[\w\-]+|mceItem\w+|mceVisualAid)/g, ''); if (v && v.indexOf('mceItem') == -1) { ti += 'class: ' + v + ' '; if (DOM.isBlock(n) || na == 'img' || na == 'span') na += '.' + v; } } na = na.replace(/(html:)/g, ''); na = {name : na, node : n, title : ti}; t.onResolveName.dispatch(t, na); ti = na.title; na = na.name; //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');"; pi = DOM.create('a', {'href' : "javascript:;", onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na); if (p.hasChildNodes()) { p.insertBefore(DOM.doc.createTextNode(' \u00bb '), p.firstChild); p.insertBefore(pi, p.firstChild); } else p.appendChild(pi); }, ed.getBody()); } }, // Commands gets called by execCommand _sel : function(v) { this.editor.execCommand('mceSelectNodeDepth', false, v); }, _mceInsertAnchor : function(ui, v) { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/anchor.htm', width : 320 + parseInt(ed.getLang('openacs.anchor_delta_width', 0)), height : 90 + parseInt(ed.getLang('openacs.anchor_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceCharMap : function() { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/charmap.htm', width : 550 + parseInt(ed.getLang('openacs.charmap_delta_width', 0)), height : 250 + parseInt(ed.getLang('openacs.charmap_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceHelp : function() { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/about.htm', width : 480, height : 380, inline : true }, { theme_url : this.url }); }, _mceColorPicker : function(u, v) { var ed = this.editor; v = v || {}; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/color_picker.htm', width : 375 + parseInt(ed.getLang('openacs.colorpicker_delta_width', 0)), height : 250 + parseInt(ed.getLang('openacs.colorpicker_delta_height', 0)), close_previous : false, inline : true }, { input_color : v.color, func : v.func, theme_url : this.url }); }, _mceCodeEditor : function(ui, val) { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/source_editor.htm', width : parseInt(ed.getParam("theme_openacs_source_editor_width", 720)), height : parseInt(ed.getParam("theme_openacs_source_editor_height", 580)), inline : true, resizable : true, maximizable : true }, { theme_url : this.url }); }, _mceImage : function(ui, val) { var ed = this.editor; // Internal image object like a flash placeholder if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1) return; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/image.htm', width : 355 + parseInt(ed.getLang('openacs.image_delta_width', 0)), height : 275 + parseInt(ed.getLang('openacs.image_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceLink : function(ui, val) { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/link.htm', width : 310 + parseInt(ed.getLang('openacs.link_delta_width', 0)), height : 200 + parseInt(ed.getLang('openacs.link_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceNewDocument : function() { var ed = this.editor; ed.windowManager.confirm('openacs.newdocument', function(s) { if (s) ed.execCommand('mceSetContent', false, ''); }); }, _mceForeColor : function() { var t = this; this._mceColorPicker(0, { color: t.fgColor, func : function(co) { t.fgColor = co; t.editor.execCommand('ForeColor', false, co); } }); }, _mceBackColor : function() { var t = this; this._mceColorPicker(0, { color: t.bgColor, func : function(co) { t.bgColor = co; t.editor.execCommand('HiliteColor', false, co); } }); }, _ufirst : function(s) { return s.substring(0, 1).toUpperCase() + s.substring(1); } }); tinymce.ThemeManager.add('openacs', tinymce.themes.OpenacsTheme); }(tinymce));openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000755000175000017500000000000011724401447033625 5ustar frankiefrankie././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/xp/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000755000175000017500000000000011575225662033634 5ustar frankiefrankie././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/xp/tabs_bg.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000006010746454070033626 0ustar frankiefrankieGIF89a€‘§´ÿÿÿ!ù,Œ©Ë­ ;././@LongLink0000000000000000000000000000016700000000000011571 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/xp/tab_sel_end.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000014510746454070033632 0ustar frankiefrankieGIF89a³û¾9ù¸8áÆŽÝÂîŸ1Ý¡Sñïßä—<ÿÇ<‘›œüüþ!ù,ð ˆ@¡(•vç^Ž_)šd;././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/xp/tab_bg.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000126610746454070033637 0ustar frankiefrankieGIF89aÄüüûööôýýüòòîÐÖÐôô啕¿øø÷¶ÄÍäéìõõòüüüúúúñïßãéìóóïññíððêþþþööòúúùððëøøöòòíôôðóóîööóõõñññì‘§´ÿÿÿ!ù,ÿ`C]ižhª®lë¾p,Ïtmßx®ï|ïÛDÂC,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíV ‰xL.›Ïè´zÍn»ßð¸|N¯Ûïø¼~Oï ‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›’  ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹²¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ÐÝÞßàáâãäåæçèéêëìíîïðñòóôõöîÝûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH‘a‡ 6hÜȱ£Ç CŠI²¤É“(Sÿª\ɲ¥Ë—0cÊœ¹²ƒF 8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£&í€óÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·g;(¡®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±cÃê^˜L¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^Íšt‡ ÈžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_>¼ÃdУKŸN½ºõëØ³kßν»÷ïàËO¾¼ùóèӇbû÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hàÿuPA3 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–èá(¦¨âŠ,¶èâ‹0Æc;././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/xp/tab_sel_bg.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000065410746454070033637 0ustar frankiefrankieGIF89a,(³‘›œáÆŽù¸8ë—.Ý¡SîŸ1ñïßù¹8ÿÈ<æ‹,ÿÇ<ÿÿÿüüþ!ù,,(ÿЄ‘ª½8ëÍ»ÿ`(Ždižhª¢Aq p,Ïtmßx®ï|ïÿÀ pH, …rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿^cL.›ÏhóbÍn»ßð¸|N¯Ûïø¼~Ïïûÿvbiƒ„j€‡ˆ‰Š‹ŒŽ‚…’i•–—˜™š~‘“žd›¡¢£¤¥zŸž¦«¬­®Ž¨©’¯´µ¶·o±²„¸½¾¿¡º»”ÀÅÆÇ€ÂÃgÈÍÎÏqÊËeÐÕÖÇÒÓc×ÜݶÙÚÞâã¥àÓäèé—æÚíîïðñòóôõÓìöùúûüýþÿ ðH° Áƒó"\Ȱ¡Ã‚ JœH±¢¬ˆ3jÜø#Ç YCêó(²¤É“Qª\Éò^Ë—0cš!)³¦Í…4oêÜÙ/'ÏŸ@ãù J´hJ£H“Öª´©R¦N£…*µêNªV³Êε+K®^Ú+¶ìG²fÓZD«¶íÃ;././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/xp/tab_end.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000025110746454070033630 0ustar frankiefrankieGIF89aÄþþþûûù¡³»çäÝÈÑÍíñó¶ÄÍãéëÐÖЩ¹¿ëêãñïßóñîïîèèåßñðëéæàæãÝöôòðïêåâÚîíæëèáìëå‘§´!ù,& @,…GH˜4aÌ…=Ö\OÖ䕃õ˜Ë !bŒ%‰i†;././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/newdocument.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000025210746454067033637 0ustar frankiefrankieGIF89aÃ2Jb’¢²ÒÖ⢵ÒòòòÂÊÒþþþ’ªÂâçò²Ââ²¾ÒòøþÒÝò¢­ÂÂÌÞ!ù,WðÉI«½8ëœzWÊàl‰až 0fÊy…ʺfÜÙ@×v¾/„¦±# „¢k82‡¥‘´–MAµr5 Ç–Ò5Lâ'æh»Ûê‹íF¯oîø¼>;././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/justifyfull.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000010710746454067033636 0ustar frankiefrankieGIF89a!ù,Œ©Ë혴֭¦îÝ=Ÿ:£U6ç•¶î ;././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/cancel_button_bg.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000124510746454067033642 0ustar frankiefrankieGIF89aZÄùŒüÕÊûµ­û¹ûÎÄú¤ž÷øøýþýùùúüüûøø÷÷ø÷ùúùþþýúùùýýþþýýûüüøøøýýýüüüùùùüÚÎûûûúúú÷÷÷üÝÑþþþø€~öööÿÿÿ!ù,Zÿà'Ždižhª®l«½p,Ïtmßx~‹VïÿÀ pH,EQ Ði:ŸÐ¨tJ­Z¯Ñ¥’€íz¿`j€ "p;™ 4n·ÓjuS.Ÿ»ïO¶³nßÇ£hif"‚p‰Š‹ŒˆŒq‘’l“†…i  ›œ¡š›   ž ©›¥š®­Ÿ©­§ž°·¯½ À«Ÿ¡p ¸¥—ÍÏÍι§ÒÐÖÐÕÕÓܹÒßÙàØÛÔ Ë"ËÚ ïÚÚ í÷ôÚìû*T׎Þ=xõ!è×n¡?~ù9¨À a…s Àpá†=‚I2dÉ“(Qÿй’cÊ” ˆÐرfMŽ6mâÌɳ§ÇŽ.}  t§M3 DèH!…§"$HÀ4ÂSªND°ÊªÓ¥¾†{á)…²f£†mÚ4+[³p»¢Mà阰÷)_ |ÿž@8ð`‡#F ¸±_Ɖlx/_¼"ðNhð`„ ?èܹhÐ|~ðhTn aƒgÕ¢cîC hhJ]YÊy‡(’¦jßË`´¨AÙÈ1(œpȤ$;././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/bold_es.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000012010746454067033631 0ustar frankiefrankieGIF89a€ÿÿÿ!ù ,'Œ©Ëí˜ÀÐê®Å™n8aøŒÙmhCj%ç½GÌÒk„çúÎ7;././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/bold_fr.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000011610746454067033636 0ustar frankiefrankieGIF89a!ù,%Œ©Ëí˜3ŠÁ£‡7o]•.^&Fiªl›iÖöçz;././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/italic_es.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000011210746454067033632 0ustar frankiefrankieGIF89a€ÿÿÿ!ù,!Œ©Ëí˜ÓPXCÆDMyßõæØâ&ma ÇòL×;././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/cut.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000027310746454067033642 0ustar frankiefrankieGIF89aÃC§•£_m‡°µ¼\y®"M{†—ÑÍÅ• ²Y¾/c±¤©³j‚²½ÀÀM²!ù,hðÉI«½8¯UÏÏ ”0€Ï!S0¢O€4O³ð³ ¸±åCÀ€0r2! ø0 ˜FAP `G±Ð: €AH<„, ³ŠG!þ\ÅøÁÈ;No `pGL‰Š‹Š;././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/bold_de_se.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000011110746454067033631 0ustar frankiefrankieGIF89a!ù, Œ©Ëí˜tFzÀµ1s½U€Ù•Ü(¦î ÇòL;././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/justifyright.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000010610746454067033635 0ustar frankiefrankieGIF89a!ù,Œ©Ë혴ֈµùít8‰ É™©¶îë;././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/anchor.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000025310746454067033640 0ustar frankiefrankieGIF89aÃ)=i†“§]jŠÂÅÎ8Q„¤¬ÀÒÓÙbw³¦ª²7LtN`‘w޼¤¬ÎTn¢¼ÂÚ!ù,XðÉI«½8ë=×qµ0N‡Q˜çÃ(JÁT£„LÍJò5¢;FsøH,’:î Œ§0Pš Eô2P4FB 2Ab HNÚ­ÐZø¼~;././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/visualaid.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000031610746454067033640 0ustar frankiefrankieGIF89aÃ2Jbž®Â×Úê\w¡²ÅÕr‹²úüþ´ò‹ŸÂ¬Äòßêþ¬¸Ò‚–²ÂÐâ¼Õò!ù,{ðÉI«½8ëÍiû!.K`žža jë* ®î ËSƒ0'â3Œ‚p€“T•€eh`‰âãhH Œ&ᙈR*ß.8˜¥`Zó©H Ž:Üt¶Ýq9%i fg{* P qR|\nŠ‹y—˜™šœž;././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/browse.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000016110746454067033636 0ustar frankiefrankieGIF89a¡.Drÿÿÿ› !ù,Bœ©Ë £;㭹׆¢HV bJ~hª¾ìfŽvXç ò´Þƒg¹Áé6*îbÁVMƒÅ”H›²“ih·Ü;././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/justifyleft.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000010710746454067033636 0ustar frankiefrankieGIF89a!ù,Œ©Ë혴֭Å<èt8‰y™ ª¶î ;././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/paste.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000043610746454067033643 0ustar frankiefrankieGIF89aÔB3#¢‚"bz’ïÍ\½ÊÚBO]z†¢ÚÒ’Wh„²šRò¶êîòŠj*¦²Æ’‡jhXBô뢜‚Ò“ÒÊ‚Ÿ²òÄ6whTÒÞò¶ªüò²—‚Ú£ þüþð×yJB:!ù,›à'Ždižhª®æ²­ë@Ða9šƒbYEÇÄÂ(,'^Æq€t‰G@‚4ñ‚–löÁP #6 )r‹y”["žŸž;././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/indent.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000016010746454067033635 0ustar frankiefrankieGIF89a²;Z›Š¦ÒQ„âÊÓà^z°®ºÊ!ù,5xºÜþ0ʹ½h»»ÆÓ0•·5„(湈C ƒ„‡ ©è K'ײ3§Ïqùc:' ;././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/italic_tw.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000042210746454067033636 0ustar frankiefrankieGIF89aÄoooŸŸŸÏÏÏOOO¯¯¯___///ïïï¿¿¿ßßß???ÿÿÿ!ù, $Ždižh:.*z$ # Ÿ& Ÿm‡#b% 04œ-F2 -²-»¼½!;././@LongLink0000000000000000000000000000017100000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/insert_button_bg.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000127710746454067033647 0ustar frankiefrankieGIF89aZÄÿÿÿþýþüûüúùúø÷øÏÔü°Åû“µù~«øýþþûüü÷øøýþýûüûùúù÷ø÷þþýýýüüüûûûúøø÷÷÷öúùùýýýüüüûûûúúúùùùøøø÷÷÷ööö!ù,Zÿ Ždižhª®lk¼p,Ïtmßx~‹zïÿ@Ïð)ȤrÉl:ŸÉ×J­Z¯L)à@,zËG,=ß²yíe«–¯QnŒ³—äbøÃå>h‚ƒ„qh€…‰Š„Œ_Ž_"h   ©¤  ­¨¬¢­°šŸ ©®²º±®ž¼Æ°¶—–ÒÔÒÓ©Ø×ÕÛÕÚÚØáâ×äåÝÝà©ßÏ[ ßòùßýúâÜÀ`@€ùêÉûw C}ñþåc‡àÀ 6hÔ˜q£ÇAŠ9²ãF“$SÿN¨h  0cjØ “‚Lš2sÚÔ'Mœ9ƒÆÜ “¨†y@ ‚d˜¡ª†&DÍà ê T'8躀«Uª 4 @ ê U3H; mØ©qóê5[vîW§Mˆ‹pÕÂ$$Ž+CãÂ+~œƒåÉŠ3άÙ2aÇ=;­ñaÅ€8ÅÁ²€ ¼V`Ùrر1Èn€A€eÞ¾øîÝ»õk¯yî͜u„ç Dˆîšzoß³YcX:ÁSÏÃCO¾|øæÓ«_Oýùõ ˆˆ ~ýéÐÛw__ýçû¸Ÿÿ¹—zà(à<Þg*€€|Ð'à…f¨á†vxa|óÅ'âˆ$–hâ‰(¦¨âŠ)†Èâ‹0Æ(£Š-Ôhã8Þ;././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/button_menu.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000007110746454067033636 0ustar frankiefrankieGIF89a €ÿÿÿ!ù, Œ©Ëí˜SV¢Þ¼‡;././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/code.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000015610746454067033642 0ustar frankiefrankieGIF89a²!B„!R¥BsÆ^ŽÐ!ù,3HºÜþ0ÊI«½¸µƒ'B³g `[.@œ®-ûr8¡Ö®™ï¬ ipËȤriL;././@LongLink0000000000000000000000000000016300000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/menu_check.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000006310746454067033637 0ustar frankiefrankieGIF89a€ÿÿÿ!ù, ŒgÀ˜ÝVDª;././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/buttons.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000001303610746454067033643 0ustar frankiefrankieGIF89aìæÿÿÿ¸µþòòù’ªò9c„¥ð®¹ÒX„à‚§òšºøÑÚìBˆ§ÆüÞéý]p¢ÃøzŽ®§³Æ¿È×ÅÊÒÊÚòÉÓâäìø‘¢¹£°Â7Lf3Jc’ªÂR^j °²ÂÒûüýwÚ­A¢ Ð<<,››™òèdôï°õß(åÚ‘šlÓ£ðw›xGuZ>©¡ (#òÑ £ Ð º ù¯¯ËôÂÂóÁÁûÉÉ÷ÞÞ›ŒŒ“††¥œœþþþâââÿÿÿ!ùH,ìÿ€H‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½ƒ¾ÂÃÄÅÆÇÈÉ´&ÌÌ-Í&ʾ…ÔÒÛÜÝÞÄ ‚ÁH äß,+ë+,òè÷Œúû´xj‚ ÿ¶=€€A@B >lD øREx4Ïš!™¡dµn .vd%#Ä“6Â\´@‚ ÌÜ¡§ÏŸ>ÈX‹_?j+A …Ä¢)Ñná3÷‘:ÐP´KtaB< éM°wè¦Y³ Ó°V±­[Mgÿo6¸6TÓ‘šº5„ß¿4$M´Àè¾C+Ž›ÖP x ,e°© n 8,”y³£¿~µ]ºXRÞ¶ 5„©ñcQ &RÑ¢… µo“|/S¶ŽôÔŒ@çàF^5Ÿ«ÔsŸ?HÀD#ÙxüPËuM0°ô‚Õ™ÿAD‰Ÿ®¨_Ïž½¡öð׿>}÷šú‚8ü¦è¥Â '¤ð‚ æ3á)’%‰£KCâ~Œד„ãa"†éãVEÅ¬Ó X1³Î!]=àÏ0öÏXe—fÙ!!Á~<^plƒ<¤AvC"bÀOq娉ÿ€ˆ  ‰0Yà "rw pwå[^€‡‚èš?‚eØh´¦ ‰À£_t¢J"±V„@xN6Ë92 °à …Üh¨†ìè0Æö:ŽX!%g•Bpé#hö ÉRõÀØ!#ºuÑ©…[¥Ztê¤H + ÔZk ¸Ö`ƒ ‹„˜"Í<ó m&`Â<)ô) Òì!š"ðšMiIç`EÉ9´l$ŒéÒ#`ðO?ÚºA ÀzH? dÙ–:qây#Œ ¾Z(ß}‹´W•&Š‚fn™‡ Àö Ű ,xB '¨` ÿ &¬@h"Ùՠ!)ýõÝš¶H€§´K1›ò"šš5ê&úû&>~+ÉÇ7“Uˆ:Ì èsŠ[Ì\ú8H]cjÅ9ÈŽ%•d-] 𣜠¬¥AÖHØŒ„ªr)<™!ú”PR áEL Å¿€±Æ‡¨]ñ .ú‚ (ll½\òÝ¥Ð<"«×‚(*"l¦ÒæÌ äcEI D+å–ïm(ƒ,¤À‚ /ì5È‘@•ލ5U*Üœ4ŽéF¢:˜Šêú ~ùx§Ž°7»f¤.ºßûIzéH¢‚Ìšl( ýôÓÇ€ë D,rp„ÐVHΤ@3ÿIp¯òRò!"±k×PRë`þ 5¶@ x;ÿ#b.¯´#ÔÐÆµ!¿0€wôsCÂE³#y gè‰òEAçeŸP”ö°BÜG`ì ">2 œê59•ù ö î[YÛß’d±0t.€"$¶y%ädôcž_¾“ô¥ï|†ÇIÓK˜l~êDqº–Ñ,DaNEs¨„lÂ{“în×tDp$H# Þ¥,5®1LV;Ä zö ¨Ž@+<ˆvÜ! i[ÔÙÓþÒGýjªÓÐO¬©8©k„P’á@p¼–™Oú(ä±\„ŠU,ÿ 4u¸3v.¢t)µØ¥3åîK^B]MB€¶cµD;šÌ]K¸·¸UMIÉŸ¶‘Á!AOÆÜò`±Ïµ`0`3 ¤dvÙÍ©fŠÈ»"*Ú¢›dìÚ “9‰¥,¤Zäò†W¼TEHŠ"œ÷(BÌÊV¶êA®j€0%.!–(Ip‚®¸ŠS<¢&(”° b“@W˜©¬™X.Z´ÕÎ_Ä ))É 5Að˜Ápa»›ÿ(‹ À¢WxR ŽÀ‚è)DC8$Â$Nq`ôƒ_HB3Õ:oºÈ·œ ¢,>„Pè^@UªæPo†ÿ`HÕzh€ 3d„ìcû¤%E²¢Ï1$(ŸHÉ)BY‘yLb³Ÿþ´FÕÈÔ°xˆúù%*æêk„¡Šœ*j¥‘ i62q¾ÐSï‡ÒX‚¸u*˜l $°Y8â‰XAQEkÇЊNGáÐ$–HNZB`áaù#¨uÇGHb¤dìd'®e§NŠb+Ó6*4ýˆé¥¬˜ T®¨Íc9j;ˆ Î"5±éQK}”‚†è¥5í¨!Á¾0`¶¨ôsG]éÑäqÅ =ʚ ñ[nkµÇ¼oæq#5“6Ü+ØmÕ(d"ƒËÔ¥äAÎBäÎGmÿiþ)ˆ G˜U&+$”5NR-¶4Ïý#@7Œ„¤JI²¸zÜ2Q3s!'$°Ó§Ögž´!;6ýFjÍ÷kz½ Áú`Ø!0}g]™cÇÖË&¢i-¬ÛÚ»ªÚo®PÕNg E›—ÁŽî“~V’àV±>ÒPZÒÿBºØÕx€'ÐÄCH»6H¨öŠƒ§9â-o/¸c¸ó8ðpé/|QaÒUÔ”pĵ…¨|¶«Ñ—·ccj¢¥ ¯c u¨S úxw"ÓÅ#0¢Ú¤Œ¹éMûýZß@Py¤•f_òîöÕ´ùB;ôšÒô€×xÊïÝOÁÀ€O3b˜.f²q0‘fÿ}æ6uDâ>-FŽ@O<ƒˆW6j•¸uY!± c¸½ ò~2â›ûüÄ}R”Ð{‚ŸœsSƒÈÀŒecÐ`0ØA1XÉ>ÍS1 öqP‚P}mçߨ"éd¡¥@bSVAÅ•Uˆÿ?jß^F]ÇÄLIàc.º0©Ê`5›¾bÓk¼B'ž,`_#(Ͼ¦Á< ôÀŒ%›Ã+±Aj$0ì<¦wÅš±‚£S¸ 90ˆs2RÓL¬ø@`ij*bÖ’'Äc&ÛVA1eª³Á3ˆ]‚õÇ=†¯ïËØ=‘M¦Ð¹lÒQ§i™ÀcHðÌj'JYM¬ö³kŽ„9þìÿ>“1A4q4´r ÷ ŠòqápÆrH`V)ºÓ(ÿñ%áÄ[Huà"‹‚ ‘&RÍ3ÒW Ì@9Ð`!‚JW-ÿaq}Ó"ÿ“S0òe:²mû„dbìµ{“r„Ô(-ǧw`C  ”/Ti7WMA·,°¡q#&HRÕâ5¹Ó(#J7BE ò átÁ;S7ðT†#(¦N[˜`'`†xˆˆhЈ  Ax剄ð/h…HfwOÅfÐbiF?±&óxdów€J,p /$‡ÇeˆçƒÔT‚ °!bÃ1w@t{œA§¢f„yW‹ìRGƒÖ‰‚0z"ðy ðŸ'}EÕpi}…&!4h‡vwvU‰[†g…`ÑZ8ÿr´gu!B)1b˜fCxÓ{aõ{ƒ U„Wüg|>;ÉŨPOÃVêájÏÇVà#µ†}m( ólR5y–(îæBáE&”u‹òaH(‰Ó1ËÖòq’Á.ç"õ"œ•ma2üçø8áJ†Ç¸"w|´³'`‚Pƒ$ıSáD;‚$à"[$- Vr…óÔRšÒiÒƒ+p…Ëè.ƒZÁš‘5æ…„Ð%~Qq;؃Ið"šÔ"R834ÃXKø^TÃ.-Ç.ÄQÅ!4”ã” ! Šx"HDS†6GIgQÿ4ŠI9¡0^³rô&©gŒ×§tþ¸¶;r˜;Ô¨(ç4uƒX8ÑT†¢iaóÐb²!v16vG0Ј!‰‰Yb•%C™ˆDêÃ>7³w%ЇJSfŠ™u‰Y¶eΉxkÑƘ8ÁB%H‹Ä.ëÃ.3a@´_ogtÂ.VCàŒ/°/ëéŒh^Õ˜0™}U‘-µqŸôð}ñUŽÖÐwÜtŽÚˆiß¶XT±,Ûö[t4üVúÈœTV©ÆR­VYœ¸ˆ³Ö‡êá!ô©QÄ%_á…±5‘¸nûY‡2clá%²ÁaŽõÿ\%u„€4;Q’Š¿€—†À’+€EŠ+™ú#Hã<¦-à¡;_x8pþÙ“+G@éÃÄ(iÕo}¡\¢˜lÙ:ÉÒuÉwp¨¤*H `B•óŽS ; Ðd,W(禃ÄS–f´&XreJ35á)àq„YLs)hÑ457LéÄkÇ$s-f©U¨<ñ2OÐ÷˜Ìº“›—#6^c)Úç Ÿò†àXdÔ™Ô(3£i:iš'§ $´êuѧàŸ0c0v²9›µÉv.²^AiÒ•F¾ù››™ ërF¥J¦¨$­Ž`,|èÿ&amüw4±d@áÑäD…év`ÂqEMÆ£$ uD !zØx†Æ¯ˆFŒÅH6ÅÄIÌz¦E§r¹TÄù ·¡ë@9É ¬V{'uLù˜:û¢Q$›Ù´Æ¡Sd2¯v¡ª¯#ÊRU"Œ%!ÏÕ¢.z~lÙáp¨ƒi> P(ù üZ(2(Gª1.à3§åûnYZ3QR9(1Wj‡-Ó‘(÷¦Æ2ê1IÒV‚!øsó¦³A§Ð>"B”ÝC§uº.ÙÉ•ÃJnò*i4TÿñMC%$#P;Q¨h2z fÐ&7J·“ÿ“š'ãƒ_—c4þ™_ÿfu ø}…agaX^ÃX &'°ÚaEç¹ Nz¢,¥û‹Ea°ú­ó€¨R8¯Æöfn‚4PMË6•/$ðõë/ ½‹™@E òTpXÙ ¿·±iliX^¡¶YÕ䲤È'¡¤ðDõ±ʪ›ÐÞ @¡X-[¸™p9‹@JÇÁ3wTµ1nsZ) D<` {&Lÿ\÷âI µ91®Ë{ô•o0÷¢ð ‡F¨˜À H’|ÇqÀëP¶§‚ħB €YÃð…xÊáq[âi4Y$P·ÿ‘BôæÒT²´®”;5%f¸Žz)@~«’Ë¢$)ËQ7&})˜å&¹ºª‡ü`»ËÂ<è•&º3¹­ÊtËÃÆR3“lov|PÉ®*”ù…cXt8»e:±««8ªlÊóÔ²"¦f²á3ö ›àPÈ "6Z….Ê•³»X.ѯlÄ[¼Æ›À°ÙšÛÂì΋ ®] :“™`æÁ¼Cç*ܧÜv.Éýý¹y… mnäFØ:¿wÞÀ(á-ÞãmyîßÄpY4}{…˜D3Ý/ÐÌ— ÞÇMÎAåëÝ+þçŠ`—3©ÚƒÐ%¨f´áó+nó3 «íƒ#m^…/D‹:5:7Qž«fåVyG»’Råy²è/„‰ŠºBþ(NÏþìhæX„ «ßŠì¢;»Ø®«ÛÞ{`›½àîâîeçÝ<è´`îçŽ Éî°ð‰—Ðîî>ïÝÀÌìàÚ‘aåòºw¿£@©ª»èô^8ÝZžç¡ ïMåìõÄÁ~±×Ÿ Œ>ð_ññŸñ_ ü°ñÿñ ò"?ò$_ò&ò(Ÿò*¿ò,O;././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/sub.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000022410746454067033636 0ustar frankiefrankieGIF89aà 2R‚“’†šÂHEH£¢ RvÊiig252¯»ÓBb§""R‚ⲯ¯RVR!ù,AðÉI«½8ëÍ»ÿÔq4Rã,\A8MCBW8‚}|.àÇœ†­Pø=†f(HŠIBzLUƒ"Píz¿àL;././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/underline_ru.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000011510746454067033635 0ustar frankiefrankieGIF89aMMM!ù,$Œ©Ëí£„j=ö›iáç|d‰…¸rª‡µkËö?;././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/sup.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000022310746454067033635 0ustar frankiefrankieGIF89aÓ’«©¨2R‚êçã>@>¯»ÓR~ÚBb§XWW222rrr†šÂ""RrÂ!ù,@ðÉI«½8ëÍû<ãQ2J¥-‰ Ió8È€ E‹A' Á&CÎ TfoÓ¸QÀiËíz¿§;././@LongLink0000000000000000000000000000016500000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/underline_tw.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000036510746454067033644 0ustar frankiefrankieGIF89aĪªªUUUîîîwwwÌÌÌ™™™333fffÏÏÏ"""ïïï&&&LLLoooDDD???ˆˆˆ¿¿¿»»»ÿÿÿ!ù,r`%ŽdižhJ‘Š>TQ“jÓMT¤Á™*„žÌT F€Hp< "‚ F©¹*¹+¥õ%eÒ9P(Ð&m2 <îwri)‚»i#€^i}„( =Ž’ # —˜ ˜œ …Ÿ(!;././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/underline.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000013010746454067033632 0ustar frankiefrankieGIF89a¡{{{!ù,)”©Ëí˜@ÐúæÑ[œžãM ’bz˜-ÕÊ…ÛúÎ÷¾P;././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/numlist.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/images/0000644000175000017500000000015710746454067033643 0ustar frankiefrankieGIF89a²CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), default quality ÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀ–,"ÿÄ ÿĵ}!1AQa"q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?å­‡JضíY6ã¥k[ö¯­õìDÍ{nÕ¯lzVE¿jÖ·=+ȯÂÄHÙ¶=+^ÙºV-¹éZÖíÒ¼ŠÐ<,C4Ù¾AUej•›äZF®X@ðqEyZ©ÊjĆªHk®>sŠÒš§)«R©!®È@ùÜTJÌ~jršcšœ¦½4u‹ "ÔB¬v¨#cµqU–‡Ðáç¡TL*f ðqLìŒÈXTL*v ùÜQ´f@£"¦aL#šùìBÔÕL·n:V¥¿jÍ€t­8;WZ'“^f¥¿jÕ·=+*ßµiÀzW—Z'‹^F½¹éZ¶íÒ±à=+Ré^]h-vh–ùEV‘ªBß(ªò5rƉ‰ ÕY O!ª²ê„Šò«!««!®¸@ðq1+·Þ§)¦1ù©À×~:ž<á©*š‘MD <÷°ÈÅÀ™MH B H {øc'`xªW­ZŠ©9ë^åá©™qÞ²®;Ö¤ýë.~õêÑ‘ëЉ•p:ÖUÀëZ󎵗8ë^­žÕ˜÷ Ö jäëÖ kÑŒýÓÚâhÖ­F*Ö­F+Ì÷°Äñе¨#j1\“™ïá¤XŒTøâ¢ŒTý«’¤´=ÚЉ…FÂ¥4ÆââYÔ¦B£aSQ‘^$ÕL……FELE0Šð«­MTËP•¥jÏ„t­{W XžUišPv­(J̇µhÂzW›V'“ZF¤¥i@Ý+*Ò´an•æÕäVfo”Uyž[åµsƈ"‘ª´†¥sUœ×L x¸„C!ªÒÍVs]0âb"BÇšPi§­(5ÛB:žT¡©(4ðj j@kÚã'Pj@jià×·‡2p&Š©9ëVâªÎz׳EŽœ53§ïY³÷­)»ÖtÕéÒ‘êQ‰™8ëY³Žµ©8ëYÓµèÒ™ëQFLëÖ¡jÜëÖ¡E®øÏC× ‰#Zµ¨‘jÂ-e9žÖš1VPT(*Ê æ”Ïo"xÅMÚ¢AScŠå©-fŒô#5)Â+ÈÄ3©LˆŠŒŠ˜Šaâb ÈH¦R‘L"¼ZËSE2Ì#¥hCT¢zä©Ë«2ü5¡ ¬èªü&¸*Dó*Èфք-Ò³!5~&® <ʬ¼[åµ8·Ê*jÂ0<ºÄnj»š‘Í@æ·Œ"²"sUÜÔÎj»šèŒ"´HZp¦´ ×]êy²†¤ ÓÁ¨§ƒ^µfàJ <ˆp5ëÐ3p&Š«1©Áâ«LkÖ¤ÂÔ£5P˜u«óU «Ð§#Ñ¥>aÖ³æ¥(ªŠï§3Ô¥2e¨‘jÔËQ"×bž‡§EE«µ-XAYÊg¯E’ «*$: ç”ÏZ„‰T¸â˜‚¥ÇÏ9hzÔ§¡Â*B)¤W—Y dDS©H¦^EcE2")˜©H¦â¼š«RÔË »TŒUÈ«š¢<Ú³.EWb5J*¹®:‘<ú’/DjôMYÑš»WH}F\-òÔ.Ô¥¸¨™«Àóªv¨ÓÙª5´`y•QšÍJÆ¡c[Æ™V$g­(4Òy é¥‚PÔx54àkÓ¤ˆp$ž D <ôéàH W”ÔÙâ ×¥M„!©NZ¥-]–©Ë]´äwR‰FQT¥~ATåÙNg¡IÒ¯Z¬Èµ­u©èzäZ™5V¦QYÊg§EAS ¨ÔTÊ+LôéH•IÚ˜¢¤íXNZ•9è0Ša)¦^uVl¦FE0Š”ŠiæU-LˆŠn*B)¸¯6¢Ôµ2xÅ[Ž«F*Ôu„ÑçT™f:·ª‘Õ˜ÍrÎ'Ic5j6ªHjÌm\³ÅQ–ËqQ³Râ£f¬Ô‚1¨˜Ò±¨˜ÖªD5DƞƢcZ¨"0õ¥šzÒŠÞœN7àÓ¨Å8麗p$œ F 8ï¦K&j Iš†C]ÐajV’ªIVÞªÉ]p‘ÙNITU×ZA]P™ÙN%£U«-1Vºô;i U©”R*Ôªµg}1TTÊ)Š*U“™ßNCÔT˜âš¢ŸŽ+Hî„ôE4ŠŠiÇQ›)‘‘M"¤"šEyõ S#"›ŠŠLW ÑJdÈ*ÂT(*t¬äŽ Ì*¬•:ç”NYÈ´†¬#UD5:5a(Óe’ÜS©»¸¦¬ÔYŠÆ¢cJMFMh rMÆ£cN&£&´P8çZ¦š\ÖЉÎà<Pi€Ó³]PDrœ Gš\×dàIš‰Í;5šêƒÃRªïS½BõщYÅWqVœT+¢3:¡£­1V§u¦…­”ô:`„U©P¤¡Ìëƒ"Š@*@*θHrŠv)§â²”ޏÌaÒ*B)¤W4Ù¢˜Â)¤T„R\“)LŒŠn*LRb¹&Šç%QS-F¢¤Z–Ž L•je5 Ô‹Y8˜ÊDêjej¬¦¤V¬œ d˸¦–¦nâšZ¥@ÂC‰¦HM4š¥ &šMÓI«P9å ¥Í6ŒÖ‘‰“€üÒæ™š\ÖñDòÍ.i™£5¼EÈIš.i¬kx°P#j…ªV¨ÚµR6ŒHXT,*à …j¦mVe¦…©™iÖœæÑCBÓÀ¥ N“™¼DžSÀ¨s:# @¸¨r7ŒÆâ“üRb±“+œf)1OÅ&+ Î3˜§âŒVCç {#openacs_dlg.image_title}
     
    x
    ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/about.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/about.h0000644000175000017500000000564611226234176033656 0ustar frankiefrankie {#openacs_dlg.about_title}

    {#openacs_dlg.about_title}

    Version: ()

    TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under LGPL by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.

    Copyright © 2003-2008, Moxiecode Systems AB, All rights reserved.

    For more information about this software visit the TinyMCE website.

    Got Moxie? Hosted By Sourceforge Also on freshmeat

    {#openacs_dlg.about_loaded}

     

    ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/source_editor.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/source_0000644000175000017500000000250711226234176033746 0ustar frankiefrankie {#openacs_dlg.code_title}
    {#openacs_dlg.code_title}

    ././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/editor_template_src.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/editor_0000644000175000017500000010171111267605465033741 0ustar frankiefrankie/** * $Id: editor_template_src.js,v 1.5 2009/10/21 13:23:01 daveb Exp $ * * @author Moxiecode * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. */ (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode; // Tell it to load theme specific language pack(s) tinymce.ThemeManager.requireLangPack('openacs'); tinymce.create('tinymce.themes.OpenacsTheme', { sizes : [8, 10, 12, 14, 18, 24, 36], // Control name lookup, format: title, command controls : { bold : ['bold_desc', 'Bold'], italic : ['italic_desc', 'Italic'], underline : ['underline_desc', 'Underline'], strikethrough : ['striketrough_desc', 'Strikethrough'], justifyleft : ['justifyleft_desc', 'JustifyLeft'], justifycenter : ['justifycenter_desc', 'JustifyCenter'], justifyright : ['justifyright_desc', 'JustifyRight'], justifyfull : ['justifyfull_desc', 'JustifyFull'], bullist : ['bullist_desc', 'InsertUnorderedList'], numlist : ['numlist_desc', 'InsertOrderedList'], outdent : ['outdent_desc', 'Outdent'], indent : ['indent_desc', 'Indent'], cut : ['cut_desc', 'Cut'], copy : ['copy_desc', 'Copy'], paste : ['paste_desc', 'Paste'], undo : ['undo_desc', 'Undo'], redo : ['redo_desc', 'Redo'], link : ['link_desc', 'mceLink'], unlink : ['unlink_desc', 'unlink'], image : ['image_desc', 'mceImage'], cleanup : ['cleanup_desc', 'mceCleanup'], help : ['help_desc', 'mceHelp'], code : ['code_desc', 'mceCodeEditor'], hr : ['hr_desc', 'InsertHorizontalRule'], removeformat : ['removeformat_desc', 'RemoveFormat'], sub : ['sub_desc', 'subscript'], sup : ['sup_desc', 'superscript'], forecolor : ['forecolor_desc', 'ForeColor'], forecolorpicker : ['forecolor_desc', 'mceForeColor'], backcolor : ['backcolor_desc', 'HiliteColor'], backcolorpicker : ['backcolor_desc', 'mceBackColor'], charmap : ['charmap_desc', 'mceCharMap'], visualaid : ['visualaid_desc', 'mceToggleVisualAid'], anchor : ['anchor_desc', 'mceInsertAnchor'], newdocument : ['newdocument_desc', 'mceNewDocument'], blockquote : ['blockquote_desc', 'mceBlockQuote'] }, stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'], init : function(ed, url) { var t = this, s, v, o; t.editor = ed; t.url = url; t.onResolveName = new tinymce.util.Dispatcher(this); // Default settings t.settings = s = extend({ theme_openacs_path : true, theme_openacs_toolbar_location : 'bottom', theme_openacs_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect", theme_openacs_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code", theme_openacs_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap", theme_openacs_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6", theme_openacs_toolbar_align : "center", theme_openacs_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats", theme_openacs_more_colors : 1, theme_openacs_row_height : 23, theme_openacs_resize_horizontal : 1, theme_openacs_resizing_use_cookie : 1, theme_openacs_font_sizes : "1,2,3,4,5,6,7", readonly : ed.settings.readonly }, ed.settings); // Setup default font_size_style_values if (!s.font_size_style_values) s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt"; if (tinymce.is(s.theme_openacs_font_sizes, 'string')) { s.font_size_style_values = tinymce.explode(s.font_size_style_values); s.font_size_classes = tinymce.explode(s.font_size_classes || ''); // Parse string value o = {}; ed.settings.theme_openacs_font_sizes = s.theme_openacs_font_sizes; each(ed.getParam('theme_openacs_font_sizes', '', 'hash'), function(v, k) { var cl; if (k == v && v >= 1 && v <= 7) { k = v + ' (' + t.sizes[v - 1] + 'pt)'; if (ed.settings.convert_fonts_to_spans) { cl = s.font_size_classes[v - 1]; v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt'); } } if (/^\s*\./.test(v)) cl = v.replace(/\./g, ''); o[k] = cl ? {'class' : cl} : {fontSize : v}; }); s.theme_openacs_font_sizes = o; } if ((v = s.theme_openacs_path_location) && v != 'none') s.theme_openacs_statusbar_location = s.theme_openacs_path_location; if (s.theme_openacs_statusbar_location == 'none') s.theme_openacs_statusbar_location = 0; // Init editor ed.onInit.add(function() { ed.onNodeChange.add(t._nodeChanged, t); if (ed.settings.content_css !== false) ed.dom.loadCSS(ed.baseURI.toAbsolute("themes/openacs/skins/" + ed.settings.skin + "/content.css")); }); ed.onSetProgressState.add(function(ed, b, ti) { var co, id = ed.id, tb; if (b) { t.progressTimer = setTimeout(function() { co = ed.getContainer(); co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild); tb = DOM.get(ed.id + '_tbl'); DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}}); DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}}); }, ti || 0); } else { DOM.remove(id + '_blocker'); DOM.remove(id + '_progress'); clearTimeout(t.progressTimer); } }); DOM.loadCSS(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css"); if (s.skin_variant) DOM.loadCSS(url + "/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css"); }, createControl : function(n, cf) { var cd, c; if (c = cf.createControl(n)) return c; switch (n) { case "styleselect": return this._createStyleSelect(); case "formatselect": return this._createBlockFormats(); case "fontselect": return this._createFontSelect(); case "fontsizeselect": return this._createFontSizeSelect(); case "forecolor": return this._createForeColorMenu(); case "backcolor": return this._createBackColorMenu(); } if ((cd = this.controls[n])) return cf.createButton(n, {title : "openacs." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]}); }, execCommand : function(cmd, ui, val) { var f = this['_' + cmd]; if (f) { f.call(this, ui, val); return true; } return false; }, _importClasses : function(e) { var ed = this.editor, c = ed.controlManager.get('styleselect'); if (c.getLength() == 0) { each(ed.dom.getClasses(), function(o) { c.add(o['class'], o['class']); }); } }, _createStyleSelect : function(n) { var t = this, ed = t.editor, cf = ed.controlManager, c = cf.createListBox('styleselect', { title : 'openacs.style_select', onselect : function(v) { if (c.selectedValue === v) { ed.execCommand('mceSetStyleInfo', 0, {command : 'removeformat'}); c.select(); return false; } else ed.execCommand('mceSetCSSClass', 0, v); } }); if (c) { each(ed.getParam('theme_openacs_styles', '', 'hash'), function(v, k) { if (v) c.add(t.editor.translate(k), v); }); c.onPostRender.add(function(ed, n) { if (!c.NativeListBox) { Event.add(n.id + '_text', 'focus', t._importClasses, t); Event.add(n.id + '_text', 'mousedown', t._importClasses, t); Event.add(n.id + '_open', 'focus', t._importClasses, t); Event.add(n.id + '_open', 'mousedown', t._importClasses, t); } else Event.add(n.id, 'focus', t._importClasses, t); }); } return c; }, _createFontSelect : function() { var c, t = this, ed = t.editor; c = ed.controlManager.createListBox('fontselect', {title : 'openacs.fontdefault', cmd : 'FontName'}); if (c) { each(ed.getParam('theme_openacs_fonts', t.settings.theme_openacs_fonts, 'hash'), function(v, k) { c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''}); }); } return c; }, _createFontSizeSelect : function() { var t = this, ed = t.editor, c, i = 0, cl = []; c = ed.controlManager.createListBox('fontsizeselect', {title : 'openacs.font_size', onselect : function(v) { if (v.fontSize) ed.execCommand('FontSize', false, v.fontSize); else { each(t.settings.theme_openacs_font_sizes, function(v, k) { if (v['class']) cl.push(v['class']); }); ed.editorCommands._applyInlineStyle('span', {'class' : v['class']}, {check_classes : cl}); } }}); if (c) { each(t.settings.theme_openacs_font_sizes, function(v, k) { var fz = v.fontSize; if (fz >= 1 && fz <= 7) fz = t.sizes[parseInt(fz) - 1] + 'pt'; c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))}); }); } return c; }, _createBlockFormats : function() { var c, fmts = { p : 'openacs.paragraph', address : 'openacs.address', pre : 'openacs.pre', h1 : 'openacs.h1', h2 : 'openacs.h2', h3 : 'openacs.h3', h4 : 'openacs.h4', h5 : 'openacs.h5', h6 : 'openacs.h6', div : 'openacs.div', blockquote : 'openacs.blockquote', code : 'openacs.code', dt : 'openacs.dt', dd : 'openacs.dd', samp : 'openacs.samp' }, t = this; c = t.editor.controlManager.createListBox('formatselect', {title : 'openacs.block', cmd : 'FormatBlock'}); if (c) { each(t.editor.getParam('theme_openacs_blockformats', t.settings.theme_openacs_blockformats, 'hash'), function(v, k) { c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v}); }); } return c; }, _createForeColorMenu : function() { var c, t = this, s = t.settings, o = {}, v; if (s.theme_openacs_more_colors) { o.more_colors_func = function() { t._mceColorPicker(0, { color : c.value, func : function(co) { c.setColor(co); } }); }; } if (v = s.theme_openacs_text_colors) o.colors = v; if (s.theme_openacs_default_foreground_color) o.default_color = s.theme_openacs_default_foreground_color; o.title = 'openacs.forecolor_desc'; o.cmd = 'ForeColor'; o.scope = this; c = t.editor.controlManager.createColorSplitButton('forecolor', o); return c; }, _createBackColorMenu : function() { var c, t = this, s = t.settings, o = {}, v; if (s.theme_openacs_more_colors) { o.more_colors_func = function() { t._mceColorPicker(0, { color : c.value, func : function(co) { c.setColor(co); } }); }; } if (v = s.theme_openacs_background_colors) o.colors = v; if (s.theme_openacs_default_background_color) o.default_color = s.theme_openacs_default_background_color; o.title = 'openacs.backcolor_desc'; o.cmd = 'HiliteColor'; o.scope = this; c = t.editor.controlManager.createColorSplitButton('backcolor', o); return c; }, renderUI : function(o) { var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl; n = p = DOM.create('span', {id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '')}); if (!DOM.boxModel) n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'}); n = sc = DOM.add(n, 'table', {id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0}); n = tb = DOM.add(n, 'tbody'); switch ((s.theme_openacs_layout_manager || '').toLowerCase()) { case "rowlayout": ic = t._rowLayout(s, tb, o); break; case "customlayout": ic = ed.execCallback("theme_openacs_custom_layout", s, tb, o, p); break; default: ic = t._simpleLayout(s, tb, o, p); } n = o.targetNode; // Add classes to first and last TRs nl = DOM.stdMode ? sc.getElementsByTagName('tr') : sc.rows; // Quick fix for IE 8 DOM.addClass(nl[0], 'mceFirst'); DOM.addClass(nl[nl.length - 1], 'mceLast'); // Add classes to first and last TDs each(DOM.select('tr', tb), function(n) { DOM.addClass(n.firstChild, 'mceFirst'); DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast'); }); if (DOM.get(s.theme_openacs_toolbar_container)) DOM.get(s.theme_openacs_toolbar_container).appendChild(p); else DOM.insertAfter(p, n); Event.add(ed.id + '_path_row', 'click', function(e) { e = e.target; if (e.nodeName == 'A') { t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1')); return Event.cancel(e); } }); /* if (DOM.get(ed.id + '_path_row')) { Event.add(ed.id + '_tbl', 'mouseover', function(e) { var re; e = e.target; if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) { re = DOM.get(ed.id + '_path_row'); t.lastPath = re.innerHTML; DOM.setHTML(re, e.parentNode.title); } }); Event.add(ed.id + '_tbl', 'mouseout', function(e) { if (t.lastPath) { DOM.setHTML(ed.id + '_path_row', t.lastPath); t.lastPath = 0; } }); } */ if (!ed.getParam('accessibility_focus')) Event.add(DOM.add(p, 'a', {href : '#'}, ''), 'focus', function() {tinyMCE.get(ed.id).focus();}); if (s.theme_openacs_toolbar_location == 'external') o.deltaHeight = 0; t.deltaHeight = o.deltaHeight; o.targetNode = null; return { iframeContainer : ic, editorContainer : ed.id + '_parent', sizeContainer : sc, deltaHeight : o.deltaHeight }; }, getInfo : function() { return { longname : 'Openacs theme', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', version : tinymce.majorVersion + "." + tinymce.minorVersion } }, resizeBy : function(dw, dh) { var e = DOM.get(this.editor.id + '_tbl'); this.resizeTo(e.clientWidth + dw, e.clientHeight + dh); }, resizeTo : function(w, h) { var ed = this.editor, s = ed.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr'), dh; // Boundery fix box w = Math.max(s.theme_openacs_resizing_min_width || 100, w); h = Math.max(s.theme_openacs_resizing_min_height || 100, h); w = Math.min(s.theme_openacs_resizing_max_width || 0xFFFF, w); h = Math.min(s.theme_openacs_resizing_max_height || 0xFFFF, h); // Calc difference between iframe and container dh = e.clientHeight - ifr.clientHeight; // Resize iframe and container DOM.setStyle(ifr, 'height', h - dh); DOM.setStyles(e, {width : w, height : h}); }, destroy : function() { var id = this.editor.id; Event.clear(id + '_resize'); Event.clear(id + '_path_row'); Event.clear(id + '_external_close'); }, // Internal functions _simpleLayout : function(s, tb, o, p) { var t = this, ed = t.editor, lo = s.theme_openacs_toolbar_location, sl = s.theme_openacs_statusbar_location, n, ic, etb, c; if (s.readonly) { n = DOM.add(tb, 'tr'); n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); return ic; } // Create toolbar container at top if (lo == 'top') t._addToolbars(tb, o); // Create external toolbar if (lo == 'external') { n = c = DOM.create('div', {style : 'position:relative'}); n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'}); DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'}); n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0}); etb = DOM.add(n, 'tbody'); if (p.firstChild.className == 'mceOldBoxModel') p.firstChild.appendChild(c); else p.insertBefore(c, p.firstChild); t._addToolbars(etb, o); ed.onMouseUp.add(function() { var e = DOM.get(ed.id + '_external'); DOM.show(e); DOM.hide(lastExtID); var f = Event.add(ed.id + '_external_close', 'click', function() { DOM.hide(ed.id + '_external'); Event.remove(ed.id + '_external_close', 'click', f); }); DOM.show(e); DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1); // Fixes IE rendering bug DOM.hide(e); DOM.show(e); e.style.filter = ''; lastExtID = ed.id + '_external'; e = null; }); } if (sl == 'top') t._addStatusBar(tb, o); // Create iframe container if (!s.theme_openacs_toolbar_container) { n = DOM.add(tb, 'tr'); n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); } // Create toolbar container at bottom if (lo == 'bottom') t._addToolbars(tb, o); if (sl == 'bottom') t._addStatusBar(tb, o); return ic; }, _rowLayout : function(s, tb, o) { var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a; dc = s.theme_openacs_containers_default_class || ''; da = s.theme_openacs_containers_default_align || 'center'; each(explode(s.theme_openacs_containers || ''), function(c, i) { var v = s['theme_openacs_container_' + c] || ''; switch (v.toLowerCase()) { case 'mceeditor': n = DOM.add(tb, 'tr'); n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); break; case 'mceelementpath': t._addStatusBar(tb, o); break; default: a = (s['theme_openacs_container_' + c + '_align'] || da).toLowerCase(); a = 'mce' + t._ufirst(a); n = DOM.add(DOM.add(tb, 'tr'), 'td', { 'class' : 'mceToolbar ' + (s['theme_openacs_container_' + c + '_class'] || dc) + ' ' + a || da }); to = cf.createToolbar("toolbar" + i); t._addControls(v, to); DOM.setHTML(n, to.renderHTML()); o.deltaHeight -= s.theme_openacs_row_height; } }); return ic; }, _addControls : function(v, tb) { var t = this, s = t.settings, di, cf = t.editor.controlManager; if (s.theme_openacs_disable && !t._disabled) { di = {}; each(explode(s.theme_openacs_disable), function(v) { di[v] = 1; }); t._disabled = di; } else di = t._disabled; each(explode(v), function(n) { var c; if (di && di[n]) return; // Compatiblity with 2.x if (n == 'tablecontrols') { each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) { n = t.createControl(n, cf); if (n) tb.add(n); }); return; } c = t.createControl(n, cf); if (c) tb.add(c); }); }, _addToolbars : function(c, o) { var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, h = [], a; a = s.theme_openacs_toolbar_align.toLowerCase(); a = 'mce' + t._ufirst(a); n = DOM.add(DOM.add(c, 'tr'), 'td', {'class' : 'mceToolbar ' + a}); if (!ed.getParam('accessibility_focus')) h.push(DOM.createHTML('a', {href : '#', onfocus : 'tinyMCE.get(\'' + ed.id + '\').focus();'}, '')); h.push(DOM.createHTML('a', {href : '#', accesskey : 'q', title : ed.getLang("openacs.toolbar_focus")}, '')); // Create toolbar and add the controls for (i=1; (v = s['theme_openacs_buttons' + i]); i++) { tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i}); if (s['theme_openacs_buttons' + i + '_add']) v += ',' + s['theme_openacs_buttons' + i + '_add']; if (s['theme_openacs_buttons' + i + '_add_before']) v = s['theme_openacs_buttons' + i + '_add_before'] + ',' + v; t._addControls(v, tb); //n.appendChild(n = tb.render()); h.push(tb.renderHTML()); o.deltaHeight -= s.theme_openacs_row_height; } h.push(DOM.createHTML('a', {href : '#', accesskey : 'z', title : ed.getLang("openacs.toolbar_focus"), onfocus : 'tinyMCE.getInstanceById(\'' + ed.id + '\').focus();'}, '')); DOM.setHTML(n, h.join('')); }, _addStatusBar : function(tb, o) { var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td; n = DOM.add(tb, 'tr'); n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'}); n = DOM.add(n, 'div', {id : ed.id + '_path_row'}, s.theme_openacs_path ? ed.translate('openacs.path') + ': ' : ' '); DOM.add(n, 'a', {href : '#', accesskey : 'x'}); if (s.theme_openacs_resizing) { DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize'}); if (s.theme_openacs_resizing_use_cookie) { ed.onPostRender.add(function() { var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl'); if (!o) return; if (s.theme_openacs_resize_horizontal) c.style.width = Math.max(10, o.cw) + 'px'; c.style.height = Math.max(10, o.ch) + 'px'; DOM.get(ed.id + '_ifr').style.height = Math.max(10, parseInt(o.ch) + t.deltaHeight) + 'px'; }); } ed.onPostRender.add(function() { Event.add(ed.id + '_resize', 'mousedown', function(e) { var c, p, w, h, n, pa; // Measure container c = DOM.get(ed.id + '_tbl'); w = c.clientWidth; h = c.clientHeight; miw = s.theme_openacs_resizing_min_width || 100; mih = s.theme_openacs_resizing_min_height || 100; maw = s.theme_openacs_resizing_max_width || 0xFFFF; mah = s.theme_openacs_resizing_max_height || 0xFFFF; // Setup placeholder p = DOM.add(DOM.get(ed.id + '_parent'), 'div', {'class' : 'mcePlaceHolder'}); DOM.setStyles(p, {width : w, height : h}); // Replace with placeholder DOM.hide(c); DOM.show(p); // Create internal resize obj r = { x : e.screenX, y : e.screenY, w : w, h : h, dx : null, dy : null }; // Start listening mf = Event.add(DOM.doc, 'mousemove', function(e) { var w, h; // Calc delta values r.dx = e.screenX - r.x; r.dy = e.screenY - r.y; // Boundery fix box w = Math.max(miw, r.w + r.dx); h = Math.max(mih, r.h + r.dy); w = Math.min(maw, w); h = Math.min(mah, h); // Resize placeholder if (s.theme_openacs_resize_horizontal) p.style.width = w + 'px'; p.style.height = h + 'px'; return Event.cancel(e); }); me = Event.add(DOM.doc, 'mouseup', function(e) { var ifr; // Stop listening Event.remove(DOM.doc, 'mousemove', mf); Event.remove(DOM.doc, 'mouseup', me); c.style.display = ''; DOM.remove(p); if (r.dx === null) return; ifr = DOM.get(ed.id + '_ifr'); if (s.theme_openacs_resize_horizontal) c.style.width = Math.max(10, r.w + r.dx) + 'px'; c.style.height = Math.max(10, r.h + r.dy) + 'px'; ifr.style.height = Math.max(10, ifr.clientHeight + r.dy) + 'px'; if (s.theme_openacs_resizing_use_cookie) { Cookie.setHash("TinyMCE_" + ed.id + "_size", { cw : r.w + r.dx, ch : r.h + r.dy }); } }); return Event.cancel(e); }); }); } o.deltaHeight -= 21; n = tb = null; }, _nodeChanged : function(ed, cm, n, co) { var t = this, p, de = 0, v, c, s = t.settings, cl, fz, fn; if (s.readonly) return; tinymce.each(t.stateControls, function(c) { cm.setActive(c, ed.queryCommandState(t.controls[c][1])); }); cm.setActive('visualaid', ed.hasVisual); cm.setDisabled('undo', !ed.undoManager.hasUndo() && !ed.typing); cm.setDisabled('redo', !ed.undoManager.hasRedo()); cm.setDisabled('outdent', !ed.queryCommandState('Outdent')); p = DOM.getParent(n, 'A'); if (c = cm.get('link')) { if (!p || !p.name) { c.setDisabled(!p && co); c.setActive(!!p); } } if (c = cm.get('unlink')) { c.setDisabled(!p && co); c.setActive(!!p && !p.name); } if (c = cm.get('anchor')) { c.setActive(!!p && p.name); if (tinymce.isWebKit) { p = DOM.getParent(n, 'IMG'); c.setActive(!!p && DOM.getAttrib(p, 'mce_name') == 'a'); } } p = DOM.getParent(n, 'IMG'); if (c = cm.get('image')) c.setActive(!!p && n.className.indexOf('mceItem') == -1); if (c = cm.get('styleselect')) { if (n.className) { t._importClasses(); c.select(n.className); } else c.select(); } if (c = cm.get('formatselect')) { p = DOM.getParent(n, DOM.isBlock); if (p) c.select(p.nodeName.toLowerCase()); } if (ed.settings.convert_fonts_to_spans) { ed.dom.getParent(n, function(n) { if (n.nodeName === 'SPAN') { if (!cl && n.className) cl = n.className; if (!fz && n.style.fontSize) fz = n.style.fontSize; if (!fn && n.style.fontFamily) fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase(); } return false; }); if (c = cm.get('fontselect')) { c.select(function(v) { return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn; }); } if (c = cm.get('fontsizeselect')) { c.select(function(v) { if (v.fontSize && v.fontSize === fz) return true; if (v['class'] && v['class'] === cl) return true; }); } } else { if (c = cm.get('fontselect')) c.select(ed.queryCommandValue('FontName')); if (c = cm.get('fontsizeselect')) { v = ed.queryCommandValue('FontSize'); c.select(function(iv) { return iv.fontSize == v; }); } } if (s.theme_openacs_path && s.theme_openacs_statusbar_location) { p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'}); DOM.setHTML(p, ''); ed.dom.getParent(n, function(n) { var na = n.nodeName.toLowerCase(), u, pi, ti = ''; // Ignore non element and hidden elements if (n.nodeType != 1 || n.nodeName === 'BR' || (DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved'))) return; // Fake name if (v = DOM.getAttrib(n, 'mce_name')) na = v; // Handle prefix if (tinymce.isIE && n.scopeName !== 'HTML') na = n.scopeName + ':' + na; // Remove internal prefix na = na.replace(/mce\:/g, ''); // Handle node name switch (na) { case 'b': na = 'strong'; break; case 'i': na = 'em'; break; case 'img': if (v = DOM.getAttrib(n, 'src')) ti += 'src: ' + v + ' '; break; case 'a': if (v = DOM.getAttrib(n, 'name')) { ti += 'name: ' + v + ' '; na += '#' + v; } if (v = DOM.getAttrib(n, 'href')) ti += 'href: ' + v + ' '; break; case 'font': if (s.convert_fonts_to_spans) na = 'span'; if (v = DOM.getAttrib(n, 'face')) ti += 'font: ' + v + ' '; if (v = DOM.getAttrib(n, 'size')) ti += 'size: ' + v + ' '; if (v = DOM.getAttrib(n, 'color')) ti += 'color: ' + v + ' '; break; case 'span': if (v = DOM.getAttrib(n, 'style')) ti += 'style: ' + v + ' '; break; } if (v = DOM.getAttrib(n, 'id')) ti += 'id: ' + v + ' '; if (v = n.className) { v = v.replace(/(webkit-[\w\-]+|Apple-[\w\-]+|mceItem\w+|mceVisualAid)/g, ''); if (v && v.indexOf('mceItem') == -1) { ti += 'class: ' + v + ' '; if (DOM.isBlock(n) || na == 'img' || na == 'span') na += '.' + v; } } na = na.replace(/(html:)/g, ''); na = {name : na, node : n, title : ti}; t.onResolveName.dispatch(t, na); ti = na.title; na = na.name; //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');"; pi = DOM.create('a', {'href' : "javascript:;", onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na); if (p.hasChildNodes()) { p.insertBefore(DOM.doc.createTextNode(' \u00bb '), p.firstChild); p.insertBefore(pi, p.firstChild); } else p.appendChild(pi); }, ed.getBody()); } }, // Commands gets called by execCommand _sel : function(v) { this.editor.execCommand('mceSelectNodeDepth', false, v); }, _mceInsertAnchor : function(ui, v) { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/anchor.htm', width : 320 + parseInt(ed.getLang('openacs.anchor_delta_width', 0)), height : 90 + parseInt(ed.getLang('openacs.anchor_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceCharMap : function() { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/charmap.htm', width : 550 + parseInt(ed.getLang('openacs.charmap_delta_width', 0)), height : 250 + parseInt(ed.getLang('openacs.charmap_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceHelp : function() { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/about.htm', width : 480, height : 380, inline : true }, { theme_url : this.url }); }, _mceColorPicker : function(u, v) { var ed = this.editor; v = v || {}; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/color_picker.htm', width : 375 + parseInt(ed.getLang('openacs.colorpicker_delta_width', 0)), height : 250 + parseInt(ed.getLang('openacs.colorpicker_delta_height', 0)), close_previous : false, inline : true }, { input_color : v.color, func : v.func, theme_url : this.url }); }, _mceCodeEditor : function(ui, val) { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/source_editor.htm', width : parseInt(ed.getParam("theme_openacs_source_editor_width", 720)), height : parseInt(ed.getParam("theme_openacs_source_editor_height", 580)), inline : true, resizable : true, maximizable : true }, { theme_url : this.url }); }, _mceImage : function(ui, val) { var ed = this.editor; // Internal image object like a flash placeholder if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1) return; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/image.htm', width : 355 + parseInt(ed.getLang('openacs.image_delta_width', 0)), height : 275 + parseInt(ed.getLang('openacs.image_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceLink : function(ui, val) { var ed = this.editor; ed.windowManager.open({ url : tinymce.baseURL + '/themes/openacs/link.htm', width : 310 + parseInt(ed.getLang('openacs.link_delta_width', 0)), height : 200 + parseInt(ed.getLang('openacs.link_delta_height', 0)), inline : true }, { theme_url : this.url }); }, _mceNewDocument : function() { var ed = this.editor; ed.windowManager.confirm('openacs.newdocument', function(s) { if (s) ed.execCommand('mceSetContent', false, ''); }); }, _mceForeColor : function() { var t = this; this._mceColorPicker(0, { color: t.fgColor, func : function(co) { t.fgColor = co; t.editor.execCommand('ForeColor', false, co); } }); }, _mceBackColor : function() { var t = this; this._mceColorPicker(0, { color: t.bgColor, func : function(co) { t.bgColor = co; t.editor.execCommand('HiliteColor', false, co); } }); }, _ufirst : function(s) { return s.substring(0, 1).toUpperCase() + s.substring(1); } }); tinymce.ThemeManager.add('openacs', tinymce.themes.OpenacsTheme); }(tinymce));././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/link.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/link.ht0000644000175000017500000000512111226234176033651 0ustar frankiefrankie {#openacs_dlg.link_title}
     
    ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/color_picker.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/themes/openacs/color_p0000644000175000017500000000552411226234176033746 0ustar frankiefrankie {#openacs_dlg.colorpicker_title}
    {#openacs_dlg.colorpicker_picker_title}

    {#openacs_dlg.colorpicker_palette_title}

    {#openacs_dlg.colorpicker_named_title}

    {#openacs_dlg.colorpicker_name}
    openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/license.txt0000644000175000017500000006446310746454027031650 0ustar frankiefrankie GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/0000755000175000017500000000000011724401447031124 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/0000755000175000017500000000000011724401447032062 5ustar frankiefrankie././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/editor_pl0000644000175000017500000000304111201073572033756 0ustar frankiefrankie(function(){tinymce.create("tinymce.plugins.Save",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceSave",c._save,c);a.addCommand("mceCancel",c._cancel,c);a.addButton("save",{title:"save.save_desc",cmd:"mceSave"});a.addButton("cancel",{title:"save.cancel_desc",cmd:"mceCancel"});a.onNodeChange.add(c._nodeChange,c);a.addShortcut("ctrl+s",a.getLang("save.save_desc"),"mceSave")},getInfo:function(){return{longname:"Save",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(b,a,c){var b=this.editor;if(b.getParam("save_enablewhendirty")){a.setDisabled("save",!b.isDirty());a.setDisabled("cancel",!b.isDirty())}},_save:function(){var c=this.editor,a,e,d,b;a=tinymce.DOM.get(c.id).form||tinymce.DOM.getParent(c.id,"form");if(c.getParam("save_enablewhendirty")&&!c.isDirty()){return}tinyMCE.triggerSave();if(e=c.getParam("save_onsavecallback")){if(c.execCallback("save_onsavecallback",c)){c.startContent=tinymce.trim(c.getContent({format:"raw"}));c.nodeChanged()}return}if(a){c.isNotDirty=true;if(a.onsubmit==null||a.onsubmit()!=false){a.submit()}c.nodeChanged()}else{c.windowManager.alert("Error: No form element found.")}},_cancel:function(){var a=this.editor,c,b=tinymce.trim(a.startContent);if(c=a.getParam("save_oncancelcallback")){a.execCallback("save_oncancelcallback",a);return}a.setContent(b);a.undoManager.clear();a.nodeChanged()}});tinymce.PluginManager.add("save",tinymce.plugins.Save)})();openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/langs/0000755000175000017500000000000011724401447033166 5ustar frankiefrankie././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/langs/en.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/langs/en.0000644000175000017500000000015610746454054033600 0ustar frankiefrankie// UK lang variables tinyMCE.addToLang('',{ save_desc : 'Save', cancel_desc : 'Cancel all changes' }); ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/editor_plugin_src.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/editor_pl0000644000175000017500000000466711201073572033775 0ustar frankiefrankie/** * $Id: editor_plugin_src.js,v 1.2 2009/05/08 18:18:34 daveb Exp $ * * @author Moxiecode * @copyright Copyright © 2004-2008, Moxiecode Systems AB, All rights reserved. */ (function() { tinymce.create('tinymce.plugins.Save', { init : function(ed, url) { var t = this; t.editor = ed; // Register commands ed.addCommand('mceSave', t._save, t); ed.addCommand('mceCancel', t._cancel, t); // Register buttons ed.addButton('save', {title : 'save.save_desc', cmd : 'mceSave'}); ed.addButton('cancel', {title : 'save.cancel_desc', cmd : 'mceCancel'}); ed.onNodeChange.add(t._nodeChange, t); ed.addShortcut('ctrl+s', ed.getLang('save.save_desc'), 'mceSave'); }, getInfo : function() { return { longname : 'Save', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save', version : tinymce.majorVersion + "." + tinymce.minorVersion }; }, // Private methods _nodeChange : function(ed, cm, n) { var ed = this.editor; if (ed.getParam('save_enablewhendirty')) { cm.setDisabled('save', !ed.isDirty()); cm.setDisabled('cancel', !ed.isDirty()); } }, // Private methods _save : function() { var ed = this.editor, formObj, os, i, elementId; formObj = tinymce.DOM.get(ed.id).form || tinymce.DOM.getParent(ed.id, 'form'); if (ed.getParam("save_enablewhendirty") && !ed.isDirty()) return; tinyMCE.triggerSave(); // Use callback instead if (os = ed.getParam("save_onsavecallback")) { if (ed.execCallback('save_onsavecallback', ed)) { ed.startContent = tinymce.trim(ed.getContent({format : 'raw'})); ed.nodeChanged(); } return; } if (formObj) { ed.isNotDirty = true; if (formObj.onsubmit == null || formObj.onsubmit() != false) formObj.submit(); ed.nodeChanged(); } else ed.windowManager.alert("Error: No form element found."); }, _cancel : function() { var ed = this.editor, os, h = tinymce.trim(ed.startContent); // Use callback instead if (os = ed.getParam("save_oncancelcallback")) { ed.execCallback('save_oncancelcallback', ed); return; } ed.setContent(h); ed.undoManager.clear(); ed.nodeChanged(); } }); // Register plugin tinymce.PluginManager.add('save', tinymce.plugins.Save); })();openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/images/0000755000175000017500000000000011724401447033327 5ustar frankiefrankie././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/images/save.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/images/sa0000644000175000017500000000043510746454054033664 0ustar frankiefrankieGIF89aÔ¶¾ÆNXÆææö2:R B¦ŽŽæFHšÆÖîzrÖ¦žæRRRrz–¾¾þ-:?UU±ööö"BrbcÍbn†*B¦BJ¶ŽŽöB:®¦þýþþ–®æRZr*J¶ÖàøÆÆÚ!ù,šà'Ždižhª¢MÛ`˜bÌFb›­•íü.<\C×ÛA„` Ó03'¡$1ÅhgZ)XžA‘tE††D<è ÉÁ”V î%.˜—ê56?~$ 0?&Š‚“%•   ‰ƒ ·­#f@¿Á+ÅÆÇÆ!;././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/images/cancel.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/images/ca0000644000175000017500000000112710746454054033643 0ustar frankiefrankieGIF89aægñýÿïð**ÿ$$ÿ+&ñù#ÿÏÏÿj]øE5ÿh[ý--ú%÷C3÷ý,,ù;;üKK÷þgZöý00ýÅÅõù##ÿGCú/*ÿ##õ ÷50þÊÊ÷C4ü))òùL<ýPPü<8þËËý//þGCíüJJ÷44ùN?ø$$öø99ù::üLLúSDóøG8ûXJøK<ûLHý_RüGGöû72øþbUøI:ö##÷33øH8þeXþ33ü((÷D4ö$$ý##ü]Oõ ûGB÷B2ûþRRþdWõ ù==þcVþaTÿi\ò##ù)$þ22ï!!ü'"üHHþÌÌûWIÿ[XúQBõ ú>>ûþ44øø##ý]OýÉÉÿÿÿ!ùg,´€g‚ƒ„…†‡ˆ‰Š‹ŽH‹T CRSYM‰” bW &I.‡Ÿ] N([8\G† ) ‚2+‚ ^4·D%†`c-†O¤„Q=7Ì…>"Z„1Bׄ9E:†, †ae<'‚0‚;í…6Kf(¼‚ბ‘A0à ¸/J2<8($~ÔX‚ ÅEUˆ0@–E(Sª\y&;././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/readme.txtopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/save/readme.tx0000644000175000017500000000007510746454054033703 0ustar frankiefrankieCheck the TinyMCE documentation for details on this plugin. openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/0000755000175000017500000000000011575225654032120 5ustar frankiefrankie././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/editor_pl0000644000175000017500000000222110746454063034016 0ustar frankiefrankievar TinyMCE_ZoomPlugin={getInfo:function(){return{longname:'Zoom',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/zoom',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion}},getControlHTML:function(control_name){if(!tinyMCE.isMSIE||tinyMCE.isMSIE5_0||tinyMCE.isOpera)return"";switch(control_name){case"zoom":return''}return""},execCommand:function(editor_id,element,command,user_interface,value){switch(command){case"mceZoom":tinyMCE.getInstanceById(editor_id).contentDocument.body.style.zoom=value;tinyMCE.getInstanceById(editor_id).contentDocument.body.style.mozZoom=value;return true}return false}};tinyMCE.addPlugin("zoom",TinyMCE_ZoomPlugin);././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/editor_plugin_src.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/editor_pl0000644000175000017500000000334510746454063034026 0ustar frankiefrankie/** * $Id: editor_plugin_src.js,v 1.1 2008/01/25 21:44:19 daveb Exp $ * * @author Moxiecode * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved. */ var TinyMCE_ZoomPlugin = { getInfo : function() { return { longname : 'Zoom', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/zoom', version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion }; }, /** * Returns the HTML contents of the zoom control. */ getControlHTML : function(control_name) { if (!tinyMCE.isMSIE || tinyMCE.isMSIE5_0 || tinyMCE.isOpera) return ""; switch (control_name) { case "zoom": return ''; } return ""; }, /** * Executes the mceZoom command. */ execCommand : function(editor_id, element, command, user_interface, value) { // Handle commands switch (command) { case "mceZoom": tinyMCE.getInstanceById(editor_id).contentDocument.body.style.zoom = value; tinyMCE.getInstanceById(editor_id).contentDocument.body.style.mozZoom = value; return true; } // Pass to next handler in chain return false; } }; tinyMCE.addPlugin("zoom", TinyMCE_ZoomPlugin); ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/readme.txtopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/zoom/readme.tx0000644000175000017500000000007510746454063033731 0ustar frankiefrankieCheck the TinyMCE documentation for details on this plugin. openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/0000755000175000017500000000000011724401447033651 5ustar frankiefrankie././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/e0000644000175000017500000002474511526350530034030 0ustar frankiefrankie(function(){var d=tinymce.DOM,b=tinymce.dom.Element,a=tinymce.dom.Event,e=tinymce.each,c=tinymce.is;tinymce.create("tinymce.plugins.InlinePopups",{init:function(f,g){f.onBeforeRenderUI.add(function(){f.windowManager=new tinymce.InlineWindowManager(f);d.loadCSS(g+"/skins/"+(f.settings.inlinepopups_skin||"clearlooks2")+"/window.css")})},getInfo:function(){return{longname:"InlinePopups",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.create("tinymce.InlineWindowManager:tinymce.WindowManager",{InlineWindowManager:function(f){var g=this;g.parent(f);g.zIndex=300000;g.count=0;g.windows={}},open:function(r,j){var y=this,i,k="",q=y.editor,g=0,s=0,h,m,n,o,l,v,x;r=r||{};j=j||{};if(!r.inline){return y.parent(r,j)}if(!r.type){y.bookmark=q.selection.getBookmark(1)}i=d.uniqueId();h=d.getViewPort();r.width=parseInt(r.width||320);r.height=parseInt(r.height||240)+(tinymce.isIE?8:0);r.min_width=parseInt(r.min_width||150);r.min_height=parseInt(r.min_height||100);r.max_width=parseInt(r.max_width||2000);r.max_height=parseInt(r.max_height||2000);r.left=r.left||Math.round(Math.max(h.x,h.x+(h.w/2)-(r.width/2)));r.top=r.top||Math.round(Math.max(h.y,h.y+(h.h/2)-(r.height/2)));r.movable=r.resizable=true;j.mce_width=r.width;j.mce_height=r.height;j.mce_inline=true;j.mce_window_id=i;j.mce_auto_focus=r.auto_focus;y.features=r;y.params=j;y.onOpen.dispatch(y,r,j);if(r.type){k+=" mceModal";if(r.type){k+=" mce"+r.type.substring(0,1).toUpperCase()+r.type.substring(1)}r.resizable=false}if(r.statusbar){k+=" mceStatusbar"}if(r.resizable){k+=" mceResizable"}if(r.minimizable){k+=" mceMinimizable"}if(r.maximizable){k+=" mceMaximizable"}if(r.movable){k+=" mceMovable"}y._addAll(d.doc.body,["div",{id:i,"class":(q.settings.inlinepopups_skin||"clearlooks2")+(tinymce.isIE&&window.getSelection?" ie9":""),style:"width:100px;height:100px"},["div",{id:i+"_wrapper","class":"mceWrapper"+k},["div",{id:i+"_top","class":"mceTop"},["div",{"class":"mceLeft"}],["div",{"class":"mceCenter"}],["div",{"class":"mceRight"}],["span",{id:i+"_title"},r.title||""]],["div",{id:i+"_middle","class":"mceMiddle"},["div",{id:i+"_left","class":"mceLeft"}],["span",{id:i+"_content"}],["div",{id:i+"_right","class":"mceRight"}]],["div",{id:i+"_bottom","class":"mceBottom"},["div",{"class":"mceLeft"}],["div",{"class":"mceCenter"}],["div",{"class":"mceRight"}],["span",{id:i+"_status"},"Content"]],["a",{"class":"mceMove",tabindex:"-1",href:"javascript:;"}],["a",{"class":"mceMin",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceMax",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceMed",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceClose",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{id:i+"_resize_n","class":"mceResize mceResizeN",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_s","class":"mceResize mceResizeS",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_w","class":"mceResize mceResizeW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_e","class":"mceResize mceResizeE",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_nw","class":"mceResize mceResizeNW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_ne","class":"mceResize mceResizeNE",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_sw","class":"mceResize mceResizeSW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_se","class":"mceResize mceResizeSE",tabindex:"-1",href:"javascript:;"}]]]);d.setStyles(i,{top:-10000,left:-10000});if(tinymce.isGecko){d.setStyle(i,"overflow","auto")}if(!r.type){g+=d.get(i+"_left").clientWidth;g+=d.get(i+"_right").clientWidth;s+=d.get(i+"_top").clientHeight;s+=d.get(i+"_bottom").clientHeight}d.setStyles(i,{top:r.top,left:r.left,width:r.width+g,height:r.height+s});x=r.url||r.file;if(x){if(tinymce.relaxedDomain){x+=(x.indexOf("?")==-1?"?":"&")+"mce_rdomain="+tinymce.relaxedDomain}x=tinymce._addVer(x)}if(!r.type){d.add(i+"_content","iframe",{id:i+"_ifr",src:'javascript:""',frameBorder:0,style:"border:0;width:10px;height:10px"});d.setStyles(i+"_ifr",{width:r.width,height:r.height});d.setAttrib(i+"_ifr","src",x)}else{d.add(i+"_wrapper","a",{id:i+"_ok","class":"mceButton mceOk",href:"javascript:;",onmousedown:"return false;"},"Ok");if(r.type=="confirm"){d.add(i+"_wrapper","a",{"class":"mceButton mceCancel",href:"javascript:;",onmousedown:"return false;"},"Cancel")}d.add(i+"_middle","div",{"class":"mceIcon"});d.setHTML(i+"_content",r.content.replace("\n","
    "))}n=a.add(i,"mousedown",function(t){var u=t.target,f,p;f=y.windows[i];y.focus(i);if(u.nodeName=="A"||u.nodeName=="a"){if(u.className=="mceMax"){f.oldPos=f.element.getXY();f.oldSize=f.element.getSize();p=d.getViewPort();p.w-=2;p.h-=2;f.element.moveTo(p.x,p.y);f.element.resizeTo(p.w,p.h);d.setStyles(i+"_ifr",{width:p.w-f.deltaWidth,height:p.h-f.deltaHeight});d.addClass(i+"_wrapper","mceMaximized")}else{if(u.className=="mceMed"){f.element.moveTo(f.oldPos.x,f.oldPos.y);f.element.resizeTo(f.oldSize.w,f.oldSize.h);f.iframeElement.resizeTo(f.oldSize.w-f.deltaWidth,f.oldSize.h-f.deltaHeight);d.removeClass(i+"_wrapper","mceMaximized")}else{if(u.className=="mceMove"){return y._startDrag(i,t,u.className)}else{if(d.hasClass(u,"mceResize")){return y._startDrag(i,t,u.className.substring(13))}}}}}});o=a.add(i,"click",function(f){var p=f.target;y.focus(i);if(p.nodeName=="A"||p.nodeName=="a"){switch(p.className){case"mceClose":y.close(null,i);return a.cancel(f);case"mceButton mceOk":case"mceButton mceCancel":r.button_func(p.className=="mceButton mceOk");return a.cancel(f)}}});v=y.windows[i]={id:i,mousedown_func:n,click_func:o,element:new b(i,{blocker:1,container:q.getContainer()}),iframeElement:new b(i+"_ifr"),features:r,deltaWidth:g,deltaHeight:s};v.iframeElement.on("focus",function(){y.focus(i)});if(y.count==0&&y.editor.getParam("dialog_type","modal")=="modal"){d.add(d.doc.body,"div",{id:"mceModalBlocker","class":(y.editor.settings.inlinepopups_skin||"clearlooks2")+"_modalBlocker",style:{zIndex:y.zIndex-1}});d.show("mceModalBlocker")}else{d.setStyle("mceModalBlocker","z-index",y.zIndex-1)}if(tinymce.isIE6||/Firefox\/2\./.test(navigator.userAgent)||(tinymce.isIE&&!d.boxModel)){d.setStyles("mceModalBlocker",{position:"absolute",left:h.x,top:h.y,width:h.w-2,height:h.h-2})}y.focus(i);y._fixIELayout(i,1);if(d.get(i+"_ok")){d.get(i+"_ok").focus()}y.count++;return v},focus:function(h){var g=this,f;if(f=g.windows[h]){f.zIndex=this.zIndex++;f.element.setStyle("zIndex",f.zIndex);f.element.update();h=h+"_wrapper";d.removeClass(g.lastId,"mceFocus");d.addClass(h,"mceFocus");g.lastId=h}},_addAll:function(k,h){var g,l,f=this,j=tinymce.DOM;if(c(h,"string")){k.appendChild(j.doc.createTextNode(h))}else{if(h.length){k=k.appendChild(j.create(h[0],h[1]));for(g=2;gf){i=m;f=m.zIndex}});if(i){h.focus(i.id)}}},setTitle:function(f,g){var h;f=this._findId(f);if(h=d.get(f+"_title")){h.innerHTML=d.encode(g)}},alert:function(g,f,j){var i=this,h;h=i.open({title:i,type:"alert",button_func:function(k){if(f){f.call(k||i,k)}i.close(null,h.id)},content:d.encode(i.editor.getLang(g,g)),inline:1,width:400,height:130})},confirm:function(g,f,j){var i=this,h;h=i.open({title:i,type:"confirm",button_func:function(k){if(f){f.call(k||i,k)}i.close(null,h.id)},content:d.encode(i.editor.getLang(g,g)),inline:1,width:400,height:130})},_findId:function(f){var g=this;if(typeof(f)=="string"){return f}e(g.windows,function(h){var i=d.get(h.id+"_ifr");if(i&&f==i.contentWindow){f=h.id;return false}});return f},_fixIELayout:function(i,h){var f,g;if(!tinymce.isIE6){return}e(["n","s","w","e","nw","ne","sw","se"],function(j){var k=d.get(i+"_resize_"+j);d.setStyles(k,{width:h?k.clientWidth:"",height:h?k.clientHeight:"",cursor:d.getStyle(k,"cursor",1)});d.setStyle(i+"_bottom","bottom","-1px");k=0});if(f=this.windows[i]){f.element.hide();f.element.show();e(d.select("div,a",i),function(k,j){if(k.currentStyle.backgroundImage!="none"){g=new Image();g.src=k.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/,"$1")}});d.get(i).style.filter=""}}});tinymce.PluginManager.add("inlinepopups",tinymce.plugins.InlinePopups)})();././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000755000175000017500000000000011724401447034034 5ustar frankiefrankie././@LongLink0000000000000000000000000000016600000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000755000175000017500000000000011575225640034037 5ustar frankiefrankie././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000755000175000017500000000000011724401447034034 5ustar frankiefrankie././@LongLink0000000000000000000000000000020300000000000011560 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000146211201067036034031 0ustar frankiefrankieGIF89a æ½wvÔnn£ Ý\\©Ü££Ä<<ÒÑÏÏÒ66ÄCCÙJJ888ÕCCÕdd»--µ”“ÓQQ´33ÜÂÂÛyyÆWWÚiiÛvv»kjÕÔÒÎÏÍÑÌ»<<Íàllßbb¬$$áuuÙEE׎ŽÏÚ´´³MLápp¬++Ó$$ßeeÍKKÎÙRRÃŒ‹§¨ͳ±»¼ºÏ×==ØAAºddÖÖÔÚÎÍÓËÉÒ::Ò))¥¯::¯§¥ÏÒJJßjjÛWWÛPP±((¢Ø;;ůħ›É£¡п½%%%ÇÈÆª ŸÕ00Ìcc½IIªŸžÕÒÐϺ¹Ì±¯ÐÀ¾Ö˜˜À~ÈŸž¸^]×¢¢ŸÜUUÏ,,ÚŒŒ×ssÕyyÓÉÇÒÓÑà||ÓÔÒÙ­­´QPÀNNÉÊÈËÌÊÌÍËđƘ–»BBçÁÁÒ__Ñ??¼Úmm§ 㺺߀€ÛbbÑÅÃÁ…„ŸÌÿÿÿÖ×Õ!ù, ÿ€‚ƒ„…†‡ˆ‰Š‹ŒŽ…Œo2u20•Šv7$r1U‡{))F¦…1+55=;°ƒp!}%Y!8¼d>x`~~ ¹M¼\j_}]ÏhE(°M2x&sÏÏB¹W¦( 'ç~7 ?Wf.óÏä¸ÈãcK¥R¸˜ðŒ‡s&¢(‘ÃÑ#>88çðÜ…Dpj¤"@ó:ž ²¢)Fn$ é0&åÃsaº‰xµèS-€*ÏõØÐB—"-È„ À}l9†hǬ[ý8q’•‡ !° Â0¥H¶¬hýÜéåAšCzf•CË€Ú.˜aˆË»xtífÕábŃ|„¬Ìò—¶± xXBÈ’³ŽÑÆé³á B(ÔèCº´éÓ¨û¸Hà倠6v ¤A;ˆ!,rØMä…ïÀܰ‘€Î ¯!áü¹óçЛPfÐ@ (Ùν»÷ï@h õ$‰ùóèÓ§g㙣@;././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/corners.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000161711201067036034033 0ustar frankiefrankieGIF89a'æIïëç=:8ØÏÇÿÿÿ }‘¡íéâêåÝ‚•¥~’¢“£îêãôñíóðë÷õòõó½ìçàëæÞ‹ž­—¨·ëçßñî釚©“¤³¡°ËÕÜu‰™êæÞùøöìèáìèà€”¤”¤Íù¢²Àûúøýýü¦¶Ãüûúµ¦œ³¿Èþþý³¾Èôòî±½Æòïë³§•ôñìõòî²¾Çýüû²½ÇÅÏ×ùøõøöó¼ÆÐúù÷ºÄηÂÌ´¿Éûûúóñì%+¾ÈÒ­¸ÂÈÑÙ´ÀÉÁËÔòðëÊÓÛø÷ôÿÿÿ!ùI,'ÿ€I‚‚ƒ„…††I)Ž)#ƒ&š&›ƒŠ‚“‘¨¨—™I++¯µ&±ˆµ¤‚Ž©’½½˜¯&(ůG'ÉÅ(¡IÉ'Gн¿À­¯4%Ú¯C$ÞÚ%4…Þ$CÒŽÔ¬#ë>ñ6öò>÷6ÓTõ@`>(P¤‚à è(ð°B€è:ª–¢À  !’¡d†n0™!F_¬ª‚¤ÍrhØ©áf$@xjÈñ2]/™p8Xê À P)0u€#@T ;Šj€ôÁ…¯ðÀ@Ø ”ÅÀC+Rìâx .‚. è5`Á‹{ ¸p³”aºvñîû7ðà€20Ò¡r‡5hV`¹ƒÀ›kî%ÙÁ„ÓÌØ¬õ„¦6ÏíHò ¸-`± ÷‚Ü~öÍ‚6É1$(—°Û÷‚åb ï]2+ä ²ƒ "„÷ÚAH7ð]…qÉ >¨ÿÀ]„{ë?à4ðÞ¼uÒ‰ZØ @&Àß-`=œ—߀qà€H„‚ƒ 2€tÈA† È€‡@\q©‚¢d2 †ö"†"ÆXJAÙ¸H ;././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000225311201067036034030 0ustar frankiefrankieGIF89at0Äž¡œïïîn{…Q[c787ÿÿÿ«ºÆk|ŒµÃÏ`r€‹•ž~‘ ÏØßWdp¢±¿˜©·Ziu ¯^n|\kyø÷÷ööôÄÆÃy{xÏÍÉÿÿÿ!ù,t0ÿ FŒdiž§&¢l;ªnœ®r-bA®ï|¿c#¯B,< Aèk6•L§T§´L¯9ËÈ:ˆz:Ž9D…ƒ;‘‹”Œ{>„9Ÿu|’š–¥£<š›€h­”m¬¤˜“FªY¦‹‰‡½;…SbÇÈÇ®ÉÍ#ÆÍÊ”ÒÈÏÑÒÌÍÝ×ÙÛ×…×ÉáåËåçãÔÕÕêìÜôåóÜÖòÐè®úÚü…âÙÛ7®8‚øºò'NÃc÷Ú¹c0ßÁã¾Dñ¡Çu+jtòã@Œ&;ÿ¦<Ùp¥¹’.±ÁŒ r MiPn6˩Ϟ€Ð¨QFºHª”…ŠP£JJ•êÓªX³B½ªµ«T®^½j€Ê ¬Ù³hÓž•ª¶­[lßÊ5w®Ü¨òêÝË·o_¨~ Ö x°a¾…+†j ±ãÇ#Gf,¹²åÆ”/k~œyóf¨B‹MºtiЦS«Út×°_¯n]Z¶hÛ©¡>ØÍ»·ïß¿uûõðÞ‡}üAòß̉?5‚õëØ³k×^}{„åÞ±wß¾üuøãÉ?~À‚÷ðãËŸ?*ý÷âç¿ßþýýúñ·€üÅ&à{P5 àÿ‚ 6è ƒ >Ø@ '¡‚>HaƒJ˜¡„±]¸ T”h¢‰åpâŠÈb‰*B âŒ/šèâ‹1ž˜ã‹7âX\60ÁD™b‘HNU’F7AL¹d”P"Ye”S2 Û[F©ä„)¦˜)Ži¦Pyfdª)fšn–é&š`ÆÉ&™wº U|öé矀ºg ~G(Ÿƒª¨ ,ꨟP 餔Vj©¥‘^ªé¦’fÊé§”z *¨Q)`ꩨ¦ª*ªR­êê« ´ 묧ÊJë¬[…¥+XºfÅk¯Uý ìT*`ì±È&«¬²Å.ëì³Æ6 í´ÈJK-ÿµk×\Èn+W·Þºn¸j«Ø¹Æž«XºêÆn»‚ëÙ¼òλY½ö^†o¾•»Ú¿¥ù ðÀìZy«\[£áfš±ÍEüÄÃ-'1ÅÊ•×ÆÐMÝpƲ'2v!{{%«w²w)« Ê(s|Æà5ÿ7€ôå\ l2+âÐ b…!^h´†vøàÒ ÂF´±@¦$T×#;²˜5Ž,v½â×>Æv5Öxy¤—ƪíä•L¶Me’p')·–¯q™7ÛÌ)§›ÆÎÙf˜yª¸Ë ~¸š¯ÙøœÆ>*yä‹z(å’/Šyæ— 0êçÆ~>j(è¢Jzé›{+­È®>k뮿 {ì«F{ííÖÞþlîº/Ë{ïÉj;././@LongLink0000000000000000000000000000020400000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000043011201067036034023 0ustar frankiefrankieGIF89aP³ÊËÈcccÖ×ÕâãáßßÞåæåÖØÖÿÿÿ!ù,PÅPC«½8ëÍ;’Œdižhª®ìjLm,ÏtJÕx®—÷îÿ¬pHD‹HÝ1Éœ-›P—¨@­Z¯Ø¬vËívoÞ°xL΂Ëè´šz^»ßÛ6|>¿îø¼~Ïïûÿ€v…†‡ˆzƒ"‰Žw‹”•‚„–™™’š•œž¡’¥¦§¨©ª«¬­®­¤¯²³´µ¨±¶¹º»¸»¾¿°7ÀÃħ½ÈÉÊËÌÍÎÏÐÑÌÇÒÕÖרƒÙÝÞßÈ/!äåæç ;././@LongLink0000000000000000000000000000021000000000000011556 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000140111201067036034022 0ustar frankiefrankieGIF89a-PÕÿÿÿ$%'‚•¥”¤¡°“¤³—¨·ž¯½¢²À¦¶Ãª¹Æu‰™}‘¡€”¤“£~’¢‡š©‹ž­ËÕÜýýüìèàëçßêæÞõóïûúøùøöîêãíéâìèáëæÞêåÝóðëñîé³§•÷õòìçàôñíÍùÑÈ¿ïëçüûúØÏǵ¦œ=:8ÿÿÿ!ù.,-PÿÀ–pH,È$eÉl:ŸÐ¨tJ­VSجvËíz¿™°xL.›ÏhzÍn»ßðøhN¯Ûïø¼Ãïûÿ€‚ƒ%…†‡ˆ‰Š‹Œ Ž‘’“”•!—˜™š›œž ¡¢£¤¥¦§¨©ªª­®¯°±²³´¶·¸¹º»¼½¿ÀÁÂÃÄÅÆ$ÈÉÊËÌÍÎÏÑÒÓÔÕÖרÚÛÜÝÞßàáãäåæçèéêëìííðñòóôõö÷"ùúûüýþÿH° ÁƒNXȰ¡Ã‡#J\@±¢Å‹3jܨ £Ç CŠI2É“(Sª\ɲ%‚—0cÊœI³¦Í8sêÜɳ§ÏÿŸ‚ J´¨Ñ£H (]Ê´©Ó§P£J˜JµªÕ«X³jÀµ«×¯`ÊÛ ¬Ù³hÓª]˶­Û·o!ÈK·®Ý»xóêÝ˗€ L¸°áÈ'vÀ¸±ãÇ#KžL ²å˘3kÞÌy€çÏ C‹Mº´éÓ¨Q3Xͺµë×°cË@»¶íÛ¸sëÞ½¢·ïßÀƒ N…ñãÈ“+_μ¹óçУKŸ>Ý„õëØ³kßν;‹ïàËO¾¼ùèÓ«_Ͼ½û÷_âËŸŸ…ºýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒ ¨Â„Vhá…f¨¡yvè!x.„(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ.;././@LongLink0000000000000000000000000000020500000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000162311201067036034030 0ustar frankiefrankieGIF89a æÏÉÀ÷*šT Ïx£g(½¦Š¡Zú´[ú¥3þóèûÊœÿþÿ[ÑÌÅ«u=œœ›ÕÕÑ»nú¤K¤¥¤ö€½¾¼šc+؈,ÇÀ¹ú¨M¸eÑ…+ìž9øCú­RÚƒ“L š”ö¥5÷´\›™•ì£Dö~õzúÁŒÉÊȼ½º÷“3õ~ ÅÆÄù™%ú¸zú²nÒÓÑúœ)µ¶´ù«Eù–"ö‡øš<öƒ­®¬ÎÏÍø¼jª«ªÁÂÀù°T±²°ö‰¹¹¸ÿû÷ë—,ú -÷ˆù¡E΂-¥wIÜ•@±ƒT÷–8ÃÄ»¼º´ŒaËÌÊ¡_ÒÎÈ®}IÏÐÎÕÖÔþ÷ñ¿À¾ÐÑÏø—:³´²°±¯·¸¶ëªTÄÅÃ̵«¬ªÐ†2ù«aÉû•{_–}aÝŠ#÷™?ü׳û¸^ù©]©Ÿ’¯°¯Ý1ÓÔÒÇÈÆ˜PûÅ‘ø¦Uõ{ø›7¨©§û«9•Pú»ÿýü¸¹·¬­«ö|õy÷•7Ö×Õ!ù, ÿ€‚ƒ„ Q Q …’“_J]#i#]J_””Kai~­®aK¥ƒ #L®¾®G#‘¥ HY¿Ì¯H Å“ɽÍÖµ’OºÕÖ×O’ÊÍ Vê Ö?…S¼è öìÍS„Riß~¡°·8¤ *Á¸ñ€“À£À mŽ€ƒA¸m ŠRâ85Å|,eп€¿$ìÄFÌhp ð#A}‚µ±â—?`º Âbˆ=¡Pçi¥s$“¾ š`A‚¨Qmph)ÈÁ:­´ò‰ÚAN°Qð͈T@ƒ ¸P·âí³£â-NìU°ÍÞ>Eš2`Ç^§ Xà5ò¡rñâ±go‘wÜxd> WqÒ™C:ª‹Ú(SM¡uÐ" ÙC@ƒˆk÷î¡,U&aIá¥B8ª]1!xh $qÒ$…ŽmýZ\¢e8>aG‘àXX„K…îT$AO>Ç„eœw#X@Fô°Å ÷y§sè„ÿ=@Â…&Ƃܽñrûùá îÑɲ¡…}Wxá -PÁ\"FèÄ÷ùÐÈI;././@LongLink0000000000000000000000000000020600000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000000013411201067036034024 0ustar frankiefrankieGIF89a ¢ïë給œÜÔÌÿÿÿ!ù, !(AK(æ «½8µÅÔvu—•ã)‚ž~äÃ*ýF ;././@LongLink0000000000000000000000000000020000000000000011555 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/s0000644000175000017500000001605511526350530034041 0ustar frankiefrankie/* Clearlooks 2 */ /* Reset */ .clearlooks2, .clearlooks2 div, .clearlooks2 span, .clearlooks2 a {vertical-align:baseline; text-align:left; position:absolute; border:0; padding:0; margin:0; background:transparent; font-family:Arial,Verdana; font-size:11px; color:#000; text-decoration:none; font-weight:normal; width:auto; height:auto; overflow:hidden; display:block} /* General */ .clearlooks2 {position:absolute; direction:ltr} .clearlooks2 .mceWrapper {position:static} .mceEventBlocker {position:fixed; left:0; top:0; background:url(img/horizontal.gif) no-repeat 0 -75px; width:100%; height:100%} .clearlooks2 .mcePlaceHolder {border:1px solid #000; background:#888; top:0; left:0; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50)} .clearlooks2_modalBlocker {position:fixed; left:0; top:0; width:100%; height:100%; background:#FFF; opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60); display:none} /* Top */ .clearlooks2 .mceTop, .clearlooks2 .mceTop div {top:0; width:100%; height:23px} .clearlooks2 .mceTop .mceLeft {width:6px; background:url(img/corners.gif)} .clearlooks2 .mceTop .mceCenter {right:6px; width:100%; height:23px; background:url(img/horizontal.gif) 12px 0; clip:rect(auto auto auto 12px)} .clearlooks2 .mceTop .mceRight {right:0; width:6px; height:23px; background:url(img/corners.gif) -12px 0} .clearlooks2 .mceTop span {width:100%; text-align:center; vertical-align:middle; line-height:23px; font-weight:bold} .clearlooks2 .mceFocus .mceTop .mceLeft {background:url(img/corners.gif) -6px 0} .clearlooks2 .mceFocus .mceTop .mceCenter {background:url(img/horizontal.gif) 0 -23px} .clearlooks2 .mceFocus .mceTop .mceRight {background:url(img/corners.gif) -18px 0} .clearlooks2 .mceFocus .mceTop span {color:#FFF} /* Middle */ .clearlooks2 .mceMiddle, .clearlooks2 .mceMiddle div {top:0} .clearlooks2 .mceMiddle {width:100%; height:100%; clip:rect(23px auto auto auto)} .clearlooks2 .mceMiddle .mceLeft {left:0; width:5px; height:100%; background:url(img/vertical.gif) -5px 0} .clearlooks2 .mceMiddle span {top:23px; left:5px; width:100%; height:100%; background:#FFF} .clearlooks2 .mceMiddle .mceRight {right:0; width:5px; height:100%; background:url(img/vertical.gif)} /* Bottom */ .clearlooks2 .mceBottom, .clearlooks2 .mceBottom div {height:6px} .clearlooks2 .mceBottom {left:0; bottom:0; width:100%} .clearlooks2 .mceBottom div {top:0} .clearlooks2 .mceBottom .mceLeft {left:0; width:5px; background:url(img/corners.gif) -34px -6px} .clearlooks2 .mceBottom .mceCenter {left:5px; width:100%; background:url(img/horizontal.gif) 0 -46px} .clearlooks2 .mceBottom .mceRight {right:0; width:5px; background: url(img/corners.gif) -34px 0} .clearlooks2 .mceBottom span {display:none} .clearlooks2 .mceStatusbar .mceBottom, .clearlooks2 .mceStatusbar .mceBottom div {height:23px} .clearlooks2 .mceStatusbar .mceBottom .mceLeft {background:url(img/corners.gif) -29px 0} .clearlooks2 .mceStatusbar .mceBottom .mceCenter {background:url(img/horizontal.gif) 0 -52px} .clearlooks2 .mceStatusbar .mceBottom .mceRight {background:url(img/corners.gif) -24px 0} .clearlooks2 .mceStatusbar .mceBottom span {display:block; left:7px; font-family:Arial, Verdana; font-size:11px; line-height:23px} /* Actions */ .clearlooks2 a {width:29px; height:16px; top:3px;} .clearlooks2 .mceClose {right:6px; background:url(img/buttons.gif) -87px 0} .clearlooks2 .mceMin {display:none; right:68px; background:url(img/buttons.gif) 0 0} .clearlooks2 .mceMed {display:none; right:37px; background:url(img/buttons.gif) -29px 0} .clearlooks2 .mceMax {display:none; right:37px; background:url(img/buttons.gif) -58px 0} .clearlooks2 .mceMove {display:none;width:100%;cursor:move;background:url(img/corners.gif) no-repeat -100px -100px} .clearlooks2 .mceMovable .mceMove {display:block} .clearlooks2 .mceFocus .mceClose {right:6px; background:url(img/buttons.gif) -87px -16px} .clearlooks2 .mceFocus .mceMin {right:68px; background:url(img/buttons.gif) 0 -16px} .clearlooks2 .mceFocus .mceMed {right:37px; background:url(img/buttons.gif) -29px -16px} .clearlooks2 .mceFocus .mceMax {right:37px; background:url(img/buttons.gif) -58px -16px} .clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px} .clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px} .clearlooks2 .mceFocus .mceMin:hover {right:68px; background:url(img/buttons.gif) 0 -32px} .clearlooks2 .mceFocus .mceMed:hover {right:37px; background:url(img/buttons.gif) -29px -32px} .clearlooks2 .mceFocus .mceMax:hover {right:37px; background:url(img/buttons.gif) -58px -32px} /* Resize */ .clearlooks2 .mceResize {top:auto; left:auto; display:none; width:5px; height:5px; background:url(img/horizontal.gif) no-repeat 0 -75px} .clearlooks2 .mceResizable .mceResize {display:block} .clearlooks2 .mceResizable .mceMin, .clearlooks2 .mceMax {display:none} .clearlooks2 .mceMinimizable .mceMin {display:block} .clearlooks2 .mceMaximizable .mceMax {display:block} .clearlooks2 .mceMaximized .mceMed {display:block} .clearlooks2 .mceMaximized .mceMax {display:none} .clearlooks2 a.mceResizeN {top:0; left:0; width:100%; cursor:n-resize} .clearlooks2 a.mceResizeNW {top:0; left:0; cursor:nw-resize} .clearlooks2 a.mceResizeNE {top:0; right:0; cursor:ne-resize} .clearlooks2 a.mceResizeW {top:0; left:0; height:100%; cursor:w-resize;} .clearlooks2 a.mceResizeE {top:0; right:0; height:100%; cursor:e-resize} .clearlooks2 a.mceResizeS {bottom:0; left:0; width:100%; cursor:s-resize} .clearlooks2 a.mceResizeSW {bottom:0; left:0; cursor:sw-resize} .clearlooks2 a.mceResizeSE {bottom:0; right:0; cursor:se-resize} /* Alert/Confirm */ .clearlooks2 .mceButton {font-weight:bold; bottom:10px; width:80px; height:30px; background:url(img/button.gif); line-height:30px; vertical-align:middle; text-align:center; outline:0} .clearlooks2 .mceMiddle .mceIcon {left:15px; top:35px; width:32px; height:32px} .clearlooks2 .mceAlert .mceMiddle span, .clearlooks2 .mceConfirm .mceMiddle span {background:transparent;left:60px; top:35px; width:320px; height:50px; font-weight:bold; overflow:auto; white-space:normal} .clearlooks2 a:hover {font-weight:bold;} .clearlooks2 .mceAlert .mceMiddle, .clearlooks2 .mceConfirm .mceMiddle {background:#D6D7D5} .clearlooks2 .mceAlert .mceOk {left:50%; top:auto; margin-left: -40px} .clearlooks2 .mceAlert .mceIcon {background:url(img/alert.gif)} .clearlooks2 .mceConfirm .mceOk {left:50%; top:auto; margin-left: -90px} .clearlooks2 .mceConfirm .mceCancel {left:50%; top:auto} .clearlooks2 .mceConfirm .mceIcon {background:url(img/confirm.gif)} /* IE9 fixes */ .clearlooks2.ie9 .mceTop .mceCenter {clip:auto;} .clearlooks2.ie9 .mceMiddle {clip:auto;} .clearlooks2.ie9 .mceMiddle .mceLeft, .clearlooks2.ie9 .mceMiddle .mceRight {top: 23px;} .clearlooks2.ie9 .mceAlert .mceMiddle span, .clearlooks2.ie9 .mceConfirm .mceMiddle span {top:13px;} .clearlooks2.ie9 .mceModal .mceMiddle {top:23px} .clearlooks2.ie9 .mceModal .mceMiddle .mceLeft, .clearlooks2.ie9 .mceModal .mceMiddle .mceRight {top: 0} .clearlooks2.ie9 .mceMiddle .mceIcon {top:13px} .clearlooks2.ie9 .mceTop .mceCenter {top:0; right:auto; left:6px; width:calc(100%-12px)} ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/editor_plugin_src.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/e0000644000175000017500000004214611526350530034023 0ustar frankiefrankie/** * editor_plugin_src.js * * Copyright 2009, Moxiecode Systems AB * Released under LGPL License. * * License: http://tinymce.moxiecode.com/license * Contributing: http://tinymce.moxiecode.com/contributing */ (function() { var DOM = tinymce.DOM, Element = tinymce.dom.Element, Event = tinymce.dom.Event, each = tinymce.each, is = tinymce.is; tinymce.create('tinymce.plugins.InlinePopups', { init : function(ed, url) { // Replace window manager ed.onBeforeRenderUI.add(function() { ed.windowManager = new tinymce.InlineWindowManager(ed); DOM.loadCSS(url + '/skins/' + (ed.settings.inlinepopups_skin || 'clearlooks2') + "/window.css"); }); }, getInfo : function() { return { longname : 'InlinePopups', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups', version : tinymce.majorVersion + "." + tinymce.minorVersion }; } }); tinymce.create('tinymce.InlineWindowManager:tinymce.WindowManager', { InlineWindowManager : function(ed) { var t = this; t.parent(ed); t.zIndex = 300000; t.count = 0; t.windows = {}; }, open : function(f, p) { var t = this, id, opt = '', ed = t.editor, dw = 0, dh = 0, vp, po, mdf, clf, we, w, u; f = f || {}; p = p || {}; // Run native windows if (!f.inline) return t.parent(f, p); // Only store selection if the type is a normal window if (!f.type) t.bookmark = ed.selection.getBookmark(1); id = DOM.uniqueId(); vp = DOM.getViewPort(); f.width = parseInt(f.width || 320); f.height = parseInt(f.height || 240) + (tinymce.isIE ? 8 : 0); f.min_width = parseInt(f.min_width || 150); f.min_height = parseInt(f.min_height || 100); f.max_width = parseInt(f.max_width || 2000); f.max_height = parseInt(f.max_height || 2000); f.left = f.left || Math.round(Math.max(vp.x, vp.x + (vp.w / 2.0) - (f.width / 2.0))); f.top = f.top || Math.round(Math.max(vp.y, vp.y + (vp.h / 2.0) - (f.height / 2.0))); f.movable = f.resizable = true; p.mce_width = f.width; p.mce_height = f.height; p.mce_inline = true; p.mce_window_id = id; p.mce_auto_focus = f.auto_focus; // Transpose // po = DOM.getPos(ed.getContainer()); // f.left -= po.x; // f.top -= po.y; t.features = f; t.params = p; t.onOpen.dispatch(t, f, p); if (f.type) { opt += ' mceModal'; if (f.type) opt += ' mce' + f.type.substring(0, 1).toUpperCase() + f.type.substring(1); f.resizable = false; } if (f.statusbar) opt += ' mceStatusbar'; if (f.resizable) opt += ' mceResizable'; if (f.minimizable) opt += ' mceMinimizable'; if (f.maximizable) opt += ' mceMaximizable'; if (f.movable) opt += ' mceMovable'; // Create DOM objects t._addAll(DOM.doc.body, ['div', {id : id, 'class' : (ed.settings.inlinepopups_skin || 'clearlooks2') + (tinymce.isIE && window.getSelection ? ' ie9' : ''), style : 'width:100px;height:100px'}, ['div', {id : id + '_wrapper', 'class' : 'mceWrapper' + opt}, ['div', {id : id + '_top', 'class' : 'mceTop'}, ['div', {'class' : 'mceLeft'}], ['div', {'class' : 'mceCenter'}], ['div', {'class' : 'mceRight'}], ['span', {id : id + '_title'}, f.title || ''] ], ['div', {id : id + '_middle', 'class' : 'mceMiddle'}, ['div', {id : id + '_left', 'class' : 'mceLeft'}], ['span', {id : id + '_content'}], ['div', {id : id + '_right', 'class' : 'mceRight'}] ], ['div', {id : id + '_bottom', 'class' : 'mceBottom'}, ['div', {'class' : 'mceLeft'}], ['div', {'class' : 'mceCenter'}], ['div', {'class' : 'mceRight'}], ['span', {id : id + '_status'}, 'Content'] ], ['a', {'class' : 'mceMove', tabindex : '-1', href : 'javascript:;'}], ['a', {'class' : 'mceMin', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], ['a', {'class' : 'mceMax', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], ['a', {'class' : 'mceMed', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], ['a', {'class' : 'mceClose', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], ['a', {id : id + '_resize_n', 'class' : 'mceResize mceResizeN', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_s', 'class' : 'mceResize mceResizeS', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_w', 'class' : 'mceResize mceResizeW', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_e', 'class' : 'mceResize mceResizeE', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_nw', 'class' : 'mceResize mceResizeNW', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_ne', 'class' : 'mceResize mceResizeNE', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_sw', 'class' : 'mceResize mceResizeSW', tabindex : '-1', href : 'javascript:;'}], ['a', {id : id + '_resize_se', 'class' : 'mceResize mceResizeSE', tabindex : '-1', href : 'javascript:;'}] ] ] ); DOM.setStyles(id, {top : -10000, left : -10000}); // Fix gecko rendering bug, where the editors iframe messed with window contents if (tinymce.isGecko) DOM.setStyle(id, 'overflow', 'auto'); // Measure borders if (!f.type) { dw += DOM.get(id + '_left').clientWidth; dw += DOM.get(id + '_right').clientWidth; dh += DOM.get(id + '_top').clientHeight; dh += DOM.get(id + '_bottom').clientHeight; } // Resize window DOM.setStyles(id, {top : f.top, left : f.left, width : f.width + dw, height : f.height + dh}); u = f.url || f.file; if (u) { if (tinymce.relaxedDomain) u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain; u = tinymce._addVer(u); } if (!f.type) { DOM.add(id + '_content', 'iframe', {id : id + '_ifr', src : 'javascript:""', frameBorder : 0, style : 'border:0;width:10px;height:10px'}); DOM.setStyles(id + '_ifr', {width : f.width, height : f.height}); DOM.setAttrib(id + '_ifr', 'src', u); } else { DOM.add(id + '_wrapper', 'a', {id : id + '_ok', 'class' : 'mceButton mceOk', href : 'javascript:;', onmousedown : 'return false;'}, 'Ok'); if (f.type == 'confirm') DOM.add(id + '_wrapper', 'a', {'class' : 'mceButton mceCancel', href : 'javascript:;', onmousedown : 'return false;'}, 'Cancel'); DOM.add(id + '_middle', 'div', {'class' : 'mceIcon'}); DOM.setHTML(id + '_content', f.content.replace('\n', '
    ')); } // Register events mdf = Event.add(id, 'mousedown', function(e) { var n = e.target, w, vp; w = t.windows[id]; t.focus(id); if (n.nodeName == 'A' || n.nodeName == 'a') { if (n.className == 'mceMax') { w.oldPos = w.element.getXY(); w.oldSize = w.element.getSize(); vp = DOM.getViewPort(); // Reduce viewport size to avoid scrollbars vp.w -= 2; vp.h -= 2; w.element.moveTo(vp.x, vp.y); w.element.resizeTo(vp.w, vp.h); DOM.setStyles(id + '_ifr', {width : vp.w - w.deltaWidth, height : vp.h - w.deltaHeight}); DOM.addClass(id + '_wrapper', 'mceMaximized'); } else if (n.className == 'mceMed') { // Reset to old size w.element.moveTo(w.oldPos.x, w.oldPos.y); w.element.resizeTo(w.oldSize.w, w.oldSize.h); w.iframeElement.resizeTo(w.oldSize.w - w.deltaWidth, w.oldSize.h - w.deltaHeight); DOM.removeClass(id + '_wrapper', 'mceMaximized'); } else if (n.className == 'mceMove') return t._startDrag(id, e, n.className); else if (DOM.hasClass(n, 'mceResize')) return t._startDrag(id, e, n.className.substring(13)); } }); clf = Event.add(id, 'click', function(e) { var n = e.target; t.focus(id); if (n.nodeName == 'A' || n.nodeName == 'a') { switch (n.className) { case 'mceClose': t.close(null, id); return Event.cancel(e); case 'mceButton mceOk': case 'mceButton mceCancel': f.button_func(n.className == 'mceButton mceOk'); return Event.cancel(e); } } }); // Add window w = t.windows[id] = { id : id, mousedown_func : mdf, click_func : clf, element : new Element(id, {blocker : 1, container : ed.getContainer()}), iframeElement : new Element(id + '_ifr'), features : f, deltaWidth : dw, deltaHeight : dh }; w.iframeElement.on('focus', function() { t.focus(id); }); // Setup blocker if (t.count == 0 && t.editor.getParam('dialog_type', 'modal') == 'modal') { DOM.add(DOM.doc.body, 'div', { id : 'mceModalBlocker', 'class' : (t.editor.settings.inlinepopups_skin || 'clearlooks2') + '_modalBlocker', style : {zIndex : t.zIndex - 1} }); DOM.show('mceModalBlocker'); // Reduces flicker in IE } else DOM.setStyle('mceModalBlocker', 'z-index', t.zIndex - 1); if (tinymce.isIE6 || /Firefox\/2\./.test(navigator.userAgent) || (tinymce.isIE && !DOM.boxModel)) DOM.setStyles('mceModalBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2}); t.focus(id); t._fixIELayout(id, 1); // Focus ok button if (DOM.get(id + '_ok')) DOM.get(id + '_ok').focus(); t.count++; return w; }, focus : function(id) { var t = this, w; if (w = t.windows[id]) { w.zIndex = this.zIndex++; w.element.setStyle('zIndex', w.zIndex); w.element.update(); id = id + '_wrapper'; DOM.removeClass(t.lastId, 'mceFocus'); DOM.addClass(id, 'mceFocus'); t.lastId = id; } }, _addAll : function(te, ne) { var i, n, t = this, dom = tinymce.DOM; if (is(ne, 'string')) te.appendChild(dom.doc.createTextNode(ne)); else if (ne.length) { te = te.appendChild(dom.create(ne[0], ne[1])); for (i=2; i ix) { fw = w; ix = w.zIndex; } }); if (fw) t.focus(fw.id); } }, setTitle : function(w, ti) { var e; w = this._findId(w); if (e = DOM.get(w + '_title')) e.innerHTML = DOM.encode(ti); }, alert : function(txt, cb, s) { var t = this, w; w = t.open({ title : t, type : 'alert', button_func : function(s) { if (cb) cb.call(s || t, s); t.close(null, w.id); }, content : DOM.encode(t.editor.getLang(txt, txt)), inline : 1, width : 400, height : 130 }); }, confirm : function(txt, cb, s) { var t = this, w; w = t.open({ title : t, type : 'confirm', button_func : function(s) { if (cb) cb.call(s || t, s); t.close(null, w.id); }, content : DOM.encode(t.editor.getLang(txt, txt)), inline : 1, width : 400, height : 130 }); }, // Internal functions _findId : function(w) { var t = this; if (typeof(w) == 'string') return w; each(t.windows, function(wo) { var ifr = DOM.get(wo.id + '_ifr'); if (ifr && w == ifr.contentWindow) { w = wo.id; return false; } }); return w; }, _fixIELayout : function(id, s) { var w, img; if (!tinymce.isIE6) return; // Fixes the bug where hover flickers and does odd things in IE6 each(['n','s','w','e','nw','ne','sw','se'], function(v) { var e = DOM.get(id + '_resize_' + v); DOM.setStyles(e, { width : s ? e.clientWidth : '', height : s ? e.clientHeight : '', cursor : DOM.getStyle(e, 'cursor', 1) }); DOM.setStyle(id + "_bottom", 'bottom', '-1px'); e = 0; }); // Fixes graphics glitch if (w = this.windows[id]) { // Fixes rendering bug after resize w.element.hide(); w.element.show(); // Forced a repaint of the window //DOM.get(id).style.filter = ''; // IE has a bug where images used in CSS won't get loaded // sometimes when the cache in the browser is disabled // This fix tries to solve it by loading the images using the image object each(DOM.select('div,a', id), function(e, i) { if (e.currentStyle.backgroundImage != 'none') { img = new Image(); img.src = e.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/, '$1'); } }); DOM.get(id).style.filter = ''; } } }); // Register plugin tinymce.PluginManager.add('inlinepopups', tinymce.plugins.InlinePopups); })(); ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/template.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/inlinepopups/t0000644000175000017500000003111611201067036034031 0ustar frankiefrankie Template for dialogs
    Blured
    Content
    Statusbar text.
    Focused
    Content
    Statusbar text.
    Statusbar
    Content
    Statusbar text.
    Statusbar, Resizable
    Content
    Statusbar text.
    Resizable, Maximizable
    Content
    Statusbar text.
    Blurred, Maximizable, Statusbar, Resizable
    Content
    Statusbar text.
    Maximized, Maximizable, Minimizable
    Content
    Statusbar text.
    Blured
    Content
    Statusbar text.
    Alert
    This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message.
    Ok
    Confirm
    This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message. This is a very long error message.
    Ok Cancel
    openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/0000755000175000017500000000000011724401447032723 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/js/0000755000175000017500000000000011724401447033337 5ustar frankiefrankie././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/js/fullpage.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/js/fu0000644000175000017500000003674211526350530033704 0ustar frankiefrankie/** * fullpage.js * * Copyright 2009, Moxiecode Systems AB * Released under LGPL License. * * License: http://tinymce.moxiecode.com/license * Contributing: http://tinymce.moxiecode.com/contributing */ tinyMCEPopup.requireLangPack(); var doc; var defaultDocTypes = 'XHTML 1.0 Transitional=,' + 'XHTML 1.0 Frameset=,' + 'XHTML 1.0 Strict=,' + 'XHTML 1.1=,' + 'HTML 4.01 Transitional=,' + 'HTML 4.01 Strict=,' + 'HTML 4.01 Frameset='; var defaultEncodings = 'Western european (iso-8859-1)=iso-8859-1,' + 'Central European (iso-8859-2)=iso-8859-2,' + 'Unicode (UTF-8)=utf-8,' + 'Chinese traditional (Big5)=big5,' + 'Cyrillic (iso-8859-5)=iso-8859-5,' + 'Japanese (iso-2022-jp)=iso-2022-jp,' + 'Greek (iso-8859-7)=iso-8859-7,' + 'Korean (iso-2022-kr)=iso-2022-kr,' + 'ASCII (us-ascii)=us-ascii'; var defaultMediaTypes = 'all=all,' + 'screen=screen,' + 'print=print,' + 'tty=tty,' + 'tv=tv,' + 'projection=projection,' + 'handheld=handheld,' + 'braille=braille,' + 'aural=aural'; var defaultFontNames = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings'; var defaultFontSizes = '10px,11px,12px,13px,14px,15px,16px'; function init() { var f = document.forms['fullpage'], el = f.elements, e, i, p, doctypes, encodings, mediaTypes, fonts, ed = tinyMCEPopup.editor, dom = tinyMCEPopup.dom, style; // Setup doctype select box doctypes = ed.getParam("fullpage_doctypes", defaultDocTypes).split(','); for (i=0; i 1) addSelectValue(f, 'doctypes', p[0], p[1]); } // Setup fonts select box fonts = ed.getParam("fullpage_fonts", defaultFontNames).split(';'); for (i=0; i 1) addSelectValue(f, 'fontface', p[0], p[1]); } // Setup fontsize select box fonts = ed.getParam("fullpage_fontsizes", defaultFontSizes).split(','); for (i=0; i 1) { addSelectValue(f, 'element_style_media', p[0], p[1]); addSelectValue(f, 'element_link_media', p[0], p[1]); } } // Setup encodings select box encodings = ed.getParam("fullpage_encodings", defaultEncodings).split(','); for (i=0; i 1) { addSelectValue(f, 'docencoding', p[0], p[1]); addSelectValue(f, 'element_script_charset', p[0], p[1]); addSelectValue(f, 'element_link_charset', p[0], p[1]); } } document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor'); document.getElementById('link_color_pickcontainer').innerHTML = getColorPickerHTML('link_color_pick','link_color'); //document.getElementById('hover_color_pickcontainer').innerHTML = getColorPickerHTML('hover_color_pick','hover_color'); document.getElementById('visited_color_pickcontainer').innerHTML = getColorPickerHTML('visited_color_pick','visited_color'); document.getElementById('active_color_pickcontainer').innerHTML = getColorPickerHTML('active_color_pick','active_color'); document.getElementById('textcolor_pickcontainer').innerHTML = getColorPickerHTML('textcolor_pick','textcolor'); document.getElementById('stylesheet_browsercontainer').innerHTML = getBrowserHTML('stylesheetbrowser','stylesheet','file','fullpage'); document.getElementById('link_href_pickcontainer').innerHTML = getBrowserHTML('link_href_browser','element_link_href','file','fullpage'); document.getElementById('script_src_pickcontainer').innerHTML = getBrowserHTML('script_src_browser','element_script_src','file','fullpage'); document.getElementById('bgimage_pickcontainer').innerHTML = getBrowserHTML('bgimage_browser','bgimage','image','fullpage'); // Resize some elements if (isVisible('stylesheetbrowser')) document.getElementById('stylesheet').style.width = '220px'; if (isVisible('link_href_browser')) document.getElementById('element_link_href').style.width = '230px'; if (isVisible('bgimage_browser')) document.getElementById('bgimage').style.width = '210px'; // Add iframe dom.add(document.body, 'iframe', {id : 'documentIframe', src : 'javascript:""', style : {display : 'none'}}); doc = dom.get('documentIframe').contentWindow.document; h = tinyMCEPopup.getWindowArg('head_html'); // Preprocess the HTML disable scripts and urls h = h.replace(/
    {#fullpage_dlg.meta_props}
     
     
     
     
     
     
    {#fullpage_dlg.langprops}
     
     
     
    {#fullpage_dlg.appearance_textprops}
     
    {#fullpage_dlg.appearance_bgprops}
     
     
    {#fullpage_dlg.appearance_marginprops}
    {#fullpage_dlg.appearance_linkprops}
     
     
       
    {#fullpage_dlg.appearance_style}
     
    {#fullpage_dlg.head_elements}

    {#fullpage_dlg.meta_element}
    {#fullpage_dlg.title_element}
    {#fullpage_dlg.script_element}
     
    {#fullpage_dlg.style_element}
    {#fullpage_dlg.base_element}
    {#fullpage_dlg.comment_element}
    ././@LongLink0000000000000000000000000000016000000000000011562 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/edito0000644000175000017500000000553711526350527033766 0ustar frankiefrankie(function(){tinymce.create("tinymce.plugins.FullPagePlugin",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceFullPageProperties",function(){a.windowManager.open({file:b+"/fullpage.htm",width:430+parseInt(a.getLang("fullpage.delta_width",0)),height:495+parseInt(a.getLang("fullpage.delta_height",0)),inline:1},{plugin_url:b,head_html:c.head})});a.addButton("fullpage",{title:"fullpage.desc",cmd:"mceFullPageProperties"});a.onBeforeSetContent.add(c._setContent,c);a.onSetContent.add(c._setBodyAttribs,c);a.onGetContent.add(c._getContent,c)},getInfo:function(){return{longname:"Fullpage",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_setBodyAttribs:function(d,a){var l,c,e,g,b,h,j,f=this.head.match(/body(.*?)>/i);if(f&&f[1]){l=f[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g);if(l){for(c=0,e=l.length;c",a);h.head=f.substring(0,a+1);j=f.indexOf("\n'}h.head+=d.getParam("fullpage_default_doctype",'');h.head+="\n\n\n"+d.getParam("fullpage_default_title","Untitled document")+"\n";if(g=d.getParam("fullpage_default_encoding")){h.head+='\n'}if(g=d.getParam("fullpage_default_font_family")){i+="font-family: "+g+";"}if(g=d.getParam("fullpage_default_font_size")){i+="font-size: "+g+";"}if(g=d.getParam("fullpage_default_text_color")){i+="color: "+g+";"}h.head+="\n\n";h.foot="\n\n"}},_getContent:function(a,c){var b=this;if(!c.source_view||!a.getParam("fullpage_hide_in_source_view")){c.content=tinymce.trim(b.head)+"\n"+tinymce.trim(c.content)+"\n"+tinymce.trim(b.foot)}}});tinymce.PluginManager.add("fullpage",tinymce.plugins.FullPagePlugin)})();././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000755000175000017500000000000011575225637033761 5ustar frankiefrankie././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/sc_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000521511526350530033751 0ustar frankiefrankietinyMCE.addI18n('sc.fullpage_dlg',{title:"\u6863\u5c5e\u6027",meta_tab:"\u4e00\u822c",appearance_tab:"\u5916\u89c2",advanced_tab:"\u9ad8\u7ea7",meta_props:"\u6807\u7b7e( Meta )\u4fe1\u606f",langprops:"\u8bed\u8a00\u4e0e\u7f16\u7801",meta_title:"\u6807\u9898",meta_keywords:"\u5173\u952e\u5b57",meta_description:"\u5185\u5bb9\u8bf4\u660e",meta_robots:"Robots",doctypes:"Doctype",langcode:"\u8bed\u8a00\u7f16\u7801",langdir:"\u8bed\u8a00\u4e66\u5199\u65b9\u5411",ltr:"\u7531\u5de6\u5230\u53f3",rtl:"\u7531\u53f3\u5230\u5de6",xml_pi:"XML\u5ba3\u544a",encoding:"\u5b57\u5143\u7f16\u7801",appearance_bgprops:"\u80cc\u666f\u5c5e\u6027",appearance_marginprops:"Body margins",appearance_linkprops:"\u8fde\u7ed3\u989c\u8272",appearance_textprops:"\u6587\u672c\u5c5e\u6027",bgcolor:"\u80cc\u666f\u989c\u8272",bgimage:"\u80cc\u666f\u56fe\u7247",left_margin:"\u5de6\u8fb9\u754c",right_margin:"\u53f3\u8fb9\u754c",top_margin:"\u4e0a\u8fb9\u754c",bottom_margin:"\u4e0b\u8fb9\u754c",text_color:"\u6587\u5b57\u989c\u8272",font_size:"\u5b57\u4f53\u5c3a\u5bf8",font_face:"\u5b57\u4f53",link_color:"\u8fde\u7ed3\u989c\u8272",hover_color:"Hover\u989c\u8272",visited_color:"Visited\u989c\u8272",active_color:"Active\u989c\u8272",textcolor:"\u989c\u8272",fontsize:"\u5b57\u4f53\u5927\u5c0f",fontface:"\u5b57\u5f62\u4f53\u7cfb",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"\u6837\u5f0f\u8868\u5355\u53ca\u6837\u5f0f\u5c5e\u6027",stylesheet:"\u6837\u5f0f\u8868\u5355",style:"\u6837\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6743",add:"\u6dfb\u52a0\u65b0\u5143\u7d20",remove:"\u79fb\u9664\u9009\u5b9a\u5143\u7d20",moveup:"\u4e0a\u79fb\u9009\u5b9a\u5143\u7d20",movedown:"\u4e0b\u79fb\u9009\u5b9a\u5143\u7d20",head_elements:"Head elements",info:"\u4fe1\u606f",add_title:"\u67e5\u627e\u5143\u7d20",add_meta:"Meta\u5143\u7d20",add_script:"Script\u5143\u7d20",add_style:"Style\u5143\u7d20",add_link:"Link\u5143\u7d20",add_base:"Base\u5143\u7d20",add_comment:"Comment node",title_element:"\u67e5\u627eelement",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"\u8bed\u8a00",href:"Href",target:"\u76ee\u6807",type:"\u7c7b\u578b",charset:"\u5b57\u5143\u96c6",defer:"\u5ef6\u7f13",media:"\u5a92\u4f53",properties:"\u5c5e\u6027",name:"\u540d\u79f0",value:"\u503c",content:"\u5185\u5bb9",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u4e00\u822c",advanced_props:"\u9ad8\u7ea7"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ia_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000541111526350530033747 0ustar frankiefrankietinyMCE.addI18n('ia.fullpage_dlg',{title:"\u6863\u6848\u5c5e\u6027",meta_tab:"\u57fa\u672c",appearance_tab:"\u5916\u89c2",advanced_tab:"\u9ad8\u7ea7",meta_props:"\u4e2d\u7ee7\u6570\u636e\u5377\u6807\u5c5e\u6027",langprops:"\u8bed\u8a00",meta_title:"\u6807\u9898",meta_keywords:"\u5173\u952e\u8bcd",meta_description:"\u5185\u5bb9\u8bf4\u660e",meta_robots:"\u673a\u5668\u4eba",doctypes:"DocType",langcode:"\u8bed\u8a00\u7f16\u7801",langdir:"\u8bed\u8a00\u4e66\u5199\u65b9\u5411",ltr:"\u4ece\u5de6\u5230\u53f3",rtl:"\u4ece\u53f3\u5230\u5de6",xml_pi:"XML \u58f0\u660e",encoding:"\u5b57\u7b26\u7f16\u7801",appearance_bgprops:"\u80cc\u666f\u5c5e\u6027",appearance_marginprops:"\u8fb9\u8ddd",appearance_linkprops:"\u8fde\u7ed3\u989c\u8272",appearance_textprops:"\u6587\u5b57\u5c5e\u6027",bgcolor:"\u80cc\u666f\u989c\u8272",bgimage:"\u80cc\u666f\u56fe\u7247",left_margin:"\u5de6\u8fb9\u8ddd",right_margin:"\u53f3\u8fb9\u8ddd",top_margin:"\u4e0a\u8fb9\u8ddd",bottom_margin:"\u4e0b\u8fb9\u8ddd",text_color:"\u6587\u5b57\u989c\u8272",font_size:"\u6587\u5b57\u5927\u5c0f",font_face:"\u5b57\u4f53",link_color:"\u8fde\u7ed3\u989c\u8272",hover_color:"Hover \u989c\u8272",visited_color:"Visited \u989c\u8272",active_color:"Active \u989c\u8272",textcolor:"\u989c\u8272",fontsize:"\u6587\u5b57\u5927\u5c0f",fontface:"\u5b57\u4f53",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"\u6837\u5f0f\u8868\u5c5e\u6027",stylesheet:"\u6837\u5f0f\u8868",style:"\u6837\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6743",add:"\u6dfb\u52a0\u65b0\u5bf9\u8c61",remove:"\u5220\u9664\u9009\u62e9\u7684\u5bf9\u8c61",moveup:"\u5411\u4e0a\u79fb\u52a8\u9009\u62e9\u7684\u5bf9\u8c61",movedown:"\u5411\u4e0b\u79fb\u52a8\u9009\u62e9\u7684\u5bf9\u8c61",head_elements:"\u5934\u5bf9\u8c61",info:"\u4fe1\u606f",add_title:"\u67e5\u627e\u5bf9\u8c61",add_meta:"\u5143\u5bf9\u8c61",add_script:"\u811a\u672c\u5bf9\u8c61",add_style:"\u6837\u5f0f\u5bf9\u8c61",add_link:"\u8fde\u7ed3\u5316\u5bf9\u8c61",add_base:"Base\u5bf9\u8c61",add_comment:"\u6ce8\u91ca\u5bf9\u8c61",title_element:"\u67e5\u627e\u5bf9\u8c61",script_element:"\u811a\u672c\u5bf9\u8c61",style_element:"\u6837\u5f0f\u5bf9\u8c61",base_element:"Base\u5bf9\u8c61",link_element:"\u8fde\u7ed3\u5316\u5bf9\u8c61",meta_element:"\u5143\u5bf9\u8c61",comment_element:"\u6ce8\u91ca\u5bf9\u8c61",src:"Src",language:"\u8bed\u8a00",href:"Href",target:"\u76ee\u6807",type:"\u7c7b\u578b",charset:"\u5b57\u7b26\u96c6",defer:"Defer",media:"\u5a92\u4f53",properties:"\u5c5e\u6027",name:"\u540d",value:"\u503c",content:"\u5185\u5bb9",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u57fa\u672c",advanced_props:"\u9ad8\u7ea7"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/cy_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000427211526350530033753 0ustar frankiefrankietinyMCE.addI18n('cy.fullpage_dlg',{title:"Priodweddau dogfen",meta_tab:"Cyffredinol",appearance_tab:"Ymddangosiad",advanced_tab:"Uwch",meta_props:"Gwybodaeth meta",langprops:"Iaith ac amgodiad",meta_title:"Teitl",meta_keywords:"Allweddair",meta_description:"Disgrifiad",meta_robots:"Robotau",doctypes:"Math dogfen",langcode:"Cod iaith",langdir:"Cyfeiriad iaith",ltr:"Chwith i\'r dde",rtl:"De i\'r chwith",xml_pi:"Datganiad XML",encoding:"Amgodiad nodau",appearance_bgprops:"Priodweddau cefndir",appearance_marginprops:"Ymylon corff",appearance_linkprops:"Lliwiau cysylltau",appearance_textprops:"Priodweddau testun",bgcolor:"Lliw cefndir",bgimage:"Delwedd cefndir",left_margin:"Ymyl chwith",right_margin:"Ymyl dde",top_margin:"Ymyl brig",bottom_margin:"Ymyl gwaelod",text_color:"Lliw testun",font_size:"Maint ffont",font_face:"Wyneb ffont",link_color:"Lliw cysylltau",hover_color:"Lliw hofran",visited_color:"Lliw ymwelwyd",active_color:"Lliw actif",textcolor:"Lliw",fontsize:"Maint ffont",fontface:"Teulu ffont",meta_index_follow:"Mynegeio a ddilyn y cysylltau",meta_index_nofollow:"Mynegeio a peidio ddilyn y cysylltau",meta_noindex_follow:"Peidio mynegeio ond ddilyn y cysylltau",meta_noindex_nofollow:"Peidio mynegeio a peidio ddilyn y cysylltau",appearance_style:"Priodweddau dalen-arddull ac arddull",stylesheet:"Dalen-arddull",style:"Arddull",author:"Awdur",copyright:"Hawlfraint",add:"Ychwanegu elfen newydd",remove:"Tynnu elfen dewisedig",moveup:"Symud elfen dewisedig i fyny",movedown:"Symud elfen dewisedig i lawr",head_elements:"Elfennau pen",info:"Gwybodaeth",add_title:"Elfen teitl",add_meta:"Elfen meta",add_script:"Elfen sgript",add_style:"Elfen arddull",add_link:"Elfen cyswllt",add_base:"Elfen sail",add_comment:"Nod sylw",title_element:"Elfen teitl",script_element:"Elfen sgript",style_element:"Elfen arddull",base_element:"Elfen sail",link_element:"Elfen cyswllt",meta_element:"Elfen meta",comment_element:"Sylw",src:"Fynhonell",language:"Iaith",href:"Href",target:"Targed",type:"Math",charset:"Set nodau",defer:"Gohirio",media:"Cyfryngau",properties:"Priodweddau",name:"Enw",value:"Gwerth",content:"Cynnwys",rel:"Perthynas",rev:"Diwygiad",hreflang:"Iaith href",general_props:"Cyfferdinol",advanced_props:"Uwch"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/sr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000432211526350530033747 0ustar frankiefrankietinyMCE.addI18n('sr.fullpage_dlg',{title:"Svojstva dokumenta",meta_tab:"Osnovno",appearance_tab:"Izgled",advanced_tab:"Napredno",meta_props:"Meta informacije",langprops:"Jezik i kodiranje",meta_title:"Naslov",meta_keywords:"Klju\u010dne re\u010di",meta_description:"Opis",meta_robots:"Robots",doctypes:"Doctype",langcode:"Kod jezika",langdir:"Smjer jezika",ltr:"S leva na desno",rtl:"S desna na levo",xml_pi:"XML deklaracija",encoding:"Kodiranje znakova",appearance_bgprops:"Svojstva pozadine",appearance_marginprops:"Margina",appearance_linkprops:"Boja linka",appearance_textprops:"Svojstva teksta",bgcolor:"Boja pozadine",bgimage:"Pozadinska slika",left_margin:"Leva margina",right_margin:"Desna margina",top_margin:"Gornja margina",bottom_margin:"Donja margina",text_color:"Boja teksta",font_size:"Veli\u010dina pisma",font_face:"Pismo",link_color:"Boja linka",hover_color:"Boja linka ispod mi\u0161a",visited_color:"Boja posje\u0107enog linka",active_color:"Boja aktivnog linka",textcolor:"Boja",fontsize:"Veli\u010dina pisma",fontface:"Skupina pisama",meta_index_follow:"Indeksiraj i sledi linkove",meta_index_nofollow:"Indeksiraj i ne sledi linkove",meta_noindex_follow:"Ne indeksiraj i sledi linkove",meta_noindex_nofollow:"Ne indeksiraj i ne sledi linkove",appearance_style:"CSS i svojstva stila",stylesheet:"CSS",style:"Stil",author:"Autor",copyright:"Autorska prava",add:"Dodaj novi element",remove:"Ukloni odabrani element",moveup:"Pomakni odabrani element prema gore",movedown:"Pomakni odabrani element prema dolje",head_elements:"Zaglavni elementi",info:"Informacije",add_title:"Naslovni element",add_meta:"Meta element",add_script:"Skriptni element",add_style:"Sitlski element",add_link:"Element linka",add_base:"Osnovni element",add_comment:"Komentar",title_element:"Naslovni element",script_element:"Skriptni element",style_element:"Stilski element",base_element:"Osnovni element",link_element:"Element linka",meta_element:"Meta element",comment_element:"Komentar",src:"Src",language:"Jezik",href:"Href",target:"Meta",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Svojstva",name:"Ime",value:"Vrednost",content:"Sadr\u017eaj",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Osnovno",advanced_props:"Napredno"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/mn_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001431011526350530033745 0ustar frankiefrankietinyMCE.addI18n('mn.fullpage_dlg',{title:"\u0411\u0430\u0440\u0438\u043c\u0442\u044b\u043d \u0442\u043e\u0434\u0440\u0443\u0443\u043b\u0433\u0430",meta_tab:"\u0415\u0440\u04e9\u043d\u0445\u0438\u0439",appearance_tab:"\u0425\u0430\u0440\u0430\u0433\u0434\u0430\u0446",advanced_tab:"\u04e8\u0440\u0433\u04e9\u0442\u0433\u04e9\u0441\u04e9\u043d",meta_props:"Meta-\u043c\u044d\u0434\u044d\u044d\u043b\u044d\u043b",langprops:"\u0425\u044d\u043b \u0431\u0430 \u043a\u043e\u0434\u0447\u0438\u043b\u043e\u043b",meta_title:"\u0413\u0430\u0440\u0447\u0438\u0433",meta_keywords:"Keywords",meta_description:"\u0422\u0430\u0439\u043b\u0431\u0430\u0440",meta_robots:"Robots",doctypes:"DocType",langcode:"\u0425\u044d\u043b\u043d\u0438\u0439 \u043a\u043e\u0434",langdir:"\u0425\u044d\u043b\u043d\u0438\u0439 \u0447\u0438\u0433\u043b\u044d\u043b",ltr:"\u0417\u04af\u04af\u043d\u044d\u044d\u0441 \u0431\u0430\u0440\u0443\u0443\u043d",rtl:"\u0411\u0430\u0440\u0443\u0443\u043d\u0430\u0430\u0441 \u0437\u04af\u04af\u043d",xml_pi:"XML \u0442\u043e\u0434\u043e\u0440\u0445\u043e\u0439\u043b\u043e\u043b\u0442",encoding:"\u0422\u044d\u043c\u0434\u044d\u0433\u0442 \u043a\u043e\u0434\u0447\u0438\u043b\u043e\u043b",appearance_bgprops:"\u0414\u044d\u0432\u0441\u0433\u044d\u0440\u0438\u0439\u043d \u0448\u0438\u043d\u0436\u04af\u04af\u0434",appearance_marginprops:"\u042d\u0445 \u0431\u0438\u0435\u0438\u0439\u043d \u044d\u043c\u0436\u044d\u044d\u0440",appearance_linkprops:"\u0425\u043e\u043b\u0431\u043e\u043e\u0441\u044b\u043d \u04e9\u043d\u0433\u04e9",appearance_textprops:"\u0411\u0438\u0447\u0432\u044d\u0440\u0438\u0439\u043d \u0448\u0438\u043d\u0436\u04af\u04af\u0434",bgcolor:"\u0414\u044d\u0432\u0441\u0433\u044d\u0440 \u04e9\u043d\u0433\u04e9",bgimage:"\u0414\u044d\u0432\u0441\u0433\u044d\u0440 \u0437\u0443\u0440\u0430\u0433",left_margin:"\u0417\u04af\u04af\u043d \u0430\u043b\u0441\u043b\u0430\u043b\u0442",right_margin:"\u0411\u0430\u0440\u0443\u0443\u043d \u0430\u043b\u0441\u043b\u0430\u043b\u0442",top_margin:"\u0414\u044d\u044d\u0434 \u0430\u043b\u0441\u043b\u0430\u043b\u0442",bottom_margin:"\u0414\u043e\u043e\u0434 \u0430\u043b\u0441\u043b\u0430\u043b\u0442",text_color:"\u0411\u0438\u0447\u0432\u044d\u0440\u0438\u0439\u043d \u04e9\u043d\u0433\u04e9",font_size:"\u0411\u0438\u0447\u0433\u0438\u0439\u043d \u0445\u044d\u043c\u0436\u044d\u044d",font_face:"\u0424\u043e\u043d\u0442",link_color:"\u0425\u043e\u043b\u0431\u043e\u043e\u0441\u044b\u043d \u04e9\u043d\u0433\u04e9",hover_color:"\u0414\u044d\u044d\u0440 \u043d\u044c \u0445\u04af\u0440\u044d\u0445 \u04e9\u043d\u0433\u04e9",visited_color:"\u0417\u043e\u0447\u0438\u043b\u0441\u043e\u043d \u04e9\u043d\u0433\u04e9",active_color:"\u0418\u0434\u044d\u0432\u0445\u0442\u044d\u0439 \u04e9\u043d\u0433\u04e9",textcolor:"\u04e8\u043d\u0433\u04e9",fontsize:"\u0411\u0438\u0447\u0433\u0438\u0439\u043d \u0445\u044d\u043c\u0436\u044d\u044d",fontface:"\u0424\u043e\u043d\u0442",meta_index_follow:"\u0418\u043d\u0434\u0435\u043a\u0441\u043b\u044d\u044d\u0434 \u0434\u0430\u0433\u0430\u043d\u0430",meta_index_nofollow:"\u0418\u043d\u0434\u0435\u043a\u0441\u043b\u044d\u044d\u0434 \u0434\u0430\u0433\u0430\u0445\u0433\u04af\u0439",meta_noindex_follow:"\u0418\u043d\u0434\u0435\u043a\u0441\u043b\u044d\u0445\u0433\u04af\u0439 \u0434\u0430\u0433\u0430\u043d\u0430",meta_noindex_nofollow:"\u0418\u043d\u0434\u0435\u043a\u0441\u043b\u044d\u0445\u0433\u04af\u0439 \u0434\u0430\u0433\u0430\u0445\u0433\u04af\u0439",appearance_style:"CSS-Stylesheet \u0431\u0430 \u0445\u044d\u043b\u0431\u044d\u0440\u0436\u04af\u04af\u043b\u044d\u043b\u0442",stylesheet:"CSS-Stylesheet",style:"CSS-Stil",author:"\u0417\u043e\u0445\u0438\u043e\u0433\u0447",copyright:"\u0417\u043e\u0445\u0438\u043e\u0433\u0447\u0438\u0439\u043d \u044d\u0440\u0445",add:"\u0428\u0438\u043d\u044d \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u044d\u043c\u044d\u0445",remove:"\u0421\u043e\u043d\u0433\u043e\u0441\u043e\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0439\u0433 \u0443\u0441\u0442\u0433\u0430\u0445",moveup:"\u0421\u043e\u043d\u0433\u043e\u0441\u043e\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0439\u0433 \u0434\u044d\u044d\u0448 \u0445\u04e9\u0434\u04e9\u043b\u0433\u04e9\u0445",movedown:"\u0421\u043e\u043d\u0433\u043e\u0441\u043e\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0439\u0433 \u0434\u043e\u043e\u0448 \u0445\u04e9\u0434\u04e9\u043b\u0433\u04e9\u0445",head_elements:"\u0413\u0430\u0440\u0447\u0438\u0433 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",info:"\u041c\u044d\u0434\u044d\u044d\u043b\u044d\u043b",add_title:"\u0413\u0430\u0440\u0447\u0438\u0433-\u044d\u043b\u0435\u043c\u0435\u043d\u0442",add_meta:"Meta-\u044d\u043b\u0435\u043c\u0435\u043d\u0442",add_script:"\u0421\u043a\u0440\u0438\u043f\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",add_style:"\u0417\u0430\u0433\u0432\u0430\u0440 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",add_link:"\u0425\u043e\u043b\u0431\u043e\u043e\u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",add_base:"\u0421\u0443\u0443\u0440\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442",add_comment:"HTML-\u0442\u0430\u0439\u043b\u0431\u0430\u0440",title_element:"\u0411\u0438\u0447\u0432\u044d\u0440 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",script_element:"Script-\u044d\u043b\u0435\u043c\u0435\u043d\u0442",style_element:"Style-\u044d\u043b\u0435\u043c\u0435\u043d\u0442",base_element:"\u0421\u0443\u0443\u0440\u044c-\u044d\u043b\u0435\u043c\u0435\u043d\u0442",link_element:"\u0417\u04af\u04af\u043d-\u044d\u043b\u0435\u043c\u0435\u043d\u0442",meta_element:"\u0411\u0430\u0440\u0443\u0443\u043d",comment_element:"\u0422\u0430\u0439\u043b\u0431\u0430\u0440",src:"\u042d\u0445",language:"\u0425\u044d\u043b",href:"Href",target:"\u0422\u043e\u0432\u043b\u043e\u0441\u043e\u043d",type:"\u0422\u04e9\u0440\u04e9\u043b",charset:"\u0422\u044d\u043c\u0434\u044d\u0433\u0442\u0438\u0439\u043d \u043e\u043b\u043e\u043d\u043b\u043e\u0433",defer:"Defer",media:"\u041c\u0435\u0434\u0438\u0430",properties:"\u0422\u043e\u0434\u0440\u0443\u0443\u043b\u0433\u0430",name:"\u041d\u044d\u0440",value:"\u0423\u0442\u0433\u0430",content:"\u0410\u0433\u0443\u0443\u043b\u0433\u0430",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u0415\u0440\u04e9\u043d\u0445\u0438\u0439",advanced_props:"\u04e8\u0440\u0433\u04e9\u0442\u0433\u04e9\u0441\u04e9\u043d"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/fi_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000462111526350530033751 0ustar frankiefrankietinyMCE.addI18n('fi.fullpage_dlg',{title:"Tiedoston asetukset",meta_tab:"Yleinen",appearance_tab:"Ulkoasu",advanced_tab:"Edistynyt",meta_props:"Metatiedot",langprops:"Kieli ja koodaus",meta_title:"Otsikko",meta_keywords:"Avainsanat",meta_description:"Kuvaus",meta_robots:"Robotit",doctypes:"Dokumenttityypit",langcode:"Kielen koodi",langdir:"Kielen suunta",ltr:"Vasemmalta oikealle",rtl:"Oikealta vasemmalle",xml_pi:"XML-ilmoitus",encoding:"Tekstin koodaus",appearance_bgprops:"Taustan asetukset",appearance_marginprops:"Body-marginaalit",appearance_linkprops:"Linkkien v\u00e4rit",appearance_textprops:"Tekstin asetukset",bgcolor:"Taustan v\u00e4ri",bgimage:"Taustakuva",left_margin:"Vasen marginaali",right_margin:"Oikea marginaali",top_margin:"Yl\u00e4marginaali",bottom_margin:"Alamarginaali",text_color:"Tekstin v\u00e4ri",font_size:"Fonttikoko",font_face:"Fontti",link_color:"Linkin v\u00e4ri",hover_color:"Hover-v\u00e4ri",visited_color:"Vierailtu v\u00e4ri",active_color:"Aktiivinen v\u00e4ri",textcolor:"V\u00e4ri",fontsize:"Fonttikoko",fontface:"Fontti",meta_index_follow:"Indeksoi ja seuraa linkkej\u00e4",meta_index_nofollow:"Indeksoi, mutta \u00e4l\u00e4 seuraa linkkej\u00e4",meta_noindex_follow:"\u00c4l\u00e4 indeksoi, mutta seuraa linkkej\u00e4.",meta_noindex_nofollow:"\u00c4l\u00e4 indeksoi, \u00e4l\u00e4k\u00e4 seuraa linkkej\u00e4",appearance_style:"Tyylitiedosto ja tyylin asetukset",stylesheet:"Tyylitiedosto",style:"Tyyli",author:"Kirjoittaja",copyright:"Copyright",add:"Lis\u00e4\u00e4 uusi elementti",remove:"Poista valittu elementti",moveup:"Siirr\u00e4 valittua elementti\u00e4 yl\u00f6s",movedown:"Siirr\u00e4 valittua elementti\u00e4 alas",head_elements:"P\u00e4\u00e4elementti",info:"Informaatio",add_title:"Otsikkoelementti",add_meta:"Meta-elementti",add_script:"Script-elementti",add_style:"Tyylielementti",add_link:"Linkkielementti",add_base:"Base-elementti",add_comment:"Yleinen elementti",title_element:"Otsikkoelementti",script_element:"Script-elementti",style_element:"Tyylielementti",base_element:"Base-elementti",link_element:"Linkkielementti",meta_element:"Meta-elementti",comment_element:"Kommentti",src:"L\u00e4hde",language:"Kieli",href:"Href",target:"Kohde",type:"Tyyppi",charset:"Kirjasintyyppi",defer:"Mukautuminen",media:"Media",properties:"Asetukset",name:"Nimi",value:"Arvo",content:"Sis\u00e4lt\u00f6",rel:"Rel",rev:"Rev",hreflang:"Href-kieli",general_props:"Yleinen",advanced_props:"Edistynyt"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/tn_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('tn.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ms_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000421511526350530033750 0ustar frankiefrankietinyMCE.addI18n('ms.fullpage_dlg',{title:"Alatan dokumen",meta_tab:"Am",appearance_tab:"Penglihatan",advanced_tab:"Lanjutan",meta_props:"Meta informasi",langprops:"Bahasa dan enkod",meta_title:"Tajuk",meta_keywords:"Kata kunci",meta_description:"Huraian",meta_robots:"Robot",doctypes:"Doctype",langcode:"Kod bahasa",langdir:"Arah bahasa",ltr:"Kiri ke kanan",rtl:"Kanan ke kiri",xml_pi:"XML deklarasi",encoding:"PengKod aksara",appearance_bgprops:"Alatan latar belakang",appearance_marginprops:"Ruangan tepi isi kandungan",appearance_linkprops:"Pautan warna",appearance_textprops:"Alatan teks",bgcolor:"Warna latar belakang",bgimage:"Imej latar belakang",left_margin:"Ruangan tepi kiri",right_margin:"Ruangan tepi kanan",top_margin:"Ruangan tepi atas",bottom_margin:"Ruangan tepi bawah",text_color:"Warna teks",font_size:"Saiz Huruf",font_face:"Jenis Huruf",link_color:"Pautan Warna",hover_color:"Warna di atas",visited_color:"Warna telah lawat",active_color:"Warna aktif",textcolor:"Warna",fontsize:"Saiz huruf",fontface:"Keluarga huruf",meta_index_follow:"Indeks dan ikut pautan",meta_index_nofollow:"Indeks dan jangan ikut pautan",meta_noindex_follow:"Jangan indeks tapi ikut pautan",meta_noindex_nofollow:"Jangan indeks dan ikut pautan",appearance_style:"Stylesheet dan alatan gaya",stylesheet:"Stylesheet",style:"Gaya",author:"Pengarang",copyright:"Hakcipta",add:"Tambah unsur baru",remove:"Alih unsur yang dipilih",moveup:"Alih unsur yang dipilih ke atas",movedown:"Alih unsur yang dipilih ke bawah",head_elements:"Unsur pembuka",info:"Informasi",add_title:"Unsur tajuk",add_meta:"Unsur meta",add_script:"Unsur skrip",add_style:"Unsur gaya",add_link:"Unsur pautan",add_base:"Unsur dasar",add_comment:"Nod komen",title_element:"Unsur tajuk",script_element:"Unsur skrip",style_element:"Unsur gaya",base_element:"Unsur dasar",link_element:"Unsur pautan",meta_element:"Unsur meta",comment_element:"Komen",src:"Src",language:"Bahasa",href:"Href",target:"Sasaran",type:"Jenis",charset:"Set huruf",defer:"Menangguhkan",media:"Media",properties:"Alatan",name:"Nama",value:"Nilai",content:"Isi kandungan",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Am",advanced_props:"Lanjutan"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ka_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001626511526350530033760 0ustar frankiefrankietinyMCE.addI18n('ka.fullpage_dlg',{title:"\u10d3\u10dd\u10d9\u10e3\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10db\u10d0\u10ee\u10d0\u10e1\u10d8\u10d0\u10d7\u10d4\u10d1\u10da\u10d4\u10d1\u10d8",meta_tab:"\u10e1\u10d0\u10d4\u10e0\u10d7\u10dd",appearance_tab:"\u10e9\u10d5\u10d4\u10dc\u10d4\u10d1\u10d0",advanced_tab:"\u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d8\u10d7",meta_props:"\u10d8\u10dc\u10e4\u10dd\u10e0\u10db\u10d0\u10ea\u10d8\u10d8\u10e1 \u10db\u10d8\u10d6\u10d0\u10dc\u10d8",langprops:"\u10d4\u10dc\u10d0 \u10d3\u10d0 \u10d9\u10dd\u10d3\u10d8\u10e0\u10d4\u10d1\u10d0",meta_title:"\u10e1\u10d0\u10d7\u10d0\u10e3\u10e0\u10d8",meta_keywords:"\u10e1\u10d0\u10d9\u10d5\u10d0\u10dc\u10eb\u10dd \u10e1\u10d8\u10e2\u10e7\u10d5\u10d4\u10d1\u10d8",meta_description:"\u10d0\u10e0\u10ec\u10d4\u10e0\u10d0",meta_robots:"\u10dc\u10d0\u10db\u10e3\u10e8\u10d4\u10d5\u10e0\u10d4\u10d1\u10d8",doctypes:"\u10e2\u10d8\u10de\u10d8",langcode:"\u10d4\u10dc\u10d8\u10e1 \u10d9\u10dd\u10d3\u10d8",langdir:"\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10db\u10d8\u10db\u10d0\u10e0\u10d7\u10e3\u10da\u10d4\u10d1\u10d0",ltr:"\u10db\u10d0\u10e0\u10ea\u10e1\u10dc\u10d8\u10d3\u10d0\u10dc \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d5",rtl:"\u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d3\u10d0\u10dc \u10db\u10d0\u10e0\u10ea\u10ee\u10dc\u10d8\u10d5",xml_pi:"XML \u10d2\u10d0\u10dc\u10ea\u10ee\u10d0\u10d3\u10d4\u10d1\u10d0",encoding:"\u10d9\u10dd\u10d3\u10d8\u10e0\u10d4\u10d1\u10d0",appearance_bgprops:"\u10e4\u10dd\u10dc\u10d8\u10e1 \u10db\u10d0\u10ee\u10d0\u10e1\u10d8\u10d0\u10d7\u10d4\u10d1\u10da\u10d4\u10d1\u10d8",appearance_marginprops:"\u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d4\u10d1\u10d8",appearance_linkprops:"\u10d1\u10db\u10e3\u10da\u10d4\u10d1\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",appearance_textprops:"\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10db\u10d0\u10d0\u10e1\u10d8\u10d0\u10d7\u10d4\u10d1\u10da\u10d4\u10d1\u10d8",bgcolor:"\u10e4\u10dd\u10dc\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",bgimage:"\u10e4\u10dd\u10dc\u10e3\u10e0\u10d8 \u10d2\u10d0\u10db\u10dd\u10e1\u10d0\u10ee\u10e3\u10da\u10d4\u10d1\u10d0",left_margin:"\u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d0 \u10db\u10d0\u10e0\u10ea\u10e1\u10dc\u10d8\u10d3\u10d0\u10dc",right_margin:"\u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d0 \u10db\u10d0\u10e0\u10ef\u10d5\u10dc\u10d8\u10d3\u10d0\u10dc",top_margin:"\u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d0 \u10d6\u10d4\u10db\u10dd\u10d3\u10d0\u10dc",bottom_margin:"\u10d3\u10d0\u10e8\u10dd\u10e0\u10d4\u10d1\u10d0 \u10e5\u10d5\u10d4\u10db\u10dd\u10d3\u10d0\u10dc",text_color:"\u10e2\u10d4\u10e5\u10e1\u10e2\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",font_size:"\u10e8\u10e0\u10d8\u10e4\u10e2\u10d8\u10e1 \u10d6\u10dd\u10db\u10d0",font_face:"\u10e8\u10e0\u10d8\u10e4\u10e2\u10d8",link_color:"\u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",hover_color:"\u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8 \u10d2\u10d0\u10d0\u10e5\u10e2\u10d8\u10e3\u10e0\u10d4\u10d1\u10d8\u10e1\u10d0\u10e1",visited_color:"\u10d2\u10d0\u10d0\u10e5\u10e2\u10d8\u10e3\u10e0\u10d4\u10d1\u10e3\u10da\u10d8 \u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",active_color:"\u10d0\u10e5\u10e2\u10d8\u10e3\u10e0\u10d8 \u10d1\u10db\u10e3\u10da\u10d8\u10e1 \u10e4\u10d4\u10e0\u10d8",textcolor:"\u10e4\u10d4\u10e0\u10d8",fontsize:"\u10e8\u10e0\u10d8\u10e4\u10e2\u10d8\u10e1 \u10d6\u10dd\u10db\u10d0",fontface:"\u10e8\u10e0\u10d8\u10e4\u10e2\u10d8\u10e1 \u10d9\u10d0\u10e2\u10d4\u10d2\u10dd\u10e0\u10d8\u10d0",meta_index_follow:"\u10d3\u10d0\u10d5\u10d0\u10d8\u10dc\u10d3\u10d4\u10e5\u10e1\u10dd\u10d7 \u10d3\u10d0 \u10d2\u10d0\u10d5\u10e7\u10d5\u10d4\u10d7 \u10d1\u10db\u10e3\u10da\u10d4\u10d1\u10e1",meta_index_nofollow:"\u10d3\u10d0\u10d5\u10d0\u10d8\u10dc\u10d3\u10d4\u10e5\u10e1\u10dd\u10d7 \u10d3\u10d0 \u10d0\u10e0 \u10d2\u10d0\u10d5\u10e7\u10d5\u10d4\u10d7 \u10d1\u10db\u10e3\u10da\u10d4\u10d1\u10e1",meta_noindex_follow:"\u10d0\u10e0 \u10d3\u10d0\u10d5\u10d0\u10d8\u10dc\u10d3\u10d4\u10e5\u10e1\u10dd\u10d7, \u10db\u10d0\u10d2\u10e0\u10d0\u10db \u10d1\u10db\u10e3\u10da\u10d4\u10d1\u10e1 \u10d2\u10d0\u10d5\u10e7\u10d5\u10d4\u10d7",meta_noindex_nofollow:"\u10d0\u10e0 \u10d3\u10d0\u10d5\u10d0\u10d8\u10dc\u10d3\u10d4\u10e5\u10e1\u10dd\u10d7 \u10d3\u10d0 \u10d0\u10e0 \u10d2\u10d0\u10d5\u10e7\u10d5\u10d4\u10d7 \u10d1\u10db\u10e3\u10da\u10d4\u10d1\u10e1",appearance_style:"\u10e1\u10e2\u10d8\u10da\u10d4\u10d1\u10d8\u10e1 \u10db\u10d0\u10e9\u10d5\u10d4\u10dc\u10d4\u10d1\u10da\u10d4\u10d1\u10d8 \u10d3\u10d0 \u10e1\u10d8\u10d0",stylesheet:"\u10e1\u10e2\u10d8\u10da\u10d4\u10d1\u10d8\u10e1 \u10e1\u10d8\u10d0",style:"\u10e1\u10e2\u10d8\u10da\u10d8",author:"\u10d0\u10d5\u10e2\u10dd\u10e0\u10d8",copyright:"\u10d9\u10dd\u10de\u10d8\u10e0\u10d0\u10d8\u10e2\u10d8",add:"\u10d0\u10ee\u10d0\u10da\u10d8 \u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d0",remove:"\u10db\u10dd\u10dc\u10d8\u10e8\u10dc\u10e3\u10da\u10d8 \u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10ec\u10d0\u10e8\u10da\u10d0",moveup:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10d6\u10d4\u10db\u10dd\u10d7 \u10d2\u10d0\u10d3\u10d0\u10d0\u10d3\u10d2\u10d8\u10da\u10d4\u10d1\u10d0",movedown:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8\u10e1 \u10e5\u10d5\u10d4\u10db\u10dd\u10d7 \u10d2\u10d0\u10d3\u10d0\u10d0\u10d3\u10d2\u10d8\u10da\u10d4\u10d1\u10d0",head_elements:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Header",info:"\u10d8\u10dc\u10e4\u10dd\u10e0\u10db\u10d0\u10ea\u10d8\u10d0",add_title:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Title",add_meta:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Meta",add_script:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Script",add_style:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Style",add_link:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Link",add_base:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Base",add_comment:"\u10d9\u10dd\u10db\u10d4\u10dc\u10e2\u10d0\u10e0\u10d8",title_element:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Title",script_element:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Script",style_element:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Style",base_element:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Base",link_element:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Link",meta_element:"\u10d4\u10da\u10d4\u10db\u10d4\u10dc\u10e2\u10d8 Meta",comment_element:"\u10d9\u10dd\u10db\u10d4\u10dc\u10e2\u10d8\u10d0\u10e0\u10d8",src:"Src",language:"\u10d4\u10dc\u10d0",href:"\u10d1\u10db\u10e3\u10da\u10d8",target:"\u10db\u10d8\u10d6\u10d0\u10dc\u10d8",type:"\u10e2\u10d8\u10de\u10d8",charset:"\u10d9\u10dd\u10d3\u10d8\u10e0\u10d4\u10d1\u10d0",defer:"\u10d2\u10d0\u10d3\u10d0\u10e2\u10d0\u10dc\u10d0",media:"\u10db\u10d4\u10d3\u10d8\u10d0",properties:"\u10de\u10d0\u10e0\u10d0\u10db\u10d4\u10e2\u10e0\u10d4\u10d1\u10d8",name:"\u10e1\u10d0\u10ee\u10d4\u10da\u10ec\u10dd\u10d3\u10d4\u10d1\u10d0",value:"\u10db\u10d0\u10e9\u10d5\u10d4\u10dc\u10d4\u10d1\u10d4\u10da\u10d8",content:"\u10e8\u10d8\u10dc\u10d0\u10d0\u10e0\u10e1\u10d8",rel:"Rel",rev:"Rev",hreflang:"\u10d4\u10dc\u10d8\u10e1 \u10d1\u10db\u10e3\u10da\u10d8",general_props:"\u10e1\u10d0\u10d4\u10e0\u10d7\u10dd",advanced_props:"\u10d3\u10d0\u10db\u10d0\u10e2\u10d4\u10d1\u10d8\u10d7"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/lt_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000532711526350530033755 0ustar frankiefrankietinyMCE.addI18n('lt.fullpage_dlg',{title:"Dokumento nustatymai",meta_tab:"Bendra",appearance_tab:"I\u0161vaizda",advanced_tab:"I\u0161pl\u0117sta",meta_props:"Meta informacija",langprops:"Kalba ir koduot\u0117",meta_title:"Pavadinimas",meta_keywords:"Rakta\u017eod\u017eiai",meta_description:"Apra\u0161as",meta_robots:"Robotai",doctypes:"Dokumento tipas",langcode:"Kalbos kodas",langdir:"Kalbos kryptis",ltr:"I\u0161 kair\u0117s \u012f de\u0161in\u0119",rtl:"I\u0161 de\u0161in\u0117s \u012f kair\u0119",xml_pi:"XML deklaracijos",encoding:"Simboli\u0173 koduot\u0117",appearance_bgprops:"Fono nustatymai",appearance_marginprops:"K\u016bno para\u0161t\u0117s",appearance_linkprops:"Nuorod\u0173 spalvos",appearance_textprops:"Teksto nustatymai",bgcolor:"Fono spalva",bgimage:"Fono paveiksl\u0117lis",left_margin:"Kair\u0117 para\u0161t\u0117",right_margin:"De\u0161in\u0117 para\u0161t\u0117",top_margin:"Vir\u0161utin\u0117 para\u0161t\u0117",bottom_margin:"Apatin\u0117 para\u0161t\u0117",text_color:"Teksto spalva",font_size:"\u0160rifto dydis",font_face:"\u0160riftas",link_color:"Nuorodos spalva",hover_color:"U\u017evedus pele spalva",visited_color:"Aplankytos spalva",active_color:"Aktyvios spalva",textcolor:"Spalva",fontsize:"\u0160rifto dydis",fontface:"\u0160rifto \u0161eima",meta_index_follow:"Indeksuoti ir sekti nuorodomis",meta_index_nofollow:"Indeksuoti ir nesekti nuorodomis",meta_noindex_follow:"Neindeksuoti, bet sekti nuorodomis",meta_noindex_nofollow:"Neindeksuoti ir nesekti nuorodomis",appearance_style:"Stili\u0173 lapo ir stiliaus nustatymai",stylesheet:"Stili\u0173 lapas",style:"Stilius",author:"Autorius",copyright:"Autoriaus teis\u0117s",add:"Prid\u0117ti nauj\u0105 element\u0105",remove:"Pa\u0161alinti pa\u017eym\u0117t\u0105 element\u0105",moveup:"Perkelti pa\u017eym\u0117t\u0105 element\u0105 \u012f vir\u0161\u0173",movedown:"Perkelti pa\u017eym\u0117t\u0105 element\u0105 \u012f apa\u010di\u0105",head_elements:"Antra\u0161t\u0117s elementai",info:"Informacija",add_title:"Pavadinimo elementas",add_meta:"Meta elementas",add_script:"Skripto elementas",add_style:"Stiliaus elementas",add_link:"Nuorodos elementas",add_base:"Bazinis elementas",add_comment:"Komentaro mazgas",title_element:"Pavadinimo elementas",script_element:"Skripto elementas",style_element:"Stiliaus elementas",base_element:"Bazinis elementas",link_element:"Nuorodos elementas",meta_element:"Meta elementas",comment_element:"Komentaras",src:"\u0160altinis",language:"Kalba",href:"Href",target:"Paskirtis",type:"Tipas",charset:"Koduot\u0117",defer:"Atid\u0117ti",media:"Medija",properties:"Nustatymai",name:"Vardas",value:"Reik\u0161m\u0117",content:"Turinys",rel:"Laida",rev:"Pataisa",hreflang:"Href kalba",general_props:"Bendra",advanced_props:"I\u0161pl\u0117sta"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/da_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000431711526350530033753 0ustar frankiefrankietinyMCE.addI18n('da.fullpage_dlg',{title:"Dokumentegenskaber",meta_tab:"Generelt",appearance_tab:"Udseende",advanced_tab:"Advanceret",meta_props:"Meta-information",langprops:"Sprog og kodning",meta_title:"Titel",meta_keywords:"N\u00f8gleord",meta_description:"Beskrivelse",meta_robots:"Robots",doctypes:"Doctype",langcode:"Sprogkode",langdir:"Sprogretning",ltr:"Venstre mod h\u00f8jre",rtl:"H\u00f8jre md venstre",xml_pi:"XML declaration",encoding:"Tegns\u00e6t",appearance_bgprops:"Baggrundsegenskaber",appearance_marginprops:"Body margins",appearance_linkprops:"Link farver",appearance_textprops:"Tekstegenskaber",bgcolor:"Baggrundsfarve",bgimage:"Baggrundsbillede",left_margin:"Venstre margin",right_margin:"H\u00f8jre margin",top_margin:"Topmargin",bottom_margin:"Bundmargin",text_color:"Tekstfarve",font_size:"Skriftst\u00f8rrelse",font_face:"Skrifttype",link_color:"Linkfarve",hover_color:"Farve ved aktivering",visited_color:"Farve efter museklik",active_color:"Farve ved museklik",textcolor:"Farve",fontsize:"Skriftst\u00f8rrelse",fontface:"Skrifttype",meta_index_follow:"Indeks og f\u00f8lg links",meta_index_nofollow:"Indeks og f\u00f8lg ikke links",meta_noindex_follow:"Ingen indeks, men f\u00f8lg links",meta_noindex_nofollow:"Ingen indeks og f\u00f8lg ikke links",appearance_style:"Stylesheet og style-egenskaber",stylesheet:"Stylesheet",style:"Style",author:"Forfatter",copyright:"Copyright",add:"Tilf\u00f8j nyt element",remove:"Slet valgte element",moveup:"Flyt valgte element op",movedown:"Flyt valgte element ned",head_elements:"Hovedelement",info:"Information",add_title:"Titelelement",add_meta:"Meta-element",add_script:"Script-element",add_style:"Style-element",add_link:"Link-element",add_base:"Base-element",add_comment:"Kommentar-node",title_element:"Titelelement",script_element:"Script-element",style_element:"Style-element",base_element:"Base-element",link_element:"Link-element",meta_element:"Meta-element",comment_element:"Kommentar",src:"Src",language:"Sprog",href:"Href",target:"Destination",type:"Type",charset:"Tegns\u00e6t",defer:"Defer",media:"Media",properties:"Egenskaber",name:"Navn",value:"V\u00e6rdi",content:"Indhold",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Generelt",advanced_props:"Advanceret"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ur_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('ur.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/se_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000454711526350530033760 0ustar frankiefrankietinyMCE.addI18n('se.fullpage_dlg',{title:"Dokumentinst\u00e4llningar",meta_tab:"Generella",appearance_tab:"Utseende",advanced_tab:"Avancerat",meta_props:"Metainformation",langprops:"Spr\u00e5k och kodning",meta_title:"Titel",meta_keywords:"Nyckelord",meta_description:"Bekrivning",meta_robots:"Robots",doctypes:"Doctype",langcode:"Spr\u00e5kkod",langdir:"Skriftriktning",ltr:"V\u00e4nster till h\u00f6ger",rtl:"H\u00f6ger till v\u00e4nster",xml_pi:"XML deklaration",encoding:"Teckenkodning",appearance_bgprops:"Bakgrundsinst\u00e4llningar",appearance_marginprops:"Body marginaler",appearance_linkprops:"L\u00e4nkf\u00e4rger",appearance_textprops:"Textinst\u00e4llningar",bgcolor:"Bakgrundsf\u00e4rg",bgimage:"Bakgrundsbild",left_margin:"V\u00e4nstermarginal",right_margin:"H\u00f6germarginal",top_margin:"Toppmarginal",bottom_margin:"Bottenmarginal",text_color:"Textf\u00e4rg",font_size:"Textstorlek",font_face:"Textstil",link_color:"L\u00e4nkf\u00e4rg",hover_color:"Hover f\u00e4rg",visited_color:"Visited f\u00e4rg",active_color:"Active f\u00e4rg",textcolor:"F\u00e4rg",fontsize:"Textstorlek",fontface:"Textstil",meta_index_follow:"Indexera och f\u00f6lj l\u00e4nkar",meta_index_nofollow:"Indexera men f\u00f6lj ej l\u00e4nkar",meta_noindex_follow:"Indexera inte men f\u00f6lj l\u00e4nkar",meta_noindex_nofollow:"Indexera inte och f\u00f6lj ej l\u00e4nkar",appearance_style:"Stilmall och stilegenskaper",stylesheet:"Stilmall",style:"Stil",author:"F\u00f6rfattare",copyright:"Copyright",add:"L\u00e4gg till element",remove:"Radera det markerade elementet",moveup:"Flytta det markerade elementet upp\u00e5t",movedown:"Flytta det markerade elementet ned\u00e5t",head_elements:"Head element",info:"Information",add_title:"Titel-element",add_meta:"Meta-element",add_script:"Script-element",add_style:"Stil-element",add_link:"L\u00e4nk-element",add_base:"Base-element",add_comment:"Kommentarsnod",title_element:"Titel-element",script_element:"Script-element",style_element:"Style-element",base_element:"Base-element",link_element:"Link-element",meta_element:"Meta-element",comment_element:"Comment-element",src:"Src",language:"Spr\u00e5k",href:"Href",target:"M\u00e5l",type:"Typ",charset:"Teckenupps\u00e4ttning",defer:"Defer",media:"Media",properties:"Egenskaper",name:"Name",value:"Value",content:"Inneh\u00e5ll",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Generellt",advanced_props:"Avancerat"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/et_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000460411526350530033752 0ustar frankiefrankietinyMCE.addI18n('et.fullpage_dlg',{title:"Dokumendi omadused",meta_tab:"\u00dcldine",appearance_tab:"V\u00e4limus",advanced_tab:"P\u00f5hjalikum",meta_props:"\u201eMeta\u201c informatioon",langprops:"Keel ja kodeering",meta_title:"Pealkiri",meta_keywords:"M\u00e4rks\u00f5nad",meta_description:"Kirjeldus",meta_robots:"Robotid",doctypes:"Dokumendi t\u00fc\u00fcp",langcode:"Keele kood",langdir:"Keele suund",ltr:"Vasakult paremale",rtl:"Paremalt vasakule",xml_pi:"XML avaldus",encoding:"Karakteri kodeering",appearance_bgprops:"Tausta seadistus",appearance_marginprops:"Sisu piir",appearance_linkprops:"Lingi v\u00e4rv",appearance_textprops:"Teksti seaded",bgcolor:"Tausta v\u00e4rv",bgimage:"Tausta pilt",left_margin:"Vasak piir",right_margin:"Parem piir",top_margin:"\u00dclemine piir",bottom_margin:"Alumine piir",text_color:"Teksti v\u00e4rv",font_size:"Fondi suurus",font_face:"Fondi n\u00e4gu",link_color:"Lingi v\u00e4rv",hover_color:"\u00dcle-v\u00e4rv",visited_color:"K\u00fclastatud-v\u00e4rv",active_color:"Aktiivne-v\u00e4rv",textcolor:"V\u00f6rv",fontsize:"Fondi suurus",fontface:"Font",meta_index_follow:"M\u00e4rgi ja j\u00e4rgi linki",meta_index_nofollow:"M\u00e4rgi ja \u00e4ra j\u00e4rgi linki",meta_noindex_follow:"\u00c4ra m\u00e4rgi linki, aga j\u00e4rgi linki",meta_noindex_nofollow:"\u00c4ra m\u00e4rgi linki ja \u00e4ra j\u00e4rgi linki",appearance_style:"Stiilileht ja stiili seaded",stylesheet:"Stiilileht",style:"Stiil",author:"Autor",copyright:"Autorikaitse",add:"Lisa uus element",remove:"Eemalda valitud element",moveup:"Liiguta valitud element \u00fclesse",movedown:"Liiguta valitud element alla",head_elements:"P\u00f5hielemendid",info:"Informatioon",add_title:"Pealkirja element",add_meta:"\u201eMeta\u201c element",add_script:"Skript\u2019i element",add_style:"Stiili element",add_link:"Lingi element",add_base:"Baaselement",add_comment:"Kommentaar",title_element:"Pealkirja element",script_element:"Skript\u2019i element",style_element:"Stiili element",base_element:"Baaselement",link_element:"Lingi element",meta_element:"\u201eMeta\u201c element",comment_element:"kommentaar",src:"Src",language:"Keel",href:"Href",target:"Sihtm\u00e4rk",type:"T\u00fc\u00fcp",charset:"Charset",defer:"Edasi l\u00fckkamine",media:"Meedia",properties:"Seaded",name:"Nimi",value:"V\u00e4\u00e4rtus",content:"Sisu",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u00dcldine",advanced_props:"T\u00e4psustatud"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/no_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000433711526350530033755 0ustar frankiefrankietinyMCE.addI18n('no.fullpage_dlg',{title:"Dokumentegenskaper",meta_tab:"Generelt",appearance_tab:"Utseende",advanced_tab:"Avansert",meta_props:"Meta informasjon",langprops:"Spr\u00e5k og koding",meta_title:"Tittel",meta_keywords:"N\u00f8kkelord",meta_description:"Beskrivelse",meta_robots:"Roboter",doctypes:"Dokument type",langcode:"Spr\u00e5kkode",langdir:"Skriftretning",ltr:"Venstre mot h\u00f8yre",rtl:"H\u00f8yre mot venstre",xml_pi:"XML deklarering",encoding:"Karakter konvertering",appearance_bgprops:"Bakgrunnsegenskaper",appearance_marginprops:"Body marg",appearance_linkprops:"Lenke farger",appearance_textprops:"Tekst egenskaper",bgcolor:"Bakgrunnsfarge",bgimage:"Bakgrunnsbilde",left_margin:"Venstre marg",right_margin:"H\u00f8yre marg",top_margin:"Topp marg",bottom_margin:"Bunn marg",text_color:"Tekstfarge",font_size:"Skriftst\u00f8rrelse",font_face:"Skrifttype",link_color:"Lenke farge",hover_color:"Mus-over farge",visited_color:"Bes\u00f8kt farge",active_color:"Aktiv farge",textcolor:"Farge",fontsize:"Skriftst\u00f8rrelse",fontface:"Skriftfamile",meta_index_follow:"Indekser og f\u00f8lg lenkene",meta_index_nofollow:"Indekser og ikke f\u00f8lg lenkene",meta_noindex_follow:"Ikke indekser, men f\u00f8lg lenkene",meta_noindex_nofollow:"Ikke indekser, og ikke f\u00f8lg lenkene",appearance_style:"Stilark og stilegenskaper",stylesheet:"Stilark",style:"Stil",author:"Forfatter",copyright:"Copyright",add:"Legg til nytt element",remove:"Fjerne valgt element",moveup:"Flytt markert element opp",movedown:"Flytt markert element ned",head_elements:"Overskriftselement",info:"Informasjon",add_title:"Tittelelement",add_meta:"Metaelement",add_script:"Skriptelement",add_style:"Stilelement",add_link:"Lenkeelement",add_base:"Basiselement",add_comment:"Kommentar",title_element:"Tittelelement",script_element:"Skriptelement",style_element:"Stilelement",base_element:"Basiselement",link_element:"Lenkeelement",meta_element:"Metaelement",comment_element:"Kommentar",src:"Kilde",language:"Spr\u00e5k",href:"Href",target:"M\u00e5l",type:"Type",charset:"Tegnsett",defer:"Henstille",media:"Objekt",properties:"Egenskaper",name:"Navn",value:"Verdi",content:"Innhold",rel:"Rel",rev:"Rev",hreflang:"Href spr\u00e5k",general_props:"Generelt",advanced_props:"Avansert"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/hi_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('hi.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/mk_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000451611526350530033754 0ustar frankiefrankietinyMCE.addI18n('mk.fullpage_dlg',{title:"Svojstva dokumenta",meta_tab:"Osnovno",appearance_tab:"Izgled",advanced_tab:"Napredno",meta_props:"Meta informacije",langprops:"Jezik i kodiranje",meta_title:"\u041d\u0430\u0441\u043b\u043e\u0432",meta_keywords:"Klju\u010dne re\u010di",meta_description:"Opis",meta_robots:"Robots",doctypes:"Doctype",langcode:"Kod jezika",langdir:"Smjer jezika",ltr:"S leva na desno",rtl:"S desna na levo",xml_pi:"XML deklaracija",encoding:"Kodiranje znakova",appearance_bgprops:"Svojstva pozadine",appearance_marginprops:"Margina",appearance_linkprops:"Boja poveznica",appearance_textprops:"Svojstva teksta",bgcolor:"Boja pozadine",bgimage:"Pozadinska slika",left_margin:"Leva margina",right_margin:"Desna margina",top_margin:"Gornja margina",bottom_margin:"Donja margina",text_color:"Boja teksta",font_size:"Veli\u010dina pisma",font_face:"Pismo",link_color:"Boja poveznice",hover_color:"Boja poveznice ispod mi\u0161a",visited_color:"Boja posje\u0107ene poveznice",active_color:"Boja aktivne poveznice",textcolor:"Boja",fontsize:"Veli\u010dina pisma",fontface:"Skupina pisama",meta_index_follow:"Indeksiraj i sledi poveznice",meta_index_nofollow:"Indeksiraj i ne sledi poveznice",meta_noindex_follow:"Ne indeksiraj i sledi poveznice",meta_noindex_nofollow:"Ne indeksiraj i ne sledi poveznice",appearance_style:"CSS i svojstva stila",stylesheet:"CSS",style:"Stil",author:"Autor",copyright:"Autorska prava",add:"Dodaj novi element",remove:"Ukloni odabrani element",moveup:"Pomakni odabrani element prema gore",movedown:"Pomakni odabrani element prema dolje",head_elements:"Zaglavni elementi",info:"Informacije",add_title:"\u041d\u0430\u0441\u043b\u043e\u0432ni element",add_meta:"Meta element",add_script:"Skriptni element",add_style:"Sitlski element",add_link:"Element poveznice",add_base:"Osnovni element",add_comment:"Komentar",title_element:"\u041d\u0430\u0441\u043b\u043e\u0432ni element",script_element:"Skriptni element",style_element:"Stilski element",base_element:"Osnovni element",link_element:"Element poveznice",meta_element:"Meta element",comment_element:"Komentar",src:"Src",language:"Jezik",href:"Href",target:"Meta",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Svojstva",name:"Ime",value:"Vrednost",content:"Sadr\u017eaj",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Osnovno",advanced_props:"Napredno"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ru_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001372311526350530033754 0ustar frankiefrankietinyMCE.addI18n('ru.fullpage_dlg',{title:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",meta_tab:"\u041e\u0431\u0449\u0435\u0435",appearance_tab:"\u0412\u0438\u0434",advanced_tab:"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e",meta_props:"\u0426\u0435\u043b\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438",langprops:"\u042f\u0437\u044b\u043a \u0438 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f",meta_title:"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",meta_keywords:"\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430",meta_description:"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",meta_robots:"\u0420\u0430\u0431\u043e\u0442\u044b",doctypes:"\u0422\u0438\u043f",langcode:"\u041a\u043e\u0434 \u044f\u0437\u044b\u043a\u0430",langdir:"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430",ltr:"\u0421\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e",rtl:"\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e",xml_pi:"\u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 XML",encoding:"\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430",appearance_bgprops:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0444\u043e\u043d\u0430",appearance_marginprops:"\u041e\u0442\u0441\u0442\u0443\u043f\u044b",appearance_linkprops:"\u0426\u0432\u0435\u0442 \u0441\u0441\u044b\u043b\u043e\u043a",appearance_textprops:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0442\u0435\u043a\u0441\u0442\u0430",bgcolor:"\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430",bgimage:"\u0424\u043e\u043d\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",left_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u043b\u0435\u0432\u0430",right_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u043f\u0440\u0430\u0432\u0430",top_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u0432\u0435\u0440\u0445\u0443",bottom_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u043d\u0438\u0437\u0443",text_color:"\u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430",font_size:"\u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430",font_face:"\u0428\u0440\u0438\u0444\u0442",link_color:"\u0426\u0432\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438",hover_color:"\u0426\u0432\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0438",visited_color:"\u0426\u0432\u0435\u0442 \u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0438",active_color:"\u0426\u0432\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0438",textcolor:"\u0426\u0432\u0435\u0442",fontsize:"\u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430",fontface:"\u0421\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u0448\u0440\u0438\u0444\u0442\u043e\u0432",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don \\ \'t follow the links",appearance_style:"\u041b\u0438\u0441\u0442 \u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u0442\u0438\u043b\u0435\u0439",stylesheet:"\u041b\u0438\u0441\u0442 \u0441\u0442\u0438\u043b\u0435\u0439",style:"\u0421\u0442\u0438\u043b\u044c",author:"\u0410\u0432\u0442\u043e\u0440",copyright:"\u041a\u043e\u043f\u0438\u0440\u0430\u0439\u0442",add:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",remove:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",moveup:"\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u0432\u0435\u0440\u0445",movedown:"\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u043d\u0438\u0437",head_elements:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Header",info:"\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f",add_title:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Title",add_meta:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Meta",add_script:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Script",add_style:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Style",add_link:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Link",add_base:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Base",add_comment:"\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439",title_element:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Title",script_element:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Script",style_element:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Style",base_element:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Base",link_element:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Link",meta_element:"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 Meta",comment_element:"\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439",src:"Src",language:"\u042f\u0437\u044b\u043a",href:"\u0441\u0441\u044b\u043b\u043a\u0430",target:"\u0426\u0435\u043b\u044c",type:"Type",charset:"\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430",defer:"\u041e\u0442\u0441\u0440\u043e\u0447\u043a\u0430",media:"\u041c\u0435\u0434\u0438\u0430",properties:"\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b",name:"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",value:"\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435",content:"\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",rel:"Rel",rev:"Rev",hreflang:"\u042f\u0437\u044b\u043a \u0441\u0441\u044b\u043b\u043a\u0438",general_props:"\u041e\u0431\u0449\u0435\u0435",advanced_props:"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/vi_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000645411526350530033757 0ustar frankiefrankietinyMCE.addI18n('vi.fullpage_dlg',{title:"Thu\u1ed9c t\u00ednh v\u0103n b\u1ea3n",meta_tab:"Chung",appearance_tab:"Xu\u1ea5t hi\u1ec7n",advanced_tab:"N\u00e2ng cao",meta_props:"Th\u00f4ng tin Meta",langprops:"Ng\u00f4n ng\u1eef v\u00e0 m\u00e3 h\u00f3a",meta_title:"Ti\u00eau \u0111\u1ec1",meta_keywords:"T\u1eeb kh\u00f3a",meta_description:"M\u00f4 t\u1ea3",meta_robots:"Robots",doctypes:"Ki\u1ec3u t\u00e0i li\u1ec7u",langcode:"M\u00e3 ng\u00f4n ng\u1eef",langdir:"H\u01b0\u1edbng ng\u00f4n ng\u1eef",ltr:"Tr\u00e1i qua ph\u1ea3i",rtl:"Ph\u1ea3i qua tr\u00e1i",xml_pi:"Khai b\u00e1o XML",encoding:"M\u00e3 h\u00f3a k\u00fd t\u1ef1",appearance_bgprops:"Thu\u1ed9c t\u00ednh n\u1ec1n",appearance_marginprops:"Bi\u00ean c\u1ee7a th\u00e2n t\u00e0i li\u1ec7u",appearance_linkprops:"M\u00e0u li\u00ean k\u1ebft",appearance_textprops:"Thu\u00f4c t\u00ednh v\u0103n b\u1ea3n",bgcolor:"M\u00e0u n\u1ec1n",bgimage:"\u1ea2nh n\u1ec1n",left_margin:"Bi\u00ean tr\u00e1i",right_margin:"Bi\u00ean ph\u1ea3i",top_margin:"Bi\u00ean tr\u00ean",bottom_margin:"Bi\u00ean d\u01b0\u1edbi",text_color:"M\u00e0u v\u0103n b\u1ea3n",font_size:"K\u00edch c\u1ee1 ph\u00f4ng",font_face:"Ph\u00f4ng ch\u1eef",link_color:"M\u00e0u li\u00ean k\u1ebft",hover_color:"M\u00e0u khi tr\u1ecf chu\u1ed9t",visited_color:"M\u00e0u \u0111\u00e3 gh\u00e9 th\u0103m",active_color:"M\u00e0u ho\u1ea1t \u0111\u1ed9ng",textcolor:"M\u00e0u",fontsize:"K\u00edch c\u1ee1 ph\u00f4ng",fontface:"T\u1eadp h\u1ee3p ph\u00f4ng",meta_index_follow:"Ch\u1ec9 s\u1ed1 v\u00e0 theo li\u00ean k\u1ebft",meta_index_nofollow:"Ch\u1ec9 s\u1ed1 v\u00e0 kh\u00f4ng theo li\u00ean k\u1ebft",meta_noindex_follow:"Kh\u00f4ng ch\u1ec9 s\u1ed1 nh\u01b0ng theo li\u00ean k\u1ebft",meta_noindex_nofollow:"Kh\u00f4ng ch\u1ec9 s\u1ed1 v\u00e0 kh\u00f4ng theo li\u00ean k\u1ebft",appearance_style:"Thu\u1ed9c t\u00ednh ki\u1ec3u d\u00e1ng v\u00e0 stylesheet",stylesheet:"Stylesheet",style:"Ki\u1ec3u d\u00e1ng",author:"T\u00e1c gi\u1ea3",copyright:"B\u1ea3n quy\u1ec1n",add:"Th\u00eam ph\u1ea7n t\u1eed m\u1edbi",remove:"Lo\u1ea1i b\u1ecf ph\u1ea7n t\u1eed \u0111\u00e3 ch\u1ecdn",moveup:"Di chuy\u1ec3n ph\u1ea7n t\u1eed \u0111\u00e3 ch\u1ecdn \u0111i l\u00ean",movedown:"Di chuy\u1ec3n ph\u1ea7n t\u1eed \u0111\u00e3 ch\u1ecdn \u0111i xu\u1ed1ng",head_elements:"Ph\u1ea7n t\u1eed \u0111\u1ea7u \u0111\u1ec1",info:"Th\u00f4ng tin",add_title:"Ph\u1ea7n t\u1eed ti\u00eau \u0111\u1ec1",add_meta:"Ph\u1ea7n t\u1eed meta",add_script:"Ph\u1ea7n t\u1eed script",add_style:"Ph\u1ea7n t\u1eed ki\u1ec3u d\u00e1ng",add_link:"Ph\u1ea7n t\u1eed li\u00ean k\u1ebft",add_base:"Ph\u1ea7n t\u1eed c\u01a1 s\u1edf",add_comment:"Comment node",title_element:"Ph\u1ea7n t\u1eed ti\u00eau \u0111\u1ec1",script_element:"Ph\u1ea7n t\u1eed script",style_element:"Ph\u1ea7n t\u1eed ki\u1ec3u d\u00e1ng",base_element:"Ph\u1ea7n t\u1eed c\u01a1 s\u1edf",link_element:"Ph\u1ea7n t\u1eed li\u00ean k\u1ebft",meta_element:"Ph\u1ea7n t\u1eed meta",comment_element:"Ch\u00fa th\u00edch",src:"Src",language:"Ng\u00f4n ng\u1eef",href:"Href",target:"\u0110\u00edch",type:"Ki\u1ec3u",charset:"T\u1eadp k\u00fd t\u1ef1",defer:"Tr\u00ec ho\u00e3n",media:"Ph\u01b0\u01a1ng ti\u1ec7n",properties:"Thu\u1ed9c t\u00ednh",name:"T\u00ean",value:"Gi\u00e1 tr\u1ecb",content:"N\u1ed9i dung",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Chung",advanced_props:"N\u00e2ng cao"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/br_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000437511526350530033757 0ustar frankiefrankietinyMCE.addI18n('br.fullpage_dlg',{title:"Propriedades do documento",meta_tab:"Geral",appearance_tab:"Apar\u00eancia",advanced_tab:"Avan\u00e7ado",meta_props:"Meta-informa\u00e7\u00e3o",langprops:"Linguagem e codifica\u00e7\u00e3o",meta_title:"T\u00edtulo",meta_keywords:"Palavras-chave",meta_description:"Descri\u00e7\u00e3o",meta_robots:"Robots",doctypes:"Doctype",langcode:"C\u00f3digo de linguagem",langdir:"Dire\u00e7\u00e3o do texto",ltr:"Esquerda para direita",rtl:"Direita para esquerda",xml_pi:"Declara\u00e7\u00e3o XML",encoding:"Codifica\u00e7\u00e3o de caracteres",appearance_bgprops:"Propriedades do plano de fundo",appearance_marginprops:"Margens (BODY)",appearance_linkprops:"Cores dos links",appearance_textprops:"Propriedades de texto",bgcolor:"Cor de fundo",bgimage:"Imagem de fundo",left_margin:"Margem esquerda",right_margin:"Margem direita",top_margin:"Margem topo",bottom_margin:"Margem base",text_color:"Cor do texto",font_size:"Tamanho fonte",font_face:"Fonte",link_color:"Cores dos links",hover_color:"Hover",visited_color:"Visited",active_color:"Active",textcolor:"Cor",fontsize:"Tamanho fonte",fontface:"Fonte",meta_index_follow:"Indexar e seguir os hyperlinks",meta_index_nofollow:"Indexar e n\u00e3o seguir os hyperlinks",meta_noindex_follow:"Seguir hyperlinks, mas n\u00e3o indexar",meta_noindex_nofollow:"N\u00e3o indexar / n\u00e3o seguir hyperlinks.",appearance_style:"Propriedades de folhas de estilo",stylesheet:"Folha de estilo",style:"Estilo",author:"Autor",copyright:"Copyright",add:"Acrescentar Novo elemento",remove:"Remover elemento selecionado",moveup:"Subir elemento selecionado",movedown:"Descer elemento selecionado",head_elements:"Elementos HEAD",info:"Informa\u00e7\u00e3o",add_title:"TITLE",add_meta:"META",add_script:"SCRIPT",add_style:"STYLE",add_link:"LINK",add_base:"BASE",add_comment:"Coment\u00e1rio",title_element:"TITLE",script_element:"SCRIPT",style_element:"STYLE",base_element:"BASE",link_element:"LINK",meta_element:"META",comment_element:"Coment\u00e1rio",src:"Src",language:"Idioma",href:"Href",target:"Alvo",type:"Tipo",charset:"Charset",defer:"Adiar",media:"Media",properties:"Propriedades",name:"Nome",value:"Valor",content:"Conte\u00fado",rel:"rel",rev:"rev",hreflang:"Href lang",general_props:"Geral",advanced_props:"Avan\u00e7ado"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/el_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000002005211526350530033745 0ustar frankiefrankietinyMCE.addI18n('el.fullpage_dlg',{title:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03b5\u03b3\u03b3\u03c1\u03ac\u03c6\u03bf\u03c5",meta_tab:"\u0393\u03b5\u03bd\u03b9\u03ba\u03ac",appearance_tab:"\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7",advanced_tab:"\u0393\u03b9\u03b1 \u03c0\u03c1\u03bf\u03c7\u03c9\u03c1\u03b7\u03bc\u03ad\u03bd\u03bf\u03c5\u03c2",meta_props:"\u039c\u03b5\u03c4\u03b1-\u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2",langprops:"\u0393\u03bb\u03ce\u03c3\u03c3\u03b1 \u03ba\u03b1\u03b9 \u03ba\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7",meta_title:"\u03a4\u03af\u03c4\u03bb\u03bf\u03c2",meta_keywords:"\u039b\u03ad\u03be\u03b5\u03b9\u03c2 \u03ba\u03bb\u03b5\u03b9\u03b4\u03b9\u03ac",meta_description:"\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae",meta_robots:"\u03a1\u03bf\u03bc\u03c0\u03cc\u03c4",doctypes:"Doctype",langcode:"\u039a\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2",langdir:"\u039a\u03b1\u03c4\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1\u03c2",ltr:"\u0391\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac \u03c0\u03c1\u03bf\u03c2 \u03b4\u03b5\u03be\u03b9\u03ac",rtl:"\u0394\u03b5\u03be\u03b9\u03ac \u03c0\u03c1\u03bf\u03c2 \u03b1\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03ac",xml_pi:"\u0394\u03ae\u03bb\u03c9\u03c3\u03b7 XML",encoding:"\u039a\u03c9\u03b4\u03b9\u03ba\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd",appearance_bgprops:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5",appearance_marginprops:"\u03a0\u03b5\u03c1\u03b9\u03b8\u03ce\u03c1\u03b9\u03b1 \u03c3\u03ce\u03bc\u03b1\u03c4\u03bf\u03c2",appearance_linkprops:"\u03a7\u03c1\u03ce\u03bc\u03b1\u03c4\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03c9\u03bd",appearance_textprops:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5",bgcolor:"\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5",bgimage:"\u0395\u03b9\u03ba\u03cc\u03bd\u03b1 \u03c6\u03cc\u03bd\u03c4\u03bf\u03c5",left_margin:"\u0391\u03c1\u03b9\u03c3\u03c4\u03b5\u03c1\u03cc \u03c0\u03b5\u03c1\u03b9\u03b8\u03ce\u03c1\u03b9\u03bf",right_margin:"\u0394\u03b5\u03be\u03b9\u03cc \u03c0\u03b5\u03c1\u03b9\u03b8\u03ce\u03c1\u03b9\u03bf",top_margin:"\u03a0\u03ac\u03bd\u03c9 \u03c0\u03b5\u03c1\u03b9\u03b8\u03ce\u03c1\u03b9\u03bf",bottom_margin:"\u039a\u03ac\u03c4\u03c9 \u03c0\u03b5\u03c1\u03b9\u03b8\u03ce\u03c1\u03b9\u03bf",text_color:"\u03a7\u03c1\u03ce\u03bc\u03b1 \u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5",font_size:"\u039c\u03ad\u03b3\u03b5\u03b8\u03bf\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ac\u03c4\u03c9\u03bd",font_face:"\u0393\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03bf\u03c3\u03b5\u03b9\u03c1\u03ac",link_color:"\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",hover_color:"\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5 (Hover)",visited_color:"\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5 (Visited)",active_color:"\u03a7\u03c1\u03ce\u03bc\u03b1 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5 (Active)",textcolor:"\u03a7\u03c1\u03ce\u03bc\u03b1",fontsize:"\u039c\u03ad\u03b3\u03b5\u03b8\u03bf\u03c2 \u03b3\u03c1\u03b1\u03bc\u03bc\u03ac\u03c4\u03c9\u03bd",fontface:"\u0393\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03bf\u03c3\u03b5\u03b9\u03c1\u03ac",meta_index_follow:"\u039a\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b7\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b7\u03b8\u03bf\u03cd\u03bd \u03bf\u03b9 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03b9",meta_index_nofollow:"\u039a\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b7\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03bc\u03b7\u03bd \u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b7\u03b8\u03bf\u03cd\u03bd \u03bf\u03b9 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03b9",meta_noindex_follow:"\u03a7\u03c9\u03c1\u03af\u03c2 \u03ba\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b7\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b7\u03b8\u03bf\u03cd\u03bd \u03bf\u03b9 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03b9",meta_noindex_nofollow:"\u03a7\u03c9\u03c1\u03af\u03c2 \u03ba\u03b1\u03c4\u03b1\u03c7\u03ce\u03c1\u03b7\u03c3\u03b7 \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03bc\u03b7\u03bd \u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03b7\u03b8\u03bf\u03cd\u03bd \u03bf\u03b9 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03bc\u03bf\u03b9",appearance_style:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2 \u03c3\u03c4\u03c5\u03bb \u03ba\u03b1\u03b9 \u03b1\u03c1\u03c7\u03b5\u03af\u03bf\u03c5 \u03c3\u03c4\u03c5\u03bb",stylesheet:"\u0391\u03c1\u03c7\u03b5\u03af\u03bf \u03c3\u03c4\u03c5\u03bb",style:"\u03a3\u03c4\u03c5\u03bb",author:"\u03a3\u03c5\u03b3\u03b3\u03c1\u03b1\u03c6\u03ad\u03b1\u03c2",copyright:"\u0394\u03b9\u03ba\u03b1\u03af\u03c9\u03bc\u03b1 \u03ba\u03b1\u03c4\u03b1\u03c3\u03ba\u03b5\u03c5\u03b1\u03c3\u03c4\u03ae",add:"\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5",remove:"\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5",moveup:"\u039c\u03b5\u03c4\u03b1\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5 \u03c0\u03ac\u03bd\u03c9",movedown:"\u039c\u03b5\u03c4\u03b1\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03b5\u03c0\u03b9\u03bb\u03b5\u03b3\u03bc\u03ad\u03bd\u03bf\u03c5 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf\u03c5 \u03ba\u03ac\u03c4\u03c9",head_elements:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03ba\u03b5\u03c6\u03b1\u03bb\u03ae\u03c2",info:"\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2",add_title:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03c4\u03af\u03c4\u03bb\u03bf\u03c5",add_meta:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03bc\u03b5\u03c4\u03b1-\u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2",add_script:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf Script",add_style:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03c3\u03c4\u03c5\u03bb",add_link:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",add_base:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03b2\u03ac\u03c3\u03b7\u03c2",add_comment:"\u039a\u03cc\u03bc\u03b2\u03bf\u03c2 \u03c3\u03c7\u03bf\u03bb\u03af\u03bf\u03c5",title_element:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03c4\u03af\u03c4\u03bb\u03bf\u03c5",script_element:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf Script",style_element:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03c3\u03c4\u03c5\u03bb",base_element:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03b2\u03ac\u03c3\u03b7\u03c2",link_element:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5",meta_element:"\u03a3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03bf \u03bc\u03b5\u03c4\u03b1-\u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b1\u03c2",comment_element:"\u03a3\u03c7\u03cc\u03bb\u03b9\u03bf",src:"\u03a0\u03b7\u03b3\u03ae",language:"\u0393\u03bb\u03ce\u03c3\u03c3\u03b1",href:"Href",target:"\u03a3\u03c4\u03cc\u03c7\u03bf\u03c2",type:"\u03a4\u03cd\u03c0\u03bf\u03c2",charset:"\u03a3\u03b5\u03c4 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03ae\u03c1\u03c9\u03bd",defer:"Defer",media:"Media",properties:"\u0399\u03b4\u03b9\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",name:"\u038c\u03bd\u03bf\u03bc\u03b1",value:"\u03a4\u03b9\u03bc\u03ae",content:"\u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf",rel:"Rel",rev:"Rev",hreflang:"\u0393\u03bb\u03ce\u03c3\u03c3\u03b1 Href",general_props:"\u0393\u03b5\u03bd\u03b9\u03ba\u03ac",advanced_props:"\u0393\u03b9\u03b1 \u03c0\u03c1\u03bf\u03c7\u03c9\u03c1\u03b7\u03bc\u03ad\u03bd\u03bf\u03c5\u03c2"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/fa_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001356511526350530033760 0ustar frankiefrankietinyMCE.addI18n('fa.fullpage_dlg',{title:"\u0645\u0634\u062e\u0635\u0627\u062a \u0633\u0646\u062f",meta_tab:"\u0639\u0645\u0648\u0645\u06cc",appearance_tab:"\u0638\u0627\u0647\u0631",advanced_tab:"\u067e\u06cc\u0634\u0631\u0641\u062a\u0647",meta_props:"\u0627\u0637\u0644\u0627\u0639\u0627\u062a \u0645\u062a\u0627 (Meta)",langprops:"\u0632\u0628\u0627\u0646 \u0648 \u0631\u0645\u0632\u06af\u0630\u0627\u0631\u06cc (Encoding)",meta_title:"\u0639\u0646\u0648\u0627\u0646",meta_keywords:"\u06a9\u0644\u0645\u0627\u062a \u06a9\u0644\u06cc\u062f\u06cc",meta_description:"\u062a\u0648\u0636\u06cc\u062d",meta_robots:"\u0631\u0648\u0628\u0627\u062a \u0647\u0627 (Robots)",doctypes:"\u0646\u0648\u0639 \u0633\u0646\u062f",langcode:"\u06a9\u062f \u0632\u0628\u0627\u0646",langdir:"\u062c\u0647\u062a \u0632\u0628\u0627\u0646",ltr:"\u0686\u067e \u0628\u0647 \u0631\u0627\u0633\u062a",rtl:"\u0631\u0627\u0633\u062a \u0628\u0647 \u0686\u067e",xml_pi:"\u0627\u0639\u0644\u0627\u0646 XML",encoding:"\u0631\u0645\u0632\u06af\u0630\u0627\u0631\u06cc (Encoding) \u06a9\u0627\u0631\u0627\u06a9\u062a\u0631",appearance_bgprops:"\u0645\u0634\u062e\u0635\u0627\u062a \u0632\u0645\u06cc\u0646\u0647",appearance_marginprops:"\u062d\u0627\u0634\u06cc\u0647 \u0647\u0627\u06cc \u0628\u062f\u0646\u0647 (Body)",appearance_linkprops:"\u0631\u0646\u06af \u0647\u0627\u06cc \u0644\u06cc\u0646\u06a9",appearance_textprops:"\u0645\u0634\u062e\u0635\u0627\u062a \u0645\u062a\u0646",bgcolor:"\u0631\u0646\u06af \u0632\u0645\u06cc\u0646\u0647",bgimage:"\u062a\u0635\u0648\u06cc\u0631 \u0632\u0645\u06cc\u0646\u0647",left_margin:"\u062d\u0627\u0634\u06cc\u0647 \u0686\u067e",right_margin:"\u062d\u0627\u0634\u06cc\u0647 \u0631\u0627\u0633\u062a",top_margin:"\u062d\u0627\u0634\u06cc\u0647 \u0628\u0627\u0644\u0627",bottom_margin:"\u062d\u0627\u0634\u06cc\u0647 \u067e\u0627\u06cc\u06cc\u0646",text_color:"\u0631\u0646\u06af \u0645\u062a\u0646",font_size:"\u0627\u0646\u062f\u0627\u0632\u0647 \u0642\u0644\u0645",font_face:"\u0638\u0627\u0647\u0631 \u0642\u0644\u0645",link_color:"\u0631\u0646\u06af \u0642\u0644\u0645",hover_color:"\u0631\u0646\u06af \u062f\u0631 \u062d\u0627\u0644\u062a \u0642\u0631\u0627\u0631\u06af\u06cc\u0631\u06cc \u0645\u0648\u0633",visited_color:"\u0631\u0646\u06af \u062f\u0631 \u062d\u0627\u0644\u062a \u0628\u0627\u0632\u062f\u06cc\u062f \u0634\u062f\u0647",active_color:"\u0631\u0646\u06af \u062f\u0631 \u062d\u0627\u0644\u062a \u0641\u0639\u0627\u0644",textcolor:"\u0631\u0646\u06af",fontsize:"\u0627\u0646\u062f\u0627\u0632\u0647 \u0642\u0644\u0645",fontface:"\u062e\u0627\u0646\u0648\u0627\u062f\u0647 \u0642\u0644\u0645",meta_index_follow:"\u0641\u0647\u0631\u0633\u062a \u0648 \u062f\u0646\u0628\u0627\u0644\u0647 \u0631\u0648\u06cc \u0644\u06cc\u0646\u06a9 \u0647\u0627",meta_index_nofollow:"\u0641\u0647\u0631\u0633\u062a \u0648 \u0639\u062f\u0645 \u062f\u0646\u0628\u0627\u0644\u0647 \u0631\u0648\u06cc \u0644\u06cc\u0646\u06a9 \u0647\u0627",meta_noindex_follow:"\u0639\u062f\u0645 \u0641\u0647\u0631\u0633\u062a \u0627\u0645\u0627 \u062f\u0646\u0628\u0627\u0644\u0647 \u0631\u0648\u06cc \u0644\u06cc\u0646\u06a9 \u0647\u0627",meta_noindex_nofollow:"\u0639\u062f\u0645 \u0641\u0647\u0631\u0633\u062a \u0648 \u0639\u062f\u0645 \u062f\u0646\u0628\u0627\u0644\u0647 \u0631\u0648\u06cc \u0644\u06cc\u0646\u06a9 \u0647\u0627",appearance_style:"\u0648\u0631\u0642\u0647 \u0627\u0633\u062a\u06cc\u0644 \u0648 \u0645\u0634\u062e\u0635\u0627\u062a \u0627\u0633\u062a\u06cc\u0644",stylesheet:"\u0648\u0631\u0642\u0647 \u0627\u0633\u062a\u06cc\u0644",style:"\u0627\u0633\u062a\u06cc\u0644",author:"\u0645\u0624\u0644\u0641",copyright:"\u062d\u0642 \u0627\u0646\u062d\u0635\u0627\u0631\u06cc",add:"\u0627\u0641\u0632\u0648\u062f\u0646 \u0639\u0646\u0635\u0631 \u062c\u062f\u06cc\u062f",remove:"\u062d\u0630\u0641 \u0639\u0646\u0635\u0631 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647",moveup:"\u0627\u0646\u062a\u0642\u0627\u0644 \u0639\u0646\u0635\u0631 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647 \u0628\u0647 \u0628\u0627\u0644\u0627",movedown:"\u0627\u0646\u062a\u0642\u0627\u0644 \u0639\u0646\u0635\u0631 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647 \u0628\u0647 \u067e\u0627\u06cc\u06cc\u0646",head_elements:"\u0639\u0646\u0627\u0635\u0631 \u0633\u0631 (Head)",info:"\u0627\u0637\u0644\u0627\u0639\u0627\u062a",add_title:"\u0639\u0646\u0635\u0631 \u0639\u0646\u0648\u0627\u0646",add_meta:"\u0639\u0646\u0635\u0631 \u0645\u062a\u0627 (Meta)",add_script:"\u0639\u0646\u0635\u0631 \u0627\u0633\u06a9\u0631\u06cc\u067e\u062a (Script)",add_style:"\u0639\u0646\u0635\u0631 \u0627\u0633\u062a\u06cc\u0644 (Style)",add_link:"\u0639\u0646\u0635\u0631 \u0644\u06cc\u0646\u06a9 (Link)",add_base:"\u0639\u0646\u0635\u0631 \u067e\u0627\u06cc\u0647 (Base)",add_comment:"\u06af\u0631\u0647 \u062a\u0648\u0636\u06cc\u062d",title_element:"\u0639\u0646\u0635\u0631 \u0639\u0646\u0648\u0627\u0646 (Title)",script_element:"\u0639\u0646\u0635\u0631 \u0627\u0633\u06a9\u0631\u06cc\u067e\u062a (Script)",style_element:"\u0639\u0646\u0635\u0631 \u0627\u0633\u062a\u06cc\u0644 (Style)",base_element:"\u0639\u0646\u0635\u0631 \u067e\u0627\u06cc\u0647",link_element:"\u0639\u0646\u0635\u0631 \u0644\u06cc\u0646\u06a9",meta_element:"\u0639\u0646\u0635\u0631 \u0645\u062a\u0627 (Meta)",comment_element:"\u062a\u0648\u0636\u06cc\u062d",src:"\u0645\u0646\u0628\u0639 (Src)",language:"\u0632\u0628\u0627\u0646",href:"\u0622\u062f\u0631\u0633 (Href)",target:"\u0645\u0642\u0635\u062f (Target)",type:"\u0646\u0648\u0639",charset:"\u0645\u062c\u0645\u0648\u0639\u0647 \u06a9\u0627\u0631\u0627\u06a9\u062a\u0631 (Charset)",defer:"Defer",media:"\u0631\u0633\u0627\u0646\u0647 (Media)",properties:"\u0645\u0634\u062e\u0635\u0627\u062a",name:"\u0646\u0627\u0645",value:"\u0645\u0642\u062f\u0627\u0631",content:"\u0645\u062d\u062a\u0648\u0627",rel:"Rel",rev:"Rev",hreflang:"\u0632\u0628\u0627\u0646 Href",general_props:"\u0639\u0645\u0648\u0645\u06cc",advanced_props:"\u067e\u06cc\u0634\u0631\u0641\u062a\u0647"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/km_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001534511526350530033756 0ustar frankiefrankietinyMCE.addI18n('km.fullpage_dlg',{title:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u17af\u1780\u179f\u17b6\u179a",meta_tab:"\u1791\u17bc\u1791\u17c5",appearance_tab:"\u179a\u17bc\u1794\u179a\u17b6\u1784",advanced_tab:"\u1780\u1798\u17d2\u179a\u17b7\u178f\u1781\u17d2\u1796\u179f\u17cb",meta_props:"\u1796\u17d0\u178f\u17cc\u1798\u17b6\u1793\u1798\u17c1\u178f\u17b6",langprops:"\u1797\u17b6\u179f\u17b6 \u1793\u17b7\u1784 \u1780\u17bc\u178a\u179f\u17d2\u179a\u17b6\u1799",meta_title:"\u1785\u17c6\u178e\u1784\u1787\u17be\u1784",meta_keywords:"\u1796\u17b6\u1780\u17d2\u1799\u1782\u1793\u17d2\u179b\u17b9\u17c7",meta_description:"\u1796\u17b7\u1796\u178e\u17cc\u1793\u17b6",meta_robots:"\u1798\u1793\u17bb\u179f\u17d2\u179f\u1799\u1793\u17d2\u178f",doctypes:"\u1794\u17d2\u179a\u1797\u17c1\u1791\u17af\u1780\u179f\u17b6\u179a",langcode:"\u1780\u17bc\u178a\u1797\u17b6\u179f\u17b6",langdir:"\u1791\u17b7\u179f\u178a\u17c5\u1797\u17b6\u179f\u17b6",ltr:"\u1796\u17b8\u1786\u17d2\u179c\u17c1\u1784\u1791\u17c5\u179f\u17d2\u178f\u17b6\u17c6",rtl:"\u1796\u17b8\u179f\u17d2\u178f\u17b6\u17c6\u1791\u17c5\u1786\u17d2\u179c\u17c1\u1784",xml_pi:"\u1780\u17b6\u179a\u1794\u17d2\u179a\u1780\u17b6\u179f XML",encoding:"\u1780\u17bc\u178a\u179f\u17d2\u179a\u17b6\u1799\u178f\u17bd\u17a2\u1780\u17d2\u179f\u179a",appearance_bgprops:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u1795\u17d2\u1791\u17c3\u1781\u17b6\u1784\u1780\u17d2\u179a\u17c4\u1799",appearance_marginprops:"\u179a\u17b9\u1798\u178f\u17bd",appearance_linkprops:"\u1796\u178e\u17cc\u178f\u17c6\u178e",appearance_textprops:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u17a2\u178f\u17d2\u1790\u1794\u1791",bgcolor:"\u1796\u178e\u17cc\u1795\u17d2\u1791\u17c3\u1781\u17b6\u1784\u1780\u17d2\u179a\u17c4\u1799",bgimage:"\u179a\u17bc\u1794\u1797\u17b6\u1796\u1795\u17d2\u1791\u17c3\u1781\u17b6\u1784\u1780\u17d2\u179a\u17c4\u1799",left_margin:"\u179a\u17b9\u1798\u1786\u17d2\u179c\u17c1\u1784",right_margin:"\u179a\u17b9\u1798\u179f\u17d2\u178f\u17b6\u17c6",top_margin:"\u179a\u17b9\u1798\u179b\u17be",bottom_margin:"\u179a\u17b9\u1798\u1780\u17d2\u179a\u17c4\u1798",text_color:"\u1796\u178e\u17cc\u17a2\u178f\u17d2\u1790\u1794\u1791",font_size:"\u1791\u17c6\u17a0\u17c6\u1796\u17bb\u1798\u17d2\u1796\u17a2\u1780\u17d2\u179f\u179a",font_face:"\u1796\u17bb\u1798\u17d2\u1796\u17a2\u1780\u17d2\u179f\u179a\u179f\u1793\u17d2\u1798\u178f",link_color:"\u1796\u178e\u17cc\u178f\u17c6\u178e",hover_color:"\u1796\u178e\u17cc\u178a\u17b6\u1780\u17cb\u179b\u17be",visited_color:"\u1796\u178e\u17cc\u1791\u179f\u17d2\u179f\u1793\u17b6\u179a\u17bd\u1785",active_color:"\u1796\u178e\u17cc\u179f\u1780\u1798\u17d2\u1798",textcolor:"\u1796\u178e\u17cc",fontsize:"\u1791\u17c6\u17a0\u17c6\u1796\u17bb\u1798\u17d2\u1796\u17a2\u1780\u17d2\u179f\u179a",fontface:"\u179f\u17d2\u179a\u179b\u17b6\u1799\u17a2\u1780\u17d2\u179f\u179a",meta_index_follow:"\u1785\u1784\u17d2\u17a2\u17bb\u179b \u1793\u17b7\u1784 \u178f\u17b6\u1798\u178f\u17c6\u178e\u1791\u17b6\u17c6\u1784\u1793\u17c1\u17c7",meta_index_nofollow:"\u1785\u1784\u17d2\u17a2\u17bb\u179b \u1793\u17b7\u1784\u1798\u17b7\u1793\u178f\u17b6\u1798\u178f\u17c6\u178e\u1791\u17b6\u17c6\u1784\u1793\u17c1\u17c7",meta_noindex_follow:"\u1780\u17bb\u17c6\u1785\u1784\u17d2\u17a2\u17bb\u179b \u1793\u17b7\u1784\u178f\u17b6\u1798\u178f\u17c6\u178e\u1791\u17b6\u17c6\u1784\u1793\u17c1\u17c7",meta_noindex_nofollow:"\u1780\u17bb\u17c6\u1785\u1784\u17d2\u17a2\u17bb\u179b \u1793\u17b7\u1784 \u1780\u17bb\u17c6\u178f\u17b6\u1798\u178f\u17c6\u178e\u1791\u17b6\u17c6\u1784\u1793\u17c1\u17c7",appearance_style:"\u179f\u1793\u17d2\u179b\u17b9\u1780\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798 \u1793\u17b7\u1784 \u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798",stylesheet:"\u179f\u1793\u17d2\u179b\u17b9\u1780\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798",style:"\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798",author:"\u17a2\u17d2\u1793\u1780\u1793\u17b7\u1796\u1793\u17d2\u1792",copyright:"\u179a\u1780\u17d2\u179f\u17b6\u179f\u17b7\u1791\u17d2\u1792\u17b7",add:"\u1794\u1793\u17d2\u1790\u17c2\u1798\u1792\u17b6\u178f\u17bb\u1790\u17d2\u1798\u17b8",remove:"\u178a\u1780\u1792\u17b6\u178f\u17bb\u178a\u17c2\u179b\u1794\u17b6\u1793\u1787\u17d2\u179a\u17be\u179f\u1785\u17c1\u1789",moveup:"\u1795\u17d2\u179b\u17b6\u179f\u17cb\u1791\u17b8\u1792\u17b6\u178f\u17bb\u178a\u17c2\u179b\u1794\u17b6\u1793\u1787\u17d2\u179a\u17be\u179f\u17a1\u17be\u1784\u179b\u17be",movedown:"\u1795\u17d2\u179b\u17b6\u179f\u17cb\u1791\u17b8\u1792\u17b6\u178f\u17bb\u178a\u17c2\u179b\u1794\u17b6\u1793\u1787\u17d2\u179a\u17be\u179f\u1785\u17bb\u17c7\u1780\u17d2\u179a\u17c4\u1798",head_elements:"\u1792\u17b6\u178f\u17bb\u1787\u17b6\u1780\u17d2\u1794\u17b6\u179b",info:"\u1796\u17d0\u178f\u17cc\u1798\u17b6\u1793",add_title:"\u1792\u17b6\u178f\u17bb\u1785\u17c6\u178e\u1784\u1787\u17be\u1784",add_meta:"\u1792\u17b6\u178f\u17bb\u1798\u17c1\u178f\u17b6",add_script:"\u1792\u17b6\u178f\u17bb\u179f\u17d2\u1782\u17d2\u179a\u17b8\u1794",add_style:"\u1792\u17b6\u178f\u17bb\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798",add_link:"\u1792\u17b6\u178f\u17bb\u178f\u17c6\u178e",add_base:"\u1792\u17b6\u178f\u17bb\u1782\u17c4\u179b",add_comment:"\u1790\u17d2\u1793\u17b6\u17c6\u1784\u179f\u17c1\u1785\u1780\u17d2\u178f\u17b8\u17a2\u1792\u17b7\u1794\u17d2\u1794\u17b6\u1799",title_element:"\u1792\u17b6\u178f\u17bb\u1785\u17c6\u178e\u1784\u1787\u17be\u1784",script_element:"\u1792\u17b6\u178f\u17bb\u179f\u17d2\u179a\u17d2\u1782\u17b8\u1794",style_element:"\u1792\u17b6\u178f\u17bb\u179a\u1785\u1793\u17b6\u1794\u17d0\u1791\u17d2\u1798",base_element:"\u1792\u17b6\u178f\u17bb\u1782\u17c4\u179b",link_element:"\u1792\u17b6\u178f\u17bb\u178f\u17c6\u178e",meta_element:"\u1792\u17b6\u178f\u17bb\u1798\u17c1\u178f\u17b6",comment_element:"\u179f\u17c1\u1785\u1780\u17d2\u178f\u17b8\u17a2\u1792\u17b7\u1794\u17d2\u1794\u17b6\u1799",src:"\u1794\u17d2\u179a\u1797\u1796src",language:"\u1797\u17b6\u179f\u17b6",href:"\u17a2\u17b6\u179f\u1799\u178a\u17d2\u178b\u17b6\u1793Href",target:"\u1782\u17c4\u179b\u178a\u17c5",type:"\u1794\u17d2\u179a\u1797\u17c1\u1791",charset:"\u179f\u17c6\u178e\u17bb\u17c6\u178f\u17bd\u17a2\u1780\u17d2\u179f\u179a",defer:"\u1796\u1793\u17d2\u1799\u17b6\u1796\u17c1\u179b",media:"\u1798\u17c1\u178c\u17c0",properties:"\u179b\u1780\u17d2\u1781\u178e\u17c8\u179f\u1798\u17d2\u1794\u178f\u17d2\u178f\u17b7",name:"\u1788\u17d2\u1798\u17c4\u17c7",value:"\u178f\u1798\u17d2\u179b\u17c3",content:"\u1798\u17b6\u178f\u17b7\u1780\u17b6",rel:"Rel",rev:"Rev",hreflang:"Href",general_props:"\u1791\u17bc\u1791\u17c5",advanced_props:"\u1780\u1798\u17d2\u179a\u17b7\u178f\u1781\u17d2\u1796\u179f\u17cb"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/lb_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000461611526350530033755 0ustar frankiefrankietinyMCE.addI18n('lb.fullpage_dlg',{title:"Dokument-Eegeschaften",meta_tab:"Allgemeng",appearance_tab:"Ausgesinn",advanced_tab:"Erweidert",meta_props:"Meta-Informatioun",langprops:"Sprooch a Kod\u00e9ierung",meta_title:"Titel",meta_keywords:"Sch\u00ebsselwierder",meta_description:"Beschreiwung",meta_robots:"Roboter",doctypes:"DocType",langcode:"Sproochcode",langdir:"Spoochrichtung",ltr:"L\u00e9nks no Riets",rtl:"Riets no L\u00e9nks",xml_pi:"XML Deklaratioun",encoding:"Zeechekod\u00e9ierung",appearance_bgprops:"Hannergrond-Eegeschaften",appearance_marginprops:"Ofst\u00e4nn vum Body",appearance_linkprops:"Linkfuerwen",appearance_textprops:"Text-Eegeschaften",bgcolor:"Hannergrondfuerf",bgimage:"Hannergrondbild",left_margin:"L\u00e9nken Ofstand",right_margin:"Rietsen Ofstand",top_margin:"Ieweschten Ofstand",bottom_margin:"\u00cbnneschten Ofstand",text_color:"Textfuerf",font_size:"Schr\u00ebftgr\u00e9isst",font_face:"Schr\u00ebftaart",link_color:"Linkfuerf",hover_color:"Hover-Fuerf",visited_color:"Besicht-Fuerf",active_color:"Aktiv-Fuerf",textcolor:"Fuerf",fontsize:"Schr\u00ebftgr\u00e9ist",fontface:"Schr\u00ebftaart",meta_index_follow:"Indiz\u00e9ieren, an de Linken nogoen",meta_index_nofollow:"Indiz\u00e9ieren, m\u00e4 de Linken net nogoen",meta_noindex_follow:"Net indiz\u00e9ieren, m\u00e4 de Linken nogoen",meta_noindex_nofollow:"Net indiz\u00e9ieren an och net de Linken nogoen",appearance_style:"CSS-Stil Blat a Stileegeschaften",stylesheet:"CSS-Stil Blat",style:"CSS-Stil",author:"Auteur",copyright:"Copyright",add:"Neit Element b\u00e4if\u00fcgen",remove:"Ausgewielt Element ewechhuelen",moveup:"Ausgewielt Element nach uewen beweegen",movedown:"Ausgewielt Element no \u00ebnnen beweegen",head_elements:"Iwwerschr\u00ebftenelementer",info:"Informatioun",add_title:"Titel-Element",add_meta:"Meta-Element",add_script:"Script-Element",add_style:"Stil-Element",add_link:"Link-Element",add_base:"Basis-Element",add_comment:"HTML-Kommentar",title_element:"Titel-Element",script_element:"Script-Element",style_element:"Stil-Element",base_element:"Basis-Element",link_element:"Link-Element",meta_element:"Meta_Element",comment_element:"Kommentar",src:"Src",language:"Sprooche",href:"Href",target:"Zil",type:"Typ",charset:"Zeechesaz",defer:"Defer",media:"Media",properties:"Eegeschaften",name:"Numm",value:"W\u00e4ert",content:"Inhalt",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Allgemeng",advanced_props:"Erweidert"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/lv_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('lv.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/sl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000427211526350530033753 0ustar frankiefrankietinyMCE.addI18n('sl.fullpage_dlg',{title:"Lastnosti dokumenta",meta_tab:"Splo\u0161no",appearance_tab:"Izgled",advanced_tab:"Napredno",meta_props:"Meta podatki",langprops:"Jezik in kodiranje",meta_title:"Naslov",meta_keywords:"Klju\u010dne besede",meta_description:"Opis",meta_robots:"Roboti",doctypes:"Doctype",langcode:"Koda jezika",langdir:"Smer pisave",ltr:"Od leve proti desni",rtl:"Od desne proti levi",xml_pi:"Najava XML",encoding:"Kodiranje znakov",appearance_bgprops:"Lastnosti ozadja",appearance_marginprops:"Robovi telesa",appearance_linkprops:"Barve povezav",appearance_textprops:"Lastnosti besedila",bgcolor:"Barva ozadja",bgimage:"Slika ozadja",left_margin:"Levi rob",right_margin:"Desni rob",top_margin:"Zgornji rob",bottom_margin:"Spodnji rob",text_color:"Barva pisave",font_size:"Velikost pisave",font_face:"Vrsta pisave",link_color:"Barva povezave",hover_color:"Barva nakazane povezave",visited_color:"Barva obiskane povezave",active_color:"Barva dejavne povezave",textcolor:"Barva",fontsize:"Velikost pisave",fontface:"Dru\u017eina pisave",meta_index_follow:"Indeksiraj in sledi povezavam",meta_index_nofollow:"Indeksiraj a ne sledi povezavam",meta_noindex_follow:"Ne indeksiraj a sledi pvoezavams",meta_noindex_nofollow:"Ne indeksiraj in ne sledi povezavam",appearance_style:"Lastnosti slogov",stylesheet:"Slogi",style:"Slog",author:"Avtor",copyright:"Copyright",add:"Dodaj element",remove:"Odstrani izbrani element",moveup:"Premakni izbrani element navzgor",movedown:"Premakni izbrani element navzdol",head_elements:"Elementi glave",info:"Informacija",add_title:"element Title",add_meta:"element Meta",add_script:"element Script",add_style:"element Style",add_link:"element Link",add_base:"element Base",add_comment:"komentar",title_element:"element Title",script_element:"element Script",style_element:"element Style",base_element:"element Base",link_element:"element Link",meta_element:"element Meta",comment_element:"komentar",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Lastnosti",name:"ime",value:"vrednost",content:"vsebina",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Splo\u0161no",advanced_props:"Napredno"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ta_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('ta.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/nl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000434111526350530033750 0ustar frankiefrankietinyMCE.addI18n('nl.fullpage_dlg',{title:"Documenteigenschappen",meta_tab:"Algemeen",appearance_tab:"Weergave",advanced_tab:"Geavanceerd",meta_props:"Meta informatie",langprops:"Taal en codering",meta_title:"Titel",meta_keywords:"Sleutelwoorden",meta_description:"Beschrijving",meta_robots:"Robots",doctypes:"Doctype",langcode:"Taalcode",langdir:"Taalrichting",ltr:"Van links naar rechts",rtl:"Van rechts naar links",xml_pi:"XML toewijzing",encoding:"Karaktercodering",appearance_bgprops:"Achtergrondeigenschappen",appearance_marginprops:"Bodymarge",appearance_linkprops:"Linkkleuren",appearance_textprops:"Teksteigenschappen",bgcolor:"Achtergrondkleur",bgimage:"Achtergrondafbeelding",left_margin:"Linkermarge",right_margin:"Rechtermarge",top_margin:"Bovenmarge",bottom_margin:"Ondermarge",text_color:"Tekstkleur",font_size:"Tekengrootte",font_face:"Lettertype",link_color:"Linkkleur",hover_color:"Hoverkleur",visited_color:"Bezocht kleur",active_color:"Actieve kleur",textcolor:"Kleur",fontsize:"Tekengrootte",fontface:"Lettertype",meta_index_follow:"Links indexeren en volgen",meta_index_nofollow:"Links indexeren maar niet volgen",meta_noindex_follow:"Links volgen maar niet indexeren",meta_noindex_nofollow:"Links niet indexeren en niet volgen",appearance_style:"Stijlblad en stijleigenschappen",stylesheet:"Stijlblad",style:"Stijl",author:"Auteur",copyright:"Copyright",add:"Nieuw element toevoegen",remove:"Geselecteerde elementen verwijderen",moveup:"Geselecteerde elementen omhoog verplaatsen",movedown:"Geselecteerde elementen omlaag verplaatsen",head_elements:"Kopelementen",info:"Informatie",add_title:"Titelelement",add_meta:"Meta-element",add_script:"Scriptelement",add_style:"Stijlelement",add_link:"Linkelement",add_base:"Basiselement",add_comment:"Opmerkingknooppunt",title_element:"Titelelement",script_element:"Scriptelement",style_element:"Stijlelement",base_element:"Basiselement",link_element:"Linkelement",meta_element:"Meta-element",comment_element:"Opmerking",src:"Bron",language:"Taal",href:"Href",target:"Doel",type:"Type",charset:"Karakterset",defer:"Uitstellen",media:"Media",properties:"Eigenschappen",name:"Naam",value:"Waarde",content:"Inhoud",rel:"Rel",rev:"Rev",hreflang:"Href taal",general_props:"Algemeen",advanced_props:"Geavanceerd"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/be_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('be.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/sv_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000454711526350530033760 0ustar frankiefrankietinyMCE.addI18n('sv.fullpage_dlg',{title:"Dokumentinst\u00e4llningar",meta_tab:"Generella",appearance_tab:"Utseende",advanced_tab:"Avancerat",meta_props:"Metainformation",langprops:"Spr\u00e5k och kodning",meta_title:"Titel",meta_keywords:"Nyckelord",meta_description:"Bekrivning",meta_robots:"Robots",doctypes:"Doctype",langcode:"Spr\u00e5kkod",langdir:"Skriftriktning",ltr:"V\u00e4nster till h\u00f6ger",rtl:"H\u00f6ger till v\u00e4nster",xml_pi:"XML deklaration",encoding:"Teckenkodning",appearance_bgprops:"Bakgrundsinst\u00e4llningar",appearance_marginprops:"Body marginaler",appearance_linkprops:"L\u00e4nkf\u00e4rger",appearance_textprops:"Textinst\u00e4llningar",bgcolor:"Bakgrundsf\u00e4rg",bgimage:"Bakgrundsbild",left_margin:"V\u00e4nstermarginal",right_margin:"H\u00f6germarginal",top_margin:"Toppmarginal",bottom_margin:"Bottenmarginal",text_color:"Textf\u00e4rg",font_size:"Textstorlek",font_face:"Textstil",link_color:"L\u00e4nkf\u00e4rg",hover_color:"Hover f\u00e4rg",visited_color:"Visited f\u00e4rg",active_color:"Active f\u00e4rg",textcolor:"F\u00e4rg",fontsize:"Textstorlek",fontface:"Textstil",meta_index_follow:"Indexera och f\u00f6lj l\u00e4nkar",meta_index_nofollow:"Indexera men f\u00f6lj ej l\u00e4nkar",meta_noindex_follow:"Indexera inte men f\u00f6lj l\u00e4nkar",meta_noindex_nofollow:"Indexera inte och f\u00f6lj ej l\u00e4nkar",appearance_style:"Stilmall och stilegenskaper",stylesheet:"Stilmall",style:"Stil",author:"F\u00f6rfattare",copyright:"Copyright",add:"L\u00e4gg till element",remove:"Radera det markerade elementet",moveup:"Flytta det markerade elementet upp\u00e5t",movedown:"Flytta det markerade elementet ned\u00e5t",head_elements:"Head element",info:"Information",add_title:"Titel-element",add_meta:"Meta-element",add_script:"Script-element",add_style:"Stil-element",add_link:"L\u00e4nk-element",add_base:"Base-element",add_comment:"Kommentarsnod",title_element:"Titel-element",script_element:"Script-element",style_element:"Style-element",base_element:"Base-element",link_element:"Link-element",meta_element:"Meta-element",comment_element:"Comment-element",src:"Src",language:"Spr\u00e5k",href:"Href",target:"M\u00e5l",type:"Typ",charset:"Teckenupps\u00e4ttning",defer:"Defer",media:"Media",properties:"Egenskaper",name:"Name",value:"Value",content:"Inneh\u00e5ll",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Generellt",advanced_props:"Avancerat"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/gl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000453411526350530033754 0ustar frankiefrankietinyMCE.addI18n('gl.fullpage_dlg',{title:"Propiedades do documento",meta_tab:"Xeral",appearance_tab:"Apariencia",advanced_tab:"Avanzado",meta_props:"Informaci\u00f3n Meta",langprops:"Lenguaxe e codificaci\u00f3n",meta_title:"T\u00edtulo",meta_keywords:"Verbas chave",meta_description:"Descripci\u00f3n",meta_robots:"Robots",doctypes:"Tipo de doc.",langcode:"C\u00f3digo da lenguaxe",langdir:"Direcci\u00f3n da lenguaxe",ltr:"Esquerda a dereita",rtl:"Dereita a esquerda",xml_pi:"Declaraci\u00f3n XML",encoding:"Codificaci\u00f3n de caracteres",appearance_bgprops:"Propiedades do fondo",appearance_marginprops:"Marxes",appearance_linkprops:"Cores do v\u00ednculo",appearance_textprops:"Propiedades de texto",bgcolor:"Cor de fondo",bgimage:"Imaxe de fondo",left_margin:"Marxe esquerdo",right_margin:"Marxe dereito",top_margin:"Marxe superior",bottom_margin:"Marxe inferior",text_color:"Cor do texto",font_size:"Tama\u00f1o de fonte",font_face:"Fonte",link_color:"Cor de v\u00ednculo",hover_color:"Cor rato encima",visited_color:"Cor visitado",active_color:"Cor activo",textcolor:"Cor",fontsize:"Tama\u00f1o de fonte",fontface:"Fonte",meta_index_follow:"Indexar e segui-los v\u00ednculos",meta_index_nofollow:"Indexar e non segui-los v\u00ednculos",meta_noindex_follow:"Non indexar pero seguir v\u00ednculos",meta_noindex_nofollow:"Non indexar e non seguir v\u00ednculos",appearance_style:"Propiedades de folla de estilos e estilo",stylesheet:"Folla de estilo",style:"Estilo",author:"Autor",copyright:"Copyright",add:"Agregar novo elemento",remove:"Eliminar elemento seleccionado",moveup:"Mover elemento seleccionado arriba",movedown:"Mover elemento seleccionado abaixo",head_elements:"Elementos Head",info:"Informaci\u00f3n",add_title:"Elemento Title",add_meta:"Elemento Meta",add_script:"Elemento Script",add_style:"Elemento Style",add_link:"Elemento Link",add_base:"Elemento Base",add_comment:"Nodo Comment",title_element:"Elemento Title",script_element:"Elemento Script",style_element:"Elemento Style",base_element:"Elemento Base",link_element:"Elemento Link",meta_element:"Elemento Meta",comment_element:"Comentario",src:"Src",language:"Lenguaxe",href:"Href",target:"Obxetivo",type:"Tipo",charset:"Charset",defer:"Defer",media:"Medio",properties:"Propiedades",name:"Nome",value:"Valor",content:"Contido",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Xeral",advanced_props:"Avanzado"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/sq_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000472611526350530033757 0ustar frankiefrankietinyMCE.addI18n('sq.fullpage_dlg',{title:"Tiparet e dokumentit",meta_tab:"T\u00eb P\u00ebrgjithshme",appearance_tab:"Pamja",advanced_tab:"T\u00eb Avancuara",meta_props:"Informacioni Meta",langprops:"Gjuha dhe kodimi",meta_title:"Titulli",meta_keywords:"Fjal\u00ebt ky\u00e7e",meta_description:"P\u00ebrshkrimi",meta_robots:"Robot\u00ebt",doctypes:"Doctype",langcode:"Kodi i gjuh\u00ebs",langdir:"Drejtimi i gjuh\u00ebs",ltr:"Majtas-djathtas",rtl:"Djathtas-majtas",xml_pi:"Deklarimi XML",encoding:"Kodimi i karakter\u00ebve",appearance_bgprops:"Tiparet e fush\u00ebs",appearance_marginprops:"Hap\u00ebsirat e trupit",appearance_linkprops:"Ngjyra e lidhjeve",appearance_textprops:"Tiparet e tekstit",bgcolor:"Ngjyra e fush\u00ebs",bgimage:"Foto e fush\u00ebs",left_margin:"Hap\u00ebsira majtas",right_margin:"Hap\u00ebsira djathtas",top_margin:"Hap\u00ebsira n\u00eb krye",bottom_margin:"Hap\u00ebsira n\u00eb fund",text_color:"Ngjyra e tekstit",font_size:"Madh\u00ebsia e g\u00ebrmave",font_face:"Tipi i g\u00ebrm\u00ebs",link_color:"Ngjyra e lidhjes",hover_color:"Ngjyra e hover",visited_color:"Ngjyra e vizituar",active_color:"Ngjyra aktive",textcolor:"Ngjyra",fontsize:"Madh\u00ebsia e g\u00ebrmave",fontface:"Tipi i g\u00ebrm\u00ebs",meta_index_follow:"Indekso dhe ndiq lidhjet",meta_index_nofollow:"Indekso por mos ndiq lidhjet",meta_noindex_follow:"Mos indekso por ndiq lidhjet",meta_noindex_nofollow:"Mos indekso e as mos ndiq lidhjet",appearance_style:"Faqja e stileve dhe tiparete tyre",stylesheet:"Faqja e stileve",style:"Stili",author:"Autori",copyright:"T\u00eb drejtat e kopjes",add:"Shto nj\u00eb element t\u00eb ri",remove:"Fshi elementin e zgjedhur",moveup:"L\u00ebviz elementin sip\u00ebr",movedown:"L\u00ebviz elementin posht\u00eb",head_elements:"Element\u00ebt e kok\u00ebs",info:"Informacion",add_title:"Element titull",add_meta:"Element meta",add_script:"Element script",add_style:"Element stil",add_link:"Element lidhej",add_base:"Element baz\u00eb",add_comment:"Komento",title_element:"Element titull",script_element:"Element script",style_element:"Element stil",base_element:"Element baz\u00eb",link_element:"Element lidhje",meta_element:"Element meta",comment_element:"Komento",src:"Src",language:"Gjuha",href:"Href",target:"Sh\u00ebnjestra",type:"Tipi",charset:"Charset",defer:"Defer",media:"Media",properties:"Tiparet",name:"Emri",value:"Vlera",content:"P\u00ebrmbajtja",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"T\u00eb P\u00ebrgjithshme",advanced_props:"T\u00eb Avancuara"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/nb_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000434611526350530033755 0ustar frankiefrankietinyMCE.addI18n('nb.fullpage_dlg',{title:"Dokumentegenskaper",meta_tab:"Generelt",appearance_tab:"Utseende",advanced_tab:"Avansert",meta_props:"Metainformasjon",langprops:"Spr\u00e5k og koding",meta_title:"Tittel",meta_keywords:"N\u00f8kkelord",meta_description:"Beskrivelse",meta_robots:"Roboter",doctypes:"Doctype",langcode:"Spr\u00e5kkode",langdir:"Skriftretning",ltr:"Venstre mot h\u00f8yre",rtl:"H\u00f8yre mot venstre",xml_pi:"XML-deklarasjon",encoding:"Tegnkonvertering",appearance_bgprops:"Bakgrunnsegenskaper",appearance_marginprops:"Body-marg",appearance_linkprops:"Lenkefarger",appearance_textprops:"Tekstegenskaper",bgcolor:"Bakgrunn",bgimage:"Bakgrunnsbilde",left_margin:"Venstre marg",right_margin:"H\u00f8yre marg",top_margin:"Toppmarg",bottom_margin:"Bunnmarg",text_color:"Farge",font_size:"Skriftst\u00f8rrelse",font_face:"Skrifttype",link_color:"Lenkefarge",hover_color:"Mus over-farge",visited_color:"Bes\u00f8kt-farge",active_color:"Aktive farge",textcolor:"Farge",fontsize:"Skriftst\u00f8rrelse",fontface:"Skrifttype",meta_index_follow:"Indekser, og f\u00f8lg lenkene",meta_index_nofollow:"Indekser, men ikke f\u00f8lg lenkene",meta_noindex_follow:"Ikke indekser, men f\u00f8lg lenkene",meta_noindex_nofollow:"Ikke indekser, og ikke f\u00f8lg lenkene",appearance_style:"Stilark og stilegenskaper",stylesheet:"Stilark",style:"Stil",author:"Forfatter",copyright:"Copyright",add:"Legg til nytt element",remove:"Fjern",moveup:"Flytt markert element opp",movedown:"Flytt markert element ned",head_elements:"Overskriftselementer",info:"Informasjon",add_title:"Tittelelement",add_meta:"Metaelement",add_script:"Skriptelement",add_style:"Stilelement",add_link:"Lenkeelement",add_base:"Basiselement",add_comment:"Kommentarnode",title_element:"Tittelelement",script_element:"Skriptelement",style_element:"Stilelement",base_element:"Basiselement",link_element:"Lenkeelement",meta_element:"Metaelement",comment_element:"Kommentar",src:"Skjerm",language:"Spr\u00e5k",href:"Href",target:"M\u00e5l",type:"Type",charset:"Tegnsett",defer:"Defer",media:"Objekt",properties:"Egenskaper",name:"Navn",value:"Verdi",content:"Innhold",rel:"Sidens forhold til m\u00e5let",rev:"M\u00e5lets forhold til siden",hreflang:"Href lang",general_props:"Generelt",advanced_props:"Avasert"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/cs_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000531211526350530033747 0ustar frankiefrankietinyMCE.addI18n('cs.fullpage_dlg',{title:"Vlastnosti dokumentu",meta_tab:"Obecn\u00e9",appearance_tab:"Vzhled",advanced_tab:"Roz\u0161\u00ed\u0159en\u00e9",meta_props:"Meta informace",langprops:"Jazyk a k\u00f3dov\u00e1n\u00ed",meta_title:"Titulek",meta_keywords:"Kl\u00ed\u010dov\u00e1 slova",meta_description:"Popis",meta_robots:"Roboti",doctypes:"Typ dokumentu",langcode:"K\u00f3d jazyka",langdir:"Sm\u011br textu",ltr:"Zleva doprava",rtl:"Zprava doleva",xml_pi:"XML deklarace",encoding:"K\u00f3dov\u00e1n\u00ed",appearance_bgprops:"Vlastnosti pozad\u00ed",appearance_marginprops:"Okraje t\u011bla dokumentu",appearance_linkprops:"Vlastnosti odkaz\u016f",appearance_textprops:"Vlastnosti textu",bgcolor:"Barva pozad\u00ed",bgimage:"Obr\u00e1zek pozad\u00ed",left_margin:"Lev\u00fd okraj",right_margin:"Prav\u00fd okraj",top_margin:"Horn\u00ed okraj",bottom_margin:"Spodn\u00ed okraj",text_color:"Barva textu",font_size:"Velikost p\u00edsma",font_face:"Typ p\u00edsma",link_color:"Barva odkazu",hover_color:"Barva zvolen\u00e9ho odkazu",visited_color:"Barva nav\u0161t\u00edven\u00e9ho odkazu",active_color:"Barva aktivn\u00edho odkazu",textcolor:"Barva",fontsize:"Velikost p\u00edsma",fontface:"Typ p\u00edsma",meta_index_follow:"Indexovat a sledovat odkazy",meta_index_nofollow:"Indexovat a nesledovat odkazy",meta_noindex_follow:"Neindexovat, ale sledovat odkazy",meta_noindex_nofollow:"Neindexovat a nesledovat odkazy",appearance_style:"Vlastnosti styl\u016f",stylesheet:"Stylopis",style:"Styl",author:"Autor",copyright:"Autorsk\u00e1 pr\u00e1va",add:"P\u0159idat nov\u00fd element",remove:"Odebrat ozna\u010den\u00fd element",moveup:"P\u0159esu\u0148 ozna\u010den\u00fd element v\u00fd\u0161",movedown:"P\u0159esu\u0148 ozna\u010den\u00fd element n\u00ed\u017e",head_elements:"Hlavi\u010dky",info:"Informace",add_title:"Vlo\u017eit titulek",add_meta:"Vlo\u017eit meta informace",add_script:"Vlo\u017eit skript",add_style:"Vlo\u017eit styl",add_link:"Vlo\u017eit nezobrazovan\u00fd odkaz",add_base:"Vlo\u017eit z\u00e1kladn\u00ed um\u00edst\u011bn\u00ed",add_comment:"Vlo\u017eit koment\u00e1\u0159",title_element:"Titulek",script_element:"Skript",style_element:"Styl",base_element:"Z\u00e1kladn\u00ed um\u00edst\u011bn\u00ed",link_element:"Nezobrazovan\u00fd odkaz",meta_element:"Meta informace",comment_element:"Koment\u00e1\u0159",src:"Zdroj",language:"Jazyk",href:"Soubor/URL",target:"C\u00edl",type:"Typ",charset:"Znakov\u00e1 sada",defer:"Odlo\u017eit (defer)",media:"M\u00e9dia",properties:"Vlastnosti",name:"N\u00e1zev",value:"Hodnota",content:"Obsah",rel:"Vztah str\u00e1nky k c\u00edli",rev:"Vztah c\u00edle ke str\u00e1nce",hreflang:"Jazyk odkazu",general_props:"Obecn\u00e9 parametry",advanced_props:"Roz\u0161\u00ed\u0159en\u00e9 parametry"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/it_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000457411526350530033760 0ustar frankiefrankietinyMCE.addI18n('it.fullpage_dlg',{title:"Propriet\u00e0 Documento",meta_tab:"Generale",appearance_tab:"Aspetto",advanced_tab:"Avanzate",meta_props:"Informazioni Metatag",langprops:"Lingua e codifica",meta_title:"Titolo",meta_keywords:"Parole chiave",meta_description:"Descrizione",meta_robots:"Robots",doctypes:"Doctype",langcode:"Codice lingua",langdir:"Direzione testo",ltr:"Sinistra verso destra",rtl:"Destra verso sinistra",xml_pi:"Dichiarazione XML",encoding:"Codifica carattere",appearance_bgprops:"Propriet\u00e0 sfondo",appearance_marginprops:"Margini body",appearance_linkprops:"Colori collegamenti",appearance_textprops:"Propriet\u00e0 testo",bgcolor:"Colore sfondo",bgimage:"Immagine sfondo",left_margin:"Margine sinistro",right_margin:"Margine destro",top_margin:"Margine superiore",bottom_margin:"Margine inferiore",text_color:"Colore testo",font_size:"Dimensione carattere",font_face:"Tipo carattere",link_color:"Colore collegamento",hover_color:"Colore \\\'Hover\\\'",visited_color:"Colore \\\'Visited\\\'",active_color:"Colore \\\'Active\\\'",textcolor:"Colore",fontsize:"Dimensione carattere",fontface:"Famiglia carattere",meta_index_follow:"Indicizzare e seguire collegamenti",meta_index_nofollow:"Indicizzare e non segure collegamenti",meta_noindex_follow:"Non indicizzare ma seguire collegamenti",meta_noindex_nofollow:"Non indicizzare e non seguire collegamenti",appearance_style:"Propriet\u00e0 stili e fogli di stile",stylesheet:"Fogli di stile",style:"Stile",author:"Autore",copyright:"Copyright",add:"Aggiungi nuovo elemento",remove:"Rimuovi elemento selezionato",moveup:"Sposta elemento selezionato in alto",movedown:"Sposta elemento selezionato in basso",head_elements:"Elementi Head",info:"Informazioni",add_title:"Elemento Titolo",add_meta:"Elemento Meta",add_script:"Elemento Script",add_style:"Elemento Style",add_link:"Elemento Link",add_base:"Elemento Base",add_comment:"Nodo Commento",title_element:"Elemento Titolo",script_element:"Elemento Script",style_element:"Elemento Style",base_element:"Elemento Base",link_element:"Elemento Link",meta_element:"Elemento Meta",comment_element:"Commento",src:"Sorgente",language:"Linguaggio",href:"Href",target:"Target",type:"Tipo",charset:"Set caratteri",defer:"Defer",media:"Media",properties:"Propriet\u00e0",name:"Nome",value:"Valore",content:"Contenuto",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Generale",advanced_props:"Avanzate"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/hu_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000501611526350530033750 0ustar frankiefrankietinyMCE.addI18n('hu.fullpage_dlg',{title:"Dokumentum tulajdons\u00e1gai",meta_tab:"\u00c1ltal\u00e1nos",appearance_tab:"Megjelen\u00e9s",advanced_tab:"Halad\u00f3",meta_props:"Meta inform\u00e1ci\u00f3",langprops:"Nyelv \u00e9s k\u00f3dol\u00e1s",meta_title:"C\u00edm",meta_keywords:"Kulcsszavak",meta_description:"Le\u00edr\u00e1s",meta_robots:"Robotok",doctypes:"Doctype",langcode:"Nyelvk\u00f3d",langdir:"\u00cdr\u00e1s ir\u00e1nya",ltr:"Balr\u00f3l jobra",rtl:"Jobbr\u00f3l balra",xml_pi:"XML deklar\u00e1ci\u00f3",encoding:"Karakterk\u00f3dol\u00e1s",appearance_bgprops:"H\u00e1tt\u00e9r tulajdons\u00e1gai",appearance_marginprops:"Test keret",appearance_linkprops:"Link sz\u00ednek",appearance_textprops:"Sz\u00f6veg tulajdons\u00e1gai",bgcolor:"H\u00e1tt\u00e9rsz\u00edn",bgimage:"H\u00e1tt\u00e9rk\u00e9p",left_margin:"Bal marg\u00f3",right_margin:"Jobb marg\u00f3",top_margin:"Fels\u0151 marg\u00f3",bottom_margin:"Als\u00f3 marg\u00f3",text_color:"Sz\u00f6vegsz\u00edn",font_size:"Bet\u0171m\u00e9ret",font_face:"Bet\u0171t\u00edpus",link_color:"Link sz\u00edn",hover_color:"F\u00f6l\u00e9vitt sz\u00edn",visited_color:"L\u00e1togatva sz\u00edn",active_color:"Akt\u00edv sz\u00edn",textcolor:"Sz\u00edn",fontsize:"Bet\u0171m\u00e9ret",fontface:"Bet\u0171t\u00edpus",meta_index_follow:"Indexel \u00e9s k\u00f6veti a linkeket",meta_index_nofollow:"Indexel, de nem k\u00f6veti a linkeket",meta_noindex_follow:"Nem indexel, de k\u00f6veti a linkeket",meta_noindex_nofollow:"Nem indexel \u00e9s nem k\u00f6veti a linkeket",appearance_style:"Stylesheet \u00e9s style tulajdons\u00e1gok",stylesheet:"Stylesheet",style:"Style",author:"Szerz\u0151",copyright:"Copyright",add:"\u00daj elem hozz\u00e1ad\u00e1sa",remove:"Kijel\u00f6lt elem t\u00f6rl\u00e9se",moveup:"Kijel\u00f6lt elem felfel\u00e9 mozgat\u00e1sa",movedown:"Kijel\u00f6lt elem lefel\u00e9 mozgat\u00e1sa",head_elements:"Fej elemek",info:"Inform\u00e1ci\u00f3",add_title:"C\u00edm elem",add_meta:"Meta elem",add_script:"Script elem",add_style:"Style elem",add_link:"Link elem",add_base:"Base elem",add_comment:"Comment elem",title_element:"Title elem",script_element:"Script elem",style_element:"Style elem",base_element:"Base elem",link_element:"Link elem",meta_element:"Meta elem",comment_element:"Megjegyz\u00e9s",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u00c1ltal\u00e1nos",advanced_props:"Halad\u00f3"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/az_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000573711526350530033762 0ustar frankiefrankietinyMCE.addI18n('az.fullpage_dlg',{title:"S\u0259n\u0259d x\u00fcsusiyy\u0259tl\u0259ri",meta_tab:"\u00dcmumi",appearance_tab:"G\u00f6r\u00fcn\u00fc\u015f",advanced_tab:"\u018flav\u0259l\u0259r",meta_props:"Meta m\u0259lumat",langprops:"Dil v\u0259 kodla\u015fd\u0131rma",meta_title:"Ba\u015fl\u0131q",meta_keywords:"A\u00e7ar s\u00f6zl\u0259ri",meta_description:"T\u0259svir",meta_robots:"Robotlar",doctypes:"S\u0259n\u0259d n\u00f6v\u00fc",langcode:"Dil kodu",langdir:"Dil istiqam\u0259ti",ltr:"Soldan sa\u011fa",rtl:"Sa\u011fdan sola",xml_pi:"XML t\u0259rifi",encoding:"\u0130\u015far\u0259 kodla\u015fd\u0131rmas\u0131",appearance_bgprops:"Arxa plan x\u00fcsusiyy\u0259tl\u0259ri",appearance_marginprops:"G\u00f6vd\u0259 k\u0259narlar\u0131",appearance_linkprops:"Ke\u00e7id r\u0259ngl\u0259ri",appearance_textprops:"M\u0259tn x\u00fcsusiyy\u0259tl\u0259ri",bgcolor:"Arxa plan r\u0259ngi",bgimage:"Arxa plan \u015f\u0259kli",left_margin:"Sol bo\u015fluq",right_margin:"Sa\u011f bo\u015fluq",top_margin:"\u00dcst bo\u015fluq",bottom_margin:"Alt bo\u015fluq",text_color:"M\u0259tn r\u0259ngi",font_size:"\u015erift \u00f6l\u00e7\u00fcs\u00fc",font_face:"\u015erift n\u00f6v\u00fc",link_color:"Ke\u00e7id r\u0259ngi",hover_color:"\u00dcz\u0259rind\u0259ki r\u0259ng",visited_color:"Bax\u0131lm\u0131\u015f r\u0259ng",active_color:"Aktiv r\u0259ng",textcolor:"R\u0259ng",fontsize:"\u015erift \u00f6l\u00e7\u00fcs\u00fc",fontface:"\u015erift ail\u0259si",meta_index_follow:"\u0130ndeks et v\u0259 ke\u00e7idi izl\u0259",meta_index_nofollow:"\u0130ndeks et lakin ke\u00e7idi izl\u0259m\u0259",meta_noindex_follow:"\u0130ndeks etm\u0259 lakin ke\u00e7idi izl\u0259",meta_noindex_nofollow:"\u0130ndeks etm\u0259 v\u0259 ke\u00e7idl\u0259ri izl\u0259m\u0259",appearance_style:"Stil v\u0259r\u0259qi v\u0259 x\u00fcsusiyy\u0259tl\u0259ri",stylesheet:"Stil v\u0259r\u0259qi",style:"Stil",author:"M\u00fc\u0259llif",copyright:"M\u00fc\u0259llif h\u00fcququ",add:"Yeni element \u0259lav\u0259 et",remove:"Se\u00e7ilmi\u015f elementi sil",moveup:"Se\u00e7il\u0259n elementi yuxar\u0131 \u00e7\u0259k",movedown:"Se\u00e7il\u0259n elementi a\u015fa\u011f\u0131 \u00e7\u0259k",head_elements:"Ba\u015f elementl\u0259r",info:"M\u0259lumat",add_title:"Ba\u015fl\u0131q elementi",add_meta:"Meta elementi",add_script:"Skript elementi",add_style:"Stil elementi",add_link:"Ke\u00e7id elementi",add_base:"Baza elementi",add_comment:"\u015e\u0259rh d\u00fcy\u00fcn\u00fc",title_element:"Ba\u015fl\u0131q elementi",script_element:"Skript elementi",style_element:"Stil elementi",base_element:"Baza elementi",link_element:"Ke\u00e7id elementi",meta_element:"Meta elementi",comment_element:"\u015e\u0259rh",src:"Src",language:"Dil",href:"Href",target:"H\u0259d\u0259f",type:"N\u00f6v",charset:"\u00c7arset",defer:"T\u0259xir\u0259 sal",media:"Media",properties:"X\u00fcsusiyy\u0259tl\u0259r",name:"Ad\u0131",value:"D\u0259y\u0259r",content:"M\u0259zmun",rel:"Rel",rev:"Rev",hreflang:"Href dili",general_props:"\u00dcmumi",advanced_props:"\u018flav\u0259l\u0259r"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/en_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('en.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ko_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000532411526350530033752 0ustar frankiefrankietinyMCE.addI18n('ko.fullpage_dlg',{title:"\ud398\uc774\uc9c0\uc758 \uc18d\uc131",meta_tab:"\uc77c\ubc18",appearance_tab:"\ud45c\uc2dc",advanced_tab:"\uace0\uae09",meta_props:"\uba54\ud0c0 \uc815\ubcf4",langprops:"\uc5b8\uc5b4\uc640 \uc778\ucf54\ub529",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"\uc5b8\uc5b4 \ucf54\ub4dc",langdir:"\ubb38\uc790 \ubc29\ud5a5",ltr:"\uc67c\ucabd\uc5d0\uc11c \uc624\ub978\ucabd",rtl:"\uc624\ub978\ucabd\uc5d0\uc11c \uc67c\ucabd",xml_pi:"XML\uc120\uc5b8",encoding:"\ubb38\uc790 \uc778\ucf54\ub529",appearance_bgprops:"\ubc30\uacbd \uc124\uc815",appearance_marginprops:"Body \ub9c8\uc9c4",appearance_linkprops:"\ub9c1\ud06c\uc0c9",appearance_textprops:"\ud14d\uc2a4\ud2b8 \uc124\uc815",bgcolor:"\ubc30\uacbd\uc0c9",bgimage:"\ubc30\uacbd \uc774\ubbf8\uc9c0",left_margin:"\uc67c\ucabd \ub9c8\uc9c4",right_margin:"\uc624\ub978\ucabd \ub9c8\uc9c4",top_margin:"\uc704 \ub9c8\uc9c4",bottom_margin:"\uc544\ub798 \ub9c8\uc9c4",text_color:"\ubb38\uc790\uc0c9",font_size:"\ubb38\uc790 \ud06c\uae30",font_face:"\uae00\uaf34",link_color:"\ub9c1\ud06c\uc0c9",hover_color:"\ub9c1\ud06c\uc0c9(hover)",visited_color:"\ub9c1\ud06c\uc0c9(visited)",active_color:"\ub9c1\ud06c\uc0c9(active)",textcolor:"\uc0c9",fontsize:"\ubb38\uc790 \ud06c\uae30",fontface:"\ud3f0\ud2b8",meta_index_follow:"\ubaa8\ub450 \ud5c8\uac00",meta_index_nofollow:"\ud398\uc774\uc9c0\ub97c \ud5c8\uac00\ud558\uc9c0\ub9cc \ub9c1\ud06c \uae08\uc9c0",meta_noindex_follow:"\ud398\uc774\uc9c0\ub97c \uae08\uc9c0\ud558\uace0 \ub9c1\ud06c \ud5c8\uac00",meta_noindex_nofollow:"\ubaa8\ub450 \uae08\uc9c0",appearance_style:"\uc2a4\ud0c0\uc77c\uc2dc\ud2b8 \uc124\uc815",stylesheet:"\uc2a4\ud0c0\uc77c\uc2dc\ud2b8",style:"\uc2a4\ud0c0\uc77c",author:"\ud544\uc790",copyright:"Copyright",add:"\uc694\uc18c \ucd94\uac00",remove:"\uc120\ud0dd \uc694\uc18c\ub97c \uc0ad\uc81c",moveup:"\uc120\ud0dd \uc694\uc18c\ub97c \uc704\uc5d0 \uc774\ub3d9",movedown:"\uc120\ud0dd \uc694\uc18c\ub97c \uc544\ub798\uc5d0 \uc774\ub3d9",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/pt_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000436711526350530033760 0ustar frankiefrankietinyMCE.addI18n('pt.fullpage_dlg',{title:"Propriedades do documento",meta_tab:"Geral",appearance_tab:"Apar\u00eancia",advanced_tab:"Avan\u00e7ado",meta_props:"Meta-informa\u00e7\u00e3o",langprops:"Idioma e codifica\u00e7\u00e3o",meta_title:"T\u00edtulo",meta_keywords:"Palavras-chave",meta_description:"Descri\u00e7\u00e3o",meta_robots:"Robots",doctypes:"Doctype",langcode:"C\u00f3digo do idioma",langdir:"Dire\u00e7\u00e3o do texto",ltr:"Esquerda para direita",rtl:"Direita para esquerda",xml_pi:"Declara\u00e7\u00e3o XML",encoding:"Codifica\u00e7\u00e3o de caracteres",appearance_bgprops:"Propriedades do plano de fundo",appearance_marginprops:"Margens (BODY)",appearance_linkprops:"Cores dos links",appearance_textprops:"Propriedades de texto",bgcolor:"Cor de fundo",bgimage:"Imagem de fundo",left_margin:"Margem esquerda",right_margin:"Margem direita",top_margin:"Margem topo",bottom_margin:"Margem base",text_color:"Cor do texto",font_size:"Tamanho fonte",font_face:"Fonte",link_color:"Cores dos links",hover_color:"Hover",visited_color:"Visitado",active_color:"Ativo",textcolor:"Cor",fontsize:"Tamanho fonte",fontface:"Fonte",meta_index_follow:"Indexar e seguir os hyperlinks",meta_index_nofollow:"Indexar e n\u00e3o seguir os hyperlinks",meta_noindex_follow:"Seguir hyperlinks, mas n\u00e3o indexar",meta_noindex_nofollow:"N\u00e3o indexar / n\u00e3o seguir hyperlinks.",appearance_style:"Propriedades de folhas de estilo",stylesheet:"Folha de estilo",style:"Estilo",author:"Autor",copyright:"Copyright",add:"Acrescentar novo elemento",remove:"Remover elemento selecionado",moveup:"Subir elemento selecionado",movedown:"Descer elemento selecionado",head_elements:"Elementos HEAD",info:"Informa\u00e7\u00e3o",add_title:"TITLE",add_meta:"META",add_script:"SCRIPT",add_style:"STYLE",add_link:"LINK",add_base:"BASE",add_comment:"Coment\u00e1rio",title_element:"TITLE",script_element:"SCRIPT",style_element:"STYLE",base_element:"BASE",link_element:"LINK",meta_element:"META",comment_element:"Coment\u00e1rio",src:"src",language:"Idioma",href:"href",target:"Alvo",type:"Tipo",charset:"Charset",defer:"Adiar",media:"Media",properties:"Propriedades",name:"Nome",value:"Valor",content:"Conte\u00fado",rel:"rel",rev:"rev",hreflang:"href lang",general_props:"Geral",advanced_props:"Avan\u00e7ado"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/th_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000757011526350530033757 0ustar frankiefrankietinyMCE.addI18n('th.fullpage_dlg',{title:"\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e40\u0e2d\u0e01\u0e2a\u0e32\u0e23",meta_tab:"\u0e17\u0e31\u0e48\u0e27\u0e44\u0e1b",appearance_tab:"\u0e23\u0e39\u0e1b\u0e25\u0e31\u0e01\u0e29\u0e13\u0e4c",advanced_tab:"\u0e02\u0e31\u0e49\u0e19\u0e2a\u0e39\u0e07",meta_props:"\u0e23\u0e32\u0e22\u0e25\u0e30\u0e40\u0e2d\u0e35\u0e22\u0e14\u0e40\u0e21\u0e15\u0e49\u0e32",langprops:"\u0e20\u0e32\u0e29\u0e32 \u0e41\u0e25\u0e30 \u0e01\u0e32\u0e23\u0e40\u0e02\u0e49\u0e32\u0e23\u0e2b\u0e31\u0e2a",meta_title:"\u0e0a\u0e37\u0e48\u0e2d",meta_keywords:"\u0e04\u0e33\u0e2a\u0e33\u0e04\u0e31\u0e0d",meta_description:"\u0e23\u0e32\u0e22\u0e25\u0e30\u0e40\u0e2d\u0e35\u0e22\u0e14",meta_robots:"Robots",doctypes:"Doctype",langcode:"\u0e42\u0e04\u0e4a\u0e14\u0e20\u0e32\u0e29\u0e32",langdir:"\u0e17\u0e34\u0e28\u0e17\u0e32\u0e07\u0e01\u0e32\u0e23\u0e2d\u0e48\u0e32\u0e19",ltr:"\u0e0b\u0e49\u0e32\u0e22\u0e44\u0e1b\u0e02\u0e27\u0e32",rtl:"\u0e02\u0e27\u0e32\u0e44\u0e1b\u0e0b\u0e49\u0e32\u0e22",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e25\u0e31\u0e07",appearance_marginprops:"Body margins",appearance_linkprops:"\u0e2a\u0e35\u0e25\u0e34\u0e49\u0e07\u0e04\u0e4c",appearance_textprops:"\u0e04\u0e38\u0e13\u0e2a\u0e21\u0e1a\u0e31\u0e15\u0e34\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21",bgcolor:"\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e25\u0e31\u0e07 color",bgimage:"\u0e1e\u0e37\u0e49\u0e19\u0e2b\u0e25\u0e31\u0e07 image",left_margin:"\u0e02\u0e2d\u0e1a\u0e0b\u0e49\u0e32\u0e22",right_margin:"\u0e02\u0e2d\u0e1a\u0e02\u0e27\u0e32",top_margin:"\u0e02\u0e2d\u0e1a\u0e1a\u0e21",bottom_margin:"\u0e02\u0e2d\u0e1a\u0e25\u0e48\u0e32\u0e07",text_color:"\u0e2a\u0e35\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21",font_size:"\u0e02\u0e19\u0e32\u0e14\u0e15\u0e31\u0e27\u0e2d\u0e31\u0e01\u0e29\u0e23",font_face:"\u0e15\u0e31\u0e27\u0e2d\u0e31\u0e01\u0e29\u0e23",link_color:"\u0e2a\u0e35\u0e25\u0e34\u0e49\u0e07\u0e04\u0e4c",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"\u0e2a\u0e35",fontsize:"\u0e02\u0e19\u0e32\u0e14\u0e15\u0e31\u0e27\u0e2d\u0e31\u0e01\u0e29\u0e23",fontface:"\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e15\u0e31\u0e27\u0e2d\u0e01\u0e29\u0e23",meta_index_follow:"Index and follow the \u0e25\u0e34\u0e49\u0e07\u0e04\u0e4cs",meta_index_nofollow:"Index and don\'t follow the \u0e25\u0e34\u0e49\u0e07\u0e04\u0e4cs",meta_noindex_follow:"Do not index but follow the \u0e25\u0e34\u0e49\u0e07\u0e04\u0e4cs",meta_noindex_nofollow:"Do not index and don\\\'t follow the \u0e25\u0e34\u0e49\u0e07\u0e04\u0e4cs",appearance_style:"\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1asheet and style properties",stylesheet:"\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1asheet",style:"\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"\u0e0a\u0e37\u0e48\u0e2d element",add_meta:"Meta element",add_script:"Script element",add_style:"\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"\u0e0a\u0e37\u0e48\u0e2d element",script_element:"Script element",style_element:"\u0e23\u0e39\u0e1b\u0e41\u0e1a\u0e1a element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"\u0e20\u0e32\u0e29\u0e32",href:"Href",target:"\u0e40\u0e1b\u0e49\u0e32\u0e2b\u0e21\u0e32\u0e22",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u0e17\u0e31\u0e48\u0e27\u0e44\u0e1b",advanced_props:"\u0e02\u0e31\u0e49\u0e19\u0e2a\u0e39\u0e07"});././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/zh-cn_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000545711526350530033761 0ustar frankiefrankietinyMCE.addI18n('zh-cn.fullpage_dlg',{title:"\u6587\u4ef6\u5c5e\u6027","meta_tab":"\u666e\u901a","appearance_tab":"\u5916\u89c2","advanced_tab":"\u9ad8\u7ea7","meta_props":"Meta\u4fe1\u606f",langprops:"\u8bed\u8a00\u548c\u7f16\u7801","meta_title":"\u6807\u9898","meta_keywords":"Meta \u5173\u952e\u5b57","meta_description":"Meta \u63cf\u8ff0","meta_robots":"\u641c\u7d22\u673a\u5668\u4eba",doctypes:"\u6587\u6863\u7c7b\u578b",langcode:"\u8bed\u8a00\u7f16\u7801",langdir:"\u8bed\u8a00\u6587\u5b57\u65b9\u5411",ltr:"\u4ece\u5de6\u5230\u53f3",rtl:"\u4ece\u53f3\u5230\u5de6","xml_pi":"XML\u7533\u660e",encoding:"\u5b57\u7b26\u7f16\u7801","appearance_bgprops":"\u80cc\u666f\u5c5e\u6027","appearance_marginprops":"\u9875\u8fb9\u8ddd","appearance_linkprops":"\u8d85\u94fe\u63a5\u989c\u8272","appearance_textprops":"\u6587\u672c\u5c5e\u6027",bgcolor:"\u80cc\u666f\u989c\u8272",bgimage:"\u80cc\u666f\u56fe\u7247","left_margin":"\u5de6\u8fb9\u8ddd","right_margin":"\u53f3\u8fb9\u8ddd","top_margin":"\u4e0a\u8fb9\u8ddd","bottom_margin":"\u4e0b\u8fb9\u8ddd","text_color":"\u6587\u672c\u989c\u8272","font_size":"\u5b57\u4f53\u5927\u5c0f","font_face":"\u5b57\u4f53","link_color":"\u8d85\u94fe\u63a5\u989c\u8272","hover_color":"Hover\u989c\u8272","visited_color":"Visited\u989c\u8272","active_color":"Active\u989c\u8272",textcolor:"\u989c\u8272",fontsize:"\u5b57\u4f53\u5927\u5c0f",fontface:"\u5b57\u4f53","meta_index_follow":"\u7d22\u5f15\u5e76\u8fde\u7ed3","meta_index_nofollow":"\u7d22\u5f15\u4f46\u4e0d\u8fde\u7ed3","meta_noindex_follow":"\u4e0d\u7d22\u5f15\u4f46\u8fde\u7ed3","meta_noindex_nofollow":"\u4e0d\u7d22\u5f15\u4e5f\u4e0d\u8fde\u7ed3","appearance_style":"\u6837\u5f0f\u8868\u4e0e\u6837\u5f0f\u5c5e\u6027",stylesheet:"\u6837\u5f0f\u8868",style:"\u6837\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6743\u58f0\u660e",add:"\u6dfb\u52a0\u5143\u7d20",remove:"\u5220\u9664\u9009\u62e9\u5143\u7d20",moveup:"\u4e0a\u79fb\u9009\u62e9\u5143\u7d20",movedown:"\u4e0b\u79fb\u9009\u62e9\u5143\u7d20","head_elements":"Head\u5143\u7d20",info:"\u4fe1\u606f","add_title":"Title\u5143\u7d20","add_meta":"Meta\u5143\u7d20","add_script":"Script\u5143\u7d20","add_style":"Style\u5143\u7d20","add_link":"Link\u5143\u7d20","add_base":"Base\u5143\u7d20","add_comment":"\u6ce8\u91ca","title_element":"Title\u5143\u7d20","script_element":"Script\u5143\u7d20","style_element":"Style\u5143\u7d20","base_element":"Base\u5143\u7d20","link_element":"Link\u5143\u7d20","meta_element":"Meta\u5143\u7d20","comment_element":"\u6ce8\u91ca",src:"\u5730\u5740",language:"\u8bed\u8a00",href:"Href",target:"\u76ee\u6807",type:"\u7c7b\u578b",charset:"\u5b57\u7b26\u96c6",defer:"Defer",media:"\u5a92\u4f53",properties:"\u5c5e\u6027",name:"\u540d\u79f0",value:"\u503c",content:"\u5185\u5bb9",rel:"Rel",rev:"Rev",hreflang:"Href\u8bed\u8a00","general_props":"\u5e38\u89c4","advanced_props":"\u9ad8\u7ea7"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/fr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000532411526350530033752 0ustar frankiefrankietinyMCE.addI18n('fr.fullpage_dlg',{title:"Propri\u00e9t\u00e9s du document",meta_tab:"G\u00e9n\u00e9ral",appearance_tab:"Apparence",advanced_tab:"Avanc\u00e9",meta_props:"Metadonn\u00e9es",langprops:"Langue et encodage",meta_title:"Titre",meta_keywords:"Mots-cl\u00e9s",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Code de la langue",langdir:"Sens de lecture",ltr:"De gauche \u00e0 droite",rtl:"De droite \u00e0 gauche",xml_pi:"D\u00e9claration XML",encoding:"Encodage des caract\u00e8res",appearance_bgprops:"Propri\u00e9t\u00e9s du fond",appearance_marginprops:"Marge du corps de la page",appearance_linkprops:"Couleurs des liens",appearance_textprops:"Propri\u00e9t\u00e9s du texte",bgcolor:"Couleur de fond",bgimage:"Image de fond",left_margin:"Marge de gauche",right_margin:"Marge de droite",top_margin:"Marge du haut",bottom_margin:"Marge du bas",text_color:"Couleur du texte",font_size:"Taille de la police",font_face:"Nom de la police",link_color:"Couleur des liens",hover_color:"Couleur au survol",visited_color:"Couleur des liens visit\u00e9s",active_color:"Couleur du lien actif",textcolor:"Couleur",fontsize:"Taille de police",fontface:"Nom de la police",meta_index_follow:"Indexer et suivre les liens",meta_index_nofollow:"Indexer et ne pas suivre les liens",meta_noindex_follow:"Ne pas indexer et suivre les liens",meta_noindex_nofollow:"Ne pas indexer et ne pas suivre les liens",appearance_style:"Propri\u00e9t\u00e9s de la feuille de style et du style",stylesheet:"Feuille de style",style:"Style",author:"Auteur",copyright:"Copyright",add:"Ajouter un nouvel \u00e9l\u00e9ment",remove:"Retirer l\'\u00e9l\u00e9ment s\u00e9lectionn\u00e9",moveup:"D\u00e9placer l\'\u00e9l\u00e9ment s\u00e9lectionn\u00e9 vers le haut",movedown:"D\u00e9placer l\'\u00e9l\u00e9ment s\u00e9lectionn\u00e9 vers le bas",head_elements:"\u00c9l\u00e9ments d\'en-t\u00eate",info:"Information",add_title:"\u00c9l\u00e9ment de titre",add_meta:"\u00c9l\u00e9ment Meta",add_script:"\u00c9l\u00e9ment de script",add_style:"\u00c9l\u00e9ment de style",add_link:"\u00c9l\u00e9ment de lien",add_base:"\u00c9l\u00e9ment de base",add_comment:"Commentaire",title_element:"\u00c9l\u00e9ment de titre",script_element:"\u00c9l\u00e9ment de script",style_element:"\u00c9l\u00e9ment de style",base_element:"\u00c9l\u00e9ment de base",link_element:"\u00c9l\u00e9ment de lien",meta_element:"\u00c9l\u00e9ment Meta",comment_element:"Commentaire",src:"Source",language:"Langue",href:"Href",target:"Cible",type:"Type",charset:"Charset",defer:"D\u00e9f\u00e9rer",media:"M\u00e9dia",properties:"Propri\u00e9t\u00e9s",name:"Nom",value:"Valeur",content:"Contenu",rel:"Rel",rev:"Rev",hreflang:"langue Href",general_props:"G\u00e9n\u00e9ral",advanced_props:"Avanc\u00e9"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/de_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000451111526350530033747 0ustar frankiefrankietinyMCE.addI18n('de.fullpage_dlg',{title:"Dokument-Eigenschaften",meta_tab:"Allgemein",appearance_tab:"Aussehen",advanced_tab:"Erweitert",meta_props:"Meta-Information",langprops:"Sprache und Codierung",meta_title:"Titel",meta_keywords:"Keywords",meta_description:"Beschreibung",meta_robots:"Robots",doctypes:"DocType",langcode:"Sprachcode",langdir:"Sprachrichtung",ltr:"Links nach Rechts",rtl:"Rechts nach Links",xml_pi:"XML Deklaration",encoding:"Zeichencodierung",appearance_bgprops:"Hintergrund-Eigenschaften",appearance_marginprops:"Abst\u00e4nde des Body",appearance_linkprops:"Linkfarben",appearance_textprops:"Text-Eigenschaften",bgcolor:"Hintergrundfarbe",bgimage:"Hintergrundbild",left_margin:"Linker Abstand",right_margin:"Rechter Abstand",top_margin:"Oberer Abstand",bottom_margin:"Unterer Abstand",text_color:"Textfarbe",font_size:"Schriftgr\u00f6\u00dfe",font_face:"Schriftart",link_color:"Linkfarbe",hover_color:"Hover-Farbe",visited_color:"Visited-Farbe",active_color:"Active-Farbe",textcolor:"Farbe",fontsize:"Schriftgr\u00f6\u00dfe",fontface:"Schriftart",meta_index_follow:"Indizieren und den Links folgen",meta_index_nofollow:"Indizieren, aber den Links nicht folgen",meta_noindex_follow:"Nicht indizieren, aber den Links folgen",meta_noindex_nofollow:"Nicht indizieren und auch nicht den Links folgen",appearance_style:"CSS-Stylesheet und Stileigenschaften",stylesheet:"CSS-Stylesheet",style:"CSS-Stil",author:"Autor",copyright:"Copyright",add:"Neues Element hinzuf\u00fcgen",remove:"Ausgew\u00e4hltes Element entfernen",moveup:"Ausgew\u00e4hltes Element nach oben bewegen",movedown:"Ausgew\u00e4hltes Element nach unten bewegen",head_elements:"\u00dcberschriftenelemente",info:"Information",add_title:"Titel-Element",add_meta:"Meta-Element",add_script:"Script-Element",add_style:"Style-Element",add_link:"Link-Element",add_base:"Base-Element",add_comment:"HTML-Kommentar",title_element:"Titel-Element",script_element:"Script-Element",style_element:"Style-Element",base_element:"Base-Element",link_element:"Link-Element",meta_element:"Meta_Element",comment_element:"Kommentar",src:"Src",language:"Sprache",href:"Href",target:"Ziel",type:"Typ",charset:"Zeichensatz",defer:"Defer",media:"Media",properties:"Eigenschaften",name:"Name",value:"Wert",content:"Inhalt",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Allgemein",advanced_props:"Erweitert"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/si_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('si.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ja_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000646211526350530033756 0ustar frankiefrankietinyMCE.addI18n('ja.fullpage_dlg',{title:"\u30da\u30fc\u30b8\u8a2d\u5b9a",meta_tab:"\u4e00\u822c",appearance_tab:"\u8868\u793a",advanced_tab:"\u4e0a\u7d1a\u8005\u5411\u3051",meta_props:"\u30e1\u30bf\u60c5\u5831",langprops:"\u8a00\u8a9e\u3068\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0",meta_title:"\u30bf\u30a4\u30c8\u30eb",meta_keywords:"\u30ad\u30fc\u30ef\u30fc\u30c9",meta_description:"\u8aac\u660e",meta_robots:"\u691c\u7d22\u30ed\u30dc\u30c3\u30c8\u5236\u5fa1",doctypes:"DOCTYPE",langcode:"\u8a00\u8a9e\u30b3\u30fc\u30c9",langdir:"\u6587\u7ae0\u306e\u65b9\u5411",ltr:"\u5de6\u304b\u3089\u53f3",rtl:"\u53f3\u304b\u3089\u5de6",xml_pi:"XML\u5ba3\u8a00",encoding:"\u6587\u5b57\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0",appearance_bgprops:"\u80cc\u666f\u306e\u30d7\u30ed\u30d1\u30c6\u30a3",appearance_marginprops:"\u4f59\u767d",appearance_linkprops:"\u30ea\u30f3\u30af\u8272",appearance_textprops:"\u6587\u5b57\u3082\u30d7\u30ed\u30d1\u30c6\u30a3",bgcolor:"\u80cc\u666f\u8272",bgimage:"\u80cc\u666f\u753b\u50cf",left_margin:"\u5de6\u4f59\u767d",right_margin:"\u53f3\u4f59\u767d",top_margin:"\u4e0a\u4f59\u767d",bottom_margin:"\u4e0b\u4f59\u767d",text_color:"\u6587\u5b57\u8272",font_size:"\u6587\u5b57\u30b5\u30a4\u30ba",font_face:"\u30d5\u30a9\u30f3\u30c8",link_color:"\u30ea\u30f3\u30af\u8272",hover_color:"\u30ea\u30f3\u30af\u8272(hover)",visited_color:"\u30ea\u30f3\u30af\u8272(visited)",active_color:"\u30ea\u30f3\u30af\u8272(active)",textcolor:"\u8272",fontsize:"\u6587\u5b57\u30b5\u30a4\u30ba",fontface:"\u30d5\u30a9\u30f3\u30c8",meta_index_follow:"\u3053\u306e\u30da\u30fc\u30b8\u3068\u30ea\u30f3\u30af\u5148\u306e\u5de1\u56de\u3092\u8a31\u53ef",meta_index_nofollow:"\u3053\u306e\u30da\u30fc\u30b8\u306e\u5de1\u56de\u3092\u8a31\u53ef\u3001\u30ea\u30f3\u30af\u5148\u306e\u5de1\u56de\u3092\u7981\u6b62",meta_noindex_follow:"\u3053\u306e\u30da\u30fc\u30b8\u306e\u5de1\u56de\u3092\u7981\u6b62\u3001\u30ea\u30f3\u30af\u5148\u306e\u5de1\u56de\u3092\u8a31\u53ef",meta_noindex_nofollow:"\u3053\u306e\u30da\u30fc\u30b8\u3068\u30ea\u30f3\u30af\u5148\u306e\u5de1\u56de\u3092\u7981\u6b62",appearance_style:"\u30b9\u30bf\u30a4\u30eb\u8a2d\u5b9a",stylesheet:"\u30b9\u30bf\u30a4\u30eb\u30b7\u30fc\u30c8",style:"style\u5c5e\u6027",author:"\u4f5c\u8005",copyright:"\u30b3\u30d4\u30fc\u30e9\u30a4\u30c8",add:"\u30a8\u30ec\u30e1\u30f3\u30c8\u8ffd\u52a0",remove:"\u9078\u629e\u8981\u7d20\u306e\u524a\u9664",moveup:"\u9078\u629e\u8981\u7d20\u3092\u4e0a\u3078\u79fb\u52d5",movedown:"\u9078\u629e\u8981\u7d20\u3092\u4e0b\u3078\u79fb\u52d5",head_elements:"Head\u8981\u7d20",info:"\u30a4\u30f3\u30d5\u30a9\u30e1\u30fc\u30b7\u30e7\u30f3",add_title:"Title\u8981\u7d20",add_meta:"Meta\u8981\u7d20",add_script:"Script\u8981\u7d20",add_style:"Style\u8981\u7d20",add_link:"Link\u8981\u7d20",add_base:"Base\u8981\u7d20",add_comment:"Comment\u30ce\u30fc\u30c9",title_element:"Title\u8981\u7d20",script_element:"Script\u8981\u7d20",style_element:"Style\u8981\u7d20",base_element:"Base\u8981\u7d20",link_element:"Link\u8981\u7d20",meta_element:"Meta\u8981\u7d20",comment_element:"Comment",src:"src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u4e00\u822c",advanced_props:"\u4e0a\u7d1a\u8005\u5411\u3051"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ro_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000464611526350530033760 0ustar frankiefrankietinyMCE.addI18n('ro.fullpage_dlg',{title:"Propriet\u0103\u0163i document",meta_tab:"General",appearance_tab:"Aparen\u0163\u0103",advanced_tab:"Avansat",meta_props:"Meta informa\u0163ii",langprops:"Limb\u0103 \u015fi codare",meta_title:"Titlu",meta_keywords:"Cuvinte cheie",meta_description:"Descriere",meta_robots:"Robo\u0163i",doctypes:"Doctype",langcode:"Cod limb\u0103",langdir:"Direc\u0163ie limb\u0103",ltr:"De la st\u00e2nga la dreapta",rtl:"De la dreapta la st\u00e2nga",xml_pi:"Declara\u0163ie XML",encoding:"Cod caractere",appearance_bgprops:"Propriet\u0103\u0163i fundal",appearance_marginprops:"Margini corp",appearance_linkprops:"Culoare leg\u0103turi",appearance_textprops:"Propriet\u0103\u0163i text",bgcolor:"Culoare de fundal",bgimage:"Imagine de fundal",left_margin:"Margine st\u00e2nga",right_margin:"Margine dreapta",top_margin:"Margine sus",bottom_margin:"Margine jos",text_color:"Culoare text",font_size:"Dimensiune font",font_face:"Tip font",link_color:"Culoare leg\u0103tur\u0103",hover_color:"Culoare leg\u0103tur\u0103 la maus deasupra",visited_color:"Leg\u0103tur\u0103 vizitat\u0103",active_color:"Leg\u0103tur\u0103 activ\u0103",textcolor:"Culoare",fontsize:"Dimensiune font",fontface:"Tip font",meta_index_follow:"Indexeaz\u0103 \u015fi urm\u0103re\u015fte aceste leg\u0103turi",meta_index_nofollow:"Indexeaz\u0103 \u015fi nu urm\u0103ri aceste leg\u0103turi",meta_noindex_follow:"Nu indexa, dar urm\u0103re\u015fte aceste leg\u0103turi",meta_noindex_nofollow:"Nu indexa \u015fi nu urm\u0103ri aceste leg\u0103turi",appearance_style:"Stil",stylesheet:"Foaie de stil",style:"Stil",author:"Autor",copyright:"Copyright",add:"Adaug\u0103 un element",remove:"\u015eterge element selectat",moveup:"Mut\u0103 elementul selectat \u00een sus",movedown:"Mut\u0103 elementul selectat \u00een jos",head_elements:"Elemente de antet",info:"Informa\u0163ii",add_title:"Titlu",add_meta:"Meta",add_script:"Script",add_style:"Stil",add_link:"Link",add_base:"Base",add_comment:"Comentariu",title_element:"Title",script_element:"Script",style_element:"Stil",base_element:"Base",link_element:"Link",meta_element:"Meta",comment_element:"Comentariu",src:"Src",language:"Limb\u0103",href:"Href",target:"\u0162int\u0103",type:"Tip",charset:"Set de caractere",defer:"Defer",media:"Media",properties:"Propriet\u0103\u0163i",name:"Nume",value:"Valoare",content:"Con\u0163inut",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Avansat"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/es_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000463211526350530033753 0ustar frankiefrankietinyMCE.addI18n('es.fullpage_dlg',{title:"Propiedades del documento",meta_tab:"General",appearance_tab:"Apariencia",advanced_tab:"Avanzado",meta_props:"Informaci\u00f3n Meta",langprops:"Lenguaje y codificaci\u00f3n",meta_title:"T\u00edtulo",meta_keywords:"Palabras clave",meta_description:"Descripci\u00f3n",meta_robots:"Robots",doctypes:"Tipo de doc.",langcode:"C\u00f3digo del lenguaje",langdir:"Direcci\u00f3n del lenguaje",ltr:"Izquierda a derecha",rtl:"Derecha a izquierda",xml_pi:"Declaraci\u00f3n XML",encoding:"Codificaci\u00f3n de caracteres",appearance_bgprops:"Propiedades del fondo",appearance_marginprops:"M\u00e1rgenes",appearance_linkprops:"Colores del v\u00ednculo",appearance_textprops:"Propiedades de texto",bgcolor:"Color de fondo",bgimage:"Imagen de fondo",left_margin:"Margen izquierdo",right_margin:"Margen derecho",top_margin:"Margen superior",bottom_margin:"Margen inferior",text_color:"Color del texto",font_size:"Tama\u00f1o de fuente",font_face:"Fuente",link_color:"Color de v\u00ednculo",hover_color:"Color rat\u00f3n encima",visited_color:"Color visitado",active_color:"Color activo",textcolor:"Color",fontsize:"Tama\u00f1o de fuente",fontface:"Fuente",meta_index_follow:"Indexar y seguir los v\u00ednculos",meta_index_nofollow:"Indexar y no seguir los v\u00ednculos",meta_noindex_follow:"No indexar pero seguir v\u00ednculos",meta_noindex_nofollow:"No indexar y no seguir v\u00ednculos",appearance_style:"Propiedades de hoja de estilos y estilo",stylesheet:"Hoja de estilo",style:"Estilo",author:"Autor",copyright:"Copyright",add:"Agregar nuevo elemento",remove:"Eliminar elemento seleccionado",moveup:"Mover elemento seleccionado hacia arriba",movedown:"Mover elemento seleccionado hacia abajo",head_elements:"Elemento Head",info:"Informaci\u00f3n",add_title:"Elemento Title",add_meta:"Elemento Meta",add_script:"Elemento Script",add_style:"Elemento Style",add_link:"Elemento Link",add_base:"Elemento Base",add_comment:"Nodo Comment",title_element:"Elemento Title",script_element:"Elemento Script",style_element:"Elemento Style",base_element:"Elemento Base",link_element:"Elemento Link",meta_element:"Elemento Meta",comment_element:"Comentario",src:"Src",language:"Lenguaje",href:"Href",target:"Target",type:"Tipo",charset:"Charset",defer:"Defer",media:"Medio",properties:"Propiedades",name:"Nombre",value:"Valor",content:"Contenido",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Avanzado"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/tw_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000524311526350530033752 0ustar frankiefrankietinyMCE.addI18n('tw.fullpage_dlg',{title:"\u6a94\u6848\u5c6c\u6027",meta_tab:"\u6a19\u6e96",appearance_tab:"\u5916\u89c0",advanced_tab:"\u9032\u968e",meta_props:"Mata\u8a0a\u606f",langprops:"\u8a9e\u8a00\u548c\u7de8\u78bc",meta_title:"\u6a19\u984c",meta_keywords:"\u95dc\u9375\u5b57",meta_description:"\u8aaa\u660e",meta_robots:"Robots",doctypes:"DocType",langcode:"\u6587\u5b57\u7de8\u78bc",langdir:"\u6587\u5b57\u66f8\u5beb\u65b9\u5411",ltr:"\u5f9e\u5de6\u5230\u53f3",rtl:"\u5f9e\u53f3\u5230\u5de6",xml_pi:"XML\u8072\u660e",encoding:"\u5b57\u5143\u7de8\u78bc",appearance_bgprops:"\u80cc\u666f\u984f\u8272",appearance_marginprops:"\u908a\u8ddd",appearance_linkprops:"\u8d85\u9023\u7d50\u984f\u8272",appearance_textprops:"\u6587\u5b57\u5c6c\u6027",bgcolor:"\u80cc\u666f\u984f\u8272",bgimage:"\u80cc\u666f\u5716\u7247",left_margin:"\u5de6\u908a\u8ddd",right_margin:"\u53f3\u908a\u8ddd",top_margin:"\u4e0a\u908a\u8ddd",bottom_margin:"\u4e0b\u908a\u8ddd",text_color:"\u6587\u5b57\u984f\u8272",font_size:"\u6587\u5b57\u5927\u5c0f",font_face:"\u5b57\u9ad4",link_color:"\u8d85\u9023\u7d50\u984f\u8272",hover_color:"Hover \u984f\u8272",visited_color:"Visited \u984f\u8272",active_color:"Active \u984f\u8272",textcolor:"\u984f\u8272",fontsize:"\u6587\u5b57\u5927\u5c0f",fontface:"\u5b57\u9ad4",meta_index_follow:"\u7d22\u5f15\u4e26\u9023\u7d50",meta_index_nofollow:"\u7d22\u5f15\u4f46\u4e0d\u9023\u7d50",meta_noindex_follow:"\u4e0d\u7d22\u5f15\u4f46\u9023\u7d50",meta_noindex_nofollow:"\u4e0d\u7d22\u5f15\u4e5f\u4e0d\u9023\u7d50",appearance_style:"\u6a23\u5f0f\u5217\u8868\u8207\u6a23\u5f0f\u5c6c\u6027",stylesheet:"\u6a23\u5f0f\u5217\u8868",style:"\u6a23\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6b0a\u8072\u660e",add:"\u65b0\u589e\u5143\u7d20",remove:"\u522a\u9664\u9078\u64c7\u5143\u7d20",moveup:"\u4e0a\u79fb\u9078\u64c7\u5143\u7d20",movedown:"\u4e0b\u79fb\u9078\u64c7\u5143\u7d20",head_elements:"Head \u5143\u7d20",info:"\u8cc7\u8a0a",add_title:"Title \u5143\u7d20",add_meta:"Meta \u5143\u7d20",add_script:"Script \u5143\u7d20",add_style:"Style \u5143\u7d20",add_link:"Link \u5143\u7d20",add_base:"Base \u5143\u7d20",add_comment:"\u8a3b\u91cb",title_element:"Title \u5143\u7d20",script_element:"Script \u5143\u7d20",style_element:"Style \u5143\u7d20",base_element:"Base \u5143\u7d20",link_element:"Link \u5143\u7d20",meta_element:"Meta \u5143\u7d20",comment_element:"\u8a3b\u91cb",src:"src",language:"\u8a9e\u8a00",href:"href",target:"\u76ee\u6a19",type:"\u985e\u578b",charset:"\u5b57\u5143\u96c6",defer:"Defer",media:"\u5f71\u7247",properties:"\u5c6c\u6027",name:"\u540d\u7a31",value:"\u503c",content:"\u5167\u5bb9",rel:"rel",rev:"rev",hreflang:"href lang",general_props:"\u4e00\u822c",advanced_props:"\u9032\u968e"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ca_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000473011526350530033752 0ustar frankiefrankietinyMCE.addI18n('ca.fullpage_dlg',{title:"Propietats del document",meta_tab:"General",appearance_tab:"Aparen\u00e7a",advanced_tab:"Avan\u00e7at",meta_props:"Metainformaci\u00f3",langprops:"Idioma i codificaci\u00f3",meta_title:"T\u00edtol",meta_keywords:"Paraules clau",meta_description:"Descripci\u00f3",meta_robots:"Robots",doctypes:"Doctype",langcode:"Codi d\\\'idioma",langdir:"Direcci\u00f3 de l\\\'idioma",ltr:"D\\\'esquerra a dreta",rtl:"De dreta a esquerra",xml_pi:"Declaraci\u00f3 XML",encoding:"Codificaci\u00f3 dels car\u00e0cters",appearance_bgprops:"Propietats del fons",appearance_marginprops:"Marges del cos",appearance_linkprops:"Colors d\\\'enlla\u00e7",appearance_textprops:"Propietats del text",bgcolor:"Color del fons",bgimage:"Imatge del fons",left_margin:"Marge esquerre",right_margin:"Marge dret",top_margin:"Marge superior",bottom_margin:"Marge inferior",text_color:"Color del text",font_size:"Mida de la font",font_face:"Font",link_color:"Color d\\\'enlla\u00e7",hover_color:"Color quan es passi per sobre",visited_color:"Color quan ja \u00e9s visitat",active_color:"Color quan \u00e9s actiu",textcolor:"Color",fontsize:"Mida de la font",fontface:"Fam\u00edlia de la font",meta_index_follow:"Indexa i segueix els enlla\u00e7os",meta_index_nofollow:"Indexa i no segueixis els enlla\u00e7os",meta_noindex_follow:"No indexis per\u00f2 segueix els enlla\u00e7os",meta_noindex_nofollow:"No indexis i no segueixis els enlla\u00e7os",appearance_style:"Full d\\\'estils i propietats dels estils",stylesheet:"Full d\\\'estils",style:"Estil",author:"Autor",copyright:"Copyright",add:"Afegeix un nou element",remove:"Elimina l\\\'element seleccionat",moveup:"Mou amunt l\\\'element seleccionat",movedown:"Mou avall l\\\'element seleccionat",head_elements:"Elements d\\\'encap\u00e7alament",info:"Informaci\u00f3",add_title:"Element t\u00edtol",add_meta:"Element meta",add_script:"Element script",add_style:"Element estil",add_link:"Element enlla\u00e7",add_base:"Element base",add_comment:"Node comentari",title_element:"Element t\u00edtol",script_element:"Element script",style_element:"Element estil",base_element:"Element base",link_element:"Element enlla\u00e7",meta_element:"Element meta",comment_element:"Comentari",src:"Src",language:"Idioma",href:"Href",target:"Dest\u00ed",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Propietats",name:"Nom",value:"Valor",content:"Contingut",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Avan\u00e7at"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/tr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000516511526350530033755 0ustar frankiefrankietinyMCE.addI18n('tr.fullpage_dlg',{title:"Belge \u00f6zellikleri",meta_tab:"Genel",appearance_tab:"G\u00f6r\u00fcn\u00fcm",advanced_tab:"Geli\u015fmi\u015f",meta_props:"Meta bilgisi",langprops:"Dil ve kodlama",meta_title:"Ba\u015fl\u0131k",meta_keywords:"Anahtar kelimeler",meta_description:"A\u00e7\u0131klama",meta_robots:"Robotlar",doctypes:"Belge tipi",langcode:"Dil kodu",langdir:"Dil y\u00f6n\u00fc",ltr:"Sa\u011fdan sola",rtl:"Soldan sa\u011fa",xml_pi:"XML tan\u0131m\u0131",encoding:"Karakter kodlamas\u0131",appearance_bgprops:"Arkaplan \u00f6zellikleri",appearance_marginprops:"G\u00f6vde bo\u015fluklar\u0131",appearance_linkprops:"Ba\u011flant\u0131 renkleri",appearance_textprops:"Metin \u00f6zellikleri",bgcolor:"Arkaplan rengi",bgimage:"Arkaplan resmi",left_margin:"Sol bo\u015fluk",right_margin:"Sa\u011f bo\u015fluk",top_margin:"\u00dcst bo\u015fluk",bottom_margin:"Alt bo\u015fluk",text_color:"Metin rengi",font_size:"Yaz\u0131 boyutu",font_face:"Yaz\u0131 tipi",link_color:"Ba\u011flant\u0131 rengi",hover_color:"Fare \u00fcst\u00fcnde rengi",visited_color:"Ziyaret edilmi\u015f ba\u011flant\u0131 rengi",active_color:"Ge\u00e7erli renk",textcolor:"Renk",fontsize:"Yaz\u0131 boyutu",fontface:"Yaz\u0131 tipi",meta_index_follow:"\u0130ndeksle ve ba\u011flant\u0131lar\u0131 izle.",meta_index_nofollow:"\u0130ndeksle ve ba\u011flant\u0131lar\u0131 izleme.",meta_noindex_follow:"\u0130ndeksleme ama ba\u011flant\u0131lar\u0131 izle.",meta_noindex_nofollow:"\u0130ndeksleme ve ba\u011flant\u0131lar\u0131 izleme.",appearance_style:"Stil ve stil sayfas\u0131 \u00f6zellikleri",stylesheet:"Stil sayfas\u0131",style:"Stil",author:"Yazar",copyright:"Telik hakk\u0131",add:"Yeni nesne ekle",remove:"Se\u00e7ili nesneyi kald\u0131r",moveup:"Se\u00e7ili nesneyi yukar\u0131 ta\u015f\u0131",movedown:"Se\u00e7ili nesneyi a\u015fa\u011f\u0131 ta\u015f\u0131",head_elements:"Ba\u015fl\u0131k nesneleri",info:"Bilgi",add_title:"Ba\u015fl\u0131k nesnesi",add_meta:"Meta nesnesi",add_script:"Script nesnesi",add_style:"Stil nesnesi",add_link:"Ba\u011flant\u0131 nesnesi",add_base:"Temel nesne",add_comment:"Yorum d\u00fc\u011f\u00fcm\u00fc",title_element:"Ba\u015fl\u0131k nesnesi",script_element:"Script nesnesi",style_element:"Stil nesnesi",base_element:"Temel nesne",link_element:"Ba\u011flant\u0131 nesnesi",meta_element:"Meta nesnesi",comment_element:"Yorum",src:"Src",language:"Dil",href:"Href",target:"Hedef",type:"Tip",charset:"Karakter seti",defer:"Erteleme",media:"Medya",properties:"\u00d6zellikler",name:"\u0130sim",value:"De\u011fer",content:"\u0130\u00e7erik",rel:"Rel",rev:"Rev",hreflang:"Href dili",general_props:"Genel",advanced_props:"Geli\u015fmi\u015f"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/nn_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000441711526350530033754 0ustar frankiefrankietinyMCE.addI18n('nn.fullpage_dlg',{title:"Dokumenteigenskapar",meta_tab:"Generelt",appearance_tab:"Utsj\u00e5nad",advanced_tab:"Avansert",meta_props:"Metainformasjon",langprops:"Spr\u00e5k og koding",meta_title:"Tittel",meta_keywords:"N\u00f8kkelord",meta_description:"Omtale",meta_robots:"Roboter",doctypes:"Doctype",langcode:"Spr\u00e5kkode",langdir:"Skriftretning",ltr:"Venstre mot h\u00f8gre",rtl:"H\u00f8gre mot venstre",xml_pi:"XML-deklarasjon",encoding:"Teiknkonvertering",appearance_bgprops:"Bakgrunnseigenskapar",appearance_marginprops:"Body-marg",appearance_linkprops:"Lenkjefargar",appearance_textprops:"Teksteigenskapar",bgcolor:"Bakgrunn",bgimage:"Bakgrunnsbilete",left_margin:"Venstre marg",right_margin:"H\u00f8gre marg",top_margin:"Toppmarg",bottom_margin:"Botnmarg",text_color:"Farge",font_size:"Skriftstorleik",font_face:"Skrifttype",link_color:"Lenkjefarge",hover_color:"Mus-over-farge",visited_color:"Bes\u00f8kt-farge",active_color:"Aktiv farge",textcolor:"Farge",fontsize:"Skriftstorleik",fontface:"Skriftfamile",meta_index_follow:"Indekser, og f\u00f8lg lenkjene",meta_index_nofollow:"Indekser, men ikkje f\u00f8lg lenkjene",meta_noindex_follow:"Ikkje indekser, men f\u00f8lg lenkjene",meta_noindex_nofollow:"Ikkje indekser, og ikkje f\u00f8lg lenkjene",appearance_style:"Stilark og stileigenskapar",stylesheet:"Stilark",style:"Stil",author:"Forfattar",copyright:"Copyright",add:"Legg til nytt element",remove:"Fjern",moveup:"Flytt markert element opp",movedown:"Flytt markert element ned",head_elements:"Overskriftselement",info:"Informasjon",add_title:"Tittelelement",add_meta:"Metaelement",add_script:"Skriptelement",add_style:"Stilelement",add_link:"Lenkjeelement",add_base:"Basiselement",add_comment:"Kommentarnode",title_element:"Tittelelement",script_element:"Skriptelement",style_element:"Stilelement",base_element:"Basiselement",link_element:"Lenkjeelement",meta_element:"Metaelement",comment_element:"Kommentar",src:"Skjerm",language:"Spr\u00e5k",href:"Href",target:"M\u00e5l",type:"Type",charset:"Teiknsett",defer:"Defer",media:"Objekt",properties:"Eigenskapar",name:"Namn",value:"Verdi",content:"Nytt lag...",rel:"Sida sitt tilh\u00f8ve til m\u00e5let",rev:"M\u00e5let sitt tilh\u00f8ve til sida",hreflang:"Href lang",general_props:"Generelt",advanced_props:"Generelle eigenskapar"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/bg_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001300411526350530033744 0ustar frankiefrankietinyMCE.addI18n('bg.fullpage_dlg',{title:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",meta_tab:"\u041e\u0431\u0449\u0438",appearance_tab:"\u0412\u044a\u043d\u0448\u0435\u043d \u0432\u0438\u0434",advanced_tab:"\u0417\u0430 \u043d\u0430\u043f\u0440\u0435\u0434\u043d\u0430\u043b\u0438",meta_props:"Meta \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f",langprops:"\u0415\u0437\u0438\u043a \u0438 \u043a\u043e\u0434\u0438\u0440\u0430\u043d\u0435",meta_title:"\u0417\u0430\u0433\u043b\u0430\u0432\u0438\u0435",meta_keywords:"\u041a\u043b\u044e\u0447\u043e\u0432\u0438 \u0434\u0443\u043c\u0438",meta_description:"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",meta_robots:"\u0420\u043e\u0431\u043e\u0442\u0438",doctypes:"\u0422\u0438\u043f",langcode:"\u041a\u043e\u0434 \u043d\u0430 \u0435\u0437\u0438\u043a\u0430",langdir:"\u041f\u043e\u0441\u043e\u043a\u0430 \u043d\u0430 \u0435\u0437\u0438\u043a\u0430",ltr:"\u041e\u0442\u043b\u044f\u0432\u043e \u043d\u0430 \u0434\u044f\u0441\u043d\u043e",rtl:"\u041e\u0442\u0434\u044f\u0441\u043d\u043e \u043d\u0430 \u043b\u044f\u0432\u043e",xml_pi:"XML \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0446\u0438\u0438",encoding:"\u041a\u043e\u0434\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0441\u0438\u043c\u0432\u043e\u043b\u0438\u0442\u0435",appearance_bgprops:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0444\u043e\u043d\u0430",appearance_marginprops:"Body margins",appearance_linkprops:"\u0426\u0432\u0435\u0442\u043e\u0432\u0435 \u043d\u0430 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435",appearance_textprops:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430",bgcolor:"\u0426\u0432\u044f\u0442 \u043d\u0430 \u0434\u043e\u043d\u0430",bgimage:"\u0424\u043e\u043d\u043e\u0432\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430",left_margin:"\u041b\u044f\u0432 margin",right_margin:"\u0414\u0435\u0430\u0441\u0435\u043d margin",top_margin:"\u0413\u043e\u0440\u0435\u043d margin",bottom_margin:"\u0414\u043e\u043b\u0435\u043d margin",text_color:"\u0426\u0432\u044f\u0442 \u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430",font_size:"\u0420\u0430\u0437\u043c\u0435\u0440 \u043d\u0430 \u0448\u0440\u0438\u0444\u0442\u0430",font_face:"\u0428\u0440\u0438\u0444\u0442",link_color:"\u0426\u0432\u044f\u0442 \u043d\u0430 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430",hover_color:"\u0426\u0432\u044f\u0442 \u043f\u0440\u0438 hover",visited_color:"\u0426\u0432\u044f\u0442 \u0437\u0430 \u043f\u043e\u0441\u0435\u0442\u0435\u043d\u0438 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0438",active_color:"\u0410\u043a\u0442\u0438\u0432\u0435\u043d \u0446\u0432\u044f\u0442",textcolor:"\u0426\u0432\u044f\u0442",fontsize:"\u0420\u0430\u0437\u043c\u0435\u0440 \u043d\u0430 \u0448\u0440\u0438\u0444\u0442\u0430",fontface:"\u0428\u0440\u0438\u0444\u0442",meta_index_follow:"\u0418\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0430\u0439 \u0438 \u0441\u043b\u0435\u0434\u0432\u0430\u0439 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435",meta_index_nofollow:"\u0418\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0430\u0439 \u0438 \u043d\u0435 \u0441\u043b\u0435\u0434\u0432\u0430\u0439 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435",meta_noindex_follow:"\u041d\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0430\u0439 \u043d\u043e \u0441\u043b\u0435\u0434\u0432\u0430\u0439 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435",meta_noindex_nofollow:"\u041d\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0430\u0439 \u0438 \u043d\u0435 \u0441\u043b\u0435\u0434\u0432\u0430\u0439 \u0445\u0438\u043f\u0435\u0440\u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435",appearance_style:"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 Stylesheet \u0438 \u0441\u0442\u0438\u043b\u0430",stylesheet:"Stylesheet",style:"\u0421\u0442\u0438\u043b",author:"\u0410\u0432\u0442\u043e\u0440",copyright:"Copyright",add:"\u0414\u043e\u0431\u0430\u0432\u0438 \u043d\u043e\u0432 \u0435\u043b\u0435\u043c\u0435\u043d\u0442",remove:"\u041f\u0440\u0435\u043c\u0430\u0445\u043d\u0438 \u0438\u0437\u0431\u0440\u0430\u043d\u0438\u044f\u0442 \u0435\u043b\u0435\u043c\u0435\u043d\u0442",moveup:"\u041f\u0440\u0438\u0434\u0432\u0438\u0436\u0438 \u0438\u0437\u0431\u0440\u0430\u043d\u0438\u044f\u0442 \u0435\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0433\u043e\u0440\u0435",movedown:"\u041f\u0440\u0438\u0434\u0432\u0438\u0436\u0438 \u0438\u0437\u0431\u0440\u0430\u043d\u0438\u044f\u0442 \u0435\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0434\u043e\u043b\u0443",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u041e\u0431\u0449\u0438",advanced_props:"\u0417\u0430 \u043d\u0430\u043f\u0440\u0435\u0434\u043d\u0430\u043b\u0438"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/pl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000510211526350530033744 0ustar frankiefrankietinyMCE.addI18n('pl.fullpage_dlg',{title:"W\u0142a\u015bciwo\u015bci dokumentu",meta_tab:"Og\u00f3lne",appearance_tab:"Wygl\u0105d",advanced_tab:"Zaawansowane",meta_props:"Meta informacje",langprops:"J\u0119zyk i kodowanie",meta_title:"Tytu\u0142",meta_keywords:"S\u0142owa kluczowe",meta_description:"Opis",meta_robots:"Roboty",doctypes:"Typ dokumentu",langcode:"Oznaczenie kodowe j\u0119zyka",langdir:"Kierunek czytania tekstu",ltr:"Kierunek z lewej do prawej",rtl:"Kierunek z prawej do lewej",xml_pi:"XML deklaracja",encoding:"Kodowanie znak\u00f3w",appearance_bgprops:"W\u0142a\u015bciwo\u015bci t\u0142a",appearance_marginprops:"Marginesy strony",appearance_linkprops:"Kolor odno\u015bnik\u00f3w",appearance_textprops:"W\u0142a\u015bciwo\u015bci tekstu",bgcolor:"Kolor t\u0142a",bgimage:"Obrazek t\u0142a",left_margin:"Lewy margines",right_margin:"Prawy margines",top_margin:"G\u00f3rny margines",bottom_margin:"Dolny margines",text_color:"Kolor tekstu",font_size:"Rozmiar czcionki",font_face:"Czcionka",link_color:"Kolor odno\u015bnika",hover_color:"Kolor po najechaniu myszk\u0105",visited_color:"Kolor odwiedzonych link\u00f3w",active_color:"Kolor aktywnych link\u00f3w",textcolor:"Kolor",fontsize:"Rozmiar czcionki",fontface:"Rodzaj czcionki",meta_index_follow:"Indeksuj i pod\u0105\u017caj za linkami",meta_index_nofollow:"Indeksuj i nie pod\u0105\u017caj za odno\u015bnikami",meta_noindex_follow:"Nie indeksuj i pod\u0105\u017caj za odno\u015bnikami",meta_noindex_nofollow:"Nie indeksuj i nie pod\u0105\u017caj za odno\u015bnikami",appearance_style:"Arkusze i w\u0142a\u015bciwo\u015bci styl\u00f3w",stylesheet:"Arkusz styl\u00f3w",style:"Styl",author:"Autor",copyright:"Prawa autorskie",add:"Dodaj nowy element",remove:"Usu\u0144 wybrany element",moveup:"Przesu\u0144 wybrane element do g\u00f3ry",movedown:"Przesu\u0144 wybrane element w d\u00f3\u0142",head_elements:"Elementy nag\u0142\u00f3wka",info:"Informacja",add_title:"Tytu\u0142",add_meta:"Meta tag",add_script:"Skrypt",add_style:"Styl",add_link:"Odno\u015bnik",add_base:"Baza",add_comment:"Komentarz",title_element:"Tytu\u0142",script_element:"Skrypt",style_element:"Styl",base_element:"Baza",link_element:"Odno\u015bnik",meta_element:"Meta tag",comment_element:"Komentarz",src:"\u0139\u0161r\u00f3d\u0142o",language:"J\u0119zyk",href:"Odno\u015bnik",target:"Cel",type:"Typ",charset:"Kodowanie",defer:"Defer",media:"Media",properties:"W\u0142a\u015bciwo\u015bci",name:"Nazwa",value:"Warto\u015b\u0107",content:"Zawarto\u015b\u0107",rel:"Rel",rev:"Rev",hreflang:"J\u0119zyk odno\u015bnika",general_props:"G\u0142\u00f3wne",advanced_props:"Zaawansowane"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/hr_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000440611526350530033752 0ustar frankiefrankietinyMCE.addI18n('hr.fullpage_dlg',{title:"Svojstva dokumenta",meta_tab:"Osnovno",appearance_tab:"Izgled",advanced_tab:"Napredno",meta_props:"Meta informacije",langprops:"Jezik i kodiranje",meta_title:"Naslov",meta_keywords:"Klju\u010dne rije\u010di",meta_description:"Opis",meta_robots:"Robots",doctypes:"Doctype",langcode:"Kod jezika",langdir:"Smjer jezika",ltr:"S lijeva na desno",rtl:"S desna na lijevo",xml_pi:"XML deklaracija",encoding:"Kodiranje znakova",appearance_bgprops:"Svojstva pozadine",appearance_marginprops:"Margina",appearance_linkprops:"Boja poveznica",appearance_textprops:"Svojstva teksta",bgcolor:"Boja pozadine",bgimage:"Pozadinska slika",left_margin:"Lijeva margina",right_margin:"Desna margina",top_margin:"Gornja margina",bottom_margin:"Donja margina",text_color:"Boja teksta",font_size:"Veli\u010dina pisma",font_face:"Pismo",link_color:"Boja poveznice",hover_color:"Boja poveznice ispod mi\u0161a",visited_color:"Boja posje\u0107ene poveznice",active_color:"Boja aktivne poveznice",textcolor:"Boja",fontsize:"Veli\u010dina pisma",fontface:"Skupina pisama",meta_index_follow:"Indeksiraj i slijedi poveznice",meta_index_nofollow:"Indeksiraj i ne slijedi poveznice",meta_noindex_follow:"Ne indeksiraj i slijedi poveznice",meta_noindex_nofollow:"Ne indeksiraj i ne slijedi poveznice",appearance_style:"CSS i svojstva stila",stylesheet:"CSS",style:"Stil",author:"Autor",copyright:"Autorska prava",add:"Dodaj novi element",remove:"Ukloni odabrani element",moveup:"Pomakni odabrani element prema gore",movedown:"Pomakni odabrani element prema dolje",head_elements:"Zaglavni elementi",info:"Informacije",add_title:"Naslovni element",add_meta:"Meta element",add_script:"Skriptni element",add_style:"Sitlski element",add_link:"Element poveznice",add_base:"Osnovni element",add_comment:"Komentar",title_element:"Naslovni element",script_element:"Skriptni element",style_element:"Stilski element",base_element:"Osnovni element",link_element:"Element poveznice",meta_element:"Meta element",comment_element:"Komentar",src:"Src",language:"Jezik",href:"Href",target:"Meta",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Svojstva",name:"Ime",value:"Vrijednost",content:"Sadr\u017eaj",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Osnovno",advanced_props:"Napredno"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/my_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001413711526350530033754 0ustar frankiefrankietinyMCE.addI18n('my.fullpage_dlg',{title:"\u1005\u102c\u101b\u103d\u1000\u103a\u1005\u102c\u1010\u1019\u103a\u1038 \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",meta_tab:"\u1021\u1031\u1011\u103d\u1031\u1011\u103d",appearance_tab:"\u1021\u101e\u103d\u1004\u103a\u1021\u103c\u1015\u1004\u103a",advanced_tab:"\u1021\u1011\u1030\u1038",meta_props:"Meta \u1021\u1001\u103b\u1000\u103a\u1021\u101c\u1000\u103a\u1019\u103b\u102c\u1038",langprops:"\u1018\u102c\u101e\u102c\u1005\u1000\u102c\u1038\u1014\u103e\u1004\u103a\u1037 \u1000\u102f\u1010\u103a\u101d\u103e\u1000\u103a\u1005\u1014\u1005\u103a",meta_title:"\u1031\u1001\u102b\u1004\u103a\u1038\u1005\u102e\u1038\u1021\u1019\u100a\u103a",meta_keywords:"\u1031\u101e\u102c\u1037\u1001\u103b\u1000\u103a\u1005\u1000\u102c\u1038\u101c\u1036\u102f\u1038\u1019\u103b\u102c\u1038",meta_description:"\u1031\u1016\u102c\u103a\u103c\u1015\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038",meta_robots:"\u101b\u102d\u102f\u1037\u1031\u1018\u102c\u1037\u1019\u103b\u102c\u1038",doctypes:"DocType",langcode:"\u1018\u102c\u101e\u102c\u1005\u1000\u102c\u1038 \u1000\u102f\u1010\u103a",langdir:"\u1005\u102c\u1031\u101b\u1038\u101e\u102c\u1038\u1019\u103e\u102f \u1025\u102e\u1038\u1010\u100a\u103a\u1001\u103b\u1000\u103a",ltr:"\u1018\u101a\u103a\u1019\u103e \u100a\u102c",rtl:"\u100a\u102c\u1019\u103e \u1018\u101a\u103a",xml_pi:"XML \u1031\u103c\u1000\u102c\u103a\u103c\u1004\u102c\u1001\u103b\u1000\u103a\u1019\u103b\u102c\u1038",encoding:"\u1021\u1000\u1039\u1001\u101b\u102c \u1000\u102f\u1010\u103a\u101d\u103e\u1000\u103a\u1005\u1014\u1005\u103a",appearance_bgprops:"\u1031\u1014\u102c\u1000\u103a\u1001\u1036 \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",appearance_marginprops:"\u1000\u102d\u102f\u101a\u103a\u1011\u100a\u103a \u1031\u1018\u1038\u1019\u103b\u1009\u103a\u1038\u1019\u103b\u102c\u1038",appearance_linkprops:"\u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c \u1021\u1031\u101b\u102c\u1004\u103a\u1019\u103b\u102c\u1038",appearance_textprops:"\u1005\u102c\u101e\u102c\u1038 \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",bgcolor:"\u1031\u1014\u102c\u1000\u103a\u1001\u1036 \u1021\u1031\u101b\u102c\u1004\u103a",bgimage:"\u1031\u1014\u102c\u1000\u103a\u1001\u1036 \u101b\u102f\u1015\u103a\u1015\u1036\u102f",left_margin:"\u1018\u101a\u103a\u1018\u1000\u103a \u1031\u1018\u1038\u1019\u103b\u1009\u103a\u1038",right_margin:"\u100a\u102c\u1018\u1000\u103a \u1031\u1018\u1038\u1019\u103b\u1009\u103a\u1038",top_margin:"\u1011\u102d\u1015\u103a\u1015\u102d\u102f\u1004\u103a\u1038 \u1031\u1018\u1038\u1019\u103b\u1009\u103a\u1038",bottom_margin:"\u1031\u1021\u102c\u1000\u103a\u1031\u103c\u1001 \u1031\u1018\u1038\u1019\u103b\u1009\u103a\u1038",text_color:"\u1005\u102c\u101e\u102c\u1038\u1021\u1031\u101b\u102c\u1004\u103a",font_size:"\u1005\u102c\u101c\u1036\u102f\u1038 \u1031\u1016\u102c\u1004\u103a\u1037\u1021\u101b\u103d\u101a\u103a",font_face:"\u1005\u102c\u101c\u1036\u102f\u1038\u1031\u1016\u102c\u1004\u103a\u1037 \u1019\u102d\u101e\u102c\u1038\u1005\u102f",link_color:"\u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c \u1021\u1031\u101b\u102c\u1004\u103a",hover_color:"Hover \u1021\u1031\u101b\u102c\u1004\u103a",visited_color:"Visited \u1021\u1031\u101b\u102c\u1004\u103a",active_color:"Active \u1021\u1031\u101b\u102c\u1004\u103a",textcolor:"\u1021\u1031\u101b\u102c\u1004\u103a",fontsize:"\u1005\u102c\u101c\u1036\u102f\u1038 \u1031\u1016\u102c\u1004\u103a\u1037\u1021\u101b\u103d\u101a\u103a",fontface:"\u1005\u102c\u101c\u1036\u102f\u1038\u1031\u1016\u102c\u1004\u103a\u1037 \u1019\u102d\u101e\u102c\u1038\u1005\u102f",meta_index_follow:"\u1021\u100a\u103d\u103e\u1014\u103a\u1038\u103c\u1015\u102f\u101c\u102f\u1015\u103a\u104d \u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c\u1031\u1014\u102c\u1000\u103a\u101c\u102d\u102f\u1000\u103a\u1015\u102b",meta_index_nofollow:"\u1021\u100a\u103d\u103e\u1014\u103a\u1038\u103c\u1015\u102f\u101c\u102f\u1015\u103a\u103c\u1015\u102e\u1038 \u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c\u1031\u1014\u102c\u1000\u103a\u1019\u101c\u102d\u102f\u1000\u103a\u1015\u102b\u1014\u103e\u1004\u103a\u1037",meta_noindex_follow:"\u1021\u100a\u103d\u103e\u1014\u103a\u1038\u1019\u103c\u1015\u102f\u101c\u102f\u1015\u103a\u1018\u1032 \u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c\u1031\u1014\u102c\u1000\u103a\u101c\u102d\u102f\u1000\u103a\u1015\u102b",meta_noindex_nofollow:"\u1021\u100a\u103d\u103e\u1014\u103a\u1038\u1019\u101c\u102f\u1015\u103a\u1015\u102b \u1001\u103b\u102d\u1010\u103a\u1006\u1000\u103a\u101c\u102d\u1015\u103a\u1005\u102c\u1031\u1014\u102c\u1000\u103a\u101c\u100a\u103a\u1038 \u1019\u101c\u102d\u102f\u1000\u103a\u1015\u102b",appearance_style:"Stylesheet \u1014\u103e\u1004\u103a \u1005\u1010\u102d\u102f\u1004\u103a \u101d\u102d\u1031\u101e\u101e\u101c\u1000\u1039\u1001\u100f\u102c\u1019\u103b\u102c\u1038",stylesheet:"\u1005\u1010\u102d\u102f\u1004\u103a \u1005\u102c\u101b\u103d\u1000\u103a",style:"\u1005\u1010\u102d\u102f\u1004\u103a",author:"\u1031\u101b\u1038\u101e\u1030",copyright:"\u1019\u1030\u1015\u102d\u102f\u1004\u103a\u1001\u103d\u1004\u103a\u1037",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/kl_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('kl.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ar_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000426211526350530033752 0ustar frankiefrankietinyMCE.addI18n('ar.fullpage_dlg',{title:"Document properties",meta_tab:"\u0639\u0627\u0645",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u0639\u0627\u0645",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/te_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('te.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/sk_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000560711526350530033756 0ustar frankiefrankietinyMCE.addI18n('sk.fullpage_dlg',{title:"Vlastnosti dokumentu",meta_tab:"Obecn\u00e9",appearance_tab:"Vzh\u013ead",advanced_tab:"Roz\u0161\u00edren\u00e9",meta_props:"Meta inform\u00e1cie",langprops:"Jazyk a k\u00f3dovanie",meta_title:"Titulok",meta_keywords:"K\u013e\u00fa\u010dov\u00e9 slov\u00e1",meta_description:"Popis",meta_robots:"Roboti",doctypes:"Typ dokumentu",langcode:"K\u00f3d jazyka",langdir:"Smer textu",ltr:"Z\u013eava doprava",rtl:"Sprava do\u013eava",xml_pi:"XML deklar\u00e1cia",encoding:"K\u00f3dovanie",appearance_bgprops:"Vlastnosti pozadia",appearance_marginprops:"Okraje tela dokumentu",appearance_linkprops:"Vlastnosti odkazov",appearance_textprops:"Vlastnosti textu",bgcolor:"Farba pozadia",bgimage:"Obr\u00e1zok pozadia",left_margin:"\u013dav\u00fd okraj",right_margin:"Prav\u00fd okraj",top_margin:"Horn\u00fd okraj",bottom_margin:"Doln\u00fd okraj",text_color:"Farba textu",font_size:"Ve\u013ekos\u0165 p\u00edsma",font_face:"Typ p\u00edsma",link_color:"Farba odkazu",hover_color:"Farba vybrat\u00e9ho odkazu",visited_color:"Farba nav\u0161t\u00edven\u00e9ho odkazu",active_color:"Farba akt\u00edvneho odkazu",textcolor:"Farba",fontsize:"Ve\u013ekos\u0165 p\u00edsma",fontface:"Typ p\u00edsma",meta_index_follow:"Indexova\u0165 a n\u00e1sledova\u0165 odkazy",meta_index_nofollow:"Indexova\u0165 a nen\u00e1sledova\u0165 odkazy",meta_noindex_follow:"Neindexova\u0165, ale n\u00e1sledova\u0165 odkazy",meta_noindex_nofollow:"Neindexova\u0165 a nen\u00e1sledova\u0165 odkazy",appearance_style:"Vlastnosti \u0161t\u00fdlov",stylesheet:"\u0160t\u00fdlopis",style:"\u0160t\u00fdl",author:"Autor",copyright:"Autorsk\u00e9 pr\u00e1va",add:"Prida\u0165 nov\u00fd element",remove:"Odstr\u00e1ni\u0165 ozna\u010den\u00fd element",moveup:"Presun\u00fa\u0165 ozna\u010den\u00fd element vy\u0161\u0161ie ",movedown:"P\u0159esun\u00fa\u0165 ozna\u010den\u00fd element ni\u017e\u0161ie",head_elements:"Hlavi\u010dky",info:"Inform\u00e1cie",add_title:"Vlo\u017ei\u0165 titulok",add_meta:"Vlo\u017ei\u0165 meta inform\u00e1cie",add_script:"Vlo\u017ei\u0165 skript",add_style:"Vlo\u017ei\u0165 \u0161t\u00fdl",add_link:"Vlo\u017ei\u0165 nezobrazovan\u00fd odkaz",add_base:"Vlo\u017ei\u0165 z\u00e1kladn\u00e9 umiestnenie",add_comment:"Vlo\u017ei\u0165 koment\u00e1r",title_element:"Titulok",script_element:"Skript",style_element:"\u0160t\u00fdl",base_element:"Z\u00e1kladn\u00e9 umiestnenie",link_element:"Nezobrazovan\u00fd odkaz",meta_element:"Meta inform\u00e1cie",comment_element:"Koment\u00e1r",src:"Zdroj",language:"Jazyk",href:"S\u00fabor/URL",target:"Cie\u013e",type:"Typ",charset:"K\u00f3dovanie",defer:"Odlo\u017ei\u0165 (defer)",media:"M\u00e9di\u00e1",properties:"Vlastnosti",name:"N\u00e1zov",value:"Hodnota",content:"Obsah",rel:"Vz\u0165ah str\u00e1nky k cie\u013eu",rev:"Vz\u0165ah cie\u013ea k str\u00e1nke",hreflang:"Jazyk odkazu",general_props:"Obecn\u00e9 parametre",advanced_props:"Roz\u0161\u00edren\u00e9 parametre"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/eu_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000453011526350530033750 0ustar frankiefrankietinyMCE.addI18n('eu.fullpage_dlg',{title:"Dokumentuaren ezaugarriak",meta_tab:"Orokorra",appearance_tab:"Itxura",advanced_tab:"Aurreratua",meta_props:"Meta datuak",langprops:"Hizkuntza eta kodeketa",meta_title:"Izenburua",meta_keywords:"Hitz-gakoak",meta_description:"Deskribapena",meta_robots:"Robotak",doctypes:"Dokumentu mota",langcode:"Hizkuntza kodea",langdir:"Hizkuntza norabidea",ltr:"Ezkerretik eskuinera",rtl:"Eskuinetik ezkerrera",xml_pi:"XML zehaztapena",encoding:"Karaktere kodeketa",appearance_bgprops:"Atzeko ezaugarriak",appearance_marginprops:"Gorputzaren marginak",appearance_linkprops:"Lotura koloreak",appearance_textprops:"Testu ezaugarriak",bgcolor:"Atzeko kolorea",bgimage:"Atzeko irudia",left_margin:"Ezker margina",right_margin:"Eskuin margina",top_margin:"Goiko margina",bottom_margin:"Beheko margina",text_color:"Testu kolorea",font_size:"Letra tamaina",font_face:"Letra mota",link_color:"Loturaren kolorea",hover_color:"Lotura gainean kolorea",visited_color:"Bisitatutako lotura kolorea",active_color:"Loruta aktiboaren kolorea",textcolor:"Kolorea",fontsize:"Letra tamaina",fontface:"Letra mota",meta_index_follow:"Indexatu eta jarraitu loturak",meta_index_nofollow:"Indexatu eta ez jarraitu loturak",meta_noindex_follow:"Ez indexatu, baina jarraitu loturak",meta_noindex_nofollow:"Ez indexatu eta ez jarraitu loturak",appearance_style:"Estilo orri eta estilo ezaugarriak",stylesheet:"Estilo orria",style:"Estiloa",author:"Egilea",copyright:"Copyright",add:"Gehitu elementua",remove:"Ezabatu aukeratutako elementua",moveup:"Mugitu aukeratutako elementua gora",movedown:"Mugitu aukeratutako elementua behera",head_elements:"Goiburuko elementuak",info:"Informazioa",add_title:"Title elementua",add_meta:"Meta elementua",add_script:"Script elementua",add_style:"Style elementua",add_link:"Link elementua",add_base:"Base elementua",add_comment:"Comment nodoa",title_element:"Title elementua",script_element:"Script elementua",style_element:"Style elementua",base_element:"Base elementua",link_element:"Link elementua",meta_element:"Meta elementua",comment_element:"Iruzkina",src:"Src",language:"Hizkuntza",href:"Href",target:"Helburua",type:"Mota",charset:"Karaktereak",defer:"Defer",media:"Media",properties:"Ezaugarriak",name:"Izena",value:"Balioa",content:"Edukia",rel:"Rel",rev:"Rev",hreflang:"Href hizkuntza",general_props:"Orokorra",advanced_props:"Aurreratua"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ch_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000523511526350530033753 0ustar frankiefrankietinyMCE.addI18n('ch.fullpage_dlg',{title:"\u6863\u6848\u5c5e\u6027",meta_tab:"\u6807\u51c6",appearance_tab:"\u5916\u89c2",advanced_tab:"\u9ad8\u7ea7",meta_props:"Mata\u8baf\u606f",langprops:"\u8bed\u8a00\u7f16\u7801",meta_title:"\u6807\u9898",meta_keywords:"\u5173\u952e\u5b57",meta_description:"\u8bf4\u660e",meta_robots:"Robots",doctypes:"DocType",langcode:"\u6587\u5b57\u7f16\u7801",langdir:"\u6587\u5b57\u4e66\u5199\u65b9\u5411",ltr:"\u4ece\u5de6\u5230\u53f3",rtl:"\u4ece\u53f3\u5230\u5de6",xml_pi:"XML\u58f0\u660e",encoding:"\u8bed\u8a00\u7f16\u7801",appearance_bgprops:"\u80cc\u666f\u989c\u8272",appearance_marginprops:"\u8fb9\u8ddd",appearance_linkprops:"\u8d85\u8fde\u7ed3\u989c\u8272",appearance_textprops:"\u6587\u5b57\u5c5e\u6027",bgcolor:"\u80cc\u666f\u989c\u8272",bgimage:"\u80cc\u666f\u56fe\u7247",left_margin:"\u5de6\u8fb9\u8ddd",right_margin:"\u53f3\u8fb9\u8ddd",top_margin:"\u4e0a\u8fb9\u8ddd",bottom_margin:"\u4e0b\u8fb9\u8ddd",text_color:"\u6587\u5b57\u989c\u8272",font_size:"\u6587\u5b57\u5927\u5c0f",font_face:"\u5b57\u4f53",link_color:"\u8d85\u8fde\u7ed3\u989c\u8272",hover_color:"Hover \u989c\u8272",visited_color:"Visited \u989c\u8272",active_color:"Active \u989c\u8272",textcolor:"\u989c\u8272",fontsize:"\u6587\u5b57\u5927\u5c0f",fontface:"\u5b57\u4f53",meta_index_follow:"\u7d22\u5f15\u5e76\u8fde\u7ed3",meta_index_nofollow:"\u7d22\u5f15\u4f46\u4e0d\u8fde\u7ed3",meta_noindex_follow:"\u4e0d\u7d22\u5f15\u4f46\u8fde\u7ed3",meta_noindex_nofollow:"\u4e0d\u7d22\u5f15\u4e5f\u4e0d\u8fde\u7ed3",appearance_style:"\u6837\u5f0f\u5217\u8868\u4e0e\u6837\u5f0f\u5c5e\u6027",stylesheet:"\u6837\u5f0f\u5217\u8868",style:"\u6837\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6743\u58f0\u660e",add:"\u65b0\u589e\u5143\u7d20",remove:"\u5220\u9664\u9009\u62e9\u5143\u7d20",moveup:"\u4e0a\u79fb\u9009\u62e9\u5143\u7d20",movedown:"\u4e0b\u79fb\u9009\u62e9\u5143\u7d20",head_elements:"Head \u5143\u7d20",info:"\u4fe1\u606f",add_title:"Title \u5143\u7d20",add_meta:"Meta \u5143\u7d20",add_script:"Script \u5143\u7d20",add_style:"Style \u5143\u7d20",add_link:"Link \u5143\u7d20",add_base:"Base \u5143\u7d20",add_comment:"\u6ce8\u91ca",title_element:"Title \u5143\u7d20",script_element:"Script \u5143\u7d20",style_element:"Style \u5143\u7d20",base_element:"Base \u5143\u7d20",link_element:"Link \u5143\u7d20",meta_element:"Meta \u5143\u7d20",comment_element:"\u6ce8\u91ca",src:"src",language:"\u8bed\u8a00",href:"href",target:"\u76ee\u6807",type:"\u7c7b\u578b",charset:"\u5b57\u7b26\u96c6",defer:"Defer",media:"\u5f71\u7247",properties:"\u5c5e\u6027",name:"\u540d\u79f0",value:"\u503c",content:"\u5185\u5bb9",rel:"rel",rev:"rev",hreflang:"href lang",general_props:"\u6807\u51c6",advanced_props:"\u9ad8\u7ea7"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/bn_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('bn.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/id_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('id.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/tt_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000543311526350530033753 0ustar frankiefrankietinyMCE.addI18n('tt.fullpage_dlg',{title:"\u6a94\u6848\u5c6c\u6027",meta_tab:"\u57fa\u672c",appearance_tab:"\u5916\u89c0",advanced_tab:"\u9032\u968e",meta_props:"\u4e2d\u7e7c\u8cc7\u6599\u5377\u6a19\u5c6c\u6027",langprops:"\u8a9e\u8a00",meta_title:"\u6a19\u984c",meta_keywords:"\u95dc\u9375\u5b57",meta_description:"\u5167\u5bb9\u8aaa\u660e",meta_robots:"\u6a5f\u5668\u4eba",doctypes:"DocType",langcode:"\u8a9e\u8a00\u7de8\u78bc",langdir:"\u8a9e\u8a00\u66f8\u5beb\u65b9\u5411",ltr:"\u5f9e\u5de6\u5230\u53f3",rtl:"\u5f9e\u53f3\u5230\u5de6",xml_pi:"XML \u8072\u660e",encoding:"\u5b57\u5143\u7de8\u78bc",appearance_bgprops:"\u80cc\u666f\u5c6c\u6027",appearance_marginprops:"\u908a\u8ddd",appearance_linkprops:"\u9023\u7d50\u9854\u8272",appearance_textprops:"\u6587\u5b57\u5c6c\u6027",bgcolor:"\u80cc\u666f\u9854\u8272",bgimage:"\u80cc\u666f\u5716\u7247",left_margin:"\u5de6\u908a\u8ddd",right_margin:"\u53f3\u908a\u8ddd",top_margin:"\u4e0a\u908a\u8ddd",bottom_margin:"\u4e0b\u908a\u8ddd",text_color:"\u6587\u5b57\u9854\u8272",font_size:"\u6587\u5b57\u5927\u5c0f",font_face:"\u5b57\u9ad4",link_color:"\u9023\u7d50\u9854\u8272",hover_color:"Hover \u9854\u8272",visited_color:"Visited \u9854\u8272",active_color:"Active \u9854\u8272",textcolor:"\u9854\u8272",fontsize:"\u6587\u5b57\u5927\u5c0f",fontface:"\u5b57\u9ad4",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"\u6a23\u5f0f\u8868\u5c6c\u6027",stylesheet:"\u6a23\u5f0f\u8868",style:"\u6a23\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6b0a",add:"\u65b0\u589e\u6587\u4ef6\u65b0\u7269\u4ef6",remove:"\u522a\u9664\u9078\u64c7\u7684\u7269\u4ef6",moveup:"\u5411\u4e0a\u79fb\u52d5\u9078\u64c7\u7684\u7269\u4ef6",movedown:"\u5411\u4e0b\u79fb\u52d5\u9078\u64c7\u7684\u7269\u4ef6",head_elements:"\u524d\u982d\u7269\u4ef6",info:"\u8cc7\u8a0a",add_title:"\u641c\u5c0b\u7269\u4ef6",add_meta:"\u5143\u7269\u4ef6",add_script:"\u8173\u672c\u7269\u4ef6",add_style:"\u6a23\u5f0f\u7269\u4ef6",add_link:"\u9023\u7d50\u5316\u7269\u4ef6",add_base:"Base\u7269\u4ef6",add_comment:"\u6ce8\u91cb\u7269\u4ef6",title_element:"\u641c\u5c0b\u7269\u4ef6",script_element:"\u8173\u672c\u7269\u4ef6",style_element:"\u6a23\u5f0f\u7269\u4ef6",base_element:"Base\u7269\u4ef6",link_element:"\u9023\u7d50\u5316\u7269\u4ef6",meta_element:"\u5143\u7269\u4ef6",comment_element:"\u6ce8\u91cb\u7269\u4ef6",src:"Src",language:"\u8a9e\u8a00",href:"Href",target:"\u76ee\u6a19",type:"\u985e\u578b",charset:"\u5b57\u5143\u96c6",defer:"Defer",media:"\u5a92\u9ad4",properties:"\u5c6c\u6027",name:"\u540d",value:"\u503c",content:"\u5167\u5bb9",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u57fa\u672c",advanced_props:"\u9032\u968e"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/zu_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000520711526350530033752 0ustar frankiefrankietinyMCE.addI18n('zu.fullpage_dlg',{title:"\u6863\u6848\u5c5e\u6027",meta_tab:"\u4e00\u822c",appearance_tab:"\u5916\u89c2",advanced_tab:"\u9ad8\u7ea7",meta_props:"\u6807\u7b7e( Meta )\u4fe1\u606f",langprops:"\u8bed\u8a00\u4e0e\u7f16\u7801",meta_title:"\u6807\u9898",meta_keywords:"\u5173\u952e\u5b57",meta_description:"\u5185\u5bb9\u8bf4\u660e",meta_robots:"Robots",doctypes:"Doctype",langcode:"\u8bed\u8a00\u7f16\u7801",langdir:"\u8bed\u8a00\u4e66\u5199\u65b9\u5411",ltr:"\u7531\u5de6\u5230\u53f3",rtl:"\u7531\u53f3\u5230\u5de6",xml_pi:"XML\u5ba3\u544a",encoding:"\u5b57\u5143\u7f16\u7801",appearance_bgprops:"\u80cc\u666f\u5c5e\u6027",appearance_marginprops:"Body margins",appearance_linkprops:"\u8fde\u7ed3\u989c\u8272",appearance_textprops:"\u6587\u5b57\u5c5e\u6027",bgcolor:"\u80cc\u666f\u989c\u8272",bgimage:"\u80cc\u666f\u56fe\u7247",left_margin:"\u5de6\u8fb9\u754c",right_margin:"\u53f3\u8fb9\u754c",top_margin:"\u4e0a\u8fb9\u754c",bottom_margin:"\u4e0b\u8fb9\u754c",text_color:"\u6587\u5b57\u989c\u8272",font_size:"\u5b57\u4f53\u5c3a\u5bf8",font_face:"\u5b57\u4f53",link_color:"\u8fde\u7ed3\u989c\u8272",hover_color:"Hover\u989c\u8272",visited_color:"Visited\u989c\u8272",active_color:"Active\u989c\u8272",textcolor:"\u989c\u8272",fontsize:"\u5b57\u4f53\u5927\u5c0f",fontface:"\u5b57\u5f62\u4f53\u7cfb",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"\u6837\u5f0f\u8868\u53ca\u6837\u5f0f\u5c5e\u6027",stylesheet:"\u6837\u5f0f\u8868",style:"\u6837\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6743",add:"\u6dfb\u52a0\u65b0\u5143\u7d20",remove:"\u79fb\u9664\u9009\u5b9a\u5143\u7d20",moveup:"\u4e0a\u79fb\u9009\u5b9a\u5143\u7d20",movedown:"\u4e0b\u79fb\u9009\u5b9a\u5143\u7d20",head_elements:"Head elements",info:"\u4fe1\u606f",add_title:"\u67e5\u627e\u5143\u7d20",add_meta:"Meta\u5143\u7d20",add_script:"Script\u5143\u7d20",add_style:"Style\u5143\u7d20",add_link:"Link\u5143\u7d20",add_base:"Base\u5143\u7d20",add_comment:"Comment node",title_element:"\u67e5\u627eelement",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"\u8bed\u8a00",href:"Href",target:"\u76ee\u6807",type:"\u7c7b\u578b",charset:"\u5b57\u5143\u96c6",defer:"\u5ef6\u7f13",media:"\u5a92\u4f53",properties:"\u5c5e\u6027",name:"\u540d\u79f0",value:"\u503c",content:"\u5185\u5bb9",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u4e00\u822c",advanced_props:"\u9ad8\u7ea7"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/dv_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('dv.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/he_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000760111526350530033752 0ustar frankiefrankietinyMCE.addI18n('he.fullpage_dlg',{title:"\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05de\u05e1\u05de\u05da",meta_tab:"\u05db\u05dc\u05dc\u05d9",appearance_tab:"\u05de\u05e8\u05d0\u05d4",advanced_tab:"\u05de\u05ea\u05e7\u05d3\u05dd",meta_props:"\u05ea\u05d2\u05d9 \u05de\u05d8\u05d4",langprops:"\u05e9\u05e4\u05d4 \u05d5\u05e7\u05d9\u05d3\u05d5\u05d3",meta_title:"\u05db\u05d5\u05ea\u05e8\u05ea",meta_keywords:"\u05de\u05d9\u05dc\u05d5\u05ea \u05de\u05e4\u05ea\u05d7",meta_description:"\u05ea\u05d9\u05d0\u05d5\u05e8",meta_robots:"\u05e8\u05d5\u05d1\u05d5\u05d8\u05d9\u05dd",doctypes:"Doctype",langcode:"\u05e7\u05d5\u05d3 \u05d4\u05e9\u05e4\u05d4",langdir:"\u05db\u05d9\u05d5\u05d5\u05df \u05d4\u05e9\u05e4\u05d4",ltr:"\u05de\u05e9\u05de\u05d0\u05dc \u05dc\u05d9\u05de\u05d9\u05df",rtl:"\u05de\u05d9\u05de\u05d9\u05df \u05dc\u05e9\u05de\u05d0\u05dc",xml_pi:"XML declaration",encoding:"\u05e7\u05d9\u05d3\u05d5\u05d3 \u05ea\u05d5\u05d5\u05d9\u05dd",appearance_bgprops:"\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9 \u05e8\u05e7\u05e2",appearance_marginprops:"Body margins",appearance_linkprops:"\u05e6\u05d1\u05e2 \u05e7\u05d9\u05e9\u05d5\u05e8\u05d9\u05dd",appearance_textprops:"Text properties",bgcolor:"\u05e6\u05d1\u05e2 \u05e8\u05e7\u05e2",bgimage:"\u05ea\u05de\u05d5\u05e0\u05ea \u05e8\u05e7\u05e2",left_margin:"\u05e9\u05d5\u05dc\u05d9\u05d9\u05dd \u05e9\u05de\u05d0\u05dc\u05d9\u05d9\u05dd",right_margin:"\u05e9\u05d5\u05dc\u05d9\u05d9\u05dd \u05d9\u05de\u05e0\u05d9\u05d9\u05dd",top_margin:"\u05e9\u05d5\u05dc\u05d9\u05d9\u05dd \u05e2\u05dc\u05d9\u05d5\u05e0\u05d9\u05dd",bottom_margin:"\u05e9\u05d5\u05dc\u05d9\u05d9\u05dd \u05ea\u05d7\u05ea\u05d9\u05d9\u05dd",text_color:"\u05e6\u05d1\u05e2 \u05d8\u05e7\u05e1\u05d8",font_size:"\u05d2\u05d5\u05d3\u05dc \u05d2\u05d5\u05e4\u05df",font_face:"\u05e1\u05d5\u05d2 \u05d2\u05d5\u05e4\u05df",link_color:"\u05e6\u05d1\u05e2 \u05e7\u05d9\u05e9\u05d5\u05e8",hover_color:"\u05e6\u05d1\u05e2 \u05e7\u05d9\u05e9\u05d5\u05e8 \u05d1\u05de\u05e2\u05d1\u05e8 \u05e2\u05db\u05d1\u05e8",visited_color:"\u05e6\u05d1\u05e2 \u05e7\u05d9\u05e9\u05d5\u05e8 \u05e9\u05e0\u05e6\u05e4\u05d4",active_color:"\u05e6\u05d1\u05e2 \u05e7\u05d9\u05e9\u05d5\u05e8 \u05e4\u05e2\u05d9\u05dc",textcolor:"\u05e6\u05d1\u05e2",fontsize:"\u05d2\u05d5\u05d3\u05dc \u05d2\u05d5\u05e4\u05df",fontface:"\u05d2\u05d5\u05e4\u05df",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"\u05e1\u05d2\u05e0\u05d5\u05df \u05e2\u05d9\u05e6\u05d5\u05d1",style:"\u05e2\u05d9\u05e6\u05d5\u05d1",author:"\u05db\u05d5\u05ea\u05d1",copyright:"\u05d6\u05db\u05d5\u05d9\u05d5\u05ea \u05d9\u05d5\u05e6\u05e8\u05d9\u05dd",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"\u05de\u05d9\u05d3\u05e2",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"\u05ea\u05d2\u05d5\u05d1\u05d4",src:"\u05db\u05ea\u05d5\u05d1\u05ea \u05de\u05e7\u05d5\u05e8",language:"\u05e9\u05e4\u05d4",href:"Href",target:"\u05d9\u05e2\u05d3",type:"\u05e1\u05d5\u05d2",charset:"\u05e7\u05d9\u05d3\u05d5\u05d3",defer:"Defer",media:"\u05de\u05d3\u05d9\u05d4",properties:"\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9\u05dd",name:"\u05e9\u05dd",value:"\u05e2\u05e8\u05da",content:"\u05ea\u05d5\u05db\u05df",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u05db\u05dc\u05dc\u05d9",advanced_props:"\u05de\u05ea\u05e7\u05d3\u05dd"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ml_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('ml.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/is_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000473511526350530033757 0ustar frankiefrankietinyMCE.addI18n('is.fullpage_dlg',{title:"Valm\u00f6guleikar skjals",meta_tab:"Almennt",appearance_tab:"\u00datlit",advanced_tab:"\u00cdtarlegt",meta_props:"Meta uppl\u00fdsingar",langprops:"Tungum\u00e1l",meta_title:"Titill",meta_keywords:"Leitaror\u00f0",meta_description:"L\u00fdsing",meta_robots:"Robots",doctypes:"Doctype",langcode:"Tungum\u00e1la k\u00f3\u00f0i",langdir:"Tungum\u00e1la \u00e1tt",ltr:"Vinstri til h\u00e6gri",rtl:"H\u00e6gri til vinstri",xml_pi:"XML declaration",encoding:"Stafa enk\u00f3\u00f0un",appearance_bgprops:"Bakgrunns m\u00f6guleikar",appearance_marginprops:"innihalds sp\u00e1ss\u00eda",appearance_linkprops:"Litir \u00e1 hlekkjum",appearance_textprops:"Text properties",bgcolor:"Bakgrunnslitur",bgimage:"Bakgrunnsmynd",left_margin:"vinstri sp\u00e1ss\u00eda",right_margin:"H\u00e6gri sp\u00e1ss\u00eda",top_margin:"Top sp\u00e1ss\u00eda",bottom_margin:"Botn sp\u00e1ss\u00eda",text_color:"Textalitur",font_size:"Stafast\u00e6r\u00f0",font_face:"Stafager\u00f0",link_color:"Litur \u00e1 hlekk",hover_color:"hover litur",visited_color:"Heims\u00f3ttur litur",active_color:"Virkur litur",textcolor:"Litur",fontsize:"Stafast\u00e6r\u00f0",fontface:"Stafa fj\u00f6lskylda",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"St\u00edlsni\u00f0 og eiginleikar",stylesheet:"St\u00edlsni\u00f0",style:"St\u00edll",author:"H\u00f6fundur",copyright:"Eignar\u00e9ttur",add:"B\u00e6ta vi\u00f0 n\u00fdjum hlut",remove:"Fjarl\u00e6gja valinn hlut",moveup:"F\u00e6ra valinn hlut upp",movedown:"F\u00e6ra valinn hlut ni\u00f0ur",head_elements:"A\u00f0al hlutur",info:"Uppl\u00fdsingar",add_title:"Titill hluts",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"B\u00e6ta vi\u00f0 athugasemd",title_element:"Titill hluts",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Tungum\u00e1l",href:"Href",target:"\u00c1\u00e6tlunarsta\u00f0ur",type:"Tegund",charset:"stafasett",defer:"V\u00edsun",media:"Margmi\u00f0lun",properties:"Eiginleikar",name:"Nafn",value:"Value",content:"Innihald",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Almennt",advanced_props:"\u00cdtarlegt"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/hy_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001204211526350530033745 0ustar frankiefrankietinyMCE.addI18n('hy.fullpage_dlg',{title:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",meta_tab:"\u041e\u0431\u0449\u0435\u0435",appearance_tab:"\u0412\u0438\u0434",advanced_tab:"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e",meta_props:"\u0426\u0435\u043b\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438",langprops:"\u042f\u0437\u044b\u043a \u0438 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f",meta_title:"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",meta_keywords:"\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430",meta_description:"\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435",meta_robots:"\u0420\u0430\u0431\u043e\u0442\u044b",doctypes:"Doctype",langcode:"\u041a\u043e\u0434 \u044f\u0437\u044b\u043a\u0430",langdir:"\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u044f\u0437\u044b\u043a\u0430",ltr:"\u0421\u043b\u0435\u0432\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043e",rtl:"\u0421\u043f\u0440\u0430\u0432\u0430 \u043d\u0430\u043b\u0435\u0432\u043e",xml_pi:"XML declaration",encoding:"\u041a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430",appearance_bgprops:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0444\u043e\u043d\u0430",appearance_marginprops:"\u041e\u0442\u0441\u0442\u0443\u043f\u044b",appearance_linkprops:"\u0426\u0432\u0435\u0442 \u0441\u0441\u044b\u043b\u043e\u043a",appearance_textprops:"\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0442\u0435\u043a\u0441\u0442\u0430",bgcolor:"\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430",bgimage:"\u0424\u043e\u043d\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435",left_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u043b\u0435\u0432\u0430",right_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u043f\u0440\u0430\u0432\u0430",top_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u0432\u0435\u0440\u0445\u0443",bottom_margin:"\u041e\u0442\u0441\u0442\u0443\u043f \u0441\u043d\u0438\u0437\u0443",text_color:"\u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430",font_size:"\u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430",font_face:"\u0428\u0440\u0438\u0444\u0442",link_color:"\u0426\u0432\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438",hover_color:"\u0426\u0432\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0438",visited_color:"\u0426\u0432\u0435\u0442 \u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0438",active_color:"\u0426\u0432\u0435\u0442 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0438",textcolor:"\u0426\u0432\u0435\u0442",fontsize:"\u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430",fontface:"\u0421\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u0448\u0440\u0438\u0444\u0442\u0430",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don \\ \'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"\u0421\u0442\u0438\u043b\u044c",author:"\u0410\u0432\u0442\u043e\u0440",copyright:"\u041a\u043e\u043f\u0438\u0440\u0430\u0439\u0442",add:"\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",remove:"\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442",moveup:"\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u0432\u0435\u0440\u0445",movedown:"\u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u043d\u0438\u0437",head_elements:"Head elements",info:"\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta \u044d\u043b\u0435\u043c\u0435\u043d\u0442",comment_element:"\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439",src:"Src",language:"\u042f\u0437\u044b\u043a",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435",value:"\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435",content:"\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"\u041e\u0431\u0449\u0435\u0435",advanced_props:"\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/bs_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000440611526350530033752 0ustar frankiefrankietinyMCE.addI18n('bs.fullpage_dlg',{title:"Svojstva dokumenta",meta_tab:"Osnovno",appearance_tab:"Izgled",advanced_tab:"Napredno",meta_props:"Meta informacije",langprops:"Jezik i kodiranje",meta_title:"Naslov",meta_keywords:"Klju\u010dne rije\u010di",meta_description:"Opis",meta_robots:"Robots",doctypes:"Doctype",langcode:"Kod jezika",langdir:"Smjer jezika",ltr:"S lijeva na desno",rtl:"S desna na lijevo",xml_pi:"XML deklaracija",encoding:"Kodiranje znakova",appearance_bgprops:"Svojstva pozadine",appearance_marginprops:"Margina",appearance_linkprops:"Boja poveznica",appearance_textprops:"Svojstva teksta",bgcolor:"Boja pozadine",bgimage:"Pozadinska slika",left_margin:"Lijeva margina",right_margin:"Desna margina",top_margin:"Gornja margina",bottom_margin:"Donja margina",text_color:"Boja teksta",font_size:"Veli\u010dina pisma",font_face:"Pismo",link_color:"Boja poveznice",hover_color:"Boja poveznice ispod mi\u0161a",visited_color:"Boja posje\u0107ene poveznice",active_color:"Boja aktivne poveznice",textcolor:"Boja",fontsize:"Veli\u010dina pisma",fontface:"Skupina pisama",meta_index_follow:"Indeksiraj i slijedi poveznice",meta_index_nofollow:"Indeksiraj i ne slijedi poveznice",meta_noindex_follow:"Ne indeksiraj i slijedi poveznice",meta_noindex_nofollow:"Ne indeksiraj i ne slijedi poveznice",appearance_style:"CSS i svojstva stila",stylesheet:"CSS",style:"Stil",author:"Autor",copyright:"Autorska prava",add:"Dodaj novi element",remove:"Ukloni odabrani element",moveup:"Pomakni odabrani element prema gore",movedown:"Pomakni odabrani element prema dolje",head_elements:"Zaglavni elementi",info:"Informacije",add_title:"Naslovni element",add_meta:"Meta element",add_script:"Skriptni element",add_style:"Sitlski element",add_link:"Element poveznice",add_base:"Osnovni element",add_comment:"Komentar",title_element:"Naslovni element",script_element:"Skriptni element",style_element:"Stilski element",base_element:"Osnovni element",link_element:"Element poveznice",meta_element:"Meta element",comment_element:"Komentar",src:"Src",language:"Jezik",href:"Href",target:"Meta",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Svojstva",name:"Ime",value:"Vrijednost",content:"Sadr\u017eaj",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"Osnovno",advanced_props:"Napredno"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/uk_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000001564711526350530033763 0ustar frankiefrankietinyMCE.addI18n('uk.fullpage_dlg',{title:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430",meta_tab:"\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0435",appearance_tab:"\u0412\u0438\u0433\u043b\u044f\u0434",advanced_tab:"\u0414\u043e\u0434\u0430\u0442\u043a\u043e\u0432\u043e",meta_props:"\u041c\u0435\u0442\u0430 \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044f",langprops:"\u041c\u043e\u0432\u0430 \u0442\u0430 \u043a\u043e\u0434\u0443\u0432\u0430\u043d\u043d\u044f",meta_title:"\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a",meta_keywords:"\u041a\u043b\u044e\u0447\u043e\u0432\u0456 \u0441\u043b\u043e\u0432\u0430",meta_description:"\u041e\u043f\u0438\u0441",meta_robots:"\u0420\u043e\u0431\u043e\u0442\u0438",doctypes:"Doctype",langcode:"\u041a\u043e\u0434 \u043c\u043e\u0432\u0438",langdir:"\u041d\u0430\u043f\u0440\u044f\u043c \u043c\u043e\u0432\u0438",ltr:"\u0417\u043b\u0456\u0432\u0430 \u043f\u0440\u0430\u0432\u043e\u0440\u0443\u0447",rtl:"\u0421\u043f\u0440\u0430\u0432\u0430 \u043b\u0456\u0432\u043e\u0440\u0443\u0447",xml_pi:"\u041e\u0431\'\u044f\u0432\u043b\u0435\u043d\u043d\u044f XML",encoding:"\u041a\u043e\u0434\u0443\u0432\u0430\u043d\u043d\u044f \u0441\u0438\u043c\u0432\u043e\u043b\u0456\u0432",appearance_bgprops:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0444\u043e\u043d\u0443",appearance_marginprops:"\u0412\u0456\u0434\u0441\u0442\u0443\u043f\u0438",appearance_linkprops:"\u041a\u043e\u043b\u0456\u0440 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u044c",appearance_textprops:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0442\u0435\u043a\u0441\u0442\u0443",bgcolor:"\u041a\u043e\u043b\u0456\u0440 \u0444\u043e\u043d\u0443",bgimage:"\u0424\u043e\u043d\u043e\u0432\u0435 \u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044f",left_margin:"\u0412\u0456\u0434\u0441\u0442\u0443\u043f \u0437\u043b\u0456\u0432\u0430",right_margin:"\u0412\u0456\u0434\u0441\u0442\u0443\u043f \u0441\u043f\u0440\u0430\u0432\u0430",top_margin:"\u0412\u0456\u0434\u0441\u0442\u0443\u043f \u0437\u0432\u0435\u0440\u0445\u0443",bottom_margin:"\u0412\u0456\u0434\u0441\u0442\u0443\u043f \u0437\u043d\u0438\u0437\u0443",text_color:"\u041a\u043e\u043b\u0456\u0440 \u0442\u0435\u043a\u0441\u0442\u0443",font_size:"\u0420\u043e\u0437\u043c\u0456\u0440 \u0448\u0440\u0438\u0444\u0442\u0430",font_face:"\u0428\u0440\u0438\u0444\u0442",link_color:"\u041a\u043e\u043b\u0456\u0440 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",hover_color:"\u041a\u043e\u043b\u0456\u0440 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u043d\u0456",visited_color:"\u041a\u043e\u043b\u0456\u0440 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f \u043f\u0440\u0438 \u043d\u0430\u0442\u0438\u0441\u043d\u0435\u043d\u043d\u0456",active_color:"\u041a\u043e\u043b\u0456\u0440 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",textcolor:"\u041a\u043e\u043b\u0456\u0440",fontsize:"\u0420\u043e\u0437\u043c\u0456\u0440 \u0448\u0440\u0438\u0444\u0442\u0430",fontface:"\u0421\u0456\u043c\u0435\u0439\u0441\u0442\u0432\u043e \u0448\u0440\u0438\u0444\u0442\u0430",meta_index_follow:"\u0406\u043d\u0434\u0435\u043a\u0441\u0443\u0432\u0430\u0442\u0438 \u0456 \u0439\u0442\u0438 \u0437\u0430 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f\u043c\u0438",meta_index_nofollow:"\u0406\u043d\u0434\u0435\u043a\u0441\u0443\u0432\u0430\u0442\u0438 \u0456 \u043d\u0435 \u0439\u0442\u0438 \u0437\u0430 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f\u043c\u0438",meta_noindex_follow:"\u041d\u0435 \u0456\u043d\u0434\u0435\u043a\u0441\u0443\u0432\u0430\u0442\u0438, \u0430\u043b\u0435 \u0439\u0442\u0438 \u0437\u0430 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f\u043c\u0438",meta_noindex_nofollow:"\u041d\u0435 \u0456\u043d\u0434\u0435\u043a\u0441\u0443\u0432\u0430\u0442\u0438 \u0456 \u043d\u0435 \u0439\u0442\u0438 \u0437\u0430 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f\u043c\u0438",appearance_style:"\u0422\u0430\u0431\u043b\u0438\u0446\u044f \u0441\u0442\u0438\u043b\u044e \u0442\u0430 \u0432\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456 \u0441\u0442\u0438\u043b\u044e",stylesheet:"\u0422\u0430\u0431\u043b\u0438\u0446\u044f \u0441\u0442\u0438\u043b\u044e",style:"\u0421\u0442\u0438\u043b\u044c",author:"\u0410\u0432\u0442\u043e\u0440",copyright:"\u0410\u0432\u0442\u043e\u0440\u0441\u044c\u043a\u0435 \u043f\u0440\u0430\u0432\u043e",add:"\u0414\u043e\u0434\u0430\u0442\u0438 \u043d\u043e\u0432\u0438\u0439 \u0435\u043b\u0435\u043c\u0435\u043d\u0442",remove:"\u0412\u0438\u0434\u0430\u043b\u0438\u0442\u0438 \u0432\u0438\u0434\u0456\u043b\u0435\u043d\u0438\u0439 \u0435\u043b\u0435\u043c\u0435\u043d\u0442",moveup:"\u041f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0438\u0442\u0438 \u0435\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u0433\u043e\u0440\u0443",movedown:"\u041f\u0435\u0440\u0435\u043c\u0456\u0441\u0442\u0438\u0442\u0438 \u0435\u043b\u0435\u043c\u0435\u043d\u0442 \u0432\u043d\u0438\u0437",head_elements:"Head \u0435\u043b\u0435\u043c\u0435\u043d\u0442\u0438",info:"\u0406\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044f",add_title:"Title \u0435\u043b\u0435\u043c\u0435\u043d\u0442",add_meta:"Meta \u0435\u043b\u0435\u043c\u0435\u043d\u0442",add_script:"Script \u0435\u043b\u0435\u043c\u0435\u043d\u0442",add_style:"Style \u0435\u043b\u0435\u043c\u0435\u043d\u0442",add_link:"Link \u0435\u043b\u0435\u043c\u0435\u043d\u0442",add_base:"Base \u0435\u043b\u0435\u043c\u0435\u043d\u0442",add_comment:"\u0412\u0443\u0437\u043e\u043b \u043a\u043e\u043c\u0435\u043d\u0442\u0430\u0440\u044f",title_element:"Title \u0435\u043b\u0435\u043c\u0435\u043d\u0442",script_element:"Script \u0435\u043b\u0435\u043c\u0435\u043d\u0442",style_element:"Style \u0435\u043b\u0435\u043c\u0435\u043d\u0442",base_element:"Base \u0435\u043b\u0435\u043c\u0435\u043d\u0442",link_element:"Link \u0435\u043b\u0435\u043c\u0435\u043d\u0442",meta_element:"Meta \u0435\u043b\u0435\u043c\u0435\u043d\u0442",comment_element:"\u041a\u043e\u043c\u0435\u043d\u0442\u0430\u0440",src:"\u0414\u0436\u0435\u0440\u0435\u043b\u043e",language:"\u041c\u043e\u0432\u0430",href:"\u041f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",target:"\u0426\u0456\u043b\u044c",type:"\u0422\u0438\u043f",charset:"\u041a\u043e\u0434\u0443\u0432\u0430\u043d\u043d\u044f",defer:"Defer",media:"\u041c\u0435\u0434\u0456\u0430",properties:"\u0412\u043b\u0430\u0441\u0442\u0438\u0432\u043e\u0441\u0442\u0456",name:"\u041d\u0430\u0437\u0432\u0430",value:"\u0417\u043d\u0430\u0447\u0435\u043d\u043d\u044f",content:"\u0417\u043c\u0456\u0441\u0442",rel:"\u0417\u0432\'\u044f\u0437\u043e\u043a",rev:"Rev",hreflang:"\u041c\u043e\u0432\u0430 \u043f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f",general_props:"\u0417\u0430\u0433\u0430\u043b\u044c\u043d\u0435",advanced_props:"\u0414\u043e\u0434\u0430\u0442\u043a\u043e\u0432\u043e"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/gu_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('gu.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/ps_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000423411526350530033751 0ustar frankiefrankietinyMCE.addI18n('ps.fullpage_dlg',{title:"Document properties",meta_tab:"General",appearance_tab:"Appearance",advanced_tab:"Advanced",meta_props:"Meta information",langprops:"Language and encoding",meta_title:"Title",meta_keywords:"Keywords",meta_description:"Description",meta_robots:"Robots",doctypes:"Doctype",langcode:"Language code",langdir:"Language direction",ltr:"Left to right",rtl:"Right to left",xml_pi:"XML declaration",encoding:"Character encoding",appearance_bgprops:"Background properties",appearance_marginprops:"Body margins",appearance_linkprops:"Link colors",appearance_textprops:"Text properties",bgcolor:"Background color",bgimage:"Background image",left_margin:"Left margin",right_margin:"Right margin",top_margin:"Top margin",bottom_margin:"Bottom margin",text_color:"Text color",font_size:"Font size",font_face:"Font face",link_color:"Link color",hover_color:"Hover color",visited_color:"Visited color",active_color:"Active color",textcolor:"Color",fontsize:"Font size",fontface:"Font family",meta_index_follow:"Index and follow the links",meta_index_nofollow:"Index and don\'t follow the links",meta_noindex_follow:"Do not index but follow the links",meta_noindex_nofollow:"Do not index and don\\\'t follow the links",appearance_style:"Stylesheet and style properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add new element",remove:"Remove selected element",moveup:"Move selected element up",movedown:"Move selected element down",head_elements:"Head elements",info:"Information",add_title:"Title element",add_meta:"Meta element",add_script:"Script element",add_style:"Style element",add_link:"Link element",add_base:"Base element",add_comment:"Comment node",title_element:"Title element",script_element:"Script element",style_element:"Style element",base_element:"Base element",link_element:"Link element",meta_element:"Meta element",comment_element:"Comment",src:"Src",language:"Language",href:"Href",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"Href lang",general_props:"General",advanced_props:"Advanced"});././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs/zh_dlg.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/langs0000644000175000017500000000523511526350530033753 0ustar frankiefrankietinyMCE.addI18n('zh.fullpage_dlg',{title:"\u6863\u6848\u5c5e\u6027",meta_tab:"\u6807\u51c6",appearance_tab:"\u5916\u89c2",advanced_tab:"\u9ad8\u7ea7",meta_props:"Mata\u8baf\u606f",langprops:"\u8bed\u8a00\u7f16\u7801",meta_title:"\u6807\u9898",meta_keywords:"\u5173\u952e\u5b57",meta_description:"\u8bf4\u660e",meta_robots:"Robots",doctypes:"DocType",langcode:"\u6587\u5b57\u7f16\u7801",langdir:"\u6587\u5b57\u4e66\u5199\u65b9\u5411",ltr:"\u4ece\u5de6\u5230\u53f3",rtl:"\u4ece\u53f3\u5230\u5de6",xml_pi:"XML\u58f0\u660e",encoding:"\u8bed\u8a00\u7f16\u7801",appearance_bgprops:"\u80cc\u666f\u989c\u8272",appearance_marginprops:"\u8fb9\u8ddd",appearance_linkprops:"\u8d85\u8fde\u7ed3\u989c\u8272",appearance_textprops:"\u6587\u5b57\u5c5e\u6027",bgcolor:"\u80cc\u666f\u989c\u8272",bgimage:"\u80cc\u666f\u56fe\u7247",left_margin:"\u5de6\u8fb9\u8ddd",right_margin:"\u53f3\u8fb9\u8ddd",top_margin:"\u4e0a\u8fb9\u8ddd",bottom_margin:"\u4e0b\u8fb9\u8ddd",text_color:"\u6587\u5b57\u989c\u8272",font_size:"\u6587\u5b57\u5927\u5c0f",font_face:"\u5b57\u4f53",link_color:"\u8d85\u8fde\u7ed3\u989c\u8272",hover_color:"Hover \u989c\u8272",visited_color:"Visited \u989c\u8272",active_color:"Active \u989c\u8272",textcolor:"\u989c\u8272",fontsize:"\u6587\u5b57\u5927\u5c0f",fontface:"\u5b57\u4f53",meta_index_follow:"\u7d22\u5f15\u5e76\u8fde\u7ed3",meta_index_nofollow:"\u7d22\u5f15\u4f46\u4e0d\u8fde\u7ed3",meta_noindex_follow:"\u4e0d\u7d22\u5f15\u4f46\u8fde\u7ed3",meta_noindex_nofollow:"\u4e0d\u7d22\u5f15\u4e5f\u4e0d\u8fde\u7ed3",appearance_style:"\u6837\u5f0f\u5217\u8868\u4e0e\u6837\u5f0f\u5c5e\u6027",stylesheet:"\u6837\u5f0f\u5217\u8868",style:"\u6837\u5f0f",author:"\u4f5c\u8005",copyright:"\u7248\u6743\u58f0\u660e",add:"\u65b0\u589e\u5143\u7d20",remove:"\u5220\u9664\u9009\u62e9\u5143\u7d20",moveup:"\u4e0a\u79fb\u9009\u62e9\u5143\u7d20",movedown:"\u4e0b\u79fb\u9009\u62e9\u5143\u7d20",head_elements:"Head \u5143\u7d20",info:"\u4fe1\u606f",add_title:"Title \u5143\u7d20",add_meta:"Meta \u5143\u7d20",add_script:"Script \u5143\u7d20",add_style:"Style \u5143\u7d20",add_link:"Link \u5143\u7d20",add_base:"Base \u5143\u7d20",add_comment:"\u8a3b\u91ca",title_element:"Title \u5143\u7d20",script_element:"Script \u5143\u7d20",style_element:"Style \u5143\u7d20",base_element:"Base \u5143\u7d20",link_element:"Link \u5143\u7d20",meta_element:"Meta \u5143\u7d20",comment_element:"\u8a3b\u91ca",src:"src",language:"\u8bed\u8a00",href:"href",target:"\u76ee\u6807",type:"\u7c7b\u578b",charset:"\u5b57\u7b26\u96c6",defer:"Defer",media:"\u5f71\u7247",properties:"\u5c5e\u6027",name:"\u540d\u79f0",value:"\u503c",content:"\u5185\u5bb9",rel:"rel",rev:"rev",hreflang:"href lang",general_props:"\u6807\u51c6",advanced_props:"\u9ad8\u7ea7"});././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/editor_plugin_src.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/fullpage/edito0000644000175000017500000001055611526350527033763 0ustar frankiefrankie/** * editor_plugin_src.js * * Copyright 2009, Moxiecode Systems AB * Released under LGPL License. * * License: http://tinymce.moxiecode.com/license * Contributing: http://tinymce.moxiecode.com/contributing */ (function() { tinymce.create('tinymce.plugins.FullPagePlugin', { init : function(ed, url) { var t = this; t.editor = ed; // Register commands ed.addCommand('mceFullPageProperties', function() { ed.windowManager.open({ file : url + '/fullpage.htm', width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)), height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)), inline : 1 }, { plugin_url : url, head_html : t.head }); }); // Register buttons ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'}); ed.onBeforeSetContent.add(t._setContent, t); ed.onSetContent.add(t._setBodyAttribs, t); ed.onGetContent.add(t._getContent, t); }, getInfo : function() { return { longname : 'Fullpage', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage', version : tinymce.majorVersion + "." + tinymce.minorVersion }; }, // Private plugin internal methods _setBodyAttribs : function(ed, o) { var bdattr, i, len, kv, k, v, t, attr = this.head.match(/body(.*?)>/i); if (attr && attr[1]) { bdattr = attr[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g); if (bdattr) { for(i = 0, len = bdattr.length; i < len; i++) { kv = bdattr[i].split('='); k = kv[0].replace(/\s/,''); v = kv[1]; if (v) { v = v.replace(/^\s+/,'').replace(/\s+$/,''); t = v.match(/^["'](.*)["']$/); if (t) v = t[1]; } else v = k; ed.dom.setAttrib(ed.getBody(), 'style', v); } } } }, _createSerializer : function() { return new tinymce.dom.Serializer({ dom : this.editor.dom, apply_source_formatting : true }); }, _setContent : function(ed, o) { var t = this, sp, ep, c = o.content, v, st = ''; // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate if (o.format == 'raw' && t.head) return; if (o.source_view && ed.getParam('fullpage_hide_in_source_view')) return; // Parse out head, body and footer c = c.replace(/<(\/?)BODY/gi, '<$1body'); sp = c.indexOf('', sp); t.head = c.substring(0, sp + 1); ep = c.indexOf('\n'; t.head += ed.getParam('fullpage_default_doctype', ''); t.head += '\n\n\n' + ed.getParam('fullpage_default_title', 'Untitled document') + '\n'; if (v = ed.getParam('fullpage_default_encoding')) t.head += '\n'; if (v = ed.getParam('fullpage_default_font_family')) st += 'font-family: ' + v + ';'; if (v = ed.getParam('fullpage_default_font_size')) st += 'font-size: ' + v + ';'; if (v = ed.getParam('fullpage_default_text_color')) st += 'color: ' + v + ';'; t.head += '\n\n'; t.foot = '\n\n'; } }, _getContent : function(ed, o) { var t = this; if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view')) o.content = tinymce.trim(t.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(t.foot); } }); // Register plugin tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin); })();openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/advhr/0000755000175000017500000000000011724401447032230 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/advhr/js/0000755000175000017500000000000011724401447032644 5ustar frankiefrankie././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/advhr/js/rule.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/advhr/js/rule.0000644000175000017500000000245211201067035033606 0ustar frankiefrankievar AdvHRDialog = { init : function(ed) { var dom = ed.dom, f = document.forms[0], n = ed.selection.getNode(), w; w = dom.getAttrib(n, 'width'); f.width.value = w ? parseInt(w) : (dom.getStyle('width') || ''); f.size.value = dom.getAttrib(n, 'size') || parseInt(dom.getStyle('height')) || ''; f.noshade.checked = !!dom.getAttrib(n, 'noshade') || !!dom.getStyle('border-width'); selectByValue(f, 'width2', w.indexOf('%') != -1 ? '%' : 'px'); }, update : function() { var ed = tinyMCEPopup.editor, h, f = document.forms[0], st = ''; h = ' {#advhr.advhr_desc}
    openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/layer/0000755000175000017500000000000011724401447032240 5ustar frankiefrankie././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/layer/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/layer/editor_p0000644000175000017500000000655011201073571033767 0ustar frankiefrankie(function(){tinymce.create("tinymce.plugins.Layer",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceInsertLayer",c._insertLayer,c);a.addCommand("mceMoveForward",function(){c._move(1)});a.addCommand("mceMoveBackward",function(){c._move(-1)});a.addCommand("mceMakeAbsolute",function(){c._toggleAbsolute()});a.addButton("moveforward",{title:"layer.forward_desc",cmd:"mceMoveForward"});a.addButton("movebackward",{title:"layer.backward_desc",cmd:"mceMoveBackward"});a.addButton("absolute",{title:"layer.absolute_desc",cmd:"mceMakeAbsolute"});a.addButton("insertlayer",{title:"layer.insertlayer_desc",cmd:"mceInsertLayer"});a.onInit.add(function(){if(tinymce.isIE){a.getDoc().execCommand("2D-Position",false,true)}});a.onNodeChange.add(c._nodeChange,c);a.onVisualAid.add(c._visualAid,c)},getInfo:function(){return{longname:"Layer",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(b,a,e){var c,d;c=this._getParentLayer(e);d=b.dom.getParent(e,"DIV,P,IMG");if(!d){a.setDisabled("absolute",1);a.setDisabled("moveforward",1);a.setDisabled("movebackward",1)}else{a.setDisabled("absolute",0);a.setDisabled("moveforward",!c);a.setDisabled("movebackward",!c);a.setActive("absolute",c&&c.style.position.toLowerCase()=="absolute")}},_visualAid:function(a,c,b){var d=a.dom;tinymce.each(d.select("div,p",c),function(f){if(/^(absolute|relative|static)$/i.test(f.style.position)){if(b){d.addClass(f,"mceItemVisualAid")}else{d.removeClass(f,"mceItemVisualAid")}}})},_move:function(h){var b=this.editor,f,g=[],e=this._getParentLayer(b.selection.getNode()),c=-1,j=-1,a;a=[];tinymce.walk(b.getBody(),function(d){if(d.nodeType==1&&/^(absolute|relative|static)$/i.test(d.style.position)){a.push(d)}},"childNodes");for(f=0;f-1){a[c].style.zIndex=g[j];a[j].style.zIndex=g[c]}else{if(g[c]>0){a[c].style.zIndex=g[c]-1}}}else{for(f=0;fg[c]){j=f;break}}if(j>-1){a[c].style.zIndex=g[j];a[j].style.zIndex=g[c]}else{a[c].style.zIndex=g[c]+1}}b.execCommand("mceRepaint")},_getParentLayer:function(a){return this.editor.dom.getParent(a,function(b){return b.nodeType==1&&/^(absolute|relative|static)$/i.test(b.style.position)})},_insertLayer:function(){var a=this.editor,b=a.dom.getPos(a.dom.getParent(a.selection.getNode(),"*"));a.dom.add(a.getBody(),"div",{style:{position:"absolute",left:b.x,top:(b.y>20?b.y:20),width:100,height:100},"class":"mceItemVisualAid"},a.selection.getContent()||a.getLang("layer.content"))},_toggleAbsolute:function(){var a=this.editor,b=this._getParentLayer(a.selection.getNode());if(!b){b=a.dom.getParent(a.selection.getNode(),"DIV,P,IMG")}if(b){if(b.style.position.toLowerCase()=="absolute"){a.dom.setStyles(b,{position:"",left:"",top:"",width:"",height:""});a.dom.removeClass(b,"mceItemVisualAid")}else{if(b.style.left==""){b.style.left=20+"px"}if(b.style.top==""){b.style.top=20+"px"}if(b.style.width==""){b.style.width=b.width?(b.width+"px"):"100px"}if(b.style.height==""){b.style.height=b.height?(b.height+"px"):"100px"}b.style.position="absolute";a.addVisual(a.getBody())}a.execCommand("mceRepaint");a.nodeChanged()}}});tinymce.PluginManager.add("layer",tinymce.plugins.Layer)})();././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/layer/editor_plugin_src.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/layer/editor_p0000644000175000017500000001227711526350530033775 0ustar frankiefrankie/** * editor_plugin_src.js * * Copyright 2009, Moxiecode Systems AB * Released under LGPL License. * * License: http://tinymce.moxiecode.com/license * Contributing: http://tinymce.moxiecode.com/contributing */ (function() { tinymce.create('tinymce.plugins.Layer', { init : function(ed, url) { var t = this; t.editor = ed; // Register commands ed.addCommand('mceInsertLayer', t._insertLayer, t); ed.addCommand('mceMoveForward', function() { t._move(1); }); ed.addCommand('mceMoveBackward', function() { t._move(-1); }); ed.addCommand('mceMakeAbsolute', function() { t._toggleAbsolute(); }); // Register buttons ed.addButton('moveforward', {title : 'layer.forward_desc', cmd : 'mceMoveForward'}); ed.addButton('movebackward', {title : 'layer.backward_desc', cmd : 'mceMoveBackward'}); ed.addButton('absolute', {title : 'layer.absolute_desc', cmd : 'mceMakeAbsolute'}); ed.addButton('insertlayer', {title : 'layer.insertlayer_desc', cmd : 'mceInsertLayer'}); ed.onInit.add(function() { if (tinymce.isIE) ed.getDoc().execCommand('2D-Position', false, true); }); ed.onNodeChange.add(t._nodeChange, t); ed.onVisualAid.add(t._visualAid, t); }, getInfo : function() { return { longname : 'Layer', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer', version : tinymce.majorVersion + "." + tinymce.minorVersion }; }, // Private methods _nodeChange : function(ed, cm, n) { var le, p; le = this._getParentLayer(n); p = ed.dom.getParent(n, 'DIV,P,IMG'); if (!p) { cm.setDisabled('absolute', 1); cm.setDisabled('moveforward', 1); cm.setDisabled('movebackward', 1); } else { cm.setDisabled('absolute', 0); cm.setDisabled('moveforward', !le); cm.setDisabled('movebackward', !le); cm.setActive('absolute', le && le.style.position.toLowerCase() == "absolute"); } }, // Private methods _visualAid : function(ed, e, s) { var dom = ed.dom; tinymce.each(dom.select('div,p', e), function(e) { if (/^(absolute|relative|static)$/i.test(e.style.position)) { if (s) dom.addClass(e, 'mceItemVisualAid'); else dom.removeClass(e, 'mceItemVisualAid'); } }); }, _move : function(d) { var ed = this.editor, i, z = [], le = this._getParentLayer(ed.selection.getNode()), ci = -1, fi = -1, nl; nl = []; tinymce.walk(ed.getBody(), function(n) { if (n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position)) nl.push(n); }, 'childNodes'); // Find z-indexes for (i=0; i -1) { nl[ci].style.zIndex = z[fi]; nl[fi].style.zIndex = z[ci]; } else { if (z[ci] > 0) nl[ci].style.zIndex = z[ci] - 1; } } else { // Move forward // Try find a higher one for (i=0; i z[ci]) { fi = i; break; } } if (fi > -1) { nl[ci].style.zIndex = z[fi]; nl[fi].style.zIndex = z[ci]; } else nl[ci].style.zIndex = z[ci] + 1; } ed.execCommand('mceRepaint'); }, _getParentLayer : function(n) { return this.editor.dom.getParent(n, function(n) { return n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position); }); }, _insertLayer : function() { var ed = this.editor, p = ed.dom.getPos(ed.dom.getParent(ed.selection.getNode(), '*')); ed.dom.add(ed.getBody(), 'div', { style : { position : 'absolute', left : p.x, top : (p.y > 20 ? p.y : 20), width : 100, height : 100 }, 'class' : 'mceItemVisualAid' }, ed.selection.getContent() || ed.getLang('layer.content')); }, _toggleAbsolute : function() { var ed = this.editor, le = this._getParentLayer(ed.selection.getNode()); if (!le) le = ed.dom.getParent(ed.selection.getNode(), 'DIV,P,IMG'); if (le) { if (le.style.position.toLowerCase() == "absolute") { ed.dom.setStyles(le, { position : '', left : '', top : '', width : '', height : '' }); ed.dom.removeClass(le, 'mceItemVisualAid'); } else { if (le.style.left == "") le.style.left = 20 + 'px'; if (le.style.top == "") le.style.top = 20 + 'px'; if (le.style.width == "") le.style.width = le.width ? (le.width + 'px') : '100px'; if (le.style.height == "") le.style.height = le.height ? (le.height + 'px') : '100px'; le.style.position = "absolute"; ed.addVisual(ed.getBody()); } ed.execCommand('mceRepaint'); ed.nodeChanged(); } } }); // Register plugin tinymce.PluginManager.add('layer', tinymce.plugins.Layer); })();openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/0000755000175000017500000000000011724401447032203 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/js/0000755000175000017500000000000011724401447032617 5ustar frankiefrankie././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/js/embed.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/js/embed0000644000175000017500000000362211201067037033612 0ustar frankiefrankie/** * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose. */ function writeFlash(p) { writeEmbed( 'D27CDB6E-AE6D-11cf-96B8-444553540000', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', 'application/x-shockwave-flash', p ); } function writeShockWave(p) { writeEmbed( '166B1BCA-3F9C-11CF-8075-444553540000', 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0', 'application/x-director', p ); } function writeQuickTime(p) { writeEmbed( '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B', 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0', 'video/quicktime', p ); } function writeRealMedia(p) { writeEmbed( 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', 'audio/x-pn-realaudio-plugin', p ); } function writeWindowsMedia(p) { p.url = p.src; writeEmbed( '6BF52A52-394A-11D3-B153-00C04F79FAA6', 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701', 'application/x-mplayer2', p ); } function writeEmbed(cls, cb, mt, p) { var h = '', n; h += ''; h += ''); function init() { var pl = "", f, val; var type = "flash", fe, i; ed = tinyMCEPopup.editor; tinyMCEPopup.resizeToInnerSize(); f = document.forms[0] fe = ed.selection.getNode(); if (/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(ed.dom.getAttrib(fe, 'class'))) { pl = fe.title; switch (ed.dom.getAttrib(fe, 'class')) { case 'mceItemFlash': type = 'flash'; break; case 'mceItemFlashVideo': type = 'flv'; break; case 'mceItemShockWave': type = 'shockwave'; break; case 'mceItemWindowsMedia': type = 'wmp'; break; case 'mceItemQuickTime': type = 'qt'; break; case 'mceItemRealMedia': type = 'rmp'; break; } document.forms[0].insert.value = ed.getLang('update', 'Insert', true); } document.getElementById('filebrowsercontainer').innerHTML = getBrowserHTML('filebrowser','src','media','media'); document.getElementById('qtsrcfilebrowsercontainer').innerHTML = getBrowserHTML('qtsrcfilebrowser','qt_qtsrc','media','media'); document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor'); var html = getMediaListHTML('medialist','src','media','media'); if (html == "") document.getElementById("linklistrow").style.display = 'none'; else document.getElementById("linklistcontainer").innerHTML = html; // Resize some elements if (isVisible('filebrowser')) document.getElementById('src').style.width = '230px'; // Setup form if (pl != "") { pl = tinyMCEPopup.editor.plugins.media._parse(pl); switch (type) { case "flash": setBool(pl, 'flash', 'play'); setBool(pl, 'flash', 'loop'); setBool(pl, 'flash', 'menu'); setBool(pl, 'flash', 'swliveconnect'); setStr(pl, 'flash', 'quality'); setStr(pl, 'flash', 'scale'); setStr(pl, 'flash', 'salign'); setStr(pl, 'flash', 'wmode'); setStr(pl, 'flash', 'base'); setStr(pl, 'flash', 'flashvars'); break; case "qt": setBool(pl, 'qt', 'loop'); setBool(pl, 'qt', 'autoplay'); setBool(pl, 'qt', 'cache'); setBool(pl, 'qt', 'controller'); setBool(pl, 'qt', 'correction'); setBool(pl, 'qt', 'enablejavascript'); setBool(pl, 'qt', 'kioskmode'); setBool(pl, 'qt', 'autohref'); setBool(pl, 'qt', 'playeveryframe'); setBool(pl, 'qt', 'tarsetcache'); setStr(pl, 'qt', 'scale'); setStr(pl, 'qt', 'starttime'); setStr(pl, 'qt', 'endtime'); setStr(pl, 'qt', 'tarset'); setStr(pl, 'qt', 'qtsrcchokespeed'); setStr(pl, 'qt', 'volume'); setStr(pl, 'qt', 'qtsrc'); break; case "shockwave": setBool(pl, 'shockwave', 'sound'); setBool(pl, 'shockwave', 'progress'); setBool(pl, 'shockwave', 'autostart'); setBool(pl, 'shockwave', 'swliveconnect'); setStr(pl, 'shockwave', 'swvolume'); setStr(pl, 'shockwave', 'swstretchstyle'); setStr(pl, 'shockwave', 'swstretchhalign'); setStr(pl, 'shockwave', 'swstretchvalign'); break; case "wmp": setBool(pl, 'wmp', 'autostart'); setBool(pl, 'wmp', 'enabled'); setBool(pl, 'wmp', 'enablecontextmenu'); setBool(pl, 'wmp', 'fullscreen'); setBool(pl, 'wmp', 'invokeurls'); setBool(pl, 'wmp', 'mute'); setBool(pl, 'wmp', 'stretchtofit'); setBool(pl, 'wmp', 'windowlessvideo'); setStr(pl, 'wmp', 'balance'); setStr(pl, 'wmp', 'baseurl'); setStr(pl, 'wmp', 'captioningid'); setStr(pl, 'wmp', 'currentmarker'); setStr(pl, 'wmp', 'currentposition'); setStr(pl, 'wmp', 'defaultframe'); setStr(pl, 'wmp', 'playcount'); setStr(pl, 'wmp', 'rate'); setStr(pl, 'wmp', 'uimode'); setStr(pl, 'wmp', 'volume'); break; case "rmp": setBool(pl, 'rmp', 'autostart'); setBool(pl, 'rmp', 'loop'); setBool(pl, 'rmp', 'autogotourl'); setBool(pl, 'rmp', 'center'); setBool(pl, 'rmp', 'imagestatus'); setBool(pl, 'rmp', 'maintainaspect'); setBool(pl, 'rmp', 'nojava'); setBool(pl, 'rmp', 'prefetch'); setBool(pl, 'rmp', 'shuffle'); setStr(pl, 'rmp', 'console'); setStr(pl, 'rmp', 'controls'); setStr(pl, 'rmp', 'numloop'); setStr(pl, 'rmp', 'scriptcallbacks'); break; } setStr(pl, null, 'src'); setStr(pl, null, 'id'); setStr(pl, null, 'name'); setStr(pl, null, 'vspace'); setStr(pl, null, 'hspace'); setStr(pl, null, 'bgcolor'); setStr(pl, null, 'align'); setStr(pl, null, 'width'); setStr(pl, null, 'height'); if ((val = ed.dom.getAttrib(fe, "width")) != "") pl.width = f.width.value = val; if ((val = ed.dom.getAttrib(fe, "height")) != "") pl.height = f.height.value = val; oldWidth = pl.width ? parseInt(pl.width) : 0; oldHeight = pl.height ? parseInt(pl.height) : 0; } else oldWidth = oldHeight = 0; selectByValue(f, 'media_type', type); changedType(type); updateColor('bgcolor_pick', 'bgcolor'); TinyMCE_EditableSelects.init(); generatePreview(); } function insertMedia() { var fe, f = document.forms[0], h; tinyMCEPopup.restoreSelection(); if (!AutoValidator.validate(f)) { tinyMCEPopup.alert(ed.getLang('invalid_data')); return false; } f.width.value = f.width.value == "" ? 100 : f.width.value; f.height.value = f.height.value == "" ? 100 : f.height.value; fe = ed.selection.getNode(); if (fe != null && /mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(ed.dom.getAttrib(fe, 'class'))) { switch (f.media_type.options[f.media_type.selectedIndex].value) { case "flash": fe.className = "mceItemFlash"; break; case "flv": fe.className = "mceItemFlashVideo"; break; case "shockwave": fe.className = "mceItemShockWave"; break; case "qt": fe.className = "mceItemQuickTime"; break; case "wmp": fe.className = "mceItemWindowsMedia"; break; case "rmp": fe.className = "mceItemRealMedia"; break; } if (fe.width != f.width.value || fe.height != f.height.value) ed.execCommand('mceRepaint'); fe.title = serializeParameters(); fe.width = f.width.value; fe.height = f.height.value; fe.style.width = f.width.value + (f.width.value.indexOf('%') == -1 ? 'px' : ''); fe.style.height = f.height.value + (f.height.value.indexOf('%') == -1 ? 'px' : ''); fe.align = f.align.options[f.align.selectedIndex].value; } else { h = ' 0) { var html = ""; html += ''; return html; } return ""; } function getType(v) { var fo, i, c, el, x, f = document.forms[0]; fo = ed.getParam("media_types", "flash=swf;flv=flv;shockwave=dcr;qt=mov,qt,mpg,mp3,mp4,mpeg;shockwave=dcr;wmp=avi,wmv,wm,asf,asx,wmx,wvx;rmp=rm,ra,ram").split(';'); // YouTube if (v.match(/watch\?v=(.+)(.*)/)) { f.width.value = '425'; f.height.value = '350'; f.src.value = 'http://www.youtube.com/v/' + v.match(/v=(.*)(.*)/)[0].split('=')[1]; return 'flash'; } // Google video if (v.indexOf('http://video.google.com/videoplay?docid=') == 0) { f.width.value = '425'; f.height.value = '326'; f.src.value = 'http://video.google.com/googleplayer.swf?docId=' + v.substring('http://video.google.com/videoplay?docid='.length) + '&hl=en'; return 'flash'; } for (i=0; i 0 ? s.substring(0, s.length - 1) : s; return s; } function setBool(pl, p, n) { if (typeof(pl[n]) == "undefined") return; document.forms[0].elements[p + "_" + n].checked = pl[n] != 'false'; } function setStr(pl, p, n) { var f = document.forms[0], e = f.elements[(p != null ? p + "_" : '') + n]; if (typeof(pl[n]) == "undefined") return; if (e.type == "text") e.value = pl[n]; else selectByValue(f, (p != null ? p + "_" : '') + n, pl[n]); } function getBool(p, n, d, tv, fv) { var v = document.forms[0].elements[p + "_" + n].checked; tv = typeof(tv) == 'undefined' ? 'true' : "'" + jsEncode(tv) + "'"; fv = typeof(fv) == 'undefined' ? 'false' : "'" + jsEncode(fv) + "'"; return (v == d) ? '' : n + (v ? ':' + tv + ',' : ":\'" + fv + "\',"); } function getStr(p, n, d) { var e = document.forms[0].elements[(p != null ? p + "_" : "") + n]; var v = e.type == "text" ? e.value : e.options[e.selectedIndex].value; if (n == 'src') v = tinyMCEPopup.editor.convertURL(v, 'src', null); return ((n == d || v == '') ? '' : n + ":'" + jsEncode(v) + "',"); } function getInt(p, n, d) { var e = document.forms[0].elements[(p != null ? p + "_" : "") + n]; var v = e.type == "text" ? e.value : e.options[e.selectedIndex].value; return ((n == d || v == '') ? '' : n + ":" + v.replace(/[^0-9]+/g, '') + ","); } function jsEncode(s) { s = s.replace(new RegExp('\\\\', 'g'), '\\\\'); s = s.replace(new RegExp('"', 'g'), '\\"'); s = s.replace(new RegExp("'", 'g'), "\\'"); return s; } function generatePreview(c) { var f = document.forms[0], p = document.getElementById('prev'), h = '', cls, pl, n, type, codebase, wp, hp, nw, nh; p.innerHTML = ''; nw = parseInt(f.width.value); nh = parseInt(f.height.value); if (f.width.value != "" && f.height.value != "") { if (f.constrain.checked) { if (c == 'width' && oldWidth != 0) { wp = nw / oldWidth; nh = Math.round(wp * nh); f.height.value = nh; } else if (c == 'height' && oldHeight != 0) { hp = nh / oldHeight; nw = Math.round(hp * nw); f.width.value = nw; } } } if (f.width.value != "") oldWidth = nw; if (f.height.value != "") oldHeight = nh; // After constrain pl = serializeParameters(); switch (f.media_type.options[f.media_type.selectedIndex].value) { case "flash": cls = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; codebase = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'; type = 'application/x-shockwave-flash'; break; case "shockwave": cls = 'clsid:166B1BCA-3F9C-11CF-8075-444553540000'; codebase = 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0'; type = 'application/x-director'; break; case "qt": cls = 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B'; codebase = 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0'; type = 'video/quicktime'; break; case "wmp": cls = ed.getParam('media_wmp6_compatible') ? 'clsid:05589FA1-C356-11CE-BF01-00AA0055595A' : 'clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6'; codebase = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701'; type = 'application/x-mplayer2'; break; case "rmp": cls = 'clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA'; codebase = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701'; type = 'audio/x-pn-realaudio-plugin'; break; } if (pl == '') { p.innerHTML = ''; return; } pl = tinyMCEPopup.editor.plugins.media._parse(pl); if (!pl.src) { p.innerHTML = ''; return; } pl.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(pl.src); pl.width = !pl.width ? 100 : pl.width; pl.height = !pl.height ? 100 : pl.height; pl.id = !pl.id ? 'obj' : pl.id; pl.name = !pl.name ? 'eobj' : pl.name; pl.align = !pl.align ? '' : pl.align; // Avoid annoying warning about insecure items if (!tinymce.isIE || document.location.protocol != 'https:') { h += ''; for (n in pl) { h += ''; // Add extra url parameter if it's an absolute URL if (n == 'src' && pl[n].indexOf('://') != -1) h += ''; } } h += '))'×=., ? ., B á2%3cB( ýê ì~;././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/img/realmedia.gifopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/img/real0000644000175000017500000000066711201067037033627 0ustar frankiefrankieGIF89a%ÄRPM ÀÚ@Œkű¯®@=;.+)c¢À¿¾Ž¶Õ5x®ÌÌÌÁÖæ‹ŠˆH†¶Vš™™™usq}©Ì$p©£¢¡ÕÕÔÔãîX‘¾äãã êñ÷J“fffÿÿÿ!ù,%ÿà'Žß ¢’…iLÏD 8n²tàYuŽÈD#ux z"  #7S ,V ". ;*?5;" ÂÀ<_« ËË Ë,\¤" !;././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/editor_p0000644000175000017500000001772211526350530033740 0ustar frankiefrankie(function(){var a=tinymce.each;tinymce.create("tinymce.plugins.MediaPlugin",{init:function(b,c){var e=this;e.editor=b;e.url=c;function f(g){return/^(mceItemFlash|mceItemShockWave|mceItemWindowsMedia|mceItemQuickTime|mceItemRealMedia)$/.test(g.className)}b.onPreInit.add(function(){b.serializer.addRules("param[name|value|_mce_value]")});b.addCommand("mceMedia",function(){b.windowManager.open({file:c+"/media.htm",width:430+parseInt(b.getLang("media.delta_width",0)),height:470+parseInt(b.getLang("media.delta_height",0)),inline:1},{plugin_url:c})});b.addButton("media",{title:"media.desc",cmd:"mceMedia"});b.onNodeChange.add(function(h,g,i){g.setActive("media",i.nodeName=="IMG"&&f(i))});b.onInit.add(function(){var g={mceItemFlash:"flash",mceItemShockWave:"shockwave",mceItemWindowsMedia:"windowsmedia",mceItemQuickTime:"quicktime",mceItemRealMedia:"realmedia"};b.selection.onSetContent.add(function(){e._spansToImgs(b.getBody())});b.selection.onBeforeSetContent.add(e._objectsToSpans,e);if(b.settings.content_css!==false){b.dom.loadCSS(c+"/css/content.css")}if(b.theme&&b.theme.onResolveName){b.theme.onResolveName.add(function(h,i){if(i.name=="img"){a(g,function(l,j){if(b.dom.hasClass(i.node,j)){i.name=l;i.title=b.dom.getAttrib(i.node,"title");return false}})}})}if(b&&b.plugins.contextmenu){b.plugins.contextmenu.onContextMenu.add(function(i,h,j){if(j.nodeName=="IMG"&&/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(j.className)){h.add({title:"media.edit",icon:"media",cmd:"mceMedia"})}})}});b.onBeforeSetContent.add(e._objectsToSpans,e);b.onSetContent.add(function(){e._spansToImgs(b.getBody())});b.onPreProcess.add(function(g,i){var h=g.dom;if(i.set){e._spansToImgs(i.node);a(h.select("IMG",i.node),function(k){var j;if(f(k)){j=e._parse(k.title);h.setAttrib(k,"width",h.getAttrib(k,"width",j.width||100));h.setAttrib(k,"height",h.getAttrib(k,"height",j.height||100))}})}if(i.get){a(h.select("IMG",i.node),function(m){var l,j,k;if(g.getParam("media_use_script")){if(f(m)){m.className=m.className.replace(/mceItem/g,"mceTemp")}return}switch(m.className){case"mceItemFlash":l="d27cdb6e-ae6d-11cf-96b8-444553540000";j="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0";k="application/x-shockwave-flash";break;case"mceItemShockWave":l="166b1bca-3f9c-11cf-8075-444553540000";j="http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0";k="application/x-director";break;case"mceItemWindowsMedia":l=g.getParam("media_wmp6_compatible")?"05589fa1-c356-11ce-bf01-00aa0055595a":"6bf52a52-394a-11d3-b153-00c04f79faa6";j="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701";k="application/x-mplayer2";break;case"mceItemQuickTime":l="02bf25d5-8c17-4b23-bc80-d3488abddc6b";j="http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0";k="video/quicktime";break;case"mceItemRealMedia":l="cfcdaa03-8be4-11cf-b84b-0020afbbccfa";j="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0";k="audio/x-pn-realaudio-plugin";break}if(l){h.replace(e._buildObj({classid:l,codebase:j,type:k},m),m)}})}});b.onPostProcess.add(function(g,h){h.content=h.content.replace(/_mce_value=/g,"value=")});function d(g,h){h=new RegExp(h+'="([^"]+)"',"g").exec(g);return h?b.dom.decode(h[1]):""}b.onPostProcess.add(function(g,h){if(g.getParam("media_use_script")){h.content=h.content.replace(/]+>/g,function(j){var i=d(j,"class");if(/^(mceTempFlash|mceTempShockWave|mceTempWindowsMedia|mceTempQuickTime|mceTempRealMedia)$/.test(i)){at=e._parse(d(j,"title"));at.width=d(j,"width");at.height=d(j,"height");j=''; } return im; }); } }); }, getInfo : function() { return { longname : 'Media', author : 'Moxiecode Systems AB', authorurl : 'http://tinymce.moxiecode.com', infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media', version : tinymce.majorVersion + "." + tinymce.minorVersion }; }, // Private methods _objectsToSpans : function(ed, o) { var t = this, h = o.content; h = h.replace(/]*>\s*write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\(\{([^\)]*)\}\);\s*<\/script>/gi, function(a, b, c) { var o = t._parse(c); return '' }); h = h.replace(/]*)>/gi, ''); h = h.replace(/]*)\/?>/gi, ''); h = h.replace(/]*)>/gi, ''); h = h.replace(/<\/(object)([^>]*)>/gi, ''); h = h.replace(/<\/embed>/gi, ''); h = h.replace(/]*)>/gi, function(a, b) {return ''}); h = h.replace(/\/ class=\"mceItemParam\"><\/span>/gi, 'class="mceItemParam">'); o.content = h; }, _buildObj : function(o, n) { var ob, ed = this.editor, dom = ed.dom, p = this._parse(n.title), stc; stc = ed.getParam('media_strict', true) && o.type == 'application/x-shockwave-flash'; p.width = o.width = dom.getAttrib(n, 'width') || 100; p.height = o.height = dom.getAttrib(n, 'height') || 100; if (p.src) p.src = ed.convertURL(p.src, 'src', n); if (stc) { ob = dom.create('span', { id : p.id, _mce_name : 'object', type : 'application/x-shockwave-flash', data : p.src, style : dom.getAttrib(n, 'style'), width : o.width, height : o.height }); } else { ob = dom.create('span', { id : p.id, _mce_name : 'object', classid : "clsid:" + o.classid, style : dom.getAttrib(n, 'style'), codebase : o.codebase, width : o.width, height : o.height }); } each (p, function(v, k) { if (!/^(width|height|codebase|classid|id|_cx|_cy)$/.test(k)) { // Use url instead of src in IE for Windows media if (o.type == 'application/x-mplayer2' && k == 'src' && !p.url) k = 'url'; if (v) dom.add(ob, 'span', {_mce_name : 'param', name : k, '_mce_value' : v}); } }); if (!stc) dom.add(ob, 'span', tinymce.extend({_mce_name : 'embed', type : o.type, style : dom.getAttrib(n, 'style')}, p)); return ob; }, _spansToImgs : function(p) { var t = this, dom = t.editor.dom, im, ci; each(dom.select('span', p), function(n) { // Convert object into image if (dom.getAttrib(n, 'class') == 'mceItemObject') { ci = dom.getAttrib(n, "classid").toLowerCase().replace(/\s+/g, ''); switch (ci) { case 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000': dom.replace(t._createImg('mceItemFlash', n), n); break; case 'clsid:166b1bca-3f9c-11cf-8075-444553540000': dom.replace(t._createImg('mceItemShockWave', n), n); break; case 'clsid:6bf52a52-394a-11d3-b153-00c04f79faa6': case 'clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95': case 'clsid:05589fa1-c356-11ce-bf01-00aa0055595a': dom.replace(t._createImg('mceItemWindowsMedia', n), n); break; case 'clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b': dom.replace(t._createImg('mceItemQuickTime', n), n); break; case 'clsid:cfcdaa03-8be4-11cf-b84b-0020afbbccfa': dom.replace(t._createImg('mceItemRealMedia', n), n); break; default: dom.replace(t._createImg('mceItemFlash', n), n); } return; } // Convert embed into image if (dom.getAttrib(n, 'class') == 'mceItemEmbed') { switch (dom.getAttrib(n, 'type')) { case 'application/x-shockwave-flash': dom.replace(t._createImg('mceItemFlash', n), n); break; case 'application/x-director': dom.replace(t._createImg('mceItemShockWave', n), n); break; case 'application/x-mplayer2': dom.replace(t._createImg('mceItemWindowsMedia', n), n); break; case 'video/quicktime': dom.replace(t._createImg('mceItemQuickTime', n), n); break; case 'audio/x-pn-realaudio-plugin': dom.replace(t._createImg('mceItemRealMedia', n), n); break; default: dom.replace(t._createImg('mceItemFlash', n), n); } } }); }, _createImg : function(cl, n) { var im, dom = this.editor.dom, pa = {}, ti = '', args; args = ['id', 'name', 'width', 'height', 'bgcolor', 'align', 'flashvars', 'src', 'wmode', 'allowfullscreen', 'quality', 'data']; // Create image im = dom.create('img', { src : this.url + '/img/trans.gif', width : dom.getAttrib(n, 'width') || 100, height : dom.getAttrib(n, 'height') || 100, style : dom.getAttrib(n, 'style'), 'class' : cl }); // Setup base parameters each(args, function(na) { var v = dom.getAttrib(n, na); if (v) pa[na] = v; }); // Add optional parameters each(dom.select('span', n), function(n) { if (dom.hasClass(n, 'mceItemParam')) pa[dom.getAttrib(n, 'name')] = dom.getAttrib(n, '_mce_value'); }); // Use src not movie if (pa.movie) { pa.src = pa.movie; delete pa.movie; } // No src try data if (!pa.src) { pa.src = pa.data; delete pa.data; } // Merge with embed args n = dom.select('.mceItemEmbed', n)[0]; if (n) { each(args, function(na) { var v = dom.getAttrib(n, na); if (v && !pa[na]) pa[na] = v; }); } delete pa.width; delete pa.height; im.title = this._serialize(pa); return im; }, _parse : function(s) { return tinymce.util.JSON.parse('{' + s + '}'); }, _serialize : function(o) { return tinymce.util.JSON.serialize(o).replace(/[{}]/g, ''); } }); // Register plugin tinymce.PluginManager.add('media', tinymce.plugins.MediaPlugin); })();././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/media.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/media/media.ht0000644000175000017500000007763311526350530033633 0ustar frankiefrankie {#media_dlg.title}
    {#media_dlg.general}
     
    x   
    {#media_dlg.preview}
    {#media_dlg.advanced}
     
    {#media_dlg.flash_options}
    {#media_dlg.flv_options}
    {#media_dlg.qt_options}
     
     
    {#media_dlg.wmp_options}
    {#media_dlg.rmp_options}
     
    {#media_dlg.shockwave_options}
    openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/0000755000175000017500000000000011724401447032240 5ustar frankiefrankieopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/js/0000755000175000017500000000000011724401447032654 5ustar frankiefrankie././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/js/pasteword.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/js/paste0000644000175000017500000000311211226234174033706 0ustar frankiefrankietinyMCEPopup.requireLangPack(); var PasteWordDialog = { init : function() { var ed = tinyMCEPopup.editor, el = document.getElementById('iframecontainer'), ifr, doc, css, cssHTML = ''; // Create iframe el.innerHTML = ''; ifr = document.getElementById('iframe'); doc = ifr.contentWindow.document; // Force absolute CSS urls css = [ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css")]; css = css.concat(tinymce.explode(ed.settings.content_css) || []); tinymce.each(css, function(u) { cssHTML += ''; }); // Write content into iframe doc.open(); doc.write('' + cssHTML + ''); doc.close(); doc.designMode = 'on'; this.resize(); window.setTimeout(function() { ifr.contentWindow.focus(); }, 10); }, insert : function() { var h = document.getElementById('iframe').contentWindow.document.body.innerHTML; tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, h); tinyMCEPopup.close(); }, resize : function() { var vp = tinyMCEPopup.dom.getViewPort(window), el; el = document.getElementById('iframe'); if (el) { el.style.width = (vp.w - 20) + 'px'; el.style.height = (vp.h - 90) + 'px'; } } }; tinyMCEPopup.onInit.add(PasteWordDialog.init, PasteWordDialog); ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/js/pastetext.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/js/paste0000644000175000017500000000155011226234174033712 0ustar frankiefrankietinyMCEPopup.requireLangPack(); var PasteTextDialog = { init : function() { this.resize(); }, insert : function() { var h = tinyMCEPopup.dom.encode(document.getElementById('content').value), lines; // Convert linebreaks into paragraphs if (document.getElementById('linebreaks').checked) { lines = h.split(/\r?\n/); if (lines.length > 1) { h = ''; tinymce.each(lines, function(row) { h += '

    ' + row + '

    '; }); } } tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, h); tinyMCEPopup.close(); }, resize : function() { var vp = tinyMCEPopup.dom.getViewPort(window), el; el = document.getElementById('content'); el.style.width = (vp.w - 20) + 'px'; el.style.height = (vp.h - 90) + 'px'; } }; tinyMCEPopup.onInit.add(PasteTextDialog.init, PasteTextDialog); openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/css/0000755000175000017500000000000011724401447033030 5ustar frankiefrankie././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/css/blank.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/css/blan0000644000175000017500000000063111201073572033661 0ustar frankiefrankiehtml, body {height:98%} body { background-color: #FFFFFF; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10px; scrollbar-3dlight-color: #F0F0EE; scrollbar-arrow-color: #676662; scrollbar-base-color: #F0F0EE; scrollbar-darkshadow-color: #DDDDDD; scrollbar-face-color: #E0E0DD; scrollbar-highlight-color: #F0F0EE; scrollbar-shadow-color: #F0F0EE; scrollbar-track-color: #F5F5F5; } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/css/pasteword.cssopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/css/past0000644000175000017500000000006110746454052033722 0ustar frankiefrankie.sourceIframe { border: 1px solid #808080; } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/blank.htmopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/blank.ht0000644000175000017500000000075411201073572033664 0ustar frankiefrankie blank_page ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/jscripts/openacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/jscripts0000755000175000017500000000000011724401447034022 5ustar frankiefrankie././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/jscripts/pasteword.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/jscripts0000644000175000017500000000257610746454052034041 0ustar frankiefrankiefunction saveContent() { var html = document.getElementById("frmData").contentWindow.document.body.innerHTML; if (html == ''){ tinyMCEPopup.close(); return false; } tinyMCEPopup.execCommand('mcePasteWord', false, html); tinyMCEPopup.close(); } function onLoadInit() { tinyMCEPopup.resizeToInnerSize(); // Fix for endless reloading in FF window.setTimeout('createIFrame();', 10); } function createIFrame() { document.getElementById('iframecontainer').innerHTML = ''; } var wHeight=0, wWidth=0, owHeight=0, owWidth=0; function initIframe(doc) { var dir = tinyMCE.selectedInstance.settings['directionality']; doc.body.dir = dir; // Remove Gecko spellchecking if (tinyMCE.isGecko) doc.body.spellcheck = tinyMCE.getParam("gecko_spellcheck"); resizeInputs(); } function resizeInputs() { if (!tinyMCE.isMSIE) { wHeight = self.innerHeight - 80; wWidth = self.innerWidth - 18; } else { wHeight = document.body.clientHeight - 80; wWidth = document.body.clientWidth - 18; } var elm = document.getElementById('frmData'); if (elm) { elm.style.height = Math.abs(wHeight) + 'px'; elm.style.width = Math.abs(wWidth) + 'px'; } } ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/jscripts/pastetext.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/jscripts0000644000175000017500000000165510746454052034036 0ustar frankiefrankiefunction saveContent() { if (document.forms[0].htmlSource.value == '') { tinyMCEPopup.close(); return false; } tinyMCEPopup.execCommand('mcePasteText', false, { html : document.forms[0].htmlSource.value, linebreaks : document.forms[0].linebreaks.checked }); tinyMCEPopup.close(); } function onLoadInit() { tinyMCEPopup.resizeToInnerSize(); // Remove Gecko spellchecking if (tinyMCE.isGecko) document.body.spellcheck = tinyMCE.getParam("gecko_spellcheck"); resizeInputs(); } var wHeight=0, wWidth=0, owHeight=0, owWidth=0; function resizeInputs() { if (!tinyMCE.isMSIE) { wHeight = self.innerHeight-80; wWidth = self.innerWidth-17; } else { wHeight = document.body.clientHeight-80; wWidth = document.body.clientWidth-17; } document.forms[0].htmlSource.style.height = Math.abs(wHeight) + 'px'; document.forms[0].htmlSource.style.width = Math.abs(wWidth) + 'px'; } ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/editor_plugin.jsopenacs-5.7.0/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/plugins/paste/editor_p0000644000175000017500000001602411226234174033771 0ustar frankiefrankie(function(){var a=tinymce.each;tinymce.create("tinymce.plugins.PastePlugin",{init:function(c,d){var e=this,b;e.editor=c;e.url=d;e.onPreProcess=new tinymce.util.Dispatcher(e);e.onPostProcess=new tinymce.util.Dispatcher(e);e.onPreProcess.add(e._preProcess);e.onPostProcess.add(e._postProcess);e.onPreProcess.add(function(h,i){c.execCallback("paste_preprocess",h,i)});e.onPostProcess.add(function(h,i){c.execCallback("paste_postprocess",h,i)});function g(i){var k=c.dom,j={content:i};e.onPreProcess.dispatch(e,j);j.node=k.create("div",0,j.content);e.onPostProcess.dispatch(e,j);j.content=c.serializer.serialize(j.node,{getInner:1});if(/<(p|h[1-6]|ul|ol)/.test(j.content)){e._insertBlockContent(c,k,j.content)}else{e._insert(j.content)}}c.addCommand("mceInsertClipboardContent",function(i,h){g(h)});function f(l){var p,k,i,j=c.selection,o=c.dom,h=c.getBody(),m;if(o.get("_mcePaste")){return}p=o.add(h,"div",{id:"_mcePaste"}," ");if(h!=c.getDoc().body){m=o.getPos(c.selection.getStart(),h).y}else{m=h.scrollTop}o.setStyles(p,{position:"absolute",left:-10000,top:m,width:1,height:1,overflow:"hidden"});if(tinymce.isIE){i=o.doc.body.createTextRange();i.moveToElementText(p);i.execCommand("Paste");o.remove(p);g(p.innerHTML);return tinymce.dom.Event.cancel(l)}else{k=c.selection.getRng();p=p.firstChild;i=c.getDoc().createRange();i.setStart(p,0);i.setEnd(p,1);j.setRng(i);window.setTimeout(function(){var r=o.get("_mcePaste"),q;r.id="_mceRemoved";o.remove(r);r=o.get("_mcePaste")||r;q=(o.select("> span.Apple-style-span div",r)[0]||o.select("> span.Apple-style-span",r)[0]||r).innerHTML;o.remove(r);if(k){j.setRng(k)}g(q)},0)}}if(c.getParam("paste_auto_cleanup_on_paste",true)){if(tinymce.isOpera||/Firefox\/2/.test(navigator.userAgent)){c.onKeyDown.add(function(h,i){if(((tinymce.isMac?i.metaKey:i.ctrlKey)&&i.keyCode==86)||(i.shiftKey&&i.keyCode==45)){f(i)}})}else{c.onPaste.addToTop(function(h,i){return f(i)})}}if(c.getParam("paste_block_drop")){c.onInit.add(function(){c.dom.bind(c.getBody(),["dragend","dragover","draggesture","dragdrop","drop","drag"],function(h){h.preventDefault();h.stopPropagation();return false})})}e._legacySupport()},getInfo:function(){return{longname:"Paste text/word",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_preProcess:function(d,g){var b=this.editor,c=g.content,f,e;function f(h){a(h,function(i){if(i.constructor==RegExp){c=c.replace(i,"")}else{c=c.replace(i[0],i[1])}})}f([/^\s*( )+/g,/( |]*>)+\s*$/g]);if(/(class=\"?Mso|style=\"[^\"]*\bmso\-|w:WordDocument)/.test(c)){g.wordContent=true;if(b.getParam("paste_convert_middot_lists",true)){f([[//gi,"$&__MCE_ITEM__"],[/(]+:\s*symbol[^>]+>)/gi,"$1__MCE_ITEM__"],[/(]+mso-list:[^>]+>)/gi,"$1__MCE_ITEM__"]])}f([//gi,/<\/?(img|font|meta|link|style|div|v:\w+)[^>]*>/gi,/<\\?\?xml[^>]*>/gi,/<\/?o:[^>]*>/gi,/ (id|name|language|type|on\w+|v:\w+)=\"([^\"]*)\"/gi,/ (id|name|language|type|on\w+|v:\w+)=(\w+)/gi,[/<(\/?)s>/gi,"<$1strike>"],/]+>[\s\S]*?<\/script>/gi,[/ /g,"\u00a0"]]);if(!b.getParam("paste_retain_style_properties")){f([/<\/?(span)[^>]*>/gi])}}e=b.getParam("paste_strip_class_attributes","all");if(e!="none"){if(e=="all"){f([/ class=\"([^\"]*)\"/gi,/ class=(\w+)/gi])}else{f([/ class=\"(mso[^\"]*)\"/gi,/ class=(mso\w+)/gi])}}if(b.getParam("paste_remove_spans")){f([/<\/?(span)[^>]*>/gi])}g.content=c},_postProcess:function(e,g){var d=this,c=d.editor,f=c.dom,b;if(g.wordContent){a(f.select("a",g.node),function(h){if(!h.href||h.href.indexOf("#_Toc")!=-1){f.remove(h,1)}});if(d.editor.getParam("paste_convert_middot_lists",true)){d._convertLists(e,g)}b=c.getParam("paste_retain_style_properties");if(tinymce.is(b,"string")){b=tinymce.explode(b)}a(f.select("*",g.node),function(l){var m={},j=0,k,n,h;if(b){for(k=0;k0){f.setStyles(l,m)}else{if(l.nodeName=="SPAN"&&!l.className){f.remove(l,true)}}})}if(c.getParam("paste_remove_styles")||(c.getParam("paste_remove_styles_if_webkit")&&tinymce.isWebKit)){a(f.select("*[style]",g.node),function(h){h.removeAttribute("style");h.removeAttribute("mce_style")})}else{if(tinymce.isWebKit){a(f.select("*",g.node),function(h){h.removeAttribute("mce_style")})}}},_convertLists:function(e,c){var g=e.editor.dom,f,j,b=-1,d,k=[],i,h;a(g.select("p",c.node),function(r){var n,s="",q,o,l,m;for(n=r.firstChild;n&&n.nodeType==3;n=n.nextSibling){s+=n.nodeValue}s=r.innerHTML.replace(/<\/?\w+[^>]*>/gi,"").replace(/ /g,"\u00a0");if(/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o]\s*\u00a0*/.test(s)){q="ul"}if(/^__MCE_ITEM__\s*\w+\.\s*\u00a0{2,}/.test(s)){q="ol"}if(q){d=parseFloat(r.style.marginLeft||0);if(d>b){k.push(d)}if(!f||q!=i){f=g.create(q);g.insertAfter(f,r)}else{if(d>b){f=j.appendChild(g.create(q))}else{if(d]*>/gi,"");if(q=="ul"&&/^[\u2022\u00b7\u00a7\u00d8o]/.test(p)){g.remove(t)}else{if(/^[\s\S]*\w+\.( |\u00a0)*\s*/.test(p)){g.remove(t)}}});o=r.innerHTML;if(q=="ul"){o=r.innerHTML.replace(/__MCE_ITEM__/g,"").replace(/^[\u2022\u00b7\u00a7\u00d8o]\s*( |\u00a0)+\s*/,"")}else{o=r.innerHTML.replace(/__MCE_ITEM__/g,"").replace(/^\s*\w+\.( |\u00a0)+\s*/,"")}j=f.appendChild(g.create("li",0,o));g.remove(r);b=d;i=q}else{f=b=0}});h=c.node.innerHTML;if(h.indexOf("__MCE_ITEM__")!=-1){c.node.innerHTML=h.replace(/__MCE_ITEM__/g,"")}},_insertBlockContent:function(h,e,i){var c,g,d=h.selection,m,j,b,k,f;function l(p){var o;if(tinymce.isIE){o=h.getDoc().body.createTextRange();o.moveToElementText(p);o.collapse(false);o.select()}else{d.select(p,1);d.collapse(false)}}this._insert(' ',1);g=e.get("_marker");c=e.getParent(g,"p,h1,h2,h3,h4,h5,h6,ul,ol");if(c){g=e.split(c,g);a(e.create("div",0,i).childNodes,function(o){m=g.parentNode.insertBefore(o.cloneNode(true),g)});l(m)}else{e.setOuterHTML(g,i);d.select(h.getBody(),1);d.collapse(0)}e.remove("_marker");j=d.getStart();b=e.getViewPort(h.getWin());k=h.dom.getPos(j).y;f=j.clientHeight;if(kb.y+b.h){h.getDoc().body.scrollTop=k